diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..b9ed3f3b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,93 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +main/source/**/* text=auto + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just comment the entries below and +# uncomment the group further below +############################################################################### + +main/source/**/*.sln text eol=crlf +main/source/**/*.csproj text eol=crlf +main/source/**/*.vbproj text eol=crlf +main/source/**/*.vcxproj text eol=crlf +main/source/**/*.vcproj text eol=crlf +main/source/**/*.dbproj text eol=crlf +main/source/**/*.fsproj text eol=crlf +main/source/**/*.lsproj text eol=crlf +main/source/**/*.wixproj text eol=crlf +main/source/**/*.modelproj text eol=crlf +main/source/**/*.sqlproj text eol=crlf +main/source/**/*.wmaproj text eol=crlf + +main/source/**/*.xproj text eol=crlf +main/source/**/*.props text eol=crlf +main/source/**/*.filters text eol=crlf +main/source/**/*.vcxitems text eol=crlf + + +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +#*.xproj merge=binary +#*.props merge=binary +#*.filters merge=binary +#*.vcxitems merge=binary + +# C++ Stuff + +# sources +main/source/**/*.c text +main/source/**/*.cc text +main/source/**/*.cxx text +main/source/**/*.cpp text +main/source/**/*.c++ text +main/source/**/*.hpp text +main/source/**/*.h text +main/source/**/*.h++ text +main/source/**/*.hh text + +# Compiled Object files +*.slo binary +*.lo binary +*.o binary +*.obj binary + +# Precompiled Headers +*.gch binary +*.pch binary + +# Compiled Dynamic libraries +*.so binary +*.dylib binary +*.dll binary + +# Compiled Static libraries +*.lai binary +*.la binary +*.a binary +*.lib binary + +# Executables +*.exe binary +*.out binary +*.app binary + diff --git a/.gitignore b/.gitignore index 3d78a2bd..8c273b57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,51 @@ -# Compiled source # -################### -*.com -*.class -*.dll -*.exe -*.o -*.so - -# Packages # -############ -# it's better to unpack these files and commit the raw source -# git has its own built in compression methods -*.7z -*.dmg -*.gz -*.iso -*.jar -*.rar -*.tar -*.zip - -# Logs and databases # -###################### -*.log -*.sql -*.sqlite - -# OS generated files # -###################### -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# Visual Studio # -################# +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ *_i.c *_p.c +*_i.h *.ilk *.meta *.obj @@ -61,13 +66,179 @@ Thumbs.db *.vssscc .builds *.pidb -*.log +*.svclog *.scc -*.wav -*.XML + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ # Add include dir # ################### !main/source/includes/ + diff --git a/main/source/HPB_bot.sln b/main/source/HPB_bot.sln index 2181a55a..a9ab843e 100644 --- a/main/source/HPB_bot.sln +++ b/main/source/HPB_bot.sln @@ -1,21 +1,21 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HPB_bot", "HPB_bot\dlls\HPB_bot.vcproj", "{4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Debug.ActiveCfg = Debug|Win32 - {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Debug.Build.0 = Debug|Win32 - {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Release.ActiveCfg = Release|Win32 - {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HPB_bot", "HPB_bot\dlls\HPB_bot.vcproj", "{4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Debug.ActiveCfg = Debug|Win32 + {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Debug.Build.0 = Debug|Win32 + {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Release.ActiveCfg = Release|Win32 + {4D2D2333-4ACF-44B3-925C-1625FC8EFEA8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/main/source/HPB_bot/dlls/HPB_bot.def b/main/source/HPB_bot/dlls/HPB_bot.def index e3e89fda..4bccf81b 100644 --- a/main/source/HPB_bot/dlls/HPB_bot.def +++ b/main/source/HPB_bot/dlls/HPB_bot.def @@ -1,5 +1,5 @@ -LIBRARY HPB_bot -EXPORTS - GiveFnptrsToDll @1 -SECTIONS - .data READ WRITE +LIBRARY HPB_bot +EXPORTS + GiveFnptrsToDll @1 +SECTIONS + .data READ WRITE diff --git a/main/source/HPB_bot/dlls/HPB_bot.vcproj b/main/source/HPB_bot/dlls/HPB_bot.vcproj index f1bd37ac..eb944285 100644 --- a/main/source/HPB_bot/dlls/HPB_bot.vcproj +++ b/main/source/HPB_bot/dlls/HPB_bot.vcproj @@ -1,394 +1,394 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/source/HPB_bot/dlls/bot.cpp b/main/source/HPB_bot/dlls/bot.cpp index 5c8afe29..8601f530 100644 --- a/main/source/HPB_bot/dlls/bot.cpp +++ b/main/source/HPB_bot/dlls/bot.cpp @@ -1,2087 +1,2087 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot.cpp -// - -//#include "windows.h" -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" -#include "bot_func.h" -#include "waypoint.h" -#include "bot_weapons.h" - -#include -#include -#include "mod/AvHMarineEquipmentConstants.h" -#include "mod/AvHMessage.h" -#include "mod/AvHCommandConstants.h" -#include "mod/AvHMessage.h" -#include "mod/AvHPlayer.h" - -#ifndef __linux__ -extern HINSTANCE h_Library; -#else -extern void *h_Library; -#endif - - -extern int mod_id; -extern WAYPOINT waypoints[MAX_WAYPOINTS]; -extern int num_waypoints; // number of waypoints currently in use -extern int default_bot_skill; -extern edict_t *pent_info_ctfdetect; - -extern int max_team_players[4]; -extern int team_class_limits[4]; -extern int max_teams; -extern char bot_whine[MAX_BOT_WHINE][81]; -extern int whine_count; - -extern int flf_bug_fix; - -static FILE *fp; - - -#define PLAYER_SEARCH_RADIUS 40.0 -#define FLF_PLAYER_SEARCH_RADIUS 60.0 - - -bot_t bots[32]; // max of 32 bots in a game -bool b_observer_mode = FALSE; -bool b_botdontshoot = FALSE; - -extern int recent_bot_whine[5]; - -int number_names = 0; - -#define MAX_BOT_NAMES 100 - -#define VALVE_MAX_SKINS 10 -#define GEARBOX_MAX_SKINS 20 - -// indicate which models are currently used for random model allocation -bool valve_skin_used[VALVE_MAX_SKINS] = { - FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; - -bool gearbox_skin_used[GEARBOX_MAX_SKINS] = { - FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, - FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; - -// store the names of the models... -char *valve_bot_skins[VALVE_MAX_SKINS] = { - "barney", "gina", "gman", "gordon", "helmet", - "hgrunt", "recon", "robo", "scientist", "zombie"}; - -char *gearbox_bot_skins[GEARBOX_MAX_SKINS] = { - "barney", "beret", "cl_suit", "drill", "fassn", "gina", "gman", - "gordon", "grunt", "helmet", "hgrunt", "massn", "otis", "recon", - "recruit", "robo", "scientist", "shepard", "tower", "zombie"}; - -// store the player names for each of the models... -char *valve_bot_names[VALVE_MAX_SKINS] = { - "Barney", "Gina", "G-Man", "Gordon", "Helmet", - "H-Grunt", "Recon", "Robo", "Scientist", "Zombie"}; - -char *gearbox_bot_names[GEARBOX_MAX_SKINS] = { - "Barney", "Beret", "Cl_suit", "Drill", "Fassn", "Gina", "G-Man", - "Gordon", "Grunt", "Helmet", "H-Grunt", "Massn", "Otis", "Recon", - "Recruit", "Robo", "Scientist", "Shepard", "Tower", "Zombie"}; - -char bot_names[MAX_BOT_NAMES][BOT_NAME_LEN+1]; - -// how often (out of 1000 times) the bot will pause, based on bot skill -float pause_frequency[5] = {4, 7, 10, 15, 20}; - -float pause_time[5][2] = { - {0.2, 0.5}, {0.5, 1.0}, {0.7, 1.3}, {1.0, 1.7}, {1.2, 2.0}}; - - -inline edict_t *CREATE_FAKE_CLIENT( const char *netname ) -{ - return (*g_engfuncs.pfnCreateFakeClient)( netname ); -} - -inline char *GET_INFOBUFFER( edict_t *e ) -{ - return (*g_engfuncs.pfnGetInfoKeyBuffer)( e ); -} - -inline char *GET_INFO_KEY_VALUE( char *infobuffer, char *key ) -{ - return (g_engfuncs.pfnInfoKeyValue( infobuffer, key )); -} - -inline void SET_CLIENT_KEY_VALUE( int clientIndex, char *infobuffer, - char *key, char *value ) -{ - (*g_engfuncs.pfnSetClientKeyValue)( clientIndex, infobuffer, key, value ); -} - - -// this is the LINK_ENTITY_TO_CLASS function that creates a player (bot) -void player( entvars_t *pev ) -{ - static LINK_ENTITY_FUNC otherClassName = NULL; - if (otherClassName == NULL) - otherClassName = (LINK_ENTITY_FUNC)GetProcAddress(h_Library, "player"); - if (otherClassName != NULL) - { - (*otherClassName)(pev); - } -} - -void BotProcessVoiceCommands(bot_t* pBot) -{ - if((pBot->mTimeOfNextOrderRequest != -1) && (gpGlobals->time > pBot->mTimeOfNextOrderRequest)) - { - if(pBot->pEdict->v.impulse == 0) - { - pBot->pEdict->v.impulse = ORDER_REQUEST; - pBot->mTimeOfNextOrderRequest = -1; - } - } - if((pBot->mTimeOfNextAmmoRequest != -1) && (gpGlobals->time > pBot->mTimeOfNextAmmoRequest)) - { - if(pBot->pEdict->v.impulse == 0) - { - pBot->pEdict->v.impulse = SAYING_5; - pBot->mTimeOfNextAmmoRequest = -1; - } - } - if((pBot->mTimeOfNextRandomSaying != -1) && (gpGlobals->time > pBot->mTimeOfNextRandomSaying)) - { - if(pBot->pEdict->v.impulse == 0) - { - pBot->pEdict->v.impulse = SAYING_1 + g_engfuncs.pfnRandomLong(0, 5); - pBot->mTimeOfNextRandomSaying = -1; - } - } - if((pBot->mTimeOfNextTaunt != -1) && (gpGlobals->time > pBot->mTimeOfNextTaunt)) - { - if(pBot->pEdict->v.impulse == 0) - { - pBot->pEdict->v.impulse = SAYING_3; - pBot->mTimeOfNextTaunt = -1; - } - } - if((pBot->mTimeOfNextAcknowledge != -1) && (gpGlobals->time > pBot->mTimeOfNextAcknowledge)) - { - if(pBot->pEdict->v.impulse == 0) - { - pBot->pEdict->v.impulse = ORDER_ACK; - pBot->mTimeOfNextAcknowledge = -1; - } - } -} - -void BotSpawnInit( bot_t *pBot ) -{ - pBot->v_prev_origin = Vector(9999.0, 9999.0, 9999.0); - pBot->prev_time = gpGlobals->time; - - pBot->waypoint_origin = Vector(0, 0, 0); - pBot->f_waypoint_time = 0.0; - pBot->curr_waypoint_index = -1; - pBot->prev_waypoint_index[0] = -1; - pBot->prev_waypoint_index[1] = -1; - pBot->prev_waypoint_index[2] = -1; - pBot->prev_waypoint_index[3] = -1; - pBot->prev_waypoint_index[4] = -1; - - pBot->f_random_waypoint_time = gpGlobals->time; - pBot->waypoint_goal = -1; - pBot->f_waypoint_goal_time = 0.0; - pBot->waypoint_near_flag = FALSE; - pBot->waypoint_flag_origin = Vector(0, 0, 0); - pBot->prev_waypoint_distance = 0.0; - - pBot->msecnum = 0; - pBot->msecdel = 0.0; - pBot->msecval = 0.0; - - pBot->bot_health = 0; - pBot->bot_armor = 0; - pBot->bot_weapons = 0; - pBot->blinded_time = 0.0; - - // Init AvH variables - pBot->mBotPlayMode = PLAYMODE_READYROOM; - - pBot->mOrderState = 0; - pBot->mOrderNumPlayers = -1; - pBot->mOrderType = ORDERTYPE_UNDEFINED; - pBot->mOrderTargetType = ORDERTARGETTYPE_UNDEFINED; - pBot->mOrderLocation[0] = pBot->mOrderLocation[1] = pBot->mOrderLocation[2] = 0.0f; - pBot->mOrderTargetIndex = -1; - pBot->mOrderCompleted = false; - - pBot->mTimeOfNextAcknowledge = -1; - pBot->mTimeOfNextAmmoRequest = -1; - pBot->mTimeOfNextOrderRequest = -1; - pBot->mTimeOfNextTaunt = -1; - pBot->mTimeOfNextRandomSaying = -1; - - pBot->mGestateUser3 = AVH_USER3_NONE; - pBot->mResources = 0; - // end AvH variable init - - pBot->f_max_speed = CVAR_GET_FLOAT("sv_maxspeed"); - - pBot->prev_speed = 0.0; // fake "paused" since bot is NOT stuck - - pBot->f_find_item = 0.0; - - pBot->ladder_dir = LADDER_UNKNOWN; - pBot->f_start_use_ladder_time = 0.0; - pBot->f_end_use_ladder_time = 0.0; - pBot->waypoint_top_of_ladder = FALSE; - - pBot->f_wall_check_time = 0.0; - pBot->f_wall_on_right = 0.0; - pBot->f_wall_on_left = 0.0; - pBot->f_dont_avoid_wall_time = 0.0; - pBot->f_look_for_waypoint_time = 0.0; - pBot->f_jump_time = 0.0; - pBot->f_dont_check_stuck = 0.0; - - // pick a wander direction (50% of the time to the left, 50% to the right) - if (RANDOM_LONG(1, 100) <= 50) - pBot->wander_dir = WANDER_LEFT; - else - pBot->wander_dir = WANDER_RIGHT; - - pBot->f_exit_water_time = 0.0; - - pBot->pBotEnemy = NULL; - pBot->f_bot_see_enemy_time = gpGlobals->time; - pBot->f_bot_find_enemy_time = gpGlobals->time; - pBot->pBotUser = NULL; - pBot->f_bot_use_time = 0.0; - pBot->b_bot_say_killed = FALSE; - pBot->f_bot_say_killed = 0.0; - pBot->f_sniper_aim_time = 0.0; - - pBot->f_shoot_time = gpGlobals->time; - pBot->f_primary_charging = -1.0; - pBot->f_secondary_charging = -1.0; - pBot->charging_weapon_id = 0; - - pBot->f_pause_time = 0.0; - pBot->f_sound_update_time = 0.0; - pBot->bot_has_flag = FALSE; - - pBot->b_see_tripmine = FALSE; - pBot->b_shoot_tripmine = FALSE; - pBot->v_tripmine = Vector(0,0,0); - - pBot->b_use_health_station = FALSE; - pBot->f_use_health_time = 0.0; - pBot->b_use_HEV_station = FALSE; - pBot->f_use_HEV_time = 0.0; - - pBot->b_use_button = FALSE; - pBot->f_use_button_time = 0; - pBot->b_lift_moving = FALSE; - - pBot->b_use_capture = FALSE; - pBot->f_use_capture_time = 0.0; - pBot->pCaptureEdict = NULL; - - memset(&(pBot->current_weapon), 0, sizeof(pBot->current_weapon)); - memset(&(pBot->m_rgAmmo), 0, sizeof(pBot->m_rgAmmo)); -} - - -void BotNameInit( void ) -{ - FILE *bot_name_fp; - char bot_name_filename[256]; - int str_index; - char name_buffer[80]; - int length, index; - - UTIL_BuildFileName(bot_name_filename, "bot_names.txt", NULL); - - bot_name_fp = fopen(bot_name_filename, "r"); - - if (bot_name_fp != NULL) - { - while ((number_names < MAX_BOT_NAMES) && - (fgets(name_buffer, 80, bot_name_fp) != NULL)) - { - length = strlen(name_buffer); - - if (name_buffer[length-1] == '\n') - { - name_buffer[length-1] = 0; // remove '\n' - length--; - } - - str_index = 0; - while (str_index < length) - { - if ((name_buffer[str_index] < ' ') || (name_buffer[str_index] > '~') || - (name_buffer[str_index] == '"')) - for (index=str_index; index < length; index++) - name_buffer[index] = name_buffer[index+1]; - - str_index++; - } - - if (name_buffer[0] != 0) - { - strncpy(bot_names[number_names], name_buffer, BOT_NAME_LEN); - - number_names++; - } - } - - fclose(bot_name_fp); - } -} - - -void BotPickName( char *name_buffer ) -{ - int name_index, index; - bool used; - edict_t *pPlayer; - int attempts = 0; - - // see if a name exists from a kicked bot (if so, reuse it) - for (index=0; index < 32; index++) - { - if ((bots[index].is_used == FALSE) && (bots[index].name[0])) - { - strcpy(name_buffer, bots[index].name); - - return; - } - } - - name_index = RANDOM_LONG(1, number_names) - 1; // zero based - - // check make sure this name isn't used - used = TRUE; - - while (used) - { - used = FALSE; - - for (index = 1; index <= gpGlobals->maxClients; index++) - { - pPlayer = INDEXENT(index); - - if (pPlayer && !pPlayer->free) - { - if (strcmp(bot_names[name_index], STRING(pPlayer->v.netname)) == 0) - { - used = TRUE; - break; - } - } - } - - if (used) - { - name_index++; - - if (name_index == number_names) - name_index = 0; - - attempts++; - - if (attempts == number_names) - used = FALSE; // break out of loop even if already used - } - } - - strcpy(name_buffer, bot_names[name_index]); -} - - -void BotCreate( edict_t *pPlayer, const char *arg1, const char *arg2, - const char *arg3, const char *arg4) -{ - edict_t *BotEnt; - bot_t *pBot; - char c_skin[BOT_SKIN_LEN+1]; - char c_name[BOT_NAME_LEN+1]; - int skill; - int index; - int i, j, length; - bool found = FALSE; - - - if ((mod_id == VALVE_DLL) || - ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect == NULL))) - { - int max_skin_index; - - if (mod_id == VALVE_DLL) - max_skin_index = VALVE_MAX_SKINS; - else // must be GEARBOX_DLL - max_skin_index = GEARBOX_MAX_SKINS; - - if ((arg1 == NULL) || (*arg1 == 0)) - { - bool *pSkinUsed; - - // pick a random skin - if (mod_id == VALVE_DLL) - { - index = RANDOM_LONG(0, VALVE_MAX_SKINS-1); - pSkinUsed = &valve_skin_used[0]; - } - else // must be GEARBOX_DLL - { - index = RANDOM_LONG(0, GEARBOX_MAX_SKINS-1); - pSkinUsed = &gearbox_skin_used[0]; - } - - // check if this skin has already been used... - while (pSkinUsed[index] == TRUE) - { - index++; - - if (index == max_skin_index) - index = 0; - } - - pSkinUsed[index] = TRUE; - - // check if all skins are now used... - for (i = 0; i < max_skin_index; i++) - { - if (pSkinUsed[i] == FALSE) - break; - } - - // if all skins are used, reset used to FALSE for next selection - if (i == max_skin_index) - { - for (i = 0; i < max_skin_index; i++) - pSkinUsed[i] = FALSE; - } - - if (mod_id == VALVE_DLL) - strcpy( c_skin, valve_bot_skins[index] ); - else // must be GEARBOX_DLL - strcpy( c_skin, gearbox_bot_skins[index] ); - } - else - { - strncpy( c_skin, arg1, BOT_SKIN_LEN-1 ); - c_skin[BOT_SKIN_LEN] = 0; // make sure c_skin is null terminated - } - - for (i = 0; c_skin[i] != 0; i++) - c_skin[i] = tolower( c_skin[i] ); // convert to all lowercase - - index = 0; - - while ((!found) && (index < max_skin_index)) - { - if (mod_id == VALVE_DLL) - { - if (strcmp(c_skin, valve_bot_skins[index]) == 0) - found = TRUE; - else - index++; - } - else // must be GEARBOX_DLL - { - if (strcmp(c_skin, gearbox_bot_skins[index]) == 0) - found = TRUE; - else - index++; - } - } - - if (found == TRUE) - { - if ((arg2 != NULL) && (*arg2 != 0)) - { - strncpy( c_name, arg2, BOT_SKIN_LEN-1 ); - c_name[BOT_SKIN_LEN] = 0; // make sure c_name is null terminated - } - else - { - if (number_names > 0) - BotPickName( c_name ); - else if (mod_id == VALVE_DLL) - strcpy( c_name, valve_bot_names[index] ); - else // must be GEARBOX_DLL - strcpy( c_name, gearbox_bot_names[index] ); - } - } - else - { - char dir_name[32]; - char filename[128]; - - struct stat stat_str; - - GET_GAME_DIR(dir_name); - -#ifndef __linux__ - sprintf(filename, "%s\\models\\player\\%s", dir_name, c_skin); -#else - sprintf(filename, "%s/models/player/%s", dir_name, c_skin); -#endif - - if (stat(filename, &stat_str) != 0) - { -#ifndef __linux__ - sprintf(filename, "valve\\models\\player\\%s", c_skin); -#else - sprintf(filename, "valve/models/player/%s", c_skin); -#endif - if (stat(filename, &stat_str) != 0) - { - char err_msg[80]; - - sprintf( err_msg, "model \"%s\" is unknown.\n", c_skin ); - if (pPlayer) - ClientPrint(pPlayer, HUD_PRINTNOTIFY, err_msg ); - if (IS_DEDICATED_SERVER()) - printf(err_msg); - - if (pPlayer) - ClientPrint(pPlayer, HUD_PRINTNOTIFY, - "use barney, gina, gman, gordon, helmet, hgrunt,\n"); - if (IS_DEDICATED_SERVER()) - printf("use barney, gina, gman, gordon, helmet, hgrunt,\n"); - if (pPlayer) - ClientPrint(pPlayer, HUD_PRINTNOTIFY, - " recon, robo, scientist, or zombie\n"); - if (IS_DEDICATED_SERVER()) - printf(" recon, robo, scientist, or zombie\n"); - return; - } - } - - if ((arg2 != NULL) && (*arg2 != 0)) - { - strncpy( c_name, arg2, BOT_NAME_LEN-1 ); - c_name[BOT_NAME_LEN] = 0; // make sure c_name is null terminated - } - else - { - if (number_names > 0) - BotPickName( c_name ); - else - { - // copy the name of the model to the bot's name... - strncpy( c_name, arg1, BOT_NAME_LEN-1 ); - c_name[BOT_NAME_LEN] = 0; // make sure c_skin is null terminated - } - } - } - - skill = 0; - - if ((arg3 != NULL) && (*arg3 != 0)) - skill = atoi(arg3); - - if ((skill < 1) || (skill > 5)) - skill = default_bot_skill; - } - else - { - if ((arg3 != NULL) && (*arg3 != 0)) - { - strncpy( c_name, arg3, BOT_NAME_LEN-1 ); - c_name[BOT_NAME_LEN] = 0; // make sure c_name is null terminated - } - else - { - if (number_names > 0) - BotPickName( c_name ); - else - strcpy(c_name, "Bot"); - } - - skill = 0; - - if ((arg4 != NULL) && (*arg4 != 0)) - skill = atoi(arg4); - - if ((skill < 1) || (skill > 5)) - skill = default_bot_skill; - } - - length = strlen(c_name); - - // remove any illegal characters from name... - for (i = 0; i < length; i++) - { - if ((c_name[i] <= ' ') || (c_name[i] > '~') || - (c_name[i] == '"')) - { - for (j = i; j < length; j++) // shuffle chars left (and null) - c_name[j] = c_name[j+1]; - length--; - } - } - - BotEnt = CREATE_FAKE_CLIENT( c_name ); - - if (FNullEnt( BotEnt )) - { - if (pPlayer) - ClientPrint( pPlayer, HUD_PRINTNOTIFY, "Max. Players reached. Can't create bot!\n"); - } - else - { - char ptr[128]; // allocate space for message from ClientConnect - char *infobuffer; - int clientIndex; - int index; - - if (IS_DEDICATED_SERVER()) - printf("Creating bot...\n"); - else if (pPlayer) - ClientPrint( pPlayer, HUD_PRINTNOTIFY, "Creating bot...\n"); - - index = 0; - while ((bots[index].is_used) && (index < 32)) - index++; - - if (index == 32) - { - ClientPrint( pPlayer, HUD_PRINTNOTIFY, "Can't create bot!\n"); - return; - } - - // create the player entity by calling MOD's player function - // (from LINK_ENTITY_TO_CLASS for player object) - - player( VARS(BotEnt) ); - - infobuffer = GET_INFOBUFFER( BotEnt ); - clientIndex = ENTINDEX( BotEnt ); - - - if ((mod_id == VALVE_DLL) || (mod_id == GEARBOX_DLL)) - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "model", c_skin ); - else // other mods - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "model", "gina" ); - - if (mod_id == CSTRIKE_DLL) - { - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "rate", "3500.000000"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_updaterate", "20"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_lw", "1"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_lc", "1"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "tracker", "0"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_dlmax", "128"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "lefthand", "1"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "friends", "0"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "dm", "0"); - SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "ah", "1"); - } - - ClientConnect( BotEnt, c_name, "127.0.0.1", ptr ); - - // Pieter van Dijk - use instead of DispatchSpawn() - Hip Hip Hurray! - ClientPutInServer( BotEnt ); - - BotEnt->v.flags |= FL_FAKECLIENT; - - // initialize all the variables for this bot... - - pBot = &bots[index]; - - pBot->is_used = TRUE; - pBot->respawn_state = RESPAWN_IDLE; - pBot->create_time = gpGlobals->time; - pBot->name[0] = 0; // name not set by server yet - pBot->bot_money = 0; - - strcpy(pBot->skin, c_skin); - - pBot->pEdict = BotEnt; - - pBot->not_started = 1; // hasn't joined game yet - - if (mod_id == TFC_DLL) - pBot->start_action = MSG_TFC_IDLE; - else if (mod_id == CSTRIKE_DLL) - pBot->start_action = MSG_CS_IDLE; - else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) - pBot->start_action = MSG_OPFOR_IDLE; - else if (mod_id == FRONTLINE_DLL) - pBot->start_action = MSG_FLF_IDLE; - else if (mod_id == AVH_DLL) - pBot->start_action = MSG_AVH_IDLE; - else - pBot->start_action = 0; // not needed for non-team MODs - - - BotSpawnInit(pBot); - - pBot->need_to_initialize = FALSE; // don't need to initialize yet - - BotEnt->v.idealpitch = BotEnt->v.v_angle.x; - BotEnt->v.ideal_yaw = BotEnt->v.v_angle.y; - BotEnt->v.pitch_speed = BOT_PITCH_SPEED; - BotEnt->v.yaw_speed = BOT_YAW_SPEED; - - pBot->warmup = 0; // for Front Line Force - pBot->idle_angle = 0.0; - pBot->idle_angle_time = 0.0; - pBot->round_end = 0; - pBot->defender = 0; - - pBot->bot_skill = skill - 1; // 0 based for array indexes - - pBot->bot_team = -1; - pBot->bot_class = -1; - - if ((mod_id == TFC_DLL) || (mod_id == CSTRIKE_DLL) || - ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) || - (mod_id == FRONTLINE_DLL)) - { - if ((arg1 != NULL) && (arg1[0] != 0)) - { - pBot->bot_team = atoi(arg1); - - if ((arg2 != NULL) && (arg2[0] != 0)) - { - pBot->bot_class = atoi(arg2); - } - } - } - } -} - - -int BotInFieldOfView(bot_t *pBot, Vector dest) -{ - // find angles from source to destination... - Vector entity_angles = UTIL_VecToAngles( dest ); - - // make yaw angle 0 to 360 degrees if negative... - if (entity_angles.y < 0) - entity_angles.y += 360; - - // get bot's current view angle... - float view_angle = pBot->pEdict->v.v_angle.y; - - // make view angle 0 to 360 degrees if negative... - if (view_angle < 0) - view_angle += 360; - - // return the absolute value of angle to destination entity - // zero degrees means straight ahead, 45 degrees to the left or - // 45 degrees to the right is the limit of the normal view angle - - // rsm - START angle bug fix - int angle = abs((int)view_angle - (int)entity_angles.y); - - if (angle > 180) - angle = 360 - angle; - - return angle; - // rsm - END -} - - -bool BotEntityIsVisible( bot_t *pBot, Vector dest ) -{ - TraceResult tr; - - // trace a line from bot's eyes to destination... - UTIL_TraceLine( pBot->pEdict->v.origin + pBot->pEdict->v.view_ofs, - dest, ignore_monsters, - pBot->pEdict->v.pContainingEntity, &tr ); - - // check if line of sight to object is not blocked (i.e. visible) - if (tr.flFraction >= 1.0) - return TRUE; - else - return FALSE; -} - - -void BotFindItem( bot_t *pBot ) -{ - edict_t *pent = NULL; - edict_t *pPickupEntity = NULL; - Vector pickup_origin; - Vector entity_origin; - float radius = 500; - bool can_pickup; - float min_distance; - char item_name[40]; - TraceResult tr; - Vector vecStart; - Vector vecEnd; - int angle_to_entity; - edict_t *pEdict = pBot->pEdict; - - pBot->pBotPickupItem = NULL; - - // use a MUCH smaller search radius when waypoints are available - if ((num_waypoints > 0) && (pBot->curr_waypoint_index != -1)) - radius = 100.0; - else - radius = 500.0; - - min_distance = radius + 1.0; - - while ((pent = UTIL_FindEntityInSphere( pent, pEdict->v.origin, radius )) != NULL) - { - can_pickup = FALSE; // assume can't use it until known otherwise - - strcpy(item_name, STRING(pent->v.classname)); - - // see if this is a "func_" type of entity (func_button, etc.)... - if (strncmp("func_", item_name, 5) == 0) - { - // BModels have 0,0,0 for origin so must use VecBModelOrigin... - entity_origin = VecBModelOrigin(pent); - - vecStart = pEdict->v.origin + pEdict->v.view_ofs; - vecEnd = entity_origin; - - angle_to_entity = BotInFieldOfView( pBot, vecEnd - vecStart ); - - // check if entity is outside field of view (+/- 45 degrees) - if (angle_to_entity > 45) - continue; // skip this item if bot can't "see" it - - // check if entity is a ladder (ladders are a special case) - // DON'T search for ladders if there are waypoints in this level... - if ((strcmp("func_ladder", item_name) == 0) && (num_waypoints == 0)) - { - // force ladder origin to same z coordinate as bot since - // the VecBModelOrigin is the center of the ladder. For - // LONG ladders, the center MAY be hundreds of units above - // the bot. Fake an origin at the same level as the bot... - - entity_origin.z = pEdict->v.origin.z; - vecEnd = entity_origin; - - // trace a line from bot's eyes to func_ladder entity... - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // check if traced all the way up to the entity (didn't hit wall) - if (tr.flFraction >= 1.0) - { - // find distance to item for later use... - float distance = (vecEnd - vecStart).Length( ); - - // use the ladder about 100% of the time, if haven't - // used a ladder in at least 5 seconds... - if ((RANDOM_LONG(1, 100) <= 100) && - ((pBot->f_end_use_ladder_time + 5.0) < gpGlobals->time)) - { - // if close to ladder... - if (distance < 100) - { - // don't avoid walls for a while - pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; - } - - can_pickup = TRUE; - } - } - } - else - { - // trace a line from bot's eyes to func_ entity... - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // check if traced all the way up to the entity (didn't hit wall) - if (strcmp(item_name, STRING(tr.pHit->v.classname)) == 0) - { - // find distance to item for later use... - float distance = (vecEnd - vecStart).Length( ); - - // check if entity is wall mounted health charger... - if (strcmp("func_healthcharger", item_name) == 0) - { - // check if the bot can use this item and - // check if the recharger is ready to use (has power left)... - if ((pEdict->v.health < 100) && (pent->v.frame == 0)) - { - // check if flag not set... - if (!pBot->b_use_health_station) - { - // check if close enough and facing it directly... - if ((distance < PLAYER_SEARCH_RADIUS) && - (angle_to_entity <= 10)) - { - pBot->b_use_health_station = TRUE; - pBot->f_use_health_time = gpGlobals->time; - } - - // if close to health station... - if (distance < 100) - { - // don't avoid walls for a while - pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; - } - - can_pickup = TRUE; - } - } - else - { - // don't need or can't use this item... - pBot->b_use_health_station = FALSE; - } - } - - // check if entity is wall mounted HEV charger... - else if (strcmp("func_recharge", item_name) == 0) - { - // check if the bot can use this item and - // check if the recharger is ready to use (has power left)... - if ((pEdict->v.armorvalue < VALVE_MAX_NORMAL_BATTERY) && - (pent->v.frame == 0)) - { - // check if flag not set and facing it... - if (!pBot->b_use_HEV_station) - { - // check if close enough and facing it directly... - if ((distance < PLAYER_SEARCH_RADIUS) && - (angle_to_entity <= 10)) - { - pBot->b_use_HEV_station = TRUE; - pBot->f_use_HEV_time = gpGlobals->time; - } - - // if close to HEV recharger... - if (distance < 100) - { - // don't avoid walls for a while - pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; - } - - can_pickup = TRUE; - } - } - else - { - // don't need or can't use this item... - pBot->b_use_HEV_station = FALSE; - } - } - - // check if entity is a button... - else if (strcmp("func_button", item_name) == 0) - { - // use the button about 100% of the time, if haven't - // used a button in at least 5 seconds... - if ((RANDOM_LONG(1, 100) <= 100) && - ((pBot->f_use_button_time + 5) < gpGlobals->time)) - { - // check if flag not set and facing it... - if (!pBot->b_use_button) - { - // check if close enough and facing it directly... - if ((distance < PLAYER_SEARCH_RADIUS) && - (angle_to_entity <= 10)) - { - pBot->b_use_button = TRUE; - pBot->b_lift_moving = FALSE; - pBot->f_use_button_time = gpGlobals->time; - } - - // if close to button... - if (distance < 100) - { - // don't avoid walls for a while - pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; - } - - can_pickup = TRUE; - } - } - else - { - // don't need or can't use this item... - pBot->b_use_button = FALSE; - } - } - } - } - } - else // everything else... - { - entity_origin = pent->v.origin; - - vecStart = pEdict->v.origin + pEdict->v.view_ofs; - vecEnd = entity_origin; - - // find angles from bot origin to entity... - angle_to_entity = BotInFieldOfView( pBot, vecEnd - vecStart ); - - // check if entity is outside field of view (+/- 45 degrees) - if (angle_to_entity > 45) - continue; // skip this item if bot can't "see" it - - // check if line of sight to object is not blocked (i.e. visible) - if (BotEntityIsVisible( pBot, vecEnd )) - { - // check if entity is a weapon... - if (strncmp("weapon_", item_name, 7) == 0) - { - if (pent->v.effects & EF_NODRAW) - { - // someone owns this weapon or it hasn't respawned yet - continue; - } - - can_pickup = TRUE; - } - - // check if entity is ammo... - else if (strncmp("ammo_", item_name, 5) == 0) - { - // check if the item is not visible (i.e. has not respawned) - if (pent->v.effects & EF_NODRAW) - continue; - - can_pickup = TRUE; - } - - // check if entity is a battery... - else if (strcmp("item_battery", item_name) == 0) - { - // check if the item is not visible (i.e. has not respawned) - if (pent->v.effects & EF_NODRAW) - continue; - - // check if the bot can use this item... - if (pEdict->v.armorvalue < VALVE_MAX_NORMAL_BATTERY) - { - can_pickup = TRUE; - } - } - - // check if entity is a healthkit... - else if (strcmp("item_healthkit", item_name) == 0) - { - // check if the item is not visible (i.e. has not respawned) - if (pent->v.effects & EF_NODRAW) - continue; - - // check if the bot can use this item... - if (pEdict->v.health < 100) - { - can_pickup = TRUE; - } - } - - // check if entity is a packed up weapons box... - else if (strcmp("weaponbox", item_name) == 0) - { - can_pickup = TRUE; - } - - // check if entity is the spot from RPG laser - else if (strcmp("laser_spot", item_name) == 0) - { - } - - // check if entity is an armed tripmine - //else if (strcmp("monster_tripmine", item_name) == 0) - else if (strcmp(kwsDeployedMine, item_name) == 0) - { - float distance = (pent->v.origin - pEdict->v.origin).Length( ); - - if (pBot->b_see_tripmine) - { - // see if this tripmine is closer to bot... - if (distance < (pBot->v_tripmine - pEdict->v.origin).Length()) - { - pBot->v_tripmine = pent->v.origin; - pBot->b_shoot_tripmine = FALSE; - - // see if bot is far enough to shoot the tripmine... - if (distance >= 375) - { - pBot->b_shoot_tripmine = TRUE; - } - } - } - else - { - pBot->b_see_tripmine = TRUE; - pBot->v_tripmine = pent->v.origin; - pBot->b_shoot_tripmine = FALSE; - - // see if bot is far enough to shoot the tripmine... - if (distance >= 375) // 375 is damage radius - { - pBot->b_shoot_tripmine = TRUE; - } - } - } - - // check if entity is an armed satchel charge - else if (strcmp("monster_satchel", item_name) == 0) - { - } - - // check if entity is a snark (squeak grenade) - else if (strcmp("monster_snark", item_name) == 0) - { - } - - else if ((mod_id == FRONTLINE_DLL) && (!pBot->defender) && - (strcmp("capture_point", item_name) == 0)) - { - int team = UTIL_GetTeam(pEdict); // skin and team must match - - if (flf_bug_fix) - team = 1 - team; // BACKWARDS bug! - - // check if flag not set and point not captured... - if ((!pBot->b_use_capture) && (pent->v.skin == team)) - { - float distance = (pent->v.origin - pEdict->v.origin).Length( ); - - // check if close enough and facing it directly... - if ((distance < FLF_PLAYER_SEARCH_RADIUS) && - (angle_to_entity <= 20)) - { - pBot->b_use_capture = TRUE; - pBot->f_use_capture_time = gpGlobals->time + 8.0; - pBot->pCaptureEdict = pent; - } - - // if close to capture point... - if (distance < 160) - { - // don't avoid walls for a while - pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; - } - - can_pickup = TRUE; - } - } - - } // end if object is visible - } // end else not "func_" entity - - if (can_pickup) // if the bot found something it can pickup... - { - float distance = (entity_origin - pEdict->v.origin).Length( ); - - // see if it's the closest item so far... - if (distance < min_distance) - { - min_distance = distance; // update the minimum distance - pPickupEntity = pent; // remember this entity - pickup_origin = entity_origin; // remember location of entity - } - } - } // end while loop - - if (pPickupEntity != NULL) - { - // let's head off toward that item... - Vector v_item = pickup_origin - pEdict->v.origin; - - Vector bot_angles = UTIL_VecToAngles( v_item ); - - pEdict->v.ideal_yaw = bot_angles.y; - - BotFixIdealYaw(pEdict); - - pBot->pBotPickupItem = pPickupEntity; // save the item bot is trying to get - } -} - - -void BotThink( bot_t *pBot ) -{ - int index = 0; - Vector v_diff; // vector from previous to current location - float pitch_degrees; - float yaw_degrees; - float moved_distance; // length of v_diff vector (distance bot moved) - TraceResult tr; - bool found_waypoint; - bool is_idle; - - edict_t *pEdict = pBot->pEdict; - - - pEdict->v.flags |= FL_FAKECLIENT; - - if (pBot->name[0] == 0) // name filled in yet? - strcpy(pBot->name, STRING(pBot->pEdict->v.netname)); - - -// TheFatal - START from Advanced Bot Framework (Thanks Rich!) - - // adjust the millisecond delay based on the frame rate interval... - if (pBot->msecdel <= gpGlobals->time) - { - pBot->msecdel = gpGlobals->time + 0.5; - if (pBot->msecnum > 0) - pBot->msecval = 450.0/pBot->msecnum; - pBot->msecnum = 0; - } - else - pBot->msecnum++; - - if (pBot->msecval < 1) // don't allow msec to be less than 1... - pBot->msecval = 1; - - if (pBot->msecval > 100) // ...or greater than 100 - pBot->msecval = 100; - -// TheFatal - END - - - pEdict->v.button = 0; - pBot->f_move_speed = 0.0; - - if(pBot->mBotPlayMode == PLAYMODE_READYROOM) - { - // Look at desired team and head to nearest start entity - AvHClassType theClassType = AVH_CLASS_TYPE_UNDEFINED; - - FakeClientCommand(pEdict, kcAutoAssign, NULL, NULL); - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - } - - // if the bot hasn't selected stuff to start the game yet, go do that... - if (pBot->not_started) - { - BotStartGame( pBot ); - - // Do this to test server performance - //return; - - g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, 0.0, - 0, 0, pEdict->v.button, 0, pBot->msecval); - - //return; - } - - if((pBot->mOrderType != ORDERTYPE_UNDEFINED) && (!pBot->mOrderCompleted)) - { - // Every once in a while mention our order - if(RANDOM_LONG(0, 200) == 0) - { - char theMessage[256]; - sprintf(theMessage, "Order type: %d, target type: %d\n", pBot->mOrderType, pBot->mOrderTargetType); - //UTIL_HostSay(pBot->pEdict, 0, theMessage); - } - } - else - { - // Occasionally ask for orders when not doing anything else - if(RANDOM_LONG(0, 1800) == 0) - { - if(pBot->mTimeOfNextOrderRequest == -1) - { - pBot->mTimeOfNextOrderRequest = gpGlobals->time; - } - } - } - - if(RANDOM_LONG(0, 1000)) - { - pBot->mTimeOfNextRandomSaying = gpGlobals->time; - } - - // If we're out of ammo, occasionally ask for more - // Get current weapon - int theWeaponID = pBot->current_weapon.iId; - if(theWeaponID > 0) - { - if((pBot->current_weapon.iAmmo1 != -1) && (pBot->current_weapon.iClip <= 10)) - { - if(RANDOM_LONG(0, 40)) - { - if(pBot->mTimeOfNextAmmoRequest == -1) - { - pBot->mTimeOfNextAmmoRequest = gpGlobals->time; - } - } - } - } - - - if ((pBot->b_bot_say_killed) && (pBot->f_bot_say_killed < gpGlobals->time)) - { - int whine_index = 0; - bool used; - int i, recent_count; - char msg[120]; - - pBot->b_bot_say_killed = FALSE; - - recent_count = 0; - - while (recent_count < 5) - { - whine_index = RANDOM_LONG(0, whine_count-1); - - used = FALSE; - - for (i=0; i < 5; i++) - { - if (recent_bot_whine[i] == whine_index) - used = TRUE; - } - - if (used) - recent_count++; - else - break; - } - - for (i=4; i > 0; i--) - recent_bot_whine[i] = recent_bot_whine[i-1]; - - recent_bot_whine[0] = whine_index; - - if (strstr(bot_whine[whine_index], "%s") != NULL) // is "%s" in whine text? - sprintf(msg, bot_whine[whine_index], STRING(pBot->killer_edict->v.netname)); - else - sprintf(msg, bot_whine[whine_index]); - - UTIL_HostSay(pEdict, 0, msg); - } - - // if the bot is dead, randomly press fire to respawn... - if ((pEdict->v.health < 1) || (pEdict->v.deadflag != DEAD_NO)) - { - if (pBot->need_to_initialize) - { - BotSpawnInit(pBot); - - // did another player kill this bot AND bot whine messages loaded AND - // has the bot been alive for at least 15 seconds AND - if ((pBot->killer_edict != NULL) && (whine_count > 0) && - ((pBot->f_bot_spawn_time + 15.0) <= gpGlobals->time)) - { - if ((RANDOM_LONG(1,100) <= 10)) - { - pBot->b_bot_say_killed = TRUE; - pBot->f_bot_say_killed = gpGlobals->time + 10.0 + RANDOM_FLOAT(0.0, 5.0); - } - } - - pBot->need_to_initialize = FALSE; - } - - if (RANDOM_LONG(1, 100) > 50) - pEdict->v.button = IN_ATTACK; - - g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, pBot->f_move_speed, - 0, 0, pEdict->v.button, 0, pBot->msecval); - - return; - } - - // set this for the next time the bot dies so it will initialize stuff - if (pBot->need_to_initialize == FALSE) - { - pBot->need_to_initialize = TRUE; - pBot->f_bot_spawn_time = gpGlobals->time; - } - - is_idle = FALSE; - - if ((mod_id == FRONTLINE_DLL) && (pBot->round_end)) - { - if (pBot->warmup) // has warmup started (i.e. start of round?) - { - pBot->round_end = 0; - - BotSpawnInit(pBot); - } - - is_idle = TRUE; - - flf_bug_fix = 0; // BACKWARDS bug off now! - } - - if ((mod_id == FRONTLINE_DLL) && (pBot->warmup) && (!pBot->defender)) - { - if (pBot->curr_waypoint_index == -1) - { - // find the nearest visible waypoint - int i = WaypointFindNearest(pEdict, REACHABLE_RANGE, pBot->defender); - - if (i != -1) - { - Vector v_direction = waypoints[i].origin - pEdict->v.origin; - - Vector bot_angles = UTIL_VecToAngles( v_direction ); - - pBot->idle_angle = bot_angles.y; - } - else - pBot->idle_angle = pEdict->v.v_angle.y; - } - - is_idle = TRUE; - } - - if (pBot->blinded_time > gpGlobals->time) - { - is_idle = TRUE; // don't do anything while blinded - } - - if(CVAR_GET_FLOAT("freezebots") > 0) - { - return; // Don't move. - } - - if (is_idle) - { - if (pBot->idle_angle_time <= gpGlobals->time) - { - pBot->idle_angle_time = gpGlobals->time + RANDOM_FLOAT(0.5, 2.0); - - pEdict->v.ideal_yaw = pBot->idle_angle + RANDOM_FLOAT(0.0, 40.0) - 20.0; - - BotFixIdealYaw(pEdict); - } - - // turn towards ideal_yaw by yaw_speed degrees (slower than normal) - BotChangeYaw( pBot, pEdict->v.yaw_speed / 2 ); - - g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, pBot->f_move_speed, - 0, 0, pEdict->v.button, 0, pBot->msecval); - - return; - } - else - { - pBot->idle_angle = pEdict->v.v_angle.y; - } - - // check if time to check for player sounds (if don't already have enemy) - if ((pBot->f_sound_update_time <= gpGlobals->time) && - (pBot->pBotEnemy == NULL)) - { - int ind; - edict_t *pPlayer; - - pBot->f_sound_update_time = gpGlobals->time + 1.0; - - for (ind = 1; ind <= gpGlobals->maxClients; ind++) - { - pPlayer = INDEXENT(ind); - - // is this player slot is valid and it's not this bot... - if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) - { - // if observer mode enabled, don't listen to this player... - if ((b_observer_mode) && !(pPlayer->v.flags & FL_FAKECLIENT)) - continue; - - if (IsAlive(pPlayer) && - (FBitSet(pPlayer->v.flags, FL_CLIENT) || - FBitSet(pPlayer->v.flags, FL_FAKECLIENT))) - { - // check for sounds being made by other players... - if (UpdateSounds(pEdict, pPlayer)) - { - // don't check for sounds for another 30 seconds - pBot->f_sound_update_time = gpGlobals->time + 30.0; - } - } - } - } - } - - pBot->f_move_speed = pBot->f_max_speed; // set to max speed - - if (pBot->prev_time <= gpGlobals->time) - { - // see how far bot has moved since the previous position... - v_diff = pBot->v_prev_origin - pEdict->v.origin; - moved_distance = v_diff.Length(); - - // save current position as previous - pBot->v_prev_origin = pEdict->v.origin; - pBot->prev_time = gpGlobals->time + 0.2; - } - else - { - moved_distance = 2.0; - } - - // if the bot is under water, adjust pitch by pitch_speed degrees - if ((pEdict->v.waterlevel == 2) || - (pEdict->v.waterlevel == 3)) - { - // turn towards ideal_pitch by pitch_speed degrees - pitch_degrees = BotChangePitch( pBot, pEdict->v.pitch_speed ); - } - else - pitch_degrees = 0.0; - - // turn towards ideal_yaw by yaw_speed degrees - yaw_degrees = BotChangeYaw( pBot, pEdict->v.yaw_speed ); - - if ((pitch_degrees >= pEdict->v.pitch_speed) || - (yaw_degrees >= pEdict->v.yaw_speed)) - { - pBot->f_move_speed = 0.0; // don't move while turning a lot - } - else if ((pitch_degrees >= 10) || - (yaw_degrees >= 10)) // turning more than 10 degrees? - { - pBot->f_move_speed = pBot->f_move_speed / 4; // slow down while turning - } - else // else handle movement related actions... - { - if (b_botdontshoot == 0) - { - if ((mod_id == TFC_DLL) && (pBot->bot_has_flag == TRUE)) - { - // is it time to check whether bot should look for enemies yet? - if (pBot->f_bot_find_enemy_time <= gpGlobals->time) - { - pBot->f_bot_find_enemy_time = gpGlobals->time + 5.0; - - if (RANDOM_LONG(1, 100) <= 40) - pBot->pBotEnemy = BotFindEnemy( pBot ); - } - } - else - { - // Now that bots scan every entity in the world, do this less often - if(RANDOM_LONG(1, 100) <= 20) - { - pBot->pBotEnemy = BotFindEnemy( pBot ); - } - } - } - else - pBot->pBotEnemy = NULL; // clear enemy pointer (no ememy for you!) - - if (pBot->pBotEnemy != NULL) // does an enemy exist? - { - BotShootAtEnemy( pBot ); // shoot at the enemy - - pBot->f_pause_time = 0; // dont't pause if enemy exists - } - - else if (pBot->f_pause_time > gpGlobals->time) // is bot "paused"? - { - // you could make the bot look left then right, or look up - // and down, to make it appear that the bot is hunting for - // something (don't do anything right now) - } - - // is bot being "used" and can still follow "user"? - else if ((pBot->pBotUser != NULL) && BotFollowUser( pBot )) - { - // do nothing here! - ; - } - - else - { - // no enemy, let's just wander around... - - if ((pEdict->v.waterlevel != 2) && // is bot NOT under water? - (pEdict->v.waterlevel != 3)) - { - // reset pitch to 0 (level horizontally) - pEdict->v.idealpitch = 0; - pEdict->v.v_angle.x = 0; - } - - pEdict->v.v_angle.z = 0; // reset roll to 0 (straight up and down) - - pEdict->v.angles.x = 0; - pEdict->v.angles.y = pEdict->v.v_angle.y; - pEdict->v.angles.z = 0; - - // check if bot should look for items now or not... - if (pBot->f_find_item < gpGlobals->time) - { - BotFindItem( pBot ); // see if there are any visible items - } - - // check if bot sees a tripmine... - if (pBot->b_see_tripmine) - { - // check if bot can shoot the tripmine... - if ((pBot->b_shoot_tripmine) && BotShootTripmine( pBot )) - { - // shot at tripmine, may or may not have hit it, clear - // flags anyway, next BotFindItem will see it again if - // it is still there... - - pBot->b_shoot_tripmine = FALSE; - pBot->b_see_tripmine = FALSE; - - // pause for a while to allow tripmine to explode... - pBot->f_pause_time = gpGlobals->time + 0.5; - } - else // run away!!! - { - Vector tripmine_angles; - - tripmine_angles = UTIL_VecToAngles( pBot->v_tripmine - pEdict->v.origin ); - - // face away from the tripmine - pEdict->v.ideal_yaw += 180; // rotate 180 degrees - - BotFixIdealYaw(pEdict); - - pBot->b_see_tripmine = FALSE; - - pBot->f_move_speed = 0; // don't run while turning - } - } - - // check if should use wall mounted health station... - else if (pBot->b_use_health_station) - { - if ((pBot->f_use_health_time + 10.0) > gpGlobals->time) - { - pBot->f_move_speed = 0; // don't move while using health station - - pEdict->v.button = IN_USE; - } - else - { - // bot is stuck trying to "use" a health station... - - pBot->b_use_health_station = FALSE; - - // don't look for items for a while since the bot - // could be stuck trying to get to an item - pBot->f_find_item = gpGlobals->time + 0.5; - } - } - - // check if should use wall mounted HEV station... - else if (pBot->b_use_HEV_station) - { - if ((pBot->f_use_HEV_time + 10.0) > gpGlobals->time) - { - pBot->f_move_speed = 0; // don't move while using HEV station - - pEdict->v.button = IN_USE; - } - else - { - // bot is stuck trying to "use" a HEV station... - - pBot->b_use_HEV_station = FALSE; - - // don't look for items for a while since the bot - // could be stuck trying to get to an item - pBot->f_find_item = gpGlobals->time + 0.5; - } - } - - // check if should capture a point by using it... - else if (pBot->b_use_capture) - { - int team = UTIL_GetTeam(pEdict); // skin and team must match - - if (flf_bug_fix) - team = 1 - team; // BACKWARDS bug fix! - - // still capturing and hasn't captured yet... - if ((pBot->f_use_capture_time > gpGlobals->time) && - (pBot->pCaptureEdict->v.skin == team)) - { - pBot->f_move_speed = 0; // don't move while capturing - - pEdict->v.button = IN_USE; - } - else - { - // bot is stuck trying to "use" a capture point... - - pBot->b_use_capture = FALSE; - - // don't look for items for a while since the bot - // could be stuck trying to get to an item - pBot->f_find_item = gpGlobals->time + 0.5; - } - } - - else if (pBot->b_use_button) - { - pBot->f_move_speed = 0; // don't move while using elevator - - BotUseLift( pBot, moved_distance ); - } - - else - { - if (pEdict->v.waterlevel == 3) // check if the bot is underwater... - { - BotUnderWater( pBot ); - } - - found_waypoint = FALSE; - - // if the bot is not trying to get to something AND - // it is time to look for a waypoint AND - // there are waypoints in this level... - - if ((pBot->pBotPickupItem == NULL) && - (pBot->f_look_for_waypoint_time <= gpGlobals->time) && - (num_waypoints != 0)) - { - found_waypoint = BotHeadTowardWaypoint(pBot); - } - - // check if the bot is on a ladder... - if (pEdict->v.movetype == MOVETYPE_FLY) - { - // check if bot JUST got on the ladder... - if ((pBot->f_end_use_ladder_time + 1.0) < gpGlobals->time) - pBot->f_start_use_ladder_time = gpGlobals->time; - - // go handle the ladder movement - BotOnLadder( pBot, moved_distance ); - - pBot->f_dont_avoid_wall_time = gpGlobals->time + 2.0; - pBot->f_end_use_ladder_time = gpGlobals->time; - } - else - { - // check if the bot JUST got off the ladder... - if ((pBot->f_end_use_ladder_time + 1.0) > gpGlobals->time) - { - pBot->ladder_dir = LADDER_UNKNOWN; - } - } - - // if the bot isn't headed toward a waypoint... - if (found_waypoint == FALSE) - { - TraceResult tr; - - // check if we should be avoiding walls - if (pBot->f_dont_avoid_wall_time <= gpGlobals->time) - { - // let's just randomly wander around - if (BotStuckInCorner( pBot )) - { - pEdict->v.ideal_yaw += 180; // turn 180 degrees - - BotFixIdealYaw(pEdict); - - pBot->f_move_speed = 0; // don't move while turning - pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; - - moved_distance = 2.0; // dont use bot stuck code - } - else - { - // check if there is a wall on the left... - if (!BotCheckWallOnLeft( pBot )) - { - // if there was a wall on the left over 1/2 a second ago then - // 20% of the time randomly turn between 45 and 60 degrees - - if ((pBot->f_wall_on_left != 0) && - (pBot->f_wall_on_left <= gpGlobals->time - 0.5) && - (RANDOM_LONG(1, 100) <= 20)) - { - pEdict->v.ideal_yaw += RANDOM_LONG(45, 60); - - BotFixIdealYaw(pEdict); - - pBot->f_move_speed = 0; // don't move while turning - pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; - } - - pBot->f_wall_on_left = 0; // reset wall detect time - } - else if (!BotCheckWallOnRight( pBot )) - { - // if there was a wall on the right over 1/2 a second ago then - // 20% of the time randomly turn between 45 and 60 degrees - - if ((pBot->f_wall_on_right != 0) && - (pBot->f_wall_on_right <= gpGlobals->time - 0.5) && - (RANDOM_LONG(1, 100) <= 20)) - { - pEdict->v.ideal_yaw -= RANDOM_LONG(45, 60); - - BotFixIdealYaw(pEdict); - - pBot->f_move_speed = 0; // don't move while turning - pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; - } - - pBot->f_wall_on_right = 0; // reset wall detect time - } - } - } - - // check if bot is about to hit a wall. TraceResult gets returned - if ((pBot->f_dont_avoid_wall_time <= gpGlobals->time) && - BotCantMoveForward( pBot, &tr )) - { - // ADD LATER - // need to check if bot can jump up or duck under here... - // ADD LATER - - BotTurnAtWall( pBot, &tr ); - } - } - - // check if bot is on a ladder and has been on a ladder for - // more than 5 seconds... - if ((pEdict->v.movetype == MOVETYPE_FLY) && - (pBot->f_start_use_ladder_time > 0.0) && - ((pBot->f_start_use_ladder_time + 5.0) <= gpGlobals->time)) - { - // bot is stuck on a ladder... - - BotRandomTurn(pBot); - - // don't look for items for 2 seconds - pBot->f_find_item = gpGlobals->time + 2.0; - - pBot->f_start_use_ladder_time = 0.0; // reset start ladder time - } - - // check if the bot hasn't moved much since the last location - // (and NOT on a ladder since ladder stuck handled elsewhere) - // (don't check for stuck if f_dont_check_stuck in the future) - if ((moved_distance <= 1.0) && (pBot->prev_speed >= 1.0) && - (pEdict->v.movetype != MOVETYPE_FLY) && - (pBot->f_dont_check_stuck < gpGlobals->time)) - { - // the bot must be stuck! - - pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; - pBot->f_look_for_waypoint_time = gpGlobals->time + 1.0; - - if (BotCanJumpUp( pBot )) // can the bot jump onto something? - { - if ((pBot->f_jump_time + 2.0) <= gpGlobals->time) - { - pBot->f_jump_time = gpGlobals->time; - pEdict->v.button |= IN_JUMP; // jump up and move forward - } - else - { - // bot already tried jumping less than two seconds ago, just turn - BotRandomTurn(pBot); - } - } - else if (BotCanDuckUnder( pBot )) // can the bot duck under something? - { - pEdict->v.button |= IN_DUCK; // duck down and move forward - } - else - { - BotRandomTurn(pBot); - - // is the bot trying to get to an item?... - if (pBot->pBotPickupItem != NULL) - { - // don't look for items for a while since the bot - // could be stuck trying to get to an item - pBot->f_find_item = gpGlobals->time + 0.5; - } - } - } - - // should the bot pause for a while here? - // (don't pause on ladders or while being "used"... - if ((RANDOM_LONG(1, 1000) <= pause_frequency[pBot->bot_skill]) && - (pEdict->v.movetype != MOVETYPE_FLY) && - (pBot->pBotUser == NULL)) - { - // set the time that the bot will stop "pausing" - pBot->f_pause_time = gpGlobals->time + - RANDOM_FLOAT(pause_time[pBot->bot_skill][0], - pause_time[pBot->bot_skill][1]); - } - } - } - } - - // Potentially morph up if we're an alien - AvHUser3 theUser3 = (AvHUser3)(pBot->pEdict->v.iuser3); - if((pBot->pBotEnemy == NULL) && (theUser3 >= AVH_USER3_ALIEN_PLAYER1) && (theUser3 <= AVH_USER3_ALIEN_PLAYER4)) - { - int theMaxUpgrade = (int)(AVH_USER3_ALIEN_PLAYER5 - theUser3); - //const UpgradeCostListType& theUpgradeCosts = GetGameRules()->GetUpgradeCosts(); - - if(RANDOM_LONG(0, 400) == 0) - { - // Pick a random upgrade - AvHUser3 theMinUpgrade = (AvHUser3)(theUser3 + 1); - int theMaxUpgrade = AVH_USER3_ALIEN_PLAYER5; - AvHUser3 theUpgradeUser3 = (AvHUser3)(RANDOM_LONG((int)theMinUpgrade, (int)theMaxUpgrade)); - int thePointCost = 0; - AvHMessageID theMessage = MESSAGE_NULL; - switch(theUpgradeUser3) - { - case AVH_USER3_ALIEN_PLAYER2: - thePointCost = 15; - theMessage = ALIEN_LIFEFORM_TWO; - break; - case AVH_USER3_ALIEN_PLAYER3: - thePointCost = 30; - theMessage = ALIEN_LIFEFORM_THREE; - break; - case AVH_USER3_ALIEN_PLAYER4: - thePointCost = 50; - theMessage = ALIEN_LIFEFORM_FOUR; - break; - case AVH_USER3_ALIEN_PLAYER5: - thePointCost = 75; - theMessage = ALIEN_LIFEFORM_FIVE; - break; - } - - //thePointCost = GetGameRules()->GetPointCostForMessageID(theMessage); - - //if(pBot->mResources >= thePointCost) - //{ - pBot->pEdict->v.impulse = theMessage; - //} - } - - if(RANDOM_LONG(0, 75) == 0) - { - // Pick a random upgrade to try to "buy" - AvHMessageID theUpgrade = (AvHMessageID)(ALIEN_EVOLUTION_ONE + RANDOM_LONG(0, kNumAlienUpgrades-1)); - pBot->pEdict->v.impulse = theUpgrade; - } - } - - // TODO: Help build a nearby team structure - if(pBot->pBotEnemy == NULL && (theUser3 == AVH_USER3_MARINE_PLAYER)) - { - } - - if (pBot->curr_waypoint_index != -1) // does the bot have a waypoint? - { - // check if the next waypoint is a door waypoint... - if (waypoints[pBot->curr_waypoint_index].flags & W_FL_DOOR) - { - pBot->f_move_speed = pBot->f_max_speed / 3; // slow down for doors - } - - // check if the next waypoint is a ladder waypoint... - if (waypoints[pBot->curr_waypoint_index].flags & W_FL_LADDER) - { - // check if the waypoint is at the top of a ladder AND - // the bot isn't currenly on a ladder... - if ((pBot->waypoint_top_of_ladder) && - (pEdict->v.movetype != MOVETYPE_FLY)) - { - // is the bot on "ground" above the ladder? - if (pEdict->v.flags & FL_ONGROUND) - { - float waypoint_distance = (pEdict->v.origin - pBot->waypoint_origin).Length(); - - if (waypoint_distance <= 20.0) // if VERY close... - pBot->f_move_speed = 20.0; // go VERY slow - else if (waypoint_distance <= 100.0) // if fairly close... - pBot->f_move_speed = 50.0; // go fairly slow - - pBot->ladder_dir = LADDER_DOWN; - pBot->f_dont_check_stuck = gpGlobals->time + 1.0; - } - else // bot must be in mid-air, go BACKWARDS to touch ladder... - { - pBot->f_move_speed = -pBot->f_max_speed; - } - } - else - { - // don't avoid walls for a while - pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; - - pBot->waypoint_top_of_ladder = FALSE; - } - } - - // check if the next waypoint is a crouch waypoint... - if (waypoints[pBot->curr_waypoint_index].flags & W_FL_CROUCH) - pEdict->v.button |= IN_DUCK; // duck down while moving forward - - // check if the waypoint is a sniper waypoint AND - // bot isn't currently aiming at an ememy... - if ((waypoints[pBot->curr_waypoint_index].flags & W_FL_SNIPER) && - (pBot->pBotEnemy == NULL)) - { - if ((mod_id != TFC_DLL) || - ((mod_id == TFC_DLL) && (pEdict->v.playerclass == TFC_CLASS_SNIPER))) - { - // check if it's time to adjust aim yet... - if (pBot->f_sniper_aim_time <= gpGlobals->time) - { - int aim_index; - - aim_index = WaypointFindNearestAiming(waypoints[pBot->curr_waypoint_index].origin); - - if (aim_index != -1) - { - Vector v_aim = waypoints[aim_index].origin - waypoints[pBot->curr_waypoint_index].origin; - - Vector aim_angles = UTIL_VecToAngles( v_aim ); - - aim_angles.y += RANDOM_LONG(0, 30) - 15; - - pEdict->v.ideal_yaw = aim_angles.y; - - BotFixIdealYaw(pEdict); - } - - // don't adjust aim again until after a few seconds... - pBot->f_sniper_aim_time = gpGlobals->time + RANDOM_FLOAT(3.0, 5.0); - } - } - } - } - - // Process voice commands - BotProcessVoiceCommands(pBot); - - if (pBot->f_pause_time > gpGlobals->time) // is the bot "paused"? - pBot->f_move_speed = 0; // don't move while pausing - - // make the body face the same way the bot is looking - pEdict->v.angles.y = pEdict->v.v_angle.y; - - // save the previous speed (for checking if stuck) - pBot->prev_speed = pBot->f_move_speed; - - //CBaseEntity* theEntity = CBaseEntity::Instance(pEdict); - //CBasePlayer* thePlayer = (CBasePlayer*)(theEntity); - //thePlayer->PreThink(); - - g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, pBot->f_move_speed, - 0, 0, pEdict->v.button, 0, pBot->msecval); - - //thePlayer->PostThink(); - - return; -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot.cpp +// + +//#include "windows.h" +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" +#include "bot_func.h" +#include "waypoint.h" +#include "bot_weapons.h" + +#include +#include +#include "mod/AvHMarineEquipmentConstants.h" +#include "mod/AvHMessage.h" +#include "mod/AvHCommandConstants.h" +#include "mod/AvHMessage.h" +#include "mod/AvHPlayer.h" + +#ifndef __linux__ +extern HINSTANCE h_Library; +#else +extern void *h_Library; +#endif + + +extern int mod_id; +extern WAYPOINT waypoints[MAX_WAYPOINTS]; +extern int num_waypoints; // number of waypoints currently in use +extern int default_bot_skill; +extern edict_t *pent_info_ctfdetect; + +extern int max_team_players[4]; +extern int team_class_limits[4]; +extern int max_teams; +extern char bot_whine[MAX_BOT_WHINE][81]; +extern int whine_count; + +extern int flf_bug_fix; + +static FILE *fp; + + +#define PLAYER_SEARCH_RADIUS 40.0 +#define FLF_PLAYER_SEARCH_RADIUS 60.0 + + +bot_t bots[32]; // max of 32 bots in a game +bool b_observer_mode = FALSE; +bool b_botdontshoot = FALSE; + +extern int recent_bot_whine[5]; + +int number_names = 0; + +#define MAX_BOT_NAMES 100 + +#define VALVE_MAX_SKINS 10 +#define GEARBOX_MAX_SKINS 20 + +// indicate which models are currently used for random model allocation +bool valve_skin_used[VALVE_MAX_SKINS] = { + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; + +bool gearbox_skin_used[GEARBOX_MAX_SKINS] = { + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; + +// store the names of the models... +char *valve_bot_skins[VALVE_MAX_SKINS] = { + "barney", "gina", "gman", "gordon", "helmet", + "hgrunt", "recon", "robo", "scientist", "zombie"}; + +char *gearbox_bot_skins[GEARBOX_MAX_SKINS] = { + "barney", "beret", "cl_suit", "drill", "fassn", "gina", "gman", + "gordon", "grunt", "helmet", "hgrunt", "massn", "otis", "recon", + "recruit", "robo", "scientist", "shepard", "tower", "zombie"}; + +// store the player names for each of the models... +char *valve_bot_names[VALVE_MAX_SKINS] = { + "Barney", "Gina", "G-Man", "Gordon", "Helmet", + "H-Grunt", "Recon", "Robo", "Scientist", "Zombie"}; + +char *gearbox_bot_names[GEARBOX_MAX_SKINS] = { + "Barney", "Beret", "Cl_suit", "Drill", "Fassn", "Gina", "G-Man", + "Gordon", "Grunt", "Helmet", "H-Grunt", "Massn", "Otis", "Recon", + "Recruit", "Robo", "Scientist", "Shepard", "Tower", "Zombie"}; + +char bot_names[MAX_BOT_NAMES][BOT_NAME_LEN+1]; + +// how often (out of 1000 times) the bot will pause, based on bot skill +float pause_frequency[5] = {4, 7, 10, 15, 20}; + +float pause_time[5][2] = { + {0.2, 0.5}, {0.5, 1.0}, {0.7, 1.3}, {1.0, 1.7}, {1.2, 2.0}}; + + +inline edict_t *CREATE_FAKE_CLIENT( const char *netname ) +{ + return (*g_engfuncs.pfnCreateFakeClient)( netname ); +} + +inline char *GET_INFOBUFFER( edict_t *e ) +{ + return (*g_engfuncs.pfnGetInfoKeyBuffer)( e ); +} + +inline char *GET_INFO_KEY_VALUE( char *infobuffer, char *key ) +{ + return (g_engfuncs.pfnInfoKeyValue( infobuffer, key )); +} + +inline void SET_CLIENT_KEY_VALUE( int clientIndex, char *infobuffer, + char *key, char *value ) +{ + (*g_engfuncs.pfnSetClientKeyValue)( clientIndex, infobuffer, key, value ); +} + + +// this is the LINK_ENTITY_TO_CLASS function that creates a player (bot) +void player( entvars_t *pev ) +{ + static LINK_ENTITY_FUNC otherClassName = NULL; + if (otherClassName == NULL) + otherClassName = (LINK_ENTITY_FUNC)GetProcAddress(h_Library, "player"); + if (otherClassName != NULL) + { + (*otherClassName)(pev); + } +} + +void BotProcessVoiceCommands(bot_t* pBot) +{ + if((pBot->mTimeOfNextOrderRequest != -1) && (gpGlobals->time > pBot->mTimeOfNextOrderRequest)) + { + if(pBot->pEdict->v.impulse == 0) + { + pBot->pEdict->v.impulse = ORDER_REQUEST; + pBot->mTimeOfNextOrderRequest = -1; + } + } + if((pBot->mTimeOfNextAmmoRequest != -1) && (gpGlobals->time > pBot->mTimeOfNextAmmoRequest)) + { + if(pBot->pEdict->v.impulse == 0) + { + pBot->pEdict->v.impulse = SAYING_5; + pBot->mTimeOfNextAmmoRequest = -1; + } + } + if((pBot->mTimeOfNextRandomSaying != -1) && (gpGlobals->time > pBot->mTimeOfNextRandomSaying)) + { + if(pBot->pEdict->v.impulse == 0) + { + pBot->pEdict->v.impulse = SAYING_1 + g_engfuncs.pfnRandomLong(0, 5); + pBot->mTimeOfNextRandomSaying = -1; + } + } + if((pBot->mTimeOfNextTaunt != -1) && (gpGlobals->time > pBot->mTimeOfNextTaunt)) + { + if(pBot->pEdict->v.impulse == 0) + { + pBot->pEdict->v.impulse = SAYING_3; + pBot->mTimeOfNextTaunt = -1; + } + } + if((pBot->mTimeOfNextAcknowledge != -1) && (gpGlobals->time > pBot->mTimeOfNextAcknowledge)) + { + if(pBot->pEdict->v.impulse == 0) + { + pBot->pEdict->v.impulse = ORDER_ACK; + pBot->mTimeOfNextAcknowledge = -1; + } + } +} + +void BotSpawnInit( bot_t *pBot ) +{ + pBot->v_prev_origin = Vector(9999.0, 9999.0, 9999.0); + pBot->prev_time = gpGlobals->time; + + pBot->waypoint_origin = Vector(0, 0, 0); + pBot->f_waypoint_time = 0.0; + pBot->curr_waypoint_index = -1; + pBot->prev_waypoint_index[0] = -1; + pBot->prev_waypoint_index[1] = -1; + pBot->prev_waypoint_index[2] = -1; + pBot->prev_waypoint_index[3] = -1; + pBot->prev_waypoint_index[4] = -1; + + pBot->f_random_waypoint_time = gpGlobals->time; + pBot->waypoint_goal = -1; + pBot->f_waypoint_goal_time = 0.0; + pBot->waypoint_near_flag = FALSE; + pBot->waypoint_flag_origin = Vector(0, 0, 0); + pBot->prev_waypoint_distance = 0.0; + + pBot->msecnum = 0; + pBot->msecdel = 0.0; + pBot->msecval = 0.0; + + pBot->bot_health = 0; + pBot->bot_armor = 0; + pBot->bot_weapons = 0; + pBot->blinded_time = 0.0; + + // Init AvH variables + pBot->mBotPlayMode = PLAYMODE_READYROOM; + + pBot->mOrderState = 0; + pBot->mOrderNumPlayers = -1; + pBot->mOrderType = ORDERTYPE_UNDEFINED; + pBot->mOrderTargetType = ORDERTARGETTYPE_UNDEFINED; + pBot->mOrderLocation[0] = pBot->mOrderLocation[1] = pBot->mOrderLocation[2] = 0.0f; + pBot->mOrderTargetIndex = -1; + pBot->mOrderCompleted = false; + + pBot->mTimeOfNextAcknowledge = -1; + pBot->mTimeOfNextAmmoRequest = -1; + pBot->mTimeOfNextOrderRequest = -1; + pBot->mTimeOfNextTaunt = -1; + pBot->mTimeOfNextRandomSaying = -1; + + pBot->mGestateUser3 = AVH_USER3_NONE; + pBot->mResources = 0; + // end AvH variable init + + pBot->f_max_speed = CVAR_GET_FLOAT("sv_maxspeed"); + + pBot->prev_speed = 0.0; // fake "paused" since bot is NOT stuck + + pBot->f_find_item = 0.0; + + pBot->ladder_dir = LADDER_UNKNOWN; + pBot->f_start_use_ladder_time = 0.0; + pBot->f_end_use_ladder_time = 0.0; + pBot->waypoint_top_of_ladder = FALSE; + + pBot->f_wall_check_time = 0.0; + pBot->f_wall_on_right = 0.0; + pBot->f_wall_on_left = 0.0; + pBot->f_dont_avoid_wall_time = 0.0; + pBot->f_look_for_waypoint_time = 0.0; + pBot->f_jump_time = 0.0; + pBot->f_dont_check_stuck = 0.0; + + // pick a wander direction (50% of the time to the left, 50% to the right) + if (RANDOM_LONG(1, 100) <= 50) + pBot->wander_dir = WANDER_LEFT; + else + pBot->wander_dir = WANDER_RIGHT; + + pBot->f_exit_water_time = 0.0; + + pBot->pBotEnemy = NULL; + pBot->f_bot_see_enemy_time = gpGlobals->time; + pBot->f_bot_find_enemy_time = gpGlobals->time; + pBot->pBotUser = NULL; + pBot->f_bot_use_time = 0.0; + pBot->b_bot_say_killed = FALSE; + pBot->f_bot_say_killed = 0.0; + pBot->f_sniper_aim_time = 0.0; + + pBot->f_shoot_time = gpGlobals->time; + pBot->f_primary_charging = -1.0; + pBot->f_secondary_charging = -1.0; + pBot->charging_weapon_id = 0; + + pBot->f_pause_time = 0.0; + pBot->f_sound_update_time = 0.0; + pBot->bot_has_flag = FALSE; + + pBot->b_see_tripmine = FALSE; + pBot->b_shoot_tripmine = FALSE; + pBot->v_tripmine = Vector(0,0,0); + + pBot->b_use_health_station = FALSE; + pBot->f_use_health_time = 0.0; + pBot->b_use_HEV_station = FALSE; + pBot->f_use_HEV_time = 0.0; + + pBot->b_use_button = FALSE; + pBot->f_use_button_time = 0; + pBot->b_lift_moving = FALSE; + + pBot->b_use_capture = FALSE; + pBot->f_use_capture_time = 0.0; + pBot->pCaptureEdict = NULL; + + memset(&(pBot->current_weapon), 0, sizeof(pBot->current_weapon)); + memset(&(pBot->m_rgAmmo), 0, sizeof(pBot->m_rgAmmo)); +} + + +void BotNameInit( void ) +{ + FILE *bot_name_fp; + char bot_name_filename[256]; + int str_index; + char name_buffer[80]; + int length, index; + + UTIL_BuildFileName(bot_name_filename, "bot_names.txt", NULL); + + bot_name_fp = fopen(bot_name_filename, "r"); + + if (bot_name_fp != NULL) + { + while ((number_names < MAX_BOT_NAMES) && + (fgets(name_buffer, 80, bot_name_fp) != NULL)) + { + length = strlen(name_buffer); + + if (name_buffer[length-1] == '\n') + { + name_buffer[length-1] = 0; // remove '\n' + length--; + } + + str_index = 0; + while (str_index < length) + { + if ((name_buffer[str_index] < ' ') || (name_buffer[str_index] > '~') || + (name_buffer[str_index] == '"')) + for (index=str_index; index < length; index++) + name_buffer[index] = name_buffer[index+1]; + + str_index++; + } + + if (name_buffer[0] != 0) + { + strncpy(bot_names[number_names], name_buffer, BOT_NAME_LEN); + + number_names++; + } + } + + fclose(bot_name_fp); + } +} + + +void BotPickName( char *name_buffer ) +{ + int name_index, index; + bool used; + edict_t *pPlayer; + int attempts = 0; + + // see if a name exists from a kicked bot (if so, reuse it) + for (index=0; index < 32; index++) + { + if ((bots[index].is_used == FALSE) && (bots[index].name[0])) + { + strcpy(name_buffer, bots[index].name); + + return; + } + } + + name_index = RANDOM_LONG(1, number_names) - 1; // zero based + + // check make sure this name isn't used + used = TRUE; + + while (used) + { + used = FALSE; + + for (index = 1; index <= gpGlobals->maxClients; index++) + { + pPlayer = INDEXENT(index); + + if (pPlayer && !pPlayer->free) + { + if (strcmp(bot_names[name_index], STRING(pPlayer->v.netname)) == 0) + { + used = TRUE; + break; + } + } + } + + if (used) + { + name_index++; + + if (name_index == number_names) + name_index = 0; + + attempts++; + + if (attempts == number_names) + used = FALSE; // break out of loop even if already used + } + } + + strcpy(name_buffer, bot_names[name_index]); +} + + +void BotCreate( edict_t *pPlayer, const char *arg1, const char *arg2, + const char *arg3, const char *arg4) +{ + edict_t *BotEnt; + bot_t *pBot; + char c_skin[BOT_SKIN_LEN+1]; + char c_name[BOT_NAME_LEN+1]; + int skill; + int index; + int i, j, length; + bool found = FALSE; + + + if ((mod_id == VALVE_DLL) || + ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect == NULL))) + { + int max_skin_index; + + if (mod_id == VALVE_DLL) + max_skin_index = VALVE_MAX_SKINS; + else // must be GEARBOX_DLL + max_skin_index = GEARBOX_MAX_SKINS; + + if ((arg1 == NULL) || (*arg1 == 0)) + { + bool *pSkinUsed; + + // pick a random skin + if (mod_id == VALVE_DLL) + { + index = RANDOM_LONG(0, VALVE_MAX_SKINS-1); + pSkinUsed = &valve_skin_used[0]; + } + else // must be GEARBOX_DLL + { + index = RANDOM_LONG(0, GEARBOX_MAX_SKINS-1); + pSkinUsed = &gearbox_skin_used[0]; + } + + // check if this skin has already been used... + while (pSkinUsed[index] == TRUE) + { + index++; + + if (index == max_skin_index) + index = 0; + } + + pSkinUsed[index] = TRUE; + + // check if all skins are now used... + for (i = 0; i < max_skin_index; i++) + { + if (pSkinUsed[i] == FALSE) + break; + } + + // if all skins are used, reset used to FALSE for next selection + if (i == max_skin_index) + { + for (i = 0; i < max_skin_index; i++) + pSkinUsed[i] = FALSE; + } + + if (mod_id == VALVE_DLL) + strcpy( c_skin, valve_bot_skins[index] ); + else // must be GEARBOX_DLL + strcpy( c_skin, gearbox_bot_skins[index] ); + } + else + { + strncpy( c_skin, arg1, BOT_SKIN_LEN-1 ); + c_skin[BOT_SKIN_LEN] = 0; // make sure c_skin is null terminated + } + + for (i = 0; c_skin[i] != 0; i++) + c_skin[i] = tolower( c_skin[i] ); // convert to all lowercase + + index = 0; + + while ((!found) && (index < max_skin_index)) + { + if (mod_id == VALVE_DLL) + { + if (strcmp(c_skin, valve_bot_skins[index]) == 0) + found = TRUE; + else + index++; + } + else // must be GEARBOX_DLL + { + if (strcmp(c_skin, gearbox_bot_skins[index]) == 0) + found = TRUE; + else + index++; + } + } + + if (found == TRUE) + { + if ((arg2 != NULL) && (*arg2 != 0)) + { + strncpy( c_name, arg2, BOT_SKIN_LEN-1 ); + c_name[BOT_SKIN_LEN] = 0; // make sure c_name is null terminated + } + else + { + if (number_names > 0) + BotPickName( c_name ); + else if (mod_id == VALVE_DLL) + strcpy( c_name, valve_bot_names[index] ); + else // must be GEARBOX_DLL + strcpy( c_name, gearbox_bot_names[index] ); + } + } + else + { + char dir_name[32]; + char filename[128]; + + struct stat stat_str; + + GET_GAME_DIR(dir_name); + +#ifndef __linux__ + sprintf(filename, "%s\\models\\player\\%s", dir_name, c_skin); +#else + sprintf(filename, "%s/models/player/%s", dir_name, c_skin); +#endif + + if (stat(filename, &stat_str) != 0) + { +#ifndef __linux__ + sprintf(filename, "valve\\models\\player\\%s", c_skin); +#else + sprintf(filename, "valve/models/player/%s", c_skin); +#endif + if (stat(filename, &stat_str) != 0) + { + char err_msg[80]; + + sprintf( err_msg, "model \"%s\" is unknown.\n", c_skin ); + if (pPlayer) + ClientPrint(pPlayer, HUD_PRINTNOTIFY, err_msg ); + if (IS_DEDICATED_SERVER()) + printf(err_msg); + + if (pPlayer) + ClientPrint(pPlayer, HUD_PRINTNOTIFY, + "use barney, gina, gman, gordon, helmet, hgrunt,\n"); + if (IS_DEDICATED_SERVER()) + printf("use barney, gina, gman, gordon, helmet, hgrunt,\n"); + if (pPlayer) + ClientPrint(pPlayer, HUD_PRINTNOTIFY, + " recon, robo, scientist, or zombie\n"); + if (IS_DEDICATED_SERVER()) + printf(" recon, robo, scientist, or zombie\n"); + return; + } + } + + if ((arg2 != NULL) && (*arg2 != 0)) + { + strncpy( c_name, arg2, BOT_NAME_LEN-1 ); + c_name[BOT_NAME_LEN] = 0; // make sure c_name is null terminated + } + else + { + if (number_names > 0) + BotPickName( c_name ); + else + { + // copy the name of the model to the bot's name... + strncpy( c_name, arg1, BOT_NAME_LEN-1 ); + c_name[BOT_NAME_LEN] = 0; // make sure c_skin is null terminated + } + } + } + + skill = 0; + + if ((arg3 != NULL) && (*arg3 != 0)) + skill = atoi(arg3); + + if ((skill < 1) || (skill > 5)) + skill = default_bot_skill; + } + else + { + if ((arg3 != NULL) && (*arg3 != 0)) + { + strncpy( c_name, arg3, BOT_NAME_LEN-1 ); + c_name[BOT_NAME_LEN] = 0; // make sure c_name is null terminated + } + else + { + if (number_names > 0) + BotPickName( c_name ); + else + strcpy(c_name, "Bot"); + } + + skill = 0; + + if ((arg4 != NULL) && (*arg4 != 0)) + skill = atoi(arg4); + + if ((skill < 1) || (skill > 5)) + skill = default_bot_skill; + } + + length = strlen(c_name); + + // remove any illegal characters from name... + for (i = 0; i < length; i++) + { + if ((c_name[i] <= ' ') || (c_name[i] > '~') || + (c_name[i] == '"')) + { + for (j = i; j < length; j++) // shuffle chars left (and null) + c_name[j] = c_name[j+1]; + length--; + } + } + + BotEnt = CREATE_FAKE_CLIENT( c_name ); + + if (FNullEnt( BotEnt )) + { + if (pPlayer) + ClientPrint( pPlayer, HUD_PRINTNOTIFY, "Max. Players reached. Can't create bot!\n"); + } + else + { + char ptr[128]; // allocate space for message from ClientConnect + char *infobuffer; + int clientIndex; + int index; + + if (IS_DEDICATED_SERVER()) + printf("Creating bot...\n"); + else if (pPlayer) + ClientPrint( pPlayer, HUD_PRINTNOTIFY, "Creating bot...\n"); + + index = 0; + while ((bots[index].is_used) && (index < 32)) + index++; + + if (index == 32) + { + ClientPrint( pPlayer, HUD_PRINTNOTIFY, "Can't create bot!\n"); + return; + } + + // create the player entity by calling MOD's player function + // (from LINK_ENTITY_TO_CLASS for player object) + + player( VARS(BotEnt) ); + + infobuffer = GET_INFOBUFFER( BotEnt ); + clientIndex = ENTINDEX( BotEnt ); + + + if ((mod_id == VALVE_DLL) || (mod_id == GEARBOX_DLL)) + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "model", c_skin ); + else // other mods + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "model", "gina" ); + + if (mod_id == CSTRIKE_DLL) + { + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "rate", "3500.000000"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_updaterate", "20"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_lw", "1"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_lc", "1"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "tracker", "0"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "cl_dlmax", "128"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "lefthand", "1"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "friends", "0"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "dm", "0"); + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "ah", "1"); + } + + ClientConnect( BotEnt, c_name, "127.0.0.1", ptr ); + + // Pieter van Dijk - use instead of DispatchSpawn() - Hip Hip Hurray! + ClientPutInServer( BotEnt ); + + BotEnt->v.flags |= FL_FAKECLIENT; + + // initialize all the variables for this bot... + + pBot = &bots[index]; + + pBot->is_used = TRUE; + pBot->respawn_state = RESPAWN_IDLE; + pBot->create_time = gpGlobals->time; + pBot->name[0] = 0; // name not set by server yet + pBot->bot_money = 0; + + strcpy(pBot->skin, c_skin); + + pBot->pEdict = BotEnt; + + pBot->not_started = 1; // hasn't joined game yet + + if (mod_id == TFC_DLL) + pBot->start_action = MSG_TFC_IDLE; + else if (mod_id == CSTRIKE_DLL) + pBot->start_action = MSG_CS_IDLE; + else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) + pBot->start_action = MSG_OPFOR_IDLE; + else if (mod_id == FRONTLINE_DLL) + pBot->start_action = MSG_FLF_IDLE; + else if (mod_id == AVH_DLL) + pBot->start_action = MSG_AVH_IDLE; + else + pBot->start_action = 0; // not needed for non-team MODs + + + BotSpawnInit(pBot); + + pBot->need_to_initialize = FALSE; // don't need to initialize yet + + BotEnt->v.idealpitch = BotEnt->v.v_angle.x; + BotEnt->v.ideal_yaw = BotEnt->v.v_angle.y; + BotEnt->v.pitch_speed = BOT_PITCH_SPEED; + BotEnt->v.yaw_speed = BOT_YAW_SPEED; + + pBot->warmup = 0; // for Front Line Force + pBot->idle_angle = 0.0; + pBot->idle_angle_time = 0.0; + pBot->round_end = 0; + pBot->defender = 0; + + pBot->bot_skill = skill - 1; // 0 based for array indexes + + pBot->bot_team = -1; + pBot->bot_class = -1; + + if ((mod_id == TFC_DLL) || (mod_id == CSTRIKE_DLL) || + ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) || + (mod_id == FRONTLINE_DLL)) + { + if ((arg1 != NULL) && (arg1[0] != 0)) + { + pBot->bot_team = atoi(arg1); + + if ((arg2 != NULL) && (arg2[0] != 0)) + { + pBot->bot_class = atoi(arg2); + } + } + } + } +} + + +int BotInFieldOfView(bot_t *pBot, Vector dest) +{ + // find angles from source to destination... + Vector entity_angles = UTIL_VecToAngles( dest ); + + // make yaw angle 0 to 360 degrees if negative... + if (entity_angles.y < 0) + entity_angles.y += 360; + + // get bot's current view angle... + float view_angle = pBot->pEdict->v.v_angle.y; + + // make view angle 0 to 360 degrees if negative... + if (view_angle < 0) + view_angle += 360; + + // return the absolute value of angle to destination entity + // zero degrees means straight ahead, 45 degrees to the left or + // 45 degrees to the right is the limit of the normal view angle + + // rsm - START angle bug fix + int angle = abs((int)view_angle - (int)entity_angles.y); + + if (angle > 180) + angle = 360 - angle; + + return angle; + // rsm - END +} + + +bool BotEntityIsVisible( bot_t *pBot, Vector dest ) +{ + TraceResult tr; + + // trace a line from bot's eyes to destination... + UTIL_TraceLine( pBot->pEdict->v.origin + pBot->pEdict->v.view_ofs, + dest, ignore_monsters, + pBot->pEdict->v.pContainingEntity, &tr ); + + // check if line of sight to object is not blocked (i.e. visible) + if (tr.flFraction >= 1.0) + return TRUE; + else + return FALSE; +} + + +void BotFindItem( bot_t *pBot ) +{ + edict_t *pent = NULL; + edict_t *pPickupEntity = NULL; + Vector pickup_origin; + Vector entity_origin; + float radius = 500; + bool can_pickup; + float min_distance; + char item_name[40]; + TraceResult tr; + Vector vecStart; + Vector vecEnd; + int angle_to_entity; + edict_t *pEdict = pBot->pEdict; + + pBot->pBotPickupItem = NULL; + + // use a MUCH smaller search radius when waypoints are available + if ((num_waypoints > 0) && (pBot->curr_waypoint_index != -1)) + radius = 100.0; + else + radius = 500.0; + + min_distance = radius + 1.0; + + while ((pent = UTIL_FindEntityInSphere( pent, pEdict->v.origin, radius )) != NULL) + { + can_pickup = FALSE; // assume can't use it until known otherwise + + strcpy(item_name, STRING(pent->v.classname)); + + // see if this is a "func_" type of entity (func_button, etc.)... + if (strncmp("func_", item_name, 5) == 0) + { + // BModels have 0,0,0 for origin so must use VecBModelOrigin... + entity_origin = VecBModelOrigin(pent); + + vecStart = pEdict->v.origin + pEdict->v.view_ofs; + vecEnd = entity_origin; + + angle_to_entity = BotInFieldOfView( pBot, vecEnd - vecStart ); + + // check if entity is outside field of view (+/- 45 degrees) + if (angle_to_entity > 45) + continue; // skip this item if bot can't "see" it + + // check if entity is a ladder (ladders are a special case) + // DON'T search for ladders if there are waypoints in this level... + if ((strcmp("func_ladder", item_name) == 0) && (num_waypoints == 0)) + { + // force ladder origin to same z coordinate as bot since + // the VecBModelOrigin is the center of the ladder. For + // LONG ladders, the center MAY be hundreds of units above + // the bot. Fake an origin at the same level as the bot... + + entity_origin.z = pEdict->v.origin.z; + vecEnd = entity_origin; + + // trace a line from bot's eyes to func_ladder entity... + UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // check if traced all the way up to the entity (didn't hit wall) + if (tr.flFraction >= 1.0) + { + // find distance to item for later use... + float distance = (vecEnd - vecStart).Length( ); + + // use the ladder about 100% of the time, if haven't + // used a ladder in at least 5 seconds... + if ((RANDOM_LONG(1, 100) <= 100) && + ((pBot->f_end_use_ladder_time + 5.0) < gpGlobals->time)) + { + // if close to ladder... + if (distance < 100) + { + // don't avoid walls for a while + pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; + } + + can_pickup = TRUE; + } + } + } + else + { + // trace a line from bot's eyes to func_ entity... + UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // check if traced all the way up to the entity (didn't hit wall) + if (strcmp(item_name, STRING(tr.pHit->v.classname)) == 0) + { + // find distance to item for later use... + float distance = (vecEnd - vecStart).Length( ); + + // check if entity is wall mounted health charger... + if (strcmp("func_healthcharger", item_name) == 0) + { + // check if the bot can use this item and + // check if the recharger is ready to use (has power left)... + if ((pEdict->v.health < 100) && (pent->v.frame == 0)) + { + // check if flag not set... + if (!pBot->b_use_health_station) + { + // check if close enough and facing it directly... + if ((distance < PLAYER_SEARCH_RADIUS) && + (angle_to_entity <= 10)) + { + pBot->b_use_health_station = TRUE; + pBot->f_use_health_time = gpGlobals->time; + } + + // if close to health station... + if (distance < 100) + { + // don't avoid walls for a while + pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; + } + + can_pickup = TRUE; + } + } + else + { + // don't need or can't use this item... + pBot->b_use_health_station = FALSE; + } + } + + // check if entity is wall mounted HEV charger... + else if (strcmp("func_recharge", item_name) == 0) + { + // check if the bot can use this item and + // check if the recharger is ready to use (has power left)... + if ((pEdict->v.armorvalue < VALVE_MAX_NORMAL_BATTERY) && + (pent->v.frame == 0)) + { + // check if flag not set and facing it... + if (!pBot->b_use_HEV_station) + { + // check if close enough and facing it directly... + if ((distance < PLAYER_SEARCH_RADIUS) && + (angle_to_entity <= 10)) + { + pBot->b_use_HEV_station = TRUE; + pBot->f_use_HEV_time = gpGlobals->time; + } + + // if close to HEV recharger... + if (distance < 100) + { + // don't avoid walls for a while + pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; + } + + can_pickup = TRUE; + } + } + else + { + // don't need or can't use this item... + pBot->b_use_HEV_station = FALSE; + } + } + + // check if entity is a button... + else if (strcmp("func_button", item_name) == 0) + { + // use the button about 100% of the time, if haven't + // used a button in at least 5 seconds... + if ((RANDOM_LONG(1, 100) <= 100) && + ((pBot->f_use_button_time + 5) < gpGlobals->time)) + { + // check if flag not set and facing it... + if (!pBot->b_use_button) + { + // check if close enough and facing it directly... + if ((distance < PLAYER_SEARCH_RADIUS) && + (angle_to_entity <= 10)) + { + pBot->b_use_button = TRUE; + pBot->b_lift_moving = FALSE; + pBot->f_use_button_time = gpGlobals->time; + } + + // if close to button... + if (distance < 100) + { + // don't avoid walls for a while + pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; + } + + can_pickup = TRUE; + } + } + else + { + // don't need or can't use this item... + pBot->b_use_button = FALSE; + } + } + } + } + } + else // everything else... + { + entity_origin = pent->v.origin; + + vecStart = pEdict->v.origin + pEdict->v.view_ofs; + vecEnd = entity_origin; + + // find angles from bot origin to entity... + angle_to_entity = BotInFieldOfView( pBot, vecEnd - vecStart ); + + // check if entity is outside field of view (+/- 45 degrees) + if (angle_to_entity > 45) + continue; // skip this item if bot can't "see" it + + // check if line of sight to object is not blocked (i.e. visible) + if (BotEntityIsVisible( pBot, vecEnd )) + { + // check if entity is a weapon... + if (strncmp("weapon_", item_name, 7) == 0) + { + if (pent->v.effects & EF_NODRAW) + { + // someone owns this weapon or it hasn't respawned yet + continue; + } + + can_pickup = TRUE; + } + + // check if entity is ammo... + else if (strncmp("ammo_", item_name, 5) == 0) + { + // check if the item is not visible (i.e. has not respawned) + if (pent->v.effects & EF_NODRAW) + continue; + + can_pickup = TRUE; + } + + // check if entity is a battery... + else if (strcmp("item_battery", item_name) == 0) + { + // check if the item is not visible (i.e. has not respawned) + if (pent->v.effects & EF_NODRAW) + continue; + + // check if the bot can use this item... + if (pEdict->v.armorvalue < VALVE_MAX_NORMAL_BATTERY) + { + can_pickup = TRUE; + } + } + + // check if entity is a healthkit... + else if (strcmp("item_healthkit", item_name) == 0) + { + // check if the item is not visible (i.e. has not respawned) + if (pent->v.effects & EF_NODRAW) + continue; + + // check if the bot can use this item... + if (pEdict->v.health < 100) + { + can_pickup = TRUE; + } + } + + // check if entity is a packed up weapons box... + else if (strcmp("weaponbox", item_name) == 0) + { + can_pickup = TRUE; + } + + // check if entity is the spot from RPG laser + else if (strcmp("laser_spot", item_name) == 0) + { + } + + // check if entity is an armed tripmine + //else if (strcmp("monster_tripmine", item_name) == 0) + else if (strcmp(kwsDeployedMine, item_name) == 0) + { + float distance = (pent->v.origin - pEdict->v.origin).Length( ); + + if (pBot->b_see_tripmine) + { + // see if this tripmine is closer to bot... + if (distance < (pBot->v_tripmine - pEdict->v.origin).Length()) + { + pBot->v_tripmine = pent->v.origin; + pBot->b_shoot_tripmine = FALSE; + + // see if bot is far enough to shoot the tripmine... + if (distance >= 375) + { + pBot->b_shoot_tripmine = TRUE; + } + } + } + else + { + pBot->b_see_tripmine = TRUE; + pBot->v_tripmine = pent->v.origin; + pBot->b_shoot_tripmine = FALSE; + + // see if bot is far enough to shoot the tripmine... + if (distance >= 375) // 375 is damage radius + { + pBot->b_shoot_tripmine = TRUE; + } + } + } + + // check if entity is an armed satchel charge + else if (strcmp("monster_satchel", item_name) == 0) + { + } + + // check if entity is a snark (squeak grenade) + else if (strcmp("monster_snark", item_name) == 0) + { + } + + else if ((mod_id == FRONTLINE_DLL) && (!pBot->defender) && + (strcmp("capture_point", item_name) == 0)) + { + int team = UTIL_GetTeam(pEdict); // skin and team must match + + if (flf_bug_fix) + team = 1 - team; // BACKWARDS bug! + + // check if flag not set and point not captured... + if ((!pBot->b_use_capture) && (pent->v.skin == team)) + { + float distance = (pent->v.origin - pEdict->v.origin).Length( ); + + // check if close enough and facing it directly... + if ((distance < FLF_PLAYER_SEARCH_RADIUS) && + (angle_to_entity <= 20)) + { + pBot->b_use_capture = TRUE; + pBot->f_use_capture_time = gpGlobals->time + 8.0; + pBot->pCaptureEdict = pent; + } + + // if close to capture point... + if (distance < 160) + { + // don't avoid walls for a while + pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; + } + + can_pickup = TRUE; + } + } + + } // end if object is visible + } // end else not "func_" entity + + if (can_pickup) // if the bot found something it can pickup... + { + float distance = (entity_origin - pEdict->v.origin).Length( ); + + // see if it's the closest item so far... + if (distance < min_distance) + { + min_distance = distance; // update the minimum distance + pPickupEntity = pent; // remember this entity + pickup_origin = entity_origin; // remember location of entity + } + } + } // end while loop + + if (pPickupEntity != NULL) + { + // let's head off toward that item... + Vector v_item = pickup_origin - pEdict->v.origin; + + Vector bot_angles = UTIL_VecToAngles( v_item ); + + pEdict->v.ideal_yaw = bot_angles.y; + + BotFixIdealYaw(pEdict); + + pBot->pBotPickupItem = pPickupEntity; // save the item bot is trying to get + } +} + + +void BotThink( bot_t *pBot ) +{ + int index = 0; + Vector v_diff; // vector from previous to current location + float pitch_degrees; + float yaw_degrees; + float moved_distance; // length of v_diff vector (distance bot moved) + TraceResult tr; + bool found_waypoint; + bool is_idle; + + edict_t *pEdict = pBot->pEdict; + + + pEdict->v.flags |= FL_FAKECLIENT; + + if (pBot->name[0] == 0) // name filled in yet? + strcpy(pBot->name, STRING(pBot->pEdict->v.netname)); + + +// TheFatal - START from Advanced Bot Framework (Thanks Rich!) + + // adjust the millisecond delay based on the frame rate interval... + if (pBot->msecdel <= gpGlobals->time) + { + pBot->msecdel = gpGlobals->time + 0.5; + if (pBot->msecnum > 0) + pBot->msecval = 450.0/pBot->msecnum; + pBot->msecnum = 0; + } + else + pBot->msecnum++; + + if (pBot->msecval < 1) // don't allow msec to be less than 1... + pBot->msecval = 1; + + if (pBot->msecval > 100) // ...or greater than 100 + pBot->msecval = 100; + +// TheFatal - END + + + pEdict->v.button = 0; + pBot->f_move_speed = 0.0; + + if(pBot->mBotPlayMode == PLAYMODE_READYROOM) + { + // Look at desired team and head to nearest start entity + AvHClassType theClassType = AVH_CLASS_TYPE_UNDEFINED; + + FakeClientCommand(pEdict, kcAutoAssign, NULL, NULL); + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + } + + // if the bot hasn't selected stuff to start the game yet, go do that... + if (pBot->not_started) + { + BotStartGame( pBot ); + + // Do this to test server performance + //return; + + g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, 0.0, + 0, 0, pEdict->v.button, 0, pBot->msecval); + + //return; + } + + if((pBot->mOrderType != ORDERTYPE_UNDEFINED) && (!pBot->mOrderCompleted)) + { + // Every once in a while mention our order + if(RANDOM_LONG(0, 200) == 0) + { + char theMessage[256]; + sprintf(theMessage, "Order type: %d, target type: %d\n", pBot->mOrderType, pBot->mOrderTargetType); + //UTIL_HostSay(pBot->pEdict, 0, theMessage); + } + } + else + { + // Occasionally ask for orders when not doing anything else + if(RANDOM_LONG(0, 1800) == 0) + { + if(pBot->mTimeOfNextOrderRequest == -1) + { + pBot->mTimeOfNextOrderRequest = gpGlobals->time; + } + } + } + + if(RANDOM_LONG(0, 1000)) + { + pBot->mTimeOfNextRandomSaying = gpGlobals->time; + } + + // If we're out of ammo, occasionally ask for more + // Get current weapon + int theWeaponID = pBot->current_weapon.iId; + if(theWeaponID > 0) + { + if((pBot->current_weapon.iAmmo1 != -1) && (pBot->current_weapon.iClip <= 10)) + { + if(RANDOM_LONG(0, 40)) + { + if(pBot->mTimeOfNextAmmoRequest == -1) + { + pBot->mTimeOfNextAmmoRequest = gpGlobals->time; + } + } + } + } + + + if ((pBot->b_bot_say_killed) && (pBot->f_bot_say_killed < gpGlobals->time)) + { + int whine_index = 0; + bool used; + int i, recent_count; + char msg[120]; + + pBot->b_bot_say_killed = FALSE; + + recent_count = 0; + + while (recent_count < 5) + { + whine_index = RANDOM_LONG(0, whine_count-1); + + used = FALSE; + + for (i=0; i < 5; i++) + { + if (recent_bot_whine[i] == whine_index) + used = TRUE; + } + + if (used) + recent_count++; + else + break; + } + + for (i=4; i > 0; i--) + recent_bot_whine[i] = recent_bot_whine[i-1]; + + recent_bot_whine[0] = whine_index; + + if (strstr(bot_whine[whine_index], "%s") != NULL) // is "%s" in whine text? + sprintf(msg, bot_whine[whine_index], STRING(pBot->killer_edict->v.netname)); + else + sprintf(msg, bot_whine[whine_index]); + + UTIL_HostSay(pEdict, 0, msg); + } + + // if the bot is dead, randomly press fire to respawn... + if ((pEdict->v.health < 1) || (pEdict->v.deadflag != DEAD_NO)) + { + if (pBot->need_to_initialize) + { + BotSpawnInit(pBot); + + // did another player kill this bot AND bot whine messages loaded AND + // has the bot been alive for at least 15 seconds AND + if ((pBot->killer_edict != NULL) && (whine_count > 0) && + ((pBot->f_bot_spawn_time + 15.0) <= gpGlobals->time)) + { + if ((RANDOM_LONG(1,100) <= 10)) + { + pBot->b_bot_say_killed = TRUE; + pBot->f_bot_say_killed = gpGlobals->time + 10.0 + RANDOM_FLOAT(0.0, 5.0); + } + } + + pBot->need_to_initialize = FALSE; + } + + if (RANDOM_LONG(1, 100) > 50) + pEdict->v.button = IN_ATTACK; + + g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, pBot->f_move_speed, + 0, 0, pEdict->v.button, 0, pBot->msecval); + + return; + } + + // set this for the next time the bot dies so it will initialize stuff + if (pBot->need_to_initialize == FALSE) + { + pBot->need_to_initialize = TRUE; + pBot->f_bot_spawn_time = gpGlobals->time; + } + + is_idle = FALSE; + + if ((mod_id == FRONTLINE_DLL) && (pBot->round_end)) + { + if (pBot->warmup) // has warmup started (i.e. start of round?) + { + pBot->round_end = 0; + + BotSpawnInit(pBot); + } + + is_idle = TRUE; + + flf_bug_fix = 0; // BACKWARDS bug off now! + } + + if ((mod_id == FRONTLINE_DLL) && (pBot->warmup) && (!pBot->defender)) + { + if (pBot->curr_waypoint_index == -1) + { + // find the nearest visible waypoint + int i = WaypointFindNearest(pEdict, REACHABLE_RANGE, pBot->defender); + + if (i != -1) + { + Vector v_direction = waypoints[i].origin - pEdict->v.origin; + + Vector bot_angles = UTIL_VecToAngles( v_direction ); + + pBot->idle_angle = bot_angles.y; + } + else + pBot->idle_angle = pEdict->v.v_angle.y; + } + + is_idle = TRUE; + } + + if (pBot->blinded_time > gpGlobals->time) + { + is_idle = TRUE; // don't do anything while blinded + } + + if(CVAR_GET_FLOAT("freezebots") > 0) + { + return; // Don't move. + } + + if (is_idle) + { + if (pBot->idle_angle_time <= gpGlobals->time) + { + pBot->idle_angle_time = gpGlobals->time + RANDOM_FLOAT(0.5, 2.0); + + pEdict->v.ideal_yaw = pBot->idle_angle + RANDOM_FLOAT(0.0, 40.0) - 20.0; + + BotFixIdealYaw(pEdict); + } + + // turn towards ideal_yaw by yaw_speed degrees (slower than normal) + BotChangeYaw( pBot, pEdict->v.yaw_speed / 2 ); + + g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, pBot->f_move_speed, + 0, 0, pEdict->v.button, 0, pBot->msecval); + + return; + } + else + { + pBot->idle_angle = pEdict->v.v_angle.y; + } + + // check if time to check for player sounds (if don't already have enemy) + if ((pBot->f_sound_update_time <= gpGlobals->time) && + (pBot->pBotEnemy == NULL)) + { + int ind; + edict_t *pPlayer; + + pBot->f_sound_update_time = gpGlobals->time + 1.0; + + for (ind = 1; ind <= gpGlobals->maxClients; ind++) + { + pPlayer = INDEXENT(ind); + + // is this player slot is valid and it's not this bot... + if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) + { + // if observer mode enabled, don't listen to this player... + if ((b_observer_mode) && !(pPlayer->v.flags & FL_FAKECLIENT)) + continue; + + if (IsAlive(pPlayer) && + (FBitSet(pPlayer->v.flags, FL_CLIENT) || + FBitSet(pPlayer->v.flags, FL_FAKECLIENT))) + { + // check for sounds being made by other players... + if (UpdateSounds(pEdict, pPlayer)) + { + // don't check for sounds for another 30 seconds + pBot->f_sound_update_time = gpGlobals->time + 30.0; + } + } + } + } + } + + pBot->f_move_speed = pBot->f_max_speed; // set to max speed + + if (pBot->prev_time <= gpGlobals->time) + { + // see how far bot has moved since the previous position... + v_diff = pBot->v_prev_origin - pEdict->v.origin; + moved_distance = v_diff.Length(); + + // save current position as previous + pBot->v_prev_origin = pEdict->v.origin; + pBot->prev_time = gpGlobals->time + 0.2; + } + else + { + moved_distance = 2.0; + } + + // if the bot is under water, adjust pitch by pitch_speed degrees + if ((pEdict->v.waterlevel == 2) || + (pEdict->v.waterlevel == 3)) + { + // turn towards ideal_pitch by pitch_speed degrees + pitch_degrees = BotChangePitch( pBot, pEdict->v.pitch_speed ); + } + else + pitch_degrees = 0.0; + + // turn towards ideal_yaw by yaw_speed degrees + yaw_degrees = BotChangeYaw( pBot, pEdict->v.yaw_speed ); + + if ((pitch_degrees >= pEdict->v.pitch_speed) || + (yaw_degrees >= pEdict->v.yaw_speed)) + { + pBot->f_move_speed = 0.0; // don't move while turning a lot + } + else if ((pitch_degrees >= 10) || + (yaw_degrees >= 10)) // turning more than 10 degrees? + { + pBot->f_move_speed = pBot->f_move_speed / 4; // slow down while turning + } + else // else handle movement related actions... + { + if (b_botdontshoot == 0) + { + if ((mod_id == TFC_DLL) && (pBot->bot_has_flag == TRUE)) + { + // is it time to check whether bot should look for enemies yet? + if (pBot->f_bot_find_enemy_time <= gpGlobals->time) + { + pBot->f_bot_find_enemy_time = gpGlobals->time + 5.0; + + if (RANDOM_LONG(1, 100) <= 40) + pBot->pBotEnemy = BotFindEnemy( pBot ); + } + } + else + { + // Now that bots scan every entity in the world, do this less often + if(RANDOM_LONG(1, 100) <= 20) + { + pBot->pBotEnemy = BotFindEnemy( pBot ); + } + } + } + else + pBot->pBotEnemy = NULL; // clear enemy pointer (no ememy for you!) + + if (pBot->pBotEnemy != NULL) // does an enemy exist? + { + BotShootAtEnemy( pBot ); // shoot at the enemy + + pBot->f_pause_time = 0; // dont't pause if enemy exists + } + + else if (pBot->f_pause_time > gpGlobals->time) // is bot "paused"? + { + // you could make the bot look left then right, or look up + // and down, to make it appear that the bot is hunting for + // something (don't do anything right now) + } + + // is bot being "used" and can still follow "user"? + else if ((pBot->pBotUser != NULL) && BotFollowUser( pBot )) + { + // do nothing here! + ; + } + + else + { + // no enemy, let's just wander around... + + if ((pEdict->v.waterlevel != 2) && // is bot NOT under water? + (pEdict->v.waterlevel != 3)) + { + // reset pitch to 0 (level horizontally) + pEdict->v.idealpitch = 0; + pEdict->v.v_angle.x = 0; + } + + pEdict->v.v_angle.z = 0; // reset roll to 0 (straight up and down) + + pEdict->v.angles.x = 0; + pEdict->v.angles.y = pEdict->v.v_angle.y; + pEdict->v.angles.z = 0; + + // check if bot should look for items now or not... + if (pBot->f_find_item < gpGlobals->time) + { + BotFindItem( pBot ); // see if there are any visible items + } + + // check if bot sees a tripmine... + if (pBot->b_see_tripmine) + { + // check if bot can shoot the tripmine... + if ((pBot->b_shoot_tripmine) && BotShootTripmine( pBot )) + { + // shot at tripmine, may or may not have hit it, clear + // flags anyway, next BotFindItem will see it again if + // it is still there... + + pBot->b_shoot_tripmine = FALSE; + pBot->b_see_tripmine = FALSE; + + // pause for a while to allow tripmine to explode... + pBot->f_pause_time = gpGlobals->time + 0.5; + } + else // run away!!! + { + Vector tripmine_angles; + + tripmine_angles = UTIL_VecToAngles( pBot->v_tripmine - pEdict->v.origin ); + + // face away from the tripmine + pEdict->v.ideal_yaw += 180; // rotate 180 degrees + + BotFixIdealYaw(pEdict); + + pBot->b_see_tripmine = FALSE; + + pBot->f_move_speed = 0; // don't run while turning + } + } + + // check if should use wall mounted health station... + else if (pBot->b_use_health_station) + { + if ((pBot->f_use_health_time + 10.0) > gpGlobals->time) + { + pBot->f_move_speed = 0; // don't move while using health station + + pEdict->v.button = IN_USE; + } + else + { + // bot is stuck trying to "use" a health station... + + pBot->b_use_health_station = FALSE; + + // don't look for items for a while since the bot + // could be stuck trying to get to an item + pBot->f_find_item = gpGlobals->time + 0.5; + } + } + + // check if should use wall mounted HEV station... + else if (pBot->b_use_HEV_station) + { + if ((pBot->f_use_HEV_time + 10.0) > gpGlobals->time) + { + pBot->f_move_speed = 0; // don't move while using HEV station + + pEdict->v.button = IN_USE; + } + else + { + // bot is stuck trying to "use" a HEV station... + + pBot->b_use_HEV_station = FALSE; + + // don't look for items for a while since the bot + // could be stuck trying to get to an item + pBot->f_find_item = gpGlobals->time + 0.5; + } + } + + // check if should capture a point by using it... + else if (pBot->b_use_capture) + { + int team = UTIL_GetTeam(pEdict); // skin and team must match + + if (flf_bug_fix) + team = 1 - team; // BACKWARDS bug fix! + + // still capturing and hasn't captured yet... + if ((pBot->f_use_capture_time > gpGlobals->time) && + (pBot->pCaptureEdict->v.skin == team)) + { + pBot->f_move_speed = 0; // don't move while capturing + + pEdict->v.button = IN_USE; + } + else + { + // bot is stuck trying to "use" a capture point... + + pBot->b_use_capture = FALSE; + + // don't look for items for a while since the bot + // could be stuck trying to get to an item + pBot->f_find_item = gpGlobals->time + 0.5; + } + } + + else if (pBot->b_use_button) + { + pBot->f_move_speed = 0; // don't move while using elevator + + BotUseLift( pBot, moved_distance ); + } + + else + { + if (pEdict->v.waterlevel == 3) // check if the bot is underwater... + { + BotUnderWater( pBot ); + } + + found_waypoint = FALSE; + + // if the bot is not trying to get to something AND + // it is time to look for a waypoint AND + // there are waypoints in this level... + + if ((pBot->pBotPickupItem == NULL) && + (pBot->f_look_for_waypoint_time <= gpGlobals->time) && + (num_waypoints != 0)) + { + found_waypoint = BotHeadTowardWaypoint(pBot); + } + + // check if the bot is on a ladder... + if (pEdict->v.movetype == MOVETYPE_FLY) + { + // check if bot JUST got on the ladder... + if ((pBot->f_end_use_ladder_time + 1.0) < gpGlobals->time) + pBot->f_start_use_ladder_time = gpGlobals->time; + + // go handle the ladder movement + BotOnLadder( pBot, moved_distance ); + + pBot->f_dont_avoid_wall_time = gpGlobals->time + 2.0; + pBot->f_end_use_ladder_time = gpGlobals->time; + } + else + { + // check if the bot JUST got off the ladder... + if ((pBot->f_end_use_ladder_time + 1.0) > gpGlobals->time) + { + pBot->ladder_dir = LADDER_UNKNOWN; + } + } + + // if the bot isn't headed toward a waypoint... + if (found_waypoint == FALSE) + { + TraceResult tr; + + // check if we should be avoiding walls + if (pBot->f_dont_avoid_wall_time <= gpGlobals->time) + { + // let's just randomly wander around + if (BotStuckInCorner( pBot )) + { + pEdict->v.ideal_yaw += 180; // turn 180 degrees + + BotFixIdealYaw(pEdict); + + pBot->f_move_speed = 0; // don't move while turning + pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; + + moved_distance = 2.0; // dont use bot stuck code + } + else + { + // check if there is a wall on the left... + if (!BotCheckWallOnLeft( pBot )) + { + // if there was a wall on the left over 1/2 a second ago then + // 20% of the time randomly turn between 45 and 60 degrees + + if ((pBot->f_wall_on_left != 0) && + (pBot->f_wall_on_left <= gpGlobals->time - 0.5) && + (RANDOM_LONG(1, 100) <= 20)) + { + pEdict->v.ideal_yaw += RANDOM_LONG(45, 60); + + BotFixIdealYaw(pEdict); + + pBot->f_move_speed = 0; // don't move while turning + pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; + } + + pBot->f_wall_on_left = 0; // reset wall detect time + } + else if (!BotCheckWallOnRight( pBot )) + { + // if there was a wall on the right over 1/2 a second ago then + // 20% of the time randomly turn between 45 and 60 degrees + + if ((pBot->f_wall_on_right != 0) && + (pBot->f_wall_on_right <= gpGlobals->time - 0.5) && + (RANDOM_LONG(1, 100) <= 20)) + { + pEdict->v.ideal_yaw -= RANDOM_LONG(45, 60); + + BotFixIdealYaw(pEdict); + + pBot->f_move_speed = 0; // don't move while turning + pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; + } + + pBot->f_wall_on_right = 0; // reset wall detect time + } + } + } + + // check if bot is about to hit a wall. TraceResult gets returned + if ((pBot->f_dont_avoid_wall_time <= gpGlobals->time) && + BotCantMoveForward( pBot, &tr )) + { + // ADD LATER + // need to check if bot can jump up or duck under here... + // ADD LATER + + BotTurnAtWall( pBot, &tr ); + } + } + + // check if bot is on a ladder and has been on a ladder for + // more than 5 seconds... + if ((pEdict->v.movetype == MOVETYPE_FLY) && + (pBot->f_start_use_ladder_time > 0.0) && + ((pBot->f_start_use_ladder_time + 5.0) <= gpGlobals->time)) + { + // bot is stuck on a ladder... + + BotRandomTurn(pBot); + + // don't look for items for 2 seconds + pBot->f_find_item = gpGlobals->time + 2.0; + + pBot->f_start_use_ladder_time = 0.0; // reset start ladder time + } + + // check if the bot hasn't moved much since the last location + // (and NOT on a ladder since ladder stuck handled elsewhere) + // (don't check for stuck if f_dont_check_stuck in the future) + if ((moved_distance <= 1.0) && (pBot->prev_speed >= 1.0) && + (pEdict->v.movetype != MOVETYPE_FLY) && + (pBot->f_dont_check_stuck < gpGlobals->time)) + { + // the bot must be stuck! + + pBot->f_dont_avoid_wall_time = gpGlobals->time + 1.0; + pBot->f_look_for_waypoint_time = gpGlobals->time + 1.0; + + if (BotCanJumpUp( pBot )) // can the bot jump onto something? + { + if ((pBot->f_jump_time + 2.0) <= gpGlobals->time) + { + pBot->f_jump_time = gpGlobals->time; + pEdict->v.button |= IN_JUMP; // jump up and move forward + } + else + { + // bot already tried jumping less than two seconds ago, just turn + BotRandomTurn(pBot); + } + } + else if (BotCanDuckUnder( pBot )) // can the bot duck under something? + { + pEdict->v.button |= IN_DUCK; // duck down and move forward + } + else + { + BotRandomTurn(pBot); + + // is the bot trying to get to an item?... + if (pBot->pBotPickupItem != NULL) + { + // don't look for items for a while since the bot + // could be stuck trying to get to an item + pBot->f_find_item = gpGlobals->time + 0.5; + } + } + } + + // should the bot pause for a while here? + // (don't pause on ladders or while being "used"... + if ((RANDOM_LONG(1, 1000) <= pause_frequency[pBot->bot_skill]) && + (pEdict->v.movetype != MOVETYPE_FLY) && + (pBot->pBotUser == NULL)) + { + // set the time that the bot will stop "pausing" + pBot->f_pause_time = gpGlobals->time + + RANDOM_FLOAT(pause_time[pBot->bot_skill][0], + pause_time[pBot->bot_skill][1]); + } + } + } + } + + // Potentially morph up if we're an alien + AvHUser3 theUser3 = (AvHUser3)(pBot->pEdict->v.iuser3); + if((pBot->pBotEnemy == NULL) && (theUser3 >= AVH_USER3_ALIEN_PLAYER1) && (theUser3 <= AVH_USER3_ALIEN_PLAYER4)) + { + int theMaxUpgrade = (int)(AVH_USER3_ALIEN_PLAYER5 - theUser3); + //const UpgradeCostListType& theUpgradeCosts = GetGameRules()->GetUpgradeCosts(); + + if(RANDOM_LONG(0, 400) == 0) + { + // Pick a random upgrade + AvHUser3 theMinUpgrade = (AvHUser3)(theUser3 + 1); + int theMaxUpgrade = AVH_USER3_ALIEN_PLAYER5; + AvHUser3 theUpgradeUser3 = (AvHUser3)(RANDOM_LONG((int)theMinUpgrade, (int)theMaxUpgrade)); + int thePointCost = 0; + AvHMessageID theMessage = MESSAGE_NULL; + switch(theUpgradeUser3) + { + case AVH_USER3_ALIEN_PLAYER2: + thePointCost = 15; + theMessage = ALIEN_LIFEFORM_TWO; + break; + case AVH_USER3_ALIEN_PLAYER3: + thePointCost = 30; + theMessage = ALIEN_LIFEFORM_THREE; + break; + case AVH_USER3_ALIEN_PLAYER4: + thePointCost = 50; + theMessage = ALIEN_LIFEFORM_FOUR; + break; + case AVH_USER3_ALIEN_PLAYER5: + thePointCost = 75; + theMessage = ALIEN_LIFEFORM_FIVE; + break; + } + + //thePointCost = GetGameRules()->GetPointCostForMessageID(theMessage); + + //if(pBot->mResources >= thePointCost) + //{ + pBot->pEdict->v.impulse = theMessage; + //} + } + + if(RANDOM_LONG(0, 75) == 0) + { + // Pick a random upgrade to try to "buy" + AvHMessageID theUpgrade = (AvHMessageID)(ALIEN_EVOLUTION_ONE + RANDOM_LONG(0, kNumAlienUpgrades-1)); + pBot->pEdict->v.impulse = theUpgrade; + } + } + + // TODO: Help build a nearby team structure + if(pBot->pBotEnemy == NULL && (theUser3 == AVH_USER3_MARINE_PLAYER)) + { + } + + if (pBot->curr_waypoint_index != -1) // does the bot have a waypoint? + { + // check if the next waypoint is a door waypoint... + if (waypoints[pBot->curr_waypoint_index].flags & W_FL_DOOR) + { + pBot->f_move_speed = pBot->f_max_speed / 3; // slow down for doors + } + + // check if the next waypoint is a ladder waypoint... + if (waypoints[pBot->curr_waypoint_index].flags & W_FL_LADDER) + { + // check if the waypoint is at the top of a ladder AND + // the bot isn't currenly on a ladder... + if ((pBot->waypoint_top_of_ladder) && + (pEdict->v.movetype != MOVETYPE_FLY)) + { + // is the bot on "ground" above the ladder? + if (pEdict->v.flags & FL_ONGROUND) + { + float waypoint_distance = (pEdict->v.origin - pBot->waypoint_origin).Length(); + + if (waypoint_distance <= 20.0) // if VERY close... + pBot->f_move_speed = 20.0; // go VERY slow + else if (waypoint_distance <= 100.0) // if fairly close... + pBot->f_move_speed = 50.0; // go fairly slow + + pBot->ladder_dir = LADDER_DOWN; + pBot->f_dont_check_stuck = gpGlobals->time + 1.0; + } + else // bot must be in mid-air, go BACKWARDS to touch ladder... + { + pBot->f_move_speed = -pBot->f_max_speed; + } + } + else + { + // don't avoid walls for a while + pBot->f_dont_avoid_wall_time = gpGlobals->time + 5.0; + + pBot->waypoint_top_of_ladder = FALSE; + } + } + + // check if the next waypoint is a crouch waypoint... + if (waypoints[pBot->curr_waypoint_index].flags & W_FL_CROUCH) + pEdict->v.button |= IN_DUCK; // duck down while moving forward + + // check if the waypoint is a sniper waypoint AND + // bot isn't currently aiming at an ememy... + if ((waypoints[pBot->curr_waypoint_index].flags & W_FL_SNIPER) && + (pBot->pBotEnemy == NULL)) + { + if ((mod_id != TFC_DLL) || + ((mod_id == TFC_DLL) && (pEdict->v.playerclass == TFC_CLASS_SNIPER))) + { + // check if it's time to adjust aim yet... + if (pBot->f_sniper_aim_time <= gpGlobals->time) + { + int aim_index; + + aim_index = WaypointFindNearestAiming(waypoints[pBot->curr_waypoint_index].origin); + + if (aim_index != -1) + { + Vector v_aim = waypoints[aim_index].origin - waypoints[pBot->curr_waypoint_index].origin; + + Vector aim_angles = UTIL_VecToAngles( v_aim ); + + aim_angles.y += RANDOM_LONG(0, 30) - 15; + + pEdict->v.ideal_yaw = aim_angles.y; + + BotFixIdealYaw(pEdict); + } + + // don't adjust aim again until after a few seconds... + pBot->f_sniper_aim_time = gpGlobals->time + RANDOM_FLOAT(3.0, 5.0); + } + } + } + } + + // Process voice commands + BotProcessVoiceCommands(pBot); + + if (pBot->f_pause_time > gpGlobals->time) // is the bot "paused"? + pBot->f_move_speed = 0; // don't move while pausing + + // make the body face the same way the bot is looking + pEdict->v.angles.y = pEdict->v.v_angle.y; + + // save the previous speed (for checking if stuck) + pBot->prev_speed = pBot->f_move_speed; + + //CBaseEntity* theEntity = CBaseEntity::Instance(pEdict); + //CBasePlayer* thePlayer = (CBasePlayer*)(theEntity); + //thePlayer->PreThink(); + + g_engfuncs.pfnRunPlayerMove( pEdict, pEdict->v.v_angle, pBot->f_move_speed, + 0, 0, pEdict->v.button, 0, pBot->msecval); + + //thePlayer->PostThink(); + + return; +} + diff --git a/main/source/HPB_bot/dlls/bot.h b/main/source/HPB_bot/dlls/bot.h index 8687d3ab..7337cfb6 100644 --- a/main/source/HPB_bot/dlls/bot.h +++ b/main/source/HPB_bot/dlls/bot.h @@ -1,309 +1,309 @@ -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot.h -// - -#ifndef BOT_H -#define BOT_H - -// stuff for Win32 vs. Linux builds - -#ifndef __linux__ - -typedef int (FAR *GETENTITYAPI)(DLL_FUNCTIONS *, int); -typedef int (FAR *GETNEWDLLFUNCTIONS)(NEW_DLL_FUNCTIONS *, int *); -typedef void (DLLEXPORT *GIVEFNPTRSTODLL)(enginefuncs_t *, globalvars_t *); -typedef void (FAR *LINK_ENTITY_FUNC)(entvars_t *); - -#else - -#include -#define GetProcAddress dlsym - -typedef int BOOL; - -typedef int (*GETENTITYAPI)(DLL_FUNCTIONS *, int); -typedef int (*GETNEWDLLFUNCTIONS)(NEW_DLL_FUNCTIONS *, int *); -typedef void (*GIVEFNPTRSTODLL)(enginefuncs_t *, globalvars_t *); -typedef void (*LINK_ENTITY_FUNC)(entvars_t *); - -#endif - - - -// define constants used to identify the MOD we are playing... - -#define VALVE_DLL 1 -#define TFC_DLL 2 -#define CSTRIKE_DLL 3 -#define GEARBOX_DLL 4 -#define FRONTLINE_DLL 5 -#define AVH_DLL 6 - - -// define some function prototypes... -BOOL ClientConnect( edict_t *pEntity, const char *pszName, - const char *pszAddress, char szRejectReason[ 128 ] ); -void ClientPutInServer( edict_t *pEntity ); -void ClientCommand( edict_t *pEntity ); - -void FakeClientCommand(edict_t *pBot, char *arg1, char *arg2, char *arg3); - - -const char *Cmd_Args( void ); -const char *Cmd_Argv( int argc ); -int Cmd_Argc( void ); - - -#define LADDER_UNKNOWN 0 -#define LADDER_UP 1 -#define LADDER_DOWN 2 - -#define WANDER_LEFT 1 -#define WANDER_RIGHT 2 - -#define BOT_PITCH_SPEED 20 -#define BOT_YAW_SPEED 20 - -#define RESPAWN_IDLE 1 -#define RESPAWN_NEED_TO_RESPAWN 2 -#define RESPAWN_IS_RESPAWNING 3 - -// game start messages for TFC... -#define MSG_TFC_IDLE 1 -#define MSG_TFC_TEAM_SELECT 2 -#define MSG_TFC_CLASS_SELECT 3 - -// game start messages for CS... -#define MSG_CS_IDLE 1 -#define MSG_CS_TEAM_SELECT 2 -#define MSG_CS_CT_SELECT 3 -#define MSG_CS_T_SELECT 4 - -// game start messages for OpFor... -#define MSG_OPFOR_IDLE 1 -#define MSG_OPFOR_TEAM_SELECT 2 -#define MSG_OPFOR_CLASS_SELECT 3 - -// game start messages for FrontLineForce... -#define MSG_FLF_IDLE 1 -#define MSG_FLF_TEAM_SELECT 2 -#define MSG_FLF_CLASS_SELECT 3 -#define MSG_FLF_PISTOL_SELECT 4 -#define MSG_FLF_WEAPON_SELECT 5 -#define MSG_FLF_RIFLE_SELECT 6 -#define MSG_FLF_SHOTGUN_SELECT 7 -#define MSG_FLF_SUBMACHINE_SELECT 8 -#define MSG_FLF_HEAVYWEAPONS_SELECT 9 - -// game start messages for Aliens vs. Humans... -#define MSG_AVH_IDLE 1 - -#define TFC_CLASS_CIVILIAN 0 -#define TFC_CLASS_SCOUT 1 -#define TFC_CLASS_SNIPER 2 -#define TFC_CLASS_SOLDIER 3 -#define TFC_CLASS_DEMOMAN 4 -#define TFC_CLASS_MEDIC 5 -#define TFC_CLASS_HWGUY 6 -#define TFC_CLASS_PYRO 7 -#define TFC_CLASS_SPY 8 -#define TFC_CLASS_ENGINEER 9 - - -#define BOT_SKIN_LEN 32 -#define BOT_NAME_LEN 32 - -#define MAX_BOT_WHINE 100 - -#include "mod/AvHConstants.h" -#include "mod/AvHSpecials.h" - -typedef struct -{ - int iId; // weapon ID - int iClip; // amount of ammo in the clip - int iAmmo1; // amount of ammo in primary reserve - int iAmmo2; // amount of ammo in secondary reserve -} bot_current_weapon_t; - - -typedef struct -{ - bool is_used; - int respawn_state; - edict_t *pEdict; - bool need_to_initialize; - char name[BOT_NAME_LEN+1]; - char skin[BOT_SKIN_LEN+1]; - int bot_skill; - int not_started; - int start_action; - float kick_time; - float create_time; - -// TheFatal - START - int msecnum; - float msecdel; - float msecval; -// TheFatal - END - - // things from pev in CBasePlayer... - int bot_team; - int bot_class; - int bot_health; - int bot_armor; - int bot_weapons; // bit map of weapons the bot is carrying - int bot_money; // for Counter-Strike - int primary_weapon; // for Front Line Force - int secondary_weapon; // for Front Line Force - int defender; // for Front Line Force - int warmup; // for Front Line Force - float idle_angle; - float idle_angle_time; // for Front Line Force - int round_end; // round has ended (in round based games) - float blinded_time; - - // For AvH - AvHPlayMode mBotPlayMode; - - int mOrderState; - int mOrderNumPlayers; - AvHOrderType mOrderType; - AvHOrderTargetType mOrderTargetType; - float mOrderLocation[3]; - int mOrderTargetIndex; - bool mOrderCompleted; - - float mTimeOfNextTaunt; - float mTimeOfNextAmmoRequest; - float mTimeOfNextOrderRequest; - float mTimeOfNextAcknowledge; - float mTimeOfNextRandomSaying; - - AvHUser3 mGestateUser3; - int mResources; - // end for AvH - - float f_max_speed; - float prev_speed; - float prev_time; - Vector v_prev_origin; - - float f_find_item; - edict_t *pBotPickupItem; - - int ladder_dir; - float f_start_use_ladder_time; - float f_end_use_ladder_time; - bool waypoint_top_of_ladder; - - float f_wall_check_time; - float f_wall_on_right; - float f_wall_on_left; - float f_dont_avoid_wall_time; - float f_look_for_waypoint_time; - float f_jump_time; - float f_dont_check_stuck; - - int wander_dir; - float f_exit_water_time; - - Vector waypoint_origin; - float f_waypoint_time; - int curr_waypoint_index; - int prev_waypoint_index[5]; - float f_random_waypoint_time; - int waypoint_goal; - float f_waypoint_goal_time; - bool waypoint_near_flag; - Vector waypoint_flag_origin; - float prev_waypoint_distance; - - edict_t *pBotEnemy; - float f_bot_see_enemy_time; - float f_bot_find_enemy_time; - edict_t *pBotUser; - float f_bot_use_time; - float f_bot_spawn_time; - edict_t *killer_edict; - bool b_bot_say_killed; - float f_bot_say_killed; - float f_sniper_aim_time; - - - float f_shoot_time; - float f_primary_charging; - float f_secondary_charging; - int charging_weapon_id; - float f_move_speed; - float f_pause_time; - float f_sound_update_time; - bool bot_has_flag; - - bool b_see_tripmine; - bool b_shoot_tripmine; - Vector v_tripmine; - - bool b_use_health_station; - float f_use_health_time; - bool b_use_HEV_station; - float f_use_HEV_time; - - bool b_use_button; - float f_use_button_time; - bool b_lift_moving; - - bool b_use_capture; - float f_use_capture_time; - edict_t *pCaptureEdict; - - bot_current_weapon_t current_weapon; // one current weapon for each bot - int m_rgAmmo[MAX_AMMO_SLOTS]; // total ammo amounts (1 array for each bot) - -} bot_t; - - -//#define MAX_TEAMS 32 -//#define MAX_TEAMNAME_LENGTH 16 -#include "game_shared/teamconst.h" - - -#define MAX_FLAGS 5 - -typedef struct { - bool mdl_match; - int team_no; - edict_t *edict; -} FLAG_S; - - -// new UTIL.CPP functions... -edict_t *UTIL_FindEntityInSphere( edict_t *pentStart, const Vector &vecCenter, float flRadius ); -edict_t *UTIL_FindEntityByString( edict_t *pentStart, const char *szKeyword, const char *szValue ); -edict_t *UTIL_FindEntityByClassname( edict_t *pentStart, const char *szName ); -edict_t *UTIL_FindEntityByTargetname( edict_t *pentStart, const char *szName ); -void ClientPrint( edict_t *pEdict, int msg_dest, const char *msg_name); -void UTIL_SayText( const char *pText, edict_t *pEdict ); -void UTIL_HostSay( edict_t *pEntity, int teamonly, char *message ); -int UTIL_GetTeam(edict_t *pEntity); -int UTIL_GetClass(edict_t *pEntity); -int UTIL_GetBotIndex(edict_t *pEdict); -bot_t *UTIL_GetBotPointer(edict_t *pEdict); -bool IsAlive(edict_t *pEdict); -bool FInViewCone(Vector *pOrigin, edict_t *pEdict); -bool FVisible( const Vector &vecOrigin, edict_t *pEdict ); -Vector Center(edict_t *pEdict); -Vector GetGunPosition(edict_t *pEdict); -void UTIL_SelectItem(edict_t *pEdict, char *item_name); -Vector VecBModelOrigin(edict_t *pEdict); -bool UpdateSounds(edict_t *pEdict, edict_t *pPlayer); -void UTIL_ShowMenu( edict_t *pEdict, int slots, int displaytime, bool needmore, char *pText ); -void UTIL_BuildFileName(char *filename, char *arg1, char *arg2); - - -#endif // BOT_H - +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot.h +// + +#ifndef BOT_H +#define BOT_H + +// stuff for Win32 vs. Linux builds + +#ifndef __linux__ + +typedef int (FAR *GETENTITYAPI)(DLL_FUNCTIONS *, int); +typedef int (FAR *GETNEWDLLFUNCTIONS)(NEW_DLL_FUNCTIONS *, int *); +typedef void (DLLEXPORT *GIVEFNPTRSTODLL)(enginefuncs_t *, globalvars_t *); +typedef void (FAR *LINK_ENTITY_FUNC)(entvars_t *); + +#else + +#include +#define GetProcAddress dlsym + +typedef int BOOL; + +typedef int (*GETENTITYAPI)(DLL_FUNCTIONS *, int); +typedef int (*GETNEWDLLFUNCTIONS)(NEW_DLL_FUNCTIONS *, int *); +typedef void (*GIVEFNPTRSTODLL)(enginefuncs_t *, globalvars_t *); +typedef void (*LINK_ENTITY_FUNC)(entvars_t *); + +#endif + + + +// define constants used to identify the MOD we are playing... + +#define VALVE_DLL 1 +#define TFC_DLL 2 +#define CSTRIKE_DLL 3 +#define GEARBOX_DLL 4 +#define FRONTLINE_DLL 5 +#define AVH_DLL 6 + + +// define some function prototypes... +BOOL ClientConnect( edict_t *pEntity, const char *pszName, + const char *pszAddress, char szRejectReason[ 128 ] ); +void ClientPutInServer( edict_t *pEntity ); +void ClientCommand( edict_t *pEntity ); + +void FakeClientCommand(edict_t *pBot, char *arg1, char *arg2, char *arg3); + + +const char *Cmd_Args( void ); +const char *Cmd_Argv( int argc ); +int Cmd_Argc( void ); + + +#define LADDER_UNKNOWN 0 +#define LADDER_UP 1 +#define LADDER_DOWN 2 + +#define WANDER_LEFT 1 +#define WANDER_RIGHT 2 + +#define BOT_PITCH_SPEED 20 +#define BOT_YAW_SPEED 20 + +#define RESPAWN_IDLE 1 +#define RESPAWN_NEED_TO_RESPAWN 2 +#define RESPAWN_IS_RESPAWNING 3 + +// game start messages for TFC... +#define MSG_TFC_IDLE 1 +#define MSG_TFC_TEAM_SELECT 2 +#define MSG_TFC_CLASS_SELECT 3 + +// game start messages for CS... +#define MSG_CS_IDLE 1 +#define MSG_CS_TEAM_SELECT 2 +#define MSG_CS_CT_SELECT 3 +#define MSG_CS_T_SELECT 4 + +// game start messages for OpFor... +#define MSG_OPFOR_IDLE 1 +#define MSG_OPFOR_TEAM_SELECT 2 +#define MSG_OPFOR_CLASS_SELECT 3 + +// game start messages for FrontLineForce... +#define MSG_FLF_IDLE 1 +#define MSG_FLF_TEAM_SELECT 2 +#define MSG_FLF_CLASS_SELECT 3 +#define MSG_FLF_PISTOL_SELECT 4 +#define MSG_FLF_WEAPON_SELECT 5 +#define MSG_FLF_RIFLE_SELECT 6 +#define MSG_FLF_SHOTGUN_SELECT 7 +#define MSG_FLF_SUBMACHINE_SELECT 8 +#define MSG_FLF_HEAVYWEAPONS_SELECT 9 + +// game start messages for Aliens vs. Humans... +#define MSG_AVH_IDLE 1 + +#define TFC_CLASS_CIVILIAN 0 +#define TFC_CLASS_SCOUT 1 +#define TFC_CLASS_SNIPER 2 +#define TFC_CLASS_SOLDIER 3 +#define TFC_CLASS_DEMOMAN 4 +#define TFC_CLASS_MEDIC 5 +#define TFC_CLASS_HWGUY 6 +#define TFC_CLASS_PYRO 7 +#define TFC_CLASS_SPY 8 +#define TFC_CLASS_ENGINEER 9 + + +#define BOT_SKIN_LEN 32 +#define BOT_NAME_LEN 32 + +#define MAX_BOT_WHINE 100 + +#include "mod/AvHConstants.h" +#include "mod/AvHSpecials.h" + +typedef struct +{ + int iId; // weapon ID + int iClip; // amount of ammo in the clip + int iAmmo1; // amount of ammo in primary reserve + int iAmmo2; // amount of ammo in secondary reserve +} bot_current_weapon_t; + + +typedef struct +{ + bool is_used; + int respawn_state; + edict_t *pEdict; + bool need_to_initialize; + char name[BOT_NAME_LEN+1]; + char skin[BOT_SKIN_LEN+1]; + int bot_skill; + int not_started; + int start_action; + float kick_time; + float create_time; + +// TheFatal - START + int msecnum; + float msecdel; + float msecval; +// TheFatal - END + + // things from pev in CBasePlayer... + int bot_team; + int bot_class; + int bot_health; + int bot_armor; + int bot_weapons; // bit map of weapons the bot is carrying + int bot_money; // for Counter-Strike + int primary_weapon; // for Front Line Force + int secondary_weapon; // for Front Line Force + int defender; // for Front Line Force + int warmup; // for Front Line Force + float idle_angle; + float idle_angle_time; // for Front Line Force + int round_end; // round has ended (in round based games) + float blinded_time; + + // For AvH + AvHPlayMode mBotPlayMode; + + int mOrderState; + int mOrderNumPlayers; + AvHOrderType mOrderType; + AvHOrderTargetType mOrderTargetType; + float mOrderLocation[3]; + int mOrderTargetIndex; + bool mOrderCompleted; + + float mTimeOfNextTaunt; + float mTimeOfNextAmmoRequest; + float mTimeOfNextOrderRequest; + float mTimeOfNextAcknowledge; + float mTimeOfNextRandomSaying; + + AvHUser3 mGestateUser3; + int mResources; + // end for AvH + + float f_max_speed; + float prev_speed; + float prev_time; + Vector v_prev_origin; + + float f_find_item; + edict_t *pBotPickupItem; + + int ladder_dir; + float f_start_use_ladder_time; + float f_end_use_ladder_time; + bool waypoint_top_of_ladder; + + float f_wall_check_time; + float f_wall_on_right; + float f_wall_on_left; + float f_dont_avoid_wall_time; + float f_look_for_waypoint_time; + float f_jump_time; + float f_dont_check_stuck; + + int wander_dir; + float f_exit_water_time; + + Vector waypoint_origin; + float f_waypoint_time; + int curr_waypoint_index; + int prev_waypoint_index[5]; + float f_random_waypoint_time; + int waypoint_goal; + float f_waypoint_goal_time; + bool waypoint_near_flag; + Vector waypoint_flag_origin; + float prev_waypoint_distance; + + edict_t *pBotEnemy; + float f_bot_see_enemy_time; + float f_bot_find_enemy_time; + edict_t *pBotUser; + float f_bot_use_time; + float f_bot_spawn_time; + edict_t *killer_edict; + bool b_bot_say_killed; + float f_bot_say_killed; + float f_sniper_aim_time; + + + float f_shoot_time; + float f_primary_charging; + float f_secondary_charging; + int charging_weapon_id; + float f_move_speed; + float f_pause_time; + float f_sound_update_time; + bool bot_has_flag; + + bool b_see_tripmine; + bool b_shoot_tripmine; + Vector v_tripmine; + + bool b_use_health_station; + float f_use_health_time; + bool b_use_HEV_station; + float f_use_HEV_time; + + bool b_use_button; + float f_use_button_time; + bool b_lift_moving; + + bool b_use_capture; + float f_use_capture_time; + edict_t *pCaptureEdict; + + bot_current_weapon_t current_weapon; // one current weapon for each bot + int m_rgAmmo[MAX_AMMO_SLOTS]; // total ammo amounts (1 array for each bot) + +} bot_t; + + +//#define MAX_TEAMS 32 +//#define MAX_TEAMNAME_LENGTH 16 +#include "game_shared/teamconst.h" + + +#define MAX_FLAGS 5 + +typedef struct { + bool mdl_match; + int team_no; + edict_t *edict; +} FLAG_S; + + +// new UTIL.CPP functions... +edict_t *UTIL_FindEntityInSphere( edict_t *pentStart, const Vector &vecCenter, float flRadius ); +edict_t *UTIL_FindEntityByString( edict_t *pentStart, const char *szKeyword, const char *szValue ); +edict_t *UTIL_FindEntityByClassname( edict_t *pentStart, const char *szName ); +edict_t *UTIL_FindEntityByTargetname( edict_t *pentStart, const char *szName ); +void ClientPrint( edict_t *pEdict, int msg_dest, const char *msg_name); +void UTIL_SayText( const char *pText, edict_t *pEdict ); +void UTIL_HostSay( edict_t *pEntity, int teamonly, char *message ); +int UTIL_GetTeam(edict_t *pEntity); +int UTIL_GetClass(edict_t *pEntity); +int UTIL_GetBotIndex(edict_t *pEdict); +bot_t *UTIL_GetBotPointer(edict_t *pEdict); +bool IsAlive(edict_t *pEdict); +bool FInViewCone(Vector *pOrigin, edict_t *pEdict); +bool FVisible( const Vector &vecOrigin, edict_t *pEdict ); +Vector Center(edict_t *pEdict); +Vector GetGunPosition(edict_t *pEdict); +void UTIL_SelectItem(edict_t *pEdict, char *item_name); +Vector VecBModelOrigin(edict_t *pEdict); +bool UpdateSounds(edict_t *pEdict, edict_t *pPlayer); +void UTIL_ShowMenu( edict_t *pEdict, int slots, int displaytime, bool needmore, char *pText ); +void UTIL_BuildFileName(char *filename, char *arg1, char *arg2); + + +#endif // BOT_H + diff --git a/main/source/HPB_bot/dlls/bot_client.cpp b/main/source/HPB_bot/dlls/bot_client.cpp index f0e93204..807e729a 100644 --- a/main/source/HPB_bot/dlls/bot_client.cpp +++ b/main/source/HPB_bot/dlls/bot_client.cpp @@ -1,960 +1,960 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_client.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" -#include "bot_func.h" -#include "bot_client.h" -#include "bot_weapons.h" - -// types of damage to ignore... -#define IGNORE_DAMAGE (DMG_CRUSH | DMG_FREEZE | DMG_FALL | DMG_SHOCK | \ - DMG_DROWN | DMG_NERVEGAS | DMG_RADIATION | \ - DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN | \ - DMG_SLOWFREEZE | 0xFF000000) - -extern int mod_id; -extern bot_t bots[32]; - -bot_weapon_t weapon_defs[MAX_WEAPONS]; // array of weapon definitions - - -// This message is sent when the TFC VGUI menu is displayed. -void BotClient_TFC_VGUI(void *p, int bot_index) -{ - if ((*(int *)p) == 2) // is it a team select menu? - - bots[bot_index].start_action = MSG_TFC_TEAM_SELECT; - - else if ((*(int *)p) == 3) // is is a class selection menu? - - bots[bot_index].start_action = MSG_TFC_CLASS_SELECT; -} - - -// This message is sent when the Counter-Strike VGUI menu is displayed. -void BotClient_CS_VGUI(void *p, int bot_index) -{ - if ((*(int *)p) == 2) // is it a team select menu? - - bots[bot_index].start_action = MSG_CS_TEAM_SELECT; - - else if ((*(int *)p) == 26) // is is a terrorist model select menu? - - bots[bot_index].start_action = MSG_CS_T_SELECT; - - else if ((*(int *)p) == 27) // is is a counter-terrorist model select menu? - - bots[bot_index].start_action = MSG_CS_CT_SELECT; -} - - -// This message is sent when a menu is being displayed in Counter-Strike. -void BotClient_CS_ShowMenu(void *p, int bot_index) -{ - static int state = 0; // current state machine state - - if (state < 3) - { - state++; // ignore first 3 fields of message - return; - } - - if (strcmp((char *)p, "#Team_Select") == 0) // team select menu? - { - bots[bot_index].start_action = MSG_CS_TEAM_SELECT; - } - else if (strcmp((char *)p, "#Terrorist_Select") == 0) // T model select? - { - bots[bot_index].start_action = MSG_CS_T_SELECT; - } - else if (strcmp((char *)p, "#CT_Select") == 0) // CT model select menu? - { - bots[bot_index].start_action = MSG_CS_CT_SELECT; - } - - state = 0; // reset state machine -} - - -// This message is sent when the TFC VGUI menu is displayed. -void BotClient_Gearbox_VGUI(void *p, int bot_index) -{ - if ((*(int *)p) == 2) // is it a team select menu? - - bots[bot_index].start_action = MSG_OPFOR_TEAM_SELECT; - - else if ((*(int *)p) == 3) // is is a class selection menu? - - bots[bot_index].start_action = MSG_OPFOR_CLASS_SELECT; -} - - -// This message is sent when the FrontLineForce VGUI menu is displayed. -void BotClient_FLF_VGUI(void *p, int bot_index) -{ - if ((*(int *)p) == 2) // is it a team select menu? - bots[bot_index].start_action = MSG_FLF_TEAM_SELECT; - else if ((*(int *)p) == 3) // is it a class selection menu? - bots[bot_index].start_action = MSG_FLF_CLASS_SELECT; - else if ((*(int *)p) == 70) // is it a weapon selection menu? - bots[bot_index].start_action = MSG_FLF_WEAPON_SELECT; - else if ((*(int *)p) == 72) // is it a submachine gun selection menu? - bots[bot_index].start_action = MSG_FLF_SUBMACHINE_SELECT; - else if ((*(int *)p) == 73) // is it a shotgun selection menu? - bots[bot_index].start_action = MSG_FLF_SHOTGUN_SELECT; - else if ((*(int *)p) == 75) // is it a rifle selection menu? - bots[bot_index].start_action = MSG_FLF_RIFLE_SELECT; - else if ((*(int *)p) == 76) // is it a pistol selection menu? - bots[bot_index].start_action = MSG_FLF_PISTOL_SELECT; - else if ((*(int *)p) == 78) // is it a heavyweapons selection menu? - bots[bot_index].start_action = MSG_FLF_HEAVYWEAPONS_SELECT; -} - - -// This message is sent when a client joins the game. All of the weapons -// are sent with the weapon ID and information about what ammo is used. -void BotClient_Valve_WeaponList(void *p, int bot_index) -{ - static int state = 0; // current state machine state - static bot_weapon_t bot_weapon; - - if (state == 0) - { - state++; - strcpy(bot_weapon.szClassname, (char *)p); - } - else if (state == 1) - { - state++; - bot_weapon.iAmmo1 = *(int *)p; // ammo index 1 - } - else if (state == 2) - { - state++; - bot_weapon.iAmmo1Max = *(int *)p; // max ammo1 - } - else if (state == 3) - { - state++; - bot_weapon.iAmmo2 = *(int *)p; // ammo index 2 - } - else if (state == 4) - { - state++; - bot_weapon.iAmmo2Max = *(int *)p; // max ammo2 - } - else if (state == 5) - { - state++; - bot_weapon.iSlot = *(int *)p; // slot for this weapon - } - else if (state == 6) - { - state++; - bot_weapon.iPosition = *(int *)p; // position in slot - } - else if (state == 7) - { - state++; - bot_weapon.iId = *(int *)p; // weapon ID - } - else if (state == 8) - { - state = 0; - - bot_weapon.iFlags = *(int *)p; // flags for weapon (WTF???) - - // store away this weapon with it's ammo information... - weapon_defs[bot_weapon.iId] = bot_weapon; - } -} - -void BotClient_TFC_WeaponList(void *p, int bot_index) -{ - // this is just like the Valve Weapon List message - BotClient_Valve_WeaponList(p, bot_index); -} - -void BotClient_CS_WeaponList(void *p, int bot_index) -{ - // this is just like the Valve Weapon List message - BotClient_Valve_WeaponList(p, bot_index); -} - -void BotClient_Gearbox_WeaponList(void *p, int bot_index) -{ - // this is just like the Valve Weapon List message - BotClient_Valve_WeaponList(p, bot_index); -} - -void BotClient_FLF_WeaponList(void *p, int bot_index) -{ - // this is just like the Valve Weapon List message - BotClient_Valve_WeaponList(p, bot_index); -} - - -// This message is sent when a weapon is selected (either by the bot chosing -// a weapon or by the server auto assigning the bot a weapon). -void BotClient_Valve_CurrentWeapon(void *p, int bot_index) -{ - static int state = 0; // current state machine state - static int iState; - static int iId; - static int iClip; - - if (state == 0) - { - state++; - iState = *(int *)p; // state of the current weapon - } - else if (state == 1) - { - state++; - iId = *(int *)p; // weapon ID of current weapon - } - else if (state == 2) - { - state = 0; - - iClip = *(int *)p; // ammo currently in the clip for this weapon - - if (iId <= 31) - { - bots[bot_index].bot_weapons |= (1< 0) || (damage_taken > 0)) - { - // ignore certain types of damage... - if (damage_bits & IGNORE_DAMAGE) - return; - - // if the bot doesn't have an enemy and someone is shooting at it then - // turn in the attacker's direction... - if (bots[bot_index].pBotEnemy == NULL) - { - // face the attacker... - Vector v_enemy = damage_origin - bots[bot_index].pEdict->v.origin; - Vector bot_angles = UTIL_VecToAngles( v_enemy ); - - bots[bot_index].pEdict->v.ideal_yaw = bot_angles.y; - - BotFixIdealYaw(bots[bot_index].pEdict); - - // stop using health or HEV stations... - bots[bot_index].b_use_health_station = FALSE; - bots[bot_index].b_use_HEV_station = FALSE; - bots[bot_index].b_use_capture = FALSE; - } - } - } -} - -void BotClient_TFC_Damage(void *p, int bot_index) -{ - // this is just like the Valve Battery message - BotClient_Valve_Damage(p, bot_index); -} - -void BotClient_CS_Damage(void *p, int bot_index) -{ - // this is just like the Valve Battery message - BotClient_Valve_Damage(p, bot_index); -} - -void BotClient_Gearbox_Damage(void *p, int bot_index) -{ - // this is just like the Valve Battery message - BotClient_Valve_Damage(p, bot_index); -} - -void BotClient_FLF_Damage(void *p, int bot_index) -{ - // this is just like the Valve Battery message - BotClient_Valve_Damage(p, bot_index); -} - - -// This message gets sent when the bots money ammount changes (for CS) -void BotClient_CS_Money(void *p, int bot_index) -{ - static int state = 0; // current state machine state - - if (state == 0) - { - state++; - - bots[bot_index].bot_money = *(int *)p; // amount of money - } - else - { - state = 0; // ingore this field - } -} - -// This message gets sent when the bots get killed -void BotClient_Valve_DeathMsg(void *p, int bot_index) -{ - static int state = 0; // current state machine state - static int killer_index; - static int victim_index; - static edict_t *victim_edict; - static int index; - - if (state == 0) - { - state++; - killer_index = *(int *)p; // ENTINDEX() of killer - } - else if (state == 1) - { - state++; - victim_index = *(int *)p; // ENTINDEX() of victim - } - else if (state == 2) - { - state = 0; - - victim_edict = INDEXENT(victim_index); - - index = UTIL_GetBotIndex(victim_edict); - - // is this message about a bot being killed? - if (index != -1) - { - if ((killer_index == 0) || (killer_index == victim_index)) - { - // bot killed by world (worldspawn) or bot killed self... - bots[index].killer_edict = NULL; - } - else - { - // store edict of player that killed this bot... - bots[index].killer_edict = INDEXENT(killer_index); - } - } - } -} - -void BotClient_TFC_DeathMsg(void *p, int bot_index) -{ - // this is just like the Valve DeathMsg message - BotClient_Valve_DeathMsg(p, bot_index); -} - -void BotClient_CS_DeathMsg(void *p, int bot_index) -{ - // this is just like the Valve DeathMsg message - BotClient_Valve_DeathMsg(p, bot_index); -} - -void BotClient_Gearbox_DeathMsg(void *p, int bot_index) -{ - // this is just like the Valve DeathMsg message - BotClient_Valve_DeathMsg(p, bot_index); -} - -void BotClient_FLF_DeathMsg(void *p, int bot_index) -{ - // this is just like the Valve DeathMsg message - BotClient_Valve_DeathMsg(p, bot_index); -} - - -// This message gets sent when a text message is displayed -void BotClient_FLF_TextMsg(void *p, int bot_index) -{ - static int state = 0; // current state machine state - static int msg_dest = 0; - - if (state == 0) - { - state++; - msg_dest = *(int *)p; // HUD_PRINTCENTER, etc. - } - else if (state == 1) - { - state = 0; - - if (strcmp((char *)p, "You are Attacking\n") == 0) // attacker msg - { - bots[bot_index].defender = 0; // attacker - } - else if (strcmp((char *)p, "You are Defending\n") == 0) // defender msg - { - bots[bot_index].defender = 1; // defender - } - } -} - - -// This message gets sent when the WarmUpTime is enabled/disabled -void BotClient_FLF_WarmUp(void *p, int bot_index) -{ - bots[bot_index].warmup = *(int *)p; -} - - -// This message gets sent to ALL when the WarmUpTime is enabled/disabled -void BotClient_FLF_WarmUpAll(void *p, int bot_index) -{ - for (int i=0; i < 32; i++) - { - if (bots[i].is_used) // count the number of bots in use - bots[i].warmup = *(int *)p; - } -} - - -// This message gets sent when the round is over -void BotClient_FLF_WinMessage(void *p, int bot_index) -{ - for (int i=0; i < 32; i++) - { - if (bots[i].is_used) // count the number of bots in use - bots[i].round_end = 1; - } -} - - -// This message gets sent when a temp entity is created -void BotClient_FLF_TempEntity(void *p, int bot_index) -{ - static int state = 0; // current state machine state - static int te_type; // TE_ message type - - if (p == NULL) // end of message? - { - state = 0; - return; - } - - if (state == 0) - { - state++; - te_type = *(int *)p; - - return; - } - - if (te_type == TE_TEXTMESSAGE) - { - if (state == 16) - { - if (strncmp((char *)p, "Capturing ", 10) == 0) - { - // if bot is currently capturing, keep timer alive... - if (bots[bot_index].b_use_capture) - bots[bot_index].f_use_capture_time = gpGlobals->time + 2.0; - } - } - - state++; - } -} - - -void BotClient_Valve_ScreenFade(void *p, int bot_index) -{ - static int state = 0; // current state machine state - static int duration; - static int hold_time; - static int fade_flags; - int length; - - if (state == 0) - { - state++; - duration = *(int *)p; - } - else if (state == 1) - { - state++; - hold_time = *(int *)p; - } - else if (state == 2) - { - state++; - fade_flags = *(int *)p; - } - else if (state == 6) - { - state = 0; - - length = (duration + hold_time) / 4096; - bots[bot_index].blinded_time = gpGlobals->time + length - 2.0; - } - else - { - state++; - } -} - -void BotClient_TFC_ScreenFade(void *p, int bot_index) -{ - // this is just like the Valve ScreenFade message - BotClient_Valve_ScreenFade(p, bot_index); -} - -void BotClient_CS_ScreenFade(void *p, int bot_index) -{ - // this is just like the Valve ScreenFade message - BotClient_Valve_ScreenFade(p, bot_index); -} - -void BotClient_Gearbox_ScreenFade(void *p, int bot_index) -{ - // this is just like the Valve ScreenFade message - BotClient_Valve_ScreenFade(p, bot_index); -} - -void BotClient_FLF_ScreenFade(void *p, int bot_index) -{ - // this is just like the Valve ScreenFade message - BotClient_Valve_ScreenFade(p, bot_index); -} - -// AvH client functions -void BotClient_AVH_SetOrder(void *p, int bot_index) -{ - bot_t* theCurrentBot = &bots[bot_index]; - - if(theCurrentBot->mOrderNumPlayers == -1) - { - if (theCurrentBot->mOrderState == 0) - { - // Read num players - theCurrentBot->mOrderState++; - theCurrentBot->mOrderNumPlayers = *(byte *)p; - } - } - else - { - if(theCurrentBot->mOrderState <= theCurrentBot->mOrderNumPlayers) - { - // Skip by players - theCurrentBot->mOrderState++; - } - else - { - int theRealState = theCurrentBot->mOrderState - theCurrentBot->mOrderNumPlayers - 1; - if(theRealState == 0) - { - // read order - theCurrentBot->mOrderState++; - theCurrentBot->mOrderType = *((AvHOrderType *)p); - } - else if(theRealState == 1) - { - // read order target type - theCurrentBot->mOrderState++; - theCurrentBot->mOrderTargetType = *((AvHOrderTargetType *)p); - } - else - { - if((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_LOCATION) && ((theRealState >= 2) && (theRealState <= 4))) - { - theCurrentBot->mOrderLocation[theRealState-2] = *((float*)p); - theCurrentBot->mOrderState++; - } - else if((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_TARGET) && (theRealState == 2)) - { - theCurrentBot->mOrderTargetIndex = *((int*)p); - theCurrentBot->mOrderState++; - } - else if( ((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_LOCATION) && (theRealState == 5)) || - ((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_TARGET) && (theRealState == 3)) || - (theRealState == 2) ) - { - theCurrentBot->mOrderCompleted = *((int*)p); - theCurrentBot->mOrderState++; - } - else - { - // Reset - theCurrentBot->mOrderState = 0; - theCurrentBot->mOrderNumPlayers = -1; - theCurrentBot->mOrderType = ORDERTYPE_UNDEFINED; - theCurrentBot->mOrderTargetType = ORDERTARGETTYPE_UNDEFINED; - theCurrentBot->mOrderLocation[0] = theCurrentBot->mOrderLocation[1] = theCurrentBot->mOrderLocation[2] = 0.0f; - theCurrentBot->mOrderTargetIndex = -1; - theCurrentBot->mOrderCompleted = false; - } - } - } - } -} - - - -void BotClient_AVH_SetPlayMode(void *p, int bot_index) -{ - static int state = 0; // current state machine state - - if (state == 0) - { - state++; - - bots[bot_index].mBotPlayMode = (AvHPlayMode)(*(byte *)p); // amount of money - bots[bot_index].pBotEnemy = NULL; - } - else - { - state = 0; // ingore this field - } -} - -void BotClient_AVH_SetResources(void *p, int bot_index) -{ - static int state = 0; // current state machine state - - if(state == 0) - { - state++; - } - else if(state == 1) - { - bots[bot_index].mResources = (*(int *)p); // amount of money - state += 4; - } - else - { - state = 0; // ingore this field - } -} - - - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_client.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" +#include "bot_func.h" +#include "bot_client.h" +#include "bot_weapons.h" + +// types of damage to ignore... +#define IGNORE_DAMAGE (DMG_CRUSH | DMG_FREEZE | DMG_FALL | DMG_SHOCK | \ + DMG_DROWN | DMG_NERVEGAS | DMG_RADIATION | \ + DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN | \ + DMG_SLOWFREEZE | 0xFF000000) + +extern int mod_id; +extern bot_t bots[32]; + +bot_weapon_t weapon_defs[MAX_WEAPONS]; // array of weapon definitions + + +// This message is sent when the TFC VGUI menu is displayed. +void BotClient_TFC_VGUI(void *p, int bot_index) +{ + if ((*(int *)p) == 2) // is it a team select menu? + + bots[bot_index].start_action = MSG_TFC_TEAM_SELECT; + + else if ((*(int *)p) == 3) // is is a class selection menu? + + bots[bot_index].start_action = MSG_TFC_CLASS_SELECT; +} + + +// This message is sent when the Counter-Strike VGUI menu is displayed. +void BotClient_CS_VGUI(void *p, int bot_index) +{ + if ((*(int *)p) == 2) // is it a team select menu? + + bots[bot_index].start_action = MSG_CS_TEAM_SELECT; + + else if ((*(int *)p) == 26) // is is a terrorist model select menu? + + bots[bot_index].start_action = MSG_CS_T_SELECT; + + else if ((*(int *)p) == 27) // is is a counter-terrorist model select menu? + + bots[bot_index].start_action = MSG_CS_CT_SELECT; +} + + +// This message is sent when a menu is being displayed in Counter-Strike. +void BotClient_CS_ShowMenu(void *p, int bot_index) +{ + static int state = 0; // current state machine state + + if (state < 3) + { + state++; // ignore first 3 fields of message + return; + } + + if (strcmp((char *)p, "#Team_Select") == 0) // team select menu? + { + bots[bot_index].start_action = MSG_CS_TEAM_SELECT; + } + else if (strcmp((char *)p, "#Terrorist_Select") == 0) // T model select? + { + bots[bot_index].start_action = MSG_CS_T_SELECT; + } + else if (strcmp((char *)p, "#CT_Select") == 0) // CT model select menu? + { + bots[bot_index].start_action = MSG_CS_CT_SELECT; + } + + state = 0; // reset state machine +} + + +// This message is sent when the TFC VGUI menu is displayed. +void BotClient_Gearbox_VGUI(void *p, int bot_index) +{ + if ((*(int *)p) == 2) // is it a team select menu? + + bots[bot_index].start_action = MSG_OPFOR_TEAM_SELECT; + + else if ((*(int *)p) == 3) // is is a class selection menu? + + bots[bot_index].start_action = MSG_OPFOR_CLASS_SELECT; +} + + +// This message is sent when the FrontLineForce VGUI menu is displayed. +void BotClient_FLF_VGUI(void *p, int bot_index) +{ + if ((*(int *)p) == 2) // is it a team select menu? + bots[bot_index].start_action = MSG_FLF_TEAM_SELECT; + else if ((*(int *)p) == 3) // is it a class selection menu? + bots[bot_index].start_action = MSG_FLF_CLASS_SELECT; + else if ((*(int *)p) == 70) // is it a weapon selection menu? + bots[bot_index].start_action = MSG_FLF_WEAPON_SELECT; + else if ((*(int *)p) == 72) // is it a submachine gun selection menu? + bots[bot_index].start_action = MSG_FLF_SUBMACHINE_SELECT; + else if ((*(int *)p) == 73) // is it a shotgun selection menu? + bots[bot_index].start_action = MSG_FLF_SHOTGUN_SELECT; + else if ((*(int *)p) == 75) // is it a rifle selection menu? + bots[bot_index].start_action = MSG_FLF_RIFLE_SELECT; + else if ((*(int *)p) == 76) // is it a pistol selection menu? + bots[bot_index].start_action = MSG_FLF_PISTOL_SELECT; + else if ((*(int *)p) == 78) // is it a heavyweapons selection menu? + bots[bot_index].start_action = MSG_FLF_HEAVYWEAPONS_SELECT; +} + + +// This message is sent when a client joins the game. All of the weapons +// are sent with the weapon ID and information about what ammo is used. +void BotClient_Valve_WeaponList(void *p, int bot_index) +{ + static int state = 0; // current state machine state + static bot_weapon_t bot_weapon; + + if (state == 0) + { + state++; + strcpy(bot_weapon.szClassname, (char *)p); + } + else if (state == 1) + { + state++; + bot_weapon.iAmmo1 = *(int *)p; // ammo index 1 + } + else if (state == 2) + { + state++; + bot_weapon.iAmmo1Max = *(int *)p; // max ammo1 + } + else if (state == 3) + { + state++; + bot_weapon.iAmmo2 = *(int *)p; // ammo index 2 + } + else if (state == 4) + { + state++; + bot_weapon.iAmmo2Max = *(int *)p; // max ammo2 + } + else if (state == 5) + { + state++; + bot_weapon.iSlot = *(int *)p; // slot for this weapon + } + else if (state == 6) + { + state++; + bot_weapon.iPosition = *(int *)p; // position in slot + } + else if (state == 7) + { + state++; + bot_weapon.iId = *(int *)p; // weapon ID + } + else if (state == 8) + { + state = 0; + + bot_weapon.iFlags = *(int *)p; // flags for weapon (WTF???) + + // store away this weapon with it's ammo information... + weapon_defs[bot_weapon.iId] = bot_weapon; + } +} + +void BotClient_TFC_WeaponList(void *p, int bot_index) +{ + // this is just like the Valve Weapon List message + BotClient_Valve_WeaponList(p, bot_index); +} + +void BotClient_CS_WeaponList(void *p, int bot_index) +{ + // this is just like the Valve Weapon List message + BotClient_Valve_WeaponList(p, bot_index); +} + +void BotClient_Gearbox_WeaponList(void *p, int bot_index) +{ + // this is just like the Valve Weapon List message + BotClient_Valve_WeaponList(p, bot_index); +} + +void BotClient_FLF_WeaponList(void *p, int bot_index) +{ + // this is just like the Valve Weapon List message + BotClient_Valve_WeaponList(p, bot_index); +} + + +// This message is sent when a weapon is selected (either by the bot chosing +// a weapon or by the server auto assigning the bot a weapon). +void BotClient_Valve_CurrentWeapon(void *p, int bot_index) +{ + static int state = 0; // current state machine state + static int iState; + static int iId; + static int iClip; + + if (state == 0) + { + state++; + iState = *(int *)p; // state of the current weapon + } + else if (state == 1) + { + state++; + iId = *(int *)p; // weapon ID of current weapon + } + else if (state == 2) + { + state = 0; + + iClip = *(int *)p; // ammo currently in the clip for this weapon + + if (iId <= 31) + { + bots[bot_index].bot_weapons |= (1< 0) || (damage_taken > 0)) + { + // ignore certain types of damage... + if (damage_bits & IGNORE_DAMAGE) + return; + + // if the bot doesn't have an enemy and someone is shooting at it then + // turn in the attacker's direction... + if (bots[bot_index].pBotEnemy == NULL) + { + // face the attacker... + Vector v_enemy = damage_origin - bots[bot_index].pEdict->v.origin; + Vector bot_angles = UTIL_VecToAngles( v_enemy ); + + bots[bot_index].pEdict->v.ideal_yaw = bot_angles.y; + + BotFixIdealYaw(bots[bot_index].pEdict); + + // stop using health or HEV stations... + bots[bot_index].b_use_health_station = FALSE; + bots[bot_index].b_use_HEV_station = FALSE; + bots[bot_index].b_use_capture = FALSE; + } + } + } +} + +void BotClient_TFC_Damage(void *p, int bot_index) +{ + // this is just like the Valve Battery message + BotClient_Valve_Damage(p, bot_index); +} + +void BotClient_CS_Damage(void *p, int bot_index) +{ + // this is just like the Valve Battery message + BotClient_Valve_Damage(p, bot_index); +} + +void BotClient_Gearbox_Damage(void *p, int bot_index) +{ + // this is just like the Valve Battery message + BotClient_Valve_Damage(p, bot_index); +} + +void BotClient_FLF_Damage(void *p, int bot_index) +{ + // this is just like the Valve Battery message + BotClient_Valve_Damage(p, bot_index); +} + + +// This message gets sent when the bots money ammount changes (for CS) +void BotClient_CS_Money(void *p, int bot_index) +{ + static int state = 0; // current state machine state + + if (state == 0) + { + state++; + + bots[bot_index].bot_money = *(int *)p; // amount of money + } + else + { + state = 0; // ingore this field + } +} + +// This message gets sent when the bots get killed +void BotClient_Valve_DeathMsg(void *p, int bot_index) +{ + static int state = 0; // current state machine state + static int killer_index; + static int victim_index; + static edict_t *victim_edict; + static int index; + + if (state == 0) + { + state++; + killer_index = *(int *)p; // ENTINDEX() of killer + } + else if (state == 1) + { + state++; + victim_index = *(int *)p; // ENTINDEX() of victim + } + else if (state == 2) + { + state = 0; + + victim_edict = INDEXENT(victim_index); + + index = UTIL_GetBotIndex(victim_edict); + + // is this message about a bot being killed? + if (index != -1) + { + if ((killer_index == 0) || (killer_index == victim_index)) + { + // bot killed by world (worldspawn) or bot killed self... + bots[index].killer_edict = NULL; + } + else + { + // store edict of player that killed this bot... + bots[index].killer_edict = INDEXENT(killer_index); + } + } + } +} + +void BotClient_TFC_DeathMsg(void *p, int bot_index) +{ + // this is just like the Valve DeathMsg message + BotClient_Valve_DeathMsg(p, bot_index); +} + +void BotClient_CS_DeathMsg(void *p, int bot_index) +{ + // this is just like the Valve DeathMsg message + BotClient_Valve_DeathMsg(p, bot_index); +} + +void BotClient_Gearbox_DeathMsg(void *p, int bot_index) +{ + // this is just like the Valve DeathMsg message + BotClient_Valve_DeathMsg(p, bot_index); +} + +void BotClient_FLF_DeathMsg(void *p, int bot_index) +{ + // this is just like the Valve DeathMsg message + BotClient_Valve_DeathMsg(p, bot_index); +} + + +// This message gets sent when a text message is displayed +void BotClient_FLF_TextMsg(void *p, int bot_index) +{ + static int state = 0; // current state machine state + static int msg_dest = 0; + + if (state == 0) + { + state++; + msg_dest = *(int *)p; // HUD_PRINTCENTER, etc. + } + else if (state == 1) + { + state = 0; + + if (strcmp((char *)p, "You are Attacking\n") == 0) // attacker msg + { + bots[bot_index].defender = 0; // attacker + } + else if (strcmp((char *)p, "You are Defending\n") == 0) // defender msg + { + bots[bot_index].defender = 1; // defender + } + } +} + + +// This message gets sent when the WarmUpTime is enabled/disabled +void BotClient_FLF_WarmUp(void *p, int bot_index) +{ + bots[bot_index].warmup = *(int *)p; +} + + +// This message gets sent to ALL when the WarmUpTime is enabled/disabled +void BotClient_FLF_WarmUpAll(void *p, int bot_index) +{ + for (int i=0; i < 32; i++) + { + if (bots[i].is_used) // count the number of bots in use + bots[i].warmup = *(int *)p; + } +} + + +// This message gets sent when the round is over +void BotClient_FLF_WinMessage(void *p, int bot_index) +{ + for (int i=0; i < 32; i++) + { + if (bots[i].is_used) // count the number of bots in use + bots[i].round_end = 1; + } +} + + +// This message gets sent when a temp entity is created +void BotClient_FLF_TempEntity(void *p, int bot_index) +{ + static int state = 0; // current state machine state + static int te_type; // TE_ message type + + if (p == NULL) // end of message? + { + state = 0; + return; + } + + if (state == 0) + { + state++; + te_type = *(int *)p; + + return; + } + + if (te_type == TE_TEXTMESSAGE) + { + if (state == 16) + { + if (strncmp((char *)p, "Capturing ", 10) == 0) + { + // if bot is currently capturing, keep timer alive... + if (bots[bot_index].b_use_capture) + bots[bot_index].f_use_capture_time = gpGlobals->time + 2.0; + } + } + + state++; + } +} + + +void BotClient_Valve_ScreenFade(void *p, int bot_index) +{ + static int state = 0; // current state machine state + static int duration; + static int hold_time; + static int fade_flags; + int length; + + if (state == 0) + { + state++; + duration = *(int *)p; + } + else if (state == 1) + { + state++; + hold_time = *(int *)p; + } + else if (state == 2) + { + state++; + fade_flags = *(int *)p; + } + else if (state == 6) + { + state = 0; + + length = (duration + hold_time) / 4096; + bots[bot_index].blinded_time = gpGlobals->time + length - 2.0; + } + else + { + state++; + } +} + +void BotClient_TFC_ScreenFade(void *p, int bot_index) +{ + // this is just like the Valve ScreenFade message + BotClient_Valve_ScreenFade(p, bot_index); +} + +void BotClient_CS_ScreenFade(void *p, int bot_index) +{ + // this is just like the Valve ScreenFade message + BotClient_Valve_ScreenFade(p, bot_index); +} + +void BotClient_Gearbox_ScreenFade(void *p, int bot_index) +{ + // this is just like the Valve ScreenFade message + BotClient_Valve_ScreenFade(p, bot_index); +} + +void BotClient_FLF_ScreenFade(void *p, int bot_index) +{ + // this is just like the Valve ScreenFade message + BotClient_Valve_ScreenFade(p, bot_index); +} + +// AvH client functions +void BotClient_AVH_SetOrder(void *p, int bot_index) +{ + bot_t* theCurrentBot = &bots[bot_index]; + + if(theCurrentBot->mOrderNumPlayers == -1) + { + if (theCurrentBot->mOrderState == 0) + { + // Read num players + theCurrentBot->mOrderState++; + theCurrentBot->mOrderNumPlayers = *(byte *)p; + } + } + else + { + if(theCurrentBot->mOrderState <= theCurrentBot->mOrderNumPlayers) + { + // Skip by players + theCurrentBot->mOrderState++; + } + else + { + int theRealState = theCurrentBot->mOrderState - theCurrentBot->mOrderNumPlayers - 1; + if(theRealState == 0) + { + // read order + theCurrentBot->mOrderState++; + theCurrentBot->mOrderType = *((AvHOrderType *)p); + } + else if(theRealState == 1) + { + // read order target type + theCurrentBot->mOrderState++; + theCurrentBot->mOrderTargetType = *((AvHOrderTargetType *)p); + } + else + { + if((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_LOCATION) && ((theRealState >= 2) && (theRealState <= 4))) + { + theCurrentBot->mOrderLocation[theRealState-2] = *((float*)p); + theCurrentBot->mOrderState++; + } + else if((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_TARGET) && (theRealState == 2)) + { + theCurrentBot->mOrderTargetIndex = *((int*)p); + theCurrentBot->mOrderState++; + } + else if( ((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_LOCATION) && (theRealState == 5)) || + ((theCurrentBot->mOrderTargetType == ORDERTARGETTYPE_TARGET) && (theRealState == 3)) || + (theRealState == 2) ) + { + theCurrentBot->mOrderCompleted = *((int*)p); + theCurrentBot->mOrderState++; + } + else + { + // Reset + theCurrentBot->mOrderState = 0; + theCurrentBot->mOrderNumPlayers = -1; + theCurrentBot->mOrderType = ORDERTYPE_UNDEFINED; + theCurrentBot->mOrderTargetType = ORDERTARGETTYPE_UNDEFINED; + theCurrentBot->mOrderLocation[0] = theCurrentBot->mOrderLocation[1] = theCurrentBot->mOrderLocation[2] = 0.0f; + theCurrentBot->mOrderTargetIndex = -1; + theCurrentBot->mOrderCompleted = false; + } + } + } + } +} + + + +void BotClient_AVH_SetPlayMode(void *p, int bot_index) +{ + static int state = 0; // current state machine state + + if (state == 0) + { + state++; + + bots[bot_index].mBotPlayMode = (AvHPlayMode)(*(byte *)p); // amount of money + bots[bot_index].pBotEnemy = NULL; + } + else + { + state = 0; // ingore this field + } +} + +void BotClient_AVH_SetResources(void *p, int bot_index) +{ + static int state = 0; // current state machine state + + if(state == 0) + { + state++; + } + else if(state == 1) + { + bots[bot_index].mResources = (*(int *)p); // amount of money + state += 4; + } + else + { + state = 0; // ingore this field + } +} + + + diff --git a/main/source/HPB_bot/dlls/bot_client.h b/main/source/HPB_bot/dlls/bot_client.h index 4dc9e030..67b51fce 100644 --- a/main/source/HPB_bot/dlls/bot_client.h +++ b/main/source/HPB_bot/dlls/bot_client.h @@ -1,96 +1,96 @@ -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_client.h -// - -void BotClient_TFC_VGUI(void *p, int bot_index); -void BotClient_CS_VGUI(void *p, int bot_index); -void BotClient_CS_ShowMenu(void *p, int bot_index); -void BotClient_Gearbox_VGUI(void *p, int bot_index); -void BotClient_FLF_VGUI(void *p, int bot_index); - -void BotClient_Valve_WeaponList(void *p, int bot_index); -void BotClient_TFC_WeaponList(void *p, int bot_index); -void BotClient_CS_WeaponList(void *p, int bot_index); -void BotClient_Gearbox_WeaponList(void *p, int bot_index); -void BotClient_FLF_WeaponList(void *p, int bot_index); - -void BotClient_Valve_CurrentWeapon(void *p, int bot_index); -void BotClient_TFC_CurrentWeapon(void *p, int bot_index); -void BotClient_CS_CurrentWeapon(void *p, int bot_index); -void BotClient_Gearbox_CurrentWeapon(void *p, int bot_index); -void BotClient_FLF_CurrentWeapon(void *p, int bot_index); - -void BotClient_Valve_AmmoX(void *p, int bot_index); -void BotClient_TFC_AmmoX(void *p, int bot_index); -void BotClient_CS_AmmoX(void *p, int bot_index); -void BotClient_Gearbox_AmmoX(void *p, int bot_index); -void BotClient_FLF_AmmoX(void *p, int bot_index); - -void BotClient_Valve_AmmoPickup(void *p, int bot_index); -void BotClient_TFC_AmmoPickup(void *p, int bot_index); -void BotClient_CS_AmmoPickup(void *p, int bot_index); -void BotClient_Gearbox_AmmoPickup(void *p, int bot_index); -void BotClient_FLF_AmmoPickup(void *p, int bot_index); - -void BotClient_Valve_WeaponPickup(void *p, int bot_index); -void BotClient_TFC_WeaponPickup(void *p, int bot_index); -void BotClient_CS_WeaponPickup(void *p, int bot_index); -void BotClient_Gearbox_WeaponPickup(void *p, int bot_index); -void BotClient_FLF_WeaponPickup(void *p, int bot_index); - -void BotClient_Valve_ItemPickup(void *p, int bot_index); -void BotClient_TFC_ItemPickup(void *p, int bot_index); -void BotClient_CS_ItemPickup(void *p, int bot_index); -void BotClient_Gearbox_ItemPickup(void *p, int bot_index); -void BotClient_FLF_ItemPickup(void *p, int bot_index); - -void BotClient_Valve_Health(void *p, int bot_index); -void BotClient_TFC_Health(void *p, int bot_index); -void BotClient_CS_Health(void *p, int bot_index); -void BotClient_Gearbox_Health(void *p, int bot_index); -void BotClient_FLF_Health(void *p, int bot_index); - -void BotClient_Valve_Battery(void *p, int bot_index); -void BotClient_TFC_Battery(void *p, int bot_index); -void BotClient_CS_Battery(void *p, int bot_index); -void BotClient_Gearbox_Battery(void *p, int bot_index); -void BotClient_FLF_Battery(void *p, int bot_index); - -void BotClient_Valve_Damage(void *p, int bot_index); -void BotClient_TFC_Damage(void *p, int bot_index); -void BotClient_CS_Damage(void *p, int bot_index); -void BotClient_Gearbox_Damage(void *p, int bot_index); -void BotClient_FLF_Damage(void *p, int bot_index); - -void BotClient_CS_Money(void *p, int bot_index); - -void BotClient_Valve_DeathMsg(void *p, int bot_index); -void BotClient_TFC_DeathMsg(void *p, int bot_index); -void BotClient_CS_DeathMsg(void *p, int bot_index); -void BotClient_Gearbox_DeathMsg(void *p, int bot_index); -void BotClient_FLF_DeathMsg(void *p, int bot_index); - -void BotClient_FLF_TextMsg(void *p, int bot_index); - -void BotClient_FLF_WarmUp(void *p, int bot_index); -void BotClient_FLF_WarmUpAll(void *p, int bot_index); - -void BotClient_FLF_WinMessage(void *p, int bot_index); - -void BotClient_FLF_TempEntity(void *p, int bot_index); - -void BotClient_Valve_ScreenFade(void *p, int bot_index); -void BotClient_TFC_ScreenFade(void *p, int bot_index); -void BotClient_CS_ScreenFade(void *p, int bot_index); -void BotClient_Gearbox_ScreenFade(void *p, int bot_index); -void BotClient_FLF_ScreenFade(void *p, int bot_index); - -// AvH client functions -void BotClient_AVH_SetOrder(void *p, int bot_index); -void BotClient_AVH_SetPlayMode(void *p, int bot_index); -void BotClient_AVH_SetResources(void *p, int bot_index); - +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_client.h +// + +void BotClient_TFC_VGUI(void *p, int bot_index); +void BotClient_CS_VGUI(void *p, int bot_index); +void BotClient_CS_ShowMenu(void *p, int bot_index); +void BotClient_Gearbox_VGUI(void *p, int bot_index); +void BotClient_FLF_VGUI(void *p, int bot_index); + +void BotClient_Valve_WeaponList(void *p, int bot_index); +void BotClient_TFC_WeaponList(void *p, int bot_index); +void BotClient_CS_WeaponList(void *p, int bot_index); +void BotClient_Gearbox_WeaponList(void *p, int bot_index); +void BotClient_FLF_WeaponList(void *p, int bot_index); + +void BotClient_Valve_CurrentWeapon(void *p, int bot_index); +void BotClient_TFC_CurrentWeapon(void *p, int bot_index); +void BotClient_CS_CurrentWeapon(void *p, int bot_index); +void BotClient_Gearbox_CurrentWeapon(void *p, int bot_index); +void BotClient_FLF_CurrentWeapon(void *p, int bot_index); + +void BotClient_Valve_AmmoX(void *p, int bot_index); +void BotClient_TFC_AmmoX(void *p, int bot_index); +void BotClient_CS_AmmoX(void *p, int bot_index); +void BotClient_Gearbox_AmmoX(void *p, int bot_index); +void BotClient_FLF_AmmoX(void *p, int bot_index); + +void BotClient_Valve_AmmoPickup(void *p, int bot_index); +void BotClient_TFC_AmmoPickup(void *p, int bot_index); +void BotClient_CS_AmmoPickup(void *p, int bot_index); +void BotClient_Gearbox_AmmoPickup(void *p, int bot_index); +void BotClient_FLF_AmmoPickup(void *p, int bot_index); + +void BotClient_Valve_WeaponPickup(void *p, int bot_index); +void BotClient_TFC_WeaponPickup(void *p, int bot_index); +void BotClient_CS_WeaponPickup(void *p, int bot_index); +void BotClient_Gearbox_WeaponPickup(void *p, int bot_index); +void BotClient_FLF_WeaponPickup(void *p, int bot_index); + +void BotClient_Valve_ItemPickup(void *p, int bot_index); +void BotClient_TFC_ItemPickup(void *p, int bot_index); +void BotClient_CS_ItemPickup(void *p, int bot_index); +void BotClient_Gearbox_ItemPickup(void *p, int bot_index); +void BotClient_FLF_ItemPickup(void *p, int bot_index); + +void BotClient_Valve_Health(void *p, int bot_index); +void BotClient_TFC_Health(void *p, int bot_index); +void BotClient_CS_Health(void *p, int bot_index); +void BotClient_Gearbox_Health(void *p, int bot_index); +void BotClient_FLF_Health(void *p, int bot_index); + +void BotClient_Valve_Battery(void *p, int bot_index); +void BotClient_TFC_Battery(void *p, int bot_index); +void BotClient_CS_Battery(void *p, int bot_index); +void BotClient_Gearbox_Battery(void *p, int bot_index); +void BotClient_FLF_Battery(void *p, int bot_index); + +void BotClient_Valve_Damage(void *p, int bot_index); +void BotClient_TFC_Damage(void *p, int bot_index); +void BotClient_CS_Damage(void *p, int bot_index); +void BotClient_Gearbox_Damage(void *p, int bot_index); +void BotClient_FLF_Damage(void *p, int bot_index); + +void BotClient_CS_Money(void *p, int bot_index); + +void BotClient_Valve_DeathMsg(void *p, int bot_index); +void BotClient_TFC_DeathMsg(void *p, int bot_index); +void BotClient_CS_DeathMsg(void *p, int bot_index); +void BotClient_Gearbox_DeathMsg(void *p, int bot_index); +void BotClient_FLF_DeathMsg(void *p, int bot_index); + +void BotClient_FLF_TextMsg(void *p, int bot_index); + +void BotClient_FLF_WarmUp(void *p, int bot_index); +void BotClient_FLF_WarmUpAll(void *p, int bot_index); + +void BotClient_FLF_WinMessage(void *p, int bot_index); + +void BotClient_FLF_TempEntity(void *p, int bot_index); + +void BotClient_Valve_ScreenFade(void *p, int bot_index); +void BotClient_TFC_ScreenFade(void *p, int bot_index); +void BotClient_CS_ScreenFade(void *p, int bot_index); +void BotClient_Gearbox_ScreenFade(void *p, int bot_index); +void BotClient_FLF_ScreenFade(void *p, int bot_index); + +// AvH client functions +void BotClient_AVH_SetOrder(void *p, int bot_index); +void BotClient_AVH_SetPlayMode(void *p, int bot_index); +void BotClient_AVH_SetResources(void *p, int bot_index); + diff --git a/main/source/HPB_bot/dlls/bot_combat.cpp b/main/source/HPB_bot/dlls/bot_combat.cpp index 5854c873..feb19f2e 100644 --- a/main/source/HPB_bot/dlls/bot_combat.cpp +++ b/main/source/HPB_bot/dlls/bot_combat.cpp @@ -1,1301 +1,1301 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_combat.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" -#include "bot_func.h" -#include "bot_weapons.h" -#include "mod/AvHBasePlayerWeaponConstants.h" -#include "mod/AvHMarineWeaponConstants.h" -#include "mod/AvHAlienWeaponConstants.h" -#include "mod/AvHPlayer.h" - -extern int mod_id; -extern bot_weapon_t weapon_defs[MAX_WEAPONS]; -extern bool b_observer_mode; -extern int team_allies[4]; -extern edict_t *pent_info_ctfdetect; -extern float is_team_play; -extern bool checked_teamplay; - -FILE *fp; - - -typedef struct -{ - int iId; // the weapon ID value - char weapon_name[64]; // name of the weapon when selecting it - int skill_level; // bot skill must be less than or equal to this value - float primary_min_distance; // 0 = no minimum - float primary_max_distance; // 9999 = no maximum - float secondary_min_distance; // 0 = no minimum - float secondary_max_distance; // 9999 = no maximum - int use_percent; // times out of 100 to use this weapon when available - bool can_use_underwater; // can use this weapon underwater - int primary_fire_percent; // times out of 100 to use primary fire - int min_primary_ammo; // minimum ammout of primary ammo needed to fire - int min_secondary_ammo; // minimum ammout of seconday ammo needed to fire - bool primary_fire_hold; // hold down primary fire button to use? - bool secondary_fire_hold; // hold down secondary fire button to use? - bool primary_fire_charge; // charge weapon using primary fire? - bool secondary_fire_charge; // charge weapon using secondary fire? - float primary_charge_delay; // time to charge weapon - float secondary_charge_delay; // time to charge weapon -} bot_weapon_select_t; - -typedef struct -{ - int iId; - float primary_base_delay; - float primary_min_delay[5]; - float primary_max_delay[5]; - float secondary_base_delay; - float secondary_min_delay[5]; - float secondary_max_delay[5]; -} bot_fire_delay_t; - - -// weapons are stored in priority order, most desired weapon should be at -// the start of the array and least desired should be at the end - -bot_weapon_select_t valve_weapon_select[] = { - {VALVE_WEAPON_CROWBAR, "weapon_crowbar", 2, 0.0, 50.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_HANDGRENADE, "weapon_handgrenade", 5, 250.0, 750.0, 0.0, 0.0, - 30, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_SNARK, "weapon_snark", 5, 150.0, 500.0, 0.0, 0.0, - 50, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_EGON, "weapon_egon", 5, 0.0, 9999.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_GAUSS, "weapon_gauss", 5, 0.0, 9999.0, 0.0, 9999.0, - 100, FALSE, 80, 1, 10, FALSE, FALSE, FALSE, TRUE, 0.0, 0.8}, - {VALVE_WEAPON_SHOTGUN, "weapon_shotgun", 5, 30.0, 150.0, 30.0, 150.0, - 100, FALSE, 70, 1, 2, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_PYTHON, "weapon_357", 5, 30.0, 700.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_HORNETGUN, "weapon_hornetgun", 5, 30.0, 1000.0, 30.0, 1000.0, - 100, TRUE, 50, 1, 4, FALSE, TRUE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_MP5, "weapon_9mmAR", 5, 0.0, 250.0, 300.0, 600.0, - 100, FALSE, 90, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_CROSSBOW, "weapon_crossbow", 5, 100.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_RPG, "weapon_rpg", 5, 300.0, 9999.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {VALVE_WEAPON_GLOCK, "weapon_9mmhandgun", 5, 0.0, 1200.0, 0.0, 1200.0, - 100, TRUE, 70, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - /* terminator */ - {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} -}; - -bot_weapon_select_t tfc_weapon_select[] = { - {TF_WEAPON_AXE, "tf_weapon_axe", 5, 0.0, 50.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_KNIFE, "tf_weapon_knife", 5, 0.0, 40.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_SPANNER, "tf_weapon_knife", 5, 0.0, 40.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_MEDIKIT, "tf_weapon_medikit", 5, 0.0, 40.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_SNIPERRIFLE, "tf_weapon_sniperrifle", 5, 300.0, 2500.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, TRUE, FALSE, 1.0, 0.0}, - {TF_WEAPON_FLAMETHROWER, "tf_weapon_flamethrower", 5, 100.0, 500.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_AC, "tf_weapon_ac", 5, 50.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_GL, "tf_weapon_gl", 5, 300.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_RPG, "tf_weapon_rpg", 5, 300.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_IC, "tf_weapon_ic", 5, 300.0, 800.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_TRANQ, "tf_weapon_tranq", 5, 40.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_RAILGUN, "tf_weapon_railgun", 5, 40.0, 800.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_SUPERNAILGUN, "tf_weapon_superng", 5, 40.0, 800.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_SUPERSHOTGUN, "tf_weapon_supershotgun", 5, 40.0, 500.0, 0.0, 0.0, - 100, TRUE, 100, 2, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_AUTORIFLE, "tf_weapon_autorifle", 5, 0.0, 800.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_SHOTGUN, "tf_weapon_shotgun", 5, 40.0, 400.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {TF_WEAPON_NAILGUN, "tf_weapon_ng", 5, 40.0, 600.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - /* terminator */ - {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} -}; - -bot_weapon_select_t cs_weapon_select[] = { - {CS_WEAPON_KNIFE, "weapon_knife", 5, 0.0, 50.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {CS_WEAPON_USP, "weapon_usp", 5, 0.0, 1200.0, 0.0, 1200.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {CS_WEAPON_GLOCK18, "weapon_glock18", 5, 0.0, 1200.0, 0.0, 1200.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - /* terminator */ - {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} -}; - -bot_weapon_select_t gearbox_weapon_select[] = { - {GEARBOX_WEAPON_PIPEWRENCH, "weapon_pipewrench", 3, 0.0, 50.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_KNIFE, "weapon_knife", 4, 0.0, 50.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_CROWBAR, "weapon_crowbar", 2, 0.0, 50.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_DISPLACER, "weapon_displacer", 5, 100.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_SPORELAUNCHER, "weapon_sporelauncher", 5, 500.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_SHOCKRIFLE, "weapon_shockrifle", 5, 50.0, 800.0, 0.0, 0.0, - 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_SNIPERRIFLE, "weapon_sniperrifle", 5, 50.0, 1500.0, 0.0, 0.0, - 100, FALSE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_HANDGRENADE, "weapon_handgrenade", 5, 250.0, 750.0, 0.0, 0.0, - 30, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_SNARK, "weapon_snark", 5, 150.0, 500.0, 0.0, 0.0, - 50, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_EGON, "weapon_egon", 5, 0.0, 9999.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_GAUSS, "weapon_gauss", 5, 0.0, 9999.0, 0.0, 9999.0, - 100, FALSE, 80, 1, 10, FALSE, FALSE, FALSE, TRUE, 0.0, 0.8}, - {GEARBOX_WEAPON_M249, "weapon_m249", 5, 0.0, 400.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_SHOTGUN, "weapon_shotgun", 5, 30.0, 150.0, 30.0, 150.0, - 100, FALSE, 70, 1, 2, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_EAGLE, "weapon_eagle", 5, 0.0, 1200.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_PYTHON, "weapon_357", 5, 30.0, 700.0, 0.0, 0.0, - 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_HORNETGUN, "weapon_hornetgun", 5, 30.0, 1000.0, 30.0, 1000.0, - 100, TRUE, 50, 1, 4, FALSE, TRUE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_MP5, "weapon_9mmAR", 5, 0.0, 250.0, 300.0, 600.0, - 100, FALSE, 90, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_CROSSBOW, "weapon_crossbow", 5, 100.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_RPG, "weapon_rpg", 5, 300.0, 9999.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {GEARBOX_WEAPON_GLOCK, "weapon_9mmhandgun", 5, 0.0, 1200.0, 0.0, 1200.0, - 100, TRUE, 70, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - /* terminator */ - {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} -}; - -bot_weapon_select_t frontline_weapon_select[] = { - {FLF_WEAPON_HEGRENADE, "weapon_hegrenade", 3, 200.0, 1000.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_FLASHBANG, "weapon_flashbang", 3, 100.0, 800.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, -// {FLF_WEAPON_KNIFE, "weapon_knife", 3, 0.0, 60.0, 0.0, 0.0, -// 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_HK21, "weapon_hk21", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_UMP45, "weapon_ump45", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_FAMAS, "weapon_famas", 5, 0.0, 500.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_MSG90, "weapon_msg90", 5, 0.0, 2500.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_MP5A2, "weapon_mp5a2", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_AK5, "weapon_ak5", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_MP5SD, "weapon_mp5sd", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_M4, "weapon_m4", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_SPAS12, "weapon_spas12", 5, 0.0, 900.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_MAC10, "weapon_mac10", 5, 0.0, 500.0, 0.0, 0.0, - 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_BERETTA, "weapon_beretta", 5, 0.0, 1200.0, 0.0, 1200.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - {FLF_WEAPON_MK23, "weapon_mk23", 5, 0.0, 1200.0, 0.0, 1200.0, - 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, - /* terminator */ - {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} -}; - -//int iId; // the weapon ID value -//char weapon_name[64]; // name of the weapon when selecting it -//int skill_level; // bot skill must be less than or equal to this value -//float primary_min_distance; // 0 = no minimum -//float primary_max_distance; // 9999 = no maximum -//float secondary_min_distance; // 0 = no minimum -//float secondary_max_distance; // 9999 = no maximum -//int use_percent; // times out of 100 to use this weapon when available -//bool can_use_underwater; // can use this weapon underwater -//int primary_fire_percent; // times out of 100 to use primary fire -//int min_primary_ammo; // minimum ammout of primary ammo needed to fire -//int min_secondary_ammo; // minimum ammout of seconday ammo needed to fire -//bool primary_fire_hold; // hold down primary fire button to use? -//bool secondary_fire_hold; // hold down secondary fire button to use? -//bool primary_fire_charge; // charge weapon using primary fire? -//bool secondary_fire_charge; // charge weapon using secondary fire? -//float primary_charge_delay; // time to charge weapon -//float secondary_charge_delay; // time to charge weapon - -bot_weapon_select_t ns_weapon_select[] = { - {AVH_WEAPON_GRENADE_GUN, kwsGrenadeGun, 3, 120, kGGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_SONIC, kwsShotGun, 3, 0.0, kSGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_HMG, kwsHeavyMachineGun, 3, 0.0, kHMGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_MG, kwsMachineGun, 3, 0.0, kMGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_PISTOL, kwsPistol, 3, 0.0, kHGRange, 0.0, 0.0, 75, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_KNIFE, kwsKnife, 3, 0.0, kKNRange, 0.0, 0.0, 50, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - - // Base alien abilities - {AVH_WEAPON_PRIMALSCREAM, kwsPrimalScream, 3, 0.0, 300, 0.0, 0.0, 20, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_SWIPE, kwsSwipe, 3, 0.0, kSwipeRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_SPORES, kwsSporeGun, 3, 0.0, kSporeRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_SPIT, kwsSpitGun, 3, 0.0, kSpitGRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_CLAWS, kwsClaws, 3, 0.0, kClawsRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_BITE, kwsBiteGun, 3, 0.0, 60, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_ABILITY_LEAP, kwsLeap, 3, 0.0, 600, 0.0, 0.0, 50, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, - {AVH_WEAPON_SPIKE, kwsSpikeGun, 3, 0.0, kSpikeRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, -}; - -// weapon firing delay based on skill (min and max delay for each weapon) -// THESE MUST MATCH THE SAME ORDER AS THE WEAPON SELECT ARRAY!!! - -bot_fire_delay_t valve_fire_delay[] = { - {VALVE_WEAPON_CROWBAR, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_HANDGRENADE, - 0.1, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_SNARK, - 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_EGON, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_GAUSS, - 0.2, {0.0, 0.2, 0.3, 0.5, 1.0}, {0.1, 0.3, 0.5, 0.8, 1.2}, - 1.0, {0.2, 0.3, 0.5, 0.8, 1.2}, {0.5, 0.7, 1.0, 1.5, 2.0}}, - {VALVE_WEAPON_SHOTGUN, - 0.75, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, - 1.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}}, - {VALVE_WEAPON_PYTHON, - 0.75, {0.0, 0.2, 0.4, 1.0, 1.5}, {0.25, 0.5, 0.8, 1.3, 2.2}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_HORNETGUN, - 0.25, {0.0, 0.25, 0.4, 0.6, 1.0}, {0.1, 0.4, 0.7, 1.0, 1.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_MP5, - 0.1, {0.0, 0.1, 0.25, 0.4, 0.5}, {0.1, 0.3, 0.45, 0.65, 0.8}, - 1.0, {0.0, 0.4, 0.7, 1.0, 1.4}, {0.3, 0.7, 1.0, 1.6, 2.0}}, - {VALVE_WEAPON_CROSSBOW, - 0.75, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_RPG, - 1.5, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {VALVE_WEAPON_GLOCK, - 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, - /* terminator */ - {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} -}; - -bot_fire_delay_t tfc_fire_delay[] = { - {TF_WEAPON_AXE, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_KNIFE, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_SPANNER, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_MEDIKIT, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_SNIPERRIFLE, - 1.0, {0.0, 0.4, 0.7, 1.0, 1.4}, {0.3, 0.7, 1.0, 1.6, 2.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_FLAMETHROWER, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_AC, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_GL, - 0.6, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_RPG, - 0.5, {0.0, 0.1, 0.3, 0.6, 1.0}, {0.1, 0.2, 0.7, 1.0, 2.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_IC, - 2.0, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_TRANQ, - 1.5, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_RAILGUN, - 0.4, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_SUPERNAILGUN, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_SUPERSHOTGUN, - 0.6, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_AUTORIFLE, - 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_SHOTGUN, - 0.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {TF_WEAPON_NAILGUN, - 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - /* terminator */ - {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} -}; - -bot_fire_delay_t cs_fire_delay[] = { - {CS_WEAPON_KNIFE, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {CS_WEAPON_USP, - 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, - {CS_WEAPON_GLOCK18, - 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, - /* terminator */ - {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} -}; - -bot_fire_delay_t gearbox_fire_delay[] = { - {GEARBOX_WEAPON_PIPEWRENCH, - 0.5, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_KNIFE, - 0.4, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_CROWBAR, - 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_DISPLACER, - 5.0, {0.0, 0.5, 0.8, 1.6, 2.5}, {0.3, 0.8, 1.4, 2.2, 3.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_SPORELAUNCHER, - 0.5, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_SHOCKRIFLE, - 0.1, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_SNIPERRIFLE, - 1.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_HANDGRENADE, - 0.1, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_SNARK, - 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_EGON, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_GAUSS, - 0.2, {0.0, 0.2, 0.3, 0.5, 1.0}, {0.1, 0.3, 0.5, 0.8, 1.2}, - 1.0, {0.2, 0.3, 0.5, 0.8, 1.2}, {0.5, 0.7, 1.0, 1.5, 2.0}}, - {GEARBOX_WEAPON_M249, - 0.1, {0.0, 0.1, 0.25, 0.4, 0.5}, {0.1, 0.3, 0.45, 0.65, 0.8}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_SHOTGUN, - 0.75, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, - 1.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}}, - {GEARBOX_WEAPON_EAGLE, - 0.25, {0.0, 0.1, 0.2, 0.3, 0.5}, {0.1, 0.25, 0.4, 0.7, 1.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_PYTHON, - 0.75, {0.0, 0.2, 0.4, 1.0, 1.5}, {0.25, 0.5, 0.8, 1.3, 2.2}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_HORNETGUN, - 0.25, {0.0, 0.25, 0.4, 0.6, 1.0}, {0.1, 0.4, 0.7, 1.0, 1.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_MP5, - 0.1, {0.0, 0.1, 0.25, 0.4, 0.5}, {0.1, 0.3, 0.45, 0.65, 0.8}, - 1.0, {0.0, 0.4, 0.7, 1.0, 1.4}, {0.3, 0.7, 1.0, 1.6, 2.0}}, - {GEARBOX_WEAPON_CROSSBOW, - 0.75, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_RPG, - 1.5, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {GEARBOX_WEAPON_GLOCK, - 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, - /* terminator */ - {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} -}; - -bot_fire_delay_t frontline_fire_delay[] = { - {FLF_WEAPON_HEGRENADE, - 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_FLASHBANG, - 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, -// {FLF_WEAPON_KNIFE, -// 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, -// 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, - {FLF_WEAPON_HK21, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_UMP45, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_FAMAS, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_MSG90, - 1.2, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_MP5A2, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_AK5, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_MP5SD, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_M4, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_SPAS12, - 0.9, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_MAC10, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_BERETTA, - 0.4, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {FLF_WEAPON_MK23, - 0.4, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - /* terminator */ - {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, - 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} -}; -bot_fire_delay_t ns_fire_delay[] = { - {AVH_WEAPON_GRENADE_GUN, 0.3f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.2, 0.3, 0.4, 0.5, 1.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_SONIC, 0.0f, {0.0, 0.0, 0.0, 0.1, 0.3}, {0.0, 0.0, 0.0, 0.2, 0.6}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_HMG, 0.0f, {0.0, 0.0, 0.0, 0.1, 0.3}, {0.0, 0.0, 0.0, 0.2, 0.6}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_MG, 0.0f, {0.0, 0.0, 0.0, 0.1, 0.3}, {0.0, 0.0, 0.0, 0.2, 0.6}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_PISTOL, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.1, 0.15, 0.2, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_KNIFE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - - {AVH_WEAPON_PRIMALSCREAM, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_SWIPE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_SPORES, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_SPIT, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_CLAWS, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.4, 0.5}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_BITE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_ABILITY_LEAP, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, - {AVH_WEAPON_SPIKE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} -}; - -void BotCheckTeamplay(void) -{ - // is this TFC or Counter-Strike or OpFor teamplay or FrontLineForce? - if ((mod_id == TFC_DLL) || (mod_id == CSTRIKE_DLL) || - ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) || - (mod_id == FRONTLINE_DLL) || - (mod_id == AVH_DLL) ) - is_team_play = 1.0; - else - is_team_play = CVAR_GET_FLOAT("mp_teamplay"); // teamplay enabled? - - checked_teamplay = TRUE; -} - - -edict_t *BotFindEnemy( bot_t *pBot ) -{ - Vector vecEnd; - static bool flag=TRUE; - edict_t *pent = NULL; - edict_t *pNewEnemy; - float nearestdistance; - int i; - - edict_t *pEdict = pBot->pEdict; - - if(pBot->mBotPlayMode != PLAYMODE_PLAYING) - { - pBot->pBotEnemy = NULL; - } - - if (pBot->pBotEnemy != NULL) // does the bot already have an enemy? - { - vecEnd = pBot->pBotEnemy->v.origin + pBot->pBotEnemy->v.view_ofs; - - // if the enemy is dead? - if (!IsAlive(pBot->pBotEnemy)) // is the enemy dead?, assume bot killed it - { - // the enemy is dead, jump for joy about 10% of the time - if (RANDOM_LONG(1, 100) <= 10) - pEdict->v.button |= IN_JUMP; - - // Taunt sometimes after a kill - if(RANDOM_LONG(1, 5) == 1) - { - pBot->mTimeOfNextTaunt = gpGlobals->time + RANDOM_FLOAT(.3f, 4.0f); - } - - // don't have an enemy anymore so null out the pointer... - pBot->pBotEnemy = NULL; - } - else if (FInViewCone( &vecEnd, pEdict ) && - FVisible( vecEnd, pEdict )) - { - if ((mod_id == TFC_DLL) && - (pEdict->v.playerclass == TFC_CLASS_MEDIC)) - { - if (pBot->pBotEnemy->v.health >= pBot->pBotEnemy->v.max_health) - { - pBot->pBotEnemy = NULL; // player is healed, null out pointer - } - } - else - { - // if enemy is still visible and in field of view, keep it - - // face the enemy - Vector v_enemy = pBot->pBotEnemy->v.origin - pEdict->v.origin; - Vector bot_angles = UTIL_VecToAngles( v_enemy ); - - pEdict->v.ideal_yaw = bot_angles.y; - - BotFixIdealYaw(pEdict); - - // keep track of when we last saw an enemy - pBot->f_bot_see_enemy_time = gpGlobals->time; - - return (pBot->pBotEnemy); - } - } - } - - pent = NULL; - pNewEnemy = NULL; - nearestdistance = 1000; - - if (mod_id == TFC_DLL) - { - if (pEdict->v.playerclass == TFC_CLASS_MEDIC) - { - // search the world for players... - for (i = 1; i <= gpGlobals->maxClients; i++) - { - edict_t *pPlayer = INDEXENT(i); - - // skip invalid players and skip self (i.e. this bot) - if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) - { - // skip this player if not alive (i.e. dead or dying) - if (!IsAlive(pPlayer)) - continue; - - if ((b_observer_mode) && !(pPlayer->v.flags & FL_FAKECLIENT)) - continue; - - int player_team = UTIL_GetTeam(pPlayer); - int bot_team = UTIL_GetTeam(pEdict); - - // don't target your enemies... - if ((bot_team != player_team) && - !(team_allies[bot_team] & (1<v.health / pPlayer->v.max_health) > 0.50) - continue; // health greater than 50% so ignore - - vecEnd = pPlayer->v.origin + pPlayer->v.view_ofs; - - // see if bot can see the player... - if (FInViewCone( &vecEnd, pEdict ) && - FVisible( vecEnd, pEdict )) - { - float distance = (pPlayer->v.origin - pEdict->v.origin).Length(); - - if (distance < nearestdistance) - { - nearestdistance = distance; - pNewEnemy = pPlayer; - - pBot->pBotUser = NULL; // don't follow user when enemy found - } - } - } - } - } - - if (pNewEnemy == NULL) - { - while ((pent = UTIL_FindEntityByClassname( pent, "building_sentrygun" )) != NULL) - { - int sentry_team = -1; - int bot_team = UTIL_GetTeam(pEdict); - - if (pent->v.colormap == 0xA096) - sentry_team = 0; // blue team's sentry - else if (pent->v.colormap == 0x04FA) - sentry_team = 1; // red team's sentry - else if (pent->v.colormap == 0x372D) - sentry_team = 2; // yellow team's sentry - else if (pent->v.colormap == 0x6E64) - sentry_team = 3; // green team's sentry - - // don't target your own team's sentry guns... - if (bot_team == sentry_team) - continue; - - // don't target your allie's sentry guns either... - if (team_allies[bot_team] & (1<v.origin + pent->v.view_ofs; - - // is this sentry gun visible? - if (FInViewCone( &vecEnd, pEdict ) && - FVisible( vecEnd, pEdict )) - { - float distance = (pent->v.origin - pEdict->v.origin).Length(); - - // is this the closest sentry gun? - if (distance < nearestdistance) - { - nearestdistance = distance; - pNewEnemy = pent; - - pBot->pBotUser = NULL; // don't follow user when enemy found - } - } - } - } - } - - if (pNewEnemy == NULL) - { - nearestdistance = 2500; - - // search the world for players...(and enemies) - //for (i = 1; i <= gpGlobals->maxClients; i++) - for (i = 1; i <= gpGlobals->maxEntities; i++) - { - edict_t *pEntity = INDEXENT(i); - - // skip invalid players and skip self (i.e. this bot) - if ((pEntity) && (!pEntity->free) && (pEntity != pEdict) && (FBitSet(pEntity->v.flags, FL_MONSTER) || FBitSet(pEntity->v.flags, FL_CLIENT))) - { - // Skip webs? - const char* theClassName = STRING(pEntity->v.classname); - - // Skip cloaked players -// if(pEntity->v.iuser4 & MASK_ALIEN_CLOAKED) -// continue; - - // skip this player if not alive (i.e. dead or dying) - if (!IsAlive(pEntity)) - continue; - - if ((b_observer_mode) && !(pEntity->v.flags & FL_FAKECLIENT)) - continue; - - if (!checked_teamplay) // check for team play... - BotCheckTeamplay(); - - // is team play enabled? - if (is_team_play > 0.0) - { - int player_team = UTIL_GetTeam(pEntity); - int bot_team = UTIL_GetTeam(pEdict); - - // don't target your teammates... - if (bot_team == player_team) - continue; - - if (mod_id == TFC_DLL) - { - // don't target your allies either... - if (team_allies[bot_team] & (1<v.origin + pEntity->v.view_ofs; - - float theDistance = (pEdict->v.origin - pEntity->v.origin).Length(); - - // see if bot can see the player... - if ((FInViewCone( &vecEnd, pEdict ) && - FVisible( vecEnd, pEdict )) || (theDistance < 32)) - { - float distance = (pEntity->v.origin - pEdict->v.origin).Length(); - if (distance < nearestdistance) - { - nearestdistance = distance; - pNewEnemy = pEntity; - - pBot->pBotUser = NULL; // don't follow user when enemy found - } - } - } - } - } - - if (pNewEnemy) - { - // face the enemy - Vector v_enemy = pNewEnemy->v.origin - pEdict->v.origin; - Vector bot_angles = UTIL_VecToAngles( v_enemy ); - - pEdict->v.ideal_yaw = bot_angles.y; - - BotFixIdealYaw(pEdict); - - // keep track of when we last saw an enemy - pBot->f_bot_see_enemy_time = gpGlobals->time; - } - - // has the bot NOT seen an ememy for at least 5 seconds (time to reload)? - if ((pBot->f_bot_see_enemy_time > 0) && - ((pBot->f_bot_see_enemy_time + 5.0) <= gpGlobals->time)) - { - pBot->f_bot_see_enemy_time = -1; // so we won't keep reloading - - if ((mod_id == VALVE_DLL) || (mod_id == GEARBOX_DLL) || (mod_id == AVH_DLL)) - { - pEdict->v.button |= IN_RELOAD; // press reload button - } - } - - return (pNewEnemy); -} - - -Vector BotBodyTarget( edict_t *pBotEnemy, bot_t *pBot ) -{ - Vector target; - float f_distance; - float f_scale; - int d_x = 0; - int d_y = 0; - int d_z = 0; - - edict_t *pEdict = pBot->pEdict; - - f_distance = (pBotEnemy->v.origin - pEdict->v.origin).Length(); - - if (f_distance > 1000) - f_scale = 1.0; - else if (f_distance > 100) - f_scale = f_distance / 1000.0; - else - f_scale = 0.1; - - switch (pBot->bot_skill) - { - case 0: - // VERY GOOD, same as from CBasePlayer::BodyTarget (in player.h) - target = pBotEnemy->v.origin + pBotEnemy->v.view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); - d_x = 0; // no offset - d_y = 0; - d_z = 0; - break; - case 1: - // GOOD, offset a little for x, y, and z - target = pBotEnemy->v.origin + pBotEnemy->v.view_ofs; // aim for the head (if you can find it) - d_x = RANDOM_FLOAT(-5, 5) * f_scale; - d_y = RANDOM_FLOAT(-5, 5) * f_scale; - d_z = RANDOM_FLOAT(-10, 10) * f_scale; - break; - case 2: - // FAIR, offset somewhat for x, y, and z - target = pBotEnemy->v.origin; // aim for the body - d_x = RANDOM_FLOAT(-10, 10) * f_scale; - d_y = RANDOM_FLOAT(-10, 10) * f_scale; - d_z = RANDOM_FLOAT(-18, 18) * f_scale; - break; - case 3: - // POOR, offset for x, y, and z - target = pBotEnemy->v.origin; // aim for the body - d_x = RANDOM_FLOAT(-20, 20) * f_scale; - d_y = RANDOM_FLOAT(-20, 20) * f_scale; - d_z = RANDOM_FLOAT(-32, 32) * f_scale; - break; - case 4: - // BAD, offset lots for x, y, and z - target = pBotEnemy->v.origin; // aim for the body - d_x = RANDOM_FLOAT(-35, 35) * f_scale; - d_y = RANDOM_FLOAT(-35, 35) * f_scale; - d_z = RANDOM_FLOAT(-50, 50) * f_scale; - break; - } - - target = target + Vector(d_x, d_y, d_z); - - return target; -} - - -// specifing a weapon_choice allows you to choose the weapon the bot will -// use (assuming enough ammo exists for that weapon) -// BotFireWeapon will return TRUE if weapon was fired, FALSE otherwise - -bool BotFireWeapon( Vector v_enemy, bot_t *pBot, int weapon_choice) -{ - bot_weapon_select_t *pSelect = NULL; - bot_fire_delay_t *pDelay = NULL; - int select_index; - int iId; - bool use_primary; - bool use_secondary; - int use_percent; - int primary_percent; - - edict_t *pEdict = pBot->pEdict; - - float distance = v_enemy.Length(); // how far away is the enemy? - - if (mod_id == VALVE_DLL) - { - pSelect = &valve_weapon_select[0]; - pDelay = &valve_fire_delay[0]; - } - else if (mod_id == TFC_DLL) - { - pSelect = &tfc_weapon_select[0]; - pDelay = &tfc_fire_delay[0]; - } - else if (mod_id == CSTRIKE_DLL) - { - pSelect = &cs_weapon_select[0]; - pDelay = &cs_fire_delay[0]; - } - else if (mod_id == GEARBOX_DLL) - { - pSelect = &gearbox_weapon_select[0]; - pDelay = &gearbox_fire_delay[0]; - } - else if (mod_id == FRONTLINE_DLL) - { - pSelect = &frontline_weapon_select[0]; - pDelay = &frontline_fire_delay[0]; - } - else if (mod_id == AVH_DLL) - { - pSelect = &ns_weapon_select[0]; - pDelay = &ns_fire_delay[0]; - } - - if (pSelect) - { - // are we charging the primary fire? - if (pBot->f_primary_charging > 0) - { - iId = pBot->charging_weapon_id; - - if (mod_id == TFC_DLL) - { - if (iId == TF_WEAPON_SNIPERRIFLE) - { - pBot->f_move_speed = 0; // don't move while using sniper rifle - } - } - - // is it time to fire the charged weapon? - if (pBot->f_primary_charging <= gpGlobals->time) - { - // we DON'T set pEdict->v.button here to release the - // fire button which will fire the charged weapon - - pBot->f_primary_charging = -1; // -1 means not charging - - // find the correct fire delay for this weapon - select_index = 0; - - while ((pSelect[select_index].iId) && - (pSelect[select_index].iId != iId)) - select_index++; - - // set next time to shoot - int skill = pBot->bot_skill; - float base_delay, min_delay, max_delay; - - base_delay = pDelay[select_index].primary_base_delay; - min_delay = pDelay[select_index].primary_min_delay[skill]; - max_delay = pDelay[select_index].primary_max_delay[skill]; - - pBot->f_shoot_time = gpGlobals->time + base_delay + - RANDOM_FLOAT(min_delay, max_delay); - - return TRUE; - } - else - { - pEdict->v.button |= IN_ATTACK; // charge the weapon - pBot->f_shoot_time = gpGlobals->time; // keep charging - - return TRUE; - } - } - - // are we charging the secondary fire? - if (pBot->f_secondary_charging > 0) - { - iId = pBot->charging_weapon_id; - - // is it time to fire the charged weapon? - if (pBot->f_secondary_charging <= gpGlobals->time) - { - // we DON'T set pEdict->v.button here to release the - // fire button which will fire the charged weapon - - pBot->f_secondary_charging = -1; // -1 means not charging - - // find the correct fire delay for this weapon - select_index = 0; - - while ((pSelect[select_index].iId) && - (pSelect[select_index].iId != iId)) - select_index++; - - // set next time to shoot - int skill = pBot->bot_skill; - float base_delay, min_delay, max_delay; - - base_delay = pDelay[select_index].secondary_base_delay; - min_delay = pDelay[select_index].secondary_min_delay[skill]; - max_delay = pDelay[select_index].secondary_max_delay[skill]; - - pBot->f_shoot_time = gpGlobals->time + base_delay + - RANDOM_FLOAT(min_delay, max_delay); - - return TRUE; - } - else - { - pEdict->v.button |= IN_ATTACK2; // charge the weapon - pBot->f_shoot_time = gpGlobals->time; // keep charging - - return TRUE; - } - } - - select_index = 0; - - // loop through all the weapons until terminator is found... - while (pSelect[select_index].iId) - { - // was a weapon choice specified? (and if so do they NOT match?) - if ((weapon_choice != 0) && - (weapon_choice != pSelect[select_index].iId)) - { - select_index++; // skip to next weapon - continue; - } - - // is the bot NOT carrying this weapon? - if (!(pBot->bot_weapons & (1<bot_skill+1) > pSelect[select_index].skill_level) - { - select_index++; // skip to next weapon - continue; - } - - // is the bot underwater and does this weapon NOT work under water? - if ((pEdict->v.waterlevel == 3) && - !(pSelect[select_index].can_use_underwater)) - { - select_index++; // skip to next weapon - continue; - } - - use_percent = RANDOM_LONG(1, 100); - - // is use percent greater than weapon use percent? - if (use_percent > pSelect[select_index].use_percent) - { - select_index++; // skip to next weapon - continue; - } - - iId = pSelect[select_index].iId; - use_primary = FALSE; - use_secondary = FALSE; - primary_percent = RANDOM_LONG(1, 100); - - // is primary percent less than weapon primary percent AND - // no ammo required for this weapon OR - // enough ammo available to fire AND - // the bot is far enough away to use primary fire AND - // the bot is close enough to the enemy to use primary fire - - if ((primary_percent <= pSelect[select_index].primary_fire_percent) && - ((weapon_defs[iId].iAmmo1 == -1) || - (pBot->m_rgAmmo[weapon_defs[iId].iAmmo1] >= - pSelect[select_index].min_primary_ammo)) && - (distance >= pSelect[select_index].primary_min_distance) && - (distance <= pSelect[select_index].primary_max_distance)) - { - use_primary = TRUE; - } - - // otherwise see if there is enough secondary ammo AND - // the bot is far enough away to use secondary fire AND - // the bot is close enough to the enemy to use secondary fire - - else if (((weapon_defs[iId].iAmmo2 == -1) || - (pBot->m_rgAmmo[weapon_defs[iId].iAmmo2] >= - pSelect[select_index].min_secondary_ammo)) && - (distance >= pSelect[select_index].secondary_min_distance) && - (distance <= pSelect[select_index].secondary_max_distance)) - { - use_secondary = TRUE; - } - - // see if there wasn't enough ammo to fire the weapon... - if ((use_primary == FALSE) && (use_secondary == FALSE)) - { - select_index++; // skip to next weapon - continue; - } - - // select this weapon if it isn't already selected - if (pBot->current_weapon.iId != iId) - UTIL_SelectItem(pEdict, pSelect[select_index].weapon_name); - - if (pDelay[select_index].iId != iId) - { - char msg[80]; - sprintf(msg, "fire_delay mismatch for weapon id=%d\n",iId); - ALERT(at_console, msg); - - return FALSE; - } - - if (mod_id == TFC_DLL) - { - if (iId == TF_WEAPON_SNIPERRIFLE) - { - pBot->f_move_speed = 0; // don't move while using sniper rifle - - if (pEdict->v.velocity.Length() > 50) - { - return FALSE; // don't press attack key until velocity is < 50 - } - } - - if (pEdict->v.playerclass == TFC_CLASS_MEDIC) - { - int player_team = UTIL_GetTeam(pBot->pBotEnemy); - int bot_team = UTIL_GetTeam(pEdict); - - // only heal your teammates or allies... - if (((bot_team == player_team) || - (team_allies[bot_team] & (1<v.button |= IN_ATTACK; // use primary attack - - if (pSelect[select_index].primary_fire_charge) - { - pBot->charging_weapon_id = iId; - - // release primary fire after the appropriate delay... - pBot->f_primary_charging = gpGlobals->time + - pSelect[select_index].primary_charge_delay; - - pBot->f_shoot_time = gpGlobals->time; // keep charging - } - else - { - // set next time to shoot - if (pSelect[select_index].primary_fire_hold) - pBot->f_shoot_time = gpGlobals->time; // don't let button up - else - { - int skill = pBot->bot_skill; - float base_delay, min_delay, max_delay; - - base_delay = pDelay[select_index].primary_base_delay; - min_delay = pDelay[select_index].primary_min_delay[skill]; - max_delay = pDelay[select_index].primary_max_delay[skill]; - - pBot->f_shoot_time = gpGlobals->time + base_delay + - RANDOM_FLOAT(min_delay, max_delay); - } - } - } - else // MUST be use_secondary... - { - pEdict->v.button |= IN_ATTACK2; // use secondary attack - - if (pSelect[select_index].secondary_fire_charge) - { - pBot->charging_weapon_id = iId; - - // release secondary fire after the appropriate delay... - pBot->f_secondary_charging = gpGlobals->time + - pSelect[select_index].secondary_charge_delay; - - pBot->f_shoot_time = gpGlobals->time; // keep charging - } - else - { - // set next time to shoot - if (pSelect[select_index].secondary_fire_hold) - pBot->f_shoot_time = gpGlobals->time; // don't let button up - else - { - int skill = pBot->bot_skill; - float base_delay, min_delay, max_delay; - - base_delay = pDelay[select_index].secondary_base_delay; - min_delay = pDelay[select_index].secondary_min_delay[skill]; - max_delay = pDelay[select_index].secondary_max_delay[skill]; - - pBot->f_shoot_time = gpGlobals->time + base_delay + - RANDOM_FLOAT(min_delay, max_delay); - } - } - } - - return TRUE; // weapon was fired - } - } - - // didn't have any available weapons or ammo, return FALSE - return FALSE; -} - - -void BotShootAtEnemy( bot_t *pBot ) -{ - float f_distance; - - edict_t *pEdict = pBot->pEdict; - - // aim for the head and/or body - Vector v_enemy = BotBodyTarget( pBot->pBotEnemy, pBot ) - GetGunPosition(pEdict); - - pEdict->v.v_angle = UTIL_VecToAngles( v_enemy ); - - if (pEdict->v.v_angle.y > 180) - pEdict->v.v_angle.y -=360; - - // Paulo-La-Frite - START bot aiming bug fix - if (pEdict->v.v_angle.x > 180) - pEdict->v.v_angle.x -=360; - - // set the body angles to point the gun correctly - pEdict->v.angles.x = pEdict->v.v_angle.x / 3; - pEdict->v.angles.y = pEdict->v.v_angle.y; - pEdict->v.angles.z = 0; - - // adjust the view angle pitch to aim correctly (MUST be after body v.angles stuff) - pEdict->v.v_angle.x = -pEdict->v.v_angle.x; - // Paulo-La-Frite - END - - float x = pEdict->v.v_angle.y; - if (x > 180) x -= 360; - if (abs(pEdict->v.ideal_yaw - x) > 2.0) - fp = NULL; - - pEdict->v.ideal_yaw = pEdict->v.v_angle.y; - - BotFixIdealYaw(pEdict); - - - v_enemy.z = 0; // ignore z component (up & down) - - f_distance = v_enemy.Length(); // how far away is the enemy scum? - - if (f_distance > 200) // run if distance to enemy is far - pBot->f_move_speed = pBot->f_max_speed; - else if (f_distance > 20) // walk if distance is closer - pBot->f_move_speed = pBot->f_max_speed / 2; - else // don't move if close enough - pBot->f_move_speed = 0.0; - - - // is it time to shoot yet? - if (pBot->f_shoot_time <= gpGlobals->time) - { - // select the best weapon to use at this distance and fire... - BotFireWeapon(v_enemy, pBot, 0); - } -} - - -bool BotShootTripmine( bot_t *pBot ) -{ - edict_t *pEdict = pBot->pEdict; - - if (pBot->b_shoot_tripmine != TRUE) - return FALSE; - - // aim at the tripmine and fire the glock... - - Vector v_enemy = pBot->v_tripmine - GetGunPosition( pEdict ); - - pEdict->v.v_angle = UTIL_VecToAngles( v_enemy ); - - if (pEdict->v.v_angle.y > 180) - pEdict->v.v_angle.y -=360; - - // Paulo-La-Frite - START bot aiming bug fix - if (pEdict->v.v_angle.x > 180) - pEdict->v.v_angle.x -=360; - - // set the body angles to point the gun correctly - pEdict->v.angles.x = pEdict->v.v_angle.x / 3; - pEdict->v.angles.y = pEdict->v.v_angle.y; - pEdict->v.angles.z = 0; - - // adjust the view angle pitch to aim correctly (MUST be after body v.angles stuff) - pEdict->v.v_angle.x = -pEdict->v.v_angle.x; - // Paulo-La-Frite - END - - pEdict->v.ideal_yaw = pEdict->v.v_angle.y; - - BotFixIdealYaw(pEdict); - - return (BotFireWeapon( v_enemy, pBot, VALVE_WEAPON_GLOCK )); -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_combat.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" +#include "bot_func.h" +#include "bot_weapons.h" +#include "mod/AvHBasePlayerWeaponConstants.h" +#include "mod/AvHMarineWeaponConstants.h" +#include "mod/AvHAlienWeaponConstants.h" +#include "mod/AvHPlayer.h" + +extern int mod_id; +extern bot_weapon_t weapon_defs[MAX_WEAPONS]; +extern bool b_observer_mode; +extern int team_allies[4]; +extern edict_t *pent_info_ctfdetect; +extern float is_team_play; +extern bool checked_teamplay; + +FILE *fp; + + +typedef struct +{ + int iId; // the weapon ID value + char weapon_name[64]; // name of the weapon when selecting it + int skill_level; // bot skill must be less than or equal to this value + float primary_min_distance; // 0 = no minimum + float primary_max_distance; // 9999 = no maximum + float secondary_min_distance; // 0 = no minimum + float secondary_max_distance; // 9999 = no maximum + int use_percent; // times out of 100 to use this weapon when available + bool can_use_underwater; // can use this weapon underwater + int primary_fire_percent; // times out of 100 to use primary fire + int min_primary_ammo; // minimum ammout of primary ammo needed to fire + int min_secondary_ammo; // minimum ammout of seconday ammo needed to fire + bool primary_fire_hold; // hold down primary fire button to use? + bool secondary_fire_hold; // hold down secondary fire button to use? + bool primary_fire_charge; // charge weapon using primary fire? + bool secondary_fire_charge; // charge weapon using secondary fire? + float primary_charge_delay; // time to charge weapon + float secondary_charge_delay; // time to charge weapon +} bot_weapon_select_t; + +typedef struct +{ + int iId; + float primary_base_delay; + float primary_min_delay[5]; + float primary_max_delay[5]; + float secondary_base_delay; + float secondary_min_delay[5]; + float secondary_max_delay[5]; +} bot_fire_delay_t; + + +// weapons are stored in priority order, most desired weapon should be at +// the start of the array and least desired should be at the end + +bot_weapon_select_t valve_weapon_select[] = { + {VALVE_WEAPON_CROWBAR, "weapon_crowbar", 2, 0.0, 50.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_HANDGRENADE, "weapon_handgrenade", 5, 250.0, 750.0, 0.0, 0.0, + 30, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_SNARK, "weapon_snark", 5, 150.0, 500.0, 0.0, 0.0, + 50, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_EGON, "weapon_egon", 5, 0.0, 9999.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_GAUSS, "weapon_gauss", 5, 0.0, 9999.0, 0.0, 9999.0, + 100, FALSE, 80, 1, 10, FALSE, FALSE, FALSE, TRUE, 0.0, 0.8}, + {VALVE_WEAPON_SHOTGUN, "weapon_shotgun", 5, 30.0, 150.0, 30.0, 150.0, + 100, FALSE, 70, 1, 2, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_PYTHON, "weapon_357", 5, 30.0, 700.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_HORNETGUN, "weapon_hornetgun", 5, 30.0, 1000.0, 30.0, 1000.0, + 100, TRUE, 50, 1, 4, FALSE, TRUE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_MP5, "weapon_9mmAR", 5, 0.0, 250.0, 300.0, 600.0, + 100, FALSE, 90, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_CROSSBOW, "weapon_crossbow", 5, 100.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_RPG, "weapon_rpg", 5, 300.0, 9999.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {VALVE_WEAPON_GLOCK, "weapon_9mmhandgun", 5, 0.0, 1200.0, 0.0, 1200.0, + 100, TRUE, 70, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + /* terminator */ + {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} +}; + +bot_weapon_select_t tfc_weapon_select[] = { + {TF_WEAPON_AXE, "tf_weapon_axe", 5, 0.0, 50.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_KNIFE, "tf_weapon_knife", 5, 0.0, 40.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_SPANNER, "tf_weapon_knife", 5, 0.0, 40.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_MEDIKIT, "tf_weapon_medikit", 5, 0.0, 40.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_SNIPERRIFLE, "tf_weapon_sniperrifle", 5, 300.0, 2500.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, TRUE, FALSE, 1.0, 0.0}, + {TF_WEAPON_FLAMETHROWER, "tf_weapon_flamethrower", 5, 100.0, 500.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_AC, "tf_weapon_ac", 5, 50.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_GL, "tf_weapon_gl", 5, 300.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_RPG, "tf_weapon_rpg", 5, 300.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_IC, "tf_weapon_ic", 5, 300.0, 800.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_TRANQ, "tf_weapon_tranq", 5, 40.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_RAILGUN, "tf_weapon_railgun", 5, 40.0, 800.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_SUPERNAILGUN, "tf_weapon_superng", 5, 40.0, 800.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_SUPERSHOTGUN, "tf_weapon_supershotgun", 5, 40.0, 500.0, 0.0, 0.0, + 100, TRUE, 100, 2, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_AUTORIFLE, "tf_weapon_autorifle", 5, 0.0, 800.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_SHOTGUN, "tf_weapon_shotgun", 5, 40.0, 400.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {TF_WEAPON_NAILGUN, "tf_weapon_ng", 5, 40.0, 600.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + /* terminator */ + {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} +}; + +bot_weapon_select_t cs_weapon_select[] = { + {CS_WEAPON_KNIFE, "weapon_knife", 5, 0.0, 50.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {CS_WEAPON_USP, "weapon_usp", 5, 0.0, 1200.0, 0.0, 1200.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {CS_WEAPON_GLOCK18, "weapon_glock18", 5, 0.0, 1200.0, 0.0, 1200.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + /* terminator */ + {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} +}; + +bot_weapon_select_t gearbox_weapon_select[] = { + {GEARBOX_WEAPON_PIPEWRENCH, "weapon_pipewrench", 3, 0.0, 50.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_KNIFE, "weapon_knife", 4, 0.0, 50.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_CROWBAR, "weapon_crowbar", 2, 0.0, 50.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_DISPLACER, "weapon_displacer", 5, 100.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_SPORELAUNCHER, "weapon_sporelauncher", 5, 500.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_SHOCKRIFLE, "weapon_shockrifle", 5, 50.0, 800.0, 0.0, 0.0, + 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_SNIPERRIFLE, "weapon_sniperrifle", 5, 50.0, 1500.0, 0.0, 0.0, + 100, FALSE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_HANDGRENADE, "weapon_handgrenade", 5, 250.0, 750.0, 0.0, 0.0, + 30, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_SNARK, "weapon_snark", 5, 150.0, 500.0, 0.0, 0.0, + 50, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_EGON, "weapon_egon", 5, 0.0, 9999.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_GAUSS, "weapon_gauss", 5, 0.0, 9999.0, 0.0, 9999.0, + 100, FALSE, 80, 1, 10, FALSE, FALSE, FALSE, TRUE, 0.0, 0.8}, + {GEARBOX_WEAPON_M249, "weapon_m249", 5, 0.0, 400.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_SHOTGUN, "weapon_shotgun", 5, 30.0, 150.0, 30.0, 150.0, + 100, FALSE, 70, 1, 2, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_EAGLE, "weapon_eagle", 5, 0.0, 1200.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_PYTHON, "weapon_357", 5, 30.0, 700.0, 0.0, 0.0, + 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_HORNETGUN, "weapon_hornetgun", 5, 30.0, 1000.0, 30.0, 1000.0, + 100, TRUE, 50, 1, 4, FALSE, TRUE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_MP5, "weapon_9mmAR", 5, 0.0, 250.0, 300.0, 600.0, + 100, FALSE, 90, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_CROSSBOW, "weapon_crossbow", 5, 100.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_RPG, "weapon_rpg", 5, 300.0, 9999.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {GEARBOX_WEAPON_GLOCK, "weapon_9mmhandgun", 5, 0.0, 1200.0, 0.0, 1200.0, + 100, TRUE, 70, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + /* terminator */ + {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} +}; + +bot_weapon_select_t frontline_weapon_select[] = { + {FLF_WEAPON_HEGRENADE, "weapon_hegrenade", 3, 200.0, 1000.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_FLASHBANG, "weapon_flashbang", 3, 100.0, 800.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, +// {FLF_WEAPON_KNIFE, "weapon_knife", 3, 0.0, 60.0, 0.0, 0.0, +// 100, TRUE, 100, 0, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_HK21, "weapon_hk21", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_UMP45, "weapon_ump45", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_FAMAS, "weapon_famas", 5, 0.0, 500.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_MSG90, "weapon_msg90", 5, 0.0, 2500.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_MP5A2, "weapon_mp5a2", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_AK5, "weapon_ak5", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_MP5SD, "weapon_mp5sd", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_M4, "weapon_m4", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_SPAS12, "weapon_spas12", 5, 0.0, 900.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_MAC10, "weapon_mac10", 5, 0.0, 500.0, 0.0, 0.0, + 100, TRUE, 100, 1, 0, TRUE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_BERETTA, "weapon_beretta", 5, 0.0, 1200.0, 0.0, 1200.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + {FLF_WEAPON_MK23, "weapon_mk23", 5, 0.0, 1200.0, 0.0, 1200.0, + 100, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0}, + /* terminator */ + {0, "", 0, 0.0, 0.0, 0.0, 0.0, 0, TRUE, 0, 1, 1, FALSE, FALSE, FALSE, FALSE, 0.0, 0.0} +}; + +//int iId; // the weapon ID value +//char weapon_name[64]; // name of the weapon when selecting it +//int skill_level; // bot skill must be less than or equal to this value +//float primary_min_distance; // 0 = no minimum +//float primary_max_distance; // 9999 = no maximum +//float secondary_min_distance; // 0 = no minimum +//float secondary_max_distance; // 9999 = no maximum +//int use_percent; // times out of 100 to use this weapon when available +//bool can_use_underwater; // can use this weapon underwater +//int primary_fire_percent; // times out of 100 to use primary fire +//int min_primary_ammo; // minimum ammout of primary ammo needed to fire +//int min_secondary_ammo; // minimum ammout of seconday ammo needed to fire +//bool primary_fire_hold; // hold down primary fire button to use? +//bool secondary_fire_hold; // hold down secondary fire button to use? +//bool primary_fire_charge; // charge weapon using primary fire? +//bool secondary_fire_charge; // charge weapon using secondary fire? +//float primary_charge_delay; // time to charge weapon +//float secondary_charge_delay; // time to charge weapon + +bot_weapon_select_t ns_weapon_select[] = { + {AVH_WEAPON_GRENADE_GUN, kwsGrenadeGun, 3, 120, kGGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_SONIC, kwsShotGun, 3, 0.0, kSGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_HMG, kwsHeavyMachineGun, 3, 0.0, kHMGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_MG, kwsMachineGun, 3, 0.0, kMGRange, 0.0, 0.0, 100, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_PISTOL, kwsPistol, 3, 0.0, kHGRange, 0.0, 0.0, 75, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_KNIFE, kwsKnife, 3, 0.0, kKNRange, 0.0, 0.0, 50, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + + // Base alien abilities + {AVH_WEAPON_PRIMALSCREAM, kwsPrimalScream, 3, 0.0, 300, 0.0, 0.0, 20, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_SWIPE, kwsSwipe, 3, 0.0, kSwipeRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_SPORES, kwsSporeGun, 3, 0.0, kSporeRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_SPIT, kwsSpitGun, 3, 0.0, kSpitGRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_CLAWS, kwsClaws, 3, 0.0, kClawsRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_BITE, kwsBiteGun, 3, 0.0, 60, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_ABILITY_LEAP, kwsLeap, 3, 0.0, 600, 0.0, 0.0, 50, FALSE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, + {AVH_WEAPON_SPIKE, kwsSpikeGun, 3, 0.0, kSpikeRange, 0.0, 0.0, 75, TRUE, 100, 1, 0, FALSE, FALSE, FALSE, FALSE, 0.0f, 0.0f}, +}; + +// weapon firing delay based on skill (min and max delay for each weapon) +// THESE MUST MATCH THE SAME ORDER AS THE WEAPON SELECT ARRAY!!! + +bot_fire_delay_t valve_fire_delay[] = { + {VALVE_WEAPON_CROWBAR, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_HANDGRENADE, + 0.1, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_SNARK, + 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_EGON, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_GAUSS, + 0.2, {0.0, 0.2, 0.3, 0.5, 1.0}, {0.1, 0.3, 0.5, 0.8, 1.2}, + 1.0, {0.2, 0.3, 0.5, 0.8, 1.2}, {0.5, 0.7, 1.0, 1.5, 2.0}}, + {VALVE_WEAPON_SHOTGUN, + 0.75, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, + 1.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}}, + {VALVE_WEAPON_PYTHON, + 0.75, {0.0, 0.2, 0.4, 1.0, 1.5}, {0.25, 0.5, 0.8, 1.3, 2.2}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_HORNETGUN, + 0.25, {0.0, 0.25, 0.4, 0.6, 1.0}, {0.1, 0.4, 0.7, 1.0, 1.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_MP5, + 0.1, {0.0, 0.1, 0.25, 0.4, 0.5}, {0.1, 0.3, 0.45, 0.65, 0.8}, + 1.0, {0.0, 0.4, 0.7, 1.0, 1.4}, {0.3, 0.7, 1.0, 1.6, 2.0}}, + {VALVE_WEAPON_CROSSBOW, + 0.75, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_RPG, + 1.5, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {VALVE_WEAPON_GLOCK, + 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, + /* terminator */ + {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} +}; + +bot_fire_delay_t tfc_fire_delay[] = { + {TF_WEAPON_AXE, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_KNIFE, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_SPANNER, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_MEDIKIT, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_SNIPERRIFLE, + 1.0, {0.0, 0.4, 0.7, 1.0, 1.4}, {0.3, 0.7, 1.0, 1.6, 2.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_FLAMETHROWER, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_AC, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_GL, + 0.6, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_RPG, + 0.5, {0.0, 0.1, 0.3, 0.6, 1.0}, {0.1, 0.2, 0.7, 1.0, 2.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_IC, + 2.0, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_TRANQ, + 1.5, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_RAILGUN, + 0.4, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_SUPERNAILGUN, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_SUPERSHOTGUN, + 0.6, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_AUTORIFLE, + 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_SHOTGUN, + 0.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {TF_WEAPON_NAILGUN, + 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + /* terminator */ + {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} +}; + +bot_fire_delay_t cs_fire_delay[] = { + {CS_WEAPON_KNIFE, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {CS_WEAPON_USP, + 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, + {CS_WEAPON_GLOCK18, + 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, + /* terminator */ + {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} +}; + +bot_fire_delay_t gearbox_fire_delay[] = { + {GEARBOX_WEAPON_PIPEWRENCH, + 0.5, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_KNIFE, + 0.4, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_CROWBAR, + 0.3, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_DISPLACER, + 5.0, {0.0, 0.5, 0.8, 1.6, 2.5}, {0.3, 0.8, 1.4, 2.2, 3.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_SPORELAUNCHER, + 0.5, {0.0, 0.2, 0.3, 0.4, 0.6}, {0.1, 0.3, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_SHOCKRIFLE, + 0.1, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_SNIPERRIFLE, + 1.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_HANDGRENADE, + 0.1, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_SNARK, + 0.1, {0.0, 0.1, 0.2, 0.4, 0.6}, {0.1, 0.2, 0.5, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_EGON, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_GAUSS, + 0.2, {0.0, 0.2, 0.3, 0.5, 1.0}, {0.1, 0.3, 0.5, 0.8, 1.2}, + 1.0, {0.2, 0.3, 0.5, 0.8, 1.2}, {0.5, 0.7, 1.0, 1.5, 2.0}}, + {GEARBOX_WEAPON_M249, + 0.1, {0.0, 0.1, 0.25, 0.4, 0.5}, {0.1, 0.3, 0.45, 0.65, 0.8}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_SHOTGUN, + 0.75, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}, + 1.5, {0.0, 0.2, 0.4, 0.6, 0.8}, {0.25, 0.5, 0.8, 1.2, 2.0}}, + {GEARBOX_WEAPON_EAGLE, + 0.25, {0.0, 0.1, 0.2, 0.3, 0.5}, {0.1, 0.25, 0.4, 0.7, 1.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_PYTHON, + 0.75, {0.0, 0.2, 0.4, 1.0, 1.5}, {0.25, 0.5, 0.8, 1.3, 2.2}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_HORNETGUN, + 0.25, {0.0, 0.25, 0.4, 0.6, 1.0}, {0.1, 0.4, 0.7, 1.0, 1.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_MP5, + 0.1, {0.0, 0.1, 0.25, 0.4, 0.5}, {0.1, 0.3, 0.45, 0.65, 0.8}, + 1.0, {0.0, 0.4, 0.7, 1.0, 1.4}, {0.3, 0.7, 1.0, 1.6, 2.0}}, + {GEARBOX_WEAPON_CROSSBOW, + 0.75, {0.0, 0.2, 0.5, 0.8, 1.0}, {0.25, 0.4, 0.7, 1.0, 1.3}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_RPG, + 1.5, {1.0, 2.0, 3.0, 4.0, 5.0}, {3.0, 4.0, 5.0, 6.0, 7.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {GEARBOX_WEAPON_GLOCK, + 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, + /* terminator */ + {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} +}; + +bot_fire_delay_t frontline_fire_delay[] = { + {FLF_WEAPON_HEGRENADE, + 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_FLASHBANG, + 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, +// {FLF_WEAPON_KNIFE, +// 0.3, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, +// 0.2, {0.0, 0.0, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.2, 0.2, 0.4}}, + {FLF_WEAPON_HK21, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_UMP45, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_FAMAS, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_MSG90, + 1.2, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_MP5A2, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_AK5, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_MP5SD, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_M4, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_SPAS12, + 0.9, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_MAC10, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_BERETTA, + 0.4, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {FLF_WEAPON_MK23, + 0.4, {0.0, 0.1, 0.2, 0.3, 0.4}, {0.1, 0.2, 0.3, 0.4, 0.5}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + /* terminator */ + {0, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, + 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} +}; +bot_fire_delay_t ns_fire_delay[] = { + {AVH_WEAPON_GRENADE_GUN, 0.3f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.2, 0.3, 0.4, 0.5, 1.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_SONIC, 0.0f, {0.0, 0.0, 0.0, 0.1, 0.3}, {0.0, 0.0, 0.0, 0.2, 0.6}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_HMG, 0.0f, {0.0, 0.0, 0.0, 0.1, 0.3}, {0.0, 0.0, 0.0, 0.2, 0.6}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_MG, 0.0f, {0.0, 0.0, 0.0, 0.1, 0.3}, {0.0, 0.0, 0.0, 0.2, 0.6}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_PISTOL, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.1, 0.15, 0.2, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_KNIFE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + + {AVH_WEAPON_PRIMALSCREAM, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_SWIPE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_SPORES, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_SPIT, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_CLAWS, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.4, 0.5}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_BITE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_ABILITY_LEAP, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}}, + {AVH_WEAPON_SPIKE, 0.0f, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.0, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}} +}; + +void BotCheckTeamplay(void) +{ + // is this TFC or Counter-Strike or OpFor teamplay or FrontLineForce? + if ((mod_id == TFC_DLL) || (mod_id == CSTRIKE_DLL) || + ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) || + (mod_id == FRONTLINE_DLL) || + (mod_id == AVH_DLL) ) + is_team_play = 1.0; + else + is_team_play = CVAR_GET_FLOAT("mp_teamplay"); // teamplay enabled? + + checked_teamplay = TRUE; +} + + +edict_t *BotFindEnemy( bot_t *pBot ) +{ + Vector vecEnd; + static bool flag=TRUE; + edict_t *pent = NULL; + edict_t *pNewEnemy; + float nearestdistance; + int i; + + edict_t *pEdict = pBot->pEdict; + + if(pBot->mBotPlayMode != PLAYMODE_PLAYING) + { + pBot->pBotEnemy = NULL; + } + + if (pBot->pBotEnemy != NULL) // does the bot already have an enemy? + { + vecEnd = pBot->pBotEnemy->v.origin + pBot->pBotEnemy->v.view_ofs; + + // if the enemy is dead? + if (!IsAlive(pBot->pBotEnemy)) // is the enemy dead?, assume bot killed it + { + // the enemy is dead, jump for joy about 10% of the time + if (RANDOM_LONG(1, 100) <= 10) + pEdict->v.button |= IN_JUMP; + + // Taunt sometimes after a kill + if(RANDOM_LONG(1, 5) == 1) + { + pBot->mTimeOfNextTaunt = gpGlobals->time + RANDOM_FLOAT(.3f, 4.0f); + } + + // don't have an enemy anymore so null out the pointer... + pBot->pBotEnemy = NULL; + } + else if (FInViewCone( &vecEnd, pEdict ) && + FVisible( vecEnd, pEdict )) + { + if ((mod_id == TFC_DLL) && + (pEdict->v.playerclass == TFC_CLASS_MEDIC)) + { + if (pBot->pBotEnemy->v.health >= pBot->pBotEnemy->v.max_health) + { + pBot->pBotEnemy = NULL; // player is healed, null out pointer + } + } + else + { + // if enemy is still visible and in field of view, keep it + + // face the enemy + Vector v_enemy = pBot->pBotEnemy->v.origin - pEdict->v.origin; + Vector bot_angles = UTIL_VecToAngles( v_enemy ); + + pEdict->v.ideal_yaw = bot_angles.y; + + BotFixIdealYaw(pEdict); + + // keep track of when we last saw an enemy + pBot->f_bot_see_enemy_time = gpGlobals->time; + + return (pBot->pBotEnemy); + } + } + } + + pent = NULL; + pNewEnemy = NULL; + nearestdistance = 1000; + + if (mod_id == TFC_DLL) + { + if (pEdict->v.playerclass == TFC_CLASS_MEDIC) + { + // search the world for players... + for (i = 1; i <= gpGlobals->maxClients; i++) + { + edict_t *pPlayer = INDEXENT(i); + + // skip invalid players and skip self (i.e. this bot) + if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) + { + // skip this player if not alive (i.e. dead or dying) + if (!IsAlive(pPlayer)) + continue; + + if ((b_observer_mode) && !(pPlayer->v.flags & FL_FAKECLIENT)) + continue; + + int player_team = UTIL_GetTeam(pPlayer); + int bot_team = UTIL_GetTeam(pEdict); + + // don't target your enemies... + if ((bot_team != player_team) && + !(team_allies[bot_team] & (1<v.health / pPlayer->v.max_health) > 0.50) + continue; // health greater than 50% so ignore + + vecEnd = pPlayer->v.origin + pPlayer->v.view_ofs; + + // see if bot can see the player... + if (FInViewCone( &vecEnd, pEdict ) && + FVisible( vecEnd, pEdict )) + { + float distance = (pPlayer->v.origin - pEdict->v.origin).Length(); + + if (distance < nearestdistance) + { + nearestdistance = distance; + pNewEnemy = pPlayer; + + pBot->pBotUser = NULL; // don't follow user when enemy found + } + } + } + } + } + + if (pNewEnemy == NULL) + { + while ((pent = UTIL_FindEntityByClassname( pent, "building_sentrygun" )) != NULL) + { + int sentry_team = -1; + int bot_team = UTIL_GetTeam(pEdict); + + if (pent->v.colormap == 0xA096) + sentry_team = 0; // blue team's sentry + else if (pent->v.colormap == 0x04FA) + sentry_team = 1; // red team's sentry + else if (pent->v.colormap == 0x372D) + sentry_team = 2; // yellow team's sentry + else if (pent->v.colormap == 0x6E64) + sentry_team = 3; // green team's sentry + + // don't target your own team's sentry guns... + if (bot_team == sentry_team) + continue; + + // don't target your allie's sentry guns either... + if (team_allies[bot_team] & (1<v.origin + pent->v.view_ofs; + + // is this sentry gun visible? + if (FInViewCone( &vecEnd, pEdict ) && + FVisible( vecEnd, pEdict )) + { + float distance = (pent->v.origin - pEdict->v.origin).Length(); + + // is this the closest sentry gun? + if (distance < nearestdistance) + { + nearestdistance = distance; + pNewEnemy = pent; + + pBot->pBotUser = NULL; // don't follow user when enemy found + } + } + } + } + } + + if (pNewEnemy == NULL) + { + nearestdistance = 2500; + + // search the world for players...(and enemies) + //for (i = 1; i <= gpGlobals->maxClients; i++) + for (i = 1; i <= gpGlobals->maxEntities; i++) + { + edict_t *pEntity = INDEXENT(i); + + // skip invalid players and skip self (i.e. this bot) + if ((pEntity) && (!pEntity->free) && (pEntity != pEdict) && (FBitSet(pEntity->v.flags, FL_MONSTER) || FBitSet(pEntity->v.flags, FL_CLIENT))) + { + // Skip webs? + const char* theClassName = STRING(pEntity->v.classname); + + // Skip cloaked players +// if(pEntity->v.iuser4 & MASK_ALIEN_CLOAKED) +// continue; + + // skip this player if not alive (i.e. dead or dying) + if (!IsAlive(pEntity)) + continue; + + if ((b_observer_mode) && !(pEntity->v.flags & FL_FAKECLIENT)) + continue; + + if (!checked_teamplay) // check for team play... + BotCheckTeamplay(); + + // is team play enabled? + if (is_team_play > 0.0) + { + int player_team = UTIL_GetTeam(pEntity); + int bot_team = UTIL_GetTeam(pEdict); + + // don't target your teammates... + if (bot_team == player_team) + continue; + + if (mod_id == TFC_DLL) + { + // don't target your allies either... + if (team_allies[bot_team] & (1<v.origin + pEntity->v.view_ofs; + + float theDistance = (pEdict->v.origin - pEntity->v.origin).Length(); + + // see if bot can see the player... + if ((FInViewCone( &vecEnd, pEdict ) && + FVisible( vecEnd, pEdict )) || (theDistance < 32)) + { + float distance = (pEntity->v.origin - pEdict->v.origin).Length(); + if (distance < nearestdistance) + { + nearestdistance = distance; + pNewEnemy = pEntity; + + pBot->pBotUser = NULL; // don't follow user when enemy found + } + } + } + } + } + + if (pNewEnemy) + { + // face the enemy + Vector v_enemy = pNewEnemy->v.origin - pEdict->v.origin; + Vector bot_angles = UTIL_VecToAngles( v_enemy ); + + pEdict->v.ideal_yaw = bot_angles.y; + + BotFixIdealYaw(pEdict); + + // keep track of when we last saw an enemy + pBot->f_bot_see_enemy_time = gpGlobals->time; + } + + // has the bot NOT seen an ememy for at least 5 seconds (time to reload)? + if ((pBot->f_bot_see_enemy_time > 0) && + ((pBot->f_bot_see_enemy_time + 5.0) <= gpGlobals->time)) + { + pBot->f_bot_see_enemy_time = -1; // so we won't keep reloading + + if ((mod_id == VALVE_DLL) || (mod_id == GEARBOX_DLL) || (mod_id == AVH_DLL)) + { + pEdict->v.button |= IN_RELOAD; // press reload button + } + } + + return (pNewEnemy); +} + + +Vector BotBodyTarget( edict_t *pBotEnemy, bot_t *pBot ) +{ + Vector target; + float f_distance; + float f_scale; + int d_x = 0; + int d_y = 0; + int d_z = 0; + + edict_t *pEdict = pBot->pEdict; + + f_distance = (pBotEnemy->v.origin - pEdict->v.origin).Length(); + + if (f_distance > 1000) + f_scale = 1.0; + else if (f_distance > 100) + f_scale = f_distance / 1000.0; + else + f_scale = 0.1; + + switch (pBot->bot_skill) + { + case 0: + // VERY GOOD, same as from CBasePlayer::BodyTarget (in player.h) + target = pBotEnemy->v.origin + pBotEnemy->v.view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); + d_x = 0; // no offset + d_y = 0; + d_z = 0; + break; + case 1: + // GOOD, offset a little for x, y, and z + target = pBotEnemy->v.origin + pBotEnemy->v.view_ofs; // aim for the head (if you can find it) + d_x = RANDOM_FLOAT(-5, 5) * f_scale; + d_y = RANDOM_FLOAT(-5, 5) * f_scale; + d_z = RANDOM_FLOAT(-10, 10) * f_scale; + break; + case 2: + // FAIR, offset somewhat for x, y, and z + target = pBotEnemy->v.origin; // aim for the body + d_x = RANDOM_FLOAT(-10, 10) * f_scale; + d_y = RANDOM_FLOAT(-10, 10) * f_scale; + d_z = RANDOM_FLOAT(-18, 18) * f_scale; + break; + case 3: + // POOR, offset for x, y, and z + target = pBotEnemy->v.origin; // aim for the body + d_x = RANDOM_FLOAT(-20, 20) * f_scale; + d_y = RANDOM_FLOAT(-20, 20) * f_scale; + d_z = RANDOM_FLOAT(-32, 32) * f_scale; + break; + case 4: + // BAD, offset lots for x, y, and z + target = pBotEnemy->v.origin; // aim for the body + d_x = RANDOM_FLOAT(-35, 35) * f_scale; + d_y = RANDOM_FLOAT(-35, 35) * f_scale; + d_z = RANDOM_FLOAT(-50, 50) * f_scale; + break; + } + + target = target + Vector(d_x, d_y, d_z); + + return target; +} + + +// specifing a weapon_choice allows you to choose the weapon the bot will +// use (assuming enough ammo exists for that weapon) +// BotFireWeapon will return TRUE if weapon was fired, FALSE otherwise + +bool BotFireWeapon( Vector v_enemy, bot_t *pBot, int weapon_choice) +{ + bot_weapon_select_t *pSelect = NULL; + bot_fire_delay_t *pDelay = NULL; + int select_index; + int iId; + bool use_primary; + bool use_secondary; + int use_percent; + int primary_percent; + + edict_t *pEdict = pBot->pEdict; + + float distance = v_enemy.Length(); // how far away is the enemy? + + if (mod_id == VALVE_DLL) + { + pSelect = &valve_weapon_select[0]; + pDelay = &valve_fire_delay[0]; + } + else if (mod_id == TFC_DLL) + { + pSelect = &tfc_weapon_select[0]; + pDelay = &tfc_fire_delay[0]; + } + else if (mod_id == CSTRIKE_DLL) + { + pSelect = &cs_weapon_select[0]; + pDelay = &cs_fire_delay[0]; + } + else if (mod_id == GEARBOX_DLL) + { + pSelect = &gearbox_weapon_select[0]; + pDelay = &gearbox_fire_delay[0]; + } + else if (mod_id == FRONTLINE_DLL) + { + pSelect = &frontline_weapon_select[0]; + pDelay = &frontline_fire_delay[0]; + } + else if (mod_id == AVH_DLL) + { + pSelect = &ns_weapon_select[0]; + pDelay = &ns_fire_delay[0]; + } + + if (pSelect) + { + // are we charging the primary fire? + if (pBot->f_primary_charging > 0) + { + iId = pBot->charging_weapon_id; + + if (mod_id == TFC_DLL) + { + if (iId == TF_WEAPON_SNIPERRIFLE) + { + pBot->f_move_speed = 0; // don't move while using sniper rifle + } + } + + // is it time to fire the charged weapon? + if (pBot->f_primary_charging <= gpGlobals->time) + { + // we DON'T set pEdict->v.button here to release the + // fire button which will fire the charged weapon + + pBot->f_primary_charging = -1; // -1 means not charging + + // find the correct fire delay for this weapon + select_index = 0; + + while ((pSelect[select_index].iId) && + (pSelect[select_index].iId != iId)) + select_index++; + + // set next time to shoot + int skill = pBot->bot_skill; + float base_delay, min_delay, max_delay; + + base_delay = pDelay[select_index].primary_base_delay; + min_delay = pDelay[select_index].primary_min_delay[skill]; + max_delay = pDelay[select_index].primary_max_delay[skill]; + + pBot->f_shoot_time = gpGlobals->time + base_delay + + RANDOM_FLOAT(min_delay, max_delay); + + return TRUE; + } + else + { + pEdict->v.button |= IN_ATTACK; // charge the weapon + pBot->f_shoot_time = gpGlobals->time; // keep charging + + return TRUE; + } + } + + // are we charging the secondary fire? + if (pBot->f_secondary_charging > 0) + { + iId = pBot->charging_weapon_id; + + // is it time to fire the charged weapon? + if (pBot->f_secondary_charging <= gpGlobals->time) + { + // we DON'T set pEdict->v.button here to release the + // fire button which will fire the charged weapon + + pBot->f_secondary_charging = -1; // -1 means not charging + + // find the correct fire delay for this weapon + select_index = 0; + + while ((pSelect[select_index].iId) && + (pSelect[select_index].iId != iId)) + select_index++; + + // set next time to shoot + int skill = pBot->bot_skill; + float base_delay, min_delay, max_delay; + + base_delay = pDelay[select_index].secondary_base_delay; + min_delay = pDelay[select_index].secondary_min_delay[skill]; + max_delay = pDelay[select_index].secondary_max_delay[skill]; + + pBot->f_shoot_time = gpGlobals->time + base_delay + + RANDOM_FLOAT(min_delay, max_delay); + + return TRUE; + } + else + { + pEdict->v.button |= IN_ATTACK2; // charge the weapon + pBot->f_shoot_time = gpGlobals->time; // keep charging + + return TRUE; + } + } + + select_index = 0; + + // loop through all the weapons until terminator is found... + while (pSelect[select_index].iId) + { + // was a weapon choice specified? (and if so do they NOT match?) + if ((weapon_choice != 0) && + (weapon_choice != pSelect[select_index].iId)) + { + select_index++; // skip to next weapon + continue; + } + + // is the bot NOT carrying this weapon? + if (!(pBot->bot_weapons & (1<bot_skill+1) > pSelect[select_index].skill_level) + { + select_index++; // skip to next weapon + continue; + } + + // is the bot underwater and does this weapon NOT work under water? + if ((pEdict->v.waterlevel == 3) && + !(pSelect[select_index].can_use_underwater)) + { + select_index++; // skip to next weapon + continue; + } + + use_percent = RANDOM_LONG(1, 100); + + // is use percent greater than weapon use percent? + if (use_percent > pSelect[select_index].use_percent) + { + select_index++; // skip to next weapon + continue; + } + + iId = pSelect[select_index].iId; + use_primary = FALSE; + use_secondary = FALSE; + primary_percent = RANDOM_LONG(1, 100); + + // is primary percent less than weapon primary percent AND + // no ammo required for this weapon OR + // enough ammo available to fire AND + // the bot is far enough away to use primary fire AND + // the bot is close enough to the enemy to use primary fire + + if ((primary_percent <= pSelect[select_index].primary_fire_percent) && + ((weapon_defs[iId].iAmmo1 == -1) || + (pBot->m_rgAmmo[weapon_defs[iId].iAmmo1] >= + pSelect[select_index].min_primary_ammo)) && + (distance >= pSelect[select_index].primary_min_distance) && + (distance <= pSelect[select_index].primary_max_distance)) + { + use_primary = TRUE; + } + + // otherwise see if there is enough secondary ammo AND + // the bot is far enough away to use secondary fire AND + // the bot is close enough to the enemy to use secondary fire + + else if (((weapon_defs[iId].iAmmo2 == -1) || + (pBot->m_rgAmmo[weapon_defs[iId].iAmmo2] >= + pSelect[select_index].min_secondary_ammo)) && + (distance >= pSelect[select_index].secondary_min_distance) && + (distance <= pSelect[select_index].secondary_max_distance)) + { + use_secondary = TRUE; + } + + // see if there wasn't enough ammo to fire the weapon... + if ((use_primary == FALSE) && (use_secondary == FALSE)) + { + select_index++; // skip to next weapon + continue; + } + + // select this weapon if it isn't already selected + if (pBot->current_weapon.iId != iId) + UTIL_SelectItem(pEdict, pSelect[select_index].weapon_name); + + if (pDelay[select_index].iId != iId) + { + char msg[80]; + sprintf(msg, "fire_delay mismatch for weapon id=%d\n",iId); + ALERT(at_console, msg); + + return FALSE; + } + + if (mod_id == TFC_DLL) + { + if (iId == TF_WEAPON_SNIPERRIFLE) + { + pBot->f_move_speed = 0; // don't move while using sniper rifle + + if (pEdict->v.velocity.Length() > 50) + { + return FALSE; // don't press attack key until velocity is < 50 + } + } + + if (pEdict->v.playerclass == TFC_CLASS_MEDIC) + { + int player_team = UTIL_GetTeam(pBot->pBotEnemy); + int bot_team = UTIL_GetTeam(pEdict); + + // only heal your teammates or allies... + if (((bot_team == player_team) || + (team_allies[bot_team] & (1<v.button |= IN_ATTACK; // use primary attack + + if (pSelect[select_index].primary_fire_charge) + { + pBot->charging_weapon_id = iId; + + // release primary fire after the appropriate delay... + pBot->f_primary_charging = gpGlobals->time + + pSelect[select_index].primary_charge_delay; + + pBot->f_shoot_time = gpGlobals->time; // keep charging + } + else + { + // set next time to shoot + if (pSelect[select_index].primary_fire_hold) + pBot->f_shoot_time = gpGlobals->time; // don't let button up + else + { + int skill = pBot->bot_skill; + float base_delay, min_delay, max_delay; + + base_delay = pDelay[select_index].primary_base_delay; + min_delay = pDelay[select_index].primary_min_delay[skill]; + max_delay = pDelay[select_index].primary_max_delay[skill]; + + pBot->f_shoot_time = gpGlobals->time + base_delay + + RANDOM_FLOAT(min_delay, max_delay); + } + } + } + else // MUST be use_secondary... + { + pEdict->v.button |= IN_ATTACK2; // use secondary attack + + if (pSelect[select_index].secondary_fire_charge) + { + pBot->charging_weapon_id = iId; + + // release secondary fire after the appropriate delay... + pBot->f_secondary_charging = gpGlobals->time + + pSelect[select_index].secondary_charge_delay; + + pBot->f_shoot_time = gpGlobals->time; // keep charging + } + else + { + // set next time to shoot + if (pSelect[select_index].secondary_fire_hold) + pBot->f_shoot_time = gpGlobals->time; // don't let button up + else + { + int skill = pBot->bot_skill; + float base_delay, min_delay, max_delay; + + base_delay = pDelay[select_index].secondary_base_delay; + min_delay = pDelay[select_index].secondary_min_delay[skill]; + max_delay = pDelay[select_index].secondary_max_delay[skill]; + + pBot->f_shoot_time = gpGlobals->time + base_delay + + RANDOM_FLOAT(min_delay, max_delay); + } + } + } + + return TRUE; // weapon was fired + } + } + + // didn't have any available weapons or ammo, return FALSE + return FALSE; +} + + +void BotShootAtEnemy( bot_t *pBot ) +{ + float f_distance; + + edict_t *pEdict = pBot->pEdict; + + // aim for the head and/or body + Vector v_enemy = BotBodyTarget( pBot->pBotEnemy, pBot ) - GetGunPosition(pEdict); + + pEdict->v.v_angle = UTIL_VecToAngles( v_enemy ); + + if (pEdict->v.v_angle.y > 180) + pEdict->v.v_angle.y -=360; + + // Paulo-La-Frite - START bot aiming bug fix + if (pEdict->v.v_angle.x > 180) + pEdict->v.v_angle.x -=360; + + // set the body angles to point the gun correctly + pEdict->v.angles.x = pEdict->v.v_angle.x / 3; + pEdict->v.angles.y = pEdict->v.v_angle.y; + pEdict->v.angles.z = 0; + + // adjust the view angle pitch to aim correctly (MUST be after body v.angles stuff) + pEdict->v.v_angle.x = -pEdict->v.v_angle.x; + // Paulo-La-Frite - END + + float x = pEdict->v.v_angle.y; + if (x > 180) x -= 360; + if (abs(pEdict->v.ideal_yaw - x) > 2.0) + fp = NULL; + + pEdict->v.ideal_yaw = pEdict->v.v_angle.y; + + BotFixIdealYaw(pEdict); + + + v_enemy.z = 0; // ignore z component (up & down) + + f_distance = v_enemy.Length(); // how far away is the enemy scum? + + if (f_distance > 200) // run if distance to enemy is far + pBot->f_move_speed = pBot->f_max_speed; + else if (f_distance > 20) // walk if distance is closer + pBot->f_move_speed = pBot->f_max_speed / 2; + else // don't move if close enough + pBot->f_move_speed = 0.0; + + + // is it time to shoot yet? + if (pBot->f_shoot_time <= gpGlobals->time) + { + // select the best weapon to use at this distance and fire... + BotFireWeapon(v_enemy, pBot, 0); + } +} + + +bool BotShootTripmine( bot_t *pBot ) +{ + edict_t *pEdict = pBot->pEdict; + + if (pBot->b_shoot_tripmine != TRUE) + return FALSE; + + // aim at the tripmine and fire the glock... + + Vector v_enemy = pBot->v_tripmine - GetGunPosition( pEdict ); + + pEdict->v.v_angle = UTIL_VecToAngles( v_enemy ); + + if (pEdict->v.v_angle.y > 180) + pEdict->v.v_angle.y -=360; + + // Paulo-La-Frite - START bot aiming bug fix + if (pEdict->v.v_angle.x > 180) + pEdict->v.v_angle.x -=360; + + // set the body angles to point the gun correctly + pEdict->v.angles.x = pEdict->v.v_angle.x / 3; + pEdict->v.angles.y = pEdict->v.v_angle.y; + pEdict->v.angles.z = 0; + + // adjust the view angle pitch to aim correctly (MUST be after body v.angles stuff) + pEdict->v.v_angle.x = -pEdict->v.v_angle.x; + // Paulo-La-Frite - END + + pEdict->v.ideal_yaw = pEdict->v.v_angle.y; + + BotFixIdealYaw(pEdict); + + return (BotFireWeapon( v_enemy, pBot, VALVE_WEAPON_GLOCK )); +} + diff --git a/main/source/HPB_bot/dlls/bot_func.h b/main/source/HPB_bot/dlls/bot_func.h index c7427485..e03e1fb3 100644 --- a/main/source/HPB_bot/dlls/bot_func.h +++ b/main/source/HPB_bot/dlls/bot_func.h @@ -1,52 +1,52 @@ -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_func.h -// - -#ifndef BOT_FUNC_H -#define BOT_FUNC_H - - -//prototypes of bot functions... - -void BotSpawnInit( bot_t *pBot ); -void BotCreate( edict_t *pPlayer, const char *arg1, const char *arg2, - const char *arg3, const char *arg4 ); -void BotStartGame( bot_t *pBot ); -int BotInFieldOfView( bot_t *pBot, Vector dest ); -bool BotEntityIsVisible( bot_t *pBot, Vector dest ); -void BotFindItem( bot_t *pBot ); -void BotThink( bot_t *pBot ); - - -void BotFixIdealPitch( edict_t *pEdict ); -float BotChangePitch( bot_t *pBot, float speed ); -void BotFixIdealYaw( edict_t *pEdict ); -float BotChangeYaw( bot_t *pBot, float speed ); -bool BotFindWaypoint( bot_t *pBot ); -bool BotHeadTowardWaypoint( bot_t *pBot ); -void BotOnLadder( bot_t *pBot, float moved_distance ); -void BotUnderWater( bot_t *pBot ); -void BotUseLift( bot_t *pBot, float moved_distance ); -bool BotStuckInCorner( bot_t *pBot ); -void BotTurnAtWall( bot_t *pBot, TraceResult *tr ); -bool BotCantMoveForward( bot_t *pBot, TraceResult *tr ); -bool BotCanJumpUp( bot_t *pBot ); -bool BotCanDuckUnder( bot_t *pBot ); -void BotRandomTurn( bot_t *pBot ); -bool BotFollowUser( bot_t *pBot ); -bool BotCheckWallOnLeft( bot_t *pBot ); -bool BotCheckWallOnRight( bot_t *pBot ); - -edict_t *BotFindEnemy( bot_t *pBot ); -Vector BotBodyTarget( edict_t *pBotEnemy, bot_t *pBot ); -bool BotFireWeapon( Vector v_enemy, bot_t *pBot, int weapon_choice); -void BotShootAtEnemy( bot_t *pBot ); -bool BotShootTripmine( bot_t *pBot ); - - -#endif // BOT_FUNC_H - +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_func.h +// + +#ifndef BOT_FUNC_H +#define BOT_FUNC_H + + +//prototypes of bot functions... + +void BotSpawnInit( bot_t *pBot ); +void BotCreate( edict_t *pPlayer, const char *arg1, const char *arg2, + const char *arg3, const char *arg4 ); +void BotStartGame( bot_t *pBot ); +int BotInFieldOfView( bot_t *pBot, Vector dest ); +bool BotEntityIsVisible( bot_t *pBot, Vector dest ); +void BotFindItem( bot_t *pBot ); +void BotThink( bot_t *pBot ); + + +void BotFixIdealPitch( edict_t *pEdict ); +float BotChangePitch( bot_t *pBot, float speed ); +void BotFixIdealYaw( edict_t *pEdict ); +float BotChangeYaw( bot_t *pBot, float speed ); +bool BotFindWaypoint( bot_t *pBot ); +bool BotHeadTowardWaypoint( bot_t *pBot ); +void BotOnLadder( bot_t *pBot, float moved_distance ); +void BotUnderWater( bot_t *pBot ); +void BotUseLift( bot_t *pBot, float moved_distance ); +bool BotStuckInCorner( bot_t *pBot ); +void BotTurnAtWall( bot_t *pBot, TraceResult *tr ); +bool BotCantMoveForward( bot_t *pBot, TraceResult *tr ); +bool BotCanJumpUp( bot_t *pBot ); +bool BotCanDuckUnder( bot_t *pBot ); +void BotRandomTurn( bot_t *pBot ); +bool BotFollowUser( bot_t *pBot ); +bool BotCheckWallOnLeft( bot_t *pBot ); +bool BotCheckWallOnRight( bot_t *pBot ); + +edict_t *BotFindEnemy( bot_t *pBot ); +Vector BotBodyTarget( edict_t *pBotEnemy, bot_t *pBot ); +bool BotFireWeapon( Vector v_enemy, bot_t *pBot, int weapon_choice); +void BotShootAtEnemy( bot_t *pBot ); +bool BotShootTripmine( bot_t *pBot ); + + +#endif // BOT_FUNC_H + diff --git a/main/source/HPB_bot/dlls/bot_navigate.cpp b/main/source/HPB_bot/dlls/bot_navigate.cpp index 5af51f66..f2ed3d48 100644 --- a/main/source/HPB_bot/dlls/bot_navigate.cpp +++ b/main/source/HPB_bot/dlls/bot_navigate.cpp @@ -1,1094 +1,1094 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_navigate.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" -#include "bot_func.h" -#include "waypoint.h" - - -extern int mod_id; -extern WAYPOINT waypoints[MAX_WAYPOINTS]; -extern int num_waypoints; // number of waypoints currently in use -extern int team_allies[4]; -extern edict_t *pent_info_ctfdetect; -extern float is_team_play; -extern bool checked_teamplay; -extern FLAG_S flags[MAX_FLAGS]; -extern int num_flags; - -extern int flf_bug_fix; - -static FILE *fp; - - - -void BotFixIdealPitch(edict_t *pEdict) -{ - // check for wrap around of angle... - if (pEdict->v.idealpitch > 180) - pEdict->v.idealpitch -= 360; - - if (pEdict->v.idealpitch < -180) - pEdict->v.idealpitch += 360; -} - - -float BotChangePitch( bot_t *pBot, float speed ) -{ - edict_t *pEdict = pBot->pEdict; - float ideal; - float current; - float current_180; // current +/- 180 degrees - float diff; - - // turn from the current v_angle pitch to the idealpitch by selecting - // the quickest way to turn to face that direction - - current = pEdict->v.v_angle.x; - - ideal = pEdict->v.idealpitch; - - // find the difference in the current and ideal angle - diff = abs(current - ideal); - - // check if the bot is already facing the idealpitch direction... - if (diff <= 1) - return diff; // return number of degrees turned - - // check if difference is less than the max degrees per turn - if (diff < speed) - speed = diff; // just need to turn a little bit (less than max) - - // here we have four cases, both angle positive, one positive and - // the other negative, one negative and the other positive, or - // both negative. handle each case separately... - - if ((current >= 0) && (ideal >= 0)) // both positive - { - if (current > ideal) - current -= speed; - else - current += speed; - } - else if ((current >= 0) && (ideal < 0)) - { - current_180 = current - 180; - - if (current_180 > ideal) - current += speed; - else - current -= speed; - } - else if ((current < 0) && (ideal >= 0)) - { - current_180 = current + 180; - if (current_180 > ideal) - current += speed; - else - current -= speed; - } - else // (current < 0) && (ideal < 0) both negative - { - if (current > ideal) - current -= speed; - else - current += speed; - } - - // check for wrap around of angle... - if (current > 180) - current -= 360; - if (current < -180) - current += 360; - - pEdict->v.v_angle.x = current; - - return speed; // return number of degrees turned -} - - -void BotFixIdealYaw(edict_t *pEdict) -{ - // check for wrap around of angle... - if (pEdict->v.ideal_yaw > 180) - pEdict->v.ideal_yaw -= 360; - - if (pEdict->v.ideal_yaw < -180) - pEdict->v.ideal_yaw += 360; -} - - -float BotChangeYaw( bot_t *pBot, float speed ) -{ - edict_t *pEdict = pBot->pEdict; - float ideal; - float current; - float current_180; // current +/- 180 degrees - float diff; - - // turn from the current v_angle yaw to the ideal_yaw by selecting - // the quickest way to turn to face that direction - - current = pEdict->v.v_angle.y; - - ideal = pEdict->v.ideal_yaw; - - // find the difference in the current and ideal angle - diff = abs(current - ideal); - - // check if the bot is already facing the ideal_yaw direction... - if (diff <= 1) - return diff; // return number of degrees turned - - // check if difference is less than the max degrees per turn - if (diff < speed) - speed = diff; // just need to turn a little bit (less than max) - - // here we have four cases, both angle positive, one positive and - // the other negative, one negative and the other positive, or - // both negative. handle each case separately... - - if ((current >= 0) && (ideal >= 0)) // both positive - { - if (current > ideal) - current -= speed; - else - current += speed; - } - else if ((current >= 0) && (ideal < 0)) - { - current_180 = current - 180; - - if (current_180 > ideal) - current += speed; - else - current -= speed; - } - else if ((current < 0) && (ideal >= 0)) - { - current_180 = current + 180; - if (current_180 > ideal) - current += speed; - else - current -= speed; - } - else // (current < 0) && (ideal < 0) both negative - { - if (current > ideal) - current -= speed; - else - current += speed; - } - - // check for wrap around of angle... - if (current > 180) - current -= 360; - if (current < -180) - current += 360; - - pEdict->v.v_angle.y = current; - - return speed; // return number of degrees turned -} - - -bool BotFindWaypoint( bot_t *pBot ) -{ - // Do whatever you want here to find the next waypoint that the - // bot should head towards - - return FALSE; // couldn't find a waypoint -} - - -bool BotHeadTowardWaypoint( bot_t *pBot ) -{ - // You could do other stuff here if you needed to. - - // This would probably be a good place to check to see how close to a - // the current waypoint the bot is, and if the bot is close enough to - // the desired waypoint then call BotFindWaypoint to find the next one. - - if (BotFindWaypoint(pBot)) - return TRUE; - else - return FALSE; -} - - -void BotOnLadder( bot_t *pBot, float moved_distance ) -{ - Vector v_src, v_dest, view_angles; - TraceResult tr; - float angle = 0.0; - bool done = FALSE; - - edict_t *pEdict = pBot->pEdict; - - // check if the bot has JUST touched this ladder... - if (pBot->ladder_dir == LADDER_UNKNOWN) - { - // try to square up the bot on the ladder... - while ((!done) && (angle < 180.0)) - { - // try looking in one direction (forward + angle) - view_angles = pEdict->v.v_angle; - view_angles.y = pEdict->v.v_angle.y + angle; - - if (view_angles.y < 0.0) - view_angles.y += 360.0; - if (view_angles.y > 360.0) - view_angles.y -= 360.0; - - UTIL_MakeVectors( view_angles ); - - v_src = pEdict->v.origin + pEdict->v.view_ofs; - v_dest = v_src + gpGlobals->v_forward * 30; - - UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - if (tr.flFraction < 1.0) // hit something? - { - if (strcmp("func_wall", STRING(tr.pHit->v.classname)) == 0) - { - // square up to the wall... - view_angles = UTIL_VecToAngles(tr.vecPlaneNormal); - - // Normal comes OUT from wall, so flip it around... - view_angles.y += 180; - - if (view_angles.y > 180) - view_angles.y -= 360; - - pEdict->v.ideal_yaw = view_angles.y; - - BotFixIdealYaw(pEdict); - - done = TRUE; - } - } - else - { - // try looking in the other direction (forward - angle) - view_angles = pEdict->v.v_angle; - view_angles.y = pEdict->v.v_angle.y - angle; - - if (view_angles.y < 0.0) - view_angles.y += 360.0; - if (view_angles.y > 360.0) - view_angles.y -= 360.0; - - UTIL_MakeVectors( view_angles ); - - v_src = pEdict->v.origin + pEdict->v.view_ofs; - v_dest = v_src + gpGlobals->v_forward * 30; - - UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - if (tr.flFraction < 1.0) // hit something? - { - if (strcmp("func_wall", STRING(tr.pHit->v.classname)) == 0) - { - // square up to the wall... - view_angles = UTIL_VecToAngles(tr.vecPlaneNormal); - - // Normal comes OUT from wall, so flip it around... - view_angles.y += 180; - - if (view_angles.y > 180) - view_angles.y -= 360; - - pEdict->v.ideal_yaw = view_angles.y; - - BotFixIdealYaw(pEdict); - - done = TRUE; - } - } - } - - angle += 10; - } - - if (!done) // if didn't find a wall, just reset ideal_yaw... - { - // set ideal_yaw to current yaw (so bot won't keep turning) - pEdict->v.ideal_yaw = pEdict->v.v_angle.y; - - BotFixIdealYaw(pEdict); - } - } - - // moves the bot up or down a ladder. if the bot can't move - // (i.e. get's stuck with someone else on ladder), the bot will - // change directions and go the other way on the ladder. - - if (pBot->ladder_dir == LADDER_UP) // is the bot currently going up? - { - pEdict->v.v_angle.x = -60; // look upwards - - // check if the bot hasn't moved much since the last location... - if ((moved_distance <= 1) && (pBot->prev_speed >= 1.0)) - { - // the bot must be stuck, change directions... - - pEdict->v.v_angle.x = 60; // look downwards - pBot->ladder_dir = LADDER_DOWN; - } - } - else if (pBot->ladder_dir == LADDER_DOWN) // is the bot currently going down? - { - pEdict->v.v_angle.x = 60; // look downwards - - // check if the bot hasn't moved much since the last location... - if ((moved_distance <= 1) && (pBot->prev_speed >= 1.0)) - { - // the bot must be stuck, change directions... - - pEdict->v.v_angle.x = -60; // look upwards - pBot->ladder_dir = LADDER_UP; - } - } - else // the bot hasn't picked a direction yet, try going up... - { - pEdict->v.v_angle.x = -60; // look upwards - pBot->ladder_dir = LADDER_UP; - } - - // move forward (i.e. in the direction the bot is looking, up or down) - pEdict->v.button |= IN_FORWARD; -} - - -void BotUnderWater( bot_t *pBot ) -{ - bool found_waypoint = FALSE; - - edict_t *pEdict = pBot->pEdict; - - // are there waypoints in this level (and not trying to exit water)? - if ((num_waypoints > 0) && - (pBot->f_exit_water_time < gpGlobals->time)) - { - // head towards a waypoint - found_waypoint = BotHeadTowardWaypoint(pBot); - } - - if (found_waypoint == FALSE) - { - // handle movements under water. right now, just try to keep from - // drowning by swimming up towards the surface and look to see if - // there is a surface the bot can jump up onto to get out of the - // water. bots DON'T like water! - - Vector v_src, v_forward; - TraceResult tr; - int contents; - - // swim up towards the surface - pEdict->v.v_angle.x = -60; // look upwards - - // move forward (i.e. in the direction the bot is looking, up or down) - pEdict->v.button |= IN_FORWARD; - - // set gpGlobals angles based on current view angle (for TraceLine) - UTIL_MakeVectors( pEdict->v.v_angle ); - - // look from eye position straight forward (remember: the bot is looking - // upwards at a 60 degree angle so TraceLine will go out and up... - - v_src = pEdict->v.origin + pEdict->v.view_ofs; // EyePosition() - v_forward = v_src + gpGlobals->v_forward * 90; - - // trace from the bot's eyes straight forward... - UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // check if the trace didn't hit anything (i.e. nothing in the way)... - if (tr.flFraction >= 1.0) - { - // find out what the contents is of the end of the trace... - contents = UTIL_PointContents( tr.vecEndPos ); - - // check if the trace endpoint is in open space... - if (contents == CONTENTS_EMPTY) - { - // ok so far, we are at the surface of the water, continue... - - v_src = tr.vecEndPos; - v_forward = v_src; - v_forward.z -= 90; - - // trace from the previous end point straight down... - UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // check if the trace hit something... - if (tr.flFraction < 1.0) - { - contents = UTIL_PointContents( tr.vecEndPos ); - - // if contents isn't water then assume it's land, jump! - if (contents != CONTENTS_WATER) - { - pEdict->v.button |= IN_JUMP; - } - } - } - } - } -} - - -void BotUseLift( bot_t *pBot, float moved_distance ) -{ - edict_t *pEdict = pBot->pEdict; - - // just need to press the button once, when the flag gets set... - if (pBot->f_use_button_time == gpGlobals->time) - { - pEdict->v.button = IN_USE; - - // face opposite from the button - pEdict->v.ideal_yaw += 180; // rotate 180 degrees - - BotFixIdealYaw(pEdict); - } - - // check if the bot has waited too long for the lift to move... - if (((pBot->f_use_button_time + 2.0) < gpGlobals->time) && - (!pBot->b_lift_moving)) - { - // clear use button flag - pBot->b_use_button = FALSE; - - // bot doesn't have to set f_find_item since the bot - // should already be facing away from the button - - pBot->f_move_speed = pBot->f_max_speed; - } - - // check if lift has started moving... - if ((moved_distance > 1) && (!pBot->b_lift_moving)) - { - pBot->b_lift_moving = TRUE; - } - - // check if lift has stopped moving... - if ((moved_distance <= 1) && (pBot->b_lift_moving)) - { - TraceResult tr1, tr2; - Vector v_src, v_forward, v_right, v_left; - Vector v_down, v_forward_down, v_right_down, v_left_down; - - pBot->b_use_button = FALSE; - - // TraceLines in 4 directions to find which way to go... - - UTIL_MakeVectors( pEdict->v.v_angle ); - - v_src = pEdict->v.origin + pEdict->v.view_ofs; - v_forward = v_src + gpGlobals->v_forward * 90; - v_right = v_src + gpGlobals->v_right * 90; - v_left = v_src + gpGlobals->v_right * -90; - - v_down = pEdict->v.v_angle; - v_down.x = v_down.x + 45; // look down at 45 degree angle - - UTIL_MakeVectors( v_down ); - - v_forward_down = v_src + gpGlobals->v_forward * 100; - v_right_down = v_src + gpGlobals->v_right * 100; - v_left_down = v_src + gpGlobals->v_right * -100; - - // try tracing forward first... - UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr1); - UTIL_TraceLine( v_src, v_forward_down, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr2); - - // check if we hit a wall or didn't find a floor... - if ((tr1.flFraction < 1.0) || (tr2.flFraction >= 1.0)) - { - // try tracing to the RIGHT side next... - UTIL_TraceLine( v_src, v_right, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr1); - UTIL_TraceLine( v_src, v_right_down, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr2); - - // check if we hit a wall or didn't find a floor... - if ((tr1.flFraction < 1.0) || (tr2.flFraction >= 1.0)) - { - // try tracing to the LEFT side next... - UTIL_TraceLine( v_src, v_left, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr1); - UTIL_TraceLine( v_src, v_left_down, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr2); - - // check if we hit a wall or didn't find a floor... - if ((tr1.flFraction < 1.0) || (tr2.flFraction >= 1.0)) - { - // only thing to do is turn around... - pEdict->v.ideal_yaw += 180; // turn all the way around - } - else - { - pEdict->v.ideal_yaw += 90; // turn to the LEFT - } - } - else - { - pEdict->v.ideal_yaw -= 90; // turn to the RIGHT - } - - BotFixIdealYaw(pEdict); - } - - BotChangeYaw( pBot, pEdict->v.yaw_speed ); - - pBot->f_move_speed = pBot->f_max_speed; - } -} - - -bool BotStuckInCorner( bot_t *pBot ) -{ - TraceResult tr; - Vector v_src, v_dest; - edict_t *pEdict = pBot->pEdict; - - UTIL_MakeVectors( pEdict->v.v_angle ); - - // trace 45 degrees to the right... - v_src = pEdict->v.origin; - v_dest = v_src + gpGlobals->v_forward*20 + gpGlobals->v_right*20; - - UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - if (tr.flFraction >= 1.0) - return FALSE; // no wall, so not in a corner - - // trace 45 degrees to the left... - v_src = pEdict->v.origin; - v_dest = v_src + gpGlobals->v_forward*20 - gpGlobals->v_right*20; - - UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - if (tr.flFraction >= 1.0) - return FALSE; // no wall, so not in a corner - - return TRUE; // bot is in a corner -} - - -void BotTurnAtWall( bot_t *pBot, TraceResult *tr ) -{ - edict_t *pEdict = pBot->pEdict; - Vector Normal; - float Y, Y1, Y2, D1, D2, Z; - - // Find the normal vector from the trace result. The normal vector will - // be a vector that is perpendicular to the surface from the TraceResult. - - Normal = UTIL_VecToAngles(tr->vecPlaneNormal); - - // Since the bot keeps it's view angle in -180 < x < 180 degrees format, - // and since TraceResults are 0 < x < 360, we convert the bot's view - // angle (yaw) to the same format at TraceResult. - - Y = pEdict->v.v_angle.y; - Y = Y + 180; - if (Y > 359) Y -= 360; - - // Turn the normal vector around 180 degrees (i.e. make it point towards - // the wall not away from it. That makes finding the angles that the - // bot needs to turn a little easier. - - Normal.y = Normal.y - 180; - if (Normal.y < 0) - Normal.y += 360; - - // Here we compare the bots view angle (Y) to the Normal - 90 degrees (Y1) - // and the Normal + 90 degrees (Y2). These two angles (Y1 & Y2) represent - // angles that are parallel to the wall surface, but heading in opposite - // directions. We want the bot to choose the one that will require the - // least amount of turning (saves time) and have the bot head off in that - // direction. - - Y1 = Normal.y - 90; - if (RANDOM_LONG(1, 100) <= 50) - { - Y1 = Y1 - RANDOM_FLOAT(5.0, 20.0); - } - if (Y1 < 0) Y1 += 360; - - Y2 = Normal.y + 90; - if (RANDOM_LONG(1, 100) <= 50) - { - Y2 = Y2 + RANDOM_FLOAT(5.0, 20.0); - } - if (Y2 > 359) Y2 -= 360; - - // D1 and D2 are the difference (in degrees) between the bot's current - // angle and Y1 or Y2 (respectively). - - D1 = abs(Y - Y1); - if (D1 > 179) D1 = abs(D1 - 360); - D2 = abs(Y - Y2); - if (D2 > 179) D2 = abs(D2 - 360); - - // If difference 1 (D1) is more than difference 2 (D2) then the bot will - // have to turn LESS if it heads in direction Y1 otherwise, head in - // direction Y2. I know this seems backwards, but try some sample angles - // out on some graph paper and go through these equations using a - // calculator, you'll see what I mean. - - if (D1 > D2) - Z = Y1; - else - Z = Y2; - - // convert from TraceResult 0 to 360 degree format back to bot's - // -180 to 180 degree format. - - if (Z > 180) - Z -= 360; - - // set the direction to head off into... - pEdict->v.ideal_yaw = Z; - - BotFixIdealYaw(pEdict); -} - - -bool BotCantMoveForward( bot_t *pBot, TraceResult *tr ) -{ - edict_t *pEdict = pBot->pEdict; - - // use some TraceLines to determine if anything is blocking the current - // path of the bot. - - Vector v_src, v_forward; - - UTIL_MakeVectors( pEdict->v.v_angle ); - - // first do a trace from the bot's eyes forward... - - v_src = pEdict->v.origin + pEdict->v.view_ofs; // EyePosition() - v_forward = v_src + gpGlobals->v_forward * 40; - - // trace from the bot's eyes straight forward... - UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, - pEdict->v.pContainingEntity, tr); - - // check if the trace hit something... - if (tr->flFraction < 1.0) - { - return TRUE; // bot's head will hit something - } - - // bot's head is clear, check at waist level... - - v_src = pEdict->v.origin; - v_forward = v_src + gpGlobals->v_forward * 40; - - // trace from the bot's waist straight forward... - UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, - pEdict->v.pContainingEntity, tr); - - // check if the trace hit something... - if (tr->flFraction < 1.0) - { - return TRUE; // bot's body will hit something - } - - return FALSE; // bot can move forward, return false -} - - -bool BotCanJumpUp( bot_t *pBot ) -{ - // What I do here is trace 3 lines straight out, one unit higher than - // the highest normal jumping distance. I trace once at the center of - // the body, once at the right side, and once at the left side. If all - // three of these TraceLines don't hit an obstruction then I know the - // area to jump to is clear. I then need to trace from head level, - // above where the bot will jump to, downward to see if there is anything - // blocking the jump. There could be a narrow opening that the body - // will not fit into. These horizontal and vertical TraceLines seem - // to catch most of the problems with falsely trying to jump on something - // that the bot can not get onto. - - // Make flier imitate flight - if(pBot->pEdict->v.iuser3 == AVH_USER3_ALIEN_PLAYER3) - { - if(RANDOM_LONG(0, 2) == 0) - { - return TRUE; - } - } - - TraceResult tr; - Vector v_jump, v_source, v_dest; - edict_t *pEdict = pBot->pEdict; - - // convert current view angle to vectors for TraceLine math... - - v_jump = pEdict->v.v_angle; - v_jump.x = 0; // reset pitch to 0 (level horizontally) - v_jump.z = 0; // reset roll to 0 (straight up and down) - - UTIL_MakeVectors( v_jump ); - - // use center of the body first... - - // maximum jump height is 45, so check one unit above that (46) - v_source = pEdict->v.origin + Vector(0, 0, -36 + 46); - v_dest = v_source + gpGlobals->v_forward * 24; - - // trace a line forward at maximum jump height... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now check same height to one side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * 16 + Vector(0, 0, -36 + 46); - v_dest = v_source + gpGlobals->v_forward * 24; - - // trace a line forward at maximum jump height... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now check same height on the other side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * -16 + Vector(0, 0, -36 + 46); - v_dest = v_source + gpGlobals->v_forward * 24; - - // trace a line forward at maximum jump height... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now trace from head level downward to check for obstructions... - - // start of trace is 24 units in front of bot, 72 units above head... - v_source = pEdict->v.origin + gpGlobals->v_forward * 24; - - // offset 72 units from top of head (72 + 36) - v_source.z = v_source.z + 108; - - // end point of trace is 99 units straight down from start... - // (99 is 108 minus the jump limit height which is 45 - 36 = 9) - v_dest = v_source + Vector(0, 0, -99); - - // trace a line straight down toward the ground... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now check same height to one side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * 16 + gpGlobals->v_forward * 24; - v_source.z = v_source.z + 108; - v_dest = v_source + Vector(0, 0, -99); - - // trace a line straight down toward the ground... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now check same height on the other side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * -16 + gpGlobals->v_forward * 24; - v_source.z = v_source.z + 108; - v_dest = v_source + Vector(0, 0, -99); - - // trace a line straight down toward the ground... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - return TRUE; -} - - -bool BotCanDuckUnder( bot_t *pBot ) -{ - // What I do here is trace 3 lines straight out, one unit higher than - // the ducking height. I trace once at the center of the body, once - // at the right side, and once at the left side. If all three of these - // TraceLines don't hit an obstruction then I know the area to duck to - // is clear. I then need to trace from the ground up, 72 units, to make - // sure that there is something blocking the TraceLine. Then we know - // we can duck under it. - - TraceResult tr; - Vector v_duck, v_source, v_dest; - edict_t *pEdict = pBot->pEdict; - - // convert current view angle to vectors for TraceLine math... - - v_duck = pEdict->v.v_angle; - v_duck.x = 0; // reset pitch to 0 (level horizontally) - v_duck.z = 0; // reset roll to 0 (straight up and down) - - UTIL_MakeVectors( v_duck ); - - // use center of the body first... - - // duck height is 36, so check one unit above that (37) - v_source = pEdict->v.origin + Vector(0, 0, -36 + 37); - v_dest = v_source + gpGlobals->v_forward * 24; - - // trace a line forward at duck height... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now check same height to one side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * 16 + Vector(0, 0, -36 + 37); - v_dest = v_source + gpGlobals->v_forward * 24; - - // trace a line forward at duck height... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now check same height on the other side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * -16 + Vector(0, 0, -36 + 37); - v_dest = v_source + gpGlobals->v_forward * 24; - - // trace a line forward at duck height... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace hit something, return FALSE - if (tr.flFraction < 1.0) - return FALSE; - - // now trace from the ground up to check for object to duck under... - - // start of trace is 24 units in front of bot near ground... - v_source = pEdict->v.origin + gpGlobals->v_forward * 24; - v_source.z = v_source.z - 35; // offset to feet + 1 unit up - - // end point of trace is 72 units straight up from start... - v_dest = v_source + Vector(0, 0, 72); - - // trace a line straight up in the air... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace didn't hit something, return FALSE - if (tr.flFraction >= 1.0) - return FALSE; - - // now check same height to one side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * 16 + gpGlobals->v_forward * 24; - v_source.z = v_source.z - 35; // offset to feet + 1 unit up - v_dest = v_source + Vector(0, 0, 72); - - // trace a line straight up in the air... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace didn't hit something, return FALSE - if (tr.flFraction >= 1.0) - return FALSE; - - // now check same height on the other side of the bot... - v_source = pEdict->v.origin + gpGlobals->v_right * -16 + gpGlobals->v_forward * 24; - v_source.z = v_source.z - 35; // offset to feet + 1 unit up - v_dest = v_source + Vector(0, 0, 72); - - // trace a line straight up in the air... - UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // if trace didn't hit something, return FALSE - if (tr.flFraction >= 1.0) - return FALSE; - - return TRUE; -} - - -void BotRandomTurn( bot_t *pBot ) -{ - pBot->f_move_speed = 0; // don't move while turning - - if (RANDOM_LONG(1, 100) <= 10) - { - // 10 percent of the time turn completely around... - pBot->pEdict->v.ideal_yaw += 180; - } - else - { - // turn randomly between 30 and 60 degress - if (pBot->wander_dir == WANDER_LEFT) - pBot->pEdict->v.ideal_yaw += RANDOM_LONG(30, 60); - else - pBot->pEdict->v.ideal_yaw -= RANDOM_LONG(30, 60); - } - - BotFixIdealYaw(pBot->pEdict); -} - - -bool BotFollowUser( bot_t *pBot ) -{ - bool user_visible; - float f_distance; - edict_t *pEdict = pBot->pEdict; - - Vector vecEnd = pBot->pBotUser->v.origin + pBot->pBotUser->v.view_ofs; - - if (pBot->pEdict->v.waterlevel != 3) // is bot NOT under water? - pEdict->v.v_angle.x = 0; // reset pitch to 0 (level horizontally) - - pEdict->v.v_angle.z = 0; // reset roll to 0 (straight up and down) - - pEdict->v.angles.x = 0; - pEdict->v.angles.y = pEdict->v.v_angle.y; - pEdict->v.angles.z = 0; - - // Stop following when person crouches - if (!IsAlive( pBot->pBotUser ) || (pBot->pBotUser->v.flags & FL_DUCKING)) - { - // the bot's user is dead! - pBot->pBotUser = NULL; - return FALSE; - } - - user_visible = FInViewCone( &vecEnd, pEdict ) && - FVisible( vecEnd, pEdict ); - - // check if the "user" is still visible or if the user has been visible - // in the last 5 seconds (or the player just starting "using" the bot) - - if (user_visible || (pBot->f_bot_use_time + 5 > gpGlobals->time)) - { - if (user_visible) - pBot->f_bot_use_time = gpGlobals->time; // reset "last visible time" - - // face the user - Vector v_user = pBot->pBotUser->v.origin - pEdict->v.origin; - Vector bot_angles = UTIL_VecToAngles( v_user ); - - pEdict->v.ideal_yaw = bot_angles.y; - - BotFixIdealYaw(pEdict); - - f_distance = v_user.Length( ); // how far away is the "user"? - - if (f_distance > 200) // run if distance to enemy is far - pBot->f_move_speed = pBot->f_max_speed; - else if (f_distance > 50) // walk if distance is closer - pBot->f_move_speed = pBot->f_max_speed / 2; - else // don't move if close enough - pBot->f_move_speed = 0.0; - - return TRUE; - } - else - { - // person to follow has gone out of sight... - pBot->pBotUser = NULL; - - return FALSE; - } -} - - -bool BotCheckWallOnLeft( bot_t *pBot ) -{ - edict_t *pEdict = pBot->pEdict; - Vector v_src, v_left; - TraceResult tr; - - UTIL_MakeVectors( pEdict->v.v_angle ); - - // do a trace to the left... - - v_src = pEdict->v.origin; - v_left = v_src + gpGlobals->v_right * -40; // 40 units to the left - - UTIL_TraceLine( v_src, v_left, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // check if the trace hit something... - if (tr.flFraction < 1.0) - { - if (pBot->f_wall_on_left < 1.0) - pBot->f_wall_on_left = gpGlobals->time; - - return TRUE; - } - - return FALSE; -} - - -bool BotCheckWallOnRight( bot_t *pBot ) -{ - edict_t *pEdict = pBot->pEdict; - Vector v_src, v_right; - TraceResult tr; - - UTIL_MakeVectors( pEdict->v.v_angle ); - - // do a trace to the right... - - v_src = pEdict->v.origin; - v_right = v_src + gpGlobals->v_right * 40; // 40 units to the right - - UTIL_TraceLine( v_src, v_right, dont_ignore_monsters, - pEdict->v.pContainingEntity, &tr); - - // check if the trace hit something... - if (tr.flFraction < 1.0) - { - if (pBot->f_wall_on_right < 1.0) - pBot->f_wall_on_right = gpGlobals->time; - - return TRUE; - } - - return FALSE; -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_navigate.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" +#include "bot_func.h" +#include "waypoint.h" + + +extern int mod_id; +extern WAYPOINT waypoints[MAX_WAYPOINTS]; +extern int num_waypoints; // number of waypoints currently in use +extern int team_allies[4]; +extern edict_t *pent_info_ctfdetect; +extern float is_team_play; +extern bool checked_teamplay; +extern FLAG_S flags[MAX_FLAGS]; +extern int num_flags; + +extern int flf_bug_fix; + +static FILE *fp; + + + +void BotFixIdealPitch(edict_t *pEdict) +{ + // check for wrap around of angle... + if (pEdict->v.idealpitch > 180) + pEdict->v.idealpitch -= 360; + + if (pEdict->v.idealpitch < -180) + pEdict->v.idealpitch += 360; +} + + +float BotChangePitch( bot_t *pBot, float speed ) +{ + edict_t *pEdict = pBot->pEdict; + float ideal; + float current; + float current_180; // current +/- 180 degrees + float diff; + + // turn from the current v_angle pitch to the idealpitch by selecting + // the quickest way to turn to face that direction + + current = pEdict->v.v_angle.x; + + ideal = pEdict->v.idealpitch; + + // find the difference in the current and ideal angle + diff = abs(current - ideal); + + // check if the bot is already facing the idealpitch direction... + if (diff <= 1) + return diff; // return number of degrees turned + + // check if difference is less than the max degrees per turn + if (diff < speed) + speed = diff; // just need to turn a little bit (less than max) + + // here we have four cases, both angle positive, one positive and + // the other negative, one negative and the other positive, or + // both negative. handle each case separately... + + if ((current >= 0) && (ideal >= 0)) // both positive + { + if (current > ideal) + current -= speed; + else + current += speed; + } + else if ((current >= 0) && (ideal < 0)) + { + current_180 = current - 180; + + if (current_180 > ideal) + current += speed; + else + current -= speed; + } + else if ((current < 0) && (ideal >= 0)) + { + current_180 = current + 180; + if (current_180 > ideal) + current += speed; + else + current -= speed; + } + else // (current < 0) && (ideal < 0) both negative + { + if (current > ideal) + current -= speed; + else + current += speed; + } + + // check for wrap around of angle... + if (current > 180) + current -= 360; + if (current < -180) + current += 360; + + pEdict->v.v_angle.x = current; + + return speed; // return number of degrees turned +} + + +void BotFixIdealYaw(edict_t *pEdict) +{ + // check for wrap around of angle... + if (pEdict->v.ideal_yaw > 180) + pEdict->v.ideal_yaw -= 360; + + if (pEdict->v.ideal_yaw < -180) + pEdict->v.ideal_yaw += 360; +} + + +float BotChangeYaw( bot_t *pBot, float speed ) +{ + edict_t *pEdict = pBot->pEdict; + float ideal; + float current; + float current_180; // current +/- 180 degrees + float diff; + + // turn from the current v_angle yaw to the ideal_yaw by selecting + // the quickest way to turn to face that direction + + current = pEdict->v.v_angle.y; + + ideal = pEdict->v.ideal_yaw; + + // find the difference in the current and ideal angle + diff = abs(current - ideal); + + // check if the bot is already facing the ideal_yaw direction... + if (diff <= 1) + return diff; // return number of degrees turned + + // check if difference is less than the max degrees per turn + if (diff < speed) + speed = diff; // just need to turn a little bit (less than max) + + // here we have four cases, both angle positive, one positive and + // the other negative, one negative and the other positive, or + // both negative. handle each case separately... + + if ((current >= 0) && (ideal >= 0)) // both positive + { + if (current > ideal) + current -= speed; + else + current += speed; + } + else if ((current >= 0) && (ideal < 0)) + { + current_180 = current - 180; + + if (current_180 > ideal) + current += speed; + else + current -= speed; + } + else if ((current < 0) && (ideal >= 0)) + { + current_180 = current + 180; + if (current_180 > ideal) + current += speed; + else + current -= speed; + } + else // (current < 0) && (ideal < 0) both negative + { + if (current > ideal) + current -= speed; + else + current += speed; + } + + // check for wrap around of angle... + if (current > 180) + current -= 360; + if (current < -180) + current += 360; + + pEdict->v.v_angle.y = current; + + return speed; // return number of degrees turned +} + + +bool BotFindWaypoint( bot_t *pBot ) +{ + // Do whatever you want here to find the next waypoint that the + // bot should head towards + + return FALSE; // couldn't find a waypoint +} + + +bool BotHeadTowardWaypoint( bot_t *pBot ) +{ + // You could do other stuff here if you needed to. + + // This would probably be a good place to check to see how close to a + // the current waypoint the bot is, and if the bot is close enough to + // the desired waypoint then call BotFindWaypoint to find the next one. + + if (BotFindWaypoint(pBot)) + return TRUE; + else + return FALSE; +} + + +void BotOnLadder( bot_t *pBot, float moved_distance ) +{ + Vector v_src, v_dest, view_angles; + TraceResult tr; + float angle = 0.0; + bool done = FALSE; + + edict_t *pEdict = pBot->pEdict; + + // check if the bot has JUST touched this ladder... + if (pBot->ladder_dir == LADDER_UNKNOWN) + { + // try to square up the bot on the ladder... + while ((!done) && (angle < 180.0)) + { + // try looking in one direction (forward + angle) + view_angles = pEdict->v.v_angle; + view_angles.y = pEdict->v.v_angle.y + angle; + + if (view_angles.y < 0.0) + view_angles.y += 360.0; + if (view_angles.y > 360.0) + view_angles.y -= 360.0; + + UTIL_MakeVectors( view_angles ); + + v_src = pEdict->v.origin + pEdict->v.view_ofs; + v_dest = v_src + gpGlobals->v_forward * 30; + + UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + if (tr.flFraction < 1.0) // hit something? + { + if (strcmp("func_wall", STRING(tr.pHit->v.classname)) == 0) + { + // square up to the wall... + view_angles = UTIL_VecToAngles(tr.vecPlaneNormal); + + // Normal comes OUT from wall, so flip it around... + view_angles.y += 180; + + if (view_angles.y > 180) + view_angles.y -= 360; + + pEdict->v.ideal_yaw = view_angles.y; + + BotFixIdealYaw(pEdict); + + done = TRUE; + } + } + else + { + // try looking in the other direction (forward - angle) + view_angles = pEdict->v.v_angle; + view_angles.y = pEdict->v.v_angle.y - angle; + + if (view_angles.y < 0.0) + view_angles.y += 360.0; + if (view_angles.y > 360.0) + view_angles.y -= 360.0; + + UTIL_MakeVectors( view_angles ); + + v_src = pEdict->v.origin + pEdict->v.view_ofs; + v_dest = v_src + gpGlobals->v_forward * 30; + + UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + if (tr.flFraction < 1.0) // hit something? + { + if (strcmp("func_wall", STRING(tr.pHit->v.classname)) == 0) + { + // square up to the wall... + view_angles = UTIL_VecToAngles(tr.vecPlaneNormal); + + // Normal comes OUT from wall, so flip it around... + view_angles.y += 180; + + if (view_angles.y > 180) + view_angles.y -= 360; + + pEdict->v.ideal_yaw = view_angles.y; + + BotFixIdealYaw(pEdict); + + done = TRUE; + } + } + } + + angle += 10; + } + + if (!done) // if didn't find a wall, just reset ideal_yaw... + { + // set ideal_yaw to current yaw (so bot won't keep turning) + pEdict->v.ideal_yaw = pEdict->v.v_angle.y; + + BotFixIdealYaw(pEdict); + } + } + + // moves the bot up or down a ladder. if the bot can't move + // (i.e. get's stuck with someone else on ladder), the bot will + // change directions and go the other way on the ladder. + + if (pBot->ladder_dir == LADDER_UP) // is the bot currently going up? + { + pEdict->v.v_angle.x = -60; // look upwards + + // check if the bot hasn't moved much since the last location... + if ((moved_distance <= 1) && (pBot->prev_speed >= 1.0)) + { + // the bot must be stuck, change directions... + + pEdict->v.v_angle.x = 60; // look downwards + pBot->ladder_dir = LADDER_DOWN; + } + } + else if (pBot->ladder_dir == LADDER_DOWN) // is the bot currently going down? + { + pEdict->v.v_angle.x = 60; // look downwards + + // check if the bot hasn't moved much since the last location... + if ((moved_distance <= 1) && (pBot->prev_speed >= 1.0)) + { + // the bot must be stuck, change directions... + + pEdict->v.v_angle.x = -60; // look upwards + pBot->ladder_dir = LADDER_UP; + } + } + else // the bot hasn't picked a direction yet, try going up... + { + pEdict->v.v_angle.x = -60; // look upwards + pBot->ladder_dir = LADDER_UP; + } + + // move forward (i.e. in the direction the bot is looking, up or down) + pEdict->v.button |= IN_FORWARD; +} + + +void BotUnderWater( bot_t *pBot ) +{ + bool found_waypoint = FALSE; + + edict_t *pEdict = pBot->pEdict; + + // are there waypoints in this level (and not trying to exit water)? + if ((num_waypoints > 0) && + (pBot->f_exit_water_time < gpGlobals->time)) + { + // head towards a waypoint + found_waypoint = BotHeadTowardWaypoint(pBot); + } + + if (found_waypoint == FALSE) + { + // handle movements under water. right now, just try to keep from + // drowning by swimming up towards the surface and look to see if + // there is a surface the bot can jump up onto to get out of the + // water. bots DON'T like water! + + Vector v_src, v_forward; + TraceResult tr; + int contents; + + // swim up towards the surface + pEdict->v.v_angle.x = -60; // look upwards + + // move forward (i.e. in the direction the bot is looking, up or down) + pEdict->v.button |= IN_FORWARD; + + // set gpGlobals angles based on current view angle (for TraceLine) + UTIL_MakeVectors( pEdict->v.v_angle ); + + // look from eye position straight forward (remember: the bot is looking + // upwards at a 60 degree angle so TraceLine will go out and up... + + v_src = pEdict->v.origin + pEdict->v.view_ofs; // EyePosition() + v_forward = v_src + gpGlobals->v_forward * 90; + + // trace from the bot's eyes straight forward... + UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // check if the trace didn't hit anything (i.e. nothing in the way)... + if (tr.flFraction >= 1.0) + { + // find out what the contents is of the end of the trace... + contents = UTIL_PointContents( tr.vecEndPos ); + + // check if the trace endpoint is in open space... + if (contents == CONTENTS_EMPTY) + { + // ok so far, we are at the surface of the water, continue... + + v_src = tr.vecEndPos; + v_forward = v_src; + v_forward.z -= 90; + + // trace from the previous end point straight down... + UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // check if the trace hit something... + if (tr.flFraction < 1.0) + { + contents = UTIL_PointContents( tr.vecEndPos ); + + // if contents isn't water then assume it's land, jump! + if (contents != CONTENTS_WATER) + { + pEdict->v.button |= IN_JUMP; + } + } + } + } + } +} + + +void BotUseLift( bot_t *pBot, float moved_distance ) +{ + edict_t *pEdict = pBot->pEdict; + + // just need to press the button once, when the flag gets set... + if (pBot->f_use_button_time == gpGlobals->time) + { + pEdict->v.button = IN_USE; + + // face opposite from the button + pEdict->v.ideal_yaw += 180; // rotate 180 degrees + + BotFixIdealYaw(pEdict); + } + + // check if the bot has waited too long for the lift to move... + if (((pBot->f_use_button_time + 2.0) < gpGlobals->time) && + (!pBot->b_lift_moving)) + { + // clear use button flag + pBot->b_use_button = FALSE; + + // bot doesn't have to set f_find_item since the bot + // should already be facing away from the button + + pBot->f_move_speed = pBot->f_max_speed; + } + + // check if lift has started moving... + if ((moved_distance > 1) && (!pBot->b_lift_moving)) + { + pBot->b_lift_moving = TRUE; + } + + // check if lift has stopped moving... + if ((moved_distance <= 1) && (pBot->b_lift_moving)) + { + TraceResult tr1, tr2; + Vector v_src, v_forward, v_right, v_left; + Vector v_down, v_forward_down, v_right_down, v_left_down; + + pBot->b_use_button = FALSE; + + // TraceLines in 4 directions to find which way to go... + + UTIL_MakeVectors( pEdict->v.v_angle ); + + v_src = pEdict->v.origin + pEdict->v.view_ofs; + v_forward = v_src + gpGlobals->v_forward * 90; + v_right = v_src + gpGlobals->v_right * 90; + v_left = v_src + gpGlobals->v_right * -90; + + v_down = pEdict->v.v_angle; + v_down.x = v_down.x + 45; // look down at 45 degree angle + + UTIL_MakeVectors( v_down ); + + v_forward_down = v_src + gpGlobals->v_forward * 100; + v_right_down = v_src + gpGlobals->v_right * 100; + v_left_down = v_src + gpGlobals->v_right * -100; + + // try tracing forward first... + UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr1); + UTIL_TraceLine( v_src, v_forward_down, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr2); + + // check if we hit a wall or didn't find a floor... + if ((tr1.flFraction < 1.0) || (tr2.flFraction >= 1.0)) + { + // try tracing to the RIGHT side next... + UTIL_TraceLine( v_src, v_right, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr1); + UTIL_TraceLine( v_src, v_right_down, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr2); + + // check if we hit a wall or didn't find a floor... + if ((tr1.flFraction < 1.0) || (tr2.flFraction >= 1.0)) + { + // try tracing to the LEFT side next... + UTIL_TraceLine( v_src, v_left, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr1); + UTIL_TraceLine( v_src, v_left_down, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr2); + + // check if we hit a wall or didn't find a floor... + if ((tr1.flFraction < 1.0) || (tr2.flFraction >= 1.0)) + { + // only thing to do is turn around... + pEdict->v.ideal_yaw += 180; // turn all the way around + } + else + { + pEdict->v.ideal_yaw += 90; // turn to the LEFT + } + } + else + { + pEdict->v.ideal_yaw -= 90; // turn to the RIGHT + } + + BotFixIdealYaw(pEdict); + } + + BotChangeYaw( pBot, pEdict->v.yaw_speed ); + + pBot->f_move_speed = pBot->f_max_speed; + } +} + + +bool BotStuckInCorner( bot_t *pBot ) +{ + TraceResult tr; + Vector v_src, v_dest; + edict_t *pEdict = pBot->pEdict; + + UTIL_MakeVectors( pEdict->v.v_angle ); + + // trace 45 degrees to the right... + v_src = pEdict->v.origin; + v_dest = v_src + gpGlobals->v_forward*20 + gpGlobals->v_right*20; + + UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + if (tr.flFraction >= 1.0) + return FALSE; // no wall, so not in a corner + + // trace 45 degrees to the left... + v_src = pEdict->v.origin; + v_dest = v_src + gpGlobals->v_forward*20 - gpGlobals->v_right*20; + + UTIL_TraceLine( v_src, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + if (tr.flFraction >= 1.0) + return FALSE; // no wall, so not in a corner + + return TRUE; // bot is in a corner +} + + +void BotTurnAtWall( bot_t *pBot, TraceResult *tr ) +{ + edict_t *pEdict = pBot->pEdict; + Vector Normal; + float Y, Y1, Y2, D1, D2, Z; + + // Find the normal vector from the trace result. The normal vector will + // be a vector that is perpendicular to the surface from the TraceResult. + + Normal = UTIL_VecToAngles(tr->vecPlaneNormal); + + // Since the bot keeps it's view angle in -180 < x < 180 degrees format, + // and since TraceResults are 0 < x < 360, we convert the bot's view + // angle (yaw) to the same format at TraceResult. + + Y = pEdict->v.v_angle.y; + Y = Y + 180; + if (Y > 359) Y -= 360; + + // Turn the normal vector around 180 degrees (i.e. make it point towards + // the wall not away from it. That makes finding the angles that the + // bot needs to turn a little easier. + + Normal.y = Normal.y - 180; + if (Normal.y < 0) + Normal.y += 360; + + // Here we compare the bots view angle (Y) to the Normal - 90 degrees (Y1) + // and the Normal + 90 degrees (Y2). These two angles (Y1 & Y2) represent + // angles that are parallel to the wall surface, but heading in opposite + // directions. We want the bot to choose the one that will require the + // least amount of turning (saves time) and have the bot head off in that + // direction. + + Y1 = Normal.y - 90; + if (RANDOM_LONG(1, 100) <= 50) + { + Y1 = Y1 - RANDOM_FLOAT(5.0, 20.0); + } + if (Y1 < 0) Y1 += 360; + + Y2 = Normal.y + 90; + if (RANDOM_LONG(1, 100) <= 50) + { + Y2 = Y2 + RANDOM_FLOAT(5.0, 20.0); + } + if (Y2 > 359) Y2 -= 360; + + // D1 and D2 are the difference (in degrees) between the bot's current + // angle and Y1 or Y2 (respectively). + + D1 = abs(Y - Y1); + if (D1 > 179) D1 = abs(D1 - 360); + D2 = abs(Y - Y2); + if (D2 > 179) D2 = abs(D2 - 360); + + // If difference 1 (D1) is more than difference 2 (D2) then the bot will + // have to turn LESS if it heads in direction Y1 otherwise, head in + // direction Y2. I know this seems backwards, but try some sample angles + // out on some graph paper and go through these equations using a + // calculator, you'll see what I mean. + + if (D1 > D2) + Z = Y1; + else + Z = Y2; + + // convert from TraceResult 0 to 360 degree format back to bot's + // -180 to 180 degree format. + + if (Z > 180) + Z -= 360; + + // set the direction to head off into... + pEdict->v.ideal_yaw = Z; + + BotFixIdealYaw(pEdict); +} + + +bool BotCantMoveForward( bot_t *pBot, TraceResult *tr ) +{ + edict_t *pEdict = pBot->pEdict; + + // use some TraceLines to determine if anything is blocking the current + // path of the bot. + + Vector v_src, v_forward; + + UTIL_MakeVectors( pEdict->v.v_angle ); + + // first do a trace from the bot's eyes forward... + + v_src = pEdict->v.origin + pEdict->v.view_ofs; // EyePosition() + v_forward = v_src + gpGlobals->v_forward * 40; + + // trace from the bot's eyes straight forward... + UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, + pEdict->v.pContainingEntity, tr); + + // check if the trace hit something... + if (tr->flFraction < 1.0) + { + return TRUE; // bot's head will hit something + } + + // bot's head is clear, check at waist level... + + v_src = pEdict->v.origin; + v_forward = v_src + gpGlobals->v_forward * 40; + + // trace from the bot's waist straight forward... + UTIL_TraceLine( v_src, v_forward, dont_ignore_monsters, + pEdict->v.pContainingEntity, tr); + + // check if the trace hit something... + if (tr->flFraction < 1.0) + { + return TRUE; // bot's body will hit something + } + + return FALSE; // bot can move forward, return false +} + + +bool BotCanJumpUp( bot_t *pBot ) +{ + // What I do here is trace 3 lines straight out, one unit higher than + // the highest normal jumping distance. I trace once at the center of + // the body, once at the right side, and once at the left side. If all + // three of these TraceLines don't hit an obstruction then I know the + // area to jump to is clear. I then need to trace from head level, + // above where the bot will jump to, downward to see if there is anything + // blocking the jump. There could be a narrow opening that the body + // will not fit into. These horizontal and vertical TraceLines seem + // to catch most of the problems with falsely trying to jump on something + // that the bot can not get onto. + + // Make flier imitate flight + if(pBot->pEdict->v.iuser3 == AVH_USER3_ALIEN_PLAYER3) + { + if(RANDOM_LONG(0, 2) == 0) + { + return TRUE; + } + } + + TraceResult tr; + Vector v_jump, v_source, v_dest; + edict_t *pEdict = pBot->pEdict; + + // convert current view angle to vectors for TraceLine math... + + v_jump = pEdict->v.v_angle; + v_jump.x = 0; // reset pitch to 0 (level horizontally) + v_jump.z = 0; // reset roll to 0 (straight up and down) + + UTIL_MakeVectors( v_jump ); + + // use center of the body first... + + // maximum jump height is 45, so check one unit above that (46) + v_source = pEdict->v.origin + Vector(0, 0, -36 + 46); + v_dest = v_source + gpGlobals->v_forward * 24; + + // trace a line forward at maximum jump height... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now check same height to one side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * 16 + Vector(0, 0, -36 + 46); + v_dest = v_source + gpGlobals->v_forward * 24; + + // trace a line forward at maximum jump height... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now check same height on the other side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * -16 + Vector(0, 0, -36 + 46); + v_dest = v_source + gpGlobals->v_forward * 24; + + // trace a line forward at maximum jump height... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now trace from head level downward to check for obstructions... + + // start of trace is 24 units in front of bot, 72 units above head... + v_source = pEdict->v.origin + gpGlobals->v_forward * 24; + + // offset 72 units from top of head (72 + 36) + v_source.z = v_source.z + 108; + + // end point of trace is 99 units straight down from start... + // (99 is 108 minus the jump limit height which is 45 - 36 = 9) + v_dest = v_source + Vector(0, 0, -99); + + // trace a line straight down toward the ground... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now check same height to one side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * 16 + gpGlobals->v_forward * 24; + v_source.z = v_source.z + 108; + v_dest = v_source + Vector(0, 0, -99); + + // trace a line straight down toward the ground... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now check same height on the other side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * -16 + gpGlobals->v_forward * 24; + v_source.z = v_source.z + 108; + v_dest = v_source + Vector(0, 0, -99); + + // trace a line straight down toward the ground... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + return TRUE; +} + + +bool BotCanDuckUnder( bot_t *pBot ) +{ + // What I do here is trace 3 lines straight out, one unit higher than + // the ducking height. I trace once at the center of the body, once + // at the right side, and once at the left side. If all three of these + // TraceLines don't hit an obstruction then I know the area to duck to + // is clear. I then need to trace from the ground up, 72 units, to make + // sure that there is something blocking the TraceLine. Then we know + // we can duck under it. + + TraceResult tr; + Vector v_duck, v_source, v_dest; + edict_t *pEdict = pBot->pEdict; + + // convert current view angle to vectors for TraceLine math... + + v_duck = pEdict->v.v_angle; + v_duck.x = 0; // reset pitch to 0 (level horizontally) + v_duck.z = 0; // reset roll to 0 (straight up and down) + + UTIL_MakeVectors( v_duck ); + + // use center of the body first... + + // duck height is 36, so check one unit above that (37) + v_source = pEdict->v.origin + Vector(0, 0, -36 + 37); + v_dest = v_source + gpGlobals->v_forward * 24; + + // trace a line forward at duck height... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now check same height to one side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * 16 + Vector(0, 0, -36 + 37); + v_dest = v_source + gpGlobals->v_forward * 24; + + // trace a line forward at duck height... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now check same height on the other side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * -16 + Vector(0, 0, -36 + 37); + v_dest = v_source + gpGlobals->v_forward * 24; + + // trace a line forward at duck height... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace hit something, return FALSE + if (tr.flFraction < 1.0) + return FALSE; + + // now trace from the ground up to check for object to duck under... + + // start of trace is 24 units in front of bot near ground... + v_source = pEdict->v.origin + gpGlobals->v_forward * 24; + v_source.z = v_source.z - 35; // offset to feet + 1 unit up + + // end point of trace is 72 units straight up from start... + v_dest = v_source + Vector(0, 0, 72); + + // trace a line straight up in the air... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace didn't hit something, return FALSE + if (tr.flFraction >= 1.0) + return FALSE; + + // now check same height to one side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * 16 + gpGlobals->v_forward * 24; + v_source.z = v_source.z - 35; // offset to feet + 1 unit up + v_dest = v_source + Vector(0, 0, 72); + + // trace a line straight up in the air... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace didn't hit something, return FALSE + if (tr.flFraction >= 1.0) + return FALSE; + + // now check same height on the other side of the bot... + v_source = pEdict->v.origin + gpGlobals->v_right * -16 + gpGlobals->v_forward * 24; + v_source.z = v_source.z - 35; // offset to feet + 1 unit up + v_dest = v_source + Vector(0, 0, 72); + + // trace a line straight up in the air... + UTIL_TraceLine( v_source, v_dest, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // if trace didn't hit something, return FALSE + if (tr.flFraction >= 1.0) + return FALSE; + + return TRUE; +} + + +void BotRandomTurn( bot_t *pBot ) +{ + pBot->f_move_speed = 0; // don't move while turning + + if (RANDOM_LONG(1, 100) <= 10) + { + // 10 percent of the time turn completely around... + pBot->pEdict->v.ideal_yaw += 180; + } + else + { + // turn randomly between 30 and 60 degress + if (pBot->wander_dir == WANDER_LEFT) + pBot->pEdict->v.ideal_yaw += RANDOM_LONG(30, 60); + else + pBot->pEdict->v.ideal_yaw -= RANDOM_LONG(30, 60); + } + + BotFixIdealYaw(pBot->pEdict); +} + + +bool BotFollowUser( bot_t *pBot ) +{ + bool user_visible; + float f_distance; + edict_t *pEdict = pBot->pEdict; + + Vector vecEnd = pBot->pBotUser->v.origin + pBot->pBotUser->v.view_ofs; + + if (pBot->pEdict->v.waterlevel != 3) // is bot NOT under water? + pEdict->v.v_angle.x = 0; // reset pitch to 0 (level horizontally) + + pEdict->v.v_angle.z = 0; // reset roll to 0 (straight up and down) + + pEdict->v.angles.x = 0; + pEdict->v.angles.y = pEdict->v.v_angle.y; + pEdict->v.angles.z = 0; + + // Stop following when person crouches + if (!IsAlive( pBot->pBotUser ) || (pBot->pBotUser->v.flags & FL_DUCKING)) + { + // the bot's user is dead! + pBot->pBotUser = NULL; + return FALSE; + } + + user_visible = FInViewCone( &vecEnd, pEdict ) && + FVisible( vecEnd, pEdict ); + + // check if the "user" is still visible or if the user has been visible + // in the last 5 seconds (or the player just starting "using" the bot) + + if (user_visible || (pBot->f_bot_use_time + 5 > gpGlobals->time)) + { + if (user_visible) + pBot->f_bot_use_time = gpGlobals->time; // reset "last visible time" + + // face the user + Vector v_user = pBot->pBotUser->v.origin - pEdict->v.origin; + Vector bot_angles = UTIL_VecToAngles( v_user ); + + pEdict->v.ideal_yaw = bot_angles.y; + + BotFixIdealYaw(pEdict); + + f_distance = v_user.Length( ); // how far away is the "user"? + + if (f_distance > 200) // run if distance to enemy is far + pBot->f_move_speed = pBot->f_max_speed; + else if (f_distance > 50) // walk if distance is closer + pBot->f_move_speed = pBot->f_max_speed / 2; + else // don't move if close enough + pBot->f_move_speed = 0.0; + + return TRUE; + } + else + { + // person to follow has gone out of sight... + pBot->pBotUser = NULL; + + return FALSE; + } +} + + +bool BotCheckWallOnLeft( bot_t *pBot ) +{ + edict_t *pEdict = pBot->pEdict; + Vector v_src, v_left; + TraceResult tr; + + UTIL_MakeVectors( pEdict->v.v_angle ); + + // do a trace to the left... + + v_src = pEdict->v.origin; + v_left = v_src + gpGlobals->v_right * -40; // 40 units to the left + + UTIL_TraceLine( v_src, v_left, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // check if the trace hit something... + if (tr.flFraction < 1.0) + { + if (pBot->f_wall_on_left < 1.0) + pBot->f_wall_on_left = gpGlobals->time; + + return TRUE; + } + + return FALSE; +} + + +bool BotCheckWallOnRight( bot_t *pBot ) +{ + edict_t *pEdict = pBot->pEdict; + Vector v_src, v_right; + TraceResult tr; + + UTIL_MakeVectors( pEdict->v.v_angle ); + + // do a trace to the right... + + v_src = pEdict->v.origin; + v_right = v_src + gpGlobals->v_right * 40; // 40 units to the right + + UTIL_TraceLine( v_src, v_right, dont_ignore_monsters, + pEdict->v.pContainingEntity, &tr); + + // check if the trace hit something... + if (tr.flFraction < 1.0) + { + if (pBot->f_wall_on_right < 1.0) + pBot->f_wall_on_right = gpGlobals->time; + + return TRUE; + } + + return FALSE; +} + diff --git a/main/source/HPB_bot/dlls/bot_start.cpp b/main/source/HPB_bot/dlls/bot_start.cpp index 203b259f..f91863fd 100644 --- a/main/source/HPB_bot/dlls/bot_start.cpp +++ b/main/source/HPB_bot/dlls/bot_start.cpp @@ -1,813 +1,813 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_start.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" -#include "bot_func.h" -#include "bot_weapons.h" -#include "mod/AvHMessage.h" - -extern int mod_id; -extern edict_t *pent_info_ctfdetect; - -extern int max_team_players[4]; -extern int team_class_limits[4]; -extern int max_teams; - - -void BotStartGame( bot_t *pBot ) -{ - char c_team[32]; - char c_class[32]; - char c_item[32]; - int index, count, retry_count; - edict_t *pPlayer; - int team; - int class_not_allowed; - - edict_t *pEdict = pBot->pEdict; - - //CBaseEntity* theEntity = CBaseEntity::Instance(pEdict); - //AvHPlayer* thePlayer = dynamic_cast(theEntity); - - if (mod_id == TFC_DLL) - { - if ((pBot->start_action == MSG_TFC_IDLE) && - (pBot->create_time + 3.0 <= gpGlobals->time)) - { - pBot->start_action = MSG_TFC_TEAM_SELECT; // force team selection - } - - // handle Team Fortress Classic stuff here... - - if (pBot->start_action == MSG_TFC_TEAM_SELECT) - { - pBot->start_action = MSG_TFC_IDLE; // switch back to idle - pBot->create_time = gpGlobals->time; // reset - - if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && - (pBot->bot_team != 3) && (pBot->bot_team != 4) && - (pBot->bot_team != 5)) - pBot->bot_team = -1; - - if (pBot->bot_team == -1) - pBot->bot_team = RANDOM_LONG(1, max_teams); - - retry_count = 0; - - while ((retry_count < 4) && - (max_team_players[pBot->bot_team-1] > 0)) // not unlimited? - { - count = 0; - - // count number of players on this team... - for (index = 1; index <= gpGlobals->maxClients; index++) - { - pPlayer = INDEXENT(index); - - if (pPlayer && !pPlayer->free) - { - if (UTIL_GetTeam(pPlayer) == (pBot->bot_team - 1)) - count++; - } - } - - if (count < max_team_players[pBot->bot_team-1]) - break; // haven't reached limit yet, continue - else - { - pBot->bot_team++; - - if (pBot->bot_team > max_teams) - pBot->bot_team = 1; - - retry_count++; - } - } - - // select the team the bot wishes to join... - if (pBot->bot_team == 1) - strcpy(c_team, "1"); - else if (pBot->bot_team == 2) - strcpy(c_team, "2"); - else if (pBot->bot_team == 3) - strcpy(c_team, "3"); - else if (pBot->bot_team == 4) - strcpy(c_team, "4"); - else - strcpy(c_team, "5"); - - FakeClientCommand(pEdict, "jointeam", c_team, NULL); - - return; - } - - if (pBot->start_action == MSG_TFC_CLASS_SELECT) - { - pBot->start_action = MSG_TFC_IDLE; // switch back to idle - pBot->create_time = gpGlobals->time; // reset - - if ((pBot->bot_class < 0) || (pBot->bot_class > 10)) - pBot->bot_class = -1; - - if (pBot->bot_class == -1) - pBot->bot_class = RANDOM_LONG(1, 10); - - team = UTIL_GetTeam(pEdict); - - if (team_class_limits[team] == -1) // civilian only? - { - pBot->bot_class = 0; // civilian - } - else - { - if (pBot->bot_class == 10) - class_not_allowed = team_class_limits[team] & (1<<7); - else if (pBot->bot_class <= 7) - class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class-1)); - else - class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class)); - - while (class_not_allowed) - { - pBot->bot_class = RANDOM_LONG(1, 10); - - if (pBot->bot_class == 10) - class_not_allowed = team_class_limits[team] & (1<<7); - else if (pBot->bot_class <= 7) - class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class-1)); - else - class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class)); - } - } - - // select the class the bot wishes to use... - if (pBot->bot_class == 0) - strcpy(c_class, "civilian"); - else if (pBot->bot_class == 1) - strcpy(c_class, "scout"); - else if (pBot->bot_class == 2) - strcpy(c_class, "sniper"); - else if (pBot->bot_class == 3) - strcpy(c_class, "soldier"); - else if (pBot->bot_class == 4) - strcpy(c_class, "demoman"); - else if (pBot->bot_class == 5) - strcpy(c_class, "medic"); - else if (pBot->bot_class == 6) - strcpy(c_class, "hwguy"); - else if (pBot->bot_class == 7) - strcpy(c_class, "pyro"); - else if (pBot->bot_class == 8) - strcpy(c_class, "spy"); - else if (pBot->bot_class == 9) - strcpy(c_class, "engineer"); - else - strcpy(c_class, "randompc"); - - FakeClientCommand(pEdict, c_class, NULL, NULL); - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - - return; - } - } - else if (mod_id == CSTRIKE_DLL) - { - // handle Counter-Strike stuff here... - - if (pBot->start_action == MSG_CS_TEAM_SELECT) - { - pBot->start_action = MSG_CS_IDLE; // switch back to idle - - if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && - (pBot->bot_team != 5)) - pBot->bot_team = -1; - - if (pBot->bot_team == -1) - pBot->bot_team = RANDOM_LONG(1, 2); - - // select the team the bot wishes to join... - if (pBot->bot_team == 1) - strcpy(c_team, "1"); - else if (pBot->bot_team == 2) - strcpy(c_team, "2"); - else - strcpy(c_team, "5"); - - FakeClientCommand(pEdict, "menuselect", c_team, NULL); - - return; - } - - if (pBot->start_action == MSG_CS_CT_SELECT) // counter terrorist - { - pBot->start_action = MSG_CS_IDLE; // switch back to idle - - if ((pBot->bot_class < 1) || (pBot->bot_class > 4)) - pBot->bot_class = -1; // use random if invalid - - if (pBot->bot_class == -1) - pBot->bot_class = RANDOM_LONG(1, 4); - - // select the class the bot wishes to use... - if (pBot->bot_class == 1) - strcpy(c_class, "1"); - else if (pBot->bot_class == 2) - strcpy(c_class, "2"); - else if (pBot->bot_class == 3) - strcpy(c_class, "3"); - else if (pBot->bot_class == 4) - strcpy(c_class, "4"); - else - strcpy(c_class, "5"); // random - - FakeClientCommand(pEdict, "menuselect", c_class, NULL); - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - - return; - } - - if (pBot->start_action == MSG_CS_T_SELECT) // terrorist select - { - pBot->start_action = MSG_CS_IDLE; // switch back to idle - - if ((pBot->bot_class < 1) || (pBot->bot_class > 4)) - pBot->bot_class = -1; // use random if invalid - - if (pBot->bot_class == -1) - pBot->bot_class = RANDOM_LONG(1, 4); - - // select the class the bot wishes to use... - if (pBot->bot_class == 1) - strcpy(c_class, "1"); - else if (pBot->bot_class == 2) - strcpy(c_class, "2"); - else if (pBot->bot_class == 3) - strcpy(c_class, "3"); - else if (pBot->bot_class == 4) - strcpy(c_class, "4"); - else - strcpy(c_class, "5"); // random - - FakeClientCommand(pEdict, "menuselect", c_class, NULL); - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - - return; - } - } - else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) - { - // handle Opposing Force CTF stuff here... - - if (pBot->start_action == MSG_OPFOR_TEAM_SELECT) - { - pBot->start_action = MSG_OPFOR_IDLE; // switch back to idle - - if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && - (pBot->bot_team != 3)) - pBot->bot_team = -1; - - if (pBot->bot_team == -1) - pBot->bot_team = RANDOM_LONG(1, 2); - - // select the team the bot wishes to join... - if (pBot->bot_team == 1) - strcpy(c_team, "1"); - else if (pBot->bot_team == 2) - strcpy(c_team, "2"); - else - strcpy(c_team, "3"); - - FakeClientCommand(pEdict, "jointeam", c_team, NULL); - - return; - } - - if (pBot->start_action == MSG_OPFOR_CLASS_SELECT) - { - pBot->start_action = MSG_OPFOR_IDLE; // switch back to idle - - if ((pBot->bot_class < 0) || (pBot->bot_class > 10)) - pBot->bot_class = -1; - - if (pBot->bot_class == -1) - pBot->bot_class = RANDOM_LONG(1, 10); - - // select the class the bot wishes to use... - if (pBot->bot_class == 1) - strcpy(c_class, "1"); - else if (pBot->bot_class == 2) - strcpy(c_class, "2"); - else if (pBot->bot_class == 3) - strcpy(c_class, "3"); - else if (pBot->bot_class == 4) - strcpy(c_class, "4"); - else if (pBot->bot_class == 5) - strcpy(c_class, "5"); - else if (pBot->bot_class == 6) - strcpy(c_class, "6"); - else - strcpy(c_class, "7"); - - FakeClientCommand(pEdict, "selectchar", c_class, NULL); - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - - return; - } - } - else if (mod_id == FRONTLINE_DLL) - { - // handle FrontLineForce stuff here... - - if (pBot->start_action == MSG_FLF_TEAM_SELECT) - { - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && - (pBot->bot_team != 5)) - pBot->bot_team = -1; - - if (pBot->bot_team == -1) - pBot->bot_team = RANDOM_LONG(1, 2); - - // select the team the bot wishes to join... - if (pBot->bot_team == 1) - strcpy(c_team, "1"); - else if (pBot->bot_team == 2) - strcpy(c_team, "2"); - else - strcpy(c_team, "5"); - - FakeClientCommand(pEdict, "jointeam", c_team, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_CLASS_SELECT) - { - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - team = UTIL_GetTeam(pEdict); - - if (team == 0) // rebels - { - if ((pBot->bot_class < 0) || (pBot->bot_class > 3)) - pBot->bot_class = -1; - - if (pBot->bot_class == -1) - pBot->bot_class = RANDOM_LONG(1, 3); - - // select the class the bot wishes to use... - if (pBot->bot_class == 1) - strcpy(c_class, "rebelsrecon"); - else if (pBot->bot_class == 2) - strcpy(c_class, "rebelsassault"); - else - strcpy(c_class, "rebelssupport"); - } - else // commandos - { - if ((pBot->bot_class < 0) || (pBot->bot_class > 3)) - pBot->bot_class = -1; - - if (pBot->bot_class == -1) - pBot->bot_class = RANDOM_LONG(1, 3); - - // select the class the bot wishes to use... - if (pBot->bot_class == 1) - strcpy(c_class, "commandosrecon"); - else if (pBot->bot_class == 2) - strcpy(c_class, "commandosassault"); - else - strcpy(c_class, "commandossupport"); - } - - FakeClientCommand(pEdict, c_class, NULL, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_PISTOL_SELECT) - { - int prim_weapon_group, sec_weapon_group; - - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - int flf_class = UTIL_GetClass(pEdict); - - if (flf_class == 0) // recon - { - prim_weapon_group = RANDOM_LONG(1, 3); - - if (prim_weapon_group == 1) // shotguns - pBot->primary_weapon = FLF_WEAPON_SPAS12; - else if (prim_weapon_group == 2) // submachine - { - int weapon = RANDOM_LONG(1, 4); - - if (weapon == 1) - pBot->primary_weapon = FLF_WEAPON_MP5A2; - else if (weapon == 2) - pBot->primary_weapon = FLF_WEAPON_MP5SD; - else if (weapon == 3) - pBot->primary_weapon = FLF_WEAPON_MAC10; - else - pBot->primary_weapon = FLF_WEAPON_UMP45; - } - else // rifles - { - pBot->primary_weapon = FLF_WEAPON_MSG90; - } - - if (prim_weapon_group == 1) - sec_weapon_group = RANDOM_LONG(2, 3); - else if (prim_weapon_group == 3) - sec_weapon_group = RANDOM_LONG(1, 2); - else - { - if (RANDOM_LONG(1, 100) <= 50) - sec_weapon_group = 1; - else - sec_weapon_group = 3; - } - - if (sec_weapon_group == 1) // shotguns - pBot->secondary_weapon = FLF_WEAPON_SPAS12; - else if (sec_weapon_group == 2) // submachine - { - int weapon = RANDOM_LONG(1, 4); - - if (weapon == 1) - pBot->secondary_weapon = FLF_WEAPON_MP5A2; - else if (weapon == 2) - pBot->secondary_weapon = FLF_WEAPON_MP5SD; - else if (weapon == 3) - pBot->secondary_weapon = FLF_WEAPON_MAC10; - else - pBot->secondary_weapon = FLF_WEAPON_UMP45; - } - else // rifles - { - pBot->secondary_weapon = FLF_WEAPON_MSG90; - } - } - else if (flf_class == 1) // assault - { - prim_weapon_group = RANDOM_LONG(1, 3); - - if (prim_weapon_group == 1) // shotguns - pBot->primary_weapon = FLF_WEAPON_SPAS12; - else if (prim_weapon_group == 2) // submachine - { - int weapon = RANDOM_LONG(1, 4); - - if (weapon == 1) - pBot->primary_weapon = FLF_WEAPON_MP5A2; - else if (weapon == 2) - pBot->primary_weapon = FLF_WEAPON_MP5SD; - else if (weapon == 3) - pBot->primary_weapon = FLF_WEAPON_MAC10; - else - pBot->primary_weapon = FLF_WEAPON_UMP45; - } - else // rifles - { - int weapon = RANDOM_LONG(1, 3); - - if (weapon == 1) - pBot->primary_weapon = FLF_WEAPON_M4; - else if (weapon == 2) - pBot->primary_weapon = FLF_WEAPON_FAMAS; - else - pBot->primary_weapon = FLF_WEAPON_AK5; - } - - if (prim_weapon_group == 1) - sec_weapon_group = RANDOM_LONG(2, 3); - else if (prim_weapon_group == 2) - { - if (RANDOM_LONG(1, 100) <= 50) - sec_weapon_group = 1; - else - sec_weapon_group = 3; - } - else // prim == 3 - sec_weapon_group = RANDOM_LONG(1, 2); - - if (sec_weapon_group == 1) // shotguns - pBot->secondary_weapon = FLF_WEAPON_SPAS12; - else if (sec_weapon_group == 2) // submachine - { - int weapon = RANDOM_LONG(1, 4); - - if (weapon == 1) - pBot->secondary_weapon = FLF_WEAPON_MP5A2; - else if (weapon == 2) - pBot->secondary_weapon = FLF_WEAPON_MP5SD; - else if (weapon == 3) - pBot->secondary_weapon = FLF_WEAPON_MAC10; - else - pBot->secondary_weapon = FLF_WEAPON_UMP45; - } - else // rifles - { - int weapon = RANDOM_LONG(1, 3); - - if (weapon == 1) - pBot->secondary_weapon = FLF_WEAPON_M4; - else if (weapon == 2) - pBot->secondary_weapon = FLF_WEAPON_FAMAS; - else - pBot->secondary_weapon = FLF_WEAPON_AK5; - } - } - else // support - { - prim_weapon_group = RANDOM_LONG(1, 3); - - if (prim_weapon_group == 1) // shotguns - pBot->primary_weapon = FLF_WEAPON_SPAS12; - else if (prim_weapon_group == 2) // submachine - { - int weapon = RANDOM_LONG(1, 4); - - if (weapon == 1) - pBot->primary_weapon = FLF_WEAPON_MP5A2; - else if (weapon == 2) - pBot->primary_weapon = FLF_WEAPON_MP5SD; - else if (weapon == 3) - pBot->primary_weapon = FLF_WEAPON_MAC10; - else - pBot->primary_weapon = FLF_WEAPON_UMP45; - } - else if (prim_weapon_group == 3) // rifles & heavyweapons - { - if (RANDOM_LONG(1, 100) <= 50) - { - int weapon = RANDOM_LONG(1, 3); // rifles - - if (weapon == 1) - pBot->primary_weapon = FLF_WEAPON_M4; - else if (weapon == 2) - pBot->primary_weapon = FLF_WEAPON_FAMAS; - else - pBot->primary_weapon = FLF_WEAPON_AK5; - } - else // heavy weapons - { - pBot->primary_weapon = FLF_WEAPON_HK21; - } - } - - if (prim_weapon_group == 1) - sec_weapon_group = RANDOM_LONG(2, 3); - else if (prim_weapon_group == 2) - { - if (RANDOM_LONG(1, 100) <= 50) - sec_weapon_group = 1; - else - sec_weapon_group = 3; - } - else // prim == 3 - sec_weapon_group = RANDOM_LONG(1, 2); - - if (sec_weapon_group == 1) // shotguns - pBot->secondary_weapon = FLF_WEAPON_SPAS12; - else if (sec_weapon_group == 2) // submachine - { - int weapon = RANDOM_LONG(1, 4); - - if (weapon == 1) - pBot->secondary_weapon = FLF_WEAPON_MP5A2; - else if (weapon == 2) - pBot->secondary_weapon = FLF_WEAPON_MP5SD; - else if (weapon == 3) - pBot->secondary_weapon = FLF_WEAPON_MAC10; - else - pBot->secondary_weapon = FLF_WEAPON_UMP45; - } - else if (sec_weapon_group == 3) // rifles & heavyweapons - { - if (RANDOM_LONG(1, 100) <= 50) - { - int weapon = RANDOM_LONG(1, 3); // rifles - - if (weapon == 1) - pBot->secondary_weapon = FLF_WEAPON_M4; - else if (weapon == 2) - pBot->secondary_weapon = FLF_WEAPON_FAMAS; - else - pBot->secondary_weapon = FLF_WEAPON_AK5; - } - else // heavy weapons - { - pBot->secondary_weapon = FLF_WEAPON_HK21; - } - } - } - - int pistol = RANDOM_LONG(1, 2); - - if (pistol == 1) - strcpy(c_item, "26"); // mk23 - else - strcpy(c_item, "23"); // beretta - - FakeClientCommand(pEdict, "pistols", c_item, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_WEAPON_SELECT) - { - int weapon_class; - - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - if (pBot->primary_weapon) - weapon_class = pBot->primary_weapon; - else - weapon_class = pBot->secondary_weapon; - - if (weapon_class == FLF_WEAPON_SPAS12) // shotguns - strcpy(c_item, "shotgun"); - else if ((weapon_class == FLF_WEAPON_MP5A2) || // submachine - (weapon_class == FLF_WEAPON_MP5SD) || - (weapon_class == FLF_WEAPON_MAC10) || - (weapon_class == FLF_WEAPON_UMP45)) - strcpy(c_item, "submachine"); - else if ((weapon_class == FLF_WEAPON_M4) || - (weapon_class == FLF_WEAPON_FAMAS) || - (weapon_class == FLF_WEAPON_AK5) || - (weapon_class == FLF_WEAPON_MSG90)) - strcpy(c_item, "rifles"); - else - strcpy(c_item, "heavyweapons"); - - FakeClientCommand(pEdict, "wpnclass", c_item, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_SHOTGUN_SELECT) - { - int weapon_class; - - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - if (pBot->primary_weapon) - { - weapon_class = pBot->primary_weapon; - pBot->primary_weapon = 0; - } - else - { - weapon_class = pBot->secondary_weapon; - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - } - - sprintf(c_item, "%d", weapon_class); - - FakeClientCommand(pEdict, "shotgun", c_item, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_SUBMACHINE_SELECT) - { - int weapon_class; - - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - if (pBot->primary_weapon) - { - weapon_class = pBot->primary_weapon; - pBot->primary_weapon = 0; - } - else - { - weapon_class = pBot->secondary_weapon; - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - } - - sprintf(c_item, "%d", weapon_class); - - FakeClientCommand(pEdict, "submach", c_item, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_RIFLE_SELECT) - { - int weapon_class; - - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - if (pBot->primary_weapon) - { - weapon_class = pBot->primary_weapon; - pBot->primary_weapon = 0; - } - else - { - weapon_class = pBot->secondary_weapon; - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - } - - sprintf(c_item, "%d", weapon_class); - - FakeClientCommand(pEdict, "rifles", c_item, NULL); - - return; - } - - if (pBot->start_action == MSG_FLF_HEAVYWEAPONS_SELECT) - { - int weapon_class; - - pBot->start_action = MSG_FLF_IDLE; // switch back to idle - - if (pBot->primary_weapon) - { - weapon_class = pBot->primary_weapon; - pBot->primary_weapon = 0; - } - else - { - weapon_class = pBot->secondary_weapon; - - // bot has now joined the game (doesn't need to be started) - pBot->not_started = 0; - } - - sprintf(c_item, "%d", weapon_class); - - FakeClientCommand(pEdict, "heavyweapons", c_item, NULL); - - return; - } - - } - else if (mod_id == AVH_DLL) - { -// if(pBot->mBotPlayMode == PLAYMODE_READYROOM) -// { -// // Look at desired team and head to nearest start entity -// AvHClassType theClassType = AVH_CLASS_TYPE_UNDEFINED; -//// if(pBot->mBotRole == ROLE_UNDEFINED) -//// { -//// // Choose a random team -//// theClassType = AvHClassType(RANDOM_LONG(1, 2)); -//// } -//// else -//// { -//// theClassType = (AvHClassType)pBot->mBotRole; -//// } -//// -//// // Now navigate to the nearest start entity -//// if(theClassType == AVH_CLASS_TYPE_MARINE) -//// { -// FakeClientCommand(pEdict, kcAutoAssign, c_item, NULL); -// //FakeClientCommand(pEdict, kcJoinTeamOne, c_item, NULL); -// -// // Try to become a squad leader if possible -//// pBot->pEdict->v.impulse = RANK_PROMOTE; -//// } -//// else if(theClassType == AVH_CLASS_TYPE_ALIEN) -//// { -//// FakeClientCommand(pEdict, kcJoinTeamTwo, c_item, NULL); -//// } -// -// // bot has now joined the game (doesn't need to be started) -// pBot->not_started = 0; -// } - } - else - { - // otherwise, don't need to do anything to start game... - pBot->not_started = 0; - } -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_start.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" +#include "bot_func.h" +#include "bot_weapons.h" +#include "mod/AvHMessage.h" + +extern int mod_id; +extern edict_t *pent_info_ctfdetect; + +extern int max_team_players[4]; +extern int team_class_limits[4]; +extern int max_teams; + + +void BotStartGame( bot_t *pBot ) +{ + char c_team[32]; + char c_class[32]; + char c_item[32]; + int index, count, retry_count; + edict_t *pPlayer; + int team; + int class_not_allowed; + + edict_t *pEdict = pBot->pEdict; + + //CBaseEntity* theEntity = CBaseEntity::Instance(pEdict); + //AvHPlayer* thePlayer = dynamic_cast(theEntity); + + if (mod_id == TFC_DLL) + { + if ((pBot->start_action == MSG_TFC_IDLE) && + (pBot->create_time + 3.0 <= gpGlobals->time)) + { + pBot->start_action = MSG_TFC_TEAM_SELECT; // force team selection + } + + // handle Team Fortress Classic stuff here... + + if (pBot->start_action == MSG_TFC_TEAM_SELECT) + { + pBot->start_action = MSG_TFC_IDLE; // switch back to idle + pBot->create_time = gpGlobals->time; // reset + + if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && + (pBot->bot_team != 3) && (pBot->bot_team != 4) && + (pBot->bot_team != 5)) + pBot->bot_team = -1; + + if (pBot->bot_team == -1) + pBot->bot_team = RANDOM_LONG(1, max_teams); + + retry_count = 0; + + while ((retry_count < 4) && + (max_team_players[pBot->bot_team-1] > 0)) // not unlimited? + { + count = 0; + + // count number of players on this team... + for (index = 1; index <= gpGlobals->maxClients; index++) + { + pPlayer = INDEXENT(index); + + if (pPlayer && !pPlayer->free) + { + if (UTIL_GetTeam(pPlayer) == (pBot->bot_team - 1)) + count++; + } + } + + if (count < max_team_players[pBot->bot_team-1]) + break; // haven't reached limit yet, continue + else + { + pBot->bot_team++; + + if (pBot->bot_team > max_teams) + pBot->bot_team = 1; + + retry_count++; + } + } + + // select the team the bot wishes to join... + if (pBot->bot_team == 1) + strcpy(c_team, "1"); + else if (pBot->bot_team == 2) + strcpy(c_team, "2"); + else if (pBot->bot_team == 3) + strcpy(c_team, "3"); + else if (pBot->bot_team == 4) + strcpy(c_team, "4"); + else + strcpy(c_team, "5"); + + FakeClientCommand(pEdict, "jointeam", c_team, NULL); + + return; + } + + if (pBot->start_action == MSG_TFC_CLASS_SELECT) + { + pBot->start_action = MSG_TFC_IDLE; // switch back to idle + pBot->create_time = gpGlobals->time; // reset + + if ((pBot->bot_class < 0) || (pBot->bot_class > 10)) + pBot->bot_class = -1; + + if (pBot->bot_class == -1) + pBot->bot_class = RANDOM_LONG(1, 10); + + team = UTIL_GetTeam(pEdict); + + if (team_class_limits[team] == -1) // civilian only? + { + pBot->bot_class = 0; // civilian + } + else + { + if (pBot->bot_class == 10) + class_not_allowed = team_class_limits[team] & (1<<7); + else if (pBot->bot_class <= 7) + class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class-1)); + else + class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class)); + + while (class_not_allowed) + { + pBot->bot_class = RANDOM_LONG(1, 10); + + if (pBot->bot_class == 10) + class_not_allowed = team_class_limits[team] & (1<<7); + else if (pBot->bot_class <= 7) + class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class-1)); + else + class_not_allowed = team_class_limits[team] & (1<<(pBot->bot_class)); + } + } + + // select the class the bot wishes to use... + if (pBot->bot_class == 0) + strcpy(c_class, "civilian"); + else if (pBot->bot_class == 1) + strcpy(c_class, "scout"); + else if (pBot->bot_class == 2) + strcpy(c_class, "sniper"); + else if (pBot->bot_class == 3) + strcpy(c_class, "soldier"); + else if (pBot->bot_class == 4) + strcpy(c_class, "demoman"); + else if (pBot->bot_class == 5) + strcpy(c_class, "medic"); + else if (pBot->bot_class == 6) + strcpy(c_class, "hwguy"); + else if (pBot->bot_class == 7) + strcpy(c_class, "pyro"); + else if (pBot->bot_class == 8) + strcpy(c_class, "spy"); + else if (pBot->bot_class == 9) + strcpy(c_class, "engineer"); + else + strcpy(c_class, "randompc"); + + FakeClientCommand(pEdict, c_class, NULL, NULL); + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + + return; + } + } + else if (mod_id == CSTRIKE_DLL) + { + // handle Counter-Strike stuff here... + + if (pBot->start_action == MSG_CS_TEAM_SELECT) + { + pBot->start_action = MSG_CS_IDLE; // switch back to idle + + if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && + (pBot->bot_team != 5)) + pBot->bot_team = -1; + + if (pBot->bot_team == -1) + pBot->bot_team = RANDOM_LONG(1, 2); + + // select the team the bot wishes to join... + if (pBot->bot_team == 1) + strcpy(c_team, "1"); + else if (pBot->bot_team == 2) + strcpy(c_team, "2"); + else + strcpy(c_team, "5"); + + FakeClientCommand(pEdict, "menuselect", c_team, NULL); + + return; + } + + if (pBot->start_action == MSG_CS_CT_SELECT) // counter terrorist + { + pBot->start_action = MSG_CS_IDLE; // switch back to idle + + if ((pBot->bot_class < 1) || (pBot->bot_class > 4)) + pBot->bot_class = -1; // use random if invalid + + if (pBot->bot_class == -1) + pBot->bot_class = RANDOM_LONG(1, 4); + + // select the class the bot wishes to use... + if (pBot->bot_class == 1) + strcpy(c_class, "1"); + else if (pBot->bot_class == 2) + strcpy(c_class, "2"); + else if (pBot->bot_class == 3) + strcpy(c_class, "3"); + else if (pBot->bot_class == 4) + strcpy(c_class, "4"); + else + strcpy(c_class, "5"); // random + + FakeClientCommand(pEdict, "menuselect", c_class, NULL); + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + + return; + } + + if (pBot->start_action == MSG_CS_T_SELECT) // terrorist select + { + pBot->start_action = MSG_CS_IDLE; // switch back to idle + + if ((pBot->bot_class < 1) || (pBot->bot_class > 4)) + pBot->bot_class = -1; // use random if invalid + + if (pBot->bot_class == -1) + pBot->bot_class = RANDOM_LONG(1, 4); + + // select the class the bot wishes to use... + if (pBot->bot_class == 1) + strcpy(c_class, "1"); + else if (pBot->bot_class == 2) + strcpy(c_class, "2"); + else if (pBot->bot_class == 3) + strcpy(c_class, "3"); + else if (pBot->bot_class == 4) + strcpy(c_class, "4"); + else + strcpy(c_class, "5"); // random + + FakeClientCommand(pEdict, "menuselect", c_class, NULL); + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + + return; + } + } + else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) + { + // handle Opposing Force CTF stuff here... + + if (pBot->start_action == MSG_OPFOR_TEAM_SELECT) + { + pBot->start_action = MSG_OPFOR_IDLE; // switch back to idle + + if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && + (pBot->bot_team != 3)) + pBot->bot_team = -1; + + if (pBot->bot_team == -1) + pBot->bot_team = RANDOM_LONG(1, 2); + + // select the team the bot wishes to join... + if (pBot->bot_team == 1) + strcpy(c_team, "1"); + else if (pBot->bot_team == 2) + strcpy(c_team, "2"); + else + strcpy(c_team, "3"); + + FakeClientCommand(pEdict, "jointeam", c_team, NULL); + + return; + } + + if (pBot->start_action == MSG_OPFOR_CLASS_SELECT) + { + pBot->start_action = MSG_OPFOR_IDLE; // switch back to idle + + if ((pBot->bot_class < 0) || (pBot->bot_class > 10)) + pBot->bot_class = -1; + + if (pBot->bot_class == -1) + pBot->bot_class = RANDOM_LONG(1, 10); + + // select the class the bot wishes to use... + if (pBot->bot_class == 1) + strcpy(c_class, "1"); + else if (pBot->bot_class == 2) + strcpy(c_class, "2"); + else if (pBot->bot_class == 3) + strcpy(c_class, "3"); + else if (pBot->bot_class == 4) + strcpy(c_class, "4"); + else if (pBot->bot_class == 5) + strcpy(c_class, "5"); + else if (pBot->bot_class == 6) + strcpy(c_class, "6"); + else + strcpy(c_class, "7"); + + FakeClientCommand(pEdict, "selectchar", c_class, NULL); + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + + return; + } + } + else if (mod_id == FRONTLINE_DLL) + { + // handle FrontLineForce stuff here... + + if (pBot->start_action == MSG_FLF_TEAM_SELECT) + { + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + if ((pBot->bot_team != 1) && (pBot->bot_team != 2) && + (pBot->bot_team != 5)) + pBot->bot_team = -1; + + if (pBot->bot_team == -1) + pBot->bot_team = RANDOM_LONG(1, 2); + + // select the team the bot wishes to join... + if (pBot->bot_team == 1) + strcpy(c_team, "1"); + else if (pBot->bot_team == 2) + strcpy(c_team, "2"); + else + strcpy(c_team, "5"); + + FakeClientCommand(pEdict, "jointeam", c_team, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_CLASS_SELECT) + { + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + team = UTIL_GetTeam(pEdict); + + if (team == 0) // rebels + { + if ((pBot->bot_class < 0) || (pBot->bot_class > 3)) + pBot->bot_class = -1; + + if (pBot->bot_class == -1) + pBot->bot_class = RANDOM_LONG(1, 3); + + // select the class the bot wishes to use... + if (pBot->bot_class == 1) + strcpy(c_class, "rebelsrecon"); + else if (pBot->bot_class == 2) + strcpy(c_class, "rebelsassault"); + else + strcpy(c_class, "rebelssupport"); + } + else // commandos + { + if ((pBot->bot_class < 0) || (pBot->bot_class > 3)) + pBot->bot_class = -1; + + if (pBot->bot_class == -1) + pBot->bot_class = RANDOM_LONG(1, 3); + + // select the class the bot wishes to use... + if (pBot->bot_class == 1) + strcpy(c_class, "commandosrecon"); + else if (pBot->bot_class == 2) + strcpy(c_class, "commandosassault"); + else + strcpy(c_class, "commandossupport"); + } + + FakeClientCommand(pEdict, c_class, NULL, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_PISTOL_SELECT) + { + int prim_weapon_group, sec_weapon_group; + + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + int flf_class = UTIL_GetClass(pEdict); + + if (flf_class == 0) // recon + { + prim_weapon_group = RANDOM_LONG(1, 3); + + if (prim_weapon_group == 1) // shotguns + pBot->primary_weapon = FLF_WEAPON_SPAS12; + else if (prim_weapon_group == 2) // submachine + { + int weapon = RANDOM_LONG(1, 4); + + if (weapon == 1) + pBot->primary_weapon = FLF_WEAPON_MP5A2; + else if (weapon == 2) + pBot->primary_weapon = FLF_WEAPON_MP5SD; + else if (weapon == 3) + pBot->primary_weapon = FLF_WEAPON_MAC10; + else + pBot->primary_weapon = FLF_WEAPON_UMP45; + } + else // rifles + { + pBot->primary_weapon = FLF_WEAPON_MSG90; + } + + if (prim_weapon_group == 1) + sec_weapon_group = RANDOM_LONG(2, 3); + else if (prim_weapon_group == 3) + sec_weapon_group = RANDOM_LONG(1, 2); + else + { + if (RANDOM_LONG(1, 100) <= 50) + sec_weapon_group = 1; + else + sec_weapon_group = 3; + } + + if (sec_weapon_group == 1) // shotguns + pBot->secondary_weapon = FLF_WEAPON_SPAS12; + else if (sec_weapon_group == 2) // submachine + { + int weapon = RANDOM_LONG(1, 4); + + if (weapon == 1) + pBot->secondary_weapon = FLF_WEAPON_MP5A2; + else if (weapon == 2) + pBot->secondary_weapon = FLF_WEAPON_MP5SD; + else if (weapon == 3) + pBot->secondary_weapon = FLF_WEAPON_MAC10; + else + pBot->secondary_weapon = FLF_WEAPON_UMP45; + } + else // rifles + { + pBot->secondary_weapon = FLF_WEAPON_MSG90; + } + } + else if (flf_class == 1) // assault + { + prim_weapon_group = RANDOM_LONG(1, 3); + + if (prim_weapon_group == 1) // shotguns + pBot->primary_weapon = FLF_WEAPON_SPAS12; + else if (prim_weapon_group == 2) // submachine + { + int weapon = RANDOM_LONG(1, 4); + + if (weapon == 1) + pBot->primary_weapon = FLF_WEAPON_MP5A2; + else if (weapon == 2) + pBot->primary_weapon = FLF_WEAPON_MP5SD; + else if (weapon == 3) + pBot->primary_weapon = FLF_WEAPON_MAC10; + else + pBot->primary_weapon = FLF_WEAPON_UMP45; + } + else // rifles + { + int weapon = RANDOM_LONG(1, 3); + + if (weapon == 1) + pBot->primary_weapon = FLF_WEAPON_M4; + else if (weapon == 2) + pBot->primary_weapon = FLF_WEAPON_FAMAS; + else + pBot->primary_weapon = FLF_WEAPON_AK5; + } + + if (prim_weapon_group == 1) + sec_weapon_group = RANDOM_LONG(2, 3); + else if (prim_weapon_group == 2) + { + if (RANDOM_LONG(1, 100) <= 50) + sec_weapon_group = 1; + else + sec_weapon_group = 3; + } + else // prim == 3 + sec_weapon_group = RANDOM_LONG(1, 2); + + if (sec_weapon_group == 1) // shotguns + pBot->secondary_weapon = FLF_WEAPON_SPAS12; + else if (sec_weapon_group == 2) // submachine + { + int weapon = RANDOM_LONG(1, 4); + + if (weapon == 1) + pBot->secondary_weapon = FLF_WEAPON_MP5A2; + else if (weapon == 2) + pBot->secondary_weapon = FLF_WEAPON_MP5SD; + else if (weapon == 3) + pBot->secondary_weapon = FLF_WEAPON_MAC10; + else + pBot->secondary_weapon = FLF_WEAPON_UMP45; + } + else // rifles + { + int weapon = RANDOM_LONG(1, 3); + + if (weapon == 1) + pBot->secondary_weapon = FLF_WEAPON_M4; + else if (weapon == 2) + pBot->secondary_weapon = FLF_WEAPON_FAMAS; + else + pBot->secondary_weapon = FLF_WEAPON_AK5; + } + } + else // support + { + prim_weapon_group = RANDOM_LONG(1, 3); + + if (prim_weapon_group == 1) // shotguns + pBot->primary_weapon = FLF_WEAPON_SPAS12; + else if (prim_weapon_group == 2) // submachine + { + int weapon = RANDOM_LONG(1, 4); + + if (weapon == 1) + pBot->primary_weapon = FLF_WEAPON_MP5A2; + else if (weapon == 2) + pBot->primary_weapon = FLF_WEAPON_MP5SD; + else if (weapon == 3) + pBot->primary_weapon = FLF_WEAPON_MAC10; + else + pBot->primary_weapon = FLF_WEAPON_UMP45; + } + else if (prim_weapon_group == 3) // rifles & heavyweapons + { + if (RANDOM_LONG(1, 100) <= 50) + { + int weapon = RANDOM_LONG(1, 3); // rifles + + if (weapon == 1) + pBot->primary_weapon = FLF_WEAPON_M4; + else if (weapon == 2) + pBot->primary_weapon = FLF_WEAPON_FAMAS; + else + pBot->primary_weapon = FLF_WEAPON_AK5; + } + else // heavy weapons + { + pBot->primary_weapon = FLF_WEAPON_HK21; + } + } + + if (prim_weapon_group == 1) + sec_weapon_group = RANDOM_LONG(2, 3); + else if (prim_weapon_group == 2) + { + if (RANDOM_LONG(1, 100) <= 50) + sec_weapon_group = 1; + else + sec_weapon_group = 3; + } + else // prim == 3 + sec_weapon_group = RANDOM_LONG(1, 2); + + if (sec_weapon_group == 1) // shotguns + pBot->secondary_weapon = FLF_WEAPON_SPAS12; + else if (sec_weapon_group == 2) // submachine + { + int weapon = RANDOM_LONG(1, 4); + + if (weapon == 1) + pBot->secondary_weapon = FLF_WEAPON_MP5A2; + else if (weapon == 2) + pBot->secondary_weapon = FLF_WEAPON_MP5SD; + else if (weapon == 3) + pBot->secondary_weapon = FLF_WEAPON_MAC10; + else + pBot->secondary_weapon = FLF_WEAPON_UMP45; + } + else if (sec_weapon_group == 3) // rifles & heavyweapons + { + if (RANDOM_LONG(1, 100) <= 50) + { + int weapon = RANDOM_LONG(1, 3); // rifles + + if (weapon == 1) + pBot->secondary_weapon = FLF_WEAPON_M4; + else if (weapon == 2) + pBot->secondary_weapon = FLF_WEAPON_FAMAS; + else + pBot->secondary_weapon = FLF_WEAPON_AK5; + } + else // heavy weapons + { + pBot->secondary_weapon = FLF_WEAPON_HK21; + } + } + } + + int pistol = RANDOM_LONG(1, 2); + + if (pistol == 1) + strcpy(c_item, "26"); // mk23 + else + strcpy(c_item, "23"); // beretta + + FakeClientCommand(pEdict, "pistols", c_item, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_WEAPON_SELECT) + { + int weapon_class; + + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + if (pBot->primary_weapon) + weapon_class = pBot->primary_weapon; + else + weapon_class = pBot->secondary_weapon; + + if (weapon_class == FLF_WEAPON_SPAS12) // shotguns + strcpy(c_item, "shotgun"); + else if ((weapon_class == FLF_WEAPON_MP5A2) || // submachine + (weapon_class == FLF_WEAPON_MP5SD) || + (weapon_class == FLF_WEAPON_MAC10) || + (weapon_class == FLF_WEAPON_UMP45)) + strcpy(c_item, "submachine"); + else if ((weapon_class == FLF_WEAPON_M4) || + (weapon_class == FLF_WEAPON_FAMAS) || + (weapon_class == FLF_WEAPON_AK5) || + (weapon_class == FLF_WEAPON_MSG90)) + strcpy(c_item, "rifles"); + else + strcpy(c_item, "heavyweapons"); + + FakeClientCommand(pEdict, "wpnclass", c_item, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_SHOTGUN_SELECT) + { + int weapon_class; + + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + if (pBot->primary_weapon) + { + weapon_class = pBot->primary_weapon; + pBot->primary_weapon = 0; + } + else + { + weapon_class = pBot->secondary_weapon; + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + } + + sprintf(c_item, "%d", weapon_class); + + FakeClientCommand(pEdict, "shotgun", c_item, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_SUBMACHINE_SELECT) + { + int weapon_class; + + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + if (pBot->primary_weapon) + { + weapon_class = pBot->primary_weapon; + pBot->primary_weapon = 0; + } + else + { + weapon_class = pBot->secondary_weapon; + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + } + + sprintf(c_item, "%d", weapon_class); + + FakeClientCommand(pEdict, "submach", c_item, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_RIFLE_SELECT) + { + int weapon_class; + + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + if (pBot->primary_weapon) + { + weapon_class = pBot->primary_weapon; + pBot->primary_weapon = 0; + } + else + { + weapon_class = pBot->secondary_weapon; + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + } + + sprintf(c_item, "%d", weapon_class); + + FakeClientCommand(pEdict, "rifles", c_item, NULL); + + return; + } + + if (pBot->start_action == MSG_FLF_HEAVYWEAPONS_SELECT) + { + int weapon_class; + + pBot->start_action = MSG_FLF_IDLE; // switch back to idle + + if (pBot->primary_weapon) + { + weapon_class = pBot->primary_weapon; + pBot->primary_weapon = 0; + } + else + { + weapon_class = pBot->secondary_weapon; + + // bot has now joined the game (doesn't need to be started) + pBot->not_started = 0; + } + + sprintf(c_item, "%d", weapon_class); + + FakeClientCommand(pEdict, "heavyweapons", c_item, NULL); + + return; + } + + } + else if (mod_id == AVH_DLL) + { +// if(pBot->mBotPlayMode == PLAYMODE_READYROOM) +// { +// // Look at desired team and head to nearest start entity +// AvHClassType theClassType = AVH_CLASS_TYPE_UNDEFINED; +//// if(pBot->mBotRole == ROLE_UNDEFINED) +//// { +//// // Choose a random team +//// theClassType = AvHClassType(RANDOM_LONG(1, 2)); +//// } +//// else +//// { +//// theClassType = (AvHClassType)pBot->mBotRole; +//// } +//// +//// // Now navigate to the nearest start entity +//// if(theClassType == AVH_CLASS_TYPE_MARINE) +//// { +// FakeClientCommand(pEdict, kcAutoAssign, c_item, NULL); +// //FakeClientCommand(pEdict, kcJoinTeamOne, c_item, NULL); +// +// // Try to become a squad leader if possible +//// pBot->pEdict->v.impulse = RANK_PROMOTE; +//// } +//// else if(theClassType == AVH_CLASS_TYPE_ALIEN) +//// { +//// FakeClientCommand(pEdict, kcJoinTeamTwo, c_item, NULL); +//// } +// +// // bot has now joined the game (doesn't need to be started) +// pBot->not_started = 0; +// } + } + else + { + // otherwise, don't need to do anything to start game... + pBot->not_started = 0; + } +} + diff --git a/main/source/HPB_bot/dlls/bot_weapons.h b/main/source/HPB_bot/dlls/bot_weapons.h index 1c47d9db..afeb48a4 100644 --- a/main/source/HPB_bot/dlls/bot_weapons.h +++ b/main/source/HPB_bot/dlls/bot_weapons.h @@ -1,158 +1,158 @@ -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// bot_weapons.h -// - -#ifndef BOT_WEAPONS_H -#define BOT_WEAPONS_H - -// weapon ID values for Valve's Half-Life Deathmatch -#define VALVE_WEAPON_CROWBAR 1 -#define VALVE_WEAPON_GLOCK 2 -#define VALVE_WEAPON_PYTHON 3 -#define VALVE_WEAPON_MP5 4 -#define VALVE_WEAPON_CHAINGUN 5 -#define VALVE_WEAPON_CROSSBOW 6 -#define VALVE_WEAPON_SHOTGUN 7 -#define VALVE_WEAPON_RPG 8 -#define VALVE_WEAPON_GAUSS 9 -#define VALVE_WEAPON_EGON 10 -#define VALVE_WEAPON_HORNETGUN 11 -#define VALVE_WEAPON_HANDGRENADE 12 -#define VALVE_WEAPON_TRIPMINE 13 -#define VALVE_WEAPON_SATCHEL 14 -#define VALVE_WEAPON_SNARK 15 - -#define VALVE_MAX_NORMAL_BATTERY 100 -#define VALVE_HORNET_MAX_CARRY 8 - - -// weapon ID values for Valve's Team Fortress Classic & 1.5 -#define TF_WEAPON_UNKNOWN1 1 -#define TF_WEAPON_UNKNOWN2 2 -#define TF_WEAPON_MEDIKIT 3 -#define TF_WEAPON_SPANNER 4 -#define TF_WEAPON_AXE 5 -#define TF_WEAPON_SNIPERRIFLE 6 -#define TF_WEAPON_AUTORIFLE 7 -#define TF_WEAPON_SHOTGUN 8 -#define TF_WEAPON_SUPERSHOTGUN 9 -#define TF_WEAPON_NAILGUN 10 -#define TF_WEAPON_SUPERNAILGUN 11 -#define TF_WEAPON_GL 12 -#define TF_WEAPON_FLAMETHROWER 13 -#define TF_WEAPON_RPG 14 -#define TF_WEAPON_IC 15 -#define TF_WEAPON_UNKNOWN16 16 -#define TF_WEAPON_AC 17 -#define TF_WEAPON_UNKNOWN18 18 -#define TF_WEAPON_UNKNOWN19 19 -#define TF_WEAPON_TRANQ 20 -#define TF_WEAPON_RAILGUN 21 -#define TF_WEAPON_PL 22 -#define TF_WEAPON_KNIFE 23 - - -// weapon ID values for Counter-Strike -#define CS_WEAPON_P228 1 -#define CS_WEAPON_UNKNOWN2 2 -#define CS_WEAPON_SCOUT 3 -#define CS_WEAPON_HEGRENADE 4 -#define CS_WEAPON_XM1014 5 -#define CS_WEAPON_C4 6 -#define CS_WEAPON_MAC10 7 -#define CS_WEAPON_AUG 8 -#define CS_WEAPON_SMOKEGRENADE 9 -#define CS_WEAPON_ELITE 10 -#define CS_WEAPON_FIVESEVEN 11 -#define CS_WEAPON_UMP45 12 -#define CS_WEAPON_SG550 13 -#define CS_WEAPON_UNKNOWN14 14 -#define CS_WEAPON_UNKNOWN15 15 -#define CS_WEAPON_USP 16 -#define CS_WEAPON_GLOCK18 17 -#define CS_WEAPON_AWP 18 -#define CS_WEAPON_MP5NAVY 19 -#define CS_WEAPON_M249 20 -#define CS_WEAPON_M3 21 -#define CS_WEAPON_M4A1 22 -#define CS_WEAPON_TMP 23 -#define CS_WEAPON_G3SG1 24 -#define CS_WEAPON_FLASHBANG 25 -#define CS_WEAPON_DEAGLE 26 -#define CS_WEAPON_SG552 27 -#define CS_WEAPON_AK47 28 -#define CS_WEAPON_KNIFE 29 -#define CS_WEAPON_P90 30 - - -// weapon ID values for Gearbox's OpFor Deathmatch -#define GEARBOX_WEAPON_CROWBAR 1 -#define GEARBOX_WEAPON_GLOCK 2 -#define GEARBOX_WEAPON_PYTHON 3 -#define GEARBOX_WEAPON_MP5 4 -#define GEARBOX_WEAPON_CHAINGUN 5 -#define GEARBOX_WEAPON_CROSSBOW 6 -#define GEARBOX_WEAPON_SHOTGUN 7 -#define GEARBOX_WEAPON_RPG 8 -#define GEARBOX_WEAPON_GAUSS 9 -#define GEARBOX_WEAPON_EGON 10 -#define GEARBOX_WEAPON_HORNETGUN 11 -#define GEARBOX_WEAPON_HANDGRENADE 12 -#define GEARBOX_WEAPON_TRIPMINE 13 -#define GEARBOX_WEAPON_SATCHEL 14 -#define GEARBOX_WEAPON_SNARK 15 -#define GEARBOX_WEAPON_GRAPPLE 16 -#define GEARBOX_WEAPON_EAGLE 17 -#define GEARBOX_WEAPON_PIPEWRENCH 18 -#define GEARBOX_WEAPON_M249 19 -#define GEARBOX_WEAPON_DISPLACER 20 -#define GEARBOX_WEAPON_UNKNOWN21 21 -#define GEARBOX_WEAPON_SHOCKRIFLE 22 -#define GEARBOX_WEAPON_SPORELAUNCHER 23 -#define GEARBOX_WEAPON_SNIPERRIFLE 24 -#define GEARBOX_WEAPON_KNIFE 25 - - -// weapon ID values for FrontLineForce -#define FLF_WEAPON_AK5 10 -#define FLF_WEAPON_UNKNOWN11 11 -#define FLF_WEAPON_UNKNOWN12 12 -#define FLF_WEAPON_UNKNOWN13 13 -#define FLF_WEAPON_UNKNOWN14 14 -#define FLF_WEAPON_UNKNOWN15 15 -#define FLF_WEAPON_MP5SD 16 -#define FLF_WEAPON_M4 17 -#define FLF_WEAPON_FLASHBANG 18 -#define FLF_WEAPON_HEGRENADE 19 -#define FLF_WEAPON_MP5A2 20 -#define FLF_WEAPON_UMP45 21 -#define FLF_WEAPON_SPAS12 22 -#define FLF_WEAPON_BERETTA 23 -#define FLF_WEAPON_KNIFE 24 -#define FLF_WEAPON_MAC10 25 -#define FLF_WEAPON_MK23 26 -#define FLF_WEAPON_MSG90 27 -#define FLF_WEAPON_FAMAS 28 -#define FLF_WEAPON_HK21 29 - - -typedef struct -{ - char szClassname[64]; - int iAmmo1; // ammo index for primary ammo - int iAmmo1Max; // max primary ammo - int iAmmo2; // ammo index for secondary ammo - int iAmmo2Max; // max secondary ammo - int iSlot; // HUD slot (0 based) - int iPosition; // slot position - int iId; // weapon ID - int iFlags; // flags??? -} bot_weapon_t; - - -#endif // BOT_WEAPONS_H - +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// bot_weapons.h +// + +#ifndef BOT_WEAPONS_H +#define BOT_WEAPONS_H + +// weapon ID values for Valve's Half-Life Deathmatch +#define VALVE_WEAPON_CROWBAR 1 +#define VALVE_WEAPON_GLOCK 2 +#define VALVE_WEAPON_PYTHON 3 +#define VALVE_WEAPON_MP5 4 +#define VALVE_WEAPON_CHAINGUN 5 +#define VALVE_WEAPON_CROSSBOW 6 +#define VALVE_WEAPON_SHOTGUN 7 +#define VALVE_WEAPON_RPG 8 +#define VALVE_WEAPON_GAUSS 9 +#define VALVE_WEAPON_EGON 10 +#define VALVE_WEAPON_HORNETGUN 11 +#define VALVE_WEAPON_HANDGRENADE 12 +#define VALVE_WEAPON_TRIPMINE 13 +#define VALVE_WEAPON_SATCHEL 14 +#define VALVE_WEAPON_SNARK 15 + +#define VALVE_MAX_NORMAL_BATTERY 100 +#define VALVE_HORNET_MAX_CARRY 8 + + +// weapon ID values for Valve's Team Fortress Classic & 1.5 +#define TF_WEAPON_UNKNOWN1 1 +#define TF_WEAPON_UNKNOWN2 2 +#define TF_WEAPON_MEDIKIT 3 +#define TF_WEAPON_SPANNER 4 +#define TF_WEAPON_AXE 5 +#define TF_WEAPON_SNIPERRIFLE 6 +#define TF_WEAPON_AUTORIFLE 7 +#define TF_WEAPON_SHOTGUN 8 +#define TF_WEAPON_SUPERSHOTGUN 9 +#define TF_WEAPON_NAILGUN 10 +#define TF_WEAPON_SUPERNAILGUN 11 +#define TF_WEAPON_GL 12 +#define TF_WEAPON_FLAMETHROWER 13 +#define TF_WEAPON_RPG 14 +#define TF_WEAPON_IC 15 +#define TF_WEAPON_UNKNOWN16 16 +#define TF_WEAPON_AC 17 +#define TF_WEAPON_UNKNOWN18 18 +#define TF_WEAPON_UNKNOWN19 19 +#define TF_WEAPON_TRANQ 20 +#define TF_WEAPON_RAILGUN 21 +#define TF_WEAPON_PL 22 +#define TF_WEAPON_KNIFE 23 + + +// weapon ID values for Counter-Strike +#define CS_WEAPON_P228 1 +#define CS_WEAPON_UNKNOWN2 2 +#define CS_WEAPON_SCOUT 3 +#define CS_WEAPON_HEGRENADE 4 +#define CS_WEAPON_XM1014 5 +#define CS_WEAPON_C4 6 +#define CS_WEAPON_MAC10 7 +#define CS_WEAPON_AUG 8 +#define CS_WEAPON_SMOKEGRENADE 9 +#define CS_WEAPON_ELITE 10 +#define CS_WEAPON_FIVESEVEN 11 +#define CS_WEAPON_UMP45 12 +#define CS_WEAPON_SG550 13 +#define CS_WEAPON_UNKNOWN14 14 +#define CS_WEAPON_UNKNOWN15 15 +#define CS_WEAPON_USP 16 +#define CS_WEAPON_GLOCK18 17 +#define CS_WEAPON_AWP 18 +#define CS_WEAPON_MP5NAVY 19 +#define CS_WEAPON_M249 20 +#define CS_WEAPON_M3 21 +#define CS_WEAPON_M4A1 22 +#define CS_WEAPON_TMP 23 +#define CS_WEAPON_G3SG1 24 +#define CS_WEAPON_FLASHBANG 25 +#define CS_WEAPON_DEAGLE 26 +#define CS_WEAPON_SG552 27 +#define CS_WEAPON_AK47 28 +#define CS_WEAPON_KNIFE 29 +#define CS_WEAPON_P90 30 + + +// weapon ID values for Gearbox's OpFor Deathmatch +#define GEARBOX_WEAPON_CROWBAR 1 +#define GEARBOX_WEAPON_GLOCK 2 +#define GEARBOX_WEAPON_PYTHON 3 +#define GEARBOX_WEAPON_MP5 4 +#define GEARBOX_WEAPON_CHAINGUN 5 +#define GEARBOX_WEAPON_CROSSBOW 6 +#define GEARBOX_WEAPON_SHOTGUN 7 +#define GEARBOX_WEAPON_RPG 8 +#define GEARBOX_WEAPON_GAUSS 9 +#define GEARBOX_WEAPON_EGON 10 +#define GEARBOX_WEAPON_HORNETGUN 11 +#define GEARBOX_WEAPON_HANDGRENADE 12 +#define GEARBOX_WEAPON_TRIPMINE 13 +#define GEARBOX_WEAPON_SATCHEL 14 +#define GEARBOX_WEAPON_SNARK 15 +#define GEARBOX_WEAPON_GRAPPLE 16 +#define GEARBOX_WEAPON_EAGLE 17 +#define GEARBOX_WEAPON_PIPEWRENCH 18 +#define GEARBOX_WEAPON_M249 19 +#define GEARBOX_WEAPON_DISPLACER 20 +#define GEARBOX_WEAPON_UNKNOWN21 21 +#define GEARBOX_WEAPON_SHOCKRIFLE 22 +#define GEARBOX_WEAPON_SPORELAUNCHER 23 +#define GEARBOX_WEAPON_SNIPERRIFLE 24 +#define GEARBOX_WEAPON_KNIFE 25 + + +// weapon ID values for FrontLineForce +#define FLF_WEAPON_AK5 10 +#define FLF_WEAPON_UNKNOWN11 11 +#define FLF_WEAPON_UNKNOWN12 12 +#define FLF_WEAPON_UNKNOWN13 13 +#define FLF_WEAPON_UNKNOWN14 14 +#define FLF_WEAPON_UNKNOWN15 15 +#define FLF_WEAPON_MP5SD 16 +#define FLF_WEAPON_M4 17 +#define FLF_WEAPON_FLASHBANG 18 +#define FLF_WEAPON_HEGRENADE 19 +#define FLF_WEAPON_MP5A2 20 +#define FLF_WEAPON_UMP45 21 +#define FLF_WEAPON_SPAS12 22 +#define FLF_WEAPON_BERETTA 23 +#define FLF_WEAPON_KNIFE 24 +#define FLF_WEAPON_MAC10 25 +#define FLF_WEAPON_MK23 26 +#define FLF_WEAPON_MSG90 27 +#define FLF_WEAPON_FAMAS 28 +#define FLF_WEAPON_HK21 29 + + +typedef struct +{ + char szClassname[64]; + int iAmmo1; // ammo index for primary ammo + int iAmmo1Max; // max primary ammo + int iAmmo2; // ammo index for secondary ammo + int iAmmo2Max; // max secondary ammo + int iSlot; // HUD slot (0 based) + int iPosition; // slot position + int iId; // weapon ID + int iFlags; // flags??? +} bot_weapon_t; + + +#endif // BOT_WEAPONS_H + diff --git a/main/source/HPB_bot/dlls/dll.cpp b/main/source/HPB_bot/dlls/dll.cpp index 9cb8c342..55b6604a 100644 --- a/main/source/HPB_bot/dlls/dll.cpp +++ b/main/source/HPB_bot/dlls/dll.cpp @@ -1,1890 +1,1890 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// dll.cpp -// - -#include "dlls/extdll.h" -#include "dlls/enginecallback.h" -#include "dlls/util.h" -#include "dlls/cbase.h" -#include "common/entity_state.h" - -#include "bot.h" -#include "bot_func.h" -#include "waypoint.h" -#include "mod/AvHServerVariables.h" - -#define MENU_NONE 0 -#define MENU_1 1 -#define MENU_2 2 -#define MENU_3 3 - -extern GETENTITYAPI other_GetEntityAPI; -extern GETNEWDLLFUNCTIONS other_GetNewDLLFunctions; -extern enginefuncs_t g_engfuncs; -extern int debug_engine; -extern globalvars_t *gpGlobals; -extern char *g_argv; -extern bool g_waypoint_on; -extern bool g_auto_waypoint; -extern bool g_path_waypoint; -extern int num_waypoints; // number of waypoints currently in use -extern WAYPOINT waypoints[MAX_WAYPOINTS]; -extern float wp_display_time[MAX_WAYPOINTS]; -extern bot_t bots[32]; -extern bool b_observer_mode; -extern bool b_botdontshoot; -//char welcome_msg[] = "HPB bot - http://planethalflife.com/botman"; - -static FILE *fp; - -DLL_FUNCTIONS other_gFunctionTable; -DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); - -// AvH dll -int mod_id = AVH_DLL; -int m_spriteTexture = 0; -int default_bot_skill = 4; -int isFakeClientCommand = 0; -int fake_arg_count; -float bot_check_time = 30.0; -int min_bots = -1; -int max_bots = -1; -int num_bots = 0; -int prev_num_bots = 0; -bool g_GameRules = FALSE; -edict_t *clients[32]; -edict_t *listenserver_edict = NULL; -float welcome_time = 0.0; -bool welcome_sent = FALSE; -int g_menu_waypoint; -int g_menu_state = 0; - -float is_team_play = 0.0; -char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; -int num_teams = 0; -bool checked_teamplay = FALSE; -edict_t *pent_info_tfdetect = NULL; -edict_t *pent_info_ctfdetect = NULL; -edict_t *pent_info_frontline = NULL; -edict_t *pent_item_tfgoal = NULL; -int max_team_players[4]; // for TFC -int team_class_limits[4]; // for TFC -int team_allies[4]; // TFC bit mapped allies BLUE, RED, YELLOW, and GREEN -int max_teams = 0; // for TFC -FLAG_S flags[MAX_FLAGS]; // for TFC -int num_flags = 0; // for TFC - -FILE *bot_cfg_fp = NULL; -bool need_to_open_cfg = TRUE; -float bot_cfg_pause_time = 0.0; -float respawn_time = 0.0; -bool spawn_time_reset = FALSE; - -int flf_bug_fix; // for FLF 1.1 capture point bug -int flf_bug_check; // for FLF 1.1 capture point bug - - -char bot_whine[MAX_BOT_WHINE][81]; -int whine_count; -int recent_bot_whine[5]; - -cvar_t sv_bot = {"bot",""}; -cvar_t sv_freezebots = {"freezebots","0"}; - -char *show_menu_1 = - {"Waypoint Tags\n\n1. Team Specific\n2. Wait for Lift\n3. Door\n4. Sniper Spot\n5. More..."}; -char *show_menu_2 = - {"Waypoint Tags\n\n1. Team 1\n2. Team 2\n3. Team 3\n4. Team 4\n5. CANCEL"}; -char *show_menu_2_flf = - {"Waypoint Tags\n\n1. Attackers\n2. Defenders\n\n5. CANCEL"}; -char *show_menu_3 = - {"Waypoint Tags\n\n1. Flag Location\n2. Flag Goal Location\n\n5. CANCEL"}; -char *show_menu_3_flf = - {"Waypoint Tags\n\n1. Capture Point\n2. Defend Point\n3. Prone\n\n5. CANCEL"}; - - -void BotNameInit(void); -void UpdateClientData(const struct edict_s *ent, int sendweapons, struct clientdata_s *cd); -void ProcessBotCfgFile(void); - - -void GameDLLInit( void ) -{ - char filename[256]; - char buffer[256]; - int i, length; - FILE *bfp; - char *ptr; - - CVAR_REGISTER (&sv_bot); - CVAR_REGISTER (&sv_freezebots); - - for (i=0; i<32; i++) - clients[i] = NULL; - - whine_count = 0; - - // initialize the bots array of structures... - memset(bots, 0, sizeof(bots)); - - for (i=0; i < 5; i++) - recent_bot_whine[i] = -1; - - BotNameInit(); - - - UTIL_BuildFileName(filename, "bot_whine.txt", NULL); - - bfp = fopen(filename, "r"); - - if (bfp != NULL) - { - while ((whine_count < MAX_BOT_WHINE) && - (fgets(buffer, 80, bfp) != NULL)) - { - length = strlen(buffer); - - if (buffer[length-1] == '\n') - { - buffer[length-1] = 0; // remove '\n' - length--; - } - - if ((ptr = strstr(buffer, "%n")) != NULL) - { - *(ptr+1) = 's'; // change %n to %s - } - - if (length > 0) - { - strcpy(bot_whine[whine_count], buffer); - whine_count++; - } - } - - fclose(bfp); - } - - (*other_gFunctionTable.pfnGameInit)(); -} - -int DispatchSpawn( edict_t *pent ) -{ - int index; - - if (gpGlobals->deathmatch) - { - char *pClassname = (char *)STRING(pent->v.classname); - - if (debug_engine) - { - fp=fopen("bot.txt","a"); - fprintf(fp, "DispatchSpawn: %x %s\n",pent,pClassname); - if (pent->v.model != 0) - fprintf(fp, " model=%s\n",STRING(pent->v.model)); - fclose(fp); - } - - if (strcmp(pClassname, "worldspawn") == 0) - { - // do level initialization stuff here... - - WaypointInit(); - WaypointLoad(NULL); - - pent_info_tfdetect = NULL; - pent_info_ctfdetect = NULL; - pent_info_frontline = NULL; - pent_item_tfgoal = NULL; - - for (index=0; index < 4; index++) - { - max_team_players[index] = 0; // no player limit - team_class_limits[index] = 0; // no class limits - team_allies[index] = 0; - } - - max_teams = 0; - num_flags = 0; - - PRECACHE_SOUND("weapons/xbow_hit1.wav"); // waypoint add - PRECACHE_SOUND("weapons/mine_activate.wav"); // waypoint delete - PRECACHE_SOUND("common/wpn_hudoff.wav"); // path add/delete start - PRECACHE_SOUND("common/wpn_hudon.wav"); // path add/delete done - PRECACHE_SOUND("common/wpn_moveselect.wav"); // path add/delete cancel - PRECACHE_SOUND("common/wpn_denyselect.wav"); // path add/delete error - - m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr"); - - g_GameRules = TRUE; - - is_team_play = 0.0; - memset(team_names, 0, sizeof(team_names)); - num_teams = 0; - checked_teamplay = FALSE; - - bot_cfg_pause_time = 0.0; - respawn_time = 0.0; - spawn_time_reset = FALSE; - - prev_num_bots = num_bots; - num_bots = 0; - - flf_bug_fix = 0; - flf_bug_check = 0; - - bot_check_time = gpGlobals->time + 30.0; - } - } - - return (*other_gFunctionTable.pfnSpawn)(pent); -} - -void DispatchThink( edict_t *pent ) -{ - (*other_gFunctionTable.pfnThink)(pent); -} - -void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) -{ - (*other_gFunctionTable.pfnUse)(pentUsed, pentOther); -} - -void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) -{ - (*other_gFunctionTable.pfnTouch)(pentTouched, pentOther); -} - -void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) -{ - (*other_gFunctionTable.pfnBlocked)(pentBlocked, pentOther); -} - -void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) -{ - static edict_t *temp_pent; - static int flag_index; - -// fp=fopen("bot.txt","a"); fprintf(fp, "DispatchKeyValue: %x %s=%s\n",pentKeyvalue,pkvd->szKeyName,pkvd->szValue); fclose(fp); - - if (mod_id == TFC_DLL) - { - if (pentKeyvalue == pent_info_tfdetect) - { - if (strcmp(pkvd->szKeyName, "ammo_medikit") == 0) // max BLUE players - max_team_players[0] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "ammo_detpack") == 0) // max RED players - max_team_players[1] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "maxammo_medikit") == 0) // max YELLOW players - max_team_players[2] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "maxammo_detpack") == 0) // max GREEN players - max_team_players[3] = atoi(pkvd->szValue); - - else if (strcmp(pkvd->szKeyName, "maxammo_shells") == 0) // BLUE class limits - team_class_limits[0] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "maxammo_nails") == 0) // RED class limits - team_class_limits[1] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "maxammo_rockets") == 0) // YELLOW class limits - team_class_limits[2] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "maxammo_cells") == 0) // GREEN class limits - team_class_limits[3] = atoi(pkvd->szValue); - - else if (strcmp(pkvd->szKeyName, "team1_allies") == 0) // BLUE allies - team_allies[0] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "team2_allies") == 0) // RED allies - team_allies[1] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "team3_allies") == 0) // YELLOW allies - team_allies[2] = atoi(pkvd->szValue); - else if (strcmp(pkvd->szKeyName, "team4_allies") == 0) // GREEN allies - team_allies[3] = atoi(pkvd->szValue); - } - else if (pent_info_tfdetect == NULL) - { - if ((strcmp(pkvd->szKeyName, "classname") == 0) && - (strcmp(pkvd->szValue, "info_tfdetect") == 0)) - { - pent_info_tfdetect = pentKeyvalue; - } - } - - if (pentKeyvalue == pent_item_tfgoal) - { - if (strcmp(pkvd->szKeyName, "team_no") == 0) - flags[flag_index].team_no = atoi(pkvd->szValue); - - if ((strcmp(pkvd->szKeyName, "mdl") == 0) && - ((strcmp(pkvd->szValue, "models/flag.mdl") == 0) || - (strcmp(pkvd->szValue, "models/keycard.mdl") == 0) || - (strcmp(pkvd->szValue, "models/ball.mdl") == 0))) - { - flags[flag_index].mdl_match = TRUE; - num_flags++; - } - } - else if (pent_item_tfgoal == NULL) - { - if ((strcmp(pkvd->szKeyName, "classname") == 0) && - (strcmp(pkvd->szValue, "item_tfgoal") == 0)) - { - if (num_flags < MAX_FLAGS) - { - pent_item_tfgoal = pentKeyvalue; - - flags[num_flags].mdl_match = FALSE; - flags[num_flags].team_no = 0; // any team unless specified - flags[num_flags].edict = pentKeyvalue; - - flag_index = num_flags; // in case the mdl comes before team_no - } - } - } - else - { - pent_item_tfgoal = NULL; // reset for non-flag item_tfgoal's - } - - if ((strcmp(pkvd->szKeyName, "classname") == 0) && - ((strcmp(pkvd->szValue, "info_player_teamspawn") == 0) || - (strcmp(pkvd->szValue, "i_p_t") == 0))) - { - temp_pent = pentKeyvalue; - } - else if (pentKeyvalue == temp_pent) - { - if (strcmp(pkvd->szKeyName, "team_no") == 0) - { - int value = atoi(pkvd->szValue); - - if (value > max_teams) - max_teams = value; - } - } - } - else if (mod_id == GEARBOX_DLL) - { - if (pent_info_ctfdetect == NULL) - { - if ((strcmp(pkvd->szKeyName, "classname") == 0) && - (strcmp(pkvd->szValue, "info_ctfdetect") == 0)) - { - pent_info_ctfdetect = pentKeyvalue; - } - } - } - - (*other_gFunctionTable.pfnKeyValue)(pentKeyvalue, pkvd); -} - -void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) -{ - (*other_gFunctionTable.pfnSave)(pent, pSaveData); -} - -int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) -{ - return (*other_gFunctionTable.pfnRestore)(pent, pSaveData, globalEntity); -} - -void DispatchObjectCollsionBox( edict_t *pent ) -{ - (*other_gFunctionTable.pfnSetAbsBox)(pent); -} - -void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - (*other_gFunctionTable.pfnSaveWriteFields)(pSaveData, pname, pBaseData, pFields, fieldCount); -} - -void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - (*other_gFunctionTable.pfnSaveReadFields)(pSaveData, pname, pBaseData, pFields, fieldCount); -} - -void SaveGlobalState( SAVERESTOREDATA *pSaveData ) -{ - (*other_gFunctionTable.pfnSaveGlobalState)(pSaveData); -} - -void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) -{ - (*other_gFunctionTable.pfnRestoreGlobalState)(pSaveData); -} - -void ResetGlobalState( void ) -{ - (*other_gFunctionTable.pfnResetGlobalState)(); -} - -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - if (gpGlobals->deathmatch) - { - int i; - int count = 0; - - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientConnect: pent=%x name=%s\n",pEntity,pszName); fclose(fp); } - - // check if this client is the listen server client - if (strcmp(pszAddress, "loopback") == 0) - { - // save the edict of the listen server client... - listenserver_edict = pEntity; - } - - // check if this is NOT a bot joining the server... - if (strcmp(pszAddress, "127.0.0.1") != 0) - { - // don't try to add bots for 60 seconds, give client time to get added - bot_check_time = gpGlobals->time + 60.0; - - for (i=0; i < 32; i++) - { - if (bots[i].is_used) // count the number of bots in use - count++; - } - - // if there are currently more than the minimum number of bots running - // then kick one of the bots off the server... - if ((count > min_bots) && (min_bots != -1)) - { - for (i=0; i < 32; i++) - { - if (bots[i].is_used) // is this slot used? - { - char cmd[80]; - - sprintf(cmd, "kick \"%s\"\n", bots[i].name); - - SERVER_COMMAND(cmd); // kick the bot using (kick "name") - - break; - } - } - } - } - } - - return (*other_gFunctionTable.pfnClientConnect)(pEntity, pszName, pszAddress, szRejectReason); -} - -void ClientDisconnect( edict_t *pEntity ) -{ - if (gpGlobals->deathmatch) - { - int i; - - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientDisconnect: %x\n",pEntity); fclose(fp); } - - i = 0; - while ((i < 32) && (clients[i] != pEntity)) - i++; - - if (i < 32) - clients[i] = NULL; - - - for (i=0; i < 32; i++) - { - if (bots[i].pEdict == pEntity) - { - // someone kicked this bot off of the server... - - bots[i].is_used = FALSE; // this slot is now free to use - - bots[i].kick_time = gpGlobals->time; // save the kicked time - - break; - } - } - } - - (*other_gFunctionTable.pfnClientDisconnect)(pEntity); -} - -void ClientKill( edict_t *pEntity ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientKill: %x\n",pEntity); fclose(fp); } - (*other_gFunctionTable.pfnClientKill)(pEntity); -} - -void ClientPutInServer( edict_t *pEntity ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientPutInServer: %x\n",pEntity); fclose(fp); } - - int i = 0; - - while ((i < 32) && (clients[i] != NULL)) - i++; - - if (i < 32) - clients[i] = pEntity; // store this clients edict in the clients array - - (*other_gFunctionTable.pfnClientPutInServer)(pEntity); -} - -void ClientCommand( edict_t *pEntity ) -{ - // only allow custom commands if deathmatch mode and NOT dedicated server and - // client sending command is the listen server client... - - if ((gpGlobals->deathmatch) && /*(!IS_DEDICATED_SERVER()) &&*/ - (pEntity == listenserver_edict)) - { - const char *pcmd = Cmd_Argv(0); - const char *arg1 = Cmd_Argv(1); - const char *arg2 = Cmd_Argv(2); - const char *arg3 = Cmd_Argv(3); - const char *arg4 = Cmd_Argv(4); - char msg[80]; - - if (debug_engine) - { - fp=fopen("bot.txt","a"); fprintf(fp,"ClientCommand: %s",pcmd); - if ((arg1 != NULL) && (*arg1 != 0)) - fprintf(fp," %s", arg1); - if ((arg2 != NULL) && (*arg2 != 0)) - fprintf(fp," %s", arg2); - if ((arg3 != NULL) && (*arg3 != 0)) - fprintf(fp," %s", arg3); - if ((arg4 != NULL) && (*arg4 != 0)) - fprintf(fp," %s", arg4); - fprintf(fp, "\n"); - fclose(fp); - } - - if (FStrEq(pcmd, "addbot")) - { - BotCreate( pEntity, arg1, arg2, arg3, arg4 ); - - bot_check_time = gpGlobals->time + 5.0; - - return; - } - else if (FStrEq(pcmd, "observer")) - { - if ((arg1 != NULL) && (*arg1 != 0)) - { - int temp = atoi(arg1); - if (temp) - b_observer_mode = TRUE; - else - b_observer_mode = FALSE; - } - - if (b_observer_mode) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "observer mode ENABLED\n"); - else - ClientPrint(pEntity, HUD_PRINTNOTIFY, "observer mode DISABLED\n"); - - return; - } - else if (FStrEq(pcmd, "botskill")) - { - if ((arg1 != NULL) && (*arg1 != 0)) - { - int temp = atoi(arg1); - - if ((temp < 1) || (temp > 5)) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid botskill value!\n"); - else - default_bot_skill = temp; - } - - sprintf(msg, "botskill is %d\n", default_bot_skill); - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - - return; - } - else if (FStrEq(pcmd, "botdontshoot")) - { - if ((arg1 != NULL) && (*arg1 != 0)) - { - int temp = atoi(arg1); - if (temp) - b_botdontshoot = TRUE; - else - b_botdontshoot = FALSE; - } - - if (b_botdontshoot) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "botdontshoot ENABLED\n"); - else - ClientPrint(pEntity, HUD_PRINTNOTIFY, "botdontshoot DISABLED\n"); - - return; - } - else if (FStrEq(pcmd, "debug_engine")) - { - debug_engine = 1; - - ClientPrint(pEntity, HUD_PRINTNOTIFY, "debug_engine enabled!\n"); - - return; - } - else if (FStrEq(pcmd, "waypoint")) - { - if (FStrEq(arg1, "on")) - { - g_waypoint_on = TRUE; - - ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are ON\n"); - } - else if (FStrEq(arg1, "off")) - { - g_waypoint_on = FALSE; - - ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are OFF\n"); - } - else if (FStrEq(arg1, "add")) - { - if (!g_waypoint_on) - g_waypoint_on = TRUE; // turn waypoints on if off - - WaypointAdd(pEntity); - } - else if (FStrEq(arg1, "delete")) - { - if (!g_waypoint_on) - g_waypoint_on = TRUE; // turn waypoints on if off - - WaypointDelete(pEntity); - } - else if (FStrEq(arg1, "save")) - { - WaypointSave(); - - ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints saved\n"); - } - else if (FStrEq(arg1, "load")) - { - if (WaypointLoad(pEntity)) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints loaded\n"); - } - else if (FStrEq(arg1, "menu")) - { - int index; - - if (num_waypoints < 1) - return; - - index = WaypointFindNearest(pEntity, 50.0, -1); - - if (index == -1) - return; - - g_menu_waypoint = index; - g_menu_state = MENU_1; - - UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_1); - } - else if (FStrEq(arg1, "info")) - { - WaypointPrintInfo(pEntity); - } - else - { - if (g_waypoint_on) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are ON\n"); - else - ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are OFF\n"); - } - - return; - } - else if (FStrEq(pcmd, "autowaypoint")) - { - if (FStrEq(arg1, "on")) - { - g_auto_waypoint = TRUE; - g_waypoint_on = TRUE; // turn this on just in case - } - else if (FStrEq(arg1, "off")) - { - g_auto_waypoint = FALSE; - } - - if (g_auto_waypoint) - sprintf(msg, "autowaypoint is ON\n"); - else - sprintf(msg, "autowaypoint is OFF\n"); - - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - - return; - } - else if (FStrEq(pcmd, "pathwaypoint")) - { - if (FStrEq(arg1, "on")) - { - g_path_waypoint = TRUE; - g_waypoint_on = TRUE; // turn this on just in case - - ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is ON\n"); - } - else if (FStrEq(arg1, "off")) - { - g_path_waypoint = FALSE; - - ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is OFF\n"); - } - else if (FStrEq(arg1, "create1")) - { - WaypointCreatePath(pEntity, 1); - } - else if (FStrEq(arg1, "create2")) - { - WaypointCreatePath(pEntity, 2); - } - else if (FStrEq(arg1, "remove1")) - { - WaypointRemovePath(pEntity, 1); - } - else if (FStrEq(arg1, "remove2")) - { - WaypointRemovePath(pEntity, 2); - } - - return; - } - else if (FStrEq(pcmd, "menuselect") && (g_menu_state != MENU_NONE)) - { - if (g_menu_state == MENU_1) // main menu... - { - if (FStrEq(arg1, "1")) // team specific... - { - g_menu_state = MENU_2; // display team specific menu... - - if (mod_id == FRONTLINE_DLL) - UTIL_ShowMenu(pEntity, 0x13, -1, FALSE, show_menu_2_flf); - else - UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_2); - - return; - } - else if (FStrEq(arg1, "2")) // wait for lift... - { - if (waypoints[g_menu_waypoint].flags & W_FL_LIFT) - waypoints[g_menu_waypoint].flags &= ~W_FL_LIFT; // off - else - waypoints[g_menu_waypoint].flags |= W_FL_LIFT; // on - } - else if (FStrEq(arg1, "3")) // door waypoint - { - if (waypoints[g_menu_waypoint].flags & W_FL_DOOR) - waypoints[g_menu_waypoint].flags &= ~W_FL_DOOR; // off - else - waypoints[g_menu_waypoint].flags |= W_FL_DOOR; // on - } - else if (FStrEq(arg1, "4")) // sniper spot - { - if (waypoints[g_menu_waypoint].flags & W_FL_SNIPER) - waypoints[g_menu_waypoint].flags &= ~W_FL_SNIPER; // off - else - { - waypoints[g_menu_waypoint].flags |= W_FL_SNIPER; // on - - // set the aiming waypoint... - - WaypointAddAiming(pEntity); - } - } - else if (FStrEq(arg1, "5")) // more... - { - g_menu_state = MENU_3; - - if (mod_id == FRONTLINE_DLL) - UTIL_ShowMenu(pEntity, 0x17, -1, FALSE, show_menu_3_flf); - else - UTIL_ShowMenu(pEntity, 0x13, -1, FALSE, show_menu_3); - - return; - } - } - else if (g_menu_state == MENU_2) // team specific menu - { - if (waypoints[g_menu_waypoint].flags & W_FL_TEAM_SPECIFIC) - { - waypoints[g_menu_waypoint].flags &= ~W_FL_TEAM; - waypoints[g_menu_waypoint].flags &= ~W_FL_TEAM_SPECIFIC; // off - } - else - { - int team = atoi(arg1); - - team--; // make 0 to 3 - - // this is kind of a kludge (team bits MUST be LSB!!!) - waypoints[g_menu_waypoint].flags |= team; - waypoints[g_menu_waypoint].flags |= W_FL_TEAM_SPECIFIC; // on - } - } - else if (g_menu_state == MENU_3) // second menu... - { - if (mod_id == FRONTLINE_DLL) - { - if (FStrEq(arg1, "1")) // capture point - { - if (waypoints[g_menu_waypoint].flags & W_FL_FLF_CAP) - waypoints[g_menu_waypoint].flags &= ~W_FL_FLF_CAP; // off - else - waypoints[g_menu_waypoint].flags |= W_FL_FLF_CAP; // on - } - else if (FStrEq(arg1, "2")) // defend point - { - if (waypoints[g_menu_waypoint].flags & W_FL_FLF_DEFEND) - waypoints[g_menu_waypoint].flags &= ~W_FL_FLF_DEFEND; // off - else - { - waypoints[g_menu_waypoint].flags |= W_FL_FLF_DEFEND; // on - - // set the aiming waypoint... - - WaypointAddAiming(pEntity); - } - } - else if (FStrEq(arg1, "3")) // go prone - { - if (waypoints[g_menu_waypoint].flags & W_FL_PRONE) - waypoints[g_menu_waypoint].flags &= ~W_FL_PRONE; // off - else - waypoints[g_menu_waypoint].flags |= W_FL_PRONE; // on - } - } - else - { - if (FStrEq(arg1, "1")) // flag location - { - if (waypoints[g_menu_waypoint].flags & W_FL_TFC_FLAG) - waypoints[g_menu_waypoint].flags &= ~W_FL_TFC_FLAG; // off - else - waypoints[g_menu_waypoint].flags |= W_FL_TFC_FLAG; // on - } - else if (FStrEq(arg1, "2")) // flag goal - { - if (waypoints[g_menu_waypoint].flags & W_FL_TFC_FLAG_GOAL) - waypoints[g_menu_waypoint].flags &= ~W_FL_TFC_FLAG_GOAL; // off - else - waypoints[g_menu_waypoint].flags |= W_FL_TFC_FLAG_GOAL; // on - } - } - } - - g_menu_state = MENU_NONE; - - return; - } - else if (FStrEq(pcmd, "search")) - { - edict_t *pent = NULL; - float radius = 50; - char str[80]; - - ClientPrint(pEntity, HUD_PRINTCONSOLE, "searching...\n"); - - while ((pent = UTIL_FindEntityInSphere( pent, pEntity->v.origin, radius )) != NULL) - { - sprintf(str, "Found %s at %5.2f %5.2f %5.2f\n", - STRING(pent->v.classname), - pent->v.origin.x, pent->v.origin.y, - pent->v.origin.z); - ClientPrint(pEntity, HUD_PRINTCONSOLE, str); - - FILE *fp=fopen("bot.txt", "a"); - fprintf(fp, "ClientCommmand: search %s", str); - fclose(fp); - } - - return; - } - } - - (*other_gFunctionTable.pfnClientCommand)(pEntity); -} - -void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) -{ - if (debug_engine) { fp=fopen("bot.txt", "a"); fprintf(fp, "ClientUserInfoChanged: pEntity=%x infobuffer=%s\n", pEntity, infobuffer); fclose(fp); } - - (*other_gFunctionTable.pfnClientUserInfoChanged)(pEntity, infobuffer); -} - -void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) -{ - (*other_gFunctionTable.pfnServerActivate)(pEdictList, edictCount, clientMax); -} - -void ServerDeactivate( void ) -{ - (*other_gFunctionTable.pfnServerDeactivate)(); -} - -void PlayerPreThink( edict_t *pEntity ) -{ - (*other_gFunctionTable.pfnPlayerPreThink)(pEntity); -} - -void PlayerPostThink( edict_t *pEntity ) -{ - (*other_gFunctionTable.pfnPlayerPostThink)(pEntity); -} - -void StartFrame( void ) -{ - if (gpGlobals->deathmatch) - { - edict_t *pPlayer; - static float check_server_cmd = 0.0; - static int i, index, player_index, bot_index; - static float previous_time = -1.0; - static float client_update_time = 0.0; - clientdata_s cd; - char msg[256]; - int count; - - // if a new map has started then (MUST BE FIRST IN StartFrame)... - if ((gpGlobals->time + 0.1) < previous_time) - { - char filename[256]; - char mapname[64]; - - check_server_cmd = 0.0; // reset at start of map - - // check if mapname_bot.cfg file exists... - - strcpy(mapname, STRING(gpGlobals->mapname)); - strcat(mapname, "_bot.cfg"); - - UTIL_BuildFileName(filename, "maps", mapname); - - if ((bot_cfg_fp = fopen(filename, "r")) != NULL) - { - sprintf(msg, "Executing %s\n", filename); - ALERT( at_console, msg ); - - for (index = 0; index < 32; index++) - { - bots[index].is_used = FALSE; - bots[index].respawn_state = 0; - bots[index].kick_time = 0.0; - } - - if (IS_DEDICATED_SERVER()) - bot_cfg_pause_time = gpGlobals->time + 5.0; - else - bot_cfg_pause_time = gpGlobals->time + 20.0; - } - else - { - count = 0; - - // mark the bots as needing to be respawned... - for (index = 0; index < 32; index++) - { - if (count >= prev_num_bots) - { - bots[index].is_used = FALSE; - bots[index].respawn_state = 0; - bots[index].kick_time = 0.0; - } - - if (bots[index].is_used) // is this slot used? - { - bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; - count++; - } - - // check for any bots that were very recently kicked... - if ((bots[index].kick_time + 5.0) > previous_time) - { - bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; - count++; - } - else - bots[index].kick_time = 0.0; // reset to prevent false spawns later - } - - // set the respawn time - if (IS_DEDICATED_SERVER()) - respawn_time = gpGlobals->time + 5.0; - else - respawn_time = gpGlobals->time + 20.0; - } - - client_update_time = gpGlobals->time + 10.0; // start updating client data again - - bot_check_time = gpGlobals->time + 30.0; - } - - if (!IS_DEDICATED_SERVER()) - { - if ((listenserver_edict != NULL) && (welcome_sent == FALSE) && - (welcome_time < 1.0)) - { - // are they out of observer mode yet? - if (IsAlive(listenserver_edict)) - welcome_time = gpGlobals->time + 5.0; // welcome in 5 seconds - } - - if ((welcome_time > 0.0) && (welcome_time < gpGlobals->time) && - (welcome_sent == FALSE)) - { - // let's send a welcome message to this client... - //UTIL_SayText(welcome_msg, listenserver_edict); - - welcome_sent = TRUE; // clear this so we only do it once - } - } - - if (client_update_time <= gpGlobals->time) - { - client_update_time = gpGlobals->time + 1.0; - - for (i=0; i < 32; i++) - { - if (bots[i].is_used) - { - memset(&cd, 0, sizeof(cd)); - - UpdateClientData( bots[i].pEdict, 1, &cd ); - - // see if a weapon was dropped... - if (bots[i].bot_weapons != cd.weapons) - { - bots[i].bot_weapons = cd.weapons; - } - } - } - } - - count = 0; - - for (bot_index = 0; bot_index < gpGlobals->maxClients; bot_index++) - { - if ((bots[bot_index].is_used) && // is this slot used AND - (bots[bot_index].respawn_state == RESPAWN_IDLE)) // not respawning - { - BotThink(&bots[bot_index]); - - count++; - - if ((mod_id == FRONTLINE_DLL) && (flf_bug_check == 0)) - { - edict_t *pent = NULL; - int fix_flag = 0; - - flf_bug_check = 1; - - while ((pent = UTIL_FindEntityByClassname( pent, "capture_point" )) != NULL) - { - if (pent->v.skin != 0) // not blue skin? - { - flf_bug_fix = 1; // need to use bug fix code - } - } - } - } - } - - if (count > num_bots) - num_bots = count; - - for (player_index = 1; player_index <= gpGlobals->maxClients; player_index++) - { - pPlayer = INDEXENT(player_index); - - if (pPlayer && !pPlayer->free) - { - if ((g_waypoint_on) && FBitSet(pPlayer->v.flags, FL_CLIENT)) - { - WaypointThink(pPlayer); - } - - if ((mod_id == FRONTLINE_DLL) && (flf_bug_check == 0)) - { - edict_t *pent = NULL; - int fix_flag = 0; - - flf_bug_check = 1; - - while ((pent = UTIL_FindEntityByClassname( pent, "capture_point" )) != NULL) - { - if (pent->v.skin != 0) // not blue skin? - { - flf_bug_fix = 1; // need to use bug fix code - } - } - } - } - } - - // are we currently respawning bots and is it time to spawn one yet? - if ((respawn_time > 1.0) && (respawn_time <= gpGlobals->time)) - { - int index = 0; - - // find bot needing to be respawned... - while ((index < 32) && - (bots[index].respawn_state != RESPAWN_NEED_TO_RESPAWN)) - index++; - - if (index < 32) - { - bots[index].respawn_state = RESPAWN_IS_RESPAWNING; - bots[index].is_used = FALSE; // free up this slot - - // respawn 1 bot then wait a while (otherwise engine crashes) - if ((mod_id == VALVE_DLL) || - ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect == NULL))) - { - char c_skill[2]; - - sprintf(c_skill, "%d", bots[index].bot_skill); - - BotCreate(NULL, bots[index].skin, bots[index].name, c_skill, NULL); - } - else - { - char c_skill[2]; - char c_team[2]; - char c_class[3]; - - sprintf(c_skill, "%d", bots[index].bot_skill); - sprintf(c_team, "%d", bots[index].bot_team); - sprintf(c_class, "%d", bots[index].bot_class); - - if ((mod_id == TFC_DLL) || (mod_id == GEARBOX_DLL)) - BotCreate(NULL, NULL, NULL, bots[index].name, c_skill); - else - BotCreate(NULL, c_team, c_class, bots[index].name, c_skill); - } - - respawn_time = gpGlobals->time + 2.0; // set next respawn time - - bot_check_time = gpGlobals->time + 5.0; - } - else - { - respawn_time = 0.0; - } - } - - if (g_GameRules) - { - if (need_to_open_cfg) // have we open bot.cfg file yet? - { - char filename[256]; - char mapname[64]; - - need_to_open_cfg = FALSE; // only do this once!!! - - // check if mapname_bot.cfg file exists... - - strcpy(mapname, STRING(gpGlobals->mapname)); - strcat(mapname, "_bot.cfg"); - - UTIL_BuildFileName(filename, "maps", mapname); - - if ((bot_cfg_fp = fopen(filename, "r")) != NULL) - { - sprintf(msg, "Executing %s\n", filename); - ALERT( at_console, msg ); - } - else - { - UTIL_BuildFileName(filename, "bot.cfg", NULL); - - sprintf(msg, "Executing %s\n", filename); - ALERT( at_console, msg ); - - bot_cfg_fp = fopen(filename, "r"); - - if (bot_cfg_fp == NULL) - ALERT( at_console, "bot.cfg file not found\n" ); - } - - if (IS_DEDICATED_SERVER()) - bot_cfg_pause_time = gpGlobals->time + 5.0; - else - bot_cfg_pause_time = gpGlobals->time + 20.0; - } - - if (!IS_DEDICATED_SERVER() && !spawn_time_reset) - { - if (listenserver_edict != NULL) - { - if (IsAlive(listenserver_edict)) - { - spawn_time_reset = TRUE; - - if (respawn_time >= 1.0) - respawn_time = min(respawn_time, gpGlobals->time + (float)1.0); - - if (bot_cfg_pause_time >= 1.0) - bot_cfg_pause_time = min(bot_cfg_pause_time, gpGlobals->time + (float)1.0); - } - } - } - - if ((bot_cfg_fp) && - (bot_cfg_pause_time >= 1.0) && (bot_cfg_pause_time <= gpGlobals->time)) - { - // process bot.cfg file options... - ProcessBotCfgFile(); - } - - } - - // if time to check for server commands then do so... - if ((check_server_cmd <= gpGlobals->time) && IS_DEDICATED_SERVER()) - { - check_server_cmd = gpGlobals->time + 1.0; - - char *cvar_bot = (char *)CVAR_GET_STRING( "bot" ); - - if ( cvar_bot && cvar_bot[0] ) - { - char cmd_line[80]; - char *cmd, *arg1, *arg2, *arg3, *arg4; - - strcpy(cmd_line, cvar_bot); - - index = 0; - cmd = cmd_line; - arg1 = arg2 = arg3 = arg4 = NULL; - - // skip to blank or end of string... - while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) - index++; - - if (cmd_line[index] == ' ') - { - cmd_line[index++] = 0; - arg1 = &cmd_line[index]; - - // skip to blank or end of string... - while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) - index++; - - if (cmd_line[index] == ' ') - { - cmd_line[index++] = 0; - arg2 = &cmd_line[index]; - - // skip to blank or end of string... - while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) - index++; - - if (cmd_line[index] == ' ') - { - cmd_line[index++] = 0; - arg3 = &cmd_line[index]; - - // skip to blank or end of string... - while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) - index++; - - if (cmd_line[index] == ' ') - { - cmd_line[index++] = 0; - arg4 = &cmd_line[index]; - } - } - } - } - - if (strcmp(cmd, "addbot") == 0) - { - BotCreate( NULL, arg1, arg2, arg3, arg4 ); - - bot_check_time = gpGlobals->time + 5.0; - } - else if (strcmp(cmd, "min_bots") == 0) - { - min_bots = atoi( arg1 ); - - if ((min_bots < 0) || (min_bots > 31)) - min_bots = 1; - - sprintf(msg, "min_bots set to %d\n", min_bots); - printf(msg); - } - else if (strcmp(cmd, "max_bots") == 0) - { - max_bots = atoi( arg1 ); - - if ((max_bots < 0) || (max_bots > 31)) - max_bots = 1; - - sprintf(msg, "max_bots set to %d\n", max_bots); - printf(msg); - } - - CVAR_SET_STRING("bot", ""); - } - } - - // check if time to see if a bot needs to be created... - if (bot_check_time < gpGlobals->time) - { - int count = 0; - - bot_check_time = gpGlobals->time + 5.0; - - for (i = 0; i < 32; i++) - { - if (clients[i] != NULL) - count++; - } - - // if there are currently less than the maximum number of "players" - // then add another bot using the default skill level... - if ((count < max_bots) && (max_bots != -1)) - { - BotCreate( NULL, NULL, NULL, NULL, NULL ); - } - } - - previous_time = gpGlobals->time; - } - - (*other_gFunctionTable.pfnStartFrame)(); -} - -void ParmsNewLevel( void ) -{ - (*other_gFunctionTable.pfnParmsNewLevel)(); -} - -void ParmsChangeLevel( void ) -{ - (*other_gFunctionTable.pfnParmsChangeLevel)(); -} - -const char *GetGameDescription( void ) -{ - return (*other_gFunctionTable.pfnGetGameDescription)(); -} - -void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) -{ - if (debug_engine) { fp=fopen("bot.txt", "a"); fprintf(fp, "PlayerCustomization: %x\n",pEntity); fclose(fp); } - - (*other_gFunctionTable.pfnPlayerCustomization)(pEntity, pCust); -} - -void SpectatorConnect( edict_t *pEntity ) -{ - (*other_gFunctionTable.pfnSpectatorConnect)(pEntity); -} - -void SpectatorDisconnect( edict_t *pEntity ) -{ - (*other_gFunctionTable.pfnSpectatorDisconnect)(pEntity); -} - -void SpectatorThink( edict_t *pEntity ) -{ - (*other_gFunctionTable.pfnSpectatorThink)(pEntity); -} - -void Sys_Error( const char *error_string ) -{ - (*other_gFunctionTable.pfnSys_Error)(error_string); -} - -void PM_Move ( struct playermove_s *ppmove, int server ) -{ - (*other_gFunctionTable.pfnPM_Move)(ppmove, server); -} - -void PM_Init ( struct playermove_s *ppmove ) -{ - (*other_gFunctionTable.pfnPM_Init)(ppmove); -} - -char PM_FindTextureType( char *name ) -{ - return (*other_gFunctionTable.pfnPM_FindTextureType)(name); -} - -void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) -{ - (*other_gFunctionTable.pfnSetupVisibility)(pViewEntity, pClient, pvs, pas); -} - -void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) -{ - (*other_gFunctionTable.pfnUpdateClientData)(ent, sendweapons, cd); -} - -int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) -{ - return (*other_gFunctionTable.pfnAddToFullPack)(state, e, ent, host, hostflags, player, pSet); -} - -void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) -{ - (*other_gFunctionTable.pfnCreateBaseline)(player, eindex, baseline, entity, playermodelindex, player_mins, player_maxs); -} - -void RegisterEncoders( void ) -{ - (*other_gFunctionTable.pfnRegisterEncoders)(); -} - -int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) -{ - return (*other_gFunctionTable.pfnGetWeaponData)(player, info); -} - -void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) -{ - (*other_gFunctionTable.pfnCmdStart)(player, cmd, random_seed); -} - -void CmdEnd ( const edict_t *player ) -{ - (*other_gFunctionTable.pfnCmdEnd)(player); -} - -int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - return (*other_gFunctionTable.pfnConnectionlessPacket)(net_from, args, response_buffer, response_buffer_size); -} - -int GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - return (*other_gFunctionTable.pfnGetHullBounds)(hullnumber, mins, maxs); -} - -void CreateInstancedBaselines( void ) -{ - (*other_gFunctionTable.pfnCreateInstancedBaselines)(); -} - -int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) -{ - if (debug_engine) { fp=fopen("bot.txt", "a"); fprintf(fp, "InconsistentFile: %x filename=%s\n",player,filename); fclose(fp); } - - return (*other_gFunctionTable.pfnInconsistentFile)(player, filename, disconnect_message); -} - -int AllowLagCompensation( void ) -{ - return (*other_gFunctionTable.pfnAllowLagCompensation)(); -} - - -DLL_FUNCTIONS gFunctionTable = -{ - GameDLLInit, //pfnGameInit - DispatchSpawn, //pfnSpawn - DispatchThink, //pfnThink - DispatchUse, //pfnUse - DispatchTouch, //pfnTouch - DispatchBlocked, //pfnBlocked - DispatchKeyValue, //pfnKeyValue - DispatchSave, //pfnSave - DispatchRestore, //pfnRestore - DispatchObjectCollsionBox, //pfnAbsBox - - SaveWriteFields, //pfnSaveWriteFields - SaveReadFields, //pfnSaveReadFields - - SaveGlobalState, //pfnSaveGlobalState - RestoreGlobalState, //pfnRestoreGlobalState - ResetGlobalState, //pfnResetGlobalState - - ClientConnect, //pfnClientConnect - ClientDisconnect, //pfnClientDisconnect - ClientKill, //pfnClientKill - ClientPutInServer, //pfnClientPutInServer - ClientCommand, //pfnClientCommand - ClientUserInfoChanged, //pfnClientUserInfoChanged - ServerActivate, //pfnServerActivate - ServerDeactivate, //pfnServerDeactivate - - PlayerPreThink, //pfnPlayerPreThink - PlayerPostThink, //pfnPlayerPostThink - - StartFrame, //pfnStartFrame - ParmsNewLevel, //pfnParmsNewLevel - ParmsChangeLevel, //pfnParmsChangeLevel - - GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. - PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player. - - SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server - SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server - SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) - - Sys_Error, //pfnSys_Error Called when engine has encountered an error - - PM_Move, //pfnPM_Move - PM_Init, //pfnPM_Init Server version of player movement initialization - PM_FindTextureType, //pfnPM_FindTextureType - - SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client - UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client - AddToFullPack, //pfnAddToFullPack - CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. - RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding - GetWeaponData, //pfnGetWeaponData - CmdStart, //pfnCmdStart - CmdEnd, //pfnCmdEnd - ConnectionlessPacket, //pfnConnectionlessPacket - GetHullBounds, //pfnGetHullBounds - CreateInstancedBaselines, //pfnCreateInstancedBaselines - InconsistentFile, //pfnInconsistentFile - AllowLagCompensation, //pfnAllowLagCompensation -}; - -#ifdef __BORLANDC__ -int EXPORT GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) -#else -extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) -#endif -{ - // check if engine's pointer is valid and version is correct... - - if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) - return FALSE; - - // pass engine callback function table to engine... - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); - - // pass other DLLs engine callbacks to function table... - if (!(*other_GetEntityAPI)(&other_gFunctionTable, INTERFACE_VERSION)) - { - return FALSE; // error initializing function table!!! - } - - return TRUE; -} - - -#ifdef __BORLANDC__ -int EXPORT GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) -#else -extern "C" EXPORT int GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) -#endif -{ - if (other_GetNewDLLFunctions == NULL) - return FALSE; - - // pass other DLLs engine callbacks to function table... - if (!(*other_GetNewDLLFunctions)(pFunctionTable, interfaceVersion)) - { - return FALSE; // error initializing function table!!! - } - - return TRUE; -} - - -void FakeClientCommand(edict_t *pBot, char *arg1, char *arg2, char *arg3) -{ - int length; - - memset(g_argv, 0, sizeof(g_argv)); - - isFakeClientCommand = 1; - - if ((arg1 == NULL) || (*arg1 == 0)) - return; - - if ((arg2 == NULL) || (*arg2 == 0)) - { - length = sprintf(&g_argv[0], "%s", arg1); - fake_arg_count = 1; - } - else if ((arg3 == NULL) || (*arg3 == 0)) - { - length = sprintf(&g_argv[0], "%s %s", arg1, arg2); - fake_arg_count = 2; - } - else - { - length = sprintf(&g_argv[0], "%s %s %s", arg1, arg2, arg3); - fake_arg_count = 3; - } - - g_argv[length] = 0; // null terminate just in case - - strcpy(&g_argv[64], arg1); - - if (arg2) - strcpy(&g_argv[128], arg2); - - if (arg3) - strcpy(&g_argv[192], arg3); - - // allow the MOD DLL to execute the ClientCommand... - ClientCommand(pBot); - - isFakeClientCommand = 0; -} - - -const char *Cmd_Args( void ) -{ - if (isFakeClientCommand) - { - return &g_argv[0]; - } - else - { - return (*g_engfuncs.pfnCmd_Args)(); - } -} - - -const char *Cmd_Argv( int argc ) -{ - if (isFakeClientCommand) - { - if (argc == 0) - { - return &g_argv[64]; - } - else if (argc == 1) - { - return &g_argv[128]; - } - else if (argc == 2) - { - return &g_argv[192]; - } - else - { - return NULL; - } - } - else - { - return (*g_engfuncs.pfnCmd_Argv)(argc); - } -} - - -int Cmd_Argc( void ) -{ - if (isFakeClientCommand) - { - return fake_arg_count; - } - else - { - return (*g_engfuncs.pfnCmd_Argc)(); - } -} - - -void ProcessBotCfgFile(void) -{ - int ch; - char cmd_line[256]; - int cmd_index; - static char server_cmd[80]; - char *cmd, *arg1, *arg2, *arg3, *arg4; - char msg[80]; - - if (bot_cfg_pause_time > gpGlobals->time) - return; - - if (bot_cfg_fp == NULL) - return; - - cmd_index = 0; - cmd_line[cmd_index] = 0; - - ch = fgetc(bot_cfg_fp); - - // skip any leading blanks - while (ch == ' ') - ch = fgetc(bot_cfg_fp); - - while ((ch != EOF) && (ch != '\r') && (ch != '\n')) - { - if (ch == '\t') // convert tabs to spaces - ch = ' '; - - cmd_line[cmd_index] = ch; - - ch = fgetc(bot_cfg_fp); - - // skip multiple spaces in input file - while ((cmd_line[cmd_index] == ' ') && - (ch == ' ')) - ch = fgetc(bot_cfg_fp); - - cmd_index++; - } - - if (ch == '\r') // is it a carriage return? - { - ch = fgetc(bot_cfg_fp); // skip the linefeed - } - - // if reached end of file, then close it - if (ch == EOF) - { - fclose(bot_cfg_fp); - - bot_cfg_fp = NULL; - - bot_cfg_pause_time = 0.0; - } - - cmd_line[cmd_index] = 0; // terminate the command line - - // copy the command line to a server command buffer... - strcpy(server_cmd, cmd_line); - strcat(server_cmd, "\n"); - - cmd_index = 0; - cmd = cmd_line; - arg1 = arg2 = arg3 = arg4 = NULL; - - // skip to blank or end of string... - while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) - cmd_index++; - - if (cmd_line[cmd_index] == ' ') - { - cmd_line[cmd_index++] = 0; - arg1 = &cmd_line[cmd_index]; - - // skip to blank or end of string... - while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) - cmd_index++; - - if (cmd_line[cmd_index] == ' ') - { - cmd_line[cmd_index++] = 0; - arg2 = &cmd_line[cmd_index]; - - // skip to blank or end of string... - while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) - cmd_index++; - - if (cmd_line[cmd_index] == ' ') - { - cmd_line[cmd_index++] = 0; - arg3 = &cmd_line[cmd_index]; - - // skip to blank or end of string... - while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) - cmd_index++; - - if (cmd_line[cmd_index] == ' ') - { - cmd_line[cmd_index++] = 0; - arg4 = &cmd_line[cmd_index]; - } - } - } - } - - if ((cmd_line[0] == '#') || (cmd_line[0] == 0)) - return; // return if comment or blank line - - if (strcmp(cmd, "addbot") == 0) - { - BotCreate( NULL, arg1, arg2, arg3, arg4 ); - - // have to delay here or engine gives "Tried to write to - // uninitialized sizebuf_t" error and crashes... - - bot_cfg_pause_time = gpGlobals->time + 2.0; - bot_check_time = gpGlobals->time + 5.0; - - return; - } - - if (strcmp(cmd, "botskill") == 0) - { - int temp = atoi(arg1); - - if ((temp >= 1) && (temp <= 5)) - default_bot_skill = atoi( arg1 ); // set default bot skill level - - return; - } - - if (strcmp(cmd, "observer") == 0) - { - int temp = atoi(arg1); - - if (temp) - b_observer_mode = TRUE; - else - b_observer_mode = FALSE; - - return; - } - - if (strcmp(cmd, "botdontshoot") == 0) - { - int temp = atoi(arg1); - - if (temp) - b_botdontshoot = TRUE; - else - b_botdontshoot = FALSE; - - return; - } - - if (strcmp(cmd, "min_bots") == 0) - { - min_bots = atoi( arg1 ); - - if ((min_bots < 0) || (min_bots > 31)) - min_bots = 1; - - if (IS_DEDICATED_SERVER()) - { - sprintf(msg, "min_bots set to %d\n", min_bots); - printf(msg); - } - - return; - } - - if (strcmp(cmd, "max_bots") == 0) - { - max_bots = atoi( arg1 ); - - if ((max_bots < 0) || (max_bots > 31)) - max_bots = 1; - - if (IS_DEDICATED_SERVER()) - { - sprintf(msg, "max_bots set to %d\n", max_bots); - printf(msg); - } - - return; - } - - if (strcmp(cmd, "pause") == 0) - { - bot_cfg_pause_time = gpGlobals->time + atoi( arg1 ); - - return; - } - - sprintf(msg, "executing server command: %s\n", server_cmd); - ALERT( at_console, msg ); - - if (IS_DEDICATED_SERVER()) - printf(msg); - - SERVER_COMMAND(server_cmd); -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// dll.cpp +// + +#include "dlls/extdll.h" +#include "dlls/enginecallback.h" +#include "dlls/util.h" +#include "dlls/cbase.h" +#include "common/entity_state.h" + +#include "bot.h" +#include "bot_func.h" +#include "waypoint.h" +#include "mod/AvHServerVariables.h" + +#define MENU_NONE 0 +#define MENU_1 1 +#define MENU_2 2 +#define MENU_3 3 + +extern GETENTITYAPI other_GetEntityAPI; +extern GETNEWDLLFUNCTIONS other_GetNewDLLFunctions; +extern enginefuncs_t g_engfuncs; +extern int debug_engine; +extern globalvars_t *gpGlobals; +extern char *g_argv; +extern bool g_waypoint_on; +extern bool g_auto_waypoint; +extern bool g_path_waypoint; +extern int num_waypoints; // number of waypoints currently in use +extern WAYPOINT waypoints[MAX_WAYPOINTS]; +extern float wp_display_time[MAX_WAYPOINTS]; +extern bot_t bots[32]; +extern bool b_observer_mode; +extern bool b_botdontshoot; +//char welcome_msg[] = "HPB bot - http://planethalflife.com/botman"; + +static FILE *fp; + +DLL_FUNCTIONS other_gFunctionTable; +DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); + +// AvH dll +int mod_id = AVH_DLL; +int m_spriteTexture = 0; +int default_bot_skill = 4; +int isFakeClientCommand = 0; +int fake_arg_count; +float bot_check_time = 30.0; +int min_bots = -1; +int max_bots = -1; +int num_bots = 0; +int prev_num_bots = 0; +bool g_GameRules = FALSE; +edict_t *clients[32]; +edict_t *listenserver_edict = NULL; +float welcome_time = 0.0; +bool welcome_sent = FALSE; +int g_menu_waypoint; +int g_menu_state = 0; + +float is_team_play = 0.0; +char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; +int num_teams = 0; +bool checked_teamplay = FALSE; +edict_t *pent_info_tfdetect = NULL; +edict_t *pent_info_ctfdetect = NULL; +edict_t *pent_info_frontline = NULL; +edict_t *pent_item_tfgoal = NULL; +int max_team_players[4]; // for TFC +int team_class_limits[4]; // for TFC +int team_allies[4]; // TFC bit mapped allies BLUE, RED, YELLOW, and GREEN +int max_teams = 0; // for TFC +FLAG_S flags[MAX_FLAGS]; // for TFC +int num_flags = 0; // for TFC + +FILE *bot_cfg_fp = NULL; +bool need_to_open_cfg = TRUE; +float bot_cfg_pause_time = 0.0; +float respawn_time = 0.0; +bool spawn_time_reset = FALSE; + +int flf_bug_fix; // for FLF 1.1 capture point bug +int flf_bug_check; // for FLF 1.1 capture point bug + + +char bot_whine[MAX_BOT_WHINE][81]; +int whine_count; +int recent_bot_whine[5]; + +cvar_t sv_bot = {"bot",""}; +cvar_t sv_freezebots = {"freezebots","0"}; + +char *show_menu_1 = + {"Waypoint Tags\n\n1. Team Specific\n2. Wait for Lift\n3. Door\n4. Sniper Spot\n5. More..."}; +char *show_menu_2 = + {"Waypoint Tags\n\n1. Team 1\n2. Team 2\n3. Team 3\n4. Team 4\n5. CANCEL"}; +char *show_menu_2_flf = + {"Waypoint Tags\n\n1. Attackers\n2. Defenders\n\n5. CANCEL"}; +char *show_menu_3 = + {"Waypoint Tags\n\n1. Flag Location\n2. Flag Goal Location\n\n5. CANCEL"}; +char *show_menu_3_flf = + {"Waypoint Tags\n\n1. Capture Point\n2. Defend Point\n3. Prone\n\n5. CANCEL"}; + + +void BotNameInit(void); +void UpdateClientData(const struct edict_s *ent, int sendweapons, struct clientdata_s *cd); +void ProcessBotCfgFile(void); + + +void GameDLLInit( void ) +{ + char filename[256]; + char buffer[256]; + int i, length; + FILE *bfp; + char *ptr; + + CVAR_REGISTER (&sv_bot); + CVAR_REGISTER (&sv_freezebots); + + for (i=0; i<32; i++) + clients[i] = NULL; + + whine_count = 0; + + // initialize the bots array of structures... + memset(bots, 0, sizeof(bots)); + + for (i=0; i < 5; i++) + recent_bot_whine[i] = -1; + + BotNameInit(); + + + UTIL_BuildFileName(filename, "bot_whine.txt", NULL); + + bfp = fopen(filename, "r"); + + if (bfp != NULL) + { + while ((whine_count < MAX_BOT_WHINE) && + (fgets(buffer, 80, bfp) != NULL)) + { + length = strlen(buffer); + + if (buffer[length-1] == '\n') + { + buffer[length-1] = 0; // remove '\n' + length--; + } + + if ((ptr = strstr(buffer, "%n")) != NULL) + { + *(ptr+1) = 's'; // change %n to %s + } + + if (length > 0) + { + strcpy(bot_whine[whine_count], buffer); + whine_count++; + } + } + + fclose(bfp); + } + + (*other_gFunctionTable.pfnGameInit)(); +} + +int DispatchSpawn( edict_t *pent ) +{ + int index; + + if (gpGlobals->deathmatch) + { + char *pClassname = (char *)STRING(pent->v.classname); + + if (debug_engine) + { + fp=fopen("bot.txt","a"); + fprintf(fp, "DispatchSpawn: %x %s\n",pent,pClassname); + if (pent->v.model != 0) + fprintf(fp, " model=%s\n",STRING(pent->v.model)); + fclose(fp); + } + + if (strcmp(pClassname, "worldspawn") == 0) + { + // do level initialization stuff here... + + WaypointInit(); + WaypointLoad(NULL); + + pent_info_tfdetect = NULL; + pent_info_ctfdetect = NULL; + pent_info_frontline = NULL; + pent_item_tfgoal = NULL; + + for (index=0; index < 4; index++) + { + max_team_players[index] = 0; // no player limit + team_class_limits[index] = 0; // no class limits + team_allies[index] = 0; + } + + max_teams = 0; + num_flags = 0; + + PRECACHE_SOUND("weapons/xbow_hit1.wav"); // waypoint add + PRECACHE_SOUND("weapons/mine_activate.wav"); // waypoint delete + PRECACHE_SOUND("common/wpn_hudoff.wav"); // path add/delete start + PRECACHE_SOUND("common/wpn_hudon.wav"); // path add/delete done + PRECACHE_SOUND("common/wpn_moveselect.wav"); // path add/delete cancel + PRECACHE_SOUND("common/wpn_denyselect.wav"); // path add/delete error + + m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr"); + + g_GameRules = TRUE; + + is_team_play = 0.0; + memset(team_names, 0, sizeof(team_names)); + num_teams = 0; + checked_teamplay = FALSE; + + bot_cfg_pause_time = 0.0; + respawn_time = 0.0; + spawn_time_reset = FALSE; + + prev_num_bots = num_bots; + num_bots = 0; + + flf_bug_fix = 0; + flf_bug_check = 0; + + bot_check_time = gpGlobals->time + 30.0; + } + } + + return (*other_gFunctionTable.pfnSpawn)(pent); +} + +void DispatchThink( edict_t *pent ) +{ + (*other_gFunctionTable.pfnThink)(pent); +} + +void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) +{ + (*other_gFunctionTable.pfnUse)(pentUsed, pentOther); +} + +void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) +{ + (*other_gFunctionTable.pfnTouch)(pentTouched, pentOther); +} + +void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) +{ + (*other_gFunctionTable.pfnBlocked)(pentBlocked, pentOther); +} + +void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) +{ + static edict_t *temp_pent; + static int flag_index; + +// fp=fopen("bot.txt","a"); fprintf(fp, "DispatchKeyValue: %x %s=%s\n",pentKeyvalue,pkvd->szKeyName,pkvd->szValue); fclose(fp); + + if (mod_id == TFC_DLL) + { + if (pentKeyvalue == pent_info_tfdetect) + { + if (strcmp(pkvd->szKeyName, "ammo_medikit") == 0) // max BLUE players + max_team_players[0] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "ammo_detpack") == 0) // max RED players + max_team_players[1] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "maxammo_medikit") == 0) // max YELLOW players + max_team_players[2] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "maxammo_detpack") == 0) // max GREEN players + max_team_players[3] = atoi(pkvd->szValue); + + else if (strcmp(pkvd->szKeyName, "maxammo_shells") == 0) // BLUE class limits + team_class_limits[0] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "maxammo_nails") == 0) // RED class limits + team_class_limits[1] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "maxammo_rockets") == 0) // YELLOW class limits + team_class_limits[2] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "maxammo_cells") == 0) // GREEN class limits + team_class_limits[3] = atoi(pkvd->szValue); + + else if (strcmp(pkvd->szKeyName, "team1_allies") == 0) // BLUE allies + team_allies[0] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "team2_allies") == 0) // RED allies + team_allies[1] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "team3_allies") == 0) // YELLOW allies + team_allies[2] = atoi(pkvd->szValue); + else if (strcmp(pkvd->szKeyName, "team4_allies") == 0) // GREEN allies + team_allies[3] = atoi(pkvd->szValue); + } + else if (pent_info_tfdetect == NULL) + { + if ((strcmp(pkvd->szKeyName, "classname") == 0) && + (strcmp(pkvd->szValue, "info_tfdetect") == 0)) + { + pent_info_tfdetect = pentKeyvalue; + } + } + + if (pentKeyvalue == pent_item_tfgoal) + { + if (strcmp(pkvd->szKeyName, "team_no") == 0) + flags[flag_index].team_no = atoi(pkvd->szValue); + + if ((strcmp(pkvd->szKeyName, "mdl") == 0) && + ((strcmp(pkvd->szValue, "models/flag.mdl") == 0) || + (strcmp(pkvd->szValue, "models/keycard.mdl") == 0) || + (strcmp(pkvd->szValue, "models/ball.mdl") == 0))) + { + flags[flag_index].mdl_match = TRUE; + num_flags++; + } + } + else if (pent_item_tfgoal == NULL) + { + if ((strcmp(pkvd->szKeyName, "classname") == 0) && + (strcmp(pkvd->szValue, "item_tfgoal") == 0)) + { + if (num_flags < MAX_FLAGS) + { + pent_item_tfgoal = pentKeyvalue; + + flags[num_flags].mdl_match = FALSE; + flags[num_flags].team_no = 0; // any team unless specified + flags[num_flags].edict = pentKeyvalue; + + flag_index = num_flags; // in case the mdl comes before team_no + } + } + } + else + { + pent_item_tfgoal = NULL; // reset for non-flag item_tfgoal's + } + + if ((strcmp(pkvd->szKeyName, "classname") == 0) && + ((strcmp(pkvd->szValue, "info_player_teamspawn") == 0) || + (strcmp(pkvd->szValue, "i_p_t") == 0))) + { + temp_pent = pentKeyvalue; + } + else if (pentKeyvalue == temp_pent) + { + if (strcmp(pkvd->szKeyName, "team_no") == 0) + { + int value = atoi(pkvd->szValue); + + if (value > max_teams) + max_teams = value; + } + } + } + else if (mod_id == GEARBOX_DLL) + { + if (pent_info_ctfdetect == NULL) + { + if ((strcmp(pkvd->szKeyName, "classname") == 0) && + (strcmp(pkvd->szValue, "info_ctfdetect") == 0)) + { + pent_info_ctfdetect = pentKeyvalue; + } + } + } + + (*other_gFunctionTable.pfnKeyValue)(pentKeyvalue, pkvd); +} + +void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) +{ + (*other_gFunctionTable.pfnSave)(pent, pSaveData); +} + +int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) +{ + return (*other_gFunctionTable.pfnRestore)(pent, pSaveData, globalEntity); +} + +void DispatchObjectCollsionBox( edict_t *pent ) +{ + (*other_gFunctionTable.pfnSetAbsBox)(pent); +} + +void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + (*other_gFunctionTable.pfnSaveWriteFields)(pSaveData, pname, pBaseData, pFields, fieldCount); +} + +void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + (*other_gFunctionTable.pfnSaveReadFields)(pSaveData, pname, pBaseData, pFields, fieldCount); +} + +void SaveGlobalState( SAVERESTOREDATA *pSaveData ) +{ + (*other_gFunctionTable.pfnSaveGlobalState)(pSaveData); +} + +void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) +{ + (*other_gFunctionTable.pfnRestoreGlobalState)(pSaveData); +} + +void ResetGlobalState( void ) +{ + (*other_gFunctionTable.pfnResetGlobalState)(); +} + +BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +{ + if (gpGlobals->deathmatch) + { + int i; + int count = 0; + + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientConnect: pent=%x name=%s\n",pEntity,pszName); fclose(fp); } + + // check if this client is the listen server client + if (strcmp(pszAddress, "loopback") == 0) + { + // save the edict of the listen server client... + listenserver_edict = pEntity; + } + + // check if this is NOT a bot joining the server... + if (strcmp(pszAddress, "127.0.0.1") != 0) + { + // don't try to add bots for 60 seconds, give client time to get added + bot_check_time = gpGlobals->time + 60.0; + + for (i=0; i < 32; i++) + { + if (bots[i].is_used) // count the number of bots in use + count++; + } + + // if there are currently more than the minimum number of bots running + // then kick one of the bots off the server... + if ((count > min_bots) && (min_bots != -1)) + { + for (i=0; i < 32; i++) + { + if (bots[i].is_used) // is this slot used? + { + char cmd[80]; + + sprintf(cmd, "kick \"%s\"\n", bots[i].name); + + SERVER_COMMAND(cmd); // kick the bot using (kick "name") + + break; + } + } + } + } + } + + return (*other_gFunctionTable.pfnClientConnect)(pEntity, pszName, pszAddress, szRejectReason); +} + +void ClientDisconnect( edict_t *pEntity ) +{ + if (gpGlobals->deathmatch) + { + int i; + + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientDisconnect: %x\n",pEntity); fclose(fp); } + + i = 0; + while ((i < 32) && (clients[i] != pEntity)) + i++; + + if (i < 32) + clients[i] = NULL; + + + for (i=0; i < 32; i++) + { + if (bots[i].pEdict == pEntity) + { + // someone kicked this bot off of the server... + + bots[i].is_used = FALSE; // this slot is now free to use + + bots[i].kick_time = gpGlobals->time; // save the kicked time + + break; + } + } + } + + (*other_gFunctionTable.pfnClientDisconnect)(pEntity); +} + +void ClientKill( edict_t *pEntity ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientKill: %x\n",pEntity); fclose(fp); } + (*other_gFunctionTable.pfnClientKill)(pEntity); +} + +void ClientPutInServer( edict_t *pEntity ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp, "ClientPutInServer: %x\n",pEntity); fclose(fp); } + + int i = 0; + + while ((i < 32) && (clients[i] != NULL)) + i++; + + if (i < 32) + clients[i] = pEntity; // store this clients edict in the clients array + + (*other_gFunctionTable.pfnClientPutInServer)(pEntity); +} + +void ClientCommand( edict_t *pEntity ) +{ + // only allow custom commands if deathmatch mode and NOT dedicated server and + // client sending command is the listen server client... + + if ((gpGlobals->deathmatch) && /*(!IS_DEDICATED_SERVER()) &&*/ + (pEntity == listenserver_edict)) + { + const char *pcmd = Cmd_Argv(0); + const char *arg1 = Cmd_Argv(1); + const char *arg2 = Cmd_Argv(2); + const char *arg3 = Cmd_Argv(3); + const char *arg4 = Cmd_Argv(4); + char msg[80]; + + if (debug_engine) + { + fp=fopen("bot.txt","a"); fprintf(fp,"ClientCommand: %s",pcmd); + if ((arg1 != NULL) && (*arg1 != 0)) + fprintf(fp," %s", arg1); + if ((arg2 != NULL) && (*arg2 != 0)) + fprintf(fp," %s", arg2); + if ((arg3 != NULL) && (*arg3 != 0)) + fprintf(fp," %s", arg3); + if ((arg4 != NULL) && (*arg4 != 0)) + fprintf(fp," %s", arg4); + fprintf(fp, "\n"); + fclose(fp); + } + + if (FStrEq(pcmd, "addbot")) + { + BotCreate( pEntity, arg1, arg2, arg3, arg4 ); + + bot_check_time = gpGlobals->time + 5.0; + + return; + } + else if (FStrEq(pcmd, "observer")) + { + if ((arg1 != NULL) && (*arg1 != 0)) + { + int temp = atoi(arg1); + if (temp) + b_observer_mode = TRUE; + else + b_observer_mode = FALSE; + } + + if (b_observer_mode) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "observer mode ENABLED\n"); + else + ClientPrint(pEntity, HUD_PRINTNOTIFY, "observer mode DISABLED\n"); + + return; + } + else if (FStrEq(pcmd, "botskill")) + { + if ((arg1 != NULL) && (*arg1 != 0)) + { + int temp = atoi(arg1); + + if ((temp < 1) || (temp > 5)) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid botskill value!\n"); + else + default_bot_skill = temp; + } + + sprintf(msg, "botskill is %d\n", default_bot_skill); + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + + return; + } + else if (FStrEq(pcmd, "botdontshoot")) + { + if ((arg1 != NULL) && (*arg1 != 0)) + { + int temp = atoi(arg1); + if (temp) + b_botdontshoot = TRUE; + else + b_botdontshoot = FALSE; + } + + if (b_botdontshoot) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "botdontshoot ENABLED\n"); + else + ClientPrint(pEntity, HUD_PRINTNOTIFY, "botdontshoot DISABLED\n"); + + return; + } + else if (FStrEq(pcmd, "debug_engine")) + { + debug_engine = 1; + + ClientPrint(pEntity, HUD_PRINTNOTIFY, "debug_engine enabled!\n"); + + return; + } + else if (FStrEq(pcmd, "waypoint")) + { + if (FStrEq(arg1, "on")) + { + g_waypoint_on = TRUE; + + ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are ON\n"); + } + else if (FStrEq(arg1, "off")) + { + g_waypoint_on = FALSE; + + ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are OFF\n"); + } + else if (FStrEq(arg1, "add")) + { + if (!g_waypoint_on) + g_waypoint_on = TRUE; // turn waypoints on if off + + WaypointAdd(pEntity); + } + else if (FStrEq(arg1, "delete")) + { + if (!g_waypoint_on) + g_waypoint_on = TRUE; // turn waypoints on if off + + WaypointDelete(pEntity); + } + else if (FStrEq(arg1, "save")) + { + WaypointSave(); + + ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints saved\n"); + } + else if (FStrEq(arg1, "load")) + { + if (WaypointLoad(pEntity)) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints loaded\n"); + } + else if (FStrEq(arg1, "menu")) + { + int index; + + if (num_waypoints < 1) + return; + + index = WaypointFindNearest(pEntity, 50.0, -1); + + if (index == -1) + return; + + g_menu_waypoint = index; + g_menu_state = MENU_1; + + UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_1); + } + else if (FStrEq(arg1, "info")) + { + WaypointPrintInfo(pEntity); + } + else + { + if (g_waypoint_on) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are ON\n"); + else + ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are OFF\n"); + } + + return; + } + else if (FStrEq(pcmd, "autowaypoint")) + { + if (FStrEq(arg1, "on")) + { + g_auto_waypoint = TRUE; + g_waypoint_on = TRUE; // turn this on just in case + } + else if (FStrEq(arg1, "off")) + { + g_auto_waypoint = FALSE; + } + + if (g_auto_waypoint) + sprintf(msg, "autowaypoint is ON\n"); + else + sprintf(msg, "autowaypoint is OFF\n"); + + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + + return; + } + else if (FStrEq(pcmd, "pathwaypoint")) + { + if (FStrEq(arg1, "on")) + { + g_path_waypoint = TRUE; + g_waypoint_on = TRUE; // turn this on just in case + + ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is ON\n"); + } + else if (FStrEq(arg1, "off")) + { + g_path_waypoint = FALSE; + + ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is OFF\n"); + } + else if (FStrEq(arg1, "create1")) + { + WaypointCreatePath(pEntity, 1); + } + else if (FStrEq(arg1, "create2")) + { + WaypointCreatePath(pEntity, 2); + } + else if (FStrEq(arg1, "remove1")) + { + WaypointRemovePath(pEntity, 1); + } + else if (FStrEq(arg1, "remove2")) + { + WaypointRemovePath(pEntity, 2); + } + + return; + } + else if (FStrEq(pcmd, "menuselect") && (g_menu_state != MENU_NONE)) + { + if (g_menu_state == MENU_1) // main menu... + { + if (FStrEq(arg1, "1")) // team specific... + { + g_menu_state = MENU_2; // display team specific menu... + + if (mod_id == FRONTLINE_DLL) + UTIL_ShowMenu(pEntity, 0x13, -1, FALSE, show_menu_2_flf); + else + UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_2); + + return; + } + else if (FStrEq(arg1, "2")) // wait for lift... + { + if (waypoints[g_menu_waypoint].flags & W_FL_LIFT) + waypoints[g_menu_waypoint].flags &= ~W_FL_LIFT; // off + else + waypoints[g_menu_waypoint].flags |= W_FL_LIFT; // on + } + else if (FStrEq(arg1, "3")) // door waypoint + { + if (waypoints[g_menu_waypoint].flags & W_FL_DOOR) + waypoints[g_menu_waypoint].flags &= ~W_FL_DOOR; // off + else + waypoints[g_menu_waypoint].flags |= W_FL_DOOR; // on + } + else if (FStrEq(arg1, "4")) // sniper spot + { + if (waypoints[g_menu_waypoint].flags & W_FL_SNIPER) + waypoints[g_menu_waypoint].flags &= ~W_FL_SNIPER; // off + else + { + waypoints[g_menu_waypoint].flags |= W_FL_SNIPER; // on + + // set the aiming waypoint... + + WaypointAddAiming(pEntity); + } + } + else if (FStrEq(arg1, "5")) // more... + { + g_menu_state = MENU_3; + + if (mod_id == FRONTLINE_DLL) + UTIL_ShowMenu(pEntity, 0x17, -1, FALSE, show_menu_3_flf); + else + UTIL_ShowMenu(pEntity, 0x13, -1, FALSE, show_menu_3); + + return; + } + } + else if (g_menu_state == MENU_2) // team specific menu + { + if (waypoints[g_menu_waypoint].flags & W_FL_TEAM_SPECIFIC) + { + waypoints[g_menu_waypoint].flags &= ~W_FL_TEAM; + waypoints[g_menu_waypoint].flags &= ~W_FL_TEAM_SPECIFIC; // off + } + else + { + int team = atoi(arg1); + + team--; // make 0 to 3 + + // this is kind of a kludge (team bits MUST be LSB!!!) + waypoints[g_menu_waypoint].flags |= team; + waypoints[g_menu_waypoint].flags |= W_FL_TEAM_SPECIFIC; // on + } + } + else if (g_menu_state == MENU_3) // second menu... + { + if (mod_id == FRONTLINE_DLL) + { + if (FStrEq(arg1, "1")) // capture point + { + if (waypoints[g_menu_waypoint].flags & W_FL_FLF_CAP) + waypoints[g_menu_waypoint].flags &= ~W_FL_FLF_CAP; // off + else + waypoints[g_menu_waypoint].flags |= W_FL_FLF_CAP; // on + } + else if (FStrEq(arg1, "2")) // defend point + { + if (waypoints[g_menu_waypoint].flags & W_FL_FLF_DEFEND) + waypoints[g_menu_waypoint].flags &= ~W_FL_FLF_DEFEND; // off + else + { + waypoints[g_menu_waypoint].flags |= W_FL_FLF_DEFEND; // on + + // set the aiming waypoint... + + WaypointAddAiming(pEntity); + } + } + else if (FStrEq(arg1, "3")) // go prone + { + if (waypoints[g_menu_waypoint].flags & W_FL_PRONE) + waypoints[g_menu_waypoint].flags &= ~W_FL_PRONE; // off + else + waypoints[g_menu_waypoint].flags |= W_FL_PRONE; // on + } + } + else + { + if (FStrEq(arg1, "1")) // flag location + { + if (waypoints[g_menu_waypoint].flags & W_FL_TFC_FLAG) + waypoints[g_menu_waypoint].flags &= ~W_FL_TFC_FLAG; // off + else + waypoints[g_menu_waypoint].flags |= W_FL_TFC_FLAG; // on + } + else if (FStrEq(arg1, "2")) // flag goal + { + if (waypoints[g_menu_waypoint].flags & W_FL_TFC_FLAG_GOAL) + waypoints[g_menu_waypoint].flags &= ~W_FL_TFC_FLAG_GOAL; // off + else + waypoints[g_menu_waypoint].flags |= W_FL_TFC_FLAG_GOAL; // on + } + } + } + + g_menu_state = MENU_NONE; + + return; + } + else if (FStrEq(pcmd, "search")) + { + edict_t *pent = NULL; + float radius = 50; + char str[80]; + + ClientPrint(pEntity, HUD_PRINTCONSOLE, "searching...\n"); + + while ((pent = UTIL_FindEntityInSphere( pent, pEntity->v.origin, radius )) != NULL) + { + sprintf(str, "Found %s at %5.2f %5.2f %5.2f\n", + STRING(pent->v.classname), + pent->v.origin.x, pent->v.origin.y, + pent->v.origin.z); + ClientPrint(pEntity, HUD_PRINTCONSOLE, str); + + FILE *fp=fopen("bot.txt", "a"); + fprintf(fp, "ClientCommmand: search %s", str); + fclose(fp); + } + + return; + } + } + + (*other_gFunctionTable.pfnClientCommand)(pEntity); +} + +void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) +{ + if (debug_engine) { fp=fopen("bot.txt", "a"); fprintf(fp, "ClientUserInfoChanged: pEntity=%x infobuffer=%s\n", pEntity, infobuffer); fclose(fp); } + + (*other_gFunctionTable.pfnClientUserInfoChanged)(pEntity, infobuffer); +} + +void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) +{ + (*other_gFunctionTable.pfnServerActivate)(pEdictList, edictCount, clientMax); +} + +void ServerDeactivate( void ) +{ + (*other_gFunctionTable.pfnServerDeactivate)(); +} + +void PlayerPreThink( edict_t *pEntity ) +{ + (*other_gFunctionTable.pfnPlayerPreThink)(pEntity); +} + +void PlayerPostThink( edict_t *pEntity ) +{ + (*other_gFunctionTable.pfnPlayerPostThink)(pEntity); +} + +void StartFrame( void ) +{ + if (gpGlobals->deathmatch) + { + edict_t *pPlayer; + static float check_server_cmd = 0.0; + static int i, index, player_index, bot_index; + static float previous_time = -1.0; + static float client_update_time = 0.0; + clientdata_s cd; + char msg[256]; + int count; + + // if a new map has started then (MUST BE FIRST IN StartFrame)... + if ((gpGlobals->time + 0.1) < previous_time) + { + char filename[256]; + char mapname[64]; + + check_server_cmd = 0.0; // reset at start of map + + // check if mapname_bot.cfg file exists... + + strcpy(mapname, STRING(gpGlobals->mapname)); + strcat(mapname, "_bot.cfg"); + + UTIL_BuildFileName(filename, "maps", mapname); + + if ((bot_cfg_fp = fopen(filename, "r")) != NULL) + { + sprintf(msg, "Executing %s\n", filename); + ALERT( at_console, msg ); + + for (index = 0; index < 32; index++) + { + bots[index].is_used = FALSE; + bots[index].respawn_state = 0; + bots[index].kick_time = 0.0; + } + + if (IS_DEDICATED_SERVER()) + bot_cfg_pause_time = gpGlobals->time + 5.0; + else + bot_cfg_pause_time = gpGlobals->time + 20.0; + } + else + { + count = 0; + + // mark the bots as needing to be respawned... + for (index = 0; index < 32; index++) + { + if (count >= prev_num_bots) + { + bots[index].is_used = FALSE; + bots[index].respawn_state = 0; + bots[index].kick_time = 0.0; + } + + if (bots[index].is_used) // is this slot used? + { + bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; + count++; + } + + // check for any bots that were very recently kicked... + if ((bots[index].kick_time + 5.0) > previous_time) + { + bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; + count++; + } + else + bots[index].kick_time = 0.0; // reset to prevent false spawns later + } + + // set the respawn time + if (IS_DEDICATED_SERVER()) + respawn_time = gpGlobals->time + 5.0; + else + respawn_time = gpGlobals->time + 20.0; + } + + client_update_time = gpGlobals->time + 10.0; // start updating client data again + + bot_check_time = gpGlobals->time + 30.0; + } + + if (!IS_DEDICATED_SERVER()) + { + if ((listenserver_edict != NULL) && (welcome_sent == FALSE) && + (welcome_time < 1.0)) + { + // are they out of observer mode yet? + if (IsAlive(listenserver_edict)) + welcome_time = gpGlobals->time + 5.0; // welcome in 5 seconds + } + + if ((welcome_time > 0.0) && (welcome_time < gpGlobals->time) && + (welcome_sent == FALSE)) + { + // let's send a welcome message to this client... + //UTIL_SayText(welcome_msg, listenserver_edict); + + welcome_sent = TRUE; // clear this so we only do it once + } + } + + if (client_update_time <= gpGlobals->time) + { + client_update_time = gpGlobals->time + 1.0; + + for (i=0; i < 32; i++) + { + if (bots[i].is_used) + { + memset(&cd, 0, sizeof(cd)); + + UpdateClientData( bots[i].pEdict, 1, &cd ); + + // see if a weapon was dropped... + if (bots[i].bot_weapons != cd.weapons) + { + bots[i].bot_weapons = cd.weapons; + } + } + } + } + + count = 0; + + for (bot_index = 0; bot_index < gpGlobals->maxClients; bot_index++) + { + if ((bots[bot_index].is_used) && // is this slot used AND + (bots[bot_index].respawn_state == RESPAWN_IDLE)) // not respawning + { + BotThink(&bots[bot_index]); + + count++; + + if ((mod_id == FRONTLINE_DLL) && (flf_bug_check == 0)) + { + edict_t *pent = NULL; + int fix_flag = 0; + + flf_bug_check = 1; + + while ((pent = UTIL_FindEntityByClassname( pent, "capture_point" )) != NULL) + { + if (pent->v.skin != 0) // not blue skin? + { + flf_bug_fix = 1; // need to use bug fix code + } + } + } + } + } + + if (count > num_bots) + num_bots = count; + + for (player_index = 1; player_index <= gpGlobals->maxClients; player_index++) + { + pPlayer = INDEXENT(player_index); + + if (pPlayer && !pPlayer->free) + { + if ((g_waypoint_on) && FBitSet(pPlayer->v.flags, FL_CLIENT)) + { + WaypointThink(pPlayer); + } + + if ((mod_id == FRONTLINE_DLL) && (flf_bug_check == 0)) + { + edict_t *pent = NULL; + int fix_flag = 0; + + flf_bug_check = 1; + + while ((pent = UTIL_FindEntityByClassname( pent, "capture_point" )) != NULL) + { + if (pent->v.skin != 0) // not blue skin? + { + flf_bug_fix = 1; // need to use bug fix code + } + } + } + } + } + + // are we currently respawning bots and is it time to spawn one yet? + if ((respawn_time > 1.0) && (respawn_time <= gpGlobals->time)) + { + int index = 0; + + // find bot needing to be respawned... + while ((index < 32) && + (bots[index].respawn_state != RESPAWN_NEED_TO_RESPAWN)) + index++; + + if (index < 32) + { + bots[index].respawn_state = RESPAWN_IS_RESPAWNING; + bots[index].is_used = FALSE; // free up this slot + + // respawn 1 bot then wait a while (otherwise engine crashes) + if ((mod_id == VALVE_DLL) || + ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect == NULL))) + { + char c_skill[2]; + + sprintf(c_skill, "%d", bots[index].bot_skill); + + BotCreate(NULL, bots[index].skin, bots[index].name, c_skill, NULL); + } + else + { + char c_skill[2]; + char c_team[2]; + char c_class[3]; + + sprintf(c_skill, "%d", bots[index].bot_skill); + sprintf(c_team, "%d", bots[index].bot_team); + sprintf(c_class, "%d", bots[index].bot_class); + + if ((mod_id == TFC_DLL) || (mod_id == GEARBOX_DLL)) + BotCreate(NULL, NULL, NULL, bots[index].name, c_skill); + else + BotCreate(NULL, c_team, c_class, bots[index].name, c_skill); + } + + respawn_time = gpGlobals->time + 2.0; // set next respawn time + + bot_check_time = gpGlobals->time + 5.0; + } + else + { + respawn_time = 0.0; + } + } + + if (g_GameRules) + { + if (need_to_open_cfg) // have we open bot.cfg file yet? + { + char filename[256]; + char mapname[64]; + + need_to_open_cfg = FALSE; // only do this once!!! + + // check if mapname_bot.cfg file exists... + + strcpy(mapname, STRING(gpGlobals->mapname)); + strcat(mapname, "_bot.cfg"); + + UTIL_BuildFileName(filename, "maps", mapname); + + if ((bot_cfg_fp = fopen(filename, "r")) != NULL) + { + sprintf(msg, "Executing %s\n", filename); + ALERT( at_console, msg ); + } + else + { + UTIL_BuildFileName(filename, "bot.cfg", NULL); + + sprintf(msg, "Executing %s\n", filename); + ALERT( at_console, msg ); + + bot_cfg_fp = fopen(filename, "r"); + + if (bot_cfg_fp == NULL) + ALERT( at_console, "bot.cfg file not found\n" ); + } + + if (IS_DEDICATED_SERVER()) + bot_cfg_pause_time = gpGlobals->time + 5.0; + else + bot_cfg_pause_time = gpGlobals->time + 20.0; + } + + if (!IS_DEDICATED_SERVER() && !spawn_time_reset) + { + if (listenserver_edict != NULL) + { + if (IsAlive(listenserver_edict)) + { + spawn_time_reset = TRUE; + + if (respawn_time >= 1.0) + respawn_time = min(respawn_time, gpGlobals->time + (float)1.0); + + if (bot_cfg_pause_time >= 1.0) + bot_cfg_pause_time = min(bot_cfg_pause_time, gpGlobals->time + (float)1.0); + } + } + } + + if ((bot_cfg_fp) && + (bot_cfg_pause_time >= 1.0) && (bot_cfg_pause_time <= gpGlobals->time)) + { + // process bot.cfg file options... + ProcessBotCfgFile(); + } + + } + + // if time to check for server commands then do so... + if ((check_server_cmd <= gpGlobals->time) && IS_DEDICATED_SERVER()) + { + check_server_cmd = gpGlobals->time + 1.0; + + char *cvar_bot = (char *)CVAR_GET_STRING( "bot" ); + + if ( cvar_bot && cvar_bot[0] ) + { + char cmd_line[80]; + char *cmd, *arg1, *arg2, *arg3, *arg4; + + strcpy(cmd_line, cvar_bot); + + index = 0; + cmd = cmd_line; + arg1 = arg2 = arg3 = arg4 = NULL; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg1 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg2 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg3 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg4 = &cmd_line[index]; + } + } + } + } + + if (strcmp(cmd, "addbot") == 0) + { + BotCreate( NULL, arg1, arg2, arg3, arg4 ); + + bot_check_time = gpGlobals->time + 5.0; + } + else if (strcmp(cmd, "min_bots") == 0) + { + min_bots = atoi( arg1 ); + + if ((min_bots < 0) || (min_bots > 31)) + min_bots = 1; + + sprintf(msg, "min_bots set to %d\n", min_bots); + printf(msg); + } + else if (strcmp(cmd, "max_bots") == 0) + { + max_bots = atoi( arg1 ); + + if ((max_bots < 0) || (max_bots > 31)) + max_bots = 1; + + sprintf(msg, "max_bots set to %d\n", max_bots); + printf(msg); + } + + CVAR_SET_STRING("bot", ""); + } + } + + // check if time to see if a bot needs to be created... + if (bot_check_time < gpGlobals->time) + { + int count = 0; + + bot_check_time = gpGlobals->time + 5.0; + + for (i = 0; i < 32; i++) + { + if (clients[i] != NULL) + count++; + } + + // if there are currently less than the maximum number of "players" + // then add another bot using the default skill level... + if ((count < max_bots) && (max_bots != -1)) + { + BotCreate( NULL, NULL, NULL, NULL, NULL ); + } + } + + previous_time = gpGlobals->time; + } + + (*other_gFunctionTable.pfnStartFrame)(); +} + +void ParmsNewLevel( void ) +{ + (*other_gFunctionTable.pfnParmsNewLevel)(); +} + +void ParmsChangeLevel( void ) +{ + (*other_gFunctionTable.pfnParmsChangeLevel)(); +} + +const char *GetGameDescription( void ) +{ + return (*other_gFunctionTable.pfnGetGameDescription)(); +} + +void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) +{ + if (debug_engine) { fp=fopen("bot.txt", "a"); fprintf(fp, "PlayerCustomization: %x\n",pEntity); fclose(fp); } + + (*other_gFunctionTable.pfnPlayerCustomization)(pEntity, pCust); +} + +void SpectatorConnect( edict_t *pEntity ) +{ + (*other_gFunctionTable.pfnSpectatorConnect)(pEntity); +} + +void SpectatorDisconnect( edict_t *pEntity ) +{ + (*other_gFunctionTable.pfnSpectatorDisconnect)(pEntity); +} + +void SpectatorThink( edict_t *pEntity ) +{ + (*other_gFunctionTable.pfnSpectatorThink)(pEntity); +} + +void Sys_Error( const char *error_string ) +{ + (*other_gFunctionTable.pfnSys_Error)(error_string); +} + +void PM_Move ( struct playermove_s *ppmove, int server ) +{ + (*other_gFunctionTable.pfnPM_Move)(ppmove, server); +} + +void PM_Init ( struct playermove_s *ppmove ) +{ + (*other_gFunctionTable.pfnPM_Init)(ppmove); +} + +char PM_FindTextureType( char *name ) +{ + return (*other_gFunctionTable.pfnPM_FindTextureType)(name); +} + +void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) +{ + (*other_gFunctionTable.pfnSetupVisibility)(pViewEntity, pClient, pvs, pas); +} + +void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +{ + (*other_gFunctionTable.pfnUpdateClientData)(ent, sendweapons, cd); +} + +int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) +{ + return (*other_gFunctionTable.pfnAddToFullPack)(state, e, ent, host, hostflags, player, pSet); +} + +void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) +{ + (*other_gFunctionTable.pfnCreateBaseline)(player, eindex, baseline, entity, playermodelindex, player_mins, player_maxs); +} + +void RegisterEncoders( void ) +{ + (*other_gFunctionTable.pfnRegisterEncoders)(); +} + +int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) +{ + return (*other_gFunctionTable.pfnGetWeaponData)(player, info); +} + +void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) +{ + (*other_gFunctionTable.pfnCmdStart)(player, cmd, random_seed); +} + +void CmdEnd ( const edict_t *player ) +{ + (*other_gFunctionTable.pfnCmdEnd)(player); +} + +int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + return (*other_gFunctionTable.pfnConnectionlessPacket)(net_from, args, response_buffer, response_buffer_size); +} + +int GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + return (*other_gFunctionTable.pfnGetHullBounds)(hullnumber, mins, maxs); +} + +void CreateInstancedBaselines( void ) +{ + (*other_gFunctionTable.pfnCreateInstancedBaselines)(); +} + +int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) +{ + if (debug_engine) { fp=fopen("bot.txt", "a"); fprintf(fp, "InconsistentFile: %x filename=%s\n",player,filename); fclose(fp); } + + return (*other_gFunctionTable.pfnInconsistentFile)(player, filename, disconnect_message); +} + +int AllowLagCompensation( void ) +{ + return (*other_gFunctionTable.pfnAllowLagCompensation)(); +} + + +DLL_FUNCTIONS gFunctionTable = +{ + GameDLLInit, //pfnGameInit + DispatchSpawn, //pfnSpawn + DispatchThink, //pfnThink + DispatchUse, //pfnUse + DispatchTouch, //pfnTouch + DispatchBlocked, //pfnBlocked + DispatchKeyValue, //pfnKeyValue + DispatchSave, //pfnSave + DispatchRestore, //pfnRestore + DispatchObjectCollsionBox, //pfnAbsBox + + SaveWriteFields, //pfnSaveWriteFields + SaveReadFields, //pfnSaveReadFields + + SaveGlobalState, //pfnSaveGlobalState + RestoreGlobalState, //pfnRestoreGlobalState + ResetGlobalState, //pfnResetGlobalState + + ClientConnect, //pfnClientConnect + ClientDisconnect, //pfnClientDisconnect + ClientKill, //pfnClientKill + ClientPutInServer, //pfnClientPutInServer + ClientCommand, //pfnClientCommand + ClientUserInfoChanged, //pfnClientUserInfoChanged + ServerActivate, //pfnServerActivate + ServerDeactivate, //pfnServerDeactivate + + PlayerPreThink, //pfnPlayerPreThink + PlayerPostThink, //pfnPlayerPostThink + + StartFrame, //pfnStartFrame + ParmsNewLevel, //pfnParmsNewLevel + ParmsChangeLevel, //pfnParmsChangeLevel + + GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. + PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player. + + SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server + SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server + SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) + + Sys_Error, //pfnSys_Error Called when engine has encountered an error + + PM_Move, //pfnPM_Move + PM_Init, //pfnPM_Init Server version of player movement initialization + PM_FindTextureType, //pfnPM_FindTextureType + + SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client + UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client + AddToFullPack, //pfnAddToFullPack + CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. + RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding + GetWeaponData, //pfnGetWeaponData + CmdStart, //pfnCmdStart + CmdEnd, //pfnCmdEnd + ConnectionlessPacket, //pfnConnectionlessPacket + GetHullBounds, //pfnGetHullBounds + CreateInstancedBaselines, //pfnCreateInstancedBaselines + InconsistentFile, //pfnInconsistentFile + AllowLagCompensation, //pfnAllowLagCompensation +}; + +#ifdef __BORLANDC__ +int EXPORT GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) +#else +extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) +#endif +{ + // check if engine's pointer is valid and version is correct... + + if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) + return FALSE; + + // pass engine callback function table to engine... + memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); + + // pass other DLLs engine callbacks to function table... + if (!(*other_GetEntityAPI)(&other_gFunctionTable, INTERFACE_VERSION)) + { + return FALSE; // error initializing function table!!! + } + + return TRUE; +} + + +#ifdef __BORLANDC__ +int EXPORT GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) +#else +extern "C" EXPORT int GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) +#endif +{ + if (other_GetNewDLLFunctions == NULL) + return FALSE; + + // pass other DLLs engine callbacks to function table... + if (!(*other_GetNewDLLFunctions)(pFunctionTable, interfaceVersion)) + { + return FALSE; // error initializing function table!!! + } + + return TRUE; +} + + +void FakeClientCommand(edict_t *pBot, char *arg1, char *arg2, char *arg3) +{ + int length; + + memset(g_argv, 0, sizeof(g_argv)); + + isFakeClientCommand = 1; + + if ((arg1 == NULL) || (*arg1 == 0)) + return; + + if ((arg2 == NULL) || (*arg2 == 0)) + { + length = sprintf(&g_argv[0], "%s", arg1); + fake_arg_count = 1; + } + else if ((arg3 == NULL) || (*arg3 == 0)) + { + length = sprintf(&g_argv[0], "%s %s", arg1, arg2); + fake_arg_count = 2; + } + else + { + length = sprintf(&g_argv[0], "%s %s %s", arg1, arg2, arg3); + fake_arg_count = 3; + } + + g_argv[length] = 0; // null terminate just in case + + strcpy(&g_argv[64], arg1); + + if (arg2) + strcpy(&g_argv[128], arg2); + + if (arg3) + strcpy(&g_argv[192], arg3); + + // allow the MOD DLL to execute the ClientCommand... + ClientCommand(pBot); + + isFakeClientCommand = 0; +} + + +const char *Cmd_Args( void ) +{ + if (isFakeClientCommand) + { + return &g_argv[0]; + } + else + { + return (*g_engfuncs.pfnCmd_Args)(); + } +} + + +const char *Cmd_Argv( int argc ) +{ + if (isFakeClientCommand) + { + if (argc == 0) + { + return &g_argv[64]; + } + else if (argc == 1) + { + return &g_argv[128]; + } + else if (argc == 2) + { + return &g_argv[192]; + } + else + { + return NULL; + } + } + else + { + return (*g_engfuncs.pfnCmd_Argv)(argc); + } +} + + +int Cmd_Argc( void ) +{ + if (isFakeClientCommand) + { + return fake_arg_count; + } + else + { + return (*g_engfuncs.pfnCmd_Argc)(); + } +} + + +void ProcessBotCfgFile(void) +{ + int ch; + char cmd_line[256]; + int cmd_index; + static char server_cmd[80]; + char *cmd, *arg1, *arg2, *arg3, *arg4; + char msg[80]; + + if (bot_cfg_pause_time > gpGlobals->time) + return; + + if (bot_cfg_fp == NULL) + return; + + cmd_index = 0; + cmd_line[cmd_index] = 0; + + ch = fgetc(bot_cfg_fp); + + // skip any leading blanks + while (ch == ' ') + ch = fgetc(bot_cfg_fp); + + while ((ch != EOF) && (ch != '\r') && (ch != '\n')) + { + if (ch == '\t') // convert tabs to spaces + ch = ' '; + + cmd_line[cmd_index] = ch; + + ch = fgetc(bot_cfg_fp); + + // skip multiple spaces in input file + while ((cmd_line[cmd_index] == ' ') && + (ch == ' ')) + ch = fgetc(bot_cfg_fp); + + cmd_index++; + } + + if (ch == '\r') // is it a carriage return? + { + ch = fgetc(bot_cfg_fp); // skip the linefeed + } + + // if reached end of file, then close it + if (ch == EOF) + { + fclose(bot_cfg_fp); + + bot_cfg_fp = NULL; + + bot_cfg_pause_time = 0.0; + } + + cmd_line[cmd_index] = 0; // terminate the command line + + // copy the command line to a server command buffer... + strcpy(server_cmd, cmd_line); + strcat(server_cmd, "\n"); + + cmd_index = 0; + cmd = cmd_line; + arg1 = arg2 = arg3 = arg4 = NULL; + + // skip to blank or end of string... + while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) + cmd_index++; + + if (cmd_line[cmd_index] == ' ') + { + cmd_line[cmd_index++] = 0; + arg1 = &cmd_line[cmd_index]; + + // skip to blank or end of string... + while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) + cmd_index++; + + if (cmd_line[cmd_index] == ' ') + { + cmd_line[cmd_index++] = 0; + arg2 = &cmd_line[cmd_index]; + + // skip to blank or end of string... + while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) + cmd_index++; + + if (cmd_line[cmd_index] == ' ') + { + cmd_line[cmd_index++] = 0; + arg3 = &cmd_line[cmd_index]; + + // skip to blank or end of string... + while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) + cmd_index++; + + if (cmd_line[cmd_index] == ' ') + { + cmd_line[cmd_index++] = 0; + arg4 = &cmd_line[cmd_index]; + } + } + } + } + + if ((cmd_line[0] == '#') || (cmd_line[0] == 0)) + return; // return if comment or blank line + + if (strcmp(cmd, "addbot") == 0) + { + BotCreate( NULL, arg1, arg2, arg3, arg4 ); + + // have to delay here or engine gives "Tried to write to + // uninitialized sizebuf_t" error and crashes... + + bot_cfg_pause_time = gpGlobals->time + 2.0; + bot_check_time = gpGlobals->time + 5.0; + + return; + } + + if (strcmp(cmd, "botskill") == 0) + { + int temp = atoi(arg1); + + if ((temp >= 1) && (temp <= 5)) + default_bot_skill = atoi( arg1 ); // set default bot skill level + + return; + } + + if (strcmp(cmd, "observer") == 0) + { + int temp = atoi(arg1); + + if (temp) + b_observer_mode = TRUE; + else + b_observer_mode = FALSE; + + return; + } + + if (strcmp(cmd, "botdontshoot") == 0) + { + int temp = atoi(arg1); + + if (temp) + b_botdontshoot = TRUE; + else + b_botdontshoot = FALSE; + + return; + } + + if (strcmp(cmd, "min_bots") == 0) + { + min_bots = atoi( arg1 ); + + if ((min_bots < 0) || (min_bots > 31)) + min_bots = 1; + + if (IS_DEDICATED_SERVER()) + { + sprintf(msg, "min_bots set to %d\n", min_bots); + printf(msg); + } + + return; + } + + if (strcmp(cmd, "max_bots") == 0) + { + max_bots = atoi( arg1 ); + + if ((max_bots < 0) || (max_bots > 31)) + max_bots = 1; + + if (IS_DEDICATED_SERVER()) + { + sprintf(msg, "max_bots set to %d\n", max_bots); + printf(msg); + } + + return; + } + + if (strcmp(cmd, "pause") == 0) + { + bot_cfg_pause_time = gpGlobals->time + atoi( arg1 ); + + return; + } + + sprintf(msg, "executing server command: %s\n", server_cmd); + ALERT( at_console, msg ); + + if (IS_DEDICATED_SERVER()) + printf(msg); + + SERVER_COMMAND(server_cmd); +} + diff --git a/main/source/HPB_bot/dlls/engine.cpp b/main/source/HPB_bot/dlls/engine.cpp index a68f36f9..43704e86 100644 --- a/main/source/HPB_bot/dlls/engine.cpp +++ b/main/source/HPB_bot/dlls/engine.cpp @@ -1,1233 +1,1233 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// engine.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" - -#include "bot.h" -#include "bot_client.h" -#include "HPB_bot/engine/engine.h" - - -extern enginefuncs_t g_engfuncs; -extern bot_t bots[32]; -extern int mod_id; - - -int debug_engine = 0; - -void (*botMsgFunction)(void *, int) = NULL; -void (*botMsgEndFunction)(void *, int) = NULL; -int botMsgIndex; - -// messages created in RegUserMsg which will be "caught" -int message_VGUI = 0; -int message_ShowMenu = 0; -int message_WeaponList = 0; -int message_CurWeapon = 0; -int message_AmmoX = 0; -int message_WeapPickup = 0; -int message_AmmoPickup = 0; -int message_ItemPickup = 0; -int message_Health = 0; -int message_Battery = 0; // Armor -int message_Damage = 0; -int message_Money = 0; // for Counter-Strike -int message_DeathMsg = 0; -int message_TextMsg = 0; -int message_WarmUp = 0; // for Front Line Force -int message_WinMessage = 0; // for Front Line Force -int message_ScreenFade = 0; - -// AvH messages -int message_SetPlayMode = 0; -int message_SetOrder = 0; -int message_SetResources = 0; - -static FILE *fp; - - -int pfnPrecacheModel(char* s) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheModel: %s\n",s); fclose(fp); } - return (*g_engfuncs.pfnPrecacheModel)(s); -} -int pfnPrecacheSound(char* s) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheSound: %s\n",s); fclose(fp); } - return (*g_engfuncs.pfnPrecacheSound)(s); -} -void pfnSetModel(edict_t *e, const char *m) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetModel: edict=%x %s\n",e,m); fclose(fp); } - (*g_engfuncs.pfnSetModel)(e, m); -} -int pfnModelIndex(const char *m) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnModelIndex: %s\n",m); fclose(fp); } - return (*g_engfuncs.pfnModelIndex)(m); -} -int pfnModelFrames(int modelIndex) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnModelFrames:\n"); fclose(fp); } - return (*g_engfuncs.pfnModelFrames)(modelIndex); -} -void pfnSetSize(edict_t *e, const float *rgflMin, const float *rgflMax) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetSize: %x\n",e); fclose(fp); } - (*g_engfuncs.pfnSetSize)(e, rgflMin, rgflMax); -} -void pfnChangeLevel(char* s1, char* s2) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnChangeLevel:\n"); fclose(fp); } - - // kick any bot off of the server after time/frag limit... - for (int index = 0; index < 32; index++) - { - if (bots[index].is_used) // is this slot used? - { - char cmd[40]; - - sprintf(cmd, "kick \"%s\"\n", bots[index].name); - - bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; - - SERVER_COMMAND(cmd); // kick the bot using (kick "name") - } - } - - (*g_engfuncs.pfnChangeLevel)(s1, s2); -} -void pfnGetSpawnParms(edict_t *ent) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetSpawnParms:\n"); fclose(fp); } - (*g_engfuncs.pfnGetSpawnParms)(ent); -} -void pfnSaveSpawnParms(edict_t *ent) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSaveSpawnParms:\n"); fclose(fp); } - (*g_engfuncs.pfnSaveSpawnParms)(ent); -} -float pfnVecToYaw(const float *rgflVector) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnVecToYaw:\n"); fclose(fp); } - return (*g_engfuncs.pfnVecToYaw)(rgflVector); -} -void pfnVecToAngles(const float *rgflVectorIn, float *rgflVectorOut) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnVecToAngles:\n"); fclose(fp); } - (*g_engfuncs.pfnVecToAngles)(rgflVectorIn, rgflVectorOut); -} -void pfnMoveToOrigin(edict_t *ent, const float *pflGoal, float dist, int iMoveType) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMoveToOrigin:\n"); fclose(fp); } - (*g_engfuncs.pfnMoveToOrigin)(ent, pflGoal, dist, iMoveType); -} -void pfnChangeYaw(edict_t* ent) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnChangeYaw:\n"); fclose(fp); } - (*g_engfuncs.pfnChangeYaw)(ent); -} -void pfnChangePitch(edict_t* ent) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnChangePitch:\n"); fclose(fp); } - (*g_engfuncs.pfnChangePitch)(ent); -} -edict_t* pfnFindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindEntityByString: %s\n",pszValue); fclose(fp); } - return (*g_engfuncs.pfnFindEntityByString)(pEdictStartSearchAfter, pszField, pszValue); -} -int pfnGetEntityIllum(edict_t* pEnt) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetEntityIllum:\n"); fclose(fp); } - return (*g_engfuncs.pfnGetEntityIllum)(pEnt); -} -edict_t* pfnFindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindEntityInSphere:\n"); fclose(fp); } - return (*g_engfuncs.pfnFindEntityInSphere)(pEdictStartSearchAfter, org, rad); -} -edict_t* pfnFindClientInPVS(edict_t *pEdict) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindClientInPVS:\n"); fclose(fp); } - return (*g_engfuncs.pfnFindClientInPVS)(pEdict); -} -edict_t* pfnEntitiesInPVS(edict_t *pplayer) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEntitiesInPVS:\n"); fclose(fp); } - return (*g_engfuncs.pfnEntitiesInPVS)(pplayer); -} -void pfnMakeVectors(const float *rgflVector) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMakeVectors:\n"); fclose(fp); } - (*g_engfuncs.pfnMakeVectors)(rgflVector); -} -void pfnAngleVectors(const float *rgflVector, float *forward, float *right, float *up) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnAngleVectors:\n"); fclose(fp); } - (*g_engfuncs.pfnAngleVectors)(rgflVector, forward, right, up); -} -edict_t* pfnCreateEntity(void) -{ - edict_t *pent = (*g_engfuncs.pfnCreateEntity)(); - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateEntity: %x\n",pent); fclose(fp); } - return pent; -} -void pfnRemoveEntity(edict_t* e) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRemoveEntity: %x\n",e); fclose(fp); } - if (debug_engine) - { - fp=fopen("bot.txt","a"); - fprintf(fp,"pfnRemoveEntity: %x\n",e); - if (e->v.model != 0) - fprintf(fp," model=%s\n", STRING(e->v.model)); - fclose(fp); - } - - (*g_engfuncs.pfnRemoveEntity)(e); -} -edict_t* pfnCreateNamedEntity(int className) -{ - edict_t *pent = (*g_engfuncs.pfnCreateNamedEntity)(className); - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateNamedEntity: edict=%x name=%s\n",pent,STRING(className)); fclose(fp); } - return pent; -} -void pfnMakeStatic(edict_t *ent) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMakeStatic:\n"); fclose(fp); } - (*g_engfuncs.pfnMakeStatic)(ent); -} -int pfnEntIsOnFloor(edict_t *e) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEntIsOnFloor:\n"); fclose(fp); } - return (*g_engfuncs.pfnEntIsOnFloor)(e); -} -int pfnDropToFloor(edict_t* e) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDropToFloor:\n"); fclose(fp); } - return (*g_engfuncs.pfnDropToFloor)(e); -} -int pfnWalkMove(edict_t *ent, float yaw, float dist, int iMode) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWalkMove:\n"); fclose(fp); } - return (*g_engfuncs.pfnWalkMove)(ent, yaw, dist, iMode); -} -void pfnSetOrigin(edict_t *e, const float *rgflOrigin) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetOrigin:\n"); fclose(fp); } - (*g_engfuncs.pfnSetOrigin)(e, rgflOrigin); -} -void pfnEmitSound(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEmitSound:\n"); fclose(fp); } - (*g_engfuncs.pfnEmitSound)(entity, channel, sample, volume, attenuation, fFlags, pitch); -} -void pfnEmitAmbientSound(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEmitAmbientSound:\n"); fclose(fp); } - (*g_engfuncs.pfnEmitAmbientSound)(entity, pos, samp, vol, attenuation, fFlags, pitch); -} -void pfnTraceLine(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceLine:\n"); fclose(fp); } - (*g_engfuncs.pfnTraceLine)(v1, v2, fNoMonsters, pentToSkip, ptr); -} -void pfnTraceToss(edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceToss:\n"); fclose(fp); } - (*g_engfuncs.pfnTraceToss)(pent, pentToIgnore, ptr); -} -int pfnTraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceMonsterHull:\n"); fclose(fp); } - return (*g_engfuncs.pfnTraceMonsterHull)(pEdict, v1, v2, fNoMonsters, pentToSkip, ptr); -} -void pfnTraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceHull:\n"); fclose(fp); } - (*g_engfuncs.pfnTraceHull)(v1, v2, fNoMonsters, hullNumber, pentToSkip, ptr); -} -void pfnTraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceModel:\n"); fclose(fp); } - (*g_engfuncs.pfnTraceModel)(v1, v2, hullNumber, pent, ptr); -} -const char *pfnTraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2 ) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceTexture:\n"); fclose(fp); } - return (*g_engfuncs.pfnTraceTexture)(pTextureEntity, v1, v2); -} -void pfnTraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceSphere:\n"); fclose(fp); } - (*g_engfuncs.pfnTraceSphere)(v1, v2, fNoMonsters, radius, pentToSkip, ptr); -} -void pfnGetAimVector(edict_t* ent, float speed, float *rgflReturn) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetAimVector:\n"); fclose(fp); } - (*g_engfuncs.pfnGetAimVector)(ent, speed, rgflReturn); -} -void pfnServerCommand(char* str) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnServerCommand: %s\n",str); fclose(fp); } - (*g_engfuncs.pfnServerCommand)(str); -} -void pfnServerExecute(void) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnServerExecute:\n"); fclose(fp); } - (*g_engfuncs.pfnServerExecute)(); -} -void pfnClientCommand(edict_t* pEdict, char* szFmt, ...) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnClientCommand=%s\n",szFmt); fclose(fp); } - return; -} -void pfnParticleEffect(const float *org, const float *dir, float color, float count) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnParticleEffect:\n"); fclose(fp); } - (*g_engfuncs.pfnParticleEffect)(org, dir, color, count); -} -void pfnLightStyle(int style, char* val) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnLightStyle:\n"); fclose(fp); } - (*g_engfuncs.pfnLightStyle)(style, val); -} -int pfnDecalIndex(const char *name) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDecalIndex:\n"); fclose(fp); } - return (*g_engfuncs.pfnDecalIndex)(name); -} -int pfnPointContents(const float *rgflVector) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPointContents:\n"); fclose(fp); } - return (*g_engfuncs.pfnPointContents)(rgflVector); -} -void pfnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) -{ - if (gpGlobals->deathmatch) - { - int index = -1; - - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMessageBegin: edict=%x dest=%d type=%d\n",ed,msg_dest,msg_type); fclose(fp); } - - if (ed) - { - index = UTIL_GetBotIndex(ed); - - // is this message for a bot? - if (index != -1) - { - botMsgFunction = NULL; // no msg function until known otherwise - botMsgEndFunction = NULL; // no msg end function until known otherwise - botMsgIndex = index; // index of bot receiving message - - if (mod_id == VALVE_DLL) - { - if (msg_type == message_WeaponList) - botMsgFunction = BotClient_Valve_WeaponList; - else if (msg_type == message_CurWeapon) - botMsgFunction = BotClient_Valve_CurrentWeapon; - else if (msg_type == message_AmmoX) - botMsgFunction = BotClient_Valve_AmmoX; - else if (msg_type == message_AmmoPickup) - botMsgFunction = BotClient_Valve_AmmoPickup; - else if (msg_type == message_WeapPickup) - botMsgFunction = BotClient_Valve_WeaponPickup; - else if (msg_type == message_ItemPickup) - botMsgFunction = BotClient_Valve_ItemPickup; - else if (msg_type == message_Health) - botMsgFunction = BotClient_Valve_Health; - else if (msg_type == message_Battery) - botMsgFunction = BotClient_Valve_Battery; - else if (msg_type == message_Damage) - botMsgFunction = BotClient_Valve_Damage; - else if (msg_type == message_ScreenFade) - botMsgFunction = BotClient_Valve_ScreenFade; - } - else if (mod_id == TFC_DLL) - { - if (msg_type == message_VGUI) - botMsgFunction = BotClient_TFC_VGUI; - else if (msg_type == message_WeaponList) - botMsgFunction = BotClient_TFC_WeaponList; - else if (msg_type == message_CurWeapon) - botMsgFunction = BotClient_TFC_CurrentWeapon; - else if (msg_type == message_AmmoX) - botMsgFunction = BotClient_TFC_AmmoX; - else if (msg_type == message_AmmoPickup) - botMsgFunction = BotClient_TFC_AmmoPickup; - else if (msg_type == message_WeapPickup) - botMsgFunction = BotClient_TFC_WeaponPickup; - else if (msg_type == message_ItemPickup) - botMsgFunction = BotClient_TFC_ItemPickup; - else if (msg_type == message_Health) - botMsgFunction = BotClient_TFC_Health; - else if (msg_type == message_Battery) - botMsgFunction = BotClient_TFC_Battery; - else if (msg_type == message_Damage) - botMsgFunction = BotClient_TFC_Damage; - else if (msg_type == message_ScreenFade) - botMsgFunction = BotClient_TFC_ScreenFade; - } - else if (mod_id == CSTRIKE_DLL) - { - if (msg_type == message_VGUI) - botMsgFunction = BotClient_CS_VGUI; - else if (msg_type == message_ShowMenu) - botMsgFunction = BotClient_CS_ShowMenu; - else if (msg_type == message_WeaponList) - botMsgFunction = BotClient_CS_WeaponList; - else if (msg_type == message_CurWeapon) - botMsgFunction = BotClient_CS_CurrentWeapon; - else if (msg_type == message_AmmoX) - botMsgFunction = BotClient_CS_AmmoX; - else if (msg_type == message_WeapPickup) - botMsgFunction = BotClient_CS_WeaponPickup; - else if (msg_type == message_AmmoPickup) - botMsgFunction = BotClient_CS_AmmoPickup; - else if (msg_type == message_ItemPickup) - botMsgFunction = BotClient_CS_ItemPickup; - else if (msg_type == message_Health) - botMsgFunction = BotClient_CS_Health; - else if (msg_type == message_Battery) - botMsgFunction = BotClient_CS_Battery; - else if (msg_type == message_Damage) - botMsgFunction = BotClient_CS_Damage; - else if (msg_type == message_Money) - botMsgFunction = BotClient_CS_Money; - else if (msg_type == message_ScreenFade) - botMsgFunction = BotClient_CS_ScreenFade; - } - else if (mod_id == GEARBOX_DLL) - { - if (msg_type == message_VGUI) - botMsgFunction = BotClient_Gearbox_VGUI; - else if (msg_type == message_WeaponList) - botMsgFunction = BotClient_Gearbox_WeaponList; - else if (msg_type == message_CurWeapon) - botMsgFunction = BotClient_Gearbox_CurrentWeapon; - else if (msg_type == message_AmmoX) - botMsgFunction = BotClient_Gearbox_AmmoX; - else if (msg_type == message_AmmoPickup) - botMsgFunction = BotClient_Gearbox_AmmoPickup; - else if (msg_type == message_WeapPickup) - botMsgFunction = BotClient_Gearbox_WeaponPickup; - else if (msg_type == message_ItemPickup) - botMsgFunction = BotClient_Gearbox_ItemPickup; - else if (msg_type == message_Health) - botMsgFunction = BotClient_Gearbox_Health; - else if (msg_type == message_Battery) - botMsgFunction = BotClient_Gearbox_Battery; - else if (msg_type == message_Damage) - botMsgFunction = BotClient_Gearbox_Damage; - else if (msg_type == message_ScreenFade) - botMsgFunction = BotClient_Gearbox_ScreenFade; - } - else if (mod_id == FRONTLINE_DLL) - { - if (msg_type == message_VGUI) - botMsgFunction = BotClient_FLF_VGUI; - else if (msg_type == message_WeaponList) - botMsgFunction = BotClient_FLF_WeaponList; - else if (msg_type == message_CurWeapon) - botMsgFunction = BotClient_FLF_CurrentWeapon; - else if (msg_type == message_AmmoX) - botMsgFunction = BotClient_FLF_AmmoX; - else if (msg_type == message_AmmoPickup) - botMsgFunction = BotClient_FLF_AmmoPickup; - else if (msg_type == message_WeapPickup) - botMsgFunction = BotClient_FLF_WeaponPickup; - else if (msg_type == message_ItemPickup) - botMsgFunction = BotClient_FLF_ItemPickup; - else if (msg_type == message_Health) - botMsgFunction = BotClient_FLF_Health; - else if (msg_type == message_Battery) - botMsgFunction = BotClient_FLF_Battery; - else if (msg_type == message_Damage) - botMsgFunction = BotClient_FLF_Damage; - else if (msg_type == message_TextMsg) - botMsgFunction = BotClient_FLF_TextMsg; - else if (msg_type == message_WarmUp) - botMsgFunction = BotClient_FLF_WarmUp; - else if (msg_type == message_ScreenFade) - botMsgFunction = BotClient_FLF_ScreenFade; - else if (msg_type == 23) // SVC_TEMPENTITY - { - botMsgFunction = BotClient_FLF_TempEntity; - botMsgEndFunction = BotClient_FLF_TempEntity; - } - } - else if (mod_id == AVH_DLL) - { - if (msg_type == message_SetPlayMode) - botMsgFunction = BotClient_AVH_SetPlayMode; - else if (msg_type == message_AmmoX) - botMsgFunction = BotClient_Valve_AmmoX; - else if (msg_type == message_AmmoPickup) - botMsgFunction = BotClient_Valve_AmmoPickup; - else if (msg_type == message_WeapPickup) - botMsgFunction = BotClient_Valve_WeaponPickup; - else if (msg_type == message_ItemPickup) - botMsgFunction = BotClient_Valve_ItemPickup; - else if (msg_type == message_WeaponList) - botMsgFunction = BotClient_Valve_WeaponList; - else if (msg_type == message_SetOrder) - botMsgFunction = BotClient_AVH_SetOrder; - else if (msg_type == message_SetResources) - botMsgFunction = BotClient_AVH_SetResources; - } - } - } - else if (msg_dest == MSG_ALL) - { - botMsgFunction = NULL; // no msg function until known otherwise - botMsgIndex = -1; // index of bot receiving message (none) - - if (mod_id == VALVE_DLL) - { - if (msg_type == message_DeathMsg) - botMsgFunction = BotClient_Valve_DeathMsg; - } - else if (mod_id == TFC_DLL) - { - if (msg_type == message_DeathMsg) - botMsgFunction = BotClient_TFC_DeathMsg; - } - else if (mod_id == CSTRIKE_DLL) - { - if (msg_type == message_DeathMsg) - botMsgFunction = BotClient_CS_DeathMsg; - } - else if (mod_id == GEARBOX_DLL) - { - if (msg_type == message_DeathMsg) - botMsgFunction = BotClient_Gearbox_DeathMsg; - } - else if (mod_id == FRONTLINE_DLL) - { - if (msg_type == message_DeathMsg) - botMsgFunction = BotClient_FLF_DeathMsg; - else if (msg_type == message_WarmUp) - botMsgFunction = BotClient_FLF_WarmUpAll; - else if (msg_type == message_WinMessage) - botMsgFunction = BotClient_FLF_WinMessage; - } - } - } - - (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); -} -void pfnMessageEnd(void) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMessageEnd:\n"); fclose(fp); } - - if (botMsgEndFunction) - (*botMsgEndFunction)(NULL, botMsgIndex); // NULL indicated msg end - - // clear out the bot message function pointers... - botMsgFunction = NULL; - botMsgEndFunction = NULL; - } - - (*g_engfuncs.pfnMessageEnd)(); -} -void pfnWriteByte(int iValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteByte: %d\n",iValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&iValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteByte)(iValue); -} -void pfnWriteChar(int iValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteChar: %d\n",iValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&iValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteChar)(iValue); -} -void pfnWriteShort(int iValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteShort: %d\n",iValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&iValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteShort)(iValue); -} -void pfnWriteLong(int iValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteLong: %d\n",iValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&iValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteLong)(iValue); -} -void pfnWriteAngle(float flValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteAngle: %f\n",flValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&flValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteAngle)(flValue); -} -void pfnWriteCoord(float flValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteCoord: %f\n",flValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&flValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteCoord)(flValue); -} -void pfnWriteString(const char *sz) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteString: %s\n",sz); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)sz, botMsgIndex); - } - - (*g_engfuncs.pfnWriteString)(sz); -} -void pfnWriteEntity(int iValue) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteEntity: %d\n",iValue); fclose(fp); } - - // if this message is for a bot, call the client message function... - if (botMsgFunction) - (*botMsgFunction)((void *)&iValue, botMsgIndex); - } - - (*g_engfuncs.pfnWriteEntity)(iValue); -} -void pfnCVarRegister(cvar_t *pCvar) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarRegister:\n"); fclose(fp); } - (*g_engfuncs.pfnCVarRegister)(pCvar); -} -float pfnCVarGetFloat(const char *szVarName) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarGetFloat: %s\n",szVarName); fclose(fp); } - return (*g_engfuncs.pfnCVarGetFloat)(szVarName); -} -const char* pfnCVarGetString(const char *szVarName) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarGetString:\n"); fclose(fp); } - return (*g_engfuncs.pfnCVarGetString)(szVarName); -} -void pfnCVarSetFloat(const char *szVarName, float flValue) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarSetFloat:\n"); fclose(fp); } - (*g_engfuncs.pfnCVarSetFloat)(szVarName, flValue); -} -void pfnCVarSetString(const char *szVarName, const char *szValue) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarSetString:\n"); fclose(fp); } - (*g_engfuncs.pfnCVarSetString)(szVarName, szValue); -} -void* pfnPvAllocEntPrivateData(edict_t *pEdict, long cb) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPvAllocEntPrivateData:\n"); fclose(fp); } - return (*g_engfuncs.pfnPvAllocEntPrivateData)(pEdict, cb); -} -void* pfnPvEntPrivateData(edict_t *pEdict) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPvEntPrivateData:\n"); fclose(fp); } - return (*g_engfuncs.pfnPvEntPrivateData)(pEdict); -} -void pfnFreeEntPrivateData(edict_t *pEdict) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFreeEntPrivateData:\n"); fclose(fp); } - (*g_engfuncs.pfnFreeEntPrivateData)(pEdict); -} -const char* pfnSzFromIndex(int iString) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSzFromIndex:\n"); fclose(fp); } - return (*g_engfuncs.pfnSzFromIndex)(iString); -} -int pfnAllocString(const char *szValue) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnAllocString:\n"); fclose(fp); } - return (*g_engfuncs.pfnAllocString)(szValue); -} -entvars_t* pfnGetVarsOfEnt(edict_t *pEdict) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetVarsOfEnt:\n"); fclose(fp); } - return (*g_engfuncs.pfnGetVarsOfEnt)(pEdict); -} -edict_t* pfnPEntityOfEntOffset(int iEntOffset) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPEntityOfEntOffset:\n"); fclose(fp); } - return (*g_engfuncs.pfnPEntityOfEntOffset)(iEntOffset); -} -int pfnEntOffsetOfPEntity(const edict_t *pEdict) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEntOffsetOfPEntity: %x\n",pEdict); fclose(fp); } - return (*g_engfuncs.pfnEntOffsetOfPEntity)(pEdict); -} -int pfnIndexOfEdict(const edict_t *pEdict) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnIndexOfEdict: %x\n",pEdict); fclose(fp); } - return (*g_engfuncs.pfnIndexOfEdict)(pEdict); -} -edict_t* pfnPEntityOfEntIndex(int iEntIndex) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPEntityOfEntIndex:\n"); fclose(fp); } - return (*g_engfuncs.pfnPEntityOfEntIndex)(iEntIndex); -} -edict_t* pfnFindEntityByVars(entvars_t* pvars) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindEntityByVars:\n"); fclose(fp); } - return (*g_engfuncs.pfnFindEntityByVars)(pvars); -} -void* pfnGetModelPtr(edict_t* pEdict) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetModelPtr: %x\n",pEdict); fclose(fp); } - return (*g_engfuncs.pfnGetModelPtr)(pEdict); -} -int pfnRegUserMsg(const char *pszName, int iSize) -{ - int msg; - - msg = (*g_engfuncs.pfnRegUserMsg)(pszName, iSize); - - //if (gpGlobals->deathmatch) - //{ -#ifdef _DEBUG - fp=fopen("bot.txt","a"); fprintf(fp,"pfnRegUserMsg: pszName=%s msg=%d\n",pszName,msg); fclose(fp); -#endif - - if (mod_id == VALVE_DLL) - { - if (strcmp(pszName, "WeaponList") == 0) - message_WeaponList = msg; - else if (strcmp(pszName, "CurWeapon") == 0) - message_CurWeapon = msg; - else if (strcmp(pszName, "AmmoX") == 0) - message_AmmoX = msg; - else if (strcmp(pszName, "AmmoPickup") == 0) - message_AmmoPickup = msg; - else if (strcmp(pszName, "WeapPickup") == 0) - message_WeapPickup = msg; - else if (strcmp(pszName, "ItemPickup") == 0) - message_ItemPickup = msg; - else if (strcmp(pszName, "Health") == 0) - message_Health = msg; - else if (strcmp(pszName, "Battery") == 0) - message_Battery = msg; - else if (strcmp(pszName, "Damage") == 0) - message_Damage = msg; - else if (strcmp(pszName, "DeathMsg") == 0) - message_DeathMsg = msg; - else if (strcmp(pszName, "ScreenFade") == 0) - message_ScreenFade = msg; - } - else if (mod_id == TFC_DLL) - { - if (strcmp(pszName, "VGUIMenu") == 0) - message_VGUI = msg; - else if (strcmp(pszName, "WeaponList") == 0) - message_WeaponList = msg; - else if (strcmp(pszName, "CurWeapon") == 0) - message_CurWeapon = msg; - else if (strcmp(pszName, "AmmoX") == 0) - message_AmmoX = msg; - else if (strcmp(pszName, "AmmoPickup") == 0) - message_AmmoPickup = msg; - else if (strcmp(pszName, "WeapPickup") == 0) - message_WeapPickup = msg; - else if (strcmp(pszName, "ItemPickup") == 0) - message_ItemPickup = msg; - else if (strcmp(pszName, "Health") == 0) - message_Health = msg; - else if (strcmp(pszName, "Battery") == 0) - message_Battery = msg; - else if (strcmp(pszName, "Damage") == 0) - message_Damage = msg; - else if (strcmp(pszName, "DeathMsg") == 0) - message_DeathMsg = msg; - else if (strcmp(pszName, "ScreenFade") == 0) - message_ScreenFade = msg; - } - else if (mod_id == CSTRIKE_DLL) - { - if (strcmp(pszName, "VGUIMenu") == 0) - message_VGUI = msg; - else if (strcmp(pszName, "ShowMenu") == 0) - message_ShowMenu = msg; - else if (strcmp(pszName, "WeaponList") == 0) - message_WeaponList = msg; - else if (strcmp(pszName, "CurWeapon") == 0) - message_CurWeapon = msg; - else if (strcmp(pszName, "AmmoX") == 0) - message_AmmoX = msg; - else if (strcmp(pszName, "AmmoPickup") == 0) - message_AmmoPickup = msg; - else if (strcmp(pszName, "WeapPickup") == 0) - message_WeapPickup = msg; - else if (strcmp(pszName, "ItemPickup") == 0) - message_ItemPickup = msg; - else if (strcmp(pszName, "Health") == 0) - message_Health = msg; - else if (strcmp(pszName, "Battery") == 0) - message_Battery = msg; - else if (strcmp(pszName, "Damage") == 0) - message_Damage = msg; - else if (strcmp(pszName, "Money") == 0) - message_Money = msg; - else if (strcmp(pszName, "DeathMsg") == 0) - message_DeathMsg = msg; - else if (strcmp(pszName, "ScreenFade") == 0) - message_ScreenFade = msg; - } - else if (mod_id == GEARBOX_DLL) - { - if (strcmp(pszName, "VGUIMenu") == 0) - message_VGUI = msg; - else if (strcmp(pszName, "WeaponList") == 0) - message_WeaponList = msg; - else if (strcmp(pszName, "CurWeapon") == 0) - message_CurWeapon = msg; - else if (strcmp(pszName, "AmmoX") == 0) - message_AmmoX = msg; - else if (strcmp(pszName, "AmmoPickup") == 0) - message_AmmoPickup = msg; - else if (strcmp(pszName, "WeapPickup") == 0) - message_WeapPickup = msg; - else if (strcmp(pszName, "ItemPickup") == 0) - message_ItemPickup = msg; - else if (strcmp(pszName, "Health") == 0) - message_Health = msg; - else if (strcmp(pszName, "Battery") == 0) - message_Battery = msg; - else if (strcmp(pszName, "Damage") == 0) - message_Damage = msg; - else if (strcmp(pszName, "DeathMsg") == 0) - message_DeathMsg = msg; - else if (strcmp(pszName, "ScreenFade") == 0) - message_ScreenFade = msg; - } - else if (mod_id == FRONTLINE_DLL) - { - if (strcmp(pszName, "VGUIMenu") == 0) - message_VGUI = msg; - else if (strcmp(pszName, "WeaponList") == 0) - message_WeaponList = msg; - else if (strcmp(pszName, "CurWeapon") == 0) - message_CurWeapon = msg; - else if (strcmp(pszName, "AmmoX") == 0) - message_AmmoX = msg; - else if (strcmp(pszName, "AmmoPickup") == 0) - message_AmmoPickup = msg; - else if (strcmp(pszName, "WeapPickup") == 0) - message_WeapPickup = msg; - else if (strcmp(pszName, "ItemPickup") == 0) - message_ItemPickup = msg; - else if (strcmp(pszName, "Health") == 0) - message_Health = msg; - else if (strcmp(pszName, "Battery") == 0) - message_Battery = msg; - else if (strcmp(pszName, "Damage") == 0) - message_Damage = msg; - else if (strcmp(pszName, "DeathMsg") == 0) - message_DeathMsg = msg; - else if (strcmp(pszName, "TextMsg") == 0) - message_TextMsg = msg; - else if (strcmp(pszName, "WarmUp") == 0) - message_WarmUp = msg; - else if (strcmp(pszName, "WinMessage") == 0) - message_WinMessage = msg; - else if (strcmp(pszName, "ScreenFade") == 0) - message_ScreenFade = msg; - } - else if (mod_id == AVH_DLL) - { - if (strcmp(pszName, "SetPlayMode") == 0) - message_SetPlayMode = msg; - else if (strcmp(pszName, "AmmoX") == 0) - message_AmmoX = msg; - else if (strcmp(pszName, "AmmoPickup") == 0) - message_AmmoPickup = msg; - else if (strcmp(pszName, "WeapPickup") == 0) - message_WeapPickup = msg; - else if (strcmp(pszName, "ItemPickup") == 0) - message_ItemPickup = msg; - else if (strcmp(pszName, "WeaponList") == 0) - message_WeaponList = msg; - else if (strcmp(pszName, "SetOrder") == 0) - message_SetOrder = msg; - else if (strcmp(pszName, "SetRsrces") == 0) - message_SetResources = msg; - - } - //} - - return msg; -} -void pfnAnimationAutomove(const edict_t* pEdict, float flTime) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnAnimationAutomove:\n"); fclose(fp); } - (*g_engfuncs.pfnAnimationAutomove)(pEdict, flTime); -} -void pfnGetBonePosition(const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetBonePosition:\n"); fclose(fp); } - (*g_engfuncs.pfnGetBonePosition)(pEdict, iBone, rgflOrigin, rgflAngles); -} -unsigned long pfnFunctionFromName( const char *pName ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFunctionFromName:\n"); fclose(fp); } - return (*g_engfuncs.pfnFunctionFromName)(pName); -} -const char *pfnNameForFunction( unsigned long function ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnNameForFunction:\n"); fclose(fp); } - const char* theName = (*g_engfuncs.pfnNameForFunction)(function); - return theName; -} -void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnClientPrintf:\n"); fclose(fp); } - (*g_engfuncs.pfnClientPrintf)(pEdict, ptype, szMsg); -} -void pfnServerPrint( const char *szMsg ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnServerPrint: %s\n",szMsg); fclose(fp); } - (*g_engfuncs.pfnServerPrint)(szMsg); -} -void pfnGetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetAttachment:\n"); fclose(fp); } - (*g_engfuncs.pfnGetAttachment)(pEdict, iAttachment, rgflOrigin, rgflAngles); -} -void pfnCRC32_Init(CRC32_t *pulCRC) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_Init:\n"); fclose(fp); } - (*g_engfuncs.pfnCRC32_Init)(pulCRC); -} -void pfnCRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_ProcessBuffer:\n"); fclose(fp); } - (*g_engfuncs.pfnCRC32_ProcessBuffer)(pulCRC, p, len); -} -void pfnCRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_ProcessByte:\n"); fclose(fp); } - (*g_engfuncs.pfnCRC32_ProcessByte)(pulCRC, ch); -} -CRC32_t pfnCRC32_Final(CRC32_t pulCRC) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_Final:\n"); fclose(fp); } - return (*g_engfuncs.pfnCRC32_Final)(pulCRC); -} -long pfnRandomLong(long lLow, long lHigh) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRandomLong: lLow=%d lHigh=%d\n",lLow,lHigh); fclose(fp); } - return (*g_engfuncs.pfnRandomLong)(lLow, lHigh); -} -float pfnRandomFloat(float flLow, float flHigh) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRandomFloat:\n"); fclose(fp); } - return (*g_engfuncs.pfnRandomFloat)(flLow, flHigh); -} -void pfnSetView(const edict_t *pClient, const edict_t *pViewent ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetView:\n"); fclose(fp); } - (*g_engfuncs.pfnSetView)(pClient, pViewent); -} -float pfnTime( void ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTime:\n"); fclose(fp); } - return (*g_engfuncs.pfnTime)(); -} -void pfnCrosshairAngle(const edict_t *pClient, float pitch, float yaw) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCrosshairAngle:\n"); fclose(fp); } - (*g_engfuncs.pfnCrosshairAngle)(pClient, pitch, yaw); -} -byte *pfnLoadFileForMe(char *filename, int *pLength) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnLoadFileForMe: filename=%s\n",filename); fclose(fp); } - return (*g_engfuncs.pfnLoadFileForMe)(filename, pLength); -} -void pfnFreeFile(void *buffer) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFreeFile:\n"); fclose(fp); } - (*g_engfuncs.pfnFreeFile)(buffer); -} -void pfnEndSection(const char *pszSectionName) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEndSection:\n"); fclose(fp); } - (*g_engfuncs.pfnEndSection)(pszSectionName); -} -int pfnCompareFileTime(char *filename1, char *filename2, int *iCompare) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCompareFileTime:\n"); fclose(fp); } - return (*g_engfuncs.pfnCompareFileTime)(filename1, filename2, iCompare); -} -void pfnGetGameDir(char *szGetGameDir) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetGameDir:\n"); fclose(fp); } - (*g_engfuncs.pfnGetGameDir)(szGetGameDir); -} -void pfnCvar_RegisterVariable(cvar_t *variable) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCvar_RegisterVariable:\n"); fclose(fp); } - (*g_engfuncs.pfnCvar_RegisterVariable)(variable); -} -void pfnFadeClientVolume(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFadeClientVolume:\n"); fclose(fp); } - (*g_engfuncs.pfnFadeClientVolume)(pEdict, fadePercent, fadeOutSeconds, holdTime, fadeInSeconds); -} -void pfnSetClientMaxspeed(const edict_t *pEdict, float fNewMaxspeed) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetClientMaxspeed: edict=%x %f\n",pEdict,fNewMaxspeed); fclose(fp); } - (*g_engfuncs.pfnSetClientMaxspeed)(pEdict, fNewMaxspeed); -} -edict_t * pfnCreateFakeClient(const char *netname) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateFakeClient:\n"); fclose(fp); } - return (*g_engfuncs.pfnCreateFakeClient)(netname); -} -void pfnRunPlayerMove(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRunPlayerMove:\n"); fclose(fp); } - (*g_engfuncs.pfnRunPlayerMove)(fakeclient, viewangles, forwardmove, sidemove, upmove, buttons, impulse, msec); -} -int pfnNumberOfEntities(void) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnNumberOfEntities:\n"); fclose(fp); } - return (*g_engfuncs.pfnNumberOfEntities)(); -} -char* pfnGetInfoKeyBuffer(edict_t *e) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetInfoKeyBuffer:\n"); fclose(fp); } - return (*g_engfuncs.pfnGetInfoKeyBuffer)(e); -} -char* pfnInfoKeyValue(char *infobuffer, char *key) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnInfoKeyValue: %s %s\n",infobuffer,key); fclose(fp); } - return (*g_engfuncs.pfnInfoKeyValue)(infobuffer, key); -} -void pfnSetKeyValue(char *infobuffer, char *key, char *value) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetKeyValue: %s %s\n",key,value); fclose(fp); } - (*g_engfuncs.pfnSetKeyValue)(infobuffer, key, value); -} -void pfnSetClientKeyValue(int clientIndex, char *infobuffer, char *key, char *value) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetClientKeyValue: %s %s\n",key,value); fclose(fp); } - (*g_engfuncs.pfnSetClientKeyValue)(clientIndex, infobuffer, key, value); -} -int pfnIsMapValid(char *filename) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnIsMapValid:\n"); fclose(fp); } - return (*g_engfuncs.pfnIsMapValid)(filename); -} -void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex ) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnStaticDecal:\n"); fclose(fp); } - (*g_engfuncs.pfnStaticDecal)(origin, decalIndex, entityIndex, modelIndex); -} -int pfnPrecacheGeneric(char* s) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheGeneric: %s\n",s); fclose(fp); } - return (*g_engfuncs.pfnPrecacheGeneric)(s); -} -int pfnGetPlayerUserId(edict_t *e ) -{ - if (gpGlobals->deathmatch) - { - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPlayerUserId: %x\n",e); fclose(fp); } - - if (mod_id == GEARBOX_DLL) - { - // is this edict a bot? - if (UTIL_GetBotPointer( e )) - return 0; // don't return a valid index (so bot won't get kicked) - } - } - - return (*g_engfuncs.pfnGetPlayerUserId)(e); -} -void pfnBuildSoundMsg(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnBuildSoundMsg:\n"); fclose(fp); } - (*g_engfuncs.pfnBuildSoundMsg)(entity, channel, sample, volume, attenuation, fFlags, pitch, msg_dest, msg_type, pOrigin, ed); -} -int pfnIsDedicatedServer(void) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnIsDedicatedServer:\n"); fclose(fp); } - return (*g_engfuncs.pfnIsDedicatedServer)(); -} -cvar_t* pfnCVarGetPointer(const char *szVarName) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarGetPointer: %s\n",szVarName); fclose(fp); } - return (*g_engfuncs.pfnCVarGetPointer)(szVarName); -} -unsigned int pfnGetPlayerWONId(edict_t *e) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPlayerWONId: %x\n",e); fclose(fp); } - return (*g_engfuncs.pfnGetPlayerWONId)(e); -} - - -// new stuff for SDK 2.0 - -void pfnInfo_RemoveKey(char *s, const char *key) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnInfo_RemoveKey:\n"); fclose(fp); } - (*g_engfuncs.pfnInfo_RemoveKey)(s, key); -} -const char *pfnGetPhysicsKeyValue(const edict_t *pClient, const char *key) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPhysicsKeyValue:\n"); fclose(fp); } - return (*g_engfuncs.pfnGetPhysicsKeyValue)(pClient, key); -} -void pfnSetPhysicsKeyValue(const edict_t *pClient, const char *key, const char *value) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetPhysicsKeyValue:\n"); fclose(fp); } - (*g_engfuncs.pfnSetPhysicsKeyValue)(pClient, key, value); -} -const char *pfnGetPhysicsInfoString(const edict_t *pClient) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPhysicsInfoString:\n"); fclose(fp); } - return (*g_engfuncs.pfnGetPhysicsInfoString)(pClient); -} -unsigned short pfnPrecacheEvent(int type, const char *psz) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheEvent:\n"); fclose(fp); } - return (*g_engfuncs.pfnPrecacheEvent)(type, psz); -} -void pfnPlaybackEvent(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, - float *origin, float *angles, float fparam1,float fparam2, int iparam1, int iparam2, int bparam1, int bparam2) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPlaybackEvent:\n"); fclose(fp); } - (*g_engfuncs.pfnPlaybackEvent)(flags, pInvoker, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2); -} -unsigned char *pfnSetFatPVS(float *org) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetFatPVS:\n"); fclose(fp); } - return (*g_engfuncs.pfnSetFatPVS)(org); -} -unsigned char *pfnSetFatPAS(float *org) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetFatPAS:\n"); fclose(fp); } - return (*g_engfuncs.pfnSetFatPAS)(org); -} -int pfnCheckVisibility(const edict_t *entity, unsigned char *pset) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCheckVisibility:\n"); fclose(fp); } - return (*g_engfuncs.pfnCheckVisibility)(entity, pset); -} -void pfnDeltaSetField(struct delta_s *pFields, const char *fieldname) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaSetField:\n"); fclose(fp); } - (*g_engfuncs.pfnDeltaSetField)(pFields, fieldname); -} -void pfnDeltaUnsetField(struct delta_s *pFields, const char *fieldname) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaUnsetField:\n"); fclose(fp); } - (*g_engfuncs.pfnDeltaUnsetField)(pFields, fieldname); -} -void pfnDeltaAddEncoder(char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to)) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaAddEncoder:\n"); fclose(fp); } - (*g_engfuncs.pfnDeltaAddEncoder)(name, conditionalencode); -} -int pfnGetCurrentPlayer(void) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetCurrentPlayer:\n"); fclose(fp); } - return (*g_engfuncs.pfnGetCurrentPlayer)(); -} -int pfnCanSkipPlayer(const edict_t *player) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCanSkipPlayer:\n"); fclose(fp); } - return (*g_engfuncs.pfnCanSkipPlayer)(player); -} -int pfnDeltaFindField(struct delta_s *pFields, const char *fieldname) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaFindField:\n"); fclose(fp); } - return (*g_engfuncs.pfnDeltaFindField)(pFields, fieldname); -} -void pfnDeltaSetFieldByIndex(struct delta_s *pFields, int fieldNumber) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaSetFieldByIndex:\n"); fclose(fp); } - (*g_engfuncs.pfnDeltaSetFieldByIndex)(pFields, fieldNumber); -} -void pfnDeltaUnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) -{ -// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaUnsetFieldByIndex:\n"); fclose(fp); } - (*g_engfuncs.pfnDeltaUnsetFieldByIndex)(pFields, fieldNumber); -} -void pfnSetGroupMask(int mask, int op) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetGroupMask:\n"); fclose(fp); } - (*g_engfuncs.pfnSetGroupMask)(mask, op); -} -int pfnCreateInstancedBaseline(int classname, struct entity_state_s *baseline) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateInstancedBaseline:\n"); fclose(fp); } - return (*g_engfuncs.pfnCreateInstancedBaseline)(classname, baseline); -} -void pfnCvar_DirectSet(struct cvar_s *var, char *value) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCvar_DirectSet:\n"); fclose(fp); } - (*g_engfuncs.pfnCvar_DirectSet)(var, value); -} -void pfnForceUnmodified(FORCE_TYPE type, float *mins, float *maxs, const char *filename) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnForceUnmodified:\n"); fclose(fp); } - (*g_engfuncs.pfnForceUnmodified)(type, mins, maxs, filename); -} -void pfnGetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss) -{ - if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPlayerStats:\n"); fclose(fp); } - (*g_engfuncs.pfnGetPlayerStats)(pClient, ping, packet_loss); -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// engine.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" + +#include "bot.h" +#include "bot_client.h" +#include "HPB_bot/engine/engine.h" + + +extern enginefuncs_t g_engfuncs; +extern bot_t bots[32]; +extern int mod_id; + + +int debug_engine = 0; + +void (*botMsgFunction)(void *, int) = NULL; +void (*botMsgEndFunction)(void *, int) = NULL; +int botMsgIndex; + +// messages created in RegUserMsg which will be "caught" +int message_VGUI = 0; +int message_ShowMenu = 0; +int message_WeaponList = 0; +int message_CurWeapon = 0; +int message_AmmoX = 0; +int message_WeapPickup = 0; +int message_AmmoPickup = 0; +int message_ItemPickup = 0; +int message_Health = 0; +int message_Battery = 0; // Armor +int message_Damage = 0; +int message_Money = 0; // for Counter-Strike +int message_DeathMsg = 0; +int message_TextMsg = 0; +int message_WarmUp = 0; // for Front Line Force +int message_WinMessage = 0; // for Front Line Force +int message_ScreenFade = 0; + +// AvH messages +int message_SetPlayMode = 0; +int message_SetOrder = 0; +int message_SetResources = 0; + +static FILE *fp; + + +int pfnPrecacheModel(char* s) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheModel: %s\n",s); fclose(fp); } + return (*g_engfuncs.pfnPrecacheModel)(s); +} +int pfnPrecacheSound(char* s) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheSound: %s\n",s); fclose(fp); } + return (*g_engfuncs.pfnPrecacheSound)(s); +} +void pfnSetModel(edict_t *e, const char *m) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetModel: edict=%x %s\n",e,m); fclose(fp); } + (*g_engfuncs.pfnSetModel)(e, m); +} +int pfnModelIndex(const char *m) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnModelIndex: %s\n",m); fclose(fp); } + return (*g_engfuncs.pfnModelIndex)(m); +} +int pfnModelFrames(int modelIndex) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnModelFrames:\n"); fclose(fp); } + return (*g_engfuncs.pfnModelFrames)(modelIndex); +} +void pfnSetSize(edict_t *e, const float *rgflMin, const float *rgflMax) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetSize: %x\n",e); fclose(fp); } + (*g_engfuncs.pfnSetSize)(e, rgflMin, rgflMax); +} +void pfnChangeLevel(char* s1, char* s2) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnChangeLevel:\n"); fclose(fp); } + + // kick any bot off of the server after time/frag limit... + for (int index = 0; index < 32; index++) + { + if (bots[index].is_used) // is this slot used? + { + char cmd[40]; + + sprintf(cmd, "kick \"%s\"\n", bots[index].name); + + bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; + + SERVER_COMMAND(cmd); // kick the bot using (kick "name") + } + } + + (*g_engfuncs.pfnChangeLevel)(s1, s2); +} +void pfnGetSpawnParms(edict_t *ent) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetSpawnParms:\n"); fclose(fp); } + (*g_engfuncs.pfnGetSpawnParms)(ent); +} +void pfnSaveSpawnParms(edict_t *ent) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSaveSpawnParms:\n"); fclose(fp); } + (*g_engfuncs.pfnSaveSpawnParms)(ent); +} +float pfnVecToYaw(const float *rgflVector) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnVecToYaw:\n"); fclose(fp); } + return (*g_engfuncs.pfnVecToYaw)(rgflVector); +} +void pfnVecToAngles(const float *rgflVectorIn, float *rgflVectorOut) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnVecToAngles:\n"); fclose(fp); } + (*g_engfuncs.pfnVecToAngles)(rgflVectorIn, rgflVectorOut); +} +void pfnMoveToOrigin(edict_t *ent, const float *pflGoal, float dist, int iMoveType) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMoveToOrigin:\n"); fclose(fp); } + (*g_engfuncs.pfnMoveToOrigin)(ent, pflGoal, dist, iMoveType); +} +void pfnChangeYaw(edict_t* ent) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnChangeYaw:\n"); fclose(fp); } + (*g_engfuncs.pfnChangeYaw)(ent); +} +void pfnChangePitch(edict_t* ent) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnChangePitch:\n"); fclose(fp); } + (*g_engfuncs.pfnChangePitch)(ent); +} +edict_t* pfnFindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindEntityByString: %s\n",pszValue); fclose(fp); } + return (*g_engfuncs.pfnFindEntityByString)(pEdictStartSearchAfter, pszField, pszValue); +} +int pfnGetEntityIllum(edict_t* pEnt) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetEntityIllum:\n"); fclose(fp); } + return (*g_engfuncs.pfnGetEntityIllum)(pEnt); +} +edict_t* pfnFindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindEntityInSphere:\n"); fclose(fp); } + return (*g_engfuncs.pfnFindEntityInSphere)(pEdictStartSearchAfter, org, rad); +} +edict_t* pfnFindClientInPVS(edict_t *pEdict) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindClientInPVS:\n"); fclose(fp); } + return (*g_engfuncs.pfnFindClientInPVS)(pEdict); +} +edict_t* pfnEntitiesInPVS(edict_t *pplayer) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEntitiesInPVS:\n"); fclose(fp); } + return (*g_engfuncs.pfnEntitiesInPVS)(pplayer); +} +void pfnMakeVectors(const float *rgflVector) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMakeVectors:\n"); fclose(fp); } + (*g_engfuncs.pfnMakeVectors)(rgflVector); +} +void pfnAngleVectors(const float *rgflVector, float *forward, float *right, float *up) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnAngleVectors:\n"); fclose(fp); } + (*g_engfuncs.pfnAngleVectors)(rgflVector, forward, right, up); +} +edict_t* pfnCreateEntity(void) +{ + edict_t *pent = (*g_engfuncs.pfnCreateEntity)(); + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateEntity: %x\n",pent); fclose(fp); } + return pent; +} +void pfnRemoveEntity(edict_t* e) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRemoveEntity: %x\n",e); fclose(fp); } + if (debug_engine) + { + fp=fopen("bot.txt","a"); + fprintf(fp,"pfnRemoveEntity: %x\n",e); + if (e->v.model != 0) + fprintf(fp," model=%s\n", STRING(e->v.model)); + fclose(fp); + } + + (*g_engfuncs.pfnRemoveEntity)(e); +} +edict_t* pfnCreateNamedEntity(int className) +{ + edict_t *pent = (*g_engfuncs.pfnCreateNamedEntity)(className); + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateNamedEntity: edict=%x name=%s\n",pent,STRING(className)); fclose(fp); } + return pent; +} +void pfnMakeStatic(edict_t *ent) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMakeStatic:\n"); fclose(fp); } + (*g_engfuncs.pfnMakeStatic)(ent); +} +int pfnEntIsOnFloor(edict_t *e) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEntIsOnFloor:\n"); fclose(fp); } + return (*g_engfuncs.pfnEntIsOnFloor)(e); +} +int pfnDropToFloor(edict_t* e) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDropToFloor:\n"); fclose(fp); } + return (*g_engfuncs.pfnDropToFloor)(e); +} +int pfnWalkMove(edict_t *ent, float yaw, float dist, int iMode) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWalkMove:\n"); fclose(fp); } + return (*g_engfuncs.pfnWalkMove)(ent, yaw, dist, iMode); +} +void pfnSetOrigin(edict_t *e, const float *rgflOrigin) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetOrigin:\n"); fclose(fp); } + (*g_engfuncs.pfnSetOrigin)(e, rgflOrigin); +} +void pfnEmitSound(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEmitSound:\n"); fclose(fp); } + (*g_engfuncs.pfnEmitSound)(entity, channel, sample, volume, attenuation, fFlags, pitch); +} +void pfnEmitAmbientSound(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEmitAmbientSound:\n"); fclose(fp); } + (*g_engfuncs.pfnEmitAmbientSound)(entity, pos, samp, vol, attenuation, fFlags, pitch); +} +void pfnTraceLine(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceLine:\n"); fclose(fp); } + (*g_engfuncs.pfnTraceLine)(v1, v2, fNoMonsters, pentToSkip, ptr); +} +void pfnTraceToss(edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceToss:\n"); fclose(fp); } + (*g_engfuncs.pfnTraceToss)(pent, pentToIgnore, ptr); +} +int pfnTraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceMonsterHull:\n"); fclose(fp); } + return (*g_engfuncs.pfnTraceMonsterHull)(pEdict, v1, v2, fNoMonsters, pentToSkip, ptr); +} +void pfnTraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceHull:\n"); fclose(fp); } + (*g_engfuncs.pfnTraceHull)(v1, v2, fNoMonsters, hullNumber, pentToSkip, ptr); +} +void pfnTraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceModel:\n"); fclose(fp); } + (*g_engfuncs.pfnTraceModel)(v1, v2, hullNumber, pent, ptr); +} +const char *pfnTraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2 ) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceTexture:\n"); fclose(fp); } + return (*g_engfuncs.pfnTraceTexture)(pTextureEntity, v1, v2); +} +void pfnTraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTraceSphere:\n"); fclose(fp); } + (*g_engfuncs.pfnTraceSphere)(v1, v2, fNoMonsters, radius, pentToSkip, ptr); +} +void pfnGetAimVector(edict_t* ent, float speed, float *rgflReturn) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetAimVector:\n"); fclose(fp); } + (*g_engfuncs.pfnGetAimVector)(ent, speed, rgflReturn); +} +void pfnServerCommand(char* str) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnServerCommand: %s\n",str); fclose(fp); } + (*g_engfuncs.pfnServerCommand)(str); +} +void pfnServerExecute(void) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnServerExecute:\n"); fclose(fp); } + (*g_engfuncs.pfnServerExecute)(); +} +void pfnClientCommand(edict_t* pEdict, char* szFmt, ...) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnClientCommand=%s\n",szFmt); fclose(fp); } + return; +} +void pfnParticleEffect(const float *org, const float *dir, float color, float count) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnParticleEffect:\n"); fclose(fp); } + (*g_engfuncs.pfnParticleEffect)(org, dir, color, count); +} +void pfnLightStyle(int style, char* val) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnLightStyle:\n"); fclose(fp); } + (*g_engfuncs.pfnLightStyle)(style, val); +} +int pfnDecalIndex(const char *name) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDecalIndex:\n"); fclose(fp); } + return (*g_engfuncs.pfnDecalIndex)(name); +} +int pfnPointContents(const float *rgflVector) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPointContents:\n"); fclose(fp); } + return (*g_engfuncs.pfnPointContents)(rgflVector); +} +void pfnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + if (gpGlobals->deathmatch) + { + int index = -1; + + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMessageBegin: edict=%x dest=%d type=%d\n",ed,msg_dest,msg_type); fclose(fp); } + + if (ed) + { + index = UTIL_GetBotIndex(ed); + + // is this message for a bot? + if (index != -1) + { + botMsgFunction = NULL; // no msg function until known otherwise + botMsgEndFunction = NULL; // no msg end function until known otherwise + botMsgIndex = index; // index of bot receiving message + + if (mod_id == VALVE_DLL) + { + if (msg_type == message_WeaponList) + botMsgFunction = BotClient_Valve_WeaponList; + else if (msg_type == message_CurWeapon) + botMsgFunction = BotClient_Valve_CurrentWeapon; + else if (msg_type == message_AmmoX) + botMsgFunction = BotClient_Valve_AmmoX; + else if (msg_type == message_AmmoPickup) + botMsgFunction = BotClient_Valve_AmmoPickup; + else if (msg_type == message_WeapPickup) + botMsgFunction = BotClient_Valve_WeaponPickup; + else if (msg_type == message_ItemPickup) + botMsgFunction = BotClient_Valve_ItemPickup; + else if (msg_type == message_Health) + botMsgFunction = BotClient_Valve_Health; + else if (msg_type == message_Battery) + botMsgFunction = BotClient_Valve_Battery; + else if (msg_type == message_Damage) + botMsgFunction = BotClient_Valve_Damage; + else if (msg_type == message_ScreenFade) + botMsgFunction = BotClient_Valve_ScreenFade; + } + else if (mod_id == TFC_DLL) + { + if (msg_type == message_VGUI) + botMsgFunction = BotClient_TFC_VGUI; + else if (msg_type == message_WeaponList) + botMsgFunction = BotClient_TFC_WeaponList; + else if (msg_type == message_CurWeapon) + botMsgFunction = BotClient_TFC_CurrentWeapon; + else if (msg_type == message_AmmoX) + botMsgFunction = BotClient_TFC_AmmoX; + else if (msg_type == message_AmmoPickup) + botMsgFunction = BotClient_TFC_AmmoPickup; + else if (msg_type == message_WeapPickup) + botMsgFunction = BotClient_TFC_WeaponPickup; + else if (msg_type == message_ItemPickup) + botMsgFunction = BotClient_TFC_ItemPickup; + else if (msg_type == message_Health) + botMsgFunction = BotClient_TFC_Health; + else if (msg_type == message_Battery) + botMsgFunction = BotClient_TFC_Battery; + else if (msg_type == message_Damage) + botMsgFunction = BotClient_TFC_Damage; + else if (msg_type == message_ScreenFade) + botMsgFunction = BotClient_TFC_ScreenFade; + } + else if (mod_id == CSTRIKE_DLL) + { + if (msg_type == message_VGUI) + botMsgFunction = BotClient_CS_VGUI; + else if (msg_type == message_ShowMenu) + botMsgFunction = BotClient_CS_ShowMenu; + else if (msg_type == message_WeaponList) + botMsgFunction = BotClient_CS_WeaponList; + else if (msg_type == message_CurWeapon) + botMsgFunction = BotClient_CS_CurrentWeapon; + else if (msg_type == message_AmmoX) + botMsgFunction = BotClient_CS_AmmoX; + else if (msg_type == message_WeapPickup) + botMsgFunction = BotClient_CS_WeaponPickup; + else if (msg_type == message_AmmoPickup) + botMsgFunction = BotClient_CS_AmmoPickup; + else if (msg_type == message_ItemPickup) + botMsgFunction = BotClient_CS_ItemPickup; + else if (msg_type == message_Health) + botMsgFunction = BotClient_CS_Health; + else if (msg_type == message_Battery) + botMsgFunction = BotClient_CS_Battery; + else if (msg_type == message_Damage) + botMsgFunction = BotClient_CS_Damage; + else if (msg_type == message_Money) + botMsgFunction = BotClient_CS_Money; + else if (msg_type == message_ScreenFade) + botMsgFunction = BotClient_CS_ScreenFade; + } + else if (mod_id == GEARBOX_DLL) + { + if (msg_type == message_VGUI) + botMsgFunction = BotClient_Gearbox_VGUI; + else if (msg_type == message_WeaponList) + botMsgFunction = BotClient_Gearbox_WeaponList; + else if (msg_type == message_CurWeapon) + botMsgFunction = BotClient_Gearbox_CurrentWeapon; + else if (msg_type == message_AmmoX) + botMsgFunction = BotClient_Gearbox_AmmoX; + else if (msg_type == message_AmmoPickup) + botMsgFunction = BotClient_Gearbox_AmmoPickup; + else if (msg_type == message_WeapPickup) + botMsgFunction = BotClient_Gearbox_WeaponPickup; + else if (msg_type == message_ItemPickup) + botMsgFunction = BotClient_Gearbox_ItemPickup; + else if (msg_type == message_Health) + botMsgFunction = BotClient_Gearbox_Health; + else if (msg_type == message_Battery) + botMsgFunction = BotClient_Gearbox_Battery; + else if (msg_type == message_Damage) + botMsgFunction = BotClient_Gearbox_Damage; + else if (msg_type == message_ScreenFade) + botMsgFunction = BotClient_Gearbox_ScreenFade; + } + else if (mod_id == FRONTLINE_DLL) + { + if (msg_type == message_VGUI) + botMsgFunction = BotClient_FLF_VGUI; + else if (msg_type == message_WeaponList) + botMsgFunction = BotClient_FLF_WeaponList; + else if (msg_type == message_CurWeapon) + botMsgFunction = BotClient_FLF_CurrentWeapon; + else if (msg_type == message_AmmoX) + botMsgFunction = BotClient_FLF_AmmoX; + else if (msg_type == message_AmmoPickup) + botMsgFunction = BotClient_FLF_AmmoPickup; + else if (msg_type == message_WeapPickup) + botMsgFunction = BotClient_FLF_WeaponPickup; + else if (msg_type == message_ItemPickup) + botMsgFunction = BotClient_FLF_ItemPickup; + else if (msg_type == message_Health) + botMsgFunction = BotClient_FLF_Health; + else if (msg_type == message_Battery) + botMsgFunction = BotClient_FLF_Battery; + else if (msg_type == message_Damage) + botMsgFunction = BotClient_FLF_Damage; + else if (msg_type == message_TextMsg) + botMsgFunction = BotClient_FLF_TextMsg; + else if (msg_type == message_WarmUp) + botMsgFunction = BotClient_FLF_WarmUp; + else if (msg_type == message_ScreenFade) + botMsgFunction = BotClient_FLF_ScreenFade; + else if (msg_type == 23) // SVC_TEMPENTITY + { + botMsgFunction = BotClient_FLF_TempEntity; + botMsgEndFunction = BotClient_FLF_TempEntity; + } + } + else if (mod_id == AVH_DLL) + { + if (msg_type == message_SetPlayMode) + botMsgFunction = BotClient_AVH_SetPlayMode; + else if (msg_type == message_AmmoX) + botMsgFunction = BotClient_Valve_AmmoX; + else if (msg_type == message_AmmoPickup) + botMsgFunction = BotClient_Valve_AmmoPickup; + else if (msg_type == message_WeapPickup) + botMsgFunction = BotClient_Valve_WeaponPickup; + else if (msg_type == message_ItemPickup) + botMsgFunction = BotClient_Valve_ItemPickup; + else if (msg_type == message_WeaponList) + botMsgFunction = BotClient_Valve_WeaponList; + else if (msg_type == message_SetOrder) + botMsgFunction = BotClient_AVH_SetOrder; + else if (msg_type == message_SetResources) + botMsgFunction = BotClient_AVH_SetResources; + } + } + } + else if (msg_dest == MSG_ALL) + { + botMsgFunction = NULL; // no msg function until known otherwise + botMsgIndex = -1; // index of bot receiving message (none) + + if (mod_id == VALVE_DLL) + { + if (msg_type == message_DeathMsg) + botMsgFunction = BotClient_Valve_DeathMsg; + } + else if (mod_id == TFC_DLL) + { + if (msg_type == message_DeathMsg) + botMsgFunction = BotClient_TFC_DeathMsg; + } + else if (mod_id == CSTRIKE_DLL) + { + if (msg_type == message_DeathMsg) + botMsgFunction = BotClient_CS_DeathMsg; + } + else if (mod_id == GEARBOX_DLL) + { + if (msg_type == message_DeathMsg) + botMsgFunction = BotClient_Gearbox_DeathMsg; + } + else if (mod_id == FRONTLINE_DLL) + { + if (msg_type == message_DeathMsg) + botMsgFunction = BotClient_FLF_DeathMsg; + else if (msg_type == message_WarmUp) + botMsgFunction = BotClient_FLF_WarmUpAll; + else if (msg_type == message_WinMessage) + botMsgFunction = BotClient_FLF_WinMessage; + } + } + } + + (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); +} +void pfnMessageEnd(void) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnMessageEnd:\n"); fclose(fp); } + + if (botMsgEndFunction) + (*botMsgEndFunction)(NULL, botMsgIndex); // NULL indicated msg end + + // clear out the bot message function pointers... + botMsgFunction = NULL; + botMsgEndFunction = NULL; + } + + (*g_engfuncs.pfnMessageEnd)(); +} +void pfnWriteByte(int iValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteByte: %d\n",iValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&iValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteByte)(iValue); +} +void pfnWriteChar(int iValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteChar: %d\n",iValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&iValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteChar)(iValue); +} +void pfnWriteShort(int iValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteShort: %d\n",iValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&iValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteShort)(iValue); +} +void pfnWriteLong(int iValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteLong: %d\n",iValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&iValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteLong)(iValue); +} +void pfnWriteAngle(float flValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteAngle: %f\n",flValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&flValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteAngle)(flValue); +} +void pfnWriteCoord(float flValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteCoord: %f\n",flValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&flValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteCoord)(flValue); +} +void pfnWriteString(const char *sz) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteString: %s\n",sz); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)sz, botMsgIndex); + } + + (*g_engfuncs.pfnWriteString)(sz); +} +void pfnWriteEntity(int iValue) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnWriteEntity: %d\n",iValue); fclose(fp); } + + // if this message is for a bot, call the client message function... + if (botMsgFunction) + (*botMsgFunction)((void *)&iValue, botMsgIndex); + } + + (*g_engfuncs.pfnWriteEntity)(iValue); +} +void pfnCVarRegister(cvar_t *pCvar) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarRegister:\n"); fclose(fp); } + (*g_engfuncs.pfnCVarRegister)(pCvar); +} +float pfnCVarGetFloat(const char *szVarName) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarGetFloat: %s\n",szVarName); fclose(fp); } + return (*g_engfuncs.pfnCVarGetFloat)(szVarName); +} +const char* pfnCVarGetString(const char *szVarName) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarGetString:\n"); fclose(fp); } + return (*g_engfuncs.pfnCVarGetString)(szVarName); +} +void pfnCVarSetFloat(const char *szVarName, float flValue) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarSetFloat:\n"); fclose(fp); } + (*g_engfuncs.pfnCVarSetFloat)(szVarName, flValue); +} +void pfnCVarSetString(const char *szVarName, const char *szValue) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarSetString:\n"); fclose(fp); } + (*g_engfuncs.pfnCVarSetString)(szVarName, szValue); +} +void* pfnPvAllocEntPrivateData(edict_t *pEdict, long cb) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPvAllocEntPrivateData:\n"); fclose(fp); } + return (*g_engfuncs.pfnPvAllocEntPrivateData)(pEdict, cb); +} +void* pfnPvEntPrivateData(edict_t *pEdict) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPvEntPrivateData:\n"); fclose(fp); } + return (*g_engfuncs.pfnPvEntPrivateData)(pEdict); +} +void pfnFreeEntPrivateData(edict_t *pEdict) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFreeEntPrivateData:\n"); fclose(fp); } + (*g_engfuncs.pfnFreeEntPrivateData)(pEdict); +} +const char* pfnSzFromIndex(int iString) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSzFromIndex:\n"); fclose(fp); } + return (*g_engfuncs.pfnSzFromIndex)(iString); +} +int pfnAllocString(const char *szValue) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnAllocString:\n"); fclose(fp); } + return (*g_engfuncs.pfnAllocString)(szValue); +} +entvars_t* pfnGetVarsOfEnt(edict_t *pEdict) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetVarsOfEnt:\n"); fclose(fp); } + return (*g_engfuncs.pfnGetVarsOfEnt)(pEdict); +} +edict_t* pfnPEntityOfEntOffset(int iEntOffset) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPEntityOfEntOffset:\n"); fclose(fp); } + return (*g_engfuncs.pfnPEntityOfEntOffset)(iEntOffset); +} +int pfnEntOffsetOfPEntity(const edict_t *pEdict) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEntOffsetOfPEntity: %x\n",pEdict); fclose(fp); } + return (*g_engfuncs.pfnEntOffsetOfPEntity)(pEdict); +} +int pfnIndexOfEdict(const edict_t *pEdict) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnIndexOfEdict: %x\n",pEdict); fclose(fp); } + return (*g_engfuncs.pfnIndexOfEdict)(pEdict); +} +edict_t* pfnPEntityOfEntIndex(int iEntIndex) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPEntityOfEntIndex:\n"); fclose(fp); } + return (*g_engfuncs.pfnPEntityOfEntIndex)(iEntIndex); +} +edict_t* pfnFindEntityByVars(entvars_t* pvars) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFindEntityByVars:\n"); fclose(fp); } + return (*g_engfuncs.pfnFindEntityByVars)(pvars); +} +void* pfnGetModelPtr(edict_t* pEdict) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetModelPtr: %x\n",pEdict); fclose(fp); } + return (*g_engfuncs.pfnGetModelPtr)(pEdict); +} +int pfnRegUserMsg(const char *pszName, int iSize) +{ + int msg; + + msg = (*g_engfuncs.pfnRegUserMsg)(pszName, iSize); + + //if (gpGlobals->deathmatch) + //{ +#ifdef _DEBUG + fp=fopen("bot.txt","a"); fprintf(fp,"pfnRegUserMsg: pszName=%s msg=%d\n",pszName,msg); fclose(fp); +#endif + + if (mod_id == VALVE_DLL) + { + if (strcmp(pszName, "WeaponList") == 0) + message_WeaponList = msg; + else if (strcmp(pszName, "CurWeapon") == 0) + message_CurWeapon = msg; + else if (strcmp(pszName, "AmmoX") == 0) + message_AmmoX = msg; + else if (strcmp(pszName, "AmmoPickup") == 0) + message_AmmoPickup = msg; + else if (strcmp(pszName, "WeapPickup") == 0) + message_WeapPickup = msg; + else if (strcmp(pszName, "ItemPickup") == 0) + message_ItemPickup = msg; + else if (strcmp(pszName, "Health") == 0) + message_Health = msg; + else if (strcmp(pszName, "Battery") == 0) + message_Battery = msg; + else if (strcmp(pszName, "Damage") == 0) + message_Damage = msg; + else if (strcmp(pszName, "DeathMsg") == 0) + message_DeathMsg = msg; + else if (strcmp(pszName, "ScreenFade") == 0) + message_ScreenFade = msg; + } + else if (mod_id == TFC_DLL) + { + if (strcmp(pszName, "VGUIMenu") == 0) + message_VGUI = msg; + else if (strcmp(pszName, "WeaponList") == 0) + message_WeaponList = msg; + else if (strcmp(pszName, "CurWeapon") == 0) + message_CurWeapon = msg; + else if (strcmp(pszName, "AmmoX") == 0) + message_AmmoX = msg; + else if (strcmp(pszName, "AmmoPickup") == 0) + message_AmmoPickup = msg; + else if (strcmp(pszName, "WeapPickup") == 0) + message_WeapPickup = msg; + else if (strcmp(pszName, "ItemPickup") == 0) + message_ItemPickup = msg; + else if (strcmp(pszName, "Health") == 0) + message_Health = msg; + else if (strcmp(pszName, "Battery") == 0) + message_Battery = msg; + else if (strcmp(pszName, "Damage") == 0) + message_Damage = msg; + else if (strcmp(pszName, "DeathMsg") == 0) + message_DeathMsg = msg; + else if (strcmp(pszName, "ScreenFade") == 0) + message_ScreenFade = msg; + } + else if (mod_id == CSTRIKE_DLL) + { + if (strcmp(pszName, "VGUIMenu") == 0) + message_VGUI = msg; + else if (strcmp(pszName, "ShowMenu") == 0) + message_ShowMenu = msg; + else if (strcmp(pszName, "WeaponList") == 0) + message_WeaponList = msg; + else if (strcmp(pszName, "CurWeapon") == 0) + message_CurWeapon = msg; + else if (strcmp(pszName, "AmmoX") == 0) + message_AmmoX = msg; + else if (strcmp(pszName, "AmmoPickup") == 0) + message_AmmoPickup = msg; + else if (strcmp(pszName, "WeapPickup") == 0) + message_WeapPickup = msg; + else if (strcmp(pszName, "ItemPickup") == 0) + message_ItemPickup = msg; + else if (strcmp(pszName, "Health") == 0) + message_Health = msg; + else if (strcmp(pszName, "Battery") == 0) + message_Battery = msg; + else if (strcmp(pszName, "Damage") == 0) + message_Damage = msg; + else if (strcmp(pszName, "Money") == 0) + message_Money = msg; + else if (strcmp(pszName, "DeathMsg") == 0) + message_DeathMsg = msg; + else if (strcmp(pszName, "ScreenFade") == 0) + message_ScreenFade = msg; + } + else if (mod_id == GEARBOX_DLL) + { + if (strcmp(pszName, "VGUIMenu") == 0) + message_VGUI = msg; + else if (strcmp(pszName, "WeaponList") == 0) + message_WeaponList = msg; + else if (strcmp(pszName, "CurWeapon") == 0) + message_CurWeapon = msg; + else if (strcmp(pszName, "AmmoX") == 0) + message_AmmoX = msg; + else if (strcmp(pszName, "AmmoPickup") == 0) + message_AmmoPickup = msg; + else if (strcmp(pszName, "WeapPickup") == 0) + message_WeapPickup = msg; + else if (strcmp(pszName, "ItemPickup") == 0) + message_ItemPickup = msg; + else if (strcmp(pszName, "Health") == 0) + message_Health = msg; + else if (strcmp(pszName, "Battery") == 0) + message_Battery = msg; + else if (strcmp(pszName, "Damage") == 0) + message_Damage = msg; + else if (strcmp(pszName, "DeathMsg") == 0) + message_DeathMsg = msg; + else if (strcmp(pszName, "ScreenFade") == 0) + message_ScreenFade = msg; + } + else if (mod_id == FRONTLINE_DLL) + { + if (strcmp(pszName, "VGUIMenu") == 0) + message_VGUI = msg; + else if (strcmp(pszName, "WeaponList") == 0) + message_WeaponList = msg; + else if (strcmp(pszName, "CurWeapon") == 0) + message_CurWeapon = msg; + else if (strcmp(pszName, "AmmoX") == 0) + message_AmmoX = msg; + else if (strcmp(pszName, "AmmoPickup") == 0) + message_AmmoPickup = msg; + else if (strcmp(pszName, "WeapPickup") == 0) + message_WeapPickup = msg; + else if (strcmp(pszName, "ItemPickup") == 0) + message_ItemPickup = msg; + else if (strcmp(pszName, "Health") == 0) + message_Health = msg; + else if (strcmp(pszName, "Battery") == 0) + message_Battery = msg; + else if (strcmp(pszName, "Damage") == 0) + message_Damage = msg; + else if (strcmp(pszName, "DeathMsg") == 0) + message_DeathMsg = msg; + else if (strcmp(pszName, "TextMsg") == 0) + message_TextMsg = msg; + else if (strcmp(pszName, "WarmUp") == 0) + message_WarmUp = msg; + else if (strcmp(pszName, "WinMessage") == 0) + message_WinMessage = msg; + else if (strcmp(pszName, "ScreenFade") == 0) + message_ScreenFade = msg; + } + else if (mod_id == AVH_DLL) + { + if (strcmp(pszName, "SetPlayMode") == 0) + message_SetPlayMode = msg; + else if (strcmp(pszName, "AmmoX") == 0) + message_AmmoX = msg; + else if (strcmp(pszName, "AmmoPickup") == 0) + message_AmmoPickup = msg; + else if (strcmp(pszName, "WeapPickup") == 0) + message_WeapPickup = msg; + else if (strcmp(pszName, "ItemPickup") == 0) + message_ItemPickup = msg; + else if (strcmp(pszName, "WeaponList") == 0) + message_WeaponList = msg; + else if (strcmp(pszName, "SetOrder") == 0) + message_SetOrder = msg; + else if (strcmp(pszName, "SetRsrces") == 0) + message_SetResources = msg; + + } + //} + + return msg; +} +void pfnAnimationAutomove(const edict_t* pEdict, float flTime) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnAnimationAutomove:\n"); fclose(fp); } + (*g_engfuncs.pfnAnimationAutomove)(pEdict, flTime); +} +void pfnGetBonePosition(const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetBonePosition:\n"); fclose(fp); } + (*g_engfuncs.pfnGetBonePosition)(pEdict, iBone, rgflOrigin, rgflAngles); +} +unsigned long pfnFunctionFromName( const char *pName ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFunctionFromName:\n"); fclose(fp); } + return (*g_engfuncs.pfnFunctionFromName)(pName); +} +const char *pfnNameForFunction( unsigned long function ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnNameForFunction:\n"); fclose(fp); } + const char* theName = (*g_engfuncs.pfnNameForFunction)(function); + return theName; +} +void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnClientPrintf:\n"); fclose(fp); } + (*g_engfuncs.pfnClientPrintf)(pEdict, ptype, szMsg); +} +void pfnServerPrint( const char *szMsg ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnServerPrint: %s\n",szMsg); fclose(fp); } + (*g_engfuncs.pfnServerPrint)(szMsg); +} +void pfnGetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetAttachment:\n"); fclose(fp); } + (*g_engfuncs.pfnGetAttachment)(pEdict, iAttachment, rgflOrigin, rgflAngles); +} +void pfnCRC32_Init(CRC32_t *pulCRC) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_Init:\n"); fclose(fp); } + (*g_engfuncs.pfnCRC32_Init)(pulCRC); +} +void pfnCRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_ProcessBuffer:\n"); fclose(fp); } + (*g_engfuncs.pfnCRC32_ProcessBuffer)(pulCRC, p, len); +} +void pfnCRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_ProcessByte:\n"); fclose(fp); } + (*g_engfuncs.pfnCRC32_ProcessByte)(pulCRC, ch); +} +CRC32_t pfnCRC32_Final(CRC32_t pulCRC) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCRC32_Final:\n"); fclose(fp); } + return (*g_engfuncs.pfnCRC32_Final)(pulCRC); +} +long pfnRandomLong(long lLow, long lHigh) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRandomLong: lLow=%d lHigh=%d\n",lLow,lHigh); fclose(fp); } + return (*g_engfuncs.pfnRandomLong)(lLow, lHigh); +} +float pfnRandomFloat(float flLow, float flHigh) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRandomFloat:\n"); fclose(fp); } + return (*g_engfuncs.pfnRandomFloat)(flLow, flHigh); +} +void pfnSetView(const edict_t *pClient, const edict_t *pViewent ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetView:\n"); fclose(fp); } + (*g_engfuncs.pfnSetView)(pClient, pViewent); +} +float pfnTime( void ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnTime:\n"); fclose(fp); } + return (*g_engfuncs.pfnTime)(); +} +void pfnCrosshairAngle(const edict_t *pClient, float pitch, float yaw) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCrosshairAngle:\n"); fclose(fp); } + (*g_engfuncs.pfnCrosshairAngle)(pClient, pitch, yaw); +} +byte *pfnLoadFileForMe(char *filename, int *pLength) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnLoadFileForMe: filename=%s\n",filename); fclose(fp); } + return (*g_engfuncs.pfnLoadFileForMe)(filename, pLength); +} +void pfnFreeFile(void *buffer) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFreeFile:\n"); fclose(fp); } + (*g_engfuncs.pfnFreeFile)(buffer); +} +void pfnEndSection(const char *pszSectionName) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnEndSection:\n"); fclose(fp); } + (*g_engfuncs.pfnEndSection)(pszSectionName); +} +int pfnCompareFileTime(char *filename1, char *filename2, int *iCompare) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCompareFileTime:\n"); fclose(fp); } + return (*g_engfuncs.pfnCompareFileTime)(filename1, filename2, iCompare); +} +void pfnGetGameDir(char *szGetGameDir) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetGameDir:\n"); fclose(fp); } + (*g_engfuncs.pfnGetGameDir)(szGetGameDir); +} +void pfnCvar_RegisterVariable(cvar_t *variable) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCvar_RegisterVariable:\n"); fclose(fp); } + (*g_engfuncs.pfnCvar_RegisterVariable)(variable); +} +void pfnFadeClientVolume(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnFadeClientVolume:\n"); fclose(fp); } + (*g_engfuncs.pfnFadeClientVolume)(pEdict, fadePercent, fadeOutSeconds, holdTime, fadeInSeconds); +} +void pfnSetClientMaxspeed(const edict_t *pEdict, float fNewMaxspeed) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetClientMaxspeed: edict=%x %f\n",pEdict,fNewMaxspeed); fclose(fp); } + (*g_engfuncs.pfnSetClientMaxspeed)(pEdict, fNewMaxspeed); +} +edict_t * pfnCreateFakeClient(const char *netname) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateFakeClient:\n"); fclose(fp); } + return (*g_engfuncs.pfnCreateFakeClient)(netname); +} +void pfnRunPlayerMove(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnRunPlayerMove:\n"); fclose(fp); } + (*g_engfuncs.pfnRunPlayerMove)(fakeclient, viewangles, forwardmove, sidemove, upmove, buttons, impulse, msec); +} +int pfnNumberOfEntities(void) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnNumberOfEntities:\n"); fclose(fp); } + return (*g_engfuncs.pfnNumberOfEntities)(); +} +char* pfnGetInfoKeyBuffer(edict_t *e) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetInfoKeyBuffer:\n"); fclose(fp); } + return (*g_engfuncs.pfnGetInfoKeyBuffer)(e); +} +char* pfnInfoKeyValue(char *infobuffer, char *key) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnInfoKeyValue: %s %s\n",infobuffer,key); fclose(fp); } + return (*g_engfuncs.pfnInfoKeyValue)(infobuffer, key); +} +void pfnSetKeyValue(char *infobuffer, char *key, char *value) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetKeyValue: %s %s\n",key,value); fclose(fp); } + (*g_engfuncs.pfnSetKeyValue)(infobuffer, key, value); +} +void pfnSetClientKeyValue(int clientIndex, char *infobuffer, char *key, char *value) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetClientKeyValue: %s %s\n",key,value); fclose(fp); } + (*g_engfuncs.pfnSetClientKeyValue)(clientIndex, infobuffer, key, value); +} +int pfnIsMapValid(char *filename) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnIsMapValid:\n"); fclose(fp); } + return (*g_engfuncs.pfnIsMapValid)(filename); +} +void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex ) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnStaticDecal:\n"); fclose(fp); } + (*g_engfuncs.pfnStaticDecal)(origin, decalIndex, entityIndex, modelIndex); +} +int pfnPrecacheGeneric(char* s) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheGeneric: %s\n",s); fclose(fp); } + return (*g_engfuncs.pfnPrecacheGeneric)(s); +} +int pfnGetPlayerUserId(edict_t *e ) +{ + if (gpGlobals->deathmatch) + { + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPlayerUserId: %x\n",e); fclose(fp); } + + if (mod_id == GEARBOX_DLL) + { + // is this edict a bot? + if (UTIL_GetBotPointer( e )) + return 0; // don't return a valid index (so bot won't get kicked) + } + } + + return (*g_engfuncs.pfnGetPlayerUserId)(e); +} +void pfnBuildSoundMsg(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnBuildSoundMsg:\n"); fclose(fp); } + (*g_engfuncs.pfnBuildSoundMsg)(entity, channel, sample, volume, attenuation, fFlags, pitch, msg_dest, msg_type, pOrigin, ed); +} +int pfnIsDedicatedServer(void) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnIsDedicatedServer:\n"); fclose(fp); } + return (*g_engfuncs.pfnIsDedicatedServer)(); +} +cvar_t* pfnCVarGetPointer(const char *szVarName) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCVarGetPointer: %s\n",szVarName); fclose(fp); } + return (*g_engfuncs.pfnCVarGetPointer)(szVarName); +} +unsigned int pfnGetPlayerWONId(edict_t *e) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPlayerWONId: %x\n",e); fclose(fp); } + return (*g_engfuncs.pfnGetPlayerWONId)(e); +} + + +// new stuff for SDK 2.0 + +void pfnInfo_RemoveKey(char *s, const char *key) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnInfo_RemoveKey:\n"); fclose(fp); } + (*g_engfuncs.pfnInfo_RemoveKey)(s, key); +} +const char *pfnGetPhysicsKeyValue(const edict_t *pClient, const char *key) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPhysicsKeyValue:\n"); fclose(fp); } + return (*g_engfuncs.pfnGetPhysicsKeyValue)(pClient, key); +} +void pfnSetPhysicsKeyValue(const edict_t *pClient, const char *key, const char *value) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetPhysicsKeyValue:\n"); fclose(fp); } + (*g_engfuncs.pfnSetPhysicsKeyValue)(pClient, key, value); +} +const char *pfnGetPhysicsInfoString(const edict_t *pClient) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPhysicsInfoString:\n"); fclose(fp); } + return (*g_engfuncs.pfnGetPhysicsInfoString)(pClient); +} +unsigned short pfnPrecacheEvent(int type, const char *psz) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPrecacheEvent:\n"); fclose(fp); } + return (*g_engfuncs.pfnPrecacheEvent)(type, psz); +} +void pfnPlaybackEvent(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, + float *origin, float *angles, float fparam1,float fparam2, int iparam1, int iparam2, int bparam1, int bparam2) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnPlaybackEvent:\n"); fclose(fp); } + (*g_engfuncs.pfnPlaybackEvent)(flags, pInvoker, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2); +} +unsigned char *pfnSetFatPVS(float *org) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetFatPVS:\n"); fclose(fp); } + return (*g_engfuncs.pfnSetFatPVS)(org); +} +unsigned char *pfnSetFatPAS(float *org) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetFatPAS:\n"); fclose(fp); } + return (*g_engfuncs.pfnSetFatPAS)(org); +} +int pfnCheckVisibility(const edict_t *entity, unsigned char *pset) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCheckVisibility:\n"); fclose(fp); } + return (*g_engfuncs.pfnCheckVisibility)(entity, pset); +} +void pfnDeltaSetField(struct delta_s *pFields, const char *fieldname) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaSetField:\n"); fclose(fp); } + (*g_engfuncs.pfnDeltaSetField)(pFields, fieldname); +} +void pfnDeltaUnsetField(struct delta_s *pFields, const char *fieldname) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaUnsetField:\n"); fclose(fp); } + (*g_engfuncs.pfnDeltaUnsetField)(pFields, fieldname); +} +void pfnDeltaAddEncoder(char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to)) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaAddEncoder:\n"); fclose(fp); } + (*g_engfuncs.pfnDeltaAddEncoder)(name, conditionalencode); +} +int pfnGetCurrentPlayer(void) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetCurrentPlayer:\n"); fclose(fp); } + return (*g_engfuncs.pfnGetCurrentPlayer)(); +} +int pfnCanSkipPlayer(const edict_t *player) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCanSkipPlayer:\n"); fclose(fp); } + return (*g_engfuncs.pfnCanSkipPlayer)(player); +} +int pfnDeltaFindField(struct delta_s *pFields, const char *fieldname) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaFindField:\n"); fclose(fp); } + return (*g_engfuncs.pfnDeltaFindField)(pFields, fieldname); +} +void pfnDeltaSetFieldByIndex(struct delta_s *pFields, int fieldNumber) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaSetFieldByIndex:\n"); fclose(fp); } + (*g_engfuncs.pfnDeltaSetFieldByIndex)(pFields, fieldNumber); +} +void pfnDeltaUnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) +{ +// if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnDeltaUnsetFieldByIndex:\n"); fclose(fp); } + (*g_engfuncs.pfnDeltaUnsetFieldByIndex)(pFields, fieldNumber); +} +void pfnSetGroupMask(int mask, int op) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnSetGroupMask:\n"); fclose(fp); } + (*g_engfuncs.pfnSetGroupMask)(mask, op); +} +int pfnCreateInstancedBaseline(int classname, struct entity_state_s *baseline) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCreateInstancedBaseline:\n"); fclose(fp); } + return (*g_engfuncs.pfnCreateInstancedBaseline)(classname, baseline); +} +void pfnCvar_DirectSet(struct cvar_s *var, char *value) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnCvar_DirectSet:\n"); fclose(fp); } + (*g_engfuncs.pfnCvar_DirectSet)(var, value); +} +void pfnForceUnmodified(FORCE_TYPE type, float *mins, float *maxs, const char *filename) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnForceUnmodified:\n"); fclose(fp); } + (*g_engfuncs.pfnForceUnmodified)(type, mins, maxs, filename); +} +void pfnGetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss) +{ + if (debug_engine) { fp=fopen("bot.txt","a"); fprintf(fp,"pfnGetPlayerStats:\n"); fclose(fp); } + (*g_engfuncs.pfnGetPlayerStats)(pClient, ping, packet_loss); +} + diff --git a/main/source/HPB_bot/dlls/h_export.cpp b/main/source/HPB_bot/dlls/h_export.cpp index c9dedfa5..acb2360b 100644 --- a/main/source/HPB_bot/dlls/h_export.cpp +++ b/main/source/HPB_bot/dlls/h_export.cpp @@ -1,290 +1,290 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// h_export.cpp -// - -#include "dlls/extdll.h" -#include "dlls/enginecallback.h" -#include "dlls/util.h" -#include "dlls/cbase.h" -#include "mod/AvHConstants.h" - -#include "bot.h" -#include "HPB_bot/engine/engine.h" -#include "../types.h" - -#ifndef __linux__ - -HINSTANCE h_Library = NULL; -HGLOBAL h_global_argv = NULL; - -#else - -void *h_Library = NULL; -char h_global_argv[1024]; - -#endif - -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; -char *g_argv; - -static FILE *fp; - - -GETENTITYAPI other_GetEntityAPI = NULL; -GETNEWDLLFUNCTIONS other_GetNewDLLFunctions = NULL; -GIVEFNPTRSTODLL other_GiveFnptrsToDll = NULL; - -extern int mod_id; - - -#ifndef __linux__ - -// Required DLL entry point -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - if (h_Library) - FreeLibrary(h_Library); - - if (h_global_argv) - { - GlobalUnlock(h_global_argv); - GlobalFree(h_global_argv); - } - } - - return TRUE; -} - -#endif - -#ifndef __linux__ -#ifdef __BORLANDC__ -extern "C" DLLEXPORT void EXPORT GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals) -#else -void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -#endif -#else -extern "C" DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -#endif -{ - int pos; - char game_dir[256]; - char mod_name[32]; - -//#ifdef AVH_MAPPER_BUILD -//strcpy(mod_name, kModDirectory); -//#endif - - // get the engine functions from the engine... - - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; - - // find the directory name of the currently running MOD... - (*g_engfuncs.pfnGetGameDir)(game_dir); - - pos = strlen(game_dir) - 1; - - // scan backwards till first directory separator... - while ((pos) && (game_dir[pos] != '/')) - pos--; - - if (pos == 0) - { - // Error getting directory name! - - ALERT( at_error, "HPB_bot - Error determining MOD directory name!" ); - } - - pos++; - strcpy(mod_name, &game_dir[pos]); - - mod_id = AVH_DLL; - - -#ifdef WIN32 - string theTempName = string(getModDirectory()) + "\\dlls\\ns.dll"; - h_Library = LoadLibrary(theTempName.c_str()); -// TODO: Add this in when supporting linux again -#else - printf("DLopening ns/dlls/HPB_bot_i386.so..."); - h_Library = dlopen("ns/dlls/HPB_bot_i386.so", RTLD_NOW); -#endif - - - if (h_Library == NULL) - { - // Directory error or Unsupported MOD! - - ALERT( at_error, "HPB_bot - MOD dll not found (or unsupported MOD)!" ); - } - - -#ifndef __linux__ - h_global_argv = GlobalAlloc(GMEM_SHARE, 1024); - g_argv = (char *)GlobalLock(h_global_argv); -#else - g_argv = (char *)h_global_argv; -#endif - - other_GetEntityAPI = (GETENTITYAPI)GetProcAddress(h_Library, "GetEntityAPI"); - - if (other_GetEntityAPI == NULL) - { - // Can't find GetEntityAPI! - - ALERT( at_error, "HPB_bot - Can't get MOD's GetEntityAPI!" ); - } - - other_GetNewDLLFunctions = (GETNEWDLLFUNCTIONS)GetProcAddress(h_Library, "GetNewDLLFunctions"); - -// if (other_GetNewDLLFunctions == NULL) -// { -// // Can't find GetNewDLLFunctions! -// -// ALERT( at_error, "HPB_bot - Can't get MOD's GetNewDLLFunctions!" ); -// } - - other_GiveFnptrsToDll = (GIVEFNPTRSTODLL)GetProcAddress(h_Library, "GiveFnptrsToDll"); - - if (other_GiveFnptrsToDll == NULL) - { - // Can't find GiveFnptrsToDll! - - ALERT( at_error, "HPB_bot - Can't get MOD's GiveFnptrsToDll!" ); - } - - pengfuncsFromEngine->pfnCmd_Args = Cmd_Args; - pengfuncsFromEngine->pfnCmd_Argv = Cmd_Argv; - pengfuncsFromEngine->pfnCmd_Argc = Cmd_Argc; - - pengfuncsFromEngine->pfnPrecacheModel = pfnPrecacheModel; - pengfuncsFromEngine->pfnPrecacheSound = pfnPrecacheSound; - pengfuncsFromEngine->pfnSetModel = pfnSetModel; - pengfuncsFromEngine->pfnModelIndex = pfnModelIndex; - pengfuncsFromEngine->pfnModelFrames = pfnModelFrames; - pengfuncsFromEngine->pfnSetSize = pfnSetSize; - pengfuncsFromEngine->pfnChangeLevel = pfnChangeLevel; - pengfuncsFromEngine->pfnGetSpawnParms = pfnGetSpawnParms; - pengfuncsFromEngine->pfnSaveSpawnParms = pfnSaveSpawnParms; - pengfuncsFromEngine->pfnVecToYaw = pfnVecToYaw; - pengfuncsFromEngine->pfnVecToAngles = pfnVecToAngles; - pengfuncsFromEngine->pfnMoveToOrigin = pfnMoveToOrigin; - pengfuncsFromEngine->pfnChangeYaw = pfnChangeYaw; - pengfuncsFromEngine->pfnChangePitch = pfnChangePitch; - pengfuncsFromEngine->pfnFindEntityByString = pfnFindEntityByString; - pengfuncsFromEngine->pfnGetEntityIllum = pfnGetEntityIllum; - pengfuncsFromEngine->pfnFindEntityInSphere = pfnFindEntityInSphere; - pengfuncsFromEngine->pfnFindClientInPVS = pfnFindClientInPVS; - pengfuncsFromEngine->pfnEntitiesInPVS = pfnEntitiesInPVS; - pengfuncsFromEngine->pfnMakeVectors = pfnMakeVectors; - pengfuncsFromEngine->pfnAngleVectors = pfnAngleVectors; - pengfuncsFromEngine->pfnCreateEntity = pfnCreateEntity; - pengfuncsFromEngine->pfnRemoveEntity = pfnRemoveEntity; - pengfuncsFromEngine->pfnCreateNamedEntity = pfnCreateNamedEntity; - pengfuncsFromEngine->pfnMakeStatic = pfnMakeStatic; - pengfuncsFromEngine->pfnEntIsOnFloor = pfnEntIsOnFloor; - pengfuncsFromEngine->pfnDropToFloor = pfnDropToFloor; - pengfuncsFromEngine->pfnWalkMove = pfnWalkMove; - pengfuncsFromEngine->pfnSetOrigin = pfnSetOrigin; - pengfuncsFromEngine->pfnEmitSound = pfnEmitSound; - pengfuncsFromEngine->pfnEmitAmbientSound = pfnEmitAmbientSound; - pengfuncsFromEngine->pfnTraceLine = pfnTraceLine; - pengfuncsFromEngine->pfnTraceToss = pfnTraceToss; - pengfuncsFromEngine->pfnTraceMonsterHull = pfnTraceMonsterHull; - pengfuncsFromEngine->pfnTraceHull = pfnTraceHull; - pengfuncsFromEngine->pfnTraceModel = pfnTraceModel; - pengfuncsFromEngine->pfnTraceTexture = pfnTraceTexture; - pengfuncsFromEngine->pfnTraceSphere = pfnTraceSphere; - pengfuncsFromEngine->pfnGetAimVector = pfnGetAimVector; - pengfuncsFromEngine->pfnServerCommand = pfnServerCommand; - pengfuncsFromEngine->pfnServerExecute = pfnServerExecute; - - pengfuncsFromEngine->pfnClientCommand = pfnClientCommand; - - pengfuncsFromEngine->pfnParticleEffect = pfnParticleEffect; - pengfuncsFromEngine->pfnLightStyle = pfnLightStyle; - pengfuncsFromEngine->pfnDecalIndex = pfnDecalIndex; - pengfuncsFromEngine->pfnPointContents = pfnPointContents; - pengfuncsFromEngine->pfnMessageBegin = pfnMessageBegin; - pengfuncsFromEngine->pfnMessageEnd = pfnMessageEnd; - pengfuncsFromEngine->pfnWriteByte = pfnWriteByte; - pengfuncsFromEngine->pfnWriteChar = pfnWriteChar; - pengfuncsFromEngine->pfnWriteShort = pfnWriteShort; - pengfuncsFromEngine->pfnWriteLong = pfnWriteLong; - pengfuncsFromEngine->pfnWriteAngle = pfnWriteAngle; - pengfuncsFromEngine->pfnWriteCoord = pfnWriteCoord; - pengfuncsFromEngine->pfnWriteString = pfnWriteString; - pengfuncsFromEngine->pfnWriteEntity = pfnWriteEntity; - pengfuncsFromEngine->pfnCVarRegister = pfnCVarRegister; - pengfuncsFromEngine->pfnCVarGetFloat = pfnCVarGetFloat; - pengfuncsFromEngine->pfnCVarGetString = pfnCVarGetString; - pengfuncsFromEngine->pfnCVarSetFloat = pfnCVarSetFloat; - pengfuncsFromEngine->pfnCVarSetString = pfnCVarSetString; - pengfuncsFromEngine->pfnPvAllocEntPrivateData = pfnPvAllocEntPrivateData; - pengfuncsFromEngine->pfnPvEntPrivateData = pfnPvEntPrivateData; - pengfuncsFromEngine->pfnFreeEntPrivateData = pfnFreeEntPrivateData; - pengfuncsFromEngine->pfnSzFromIndex = pfnSzFromIndex; - pengfuncsFromEngine->pfnAllocString = pfnAllocString; - pengfuncsFromEngine->pfnGetVarsOfEnt = pfnGetVarsOfEnt; - pengfuncsFromEngine->pfnPEntityOfEntOffset = pfnPEntityOfEntOffset; - pengfuncsFromEngine->pfnEntOffsetOfPEntity = pfnEntOffsetOfPEntity; - pengfuncsFromEngine->pfnIndexOfEdict = pfnIndexOfEdict; - pengfuncsFromEngine->pfnPEntityOfEntIndex = pfnPEntityOfEntIndex; - pengfuncsFromEngine->pfnFindEntityByVars = pfnFindEntityByVars; - pengfuncsFromEngine->pfnGetModelPtr = pfnGetModelPtr; - pengfuncsFromEngine->pfnRegUserMsg = pfnRegUserMsg; - pengfuncsFromEngine->pfnAnimationAutomove = pfnAnimationAutomove; - pengfuncsFromEngine->pfnGetBonePosition = pfnGetBonePosition; - pengfuncsFromEngine->pfnFunctionFromName = pfnFunctionFromName; - pengfuncsFromEngine->pfnNameForFunction = pfnNameForFunction; - pengfuncsFromEngine->pfnClientPrintf = pfnClientPrintf; - pengfuncsFromEngine->pfnServerPrint = pfnServerPrint; - pengfuncsFromEngine->pfnGetAttachment = pfnGetAttachment; - pengfuncsFromEngine->pfnCRC32_Init = pfnCRC32_Init; - pengfuncsFromEngine->pfnCRC32_ProcessBuffer = pfnCRC32_ProcessBuffer; - pengfuncsFromEngine->pfnCRC32_ProcessByte = pfnCRC32_ProcessByte; - pengfuncsFromEngine->pfnCRC32_Final = pfnCRC32_Final; - pengfuncsFromEngine->pfnRandomLong = pfnRandomLong; - pengfuncsFromEngine->pfnRandomFloat = pfnRandomFloat; - pengfuncsFromEngine->pfnSetView = pfnSetView; - pengfuncsFromEngine->pfnTime = pfnTime; - pengfuncsFromEngine->pfnCrosshairAngle = pfnCrosshairAngle; - pengfuncsFromEngine->pfnLoadFileForMe = pfnLoadFileForMe; - pengfuncsFromEngine->pfnFreeFile = pfnFreeFile; - pengfuncsFromEngine->pfnEndSection = pfnEndSection; - pengfuncsFromEngine->pfnCompareFileTime = pfnCompareFileTime; - pengfuncsFromEngine->pfnGetGameDir = pfnGetGameDir; - pengfuncsFromEngine->pfnCvar_RegisterVariable = pfnCvar_RegisterVariable; - pengfuncsFromEngine->pfnFadeClientVolume = pfnFadeClientVolume; - pengfuncsFromEngine->pfnSetClientMaxspeed = pfnSetClientMaxspeed; - pengfuncsFromEngine->pfnCreateFakeClient = pfnCreateFakeClient; - pengfuncsFromEngine->pfnRunPlayerMove = pfnRunPlayerMove; - pengfuncsFromEngine->pfnNumberOfEntities = pfnNumberOfEntities; - pengfuncsFromEngine->pfnGetInfoKeyBuffer = pfnGetInfoKeyBuffer; - pengfuncsFromEngine->pfnInfoKeyValue = pfnInfoKeyValue; - pengfuncsFromEngine->pfnSetKeyValue = pfnSetKeyValue; - pengfuncsFromEngine->pfnSetClientKeyValue = pfnSetClientKeyValue; - pengfuncsFromEngine->pfnIsMapValid = pfnIsMapValid; - pengfuncsFromEngine->pfnStaticDecal = pfnStaticDecal; - pengfuncsFromEngine->pfnPrecacheGeneric = pfnPrecacheGeneric; - pengfuncsFromEngine->pfnGetPlayerUserId = pfnGetPlayerUserId; - pengfuncsFromEngine->pfnBuildSoundMsg = pfnBuildSoundMsg; - pengfuncsFromEngine->pfnIsDedicatedServer = pfnIsDedicatedServer; - pengfuncsFromEngine->pfnCVarGetPointer = pfnCVarGetPointer; - pengfuncsFromEngine->pfnGetPlayerWONId = pfnGetPlayerWONId; - - // give the engine functions to the other DLL... - (*other_GiveFnptrsToDll)(pengfuncsFromEngine, pGlobals); -} - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// h_export.cpp +// + +#include "dlls/extdll.h" +#include "dlls/enginecallback.h" +#include "dlls/util.h" +#include "dlls/cbase.h" +#include "mod/AvHConstants.h" + +#include "bot.h" +#include "HPB_bot/engine/engine.h" +#include "../types.h" + +#ifndef __linux__ + +HINSTANCE h_Library = NULL; +HGLOBAL h_global_argv = NULL; + +#else + +void *h_Library = NULL; +char h_global_argv[1024]; + +#endif + +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; +char *g_argv; + +static FILE *fp; + + +GETENTITYAPI other_GetEntityAPI = NULL; +GETNEWDLLFUNCTIONS other_GetNewDLLFunctions = NULL; +GIVEFNPTRSTODLL other_GiveFnptrsToDll = NULL; + +extern int mod_id; + + +#ifndef __linux__ + +// Required DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + if (h_Library) + FreeLibrary(h_Library); + + if (h_global_argv) + { + GlobalUnlock(h_global_argv); + GlobalFree(h_global_argv); + } + } + + return TRUE; +} + +#endif + +#ifndef __linux__ +#ifdef __BORLANDC__ +extern "C" DLLEXPORT void EXPORT GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals) +#else +void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +#endif +#else +extern "C" DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +#endif +{ + int pos; + char game_dir[256]; + char mod_name[32]; + +//#ifdef AVH_MAPPER_BUILD +//strcpy(mod_name, kModDirectory); +//#endif + + // get the engine functions from the engine... + + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; + + // find the directory name of the currently running MOD... + (*g_engfuncs.pfnGetGameDir)(game_dir); + + pos = strlen(game_dir) - 1; + + // scan backwards till first directory separator... + while ((pos) && (game_dir[pos] != '/')) + pos--; + + if (pos == 0) + { + // Error getting directory name! + + ALERT( at_error, "HPB_bot - Error determining MOD directory name!" ); + } + + pos++; + strcpy(mod_name, &game_dir[pos]); + + mod_id = AVH_DLL; + + +#ifdef WIN32 + string theTempName = string(getModDirectory()) + "\\dlls\\ns.dll"; + h_Library = LoadLibrary(theTempName.c_str()); +// TODO: Add this in when supporting linux again +#else + printf("DLopening ns/dlls/HPB_bot_i386.so..."); + h_Library = dlopen("ns/dlls/HPB_bot_i386.so", RTLD_NOW); +#endif + + + if (h_Library == NULL) + { + // Directory error or Unsupported MOD! + + ALERT( at_error, "HPB_bot - MOD dll not found (or unsupported MOD)!" ); + } + + +#ifndef __linux__ + h_global_argv = GlobalAlloc(GMEM_SHARE, 1024); + g_argv = (char *)GlobalLock(h_global_argv); +#else + g_argv = (char *)h_global_argv; +#endif + + other_GetEntityAPI = (GETENTITYAPI)GetProcAddress(h_Library, "GetEntityAPI"); + + if (other_GetEntityAPI == NULL) + { + // Can't find GetEntityAPI! + + ALERT( at_error, "HPB_bot - Can't get MOD's GetEntityAPI!" ); + } + + other_GetNewDLLFunctions = (GETNEWDLLFUNCTIONS)GetProcAddress(h_Library, "GetNewDLLFunctions"); + +// if (other_GetNewDLLFunctions == NULL) +// { +// // Can't find GetNewDLLFunctions! +// +// ALERT( at_error, "HPB_bot - Can't get MOD's GetNewDLLFunctions!" ); +// } + + other_GiveFnptrsToDll = (GIVEFNPTRSTODLL)GetProcAddress(h_Library, "GiveFnptrsToDll"); + + if (other_GiveFnptrsToDll == NULL) + { + // Can't find GiveFnptrsToDll! + + ALERT( at_error, "HPB_bot - Can't get MOD's GiveFnptrsToDll!" ); + } + + pengfuncsFromEngine->pfnCmd_Args = Cmd_Args; + pengfuncsFromEngine->pfnCmd_Argv = Cmd_Argv; + pengfuncsFromEngine->pfnCmd_Argc = Cmd_Argc; + + pengfuncsFromEngine->pfnPrecacheModel = pfnPrecacheModel; + pengfuncsFromEngine->pfnPrecacheSound = pfnPrecacheSound; + pengfuncsFromEngine->pfnSetModel = pfnSetModel; + pengfuncsFromEngine->pfnModelIndex = pfnModelIndex; + pengfuncsFromEngine->pfnModelFrames = pfnModelFrames; + pengfuncsFromEngine->pfnSetSize = pfnSetSize; + pengfuncsFromEngine->pfnChangeLevel = pfnChangeLevel; + pengfuncsFromEngine->pfnGetSpawnParms = pfnGetSpawnParms; + pengfuncsFromEngine->pfnSaveSpawnParms = pfnSaveSpawnParms; + pengfuncsFromEngine->pfnVecToYaw = pfnVecToYaw; + pengfuncsFromEngine->pfnVecToAngles = pfnVecToAngles; + pengfuncsFromEngine->pfnMoveToOrigin = pfnMoveToOrigin; + pengfuncsFromEngine->pfnChangeYaw = pfnChangeYaw; + pengfuncsFromEngine->pfnChangePitch = pfnChangePitch; + pengfuncsFromEngine->pfnFindEntityByString = pfnFindEntityByString; + pengfuncsFromEngine->pfnGetEntityIllum = pfnGetEntityIllum; + pengfuncsFromEngine->pfnFindEntityInSphere = pfnFindEntityInSphere; + pengfuncsFromEngine->pfnFindClientInPVS = pfnFindClientInPVS; + pengfuncsFromEngine->pfnEntitiesInPVS = pfnEntitiesInPVS; + pengfuncsFromEngine->pfnMakeVectors = pfnMakeVectors; + pengfuncsFromEngine->pfnAngleVectors = pfnAngleVectors; + pengfuncsFromEngine->pfnCreateEntity = pfnCreateEntity; + pengfuncsFromEngine->pfnRemoveEntity = pfnRemoveEntity; + pengfuncsFromEngine->pfnCreateNamedEntity = pfnCreateNamedEntity; + pengfuncsFromEngine->pfnMakeStatic = pfnMakeStatic; + pengfuncsFromEngine->pfnEntIsOnFloor = pfnEntIsOnFloor; + pengfuncsFromEngine->pfnDropToFloor = pfnDropToFloor; + pengfuncsFromEngine->pfnWalkMove = pfnWalkMove; + pengfuncsFromEngine->pfnSetOrigin = pfnSetOrigin; + pengfuncsFromEngine->pfnEmitSound = pfnEmitSound; + pengfuncsFromEngine->pfnEmitAmbientSound = pfnEmitAmbientSound; + pengfuncsFromEngine->pfnTraceLine = pfnTraceLine; + pengfuncsFromEngine->pfnTraceToss = pfnTraceToss; + pengfuncsFromEngine->pfnTraceMonsterHull = pfnTraceMonsterHull; + pengfuncsFromEngine->pfnTraceHull = pfnTraceHull; + pengfuncsFromEngine->pfnTraceModel = pfnTraceModel; + pengfuncsFromEngine->pfnTraceTexture = pfnTraceTexture; + pengfuncsFromEngine->pfnTraceSphere = pfnTraceSphere; + pengfuncsFromEngine->pfnGetAimVector = pfnGetAimVector; + pengfuncsFromEngine->pfnServerCommand = pfnServerCommand; + pengfuncsFromEngine->pfnServerExecute = pfnServerExecute; + + pengfuncsFromEngine->pfnClientCommand = pfnClientCommand; + + pengfuncsFromEngine->pfnParticleEffect = pfnParticleEffect; + pengfuncsFromEngine->pfnLightStyle = pfnLightStyle; + pengfuncsFromEngine->pfnDecalIndex = pfnDecalIndex; + pengfuncsFromEngine->pfnPointContents = pfnPointContents; + pengfuncsFromEngine->pfnMessageBegin = pfnMessageBegin; + pengfuncsFromEngine->pfnMessageEnd = pfnMessageEnd; + pengfuncsFromEngine->pfnWriteByte = pfnWriteByte; + pengfuncsFromEngine->pfnWriteChar = pfnWriteChar; + pengfuncsFromEngine->pfnWriteShort = pfnWriteShort; + pengfuncsFromEngine->pfnWriteLong = pfnWriteLong; + pengfuncsFromEngine->pfnWriteAngle = pfnWriteAngle; + pengfuncsFromEngine->pfnWriteCoord = pfnWriteCoord; + pengfuncsFromEngine->pfnWriteString = pfnWriteString; + pengfuncsFromEngine->pfnWriteEntity = pfnWriteEntity; + pengfuncsFromEngine->pfnCVarRegister = pfnCVarRegister; + pengfuncsFromEngine->pfnCVarGetFloat = pfnCVarGetFloat; + pengfuncsFromEngine->pfnCVarGetString = pfnCVarGetString; + pengfuncsFromEngine->pfnCVarSetFloat = pfnCVarSetFloat; + pengfuncsFromEngine->pfnCVarSetString = pfnCVarSetString; + pengfuncsFromEngine->pfnPvAllocEntPrivateData = pfnPvAllocEntPrivateData; + pengfuncsFromEngine->pfnPvEntPrivateData = pfnPvEntPrivateData; + pengfuncsFromEngine->pfnFreeEntPrivateData = pfnFreeEntPrivateData; + pengfuncsFromEngine->pfnSzFromIndex = pfnSzFromIndex; + pengfuncsFromEngine->pfnAllocString = pfnAllocString; + pengfuncsFromEngine->pfnGetVarsOfEnt = pfnGetVarsOfEnt; + pengfuncsFromEngine->pfnPEntityOfEntOffset = pfnPEntityOfEntOffset; + pengfuncsFromEngine->pfnEntOffsetOfPEntity = pfnEntOffsetOfPEntity; + pengfuncsFromEngine->pfnIndexOfEdict = pfnIndexOfEdict; + pengfuncsFromEngine->pfnPEntityOfEntIndex = pfnPEntityOfEntIndex; + pengfuncsFromEngine->pfnFindEntityByVars = pfnFindEntityByVars; + pengfuncsFromEngine->pfnGetModelPtr = pfnGetModelPtr; + pengfuncsFromEngine->pfnRegUserMsg = pfnRegUserMsg; + pengfuncsFromEngine->pfnAnimationAutomove = pfnAnimationAutomove; + pengfuncsFromEngine->pfnGetBonePosition = pfnGetBonePosition; + pengfuncsFromEngine->pfnFunctionFromName = pfnFunctionFromName; + pengfuncsFromEngine->pfnNameForFunction = pfnNameForFunction; + pengfuncsFromEngine->pfnClientPrintf = pfnClientPrintf; + pengfuncsFromEngine->pfnServerPrint = pfnServerPrint; + pengfuncsFromEngine->pfnGetAttachment = pfnGetAttachment; + pengfuncsFromEngine->pfnCRC32_Init = pfnCRC32_Init; + pengfuncsFromEngine->pfnCRC32_ProcessBuffer = pfnCRC32_ProcessBuffer; + pengfuncsFromEngine->pfnCRC32_ProcessByte = pfnCRC32_ProcessByte; + pengfuncsFromEngine->pfnCRC32_Final = pfnCRC32_Final; + pengfuncsFromEngine->pfnRandomLong = pfnRandomLong; + pengfuncsFromEngine->pfnRandomFloat = pfnRandomFloat; + pengfuncsFromEngine->pfnSetView = pfnSetView; + pengfuncsFromEngine->pfnTime = pfnTime; + pengfuncsFromEngine->pfnCrosshairAngle = pfnCrosshairAngle; + pengfuncsFromEngine->pfnLoadFileForMe = pfnLoadFileForMe; + pengfuncsFromEngine->pfnFreeFile = pfnFreeFile; + pengfuncsFromEngine->pfnEndSection = pfnEndSection; + pengfuncsFromEngine->pfnCompareFileTime = pfnCompareFileTime; + pengfuncsFromEngine->pfnGetGameDir = pfnGetGameDir; + pengfuncsFromEngine->pfnCvar_RegisterVariable = pfnCvar_RegisterVariable; + pengfuncsFromEngine->pfnFadeClientVolume = pfnFadeClientVolume; + pengfuncsFromEngine->pfnSetClientMaxspeed = pfnSetClientMaxspeed; + pengfuncsFromEngine->pfnCreateFakeClient = pfnCreateFakeClient; + pengfuncsFromEngine->pfnRunPlayerMove = pfnRunPlayerMove; + pengfuncsFromEngine->pfnNumberOfEntities = pfnNumberOfEntities; + pengfuncsFromEngine->pfnGetInfoKeyBuffer = pfnGetInfoKeyBuffer; + pengfuncsFromEngine->pfnInfoKeyValue = pfnInfoKeyValue; + pengfuncsFromEngine->pfnSetKeyValue = pfnSetKeyValue; + pengfuncsFromEngine->pfnSetClientKeyValue = pfnSetClientKeyValue; + pengfuncsFromEngine->pfnIsMapValid = pfnIsMapValid; + pengfuncsFromEngine->pfnStaticDecal = pfnStaticDecal; + pengfuncsFromEngine->pfnPrecacheGeneric = pfnPrecacheGeneric; + pengfuncsFromEngine->pfnGetPlayerUserId = pfnGetPlayerUserId; + pengfuncsFromEngine->pfnBuildSoundMsg = pfnBuildSoundMsg; + pengfuncsFromEngine->pfnIsDedicatedServer = pfnIsDedicatedServer; + pengfuncsFromEngine->pfnCVarGetPointer = pfnCVarGetPointer; + pengfuncsFromEngine->pfnGetPlayerWONId = pfnGetPlayerWONId; + + // give the engine functions to the other DLL... + (*other_GiveFnptrsToDll)(pengfuncsFromEngine, pGlobals); +} + diff --git a/main/source/HPB_bot/dlls/h_export.cpp~ b/main/source/HPB_bot/dlls/h_export.cpp~ deleted file mode 100644 index 68d11dd6..00000000 --- a/main/source/HPB_bot/dlls/h_export.cpp~ +++ /dev/null @@ -1,290 +0,0 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// h_export.cpp -// - -#include "dlls/extdll.h" -#include "dlls/enginecallback.h" -#include "dlls/util.h" -#include "dlls/cbase.h" -#include "mod/AvHConstants.h" - -#include "bot.h" -#include "HPB_bot/engine/engine.h" -#include "types.h" - -#ifndef __linux__ - -HINSTANCE h_Library = NULL; -HGLOBAL h_global_argv = NULL; - -#else - -void *h_Library = NULL; -char h_global_argv[1024]; - -#endif - -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; -char *g_argv; - -static FILE *fp; - - -GETENTITYAPI other_GetEntityAPI = NULL; -GETNEWDLLFUNCTIONS other_GetNewDLLFunctions = NULL; -GIVEFNPTRSTODLL other_GiveFnptrsToDll = NULL; - -extern int mod_id; - - -#ifndef __linux__ - -// Required DLL entry point -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - if (h_Library) - FreeLibrary(h_Library); - - if (h_global_argv) - { - GlobalUnlock(h_global_argv); - GlobalFree(h_global_argv); - } - } - - return TRUE; -} - -#endif - -#ifndef __linux__ -#ifdef __BORLANDC__ -extern "C" DLLEXPORT void EXPORT GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals) -#else -void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -#endif -#else -extern "C" DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -#endif -{ - int pos; - char game_dir[256]; - char mod_name[32]; - -//#ifdef AVH_MAPPER_BUILD -//strcpy(mod_name, kModDirectory); -//#endif - - // get the engine functions from the engine... - - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; - - // find the directory name of the currently running MOD... - (*g_engfuncs.pfnGetGameDir)(game_dir); - - pos = strlen(game_dir) - 1; - - // scan backwards till first directory separator... - while ((pos) && (game_dir[pos] != '/')) - pos--; - - if (pos == 0) - { - // Error getting directory name! - - ALERT( at_error, "HPB_bot - Error determining MOD directory name!" ); - } - - pos++; - strcpy(mod_name, &game_dir[pos]); - - mod_id = AVH_DLL; - - -#ifdef WIN32 - string theTempName = string(getModDirectory()) + "\\dlls\\ns.dll"; - h_Library = LoadLibrary(theTempName.c_str()); -// TODO: Add this in when supporting linux again -#else - printf("DLopening ns/dlls/HPB_bot_i386.so..."); - h_Library = dlopen("ns/dlls/HPB_bot_i386.so", RTLD_NOW); -#endif - - - if (h_Library == NULL) - { - // Directory error or Unsupported MOD! - - ALERT( at_error, "HPB_bot - MOD dll not found (or unsupported MOD)!" ); - } - - -#ifndef __linux__ - h_global_argv = GlobalAlloc(GMEM_SHARE, 1024); - g_argv = (char *)GlobalLock(h_global_argv); -#else - g_argv = (char *)h_global_argv; -#endif - - other_GetEntityAPI = (GETENTITYAPI)GetProcAddress(h_Library, "GetEntityAPI"); - - if (other_GetEntityAPI == NULL) - { - // Can't find GetEntityAPI! - - ALERT( at_error, "HPB_bot - Can't get MOD's GetEntityAPI!" ); - } - - other_GetNewDLLFunctions = (GETNEWDLLFUNCTIONS)GetProcAddress(h_Library, "GetNewDLLFunctions"); - -// if (other_GetNewDLLFunctions == NULL) -// { -// // Can't find GetNewDLLFunctions! -// -// ALERT( at_error, "HPB_bot - Can't get MOD's GetNewDLLFunctions!" ); -// } - - other_GiveFnptrsToDll = (GIVEFNPTRSTODLL)GetProcAddress(h_Library, "GiveFnptrsToDll"); - - if (other_GiveFnptrsToDll == NULL) - { - // Can't find GiveFnptrsToDll! - - ALERT( at_error, "HPB_bot - Can't get MOD's GiveFnptrsToDll!" ); - } - - pengfuncsFromEngine->pfnCmd_Args = Cmd_Args; - pengfuncsFromEngine->pfnCmd_Argv = Cmd_Argv; - pengfuncsFromEngine->pfnCmd_Argc = Cmd_Argc; - - pengfuncsFromEngine->pfnPrecacheModel = pfnPrecacheModel; - pengfuncsFromEngine->pfnPrecacheSound = pfnPrecacheSound; - pengfuncsFromEngine->pfnSetModel = pfnSetModel; - pengfuncsFromEngine->pfnModelIndex = pfnModelIndex; - pengfuncsFromEngine->pfnModelFrames = pfnModelFrames; - pengfuncsFromEngine->pfnSetSize = pfnSetSize; - pengfuncsFromEngine->pfnChangeLevel = pfnChangeLevel; - pengfuncsFromEngine->pfnGetSpawnParms = pfnGetSpawnParms; - pengfuncsFromEngine->pfnSaveSpawnParms = pfnSaveSpawnParms; - pengfuncsFromEngine->pfnVecToYaw = pfnVecToYaw; - pengfuncsFromEngine->pfnVecToAngles = pfnVecToAngles; - pengfuncsFromEngine->pfnMoveToOrigin = pfnMoveToOrigin; - pengfuncsFromEngine->pfnChangeYaw = pfnChangeYaw; - pengfuncsFromEngine->pfnChangePitch = pfnChangePitch; - pengfuncsFromEngine->pfnFindEntityByString = pfnFindEntityByString; - pengfuncsFromEngine->pfnGetEntityIllum = pfnGetEntityIllum; - pengfuncsFromEngine->pfnFindEntityInSphere = pfnFindEntityInSphere; - pengfuncsFromEngine->pfnFindClientInPVS = pfnFindClientInPVS; - pengfuncsFromEngine->pfnEntitiesInPVS = pfnEntitiesInPVS; - pengfuncsFromEngine->pfnMakeVectors = pfnMakeVectors; - pengfuncsFromEngine->pfnAngleVectors = pfnAngleVectors; - pengfuncsFromEngine->pfnCreateEntity = pfnCreateEntity; - pengfuncsFromEngine->pfnRemoveEntity = pfnRemoveEntity; - pengfuncsFromEngine->pfnCreateNamedEntity = pfnCreateNamedEntity; - pengfuncsFromEngine->pfnMakeStatic = pfnMakeStatic; - pengfuncsFromEngine->pfnEntIsOnFloor = pfnEntIsOnFloor; - pengfuncsFromEngine->pfnDropToFloor = pfnDropToFloor; - pengfuncsFromEngine->pfnWalkMove = pfnWalkMove; - pengfuncsFromEngine->pfnSetOrigin = pfnSetOrigin; - pengfuncsFromEngine->pfnEmitSound = pfnEmitSound; - pengfuncsFromEngine->pfnEmitAmbientSound = pfnEmitAmbientSound; - pengfuncsFromEngine->pfnTraceLine = pfnTraceLine; - pengfuncsFromEngine->pfnTraceToss = pfnTraceToss; - pengfuncsFromEngine->pfnTraceMonsterHull = pfnTraceMonsterHull; - pengfuncsFromEngine->pfnTraceHull = pfnTraceHull; - pengfuncsFromEngine->pfnTraceModel = pfnTraceModel; - pengfuncsFromEngine->pfnTraceTexture = pfnTraceTexture; - pengfuncsFromEngine->pfnTraceSphere = pfnTraceSphere; - pengfuncsFromEngine->pfnGetAimVector = pfnGetAimVector; - pengfuncsFromEngine->pfnServerCommand = pfnServerCommand; - pengfuncsFromEngine->pfnServerExecute = pfnServerExecute; - - pengfuncsFromEngine->pfnClientCommand = pfnClientCommand; - - pengfuncsFromEngine->pfnParticleEffect = pfnParticleEffect; - pengfuncsFromEngine->pfnLightStyle = pfnLightStyle; - pengfuncsFromEngine->pfnDecalIndex = pfnDecalIndex; - pengfuncsFromEngine->pfnPointContents = pfnPointContents; - pengfuncsFromEngine->pfnMessageBegin = pfnMessageBegin; - pengfuncsFromEngine->pfnMessageEnd = pfnMessageEnd; - pengfuncsFromEngine->pfnWriteByte = pfnWriteByte; - pengfuncsFromEngine->pfnWriteChar = pfnWriteChar; - pengfuncsFromEngine->pfnWriteShort = pfnWriteShort; - pengfuncsFromEngine->pfnWriteLong = pfnWriteLong; - pengfuncsFromEngine->pfnWriteAngle = pfnWriteAngle; - pengfuncsFromEngine->pfnWriteCoord = pfnWriteCoord; - pengfuncsFromEngine->pfnWriteString = pfnWriteString; - pengfuncsFromEngine->pfnWriteEntity = pfnWriteEntity; - pengfuncsFromEngine->pfnCVarRegister = pfnCVarRegister; - pengfuncsFromEngine->pfnCVarGetFloat = pfnCVarGetFloat; - pengfuncsFromEngine->pfnCVarGetString = pfnCVarGetString; - pengfuncsFromEngine->pfnCVarSetFloat = pfnCVarSetFloat; - pengfuncsFromEngine->pfnCVarSetString = pfnCVarSetString; - pengfuncsFromEngine->pfnPvAllocEntPrivateData = pfnPvAllocEntPrivateData; - pengfuncsFromEngine->pfnPvEntPrivateData = pfnPvEntPrivateData; - pengfuncsFromEngine->pfnFreeEntPrivateData = pfnFreeEntPrivateData; - pengfuncsFromEngine->pfnSzFromIndex = pfnSzFromIndex; - pengfuncsFromEngine->pfnAllocString = pfnAllocString; - pengfuncsFromEngine->pfnGetVarsOfEnt = pfnGetVarsOfEnt; - pengfuncsFromEngine->pfnPEntityOfEntOffset = pfnPEntityOfEntOffset; - pengfuncsFromEngine->pfnEntOffsetOfPEntity = pfnEntOffsetOfPEntity; - pengfuncsFromEngine->pfnIndexOfEdict = pfnIndexOfEdict; - pengfuncsFromEngine->pfnPEntityOfEntIndex = pfnPEntityOfEntIndex; - pengfuncsFromEngine->pfnFindEntityByVars = pfnFindEntityByVars; - pengfuncsFromEngine->pfnGetModelPtr = pfnGetModelPtr; - pengfuncsFromEngine->pfnRegUserMsg = pfnRegUserMsg; - pengfuncsFromEngine->pfnAnimationAutomove = pfnAnimationAutomove; - pengfuncsFromEngine->pfnGetBonePosition = pfnGetBonePosition; - pengfuncsFromEngine->pfnFunctionFromName = pfnFunctionFromName; - pengfuncsFromEngine->pfnNameForFunction = pfnNameForFunction; - pengfuncsFromEngine->pfnClientPrintf = pfnClientPrintf; - pengfuncsFromEngine->pfnServerPrint = pfnServerPrint; - pengfuncsFromEngine->pfnGetAttachment = pfnGetAttachment; - pengfuncsFromEngine->pfnCRC32_Init = pfnCRC32_Init; - pengfuncsFromEngine->pfnCRC32_ProcessBuffer = pfnCRC32_ProcessBuffer; - pengfuncsFromEngine->pfnCRC32_ProcessByte = pfnCRC32_ProcessByte; - pengfuncsFromEngine->pfnCRC32_Final = pfnCRC32_Final; - pengfuncsFromEngine->pfnRandomLong = pfnRandomLong; - pengfuncsFromEngine->pfnRandomFloat = pfnRandomFloat; - pengfuncsFromEngine->pfnSetView = pfnSetView; - pengfuncsFromEngine->pfnTime = pfnTime; - pengfuncsFromEngine->pfnCrosshairAngle = pfnCrosshairAngle; - pengfuncsFromEngine->pfnLoadFileForMe = pfnLoadFileForMe; - pengfuncsFromEngine->pfnFreeFile = pfnFreeFile; - pengfuncsFromEngine->pfnEndSection = pfnEndSection; - pengfuncsFromEngine->pfnCompareFileTime = pfnCompareFileTime; - pengfuncsFromEngine->pfnGetGameDir = pfnGetGameDir; - pengfuncsFromEngine->pfnCvar_RegisterVariable = pfnCvar_RegisterVariable; - pengfuncsFromEngine->pfnFadeClientVolume = pfnFadeClientVolume; - pengfuncsFromEngine->pfnSetClientMaxspeed = pfnSetClientMaxspeed; - pengfuncsFromEngine->pfnCreateFakeClient = pfnCreateFakeClient; - pengfuncsFromEngine->pfnRunPlayerMove = pfnRunPlayerMove; - pengfuncsFromEngine->pfnNumberOfEntities = pfnNumberOfEntities; - pengfuncsFromEngine->pfnGetInfoKeyBuffer = pfnGetInfoKeyBuffer; - pengfuncsFromEngine->pfnInfoKeyValue = pfnInfoKeyValue; - pengfuncsFromEngine->pfnSetKeyValue = pfnSetKeyValue; - pengfuncsFromEngine->pfnSetClientKeyValue = pfnSetClientKeyValue; - pengfuncsFromEngine->pfnIsMapValid = pfnIsMapValid; - pengfuncsFromEngine->pfnStaticDecal = pfnStaticDecal; - pengfuncsFromEngine->pfnPrecacheGeneric = pfnPrecacheGeneric; - pengfuncsFromEngine->pfnGetPlayerUserId = pfnGetPlayerUserId; - pengfuncsFromEngine->pfnBuildSoundMsg = pfnBuildSoundMsg; - pengfuncsFromEngine->pfnIsDedicatedServer = pfnIsDedicatedServer; - pengfuncsFromEngine->pfnCVarGetPointer = pfnCVarGetPointer; - pengfuncsFromEngine->pfnGetPlayerWONId = pfnGetPlayerWONId; - - // give the engine functions to the other DLL... - (*other_GiveFnptrsToDll)(pengfuncsFromEngine, pGlobals); -} - diff --git a/main/source/HPB_bot/dlls/linkfunc.cpp b/main/source/HPB_bot/dlls/linkfunc.cpp index f9ef6bfc..a2b9e382 100644 --- a/main/source/HPB_bot/dlls/linkfunc.cpp +++ b/main/source/HPB_bot/dlls/linkfunc.cpp @@ -1,689 +1,689 @@ -// -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// linkfunc.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" - -// For some reason, including these and using them doesn't work. Has something to do with -// the preprocessor but I don't get it... -//#include "mod/AvHConstants.h" -//#include "mod/AvHMarineEquipmentConstants.h" - -#ifdef __BORLANDC__ -extern HINSTANCE _h_Library; -#elif _WIN32 -extern HINSTANCE h_Library; -#else -extern void *h_Library; -#endif - -#ifdef __BORLANDC__ - -#define LINK_ENTITY_TO_FUNC(mapClassName) \ - extern "C" EXPORT void mapClassName( entvars_t *pev ); \ - void mapClassName( entvars_t *pev ) { \ - static LINK_ENTITY_FUNC otherClassName = NULL; \ - static int skip_this = 0; \ - if (skip_this) return; \ - if (otherClassName == NULL) \ - otherClassName = (LINK_ENTITY_FUNC)GetProcAddress(_h_Library, #mapClassName); \ - if (otherClassName == NULL) { \ - skip_this = 1; return; \ - } \ - (*otherClassName)(pev); } - -#else - -#define LINK_ENTITY_TO_FUNC(mapClassName) \ - extern "C" EXPORT void mapClassName( entvars_t *pev ); \ - void mapClassName( entvars_t *pev ) { \ - static LINK_ENTITY_FUNC otherClassName = NULL; \ - static int skip_this = 0; \ - if (skip_this) return; \ - if (otherClassName == NULL) \ - otherClassName = (LINK_ENTITY_FUNC)GetProcAddress(h_Library, #mapClassName); \ - if (otherClassName == NULL) { \ - skip_this = 1; return; \ - } \ - (*otherClassName)(pev); } - -#endif - -// new stuff for 1.1.0.4 release -//LINK_ENTITY_TO_FUNC(CreateInterface); - -// entities for Valve's hl.dll and Standard SDK... -LINK_ENTITY_TO_FUNC(aiscripted_sequence); -LINK_ENTITY_TO_FUNC(ambient_generic); -LINK_ENTITY_TO_FUNC(ammo_357); -LINK_ENTITY_TO_FUNC(ammo_9mmAR); -LINK_ENTITY_TO_FUNC(ammo_9mmbox); -LINK_ENTITY_TO_FUNC(ammo_9mmclip); -LINK_ENTITY_TO_FUNC(ammo_ARgrenades); -LINK_ENTITY_TO_FUNC(ammo_buckshot); -LINK_ENTITY_TO_FUNC(ammo_crossbow); -LINK_ENTITY_TO_FUNC(ammo_egonclip); -LINK_ENTITY_TO_FUNC(ammo_gaussclip); -LINK_ENTITY_TO_FUNC(ammo_glockclip); -LINK_ENTITY_TO_FUNC(ammo_mp5clip); -LINK_ENTITY_TO_FUNC(ammo_mp5grenades); -LINK_ENTITY_TO_FUNC(ammo_rpgclip); -LINK_ENTITY_TO_FUNC(beam); -LINK_ENTITY_TO_FUNC(bmortar); -LINK_ENTITY_TO_FUNC(bodyque); -LINK_ENTITY_TO_FUNC(button_target); -LINK_ENTITY_TO_FUNC(cine_blood); -LINK_ENTITY_TO_FUNC(controller_energy_ball); -LINK_ENTITY_TO_FUNC(controller_head_ball); -LINK_ENTITY_TO_FUNC(crossbow_bolt); -LINK_ENTITY_TO_FUNC(cycler); -LINK_ENTITY_TO_FUNC(cycler_prdroid); -LINK_ENTITY_TO_FUNC(cycler_sprite); -LINK_ENTITY_TO_FUNC(cycler_weapon); -LINK_ENTITY_TO_FUNC(cycler_wreckage); -LINK_ENTITY_TO_FUNC(DelayedUse); -LINK_ENTITY_TO_FUNC(env_beam); -LINK_ENTITY_TO_FUNC(env_beverage); -LINK_ENTITY_TO_FUNC(env_blood); -LINK_ENTITY_TO_FUNC(env_bubbles); -LINK_ENTITY_TO_FUNC(env_debris); -LINK_ENTITY_TO_FUNC(env_explosion); -LINK_ENTITY_TO_FUNC(env_fade); -LINK_ENTITY_TO_FUNC(env_funnel); -LINK_ENTITY_TO_FUNC(env_global); -LINK_ENTITY_TO_FUNC(env_glow); -LINK_ENTITY_TO_FUNC(env_laser); -LINK_ENTITY_TO_FUNC(env_lightning); -LINK_ENTITY_TO_FUNC(env_message); -LINK_ENTITY_TO_FUNC(env_render); -LINK_ENTITY_TO_FUNC(env_shake); -LINK_ENTITY_TO_FUNC(env_shooter); -LINK_ENTITY_TO_FUNC(env_smoker); -LINK_ENTITY_TO_FUNC(env_sound); -LINK_ENTITY_TO_FUNC(env_spark); -LINK_ENTITY_TO_FUNC(env_sprite); -LINK_ENTITY_TO_FUNC(fireanddie); -LINK_ENTITY_TO_FUNC(func_breakable); -LINK_ENTITY_TO_FUNC(func_button); -LINK_ENTITY_TO_FUNC(func_conveyor); -LINK_ENTITY_TO_FUNC(func_door); -LINK_ENTITY_TO_FUNC(func_door_rotating); -LINK_ENTITY_TO_FUNC(func_friction); -LINK_ENTITY_TO_FUNC(func_guntarget); -LINK_ENTITY_TO_FUNC(func_healthcharger); -LINK_ENTITY_TO_FUNC(func_illusionary); -LINK_ENTITY_TO_FUNC(func_ladder); -LINK_ENTITY_TO_FUNC(func_monsterclip); -LINK_ENTITY_TO_FUNC(func_mortar_field); -LINK_ENTITY_TO_FUNC(func_pendulum); -LINK_ENTITY_TO_FUNC(func_plat); -LINK_ENTITY_TO_FUNC(func_platrot); -LINK_ENTITY_TO_FUNC(func_pushable); -LINK_ENTITY_TO_FUNC(func_recharge); -LINK_ENTITY_TO_FUNC(func_rot_button); -LINK_ENTITY_TO_FUNC(func_rotating); -LINK_ENTITY_TO_FUNC(func_tank); -LINK_ENTITY_TO_FUNC(func_tankcontrols); -LINK_ENTITY_TO_FUNC(func_tanklaser); -LINK_ENTITY_TO_FUNC(func_tankmortar); -LINK_ENTITY_TO_FUNC(func_tankrocket); -LINK_ENTITY_TO_FUNC(func_trackautochange); -LINK_ENTITY_TO_FUNC(func_trackchange); -LINK_ENTITY_TO_FUNC(func_tracktrain); -LINK_ENTITY_TO_FUNC(func_train); -LINK_ENTITY_TO_FUNC(func_traincontrols); -LINK_ENTITY_TO_FUNC(func_wall); -LINK_ENTITY_TO_FUNC(func_wall_toggle); -LINK_ENTITY_TO_FUNC(func_water); -LINK_ENTITY_TO_FUNC(game_counter); -LINK_ENTITY_TO_FUNC(game_counter_set); -LINK_ENTITY_TO_FUNC(game_end); -LINK_ENTITY_TO_FUNC(game_player_equip); -LINK_ENTITY_TO_FUNC(game_player_hurt); -LINK_ENTITY_TO_FUNC(game_player_team); -LINK_ENTITY_TO_FUNC(game_score); -LINK_ENTITY_TO_FUNC(game_team_master); -LINK_ENTITY_TO_FUNC(game_team_set); -LINK_ENTITY_TO_FUNC(game_text); -LINK_ENTITY_TO_FUNC(game_zone_player); -LINK_ENTITY_TO_FUNC(garg_stomp); -LINK_ENTITY_TO_FUNC(gibshooter); -LINK_ENTITY_TO_FUNC(grenade); -LINK_ENTITY_TO_FUNC(hornet); -LINK_ENTITY_TO_FUNC(hvr_rocket); -LINK_ENTITY_TO_FUNC(info_bigmomma); -LINK_ENTITY_TO_FUNC(info_intermission); -LINK_ENTITY_TO_FUNC(info_landmark); -LINK_ENTITY_TO_FUNC(info_node); -LINK_ENTITY_TO_FUNC(info_node_air); -LINK_ENTITY_TO_FUNC(info_null); -LINK_ENTITY_TO_FUNC(info_player_deathmatch); -LINK_ENTITY_TO_FUNC(info_player_start); -LINK_ENTITY_TO_FUNC(info_target); -LINK_ENTITY_TO_FUNC(info_teleport_destination); -LINK_ENTITY_TO_FUNC(infodecal); -LINK_ENTITY_TO_FUNC(item_airtank); -LINK_ENTITY_TO_FUNC(item_antidote); -LINK_ENTITY_TO_FUNC(item_battery); -LINK_ENTITY_TO_FUNC(item_healthkit); -LINK_ENTITY_TO_FUNC(item_longjump); -LINK_ENTITY_TO_FUNC(item_security); -LINK_ENTITY_TO_FUNC(item_sodacan); -LINK_ENTITY_TO_FUNC(item_suit); -LINK_ENTITY_TO_FUNC(laser_spot); -LINK_ENTITY_TO_FUNC(light); -LINK_ENTITY_TO_FUNC(light_environment); -LINK_ENTITY_TO_FUNC(light_spot); -LINK_ENTITY_TO_FUNC(momentary_door); -LINK_ENTITY_TO_FUNC(momentary_rot_button); -LINK_ENTITY_TO_FUNC(monstermaker); -LINK_ENTITY_TO_FUNC(monster_alien_controller); -LINK_ENTITY_TO_FUNC(monster_alien_grunt); -LINK_ENTITY_TO_FUNC(monster_alien_slave); -LINK_ENTITY_TO_FUNC(monster_apache); -LINK_ENTITY_TO_FUNC(monster_babycrab); -LINK_ENTITY_TO_FUNC(monster_barnacle); -LINK_ENTITY_TO_FUNC(monster_barney); -LINK_ENTITY_TO_FUNC(monster_barney_dead); -LINK_ENTITY_TO_FUNC(monster_bigmomma); -LINK_ENTITY_TO_FUNC(monster_bloater); -LINK_ENTITY_TO_FUNC(monster_bullchicken); -LINK_ENTITY_TO_FUNC(monster_cine2_hvyweapons); -LINK_ENTITY_TO_FUNC(monster_cine2_scientist); -LINK_ENTITY_TO_FUNC(monster_cine2_slave); -LINK_ENTITY_TO_FUNC(monster_cine3_barney); -LINK_ENTITY_TO_FUNC(monster_cine3_scientist); -LINK_ENTITY_TO_FUNC(monster_cine_barney); -LINK_ENTITY_TO_FUNC(monster_cine_panther); -LINK_ENTITY_TO_FUNC(monster_cine_scientist); -LINK_ENTITY_TO_FUNC(monster_cockroach); -LINK_ENTITY_TO_FUNC(monster_flyer); -LINK_ENTITY_TO_FUNC(monster_flyer_flock); -LINK_ENTITY_TO_FUNC(monster_furniture); -LINK_ENTITY_TO_FUNC(monster_gargantua); -LINK_ENTITY_TO_FUNC(monster_generic); -LINK_ENTITY_TO_FUNC(monster_gman); -LINK_ENTITY_TO_FUNC(monster_grunt_repel); -LINK_ENTITY_TO_FUNC(monster_headcrab); -LINK_ENTITY_TO_FUNC(monster_hevsuit_dead); -LINK_ENTITY_TO_FUNC(monster_hgrunt_dead); -LINK_ENTITY_TO_FUNC(monster_houndeye); -LINK_ENTITY_TO_FUNC(monster_human_assassin); -LINK_ENTITY_TO_FUNC(monster_human_grunt); -LINK_ENTITY_TO_FUNC(monster_ichthyosaur); -LINK_ENTITY_TO_FUNC(monster_leech); -LINK_ENTITY_TO_FUNC(monster_miniturret); -LINK_ENTITY_TO_FUNC(monster_mortar); -LINK_ENTITY_TO_FUNC(monster_nihilanth); -LINK_ENTITY_TO_FUNC(monster_osprey); -LINK_ENTITY_TO_FUNC(monster_rat); -LINK_ENTITY_TO_FUNC(monster_satchel); -LINK_ENTITY_TO_FUNC(monster_scientist); -LINK_ENTITY_TO_FUNC(monster_scientist_dead); -LINK_ENTITY_TO_FUNC(monster_sentry); -LINK_ENTITY_TO_FUNC(monster_sitting_scientist); -LINK_ENTITY_TO_FUNC(monster_snark); -LINK_ENTITY_TO_FUNC(monster_tentacle); -LINK_ENTITY_TO_FUNC(monster_tentaclemaw); -LINK_ENTITY_TO_FUNC(monster_tripmine); -LINK_ENTITY_TO_FUNC(monster_turret); -LINK_ENTITY_TO_FUNC(monster_vortigaunt); -LINK_ENTITY_TO_FUNC(monster_zombie); -LINK_ENTITY_TO_FUNC(multi_manager); -LINK_ENTITY_TO_FUNC(multisource); -LINK_ENTITY_TO_FUNC(nihilanth_energy_ball); -LINK_ENTITY_TO_FUNC(node_viewer); -LINK_ENTITY_TO_FUNC(node_viewer_fly); -LINK_ENTITY_TO_FUNC(node_viewer_human); -LINK_ENTITY_TO_FUNC(node_viewer_large); -LINK_ENTITY_TO_FUNC(path_corner); -LINK_ENTITY_TO_FUNC(path_track); -LINK_ENTITY_TO_FUNC(player); -LINK_ENTITY_TO_FUNC(player_loadsaved); -LINK_ENTITY_TO_FUNC(player_weaponstrip); -LINK_ENTITY_TO_FUNC(rpg_rocket); -LINK_ENTITY_TO_FUNC(scripted_sentence); -LINK_ENTITY_TO_FUNC(scripted_sequence); -LINK_ENTITY_TO_FUNC(soundent); -LINK_ENTITY_TO_FUNC(spark_shower); -LINK_ENTITY_TO_FUNC(speaker); -LINK_ENTITY_TO_FUNC(squidspit); -LINK_ENTITY_TO_FUNC(streak_spiral); -LINK_ENTITY_TO_FUNC(target_cdaudio); -LINK_ENTITY_TO_FUNC(test_effect); -LINK_ENTITY_TO_FUNC(testhull); -LINK_ENTITY_TO_FUNC(trigger); -LINK_ENTITY_TO_FUNC(trigger_auto); -LINK_ENTITY_TO_FUNC(trigger_autosave); -LINK_ENTITY_TO_FUNC(trigger_camera); -LINK_ENTITY_TO_FUNC(trigger_cdaudio); -LINK_ENTITY_TO_FUNC(trigger_changelevel); -LINK_ENTITY_TO_FUNC(trigger_changetarget); -LINK_ENTITY_TO_FUNC(trigger_counter); -LINK_ENTITY_TO_FUNC(trigger_endsection); -LINK_ENTITY_TO_FUNC(trigger_gravity); -LINK_ENTITY_TO_FUNC(trigger_hurt); -LINK_ENTITY_TO_FUNC(trigger_monsterjump); -LINK_ENTITY_TO_FUNC(trigger_multiple); -LINK_ENTITY_TO_FUNC(trigger_once); -LINK_ENTITY_TO_FUNC(trigger_push); -LINK_ENTITY_TO_FUNC(trigger_relay); -LINK_ENTITY_TO_FUNC(trigger_teleport); -LINK_ENTITY_TO_FUNC(trigger_transition); -LINK_ENTITY_TO_FUNC(weapon_357); -LINK_ENTITY_TO_FUNC(weapon_9mmAR); -LINK_ENTITY_TO_FUNC(weapon_9mmhandgun); -LINK_ENTITY_TO_FUNC(weapon_crossbow); -LINK_ENTITY_TO_FUNC(weapon_crowbar); -LINK_ENTITY_TO_FUNC(weapon_egon); -LINK_ENTITY_TO_FUNC(weapon_gauss); -LINK_ENTITY_TO_FUNC(weapon_glock); -LINK_ENTITY_TO_FUNC(weapon_handgrenade); -LINK_ENTITY_TO_FUNC(weapon_hornetgun); -LINK_ENTITY_TO_FUNC(weapon_mp5); -LINK_ENTITY_TO_FUNC(weapon_python); -LINK_ENTITY_TO_FUNC(weapon_rpg); -LINK_ENTITY_TO_FUNC(weapon_satchel); -//LINK_ENTITY_TO_FUNC(weapon_shotgun); -LINK_ENTITY_TO_FUNC(weapon_snark); -LINK_ENTITY_TO_FUNC(weapon_tripmine); -LINK_ENTITY_TO_FUNC(weaponbox); -LINK_ENTITY_TO_FUNC(world_items); -LINK_ENTITY_TO_FUNC(worldspawn); -LINK_ENTITY_TO_FUNC(xen_hair); -LINK_ENTITY_TO_FUNC(xen_hull); -LINK_ENTITY_TO_FUNC(xen_plantlight); -LINK_ENTITY_TO_FUNC(xen_spore_large); -LINK_ENTITY_TO_FUNC(xen_spore_medium); -LINK_ENTITY_TO_FUNC(xen_spore_small); -LINK_ENTITY_TO_FUNC(xen_tree); -LINK_ENTITY_TO_FUNC(xen_ttrigger); - -//// entities for Team Fortress 1.5 -//LINK_ENTITY_TO_FUNC(building_dispenser); -//LINK_ENTITY_TO_FUNC(building_sentrygun); -//LINK_ENTITY_TO_FUNC(building_sentrygun_base); -//LINK_ENTITY_TO_FUNC(detpack); -//LINK_ENTITY_TO_FUNC(dispenser_refill_timer); -//LINK_ENTITY_TO_FUNC(func_nobuild); -//LINK_ENTITY_TO_FUNC(func_nogrenades); -//LINK_ENTITY_TO_FUNC(ghost); -//LINK_ENTITY_TO_FUNC(i_p_t); -//LINK_ENTITY_TO_FUNC(i_t_g); -//LINK_ENTITY_TO_FUNC(i_t_t); -//LINK_ENTITY_TO_FUNC(info_areadef); -//LINK_ENTITY_TO_FUNC(info_player_teamspawn); -//LINK_ENTITY_TO_FUNC(info_tf_teamcheck); -//LINK_ENTITY_TO_FUNC(info_tf_teamset); -//LINK_ENTITY_TO_FUNC(info_tfdetect); -//LINK_ENTITY_TO_FUNC(info_tfgoal); -//LINK_ENTITY_TO_FUNC(info_tfgoal_timer); -//LINK_ENTITY_TO_FUNC(item_armor1); -//LINK_ENTITY_TO_FUNC(item_armor2); -//LINK_ENTITY_TO_FUNC(item_armor3); -//LINK_ENTITY_TO_FUNC(item_artifact_envirosuit); -//LINK_ENTITY_TO_FUNC(item_artifact_invisibility); -//LINK_ENTITY_TO_FUNC(item_artifact_invulnerability); -//LINK_ENTITY_TO_FUNC(item_artifact_super_damage); -//LINK_ENTITY_TO_FUNC(item_cells); -//LINK_ENTITY_TO_FUNC(item_health); -//LINK_ENTITY_TO_FUNC(item_rockets); -//LINK_ENTITY_TO_FUNC(item_shells); -//LINK_ENTITY_TO_FUNC(item_spikes); -//LINK_ENTITY_TO_FUNC(item_tfgoal); -//LINK_ENTITY_TO_FUNC(teledeath); -//LINK_ENTITY_TO_FUNC(tf_ammo_rpgclip); -//LINK_ENTITY_TO_FUNC(tf_flame); -//LINK_ENTITY_TO_FUNC(tf_flamethrower_burst); -//LINK_ENTITY_TO_FUNC(tf_gl_grenade); -//LINK_ENTITY_TO_FUNC(tf_ic_rocket); -//LINK_ENTITY_TO_FUNC(tf_nailgun_nail); -//LINK_ENTITY_TO_FUNC(tf_rpg_rocket); -//LINK_ENTITY_TO_FUNC(tf_weapon_ac); -//LINK_ENTITY_TO_FUNC(tf_weapon_autorifle); -//LINK_ENTITY_TO_FUNC(tf_weapon_axe); -//LINK_ENTITY_TO_FUNC(tf_weapon_caltrop); -//LINK_ENTITY_TO_FUNC(tf_weapon_caltropgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_concussiongrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_empgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_flamethrower); -//LINK_ENTITY_TO_FUNC(tf_weapon_gasgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_genericprimedgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_gl); -//LINK_ENTITY_TO_FUNC(tf_weapon_ic); -//LINK_ENTITY_TO_FUNC(tf_weapon_knife); -//LINK_ENTITY_TO_FUNC(tf_weapon_medikit); -//LINK_ENTITY_TO_FUNC(tf_weapon_mirvbomblet); -//LINK_ENTITY_TO_FUNC(tf_weapon_mirvgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_nailgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_napalmgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_ng); -//LINK_ENTITY_TO_FUNC(tf_weapon_normalgrenade); -//LINK_ENTITY_TO_FUNC(tf_weapon_pl); -//LINK_ENTITY_TO_FUNC(tf_weapon_railgun); -//LINK_ENTITY_TO_FUNC(tf_weapon_rpg); -//LINK_ENTITY_TO_FUNC(tf_weapon_shotgun); -//LINK_ENTITY_TO_FUNC(tf_weapon_sniperrifle); -//LINK_ENTITY_TO_FUNC(tf_weapon_spanner); -//LINK_ENTITY_TO_FUNC(tf_weapon_superng); -//LINK_ENTITY_TO_FUNC(tf_weapon_supershotgun); -//LINK_ENTITY_TO_FUNC(tf_weapon_tranq); -//LINK_ENTITY_TO_FUNC(timer); -// -//// entities for Counter-Strike (Beta 6.5, 6.6, 7.0, 7.1) & 1.0 -//LINK_ENTITY_TO_FUNC(ammo_338magnum); -//LINK_ENTITY_TO_FUNC(ammo_357sig); -//LINK_ENTITY_TO_FUNC(ammo_45acp); -//LINK_ENTITY_TO_FUNC(ammo_50ae); -//LINK_ENTITY_TO_FUNC(ammo_556nato); -//LINK_ENTITY_TO_FUNC(ammo_556natobox); -//LINK_ENTITY_TO_FUNC(ammo_57mm); -//LINK_ENTITY_TO_FUNC(ammo_762nato); -//LINK_ENTITY_TO_FUNC(ammo_9mm); -//LINK_ENTITY_TO_FUNC(armoury_entity); -//LINK_ENTITY_TO_FUNC(env_bombglow); -//LINK_ENTITY_TO_FUNC(func_bomb_target); -//LINK_ENTITY_TO_FUNC(func_buyzone); -//LINK_ENTITY_TO_FUNC(func_escapezone); -//LINK_ENTITY_TO_FUNC(func_grencatch); -//LINK_ENTITY_TO_FUNC(func_hostage_rescue); -//LINK_ENTITY_TO_FUNC(func_vehicle); -//LINK_ENTITY_TO_FUNC(func_vehiclecontrols); -//LINK_ENTITY_TO_FUNC(func_vip_safetyzone); -//LINK_ENTITY_TO_FUNC(func_weaponcheck); -//LINK_ENTITY_TO_FUNC(hostage_entity); -//LINK_ENTITY_TO_FUNC(info_bomb_target); -//LINK_ENTITY_TO_FUNC(info_hostage_rescue); -//LINK_ENTITY_TO_FUNC(info_map_parameters); -//LINK_ENTITY_TO_FUNC(info_vip_start); -//LINK_ENTITY_TO_FUNC(item_assaultsuit); -//LINK_ENTITY_TO_FUNC(item_kevlar); -//LINK_ENTITY_TO_FUNC(item_thighpack); -//LINK_ENTITY_TO_FUNC(weapon_ak47); -//LINK_ENTITY_TO_FUNC(weapon_aug); -//LINK_ENTITY_TO_FUNC(weapon_awp); -//LINK_ENTITY_TO_FUNC(weapon_c4); -//LINK_ENTITY_TO_FUNC(weapon_deagle); -//LINK_ENTITY_TO_FUNC(weapon_elite); -//LINK_ENTITY_TO_FUNC(weapon_fiveseven); -//LINK_ENTITY_TO_FUNC(weapon_flashbang); -//LINK_ENTITY_TO_FUNC(weapon_g3sg1); -//LINK_ENTITY_TO_FUNC(weapon_glock18); -//LINK_ENTITY_TO_FUNC(weapon_hegrenade); -//LINK_ENTITY_TO_FUNC(weapon_knife); -//LINK_ENTITY_TO_FUNC(weapon_m249); -//LINK_ENTITY_TO_FUNC(weapon_m3); -//LINK_ENTITY_TO_FUNC(weapon_m4a1); -//LINK_ENTITY_TO_FUNC(weapon_mac10); -//LINK_ENTITY_TO_FUNC(weapon_mp5navy); -//LINK_ENTITY_TO_FUNC(weapon_p228); -//LINK_ENTITY_TO_FUNC(weapon_p90); -//LINK_ENTITY_TO_FUNC(weapon_scout); -//LINK_ENTITY_TO_FUNC(weapon_sg550); -//LINK_ENTITY_TO_FUNC(weapon_sg552); -//LINK_ENTITY_TO_FUNC(weapon_smokegrenade); -//LINK_ENTITY_TO_FUNC(weapon_tmp); -//LINK_ENTITY_TO_FUNC(weapon_usp); -//LINK_ENTITY_TO_FUNC(weapon_ump45); -//LINK_ENTITY_TO_FUNC(weapon_xm1014); -// -//// entities for Opposing Force -//LINK_ENTITY_TO_FUNC(ammo_556); -//LINK_ENTITY_TO_FUNC(ammo_762); -//LINK_ENTITY_TO_FUNC(ammo_eagleclip); -//LINK_ENTITY_TO_FUNC(ammo_spore); -//LINK_ENTITY_TO_FUNC(charged_bolt); -//LINK_ENTITY_TO_FUNC(displacer_ball); -//LINK_ENTITY_TO_FUNC(eagle_laser); -//LINK_ENTITY_TO_FUNC(env_blowercannon); -//LINK_ENTITY_TO_FUNC(env_electrified_wire); -//LINK_ENTITY_TO_FUNC(env_genewormcloud); -//LINK_ENTITY_TO_FUNC(env_genewormspawn); -//LINK_ENTITY_TO_FUNC(env_rope); -//LINK_ENTITY_TO_FUNC(env_spritetrain); -//LINK_ENTITY_TO_FUNC(func_op4mortarcontroller); -//LINK_ENTITY_TO_FUNC(func_tank_of); -//LINK_ENTITY_TO_FUNC(func_tankcontrols_of); -//LINK_ENTITY_TO_FUNC(func_tanklaser_of); -//LINK_ENTITY_TO_FUNC(func_tankmortar_of); -//LINK_ENTITY_TO_FUNC(func_tankrocket_of); -//LINK_ENTITY_TO_FUNC(gonomeguts); -//LINK_ENTITY_TO_FUNC(grapple_tip); -//LINK_ENTITY_TO_FUNC(hvr_blkop_rocket); -//LINK_ENTITY_TO_FUNC(info_ctfdetect); -//LINK_ENTITY_TO_FUNC(info_ctfspawn); -//LINK_ENTITY_TO_FUNC(info_ctfspawn_powerup); -//LINK_ENTITY_TO_FUNC(info_displacer_earth_target); -//LINK_ENTITY_TO_FUNC(info_displacer_xen_target); -//LINK_ENTITY_TO_FUNC(info_pitworm); -//LINK_ENTITY_TO_FUNC(info_pitworm_steam_lock); -//LINK_ENTITY_TO_FUNC(item_ctfaccelerator); -//LINK_ENTITY_TO_FUNC(item_ctfbackpack); -//LINK_ENTITY_TO_FUNC(item_ctfbase); -//LINK_ENTITY_TO_FUNC(item_ctfflag); -//LINK_ENTITY_TO_FUNC(item_ctflongjump); -//LINK_ENTITY_TO_FUNC(item_ctfportablehev); -//LINK_ENTITY_TO_FUNC(item_ctfregeneration); -//LINK_ENTITY_TO_FUNC(item_generic); -//LINK_ENTITY_TO_FUNC(item_nuclearbomb); -//LINK_ENTITY_TO_FUNC(item_nuclearbombbutton); -//LINK_ENTITY_TO_FUNC(item_nuclearbombtimer); -//LINK_ENTITY_TO_FUNC(item_vest); -//LINK_ENTITY_TO_FUNC(monster_ShockTrooper_dead); -//LINK_ENTITY_TO_FUNC(monster_alien_babyvoltigore); -//LINK_ENTITY_TO_FUNC(monster_alien_slave_dead); -//LINK_ENTITY_TO_FUNC(monster_alien_voltigore); -//LINK_ENTITY_TO_FUNC(monster_assassin_repel); -//LINK_ENTITY_TO_FUNC(monster_blkop_apache); -//LINK_ENTITY_TO_FUNC(monster_blkop_osprey); -//LINK_ENTITY_TO_FUNC(monster_cleansuit_scientist); -//LINK_ENTITY_TO_FUNC(monster_cleansuit_scientist_dead); -//LINK_ENTITY_TO_FUNC(monster_drillsergeant); -//LINK_ENTITY_TO_FUNC(monster_fgrunt_repel); -//LINK_ENTITY_TO_FUNC(monster_geneworm); -//LINK_ENTITY_TO_FUNC(monster_gonome); -//LINK_ENTITY_TO_FUNC(monster_gonome_dead); -//LINK_ENTITY_TO_FUNC(monster_grunt_ally_repel); -//LINK_ENTITY_TO_FUNC(monster_hfgrunt_dead); -//LINK_ENTITY_TO_FUNC(monster_houndeye_dead); -//LINK_ENTITY_TO_FUNC(monster_human_friendly_grunt); -//LINK_ENTITY_TO_FUNC(monster_human_grunt_ally); -//LINK_ENTITY_TO_FUNC(monster_human_grunt_ally_dead); -//LINK_ENTITY_TO_FUNC(monster_human_medic_ally); -//LINK_ENTITY_TO_FUNC(monster_human_torch_ally); -//LINK_ENTITY_TO_FUNC(monster_male_assassin); -//LINK_ENTITY_TO_FUNC(monster_massassin_dead); -//LINK_ENTITY_TO_FUNC(monster_medic_ally_repel); -//LINK_ENTITY_TO_FUNC(monster_op4loader); -//LINK_ENTITY_TO_FUNC(monster_otis); -//LINK_ENTITY_TO_FUNC(monster_otis_dead); -//LINK_ENTITY_TO_FUNC(monster_penguin); -//LINK_ENTITY_TO_FUNC(monster_pitdrone); -//LINK_ENTITY_TO_FUNC(monster_pitworm); -//LINK_ENTITY_TO_FUNC(monster_pitworm_up); -//LINK_ENTITY_TO_FUNC(monster_recruit); -//LINK_ENTITY_TO_FUNC(monster_shockroach); -//LINK_ENTITY_TO_FUNC(monster_shocktrooper); -//LINK_ENTITY_TO_FUNC(monster_shocktrooper_repel); -//LINK_ENTITY_TO_FUNC(monster_sitting_cleansuit_scientist); -//LINK_ENTITY_TO_FUNC(monster_skeleton_dead); -//LINK_ENTITY_TO_FUNC(monster_torch_ally_repel); -//LINK_ENTITY_TO_FUNC(monster_zombie_barney); -//LINK_ENTITY_TO_FUNC(monster_zombie_soldier); -//LINK_ENTITY_TO_FUNC(monster_zombie_soldier_dead); -//LINK_ENTITY_TO_FUNC(mortar_shell); -//LINK_ENTITY_TO_FUNC(op4mortar); -//LINK_ENTITY_TO_FUNC(pitdronespike); -//LINK_ENTITY_TO_FUNC(pitworm_gib); -//LINK_ENTITY_TO_FUNC(pitworm_gibshooter); -//LINK_ENTITY_TO_FUNC(rope_sample); -//LINK_ENTITY_TO_FUNC(rope_segment); -//LINK_ENTITY_TO_FUNC(shock_beam); -//LINK_ENTITY_TO_FUNC(spore); -//LINK_ENTITY_TO_FUNC(trigger_ctfgeneric); -//LINK_ENTITY_TO_FUNC(trigger_geneworm_hit); -//LINK_ENTITY_TO_FUNC(trigger_kill_nogib); -//LINK_ENTITY_TO_FUNC(trigger_playerfreeze); -//LINK_ENTITY_TO_FUNC(trigger_xen_return); -//LINK_ENTITY_TO_FUNC(weapon_displacer); -//LINK_ENTITY_TO_FUNC(weapon_eagle); -//LINK_ENTITY_TO_FUNC(weapon_grapple); -//LINK_ENTITY_TO_FUNC(weapon_penguin); -//LINK_ENTITY_TO_FUNC(weapon_pipewrench); -//LINK_ENTITY_TO_FUNC(weapon_shockrifle); -//LINK_ENTITY_TO_FUNC(weapon_shockroach); -//LINK_ENTITY_TO_FUNC(weapon_sniperrifle); -//LINK_ENTITY_TO_FUNC(weapon_sporelauncher); -// -//// entities for FrontLineForce (1.0) -//LINK_ENTITY_TO_FUNC(ammo_ak5); -//LINK_ENTITY_TO_FUNC(ammo_beretta); -//LINK_ENTITY_TO_FUNC(ammo_famas); -//LINK_ENTITY_TO_FUNC(ammo_hk21); -//LINK_ENTITY_TO_FUNC(ammo_m4); -//LINK_ENTITY_TO_FUNC(ammo_mac10); -//LINK_ENTITY_TO_FUNC(ammo_mk23); -//LINK_ENTITY_TO_FUNC(ammo_mp5a2); -//LINK_ENTITY_TO_FUNC(ammo_mp5sd); -//LINK_ENTITY_TO_FUNC(ammo_msg90); -//LINK_ENTITY_TO_FUNC(ammo_spas12); -//LINK_ENTITY_TO_FUNC(ammo_ump45); -//LINK_ENTITY_TO_FUNC(capture_point); -//LINK_ENTITY_TO_FUNC(info_frontline); -//LINK_ENTITY_TO_FUNC(info_player_attacker); -//LINK_ENTITY_TO_FUNC(info_player_defender); -//LINK_ENTITY_TO_FUNC(info_player_observer); -//LINK_ENTITY_TO_FUNC(weapon_ak5); -//LINK_ENTITY_TO_FUNC(weapon_beretta); -//LINK_ENTITY_TO_FUNC(weapon_famas); -//LINK_ENTITY_TO_FUNC(weapon_hk21); -//LINK_ENTITY_TO_FUNC(weapon_m4); -//LINK_ENTITY_TO_FUNC(weapon_mk23); -//LINK_ENTITY_TO_FUNC(weapon_mp5a2); -//LINK_ENTITY_TO_FUNC(weapon_mp5sd); -//LINK_ENTITY_TO_FUNC(weapon_msg90); -//LINK_ENTITY_TO_FUNC(weapon_spas12); - -// entities for Natural Selection -LINK_ENTITY_TO_FUNC(info_team_start); -LINK_ENTITY_TO_FUNC(info_spectate); -LINK_ENTITY_TO_FUNC(info_join_team); -LINK_ENTITY_TO_FUNC(info_leave_game); -LINK_ENTITY_TO_FUNC(info_join_autoassign); -LINK_ENTITY_TO_FUNC(info_mapinfo); -LINK_ENTITY_TO_FUNC(info_gameplay); - -LINK_ENTITY_TO_FUNC(env_fog); -LINK_ENTITY_TO_FUNC(env_gamma); -LINK_ENTITY_TO_FUNC(env_particles); -LINK_ENTITY_TO_FUNC(env_particles_custom); - -LINK_ENTITY_TO_FUNC(func_weldable); -LINK_ENTITY_TO_FUNC(func_seethrough); -LINK_ENTITY_TO_FUNC(func_seethroughdoor); -//LINK_ENTITY_TO_FUNC(func_waypoint); -LINK_ENTITY_TO_FUNC(func_nobuild); -LINK_ENTITY_TO_FUNC(func_resource); - -LINK_ENTITY_TO_FUNC(target_mp3audio); -LINK_ENTITY_TO_FUNC(trigger_random); -LINK_ENTITY_TO_FUNC(trigger_presence); -LINK_ENTITY_TO_FUNC(trigger_script); -LINK_ENTITY_TO_FUNC(info_location); - -LINK_ENTITY_TO_FUNC(team_hive); -LINK_ENTITY_TO_FUNC(team_command); -LINK_ENTITY_TO_FUNC(team_breach); -LINK_ENTITY_TO_FUNC(team_egg); -LINK_ENTITY_TO_FUNC(team_webstrand); - -// Marine weapons and equipment -LINK_ENTITY_TO_FUNC(weapon_knife); -LINK_ENTITY_TO_FUNC(weapon_grenade); -LINK_ENTITY_TO_FUNC(weapon_machinegun); -LINK_ENTITY_TO_FUNC(weapon_pistol); -LINK_ENTITY_TO_FUNC(weapon_flamegun); -LINK_ENTITY_TO_FUNC(weapon_heavymachinegun); -LINK_ENTITY_TO_FUNC(weapon_grenadegun); -LINK_ENTITY_TO_FUNC(weapon_shotgun); -LINK_ENTITY_TO_FUNC(weapon_nukegun); -LINK_ENTITY_TO_FUNC(weapon_mine); -LINK_ENTITY_TO_FUNC(weapon_welder); - -LINK_ENTITY_TO_FUNC(item_genericammo); -LINK_ENTITY_TO_FUNC(item_mine); -LINK_ENTITY_TO_FUNC(item_health); -LINK_ENTITY_TO_FUNC(item_catalyst); -LINK_ENTITY_TO_FUNC(item_heavyarmor); -LINK_ENTITY_TO_FUNC(item_jetpack); - -LINK_ENTITY_TO_FUNC(scan); -LINK_ENTITY_TO_FUNC(turret); -LINK_ENTITY_TO_FUNC(phasegate); -LINK_ENTITY_TO_FUNC(siegeturret); -LINK_ENTITY_TO_FUNC(nuke); - -// Marine buildings -LINK_ENTITY_TO_FUNC(resourcetower); -LINK_ENTITY_TO_FUNC(team_infportal); -LINK_ENTITY_TO_FUNC(team_turretfactory); -LINK_ENTITY_TO_FUNC(team_advturretfactory); -LINK_ENTITY_TO_FUNC(team_armory); -LINK_ENTITY_TO_FUNC(team_advarmory); -LINK_ENTITY_TO_FUNC(team_armslab); -LINK_ENTITY_TO_FUNC(team_prototypelab); -LINK_ENTITY_TO_FUNC(team_observatory); -LINK_ENTITY_TO_FUNC(team_chemlab); -LINK_ENTITY_TO_FUNC(team_medlab); -LINK_ENTITY_TO_FUNC(team_nukeplant); - -// Alien buildings -LINK_ENTITY_TO_FUNC(alienresourcetower); -LINK_ENTITY_TO_FUNC(defensechamber); -LINK_ENTITY_TO_FUNC(spikeprojectile); -LINK_ENTITY_TO_FUNC(offensechamber); -LINK_ENTITY_TO_FUNC(sensorychamber); -LINK_ENTITY_TO_FUNC(movementchamber); - -// Alien abilities that are technically weapons (along with their projectiles) -LINK_ENTITY_TO_FUNC(weapon_acidrocket); -LINK_ENTITY_TO_FUNC(weapon_acidrocketgun); -LINK_ENTITY_TO_FUNC(weapon_bilebomb); -LINK_ENTITY_TO_FUNC(weapon_bilebombgun); -LINK_ENTITY_TO_FUNC(weapon_bitegun); -LINK_ENTITY_TO_FUNC(weapon_blink); -LINK_ENTITY_TO_FUNC(weapon_claws); -LINK_ENTITY_TO_FUNC(weapon_devour); -LINK_ENTITY_TO_FUNC(weapon_divinewind); -LINK_ENTITY_TO_FUNC(weapon_healingspray); -LINK_ENTITY_TO_FUNC(weapon_metabolize); -LINK_ENTITY_TO_FUNC(weapon_parasite); -LINK_ENTITY_TO_FUNC(weapon_primalscream); -LINK_ENTITY_TO_FUNC(weapon_spikegun); -LINK_ENTITY_TO_FUNC(weapon_bite2gun); -LINK_ENTITY_TO_FUNC(weapon_spit); -LINK_ENTITY_TO_FUNC(weapon_spore); -LINK_ENTITY_TO_FUNC(weapon_stomp); -LINK_ENTITY_TO_FUNC(weapon_swipe); -LINK_ENTITY_TO_FUNC(weapon_umbra); -LINK_ENTITY_TO_FUNC(weapon_webspinner); - -// Alien abilities -LINK_ENTITY_TO_FUNC(weapon_leap); -LINK_ENTITY_TO_FUNC(weapon_charge); - -LINK_ENTITY_TO_FUNC(webgunprojectile); -LINK_ENTITY_TO_FUNC(spitgunprojectile); -LINK_ENTITY_TO_FUNC(stompprojectile); -LINK_ENTITY_TO_FUNC(sporegunprojectile); -LINK_ENTITY_TO_FUNC(umbracloud); -LINK_ENTITY_TO_FUNC(umbraprojectile); - +// +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// linkfunc.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" + +// For some reason, including these and using them doesn't work. Has something to do with +// the preprocessor but I don't get it... +//#include "mod/AvHConstants.h" +//#include "mod/AvHMarineEquipmentConstants.h" + +#ifdef __BORLANDC__ +extern HINSTANCE _h_Library; +#elif _WIN32 +extern HINSTANCE h_Library; +#else +extern void *h_Library; +#endif + +#ifdef __BORLANDC__ + +#define LINK_ENTITY_TO_FUNC(mapClassName) \ + extern "C" EXPORT void mapClassName( entvars_t *pev ); \ + void mapClassName( entvars_t *pev ) { \ + static LINK_ENTITY_FUNC otherClassName = NULL; \ + static int skip_this = 0; \ + if (skip_this) return; \ + if (otherClassName == NULL) \ + otherClassName = (LINK_ENTITY_FUNC)GetProcAddress(_h_Library, #mapClassName); \ + if (otherClassName == NULL) { \ + skip_this = 1; return; \ + } \ + (*otherClassName)(pev); } + +#else + +#define LINK_ENTITY_TO_FUNC(mapClassName) \ + extern "C" EXPORT void mapClassName( entvars_t *pev ); \ + void mapClassName( entvars_t *pev ) { \ + static LINK_ENTITY_FUNC otherClassName = NULL; \ + static int skip_this = 0; \ + if (skip_this) return; \ + if (otherClassName == NULL) \ + otherClassName = (LINK_ENTITY_FUNC)GetProcAddress(h_Library, #mapClassName); \ + if (otherClassName == NULL) { \ + skip_this = 1; return; \ + } \ + (*otherClassName)(pev); } + +#endif + +// new stuff for 1.1.0.4 release +//LINK_ENTITY_TO_FUNC(CreateInterface); + +// entities for Valve's hl.dll and Standard SDK... +LINK_ENTITY_TO_FUNC(aiscripted_sequence); +LINK_ENTITY_TO_FUNC(ambient_generic); +LINK_ENTITY_TO_FUNC(ammo_357); +LINK_ENTITY_TO_FUNC(ammo_9mmAR); +LINK_ENTITY_TO_FUNC(ammo_9mmbox); +LINK_ENTITY_TO_FUNC(ammo_9mmclip); +LINK_ENTITY_TO_FUNC(ammo_ARgrenades); +LINK_ENTITY_TO_FUNC(ammo_buckshot); +LINK_ENTITY_TO_FUNC(ammo_crossbow); +LINK_ENTITY_TO_FUNC(ammo_egonclip); +LINK_ENTITY_TO_FUNC(ammo_gaussclip); +LINK_ENTITY_TO_FUNC(ammo_glockclip); +LINK_ENTITY_TO_FUNC(ammo_mp5clip); +LINK_ENTITY_TO_FUNC(ammo_mp5grenades); +LINK_ENTITY_TO_FUNC(ammo_rpgclip); +LINK_ENTITY_TO_FUNC(beam); +LINK_ENTITY_TO_FUNC(bmortar); +LINK_ENTITY_TO_FUNC(bodyque); +LINK_ENTITY_TO_FUNC(button_target); +LINK_ENTITY_TO_FUNC(cine_blood); +LINK_ENTITY_TO_FUNC(controller_energy_ball); +LINK_ENTITY_TO_FUNC(controller_head_ball); +LINK_ENTITY_TO_FUNC(crossbow_bolt); +LINK_ENTITY_TO_FUNC(cycler); +LINK_ENTITY_TO_FUNC(cycler_prdroid); +LINK_ENTITY_TO_FUNC(cycler_sprite); +LINK_ENTITY_TO_FUNC(cycler_weapon); +LINK_ENTITY_TO_FUNC(cycler_wreckage); +LINK_ENTITY_TO_FUNC(DelayedUse); +LINK_ENTITY_TO_FUNC(env_beam); +LINK_ENTITY_TO_FUNC(env_beverage); +LINK_ENTITY_TO_FUNC(env_blood); +LINK_ENTITY_TO_FUNC(env_bubbles); +LINK_ENTITY_TO_FUNC(env_debris); +LINK_ENTITY_TO_FUNC(env_explosion); +LINK_ENTITY_TO_FUNC(env_fade); +LINK_ENTITY_TO_FUNC(env_funnel); +LINK_ENTITY_TO_FUNC(env_global); +LINK_ENTITY_TO_FUNC(env_glow); +LINK_ENTITY_TO_FUNC(env_laser); +LINK_ENTITY_TO_FUNC(env_lightning); +LINK_ENTITY_TO_FUNC(env_message); +LINK_ENTITY_TO_FUNC(env_render); +LINK_ENTITY_TO_FUNC(env_shake); +LINK_ENTITY_TO_FUNC(env_shooter); +LINK_ENTITY_TO_FUNC(env_smoker); +LINK_ENTITY_TO_FUNC(env_sound); +LINK_ENTITY_TO_FUNC(env_spark); +LINK_ENTITY_TO_FUNC(env_sprite); +LINK_ENTITY_TO_FUNC(fireanddie); +LINK_ENTITY_TO_FUNC(func_breakable); +LINK_ENTITY_TO_FUNC(func_button); +LINK_ENTITY_TO_FUNC(func_conveyor); +LINK_ENTITY_TO_FUNC(func_door); +LINK_ENTITY_TO_FUNC(func_door_rotating); +LINK_ENTITY_TO_FUNC(func_friction); +LINK_ENTITY_TO_FUNC(func_guntarget); +LINK_ENTITY_TO_FUNC(func_healthcharger); +LINK_ENTITY_TO_FUNC(func_illusionary); +LINK_ENTITY_TO_FUNC(func_ladder); +LINK_ENTITY_TO_FUNC(func_monsterclip); +LINK_ENTITY_TO_FUNC(func_mortar_field); +LINK_ENTITY_TO_FUNC(func_pendulum); +LINK_ENTITY_TO_FUNC(func_plat); +LINK_ENTITY_TO_FUNC(func_platrot); +LINK_ENTITY_TO_FUNC(func_pushable); +LINK_ENTITY_TO_FUNC(func_recharge); +LINK_ENTITY_TO_FUNC(func_rot_button); +LINK_ENTITY_TO_FUNC(func_rotating); +LINK_ENTITY_TO_FUNC(func_tank); +LINK_ENTITY_TO_FUNC(func_tankcontrols); +LINK_ENTITY_TO_FUNC(func_tanklaser); +LINK_ENTITY_TO_FUNC(func_tankmortar); +LINK_ENTITY_TO_FUNC(func_tankrocket); +LINK_ENTITY_TO_FUNC(func_trackautochange); +LINK_ENTITY_TO_FUNC(func_trackchange); +LINK_ENTITY_TO_FUNC(func_tracktrain); +LINK_ENTITY_TO_FUNC(func_train); +LINK_ENTITY_TO_FUNC(func_traincontrols); +LINK_ENTITY_TO_FUNC(func_wall); +LINK_ENTITY_TO_FUNC(func_wall_toggle); +LINK_ENTITY_TO_FUNC(func_water); +LINK_ENTITY_TO_FUNC(game_counter); +LINK_ENTITY_TO_FUNC(game_counter_set); +LINK_ENTITY_TO_FUNC(game_end); +LINK_ENTITY_TO_FUNC(game_player_equip); +LINK_ENTITY_TO_FUNC(game_player_hurt); +LINK_ENTITY_TO_FUNC(game_player_team); +LINK_ENTITY_TO_FUNC(game_score); +LINK_ENTITY_TO_FUNC(game_team_master); +LINK_ENTITY_TO_FUNC(game_team_set); +LINK_ENTITY_TO_FUNC(game_text); +LINK_ENTITY_TO_FUNC(game_zone_player); +LINK_ENTITY_TO_FUNC(garg_stomp); +LINK_ENTITY_TO_FUNC(gibshooter); +LINK_ENTITY_TO_FUNC(grenade); +LINK_ENTITY_TO_FUNC(hornet); +LINK_ENTITY_TO_FUNC(hvr_rocket); +LINK_ENTITY_TO_FUNC(info_bigmomma); +LINK_ENTITY_TO_FUNC(info_intermission); +LINK_ENTITY_TO_FUNC(info_landmark); +LINK_ENTITY_TO_FUNC(info_node); +LINK_ENTITY_TO_FUNC(info_node_air); +LINK_ENTITY_TO_FUNC(info_null); +LINK_ENTITY_TO_FUNC(info_player_deathmatch); +LINK_ENTITY_TO_FUNC(info_player_start); +LINK_ENTITY_TO_FUNC(info_target); +LINK_ENTITY_TO_FUNC(info_teleport_destination); +LINK_ENTITY_TO_FUNC(infodecal); +LINK_ENTITY_TO_FUNC(item_airtank); +LINK_ENTITY_TO_FUNC(item_antidote); +LINK_ENTITY_TO_FUNC(item_battery); +LINK_ENTITY_TO_FUNC(item_healthkit); +LINK_ENTITY_TO_FUNC(item_longjump); +LINK_ENTITY_TO_FUNC(item_security); +LINK_ENTITY_TO_FUNC(item_sodacan); +LINK_ENTITY_TO_FUNC(item_suit); +LINK_ENTITY_TO_FUNC(laser_spot); +LINK_ENTITY_TO_FUNC(light); +LINK_ENTITY_TO_FUNC(light_environment); +LINK_ENTITY_TO_FUNC(light_spot); +LINK_ENTITY_TO_FUNC(momentary_door); +LINK_ENTITY_TO_FUNC(momentary_rot_button); +LINK_ENTITY_TO_FUNC(monstermaker); +LINK_ENTITY_TO_FUNC(monster_alien_controller); +LINK_ENTITY_TO_FUNC(monster_alien_grunt); +LINK_ENTITY_TO_FUNC(monster_alien_slave); +LINK_ENTITY_TO_FUNC(monster_apache); +LINK_ENTITY_TO_FUNC(monster_babycrab); +LINK_ENTITY_TO_FUNC(monster_barnacle); +LINK_ENTITY_TO_FUNC(monster_barney); +LINK_ENTITY_TO_FUNC(monster_barney_dead); +LINK_ENTITY_TO_FUNC(monster_bigmomma); +LINK_ENTITY_TO_FUNC(monster_bloater); +LINK_ENTITY_TO_FUNC(monster_bullchicken); +LINK_ENTITY_TO_FUNC(monster_cine2_hvyweapons); +LINK_ENTITY_TO_FUNC(monster_cine2_scientist); +LINK_ENTITY_TO_FUNC(monster_cine2_slave); +LINK_ENTITY_TO_FUNC(monster_cine3_barney); +LINK_ENTITY_TO_FUNC(monster_cine3_scientist); +LINK_ENTITY_TO_FUNC(monster_cine_barney); +LINK_ENTITY_TO_FUNC(monster_cine_panther); +LINK_ENTITY_TO_FUNC(monster_cine_scientist); +LINK_ENTITY_TO_FUNC(monster_cockroach); +LINK_ENTITY_TO_FUNC(monster_flyer); +LINK_ENTITY_TO_FUNC(monster_flyer_flock); +LINK_ENTITY_TO_FUNC(monster_furniture); +LINK_ENTITY_TO_FUNC(monster_gargantua); +LINK_ENTITY_TO_FUNC(monster_generic); +LINK_ENTITY_TO_FUNC(monster_gman); +LINK_ENTITY_TO_FUNC(monster_grunt_repel); +LINK_ENTITY_TO_FUNC(monster_headcrab); +LINK_ENTITY_TO_FUNC(monster_hevsuit_dead); +LINK_ENTITY_TO_FUNC(monster_hgrunt_dead); +LINK_ENTITY_TO_FUNC(monster_houndeye); +LINK_ENTITY_TO_FUNC(monster_human_assassin); +LINK_ENTITY_TO_FUNC(monster_human_grunt); +LINK_ENTITY_TO_FUNC(monster_ichthyosaur); +LINK_ENTITY_TO_FUNC(monster_leech); +LINK_ENTITY_TO_FUNC(monster_miniturret); +LINK_ENTITY_TO_FUNC(monster_mortar); +LINK_ENTITY_TO_FUNC(monster_nihilanth); +LINK_ENTITY_TO_FUNC(monster_osprey); +LINK_ENTITY_TO_FUNC(monster_rat); +LINK_ENTITY_TO_FUNC(monster_satchel); +LINK_ENTITY_TO_FUNC(monster_scientist); +LINK_ENTITY_TO_FUNC(monster_scientist_dead); +LINK_ENTITY_TO_FUNC(monster_sentry); +LINK_ENTITY_TO_FUNC(monster_sitting_scientist); +LINK_ENTITY_TO_FUNC(monster_snark); +LINK_ENTITY_TO_FUNC(monster_tentacle); +LINK_ENTITY_TO_FUNC(monster_tentaclemaw); +LINK_ENTITY_TO_FUNC(monster_tripmine); +LINK_ENTITY_TO_FUNC(monster_turret); +LINK_ENTITY_TO_FUNC(monster_vortigaunt); +LINK_ENTITY_TO_FUNC(monster_zombie); +LINK_ENTITY_TO_FUNC(multi_manager); +LINK_ENTITY_TO_FUNC(multisource); +LINK_ENTITY_TO_FUNC(nihilanth_energy_ball); +LINK_ENTITY_TO_FUNC(node_viewer); +LINK_ENTITY_TO_FUNC(node_viewer_fly); +LINK_ENTITY_TO_FUNC(node_viewer_human); +LINK_ENTITY_TO_FUNC(node_viewer_large); +LINK_ENTITY_TO_FUNC(path_corner); +LINK_ENTITY_TO_FUNC(path_track); +LINK_ENTITY_TO_FUNC(player); +LINK_ENTITY_TO_FUNC(player_loadsaved); +LINK_ENTITY_TO_FUNC(player_weaponstrip); +LINK_ENTITY_TO_FUNC(rpg_rocket); +LINK_ENTITY_TO_FUNC(scripted_sentence); +LINK_ENTITY_TO_FUNC(scripted_sequence); +LINK_ENTITY_TO_FUNC(soundent); +LINK_ENTITY_TO_FUNC(spark_shower); +LINK_ENTITY_TO_FUNC(speaker); +LINK_ENTITY_TO_FUNC(squidspit); +LINK_ENTITY_TO_FUNC(streak_spiral); +LINK_ENTITY_TO_FUNC(target_cdaudio); +LINK_ENTITY_TO_FUNC(test_effect); +LINK_ENTITY_TO_FUNC(testhull); +LINK_ENTITY_TO_FUNC(trigger); +LINK_ENTITY_TO_FUNC(trigger_auto); +LINK_ENTITY_TO_FUNC(trigger_autosave); +LINK_ENTITY_TO_FUNC(trigger_camera); +LINK_ENTITY_TO_FUNC(trigger_cdaudio); +LINK_ENTITY_TO_FUNC(trigger_changelevel); +LINK_ENTITY_TO_FUNC(trigger_changetarget); +LINK_ENTITY_TO_FUNC(trigger_counter); +LINK_ENTITY_TO_FUNC(trigger_endsection); +LINK_ENTITY_TO_FUNC(trigger_gravity); +LINK_ENTITY_TO_FUNC(trigger_hurt); +LINK_ENTITY_TO_FUNC(trigger_monsterjump); +LINK_ENTITY_TO_FUNC(trigger_multiple); +LINK_ENTITY_TO_FUNC(trigger_once); +LINK_ENTITY_TO_FUNC(trigger_push); +LINK_ENTITY_TO_FUNC(trigger_relay); +LINK_ENTITY_TO_FUNC(trigger_teleport); +LINK_ENTITY_TO_FUNC(trigger_transition); +LINK_ENTITY_TO_FUNC(weapon_357); +LINK_ENTITY_TO_FUNC(weapon_9mmAR); +LINK_ENTITY_TO_FUNC(weapon_9mmhandgun); +LINK_ENTITY_TO_FUNC(weapon_crossbow); +LINK_ENTITY_TO_FUNC(weapon_crowbar); +LINK_ENTITY_TO_FUNC(weapon_egon); +LINK_ENTITY_TO_FUNC(weapon_gauss); +LINK_ENTITY_TO_FUNC(weapon_glock); +LINK_ENTITY_TO_FUNC(weapon_handgrenade); +LINK_ENTITY_TO_FUNC(weapon_hornetgun); +LINK_ENTITY_TO_FUNC(weapon_mp5); +LINK_ENTITY_TO_FUNC(weapon_python); +LINK_ENTITY_TO_FUNC(weapon_rpg); +LINK_ENTITY_TO_FUNC(weapon_satchel); +//LINK_ENTITY_TO_FUNC(weapon_shotgun); +LINK_ENTITY_TO_FUNC(weapon_snark); +LINK_ENTITY_TO_FUNC(weapon_tripmine); +LINK_ENTITY_TO_FUNC(weaponbox); +LINK_ENTITY_TO_FUNC(world_items); +LINK_ENTITY_TO_FUNC(worldspawn); +LINK_ENTITY_TO_FUNC(xen_hair); +LINK_ENTITY_TO_FUNC(xen_hull); +LINK_ENTITY_TO_FUNC(xen_plantlight); +LINK_ENTITY_TO_FUNC(xen_spore_large); +LINK_ENTITY_TO_FUNC(xen_spore_medium); +LINK_ENTITY_TO_FUNC(xen_spore_small); +LINK_ENTITY_TO_FUNC(xen_tree); +LINK_ENTITY_TO_FUNC(xen_ttrigger); + +//// entities for Team Fortress 1.5 +//LINK_ENTITY_TO_FUNC(building_dispenser); +//LINK_ENTITY_TO_FUNC(building_sentrygun); +//LINK_ENTITY_TO_FUNC(building_sentrygun_base); +//LINK_ENTITY_TO_FUNC(detpack); +//LINK_ENTITY_TO_FUNC(dispenser_refill_timer); +//LINK_ENTITY_TO_FUNC(func_nobuild); +//LINK_ENTITY_TO_FUNC(func_nogrenades); +//LINK_ENTITY_TO_FUNC(ghost); +//LINK_ENTITY_TO_FUNC(i_p_t); +//LINK_ENTITY_TO_FUNC(i_t_g); +//LINK_ENTITY_TO_FUNC(i_t_t); +//LINK_ENTITY_TO_FUNC(info_areadef); +//LINK_ENTITY_TO_FUNC(info_player_teamspawn); +//LINK_ENTITY_TO_FUNC(info_tf_teamcheck); +//LINK_ENTITY_TO_FUNC(info_tf_teamset); +//LINK_ENTITY_TO_FUNC(info_tfdetect); +//LINK_ENTITY_TO_FUNC(info_tfgoal); +//LINK_ENTITY_TO_FUNC(info_tfgoal_timer); +//LINK_ENTITY_TO_FUNC(item_armor1); +//LINK_ENTITY_TO_FUNC(item_armor2); +//LINK_ENTITY_TO_FUNC(item_armor3); +//LINK_ENTITY_TO_FUNC(item_artifact_envirosuit); +//LINK_ENTITY_TO_FUNC(item_artifact_invisibility); +//LINK_ENTITY_TO_FUNC(item_artifact_invulnerability); +//LINK_ENTITY_TO_FUNC(item_artifact_super_damage); +//LINK_ENTITY_TO_FUNC(item_cells); +//LINK_ENTITY_TO_FUNC(item_health); +//LINK_ENTITY_TO_FUNC(item_rockets); +//LINK_ENTITY_TO_FUNC(item_shells); +//LINK_ENTITY_TO_FUNC(item_spikes); +//LINK_ENTITY_TO_FUNC(item_tfgoal); +//LINK_ENTITY_TO_FUNC(teledeath); +//LINK_ENTITY_TO_FUNC(tf_ammo_rpgclip); +//LINK_ENTITY_TO_FUNC(tf_flame); +//LINK_ENTITY_TO_FUNC(tf_flamethrower_burst); +//LINK_ENTITY_TO_FUNC(tf_gl_grenade); +//LINK_ENTITY_TO_FUNC(tf_ic_rocket); +//LINK_ENTITY_TO_FUNC(tf_nailgun_nail); +//LINK_ENTITY_TO_FUNC(tf_rpg_rocket); +//LINK_ENTITY_TO_FUNC(tf_weapon_ac); +//LINK_ENTITY_TO_FUNC(tf_weapon_autorifle); +//LINK_ENTITY_TO_FUNC(tf_weapon_axe); +//LINK_ENTITY_TO_FUNC(tf_weapon_caltrop); +//LINK_ENTITY_TO_FUNC(tf_weapon_caltropgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_concussiongrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_empgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_flamethrower); +//LINK_ENTITY_TO_FUNC(tf_weapon_gasgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_genericprimedgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_gl); +//LINK_ENTITY_TO_FUNC(tf_weapon_ic); +//LINK_ENTITY_TO_FUNC(tf_weapon_knife); +//LINK_ENTITY_TO_FUNC(tf_weapon_medikit); +//LINK_ENTITY_TO_FUNC(tf_weapon_mirvbomblet); +//LINK_ENTITY_TO_FUNC(tf_weapon_mirvgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_nailgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_napalmgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_ng); +//LINK_ENTITY_TO_FUNC(tf_weapon_normalgrenade); +//LINK_ENTITY_TO_FUNC(tf_weapon_pl); +//LINK_ENTITY_TO_FUNC(tf_weapon_railgun); +//LINK_ENTITY_TO_FUNC(tf_weapon_rpg); +//LINK_ENTITY_TO_FUNC(tf_weapon_shotgun); +//LINK_ENTITY_TO_FUNC(tf_weapon_sniperrifle); +//LINK_ENTITY_TO_FUNC(tf_weapon_spanner); +//LINK_ENTITY_TO_FUNC(tf_weapon_superng); +//LINK_ENTITY_TO_FUNC(tf_weapon_supershotgun); +//LINK_ENTITY_TO_FUNC(tf_weapon_tranq); +//LINK_ENTITY_TO_FUNC(timer); +// +//// entities for Counter-Strike (Beta 6.5, 6.6, 7.0, 7.1) & 1.0 +//LINK_ENTITY_TO_FUNC(ammo_338magnum); +//LINK_ENTITY_TO_FUNC(ammo_357sig); +//LINK_ENTITY_TO_FUNC(ammo_45acp); +//LINK_ENTITY_TO_FUNC(ammo_50ae); +//LINK_ENTITY_TO_FUNC(ammo_556nato); +//LINK_ENTITY_TO_FUNC(ammo_556natobox); +//LINK_ENTITY_TO_FUNC(ammo_57mm); +//LINK_ENTITY_TO_FUNC(ammo_762nato); +//LINK_ENTITY_TO_FUNC(ammo_9mm); +//LINK_ENTITY_TO_FUNC(armoury_entity); +//LINK_ENTITY_TO_FUNC(env_bombglow); +//LINK_ENTITY_TO_FUNC(func_bomb_target); +//LINK_ENTITY_TO_FUNC(func_buyzone); +//LINK_ENTITY_TO_FUNC(func_escapezone); +//LINK_ENTITY_TO_FUNC(func_grencatch); +//LINK_ENTITY_TO_FUNC(func_hostage_rescue); +//LINK_ENTITY_TO_FUNC(func_vehicle); +//LINK_ENTITY_TO_FUNC(func_vehiclecontrols); +//LINK_ENTITY_TO_FUNC(func_vip_safetyzone); +//LINK_ENTITY_TO_FUNC(func_weaponcheck); +//LINK_ENTITY_TO_FUNC(hostage_entity); +//LINK_ENTITY_TO_FUNC(info_bomb_target); +//LINK_ENTITY_TO_FUNC(info_hostage_rescue); +//LINK_ENTITY_TO_FUNC(info_map_parameters); +//LINK_ENTITY_TO_FUNC(info_vip_start); +//LINK_ENTITY_TO_FUNC(item_assaultsuit); +//LINK_ENTITY_TO_FUNC(item_kevlar); +//LINK_ENTITY_TO_FUNC(item_thighpack); +//LINK_ENTITY_TO_FUNC(weapon_ak47); +//LINK_ENTITY_TO_FUNC(weapon_aug); +//LINK_ENTITY_TO_FUNC(weapon_awp); +//LINK_ENTITY_TO_FUNC(weapon_c4); +//LINK_ENTITY_TO_FUNC(weapon_deagle); +//LINK_ENTITY_TO_FUNC(weapon_elite); +//LINK_ENTITY_TO_FUNC(weapon_fiveseven); +//LINK_ENTITY_TO_FUNC(weapon_flashbang); +//LINK_ENTITY_TO_FUNC(weapon_g3sg1); +//LINK_ENTITY_TO_FUNC(weapon_glock18); +//LINK_ENTITY_TO_FUNC(weapon_hegrenade); +//LINK_ENTITY_TO_FUNC(weapon_knife); +//LINK_ENTITY_TO_FUNC(weapon_m249); +//LINK_ENTITY_TO_FUNC(weapon_m3); +//LINK_ENTITY_TO_FUNC(weapon_m4a1); +//LINK_ENTITY_TO_FUNC(weapon_mac10); +//LINK_ENTITY_TO_FUNC(weapon_mp5navy); +//LINK_ENTITY_TO_FUNC(weapon_p228); +//LINK_ENTITY_TO_FUNC(weapon_p90); +//LINK_ENTITY_TO_FUNC(weapon_scout); +//LINK_ENTITY_TO_FUNC(weapon_sg550); +//LINK_ENTITY_TO_FUNC(weapon_sg552); +//LINK_ENTITY_TO_FUNC(weapon_smokegrenade); +//LINK_ENTITY_TO_FUNC(weapon_tmp); +//LINK_ENTITY_TO_FUNC(weapon_usp); +//LINK_ENTITY_TO_FUNC(weapon_ump45); +//LINK_ENTITY_TO_FUNC(weapon_xm1014); +// +//// entities for Opposing Force +//LINK_ENTITY_TO_FUNC(ammo_556); +//LINK_ENTITY_TO_FUNC(ammo_762); +//LINK_ENTITY_TO_FUNC(ammo_eagleclip); +//LINK_ENTITY_TO_FUNC(ammo_spore); +//LINK_ENTITY_TO_FUNC(charged_bolt); +//LINK_ENTITY_TO_FUNC(displacer_ball); +//LINK_ENTITY_TO_FUNC(eagle_laser); +//LINK_ENTITY_TO_FUNC(env_blowercannon); +//LINK_ENTITY_TO_FUNC(env_electrified_wire); +//LINK_ENTITY_TO_FUNC(env_genewormcloud); +//LINK_ENTITY_TO_FUNC(env_genewormspawn); +//LINK_ENTITY_TO_FUNC(env_rope); +//LINK_ENTITY_TO_FUNC(env_spritetrain); +//LINK_ENTITY_TO_FUNC(func_op4mortarcontroller); +//LINK_ENTITY_TO_FUNC(func_tank_of); +//LINK_ENTITY_TO_FUNC(func_tankcontrols_of); +//LINK_ENTITY_TO_FUNC(func_tanklaser_of); +//LINK_ENTITY_TO_FUNC(func_tankmortar_of); +//LINK_ENTITY_TO_FUNC(func_tankrocket_of); +//LINK_ENTITY_TO_FUNC(gonomeguts); +//LINK_ENTITY_TO_FUNC(grapple_tip); +//LINK_ENTITY_TO_FUNC(hvr_blkop_rocket); +//LINK_ENTITY_TO_FUNC(info_ctfdetect); +//LINK_ENTITY_TO_FUNC(info_ctfspawn); +//LINK_ENTITY_TO_FUNC(info_ctfspawn_powerup); +//LINK_ENTITY_TO_FUNC(info_displacer_earth_target); +//LINK_ENTITY_TO_FUNC(info_displacer_xen_target); +//LINK_ENTITY_TO_FUNC(info_pitworm); +//LINK_ENTITY_TO_FUNC(info_pitworm_steam_lock); +//LINK_ENTITY_TO_FUNC(item_ctfaccelerator); +//LINK_ENTITY_TO_FUNC(item_ctfbackpack); +//LINK_ENTITY_TO_FUNC(item_ctfbase); +//LINK_ENTITY_TO_FUNC(item_ctfflag); +//LINK_ENTITY_TO_FUNC(item_ctflongjump); +//LINK_ENTITY_TO_FUNC(item_ctfportablehev); +//LINK_ENTITY_TO_FUNC(item_ctfregeneration); +//LINK_ENTITY_TO_FUNC(item_generic); +//LINK_ENTITY_TO_FUNC(item_nuclearbomb); +//LINK_ENTITY_TO_FUNC(item_nuclearbombbutton); +//LINK_ENTITY_TO_FUNC(item_nuclearbombtimer); +//LINK_ENTITY_TO_FUNC(item_vest); +//LINK_ENTITY_TO_FUNC(monster_ShockTrooper_dead); +//LINK_ENTITY_TO_FUNC(monster_alien_babyvoltigore); +//LINK_ENTITY_TO_FUNC(monster_alien_slave_dead); +//LINK_ENTITY_TO_FUNC(monster_alien_voltigore); +//LINK_ENTITY_TO_FUNC(monster_assassin_repel); +//LINK_ENTITY_TO_FUNC(monster_blkop_apache); +//LINK_ENTITY_TO_FUNC(monster_blkop_osprey); +//LINK_ENTITY_TO_FUNC(monster_cleansuit_scientist); +//LINK_ENTITY_TO_FUNC(monster_cleansuit_scientist_dead); +//LINK_ENTITY_TO_FUNC(monster_drillsergeant); +//LINK_ENTITY_TO_FUNC(monster_fgrunt_repel); +//LINK_ENTITY_TO_FUNC(monster_geneworm); +//LINK_ENTITY_TO_FUNC(monster_gonome); +//LINK_ENTITY_TO_FUNC(monster_gonome_dead); +//LINK_ENTITY_TO_FUNC(monster_grunt_ally_repel); +//LINK_ENTITY_TO_FUNC(monster_hfgrunt_dead); +//LINK_ENTITY_TO_FUNC(monster_houndeye_dead); +//LINK_ENTITY_TO_FUNC(monster_human_friendly_grunt); +//LINK_ENTITY_TO_FUNC(monster_human_grunt_ally); +//LINK_ENTITY_TO_FUNC(monster_human_grunt_ally_dead); +//LINK_ENTITY_TO_FUNC(monster_human_medic_ally); +//LINK_ENTITY_TO_FUNC(monster_human_torch_ally); +//LINK_ENTITY_TO_FUNC(monster_male_assassin); +//LINK_ENTITY_TO_FUNC(monster_massassin_dead); +//LINK_ENTITY_TO_FUNC(monster_medic_ally_repel); +//LINK_ENTITY_TO_FUNC(monster_op4loader); +//LINK_ENTITY_TO_FUNC(monster_otis); +//LINK_ENTITY_TO_FUNC(monster_otis_dead); +//LINK_ENTITY_TO_FUNC(monster_penguin); +//LINK_ENTITY_TO_FUNC(monster_pitdrone); +//LINK_ENTITY_TO_FUNC(monster_pitworm); +//LINK_ENTITY_TO_FUNC(monster_pitworm_up); +//LINK_ENTITY_TO_FUNC(monster_recruit); +//LINK_ENTITY_TO_FUNC(monster_shockroach); +//LINK_ENTITY_TO_FUNC(monster_shocktrooper); +//LINK_ENTITY_TO_FUNC(monster_shocktrooper_repel); +//LINK_ENTITY_TO_FUNC(monster_sitting_cleansuit_scientist); +//LINK_ENTITY_TO_FUNC(monster_skeleton_dead); +//LINK_ENTITY_TO_FUNC(monster_torch_ally_repel); +//LINK_ENTITY_TO_FUNC(monster_zombie_barney); +//LINK_ENTITY_TO_FUNC(monster_zombie_soldier); +//LINK_ENTITY_TO_FUNC(monster_zombie_soldier_dead); +//LINK_ENTITY_TO_FUNC(mortar_shell); +//LINK_ENTITY_TO_FUNC(op4mortar); +//LINK_ENTITY_TO_FUNC(pitdronespike); +//LINK_ENTITY_TO_FUNC(pitworm_gib); +//LINK_ENTITY_TO_FUNC(pitworm_gibshooter); +//LINK_ENTITY_TO_FUNC(rope_sample); +//LINK_ENTITY_TO_FUNC(rope_segment); +//LINK_ENTITY_TO_FUNC(shock_beam); +//LINK_ENTITY_TO_FUNC(spore); +//LINK_ENTITY_TO_FUNC(trigger_ctfgeneric); +//LINK_ENTITY_TO_FUNC(trigger_geneworm_hit); +//LINK_ENTITY_TO_FUNC(trigger_kill_nogib); +//LINK_ENTITY_TO_FUNC(trigger_playerfreeze); +//LINK_ENTITY_TO_FUNC(trigger_xen_return); +//LINK_ENTITY_TO_FUNC(weapon_displacer); +//LINK_ENTITY_TO_FUNC(weapon_eagle); +//LINK_ENTITY_TO_FUNC(weapon_grapple); +//LINK_ENTITY_TO_FUNC(weapon_penguin); +//LINK_ENTITY_TO_FUNC(weapon_pipewrench); +//LINK_ENTITY_TO_FUNC(weapon_shockrifle); +//LINK_ENTITY_TO_FUNC(weapon_shockroach); +//LINK_ENTITY_TO_FUNC(weapon_sniperrifle); +//LINK_ENTITY_TO_FUNC(weapon_sporelauncher); +// +//// entities for FrontLineForce (1.0) +//LINK_ENTITY_TO_FUNC(ammo_ak5); +//LINK_ENTITY_TO_FUNC(ammo_beretta); +//LINK_ENTITY_TO_FUNC(ammo_famas); +//LINK_ENTITY_TO_FUNC(ammo_hk21); +//LINK_ENTITY_TO_FUNC(ammo_m4); +//LINK_ENTITY_TO_FUNC(ammo_mac10); +//LINK_ENTITY_TO_FUNC(ammo_mk23); +//LINK_ENTITY_TO_FUNC(ammo_mp5a2); +//LINK_ENTITY_TO_FUNC(ammo_mp5sd); +//LINK_ENTITY_TO_FUNC(ammo_msg90); +//LINK_ENTITY_TO_FUNC(ammo_spas12); +//LINK_ENTITY_TO_FUNC(ammo_ump45); +//LINK_ENTITY_TO_FUNC(capture_point); +//LINK_ENTITY_TO_FUNC(info_frontline); +//LINK_ENTITY_TO_FUNC(info_player_attacker); +//LINK_ENTITY_TO_FUNC(info_player_defender); +//LINK_ENTITY_TO_FUNC(info_player_observer); +//LINK_ENTITY_TO_FUNC(weapon_ak5); +//LINK_ENTITY_TO_FUNC(weapon_beretta); +//LINK_ENTITY_TO_FUNC(weapon_famas); +//LINK_ENTITY_TO_FUNC(weapon_hk21); +//LINK_ENTITY_TO_FUNC(weapon_m4); +//LINK_ENTITY_TO_FUNC(weapon_mk23); +//LINK_ENTITY_TO_FUNC(weapon_mp5a2); +//LINK_ENTITY_TO_FUNC(weapon_mp5sd); +//LINK_ENTITY_TO_FUNC(weapon_msg90); +//LINK_ENTITY_TO_FUNC(weapon_spas12); + +// entities for Natural Selection +LINK_ENTITY_TO_FUNC(info_team_start); +LINK_ENTITY_TO_FUNC(info_spectate); +LINK_ENTITY_TO_FUNC(info_join_team); +LINK_ENTITY_TO_FUNC(info_leave_game); +LINK_ENTITY_TO_FUNC(info_join_autoassign); +LINK_ENTITY_TO_FUNC(info_mapinfo); +LINK_ENTITY_TO_FUNC(info_gameplay); + +LINK_ENTITY_TO_FUNC(env_fog); +LINK_ENTITY_TO_FUNC(env_gamma); +LINK_ENTITY_TO_FUNC(env_particles); +LINK_ENTITY_TO_FUNC(env_particles_custom); + +LINK_ENTITY_TO_FUNC(func_weldable); +LINK_ENTITY_TO_FUNC(func_seethrough); +LINK_ENTITY_TO_FUNC(func_seethroughdoor); +//LINK_ENTITY_TO_FUNC(func_waypoint); +LINK_ENTITY_TO_FUNC(func_nobuild); +LINK_ENTITY_TO_FUNC(func_resource); + +LINK_ENTITY_TO_FUNC(target_mp3audio); +LINK_ENTITY_TO_FUNC(trigger_random); +LINK_ENTITY_TO_FUNC(trigger_presence); +LINK_ENTITY_TO_FUNC(trigger_script); +LINK_ENTITY_TO_FUNC(info_location); + +LINK_ENTITY_TO_FUNC(team_hive); +LINK_ENTITY_TO_FUNC(team_command); +LINK_ENTITY_TO_FUNC(team_breach); +LINK_ENTITY_TO_FUNC(team_egg); +LINK_ENTITY_TO_FUNC(team_webstrand); + +// Marine weapons and equipment +LINK_ENTITY_TO_FUNC(weapon_knife); +LINK_ENTITY_TO_FUNC(weapon_grenade); +LINK_ENTITY_TO_FUNC(weapon_machinegun); +LINK_ENTITY_TO_FUNC(weapon_pistol); +LINK_ENTITY_TO_FUNC(weapon_flamegun); +LINK_ENTITY_TO_FUNC(weapon_heavymachinegun); +LINK_ENTITY_TO_FUNC(weapon_grenadegun); +LINK_ENTITY_TO_FUNC(weapon_shotgun); +LINK_ENTITY_TO_FUNC(weapon_nukegun); +LINK_ENTITY_TO_FUNC(weapon_mine); +LINK_ENTITY_TO_FUNC(weapon_welder); + +LINK_ENTITY_TO_FUNC(item_genericammo); +LINK_ENTITY_TO_FUNC(item_mine); +LINK_ENTITY_TO_FUNC(item_health); +LINK_ENTITY_TO_FUNC(item_catalyst); +LINK_ENTITY_TO_FUNC(item_heavyarmor); +LINK_ENTITY_TO_FUNC(item_jetpack); + +LINK_ENTITY_TO_FUNC(scan); +LINK_ENTITY_TO_FUNC(turret); +LINK_ENTITY_TO_FUNC(phasegate); +LINK_ENTITY_TO_FUNC(siegeturret); +LINK_ENTITY_TO_FUNC(nuke); + +// Marine buildings +LINK_ENTITY_TO_FUNC(resourcetower); +LINK_ENTITY_TO_FUNC(team_infportal); +LINK_ENTITY_TO_FUNC(team_turretfactory); +LINK_ENTITY_TO_FUNC(team_advturretfactory); +LINK_ENTITY_TO_FUNC(team_armory); +LINK_ENTITY_TO_FUNC(team_advarmory); +LINK_ENTITY_TO_FUNC(team_armslab); +LINK_ENTITY_TO_FUNC(team_prototypelab); +LINK_ENTITY_TO_FUNC(team_observatory); +LINK_ENTITY_TO_FUNC(team_chemlab); +LINK_ENTITY_TO_FUNC(team_medlab); +LINK_ENTITY_TO_FUNC(team_nukeplant); + +// Alien buildings +LINK_ENTITY_TO_FUNC(alienresourcetower); +LINK_ENTITY_TO_FUNC(defensechamber); +LINK_ENTITY_TO_FUNC(spikeprojectile); +LINK_ENTITY_TO_FUNC(offensechamber); +LINK_ENTITY_TO_FUNC(sensorychamber); +LINK_ENTITY_TO_FUNC(movementchamber); + +// Alien abilities that are technically weapons (along with their projectiles) +LINK_ENTITY_TO_FUNC(weapon_acidrocket); +LINK_ENTITY_TO_FUNC(weapon_acidrocketgun); +LINK_ENTITY_TO_FUNC(weapon_bilebomb); +LINK_ENTITY_TO_FUNC(weapon_bilebombgun); +LINK_ENTITY_TO_FUNC(weapon_bitegun); +LINK_ENTITY_TO_FUNC(weapon_blink); +LINK_ENTITY_TO_FUNC(weapon_claws); +LINK_ENTITY_TO_FUNC(weapon_devour); +LINK_ENTITY_TO_FUNC(weapon_divinewind); +LINK_ENTITY_TO_FUNC(weapon_healingspray); +LINK_ENTITY_TO_FUNC(weapon_metabolize); +LINK_ENTITY_TO_FUNC(weapon_parasite); +LINK_ENTITY_TO_FUNC(weapon_primalscream); +LINK_ENTITY_TO_FUNC(weapon_spikegun); +LINK_ENTITY_TO_FUNC(weapon_bite2gun); +LINK_ENTITY_TO_FUNC(weapon_spit); +LINK_ENTITY_TO_FUNC(weapon_spore); +LINK_ENTITY_TO_FUNC(weapon_stomp); +LINK_ENTITY_TO_FUNC(weapon_swipe); +LINK_ENTITY_TO_FUNC(weapon_umbra); +LINK_ENTITY_TO_FUNC(weapon_webspinner); + +// Alien abilities +LINK_ENTITY_TO_FUNC(weapon_leap); +LINK_ENTITY_TO_FUNC(weapon_charge); + +LINK_ENTITY_TO_FUNC(webgunprojectile); +LINK_ENTITY_TO_FUNC(spitgunprojectile); +LINK_ENTITY_TO_FUNC(stompprojectile); +LINK_ENTITY_TO_FUNC(sporegunprojectile); +LINK_ENTITY_TO_FUNC(umbracloud); +LINK_ENTITY_TO_FUNC(umbraprojectile); + diff --git a/main/source/HPB_bot/dlls/make b/main/source/HPB_bot/dlls/make index 436504db..0ab6a8c7 100644 --- a/main/source/HPB_bot/dlls/make +++ b/main/source/HPB_bot/dlls/make @@ -1,44 +1,44 @@ -# -# HPB_bot makefile for Linux -# -# created: 12/16/2000 botman (botman@mailandnews.com) -# - -# the following specifies the path to your MOD... -MOD_DIR = ../ - -CPP = egcs - -BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -DAVH_SERVER -DLINUX - -CFLAGS=$(BASE_CFLAGS) -w -m486 -O2 -ffast-math -funroll-loops \ - -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ - -malign-jumps=2 -malign-functions=2 - -INCLUDEDIRS=-I. -I../../engine -I../../common -I../../mod -I../../game_shared -I../../lua/include -I../../pm_shared -I../.. -I../../dlls - -LDFLAGS=-lm -lstdc++ -#SHLIBCFLAGS=-fPIC -SHLIBLDFLAGS=-shared -static - -#CPPFLAGS = ${BASEFLAGS} -m486 -O2 -w -I../engine -I../common -I../pm_shared -CPPFLAGS = ${BASEFLAGS} -m486 -w -I../engine -I../../common -I../../pm_shared - -OBJ = bot.o bot_client.o bot_combat.o bot_navigate.o bot_start.o dll.o engine.o h_export.o linkfunc.o util.o waypoint.o - -#${CPP} $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ ${OBJ} -ldl - -HPB_bot_i386.so: ${OBJ} - ${CPP} $(CFLAGS) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ ${OBJ} - cp -f HPB_bot_i386.so ${MOD_DIR}/dlls - -clean: - -rm -f *.o - -rm -f *.so - -%.o: %.cpp - ${CPP} ${CPPFLAGS} $(INCLUDEDIRS) -c $< -o $@ - -%.o: %.c - ${CPP} ${CPPFLAGS} $(INCLUDEDIRS) -c $< -o $@ - +# +# HPB_bot makefile for Linux +# +# created: 12/16/2000 botman (botman@mailandnews.com) +# + +# the following specifies the path to your MOD... +MOD_DIR = ../ + +CPP = egcs + +BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -DAVH_SERVER -DLINUX + +CFLAGS=$(BASE_CFLAGS) -w -m486 -O2 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ + -malign-jumps=2 -malign-functions=2 + +INCLUDEDIRS=-I. -I../../engine -I../../common -I../../mod -I../../game_shared -I../../lua/include -I../../pm_shared -I../.. -I../../dlls + +LDFLAGS=-lm -lstdc++ +#SHLIBCFLAGS=-fPIC +SHLIBLDFLAGS=-shared -static + +#CPPFLAGS = ${BASEFLAGS} -m486 -O2 -w -I../engine -I../common -I../pm_shared +CPPFLAGS = ${BASEFLAGS} -m486 -w -I../engine -I../../common -I../../pm_shared + +OBJ = bot.o bot_client.o bot_combat.o bot_navigate.o bot_start.o dll.o engine.o h_export.o linkfunc.o util.o waypoint.o + +#${CPP} $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ ${OBJ} -ldl + +HPB_bot_i386.so: ${OBJ} + ${CPP} $(CFLAGS) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ ${OBJ} + cp -f HPB_bot_i386.so ${MOD_DIR}/dlls + +clean: + -rm -f *.o + -rm -f *.so + +%.o: %.cpp + ${CPP} ${CPPFLAGS} $(INCLUDEDIRS) -c $< -o $@ + +%.o: %.c + ${CPP} ${CPPFLAGS} $(INCLUDEDIRS) -c $< -o $@ + diff --git a/main/source/HPB_bot/dlls/util.cpp b/main/source/HPB_bot/dlls/util.cpp index c6a034af..d7de2028 100644 --- a/main/source/HPB_bot/dlls/util.cpp +++ b/main/source/HPB_bot/dlls/util.cpp @@ -1,661 +1,661 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// util.cpp -// - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "HPB_bot/engine/engine.h" -#include "dlls/cbase.h" -#include "dlls/player.h" - -#include "bot.h" -#include "bot_func.h" - - -extern int mod_id; -extern bot_t bots[32]; -extern edict_t *pent_info_ctfdetect; -extern char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; -extern int num_teams; - -int gmsgTextMsg = 0; -int gmsgSayText = 0; -int gmsgShowMenu = 0; - - -Vector UTIL_VecToAngles( const Vector &vec ) -{ - float rgflVecOut[3]; - VEC_TO_ANGLES(vec, rgflVecOut); - return Vector(rgflVecOut); -} - - -// Overloaded to add IGNORE_GLASS -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); -} - - -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); -} - - -void UTIL_MakeVectors( const Vector &vecAngles ) -{ - MAKE_VECTORS( vecAngles ); -} - - -edict_t *UTIL_FindEntityInSphere( edict_t *pentStart, const Vector &vecCenter, float flRadius ) -{ - edict_t *pentEntity; - - pentEntity = FIND_ENTITY_IN_SPHERE( pentStart, vecCenter, flRadius); - - if (!FNullEnt(pentEntity)) - return pentEntity; - - return NULL; -} - - -edict_t *UTIL_FindEntityByString( edict_t *pentStart, const char *szKeyword, const char *szValue ) -{ - edict_t *pentEntity; - - pentEntity = FIND_ENTITY_BY_STRING( pentStart, szKeyword, szValue ); - - if (!FNullEnt(pentEntity)) - return pentEntity; - return NULL; -} - -edict_t *UTIL_FindEntityByClassname( edict_t *pentStart, const char *szName ) -{ - return UTIL_FindEntityByString( pentStart, "classname", szName ); -} - -edict_t *UTIL_FindEntityByTargetname( edict_t *pentStart, const char *szName ) -{ - return UTIL_FindEntityByString( pentStart, "targetname", szName ); -} - - -int UTIL_PointContents( const Vector &vec ) -{ - return POINT_CONTENTS(vec); -} - - -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) -{ - SET_SIZE( ENT(pev), vecMin, vecMax ); -} - - -void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) -{ - SET_ORIGIN(ENT(pev), vecOrigin ); -} - - -void ClientPrint( edict_t *pEntity, int msg_dest, const char *msg_name) -{ -// if (gmsgTextMsg == 0) -// gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); -// -// pfnMessageBegin( MSG_ONE, gmsgTextMsg, NULL, pEntity ); -// -// pfnWriteByte( msg_dest ); -// pfnWriteString( msg_name ); -// pfnMessageEnd(); -} - -void UTIL_SayText( const char *pText, edict_t *pEdict ) -{ -// if (gmsgSayText == 0) -// gmsgSayText = REG_USER_MSG( "SayText", -1 ); -// -// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, pEdict ); -// pfnWriteByte( ENTINDEX(pEdict) ); -// if (mod_id == FRONTLINE_DLL) -// pfnWriteShort(0); -// pfnWriteString( pText ); -// pfnMessageEnd(); -} - - -void UTIL_HostSay( edict_t *pEntity, int teamonly, char *message ) -{ -// int j; -// char text[128]; -// char *pc; -// int sender_team, player_team; -// edict_t *client; -// -// // make sure the text has content -// for ( pc = message; pc != NULL && *pc != 0; pc++ ) -// { -// if ( isprint( *pc ) && !isspace( *pc ) ) -// { -// pc = NULL; // we've found an alphanumeric character, so text is valid -// break; -// } -// } -// -// if ( pc != NULL ) -// return; // no character found, so say nothing -// -// // turn on color set 2 (color on, no sound) -// if ( teamonly ) -// sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); -// else -// sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); -// -// j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator -// if ( (int)strlen(message) > j ) -// message[j] = 0; -// -// strcat( text, message ); -// strcat( text, "\n" ); -// -// // loop through all players -// // Start with the first player. -// // This may return the world in single player if the client types something between levels or during spawn -// // so check it, or it will infinite loop -// -// if (gmsgSayText == 0) -// gmsgSayText = REG_USER_MSG( "SayText", -1 ); -// -// sender_team = UTIL_GetTeam(pEntity); -// -// client = NULL; -// while ( ((client = UTIL_FindEntityByClassname( client, "player" )) != NULL) && -// (!FNullEnt(client)) ) -// { -// if ( client == pEntity ) // skip sender of message -// continue; -// -// player_team = UTIL_GetTeam(client); -// -// if ( teamonly && (sender_team != player_team) ) -// continue; -// -// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, client ); -// pfnWriteByte( ENTINDEX(pEntity) ); -// if (mod_id == FRONTLINE_DLL) -// pfnWriteShort(0); -// pfnWriteString( text ); -// pfnMessageEnd(); -// } -// -// // print to the sending client -// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, pEntity ); -// pfnWriteByte( ENTINDEX(pEntity) ); -// if (mod_id == FRONTLINE_DLL) -// pfnWriteShort(0); -// pfnWriteString( text ); -// pfnMessageEnd(); -// -// // echo to server console -// g_engfuncs.pfnServerPrint( text ); -} - - -#ifdef DEBUG -edict_t *DBG_EntOfVars( const entvars_t *pev ) -{ - if (pev->pContainingEntity != NULL) - return pev->pContainingEntity; - ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); - edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); - if (pent == NULL) - ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); - ((entvars_t *)pev)->pContainingEntity = pent; - return pent; -} -#endif //DEBUG - - -// return team number 0 through 3 based what MOD uses for team numbers -int UTIL_GetTeam(edict_t *pEntity) -{ - if (mod_id == TFC_DLL) - { - return pEntity->v.team - 1; // TFC teams are 1-4 based - } - else if (mod_id == CSTRIKE_DLL) - { - char *infobuffer; - char model_name[32]; - - infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); - strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); - - if ((strcmp(model_name, "terror") == 0) || // Phoenix Connektion - (strcmp(model_name, "arab") == 0) || // old L337 Krew - (strcmp(model_name, "leet") == 0) || // L337 Krew - (strcmp(model_name, "artic") == 0) || // Artic Avenger - (strcmp(model_name, "guerilla") == 0)) // Gorilla Warfare - { - return 0; - } - else if ((strcmp(model_name, "urban") == 0) || // Seal Team 6 - (strcmp(model_name, "gsg9") == 0) || // German GSG-9 - (strcmp(model_name, "sas") == 0) || // UK SAS - (strcmp(model_name, "gign") == 0) || // French GIGN - (strcmp(model_name, "vip") == 0)) // VIP - { - return 1; - } - - return 0; // return zero if team is unknown - } - else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) - { - // OpFor CTF map... - - char *infobuffer; - char model_name[32]; - - infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); - strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); - - if ((strcmp(model_name, "ctf_barney") == 0) || - (strcmp(model_name, "cl_suit") == 0) || - (strcmp(model_name, "ctf_gina") == 0) || - (strcmp(model_name, "ctf_gordon") == 0) || - (strcmp(model_name, "otis") == 0) || - (strcmp(model_name, "ctf_scientist") == 0)) - { - return 0; - } - else if ((strcmp(model_name, "beret") == 0) || - (strcmp(model_name, "drill") == 0) || - (strcmp(model_name, "grunt") == 0) || - (strcmp(model_name, "recruit") == 0) || - (strcmp(model_name, "shephard") == 0) || - (strcmp(model_name, "tower") == 0)) - { - return 1; - } - - return 0; // return zero if team is unknown - } - else if (mod_id == FRONTLINE_DLL) - { - return pEntity->v.team - 1; // Front Line Force teams are 1-4 based - } - else if(mod_id == AVH_DLL) - { - return pEntity->v.team; - } - else // must be HL or OpFor deathmatch... - { - char *infobuffer; - char model_name[32]; - - if (team_names[0][0] == 0) - { - char *pName; - char teamlist[MAX_TEAMS*MAX_TEAMNAME_LENGTH]; - int i; - - num_teams = 0; - strcpy(teamlist, CVAR_GET_STRING("mp_teamlist")); - pName = teamlist; - pName = strtok(pName, ";"); - - while (pName != NULL && *pName) - { - // check that team isn't defined twice - for (i=0; i < num_teams; i++) - if (strcmp(pName, team_names[i]) == 0) - break; - if (i == num_teams) - { - strcpy(team_names[num_teams], pName); - num_teams++; - } - pName = strtok(NULL, ";"); - } - } - - infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); - strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); - - for (int index=0; index < num_teams; index++) - { - if (strcmp(model_name, team_names[index]) == 0) - return index; - } - - return 0; - } -} - - -// return class number 0 through N -int UTIL_GetClass(edict_t *pEntity) -{ - char *infobuffer; - char model_name[32]; - - infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); - strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); - - if (mod_id == FRONTLINE_DLL) - { - if ((strcmp(model_name, "natorecon") == 0) || - (strcmp(model_name, "axisrecon") == 0)) - { - return 0; // recon - } - else if ((strcmp(model_name, "natoassault") == 0) || - (strcmp(model_name, "axisassault") == 0)) - { - return 1; // assault - } - else if ((strcmp(model_name, "natosupport") == 0) || - (strcmp(model_name, "axissupport") == 0)) - { - return 2; // support - } - } - - return 0; -} - - -int UTIL_GetBotIndex(edict_t *pEdict) -{ - int index; - - for (index=0; index < 32; index++) - { - if (bots[index].pEdict == pEdict) - { - return index; - } - } - - return -1; // return -1 if edict is not a bot -} - - -bot_t *UTIL_GetBotPointer(edict_t *pEdict) -{ - int index; - - for (index=0; index < 32; index++) - { - if (bots[index].pEdict == pEdict) - { - break; - } - } - - if (index < 32) - return (&bots[index]); - - return NULL; // return NULL if edict is not a bot -} - - -bool IsAlive(edict_t *pEdict) -{ - return ((pEdict->v.deadflag == DEAD_NO) && - (pEdict->v.health > 0) && !(pEdict->v.flags & FL_NOTARGET)); -} - - -bool FInViewCone(Vector *pOrigin, edict_t *pEdict) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pEdict->v.angles ); - - vec2LOS = ( *pOrigin - pEdict->v.origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > 0.50 ) // 60 degree field of view - { - return TRUE; - } - else - { - return FALSE; - } -} - - -bool FVisible( const Vector &vecOrigin, edict_t *pEdict ) -{ - TraceResult tr; - Vector vecLookerOrigin; - - // look through caller's eyes - vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs; - - int bInWater = (UTIL_PointContents (vecOrigin) == CONTENTS_WATER); - int bLookerInWater = (UTIL_PointContents (vecLookerOrigin) == CONTENTS_WATER); - - // don't look through water - if (bInWater != bLookerInWater) - return FALSE; - - UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, pEdict, &tr); - - if (tr.flFraction != 1.0) - { - return FALSE; // Line of sight is not established - } - else - { - return TRUE; // line of sight is valid. - } -} - - -Vector GetGunPosition(edict_t *pEdict) -{ - return (pEdict->v.origin + pEdict->v.view_ofs); -} - - -void UTIL_SelectItem(edict_t *pEdict, char *item_name) -{ - FakeClientCommand(pEdict, item_name, NULL, NULL); -} - - -Vector VecBModelOrigin(edict_t *pEdict) -{ - return pEdict->v.absmin + (pEdict->v.size * 0.5); -} - - -bool UpdateSounds(edict_t *pEdict, edict_t *pPlayer) -{ - float distance; - static bool check_footstep_sounds = TRUE; - static float footstep_sounds_on; - float sensitivity = 1.0; - float volume; - - // update sounds made by this player, alert bots if they are nearby... - - if (check_footstep_sounds) - { - check_footstep_sounds = FALSE; - footstep_sounds_on = CVAR_GET_FLOAT("mp_footsteps"); - } - - if (footstep_sounds_on > 0.0) - { - CBasePlayer* thePlayer = (CBasePlayer*)CBaseEntity::Instance(pPlayer); - - // check if this player is moving fast enough to make sounds... - if (pPlayer->v.velocity.Length2D() > thePlayer->GetMaxWalkSpeed()) - { - volume = 500.0; // volume of sound being made (just pick something) - - Vector v_sound = pPlayer->v.origin - pEdict->v.origin; - - distance = v_sound.Length(); - - // is the bot close enough to hear this sound? - if (distance < (volume * sensitivity)) - { - Vector bot_angles = UTIL_VecToAngles( v_sound ); - - pEdict->v.ideal_yaw = bot_angles.y; - - BotFixIdealYaw(pEdict); - - return TRUE; - } - } - } - - return FALSE; -} - - -void UTIL_ShowMenu( edict_t *pEdict, int slots, int displaytime, bool needmore, char *pText ) -{ -// if (gmsgShowMenu == 0) -// gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 ); -// -// pfnMessageBegin( MSG_ONE, gmsgShowMenu, NULL, pEdict ); -// -// pfnWriteShort( slots ); -// pfnWriteChar( displaytime ); -// pfnWriteByte( needmore ); -// pfnWriteString( pText ); -// -// pfnMessageEnd(); -} - -void UTIL_BuildFileName(char *filename, char *arg1, char *arg2) -{ - - if (mod_id == VALVE_DLL) -#ifndef __linux__ - strcpy(filename, "valve\\"); -#else - strcpy(filename, "valve/"); -#endif - - else if (mod_id == TFC_DLL) -#ifndef __linux__ - strcpy(filename, "tfc\\"); -#else - strcpy(filename, "tfc/"); -#endif - - else if (mod_id == CSTRIKE_DLL) -#ifndef __linux__ - strcpy(filename, "cstrike\\"); -#else - strcpy(filename, "cstrike/"); -#endif - - else if (mod_id == GEARBOX_DLL) -#ifndef __linux__ - strcpy(filename, "gearbox\\"); -#else - strcpy(filename, "gearbox/"); -#endif - - else if (mod_id == FRONTLINE_DLL) -#ifndef __linux__ - strcpy(filename, "frontline\\"); -#else - strcpy(filename, "frontline/"); -#endif - - else if (mod_id == AVH_DLL) - { - string filenameString = string(getModDirectory()); -#ifndef __linux__ - filenameString += "\\"; -#else - filenameString += '/'; -#endif - strcpy(filename,filenameString.c_str()); - } - else - { - filename[0] = 0; - return; - } - - if ((arg1) && (*arg1) && (arg2) && (*arg2)) - { - strcat(filename, arg1); - -#ifndef __linux__ - strcat(filename, "\\"); -#else - strcat(filename, "/"); -#endif - - strcat(filename, arg2); - } - else if ((arg1) && (*arg1)) - { - strcat(filename, arg1); - } - - printf("UTIL_BuildFileName:"); - printf(filename); - printf("\n"); -} - -//========================================================= -// UTIL_LogPrintf - Prints a logged message to console. -// Preceded by LOG: ( timestamp ) < message > -//========================================================= -void UTIL_LogPrintf( char *fmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start ( argptr, fmt ); - vsprintf ( string, fmt, argptr ); - va_end ( argptr ); - - // Print to server console - printf("UTIL_LogPrintf:"); - printf(string); - printf("\n"); - ALERT( at_logged, "%s", string ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// util.cpp +// + +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "HPB_bot/engine/engine.h" +#include "dlls/cbase.h" +#include "dlls/player.h" + +#include "bot.h" +#include "bot_func.h" + + +extern int mod_id; +extern bot_t bots[32]; +extern edict_t *pent_info_ctfdetect; +extern char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; +extern int num_teams; + +int gmsgTextMsg = 0; +int gmsgSayText = 0; +int gmsgShowMenu = 0; + + +Vector UTIL_VecToAngles( const Vector &vec ) +{ + float rgflVecOut[3]; + VEC_TO_ANGLES(vec, rgflVecOut); + return Vector(rgflVecOut); +} + + +// Overloaded to add IGNORE_GLASS +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) +{ + TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); +} + + +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); +} + + +void UTIL_MakeVectors( const Vector &vecAngles ) +{ + MAKE_VECTORS( vecAngles ); +} + + +edict_t *UTIL_FindEntityInSphere( edict_t *pentStart, const Vector &vecCenter, float flRadius ) +{ + edict_t *pentEntity; + + pentEntity = FIND_ENTITY_IN_SPHERE( pentStart, vecCenter, flRadius); + + if (!FNullEnt(pentEntity)) + return pentEntity; + + return NULL; +} + + +edict_t *UTIL_FindEntityByString( edict_t *pentStart, const char *szKeyword, const char *szValue ) +{ + edict_t *pentEntity; + + pentEntity = FIND_ENTITY_BY_STRING( pentStart, szKeyword, szValue ); + + if (!FNullEnt(pentEntity)) + return pentEntity; + return NULL; +} + +edict_t *UTIL_FindEntityByClassname( edict_t *pentStart, const char *szName ) +{ + return UTIL_FindEntityByString( pentStart, "classname", szName ); +} + +edict_t *UTIL_FindEntityByTargetname( edict_t *pentStart, const char *szName ) +{ + return UTIL_FindEntityByString( pentStart, "targetname", szName ); +} + + +int UTIL_PointContents( const Vector &vec ) +{ + return POINT_CONTENTS(vec); +} + + +void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) +{ + SET_SIZE( ENT(pev), vecMin, vecMax ); +} + + +void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) +{ + SET_ORIGIN(ENT(pev), vecOrigin ); +} + + +void ClientPrint( edict_t *pEntity, int msg_dest, const char *msg_name) +{ +// if (gmsgTextMsg == 0) +// gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); +// +// pfnMessageBegin( MSG_ONE, gmsgTextMsg, NULL, pEntity ); +// +// pfnWriteByte( msg_dest ); +// pfnWriteString( msg_name ); +// pfnMessageEnd(); +} + +void UTIL_SayText( const char *pText, edict_t *pEdict ) +{ +// if (gmsgSayText == 0) +// gmsgSayText = REG_USER_MSG( "SayText", -1 ); +// +// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, pEdict ); +// pfnWriteByte( ENTINDEX(pEdict) ); +// if (mod_id == FRONTLINE_DLL) +// pfnWriteShort(0); +// pfnWriteString( pText ); +// pfnMessageEnd(); +} + + +void UTIL_HostSay( edict_t *pEntity, int teamonly, char *message ) +{ +// int j; +// char text[128]; +// char *pc; +// int sender_team, player_team; +// edict_t *client; +// +// // make sure the text has content +// for ( pc = message; pc != NULL && *pc != 0; pc++ ) +// { +// if ( isprint( *pc ) && !isspace( *pc ) ) +// { +// pc = NULL; // we've found an alphanumeric character, so text is valid +// break; +// } +// } +// +// if ( pc != NULL ) +// return; // no character found, so say nothing +// +// // turn on color set 2 (color on, no sound) +// if ( teamonly ) +// sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); +// else +// sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); +// +// j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator +// if ( (int)strlen(message) > j ) +// message[j] = 0; +// +// strcat( text, message ); +// strcat( text, "\n" ); +// +// // loop through all players +// // Start with the first player. +// // This may return the world in single player if the client types something between levels or during spawn +// // so check it, or it will infinite loop +// +// if (gmsgSayText == 0) +// gmsgSayText = REG_USER_MSG( "SayText", -1 ); +// +// sender_team = UTIL_GetTeam(pEntity); +// +// client = NULL; +// while ( ((client = UTIL_FindEntityByClassname( client, "player" )) != NULL) && +// (!FNullEnt(client)) ) +// { +// if ( client == pEntity ) // skip sender of message +// continue; +// +// player_team = UTIL_GetTeam(client); +// +// if ( teamonly && (sender_team != player_team) ) +// continue; +// +// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, client ); +// pfnWriteByte( ENTINDEX(pEntity) ); +// if (mod_id == FRONTLINE_DLL) +// pfnWriteShort(0); +// pfnWriteString( text ); +// pfnMessageEnd(); +// } +// +// // print to the sending client +// pfnMessageBegin( MSG_ONE, gmsgSayText, NULL, pEntity ); +// pfnWriteByte( ENTINDEX(pEntity) ); +// if (mod_id == FRONTLINE_DLL) +// pfnWriteShort(0); +// pfnWriteString( text ); +// pfnMessageEnd(); +// +// // echo to server console +// g_engfuncs.pfnServerPrint( text ); +} + + +#ifdef DEBUG +edict_t *DBG_EntOfVars( const entvars_t *pev ) +{ + if (pev->pContainingEntity != NULL) + return pev->pContainingEntity; + ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); + edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); + if (pent == NULL) + ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); + ((entvars_t *)pev)->pContainingEntity = pent; + return pent; +} +#endif //DEBUG + + +// return team number 0 through 3 based what MOD uses for team numbers +int UTIL_GetTeam(edict_t *pEntity) +{ + if (mod_id == TFC_DLL) + { + return pEntity->v.team - 1; // TFC teams are 1-4 based + } + else if (mod_id == CSTRIKE_DLL) + { + char *infobuffer; + char model_name[32]; + + infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); + strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); + + if ((strcmp(model_name, "terror") == 0) || // Phoenix Connektion + (strcmp(model_name, "arab") == 0) || // old L337 Krew + (strcmp(model_name, "leet") == 0) || // L337 Krew + (strcmp(model_name, "artic") == 0) || // Artic Avenger + (strcmp(model_name, "guerilla") == 0)) // Gorilla Warfare + { + return 0; + } + else if ((strcmp(model_name, "urban") == 0) || // Seal Team 6 + (strcmp(model_name, "gsg9") == 0) || // German GSG-9 + (strcmp(model_name, "sas") == 0) || // UK SAS + (strcmp(model_name, "gign") == 0) || // French GIGN + (strcmp(model_name, "vip") == 0)) // VIP + { + return 1; + } + + return 0; // return zero if team is unknown + } + else if ((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect != NULL)) + { + // OpFor CTF map... + + char *infobuffer; + char model_name[32]; + + infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); + strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); + + if ((strcmp(model_name, "ctf_barney") == 0) || + (strcmp(model_name, "cl_suit") == 0) || + (strcmp(model_name, "ctf_gina") == 0) || + (strcmp(model_name, "ctf_gordon") == 0) || + (strcmp(model_name, "otis") == 0) || + (strcmp(model_name, "ctf_scientist") == 0)) + { + return 0; + } + else if ((strcmp(model_name, "beret") == 0) || + (strcmp(model_name, "drill") == 0) || + (strcmp(model_name, "grunt") == 0) || + (strcmp(model_name, "recruit") == 0) || + (strcmp(model_name, "shephard") == 0) || + (strcmp(model_name, "tower") == 0)) + { + return 1; + } + + return 0; // return zero if team is unknown + } + else if (mod_id == FRONTLINE_DLL) + { + return pEntity->v.team - 1; // Front Line Force teams are 1-4 based + } + else if(mod_id == AVH_DLL) + { + return pEntity->v.team; + } + else // must be HL or OpFor deathmatch... + { + char *infobuffer; + char model_name[32]; + + if (team_names[0][0] == 0) + { + char *pName; + char teamlist[MAX_TEAMS*MAX_TEAMNAME_LENGTH]; + int i; + + num_teams = 0; + strcpy(teamlist, CVAR_GET_STRING("mp_teamlist")); + pName = teamlist; + pName = strtok(pName, ";"); + + while (pName != NULL && *pName) + { + // check that team isn't defined twice + for (i=0; i < num_teams; i++) + if (strcmp(pName, team_names[i]) == 0) + break; + if (i == num_teams) + { + strcpy(team_names[num_teams], pName); + num_teams++; + } + pName = strtok(NULL, ";"); + } + } + + infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); + strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); + + for (int index=0; index < num_teams; index++) + { + if (strcmp(model_name, team_names[index]) == 0) + return index; + } + + return 0; + } +} + + +// return class number 0 through N +int UTIL_GetClass(edict_t *pEntity) +{ + char *infobuffer; + char model_name[32]; + + infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)( pEntity ); + strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model"))); + + if (mod_id == FRONTLINE_DLL) + { + if ((strcmp(model_name, "natorecon") == 0) || + (strcmp(model_name, "axisrecon") == 0)) + { + return 0; // recon + } + else if ((strcmp(model_name, "natoassault") == 0) || + (strcmp(model_name, "axisassault") == 0)) + { + return 1; // assault + } + else if ((strcmp(model_name, "natosupport") == 0) || + (strcmp(model_name, "axissupport") == 0)) + { + return 2; // support + } + } + + return 0; +} + + +int UTIL_GetBotIndex(edict_t *pEdict) +{ + int index; + + for (index=0; index < 32; index++) + { + if (bots[index].pEdict == pEdict) + { + return index; + } + } + + return -1; // return -1 if edict is not a bot +} + + +bot_t *UTIL_GetBotPointer(edict_t *pEdict) +{ + int index; + + for (index=0; index < 32; index++) + { + if (bots[index].pEdict == pEdict) + { + break; + } + } + + if (index < 32) + return (&bots[index]); + + return NULL; // return NULL if edict is not a bot +} + + +bool IsAlive(edict_t *pEdict) +{ + return ((pEdict->v.deadflag == DEAD_NO) && + (pEdict->v.health > 0) && !(pEdict->v.flags & FL_NOTARGET)); +} + + +bool FInViewCone(Vector *pOrigin, edict_t *pEdict) +{ + Vector2D vec2LOS; + float flDot; + + UTIL_MakeVectors ( pEdict->v.angles ); + + vec2LOS = ( *pOrigin - pEdict->v.origin ).Make2D(); + vec2LOS = vec2LOS.Normalize(); + + flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + + if ( flDot > 0.50 ) // 60 degree field of view + { + return TRUE; + } + else + { + return FALSE; + } +} + + +bool FVisible( const Vector &vecOrigin, edict_t *pEdict ) +{ + TraceResult tr; + Vector vecLookerOrigin; + + // look through caller's eyes + vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs; + + int bInWater = (UTIL_PointContents (vecOrigin) == CONTENTS_WATER); + int bLookerInWater = (UTIL_PointContents (vecLookerOrigin) == CONTENTS_WATER); + + // don't look through water + if (bInWater != bLookerInWater) + return FALSE; + + UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, pEdict, &tr); + + if (tr.flFraction != 1.0) + { + return FALSE; // Line of sight is not established + } + else + { + return TRUE; // line of sight is valid. + } +} + + +Vector GetGunPosition(edict_t *pEdict) +{ + return (pEdict->v.origin + pEdict->v.view_ofs); +} + + +void UTIL_SelectItem(edict_t *pEdict, char *item_name) +{ + FakeClientCommand(pEdict, item_name, NULL, NULL); +} + + +Vector VecBModelOrigin(edict_t *pEdict) +{ + return pEdict->v.absmin + (pEdict->v.size * 0.5); +} + + +bool UpdateSounds(edict_t *pEdict, edict_t *pPlayer) +{ + float distance; + static bool check_footstep_sounds = TRUE; + static float footstep_sounds_on; + float sensitivity = 1.0; + float volume; + + // update sounds made by this player, alert bots if they are nearby... + + if (check_footstep_sounds) + { + check_footstep_sounds = FALSE; + footstep_sounds_on = CVAR_GET_FLOAT("mp_footsteps"); + } + + if (footstep_sounds_on > 0.0) + { + CBasePlayer* thePlayer = (CBasePlayer*)CBaseEntity::Instance(pPlayer); + + // check if this player is moving fast enough to make sounds... + if (pPlayer->v.velocity.Length2D() > thePlayer->GetMaxWalkSpeed()) + { + volume = 500.0; // volume of sound being made (just pick something) + + Vector v_sound = pPlayer->v.origin - pEdict->v.origin; + + distance = v_sound.Length(); + + // is the bot close enough to hear this sound? + if (distance < (volume * sensitivity)) + { + Vector bot_angles = UTIL_VecToAngles( v_sound ); + + pEdict->v.ideal_yaw = bot_angles.y; + + BotFixIdealYaw(pEdict); + + return TRUE; + } + } + } + + return FALSE; +} + + +void UTIL_ShowMenu( edict_t *pEdict, int slots, int displaytime, bool needmore, char *pText ) +{ +// if (gmsgShowMenu == 0) +// gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 ); +// +// pfnMessageBegin( MSG_ONE, gmsgShowMenu, NULL, pEdict ); +// +// pfnWriteShort( slots ); +// pfnWriteChar( displaytime ); +// pfnWriteByte( needmore ); +// pfnWriteString( pText ); +// +// pfnMessageEnd(); +} + +void UTIL_BuildFileName(char *filename, char *arg1, char *arg2) +{ + + if (mod_id == VALVE_DLL) +#ifndef __linux__ + strcpy(filename, "valve\\"); +#else + strcpy(filename, "valve/"); +#endif + + else if (mod_id == TFC_DLL) +#ifndef __linux__ + strcpy(filename, "tfc\\"); +#else + strcpy(filename, "tfc/"); +#endif + + else if (mod_id == CSTRIKE_DLL) +#ifndef __linux__ + strcpy(filename, "cstrike\\"); +#else + strcpy(filename, "cstrike/"); +#endif + + else if (mod_id == GEARBOX_DLL) +#ifndef __linux__ + strcpy(filename, "gearbox\\"); +#else + strcpy(filename, "gearbox/"); +#endif + + else if (mod_id == FRONTLINE_DLL) +#ifndef __linux__ + strcpy(filename, "frontline\\"); +#else + strcpy(filename, "frontline/"); +#endif + + else if (mod_id == AVH_DLL) + { + string filenameString = string(getModDirectory()); +#ifndef __linux__ + filenameString += "\\"; +#else + filenameString += '/'; +#endif + strcpy(filename,filenameString.c_str()); + } + else + { + filename[0] = 0; + return; + } + + if ((arg1) && (*arg1) && (arg2) && (*arg2)) + { + strcat(filename, arg1); + +#ifndef __linux__ + strcat(filename, "\\"); +#else + strcat(filename, "/"); +#endif + + strcat(filename, arg2); + } + else if ((arg1) && (*arg1)) + { + strcat(filename, arg1); + } + + printf("UTIL_BuildFileName:"); + printf(filename); + printf("\n"); +} + +//========================================================= +// UTIL_LogPrintf - Prints a logged message to console. +// Preceded by LOG: ( timestamp ) < message > +//========================================================= +void UTIL_LogPrintf( char *fmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start ( argptr, fmt ); + vsprintf ( string, fmt, argptr ); + va_end ( argptr ); + + // Print to server console + printf("UTIL_LogPrintf:"); + printf(string); + printf("\n"); + ALERT( at_logged, "%s", string ); +} + diff --git a/main/source/HPB_bot/dlls/waypoint.cpp b/main/source/HPB_bot/dlls/waypoint.cpp index 5eb2c8de..d99a9520 100644 --- a/main/source/HPB_bot/dlls/waypoint.cpp +++ b/main/source/HPB_bot/dlls/waypoint.cpp @@ -1,1938 +1,1938 @@ -// HPB bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// waypoint.cpp -// - -#ifndef __linux__ -#include -#endif -#include -#ifndef __linux__ -#include -#else -#include -#endif - -#include "dlls/extdll.h" -#include "dlls/enginecallback.h" -#include "dlls/util.h" -#include "dlls/cbase.h" - -#include "bot.h" -#include "waypoint.h" -//#include "mod/NetworkMeter.h" - -extern int mod_id; -extern int m_spriteTexture; - -// waypoints with information bits (flags) -WAYPOINT waypoints[MAX_WAYPOINTS]; - -// number of waypoints currently in use -int num_waypoints; - -// declare the array of head pointers to the path structures... -PATH *paths[MAX_WAYPOINTS]; - -// time that this waypoint was displayed (while editing) -float wp_display_time[MAX_WAYPOINTS]; - -bool g_waypoint_paths = FALSE; // have any paths been allocated? -bool g_waypoint_on = FALSE; -bool g_auto_waypoint = FALSE; -bool g_path_waypoint = FALSE; -Vector last_waypoint; -float f_path_time = 0.0; - -unsigned int route_num_waypoints; -unsigned short *shortest_path[4] = {NULL, NULL, NULL, NULL}; -unsigned short *from_to[4] = {NULL, NULL, NULL, NULL}; - -static FILE *fp; - - -void WaypointDebug(void) -{ - int y = 1, x = 1; - - fp=fopen("bot.txt","a"); - fprintf(fp,"WaypointDebug: LINKED LIST ERROR!!!\n"); - fclose(fp); - - x = x - 1; // x is zero - y = y / x; // cause an divide by zero exception - - return; -} - - -// free the linked list of waypoint path nodes... -void WaypointFree(void) -{ - for (int i=0; i < MAX_WAYPOINTS; i++) - { - int count = 0; - - if (paths[i]) - { - PATH *p = paths[i]; - PATH *p_next; - - while (p) // free the linked list - { - p_next = p->next; // save the link to next - free(p); - p = p_next; - -#ifdef _DEBUG - count++; - if (count > 1000) WaypointDebug(); -#endif - } - - paths[i] = NULL; - } - } -} - - -// initialize the waypoint structures... -void WaypointInit(void) -{ - int i; - - // have any waypoint path nodes been allocated yet? - if (g_waypoint_paths) - WaypointFree(); // must free previously allocated path memory - - for (i=0; i < 4; i++) - { - if (shortest_path[i] != NULL) - free(shortest_path[i]); - - if (from_to[i] != NULL) - free(from_to[i]); - } - - for (i=0; i < MAX_WAYPOINTS; i++) - { - waypoints[i].flags = 0; - waypoints[i].origin = Vector(0,0,0); - - wp_display_time[i] = 0.0; - - paths[i] = NULL; // no paths allocated yet - } - - f_path_time = 0.0; // reset waypoint path display time - - num_waypoints = 0; - - last_waypoint = Vector(0,0,0); - - for (i=0; i < 4; i++) - { - shortest_path[i] = NULL; - from_to[i] = NULL; - } -} - - -// add a path from one waypoint (add_index) to another (path_index)... -void WaypointAddPath(short int add_index, short int path_index) -{ - PATH *p, *prev; - int i; - int count = 0; - - p = paths[add_index]; - prev = NULL; - - // find an empty slot for new path_index... - while (p != NULL) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] == -1) - { - p->index[i] = path_index; - - return; - } - - i++; - } - - prev = p; // save the previous node in linked list - p = p->next; // go to next node in linked list - -#ifdef _DEBUG - count++; - if (count > 100) WaypointDebug(); -#endif - } - - p = (PATH *)malloc(sizeof(PATH)); - - if (p == NULL) - { - ALERT(at_error, "HPB_bot - Error allocating memory for path!"); - } - - p->index[0] = path_index; - p->index[1] = -1; - p->index[2] = -1; - p->index[3] = -1; - p->next = NULL; - - if (prev != NULL) - prev->next = p; // link new node into existing list - - if (paths[add_index] == NULL) - paths[add_index] = p; // save head point if necessary -} - - -// delete all paths to this waypoint index... -void WaypointDeletePath(short int del_index) -{ - PATH *p; - int index, i; - - // search all paths for this index... - for (index=0; index < num_waypoints; index++) - { - p = paths[index]; - - int count = 0; - - // search linked list for del_index... - while (p != NULL) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] == del_index) - { - p->index[i] = -1; // unassign this path - } - - i++; - } - - p = p->next; // go to next node in linked list - -#ifdef _DEBUG - count++; - if (count > 100) WaypointDebug(); -#endif - } - } -} - - -// delete a path from a waypoint (path_index) to another waypoint -// (del_index)... -void WaypointDeletePath(short int path_index, short int del_index) -{ - PATH *p; - int i; - int count = 0; - - p = paths[path_index]; - - // search linked list for del_index... - while (p != NULL) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] == del_index) - { - p->index[i] = -1; // unassign this path - } - - i++; - } - - p = p->next; // go to next node in linked list - -#ifdef _DEBUG - count++; - if (count > 100) WaypointDebug(); -#endif - } -} - - -// find a path from the current waypoint. (pPath MUST be NULL on the -// initial call. subsequent calls will return other paths if they exist.) -int WaypointFindPath(PATH **pPath, int *path_index, int waypoint_index, int team) -{ - int index; - int count = 0; - - if (*pPath == NULL) - { - *pPath = paths[waypoint_index]; - *path_index = 0; - } - - if (*path_index == MAX_PATH_INDEX) - { - *path_index = 0; - - *pPath = (*pPath)->next; // go to next node in linked list - } - - while (*pPath != NULL) - { - while (*path_index < MAX_PATH_INDEX) - { - if ((*pPath)->index[*path_index] != -1) // found a path? - { - // save the return value - index = (*pPath)->index[*path_index]; - - // skip this path if next waypoint is team specific and NOT this team - if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[index].flags & W_FL_TEAM) != team)) - { - (*path_index)++; - continue; - } - - // set up stuff for subsequent calls... - (*path_index)++; - - return index; - } - - (*path_index)++; - } - - *path_index = 0; - - *pPath = (*pPath)->next; // go to next node in linked list - -#ifdef _DEBUG - count++; - if (count > 100) WaypointDebug(); -#endif - } - - return -1; -} - - -// find the nearest waypoint to the player and return the index -// (-1 if not found)... -int WaypointFindNearest(edict_t *pEntity, float range, int team) -{ - int i, min_index; - float distance; - float min_distance; - TraceResult tr; - - if (num_waypoints < 1) - return -1; - - // find the nearest waypoint... - - min_index = -1; - min_distance = 9999.0; - - for (i=0; i < num_waypoints; i++) - { - if (waypoints[i].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[i].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[i].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[i].flags & W_FL_TEAM) != team)) - continue; - - distance = (waypoints[i].origin - pEntity->v.origin).Length(); - - if ((distance < min_distance) && (distance < range)) - { - // if waypoint is visible from current position (even behind head)... - UTIL_TraceLine( pEntity->v.origin + pEntity->v.view_ofs, waypoints[i].origin, - ignore_monsters, pEntity->v.pContainingEntity, &tr ); - - if (tr.flFraction >= 1.0) - { - min_index = i; - min_distance = distance; - } - } - } - - return min_index; -} - - -// find the nearest waypoint to the source postition and return the index -// of that waypoint... -int WaypointFindNearest(Vector v_src, edict_t *pEntity, float range, int team) -{ - int index, min_index; - float distance; - float min_distance; - TraceResult tr; - - if (num_waypoints < 1) - return -1; - - // find the nearest waypoint... - - min_index = -1; - min_distance = 9999.0; - - for (index=0; index < num_waypoints; index++) - { - if (waypoints[index].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[index].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[index].flags & W_FL_TEAM) != team)) - continue; - - distance = (waypoints[index].origin - v_src).Length(); - - if ((distance < min_distance) && (distance < range)) - { - // if waypoint is visible from source position... - UTIL_TraceLine( v_src, waypoints[index].origin, ignore_monsters, - pEntity->v.pContainingEntity, &tr ); - - if (tr.flFraction >= 1.0) - { - min_index = index; - min_distance = distance; - } - } - } - - return min_index; -} - - -// find the goal nearest to the player matching the "flags" bits and return -// the index of that waypoint... -int WaypointFindNearestGoal(edict_t *pEntity, int src, int team, int flags) -{ - int index, min_index; - int distance, min_distance; - - if (num_waypoints < 1) - return -1; - - // find the nearest waypoint with the matching flags... - - min_index = -1; - min_distance = 99999; - - for (index=0; index < num_waypoints; index++) - { - if (index == src) - continue; // skip the source waypoint - - if (waypoints[index].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[index].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[index].flags & W_FL_TEAM) != team)) - continue; - - if ((waypoints[index].flags & flags) != flags) - continue; // skip this waypoint if the flags don't match - - distance = WaypointDistanceFromTo(src, index, team); - - if (distance < min_distance) - { - min_index = index; - min_distance = distance; - } - } - - return min_index; -} - - -// find the goal nearest to the source position (v_src) matching the "flags" -// bits and return the index of that waypoint... -int WaypointFindNearestGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags) -{ - int index, min_index; - int distance, min_distance; - - if (num_waypoints < 1) - return -1; - - // find the nearest waypoint with the matching flags... - - min_index = -1; - min_distance = 99999; - - for (index=0; index < num_waypoints; index++) - { - if (waypoints[index].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[index].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[index].flags & W_FL_TEAM) != team)) - continue; - - if ((waypoints[index].flags & flags) != flags) - continue; // skip this waypoint if the flags don't match - - distance = (waypoints[index].origin - v_src).Length(); - - if ((distance < range) && (distance < min_distance)) - { - min_index = index; - min_distance = distance; - } - } - - return min_index; -} - - -// find a random goal matching the "flags" bits and return the index of -// that waypoint... -int WaypointFindRandomGoal(edict_t *pEntity, int team, int flags) -{ - int index; - int indexes[50]; - int count = 0; - - if (num_waypoints < 1) - return -1; - - // find all the waypoints with the matching flags... - - for (index=0; index < num_waypoints; index++) - { - if (waypoints[index].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[index].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[index].flags & W_FL_TEAM) != team)) - continue; - - if ((waypoints[index].flags & flags) != flags) - continue; // skip this waypoint if the flags don't match - - if (count < 50) - { - indexes[count] = index; - - count++; - } - } - - if (count == 0) // no matching waypoints found - return -1; - - index = RANDOM_LONG(1, count) - 1; - - return indexes[index]; -} - - -// find a random goal within a range of a position (v_src) matching the -// "flags" bits and return the index of that waypoint... -int WaypointFindRandomGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags) -{ - int index; - int indexes[50]; - int count = 0; - float distance; - - if (num_waypoints < 1) - return -1; - - // find all the waypoints with the matching flags... - - for (index=0; index < num_waypoints; index++) - { - if (waypoints[index].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[index].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[index].flags & W_FL_TEAM) != team)) - continue; - - if ((waypoints[index].flags & flags) != flags) - continue; // skip this waypoint if the flags don't match - - distance = (waypoints[index].origin - v_src).Length(); - - if ((distance < range) && (count < 50)) - { - indexes[count] = index; - - count++; - } - } - - if (count == 0) // no matching waypoints found - return -1; - - index = RANDOM_LONG(1, count) - 1; - - return indexes[index]; -} - - -// find the nearest "special" aiming waypoint (for sniper aiming)... -int WaypointFindNearestAiming(Vector v_origin) -{ - int index; - int min_index = -1; - int min_distance = 9999.0; - float distance; - - if (num_waypoints < 1) - return -1; - - // search for nearby aiming waypoint... - for (index=0; index < num_waypoints; index++) - { - if (waypoints[index].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if ((waypoints[index].flags & W_FL_AIMING) == 0) - continue; // skip any NON aiming waypoints - - distance = (v_origin - waypoints[index].origin).Length(); - - if ((distance < min_distance) && (distance < 40)) - { - min_index = index; - min_distance = distance; - } - } - - return min_index; -} - - -void WaypointDrawBeam(edict_t *pEntity, Vector start, Vector end, int width, - int noise, int red, int green, int blue, int brightness, int speed) -{ -// MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); -// WRITE_BYTE( TE_BEAMPOINTS); -// WRITE_COORD(start.x); -// WRITE_COORD(start.y); -// WRITE_COORD(start.z); -// WRITE_COORD(end.x); -// WRITE_COORD(end.y); -// WRITE_COORD(end.z); -// WRITE_SHORT( m_spriteTexture ); -// WRITE_BYTE( 1 ); // framestart -// WRITE_BYTE( 10 ); // framerate -// WRITE_BYTE( 10 ); // life in 0.1's -// WRITE_BYTE( width ); // width -// WRITE_BYTE( noise ); // noise -// -// WRITE_BYTE( red ); // r, g, b -// WRITE_BYTE( green ); // r, g, b -// WRITE_BYTE( blue ); // r, g, b -// -// WRITE_BYTE( brightness ); // brightness -// WRITE_BYTE( speed ); // speed -// MESSAGE_END(); -} - - -void WaypointAdd(edict_t *pEntity) -{ - int index; - edict_t *pent = NULL; - float radius = 40; - char item_name[64]; - - if (num_waypoints >= MAX_WAYPOINTS) - return; - - index = 0; - - // find the next available slot for the new waypoint... - while (index < num_waypoints) - { - if (waypoints[index].flags & W_FL_DELETED) - break; - - index++; - } - - waypoints[index].flags = 0; - - // store the origin (location) of this waypoint (use entity origin) - waypoints[index].origin = pEntity->v.origin; - - // store the last used waypoint for the auto waypoint code... - last_waypoint = pEntity->v.origin; - - // set the time that this waypoint was originally displayed... - wp_display_time[index] = gpGlobals->time; - - - Vector start, end; - - start = pEntity->v.origin - Vector(0, 0, 34); - end = start + Vector(0, 0, 68); - - if ((pEntity->v.flags & FL_DUCKING) == FL_DUCKING) - { - waypoints[index].flags |= W_FL_CROUCH; // crouching waypoint - - start = pEntity->v.origin - Vector(0, 0, 17); - end = start + Vector(0, 0, 34); - } - - if (pEntity->v.movetype == MOVETYPE_FLY) - waypoints[index].flags |= W_FL_LADDER; // waypoint on a ladder - - - //******************************************************** - // look for lift, ammo, flag, health, armor, etc. - //******************************************************** - - while ((pent = UTIL_FindEntityInSphere( pent, pEntity->v.origin, radius )) != NULL) - { - strcpy(item_name, STRING(pent->v.classname)); - - if (strcmp("item_healthkit", item_name) == 0) - { - ClientPrint(pEntity, HUD_PRINTCONSOLE, "found a healthkit!\n"); - waypoints[index].flags = W_FL_HEALTH; - } - - if (strncmp("item_armor", item_name, 10) == 0) - { - ClientPrint(pEntity, HUD_PRINTCONSOLE, "found some armor!\n"); - waypoints[index].flags = W_FL_ARMOR; - } - - // ************* - // LOOK FOR AMMO - // ************* - - } - - // draw a blue waypoint - WaypointDrawBeam(pEntity, start, end, 30, 0, 0, 0, 255, 250, 5); - - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "weapons/xbow_hit1.wav", 1.0, - ATTN_NORM, 0, 100); - - // increment total number of waypoints if adding at end of array... - if (index == num_waypoints) - num_waypoints++; - - // calculate all the paths to this new waypoint - for (int i=0; i < num_waypoints; i++) - { - if (i == index) - continue; // skip the waypoint that was just added - - if (waypoints[i].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // check if the waypoint is reachable from the new one (one-way) - if ( WaypointReachable(pEntity->v.origin, waypoints[i].origin, pEntity) ) - { - WaypointAddPath(index, i); - } - - // check if the new one is reachable from the waypoint (other way) - if ( WaypointReachable(waypoints[i].origin, pEntity->v.origin, pEntity) ) - { - WaypointAddPath(i, index); - } - } -} - - -void WaypointAddAiming(edict_t *pEntity) -{ - int index; - edict_t *pent = NULL; - - if (num_waypoints >= MAX_WAYPOINTS) - return; - - index = 0; - - // find the next available slot for the new waypoint... - while (index < num_waypoints) - { - if (waypoints[index].flags & W_FL_DELETED) - break; - - index++; - } - - waypoints[index].flags = W_FL_AIMING; // aiming waypoint - - Vector v_angle = pEntity->v.v_angle; - - v_angle.x = 0; // reset pitch to horizontal - v_angle.z = 0; // reset roll to level - - UTIL_MakeVectors(v_angle); - - // store the origin (location) of this waypoint (use entity origin) - waypoints[index].origin = pEntity->v.origin + gpGlobals->v_forward * 25; - - // set the time that this waypoint was originally displayed... - wp_display_time[index] = gpGlobals->time; - - - Vector start, end; - - start = pEntity->v.origin - Vector(0, 0, 10); - end = start + Vector(0, 0, 14); - - // draw a blue waypoint - WaypointDrawBeam(pEntity, start, end, 30, 0, 0, 0, 255, 250, 5); - - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "weapons/xbow_hit1.wav", 1.0, - ATTN_NORM, 0, 100); - - // increment total number of waypoints if adding at end of array... - if (index == num_waypoints) - num_waypoints++; -} - - -void WaypointDelete(edict_t *pEntity) -{ - int index; - int count = 0; - - if (num_waypoints < 1) - return; - - index = WaypointFindNearest(pEntity, 50.0, -1); - - if (index == -1) - return; - - if ((waypoints[index].flags & W_FL_SNIPER) || - ((mod_id == FRONTLINE_DLL) && (waypoints[index].flags & W_FL_FLF_DEFEND))) - { - int i; - int min_index = -1; - int min_distance = 9999.0; - float distance; - - // search for nearby aiming waypoint and delete it also... - for (i=0; i < num_waypoints; i++) - { - if (waypoints[i].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if ((waypoints[i].flags & W_FL_AIMING) == 0) - continue; // skip any NON aiming waypoints - - distance = (waypoints[i].origin - waypoints[index].origin).Length(); - - if ((distance < min_distance) && (distance < 40)) - { - min_index = i; - min_distance = distance; - } - } - - if (min_index != -1) - { - waypoints[min_index].flags = W_FL_DELETED; // not being used - waypoints[min_index].origin = Vector(0,0,0); - - wp_display_time[min_index] = 0.0; - } - } - - // delete any paths that lead to this index... - WaypointDeletePath(index); - - // free the path for this index... - - if (paths[index] != NULL) - { - PATH *p = paths[index]; - PATH *p_next; - - while (p) // free the linked list - { - p_next = p->next; // save the link to next - free(p); - p = p_next; - -#ifdef _DEBUG - count++; - if (count > 100) WaypointDebug(); -#endif - } - - paths[index] = NULL; - } - - waypoints[index].flags = W_FL_DELETED; // not being used - waypoints[index].origin = Vector(0,0,0); - - wp_display_time[index] = 0.0; - - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "weapons/mine_activate.wav", 1.0, - ATTN_NORM, 0, 100); -} - - -// allow player to manually create a path from one waypoint to another -void WaypointCreatePath(edict_t *pEntity, int cmd) -{ - static int waypoint1 = -1; // initialized to unassigned - static int waypoint2 = -1; // initialized to unassigned - - if (cmd == 1) // assign source of path - { - waypoint1 = WaypointFindNearest(pEntity, 50.0, -1); - - if (waypoint1 == -1) - { - // play "cancelled" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_moveselect.wav", 1.0, - ATTN_NORM, 0, 100); - - return; - } - - // play "start" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudoff.wav", 1.0, - ATTN_NORM, 0, 100); - - return; - } - - if (cmd == 2) // assign dest of path and make path - { - waypoint2 = WaypointFindNearest(pEntity, 50.0, -1); - - if ((waypoint1 == -1) || (waypoint2 == -1)) - { - // play "error" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_denyselect.wav", 1.0, - ATTN_NORM, 0, 100); - - return; - } - - WaypointAddPath(waypoint1, waypoint2); - - // play "done" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudon.wav", 1.0, - ATTN_NORM, 0, 100); - } -} - - -// allow player to manually remove a path from one waypoint to another -void WaypointRemovePath(edict_t *pEntity, int cmd) -{ - static int waypoint1 = -1; // initialized to unassigned - static int waypoint2 = -1; // initialized to unassigned - - if (cmd == 1) // assign source of path - { - waypoint1 = WaypointFindNearest(pEntity, 50.0, -1); - - if (waypoint1 == -1) - { - // play "cancelled" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_moveselect.wav", 1.0, - ATTN_NORM, 0, 100); - - return; - } - - // play "start" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudoff.wav", 1.0, - ATTN_NORM, 0, 100); - - return; - } - - if (cmd == 2) // assign dest of path and make path - { - waypoint2 = WaypointFindNearest(pEntity, 50.0, -1); - - if ((waypoint1 == -1) || (waypoint2 == -1)) - { - // play "error" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_denyselect.wav", 1.0, - ATTN_NORM, 0, 100); - - return; - } - - WaypointDeletePath(waypoint1, waypoint2); - - // play "done" sound... - EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudon.wav", 1.0, - ATTN_NORM, 0, 100); - } -} - - -bool WaypointLoad(edict_t *pEntity) -{ - char mapname[64]; - char filename[256]; - WAYPOINT_HDR header; - char msg[80]; - int index, i; - short int num; - short int path_index; - - strcpy(mapname, STRING(gpGlobals->mapname)); - strcat(mapname, ".wpt"); - - UTIL_BuildFileName(filename, "maps", mapname); - - if (IS_DEDICATED_SERVER()) - printf("loading waypoint file: %s\n", filename); - - FILE *bfp = fopen(filename, "rb"); - - // if file exists, read the waypoint structure from it - if (bfp != NULL) - { - fread(&header, sizeof(header), 1, bfp); - - header.filetype[7] = 0; - if (strcmp(header.filetype, "HPB_bot") == 0) - { - if (header.waypoint_file_version != WAYPOINT_VERSION) - { - if (pEntity) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "Incompatible HPB bot waypoint file version!\nWaypoints not loaded!\n"); - - fclose(bfp); - return FALSE; - } - - header.mapname[31] = 0; - - if (strcmp(header.mapname, STRING(gpGlobals->mapname)) == 0) - { - WaypointInit(); // remove any existing waypoints - - for (i=0; i < header.number_of_waypoints; i++) - { - fread(&waypoints[i], sizeof(waypoints[0]), 1, bfp); - num_waypoints++; - } - - // read and add waypoint paths... - for (index=0; index < num_waypoints; index++) - { - // read the number of paths from this node... - fread(&num, sizeof(num), 1, bfp); - - for (i=0; i < num; i++) - { - fread(&path_index, sizeof(path_index), 1, bfp); - - WaypointAddPath(index, path_index); - } - } - - g_waypoint_paths = TRUE; // keep track so path can be freed - } - else - { - if (pEntity) - { - sprintf(msg, "%s HPB bot waypoints are not for this map!\n", filename); - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - } - - fclose(bfp); - return FALSE; - } - } - else - { - if (pEntity) - { - sprintf(msg, "%s is not a HPB bot waypoint file!\n", filename); - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - } - - fclose(bfp); - return FALSE; - } - - fclose(bfp); - - WaypointRouteInit(); - } - else - { - if (pEntity) - { - sprintf(msg, "Waypoint file %s does not exist!\n", filename); - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - } - - if (IS_DEDICATED_SERVER()) - printf("waypoint file %s not found!\n", filename); - - return FALSE; - } - - return TRUE; -} - - -void WaypointSave(void) -{ - char filename[256]; - char mapname[64]; - WAYPOINT_HDR header; - int index, i; - short int num; - PATH *p; - - strcpy(header.filetype, "HPB_bot"); - - header.waypoint_file_version = WAYPOINT_VERSION; - - header.waypoint_file_flags = 0; // not currently used - - header.number_of_waypoints = num_waypoints; - - memset(header.mapname, 0, sizeof(header.mapname)); - strncpy(header.mapname, STRING(gpGlobals->mapname), 31); - header.mapname[31] = 0; - - strcpy(mapname, STRING(gpGlobals->mapname)); - strcat(mapname, ".wpt"); - - UTIL_BuildFileName(filename, "maps", mapname); - - FILE *bfp = fopen(filename, "wb"); - - // write the waypoint header to the file... - fwrite(&header, sizeof(header), 1, bfp); - - // write the waypoint data to the file... - for (index=0; index < num_waypoints; index++) - { - fwrite(&waypoints[index], sizeof(waypoints[0]), 1, bfp); - } - - // save the waypoint paths... - for (index=0; index < num_waypoints; index++) - { - // count the number of paths from this node... - - p = paths[index]; - num = 0; - - while (p != NULL) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] != -1) - num++; // count path node if it's used - - i++; - } - - p = p->next; // go to next node in linked list - } - - fwrite(&num, sizeof(num), 1, bfp); // write the count - - // now write out each path index... - - p = paths[index]; - - while (p != NULL) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] != -1) // save path node if it's used - fwrite(&p->index[i], sizeof(p->index[0]), 1, bfp); - - i++; - } - - p = p->next; // go to next node in linked list - } - } - - fclose(bfp); -} - - -bool WaypointReachable(Vector v_src, Vector v_dest, edict_t *pEntity) -{ - TraceResult tr; - float curr_height, last_height; - - float distance = (v_dest - v_src).Length(); - - // is the destination close enough? - if (distance < REACHABLE_RANGE) - { - // check if this waypoint is "visible"... - - UTIL_TraceLine( v_src, v_dest, ignore_monsters, - pEntity->v.pContainingEntity, &tr ); - - // if waypoint is visible from current position (even behind head)... - if (tr.flFraction >= 1.0) - { - // check for special case of both waypoints being underwater... - if ((POINT_CONTENTS( v_src ) == CONTENTS_WATER) && - (POINT_CONTENTS( v_dest ) == CONTENTS_WATER)) - { - return TRUE; - } - - // check for special case of waypoint being suspended in mid-air... - - // is dest waypoint higher than src? (45 is max jump height) - if (v_dest.z > (v_src.z + 45.0)) - { - Vector v_new_src = v_dest; - Vector v_new_dest = v_dest; - - v_new_dest.z = v_new_dest.z - 50; // straight down 50 units - - UTIL_TraceLine(v_new_src, v_new_dest, dont_ignore_monsters, - pEntity->v.pContainingEntity, &tr); - - // check if we didn't hit anything, if not then it's in mid-air - if (tr.flFraction >= 1.0) - { - return FALSE; // can't reach this one - } - } - - // check if distance to ground increases more than jump height - // at points between source and destination... - - Vector v_direction = (v_dest - v_src).Normalize(); // 1 unit long - Vector v_check = v_src; - Vector v_down = v_src; - - v_down.z = v_down.z - 1000.0; // straight down 1000 units - - UTIL_TraceLine(v_check, v_down, ignore_monsters, - pEntity->v.pContainingEntity, &tr); - - last_height = tr.flFraction * 1000.0; // height from ground - - distance = (v_dest - v_check).Length(); // distance from goal - - while (distance > 10.0) - { - // move 10 units closer to the goal... - v_check = v_check + (v_direction * 10.0); - - v_down = v_check; - v_down.z = v_down.z - 1000.0; // straight down 1000 units - - UTIL_TraceLine(v_check, v_down, ignore_monsters, - pEntity->v.pContainingEntity, &tr); - - curr_height = tr.flFraction * 1000.0; // height from ground - - // is the difference in the last height and the current height - // higher that the jump height? - if ((last_height - curr_height) > 45.0) - { - // can't get there from here... - return FALSE; - } - - last_height = curr_height; - - distance = (v_dest - v_check).Length(); // distance from goal - } - - return TRUE; - } - } - - return FALSE; -} - - -// find the nearest reachable waypoint -int WaypointFindReachable(edict_t *pEntity, float range, int team) -{ - int i, min_index; - float distance; - float min_distance; - TraceResult tr; - - // find the nearest waypoint... - - min_distance = 9999.0; - - for (i=0; i < num_waypoints; i++) - { - if (waypoints[i].flags & W_FL_DELETED) - continue; // skip any deleted waypoints - - if (waypoints[i].flags & W_FL_AIMING) - continue; // skip any aiming waypoints - - // skip this waypoint if it's team specific and teams don't match... - if ((team != -1) && (waypoints[i].flags & W_FL_TEAM_SPECIFIC) && - ((waypoints[i].flags & W_FL_TEAM) != team)) - continue; - - distance = (waypoints[i].origin - pEntity->v.origin).Length(); - - if (distance < min_distance) - { - // if waypoint is visible from current position (even behind head)... - UTIL_TraceLine( pEntity->v.origin + pEntity->v.view_ofs, waypoints[i].origin, - ignore_monsters, pEntity->v.pContainingEntity, &tr ); - - if (tr.flFraction >= 1.0) - { - if (WaypointReachable(pEntity->v.origin, waypoints[i].origin, pEntity)) - { - min_index = i; - min_distance = distance; - } - } - } - } - - // if not close enough to a waypoint then just return - if (min_distance > range) - return -1; - - return min_index; - -} - - -void WaypointPrintInfo(edict_t *pEntity) -{ - char msg[80]; - int index; - int flags; - - // find the nearest waypoint... - index = WaypointFindNearest(pEntity, 50.0, -1); - - if (index == -1) - return; - - sprintf(msg,"Waypoint %d of %d total\n", index, num_waypoints); - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - - flags = waypoints[index].flags; - - if (flags & W_FL_TEAM_SPECIFIC) - { - if (mod_id == FRONTLINE_DLL) - { - if ((flags & W_FL_TEAM) == 0) - strcpy(msg, "Waypoint is for Attackers\n"); - else if ((flags & W_FL_TEAM) == 1) - strcpy(msg, "Waypoint is for Defenders\n"); - } - else - { - if ((flags & W_FL_TEAM) == 0) - strcpy(msg, "Waypoint is for TEAM 1\n"); - else if ((flags & W_FL_TEAM) == 1) - strcpy(msg, "Waypoint is for TEAM 2\n"); - else if ((flags & W_FL_TEAM) == 2) - strcpy(msg, "Waypoint is for TEAM 3\n"); - else if ((flags & W_FL_TEAM) == 3) - strcpy(msg, "Waypoint is for TEAM 4\n"); - } - - ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); - } - - if (flags & W_FL_LIFT) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "Bot will wait for lift before approaching\n"); - - if (flags & W_FL_LADDER) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "This waypoint is on a ladder\n"); - - if (flags & W_FL_DOOR) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "This is a door waypoint\n"); - - if (flags & W_FL_HEALTH) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is health near this waypoint\n"); - - if (flags & W_FL_ARMOR) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is armor near this waypoint\n"); - - if (flags & W_FL_AMMO) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is ammo near this waypoint\n"); - - if (flags & W_FL_SNIPER) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "This is a sniper waypoint\n"); - - if (flags & W_FL_TFC_FLAG) - { - if (mod_id == FRONTLINE_DLL) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is a capture point near this waypoint\n"); - else - ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is a flag near this waypoint\n"); - } - - if (flags & W_FL_TFC_FLAG_GOAL) - { - if (mod_id == FRONTLINE_DLL) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "This is a defender location\n"); - else - ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is a flag goal near this waypoint\n"); - } - - if (flags & W_FL_PRONE) - ClientPrint(pEntity, HUD_PRINTNOTIFY, "Bot will go prone here\n"); -} - - -void WaypointThink(edict_t *pEntity) -{ - float distance, min_distance; - Vector start, end; - int i, index; - - if (g_auto_waypoint) // is auto waypoint on? - { - // find the distance from the last used waypoint - distance = (last_waypoint - pEntity->v.origin).Length(); - - if (distance > 200) - { - min_distance = 9999.0; - - // check that no other reachable waypoints are nearby... - for (i=0; i < num_waypoints; i++) - { - if (waypoints[i].flags & W_FL_DELETED) - continue; - - if (waypoints[i].flags & W_FL_AIMING) - continue; - - if (WaypointReachable(pEntity->v.origin, waypoints[i].origin, pEntity)) - { - distance = (waypoints[i].origin - pEntity->v.origin).Length(); - - if (distance < min_distance) - min_distance = distance; - } - } - - // make sure nearest waypoint is far enough away... - if (min_distance >= 200) - WaypointAdd(pEntity); // place a waypoint here - } - } - - min_distance = 9999.0; - - if (g_waypoint_on) // display the waypoints if turned on... - { - for (i=0; i < num_waypoints; i++) - { - if ((waypoints[i].flags & W_FL_DELETED) == W_FL_DELETED) - continue; - - distance = (waypoints[i].origin - pEntity->v.origin).Length(); - - if (distance < 500) - { - if (distance < min_distance) - { - index = i; // store index of nearest waypoint - min_distance = distance; - } - - if ((wp_display_time[i] + 1.0) < gpGlobals->time) - { - if (waypoints[i].flags & W_FL_CROUCH) - { - start = waypoints[i].origin - Vector(0, 0, 17); - end = start + Vector(0, 0, 34); - } - else if (waypoints[i].flags & W_FL_AIMING) - { - start = waypoints[i].origin + Vector(0, 0, 10); - end = start + Vector(0, 0, 14); - } - else - { - start = waypoints[i].origin - Vector(0, 0, 34); - end = start + Vector(0, 0, 68); - } - - // draw a blue waypoint - WaypointDrawBeam(pEntity, start, end, 30, 0, 0, 0, 255, 250, 5); - - wp_display_time[i] = gpGlobals->time; - } - } - } - - // check if path waypointing is on... - if (g_path_waypoint) - { - // check if player is close enough to a waypoint and time to draw path... - if ((min_distance <= 50) && (f_path_time <= gpGlobals->time)) - { - PATH *p; - - f_path_time = gpGlobals->time + 1.0; - - p = paths[index]; - - while (p != NULL) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] != -1) - { - Vector v_src = waypoints[index].origin; - Vector v_dest = waypoints[p->index[i]].origin; - - // draw a white line to this index's waypoint - WaypointDrawBeam(pEntity, v_src, v_dest, 10, 2, 250, 250, 250, 200, 10); - } - - i++; - } - - p = p->next; // go to next node in linked list - } - } - } - } -} - - -// run Floyd's algorithm on the waypoint list to generate the least cost -// path matrix... -void WaypointFloyds(unsigned short *shortest_path, unsigned short *from_to) -{ - unsigned int x, y, z; - int changed = 1; - int distance; - - for (y=0; y < route_num_waypoints; y++) - { - for (z=0; z < route_num_waypoints; z++) - { - from_to[y * route_num_waypoints + z] = z; - } - } - - while (changed) - { - changed = 0; - - for (x=0; x < route_num_waypoints; x++) - { - for (y=0; y < route_num_waypoints; y++) - { - for (z=0; z < route_num_waypoints; z++) - { - if ((shortest_path[y * route_num_waypoints + x] == WAYPOINT_UNREACHABLE) || - (shortest_path[x * route_num_waypoints + z] == WAYPOINT_UNREACHABLE)) - continue; - - distance = shortest_path[y * route_num_waypoints + x] + - shortest_path[x * route_num_waypoints + z]; - - if (distance > WAYPOINT_MAX_DISTANCE) - distance = WAYPOINT_MAX_DISTANCE; - - if ((distance < shortest_path[y * route_num_waypoints + z]) || - (shortest_path[y * route_num_waypoints + z] == WAYPOINT_UNREACHABLE)) - { - shortest_path[y * route_num_waypoints + z] = distance; - from_to[y * route_num_waypoints + z] = from_to[y * route_num_waypoints + x]; - changed = 1; - } - } - } - } - } -} - - -// load the waypoint route files (.wp1, .wp2, etc.) or generate them if -// they don't exist... -void WaypointRouteInit(void) -{ - unsigned int index; - bool build_matrix[4]; - int matrix; - unsigned int array_size; - unsigned int row; - int i, offset; - unsigned int a, b; - float distance; - unsigned short *pShortestPath, *pFromTo; - char msg[80]; - unsigned int num_items; - FILE *bfp; - char filename[256]; - char filename2[256]; - char mapname[64]; - - if (num_waypoints == 0) - return; - - // save number of current waypoints in case waypoints get added later - route_num_waypoints = num_waypoints; - - strcpy(mapname, STRING(gpGlobals->mapname)); - strcat(mapname, ".wpt"); - - UTIL_BuildFileName(filename, "maps", mapname); - - build_matrix[0] = TRUE; // always build matrix 0 (non-team and team 1) - build_matrix[1] = FALSE; - build_matrix[2] = FALSE; - build_matrix[3] = FALSE; - - // find out how many route matrixes to create... - for (index=0; index < route_num_waypoints; index++) - { - if (waypoints[index].flags & W_FL_TEAM_SPECIFIC) - { - if ((waypoints[index].flags & W_FL_TEAM) == 0x01) // team 2? - build_matrix[1] = TRUE; - - if ((waypoints[index].flags & W_FL_TEAM) == 0x02) // team 3? - build_matrix[2] = TRUE; - - if ((waypoints[index].flags & W_FL_TEAM) == 0x03) // team 4? - build_matrix[3] = TRUE; - } - } - - array_size = route_num_waypoints * route_num_waypoints; - - for (matrix=0; matrix < 4; matrix++) - { - if (build_matrix[matrix]) - { - char ext_str[5]; // ".wpX\0" - int file1, file2; - struct stat stat1, stat2; - - sprintf(ext_str, ".wp%d", matrix+1); - - strcpy(mapname, STRING(gpGlobals->mapname)); - strcat(mapname, ext_str); - - UTIL_BuildFileName(filename2, "maps", mapname); - - if (access(filename2, 0) == 0) // does the .wpX file exist? - { - file1 = open(filename, O_RDONLY); - file2 = open(filename2, O_RDONLY); - - fstat(file1, &stat1); - fstat(file2, &stat2); - - close(file1); - close(file2); - - if (stat1.st_mtime < stat2.st_mtime) // is .wpt older than .wpX file? - { - sprintf(msg, "loading HPB bot waypoint paths for team %d\n", matrix+1); - ALERT(at_console, msg); - - shortest_path[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); - - if (shortest_path[matrix] == NULL) - ALERT(at_error, "HPB_bot - Error allocating memory for shortest path!"); - - from_to[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); - - if (from_to[matrix] == NULL) - ALERT(at_error, "HPB_bot - Error allocating memory for from to matrix!"); - - bfp = fopen(filename2, "rb"); - - if (bfp != NULL) - { - num_items = fread(shortest_path[matrix], sizeof(unsigned short), array_size, bfp); - - if (num_items != array_size) - { - // if couldn't read enough data, free memory to recalculate it - - ALERT(at_console, "error reading enough path items, recalculating...\n"); - - free(shortest_path[matrix]); - shortest_path[matrix] = NULL; - - free(from_to[matrix]); - from_to[matrix] = NULL; - } - else - { - num_items = fread(from_to[matrix], sizeof(unsigned short), array_size, bfp); - - if (num_items != array_size) - { - // if couldn't read enough data, free memory to recalculate it - - ALERT(at_console, "error reading enough path items, recalculating...\n"); - - free(shortest_path[matrix]); - shortest_path[matrix] = NULL; - - free(from_to[matrix]); - from_to[matrix] = NULL; - } - } - } - else - { - ALERT(at_console, "HPB_bot - Error reading waypoint paths!\n"); - - free(shortest_path[matrix]); - shortest_path[matrix] = NULL; - - free(from_to[matrix]); - from_to[matrix] = NULL; - } - - fclose(bfp); - } - } - - if (shortest_path[matrix] == NULL) - { - sprintf(msg, "calculating HPB bot waypoint paths for team %d...\n", matrix+1); - ALERT(at_console, msg); - - shortest_path[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); - - if (shortest_path[matrix] == NULL) - ALERT(at_error, "HPB_bot - Error allocating memory for shortest path!"); - - from_to[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); - - if (from_to[matrix] == NULL) - ALERT(at_error, "HPB_bot - Error allocating memory for from to matrix!"); - - pShortestPath = shortest_path[matrix]; - pFromTo = from_to[matrix]; - - for (index=0; index < array_size; index++) - pShortestPath[index] = WAYPOINT_UNREACHABLE; - - for (index=0; index < route_num_waypoints; index++) - pShortestPath[index * route_num_waypoints + index] = 0; // zero diagonal - - for (row=0; row < route_num_waypoints; row++) - { - if (paths[row] != NULL) - { - PATH *p = paths[row]; - - while (p) - { - i = 0; - - while (i < MAX_PATH_INDEX) - { - if (p->index[i] != -1) - { - index = p->index[i]; - - // check if this is NOT team specific OR matches this team - if (!(waypoints[index].flags & W_FL_TEAM_SPECIFIC) || - ((waypoints[index].flags & W_FL_TEAM) == matrix)) - { - distance = (waypoints[row].origin - waypoints[index].origin).Length(); - - if (distance > (float)WAYPOINT_MAX_DISTANCE) - distance = (float)WAYPOINT_MAX_DISTANCE; - - if (distance > REACHABLE_RANGE) - { - sprintf(msg, "Waypoint path distance > %4.1f at from %d to %d\n", - REACHABLE_RANGE, row, index); - ALERT(at_console, msg); - } - else - { - offset = row * route_num_waypoints + index; - - pShortestPath[offset] = (unsigned short)distance; - } - } - } - - i++; - } - - p = p->next; // go to next node in linked list - } - } - } - - // run Floyd's Algorithm to generate the from_to matrix... - WaypointFloyds(pShortestPath, pFromTo); - - for (a=0; a < route_num_waypoints; a++) - { - for (b=0; b < route_num_waypoints; b++) - if (pShortestPath[a * route_num_waypoints + b] == WAYPOINT_UNREACHABLE) - pFromTo[a * route_num_waypoints + b] = WAYPOINT_UNREACHABLE; - } - - bfp = fopen(filename2, "wb"); - - if (bfp != NULL) - { - num_items = fwrite(shortest_path[matrix], sizeof(unsigned short), array_size, bfp); - - if (num_items != array_size) - { - // if couldn't write enough data, close file and delete it - - fclose(bfp); - unlink(filename2); - } - else - { - num_items = fwrite(from_to[matrix], sizeof(unsigned short), array_size, bfp); - - fclose(bfp); - - if (num_items != array_size) - { - // if couldn't write enough data, delete file - unlink(filename2); - } - } - } - else - { - ALERT(at_console, "HPB_bot - Error writing waypoint paths!\n"); - } - - sprintf(msg, "HPB bot waypoint path calculations for team %d complete!\n",matrix+1); - ALERT(at_console, msg); - } - } - } - -} - - -// return the next waypoint index for a path from the Floyd matrix when -// going from a source waypoint index (src) to a destination waypoint -// index (dest)... -unsigned short WaypointRouteFromTo(int src, int dest, int team) -{ - unsigned short *pFromTo; - - if ((team < -1) || (team > 3)) - return -1; - - if (team == -1) // -1 means non-team play - team = 0; - - if (from_to[team] == NULL) // if no team specific waypoints use team 0 - team = 0; - - if (from_to[team] == NULL) // if no route information just return - return -1; - - pFromTo = from_to[team]; - - return pFromTo[src * route_num_waypoints + dest]; -} - - -// return the total distance (based on the Floyd matrix) of a path from -// the source waypoint index (src) to the destination waypoint index -// (dest)... -int WaypointDistanceFromTo(int src, int dest, int team) -{ - unsigned short *pShortestPath; - - if ((team < -1) || (team > 3)) - return -1; - - if (team == -1) // -1 means non-team play - team = 0; - - if (from_to[team] == NULL) // if no team specific waypoints use team 0 - team = 0; - - if (from_to[team] == NULL) // if no route information just return - return -1; - - pShortestPath = shortest_path[team]; - - return (int)(pShortestPath[src * route_num_waypoints + dest]); -} - +// HPB bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// waypoint.cpp +// + +#ifndef __linux__ +#include +#endif +#include +#ifndef __linux__ +#include +#else +#include +#endif + +#include "dlls/extdll.h" +#include "dlls/enginecallback.h" +#include "dlls/util.h" +#include "dlls/cbase.h" + +#include "bot.h" +#include "waypoint.h" +//#include "mod/NetworkMeter.h" + +extern int mod_id; +extern int m_spriteTexture; + +// waypoints with information bits (flags) +WAYPOINT waypoints[MAX_WAYPOINTS]; + +// number of waypoints currently in use +int num_waypoints; + +// declare the array of head pointers to the path structures... +PATH *paths[MAX_WAYPOINTS]; + +// time that this waypoint was displayed (while editing) +float wp_display_time[MAX_WAYPOINTS]; + +bool g_waypoint_paths = FALSE; // have any paths been allocated? +bool g_waypoint_on = FALSE; +bool g_auto_waypoint = FALSE; +bool g_path_waypoint = FALSE; +Vector last_waypoint; +float f_path_time = 0.0; + +unsigned int route_num_waypoints; +unsigned short *shortest_path[4] = {NULL, NULL, NULL, NULL}; +unsigned short *from_to[4] = {NULL, NULL, NULL, NULL}; + +static FILE *fp; + + +void WaypointDebug(void) +{ + int y = 1, x = 1; + + fp=fopen("bot.txt","a"); + fprintf(fp,"WaypointDebug: LINKED LIST ERROR!!!\n"); + fclose(fp); + + x = x - 1; // x is zero + y = y / x; // cause an divide by zero exception + + return; +} + + +// free the linked list of waypoint path nodes... +void WaypointFree(void) +{ + for (int i=0; i < MAX_WAYPOINTS; i++) + { + int count = 0; + + if (paths[i]) + { + PATH *p = paths[i]; + PATH *p_next; + + while (p) // free the linked list + { + p_next = p->next; // save the link to next + free(p); + p = p_next; + +#ifdef _DEBUG + count++; + if (count > 1000) WaypointDebug(); +#endif + } + + paths[i] = NULL; + } + } +} + + +// initialize the waypoint structures... +void WaypointInit(void) +{ + int i; + + // have any waypoint path nodes been allocated yet? + if (g_waypoint_paths) + WaypointFree(); // must free previously allocated path memory + + for (i=0; i < 4; i++) + { + if (shortest_path[i] != NULL) + free(shortest_path[i]); + + if (from_to[i] != NULL) + free(from_to[i]); + } + + for (i=0; i < MAX_WAYPOINTS; i++) + { + waypoints[i].flags = 0; + waypoints[i].origin = Vector(0,0,0); + + wp_display_time[i] = 0.0; + + paths[i] = NULL; // no paths allocated yet + } + + f_path_time = 0.0; // reset waypoint path display time + + num_waypoints = 0; + + last_waypoint = Vector(0,0,0); + + for (i=0; i < 4; i++) + { + shortest_path[i] = NULL; + from_to[i] = NULL; + } +} + + +// add a path from one waypoint (add_index) to another (path_index)... +void WaypointAddPath(short int add_index, short int path_index) +{ + PATH *p, *prev; + int i; + int count = 0; + + p = paths[add_index]; + prev = NULL; + + // find an empty slot for new path_index... + while (p != NULL) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] == -1) + { + p->index[i] = path_index; + + return; + } + + i++; + } + + prev = p; // save the previous node in linked list + p = p->next; // go to next node in linked list + +#ifdef _DEBUG + count++; + if (count > 100) WaypointDebug(); +#endif + } + + p = (PATH *)malloc(sizeof(PATH)); + + if (p == NULL) + { + ALERT(at_error, "HPB_bot - Error allocating memory for path!"); + } + + p->index[0] = path_index; + p->index[1] = -1; + p->index[2] = -1; + p->index[3] = -1; + p->next = NULL; + + if (prev != NULL) + prev->next = p; // link new node into existing list + + if (paths[add_index] == NULL) + paths[add_index] = p; // save head point if necessary +} + + +// delete all paths to this waypoint index... +void WaypointDeletePath(short int del_index) +{ + PATH *p; + int index, i; + + // search all paths for this index... + for (index=0; index < num_waypoints; index++) + { + p = paths[index]; + + int count = 0; + + // search linked list for del_index... + while (p != NULL) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] == del_index) + { + p->index[i] = -1; // unassign this path + } + + i++; + } + + p = p->next; // go to next node in linked list + +#ifdef _DEBUG + count++; + if (count > 100) WaypointDebug(); +#endif + } + } +} + + +// delete a path from a waypoint (path_index) to another waypoint +// (del_index)... +void WaypointDeletePath(short int path_index, short int del_index) +{ + PATH *p; + int i; + int count = 0; + + p = paths[path_index]; + + // search linked list for del_index... + while (p != NULL) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] == del_index) + { + p->index[i] = -1; // unassign this path + } + + i++; + } + + p = p->next; // go to next node in linked list + +#ifdef _DEBUG + count++; + if (count > 100) WaypointDebug(); +#endif + } +} + + +// find a path from the current waypoint. (pPath MUST be NULL on the +// initial call. subsequent calls will return other paths if they exist.) +int WaypointFindPath(PATH **pPath, int *path_index, int waypoint_index, int team) +{ + int index; + int count = 0; + + if (*pPath == NULL) + { + *pPath = paths[waypoint_index]; + *path_index = 0; + } + + if (*path_index == MAX_PATH_INDEX) + { + *path_index = 0; + + *pPath = (*pPath)->next; // go to next node in linked list + } + + while (*pPath != NULL) + { + while (*path_index < MAX_PATH_INDEX) + { + if ((*pPath)->index[*path_index] != -1) // found a path? + { + // save the return value + index = (*pPath)->index[*path_index]; + + // skip this path if next waypoint is team specific and NOT this team + if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[index].flags & W_FL_TEAM) != team)) + { + (*path_index)++; + continue; + } + + // set up stuff for subsequent calls... + (*path_index)++; + + return index; + } + + (*path_index)++; + } + + *path_index = 0; + + *pPath = (*pPath)->next; // go to next node in linked list + +#ifdef _DEBUG + count++; + if (count > 100) WaypointDebug(); +#endif + } + + return -1; +} + + +// find the nearest waypoint to the player and return the index +// (-1 if not found)... +int WaypointFindNearest(edict_t *pEntity, float range, int team) +{ + int i, min_index; + float distance; + float min_distance; + TraceResult tr; + + if (num_waypoints < 1) + return -1; + + // find the nearest waypoint... + + min_index = -1; + min_distance = 9999.0; + + for (i=0; i < num_waypoints; i++) + { + if (waypoints[i].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[i].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[i].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[i].flags & W_FL_TEAM) != team)) + continue; + + distance = (waypoints[i].origin - pEntity->v.origin).Length(); + + if ((distance < min_distance) && (distance < range)) + { + // if waypoint is visible from current position (even behind head)... + UTIL_TraceLine( pEntity->v.origin + pEntity->v.view_ofs, waypoints[i].origin, + ignore_monsters, pEntity->v.pContainingEntity, &tr ); + + if (tr.flFraction >= 1.0) + { + min_index = i; + min_distance = distance; + } + } + } + + return min_index; +} + + +// find the nearest waypoint to the source postition and return the index +// of that waypoint... +int WaypointFindNearest(Vector v_src, edict_t *pEntity, float range, int team) +{ + int index, min_index; + float distance; + float min_distance; + TraceResult tr; + + if (num_waypoints < 1) + return -1; + + // find the nearest waypoint... + + min_index = -1; + min_distance = 9999.0; + + for (index=0; index < num_waypoints; index++) + { + if (waypoints[index].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[index].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[index].flags & W_FL_TEAM) != team)) + continue; + + distance = (waypoints[index].origin - v_src).Length(); + + if ((distance < min_distance) && (distance < range)) + { + // if waypoint is visible from source position... + UTIL_TraceLine( v_src, waypoints[index].origin, ignore_monsters, + pEntity->v.pContainingEntity, &tr ); + + if (tr.flFraction >= 1.0) + { + min_index = index; + min_distance = distance; + } + } + } + + return min_index; +} + + +// find the goal nearest to the player matching the "flags" bits and return +// the index of that waypoint... +int WaypointFindNearestGoal(edict_t *pEntity, int src, int team, int flags) +{ + int index, min_index; + int distance, min_distance; + + if (num_waypoints < 1) + return -1; + + // find the nearest waypoint with the matching flags... + + min_index = -1; + min_distance = 99999; + + for (index=0; index < num_waypoints; index++) + { + if (index == src) + continue; // skip the source waypoint + + if (waypoints[index].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[index].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[index].flags & W_FL_TEAM) != team)) + continue; + + if ((waypoints[index].flags & flags) != flags) + continue; // skip this waypoint if the flags don't match + + distance = WaypointDistanceFromTo(src, index, team); + + if (distance < min_distance) + { + min_index = index; + min_distance = distance; + } + } + + return min_index; +} + + +// find the goal nearest to the source position (v_src) matching the "flags" +// bits and return the index of that waypoint... +int WaypointFindNearestGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags) +{ + int index, min_index; + int distance, min_distance; + + if (num_waypoints < 1) + return -1; + + // find the nearest waypoint with the matching flags... + + min_index = -1; + min_distance = 99999; + + for (index=0; index < num_waypoints; index++) + { + if (waypoints[index].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[index].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[index].flags & W_FL_TEAM) != team)) + continue; + + if ((waypoints[index].flags & flags) != flags) + continue; // skip this waypoint if the flags don't match + + distance = (waypoints[index].origin - v_src).Length(); + + if ((distance < range) && (distance < min_distance)) + { + min_index = index; + min_distance = distance; + } + } + + return min_index; +} + + +// find a random goal matching the "flags" bits and return the index of +// that waypoint... +int WaypointFindRandomGoal(edict_t *pEntity, int team, int flags) +{ + int index; + int indexes[50]; + int count = 0; + + if (num_waypoints < 1) + return -1; + + // find all the waypoints with the matching flags... + + for (index=0; index < num_waypoints; index++) + { + if (waypoints[index].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[index].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[index].flags & W_FL_TEAM) != team)) + continue; + + if ((waypoints[index].flags & flags) != flags) + continue; // skip this waypoint if the flags don't match + + if (count < 50) + { + indexes[count] = index; + + count++; + } + } + + if (count == 0) // no matching waypoints found + return -1; + + index = RANDOM_LONG(1, count) - 1; + + return indexes[index]; +} + + +// find a random goal within a range of a position (v_src) matching the +// "flags" bits and return the index of that waypoint... +int WaypointFindRandomGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags) +{ + int index; + int indexes[50]; + int count = 0; + float distance; + + if (num_waypoints < 1) + return -1; + + // find all the waypoints with the matching flags... + + for (index=0; index < num_waypoints; index++) + { + if (waypoints[index].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[index].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[index].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[index].flags & W_FL_TEAM) != team)) + continue; + + if ((waypoints[index].flags & flags) != flags) + continue; // skip this waypoint if the flags don't match + + distance = (waypoints[index].origin - v_src).Length(); + + if ((distance < range) && (count < 50)) + { + indexes[count] = index; + + count++; + } + } + + if (count == 0) // no matching waypoints found + return -1; + + index = RANDOM_LONG(1, count) - 1; + + return indexes[index]; +} + + +// find the nearest "special" aiming waypoint (for sniper aiming)... +int WaypointFindNearestAiming(Vector v_origin) +{ + int index; + int min_index = -1; + int min_distance = 9999.0; + float distance; + + if (num_waypoints < 1) + return -1; + + // search for nearby aiming waypoint... + for (index=0; index < num_waypoints; index++) + { + if (waypoints[index].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if ((waypoints[index].flags & W_FL_AIMING) == 0) + continue; // skip any NON aiming waypoints + + distance = (v_origin - waypoints[index].origin).Length(); + + if ((distance < min_distance) && (distance < 40)) + { + min_index = index; + min_distance = distance; + } + } + + return min_index; +} + + +void WaypointDrawBeam(edict_t *pEntity, Vector start, Vector end, int width, + int noise, int red, int green, int blue, int brightness, int speed) +{ +// MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); +// WRITE_BYTE( TE_BEAMPOINTS); +// WRITE_COORD(start.x); +// WRITE_COORD(start.y); +// WRITE_COORD(start.z); +// WRITE_COORD(end.x); +// WRITE_COORD(end.y); +// WRITE_COORD(end.z); +// WRITE_SHORT( m_spriteTexture ); +// WRITE_BYTE( 1 ); // framestart +// WRITE_BYTE( 10 ); // framerate +// WRITE_BYTE( 10 ); // life in 0.1's +// WRITE_BYTE( width ); // width +// WRITE_BYTE( noise ); // noise +// +// WRITE_BYTE( red ); // r, g, b +// WRITE_BYTE( green ); // r, g, b +// WRITE_BYTE( blue ); // r, g, b +// +// WRITE_BYTE( brightness ); // brightness +// WRITE_BYTE( speed ); // speed +// MESSAGE_END(); +} + + +void WaypointAdd(edict_t *pEntity) +{ + int index; + edict_t *pent = NULL; + float radius = 40; + char item_name[64]; + + if (num_waypoints >= MAX_WAYPOINTS) + return; + + index = 0; + + // find the next available slot for the new waypoint... + while (index < num_waypoints) + { + if (waypoints[index].flags & W_FL_DELETED) + break; + + index++; + } + + waypoints[index].flags = 0; + + // store the origin (location) of this waypoint (use entity origin) + waypoints[index].origin = pEntity->v.origin; + + // store the last used waypoint for the auto waypoint code... + last_waypoint = pEntity->v.origin; + + // set the time that this waypoint was originally displayed... + wp_display_time[index] = gpGlobals->time; + + + Vector start, end; + + start = pEntity->v.origin - Vector(0, 0, 34); + end = start + Vector(0, 0, 68); + + if ((pEntity->v.flags & FL_DUCKING) == FL_DUCKING) + { + waypoints[index].flags |= W_FL_CROUCH; // crouching waypoint + + start = pEntity->v.origin - Vector(0, 0, 17); + end = start + Vector(0, 0, 34); + } + + if (pEntity->v.movetype == MOVETYPE_FLY) + waypoints[index].flags |= W_FL_LADDER; // waypoint on a ladder + + + //******************************************************** + // look for lift, ammo, flag, health, armor, etc. + //******************************************************** + + while ((pent = UTIL_FindEntityInSphere( pent, pEntity->v.origin, radius )) != NULL) + { + strcpy(item_name, STRING(pent->v.classname)); + + if (strcmp("item_healthkit", item_name) == 0) + { + ClientPrint(pEntity, HUD_PRINTCONSOLE, "found a healthkit!\n"); + waypoints[index].flags = W_FL_HEALTH; + } + + if (strncmp("item_armor", item_name, 10) == 0) + { + ClientPrint(pEntity, HUD_PRINTCONSOLE, "found some armor!\n"); + waypoints[index].flags = W_FL_ARMOR; + } + + // ************* + // LOOK FOR AMMO + // ************* + + } + + // draw a blue waypoint + WaypointDrawBeam(pEntity, start, end, 30, 0, 0, 0, 255, 250, 5); + + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "weapons/xbow_hit1.wav", 1.0, + ATTN_NORM, 0, 100); + + // increment total number of waypoints if adding at end of array... + if (index == num_waypoints) + num_waypoints++; + + // calculate all the paths to this new waypoint + for (int i=0; i < num_waypoints; i++) + { + if (i == index) + continue; // skip the waypoint that was just added + + if (waypoints[i].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // check if the waypoint is reachable from the new one (one-way) + if ( WaypointReachable(pEntity->v.origin, waypoints[i].origin, pEntity) ) + { + WaypointAddPath(index, i); + } + + // check if the new one is reachable from the waypoint (other way) + if ( WaypointReachable(waypoints[i].origin, pEntity->v.origin, pEntity) ) + { + WaypointAddPath(i, index); + } + } +} + + +void WaypointAddAiming(edict_t *pEntity) +{ + int index; + edict_t *pent = NULL; + + if (num_waypoints >= MAX_WAYPOINTS) + return; + + index = 0; + + // find the next available slot for the new waypoint... + while (index < num_waypoints) + { + if (waypoints[index].flags & W_FL_DELETED) + break; + + index++; + } + + waypoints[index].flags = W_FL_AIMING; // aiming waypoint + + Vector v_angle = pEntity->v.v_angle; + + v_angle.x = 0; // reset pitch to horizontal + v_angle.z = 0; // reset roll to level + + UTIL_MakeVectors(v_angle); + + // store the origin (location) of this waypoint (use entity origin) + waypoints[index].origin = pEntity->v.origin + gpGlobals->v_forward * 25; + + // set the time that this waypoint was originally displayed... + wp_display_time[index] = gpGlobals->time; + + + Vector start, end; + + start = pEntity->v.origin - Vector(0, 0, 10); + end = start + Vector(0, 0, 14); + + // draw a blue waypoint + WaypointDrawBeam(pEntity, start, end, 30, 0, 0, 0, 255, 250, 5); + + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "weapons/xbow_hit1.wav", 1.0, + ATTN_NORM, 0, 100); + + // increment total number of waypoints if adding at end of array... + if (index == num_waypoints) + num_waypoints++; +} + + +void WaypointDelete(edict_t *pEntity) +{ + int index; + int count = 0; + + if (num_waypoints < 1) + return; + + index = WaypointFindNearest(pEntity, 50.0, -1); + + if (index == -1) + return; + + if ((waypoints[index].flags & W_FL_SNIPER) || + ((mod_id == FRONTLINE_DLL) && (waypoints[index].flags & W_FL_FLF_DEFEND))) + { + int i; + int min_index = -1; + int min_distance = 9999.0; + float distance; + + // search for nearby aiming waypoint and delete it also... + for (i=0; i < num_waypoints; i++) + { + if (waypoints[i].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if ((waypoints[i].flags & W_FL_AIMING) == 0) + continue; // skip any NON aiming waypoints + + distance = (waypoints[i].origin - waypoints[index].origin).Length(); + + if ((distance < min_distance) && (distance < 40)) + { + min_index = i; + min_distance = distance; + } + } + + if (min_index != -1) + { + waypoints[min_index].flags = W_FL_DELETED; // not being used + waypoints[min_index].origin = Vector(0,0,0); + + wp_display_time[min_index] = 0.0; + } + } + + // delete any paths that lead to this index... + WaypointDeletePath(index); + + // free the path for this index... + + if (paths[index] != NULL) + { + PATH *p = paths[index]; + PATH *p_next; + + while (p) // free the linked list + { + p_next = p->next; // save the link to next + free(p); + p = p_next; + +#ifdef _DEBUG + count++; + if (count > 100) WaypointDebug(); +#endif + } + + paths[index] = NULL; + } + + waypoints[index].flags = W_FL_DELETED; // not being used + waypoints[index].origin = Vector(0,0,0); + + wp_display_time[index] = 0.0; + + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "weapons/mine_activate.wav", 1.0, + ATTN_NORM, 0, 100); +} + + +// allow player to manually create a path from one waypoint to another +void WaypointCreatePath(edict_t *pEntity, int cmd) +{ + static int waypoint1 = -1; // initialized to unassigned + static int waypoint2 = -1; // initialized to unassigned + + if (cmd == 1) // assign source of path + { + waypoint1 = WaypointFindNearest(pEntity, 50.0, -1); + + if (waypoint1 == -1) + { + // play "cancelled" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_moveselect.wav", 1.0, + ATTN_NORM, 0, 100); + + return; + } + + // play "start" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudoff.wav", 1.0, + ATTN_NORM, 0, 100); + + return; + } + + if (cmd == 2) // assign dest of path and make path + { + waypoint2 = WaypointFindNearest(pEntity, 50.0, -1); + + if ((waypoint1 == -1) || (waypoint2 == -1)) + { + // play "error" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_denyselect.wav", 1.0, + ATTN_NORM, 0, 100); + + return; + } + + WaypointAddPath(waypoint1, waypoint2); + + // play "done" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudon.wav", 1.0, + ATTN_NORM, 0, 100); + } +} + + +// allow player to manually remove a path from one waypoint to another +void WaypointRemovePath(edict_t *pEntity, int cmd) +{ + static int waypoint1 = -1; // initialized to unassigned + static int waypoint2 = -1; // initialized to unassigned + + if (cmd == 1) // assign source of path + { + waypoint1 = WaypointFindNearest(pEntity, 50.0, -1); + + if (waypoint1 == -1) + { + // play "cancelled" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_moveselect.wav", 1.0, + ATTN_NORM, 0, 100); + + return; + } + + // play "start" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudoff.wav", 1.0, + ATTN_NORM, 0, 100); + + return; + } + + if (cmd == 2) // assign dest of path and make path + { + waypoint2 = WaypointFindNearest(pEntity, 50.0, -1); + + if ((waypoint1 == -1) || (waypoint2 == -1)) + { + // play "error" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_denyselect.wav", 1.0, + ATTN_NORM, 0, 100); + + return; + } + + WaypointDeletePath(waypoint1, waypoint2); + + // play "done" sound... + EMIT_SOUND_DYN2(pEntity, CHAN_WEAPON, "common/wpn_hudon.wav", 1.0, + ATTN_NORM, 0, 100); + } +} + + +bool WaypointLoad(edict_t *pEntity) +{ + char mapname[64]; + char filename[256]; + WAYPOINT_HDR header; + char msg[80]; + int index, i; + short int num; + short int path_index; + + strcpy(mapname, STRING(gpGlobals->mapname)); + strcat(mapname, ".wpt"); + + UTIL_BuildFileName(filename, "maps", mapname); + + if (IS_DEDICATED_SERVER()) + printf("loading waypoint file: %s\n", filename); + + FILE *bfp = fopen(filename, "rb"); + + // if file exists, read the waypoint structure from it + if (bfp != NULL) + { + fread(&header, sizeof(header), 1, bfp); + + header.filetype[7] = 0; + if (strcmp(header.filetype, "HPB_bot") == 0) + { + if (header.waypoint_file_version != WAYPOINT_VERSION) + { + if (pEntity) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "Incompatible HPB bot waypoint file version!\nWaypoints not loaded!\n"); + + fclose(bfp); + return FALSE; + } + + header.mapname[31] = 0; + + if (strcmp(header.mapname, STRING(gpGlobals->mapname)) == 0) + { + WaypointInit(); // remove any existing waypoints + + for (i=0; i < header.number_of_waypoints; i++) + { + fread(&waypoints[i], sizeof(waypoints[0]), 1, bfp); + num_waypoints++; + } + + // read and add waypoint paths... + for (index=0; index < num_waypoints; index++) + { + // read the number of paths from this node... + fread(&num, sizeof(num), 1, bfp); + + for (i=0; i < num; i++) + { + fread(&path_index, sizeof(path_index), 1, bfp); + + WaypointAddPath(index, path_index); + } + } + + g_waypoint_paths = TRUE; // keep track so path can be freed + } + else + { + if (pEntity) + { + sprintf(msg, "%s HPB bot waypoints are not for this map!\n", filename); + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + } + + fclose(bfp); + return FALSE; + } + } + else + { + if (pEntity) + { + sprintf(msg, "%s is not a HPB bot waypoint file!\n", filename); + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + } + + fclose(bfp); + return FALSE; + } + + fclose(bfp); + + WaypointRouteInit(); + } + else + { + if (pEntity) + { + sprintf(msg, "Waypoint file %s does not exist!\n", filename); + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + } + + if (IS_DEDICATED_SERVER()) + printf("waypoint file %s not found!\n", filename); + + return FALSE; + } + + return TRUE; +} + + +void WaypointSave(void) +{ + char filename[256]; + char mapname[64]; + WAYPOINT_HDR header; + int index, i; + short int num; + PATH *p; + + strcpy(header.filetype, "HPB_bot"); + + header.waypoint_file_version = WAYPOINT_VERSION; + + header.waypoint_file_flags = 0; // not currently used + + header.number_of_waypoints = num_waypoints; + + memset(header.mapname, 0, sizeof(header.mapname)); + strncpy(header.mapname, STRING(gpGlobals->mapname), 31); + header.mapname[31] = 0; + + strcpy(mapname, STRING(gpGlobals->mapname)); + strcat(mapname, ".wpt"); + + UTIL_BuildFileName(filename, "maps", mapname); + + FILE *bfp = fopen(filename, "wb"); + + // write the waypoint header to the file... + fwrite(&header, sizeof(header), 1, bfp); + + // write the waypoint data to the file... + for (index=0; index < num_waypoints; index++) + { + fwrite(&waypoints[index], sizeof(waypoints[0]), 1, bfp); + } + + // save the waypoint paths... + for (index=0; index < num_waypoints; index++) + { + // count the number of paths from this node... + + p = paths[index]; + num = 0; + + while (p != NULL) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] != -1) + num++; // count path node if it's used + + i++; + } + + p = p->next; // go to next node in linked list + } + + fwrite(&num, sizeof(num), 1, bfp); // write the count + + // now write out each path index... + + p = paths[index]; + + while (p != NULL) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] != -1) // save path node if it's used + fwrite(&p->index[i], sizeof(p->index[0]), 1, bfp); + + i++; + } + + p = p->next; // go to next node in linked list + } + } + + fclose(bfp); +} + + +bool WaypointReachable(Vector v_src, Vector v_dest, edict_t *pEntity) +{ + TraceResult tr; + float curr_height, last_height; + + float distance = (v_dest - v_src).Length(); + + // is the destination close enough? + if (distance < REACHABLE_RANGE) + { + // check if this waypoint is "visible"... + + UTIL_TraceLine( v_src, v_dest, ignore_monsters, + pEntity->v.pContainingEntity, &tr ); + + // if waypoint is visible from current position (even behind head)... + if (tr.flFraction >= 1.0) + { + // check for special case of both waypoints being underwater... + if ((POINT_CONTENTS( v_src ) == CONTENTS_WATER) && + (POINT_CONTENTS( v_dest ) == CONTENTS_WATER)) + { + return TRUE; + } + + // check for special case of waypoint being suspended in mid-air... + + // is dest waypoint higher than src? (45 is max jump height) + if (v_dest.z > (v_src.z + 45.0)) + { + Vector v_new_src = v_dest; + Vector v_new_dest = v_dest; + + v_new_dest.z = v_new_dest.z - 50; // straight down 50 units + + UTIL_TraceLine(v_new_src, v_new_dest, dont_ignore_monsters, + pEntity->v.pContainingEntity, &tr); + + // check if we didn't hit anything, if not then it's in mid-air + if (tr.flFraction >= 1.0) + { + return FALSE; // can't reach this one + } + } + + // check if distance to ground increases more than jump height + // at points between source and destination... + + Vector v_direction = (v_dest - v_src).Normalize(); // 1 unit long + Vector v_check = v_src; + Vector v_down = v_src; + + v_down.z = v_down.z - 1000.0; // straight down 1000 units + + UTIL_TraceLine(v_check, v_down, ignore_monsters, + pEntity->v.pContainingEntity, &tr); + + last_height = tr.flFraction * 1000.0; // height from ground + + distance = (v_dest - v_check).Length(); // distance from goal + + while (distance > 10.0) + { + // move 10 units closer to the goal... + v_check = v_check + (v_direction * 10.0); + + v_down = v_check; + v_down.z = v_down.z - 1000.0; // straight down 1000 units + + UTIL_TraceLine(v_check, v_down, ignore_monsters, + pEntity->v.pContainingEntity, &tr); + + curr_height = tr.flFraction * 1000.0; // height from ground + + // is the difference in the last height and the current height + // higher that the jump height? + if ((last_height - curr_height) > 45.0) + { + // can't get there from here... + return FALSE; + } + + last_height = curr_height; + + distance = (v_dest - v_check).Length(); // distance from goal + } + + return TRUE; + } + } + + return FALSE; +} + + +// find the nearest reachable waypoint +int WaypointFindReachable(edict_t *pEntity, float range, int team) +{ + int i, min_index; + float distance; + float min_distance; + TraceResult tr; + + // find the nearest waypoint... + + min_distance = 9999.0; + + for (i=0; i < num_waypoints; i++) + { + if (waypoints[i].flags & W_FL_DELETED) + continue; // skip any deleted waypoints + + if (waypoints[i].flags & W_FL_AIMING) + continue; // skip any aiming waypoints + + // skip this waypoint if it's team specific and teams don't match... + if ((team != -1) && (waypoints[i].flags & W_FL_TEAM_SPECIFIC) && + ((waypoints[i].flags & W_FL_TEAM) != team)) + continue; + + distance = (waypoints[i].origin - pEntity->v.origin).Length(); + + if (distance < min_distance) + { + // if waypoint is visible from current position (even behind head)... + UTIL_TraceLine( pEntity->v.origin + pEntity->v.view_ofs, waypoints[i].origin, + ignore_monsters, pEntity->v.pContainingEntity, &tr ); + + if (tr.flFraction >= 1.0) + { + if (WaypointReachable(pEntity->v.origin, waypoints[i].origin, pEntity)) + { + min_index = i; + min_distance = distance; + } + } + } + } + + // if not close enough to a waypoint then just return + if (min_distance > range) + return -1; + + return min_index; + +} + + +void WaypointPrintInfo(edict_t *pEntity) +{ + char msg[80]; + int index; + int flags; + + // find the nearest waypoint... + index = WaypointFindNearest(pEntity, 50.0, -1); + + if (index == -1) + return; + + sprintf(msg,"Waypoint %d of %d total\n", index, num_waypoints); + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + + flags = waypoints[index].flags; + + if (flags & W_FL_TEAM_SPECIFIC) + { + if (mod_id == FRONTLINE_DLL) + { + if ((flags & W_FL_TEAM) == 0) + strcpy(msg, "Waypoint is for Attackers\n"); + else if ((flags & W_FL_TEAM) == 1) + strcpy(msg, "Waypoint is for Defenders\n"); + } + else + { + if ((flags & W_FL_TEAM) == 0) + strcpy(msg, "Waypoint is for TEAM 1\n"); + else if ((flags & W_FL_TEAM) == 1) + strcpy(msg, "Waypoint is for TEAM 2\n"); + else if ((flags & W_FL_TEAM) == 2) + strcpy(msg, "Waypoint is for TEAM 3\n"); + else if ((flags & W_FL_TEAM) == 3) + strcpy(msg, "Waypoint is for TEAM 4\n"); + } + + ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); + } + + if (flags & W_FL_LIFT) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "Bot will wait for lift before approaching\n"); + + if (flags & W_FL_LADDER) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "This waypoint is on a ladder\n"); + + if (flags & W_FL_DOOR) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "This is a door waypoint\n"); + + if (flags & W_FL_HEALTH) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is health near this waypoint\n"); + + if (flags & W_FL_ARMOR) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is armor near this waypoint\n"); + + if (flags & W_FL_AMMO) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is ammo near this waypoint\n"); + + if (flags & W_FL_SNIPER) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "This is a sniper waypoint\n"); + + if (flags & W_FL_TFC_FLAG) + { + if (mod_id == FRONTLINE_DLL) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is a capture point near this waypoint\n"); + else + ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is a flag near this waypoint\n"); + } + + if (flags & W_FL_TFC_FLAG_GOAL) + { + if (mod_id == FRONTLINE_DLL) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "This is a defender location\n"); + else + ClientPrint(pEntity, HUD_PRINTNOTIFY, "There is a flag goal near this waypoint\n"); + } + + if (flags & W_FL_PRONE) + ClientPrint(pEntity, HUD_PRINTNOTIFY, "Bot will go prone here\n"); +} + + +void WaypointThink(edict_t *pEntity) +{ + float distance, min_distance; + Vector start, end; + int i, index; + + if (g_auto_waypoint) // is auto waypoint on? + { + // find the distance from the last used waypoint + distance = (last_waypoint - pEntity->v.origin).Length(); + + if (distance > 200) + { + min_distance = 9999.0; + + // check that no other reachable waypoints are nearby... + for (i=0; i < num_waypoints; i++) + { + if (waypoints[i].flags & W_FL_DELETED) + continue; + + if (waypoints[i].flags & W_FL_AIMING) + continue; + + if (WaypointReachable(pEntity->v.origin, waypoints[i].origin, pEntity)) + { + distance = (waypoints[i].origin - pEntity->v.origin).Length(); + + if (distance < min_distance) + min_distance = distance; + } + } + + // make sure nearest waypoint is far enough away... + if (min_distance >= 200) + WaypointAdd(pEntity); // place a waypoint here + } + } + + min_distance = 9999.0; + + if (g_waypoint_on) // display the waypoints if turned on... + { + for (i=0; i < num_waypoints; i++) + { + if ((waypoints[i].flags & W_FL_DELETED) == W_FL_DELETED) + continue; + + distance = (waypoints[i].origin - pEntity->v.origin).Length(); + + if (distance < 500) + { + if (distance < min_distance) + { + index = i; // store index of nearest waypoint + min_distance = distance; + } + + if ((wp_display_time[i] + 1.0) < gpGlobals->time) + { + if (waypoints[i].flags & W_FL_CROUCH) + { + start = waypoints[i].origin - Vector(0, 0, 17); + end = start + Vector(0, 0, 34); + } + else if (waypoints[i].flags & W_FL_AIMING) + { + start = waypoints[i].origin + Vector(0, 0, 10); + end = start + Vector(0, 0, 14); + } + else + { + start = waypoints[i].origin - Vector(0, 0, 34); + end = start + Vector(0, 0, 68); + } + + // draw a blue waypoint + WaypointDrawBeam(pEntity, start, end, 30, 0, 0, 0, 255, 250, 5); + + wp_display_time[i] = gpGlobals->time; + } + } + } + + // check if path waypointing is on... + if (g_path_waypoint) + { + // check if player is close enough to a waypoint and time to draw path... + if ((min_distance <= 50) && (f_path_time <= gpGlobals->time)) + { + PATH *p; + + f_path_time = gpGlobals->time + 1.0; + + p = paths[index]; + + while (p != NULL) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] != -1) + { + Vector v_src = waypoints[index].origin; + Vector v_dest = waypoints[p->index[i]].origin; + + // draw a white line to this index's waypoint + WaypointDrawBeam(pEntity, v_src, v_dest, 10, 2, 250, 250, 250, 200, 10); + } + + i++; + } + + p = p->next; // go to next node in linked list + } + } + } + } +} + + +// run Floyd's algorithm on the waypoint list to generate the least cost +// path matrix... +void WaypointFloyds(unsigned short *shortest_path, unsigned short *from_to) +{ + unsigned int x, y, z; + int changed = 1; + int distance; + + for (y=0; y < route_num_waypoints; y++) + { + for (z=0; z < route_num_waypoints; z++) + { + from_to[y * route_num_waypoints + z] = z; + } + } + + while (changed) + { + changed = 0; + + for (x=0; x < route_num_waypoints; x++) + { + for (y=0; y < route_num_waypoints; y++) + { + for (z=0; z < route_num_waypoints; z++) + { + if ((shortest_path[y * route_num_waypoints + x] == WAYPOINT_UNREACHABLE) || + (shortest_path[x * route_num_waypoints + z] == WAYPOINT_UNREACHABLE)) + continue; + + distance = shortest_path[y * route_num_waypoints + x] + + shortest_path[x * route_num_waypoints + z]; + + if (distance > WAYPOINT_MAX_DISTANCE) + distance = WAYPOINT_MAX_DISTANCE; + + if ((distance < shortest_path[y * route_num_waypoints + z]) || + (shortest_path[y * route_num_waypoints + z] == WAYPOINT_UNREACHABLE)) + { + shortest_path[y * route_num_waypoints + z] = distance; + from_to[y * route_num_waypoints + z] = from_to[y * route_num_waypoints + x]; + changed = 1; + } + } + } + } + } +} + + +// load the waypoint route files (.wp1, .wp2, etc.) or generate them if +// they don't exist... +void WaypointRouteInit(void) +{ + unsigned int index; + bool build_matrix[4]; + int matrix; + unsigned int array_size; + unsigned int row; + int i, offset; + unsigned int a, b; + float distance; + unsigned short *pShortestPath, *pFromTo; + char msg[80]; + unsigned int num_items; + FILE *bfp; + char filename[256]; + char filename2[256]; + char mapname[64]; + + if (num_waypoints == 0) + return; + + // save number of current waypoints in case waypoints get added later + route_num_waypoints = num_waypoints; + + strcpy(mapname, STRING(gpGlobals->mapname)); + strcat(mapname, ".wpt"); + + UTIL_BuildFileName(filename, "maps", mapname); + + build_matrix[0] = TRUE; // always build matrix 0 (non-team and team 1) + build_matrix[1] = FALSE; + build_matrix[2] = FALSE; + build_matrix[3] = FALSE; + + // find out how many route matrixes to create... + for (index=0; index < route_num_waypoints; index++) + { + if (waypoints[index].flags & W_FL_TEAM_SPECIFIC) + { + if ((waypoints[index].flags & W_FL_TEAM) == 0x01) // team 2? + build_matrix[1] = TRUE; + + if ((waypoints[index].flags & W_FL_TEAM) == 0x02) // team 3? + build_matrix[2] = TRUE; + + if ((waypoints[index].flags & W_FL_TEAM) == 0x03) // team 4? + build_matrix[3] = TRUE; + } + } + + array_size = route_num_waypoints * route_num_waypoints; + + for (matrix=0; matrix < 4; matrix++) + { + if (build_matrix[matrix]) + { + char ext_str[5]; // ".wpX\0" + int file1, file2; + struct stat stat1, stat2; + + sprintf(ext_str, ".wp%d", matrix+1); + + strcpy(mapname, STRING(gpGlobals->mapname)); + strcat(mapname, ext_str); + + UTIL_BuildFileName(filename2, "maps", mapname); + + if (access(filename2, 0) == 0) // does the .wpX file exist? + { + file1 = open(filename, O_RDONLY); + file2 = open(filename2, O_RDONLY); + + fstat(file1, &stat1); + fstat(file2, &stat2); + + close(file1); + close(file2); + + if (stat1.st_mtime < stat2.st_mtime) // is .wpt older than .wpX file? + { + sprintf(msg, "loading HPB bot waypoint paths for team %d\n", matrix+1); + ALERT(at_console, msg); + + shortest_path[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); + + if (shortest_path[matrix] == NULL) + ALERT(at_error, "HPB_bot - Error allocating memory for shortest path!"); + + from_to[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); + + if (from_to[matrix] == NULL) + ALERT(at_error, "HPB_bot - Error allocating memory for from to matrix!"); + + bfp = fopen(filename2, "rb"); + + if (bfp != NULL) + { + num_items = fread(shortest_path[matrix], sizeof(unsigned short), array_size, bfp); + + if (num_items != array_size) + { + // if couldn't read enough data, free memory to recalculate it + + ALERT(at_console, "error reading enough path items, recalculating...\n"); + + free(shortest_path[matrix]); + shortest_path[matrix] = NULL; + + free(from_to[matrix]); + from_to[matrix] = NULL; + } + else + { + num_items = fread(from_to[matrix], sizeof(unsigned short), array_size, bfp); + + if (num_items != array_size) + { + // if couldn't read enough data, free memory to recalculate it + + ALERT(at_console, "error reading enough path items, recalculating...\n"); + + free(shortest_path[matrix]); + shortest_path[matrix] = NULL; + + free(from_to[matrix]); + from_to[matrix] = NULL; + } + } + } + else + { + ALERT(at_console, "HPB_bot - Error reading waypoint paths!\n"); + + free(shortest_path[matrix]); + shortest_path[matrix] = NULL; + + free(from_to[matrix]); + from_to[matrix] = NULL; + } + + fclose(bfp); + } + } + + if (shortest_path[matrix] == NULL) + { + sprintf(msg, "calculating HPB bot waypoint paths for team %d...\n", matrix+1); + ALERT(at_console, msg); + + shortest_path[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); + + if (shortest_path[matrix] == NULL) + ALERT(at_error, "HPB_bot - Error allocating memory for shortest path!"); + + from_to[matrix] = (unsigned short *)malloc(sizeof(unsigned short) * array_size); + + if (from_to[matrix] == NULL) + ALERT(at_error, "HPB_bot - Error allocating memory for from to matrix!"); + + pShortestPath = shortest_path[matrix]; + pFromTo = from_to[matrix]; + + for (index=0; index < array_size; index++) + pShortestPath[index] = WAYPOINT_UNREACHABLE; + + for (index=0; index < route_num_waypoints; index++) + pShortestPath[index * route_num_waypoints + index] = 0; // zero diagonal + + for (row=0; row < route_num_waypoints; row++) + { + if (paths[row] != NULL) + { + PATH *p = paths[row]; + + while (p) + { + i = 0; + + while (i < MAX_PATH_INDEX) + { + if (p->index[i] != -1) + { + index = p->index[i]; + + // check if this is NOT team specific OR matches this team + if (!(waypoints[index].flags & W_FL_TEAM_SPECIFIC) || + ((waypoints[index].flags & W_FL_TEAM) == matrix)) + { + distance = (waypoints[row].origin - waypoints[index].origin).Length(); + + if (distance > (float)WAYPOINT_MAX_DISTANCE) + distance = (float)WAYPOINT_MAX_DISTANCE; + + if (distance > REACHABLE_RANGE) + { + sprintf(msg, "Waypoint path distance > %4.1f at from %d to %d\n", + REACHABLE_RANGE, row, index); + ALERT(at_console, msg); + } + else + { + offset = row * route_num_waypoints + index; + + pShortestPath[offset] = (unsigned short)distance; + } + } + } + + i++; + } + + p = p->next; // go to next node in linked list + } + } + } + + // run Floyd's Algorithm to generate the from_to matrix... + WaypointFloyds(pShortestPath, pFromTo); + + for (a=0; a < route_num_waypoints; a++) + { + for (b=0; b < route_num_waypoints; b++) + if (pShortestPath[a * route_num_waypoints + b] == WAYPOINT_UNREACHABLE) + pFromTo[a * route_num_waypoints + b] = WAYPOINT_UNREACHABLE; + } + + bfp = fopen(filename2, "wb"); + + if (bfp != NULL) + { + num_items = fwrite(shortest_path[matrix], sizeof(unsigned short), array_size, bfp); + + if (num_items != array_size) + { + // if couldn't write enough data, close file and delete it + + fclose(bfp); + unlink(filename2); + } + else + { + num_items = fwrite(from_to[matrix], sizeof(unsigned short), array_size, bfp); + + fclose(bfp); + + if (num_items != array_size) + { + // if couldn't write enough data, delete file + unlink(filename2); + } + } + } + else + { + ALERT(at_console, "HPB_bot - Error writing waypoint paths!\n"); + } + + sprintf(msg, "HPB bot waypoint path calculations for team %d complete!\n",matrix+1); + ALERT(at_console, msg); + } + } + } + +} + + +// return the next waypoint index for a path from the Floyd matrix when +// going from a source waypoint index (src) to a destination waypoint +// index (dest)... +unsigned short WaypointRouteFromTo(int src, int dest, int team) +{ + unsigned short *pFromTo; + + if ((team < -1) || (team > 3)) + return -1; + + if (team == -1) // -1 means non-team play + team = 0; + + if (from_to[team] == NULL) // if no team specific waypoints use team 0 + team = 0; + + if (from_to[team] == NULL) // if no route information just return + return -1; + + pFromTo = from_to[team]; + + return pFromTo[src * route_num_waypoints + dest]; +} + + +// return the total distance (based on the Floyd matrix) of a path from +// the source waypoint index (src) to the destination waypoint index +// (dest)... +int WaypointDistanceFromTo(int src, int dest, int team) +{ + unsigned short *pShortestPath; + + if ((team < -1) || (team > 3)) + return -1; + + if (team == -1) // -1 means non-team play + team = 0; + + if (from_to[team] == NULL) // if no team specific waypoints use team 0 + team = 0; + + if (from_to[team] == NULL) // if no route information just return + return -1; + + pShortestPath = shortest_path[team]; + + return (int)(pShortestPath[src * route_num_waypoints + dest]); +} + diff --git a/main/source/HPB_bot/dlls/waypoint.h b/main/source/HPB_bot/dlls/waypoint.h index dc84707c..bdb7f8aa 100644 --- a/main/source/HPB_bot/dlls/waypoint.h +++ b/main/source/HPB_bot/dlls/waypoint.h @@ -1,104 +1,104 @@ -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// waypoint.h -// - -#ifndef WAYPOINT_H -#define WAYPOINT_H - -#include - -#define MAX_WAYPOINTS 1024 - -#define REACHABLE_RANGE 400.0 - -// defines for waypoint flags field (32 bits are available) -#define W_FL_TEAM ((1<<0) + (1<<1)) /* allow for 4 teams (0-3) */ -#define W_FL_TEAM_SPECIFIC (1<<2) /* waypoint only for specified team */ -#define W_FL_CROUCH (1<<3) /* must crouch to reach this waypoint */ -#define W_FL_LADDER (1<<4) /* waypoint on a ladder */ -#define W_FL_LIFT (1<<5) /* wait for lift to be down before approaching this waypoint */ -#define W_FL_DOOR (1<<6) /* wait for door to open */ -#define W_FL_HEALTH (1<<7) /* health kit (or wall mounted) location */ -#define W_FL_ARMOR (1<<8) /* armor (or HEV) location */ -#define W_FL_AMMO (1<<9) /* ammo location */ -#define W_FL_SNIPER (1<<10) /* sniper waypoint (a good sniper spot) */ - -#define W_FL_TFC_FLAG (1<<11) /* flag position (or hostage or president) */ -#define W_FL_FLF_CAP (1<<11) /* Front Line Force capture point */ - -#define W_FL_TFC_FLAG_GOAL (1<<12) /* flag return position (or rescue zone) */ -#define W_FL_FLF_DEFEND (1<<12) /* Front Line Force defend point */ - -#define W_FL_PRONE (1<<13) /* go prone (laying down) */ -#define W_FL_AIMING (1<<14) /* aiming waypoint */ - -#define W_FL_DELETED (1<<31) /* used by waypoint allocation code */ - - -#define WAYPOINT_VERSION 4 - -// define the waypoint file header structure... -typedef struct { - char filetype[8]; // should be "HPB_bot\0" - int waypoint_file_version; - int waypoint_file_flags; // not currently used - int number_of_waypoints; - char mapname[32]; // name of map for these waypoints -} WAYPOINT_HDR; - - -// define the structure for waypoints... -typedef struct { - int flags; // button, lift, flag, health, ammo, etc. - Vector origin; // location -} WAYPOINT; - - - -#define WAYPOINT_UNREACHABLE USHRT_MAX -#define WAYPOINT_MAX_DISTANCE (USHRT_MAX-1) - -#define MAX_PATH_INDEX 4 - -// define the structure for waypoint paths (paths are connections between -// two waypoint nodes that indicates the bot can get from point A to point B. -// note that paths DON'T have to be two-way. sometimes they are just one-way -// connections between two points. There is an array called "paths" that -// contains head pointers to these structures for each waypoint index. -typedef struct path { - short int index[MAX_PATH_INDEX]; // indexes of waypoints (index -1 means not used) - struct path *next; // link to next structure -} PATH; - - -// waypoint function prototypes... -void WaypointInit(void); -int WaypointFindPath(PATH **pPath, int *path_index, int waypoint_index, int team); -int WaypointFindNearest(edict_t *pEntity, float distance, int team); -int WaypointFindNearest(Vector v_src, edict_t *pEntity, float range, int team); -int WaypointFindNearestGoal(edict_t *pEntity, int src, int team, int flags); -int WaypointFindNearestGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags); -int WaypointFindRandomGoal(edict_t *pEntity, int team, int flags); -int WaypointFindRandomGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags); -int WaypointFindNearestAiming(Vector v_origin); -void WaypointAdd(edict_t *pEntity); -void WaypointAddAiming(edict_t *pEntity); -void WaypointDelete(edict_t *pEntity); -void WaypointCreatePath(edict_t *pEntity, int cmd); -void WaypointRemovePath(edict_t *pEntity, int cmd); -bool WaypointLoad(edict_t *pEntity); -void WaypointSave(void); -bool WaypointReachable(Vector v_srv, Vector v_dest, edict_t *pEntity); -int WaypointFindReachable(edict_t *pEntity, float range, int team); -void WaypointPrintInfo(edict_t *pEntity); -void WaypointThink(edict_t *pEntity); -void WaypointFloyds(short *shortest_path, short *from_to); -void WaypointRouteInit(void); -unsigned short WaypointRouteFromTo(int src, int dest, int team); -int WaypointDistanceFromTo(int src, int dest, int team); - -#endif // WAYPOINT_H +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// waypoint.h +// + +#ifndef WAYPOINT_H +#define WAYPOINT_H + +#include + +#define MAX_WAYPOINTS 1024 + +#define REACHABLE_RANGE 400.0 + +// defines for waypoint flags field (32 bits are available) +#define W_FL_TEAM ((1<<0) + (1<<1)) /* allow for 4 teams (0-3) */ +#define W_FL_TEAM_SPECIFIC (1<<2) /* waypoint only for specified team */ +#define W_FL_CROUCH (1<<3) /* must crouch to reach this waypoint */ +#define W_FL_LADDER (1<<4) /* waypoint on a ladder */ +#define W_FL_LIFT (1<<5) /* wait for lift to be down before approaching this waypoint */ +#define W_FL_DOOR (1<<6) /* wait for door to open */ +#define W_FL_HEALTH (1<<7) /* health kit (or wall mounted) location */ +#define W_FL_ARMOR (1<<8) /* armor (or HEV) location */ +#define W_FL_AMMO (1<<9) /* ammo location */ +#define W_FL_SNIPER (1<<10) /* sniper waypoint (a good sniper spot) */ + +#define W_FL_TFC_FLAG (1<<11) /* flag position (or hostage or president) */ +#define W_FL_FLF_CAP (1<<11) /* Front Line Force capture point */ + +#define W_FL_TFC_FLAG_GOAL (1<<12) /* flag return position (or rescue zone) */ +#define W_FL_FLF_DEFEND (1<<12) /* Front Line Force defend point */ + +#define W_FL_PRONE (1<<13) /* go prone (laying down) */ +#define W_FL_AIMING (1<<14) /* aiming waypoint */ + +#define W_FL_DELETED (1<<31) /* used by waypoint allocation code */ + + +#define WAYPOINT_VERSION 4 + +// define the waypoint file header structure... +typedef struct { + char filetype[8]; // should be "HPB_bot\0" + int waypoint_file_version; + int waypoint_file_flags; // not currently used + int number_of_waypoints; + char mapname[32]; // name of map for these waypoints +} WAYPOINT_HDR; + + +// define the structure for waypoints... +typedef struct { + int flags; // button, lift, flag, health, ammo, etc. + Vector origin; // location +} WAYPOINT; + + + +#define WAYPOINT_UNREACHABLE USHRT_MAX +#define WAYPOINT_MAX_DISTANCE (USHRT_MAX-1) + +#define MAX_PATH_INDEX 4 + +// define the structure for waypoint paths (paths are connections between +// two waypoint nodes that indicates the bot can get from point A to point B. +// note that paths DON'T have to be two-way. sometimes they are just one-way +// connections between two points. There is an array called "paths" that +// contains head pointers to these structures for each waypoint index. +typedef struct path { + short int index[MAX_PATH_INDEX]; // indexes of waypoints (index -1 means not used) + struct path *next; // link to next structure +} PATH; + + +// waypoint function prototypes... +void WaypointInit(void); +int WaypointFindPath(PATH **pPath, int *path_index, int waypoint_index, int team); +int WaypointFindNearest(edict_t *pEntity, float distance, int team); +int WaypointFindNearest(Vector v_src, edict_t *pEntity, float range, int team); +int WaypointFindNearestGoal(edict_t *pEntity, int src, int team, int flags); +int WaypointFindNearestGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags); +int WaypointFindRandomGoal(edict_t *pEntity, int team, int flags); +int WaypointFindRandomGoal(Vector v_src, edict_t *pEntity, float range, int team, int flags); +int WaypointFindNearestAiming(Vector v_origin); +void WaypointAdd(edict_t *pEntity); +void WaypointAddAiming(edict_t *pEntity); +void WaypointDelete(edict_t *pEntity); +void WaypointCreatePath(edict_t *pEntity, int cmd); +void WaypointRemovePath(edict_t *pEntity, int cmd); +bool WaypointLoad(edict_t *pEntity); +void WaypointSave(void); +bool WaypointReachable(Vector v_srv, Vector v_dest, edict_t *pEntity); +int WaypointFindReachable(edict_t *pEntity, float range, int team); +void WaypointPrintInfo(edict_t *pEntity); +void WaypointThink(edict_t *pEntity); +void WaypointFloyds(short *shortest_path, short *from_to); +void WaypointRouteInit(void); +unsigned short WaypointRouteFromTo(int src, int dest, int team); +int WaypointDistanceFromTo(int src, int dest, int team); + +#endif // WAYPOINT_H diff --git a/main/source/HPB_bot/engine/engine.h b/main/source/HPB_bot/engine/engine.h index 02a2c4ee..8d0bb22a 100644 --- a/main/source/HPB_bot/engine/engine.h +++ b/main/source/HPB_bot/engine/engine.h @@ -1,156 +1,156 @@ -// -// HPB_bot - botman's High Ping Bastard bot -// -// (http://planethalflife.com/botman/) -// -// engine.h -// - -#ifndef ENGINE_H -#define ENGINE_H - -// engine prototypes (from engine\eiface.h)... -int pfnPrecacheModel( char* s ); -int pfnPrecacheSound( char* s ); -void pfnSetModel( edict_t *e, const char *m ); -int pfnModelIndex( const char *m ); -int pfnModelFrames( int modelIndex ); -void pfnSetSize( edict_t *e, const float *rgflMin, const float *rgflMax ); -void pfnChangeLevel( char* s1, char* s2 ); -void pfnGetSpawnParms( edict_t *ent ); -void pfnSaveSpawnParms( edict_t *ent ); -float pfnVecToYaw( const float *rgflVector ); -void pfnVecToAngles( const float *rgflVectorIn, float *rgflVectorOut ); -void pfnMoveToOrigin( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); -void pfnChangeYaw( edict_t* ent ); -void pfnChangePitch( edict_t* ent ); -edict_t* pfnFindEntityByString( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue ); -int pfnGetEntityIllum( edict_t* pEnt ); -edict_t* pfnFindEntityInSphere( edict_t *pEdictStartSearchAfter, const float *org, float rad ); -edict_t* pfnFindClientInPVS( edict_t *pEdict ); -edict_t* pfnEntitiesInPVS( edict_t *pplayer ); -void pfnMakeVectors( const float *rgflVector ); -void pfnAngleVectors( const float *rgflVector, float *forward, float *right, float *up ); -edict_t* pfnCreateEntity( void ); -void pfnRemoveEntity( edict_t* e ); -edict_t* pfnCreateNamedEntity( int className ); -void pfnMakeStatic( edict_t *ent ); -int pfnEntIsOnFloor( edict_t *e ); -int pfnDropToFloor( edict_t* e ); -int pfnWalkMove( edict_t *ent, float yaw, float dist, int iMode ); -void pfnSetOrigin( edict_t *e, const float *rgflOrigin ); -void pfnEmitSound( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch ); -void pfnEmitAmbientSound( edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch ); -void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); -void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ); -int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); -void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); -void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); -const char *pfnTraceTexture( edict_t *pTextureEntity, const float *v1, const float *v2 ); -void pfnTraceSphere( const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr ); -void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn ); -void pfnServerCommand( char* str ); -void pfnServerExecute( void ); -void pfnClientCommand( edict_t* pEdict, char* szFmt, ... ); -void pfnParticleEffect( const float *org, const float *dir, float color, float count ); -void pfnLightStyle( int style, char* val ); -int pfnDecalIndex( const char *name ); -int pfnPointContents( const float *rgflVector ); -void pfnMessageBegin( int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ); -void pfnMessageEnd( void ); -void pfnWriteByte( int iValue ); -void pfnWriteChar( int iValue ); -void pfnWriteShort( int iValue ); -void pfnWriteLong( int iValue ); -void pfnWriteAngle( float flValue ); -void pfnWriteCoord( float flValue ); -void pfnWriteString( const char *sz ); -void pfnWriteEntity( int iValue ); -void pfnCVarRegister( cvar_t *pCvar ); -float pfnCVarGetFloat( const char *szVarName ); -const char* pfnCVarGetString( const char *szVarName ); -void pfnCVarSetFloat( const char *szVarName, float flValue ); -void pfnCVarSetString( const char *szVarName, const char *szValue ); -void pfnAlertMessage( ALERT_TYPE atype, char *szFmt, ... ); -void pfnEngineFprintf( FILE *pfile, char *szFmt, ... ); -void* pfnPvAllocEntPrivateData( edict_t *pEdict, long cb ); -void* pfnPvEntPrivateData( edict_t *pEdict ); -void pfnFreeEntPrivateData( edict_t *pEdict ); -const char* pfnSzFromIndex( int iString ); -int pfnAllocString( const char *szValue ); -struct entvars_s* pfnGetVarsOfEnt( edict_t *pEdict ); -edict_t* pfnPEntityOfEntOffset( int iEntOffset ); -int pfnEntOffsetOfPEntity( const edict_t *pEdict ); -int pfnIndexOfEdict( const edict_t *pEdict ); -edict_t* pfnPEntityOfEntIndex( int iEntIndex ); -edict_t* pfnFindEntityByVars( struct entvars_s* pvars ); -void* pfnGetModelPtr( edict_t* pEdict ); -int pfnRegUserMsg( const char *pszName, int iSize ); -void pfnAnimationAutomove( const edict_t* pEdict, float flTime ); -void pfnGetBonePosition( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); -unsigned long pfnFunctionFromName( const char *pName ); -const char *pfnNameForFunction( unsigned long function ); -void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); -void pfnServerPrint( const char *szMsg ); -const char *pfnCmd_Args( void ); -const char *pfnCmd_Argv( int argc ); -int pfnCmd_Argc( void ); -void pfnGetAttachment( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); -void pfnCRC32_Init( CRC32_t *pulCRC ); -void pfnCRC32_ProcessBuffer( CRC32_t *pulCRC, void *p, int len ); -void pfnCRC32_ProcessByte( CRC32_t *pulCRC, unsigned char ch ); -CRC32_t pfnCRC32_Final( CRC32_t pulCRC ); -long pfnRandomLong( long lLow, long lHigh ); -float pfnRandomFloat( float flLow, float flHigh ); -void pfnSetView( const edict_t *pClient, const edict_t *pViewent ); -float pfnTime( void ); -void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw ); -byte * pfnLoadFileForMe( char *filename, int *pLength ); -void pfnFreeFile( void *buffer ); -void pfnEndSection( const char *pszSectionName ); -int pfnCompareFileTime( char *filename1, char *filename2, int *iCompare ); -void pfnGetGameDir( char *szGetGameDir ); -void pfnCvar_RegisterVariable( cvar_t *variable ); -void pfnFadeClientVolume( const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds ); -void pfnSetClientMaxspeed( const edict_t *pEdict, float fNewMaxspeed ); -edict_t * pfnCreateFakeClient( const char *netname ); -void pfnRunPlayerMove( edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); -int pfnNumberOfEntities( void ); -char* pfnGetInfoKeyBuffer( edict_t *e ); -char* pfnInfoKeyValue( char *infobuffer, char *key ); -void pfnSetKeyValue( char *infobuffer, char *key, char *value ); -void pfnSetClientKeyValue( int clientIndex, char *infobuffer, char *key, char *value ); -int pfnIsMapValid( char *filename ); -void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex ); -int pfnPrecacheGeneric( char* s ); -int pfnGetPlayerUserId( edict_t *e ); -void pfnBuildSoundMsg( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ); -int pfnIsDedicatedServer( void ); -cvar_t *pfnCVarGetPointer( const char *szVarName ); -unsigned int pfnGetPlayerWONId( edict_t *e ); - -void pfnInfo_RemoveKey( char *s, const char *key ); -const char *pfnGetPhysicsKeyValue( const edict_t *pClient, const char *key ); -void pfnSetPhysicsKeyValue( const edict_t *pClient, const char *key, const char *value ); -const char *pfnGetPhysicsInfoString( const edict_t *pClient ); -unsigned short pfnPrecacheEvent( int type, const char*psz ); -void pfnPlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); -unsigned char *pfnSetFatPVS( float *org ); -unsigned char *pfnSetFatPAS( float *org ); -int pfnCheckVisibility ( const edict_t *entity, unsigned char *pset ); -void pfnDeltaSetField( struct delta_s *pFields, const char *fieldname ); -void pfnDeltaUnsetField( struct delta_s *pFields, const char *fieldname ); -void pfnDeltaAddEncoder( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); -int pfnGetCurrentPlayer( void ); -int pfnCanSkipPlayer( const edict_t *player ); -int pfnDeltaFindField( struct delta_s *pFields, const char *fieldname ); -void pfnDeltaSetFieldByIndex( struct delta_s *pFields, int fieldNumber ); -void pfnDeltaUnsetFieldByIndex( struct delta_s *pFields, int fieldNumber ); -void pfnSetGroupMask( int mask, int op ); -int pfnCreateInstancedBaseline( int classname, struct entity_state_s *baseline ); -void pfnCvar_DirectSet( struct cvar_s *var, char *value ); -void pfnForceUnmodified( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); -void pfnGetPlayerStats( const edict_t *pClient, int *ping, int *packet_loss ); - -#endif // ENGINE_H - +// +// HPB_bot - botman's High Ping Bastard bot +// +// (http://planethalflife.com/botman/) +// +// engine.h +// + +#ifndef ENGINE_H +#define ENGINE_H + +// engine prototypes (from engine\eiface.h)... +int pfnPrecacheModel( char* s ); +int pfnPrecacheSound( char* s ); +void pfnSetModel( edict_t *e, const char *m ); +int pfnModelIndex( const char *m ); +int pfnModelFrames( int modelIndex ); +void pfnSetSize( edict_t *e, const float *rgflMin, const float *rgflMax ); +void pfnChangeLevel( char* s1, char* s2 ); +void pfnGetSpawnParms( edict_t *ent ); +void pfnSaveSpawnParms( edict_t *ent ); +float pfnVecToYaw( const float *rgflVector ); +void pfnVecToAngles( const float *rgflVectorIn, float *rgflVectorOut ); +void pfnMoveToOrigin( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); +void pfnChangeYaw( edict_t* ent ); +void pfnChangePitch( edict_t* ent ); +edict_t* pfnFindEntityByString( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue ); +int pfnGetEntityIllum( edict_t* pEnt ); +edict_t* pfnFindEntityInSphere( edict_t *pEdictStartSearchAfter, const float *org, float rad ); +edict_t* pfnFindClientInPVS( edict_t *pEdict ); +edict_t* pfnEntitiesInPVS( edict_t *pplayer ); +void pfnMakeVectors( const float *rgflVector ); +void pfnAngleVectors( const float *rgflVector, float *forward, float *right, float *up ); +edict_t* pfnCreateEntity( void ); +void pfnRemoveEntity( edict_t* e ); +edict_t* pfnCreateNamedEntity( int className ); +void pfnMakeStatic( edict_t *ent ); +int pfnEntIsOnFloor( edict_t *e ); +int pfnDropToFloor( edict_t* e ); +int pfnWalkMove( edict_t *ent, float yaw, float dist, int iMode ); +void pfnSetOrigin( edict_t *e, const float *rgflOrigin ); +void pfnEmitSound( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch ); +void pfnEmitAmbientSound( edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch ); +void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); +void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ); +int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); +void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); +void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); +const char *pfnTraceTexture( edict_t *pTextureEntity, const float *v1, const float *v2 ); +void pfnTraceSphere( const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr ); +void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn ); +void pfnServerCommand( char* str ); +void pfnServerExecute( void ); +void pfnClientCommand( edict_t* pEdict, char* szFmt, ... ); +void pfnParticleEffect( const float *org, const float *dir, float color, float count ); +void pfnLightStyle( int style, char* val ); +int pfnDecalIndex( const char *name ); +int pfnPointContents( const float *rgflVector ); +void pfnMessageBegin( int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ); +void pfnMessageEnd( void ); +void pfnWriteByte( int iValue ); +void pfnWriteChar( int iValue ); +void pfnWriteShort( int iValue ); +void pfnWriteLong( int iValue ); +void pfnWriteAngle( float flValue ); +void pfnWriteCoord( float flValue ); +void pfnWriteString( const char *sz ); +void pfnWriteEntity( int iValue ); +void pfnCVarRegister( cvar_t *pCvar ); +float pfnCVarGetFloat( const char *szVarName ); +const char* pfnCVarGetString( const char *szVarName ); +void pfnCVarSetFloat( const char *szVarName, float flValue ); +void pfnCVarSetString( const char *szVarName, const char *szValue ); +void pfnAlertMessage( ALERT_TYPE atype, char *szFmt, ... ); +void pfnEngineFprintf( FILE *pfile, char *szFmt, ... ); +void* pfnPvAllocEntPrivateData( edict_t *pEdict, long cb ); +void* pfnPvEntPrivateData( edict_t *pEdict ); +void pfnFreeEntPrivateData( edict_t *pEdict ); +const char* pfnSzFromIndex( int iString ); +int pfnAllocString( const char *szValue ); +struct entvars_s* pfnGetVarsOfEnt( edict_t *pEdict ); +edict_t* pfnPEntityOfEntOffset( int iEntOffset ); +int pfnEntOffsetOfPEntity( const edict_t *pEdict ); +int pfnIndexOfEdict( const edict_t *pEdict ); +edict_t* pfnPEntityOfEntIndex( int iEntIndex ); +edict_t* pfnFindEntityByVars( struct entvars_s* pvars ); +void* pfnGetModelPtr( edict_t* pEdict ); +int pfnRegUserMsg( const char *pszName, int iSize ); +void pfnAnimationAutomove( const edict_t* pEdict, float flTime ); +void pfnGetBonePosition( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); +unsigned long pfnFunctionFromName( const char *pName ); +const char *pfnNameForFunction( unsigned long function ); +void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); +void pfnServerPrint( const char *szMsg ); +const char *pfnCmd_Args( void ); +const char *pfnCmd_Argv( int argc ); +int pfnCmd_Argc( void ); +void pfnGetAttachment( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); +void pfnCRC32_Init( CRC32_t *pulCRC ); +void pfnCRC32_ProcessBuffer( CRC32_t *pulCRC, void *p, int len ); +void pfnCRC32_ProcessByte( CRC32_t *pulCRC, unsigned char ch ); +CRC32_t pfnCRC32_Final( CRC32_t pulCRC ); +long pfnRandomLong( long lLow, long lHigh ); +float pfnRandomFloat( float flLow, float flHigh ); +void pfnSetView( const edict_t *pClient, const edict_t *pViewent ); +float pfnTime( void ); +void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw ); +byte * pfnLoadFileForMe( char *filename, int *pLength ); +void pfnFreeFile( void *buffer ); +void pfnEndSection( const char *pszSectionName ); +int pfnCompareFileTime( char *filename1, char *filename2, int *iCompare ); +void pfnGetGameDir( char *szGetGameDir ); +void pfnCvar_RegisterVariable( cvar_t *variable ); +void pfnFadeClientVolume( const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds ); +void pfnSetClientMaxspeed( const edict_t *pEdict, float fNewMaxspeed ); +edict_t * pfnCreateFakeClient( const char *netname ); +void pfnRunPlayerMove( edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); +int pfnNumberOfEntities( void ); +char* pfnGetInfoKeyBuffer( edict_t *e ); +char* pfnInfoKeyValue( char *infobuffer, char *key ); +void pfnSetKeyValue( char *infobuffer, char *key, char *value ); +void pfnSetClientKeyValue( int clientIndex, char *infobuffer, char *key, char *value ); +int pfnIsMapValid( char *filename ); +void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex ); +int pfnPrecacheGeneric( char* s ); +int pfnGetPlayerUserId( edict_t *e ); +void pfnBuildSoundMsg( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ); +int pfnIsDedicatedServer( void ); +cvar_t *pfnCVarGetPointer( const char *szVarName ); +unsigned int pfnGetPlayerWONId( edict_t *e ); + +void pfnInfo_RemoveKey( char *s, const char *key ); +const char *pfnGetPhysicsKeyValue( const edict_t *pClient, const char *key ); +void pfnSetPhysicsKeyValue( const edict_t *pClient, const char *key, const char *value ); +const char *pfnGetPhysicsInfoString( const edict_t *pClient ); +unsigned short pfnPrecacheEvent( int type, const char*psz ); +void pfnPlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); +unsigned char *pfnSetFatPVS( float *org ); +unsigned char *pfnSetFatPAS( float *org ); +int pfnCheckVisibility ( const edict_t *entity, unsigned char *pset ); +void pfnDeltaSetField( struct delta_s *pFields, const char *fieldname ); +void pfnDeltaUnsetField( struct delta_s *pFields, const char *fieldname ); +void pfnDeltaAddEncoder( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); +int pfnGetCurrentPlayer( void ); +int pfnCanSkipPlayer( const edict_t *player ); +int pfnDeltaFindField( struct delta_s *pFields, const char *fieldname ); +void pfnDeltaSetFieldByIndex( struct delta_s *pFields, int fieldNumber ); +void pfnDeltaUnsetFieldByIndex( struct delta_s *pFields, int fieldNumber ); +void pfnSetGroupMask( int mask, int op ); +int pfnCreateInstancedBaseline( int classname, struct entity_state_s *baseline ); +void pfnCvar_DirectSet( struct cvar_s *var, char *value ); +void pfnForceUnmodified( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); +void pfnGetPlayerStats( const edict_t *pClient, int *ping, int *packet_loss ); + +#endif // ENGINE_H + diff --git a/main/source/HPB_bot/exports/exports.c b/main/source/HPB_bot/exports/exports.c index 3de4c147..70c376b3 100644 --- a/main/source/HPB_bot/exports/exports.c +++ b/main/source/HPB_bot/exports/exports.c @@ -1,419 +1,419 @@ -// -// (http://planethalflife.com/botman/) -// -// exports.c -// - -#include -#include -#include -#include - - -#define DOS_SIGNATURE 0x5A4D /* MZ */ -#define NT_SIGNATURE 0x00004550 /* PE00 */ - - -// globals -WORD *p_Ordinals = NULL; -DWORD *p_Names = NULL; -DWORD *p_Functions = NULL; -int num_ordinals; - - -typedef struct { // DOS .EXE header - WORD e_magic; // Magic number - WORD e_cblp; // Bytes on last page of file - WORD e_cp; // Pages in file - WORD e_crlc; // Relocations - WORD e_cparhdr; // Size of header in paragraphs - WORD e_minalloc; // Minimum extra paragraphs needed - WORD e_maxalloc; // Maximum extra paragraphs needed - WORD e_ss; // Initial (relative) SS value - WORD e_sp; // Initial SP value - WORD e_csum; // Checksum - WORD e_ip; // Initial IP value - WORD e_cs; // Initial (relative) CS value - WORD e_lfarlc; // File address of relocation table - WORD e_ovno; // Overlay number - WORD e_res[4]; // Reserved words - WORD e_oemid; // OEM identifier (for e_oeminfo) - WORD e_oeminfo; // OEM information; e_oemid specific - WORD e_res2[10]; // Reserved words - LONG e_lfanew; // File address of new exe header - } DOS_HEADER, *P_DOS_HEADER; - -typedef struct { - WORD Machine; - WORD NumberOfSections; - DWORD TimeDateStamp; - DWORD PointerToSymbolTable; - DWORD NumberOfSymbols; - WORD SizeOfOptionalHeader; - WORD Characteristics; -} PE_HEADER, *P_PE_HEADER; - -#define SIZEOF_SHORT_NAME 8 - -typedef struct { - BYTE Name[SIZEOF_SHORT_NAME]; - union { - DWORD PhysicalAddress; - DWORD VirtualSize; - } Misc; - DWORD VirtualAddress; - DWORD SizeOfRawData; - DWORD PointerToRawData; - DWORD PointerToRelocations; - DWORD PointerToLinenumbers; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD Characteristics; -} SECTION_HEADER, *P_SECTION_HEADER; - -typedef struct { - DWORD VirtualAddress; - DWORD Size; -} DATA_DIRECTORY, *P_DATA_DIRECTORY; - -#define NUMBEROF_DIRECTORY_ENTRIES 16 - -typedef struct { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - DWORD SizeOfStackReserve; - DWORD SizeOfStackCommit; - DWORD SizeOfHeapReserve; - DWORD SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - DATA_DIRECTORY DataDirectory[NUMBEROF_DIRECTORY_ENTRIES]; -} OPTIONAL_HEADER, *P_OPTIONAL_HEADER; - -typedef struct { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; // RVA from base of image - DWORD AddressOfNames; // RVA from base of image - DWORD AddressOfNameOrdinals; // RVA from base of image -} EXPORT_DIRECTORY, *P_EXPORT_DIRECTORY; - - -void FreeNameFuncGlobals(void) -{ - if (p_Ordinals) - free(p_Ordinals); - if (p_Functions) - free(p_Functions); - if (p_Names) - free(p_Names); -} - - -void FgetString(char *str, FILE *bfp) -{ - char ch; - - while ((ch = fgetc(bfp)) != EOF) - { - *str++ = ch; - if (ch == 0) - break; - } -} - - -int main(int argc, char *argv[]) -{ - FILE *bfp; - char filename[80]; - BOOL extended = FALSE; - DOS_HEADER dos_header; - LONG nt_signature; - PE_HEADER pe_header; - SECTION_HEADER section_header; - BOOL edata_found; - OPTIONAL_HEADER optional_header; - LONG edata_offset; - LONG edata_delta; - EXPORT_DIRECTORY export_directory; - LONG name_offset; - LONG ordinal_offset; - LONG function_offset; - char function_name[256]; - int i, index; - BOOL error; - //char msg[80]; - - - if (argc < 2) - { - printf("usage: exports [-e] filename.dll\n"); - return -1; - } - - if (argc > 2) - { - if (argv[1][0] == '-') - { - if (argv[1][1] == 'e') - { - strcpy(filename, argv[2]); - extended = TRUE; - } - else - { - printf("unknown option \"%s\"\n\n", argv[1]); - printf("usage: exports [-e] filename.dll\n"); - return -1; - } - } - else - { - printf("usage: exports [-e] filename.dll\n"); - return -1; - } - } - else - strcpy(filename, argv[1]); - - if ((bfp=fopen(filename, "rb")) == NULL) - { - printf("DLL file %s not found!", filename); - return -1; - } - - if (fread(&dos_header, sizeof(dos_header), 1, bfp) != 1) - { - printf("%s is NOT a valid DLL file!", filename); - return -1; - } - - if (dos_header.e_magic != DOS_SIGNATURE) - { - printf("file does not have a valid DLL signature!"); - return -1; - } - - if (fseek(bfp, dos_header.e_lfanew, SEEK_SET) == -1) - { - printf("error seeking to new exe header!"); - return -1; - } - - if (fread(&nt_signature, sizeof(nt_signature), 1, bfp) != 1) - { - printf("file does not have a valid NT signature!"); - return -1; - } - - if (nt_signature != NT_SIGNATURE) - { - printf("file does not have a valid NT signature!"); - return -1; - } - - if (fread(&pe_header, sizeof(pe_header), 1, bfp) != 1) - { - printf("file does not have a valid PE header!"); - return -1; - } - - if (pe_header.SizeOfOptionalHeader == 0) - { - printf("file does not have an optional header!"); - return -1; - } - - if (fread(&optional_header, sizeof(optional_header), 1, bfp) != 1) - { - printf("file does not have a valid optional header!"); - return -1; - } - - edata_found = FALSE; - - for (i=0; i < pe_header.NumberOfSections; i++) - { - if (fread(§ion_header, sizeof(section_header), 1, bfp) != 1) - { - printf("error reading section header!"); - return -1; - } - - if (strcmp((char *)section_header.Name, ".edata") == 0) - { - edata_found = TRUE; - break; - } - } - - if (edata_found) - { - edata_offset = section_header.PointerToRawData; - edata_delta = section_header.VirtualAddress - section_header.PointerToRawData; - } - else - { - edata_offset = optional_header.DataDirectory[0].VirtualAddress; - edata_delta = 0L; - } - - - if (fseek(bfp, edata_offset, SEEK_SET) == -1) - { - printf("file does not have a valid exports section!"); - return -1; - } - - if (fread(&export_directory, sizeof(export_directory), 1, bfp) != 1) - { - printf("file does not have a valid optional header!"); - return -1; - } - - num_ordinals = export_directory.NumberOfNames; // also number of ordinals - - - ordinal_offset = export_directory.AddressOfNameOrdinals - edata_delta; - - if (fseek(bfp, ordinal_offset, SEEK_SET) == -1) - { - printf("file does not have a valid ordinals section!"); - return -1; - } - - if ((p_Ordinals = (WORD *)malloc(num_ordinals * sizeof(WORD))) == NULL) - { - printf("error allocating memory for ordinals section!"); - return -1; - } - - if (fread(p_Ordinals, num_ordinals * sizeof(WORD), 1, bfp) != 1) - { - FreeNameFuncGlobals(); - - printf("error reading ordinals table!"); - return -1; - } - - - function_offset = export_directory.AddressOfFunctions - edata_delta; - - if (fseek(bfp, function_offset, SEEK_SET) == -1) - { - FreeNameFuncGlobals(); - - printf("file does not have a valid export address section!"); - return -1; - } - - if ((p_Functions = (DWORD *)malloc(num_ordinals * sizeof(DWORD))) == NULL) - { - FreeNameFuncGlobals(); - - printf("error allocating memory for export address section!"); - return -1; - } - - if (fread(p_Functions, num_ordinals * sizeof(DWORD), 1, bfp) != 1) - { - FreeNameFuncGlobals(); - - printf("error reading export address section!"); - return -1; - } - - - name_offset = export_directory.AddressOfNames - edata_delta; - - if (fseek(bfp, name_offset, SEEK_SET) == -1) - { - FreeNameFuncGlobals(); - - printf("file does not have a valid names section!"); - return -1; - } - - if ((p_Names = (DWORD *)malloc(num_ordinals * sizeof(DWORD))) == NULL) - { - FreeNameFuncGlobals(); - - printf("error allocating memory for names section!"); - return -1; - } - - if (fread(p_Names, num_ordinals * sizeof(DWORD), 1, bfp) != 1) - { - FreeNameFuncGlobals(); - - printf("error reading names table!"); - return -1; - } - - error = FALSE; - - for (i=0; (i < num_ordinals) && (error==FALSE); i++) - { - name_offset = p_Names[i] - edata_delta; - - if (name_offset != 0) - { - if (fseek(bfp, name_offset, SEEK_SET) == -1) - { - printf("error in loading names section!\n"); - error = TRUE; - } - else - { - FgetString(function_name, bfp); - - if (extended) - { - index = p_Ordinals[i]; - - printf("ordinal=%3d addr=%08lX name=%s\n", - (p_Ordinals[i]+1), p_Functions[index], function_name); - } - else - printf("%s\n", function_name); - } - } - } - - FreeNameFuncGlobals(); - - fclose(bfp); - - return 0; -} - - +// +// (http://planethalflife.com/botman/) +// +// exports.c +// + +#include +#include +#include +#include + + +#define DOS_SIGNATURE 0x5A4D /* MZ */ +#define NT_SIGNATURE 0x00004550 /* PE00 */ + + +// globals +WORD *p_Ordinals = NULL; +DWORD *p_Names = NULL; +DWORD *p_Functions = NULL; +int num_ordinals; + + +typedef struct { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + LONG e_lfanew; // File address of new exe header + } DOS_HEADER, *P_DOS_HEADER; + +typedef struct { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} PE_HEADER, *P_PE_HEADER; + +#define SIZEOF_SHORT_NAME 8 + +typedef struct { + BYTE Name[SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} SECTION_HEADER, *P_SECTION_HEADER; + +typedef struct { + DWORD VirtualAddress; + DWORD Size; +} DATA_DIRECTORY, *P_DATA_DIRECTORY; + +#define NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + DATA_DIRECTORY DataDirectory[NUMBEROF_DIRECTORY_ENTRIES]; +} OPTIONAL_HEADER, *P_OPTIONAL_HEADER; + +typedef struct { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; // RVA from base of image + DWORD AddressOfNames; // RVA from base of image + DWORD AddressOfNameOrdinals; // RVA from base of image +} EXPORT_DIRECTORY, *P_EXPORT_DIRECTORY; + + +void FreeNameFuncGlobals(void) +{ + if (p_Ordinals) + free(p_Ordinals); + if (p_Functions) + free(p_Functions); + if (p_Names) + free(p_Names); +} + + +void FgetString(char *str, FILE *bfp) +{ + char ch; + + while ((ch = fgetc(bfp)) != EOF) + { + *str++ = ch; + if (ch == 0) + break; + } +} + + +int main(int argc, char *argv[]) +{ + FILE *bfp; + char filename[80]; + BOOL extended = FALSE; + DOS_HEADER dos_header; + LONG nt_signature; + PE_HEADER pe_header; + SECTION_HEADER section_header; + BOOL edata_found; + OPTIONAL_HEADER optional_header; + LONG edata_offset; + LONG edata_delta; + EXPORT_DIRECTORY export_directory; + LONG name_offset; + LONG ordinal_offset; + LONG function_offset; + char function_name[256]; + int i, index; + BOOL error; + //char msg[80]; + + + if (argc < 2) + { + printf("usage: exports [-e] filename.dll\n"); + return -1; + } + + if (argc > 2) + { + if (argv[1][0] == '-') + { + if (argv[1][1] == 'e') + { + strcpy(filename, argv[2]); + extended = TRUE; + } + else + { + printf("unknown option \"%s\"\n\n", argv[1]); + printf("usage: exports [-e] filename.dll\n"); + return -1; + } + } + else + { + printf("usage: exports [-e] filename.dll\n"); + return -1; + } + } + else + strcpy(filename, argv[1]); + + if ((bfp=fopen(filename, "rb")) == NULL) + { + printf("DLL file %s not found!", filename); + return -1; + } + + if (fread(&dos_header, sizeof(dos_header), 1, bfp) != 1) + { + printf("%s is NOT a valid DLL file!", filename); + return -1; + } + + if (dos_header.e_magic != DOS_SIGNATURE) + { + printf("file does not have a valid DLL signature!"); + return -1; + } + + if (fseek(bfp, dos_header.e_lfanew, SEEK_SET) == -1) + { + printf("error seeking to new exe header!"); + return -1; + } + + if (fread(&nt_signature, sizeof(nt_signature), 1, bfp) != 1) + { + printf("file does not have a valid NT signature!"); + return -1; + } + + if (nt_signature != NT_SIGNATURE) + { + printf("file does not have a valid NT signature!"); + return -1; + } + + if (fread(&pe_header, sizeof(pe_header), 1, bfp) != 1) + { + printf("file does not have a valid PE header!"); + return -1; + } + + if (pe_header.SizeOfOptionalHeader == 0) + { + printf("file does not have an optional header!"); + return -1; + } + + if (fread(&optional_header, sizeof(optional_header), 1, bfp) != 1) + { + printf("file does not have a valid optional header!"); + return -1; + } + + edata_found = FALSE; + + for (i=0; i < pe_header.NumberOfSections; i++) + { + if (fread(§ion_header, sizeof(section_header), 1, bfp) != 1) + { + printf("error reading section header!"); + return -1; + } + + if (strcmp((char *)section_header.Name, ".edata") == 0) + { + edata_found = TRUE; + break; + } + } + + if (edata_found) + { + edata_offset = section_header.PointerToRawData; + edata_delta = section_header.VirtualAddress - section_header.PointerToRawData; + } + else + { + edata_offset = optional_header.DataDirectory[0].VirtualAddress; + edata_delta = 0L; + } + + + if (fseek(bfp, edata_offset, SEEK_SET) == -1) + { + printf("file does not have a valid exports section!"); + return -1; + } + + if (fread(&export_directory, sizeof(export_directory), 1, bfp) != 1) + { + printf("file does not have a valid optional header!"); + return -1; + } + + num_ordinals = export_directory.NumberOfNames; // also number of ordinals + + + ordinal_offset = export_directory.AddressOfNameOrdinals - edata_delta; + + if (fseek(bfp, ordinal_offset, SEEK_SET) == -1) + { + printf("file does not have a valid ordinals section!"); + return -1; + } + + if ((p_Ordinals = (WORD *)malloc(num_ordinals * sizeof(WORD))) == NULL) + { + printf("error allocating memory for ordinals section!"); + return -1; + } + + if (fread(p_Ordinals, num_ordinals * sizeof(WORD), 1, bfp) != 1) + { + FreeNameFuncGlobals(); + + printf("error reading ordinals table!"); + return -1; + } + + + function_offset = export_directory.AddressOfFunctions - edata_delta; + + if (fseek(bfp, function_offset, SEEK_SET) == -1) + { + FreeNameFuncGlobals(); + + printf("file does not have a valid export address section!"); + return -1; + } + + if ((p_Functions = (DWORD *)malloc(num_ordinals * sizeof(DWORD))) == NULL) + { + FreeNameFuncGlobals(); + + printf("error allocating memory for export address section!"); + return -1; + } + + if (fread(p_Functions, num_ordinals * sizeof(DWORD), 1, bfp) != 1) + { + FreeNameFuncGlobals(); + + printf("error reading export address section!"); + return -1; + } + + + name_offset = export_directory.AddressOfNames - edata_delta; + + if (fseek(bfp, name_offset, SEEK_SET) == -1) + { + FreeNameFuncGlobals(); + + printf("file does not have a valid names section!"); + return -1; + } + + if ((p_Names = (DWORD *)malloc(num_ordinals * sizeof(DWORD))) == NULL) + { + FreeNameFuncGlobals(); + + printf("error allocating memory for names section!"); + return -1; + } + + if (fread(p_Names, num_ordinals * sizeof(DWORD), 1, bfp) != 1) + { + FreeNameFuncGlobals(); + + printf("error reading names table!"); + return -1; + } + + error = FALSE; + + for (i=0; (i < num_ordinals) && (error==FALSE); i++) + { + name_offset = p_Names[i] - edata_delta; + + if (name_offset != 0) + { + if (fseek(bfp, name_offset, SEEK_SET) == -1) + { + printf("error in loading names section!\n"); + error = TRUE; + } + else + { + FgetString(function_name, bfp); + + if (extended) + { + index = p_Ordinals[i]; + + printf("ordinal=%3d addr=%08lX name=%s\n", + (p_Ordinals[i]+1), p_Functions[index], function_name); + } + else + printf("%s\n", function_name); + } + } + } + + FreeNameFuncGlobals(); + + fclose(bfp); + + return 0; +} + + diff --git a/main/source/HPB_bot/exports/exports.dsp b/main/source/HPB_bot/exports/exports.dsp index 65382224..77b1c2b8 100644 --- a/main/source/HPB_bot/exports/exports.dsp +++ b/main/source/HPB_bot/exports/exports.dsp @@ -1,100 +1,100 @@ -# Microsoft Developer Studio Project File - Name="exports" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=exports - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "exports.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "exports.mak" CFG="exports - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "exports - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "exports - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "exports - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "exports - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "exports - Win32 Release" -# Name "exports - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\exports.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="exports" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=exports - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "exports.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "exports.mak" CFG="exports - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "exports - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "exports - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "exports - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "exports - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "exports - Win32 Release" +# Name "exports - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\exports.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/main/source/Natural_Selection.sdf b/main/source/Natural_Selection.sdf index 2a27c4ac..ca8ed647 100644 Binary files a/main/source/Natural_Selection.sdf and b/main/source/Natural_Selection.sdf differ diff --git a/main/source/Natural_Selection.sln b/main/source/Natural_Selection.sln index 2e575208..8f096ebf 100644 --- a/main/source/Natural_Selection.sln +++ b/main/source/Natural_Selection.sln @@ -1,33 +1,35 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cl_dll.dll", "cl_dll\cl_dll.vcxproj", "{665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ns.dll", "dlls\hl.vcxproj", "{BC87A180-F17B-83FC-5D7D-470FAD003ABC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Developer - debug|Win32 = Developer - debug|Win32 - Developer - release|Win32 = Developer - release|Win32 - Playtest - balance disabled|Win32 = Playtest - balance disabled|Win32 - Playtest|Win32 = Playtest|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - debug|Win32.ActiveCfg = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - debug|Win32.Build.0 = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - release|Win32.ActiveCfg = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - release|Win32.Build.0 = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest - balance disabled|Win32.ActiveCfg = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest - balance disabled|Win32.Build.0 = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest|Win32.ActiveCfg = Playtest|Win32 - {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest|Win32.Build.0 = Playtest|Win32 - {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Developer - debug|Win32.ActiveCfg = Developer - debug|Win32 - {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Developer - release|Win32.ActiveCfg = Developer - release|Win32 - {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest - balance disabled|Win32.ActiveCfg = Playtest - balance disabled|Win32 - {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest - balance disabled|Win32.Build.0 = Playtest - balance disabled|Win32 - {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest|Win32.ActiveCfg = Playtest|Win32 - {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest|Win32.Build.0 = Playtest|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cl_dll.dll", "cl_dll\cl_dll.vcxproj", "{665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ns.dll", "dlls\hl.vcxproj", "{BC87A180-F17B-83FC-5D7D-470FAD003ABC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Developer - debug|Win32 = Developer - debug|Win32 + Developer - release|Win32 = Developer - release|Win32 + Playtest - balance disabled|Win32 = Playtest - balance disabled|Win32 + Playtest|Win32 = Playtest|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - debug|Win32.ActiveCfg = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - debug|Win32.Build.0 = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - release|Win32.ActiveCfg = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Developer - release|Win32.Build.0 = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest - balance disabled|Win32.ActiveCfg = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest - balance disabled|Win32.Build.0 = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest|Win32.ActiveCfg = Playtest|Win32 + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8}.Playtest|Win32.Build.0 = Playtest|Win32 + {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Developer - debug|Win32.ActiveCfg = Developer - debug|Win32 + {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Developer - release|Win32.ActiveCfg = Developer - release|Win32 + {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest - balance disabled|Win32.ActiveCfg = Playtest - balance disabled|Win32 + {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest - balance disabled|Win32.Build.0 = Playtest - balance disabled|Win32 + {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest|Win32.ActiveCfg = Playtest|Win32 + {BC87A180-F17B-83FC-5D7D-470FAD003ABC}.Playtest|Win32.Build.0 = Playtest|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/main/source/build.h b/main/source/build.h index 56effb4e..82d12628 100644 --- a/main/source/build.h +++ b/main/source/build.h @@ -1,73 +1,73 @@ -//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= -// -// The copyright to the contents herein is the property of Charles G. Cleveland. -// The contents may be used and/or copied only with the written permission of -// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: build.h $ -// $Date: 2002/11/22 22:09:10 $ -// -//------------------------------------------------------------------------------- -// $Log: build.h,v $ -// Revision 1.17 2002/11/22 22:09:10 Flayra -// - Updated version # -// -// Revision 1.16 2002/11/22 21:07:55 Flayra -// - Removed dev build, use DEBUG instead -// -// Revision 1.15 2002/11/15 19:09:57 Flayra -// - Reworked network metering to be easily toggleable -// -// Revision 1.14 2002/11/12 02:20:25 Flayra -// - Updated version number -// -// Revision 1.13 2002/11/06 01:37:07 Flayra -// - Regular update -// -// Revision 1.12 2002/11/03 04:54:45 Flayra -// - Regular update -// -// Revision 1.11 2002/10/24 21:09:04 Flayra -// - No longer needed -// -// Revision 1.10 2002/10/20 16:33:31 Flayra -// - Regular update -// -// Revision 1.9 2002/10/16 20:48:18 Flayra -// - Regular update -// -// Revision 1.8 2002/10/03 19:07:12 Flayra -// - Profiling switch -// - Regular game version update -// -// Revision 1.7 2002/09/23 21:51:39 Flayra -// - Regular update -// -// Revision 1.6 2002/09/09 19:38:34 Flayra -// - Tried implementing DirectX version of gamma ramp support -// -// Revision 1.5 2002/08/16 02:21:37 Flayra -// - Re-enabled selection -// -// Revision 1.4 2002/08/09 00:14:59 Flayra -// - Removed selection prediction -// -// Revision 1.3 2002/05/23 02:41:53 Flayra -// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development. -// -//=============================================================================== -#ifndef BUILD_H -#define BUILD_H - -// Build in code to help playtest. Choose neither, AVH_PLAYTEST_BUILD, or AVH_PLAYTEST_BUILD _and_ AVH_LAN_PLAYTEST_BUILD -#ifdef DEBUG - #define AVH_PLAYTEST_BUILD -#endif - -//#define PROFILE_BUILD -//#define USE_NETWORK_METERING - +//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= +// +// The copyright to the contents herein is the property of Charles G. Cleveland. +// The contents may be used and/or copied only with the written permission of +// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: build.h $ +// $Date: 2002/11/22 22:09:10 $ +// +//------------------------------------------------------------------------------- +// $Log: build.h,v $ +// Revision 1.17 2002/11/22 22:09:10 Flayra +// - Updated version # +// +// Revision 1.16 2002/11/22 21:07:55 Flayra +// - Removed dev build, use DEBUG instead +// +// Revision 1.15 2002/11/15 19:09:57 Flayra +// - Reworked network metering to be easily toggleable +// +// Revision 1.14 2002/11/12 02:20:25 Flayra +// - Updated version number +// +// Revision 1.13 2002/11/06 01:37:07 Flayra +// - Regular update +// +// Revision 1.12 2002/11/03 04:54:45 Flayra +// - Regular update +// +// Revision 1.11 2002/10/24 21:09:04 Flayra +// - No longer needed +// +// Revision 1.10 2002/10/20 16:33:31 Flayra +// - Regular update +// +// Revision 1.9 2002/10/16 20:48:18 Flayra +// - Regular update +// +// Revision 1.8 2002/10/03 19:07:12 Flayra +// - Profiling switch +// - Regular game version update +// +// Revision 1.7 2002/09/23 21:51:39 Flayra +// - Regular update +// +// Revision 1.6 2002/09/09 19:38:34 Flayra +// - Tried implementing DirectX version of gamma ramp support +// +// Revision 1.5 2002/08/16 02:21:37 Flayra +// - Re-enabled selection +// +// Revision 1.4 2002/08/09 00:14:59 Flayra +// - Removed selection prediction +// +// Revision 1.3 2002/05/23 02:41:53 Flayra +// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development. +// +//=============================================================================== +#ifndef BUILD_H +#define BUILD_H + +// Build in code to help playtest. Choose neither, AVH_PLAYTEST_BUILD, or AVH_PLAYTEST_BUILD _and_ AVH_LAN_PLAYTEST_BUILD +#ifdef DEBUG + #define AVH_PLAYTEST_BUILD +#endif + +//#define PROFILE_BUILD +//#define USE_NETWORK_METERING + #endif \ No newline at end of file diff --git a/main/source/cl_dll/CLabelHeader.h b/main/source/cl_dll/CLabelHeader.h index 0a378528..9482b065 100644 --- a/main/source/cl_dll/CLabelHeader.h +++ b/main/source/cl_dll/CLabelHeader.h @@ -1,193 +1,193 @@ -#ifndef CLABELHEADER_H -#define CLABELHEADER_H - -#include -#include "cl_dll/vgui_TeamFortressViewport.h" - -class CTextImage2 : public Image -{ -public: - CTextImage2() - { - _image[0] = new TextImage(""); - _image[1] = new TextImage(""); - } - - ~CTextImage2() - { - delete _image[0]; - delete _image[1]; - } - - TextImage *GetImage(int image) - { - return _image[image]; - } - - void getSize(int &wide, int &tall) - { - int w1, w2, t1, t2; - _image[0]->getTextSize(w1, t1); - _image[1]->getTextSize(w2, t2); - - wide = w1 + w2; - tall = max(t1, t2); - setSize(wide, tall); - } - - void doPaint(Panel *panel) - { - _image[0]->doPaint(panel); - _image[1]->doPaint(panel); - } - - void setPos(int x, int y) - { - _image[0]->setPos(x, y); - - int swide, stall; - _image[0]->getSize(swide, stall); - - int wide, tall; - _image[1]->getSize(wide, tall); - _image[1]->setPos(x + wide, y + (stall * 0.9) - tall); - } - - void setColor(Color color) - { - _image[0]->setColor(color); - } - - void setColor2(Color color) - { - _image[1]->setColor(color); - } - -private: - TextImage *_image[2]; - -}; - -class CLabelHeader : public Label -{ -public: - CLabelHeader() : Label("") - { - _dualImage = new CTextImage2(); - _dualImage->setColor2(Color(255, 170, 0, 0)); - _row = -2; - _useFgColorAsImageColor = true; - _offset[0] = 0; - _offset[1] = 0; - } - - ~CLabelHeader() - { - delete _dualImage; - } - - void setRow(int row) - { - _row = row; - } - - void setFgColorAsImageColor(bool state) - { - _useFgColorAsImageColor = state; - } - - virtual void setText(int textBufferLen, const char* text) - { - _dualImage->GetImage(0)->setText(text); - - // calculate the text size - Font *font = _dualImage->GetImage(0)->getFont(); - _gap = 0; - for (const char *ch = text; *ch != 0; ch++) - { - int a, b, c; - font->getCharABCwide(*ch, a, b, c); - _gap += (a + b + c); - } - - _gap += XRES(5); - } - - virtual void setText(const char* text) - { - // strip any non-alnum characters from the end - char buf[512]; - strcpy(buf, text); - - size_t len = strlen(buf); - while (len && isspace(buf[--len])) - { - buf[len] = 0; - } - - CLabelHeader::setText(0, buf); - } - - void setText2(const char *text) - { - _dualImage->GetImage(1)->setText(text); - } - - void getTextSize(int &wide, int &tall) - { - _dualImage->getSize(wide, tall); - } - - void setFgColor(int r,int g,int b,int a) - { - Label::setFgColor(r,g,b,a); - Color color(r,g,b,a); - _dualImage->setColor(color); - _dualImage->setColor2(color); - if (_image && _useFgColorAsImageColor) - { - _image->setColor(color); - } - repaint(); - } - - void setFgColor(Scheme::SchemeColor sc) - { - int r, g, b, a; - Label::setFgColor(sc); - Label::getFgColor( r, g, b, a ); - - // Call the r,g,b,a version so it sets the color in the dualImage.. - setFgColor( r, g, b, a ); - } - - void setFont(Font *font) - { - _dualImage->GetImage(0)->setFont(font); - } - - void setFont2(Font *font) - { - _dualImage->GetImage(1)->setFont(font); - } - - // this adjust the absolute position of the text after alignment is calculated - void setTextOffset(int x, int y) - { - _offset[0] = x; - _offset[1] = y; - } - - void paint(); - void paintBackground(); - void calcAlignment(int iwide, int itall, int &x, int &y); - -private: - CTextImage2 *_dualImage; - int _row; - int _gap; - int _offset[2]; - bool _useFgColorAsImageColor; -}; - +#ifndef CLABELHEADER_H +#define CLABELHEADER_H + +#include +#include "cl_dll/vgui_TeamFortressViewport.h" + +class CTextImage2 : public Image +{ +public: + CTextImage2() + { + _image[0] = new TextImage(""); + _image[1] = new TextImage(""); + } + + ~CTextImage2() + { + delete _image[0]; + delete _image[1]; + } + + TextImage *GetImage(int image) + { + return _image[image]; + } + + void getSize(int &wide, int &tall) + { + int w1, w2, t1, t2; + _image[0]->getTextSize(w1, t1); + _image[1]->getTextSize(w2, t2); + + wide = w1 + w2; + tall = max(t1, t2); + setSize(wide, tall); + } + + void doPaint(Panel *panel) + { + _image[0]->doPaint(panel); + _image[1]->doPaint(panel); + } + + void setPos(int x, int y) + { + _image[0]->setPos(x, y); + + int swide, stall; + _image[0]->getSize(swide, stall); + + int wide, tall; + _image[1]->getSize(wide, tall); + _image[1]->setPos(x + wide, y + (stall * 0.9) - tall); + } + + void setColor(Color color) + { + _image[0]->setColor(color); + } + + void setColor2(Color color) + { + _image[1]->setColor(color); + } + +private: + TextImage *_image[2]; + +}; + +class CLabelHeader : public Label +{ +public: + CLabelHeader() : Label("") + { + _dualImage = new CTextImage2(); + _dualImage->setColor2(Color(255, 170, 0, 0)); + _row = -2; + _useFgColorAsImageColor = true; + _offset[0] = 0; + _offset[1] = 0; + } + + ~CLabelHeader() + { + delete _dualImage; + } + + void setRow(int row) + { + _row = row; + } + + void setFgColorAsImageColor(bool state) + { + _useFgColorAsImageColor = state; + } + + virtual void setText(int textBufferLen, const char* text) + { + _dualImage->GetImage(0)->setText(text); + + // calculate the text size + Font *font = _dualImage->GetImage(0)->getFont(); + _gap = 0; + for (const char *ch = text; *ch != 0; ch++) + { + int a, b, c; + font->getCharABCwide(*ch, a, b, c); + _gap += (a + b + c); + } + + _gap += XRES(5); + } + + virtual void setText(const char* text) + { + // strip any non-alnum characters from the end + char buf[512]; + strcpy(buf, text); + + size_t len = strlen(buf); + while (len && isspace(buf[--len])) + { + buf[len] = 0; + } + + CLabelHeader::setText(0, buf); + } + + void setText2(const char *text) + { + _dualImage->GetImage(1)->setText(text); + } + + void getTextSize(int &wide, int &tall) + { + _dualImage->getSize(wide, tall); + } + + void setFgColor(int r,int g,int b,int a) + { + Label::setFgColor(r,g,b,a); + Color color(r,g,b,a); + _dualImage->setColor(color); + _dualImage->setColor2(color); + if (_image && _useFgColorAsImageColor) + { + _image->setColor(color); + } + repaint(); + } + + void setFgColor(Scheme::SchemeColor sc) + { + int r, g, b, a; + Label::setFgColor(sc); + Label::getFgColor( r, g, b, a ); + + // Call the r,g,b,a version so it sets the color in the dualImage.. + setFgColor( r, g, b, a ); + } + + void setFont(Font *font) + { + _dualImage->GetImage(0)->setFont(font); + } + + void setFont2(Font *font) + { + _dualImage->GetImage(1)->setFont(font); + } + + // this adjust the absolute position of the text after alignment is calculated + void setTextOffset(int x, int y) + { + _offset[0] = x; + _offset[1] = y; + } + + void paint(); + void paintBackground(); + void calcAlignment(int iwide, int itall, int &x, int &y); + +private: + CTextImage2 *_dualImage; + int _row; + int _gap; + int _offset[2]; + bool _useFgColorAsImageColor; +}; + #endif \ No newline at end of file diff --git a/main/source/cl_dll/GameStudioModelRenderer.cpp b/main/source/cl_dll/GameStudioModelRenderer.cpp index 67c73dee..71d0c50c 100644 --- a/main/source/cl_dll/GameStudioModelRenderer.cpp +++ b/main/source/cl_dll/GameStudioModelRenderer.cpp @@ -1,116 +1,116 @@ -#include -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/com_model.h" -#include "engine/studio.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "common/dlight.h" -#include "common/triangleapi.h" - -#include -#include -#include -#include - -#include "studio_util.h" -#include "r_studioint.h" - -#include "StudioModelRenderer.h" -#include "GameStudioModelRenderer.h" - -#include "engine/APIProxy.h" -#include "Exports.h" - -// -// Override the StudioModelRender virtual member functions here to implement custom bone -// setup, blending, etc. -// - -// Global engine <-> studio model rendering code interface -extern engine_studio_api_t IEngineStudio; - -// The renderer object, created on the stack. -CGameStudioModelRenderer g_StudioRenderer; -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -CGameStudioModelRenderer::CGameStudioModelRenderer( void ) -{ -} - -//////////////////////////////////// -// Hooks to class implementation -//////////////////////////////////// - -/* -==================== -R_StudioDrawPlayer - -==================== -*/ -int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); -} - -/* -==================== -R_StudioDrawModel - -==================== -*/ -int R_StudioDrawModel( int flags ) -{ - return g_StudioRenderer.StudioDrawModel( flags ); -} - -/* -==================== -R_StudioInit - -==================== -*/ -void R_StudioInit( void ) -{ - g_StudioRenderer.Init(); -} - -// The simple drawing interface we'll pass back to the engine -r_studio_interface_t studio = -{ - STUDIO_INTERFACE_VERSION, - R_StudioDrawModel, - R_StudioDrawPlayer, -}; - -/* -==================== -HUD_GetStudioModelInterface - -Export this function for the engine to use the studio renderer class to render objects. -==================== -*/ -extern "C" int CL_DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) -{ -// RecClStudioInterface(version, ppinterface, pstudio); - - if ( version != STUDIO_INTERFACE_VERSION ) - return 0; - - // Point the engine to our callbacks - *ppinterface = &studio; - - // Copy in engine helper functions - memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); - - // Initialize local variables, etc. - R_StudioInit(); - - // Success - return 1; -} +#include +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/com_model.h" +#include "engine/studio.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "common/dlight.h" +#include "common/triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +#include "engine/APIProxy.h" +#include "Exports.h" + +// +// Override the StudioModelRender virtual member functions here to implement custom bone +// setup, blending, etc. +// + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +extern "C" int CL_DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ +// RecClStudioInterface(version, ppinterface, pstudio); + + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/main/source/cl_dll/GameStudioModelRenderer.h b/main/source/cl_dll/GameStudioModelRenderer.h index 92c596e6..7b37d8c9 100644 --- a/main/source/cl_dll/GameStudioModelRenderer.h +++ b/main/source/cl_dll/GameStudioModelRenderer.h @@ -1,19 +1,19 @@ -#if !defined( GAMESTUDIOMODELRENDERER_H ) -#define GAMESTUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif - -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -class CGameStudioModelRenderer : public CStudioModelRenderer -{ -public: - CGameStudioModelRenderer( void ); -}; - +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); +}; + #endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/main/source/cl_dll/GameStudioModelRenderer_Sample.cpp b/main/source/cl_dll/GameStudioModelRenderer_Sample.cpp index d9592b05..03a69707 100644 --- a/main/source/cl_dll/GameStudioModelRenderer_Sample.cpp +++ b/main/source/cl_dll/GameStudioModelRenderer_Sample.cpp @@ -1,985 +1,985 @@ -#include -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "com_model.h" -#include "studio.h" -#include "entity_state.h" -#include "cl_entity.h" -#include "dlight.h" -#include "triangleapi.h" - -#include -#include -#include -#include - -#include "studio_util.h" -#include "r_studioint.h" - -#include "StudioModelRenderer.h" -#include "GameStudioModelRenderer.h" - -// Predicted values saved off in hl_weapons.cpp -void Game_GetSequence( int *seq, int *gaitseq ); -void Game_GetOrientation( float *o, float *a ); - -float g_flStartScaleTime; -int iPrevRenderState; -int iRenderStateChanged; - -// Global engine <-> studio model rendering code interface -extern engine_studio_api_t IEngineStudio; - -typedef struct -{ - vec3_t origin; - vec3_t angles; - - vec3_t realangles; - - float animtime; - float frame; - int sequence; - int gaitsequence; - float framerate; - - int m_fSequenceLoops; - int m_fSequenceFinished; - - byte controller[ 4 ]; - byte blending[ 2 ]; - - latchedvars_t lv; -} client_anim_state_t; - -static client_anim_state_t g_state; -static client_anim_state_t g_clientstate; - -// The renderer object, created on the stack. -CGameStudioModelRenderer g_StudioRenderer; -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -CGameStudioModelRenderer::CGameStudioModelRenderer( void ) -{ - // If you want to predict animations locally, set this to TRUE - // NOTE: The animation code is somewhat broken, but gives you a sense for how - // to do client side animation of the predicted player in a third person game. - m_bLocal = false; -} - -/* -==================== -StudioSetupBones - -==================== -*/ -void CGameStudioModelRenderer::StudioSetupBones ( void ) -{ - int i; - double f; - - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; - - static float pos[MAXSTUDIOBONES][3]; - static vec4_t q[MAXSTUDIOBONES]; - float bonematrix[3][4]; - - static float pos2[MAXSTUDIOBONES][3]; - static vec4_t q2[MAXSTUDIOBONES]; - static float pos3[MAXSTUDIOBONES][3]; - static vec4_t q3[MAXSTUDIOBONES]; - static float pos4[MAXSTUDIOBONES][3]; - static vec4_t q4[MAXSTUDIOBONES]; - - // Use default bone setup for nonplayers - if ( !m_pCurrentEntity->player ) - { - CStudioModelRenderer::StudioSetupBones(); - return; - } - - // Bound sequence number. - if ( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - if ( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) - { - f = m_pPlayerInfo->gaitframe; - } - else - { - f = StudioEstimateFrame( pseqdesc ); - } - - // This game knows how to do three way blending - if ( pseqdesc->numblends == 3 ) - { - float s; - - // Get left anim - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - - // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right - if ( m_pCurrentEntity->curstate.blending[0] <= 127 ) - { - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - // Scale 0-127 blending up to 0-255 - s = m_pCurrentEntity->curstate.blending[0]; - s = ( s * 2.0 ); - } - else - { - - // Skip ahead to middle - panim += m_pStudioHeader->numbones; - - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - // Scale 127-255 blending up to 0-255 - s = m_pCurrentEntity->curstate.blending[0]; - s = 2.0 * ( s - 127.0 ); - } - - // Normalize interpolant - s /= 255.0; - - // Go to middle or right - panim += m_pStudioHeader->numbones; - - StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); - - // Spherically interpolate the bones - StudioSlerpBones( q, pos, q2, pos2, s ); - } - else - { - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - } - - // Are we in the process of transitioning from one sequence to another. - if ( m_fDoInterp && - m_pCurrentEntity->latched.sequencetime && - ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && - ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) - { - // blend from last sequence - static float pos1b[MAXSTUDIOBONES][3]; - static vec4_t q1b[MAXSTUDIOBONES]; - float s; - - // Blending value into last sequence - unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[ 0 ]; - - // Point at previous sequenece - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; - - // Know how to do three way blends - if ( pseqdesc->numblends == 3 ) - { - float s; - - // Get left animation - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - - if ( prevseqblending <= 127 ) - { - // Set up bones based on final frame of previous sequence - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = prevseqblending; - s = ( s * 2.0 ); - } - else - { - // Skip to middle blend - panim += m_pStudioHeader->numbones; - - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = prevseqblending; - s = 2.0 * ( s - 127.0 ); - } - - // Normalize - s /= 255.0; - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - // Interpolate bones - StudioSlerpBones( q1b, pos1b, q2, pos2, s ); - } - else - { - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - // clip prevframe - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - } - - // Now blend last frame of previous sequence with current sequence. - s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; - StudioSlerpBones( q, pos, q1b, pos1b, s ); - } - else - { - m_pCurrentEntity->latched.prevframe = f; - } - - // Now convert quaternions and bone positions into matrices - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - QuaternionMatrix( q[i], bonematrix ); - - bonematrix[0][3] = pos[i][0]; - bonematrix[1][3] = pos[i][1]; - bonematrix[2][3] = pos[i][2]; - - if (pbones[i].parent == -1) - { - if ( IEngineStudio.IsHardware() ) - { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - else - { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - - // Apply client-side effects to the transformation matrix - StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); - } - else - { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); - } - } -} - -/* -==================== -StudioEstimateGait - -==================== -*/ -void CGameStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) -{ - float dt; - vec3_t est_velocity; - - dt = (m_clTime - m_clOldTime); - dt = max( 0.0, dt ); - dt = min( 1.0, dt ); - - if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) - { - m_flGaitMovement = 0; - return; - } - - // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); - if ( m_fGaitEstimation ) - { - VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); - VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); - m_flGaitMovement = Length( est_velocity ); - if (dt <= 0 || m_flGaitMovement / dt < 5) - { - m_flGaitMovement = 0; - est_velocity[0] = 0; - est_velocity[1] = 0; - } - } - else - { - VectorCopy( pplayer->velocity, est_velocity ); - m_flGaitMovement = Length( est_velocity ) * dt; - } - - if (est_velocity[1] == 0 && est_velocity[0] == 0) - { - float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; - if (flYawDiff > 180) - flYawDiff -= 360; - if (flYawDiff < -180) - flYawDiff += 360; - - if (dt < 0.25) - flYawDiff *= dt * 4; - else - flYawDiff *= dt; - - m_pPlayerInfo->gaityaw += flYawDiff; - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; - - m_flGaitMovement = 0; - } - else - { - m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); - if (m_pPlayerInfo->gaityaw > 180) - m_pPlayerInfo->gaityaw = 180; - if (m_pPlayerInfo->gaityaw < -180) - m_pPlayerInfo->gaityaw = -180; - } - -} - -/* -==================== -StudioProcessGait - -==================== -*/ -void CGameStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) -{ - mstudioseqdesc_t *pseqdesc; - float dt; - float flYaw; // view direction relative to movement - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - m_pCurrentEntity->angles[PITCH] = 0; - m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; - - dt = (m_clTime - m_clOldTime); - dt = max( 0.0, dt ); - dt = min( 1.0, dt ); - - StudioEstimateGait( pplayer ); - - // calc side to side turning - flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - - flYaw = fmod( flYaw, 360.0 ); - - if (flYaw < -180) - { - flYaw = flYaw + 360; - } - else if (flYaw > 180) - { - flYaw = flYaw - 360; - } - - float maxyaw = 120.0; - - if (flYaw > maxyaw) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw - 180; - } - else if (flYaw < -maxyaw) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw + 180; - } - - float blend_yaw = ( flYaw / 90.0 ) * 128.0 + 127.0; - blend_yaw = min( 255.0, blend_yaw ); - blend_yaw = max( 0.0, blend_yaw ); - - blend_yaw = 255.0 - blend_yaw; - - m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw); - m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; - m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; - - m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; - if (m_pCurrentEntity->angles[YAW] < -0) - { - m_pCurrentEntity->angles[YAW] += 360; - } - m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; - - // Calc gait frame - if (pseqdesc->linearmovement[0] > 0) - { - m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; - } - else - { - m_pPlayerInfo->gaitframe += pseqdesc->fps * dt * m_pCurrentEntity->curstate.framerate; - } - - // Do modulo - m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; - if (m_pPlayerInfo->gaitframe < 0) - { - m_pPlayerInfo->gaitframe += pseqdesc->numframes; - } -} - -/* -============================== -SavePlayerState - -For local player, in third person, we need to store real render data and then - setup for with fake/client side animation data -============================== -*/ -void CGameStudioModelRenderer::SavePlayerState( entity_state_t *pplayer ) -{ - client_anim_state_t *st; - cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); - assert( ent ); - if ( !ent ) - return; - - st = &g_state; - - st->angles = ent->curstate.angles; - st->origin = ent->curstate.origin; - - st->realangles = ent->angles; - - st->sequence = ent->curstate.sequence; - st->gaitsequence = pplayer->gaitsequence; - st->animtime = ent->curstate.animtime; - st->frame = ent->curstate.frame; - st->framerate = ent->curstate.framerate; - memcpy( st->blending, ent->curstate.blending, 2 ); - memcpy( st->controller, ent->curstate.controller, 4 ); - - st->lv = ent->latched; -} - -void GetSequenceInfo( void *pmodel, client_anim_state_t *pev, float *pflFrameRate, float *pflGroundSpeed ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - mstudioseqdesc_t *pseqdesc; - - if (pev->sequence >= pstudiohdr->numseq) - { - *pflFrameRate = 0.0; - *pflGroundSpeed = 0.0; - return; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->numframes > 1) - { - *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); - *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); - *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); - } - else - { - *pflFrameRate = 256.0; - *pflGroundSpeed = 0.0; - } -} - -int GetSequenceFlags( void *pmodel, client_anim_state_t *pev ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) - return 0; - - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - return pseqdesc->flags; -} - -float StudioFrameAdvance ( client_anim_state_t *st, float framerate, float flInterval ) -{ - if (flInterval == 0.0) - { - flInterval = (gEngfuncs.GetClientTime() - st->animtime); - if (flInterval <= 0.001) - { - st->animtime = gEngfuncs.GetClientTime(); - return 0.0; - } - } - if (!st->animtime) - flInterval = 0.0; - - st->frame += flInterval * framerate * st->framerate; - st->animtime = gEngfuncs.GetClientTime(); - - if (st->frame < 0.0 || st->frame >= 256.0) - { - if ( st->m_fSequenceLoops ) - st->frame -= (int)(st->frame / 256.0) * 256.0; - else - st->frame = (st->frame < 0.0) ? 0 : 255; - st->m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents - } - - return flInterval; -} - -/* -============================== -SetupClientAnimation - -Called to set up local player's animation values -============================== -*/ -void CGameStudioModelRenderer::SetupClientAnimation( entity_state_t *pplayer ) -{ - static double oldtime; - double curtime, dt; - - client_anim_state_t *st; - float fr, gs; - - cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); - assert( ent ); - if ( !ent ) - return; - - curtime = gEngfuncs.GetClientTime(); - dt = curtime - oldtime; - dt = min( 1.0, max( 0.0, dt ) ); - - oldtime = curtime; - st = &g_clientstate; - - st->framerate = 1.0; - - int oldseq = st->sequence; - Game_GetSequence( &st->sequence, &st->gaitsequence ); //CVAR_GET_FLOAT( "sequence" ); - Game_GetOrientation( (float *)&st->origin, (float *)&st->angles ); - st->realangles = st->angles; - - if ( st->sequence != oldseq ) - { - st->frame = 0.0; - st->lv.prevsequence = oldseq; - st->lv.sequencetime = st->animtime; - - memcpy( st->lv.prevseqblending, st->blending, 2 ); - memcpy( st->lv.prevcontroller, st->controller, 4 ); - } - - void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( ent->model ); - - GetSequenceInfo( pmodel, st, &fr, &gs ); - st->m_fSequenceLoops = ((GetSequenceFlags( pmodel, st ) & STUDIO_LOOPING) != 0); - StudioFrameAdvance( st, fr, dt ); - -// gEngfuncs.Con_Printf( "gs %i frame %f\n", st->gaitsequence, st->frame ); - - ent->angles = st->realangles; - ent->curstate.angles = st->angles; - ent->curstate.origin = st->origin; - - ent->curstate.sequence = st->sequence; - pplayer->gaitsequence = st->gaitsequence; - ent->curstate.animtime = st->animtime; - ent->curstate.frame = st->frame; - ent->curstate.framerate = st->framerate; - memcpy( ent->curstate.blending, st->blending, 2 ); - memcpy( ent->curstate.controller, st->controller, 4 ); - - ent->latched = st->lv; -} - -/* -============================== -RestorePlayerState - -Called to restore original player state information -============================== -*/ -void CGameStudioModelRenderer::RestorePlayerState( entity_state_t *pplayer ) -{ - client_anim_state_t *st; - cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); - assert( ent ); - if ( !ent ) - return; - - st = &g_clientstate; - - st->angles = ent->curstate.angles; - st->origin = ent->curstate.origin; - st->realangles = ent->angles; - - st->sequence = ent->curstate.sequence; - st->gaitsequence = pplayer->gaitsequence; - st->animtime = ent->curstate.animtime; - st->frame = ent->curstate.frame; - st->framerate = ent->curstate.framerate; - memcpy( st->blending, ent->curstate.blending, 2 ); - memcpy( st->controller, ent->curstate.controller, 4 ); - - st->lv = ent->latched; - - st = &g_state; - - ent->curstate.angles = st->angles; - ent->curstate.origin = st->origin; - ent->angles = st->realangles; - - ent->curstate.sequence = st->sequence; - pplayer->gaitsequence = st->gaitsequence; - ent->curstate.animtime = st->animtime; - ent->curstate.frame = st->frame; - ent->curstate.framerate = st->framerate; - memcpy( ent->curstate.blending, st->blending, 2 ); - memcpy( ent->curstate.controller, st->controller, 4 ); - - ent->latched = st->lv; -} - -/* -============================== -StudioDrawPlayer - -============================== -*/ -int CGameStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - int iret = 0; - - bool isLocalPlayer = false; - - // Set up for client? - if ( m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer() ) - { - isLocalPlayer = true; - } - - if ( isLocalPlayer ) - { - // Store original data - SavePlayerState( pplayer ); - - // Copy in client side animation data - SetupClientAnimation( pplayer ); - } - - // Call real draw function - iret = _StudioDrawPlayer( flags, pplayer ); - - // Restore for client? - if ( isLocalPlayer ) - { - // Restore the original data for the player - RestorePlayerState( pplayer ); - } - - return iret; -} - -/* -==================== -_StudioDrawPlayer - -==================== -*/ -int CGameStudioModelRenderer::_StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - alight_t lighting; - vec3_t dir; - - m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); - IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); - IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); - IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - - m_nPlayerIndex = pplayer->number - 1; - - if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) - return 0; - - m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); - if (m_pRenderModel == NULL) - return 0; - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - IEngineStudio.SetRenderModel( m_pRenderModel ); - - if (pplayer->gaitsequence) - { - vec3_t orig_angles; - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - VectorCopy( m_pCurrentEntity->angles, orig_angles ); - - StudioProcessGait( pplayer ); - - m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; - m_pPlayerInfo = NULL; - - StudioSetUpTransform( 0 ); - VectorCopy( orig_angles, m_pCurrentEntity->angles ); - } - else - { - m_pCurrentEntity->curstate.controller[0] = 127; - m_pCurrentEntity->curstate.controller[1] = 127; - m_pCurrentEntity->curstate.controller[2] = 127; - m_pCurrentEntity->curstate.controller[3] = 127; - m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; - m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; - m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; - m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - m_pPlayerInfo->gaitsequence = 0; - - StudioSetUpTransform( 0 ); - } - - if (flags & STUDIO_RENDER) - { - // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) - return 0; - - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie - - if (m_pStudioHeader->numbodyparts == 0) - return 1; - } - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - StudioSetupBones( ); - StudioSaveBones( ); - m_pPlayerInfo->renderframe = m_nFrameCount; - - m_pPlayerInfo = NULL; - - if (flags & STUDIO_EVENTS) - { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); - // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); - } - } - - if (flags & STUDIO_RENDER) - { - /* - if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) - { - // show highest resolution multiplayer model - m_pCurrentEntity->curstate.body = 255; - } - - if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) - { - m_pCurrentEntity->curstate.body = 1; // force helmet - } - */ - - lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); - - IEngineStudio.StudioEntityLight( &lighting ); - - // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - // get remap colors - m_nTopColor = m_pPlayerInfo->topcolor; - if (m_nTopColor < 0) - m_nTopColor = 0; - if (m_nTopColor > 360) - m_nTopColor = 360; - m_nBottomColor = m_pPlayerInfo->bottomcolor; - if (m_nBottomColor < 0) - m_nBottomColor = 0; - if (m_nBottomColor > 360) - m_nBottomColor = 360; - - IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - - StudioRenderModel( ); - m_pPlayerInfo = NULL; - - if (pplayer->weaponmodel) - { - cl_entity_t saveent = *m_pCurrentEntity; - - model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - - StudioMergeBones( pweaponmodel); - - IEngineStudio.StudioSetupLighting (&lighting); - - StudioRenderModel( ); - - StudioCalcAttachments( ); - - *m_pCurrentEntity = saveent; - } - } - - return 1; -} - -/* -==================== -Studio_FxTransform - -==================== -*/ -void CGameStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) -{ - switch( ent->curstate.renderfx ) - { - case kRenderFxDistort: - case kRenderFxHologram: - if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); - } - else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - float offset; - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - offset = gEngfuncs.pfnRandomFloat(-10,10); - transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; - } - break; - case kRenderFxExplode: - { - if ( iRenderStateChanged ) - { - g_flStartScaleTime = m_clTime; - iRenderStateChanged = FALSE; - } - - // Make the Model continue to shrink - float flTimeDelta = m_clTime - g_flStartScaleTime; - if ( flTimeDelta > 0 ) - { - float flScale = 0.001; - // Goes almost all away - if ( flTimeDelta <= 2.0 ) - flScale = 1.0 - (flTimeDelta / 2.0); - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - transform[i][j] *= flScale; - } - } - } - break; - } -} - -//////////////////////////////////// -// Hooks to class implementation -//////////////////////////////////// - -/* -==================== -R_StudioDrawPlayer - -==================== -*/ -int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); -} - -/* -==================== -R_StudioDrawModel - -==================== -*/ -int R_StudioDrawModel( int flags ) -{ - return g_StudioRenderer.StudioDrawModel( flags ); -} - -/* -==================== -R_StudioInit - -==================== -*/ -void R_StudioInit( void ) -{ - g_StudioRenderer.Init(); -} - -// The simple drawing interface we'll pass back to the engine -r_studio_interface_t studio = -{ - STUDIO_INTERFACE_VERSION, - R_StudioDrawModel, - R_StudioDrawPlayer, -}; - -/* -==================== -HUD_GetStudioModelInterface - -Export this function for the engine to use the studio renderer class to render objects. -==================== -*/ -#define DLLEXPORT __declspec( dllexport ) -extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) -{ - if ( version != STUDIO_INTERFACE_VERSION ) - return 0; - - // Point the engine to our callbacks - *ppinterface = &studio; - - // Copy in engine helper functions - memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); - - // Initialize local variables, etc. - R_StudioInit(); - - // Success - return 1; -} +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Predicted values saved off in hl_weapons.cpp +void Game_GetSequence( int *seq, int *gaitseq ); +void Game_GetOrientation( float *o, float *a ); + +float g_flStartScaleTime; +int iPrevRenderState; +int iRenderStateChanged; + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +typedef struct +{ + vec3_t origin; + vec3_t angles; + + vec3_t realangles; + + float animtime; + float frame; + int sequence; + int gaitsequence; + float framerate; + + int m_fSequenceLoops; + int m_fSequenceFinished; + + byte controller[ 4 ]; + byte blending[ 2 ]; + + latchedvars_t lv; +} client_anim_state_t; + +static client_anim_state_t g_state; +static client_anim_state_t g_clientstate; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ + // If you want to predict animations locally, set this to TRUE + // NOTE: The animation code is somewhat broken, but gives you a sense for how + // to do client side animation of the predicted player in a third person game. + m_bLocal = false; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CGameStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + // Use default bone setup for nonplayers + if ( !m_pCurrentEntity->player ) + { + CStudioModelRenderer::StudioSetupBones(); + return; + } + + // Bound sequence number. + if ( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + if ( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) + { + f = m_pPlayerInfo->gaitframe; + } + else + { + f = StudioEstimateFrame( pseqdesc ); + } + + // This game knows how to do three way blending + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left anim + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right + if ( m_pCurrentEntity->curstate.blending[0] <= 127 ) + { + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 0-127 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = ( s * 2.0 ); + } + else + { + + // Skip ahead to middle + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 127-255 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize interpolant + s /= 255.0; + + // Go to middle or right + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + // Spherically interpolate the bones + StudioSlerpBones( q, pos, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + } + + // Are we in the process of transitioning from one sequence to another. + if ( m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + // Blending value into last sequence + unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[ 0 ]; + + // Point at previous sequenece + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + + // Know how to do three way blends + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left animation + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + if ( prevseqblending <= 127 ) + { + // Set up bones based on final frame of previous sequence + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = ( s * 2.0 ); + } + else + { + // Skip to middle blend + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize + s /= 255.0; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + // Interpolate bones + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + } + + // Now blend last frame of previous sequence with current sequence. + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + m_pCurrentEntity->latched.prevframe = f; + } + + // Now convert quaternions and bone positions into matrices + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CGameStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CGameStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + float flYaw; // view direction relative to movement + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + m_pCurrentEntity->angles[PITCH] = 0; + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + StudioEstimateGait( pplayer ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + + flYaw = fmod( flYaw, 360.0 ); + + if (flYaw < -180) + { + flYaw = flYaw + 360; + } + else if (flYaw > 180) + { + flYaw = flYaw - 360; + } + + float maxyaw = 120.0; + + if (flYaw > maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + float blend_yaw = ( flYaw / 90.0 ) * 128.0 + 127.0; + blend_yaw = min( 255.0, blend_yaw ); + blend_yaw = max( 0.0, blend_yaw ); + + blend_yaw = 255.0 - blend_yaw; + + m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw); + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + { + m_pCurrentEntity->angles[YAW] += 360; + } + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // Calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt * m_pCurrentEntity->curstate.framerate; + } + + // Do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + { + m_pPlayerInfo->gaitframe += pseqdesc->numframes; + } +} + +/* +============================== +SavePlayerState + +For local player, in third person, we need to store real render data and then + setup for with fake/client side animation data +============================== +*/ +void CGameStudioModelRenderer::SavePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_state; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; +} + +void GetSequenceInfo( void *pmodel, client_anim_state_t *pev, float *pflFrameRate, float *pflGroundSpeed ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return; + + mstudioseqdesc_t *pseqdesc; + + if (pev->sequence >= pstudiohdr->numseq) + { + *pflFrameRate = 0.0; + *pflGroundSpeed = 0.0; + return; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + if (pseqdesc->numframes > 1) + { + *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); + *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); + *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); + } + else + { + *pflFrameRate = 256.0; + *pflGroundSpeed = 0.0; + } +} + +int GetSequenceFlags( void *pmodel, client_anim_state_t *pev ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) + return 0; + + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + return pseqdesc->flags; +} + +float StudioFrameAdvance ( client_anim_state_t *st, float framerate, float flInterval ) +{ + if (flInterval == 0.0) + { + flInterval = (gEngfuncs.GetClientTime() - st->animtime); + if (flInterval <= 0.001) + { + st->animtime = gEngfuncs.GetClientTime(); + return 0.0; + } + } + if (!st->animtime) + flInterval = 0.0; + + st->frame += flInterval * framerate * st->framerate; + st->animtime = gEngfuncs.GetClientTime(); + + if (st->frame < 0.0 || st->frame >= 256.0) + { + if ( st->m_fSequenceLoops ) + st->frame -= (int)(st->frame / 256.0) * 256.0; + else + st->frame = (st->frame < 0.0) ? 0 : 255; + st->m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents + } + + return flInterval; +} + +/* +============================== +SetupClientAnimation + +Called to set up local player's animation values +============================== +*/ +void CGameStudioModelRenderer::SetupClientAnimation( entity_state_t *pplayer ) +{ + static double oldtime; + double curtime, dt; + + client_anim_state_t *st; + float fr, gs; + + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + curtime = gEngfuncs.GetClientTime(); + dt = curtime - oldtime; + dt = min( 1.0, max( 0.0, dt ) ); + + oldtime = curtime; + st = &g_clientstate; + + st->framerate = 1.0; + + int oldseq = st->sequence; + Game_GetSequence( &st->sequence, &st->gaitsequence ); //CVAR_GET_FLOAT( "sequence" ); + Game_GetOrientation( (float *)&st->origin, (float *)&st->angles ); + st->realangles = st->angles; + + if ( st->sequence != oldseq ) + { + st->frame = 0.0; + st->lv.prevsequence = oldseq; + st->lv.sequencetime = st->animtime; + + memcpy( st->lv.prevseqblending, st->blending, 2 ); + memcpy( st->lv.prevcontroller, st->controller, 4 ); + } + + void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( ent->model ); + + GetSequenceInfo( pmodel, st, &fr, &gs ); + st->m_fSequenceLoops = ((GetSequenceFlags( pmodel, st ) & STUDIO_LOOPING) != 0); + StudioFrameAdvance( st, fr, dt ); + +// gEngfuncs.Con_Printf( "gs %i frame %f\n", st->gaitsequence, st->frame ); + + ent->angles = st->realangles; + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +RestorePlayerState + +Called to restore original player state information +============================== +*/ +void CGameStudioModelRenderer::RestorePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_clientstate; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; + + st = &g_state; + + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + ent->angles = st->realangles; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +StudioDrawPlayer + +============================== +*/ +int CGameStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + int iret = 0; + + bool isLocalPlayer = false; + + // Set up for client? + if ( m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer() ) + { + isLocalPlayer = true; + } + + if ( isLocalPlayer ) + { + // Store original data + SavePlayerState( pplayer ); + + // Copy in client side animation data + SetupClientAnimation( pplayer ); + } + + // Call real draw function + iret = _StudioDrawPlayer( flags, pplayer ); + + // Restore for client? + if ( isLocalPlayer ) + { + // Restore the original data for the player + RestorePlayerState( pplayer ); + } + + return iret; +} + +/* +==================== +_StudioDrawPlayer + +==================== +*/ +int CGameStudioModelRenderer::_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + /* + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + */ + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CGameStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + if ( iRenderStateChanged ) + { + g_flStartScaleTime = m_clTime; + iRenderStateChanged = FALSE; + } + + // Make the Model continue to shrink + float flTimeDelta = m_clTime - g_flStartScaleTime; + if ( flTimeDelta > 0 ) + { + float flScale = 0.001; + // Goes almost all away + if ( flTimeDelta <= 2.0 ) + flScale = 1.0 - (flTimeDelta / 2.0); + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + transform[i][j] *= flScale; + } + } + } + break; + } +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +#define DLLEXPORT __declspec( dllexport ) +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/main/source/cl_dll/GameStudioModelRenderer_Sample.h b/main/source/cl_dll/GameStudioModelRenderer_Sample.h index 3fe5ea5c..64f6c8b0 100644 --- a/main/source/cl_dll/GameStudioModelRenderer_Sample.h +++ b/main/source/cl_dll/GameStudioModelRenderer_Sample.h @@ -1,48 +1,48 @@ -#if !defined( GAMESTUDIOMODELRENDERER_H ) -#define GAMESTUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif - -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -class CGameStudioModelRenderer : public CStudioModelRenderer -{ -public: - CGameStudioModelRenderer( void ); - - // Set up model bone positions - virtual void StudioSetupBones ( void ); - - // Estimate gait frame for player - virtual void StudioEstimateGait ( entity_state_t *pplayer ); - - // Process movement of player - virtual void StudioProcessGait ( entity_state_t *pplayer ); - - // Player drawing code - virtual int StudioDrawPlayer( int flags, entity_state_t *pplayer ); - virtual int _StudioDrawPlayer( int flags, entity_state_t *pplayer ); - - // Apply special effects to transform matrix - virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); - -private: - // For local player, in third person, we need to store real render data and then - // setup for with fake/client side animation data - void SavePlayerState( entity_state_t *pplayer ); - // Called to set up local player's animation values - void SetupClientAnimation( entity_state_t *pplayer ); - // Called to restore original player state information - void RestorePlayerState( entity_state_t *pplayer ); - -private: - // Private data - bool m_bLocal; -}; - +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + + // Player drawing code + virtual int StudioDrawPlayer( int flags, entity_state_t *pplayer ); + virtual int _StudioDrawPlayer( int flags, entity_state_t *pplayer ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + +private: + // For local player, in third person, we need to store real render data and then + // setup for with fake/client side animation data + void SavePlayerState( entity_state_t *pplayer ); + // Called to set up local player's animation values + void SetupClientAnimation( entity_state_t *pplayer ); + // Called to restore original player state information + void RestorePlayerState( entity_state_t *pplayer ); + +private: + // Private data + bool m_bLocal; +}; + #endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/main/source/cl_dll/StudioModelRenderer.cpp b/main/source/cl_dll/StudioModelRenderer.cpp index 2bbda552..b1a72942 100644 --- a/main/source/cl_dll/StudioModelRenderer.cpp +++ b/main/source/cl_dll/StudioModelRenderer.cpp @@ -1,1910 +1,1910 @@ -// studio_model.cpp -// routines for setting up to draw 3DStudio models - -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/com_model.h" -#include "engine/studio.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "common/dlight.h" -#include "common/triangleapi.h" - -#include -#include -#include -#include - -#include "studio_util.h" -#include "r_studioint.h" - -#include "StudioModelRenderer.h" -#include "GameStudioModelRenderer.h" - -#include "util/MathUtil.h" - -// Global engine <-> studio model rendering code interface -engine_studio_api_t IEngineStudio; - -#include "mod/AvHSpecials.h" - -int GetRenderModeForModelName(int inRenderMode, char* inName) -{ - int theRenderMode = inRenderMode; - -// if(!strncmp("tcol", inName, 4)) -// { -// theRenderMode = kRenderTransColor; -// } - if(!strncmp("ttex", inName, 4)) - { - theRenderMode = kRenderTransTexture; - } - else if(!strncmp("glow", inName, 4)) - { - theRenderMode = kRenderGlow; - } - else if(!strncmp("talp", inName, 4)) - { - theRenderMode = kRenderTransAlpha; - } - else if(!strncmp("tadd", inName, 4)) - { - theRenderMode = kRenderTransAdd; - } - - return theRenderMode; -} - - -///////////////////// -// Implementation of CStudioModelRenderer.h - -/* -==================== -Init - -==================== -*/ -void CStudioModelRenderer::Init( void ) -{ - // Set up some variables shared with engine - m_pCvarHiModels = IEngineStudio.GetCvar( "cl_himodels" ); - m_pCvarDeveloper = IEngineStudio.GetCvar( "developer" ); - m_pCvarDrawEntities = IEngineStudio.GetCvar( "r_drawentities" ); - - m_pChromeSprite = IEngineStudio.GetChromeSprite(); - - IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn ); - - // Get pointers to engine data structures - m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform(); - m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform(); - m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform(); - m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix(); -} - -/* -==================== -CStudioModelRenderer - -==================== -*/ -CStudioModelRenderer::CStudioModelRenderer( void ) -{ - m_fDoInterp = 1; - m_fGaitEstimation = 1; - m_pCurrentEntity = NULL; - m_pCvarHiModels = NULL; - m_pCvarDeveloper = NULL; - m_pCvarDrawEntities = NULL; - m_pChromeSprite = NULL; - m_pStudioModelCount = NULL; - m_pModelsDrawn = NULL; - m_protationmatrix = NULL; - m_paliastransform = NULL; - m_pbonetransform = NULL; - m_plighttransform = NULL; - m_pStudioHeader = NULL; - m_pBodyPart = NULL; - m_pSubModel = NULL; - m_pPlayerInfo = NULL; - m_pRenderModel = NULL; -} - -/* -==================== -~CStudioModelRenderer - -==================== -*/ -CStudioModelRenderer::~CStudioModelRenderer( void ) -{ -} - -/* -==================== -StudioCalcBoneAdj - -==================== -*/ -void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) -{ - int i, j; - float value; - mstudiobonecontroller_t *pbonecontroller; - - pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); - - for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) - { - i = pbonecontroller[j].index; - if (i <= 3) - { - // check for 360% wrapping - if (pbonecontroller[j].type & STUDIO_RLOOP) - { - if (abs(pcontroller1[i] - pcontroller2[i]) > 128) - { - int a, b; - a = (pcontroller1[j] + 128) % 256; - b = (pcontroller2[j] + 128) % 256; - value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; - } - else - { - value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; - } - } - else - { - value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; - if (value < 0) value = 0; - if (value > 1.0) value = 1.0; - value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; - } - // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); - } - else - { - value = mouthopen / 64.0; - if (value > 1.0) value = 1.0; - value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; - // Con_DPrintf("%d %f\n", mouthopen, value ); - } - switch(pbonecontroller[j].type & STUDIO_TYPES) - { - case STUDIO_XR: - case STUDIO_YR: - case STUDIO_ZR: - adj[j] = value * (M_PI / 180.0); - break; - case STUDIO_X: - case STUDIO_Y: - case STUDIO_Z: - adj[j] = value; - break; - } - } -} - - -/* -==================== -StudioCalcBoneQuaterion - -==================== -*/ -void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) -{ - int j, k; - vec4_t q1, q2; - vec3_t angle1, angle2; - mstudioanimvalue_t *panimvalue; - - for (j = 0; j < 3; j++) - { - if (panim->offset[j+3] == 0) - { - angle2[j] = angle1[j] = pbone->value[j+3]; // default; - } - else - { - panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); - k = frame; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - while (panimvalue->num.total <= k) - { - k -= panimvalue->num.total; - panimvalue += panimvalue->num.valid + 1; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - } - // Bah, missing blend! - if (panimvalue->num.valid > k) - { - angle1[j] = panimvalue[k+1].value; - - if (panimvalue->num.valid > k + 1) - { - angle2[j] = panimvalue[k+2].value; - } - else - { - if (panimvalue->num.total > k + 1) - angle2[j] = angle1[j]; - else - angle2[j] = panimvalue[panimvalue->num.valid+2].value; - } - } - else - { - angle1[j] = panimvalue[panimvalue->num.valid].value; - if (panimvalue->num.total > k + 1) - { - angle2[j] = angle1[j]; - } - else - { - angle2[j] = panimvalue[panimvalue->num.valid + 2].value; - } - } - angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; - angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; - } - - if (pbone->bonecontroller[j+3] != -1) - { - angle1[j] += adj[pbone->bonecontroller[j+3]]; - angle2[j] += adj[pbone->bonecontroller[j+3]]; - } - } - - if (!VectorCompare( angle1, angle2 )) - { - AngleQuaternion( angle1, q1 ); - AngleQuaternion( angle2, q2 ); - QuaternionSlerp( q1, q2, s, q ); - } - else - { - AngleQuaternion( angle1, q ); - } -} - -/* -==================== -StudioCalcBonePosition - -==================== -*/ -void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) -{ - int j, k; - mstudioanimvalue_t *panimvalue; - - for (j = 0; j < 3; j++) - { - pos[j] = pbone->value[j]; // default; - if (panim->offset[j] != 0) - { - panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); - /* - if (i == 0 && j == 0) - Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); - */ - - k = frame; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - // find span of values that includes the frame we want - while (panimvalue->num.total <= k) - { - k -= panimvalue->num.total; - panimvalue += panimvalue->num.valid + 1; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - } - // if we're inside the span - if (panimvalue->num.valid > k) - { - // and there's more data in the span - if (panimvalue->num.valid > k + 1) - { - pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; - } - else - { - pos[j] += panimvalue[k+1].value * pbone->scale[j]; - } - } - else - { - // are we at the end of the repeating values section and there's another section with data? - if (panimvalue->num.total <= k + 1) - { - pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; - } - else - { - pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; - } - } - } - if ( pbone->bonecontroller[j] != -1 && adj ) - { - pos[j] += adj[pbone->bonecontroller[j]]; - } - } -} - -/* -==================== -StudioSlerpBones - -==================== -*/ -void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) -{ - int i; - vec4_t q3; - float s1; - - if (s < 0) s = 0; - else if (s > 1.0) s = 1.0; - - s1 = 1.0 - s; - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - QuaternionSlerp( q1[i], q2[i], s, q3 ); - q1[i][0] = q3[0]; - q1[i][1] = q3[1]; - q1[i][2] = q3[2]; - q1[i][3] = q3[3]; - pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; - pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; - pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; - } -} - -/* -==================== -StudioGetAnim - -==================== -*/ -mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) -{ - mstudioseqgroup_t *pseqgroup; - cache_user_t *paSequences; - - pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; - - if (pseqdesc->seqgroup == 0) - { +// studio_model.cpp +// routines for setting up to draw 3DStudio models + +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/com_model.h" +#include "engine/studio.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "common/dlight.h" +#include "common/triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +#include "util/MathUtil.h" + +// Global engine <-> studio model rendering code interface +engine_studio_api_t IEngineStudio; + +#include "mod/AvHSpecials.h" + +int GetRenderModeForModelName(int inRenderMode, char* inName) +{ + int theRenderMode = inRenderMode; + +// if(!strncmp("tcol", inName, 4)) +// { +// theRenderMode = kRenderTransColor; +// } + if(!strncmp("ttex", inName, 4)) + { + theRenderMode = kRenderTransTexture; + } + else if(!strncmp("glow", inName, 4)) + { + theRenderMode = kRenderGlow; + } + else if(!strncmp("talp", inName, 4)) + { + theRenderMode = kRenderTransAlpha; + } + else if(!strncmp("tadd", inName, 4)) + { + theRenderMode = kRenderTransAdd; + } + + return theRenderMode; +} + + +///////////////////// +// Implementation of CStudioModelRenderer.h + +/* +==================== +Init + +==================== +*/ +void CStudioModelRenderer::Init( void ) +{ + // Set up some variables shared with engine + m_pCvarHiModels = IEngineStudio.GetCvar( "cl_himodels" ); + m_pCvarDeveloper = IEngineStudio.GetCvar( "developer" ); + m_pCvarDrawEntities = IEngineStudio.GetCvar( "r_drawentities" ); + + m_pChromeSprite = IEngineStudio.GetChromeSprite(); + + IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn ); + + // Get pointers to engine data structures + m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform(); + m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform(); + m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform(); + m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix(); +} + +/* +==================== +CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::CStudioModelRenderer( void ) +{ + m_fDoInterp = 1; + m_fGaitEstimation = 1; + m_pCurrentEntity = NULL; + m_pCvarHiModels = NULL; + m_pCvarDeveloper = NULL; + m_pCvarDrawEntities = NULL; + m_pChromeSprite = NULL; + m_pStudioModelCount = NULL; + m_pModelsDrawn = NULL; + m_protationmatrix = NULL; + m_paliastransform = NULL; + m_pbonetransform = NULL; + m_plighttransform = NULL; + m_pStudioHeader = NULL; + m_pBodyPart = NULL; + m_pSubModel = NULL; + m_pPlayerInfo = NULL; + m_pRenderModel = NULL; +} + +/* +==================== +~CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::~CStudioModelRenderer( void ) +{ +} + +/* +==================== +StudioCalcBoneAdj + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) +{ + int i, j; + float value; + mstudiobonecontroller_t *pbonecontroller; + + pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + + for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) + { + i = pbonecontroller[j].index; + if (i <= 3) + { + // check for 360% wrapping + if (pbonecontroller[j].type & STUDIO_RLOOP) + { + if (abs(pcontroller1[i] - pcontroller2[i]) > 128) + { + int a, b; + a = (pcontroller1[j] + 128) % 256; + b = (pcontroller2[j] + 128) % 256; + value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; + } + else + { + value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; + } + } + else + { + value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); + } + else + { + value = mouthopen / 64.0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + // Con_DPrintf("%d %f\n", mouthopen, value ); + } + switch(pbonecontroller[j].type & STUDIO_TYPES) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = value * (M_PI / 180.0); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + + +/* +==================== +StudioCalcBoneQuaterion + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) +{ + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + if (panim->offset[j+3] == 0) + { + angle2[j] = angle1[j] = pbone->value[j+3]; // default; + } + else + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // Bah, missing blend! + if (panimvalue->num.valid > k) + { + angle1[j] = panimvalue[k+1].value; + + if (panimvalue->num.valid > k + 1) + { + angle2[j] = panimvalue[k+2].value; + } + else + { + if (panimvalue->num.total > k + 1) + angle2[j] = angle1[j]; + else + angle2[j] = panimvalue[panimvalue->num.valid+2].value; + } + } + else + { + angle1[j] = panimvalue[panimvalue->num.valid].value; + if (panimvalue->num.total > k + 1) + { + angle2[j] = angle1[j]; + } + else + { + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; + angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; + } + + if (pbone->bonecontroller[j+3] != -1) + { + angle1[j] += adj[pbone->bonecontroller[j+3]]; + angle2[j] += adj[pbone->bonecontroller[j+3]]; + } + } + + if (!VectorCompare( angle1, angle2 )) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionSlerp( q1, q2, s, q ); + } + else + { + AngleQuaternion( angle1, q ); + } +} + +/* +==================== +StudioCalcBonePosition + +==================== +*/ +void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) +{ + int j, k; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + /* + if (i == 0 && j == 0) + Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); + */ + + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k+1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + if ( pbone->bonecontroller[j] != -1 && adj ) + { + pos[j] += adj[pbone->bonecontroller[j]]; + } + } +} + +/* +==================== +StudioSlerpBones + +==================== +*/ +void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) +{ + int i; + vec4_t q3; + float s1; + + if (s < 0) s = 0; + else if (s > 1.0) s = 1.0; + + s1 = 1.0 - s; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionSlerp( q1[i], q2[i], s, q3 ); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + +/* +==================== +StudioGetAnim + +==================== +*/ +mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) +{ + mstudioseqgroup_t *pseqgroup; + cache_user_t *paSequences; + + pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + + if (pseqdesc->seqgroup == 0) + { return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqdesc->animindex); - } - - paSequences = (cache_user_t *)m_pSubModel->submodels; - - if (paSequences == NULL) - { - paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! - m_pSubModel->submodels = (dmodel_t *)paSequences; - } - - if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) - { - gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); - IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); - } - return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); -} - -/* -==================== -StudioPlayerBlend - -==================== -*/ -void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) -{ - // calc up/down pointing - *pBlend = (*pPitch * 3); - if (*pBlend < pseqdesc->blendstart[0]) - { - *pPitch -= pseqdesc->blendstart[0] / 3.0; - *pBlend = 0; - } - else if (*pBlend > pseqdesc->blendend[0]) - { - *pPitch -= pseqdesc->blendend[0] / 3.0; - *pBlend = 255; - } - else - { - if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error - *pBlend = 127; - else - *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); - *pPitch = 0; - } -} - -/* -==================== -StudioSetUpTransform - -==================== -*/ -void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) -{ - int i; - vec3_t angles; - vec3_t modelpos; - -// tweek model origin - //for (i = 0; i < 3; i++) - // modelpos[i] = m_pCurrentEntity->origin[i]; - - VectorCopy( m_pCurrentEntity->origin, modelpos ); - -// TODO: should really be stored with the entity instead of being reconstructed -// TODO: should use a look-up table -// TODO: could cache lazily, stored in the entity - angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; - angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; - angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; - - //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); - //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); - if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) - { - float f = 0; - float d; - - // don't do it if the goalstarttime hasn't updated in a while. - - // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit - // was increased to 1.0 s., which is 2x the max lag we are accounting for. - - if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && - ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) - { - f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); - //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); - } - - if (m_fDoInterp) - { - // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set - f = f - 1.0; - } - else - { - f = 0; - } - - for (i = 0; i < 3; i++) - { - modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; - } - - // NOTE: Because multiplayer lag can be relatively large, we don't want to cap - // f at 1.5 anymore. - //if (f > -1.0 && f < 1.5) {} - -// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); - for (i = 0; i < 3; i++) - { - float ang1, ang2; - - ang1 = m_pCurrentEntity->angles[i]; - ang2 = m_pCurrentEntity->latched.prevangles[i]; - - d = ang1 - ang2; - if (d > 180) - { - d -= 360; - } - else if (d < -180) - { - d += 360; - } - - angles[i] += d * f; - } - //Con_DPrintf("%.3f \n", f ); - } - else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) - { - VectorCopy( m_pCurrentEntity->angles, angles ); - } - - // Added by mmcguire. - - if (m_pCurrentEntity->curstate.iuser3 == AVH_USER3_ALIEN_PLAYER1) - { - - // Override the orientation with the values stored in vuser1. - - VectorCopy(m_pCurrentEntity->curstate.vuser1, angles); - - // The code that sets up the transformation negates the pitch - // for some reason, so compensate for that here. - - angles[PITCH] = -angles[PITCH]; - - } - - -// bool theIsWallSticking = GetHasUpgrade(m_pCurrentEntity->curstate.iuser4, MASK_WALLSTICKING); -// if(theIsWallSticking) -// { -// //RotateFloatValuesByVector(angles[ROLL], angles[YAW], angles[PITCH], m_pCurrentEntity->curstate.vuser1); -// //VectorCopy(m_pCurrentEntity->curstate.vuser1, angles); -// -// // Surface normal is in vuser1. Transform current forward to new forward -// vec3_t theCurrentForward; -// vec3_t theCurrentRight; -// vec3_t theCurrentUp; -// gEngfuncs.pfnAngleVectors(angles, theCurrentForward, theCurrentRight, theCurrentUp); -// -// vec3_t theWallUp = m_pCurrentEntity->curstate.vuser1; -// -// vec3_t theWallSide; -// CrossProduct(theWallUp, theCurrentForward, theWallSide); -// -// vec3_t theWallForward; -// //CrossProduct(theWallUp, theWallSide, theWallForward); -// VectorCopy(theCurrentForward, theWallForward); -// -// // Build matrix to transform current frame of reference to that of sticking to wall -// float theViewToWallMatrix[3][4]; -// theViewToWallMatrix[0][0] = theWallForward.x; -// theViewToWallMatrix[0][1] = theWallForward.y; -// theViewToWallMatrix[0][2] = theWallForward.z; -// -// theViewToWallMatrix[1][0] = theWallSide.x; -// theViewToWallMatrix[1][1] = theWallSide.y; -// theViewToWallMatrix[1][2] = theWallSide.z; -// -// theViewToWallMatrix[2][0] = theWallUp.x; -// theViewToWallMatrix[2][1] = theWallUp.y; -// theViewToWallMatrix[2][2] = theWallUp.z; -// -// vec3_t theNewForward; -// VectorTransform(theCurrentForward, theViewToWallMatrix, theNewForward); -// -// // Transform new forward to angles -// VectorAngles(theNewForward, angles); -// } - - //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); - //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); - - angles[PITCH] = -angles[PITCH]; - AngleMatrix (angles, (*m_protationmatrix)); - - if ( !IEngineStudio.IsHardware() ) - { - static float viewmatrix[3][4]; - - VectorCopy (m_vRight, viewmatrix[0]); - VectorCopy (m_vUp, viewmatrix[1]); - VectorInverse (viewmatrix[1]); - VectorCopy (m_vNormal, viewmatrix[2]); - - (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; - (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; - (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; - - ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); - - // do the scaling up of x and y to screen coordinates as part of the transform - // for the unclipped case (it would mess up clipping in the clipped case). - // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y - // correspondingly so the projected x and y come out right - // FIXME: make this work for clipped case too? - if (trivial_accept) - { - for (i=0 ; i<4 ; i++) - { - (*m_paliastransform)[0][i] *= m_fSoftwareXScale * - (1.0 / (ZISCALE * 0x10000)); - (*m_paliastransform)[1][i] *= m_fSoftwareYScale * - (1.0 / (ZISCALE * 0x10000)); - (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); - - } - } - } - - (*m_protationmatrix)[0][3] = modelpos[0]; - (*m_protationmatrix)[1][3] = modelpos[1]; - (*m_protationmatrix)[2][3] = modelpos[2]; -} - - -/* -==================== -StudioEstimateInterpolant - -==================== -*/ -float CStudioModelRenderer::StudioEstimateInterpolant( void ) -{ - float dadt = 1.0; - - if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) - { - dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; - if (dadt > 2.0) - { - dadt = 2.0; - } - } - return dadt; -} - -/* -==================== -StudioCalcRotations - -==================== -*/ -void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) -{ - int i; - int frame; - mstudiobone_t *pbone; - - float s; - float adj[MAXSTUDIOCONTROLLERS]; - float dadt; - - if (f > pseqdesc->numframes - 1) - { - f = 0; // bah, fix this bug with changing sequences too fast - } - // BUG ( somewhere else ) but this code should validate this data. - // This could cause a crash if the frame # is negative, so we'll go ahead - // and clamp it here - else if ( f < -0.01 ) - { - f = -0.01; - } - - frame = (int)f; - - //gEngfuncs.Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); - - // gEngfuncs.Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); - - //gEngfuncs.Con_DPrintf("frame %d %d\n", frame1, frame2 ); - - - dadt = StudioEstimateInterpolant( ); - s = (f - frame); - - // add in programtic controllers - pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); - - for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) - { - StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); - - StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); - // if (0 && i == 0) - // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); - } - - if (pseqdesc->motiontype & STUDIO_X) - { - pos[pseqdesc->motionbone][0] = 0.0; - } - if (pseqdesc->motiontype & STUDIO_Y) - { - pos[pseqdesc->motionbone][1] = 0.0; - } - if (pseqdesc->motiontype & STUDIO_Z) - { - pos[pseqdesc->motionbone][2] = 0.0; - } - - //gEngfuncs.Con_Printf("framerate %f\n", m_pCurrentEntity->curstate.framerate); - - s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; - - if (pseqdesc->motiontype & STUDIO_LX) - { - pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; - } - if (pseqdesc->motiontype & STUDIO_LY) - { - pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; - } - if (pseqdesc->motiontype & STUDIO_LZ) - { - pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; - } -} - -/* -==================== -Studio_FxTransform - -==================== -*/ -void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) -{ - switch( ent->curstate.renderfx ) - { - case kRenderFxDistort: - case kRenderFxHologram: - if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); - } - else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - float offset; - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - offset = gEngfuncs.pfnRandomFloat(-10,10); - transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; - } - break; - case kRenderFxExplode: - { - float scale; - - scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; - if ( scale > 2 ) // Don't blow up more than 200% - scale = 2; - transform[0][1] *= scale; - transform[1][1] *= scale; - transform[2][1] *= scale; - } - break; - - } -} - -/* -==================== -StudioEstimateFrame - -==================== -*/ -float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) -{ - double dfdt, f; - - if ( m_fDoInterp ) - { - if ( m_clTime < m_pCurrentEntity->curstate.animtime ) - { - dfdt = 0; - } - else - { - dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; - - } - } - else - { - dfdt = 0; - } - - if (pseqdesc->numframes <= 1) - { - f = 0; - } - else - { - f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; - } - - f += dfdt; - - if (pseqdesc->flags & STUDIO_LOOPING) - { - if (pseqdesc->numframes > 1) - { - f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); - } - if (f < 0) - { - f += (pseqdesc->numframes - 1); - } - } - else - { - if (f >= pseqdesc->numframes - 1.001) - { - f = pseqdesc->numframes - 1.001; - } - if (f < 0.0) - { - f = 0.0; - } - } - return f; -} - -bool GetDoesBoneHaveParent(int inMaybeBeneathBone, int inParentBone, mstudiobone_t* inBones) -{ - bool theSuccess = false; - - ASSERT(inMaybeBeneathBone < MAXSTUDIOBONES); - ASSERT(inParentBone < MAXSTUDIOBONES); - - int theCurrentParent = inBones[inMaybeBeneathBone].parent; - - if(theCurrentParent == inParentBone) - { - theSuccess = true; - } - else if(theCurrentParent != -1) - { - theSuccess = GetDoesBoneHaveParent(theCurrentParent, inParentBone, inBones); - } - - return theSuccess; -} - -/* -==================== -StudioSetupBones - -==================== -*/ -void CStudioModelRenderer::StudioSetupBones ( void ) -{ - int i; - double f; - - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; - - static float pos[MAXSTUDIOBONES][3]; - static vec4_t q[MAXSTUDIOBONES]; - float bonematrix[3][4]; - - static float pos2[MAXSTUDIOBONES][3]; - static vec4_t q2[MAXSTUDIOBONES]; - static float pos3[MAXSTUDIOBONES][3]; - static vec4_t q3[MAXSTUDIOBONES]; - static float pos4[MAXSTUDIOBONES][3]; - static vec4_t q4[MAXSTUDIOBONES]; - - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) - { - m_pCurrentEntity->curstate.sequence = 0; - } - else if (m_pCurrentEntity->curstate.sequence < 0) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - f = StudioEstimateFrame( pseqdesc ); - - if (m_pCurrentEntity->latched.prevframe > f) - { - //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); - } - - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - if (pseqdesc->numblends > 1) - { - float s; - float dadt; - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); - - dadt = StudioEstimateInterpolant(); - s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; - - StudioSlerpBones( q, pos, q2, pos2, s ); - - if (pseqdesc->numblends == 4) - { - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); - - s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; - StudioSlerpBones( q3, pos3, q4, pos4, s ); - - s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; - StudioSlerpBones( q, pos, q3, pos3, s ); - } - } - - if (m_fDoInterp && - m_pCurrentEntity->latched.sequencetime && - ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && - ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) - { - // blend from last sequence - static float pos1b[MAXSTUDIOBONES][3]; - static vec4_t q1b[MAXSTUDIOBONES]; - float s; - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - // clip prevframe - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - if (pseqdesc->numblends > 1) - { - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; - StudioSlerpBones( q1b, pos1b, q2, pos2, s ); - - if (pseqdesc->numblends == 4) - { - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; - StudioSlerpBones( q3, pos3, q4, pos4, s ); - - s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; - StudioSlerpBones( q1b, pos1b, q3, pos3, s ); - } - } - - s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; - StudioSlerpBones( q, pos, q1b, pos1b, s ); - } - else - { - //Con_DPrintf("prevframe = %4.2f\n", f); - m_pCurrentEntity->latched.prevframe = f; - } - - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - // calc gait animation - if (m_pPlayerInfo && (m_pPlayerInfo->gaitsequence != 0) && (m_pPlayerInfo->gaitsequence != 255)) - { - m_pPlayerInfo->gaitsequence = max(min(m_pPlayerInfo->gaitsequence, m_pStudioHeader->numseq-1), 0); - -// // Trim sequences within range (not sure why this is out of range though) -// int theIndex = min(max(0, m_pStudioHeader->seqindex), m_pStudioHeader->numseq - 1); -// if(theIndex != m_pStudioHeader->seqindex) -// { -// m_pStudioHeader->seqindex = theIndex; -// m_pPlayerInfo->gaitsequence = 0; -// } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; - - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); - -// Valve way -// for (i = 0; i < m_pStudioHeader->numbones; i++) -// { -// if (strcmp( pbones[i].name, "Bip01 Spine") == 0) -// break; -// memcpy( pos[i], pos2[i], sizeof( pos[i] )); -// memcpy( q[i], q2[i], sizeof( q[i] )); -// } - -// NS way - // Look up parent bone that defines the boundary for gaitsequence - int theNumParents = 0; - int theParents[MAXSTUDIOBONES]; - memset(theParents, -1, sizeof(int)*MAXSTUDIOBONES); - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - // Must contain "Thigh" - if(strstr(pbones[i].name, "Thigh")) - { - theParents[theNumParents++] = i; - } - } - // If this is firing, it means a model has a gaitsequence set but doesn't have a bone that defines which bones are used for that gaitsequence - //ASSERT(theNumParents > 0); - - // If there aren't any thighs, assume that the old HL way was used - if(theNumParents > 0) - { - int theNumBonesWithThisParent = 0; - int theBonesWithParent[MAXSTUDIOBONES]; - - // For each bone - for(i = 0; i < m_pStudioHeader->numbones; i++) - { - for(int j = 0; j < theNumParents; j++) - { - // Does bone have this parent bone? - int theParent = theParents[j]; - //if(/*(i == theParent) ||*/ GetDoesBoneHaveParent(i, theParent, pbones)) - char* theBoneName = pbones[i].name; - if(!strcmp(theBoneName, "Bip01") || (!strcmp(theBoneName, "Bip01 Pelvis")) || (i == theParent) || GetDoesBoneHaveParent(i, theParent, pbones)) - { - // If so, add it to the list and increment num bones - theBonesWithParent[theNumBonesWithThisParent++] = i; - break; - } - } - } - - for(int j = 0; j < theNumBonesWithThisParent; j++) - { - int i = theBonesWithParent[j]; - - // If the bone is in this list, use that bones data (gaitsequence) instead of the existing data (sequence) - memcpy( pos[i], pos2[i], sizeof( pos[i] )); - memcpy( q[i], q2[i], sizeof( q[i] )); - } - } - else - { - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - if (strcmp( pbones[i].name, "Bip01 Spine") == 0) - break; - memcpy( pos[i], pos2[i], sizeof( pos[i] )); - memcpy( q[i], q2[i], sizeof( q[i] )); - } - } - - //gEngfuncs.Con_Printf("gait: %d, frame: %f\n", m_pPlayerInfo->gaitsequence, m_pPlayerInfo->gaitframe); - } - - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - QuaternionMatrix( q[i], bonematrix ); - - bonematrix[0][3] = pos[i][0]; - bonematrix[1][3] = pos[i][1]; - bonematrix[2][3] = pos[i][2]; - - if (pbones[i].parent == -1) - { - if ( IEngineStudio.IsHardware() ) - { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); - // MatrixCopy should be faster... - //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); - } - else - { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - - // Apply client-side effects to the transformation matrix - StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); - } - else - { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); - } - } -} - - -/* -==================== -StudioSaveBones - -==================== -*/ -void CStudioModelRenderer::StudioSaveBones( void ) -{ - int i; - - mstudiobone_t *pbones; - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - m_nCachedBones = m_pStudioHeader->numbones; - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - strcpy( m_nCachedBoneNames[i], pbones[i].name ); - MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); - MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] ); - } -} - - -/* -==================== -StudioMergeBones - -==================== -*/ -void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) -{ - int i, j; - double f; - int do_hunt = true; - - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; - - static float pos[MAXSTUDIOBONES][3]; - float bonematrix[3][4]; - static vec4_t q[MAXSTUDIOBONES]; - - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - f = StudioEstimateFrame( pseqdesc ); - - if (m_pCurrentEntity->latched.prevframe > f) - { - //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); - } - - panim = StudioGetAnim( m_pSubModel, pseqdesc ); - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - for (j = 0; j < m_nCachedBones; j++) - { - if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) - { - MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); - MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); - break; - } - } - if (j >= m_nCachedBones) - { - QuaternionMatrix( q[i], bonematrix ); - - bonematrix[0][3] = pos[i][0]; - bonematrix[1][3] = pos[i][1]; - bonematrix[2][3] = pos[i][2]; - - if (pbones[i].parent == -1) - { - if ( IEngineStudio.IsHardware() ) - { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); - // MatrixCopy should be faster... - //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); - } - else - { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - - // Apply client-side effects to the transformation matrix - StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); - } - else - { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); - } - } - } -} - -/* -==================== -StudioDrawModel - -==================== -*/ -int CStudioModelRenderer::StudioDrawModel( int flags ) -{ - alight_t lighting; - vec3_t dir; - - m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); - IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); - IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); - IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - - // Horrible hack for preventing visual artifacts while being digested - if(gHUD.GetIsBeingDigested()) - { - return 0; - } - - /* - // Now render eyebeam if model is marine // - // If player is a marine - if(m_pCurrentEntity->curstate.iuser3 == AVH_USER3_MARINE_PLAYER) - { - // Get eyepiece attachment - vec3_t theEyepieceOrigin; - VectorCopy(m_pCurrentEntity->attachment[2], theEyepieceOrigin); - - // Build this line - - // Run a traceline along this line until it hits - - // Get endpoint - - // Draw red additive light along this line - //gEngfuncs.pEfxAPI->R_RocketTrail(); - } - */ - - if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) - { - entity_state_t deadplayer; - - int result; - int save_interp; - - if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) - return 0; - - // get copy of player - deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; - - // clear weapon, movement state - deadplayer.number = m_pCurrentEntity->curstate.renderamt; - deadplayer.weaponmodel = 0; - deadplayer.gaitsequence = 0; - - deadplayer.movetype = MOVETYPE_NONE; - VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles ); - VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin ); - - save_interp = m_fDoInterp; - m_fDoInterp = 0; - - // draw as though it were a player - result = StudioDrawPlayer( flags, &deadplayer ); - - m_fDoInterp = save_interp; - return result; - } - - m_pRenderModel = m_pCurrentEntity->model; - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - IEngineStudio.SetRenderModel( m_pRenderModel ); - - StudioSetUpTransform( 0 ); - - if (flags & STUDIO_RENDER) - { - // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) - return 0; - - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie - - if (m_pStudioHeader->numbodyparts == 0) - return 1; - } - - if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) - { - StudioMergeBones( m_pRenderModel ); - } - else - { - StudioSetupBones( ); - } - StudioSaveBones( ); - - if (flags & STUDIO_EVENTS) - { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); - // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); - } - } - - if (flags & STUDIO_RENDER) - { - lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); - - IEngineStudio.StudioEntityLight( &lighting ); - - // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); - - // get remap colors - m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; - m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; - - IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - - StudioRenderModel(); - - // If this is the local player's view model, hook into HUD - char theModelName[MAX_MODEL_NAME]; - strcpy(theModelName, this->m_pCurrentEntity->model->name); - - gHUD.PostModelRender(theModelName); - } - - return 1; -} - -/* -==================== -StudioEstimateGait - -==================== -*/ -void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) -{ - float dt; - vec3_t est_velocity; - - dt = (m_clTime - m_clOldTime); - if (dt < 0) - dt = 0; - else if (dt > 1.0) - dt = 1; - - if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) - { - m_flGaitMovement = 0; - return; - } - - // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); - if ( m_fGaitEstimation ) - { - VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); - VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); - m_flGaitMovement = Length( est_velocity ); - if (dt <= 0 || m_flGaitMovement / dt < 5) - { - m_flGaitMovement = 0; - est_velocity[0] = 0; - est_velocity[1] = 0; - } - } - else - { - VectorCopy( pplayer->velocity, est_velocity ); - m_flGaitMovement = Length( est_velocity ) * dt; - } - - if (est_velocity[1] == 0 && est_velocity[0] == 0) - { - float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; - if (flYawDiff > 180) - flYawDiff -= 360; - if (flYawDiff < -180) - flYawDiff += 360; - - if (dt < 0.25) - flYawDiff *= dt * 4; - else - flYawDiff *= dt; - - m_pPlayerInfo->gaityaw += flYawDiff; - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; - - m_flGaitMovement = 0; - } - else - { - m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); - if (m_pPlayerInfo->gaityaw > 180) - m_pPlayerInfo->gaityaw = 180; - if (m_pPlayerInfo->gaityaw < -180) - m_pPlayerInfo->gaityaw = -180; - } - -} - -/* -==================== -StudioProcessGait - -==================== -*/ -void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) -{ - mstudioseqdesc_t *pseqdesc; - float dt; - int iBlend; - float flYaw; // view direction relative to movement - - m_pCurrentEntity->curstate.sequence = max(min(m_pCurrentEntity->curstate.sequence, m_pStudioHeader->numseq-1), 0); - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); - - m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; - m_pCurrentEntity->curstate.blending[0] = iBlend; - m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; - m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; - - // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); - - dt = (m_clTime - m_clOldTime); - if (dt < 0) - dt = 0; - else if (dt > 1.0) - dt = 1; - - StudioEstimateGait( pplayer ); - - // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); - - // calc side to side turning - flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYaw = flYaw - (int)(flYaw / 360) * 360; - if (flYaw < -180) - flYaw = flYaw + 360; - if (flYaw > 180) - flYaw = flYaw - 360; - - if (flYaw > 120) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw - 180; - } - else if (flYaw < -120) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw + 180; - } - - // adjust torso - m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; - m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; - m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; - m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - - m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; - if (m_pCurrentEntity->angles[YAW] < -0) - m_pCurrentEntity->angles[YAW] += 360; - m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; - - pplayer->gaitsequence = max(min(pplayer->gaitsequence, m_pStudioHeader->numseq-1), 0); - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; - - // calc gait frame - if (pseqdesc->linearmovement[0] > 0) - { - m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; - } - else - { - m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; - } - - // do modulo - m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; - if (m_pPlayerInfo->gaitframe < 0) - m_pPlayerInfo->gaitframe += pseqdesc->numframes; -} - -/* -==================== -StudioDrawPlayer - -==================== -*/ -int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - alight_t lighting; - vec3_t dir; - - m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); - IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); - IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); - IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - - // Horrible hack for preventing visual artifacts while being digested - if(gHUD.GetIsBeingDigested()) - { - return 0; - } - - // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); - - // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); - - // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); - - m_nPlayerIndex = pplayer->number - 1; - - if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) - return 0; - - //m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); - m_pRenderModel = m_pCurrentEntity->model; - if (m_pRenderModel == NULL) - return 0; - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - IEngineStudio.SetRenderModel( m_pRenderModel ); - - if (pplayer->gaitsequence) - { - vec3_t orig_angles; - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - VectorCopy( m_pCurrentEntity->angles, orig_angles ); - - StudioProcessGait( pplayer ); - - m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; - m_pPlayerInfo = NULL; - - StudioSetUpTransform( 0 ); - VectorCopy( orig_angles, m_pCurrentEntity->angles ); - } - else - { - m_pCurrentEntity->curstate.controller[0] = 127; - m_pCurrentEntity->curstate.controller[1] = 127; - m_pCurrentEntity->curstate.controller[2] = 127; - m_pCurrentEntity->curstate.controller[3] = 127; - m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; - m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; - m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; - m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - m_pPlayerInfo->gaitsequence = 0; - - StudioSetUpTransform( 0 ); - } - - if (flags & STUDIO_RENDER) - { - // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) - return 0; - - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie - - if (m_pStudioHeader->numbodyparts == 0) - return 1; - } - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - StudioSetupBones( ); - StudioSaveBones( ); - m_pPlayerInfo->renderframe = m_nFrameCount; - - m_pPlayerInfo = NULL; - - if (flags & STUDIO_EVENTS) - { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); - // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); - } - } - - if (flags & STUDIO_RENDER) - { - /* - if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) - { - // show highest resolution multiplayer model - m_pCurrentEntity->curstate.body = 255; - } - */ - - lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); - - IEngineStudio.StudioEntityLight( &lighting ); - - // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - // get remap colors - m_nTopColor = m_pPlayerInfo->topcolor; - m_nBottomColor = m_pPlayerInfo->bottomcolor; - if (m_nTopColor < 0) - m_nTopColor = 0; - if (m_nTopColor > 360) - m_nTopColor = 360; - if (m_nBottomColor < 0) - m_nBottomColor = 0; - if (m_nBottomColor > 360) - m_nBottomColor = 360; - - IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - - StudioRenderModel( ); - m_pPlayerInfo = NULL; - - if (pplayer->weaponmodel) - { - cl_entity_t saveent = *m_pCurrentEntity; - - model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - - StudioMergeBones( pweaponmodel); - - IEngineStudio.StudioSetupLighting (&lighting); - - StudioRenderModel( ); - - StudioCalcAttachments( ); - - *m_pCurrentEntity = saveent; - } - } - - return 1; -} - -/* -==================== -StudioCalcAttachments - -==================== -*/ -void CStudioModelRenderer::StudioCalcAttachments( void ) -{ - int i; - mstudioattachment_t *pattachment; - - if ( m_pStudioHeader->numattachments > 4 ) - { - gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); - exit( -1 ); - } - - // calculate attachment points - pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); - for (i = 0; i < m_pStudioHeader->numattachments; i++) - { - VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); - } -} - -/* -==================== -StudioRenderModel - -==================== -*/ -void CStudioModelRenderer::StudioRenderModel( void ) -{ - IEngineStudio.SetChromeOrigin(); - IEngineStudio.SetForceFaceFlags( 0 ); - - if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) - { - m_pCurrentEntity->curstate.renderfx = kRenderFxNone; - StudioRenderFinal( ); - - if ( !IEngineStudio.IsHardware() ) - { - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - } - - IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME ); - - gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); - m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; - - StudioRenderFinal( ); - if ( !IEngineStudio.IsHardware() ) - { - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - } - } - else - { - StudioRenderFinal( ); - } -} - -/* -==================== -StudioRenderFinal_Software - -==================== -*/ -void CStudioModelRenderer::StudioRenderFinal_Software( void ) -{ - int i; - - // Note, rendermode set here has effect in SW - IEngineStudio.SetupRenderer( 0 ); - - // Put this in here? - //int theRenderMode = GetRenderModeForModelName(rendermode, m_pSubModel[i].name); - - if (m_pCvarDrawEntities->value == 2) - { - IEngineStudio.StudioDrawBones( ); - } - else if (m_pCvarDrawEntities->value == 3) - { - IEngineStudio.StudioDrawHulls( ); - } - else - { - for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) - { - IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); - IEngineStudio.StudioDrawPoints( ); - } - } - - if (m_pCvarDrawEntities->value == 4) - { - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - IEngineStudio.StudioDrawHulls( ); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - } - - if (m_pCvarDrawEntities->value == 5) - { - IEngineStudio.StudioDrawAbsBBox( ); - } - - IEngineStudio.RestoreRenderer(); -} - -/* -==================== -StudioRenderFinal_Hardware - - ==================== -*/ -void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) -{ - int i; - int rendermode; - - rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; - IEngineStudio.SetupRenderer( rendermode ); - - if (m_pCvarDrawEntities->value == 2) - { - IEngineStudio.StudioDrawBones(); - } - else if (m_pCvarDrawEntities->value == 3) - { - IEngineStudio.StudioDrawHulls(); - } - else - { - for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) - { - IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); - - if (m_fDoInterp) - { - // interpolation messes up bounding boxes. - m_pCurrentEntity->trivial_accept = 0; - } - - IEngineStudio.GL_SetRenderMode(rendermode); - -// mstudiobodyparts_t* pbodypart = (mstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + i; -// -// //int index = m_bodynum / pbodypart->base; -// //index = index % pbodypart->nummodels; -// -// mstudiomodel_t* theModel = (mstudiomodel_t *)((byte *)m_pStudioHeader + pbodypart->modelindex);// + index; -// ASSERT(theModel); -// -// int theModelRenderMode = rendermode;//GetRenderModeForModelName(rendermode, theModel->name); -// -// // This could be dangerous...how to find out? -// //IEngineStudio.SetupRenderer( theModelRenderMode ); -// -// IEngineStudio.GL_SetRenderMode( theModelRenderMode ); - - IEngineStudio.StudioDrawPoints(); - IEngineStudio.GL_StudioDrawShadow(); - } - } - - if ( m_pCvarDrawEntities->value == 4 ) - { - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - IEngineStudio.StudioDrawHulls( ); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - } - - if (m_pCvarDrawEntities->value == 5) - { - IEngineStudio.StudioDrawAbsBBox( ); - } - - IEngineStudio.RestoreRenderer(); -} - -/* -==================== -StudioRenderFinal - -==================== -*/ -void CStudioModelRenderer::StudioRenderFinal(void) -{ - if ( IEngineStudio.IsHardware() ) - { - StudioRenderFinal_Hardware(); - } - else - { - StudioRenderFinal_Software(); - } -} - + } + + paSequences = (cache_user_t *)m_pSubModel->submodels; + + if (paSequences == NULL) + { + paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! + m_pSubModel->submodels = (dmodel_t *)paSequences; + } + + if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) + { + gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); + IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); + } + return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); +} + +/* +==================== +StudioPlayerBlend + +==================== +*/ +void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) +{ + // calc up/down pointing + *pBlend = (*pPitch * 3); + if (*pBlend < pseqdesc->blendstart[0]) + { + *pPitch -= pseqdesc->blendstart[0] / 3.0; + *pBlend = 0; + } + else if (*pBlend > pseqdesc->blendend[0]) + { + *pPitch -= pseqdesc->blendend[0] / 3.0; + *pBlend = 255; + } + else + { + if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error + *pBlend = 127; + else + *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pPitch = 0; + } +} + +/* +==================== +StudioSetUpTransform + +==================== +*/ +void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) +{ + int i; + vec3_t angles; + vec3_t modelpos; + +// tweek model origin + //for (i = 0; i < 3; i++) + // modelpos[i] = m_pCurrentEntity->origin[i]; + + VectorCopy( m_pCurrentEntity->origin, modelpos ); + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; + angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; + angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; + + //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); + //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) + { + float f = 0; + float d; + + // don't do it if the goalstarttime hasn't updated in a while. + + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + + if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && + ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) + { + f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); + //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); + } + + if (m_fDoInterp) + { + // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set + f = f - 1.0; + } + else + { + f = 0; + } + + for (i = 0; i < 3; i++) + { + modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; + } + + // NOTE: Because multiplayer lag can be relatively large, we don't want to cap + // f at 1.5 anymore. + //if (f > -1.0 && f < 1.5) {} + +// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); + for (i = 0; i < 3; i++) + { + float ang1, ang2; + + ang1 = m_pCurrentEntity->angles[i]; + ang2 = m_pCurrentEntity->latched.prevangles[i]; + + d = ang1 - ang2; + if (d > 180) + { + d -= 360; + } + else if (d < -180) + { + d += 360; + } + + angles[i] += d * f; + } + //Con_DPrintf("%.3f \n", f ); + } + else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) + { + VectorCopy( m_pCurrentEntity->angles, angles ); + } + + // Added by mmcguire. + + if (m_pCurrentEntity->curstate.iuser3 == AVH_USER3_ALIEN_PLAYER1) + { + + // Override the orientation with the values stored in vuser1. + + VectorCopy(m_pCurrentEntity->curstate.vuser1, angles); + + // The code that sets up the transformation negates the pitch + // for some reason, so compensate for that here. + + angles[PITCH] = -angles[PITCH]; + + } + + +// bool theIsWallSticking = GetHasUpgrade(m_pCurrentEntity->curstate.iuser4, MASK_WALLSTICKING); +// if(theIsWallSticking) +// { +// //RotateFloatValuesByVector(angles[ROLL], angles[YAW], angles[PITCH], m_pCurrentEntity->curstate.vuser1); +// //VectorCopy(m_pCurrentEntity->curstate.vuser1, angles); +// +// // Surface normal is in vuser1. Transform current forward to new forward +// vec3_t theCurrentForward; +// vec3_t theCurrentRight; +// vec3_t theCurrentUp; +// gEngfuncs.pfnAngleVectors(angles, theCurrentForward, theCurrentRight, theCurrentUp); +// +// vec3_t theWallUp = m_pCurrentEntity->curstate.vuser1; +// +// vec3_t theWallSide; +// CrossProduct(theWallUp, theCurrentForward, theWallSide); +// +// vec3_t theWallForward; +// //CrossProduct(theWallUp, theWallSide, theWallForward); +// VectorCopy(theCurrentForward, theWallForward); +// +// // Build matrix to transform current frame of reference to that of sticking to wall +// float theViewToWallMatrix[3][4]; +// theViewToWallMatrix[0][0] = theWallForward.x; +// theViewToWallMatrix[0][1] = theWallForward.y; +// theViewToWallMatrix[0][2] = theWallForward.z; +// +// theViewToWallMatrix[1][0] = theWallSide.x; +// theViewToWallMatrix[1][1] = theWallSide.y; +// theViewToWallMatrix[1][2] = theWallSide.z; +// +// theViewToWallMatrix[2][0] = theWallUp.x; +// theViewToWallMatrix[2][1] = theWallUp.y; +// theViewToWallMatrix[2][2] = theWallUp.z; +// +// vec3_t theNewForward; +// VectorTransform(theCurrentForward, theViewToWallMatrix, theNewForward); +// +// // Transform new forward to angles +// VectorAngles(theNewForward, angles); +// } + + //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); + //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); + + angles[PITCH] = -angles[PITCH]; + AngleMatrix (angles, (*m_protationmatrix)); + + if ( !IEngineStudio.IsHardware() ) + { + static float viewmatrix[3][4]; + + VectorCopy (m_vRight, viewmatrix[0]); + VectorCopy (m_vUp, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (m_vNormal, viewmatrix[2]); + + (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; + (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; + (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; + + ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); + + // do the scaling up of x and y to screen coordinates as part of the transform + // for the unclipped case (it would mess up clipping in the clipped case). + // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y + // correspondingly so the projected x and y come out right + // FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + (*m_paliastransform)[0][i] *= m_fSoftwareXScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[1][i] *= m_fSoftwareYScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); + + } + } + } + + (*m_protationmatrix)[0][3] = modelpos[0]; + (*m_protationmatrix)[1][3] = modelpos[1]; + (*m_protationmatrix)[2][3] = modelpos[2]; +} + + +/* +==================== +StudioEstimateInterpolant + +==================== +*/ +float CStudioModelRenderer::StudioEstimateInterpolant( void ) +{ + float dadt = 1.0; + + if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) + { + dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; + if (dadt > 2.0) + { + dadt = 2.0; + } + } + return dadt; +} + +/* +==================== +StudioCalcRotations + +==================== +*/ +void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +{ + int i; + int frame; + mstudiobone_t *pbone; + + float s; + float adj[MAXSTUDIOCONTROLLERS]; + float dadt; + + if (f > pseqdesc->numframes - 1) + { + f = 0; // bah, fix this bug with changing sequences too fast + } + // BUG ( somewhere else ) but this code should validate this data. + // This could cause a crash if the frame # is negative, so we'll go ahead + // and clamp it here + else if ( f < -0.01 ) + { + f = -0.01; + } + + frame = (int)f; + + //gEngfuncs.Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); + + // gEngfuncs.Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); + + //gEngfuncs.Con_DPrintf("frame %d %d\n", frame1, frame2 ); + + + dadt = StudioEstimateInterpolant( ); + s = (f - frame); + + // add in programtic controllers + pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); + + for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) + { + StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); + + StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + // if (0 && i == 0) + // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); + } + + if (pseqdesc->motiontype & STUDIO_X) + { + pos[pseqdesc->motionbone][0] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Y) + { + pos[pseqdesc->motionbone][1] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Z) + { + pos[pseqdesc->motionbone][2] = 0.0; + } + + //gEngfuncs.Con_Printf("framerate %f\n", m_pCurrentEntity->curstate.framerate); + + s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; + + if (pseqdesc->motiontype & STUDIO_LX) + { + pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; + } + if (pseqdesc->motiontype & STUDIO_LY) + { + pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; + } + if (pseqdesc->motiontype & STUDIO_LZ) + { + pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; + } +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + float scale; + + scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; + if ( scale > 2 ) // Don't blow up more than 200% + scale = 2; + transform[0][1] *= scale; + transform[1][1] *= scale; + transform[2][1] *= scale; + } + break; + + } +} + +/* +==================== +StudioEstimateFrame + +==================== +*/ +float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) +{ + double dfdt, f; + + if ( m_fDoInterp ) + { + if ( m_clTime < m_pCurrentEntity->curstate.animtime ) + { + dfdt = 0; + } + else + { + dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; + + } + } + else + { + dfdt = 0; + } + + if (pseqdesc->numframes <= 1) + { + f = 0; + } + else + { + f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; + } + + f += dfdt; + + if (pseqdesc->flags & STUDIO_LOOPING) + { + if (pseqdesc->numframes > 1) + { + f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + } + if (f < 0) + { + f += (pseqdesc->numframes - 1); + } + } + else + { + if (f >= pseqdesc->numframes - 1.001) + { + f = pseqdesc->numframes - 1.001; + } + if (f < 0.0) + { + f = 0.0; + } + } + return f; +} + +bool GetDoesBoneHaveParent(int inMaybeBeneathBone, int inParentBone, mstudiobone_t* inBones) +{ + bool theSuccess = false; + + ASSERT(inMaybeBeneathBone < MAXSTUDIOBONES); + ASSERT(inParentBone < MAXSTUDIOBONES); + + int theCurrentParent = inBones[inMaybeBeneathBone].parent; + + if(theCurrentParent == inParentBone) + { + theSuccess = true; + } + else if(theCurrentParent != -1) + { + theSuccess = GetDoesBoneHaveParent(theCurrentParent, inParentBone, inBones); + } + + return theSuccess; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + else if (m_pCurrentEntity->curstate.sequence < 0) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + if (pseqdesc->numblends > 1) + { + float s; + float dadt; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + dadt = StudioEstimateInterpolant(); + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + + StudioSlerpBones( q, pos, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); + + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q, pos, q3, pos3, s ); + } + } + + if (m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + if (pseqdesc->numblends > 1) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; + StudioSlerpBones( q1b, pos1b, q3, pos3, s ); + } + } + + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + //Con_DPrintf("prevframe = %4.2f\n", f); + m_pCurrentEntity->latched.prevframe = f; + } + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + // calc gait animation + if (m_pPlayerInfo && (m_pPlayerInfo->gaitsequence != 0) && (m_pPlayerInfo->gaitsequence != 255)) + { + m_pPlayerInfo->gaitsequence = max(min(m_pPlayerInfo->gaitsequence, m_pStudioHeader->numseq-1), 0); + +// // Trim sequences within range (not sure why this is out of range though) +// int theIndex = min(max(0, m_pStudioHeader->seqindex), m_pStudioHeader->numseq - 1); +// if(theIndex != m_pStudioHeader->seqindex) +// { +// m_pStudioHeader->seqindex = theIndex; +// m_pPlayerInfo->gaitsequence = 0; +// } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); + +// Valve way +// for (i = 0; i < m_pStudioHeader->numbones; i++) +// { +// if (strcmp( pbones[i].name, "Bip01 Spine") == 0) +// break; +// memcpy( pos[i], pos2[i], sizeof( pos[i] )); +// memcpy( q[i], q2[i], sizeof( q[i] )); +// } + +// NS way + // Look up parent bone that defines the boundary for gaitsequence + int theNumParents = 0; + int theParents[MAXSTUDIOBONES]; + memset(theParents, -1, sizeof(int)*MAXSTUDIOBONES); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + // Must contain "Thigh" + if(strstr(pbones[i].name, "Thigh")) + { + theParents[theNumParents++] = i; + } + } + // If this is firing, it means a model has a gaitsequence set but doesn't have a bone that defines which bones are used for that gaitsequence + //ASSERT(theNumParents > 0); + + // If there aren't any thighs, assume that the old HL way was used + if(theNumParents > 0) + { + int theNumBonesWithThisParent = 0; + int theBonesWithParent[MAXSTUDIOBONES]; + + // For each bone + for(i = 0; i < m_pStudioHeader->numbones; i++) + { + for(int j = 0; j < theNumParents; j++) + { + // Does bone have this parent bone? + int theParent = theParents[j]; + //if(/*(i == theParent) ||*/ GetDoesBoneHaveParent(i, theParent, pbones)) + char* theBoneName = pbones[i].name; + if(!strcmp(theBoneName, "Bip01") || (!strcmp(theBoneName, "Bip01 Pelvis")) || (i == theParent) || GetDoesBoneHaveParent(i, theParent, pbones)) + { + // If so, add it to the list and increment num bones + theBonesWithParent[theNumBonesWithThisParent++] = i; + break; + } + } + } + + for(int j = 0; j < theNumBonesWithThisParent; j++) + { + int i = theBonesWithParent[j]; + + // If the bone is in this list, use that bones data (gaitsequence) instead of the existing data (sequence) + memcpy( pos[i], pos2[i], sizeof( pos[i] )); + memcpy( q[i], q2[i], sizeof( q[i] )); + } + } + else + { + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + if (strcmp( pbones[i].name, "Bip01 Spine") == 0) + break; + memcpy( pos[i], pos2[i], sizeof( pos[i] )); + memcpy( q[i], q2[i], sizeof( q[i] )); + } + } + + //gEngfuncs.Con_Printf("gait: %d, frame: %f\n", m_pPlayerInfo->gaitsequence, m_pPlayerInfo->gaitframe); + } + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + + +/* +==================== +StudioSaveBones + +==================== +*/ +void CStudioModelRenderer::StudioSaveBones( void ) +{ + int i; + + mstudiobone_t *pbones; + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + m_nCachedBones = m_pStudioHeader->numbones; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + strcpy( m_nCachedBoneNames[i], pbones[i].name ); + MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); + MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] ); + } +} + + +/* +==================== +StudioMergeBones + +==================== +*/ +void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) +{ + int i, j; + double f; + int do_hunt = true; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + float bonematrix[3][4]; + static vec4_t q[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pSubModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + for (j = 0; j < m_nCachedBones; j++) + { + if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) + { + MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); + MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); + break; + } + } + if (j >= m_nCachedBones) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } + } +} + +/* +==================== +StudioDrawModel + +==================== +*/ +int CStudioModelRenderer::StudioDrawModel( int flags ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + // Horrible hack for preventing visual artifacts while being digested + if(gHUD.GetIsBeingDigested()) + { + return 0; + } + + /* + // Now render eyebeam if model is marine // + // If player is a marine + if(m_pCurrentEntity->curstate.iuser3 == AVH_USER3_MARINE_PLAYER) + { + // Get eyepiece attachment + vec3_t theEyepieceOrigin; + VectorCopy(m_pCurrentEntity->attachment[2], theEyepieceOrigin); + + // Build this line + + // Run a traceline along this line until it hits + + // Get endpoint + + // Draw red additive light along this line + //gEngfuncs.pEfxAPI->R_RocketTrail(); + } + */ + + if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) + { + entity_state_t deadplayer; + + int result; + int save_interp; + + if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) + return 0; + + // get copy of player + deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; + + // clear weapon, movement state + deadplayer.number = m_pCurrentEntity->curstate.renderamt; + deadplayer.weaponmodel = 0; + deadplayer.gaitsequence = 0; + + deadplayer.movetype = MOVETYPE_NONE; + VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles ); + VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin ); + + save_interp = m_fDoInterp; + m_fDoInterp = 0; + + // draw as though it were a player + result = StudioDrawPlayer( flags, &deadplayer ); + + m_fDoInterp = save_interp; + return result; + } + + m_pRenderModel = m_pCurrentEntity->model; + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + StudioSetUpTransform( 0 ); + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) + { + StudioMergeBones( m_pRenderModel ); + } + else + { + StudioSetupBones( ); + } + StudioSaveBones( ); + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + // get remap colors + m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel(); + + // If this is the local player's view model, hook into HUD + char theModelName[MAX_MODEL_NAME]; + strcpy(theModelName, this->m_pCurrentEntity->model->name); + + gHUD.PostModelRender(theModelName); + } + + return 1; +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + int iBlend; + float flYaw; // view direction relative to movement + + m_pCurrentEntity->curstate.sequence = max(min(m_pCurrentEntity->curstate.sequence, m_pStudioHeader->numseq-1), 0); + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); + + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + m_pCurrentEntity->curstate.blending[0] = iBlend; + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + StudioEstimateGait( pplayer ); + + // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + if (flYaw < -180) + flYaw = flYaw + 360; + if (flYaw > 180) + flYaw = flYaw - 360; + + if (flYaw > 120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + // adjust torso + m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + m_pCurrentEntity->angles[YAW] += 360; + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + pplayer->gaitsequence = max(min(pplayer->gaitsequence, m_pStudioHeader->numseq-1), 0); + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; + } + + // do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + m_pPlayerInfo->gaitframe += pseqdesc->numframes; +} + +/* +==================== +StudioDrawPlayer + +==================== +*/ +int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + // Horrible hack for preventing visual artifacts while being digested + if(gHUD.GetIsBeingDigested()) + { + return 0; + } + + // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); + + // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); + + // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + //m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + m_pRenderModel = m_pCurrentEntity->model; + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + /* + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + */ + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +StudioCalcAttachments + +==================== +*/ +void CStudioModelRenderer::StudioCalcAttachments( void ) +{ + int i; + mstudioattachment_t *pattachment; + + if ( m_pStudioHeader->numattachments > 4 ) + { + gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); + exit( -1 ); + } + + // calculate attachment points + pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + for (i = 0; i < m_pStudioHeader->numattachments; i++) + { + VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); + } +} + +/* +==================== +StudioRenderModel + +==================== +*/ +void CStudioModelRenderer::StudioRenderModel( void ) +{ + IEngineStudio.SetChromeOrigin(); + IEngineStudio.SetForceFaceFlags( 0 ); + + if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) + { + m_pCurrentEntity->curstate.renderfx = kRenderFxNone; + StudioRenderFinal( ); + + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + } + + IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME ); + + gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); + m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; + + StudioRenderFinal( ); + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + } + else + { + StudioRenderFinal( ); + } +} + +/* +==================== +StudioRenderFinal_Software + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Software( void ) +{ + int i; + + // Note, rendermode set here has effect in SW + IEngineStudio.SetupRenderer( 0 ); + + // Put this in here? + //int theRenderMode = GetRenderModeForModelName(rendermode, m_pSubModel[i].name); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones( ); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls( ); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + IEngineStudio.StudioDrawPoints( ); + } + } + + if (m_pCvarDrawEntities->value == 4) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal_Hardware + + ==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) +{ + int i; + int rendermode; + + rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; + IEngineStudio.SetupRenderer( rendermode ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones(); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls(); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + + if (m_fDoInterp) + { + // interpolation messes up bounding boxes. + m_pCurrentEntity->trivial_accept = 0; + } + + IEngineStudio.GL_SetRenderMode(rendermode); + +// mstudiobodyparts_t* pbodypart = (mstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + i; +// +// //int index = m_bodynum / pbodypart->base; +// //index = index % pbodypart->nummodels; +// +// mstudiomodel_t* theModel = (mstudiomodel_t *)((byte *)m_pStudioHeader + pbodypart->modelindex);// + index; +// ASSERT(theModel); +// +// int theModelRenderMode = rendermode;//GetRenderModeForModelName(rendermode, theModel->name); +// +// // This could be dangerous...how to find out? +// //IEngineStudio.SetupRenderer( theModelRenderMode ); +// +// IEngineStudio.GL_SetRenderMode( theModelRenderMode ); + + IEngineStudio.StudioDrawPoints(); + IEngineStudio.GL_StudioDrawShadow(); + } + } + + if ( m_pCvarDrawEntities->value == 4 ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal(void) +{ + if ( IEngineStudio.IsHardware() ) + { + StudioRenderFinal_Hardware(); + } + else + { + StudioRenderFinal_Software(); + } +} + diff --git a/main/source/cl_dll/StudioModelRenderer.h b/main/source/cl_dll/StudioModelRenderer.h index 0220d448..fae3a8ee 100644 --- a/main/source/cl_dll/StudioModelRenderer.h +++ b/main/source/cl_dll/StudioModelRenderer.h @@ -1,182 +1,182 @@ -#if !defined ( STUDIOMODELRENDERER_H ) -#define STUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif - -/* -==================== -CStudioModelRenderer - -==================== -*/ -class CStudioModelRenderer -{ -public: - // Construction/Destruction - CStudioModelRenderer( void ); - virtual ~CStudioModelRenderer( void ); - - // Initialization - virtual void Init( void ); - -public: - // Public Interfaces - virtual int StudioDrawModel ( int flags ); - virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); - -public: - // Local interfaces - // - - // Look up animation data for sequence - virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); - - // Interpolate model position and angles and set up matrices - virtual void StudioSetUpTransform (int trivial_accept); - - // Set up model bone positions - virtual void StudioSetupBones ( void ); - - // Find final attachment points - virtual void StudioCalcAttachments ( void ); - - // Save bone matrices and names - virtual void StudioSaveBones( void ); - - // Merge cached bones with current bones for model - virtual void StudioMergeBones ( model_t *m_pSubModel ); - - // Determine interpolation fraction - virtual float StudioEstimateInterpolant( void ); - - // Determine current frame for rendering - virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); - - // Apply special effects to transform matrix - virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); - - // Spherical interpolation of bones - virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); - - // Compute bone adjustments ( bone controllers ) - virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); - - // Get bone quaternions - virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); - - // Get bone positions - virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); - - // Compute rotations - virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); - - // Send bones and verts to renderer - virtual void StudioRenderModel ( void ); - - // Finalize rendering - virtual void StudioRenderFinal (void); - - // GL&D3D vs. Software renderer finishing functions - virtual void StudioRenderFinal_Software ( void ); - virtual void StudioRenderFinal_Hardware ( void ); - - // Player specific data - // Determine pitch and blending amounts for players - virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); - - // Estimate gait frame for player - virtual void StudioEstimateGait ( entity_state_t *pplayer ); - - // Process movement of player - virtual void StudioProcessGait ( entity_state_t *pplayer ); - -public: - - // Client clock - double m_clTime; - // Old Client clock - double m_clOldTime; - - // Do interpolation? - int m_fDoInterp; - // Do gait estimation? - int m_fGaitEstimation; - - // Current render frame # - int m_nFrameCount; - - // Cvars that studio model code needs to reference - // - // Use high quality models? - cvar_t *m_pCvarHiModels; - // Developer debug output desired? - cvar_t *m_pCvarDeveloper; - // Draw entities bone hit boxes, etc? - cvar_t *m_pCvarDrawEntities; - - // The entity which we are currently rendering. - cl_entity_t *m_pCurrentEntity; - - // The model for the entity being rendered - model_t *m_pRenderModel; - - // Player info for current player, if drawing a player - player_info_t *m_pPlayerInfo; - - // The index of the player being drawn - int m_nPlayerIndex; - - // The player's gait movement - float m_flGaitMovement; - - // Pointer to header block for studio model data - studiohdr_t *m_pStudioHeader; - - // Pointers to current body part and submodel - mstudiobodyparts_t *m_pBodyPart; - mstudiomodel_t *m_pSubModel; - - // Palette substition for top and bottom of model - int m_nTopColor; - int m_nBottomColor; - - // - // Sprite model used for drawing studio model chrome - model_t *m_pChromeSprite; - - // Caching - // Number of bones in bone cache - int m_nCachedBones; - // Names of cached bones - char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; - // Cached bone & light transformation matrices - float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; - float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; - - // Software renderer scale factors - float m_fSoftwareXScale, m_fSoftwareYScale; - - // Current view vectors and render origin - float m_vUp[ 3 ]; - float m_vRight[ 3 ]; - float m_vNormal[ 3 ]; - - float m_vRenderOrigin[ 3 ]; - - // Model render counters ( from engine ) - int *m_pStudioModelCount; - int *m_pModelsDrawn; - - // Matrices - // Model to world transformation - float (*m_protationmatrix)[ 3 ][ 4 ]; - // Model to view transformation - float (*m_paliastransform)[ 3 ][ 4 ]; - - // Concatenated bone and light transforms - float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; - float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; -}; - +#if !defined ( STUDIOMODELRENDERER_H ) +#define STUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CStudioModelRenderer + +==================== +*/ +class CStudioModelRenderer +{ +public: + // Construction/Destruction + CStudioModelRenderer( void ); + virtual ~CStudioModelRenderer( void ); + + // Initialization + virtual void Init( void ); + +public: + // Public Interfaces + virtual int StudioDrawModel ( int flags ); + virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); + +public: + // Local interfaces + // + + // Look up animation data for sequence + virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); + + // Interpolate model position and angles and set up matrices + virtual void StudioSetUpTransform (int trivial_accept); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Find final attachment points + virtual void StudioCalcAttachments ( void ); + + // Save bone matrices and names + virtual void StudioSaveBones( void ); + + // Merge cached bones with current bones for model + virtual void StudioMergeBones ( model_t *m_pSubModel ); + + // Determine interpolation fraction + virtual float StudioEstimateInterpolant( void ); + + // Determine current frame for rendering + virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + + // Spherical interpolation of bones + virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); + + // Compute bone adjustments ( bone controllers ) + virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); + + // Get bone quaternions + virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); + + // Get bone positions + virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); + + // Compute rotations + virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); + + // Send bones and verts to renderer + virtual void StudioRenderModel ( void ); + + // Finalize rendering + virtual void StudioRenderFinal (void); + + // GL&D3D vs. Software renderer finishing functions + virtual void StudioRenderFinal_Software ( void ); + virtual void StudioRenderFinal_Hardware ( void ); + + // Player specific data + // Determine pitch and blending amounts for players + virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + +public: + + // Client clock + double m_clTime; + // Old Client clock + double m_clOldTime; + + // Do interpolation? + int m_fDoInterp; + // Do gait estimation? + int m_fGaitEstimation; + + // Current render frame # + int m_nFrameCount; + + // Cvars that studio model code needs to reference + // + // Use high quality models? + cvar_t *m_pCvarHiModels; + // Developer debug output desired? + cvar_t *m_pCvarDeveloper; + // Draw entities bone hit boxes, etc? + cvar_t *m_pCvarDrawEntities; + + // The entity which we are currently rendering. + cl_entity_t *m_pCurrentEntity; + + // The model for the entity being rendered + model_t *m_pRenderModel; + + // Player info for current player, if drawing a player + player_info_t *m_pPlayerInfo; + + // The index of the player being drawn + int m_nPlayerIndex; + + // The player's gait movement + float m_flGaitMovement; + + // Pointer to header block for studio model data + studiohdr_t *m_pStudioHeader; + + // Pointers to current body part and submodel + mstudiobodyparts_t *m_pBodyPart; + mstudiomodel_t *m_pSubModel; + + // Palette substition for top and bottom of model + int m_nTopColor; + int m_nBottomColor; + + // + // Sprite model used for drawing studio model chrome + model_t *m_pChromeSprite; + + // Caching + // Number of bones in bone cache + int m_nCachedBones; + // Names of cached bones + char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; + // Cached bone & light transformation matrices + float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; + + // Software renderer scale factors + float m_fSoftwareXScale, m_fSoftwareYScale; + + // Current view vectors and render origin + float m_vUp[ 3 ]; + float m_vRight[ 3 ]; + float m_vNormal[ 3 ]; + + float m_vRenderOrigin[ 3 ]; + + // Model render counters ( from engine ) + int *m_pStudioModelCount; + int *m_pModelsDrawn; + + // Matrices + // Model to world transformation + float (*m_protationmatrix)[ 3 ][ 4 ]; + // Model to view transformation + float (*m_paliastransform)[ 3 ][ 4 ]; + + // Concatenated bone and light transforms + float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; +}; + #endif // STUDIOMODELRENDERER_H \ No newline at end of file diff --git a/main/source/cl_dll/ammo.cpp b/main/source/cl_dll/ammo.cpp index e8c33dec..9d8af707 100644 --- a/main/source/cl_dll/ammo.cpp +++ b/main/source/cl_dll/ammo.cpp @@ -1,1461 +1,1461 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Ammo.cpp -// -// implementation of CHudAmmo class -// - -#include "hud.h" -#include "cl_util.h" - -#include -#include - -#include "ammohistory.h" -#include "vgui_TeamFortressViewport.h" -#include "mod/AvHClientVariables.h" -#include "mod/AvHSharedUtil.h" -#include "mod/AvHScrollHandler.h" -#include "mod/AvHNetworkMessages.h" - -WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise - // this points to the active weapon menu item -WEAPON *gpLastSel; // Last weapon menu selection - -bool HUD_GetWeaponEnabled(int inID); -client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); - -WeaponsResource gWR; - -int g_weaponselect = 0; - -extern bool gCanMove; - -void IN_AttackDownForced(void); -void IN_AttackUpForced(void); -void IN_Attack2Down(void); -void IN_Attack2Up(void); -void IN_ReloadDown(); -void IN_ReloadUp(); -bool CheckInAttack(void); - -//Equivalent to DECLARE_COMMAND(lastinv,LastInv) except we use gWR instead of gHud -void __CmdFunc_LastInv(void) -{ gWR.UserCmd_LastInv(); } - -// +movement -void __CmdFunc_MovementOn(void) -{ gWR.UserCmd_MovementOn(); } -void __CmdFunc_MovementOff(void) -{ gWR.UserCmd_MovementOff(); } - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -WeaponsResource::WeaponsResource(void) : lastWeapon(NULL), iOldWeaponBits(0) {} -WeaponsResource::~WeaponsResource(void) {} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::Init( void ) -{ - memset( rgWeapons, 0, sizeof(WEAPON)*MAX_WEAPONS ); - Reset(); - HOOK_COMMAND("lastinv", LastInv); - // +movement - HOOK_COMMAND("+movement", MovementOn); - HOOK_COMMAND("-movement", MovementOff); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::Reset( void ) -{ - lastWeapon = NULL; - iOldWeaponBits = 0; - memset( rgSlots, 0, sizeof(WEAPON*)*MAX_WEAPON_SLOTS*MAX_WEAPON_POSITIONS ); - memset( riAmmo, 0, sizeof(int)*MAX_AMMO_TYPES ); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource :: LoadAllWeaponSprites( void ) -{ - int customCrosshairs=CVAR_GET_FLOAT(kvCustomCrosshair); - for (int i = 0; i < MAX_WEAPONS; i++) - { - if ( rgWeapons[i].iId ) - LoadWeaponSprites( &rgWeapons[i], customCrosshairs ); - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -inline void LoadWeaponSprite( client_sprite_t* ptr, HSPRITE& sprite, wrect_t& bounds ) -{ - if( ptr ) - { - string name( "sprites/" ); - name.append( ptr->szSprite ); - name.append( ".spr" ); - sprite = SPR_Load(name.c_str()); - bounds = ptr->rc; - } - else - { - sprite = NULL; - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon, int custom ) -{ - if ( custom < 0 || custom > 4 ) - custom=1; - - int resolutions[6] = { 320, 640, 800, 1024, 1280, 1600}; - const int numRes=6; - int i=0, j=0, iRes=320; - int screenWidth=ScreenWidth(); - - for ( j=0; j < numRes; j++ ) { - if ( screenWidth == resolutions[j] ) { - iRes=resolutions[j]; - break; - } - if ( j > 0 && screenWidth > resolutions[j-1] && screenWidth < resolutions[j] ) { - iRes=resolutions[j-1]; - break; - } - } - - char sz[128]; - - if ( !pWeapon ) - return; - - memset( &pWeapon->rcCrosshair, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) ); - pWeapon->hCrosshair =0; - pWeapon->hInactive = 0; - pWeapon->hActive = 0; - pWeapon->hAmmo = 0; - pWeapon->hAmmo2 = 0; - - sprintf(sz, "sprites/%s.txt", pWeapon->szName); - client_sprite_t *pList = SPR_GetList(sz, &i); - - if (!pList) - { - ASSERT(pList); - return; - } - - char crosshairName[32]; - sprintf(crosshairName, "crosshair_%d", custom); - for ( j=numRes-1; j>=0; j-- ) { - if ( resolutions[j] <= iRes ) { - if( pWeapon->hCrosshair == NULL ) - LoadWeaponSprite( GetSpriteList( pList, crosshairName, resolutions[j], i ), pWeapon->hCrosshair, pWeapon->rcCrosshair ); - if( pWeapon->hCrosshair == NULL && custom != 0 ) - LoadWeaponSprite( GetSpriteList( pList, "crosshair_0", resolutions[j], i ), pWeapon->hCrosshair, pWeapon->rcCrosshair ); - - - if( pWeapon->hInactive == NULL ) - LoadWeaponSprite( GetSpriteList( pList, "weapon", resolutions[j], i ), pWeapon->hInactive, pWeapon->rcInactive ); - - if( pWeapon->hActive == NULL ) - LoadWeaponSprite( GetSpriteList( pList, "weapon_s", resolutions[j], i ), pWeapon->hActive, pWeapon->rcActive ); - - if( pWeapon->hAmmo == NULL ) - LoadWeaponSprite( GetSpriteList( pList, "ammo", resolutions[j], i ), pWeapon->hAmmo, pWeapon->rcAmmo ); - - if( pWeapon->hAmmo2 == NULL ) - LoadWeaponSprite( GetSpriteList( pList, "ammo2", resolutions[j], i ), pWeapon->hAmmo2, pWeapon->rcAmmo2 ); - } - } - - if( pWeapon->hActive || pWeapon->hInactive || pWeapon->hAmmo || pWeapon->hAmmo2 ) - { gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -WEAPON* WeaponsResource::GetWeapon( int iId ) -{ - if( iId < 0 || iId >= MAX_WEAPONS ) { return NULL; } - return rgWeapons[iId].iId ? &rgWeapons[iId] : NULL; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -WEAPON* WeaponsResource::GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; } - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -WEAPON* WeaponsResource::GetFirstPos( int iSlot ) -{ - WEAPON *returnVal = NULL; - ASSERT( iSlot < MAX_WEAPON_SLOTS && iSlot >= 0 ); - - for( int counter = 0; counter < MAX_WEAPON_POSITIONS; ++counter ) - { - if( this->IsSelectable(rgSlots[iSlot][counter]) ) - { - returnVal = rgSlots[iSlot][counter]; - break; - } - } - - return returnVal; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -WEAPON* WeaponsResource::GetNextActivePos( int iSlot, int iSlotPos ) -{ - WEAPON* returnVal = NULL; - ASSERT( iSlot < MAX_WEAPON_SLOTS && iSlot >= 0 ); - ASSERT( iSlotPos >= 0 ); - - for( int counter = iSlotPos+1; counter < MAX_WEAPON_POSITIONS; ++counter ) - { - if( this->IsSelectable(rgSlots[iSlot][counter]) ) - { - returnVal = rgSlots[iSlot][counter]; - break; - } - } - - return returnVal; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -bool WeaponsResource::IsEnabled(WEAPON* p) -{ - if( p == NULL ) { return false; } - return HUD_GetWeaponEnabled(p->iId) && this->HasAmmo(p); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -bool WeaponsResource::IsSelectable(WEAPON* p) -{ - if( p == NULL ) { return false; } - return HUD_GetWeaponEnabled(p->iId); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -bool WeaponsResource::HasAmmo( WEAPON* p ) -{ - if( p == NULL) { return false; } - //note : if max ammo capacity is -1, this has always returned true in spite of not - // having actual ammo -- KGP - return (p->iAmmoType == -1) || (p->iMax1 == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) - || CountAmmo(p->iAmmo2Type) || (p->iFlags & WEAPON_FLAGS_SELECTIONEMPTY ); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -int WeaponsResource::CountAmmo( int iId ) -{ - ASSERT( iId < MAX_AMMO_TYPES ); - if( iId < 0 ) return 0; - return riAmmo[iId]; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -int WeaponsResource::GetAmmo( int iId ) -{ - ASSERT( iId < MAX_AMMO_TYPES && iId > -1 ); - return riAmmo[iId]; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::SetAmmo( int iId, int iCount ) -{ - ASSERT( iId < MAX_AMMO_TYPES && iId > -1 ); - riAmmo[iId] = iCount; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -HSPRITE* WeaponsResource::GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( rgWeapons[i].iAmmoType == iAmmoId ) - { - rect = rgWeapons[i].rcAmmo; - return &rgWeapons[i].hAmmo; - } - else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) - { - rect = rgWeapons[i].rcAmmo2; - return &rgWeapons[i].hAmmo2; - } - } - - return NULL; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::AddWeapon( WEAPON *wp ) -{ - int customCrosshairs=CVAR_GET_FLOAT(kvCustomCrosshair); - rgWeapons[ wp->iId ] = *wp; - LoadWeaponSprites( &rgWeapons[ wp->iId ], customCrosshairs); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::PickupWeapon( WEAPON *wp ) -{ - rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp; -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::DropWeapon( WEAPON *wp ) -{ - rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL; - if(lastWeapon == wp) //dropped last weapon, remove it from the list - { lastWeapon = NULL; } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::DropAllWeapons( void ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( rgWeapons[i].iId ) - DropWeapon( &rgWeapons[i] ); - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::UserCmd_LastInv(void) -{ - if(this->IsSelectable(this->lastWeapon)) - { - this->SetCurrentWeapon(lastWeapon); - // : 764 - //const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON); - //gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::UserCmd_MovementOn() -{ - // Find out which weapon we want to trigger - AvHUser3 theUser3 = gHUD.GetHUDUser3(); - int wID = -1; - switch(theUser3) - { - case AVH_USER3_ALIEN_PLAYER1: - wID = AVH_ABILITY_LEAP; - break; - case AVH_USER3_ALIEN_PLAYER3: - // TODO: Add flap - break; - case AVH_USER3_ALIEN_PLAYER4: - wID = AVH_WEAPON_BLINK; - break; - case AVH_USER3_ALIEN_PLAYER5: - wID = AVH_ABILITY_CHARGE; - break; - default: - IN_ReloadDown(); - return; - } - - if (wID > -1) - { - // Fetch the needed movement weapon - WEAPON *p = this->GetWeapon(wID); - if (p != NULL && this->IsSelectable(p)) - { - // Send activation of ability asap - IN_Attack2Down(); - } - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::UserCmd_MovementOff() -{ - // Ensure that we're not activating any weapons when selected - IN_Attack2Up(); - IN_ReloadUp(); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::SetValidWeapon(void) -{ - WEAPON* p = this->GetFirstPos(0); //alien attack 1 or primary marine weapon - if(gHUD.GetIsAlien()) - { - this->SetCurrentWeapon(p); - } - else - { - if(this->IsSelectable(p) && this->HasAmmo(p)) - { - this->SetCurrentWeapon(p); - } - else - { - p = this->GetFirstPos(1); //pistol slot - if(this->IsSelectable(p) && this->HasAmmo(p)) - { - this->SetCurrentWeapon(p); - } - else - { - p = this->GetFirstPos(2); //knife slot - this->SetCurrentWeapon(p); - } - } - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource::SetCurrentWeapon(WEAPON* newWeapon) -{ - WEAPON* currentWeapon = this->GetWeapon(gHUD.GetCurrentWeaponID()); - // : 497 - Because weapon state can get out of sync, we should allow this even if the weapons are the same - // && newWeapon != currentWeapon - if( newWeapon != NULL ) - { - if( newWeapon != currentWeapon ) - { lastWeapon = currentWeapon; } - ServerCmd(newWeapon->szName); - g_weaponselect = newWeapon->iId; - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) -{ - if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) - { // menu is overriding slot use commands - gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers - return; - } - - if ( iSlot >= MAX_WEAPON_SLOTS ) - return; - - if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) - return; - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) //require suit - return; - - if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) //require something besides suit - return; - - WEAPON *p = NULL; - bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; - if ((gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot)) - { - p = GetFirstPos(iSlot); - const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON); - gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - - if (this->IsSelectable(p) && fastSwitch) //check to see if we can use fastSwitch - { - WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); - if (!this->IsSelectable(p2)) //only one target in the bucket - { - this->SetCurrentWeapon(p); - return; - } - } - } - else - { - const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_MOVE_SELECT); - gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - - if ( gpActiveSel ) - p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); - if ( !p ) - p = GetFirstPos( iSlot ); - } - - if (!this->IsSelectable(p)) // no valid selection found - { - // if fastSwitch is on, ignore, else turn on the menu - if ( !fastSwitch ) { - gpActiveSel = (WEAPON *)1; - } - else { - gpActiveSel = NULL; - } - } - else - { - gpActiveSel = p; - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height - -HSPRITE ghsprBuckets; // Sprite for top row of weapons menu - -DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip -DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type -DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count -DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record -DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record -DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily -DECLARE_MESSAGE(m_Ammo, ItemPickup); - -DECLARE_COMMAND(m_Ammo, Slot1); -DECLARE_COMMAND(m_Ammo, Slot2); -DECLARE_COMMAND(m_Ammo, Slot3); -DECLARE_COMMAND(m_Ammo, Slot4); -DECLARE_COMMAND(m_Ammo, Slot5); -DECLARE_COMMAND(m_Ammo, Slot6); -DECLARE_COMMAND(m_Ammo, Slot7); -DECLARE_COMMAND(m_Ammo, Slot8); -DECLARE_COMMAND(m_Ammo, Slot9); -DECLARE_COMMAND(m_Ammo, Slot10); -DECLARE_COMMAND(m_Ammo, Close); -DECLARE_COMMAND(m_Ammo, NextWeapon); -DECLARE_COMMAND(m_Ammo, PrevWeapon); - -// width of ammo fonts -#define AMMO_SMALL_WIDTH 10 -#define AMMO_LARGE_WIDTH 20 - -#define HISTORY_DRAW_TIME "5" - -int CHudAmmo::Init(void) -{ - gHUD.AddHudElem(this); - - HOOK_MESSAGE(CurWeapon); - HOOK_MESSAGE(WeaponList); - HOOK_MESSAGE(AmmoPickup); - HOOK_MESSAGE(WeapPickup); - HOOK_MESSAGE(ItemPickup); - HOOK_MESSAGE(HideWeapon); - HOOK_MESSAGE(AmmoX); - - HOOK_COMMAND("slot1", Slot1); - HOOK_COMMAND("slot2", Slot2); - HOOK_COMMAND("slot3", Slot3); - HOOK_COMMAND("slot4", Slot4); - HOOK_COMMAND("slot5", Slot5); - HOOK_COMMAND("slot6", Slot6); - HOOK_COMMAND("slot7", Slot7); - HOOK_COMMAND("slot8", Slot8); - HOOK_COMMAND("slot9", Slot9); - HOOK_COMMAND("slot10", Slot10); - HOOK_COMMAND("cancelselect", Close); - HOOK_COMMAND("invnext", NextWeapon); - HOOK_COMMAND("invprev", PrevWeapon); - - Reset(); - - CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); - CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress - - m_iFlags |= HUD_ACTIVE; //!!! - - gWR.Init(); - gHR.Init(); - - return 1; -}; - -void CHudAmmo::Reset(void) -{ - m_fFade = 0; - m_iFlags |= HUD_ACTIVE; //!!! - - gpActiveSel = NULL; - gHUD.m_iHideHUDDisplay = 0; - - gWR.Reset(); - gHR.Reset(); - - m_customCrosshair=0; - // VidInit(); - -} - -int CHudAmmo::VidInit(void) -{ - // Load sprites for buckets (top row of weapon menu) - m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); - m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); - - ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); - giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; - giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; - - gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); - - // If we've already loaded weapons, let's get new sprites - gWR.LoadAllWeaponSprites(); - - if (ScreenWidth() >= 640) - { - giABWidth = 20; - giABHeight = 4; - } - else - { - giABWidth = 10; - giABHeight = 2; - } - - return 1; -} - -// -// Think: -// Used for selection of weapon menu item. -// - -void CHudAmmo::Think(void) -{ - if ( gHUD.m_fPlayerDead ) - return; - - if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) - { - gWR.iOldWeaponBits = gHUD.m_iWeaponBits; - bool droppedCurrent = false; - - for (int i = MAX_WEAPONS-1; i > 0; i-- ) - { - WEAPON *p = gWR.GetWeapon(i); - - if ( p ) - { - if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) - gWR.PickupWeapon( p ); - else - gWR.DropWeapon( p ); - } - } - } - if ( (int)CVAR_GET_FLOAT(kvCustomCrosshair) != m_customCrosshair ) { - m_customCrosshair=(int)CVAR_GET_FLOAT(kvCustomCrosshair); - for ( int i=0; i < MAX_WEAPONS; i++ ) { - WEAPON *weapon = gWR.GetWeapon(i); - if ( weapon ) { - gWR.LoadWeaponSprites(weapon, m_customCrosshair); - if ( gHUD.GetHUDPlayMode() != PLAYMODE_READYROOM && gHUD.GetCurrentWeaponID() == weapon->iId ) { - gHUD.SetCurrentCrosshair(weapon->hCrosshair, weapon->rcCrosshair, 255, 255, 255); - } - } - } - - } - - if(gHUD.GetIsAlien()) //check for hive death causing loss of current weapon - { - WEAPON* currentWeapon = gWR.GetWeapon(gHUD.GetCurrentWeaponID()); - if(!gWR.IsSelectable(currentWeapon)) //current weapon isn't valid - { - gWR.SetValidWeapon(); //get best option - } - } - - if (!gpActiveSel) - return; - - // has the player selected one? - if (gHUD.m_iKeyBits & IN_ATTACK) - { - if (gpActiveSel != (WEAPON *)1) - { - gWR.SetCurrentWeapon(gpActiveSel); - } - - gpLastSel = gpActiveSel; - gpActiveSel = NULL; - gHUD.m_iKeyBits &= ~IN_ATTACK; - - const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_SELECT); - gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - } -} - - -//------------------------------------------------------------------------ -// Message Handlers -//------------------------------------------------------------------------ - -// -// AmmoX -- Update the count of a known type of ammo -// -int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) -{ - int iIndex, iCount; - NetMsg_AmmoX( pbuf, iSize, iIndex, iCount ); - gWR.SetAmmo( iIndex, abs(iCount) ); - - return 1; -} - -int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) -{ - int iIndex, iCount; - NetMsg_AmmoPickup( pbuf, iSize, iIndex, iCount ); - - // Add ammo to the history - gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); - - return 1; -} - -int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) -{ - int iIndex; - NetMsg_WeapPickup( pbuf, iSize, iIndex ); - - // Add the weapon to the history - gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); - - return 1; -} - -int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) -{ - string szName; - NetMsg_ItemPickup( pbuf, iSize, szName ); - - // Add the weapon to the history - gHR.AddToHistory( HISTSLOT_ITEM, szName.c_str() ); - - return 1; -} - - -int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) -{ - NetMsg_HideWeapon( pbuf, iSize, gHUD.m_iHideHUDDisplay ); - - if (gEngfuncs.IsSpectateOnly()) - return 1; - if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) - { - static wrect_t nullrc; - gpActiveSel = NULL; - gHUD.SetCurrentCrosshair( 0, nullrc, 0, 0, 0 ); - } - else - { - if ( m_pWeapon ) - gHUD.SetCurrentCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); - } - - return 1; -} - -// -// CurWeapon: Update hud state with the current weapon and clip count. Ammo -// counts are updated with AmmoX. Server assures that the Weapon ammo type -// numbers match a real ammo type. -// -int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) -{ - static wrect_t nullrc; - - int iState, iId, iClip; - NetMsg_CurWeapon( pbuf, iSize, iState, iId, iClip ); - - if ( iId < 1 ) //signal kills crosshairs if this condition is met... - { - gHUD.SetCurrentCrosshair(0, nullrc, 0, 0, 0); - return 0; - } - - if ( g_iUser1 != OBS_IN_EYE ) - { - if ( iId == -1 && iClip == -1 ) //this conditional is never true due to iId < 1 check above! - { - gHUD.m_fPlayerDead = TRUE; - gpActiveSel = NULL; - return 1; - } - - gHUD.m_fPlayerDead = FALSE; - } - - WEAPON *pWeapon = gWR.GetWeapon( iId ); - if( pWeapon == NULL ) //don't have the weapon described in our resource list - { return 0; } - - bool bOnTarget = (iState & WEAPON_ON_TARGET) != 0; //used to track autoaim state - bool bIsCurrent = (iState & WEAPON_IS_CURRENT) != 0; - pWeapon->iEnabled = (iState & WEAPON_IS_ENABLED) != 0 ? TRUE : FALSE; - pWeapon->iClip = abs(iClip); - - // Ensure that movement is enabled/disabled according to weapons - if (iId == 22 || iId == 11 || iId == 21) - { - gCanMove = pWeapon->iEnabled; - } - - if( !bIsCurrent ) - { return 1; } - - m_pWeapon = pWeapon; - - if ( !(gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) - { - gHUD.SetCurrentCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); - -/* if ( gHUD.m_iFOV >= 90 ) - { // normal crosshairs - if (bOnTarget && m_pWeapon->hAutoaim) - gHUD.SetCurrentCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); - else - gHUD.SetCurrentCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); - } - else - { // zoomed crosshairs - if (bOnTarget && m_pWeapon->hZoomedAutoaim) - gHUD.SetCurrentCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); - else - gHUD.SetCurrentCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); - }*/ - } - - m_fFade = 200.0f; //!!! - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -// -// WeaponList -- Tells the hud about a new weapon type. -// -int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) -{ - WeaponList weapon_data; - NetMsg_WeaponList( pbuf, iSize, weapon_data ); - - WEAPON Weapon; - memset( &Weapon, 0, sizeof(WEAPON) ); - - strcpy( Weapon.szName, weapon_data.weapon_name.c_str() ); - Weapon.iAmmoType = weapon_data.ammo1_type; - Weapon.iMax1 = weapon_data.ammo1_max_amnt == 255 ? -1 : weapon_data.ammo1_max_amnt; - Weapon.iAmmo2Type = weapon_data.ammo2_type; - Weapon.iMax2 = weapon_data.ammo2_max_amnt == 255 ? -1 : weapon_data.ammo2_max_amnt; - Weapon.iSlot = weapon_data.bucket; - Weapon.iSlotPos = weapon_data.bucket_pos; - Weapon.iId = weapon_data.bit_index; - Weapon.iFlags = weapon_data.flags; - Weapon.iClip = 0; - // : 497 - default value for enable state - Weapon.iEnabled = 0; - - gWR.AddWeapon( &Weapon ); - return 1; -} - -//------------------------------------------------------------------------ -// Command Handlers -//------------------------------------------------------------------------ -// Slot button pressed -void CHudAmmo::SlotInput( int iSlot ) -{ - // Let the Viewport use it first, for menus - if ( gViewPort && gViewPort->SlotInput( iSlot ) ) - return; - - gWR.SelectSlot( iSlot, FALSE, 1 ); -} - -void CHudAmmo::UserCmd_Slot1(void) -{ - SlotInput( 0 ); -} - -void CHudAmmo::UserCmd_Slot2(void) -{ - SlotInput( 1 ); -} - -void CHudAmmo::UserCmd_Slot3(void) -{ - SlotInput( 2 ); -} - -void CHudAmmo::UserCmd_Slot4(void) -{ - SlotInput( 3 ); -} - -void CHudAmmo::UserCmd_Slot5(void) -{ - SlotInput( 4 ); -} - -void CHudAmmo::UserCmd_Slot6(void) -{ - SlotInput( 5 ); -} - -void CHudAmmo::UserCmd_Slot7(void) -{ - SlotInput( 6 ); -} - -void CHudAmmo::UserCmd_Slot8(void) -{ - SlotInput( 7 ); -} - -void CHudAmmo::UserCmd_Slot9(void) -{ - SlotInput( 8 ); -} - -void CHudAmmo::UserCmd_Slot10(void) -{ - SlotInput( 9 ); -} - -void CHudAmmo::UserCmd_Close(void) -{ - if (gpActiveSel) - { - gpLastSel = gpActiveSel; - gpActiveSel = NULL; - - const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_OFF); - gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - } -} - - -// Selects the next item in the weapon menu -void CHudAmmo::UserCmd_NextWeapon(void) -{ - if(gHUD.GetInTopDownMode()) - { - AvHScrollHandler::ScrollHeightUp(); - } - - if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) - return; - - if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) - gpActiveSel = m_pWeapon; - - int pos = 0; - int slot = 0; - if ( gpActiveSel ) - { - pos = gpActiveSel->iSlotPos + 1; - slot = gpActiveSel->iSlot; - } - - for ( int loop = 0; loop <= 1; loop++ ) - { - for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) - { - for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) - { - WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - - if (gWR.IsSelectable(wsp)) - { - gpActiveSel = wsp; - return; - } - } - - pos = 0; - } - - slot = 0; // start looking from the first slot again - } - - gpActiveSel = NULL; -} - -// Selects the previous item in the menu -void CHudAmmo::UserCmd_PrevWeapon(void) -{ - if(gHUD.GetInTopDownMode()) - { - AvHScrollHandler::ScrollHeightDown(); - } - - if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) - return; - - if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) - gpActiveSel = m_pWeapon; - - int pos = MAX_WEAPON_POSITIONS-1; - int slot = MAX_WEAPON_SLOTS-1; - if ( gpActiveSel ) - { - pos = gpActiveSel->iSlotPos - 1; - slot = gpActiveSel->iSlot; - } - - for ( int loop = 0; loop <= 1; loop++ ) - { - for ( ; slot >= 0; slot-- ) - { - for ( ; pos >= 0; pos-- ) - { - WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - - if (gWR.IsSelectable(wsp)) - { - gpActiveSel = wsp; - return; - } - } - - pos = MAX_WEAPON_POSITIONS-1; - } - - slot = MAX_WEAPON_SLOTS-1; - } - - gpActiveSel = NULL; -} - -void CHudAmmo::SetCurrentClip(int inClip) -{ - if(this->m_pWeapon) - { - this->m_pWeapon->iClip = inClip; - } -} - -//------------------------------------------------------------------------- -// Drawing code -//------------------------------------------------------------------------- - -int CHudAmmo::Draw(float flTime) -{ - int a, x, y, r, g, b; - int AmmoWidth; - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return 1; - - if (/*!gHUD.GetIsAlive() ||*/ (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) - return 1; - - // Draw Weapon Menu - DrawWList(flTime); - - // Draw ammo pickup history - gHR.DrawAmmoHistory( flTime ); - - if (!(m_iFlags & HUD_ACTIVE)) - return 0; - - if (!m_pWeapon) - return 0; - - WEAPON *pw = m_pWeapon; // shorthand - - // SPR_Draw Ammo - if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) - return 0; - - - int iFlags = DHN_DRAWZERO; // draw 0 values - - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - - a = (int) max( MIN_ALPHA, m_fFade ); - - if (m_fFade > 0) - m_fFade -= (gHUD.m_flTimeDelta * 20); - - gHUD.GetPrimaryHudColor(r, g, b); - - ScaleColors(r, g, b, a ); - - int theViewport[4]; - gHUD.GetViewport(theViewport); - - // Does this weapon have a clip? - y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; - - // Does weapon have any ammo at all? - if (m_pWeapon->iAmmoType > 0) - { - int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; - - if (pw->iClip >= 0) - { - // room for the number and the '|' and the current ammo - - x = theViewport[0] + theViewport[2] - (8 * AmmoWidth) - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); - - wrect_t rc; - rc.top = 0; - rc.left = 0; - rc.right = AmmoWidth; - rc.bottom = 100; - - int iBarWidth = AmmoWidth/10; - - x += AmmoWidth/2; - - gHUD.GetPrimaryHudColor(r, g, b); - - // draw the | bar - FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); - - x += iBarWidth + AmmoWidth/2;; - - // GL Seems to need this - ScaleColors(r, g, b, a ); - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - - - } - else - { - // SPR_Draw a bullets only line - x = theViewport[0] + theViewport[2] - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - } - - // Draw the ammo Icon - int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; - SPR_Set(m_pWeapon->hAmmo, r, g, b); - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); - } - - // Does weapon have seconday ammo? - if (pw->iAmmo2Type > 0) - { - int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; - - // Do we have secondary ammo? - if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) - { - y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; - x = theViewport[0] + theViewport[2] - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); - - // Draw the ammo Icon - SPR_Set(m_pWeapon->hAmmo2, r, g, b); - int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); - } - } - return 1; -} - - -// -// Draws the ammo bar on the hud -// -int DrawBar(int x, int y, int width, int height, float f) -{ - int r, g, b; - - if (f < 0) - f = 0; - if (f > 1) - f = 1; - - if (f) - { - int w = f * width; - - // Always show at least one pixel if we have ammo. - if (w <= 0) - w = 1; - UnpackRGB(r, g, b, RGB_GREENISH); - FillRGBA(x, y, w, height, r, g, b, 255); - x += w; - width -= w; - } - - gHUD.GetPrimaryHudColor(r, g, b); - FillRGBA(x, y, width, height, r, g, b, 128); - - return (x + width); -} - - - -void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) -{ - if ( !p ) - return; - - if (p->iAmmoType != -1) - { - if (!gWR.CountAmmo(p->iAmmoType)) - return; - - float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; - - x = DrawBar(x, y, width, height, f); - - - // Do we have secondary ammo too? - - if (p->iAmmo2Type != -1) - { - f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; - - x += 5; //!!! - - DrawBar(x, y, width, height, f); - } - } -} - - - - -// -// Draw Weapon Menu -// -int CHudAmmo::DrawWList(float flTime) -{ - int r,g,b,x,y,a,i; - - if ( !gpActiveSel ) - { - gHUD.SetSelectingWeaponID(-1); - return 0; - } - - int iActiveSlot; - - if ( gpActiveSel == (WEAPON *)1 ) - iActiveSlot = -1; // current slot has no weapons - else - iActiveSlot = gpActiveSel->iSlot; - - x = 10; //!!! - y = 10; //!!! - - - // Ensure that there are available choices in the active slot - if ( iActiveSlot > 0 ) - { - if ( !gWR.GetFirstPos( iActiveSlot ) ) - { - gpActiveSel = (WEAPON *)1; - iActiveSlot = -1; - } - } - - // Draw top line - for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) - { - int iWidth; - - gHUD.GetPrimaryHudColor(r, g, b); - - if ( iActiveSlot == i ) - a = 255; - else - a = 192; - - ScaleColors(r, g, b, 255); - SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); - - // make active slot wide enough to accomodate gun pictures - if ( i == iActiveSlot ) - { - WEAPON *p = gWR.GetFirstPos(iActiveSlot); - if ( p ) - iWidth = p->rcActive.right - p->rcActive.left; - else - iWidth = giBucketWidth; - } - else - iWidth = giBucketWidth; - - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); - - x += iWidth + 5; - } - - - a = 128; //!!! - x = 10; - - // Draw all of the buckets - for (i = 0; i < MAX_WEAPON_SLOTS; i++) - { - y = giBucketHeight + 10; - - // If this is the active slot, draw the bigger pictures, - // otherwise just draw boxes - if ( i == iActiveSlot ) - { - WEAPON *p = gWR.GetFirstPos( i ); - int iWidth = giBucketWidth; - if ( p ) - iWidth = p->rcActive.right - p->rcActive.left; - - for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) - { - p = gWR.GetWeaponSlot( i, iPos ); - - if ( !p || !p->iId ) - continue; - - // Preserve red/yellow depending on whether it has ammo or not - if(!gWR.IsEnabled(p)) - { - UnpackRGB(r,g,b, RGB_REDISH); - ScaleColors(r, g, b, 128); - } - else - { - gHUD.GetPrimaryHudColor(r, g, b); - ScaleColors(r, g, b, 192); - } - - if ( gpActiveSel == p ) - { - SPR_Set(p->hActive, r, g, b ); - SPR_DrawAdditive(0, x, y, &p->rcActive); - - SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); - - // Lookup iID for helptext - gHUD.SetSelectingWeaponID(p->iId, r, g, b); - } - else - { - // Draw Weapon if Red if no ammo - - //if (gWR.IsSelectable(p)) - // ScaleColors(r, g, b, 192); - //else - //{ - // UnpackRGB(r,g,b, RGB_REDISH); - // ScaleColors(r, g, b, 128); - //} - - SPR_Set( p->hInactive, r, g, b ); - SPR_DrawAdditive( 0, x, y, &p->rcInactive ); - } - - // Draw Ammo Bar - - DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); - - y += p->rcActive.bottom - p->rcActive.top + 5; - } - - x += iWidth + 5; - - } - else - { - // Draw Row of weapons. - gHUD.GetPrimaryHudColor(r, g, b); - - for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) - { - WEAPON *p = gWR.GetWeaponSlot( i, iPos ); - - if ( !p || !p->iId ) - continue; - - if ( gWR.IsEnabled(p) ) - { - gHUD.GetPrimaryHudColor(r, g, b); - a = 128; - } - else - { - UnpackRGB(r,g,b, RGB_REDISH); - a = 96; - } - - FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); - - y += giBucketHeight + 5; - } - - x += giBucketWidth + 5; - } - } - - return 1; - -} - - -/* ================================= - GetSpriteList - -Finds and returns the matching -sprite name 'psz' and resolution 'iRes' -in the given sprite list 'pList' -iCount is the number of items in the pList -================================= */ -client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) -{ - if (!pList) - return NULL; - - int i = iCount; - client_sprite_t *p = pList; - - while(i--) - { - if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) - return p; - p++; - } - - return NULL; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Ammo.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" + +#include +#include + +#include "ammohistory.h" +#include "vgui_TeamFortressViewport.h" +#include "mod/AvHClientVariables.h" +#include "mod/AvHSharedUtil.h" +#include "mod/AvHScrollHandler.h" +#include "mod/AvHNetworkMessages.h" + +WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise + // this points to the active weapon menu item +WEAPON *gpLastSel; // Last weapon menu selection + +bool HUD_GetWeaponEnabled(int inID); +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +WeaponsResource gWR; + +int g_weaponselect = 0; + +extern bool gCanMove; + +void IN_AttackDownForced(void); +void IN_AttackUpForced(void); +void IN_Attack2Down(void); +void IN_Attack2Up(void); +void IN_ReloadDown(); +void IN_ReloadUp(); +bool CheckInAttack(void); + +//Equivalent to DECLARE_COMMAND(lastinv,LastInv) except we use gWR instead of gHud +void __CmdFunc_LastInv(void) +{ gWR.UserCmd_LastInv(); } + +// +movement +void __CmdFunc_MovementOn(void) +{ gWR.UserCmd_MovementOn(); } +void __CmdFunc_MovementOff(void) +{ gWR.UserCmd_MovementOff(); } + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WeaponsResource::WeaponsResource(void) : lastWeapon(NULL), iOldWeaponBits(0) {} +WeaponsResource::~WeaponsResource(void) {} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::Init( void ) +{ + memset( rgWeapons, 0, sizeof(WEAPON)*MAX_WEAPONS ); + Reset(); + HOOK_COMMAND("lastinv", LastInv); + // +movement + HOOK_COMMAND("+movement", MovementOn); + HOOK_COMMAND("-movement", MovementOff); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::Reset( void ) +{ + lastWeapon = NULL; + iOldWeaponBits = 0; + memset( rgSlots, 0, sizeof(WEAPON*)*MAX_WEAPON_SLOTS*MAX_WEAPON_POSITIONS ); + memset( riAmmo, 0, sizeof(int)*MAX_AMMO_TYPES ); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource :: LoadAllWeaponSprites( void ) +{ + int customCrosshairs=CVAR_GET_FLOAT(kvCustomCrosshair); + for (int i = 0; i < MAX_WEAPONS; i++) + { + if ( rgWeapons[i].iId ) + LoadWeaponSprites( &rgWeapons[i], customCrosshairs ); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +inline void LoadWeaponSprite( client_sprite_t* ptr, HSPRITE& sprite, wrect_t& bounds ) +{ + if( ptr ) + { + string name( "sprites/" ); + name.append( ptr->szSprite ); + name.append( ".spr" ); + sprite = SPR_Load(name.c_str()); + bounds = ptr->rc; + } + else + { + sprite = NULL; + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon, int custom ) +{ + if ( custom < 0 || custom > 4 ) + custom=1; + + int resolutions[6] = { 320, 640, 800, 1024, 1280, 1600}; + const int numRes=6; + int i=0, j=0, iRes=320; + int screenWidth=ScreenWidth(); + + for ( j=0; j < numRes; j++ ) { + if ( screenWidth == resolutions[j] ) { + iRes=resolutions[j]; + break; + } + if ( j > 0 && screenWidth > resolutions[j-1] && screenWidth < resolutions[j] ) { + iRes=resolutions[j-1]; + break; + } + } + + char sz[128]; + + if ( !pWeapon ) + return; + + memset( &pWeapon->rcCrosshair, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) ); + pWeapon->hCrosshair =0; + pWeapon->hInactive = 0; + pWeapon->hActive = 0; + pWeapon->hAmmo = 0; + pWeapon->hAmmo2 = 0; + + sprintf(sz, "sprites/%s.txt", pWeapon->szName); + client_sprite_t *pList = SPR_GetList(sz, &i); + + if (!pList) + { + ASSERT(pList); + return; + } + + char crosshairName[32]; + sprintf(crosshairName, "crosshair_%d", custom); + for ( j=numRes-1; j>=0; j-- ) { + if ( resolutions[j] <= iRes ) { + if( pWeapon->hCrosshair == NULL ) + LoadWeaponSprite( GetSpriteList( pList, crosshairName, resolutions[j], i ), pWeapon->hCrosshair, pWeapon->rcCrosshair ); + if( pWeapon->hCrosshair == NULL && custom != 0 ) + LoadWeaponSprite( GetSpriteList( pList, "crosshair_0", resolutions[j], i ), pWeapon->hCrosshair, pWeapon->rcCrosshair ); + + + if( pWeapon->hInactive == NULL ) + LoadWeaponSprite( GetSpriteList( pList, "weapon", resolutions[j], i ), pWeapon->hInactive, pWeapon->rcInactive ); + + if( pWeapon->hActive == NULL ) + LoadWeaponSprite( GetSpriteList( pList, "weapon_s", resolutions[j], i ), pWeapon->hActive, pWeapon->rcActive ); + + if( pWeapon->hAmmo == NULL ) + LoadWeaponSprite( GetSpriteList( pList, "ammo", resolutions[j], i ), pWeapon->hAmmo, pWeapon->rcAmmo ); + + if( pWeapon->hAmmo2 == NULL ) + LoadWeaponSprite( GetSpriteList( pList, "ammo2", resolutions[j], i ), pWeapon->hAmmo2, pWeapon->rcAmmo2 ); + } + } + + if( pWeapon->hActive || pWeapon->hInactive || pWeapon->hAmmo || pWeapon->hAmmo2 ) + { gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WEAPON* WeaponsResource::GetWeapon( int iId ) +{ + if( iId < 0 || iId >= MAX_WEAPONS ) { return NULL; } + return rgWeapons[iId].iId ? &rgWeapons[iId] : NULL; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WEAPON* WeaponsResource::GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; } + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WEAPON* WeaponsResource::GetFirstPos( int iSlot ) +{ + WEAPON *returnVal = NULL; + ASSERT( iSlot < MAX_WEAPON_SLOTS && iSlot >= 0 ); + + for( int counter = 0; counter < MAX_WEAPON_POSITIONS; ++counter ) + { + if( this->IsSelectable(rgSlots[iSlot][counter]) ) + { + returnVal = rgSlots[iSlot][counter]; + break; + } + } + + return returnVal; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WEAPON* WeaponsResource::GetNextActivePos( int iSlot, int iSlotPos ) +{ + WEAPON* returnVal = NULL; + ASSERT( iSlot < MAX_WEAPON_SLOTS && iSlot >= 0 ); + ASSERT( iSlotPos >= 0 ); + + for( int counter = iSlotPos+1; counter < MAX_WEAPON_POSITIONS; ++counter ) + { + if( this->IsSelectable(rgSlots[iSlot][counter]) ) + { + returnVal = rgSlots[iSlot][counter]; + break; + } + } + + return returnVal; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +bool WeaponsResource::IsEnabled(WEAPON* p) +{ + if( p == NULL ) { return false; } + return HUD_GetWeaponEnabled(p->iId) && this->HasAmmo(p); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +bool WeaponsResource::IsSelectable(WEAPON* p) +{ + if( p == NULL ) { return false; } + return HUD_GetWeaponEnabled(p->iId); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +bool WeaponsResource::HasAmmo( WEAPON* p ) +{ + if( p == NULL) { return false; } + //note : if max ammo capacity is -1, this has always returned true in spite of not + // having actual ammo -- KGP + return (p->iAmmoType == -1) || (p->iMax1 == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) + || CountAmmo(p->iAmmo2Type) || (p->iFlags & WEAPON_FLAGS_SELECTIONEMPTY ); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +int WeaponsResource::CountAmmo( int iId ) +{ + ASSERT( iId < MAX_AMMO_TYPES ); + if( iId < 0 ) return 0; + return riAmmo[iId]; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +int WeaponsResource::GetAmmo( int iId ) +{ + ASSERT( iId < MAX_AMMO_TYPES && iId > -1 ); + return riAmmo[iId]; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::SetAmmo( int iId, int iCount ) +{ + ASSERT( iId < MAX_AMMO_TYPES && iId > -1 ); + riAmmo[iId] = iCount; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +HSPRITE* WeaponsResource::GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) +{ + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iAmmoType == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo; + return &rgWeapons[i].hAmmo; + } + else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo2; + return &rgWeapons[i].hAmmo2; + } + } + + return NULL; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::AddWeapon( WEAPON *wp ) +{ + int customCrosshairs=CVAR_GET_FLOAT(kvCustomCrosshair); + rgWeapons[ wp->iId ] = *wp; + LoadWeaponSprites( &rgWeapons[ wp->iId ], customCrosshairs); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::PickupWeapon( WEAPON *wp ) +{ + rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::DropWeapon( WEAPON *wp ) +{ + rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL; + if(lastWeapon == wp) //dropped last weapon, remove it from the list + { lastWeapon = NULL; } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::DropAllWeapons( void ) +{ + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iId ) + DropWeapon( &rgWeapons[i] ); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::UserCmd_LastInv(void) +{ + if(this->IsSelectable(this->lastWeapon)) + { + this->SetCurrentWeapon(lastWeapon); + // : 764 + //const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON); + //gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::UserCmd_MovementOn() +{ + // Find out which weapon we want to trigger + AvHUser3 theUser3 = gHUD.GetHUDUser3(); + int wID = -1; + switch(theUser3) + { + case AVH_USER3_ALIEN_PLAYER1: + wID = AVH_ABILITY_LEAP; + break; + case AVH_USER3_ALIEN_PLAYER3: + // TODO: Add flap + break; + case AVH_USER3_ALIEN_PLAYER4: + wID = AVH_WEAPON_BLINK; + break; + case AVH_USER3_ALIEN_PLAYER5: + wID = AVH_ABILITY_CHARGE; + break; + default: + IN_ReloadDown(); + return; + } + + if (wID > -1) + { + // Fetch the needed movement weapon + WEAPON *p = this->GetWeapon(wID); + if (p != NULL && this->IsSelectable(p)) + { + // Send activation of ability asap + IN_Attack2Down(); + } + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::UserCmd_MovementOff() +{ + // Ensure that we're not activating any weapons when selected + IN_Attack2Up(); + IN_ReloadUp(); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::SetValidWeapon(void) +{ + WEAPON* p = this->GetFirstPos(0); //alien attack 1 or primary marine weapon + if(gHUD.GetIsAlien()) + { + this->SetCurrentWeapon(p); + } + else + { + if(this->IsSelectable(p) && this->HasAmmo(p)) + { + this->SetCurrentWeapon(p); + } + else + { + p = this->GetFirstPos(1); //pistol slot + if(this->IsSelectable(p) && this->HasAmmo(p)) + { + this->SetCurrentWeapon(p); + } + else + { + p = this->GetFirstPos(2); //knife slot + this->SetCurrentWeapon(p); + } + } + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource::SetCurrentWeapon(WEAPON* newWeapon) +{ + WEAPON* currentWeapon = this->GetWeapon(gHUD.GetCurrentWeaponID()); + // : 497 - Because weapon state can get out of sync, we should allow this even if the weapons are the same + // && newWeapon != currentWeapon + if( newWeapon != NULL ) + { + if( newWeapon != currentWeapon ) + { lastWeapon = currentWeapon; } + ServerCmd(newWeapon->szName); + g_weaponselect = newWeapon->iId; + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) +{ + if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) + { // menu is overriding slot use commands + gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers + return; + } + + if ( iSlot >= MAX_WEAPON_SLOTS ) + return; + + if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + return; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) //require suit + return; + + if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) //require something besides suit + return; + + WEAPON *p = NULL; + bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; + if ((gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot)) + { + p = GetFirstPos(iSlot); + const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON); + gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + + if (this->IsSelectable(p) && fastSwitch) //check to see if we can use fastSwitch + { + WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); + if (!this->IsSelectable(p2)) //only one target in the bucket + { + this->SetCurrentWeapon(p); + return; + } + } + } + else + { + const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_MOVE_SELECT); + gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + + if ( gpActiveSel ) + p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); + if ( !p ) + p = GetFirstPos( iSlot ); + } + + if (!this->IsSelectable(p)) // no valid selection found + { + // if fastSwitch is on, ignore, else turn on the menu + if ( !fastSwitch ) { + gpActiveSel = (WEAPON *)1; + } + else { + gpActiveSel = NULL; + } + } + else + { + gpActiveSel = p; + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height + +HSPRITE ghsprBuckets; // Sprite for top row of weapons menu + +DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip +DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type +DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count +DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record +DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record +DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily +DECLARE_MESSAGE(m_Ammo, ItemPickup); + +DECLARE_COMMAND(m_Ammo, Slot1); +DECLARE_COMMAND(m_Ammo, Slot2); +DECLARE_COMMAND(m_Ammo, Slot3); +DECLARE_COMMAND(m_Ammo, Slot4); +DECLARE_COMMAND(m_Ammo, Slot5); +DECLARE_COMMAND(m_Ammo, Slot6); +DECLARE_COMMAND(m_Ammo, Slot7); +DECLARE_COMMAND(m_Ammo, Slot8); +DECLARE_COMMAND(m_Ammo, Slot9); +DECLARE_COMMAND(m_Ammo, Slot10); +DECLARE_COMMAND(m_Ammo, Close); +DECLARE_COMMAND(m_Ammo, NextWeapon); +DECLARE_COMMAND(m_Ammo, PrevWeapon); + +// width of ammo fonts +#define AMMO_SMALL_WIDTH 10 +#define AMMO_LARGE_WIDTH 20 + +#define HISTORY_DRAW_TIME "5" + +int CHudAmmo::Init(void) +{ + gHUD.AddHudElem(this); + + HOOK_MESSAGE(CurWeapon); + HOOK_MESSAGE(WeaponList); + HOOK_MESSAGE(AmmoPickup); + HOOK_MESSAGE(WeapPickup); + HOOK_MESSAGE(ItemPickup); + HOOK_MESSAGE(HideWeapon); + HOOK_MESSAGE(AmmoX); + + HOOK_COMMAND("slot1", Slot1); + HOOK_COMMAND("slot2", Slot2); + HOOK_COMMAND("slot3", Slot3); + HOOK_COMMAND("slot4", Slot4); + HOOK_COMMAND("slot5", Slot5); + HOOK_COMMAND("slot6", Slot6); + HOOK_COMMAND("slot7", Slot7); + HOOK_COMMAND("slot8", Slot8); + HOOK_COMMAND("slot9", Slot9); + HOOK_COMMAND("slot10", Slot10); + HOOK_COMMAND("cancelselect", Close); + HOOK_COMMAND("invnext", NextWeapon); + HOOK_COMMAND("invprev", PrevWeapon); + + Reset(); + + CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); + CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress + + m_iFlags |= HUD_ACTIVE; //!!! + + gWR.Init(); + gHR.Init(); + + return 1; +}; + +void CHudAmmo::Reset(void) +{ + m_fFade = 0; + m_iFlags |= HUD_ACTIVE; //!!! + + gpActiveSel = NULL; + gHUD.m_iHideHUDDisplay = 0; + + gWR.Reset(); + gHR.Reset(); + + m_customCrosshair=0; + // VidInit(); + +} + +int CHudAmmo::VidInit(void) +{ + // Load sprites for buckets (top row of weapon menu) + m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); + m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); + + ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); + giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; + giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; + + gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); + + // If we've already loaded weapons, let's get new sprites + gWR.LoadAllWeaponSprites(); + + if (ScreenWidth() >= 640) + { + giABWidth = 20; + giABHeight = 4; + } + else + { + giABWidth = 10; + giABHeight = 2; + } + + return 1; +} + +// +// Think: +// Used for selection of weapon menu item. +// + +void CHudAmmo::Think(void) +{ + if ( gHUD.m_fPlayerDead ) + return; + + if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) + { + gWR.iOldWeaponBits = gHUD.m_iWeaponBits; + bool droppedCurrent = false; + + for (int i = MAX_WEAPONS-1; i > 0; i-- ) + { + WEAPON *p = gWR.GetWeapon(i); + + if ( p ) + { + if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) + gWR.PickupWeapon( p ); + else + gWR.DropWeapon( p ); + } + } + } + if ( (int)CVAR_GET_FLOAT(kvCustomCrosshair) != m_customCrosshair ) { + m_customCrosshair=(int)CVAR_GET_FLOAT(kvCustomCrosshair); + for ( int i=0; i < MAX_WEAPONS; i++ ) { + WEAPON *weapon = gWR.GetWeapon(i); + if ( weapon ) { + gWR.LoadWeaponSprites(weapon, m_customCrosshair); + if ( gHUD.GetHUDPlayMode() != PLAYMODE_READYROOM && gHUD.GetCurrentWeaponID() == weapon->iId ) { + gHUD.SetCurrentCrosshair(weapon->hCrosshair, weapon->rcCrosshair, 255, 255, 255); + } + } + } + + } + + if(gHUD.GetIsAlien()) //check for hive death causing loss of current weapon + { + WEAPON* currentWeapon = gWR.GetWeapon(gHUD.GetCurrentWeaponID()); + if(!gWR.IsSelectable(currentWeapon)) //current weapon isn't valid + { + gWR.SetValidWeapon(); //get best option + } + } + + if (!gpActiveSel) + return; + + // has the player selected one? + if (gHUD.m_iKeyBits & IN_ATTACK) + { + if (gpActiveSel != (WEAPON *)1) + { + gWR.SetCurrentWeapon(gpActiveSel); + } + + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + gHUD.m_iKeyBits &= ~IN_ATTACK; + + const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_SELECT); + gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + } +} + + +//------------------------------------------------------------------------ +// Message Handlers +//------------------------------------------------------------------------ + +// +// AmmoX -- Update the count of a known type of ammo +// +int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) +{ + int iIndex, iCount; + NetMsg_AmmoX( pbuf, iSize, iIndex, iCount ); + gWR.SetAmmo( iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) +{ + int iIndex, iCount; + NetMsg_AmmoPickup( pbuf, iSize, iIndex, iCount ); + + // Add ammo to the history + gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) +{ + int iIndex; + NetMsg_WeapPickup( pbuf, iSize, iIndex ); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); + + return 1; +} + +int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) +{ + string szName; + NetMsg_ItemPickup( pbuf, iSize, szName ); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_ITEM, szName.c_str() ); + + return 1; +} + + +int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) +{ + NetMsg_HideWeapon( pbuf, iSize, gHUD.m_iHideHUDDisplay ); + + if (gEngfuncs.IsSpectateOnly()) + return 1; + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + { + static wrect_t nullrc; + gpActiveSel = NULL; + gHUD.SetCurrentCrosshair( 0, nullrc, 0, 0, 0 ); + } + else + { + if ( m_pWeapon ) + gHUD.SetCurrentCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); + } + + return 1; +} + +// +// CurWeapon: Update hud state with the current weapon and clip count. Ammo +// counts are updated with AmmoX. Server assures that the Weapon ammo type +// numbers match a real ammo type. +// +int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) +{ + static wrect_t nullrc; + + int iState, iId, iClip; + NetMsg_CurWeapon( pbuf, iSize, iState, iId, iClip ); + + if ( iId < 1 ) //signal kills crosshairs if this condition is met... + { + gHUD.SetCurrentCrosshair(0, nullrc, 0, 0, 0); + return 0; + } + + if ( g_iUser1 != OBS_IN_EYE ) + { + if ( iId == -1 && iClip == -1 ) //this conditional is never true due to iId < 1 check above! + { + gHUD.m_fPlayerDead = TRUE; + gpActiveSel = NULL; + return 1; + } + + gHUD.m_fPlayerDead = FALSE; + } + + WEAPON *pWeapon = gWR.GetWeapon( iId ); + if( pWeapon == NULL ) //don't have the weapon described in our resource list + { return 0; } + + bool bOnTarget = (iState & WEAPON_ON_TARGET) != 0; //used to track autoaim state + bool bIsCurrent = (iState & WEAPON_IS_CURRENT) != 0; + pWeapon->iEnabled = (iState & WEAPON_IS_ENABLED) != 0 ? TRUE : FALSE; + pWeapon->iClip = abs(iClip); + + // Ensure that movement is enabled/disabled according to weapons + if (iId == 22 || iId == 11 || iId == 21) + { + gCanMove = pWeapon->iEnabled; + } + + if( !bIsCurrent ) + { return 1; } + + m_pWeapon = pWeapon; + + if ( !(gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + { + gHUD.SetCurrentCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); + +/* if ( gHUD.m_iFOV >= 90 ) + { // normal crosshairs + if (bOnTarget && m_pWeapon->hAutoaim) + gHUD.SetCurrentCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); + else + gHUD.SetCurrentCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); + } + else + { // zoomed crosshairs + if (bOnTarget && m_pWeapon->hZoomedAutoaim) + gHUD.SetCurrentCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); + else + gHUD.SetCurrentCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); + }*/ + } + + m_fFade = 200.0f; //!!! + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +// +// WeaponList -- Tells the hud about a new weapon type. +// +int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) +{ + WeaponList weapon_data; + NetMsg_WeaponList( pbuf, iSize, weapon_data ); + + WEAPON Weapon; + memset( &Weapon, 0, sizeof(WEAPON) ); + + strcpy( Weapon.szName, weapon_data.weapon_name.c_str() ); + Weapon.iAmmoType = weapon_data.ammo1_type; + Weapon.iMax1 = weapon_data.ammo1_max_amnt == 255 ? -1 : weapon_data.ammo1_max_amnt; + Weapon.iAmmo2Type = weapon_data.ammo2_type; + Weapon.iMax2 = weapon_data.ammo2_max_amnt == 255 ? -1 : weapon_data.ammo2_max_amnt; + Weapon.iSlot = weapon_data.bucket; + Weapon.iSlotPos = weapon_data.bucket_pos; + Weapon.iId = weapon_data.bit_index; + Weapon.iFlags = weapon_data.flags; + Weapon.iClip = 0; + // : 497 - default value for enable state + Weapon.iEnabled = 0; + + gWR.AddWeapon( &Weapon ); + return 1; +} + +//------------------------------------------------------------------------ +// Command Handlers +//------------------------------------------------------------------------ +// Slot button pressed +void CHudAmmo::SlotInput( int iSlot ) +{ + // Let the Viewport use it first, for menus + if ( gViewPort && gViewPort->SlotInput( iSlot ) ) + return; + + gWR.SelectSlot( iSlot, FALSE, 1 ); +} + +void CHudAmmo::UserCmd_Slot1(void) +{ + SlotInput( 0 ); +} + +void CHudAmmo::UserCmd_Slot2(void) +{ + SlotInput( 1 ); +} + +void CHudAmmo::UserCmd_Slot3(void) +{ + SlotInput( 2 ); +} + +void CHudAmmo::UserCmd_Slot4(void) +{ + SlotInput( 3 ); +} + +void CHudAmmo::UserCmd_Slot5(void) +{ + SlotInput( 4 ); +} + +void CHudAmmo::UserCmd_Slot6(void) +{ + SlotInput( 5 ); +} + +void CHudAmmo::UserCmd_Slot7(void) +{ + SlotInput( 6 ); +} + +void CHudAmmo::UserCmd_Slot8(void) +{ + SlotInput( 7 ); +} + +void CHudAmmo::UserCmd_Slot9(void) +{ + SlotInput( 8 ); +} + +void CHudAmmo::UserCmd_Slot10(void) +{ + SlotInput( 9 ); +} + +void CHudAmmo::UserCmd_Close(void) +{ + if (gpActiveSel) + { + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + + const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_OFF); + gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + } +} + + +// Selects the next item in the weapon menu +void CHudAmmo::UserCmd_NextWeapon(void) +{ + if(gHUD.GetInTopDownMode()) + { + AvHScrollHandler::ScrollHeightUp(); + } + + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = 0; + int slot = 0; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos + 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) + { + for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if (gWR.IsSelectable(wsp)) + { + gpActiveSel = wsp; + return; + } + } + + pos = 0; + } + + slot = 0; // start looking from the first slot again + } + + gpActiveSel = NULL; +} + +// Selects the previous item in the menu +void CHudAmmo::UserCmd_PrevWeapon(void) +{ + if(gHUD.GetInTopDownMode()) + { + AvHScrollHandler::ScrollHeightDown(); + } + + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = MAX_WEAPON_POSITIONS-1; + int slot = MAX_WEAPON_SLOTS-1; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos - 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot >= 0; slot-- ) + { + for ( ; pos >= 0; pos-- ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if (gWR.IsSelectable(wsp)) + { + gpActiveSel = wsp; + return; + } + } + + pos = MAX_WEAPON_POSITIONS-1; + } + + slot = MAX_WEAPON_SLOTS-1; + } + + gpActiveSel = NULL; +} + +void CHudAmmo::SetCurrentClip(int inClip) +{ + if(this->m_pWeapon) + { + this->m_pWeapon->iClip = inClip; + } +} + +//------------------------------------------------------------------------- +// Drawing code +//------------------------------------------------------------------------- + +int CHudAmmo::Draw(float flTime) +{ + int a, x, y, r, g, b; + int AmmoWidth; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if (/*!gHUD.GetIsAlive() ||*/ (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // Draw Weapon Menu + DrawWList(flTime); + + // Draw ammo pickup history + gHR.DrawAmmoHistory( flTime ); + + if (!(m_iFlags & HUD_ACTIVE)) + return 0; + + if (!m_pWeapon) + return 0; + + WEAPON *pw = m_pWeapon; // shorthand + + // SPR_Draw Ammo + if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) + return 0; + + + int iFlags = DHN_DRAWZERO; // draw 0 values + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + a = (int) max( MIN_ALPHA, m_fFade ); + + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); + + gHUD.GetPrimaryHudColor(r, g, b); + + ScaleColors(r, g, b, a ); + + int theViewport[4]; + gHUD.GetViewport(theViewport); + + // Does this weapon have a clip? + y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; + + // Does weapon have any ammo at all? + if (m_pWeapon->iAmmoType > 0) + { + int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; + + if (pw->iClip >= 0) + { + // room for the number and the '|' and the current ammo + + x = theViewport[0] + theViewport[2] - (8 * AmmoWidth) - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); + + wrect_t rc; + rc.top = 0; + rc.left = 0; + rc.right = AmmoWidth; + rc.bottom = 100; + + int iBarWidth = AmmoWidth/10; + + x += AmmoWidth/2; + + gHUD.GetPrimaryHudColor(r, g, b); + + // draw the | bar + FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); + + x += iBarWidth + AmmoWidth/2;; + + // GL Seems to need this + ScaleColors(r, g, b, a ); + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + + + } + else + { + // SPR_Draw a bullets only line + x = theViewport[0] + theViewport[2] - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + } + + // Draw the ammo Icon + int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; + SPR_Set(m_pWeapon->hAmmo, r, g, b); + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); + } + + // Does weapon have seconday ammo? + if (pw->iAmmo2Type > 0) + { + int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; + + // Do we have secondary ammo? + if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) + { + y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; + x = theViewport[0] + theViewport[2] - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); + + // Draw the ammo Icon + SPR_Set(m_pWeapon->hAmmo2, r, g, b); + int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); + } + } + return 1; +} + + +// +// Draws the ammo bar on the hud +// +int DrawBar(int x, int y, int width, int height, float f) +{ + int r, g, b; + + if (f < 0) + f = 0; + if (f > 1) + f = 1; + + if (f) + { + int w = f * width; + + // Always show at least one pixel if we have ammo. + if (w <= 0) + w = 1; + UnpackRGB(r, g, b, RGB_GREENISH); + FillRGBA(x, y, w, height, r, g, b, 255); + x += w; + width -= w; + } + + gHUD.GetPrimaryHudColor(r, g, b); + FillRGBA(x, y, width, height, r, g, b, 128); + + return (x + width); +} + + + +void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) +{ + if ( !p ) + return; + + if (p->iAmmoType != -1) + { + if (!gWR.CountAmmo(p->iAmmoType)) + return; + + float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; + + x = DrawBar(x, y, width, height, f); + + + // Do we have secondary ammo too? + + if (p->iAmmo2Type != -1) + { + f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; + + x += 5; //!!! + + DrawBar(x, y, width, height, f); + } + } +} + + + + +// +// Draw Weapon Menu +// +int CHudAmmo::DrawWList(float flTime) +{ + int r,g,b,x,y,a,i; + + if ( !gpActiveSel ) + { + gHUD.SetSelectingWeaponID(-1); + return 0; + } + + int iActiveSlot; + + if ( gpActiveSel == (WEAPON *)1 ) + iActiveSlot = -1; // current slot has no weapons + else + iActiveSlot = gpActiveSel->iSlot; + + x = 10; //!!! + y = 10; //!!! + + + // Ensure that there are available choices in the active slot + if ( iActiveSlot > 0 ) + { + if ( !gWR.GetFirstPos( iActiveSlot ) ) + { + gpActiveSel = (WEAPON *)1; + iActiveSlot = -1; + } + } + + // Draw top line + for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) + { + int iWidth; + + gHUD.GetPrimaryHudColor(r, g, b); + + if ( iActiveSlot == i ) + a = 255; + else + a = 192; + + ScaleColors(r, g, b, 255); + SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); + + // make active slot wide enough to accomodate gun pictures + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos(iActiveSlot); + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + else + iWidth = giBucketWidth; + } + else + iWidth = giBucketWidth; + + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); + + x += iWidth + 5; + } + + + a = 128; //!!! + x = 10; + + // Draw all of the buckets + for (i = 0; i < MAX_WEAPON_SLOTS; i++) + { + y = giBucketHeight + 10; + + // If this is the active slot, draw the bigger pictures, + // otherwise just draw boxes + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos( i ); + int iWidth = giBucketWidth; + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + // Preserve red/yellow depending on whether it has ammo or not + if(!gWR.IsEnabled(p)) + { + UnpackRGB(r,g,b, RGB_REDISH); + ScaleColors(r, g, b, 128); + } + else + { + gHUD.GetPrimaryHudColor(r, g, b); + ScaleColors(r, g, b, 192); + } + + if ( gpActiveSel == p ) + { + SPR_Set(p->hActive, r, g, b ); + SPR_DrawAdditive(0, x, y, &p->rcActive); + + SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); + + // Lookup iID for helptext + gHUD.SetSelectingWeaponID(p->iId, r, g, b); + } + else + { + // Draw Weapon if Red if no ammo + + //if (gWR.IsSelectable(p)) + // ScaleColors(r, g, b, 192); + //else + //{ + // UnpackRGB(r,g,b, RGB_REDISH); + // ScaleColors(r, g, b, 128); + //} + + SPR_Set( p->hInactive, r, g, b ); + SPR_DrawAdditive( 0, x, y, &p->rcInactive ); + } + + // Draw Ammo Bar + + DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); + + y += p->rcActive.bottom - p->rcActive.top + 5; + } + + x += iWidth + 5; + + } + else + { + // Draw Row of weapons. + gHUD.GetPrimaryHudColor(r, g, b); + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + WEAPON *p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + if ( gWR.IsEnabled(p) ) + { + gHUD.GetPrimaryHudColor(r, g, b); + a = 128; + } + else + { + UnpackRGB(r,g,b, RGB_REDISH); + a = 96; + } + + FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); + + y += giBucketHeight + 5; + } + + x += giBucketWidth + 5; + } + } + + return 1; + +} + + +/* ================================= + GetSpriteList + +Finds and returns the matching +sprite name 'psz' and resolution 'iRes' +in the given sprite list 'pList' +iCount is the number of items in the pList +================================= */ +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) +{ + if (!pList) + return NULL; + + int i = iCount; + client_sprite_t *p = pList; + + while(i--) + { + if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) + return p; + p++; + } + + return NULL; +} diff --git a/main/source/cl_dll/ammo.h b/main/source/cl_dll/ammo.h index 107c34ce..b5c3f221 100644 --- a/main/source/cl_dll/ammo.h +++ b/main/source/cl_dll/ammo.h @@ -1,64 +1,64 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef __AMMO_H__ -#define __AMMO_H__ - -#define MAX_WEAPON_NAME 128 - - -#define WEAPON_FLAGS_SELECTIONEMPTY 1 - -struct WEAPON -{ - char szName[MAX_WEAPON_NAME]; - int iAmmoType; - int iAmmo2Type; - int iMax1; - int iMax2; - int iSlot; - int iSlotPos; - int iFlags; - int iId; - int iClip; - // : 497 - weapon enable state - int iEnabled; - - int iCount; // # of itesm in plist - - HSPRITE hActive; - wrect_t rcActive; - HSPRITE hInactive; - wrect_t rcInactive; - HSPRITE hAmmo; - wrect_t rcAmmo; - HSPRITE hAmmo2; - wrect_t rcAmmo2; - HSPRITE hCrosshair; - wrect_t rcCrosshair; - -/* HSPRITE hAutoaim; - wrect_t rcAutoaim; - HSPRITE hZoomedCrosshair; - wrect_t rcZoomedCrosshair; - HSPRITE hZoomedAutoaim; - wrect_t rcZoomedAutoaim; - */ -}; - -typedef int AMMO; - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef __AMMO_H__ +#define __AMMO_H__ + +#define MAX_WEAPON_NAME 128 + + +#define WEAPON_FLAGS_SELECTIONEMPTY 1 + +struct WEAPON +{ + char szName[MAX_WEAPON_NAME]; + int iAmmoType; + int iAmmo2Type; + int iMax1; + int iMax2; + int iSlot; + int iSlotPos; + int iFlags; + int iId; + int iClip; + // : 497 - weapon enable state + int iEnabled; + + int iCount; // # of itesm in plist + + HSPRITE hActive; + wrect_t rcActive; + HSPRITE hInactive; + wrect_t rcInactive; + HSPRITE hAmmo; + wrect_t rcAmmo; + HSPRITE hAmmo2; + wrect_t rcAmmo2; + HSPRITE hCrosshair; + wrect_t rcCrosshair; + +/* HSPRITE hAutoaim; + wrect_t rcAutoaim; + HSPRITE hZoomedCrosshair; + wrect_t rcZoomedCrosshair; + HSPRITE hZoomedAutoaim; + wrect_t rcZoomedAutoaim; + */ +}; + +typedef int AMMO; + + #endif \ No newline at end of file diff --git a/main/source/cl_dll/ammo_secondary.cpp b/main/source/cl_dll/ammo_secondary.cpp index 56c84c14..ac554fa2 100644 --- a/main/source/cl_dll/ammo_secondary.cpp +++ b/main/source/cl_dll/ammo_secondary.cpp @@ -1,104 +1,104 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// ammo_secondary.cpp -// -// implementation of CHudAmmoSecondary class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include - -int CHudAmmoSecondary :: Init( void ) -{ - gHUD.AddHudElem(this); - m_HUD_ammoicon = 0; - - for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) - m_iAmmoAmounts[i] = -1; // -1 means don't draw this value - - Reset(); - - return 1; -} - -void CHudAmmoSecondary :: Reset( void ) -{ - m_fFade = 0; -} - -int CHudAmmoSecondary :: VidInit( void ) -{ - return 1; -} - -int CHudAmmoSecondary :: Draw(float flTime) -{ - if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) - return 1; - - // draw secondary ammo icons above normal ammo readout - int a, x, y, r, g, b, AmmoWidth; - gHUD.GetPrimaryHudColor(r, g, b); - a = (int) max( MIN_ALPHA, m_fFade ); - if (m_fFade > 0) - m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons - ScaleColors( r, g, b, a ); - - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - - y = ScreenHeight() - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values - x = ScreenWidth() - AmmoWidth; - - if ( m_HUD_ammoicon ) - { - // Draw the ammo icon - x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); - y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); - - SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); - } - else - { // move the cursor by the '0' char instead, since we don't have an icon to work with - x -= AmmoWidth; - y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); - } - - // draw the ammo counts, in reverse order, from right to left - for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) - { - if ( m_iAmmoAmounts[i] < 0 ) - continue; // negative ammo amounts imply that they shouldn't be drawn - - // half a char gap between the ammo number and the previous pic - x -= (AmmoWidth / 2); - - // draw the number, right-aligned - x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); - gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); - - if ( i != 0 ) - { - // draw the divider bar - x -= (AmmoWidth / 2); - FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); - } - } - - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// ammo_secondary.cpp +// +// implementation of CHudAmmoSecondary class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include + +int CHudAmmoSecondary :: Init( void ) +{ + gHUD.AddHudElem(this); + m_HUD_ammoicon = 0; + + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + m_iAmmoAmounts[i] = -1; // -1 means don't draw this value + + Reset(); + + return 1; +} + +void CHudAmmoSecondary :: Reset( void ) +{ + m_fFade = 0; +} + +int CHudAmmoSecondary :: VidInit( void ) +{ + return 1; +} + +int CHudAmmoSecondary :: Draw(float flTime) +{ + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // draw secondary ammo icons above normal ammo readout + int a, x, y, r, g, b, AmmoWidth; + gHUD.GetPrimaryHudColor(r, g, b); + a = (int) max( MIN_ALPHA, m_fFade ); + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons + ScaleColors( r, g, b, a ); + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + y = ScreenHeight() - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values + x = ScreenWidth() - AmmoWidth; + + if ( m_HUD_ammoicon ) + { + // Draw the ammo icon + x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); + y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); + + SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); + } + else + { // move the cursor by the '0' char instead, since we don't have an icon to work with + x -= AmmoWidth; + y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); + } + + // draw the ammo counts, in reverse order, from right to left + for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) + { + if ( m_iAmmoAmounts[i] < 0 ) + continue; // negative ammo amounts imply that they shouldn't be drawn + + // half a char gap between the ammo number and the previous pic + x -= (AmmoWidth / 2); + + // draw the number, right-aligned + x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); + gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); + + if ( i != 0 ) + { + // draw the divider bar + x -= (AmmoWidth / 2); + FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); + } + } + + return 1; +} diff --git a/main/source/cl_dll/ammohistory.cpp b/main/source/cl_dll/ammohistory.cpp index 6382d7d6..541f0e04 100644 --- a/main/source/cl_dll/ammohistory.cpp +++ b/main/source/cl_dll/ammohistory.cpp @@ -1,173 +1,173 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// ammohistory.cpp -// - - -#include "hud.h" -#include "cl_util.h" - -#include -#include - -#include "ammohistory.h" - -HistoryResource gHR; - -#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) -#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) -#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight() - 100) - -#define MAX_ITEM_NAME 32 -int HISTORY_DRAW_TIME = 5; - -// keep a list of items -struct ITEM_INFO -{ - char szName[MAX_ITEM_NAME]; - HSPRITE spr; - wrect_t rect; -}; - -void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) -{ - if ( iType == HISTSLOT_AMMO && !iCount ) - return; // no amount, so don't add - - if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) - { // the pic would have to be drawn too high - // so start from the bottom - iCurrentHistorySlot = 0; - } - - HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot - HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); - - freeslot->type = iType; - freeslot->iId = iId; - freeslot->iCount = iCount; - freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; -} - -void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount ) -{ - if ( iType != HISTSLOT_ITEM ) - return; - - int i = gHUD.GetSpriteIndex( szName ); - if ( i == -1 ) - return; // unknown sprite name, don't add it to history - - return this->AddToHistory( iType, i, iCount ); -} - -void HistoryResource :: CheckClearHistory( void ) -{ - for ( int i = 0; i < MAX_HISTORY; i++ ) - { - if ( rgAmmoHistory[i].type ) - return; - } - - iCurrentHistorySlot = 0; -} - -// -// Draw Ammo pickup history -// -int HistoryResource :: DrawAmmoHistory( float flTime ) -{ - for ( int i = 0; i < MAX_HISTORY; i++ ) - { - if ( rgAmmoHistory[i].type ) - { - rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); - - if ( rgAmmoHistory[i].DisplayTime <= flTime ) - { // pic drawing time has expired - memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); - CheckClearHistory(); - } - else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO ) - { - wrect_t rcPic; - HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); - - int r, g, b; - gHUD.GetPrimaryHudColor(r, g, b); - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); - - // Draw the pic - int ypos = ScreenHeight() - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth() - 24; - if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic - { // the dll has to make sure it has sent info the weapons you need - SPR_Set( *spr, r, g, b ); - SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); - } - - // Draw the number - gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); - } - else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) - { - WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId ); - - if ( !weap ) - return 1; // we don't know about the weapon yet, so don't draw anything - - int r, g, b; - gHUD.GetPrimaryHudColor(r, g, b); - - if ( !gWR.HasAmmo( weap ) ) - UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red - - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); - - int ypos = ScreenHeight() - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth() - (weap->rcInactive.right - weap->rcInactive.left); - SPR_Set( weap->hInactive, r, g, b ); - SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive ); - } - else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM ) - { - int r, g, b; - - if ( !rgAmmoHistory[i].iId ) - continue; // sprite not loaded - - wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); - - gHUD.GetPrimaryHudColor(r, g, b); - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); - - int ypos = ScreenHeight() - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth() - (rect.right - rect.left) - 10; - - SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b ); - SPR_DrawAdditive( 0, xpos, ypos, &rect ); - } - } - } - - - return 1; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// ammohistory.cpp +// + + +#include "hud.h" +#include "cl_util.h" + +#include +#include + +#include "ammohistory.h" + +HistoryResource gHR; + +#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) +#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) +#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight() - 100) + +#define MAX_ITEM_NAME 32 +int HISTORY_DRAW_TIME = 5; + +// keep a list of items +struct ITEM_INFO +{ + char szName[MAX_ITEM_NAME]; + HSPRITE spr; + wrect_t rect; +}; + +void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) +{ + if ( iType == HISTSLOT_AMMO && !iCount ) + return; // no amount, so don't add + + if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) + { // the pic would have to be drawn too high + // so start from the bottom + iCurrentHistorySlot = 0; + } + + HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot + HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); + + freeslot->type = iType; + freeslot->iId = iId; + freeslot->iCount = iCount; + freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; +} + +void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount ) +{ + if ( iType != HISTSLOT_ITEM ) + return; + + int i = gHUD.GetSpriteIndex( szName ); + if ( i == -1 ) + return; // unknown sprite name, don't add it to history + + return this->AddToHistory( iType, i, iCount ); +} + +void HistoryResource :: CheckClearHistory( void ) +{ + for ( int i = 0; i < MAX_HISTORY; i++ ) + { + if ( rgAmmoHistory[i].type ) + return; + } + + iCurrentHistorySlot = 0; +} + +// +// Draw Ammo pickup history +// +int HistoryResource :: DrawAmmoHistory( float flTime ) +{ + for ( int i = 0; i < MAX_HISTORY; i++ ) + { + if ( rgAmmoHistory[i].type ) + { + rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); + + if ( rgAmmoHistory[i].DisplayTime <= flTime ) + { // pic drawing time has expired + memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); + CheckClearHistory(); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO ) + { + wrect_t rcPic; + HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); + + int r, g, b; + gHUD.GetPrimaryHudColor(r, g, b); + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + // Draw the pic + int ypos = ScreenHeight() - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth() - 24; + if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic + { // the dll has to make sure it has sent info the weapons you need + SPR_Set( *spr, r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); + } + + // Draw the number + gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) + { + WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId ); + + if ( !weap ) + return 1; // we don't know about the weapon yet, so don't draw anything + + int r, g, b; + gHUD.GetPrimaryHudColor(r, g, b); + + if ( !gWR.HasAmmo( weap ) ) + UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red + + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + int ypos = ScreenHeight() - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth() - (weap->rcInactive.right - weap->rcInactive.left); + SPR_Set( weap->hInactive, r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive ); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM ) + { + int r, g, b; + + if ( !rgAmmoHistory[i].iId ) + continue; // sprite not loaded + + wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); + + gHUD.GetPrimaryHudColor(r, g, b); + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + int ypos = ScreenHeight() - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth() - (rect.right - rect.left) - 10; + + SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &rect ); + } + } + } + + + return 1; +} + + diff --git a/main/source/cl_dll/ammohistory.h b/main/source/cl_dll/ammohistory.h index fb42951c..661706db 100644 --- a/main/source/cl_dll/ammohistory.h +++ b/main/source/cl_dll/ammohistory.h @@ -1,129 +1,129 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -* Modified by Charles G. Cleveland -* -* $Workfile: ammohistory.h $ -* $Date: 2002/06/25 17:05:31 $ -* -*------------------------------------------------------------------------------- -* $Log: ammohistory.h,v $ -* Revision 1.3 2002/06/25 17:05:31 Flayra -* - Weapon enabling/disabling works differently now -* -*=============================================================================== -****/ -// -// ammohistory.h -// - -// this is the max number of items in each bucket -#define MAX_WEAPON_POSITIONS 10 - -class WeaponsResource -{ -public: - WeaponsResource( void ); - ~WeaponsResource( void ); - void Init( void ); - void Reset( void ); - - void LoadWeaponSprites( WEAPON* wp, int custom ); - void LoadAllWeaponSprites( void ); - - WEAPON* GetWeapon( int iId ); - WEAPON* GetWeaponSlot( int slot, int pos ); - WEAPON* GetFirstPos( int iSlot ); - WEAPON* GetNextActivePos( int iSlot, int iSlotPos ); - - bool IsEnabled( WEAPON *p ); - bool IsSelectable( WEAPON *p ); - - bool HasAmmo( WEAPON *p ); - int CountAmmo( int iId ); - int GetAmmo( int iId ); - void SetAmmo( int iId, int iCount ); - HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); //TODO: fix bass-ackwards arrangement and store sprites with ammo types - - void AddWeapon( WEAPON* wp ); - void PickupWeapon( WEAPON* wp ); - void DropWeapon( WEAPON* wp ); - void DropAllWeapons( void ); - - //CONSIDER: Should the selection functions be in the menu with the selection variables? - void UserCmd_LastInv( void ); - void UserCmd_MovementOn( void ); - void UserCmd_MovementOff( void ); - void SetValidWeapon( void ); - void SetCurrentWeapon( WEAPON* wp ); - void SelectSlot( int iSlot, int fAdvance, int iDirection ); - - friend CHudAmmo; //for iOldWeaponBits access -private: - WEAPON rgWeapons[MAX_WEAPONS]; // current weapon state - WEAPON* rgSlots[MAX_WEAPON_SLOTS][MAX_WEAPON_POSITIONS]; // current weapon slot map - WEAPON* lastWeapon; // client-side lastinv - - int riAmmo[MAX_AMMO_TYPES]; // current ammo counts - int iOldWeaponBits; -}; - -extern WeaponsResource gWR; - - -#define MAX_HISTORY 12 -enum { - HISTSLOT_EMPTY, - HISTSLOT_AMMO, - HISTSLOT_WEAP, - HISTSLOT_ITEM, -}; - -class HistoryResource -{ -private: - struct HIST_ITEM { - int type; - float DisplayTime; // the time at which this item should be removed from the history - int iCount; - int iId; - }; - - HIST_ITEM rgAmmoHistory[MAX_HISTORY]; - -public: - - void Init( void ) - { - Reset(); - } - - void Reset( void ) - { - memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); - } - - int iHistoryGap; - int iCurrentHistorySlot; - - void AddToHistory( int iType, int iId, int iCount = 0 ); - void AddToHistory( int iType, const char *szName, int iCount = 0 ); - - void CheckClearHistory( void ); - int DrawAmmoHistory( float flTime ); -}; - -extern HistoryResource gHR; - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +* Modified by Charles G. Cleveland +* +* $Workfile: ammohistory.h $ +* $Date: 2002/06/25 17:05:31 $ +* +*------------------------------------------------------------------------------- +* $Log: ammohistory.h,v $ +* Revision 1.3 2002/06/25 17:05:31 Flayra +* - Weapon enabling/disabling works differently now +* +*=============================================================================== +****/ +// +// ammohistory.h +// + +// this is the max number of items in each bucket +#define MAX_WEAPON_POSITIONS 10 + +class WeaponsResource +{ +public: + WeaponsResource( void ); + ~WeaponsResource( void ); + void Init( void ); + void Reset( void ); + + void LoadWeaponSprites( WEAPON* wp, int custom ); + void LoadAllWeaponSprites( void ); + + WEAPON* GetWeapon( int iId ); + WEAPON* GetWeaponSlot( int slot, int pos ); + WEAPON* GetFirstPos( int iSlot ); + WEAPON* GetNextActivePos( int iSlot, int iSlotPos ); + + bool IsEnabled( WEAPON *p ); + bool IsSelectable( WEAPON *p ); + + bool HasAmmo( WEAPON *p ); + int CountAmmo( int iId ); + int GetAmmo( int iId ); + void SetAmmo( int iId, int iCount ); + HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); //TODO: fix bass-ackwards arrangement and store sprites with ammo types + + void AddWeapon( WEAPON* wp ); + void PickupWeapon( WEAPON* wp ); + void DropWeapon( WEAPON* wp ); + void DropAllWeapons( void ); + + //CONSIDER: Should the selection functions be in the menu with the selection variables? + void UserCmd_LastInv( void ); + void UserCmd_MovementOn( void ); + void UserCmd_MovementOff( void ); + void SetValidWeapon( void ); + void SetCurrentWeapon( WEAPON* wp ); + void SelectSlot( int iSlot, int fAdvance, int iDirection ); + + friend CHudAmmo; //for iOldWeaponBits access +private: + WEAPON rgWeapons[MAX_WEAPONS]; // current weapon state + WEAPON* rgSlots[MAX_WEAPON_SLOTS][MAX_WEAPON_POSITIONS]; // current weapon slot map + WEAPON* lastWeapon; // client-side lastinv + + int riAmmo[MAX_AMMO_TYPES]; // current ammo counts + int iOldWeaponBits; +}; + +extern WeaponsResource gWR; + + +#define MAX_HISTORY 12 +enum { + HISTSLOT_EMPTY, + HISTSLOT_AMMO, + HISTSLOT_WEAP, + HISTSLOT_ITEM, +}; + +class HistoryResource +{ +private: + struct HIST_ITEM { + int type; + float DisplayTime; // the time at which this item should be removed from the history + int iCount; + int iId; + }; + + HIST_ITEM rgAmmoHistory[MAX_HISTORY]; + +public: + + void Init( void ) + { + Reset(); + } + + void Reset( void ) + { + memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); + } + + int iHistoryGap; + int iCurrentHistorySlot; + + void AddToHistory( int iType, int iId, int iCount = 0 ); + void AddToHistory( int iType, const char *szName, int iCount = 0 ); + + void CheckClearHistory( void ); + int DrawAmmoHistory( float flTime ); +}; + +extern HistoryResource gHR; + + + diff --git a/main/source/cl_dll/battery.cpp b/main/source/cl_dll/battery.cpp index 6d0ac04c..990c829c 100644 --- a/main/source/cl_dll/battery.cpp +++ b/main/source/cl_dll/battery.cpp @@ -1,156 +1,156 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// battery.cpp -// -// implementation of CHudBattery class -// - -#include "hud.h" -#include "cl_util.h" - -#include -#include -#include "AvHPlayerUpgrade.h" -#include "AvHHudConstants.h" -#include "AvHNetworkMessages.h" - -DECLARE_MESSAGE(m_Battery, Battery) - -int CHudBattery::Init(void) -{ - m_iBat = 0; - m_fFade = 0; - m_iFlags = 0; - - HOOK_MESSAGE(Battery); - - gHUD.AddHudElem(this); - - return 1; -}; - - -int CHudBattery::VidInit(void) -{ - int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); - int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); - - m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded - m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty ); - m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full ); - m_iHeight = m_prc2->bottom - m_prc1->top; - m_fFade = 0; - return 1; -}; - -int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) -{ - m_iFlags |= HUD_ACTIVE; - - - int x; - NetMsg_Battery( pbuf, iSize, x ); - - if (x != m_iBat) - { - // We're sent the health of the player we're observing as if it were our own - m_fFade = FADE_TIME; - m_iBat = x; - } - - return 1; -} - - -int CHudBattery::Draw(float flTime) -{ - - if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) - return 1; - - int r, g, b, x, y, a; - wrect_t rc; - - rc = *m_prc2; - - int theMaxArmor = gHUD.GetHUDMaxArmor(); - float theScalar = 1.0f/theMaxArmor; - - rc.top += m_iHeight * ((float)(theMaxArmor-(min(theMaxArmor, m_iBat))) * theScalar); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 - - gHUD.GetPrimaryHudColor(r, g, b); - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return 1; - - // Has health changed? Flash the health # - if (m_fFade) - { - if (m_fFade > FADE_TIME) - m_fFade = FADE_TIME; - - m_fFade -= (gHUD.m_flTimeDelta * 20); - if (m_fFade <= 0) - { - a = 128; - m_fFade = 0; - } - - // Fade the health number back to dim - - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - - } - else - a = MIN_ALPHA; - - ScaleColors(r, g, b, a ); - - int iOffset = (m_prc1->bottom - m_prc1->top)/6; - - int theInset = 0; - if(gHUD.GetIsAlien()) - { - theInset = ScreenWidth()*kResourceEnergyBarWidth; - } - - int theViewport[4]; - gHUD.GetViewport(theViewport); - - y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = theViewport[0] + theInset + kArmorLeftInset*ScreenWidth(); - - // make sure we have the right sprite handles - if ( !m_hSprite1 ) - m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); - if ( !m_hSprite2 ) - m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); - - SPR_Set(m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); - - if (rc.bottom > rc.top) - { - SPR_Set(m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); - } - - x += (m_prc1->right - m_prc1->left); - x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); - - return 1; - -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// battery.cpp +// +// implementation of CHudBattery class +// + +#include "hud.h" +#include "cl_util.h" + +#include +#include +#include "AvHPlayerUpgrade.h" +#include "AvHHudConstants.h" +#include "AvHNetworkMessages.h" + +DECLARE_MESSAGE(m_Battery, Battery) + +int CHudBattery::Init(void) +{ + m_iBat = 0; + m_fFade = 0; + m_iFlags = 0; + + HOOK_MESSAGE(Battery); + + gHUD.AddHudElem(this); + + return 1; +}; + + +int CHudBattery::VidInit(void) +{ + int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); + int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); + + m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded + m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty ); + m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full ); + m_iHeight = m_prc2->bottom - m_prc1->top; + m_fFade = 0; + return 1; +}; + +int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + + int x; + NetMsg_Battery( pbuf, iSize, x ); + + if (x != m_iBat) + { + // We're sent the health of the player we're observing as if it were our own + m_fFade = FADE_TIME; + m_iBat = x; + } + + return 1; +} + + +int CHudBattery::Draw(float flTime) +{ + + if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + rc = *m_prc2; + + int theMaxArmor = gHUD.GetHUDMaxArmor(); + float theScalar = 1.0f/theMaxArmor; + + rc.top += m_iHeight * ((float)(theMaxArmor-(min(theMaxArmor, m_iBat))) * theScalar); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + + gHUD.GetPrimaryHudColor(r, g, b); + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + // Has health changed? Flash the health # + if (m_fFade) + { + if (m_fFade > FADE_TIME) + m_fFade = FADE_TIME; + + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = 128; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + ScaleColors(r, g, b, a ); + + int iOffset = (m_prc1->bottom - m_prc1->top)/6; + + int theInset = 0; + if(gHUD.GetIsAlien()) + { + theInset = ScreenWidth()*kResourceEnergyBarWidth; + } + + int theViewport[4]; + gHUD.GetViewport(theViewport); + + y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = theViewport[0] + theInset + kArmorLeftInset*ScreenWidth(); + + // make sure we have the right sprite handles + if ( !m_hSprite1 ) + m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); + if ( !m_hSprite2 ) + m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); + + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); + + if (rc.bottom > rc.top) + { + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); + } + + x += (m_prc1->right - m_prc1->left); + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); + + return 1; + +} diff --git a/main/source/cl_dll/camera.h b/main/source/cl_dll/camera.h index 7b7cd017..0cf4beef 100644 --- a/main/source/cl_dll/camera.h +++ b/main/source/cl_dll/camera.h @@ -1,17 +1,17 @@ -// Camera.h -- defines and such for a 3rd person camera -// NOTE: must include quakedef.h first - -#ifndef _CAMERA_H_ -#define _CAMEA_H_ - -// pitch, yaw, dist -extern vec3_t cam_ofs; -// Using third person camera -extern int cam_thirdperson; - -void CAM_Init( void ); -void CAM_ClearStates( void ); -void CAM_StartMouseMove(void); -void CAM_EndMouseMove(void); - -#endif // _CAMERA_H_ +// Camera.h -- defines and such for a 3rd person camera +// NOTE: must include quakedef.h first + +#ifndef _CAMERA_H_ +#define _CAMEA_H_ + +// pitch, yaw, dist +extern vec3_t cam_ofs; +// Using third person camera +extern int cam_thirdperson; + +void CAM_Init( void ); +void CAM_ClearStates( void ); +void CAM_StartMouseMove(void); +void CAM_EndMouseMove(void); + +#endif // _CAMERA_H_ diff --git a/main/source/cl_dll/cdll_int.cpp b/main/source/cl_dll/cdll_int.cpp index 69ed67ab..8881398d 100644 --- a/main/source/cl_dll/cdll_int.cpp +++ b/main/source/cl_dll/cdll_int.cpp @@ -1,463 +1,463 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cdll_int.c -// -// this implementation handles the linking of the engine to the DLL -// - -#include "hud.h" -#include "cl_util.h" -#include "netadr.h" -#undef INTERFACE_H -#include "../common/interface.h" -#include "vgui_SchemeManager.h" -#include -/* -extern "C" -{ -#include "pm_shared.h" -}*/ -#include "pm_shared.h" - -#include -#include "hud_servers.h" -#include "vgui_int.h" - -#include "AvHHud.h" -#include "AvHUIFactory.h" -#include "AvHParticleSystemManager.h" -#include "AvHHulls.h" -#include "interface.h" -//#include "itrackeruser.h" - -#ifdef _WIN32 -#include "winsani_in.h" -#include -#include "winsani_out.h" -#endif -#include "Exports.h" -# -#include "tri.h" -#include "vgui_TeamFortressViewport.h" -#include "interface.h" - -#include "APIProxy.h" -//#include "cl_dll/Exports.h" - -cl_enginefunc_t gEngfuncs; - -// Instead of using default Half-life HUD, use more flexible one I've added -//CHud gHUD; -//UIHud gHUD("StratHL/ui.txt", new AvHUIFactory()); -AvHHud gHUD((string(getModDirectory()) + "/ui.txt").c_str(), new AvHUIFactory()); - -TeamFortressViewport *gViewPort = NULL; - -HINTERFACEMODULE g_hTrackerModule = NULL; -//ITrackerUser *g_pTrackerUser = NULL; - -void InitInput (void); -void EV_HookEvents( void ); -void IN_Commands( void ); - -/* -================================ -HUD_GetHullBounds - - Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. -================================ -*/ -int CL_DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ -// RecClGetHullBounds(hullnumber, mins, maxs); - - int iret = 0; - - switch ( hullnumber ) - { - case 0: // Human and level 4 alien, crouched level 5 - HULL0_MIN.CopyToArray(mins); - HULL0_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 1: // Crouched human, level 2 alien, level 3, crouched level 3 and 4 - HULL1_MIN.CopyToArray(mins); - HULL1_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 2: // Point based hull - HULL2_MIN.CopyToArray(mins); - HULL2_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 3: // Huge alien - HULL3_MIN.CopyToArray(mins); - HULL3_MAX.CopyToArray(maxs); - iret = 1; - break; - } - - return iret; -} - -/* -================================ -HUD_ConnectionlessPacket - - Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max - size of the response_buffer, so you must zero it out if you choose not to respond. -================================ -*/ -int CL_DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - //RecClConnectionlessPacket(net_from, args, response_buffer, response_buffer_size); - - // Parse stuff from args - int max_buffer_size = *response_buffer_size; - - // Zero it out since we aren't going to respond. - // If we wanted to response, we'd write data into response_buffer - *response_buffer_size = 0; - - // Since we don't listen for anything here, just respond that it's a bogus message - // If we didn't reject the message, we'd return 1 for success instead. - return 0; -} - -void CL_DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) -{ - //RecClClientMoveInit(ppmove); - - PM_Init( ppmove ); -} - -char CL_DLLEXPORT HUD_PlayerMoveTexture( char *name ) -{ -// RecClClientTextureType(name); - - return PM_FindTextureType( name ); -} - -void CL_DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) -{ - //RecClClientMove(ppmove, server); - - PM_Move( ppmove, server ); -} - -int CL_DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) -{ - gEngfuncs = *pEnginefuncs; - - //RecClInitialize(pEnginefuncs, iVersion); - - if (iVersion != CLDLL_INTERFACE_VERSION) - return 0; - - memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); - - EV_HookEvents(); - gHUD.InitExploitPrevention(); - - return 1; -} - - -/* -========================== - HUD_VidInit - -Called when the game initializes -and whenever the vid_mode is changed -so the HUD can reinitialize itself. -========================== -*/ - -int CL_DLLEXPORT HUD_VidInit( void ) -{ - gHUD.InitExploitPrevention(); -// RecClHudVidInit(); - gHUD.VidInit(); - - VGui_Startup(); - - return 1; -} - -/* -========================== -HUD_Init - - Called whenever the client connects - to a server. Reinitializes all - the hud variables. - ========================== -*/ - -void CL_DLLEXPORT HUD_Init( void ) -{ -// RecClHudInit(); - InitInput(); - gHUD.Init(); - Scheme_Init(); -} - -/* -void UIDrawVariableBarSpriteHoles(int inSprite, int inX, int inY, float inPercentage) -{ - // Assumes that frame 0 is the empty sprite, frame 1 is full sprite - const int kEmptyFrame = 0; - const int kFullFrame = 1; - - int theSpriteWidth = SPR_Width(inSprite, kFullFrame); - int theSpriteHeight = SPR_Height(inSprite, kFullFrame); - - int theColorComponent = 255; - - // Draw empty sprite - SPR_Set(inSprite, theColorComponent, theColorComponent, theColorComponent); - SPR_DrawHoles(kEmptyFrame, inX, inY, NULL); - - // Draw secondary level if specified, at half brightness - int theFilledHeight = theSpriteHeight*inPercentage; - theFilledHeight = theSpriteHeight*inPercentage; - - // Draw partially full sprite. Enable scissor so it's not all drawn. - SPR_EnableScissor(inX, inY + (theSpriteHeight - theFilledHeight), theSpriteWidth, theFilledHeight); - - SPR_Set(inSprite, theColorComponent, theColorComponent, theColorComponent); - SPR_DrawHoles(kFullFrame, inX, inY, NULL); - - SPR_DisableScissor(); -} -*/ -// Demonstrates black lines around the edge of sprites (both using tri API and SPR_* calls) -// Demonstrates scissor not working properly - -/* -========================== -HUD_Redraw - - called every screen frame to - redraw the HUD. - =========================== -*/ - -int CL_DLLEXPORT HUD_Redraw( float time, int intermission ) -{ -// RecClHudRedraw(time, intermission); - - gHUD.Redraw( time, intermission ); - - //Direct3DTest(); - - //SoftwareTest(); - - return 1; -} - - -/* -========================== - HUD_UpdateClientData - -called every time shared client -dll/engine data gets changed, -and gives the cdll a chance -to modify the data. - -returns 1 if anything has been changed, 0 otherwise. -========================== -*/ - -int CL_DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) -{ -// RecClHudUpdateClientData(pcldata, flTime); - - IN_Commands(); - - return gHUD.UpdateClientData(pcldata, flTime ); -} - -/* -========================== - HUD_Reset - -Called at start and end of demos to restore to "non"HUD state. -========================== -*/ - -void CL_DLLEXPORT HUD_Reset( void ) -{ -// RecClHudReset(); - - gHUD.VidInit(); - AvHParticleSystemManager::Instance()->Reset(); -} - -/* -========================== -HUD_Frame - - Called by engine every frame that client .dll is loaded - ========================== -*/ - -void CL_DLLEXPORT HUD_Frame( double time ) -{ -// RecClHudFrame(time); - - ServersThink( time ); - - GetClientVoiceMgr()->Frame(time); -} - - -/* -========================== -HUD_VoiceStatus - - Called when a player starts or stops talking. - ========================== -*/ - -void CL_DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) -{ -// RecClVoiceStatus(entindex, bTalking); - - GetClientVoiceMgr()->UpdateSpeakerStatus(entindex, bTalking); -} - -/* -========================== -HUD_DirectorEvent - - Called when a director event message was received - ========================== -*/ - -void CL_DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) -{ -// RecClDirectorMessage(iSize, pbuf); - gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); -} - - - -cldll_func_dst_t *g_pcldstAddrs; - -extern "C" void CL_DLLEXPORT F(void *pv) -{ - cldll_func_t *pcldll_func = (cldll_func_t *)pv; - - // Hack! - g_pcldstAddrs = ((cldll_func_dst_t *)pcldll_func->pHudVidInitFunc); - - cldll_func_t cldll_func = - { - Initialize, - HUD_Init, - HUD_VidInit, - HUD_Redraw, - HUD_UpdateClientData, - HUD_Reset, - HUD_PlayerMove, - HUD_PlayerMoveInit, - HUD_PlayerMoveTexture, - IN_ActivateMouse, - IN_DeactivateMouse, - IN_MouseEvent, - IN_ClearStates, - IN_Accumulate, - CL_CreateMove, - CL_IsThirdPerson, - CL_CameraOffset, - KB_Find, - CAM_Think, - V_CalcRefdef, - HUD_AddEntity, - HUD_CreateEntities, - HUD_DrawNormalTriangles, - HUD_DrawTransparentTriangles, - HUD_StudioEvent, - HUD_PostRunCmd, - HUD_Shutdown, - HUD_TxferLocalOverrides, - HUD_ProcessPlayerState, - HUD_TxferPredictionData, - Demo_ReadBuffer, - HUD_ConnectionlessPacket, - HUD_GetHullBounds, - HUD_Frame, - HUD_Key_Event, - HUD_TempEntUpdate, - HUD_GetUserEntity, - HUD_VoiceStatus, - HUD_DirectorMessage, - HUD_GetStudioModelInterface, - //HUD_ChatInputPosition, - }; - - *pcldll_func = cldll_func; -} - -#include "cl_dll/IGameClientExports.h" - -//----------------------------------------------------------------------------- -// Purpose: Exports functions that are used by the gameUI for UI dialogs -//----------------------------------------------------------------------------- -class CClientExports : public IGameClientExports -{ -public: - // returns the name of the server the user is connected to, if any - virtual const char *GetServerHostName() - { - /*if (gViewPortInterface) - { - return gViewPortInterface->GetServerName(); - }*/ - return ""; - } - - // ingame voice manipulation - virtual bool IsPlayerGameVoiceMuted(int playerIndex) - { - if (GetClientVoiceMgr()) - return GetClientVoiceMgr()->IsPlayerBlocked(playerIndex); - return false; - } - - virtual void MutePlayerGameVoice(int playerIndex) - { - if (GetClientVoiceMgr()) - { - GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, true); - } - } - - virtual void UnmutePlayerGameVoice(int playerIndex) - { - if (GetClientVoiceMgr()) - { - GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, false); - } - } -}; - -EXPOSE_SINGLE_INTERFACE(CClientExports, IGameClientExports, GAMECLIENTEXPORTS_INTERFACE_VERSION); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cdll_int.c +// +// this implementation handles the linking of the engine to the DLL +// + +#include "hud.h" +#include "cl_util.h" +#include "netadr.h" +#undef INTERFACE_H +#include "../common/interface.h" +#include "vgui_SchemeManager.h" +#include +/* +extern "C" +{ +#include "pm_shared.h" +}*/ +#include "pm_shared.h" + +#include +#include "hud_servers.h" +#include "vgui_int.h" + +#include "AvHHud.h" +#include "AvHUIFactory.h" +#include "AvHParticleSystemManager.h" +#include "AvHHulls.h" +#include "interface.h" +//#include "itrackeruser.h" + +#ifdef _WIN32 +#include "winsani_in.h" +#include +#include "winsani_out.h" +#endif +#include "Exports.h" +# +#include "tri.h" +#include "vgui_TeamFortressViewport.h" +#include "interface.h" + +#include "APIProxy.h" +//#include "cl_dll/Exports.h" + +cl_enginefunc_t gEngfuncs; + +// Instead of using default Half-life HUD, use more flexible one I've added +//CHud gHUD; +//UIHud gHUD("StratHL/ui.txt", new AvHUIFactory()); +AvHHud gHUD((string(getModDirectory()) + "/ui.txt").c_str(), new AvHUIFactory()); + +TeamFortressViewport *gViewPort = NULL; + +HINTERFACEMODULE g_hTrackerModule = NULL; +//ITrackerUser *g_pTrackerUser = NULL; + +void InitInput (void); +void EV_HookEvents( void ); +void IN_Commands( void ); + +/* +================================ +HUD_GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int CL_DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ +// RecClGetHullBounds(hullnumber, mins, maxs); + + int iret = 0; + + switch ( hullnumber ) + { + case 0: // Human and level 4 alien, crouched level 5 + HULL0_MIN.CopyToArray(mins); + HULL0_MAX.CopyToArray(maxs); + iret = 1; + break; + + case 1: // Crouched human, level 2 alien, level 3, crouched level 3 and 4 + HULL1_MIN.CopyToArray(mins); + HULL1_MAX.CopyToArray(maxs); + iret = 1; + break; + + case 2: // Point based hull + HULL2_MIN.CopyToArray(mins); + HULL2_MAX.CopyToArray(maxs); + iret = 1; + break; + + case 3: // Huge alien + HULL3_MIN.CopyToArray(mins); + HULL3_MAX.CopyToArray(maxs); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +HUD_ConnectionlessPacket + + Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max + size of the response_buffer, so you must zero it out if you choose not to respond. +================================ +*/ +int CL_DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + //RecClConnectionlessPacket(net_from, args, response_buffer, response_buffer_size); + + // Parse stuff from args + int max_buffer_size = *response_buffer_size; + + // Zero it out since we aren't going to respond. + // If we wanted to response, we'd write data into response_buffer + *response_buffer_size = 0; + + // Since we don't listen for anything here, just respond that it's a bogus message + // If we didn't reject the message, we'd return 1 for success instead. + return 0; +} + +void CL_DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) +{ + //RecClClientMoveInit(ppmove); + + PM_Init( ppmove ); +} + +char CL_DLLEXPORT HUD_PlayerMoveTexture( char *name ) +{ +// RecClClientTextureType(name); + + return PM_FindTextureType( name ); +} + +void CL_DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) +{ + //RecClClientMove(ppmove, server); + + PM_Move( ppmove, server ); +} + +int CL_DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) +{ + gEngfuncs = *pEnginefuncs; + + //RecClInitialize(pEnginefuncs, iVersion); + + if (iVersion != CLDLL_INTERFACE_VERSION) + return 0; + + memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); + + EV_HookEvents(); + gHUD.InitExploitPrevention(); + + return 1; +} + + +/* +========================== + HUD_VidInit + +Called when the game initializes +and whenever the vid_mode is changed +so the HUD can reinitialize itself. +========================== +*/ + +int CL_DLLEXPORT HUD_VidInit( void ) +{ + gHUD.InitExploitPrevention(); +// RecClHudVidInit(); + gHUD.VidInit(); + + VGui_Startup(); + + return 1; +} + +/* +========================== +HUD_Init + + Called whenever the client connects + to a server. Reinitializes all + the hud variables. + ========================== +*/ + +void CL_DLLEXPORT HUD_Init( void ) +{ +// RecClHudInit(); + InitInput(); + gHUD.Init(); + Scheme_Init(); +} + +/* +void UIDrawVariableBarSpriteHoles(int inSprite, int inX, int inY, float inPercentage) +{ + // Assumes that frame 0 is the empty sprite, frame 1 is full sprite + const int kEmptyFrame = 0; + const int kFullFrame = 1; + + int theSpriteWidth = SPR_Width(inSprite, kFullFrame); + int theSpriteHeight = SPR_Height(inSprite, kFullFrame); + + int theColorComponent = 255; + + // Draw empty sprite + SPR_Set(inSprite, theColorComponent, theColorComponent, theColorComponent); + SPR_DrawHoles(kEmptyFrame, inX, inY, NULL); + + // Draw secondary level if specified, at half brightness + int theFilledHeight = theSpriteHeight*inPercentage; + theFilledHeight = theSpriteHeight*inPercentage; + + // Draw partially full sprite. Enable scissor so it's not all drawn. + SPR_EnableScissor(inX, inY + (theSpriteHeight - theFilledHeight), theSpriteWidth, theFilledHeight); + + SPR_Set(inSprite, theColorComponent, theColorComponent, theColorComponent); + SPR_DrawHoles(kFullFrame, inX, inY, NULL); + + SPR_DisableScissor(); +} +*/ +// Demonstrates black lines around the edge of sprites (both using tri API and SPR_* calls) +// Demonstrates scissor not working properly + +/* +========================== +HUD_Redraw + + called every screen frame to + redraw the HUD. + =========================== +*/ + +int CL_DLLEXPORT HUD_Redraw( float time, int intermission ) +{ +// RecClHudRedraw(time, intermission); + + gHUD.Redraw( time, intermission ); + + //Direct3DTest(); + + //SoftwareTest(); + + return 1; +} + + +/* +========================== + HUD_UpdateClientData + +called every time shared client +dll/engine data gets changed, +and gives the cdll a chance +to modify the data. + +returns 1 if anything has been changed, 0 otherwise. +========================== +*/ + +int CL_DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) +{ +// RecClHudUpdateClientData(pcldata, flTime); + + IN_Commands(); + + return gHUD.UpdateClientData(pcldata, flTime ); +} + +/* +========================== + HUD_Reset + +Called at start and end of demos to restore to "non"HUD state. +========================== +*/ + +void CL_DLLEXPORT HUD_Reset( void ) +{ +// RecClHudReset(); + + gHUD.VidInit(); + AvHParticleSystemManager::Instance()->Reset(); +} + +/* +========================== +HUD_Frame + + Called by engine every frame that client .dll is loaded + ========================== +*/ + +void CL_DLLEXPORT HUD_Frame( double time ) +{ +// RecClHudFrame(time); + + ServersThink( time ); + + GetClientVoiceMgr()->Frame(time); +} + + +/* +========================== +HUD_VoiceStatus + + Called when a player starts or stops talking. + ========================== +*/ + +void CL_DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) +{ +// RecClVoiceStatus(entindex, bTalking); + + GetClientVoiceMgr()->UpdateSpeakerStatus(entindex, bTalking); +} + +/* +========================== +HUD_DirectorEvent + + Called when a director event message was received + ========================== +*/ + +void CL_DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) +{ +// RecClDirectorMessage(iSize, pbuf); + gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); +} + + + +cldll_func_dst_t *g_pcldstAddrs; + +extern "C" void CL_DLLEXPORT F(void *pv) +{ + cldll_func_t *pcldll_func = (cldll_func_t *)pv; + + // Hack! + g_pcldstAddrs = ((cldll_func_dst_t *)pcldll_func->pHudVidInitFunc); + + cldll_func_t cldll_func = + { + Initialize, + HUD_Init, + HUD_VidInit, + HUD_Redraw, + HUD_UpdateClientData, + HUD_Reset, + HUD_PlayerMove, + HUD_PlayerMoveInit, + HUD_PlayerMoveTexture, + IN_ActivateMouse, + IN_DeactivateMouse, + IN_MouseEvent, + IN_ClearStates, + IN_Accumulate, + CL_CreateMove, + CL_IsThirdPerson, + CL_CameraOffset, + KB_Find, + CAM_Think, + V_CalcRefdef, + HUD_AddEntity, + HUD_CreateEntities, + HUD_DrawNormalTriangles, + HUD_DrawTransparentTriangles, + HUD_StudioEvent, + HUD_PostRunCmd, + HUD_Shutdown, + HUD_TxferLocalOverrides, + HUD_ProcessPlayerState, + HUD_TxferPredictionData, + Demo_ReadBuffer, + HUD_ConnectionlessPacket, + HUD_GetHullBounds, + HUD_Frame, + HUD_Key_Event, + HUD_TempEntUpdate, + HUD_GetUserEntity, + HUD_VoiceStatus, + HUD_DirectorMessage, + HUD_GetStudioModelInterface, + //HUD_ChatInputPosition, + }; + + *pcldll_func = cldll_func; +} + +#include "cl_dll/IGameClientExports.h" + +//----------------------------------------------------------------------------- +// Purpose: Exports functions that are used by the gameUI for UI dialogs +//----------------------------------------------------------------------------- +class CClientExports : public IGameClientExports +{ +public: + // returns the name of the server the user is connected to, if any + virtual const char *GetServerHostName() + { + /*if (gViewPortInterface) + { + return gViewPortInterface->GetServerName(); + }*/ + return ""; + } + + // ingame voice manipulation + virtual bool IsPlayerGameVoiceMuted(int playerIndex) + { + if (GetClientVoiceMgr()) + return GetClientVoiceMgr()->IsPlayerBlocked(playerIndex); + return false; + } + + virtual void MutePlayerGameVoice(int playerIndex) + { + if (GetClientVoiceMgr()) + { + GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, true); + } + } + + virtual void UnmutePlayerGameVoice(int playerIndex) + { + if (GetClientVoiceMgr()) + { + GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, false); + } + } +}; + +EXPOSE_SINGLE_INTERFACE(CClientExports, IGameClientExports, GAMECLIENTEXPORTS_INTERFACE_VERSION); diff --git a/main/source/cl_dll/chud.h b/main/source/cl_dll/chud.h index 87fc1214..b349e857 100644 --- a/main/source/cl_dll/chud.h +++ b/main/source/cl_dll/chud.h @@ -1,121 +1,121 @@ -#ifndef CHUD_H -#define CHUD_H - -#include "chudmisc.h" -#include "hud_spectator.h" -#include "AvHFont.h" - - -class CHud -{ -private: - HUDLIST *m_pHudList; - HSPRITE m_hsprLogo; - int m_iLogo; - client_sprite_t *m_pSpriteList; - int m_iSpriteCount; - int m_iSpriteCountAllRes; - float m_flMouseSensitivity; - -public: - - HSPRITE m_hsprCursor; - float m_flTime; // the current client time - float m_fOldTime; // the time at which the HUD was last redrawn - double m_flTimeDelta; // the difference between flTime and fOldTime - Vector m_vecOrigin; - Vector m_vecAngles; - int m_iKeyBits; - int m_iHideHUDDisplay; - int m_iFOV; - int m_iRes; - cvar_t *m_pCvarStealMouse; - cvar_t *m_pCvarDraw; - - int m_iFontHeight; - int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); - int DrawHudStringCentered(int x, int y, int iMaxX, const char *szString, int r, int g, int b ); - int DrawHudString(int x, int y, int iMaxX, const char *szString, int r, int g, int b ); - int GetHudStringHeight(); - int GetHudStringWidth(const char* szIt); - int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); - int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); - int GetNumWidth(int iNumber, int iFlags); - -private: - // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. - // freed in ~CHud() - HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt - wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ - char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ - - struct cvar_s *default_fov; - - -public: - HSPRITE GetSprite( int index ) - { - return (index < 0) ? 0 : m_rghSprites[index]; - } - - wrect_t& GetSpriteRect( int index ) - { - return m_rgrcRects[index]; - } - - - int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array - - CHudAmmo m_Ammo; - CHudHealth m_Health; - CHudSpectator m_Spectator; - CHudGeiger m_Geiger; - CHudBattery m_Battery; - CHudTrain m_Train; - CHudFlashlight m_Flash; - CHudMessage m_Message; - CHudStatusBar m_StatusBar; - CHudDeathNotice m_DeathNotice; - CHudSayText m_SayText; - CHudMenu m_Menu; - CHudAmmoSecondary m_AmmoSecondary; - CHudTextMessage m_TextMessage; - CHudStatusIcons m_StatusIcons; - - AvHFont mFont; - AvHFont mSmallFont; - - void Init( void ); - void VidInit( void ); - void Think(void); - int Redraw( float flTime, int intermission ); - int UpdateClientData( client_data_t *cdata, float time ); - - CHud() : m_iSpriteCount(0), m_pHudList(NULL) {} - ~CHud(); // destructor, frees allocated memory - - // user messages - int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); - void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); - void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); - - // Screen information - SCREENINFO m_scrinfo; - - int m_iWeaponBits; - int m_fPlayerDead; - int m_iIntermission; - - // sprite indexes - int m_HUD_number_0; - - void AddHudElem(CHudBase *p); - - float GetSensitivity(); - -}; - - - -#endif +#ifndef CHUD_H +#define CHUD_H + +#include "chudmisc.h" +#include "hud_spectator.h" +#include "AvHFont.h" + + +class CHud +{ +private: + HUDLIST *m_pHudList; + HSPRITE m_hsprLogo; + int m_iLogo; + client_sprite_t *m_pSpriteList; + int m_iSpriteCount; + int m_iSpriteCountAllRes; + float m_flMouseSensitivity; + +public: + + HSPRITE m_hsprCursor; + float m_flTime; // the current client time + float m_fOldTime; // the time at which the HUD was last redrawn + double m_flTimeDelta; // the difference between flTime and fOldTime + Vector m_vecOrigin; + Vector m_vecAngles; + int m_iKeyBits; + int m_iHideHUDDisplay; + int m_iFOV; + int m_iRes; + cvar_t *m_pCvarStealMouse; + cvar_t *m_pCvarDraw; + + int m_iFontHeight; + int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); + int DrawHudStringCentered(int x, int y, int iMaxX, const char *szString, int r, int g, int b ); + int DrawHudString(int x, int y, int iMaxX, const char *szString, int r, int g, int b ); + int GetHudStringHeight(); + int GetHudStringWidth(const char* szIt); + int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); + int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); + int GetNumWidth(int iNumber, int iFlags); + +private: + // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. + // freed in ~CHud() + HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt + wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ + char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ + + struct cvar_s *default_fov; + + +public: + HSPRITE GetSprite( int index ) + { + return (index < 0) ? 0 : m_rghSprites[index]; + } + + wrect_t& GetSpriteRect( int index ) + { + return m_rgrcRects[index]; + } + + + int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array + + CHudAmmo m_Ammo; + CHudHealth m_Health; + CHudSpectator m_Spectator; + CHudGeiger m_Geiger; + CHudBattery m_Battery; + CHudTrain m_Train; + CHudFlashlight m_Flash; + CHudMessage m_Message; + CHudStatusBar m_StatusBar; + CHudDeathNotice m_DeathNotice; + CHudSayText m_SayText; + CHudMenu m_Menu; + CHudAmmoSecondary m_AmmoSecondary; + CHudTextMessage m_TextMessage; + CHudStatusIcons m_StatusIcons; + + AvHFont mFont; + AvHFont mSmallFont; + + void Init( void ); + void VidInit( void ); + void Think(void); + int Redraw( float flTime, int intermission ); + int UpdateClientData( client_data_t *cdata, float time ); + + CHud() : m_iSpriteCount(0), m_pHudList(NULL) {} + ~CHud(); // destructor, frees allocated memory + + // user messages + int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); + void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); + void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); + + // Screen information + SCREENINFO m_scrinfo; + + int m_iWeaponBits; + int m_fPlayerDead; + int m_iIntermission; + + // sprite indexes + int m_HUD_number_0; + + void AddHudElem(CHudBase *p); + + float GetSensitivity(); + +}; + + + +#endif diff --git a/main/source/cl_dll/chudmisc.h b/main/source/cl_dll/chudmisc.h index 45423139..a5c7b1e2 100644 --- a/main/source/cl_dll/chudmisc.h +++ b/main/source/cl_dll/chudmisc.h @@ -1,506 +1,506 @@ -#ifndef CHUDMISC_H -#define CHUDMISC_H - -#define RGB_YELLOWISH 0x00FFA000 //255,160,0 -#define RGB_REDISH 0x00FF1010 //255,160,0 -#define RGB_GREENISH 0x0000A000 //0,160,0 -#define RGB_MARINE_BLUE 0x000099FF //0 153 255 -#define RGB_MARINE_SELECTED 0x006EE6FF //110, 230, 255 -#define RGB_MARINE_PARASITED 0x00E3F03D //227, 240, 61 - - -#ifndef _WIN32 -#define _cdecl -#else -#undef _cdecl -#endif - -#include "wrect.h" -#include "cl_dll.h" -#include "ammo.h" -#include "teamconst.h" - -#define DHN_DRAWZERO 1 -#define DHN_2DIGITS 2 -#define DHN_3DIGITS 4 -#define MIN_ALPHA 100 - -#define HUDELEM_ACTIVE 1 - -typedef struct { - int x, y; -} POSITION; - -typedef struct { - unsigned char r,g,b,a; -} RGBA; - -typedef struct cvar_s cvar_t; - - -#define HUD_ACTIVE 1 -#define HUD_INTERMISSION 2 - -#define MAX_PLAYER_NAME_LENGTH 32 - -#define MAX_MOTD_LENGTH 1536 - -// -//----------------------------------------------------- -// -class CHudBase -{ -public: - POSITION m_pos; - int m_type; - int m_iFlags; // active, moving, - virtual ~CHudBase() {} - virtual int Init( void ) {return 0;} - virtual int VidInit( void ) {return 0;} - virtual int Draw(float flTime) {return 0;} - virtual void Think(void) {return;} - virtual void Reset(void) {return;} - virtual void InitHUDData( void ) {} // called every time a server is connected to - -}; - -struct HUDLIST { - CHudBase *p; - HUDLIST *pNext; -}; - - - -// -//----------------------------------------------------- -// -#include "voice_status.h" -#include "hud_spectator.h" - - -// -//----------------------------------------------------- -// -class CHudAmmo: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - void Think(void); - void Reset(void); - int DrawWList(float flTime); - int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); - int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); - int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); - int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ); - - void SlotInput( int iSlot ); - void _cdecl UserCmd_Slot1( void ); - void _cdecl UserCmd_Slot2( void ); - void _cdecl UserCmd_Slot3( void ); - void _cdecl UserCmd_Slot4( void ); - void _cdecl UserCmd_Slot5( void ); - void _cdecl UserCmd_Slot6( void ); - void _cdecl UserCmd_Slot7( void ); - void _cdecl UserCmd_Slot8( void ); - void _cdecl UserCmd_Slot9( void ); - void _cdecl UserCmd_Slot10( void ); - void _cdecl UserCmd_Close( void ); - void _cdecl UserCmd_NextWeapon( void ); - void _cdecl UserCmd_PrevWeapon( void ); - - void SetCurrentClip(int inClip); -private: - float m_fFade; - RGBA m_rgba; - WEAPON *m_pWeapon; - int m_HUD_bucket0; - int m_HUD_selection; - int m_customCrosshair; - -}; - - - -// -//----------------------------------------------------- -// -class CHudAmmoSecondary: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - void Reset( void ); - int Draw(float flTime); - - int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ); - -private: - enum { - MAX_SEC_AMMO_VALUES = 4 - }; - - int m_HUD_ammoicon; // sprite indices - int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES]; - float m_fFade; -}; - - -#include "health.h" - - -#define FADE_TIME 100 - - - - -// -//----------------------------------------------------- -// -class CHudGeiger: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); - -private: - int m_iGeigerRange; - -}; - -// -//----------------------------------------------------- -// -class CHudTrain: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); - -private: - HSPRITE m_hSprite; - int m_iPos; - -}; - -// -//----------------------------------------------------- -// -class CHudStatusBar : public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw( float flTime ); - const char* GetStatusString() const; - void Reset( void ); - void ParseStatusString( int line_num ); - - int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); - -protected: - void ReparseStringIfNeeded(); - - enum { - MAX_STATUSTEXT_LENGTH = 128, - MAX_STATUSBAR_VALUES = 8, - MAX_STATUSBAR_LINES = 2, - }; - - char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn - char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn - int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar - - int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated - - // an array of colors...one color for each line - float *m_pflNameColors[MAX_STATUSBAR_LINES]; -}; - -class ScoreboardIcon; -// : 0001073 -#define CUSTOM_ICON_LENGTH 32 - -struct extra_player_info_t -{ - short score; - short lastScore; - float timeOfLastScoreChange; - short frags; - short deaths; - short playerclass; - short extra; - short auth; - short teamnumber; - char teamname[MAX_TEAM_NAME]; - char customicon[CUSTOM_ICON_LENGTH + 3]; //last 3 characters is the color. - short health; - ScoreboardIcon* icon; -}; - -struct team_info_t -{ - char name[MAX_TEAM_NAME]; - short score; - short frags; - short deaths; - short ping; - short packetloss; - short ownteam; - short players; - int already_drawn; - int scores_overriden; - int teamnumber; -}; - -extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine -extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll -extern team_info_t g_TeamInfo[MAX_TEAMS+1]; -extern int g_IsSpectator[MAX_PLAYERS+1]; - - -// -//----------------------------------------------------- -// -class CHudDeathNotice : public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ); - -private: - int m_HUD_d_skull; // sprite index of skull icon -}; - - -// -//----------------------------------------------------- -// -class CHudMenu : public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - void Reset( void ); - int Draw( float flTime ); - int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ); - - void SelectMenuItem( int menu_item ); - - int m_fMenuDisplayed; - int m_bitsValidSlots; - float m_flShutoffTime; - int m_fWaitingForMore; -}; - - -// -//----------------------------------------------------- -// -class CHudSayText : public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); - void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); - void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); -friend class CHud; -friend class CHudSpectator; - -private: - - struct cvar_s * m_HUD_saytext; - struct cvar_s * m_HUD_saytext_time; -}; - - -// -//----------------------------------------------------- -// -class CHudBattery: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); - -private: - HSPRITE m_hSprite1; - HSPRITE m_hSprite2; - wrect_t *m_prc1; - wrect_t *m_prc2; - int m_iBat; - float m_fFade; - int m_iHeight; // width of the battery innards -}; - - - -// -//----------------------------------------------------- -// -class CHudFlashlight: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - void Reset( void ); - int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); - int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); - -private: - HSPRITE m_hSprite1; - HSPRITE m_hSprite2; - HSPRITE m_hBeam; - wrect_t *m_prc1; - wrect_t *m_prc2; - wrect_t *m_prcBeam; - float m_flBat; - int m_iBat; - int m_fOn; - float m_fFade; - int m_iWidth; // width of the battery innards -}; - - -// -//----------------------------------------------------- -// -const int maxHUDMessages = 16; -struct message_parms_t -{ - client_textmessage_t *pMessage; - float time; - int x, y; - int totalWidth, totalHeight; - int width; - int lines; - int lineLength; - int length; - int r, g, b; - int text; - int fadeBlend; - float charTime; - float fadeTime; -}; - - -// -//----------------------------------------------------- -// -class CHudTextMessage: public CHudBase -{ -public: - int Init( void ); - static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); - static char *BufferedLocaliseTextString( const char *msg ); - char *LookupString( const char *msg_name, int *msg_dest = NULL ); - int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); -}; - - -// -//----------------------------------------------------- -// - -class CHudMessage: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); - int MsgFunc_HudText2(const char *pszName, int iSize, void *pbuf); - int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); - - float FadeBlend( float fadein, float fadeout, float hold, float localTime ); - int XPosition( float x, int width, int lineWidth ); - int YPosition( float y, int height ); - - void MessageAddPlayerID(const char* pName, bool inEnemy); - - void MessageAdd( const char *pName, float time ); - bool MessageRemove( const char *pName ); - void MessageDrawScan( client_textmessage_t *pMessage, float time ); - void MessageScanStart( void ); - void MessageScanNextChar( void ); - void Reset( void ); - -private: - bool DrawMessage(client_textmessage_t* inMessage, float inStartTime, float inCurrentTime); - void SetPlayerIDPosition(); - - client_textmessage_t *m_pMessages[maxHUDMessages]; - float m_startTime[maxHUDMessages]; - message_parms_t m_parms; - float m_gameTitleTime; - client_textmessage_t *m_pGameTitle; - - client_textmessage_t mPlayerIDMessage; - float mPlayerIDTime; - char* mPlayerID; - - int m_HUD_title_life; - int m_HUD_title_half; -}; - -// -//----------------------------------------------------- -// -#define MAX_SPRITE_NAME_LENGTH 24 - -class CHudStatusIcons: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - void Reset( void ); - int Draw(float flTime); - - enum { - MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, - MAX_ICONSPRITES = 4, - }; - - - //had to make these public so CHud could access them (to enable concussion icon) - //could use a friend declaration instead... - void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); - void DisableIcon( char *pszIconName ); - -private: - - typedef struct - { - char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; - HSPRITE spr; - wrect_t rc; - unsigned char r, g, b; - } icon_sprite_t; - - icon_sprite_t m_IconList[MAX_ICONSPRITES]; - -}; - -typedef struct cvar_s cvar_t; - -#endif +#ifndef CHUDMISC_H +#define CHUDMISC_H + +#define RGB_YELLOWISH 0x00FFA000 //255,160,0 +#define RGB_REDISH 0x00FF1010 //255,160,0 +#define RGB_GREENISH 0x0000A000 //0,160,0 +#define RGB_MARINE_BLUE 0x000099FF //0 153 255 +#define RGB_MARINE_SELECTED 0x006EE6FF //110, 230, 255 +#define RGB_MARINE_PARASITED 0x00E3F03D //227, 240, 61 + + +#ifndef _WIN32 +#define _cdecl +#else +#undef _cdecl +#endif + +#include "wrect.h" +#include "cl_dll.h" +#include "ammo.h" +#include "teamconst.h" + +#define DHN_DRAWZERO 1 +#define DHN_2DIGITS 2 +#define DHN_3DIGITS 4 +#define MIN_ALPHA 100 + +#define HUDELEM_ACTIVE 1 + +typedef struct { + int x, y; +} POSITION; + +typedef struct { + unsigned char r,g,b,a; +} RGBA; + +typedef struct cvar_s cvar_t; + + +#define HUD_ACTIVE 1 +#define HUD_INTERMISSION 2 + +#define MAX_PLAYER_NAME_LENGTH 32 + +#define MAX_MOTD_LENGTH 1536 + +// +//----------------------------------------------------- +// +class CHudBase +{ +public: + POSITION m_pos; + int m_type; + int m_iFlags; // active, moving, + virtual ~CHudBase() {} + virtual int Init( void ) {return 0;} + virtual int VidInit( void ) {return 0;} + virtual int Draw(float flTime) {return 0;} + virtual void Think(void) {return;} + virtual void Reset(void) {return;} + virtual void InitHUDData( void ) {} // called every time a server is connected to + +}; + +struct HUDLIST { + CHudBase *p; + HUDLIST *pNext; +}; + + + +// +//----------------------------------------------------- +// +#include "voice_status.h" +#include "hud_spectator.h" + + +// +//----------------------------------------------------- +// +class CHudAmmo: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Think(void); + void Reset(void); + int DrawWList(float flTime); + int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); + int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ); + + void SlotInput( int iSlot ); + void _cdecl UserCmd_Slot1( void ); + void _cdecl UserCmd_Slot2( void ); + void _cdecl UserCmd_Slot3( void ); + void _cdecl UserCmd_Slot4( void ); + void _cdecl UserCmd_Slot5( void ); + void _cdecl UserCmd_Slot6( void ); + void _cdecl UserCmd_Slot7( void ); + void _cdecl UserCmd_Slot8( void ); + void _cdecl UserCmd_Slot9( void ); + void _cdecl UserCmd_Slot10( void ); + void _cdecl UserCmd_Close( void ); + void _cdecl UserCmd_NextWeapon( void ); + void _cdecl UserCmd_PrevWeapon( void ); + + void SetCurrentClip(int inClip); +private: + float m_fFade; + RGBA m_rgba; + WEAPON *m_pWeapon; + int m_HUD_bucket0; + int m_HUD_selection; + int m_customCrosshair; + +}; + + + +// +//----------------------------------------------------- +// +class CHudAmmoSecondary: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + void Reset( void ); + int Draw(float flTime); + + int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ); + +private: + enum { + MAX_SEC_AMMO_VALUES = 4 + }; + + int m_HUD_ammoicon; // sprite indices + int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES]; + float m_fFade; +}; + + +#include "health.h" + + +#define FADE_TIME 100 + + + + +// +//----------------------------------------------------- +// +class CHudGeiger: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); + +private: + int m_iGeigerRange; + +}; + +// +//----------------------------------------------------- +// +class CHudTrain: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); + +private: + HSPRITE m_hSprite; + int m_iPos; + +}; + +// +//----------------------------------------------------- +// +class CHudStatusBar : public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw( float flTime ); + const char* GetStatusString() const; + void Reset( void ); + void ParseStatusString( int line_num ); + + int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); + +protected: + void ReparseStringIfNeeded(); + + enum { + MAX_STATUSTEXT_LENGTH = 128, + MAX_STATUSBAR_VALUES = 8, + MAX_STATUSBAR_LINES = 2, + }; + + char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn + char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn + int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar + + int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated + + // an array of colors...one color for each line + float *m_pflNameColors[MAX_STATUSBAR_LINES]; +}; + +class ScoreboardIcon; +// : 0001073 +#define CUSTOM_ICON_LENGTH 32 + +struct extra_player_info_t +{ + short score; + short lastScore; + float timeOfLastScoreChange; + short frags; + short deaths; + short playerclass; + short extra; + short auth; + short teamnumber; + char teamname[MAX_TEAM_NAME]; + char customicon[CUSTOM_ICON_LENGTH + 3]; //last 3 characters is the color. + short health; + ScoreboardIcon* icon; +}; + +struct team_info_t +{ + char name[MAX_TEAM_NAME]; + short score; + short frags; + short deaths; + short ping; + short packetloss; + short ownteam; + short players; + int already_drawn; + int scores_overriden; + int teamnumber; +}; + +extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +extern team_info_t g_TeamInfo[MAX_TEAMS+1]; +extern int g_IsSpectator[MAX_PLAYERS+1]; + + +// +//----------------------------------------------------- +// +class CHudDeathNotice : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ); + +private: + int m_HUD_d_skull; // sprite index of skull icon +}; + + +// +//----------------------------------------------------- +// +class CHudMenu : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + void Reset( void ); + int Draw( float flTime ); + int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ); + + void SelectMenuItem( int menu_item ); + + int m_fMenuDisplayed; + int m_bitsValidSlots; + float m_flShutoffTime; + int m_fWaitingForMore; +}; + + +// +//----------------------------------------------------- +// +class CHudSayText : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); + void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); + void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); +friend class CHud; +friend class CHudSpectator; + +private: + + struct cvar_s * m_HUD_saytext; + struct cvar_s * m_HUD_saytext_time; +}; + + +// +//----------------------------------------------------- +// +class CHudBattery: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); + +private: + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + wrect_t *m_prc1; + wrect_t *m_prc2; + int m_iBat; + float m_fFade; + int m_iHeight; // width of the battery innards +}; + + + +// +//----------------------------------------------------- +// +class CHudFlashlight: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset( void ); + int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); + +private: + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + HSPRITE m_hBeam; + wrect_t *m_prc1; + wrect_t *m_prc2; + wrect_t *m_prcBeam; + float m_flBat; + int m_iBat; + int m_fOn; + float m_fFade; + int m_iWidth; // width of the battery innards +}; + + +// +//----------------------------------------------------- +// +const int maxHUDMessages = 16; +struct message_parms_t +{ + client_textmessage_t *pMessage; + float time; + int x, y; + int totalWidth, totalHeight; + int width; + int lines; + int lineLength; + int length; + int r, g, b; + int text; + int fadeBlend; + float charTime; + float fadeTime; +}; + + +// +//----------------------------------------------------- +// +class CHudTextMessage: public CHudBase +{ +public: + int Init( void ); + static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); + static char *BufferedLocaliseTextString( const char *msg ); + char *LookupString( const char *msg_name, int *msg_dest = NULL ); + int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); +}; + + +// +//----------------------------------------------------- +// + +class CHudMessage: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); + int MsgFunc_HudText2(const char *pszName, int iSize, void *pbuf); + int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); + + float FadeBlend( float fadein, float fadeout, float hold, float localTime ); + int XPosition( float x, int width, int lineWidth ); + int YPosition( float y, int height ); + + void MessageAddPlayerID(const char* pName, bool inEnemy); + + void MessageAdd( const char *pName, float time ); + bool MessageRemove( const char *pName ); + void MessageDrawScan( client_textmessage_t *pMessage, float time ); + void MessageScanStart( void ); + void MessageScanNextChar( void ); + void Reset( void ); + +private: + bool DrawMessage(client_textmessage_t* inMessage, float inStartTime, float inCurrentTime); + void SetPlayerIDPosition(); + + client_textmessage_t *m_pMessages[maxHUDMessages]; + float m_startTime[maxHUDMessages]; + message_parms_t m_parms; + float m_gameTitleTime; + client_textmessage_t *m_pGameTitle; + + client_textmessage_t mPlayerIDMessage; + float mPlayerIDTime; + char* mPlayerID; + + int m_HUD_title_life; + int m_HUD_title_half; +}; + +// +//----------------------------------------------------- +// +#define MAX_SPRITE_NAME_LENGTH 24 + +class CHudStatusIcons: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + void Reset( void ); + int Draw(float flTime); + + enum { + MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, + MAX_ICONSPRITES = 4, + }; + + + //had to make these public so CHud could access them (to enable concussion icon) + //could use a friend declaration instead... + void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); + void DisableIcon( char *pszIconName ); + +private: + + typedef struct + { + char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; + HSPRITE spr; + wrect_t rc; + unsigned char r, g, b; + } icon_sprite_t; + + icon_sprite_t m_IconList[MAX_ICONSPRITES]; + +}; + +typedef struct cvar_s cvar_t; + +#endif diff --git a/main/source/cl_dll/cl_dll.h b/main/source/cl_dll/cl_dll.h index 20234309..cd9be37e 100644 --- a/main/source/cl_dll/cl_dll.h +++ b/main/source/cl_dll/cl_dll.h @@ -1,36 +1,36 @@ -/*** -* +/*** +* * Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cl_dll.h -// - -// 4-23-98 JOHN - -// -// This DLL is linked by the client when they first initialize. -// This DLL is responsible for the following tasks: -// - Loading the HUD graphics upon initialization -// - Drawing the HUD graphics every frame -// - Handling the custum HUD-update packets -// -typedef unsigned char byte; -typedef unsigned short word; -typedef float vec_t; -typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); - -#include "util_vector.h" +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cl_dll.h +// + +// 4-23-98 JOHN + +// +// This DLL is linked by the client when they first initialize. +// This DLL is responsible for the following tasks: +// - Loading the HUD graphics upon initialization +// - Drawing the HUD graphics every frame +// - Handling the custum HUD-update packets +// +typedef unsigned char byte; +typedef unsigned short word; +typedef float vec_t; +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); + +#include "util_vector.h" #ifdef _WIN32 #ifndef EXPORT #define EXPORT _declspec( dllexport ) @@ -38,8 +38,8 @@ typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); #else #define EXPORT __attribute__ ((visibility("default"))) #endif - -#include "../engine/cdll_int.h" -#include "../dlls/cdll_dll.h" - -extern cl_enginefunc_t gEngfuncs; + +#include "../engine/cdll_int.h" +#include "../dlls/cdll_dll.h" + +extern cl_enginefunc_t gEngfuncs; diff --git a/main/source/cl_dll/cl_dll.vcproj b/main/source/cl_dll/cl_dll.vcproj index 8edd1490..ee1db282 100644 --- a/main/source/cl_dll/cl_dll.vcproj +++ b/main/source/cl_dll/cl_dll.vcproj @@ -1,5955 +1,5955 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/source/cl_dll/cl_dll.vcxproj b/main/source/cl_dll/cl_dll.vcxproj index 8c33951d..c5cf7613 100644 --- a/main/source/cl_dll/cl_dll.vcxproj +++ b/main/source/cl_dll/cl_dll.vcxproj @@ -1,933 +1,936 @@ - - - - - Playtest - Win32 - - - - cl_dll.dll - cl_dll - - - - - - - - DynamicLibrary - false - false - MultiByte - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - .\release - $(Configuration)\ - $(TargetPath)%3b*.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat - false - client - - - - MaxSpeed - OnlyExplicitInline - false - $(SolutionDir);$(SolutionDir)\particles;$(SolutionDir)\includes\lpng1251;$(SolutionDir)\includes\zlib-1.2.8;$(SolutionDir)\includes\fmod\inc;$(SolutionDir)\includes\vgui\include;../public;../common;../external;../pm_shared;../game_shared;../mod;../util;../ui;../engine;../cl_dll;../dlls - NDEBUG;WIN32;_WINDOWS;AVH_CLIENT;USE_OLDAUTH - true - true - - - - - $(IntDir) - $(IntDir) - $(IntDir) - Level2 - false - true - Default - true - true - 4996 - true - MultiThreaded - Neither - - - particles.lib;vgui.lib;zlib.lib;libpng.lib;wsock32.lib;sdl2.lib;%(AdditionalDependencies) - true - $(SolutionDir)\particles\WIN32_Release;$(SolutionDir)\includes\lpng1251;$(SolutionDir)\includes\zlib-1.2.8;$(SolutionDir)\includes\vgui\lib\win32_vc6;$(SolutionDir)\lib\public;%(AdditionalLibraryDirectories) - - - - - - - Windows - $(IntDir)cl_dll.lib - MachineX86 - false - false - - - /NODEFAULTLIB:LIBCMT %(AdditionalOptions) - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Release/cl_dll.tlb - - - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - true - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - $(IntDir)%(Filename)1.obj - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - MaxSpeed - %(AdditionalIncludeDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Playtest + Win32 + + + + cl_dll.dll + cl_dll + + + + + {665C1DAF-9248-E06F-4E5C-A664BAFDE9D8} + 8.1 + + + + DynamicLibrary + false + false + MultiByte + v100 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\release + $(Configuration)\ + $(TargetPath)%3b*.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat + false + client + + + + MaxSpeed + OnlyExplicitInline + false + $(SolutionDir);$(SolutionDir)\particles;$(SolutionDir)\includes\lpng1251;$(SolutionDir)\includes\zlib-1.2.8;$(SolutionDir)\includes\fmod\inc;$(SolutionDir)\includes\vgui\include;../public;../common;../external;../pm_shared;../game_shared;../mod;../util;../ui;../engine;../cl_dll;../dlls + NDEBUG;WIN32;_WINDOWS;AVH_CLIENT;USE_OLDAUTH + true + true + + + + + $(IntDir) + $(IntDir) + $(IntDir) + Level2 + false + true + Default + true + true + 4996 + true + MultiThreaded + Neither + + + particles.lib;vgui.lib;zlib.lib;libpng.lib;wsock32.lib;sdl2.lib;%(AdditionalDependencies) + true + $(SolutionDir)\particles\WIN32_Release;$(SolutionDir)\includes\lpng1251;$(SolutionDir)\includes\zlib-1.2.8;$(SolutionDir)\includes\vgui\lib\win32_vc6;$(SolutionDir)\lib\public;%(AdditionalLibraryDirectories) + + + + + + + Windows + $(IntDir)cl_dll.lib + MachineX86 + false + false + + + /NODEFAULTLIB:LIBCMT %(AdditionalOptions) + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/cl_dll.tlb + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + true + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + $(IntDir)%(Filename)1.obj + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + MaxSpeed + %(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main/source/cl_dll/cl_dll.vcxproj.filters b/main/source/cl_dll/cl_dll.vcxproj.filters index dadc783e..4bc1e2e5 100644 --- a/main/source/cl_dll/cl_dll.vcxproj.filters +++ b/main/source/cl_dll/cl_dll.vcxproj.filters @@ -1,1047 +1,1047 @@ - - - - - {8d8b30a6-88bc-40e0-a19e-4b6793dd4988} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90 - - - {fb6cdf05-b5ad-4bd2-bbbb-93bb6db841c9} - *.CPP - - - {5fee03ab-1230-4f5c-8522-aeb53d4dee1f} - - - {c75d025a-22cc-477c-b3a6-c2fb5fa71216} - h;hpp;hxx;hm;inl;fi;fd - - - {1203e87c-5c0d-49d2-a172-f6f1220ace14} - - - {c54cbc98-aca6-4fc8-8a66-d0e55b966dcc} - - - {5e6638f7-791c-4391-ae1a-963a434292ca} - - - {0831440c-bcbe-4824-a97a-25473dcc0340} - - - {ad5bbb2c-1092-4ba3-ab5b-fdfa0a33f1f5} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files\hl - - - Source Files\hl - - - Source Files\hl - - - Source Files\hl - - - Source Files\hl - - - Source Files\hl - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - textrep - - - textrep - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Source Files\client-side weapons - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - ui - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - textrep - - - textrep - - - textrep - - - textrep - - - - - + + + + + {8d8b30a6-88bc-40e0-a19e-4b6793dd4988} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90 + + + {fb6cdf05-b5ad-4bd2-bbbb-93bb6db841c9} + *.CPP + + + {5fee03ab-1230-4f5c-8522-aeb53d4dee1f} + + + {c75d025a-22cc-477c-b3a6-c2fb5fa71216} + h;hpp;hxx;hm;inl;fi;fd + + + {1203e87c-5c0d-49d2-a172-f6f1220ace14} + + + {c54cbc98-aca6-4fc8-8a66-d0e55b966dcc} + + + {5e6638f7-791c-4391-ae1a-963a434292ca} + + + {0831440c-bcbe-4824-a97a-25473dcc0340} + + + {ad5bbb2c-1092-4ba3-ab5b-fdfa0a33f1f5} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\hl + + + Source Files\hl + + + Source Files\hl + + + Source Files\hl + + + Source Files\hl + + + Source Files\hl + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + textrep + + + textrep + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Source Files\client-side weapons + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + ui + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + textrep + + + textrep + + + textrep + + + textrep + + + + + \ No newline at end of file diff --git a/main/source/cl_dll/cl_dll.vcxproj.user b/main/source/cl_dll/cl_dll.vcxproj.user index f392fbec..14cbff20 100644 --- a/main/source/cl_dll/cl_dll.vcxproj.user +++ b/main/source/cl_dll/cl_dll.vcxproj.user @@ -1,11 +1,11 @@ - - - - ..\..\..\..\..\..\..\Program Files %28x86%29\Steam\SteamApps\common\Half-Life\hl.exe - WindowsLocalDebugger - -allowdebug -dev -steam -game ns - ..\.. - false - Auto - + + + + ..\..\..\..\..\..\..\Program Files %28x86%29\Steam\SteamApps\common\Half-Life\hl.exe + WindowsLocalDebugger + -allowdebug -dev -steam -game ns + ..\.. + false + Auto + \ No newline at end of file diff --git a/main/source/cl_dll/cl_util.cpp b/main/source/cl_dll/cl_util.cpp index 0a77c5d6..78b1d3f9 100644 --- a/main/source/cl_dll/cl_util.cpp +++ b/main/source/cl_dll/cl_util.cpp @@ -1,64 +1,64 @@ -#include "hud.h" -#include "cl_dll/cl_util.h" - -float gTextR = 1; -float gTextG = 1; -float gTextB = 1; - -void DrawSetTextColor(float r, float g, float b ) -{ - gTextR = r; - gTextG = g; - gTextB = b; - gEngfuncs.pfnDrawSetTextColor(r, g, b); -} - -int DrawConsoleString( int x, int y, const char *string ) -{ - //return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); - - if (string[0] == 2) - { - ++string; - } - - int result = gHUD.GetSmallFont().DrawString(x, y, string, gTextR * 255, gTextG * 255, gTextB * 255, kRenderTransAdd); - DrawSetTextColor(1, 1, 1); - - return result; - -} - -void GetConsoleStringSize( const char *string, int *width, int *height ) -{ - - //gEngfuncs.pfnDrawConsoleStringLen( string, width, height ); - - if (string[0] == 2) - { - ++string; - } - - *width = gHUD.GetSmallFont().GetStringWidth(string); - *height = gHUD.GetSmallFont().GetStringHeight(); - -} - -int ConsoleStringLen( const char *string ) -{ - int _width, _height; - GetConsoleStringSize( string, &_width, &_height ); - return _width; -} - -void ConsolePrint( const char *string ) -{ - // TODO Max: implement this - gEngfuncs.pfnConsolePrint( string ); -} - -void CenterPrint( const char *string ) -{ - // TODO Max: implement this - gEngfuncs.pfnCenterPrint( string ); +#include "hud.h" +#include "cl_dll/cl_util.h" + +float gTextR = 1; +float gTextG = 1; +float gTextB = 1; + +void DrawSetTextColor(float r, float g, float b ) +{ + gTextR = r; + gTextG = g; + gTextB = b; + gEngfuncs.pfnDrawSetTextColor(r, g, b); +} + +int DrawConsoleString( int x, int y, const char *string ) +{ + //return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); + + if (string[0] == 2) + { + ++string; + } + + int result = gHUD.GetSmallFont().DrawString(x, y, string, gTextR * 255, gTextG * 255, gTextB * 255, kRenderTransAdd); + DrawSetTextColor(1, 1, 1); + + return result; + +} + +void GetConsoleStringSize( const char *string, int *width, int *height ) +{ + + //gEngfuncs.pfnDrawConsoleStringLen( string, width, height ); + + if (string[0] == 2) + { + ++string; + } + + *width = gHUD.GetSmallFont().GetStringWidth(string); + *height = gHUD.GetSmallFont().GetStringHeight(); + +} + +int ConsoleStringLen( const char *string ) +{ + int _width, _height; + GetConsoleStringSize( string, &_width, &_height ); + return _width; +} + +void ConsolePrint( const char *string ) +{ + // TODO Max: implement this + gEngfuncs.pfnConsolePrint( string ); +} + +void CenterPrint( const char *string ) +{ + // TODO Max: implement this + gEngfuncs.pfnCenterPrint( string ); } \ No newline at end of file diff --git a/main/source/cl_dll/cl_util.h b/main/source/cl_dll/cl_util.h index 7e8190f1..ad6fe1c9 100644 --- a/main/source/cl_dll/cl_util.h +++ b/main/source/cl_dll/cl_util.h @@ -1,150 +1,150 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cl_util.h -// -#ifndef CL_UTIL_H -#define CL_UTIL_H - -#include "cvardef.h" -#include "vector_util.h" -#include "VGUI_Panel.h" -#include "../types.h" -#include "cl_dll.h" -#include "hud.h" - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#include // for safe_sprintf() -#include // " -#include // " -// Macros to hook function calls into the HUD object -#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); - -#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ - { \ - return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ - } - - -#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); -#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ - { \ - gHUD.y.UserCmd_##x( ); \ - } - -inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } -inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } -inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } - -#define SPR_Load (*gEngfuncs.pfnSPR_Load) -//HSPRITE SPR_Load(const char* inSpriteName); -#define SPR_Set (*gEngfuncs.pfnSPR_Set) -#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) -#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) - -// SPR_Draw draws a the current sprite as solid -#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) -// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) -#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) -// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) -#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) - -// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. -#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) -// SPR_DisableScissor disables the clipping rect -#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) - -void CreatePickingRay( int mousex, int mousey, Vector& outVecPickingRay); - -// -#define FillRGBA (*gEngfuncs.pfnFillRGBA) - -int ScreenHeight(); -int ScreenWidth(); - -// Use this to set any co-ords in 640x480 space -#define XRES(x) ((int)(float(x) * ((float)ScreenWidth() / 640.0f) + 0.5f)) -#define YRES(y) ((int)(float(y) * ((float)ScreenHeight() / 480.0f) + 0.5f)) - -// use this to project world coordinates to screen coordinates -#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth()*0.5f ) -#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight()*0.5f ) - -#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) -#define ServerCmd (*gEngfuncs.pfnServerCmd) -#define ClientCmd (*gEngfuncs.pfnClientCmd) -#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) -#define AngleVectors (*gEngfuncs.pfnAngleVectors) - - -// Gets the height & width of a sprite, at the specified frame -inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } -inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } - -inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } -inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) -{ - return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); -} - -void DrawSetTextColor(float r, float g, float b ); - - -int DrawConsoleString( int x, int y, const char *string ); - -void GetConsoleStringSize( const char *string, int *width, int *height ); -int ConsoleStringLen( const char *string ); - -void ConsolePrint( const char *string ); -void CenterPrint( const char *string ); - -// returns the players name of entity no. -#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) - -// sound functions -//inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } -//inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) - -void ScaleColors( int &r, int &g, int &b, int a ); - -// disable 'possible loss of data converting float to int' warning message -#pragma warning( disable: 4244 ) -// disable 'truncation from 'const double' to 'float' warning message -#pragma warning( disable: 4305 ) - -inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ -{\ - r = (ulRGB & 0xFF0000) >>16;\ - g = (ulRGB & 0xFF00) >> 8;\ - b = ulRGB & 0xFF;\ -} - -void FillRGBAClipped(vgui::Panel* inPanel, int inStartX, int inStartY, int inWidth, int inHeight, int r, int g, int b, int a); - -HSPRITE LoadSprite(const char *pszName); - -//bool LocalizeString(const char* inMessage, char* outBuffer, int inBufferSize); -bool LocalizeString(const char* inMessage, string& outputString); - - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cl_util.h +// +#ifndef CL_UTIL_H +#define CL_UTIL_H + +#include "cvardef.h" +#include "vector_util.h" +#include "VGUI_Panel.h" +#include "../types.h" +#include "cl_dll.h" +#include "hud.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#include // for safe_sprintf() +#include // " +#include // " +// Macros to hook function calls into the HUD object +#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); + +#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ + { \ + return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ + } + + +#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); +#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + gHUD.y.UserCmd_##x( ); \ + } + +inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } +inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } +inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } + +#define SPR_Load (*gEngfuncs.pfnSPR_Load) +//HSPRITE SPR_Load(const char* inSpriteName); +#define SPR_Set (*gEngfuncs.pfnSPR_Set) +#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) +#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) + +// SPR_Draw draws a the current sprite as solid +#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) +// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) +#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) +// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) +#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) + +// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. +#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) +// SPR_DisableScissor disables the clipping rect +#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) + +void CreatePickingRay( int mousex, int mousey, Vector& outVecPickingRay); + +// +#define FillRGBA (*gEngfuncs.pfnFillRGBA) + +int ScreenHeight(); +int ScreenWidth(); + +// Use this to set any co-ords in 640x480 space +#define XRES(x) ((int)(float(x) * ((float)ScreenWidth() / 640.0f) + 0.5f)) +#define YRES(y) ((int)(float(y) * ((float)ScreenHeight() / 480.0f) + 0.5f)) + +// use this to project world coordinates to screen coordinates +#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth()*0.5f ) +#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight()*0.5f ) + +#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) +#define ServerCmd (*gEngfuncs.pfnServerCmd) +#define ClientCmd (*gEngfuncs.pfnClientCmd) +#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) +#define AngleVectors (*gEngfuncs.pfnAngleVectors) + + +// Gets the height & width of a sprite, at the specified frame +inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } +inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } + +inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } +inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) +{ + return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); +} + +void DrawSetTextColor(float r, float g, float b ); + + +int DrawConsoleString( int x, int y, const char *string ); + +void GetConsoleStringSize( const char *string, int *width, int *height ); +int ConsoleStringLen( const char *string ); + +void ConsolePrint( const char *string ); +void CenterPrint( const char *string ); + +// returns the players name of entity no. +#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) + +// sound functions +//inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } +//inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) + +void ScaleColors( int &r, int &g, int &b, int a ); + +// disable 'possible loss of data converting float to int' warning message +#pragma warning( disable: 4244 ) +// disable 'truncation from 'const double' to 'float' warning message +#pragma warning( disable: 4305 ) + +inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ +{\ + r = (ulRGB & 0xFF0000) >>16;\ + g = (ulRGB & 0xFF00) >> 8;\ + b = ulRGB & 0xFF;\ +} + +void FillRGBAClipped(vgui::Panel* inPanel, int inStartX, int inStartY, int inWidth, int inHeight, int r, int g, int b, int a); + +HSPRITE LoadSprite(const char *pszName); + +//bool LocalizeString(const char* inMessage, char* outBuffer, int inBufferSize); +bool LocalizeString(const char* inMessage, string& outputString); + + +#endif diff --git a/main/source/cl_dll/cl_util.h~ b/main/source/cl_dll/cl_util.h~ deleted file mode 100644 index 21d0232b..00000000 --- a/main/source/cl_dll/cl_util.h~ +++ /dev/null @@ -1,150 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cl_util.h -// -#ifndef CL_UTIL_H -#define CL_UTIL_H - -#include "cvardef.h" -#include "vector_util.h" -#include "VGUI_Panel.h" -#include "types.h" -#include "cl_dll.h" -#include "hud.h" - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#include // for safe_sprintf() -#include // " -#include // " -// Macros to hook function calls into the HUD object -#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); - -#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ - { \ - return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ - } - - -#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); -#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ - { \ - gHUD.y.UserCmd_##x( ); \ - } - -inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } -inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } -inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } - -#define SPR_Load (*gEngfuncs.pfnSPR_Load) -//HSPRITE SPR_Load(const char* inSpriteName); -#define SPR_Set (*gEngfuncs.pfnSPR_Set) -#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) -#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) - -// SPR_Draw draws a the current sprite as solid -#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) -// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) -#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) -// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) -#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) - -// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. -#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) -// SPR_DisableScissor disables the clipping rect -#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) - -void CreatePickingRay( int mousex, int mousey, Vector& outVecPickingRay); - -// -#define FillRGBA (*gEngfuncs.pfnFillRGBA) - -int ScreenHeight(); -int ScreenWidth(); - -// Use this to set any co-ords in 640x480 space -#define XRES(x) ((int)(float(x) * ((float)ScreenWidth() / 640.0f) + 0.5f)) -#define YRES(y) ((int)(float(y) * ((float)ScreenHeight() / 480.0f) + 0.5f)) - -// use this to project world coordinates to screen coordinates -#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth()*0.5f ) -#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight()*0.5f ) - -#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) -#define ServerCmd (*gEngfuncs.pfnServerCmd) -#define ClientCmd (*gEngfuncs.pfnClientCmd) -#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) -#define AngleVectors (*gEngfuncs.pfnAngleVectors) - - -// Gets the height & width of a sprite, at the specified frame -inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } -inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } - -inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } -inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) -{ - return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); -} - -void DrawSetTextColor(float r, float g, float b ); - - -int DrawConsoleString( int x, int y, const char *string ); - -void GetConsoleStringSize( const char *string, int *width, int *height ); -int ConsoleStringLen( const char *string ); - -void ConsolePrint( const char *string ); -void CenterPrint( const char *string ); - -// returns the players name of entity no. -#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) - -// sound functions -//inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } -//inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) - -void ScaleColors( int &r, int &g, int &b, int a ); - -// disable 'possible loss of data converting float to int' warning message -#pragma warning( disable: 4244 ) -// disable 'truncation from 'const double' to 'float' warning message -#pragma warning( disable: 4305 ) - -inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ -{\ - r = (ulRGB & 0xFF0000) >>16;\ - g = (ulRGB & 0xFF00) >> 8;\ - b = ulRGB & 0xFF;\ -} - -void FillRGBAClipped(vgui::Panel* inPanel, int inStartX, int inStartY, int inWidth, int inHeight, int r, int g, int b, int a); - -HSPRITE LoadSprite(const char *pszName); - -//bool LocalizeString(const char* inMessage, char* outBuffer, int inBufferSize); -bool LocalizeString(const char* inMessage, string& outputString); - - -#endif diff --git a/main/source/cl_dll/com_weapons.cpp b/main/source/cl_dll/com_weapons.cpp index 4048ab97..d801e341 100644 --- a/main/source/cl_dll/com_weapons.cpp +++ b/main/source/cl_dll/com_weapons.cpp @@ -1,278 +1,278 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// Com_Weapons.cpp -// Shared weapons common/shared functions -#include -#include "hud.h" -#include "cl_util.h" -#include "com_weapons.h" - -#include "common/const.h" -#include "common/entity_state.h" -#include "common/r_efx.h" - -// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing -// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be -// updating state info, but not firing events -int g_runfuncs = 0; - -// During our weapon prediction processing, we'll need to reference some data that is part of -// the final state passed into the postthink functionality. We'll set this pointer and then -// reset it to NULL as appropriate -struct local_state_s *g_finalstate = NULL; - -/* -==================== -COM_Log - -Log debug messages to file ( appends ) -==================== -*/ -void COM_Log( char *pszFile, char *fmt, ...) -{ - va_list argptr; - char string[1024]; - FILE *fp; - char *pfilename; - - if ( !pszFile ) - { - pfilename = "c:\\hllog.txt"; - } - else - { - pfilename = pszFile; - } - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// Com_Weapons.cpp +// Shared weapons common/shared functions +#include +#include "hud.h" +#include "cl_util.h" +#include "com_weapons.h" + +#include "common/const.h" +#include "common/entity_state.h" +#include "common/r_efx.h" + +// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing +// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be +// updating state info, but not firing events +int g_runfuncs = 0; + +// During our weapon prediction processing, we'll need to reference some data that is part of +// the final state passed into the postthink functionality. We'll set this pointer and then +// reset it to NULL as appropriate +struct local_state_s *g_finalstate = NULL; + +/* +==================== +COM_Log + +Log debug messages to file ( appends ) +==================== +*/ +void COM_Log( char *pszFile, char *fmt, ...) +{ + va_list argptr; + char string[1024]; + FILE *fp; + char *pfilename; + + if ( !pszFile ) + { + pfilename = "c:\\hllog.txt"; + } + else + { + pfilename = pszFile; + } + va_start (argptr,fmt); vsprintf (string, fmt,argptr); - va_end (argptr); - - fp = fopen( pfilename, "a+t"); - if (fp) - { - fprintf(fp, "%s", string); - fclose(fp); - } -} - -// remember the current animation for the view model, in case we get out of sync with -// server. -static int g_currentanim; - -/* -===================== -HUD_SendWeaponAnim - -Change weapon model animation -===================== -*/ -void HUD_SendWeaponAnim( int iAnim, int body, int force ) -{ - if(iAnim >= 0) - { - // Don't actually change it. - if ( !g_runfuncs && !force ) - return; - - g_currentanim = iAnim; - - // Tell animation system new info - gEngfuncs.pfnWeaponAnim( iAnim, body ); - } -} - -/* -===================== -HUD_GetWeaponAnim - -Retrieve current predicted weapon animation -===================== -*/ -int HUD_GetWeaponAnim( void ) -{ - return g_currentanim; -} - -/* -===================== -HUD_PlaySound - -Play a sound, if we are seeing this command for the first time -===================== -*/ -void HUD_PlaySound( char *sound, float volume ) -{ - if ( !g_runfuncs || !g_finalstate ) - return; - - gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); -} - -/* -===================== -HUD_PlaybackEvent - -Directly queue up an event on the client -===================== -*/ -void HUD_PlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, - float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) -{ - vec3_t org; - vec3_t ang; - - if ( !g_runfuncs || !g_finalstate ) - return; - - // Weapon prediction events are assumed to occur at the player's origin - org = g_finalstate->playerstate.origin; - ang = v_angles; - gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); -} - -/* -===================== -HUD_SetMaxSpeed - -===================== -*/ -void HUD_SetMaxSpeed( const edict_t *ed, float speed ) -{ -} - - -/* -===================== -UTIL_WeaponTimeBase - -Always 0.0 on client, even if not predicting weapons ( won't get called - in that case ) -===================== -*/ -float UTIL_WeaponTimeBase( void ) -{ - return 0.0; -} - -static unsigned int glSeed = 0; - -unsigned int seed_table[ 256 ] = -{ - 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, - 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, - 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, - 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, - 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, - 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, - 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, - 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, - 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, - 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, - 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, - 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, - 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, - 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, - 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, - 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 -}; - -unsigned int U_Random( void ) -{ - glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - - return ( ++glSeed & 0x0fffffff ); -} - -void U_Srand( unsigned int seed ) -{ - glSeed = seed_table[ seed & 0xff ]; -} - -/* -===================== -UTIL_SharedRandomLong -===================== -*/ -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) -{ - unsigned int range; - - U_Srand( (int)seed + low + high ); - - range = high - low + 1; - if ( !(range - 1) ) - { - return low; - } - else - { - int offset; - int rnum; - - rnum = U_Random(); - - offset = rnum % range; - - return (low + offset); - } -} - -/* -===================== -UTIL_SharedRandomFloat -===================== -*/ -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) -{ - - U_Srand( (int)seed + *(int *)&low + *(int *)&high ); - - U_Random(); - U_Random(); - - float range = high - low; - if ( !range ) - { - return low; - } - else - { - int tensixrand; - float offset; - - tensixrand = U_Random() & 65535; - - offset = (float)tensixrand / 65536.0; - - return (low + offset * range ); - } -} - -/* -====================== -stub_* - -stub functions for such things as precaching. So we don't have to modify weapons code that - is compiled into both game and client .dlls. -====================== -*/ -int stub_PrecacheModel ( char* s ) { return 0; } -int stub_PrecacheSound ( char* s ) { return 0; } -unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } + va_end (argptr); + + fp = fopen( pfilename, "a+t"); + if (fp) + { + fprintf(fp, "%s", string); + fclose(fp); + } +} + +// remember the current animation for the view model, in case we get out of sync with +// server. +static int g_currentanim; + +/* +===================== +HUD_SendWeaponAnim + +Change weapon model animation +===================== +*/ +void HUD_SendWeaponAnim( int iAnim, int body, int force ) +{ + if(iAnim >= 0) + { + // Don't actually change it. + if ( !g_runfuncs && !force ) + return; + + g_currentanim = iAnim; + + // Tell animation system new info + gEngfuncs.pfnWeaponAnim( iAnim, body ); + } +} + +/* +===================== +HUD_GetWeaponAnim + +Retrieve current predicted weapon animation +===================== +*/ +int HUD_GetWeaponAnim( void ) +{ + return g_currentanim; +} + +/* +===================== +HUD_PlaySound + +Play a sound, if we are seeing this command for the first time +===================== +*/ +void HUD_PlaySound( char *sound, float volume ) +{ + if ( !g_runfuncs || !g_finalstate ) + return; + + gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); +} + +/* +===================== +HUD_PlaybackEvent + +Directly queue up an event on the client +===================== +*/ +void HUD_PlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, + float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) +{ + vec3_t org; + vec3_t ang; + + if ( !g_runfuncs || !g_finalstate ) + return; + + // Weapon prediction events are assumed to occur at the player's origin + org = g_finalstate->playerstate.origin; + ang = v_angles; + gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); +} + +/* +===================== +HUD_SetMaxSpeed + +===================== +*/ +void HUD_SetMaxSpeed( const edict_t *ed, float speed ) +{ +} + + +/* +===================== +UTIL_WeaponTimeBase + +Always 0.0 on client, even if not predicting weapons ( won't get called + in that case ) +===================== +*/ +float UTIL_WeaponTimeBase( void ) +{ + return 0.0; +} + +static unsigned int glSeed = 0; + +unsigned int seed_table[ 256 ] = +{ + 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, + 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, + 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, + 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, + 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, + 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, + 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, + 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, + 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, + 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, + 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, + 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, + 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, + 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, + 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, + 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 +}; + +unsigned int U_Random( void ) +{ + glSeed *= 69069; + glSeed += seed_table[ glSeed & 0xff ]; + + return ( ++glSeed & 0x0fffffff ); +} + +void U_Srand( unsigned int seed ) +{ + glSeed = seed_table[ seed & 0xff ]; +} + +/* +===================== +UTIL_SharedRandomLong +===================== +*/ +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) +{ + unsigned int range; + + U_Srand( (int)seed + low + high ); + + range = high - low + 1; + if ( !(range - 1) ) + { + return low; + } + else + { + int offset; + int rnum; + + rnum = U_Random(); + + offset = rnum % range; + + return (low + offset); + } +} + +/* +===================== +UTIL_SharedRandomFloat +===================== +*/ +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) +{ + + U_Srand( (int)seed + *(int *)&low + *(int *)&high ); + + U_Random(); + U_Random(); + + float range = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +/* +====================== +stub_* + +stub functions for such things as precaching. So we don't have to modify weapons code that + is compiled into both game and client .dlls. +====================== +*/ +int stub_PrecacheModel ( char* s ) { return 0; } +int stub_PrecacheSound ( char* s ) { return 0; } +unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } const char *stub_NameForFunction ( uint32 function ) { return "func"; } -void stub_SetModel ( edict_t *e, const char *m ) {} +void stub_SetModel ( edict_t *e, const char *m ) {} diff --git a/main/source/cl_dll/com_weapons.h b/main/source/cl_dll/com_weapons.h index e7eafb15..797a4602 100644 --- a/main/source/cl_dll/com_weapons.h +++ b/main/source/cl_dll/com_weapons.h @@ -1,49 +1,49 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// com_weapons.h -// Shared weapons common function prototypes -#if !defined( COM_WEAPONSH ) -#define COM_WEAPONSH -#ifdef _WIN32 -#pragma once -#endif - -#include "hud_iface.h" - -// TODO: Remove this? Insert this? -//extern "C" -//{ -// void DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); -//} - -void COM_Log( char *pszFile, char *fmt, ...); -int CL_IsDead( void ); - -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); - -int HUD_GetWeaponAnim( void ); -void HUD_SendWeaponAnim( int iAnim, int body, int force ); -void HUD_PlaySound( char *sound, float volume ); -void HUD_PlaybackEvent( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); -void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); -int stub_PrecacheModel( char* s ); -int stub_PrecacheSound( char* s ); -unsigned short stub_PrecacheEvent( int type, const char *s ); -const char *stub_NameForFunction ( uint32 function ); -void stub_SetModel ( struct edict_s *e, const char *m ); - - -extern cvar_t *cl_lw; - -extern int g_runfuncs; -extern vec3_t v_angles; -extern float g_lastFOV; -extern struct local_state_s *g_finalstate; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// com_weapons.h +// Shared weapons common function prototypes +#if !defined( COM_WEAPONSH ) +#define COM_WEAPONSH +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_iface.h" + +// TODO: Remove this? Insert this? +//extern "C" +//{ +// void DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +//} + +void COM_Log( char *pszFile, char *fmt, ...); +int CL_IsDead( void ); + +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); + +int HUD_GetWeaponAnim( void ); +void HUD_SendWeaponAnim( int iAnim, int body, int force ); +void HUD_PlaySound( char *sound, float volume ); +void HUD_PlaybackEvent( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); +void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); +int stub_PrecacheModel( char* s ); +int stub_PrecacheSound( char* s ); +unsigned short stub_PrecacheEvent( int type, const char *s ); +const char *stub_NameForFunction ( uint32 function ); +void stub_SetModel ( struct edict_s *e, const char *m ); + + +extern cvar_t *cl_lw; + +extern int g_runfuncs; +extern vec3_t v_angles; +extern float g_lastFOV; +extern struct local_state_s *g_finalstate; + #endif \ No newline at end of file diff --git a/main/source/cl_dll/death.cpp b/main/source/cl_dll/death.cpp index 02bba8f7..cf08a57c 100644 --- a/main/source/cl_dll/death.cpp +++ b/main/source/cl_dll/death.cpp @@ -1,322 +1,322 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// death notice -// -#include "hud.h" -#include "cl_util.h" - -#include -#include - -#include "vgui_TeamFortressViewport.h" -#include "mod/AvHHudConstants.h" -#include "pm_shared/pm_shared.h" -#include "mod/AvHNetworkMessages.h" - -DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); - -struct DeathNoticeItem { - char szKiller[MAX_PLAYER_NAME_LENGTH*2]; - char szVictim[MAX_PLAYER_NAME_LENGTH*2]; - int iId; // the index number of the associated sprite - int iSuicide; - int iTeamKill; - int iNonPlayerKill; - float flDisplayTime; - float *KillerColor; - float *VictimColor; -}; - -#define MAX_DEATHNOTICES 4 -static int DEATHNOTICE_DISPLAY_TIME = 6; - -#define DEATHNOTICE_TOP 20 - -DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; - -// Changing these? Change them in vgui_TeamFortressViewport::iTeamColors as well -float g_ColorWhite[3] = { 1.0, 1.0f, 1.0 }; -float g_ColorBlue[3] = { .49, .65, .82 }; -float g_ColorOrange[3] = { 1.0, .66, 0.0 }; -float g_ColorGreen[3] = { .56, .84, .55 }; -float g_ColorRed[3] = { .78, .35, .27 }; - -float g_ColorYellow[3] = { 1.0, .96, .39 }; - -float* GetClientColor(int clientIndex) -{ - int theTeamNumber = g_PlayerExtraInfo[clientIndex].teamnumber; - return kFTeamColors[theTeamNumber]; -} - -int CHudDeathNotice :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( DeathMsg ); - - CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); - - return 1; -} - - -void CHudDeathNotice :: InitHUDData( void ) -{ - memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); -} - - -int CHudDeathNotice :: VidInit( void ) -{ - m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); - - return 1; -} - -int CHudDeathNotice :: Draw( float flTime ) -{ - int x, y, r, g, b; - - for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) - { - if ( rgDeathNoticeList[i].iId == 0 ) - break; // we've gone through them all - - if ( rgDeathNoticeList[i].flDisplayTime < flTime ) - { - // display time has expired, remove the current item from the list - memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); - i--; // continue on the next item; stop the counter getting incremented - continue; - } - - rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); - - // Only draw if the viewport will let me - if ( gViewPort && gViewPort->AllowedToPrintText() ) - { - // Draw the death notice - //y = DEATHNOTICE_TOP + (20 * i); //!!! - int theBaseY = DEATHNOTICE_TOP; - - // Bring down death messages when in top down or when we're drawing letter box - if(gHUD.m_Spectator.IsInOverviewMode()) - { - // No HUD elements to compensate for - } - else if(gHUD.GetInTopDownMode()) - { - theBaseY = .10*ScreenHeight(); - } - else if(gHUD.GetIsMarine()) - { - theBaseY = .26*ScreenHeight(); - } - else if(gHUD.GetIsAlien()) - { - theBaseY = kHiveNormScreenY*ScreenHeight() + (kMaxHives-1)*((kHiveNormScreenHeight + kHiveNormScreenVerticalSpacing)*ScreenHeight()); - } - - // Lower death messages more when spectating so they don't overlap (due to letterbox) - if(g_iUser1 != OBS_NONE) - { - theBaseY += .06*ScreenHeight(); - } - - y = theBaseY + (20 * i); //!!! - - int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; - x = ScreenWidth() - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - if ( !rgDeathNoticeList[i].iSuicide ) - { - x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); - - // Draw killers name - if ( rgDeathNoticeList[i].KillerColor ) - DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); - x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); - } - - r = 255; g = 80; b = 0; - if ( rgDeathNoticeList[i].iTeamKill ) - { - r = 10; g = 240; b = 10; // display it in sickly green - } - - // Draw death weapon - SPR_Set( gHUD.GetSprite(id), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); - - x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - // Draw victims name (if it was a player that was killed) - if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) - { - if ( rgDeathNoticeList[i].VictimColor ) - DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); - x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); - } - } - } - - return 1; -} - -// This message handler may be better off elsewhere -int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) -{ - m_iFlags |= HUD_ACTIVE; - - int killer, victim; - string killed_with; - NetMsg_DeathMsg( pbuf, iSize, killer, victim, killed_with ); - - if (gViewPort) - gViewPort->DeathMsg( killer, victim ); - - gHUD.m_Spectator.DeathMessage(victim); - int i; - for ( i = 0; i < MAX_DEATHNOTICES; i++ ) - { - if ( rgDeathNoticeList[i].iId == 0 ) - break; - } - if ( i == MAX_DEATHNOTICES ) - { // move the rest of the list forward to make room for this item - memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); - i = MAX_DEATHNOTICES - 1; - } - - if (gViewPort) - gViewPort->GetAllPlayersInfo(); - - // Get the Killer's name - char *killer_name = g_PlayerInfoList[ killer ].name; - if ( !killer_name ) - { - killer_name = ""; - rgDeathNoticeList[i].szKiller[0] = 0; - } - else - { - rgDeathNoticeList[i].KillerColor = GetClientColor( killer); - strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); - rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; - } - - // Get the Victim's name - char *victim_name = NULL; - // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) - if ( ((char)victim) != -1 ) - victim_name = g_PlayerInfoList[ victim ].name; - if ( !victim_name ) - { - victim_name = ""; - rgDeathNoticeList[i].szVictim[0] = 0; - } - else - { - rgDeathNoticeList[i].VictimColor = GetClientColor(victim); - strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); - rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; - } - - // Is it a non-player object kill? - if ( ((char)victim) == -1 ) - { - rgDeathNoticeList[i].iNonPlayerKill = TRUE; - - // Store the object's name in the Victim slot (skip the d_ bit) - strcpy( rgDeathNoticeList[i].szVictim, killed_with.c_str()+2 ); - } - else - { - if ( killer == victim || killer == 0 ) - rgDeathNoticeList[i].iSuicide = TRUE; - - if ( !strcmp( killed_with.c_str(), "d_teammate" ) ) - rgDeathNoticeList[i].iTeamKill = TRUE; - } - - // Find the sprite in the list - char killed_with_spritename[32]; - sprintf(killed_with_spritename, "d_%s", killed_with.c_str()); - int spr = gHUD.GetSpriteIndex( killed_with_spritename ); - - rgDeathNoticeList[i].iId = spr; - - DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); - rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; - - if (rgDeathNoticeList[i].iNonPlayerKill) - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed a " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - ConsolePrint( "\n" ); - } - else - { - // record the death notice in the console - if ( rgDeathNoticeList[i].iSuicide ) - { - ConsolePrint( rgDeathNoticeList[i].szVictim ); - - if ( !strcmp( killed_with.c_str(), "world" ) ) - { - ConsolePrint( " died" ); - } - else - { - ConsolePrint( " killed self" ); - } - } - else if ( rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed his teammate " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - } - else - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - } - - if ( !killed_with.empty() && killed_with != "world" && !rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( " with " ); - - // replace the code names with the 'real' names - if ( killed_with == "d_egon" ) - killed_with = "d_gluon gun"; - if ( killed_with == "gauss" ) - killed_with = "d_tau cannon"; - ConsolePrint( killed_with.c_str()); // skip over the "d_" part - } - - ConsolePrint( "\n" ); - } - - return 1; -} - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// death notice +// +#include "hud.h" +#include "cl_util.h" + +#include +#include + +#include "vgui_TeamFortressViewport.h" +#include "mod/AvHHudConstants.h" +#include "pm_shared/pm_shared.h" +#include "mod/AvHNetworkMessages.h" + +DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); + +struct DeathNoticeItem { + char szKiller[MAX_PLAYER_NAME_LENGTH*2]; + char szVictim[MAX_PLAYER_NAME_LENGTH*2]; + int iId; // the index number of the associated sprite + int iSuicide; + int iTeamKill; + int iNonPlayerKill; + float flDisplayTime; + float *KillerColor; + float *VictimColor; +}; + +#define MAX_DEATHNOTICES 4 +static int DEATHNOTICE_DISPLAY_TIME = 6; + +#define DEATHNOTICE_TOP 20 + +DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; + +// Changing these? Change them in vgui_TeamFortressViewport::iTeamColors as well +float g_ColorWhite[3] = { 1.0, 1.0f, 1.0 }; +float g_ColorBlue[3] = { .49, .65, .82 }; +float g_ColorOrange[3] = { 1.0, .66, 0.0 }; +float g_ColorGreen[3] = { .56, .84, .55 }; +float g_ColorRed[3] = { .78, .35, .27 }; + +float g_ColorYellow[3] = { 1.0, .96, .39 }; + +float* GetClientColor(int clientIndex) +{ + int theTeamNumber = g_PlayerExtraInfo[clientIndex].teamnumber; + return kFTeamColors[theTeamNumber]; +} + +int CHudDeathNotice :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( DeathMsg ); + + CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); + + return 1; +} + + +void CHudDeathNotice :: InitHUDData( void ) +{ + memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); +} + + +int CHudDeathNotice :: VidInit( void ) +{ + m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); + + return 1; +} + +int CHudDeathNotice :: Draw( float flTime ) +{ + int x, y, r, g, b; + + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; // we've gone through them all + + if ( rgDeathNoticeList[i].flDisplayTime < flTime ) + { + // display time has expired, remove the current item from the list + memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); + i--; // continue on the next item; stop the counter getting incremented + continue; + } + + rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); + + // Only draw if the viewport will let me + if ( gViewPort && gViewPort->AllowedToPrintText() ) + { + // Draw the death notice + //y = DEATHNOTICE_TOP + (20 * i); //!!! + int theBaseY = DEATHNOTICE_TOP; + + // Bring down death messages when in top down or when we're drawing letter box + if(gHUD.m_Spectator.IsInOverviewMode()) + { + // No HUD elements to compensate for + } + else if(gHUD.GetInTopDownMode()) + { + theBaseY = .10*ScreenHeight(); + } + else if(gHUD.GetIsMarine()) + { + theBaseY = .26*ScreenHeight(); + } + else if(gHUD.GetIsAlien()) + { + theBaseY = kHiveNormScreenY*ScreenHeight() + (kMaxHives-1)*((kHiveNormScreenHeight + kHiveNormScreenVerticalSpacing)*ScreenHeight()); + } + + // Lower death messages more when spectating so they don't overlap (due to letterbox) + if(g_iUser1 != OBS_NONE) + { + theBaseY += .06*ScreenHeight(); + } + + y = theBaseY + (20 * i); //!!! + + int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; + x = ScreenWidth() - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + if ( !rgDeathNoticeList[i].iSuicide ) + { + x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + + // Draw killers name + if ( rgDeathNoticeList[i].KillerColor ) + DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); + } + + r = 255; g = 80; b = 0; + if ( rgDeathNoticeList[i].iTeamKill ) + { + r = 10; g = 240; b = 10; // display it in sickly green + } + + // Draw death weapon + SPR_Set( gHUD.GetSprite(id), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); + + x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + // Draw victims name (if it was a player that was killed) + if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) + { + if ( rgDeathNoticeList[i].VictimColor ) + DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); + } + } + } + + return 1; +} + +// This message handler may be better off elsewhere +int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + int killer, victim; + string killed_with; + NetMsg_DeathMsg( pbuf, iSize, killer, victim, killed_with ); + + if (gViewPort) + gViewPort->DeathMsg( killer, victim ); + + gHUD.m_Spectator.DeathMessage(victim); + int i; + for ( i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; + } + if ( i == MAX_DEATHNOTICES ) + { // move the rest of the list forward to make room for this item + memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); + i = MAX_DEATHNOTICES - 1; + } + + if (gViewPort) + gViewPort->GetAllPlayersInfo(); + + // Get the Killer's name + char *killer_name = g_PlayerInfoList[ killer ].name; + if ( !killer_name ) + { + killer_name = ""; + rgDeathNoticeList[i].szKiller[0] = 0; + } + else + { + rgDeathNoticeList[i].KillerColor = GetClientColor( killer); + strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Get the Victim's name + char *victim_name = NULL; + // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) + if ( ((char)victim) != -1 ) + victim_name = g_PlayerInfoList[ victim ].name; + if ( !victim_name ) + { + victim_name = ""; + rgDeathNoticeList[i].szVictim[0] = 0; + } + else + { + rgDeathNoticeList[i].VictimColor = GetClientColor(victim); + strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Is it a non-player object kill? + if ( ((char)victim) == -1 ) + { + rgDeathNoticeList[i].iNonPlayerKill = TRUE; + + // Store the object's name in the Victim slot (skip the d_ bit) + strcpy( rgDeathNoticeList[i].szVictim, killed_with.c_str()+2 ); + } + else + { + if ( killer == victim || killer == 0 ) + rgDeathNoticeList[i].iSuicide = TRUE; + + if ( !strcmp( killed_with.c_str(), "d_teammate" ) ) + rgDeathNoticeList[i].iTeamKill = TRUE; + } + + // Find the sprite in the list + char killed_with_spritename[32]; + sprintf(killed_with_spritename, "d_%s", killed_with.c_str()); + int spr = gHUD.GetSpriteIndex( killed_with_spritename ); + + rgDeathNoticeList[i].iId = spr; + + DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); + rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; + + if (rgDeathNoticeList[i].iNonPlayerKill) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed a " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + ConsolePrint( "\n" ); + } + else + { + // record the death notice in the console + if ( rgDeathNoticeList[i].iSuicide ) + { + ConsolePrint( rgDeathNoticeList[i].szVictim ); + + if ( !strcmp( killed_with.c_str(), "world" ) ) + { + ConsolePrint( " died" ); + } + else + { + ConsolePrint( " killed self" ); + } + } + else if ( rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed his teammate " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + else + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + + if ( !killed_with.empty() && killed_with != "world" && !rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( " with " ); + + // replace the code names with the 'real' names + if ( killed_with == "d_egon" ) + killed_with = "d_gluon gun"; + if ( killed_with == "gauss" ) + killed_with = "d_tau cannon"; + ConsolePrint( killed_with.c_str()); // skip over the "d_" part + } + + ConsolePrint( "\n" ); + } + + return 1; +} + + + + diff --git a/main/source/cl_dll/demo.cpp b/main/source/cl_dll/demo.cpp index a8d73f59..53e3c3a9 100644 --- a/main/source/cl_dll/demo.cpp +++ b/main/source/cl_dll/demo.cpp @@ -1,274 +1,274 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "hud.h" -#include "cl_util.h" -#include "demo.h" -#include "common/demo_api.h" -#include - -#include "engine/APIProxy.h" -#include "Exports.h" -#include "mod/AvHParticleTemplateClient.h" -#include "cl_dll/view.h" - -extern AvHParticleTemplateListClient gParticleTemplateList; - -int g_demosniper = 0; -int g_demosniperdamage = 0; -float g_demosniperorg[3]; -float g_demosniperangles[3]; -float g_demozoom; -vec3_t gPlaybackViewOrigin; - -int ScorePanel_InitializeDemoPlayback(int inSize, unsigned char* inBuffer); -void ScorePanel_InitializeDemoRecording(); - -float gNormMouseX = 0; -float gNormMouseY = 0; - -// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. - -void Demo_WriteByte(int inType, unsigned char inByte) -{ - Demo_WriteBuffer(inType, sizeof(unsigned char), &inByte); -} - -void Demo_WriteVector(int inType, vec3_t inVector) -{ - float theFloatArray[3]; - - theFloatArray[0] = inVector.x; - theFloatArray[1] = inVector.y; - theFloatArray[2] = inVector.z; - - Demo_WriteBuffer(inType, 3*sizeof(float), (unsigned char*)theFloatArray); -} - -void Demo_WriteFloat(int inType, float inFloat) -{ - Demo_WriteBuffer(inType, sizeof(float), (unsigned char*)&inFloat); -} - -void Demo_WriteInt(int inType, int inInt) -{ - Demo_WriteBuffer(inType, sizeof(int), (unsigned char*)&inInt); -} - -/* -===================== -Demo_WriteBuffer - -Write some data to the demo stream -===================== -*/ -void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) -{ - int pos = 0; - unsigned char buf[ 32 * 1024 ]; - *( int * )&buf[pos] = type; - pos+=sizeof( int ); - - memcpy( &buf[pos], buffer, size ); - - // Write full buffer out - gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); -} - -/* -===================== -Demo_ReadBuffer - -Engine wants us to parse some data from the demo stream -===================== -*/ -void CL_DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) -{ -// RecClReadDemoBuffer(size, buffer); - - int type; - int i = 0; - bool theMouseVisibility = false; - int particleIndex=0; - - type = *( int * )buffer; - i += sizeof( int ); - switch ( type ) - { - case TYPE_SNIPERDOT: - g_demosniper = *(int * )&buffer[ i ]; - i += sizeof( int ); - - if ( g_demosniper ) - { - g_demosniperdamage = *( int * )&buffer[ i ]; - i += sizeof( int ); - - g_demosniperangles[ 0 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperangles[ 1 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperangles[ 2 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 0 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 1 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 2 ] = *(float *)&buffer[i]; - i += sizeof( float ); - } - break; - case TYPE_ZOOM: - g_demozoom = *(float * )&buffer[ i ]; - i += sizeof( float ); - break; - - case TYPE_BASESTATE: - i += gHUD.InitializeDemoPlayback(size, (unsigned char *)&buffer[i]); - break; - - case TYPE_MOUSEVIS: - //theMouseVisibility = *(unsigned char * )&buffer[ i ]; - //gHUD.GetManager().SetMouseVisibility(theMouseVisibility); - i += sizeof(unsigned char); - break; - - case TYPE_MOUSEX: - //gNormMouseX = *(float * )&buffer[ i ]; - i += sizeof( float ); - break; - - case TYPE_MOUSEY: - //gNormMouseY = *(float * )&buffer[ i ]; - i += sizeof( float ); - break; - - case TYPE_VIEWANGLES: - v_angles[0] = *(float * )&buffer[ i ]; - i += sizeof( float ); - - v_angles[1] = *(float * )&buffer[ i ]; - i += sizeof( float ); - - v_angles[2] = *(float * )&buffer[ i ]; - i += sizeof( float ); - break; - - case TYPE_VIEWORIGIN: - v_origin[0] = *(float * )&buffer[ i ]; - i += sizeof( float ); - - v_origin[1] = *(float * )&buffer[ i ]; - i += sizeof( float ); - - v_origin[2] = *(float * )&buffer[ i ]; - i += sizeof( float ); - break; - - case TYPE_PARTICLES: - i += gParticleTemplateList.InitializeDemoPlayback(size, (unsigned char*)&buffer[i], particleIndex++); - break; - - case TYPE_BASESTATE2: - i += gHUD.InitializeDemoPlayback2(size, (unsigned char *)&buffer[i]); - break; - - case TYPE_PLAYERINFO: - i += ScorePanel_InitializeDemoPlayback(size, (unsigned char *)&buffer[i]); - break; - - case TYPE_WEAPONINFO: - i += gHUD.InitializeWeaponInfoPlayback(size, (unsigned char *)&buffer[i]); - break; - - default: - gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); - break; - } -} - -// Returns num bytes needed to save/restore a string -int GetDataSize(const string& inString) -{ - // String length - int theSize = sizeof(int); - - // String data - theSize += (int)inString.length(); - - return theSize; -} - -void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable) -{ - memcpy(inBuffer, inData + inSizeVariable, inSizeToCopy); - inSizeVariable += inSizeToCopy; -} - -void LoadStringData(string& outString, const unsigned char* inData, int& inBytesRead) -{ - // Read in string length (could be 0) - int theStringLength = 0; - memcpy(&theStringLength, inData + inBytesRead, sizeof(int)); - inBytesRead += sizeof(int); - - // Read in string, if greater then 0 - if(theStringLength > 0) - { - char* theStringData = new char[theStringLength+1]; - memcpy(theStringData, inData + inBytesRead, theStringLength); - theStringData[theStringLength] = '\0'; - inBytesRead += theStringLength; - - outString = string(theStringData); - - delete [] theStringData; - theStringData = NULL; - } -} - -void LoadVectorData(float* outData, const unsigned char* inData, int& inBytesRead) -{ - int theSize = 3*sizeof(float); - memcpy(outData, inData + inBytesRead, theSize); - inBytesRead += theSize; -} - -void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable) -{ - memcpy(inBuffer + inSizeVariable, inData, inSizeToCopy); - inSizeVariable += inSizeToCopy; -} - -// Save out string, works for empty strings -void SaveStringData(unsigned char* inBuffer, const string& inString, int& inSizeVariable) -{ - int theStringLength = (int)inString.length(); - - // Write out string length - memcpy(inBuffer + inSizeVariable, &theStringLength, sizeof(int)); - inSizeVariable += sizeof(int); - - // Write out string data, if any - memcpy(inBuffer + inSizeVariable, inString.c_str(), theStringLength); - inSizeVariable += theStringLength; -} - -void SaveVectorData(unsigned char* inBuffer, float* inData, int& inSizeVariable) -{ - int theLength = 3*sizeof(float); - - memcpy(inBuffer + inSizeVariable, inData, theLength); - inSizeVariable += theLength; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "hud.h" +#include "cl_util.h" +#include "demo.h" +#include "common/demo_api.h" +#include + +#include "engine/APIProxy.h" +#include "Exports.h" +#include "mod/AvHParticleTemplateClient.h" +#include "cl_dll/view.h" + +extern AvHParticleTemplateListClient gParticleTemplateList; + +int g_demosniper = 0; +int g_demosniperdamage = 0; +float g_demosniperorg[3]; +float g_demosniperangles[3]; +float g_demozoom; +vec3_t gPlaybackViewOrigin; + +int ScorePanel_InitializeDemoPlayback(int inSize, unsigned char* inBuffer); +void ScorePanel_InitializeDemoRecording(); + +float gNormMouseX = 0; +float gNormMouseY = 0; + +// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. + +void Demo_WriteByte(int inType, unsigned char inByte) +{ + Demo_WriteBuffer(inType, sizeof(unsigned char), &inByte); +} + +void Demo_WriteVector(int inType, vec3_t inVector) +{ + float theFloatArray[3]; + + theFloatArray[0] = inVector.x; + theFloatArray[1] = inVector.y; + theFloatArray[2] = inVector.z; + + Demo_WriteBuffer(inType, 3*sizeof(float), (unsigned char*)theFloatArray); +} + +void Demo_WriteFloat(int inType, float inFloat) +{ + Demo_WriteBuffer(inType, sizeof(float), (unsigned char*)&inFloat); +} + +void Demo_WriteInt(int inType, int inInt) +{ + Demo_WriteBuffer(inType, sizeof(int), (unsigned char*)&inInt); +} + +/* +===================== +Demo_WriteBuffer + +Write some data to the demo stream +===================== +*/ +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) +{ + int pos = 0; + unsigned char buf[ 32 * 1024 ]; + *( int * )&buf[pos] = type; + pos+=sizeof( int ); + + memcpy( &buf[pos], buffer, size ); + + // Write full buffer out + gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); +} + +/* +===================== +Demo_ReadBuffer + +Engine wants us to parse some data from the demo stream +===================== +*/ +void CL_DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) +{ +// RecClReadDemoBuffer(size, buffer); + + int type; + int i = 0; + bool theMouseVisibility = false; + int particleIndex=0; + + type = *( int * )buffer; + i += sizeof( int ); + switch ( type ) + { + case TYPE_SNIPERDOT: + g_demosniper = *(int * )&buffer[ i ]; + i += sizeof( int ); + + if ( g_demosniper ) + { + g_demosniperdamage = *( int * )&buffer[ i ]; + i += sizeof( int ); + + g_demosniperangles[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + } + break; + case TYPE_ZOOM: + g_demozoom = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + + case TYPE_BASESTATE: + i += gHUD.InitializeDemoPlayback(size, (unsigned char *)&buffer[i]); + break; + + case TYPE_MOUSEVIS: + //theMouseVisibility = *(unsigned char * )&buffer[ i ]; + //gHUD.GetManager().SetMouseVisibility(theMouseVisibility); + i += sizeof(unsigned char); + break; + + case TYPE_MOUSEX: + //gNormMouseX = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + + case TYPE_MOUSEY: + //gNormMouseY = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + + case TYPE_VIEWANGLES: + v_angles[0] = *(float * )&buffer[ i ]; + i += sizeof( float ); + + v_angles[1] = *(float * )&buffer[ i ]; + i += sizeof( float ); + + v_angles[2] = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + + case TYPE_VIEWORIGIN: + v_origin[0] = *(float * )&buffer[ i ]; + i += sizeof( float ); + + v_origin[1] = *(float * )&buffer[ i ]; + i += sizeof( float ); + + v_origin[2] = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + + case TYPE_PARTICLES: + i += gParticleTemplateList.InitializeDemoPlayback(size, (unsigned char*)&buffer[i], particleIndex++); + break; + + case TYPE_BASESTATE2: + i += gHUD.InitializeDemoPlayback2(size, (unsigned char *)&buffer[i]); + break; + + case TYPE_PLAYERINFO: + i += ScorePanel_InitializeDemoPlayback(size, (unsigned char *)&buffer[i]); + break; + + case TYPE_WEAPONINFO: + i += gHUD.InitializeWeaponInfoPlayback(size, (unsigned char *)&buffer[i]); + break; + + default: + gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); + break; + } +} + +// Returns num bytes needed to save/restore a string +int GetDataSize(const string& inString) +{ + // String length + int theSize = sizeof(int); + + // String data + theSize += (int)inString.length(); + + return theSize; +} + +void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable) +{ + memcpy(inBuffer, inData + inSizeVariable, inSizeToCopy); + inSizeVariable += inSizeToCopy; +} + +void LoadStringData(string& outString, const unsigned char* inData, int& inBytesRead) +{ + // Read in string length (could be 0) + int theStringLength = 0; + memcpy(&theStringLength, inData + inBytesRead, sizeof(int)); + inBytesRead += sizeof(int); + + // Read in string, if greater then 0 + if(theStringLength > 0) + { + char* theStringData = new char[theStringLength+1]; + memcpy(theStringData, inData + inBytesRead, theStringLength); + theStringData[theStringLength] = '\0'; + inBytesRead += theStringLength; + + outString = string(theStringData); + + delete [] theStringData; + theStringData = NULL; + } +} + +void LoadVectorData(float* outData, const unsigned char* inData, int& inBytesRead) +{ + int theSize = 3*sizeof(float); + memcpy(outData, inData + inBytesRead, theSize); + inBytesRead += theSize; +} + +void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable) +{ + memcpy(inBuffer + inSizeVariable, inData, inSizeToCopy); + inSizeVariable += inSizeToCopy; +} + +// Save out string, works for empty strings +void SaveStringData(unsigned char* inBuffer, const string& inString, int& inSizeVariable) +{ + int theStringLength = (int)inString.length(); + + // Write out string length + memcpy(inBuffer + inSizeVariable, &theStringLength, sizeof(int)); + inSizeVariable += sizeof(int); + + // Write out string data, if any + memcpy(inBuffer + inSizeVariable, inString.c_str(), theStringLength); + inSizeVariable += theStringLength; +} + +void SaveVectorData(unsigned char* inBuffer, float* inData, int& inSizeVariable) +{ + int theLength = 3*sizeof(float); + + memcpy(inBuffer + inSizeVariable, inData, theLength); + inSizeVariable += theLength; +} diff --git a/main/source/cl_dll/demo.h b/main/source/cl_dll/demo.h index 6ca80533..e19fc732 100644 --- a/main/source/cl_dll/demo.h +++ b/main/source/cl_dll/demo.h @@ -1,56 +1,56 @@ -#if !defined( DEMOH ) -#define DEMOH -#pragma once - -// Types of demo messages we can write/parse -enum -{ - TYPE_SNIPERDOT = 0, - TYPE_ZOOM, - - TYPE_BASESTATE, - TYPE_MOUSEVIS, - TYPE_MOUSEX, - TYPE_MOUSEY, - TYPE_VIEWORIGIN, - TYPE_VIEWANGLES, - TYPE_PARTICLES, - - // More base state that wasn't originally saved (made a separate type for backwards-compatibility) - TYPE_BASESTATE2, - TYPE_PLAYERINFO, - TYPE_WEAPONINFO, -}; - -void Demo_WriteVector(int inType, vec3_t inVector); -void Demo_WriteByte(int inType, unsigned char inByte); -void Demo_WriteFloat(int inType, float inFloat); -void Demo_WriteInt(int inType, int inInt); -void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); -#define LOAD_DATA(x) LoadData(&x, inBuffer, sizeof(x), theBytesRead); -#define SAVE_DATA(x) SaveData(theCharArray, &x, sizeof(x), theCounter); - -int GetDataSize(const string& inString); - -void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable); -void LoadStringData(string& outString, const unsigned char* inData, int& inBytesRead); -void LoadVectorData(float* outData, const unsigned char* inData, int& inBytesRead); - -void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable); -void SaveStringData(unsigned char* inBuffer, const string& inString, int& inSizeVariable); -void SaveVectorData(unsigned char* inBuffer, float* inData, int& inSizeVariable); - -extern int g_demosniper; -extern int g_demosniperdamage; -extern float g_demosniperorg[3]; -extern float g_demosniperangles[3]; -extern float g_demozoom; - -extern float gNormMouseX; -extern float gNormMouseY; - -extern int gVisibleMouse; -extern vec3_t v_angles; -extern vec3_t v_origin; - +#if !defined( DEMOH ) +#define DEMOH +#pragma once + +// Types of demo messages we can write/parse +enum +{ + TYPE_SNIPERDOT = 0, + TYPE_ZOOM, + + TYPE_BASESTATE, + TYPE_MOUSEVIS, + TYPE_MOUSEX, + TYPE_MOUSEY, + TYPE_VIEWORIGIN, + TYPE_VIEWANGLES, + TYPE_PARTICLES, + + // More base state that wasn't originally saved (made a separate type for backwards-compatibility) + TYPE_BASESTATE2, + TYPE_PLAYERINFO, + TYPE_WEAPONINFO, +}; + +void Demo_WriteVector(int inType, vec3_t inVector); +void Demo_WriteByte(int inType, unsigned char inByte); +void Demo_WriteFloat(int inType, float inFloat); +void Demo_WriteInt(int inType, int inInt); +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); +#define LOAD_DATA(x) LoadData(&x, inBuffer, sizeof(x), theBytesRead); +#define SAVE_DATA(x) SaveData(theCharArray, &x, sizeof(x), theCounter); + +int GetDataSize(const string& inString); + +void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable); +void LoadStringData(string& outString, const unsigned char* inData, int& inBytesRead); +void LoadVectorData(float* outData, const unsigned char* inData, int& inBytesRead); + +void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable); +void SaveStringData(unsigned char* inBuffer, const string& inString, int& inSizeVariable); +void SaveVectorData(unsigned char* inBuffer, float* inData, int& inSizeVariable); + +extern int g_demosniper; +extern int g_demosniperdamage; +extern float g_demosniperorg[3]; +extern float g_demosniperangles[3]; +extern float g_demozoom; + +extern float gNormMouseX; +extern float gNormMouseY; + +extern int gVisibleMouse; +extern vec3_t v_angles; +extern vec3_t v_origin; + #endif \ No newline at end of file diff --git a/main/source/cl_dll/entity.cpp b/main/source/cl_dll/entity.cpp index d4940a25..d8ecd30f 100644 --- a/main/source/cl_dll/entity.cpp +++ b/main/source/cl_dll/entity.cpp @@ -1,1043 +1,1043 @@ -// Client side entity management functions - -#include - -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_types.h" -#include "common/studio_event.h" // def. of mstudioevent_t -#include "common/r_efx.h" -#include "common/event_api.h" -#include "pm_shared/pm_defs.h" -#include "common/pmtrace.h" -#include "pm_shared/pm_shared.h" -#include "mod/AvHParticleSystemManager.h" -#include "mod/AvHSpecials.h" - -#include "engine/APIProxy.h" -#include "Exports.h" - -void Game_AddObjects( void ); - -extern vec3_t v_origin; -double gClientTimeLastUpdate; -int g_iAlive = 1; - -bool gTempEntClearAllFlag = false; - -/* -======================== -HUD_AddEntity - Return 0 to filter entity from visible list for rendering -======================== -*/ -int CL_DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) -{ -// RecClAddEntity(type, ent, modelname); - - gHUD.ClientProcessEntity(&ent->curstate); - - // Particle entities have a model so they will be forced through this function, - // but we don't want to draw them. - int theSpecialState = ent->curstate.iuser3; - if( (theSpecialState == AVH_USER3_PARTICLE_ON) || - (theSpecialState == AVH_USER3_PARTICLE_OFF) || - (theSpecialState == AVH_USER3_AUDIO_ON) || - (theSpecialState == AVH_USER3_AUDIO_OFF) || - (theSpecialState == AVH_USER3_NOBUILD)) - { - return 0; - } - - switch ( type ) - { - case ET_NORMAL: - case ET_PLAYER: - case ET_BEAM: - case ET_TEMPENTITY: - case ET_FRAGMENTED: - default: - break; - } - - if ( g_iUser1 == OBS_IN_EYE && ent->index == g_iUser2 ) - { - // Don't draw the player we are following in eye - return 0; - } - - return 1; - -} - -/* -========================= -HUD_TxferLocalOverrides - -The server sends us our origin with extra precision as part of the clientdata structure, not during the normal -playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate -structure, we need to copy them into the state structure at this point. -========================= -*/ -void CL_DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) -{ -// RecClTxferLocalOverrides(state, client); - - VectorCopy( client->origin, state->origin ); - - // Spectator - state->iuser1 = client->iuser1; - state->iuser2 = client->iuser2; - state->iuser3 = client->iuser3; - state->iuser4 = client->iuser4; - - state->fuser1 = client->fuser1; - state->fuser2 = client->fuser2; - state->fuser3 = client->fuser3; - state->fuser4 = client->fuser4; - - state->vuser1 = client->vuser1; - //state->vuser2 = client->vuser2; - //state->vuser3 = client->vuser3; - state->vuser4 = client->vuser4; -} - -/* -========================= -HUD_ProcessPlayerState - -We have received entity_state_t for this player over the network. We need to copy appropriate fields to the -playerstate structure -========================= -*/ -void CL_DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) -{ -// RecClProcessPlayerState(dst, src); - - // Copy in network data - VectorCopy( src->origin, dst->origin ); - VectorCopy( src->angles, dst->angles ); - - VectorCopy( src->velocity, dst->velocity ); - - dst->frame = src->frame; - dst->modelindex = src->modelindex; - dst->skin = src->skin; - dst->effects = src->effects; - dst->weaponmodel = src->weaponmodel; - dst->movetype = src->movetype; - dst->sequence = src->sequence; - dst->animtime = src->animtime; - - dst->solid = src->solid; - - dst->rendermode = src->rendermode; - dst->renderamt = src->renderamt; - dst->rendercolor.r = src->rendercolor.r; - dst->rendercolor.g = src->rendercolor.g; - dst->rendercolor.b = src->rendercolor.b; - dst->renderfx = src->renderfx; - - dst->framerate = src->framerate; - dst->body = src->body; - - memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); - memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); - - VectorCopy( src->basevelocity, dst->basevelocity ); - - dst->friction = src->friction; - dst->gravity = src->gravity; - dst->gaitsequence = src->gaitsequence; - dst->spectator = src->spectator; - dst->usehull = src->usehull; - dst->playerclass = src->playerclass; - dst->team = src->team; - dst->colormap = src->colormap; - - // Save off some data so other areas of the Client DLL can get to it - cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index - if ( dst->number == player->index ) - { - g_iPlayerClass = dst->playerclass; - g_iTeamNumber = dst->team; - - g_iUser1 = src->iuser1; - g_iUser2 = src->iuser2; - g_iUser3 = src->iuser3; - - } - - // AvH - // Copy special movement mode...is this needed? - dst->iuser1 = src->iuser1; - dst->iuser2 = src->iuser2; - dst->iuser3 = src->iuser3; - dst->iuser4 = src->iuser4; - - dst->fuser1 = src->fuser1; - dst->fuser2 = src->fuser2; - dst->fuser3 = src->fuser3; - dst->fuser4 = src->fuser4; - - dst->vuser1 = src->vuser1; - //dst->vuser2 = src->vuser2; - //dst->vuser3 = src->vuser3; - dst->vuser4 = src->vuser4; -} - -/* -========================= -HUD_TxferPredictionData - -Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in - from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's - up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server - update is occupying. -========================= -*/ -void CL_DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ) -{ -// RecClTxferPredictionData(ps, pps, pcd, ppcd, wd, pwd); - - ps->oldbuttons = pps->oldbuttons; - ps->flFallVelocity = pps->flFallVelocity; - ps->iStepLeft = pps->iStepLeft; - ps->playerclass = pps->playerclass; - - pcd->viewmodel = ppcd->viewmodel; - pcd->m_iId = ppcd->m_iId; - pcd->ammo_shells = ppcd->ammo_shells; - pcd->ammo_nails = ppcd->ammo_nails; - pcd->ammo_cells = ppcd->ammo_cells; - pcd->ammo_rockets = ppcd->ammo_rockets; - pcd->m_flNextAttack = ppcd->m_flNextAttack; - pcd->fov = ppcd->fov; - pcd->weaponanim = ppcd->weaponanim; - pcd->tfstate = ppcd->tfstate; - pcd->maxspeed = ppcd->maxspeed; - - pcd->deadflag = ppcd->deadflag; - - // Spectating or not dead == get control over view angles. - g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0; - - // Spectator - pcd->iuser1 = ppcd->iuser1; - pcd->iuser2 = ppcd->iuser2; - pcd->iuser3 = ppcd->iuser3; - pcd->iuser4 = ppcd->iuser4; - - pcd->fuser1 = ppcd->fuser1; - pcd->fuser2 = ppcd->fuser2; - pcd->fuser3 = ppcd->fuser3; - pcd->fuser4 = ppcd->fuser4; - - if( gEngfuncs.IsSpectateOnly() ) - { - // in specator mode we tell the engine who we want to spectate and how - // iuser3 is not used for duck prevention (since the spectator can't duck at all) - pcd->iuser1 = g_iUser1; // observer mode - pcd->iuser2 = g_iUser2; // first target - pcd->iuser3 = g_iUser3; // second target - - } - - VectorCopy( ppcd->vuser1, pcd->vuser1 ); - //VectorCopy( ppcd->vuser2, pcd->vuser2 ); - //VectorCopy( ppcd->vuser3, pcd->vuser3 ); - VectorCopy( ppcd->vuser4, pcd->vuser4 ); - - memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); -} - -/* -//#define TEST_IT -#if defined( TEST_IT ) - -cl_entity_t mymodel[9]; - -void MoveModel( void ) -{ - cl_entity_t *player; - int i, j; - int modelindex; - struct model_s *mod; - - // Load it up with some bogus data - player = gEngfuncs.GetLocalPlayer(); - if ( !player ) - return; - - mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); - for ( i = 0; i < 3; i++ ) - { - for ( j = 0; j < 3; j++ ) - { - // Don't draw over ourself... - if ( ( i == 1 ) && ( j == 1 ) ) - continue; - - mymodel[ i * 3 + j ] = *player; - - mymodel[ i * 3 + j ].player = 0; - - mymodel[ i * 3 + j ].model = mod; - mymodel[ i * 3 + j ].curstate.modelindex = modelindex; - - // Move it out a bit - mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); - mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); - - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); - } - } - -} - -#endif -*/ -//#define TRACE_TEST -#if defined( TRACE_TEST ) - -extern int hitent; - -cl_entity_t hit; - -void TraceModel( void ) -{ - cl_entity_t *ent; - - if ( hitent <= 0 ) - return; - - // Load it up with some bogus data - ent = gEngfuncs.GetEntityByIndex( hitent ); - if ( !ent ) - return; - - hit = *ent; - //hit.curstate.rendermode = kRenderTransTexture; - //hit.curstate.renderfx = kRenderFxGlowShell; - //hit.curstate.renderamt = 100; - - hit.origin[2] += 40; - - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); -} - -#endif - - -/* -void ParticleCallback( struct particle_s *particle, float frametime ) -{ - int i; - - for ( i = 0; i < 3; i++ ) - { - particle->org[ i ] += particle->vel[ i ] * frametime; - } -} - -cvar_t *color = NULL; -void Particles( void ) -{ - static float lasttime; - float curtime; - - curtime = gEngfuncs.GetClientTime(); - - if ( ( curtime - lasttime ) < 2.0 ) - return; - - if ( !color ) - { - color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); - } - - lasttime = curtime; - - // Create a few particles - particle_t *p; - int i, j; - - for ( i = 0; i < 1000; i++ ) - { - int r, g, b; - p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); - if ( !p ) - break; - - for ( j = 0; j < 3; j++ ) - { - p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; - p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); - } - - if ( color ) - { - sscanf( color->string, "%i %i %i", &r, &g, &b ); - } - else - { - r = 192; - g = 0; - b = 0; - } - - p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); - gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); - - // p->die is set to current time so all you have to do is add an additional time to it - p->die += 3.0; - } -} -*/ - -/* -void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) -{ - int i; - - for ( i = 0; i < 3; i++ ) - { - ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; - } -} - -void TempEnts( void ) -{ - static float lasttime; - float curtime; - - curtime = gEngfuncs.GetClientTime(); - - if ( ( curtime - lasttime ) < 10.0 ) - return; - - lasttime = curtime; - - TEMPENTITY *p; - int i, j; - struct model_s *mod; - vec3_t origin; - int index; - - mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); - - for ( i = 0; i < 100; i++ ) - { - for ( j = 0; j < 3; j++ ) - { - origin[ j ] = v_origin[ j ]; - if ( j != 2 ) - { - origin[ j ] += 75; - } - } - - p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); - if ( !p ) - break; - - for ( j = 0; j < 3; j++ ) - { - p->entity.curstate.origin[ j ] = origin[ j ]; - - // Store velocity in baseline origin - p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); - } - - // p->die is set to current time so all you have to do is add an additional time to it - p->die += 10.0; - } -} -*/ - -#if defined( BEAM_TEST ) -// Note can't index beam[ 0 ] in Beam callback, so don't use that index -// Room for 1 beam ( 0 can't be used ) -static cl_entity_t beams[ 2 ]; - -void BeamEndModel( void ) -{ - cl_entity_t *player, *model; - int modelindex; - struct model_s *mod; - - // Load it up with some bogus data - player = gEngfuncs.GetLocalPlayer(); - if ( !player ) - return; - - mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); - if ( !mod ) - return; - - // Slot 1 - model = &beams[ 1 ]; - - *model = *player; - model->player = 0; - model->model = mod; - model->curstate.modelindex = modelindex; - - // Move it out a bit - model->origin[0] = player->origin[0] - 100; - model->origin[1] = player->origin[1]; - - model->attachment[0] = model->origin; - model->attachment[1] = model->origin; - model->attachment[2] = model->origin; - model->attachment[3] = model->origin; - - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); -} - -void Beams( void ) -{ - static float lasttime; - float curtime; - struct model_s *mod; - int index; - - BeamEndModel(); - - curtime = gEngfuncs.GetClientTime(); - float end[ 3 ]; - - if ( ( curtime - lasttime ) < 10.0 ) - return; - - mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); - if ( !mod ) - return; - - lasttime = curtime; - - end [ 0 ] = v_origin.x + 100; - end [ 1 ] = v_origin.y + 100; - end [ 2 ] = v_origin.z; - - BEAM *p1; - p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, - 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); -} -#endif - -/* -========================= -HUD_CreateEntities - -Gives us a chance to add additional entities to the render this frame -========================= -*/ -void CL_DLLEXPORT HUD_CreateEntities( void ) -{ -// RecClCreateEntities(); - - // e.g., create a persistent cl_entity_t somewhere. - // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) - // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list -/* -#if defined( TEST_IT ) - MoveModel(); -#endif -*/ -#if defined( TRACE_TEST ) - TraceModel(); -#endif - -/* - Particles(); -*/ -/* - TempEnts(); -*/ - -#if defined( BEAM_TEST ) - Beams(); -#endif - - // Add in any game specific objects - Game_AddObjects(); - - GetClientVoiceMgr()->CreateEntities(); -} - -/* -========================= -HUD_StudioEvent - -The entity's studio model description indicated an event was -fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) -========================= -*/ -void CL_DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) -{ -// RecClStudioEvent(event, entity); - - switch( event->event ) - { - case 5001: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); - break; - case 5011: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); - break; - case 5021: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); - break; - case 5031: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); - break; - case 5002: - gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); - break; - // Client side sound - case 5004: - gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); - break; - - // Particles! - case 7000: - AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[0]); - break; - - case 7010: - AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[1]); - break; - - case 7020: - AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[2]); - break; - - case 7030: - AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[3]); - break; - - default: - break; - } -} - -/* -================= -CL_UpdateTEnts - -Simulation and cleanup of temporary entities -================= -*/ -void CL_DLLEXPORT HUD_TempEntUpdate ( - double frametime, // Simulation time - double client_time, // Absolute time on client - double cl_gravity, // True gravity on client - TEMPENTITY **ppTempEntFree, // List of freed temporary ents - TEMPENTITY **ppTempEntActive, // List - int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), - void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) -{ -// RecClTempEntUpdate(frametime, client_time, cl_gravity, ppTempEntFree, ppTempEntActive, Callback_AddVisibleEntity, Callback_TempEntPlaySound); - - static int gTempEntFrame = 0; - int i; - TEMPENTITY *pTemp, *pnext, *pprev; - float freq, gravity, gravitySlow, life, fastFreq; - - // don't simulate when we're paused - if(gClientTimeLastUpdate != client_time) - { - gClientTimeLastUpdate = client_time; - - // Nothing to simulate - if ( *ppTempEntActive ) - { - // in order to have tents collide with players, we have to run the player prediction code so - // that the client has the player list. We run this code once when we detect any COLLIDEALL - // tent, then set this BOOL to true so the code doesn't get run again if there's more than - // one COLLIDEALL ent for this update. (often are). - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); - - // !!!BUGBUG -- This needs to be time based - gTempEntFrame = (gTempEntFrame+1) & 31; - - pTemp = *ppTempEntActive; - - bool theIsDone = false; - - // !!! Don't simulate while paused.... This is sort of a hack, revisit. - if ( frametime <= 0 ) - { - while ( pTemp ) - { - if ( !(pTemp->flags & FTENT_NOMODEL ) ) - { - Callback_AddVisibleEntity( &pTemp->entity ); - } - pTemp = pTemp->next; - } - //goto finish; - - theIsDone = true; - } - - if(!theIsDone) - { - pprev = NULL; - freq = client_time * 0.01; - fastFreq = client_time * 5.5; - gravity = -frametime * cl_gravity; - gravitySlow = gravity * 0.5; - - while ( pTemp ) - { - int active; - - active = 1; - - life = pTemp->die - client_time; - pnext = pTemp->next; - if ( life < 0 ) - { - if ( pTemp->flags & FTENT_FADEOUT ) - { - if (pTemp->entity.curstate.rendermode == kRenderNormal) - pTemp->entity.curstate.rendermode = kRenderTransTexture; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); - if ( pTemp->entity.curstate.renderamt <= 0 ) - active = 0; - - } - else - active = 0; - } - if ( !active ) // Kill it - { - pTemp->next = *ppTempEntFree; - *ppTempEntFree = pTemp; - if ( !pprev ) // Deleting at head of list - *ppTempEntActive = pnext; - else - pprev->next = pnext; - } - else - { - pprev = pTemp; - - VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // Adjust speed if it's time - // Scale is next think time - if ( client_time > pTemp->entity.baseline.scale ) - { - // Show Sparks - gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); - - // Reduce life - pTemp->entity.baseline.framerate -= 0.1; - - if ( pTemp->entity.baseline.framerate <= 0.0 ) - { - pTemp->die = client_time; - } - else - { - // So it will die no matter what - pTemp->die = client_time + 0.5; - - // Next think - pTemp->entity.baseline.scale = client_time + 0.1; - } - } - } - else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) - { - cl_entity_t *pClient; - - pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); - - VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); - } - else if ( pTemp->flags & FTENT_SINEWAVE ) - { - pTemp->x += pTemp->entity.baseline.origin[0] * frametime; - pTemp->y += pTemp->entity.baseline.origin[1] * frametime; - - pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); - pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); - pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; - } - else if ( pTemp->flags & FTENT_SPIRAL ) - { - float s, c; - s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); - c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); -#pragma warning(push) -#pragma warning(disable: 311) - pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); - pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); - pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; -#pragma warning(pop) - } - - else - { - for ( i = 0; i < 3; i++ ) - pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; - } - - if ( pTemp->flags & FTENT_SPRANIMATE ) - { - pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - - if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) - { - // this animating sprite isn't set to loop, so destroy it. - pTemp->die = client_time; - pTemp = pnext; - continue; - } - } - } - else if ( pTemp->flags & FTENT_SPRCYCLE ) - { - pTemp->entity.curstate.frame += frametime * 10; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - } - } - // Experiment -#if 0 - if ( pTemp->flags & FTENT_SCALE ) - pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); -#endif - - if ( pTemp->flags & FTENT_ROTATE ) - { - pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; - pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; - pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; - - VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); - } - - if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) - { - vec3_t traceNormal; - float traceFraction = 1; - - if ( pTemp->flags & FTENT_COLLIDEALL ) - { - pmtrace_t pmtrace; - physent_t *pe; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); - - - if ( pmtrace.fraction != 1 ) - { - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); - - if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) - { - traceFraction = pmtrace.fraction; - VectorCopy( pmtrace.plane.normal, traceNormal ); - - if ( pTemp->hitcallback ) - { - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - } - else if ( pTemp->flags & FTENT_COLLIDEWORLD ) - { - pmtrace_t pmtrace; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); - - if ( pmtrace.fraction != 1 ) - { - traceFraction = pmtrace.fraction; - VectorCopy( pmtrace.plane.normal, traceNormal ); - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // Chop spark speeds a bit more - // - VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); - - if ( Length( pTemp->entity.baseline.origin ) < 10 ) - { - pTemp->entity.baseline.framerate = 0.0; - } - } - - if ( pTemp->hitcallback ) - { - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - - if ( traceFraction != 1 ) // Decent collision now, and damping works - { - float proj, damp; - - // Place at contact point - VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); - // Damp velocity - damp = pTemp->bounceFactor; - if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) - { - damp *= 0.5; - if ( traceNormal[2] > 0.9 ) // Hit floor? - { - if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) - { - damp = 0; // Stop - pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); - pTemp->entity.angles[0] = 0; - pTemp->entity.angles[2] = 0; - } - } - } - - if (pTemp->hitSound) - { - Callback_TempEntPlaySound(pTemp, damp); - } - - if (pTemp->flags & FTENT_COLLIDEKILL) - { - // die on impact - pTemp->flags &= ~FTENT_FADEOUT; - pTemp->die = client_time; - } - else - { - // Reflect velocity - if ( damp != 0 ) - { - proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); - VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); - // Reflect rotation (fake) - - pTemp->entity.angles[1] = -pTemp->entity.angles[1]; - } - - if ( damp != 1 ) - { - - VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); - VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); - } - } - } - } - - - if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) - { - dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); - VectorCopy (pTemp->entity.origin, dl->origin); - dl->radius = 60; - dl->color.r = 255; - dl->color.g = 120; - dl->color.b = 0; - dl->die = client_time + 0.01; - } - - if ( pTemp->flags & FTENT_SMOKETRAIL ) - { - gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); - } - - if ( pTemp->flags & FTENT_GRAVITY ) - pTemp->entity.baseline.origin[2] += gravity; - else if ( pTemp->flags & FTENT_SLOWGRAVITY ) - pTemp->entity.baseline.origin[2] += gravitySlow; - - if ( pTemp->flags & FTENT_CLIENTCUSTOM ) - { - if ( pTemp->callback ) - { - ( *pTemp->callback )( pTemp, frametime, client_time ); - } - } - - // Cull to PVS (not frustum cull, just PVS) - if ( !(pTemp->flags & FTENT_NOMODEL ) ) - { - if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) - { - if ( !(pTemp->flags & FTENT_PERSIST) ) - { - pTemp->die = client_time; // If we can't draw it this frame, just dump it. - pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die - } - } - } - } - pTemp = pnext; - } - } - - // Restore state info - gEngfuncs.pEventAPI->EV_PopPMStates(); - } - } - -//finish: -// // Restore state info -// gEngfuncs.pEventAPI->EV_PopPMStates(); -} - -/* -================= -HUD_GetUserEntity - -If you specify negative numbers for beam start and end point entities, then - the engine will call back into this function requesting a pointer to a cl_entity_t - object that describes the entity to attach the beam onto. - -Indices must start at 1, not zero. -================= -*/ -cl_entity_t CL_DLLEXPORT *HUD_GetUserEntity( int index ) -{ -// RecClGetUserEntity(index); - -#if defined( BEAM_TEST ) - // None by default, you would return a valic pointer if you create a client side - // beam and attach it to a client side entity. - if ( index > 0 && index <= 1 ) - { - return &beams[ index ]; - } - else - { - return NULL; - } -#else - return NULL; -#endif -} +// Client side entity management functions + +#include + +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/entity_types.h" +#include "common/studio_event.h" // def. of mstudioevent_t +#include "common/r_efx.h" +#include "common/event_api.h" +#include "pm_shared/pm_defs.h" +#include "common/pmtrace.h" +#include "pm_shared/pm_shared.h" +#include "mod/AvHParticleSystemManager.h" +#include "mod/AvHSpecials.h" + +#include "engine/APIProxy.h" +#include "Exports.h" + +void Game_AddObjects( void ); + +extern vec3_t v_origin; +double gClientTimeLastUpdate; +int g_iAlive = 1; + +bool gTempEntClearAllFlag = false; + +/* +======================== +HUD_AddEntity + Return 0 to filter entity from visible list for rendering +======================== +*/ +int CL_DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) +{ +// RecClAddEntity(type, ent, modelname); + + gHUD.ClientProcessEntity(&ent->curstate); + + // Particle entities have a model so they will be forced through this function, + // but we don't want to draw them. + int theSpecialState = ent->curstate.iuser3; + if( (theSpecialState == AVH_USER3_PARTICLE_ON) || + (theSpecialState == AVH_USER3_PARTICLE_OFF) || + (theSpecialState == AVH_USER3_AUDIO_ON) || + (theSpecialState == AVH_USER3_AUDIO_OFF) || + (theSpecialState == AVH_USER3_NOBUILD)) + { + return 0; + } + + switch ( type ) + { + case ET_NORMAL: + case ET_PLAYER: + case ET_BEAM: + case ET_TEMPENTITY: + case ET_FRAGMENTED: + default: + break; + } + + if ( g_iUser1 == OBS_IN_EYE && ent->index == g_iUser2 ) + { + // Don't draw the player we are following in eye + return 0; + } + + return 1; + +} + +/* +========================= +HUD_TxferLocalOverrides + +The server sends us our origin with extra precision as part of the clientdata structure, not during the normal +playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate +structure, we need to copy them into the state structure at this point. +========================= +*/ +void CL_DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) +{ +// RecClTxferLocalOverrides(state, client); + + VectorCopy( client->origin, state->origin ); + + // Spectator + state->iuser1 = client->iuser1; + state->iuser2 = client->iuser2; + state->iuser3 = client->iuser3; + state->iuser4 = client->iuser4; + + state->fuser1 = client->fuser1; + state->fuser2 = client->fuser2; + state->fuser3 = client->fuser3; + state->fuser4 = client->fuser4; + + state->vuser1 = client->vuser1; + //state->vuser2 = client->vuser2; + //state->vuser3 = client->vuser3; + state->vuser4 = client->vuser4; +} + +/* +========================= +HUD_ProcessPlayerState + +We have received entity_state_t for this player over the network. We need to copy appropriate fields to the +playerstate structure +========================= +*/ +void CL_DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) +{ +// RecClProcessPlayerState(dst, src); + + // Copy in network data + VectorCopy( src->origin, dst->origin ); + VectorCopy( src->angles, dst->angles ); + + VectorCopy( src->velocity, dst->velocity ); + + dst->frame = src->frame; + dst->modelindex = src->modelindex; + dst->skin = src->skin; + dst->effects = src->effects; + dst->weaponmodel = src->weaponmodel; + dst->movetype = src->movetype; + dst->sequence = src->sequence; + dst->animtime = src->animtime; + + dst->solid = src->solid; + + dst->rendermode = src->rendermode; + dst->renderamt = src->renderamt; + dst->rendercolor.r = src->rendercolor.r; + dst->rendercolor.g = src->rendercolor.g; + dst->rendercolor.b = src->rendercolor.b; + dst->renderfx = src->renderfx; + + dst->framerate = src->framerate; + dst->body = src->body; + + memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); + memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); + + VectorCopy( src->basevelocity, dst->basevelocity ); + + dst->friction = src->friction; + dst->gravity = src->gravity; + dst->gaitsequence = src->gaitsequence; + dst->spectator = src->spectator; + dst->usehull = src->usehull; + dst->playerclass = src->playerclass; + dst->team = src->team; + dst->colormap = src->colormap; + + // Save off some data so other areas of the Client DLL can get to it + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index + if ( dst->number == player->index ) + { + g_iPlayerClass = dst->playerclass; + g_iTeamNumber = dst->team; + + g_iUser1 = src->iuser1; + g_iUser2 = src->iuser2; + g_iUser3 = src->iuser3; + + } + + // AvH + // Copy special movement mode...is this needed? + dst->iuser1 = src->iuser1; + dst->iuser2 = src->iuser2; + dst->iuser3 = src->iuser3; + dst->iuser4 = src->iuser4; + + dst->fuser1 = src->fuser1; + dst->fuser2 = src->fuser2; + dst->fuser3 = src->fuser3; + dst->fuser4 = src->fuser4; + + dst->vuser1 = src->vuser1; + //dst->vuser2 = src->vuser2; + //dst->vuser3 = src->vuser3; + dst->vuser4 = src->vuser4; +} + +/* +========================= +HUD_TxferPredictionData + +Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in + from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's + up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server + update is occupying. +========================= +*/ +void CL_DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ) +{ +// RecClTxferPredictionData(ps, pps, pcd, ppcd, wd, pwd); + + ps->oldbuttons = pps->oldbuttons; + ps->flFallVelocity = pps->flFallVelocity; + ps->iStepLeft = pps->iStepLeft; + ps->playerclass = pps->playerclass; + + pcd->viewmodel = ppcd->viewmodel; + pcd->m_iId = ppcd->m_iId; + pcd->ammo_shells = ppcd->ammo_shells; + pcd->ammo_nails = ppcd->ammo_nails; + pcd->ammo_cells = ppcd->ammo_cells; + pcd->ammo_rockets = ppcd->ammo_rockets; + pcd->m_flNextAttack = ppcd->m_flNextAttack; + pcd->fov = ppcd->fov; + pcd->weaponanim = ppcd->weaponanim; + pcd->tfstate = ppcd->tfstate; + pcd->maxspeed = ppcd->maxspeed; + + pcd->deadflag = ppcd->deadflag; + + // Spectating or not dead == get control over view angles. + g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0; + + // Spectator + pcd->iuser1 = ppcd->iuser1; + pcd->iuser2 = ppcd->iuser2; + pcd->iuser3 = ppcd->iuser3; + pcd->iuser4 = ppcd->iuser4; + + pcd->fuser1 = ppcd->fuser1; + pcd->fuser2 = ppcd->fuser2; + pcd->fuser3 = ppcd->fuser3; + pcd->fuser4 = ppcd->fuser4; + + if( gEngfuncs.IsSpectateOnly() ) + { + // in specator mode we tell the engine who we want to spectate and how + // iuser3 is not used for duck prevention (since the spectator can't duck at all) + pcd->iuser1 = g_iUser1; // observer mode + pcd->iuser2 = g_iUser2; // first target + pcd->iuser3 = g_iUser3; // second target + + } + + VectorCopy( ppcd->vuser1, pcd->vuser1 ); + //VectorCopy( ppcd->vuser2, pcd->vuser2 ); + //VectorCopy( ppcd->vuser3, pcd->vuser3 ); + VectorCopy( ppcd->vuser4, pcd->vuser4 ); + + memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); +} + +/* +//#define TEST_IT +#if defined( TEST_IT ) + +cl_entity_t mymodel[9]; + +void MoveModel( void ) +{ + cl_entity_t *player; + int i, j; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + // Don't draw over ourself... + if ( ( i == 1 ) && ( j == 1 ) ) + continue; + + mymodel[ i * 3 + j ] = *player; + + mymodel[ i * 3 + j ].player = 0; + + mymodel[ i * 3 + j ].model = mod; + mymodel[ i * 3 + j ].curstate.modelindex = modelindex; + + // Move it out a bit + mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); + mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); + } + } + +} + +#endif +*/ +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern int hitent; + +cl_entity_t hit; + +void TraceModel( void ) +{ + cl_entity_t *ent; + + if ( hitent <= 0 ) + return; + + // Load it up with some bogus data + ent = gEngfuncs.GetEntityByIndex( hitent ); + if ( !ent ) + return; + + hit = *ent; + //hit.curstate.rendermode = kRenderTransTexture; + //hit.curstate.renderfx = kRenderFxGlowShell; + //hit.curstate.renderamt = 100; + + hit.origin[2] += 40; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); +} + +#endif + + +/* +void ParticleCallback( struct particle_s *particle, float frametime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + particle->org[ i ] += particle->vel[ i ] * frametime; + } +} + +cvar_t *color = NULL; +void Particles( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 2.0 ) + return; + + if ( !color ) + { + color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); + } + + lasttime = curtime; + + // Create a few particles + particle_t *p; + int i, j; + + for ( i = 0; i < 1000; i++ ) + { + int r, g, b; + p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; + p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); + } + + if ( color ) + { + sscanf( color->string, "%i %i %i", &r, &g, &b ); + } + else + { + r = 192; + g = 0; + b = 0; + } + + p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); + gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 3.0; + } +} +*/ + +/* +void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; + } +} + +void TempEnts( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + lasttime = curtime; + + TEMPENTITY *p; + int i, j; + struct model_s *mod; + vec3_t origin; + int index; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); + + for ( i = 0; i < 100; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + origin[ j ] = v_origin[ j ]; + if ( j != 2 ) + { + origin[ j ] += 75; + } + } + + p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->entity.curstate.origin[ j ] = origin[ j ]; + + // Store velocity in baseline origin + p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); + } + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 10.0; + } +} +*/ + +#if defined( BEAM_TEST ) +// Note can't index beam[ 0 ] in Beam callback, so don't use that index +// Room for 1 beam ( 0 can't be used ) +static cl_entity_t beams[ 2 ]; + +void BeamEndModel( void ) +{ + cl_entity_t *player, *model; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + if ( !mod ) + return; + + // Slot 1 + model = &beams[ 1 ]; + + *model = *player; + model->player = 0; + model->model = mod; + model->curstate.modelindex = modelindex; + + // Move it out a bit + model->origin[0] = player->origin[0] - 100; + model->origin[1] = player->origin[1]; + + model->attachment[0] = model->origin; + model->attachment[1] = model->origin; + model->attachment[2] = model->origin; + model->attachment[3] = model->origin; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); +} + +void Beams( void ) +{ + static float lasttime; + float curtime; + struct model_s *mod; + int index; + + BeamEndModel(); + + curtime = gEngfuncs.GetClientTime(); + float end[ 3 ]; + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); + if ( !mod ) + return; + + lasttime = curtime; + + end [ 0 ] = v_origin.x + 100; + end [ 1 ] = v_origin.y + 100; + end [ 2 ] = v_origin.z; + + BEAM *p1; + p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, + 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); +} +#endif + +/* +========================= +HUD_CreateEntities + +Gives us a chance to add additional entities to the render this frame +========================= +*/ +void CL_DLLEXPORT HUD_CreateEntities( void ) +{ +// RecClCreateEntities(); + + // e.g., create a persistent cl_entity_t somewhere. + // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) + // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list +/* +#if defined( TEST_IT ) + MoveModel(); +#endif +*/ +#if defined( TRACE_TEST ) + TraceModel(); +#endif + +/* + Particles(); +*/ +/* + TempEnts(); +*/ + +#if defined( BEAM_TEST ) + Beams(); +#endif + + // Add in any game specific objects + Game_AddObjects(); + + GetClientVoiceMgr()->CreateEntities(); +} + +/* +========================= +HUD_StudioEvent + +The entity's studio model description indicated an event was +fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) +========================= +*/ +void CL_DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) +{ +// RecClStudioEvent(event, entity); + + switch( event->event ) + { + case 5001: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); + break; + case 5011: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); + break; + case 5021: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); + break; + case 5031: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); + break; + case 5002: + gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); + break; + // Client side sound + case 5004: + gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); + break; + + // Particles! + case 7000: + AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[0]); + break; + + case 7010: + AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[1]); + break; + + case 7020: + AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[2]); + break; + + case 7030: + AvHParticleSystemManager::Instance()->CreateParticleSystem(string(event->options), entity->attachment[3]); + break; + + default: + break; + } +} + +/* +================= +CL_UpdateTEnts + +Simulation and cleanup of temporary entities +================= +*/ +void CL_DLLEXPORT HUD_TempEntUpdate ( + double frametime, // Simulation time + double client_time, // Absolute time on client + double cl_gravity, // True gravity on client + TEMPENTITY **ppTempEntFree, // List of freed temporary ents + TEMPENTITY **ppTempEntActive, // List + int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), + void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) +{ +// RecClTempEntUpdate(frametime, client_time, cl_gravity, ppTempEntFree, ppTempEntActive, Callback_AddVisibleEntity, Callback_TempEntPlaySound); + + static int gTempEntFrame = 0; + int i; + TEMPENTITY *pTemp, *pnext, *pprev; + float freq, gravity, gravitySlow, life, fastFreq; + + // don't simulate when we're paused + if(gClientTimeLastUpdate != client_time) + { + gClientTimeLastUpdate = client_time; + + // Nothing to simulate + if ( *ppTempEntActive ) + { + // in order to have tents collide with players, we have to run the player prediction code so + // that the client has the player list. We run this code once when we detect any COLLIDEALL + // tent, then set this BOOL to true so the code doesn't get run again if there's more than + // one COLLIDEALL ent for this update. (often are). + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); + + // !!!BUGBUG -- This needs to be time based + gTempEntFrame = (gTempEntFrame+1) & 31; + + pTemp = *ppTempEntActive; + + bool theIsDone = false; + + // !!! Don't simulate while paused.... This is sort of a hack, revisit. + if ( frametime <= 0 ) + { + while ( pTemp ) + { + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + Callback_AddVisibleEntity( &pTemp->entity ); + } + pTemp = pTemp->next; + } + //goto finish; + + theIsDone = true; + } + + if(!theIsDone) + { + pprev = NULL; + freq = client_time * 0.01; + fastFreq = client_time * 5.5; + gravity = -frametime * cl_gravity; + gravitySlow = gravity * 0.5; + + while ( pTemp ) + { + int active; + + active = 1; + + life = pTemp->die - client_time; + pnext = pTemp->next; + if ( life < 0 ) + { + if ( pTemp->flags & FTENT_FADEOUT ) + { + if (pTemp->entity.curstate.rendermode == kRenderNormal) + pTemp->entity.curstate.rendermode = kRenderTransTexture; + pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); + if ( pTemp->entity.curstate.renderamt <= 0 ) + active = 0; + + } + else + active = 0; + } + if ( !active ) // Kill it + { + pTemp->next = *ppTempEntFree; + *ppTempEntFree = pTemp; + if ( !pprev ) // Deleting at head of list + *ppTempEntActive = pnext; + else + pprev->next = pnext; + } + else + { + pprev = pTemp; + + VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Adjust speed if it's time + // Scale is next think time + if ( client_time > pTemp->entity.baseline.scale ) + { + // Show Sparks + gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); + + // Reduce life + pTemp->entity.baseline.framerate -= 0.1; + + if ( pTemp->entity.baseline.framerate <= 0.0 ) + { + pTemp->die = client_time; + } + else + { + // So it will die no matter what + pTemp->die = client_time + 0.5; + + // Next think + pTemp->entity.baseline.scale = client_time + 0.1; + } + } + } + else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) + { + cl_entity_t *pClient; + + pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); + + VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); + } + else if ( pTemp->flags & FTENT_SINEWAVE ) + { + pTemp->x += pTemp->entity.baseline.origin[0] * frametime; + pTemp->y += pTemp->entity.baseline.origin[1] * frametime; + + pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); + pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + else if ( pTemp->flags & FTENT_SPIRAL ) + { + float s, c; + s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); + c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); +#pragma warning(push) +#pragma warning(disable: 311) + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; +#pragma warning(pop) + } + + else + { + for ( i = 0; i < 3; i++ ) + pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; + } + + if ( pTemp->flags & FTENT_SPRANIMATE ) + { + pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + + if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) + { + // this animating sprite isn't set to loop, so destroy it. + pTemp->die = client_time; + pTemp = pnext; + continue; + } + } + } + else if ( pTemp->flags & FTENT_SPRCYCLE ) + { + pTemp->entity.curstate.frame += frametime * 10; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + } + } + // Experiment +#if 0 + if ( pTemp->flags & FTENT_SCALE ) + pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); +#endif + + if ( pTemp->flags & FTENT_ROTATE ) + { + pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; + pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; + pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; + + VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); + } + + if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) + { + vec3_t traceNormal; + float traceFraction = 1; + + if ( pTemp->flags & FTENT_COLLIDEALL ) + { + pmtrace_t pmtrace; + physent_t *pe; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); + + + if ( pmtrace.fraction != 1 ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); + + if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + } + else if ( pTemp->flags & FTENT_COLLIDEWORLD ) + { + pmtrace_t pmtrace; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); + + if ( pmtrace.fraction != 1 ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Chop spark speeds a bit more + // + VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); + + if ( Length( pTemp->entity.baseline.origin ) < 10 ) + { + pTemp->entity.baseline.framerate = 0.0; + } + } + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + + if ( traceFraction != 1 ) // Decent collision now, and damping works + { + float proj, damp; + + // Place at contact point + VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); + // Damp velocity + damp = pTemp->bounceFactor; + if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) + { + damp *= 0.5; + if ( traceNormal[2] > 0.9 ) // Hit floor? + { + if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) + { + damp = 0; // Stop + pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); + pTemp->entity.angles[0] = 0; + pTemp->entity.angles[2] = 0; + } + } + } + + if (pTemp->hitSound) + { + Callback_TempEntPlaySound(pTemp, damp); + } + + if (pTemp->flags & FTENT_COLLIDEKILL) + { + // die on impact + pTemp->flags &= ~FTENT_FADEOUT; + pTemp->die = client_time; + } + else + { + // Reflect velocity + if ( damp != 0 ) + { + proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); + VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); + // Reflect rotation (fake) + + pTemp->entity.angles[1] = -pTemp->entity.angles[1]; + } + + if ( damp != 1 ) + { + + VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); + VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); + } + } + } + } + + + if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) + { + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); + VectorCopy (pTemp->entity.origin, dl->origin); + dl->radius = 60; + dl->color.r = 255; + dl->color.g = 120; + dl->color.b = 0; + dl->die = client_time + 0.01; + } + + if ( pTemp->flags & FTENT_SMOKETRAIL ) + { + gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); + } + + if ( pTemp->flags & FTENT_GRAVITY ) + pTemp->entity.baseline.origin[2] += gravity; + else if ( pTemp->flags & FTENT_SLOWGRAVITY ) + pTemp->entity.baseline.origin[2] += gravitySlow; + + if ( pTemp->flags & FTENT_CLIENTCUSTOM ) + { + if ( pTemp->callback ) + { + ( *pTemp->callback )( pTemp, frametime, client_time ); + } + } + + // Cull to PVS (not frustum cull, just PVS) + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) + { + if ( !(pTemp->flags & FTENT_PERSIST) ) + { + pTemp->die = client_time; // If we can't draw it this frame, just dump it. + pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die + } + } + } + } + pTemp = pnext; + } + } + + // Restore state info + gEngfuncs.pEventAPI->EV_PopPMStates(); + } + } + +//finish: +// // Restore state info +// gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +================= +HUD_GetUserEntity + +If you specify negative numbers for beam start and end point entities, then + the engine will call back into this function requesting a pointer to a cl_entity_t + object that describes the entity to attach the beam onto. + +Indices must start at 1, not zero. +================= +*/ +cl_entity_t CL_DLLEXPORT *HUD_GetUserEntity( int index ) +{ +// RecClGetUserEntity(index); + +#if defined( BEAM_TEST ) + // None by default, you would return a valic pointer if you create a client side + // beam and attach it to a client side entity. + if ( index > 0 && index <= 1 ) + { + return &beams[ index ]; + } + else + { + return NULL; + } +#else + return NULL; +#endif +} diff --git a/main/source/cl_dll/ev_common.cpp b/main/source/cl_dll/ev_common.cpp index 5c441364..fe96a28c 100644 --- a/main/source/cl_dll/ev_common.cpp +++ b/main/source/cl_dll/ev_common.cpp @@ -1,225 +1,225 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// shared event functions -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" - -#include "common/r_efx.h" - -#include "eventscripts.h" -#include "common/event_api.h" -#include "pm_shared/pm_shared.h" - -#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE) -/* -================= -GetEntity - -Return's the requested cl_entity_t -================= -*/ -struct cl_entity_s *GetEntity( int idx ) -{ - return gEngfuncs.GetEntityByIndex( idx ); -} - -/* -================= -GetViewEntity - -Return's the current weapon/view model -================= -*/ -struct cl_entity_s *GetViewEntity( void ) -{ - return gEngfuncs.GetViewModel(); -} - -physent_t* GetPhysEntity(int inPhysIndex) -{ - return gEngfuncs.pEventAPI->EV_GetPhysent( inPhysIndex ); -} - -void DoCenterPrint(char* inString) -{ - CenterPrint(inString); -} - - -/* -================= -EV_CreateTracer - -Creates a tracer effect -================= -*/ -void EV_CreateTracer( float *start, float *end ) -{ - gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); -} - -/* -================= -EV_IsPlayer - -Is the entity's index in the player range? -================= -*/ -qboolean EV_IsPlayer( int idx ) -{ - if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) - return true; - - return false; -} - -/* -================= -EV_IsLocal - -Is the entity == the local player -================= -*/ -qboolean EV_IsLocal( int idx ) -{ - // check if we are in some way in first person spec mode - if ( IS_FIRSTPERSON_SPEC ) - return (g_iUser2 == idx); - else - return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; -} - -qboolean EV_IsSpec( int idx ) -{ - // check if we are in some way in first person spec mode - if ( IS_FIRSTPERSON_SPEC ) - return (g_iUser2 == idx); - else - return false; -} - -/* -================= -EV_GetGunPosition - -Figure out the height of the gun -================= -*/ -void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) -{ - int idx; - vec3_t view_ofs; - - idx = args->entindex; - - VectorClear( view_ofs ); - view_ofs[2] = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( idx ) ) - { - // in spec mode use entity viewheigh, not own - if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) - { - // Grab predicted result for local player - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( args->ducking == 1 ) - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - VectorAdd( origin, view_ofs, pos ); -} - -/* -================= -EV_EjectBrass - -Bullet shell casings -================= -*/ -void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) -{ - vec3_t endpos; - VectorClear( endpos ); - endpos[1] = rotation; - gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); -} - -/* -================= -EV_GetDefaultShellInfo - -Determine where to eject shells from -================= -*/ -void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) -{ - int i; - vec3_t view_ofs; - float fR, fU; - - int idx; - - idx = args->entindex; - - VectorClear( view_ofs ); - view_ofs[2] = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( idx ) ) - { - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( args->ducking == 1 ) - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - fR = gEngfuncs.pfnRandomFloat( 50, 70 ); - fU = gEngfuncs.pfnRandomFloat( 100, 150 ); - - for ( i = 0; i < 3; i++ ) - { - ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; - ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; - } -} - -/* -================= -EV_MuzzleFlash - -Flag weapon/view model for muzzle flash -================= -*/ -void EV_MuzzleFlash( void ) -{ - // Add muzzle flash to current weapon model - cl_entity_t *ent = GetViewEntity(); - if ( !ent ) - { - return; - } - - // Or in the muzzle flash - ent->curstate.effects |= EF_MUZZLEFLASH; +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// shared event functions +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" + +#include "common/r_efx.h" + +#include "eventscripts.h" +#include "common/event_api.h" +#include "pm_shared/pm_shared.h" + +#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE) +/* +================= +GetEntity + +Return's the requested cl_entity_t +================= +*/ +struct cl_entity_s *GetEntity( int idx ) +{ + return gEngfuncs.GetEntityByIndex( idx ); +} + +/* +================= +GetViewEntity + +Return's the current weapon/view model +================= +*/ +struct cl_entity_s *GetViewEntity( void ) +{ + return gEngfuncs.GetViewModel(); +} + +physent_t* GetPhysEntity(int inPhysIndex) +{ + return gEngfuncs.pEventAPI->EV_GetPhysent( inPhysIndex ); +} + +void DoCenterPrint(char* inString) +{ + CenterPrint(inString); +} + + +/* +================= +EV_CreateTracer + +Creates a tracer effect +================= +*/ +void EV_CreateTracer( float *start, float *end ) +{ + gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); +} + +/* +================= +EV_IsPlayer + +Is the entity's index in the player range? +================= +*/ +qboolean EV_IsPlayer( int idx ) +{ + if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) + return true; + + return false; +} + +/* +================= +EV_IsLocal + +Is the entity == the local player +================= +*/ +qboolean EV_IsLocal( int idx ) +{ + // check if we are in some way in first person spec mode + if ( IS_FIRSTPERSON_SPEC ) + return (g_iUser2 == idx); + else + return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; +} + +qboolean EV_IsSpec( int idx ) +{ + // check if we are in some way in first person spec mode + if ( IS_FIRSTPERSON_SPEC ) + return (g_iUser2 == idx); + else + return false; +} + +/* +================= +EV_GetGunPosition + +Figure out the height of the gun +================= +*/ +void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) +{ + int idx; + vec3_t view_ofs; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + // in spec mode use entity viewheigh, not own + if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) + { + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + VectorAdd( origin, view_ofs, pos ); +} + +/* +================= +EV_EjectBrass + +Bullet shell casings +================= +*/ +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) +{ + vec3_t endpos; + VectorClear( endpos ); + endpos[1] = rotation; + gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); +} + +/* +================= +EV_GetDefaultShellInfo + +Determine where to eject shells from +================= +*/ +void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) +{ + int i; + vec3_t view_ofs; + float fR, fU; + + int idx; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + fR = gEngfuncs.pfnRandomFloat( 50, 70 ); + fU = gEngfuncs.pfnRandomFloat( 100, 150 ); + + for ( i = 0; i < 3; i++ ) + { + ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; + ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; + } +} + +/* +================= +EV_MuzzleFlash + +Flag weapon/view model for muzzle flash +================= +*/ +void EV_MuzzleFlash( void ) +{ + // Add muzzle flash to current weapon model + cl_entity_t *ent = GetViewEntity(); + if ( !ent ) + { + return; + } + + // Or in the muzzle flash + ent->curstate.effects |= EF_MUZZLEFLASH; } \ No newline at end of file diff --git a/main/source/cl_dll/ev_hldm.cpp b/main/source/cl_dll/ev_hldm.cpp index dae39ff6..a53f931a 100644 --- a/main/source/cl_dll/ev_hldm.cpp +++ b/main/source/cl_dll/ev_hldm.cpp @@ -1,1971 +1,1971 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//#include "hud.h" -#include "mod/AvHHud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "common/entity_types.h" -#include "common/usercmd.h" -#include "pm_shared/pm_defs.h" -#include "pm_shared/pm_materials.h" - -#include "eventscripts.h" -#include "ev_hldm.h" - -#include "common/r_efx.h" -#include "common/event_api.h" -#include "common/event_args.h" -#include "in_defs.h" -#include "mod/AvHBasePlayerWeaponConstants.h" -#include "mod/AvHMarineWeaponConstants.h" -#include "mod/AvHAlienWeaponConstants.h" -#include - -static int tracerCount[ 32 ]; -extern AvHHud gHUD; - -#include "r_studioint.h" -#include "common/com_model.h" - -extern engine_studio_api_t IEngineStudio; - -//extern "C" char PM_FindTextureType( char *name ); -char PM_FindTextureType( char *name ); - -void V_PunchAxis( int axis, float punch ); -void VectorAngles( const float *forward, float *angles ); -Vector UTIL_GetRandomSpreadDir(unsigned int inSeed, int inShotNumber, const Vector& inBaseDirection, const Vector& inRight, const Vector& inUp, const Vector& inSpread); - -extern "C" -{ - -// HLDM -void EV_FireGlock1( struct event_args_s *args ); -void EV_FireGlock2( struct event_args_s *args ); -void EV_FireShotGunSingle( struct event_args_s *args ); -void EV_FireShotGunDouble( struct event_args_s *args ); -void EV_FireMP5( struct event_args_s *args ); -void EV_FireMP52( struct event_args_s *args ); -void EV_FirePython( struct event_args_s *args ); -void EV_FireGauss( struct event_args_s *args ); -void EV_SpinGauss( struct event_args_s *args ); -void EV_Crowbar( struct event_args_s *args ); -void EV_FireCrossbow( struct event_args_s *args ); -void EV_FireCrossbow2( struct event_args_s *args ); -void EV_FireRpg( struct event_args_s *args ); -void EV_EgonFire( struct event_args_s *args ); -void EV_EgonStop( struct event_args_s *args ); -void EV_HornetGunFire( struct event_args_s *args ); -void EV_TripmineFire( struct event_args_s *args ); -void EV_SnarkFire( struct event_args_s *args ); - - -void EV_TrainPitchAdjust( struct event_args_s *args ); -} - -#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) -#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) -#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) -#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) -#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) -#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) -#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) -#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) -#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) -#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) -#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) -#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) - -// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the -// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. -// returns volume of strike instrument (crowbar) to play -float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType, int inSoundProbability) -{ - // hit the world, try to play sound based on texture material type - char chTextureType = CHAR_TEX_CONCRETE; - float fvol; - float fvolbar = 0.0f; - char *rgsz[4]; - int cnt; - float fattn = ATTN_NORM; - int entity; - char *pTextureName; - char texname[ 64 ]; - char szbuffer[ 64 ]; - - if(gEngfuncs.pfnRandomLong(1, inSoundProbability) == 1) - { - - entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); - - // FIXME check if playtexture sounds movevar is set - // - - chTextureType = 0; - - // Player - if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) - { - // hit body - chTextureType = CHAR_TEX_FLESH; - } - else if ( entity == 0 ) - { - // get texture from entity or world (world is ent(0)) - pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); - - if ( pTextureName ) - { - strcpy( texname, pTextureName ); - pTextureName = texname; - - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - { - pTextureName += 2; - } - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - { - pTextureName++; - } - - // '}}' - strcpy( szbuffer, pTextureName ); - szbuffer[ CBTEXTURENAMEMAX - 1 ] = 0; - - // get texture type - chTextureType = PM_FindTextureType( szbuffer ); - } - } - - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: fvol = 0.3; fvolbar = 0.6; - rgsz[0] = "weapons/ric_conc-1.wav"; - rgsz[1] = "weapons/ric_conc-2.wav"; - cnt = 2; - break; - case CHAR_TEX_METAL: fvol = 0.3; fvolbar = 0.3; - rgsz[0] = "weapons/ric_metal-1.wav"; - rgsz[1] = "weapons/ric_metal-2.wav"; - cnt = 2; - break; - case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; - rgsz[0] = "player/pl_dirt1.wav"; - rgsz[1] = "player/pl_dirt2.wav"; - rgsz[2] = "player/pl_dirt3.wav"; - cnt = 3; - break; - case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; - rgsz[0] = "player/pl_duct1.wav"; - rgsz[1] = "player/pl_duct1.wav"; - cnt = 2; - break; - case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; - rgsz[0] = "player/pl_grate1.wav"; - rgsz[1] = "player/pl_grate4.wav"; - cnt = 2; - break; - case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "player/pl_tile1.wav"; - rgsz[1] = "player/pl_tile3.wav"; - rgsz[2] = "player/pl_tile2.wav"; - rgsz[3] = "player/pl_tile4.wav"; - cnt = 4; - break; - case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; - rgsz[0] = "player/pl_slosh1.wav"; - rgsz[1] = "player/pl_slosh3.wav"; - rgsz[2] = "player/pl_slosh2.wav"; - rgsz[3] = "player/pl_slosh4.wav"; - cnt = 4; - break; - case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; - rgsz[0] = "debris/wood1.wav"; - rgsz[1] = "debris/wood2.wav"; - rgsz[2] = "debris/wood3.wav"; - cnt = 3; - break; - case CHAR_TEX_GLASS: - case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "debris/glass1.wav"; - rgsz[1] = "debris/glass2.wav"; - rgsz[2] = "debris/glass3.wav"; - cnt = 3; - break; - case CHAR_TEX_FLESH: - if (iBulletType == BULLET_PLAYER_CROWBAR) - return 0.0; // crowbar already makes this sound - fvol = 1.0; fvolbar = 0.2; - rgsz[0] = "weapons/bullet_hit1.wav"; - rgsz[1] = "weapons/bullet_hit2.wav"; - fattn = 1.0; - cnt = 2; - break; - } - - if(iBulletType == BULLET_MONSTER_9MM) - { - fvol = 0.3; - fvolbar = 0.6; - rgsz[0] = "weapons/a_ric1.wav"; - rgsz[1] = "weapons/a_ric2.wav"; - rgsz[2] = "weapons/a_ric3.wav"; - cnt = 3; - } - - // play material hit sound - gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); - } - - return fvolbar; -} - -char *EV_HLDM_DamageDecal( physent_t *pe ) -{ - static char decalname[ 32 ]; - int idx; - - if ( pe->classnumber == 1 ) - { - idx = gEngfuncs.pfnRandomLong( 0, 2 ); - sprintf( decalname, "{break%i", idx + 1 ); - } - else if ( pe->rendermode != kRenderNormal ) - { - sprintf( decalname, "{bproof1" ); - } - else - { - idx = gEngfuncs.pfnRandomLong( 0, 4 ); - sprintf( decalname, "{shot%i", idx + 1 ); - } - return decalname; -} - -void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName, int inChanceOfSound) -{ - int iRand; - physent_t *pe; - - gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); - - iRand = gEngfuncs.pfnRandomLong(1, inChanceOfSound); - if ( iRand == 1)// not every bullet makes a sound. - { - const float kRicochetVolume = .2f; - int theRandomSound = gEngfuncs.pfnRandomLong(0, 4); - switch(theRandomSound) - { - case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; - case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; - case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; - } - } - - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); - - // Only decal brush models such as the world etc. - if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) - { - if ( CVAR_GET_FLOAT( "r_decals" ) ) - { - gEngfuncs.pEfxAPI->R_DecalShoot( - gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), - gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); - } - } -} - -void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType, int inSoundProbability) -{ - physent_t *pe; - - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); - - if ( pe && pe->solid == SOLID_BSP ) - { - EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ), inSoundProbability); - } -} - -int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) -{ - int tracer = 0; - int i; - qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; - - if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) - { - vec3_t vecTracerSrc; - - if ( player ) - { - vec3_t offset( 0, 0, -4 ); - - // adjust tracer position for player - for ( i = 0; i < 3; i++ ) - { - vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; - } - } - else - { - VectorCopy( vecSrc, vecTracerSrc ); - } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal - tracer = 1; - - switch( iBulletType ) - { - case BULLET_PLAYER_MP5: - case BULLET_MONSTER_MP5: - case BULLET_MONSTER_9MM: - case BULLET_MONSTER_12MM: - default: - EV_CreateTracer( vecTracerSrc, end ); - break; - } - } - - return tracer; -} - - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. -================ -*/ -//void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) -//{ -// int i; -// int iShot; -// int tracer; -// -// // Store off the old count -// gEngfuncs.pEventAPI->EV_PushPMStates(); -// -// gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false, true); -// -// // Now add in all of the players. -// gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); -// -// gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); -// -// for ( iShot = 1; iShot <= cShots; iShot++ ) -// { -// vec3_t vecDir, vecEnd; -// -// float x, y, z; -// //We randomize for the Shotgun. -// if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) -// { -// do { -// x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); -// y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); -// z = x*x+y*y; -// } while (z > 1); -// -// for ( i = 0 ; i < 3; i++ ) -// { -// vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; -// vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; -// } -// }//But other guns already have their spread randomized in the synched spread. -// else -// { -// -// for ( i = 0 ; i < 3; i++ ) -// { -// vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; -// vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; -// } -// } -// -// // For debugging -// //gEngfuncs.pEfxAPI->R_TracerEffect(vecSrc, vecEnd); -// -// pmtrace_t tr; -// gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); -// -// //gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); -// -// tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); -// -// physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); -// bool thePlayBulletHitEffect = /*true;//*/!tr.inwater && pe && !pe->player; -// -// // do damage, paint decals -// if ( tr.fraction != 1.0 ) -// { -// switch(iBulletType) -// { -// default: -// case BULLET_PLAYER_9MM: -// -// //EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); -// EV_HLDM_DecalGunshot( &tr, iBulletType ); -// -// break; -// case BULLET_PLAYER_MP5: -// -// if ( !tracer ) -// { -// //EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); -// EV_HLDM_DecalGunshot( &tr, iBulletType ); -// -// // Only play weapon effects if we hit the -// if(thePlayBulletHitEffect) -// { -// //int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); -// //TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, .6f, theSprite, kRenderGlow, kRenderFxNoDissipation, .5, 1.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); -// //theTempEntity->entity.curstate.framerate = 30; -// -// gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 6, 10, 100); -// } -// } -// break; -// case BULLET_PLAYER_BUCKSHOT: -// if ( !tracer ) -// { -// EV_HLDM_DecalGunshot( &tr, iBulletType ); -// -// // Add cool shotgun effect here -// //gEngfuncs.pEfxAPI->R_RocketTrail(vecSrc, tr.endpos, 1); -// gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); -// -// //if(thePlayBulletHitEffect) -// //{ -// // int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); -// // TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .5, 1.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); -// // theTempEntity->entity.curstate.framerate = 30; -// //} -// -// gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 5, 100, 200); -// } -// break; -// case BULLET_PLAYER_357: -// if ( !tracer ) -// { -// //EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); -// EV_HLDM_DecalGunshot( &tr, iBulletType ); -// -// if(thePlayBulletHitEffect) -// { -// // Make the smoke stick out of the target or wall just a little bit to avoid crappy sprite-in-wall effect -// Vector theEndPos = tr.endpos - 20*vecDir; -// int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); -// Vector theUp(0, 0, 30); -// TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(theEndPos, theUp, .3f, theSprite, kRenderTransAdd, kRenderFxFadeSlow, .3, 0.6, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); -// if(theTempEntity) -// { -// theTempEntity->entity.curstate.framerate = 50; -// } -// -// //// Create rising area of smoke above gun wielder -// //if(gEngfuncs.pfnRandomLong(0, 3) == 0) -// //{ -// // vec3_t theSource; -// // VectorCopy(vecSrc, theSource); -// // theSource.z += 60; -// // theSource.z += 60; -// // -// // theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .3, 3.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); -// // theTempEntity->entity.curstate.framerate = 30; -// //} -// -// // TODO: Add more here like splinters of wall and plaster -// gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 12, 100, 200); -// } -// } -// break; -// case BULLET_MONSTER_9MM: -// break; -// } -// } -// } -// -// gEngfuncs.pEventAPI->EV_PopPMStates(); -//} - -/* -================ -EV_HLDM_FireBulletsPlayer - -Client-side prediction friendly version of EV_HLDM_FireBullets -================ -*/ -void EV_HLDM_FireBulletsPlayer( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, Vector inSpread, int inRandomSeed) -{ -// int i; - int iShot; - int tracer; - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false, true); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - for ( iShot = 1; iShot <= cShots; iShot++ ) - { - vec3_t vecDir, vecEnd; - -// float x, y, z; -// //We randomize for the Shotgun. -// if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) -// { -// do { -// x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); -// y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); -// z = x*x+y*y; -// } while (z > 1); -// -// for ( i = 0 ; i < 3; i++ ) -// { -// vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; -// vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; -// } -// }//But other guns already have their spread randomized in the synched spread. -// else -// { - - //for ( i = 0 ; i < 3; i++ ) - //{ - // vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; - // vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; - //} - vecDir = UTIL_GetRandomSpreadDir(inRandomSeed, iShot, vecDirShooting, right, up, inSpread); - VectorMA(vecSrc, flDistance, vecDir, vecEnd); - //vecEnd = vecSrc + flDistance*vecDir; -// } - - // For debugging - //gEngfuncs.pEfxAPI->R_TracerEffect(vecSrc, vecEnd); - - pmtrace_t tr; - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - //gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); - - tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); - - physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - bool thePlayBulletHitEffect = /*true;//*/!tr.inwater && pe && !pe->player; - int theSoundProbability = 2; - - // do damage, paint decals - if ( tr.fraction != 1.0 ) - { - switch(iBulletType) - { - default: - case BULLET_PLAYER_9MM: - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); - EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); - break; - - case BULLET_PLAYER_MP5: - - if ( !tracer ) - { - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); - - theSoundProbability = 8; - EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); - - // Only play weapon effects if we hit the - if(thePlayBulletHitEffect) - { - // Make the smoke stick out of the target or wall just a little bit to avoid crappy sprite-in-wall effect - Vector theEndPos = tr.endpos - 20*vecDir; - int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); - Vector theUp(0, 0, 30); - TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(theEndPos, theUp, .3f, theSprite, kRenderTransAdd, kRenderFxFadeSlow, .1, 0.6, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); - if(theTempEntity) - { - theTempEntity->entity.curstate.framerate = 50; - } - - gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 6, 10, 100); - } - } - break; - case BULLET_PLAYER_BUCKSHOT: - if ( !tracer ) - { - theSoundProbability = BALANCE_VAR(kSGBulletsPerShot)/2; - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); - - theSoundProbability = BALANCE_VAR(kSGBulletsPerShot)/2; - EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); - - if(thePlayBulletHitEffect) - { - // Add cool shotgun effect here - //gEngfuncs.pEfxAPI->R_RocketTrail(vecSrc, tr.endpos, 1); - gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); - - //if(thePlayBulletHitEffect) - //{ - // int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); - // TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .5, 1.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); - // theTempEntity->entity.curstate.framerate = 30; - //} - - gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 5, 100, 200); - } - } - break; - case BULLET_PLAYER_357: - if ( !tracer ) - { - theSoundProbability = 1; - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); - EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); - - if(thePlayBulletHitEffect) - { - // Make the smoke stick out of the target or wall just a little bit to avoid crappy sprite-in-wall effect - Vector theEndPos = tr.endpos - 20*vecDir; - int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); - Vector theUp(0, 0, 30); - TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(theEndPos, theUp, .3f, theSprite, kRenderTransAdd, kRenderFxFadeSlow, .15, 0.6, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); - if(theTempEntity) - { - theTempEntity->entity.curstate.framerate = 50; - } - - //// Create rising area of smoke above gun wielder - //if(gEngfuncs.pfnRandomLong(0, 3) == 0) - //{ - // vec3_t theSource; - // VectorCopy(vecSrc, theSource); - // theSource.z += 60; - // theSource.z += 60; - // - // theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .3, 3.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); - // theTempEntity->entity.curstate.framerate = 30; - //} - - // TODO: Add more here like splinters of wall and plaster - gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 12, 100, 200); - } - } - break; - case BULLET_MONSTER_9MM: - if(!tracer) - { - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); - //EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); - - // Only play weapon effects if we hit the - if(thePlayBulletHitEffect) - { - int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kSpikeGunHitSprite); - TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, .6f, theSprite, kRenderTransAdd, kRenderFxNoDissipation, .5f, .4f, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); - if(theTempEntity) - { - theTempEntity->entity.curstate.framerate = 30; - } - } - } - break; - } - } - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} - - - -//====================== -// GLOCK START -//====================== -//void EV_FireGlock1( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// vec3_t angles; -// vec3_t velocity; -// int empty; -// -// vec3_t ShellVelocity; -// vec3_t ShellOrigin; -// int shell; -// vec3_t vecSrc, vecAiming; -// vec3_t up, right, forward; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// VectorCopy( args->angles, angles ); -// VectorCopy( args->velocity, velocity ); -// -// empty = args->bparam1; -// AngleVectors( angles, forward, right, up ); -// -// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell -// -// if ( EV_IsLocal( idx ) ) -// { -// EV_MuzzleFlash(); -// gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); -// -// V_PunchAxis( 0, -2.0 ); -// } -// -// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); -// -// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); -// -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); -// -// EV_GetGunPosition( args, vecSrc, origin ); -// -// VectorCopy( forward, vecAiming ); -// -// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2); -//} - -//void EV_FireGlock2( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// vec3_t angles; -// vec3_t velocity; -// -// vec3_t ShellVelocity; -// vec3_t ShellOrigin; -// int shell; -// vec3_t vecSrc, vecAiming; -// vec3_t vecSpread; -// vec3_t up, right, forward; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// VectorCopy( args->angles, angles ); -// VectorCopy( args->velocity, velocity ); -// -// AngleVectors( angles, forward, right, up ); -// -// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell -// -// if ( EV_IsLocal( idx ) ) -// { -// // Add muzzle flash to current weapon model -// EV_MuzzleFlash(); -// gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); -// -// V_PunchAxis( 0, -2.0 ); -// } -// -// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); -// -// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); -// -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); -// -// EV_GetGunPosition( args, vecSrc, origin ); -// -// VectorCopy( forward, vecAiming ); -// -// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); -// -//} -//====================== -// GLOCK END -//====================== - -//====================== -// SHOTGUN START -//====================== -//void EV_FireShotGunDouble( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// vec3_t angles; -// vec3_t velocity; -// -// int j; -// vec3_t ShellVelocity; -// vec3_t ShellOrigin; -// int shell; -// vec3_t vecSrc, vecAiming; -// vec3_t vecSpread; -// vec3_t up, right, forward; -// float flSpread = 0.01; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// VectorCopy( args->angles, angles ); -// VectorCopy( args->velocity, velocity ); -// -// AngleVectors( angles, forward, right, up ); -// -// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell -// -// if ( EV_IsLocal( idx ) ) -// { -// // Add muzzle flash to current weapon model -// EV_MuzzleFlash(); -// gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 ); -// V_PunchAxis( 0, -10.0 ); -// } -// -// for ( j = 0; j < 2; j++ ) -// { -// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); -// -// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); -// } -// -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); -// -// EV_GetGunPosition( args, vecSrc, origin ); -// VectorCopy( forward, vecAiming ); -// -// if ( gEngfuncs.GetMaxClients() > 1 ) -// { -// EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.17365, 0.04362 ); -// } -// else -// { -// EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); -// } -// -// if ( EV_IsLocal( idx ) ) -// { -// V_PunchAxis( 0, -10.0 ); -// } -//} - -//void EV_FireShotGunSingle( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// vec3_t angles; -// vec3_t velocity; -// -// vec3_t ShellVelocity; -// vec3_t ShellOrigin; -// int shell; -// vec3_t vecSrc, vecAiming; -// vec3_t vecSpread; -// vec3_t up, right, forward; -// float flSpread = 0.01; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// VectorCopy( args->angles, angles ); -// VectorCopy( args->velocity, velocity ); -// -// AngleVectors( angles, forward, right, up ); -// -// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell -// -// if ( EV_IsLocal( idx ) ) -// { -// // Add muzzle flash to current weapon model -// EV_MuzzleFlash(); -// gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 ); -// -// V_PunchAxis( 0, -5.0 ); -// } -// -// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); -// -// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); -// -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); -// -// EV_GetGunPosition( args, vecSrc, origin ); -// VectorCopy( forward, vecAiming ); -// -// if ( gEngfuncs.GetMaxClients() > 1 ) -// { -// EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.04362 ); -// } -// else -// { -// EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); -// } -//} -//====================== -// SHOTGUN END -//====================== - -//====================== -// MP5 START -//====================== -//void EV_FireMP5( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// vec3_t angles; -// vec3_t velocity; -// -// vec3_t ShellVelocity; -// vec3_t ShellOrigin; -// int shell; -// vec3_t vecSrc, vecAiming; -// vec3_t up, right, forward; -// float flSpread = 0.01; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// VectorCopy( args->angles, angles ); -// VectorCopy( args->velocity, velocity ); -// -// AngleVectors( angles, forward, right, up ); -// -// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell -// -// if ( EV_IsLocal( idx ) ) -// { -// // Add muzzle flash to current weapon model -// EV_MuzzleFlash(); -// gEngfuncs.pEventAPI->EV_WeaponAnimation( MG_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); -// } -// -// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); -// -// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); -// -// switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) -// { -// case 0: -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); -// break; -// case 1: -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); -// break; -// } -// -// EV_GetGunPosition( args, vecSrc, origin ); -// VectorCopy( forward, vecAiming ); -// -// if ( gEngfuncs.GetMaxClients() > 1 ) -// { -// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); -// } -// else -// { -// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); -// } -//} - -// We only predict the animation and sound -// The grenade is still launched from the server. -//void EV_FireMP52( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// -// if ( EV_IsLocal( idx ) ) -// { -// // NOTE: Put this back in if needed <<< cgc >>> -// //gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 ); -// //V_PunchAxis( 0, -10 ); -// } -// -// switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) -// { -// case 0: -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); -// break; -// case 1: -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); -// break; -// } -//} -//====================== -// MP5 END -//====================== - -//====================== -// PHYTON START -// ( .357 ) -//====================== -//void EV_FirePython( event_args_t *args ) -//{ -// int idx; -// vec3_t origin; -// vec3_t angles; -// vec3_t velocity; -// -// vec3_t vecSrc, vecAiming; -// vec3_t up, right, forward; -// float flSpread = 0.01; -// -// idx = args->entindex; -// VectorCopy( args->origin, origin ); -// VectorCopy( args->angles, angles ); -// VectorCopy( args->velocity, velocity ); -// -// AngleVectors( angles, forward, right, up ); -// -// if ( EV_IsLocal( idx ) ) -// { -// // Python uses different body in multiplayer versus single player -// int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; -// -// // Add muzzle flash to current weapon model -// EV_MuzzleFlash(); -// gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 ); -// -// V_PunchAxis( 0, -10.0 ); -// } -// -// switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) -// { -// case 0: -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); -// break; -// case 1: -// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); -// break; -// } -// -// EV_GetGunPosition( args, vecSrc, origin ); -// -// VectorCopy( forward, vecAiming ); -// -// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); -//} -//====================== -// PHYTON END -// ( .357 ) -//====================== - -//====================== -// GAUSS START -//====================== -#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch - -void EV_SpinGauss( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - int iSoundState = 0; - - int pitch; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - pitch = args->iparam1; - - iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0; - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); -} - -/* -============================== -EV_StopPreviousGauss - -============================== -*/ -void EV_StopPreviousGauss( int idx ) -{ - // Make sure we don't have a gauss spin event in the queue for this guy - gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); -} - -void EV_FireGauss( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - float flDamage = args->fparam1; - int primaryfire = args->bparam1; - - int m_fPrimaryFire = args->bparam1; - int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - vec3_t vecSrc; - vec3_t vecDest; - edict_t *pentIgnore; - pmtrace_t tr, beam_tr; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - physent_t *pEntity; - int m_iBeam, m_iGlow, m_iBalls; - vec3_t up, right, forward; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - if ( args->bparam2 ) - { - EV_StopPreviousGauss( idx ); - return; - } - -// Con_Printf( "Firing gauss with %f\n", flDamage ); - EV_GetGunPosition( args, vecSrc, origin ); - - m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); - m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); - - AngleVectors( angles, forward, right, up ); - - VectorMA( vecSrc, 8192, forward, vecDest ); - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -2.0 ); - gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); - } - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); - - while (flDamage > 10 && nMaxHits > 0) - { - nMaxHits--; - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - if ( tr.allsolid ) - break; - - if (fFirstBeam) - { - if ( EV_IsLocal( idx ) ) - { - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - } - fFirstBeam = 0; - - gEngfuncs.pEfxAPI->R_BeamEntPoint( - idx | 0x1000, - tr.endpos, - m_iBeam, - 0.1, - m_fPrimaryFire ? 1.0 : 2.5, - 0.0, - m_fPrimaryFire ? 128.0 : flDamage, - 0, - 0, - 0, - m_fPrimaryFire ? 255 : 255, - m_fPrimaryFire ? 128 : 255, - m_fPrimaryFire ? 0 : 255 - ); - } - else - { - gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, - tr.endpos, - m_iBeam, - 0.1, - m_fPrimaryFire ? 1.0 : 2.5, - 0.0, - m_fPrimaryFire ? 128.0 : flDamage, - 0, - 0, - 0, - m_fPrimaryFire ? 255 : 255, - m_fPrimaryFire ? 128 : 255, - m_fPrimaryFire ? 0 : 255 - ); - } - - pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - if ( pEntity == NULL ) - break; - - if ( pEntity->solid == SOLID_BSP ) - { - float n; - - pentIgnore = NULL; - - n = -DotProduct( tr.plane.normal, forward ); - - if (n < 0.5) // 60 degrees - { - // ALERT( at_console, "reflect %f\n", n ); - // reflect - vec3_t r; - - VectorMA( forward, 2.0 * n, tr.plane.normal, r ); - - flMaxFrac = flMaxFrac - tr.fraction; - - VectorCopy( r, forward ); - - VectorMA( tr.endpos, 8.0, forward, vecSrc ); - VectorMA( vecSrc, 8192.0, forward, vecDest ); - - gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); - - vec3_t fwd; - VectorAdd( tr.endpos, tr.plane.normal, fwd ); - - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 100 ); - - // lose energy - if ( n == 0 ) - { - n = 0.1; - } - - flDamage = flDamage * (1 - n); - - } - else - { - // tunnel - EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); - - gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); - - // limit it to one hole punch - if (fHasPunched) - { - break; - } - fHasPunched = 1; - - // try punching through wall if secondary attack (primary is incapable of breaking through) - if ( !m_fPrimaryFire ) - { - vec3_t start; - - VectorMA( tr.endpos, 8.0, forward, start ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); - - if ( !beam_tr.allsolid ) - { - vec3_t delta; - float n; - - // trace backwards to find exit point - - gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); - - VectorSubtract( beam_tr.endpos, tr.endpos, delta ); - - n = Length( delta ); - - if (n < flDamage) - { - if (n == 0) - n = 1; - flDamage -= n; - - // absorption balls - { - vec3_t fwd; - VectorSubtract( tr.endpos, forward, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 100 ); - } - - //////////////////////////////////// WHAT TO DO HERE - // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); - - gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); - - // balls - { - vec3_t fwd; - VectorSubtract( beam_tr.endpos, forward, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, - 255, 40 ); - } - - VectorAdd( beam_tr.endpos, forward, vecSrc ); - } - } - else - { - flDamage = 0; - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); - } - else - { - if ( m_fPrimaryFire ) - { - // slug doesn't punch through ever with primary - // fire, so leave a little glowy bit and make some balls - gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); - - { - vec3_t fwd; - VectorAdd( tr.endpos, tr.plane.normal, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 200 ); - } - } - - flDamage = 0; - } - } - } - else - { - VectorAdd( tr.endpos, forward, vecSrc ); - } - } -} -//====================== -// GAUSS END -//====================== - -//====================== -// CROWBAR START -//====================== - -enum crowbar_e { - CROWBAR_IDLE = 0, - CROWBAR_DRAW, - CROWBAR_HOLSTER, - CROWBAR_ATTACK1HIT, - CROWBAR_ATTACK1MISS, - CROWBAR_ATTACK2MISS, - CROWBAR_ATTACK2HIT, - CROWBAR_ATTACK3MISS, - CROWBAR_ATTACK3HIT -}; - -int g_iSwing; - -//Only predict the miss sounds, hit sounds are still played -//server side, so players don't get the wrong idea. -void EV_Crowbar( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - //Play Swing sound - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); - - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); - - switch( (g_iSwing++) % 3 ) - { - case 0: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK1MISS, 1 ); break; - case 1: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK2MISS, 1 ); break; - case 2: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK3MISS, 1 ); break; - } - } -} -//====================== -// CROWBAR END -//====================== - -//====================== -// CROSSBOW END -//====================== -enum crossbow_e { - CROSSBOW_IDLE1 = 0, // full - CROSSBOW_IDLE2, // empty - CROSSBOW_FIDGET1, // full - CROSSBOW_FIDGET2, // empty - CROSSBOW_FIRE1, // full - CROSSBOW_FIRE2, // reload - CROSSBOW_FIRE3, // empty - CROSSBOW_RELOAD, // from empty - CROSSBOW_DRAW1, // full - CROSSBOW_DRAW2, // empty - CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2, // empty -}; - -//===================== -// EV_BoltCallback -// This function is used to correct the origin and angles -// of the bolt, so it looks like it's stuck on the wall. -//===================== -void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) -{ - ent->entity.origin = ent->entity.baseline.vuser1; - ent->entity.angles = ent->entity.baseline.vuser2; -} - -void EV_FireCrossbow2( event_args_t *args ) -{ - vec3_t vecSrc, vecEnd; - vec3_t up, right, forward; - pmtrace_t tr; - - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - EV_GetGunPosition( args, vecSrc, origin ); - - VectorMA( vecSrc, 8192, forward, vecEnd ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - - if ( EV_IsLocal( idx ) ) - { - if ( args->iparam1 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); - else if ( args->iparam2 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); - } - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - //We hit something - if ( tr.fraction < 1.0 ) - { - physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - - //Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ). - if ( pe->solid != SOLID_BSP ) - { - switch( gEngfuncs.pfnRandomLong(0,1) ) - { - case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; - } - } - //Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though. - else if ( pe->rendermode == kRenderNormal ) - { - gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, PITCH_NORM ); - - //Not underwater, do some sparks... - if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) - gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); - - vec3_t vBoltAngles; - int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" ); - - VectorAngles( forward, vBoltAngles ); - - TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); - - if ( bolt ) - { - bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function. - bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit - bolt->entity.baseline.vuser2 = vBoltAngles; //Look forward! - bolt->callback = EV_BoltCallback; //So we can set the angles and origin back. (Stick the bolt to the wall) - } - } - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} - -//TODO: Fully predict the fliying bolt. -void EV_FireCrossbow( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - { - if ( args->iparam1 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); - else if ( args->iparam2 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); - - V_PunchAxis( 0, -2.0 ); - } -} -//====================== -// CROSSBOW END -//====================== - -//====================== -// RPG START -//====================== -enum rpg_e { - RPG_IDLE = 0, - RPG_FIDGET, - RPG_RELOAD, // to reload - RPG_FIRE2, // to empty - RPG_HOLSTER1, // loaded - RPG_DRAW1, // loaded - RPG_HOLSTER2, // unloaded - RPG_DRAW_UL, // unloaded - RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget -}; - -void EV_FireRpg( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 ); - - V_PunchAxis( 0, -5.0 ); - } -} -//====================== -// RPG END -//====================== - -//====================== -// EGON END -//====================== -enum egon_e { - EGON_IDLE1 = 0, - EGON_FIDGET1, - EGON_ALTFIREON, - EGON_ALTFIRECYCLE, - EGON_ALTFIREOFF, - EGON_FIRE1, - EGON_FIRE2, - EGON_FIRE3, - EGON_FIRE4, - EGON_DRAW, - EGON_HOLSTER -}; - -int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; -int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; - -enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; -enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; - -#define EGON_PRIMARY_VOLUME 450 -#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" -#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" -#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" - -//@2014 -#ifdef ARRAYSIZE -#undef ARRAYSIZE -#endif - -#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) - -BEAM *pBeam; -BEAM *pBeam2; - -void EV_EgonFire( event_args_t *args ) -{ - int idx, iFireState, iFireMode; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - iFireState = args->iparam1; - iFireMode = args->iparam2; - int iStartup = args->bparam1; - - - if ( iStartup ) - { - if ( iFireMode == FIRE_WIDE ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); - else - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); - } - else - { - if ( iFireMode == FIRE_WIDE ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); - else - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); - } - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); - - if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 ) - { - vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; - pmtrace_t tr; - - cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); - - if ( pl ) - { - VectorCopy( gHUD.m_vecAngles, angles ); - - AngleVectors( angles, forward, right, up ); - - EV_GetGunPosition( args, vecSrc, pl->origin ); - - VectorMA( vecSrc, 2048, forward, vecEnd ); - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE ); - - float r = 50.0f; - float g = 50.0f; - float b = 125.0f; - - if ( IEngineStudio.IsHardware() ) - { - r /= 100.0f; - g /= 100.0f; - } - - - pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); - - if ( pBeam ) - pBeam->flags |= ( FBEAM_SINENOISE ); - - pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); - } - } -} - -void EV_EgonStop( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy ( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); - - if ( args->iparam1 ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 ); - - if ( EV_IsLocal( idx ) ) - { - if ( pBeam ) - { - pBeam->die = 0.0; - pBeam = NULL; - } - - - if ( pBeam2 ) - { - pBeam2->die = 0.0; - pBeam2 = NULL; - } - } -} -//====================== -// EGON END -//====================== - -//====================== -// HORNET START -//====================== -enum hgun_e { - HGUN_IDLE1 = 0, - HGUN_FIDGETSWAY, - HGUN_FIDGETSHAKE, - HGUN_DOWN, - HGUN_UP, - HGUN_SHOOT -}; - -void EV_HornetGunFire( event_args_t *args ) -{ - int idx, iFireMode; - vec3_t origin, angles, vecSrc, forward, right, up; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - iFireMode = args->iparam1; - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, gEngfuncs.pfnRandomLong ( 0, 2 ) ); - gEngfuncs.pEventAPI->EV_WeaponAnimation ( HGUN_SHOOT, 1 ); - } - - switch ( gEngfuncs.pfnRandomLong ( 0 , 2 ) ) - { - case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); break; - case 1: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); break; - case 2: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); break; - } -} -//====================== -// HORNET END -//====================== - -//====================== -// TRIPMINE START -//====================== -enum tripmine_e { - TRIPMINE_IDLE1 = 0, - TRIPMINE_IDLE2, - TRIPMINE_ARM1, - TRIPMINE_ARM2, - TRIPMINE_FIDGET, - TRIPMINE_HOLSTER, - TRIPMINE_DRAW, - TRIPMINE_WORLD, - TRIPMINE_GROUND, -}; - -//We only check if it's possible to put a trip mine -//and if it is, then we play the animation. Server still places it. -void EV_TripmineFire( event_args_t *args ) -{ - int idx; - vec3_t vecSrc, angles, view_ofs, forward; - pmtrace_t tr; - - idx = args->entindex; - VectorCopy( args->origin, vecSrc ); - VectorCopy( args->angles, angles ); - - AngleVectors ( angles, forward, NULL, NULL ); - - if ( !EV_IsLocal ( idx ) ) - return; - - // Grab predicted result for local player - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - - vecSrc = vecSrc + view_ofs; - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); - - //Hit something solid - if ( tr.fraction < 1.0 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} -//====================== -// TRIPMINE END -//====================== - -//====================== -// SQUEAK START -//====================== -enum squeak_e { - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -#define VEC_HULL_MIN Vector(-16, -16, -36) -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) - -void EV_SnarkFire( event_args_t *args ) -{ - int idx; - vec3_t vecSrc, angles, view_ofs, forward; - pmtrace_t tr; - - idx = args->entindex; - VectorCopy( args->origin, vecSrc ); - VectorCopy( args->angles, angles ); - - AngleVectors ( angles, forward, NULL, NULL ); - - if ( !EV_IsLocal ( idx ) ) - return; - - if ( args->ducking ) - vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr ); - - //Find space to drop the thing. - if ( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( SQUEAK_THROW, 0 ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} -//====================== -// SQUEAK END -//====================== - -void EV_TrainPitchAdjust( event_args_t *args ) -{ - int idx; - vec3_t origin; - - unsigned short us_params; - int noise; - float m_flVolume; - int pitch; - int stop; - - char sz[ 256 ]; - - idx = args->entindex; - - VectorCopy( args->origin, origin ); - - us_params = (unsigned short)args->iparam1; - stop = args->bparam1; - - m_flVolume = (float)(us_params & 0x003f)/40.0; - noise = (int)(((us_params) >> 12 ) & 0x0007); - pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); - - switch ( noise ) - { - case 1: strcpy( sz, "plats/ttrain1.wav"); break; - case 2: strcpy( sz, "plats/ttrain2.wav"); break; - case 3: strcpy( sz, "plats/ttrain3.wav"); break; - case 4: strcpy( sz, "plats/ttrain4.wav"); break; - case 5: strcpy( sz, "plats/ttrain6.wav"); break; - case 6: strcpy( sz, "plats/ttrain7.wav"); break; - default: - // no sound - strcpy( sz, "" ); - return; - } - - if ( stop ) - { - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); - } - else - { - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); - } -} - -int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) -{ - return 0; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//#include "hud.h" +#include "mod/AvHHud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "common/entity_types.h" +#include "common/usercmd.h" +#include "pm_shared/pm_defs.h" +#include "pm_shared/pm_materials.h" + +#include "eventscripts.h" +#include "ev_hldm.h" + +#include "common/r_efx.h" +#include "common/event_api.h" +#include "common/event_args.h" +#include "in_defs.h" +#include "mod/AvHBasePlayerWeaponConstants.h" +#include "mod/AvHMarineWeaponConstants.h" +#include "mod/AvHAlienWeaponConstants.h" +#include + +static int tracerCount[ 32 ]; +extern AvHHud gHUD; + +#include "r_studioint.h" +#include "common/com_model.h" + +extern engine_studio_api_t IEngineStudio; + +//extern "C" char PM_FindTextureType( char *name ); +char PM_FindTextureType( char *name ); + +void V_PunchAxis( int axis, float punch ); +void VectorAngles( const float *forward, float *angles ); +Vector UTIL_GetRandomSpreadDir(unsigned int inSeed, int inShotNumber, const Vector& inBaseDirection, const Vector& inRight, const Vector& inUp, const Vector& inSpread); + +extern "C" +{ + +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) +#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) +#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) +#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) +#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) +#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) +#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) +#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) +#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) +#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) +#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) +#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) + +// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the +// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. +// returns volume of strike instrument (crowbar) to play +float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType, int inSoundProbability) +{ + // hit the world, try to play sound based on texture material type + char chTextureType = CHAR_TEX_CONCRETE; + float fvol; + float fvolbar = 0.0f; + char *rgsz[4]; + int cnt; + float fattn = ATTN_NORM; + int entity; + char *pTextureName; + char texname[ 64 ]; + char szbuffer[ 64 ]; + + if(gEngfuncs.pfnRandomLong(1, inSoundProbability) == 1) + { + + entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); + + // FIXME check if playtexture sounds movevar is set + // + + chTextureType = 0; + + // Player + if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) + { + // hit body + chTextureType = CHAR_TEX_FLESH; + } + else if ( entity == 0 ) + { + // get texture from entity or world (world is ent(0)) + pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); + + if ( pTextureName ) + { + strcpy( texname, pTextureName ); + pTextureName = texname; + + // strip leading '-0' or '+0~' or '{' or '!' + if (*pTextureName == '-' || *pTextureName == '+') + { + pTextureName += 2; + } + + if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + { + pTextureName++; + } + + // '}}' + strcpy( szbuffer, pTextureName ); + szbuffer[ CBTEXTURENAMEMAX - 1 ] = 0; + + // get texture type + chTextureType = PM_FindTextureType( szbuffer ); + } + } + + switch (chTextureType) + { + default: + case CHAR_TEX_CONCRETE: fvol = 0.3; fvolbar = 0.6; + rgsz[0] = "weapons/ric_conc-1.wav"; + rgsz[1] = "weapons/ric_conc-2.wav"; + cnt = 2; + break; + case CHAR_TEX_METAL: fvol = 0.3; fvolbar = 0.3; + rgsz[0] = "weapons/ric_metal-1.wav"; + rgsz[1] = "weapons/ric_metal-2.wav"; + cnt = 2; + break; + case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; + rgsz[0] = "player/pl_dirt1.wav"; + rgsz[1] = "player/pl_dirt2.wav"; + rgsz[2] = "player/pl_dirt3.wav"; + cnt = 3; + break; + case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; + rgsz[0] = "player/pl_duct1.wav"; + rgsz[1] = "player/pl_duct1.wav"; + cnt = 2; + break; + case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; + rgsz[0] = "player/pl_grate1.wav"; + rgsz[1] = "player/pl_grate4.wav"; + cnt = 2; + break; + case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; + rgsz[0] = "player/pl_tile1.wav"; + rgsz[1] = "player/pl_tile3.wav"; + rgsz[2] = "player/pl_tile2.wav"; + rgsz[3] = "player/pl_tile4.wav"; + cnt = 4; + break; + case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; + rgsz[0] = "player/pl_slosh1.wav"; + rgsz[1] = "player/pl_slosh3.wav"; + rgsz[2] = "player/pl_slosh2.wav"; + rgsz[3] = "player/pl_slosh4.wav"; + cnt = 4; + break; + case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; + rgsz[0] = "debris/wood1.wav"; + rgsz[1] = "debris/wood2.wav"; + rgsz[2] = "debris/wood3.wav"; + cnt = 3; + break; + case CHAR_TEX_GLASS: + case CHAR_TEX_COMPUTER: + fvol = 0.8; fvolbar = 0.2; + rgsz[0] = "debris/glass1.wav"; + rgsz[1] = "debris/glass2.wav"; + rgsz[2] = "debris/glass3.wav"; + cnt = 3; + break; + case CHAR_TEX_FLESH: + if (iBulletType == BULLET_PLAYER_CROWBAR) + return 0.0; // crowbar already makes this sound + fvol = 1.0; fvolbar = 0.2; + rgsz[0] = "weapons/bullet_hit1.wav"; + rgsz[1] = "weapons/bullet_hit2.wav"; + fattn = 1.0; + cnt = 2; + break; + } + + if(iBulletType == BULLET_MONSTER_9MM) + { + fvol = 0.3; + fvolbar = 0.6; + rgsz[0] = "weapons/a_ric1.wav"; + rgsz[1] = "weapons/a_ric2.wav"; + rgsz[2] = "weapons/a_ric3.wav"; + cnt = 3; + } + + // play material hit sound + gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); + } + + return fvolbar; +} + +char *EV_HLDM_DamageDecal( physent_t *pe ) +{ + static char decalname[ 32 ]; + int idx; + + if ( pe->classnumber == 1 ) + { + idx = gEngfuncs.pfnRandomLong( 0, 2 ); + sprintf( decalname, "{break%i", idx + 1 ); + } + else if ( pe->rendermode != kRenderNormal ) + { + sprintf( decalname, "{bproof1" ); + } + else + { + idx = gEngfuncs.pfnRandomLong( 0, 4 ); + sprintf( decalname, "{shot%i", idx + 1 ); + } + return decalname; +} + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName, int inChanceOfSound) +{ + int iRand; + physent_t *pe; + + gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); + + iRand = gEngfuncs.pfnRandomLong(1, inChanceOfSound); + if ( iRand == 1)// not every bullet makes a sound. + { + const float kRicochetVolume = .2f; + int theRandomSound = gEngfuncs.pfnRandomLong(0, 4); + switch(theRandomSound) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; + case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", kRicochetVolume, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + // Only decal brush models such as the world etc. + if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) + { + if ( CVAR_GET_FLOAT( "r_decals" ) ) + { + gEngfuncs.pEfxAPI->R_DecalShoot( + gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), + gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); + } + } +} + +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType, int inSoundProbability) +{ + physent_t *pe; + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + if ( pe && pe->solid == SOLID_BSP ) + { + EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ), inSoundProbability); + } +} + +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) +{ + int tracer = 0; + int i; + qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; + + if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) + { + vec3_t vecTracerSrc; + + if ( player ) + { + vec3_t offset( 0, 0, -4 ); + + // adjust tracer position for player + for ( i = 0; i < 3; i++ ) + { + vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; + } + } + else + { + VectorCopy( vecSrc, vecTracerSrc ); + } + + if ( iTracerFreq != 1 ) // guns that always trace also always decal + tracer = 1; + + switch( iBulletType ) + { + case BULLET_PLAYER_MP5: + case BULLET_MONSTER_MP5: + case BULLET_MONSTER_9MM: + case BULLET_MONSTER_12MM: + default: + EV_CreateTracer( vecTracerSrc, end ); + break; + } + } + + return tracer; +} + + +/* +================ +FireBullets + +Go to the trouble of combining multiple pellets into a single damage call. +================ +*/ +//void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) +//{ +// int i; +// int iShot; +// int tracer; +// +// // Store off the old count +// gEngfuncs.pEventAPI->EV_PushPMStates(); +// +// gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false, true); +// +// // Now add in all of the players. +// gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); +// +// gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); +// +// for ( iShot = 1; iShot <= cShots; iShot++ ) +// { +// vec3_t vecDir, vecEnd; +// +// float x, y, z; +// //We randomize for the Shotgun. +// if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) +// { +// do { +// x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); +// y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); +// z = x*x+y*y; +// } while (z > 1); +// +// for ( i = 0 ; i < 3; i++ ) +// { +// vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; +// vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; +// } +// }//But other guns already have their spread randomized in the synched spread. +// else +// { +// +// for ( i = 0 ; i < 3; i++ ) +// { +// vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; +// vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; +// } +// } +// +// // For debugging +// //gEngfuncs.pEfxAPI->R_TracerEffect(vecSrc, vecEnd); +// +// pmtrace_t tr; +// gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); +// +// //gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); +// +// tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); +// +// physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); +// bool thePlayBulletHitEffect = /*true;//*/!tr.inwater && pe && !pe->player; +// +// // do damage, paint decals +// if ( tr.fraction != 1.0 ) +// { +// switch(iBulletType) +// { +// default: +// case BULLET_PLAYER_9MM: +// +// //EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); +// EV_HLDM_DecalGunshot( &tr, iBulletType ); +// +// break; +// case BULLET_PLAYER_MP5: +// +// if ( !tracer ) +// { +// //EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); +// EV_HLDM_DecalGunshot( &tr, iBulletType ); +// +// // Only play weapon effects if we hit the +// if(thePlayBulletHitEffect) +// { +// //int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); +// //TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, .6f, theSprite, kRenderGlow, kRenderFxNoDissipation, .5, 1.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); +// //theTempEntity->entity.curstate.framerate = 30; +// +// gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 6, 10, 100); +// } +// } +// break; +// case BULLET_PLAYER_BUCKSHOT: +// if ( !tracer ) +// { +// EV_HLDM_DecalGunshot( &tr, iBulletType ); +// +// // Add cool shotgun effect here +// //gEngfuncs.pEfxAPI->R_RocketTrail(vecSrc, tr.endpos, 1); +// gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); +// +// //if(thePlayBulletHitEffect) +// //{ +// // int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); +// // TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .5, 1.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); +// // theTempEntity->entity.curstate.framerate = 30; +// //} +// +// gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 5, 100, 200); +// } +// break; +// case BULLET_PLAYER_357: +// if ( !tracer ) +// { +// //EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); +// EV_HLDM_DecalGunshot( &tr, iBulletType ); +// +// if(thePlayBulletHitEffect) +// { +// // Make the smoke stick out of the target or wall just a little bit to avoid crappy sprite-in-wall effect +// Vector theEndPos = tr.endpos - 20*vecDir; +// int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); +// Vector theUp(0, 0, 30); +// TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(theEndPos, theUp, .3f, theSprite, kRenderTransAdd, kRenderFxFadeSlow, .3, 0.6, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); +// if(theTempEntity) +// { +// theTempEntity->entity.curstate.framerate = 50; +// } +// +// //// Create rising area of smoke above gun wielder +// //if(gEngfuncs.pfnRandomLong(0, 3) == 0) +// //{ +// // vec3_t theSource; +// // VectorCopy(vecSrc, theSource); +// // theSource.z += 60; +// // theSource.z += 60; +// // +// // theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .3, 3.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); +// // theTempEntity->entity.curstate.framerate = 30; +// //} +// +// // TODO: Add more here like splinters of wall and plaster +// gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 12, 100, 200); +// } +// } +// break; +// case BULLET_MONSTER_9MM: +// break; +// } +// } +// } +// +// gEngfuncs.pEventAPI->EV_PopPMStates(); +//} + +/* +================ +EV_HLDM_FireBulletsPlayer + +Client-side prediction friendly version of EV_HLDM_FireBullets +================ +*/ +void EV_HLDM_FireBulletsPlayer( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, Vector inSpread, int inRandomSeed) +{ +// int i; + int iShot; + int tracer; + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction(false, true); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + for ( iShot = 1; iShot <= cShots; iShot++ ) + { + vec3_t vecDir, vecEnd; + +// float x, y, z; +// //We randomize for the Shotgun. +// if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) +// { +// do { +// x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); +// y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); +// z = x*x+y*y; +// } while (z > 1); +// +// for ( i = 0 ; i < 3; i++ ) +// { +// vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; +// vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; +// } +// }//But other guns already have their spread randomized in the synched spread. +// else +// { + + //for ( i = 0 ; i < 3; i++ ) + //{ + // vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; + // vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + //} + vecDir = UTIL_GetRandomSpreadDir(inRandomSeed, iShot, vecDirShooting, right, up, inSpread); + VectorMA(vecSrc, flDistance, vecDir, vecEnd); + //vecEnd = vecSrc + flDistance*vecDir; +// } + + // For debugging + //gEngfuncs.pEfxAPI->R_TracerEffect(vecSrc, vecEnd); + + pmtrace_t tr; + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + //gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); + + tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); + + physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + bool thePlayBulletHitEffect = /*true;//*/!tr.inwater && pe && !pe->player; + int theSoundProbability = 2; + + // do damage, paint decals + if ( tr.fraction != 1.0 ) + { + switch(iBulletType) + { + default: + case BULLET_PLAYER_9MM: + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); + EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); + break; + + case BULLET_PLAYER_MP5: + + if ( !tracer ) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); + + theSoundProbability = 8; + EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); + + // Only play weapon effects if we hit the + if(thePlayBulletHitEffect) + { + // Make the smoke stick out of the target or wall just a little bit to avoid crappy sprite-in-wall effect + Vector theEndPos = tr.endpos - 20*vecDir; + int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); + Vector theUp(0, 0, 30); + TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(theEndPos, theUp, .3f, theSprite, kRenderTransAdd, kRenderFxFadeSlow, .1, 0.6, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); + if(theTempEntity) + { + theTempEntity->entity.curstate.framerate = 50; + } + + gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 6, 10, 100); + } + } + break; + case BULLET_PLAYER_BUCKSHOT: + if ( !tracer ) + { + theSoundProbability = BALANCE_VAR(kSGBulletsPerShot)/2; + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); + + theSoundProbability = BALANCE_VAR(kSGBulletsPerShot)/2; + EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); + + if(thePlayBulletHitEffect) + { + // Add cool shotgun effect here + //gEngfuncs.pEfxAPI->R_RocketTrail(vecSrc, tr.endpos, 1); + gEngfuncs.pEfxAPI->R_BulletImpactParticles(tr.endpos); + + //if(thePlayBulletHitEffect) + //{ + // int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); + // TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .5, 1.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); + // theTempEntity->entity.curstate.framerate = 30; + //} + + gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 5, 100, 200); + } + } + break; + case BULLET_PLAYER_357: + if ( !tracer ) + { + theSoundProbability = 1; + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); + EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); + + if(thePlayBulletHitEffect) + { + // Make the smoke stick out of the target or wall just a little bit to avoid crappy sprite-in-wall effect + Vector theEndPos = tr.endpos - 20*vecDir; + int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kGenericWallpuff); + Vector theUp(0, 0, 30); + TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(theEndPos, theUp, .3f, theSprite, kRenderTransAdd, kRenderFxFadeSlow, .15, 0.6, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); + if(theTempEntity) + { + theTempEntity->entity.curstate.framerate = 50; + } + + //// Create rising area of smoke above gun wielder + //if(gEngfuncs.pfnRandomLong(0, 3) == 0) + //{ + // vec3_t theSource; + // VectorCopy(vecSrc, theSource); + // theSource.z += 60; + // theSource.z += 60; + // + // theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc, vec3_origin, 1.0f, theSprite, kRenderGlow, kRenderFxNoDissipation, .3, 3.0, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); + // theTempEntity->entity.curstate.framerate = 30; + //} + + // TODO: Add more here like splinters of wall and plaster + gEngfuncs.pEfxAPI->R_SparkEffect(tr.endpos, 12, 100, 200); + } + } + break; + case BULLET_MONSTER_9MM: + if(!tracer) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType, theSoundProbability); + //EV_HLDM_DecalGunshot( &tr, iBulletType, theSoundProbability); + + // Only play weapon effects if we hit the + if(thePlayBulletHitEffect) + { + int theSprite = gEngfuncs.pEventAPI->EV_FindModelIndex(kSpikeGunHitSprite); + TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->R_TempSprite(tr.endpos, vec3_origin, .6f, theSprite, kRenderTransAdd, kRenderFxNoDissipation, .5f, .4f, FTENT_COLLIDEALL | FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP | FTENT_PERSIST); + if(theTempEntity) + { + theTempEntity->entity.curstate.framerate = 30; + } + } + } + break; + } + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + + + +//====================== +// GLOCK START +//====================== +//void EV_FireGlock1( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// vec3_t angles; +// vec3_t velocity; +// int empty; +// +// vec3_t ShellVelocity; +// vec3_t ShellOrigin; +// int shell; +// vec3_t vecSrc, vecAiming; +// vec3_t up, right, forward; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// VectorCopy( args->angles, angles ); +// VectorCopy( args->velocity, velocity ); +// +// empty = args->bparam1; +// AngleVectors( angles, forward, right, up ); +// +// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell +// +// if ( EV_IsLocal( idx ) ) +// { +// EV_MuzzleFlash(); +// gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); +// +// V_PunchAxis( 0, -2.0 ); +// } +// +// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); +// +// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); +// +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); +// +// EV_GetGunPosition( args, vecSrc, origin ); +// +// VectorCopy( forward, vecAiming ); +// +// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2); +//} + +//void EV_FireGlock2( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// vec3_t angles; +// vec3_t velocity; +// +// vec3_t ShellVelocity; +// vec3_t ShellOrigin; +// int shell; +// vec3_t vecSrc, vecAiming; +// vec3_t vecSpread; +// vec3_t up, right, forward; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// VectorCopy( args->angles, angles ); +// VectorCopy( args->velocity, velocity ); +// +// AngleVectors( angles, forward, right, up ); +// +// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell +// +// if ( EV_IsLocal( idx ) ) +// { +// // Add muzzle flash to current weapon model +// EV_MuzzleFlash(); +// gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); +// +// V_PunchAxis( 0, -2.0 ); +// } +// +// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); +// +// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); +// +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); +// +// EV_GetGunPosition( args, vecSrc, origin ); +// +// VectorCopy( forward, vecAiming ); +// +// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); +// +//} +//====================== +// GLOCK END +//====================== + +//====================== +// SHOTGUN START +//====================== +//void EV_FireShotGunDouble( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// vec3_t angles; +// vec3_t velocity; +// +// int j; +// vec3_t ShellVelocity; +// vec3_t ShellOrigin; +// int shell; +// vec3_t vecSrc, vecAiming; +// vec3_t vecSpread; +// vec3_t up, right, forward; +// float flSpread = 0.01; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// VectorCopy( args->angles, angles ); +// VectorCopy( args->velocity, velocity ); +// +// AngleVectors( angles, forward, right, up ); +// +// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell +// +// if ( EV_IsLocal( idx ) ) +// { +// // Add muzzle flash to current weapon model +// EV_MuzzleFlash(); +// gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 ); +// V_PunchAxis( 0, -10.0 ); +// } +// +// for ( j = 0; j < 2; j++ ) +// { +// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); +// +// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); +// } +// +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); +// +// EV_GetGunPosition( args, vecSrc, origin ); +// VectorCopy( forward, vecAiming ); +// +// if ( gEngfuncs.GetMaxClients() > 1 ) +// { +// EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.17365, 0.04362 ); +// } +// else +// { +// EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); +// } +// +// if ( EV_IsLocal( idx ) ) +// { +// V_PunchAxis( 0, -10.0 ); +// } +//} + +//void EV_FireShotGunSingle( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// vec3_t angles; +// vec3_t velocity; +// +// vec3_t ShellVelocity; +// vec3_t ShellOrigin; +// int shell; +// vec3_t vecSrc, vecAiming; +// vec3_t vecSpread; +// vec3_t up, right, forward; +// float flSpread = 0.01; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// VectorCopy( args->angles, angles ); +// VectorCopy( args->velocity, velocity ); +// +// AngleVectors( angles, forward, right, up ); +// +// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell +// +// if ( EV_IsLocal( idx ) ) +// { +// // Add muzzle flash to current weapon model +// EV_MuzzleFlash(); +// gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 ); +// +// V_PunchAxis( 0, -5.0 ); +// } +// +// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); +// +// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); +// +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); +// +// EV_GetGunPosition( args, vecSrc, origin ); +// VectorCopy( forward, vecAiming ); +// +// if ( gEngfuncs.GetMaxClients() > 1 ) +// { +// EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.04362 ); +// } +// else +// { +// EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); +// } +//} +//====================== +// SHOTGUN END +//====================== + +//====================== +// MP5 START +//====================== +//void EV_FireMP5( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// vec3_t angles; +// vec3_t velocity; +// +// vec3_t ShellVelocity; +// vec3_t ShellOrigin; +// int shell; +// vec3_t vecSrc, vecAiming; +// vec3_t up, right, forward; +// float flSpread = 0.01; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// VectorCopy( args->angles, angles ); +// VectorCopy( args->velocity, velocity ); +// +// AngleVectors( angles, forward, right, up ); +// +// shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell +// +// if ( EV_IsLocal( idx ) ) +// { +// // Add muzzle flash to current weapon model +// EV_MuzzleFlash(); +// gEngfuncs.pEventAPI->EV_WeaponAnimation( MG_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); +// } +// +// EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); +// +// EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); +// +// switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) +// { +// case 0: +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); +// break; +// case 1: +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); +// break; +// } +// +// EV_GetGunPosition( args, vecSrc, origin ); +// VectorCopy( forward, vecAiming ); +// +// if ( gEngfuncs.GetMaxClients() > 1 ) +// { +// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); +// } +// else +// { +// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); +// } +//} + +// We only predict the animation and sound +// The grenade is still launched from the server. +//void EV_FireMP52( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// +// if ( EV_IsLocal( idx ) ) +// { +// // NOTE: Put this back in if needed <<< cgc >>> +// //gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 ); +// //V_PunchAxis( 0, -10 ); +// } +// +// switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) +// { +// case 0: +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); +// break; +// case 1: +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); +// break; +// } +//} +//====================== +// MP5 END +//====================== + +//====================== +// PHYTON START +// ( .357 ) +//====================== +//void EV_FirePython( event_args_t *args ) +//{ +// int idx; +// vec3_t origin; +// vec3_t angles; +// vec3_t velocity; +// +// vec3_t vecSrc, vecAiming; +// vec3_t up, right, forward; +// float flSpread = 0.01; +// +// idx = args->entindex; +// VectorCopy( args->origin, origin ); +// VectorCopy( args->angles, angles ); +// VectorCopy( args->velocity, velocity ); +// +// AngleVectors( angles, forward, right, up ); +// +// if ( EV_IsLocal( idx ) ) +// { +// // Python uses different body in multiplayer versus single player +// int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; +// +// // Add muzzle flash to current weapon model +// EV_MuzzleFlash(); +// gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 ); +// +// V_PunchAxis( 0, -10.0 ); +// } +// +// switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) +// { +// case 0: +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); +// break; +// case 1: +// gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); +// break; +// } +// +// EV_GetGunPosition( args, vecSrc, origin ); +// +// VectorCopy( forward, vecAiming ); +// +// EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); +//} +//====================== +// PHYTON END +// ( .357 ) +//====================== + +//====================== +// GAUSS START +//====================== +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +void EV_SpinGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int iSoundState = 0; + + int pitch; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + pitch = args->iparam1; + + iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0; + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); +} + +/* +============================== +EV_StopPreviousGauss + +============================== +*/ +void EV_StopPreviousGauss( int idx ) +{ + // Make sure we don't have a gauss spin event in the queue for this guy + gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); +} + +void EV_FireGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + float flDamage = args->fparam1; + int primaryfire = args->bparam1; + + int m_fPrimaryFire = args->bparam1; + int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + vec3_t vecSrc; + vec3_t vecDest; + edict_t *pentIgnore; + pmtrace_t tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + physent_t *pEntity; + int m_iBeam, m_iGlow, m_iBalls; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + if ( args->bparam2 ) + { + EV_StopPreviousGauss( idx ); + return; + } + +// Con_Printf( "Firing gauss with %f\n", flDamage ); + EV_GetGunPosition( args, vecSrc, origin ); + + m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); + m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); + + AngleVectors( angles, forward, right, up ); + + VectorMA( vecSrc, 8192, forward, vecDest ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -2.0 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); + } + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + while (flDamage > 10 && nMaxHits > 0) + { + nMaxHits--; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( tr.allsolid ) + break; + + if (fFirstBeam) + { + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + } + fFirstBeam = 0; + + gEngfuncs.pEfxAPI->R_BeamEntPoint( + idx | 0x1000, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + else + { + gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + + pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + if ( pEntity == NULL ) + break; + + if ( pEntity->solid == SOLID_BSP ) + { + float n; + + pentIgnore = NULL; + + n = -DotProduct( tr.plane.normal, forward ); + + if (n < 0.5) // 60 degrees + { + // ALERT( at_console, "reflect %f\n", n ); + // reflect + vec3_t r; + + VectorMA( forward, 2.0 * n, tr.plane.normal, r ); + + flMaxFrac = flMaxFrac - tr.fraction; + + VectorCopy( r, forward ); + + VectorMA( tr.endpos, 8.0, forward, vecSrc ); + VectorMA( vecSrc, 8192.0, forward, vecDest ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); + + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + + // lose energy + if ( n == 0 ) + { + n = 0.1; + } + + flDamage = flDamage * (1 - n); + + } + else + { + // tunnel + EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // limit it to one hole punch + if (fHasPunched) + { + break; + } + fHasPunched = 1; + + // try punching through wall if secondary attack (primary is incapable of breaking through) + if ( !m_fPrimaryFire ) + { + vec3_t start; + + VectorMA( tr.endpos, 8.0, forward, start ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); + + if ( !beam_tr.allsolid ) + { + vec3_t delta; + float n; + + // trace backwards to find exit point + + gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); + + VectorSubtract( beam_tr.endpos, tr.endpos, delta ); + + n = Length( delta ); + + if (n < flDamage) + { + if (n == 0) + n = 1; + flDamage -= n; + + // absorption balls + { + vec3_t fwd; + VectorSubtract( tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + } + + //////////////////////////////////// WHAT TO DO HERE + // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + + EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // balls + { + vec3_t fwd; + VectorSubtract( beam_tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, + 255, 40 ); + } + + VectorAdd( beam_tr.endpos, forward, vecSrc ); + } + } + else + { + flDamage = 0; + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } + else + { + if ( m_fPrimaryFire ) + { + // slug doesn't punch through ever with primary + // fire, so leave a little glowy bit and make some balls + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); + + { + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 200 ); + } + } + + flDamage = 0; + } + } + } + else + { + VectorAdd( tr.endpos, forward, vecSrc ); + } + } +} +//====================== +// GAUSS END +//====================== + +//====================== +// CROWBAR START +//====================== + +enum crowbar_e { + CROWBAR_IDLE = 0, + CROWBAR_DRAW, + CROWBAR_HOLSTER, + CROWBAR_ATTACK1HIT, + CROWBAR_ATTACK1MISS, + CROWBAR_ATTACK2MISS, + CROWBAR_ATTACK2HIT, + CROWBAR_ATTACK3MISS, + CROWBAR_ATTACK3HIT +}; + +int g_iSwing; + +//Only predict the miss sounds, hit sounds are still played +//server side, so players don't get the wrong idea. +void EV_Crowbar( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + //Play Swing sound + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); + + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); + + switch( (g_iSwing++) % 3 ) + { + case 0: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK1MISS, 1 ); break; + case 1: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK2MISS, 1 ); break; + case 2: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK3MISS, 1 ); break; + } + } +} +//====================== +// CROWBAR END +//====================== + +//====================== +// CROSSBOW END +//====================== +enum crossbow_e { + CROSSBOW_IDLE1 = 0, // full + CROSSBOW_IDLE2, // empty + CROSSBOW_FIDGET1, // full + CROSSBOW_FIDGET2, // empty + CROSSBOW_FIRE1, // full + CROSSBOW_FIRE2, // reload + CROSSBOW_FIRE3, // empty + CROSSBOW_RELOAD, // from empty + CROSSBOW_DRAW1, // full + CROSSBOW_DRAW2, // empty + CROSSBOW_HOLSTER1, // full + CROSSBOW_HOLSTER2, // empty +}; + +//===================== +// EV_BoltCallback +// This function is used to correct the origin and angles +// of the bolt, so it looks like it's stuck on the wall. +//===================== +void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + ent->entity.origin = ent->entity.baseline.vuser1; + ent->entity.angles = ent->entity.baseline.vuser2; +} + +void EV_FireCrossbow2( event_args_t *args ) +{ + vec3_t vecSrc, vecEnd; + vec3_t up, right, forward; + pmtrace_t tr; + + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorMA( vecSrc, 8192, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + if ( EV_IsLocal( idx ) ) + { + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); + else if ( args->iparam2 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); + } + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + //We hit something + if ( tr.fraction < 1.0 ) + { + physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + + //Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ). + if ( pe->solid != SOLID_BSP ) + { + switch( gEngfuncs.pfnRandomLong(0,1) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + //Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though. + else if ( pe->rendermode == kRenderNormal ) + { + gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, PITCH_NORM ); + + //Not underwater, do some sparks... + if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) + gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); + + vec3_t vBoltAngles; + int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" ); + + VectorAngles( forward, vBoltAngles ); + + TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); + + if ( bolt ) + { + bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function. + bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit + bolt->entity.baseline.vuser2 = vBoltAngles; //Look forward! + bolt->callback = EV_BoltCallback; //So we can set the angles and origin back. (Stick the bolt to the wall) + } + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +//TODO: Fully predict the fliying bolt. +void EV_FireCrossbow( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); + else if ( args->iparam2 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); + + V_PunchAxis( 0, -2.0 ); + } +} +//====================== +// CROSSBOW END +//====================== + +//====================== +// RPG START +//====================== +enum rpg_e { + RPG_IDLE = 0, + RPG_FIDGET, + RPG_RELOAD, // to reload + RPG_FIRE2, // to empty + RPG_HOLSTER1, // loaded + RPG_DRAW1, // loaded + RPG_HOLSTER2, // unloaded + RPG_DRAW_UL, // unloaded + RPG_IDLE_UL, // unloaded idle + RPG_FIDGET_UL, // unloaded fidget +}; + +void EV_FireRpg( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 ); + + V_PunchAxis( 0, -5.0 ); + } +} +//====================== +// RPG END +//====================== + +//====================== +// EGON END +//====================== +enum egon_e { + EGON_IDLE1 = 0, + EGON_FIDGET1, + EGON_ALTFIREON, + EGON_ALTFIRECYCLE, + EGON_ALTFIREOFF, + EGON_FIRE1, + EGON_FIRE2, + EGON_FIRE3, + EGON_FIRE4, + EGON_DRAW, + EGON_HOLSTER +}; + +int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; +int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; + +enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; +enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; + +#define EGON_PRIMARY_VOLUME 450 +#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" +#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" +#define EGON_SOUND_OFF "weapons/egon_off1.wav" +#define EGON_SOUND_RUN "weapons/egon_run3.wav" +#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" + +//@2014 +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif + +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +BEAM *pBeam; +BEAM *pBeam2; + +void EV_EgonFire( event_args_t *args ) +{ + int idx, iFireState, iFireMode; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + iFireState = args->iparam1; + iFireMode = args->iparam2; + int iStartup = args->bparam1; + + + if ( iStartup ) + { + if ( iFireMode == FIRE_WIDE ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); + } + else + { + if ( iFireMode == FIRE_WIDE ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); + } + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); + + if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 ) + { + vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; + pmtrace_t tr; + + cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); + + if ( pl ) + { + VectorCopy( gHUD.m_vecAngles, angles ); + + AngleVectors( angles, forward, right, up ); + + EV_GetGunPosition( args, vecSrc, pl->origin ); + + VectorMA( vecSrc, 2048, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE ); + + float r = 50.0f; + float g = 50.0f; + float b = 125.0f; + + if ( IEngineStudio.IsHardware() ) + { + r /= 100.0f; + g /= 100.0f; + } + + + pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); + + if ( pBeam ) + pBeam->flags |= ( FBEAM_SINENOISE ); + + pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); + } + } +} + +void EV_EgonStop( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy ( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); + + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 ); + + if ( EV_IsLocal( idx ) ) + { + if ( pBeam ) + { + pBeam->die = 0.0; + pBeam = NULL; + } + + + if ( pBeam2 ) + { + pBeam2->die = 0.0; + pBeam2 = NULL; + } + } +} +//====================== +// EGON END +//====================== + +//====================== +// HORNET START +//====================== +enum hgun_e { + HGUN_IDLE1 = 0, + HGUN_FIDGETSWAY, + HGUN_FIDGETSHAKE, + HGUN_DOWN, + HGUN_UP, + HGUN_SHOOT +}; + +void EV_HornetGunFire( event_args_t *args ) +{ + int idx, iFireMode; + vec3_t origin, angles, vecSrc, forward, right, up; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + iFireMode = args->iparam1; + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, gEngfuncs.pfnRandomLong ( 0, 2 ) ); + gEngfuncs.pEventAPI->EV_WeaponAnimation ( HGUN_SHOOT, 1 ); + } + + switch ( gEngfuncs.pfnRandomLong ( 0 , 2 ) ) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); break; + } +} +//====================== +// HORNET END +//====================== + +//====================== +// TRIPMINE START +//====================== +enum tripmine_e { + TRIPMINE_IDLE1 = 0, + TRIPMINE_IDLE2, + TRIPMINE_ARM1, + TRIPMINE_ARM2, + TRIPMINE_FIDGET, + TRIPMINE_HOLSTER, + TRIPMINE_DRAW, + TRIPMINE_WORLD, + TRIPMINE_GROUND, +}; + +//We only check if it's possible to put a trip mine +//and if it is, then we play the animation. Server still places it. +void EV_TripmineFire( event_args_t *args ) +{ + int idx; + vec3_t vecSrc, angles, view_ofs, forward; + pmtrace_t tr; + + idx = args->entindex; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); + + AngleVectors ( angles, forward, NULL, NULL ); + + if ( !EV_IsLocal ( idx ) ) + return; + + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + + vecSrc = vecSrc + view_ofs; + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); + + //Hit something solid + if ( tr.fraction < 1.0 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} +//====================== +// TRIPMINE END +//====================== + +//====================== +// SQUEAK START +//====================== +enum squeak_e { + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) + +void EV_SnarkFire( event_args_t *args ) +{ + int idx; + vec3_t vecSrc, angles, view_ofs, forward; + pmtrace_t tr; + + idx = args->entindex; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); + + AngleVectors ( angles, forward, NULL, NULL ); + + if ( !EV_IsLocal ( idx ) ) + return; + + if ( args->ducking ) + vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr ); + + //Find space to drop the thing. + if ( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( SQUEAK_THROW, 0 ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} +//====================== +// SQUEAK END +//====================== + +void EV_TrainPitchAdjust( event_args_t *args ) +{ + int idx; + vec3_t origin; + + unsigned short us_params; + int noise; + float m_flVolume; + int pitch; + int stop; + + char sz[ 256 ]; + + idx = args->entindex; + + VectorCopy( args->origin, origin ); + + us_params = (unsigned short)args->iparam1; + stop = args->bparam1; + + m_flVolume = (float)(us_params & 0x003f)/40.0; + noise = (int)(((us_params) >> 12 ) & 0x0007); + pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); + + switch ( noise ) + { + case 1: strcpy( sz, "plats/ttrain1.wav"); break; + case 2: strcpy( sz, "plats/ttrain2.wav"); break; + case 3: strcpy( sz, "plats/ttrain3.wav"); break; + case 4: strcpy( sz, "plats/ttrain4.wav"); break; + case 5: strcpy( sz, "plats/ttrain6.wav"); break; + case 6: strcpy( sz, "plats/ttrain7.wav"); break; + default: + // no sound + strcpy( sz, "" ); + return; + } + + if ( stop ) + { + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); + } + else + { + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); + } +} + +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) +{ + return 0; +} diff --git a/main/source/cl_dll/ev_hldm.h b/main/source/cl_dll/ev_hldm.h index eaf13adc..1b63ac91 100644 --- a/main/source/cl_dll/ev_hldm.h +++ b/main/source/cl_dll/ev_hldm.h @@ -1,73 +1,73 @@ -#if !defined ( EV_HLDMH ) -#define EV_HLDMH - -#include "common/bullettypes.h" - -enum glock_e { - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -enum shotgun_e { - SHOTGUN_IDLE = 0, - SHOTGUN_FIRE, - SHOTGUN_FIRE2, - SHOTGUN_RELOAD, - SHOTGUN_PUMP, - SHOTGUN_START_RELOAD, - SHOTGUN_DRAW, - SHOTGUN_HOLSTER, - SHOTGUN_IDLE4, - SHOTGUN_IDLE_DEEP -}; - -//enum mp5_e -enum avhmg_e -{ - MG_LONGIDLE = 0, - MG_IDLE1, - MG_LAUNCH, - MG_RELOAD, - MG_DEPLOY, - MG_FIRE1, - MG_FIRE2, - MG_FIRE3, -}; - -enum python_e { - PYTHON_IDLE1 = 0, - PYTHON_FIDGET, - PYTHON_FIRE1, - PYTHON_RELOAD, - PYTHON_HOLSTER, - PYTHON_DRAW, - PYTHON_IDLE2, - PYTHON_IDLE3 -}; - -#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging -#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged - -enum gauss_e { - GAUSS_IDLE = 0, - GAUSS_IDLE2, - GAUSS_FIDGET, - GAUSS_SPINUP, - GAUSS_SPIN, - GAUSS_FIRE, - GAUSS_FIRE2, - GAUSS_HOLSTER, - GAUSS_DRAW -}; - -#include "common/hldm.h" - +#if !defined ( EV_HLDMH ) +#define EV_HLDMH + +#include "common/bullettypes.h" + +enum glock_e { + GLOCK_IDLE1 = 0, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD, + GLOCK_RELOAD_NOT_EMPTY, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_ADD_SILENCER +}; + +enum shotgun_e { + SHOTGUN_IDLE = 0, + SHOTGUN_FIRE, + SHOTGUN_FIRE2, + SHOTGUN_RELOAD, + SHOTGUN_PUMP, + SHOTGUN_START_RELOAD, + SHOTGUN_DRAW, + SHOTGUN_HOLSTER, + SHOTGUN_IDLE4, + SHOTGUN_IDLE_DEEP +}; + +//enum mp5_e +enum avhmg_e +{ + MG_LONGIDLE = 0, + MG_IDLE1, + MG_LAUNCH, + MG_RELOAD, + MG_DEPLOY, + MG_FIRE1, + MG_FIRE2, + MG_FIRE3, +}; + +enum python_e { + PYTHON_IDLE1 = 0, + PYTHON_FIDGET, + PYTHON_FIRE1, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_DRAW, + PYTHON_IDLE2, + PYTHON_IDLE3 +}; + +#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging +#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged + +enum gauss_e { + GAUSS_IDLE = 0, + GAUSS_IDLE2, + GAUSS_FIDGET, + GAUSS_SPINUP, + GAUSS_SPIN, + GAUSS_FIRE, + GAUSS_FIRE2, + GAUSS_HOLSTER, + GAUSS_DRAW +}; + +#include "common/hldm.h" + #endif // EV_HLDMH \ No newline at end of file diff --git a/main/source/cl_dll/events.cpp b/main/source/cl_dll/events.cpp index 60061f1f..7a9284d0 100644 --- a/main/source/cl_dll/events.cpp +++ b/main/source/cl_dll/events.cpp @@ -1,16 +1,16 @@ -#include "hud.h" -#include "cl_util.h" - -void Game_HookEvents( void ); - -/* -=================== -EV_HookEvents - -See if game specific code wants to hook any events. -=================== -*/ -void EV_HookEvents( void ) -{ - Game_HookEvents(); +#include "hud.h" +#include "cl_util.h" + +void Game_HookEvents( void ); + +/* +=================== +EV_HookEvents + +See if game specific code wants to hook any events. +=================== +*/ +void EV_HookEvents( void ) +{ + Game_HookEvents(); } \ No newline at end of file diff --git a/main/source/cl_dll/eventscripts.h b/main/source/cl_dll/eventscripts.h index b99929da..4d80bcf1 100644 --- a/main/source/cl_dll/eventscripts.h +++ b/main/source/cl_dll/eventscripts.h @@ -1,34 +1,34 @@ -// eventscripts.h -#if !defined ( EVENTSCRIPTSH ) -#define EVENTSCRIPTSH - -#include "common/const.h" - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 - -#ifndef VEC_DUCK_VIEW -#define VEC_DUCK_VIEW 12 -#endif - -#define FTENT_FADEOUT 0x00000080 - -#include "common/damagetypes.h" -#include "pm_shared/pm_defs.h" - -// Some of these are HL/TFC specific? -void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); -void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); -void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); -qboolean EV_IsLocal( int idx ); -qboolean EV_IsSpec( int idx ); -qboolean EV_IsPlayer( int idx ); -void EV_CreateTracer( float *start, float *end ); - -struct cl_entity_s *GetEntity( int idx ); -struct cl_entity_s *GetViewEntity( void ); -physent_t* GetPhysEntity(int inPhysIndex); -void DoCenterPrint(char* inString); -void EV_MuzzleFlash( void ); - -#endif // EVENTSCRIPTSH +// eventscripts.h +#if !defined ( EVENTSCRIPTSH ) +#define EVENTSCRIPTSH + +#include "common/const.h" + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 + +#ifndef VEC_DUCK_VIEW +#define VEC_DUCK_VIEW 12 +#endif + +#define FTENT_FADEOUT 0x00000080 + +#include "common/damagetypes.h" +#include "pm_shared/pm_defs.h" + +// Some of these are HL/TFC specific? +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); +void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); +void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); +qboolean EV_IsLocal( int idx ); +qboolean EV_IsSpec( int idx ); +qboolean EV_IsPlayer( int idx ); +void EV_CreateTracer( float *start, float *end ); + +struct cl_entity_s *GetEntity( int idx ); +struct cl_entity_s *GetViewEntity( void ); +physent_t* GetPhysEntity(int inPhysIndex); +void DoCenterPrint(char* inString); +void EV_MuzzleFlash( void ); + +#endif // EVENTSCRIPTSH diff --git a/main/source/cl_dll/flashlight.cpp b/main/source/cl_dll/flashlight.cpp index cf51fc1b..17ed25e7 100644 --- a/main/source/cl_dll/flashlight.cpp +++ b/main/source/cl_dll/flashlight.cpp @@ -1,140 +1,140 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// flashlight.cpp -// -// implementation of CHudFlashlight class -// - -#include "hud.h" -#include "cl_util.h" -#include "mod/AvHNetworkMessages.h" - -#include -#include - - - -DECLARE_MESSAGE(m_Flash, FlashBat) -DECLARE_MESSAGE(m_Flash, Flashlight) - -#define BAT_NAME "sprites/%d_Flashlight.spr" - -int CHudFlashlight::Init(void) -{ - m_fFade = 0; - m_fOn = 0; - - HOOK_MESSAGE(Flashlight); - HOOK_MESSAGE(FlashBat); - - m_iFlags |= HUD_ACTIVE; - - //gHUD.AddHudElem(this); - - return 1; -}; - -void CHudFlashlight::Reset(void) -{ - m_fFade = 0; - m_fOn = 0; -} - -int CHudFlashlight::VidInit(void) -{ - int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); - int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); - int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); - - m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); - m_hSprite2 = gHUD.GetSprite(HUD_flash_full); - m_hBeam = gHUD.GetSprite(HUD_flash_beam); - m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); - m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); - m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); - m_iWidth = m_prc2->right - m_prc2->left; - - return 1; -}; - -int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) -{ - //this message is a lame duck in NS - return 0; -} - -int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) -{ - NetMsg_Flashlight( pbuf, iSize, m_fOn, m_iBat ); - m_flBat = ((float)m_iBat)/100.0; - return 1; -} - -int CHudFlashlight::Draw(float flTime) -{ - if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) - return 1; - - int r, g, b, x, y, a; - wrect_t rc; - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return 1; - - if (m_fOn) - a = 225; - else - a = MIN_ALPHA; - - if (m_flBat < 0.20) - UnpackRGB(r,g,b, RGB_REDISH); - else - { - gHUD.GetPrimaryHudColor(r, g, b); - } - - ScaleColors(r, g, b, a); - - y = (m_prc1->bottom - m_prc2->top)/2; - x = ScreenWidth() - m_iWidth - m_iWidth/2 ; - - // Draw the flashlight casing - SPR_Set(m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prc1); - - if ( m_fOn ) - { // draw the flashlight beam - x = ScreenWidth() - m_iWidth/2; - - SPR_Set( m_hBeam, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prcBeam ); - } - - // draw the flashlight energy level - x = ScreenWidth() - m_iWidth - m_iWidth/2 ; - int iOffset = m_iWidth * (1.0 - m_flBat); - if (iOffset < m_iWidth) - { - rc = *m_prc2; - rc.left += iOffset; - - SPR_Set(m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x + iOffset, y, &rc); - } - - - return 1; +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// flashlight.cpp +// +// implementation of CHudFlashlight class +// + +#include "hud.h" +#include "cl_util.h" +#include "mod/AvHNetworkMessages.h" + +#include +#include + + + +DECLARE_MESSAGE(m_Flash, FlashBat) +DECLARE_MESSAGE(m_Flash, Flashlight) + +#define BAT_NAME "sprites/%d_Flashlight.spr" + +int CHudFlashlight::Init(void) +{ + m_fFade = 0; + m_fOn = 0; + + HOOK_MESSAGE(Flashlight); + HOOK_MESSAGE(FlashBat); + + m_iFlags |= HUD_ACTIVE; + + //gHUD.AddHudElem(this); + + return 1; +}; + +void CHudFlashlight::Reset(void) +{ + m_fFade = 0; + m_fOn = 0; +} + +int CHudFlashlight::VidInit(void) +{ + int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); + int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); + int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); + + m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); + m_hSprite2 = gHUD.GetSprite(HUD_flash_full); + m_hBeam = gHUD.GetSprite(HUD_flash_beam); + m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); + m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); + m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); + m_iWidth = m_prc2->right - m_prc2->left; + + return 1; +}; + +int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) +{ + //this message is a lame duck in NS + return 0; +} + +int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) +{ + NetMsg_Flashlight( pbuf, iSize, m_fOn, m_iBat ); + m_flBat = ((float)m_iBat)/100.0; + return 1; +} + +int CHudFlashlight::Draw(float flTime) +{ + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if (m_fOn) + a = 225; + else + a = MIN_ALPHA; + + if (m_flBat < 0.20) + UnpackRGB(r,g,b, RGB_REDISH); + else + { + gHUD.GetPrimaryHudColor(r, g, b); + } + + ScaleColors(r, g, b, a); + + y = (m_prc1->bottom - m_prc2->top)/2; + x = ScreenWidth() - m_iWidth - m_iWidth/2 ; + + // Draw the flashlight casing + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prc1); + + if ( m_fOn ) + { // draw the flashlight beam + x = ScreenWidth() - m_iWidth/2; + + SPR_Set( m_hBeam, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prcBeam ); + } + + // draw the flashlight energy level + x = ScreenWidth() - m_iWidth - m_iWidth/2 ; + int iOffset = m_iWidth * (1.0 - m_flBat); + if (iOffset < m_iWidth) + { + rc = *m_prc2; + rc.left += iOffset; + + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x + iOffset, y, &rc); + } + + + return 1; } \ No newline at end of file diff --git a/main/source/cl_dll/geiger.cpp b/main/source/cl_dll/geiger.cpp index 3085fd1f..20337cb2 100644 --- a/main/source/cl_dll/geiger.cpp +++ b/main/source/cl_dll/geiger.cpp @@ -1,63 +1,63 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Geiger.cpp -// -// implementation of CHudAmmo class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include - -#include "mod/AvHNetworkMessages.h" - -DECLARE_MESSAGE(m_Geiger, Geiger ) - -int CHudGeiger::Init(void) -{ - HOOK_MESSAGE( Geiger ); - - m_iGeigerRange = 0; - m_iFlags = 0; - - //gHUD.AddHudElem(this); - - srand( (unsigned)time( NULL ) ); - - return 1; -}; - -int CHudGeiger::VidInit(void) -{ - return 1; -}; - -int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) -{ - //update geiger data - NetMsg_GeigerRange( pbuf, iSize, m_iGeigerRange ); - m_iGeigerRange <<= 2; - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -int CHudGeiger::Draw (float flTime) -{ - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Geiger.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include + +#include "mod/AvHNetworkMessages.h" + +DECLARE_MESSAGE(m_Geiger, Geiger ) + +int CHudGeiger::Init(void) +{ + HOOK_MESSAGE( Geiger ); + + m_iGeigerRange = 0; + m_iFlags = 0; + + //gHUD.AddHudElem(this); + + srand( (unsigned)time( NULL ) ); + + return 1; +}; + +int CHudGeiger::VidInit(void) +{ + return 1; +}; + +int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) +{ + //update geiger data + NetMsg_GeigerRange( pbuf, iSize, m_iGeigerRange ); + m_iGeigerRange <<= 2; + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +int CHudGeiger::Draw (float flTime) +{ + return 1; +} diff --git a/main/source/cl_dll/health.cpp b/main/source/cl_dll/health.cpp index 75aabfc9..b0eb2ca5 100644 --- a/main/source/cl_dll/health.cpp +++ b/main/source/cl_dll/health.cpp @@ -1,487 +1,487 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Health.cpp -// -// implementation of CHudHealth class -// - -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -#include "hud.h" -#include "cl_util.h" -#include -#include "mod/AvHHudConstants.h" -#include "mod/AvHPlayerUpgrade.h" -#include "mod/AvHNetworkMessages.h" - -DECLARE_MESSAGE(m_Health, Health ) -DECLARE_MESSAGE(m_Health, Damage ) - -#define PAIN_NAME "sprites/%d_pain.spr" -#define DAMAGE_NAME "sprites/%d_dmg.spr" - -int giDmgHeight, giDmgWidth; - -int giDmgFlags[NUM_DMG_TYPES] = -{ - DMG_POISON, - DMG_ACID, - DMG_FREEZE|DMG_SLOWFREEZE, - DMG_DROWN, - DMG_BURN|DMG_SLOWBURN, - DMG_NERVEGAS, - DMG_RADIATION, - DMG_SHOCK, - DMG_CALTROP, - DMG_TRANQ, - DMG_CONCUSS, - DMG_HALLUC -}; - -int CHudHealth::Init(void) -{ - HOOK_MESSAGE(Health); - HOOK_MESSAGE(Damage); - //HOOK_MESSAGE(ClCorpse); - - m_iHealth = 100; - m_fFade = 0; - m_iFlags = 0; - m_bitsDamage = 0; - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - giDmgHeight = 0; - giDmgWidth = 0; - - memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); - - - gHUD.AddHudElem(this); - return 1; -} - -void CHudHealth::Reset( void ) -{ - // make sure the pain compass is cleared when the player respawns - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - - - // force all the flashing damage icons to expire - m_bitsDamage = 0; - for ( int i = 0; i < NUM_DMG_TYPES; i++ ) - { - m_dmg[i].fExpire = 0; - } -} - -int CHudHealth::VidInit(void) -{ - m_hSprite = 0; - - m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; - m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); - - giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; - giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; - return 1; -} - -int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) -{ - int x; - NetMsg_Health( pbuf, iSize, x ); - - // TODO: update local health data - m_iFlags |= HUD_ACTIVE; - - // Only update the fade if we've changed health - if (x != m_iHealth) - { - // We're sent the health of the player we're observing as if it were our own - m_fFade = FADE_TIME; - m_iHealth = x; - } - - return 2; -} - - -int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) -{ - int armor, damageTaken; - long bitsDamage; - float origin[3]; - NetMsg_Damage( pbuf, iSize, armor, damageTaken, bitsDamage, origin ); - - vec3_t vecFrom; - - for ( int i = 0 ; i < 3 ; i++) - vecFrom[i] = origin[i]; - - UpdateTiles(gHUD.m_flTime, bitsDamage); - - // Actually took damage? - if ( damageTaken > 0 || armor > 0 ) - CalcDamageDirection(vecFrom); - - return 1; -} - - -// Returns back a color from the -// Green <-> Yellow <-> Red ramp -void CHudHealth::GetPainColor( int &r, int &g, int &b ) -{ - int theMaxHealth = gHUD.GetHUDMaxHealth(); - - if (m_iHealth > theMaxHealth/4) - { - gHUD.GetPrimaryHudColor(r, g, b); - } - else - { - r = 250; - g = 0; - b = 0; - } -} - -int CHudHealth::Draw(float flTime) -{ - int r, g, b; - int a = 0, x, y; - int HealthWidth; - - if ( /*!gHUD.GetIsAlive() ||*/ (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) /*|| gEngfuncs.IsSpectateOnly()*/ ) - return 1; - - if ( !m_hSprite ) - m_hSprite = LoadSprite(PAIN_NAME); - - // Has health changed? Flash the health # - if (m_fFade) - { - m_fFade -= (gHUD.m_flTimeDelta * 20); - if (m_fFade <= 0) - { - a = MIN_ALPHA; - m_fFade = 0; - } - - // Fade the health number back to dim - - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - - } - else - a = MIN_ALPHA; - - // Potentially se upgrades and health of spectator target - int theUpgrades = gHUD.GetHUDUpgrades(); - - // If health is getting low, make it bright red - int theMaxHealth = gHUD.GetHUDMaxHealth(); - if (m_iHealth <= theMaxHealth/10) - { - a = 255; - } - - GetPainColor( r, g, b ); - ScaleColors(r, g, b, a ); - - int theViewport[4]; - gHUD.GetViewport(theViewport); - - // Only draw health if we have the suit. - if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) - { - HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; - - y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - - x = theViewport[0] + CrossWidth /2; - - int theInset = 0; - if(gHUD.GetIsAlien() && !gHUD.GetIsCombatMode()) - { - theInset = ScreenWidth()*kResourceEnergyBarWidth; - } - x += theInset;// + kHealthLeftInset*ScreenWidth; - - SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); - - x += CrossWidth + HealthWidth / 2; - - x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); - - x += HealthWidth/2; - - gHUD.GetPrimaryHudColor(r, g, b); - - int iHeight = gHUD.m_iFontHeight; - int iWidth = HealthWidth/10; - FillRGBA(x, y, iWidth, iHeight, r, g, b, a); - } - - DrawDamage(flTime); - return DrawPain(flTime); -} - -void CHudHealth::CalcDamageDirection(vec3_t vecFrom) -{ - vec3_t forward, right, up; - float side, front; - vec3_t vecOrigin, vecAngles; - - if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) - { - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - return; - } - - - memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); - memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); - - - VectorSubtract (vecFrom, vecOrigin, vecFrom); - - float flDistToTarget = vecFrom.Length(); - - vecFrom = vecFrom.Normalize(); - AngleVectors (vecAngles, forward, right, up); - - front = DotProduct (vecFrom, right); - side = DotProduct (vecFrom, forward); - - if (flDistToTarget <= 50) - { - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; - } - else - { - if (side > 0) - { - if (side > 0.3) - m_fAttackFront = max(m_fAttackFront, side); - } - else - { - float f = fabs(side); - if (f > 0.3) - m_fAttackRear = max(m_fAttackRear, f); - } - - if (front > 0) - { - if (front > 0.3) - m_fAttackRight = max(m_fAttackRight, front); - } - else - { - float f = fabs(front); - if (f > 0.3) - m_fAttackLeft = max(m_fAttackLeft, f); - } - } -} - -int CHudHealth::DrawPain(float flTime) -{ - if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) - return 1; - - int r, g, b; - int x, y, a, shade; - - // TODO: get the shift value of the health - a = 255; // max brightness until then - - float fFade = gHUD.m_flTimeDelta * 2; - - // SPR_Draw top - if (m_fAttackFront > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackFront, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth()/2 - SPR_Width(m_hSprite, 0)/2; - y = ScreenHeight()/2 - SPR_Height(m_hSprite,0) * 3; - SPR_DrawAdditive(0, x, y, NULL); - m_fAttackFront = max( 0, m_fAttackFront - fFade ); - } else - m_fAttackFront = 0; - - if (m_fAttackRight > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackRight, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth()/2 + SPR_Width(m_hSprite, 1) * 2; - y = ScreenHeight()/2 - SPR_Height(m_hSprite,1)/2; - SPR_DrawAdditive(1, x, y, NULL); - m_fAttackRight = max( 0, m_fAttackRight - fFade ); - } else - m_fAttackRight = 0; - - if (m_fAttackRear > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackRear, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth()/2 - SPR_Width(m_hSprite, 2)/2; - y = ScreenHeight()/2 + SPR_Height(m_hSprite,2) * 2; - SPR_DrawAdditive(2, x, y, NULL); - m_fAttackRear = max( 0, m_fAttackRear - fFade ); - } else - m_fAttackRear = 0; - - if (m_fAttackLeft > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackLeft, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth()/2 - SPR_Width(m_hSprite, 3) * 3; - y = ScreenHeight()/2 - SPR_Height(m_hSprite,3)/2; - SPR_DrawAdditive(3, x, y, NULL); - - m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); - } else - m_fAttackLeft = 0; - - return 1; -} - -int CHudHealth::DrawDamage(float flTime) -{ - int r, g, b, a; - DAMAGE_IMAGE *pdmg; - - if (!m_bitsDamage) - return 1; - - gHUD.GetPrimaryHudColor(r, g, b); - a = (int)( fabs(sin(flTime*2)) * 256.0); - - ScaleColors(r, g, b, a); - - // Draw all the items - int i; - for (i = 0; i < NUM_DMG_TYPES; i++) - { - if (m_bitsDamage & giDmgFlags[i]) - { - pdmg = &m_dmg[i]; - SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); - SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); - } - } - - - // check for bits that should be expired - for ( i = 0; i < NUM_DMG_TYPES; i++ ) - { - DAMAGE_IMAGE *pdmg = &m_dmg[i]; - - if ( m_bitsDamage & giDmgFlags[i] ) - { - pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); - - if ( pdmg->fExpire <= flTime // when the time has expired - && a < 40 ) // and the flash is at the low point of the cycle - { - pdmg->fExpire = 0; - - int y = pdmg->y; - pdmg->x = pdmg->y = 0; - - // move everyone above down - for (int j = 0; j < NUM_DMG_TYPES; j++) - { - pdmg = &m_dmg[j]; - if ((pdmg->y) && (pdmg->y < y)) - pdmg->y += giDmgHeight; - - } - - m_bitsDamage &= ~giDmgFlags[i]; // clear the bits - } - } - } - - return 1; -} - - -void CHudHealth::UpdateTiles(float flTime, long bitsDamage) -{ - DAMAGE_IMAGE *pdmg; - - // Which types are new? - long bitsOn = ~m_bitsDamage & bitsDamage; - - for (int i = 0; i < NUM_DMG_TYPES; i++) - { - pdmg = &m_dmg[i]; - - // Is this one already on? - if (m_bitsDamage & giDmgFlags[i]) - { - pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration - if (!pdmg->fBaseline) - pdmg->fBaseline = flTime; - } - - // Are we just turning it on? - if (bitsOn & giDmgFlags[i]) - { - // put this one at the bottom - pdmg->x = giDmgWidth/8; - pdmg->y = ScreenHeight() - giDmgHeight * 2; - pdmg->fExpire=flTime + DMG_IMAGE_LIFE; - - // move everyone else up - for (int j = 0; j < NUM_DMG_TYPES; j++) - { - if (j == i) - continue; - - pdmg = &m_dmg[j]; - if (pdmg->y) - pdmg->y -= giDmgHeight; - - } - pdmg = &m_dmg[i]; - } - } - - // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) - m_bitsDamage |= bitsDamage; -} - - -void CreateCorpse ( Vector vOrigin, Vector vAngles, const char *pModel, float flAnimTime, int iSequence, int iBody ); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Health.cpp +// +// implementation of CHudHealth class +// + +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +#include "hud.h" +#include "cl_util.h" +#include +#include "mod/AvHHudConstants.h" +#include "mod/AvHPlayerUpgrade.h" +#include "mod/AvHNetworkMessages.h" + +DECLARE_MESSAGE(m_Health, Health ) +DECLARE_MESSAGE(m_Health, Damage ) + +#define PAIN_NAME "sprites/%d_pain.spr" +#define DAMAGE_NAME "sprites/%d_dmg.spr" + +int giDmgHeight, giDmgWidth; + +int giDmgFlags[NUM_DMG_TYPES] = +{ + DMG_POISON, + DMG_ACID, + DMG_FREEZE|DMG_SLOWFREEZE, + DMG_DROWN, + DMG_BURN|DMG_SLOWBURN, + DMG_NERVEGAS, + DMG_RADIATION, + DMG_SHOCK, + DMG_CALTROP, + DMG_TRANQ, + DMG_CONCUSS, + DMG_HALLUC +}; + +int CHudHealth::Init(void) +{ + HOOK_MESSAGE(Health); + HOOK_MESSAGE(Damage); + //HOOK_MESSAGE(ClCorpse); + + m_iHealth = 100; + m_fFade = 0; + m_iFlags = 0; + m_bitsDamage = 0; + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + giDmgHeight = 0; + giDmgWidth = 0; + + memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); + + + gHUD.AddHudElem(this); + return 1; +} + +void CHudHealth::Reset( void ) +{ + // make sure the pain compass is cleared when the player respawns + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + + + // force all the flashing damage icons to expire + m_bitsDamage = 0; + for ( int i = 0; i < NUM_DMG_TYPES; i++ ) + { + m_dmg[i].fExpire = 0; + } +} + +int CHudHealth::VidInit(void) +{ + m_hSprite = 0; + + m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; + m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); + + giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; + giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; + return 1; +} + +int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) +{ + int x; + NetMsg_Health( pbuf, iSize, x ); + + // TODO: update local health data + m_iFlags |= HUD_ACTIVE; + + // Only update the fade if we've changed health + if (x != m_iHealth) + { + // We're sent the health of the player we're observing as if it were our own + m_fFade = FADE_TIME; + m_iHealth = x; + } + + return 2; +} + + +int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + int armor, damageTaken; + long bitsDamage; + float origin[3]; + NetMsg_Damage( pbuf, iSize, armor, damageTaken, bitsDamage, origin ); + + vec3_t vecFrom; + + for ( int i = 0 ; i < 3 ; i++) + vecFrom[i] = origin[i]; + + UpdateTiles(gHUD.m_flTime, bitsDamage); + + // Actually took damage? + if ( damageTaken > 0 || armor > 0 ) + CalcDamageDirection(vecFrom); + + return 1; +} + + +// Returns back a color from the +// Green <-> Yellow <-> Red ramp +void CHudHealth::GetPainColor( int &r, int &g, int &b ) +{ + int theMaxHealth = gHUD.GetHUDMaxHealth(); + + if (m_iHealth > theMaxHealth/4) + { + gHUD.GetPrimaryHudColor(r, g, b); + } + else + { + r = 250; + g = 0; + b = 0; + } +} + +int CHudHealth::Draw(float flTime) +{ + int r, g, b; + int a = 0, x, y; + int HealthWidth; + + if ( /*!gHUD.GetIsAlive() ||*/ (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) /*|| gEngfuncs.IsSpectateOnly()*/ ) + return 1; + + if ( !m_hSprite ) + m_hSprite = LoadSprite(PAIN_NAME); + + // Has health changed? Flash the health # + if (m_fFade) + { + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = MIN_ALPHA; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + // Potentially se upgrades and health of spectator target + int theUpgrades = gHUD.GetHUDUpgrades(); + + // If health is getting low, make it bright red + int theMaxHealth = gHUD.GetHUDMaxHealth(); + if (m_iHealth <= theMaxHealth/10) + { + a = 255; + } + + GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + int theViewport[4]; + gHUD.GetViewport(theViewport); + + // Only draw health if we have the suit. + if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) + { + HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; + + y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + + x = theViewport[0] + CrossWidth /2; + + int theInset = 0; + if(gHUD.GetIsAlien() && !gHUD.GetIsCombatMode()) + { + theInset = ScreenWidth()*kResourceEnergyBarWidth; + } + x += theInset;// + kHealthLeftInset*ScreenWidth; + + SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); + + x += CrossWidth + HealthWidth / 2; + + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); + + x += HealthWidth/2; + + gHUD.GetPrimaryHudColor(r, g, b); + + int iHeight = gHUD.m_iFontHeight; + int iWidth = HealthWidth/10; + FillRGBA(x, y, iWidth, iHeight, r, g, b, a); + } + + DrawDamage(flTime); + return DrawPain(flTime); +} + +void CHudHealth::CalcDamageDirection(vec3_t vecFrom) +{ + vec3_t forward, right, up; + float side, front; + vec3_t vecOrigin, vecAngles; + + if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + return; + } + + + memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); + memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); + + + VectorSubtract (vecFrom, vecOrigin, vecFrom); + + float flDistToTarget = vecFrom.Length(); + + vecFrom = vecFrom.Normalize(); + AngleVectors (vecAngles, forward, right, up); + + front = DotProduct (vecFrom, right); + side = DotProduct (vecFrom, forward); + + if (flDistToTarget <= 50) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; + } + else + { + if (side > 0) + { + if (side > 0.3) + m_fAttackFront = max(m_fAttackFront, side); + } + else + { + float f = fabs(side); + if (f > 0.3) + m_fAttackRear = max(m_fAttackRear, f); + } + + if (front > 0) + { + if (front > 0.3) + m_fAttackRight = max(m_fAttackRight, front); + } + else + { + float f = fabs(front); + if (f > 0.3) + m_fAttackLeft = max(m_fAttackLeft, f); + } + } +} + +int CHudHealth::DrawPain(float flTime) +{ + if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) + return 1; + + int r, g, b; + int x, y, a, shade; + + // TODO: get the shift value of the health + a = 255; // max brightness until then + + float fFade = gHUD.m_flTimeDelta * 2; + + // SPR_Draw top + if (m_fAttackFront > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackFront, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth()/2 - SPR_Width(m_hSprite, 0)/2; + y = ScreenHeight()/2 - SPR_Height(m_hSprite,0) * 3; + SPR_DrawAdditive(0, x, y, NULL); + m_fAttackFront = max( 0, m_fAttackFront - fFade ); + } else + m_fAttackFront = 0; + + if (m_fAttackRight > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRight, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth()/2 + SPR_Width(m_hSprite, 1) * 2; + y = ScreenHeight()/2 - SPR_Height(m_hSprite,1)/2; + SPR_DrawAdditive(1, x, y, NULL); + m_fAttackRight = max( 0, m_fAttackRight - fFade ); + } else + m_fAttackRight = 0; + + if (m_fAttackRear > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRear, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth()/2 - SPR_Width(m_hSprite, 2)/2; + y = ScreenHeight()/2 + SPR_Height(m_hSprite,2) * 2; + SPR_DrawAdditive(2, x, y, NULL); + m_fAttackRear = max( 0, m_fAttackRear - fFade ); + } else + m_fAttackRear = 0; + + if (m_fAttackLeft > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackLeft, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth()/2 - SPR_Width(m_hSprite, 3) * 3; + y = ScreenHeight()/2 - SPR_Height(m_hSprite,3)/2; + SPR_DrawAdditive(3, x, y, NULL); + + m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); + } else + m_fAttackLeft = 0; + + return 1; +} + +int CHudHealth::DrawDamage(float flTime) +{ + int r, g, b, a; + DAMAGE_IMAGE *pdmg; + + if (!m_bitsDamage) + return 1; + + gHUD.GetPrimaryHudColor(r, g, b); + a = (int)( fabs(sin(flTime*2)) * 256.0); + + ScaleColors(r, g, b, a); + + // Draw all the items + int i; + for (i = 0; i < NUM_DMG_TYPES; i++) + { + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg = &m_dmg[i]; + SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); + SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); + } + } + + + // check for bits that should be expired + for ( i = 0; i < NUM_DMG_TYPES; i++ ) + { + DAMAGE_IMAGE *pdmg = &m_dmg[i]; + + if ( m_bitsDamage & giDmgFlags[i] ) + { + pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); + + if ( pdmg->fExpire <= flTime // when the time has expired + && a < 40 ) // and the flash is at the low point of the cycle + { + pdmg->fExpire = 0; + + int y = pdmg->y; + pdmg->x = pdmg->y = 0; + + // move everyone above down + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + pdmg = &m_dmg[j]; + if ((pdmg->y) && (pdmg->y < y)) + pdmg->y += giDmgHeight; + + } + + m_bitsDamage &= ~giDmgFlags[i]; // clear the bits + } + } + } + + return 1; +} + + +void CHudHealth::UpdateTiles(float flTime, long bitsDamage) +{ + DAMAGE_IMAGE *pdmg; + + // Which types are new? + long bitsOn = ~m_bitsDamage & bitsDamage; + + for (int i = 0; i < NUM_DMG_TYPES; i++) + { + pdmg = &m_dmg[i]; + + // Is this one already on? + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration + if (!pdmg->fBaseline) + pdmg->fBaseline = flTime; + } + + // Are we just turning it on? + if (bitsOn & giDmgFlags[i]) + { + // put this one at the bottom + pdmg->x = giDmgWidth/8; + pdmg->y = ScreenHeight() - giDmgHeight * 2; + pdmg->fExpire=flTime + DMG_IMAGE_LIFE; + + // move everyone else up + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + if (j == i) + continue; + + pdmg = &m_dmg[j]; + if (pdmg->y) + pdmg->y -= giDmgHeight; + + } + pdmg = &m_dmg[i]; + } + } + + // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) + m_bitsDamage |= bitsDamage; +} + + +void CreateCorpse ( Vector vOrigin, Vector vAngles, const char *pModel, float flAnimTime, int iSequence, int iBody ); diff --git a/main/source/cl_dll/health.h b/main/source/cl_dll/health.h index c108b0be..737089d4 100644 --- a/main/source/cl_dll/health.h +++ b/main/source/cl_dll/health.h @@ -1,117 +1,117 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef HEALTH_H -#define HEALTH_H - -#define DMG_IMAGE_LIFE 2 // seconds that image is up - -#define DMG_IMAGE_POISON 0 -#define DMG_IMAGE_ACID 1 -#define DMG_IMAGE_COLD 2 -#define DMG_IMAGE_DROWN 3 -#define DMG_IMAGE_BURN 4 -#define DMG_IMAGE_NERVE 5 -#define DMG_IMAGE_RAD 6 -#define DMG_IMAGE_SHOCK 7 -//tf defines -#define DMG_IMAGE_CALTROP 8 -#define DMG_IMAGE_TRANQ 9 -#define DMG_IMAGE_CONCUSS 10 -#define DMG_IMAGE_HALLUC 11 -#define NUM_DMG_TYPES 12 -// instant damage - -//// time-based damage -////mask off TF-specific stuff too -//#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage -// -// -//#define DMG_DROWN (1 << 14) // Drowning -//#define DMG_FIRSTTIMEBASED DMG_DROWN -// -//#define DMG_PARALYZE (1 << 15) // slows affected creature down -//#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad -//#define DMG_POISON (1 << 17) // blood poisioning -//#define DMG_RADIATION (1 << 18) // radiation exposure -//#define DMG_DROWNRECOVER (1 << 19) // drowning recovery -//#define DMG_ACID (1 << 20) // toxic chemicals or acid burns -//#define DMG_SLOWBURN (1 << 21) // in an oven -//#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer -//#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) -// -////TF ADDITIONS -//#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn -//#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance -//#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. -//#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor -//#define DMG_AIMED (1 << 28) // Does Hit location damage -//#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls -// -//#define DMG_CALTROP (1<<30) -//#define DMG_HALLUC (1<<31) -#include "damagetypes.h" - -// TF Healing Additions for TakeHealth -#define DMG_IGNORE_MAXHEALTH DMG_IGNITE -// TF Redefines since we never use the originals -#define DMG_NAIL DMG_SLASH -#define DMG_NOT_SELF DMG_FREEZE - - -#define DMG_TRANQ DMG_MORTAR -#define DMG_CONCUSS DMG_SONIC - - - -typedef struct -{ - float fExpire; - float fBaseline; - int x, y; -} DAMAGE_IMAGE; - -// -//----------------------------------------------------- -// -class CHudHealth: public CHudBase -{ -public: - virtual int Init( void ); - virtual int VidInit( void ); - virtual int Draw(float fTime); - virtual void Reset( void ); - int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); - int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); - int m_iHealth; - int m_HUD_dmg_bio; - int m_HUD_cross; - float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; - void GetPainColor( int &r, int &g, int &b ); - float m_fFade; - -private: - HSPRITE m_hSprite; - HSPRITE m_hDamage; - - DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; - int m_bitsDamage; - int DrawPain(float fTime); - int DrawDamage(float fTime); - void CalcDamageDirection(vec3_t vecFrom); - void UpdateTiles(float fTime, long bits); -}; - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef HEALTH_H +#define HEALTH_H + +#define DMG_IMAGE_LIFE 2 // seconds that image is up + +#define DMG_IMAGE_POISON 0 +#define DMG_IMAGE_ACID 1 +#define DMG_IMAGE_COLD 2 +#define DMG_IMAGE_DROWN 3 +#define DMG_IMAGE_BURN 4 +#define DMG_IMAGE_NERVE 5 +#define DMG_IMAGE_RAD 6 +#define DMG_IMAGE_SHOCK 7 +//tf defines +#define DMG_IMAGE_CALTROP 8 +#define DMG_IMAGE_TRANQ 9 +#define DMG_IMAGE_CONCUSS 10 +#define DMG_IMAGE_HALLUC 11 +#define NUM_DMG_TYPES 12 +// instant damage + +//// time-based damage +////mask off TF-specific stuff too +//#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage +// +// +//#define DMG_DROWN (1 << 14) // Drowning +//#define DMG_FIRSTTIMEBASED DMG_DROWN +// +//#define DMG_PARALYZE (1 << 15) // slows affected creature down +//#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +//#define DMG_POISON (1 << 17) // blood poisioning +//#define DMG_RADIATION (1 << 18) // radiation exposure +//#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +//#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +//#define DMG_SLOWBURN (1 << 21) // in an oven +//#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer +//#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) +// +////TF ADDITIONS +//#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +//#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +//#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +//#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +//#define DMG_AIMED (1 << 28) // Does Hit location damage +//#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls +// +//#define DMG_CALTROP (1<<30) +//#define DMG_HALLUC (1<<31) +#include "damagetypes.h" + +// TF Healing Additions for TakeHealth +#define DMG_IGNORE_MAXHEALTH DMG_IGNITE +// TF Redefines since we never use the originals +#define DMG_NAIL DMG_SLASH +#define DMG_NOT_SELF DMG_FREEZE + + +#define DMG_TRANQ DMG_MORTAR +#define DMG_CONCUSS DMG_SONIC + + + +typedef struct +{ + float fExpire; + float fBaseline; + int x, y; +} DAMAGE_IMAGE; + +// +//----------------------------------------------------- +// +class CHudHealth: public CHudBase +{ +public: + virtual int Init( void ); + virtual int VidInit( void ); + virtual int Draw(float fTime); + virtual void Reset( void ); + int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); + int m_iHealth; + int m_HUD_dmg_bio; + int m_HUD_cross; + float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; + void GetPainColor( int &r, int &g, int &b ); + float m_fFade; + +private: + HSPRITE m_hSprite; + HSPRITE m_hDamage; + + DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; + int m_bitsDamage; + int DrawPain(float fTime); + int DrawDamage(float fTime); + void CalcDamageDirection(vec3_t vecFrom); + void UpdateTiles(float fTime, long bits); +}; + +#endif diff --git a/main/source/cl_dll/hl/hl_baseentity.cpp b/main/source/cl_dll/hl/hl_baseentity.cpp index ab07154a..bd979c41 100644 --- a/main/source/cl_dll/hl/hl_baseentity.cpp +++ b/main/source/cl_dll/hl/hl_baseentity.cpp @@ -1,290 +1,290 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -/* -========================== -This file contains "stubs" of class member implementations so that we can predict certain - weapons client side. From time to time you might find that you need to implement part of the - these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and - add in the functionality you need. -========================== -*/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "skill.h" - -// Globals used by game logic -const Vector g_vecZero = Vector( 0, 0, 0 ); -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; - -ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } - -// CBaseEntity Stubs -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } -int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } -CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } -int CBaseEntity::Save( CSave &save ) { return 1; } -int CBaseEntity::Restore( CRestore &restore ) { return 1; } -void CBaseEntity::SetObjectCollisionBox( void ) { } -int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } -void CBaseEntity :: MakeDormant( void ) { } -int CBaseEntity :: IsDormant( void ) { return 0; } -BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } -int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } -int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } -CBaseEntity * CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } -void CBaseEntity::SUB_Remove( void ) { } -void CBaseEntity::AddChecksum(Checksum& inChecksum) {} -void CBaseEntity::UpdateOnRemove() {} - -// CBaseDelay Stubs -void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } -int CBaseDelay::Restore( class CRestore & ) { return 1; } -int CBaseDelay::Save( class CSave & ) { return 1; } - -// CBaseAnimating Stubs -int CBaseAnimating::Restore( class CRestore & ) { return 1; } -int CBaseAnimating::Save( class CSave & ) { return 1; } - -// DEBUG Stubs -edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } - -// UTIL_* Stubs -void UTIL_PrecacheOther( const char *szClassname ) { } -void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } -void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } -void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } -void UTIL_MakeVectors( const Vector &vecAngles ) { } -BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } -void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } -BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } -void UTIL_LogPrintf(char *,...) { } -void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } -void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } - -// CBaseToggle Stubs -int CBaseToggle::Restore( class CRestore & ) { return 1; } -int CBaseToggle::Save( class CSave & ) { return 1; } -void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } -void CBaseToggle::SaveDataForReset() {} -void CBaseToggle::ResetEntity() {} - -// CGrenade Stubs -void CGrenade::BounceSound( void ) { } -void CGrenade::Explode( Vector, Vector ) { } -void CGrenade::Explode( TraceResult *, int ) { } -void CGrenade::Killed( entvars_t *, int ) { } -void CGrenade::Spawn( void ) { } -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } -CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } -void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } -void CGrenade::SetDamageType(int inDamageType) {} //@linux otherwise it says undefined symbol - -void UTIL_Remove( CBaseEntity *pEntity ){ } -struct skilldata_t gSkillData; -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } -CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} - -Vector UTIL_VecToAngles( const Vector &vec ){ return 0; } -CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { return 0; } -void CBeam::PointEntInit( const Vector &start, int endIndex ) { } -CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } -void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } - - -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ) { return NULL; } -int CBaseMonster::GetHull() const { return head_hull; } -void CBaseMonster :: Look ( int iDistance ) { } -float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } -float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } -int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } -int CBaseAnimating :: LookupSequence ( const char *label, int queue ) { return 0; } -void CBaseAnimating :: ResetSequenceInfo ( ) { } -BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } -void CBaseAnimating :: InitBoneControllers ( void ) { } -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } -void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } -int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int inDamageType ) { } -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } -void CBaseMonster::ReportAIState( void ) { } -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } -BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } -void CBaseMonster::CorpseFallThink( void ) { } -void CBaseMonster :: MonsterInitDead( void ) { } -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } -void CBaseMonster::FadeMonster( void ) { } -void CBaseMonster :: GibMonster( void ) { } -BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } -BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } -Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } -void CBaseMonster::BecomeDead( void ) {} -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } - -int TrainSpeed(int iSpeed, int iMax) { return 0; } -void CBasePlayer :: DeathSound( void ) { } -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } -void CBasePlayer :: TabulateAmmo() { } -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } -void CBasePlayer::PackDeadPlayerItems( void ) { } -void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } -void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } -void CBasePlayer::WaterMove() { } -void CBasePlayer :: InitPlayerFromSpawn(edict_t* inSpawn) {} -BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } -BOOL CBasePlayer::IsAlive() const { return FALSE; } -BOOL CBasePlayer::IsAlive(bool) const { return FALSE; } -void CBasePlayer::PlayerDeathThink(void) { } -void CBasePlayer::StartDeathCam( void ) { } -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } -void CBasePlayer::StopObserver() { } -void CBasePlayer::PlayerUse ( void ) { } -void CBasePlayer::Jump() { } -void CBasePlayer::Duck( ) { } -int CBasePlayer::Classify ( void ) { return 0; } -void CBasePlayer::PreThink(void) { } -void CBasePlayer::CheckTimeBasedDamage() { } -void CBasePlayer :: UpdateGeigerCounter( void ) { } -void CBasePlayer::CheckSuitUpdate() { } -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } -void CBasePlayer :: UpdatePlayerSound ( void ) { } -void CBasePlayer::PostThink() { } -void CBasePlayer::EffectivePlayerClassChanged() {} -void CBasePlayer::NeedsTeamUpdate() {} -void CBasePlayer::SendTeamUpdate() {} -void CBasePlayer::Suicide() {} -void CBasePlayer :: Precache( void ) { } -int CBasePlayer::Save( CSave &save ) { return 0; } -void CBasePlayer::RenewItems(void) { } -int CBasePlayer::Restore( CRestore &restore ) { return 0; } -void CBasePlayer::SelectNextItem( int iItem ) { } -BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } -void CBasePlayer::SelectPrevItem( int iItem ) { } -CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } -void CBasePlayer::ForceClientDllUpdate( void ) { } -void CBasePlayer::ImpulseCommands( ) { } -void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } -int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } -void CBasePlayer::ItemPreFrame() { } -void CBasePlayer::ItemPostFrame() { } -int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } -int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } -int CBasePlayer::GetMaxWalkSpeed() const { return 220; } -void CBasePlayer::SendAmmoUpdate(void) { } -void CBasePlayer::SendWeaponUpdate() {} -void CBasePlayer :: UpdateClientData( void ) { } -BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } -void CBasePlayer :: BarnacleVictimReleased ( void ) { } -int CBasePlayer :: Illumination( void ) { return 0; } -void CBasePlayer :: EnableControl(BOOL fControl) { } -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } -void CBasePlayer :: ResetAutoaim( ) { } -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } -int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } -void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } -BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } -Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } -char *CBasePlayer::TeamID( void ) { return ""; } -void CBasePlayer::SetTeamID(const char* inTeamID) {}; -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } -void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } -void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } -void CBasePlayer::GiveNamedItem(const char* szName, bool inSendMessage) { } - -void ClearMultiDamage(void) { } -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } -int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } -void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } -void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } - -BOOL CBasePlayerItem::CanDeploy( void ) { return TRUE; } -BOOL CBasePlayerItem::CanHolster( void ) { return TRUE; } -BOOL CBasePlayerItem::Deploy( ) { return TRUE; } -BOOL CBasePlayerItem::IsUseable( void ) { return TRUE; } -void CBasePlayerItem::Spawn() {} - -int CBasePlayerItem::Restore( class CRestore & ) { return 1; } -int CBasePlayerItem::Save( class CSave & ) { return 1; } -int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } -int CBasePlayerWeapon::Save( class CSave & ) { return 1; } -void CBasePlayerItem :: SetObjectCollisionBox( void ) { } -void CBasePlayerItem :: FallInit( void ) { } -void CBasePlayerItem::FallThink ( void ) { } -void CBasePlayerItem::Materialize( void ) { } -void CBasePlayerItem::AttemptToMaterialize( void ) { } -void CBasePlayerItem :: CheckRespawn ( void ) { } -CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } -void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } -void CBasePlayerItem::DestroyItem( void ) { } -void CBasePlayerItem::VirtualDestroyItem( void ) { } -int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } -void CBasePlayerItem::Drop( void ) { } -void CBasePlayerItem::Kill( void ) { } -void CBasePlayerItem::Holster( int skiplocal ) { } -void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } -int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } -int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } -int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } -BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } -int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } -int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } -void CBasePlayerAmmo::Spawn( void ) { } -CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } -void CBasePlayerAmmo::Materialize( void ) { } -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } -int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } -int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } -void CBasePlayerWeapon::RetireWeapon( void ) { } -void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} -void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +/* +========================== +This file contains "stubs" of class member implementations so that we can predict certain + weapons client side. From time to time you might find that you need to implement part of the + these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and + add in the functionality you need. +========================== +*/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "skill.h" + +// Globals used by game logic +const Vector g_vecZero = Vector( 0, 0, 0 ); +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + +ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } + +// CBaseEntity Stubs +int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } +int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } +CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } +int CBaseEntity::Save( CSave &save ) { return 1; } +int CBaseEntity::Restore( CRestore &restore ) { return 1; } +void CBaseEntity::SetObjectCollisionBox( void ) { } +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } +void CBaseEntity :: MakeDormant( void ) { } +int CBaseEntity :: IsDormant( void ) { return 0; } +BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } +int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } +int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } +CBaseEntity * CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +void CBaseEntity::SUB_Remove( void ) { } +void CBaseEntity::AddChecksum(Checksum& inChecksum) {} +void CBaseEntity::UpdateOnRemove() {} + +// CBaseDelay Stubs +void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } +int CBaseDelay::Restore( class CRestore & ) { return 1; } +int CBaseDelay::Save( class CSave & ) { return 1; } + +// CBaseAnimating Stubs +int CBaseAnimating::Restore( class CRestore & ) { return 1; } +int CBaseAnimating::Save( class CSave & ) { return 1; } + +// DEBUG Stubs +edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } + +// UTIL_* Stubs +void UTIL_PrecacheOther( const char *szClassname ) { } +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } +void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_MakeVectors( const Vector &vecAngles ) { } +BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } +void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } +void UTIL_LogPrintf(char *,...) { } +void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } +void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } + +// CBaseToggle Stubs +int CBaseToggle::Restore( class CRestore & ) { return 1; } +int CBaseToggle::Save( class CSave & ) { return 1; } +void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } +void CBaseToggle::SaveDataForReset() {} +void CBaseToggle::ResetEntity() {} + +// CGrenade Stubs +void CGrenade::BounceSound( void ) { } +void CGrenade::Explode( Vector, Vector ) { } +void CGrenade::Explode( TraceResult *, int ) { } +void CGrenade::Killed( entvars_t *, int ) { } +void CGrenade::Spawn( void ) { } +CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } +CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } +void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } +void CGrenade::SetDamageType(int inDamageType) {} //@linux otherwise it says undefined symbol + +void UTIL_Remove( CBaseEntity *pEntity ){ } +struct skilldata_t gSkillData; +void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } +CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} + +Vector UTIL_VecToAngles( const Vector &vec ){ return 0; } +CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { return 0; } +void CBeam::PointEntInit( const Vector &start, int endIndex ) { } +CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } +void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } + + +CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ) { return NULL; } +int CBaseMonster::GetHull() const { return head_hull; } +void CBaseMonster :: Look ( int iDistance ) { } +float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } +BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } +float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } +int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } +int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } +int CBaseAnimating :: LookupSequence ( const char *label, int queue ) { return 0; } +void CBaseAnimating :: ResetSequenceInfo ( ) { } +BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } +void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } +float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } +void CBaseAnimating :: InitBoneControllers ( void ) { } +float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } +void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } +void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } +int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } +void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } +void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } +int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } +void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int inDamageType ) { } +void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } +void CBaseMonster::ReportAIState( void ) { } +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } +BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } +void CBaseMonster::CorpseFallThink( void ) { } +void CBaseMonster :: MonsterInitDead( void ) { } +void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } +void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::FadeMonster( void ) { } +void CBaseMonster :: GibMonster( void ) { } +BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } +BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } +Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } +void CBaseMonster::BecomeDead( void ) {} +void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} +int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } +int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } + +int TrainSpeed(int iSpeed, int iMax) { return 0; } +void CBasePlayer :: DeathSound( void ) { } +int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } +void CBasePlayer :: TabulateAmmo() { } +void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +void CBasePlayer::PackDeadPlayerItems( void ) { } +void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } +void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } +void CBasePlayer::WaterMove() { } +void CBasePlayer :: InitPlayerFromSpawn(edict_t* inSpawn) {} +BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } +BOOL CBasePlayer::IsAlive() const { return FALSE; } +BOOL CBasePlayer::IsAlive(bool) const { return FALSE; } +void CBasePlayer::PlayerDeathThink(void) { } +void CBasePlayer::StartDeathCam( void ) { } +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } +void CBasePlayer::StopObserver() { } +void CBasePlayer::PlayerUse ( void ) { } +void CBasePlayer::Jump() { } +void CBasePlayer::Duck( ) { } +int CBasePlayer::Classify ( void ) { return 0; } +void CBasePlayer::PreThink(void) { } +void CBasePlayer::CheckTimeBasedDamage() { } +void CBasePlayer :: UpdateGeigerCounter( void ) { } +void CBasePlayer::CheckSuitUpdate() { } +void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } +void CBasePlayer :: UpdatePlayerSound ( void ) { } +void CBasePlayer::PostThink() { } +void CBasePlayer::EffectivePlayerClassChanged() {} +void CBasePlayer::NeedsTeamUpdate() {} +void CBasePlayer::SendTeamUpdate() {} +void CBasePlayer::Suicide() {} +void CBasePlayer :: Precache( void ) { } +int CBasePlayer::Save( CSave &save ) { return 0; } +void CBasePlayer::RenewItems(void) { } +int CBasePlayer::Restore( CRestore &restore ) { return 0; } +void CBasePlayer::SelectNextItem( int iItem ) { } +BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } +void CBasePlayer::SelectPrevItem( int iItem ) { } +CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } +void CBasePlayer::ForceClientDllUpdate( void ) { } +void CBasePlayer::ImpulseCommands( ) { } +void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } +int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +void CBasePlayer::ItemPreFrame() { } +void CBasePlayer::ItemPostFrame() { } +int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } +int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } +int CBasePlayer::GetMaxWalkSpeed() const { return 220; } +void CBasePlayer::SendAmmoUpdate(void) { } +void CBasePlayer::SendWeaponUpdate() {} +void CBasePlayer :: UpdateClientData( void ) { } +BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } +void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBasePlayer :: BarnacleVictimReleased ( void ) { } +int CBasePlayer :: Illumination( void ) { return 0; } +void CBasePlayer :: EnableControl(BOOL fControl) { } +Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } +Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } +void CBasePlayer :: ResetAutoaim( ) { } +void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } +int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } +void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } +BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } +BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } +Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } +char *CBasePlayer::TeamID( void ) { return ""; } +void CBasePlayer::SetTeamID(const char* inTeamID) {}; +int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } +void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } +void CBasePlayer::GiveNamedItem(const char* szName, bool inSendMessage) { } + +void ClearMultiDamage(void) { } +void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } +void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } +int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } +void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } +void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } +void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } + +BOOL CBasePlayerItem::CanDeploy( void ) { return TRUE; } +BOOL CBasePlayerItem::CanHolster( void ) { return TRUE; } +BOOL CBasePlayerItem::Deploy( ) { return TRUE; } +BOOL CBasePlayerItem::IsUseable( void ) { return TRUE; } +void CBasePlayerItem::Spawn() {} + +int CBasePlayerItem::Restore( class CRestore & ) { return 1; } +int CBasePlayerItem::Save( class CSave & ) { return 1; } +int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } +int CBasePlayerWeapon::Save( class CSave & ) { return 1; } +void CBasePlayerItem :: SetObjectCollisionBox( void ) { } +void CBasePlayerItem :: FallInit( void ) { } +void CBasePlayerItem::FallThink ( void ) { } +void CBasePlayerItem::Materialize( void ) { } +void CBasePlayerItem::AttemptToMaterialize( void ) { } +void CBasePlayerItem :: CheckRespawn ( void ) { } +CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } +void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } +void CBasePlayerItem::DestroyItem( void ) { } +void CBasePlayerItem::VirtualDestroyItem( void ) { } +int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } +void CBasePlayerItem::Drop( void ) { } +void CBasePlayerItem::Kill( void ) { } +void CBasePlayerItem::Holster( int skiplocal ) { } +void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } +int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } +int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } +int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } +BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } +BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } +BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } +int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } +void CBasePlayerAmmo::Spawn( void ) { } +CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } +void CBasePlayerAmmo::Materialize( void ) { } +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } +int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +void CBasePlayerWeapon::RetireWeapon( void ) { } +void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} +void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} diff --git a/main/source/cl_dll/hl/hl_events.cpp b/main/source/cl_dll/hl/hl_events.cpp index fa599625..92ecf363 100644 --- a/main/source/cl_dll/hl/hl_events.cpp +++ b/main/source/cl_dll/hl/hl_events.cpp @@ -1,98 +1,98 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "../hud.h" -#include "../cl_util.h" -#include "event_api.h" -#include "mod/AvHMarineWeaponConstants.h" -#include "mod/AvHAlienWeaponConstants.h" - -extern "C" -{ -// HLDM -void EV_FireGlock1( struct event_args_s *args ); -void EV_FireGlock2( struct event_args_s *args ); -void EV_FireShotGunSingle( struct event_args_s *args ); -void EV_FireShotGunDouble( struct event_args_s *args ); -void EV_FireMP5( struct event_args_s *args ); -void EV_FireMP52( struct event_args_s *args ); -void EV_FirePython( struct event_args_s *args ); -void EV_FireGauss( struct event_args_s *args ); -void EV_SpinGauss( struct event_args_s *args ); -void EV_Crowbar( struct event_args_s *args ); -void EV_FireCrossbow( struct event_args_s *args ); -void EV_FireCrossbow2( struct event_args_s *args ); -void EV_FireRpg( struct event_args_s *args ); -void EV_EgonFire( struct event_args_s *args ); -void EV_EgonStop( struct event_args_s *args ); -void EV_HornetGunFire( struct event_args_s *args ); -void EV_TripmineFire( struct event_args_s *args ); -void EV_SnarkFire( struct event_args_s *args ); - - - -void EV_TrainPitchAdjust( struct event_args_s *args ); -} - -/* -====================== -Game_HookEvents - -Associate script file name with callback functions. Callback's must be extern "C" so - the engine doesn't get confused about name mangling stuff. Note that the format is - always the same. Of course, a clever mod team could actually embed parameters, behavior - into the actual .sc files and create a .sc file parser and hook their functionality through - that.. i.e., a scripting system. - -That was what we were going to do, but we ran out of time...oh well. -====================== -*/ - -#define AVH_HOOK_EVENT(s) gEngfuncs.pfnHookEvent("events/"#s".dsc", EV_#s) - -void Game_HookEvents( void ) -{ -// gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); -// gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); -// gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); -// gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); -// gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); -// gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); -// gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); -// gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); -// gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); - -// AVH_HOOK_EVENT(kMGEventName); - -// gEngfuncs.pfnHookEvent("events/train.sc", EV_TrainPitchAdjust); -// gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); -// gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); -// gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); -// gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); -// gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); -// gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); -// gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); -// gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); -// gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); -// gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); -// gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); -// gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); -// gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); -// gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); -// gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); -// gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); -// gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); -// gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); -// gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "event_api.h" +#include "mod/AvHMarineWeaponConstants.h" +#include "mod/AvHAlienWeaponConstants.h" + +extern "C" +{ +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +/* +====================== +Game_HookEvents + +Associate script file name with callback functions. Callback's must be extern "C" so + the engine doesn't get confused about name mangling stuff. Note that the format is + always the same. Of course, a clever mod team could actually embed parameters, behavior + into the actual .sc files and create a .sc file parser and hook their functionality through + that.. i.e., a scripting system. + +That was what we were going to do, but we ran out of time...oh well. +====================== +*/ + +#define AVH_HOOK_EVENT(s) gEngfuncs.pfnHookEvent("events/"#s".dsc", EV_#s) + +void Game_HookEvents( void ) +{ +// gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); +// gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); +// gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); +// gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); +// gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); +// gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); +// gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); +// gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); +// gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); + +// AVH_HOOK_EVENT(kMGEventName); + +// gEngfuncs.pfnHookEvent("events/train.sc", EV_TrainPitchAdjust); +// gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); +// gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); +// gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); +// gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); +// gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); +// gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); +// gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); +// gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); +// gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); +// gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); +// gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); +// gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); +// gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); +// gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); +// gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); +// gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); +// gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); +// gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); +// gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); +} diff --git a/main/source/cl_dll/hl/hl_objects.cpp b/main/source/cl_dll/hl/hl_objects.cpp index e84762b8..bb832135 100644 --- a/main/source/cl_dll/hl/hl_objects.cpp +++ b/main/source/cl_dll/hl/hl_objects.cpp @@ -1,89 +1,89 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "../hud.h" -#include "../cl_util.h" -#include "../demo.h" - -#include "demo_api.h" -#include "const.h" -#include "entity_state.h" -#include "cl_entity.h" - -#include "pm_defs.h" -#include "event_api.h" -#include "entity_types.h" -#include "r_efx.h" - -extern BEAM *pBeam; -extern BEAM *pBeam2; -void HUD_GetLastOrg( float *org ); - -void UpdateBeams ( void ) -{ - vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; - vec3_t view_ofs; - pmtrace_t tr; - cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); - int idx = pthisplayer->index; - - // Get our exact viewangles from engine - gEngfuncs.GetViewAngles( (float *)angles ); - - // Determine our last predicted origin - HUD_GetLastOrg( (float *)&origin ); - - AngleVectors( angles, forward, right, up ); - - VectorCopy( origin, vecSrc ); - VectorMA( vecSrc, 2048, forward, vecEnd ); - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - if ( pBeam ) - { - pBeam->target = tr.endpos; - pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. - } - - if ( pBeam2 ) - { - pBeam2->target = tr.endpos; - pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. - } -} - -/* -===================== -Game_AddObjects - -Add game specific, client-side objects here -===================== -*/ -void Game_AddObjects( void ) -{ - if ( pBeam && pBeam2 ) - UpdateBeams(); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "../demo.h" + +#include "demo_api.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "pm_defs.h" +#include "event_api.h" +#include "entity_types.h" +#include "r_efx.h" + +extern BEAM *pBeam; +extern BEAM *pBeam2; +void HUD_GetLastOrg( float *org ); + +void UpdateBeams ( void ) +{ + vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; + vec3_t view_ofs; + pmtrace_t tr; + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + int idx = pthisplayer->index; + + // Get our exact viewangles from engine + gEngfuncs.GetViewAngles( (float *)angles ); + + // Determine our last predicted origin + HUD_GetLastOrg( (float *)&origin ); + + AngleVectors( angles, forward, right, up ); + + VectorCopy( origin, vecSrc ); + VectorMA( vecSrc, 2048, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( pBeam ) + { + pBeam->target = tr.endpos; + pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } + + if ( pBeam2 ) + { + pBeam2->target = tr.endpos; + pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } +} + +/* +===================== +Game_AddObjects + +Add game specific, client-side objects here +===================== +*/ +void Game_AddObjects( void ) +{ + if ( pBeam && pBeam2 ) + UpdateBeams(); +} diff --git a/main/source/cl_dll/hl/hl_weapons.cpp b/main/source/cl_dll/hl/hl_weapons.cpp index 25d00835..f6283e59 100644 --- a/main/source/cl_dll/hl/hl_weapons.cpp +++ b/main/source/cl_dll/hl/hl_weapons.cpp @@ -1,1537 +1,1537 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -* Modified by Charlie Cleveland: -* -* $Workfile: hl_weapons.cpp $ -* $Date: 2002/10/24 21:11:52 $ -* -* ------------------------------------------------------------------------------- -* $Log: hl_weapons.cpp,v $ -* Revision 1.31 2002/10/24 21:11:52 Flayra -* - Updated jetpack effect because it was really buggy this old way -* -* Revision 1.30 2002/10/16 02:12:10 Flayra -* - Valve anti-cheat integrated! -* -* Revision 1.29 2002/10/16 00:36:40 Flayra -* - Removed blink fail -* -* Revision 1.28 2002/08/31 18:01:59 Flayra -* - Work at VALVe -* -* Revision 1.27 2002/07/08 16:09:03 Flayra -* - Removed unneeded code here, so random numbers were generated properly on both client and server -* -* Revision 1.26 2002/07/01 20:56:31 Flayra -* - Added babbler gun -* -* Revision 1.25 2002/06/25 17:03:01 Flayra -* - Removed old weapons, added new weapons, fixed mines, iuser3 enables and disables weapons -* -* =============================================================================== -****/ -#include "../hud.h" -#include "../cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "../demo.h" -#include "common/usercmd.h" -#include "common/event_flags.h" -#include "common/event_api.h" -#include "cl_dll/com_weapons.h" -#include "cl_dll/ammo.h" -#include "cl_dll/ammohistory.h" -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" -#include "dlls/monsters.h" -#include "dlls/weapons.h" -#include "dlls/nodes.h" -#include "dlls/player.h" -#include "mod/AvHEvents.h" - -#include "common/usercmd.h" -#include "common/entity_state.h" -#include "common/demo_api.h" -#include "pm_shared/pm_defs.h" -#include "common/event_api.h" -#include "common/r_efx.h" - -#include "../hud_iface.h" -#include "../com_weapons.h" - -#include "mod/AvHMarineWeapons.h" -#include "mod/AvHSpecials.h" -#include "mod/AvHAlienWeapons.h" -#include "mod/AvHAlienAbilities.h" -#include "mod/AvHAlienWeaponConstants.h" -#include "mod/AvHAlienAbilityConstants.h" -#include "mod/AvHMovementUtil.h" - -#include "engine/APIProxy.h" -#include "../Exports.h" - -extern globalvars_t *gpGlobals; -extern bool gIsJetpacking; - -// Pool of client side entities/entvars_t -static entvars_t ev[ 32 ]; -static int num_ents = 0; - -// The entity we'll use to represent the local client -static CBasePlayer player; - -// Local version of game .dll global variables ( time, etc. ) -static globalvars_t Globals; - -static CBasePlayerWeapon *g_pWpns[ 32 ]; - -bool CheckInAttack2(void); - -vec3_t previousorigin; - -// HLDM Weapon placeholder entities. -//CGlock g_Glock; - -// NS weapons -AvHKnife gKnife; -AvHMachineGun gMachineGun; -AvHPistol gPistol; -AvHSonicGun gSonicGun; -AvHHeavyMachineGun gHeavyMachineGun; -AvHGrenadeGun gGrenadeGun; -AvHGrenade gGrenade; -AvHWelder gWelder; -AvHMine gMine; -AvHSpitGun gSpitGun; -AvHClaws gClaws; -AvHSpore gSpores; -AvHBite gBite; -AvHBite2 gBite2; -AvHSpikeGun gSpikeGun; -AvHSwipe gSwipe; -AvHWebSpinner gWebSpinner; -AvHPrimalScream gPrimalScream; -AvHParasiteGun gParasite; -AvHUmbraGun gUmbra; -AvHBlinkGun gBlink; -AvHDivineWind gDivineWind; -//AvHParalysisGun gParalysisGun; -AvHBileBombGun gBileBomb; -AvHAcidRocketGun gAcidRocket; -AvHHealingSpray gHealingSpray; -AvHMetabolize gMetabolize; -AvHDevour gDevour; -AvHStomp gStomp; - -// Alien abilities -AvHLeap gLeap; -AvHCharge gCharge; - -// Jetpack events -int gJetpackEventID; -//int gWallJumpEventID; -//int gFlightEventID; -int gTeleportEventID; -int gPhaseInEventID; -int gSiegeHitEventID; -int gSiegeViewHitEventID; -int gCommanderPointsAwardedEventID; -int gBlinkEffectSuccessEventID; - -//bool gPlayingJetpack = false; -//CGlock g_Glock; -//CCrowbar g_Crowbar; -//CPython g_Python; -//CMP5 g_Mp5; -//CCrossbow g_Crossbow; -//CShotgun g_Shotgun; -//CRpg g_Rpg; -//CGauss g_Gauss; -//CEgon g_Egon; -//CHgun g_HGun; -//CHandGrenade g_HandGren; -//CSatchel g_Satchel; -//CTripmine g_Tripmine; -//CSqueak g_Snark; - -/* -====================== -AlertMessage - -Print debug messages to console -====================== -*/ -void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, szFmt); -#ifdef WIN32 - //overflow protection in MS version of function... - _vsnprintf( string, 1023, szFmt, argptr ); -#else - vsprintf (string, szFmt,argptr); -#endif - va_end (argptr); - - gEngfuncs.Con_Printf( "cl: " ); - gEngfuncs.Con_Printf( string ); -} - -// Client-side effects for jetpack -void CheckJetpack() -{ - // if local player is jetpacking, play effects immediately -// if(gIsJetpacking && !gPlayingJetpack) -// { -// cl_entity_t* thePlayer; -// thePlayer = gEngfuncs.GetLocalPlayer(); -// ASSERT(thePlayer); -// -// // Play event locally, server will tell everyone else to play event -// gEngfuncs.pEventAPI->EV_PlaybackEvent(0, NULL, gJetpackEventID, 0, thePlayer->origin, (float *)&g_vecZero, 0.0, 0.0, /*theWeaponIndex*/ 0, 0, 0, 0 ); -// -// //gPlayingJetpack = true; -// } - // Check to turn it off too (in case there's a network anomaly or the game resets or something, just trying to be safe) - //else if(!gIsJetpacking && (gPlayingJetpack)) - //{ - // gEngfuncs.pEventAPI->EV_PlaybackEvent(0, NULL, gEndJetpackEventID, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, /*theWeaponIndex*/ 0, 0, 0, 0 ); - // - // gPlayingJetpack = false; - //} -} - -//Returns if it's multiplayer. -//Mostly used by the client side weapons. -bool bIsMultiplayer ( void ) -{ - return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; -} -//Just loads a v_ model. -void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) -{ - gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); -} - -/* -===================== -HUD_PrepEntity - -Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then -we set up the m_pPlayer field. -===================== -*/ -void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) -{ - typedef vector IDListType; - static IDListType sIDList; - - memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); - pEntity->pev = &ev[ num_ents++ ]; - - pEntity->Precache(); - pEntity->Spawn(); - - if ( pWeaponOwner ) - { - ItemInfo info; - - ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; - - ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); - - // ASSERT that a weapon with this id isn't in the list - int theNewID = info.iId; - IDListType::iterator theIter = std::find(sIDList.begin(), sIDList.end(), theNewID); - ASSERT(theIter == sIDList.end()); - - // Insert id into our list - sIDList.push_back(theNewID); - - g_pWpns[ theNewID ] = (CBasePlayerWeapon *)pEntity; - } -} - -/* -===================== -CBaseEntity :: Killed - -If weapons code "kills" an entity, just set its effects to EF_NODRAW -===================== -*/ -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->effects |= EF_NODRAW; -} - -/* -===================== -CBasePlayerWeapon :: DefaultReload -===================== -*/ -BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) -{ - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - return FALSE; - - int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - if (j == 0) - return FALSE; - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; - - //!!UNDONE -- reload sound goes here !!! - //SendWeaponAnim( iAnim, UseDecrement(), body ); - - m_fInReload = TRUE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kDeployIdleInterval; - return TRUE; -} - -/* -===================== -CBasePlayerWeapon :: CanDeploy -===================== -*/ -BOOL CBasePlayerWeapon :: CanDeploy( void ) -{ - BOOL bHasAmmo = 0; - - if ( !pszAmmo1() ) - { - // this weapon doesn't use ammo, can always deploy. - return TRUE; - } - - if ( pszAmmo1() ) - { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); - } - if ( pszAmmo2() ) - { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); - } - if (m_iClip > 0) - { - bHasAmmo |= 1; - } - if (!bHasAmmo) - { - return FALSE; - } - - return TRUE; -} - -/* -===================== -CBasePlayerWeapon :: DefaultDeploy - -===================== -*/ -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) -{ - if ( !CanDeploy() ) - return FALSE; - - gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); - - SendWeaponAnim( iAnim, skiplocal, body ); - - m_pPlayer->m_flNextAttack = this->GetDeployTime(); - m_flTimeWeaponIdle = this->GetDeployTime() + kDeployIdleInterval; - return TRUE; -} - -/* -===================== -CBasePlayerWeapon :: PlayEmptySound - -===================== -*/ -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) -{ - if (m_iPlayEmptySound) - { - HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); - m_iPlayEmptySound = 0; - return 0; - } - return 0; -} - -/* -===================== -CBasePlayerWeapon :: ResetEmptySound - -===================== -*/ -void CBasePlayerWeapon :: ResetEmptySound( void ) -{ - m_iPlayEmptySound = 1; -} - -/* -===================== -CBasePlayerWeapon::Holster - -Put away weapon -===================== -*/ -void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE; // cancel any reload in progress. - m_pPlayer->pev->viewmodel = 0; -} - -/* -===================== -CBasePlayerWeapon::SendWeaponAnim - -Animate weapon model -===================== -*/ -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) -{ - m_pPlayer->pev->weaponanim = iAnim; - - HUD_SendWeaponAnim( iAnim, body, 0 ); -} - -/* -===================== -CBaseEntity::FireBulletsPlayer - -Only produces random numbers to match the server ones. -===================== -*/ -Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) -{ - //float x, y, z; - Vector theShotDirection; - - theShotDirection.x = theShotDirection.y = theShotDirection.z = 0; - -// for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) -// { -// if ( pevAttacker == NULL ) -// { -// // get circular gaussian spread -// do { -// x = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5); -// y = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5); -// z = x*x+y*y; -// } while (z > 1); -// } -// else -// { -// //Use player's random seed. -// // get circular gaussian spread -// x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); -// y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); -// z = x * x + y * y; -// } -// -// UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting) -// } - -// return Vector ( (float)(x * vecSpread.x), (float)(y * vecSpread.y), 0.0f ); - return theShotDirection; -} - - -bool GetCanUseWeapon() -{ - // This mirrors the functionality of AvHPlayer::GetCanUseWeapon. - return !gHUD.GetIsInTopDownMode() && !gHUD.GetIsBeingDigested() && !gHUD.GetIsEnsnared() && !gHUD.GetIsStunned() && gEngfuncs.GetViewModel() != NULL; -} - -/* -===================== -CBasePlayerWeapon::ItemPostFrame - -Handles weapon firing, reloading, etc. -===================== -*/ -void CBasePlayerWeapon::ItemPostFrame( void ) -{ - // Hack initialization - if (this->m_flLastAnimationPlayed >= 3.0f * BALANCE_VAR(kLeapROF) + gpGlobals->time) - this->m_flLastAnimationPlayed = 0.0f; - - if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) - { -/////////////////////////////////////////////////////////////////////////////////////////////////////// -// Put code in here to predict reloads (ie, have the ammo on screen update before we get a response) // -/////////////////////////////////////////////////////////////////////////////////////////////////////// -//#if 0 // FIXME, need ammo on client to make this work right -// // complete the reload. -// int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); -// -// // Add them to the clip -// m_iClip += j; -// m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; -//#else -// m_iClip += 10; -//#endif - m_fInReload = FALSE; - } - - // Properly propagate the end animation - if (this->PrevAttack2Status == true && !(m_pPlayer->pev->button & IN_ATTACK2)) - { - switch (gHUD.GetCurrentWeaponID()) - { - case AVH_WEAPON_SWIPE: - this->SendWeaponAnim(12); - break; - case AVH_WEAPON_ACIDROCKET: - this->SendWeaponAnim(8); - break; - case AVH_WEAPON_CLAWS: - this->SendWeaponAnim(9); - break; - case AVH_WEAPON_STOMP: - this->SendWeaponAnim(8); - break; - case AVH_WEAPON_DEVOUR: - this->SendWeaponAnim(11); - break; - } - } - - if ( (m_pPlayer->pev->button & IN_ATTACK) && !(m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextPrimaryAttack <= 0.0) ) - { - if (GetCanUseWeapon()) - { - if ( (m_iClip == 0 && pszAmmo1()) || - (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) - { - m_fFireOnEmpty = TRUE; - } - - - if ((gHUD.GetHUDUser3() == AVH_USER3_ALIEN_PLAYER1) - && (gHUD.GetCurrentWeaponID() == AVH_ABILITY_LEAP) - && (this->m_flLastAnimationPlayed + (float)BALANCE_VAR(kLeapROF) <= gpGlobals->time)) - { - // : 0001151 predict energy too - AvHAlienWeapon* theWeapon = dynamic_cast(g_pWpns[AVH_ABILITY_LEAP]); - if ( theWeapon && theWeapon->IsUseable() ) { - float theVolumeScalar = 1.0f; - cl_entity_t *player = gEngfuncs.GetLocalPlayer(); - int theSilenceLevel = AvHGetAlienUpgradeLevel(player->curstate.iuser4, MASK_UPGRADE_6); - switch(theSilenceLevel) - { - case 1: - theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel1Volume); - break; - case 2: - theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel2Volume); - break; - case 3: - theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel3Volume); - break; - } - HUD_PlaySound( kLeapSound, theVolumeScalar); - AvHMUDeductAlienEnergy(m_pPlayer->pev->fuser3, theWeapon->GetEnergyForAttack() ); - gEngfuncs.pEventAPI->EV_WeaponAnimation(3, 2); - this->m_flLastAnimationPlayed = gpGlobals->time; - } - } - //#ifdef AVH_CLIENT - //if((m_iClip == 0) && ? - //#endif - PrimaryAttack(); - //return; - } - } - // +movement: Rewritten to allow us to use +attack2 for movement abilities - else if ((m_pPlayer->pev->button & IN_ATTACK2) && (gHUD.GetIsAlien())) - { - //m_flNextSecondaryAttack - // Find out what kind of special movement we are using, and execute the animation for it - if (this->PrevAttack2Status == false) - { - bool enabled=false; - // : 0001151 predict energy too - AvHAlienWeapon *theWeapon = dynamic_cast(g_pWpns[AVH_ABILITY_LEAP]); - if ( theWeapon ) - enabled=theWeapon->IsUseable(); - - switch (gHUD.GetHUDUser3()) - { - case AVH_USER3_ALIEN_PLAYER1: - - if (enabled && (this->m_flLastAnimationPlayed + (float)BALANCE_VAR(kLeapROF) <= gpGlobals->time)) - { - float theVolumeScalar = 1.0f; - cl_entity_t *player = gEngfuncs.GetLocalPlayer(); - int theSilenceLevel = AvHGetAlienUpgradeLevel(player->curstate.iuser4, MASK_UPGRADE_6); - switch(theSilenceLevel) - { - case 1: - theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel1Volume); - break; - case 2: - theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel2Volume); - break; - case 3: - theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel3Volume); - break; - } - HUD_PlaySound( kLeapSound, theVolumeScalar); - AvHMUDeductAlienEnergy(m_pPlayer->pev->fuser3, theWeapon->GetEnergyForAttack() ); - this->SendWeaponAnim(3); - this->m_flLastAnimationPlayed = gpGlobals->time; - } - break; - case AVH_USER3_ALIEN_PLAYER4: - switch (gHUD.GetCurrentWeaponID()) - { - case AVH_WEAPON_SWIPE: - this->SendWeaponAnim(9); - break; - case AVH_WEAPON_ACIDROCKET: - this->SendWeaponAnim(11); - break; - } - break; - case AVH_USER3_ALIEN_PLAYER5: - switch (gHUD.GetCurrentWeaponID()) - { - case AVH_WEAPON_CLAWS: - this->SendWeaponAnim(5); - break; - case AVH_WEAPON_DEVOUR: - this->SendWeaponAnim(18); - break; - case AVH_WEAPON_STOMP: - this->SendWeaponAnim(15); - break; - } - break; - } - } - - if ((gHUD.GetHUDUser3() == AVH_USER3_ALIEN_PLAYER1) - && (this->m_flLastAnimationPlayed + BALANCE_VAR(kLeapROF) < gpGlobals->time)) - this->PrevAttack2Status = false; - else - this->PrevAttack2Status = true; - - return; -// if (GetCanUseWeapon()) -// { -// PrimaryAttack(); -// } - } - else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) - { - if (GetCanUseWeapon()) - { - // reload when reload is pressed, or if no buttons are down and weapon is empty. - Reload(); - } - } - // +movement: Removed case for +attack2 - else if ( !(m_pPlayer->pev->button & (IN_ATTACK /*|IN_ATTACK2 */) ) ) - { - if (GetCanUseWeapon()) - { - - // no fire buttons down - - m_fFireOnEmpty = FALSE; - - // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < 0.0 ) - { - // << CGC >> Only reload if we have more ammo to reload with - if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) - { - Reload(); - return; - } - } - - WeaponIdle( ); - } - this->PrevAttack2Status = false; - return; - } - - this->PrevAttack2Status = false; - - // catch all - if ( ShouldWeaponIdle() ) - { - WeaponIdle(); - } -} - -/* -===================== -CBasePlayer::SelectItem - - Switch weapons -===================== -*/ -void CBasePlayer::SelectItem(const char *pstr) -{ - if (!pstr) - return; - - CBasePlayerItem *pItem = NULL; - - if (!pItem) - return; - - - if (pItem == m_pActiveItem) - return; - - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - m_pLastItem = m_pActiveItem; - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - } -} - -/* -===================== -CBasePlayer::SelectLastItem - -===================== -*/ -void CBasePlayer::SelectLastItem(void) -{ - if (!m_pLastItem) - { - return; - } - - if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) - { - return; - } - - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - CBasePlayerItem *pTemp = m_pActiveItem; - m_pActiveItem = m_pLastItem; - m_pLastItem = pTemp; - m_pActiveItem->Deploy( ); -} - -/* -===================== -CBasePlayer::Killed - -===================== -*/ -void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) -{ - // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); -} - -/* -===================== -CBasePlayer::Spawn - -===================== -*/ -void CBasePlayer::Spawn( void ) -{ - if (m_pActiveItem) - m_pActiveItem->Deploy( ); - -// this->m_flLastAnimationPlayed = gpGlobals->time; -} - -/* -===================== -UTIL_TraceLine - -Don't actually trace, but act like the trace didn't hit anything. -===================== -*/ -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - memset( ptr, 0, sizeof( *ptr ) ); - ptr->flFraction = 1.0; -} - -/* -===================== -UTIL_ParticleBox - -For debugging, draw a box around a player made out of particles -===================== -*/ -void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) -{ - int i; - vec3_t mmin, mmax; - - for ( i = 0; i < 3; i++ ) - { - mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; - mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; - } - - gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); -} - -/* -===================== -UTIL_ParticleBoxes - -For debugging, draw boxes for other collidable players -===================== -*/ -void UTIL_ParticleBoxes( void ) -{ - int idx; - physent_t *pe; - cl_entity_t *player; - vec3_t mins, maxs; - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - player = gEngfuncs.GetLocalPlayer(); - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); - - for ( idx = 1; idx < 100; idx++ ) - { - pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); - if ( !pe ) - break; - - if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) - { - mins = pe->origin + pe->mins; - maxs = pe->origin + pe->maxs; - - gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); - } - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} - -/* -===================== -UTIL_ParticleLine - -For debugging, draw a line made out of particles -===================== -*/ -void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) -{ - gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); -} - -/* -===================== -CBasePlayerWeapon::PrintState - -For debugging, print out state variables to log file -===================== -*/ -void CBasePlayerWeapon::PrintState( void ) -{ - COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); - COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); - COM_Log( "c:\\hl.log", "%i ", m_iClip ); - COM_Log( "c:\\hl.log", "\r\n"); -} - -/* -===================== -HUD_InitClientWeapons - -Set up weapons, player and functions needed to run weapons code client-side. -===================== -*/ -void HUD_InitClientWeapons( void ) -{ - static int initialized = 0; - if ( initialized ) - return; - - initialized = 1; - - // Set up pointer ( dummy object ) - gpGlobals = &Globals; - - // Fill in current time ( probably not needed ) - gpGlobals->time = gEngfuncs.GetClientTime(); - - // Fake functions - g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; - g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; - g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; - g_engfuncs.pfnNameForFunction = stub_NameForFunction; - g_engfuncs.pfnSetModel = stub_SetModel; - g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; - - // Handled locally - g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; - g_engfuncs.pfnAlertMessage = AlertMessage; - - // Pass through to engine - g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; - g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; - g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; - - // Allocate a slot for the local player - HUD_PrepEntity( &player , NULL ); - - - // Allocate slot(s) for each weapon that we are going to be predicting - //HUD_PrepEntity( &g_Glock, &player ); - HUD_PrepEntity( &gKnife, &player); - HUD_PrepEntity( &gMachineGun, &player); - HUD_PrepEntity( &gPistol, &player); - HUD_PrepEntity( &gSonicGun, &player); - HUD_PrepEntity( &gHeavyMachineGun, &player); - HUD_PrepEntity( &gGrenadeGun, &player); - HUD_PrepEntity( &gGrenade, &player); - HUD_PrepEntity( &gWelder, &player); - HUD_PrepEntity( &gMine, &player); - HUD_PrepEntity( &gSpitGun, &player); - HUD_PrepEntity( &gClaws, &player); - HUD_PrepEntity( &gSpores, &player); - HUD_PrepEntity( &gSpikeGun, &player); - HUD_PrepEntity( &gBite, &player); - HUD_PrepEntity( &gBite2, &player); - HUD_PrepEntity( &gSwipe, &player); - HUD_PrepEntity( &gWebSpinner, &player); - HUD_PrepEntity( &gPrimalScream, &player); - //HUD_PrepEntity( &gParalysisGun, &player); - - HUD_PrepEntity( &gBlink, &player); - HUD_PrepEntity( &gParasite, &player); - HUD_PrepEntity( &gUmbra, &player); - HUD_PrepEntity( &gDivineWind, &player); - HUD_PrepEntity( &gBileBomb, &player); - HUD_PrepEntity( &gAcidRocket, &player); - HUD_PrepEntity( &gHealingSpray, &player); - HUD_PrepEntity( &gMetabolize, &player); - HUD_PrepEntity( &gStomp, &player); - HUD_PrepEntity( &gDevour, &player); - - HUD_PrepEntity( &gLeap, &player); - HUD_PrepEntity( &gCharge, &player); - - gJetpackEventID = PRECACHE_EVENT(1, kJetpackEvent); - //gWallJumpEventID = PRECACHE_EVENT(1, kWallJumpEvent); - //gFlightEventID = PRECACHE_EVENT(1, kFlightEvent); - gTeleportEventID = PRECACHE_EVENT(1, kTeleportEvent); - gPhaseInEventID = PRECACHE_EVENT(1, kPhaseInEvent); - gSiegeHitEventID = PRECACHE_EVENT(1, kSiegeHitEvent); - gSiegeViewHitEventID = PRECACHE_EVENT(1, kSiegeViewHitEvent); - gCommanderPointsAwardedEventID = PRECACHE_EVENT(1, kCommanderPointsAwardedEvent); - gBlinkEffectSuccessEventID = PRECACHE_EVENT(1, kBlinkEffectSuccessEventName); -} - -/* -===================== -HUD_GetLastOrg - -Retruns the last position that we stored for egon beam endpoint. -===================== -*/ -void HUD_GetLastOrg( float *org ) -{ - int i; - - // Return last origin - for ( i = 0; i < 3; i++ ) - { - org[i] = previousorigin[i]; - } -} - -/* -===================== -HUD_SetLastOrg - -Remember our exact predicted origin so we can draw the egon to the right position. -===================== -*/ -void HUD_SetLastOrg( void ) -{ - int i; - - // Offset final origin by view_offset - for ( i = 0; i < 3; i++ ) - { - previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; - } -} - - -CBasePlayerWeapon* HUD_GetWeaponForID(int inID) -{ - CBasePlayerWeapon* pWeapon = NULL; - - switch(inID) - { -// case WEAPON_GLOCK: -// pWeapon = &g_Glock; -// break; - case AVH_WEAPON_KNIFE: - pWeapon = &gKnife; - break; - case AVH_WEAPON_MG: - pWeapon = &gMachineGun; - break; - case AVH_WEAPON_PISTOL: - pWeapon = &gPistol; - break; - case AVH_WEAPON_SONIC: - pWeapon = &gSonicGun; - break; - case AVH_WEAPON_HMG: - pWeapon = &gHeavyMachineGun; - break; - case AVH_WEAPON_GRENADE_GUN: - pWeapon = &gGrenadeGun; - break; - case AVH_WEAPON_GRENADE: - pWeapon = &gGrenade; - break; - case AVH_WEAPON_WELDER: - pWeapon = &gWelder; - break; - case AVH_WEAPON_MINE: - pWeapon = &gMine; - break; - case AVH_WEAPON_SPIT: - pWeapon = &gSpitGun; - break; - case AVH_WEAPON_CLAWS: - pWeapon = &gClaws; - break; - case AVH_WEAPON_SPORES: - pWeapon = &gSpores; - break; - case AVH_WEAPON_SPIKE: - pWeapon = &gSpikeGun; - break; - case AVH_WEAPON_BITE: - pWeapon = &gBite; - break; - case AVH_WEAPON_BITE2: - pWeapon = &gBite2; - break; - case AVH_WEAPON_SWIPE: - pWeapon = &gSwipe; - break; - case AVH_WEAPON_WEBSPINNER: - pWeapon = &gWebSpinner; - break; - case AVH_WEAPON_PRIMALSCREAM: - pWeapon = &gPrimalScream; - break; - case AVH_WEAPON_PARASITE: - pWeapon = &gParasite; - break; - case AVH_WEAPON_UMBRA: - pWeapon = &gUmbra; - break; - case AVH_WEAPON_BLINK: - pWeapon = &gBlink; - break; - case AVH_WEAPON_DIVINEWIND: - pWeapon = &gDivineWind; - break; -// case AVH_WEAPON_PARALYSIS: -// pWeapon = &gParalysisGun; -// break; - case AVH_WEAPON_BILEBOMB: - pWeapon = &gBileBomb; - break; - case AVH_WEAPON_ACIDROCKET: - pWeapon = &gAcidRocket; - break; - case AVH_WEAPON_HEALINGSPRAY: - pWeapon = &gHealingSpray; - break; - case AVH_WEAPON_METABOLIZE: - pWeapon = &gMetabolize; - break; - case AVH_WEAPON_STOMP: - pWeapon = &gStomp; - break; - case AVH_WEAPON_DEVOUR: - pWeapon = &gDevour; - break; - - // Abilities - case AVH_ABILITY_LEAP: - pWeapon = &gLeap; - break; - case AVH_ABILITY_CHARGE: - pWeapon = &gCharge; - break; - } - - return pWeapon; -} - - -bool HUD_GetWeaponEnabled(int inID) -{ - ASSERT(inID >= 0); - ASSERT(inID < 32); - - // : 497 - use the enabled state in the associated WEAPON instead of the CBasePlayerWeapon's iuser3 - bool theWeaponEnabled = false; - CBasePlayerWeapon* theWeapon = g_pWpns[inID]; - if(theWeapon) - { - ItemInfo theItemInfo; - theWeapon->GetItemInfo(&theItemInfo); - WEAPON *pWeapon = gWR.GetWeapon( theItemInfo.iId ); - if ( pWeapon != 0 ) { - theWeaponEnabled = (pWeapon->iEnabled == 1); - } - } - - return theWeaponEnabled; -} - -/* -===================== -HUD_WeaponsPostThink - -Run Weapon firing code on client -===================== -*/ -void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) -{ - int i; - int buttonsChanged; - CBasePlayerWeapon* pCurrent = NULL; - weapon_data_t nulldata, *pfrom, *pto; - static int lasthealth; - - memset( &nulldata, 0, sizeof( nulldata ) ); - - HUD_InitClientWeapons(); - - // Get current clock - gpGlobals->time = time; - - // Fill in data based on selected weapon - // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? - // Store pointer to our destination entity_state_t so we can get our origin, etc. from it - CBasePlayerWeapon* pWeapon = HUD_GetWeaponForID(from->client.m_iId); - - // for setting up events on the client - g_finalstate = to; - - // If we are running events/etc. go ahead and see if we - // managed to die between last frame and this one - // If so, run the appropriate player killed or spawn function - if ( g_runfuncs ) - { - if ( to->client.health <= 0 && lasthealth > 0 ) - { - player.Killed( NULL, 0 ); - - } - else if ( to->client.health > 0 && lasthealth <= 0 ) - { - player.Spawn(); - } - - lasthealth = to->client.health; - } - - // We are not predicting the current weapon, just bow out here. - if ( !pWeapon ) - return; - - for ( i = 0; i < 32; i++ ) - { - pCurrent = g_pWpns[ i ]; - if ( !pCurrent ) - { - continue; - } - - pfrom = &from->weapondata[ i ]; - - pCurrent->m_fInReload = pfrom->m_fInReload; - pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; -// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; - pCurrent->m_iClip = pfrom->m_iClip; - pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; - pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; - pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; - if(pWeapon && (pWeapon->m_iId == pfrom->m_iId)) - { - // Predict clip - gHUD.m_Ammo.SetCurrentClip(pfrom->m_iClip); - - AvHBasePlayerWeapon* theWeapon = dynamic_cast(pWeapon); - if(theWeapon) - { - gHUD.SetCurrentWeaponData(pWeapon->m_iId, theWeapon->GetEnabledState()); - } - - //gHUD.SetClientDebugCSP(pfrom, from->client.m_flNextAttack); - } - - // Tell HUD what energy level is needed to use weapon, so alien HUD can indicate this - float theEnergyLevel = 0.0f; - AvHMUGetEnergyCost((AvHWeaponID)(pWeapon->m_iId), theEnergyLevel); - gHUD.SetCurrentUseableEnergyLevel(theEnergyLevel); - -// New SDK stuff...needed? -// pCurrent->pev->fuser1 = pfrom->fuser1; - pCurrent->m_flStartThrow = pfrom->fuser2; - pCurrent->m_flReleaseThrow = pfrom->fuser3; -// pCurrent->m_chargeReady = pfrom->iuser1; -// pCurrent->m_fInAttack = pfrom->iuser2; - pCurrent->pev->iuser3 = pfrom->iuser3; - -// pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[2]; - pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[0]; -// player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[1]; -// player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[2]; - } - - // For random weapon events, use this seed to seed random # generator - player.random_seed = random_seed; - - // Get old buttons from previous state. - player.m_afButtonLast = from->playerstate.oldbuttons; - - // Which buttsons chave changed - buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame - - // Debounced button codes for pressed/released - // The changed ones still down are "pressed" - player.m_afButtonPressed = buttonsChanged & cmd->buttons; - // The ones not down are "released" - player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); - - // Set player variables that weapons code might check/alter - player.pev->button = cmd->buttons; - - player.pev->velocity = from->client.velocity; - player.pev->flags = from->client.flags; - - player.pev->deadflag = from->client.deadflag; - player.pev->waterlevel = from->client.waterlevel; - player.pev->maxspeed = from->client.maxspeed; - player.pev->fov = from->client.fov; - player.pev->weaponanim = from->client.weaponanim; - player.pev->viewmodel = from->client.viewmodel; - player.m_flNextAttack = from->client.m_flNextAttack; - //player.m_flNextAmmoBurn = from->client.fuser2; - //player.m_flAmmoStartCharge = from->client.fuser3; - - // Removed this because NS uses vuser1 and vuser2 (and the HL weapons aren't used) - ////Stores all our ammo info, so the client side weapons can use them. - //player.ammo_9mm = (int)from->client.vuser1[0]; - //player.ammo_357 = (int)from->client.vuser1[1]; - //player.ammo_argrens = (int)from->client.vuser1[2]; - //player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... - //player.ammo_buckshot = (int)from->client.ammo_shells; - //player.ammo_uranium = (int)from->client.ammo_cells; - //player.ammo_hornets = (int)from->client.vuser2[0]; - //player.ammo_rockets = (int)from->client.ammo_rockets; - - - // Point to current weapon object - if ( from->client.m_iId ) - { - player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; - } - - if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) - { - ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; - ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; - } - - // Don't go firing anything if we have died. - // Or if we don't have a weapon model deployed - if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) - { - - if ( player.m_flNextAttack <= 0 ) - { - pWeapon->ItemPostFrame(); - } -// if ( g_runfuncs ) -// { -// pWeapon->PrintState(); -// } - } - - // Assume that we are not going to switch weapons - to->client.m_iId = from->client.m_iId; - - // Now see if we issued a changeweapon command ( and we're not dead ) - if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) - { - // Switched to a different weapon? - if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) - { - ASSERT(cmd->weaponselect >= 0); - ASSERT(cmd->weaponselect < 32); - - CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; - if ( pNew && ( pNew != pWeapon ) && player.m_pActiveItem && player.m_pActiveItem->CanHolster()) - { - // Put away old weapon - if (player.m_pActiveItem) - player.m_pActiveItem->Holster( ); - - player.m_pLastItem = player.m_pActiveItem; - player.m_pActiveItem = pNew; - - // Deploy new weapon - if (player.m_pActiveItem) - { - player.m_pActiveItem->Deploy( ); - } - - // Update weapon id so we can predict things correctly. - to->client.m_iId = cmd->weaponselect; - } - } - } - - // Copy in results of prediction code - to->client.viewmodel = player.pev->viewmodel; - to->client.fov = player.pev->fov; - to->client.weaponanim = player.pev->weaponanim; - to->client.m_flNextAttack = player.m_flNextAttack; - //to->client.fuser2 = player.m_flNextAmmoBurn; - //to->client.fuser3 = player.m_flAmmoStartCharge; - to->client.maxspeed = player.pev->maxspeed; - -// Removed this because NS uses vuser1 and vuser2 (and the HL weapons aren't used) -// //HL Weapons -// to->client.vuser1[0] = player.ammo_9mm; -// to->client.vuser1[1] = player.ammo_357; -// to->client.vuser1[2] = player.ammo_argrens; -// -// to->client.ammo_nails = player.ammo_bolts; -// to->client.ammo_shells = player.ammo_buckshot; -// to->client.ammo_cells = player.ammo_uranium; -// to->client.vuser2[0] = player.ammo_hornets; -// to->client.ammo_rockets = player.ammo_rockets; - - if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) - { - from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; - from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; - } - - // Make sure that weapon animation matches what the game .dll is telling us - // over the wire ( fixes some animation glitches ) - // Ensure that the fade and onos won't get these, to play the blink and charge animations correctly - bool noRun = (to->client.iuser3 == AVH_USER3_ALIEN_PLAYER4) || (to->client.iuser3 == AVH_USER3_ALIEN_PLAYER5); - if (g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) && !(CheckInAttack2()) && !noRun) - { - int body = 2; - - //Pop the model to body 0. - //if ( pWeapon == &g_Tripmine ) - // body = 0; - - // Force a fixed anim down to viewmodel - HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); - } - - for ( i = 0; i < 32; i++ ) - { - pCurrent = g_pWpns[ i ]; - - pto = &to->weapondata[ i ]; - - if ( !pCurrent ) - { - memset( pto, 0, sizeof( weapon_data_t ) ); - continue; - } - - pto->m_fInReload = pCurrent->m_fInReload; - pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; -// pto->m_flPumpTime = pCurrent->m_flPumpTime; - pto->m_iClip = pCurrent->m_iClip; - pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; - pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; - pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; -// pto->fuser1 = pCurrent->pev->fuser1; -// pto->fuser2 = pCurrent->m_flStartThrow; -// pto->fuser3 = pCurrent->m_flReleaseThrow; -// pto->iuser1 = pCurrent->m_chargeReady; -// pto->iuser2 = pCurrent->m_fInAttack; - pto->iuser3 = pCurrent->pev->iuser3; - - // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) - pto->m_flNextReload -= cmd->msec / 1000.0; - pto->m_fNextAimBonus -= cmd->msec / 1000.0; - pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; - pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; - pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; - pto->fuser1 -= cmd->msec / 1000.0; - - to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; - to->client.vuser4 = pCurrent->pev->vuser4; -// to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; -// to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; -// to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; - -/* if ( pto->m_flPumpTime != -9999 ) - { - pto->m_flPumpTime -= cmd->msec / 1000.0; - if ( pto->m_flPumpTime < -0.001 ) - pto->m_flPumpTime = -0.001; - }*/ - - if ( pto->m_fNextAimBonus < -1.0 ) - { - pto->m_fNextAimBonus = -1.0; - } - - if ( pto->m_flNextPrimaryAttack < -1.0 ) - { - pto->m_flNextPrimaryAttack = -1.0; - } - - if ( pto->m_flNextSecondaryAttack < -0.001 ) - { - pto->m_flNextSecondaryAttack = -0.001; - } - - if ( pto->m_flTimeWeaponIdle < -0.001 ) - { - pto->m_flTimeWeaponIdle = -0.001; - } - - if ( pto->m_flNextReload < -0.001 ) - { - pto->m_flNextReload = -0.001; - } - - if ( pto->fuser1 < -0.001 ) - { - pto->fuser1 = -0.001; - } - } - - // m_flNextAttack is now part of the weapons, but is part of the player instead - to->client.m_flNextAttack -= cmd->msec / 1000.0; - if ( to->client.m_flNextAttack < -0.001 ) - { - to->client.m_flNextAttack = -0.001; - } - - to->client.fuser2 -= cmd->msec / 1000.0; - if ( to->client.fuser2 < -0.001 ) - { - to->client.fuser2 = -0.001; - } - - to->client.fuser3 -= cmd->msec / 1000.0; - if ( to->client.fuser3 < -0.001 ) - { - to->client.fuser3 = -0.001; - } - - // Store off the last position from the predicted state. - HUD_SetLastOrg(); - - // Wipe it so we can't use it after this frame - g_finalstate = NULL; -} - - -/* -===================== -HUD_PostRunCmd - -Client calls this during prediction, after it has moved the player and updated any info changed into to-> -time is the current client clock based on prediction -cmd is the command that caused the movement, etc -runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should -be ignored -===================== -*/ -void CL_DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) -{ -// RecClPostRunCmd(from, to, cmd, runfuncs, time, random_seed); - - g_runfuncs = runfuncs; - - if ( cl_lw && cl_lw->value ) - { - HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); - } - else - { - to->client.fov = g_lastFOV; - } - - // Check to see whether too play local jetpack effects - if(runfuncs) - { - static int sLastTime = 0; - float theTimePassed = time - sLastTime; - - //CheckJetpack(); - - //UpdateJetpackLights(); - - sLastTime = time; - } - - // All games can use FOV state - g_lastFOV = to->client.fov; -} - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +* Modified by Charlie Cleveland: +* +* $Workfile: hl_weapons.cpp $ +* $Date: 2002/10/24 21:11:52 $ +* +* ------------------------------------------------------------------------------- +* $Log: hl_weapons.cpp,v $ +* Revision 1.31 2002/10/24 21:11:52 Flayra +* - Updated jetpack effect because it was really buggy this old way +* +* Revision 1.30 2002/10/16 02:12:10 Flayra +* - Valve anti-cheat integrated! +* +* Revision 1.29 2002/10/16 00:36:40 Flayra +* - Removed blink fail +* +* Revision 1.28 2002/08/31 18:01:59 Flayra +* - Work at VALVe +* +* Revision 1.27 2002/07/08 16:09:03 Flayra +* - Removed unneeded code here, so random numbers were generated properly on both client and server +* +* Revision 1.26 2002/07/01 20:56:31 Flayra +* - Added babbler gun +* +* Revision 1.25 2002/06/25 17:03:01 Flayra +* - Removed old weapons, added new weapons, fixed mines, iuser3 enables and disables weapons +* +* =============================================================================== +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "../demo.h" +#include "common/usercmd.h" +#include "common/event_flags.h" +#include "common/event_api.h" +#include "cl_dll/com_weapons.h" +#include "cl_dll/ammo.h" +#include "cl_dll/ammohistory.h" +#include "dlls/extdll.h" +#include "dlls/util.h" +#include "dlls/cbase.h" +#include "dlls/monsters.h" +#include "dlls/weapons.h" +#include "dlls/nodes.h" +#include "dlls/player.h" +#include "mod/AvHEvents.h" + +#include "common/usercmd.h" +#include "common/entity_state.h" +#include "common/demo_api.h" +#include "pm_shared/pm_defs.h" +#include "common/event_api.h" +#include "common/r_efx.h" + +#include "../hud_iface.h" +#include "../com_weapons.h" + +#include "mod/AvHMarineWeapons.h" +#include "mod/AvHSpecials.h" +#include "mod/AvHAlienWeapons.h" +#include "mod/AvHAlienAbilities.h" +#include "mod/AvHAlienWeaponConstants.h" +#include "mod/AvHAlienAbilityConstants.h" +#include "mod/AvHMovementUtil.h" + +#include "engine/APIProxy.h" +#include "../Exports.h" + +extern globalvars_t *gpGlobals; +extern bool gIsJetpacking; + +// Pool of client side entities/entvars_t +static entvars_t ev[ 32 ]; +static int num_ents = 0; + +// The entity we'll use to represent the local client +static CBasePlayer player; + +// Local version of game .dll global variables ( time, etc. ) +static globalvars_t Globals; + +static CBasePlayerWeapon *g_pWpns[ 32 ]; + +bool CheckInAttack2(void); + +vec3_t previousorigin; + +// HLDM Weapon placeholder entities. +//CGlock g_Glock; + +// NS weapons +AvHKnife gKnife; +AvHMachineGun gMachineGun; +AvHPistol gPistol; +AvHSonicGun gSonicGun; +AvHHeavyMachineGun gHeavyMachineGun; +AvHGrenadeGun gGrenadeGun; +AvHGrenade gGrenade; +AvHWelder gWelder; +AvHMine gMine; +AvHSpitGun gSpitGun; +AvHClaws gClaws; +AvHSpore gSpores; +AvHBite gBite; +AvHBite2 gBite2; +AvHSpikeGun gSpikeGun; +AvHSwipe gSwipe; +AvHWebSpinner gWebSpinner; +AvHPrimalScream gPrimalScream; +AvHParasiteGun gParasite; +AvHUmbraGun gUmbra; +AvHBlinkGun gBlink; +AvHDivineWind gDivineWind; +//AvHParalysisGun gParalysisGun; +AvHBileBombGun gBileBomb; +AvHAcidRocketGun gAcidRocket; +AvHHealingSpray gHealingSpray; +AvHMetabolize gMetabolize; +AvHDevour gDevour; +AvHStomp gStomp; + +// Alien abilities +AvHLeap gLeap; +AvHCharge gCharge; + +// Jetpack events +int gJetpackEventID; +//int gWallJumpEventID; +//int gFlightEventID; +int gTeleportEventID; +int gPhaseInEventID; +int gSiegeHitEventID; +int gSiegeViewHitEventID; +int gCommanderPointsAwardedEventID; +int gBlinkEffectSuccessEventID; + +//bool gPlayingJetpack = false; +//CGlock g_Glock; +//CCrowbar g_Crowbar; +//CPython g_Python; +//CMP5 g_Mp5; +//CCrossbow g_Crossbow; +//CShotgun g_Shotgun; +//CRpg g_Rpg; +//CGauss g_Gauss; +//CEgon g_Egon; +//CHgun g_HGun; +//CHandGrenade g_HandGren; +//CSatchel g_Satchel; +//CTripmine g_Tripmine; +//CSqueak g_Snark; + +/* +====================== +AlertMessage + +Print debug messages to console +====================== +*/ +void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, szFmt); +#ifdef WIN32 + //overflow protection in MS version of function... + _vsnprintf( string, 1023, szFmt, argptr ); +#else + vsprintf (string, szFmt,argptr); +#endif + va_end (argptr); + + gEngfuncs.Con_Printf( "cl: " ); + gEngfuncs.Con_Printf( string ); +} + +// Client-side effects for jetpack +void CheckJetpack() +{ + // if local player is jetpacking, play effects immediately +// if(gIsJetpacking && !gPlayingJetpack) +// { +// cl_entity_t* thePlayer; +// thePlayer = gEngfuncs.GetLocalPlayer(); +// ASSERT(thePlayer); +// +// // Play event locally, server will tell everyone else to play event +// gEngfuncs.pEventAPI->EV_PlaybackEvent(0, NULL, gJetpackEventID, 0, thePlayer->origin, (float *)&g_vecZero, 0.0, 0.0, /*theWeaponIndex*/ 0, 0, 0, 0 ); +// +// //gPlayingJetpack = true; +// } + // Check to turn it off too (in case there's a network anomaly or the game resets or something, just trying to be safe) + //else if(!gIsJetpacking && (gPlayingJetpack)) + //{ + // gEngfuncs.pEventAPI->EV_PlaybackEvent(0, NULL, gEndJetpackEventID, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, /*theWeaponIndex*/ 0, 0, 0, 0 ); + // + // gPlayingJetpack = false; + //} +} + +//Returns if it's multiplayer. +//Mostly used by the client side weapons. +bool bIsMultiplayer ( void ) +{ + return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; +} +//Just loads a v_ model. +void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) +{ + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); +} + +/* +===================== +HUD_PrepEntity + +Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then +we set up the m_pPlayer field. +===================== +*/ +void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) +{ + typedef vector IDListType; + static IDListType sIDList; + + memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); + pEntity->pev = &ev[ num_ents++ ]; + + pEntity->Precache(); + pEntity->Spawn(); + + if ( pWeaponOwner ) + { + ItemInfo info; + + ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; + + ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); + + // ASSERT that a weapon with this id isn't in the list + int theNewID = info.iId; + IDListType::iterator theIter = std::find(sIDList.begin(), sIDList.end(), theNewID); + ASSERT(theIter == sIDList.end()); + + // Insert id into our list + sIDList.push_back(theNewID); + + g_pWpns[ theNewID ] = (CBasePlayerWeapon *)pEntity; + } +} + +/* +===================== +CBaseEntity :: Killed + +If weapons code "kills" an entity, just set its effects to EF_NODRAW +===================== +*/ +void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->effects |= EF_NODRAW; +} + +/* +===================== +CBasePlayerWeapon :: DefaultReload +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) +{ + + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + return FALSE; + + int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + if (j == 0) + return FALSE; + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; + + //!!UNDONE -- reload sound goes here !!! + //SendWeaponAnim( iAnim, UseDecrement(), body ); + + m_fInReload = TRUE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kDeployIdleInterval; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: CanDeploy +===================== +*/ +BOOL CBasePlayerWeapon :: CanDeploy( void ) +{ + BOOL bHasAmmo = 0; + + if ( !pszAmmo1() ) + { + // this weapon doesn't use ammo, can always deploy. + return TRUE; + } + + if ( pszAmmo1() ) + { + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); + } + if ( pszAmmo2() ) + { + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); + } + if (m_iClip > 0) + { + bHasAmmo |= 1; + } + if (!bHasAmmo) + { + return FALSE; + } + + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: DefaultDeploy + +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) +{ + if ( !CanDeploy() ) + return FALSE; + + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); + + SendWeaponAnim( iAnim, skiplocal, body ); + + m_pPlayer->m_flNextAttack = this->GetDeployTime(); + m_flTimeWeaponIdle = this->GetDeployTime() + kDeployIdleInterval; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: PlayEmptySound + +===================== +*/ +BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +{ + if (m_iPlayEmptySound) + { + HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); + m_iPlayEmptySound = 0; + return 0; + } + return 0; +} + +/* +===================== +CBasePlayerWeapon :: ResetEmptySound + +===================== +*/ +void CBasePlayerWeapon :: ResetEmptySound( void ) +{ + m_iPlayEmptySound = 1; +} + +/* +===================== +CBasePlayerWeapon::Holster + +Put away weapon +===================== +*/ +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE; // cancel any reload in progress. + m_pPlayer->pev->viewmodel = 0; +} + +/* +===================== +CBasePlayerWeapon::SendWeaponAnim + +Animate weapon model +===================== +*/ +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) +{ + m_pPlayer->pev->weaponanim = iAnim; + + HUD_SendWeaponAnim( iAnim, body, 0 ); +} + +/* +===================== +CBaseEntity::FireBulletsPlayer + +Only produces random numbers to match the server ones. +===================== +*/ +Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) +{ + //float x, y, z; + Vector theShotDirection; + + theShotDirection.x = theShotDirection.y = theShotDirection.z = 0; + +// for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) +// { +// if ( pevAttacker == NULL ) +// { +// // get circular gaussian spread +// do { +// x = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5); +// y = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5); +// z = x*x+y*y; +// } while (z > 1); +// } +// else +// { +// //Use player's random seed. +// // get circular gaussian spread +// x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); +// y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); +// z = x * x + y * y; +// } +// +// UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting) +// } + +// return Vector ( (float)(x * vecSpread.x), (float)(y * vecSpread.y), 0.0f ); + return theShotDirection; +} + + +bool GetCanUseWeapon() +{ + // This mirrors the functionality of AvHPlayer::GetCanUseWeapon. + return !gHUD.GetIsInTopDownMode() && !gHUD.GetIsBeingDigested() && !gHUD.GetIsEnsnared() && !gHUD.GetIsStunned() && gEngfuncs.GetViewModel() != NULL; +} + +/* +===================== +CBasePlayerWeapon::ItemPostFrame + +Handles weapon firing, reloading, etc. +===================== +*/ +void CBasePlayerWeapon::ItemPostFrame( void ) +{ + // Hack initialization + if (this->m_flLastAnimationPlayed >= 3.0f * BALANCE_VAR(kLeapROF) + gpGlobals->time) + this->m_flLastAnimationPlayed = 0.0f; + + if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) + { +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// Put code in here to predict reloads (ie, have the ammo on screen update before we get a response) // +/////////////////////////////////////////////////////////////////////////////////////////////////////// +//#if 0 // FIXME, need ammo on client to make this work right +// // complete the reload. +// int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); +// +// // Add them to the clip +// m_iClip += j; +// m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; +//#else +// m_iClip += 10; +//#endif + m_fInReload = FALSE; + } + + // Properly propagate the end animation + if (this->PrevAttack2Status == true && !(m_pPlayer->pev->button & IN_ATTACK2)) + { + switch (gHUD.GetCurrentWeaponID()) + { + case AVH_WEAPON_SWIPE: + this->SendWeaponAnim(12); + break; + case AVH_WEAPON_ACIDROCKET: + this->SendWeaponAnim(8); + break; + case AVH_WEAPON_CLAWS: + this->SendWeaponAnim(9); + break; + case AVH_WEAPON_STOMP: + this->SendWeaponAnim(8); + break; + case AVH_WEAPON_DEVOUR: + this->SendWeaponAnim(11); + break; + } + } + + if ( (m_pPlayer->pev->button & IN_ATTACK) && !(m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextPrimaryAttack <= 0.0) ) + { + if (GetCanUseWeapon()) + { + if ( (m_iClip == 0 && pszAmmo1()) || + (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + { + m_fFireOnEmpty = TRUE; + } + + + if ((gHUD.GetHUDUser3() == AVH_USER3_ALIEN_PLAYER1) + && (gHUD.GetCurrentWeaponID() == AVH_ABILITY_LEAP) + && (this->m_flLastAnimationPlayed + (float)BALANCE_VAR(kLeapROF) <= gpGlobals->time)) + { + // : 0001151 predict energy too + AvHAlienWeapon* theWeapon = dynamic_cast(g_pWpns[AVH_ABILITY_LEAP]); + if ( theWeapon && theWeapon->IsUseable() ) { + float theVolumeScalar = 1.0f; + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); + int theSilenceLevel = AvHGetAlienUpgradeLevel(player->curstate.iuser4, MASK_UPGRADE_6); + switch(theSilenceLevel) + { + case 1: + theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel1Volume); + break; + case 2: + theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel2Volume); + break; + case 3: + theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel3Volume); + break; + } + HUD_PlaySound( kLeapSound, theVolumeScalar); + AvHMUDeductAlienEnergy(m_pPlayer->pev->fuser3, theWeapon->GetEnergyForAttack() ); + gEngfuncs.pEventAPI->EV_WeaponAnimation(3, 2); + this->m_flLastAnimationPlayed = gpGlobals->time; + } + } + //#ifdef AVH_CLIENT + //if((m_iClip == 0) && ? + //#endif + PrimaryAttack(); + //return; + } + } + // +movement: Rewritten to allow us to use +attack2 for movement abilities + else if ((m_pPlayer->pev->button & IN_ATTACK2) && (gHUD.GetIsAlien())) + { + //m_flNextSecondaryAttack + // Find out what kind of special movement we are using, and execute the animation for it + if (this->PrevAttack2Status == false) + { + bool enabled=false; + // : 0001151 predict energy too + AvHAlienWeapon *theWeapon = dynamic_cast(g_pWpns[AVH_ABILITY_LEAP]); + if ( theWeapon ) + enabled=theWeapon->IsUseable(); + + switch (gHUD.GetHUDUser3()) + { + case AVH_USER3_ALIEN_PLAYER1: + + if (enabled && (this->m_flLastAnimationPlayed + (float)BALANCE_VAR(kLeapROF) <= gpGlobals->time)) + { + float theVolumeScalar = 1.0f; + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); + int theSilenceLevel = AvHGetAlienUpgradeLevel(player->curstate.iuser4, MASK_UPGRADE_6); + switch(theSilenceLevel) + { + case 1: + theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel1Volume); + break; + case 2: + theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel2Volume); + break; + case 3: + theVolumeScalar = (float)BALANCE_VAR(kSilenceLevel3Volume); + break; + } + HUD_PlaySound( kLeapSound, theVolumeScalar); + AvHMUDeductAlienEnergy(m_pPlayer->pev->fuser3, theWeapon->GetEnergyForAttack() ); + this->SendWeaponAnim(3); + this->m_flLastAnimationPlayed = gpGlobals->time; + } + break; + case AVH_USER3_ALIEN_PLAYER4: + switch (gHUD.GetCurrentWeaponID()) + { + case AVH_WEAPON_SWIPE: + this->SendWeaponAnim(9); + break; + case AVH_WEAPON_ACIDROCKET: + this->SendWeaponAnim(11); + break; + } + break; + case AVH_USER3_ALIEN_PLAYER5: + switch (gHUD.GetCurrentWeaponID()) + { + case AVH_WEAPON_CLAWS: + this->SendWeaponAnim(5); + break; + case AVH_WEAPON_DEVOUR: + this->SendWeaponAnim(18); + break; + case AVH_WEAPON_STOMP: + this->SendWeaponAnim(15); + break; + } + break; + } + } + + if ((gHUD.GetHUDUser3() == AVH_USER3_ALIEN_PLAYER1) + && (this->m_flLastAnimationPlayed + BALANCE_VAR(kLeapROF) < gpGlobals->time)) + this->PrevAttack2Status = false; + else + this->PrevAttack2Status = true; + + return; +// if (GetCanUseWeapon()) +// { +// PrimaryAttack(); +// } + } + else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) + { + if (GetCanUseWeapon()) + { + // reload when reload is pressed, or if no buttons are down and weapon is empty. + Reload(); + } + } + // +movement: Removed case for +attack2 + else if ( !(m_pPlayer->pev->button & (IN_ATTACK /*|IN_ATTACK2 */) ) ) + { + if (GetCanUseWeapon()) + { + + // no fire buttons down + + m_fFireOnEmpty = FALSE; + + // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < 0.0 ) + { + // << CGC >> Only reload if we have more ammo to reload with + if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) + { + Reload(); + return; + } + } + + WeaponIdle( ); + } + this->PrevAttack2Status = false; + return; + } + + this->PrevAttack2Status = false; + + // catch all + if ( ShouldWeaponIdle() ) + { + WeaponIdle(); + } +} + +/* +===================== +CBasePlayer::SelectItem + + Switch weapons +===================== +*/ +void CBasePlayer::SelectItem(const char *pstr) +{ + if (!pstr) + return; + + CBasePlayerItem *pItem = NULL; + + if (!pItem) + return; + + + if (pItem == m_pActiveItem) + return; + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + m_pLastItem = m_pActiveItem; + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + } +} + +/* +===================== +CBasePlayer::SelectLastItem + +===================== +*/ +void CBasePlayer::SelectLastItem(void) +{ + if (!m_pLastItem) + { + return; + } + + if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + { + return; + } + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + CBasePlayerItem *pTemp = m_pActiveItem; + m_pActiveItem = m_pLastItem; + m_pLastItem = pTemp; + m_pActiveItem->Deploy( ); +} + +/* +===================== +CBasePlayer::Killed + +===================== +*/ +void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) +{ + // Holster weapon immediately, to allow it to cleanup + if ( m_pActiveItem ) + m_pActiveItem->Holster( ); +} + +/* +===================== +CBasePlayer::Spawn + +===================== +*/ +void CBasePlayer::Spawn( void ) +{ + if (m_pActiveItem) + m_pActiveItem->Deploy( ); + +// this->m_flLastAnimationPlayed = gpGlobals->time; +} + +/* +===================== +UTIL_TraceLine + +Don't actually trace, but act like the trace didn't hit anything. +===================== +*/ +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + memset( ptr, 0, sizeof( *ptr ) ); + ptr->flFraction = 1.0; +} + +/* +===================== +UTIL_ParticleBox + +For debugging, draw a box around a player made out of particles +===================== +*/ +void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + int i; + vec3_t mmin, mmax; + + for ( i = 0; i < 3; i++ ) + { + mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; + mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; + } + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); +} + +/* +===================== +UTIL_ParticleBoxes + +For debugging, draw boxes for other collidable players +===================== +*/ +void UTIL_ParticleBoxes( void ) +{ + int idx; + physent_t *pe; + cl_entity_t *player; + vec3_t mins, maxs; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + player = gEngfuncs.GetLocalPlayer(); + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); + + for ( idx = 1; idx < 100; idx++ ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); + if ( !pe ) + break; + + if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) + { + mins = pe->origin + pe->mins; + maxs = pe->origin + pe->maxs; + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +===================== +UTIL_ParticleLine + +For debugging, draw a line made out of particles +===================== +*/ +void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); +} + +/* +===================== +CBasePlayerWeapon::PrintState + +For debugging, print out state variables to log file +===================== +*/ +void CBasePlayerWeapon::PrintState( void ) +{ + COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); + COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); + COM_Log( "c:\\hl.log", "%i ", m_iClip ); + COM_Log( "c:\\hl.log", "\r\n"); +} + +/* +===================== +HUD_InitClientWeapons + +Set up weapons, player and functions needed to run weapons code client-side. +===================== +*/ +void HUD_InitClientWeapons( void ) +{ + static int initialized = 0; + if ( initialized ) + return; + + initialized = 1; + + // Set up pointer ( dummy object ) + gpGlobals = &Globals; + + // Fill in current time ( probably not needed ) + gpGlobals->time = gEngfuncs.GetClientTime(); + + // Fake functions + g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; + g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; + g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; + g_engfuncs.pfnNameForFunction = stub_NameForFunction; + g_engfuncs.pfnSetModel = stub_SetModel; + g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; + + // Handled locally + g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; + g_engfuncs.pfnAlertMessage = AlertMessage; + + // Pass through to engine + g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; + g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + + // Allocate a slot for the local player + HUD_PrepEntity( &player , NULL ); + + + // Allocate slot(s) for each weapon that we are going to be predicting + //HUD_PrepEntity( &g_Glock, &player ); + HUD_PrepEntity( &gKnife, &player); + HUD_PrepEntity( &gMachineGun, &player); + HUD_PrepEntity( &gPistol, &player); + HUD_PrepEntity( &gSonicGun, &player); + HUD_PrepEntity( &gHeavyMachineGun, &player); + HUD_PrepEntity( &gGrenadeGun, &player); + HUD_PrepEntity( &gGrenade, &player); + HUD_PrepEntity( &gWelder, &player); + HUD_PrepEntity( &gMine, &player); + HUD_PrepEntity( &gSpitGun, &player); + HUD_PrepEntity( &gClaws, &player); + HUD_PrepEntity( &gSpores, &player); + HUD_PrepEntity( &gSpikeGun, &player); + HUD_PrepEntity( &gBite, &player); + HUD_PrepEntity( &gBite2, &player); + HUD_PrepEntity( &gSwipe, &player); + HUD_PrepEntity( &gWebSpinner, &player); + HUD_PrepEntity( &gPrimalScream, &player); + //HUD_PrepEntity( &gParalysisGun, &player); + + HUD_PrepEntity( &gBlink, &player); + HUD_PrepEntity( &gParasite, &player); + HUD_PrepEntity( &gUmbra, &player); + HUD_PrepEntity( &gDivineWind, &player); + HUD_PrepEntity( &gBileBomb, &player); + HUD_PrepEntity( &gAcidRocket, &player); + HUD_PrepEntity( &gHealingSpray, &player); + HUD_PrepEntity( &gMetabolize, &player); + HUD_PrepEntity( &gStomp, &player); + HUD_PrepEntity( &gDevour, &player); + + HUD_PrepEntity( &gLeap, &player); + HUD_PrepEntity( &gCharge, &player); + + gJetpackEventID = PRECACHE_EVENT(1, kJetpackEvent); + //gWallJumpEventID = PRECACHE_EVENT(1, kWallJumpEvent); + //gFlightEventID = PRECACHE_EVENT(1, kFlightEvent); + gTeleportEventID = PRECACHE_EVENT(1, kTeleportEvent); + gPhaseInEventID = PRECACHE_EVENT(1, kPhaseInEvent); + gSiegeHitEventID = PRECACHE_EVENT(1, kSiegeHitEvent); + gSiegeViewHitEventID = PRECACHE_EVENT(1, kSiegeViewHitEvent); + gCommanderPointsAwardedEventID = PRECACHE_EVENT(1, kCommanderPointsAwardedEvent); + gBlinkEffectSuccessEventID = PRECACHE_EVENT(1, kBlinkEffectSuccessEventName); +} + +/* +===================== +HUD_GetLastOrg + +Retruns the last position that we stored for egon beam endpoint. +===================== +*/ +void HUD_GetLastOrg( float *org ) +{ + int i; + + // Return last origin + for ( i = 0; i < 3; i++ ) + { + org[i] = previousorigin[i]; + } +} + +/* +===================== +HUD_SetLastOrg + +Remember our exact predicted origin so we can draw the egon to the right position. +===================== +*/ +void HUD_SetLastOrg( void ) +{ + int i; + + // Offset final origin by view_offset + for ( i = 0; i < 3; i++ ) + { + previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; + } +} + + +CBasePlayerWeapon* HUD_GetWeaponForID(int inID) +{ + CBasePlayerWeapon* pWeapon = NULL; + + switch(inID) + { +// case WEAPON_GLOCK: +// pWeapon = &g_Glock; +// break; + case AVH_WEAPON_KNIFE: + pWeapon = &gKnife; + break; + case AVH_WEAPON_MG: + pWeapon = &gMachineGun; + break; + case AVH_WEAPON_PISTOL: + pWeapon = &gPistol; + break; + case AVH_WEAPON_SONIC: + pWeapon = &gSonicGun; + break; + case AVH_WEAPON_HMG: + pWeapon = &gHeavyMachineGun; + break; + case AVH_WEAPON_GRENADE_GUN: + pWeapon = &gGrenadeGun; + break; + case AVH_WEAPON_GRENADE: + pWeapon = &gGrenade; + break; + case AVH_WEAPON_WELDER: + pWeapon = &gWelder; + break; + case AVH_WEAPON_MINE: + pWeapon = &gMine; + break; + case AVH_WEAPON_SPIT: + pWeapon = &gSpitGun; + break; + case AVH_WEAPON_CLAWS: + pWeapon = &gClaws; + break; + case AVH_WEAPON_SPORES: + pWeapon = &gSpores; + break; + case AVH_WEAPON_SPIKE: + pWeapon = &gSpikeGun; + break; + case AVH_WEAPON_BITE: + pWeapon = &gBite; + break; + case AVH_WEAPON_BITE2: + pWeapon = &gBite2; + break; + case AVH_WEAPON_SWIPE: + pWeapon = &gSwipe; + break; + case AVH_WEAPON_WEBSPINNER: + pWeapon = &gWebSpinner; + break; + case AVH_WEAPON_PRIMALSCREAM: + pWeapon = &gPrimalScream; + break; + case AVH_WEAPON_PARASITE: + pWeapon = &gParasite; + break; + case AVH_WEAPON_UMBRA: + pWeapon = &gUmbra; + break; + case AVH_WEAPON_BLINK: + pWeapon = &gBlink; + break; + case AVH_WEAPON_DIVINEWIND: + pWeapon = &gDivineWind; + break; +// case AVH_WEAPON_PARALYSIS: +// pWeapon = &gParalysisGun; +// break; + case AVH_WEAPON_BILEBOMB: + pWeapon = &gBileBomb; + break; + case AVH_WEAPON_ACIDROCKET: + pWeapon = &gAcidRocket; + break; + case AVH_WEAPON_HEALINGSPRAY: + pWeapon = &gHealingSpray; + break; + case AVH_WEAPON_METABOLIZE: + pWeapon = &gMetabolize; + break; + case AVH_WEAPON_STOMP: + pWeapon = &gStomp; + break; + case AVH_WEAPON_DEVOUR: + pWeapon = &gDevour; + break; + + // Abilities + case AVH_ABILITY_LEAP: + pWeapon = &gLeap; + break; + case AVH_ABILITY_CHARGE: + pWeapon = &gCharge; + break; + } + + return pWeapon; +} + + +bool HUD_GetWeaponEnabled(int inID) +{ + ASSERT(inID >= 0); + ASSERT(inID < 32); + + // : 497 - use the enabled state in the associated WEAPON instead of the CBasePlayerWeapon's iuser3 + bool theWeaponEnabled = false; + CBasePlayerWeapon* theWeapon = g_pWpns[inID]; + if(theWeapon) + { + ItemInfo theItemInfo; + theWeapon->GetItemInfo(&theItemInfo); + WEAPON *pWeapon = gWR.GetWeapon( theItemInfo.iId ); + if ( pWeapon != 0 ) { + theWeaponEnabled = (pWeapon->iEnabled == 1); + } + } + + return theWeaponEnabled; +} + +/* +===================== +HUD_WeaponsPostThink + +Run Weapon firing code on client +===================== +*/ +void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) +{ + int i; + int buttonsChanged; + CBasePlayerWeapon* pCurrent = NULL; + weapon_data_t nulldata, *pfrom, *pto; + static int lasthealth; + + memset( &nulldata, 0, sizeof( nulldata ) ); + + HUD_InitClientWeapons(); + + // Get current clock + gpGlobals->time = time; + + // Fill in data based on selected weapon + // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? + // Store pointer to our destination entity_state_t so we can get our origin, etc. from it + CBasePlayerWeapon* pWeapon = HUD_GetWeaponForID(from->client.m_iId); + + // for setting up events on the client + g_finalstate = to; + + // If we are running events/etc. go ahead and see if we + // managed to die between last frame and this one + // If so, run the appropriate player killed or spawn function + if ( g_runfuncs ) + { + if ( to->client.health <= 0 && lasthealth > 0 ) + { + player.Killed( NULL, 0 ); + + } + else if ( to->client.health > 0 && lasthealth <= 0 ) + { + player.Spawn(); + } + + lasthealth = to->client.health; + } + + // We are not predicting the current weapon, just bow out here. + if ( !pWeapon ) + return; + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + if ( !pCurrent ) + { + continue; + } + + pfrom = &from->weapondata[ i ]; + + pCurrent->m_fInReload = pfrom->m_fInReload; + pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; +// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; + pCurrent->m_iClip = pfrom->m_iClip; + pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; + pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; + pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; + if(pWeapon && (pWeapon->m_iId == pfrom->m_iId)) + { + // Predict clip + gHUD.m_Ammo.SetCurrentClip(pfrom->m_iClip); + + AvHBasePlayerWeapon* theWeapon = dynamic_cast(pWeapon); + if(theWeapon) + { + gHUD.SetCurrentWeaponData(pWeapon->m_iId, theWeapon->GetEnabledState()); + } + + //gHUD.SetClientDebugCSP(pfrom, from->client.m_flNextAttack); + } + + // Tell HUD what energy level is needed to use weapon, so alien HUD can indicate this + float theEnergyLevel = 0.0f; + AvHMUGetEnergyCost((AvHWeaponID)(pWeapon->m_iId), theEnergyLevel); + gHUD.SetCurrentUseableEnergyLevel(theEnergyLevel); + +// New SDK stuff...needed? +// pCurrent->pev->fuser1 = pfrom->fuser1; + pCurrent->m_flStartThrow = pfrom->fuser2; + pCurrent->m_flReleaseThrow = pfrom->fuser3; +// pCurrent->m_chargeReady = pfrom->iuser1; +// pCurrent->m_fInAttack = pfrom->iuser2; + pCurrent->pev->iuser3 = pfrom->iuser3; + +// pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[2]; + pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[0]; +// player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[1]; +// player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[2]; + } + + // For random weapon events, use this seed to seed random # generator + player.random_seed = random_seed; + + // Get old buttons from previous state. + player.m_afButtonLast = from->playerstate.oldbuttons; + + // Which buttsons chave changed + buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame + + // Debounced button codes for pressed/released + // The changed ones still down are "pressed" + player.m_afButtonPressed = buttonsChanged & cmd->buttons; + // The ones not down are "released" + player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); + + // Set player variables that weapons code might check/alter + player.pev->button = cmd->buttons; + + player.pev->velocity = from->client.velocity; + player.pev->flags = from->client.flags; + + player.pev->deadflag = from->client.deadflag; + player.pev->waterlevel = from->client.waterlevel; + player.pev->maxspeed = from->client.maxspeed; + player.pev->fov = from->client.fov; + player.pev->weaponanim = from->client.weaponanim; + player.pev->viewmodel = from->client.viewmodel; + player.m_flNextAttack = from->client.m_flNextAttack; + //player.m_flNextAmmoBurn = from->client.fuser2; + //player.m_flAmmoStartCharge = from->client.fuser3; + + // Removed this because NS uses vuser1 and vuser2 (and the HL weapons aren't used) + ////Stores all our ammo info, so the client side weapons can use them. + //player.ammo_9mm = (int)from->client.vuser1[0]; + //player.ammo_357 = (int)from->client.vuser1[1]; + //player.ammo_argrens = (int)from->client.vuser1[2]; + //player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... + //player.ammo_buckshot = (int)from->client.ammo_shells; + //player.ammo_uranium = (int)from->client.ammo_cells; + //player.ammo_hornets = (int)from->client.vuser2[0]; + //player.ammo_rockets = (int)from->client.ammo_rockets; + + + // Point to current weapon object + if ( from->client.m_iId ) + { + player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; + } + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; + ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; + } + + // Don't go firing anything if we have died. + // Or if we don't have a weapon model deployed + if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) + { + + if ( player.m_flNextAttack <= 0 ) + { + pWeapon->ItemPostFrame(); + } +// if ( g_runfuncs ) +// { +// pWeapon->PrintState(); +// } + } + + // Assume that we are not going to switch weapons + to->client.m_iId = from->client.m_iId; + + // Now see if we issued a changeweapon command ( and we're not dead ) + if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) + { + // Switched to a different weapon? + if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) + { + ASSERT(cmd->weaponselect >= 0); + ASSERT(cmd->weaponselect < 32); + + CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; + if ( pNew && ( pNew != pWeapon ) && player.m_pActiveItem && player.m_pActiveItem->CanHolster()) + { + // Put away old weapon + if (player.m_pActiveItem) + player.m_pActiveItem->Holster( ); + + player.m_pLastItem = player.m_pActiveItem; + player.m_pActiveItem = pNew; + + // Deploy new weapon + if (player.m_pActiveItem) + { + player.m_pActiveItem->Deploy( ); + } + + // Update weapon id so we can predict things correctly. + to->client.m_iId = cmd->weaponselect; + } + } + } + + // Copy in results of prediction code + to->client.viewmodel = player.pev->viewmodel; + to->client.fov = player.pev->fov; + to->client.weaponanim = player.pev->weaponanim; + to->client.m_flNextAttack = player.m_flNextAttack; + //to->client.fuser2 = player.m_flNextAmmoBurn; + //to->client.fuser3 = player.m_flAmmoStartCharge; + to->client.maxspeed = player.pev->maxspeed; + +// Removed this because NS uses vuser1 and vuser2 (and the HL weapons aren't used) +// //HL Weapons +// to->client.vuser1[0] = player.ammo_9mm; +// to->client.vuser1[1] = player.ammo_357; +// to->client.vuser1[2] = player.ammo_argrens; +// +// to->client.ammo_nails = player.ammo_bolts; +// to->client.ammo_shells = player.ammo_buckshot; +// to->client.ammo_cells = player.ammo_uranium; +// to->client.vuser2[0] = player.ammo_hornets; +// to->client.ammo_rockets = player.ammo_rockets; + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; + from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; + } + + // Make sure that weapon animation matches what the game .dll is telling us + // over the wire ( fixes some animation glitches ) + // Ensure that the fade and onos won't get these, to play the blink and charge animations correctly + bool noRun = (to->client.iuser3 == AVH_USER3_ALIEN_PLAYER4) || (to->client.iuser3 == AVH_USER3_ALIEN_PLAYER5); + if (g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) && !(CheckInAttack2()) && !noRun) + { + int body = 2; + + //Pop the model to body 0. + //if ( pWeapon == &g_Tripmine ) + // body = 0; + + // Force a fixed anim down to viewmodel + HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); + } + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + + pto = &to->weapondata[ i ]; + + if ( !pCurrent ) + { + memset( pto, 0, sizeof( weapon_data_t ) ); + continue; + } + + pto->m_fInReload = pCurrent->m_fInReload; + pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; +// pto->m_flPumpTime = pCurrent->m_flPumpTime; + pto->m_iClip = pCurrent->m_iClip; + pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; + pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; + pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; +// pto->fuser1 = pCurrent->pev->fuser1; +// pto->fuser2 = pCurrent->m_flStartThrow; +// pto->fuser3 = pCurrent->m_flReleaseThrow; +// pto->iuser1 = pCurrent->m_chargeReady; +// pto->iuser2 = pCurrent->m_fInAttack; + pto->iuser3 = pCurrent->pev->iuser3; + + // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) + pto->m_flNextReload -= cmd->msec / 1000.0; + pto->m_fNextAimBonus -= cmd->msec / 1000.0; + pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; + pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; + pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; + pto->fuser1 -= cmd->msec / 1000.0; + + to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; + to->client.vuser4 = pCurrent->pev->vuser4; +// to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; +// to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; +// to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; + +/* if ( pto->m_flPumpTime != -9999 ) + { + pto->m_flPumpTime -= cmd->msec / 1000.0; + if ( pto->m_flPumpTime < -0.001 ) + pto->m_flPumpTime = -0.001; + }*/ + + if ( pto->m_fNextAimBonus < -1.0 ) + { + pto->m_fNextAimBonus = -1.0; + } + + if ( pto->m_flNextPrimaryAttack < -1.0 ) + { + pto->m_flNextPrimaryAttack = -1.0; + } + + if ( pto->m_flNextSecondaryAttack < -0.001 ) + { + pto->m_flNextSecondaryAttack = -0.001; + } + + if ( pto->m_flTimeWeaponIdle < -0.001 ) + { + pto->m_flTimeWeaponIdle = -0.001; + } + + if ( pto->m_flNextReload < -0.001 ) + { + pto->m_flNextReload = -0.001; + } + + if ( pto->fuser1 < -0.001 ) + { + pto->fuser1 = -0.001; + } + } + + // m_flNextAttack is now part of the weapons, but is part of the player instead + to->client.m_flNextAttack -= cmd->msec / 1000.0; + if ( to->client.m_flNextAttack < -0.001 ) + { + to->client.m_flNextAttack = -0.001; + } + + to->client.fuser2 -= cmd->msec / 1000.0; + if ( to->client.fuser2 < -0.001 ) + { + to->client.fuser2 = -0.001; + } + + to->client.fuser3 -= cmd->msec / 1000.0; + if ( to->client.fuser3 < -0.001 ) + { + to->client.fuser3 = -0.001; + } + + // Store off the last position from the predicted state. + HUD_SetLastOrg(); + + // Wipe it so we can't use it after this frame + g_finalstate = NULL; +} + + +/* +===================== +HUD_PostRunCmd + +Client calls this during prediction, after it has moved the player and updated any info changed into to-> +time is the current client clock based on prediction +cmd is the command that caused the movement, etc +runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should +be ignored +===================== +*/ +void CL_DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) +{ +// RecClPostRunCmd(from, to, cmd, runfuncs, time, random_seed); + + g_runfuncs = runfuncs; + + if ( cl_lw && cl_lw->value ) + { + HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); + } + else + { + to->client.fov = g_lastFOV; + } + + // Check to see whether too play local jetpack effects + if(runfuncs) + { + static int sLastTime = 0; + float theTimePassed = time - sLastTime; + + //CheckJetpack(); + + //UpdateJetpackLights(); + + sLastTime = time; + } + + // All games can use FOV state + g_lastFOV = to->client.fov; +} + + + diff --git a/main/source/cl_dll/hud.cpp b/main/source/cl_dll/hud.cpp index 39e527e8..8a71d72f 100644 --- a/main/source/cl_dll/hud.cpp +++ b/main/source/cl_dll/hud.cpp @@ -1,588 +1,588 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// hud.cpp -// -// implementation of CHud class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "hud_servers.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_int.h" - -#include "demo.h" -#include "common/demo_api.h" -#include "ui/UIComponent.h" -#include "vgui_ScorePanel.h" - -#include "mod/AvHNetworkMessages.h" -#include "ui/ChatPanel.h" -#include "mod/AvHClientVariables.h" -// : duck toggle -bool g_bDuckToggled; -// : - -class CHLVoiceStatusHelper : public IVoiceStatusHelper -{ -public: - virtual void GetPlayerTextColor(int entindex, int color[3]) - { - color[0] = color[1] = color[2] = 255; - - if( entindex >= 0 && entindex < sizeof(g_PlayerExtraInfo)/sizeof(g_PlayerExtraInfo[0]) ) - { - int iTeam = g_PlayerExtraInfo[entindex].teamnumber; - - if ( iTeam < 0 ) - { - iTeam = 0; - } - - iTeam = iTeam % iNumberOfTeamColors; - - color[0] = kTeamColors[iTeam][0]; - color[1] = kTeamColors[iTeam][1]; - color[2] = kTeamColors[iTeam][2]; - - // Draw commander voice differently - short thePlayerClass = g_PlayerExtraInfo[entindex].playerclass; - switch(thePlayerClass) - { - case PLAYERCLASS_COMMANDER: - color[0] = color[1] = color[2] = 255; - break; - } - } - } - - virtual void UpdateCursorState() - { - gViewPort->UpdateCursorState(); - } - - virtual int GetAckIconHeight() - { - return ScreenHeight() - gHUD.m_iFontHeight*3 - 6; - } - - virtual bool CanShowSpeakerLabels() - { - if( gViewPort && gViewPort->m_pScoreBoard ) - return !gViewPort->m_pScoreBoard->isVisible(); - else - return false; - } -}; -static CHLVoiceStatusHelper g_VoiceStatusHelper; - - -extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); -//CImageLabel* gTestLabel = NULL; -//extern Label* gTestLabel; - -extern cvar_t *sensitivity; -cvar_t *cl_lw = NULL; - -void ShutdownInput (void); - -int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) -{ - return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); -} - -int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) -{ - gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); - return 0; -} - -int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) -{ - gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); - return 1; -} - -int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) -{ - return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); -} - -int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) -{ - if (gViewPort) - return gViewPort->MsgFunc_TeamNames( pszName, iSize, pbuf ); - return 0; -} - -int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf) -{ - if (gViewPort) - return gViewPort->MsgFunc_MOTD( pszName, iSize, pbuf ); - return 0; -} - -int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) -{ - if (gViewPort) - return gViewPort->MsgFunc_ServerName( pszName, iSize, pbuf ); - return 0; -} - -int __MsgFunc_ScoreInfo(const char *pszName, int iSize, void *pbuf) -{ - if (gViewPort) - return gViewPort->MsgFunc_ScoreInfo( pszName, iSize, pbuf ); - return 0; -} - -int __MsgFunc_TeamScore(const char *pszName, int iSize, void *pbuf) -{ - if (gViewPort) - return gViewPort->MsgFunc_TeamScore( pszName, iSize, pbuf ); - return 0; -} - -int __MsgFunc_TeamInfo(const char *pszName, int iSize, void *pbuf) -{ - if (gViewPort) - return gViewPort->MsgFunc_TeamInfo( pszName, iSize, pbuf ); - return 0; -} - -void __CmdFunc_SpecialDummy(void) {} - -void __CmdFunc_ClRateDummy(void) { } - -// This is called every time the DLL is loaded -void CHud :: Init( void ) -{ - HOOK_MESSAGE( ResetHUD ); - HOOK_MESSAGE( InitHUD ); - HOOK_MESSAGE( ViewMode ); - HOOK_MESSAGE( SetFOV ); - - HOOK_COMMAND( "special", SpecialDummy); - HOOK_COMMAND( "_special", SpecialDummy); //prevent abuse - - HOOK_COMMAND( "cl_rate", ClRateDummy); - - HOOK_MESSAGE( TeamNames ); - HOOK_MESSAGE( MOTD ); - HOOK_MESSAGE( ServerName ); - HOOK_MESSAGE( ScoreInfo ); - HOOK_MESSAGE( TeamScore ); - HOOK_MESSAGE( TeamInfo ); - - CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch - CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round - -#ifdef DEBUG - CVAR_CREATE( "hud_hideview", "0", FCVAR_ARCHIVE ); -#endif - - m_iLogo = 0; - m_iFOV = 0; - - // : duck toggle - g_bDuckToggled = false; - // : - - CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); - default_fov = CVAR_CREATE( "default_fov", "90", 0 ); - m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); - m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); - cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); - - CVAR_CREATE( "cl_showspeed", "0", 0); - CVAR_CREATE( kvLabelMaps, "1", FCVAR_ARCHIVE); - CVAR_CREATE( kvGammaRamp, "1", FCVAR_ARCHIVE); - CVAR_CREATE( kvCustomCrosshair, "1", FCVAR_ARCHIVE); - CVAR_CREATE( kvHudMapZoom, "3", FCVAR_ARCHIVE); - CVAR_CREATE( kvLabelHivesight, "1", FCVAR_ARCHIVE); - CVAR_CREATE( "cl_iconr", "0", FCVAR_ARCHIVE); - CVAR_CREATE( "cl_icong", "149", FCVAR_ARCHIVE); - CVAR_CREATE( "cl_iconb", "221", FCVAR_ARCHIVE); - - m_pSpriteList = NULL; - - // Clear any old HUD list - if ( m_pHudList ) - { - HUDLIST *pList; - while ( m_pHudList ) - { - pList = m_pHudList; - m_pHudList = m_pHudList->pNext; - free( pList ); - } - m_pHudList = NULL; - } - - // In case we get messages before the first update -- time will be valid - m_flTime = 1.0; - - m_Ammo.Init(); - m_Health.Init(); - m_Spectator.Init(); - m_SayText.Init(); - m_Geiger.Init(); - m_Train.Init(); - m_Battery.Init(); - m_Flash.Init(); - m_Message.Init(); - m_StatusBar.Init(); - m_DeathNotice.Init(); - m_AmmoSecondary.Init(); - m_TextMessage.Init(); - m_StatusIcons.Init(); - - m_Spectator.m_chatEnabled = (m_SayText.m_HUD_saytext->value!=0); - - GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui::Panel**)&gViewPort); - - m_Menu.Init(); - - ServersInit(); - - MsgFunc_ResetHUD(0, 0, NULL ); -} - -// CHud destructor -// cleans up memory allocated for m_rg* arrays -CHud :: ~CHud() -{ - delete [] m_rghSprites; - delete [] m_rgrcRects; - delete [] m_rgszSpriteNames; - - if ( m_pHudList ) - { - HUDLIST *pList; - while ( m_pHudList ) - { - pList = m_pHudList; - m_pHudList = m_pHudList->pNext; - free( pList ); - } - m_pHudList = NULL; - } - - ServersShutdown(); -} - -// GetSpriteIndex() -// searches through the sprite list loaded from hud.txt for a name matching SpriteName -// returns an index into the gHUD.m_rghSprites[] array -// returns 0 if sprite not found -int CHud :: GetSpriteIndex( const char *SpriteName ) -{ - // look through the loaded sprite name list for SpriteName - for ( int i = 0; i < m_iSpriteCount; i++ ) - { - if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) - return i; - } - - return -1; // invalid sprite -} - -void CHud :: VidInit( void ) -{ - m_scrinfo.iSize = sizeof(m_scrinfo); - GetScreenInfo(&m_scrinfo); - - // The NS viewport isn't set up yet - int theViewPort[4]; - theViewPort[0] = theViewPort[1] = 0; - theViewPort[2] = this->m_scrinfo.iWidth; - theViewPort[3] = this->m_scrinfo.iHeight; - - gHUD.SetViewport(theViewPort); - - mFont.Load("sprites/font_arial"); - mSmallFont.Load("sprites/font_arialsmall"); - - // ---------- - // Load Sprites - // --------- -// m_hsprFont = LoadSprite("sprites/%d_font.spr"); - - m_hsprLogo = 0; - m_hsprCursor = 0; - - if (ScreenWidth() < 640) - m_iRes = 320; - else - m_iRes = 640; - - // Only load this once - if ( !m_pSpriteList ) - { - // we need to load the hud.txt, and all sprites within - m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); - - if (m_pSpriteList) - { - // count the number of sprites of the appropriate res - m_iSpriteCount = 0; - client_sprite_t *p = m_pSpriteList; - int j; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - m_iSpriteCount++; - p++; - } - - // allocated memory for sprite handle arrays - m_rghSprites = new HSPRITE[m_iSpriteCount]; - m_rgrcRects = new wrect_t[m_iSpriteCount]; - m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; - - p = m_pSpriteList; - int index = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - { - char sz[256]; - sprintf(sz, "sprites/%s.spr", p->szSprite); - m_rghSprites[index] = SPR_Load(sz); - m_rgrcRects[index] = p->rc; - strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); - - index++; - } - - p++; - } - } - } - else - { - // we have already have loaded the sprite reference from hud.txt, but - // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) - client_sprite_t *p = m_pSpriteList; - int index = 0; - for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - { - char sz[256]; - sprintf( sz, "sprites/%s.spr", p->szSprite ); - m_rghSprites[index] = SPR_Load(sz); - index++; - } - - p++; - } - } - - // assumption: number_1, number_2, etc, are all listed and loaded sequentially - m_HUD_number_0 = GetSpriteIndex( "number_0" ); - - m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; - - m_Ammo.VidInit(); - m_Health.VidInit(); - m_Spectator.VidInit(); - m_Geiger.VidInit(); - m_Train.VidInit(); - m_Battery.VidInit(); - m_Flash.VidInit(); - m_Message.VidInit(); - m_StatusBar.VidInit(); - m_DeathNotice.VidInit(); - m_SayText.VidInit(); - m_Menu.VidInit(); - m_AmmoSecondary.VidInit(); - m_TextMessage.VidInit(); - m_StatusIcons.VidInit(); - GetClientVoiceMgr()->VidInit(); -} - -float g_lastFOV = 0.0; - -/* -============ -COM_FileBase -============ -*/ -// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) -void COM_FileBase ( const char *in, char *out) -{ - int len, start, end; - - len = (int)strlen( in ); - - // scan backward for '.' - end = len - 1; - while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) - end--; - - if ( in[end] != '.' ) // no '.', copy to end - end = len-1; - else - end--; // Found ',', copy to left of '.' - - - // Scan backward for '/' - start = len-1; - while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) - start--; - - if ( in[start] != '/' && in[start] != '\\' ) - start = 0; - else - start++; - - // Length of new sting - len = end - start + 1; - - // Copy partial string - strncpy( out, &in[start], len ); - // Terminate it - out[len] = 0; -} - -/* -================= -HUD_IsGame - -================= -*/ -int HUD_IsGame( const char *game ) -{ - const char *gamedir; - char gd[ 1024 ]; - - gamedir = gEngfuncs.pfnGetGameDirectory(); - if ( gamedir && gamedir[0] ) - { - COM_FileBase( gamedir, gd ); - if ( !stricmp( gd, game ) ) - return 1; - } - return 0; -} - -/* -===================== -HUD_GetFOV - -Returns last FOV -===================== -*/ -float HUD_GetFOV( void ) -{ - if ( gEngfuncs.pDemoAPI->IsRecording() ) - { - // Write it - int i = 0; - unsigned char buf[ 100 ]; - - // Active - *( float * )&buf[ i ] = g_lastFOV; - i += sizeof( float ); - - Demo_WriteBuffer( TYPE_ZOOM, i, buf ); - } - - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) - { - g_lastFOV = g_demozoom; - } - return g_lastFOV; -} - -int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) -{ - int newfov; - NetMsg_SetFOV( pbuf, iSize, newfov ); - int def_fov = CVAR_GET_FLOAT( "default_fov" ); - - //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). - if ( cl_lw && cl_lw->value ) - return 1; - - g_lastFOV = newfov; - - if ( newfov == 0 ) - { - m_iFOV = def_fov; - } - else - { - m_iFOV = newfov; - } - - // the clients fov is actually set in the client data update section of the hud - - // Set a new sensitivity - if ( m_iFOV == def_fov ) - { - // reset to saved sensitivity - m_flMouseSensitivity = 0; - } - else - { - // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); - } - - return 1; -} - - -void CHud::AddHudElem(CHudBase *phudelem) -{ - HUDLIST *pdl, *ptemp; - -//phudelem->Think(); - - if (!phudelem) - return; - - pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); - if (!pdl) - return; - - memset(pdl, 0, sizeof(HUDLIST)); - pdl->p = phudelem; - - if (!m_pHudList) - { - m_pHudList = pdl; - return; - } - - ptemp = m_pHudList; - - while (ptemp->pNext) - ptemp = ptemp->pNext; - - ptemp->pNext = pdl; -} - -float CHud::GetSensitivity( void ) -{ - return m_flMouseSensitivity; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud.cpp +// +// implementation of CHud class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "hud_servers.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_int.h" + +#include "demo.h" +#include "common/demo_api.h" +#include "ui/UIComponent.h" +#include "vgui_ScorePanel.h" + +#include "mod/AvHNetworkMessages.h" +#include "ui/ChatPanel.h" +#include "mod/AvHClientVariables.h" +// : duck toggle +bool g_bDuckToggled; +// : + +class CHLVoiceStatusHelper : public IVoiceStatusHelper +{ +public: + virtual void GetPlayerTextColor(int entindex, int color[3]) + { + color[0] = color[1] = color[2] = 255; + + if( entindex >= 0 && entindex < sizeof(g_PlayerExtraInfo)/sizeof(g_PlayerExtraInfo[0]) ) + { + int iTeam = g_PlayerExtraInfo[entindex].teamnumber; + + if ( iTeam < 0 ) + { + iTeam = 0; + } + + iTeam = iTeam % iNumberOfTeamColors; + + color[0] = kTeamColors[iTeam][0]; + color[1] = kTeamColors[iTeam][1]; + color[2] = kTeamColors[iTeam][2]; + + // Draw commander voice differently + short thePlayerClass = g_PlayerExtraInfo[entindex].playerclass; + switch(thePlayerClass) + { + case PLAYERCLASS_COMMANDER: + color[0] = color[1] = color[2] = 255; + break; + } + } + } + + virtual void UpdateCursorState() + { + gViewPort->UpdateCursorState(); + } + + virtual int GetAckIconHeight() + { + return ScreenHeight() - gHUD.m_iFontHeight*3 - 6; + } + + virtual bool CanShowSpeakerLabels() + { + if( gViewPort && gViewPort->m_pScoreBoard ) + return !gViewPort->m_pScoreBoard->isVisible(); + else + return false; + } +}; +static CHLVoiceStatusHelper g_VoiceStatusHelper; + + +extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); +//CImageLabel* gTestLabel = NULL; +//extern Label* gTestLabel; + +extern cvar_t *sensitivity; +cvar_t *cl_lw = NULL; + +void ShutdownInput (void); + +int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); +} + +int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); +} + +int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamNames( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_MOTD( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ServerName( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ScoreInfo(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ScoreInfo( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamScore(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamScore( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamInfo(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamInfo( pszName, iSize, pbuf ); + return 0; +} + +void __CmdFunc_SpecialDummy(void) {} + +void __CmdFunc_ClRateDummy(void) { } + +// This is called every time the DLL is loaded +void CHud :: Init( void ) +{ + HOOK_MESSAGE( ResetHUD ); + HOOK_MESSAGE( InitHUD ); + HOOK_MESSAGE( ViewMode ); + HOOK_MESSAGE( SetFOV ); + + HOOK_COMMAND( "special", SpecialDummy); + HOOK_COMMAND( "_special", SpecialDummy); //prevent abuse + + HOOK_COMMAND( "cl_rate", ClRateDummy); + + HOOK_MESSAGE( TeamNames ); + HOOK_MESSAGE( MOTD ); + HOOK_MESSAGE( ServerName ); + HOOK_MESSAGE( ScoreInfo ); + HOOK_MESSAGE( TeamScore ); + HOOK_MESSAGE( TeamInfo ); + + CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch + CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round + +#ifdef DEBUG + CVAR_CREATE( "hud_hideview", "0", FCVAR_ARCHIVE ); +#endif + + m_iLogo = 0; + m_iFOV = 0; + + // : duck toggle + g_bDuckToggled = false; + // : + + CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); + default_fov = CVAR_CREATE( "default_fov", "90", 0 ); + m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); + m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); + cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); + + CVAR_CREATE( "cl_showspeed", "0", 0); + CVAR_CREATE( kvLabelMaps, "1", FCVAR_ARCHIVE); + CVAR_CREATE( kvGammaRamp, "1", FCVAR_ARCHIVE); + CVAR_CREATE( kvCustomCrosshair, "1", FCVAR_ARCHIVE); + CVAR_CREATE( kvHudMapZoom, "3", FCVAR_ARCHIVE); + CVAR_CREATE( kvLabelHivesight, "1", FCVAR_ARCHIVE); + CVAR_CREATE( "cl_iconr", "0", FCVAR_ARCHIVE); + CVAR_CREATE( "cl_icong", "149", FCVAR_ARCHIVE); + CVAR_CREATE( "cl_iconb", "221", FCVAR_ARCHIVE); + + m_pSpriteList = NULL; + + // Clear any old HUD list + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + // In case we get messages before the first update -- time will be valid + m_flTime = 1.0; + + m_Ammo.Init(); + m_Health.Init(); + m_Spectator.Init(); + m_SayText.Init(); + m_Geiger.Init(); + m_Train.Init(); + m_Battery.Init(); + m_Flash.Init(); + m_Message.Init(); + m_StatusBar.Init(); + m_DeathNotice.Init(); + m_AmmoSecondary.Init(); + m_TextMessage.Init(); + m_StatusIcons.Init(); + + m_Spectator.m_chatEnabled = (m_SayText.m_HUD_saytext->value!=0); + + GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui::Panel**)&gViewPort); + + m_Menu.Init(); + + ServersInit(); + + MsgFunc_ResetHUD(0, 0, NULL ); +} + +// CHud destructor +// cleans up memory allocated for m_rg* arrays +CHud :: ~CHud() +{ + delete [] m_rghSprites; + delete [] m_rgrcRects; + delete [] m_rgszSpriteNames; + + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + ServersShutdown(); +} + +// GetSpriteIndex() +// searches through the sprite list loaded from hud.txt for a name matching SpriteName +// returns an index into the gHUD.m_rghSprites[] array +// returns 0 if sprite not found +int CHud :: GetSpriteIndex( const char *SpriteName ) +{ + // look through the loaded sprite name list for SpriteName + for ( int i = 0; i < m_iSpriteCount; i++ ) + { + if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) + return i; + } + + return -1; // invalid sprite +} + +void CHud :: VidInit( void ) +{ + m_scrinfo.iSize = sizeof(m_scrinfo); + GetScreenInfo(&m_scrinfo); + + // The NS viewport isn't set up yet + int theViewPort[4]; + theViewPort[0] = theViewPort[1] = 0; + theViewPort[2] = this->m_scrinfo.iWidth; + theViewPort[3] = this->m_scrinfo.iHeight; + + gHUD.SetViewport(theViewPort); + + mFont.Load("sprites/font_arial"); + mSmallFont.Load("sprites/font_arialsmall"); + + // ---------- + // Load Sprites + // --------- +// m_hsprFont = LoadSprite("sprites/%d_font.spr"); + + m_hsprLogo = 0; + m_hsprCursor = 0; + + if (ScreenWidth() < 640) + m_iRes = 320; + else + m_iRes = 640; + + // Only load this once + if ( !m_pSpriteList ) + { + // we need to load the hud.txt, and all sprites within + m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); + + if (m_pSpriteList) + { + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + client_sprite_t *p = m_pSpriteList; + int j; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + + // allocated memory for sprite handle arrays + m_rghSprites = new HSPRITE[m_iSpriteCount]; + m_rgrcRects = new wrect_t[m_iSpriteCount]; + m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; + + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf(sz, "sprites/%s.spr", p->szSprite); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } + + p++; + } + } + } + else + { + // we have already have loaded the sprite reference from hud.txt, but + // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) + client_sprite_t *p = m_pSpriteList; + int index = 0; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf( sz, "sprites/%s.spr", p->szSprite ); + m_rghSprites[index] = SPR_Load(sz); + index++; + } + + p++; + } + } + + // assumption: number_1, number_2, etc, are all listed and loaded sequentially + m_HUD_number_0 = GetSpriteIndex( "number_0" ); + + m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; + + m_Ammo.VidInit(); + m_Health.VidInit(); + m_Spectator.VidInit(); + m_Geiger.VidInit(); + m_Train.VidInit(); + m_Battery.VidInit(); + m_Flash.VidInit(); + m_Message.VidInit(); + m_StatusBar.VidInit(); + m_DeathNotice.VidInit(); + m_SayText.VidInit(); + m_Menu.VidInit(); + m_AmmoSecondary.VidInit(); + m_TextMessage.VidInit(); + m_StatusIcons.VidInit(); + GetClientVoiceMgr()->VidInit(); +} + +float g_lastFOV = 0.0; + +/* +============ +COM_FileBase +============ +*/ +// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) +void COM_FileBase ( const char *in, char *out) +{ + int len, start, end; + + len = (int)strlen( in ); + + // scan backward for '.' + end = len - 1; + while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) + end--; + + if ( in[end] != '.' ) // no '.', copy to end + end = len-1; + else + end--; // Found ',', copy to left of '.' + + + // Scan backward for '/' + start = len-1; + while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) + start--; + + if ( in[start] != '/' && in[start] != '\\' ) + start = 0; + else + start++; + + // Length of new sting + len = end - start + 1; + + // Copy partial string + strncpy( out, &in[start], len ); + // Terminate it + out[len] = 0; +} + +/* +================= +HUD_IsGame + +================= +*/ +int HUD_IsGame( const char *game ) +{ + const char *gamedir; + char gd[ 1024 ]; + + gamedir = gEngfuncs.pfnGetGameDirectory(); + if ( gamedir && gamedir[0] ) + { + COM_FileBase( gamedir, gd ); + if ( !stricmp( gd, game ) ) + return 1; + } + return 0; +} + +/* +===================== +HUD_GetFOV + +Returns last FOV +===================== +*/ +float HUD_GetFOV( void ) +{ + if ( gEngfuncs.pDemoAPI->IsRecording() ) + { + // Write it + int i = 0; + unsigned char buf[ 100 ]; + + // Active + *( float * )&buf[ i ] = g_lastFOV; + i += sizeof( float ); + + Demo_WriteBuffer( TYPE_ZOOM, i, buf ); + } + + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + { + g_lastFOV = g_demozoom; + } + return g_lastFOV; +} + +int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + int newfov; + NetMsg_SetFOV( pbuf, iSize, newfov ); + int def_fov = CVAR_GET_FLOAT( "default_fov" ); + + //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). + if ( cl_lw && cl_lw->value ) + return 1; + + g_lastFOV = newfov; + + if ( newfov == 0 ) + { + m_iFOV = def_fov; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == def_fov ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + return 1; +} + + +void CHud::AddHudElem(CHudBase *phudelem) +{ + HUDLIST *pdl, *ptemp; + +//phudelem->Think(); + + if (!phudelem) + return; + + pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); + if (!pdl) + return; + + memset(pdl, 0, sizeof(HUDLIST)); + pdl->p = phudelem; + + if (!m_pHudList) + { + m_pHudList = pdl; + return; + } + + ptemp = m_pHudList; + + while (ptemp->pNext) + ptemp = ptemp->pNext; + + ptemp->pNext = pdl; +} + +float CHud::GetSensitivity( void ) +{ + return m_flMouseSensitivity; +} + + diff --git a/main/source/cl_dll/hud.h b/main/source/cl_dll/hud.h index aab293ba..bc2500d8 100644 --- a/main/source/cl_dll/hud.h +++ b/main/source/cl_dll/hud.h @@ -1,86 +1,86 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// hud.h -// -// class CHud declaration -// -// CHud handles the message, calculation, and drawing the HUD -// - -#ifndef HL_HUD_H -#define HL_HUD_H - -#include "chud.h" - -class TeamFortressViewport; - -class AvHHud; -#include "AvHHud.h" -extern AvHHud gHUD; - -#include "wrect.h" -#include "cl_dll.h" -#include "ammo.h" -#include "chudmisc.h" - -#include "voice_status.h" -#include "hud_spectator.h" - -/* -class CHudScoreboard: public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing - void UserCmd_ShowScores( void ); - void UserCmd_HideScores( void ); - int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); - void DeathMsg( int killer, int victim ); - - int m_iNumTeams; - - int m_iLastKilledBy; - int m_fLastKillTime; - int m_iPlayerNum; - int m_iShowscoresHeld; - - void GetAllPlayersInfo( void ); -private: - struct cvar_s *cl_showpacketloss; - -}; -*/ - -// -//----------------------------------------------------- -// - -#include "chud.h" - -extern TeamFortressViewport *gViewPort; - -extern int g_iPlayerClass; -extern int g_iTeamNumber; -extern int g_iUser1; -extern int g_iUser2; -extern int g_iUser3; - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud.h +// +// class CHud declaration +// +// CHud handles the message, calculation, and drawing the HUD +// + +#ifndef HL_HUD_H +#define HL_HUD_H + +#include "chud.h" + +class TeamFortressViewport; + +class AvHHud; +#include "AvHHud.h" +extern AvHHud gHUD; + +#include "wrect.h" +#include "cl_dll.h" +#include "ammo.h" +#include "chudmisc.h" + +#include "voice_status.h" +#include "hud_spectator.h" + +/* +class CHudScoreboard: public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing + void UserCmd_ShowScores( void ); + void UserCmd_HideScores( void ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + void DeathMsg( int killer, int victim ); + + int m_iNumTeams; + + int m_iLastKilledBy; + int m_fLastKillTime; + int m_iPlayerNum; + int m_iShowscoresHeld; + + void GetAllPlayersInfo( void ); +private: + struct cvar_s *cl_showpacketloss; + +}; +*/ + +// +//----------------------------------------------------- +// + +#include "chud.h" + +extern TeamFortressViewport *gViewPort; + +extern int g_iPlayerClass; +extern int g_iTeamNumber; +extern int g_iUser1; +extern int g_iUser2; +extern int g_iUser3; + +#endif diff --git a/main/source/cl_dll/hud_iface.h b/main/source/cl_dll/hud_iface.h index c763c8bb..d7fbc1ce 100644 --- a/main/source/cl_dll/hud_iface.h +++ b/main/source/cl_dll/hud_iface.h @@ -1,14 +1,14 @@ -#if !defined( HUD_IFACEH ) -#define HUD_IFACEH -#pragma once - -#ifndef EXPORT -#define EXPORT _declspec( dllexport ) -#endif - -typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); -#include "wrect.h" -#include "../engine/cdll_int.h" -extern cl_enginefunc_t gEngfuncs; - +#if !defined( HUD_IFACEH ) +#define HUD_IFACEH +#pragma once + +#ifndef EXPORT +#define EXPORT _declspec( dllexport ) +#endif + +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +#include "wrect.h" +#include "../engine/cdll_int.h" +extern cl_enginefunc_t gEngfuncs; + #endif \ No newline at end of file diff --git a/main/source/cl_dll/hud_msg.cpp b/main/source/cl_dll/hud_msg.cpp index dbe710a2..35580e9a 100644 --- a/main/source/cl_dll/hud_msg.cpp +++ b/main/source/cl_dll/hud_msg.cpp @@ -1,77 +1,77 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// hud_msg.cpp -// - -#include "hud.h" -#include "cl_util.h" -#include "common/r_efx.h" -#include "mod/AvHNetworkMessages.h" - -// : duck toggle -extern bool g_bDuckToggled; -// : - -#define MAX_CLIENTS 32 - -#if !defined( _TFC ) -extern BEAM *pBeam; -extern BEAM *pBeam2; -#endif -/// USER-DEFINED SERVER MESSAGE HANDLERS - -int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) -{ - NetMsg_ResetHUD( pbuf, iSize ); - - // clear all hud data - HUDLIST *pList = m_pHudList; - - while ( pList ) - { - if ( pList->p ) - pList->p->Reset(); - pList = pList->pNext; - } - - // reset sensitivity - m_flMouseSensitivity = 0; - - // : duck toggle - g_bDuckToggled = false; - // : - - return 0; -} - -void CAM_ToFirstPerson(void); -void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) -{ - CAM_ToFirstPerson(); -} - -void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) -{ - // prepare all hud data - HUDLIST *pList = m_pHudList; - - while (pList) - { - if ( pList->p ) - pList->p->InitHUDData(); - pList = pList->pNext; - } -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud_msg.cpp +// + +#include "hud.h" +#include "cl_util.h" +#include "common/r_efx.h" +#include "mod/AvHNetworkMessages.h" + +// : duck toggle +extern bool g_bDuckToggled; +// : + +#define MAX_CLIENTS 32 + +#if !defined( _TFC ) +extern BEAM *pBeam; +extern BEAM *pBeam2; +#endif +/// USER-DEFINED SERVER MESSAGE HANDLERS + +int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) +{ + NetMsg_ResetHUD( pbuf, iSize ); + + // clear all hud data + HUDLIST *pList = m_pHudList; + + while ( pList ) + { + if ( pList->p ) + pList->p->Reset(); + pList = pList->pNext; + } + + // reset sensitivity + m_flMouseSensitivity = 0; + + // : duck toggle + g_bDuckToggled = false; + // : + + return 0; +} + +void CAM_ToFirstPerson(void); +void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) +{ + CAM_ToFirstPerson(); +} + +void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) +{ + // prepare all hud data + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( pList->p ) + pList->p->InitHUDData(); + pList = pList->pNext; + } +} diff --git a/main/source/cl_dll/hud_redraw.cpp b/main/source/cl_dll/hud_redraw.cpp index ad3065a1..db8cf6c7 100644 --- a/main/source/cl_dll/hud_redraw.cpp +++ b/main/source/cl_dll/hud_redraw.cpp @@ -1,411 +1,411 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// hud_redraw.cpp -// -#include -#include "hud.h" -#include "cl_util.h" -#include "mod/AvHFont.h" - -#include "vgui_TeamFortressViewport.h" - -#define MAX_LOGO_FRAMES 56 - -int grgLogoFrame[MAX_LOGO_FRAMES] = -{ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, - 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 -}; - - -extern int g_iVisibleMouse; - -float HUD_GetFOV( void ); - -extern cvar_t *sensitivity; -extern cvar_t *cl_forcedefaultfov; - -// Think -void CHud::Think(void) -{ - int newfov; - HUDLIST *pList = m_pHudList; - - while (pList) - { - if (pList->p->m_iFlags & HUD_ACTIVE) - pList->p->Think(); - pList = pList->pNext; - } - - newfov = HUD_GetFOV(); - if ( newfov == 0 ) - { - m_iFOV = default_fov->value; - } - else - { - m_iFOV = newfov; - } - - if(cl_forcedefaultfov->value) - { - m_iFOV = 90; - } - - // the clients fov is actually set in the client data update section of the hud - - // Set a new sensitivity - if ( m_iFOV == default_fov->value ) - { - // reset to saved sensitivity - m_flMouseSensitivity = 0; - } - else - { - // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); - } - - // think about default fov - if ( m_iFOV == 0 ) - { // only let players adjust up in fov, and only if they are not overriden by something else - m_iFOV = max( default_fov->value, 90 ); - } -} - -// Redraw -// step through the local data, placing the appropriate graphics & text as appropriate -// returns 1 if they've changed, 0 otherwise -int CHud :: Redraw( float flTime, int intermission ) -{ - m_fOldTime = m_flTime; // save time of previous redraw - m_flTime = flTime; - m_flTimeDelta = (double)m_flTime - m_fOldTime; - static int m_flShotTime = 0; - - // Clock was reset, reset delta - if ( m_flTimeDelta < 0 ) - m_flTimeDelta = 0; - - // Bring up the scoreboard during intermission - if (gViewPort) - { - if ( m_iIntermission && !intermission ) - { - // Have to do this here so the scoreboard goes away - m_iIntermission = intermission; - gViewPort->HideCommandMenu(); - gViewPort->HideScoreBoard(); - gViewPort->UpdateSpectatorPanel(); - } - else if ( !m_iIntermission && intermission ) - { - m_iIntermission = intermission; - gViewPort->HideCommandMenu(); - gViewPort->HideVGUIMenu(); - gViewPort->ShowScoreBoard(); - gViewPort->UpdateSpectatorPanel(); - - // Take a screenshot if the client's got the cvar set - if ( CVAR_GET_FLOAT( "hud_takesshots" ) != 0 ) - m_flShotTime = flTime + 1.0; // Take a screenshot in a second - } - } - - if (m_flShotTime && m_flShotTime < flTime) - { - gEngfuncs.pfnClientCmd("snapshot\n"); - m_flShotTime = 0; - } - - m_iIntermission = intermission; - - // if no redrawing is necessary - // return 0; - - - if ( m_pCvarDraw->value) - { - HUDLIST *pList = m_pHudList; - - while (pList) - { - if ( !intermission ) - { - if ( (pList->p->m_iFlags & HUD_ACTIVE) && (!(m_iHideHUDDisplay & HIDEHUD_CHAT) && !(m_iHideHUDDisplay & HIDEHUD_ALL)) ) - pList->p->Draw(flTime); - } - else - { // it's an intermission, so only draw hud elements that are set to draw during intermissions - if ( pList->p->m_iFlags & HUD_INTERMISSION ) - pList->p->Draw( flTime ); - } - - pList = pList->pNext; - } - } - - // are we in demo mode? do we need to draw the logo in the top corner? - if (m_iLogo) - { - int x, y, i; - - if (m_hsprLogo == 0) - m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); - - SPR_Set(m_hsprLogo, 250, 250, 250 ); - - x = SPR_Width(m_hsprLogo, 0); - x = ScreenWidth() - x; - y = SPR_Height(m_hsprLogo, 0)/2; - - // Draw the logo at 20 fps - int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; - i = grgLogoFrame[iFrame] - 1; - - SPR_DrawAdditive(i, x, y, NULL); - } - - /* - if ( g_iVisibleMouse ) - { - void IN_GetMousePos( int *mx, int *my ); - int mx, my; - - IN_GetMousePos( &mx, &my ); - - if (m_hsprCursor == 0) - { - char sz[256]; - sprintf( sz, "sprites/cursor.spr" ); - m_hsprCursor = SPR_Load( sz ); - } - - SPR_Set(m_hsprCursor, 250, 250, 250 ); - - // Draw the logo at 20 fps - SPR_DrawAdditive( 0, mx, my, NULL ); - } - */ - - return 1; -} - -void ScaleColors( int &r, int &g, int &b, int a ) -{ - float x = (float)a / 255; - r = (int)(r * x); - g = (int)(g * x); - b = (int)(b * x); -} - -int CHud::GetHudStringHeight() -{ - - /* - int theHeight = 0; - theHeight = gHUD.m_scrinfo.iCharHeight; - return theHeight; - */ - - return mFont.GetStringHeight(); - -} - -int CHud::GetHudStringWidth(const char* szIt) -{ - /* - int theWidth = 0; - - // draw the string until we hit the null character or a newline character - for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) - { - theWidth += gHUD.m_scrinfo.charWidths[ *szIt ]; - } - - return theWidth; - */ - - return mFont.GetStringWidth(szIt); - -} - -int CHud::DrawHudStringCentered(int x, int y, int iMaxX, const char *szString, int r, int g, int b ) -{ - int theStringWidth = this->GetHudStringWidth(szString); - return this->DrawHudString(x - theStringWidth/2, y, iMaxX, szString, r, g, b); -} - -int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ) -{ - /* - // Try to prevent software-mode crash - int theStringHeight = this->GetHudStringHeight(); - - if((ypos + theStringHeight) < ScreenHeight()) - { - // draw the string until we hit the null character or a newline character - for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) - { - int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool - if ( next > iMaxX ) - return xpos; - - TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); - xpos = next; - } - } - - return xpos; - */ - - return mFont.DrawString(xpos, ypos, szIt, r, g, b); - -} - -int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) -{ - char szString[32]; - sprintf( szString, "%d", iNumber ); - return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); - -} - -// draws a string from right to left (right-aligned) -int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) -{ - - /* - // find the end of the string - for ( char *szIt = szString; *szIt != 0; szIt++ ) - { // we should count the length? - } - - // iterate throug the string in reverse - for ( szIt--; szIt != (szString-1); szIt-- ) - { - int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool - if ( next < iMinX ) - return xpos; - xpos = next; - - TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); - } - - return xpos; - */ - - return mFont.DrawStringReverse(xpos, ypos, szString, r, g, b); - -} - -int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) -{ - int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; - int k; - - if (iNumber > 0) - { - // SPR_Draw 100's - if (iNumber >= 100) - { - k = iNumber/100; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if (iFlags & (DHN_3DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - // SPR_Draw 10's - if (iNumber >= 10) - { - k = (iNumber % 100)/10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - // SPR_Draw ones - k = iNumber % 10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if (iFlags & DHN_DRAWZERO) - { - SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); - - // SPR_Draw 100's - if (iFlags & (DHN_3DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - // SPR_Draw ones - - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); - x += iWidth; - } - - return x; -} - - -int CHud::GetNumWidth( int iNumber, int iFlags ) -{ - if (iFlags & (DHN_3DIGITS)) - return 3; - - if (iFlags & (DHN_2DIGITS)) - return 2; - - if (iNumber <= 0) - { - if (iFlags & (DHN_DRAWZERO)) - return 1; - else - return 0; - } - - if (iNumber < 10) - return 1; - - if (iNumber < 100) - return 2; - - return 3; - -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud_redraw.cpp +// +#include +#include "hud.h" +#include "cl_util.h" +#include "mod/AvHFont.h" + +#include "vgui_TeamFortressViewport.h" + +#define MAX_LOGO_FRAMES 56 + +int grgLogoFrame[MAX_LOGO_FRAMES] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, + 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 +}; + + +extern int g_iVisibleMouse; + +float HUD_GetFOV( void ); + +extern cvar_t *sensitivity; +extern cvar_t *cl_forcedefaultfov; + +// Think +void CHud::Think(void) +{ + int newfov; + HUDLIST *pList = m_pHudList; + + while (pList) + { + if (pList->p->m_iFlags & HUD_ACTIVE) + pList->p->Think(); + pList = pList->pNext; + } + + newfov = HUD_GetFOV(); + if ( newfov == 0 ) + { + m_iFOV = default_fov->value; + } + else + { + m_iFOV = newfov; + } + + if(cl_forcedefaultfov->value) + { + m_iFOV = 90; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == default_fov->value ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + // think about default fov + if ( m_iFOV == 0 ) + { // only let players adjust up in fov, and only if they are not overriden by something else + m_iFOV = max( default_fov->value, 90 ); + } +} + +// Redraw +// step through the local data, placing the appropriate graphics & text as appropriate +// returns 1 if they've changed, 0 otherwise +int CHud :: Redraw( float flTime, int intermission ) +{ + m_fOldTime = m_flTime; // save time of previous redraw + m_flTime = flTime; + m_flTimeDelta = (double)m_flTime - m_fOldTime; + static int m_flShotTime = 0; + + // Clock was reset, reset delta + if ( m_flTimeDelta < 0 ) + m_flTimeDelta = 0; + + // Bring up the scoreboard during intermission + if (gViewPort) + { + if ( m_iIntermission && !intermission ) + { + // Have to do this here so the scoreboard goes away + m_iIntermission = intermission; + gViewPort->HideCommandMenu(); + gViewPort->HideScoreBoard(); + gViewPort->UpdateSpectatorPanel(); + } + else if ( !m_iIntermission && intermission ) + { + m_iIntermission = intermission; + gViewPort->HideCommandMenu(); + gViewPort->HideVGUIMenu(); + gViewPort->ShowScoreBoard(); + gViewPort->UpdateSpectatorPanel(); + + // Take a screenshot if the client's got the cvar set + if ( CVAR_GET_FLOAT( "hud_takesshots" ) != 0 ) + m_flShotTime = flTime + 1.0; // Take a screenshot in a second + } + } + + if (m_flShotTime && m_flShotTime < flTime) + { + gEngfuncs.pfnClientCmd("snapshot\n"); + m_flShotTime = 0; + } + + m_iIntermission = intermission; + + // if no redrawing is necessary + // return 0; + + + if ( m_pCvarDraw->value) + { + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( !intermission ) + { + if ( (pList->p->m_iFlags & HUD_ACTIVE) && (!(m_iHideHUDDisplay & HIDEHUD_CHAT) && !(m_iHideHUDDisplay & HIDEHUD_ALL)) ) + pList->p->Draw(flTime); + } + else + { // it's an intermission, so only draw hud elements that are set to draw during intermissions + if ( pList->p->m_iFlags & HUD_INTERMISSION ) + pList->p->Draw( flTime ); + } + + pList = pList->pNext; + } + } + + // are we in demo mode? do we need to draw the logo in the top corner? + if (m_iLogo) + { + int x, y, i; + + if (m_hsprLogo == 0) + m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); + + SPR_Set(m_hsprLogo, 250, 250, 250 ); + + x = SPR_Width(m_hsprLogo, 0); + x = ScreenWidth() - x; + y = SPR_Height(m_hsprLogo, 0)/2; + + // Draw the logo at 20 fps + int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; + i = grgLogoFrame[iFrame] - 1; + + SPR_DrawAdditive(i, x, y, NULL); + } + + /* + if ( g_iVisibleMouse ) + { + void IN_GetMousePos( int *mx, int *my ); + int mx, my; + + IN_GetMousePos( &mx, &my ); + + if (m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + m_hsprCursor = SPR_Load( sz ); + } + + SPR_Set(m_hsprCursor, 250, 250, 250 ); + + // Draw the logo at 20 fps + SPR_DrawAdditive( 0, mx, my, NULL ); + } + */ + + return 1; +} + +void ScaleColors( int &r, int &g, int &b, int a ) +{ + float x = (float)a / 255; + r = (int)(r * x); + g = (int)(g * x); + b = (int)(b * x); +} + +int CHud::GetHudStringHeight() +{ + + /* + int theHeight = 0; + theHeight = gHUD.m_scrinfo.iCharHeight; + return theHeight; + */ + + return mFont.GetStringHeight(); + +} + +int CHud::GetHudStringWidth(const char* szIt) +{ + /* + int theWidth = 0; + + // draw the string until we hit the null character or a newline character + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + theWidth += gHUD.m_scrinfo.charWidths[ *szIt ]; + } + + return theWidth; + */ + + return mFont.GetStringWidth(szIt); + +} + +int CHud::DrawHudStringCentered(int x, int y, int iMaxX, const char *szString, int r, int g, int b ) +{ + int theStringWidth = this->GetHudStringWidth(szString); + return this->DrawHudString(x - theStringWidth/2, y, iMaxX, szString, r, g, b); +} + +int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ) +{ + /* + // Try to prevent software-mode crash + int theStringHeight = this->GetHudStringHeight(); + + if((ypos + theStringHeight) < ScreenHeight()) + { + // draw the string until we hit the null character or a newline character + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next > iMaxX ) + return xpos; + + TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + xpos = next; + } + } + + return xpos; + */ + + return mFont.DrawString(xpos, ypos, szIt, r, g, b); + +} + +int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) +{ + char szString[32]; + sprintf( szString, "%d", iNumber ); + return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); + +} + +// draws a string from right to left (right-aligned) +int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) +{ + + /* + // find the end of the string + for ( char *szIt = szString; *szIt != 0; szIt++ ) + { // we should count the length? + } + + // iterate throug the string in reverse + for ( szIt--; szIt != (szString-1); szIt-- ) + { + int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next < iMinX ) + return xpos; + xpos = next; + + TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + } + + return xpos; + */ + + return mFont.DrawStringReverse(xpos, ypos, szString, r, g, b); + +} + +int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) +{ + int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; + int k; + + if (iNumber > 0) + { + // SPR_Draw 100's + if (iNumber >= 100) + { + k = iNumber/100; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw 10's + if (iNumber >= 10) + { + k = (iNumber % 100)/10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + k = iNumber % 10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & DHN_DRAWZERO) + { + SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); + + // SPR_Draw 100's + if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); + x += iWidth; + } + + return x; +} + + +int CHud::GetNumWidth( int iNumber, int iFlags ) +{ + if (iFlags & (DHN_3DIGITS)) + return 3; + + if (iFlags & (DHN_2DIGITS)) + return 2; + + if (iNumber <= 0) + { + if (iFlags & (DHN_DRAWZERO)) + return 1; + else + return 0; + } + + if (iNumber < 10) + return 1; + + if (iNumber < 100) + return 2; + + return 3; + +} + + diff --git a/main/source/cl_dll/hud_servers.cpp b/main/source/cl_dll/hud_servers.cpp index 561290fe..c5ec3cb7 100644 --- a/main/source/cl_dll/hud_servers.cpp +++ b/main/source/cl_dll/hud_servers.cpp @@ -1,1228 +1,1228 @@ -// hud_servers.cpp -#include "hud.h" -#include "cl_util.h" -#include "hud_servers_priv.h" -#include "hud_servers.h" -#include "common/net_api.h" -#include - #ifdef _WIN32 -#include "winsani_in.h" -#include -#include "winsani_out.h" -#else -#include -#endif -static int context_id; - -// Default master server address in case we can't read any from woncomm.lst file -#define VALVE_MASTER_ADDRESS "half-life.east.won.net" -#define PORT_MASTER 27010 -#define PORT_SERVER 27015 - -// File where we really should look for master servers -#define MASTER_PARSE_FILE "woncomm.lst" - -#define MAX_QUERIES 20 - -#define NET_API gEngfuncs.pNetAPI - -static CHudServers *g_pServers = NULL; - -/* -=================== -ListResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK ListResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->ListResponse( response ); - } -} - -/* -=================== -ServerResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK ServerResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->ServerResponse( response ); - } -} - -/* -=================== -PingResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK PingResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->PingResponse( response ); - } -} - -/* -=================== -RulesResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK RulesResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->RulesResponse( response ); - } -} -/* -=================== -PlayersResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK PlayersResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->PlayersResponse( response ); - } -} -/* -=================== -ListResponse - -=================== -*/ -void CHudServers::ListResponse( struct net_response_s *response ) -{ - request_t *list; - request_t *p; - int c = 0; - - if ( !( response->error == NET_SUCCESS ) ) - return; - - if ( response->type != NETAPI_REQUEST_SERVERLIST ) - return; - - if ( response->response ) - { - list = ( request_t * ) response->response; - while ( list ) - { - c++; - - //if ( c < 40 ) - { - // Copy from parsed stuff - p = new request_t; - p->context = -1; - p->remote_address = list->remote_address; - p->next = m_pServerList; - m_pServerList = p; - } - - // Move on - list = list->next; - } - } - - gEngfuncs.Con_Printf( "got list\n" ); - - m_nQuerying = 1; - m_nActiveQueries = 0; -} - -/* -=================== -ServerResponse - -=================== -*/ -void CHudServers::ServerResponse( struct net_response_s *response ) -{ - char *szresponse; - request_t *p; - server_t *browser; - int len; - char sz[ 32 ]; - - // Remove from active list - p = FindRequest( response->context, m_pActiveList ); - if ( p ) - { - RemoveServerFromList( &m_pActiveList, p ); - m_nActiveQueries--; - } - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_DETAILS: - if ( response->response ) - { - szresponse = (char *)response->response; - len = (int)strlen( szresponse ) + 100 + 1; - sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); - - browser = new server_t; - browser->remote_address = response->remote_address; - browser->info = new char[ len ]; - browser->ping = (int)( 1000.0 * response->ping ); - strcpy( browser->info, szresponse ); - - NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); - NET_API->SetValueForKey( browser->info, "ping", sz, len ); - - AddServer( &m_pServers, browser ); - } - break; - default: - break; - } -} - -/* -=================== -PingResponse - -=================== -*/ -void CHudServers::PingResponse( struct net_response_s *response ) -{ - char sz[ 32 ]; - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_PING: - sprintf( sz, "%.2f", 1000.0 * response->ping ); - - gEngfuncs.Con_Printf( "ping == %s\n", sz ); - break; - default: - break; - } -} - -/* -=================== -RulesResponse - -=================== -*/ -void CHudServers::RulesResponse( struct net_response_s *response ) -{ - char *szresponse; - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_RULES: - if ( response->response ) - { - szresponse = (char *)response->response; - - gEngfuncs.Con_Printf( "rules %s\n", szresponse ); - } - break; - default: - break; - } -} - -/* -=================== -PlayersResponse - -=================== -*/ -void CHudServers::PlayersResponse( struct net_response_s *response ) -{ - char *szresponse; - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_PLAYERS: - if ( response->response ) - { - szresponse = (char *)response->response; - - gEngfuncs.Con_Printf( "players %s\n", szresponse ); - } - break; - default: - break; - } -} - -/* -=================== -CompareServers - -Return 1 if p1 is "less than" p2, 0 otherwise -=================== -*/ -int CHudServers::CompareServers( server_t *p1, server_t *p2 ) -{ - const char *n1, *n2; - - if ( p1->ping < p2->ping ) - return 1; - - if ( p1->ping == p2->ping ) - { - // Pings equal, sort by second key: hostname - if ( p1->info && p2->info ) - { - n1 = NET_API->ValueForKey( p1->info, "hostname" ); - n2 = NET_API->ValueForKey( p2->info, "hostname" ); - - if ( n1 && n2 ) - { - if ( stricmp( n1, n2 ) < 0 ) - return 1; - } - } - } - - return 0; -} - -/* -=================== -AddServer - -=================== -*/ -void CHudServers::AddServer( server_t **ppList, server_t *p ) -{ -server_t *list; - - if ( !ppList || ! p ) - return; - - m_nServerCount++; - - // What sort key? Ping? - list = *ppList; - - // Head of list? - if ( !list ) - { - p->next = NULL; - *ppList = p; - return; - } - - // Put on head of list - if ( CompareServers( p, list ) ) - { - p->next = *ppList; - *ppList = p; - } - else - { - while ( list->next ) - { - // Insert before list next - if ( CompareServers( p, list->next ) ) - { - p->next = list->next->next; - list->next = p; - return; - } - - list = list->next; - } - - // Just add at end - p->next = NULL; - list->next = p; - } -} - -/* -=================== -Think - -=================== -*/ -void CHudServers::Think( double time ) -{ - m_fElapsed += time; - - if ( !m_nRequesting ) - return; - - if ( !m_nQuerying ) - return; - - QueryThink(); - - if ( ServerListSize() > 0 ) - return; - - m_dStarted = 0.0; - m_nRequesting = 0; - m_nDone = 0; - m_nQuerying = 0; - m_nActiveQueries = 0; -} - -/* -=================== -QueryThink - -=================== -*/ -void CHudServers::QueryThink( void ) -{ - request_t *p; - - if ( !m_nRequesting || m_nDone ) - return; - - if ( !m_nQuerying ) - return; - - if ( m_nActiveQueries > MAX_QUERIES ) - return; - - // Nothing left - if ( !m_pServerList ) - return; - - while ( 1 ) - { - p = m_pServerList; - - // No more in list? - if ( !p ) - break; - - // Move to next - m_pServerList = m_pServerList->next; - - // Setup context_id - p->context = context_id; - - // Start up query on this one - NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); - - // Increment active list - m_nActiveQueries++; - - // Add to active list - p->next = m_pActiveList; - m_pActiveList = p; - - // Too many active? - if ( m_nActiveQueries > MAX_QUERIES ) - break; - } -} - -/* -================== -ServerListSize - -# of servers in active query and in pending to be queried lists -================== -*/ -int CHudServers::ServerListSize( void ) -{ - int c = 0; - request_t *p; - - p = m_pServerList; - while ( p ) - { - c++; - p = p->next; - } - - p = m_pActiveList; - while ( p ) - { - c++; - p = p->next; - } - - return c; -} - -/* -=================== -FindRequest - -Look up a request by context id -=================== -*/ -CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) -{ - request_t *p; - p = pList; - while ( p ) - { - if ( context == p->context ) - return p; - - p = p->next; - } - return NULL; -} - -/* -=================== -RemoveServerFromList - -Remote, but don't delete, item from *ppList -=================== -*/ -void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) -{ - request_t *p, *n; - request_t *newlist = NULL; - - if ( !ppList ) - return; - - p = *ppList; - while ( p ) - { - n = p->next; - if ( p != item ) - { - p->next = newlist; - newlist = p; - } - p = n; - } - *ppList = newlist; -} - -/* -=================== -ClearRequestList - -=================== -*/ -void CHudServers::ClearRequestList( request_t **ppList ) -{ - request_t *p, *n; - - if ( !ppList ) - return; - - p = *ppList; - while ( p ) - { - n = p->next; - delete p; - p = n; - } - *ppList = NULL; -} - -/* -=================== -ClearServerList - -=================== -*/ -void CHudServers::ClearServerList( server_t **ppList ) -{ - server_t *p, *n; - - if ( !ppList ) - return; - - p = *ppList; - while ( p ) - { - n = p->next; - delete[] p->info; - delete p; - p = n; - } - *ppList = NULL; -} - -int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) -{ - const char *sz1, *sz2; - float fv1, fv2; - - sz1 = NET_API->ValueForKey( p1->info, fieldname ); - sz2 = NET_API->ValueForKey( p2->info, fieldname ); - - fv1 = atof( sz1 ); - fv2 = atof( sz2 ); - - if ( fv1 && fv2 ) - { - if ( fv1 > fv2 ) - return iSortOrder; - else if ( fv1 < fv2 ) - return -iSortOrder; - else - return 0; - } - - // String compare - return stricmp( sz1, sz2 ); -} - -int ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) -{ - if (!p1 || !p2) // No meaningful comparison - return 0; - - int iSortOrder = 1; - - int retval = 0; - - retval = CompareField( p1, p2, fieldname, iSortOrder ); - - return retval; -} - -static char g_fieldname[ 256 ]; -int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) -{ - CHudServers::server_t *list1, *list2; - - list1 = *(CHudServers::server_t **)elem1; - list2 = *(CHudServers::server_t **)elem2; - - return ServerListCompareFunc( list1, list2, g_fieldname ); -} - -void CHudServers::SortServers( const char *fieldname ) -{ - server_t *p; - // Create a list - if ( !m_pServers ) - return; - - strcpy( g_fieldname, fieldname ); - - int i; - int c = 0; - - p = m_pServers; - while ( p ) - { - c++; - p = p->next; - } - - server_t **pSortArray; - - pSortArray = new server_t *[ c ]; - memset( pSortArray, 0, c * sizeof( server_t * ) ); - - // Now copy the list into the pSortArray: - p = m_pServers; - i = 0; - while ( p ) - { - pSortArray[ i++ ] = p; - p = p->next; - } - - // Now do that actual sorting. - size_t nCount = c; - size_t nSize = sizeof( server_t * ); - - qsort( - pSortArray, - (size_t)nCount, - (size_t)nSize, - FnServerCompare - ); - - // Now rebuild the list. - m_pServers = pSortArray[0]; - for ( i = 0; i < c - 1; i++ ) - { - pSortArray[ i ]->next = pSortArray[ i + 1 ]; - } - pSortArray[ c - 1 ]->next = NULL; - - // Clean Up. - delete[] pSortArray; -} - -/* -=================== -GetServer - -Return particular server -=================== -*/ -CHudServers::server_t *CHudServers::GetServer( int server ) -{ - int c = 0; - server_t *p; - - p = m_pServers; - while ( p ) - { - if ( c == server ) - return p; - - c++; - p = p->next; - } - return NULL; -} - -/* -=================== -GetServerInfo - -Return info ( key/value ) string for particular server -=================== -*/ -char *CHudServers::GetServerInfo( int server ) -{ - server_t *p = GetServer( server ); - if ( p ) - { - return p->info; - } - return NULL; -} - -/* -=================== -CancelRequest - -Kill all pending requests in engine -=================== -*/ -void CHudServers::CancelRequest( void ) -{ - m_nRequesting = 0; - m_nQuerying = 0; - m_nDone = 1; - - NET_API->CancelAllRequests(); -} - -/* -================== -LoadMasterAddresses - -Loads the master server addresses from file and into the passed in array -================== -*/ -int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) -{ - int i; - char szMaster[ 256 ]; - char szMasterFile[256]; - char *pbuffer = NULL; - char *pstart = NULL ; - netadr_t adr; - char szAdr[64]; - int nPort; - int nCount = 0; - bool bIgnore; - int nDefaultPort; - - // Assume default master and master file - strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string - strcpy( szMasterFile, MASTER_PARSE_FILE ); - - // See if there is a command line override - i = gEngfuncs.CheckParm( "-comm", &pstart ); - if ( i && pstart ) - { - strcpy (szMasterFile, pstart ); - } - - // Read them in from proper file - pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc - if ( !pbuffer ) - { - goto finish_master; - } - - pstart = pbuffer; - - while ( nCount < maxservers ) - { - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if ( strlen(m_szToken) <= 0) - break; - - bIgnore = true; - - if ( !stricmp( m_szToken, "Master" ) ) - { - nDefaultPort = PORT_MASTER; - bIgnore = FALSE; - } - - // Now parse all addresses between { } - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - if ( strlen(m_szToken) <= 0 ) - break; - - if ( stricmp ( m_szToken, "{" ) ) - break; - - // Parse addresses until we get to "}" - while ( nCount < maxservers ) - { - char base[256]; - - // Now parse all addresses between { } - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) - break; - - if ( !stricmp ( m_szToken, "}" ) ) - break; - - sprintf( base, "%s", m_szToken ); - - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) - break; - - if ( stricmp( m_szToken, ":" ) ) - break; - - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) - break; - - nPort = atoi ( m_szToken ); - if ( !nPort ) - nPort = nDefaultPort; - - sprintf( szAdr, "%s:%i", base, nPort ); - - // Can we resolve it any better - if ( !NET_API->StringToAdr( szAdr, &adr ) ) - bIgnore = true; - - if ( !bIgnore ) - { - padr[ nCount++ ] = adr; - } - } - } - -finish_master: - if ( !nCount ) - { - sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string - - // Convert to netadr_t - if ( NET_API->StringToAdr ( szMaster, &adr ) ) - { - - padr[ nCount++ ] = adr; - } - } - - *count = nCount; - - if ( pbuffer ) - { - gEngfuncs.COM_FreeFile( pbuffer ); - } - - return ( nCount > 0 ) ? 1 : 0; -} - -/* -=================== -RequestList - -Request list of game servers from master -=================== -*/ -void CHudServers::RequestList( void ) -{ - m_nRequesting = 1; - m_nDone = 0; - m_dStarted = m_fElapsed; - - int count = 0; - netadr_t adr; - - if ( !LoadMasterAddresses( 1, &count, &adr ) ) - { - gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); - return; - } - - ClearRequestList( &m_pActiveList ); - ClearRequestList( &m_pServerList ); - ClearServerList( &m_pServers ); - - m_nServerCount = 0; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Kill off left overs if any - NET_API->CancelAllRequests(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); -} - -void CHudServers::RequestBroadcastList( int clearpending ) -{ - m_nRequesting = 1; - m_nDone = 0; - m_dStarted = m_fElapsed; - - netadr_t adr; - memset( &adr, 0, sizeof( adr ) ); - - if ( clearpending ) - { - ClearRequestList( &m_pActiveList ); - ClearRequestList( &m_pServerList ); - ClearServerList( &m_pServers ); - - m_nServerCount = 0; - } - - // Make sure to byte swap server if necessary ( using "host" to "net" conversion - adr.port = htons( PORT_SERVER ); - - // Make sure networking system has started. - NET_API->InitNetworking(); - - if ( clearpending ) - { - // Kill off left overs if any - NET_API->CancelAllRequests(); - } - - adr.type = NA_BROADCAST; - - // Request Servers from LAN via IP - NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); - - adr.type = NA_BROADCAST_IPX; - - // Request Servers from LAN via IPX ( if supported ) - NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); -} - -void CHudServers::ServerPing( int server ) -{ - server_t *p; - - p = GetServer( server ); - if ( !p ) - return; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); -} - -void CHudServers::ServerRules( int server ) -{ - server_t *p; - - p = GetServer( server ); - if ( !p ) - return; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); -} - -void CHudServers::ServerPlayers( int server ) -{ - server_t *p; - - p = GetServer( server ); - if ( !p ) - return; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); -} - -int CHudServers::isQuerying() -{ - return m_nRequesting ? 1 : 0; -} - - -/* -=================== -GetServerCount - -Return number of servers in browser list -=================== -*/ -int CHudServers::GetServerCount( void ) -{ - return m_nServerCount; -} - -/* -=================== -CHudServers - -=================== -*/ -CHudServers::CHudServers( void ) -{ - m_nRequesting = 0; - m_dStarted = 0.0; - m_nDone = 0; - m_pServerList = NULL; - m_pServers = NULL; - m_pActiveList = NULL; - m_nQuerying = 0; - m_nActiveQueries = 0; - - m_fElapsed = 0.0; - - - m_pPingRequest = NULL; - m_pRulesRequest = NULL; - m_pPlayersRequest = NULL; -} - -/* -=================== -~CHudServers - -=================== -*/ -CHudServers::~CHudServers( void ) -{ - ClearRequestList( &m_pActiveList ); - ClearRequestList( &m_pServerList ); - ClearServerList( &m_pServers ); - - m_nServerCount = 0; - - if ( m_pPingRequest ) - { - delete m_pPingRequest; - m_pPingRequest = NULL; - - } - - if ( m_pRulesRequest ) - { - delete m_pRulesRequest; - m_pRulesRequest = NULL; - } - - if ( m_pPlayersRequest ) - { - delete m_pPlayersRequest; - m_pPlayersRequest = NULL; - } -} - -/////////////////////////////// -// -// PUBLIC APIs -// -/////////////////////////////// - -/* -=================== -ServersGetCount - -=================== -*/ -int ServersGetCount( void ) -{ - if ( g_pServers ) - { - return g_pServers->GetServerCount(); - } - return 0; -} - -int ServersIsQuerying( void ) -{ - if ( g_pServers ) - { - return g_pServers->isQuerying(); - } - return 0; -} - -/* -=================== -ServersGetInfo - -=================== -*/ -const char *ServersGetInfo( int server ) -{ - if ( g_pServers ) - { - return g_pServers->GetServerInfo( server ); - } - - return NULL; -} - -void SortServers( const char *fieldname ) -{ - if ( g_pServers ) - { - g_pServers->SortServers( fieldname ); - } -} - -/* -=================== -ServersShutdown - -=================== -*/ -void ServersShutdown( void ) -{ - if ( g_pServers ) - { - delete g_pServers; - g_pServers = NULL; - } -} - -/* -=================== -ServersInit - -=================== -*/ -void ServersInit( void ) -{ - // Kill any previous instance - ServersShutdown(); - - g_pServers = new CHudServers(); -} - -/* -=================== -ServersThink - -=================== -*/ -void ServersThink( double time ) -{ - if ( g_pServers ) - { - g_pServers->Think( time ); - } -} - -/* -=================== -ServersCancel - -=================== -*/ -void ServersCancel( void ) -{ - if ( g_pServers ) - { - g_pServers->CancelRequest(); - } -} - -// Requests -/* -=================== -ServersList - -=================== -*/ -void ServersList( void ) -{ - if ( g_pServers ) - { - g_pServers->RequestList(); - } -} - -void BroadcastServersList( int clearpending ) -{ - if ( g_pServers ) - { - g_pServers->RequestBroadcastList( clearpending ); - } -} - -void ServerPing( int server ) -{ - if ( g_pServers ) - { - g_pServers->ServerPing( server ); - } -} - -void ServerRules( int server ) -{ - if ( g_pServers ) - { - g_pServers->ServerRules( server ); - } -} - -void ServerPlayers( int server ) -{ - if ( g_pServers ) - { - g_pServers->ServerPlayers( server ); - } -} +// hud_servers.cpp +#include "hud.h" +#include "cl_util.h" +#include "hud_servers_priv.h" +#include "hud_servers.h" +#include "common/net_api.h" +#include + #ifdef _WIN32 +#include "winsani_in.h" +#include +#include "winsani_out.h" +#else +#include +#endif +static int context_id; + +// Default master server address in case we can't read any from woncomm.lst file +#define VALVE_MASTER_ADDRESS "half-life.east.won.net" +#define PORT_MASTER 27010 +#define PORT_SERVER 27015 + +// File where we really should look for master servers +#define MASTER_PARSE_FILE "woncomm.lst" + +#define MAX_QUERIES 20 + +#define NET_API gEngfuncs.pNetAPI + +static CHudServers *g_pServers = NULL; + +/* +=================== +ListResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ListResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ListResponse( response ); + } +} + +/* +=================== +ServerResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ServerResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ServerResponse( response ); + } +} + +/* +=================== +PingResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PingResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PingResponse( response ); + } +} + +/* +=================== +RulesResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK RulesResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->RulesResponse( response ); + } +} +/* +=================== +PlayersResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PlayersResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PlayersResponse( response ); + } +} +/* +=================== +ListResponse + +=================== +*/ +void CHudServers::ListResponse( struct net_response_s *response ) +{ + request_t *list; + request_t *p; + int c = 0; + + if ( !( response->error == NET_SUCCESS ) ) + return; + + if ( response->type != NETAPI_REQUEST_SERVERLIST ) + return; + + if ( response->response ) + { + list = ( request_t * ) response->response; + while ( list ) + { + c++; + + //if ( c < 40 ) + { + // Copy from parsed stuff + p = new request_t; + p->context = -1; + p->remote_address = list->remote_address; + p->next = m_pServerList; + m_pServerList = p; + } + + // Move on + list = list->next; + } + } + + gEngfuncs.Con_Printf( "got list\n" ); + + m_nQuerying = 1; + m_nActiveQueries = 0; +} + +/* +=================== +ServerResponse + +=================== +*/ +void CHudServers::ServerResponse( struct net_response_s *response ) +{ + char *szresponse; + request_t *p; + server_t *browser; + int len; + char sz[ 32 ]; + + // Remove from active list + p = FindRequest( response->context, m_pActiveList ); + if ( p ) + { + RemoveServerFromList( &m_pActiveList, p ); + m_nActiveQueries--; + } + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_DETAILS: + if ( response->response ) + { + szresponse = (char *)response->response; + len = (int)strlen( szresponse ) + 100 + 1; + sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); + + browser = new server_t; + browser->remote_address = response->remote_address; + browser->info = new char[ len ]; + browser->ping = (int)( 1000.0 * response->ping ); + strcpy( browser->info, szresponse ); + + NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); + NET_API->SetValueForKey( browser->info, "ping", sz, len ); + + AddServer( &m_pServers, browser ); + } + break; + default: + break; + } +} + +/* +=================== +PingResponse + +=================== +*/ +void CHudServers::PingResponse( struct net_response_s *response ) +{ + char sz[ 32 ]; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PING: + sprintf( sz, "%.2f", 1000.0 * response->ping ); + + gEngfuncs.Con_Printf( "ping == %s\n", sz ); + break; + default: + break; + } +} + +/* +=================== +RulesResponse + +=================== +*/ +void CHudServers::RulesResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_RULES: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "rules %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +PlayersResponse + +=================== +*/ +void CHudServers::PlayersResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PLAYERS: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "players %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +CompareServers + +Return 1 if p1 is "less than" p2, 0 otherwise +=================== +*/ +int CHudServers::CompareServers( server_t *p1, server_t *p2 ) +{ + const char *n1, *n2; + + if ( p1->ping < p2->ping ) + return 1; + + if ( p1->ping == p2->ping ) + { + // Pings equal, sort by second key: hostname + if ( p1->info && p2->info ) + { + n1 = NET_API->ValueForKey( p1->info, "hostname" ); + n2 = NET_API->ValueForKey( p2->info, "hostname" ); + + if ( n1 && n2 ) + { + if ( stricmp( n1, n2 ) < 0 ) + return 1; + } + } + } + + return 0; +} + +/* +=================== +AddServer + +=================== +*/ +void CHudServers::AddServer( server_t **ppList, server_t *p ) +{ +server_t *list; + + if ( !ppList || ! p ) + return; + + m_nServerCount++; + + // What sort key? Ping? + list = *ppList; + + // Head of list? + if ( !list ) + { + p->next = NULL; + *ppList = p; + return; + } + + // Put on head of list + if ( CompareServers( p, list ) ) + { + p->next = *ppList; + *ppList = p; + } + else + { + while ( list->next ) + { + // Insert before list next + if ( CompareServers( p, list->next ) ) + { + p->next = list->next->next; + list->next = p; + return; + } + + list = list->next; + } + + // Just add at end + p->next = NULL; + list->next = p; + } +} + +/* +=================== +Think + +=================== +*/ +void CHudServers::Think( double time ) +{ + m_fElapsed += time; + + if ( !m_nRequesting ) + return; + + if ( !m_nQuerying ) + return; + + QueryThink(); + + if ( ServerListSize() > 0 ) + return; + + m_dStarted = 0.0; + m_nRequesting = 0; + m_nDone = 0; + m_nQuerying = 0; + m_nActiveQueries = 0; +} + +/* +=================== +QueryThink + +=================== +*/ +void CHudServers::QueryThink( void ) +{ + request_t *p; + + if ( !m_nRequesting || m_nDone ) + return; + + if ( !m_nQuerying ) + return; + + if ( m_nActiveQueries > MAX_QUERIES ) + return; + + // Nothing left + if ( !m_pServerList ) + return; + + while ( 1 ) + { + p = m_pServerList; + + // No more in list? + if ( !p ) + break; + + // Move to next + m_pServerList = m_pServerList->next; + + // Setup context_id + p->context = context_id; + + // Start up query on this one + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); + + // Increment active list + m_nActiveQueries++; + + // Add to active list + p->next = m_pActiveList; + m_pActiveList = p; + + // Too many active? + if ( m_nActiveQueries > MAX_QUERIES ) + break; + } +} + +/* +================== +ServerListSize + +# of servers in active query and in pending to be queried lists +================== +*/ +int CHudServers::ServerListSize( void ) +{ + int c = 0; + request_t *p; + + p = m_pServerList; + while ( p ) + { + c++; + p = p->next; + } + + p = m_pActiveList; + while ( p ) + { + c++; + p = p->next; + } + + return c; +} + +/* +=================== +FindRequest + +Look up a request by context id +=================== +*/ +CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) +{ + request_t *p; + p = pList; + while ( p ) + { + if ( context == p->context ) + return p; + + p = p->next; + } + return NULL; +} + +/* +=================== +RemoveServerFromList + +Remote, but don't delete, item from *ppList +=================== +*/ +void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) +{ + request_t *p, *n; + request_t *newlist = NULL; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + if ( p != item ) + { + p->next = newlist; + newlist = p; + } + p = n; + } + *ppList = newlist; +} + +/* +=================== +ClearRequestList + +=================== +*/ +void CHudServers::ClearRequestList( request_t **ppList ) +{ + request_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete p; + p = n; + } + *ppList = NULL; +} + +/* +=================== +ClearServerList + +=================== +*/ +void CHudServers::ClearServerList( server_t **ppList ) +{ + server_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete[] p->info; + delete p; + p = n; + } + *ppList = NULL; +} + +int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) +{ + const char *sz1, *sz2; + float fv1, fv2; + + sz1 = NET_API->ValueForKey( p1->info, fieldname ); + sz2 = NET_API->ValueForKey( p2->info, fieldname ); + + fv1 = atof( sz1 ); + fv2 = atof( sz2 ); + + if ( fv1 && fv2 ) + { + if ( fv1 > fv2 ) + return iSortOrder; + else if ( fv1 < fv2 ) + return -iSortOrder; + else + return 0; + } + + // String compare + return stricmp( sz1, sz2 ); +} + +int ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) +{ + if (!p1 || !p2) // No meaningful comparison + return 0; + + int iSortOrder = 1; + + int retval = 0; + + retval = CompareField( p1, p2, fieldname, iSortOrder ); + + return retval; +} + +static char g_fieldname[ 256 ]; +int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) +{ + CHudServers::server_t *list1, *list2; + + list1 = *(CHudServers::server_t **)elem1; + list2 = *(CHudServers::server_t **)elem2; + + return ServerListCompareFunc( list1, list2, g_fieldname ); +} + +void CHudServers::SortServers( const char *fieldname ) +{ + server_t *p; + // Create a list + if ( !m_pServers ) + return; + + strcpy( g_fieldname, fieldname ); + + int i; + int c = 0; + + p = m_pServers; + while ( p ) + { + c++; + p = p->next; + } + + server_t **pSortArray; + + pSortArray = new server_t *[ c ]; + memset( pSortArray, 0, c * sizeof( server_t * ) ); + + // Now copy the list into the pSortArray: + p = m_pServers; + i = 0; + while ( p ) + { + pSortArray[ i++ ] = p; + p = p->next; + } + + // Now do that actual sorting. + size_t nCount = c; + size_t nSize = sizeof( server_t * ); + + qsort( + pSortArray, + (size_t)nCount, + (size_t)nSize, + FnServerCompare + ); + + // Now rebuild the list. + m_pServers = pSortArray[0]; + for ( i = 0; i < c - 1; i++ ) + { + pSortArray[ i ]->next = pSortArray[ i + 1 ]; + } + pSortArray[ c - 1 ]->next = NULL; + + // Clean Up. + delete[] pSortArray; +} + +/* +=================== +GetServer + +Return particular server +=================== +*/ +CHudServers::server_t *CHudServers::GetServer( int server ) +{ + int c = 0; + server_t *p; + + p = m_pServers; + while ( p ) + { + if ( c == server ) + return p; + + c++; + p = p->next; + } + return NULL; +} + +/* +=================== +GetServerInfo + +Return info ( key/value ) string for particular server +=================== +*/ +char *CHudServers::GetServerInfo( int server ) +{ + server_t *p = GetServer( server ); + if ( p ) + { + return p->info; + } + return NULL; +} + +/* +=================== +CancelRequest + +Kill all pending requests in engine +=================== +*/ +void CHudServers::CancelRequest( void ) +{ + m_nRequesting = 0; + m_nQuerying = 0; + m_nDone = 1; + + NET_API->CancelAllRequests(); +} + +/* +================== +LoadMasterAddresses + +Loads the master server addresses from file and into the passed in array +================== +*/ +int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) +{ + int i; + char szMaster[ 256 ]; + char szMasterFile[256]; + char *pbuffer = NULL; + char *pstart = NULL ; + netadr_t adr; + char szAdr[64]; + int nPort; + int nCount = 0; + bool bIgnore; + int nDefaultPort; + + // Assume default master and master file + strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + strcpy( szMasterFile, MASTER_PARSE_FILE ); + + // See if there is a command line override + i = gEngfuncs.CheckParm( "-comm", &pstart ); + if ( i && pstart ) + { + strcpy (szMasterFile, pstart ); + } + + // Read them in from proper file + pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc + if ( !pbuffer ) + { + goto finish_master; + } + + pstart = pbuffer; + + while ( nCount < maxservers ) + { + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if ( strlen(m_szToken) <= 0) + break; + + bIgnore = true; + + if ( !stricmp( m_szToken, "Master" ) ) + { + nDefaultPort = PORT_MASTER; + bIgnore = FALSE; + } + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + if ( strlen(m_szToken) <= 0 ) + break; + + if ( stricmp ( m_szToken, "{" ) ) + break; + + // Parse addresses until we get to "}" + while ( nCount < maxservers ) + { + char base[256]; + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( !stricmp ( m_szToken, "}" ) ) + break; + + sprintf( base, "%s", m_szToken ); + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( stricmp( m_szToken, ":" ) ) + break; + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + nPort = atoi ( m_szToken ); + if ( !nPort ) + nPort = nDefaultPort; + + sprintf( szAdr, "%s:%i", base, nPort ); + + // Can we resolve it any better + if ( !NET_API->StringToAdr( szAdr, &adr ) ) + bIgnore = true; + + if ( !bIgnore ) + { + padr[ nCount++ ] = adr; + } + } + } + +finish_master: + if ( !nCount ) + { + sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + + // Convert to netadr_t + if ( NET_API->StringToAdr ( szMaster, &adr ) ) + { + + padr[ nCount++ ] = adr; + } + } + + *count = nCount; + + if ( pbuffer ) + { + gEngfuncs.COM_FreeFile( pbuffer ); + } + + return ( nCount > 0 ) ? 1 : 0; +} + +/* +=================== +RequestList + +Request list of game servers from master +=================== +*/ +void CHudServers::RequestList( void ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + int count = 0; + netadr_t adr; + + if ( !LoadMasterAddresses( 1, &count, &adr ) ) + { + gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); + return; + } + + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Kill off left overs if any + NET_API->CancelAllRequests(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); +} + +void CHudServers::RequestBroadcastList( int clearpending ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + netadr_t adr; + memset( &adr, 0, sizeof( adr ) ); + + if ( clearpending ) + { + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + } + + // Make sure to byte swap server if necessary ( using "host" to "net" conversion + adr.port = htons( PORT_SERVER ); + + // Make sure networking system has started. + NET_API->InitNetworking(); + + if ( clearpending ) + { + // Kill off left overs if any + NET_API->CancelAllRequests(); + } + + adr.type = NA_BROADCAST; + + // Request Servers from LAN via IP + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); + + adr.type = NA_BROADCAST_IPX; + + // Request Servers from LAN via IPX ( if supported ) + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); +} + +void CHudServers::ServerPing( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); +} + +void CHudServers::ServerRules( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); +} + +void CHudServers::ServerPlayers( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); +} + +int CHudServers::isQuerying() +{ + return m_nRequesting ? 1 : 0; +} + + +/* +=================== +GetServerCount + +Return number of servers in browser list +=================== +*/ +int CHudServers::GetServerCount( void ) +{ + return m_nServerCount; +} + +/* +=================== +CHudServers + +=================== +*/ +CHudServers::CHudServers( void ) +{ + m_nRequesting = 0; + m_dStarted = 0.0; + m_nDone = 0; + m_pServerList = NULL; + m_pServers = NULL; + m_pActiveList = NULL; + m_nQuerying = 0; + m_nActiveQueries = 0; + + m_fElapsed = 0.0; + + + m_pPingRequest = NULL; + m_pRulesRequest = NULL; + m_pPlayersRequest = NULL; +} + +/* +=================== +~CHudServers + +=================== +*/ +CHudServers::~CHudServers( void ) +{ + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + if ( m_pPingRequest ) + { + delete m_pPingRequest; + m_pPingRequest = NULL; + + } + + if ( m_pRulesRequest ) + { + delete m_pRulesRequest; + m_pRulesRequest = NULL; + } + + if ( m_pPlayersRequest ) + { + delete m_pPlayersRequest; + m_pPlayersRequest = NULL; + } +} + +/////////////////////////////// +// +// PUBLIC APIs +// +/////////////////////////////// + +/* +=================== +ServersGetCount + +=================== +*/ +int ServersGetCount( void ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerCount(); + } + return 0; +} + +int ServersIsQuerying( void ) +{ + if ( g_pServers ) + { + return g_pServers->isQuerying(); + } + return 0; +} + +/* +=================== +ServersGetInfo + +=================== +*/ +const char *ServersGetInfo( int server ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerInfo( server ); + } + + return NULL; +} + +void SortServers( const char *fieldname ) +{ + if ( g_pServers ) + { + g_pServers->SortServers( fieldname ); + } +} + +/* +=================== +ServersShutdown + +=================== +*/ +void ServersShutdown( void ) +{ + if ( g_pServers ) + { + delete g_pServers; + g_pServers = NULL; + } +} + +/* +=================== +ServersInit + +=================== +*/ +void ServersInit( void ) +{ + // Kill any previous instance + ServersShutdown(); + + g_pServers = new CHudServers(); +} + +/* +=================== +ServersThink + +=================== +*/ +void ServersThink( double time ) +{ + if ( g_pServers ) + { + g_pServers->Think( time ); + } +} + +/* +=================== +ServersCancel + +=================== +*/ +void ServersCancel( void ) +{ + if ( g_pServers ) + { + g_pServers->CancelRequest(); + } +} + +// Requests +/* +=================== +ServersList + +=================== +*/ +void ServersList( void ) +{ + if ( g_pServers ) + { + g_pServers->RequestList(); + } +} + +void BroadcastServersList( int clearpending ) +{ + if ( g_pServers ) + { + g_pServers->RequestBroadcastList( clearpending ); + } +} + +void ServerPing( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPing( server ); + } +} + +void ServerRules( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerRules( server ); + } +} + +void ServerPlayers( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPlayers( server ); + } +} diff --git a/main/source/cl_dll/hud_servers.h b/main/source/cl_dll/hud_servers.h index cb8a725b..577b5551 100644 --- a/main/source/cl_dll/hud_servers.h +++ b/main/source/cl_dll/hud_servers.h @@ -1,34 +1,34 @@ -#if !defined( HUD_SERVERSH ) -#define HUD_SERVERSH -#pragma once - -#define NET_CALLBACK /* */ - -// Dispatchers -void NET_CALLBACK ListResponse( struct net_response_s *response ); -void NET_CALLBACK ServerResponse( struct net_response_s *response ); -void NET_CALLBACK PingResponse( struct net_response_s *response ); -void NET_CALLBACK RulesResponse( struct net_response_s *response ); -void NET_CALLBACK PlayersResponse( struct net_response_s *response ); - -void ServersInit( void ); -void ServersShutdown( void ); -void ServersThink( double time ); -void ServersCancel( void ); - -// Get list and get server info from each -void ServersList( void ); - -// Query for IP / IPX LAN servers -void BroadcastServersList( int clearpending ); - -void ServerPing( int server ); -void ServerRules( int server ); -void ServerPlayers( int server ); - -int ServersGetCount( void ); -const char *ServersGetInfo( int server ); -int ServersIsQuerying( void ); -void SortServers( const char *fieldname ); - +#if !defined( HUD_SERVERSH ) +#define HUD_SERVERSH +#pragma once + +#define NET_CALLBACK /* */ + +// Dispatchers +void NET_CALLBACK ListResponse( struct net_response_s *response ); +void NET_CALLBACK ServerResponse( struct net_response_s *response ); +void NET_CALLBACK PingResponse( struct net_response_s *response ); +void NET_CALLBACK RulesResponse( struct net_response_s *response ); +void NET_CALLBACK PlayersResponse( struct net_response_s *response ); + +void ServersInit( void ); +void ServersShutdown( void ); +void ServersThink( double time ); +void ServersCancel( void ); + +// Get list and get server info from each +void ServersList( void ); + +// Query for IP / IPX LAN servers +void BroadcastServersList( int clearpending ); + +void ServerPing( int server ); +void ServerRules( int server ); +void ServerPlayers( int server ); + +int ServersGetCount( void ); +const char *ServersGetInfo( int server ); +int ServersIsQuerying( void ); +void SortServers( const char *fieldname ); + #endif // HUD_SERVERSH \ No newline at end of file diff --git a/main/source/cl_dll/hud_servers_priv.h b/main/source/cl_dll/hud_servers_priv.h index ed71367d..0fb41c13 100644 --- a/main/source/cl_dll/hud_servers_priv.h +++ b/main/source/cl_dll/hud_servers_priv.h @@ -1,91 +1,91 @@ -#if !defined( HUD_SERVERS_PRIVH ) -#define HUD_SERVERS_PRIVH -#pragma once - -#include "common/netadr.h" - -class CHudServers -{ -public: - typedef struct request_s - { - struct request_s *next; - netadr_t remote_address; - int context; - } request_t; - - typedef struct server_s - { - struct server_s *next; - netadr_t remote_address; - char *info; - int ping; - } server_t; - - CHudServers(); - ~CHudServers(); - - void Think( double time ); - void QueryThink( void ); - int isQuerying( void ); - - int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); - - void RequestList( void ); - void RequestBroadcastList( int clearpending ); - - void ServerPing( int server ); - void ServerRules( int server ); - void ServerPlayers( int server ); - - void CancelRequest( void ); - - int CompareServers( server_t *p1, server_t *p2 ); - - void ClearServerList( server_t **ppList ); - void ClearRequestList( request_t **ppList ); - - void AddServer( server_t **ppList, server_t *p ); - - void RemoveServerFromList( request_t **ppList, request_t *item ); - - request_t *FindRequest( int context, request_t *pList ); - - int ServerListSize( void ); - char *GetServerInfo( int server ); - int GetServerCount( void ); - void SortServers( const char *fieldname ); - - void ListResponse( struct net_response_s *response ); - void ServerResponse( struct net_response_s *response ); - void PingResponse( struct net_response_s *response ); - void RulesResponse( struct net_response_s *response ); - void PlayersResponse( struct net_response_s *response ); -private: - - server_t *GetServer( int server ); - - // - char m_szToken[ 1024 ]; - int m_nRequesting; - int m_nDone; - - double m_dStarted; - - request_t *m_pServerList; - request_t *m_pActiveList; - - server_t *m_pServers; - - int m_nServerCount; - - int m_nActiveQueries; - int m_nQuerying; - double m_fElapsed; - - request_t *m_pPingRequest; - request_t *m_pRulesRequest; - request_t *m_pPlayersRequest; -}; - +#if !defined( HUD_SERVERS_PRIVH ) +#define HUD_SERVERS_PRIVH +#pragma once + +#include "common/netadr.h" + +class CHudServers +{ +public: + typedef struct request_s + { + struct request_s *next; + netadr_t remote_address; + int context; + } request_t; + + typedef struct server_s + { + struct server_s *next; + netadr_t remote_address; + char *info; + int ping; + } server_t; + + CHudServers(); + ~CHudServers(); + + void Think( double time ); + void QueryThink( void ); + int isQuerying( void ); + + int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); + + void RequestList( void ); + void RequestBroadcastList( int clearpending ); + + void ServerPing( int server ); + void ServerRules( int server ); + void ServerPlayers( int server ); + + void CancelRequest( void ); + + int CompareServers( server_t *p1, server_t *p2 ); + + void ClearServerList( server_t **ppList ); + void ClearRequestList( request_t **ppList ); + + void AddServer( server_t **ppList, server_t *p ); + + void RemoveServerFromList( request_t **ppList, request_t *item ); + + request_t *FindRequest( int context, request_t *pList ); + + int ServerListSize( void ); + char *GetServerInfo( int server ); + int GetServerCount( void ); + void SortServers( const char *fieldname ); + + void ListResponse( struct net_response_s *response ); + void ServerResponse( struct net_response_s *response ); + void PingResponse( struct net_response_s *response ); + void RulesResponse( struct net_response_s *response ); + void PlayersResponse( struct net_response_s *response ); +private: + + server_t *GetServer( int server ); + + // + char m_szToken[ 1024 ]; + int m_nRequesting; + int m_nDone; + + double m_dStarted; + + request_t *m_pServerList; + request_t *m_pActiveList; + + server_t *m_pServers; + + int m_nServerCount; + + int m_nActiveQueries; + int m_nQuerying; + double m_fElapsed; + + request_t *m_pPingRequest; + request_t *m_pRulesRequest; + request_t *m_pPlayersRequest; +}; + #endif // HUD_SERVERS_PRIVH \ No newline at end of file diff --git a/main/source/cl_dll/hud_spectator.cpp b/main/source/cl_dll/hud_spectator.cpp index 5ce8fb4f..391a0657 100644 --- a/main/source/cl_dll/hud_spectator.cpp +++ b/main/source/cl_dll/hud_spectator.cpp @@ -1,1953 +1,1953 @@ -//========= Copyright � 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" -#include "common/cl_entity.h" -#include "common/triangleapi.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_SpectatorPanel.h" -#include "common/hltv.h" - -#include "pm_shared/pm_shared.h" -#include "pm_shared/pm_defs.h" -#include "common/pmtrace.h" -#include "common/entity_types.h" - -// these are included for the math functions -#include "common/com_model.h" -#include "common/demo_api.h" -#include "common/event_api.h" -#include "studio_util.h" -#include "common/screenfade.h" -#include "util/STLUtil.h" -#include "mod/AvHTitles.h" -#include "mod/AvHSprites.h" - -#pragma warning(disable: 4244) - -extern int iJumpSpectator; -extern float vJumpOrigin[3]; -extern float vJumpAngles[3]; - -extern void V_GetInEyePos(int entity, float * origin, float * angles ); -extern void V_ResetChaseCam(); -extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); -extern void VectorAngles( const float *forward, float *angles ); -extern "C" void NormalizeAngles( float *angles ); -extern float * GetClientColor( int clientIndex ); - -extern vec3_t v_origin; // last view origin -extern vec3_t v_angles; // last view angle -extern vec3_t v_cl_angles; // last client/mouse angle -extern vec3_t v_sim_org; // last sim origin - -void SpectatorMode(void) -{ - - if ( gEngfuncs.Cmd_Argc() <= 1 ) - { - gEngfuncs.Con_Printf( "usage: spec_mode \n" ); - return; - } - - // SetModes() will decide if command is executed on server or local - if ( gEngfuncs.Cmd_Argc() == 2 ) - gHUD.m_Spectator.SetMode( atoi( gEngfuncs.Cmd_Argv(1) )); - - //else if ( gEngfuncs.Cmd_Argc() == 3 ) - // gHUD.m_Spectator.SetMode( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); -} - -void SpectatorSpray(void) -{ - vec3_t forward; - char string[128]; - - if ( !gEngfuncs.IsSpectateOnly() ) - return; - - AngleVectors(v_angles,forward,NULL,NULL); - VectorScale(forward, 128, forward); - VectorAdd(forward, v_origin, forward); - pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); - if ( trace->fraction != 1.0 ) - { - sprintf(string, "drc_spray %.2f %.2f %.2f %i", - trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); - gEngfuncs.pfnServerCmd(string); - } - -} -void SpectatorHelp(void) -{ - if ( gViewPort ) - { - gViewPort->ShowVGUIMenu( MENU_SPECHELP ); - } - else - { - char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); - - if ( text ) - { - while ( *text ) - { - if ( *text != 13 ) - gEngfuncs.Con_Printf( "%c", *text ); - text++; - } - } - } -} - -void SpectatorMenu( void ) -{ - if ( gEngfuncs.Cmd_Argc() <= 1 ) - { - gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); - return; - } - - gViewPort->m_pSpectatorPanel->ShowMenu( atoi( gEngfuncs.Cmd_Argv(1))!=0 ); -} - -void ToggleScores( void ) -{ - if ( gViewPort ) - { - if (gViewPort->IsScoreBoardVisible() ) - { - gViewPort->HideScoreBoard(); - } - else - { - gViewPort->ShowScoreBoard(); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CHudSpectator::Init() -{ - gHUD.AddHudElem(this); - - m_iFlags |= HUD_ACTIVE; - m_flNextObserverInput = 0.0f; - m_zoomDelta = 0.0f; - m_moveDelta = 0.0f; - iJumpSpectator = 0; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - m_lastPrimaryObject = m_lastSecondaryObject = 0; - - gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); - gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); - gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); - gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); - gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); - - m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); - m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); - m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); - m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); - - // Removed by mmcguire. - m_overviewMode = false; - //m_overview = gEngfuncs.pfnRegisterVariable("spec_overview","1",0); - //m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); - - if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector /*|| !m_pip*/) - { - gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); - return 0; - } - - return 1; -} - - -//----------------------------------------------------------------------------- -// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed -//----------------------------------------------------------------------------- - -void UTIL_StringToVector( float * pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - if (j < 2) - { - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - -int UTIL_FindEntityInMap(char * name, float * origin, float * angle) -{ - int n,found = 0; - char keyname[256]; - char token[1024]; - - cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model - - if ( !pEnt ) return 0; - - if ( !pEnt->model ) return 0; - - char * data = pEnt->model->entities; - - while (data) - { - data = gEngfuncs.COM_ParseFile(data, token); - - if ( (token[0] == '}') || (token[0]==0) ) - break; - - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - } - - if (token[0] != '{') - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); - return 0; - } - - // we parse the first { now parse entities properties - - while ( 1 ) - { - // parse key - data = gEngfuncs.COM_ParseFile(data, token); - if (token[0] == '}') - break; // finish parsing this entity - - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - strcpy (keyname, token); - - // another hack to fix keynames with trailing spaces - n = (int)strlen(keyname); - while (n && keyname[n-1] == ' ') - { - keyname[n-1] = 0; - n--; - } - - // parse value - data = gEngfuncs.COM_ParseFile(data, token); - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - if (token[0] == '}') - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); - return 0; - } - - if (!strcmp(keyname,"classname")) - { - if (!strcmp(token, name )) - { - found = 1; // thats our entity - } - }; - - if( !strcmp( keyname, "angle" ) ) - { - float y = atof( token ); - - if (y >= 0) - { - angle[0] = 0.0f; - angle[1] = y; - } - else if ((int)y == -1) - { - angle[0] = -90.0f; - angle[1] = 0.0f;; - } - else - { - angle[0] = 90.0f; - angle[1] = 0.0f; - } - - angle[2] = 0.0f; - } - - if( !strcmp( keyname, "angles" ) ) - { - UTIL_StringToVector(angle, token); - } - - if (!strcmp(keyname,"origin")) - { - UTIL_StringToVector(origin, token); - - }; - - } // while (1) - - if (found) - return 1; - - } - - return 0; // we search all entities, but didn't found the correct - -} - -//----------------------------------------------------------------------------- -// SetSpectatorStartPosition(): -// Get valid map position and 'beam' spectator to this position -//----------------------------------------------------------------------------- - -void CHudSpectator::SetSpectatorStartPosition() -{ - // search for info_player start - if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - else - { - // jump to 0,0,0 if no better position was found - VectorCopy(vec3_origin, m_cameraOrigin); - VectorCopy(vec3_origin, m_cameraAngles); - } - - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); - - iJumpSpectator = 1; // jump anyway -} - -//----------------------------------------------------------------------------- -// Purpose: Loads new icons -//----------------------------------------------------------------------------- -int CHudSpectator::VidInit() -{ - m_hsprPlayerMarine = SPR_Load("sprites/iplayerm.spr"); - m_hsprPlayerAlien = SPR_Load("sprites/iplayera.spr"); - m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); - m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); - //m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); - //m_hsprCamera = SPR_Load("sprites/camera.spr"); - m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); - m_hsprWhite = SPR_Load(kWhiteSprite); - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flTime - -// intermission - -//----------------------------------------------------------------------------- -int CHudSpectator::Draw(float flTime) -{ - - // draw only in spectator mode - if ( !g_iUser1 ) - return 0; -// string error; -// gHUD.Update( flTime, error); - - // Removed by mmcguire. - /* - // if user pressed zoom, aplly changes - if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) - { - m_mapZoom += m_zoomDelta; - - if ( m_mapZoom > 3.0f ) - m_mapZoom = 3.0f; - - if ( m_mapZoom < 0.5f ) - m_mapZoom = 0.5f; - } - - // if user moves in map mode, change map origin - if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) - { - vec3_t right; - AngleVectors(v_angles, NULL, right, NULL); - VectorNormalize(right); - VectorScale(right, m_moveDelta, right ); - - VectorAdd( m_mapOrigin, right, m_mapOrigin ) - - } - */ - - //DrawOverviewMap(); - -/* - if (!IsInOverviewMode()) - { - return 0; - } - - if (m_hsprWhite != NULL) - { - - float bgColor[] = { 0.1, 0.1, 0.1, 1 }; - float borderColor[] = { 1, 1, 1, 1 }; - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - - float gammaScale = 1.0f / gHUD.GetGammaSlope(); - - // Draw the border on the overview map and the inset view. - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - gEngfuncs.pTriAPI->Color4f(gammaScale * borderColor[0], gammaScale * borderColor[1], gammaScale * borderColor[2], borderColor[3]); - - gEngfuncs.pTriAPI->Begin(TRI_LINES); - - int insetX1 = XRES(m_OverviewData.insetWindowX); - int insetY1 = YRES(m_OverviewData.insetWindowY); - int insetX2 = insetX1 + XRES(m_OverviewData.insetWindowWidth); - int insetY2 = insetY1 + YRES(m_OverviewData.insetWindowHeight); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - - gEngfuncs.pTriAPI->End(); - - }*/ - - - - /* - // Only draw the icon names only if map mode is in Main Mode - if ( g_iUser1 < OBS_MAP_FREE ) - return 1; - - if ( !m_drawnames->value ) - return 1; - - // make sure we have player info - gViewPort->GetAllPlayersInfo(); - */ - - return 1; - -} - -bool CHudSpectator::IsInOverviewMode() const -{ - return g_iUser1 && m_overviewMode && gHUD.GetIsNSMode(); -} - -void CHudSpectator::SetOverviewMode(bool overviewMode) -{ - m_overviewMode = overviewMode; -} - -void CHudSpectator::DrawOverviewMap() -{ - - // draw only in spectator mode - if (!IsInOverviewMode()) - { - return; - } - - AvHOverviewMap& theOverviewMap = gHUD.GetOverviewMap(); - - AvHOverviewMap::DrawInfo theDrawInfo; - - theDrawInfo.mX = XRES(m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth + 4); - theDrawInfo.mY = YRES(SPECTATOR_PANEL_HEIGHT + 4); - theDrawInfo.mWidth = ScreenWidth() - theDrawInfo.mX - XRES(4); - theDrawInfo.mHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theDrawInfo.mY; - theDrawInfo.mZoomScale = 1.0f; - AvHMapExtents theMapExtents; - theOverviewMap.GetMapExtents(theMapExtents); - - theDrawInfo.mFullScreen = true; - - float worldWidth = theMapExtents.GetMaxMapX() - theMapExtents.GetMinMapX(); - float worldHeight = theMapExtents.GetMaxMapY() - theMapExtents.GetMinMapY(); - - float xScale; - float yScale; - - float aspect1 = worldWidth / worldHeight; - float aspect2 = ((float)theDrawInfo.mWidth) / theDrawInfo.mHeight; - - if (aspect1 > aspect2) - { - xScale = 1; - yScale = 1 / aspect2; - } - else - { - xScale = aspect2; - yScale = 1; - } - - float centerX = (theMapExtents.GetMinMapX() + theMapExtents.GetMaxMapX()) / 2; - float centerY = (theMapExtents.GetMinMapY() + theMapExtents.GetMaxMapY()) / 2; - - theDrawInfo.mViewWorldMinX = centerX - worldWidth * xScale * 0.5; - theDrawInfo.mViewWorldMinY = centerY - worldHeight * yScale * 0.5; - theDrawInfo.mViewWorldMaxX = centerX + worldWidth * xScale * 0.5; - theDrawInfo.mViewWorldMaxY = centerY + worldHeight * yScale * 0.5; - - if (m_hsprWhite != NULL) - { - - float bgColor[] = { 0.1, 0.1, 0.1, 1 }; - float borderColor[] = { 1, 1, 1, 1 }; - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - float gammaScale = 1.0f / gHUD.GetGammaSlope(); - - // Draw the background. - - gEngfuncs.pTriAPI->Color4f(gammaScale * bgColor[0], gammaScale * bgColor[1], gammaScale * bgColor[2], bgColor[3]); - - gEngfuncs.pTriAPI->Begin(TRI_QUADS); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); - - gEngfuncs.pTriAPI->End(); - - // Draw the overview map. - - theOverviewMap.Draw(theDrawInfo); - - // Draw the border on the overview map and the inset view. - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - gEngfuncs.pTriAPI->Color4f(gammaScale * borderColor[0], gammaScale * borderColor[1], gammaScale * borderColor[2], borderColor[3]); - - gEngfuncs.pTriAPI->Begin(TRI_LINES); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); - - int insetX1 = XRES(m_OverviewData.insetWindowX); - int insetY1 = YRES(m_OverviewData.insetWindowY); - int insetX2 = insetX1 + XRES(m_OverviewData.insetWindowWidth); - int insetY2 = insetY1 + YRES(m_OverviewData.insetWindowHeight); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - - gEngfuncs.pTriAPI->End(); - - } - - -} - -#include "parsemsg.h" -void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) -{ - float value; - char * string; - - BEGIN_READ( pbuf, iSize ); - - int cmd = READ_BYTE(); - - switch ( cmd ) // director command byte - { - case DRC_CMD_START : - // now we have to do some things clientside, since the proxy doesn't know our mod - g_iPlayerClass = 0; - g_iTeamNumber = 0; - - // fake a InitHUD & ResetHUD message - gHUD.MsgFunc_InitHUD(NULL,0, NULL); - gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); - - break; - - case DRC_CMD_EVENT : - m_lastPrimaryObject = READ_WORD(); - m_lastSecondaryObject = READ_WORD(); - m_iObserverFlags = READ_LONG(); - - if ( m_autoDirector->value ) - { - if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) - V_ResetChaseCam(); - - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } - - break; - - case DRC_CMD_MODE : - if ( m_autoDirector->value ) - { - SetMode( READ_BYTE()); - } - break; - - case DRC_CMD_CAMERA : - if ( m_autoDirector->value ) - { - vJumpOrigin[0] = READ_COORD(); // position - vJumpOrigin[1] = READ_COORD(); - vJumpOrigin[2] = READ_COORD(); - - vJumpAngles[0] = READ_COORD(); // view angle - vJumpAngles[1] = READ_COORD(); - vJumpAngles[2] = READ_COORD(); - - gEngfuncs.SetViewAngles( vJumpAngles ); - - iJumpSpectator = 1; - } - break; - - case DRC_CMD_MESSAGE: - { - client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; - - msg->effect = READ_BYTE(); // effect - - UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color - msg->r2 = msg->r1; - msg->g2 = msg->g1; - msg->b2 = msg->b1; - msg->a2 = msg->a1 = 0xFF; // not transparent - - msg->x = READ_FLOAT(); // x pos - msg->y = READ_FLOAT(); // y pos - - msg->fadein = READ_FLOAT(); // fadein - msg->fadeout = READ_FLOAT(); // fadeout - msg->holdtime = READ_FLOAT(); // holdtime - msg->fxtime = READ_FLOAT(); // fxtime; - - strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); - m_HUDMessageText[m_lastHudMessage][127]=0; // text - - msg->pMessage = m_HUDMessageText[m_lastHudMessage]; - msg->pName = "HUD_MESSAGE"; - - gHUD.m_Message.MessageAdd( msg->pName, gHUD.m_flTime); - - m_lastHudMessage++; - m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; - - } - - break; - - case DRC_CMD_SOUND : - string = READ_STRING(); - value = READ_FLOAT(); - - gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); - - break; - - case DRC_CMD_TIMESCALE : - value = READ_FLOAT(); - break; - - - - case DRC_CMD_STATUS: - READ_LONG(); // total number of spectator slots - m_iSpectatorNumber = READ_LONG(); // total number of spectator - READ_WORD(); // total number of relay proxies - - gViewPort->UpdateSpectatorPanel(); - break; - - case DRC_CMD_BANNER: - // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga - gViewPort->m_pSpectatorPanel->m_TopBanner->LoadImage( READ_STRING() ); - gViewPort->UpdateSpectatorPanel(); - break; - - case DRC_CMD_FADE: - break; - - case DRC_CMD_STUFFTEXT: - ClientCmd( READ_STRING() ); - break; - - default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); - } -} - -void CHudSpectator::FindNextPlayer(bool bReverse) -{ - // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching - // only a subset of the players. e.g. Make it check the target's team. - - int iStart; - cl_entity_t * pEnt = NULL; - - // if we are NOT in HLTV mode, spectator targets are set on server - if ( !gEngfuncs.IsSpectateOnly() ) - { - char cmdstring[32]; - // forward command to server - sprintf(cmdstring,"follownext %i",bReverse?1:0); - gEngfuncs.pfnServerCmd(cmdstring); - return; - } - - if ( g_iUser2 ) - iStart = g_iUser2; - else - iStart = 1; - - g_iUser2 = 0; - - int iCurrent = iStart; - - int iDir = bReverse ? -1 : 1; - - // make sure we have player info - gViewPort->GetAllPlayersInfo(); - - - do - { - iCurrent += iDir; - - // Loop through the clients - if (iCurrent > MAX_PLAYERS) - iCurrent = 1; - if (iCurrent < 1) - iCurrent = MAX_PLAYERS; - - pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); - - if ( !IsActivePlayer( pEnt ) ) - continue; - - // MOD AUTHORS: Add checks on target here. - - g_iUser2 = iCurrent; - break; - - } while ( iCurrent != iStart ); - - // Did we find a target? - if ( !g_iUser2 ) - { - gEngfuncs.Con_DPrintf( "No observer targets.\n" ); - // take save camera position - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); - } - else - { - // use new entity position for roaming - VectorCopy ( pEnt->origin, vJumpOrigin ); - VectorCopy ( pEnt->angles, vJumpAngles ); - } - iJumpSpectator = 1; -} - -void CHudSpectator::HandleButtonsDown( int ButtonPressed ) -{ - if ( !gViewPort ) - return; - - //Not in intermission. - if ( gHUD.m_iIntermission ) - return; - - if ( !g_iUser1 ) - return; // dont do anything if not in spectator mode - - // don't handle buttons during normal demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) - return; - - int theNewMainMode = g_iUser1; - - // Jump changes main window modes - if ( ButtonPressed & IN_JUMP ) - { - bool theFirstPerson = (g_iUser1 == OBS_IN_EYE); - bool theInOverviewMode = gHUD.m_Spectator.IsInOverviewMode(); - - // NS - if(gHUD.GetIsNSMode()) - { - // First-person full -> chase camera full -> firstperson with overview -> chase camera with overview - if(theFirstPerson && !theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - //gHUD.m_Spectator.SetOverviewMode(false); - } - else if(!theFirstPerson && !theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(true); - } - else if(theFirstPerson && theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - //gHUD.m_Spectator.SetOverviewMode(true); - } - else if(!theFirstPerson && theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(false); - } - } - // Combat - else - { - // First-person full -> chase camera full - if(theFirstPerson) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - gHUD.m_Spectator.SetOverviewMode(false); - } - else - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(false); - } - } - } - - //g_iUser1 = theNewMainMode; - - // Attack moves to the next player - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) - { - FindNextPlayer( (ButtonPressed & IN_MOVELEFT) ? true:false ); - -// if ( g_iUser1 == OBS_ROAMING ) -// { -// gEngfuncs.SetViewAngles( vJumpAngles ); -// iJumpSpectator = 1; -// -// } - - // lease directed mode if player want to see another player - m_autoDirector->value = 0.0f; - } - -/* - double time = gEngfuncs.GetClientTime(); - - int newMainMode = g_iUser1; - int newInsetMode = m_pip->value; - - // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); - if ( !gViewPort ) - return; - - //Not in intermission. - if ( gHUD.m_iIntermission ) - return; - - if ( !g_iUser1 ) - return; // dont do anything if not in spectator mode - - // don't handle buttons during normal demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) - return; - // Slow down mouse clicks. - if ( m_flNextObserverInput > time ) - return; - - // enable spectator screen - if ( ButtonPressed & IN_DUCK ) - { - gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); - } - - // 'Use' changes inset window mode - if ( ButtonPressed & IN_USE ) - { - newInsetMode = ToggleInset(true); - } - - // if not in HLTV mode, buttons are handled server side - if ( gEngfuncs.IsSpectateOnly() ) - { - // changing target or chase mode not in overviewmode without inset window - - // Jump changes main window modes - if ( ButtonPressed & IN_JUMP ) - { - if ( g_iUser1 == OBS_CHASE_LOCKED ) - newMainMode = OBS_CHASE_FREE; - - else if ( g_iUser1 == OBS_CHASE_FREE ) - newMainMode = OBS_IN_EYE; - - else if ( g_iUser1 == OBS_IN_EYE ) - newMainMode = OBS_ROAMING; - - else if ( g_iUser1 == OBS_ROAMING ) - newMainMode = OBS_MAP_FREE; - - else if ( g_iUser1 == OBS_MAP_FREE ) - newMainMode = OBS_MAP_CHASE; - - else - newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore - } - - // Attack moves to the next player - if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) - { - FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); - - if ( g_iUser1 == OBS_ROAMING ) - { - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - - } - // lease directed mode if player want to see another player - m_autoDirector->value = 0.0f; - } - } - - SetModes(newMainMode, newInsetMode); - - if ( g_iUser1 == OBS_MAP_FREE ) - { - if ( ButtonPressed & IN_FORWARD ) - m_zoomDelta = 0.01f; - - if ( ButtonPressed & IN_BACK ) - m_zoomDelta = -0.01f; - - if ( ButtonPressed & IN_MOVELEFT ) - m_moveDelta = -12.0f; - - if ( ButtonPressed & IN_MOVERIGHT ) - m_moveDelta = 12.0f; - } - - m_flNextObserverInput = time + 0.2; -*/ - -} - -void CHudSpectator::HandleButtonsUp( int ButtonPressed ) -{ - if ( !gViewPort ) - return; - - if ( !gViewPort->m_pSpectatorPanel->isVisible() ) - return; // dont do anything if not in spectator mode - - if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) - m_zoomDelta = 0.0f; - - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) - m_moveDelta = 0.0f; -} - -void CHudSpectator::SetMode(int iNewMainMode) -{ - // if value == -1 keep old value - if ( iNewMainMode == -1 ) - iNewMainMode = g_iUser1; - - // main modes ettings will override inset window settings - if ( iNewMainMode != g_iUser1 ) - { - // if we are NOT in HLTV mode, main spectator mode is set on server - if ( !gEngfuncs.IsSpectateOnly() ) - { - char cmdstring[32]; - // forward command to server - sprintf(cmdstring,"specmode %i",iNewMainMode ); - gEngfuncs.pfnServerCmd(cmdstring); - return; - } - else - { - if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target - { - // choose last Director object if still available - if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) - { - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } - else - { - FindNextPlayer(false); // find any target - } - } - - switch ( iNewMainMode ) - { - case OBS_CHASE_LOCKED: - g_iUser1 = OBS_CHASE_LOCKED; - break; - - case OBS_CHASE_FREE: - g_iUser1 = OBS_CHASE_FREE; - break; - - case OBS_ROAMING : // jump to current vJumpOrigin/angle - g_iUser1 = OBS_ROAMING; - if ( g_iUser2 ) - { - V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - } - break; - - case OBS_IN_EYE: - g_iUser1 = OBS_IN_EYE; - break; - - /* - case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - - case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - */ - } - - if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) - { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; - m_crosshairRect.bottom = 24; - - gHUD.SetCurrentCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); - } - else - { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); - gHUD.SetCurrentCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - //char string[128]; - //sprintf(string, "#Spec_Mode%d", g_iUser1 ); - //sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); - //gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); - } - } - - gViewPort->UpdateSpectatorPanel(); -} - -bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) -{ - return ( ent && - ent->player && - ent->curstate.solid != SOLID_NOT && - ent != gEngfuncs.GetLocalPlayer() && - g_PlayerInfoList[ent->index].name != NULL - ); -} - - -bool CHudSpectator::ParseOverviewFile( ) -{ - //char filename[255]; - //char levelname[255]; - //char token[1024]; - //float height; - - char *pfile = NULL; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - - // fill in standrd values - m_OverviewData.insetWindowX = 4; // upper left corner - m_OverviewData.insetWindowY = 4 + SPECTATOR_PANEL_HEIGHT; - m_OverviewData.insetWindowHeight = 180; - m_OverviewData.insetWindowWidth = 240; - m_OverviewData.origin[0] = 0.0f; - m_OverviewData.origin[1] = 0.0f; - m_OverviewData.origin[2] = 0.0f; - m_OverviewData.zoom = 1.0f; - m_OverviewData.layers = 0; - m_OverviewData.layersHeights[0] = 0.0f; - strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); - - if ( strlen( m_OverviewData.map ) == 0 ) - return false; // not active yet - - /* - strcpy(levelname, m_OverviewData.map + 5); - levelname[strlen(levelname)-4] = 0; - - sprintf(filename, "overviews/%s.txt", levelname ); - - pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); - - if (!pfile) - { - gEngfuncs.Con_Printf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); - return false; - } - - while (true) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - - if (!pfile) - break; - - if ( !stricmp( token, "global" ) ) - { - // parse the global data - pfile = gEngfuncs.COM_ParseFile(pfile, token); - if ( stricmp( token, "{" ) ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - while (stricmp( token, "}") ) - { - if ( !stricmp( token, "zoom" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.zoom = atof( token ); - } - else if ( !stricmp( token, "origin" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - m_OverviewData.origin[0] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.origin[1] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile, token); - m_OverviewData.origin[2] = atof( token ); - } - else if ( !stricmp( token, "rotated" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.rotated = atoi( token ); - } - else if ( !stricmp( token, "inset" ) ) - { - - // Removed by mmcguire. - // This isn't supported anymore. - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowX = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowY = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowWidth = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowHeight = atof( token ); - - } - else - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - - } - } - else if ( !stricmp( token, "layer" ) ) - { - // parse a layer data - - if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - - if ( stricmp( token, "{" ) ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - while (stricmp( token, "}") ) - { - if ( !stricmp( token, "image" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); - - - } - else if ( !stricmp( token, "height" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - height = atof(token); - m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; - } - else - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - } - - m_OverviewData.layers++; - - } - } - - gEngfuncs.COM_FreeFile( pfile ); - */ - - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - - return true; - -} - -void CHudSpectator::LoadMapSprites() -{ - // right now only support for one map layer - if (m_OverviewData.layers > 0 ) - { - m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); - } - else - m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead -} - -void CHudSpectator::DrawOverviewLayer() -{ - float screenaspect, xs, ys, xStep, yStep, x,y,z; - int ix,iy,i,xTiles,yTiles,frame; - - qboolean hasMapImage = m_MapSprite?TRUE:FALSE; - model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); - - if ( hasMapImage) - { - i = m_MapSprite->numframes / (4*3); - i = sqrt((float)i); - xTiles = i*4; - yTiles = i*3; - } - else - { - xTiles = 8; - yTiles = 6; - } - - - screenaspect = 4.0f/3.0f; - - - xs = m_OverviewData.origin[0]; - ys = m_OverviewData.origin[1]; - z = ( 90.0f - v_angles[0] ) / 90.0f; - z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; - - // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); - - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); - - frame = 0; - - - // rotated view ? - if ( m_OverviewData.rotated ) - { - xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; - - y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); - - for (iy = 0; iy < yTiles; iy++) - { - x = xs - (4096.0f / (m_OverviewData.zoom)); - - for (ix = 0; ix < xTiles; ix++) - { - if (hasMapImage) - gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); - else - gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); - gEngfuncs.pTriAPI->End(); - - frame++; - x+= xStep; - } - - y+=yStep; - } - } - else - { - xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; - - - x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); - - - - for (ix = 0; ix < yTiles; ix++) - { - - y = ys + (4096.0f / (m_OverviewData.zoom)); - - for (iy = 0; iy < xTiles; iy++) - { - if (hasMapImage) - gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); - else - gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); - gEngfuncs.pTriAPI->End(); - - frame++; - - y+=yStep; - } - - x+= xStep; - - } - } -} - -void CHudSpectator::DrawOverviewEntities() -{ - /* - int i,ir,ig,ib; - struct model_s *hSpriteModel; - vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; - float x,y,z, r,g,b, sizeScale = 4.0f; - cl_entity_t * ent; - float rmatrix[3][4]; // transformation matrix - - float zScale = (90.0f - v_angles[0] ) / 90.0f; - - - z = m_OverviewData.layersHeights[0] * zScale; - // get yellow/brown HUD color - //UnpackRGB(ir,ig,ib, RGB_YELLOWISH); - gHUD.GetPrimaryHudColor(ir, ig, ib); - r = (float)ir/255.0f; - g = (float)ig/255.0f; - b = (float)ib/255.0f; - - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - - for (i=0; i < MAX_PLAYERS; i++ ) - m_vPlayerPos[i][2] = -1; // mark as invisible - - // draw all players - - float depthOffset = 0; - - for (i=MAX_OVERVIEW_ENTITIES - 1; i >= 0; i--) - { - if ( !m_OverviewEntities[i].hSprite ) - continue; - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); - ent = m_OverviewEntities[i].entity; - - int theSpriteFrame = m_OverviewEntities[i].mFrame; - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, theSpriteFrame); - - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd); - - // see R_DrawSpriteModel - // draws players sprite - - AngleVectors(ent->angles, right, up, NULL ); - - VectorCopy(ent->origin,origin); - - // Set origin of blip to just above map height, so blips are all drawn on map - origin.z = m_OverviewData.layersHeights[0] + kOverviewEntityZHeight + depthOffset; - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - float gammaSlope = gHUD.GetGammaSlope(); - - gEngfuncs.pTriAPI->Color4f( - m_OverviewEntities[i].mColorR / gammaSlope, - m_OverviewEntities[i].mColorG / gammaSlope, - m_OverviewEntities[i].mColorB / gammaSlope, - 1); - - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (0,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (1,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->End (); - - - if ( !ent->player) - continue; - // draw line under player icons - origin[2] *= zScale; - - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); - - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); - - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); - - // calculate screen position for name and infromation in hud::draw() - if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) - continue; // object is behind viewer - - screen[0] = XPROJECT(screen[0]); - screen[1] = YPROJECT(screen[1]); - screen[2] = 0.0f; - - // calculate some offset under the icon - origin[0]+=32.0f; - origin[1]+=32.0f; - - gEngfuncs.pTriAPI->WorldToScreen(origin,offset); - - offset[0] = XPROJECT(offset[0]); - offset[1] = YPROJECT(offset[1]); - offset[2] = 0.0f; - - VectorSubtract(offset, screen, offset ); - - int playerNum = ent->index - 1; - - m_vPlayerPos[playerNum][0] = screen[0]; - m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); - m_vPlayerPos[playerNum][2] = 1; // mark player as visible - - - } - - if ( !m_pip || !m_drawcone->value ) - return; - - // get current camera position and angle - - if ( m_pip == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) - { - V_GetInEyePos( g_iUser2, origin, angles ); - } - else if ( m_pip == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) - { - V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); - } - else if ( g_iUser1 == OBS_ROAMING ) - { - VectorCopy( v_sim_org, origin ); - VectorCopy( v_cl_angles, angles ); - } - else - V_GetChasePos( g_iUser2, NULL, origin, angles ); - - - // draw camera sprite - - x = origin[0]; - y = origin[1]; - z = origin[2]; - - // Set origin of cone to just above map height, so blips are all drawn on map - z = m_OverviewData.layersHeights[0] + kOverviewEntityZHeight; - - angles[0] = 0; // always show horizontal camera sprite - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - - gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); - - AngleVectors(angles, forward, NULL, NULL ); - VectorScale (forward, 512.0f, forward); - - offset[0] = 0.0f; - offset[1] = 45.0f; - offset[2] = 0.0f; - - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , right ); - - offset[1]= -45.0f; - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , left ); - - gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); - gEngfuncs.pTriAPI->End (); - */ - -} - - - -void CHudSpectator::DrawOverview() -{ - /* - // draw only in sepctator mode - if ( !g_iUser1 ) - return; - - // Only draw the overview if Map Mode is selected for this view - if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) - return; - - if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) - return; - - DrawOverviewLayer(); - DrawOverviewEntities(); - CheckOverviewEntities(); - */ - -} - - - -void CHudSpectator::CheckOverviewEntities() -{ - double time = gEngfuncs.GetClientTime(); - - // removes old entities from list - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) - { - // remove entity from list if it is too old - if ( m_OverviewEntities[i].killTime < time ) - { - memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); - } - } -} - -bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) -{ - HSPRITE hSprite = 0; - double duration = -1.0f; // duration -1 means show it only this frame; - int theFrame = 0; - bool theSuccess = false; - int theRenderMode; - - if ( ent ) - { - - if (ent->curstate.solid != SOLID_NOT) - { - gHUD.GetSpriteForUser3(AvHUser3(ent->curstate.iuser3), hSprite, theFrame, theRenderMode); - } - - /* - if ( type == ET_PLAYER ) - { - if ( ent->curstate.solid != SOLID_NOT) - { - int thePlayerClass = g_PlayerExtraInfo[ent->index].playerclass; - switch(thePlayerClass) - { - case PLAYERCLASS_ALIVE_MARINE: - hSprite = this->m_hsprPlayerMarine; - theFrame = 0; - break; - case PLAYERCLASS_ALIVE_HEAVY_MARINE: - hSprite = this->m_hsprPlayerMarine; - theFrame = 1; - break; - case PLAYERCLASS_COMMANDER: - hSprite = this->m_hsprPlayerMarine; - theFrame = 2; - break; - case PLAYERCLASS_ALIVE_LEVEL1: - hSprite = this->m_hsprPlayerAlien; - theFrame = 0; - break; - case PLAYERCLASS_ALIVE_LEVEL2: - hSprite = this->m_hsprPlayerAlien; - theFrame = 1; - break; - case PLAYERCLASS_ALIVE_LEVEL3: - hSprite = this->m_hsprPlayerAlien; - theFrame = 2; - break; - case PLAYERCLASS_ALIVE_LEVEL4: - hSprite = this->m_hsprPlayerAlien; - theFrame = 3; - break; - case PLAYERCLASS_ALIVE_LEVEL5: - hSprite = this->m_hsprPlayerAlien; - theFrame = 4; - break; - case PLAYERCLASS_ALIVE_GESTATING: - hSprite = this->m_hsprPlayerAlien; - theFrame = 5; - break; - - case PLAYERCLASS_ALIVE_DIGESTING: - break; - } - } - else - { - // it's an spectator - } - } - else if (type == ET_NORMAL) - { - // Now help icons - if(hSprite == 0) - { - AvHUser3 theUser3 = AvHUser3(ent->curstate.iuser3); - theFrame = gHUD.GetHelpIconFrameFromUser3(theUser3); - if(theFrame != -1) - { - hSprite = gHUD.GetHelpSprite(); - } - } - } - */ - } - - if(hSprite > 0) - { - - int theTeam = ent->curstate.team; - - float theR = kFTeamColors[theTeam][0]; - float theG = kFTeamColors[theTeam][1]; - float theB = kFTeamColors[theTeam][2]; - - theSuccess = AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration, theFrame, theRenderMode, theR, theG, theB); - - } - - return theSuccess; -} - -void CHudSpectator::DeathMessage(int victim) -{ - // find out where the victim is - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); - - if (pl && pl->player) - AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f, 0, kRenderTransTexture, 1, 1, 1); -} - -bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime, int inFrame, int inRenderMode, float r, float g, float b) -{ - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) - { - // find empty entity slot - if ( m_OverviewEntities[i].entity == NULL) - { - m_OverviewEntities[i].entity = ent; - m_OverviewEntities[i].hSprite = sprite; - m_OverviewEntities[i].killTime = killTime; - m_OverviewEntities[i].mFrame = inFrame; - m_OverviewEntities[i].mRenderMode = inRenderMode; - m_OverviewEntities[i].mColorR = r; - m_OverviewEntities[i].mColorG = g; - m_OverviewEntities[i].mColorB = b; - return true; - } - } - - return false; // maximum overview entities reached -} -void CHudSpectator::CheckSettings() -{ - // disallow same inset mode as main mode: - - //m_pip->value = floor(m_pip->value); - - // Removed by mmcguire. - /* - if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_LOCKED || m_pip->value == INSET_IN_EYE ) ) - { - // otherwise both would show in World picures - m_pip->value = INSET_OFF; - } - - // disble in intermission screen - if ( gHUD.m_iIntermission ) - m_pip->value = INSET_OFF; - */ - - // check chat mode - if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) - { - // hud_saytext changed - m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); - - if ( gEngfuncs.IsSpectateOnly() ) - { - // tell proxy our new chat mode - char chatcmd[32]; - sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); - gEngfuncs.pfnServerCmd(chatcmd); - } - } - - // HL/TFC has no oberserver corsshair, so set it client side - if ( g_iUser1 == OBS_IN_EYE ) - { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; - m_crosshairRect.bottom = 24; - - gHUD.SetCurrentCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); - } - else - { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); - gHUD.SetCurrentCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - // Removed by mmcguire. - /* - // if we are a real player on server don't allow inset window - // in First Person mode since this is our resticted forcecamera mode 2 - // team number 3 = SPECTATOR see player.h - - if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) - m_pip->value = INSET_OFF; - */ - - // draw small border around inset view, adjust upper black bar - //gViewPort->m_pSpectatorPanel->EnableInsetView( m_pip->value != INSET_OFF ); - gViewPort->m_pSpectatorPanel->EnableInsetView( IsInOverviewMode() ); - -} - - -void CHudSpectator::Reset() -{ - // Reset HUD - if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) - { - // update level overview if level changed - ParseOverviewFile(); - LoadMapSprites(); - } - - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - - SetSpectatorStartPosition(); -} - -void CHudSpectator::InitHUDData() -{ - gHUD.InitHUDData(); - m_lastPrimaryObject = m_lastSecondaryObject = 0; - m_flNextObserverInput = 0.0f; - m_lastHudMessage = 0; - m_iSpectatorNumber = 0; - iJumpSpectator = 0; - g_iUser1 = g_iUser2 = 0; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - - if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) - m_autoDirector->value = 1.0f; - else - m_autoDirector->value = 0.0f; - - Reset(); - - SetMode( OBS_CHASE_FREE); - - g_iUser2 = 0; // fake not target until first camera command - - // reset HUD FOV - gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); -} - +//========= Copyright � 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "common/cl_entity.h" +#include "common/triangleapi.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_SpectatorPanel.h" +#include "common/hltv.h" + +#include "pm_shared/pm_shared.h" +#include "pm_shared/pm_defs.h" +#include "common/pmtrace.h" +#include "common/entity_types.h" + +// these are included for the math functions +#include "common/com_model.h" +#include "common/demo_api.h" +#include "common/event_api.h" +#include "studio_util.h" +#include "common/screenfade.h" +#include "util/STLUtil.h" +#include "mod/AvHTitles.h" +#include "mod/AvHSprites.h" + +#pragma warning(disable: 4244) + +extern int iJumpSpectator; +extern float vJumpOrigin[3]; +extern float vJumpAngles[3]; + +extern void V_GetInEyePos(int entity, float * origin, float * angles ); +extern void V_ResetChaseCam(); +extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); +extern void VectorAngles( const float *forward, float *angles ); +extern "C" void NormalizeAngles( float *angles ); +extern float * GetClientColor( int clientIndex ); + +extern vec3_t v_origin; // last view origin +extern vec3_t v_angles; // last view angle +extern vec3_t v_cl_angles; // last client/mouse angle +extern vec3_t v_sim_org; // last sim origin + +void SpectatorMode(void) +{ + + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_mode \n" ); + return; + } + + // SetModes() will decide if command is executed on server or local + if ( gEngfuncs.Cmd_Argc() == 2 ) + gHUD.m_Spectator.SetMode( atoi( gEngfuncs.Cmd_Argv(1) )); + + //else if ( gEngfuncs.Cmd_Argc() == 3 ) + // gHUD.m_Spectator.SetMode( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); +} + +void SpectatorSpray(void) +{ + vec3_t forward; + char string[128]; + + if ( !gEngfuncs.IsSpectateOnly() ) + return; + + AngleVectors(v_angles,forward,NULL,NULL); + VectorScale(forward, 128, forward); + VectorAdd(forward, v_origin, forward); + pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); + if ( trace->fraction != 1.0 ) + { + sprintf(string, "drc_spray %.2f %.2f %.2f %i", + trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); + gEngfuncs.pfnServerCmd(string); + } + +} +void SpectatorHelp(void) +{ + if ( gViewPort ) + { + gViewPort->ShowVGUIMenu( MENU_SPECHELP ); + } + else + { + char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); + + if ( text ) + { + while ( *text ) + { + if ( *text != 13 ) + gEngfuncs.Con_Printf( "%c", *text ); + text++; + } + } + } +} + +void SpectatorMenu( void ) +{ + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); + return; + } + + gViewPort->m_pSpectatorPanel->ShowMenu( atoi( gEngfuncs.Cmd_Argv(1))!=0 ); +} + +void ToggleScores( void ) +{ + if ( gViewPort ) + { + if (gViewPort->IsScoreBoardVisible() ) + { + gViewPort->HideScoreBoard(); + } + else + { + gViewPort->ShowScoreBoard(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudSpectator::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + m_flNextObserverInput = 0.0f; + m_zoomDelta = 0.0f; + m_moveDelta = 0.0f; + iJumpSpectator = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + m_lastPrimaryObject = m_lastSecondaryObject = 0; + + gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); + gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); + gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); + gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); + gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); + + m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); + m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); + m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); + m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); + + // Removed by mmcguire. + m_overviewMode = false; + //m_overview = gEngfuncs.pfnRegisterVariable("spec_overview","1",0); + //m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); + + if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector /*|| !m_pip*/) + { + gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); + return 0; + } + + return 1; +} + + +//----------------------------------------------------------------------------- +// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed +//----------------------------------------------------------------------------- + +void UTIL_StringToVector( float * pVector, const char *pString ) +{ + char *pstr, *pfront, tempString[128]; + int j; + + strcpy( tempString, pString ); + pstr = pfront = tempString; + + for ( j = 0; j < 3; j++ ) + { + pVector[j] = atof( pfront ); + + while ( *pstr && *pstr != ' ' ) + pstr++; + if (!*pstr) + break; + pstr++; + pfront = pstr; + } + + if (j < 2) + { + for (j = j+1;j < 3; j++) + pVector[j] = 0; + } +} + +int UTIL_FindEntityInMap(char * name, float * origin, float * angle) +{ + int n,found = 0; + char keyname[256]; + char token[1024]; + + cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model + + if ( !pEnt ) return 0; + + if ( !pEnt->model ) return 0; + + char * data = pEnt->model->entities; + + while (data) + { + data = gEngfuncs.COM_ParseFile(data, token); + + if ( (token[0] == '}') || (token[0]==0) ) + break; + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + } + + if (token[0] != '{') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); + return 0; + } + + // we parse the first { now parse entities properties + + while ( 1 ) + { + // parse key + data = gEngfuncs.COM_ParseFile(data, token); + if (token[0] == '}') + break; // finish parsing this entity + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + strcpy (keyname, token); + + // another hack to fix keynames with trailing spaces + n = (int)strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = gEngfuncs.COM_ParseFile(data, token); + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + if (token[0] == '}') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); + return 0; + } + + if (!strcmp(keyname,"classname")) + { + if (!strcmp(token, name )) + { + found = 1; // thats our entity + } + }; + + if( !strcmp( keyname, "angle" ) ) + { + float y = atof( token ); + + if (y >= 0) + { + angle[0] = 0.0f; + angle[1] = y; + } + else if ((int)y == -1) + { + angle[0] = -90.0f; + angle[1] = 0.0f;; + } + else + { + angle[0] = 90.0f; + angle[1] = 0.0f; + } + + angle[2] = 0.0f; + } + + if( !strcmp( keyname, "angles" ) ) + { + UTIL_StringToVector(angle, token); + } + + if (!strcmp(keyname,"origin")) + { + UTIL_StringToVector(origin, token); + + }; + + } // while (1) + + if (found) + return 1; + + } + + return 0; // we search all entities, but didn't found the correct + +} + +//----------------------------------------------------------------------------- +// SetSpectatorStartPosition(): +// Get valid map position and 'beam' spectator to this position +//----------------------------------------------------------------------------- + +void CHudSpectator::SetSpectatorStartPosition() +{ + // search for info_player start + if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else + { + // jump to 0,0,0 if no better position was found + VectorCopy(vec3_origin, m_cameraOrigin); + VectorCopy(vec3_origin, m_cameraAngles); + } + + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + + iJumpSpectator = 1; // jump anyway +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudSpectator::VidInit() +{ + m_hsprPlayerMarine = SPR_Load("sprites/iplayerm.spr"); + m_hsprPlayerAlien = SPR_Load("sprites/iplayera.spr"); + m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); + m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); + //m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); + //m_hsprCamera = SPR_Load("sprites/camera.spr"); + m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); + m_hsprWhite = SPR_Load(kWhiteSprite); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudSpectator::Draw(float flTime) +{ + + // draw only in spectator mode + if ( !g_iUser1 ) + return 0; +// string error; +// gHUD.Update( flTime, error); + + // Removed by mmcguire. + /* + // if user pressed zoom, aplly changes + if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) + { + m_mapZoom += m_zoomDelta; + + if ( m_mapZoom > 3.0f ) + m_mapZoom = 3.0f; + + if ( m_mapZoom < 0.5f ) + m_mapZoom = 0.5f; + } + + // if user moves in map mode, change map origin + if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) + { + vec3_t right; + AngleVectors(v_angles, NULL, right, NULL); + VectorNormalize(right); + VectorScale(right, m_moveDelta, right ); + + VectorAdd( m_mapOrigin, right, m_mapOrigin ) + + } + */ + + //DrawOverviewMap(); + +/* + if (!IsInOverviewMode()) + { + return 0; + } + + if (m_hsprWhite != NULL) + { + + float bgColor[] = { 0.1, 0.1, 0.1, 1 }; + float borderColor[] = { 1, 1, 1, 1 }; + + gEngfuncs.pTriAPI->RenderMode(kRenderNormal); + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); + + float gammaScale = 1.0f / gHUD.GetGammaSlope(); + + // Draw the border on the overview map and the inset view. + + gEngfuncs.pTriAPI->RenderMode(kRenderNormal); + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); + gEngfuncs.pTriAPI->Color4f(gammaScale * borderColor[0], gammaScale * borderColor[1], gammaScale * borderColor[2], borderColor[3]); + + gEngfuncs.pTriAPI->Begin(TRI_LINES); + + int insetX1 = XRES(m_OverviewData.insetWindowX); + int insetY1 = YRES(m_OverviewData.insetWindowY); + int insetX2 = insetX1 + XRES(m_OverviewData.insetWindowWidth); + int insetY2 = insetY1 + YRES(m_OverviewData.insetWindowHeight); + + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); + + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); + + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); + + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); + + gEngfuncs.pTriAPI->End(); + + }*/ + + + + /* + // Only draw the icon names only if map mode is in Main Mode + if ( g_iUser1 < OBS_MAP_FREE ) + return 1; + + if ( !m_drawnames->value ) + return 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + */ + + return 1; + +} + +bool CHudSpectator::IsInOverviewMode() const +{ + return g_iUser1 && m_overviewMode && gHUD.GetIsNSMode(); +} + +void CHudSpectator::SetOverviewMode(bool overviewMode) +{ + m_overviewMode = overviewMode; +} + +void CHudSpectator::DrawOverviewMap() +{ + + // draw only in spectator mode + if (!IsInOverviewMode()) + { + return; + } + + AvHOverviewMap& theOverviewMap = gHUD.GetOverviewMap(); + + AvHOverviewMap::DrawInfo theDrawInfo; + + theDrawInfo.mX = XRES(m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth + 4); + theDrawInfo.mY = YRES(SPECTATOR_PANEL_HEIGHT + 4); + theDrawInfo.mWidth = ScreenWidth() - theDrawInfo.mX - XRES(4); + theDrawInfo.mHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theDrawInfo.mY; + theDrawInfo.mZoomScale = 1.0f; + AvHMapExtents theMapExtents; + theOverviewMap.GetMapExtents(theMapExtents); + + theDrawInfo.mFullScreen = true; + + float worldWidth = theMapExtents.GetMaxMapX() - theMapExtents.GetMinMapX(); + float worldHeight = theMapExtents.GetMaxMapY() - theMapExtents.GetMinMapY(); + + float xScale; + float yScale; + + float aspect1 = worldWidth / worldHeight; + float aspect2 = ((float)theDrawInfo.mWidth) / theDrawInfo.mHeight; + + if (aspect1 > aspect2) + { + xScale = 1; + yScale = 1 / aspect2; + } + else + { + xScale = aspect2; + yScale = 1; + } + + float centerX = (theMapExtents.GetMinMapX() + theMapExtents.GetMaxMapX()) / 2; + float centerY = (theMapExtents.GetMinMapY() + theMapExtents.GetMaxMapY()) / 2; + + theDrawInfo.mViewWorldMinX = centerX - worldWidth * xScale * 0.5; + theDrawInfo.mViewWorldMinY = centerY - worldHeight * yScale * 0.5; + theDrawInfo.mViewWorldMaxX = centerX + worldWidth * xScale * 0.5; + theDrawInfo.mViewWorldMaxY = centerY + worldHeight * yScale * 0.5; + + if (m_hsprWhite != NULL) + { + + float bgColor[] = { 0.1, 0.1, 0.1, 1 }; + float borderColor[] = { 1, 1, 1, 1 }; + + gEngfuncs.pTriAPI->RenderMode(kRenderNormal); + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); + float gammaScale = 1.0f / gHUD.GetGammaSlope(); + + // Draw the background. + + gEngfuncs.pTriAPI->Color4f(gammaScale * bgColor[0], gammaScale * bgColor[1], gammaScale * bgColor[2], bgColor[3]); + + gEngfuncs.pTriAPI->Begin(TRI_QUADS); + + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); + + gEngfuncs.pTriAPI->End(); + + // Draw the overview map. + + theOverviewMap.Draw(theDrawInfo); + + // Draw the border on the overview map and the inset view. + + gEngfuncs.pTriAPI->RenderMode(kRenderNormal); + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); + gEngfuncs.pTriAPI->Color4f(gammaScale * borderColor[0], gammaScale * borderColor[1], gammaScale * borderColor[2], borderColor[3]); + + gEngfuncs.pTriAPI->Begin(TRI_LINES); + + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); + + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); + + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); + + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); + gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); + + int insetX1 = XRES(m_OverviewData.insetWindowX); + int insetY1 = YRES(m_OverviewData.insetWindowY); + int insetX2 = insetX1 + XRES(m_OverviewData.insetWindowWidth); + int insetY2 = insetY1 + YRES(m_OverviewData.insetWindowHeight); + + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); + + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); + + gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); + + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); + gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); + + gEngfuncs.pTriAPI->End(); + + } + + +} + +#include "parsemsg.h" +void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) +{ + float value; + char * string; + + BEGIN_READ( pbuf, iSize ); + + int cmd = READ_BYTE(); + + switch ( cmd ) // director command byte + { + case DRC_CMD_START : + // now we have to do some things clientside, since the proxy doesn't know our mod + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + // fake a InitHUD & ResetHUD message + gHUD.MsgFunc_InitHUD(NULL,0, NULL); + gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); + + break; + + case DRC_CMD_EVENT : + m_lastPrimaryObject = READ_WORD(); + m_lastSecondaryObject = READ_WORD(); + m_iObserverFlags = READ_LONG(); + + if ( m_autoDirector->value ) + { + if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) + V_ResetChaseCam(); + + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + + break; + + case DRC_CMD_MODE : + if ( m_autoDirector->value ) + { + SetMode( READ_BYTE()); + } + break; + + case DRC_CMD_CAMERA : + if ( m_autoDirector->value ) + { + vJumpOrigin[0] = READ_COORD(); // position + vJumpOrigin[1] = READ_COORD(); + vJumpOrigin[2] = READ_COORD(); + + vJumpAngles[0] = READ_COORD(); // view angle + vJumpAngles[1] = READ_COORD(); + vJumpAngles[2] = READ_COORD(); + + gEngfuncs.SetViewAngles( vJumpAngles ); + + iJumpSpectator = 1; + } + break; + + case DRC_CMD_MESSAGE: + { + client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; + + msg->effect = READ_BYTE(); // effect + + UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color + msg->r2 = msg->r1; + msg->g2 = msg->g1; + msg->b2 = msg->b1; + msg->a2 = msg->a1 = 0xFF; // not transparent + + msg->x = READ_FLOAT(); // x pos + msg->y = READ_FLOAT(); // y pos + + msg->fadein = READ_FLOAT(); // fadein + msg->fadeout = READ_FLOAT(); // fadeout + msg->holdtime = READ_FLOAT(); // holdtime + msg->fxtime = READ_FLOAT(); // fxtime; + + strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); + m_HUDMessageText[m_lastHudMessage][127]=0; // text + + msg->pMessage = m_HUDMessageText[m_lastHudMessage]; + msg->pName = "HUD_MESSAGE"; + + gHUD.m_Message.MessageAdd( msg->pName, gHUD.m_flTime); + + m_lastHudMessage++; + m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; + + } + + break; + + case DRC_CMD_SOUND : + string = READ_STRING(); + value = READ_FLOAT(); + + gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); + + break; + + case DRC_CMD_TIMESCALE : + value = READ_FLOAT(); + break; + + + + case DRC_CMD_STATUS: + READ_LONG(); // total number of spectator slots + m_iSpectatorNumber = READ_LONG(); // total number of spectator + READ_WORD(); // total number of relay proxies + + gViewPort->UpdateSpectatorPanel(); + break; + + case DRC_CMD_BANNER: + // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga + gViewPort->m_pSpectatorPanel->m_TopBanner->LoadImage( READ_STRING() ); + gViewPort->UpdateSpectatorPanel(); + break; + + case DRC_CMD_FADE: + break; + + case DRC_CMD_STUFFTEXT: + ClientCmd( READ_STRING() ); + break; + + default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); + } +} + +void CHudSpectator::FindNextPlayer(bool bReverse) +{ + // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching + // only a subset of the players. e.g. Make it check the target's team. + + int iStart; + cl_entity_t * pEnt = NULL; + + // if we are NOT in HLTV mode, spectator targets are set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + char cmdstring[32]; + // forward command to server + sprintf(cmdstring,"follownext %i",bReverse?1:0); + gEngfuncs.pfnServerCmd(cmdstring); + return; + } + + if ( g_iUser2 ) + iStart = g_iUser2; + else + iStart = 1; + + g_iUser2 = 0; + + int iCurrent = iStart; + + int iDir = bReverse ? -1 : 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > MAX_PLAYERS) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = MAX_PLAYERS; + + pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); + + if ( !IsActivePlayer( pEnt ) ) + continue; + + // MOD AUTHORS: Add checks on target here. + + g_iUser2 = iCurrent; + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( !g_iUser2 ) + { + gEngfuncs.Con_DPrintf( "No observer targets.\n" ); + // take save camera position + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + } + else + { + // use new entity position for roaming + VectorCopy ( pEnt->origin, vJumpOrigin ); + VectorCopy ( pEnt->angles, vJumpAngles ); + } + iJumpSpectator = 1; +} + +void CHudSpectator::HandleButtonsDown( int ButtonPressed ) +{ + if ( !gViewPort ) + return; + + //Not in intermission. + if ( gHUD.m_iIntermission ) + return; + + if ( !g_iUser1 ) + return; // dont do anything if not in spectator mode + + // don't handle buttons during normal demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) + return; + + int theNewMainMode = g_iUser1; + + // Jump changes main window modes + if ( ButtonPressed & IN_JUMP ) + { + bool theFirstPerson = (g_iUser1 == OBS_IN_EYE); + bool theInOverviewMode = gHUD.m_Spectator.IsInOverviewMode(); + + // NS + if(gHUD.GetIsNSMode()) + { + // First-person full -> chase camera full -> firstperson with overview -> chase camera with overview + if(theFirstPerson && !theInOverviewMode) + { + gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); + //gHUD.m_Spectator.SetOverviewMode(false); + } + else if(!theFirstPerson && !theInOverviewMode) + { + gHUD.m_Spectator.SetMode(OBS_IN_EYE); + gHUD.m_Spectator.SetOverviewMode(true); + } + else if(theFirstPerson && theInOverviewMode) + { + gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); + //gHUD.m_Spectator.SetOverviewMode(true); + } + else if(!theFirstPerson && theInOverviewMode) + { + gHUD.m_Spectator.SetMode(OBS_IN_EYE); + gHUD.m_Spectator.SetOverviewMode(false); + } + } + // Combat + else + { + // First-person full -> chase camera full + if(theFirstPerson) + { + gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); + gHUD.m_Spectator.SetOverviewMode(false); + } + else + { + gHUD.m_Spectator.SetMode(OBS_IN_EYE); + gHUD.m_Spectator.SetOverviewMode(false); + } + } + } + + //g_iUser1 = theNewMainMode; + + // Attack moves to the next player + if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + { + FindNextPlayer( (ButtonPressed & IN_MOVELEFT) ? true:false ); + +// if ( g_iUser1 == OBS_ROAMING ) +// { +// gEngfuncs.SetViewAngles( vJumpAngles ); +// iJumpSpectator = 1; +// +// } + + // lease directed mode if player want to see another player + m_autoDirector->value = 0.0f; + } + +/* + double time = gEngfuncs.GetClientTime(); + + int newMainMode = g_iUser1; + int newInsetMode = m_pip->value; + + // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); + if ( !gViewPort ) + return; + + //Not in intermission. + if ( gHUD.m_iIntermission ) + return; + + if ( !g_iUser1 ) + return; // dont do anything if not in spectator mode + + // don't handle buttons during normal demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) + return; + // Slow down mouse clicks. + if ( m_flNextObserverInput > time ) + return; + + // enable spectator screen + if ( ButtonPressed & IN_DUCK ) + { + gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); + } + + // 'Use' changes inset window mode + if ( ButtonPressed & IN_USE ) + { + newInsetMode = ToggleInset(true); + } + + // if not in HLTV mode, buttons are handled server side + if ( gEngfuncs.IsSpectateOnly() ) + { + // changing target or chase mode not in overviewmode without inset window + + // Jump changes main window modes + if ( ButtonPressed & IN_JUMP ) + { + if ( g_iUser1 == OBS_CHASE_LOCKED ) + newMainMode = OBS_CHASE_FREE; + + else if ( g_iUser1 == OBS_CHASE_FREE ) + newMainMode = OBS_IN_EYE; + + else if ( g_iUser1 == OBS_IN_EYE ) + newMainMode = OBS_ROAMING; + + else if ( g_iUser1 == OBS_ROAMING ) + newMainMode = OBS_MAP_FREE; + + else if ( g_iUser1 == OBS_MAP_FREE ) + newMainMode = OBS_MAP_CHASE; + + else + newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore + } + + // Attack moves to the next player + if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) + { + FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); + + if ( g_iUser1 == OBS_ROAMING ) + { + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + + } + // lease directed mode if player want to see another player + m_autoDirector->value = 0.0f; + } + } + + SetModes(newMainMode, newInsetMode); + + if ( g_iUser1 == OBS_MAP_FREE ) + { + if ( ButtonPressed & IN_FORWARD ) + m_zoomDelta = 0.01f; + + if ( ButtonPressed & IN_BACK ) + m_zoomDelta = -0.01f; + + if ( ButtonPressed & IN_MOVELEFT ) + m_moveDelta = -12.0f; + + if ( ButtonPressed & IN_MOVERIGHT ) + m_moveDelta = 12.0f; + } + + m_flNextObserverInput = time + 0.2; +*/ + +} + +void CHudSpectator::HandleButtonsUp( int ButtonPressed ) +{ + if ( !gViewPort ) + return; + + if ( !gViewPort->m_pSpectatorPanel->isVisible() ) + return; // dont do anything if not in spectator mode + + if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) + m_zoomDelta = 0.0f; + + if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + m_moveDelta = 0.0f; +} + +void CHudSpectator::SetMode(int iNewMainMode) +{ + // if value == -1 keep old value + if ( iNewMainMode == -1 ) + iNewMainMode = g_iUser1; + + // main modes ettings will override inset window settings + if ( iNewMainMode != g_iUser1 ) + { + // if we are NOT in HLTV mode, main spectator mode is set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + char cmdstring[32]; + // forward command to server + sprintf(cmdstring,"specmode %i",iNewMainMode ); + gEngfuncs.pfnServerCmd(cmdstring); + return; + } + else + { + if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target + { + // choose last Director object if still available + if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) + { + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + else + { + FindNextPlayer(false); // find any target + } + } + + switch ( iNewMainMode ) + { + case OBS_CHASE_LOCKED: + g_iUser1 = OBS_CHASE_LOCKED; + break; + + case OBS_CHASE_FREE: + g_iUser1 = OBS_CHASE_FREE; + break; + + case OBS_ROAMING : // jump to current vJumpOrigin/angle + g_iUser1 = OBS_ROAMING; + if ( g_iUser2 ) + { + V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + break; + + case OBS_IN_EYE: + g_iUser1 = OBS_IN_EYE; + break; + + /* + case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + + case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + */ + } + + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + gHUD.SetCurrentCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + gHUD.SetCurrentCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + //char string[128]; + //sprintf(string, "#Spec_Mode%d", g_iUser1 ); + //sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); + //gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + } + + gViewPort->UpdateSpectatorPanel(); +} + +bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) +{ + return ( ent && + ent->player && + ent->curstate.solid != SOLID_NOT && + ent != gEngfuncs.GetLocalPlayer() && + g_PlayerInfoList[ent->index].name != NULL + ); +} + + +bool CHudSpectator::ParseOverviewFile( ) +{ + //char filename[255]; + //char levelname[255]; + //char token[1024]; + //float height; + + char *pfile = NULL; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + + // fill in standrd values + m_OverviewData.insetWindowX = 4; // upper left corner + m_OverviewData.insetWindowY = 4 + SPECTATOR_PANEL_HEIGHT; + m_OverviewData.insetWindowHeight = 180; + m_OverviewData.insetWindowWidth = 240; + m_OverviewData.origin[0] = 0.0f; + m_OverviewData.origin[1] = 0.0f; + m_OverviewData.origin[2] = 0.0f; + m_OverviewData.zoom = 1.0f; + m_OverviewData.layers = 0; + m_OverviewData.layersHeights[0] = 0.0f; + strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); + + if ( strlen( m_OverviewData.map ) == 0 ) + return false; // not active yet + + /* + strcpy(levelname, m_OverviewData.map + 5); + levelname[strlen(levelname)-4] = 0; + + sprintf(filename, "overviews/%s.txt", levelname ); + + pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); + + if (!pfile) + { + gEngfuncs.Con_Printf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); + return false; + } + + while (true) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if (!pfile) + break; + + if ( !stricmp( token, "global" ) ) + { + // parse the global data + pfile = gEngfuncs.COM_ParseFile(pfile, token); + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "zoom" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.zoom = atof( token ); + } + else if ( !stricmp( token, "origin" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[0] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.origin[1] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[2] = atof( token ); + } + else if ( !stricmp( token, "rotated" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.rotated = atoi( token ); + } + else if ( !stricmp( token, "inset" ) ) + { + + // Removed by mmcguire. + // This isn't supported anymore. + pfile = gEngfuncs.COM_ParseFile(pfile,token); + //m_OverviewData.insetWindowX = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + //m_OverviewData.insetWindowY = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + //m_OverviewData.insetWindowWidth = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + //m_OverviewData.insetWindowHeight = atof( token ); + + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + + } + } + else if ( !stricmp( token, "layer" ) ) + { + // parse a layer data + + if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "image" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); + + + } + else if ( !stricmp( token, "height" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + height = atof(token); + m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + } + + m_OverviewData.layers++; + + } + } + + gEngfuncs.COM_FreeFile( pfile ); + */ + + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + + return true; + +} + +void CHudSpectator::LoadMapSprites() +{ + // right now only support for one map layer + if (m_OverviewData.layers > 0 ) + { + m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); + } + else + m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead +} + +void CHudSpectator::DrawOverviewLayer() +{ + float screenaspect, xs, ys, xStep, yStep, x,y,z; + int ix,iy,i,xTiles,yTiles,frame; + + qboolean hasMapImage = m_MapSprite?TRUE:FALSE; + model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); + + if ( hasMapImage) + { + i = m_MapSprite->numframes / (4*3); + i = sqrt((float)i); + xTiles = i*4; + yTiles = i*3; + } + else + { + xTiles = 8; + yTiles = 6; + } + + + screenaspect = 4.0f/3.0f; + + + xs = m_OverviewData.origin[0]; + ys = m_OverviewData.origin[1]; + z = ( 90.0f - v_angles[0] ) / 90.0f; + z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; + + // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); + + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + frame = 0; + + + // rotated view ? + if ( m_OverviewData.rotated ) + { + xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); + + for (iy = 0; iy < yTiles; iy++) + { + x = xs - (4096.0f / (m_OverviewData.zoom)); + + for (ix = 0; ix < xTiles; ix++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + x+= xStep; + } + + y+=yStep; + } + } + else + { + xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + + x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); + + + + for (ix = 0; ix < yTiles; ix++) + { + + y = ys + (4096.0f / (m_OverviewData.zoom)); + + for (iy = 0; iy < xTiles; iy++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + + y+=yStep; + } + + x+= xStep; + + } + } +} + +void CHudSpectator::DrawOverviewEntities() +{ + /* + int i,ir,ig,ib; + struct model_s *hSpriteModel; + vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; + float x,y,z, r,g,b, sizeScale = 4.0f; + cl_entity_t * ent; + float rmatrix[3][4]; // transformation matrix + + float zScale = (90.0f - v_angles[0] ) / 90.0f; + + + z = m_OverviewData.layersHeights[0] * zScale; + // get yellow/brown HUD color + //UnpackRGB(ir,ig,ib, RGB_YELLOWISH); + gHUD.GetPrimaryHudColor(ir, ig, ib); + r = (float)ir/255.0f; + g = (float)ig/255.0f; + b = (float)ib/255.0f; + + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + + for (i=0; i < MAX_PLAYERS; i++ ) + m_vPlayerPos[i][2] = -1; // mark as invisible + + // draw all players + + float depthOffset = 0; + + for (i=MAX_OVERVIEW_ENTITIES - 1; i >= 0; i--) + { + if ( !m_OverviewEntities[i].hSprite ) + continue; + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); + ent = m_OverviewEntities[i].entity; + + int theSpriteFrame = m_OverviewEntities[i].mFrame; + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, theSpriteFrame); + + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd); + + // see R_DrawSpriteModel + // draws players sprite + + AngleVectors(ent->angles, right, up, NULL ); + + VectorCopy(ent->origin,origin); + + // Set origin of blip to just above map height, so blips are all drawn on map + origin.z = m_OverviewData.layersHeights[0] + kOverviewEntityZHeight + depthOffset; + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + + float gammaSlope = gHUD.GetGammaSlope(); + + gEngfuncs.pTriAPI->Color4f( + m_OverviewEntities[i].mColorR / gammaSlope, + m_OverviewEntities[i].mColorG / gammaSlope, + m_OverviewEntities[i].mColorB / gammaSlope, + 1); + + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (1,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->End (); + + + if ( !ent->player) + continue; + // draw line under player icons + origin[2] *= zScale; + + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + // calculate screen position for name and infromation in hud::draw() + if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) + continue; // object is behind viewer + + screen[0] = XPROJECT(screen[0]); + screen[1] = YPROJECT(screen[1]); + screen[2] = 0.0f; + + // calculate some offset under the icon + origin[0]+=32.0f; + origin[1]+=32.0f; + + gEngfuncs.pTriAPI->WorldToScreen(origin,offset); + + offset[0] = XPROJECT(offset[0]); + offset[1] = YPROJECT(offset[1]); + offset[2] = 0.0f; + + VectorSubtract(offset, screen, offset ); + + int playerNum = ent->index - 1; + + m_vPlayerPos[playerNum][0] = screen[0]; + m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); + m_vPlayerPos[playerNum][2] = 1; // mark player as visible + + + } + + if ( !m_pip || !m_drawcone->value ) + return; + + // get current camera position and angle + + if ( m_pip == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) + { + V_GetInEyePos( g_iUser2, origin, angles ); + } + else if ( m_pip == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) + { + V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); + } + else if ( g_iUser1 == OBS_ROAMING ) + { + VectorCopy( v_sim_org, origin ); + VectorCopy( v_cl_angles, angles ); + } + else + V_GetChasePos( g_iUser2, NULL, origin, angles ); + + + // draw camera sprite + + x = origin[0]; + y = origin[1]; + z = origin[2]; + + // Set origin of cone to just above map height, so blips are all drawn on map + z = m_OverviewData.layersHeights[0] + kOverviewEntityZHeight; + + angles[0] = 0; // always show horizontal camera sprite + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + + gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); + + AngleVectors(angles, forward, NULL, NULL ); + VectorScale (forward, 512.0f, forward); + + offset[0] = 0.0f; + offset[1] = 45.0f; + offset[2] = 0.0f; + + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , right ); + + offset[1]= -45.0f; + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , left ); + + gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); + gEngfuncs.pTriAPI->End (); + */ + +} + + + +void CHudSpectator::DrawOverview() +{ + /* + // draw only in sepctator mode + if ( !g_iUser1 ) + return; + + // Only draw the overview if Map Mode is selected for this view + if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) + return; + + if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) + return; + + DrawOverviewLayer(); + DrawOverviewEntities(); + CheckOverviewEntities(); + */ + +} + + + +void CHudSpectator::CheckOverviewEntities() +{ + double time = gEngfuncs.GetClientTime(); + + // removes old entities from list + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // remove entity from list if it is too old + if ( m_OverviewEntities[i].killTime < time ) + { + memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); + } + } +} + +bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) +{ + HSPRITE hSprite = 0; + double duration = -1.0f; // duration -1 means show it only this frame; + int theFrame = 0; + bool theSuccess = false; + int theRenderMode; + + if ( ent ) + { + + if (ent->curstate.solid != SOLID_NOT) + { + gHUD.GetSpriteForUser3(AvHUser3(ent->curstate.iuser3), hSprite, theFrame, theRenderMode); + } + + /* + if ( type == ET_PLAYER ) + { + if ( ent->curstate.solid != SOLID_NOT) + { + int thePlayerClass = g_PlayerExtraInfo[ent->index].playerclass; + switch(thePlayerClass) + { + case PLAYERCLASS_ALIVE_MARINE: + hSprite = this->m_hsprPlayerMarine; + theFrame = 0; + break; + case PLAYERCLASS_ALIVE_HEAVY_MARINE: + hSprite = this->m_hsprPlayerMarine; + theFrame = 1; + break; + case PLAYERCLASS_COMMANDER: + hSprite = this->m_hsprPlayerMarine; + theFrame = 2; + break; + case PLAYERCLASS_ALIVE_LEVEL1: + hSprite = this->m_hsprPlayerAlien; + theFrame = 0; + break; + case PLAYERCLASS_ALIVE_LEVEL2: + hSprite = this->m_hsprPlayerAlien; + theFrame = 1; + break; + case PLAYERCLASS_ALIVE_LEVEL3: + hSprite = this->m_hsprPlayerAlien; + theFrame = 2; + break; + case PLAYERCLASS_ALIVE_LEVEL4: + hSprite = this->m_hsprPlayerAlien; + theFrame = 3; + break; + case PLAYERCLASS_ALIVE_LEVEL5: + hSprite = this->m_hsprPlayerAlien; + theFrame = 4; + break; + case PLAYERCLASS_ALIVE_GESTATING: + hSprite = this->m_hsprPlayerAlien; + theFrame = 5; + break; + + case PLAYERCLASS_ALIVE_DIGESTING: + break; + } + } + else + { + // it's an spectator + } + } + else if (type == ET_NORMAL) + { + // Now help icons + if(hSprite == 0) + { + AvHUser3 theUser3 = AvHUser3(ent->curstate.iuser3); + theFrame = gHUD.GetHelpIconFrameFromUser3(theUser3); + if(theFrame != -1) + { + hSprite = gHUD.GetHelpSprite(); + } + } + } + */ + } + + if(hSprite > 0) + { + + int theTeam = ent->curstate.team; + + float theR = kFTeamColors[theTeam][0]; + float theG = kFTeamColors[theTeam][1]; + float theB = kFTeamColors[theTeam][2]; + + theSuccess = AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration, theFrame, theRenderMode, theR, theG, theB); + + } + + return theSuccess; +} + +void CHudSpectator::DeathMessage(int victim) +{ + // find out where the victim is + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); + + if (pl && pl->player) + AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f, 0, kRenderTransTexture, 1, 1, 1); +} + +bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime, int inFrame, int inRenderMode, float r, float g, float b) +{ + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // find empty entity slot + if ( m_OverviewEntities[i].entity == NULL) + { + m_OverviewEntities[i].entity = ent; + m_OverviewEntities[i].hSprite = sprite; + m_OverviewEntities[i].killTime = killTime; + m_OverviewEntities[i].mFrame = inFrame; + m_OverviewEntities[i].mRenderMode = inRenderMode; + m_OverviewEntities[i].mColorR = r; + m_OverviewEntities[i].mColorG = g; + m_OverviewEntities[i].mColorB = b; + return true; + } + } + + return false; // maximum overview entities reached +} +void CHudSpectator::CheckSettings() +{ + // disallow same inset mode as main mode: + + //m_pip->value = floor(m_pip->value); + + // Removed by mmcguire. + /* + if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_LOCKED || m_pip->value == INSET_IN_EYE ) ) + { + // otherwise both would show in World picures + m_pip->value = INSET_OFF; + } + + // disble in intermission screen + if ( gHUD.m_iIntermission ) + m_pip->value = INSET_OFF; + */ + + // check chat mode + if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) + { + // hud_saytext changed + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // tell proxy our new chat mode + char chatcmd[32]; + sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); + gEngfuncs.pfnServerCmd(chatcmd); + } + } + + // HL/TFC has no oberserver corsshair, so set it client side + if ( g_iUser1 == OBS_IN_EYE ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + gHUD.SetCurrentCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + gHUD.SetCurrentCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + // Removed by mmcguire. + /* + // if we are a real player on server don't allow inset window + // in First Person mode since this is our resticted forcecamera mode 2 + // team number 3 = SPECTATOR see player.h + + if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) + m_pip->value = INSET_OFF; + */ + + // draw small border around inset view, adjust upper black bar + //gViewPort->m_pSpectatorPanel->EnableInsetView( m_pip->value != INSET_OFF ); + gViewPort->m_pSpectatorPanel->EnableInsetView( IsInOverviewMode() ); + +} + + +void CHudSpectator::Reset() +{ + // Reset HUD + if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) + { + // update level overview if level changed + ParseOverviewFile(); + LoadMapSprites(); + } + + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + SetSpectatorStartPosition(); +} + +void CHudSpectator::InitHUDData() +{ + gHUD.InitHUDData(); + m_lastPrimaryObject = m_lastSecondaryObject = 0; + m_flNextObserverInput = 0.0f; + m_lastHudMessage = 0; + m_iSpectatorNumber = 0; + iJumpSpectator = 0; + g_iUser1 = g_iUser2 = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) + m_autoDirector->value = 1.0f; + else + m_autoDirector->value = 0.0f; + + Reset(); + + SetMode( OBS_CHASE_FREE); + + g_iUser2 = 0; // fake not target until first camera command + + // reset HUD FOV + gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); +} + diff --git a/main/source/cl_dll/hud_spectator.cpp~ b/main/source/cl_dll/hud_spectator.cpp~ deleted file mode 100644 index ade1937b..00000000 --- a/main/source/cl_dll/hud_spectator.cpp~ +++ /dev/null @@ -1,1957 +0,0 @@ -//========= Copyright � 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" -#include "common/cl_entity.h" -#include "common/triangleapi.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_SpectatorPanel.h" -#include "common/hltv.h" - -#include "pm_shared/pm_shared.h" -#include "pm_shared/pm_defs.h" -#include "common/pmtrace.h" -#include "common/entity_types.h" - -// these are included for the math functions -#include "common/com_model.h" -#include "common/demo_api.h" -#include "common/event_api.h" -#include "studio_util.h" -#include "common/screenfade.h" -#include "util/STLUtil.h" -#include "mod/AvHTitles.h" -#include "mod/AvHSprites.h" - -#pragma warning(disable: 4244) - -extern int iJumpSpectator; -extern float vJumpOrigin[3]; -extern float vJumpAngles[3]; - -extern void V_GetInEyePos(int entity, float * origin, float * angles ); -extern void V_ResetChaseCam(); -extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); -extern void VectorAngles( const float *forward, float *angles ); -extern "C" void NormalizeAngles( float *angles ); -extern float * GetClientColor( int clientIndex ); - -extern vec3_t v_origin; // last view origin -extern vec3_t v_angles; // last view angle -extern vec3_t v_cl_angles; // last client/mouse angle -extern vec3_t v_sim_org; // last sim origin - -void SpectatorMode(void) -{ - - if ( gEngfuncs.Cmd_Argc() <= 1 ) - { - gEngfuncs.Con_Printf( "usage: spec_mode \n" ); - return; - } - - // SetModes() will decide if command is executed on server or local - if ( gEngfuncs.Cmd_Argc() == 2 ) - gHUD.m_Spectator.SetMode( atoi( gEngfuncs.Cmd_Argv(1) )); - - //else if ( gEngfuncs.Cmd_Argc() == 3 ) - // gHUD.m_Spectator.SetMode( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); -} - -void SpectatorSpray(void) -{ - vec3_t forward; - char string[128]; - - if ( !gEngfuncs.IsSpectateOnly() ) - return; - - AngleVectors(v_angles,forward,NULL,NULL); - VectorScale(forward, 128, forward); - VectorAdd(forward, v_origin, forward); - pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); - if ( trace->fraction != 1.0 ) - { - sprintf(string, "drc_spray %.2f %.2f %.2f %i", - trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); - gEngfuncs.pfnServerCmd(string); - } - -} -void SpectatorHelp(void) -{ - if ( gViewPort ) - { - gViewPort->ShowVGUIMenu( MENU_SPECHELP ); - } - else - { - char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); - - if ( text ) - { - while ( *text ) - { - if ( *text != 13 ) - gEngfuncs.Con_Printf( "%c", *text ); - text++; - } - } - } -} - -void SpectatorMenu( void ) -{ - if ( gEngfuncs.Cmd_Argc() <= 1 ) - { - gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); - return; - } - - gViewPort->m_pSpectatorPanel->ShowMenu( atoi( gEngfuncs.Cmd_Argv(1))!=0 ); -} - -void ToggleScores( void ) -{ - if ( gViewPort ) - { - if (gViewPort->IsScoreBoardVisible() ) - { - gViewPort->HideScoreBoard(); - } - else - { - gViewPort->ShowScoreBoard(); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CHudSpectator::Init() -{ - gHUD.AddHudElem(this); - - m_iFlags |= HUD_ACTIVE; - m_flNextObserverInput = 0.0f; - m_zoomDelta = 0.0f; - m_moveDelta = 0.0f; - iJumpSpectator = 0; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - m_lastPrimaryObject = m_lastSecondaryObject = 0; - - gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); - gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); - gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); - gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); - gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); - - m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); - m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); - m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); - m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); - - // Removed by mmcguire. - m_overviewMode = false; - //m_overview = gEngfuncs.pfnRegisterVariable("spec_overview","1",0); - //m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); - - if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector /*|| !m_pip*/) - { - gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); - return 0; - } - - return 1; -} - - -//----------------------------------------------------------------------------- -// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed -//----------------------------------------------------------------------------- - -void UTIL_StringToVector( float * pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - if (j < 2) - { - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - -int UTIL_FindEntityInMap(char * name, float * origin, float * angle) -{ - int n,found = 0; - char keyname[256]; - char token[1024]; - - cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model - - if ( !pEnt ) return 0; - - if ( !pEnt->model ) return 0; - - char * data = pEnt->model->entities; - - while (data) - { - data = gEngfuncs.COM_ParseFile(data, token); - - if ( (token[0] == '}') || (token[0]==0) ) - break; - - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - } - - if (token[0] != '{') - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); - return 0; - } - - // we parse the first { now parse entities properties - - while ( 1 ) - { - // parse key - data = gEngfuncs.COM_ParseFile(data, token); - if (token[0] == '}') - break; // finish parsing this entity - - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - strcpy (keyname, token); - - // another hack to fix keynames with trailing spaces - n = (int)strlen(keyname); - while (n && keyname[n-1] == ' ') - { - keyname[n-1] = 0; - n--; - } - - // parse value - data = gEngfuncs.COM_ParseFile(data, token); - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - if (token[0] == '}') - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); - return 0; - } - - if (!strcmp(keyname,"classname")) - { - if (!strcmp(token, name )) - { - found = 1; // thats our entity - } - }; - - if( !strcmp( keyname, "angle" ) ) - { - float y = atof( token ); - - if (y >= 0) - { - angle[0] = 0.0f; - angle[1] = y; - } - else if ((int)y == -1) - { - angle[0] = -90.0f; - angle[1] = 0.0f;; - } - else - { - angle[0] = 90.0f; - angle[1] = 0.0f; - } - - angle[2] = 0.0f; - } - - if( !strcmp( keyname, "angles" ) ) - { - UTIL_StringToVector(angle, token); - } - - if (!strcmp(keyname,"origin")) - { - UTIL_StringToVector(origin, token); - - }; - - } // while (1) - - if (found) - return 1; - - } - - return 0; // we search all entities, but didn't found the correct - -} - -//----------------------------------------------------------------------------- -// SetSpectatorStartPosition(): -// Get valid map position and 'beam' spectator to this position -//----------------------------------------------------------------------------- - -void CHudSpectator::SetSpectatorStartPosition() -{ - // search for info_player start - if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - else - { - // jump to 0,0,0 if no better position was found - VectorCopy(vec3_origin, m_cameraOrigin); - VectorCopy(vec3_origin, m_cameraAngles); - } - - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); - - iJumpSpectator = 1; // jump anyway -} - -//----------------------------------------------------------------------------- -// Purpose: Loads new icons -//----------------------------------------------------------------------------- -int CHudSpectator::VidInit() -{ - m_hsprPlayerMarine = SPR_Load("sprites/iplayerm.spr"); - m_hsprPlayerAlien = SPR_Load("sprites/iplayera.spr"); - m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); - m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); - //m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); - //m_hsprCamera = SPR_Load("sprites/camera.spr"); - m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); - m_hsprWhite = SPR_Load(kWhiteSprite); - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flTime - -// intermission - -//----------------------------------------------------------------------------- -int CHudSpectator::Draw(float flTime) -{ - - // draw only in spectator mode - if ( !g_iUser1 ) - return 0; -// string error; -// gHUD.Update( flTime, error); - - // Removed by mmcguire. - /* - // if user pressed zoom, aplly changes - if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) - { - m_mapZoom += m_zoomDelta; - - if ( m_mapZoom > 3.0f ) - m_mapZoom = 3.0f; - - if ( m_mapZoom < 0.5f ) - m_mapZoom = 0.5f; - } - - // if user moves in map mode, change map origin - if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) - { - vec3_t right; - AngleVectors(v_angles, NULL, right, NULL); - VectorNormalize(right); - VectorScale(right, m_moveDelta, right ); - - VectorAdd( m_mapOrigin, right, m_mapOrigin ) - - } - */ - - //DrawOverviewMap(); - -/* - if (!IsInOverviewMode()) - { - return 0; - } - - if (m_hsprWhite != NULL) - { - - float bgColor[] = { 0.1, 0.1, 0.1, 1 }; - float borderColor[] = { 1, 1, 1, 1 }; - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - - float gammaScale = 1.0f / gHUD.GetGammaSlope(); - - // Draw the border on the overview map and the inset view. - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - gEngfuncs.pTriAPI->Color4f(gammaScale * borderColor[0], gammaScale * borderColor[1], gammaScale * borderColor[2], borderColor[3]); - - gEngfuncs.pTriAPI->Begin(TRI_LINES); - - int insetX1 = XRES(m_OverviewData.insetWindowX); - int insetY1 = YRES(m_OverviewData.insetWindowY); - int insetX2 = insetX1 + XRES(m_OverviewData.insetWindowWidth); - int insetY2 = insetY1 + YRES(m_OverviewData.insetWindowHeight); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - - gEngfuncs.pTriAPI->End(); - - }*/ - - - - /* - // Only draw the icon names only if map mode is in Main Mode - if ( g_iUser1 < OBS_MAP_FREE ) - return 1; - - if ( !m_drawnames->value ) - return 1; - - // make sure we have player info - gViewPort->GetAllPlayersInfo(); - */ - - return 1; - -} - -bool CHudSpectator::IsInOverviewMode() const -{ - return g_iUser1 && m_overviewMode && gHUD.GetIsNSMode(); -} - -void CHudSpectator::SetOverviewMode(bool overviewMode) -{ - m_overviewMode = overviewMode; -} - -void CHudSpectator::DrawOverviewMap() -{ - - // draw only in spectator mode - if (!IsInOverviewMode()) - { - return; - } - - AvHOverviewMap& theOverviewMap = gHUD.GetOverviewMap(); - - AvHOverviewMap::DrawInfo theDrawInfo; - - theDrawInfo.mX = XRES(m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth + 4); - theDrawInfo.mY = YRES(SPECTATOR_PANEL_HEIGHT + 4); - theDrawInfo.mWidth = ScreenWidth() - theDrawInfo.mX - XRES(4); - theDrawInfo.mHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theDrawInfo.mY; - theDrawInfo.mZoomScale = 1.0f; - AvHMapExtents theMapExtents; - theOverviewMap.GetMapExtents(theMapExtents); - - theDrawInfo.mFullScreen = true; - - float worldWidth = theMapExtents.GetMaxMapX() - theMapExtents.GetMinMapX(); - float worldHeight = theMapExtents.GetMaxMapY() - theMapExtents.GetMinMapY(); - - float xScale; - float yScale; - - float aspect1 = worldWidth / worldHeight; - float aspect2 = ((float)theDrawInfo.mWidth) / theDrawInfo.mHeight; - - if (aspect1 > aspect2) - { - xScale = 1; - yScale = 1 / aspect2; - } - else - { - xScale = aspect2; - yScale = 1; - } - - float centerX = (theMapExtents.GetMinMapX() + theMapExtents.GetMaxMapX()) / 2; - float centerY = (theMapExtents.GetMinMapY() + theMapExtents.GetMaxMapY()) / 2; - - theDrawInfo.mViewWorldMinX = centerX - worldWidth * xScale * 0.5; - theDrawInfo.mViewWorldMinY = centerY - worldHeight * yScale * 0.5; - theDrawInfo.mViewWorldMaxX = centerX + worldWidth * xScale * 0.5; - theDrawInfo.mViewWorldMaxY = centerY + worldHeight * yScale * 0.5; - - if (m_hsprWhite != NULL) - { - - float bgColor[] = { 0.1, 0.1, 0.1, 1 }; - float borderColor[] = { 1, 1, 1, 1 }; - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - #ifdef _WIN32 - float gammaScale = 1.0f / gHUD.GetGammaSlope(); - #else - float gammaScale = 1.0f; - #endif - - // Draw the background. - - gEngfuncs.pTriAPI->Color4f(gammaScale * bgColor[0], gammaScale * bgColor[1], gammaScale * bgColor[2], bgColor[3]); - - gEngfuncs.pTriAPI->Begin(TRI_QUADS); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); - - gEngfuncs.pTriAPI->End(); - - // Draw the overview map. - - theOverviewMap.Draw(theDrawInfo); - - // Draw the border on the overview map and the inset view. - - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)(gEngfuncs.GetSpritePointer(m_hsprWhite)), 0); - gEngfuncs.pTriAPI->Color4f(gammaScale * borderColor[0], gammaScale * borderColor[1], gammaScale * borderColor[2], borderColor[3]); - - gEngfuncs.pTriAPI->Begin(TRI_LINES); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY + theDrawInfo.mHeight, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); - - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX + theDrawInfo.mWidth, theDrawInfo.mY, 1); - gEngfuncs.pTriAPI->Vertex3f(theDrawInfo.mX, theDrawInfo.mY, 1); - - int insetX1 = XRES(m_OverviewData.insetWindowX); - int insetY1 = YRES(m_OverviewData.insetWindowY); - int insetX2 = insetX1 + XRES(m_OverviewData.insetWindowWidth); - int insetY2 = insetY1 + YRES(m_OverviewData.insetWindowHeight); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY1, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX2, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY2, 1); - gEngfuncs.pTriAPI->Vertex3f(insetX1, insetY1, 1); - - gEngfuncs.pTriAPI->End(); - - } - - -} - -#include "parsemsg.h" -void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) -{ - float value; - char * string; - - BEGIN_READ( pbuf, iSize ); - - int cmd = READ_BYTE(); - - switch ( cmd ) // director command byte - { - case DRC_CMD_START : - // now we have to do some things clientside, since the proxy doesn't know our mod - g_iPlayerClass = 0; - g_iTeamNumber = 0; - - // fake a InitHUD & ResetHUD message - gHUD.MsgFunc_InitHUD(NULL,0, NULL); - gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); - - break; - - case DRC_CMD_EVENT : - m_lastPrimaryObject = READ_WORD(); - m_lastSecondaryObject = READ_WORD(); - m_iObserverFlags = READ_LONG(); - - if ( m_autoDirector->value ) - { - if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) - V_ResetChaseCam(); - - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } - - break; - - case DRC_CMD_MODE : - if ( m_autoDirector->value ) - { - SetMode( READ_BYTE()); - } - break; - - case DRC_CMD_CAMERA : - if ( m_autoDirector->value ) - { - vJumpOrigin[0] = READ_COORD(); // position - vJumpOrigin[1] = READ_COORD(); - vJumpOrigin[2] = READ_COORD(); - - vJumpAngles[0] = READ_COORD(); // view angle - vJumpAngles[1] = READ_COORD(); - vJumpAngles[2] = READ_COORD(); - - gEngfuncs.SetViewAngles( vJumpAngles ); - - iJumpSpectator = 1; - } - break; - - case DRC_CMD_MESSAGE: - { - client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; - - msg->effect = READ_BYTE(); // effect - - UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color - msg->r2 = msg->r1; - msg->g2 = msg->g1; - msg->b2 = msg->b1; - msg->a2 = msg->a1 = 0xFF; // not transparent - - msg->x = READ_FLOAT(); // x pos - msg->y = READ_FLOAT(); // y pos - - msg->fadein = READ_FLOAT(); // fadein - msg->fadeout = READ_FLOAT(); // fadeout - msg->holdtime = READ_FLOAT(); // holdtime - msg->fxtime = READ_FLOAT(); // fxtime; - - strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); - m_HUDMessageText[m_lastHudMessage][127]=0; // text - - msg->pMessage = m_HUDMessageText[m_lastHudMessage]; - msg->pName = "HUD_MESSAGE"; - - gHUD.m_Message.MessageAdd( msg->pName, gHUD.m_flTime); - - m_lastHudMessage++; - m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; - - } - - break; - - case DRC_CMD_SOUND : - string = READ_STRING(); - value = READ_FLOAT(); - - gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); - - break; - - case DRC_CMD_TIMESCALE : - value = READ_FLOAT(); - break; - - - - case DRC_CMD_STATUS: - READ_LONG(); // total number of spectator slots - m_iSpectatorNumber = READ_LONG(); // total number of spectator - READ_WORD(); // total number of relay proxies - - gViewPort->UpdateSpectatorPanel(); - break; - - case DRC_CMD_BANNER: - // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga - gViewPort->m_pSpectatorPanel->m_TopBanner->LoadImage( READ_STRING() ); - gViewPort->UpdateSpectatorPanel(); - break; - - case DRC_CMD_FADE: - break; - - case DRC_CMD_STUFFTEXT: - ClientCmd( READ_STRING() ); - break; - - default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); - } -} - -void CHudSpectator::FindNextPlayer(bool bReverse) -{ - // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching - // only a subset of the players. e.g. Make it check the target's team. - - int iStart; - cl_entity_t * pEnt = NULL; - - // if we are NOT in HLTV mode, spectator targets are set on server - if ( !gEngfuncs.IsSpectateOnly() ) - { - char cmdstring[32]; - // forward command to server - sprintf(cmdstring,"follownext %i",bReverse?1:0); - gEngfuncs.pfnServerCmd(cmdstring); - return; - } - - if ( g_iUser2 ) - iStart = g_iUser2; - else - iStart = 1; - - g_iUser2 = 0; - - int iCurrent = iStart; - - int iDir = bReverse ? -1 : 1; - - // make sure we have player info - gViewPort->GetAllPlayersInfo(); - - - do - { - iCurrent += iDir; - - // Loop through the clients - if (iCurrent > MAX_PLAYERS) - iCurrent = 1; - if (iCurrent < 1) - iCurrent = MAX_PLAYERS; - - pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); - - if ( !IsActivePlayer( pEnt ) ) - continue; - - // MOD AUTHORS: Add checks on target here. - - g_iUser2 = iCurrent; - break; - - } while ( iCurrent != iStart ); - - // Did we find a target? - if ( !g_iUser2 ) - { - gEngfuncs.Con_DPrintf( "No observer targets.\n" ); - // take save camera position - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); - } - else - { - // use new entity position for roaming - VectorCopy ( pEnt->origin, vJumpOrigin ); - VectorCopy ( pEnt->angles, vJumpAngles ); - } - iJumpSpectator = 1; -} - -void CHudSpectator::HandleButtonsDown( int ButtonPressed ) -{ - if ( !gViewPort ) - return; - - //Not in intermission. - if ( gHUD.m_iIntermission ) - return; - - if ( !g_iUser1 ) - return; // dont do anything if not in spectator mode - - // don't handle buttons during normal demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) - return; - - int theNewMainMode = g_iUser1; - - // Jump changes main window modes - if ( ButtonPressed & IN_JUMP ) - { - bool theFirstPerson = (g_iUser1 == OBS_IN_EYE); - bool theInOverviewMode = gHUD.m_Spectator.IsInOverviewMode(); - - // NS - if(gHUD.GetIsNSMode()) - { - // First-person full -> chase camera full -> firstperson with overview -> chase camera with overview - if(theFirstPerson && !theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - //gHUD.m_Spectator.SetOverviewMode(false); - } - else if(!theFirstPerson && !theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(true); - } - else if(theFirstPerson && theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - //gHUD.m_Spectator.SetOverviewMode(true); - } - else if(!theFirstPerson && theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(false); - } - } - // Combat - else - { - // First-person full -> chase camera full - if(theFirstPerson) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - gHUD.m_Spectator.SetOverviewMode(false); - } - else - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(false); - } - } - } - - //g_iUser1 = theNewMainMode; - - // Attack moves to the next player - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) - { - FindNextPlayer( (ButtonPressed & IN_MOVELEFT) ? true:false ); - -// if ( g_iUser1 == OBS_ROAMING ) -// { -// gEngfuncs.SetViewAngles( vJumpAngles ); -// iJumpSpectator = 1; -// -// } - - // lease directed mode if player want to see another player - m_autoDirector->value = 0.0f; - } - -/* - double time = gEngfuncs.GetClientTime(); - - int newMainMode = g_iUser1; - int newInsetMode = m_pip->value; - - // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); - if ( !gViewPort ) - return; - - //Not in intermission. - if ( gHUD.m_iIntermission ) - return; - - if ( !g_iUser1 ) - return; // dont do anything if not in spectator mode - - // don't handle buttons during normal demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) - return; - // Slow down mouse clicks. - if ( m_flNextObserverInput > time ) - return; - - // enable spectator screen - if ( ButtonPressed & IN_DUCK ) - { - gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); - } - - // 'Use' changes inset window mode - if ( ButtonPressed & IN_USE ) - { - newInsetMode = ToggleInset(true); - } - - // if not in HLTV mode, buttons are handled server side - if ( gEngfuncs.IsSpectateOnly() ) - { - // changing target or chase mode not in overviewmode without inset window - - // Jump changes main window modes - if ( ButtonPressed & IN_JUMP ) - { - if ( g_iUser1 == OBS_CHASE_LOCKED ) - newMainMode = OBS_CHASE_FREE; - - else if ( g_iUser1 == OBS_CHASE_FREE ) - newMainMode = OBS_IN_EYE; - - else if ( g_iUser1 == OBS_IN_EYE ) - newMainMode = OBS_ROAMING; - - else if ( g_iUser1 == OBS_ROAMING ) - newMainMode = OBS_MAP_FREE; - - else if ( g_iUser1 == OBS_MAP_FREE ) - newMainMode = OBS_MAP_CHASE; - - else - newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore - } - - // Attack moves to the next player - if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) - { - FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); - - if ( g_iUser1 == OBS_ROAMING ) - { - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - - } - // lease directed mode if player want to see another player - m_autoDirector->value = 0.0f; - } - } - - SetModes(newMainMode, newInsetMode); - - if ( g_iUser1 == OBS_MAP_FREE ) - { - if ( ButtonPressed & IN_FORWARD ) - m_zoomDelta = 0.01f; - - if ( ButtonPressed & IN_BACK ) - m_zoomDelta = -0.01f; - - if ( ButtonPressed & IN_MOVELEFT ) - m_moveDelta = -12.0f; - - if ( ButtonPressed & IN_MOVERIGHT ) - m_moveDelta = 12.0f; - } - - m_flNextObserverInput = time + 0.2; -*/ - -} - -void CHudSpectator::HandleButtonsUp( int ButtonPressed ) -{ - if ( !gViewPort ) - return; - - if ( !gViewPort->m_pSpectatorPanel->isVisible() ) - return; // dont do anything if not in spectator mode - - if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) - m_zoomDelta = 0.0f; - - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) - m_moveDelta = 0.0f; -} - -void CHudSpectator::SetMode(int iNewMainMode) -{ - // if value == -1 keep old value - if ( iNewMainMode == -1 ) - iNewMainMode = g_iUser1; - - // main modes ettings will override inset window settings - if ( iNewMainMode != g_iUser1 ) - { - // if we are NOT in HLTV mode, main spectator mode is set on server - if ( !gEngfuncs.IsSpectateOnly() ) - { - char cmdstring[32]; - // forward command to server - sprintf(cmdstring,"specmode %i",iNewMainMode ); - gEngfuncs.pfnServerCmd(cmdstring); - return; - } - else - { - if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target - { - // choose last Director object if still available - if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) - { - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } - else - { - FindNextPlayer(false); // find any target - } - } - - switch ( iNewMainMode ) - { - case OBS_CHASE_LOCKED: - g_iUser1 = OBS_CHASE_LOCKED; - break; - - case OBS_CHASE_FREE: - g_iUser1 = OBS_CHASE_FREE; - break; - - case OBS_ROAMING : // jump to current vJumpOrigin/angle - g_iUser1 = OBS_ROAMING; - if ( g_iUser2 ) - { - V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - } - break; - - case OBS_IN_EYE: - g_iUser1 = OBS_IN_EYE; - break; - - /* - case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - - case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - */ - } - - if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) - { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; - m_crosshairRect.bottom = 24; - - gHUD.SetCurrentCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); - } - else - { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); - gHUD.SetCurrentCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - //char string[128]; - //sprintf(string, "#Spec_Mode%d", g_iUser1 ); - //sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); - //gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); - } - } - - gViewPort->UpdateSpectatorPanel(); -} - -bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) -{ - return ( ent && - ent->player && - ent->curstate.solid != SOLID_NOT && - ent != gEngfuncs.GetLocalPlayer() && - g_PlayerInfoList[ent->index].name != NULL - ); -} - - -bool CHudSpectator::ParseOverviewFile( ) -{ - //char filename[255]; - //char levelname[255]; - //char token[1024]; - //float height; - - char *pfile = NULL; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - - // fill in standrd values - m_OverviewData.insetWindowX = 4; // upper left corner - m_OverviewData.insetWindowY = 4 + SPECTATOR_PANEL_HEIGHT; - m_OverviewData.insetWindowHeight = 180; - m_OverviewData.insetWindowWidth = 240; - m_OverviewData.origin[0] = 0.0f; - m_OverviewData.origin[1] = 0.0f; - m_OverviewData.origin[2] = 0.0f; - m_OverviewData.zoom = 1.0f; - m_OverviewData.layers = 0; - m_OverviewData.layersHeights[0] = 0.0f; - strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); - - if ( strlen( m_OverviewData.map ) == 0 ) - return false; // not active yet - - /* - strcpy(levelname, m_OverviewData.map + 5); - levelname[strlen(levelname)-4] = 0; - - sprintf(filename, "overviews/%s.txt", levelname ); - - pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); - - if (!pfile) - { - gEngfuncs.Con_Printf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); - return false; - } - - while (true) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - - if (!pfile) - break; - - if ( !stricmp( token, "global" ) ) - { - // parse the global data - pfile = gEngfuncs.COM_ParseFile(pfile, token); - if ( stricmp( token, "{" ) ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - while (stricmp( token, "}") ) - { - if ( !stricmp( token, "zoom" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.zoom = atof( token ); - } - else if ( !stricmp( token, "origin" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - m_OverviewData.origin[0] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.origin[1] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile, token); - m_OverviewData.origin[2] = atof( token ); - } - else if ( !stricmp( token, "rotated" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.rotated = atoi( token ); - } - else if ( !stricmp( token, "inset" ) ) - { - - // Removed by mmcguire. - // This isn't supported anymore. - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowX = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowY = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowWidth = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - //m_OverviewData.insetWindowHeight = atof( token ); - - } - else - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - - } - } - else if ( !stricmp( token, "layer" ) ) - { - // parse a layer data - - if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - - if ( stricmp( token, "{" ) ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - while (stricmp( token, "}") ) - { - if ( !stricmp( token, "image" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); - - - } - else if ( !stricmp( token, "height" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - height = atof(token); - m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; - } - else - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - } - - m_OverviewData.layers++; - - } - } - - gEngfuncs.COM_FreeFile( pfile ); - */ - - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - - return true; - -} - -void CHudSpectator::LoadMapSprites() -{ - // right now only support for one map layer - if (m_OverviewData.layers > 0 ) - { - m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); - } - else - m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead -} - -void CHudSpectator::DrawOverviewLayer() -{ - float screenaspect, xs, ys, xStep, yStep, x,y,z; - int ix,iy,i,xTiles,yTiles,frame; - - qboolean hasMapImage = m_MapSprite?TRUE:FALSE; - model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); - - if ( hasMapImage) - { - i = m_MapSprite->numframes / (4*3); - i = sqrt((float)i); - xTiles = i*4; - yTiles = i*3; - } - else - { - xTiles = 8; - yTiles = 6; - } - - - screenaspect = 4.0f/3.0f; - - - xs = m_OverviewData.origin[0]; - ys = m_OverviewData.origin[1]; - z = ( 90.0f - v_angles[0] ) / 90.0f; - z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; - - // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); - - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); - - frame = 0; - - - // rotated view ? - if ( m_OverviewData.rotated ) - { - xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; - - y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); - - for (iy = 0; iy < yTiles; iy++) - { - x = xs - (4096.0f / (m_OverviewData.zoom)); - - for (ix = 0; ix < xTiles; ix++) - { - if (hasMapImage) - gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); - else - gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); - gEngfuncs.pTriAPI->End(); - - frame++; - x+= xStep; - } - - y+=yStep; - } - } - else - { - xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; - - - x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); - - - - for (ix = 0; ix < yTiles; ix++) - { - - y = ys + (4096.0f / (m_OverviewData.zoom)); - - for (iy = 0; iy < xTiles; iy++) - { - if (hasMapImage) - gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); - else - gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); - gEngfuncs.pTriAPI->End(); - - frame++; - - y+=yStep; - } - - x+= xStep; - - } - } -} - -void CHudSpectator::DrawOverviewEntities() -{ - /* - int i,ir,ig,ib; - struct model_s *hSpriteModel; - vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; - float x,y,z, r,g,b, sizeScale = 4.0f; - cl_entity_t * ent; - float rmatrix[3][4]; // transformation matrix - - float zScale = (90.0f - v_angles[0] ) / 90.0f; - - - z = m_OverviewData.layersHeights[0] * zScale; - // get yellow/brown HUD color - //UnpackRGB(ir,ig,ib, RGB_YELLOWISH); - gHUD.GetPrimaryHudColor(ir, ig, ib); - r = (float)ir/255.0f; - g = (float)ig/255.0f; - b = (float)ib/255.0f; - - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - - for (i=0; i < MAX_PLAYERS; i++ ) - m_vPlayerPos[i][2] = -1; // mark as invisible - - // draw all players - - float depthOffset = 0; - - for (i=MAX_OVERVIEW_ENTITIES - 1; i >= 0; i--) - { - if ( !m_OverviewEntities[i].hSprite ) - continue; - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); - ent = m_OverviewEntities[i].entity; - - int theSpriteFrame = m_OverviewEntities[i].mFrame; - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, theSpriteFrame); - - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd); - - // see R_DrawSpriteModel - // draws players sprite - - AngleVectors(ent->angles, right, up, NULL ); - - VectorCopy(ent->origin,origin); - - // Set origin of blip to just above map height, so blips are all drawn on map - origin.z = m_OverviewData.layersHeights[0] + kOverviewEntityZHeight + depthOffset; - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - float gammaSlope = gHUD.GetGammaSlope(); - - gEngfuncs.pTriAPI->Color4f( - m_OverviewEntities[i].mColorR / gammaSlope, - m_OverviewEntities[i].mColorG / gammaSlope, - m_OverviewEntities[i].mColorB / gammaSlope, - 1); - - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (0,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (1,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->End (); - - - if ( !ent->player) - continue; - // draw line under player icons - origin[2] *= zScale; - - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); - - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); - - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); - - // calculate screen position for name and infromation in hud::draw() - if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) - continue; // object is behind viewer - - screen[0] = XPROJECT(screen[0]); - screen[1] = YPROJECT(screen[1]); - screen[2] = 0.0f; - - // calculate some offset under the icon - origin[0]+=32.0f; - origin[1]+=32.0f; - - gEngfuncs.pTriAPI->WorldToScreen(origin,offset); - - offset[0] = XPROJECT(offset[0]); - offset[1] = YPROJECT(offset[1]); - offset[2] = 0.0f; - - VectorSubtract(offset, screen, offset ); - - int playerNum = ent->index - 1; - - m_vPlayerPos[playerNum][0] = screen[0]; - m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); - m_vPlayerPos[playerNum][2] = 1; // mark player as visible - - - } - - if ( !m_pip || !m_drawcone->value ) - return; - - // get current camera position and angle - - if ( m_pip == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) - { - V_GetInEyePos( g_iUser2, origin, angles ); - } - else if ( m_pip == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) - { - V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); - } - else if ( g_iUser1 == OBS_ROAMING ) - { - VectorCopy( v_sim_org, origin ); - VectorCopy( v_cl_angles, angles ); - } - else - V_GetChasePos( g_iUser2, NULL, origin, angles ); - - - // draw camera sprite - - x = origin[0]; - y = origin[1]; - z = origin[2]; - - // Set origin of cone to just above map height, so blips are all drawn on map - z = m_OverviewData.layersHeights[0] + kOverviewEntityZHeight; - - angles[0] = 0; // always show horizontal camera sprite - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - - gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); - - AngleVectors(angles, forward, NULL, NULL ); - VectorScale (forward, 512.0f, forward); - - offset[0] = 0.0f; - offset[1] = 45.0f; - offset[2] = 0.0f; - - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , right ); - - offset[1]= -45.0f; - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , left ); - - gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); - gEngfuncs.pTriAPI->End (); - */ - -} - - - -void CHudSpectator::DrawOverview() -{ - /* - // draw only in sepctator mode - if ( !g_iUser1 ) - return; - - // Only draw the overview if Map Mode is selected for this view - if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) - return; - - if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) - return; - - DrawOverviewLayer(); - DrawOverviewEntities(); - CheckOverviewEntities(); - */ - -} - - - -void CHudSpectator::CheckOverviewEntities() -{ - double time = gEngfuncs.GetClientTime(); - - // removes old entities from list - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) - { - // remove entity from list if it is too old - if ( m_OverviewEntities[i].killTime < time ) - { - memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); - } - } -} - -bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) -{ - HSPRITE hSprite = 0; - double duration = -1.0f; // duration -1 means show it only this frame; - int theFrame = 0; - bool theSuccess = false; - int theRenderMode; - - if ( ent ) - { - - if (ent->curstate.solid != SOLID_NOT) - { - gHUD.GetSpriteForUser3(AvHUser3(ent->curstate.iuser3), hSprite, theFrame, theRenderMode); - } - - /* - if ( type == ET_PLAYER ) - { - if ( ent->curstate.solid != SOLID_NOT) - { - int thePlayerClass = g_PlayerExtraInfo[ent->index].playerclass; - switch(thePlayerClass) - { - case PLAYERCLASS_ALIVE_MARINE: - hSprite = this->m_hsprPlayerMarine; - theFrame = 0; - break; - case PLAYERCLASS_ALIVE_HEAVY_MARINE: - hSprite = this->m_hsprPlayerMarine; - theFrame = 1; - break; - case PLAYERCLASS_COMMANDER: - hSprite = this->m_hsprPlayerMarine; - theFrame = 2; - break; - case PLAYERCLASS_ALIVE_LEVEL1: - hSprite = this->m_hsprPlayerAlien; - theFrame = 0; - break; - case PLAYERCLASS_ALIVE_LEVEL2: - hSprite = this->m_hsprPlayerAlien; - theFrame = 1; - break; - case PLAYERCLASS_ALIVE_LEVEL3: - hSprite = this->m_hsprPlayerAlien; - theFrame = 2; - break; - case PLAYERCLASS_ALIVE_LEVEL4: - hSprite = this->m_hsprPlayerAlien; - theFrame = 3; - break; - case PLAYERCLASS_ALIVE_LEVEL5: - hSprite = this->m_hsprPlayerAlien; - theFrame = 4; - break; - case PLAYERCLASS_ALIVE_GESTATING: - hSprite = this->m_hsprPlayerAlien; - theFrame = 5; - break; - - case PLAYERCLASS_ALIVE_DIGESTING: - break; - } - } - else - { - // it's an spectator - } - } - else if (type == ET_NORMAL) - { - // Now help icons - if(hSprite == 0) - { - AvHUser3 theUser3 = AvHUser3(ent->curstate.iuser3); - theFrame = gHUD.GetHelpIconFrameFromUser3(theUser3); - if(theFrame != -1) - { - hSprite = gHUD.GetHelpSprite(); - } - } - } - */ - } - - if(hSprite > 0) - { - - int theTeam = ent->curstate.team; - - float theR = kFTeamColors[theTeam][0]; - float theG = kFTeamColors[theTeam][1]; - float theB = kFTeamColors[theTeam][2]; - - theSuccess = AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration, theFrame, theRenderMode, theR, theG, theB); - - } - - return theSuccess; -} - -void CHudSpectator::DeathMessage(int victim) -{ - // find out where the victim is - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); - - if (pl && pl->player) - AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f, 0, kRenderTransTexture, 1, 1, 1); -} - -bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime, int inFrame, int inRenderMode, float r, float g, float b) -{ - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) - { - // find empty entity slot - if ( m_OverviewEntities[i].entity == NULL) - { - m_OverviewEntities[i].entity = ent; - m_OverviewEntities[i].hSprite = sprite; - m_OverviewEntities[i].killTime = killTime; - m_OverviewEntities[i].mFrame = inFrame; - m_OverviewEntities[i].mRenderMode = inRenderMode; - m_OverviewEntities[i].mColorR = r; - m_OverviewEntities[i].mColorG = g; - m_OverviewEntities[i].mColorB = b; - return true; - } - } - - return false; // maximum overview entities reached -} -void CHudSpectator::CheckSettings() -{ - // disallow same inset mode as main mode: - - //m_pip->value = floor(m_pip->value); - - // Removed by mmcguire. - /* - if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_LOCKED || m_pip->value == INSET_IN_EYE ) ) - { - // otherwise both would show in World picures - m_pip->value = INSET_OFF; - } - - // disble in intermission screen - if ( gHUD.m_iIntermission ) - m_pip->value = INSET_OFF; - */ - - // check chat mode - if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) - { - // hud_saytext changed - m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); - - if ( gEngfuncs.IsSpectateOnly() ) - { - // tell proxy our new chat mode - char chatcmd[32]; - sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); - gEngfuncs.pfnServerCmd(chatcmd); - } - } - - // HL/TFC has no oberserver corsshair, so set it client side - if ( g_iUser1 == OBS_IN_EYE ) - { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; - m_crosshairRect.bottom = 24; - - gHUD.SetCurrentCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); - } - else - { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); - gHUD.SetCurrentCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - // Removed by mmcguire. - /* - // if we are a real player on server don't allow inset window - // in First Person mode since this is our resticted forcecamera mode 2 - // team number 3 = SPECTATOR see player.h - - if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) - m_pip->value = INSET_OFF; - */ - - // draw small border around inset view, adjust upper black bar - //gViewPort->m_pSpectatorPanel->EnableInsetView( m_pip->value != INSET_OFF ); - gViewPort->m_pSpectatorPanel->EnableInsetView( IsInOverviewMode() ); - -} - - -void CHudSpectator::Reset() -{ - // Reset HUD - if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) - { - // update level overview if level changed - ParseOverviewFile(); - LoadMapSprites(); - } - - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - - SetSpectatorStartPosition(); -} - -void CHudSpectator::InitHUDData() -{ - gHUD.InitHUDData(); - m_lastPrimaryObject = m_lastSecondaryObject = 0; - m_flNextObserverInput = 0.0f; - m_lastHudMessage = 0; - m_iSpectatorNumber = 0; - iJumpSpectator = 0; - g_iUser1 = g_iUser2 = 0; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - - if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) - m_autoDirector->value = 1.0f; - else - m_autoDirector->value = 0.0f; - - Reset(); - - SetMode( OBS_CHASE_FREE); - - g_iUser2 = 0; // fake not target until first camera command - - // reset HUD FOV - gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); -} - diff --git a/main/source/cl_dll/hud_spectator.h b/main/source/cl_dll/hud_spectator.h index 91816a17..d15e4062 100644 --- a/main/source/cl_dll/hud_spectator.h +++ b/main/source/cl_dll/hud_spectator.h @@ -1,143 +1,143 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef SPECTATOR_H -#define SPECTATOR_H -#pragma once - -#include "cl_entity.h" - -// Removed by mmcguire. -/* -#define INSET_OFF 0 -#define INSET_CHASE_LOCKED 1 -#define INSET_IN_EYE 2 -*/ - -#define MAX_SPEC_HUD_MESSAGES 8 - - - -#define OVERVIEW_TILE_SIZE 128 // don't change this -#define OVERVIEW_MAX_LAYERS 1 - -//----------------------------------------------------------------------------- -// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) -//----------------------------------------------------------------------------- - -typedef struct overviewInfo_s { - char map[64]; // cl.levelname or empty - vec3_t origin; // center of map - float zoom; // zoom of map images - int layers; // how may layers do we have - float layersHeights[OVERVIEW_MAX_LAYERS]; - char layersImages[OVERVIEW_MAX_LAYERS][255]; - qboolean rotated; // are map images rotated (90 degrees) ? - - int insetWindowX; - int insetWindowY; - int insetWindowHeight; - int insetWindowWidth; -} overviewInfo_t; - -typedef struct overviewEntity_s { - - HSPRITE hSprite; - struct cl_entity_s * entity; - double killTime; - int mFrame; - int mRenderMode; - float mColorR; - float mColorG; - float mColorB; -} overviewEntity_t; - -#define MAX_OVERVIEW_ENTITIES 256 -const int kOverviewEntityZHeight = 100; - -class CHudSpectator : public CHudBase -{ -public: - void Reset(); - void CheckSettings(); - void InitHUDData( void ); - bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime, int inFrame, int inRenderMode, float r, float g, float b); - void DeathMessage(int victim); - bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); - void CheckOverviewEntities(); - void DrawOverview(); - void DrawOverviewEntities(); - void GetMapPosition( float * returnvec ); - void DrawOverviewLayer(); - void LoadMapSprites(); - bool ParseOverviewFile(); - bool IsActivePlayer(cl_entity_t * ent); - void SetMode(int iMainMode); - void HandleButtonsDown(int ButtonPressed); - void HandleButtonsUp(int ButtonPressed); - void FindNextPlayer( bool bReverse ); - void DirectorMessage( int iSize, void *pbuf ); - void SetSpectatorStartPosition(); - int Init(); - int VidInit(); - - bool IsInOverviewMode() const; - void SetOverviewMode(bool overviewMode); - - int Draw(float flTime); - void DrawOverviewMap(); - - int m_iDrawCycle; - client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; - char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; - int m_lastHudMessage; - overviewInfo_t m_OverviewData; - overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; - int m_iObserverFlags; - int m_iSpectatorNumber; - - float m_mapZoom; // zoom the user currently uses - vec3_t m_mapOrigin; // origin where user rotates around - cvar_t * m_drawnames; - cvar_t * m_drawcone; - cvar_t * m_drawstatus; - cvar_t * m_autoDirector; - - // Removed by mmcguire. - bool m_overviewMode; - //cvar_t * m_overview; - //cvar_t * m_pip; - - - qboolean m_chatEnabled; - - vec3_t m_cameraOrigin; // a help camera - vec3_t m_cameraAngles; // and it's angles - -private: - vec3_t m_vPlayerPos[MAX_PLAYERS]; - HSPRITE m_hsprPlayerMarine; - HSPRITE m_hsprPlayerAlien; - HSPRITE m_hsprCamera; - HSPRITE m_hsprPlayerDead; - HSPRITE m_hsprViewcone; - HSPRITE m_hsprUnkownMap; - HSPRITE m_hsprBeam; - HSPRITE m_hCrosshair; - HSPRITE m_hsprWhite; - - wrect_t m_crosshairRect; - - struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame - float m_flNextObserverInput; - float m_zoomDelta; - float m_moveDelta; - int m_lastPrimaryObject; - int m_lastSecondaryObject; -}; - -#endif // SPECTATOR_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SPECTATOR_H +#define SPECTATOR_H +#pragma once + +#include "cl_entity.h" + +// Removed by mmcguire. +/* +#define INSET_OFF 0 +#define INSET_CHASE_LOCKED 1 +#define INSET_IN_EYE 2 +*/ + +#define MAX_SPEC_HUD_MESSAGES 8 + + + +#define OVERVIEW_TILE_SIZE 128 // don't change this +#define OVERVIEW_MAX_LAYERS 1 + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) +//----------------------------------------------------------------------------- + +typedef struct overviewInfo_s { + char map[64]; // cl.levelname or empty + vec3_t origin; // center of map + float zoom; // zoom of map images + int layers; // how may layers do we have + float layersHeights[OVERVIEW_MAX_LAYERS]; + char layersImages[OVERVIEW_MAX_LAYERS][255]; + qboolean rotated; // are map images rotated (90 degrees) ? + + int insetWindowX; + int insetWindowY; + int insetWindowHeight; + int insetWindowWidth; +} overviewInfo_t; + +typedef struct overviewEntity_s { + + HSPRITE hSprite; + struct cl_entity_s * entity; + double killTime; + int mFrame; + int mRenderMode; + float mColorR; + float mColorG; + float mColorB; +} overviewEntity_t; + +#define MAX_OVERVIEW_ENTITIES 256 +const int kOverviewEntityZHeight = 100; + +class CHudSpectator : public CHudBase +{ +public: + void Reset(); + void CheckSettings(); + void InitHUDData( void ); + bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime, int inFrame, int inRenderMode, float r, float g, float b); + void DeathMessage(int victim); + bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void CheckOverviewEntities(); + void DrawOverview(); + void DrawOverviewEntities(); + void GetMapPosition( float * returnvec ); + void DrawOverviewLayer(); + void LoadMapSprites(); + bool ParseOverviewFile(); + bool IsActivePlayer(cl_entity_t * ent); + void SetMode(int iMainMode); + void HandleButtonsDown(int ButtonPressed); + void HandleButtonsUp(int ButtonPressed); + void FindNextPlayer( bool bReverse ); + void DirectorMessage( int iSize, void *pbuf ); + void SetSpectatorStartPosition(); + int Init(); + int VidInit(); + + bool IsInOverviewMode() const; + void SetOverviewMode(bool overviewMode); + + int Draw(float flTime); + void DrawOverviewMap(); + + int m_iDrawCycle; + client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; + char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; + int m_lastHudMessage; + overviewInfo_t m_OverviewData; + overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; + int m_iObserverFlags; + int m_iSpectatorNumber; + + float m_mapZoom; // zoom the user currently uses + vec3_t m_mapOrigin; // origin where user rotates around + cvar_t * m_drawnames; + cvar_t * m_drawcone; + cvar_t * m_drawstatus; + cvar_t * m_autoDirector; + + // Removed by mmcguire. + bool m_overviewMode; + //cvar_t * m_overview; + //cvar_t * m_pip; + + + qboolean m_chatEnabled; + + vec3_t m_cameraOrigin; // a help camera + vec3_t m_cameraAngles; // and it's angles + +private: + vec3_t m_vPlayerPos[MAX_PLAYERS]; + HSPRITE m_hsprPlayerMarine; + HSPRITE m_hsprPlayerAlien; + HSPRITE m_hsprCamera; + HSPRITE m_hsprPlayerDead; + HSPRITE m_hsprViewcone; + HSPRITE m_hsprUnkownMap; + HSPRITE m_hsprBeam; + HSPRITE m_hCrosshair; + HSPRITE m_hsprWhite; + + wrect_t m_crosshairRect; + + struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame + float m_flNextObserverInput; + float m_zoomDelta; + float m_moveDelta; + int m_lastPrimaryObject; + int m_lastSecondaryObject; +}; + +#endif // SPECTATOR_H diff --git a/main/source/cl_dll/hud_update.cpp b/main/source/cl_dll/hud_update.cpp index 7210fc28..18e2cb82 100644 --- a/main/source/cl_dll/hud_update.cpp +++ b/main/source/cl_dll/hud_update.cpp @@ -1,52 +1,102 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// hud_update.cpp -// - -#include -#include "hud.h" -#include "cl_util.h" -#include -#include - -int CL_ButtonBits( int ); -void CL_ResetButtonBits( int bits ); - -extern float v_idlescale; -float in_fov; -extern void HUD_SetCmdBits( int bits ); - -int CHud::UpdateClientData(client_data_t *cdata, float time) -{ - memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); - memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); - - m_iKeyBits = CL_ButtonBits( 0 ); - m_iWeaponBits = cdata->iWeaponBits; - - in_fov = cdata->fov; - - Think(); - - cdata->fov = m_iFOV; - - CL_ResetButtonBits( m_iKeyBits ); - - // return 1 if in anything in the client_data struct has been changed, 0 otherwise - return 1; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud_update.cpp +// + +#include +#include "hud.h" +#include "cl_util.h" +#include +#include + +int CL_ButtonBits( int ); +void CL_ResetButtonBits( int bits ); + +extern float v_idlescale; +float in_fov; +extern void HUD_SetCmdBits( int bits ); + +int CHud::UpdateClientData(client_data_t *cdata, float time) +{ + memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); + memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); + + m_iKeyBits = CL_ButtonBits( 0 ); + m_iWeaponBits = cdata->iWeaponBits; + + in_fov = cdata->fov; + + Think(); + + //cdata->fov = m_iFOV; + + float width = ScreenWidth(); + float height = ScreenHeight(); + + //horizontal+ widescreen view correction - engine uses vertical- + //starts with hacked in commander view fix where commander fov was changed to 106 so the black background beind the map is fully rendered - remove that section and change comm fov back to 90 if fixed + if (gHUD.GetIsInTopDownMode()) + { + float commFOV; + + commFOV = atanf(tan(m_iFOV * M_PI / 360) * 0.5625 * width / height) * 360 / M_PI; + + //clamp + if (commFOV > 107) + { + commFOV = 106; + } + else if (commFOV < 90) + { + commFOV = 90; + } + + cdata->fov = commFOV; + } + else + { + float newFOV; + + newFOV = atanf(tan(m_iFOV * M_PI / 360) * 0.75 * width / height) * 360 / M_PI; + + //clamp for game balance + if (m_iFOV == 105 && newFOV > 121) + { + newFOV = 120; + } + else if (m_iFOV == 100 && newFOV > 117) + { + newFOV = 116; + } + else if (m_iFOV == 90 && newFOV > 107) + { + newFOV = 106; + } + else if (newFOV < 90) + { + newFOV = 90; + } + + cdata->fov = newFOV; + } + + CL_ResetButtonBits( m_iKeyBits ); + + // return 1 if in anything in the client_data struct has been changed, 0 otherwise + return 1; +} + + diff --git a/main/source/cl_dll/in_defs.h b/main/source/cl_dll/in_defs.h index 60d99feb..00b4da58 100644 --- a/main/source/cl_dll/in_defs.h +++ b/main/source/cl_dll/in_defs.h @@ -1,12 +1,12 @@ -#if !defined( IN_DEFSH ) -#define IN_DEFSH -#pragma once - -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 - +#if !defined( IN_DEFSH ) +#define IN_DEFSH +#pragma once + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + #endif \ No newline at end of file diff --git a/main/source/cl_dll/input.cpp b/main/source/cl_dll/input.cpp index 9a49979f..9c3bd65c 100644 --- a/main/source/cl_dll/input.cpp +++ b/main/source/cl_dll/input.cpp @@ -1,1576 +1,1576 @@ -//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= -// -// The copyright to the contents herein is the property of Charles G. Cleveland. -// The contents may be used and/or copied only with the written permission of -// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: input.cpp $ -// $Date: 2002/10/16 02:12:21 $ -// -//------------------------------------------------------------------------------- -// $Log: input.cpp,v $ -// Revision 1.28 2002/10/16 02:12:21 Flayra -// - Valve anti-cheat integrated! -// -// Revision 1.27 2002/08/09 00:13:04 Flayra -// - Removed explicitly allowing specific commands. I can't remember why this was needed, but it doesn't appear to be anymore. -// -// Revision 1.26 2002/08/02 21:39:03 Flayra -// - Refactored variable names -// -// Revision 1.25 2002/07/08 16:13:31 Flayra -// - Fixed bug where command was able to switch weapons via mousewheel (bug #239) -// -//=============================================================================== -// cl.input.c -- builds an intended movement command to send to the server - -//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed - -// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All -// rights reserved. -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -extern "C" -{ -#include "kbutton.h" -} -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" -#include "camera.h" -#include "in_defs.h" -#include "view.h" -#include "bench.h" -#include -#include -#include "engine/keydefs.h" -#include "Exports.h" - -#include "vgui_TeamFortressViewport.h" -#include "mod/AvHServerVariables.h"// should we go ahead and just make a SharedVariables.h instead? -#include "mod/AvHClientVariables.h" -#include "mod/AvHMessage.h" -#include "winsani_in.h" -#include "fmod.h" -#include "winsani_out.h" -#include "mod/AvHScriptManager.h" -#include "mod/AvHScrollHandler.h" -#include "mod/AvHCommanderModeHandler.h" -#include "util/Mat3.h" - -#include "engine/APIProxy.h" -#include "Exports.h" - -// : duck toggle -extern bool g_bDuckToggled; -// : - -extern int g_iAlive; - -extern int g_weaponselect; -extern cl_enginefunc_t gEngfuncs; -bool gResetViewAngles = false; -vec3_t gViewAngles; -extern AvHCommanderModeHandler gCommanderHandler; - -/////////////////////////////// -// Begin Max's Code -/////////////////////////////// - -float gPlayerAngles[3] = { 0, 0, 0 }; -float gTargetPlayerAngles[3] = { 0, 0, 0 }; -float gWorldViewAngles[3] = { 0, 0, 0 }; - -/////////////////////////////// -// End Max's Code -/////////////////////////////// - -// Defined in pm_math.c -//extern "C" float anglemod( float a ); -float anglemod( float a ); - -void IN_Init (void); -void IN_Move ( float frametime, usercmd_t *cmd); -void IN_Shutdown( void ); -void V_Init( void ); -void VectorAngles( const float *forward, float *angles ); -int CL_ButtonBits( int ); - -// xxx need client dll function to get and clear impuse -extern cvar_t *in_joystick; - -int in_impulse = 0; -int in_cancel = 0; - -cvar_t *m_pitch; -cvar_t *m_yaw; -cvar_t *m_forward; -cvar_t *m_side; - -cvar_t *lookstrafe; -cvar_t *lookspring; -cvar_t *cl_pitchup; -cvar_t *cl_pitchdown; -cvar_t *cl_upspeed; -cvar_t *cl_forwardspeed; -cvar_t *cl_backspeed; -cvar_t *cl_sidespeed; -cvar_t *cl_movespeedkey; -cvar_t *cl_yawspeed; -cvar_t *cl_pitchspeed; -cvar_t *cl_anglespeedkey; -cvar_t *cl_vsmoothing; -cvar_t *cl_autohelp; -cvar_t *cl_centerentityid; -cvar_t *cl_musicenabled; -cvar_t *cl_musicdelay; -cvar_t *cl_musicvolume; -cvar_t *cl_musicdir; -cvar_t *cl_quickselecttime; -cvar_t *cl_highdetail; -cvar_t *cl_cmhotkeys; -cvar_t *cl_forcedefaultfov; -cvar_t *cl_dynamiclights; -cvar_t *cl_buildmessages; -cvar_t *cl_particleinfo; - -/* -=============================================================================== - -KEY BUTTONS - -Continuous button event tracking is complicated by the fact that two different -input sources (say, mouse button 1 and the control key) can both press the -same button, but the button should only be released when both of the -pressing key have been released. - -When a key event issues a button command (+forward, +attack, etc), it appends -its key number as a parameter to the command so it can be matched up with -the release. - -state bit 0 is the current state of the key -state bit 1 is edge triggered on the up to down transition -state bit 2 is edge triggered on the down to up transition - -=============================================================================== -*/ - - -kbutton_t in_mlook; -kbutton_t in_klook; -kbutton_t in_jlook; -kbutton_t in_left; -kbutton_t in_right; -kbutton_t in_forward; -kbutton_t in_back; -kbutton_t in_lookup; -kbutton_t in_lookdown; -kbutton_t in_moveleft; -kbutton_t in_moveright; -kbutton_t in_strafe; -kbutton_t in_speed; -kbutton_t in_use; -kbutton_t in_jump; -kbutton_t in_attack; -kbutton_t in_attack2; -kbutton_t in_up; -kbutton_t in_down; -kbutton_t in_duck; -kbutton_t in_reload; -kbutton_t in_alt1; -kbutton_t in_score; -kbutton_t in_break; -kbutton_t in_graph; // Display the netgraph - -typedef struct kblist_s -{ - struct kblist_s *next; - kbutton_t *pkey; - char name[32]; -} kblist_t; - -kblist_t *g_kbkeys = NULL; - -vector< pair > g_PrevCmds; - -/* -============ -KB_ConvertString - -Removes references to +use and replaces them with the keyname in the output string. If - a binding is unfound, then the original text is retained. -NOTE: Only works for text with +word in it. -============ -*/ -int KB_ConvertString( char *in, char **ppout ) -{ - char sz[ 4096 ]; - char binding[ 64 ]; - char *p; - char *pOut; - char *pEnd; - const char *pBinding; - - if ( !ppout ) - return 0; - - *ppout = NULL; - p = in; - pOut = sz; - while ( *p ) - { - if ( *p == '+' ) - { - pEnd = binding; - while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) - { - *pEnd++ = *p++; - } - - *pEnd = '\0'; - - pBinding = NULL; - if ( strlen( binding + 1 ) > 0 ) - { - // See if there is a binding for binding? - pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); - } - - if ( pBinding ) - { - *pOut++ = '['; - pEnd = (char *)pBinding; - } - else - { - pEnd = binding; - } - - while ( *pEnd ) - { - *pOut++ = *pEnd++; - } - - if ( pBinding ) - { - *pOut++ = ']'; - } - } - else - { - *pOut++ = *p++; - } - } - - *pOut = '\0'; - - pOut = ( char * )malloc( strlen( sz ) + 1 ); - strcpy( pOut, sz ); - *ppout = pOut; - - return 1; -} - -/* -============ -KB_Find - -Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files -============ -*/ -struct kbutton_s CL_DLLEXPORT *KB_Find( const char *name ) -{ -// RecClFindKey(name); - - kblist_t *p; - p = g_kbkeys; - while ( p ) - { - if ( !stricmp( name, p->name ) ) - return p->pkey; - - p = p->next; - } - return NULL; -} - -/* -============ -KB_Add - -Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find -============ -*/ -void KB_Add( const char *name, kbutton_t *pkb ) -{ - kblist_t *p; - kbutton_t *kb; - - kb = KB_Find( name ); - - if ( kb ) - return; - - p = ( kblist_t * )malloc( sizeof( kblist_t ) ); - memset( p, 0, sizeof( *p ) ); - - strcpy( p->name, name ); - p->pkey = pkb; - - p->next = g_kbkeys; - g_kbkeys = p; -} - -/* -============ -KB_Init - -Add kbutton_t definitions that the engine can query if needed -============ -*/ -void KB_Init( void ) -{ - g_kbkeys = NULL; - - KB_Add( "in_graph", &in_graph ); - KB_Add( "in_mlook", &in_mlook ); - KB_Add( "in_jlook", &in_jlook ); -} - -/* -============ -KB_Shutdown - -Clear kblist -============ -*/ -void KB_Shutdown( void ) -{ - kblist_t *p, *n; - p = g_kbkeys; - while ( p ) - { - n = p->next; - free( p ); - p = n; - } - g_kbkeys = NULL; -} - -/* -============ -KeyDown -============ -*/ -void KeyDown (kbutton_t *b) -{ - int k; - char *c; - - c = gEngfuncs.Cmd_Argv(1); - if (c[0]) - k = atoi(c); - else - k = -1; // typed manually at the console for continuous down - - int theBlockScripts = (int)gHUD.GetServerVariableFloat(kvBlockScripts); - - char *pCmd = gEngfuncs.Cmd_Argv(0); - - if(theBlockScripts && pCmd) - { - bool bFound = false; - - //Check thier last few commands (this prevents false positives if a player is hits several keys real fast) - for (int i = 0; i < g_PrevCmds.size(); i++) - { - //Check both the key pressed and the command it executed. - if(k == g_PrevCmds[i].first && !strcmp(pCmd, g_PrevCmds[i].second.c_str())) - { - bFound = true; - break; - } - } - - - if(!bFound - && strcmp(pCmd, "+mlook") - && strcmp(pCmd, "+jlook") - && strcmp(pCmd, "+showscores") - && strcmp(pCmd, "+use")) - { - gEngfuncs.pfnCenterPrint("Scripting is not allowed on this server."); - b->down[0] = b->down[1] = 0; - b->state = 4; // impulse up - return; - } - } - - if (k == b->down[0] || k == b->down[1]) - return; // repeating key - - if (!b->down[0]) - b->down[0] = k; - else if (!b->down[1]) - b->down[1] = k; - else - { - gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); - return; - } - - if (b->state & 1) - return; // still down - b->state |= 1 + 2; // down + impulse down -} - -/* -============ -KeyDownForced -============ -*/ -void KeyDownForced (kbutton_t *b) -{ - b->down[0] = 0; - b->down[1] = 0; - - if (b->state & 1) - return; // still down - b->state |= 1 + 2; // down + impulse down -} - -/* -============ -KeyUp -============ -*/ -void KeyUp (kbutton_t *b) -{ - int k; - char *c; - - c = gEngfuncs.Cmd_Argv(1); - if (c[0]) - k = atoi(c); - else - { // typed manually at the console, assume for unsticking, so clear all - b->down[0] = b->down[1] = 0; - b->state = 4; // impulse up - return; - } - - if (b->down[0] == k) - b->down[0] = 0; - else if (b->down[1] == k) - b->down[1] = 0; - else - return; // key up without coresponding down (menu pass through) - if (b->down[0] || b->down[1]) - { - //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); - return; // some other key is still holding it down - } - - if (!(b->state & 1)) - return; // still up (this should not happen) - - b->state &= ~1; // now up - b->state |= 4; // impulse up -} - -/* -============ -KeyUpForced -============ -*/ -void KeyUpForced (kbutton_t *b) -{ - b->state &= ~1; // now up - b->state |= 4; // impulse up -} - -bool AvHContainsBlockedCommands(const char* inInput) -{ - if (inInput == NULL) - { - return false; - } - - const char* kBlockedCommand[] = - { - "exec", - "wait", - "special", - "_special" - }; - - // Check for a ; indicating multiple commands. - - if (strchr(inInput, ';') != NULL) - { - return true; - } - - // Check if any of the blocked commands are being used. - - const char* theCommandEnd = strpbrk(inInput, " \t"); - - int theCommandLength; - - if (theCommandEnd == NULL) - { - theCommandLength = (int)strlen(inInput); - } - else - { - theCommandLength = theCommandEnd - inInput; - } - - for (int i = 0; i < sizeof(kBlockedCommand) / sizeof(const char*); ++i) - { - if ((int)strlen(kBlockedCommand[i]) == theCommandLength && - strncmp(inInput, kBlockedCommand[i], theCommandLength) == 0) - { - return true; - } - } - return false; -} - -/* -============ -HUD_Key_Event - -Return 1 to allow engine to process the key, otherwise, act on it as needed -============ -*/ -int CL_DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) -{ -// RecClKeyEvent(down, keynum, pszCurrentBinding); - - // Check to see if the event has any outlawed commands in it. - float theBlockScripts = gHUD.GetServerVariableFloat(kvBlockScripts); - - if (theBlockScripts && AvHContainsBlockedCommands(pszCurrentBinding)) - { - if(down)//: only show when going down. - gEngfuncs.pfnCenterPrint("Scripting is not allowed on this server.\n"); - return 0; - } - - if(pszCurrentBinding) - { - if(g_PrevCmds.size() >= 5) - g_PrevCmds.erase(g_PrevCmds.begin());//remove the oldest command - - g_PrevCmds.push_back(make_pair(keynum, (string)pszCurrentBinding)); - } - - int theProcessKeyBinding = 1; - -// char theKeyBinding[256] = "none"; -// if(pszCurrentBinding) -// { -// sprintf(theKeyBinding, pszCurrentBinding); -// } -// -// char theMessage[512]; -// sprintf(theMessage, "%s (down: %d, keynum %d)", theKeyBinding, down, keynum); -// CenterPrint(theMessage); - - if(gViewPort /*&& gViewPort->IsOptionsMenuVisible()*/) - { - - theProcessKeyBinding = gViewPort->KeyInput(down, keynum, pszCurrentBinding); - - if(pszCurrentBinding && (!strcmp(pszCurrentBinding, "toggleconsole") || !strcmp(pszCurrentBinding, "cancelselect"))) - { - theProcessKeyBinding = 1; - } - } - - - // Process topdown commands with precedence first - if(theProcessKeyBinding && gHUD.GetInTopDownMode()) - { - if((keynum != 0) && down/*&& pszCurrentBinding*/) - { - AvHMessageID theMessageID = gHUD.HotKeyHit(keynum); - if((theMessageID != MESSAGE_NULL) || (keynum == K_ESCAPE)) - { - // If ESC or cancel was hit, cancel ghost building - if((keynum == K_ESCAPE) || (theMessageID == MESSAGE_CANCEL)) - { - gHUD.SetGhostBuildingMode(MESSAGE_NULL); - } - - theProcessKeyBinding = 0; - } - } - } - - if(theProcessKeyBinding) - { - // Process only a couple keybindings in top down mode -// if(!gHUD.GetInTopDownMode() || (pszCurrentBinding && -// -// // Misc. commands -// (!strcmp(pszCurrentBinding, "toggleconsole") || !strcmp(pszCurrentBinding, "cancelselect") || !strcmp(pszCurrentBinding, "+showscores") || !strcmp(pszCurrentBinding, "-showscores") || !strcmp(pszCurrentBinding, "messagemode") || !strcmp(pszCurrentBinding, "messagemode2") || !strcmp(pszCurrentBinding, "snapshot") || !strcmp(pszCurrentBinding, "screenshot") || !strcmp(pszCurrentBinding, "+jump") || !strcmp(pszCurrentBinding, "addbot") || !strcmp(pszCurrentBinding, "+voicerecord") || !strcmp(pszCurrentBinding, "-voicerecord") || -// -// // Movement commands -// !strcmp(pszCurrentBinding, "testevent") /*|| !strcmp(pszCurrentBinding, "invnext") || !strcmp(pszCurrentBinding, "invprev")*/ || !strcmp(pszCurrentBinding, "+moveleft") || !strcmp(pszCurrentBinding, "-moveleft") || !strcmp(pszCurrentBinding, "+moveright") || !strcmp(pszCurrentBinding, "-moveright") || !strcmp(pszCurrentBinding, "+moveup") || !strcmp(pszCurrentBinding, "-moveup") || !strcmp(pszCurrentBinding, "+movedown") || !strcmp(pszCurrentBinding, "-movedown") || -// -// // For selecting groups -// !strcmp(pszCurrentBinding, "slot1") || !strcmp(pszCurrentBinding, "slot2") || !strcmp(pszCurrentBinding, "slot3") || !strcmp(pszCurrentBinding, "slot4") || !strcmp(pszCurrentBinding, "slot5") || -// -// // For creating groups -// !strcmp(pszCurrentBinding, "+duck") || !strcmp(pszCurrentBinding, "-duck") || -// -// // For testing ease -// !strcmp(pszCurrentBinding, "givepoints") -// -// ))) -// { - if (gViewPort) - theProcessKeyBinding = gViewPort->KeyInput(down, keynum, pszCurrentBinding); - -// // Don't -// if(!strcmp(pszCurrentBinding, "+jump") && gHUD.GetInTopDownMode()) -// { -// gHUD.GotoAlert(); -// } - -// } - } - - return theProcessKeyBinding; -} - -void IN_BreakDown( void ) { KeyDown( &in_break );}; -void IN_BreakUp( void ) { KeyUp( &in_break ); }; -void IN_KLookDown (void) {KeyDown(&in_klook);} -void IN_KLookUp (void) {KeyUp(&in_klook);} -void IN_JLookDown (void) {KeyDown(&in_jlook);} -void IN_JLookUp (void) {KeyUp(&in_jlook);} -void IN_MLookDown (void) {KeyDown(&in_mlook);} -void IN_UpDown(void) {KeyDown(&in_up);} -void IN_UpUp(void) {KeyUp(&in_up);} -void IN_DownDown(void) {KeyDown(&in_down);} -void IN_DownUp(void) {KeyUp(&in_down);} -void IN_LeftDown(void) {KeyDown(&in_left);} -void IN_LeftUp(void) {KeyUp(&in_left);} -void IN_RightDown(void) {KeyDown(&in_right);} -void IN_RightUp(void) {KeyUp(&in_right);} - -void IN_ForwardDown(void) -{ - KeyDown(&in_forward); - gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); -} - -void IN_ForwardUp(void) -{ - KeyUp(&in_forward); - gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); -} - -void IN_BackDown(void) -{ - KeyDown(&in_back); - gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); -} - -void IN_BackUp(void) -{ - KeyUp(&in_back); - gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); -} -void IN_LookupDown(void) {KeyDown(&in_lookup);} -void IN_LookupUp(void) {KeyUp(&in_lookup);} -void IN_LookdownDown(void) {KeyDown(&in_lookdown);} -void IN_LookdownUp(void) {KeyUp(&in_lookdown);} -void IN_MoveleftDown(void) -{ - KeyDown(&in_moveleft); - gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); -} - -void IN_MoveleftUp(void) -{ - KeyUp(&in_moveleft); - gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); -} - -void IN_MoverightDown(void) -{ - KeyDown(&in_moveright); - gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); -} - -void IN_MoverightUp(void) -{ - KeyUp(&in_moveright); - gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); -} -void IN_SpeedDown(void) {KeyDown(&in_speed);} -void IN_SpeedUp(void) {KeyUp(&in_speed);} -void IN_StrafeDown(void) {KeyDown(&in_strafe);} -void IN_StrafeUp(void) {KeyUp(&in_strafe);} - -// needs capture by hud/vgui also -extern void __CmdFunc_InputPlayerSpecial(void); -void IN_Attack2Down(void) {KeyDownForced(&in_attack2);} -void IN_Attack2Up(void) {KeyUpForced(&in_attack2);} -void IN_UseDown (void) -{ - KeyDown(&in_use); - gHUD.m_Spectator.HandleButtonsDown( IN_USE ); -} -void IN_UseUp (void) {KeyUp(&in_use);} -void IN_JumpDown (void) -{ - KeyDown(&in_jump); - gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); - -} - -void IN_JumpUp (void) -{ - KeyUp(&in_jump); - gHUD.m_Spectator.HandleButtonsUp( IN_JUMP ); -} - -void IN_DuckDown(void) -{ - KeyDown(&in_duck); - gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); -} - -void IN_DuckUp(void) {KeyUp(&in_duck);} -// : duck toggle -void IN_DuckToggle(void) -{ - g_bDuckToggled = !g_bDuckToggled; -} -// : -void IN_ReloadDown(void) {KeyDownForced(&in_reload);} -void IN_ReloadUp(void) {KeyUpForced(&in_reload);} -void IN_Alt1Down(void) {KeyDown(&in_alt1);} -void IN_Alt1Up(void) {KeyUp(&in_alt1);} -void IN_GraphDown(void) {KeyDown(&in_graph);} -void IN_GraphUp(void) {KeyUp(&in_graph);} - -void IN_AttackDown(void) -{ - KeyDown( &in_attack ); - gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); -} - -void IN_AttackUp(void) -{ - KeyUp( &in_attack ); - in_cancel = 0; - IN_Attack2Up(); -} - -void IN_AttackDownForced(void) -{ - KeyDownForced( &in_attack ); -} - -void IN_AttackUpForced(void) -{ - KeyUpForced( &in_attack ); -} - -// Special handling -void IN_Cancel(void) -{ - in_cancel = 1; -} - -bool CheckInAttack(void) -{ - return (in_attack.state & 1 || in_attack2.state & 1); -} - -bool CheckInAttack2(void) -{ - return (in_attack2.state & 1); -} - -void IN_Impulse (void) -{ - //char msg[1024]; - //sprintf(msg, "in_impulse=%s\n", gEngfuncs.Cmd_Argv(1)); - //CenterPrint(msg); - - in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); -} - -void IN_ScoreDown(void) -{ - KeyDown(&in_score); - if ( gViewPort ) - { - gViewPort->ShowScoreBoard(); - } -} - -void IN_ScoreUp(void) -{ - KeyUp(&in_score); - if ( gViewPort ) - { - gViewPort->HideScoreBoard(); - } -} - -void IN_MLookUp (void) -{ - KeyUp( &in_mlook ); - if ( !( in_mlook.state & 1 ) && lookspring->value ) - { - V_StartPitchDrift(); - } -} - -/* -=============== -CL_KeyState - -Returns 0.25 if a key was pressed and released during the frame, -0.5 if it was pressed and held -0 if held then released, and -1.0 if held for the entire time -=============== -*/ -float CL_KeyState (kbutton_t *key) -{ - float val = 0.0; - int impulsedown, impulseup, down; - - impulsedown = key->state & 2; - impulseup = key->state & 4; - down = key->state & 1; - - if ( impulsedown && !impulseup ) - { - // pressed and held this frame? - val = down ? 0.5 : 0.0; - } - - if ( impulseup && !impulsedown ) - { - // released this frame? - val = down ? 0.0 : 0.0; - } - - if ( !impulsedown && !impulseup ) - { - // held the entire frame? - val = down ? 1.0 : 0.0; - } - - if ( impulsedown && impulseup ) - { - if ( down ) - { - // released and re-pressed this frame - val = 0.75; - } - else - { - // pressed and released this frame - val = 0.25; - } - } - - // clear impulses - key->state &= 1; - return val; -} - -/* -================ -CL_AdjustAngles - -Moves the local angle positions -================ -*/ -void CL_AdjustAngles ( float frametime, float *viewangles ) -{ - float speed; - float up, down; - - if (in_speed.state & 1) - { - speed = frametime * cl_anglespeedkey->value; - } - else - { - speed = frametime; - } - - if (!(in_strafe.state & 1)) - { - viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); - viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); - viewangles[YAW] = anglemod(viewangles[YAW]); - } - if (in_klook.state & 1) - { - V_StopPitchDrift (); - viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); - viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); - } - - up = CL_KeyState (&in_lookup); - down = CL_KeyState(&in_lookdown); - - viewangles[PITCH] -= speed*cl_pitchspeed->value * up; - viewangles[PITCH] += speed*cl_pitchspeed->value * down; - - if (up || down) - V_StopPitchDrift (); - - if (viewangles[PITCH] > cl_pitchdown->value) - viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) - viewangles[PITCH] = -cl_pitchup->value; - - if (viewangles[ROLL] > 50) - viewangles[ROLL] = 50; - if (viewangles[ROLL] < -50) - viewangles[ROLL] = -50; -} - -/* -================ -CL_CreateMove - -Send the intended movement message to the server -if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and -2 ) we have finished signing on to server -================ -*/ -void CL_DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) -{ - //RecClCL_CreateMove(frametime, cmd, active); - //@linux Commander overview needs to be fixed! - float spd; - vec3_t viewangles; - static vec3_t oldangles; - - if ( active && (!gViewPort || !gViewPort->IsOptionsMenuVisible()) /*&& !gHUD.GetShowingMap()*/) - { - int theButtonState = CL_ButtonBits(1); - //memset( viewangles, 0, sizeof( vec3_t ) ); - //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; - //gEngfuncs.GetViewAngles( (float *)viewangles ); - - //CL_AdjustAngles ( frametime, viewangles ); - - memset (cmd, 0, sizeof(*cmd)); - //@ linux void IN_Move ( float frametime, usercmd_t *cmd) - float theRotationDeltas[3] = {0,0,0}; //{90,0,90} --> top down --> viewangles[YAW] - float theTranslationDeltas[3] = {0,0,0}; //--> cmd->sidemove - - IN_Move ( frametime, cmd ); - - if(gResetViewAngles) - { - VectorCopy(gViewAngles,viewangles); - gResetViewAngles = false; - } - else - { - gEngfuncs.GetViewAngles( (float *)viewangles ); - } - VectorAdd(viewangles,theRotationDeltas,viewangles); - CL_AdjustAngles ( frametime, viewangles ); - - gEngfuncs.SetViewAngles( (float *)viewangles ); - VectorCopy (viewangles,gWorldViewAngles); - - // If we're in topdown mode - bool theProcessedMove = false; - bool theIsSendingSpecialEvent = false; - bool theOverrideImpulse = false; - float theWorldX, theWorldY; - int theScriptImpulse = 0; - - AvHMessageID theAlienAbility = MESSAGE_NULL; - AvHMessageID theGroupMessage = MESSAGE_NULL; - - //int theUpgradeVar = gEngfuncs.GetLocalPlayer()->curstate.iuser4; - //bool theIsParalyzed = GetHasUpgrade(theUpgradeVar, PLAYER_PARALYZED); - if(AvHScriptManager::Instance()->GetClientMove(theButtonState, theScriptImpulse)) - { - if(theScriptImpulse) - { - theOverrideImpulse = true; - } - //theProcessedMove = true; - - // TODO: Pass theButtonState to override all CL_KeyState() calls - } - else if(gHUD.GetInTopDownMode()) - { - cmd->upmove = cmd->sidemove = cmd->forwardmove = 0; - - // If a button was JUST pressed or released - vec3_t theMouseNormPos; - AvHMessageID theTechEvent = MESSAGE_NULL; - if(gCommanderHandler.GetMoveToWorldPosition(theWorldX, theWorldY)) - { - // Commander wants to scroll to an area of the mini-map - cmd->impulse = COMMANDER_MOVETO; - cmd->upmove = theWorldX/kWorldPosNetworkConstant; - cmd->sidemove = theWorldY/kWorldPosNetworkConstant; - gCommanderHandler.ClearMoveToPosition(); - gHUD.ClearTrackingEntity(); - - theIsSendingSpecialEvent = true; - theProcessedMove = true; - } - else if(gCommanderHandler.GetDefaultOrderPosition(theWorldX, theWorldY)) - { - // Commander wants to scroll to an area of the mini-map - cmd->impulse = COMMANDER_DEFAULTORDER; - cmd->upmove = theWorldX/kWorldPosNetworkConstant; - cmd->sidemove = theWorldY/kWorldPosNetworkConstant; - gCommanderHandler.ClearDefaultOrderPosition(); - gHUD.ClearTrackingEntity(); - - theIsSendingSpecialEvent = true; - theProcessedMove = true; - } - else if(gHUD.GetAndClearTechEvent(theTechEvent)) - { - cmd->impulse = theTechEvent; - theProcessedMove = true; - theIsSendingSpecialEvent = true; - gHUD.ClearTrackingEntity(); - - } - // else scroll - else - { - // Scroll the view if the HUD tells us to, otherwise use normal key presses - int theScrollX = 0, theScrollY = 0, theScrollZ = 0; - gHUD.GetAndClearTopDownScrollAmount(theScrollX, theScrollY, theScrollZ); - - if(theScrollX || theScrollY || theScrollZ) - { - // Commander move speed - float kCommanderMoveSpeed = 1000; - cmd->upmove += kCommanderMoveSpeed * theScrollY; - cmd->sidemove += kCommanderMoveSpeed * theScrollX; - cmd->forwardmove += kCommanderMoveSpeed * theScrollZ; - - cmd->impulse = COMMANDER_SCROLL; - theOverrideImpulse = true; - - gHUD.ClearTrackingEntity(); - - //theIsSendingSpecialEvent = true; - theProcessedMove = true; - } - else if(gHUD.GetAndClearGroupEvent(theGroupMessage)) - { - cmd->impulse = theGroupMessage; - theIsSendingSpecialEvent = true; - theProcessedMove = true; - - gHUD.SetLastHotkeySelectionEvent(theGroupMessage); - } -// else if(gHUD.GetTrackingEntity() > 0) -// { -// int theTrackingEntity = gHUD.GetTrackingEntity(); -// cmd->upmove = theTrackingEntity*kHotKeyNetworkFactor; -// cmd->impulse = COMMANDER_TRACKENTITY; -// -// theIsSendingSpecialEvent = true; -// theProcessedMove = true; -// } - else if(in_impulse != 0) - { - bool theProcessImpulse = false; - switch(in_impulse) - { - case COMMANDER_SELECTALL: - case COMMANDER_NEXTIDLE: - case COMMANDER_NEXTAMMO: - case COMMANDER_NEXTHEALTH: - theProcessImpulse = true; - break; - } - - if(theProcessImpulse) - { - cmd->impulse = in_impulse; - in_impulse = 0; - - theProcessedMove = true; - theIsSendingSpecialEvent = true; - } - } - - if(!theProcessedMove && gHUD.GetAndClearSelectionEvent(theMouseNormPos, theTechEvent)) - { - // Store world position x,y in upmove,sidemove - cmd->upmove = theMouseNormPos.x*kSelectionNetworkConstant; - cmd->sidemove = theMouseNormPos.y*kSelectionNetworkConstant; - cmd->forwardmove = theMouseNormPos.z*kSelectionNetworkConstant; - - // Set impulse indicating this - //cmd->impulse = COMMANDER_MOUSECOORD; - - // This could be COMMANDER_MOUSECOORD or BUILD_TURRET or one of the other BUILD_ events - // They are all sent the same way - cmd->impulse = theTechEvent; - - // Order mode isn't currently used but may be in the future - //cmd->weaponselect = gHUD.GetOrderMode(); - - // Set buttons. Attack gets turned off when we're in mouse mode (apparently) - // so we need to set the buttons manually - cmd->buttons = theButtonState; - if(gHUD.GetMouseOneDown()) - { - cmd->buttons |= IN_ATTACK; - } - if(gHUD.GetMouseTwoDown()) - { - cmd->buttons |= IN_ATTACK2; - } - - gHUD.ClearTrackingEntity(); - - theIsSendingSpecialEvent = true; - theProcessedMove = true; - } - } - } - else if(gHUD.GetAndClearAlienAbility(theAlienAbility)) - { - cmd->impulse = theAlienAbility; - - // Added by mmcguire. - // 255 signifies that the impulse came from us and not from the console. - cmd->weaponselect = 255; - - theProcessedMove = true; - theIsSendingSpecialEvent = true; - - } - - // else process move normally - if(!theProcessedMove) - { - if ( in_strafe.state & 1 ) - { - cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); - } - - cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); - - cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); - cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); - - if ( !(in_klook.state & 1 ) ) - { - cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); - cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); - } - } - - if(!theIsSendingSpecialEvent) - { - // adjust for speed key - if ( in_speed.state & 1 ) - { - cmd->forwardmove *= cl_movespeedkey->value; - cmd->sidemove *= cl_movespeedkey->value; - cmd->upmove *= cl_movespeedkey->value; - } - - // clip to maxspeed - spd = gEngfuncs.GetClientMaxspeed(); - - if ( spd != 0.0 ) - { - // scale the 3 speeds so that the total velocity is not > cl.maxspeed - float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); - - if ( fmov > spd ) - { - float fratio = spd / fmov; - cmd->forwardmove *= fratio; - cmd->sidemove *= fratio; - cmd->upmove *= fratio; - } - } - - // Allow mice and other controllers to add their inputs - IN_Move ( frametime, cmd ); - - if(!theOverrideImpulse) - { - cmd->impulse = in_impulse; - in_impulse = 0; - } - - cmd->weaponselect = g_weaponselect; - g_weaponselect = 0; - - // - // set button and flag bits - // - cmd->buttons = theButtonState; - - // If they're in a modal dialog, or we're stunned, ignore the attack button. - int theLocalUpgrades = gHUD.GetLocalUpgrades(); - if( GetClientVoiceMgr()->IsInSquelchMode() ) - { - cmd->buttons &= ~IN_ATTACK; - } - - // Using joystick? - if ( in_joystick->value ) - { - if ( cmd->forwardmove > 0 ) - { - cmd->buttons |= IN_FORWARD; - } - else if ( cmd->forwardmove < 0 ) - { - cmd->buttons |= IN_BACK; - } - } - } - } - - gEngfuncs.GetViewAngles( (float *)viewangles ); - // Set current view angles. - - // Set current view angles but not if frozen (this still allows you to rotate in first-person, but player model won't change) - int theUser4 = gHUD.GetLocalUpgrades(); - bool theIsFrozen = GetHasUpgrade(theUser4, MASK_PLAYER_STUNNED) || GetHasUpgrade(theUser4, MASK_ALIEN_EMBRYO); - - if ( g_iAlive && !theIsFrozen) - { - VectorCopy( viewangles, cmd->viewangles ); - VectorCopy( viewangles, oldangles ); - } - else - { - VectorCopy( oldangles, cmd->viewangles ); - } - - //Bench_SetViewAngles( 1, (float *)&cmd->viewangles, frametime, cmd ); -} - -/* -============ -CL_IsDead - -Returns 1 if health is <= 0 -============ -*/ -int CL_IsDead( void ) -{ - return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; -} - -/* -============ -CL_ButtonBits - -Returns appropriate button info for keyboard and mouse state -Set bResetState to 1 to clear old state info -============ -*/ -int CL_ButtonBits( int bResetState ) -{ - int bits = 0; - - if ( in_attack.state & 3 ) - { - bits |= IN_ATTACK; - } - - if ( in_speed.state & 3 ) - { - bits |= IN_WALK; - } - - // : duck toggle - if ( g_bDuckToggled ) - { - if (!(in_duck.state & 3)) - { - bits |= IN_DUCK; - } - } - else if (in_duck.state & 3) - { - bits |= IN_DUCK; - } - // : - - if (in_jump.state & 3) - { - bits |= IN_JUMP; - } - - if ( in_forward.state & 3 ) - { - bits |= IN_FORWARD; - } - - if (in_back.state & 3) - { - bits |= IN_BACK; - } - - if (in_use.state & 3) - { - bits |= IN_USE; - } - - if (in_cancel) - { - bits |= IN_CANCEL; - } - - if ( in_left.state & 3 ) - { - bits |= IN_LEFT; - } - - if (in_right.state & 3) - { - bits |= IN_RIGHT; - } - - if ( in_moveleft.state & 3 ) - { - bits |= IN_MOVELEFT; - } - - if (in_moveright.state & 3) - { - bits |= IN_MOVERIGHT; - } - - if (in_attack2.state & 3) - { - bits |= IN_ATTACK2; - } - - if (in_reload.state & 3) - { - bits |= IN_RELOAD; - } - - if (in_alt1.state & 3) - { - bits |= IN_ALT1; - } - - if ( in_score.state & 3 ) - { - bits |= IN_SCORE; - } - - // Dead or in intermission? Shore scoreboard, too - if ( CL_IsDead() || gHUD.m_iIntermission ) - { - bits |= IN_SCORE; - } - - if ( bResetState ) - { - in_attack.state &= ~2; - in_speed.state &= ~2; - in_duck.state &= ~2; - in_jump.state &= ~2; - in_forward.state &= ~2; - in_back.state &= ~2; - in_use.state &= ~2; - in_left.state &= ~2; - in_right.state &= ~2; - in_moveleft.state &= ~2; - in_moveright.state &= ~2; - in_attack2.state &= ~2; - in_reload.state &= ~2; - in_alt1.state &= ~2; - in_score.state &= ~2; - } - - return bits; -} - -/* -============ -CL_ResetButtonBits - -============ -*/ -void CL_ResetButtonBits( int bits ) -{ - int bitsNew = CL_ButtonBits( 0 ) ^ bits; - - // Has the attack button been changed - if ( bitsNew & IN_ATTACK ) - { - // Was it pressed? or let go? - if ( bits & IN_ATTACK ) - { - KeyDown( &in_attack ); - } - else - { - // totally clear state - in_attack.state &= ~7; - in_attack2.state &= ~7; - } - } -} - -/* -============ -InitInput -============ -*/ -void InitInput (void) -{ - gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); - gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); - gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); - gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); - gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); - gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); - gEngfuncs.pfnAddCommand ("+right",IN_RightDown); - gEngfuncs.pfnAddCommand ("-right",IN_RightUp); - gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); - gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); - gEngfuncs.pfnAddCommand ("+back",IN_BackDown); - gEngfuncs.pfnAddCommand ("-back",IN_BackUp); - gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); - gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); - gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); - gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); - gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); - gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); - gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); - gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); - gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); - gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); - gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); - gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); - gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); - gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); - //gEngfuncs.pfnAddCommand ("+movement", IN_Attack2Down); - //gEngfuncs.pfnAddCommand ("-movement", IN_Attack2Up); - gEngfuncs.pfnAddCommand ("+use", IN_UseDown); - gEngfuncs.pfnAddCommand ("-use", IN_UseUp); - gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); - gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); - gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); - gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); - gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); - gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); - gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); - gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); - gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); - gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); - gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); - // : duck toggle - gEngfuncs.pfnAddCommand ("toggleduck", IN_DuckToggle); - // : - gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); - gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); - gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); - gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); - gEngfuncs.pfnAddCommand ("+score", IN_ScoreDown); - gEngfuncs.pfnAddCommand ("-score", IN_ScoreUp); - gEngfuncs.pfnAddCommand ("+showscores", IN_ScoreDown); - gEngfuncs.pfnAddCommand ("-showscores", IN_ScoreUp); - gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); - gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); - gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); - gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); - - lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); - lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); - cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); - cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); - cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); - cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); - cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); - cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); - cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); - cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); - cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); - cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); - - cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); - - m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); - m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); - m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); - m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); - - cl_autohelp = gEngfuncs.pfnRegisterVariable ( kvAutoHelp, "1.0", FCVAR_ARCHIVE ); - cl_centerentityid = gEngfuncs.pfnRegisterVariable ( kvCenterEntityID, "0.0", FCVAR_ARCHIVE ); - cl_musicenabled = gEngfuncs.pfnRegisterVariable ( kvMusicEnabled, "1.0", FCVAR_ARCHIVE ); - cl_musicvolume = gEngfuncs.pfnRegisterVariable ( kvMusicVolume, "155", FCVAR_ARCHIVE ); - cl_musicdir = gEngfuncs.pfnRegisterVariable ( kvMusicDirectory, "", FCVAR_ARCHIVE); - cl_musicdelay = gEngfuncs.pfnRegisterVariable ( kvMusicDelay, "90", FCVAR_ARCHIVE); - cl_forcedefaultfov = gEngfuncs.pfnRegisterVariable ( kvForceDefaultFOV, "0", FCVAR_ARCHIVE ); - cl_dynamiclights = gEngfuncs.pfnRegisterVariable ( kvDynamicLights, "1", FCVAR_ARCHIVE ); - cl_buildmessages = gEngfuncs.pfnRegisterVariable ( kvBuildMessages, "1", FCVAR_ARCHIVE); - cl_quickselecttime = gEngfuncs.pfnRegisterVariable ( kvQuickSelectTime, ".15", FCVAR_ARCHIVE ); - cl_highdetail = gEngfuncs.pfnRegisterVariable ( kvHighDetail, "1", FCVAR_ARCHIVE ); - cl_cmhotkeys = gEngfuncs.pfnRegisterVariable ( kvCMHotkeys, "qwerasdfzxcv", FCVAR_ARCHIVE ); - cl_forcedefaultfov = gEngfuncs.pfnRegisterVariable ( kvForceDefaultFOV, "0", FCVAR_ARCHIVE ); - cl_particleinfo = gEngfuncs.pfnRegisterVariable ( kvParticleInfo, "0", FCVAR_ARCHIVE ); - - // Initialize third person camera controls. - CAM_Init(); - // Initialize inputs - IN_Init(); - // Initialize keyboard - KB_Init(); - // Initialize view system - V_Init(); -} - -/* -============ -ShutdownInput -============ -*/ -void ShutdownInput (void) -{ - IN_Shutdown(); - KB_Shutdown(); -} -#include "interface.h" -void CL_DLLEXPORT HUD_Shutdown( void ) -{ -// RecClShutdown(); - - ShutdownInput(); - - gHUD.Shutdown(); -} +//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= +// +// The copyright to the contents herein is the property of Charles G. Cleveland. +// The contents may be used and/or copied only with the written permission of +// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: input.cpp $ +// $Date: 2002/10/16 02:12:21 $ +// +//------------------------------------------------------------------------------- +// $Log: input.cpp,v $ +// Revision 1.28 2002/10/16 02:12:21 Flayra +// - Valve anti-cheat integrated! +// +// Revision 1.27 2002/08/09 00:13:04 Flayra +// - Removed explicitly allowing specific commands. I can't remember why this was needed, but it doesn't appear to be anymore. +// +// Revision 1.26 2002/08/02 21:39:03 Flayra +// - Refactored variable names +// +// Revision 1.25 2002/07/08 16:13:31 Flayra +// - Fixed bug where command was able to switch weapons via mousewheel (bug #239) +// +//=============================================================================== +// cl.input.c -- builds an intended movement command to send to the server + +//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +extern "C" +{ +#include "kbutton.h" +} +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "view.h" +#include "bench.h" +#include +#include +#include "engine/keydefs.h" +#include "Exports.h" + +#include "vgui_TeamFortressViewport.h" +#include "mod/AvHServerVariables.h"// should we go ahead and just make a SharedVariables.h instead? +#include "mod/AvHClientVariables.h" +#include "mod/AvHMessage.h" +#include "winsani_in.h" +#include "fmod.h" +#include "winsani_out.h" +#include "mod/AvHScriptManager.h" +#include "mod/AvHScrollHandler.h" +#include "mod/AvHCommanderModeHandler.h" +#include "util/Mat3.h" + +#include "engine/APIProxy.h" +#include "Exports.h" + +// : duck toggle +extern bool g_bDuckToggled; +// : + +extern int g_iAlive; + +extern int g_weaponselect; +extern cl_enginefunc_t gEngfuncs; +bool gResetViewAngles = false; +vec3_t gViewAngles; +extern AvHCommanderModeHandler gCommanderHandler; + +/////////////////////////////// +// Begin Max's Code +/////////////////////////////// + +float gPlayerAngles[3] = { 0, 0, 0 }; +float gTargetPlayerAngles[3] = { 0, 0, 0 }; +float gWorldViewAngles[3] = { 0, 0, 0 }; + +/////////////////////////////// +// End Max's Code +/////////////////////////////// + +// Defined in pm_math.c +//extern "C" float anglemod( float a ); +float anglemod( float a ); + +void IN_Init (void); +void IN_Move ( float frametime, usercmd_t *cmd); +void IN_Shutdown( void ); +void V_Init( void ); +void VectorAngles( const float *forward, float *angles ); +int CL_ButtonBits( int ); + +// xxx need client dll function to get and clear impuse +extern cvar_t *in_joystick; + +int in_impulse = 0; +int in_cancel = 0; + +cvar_t *m_pitch; +cvar_t *m_yaw; +cvar_t *m_forward; +cvar_t *m_side; + +cvar_t *lookstrafe; +cvar_t *lookspring; +cvar_t *cl_pitchup; +cvar_t *cl_pitchdown; +cvar_t *cl_upspeed; +cvar_t *cl_forwardspeed; +cvar_t *cl_backspeed; +cvar_t *cl_sidespeed; +cvar_t *cl_movespeedkey; +cvar_t *cl_yawspeed; +cvar_t *cl_pitchspeed; +cvar_t *cl_anglespeedkey; +cvar_t *cl_vsmoothing; +cvar_t *cl_autohelp; +cvar_t *cl_centerentityid; +cvar_t *cl_musicenabled; +cvar_t *cl_musicdelay; +cvar_t *cl_musicvolume; +cvar_t *cl_musicdir; +cvar_t *cl_quickselecttime; +cvar_t *cl_highdetail; +cvar_t *cl_cmhotkeys; +cvar_t *cl_forcedefaultfov; +cvar_t *cl_dynamiclights; +cvar_t *cl_buildmessages; +cvar_t *cl_particleinfo; + +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook; +kbutton_t in_klook; +kbutton_t in_jlook; +kbutton_t in_left; +kbutton_t in_right; +kbutton_t in_forward; +kbutton_t in_back; +kbutton_t in_lookup; +kbutton_t in_lookdown; +kbutton_t in_moveleft; +kbutton_t in_moveright; +kbutton_t in_strafe; +kbutton_t in_speed; +kbutton_t in_use; +kbutton_t in_jump; +kbutton_t in_attack; +kbutton_t in_attack2; +kbutton_t in_up; +kbutton_t in_down; +kbutton_t in_duck; +kbutton_t in_reload; +kbutton_t in_alt1; +kbutton_t in_score; +kbutton_t in_break; +kbutton_t in_graph; // Display the netgraph + +typedef struct kblist_s +{ + struct kblist_s *next; + kbutton_t *pkey; + char name[32]; +} kblist_t; + +kblist_t *g_kbkeys = NULL; + +vector< pair > g_PrevCmds; + +/* +============ +KB_ConvertString + +Removes references to +use and replaces them with the keyname in the output string. If + a binding is unfound, then the original text is retained. +NOTE: Only works for text with +word in it. +============ +*/ +int KB_ConvertString( char *in, char **ppout ) +{ + char sz[ 4096 ]; + char binding[ 64 ]; + char *p; + char *pOut; + char *pEnd; + const char *pBinding; + + if ( !ppout ) + return 0; + + *ppout = NULL; + p = in; + pOut = sz; + while ( *p ) + { + if ( *p == '+' ) + { + pEnd = binding; + while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) + { + *pEnd++ = *p++; + } + + *pEnd = '\0'; + + pBinding = NULL; + if ( strlen( binding + 1 ) > 0 ) + { + // See if there is a binding for binding? + pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); + } + + if ( pBinding ) + { + *pOut++ = '['; + pEnd = (char *)pBinding; + } + else + { + pEnd = binding; + } + + while ( *pEnd ) + { + *pOut++ = *pEnd++; + } + + if ( pBinding ) + { + *pOut++ = ']'; + } + } + else + { + *pOut++ = *p++; + } + } + + *pOut = '\0'; + + pOut = ( char * )malloc( strlen( sz ) + 1 ); + strcpy( pOut, sz ); + *ppout = pOut; + + return 1; +} + +/* +============ +KB_Find + +Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files +============ +*/ +struct kbutton_s CL_DLLEXPORT *KB_Find( const char *name ) +{ +// RecClFindKey(name); + + kblist_t *p; + p = g_kbkeys; + while ( p ) + { + if ( !stricmp( name, p->name ) ) + return p->pkey; + + p = p->next; + } + return NULL; +} + +/* +============ +KB_Add + +Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find +============ +*/ +void KB_Add( const char *name, kbutton_t *pkb ) +{ + kblist_t *p; + kbutton_t *kb; + + kb = KB_Find( name ); + + if ( kb ) + return; + + p = ( kblist_t * )malloc( sizeof( kblist_t ) ); + memset( p, 0, sizeof( *p ) ); + + strcpy( p->name, name ); + p->pkey = pkb; + + p->next = g_kbkeys; + g_kbkeys = p; +} + +/* +============ +KB_Init + +Add kbutton_t definitions that the engine can query if needed +============ +*/ +void KB_Init( void ) +{ + g_kbkeys = NULL; + + KB_Add( "in_graph", &in_graph ); + KB_Add( "in_mlook", &in_mlook ); + KB_Add( "in_jlook", &in_jlook ); +} + +/* +============ +KB_Shutdown + +Clear kblist +============ +*/ +void KB_Shutdown( void ) +{ + kblist_t *p, *n; + p = g_kbkeys; + while ( p ) + { + n = p->next; + free( p ); + p = n; + } + g_kbkeys = NULL; +} + +/* +============ +KeyDown +============ +*/ +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + int theBlockScripts = (int)gHUD.GetServerVariableFloat(kvBlockScripts); + + char *pCmd = gEngfuncs.Cmd_Argv(0); + + if(theBlockScripts && pCmd) + { + bool bFound = false; + + //Check thier last few commands (this prevents false positives if a player is hits several keys real fast) + for (int i = 0; i < g_PrevCmds.size(); i++) + { + //Check both the key pressed and the command it executed. + if(k == g_PrevCmds[i].first && !strcmp(pCmd, g_PrevCmds[i].second.c_str())) + { + bFound = true; + break; + } + } + + + if(!bFound + && strcmp(pCmd, "+mlook") + && strcmp(pCmd, "+jlook") + && strcmp(pCmd, "+showscores") + && strcmp(pCmd, "+use")) + { + gEngfuncs.pfnCenterPrint("Scripting is not allowed on this server."); + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + } + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +/* +============ +KeyDownForced +============ +*/ +void KeyDownForced (kbutton_t *b) +{ + b->down[0] = 0; + b->down[1] = 0; + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +/* +============ +KeyUp +============ +*/ +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + { + //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); + return; // some other key is still holding it down + } + + if (!(b->state & 1)) + return; // still up (this should not happen) + + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +/* +============ +KeyUpForced +============ +*/ +void KeyUpForced (kbutton_t *b) +{ + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +bool AvHContainsBlockedCommands(const char* inInput) +{ + if (inInput == NULL) + { + return false; + } + + const char* kBlockedCommand[] = + { + "exec", + "wait", + "special", + "_special" + }; + + // Check for a ; indicating multiple commands. + + if (strchr(inInput, ';') != NULL) + { + return true; + } + + // Check if any of the blocked commands are being used. + + const char* theCommandEnd = strpbrk(inInput, " \t"); + + int theCommandLength; + + if (theCommandEnd == NULL) + { + theCommandLength = (int)strlen(inInput); + } + else + { + theCommandLength = theCommandEnd - inInput; + } + + for (int i = 0; i < sizeof(kBlockedCommand) / sizeof(const char*); ++i) + { + if ((int)strlen(kBlockedCommand[i]) == theCommandLength && + strncmp(inInput, kBlockedCommand[i], theCommandLength) == 0) + { + return true; + } + } + return false; +} + +/* +============ +HUD_Key_Event + +Return 1 to allow engine to process the key, otherwise, act on it as needed +============ +*/ +int CL_DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) +{ +// RecClKeyEvent(down, keynum, pszCurrentBinding); + + // Check to see if the event has any outlawed commands in it. + float theBlockScripts = gHUD.GetServerVariableFloat(kvBlockScripts); + + if (theBlockScripts && AvHContainsBlockedCommands(pszCurrentBinding)) + { + if(down)//: only show when going down. + gEngfuncs.pfnCenterPrint("Scripting is not allowed on this server.\n"); + return 0; + } + + if(pszCurrentBinding) + { + if(g_PrevCmds.size() >= 5) + g_PrevCmds.erase(g_PrevCmds.begin());//remove the oldest command + + g_PrevCmds.push_back(make_pair(keynum, (string)pszCurrentBinding)); + } + + int theProcessKeyBinding = 1; + +// char theKeyBinding[256] = "none"; +// if(pszCurrentBinding) +// { +// sprintf(theKeyBinding, pszCurrentBinding); +// } +// +// char theMessage[512]; +// sprintf(theMessage, "%s (down: %d, keynum %d)", theKeyBinding, down, keynum); +// CenterPrint(theMessage); + + if(gViewPort /*&& gViewPort->IsOptionsMenuVisible()*/) + { + + theProcessKeyBinding = gViewPort->KeyInput(down, keynum, pszCurrentBinding); + + if(pszCurrentBinding && (!strcmp(pszCurrentBinding, "toggleconsole") || !strcmp(pszCurrentBinding, "cancelselect"))) + { + theProcessKeyBinding = 1; + } + } + + + // Process topdown commands with precedence first + if(theProcessKeyBinding && gHUD.GetInTopDownMode()) + { + if((keynum != 0) && down/*&& pszCurrentBinding*/) + { + AvHMessageID theMessageID = gHUD.HotKeyHit(keynum); + if((theMessageID != MESSAGE_NULL) || (keynum == K_ESCAPE)) + { + // If ESC or cancel was hit, cancel ghost building + if((keynum == K_ESCAPE) || (theMessageID == MESSAGE_CANCEL)) + { + gHUD.SetGhostBuildingMode(MESSAGE_NULL); + } + + theProcessKeyBinding = 0; + } + } + } + + if(theProcessKeyBinding) + { + // Process only a couple keybindings in top down mode +// if(!gHUD.GetInTopDownMode() || (pszCurrentBinding && +// +// // Misc. commands +// (!strcmp(pszCurrentBinding, "toggleconsole") || !strcmp(pszCurrentBinding, "cancelselect") || !strcmp(pszCurrentBinding, "+showscores") || !strcmp(pszCurrentBinding, "-showscores") || !strcmp(pszCurrentBinding, "messagemode") || !strcmp(pszCurrentBinding, "messagemode2") || !strcmp(pszCurrentBinding, "snapshot") || !strcmp(pszCurrentBinding, "screenshot") || !strcmp(pszCurrentBinding, "+jump") || !strcmp(pszCurrentBinding, "addbot") || !strcmp(pszCurrentBinding, "+voicerecord") || !strcmp(pszCurrentBinding, "-voicerecord") || +// +// // Movement commands +// !strcmp(pszCurrentBinding, "testevent") /*|| !strcmp(pszCurrentBinding, "invnext") || !strcmp(pszCurrentBinding, "invprev")*/ || !strcmp(pszCurrentBinding, "+moveleft") || !strcmp(pszCurrentBinding, "-moveleft") || !strcmp(pszCurrentBinding, "+moveright") || !strcmp(pszCurrentBinding, "-moveright") || !strcmp(pszCurrentBinding, "+moveup") || !strcmp(pszCurrentBinding, "-moveup") || !strcmp(pszCurrentBinding, "+movedown") || !strcmp(pszCurrentBinding, "-movedown") || +// +// // For selecting groups +// !strcmp(pszCurrentBinding, "slot1") || !strcmp(pszCurrentBinding, "slot2") || !strcmp(pszCurrentBinding, "slot3") || !strcmp(pszCurrentBinding, "slot4") || !strcmp(pszCurrentBinding, "slot5") || +// +// // For creating groups +// !strcmp(pszCurrentBinding, "+duck") || !strcmp(pszCurrentBinding, "-duck") || +// +// // For testing ease +// !strcmp(pszCurrentBinding, "givepoints") +// +// ))) +// { + if (gViewPort) + theProcessKeyBinding = gViewPort->KeyInput(down, keynum, pszCurrentBinding); + +// // Don't +// if(!strcmp(pszCurrentBinding, "+jump") && gHUD.GetInTopDownMode()) +// { +// gHUD.GotoAlert(); +// } + +// } + } + + return theProcessKeyBinding; +} + +void IN_BreakDown( void ) { KeyDown( &in_break );}; +void IN_BreakUp( void ) { KeyUp( &in_break ); }; +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_JLookDown (void) {KeyDown(&in_jlook);} +void IN_JLookUp (void) {KeyUp(&in_jlook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} + +void IN_ForwardDown(void) +{ + KeyDown(&in_forward); + gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); +} + +void IN_ForwardUp(void) +{ + KeyUp(&in_forward); + gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); +} + +void IN_BackDown(void) +{ + KeyDown(&in_back); + gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); +} + +void IN_BackUp(void) +{ + KeyUp(&in_back); + gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); +} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) +{ + KeyDown(&in_moveleft); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); +} + +void IN_MoveleftUp(void) +{ + KeyUp(&in_moveleft); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); +} + +void IN_MoverightDown(void) +{ + KeyDown(&in_moveright); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); +} + +void IN_MoverightUp(void) +{ + KeyUp(&in_moveright); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); +} +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +// needs capture by hud/vgui also +extern void __CmdFunc_InputPlayerSpecial(void); +void IN_Attack2Down(void) {KeyDownForced(&in_attack2);} +void IN_Attack2Up(void) {KeyUpForced(&in_attack2);} +void IN_UseDown (void) +{ + KeyDown(&in_use); + gHUD.m_Spectator.HandleButtonsDown( IN_USE ); +} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) +{ + KeyDown(&in_jump); + gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); + +} + +void IN_JumpUp (void) +{ + KeyUp(&in_jump); + gHUD.m_Spectator.HandleButtonsUp( IN_JUMP ); +} + +void IN_DuckDown(void) +{ + KeyDown(&in_duck); + gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); +} + +void IN_DuckUp(void) {KeyUp(&in_duck);} +// : duck toggle +void IN_DuckToggle(void) +{ + g_bDuckToggled = !g_bDuckToggled; +} +// : +void IN_ReloadDown(void) {KeyDownForced(&in_reload);} +void IN_ReloadUp(void) {KeyUpForced(&in_reload);} +void IN_Alt1Down(void) {KeyDown(&in_alt1);} +void IN_Alt1Up(void) {KeyUp(&in_alt1);} +void IN_GraphDown(void) {KeyDown(&in_graph);} +void IN_GraphUp(void) {KeyUp(&in_graph);} + +void IN_AttackDown(void) +{ + KeyDown( &in_attack ); + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); +} + +void IN_AttackUp(void) +{ + KeyUp( &in_attack ); + in_cancel = 0; + IN_Attack2Up(); +} + +void IN_AttackDownForced(void) +{ + KeyDownForced( &in_attack ); +} + +void IN_AttackUpForced(void) +{ + KeyUpForced( &in_attack ); +} + +// Special handling +void IN_Cancel(void) +{ + in_cancel = 1; +} + +bool CheckInAttack(void) +{ + return (in_attack.state & 1 || in_attack2.state & 1); +} + +bool CheckInAttack2(void) +{ + return (in_attack2.state & 1); +} + +void IN_Impulse (void) +{ + //char msg[1024]; + //sprintf(msg, "in_impulse=%s\n", gEngfuncs.Cmd_Argv(1)); + //CenterPrint(msg); + + in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); +} + +void IN_ScoreDown(void) +{ + KeyDown(&in_score); + if ( gViewPort ) + { + gViewPort->ShowScoreBoard(); + } +} + +void IN_ScoreUp(void) +{ + KeyUp(&in_score); + if ( gViewPort ) + { + gViewPort->HideScoreBoard(); + } +} + +void IN_MLookUp (void) +{ + KeyUp( &in_mlook ); + if ( !( in_mlook.state & 1 ) && lookspring->value ) + { + V_StartPitchDrift(); + } +} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val = 0.0; + int impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + + if ( impulsedown && !impulseup ) + { + // pressed and held this frame? + val = down ? 0.5 : 0.0; + } + + if ( impulseup && !impulsedown ) + { + // released this frame? + val = down ? 0.0 : 0.0; + } + + if ( !impulsedown && !impulseup ) + { + // held the entire frame? + val = down ? 1.0 : 0.0; + } + + if ( impulsedown && impulseup ) + { + if ( down ) + { + // released and re-pressed this frame + val = 0.75; + } + else + { + // pressed and released this frame + val = 0.25; + } + } + + // clear impulses + key->state &= 1; + return val; +} + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles ( float frametime, float *viewangles ) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + { + speed = frametime * cl_anglespeedkey->value; + } + else + { + speed = frametime; + } + + if (!(in_strafe.state & 1)) + { + viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); + viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); + viewangles[YAW] = anglemod(viewangles[YAW]); + } + if (in_klook.state & 1) + { + V_StopPitchDrift (); + viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); + viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + viewangles[PITCH] -= speed*cl_pitchspeed->value * up; + viewangles[PITCH] += speed*cl_pitchspeed->value * down; + + if (up || down) + V_StopPitchDrift (); + + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + if (viewangles[ROLL] > 50) + viewangles[ROLL] = 50; + if (viewangles[ROLL] < -50) + viewangles[ROLL] = -50; +} + +/* +================ +CL_CreateMove + +Send the intended movement message to the server +if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and +2 ) we have finished signing on to server +================ +*/ +void CL_DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) +{ + //RecClCL_CreateMove(frametime, cmd, active); + //@linux Commander overview needs to be fixed! + float spd; + vec3_t viewangles; + static vec3_t oldangles; + + if ( active && (!gViewPort || !gViewPort->IsOptionsMenuVisible()) /*&& !gHUD.GetShowingMap()*/) + { + int theButtonState = CL_ButtonBits(1); + //memset( viewangles, 0, sizeof( vec3_t ) ); + //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; + //gEngfuncs.GetViewAngles( (float *)viewangles ); + + //CL_AdjustAngles ( frametime, viewangles ); + + memset (cmd, 0, sizeof(*cmd)); + //@ linux void IN_Move ( float frametime, usercmd_t *cmd) + float theRotationDeltas[3] = {0,0,0}; //{90,0,90} --> top down --> viewangles[YAW] + float theTranslationDeltas[3] = {0,0,0}; //--> cmd->sidemove + + IN_Move ( frametime, cmd ); + + if(gResetViewAngles) + { + VectorCopy(gViewAngles,viewangles); + gResetViewAngles = false; + } + else + { + gEngfuncs.GetViewAngles( (float *)viewangles ); + } + VectorAdd(viewangles,theRotationDeltas,viewangles); + CL_AdjustAngles ( frametime, viewangles ); + + gEngfuncs.SetViewAngles( (float *)viewangles ); + VectorCopy (viewangles,gWorldViewAngles); + + // If we're in topdown mode + bool theProcessedMove = false; + bool theIsSendingSpecialEvent = false; + bool theOverrideImpulse = false; + float theWorldX, theWorldY; + int theScriptImpulse = 0; + + AvHMessageID theAlienAbility = MESSAGE_NULL; + AvHMessageID theGroupMessage = MESSAGE_NULL; + + //int theUpgradeVar = gEngfuncs.GetLocalPlayer()->curstate.iuser4; + //bool theIsParalyzed = GetHasUpgrade(theUpgradeVar, PLAYER_PARALYZED); + if(AvHScriptManager::Instance()->GetClientMove(theButtonState, theScriptImpulse)) + { + if(theScriptImpulse) + { + theOverrideImpulse = true; + } + //theProcessedMove = true; + + // TODO: Pass theButtonState to override all CL_KeyState() calls + } + else if(gHUD.GetInTopDownMode()) + { + cmd->upmove = cmd->sidemove = cmd->forwardmove = 0; + + // If a button was JUST pressed or released + vec3_t theMouseNormPos; + AvHMessageID theTechEvent = MESSAGE_NULL; + if(gCommanderHandler.GetMoveToWorldPosition(theWorldX, theWorldY)) + { + // Commander wants to scroll to an area of the mini-map + cmd->impulse = COMMANDER_MOVETO; + cmd->upmove = theWorldX/kWorldPosNetworkConstant; + cmd->sidemove = theWorldY/kWorldPosNetworkConstant; + gCommanderHandler.ClearMoveToPosition(); + gHUD.ClearTrackingEntity(); + + theIsSendingSpecialEvent = true; + theProcessedMove = true; + } + else if(gCommanderHandler.GetDefaultOrderPosition(theWorldX, theWorldY)) + { + // Commander wants to scroll to an area of the mini-map + cmd->impulse = COMMANDER_DEFAULTORDER; + cmd->upmove = theWorldX/kWorldPosNetworkConstant; + cmd->sidemove = theWorldY/kWorldPosNetworkConstant; + gCommanderHandler.ClearDefaultOrderPosition(); + gHUD.ClearTrackingEntity(); + + theIsSendingSpecialEvent = true; + theProcessedMove = true; + } + else if(gHUD.GetAndClearTechEvent(theTechEvent)) + { + cmd->impulse = theTechEvent; + theProcessedMove = true; + theIsSendingSpecialEvent = true; + gHUD.ClearTrackingEntity(); + + } + // else scroll + else + { + // Scroll the view if the HUD tells us to, otherwise use normal key presses + int theScrollX = 0, theScrollY = 0, theScrollZ = 0; + gHUD.GetAndClearTopDownScrollAmount(theScrollX, theScrollY, theScrollZ); + + if(theScrollX || theScrollY || theScrollZ) + { + // Commander move speed + float kCommanderMoveSpeed = 1000; + cmd->upmove += kCommanderMoveSpeed * theScrollY; + cmd->sidemove += kCommanderMoveSpeed * theScrollX; + cmd->forwardmove += kCommanderMoveSpeed * theScrollZ; + + cmd->impulse = COMMANDER_SCROLL; + theOverrideImpulse = true; + + gHUD.ClearTrackingEntity(); + + //theIsSendingSpecialEvent = true; + theProcessedMove = true; + } + else if(gHUD.GetAndClearGroupEvent(theGroupMessage)) + { + cmd->impulse = theGroupMessage; + theIsSendingSpecialEvent = true; + theProcessedMove = true; + + gHUD.SetLastHotkeySelectionEvent(theGroupMessage); + } +// else if(gHUD.GetTrackingEntity() > 0) +// { +// int theTrackingEntity = gHUD.GetTrackingEntity(); +// cmd->upmove = theTrackingEntity*kHotKeyNetworkFactor; +// cmd->impulse = COMMANDER_TRACKENTITY; +// +// theIsSendingSpecialEvent = true; +// theProcessedMove = true; +// } + else if(in_impulse != 0) + { + bool theProcessImpulse = false; + switch(in_impulse) + { + case COMMANDER_SELECTALL: + case COMMANDER_NEXTIDLE: + case COMMANDER_NEXTAMMO: + case COMMANDER_NEXTHEALTH: + theProcessImpulse = true; + break; + } + + if(theProcessImpulse) + { + cmd->impulse = in_impulse; + in_impulse = 0; + + theProcessedMove = true; + theIsSendingSpecialEvent = true; + } + } + + if(!theProcessedMove && gHUD.GetAndClearSelectionEvent(theMouseNormPos, theTechEvent)) + { + // Store world position x,y in upmove,sidemove + cmd->upmove = theMouseNormPos.x*kSelectionNetworkConstant; + cmd->sidemove = theMouseNormPos.y*kSelectionNetworkConstant; + cmd->forwardmove = theMouseNormPos.z*kSelectionNetworkConstant; + + // Set impulse indicating this + //cmd->impulse = COMMANDER_MOUSECOORD; + + // This could be COMMANDER_MOUSECOORD or BUILD_TURRET or one of the other BUILD_ events + // They are all sent the same way + cmd->impulse = theTechEvent; + + // Order mode isn't currently used but may be in the future + //cmd->weaponselect = gHUD.GetOrderMode(); + + // Set buttons. Attack gets turned off when we're in mouse mode (apparently) + // so we need to set the buttons manually + cmd->buttons = theButtonState; + if(gHUD.GetMouseOneDown()) + { + cmd->buttons |= IN_ATTACK; + } + if(gHUD.GetMouseTwoDown()) + { + cmd->buttons |= IN_ATTACK2; + } + + gHUD.ClearTrackingEntity(); + + theIsSendingSpecialEvent = true; + theProcessedMove = true; + } + } + } + else if(gHUD.GetAndClearAlienAbility(theAlienAbility)) + { + cmd->impulse = theAlienAbility; + + // Added by mmcguire. + // 255 signifies that the impulse came from us and not from the console. + cmd->weaponselect = 255; + + theProcessedMove = true; + theIsSendingSpecialEvent = true; + + } + + // else process move normally + if(!theProcessedMove) + { + if ( in_strafe.state & 1 ) + { + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); + + if ( !(in_klook.state & 1 ) ) + { + cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); + } + } + + if(!theIsSendingSpecialEvent) + { + // adjust for speed key + if ( in_speed.state & 1 ) + { + cmd->forwardmove *= cl_movespeedkey->value; + cmd->sidemove *= cl_movespeedkey->value; + cmd->upmove *= cl_movespeedkey->value; + } + + // clip to maxspeed + spd = gEngfuncs.GetClientMaxspeed(); + + if ( spd != 0.0 ) + { + // scale the 3 speeds so that the total velocity is not > cl.maxspeed + float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); + + if ( fmov > spd ) + { + float fratio = spd / fmov; + cmd->forwardmove *= fratio; + cmd->sidemove *= fratio; + cmd->upmove *= fratio; + } + } + + // Allow mice and other controllers to add their inputs + IN_Move ( frametime, cmd ); + + if(!theOverrideImpulse) + { + cmd->impulse = in_impulse; + in_impulse = 0; + } + + cmd->weaponselect = g_weaponselect; + g_weaponselect = 0; + + // + // set button and flag bits + // + cmd->buttons = theButtonState; + + // If they're in a modal dialog, or we're stunned, ignore the attack button. + int theLocalUpgrades = gHUD.GetLocalUpgrades(); + if( GetClientVoiceMgr()->IsInSquelchMode() ) + { + cmd->buttons &= ~IN_ATTACK; + } + + // Using joystick? + if ( in_joystick->value ) + { + if ( cmd->forwardmove > 0 ) + { + cmd->buttons |= IN_FORWARD; + } + else if ( cmd->forwardmove < 0 ) + { + cmd->buttons |= IN_BACK; + } + } + } + } + + gEngfuncs.GetViewAngles( (float *)viewangles ); + // Set current view angles. + + // Set current view angles but not if frozen (this still allows you to rotate in first-person, but player model won't change) + int theUser4 = gHUD.GetLocalUpgrades(); + bool theIsFrozen = GetHasUpgrade(theUser4, MASK_PLAYER_STUNNED) || GetHasUpgrade(theUser4, MASK_ALIEN_EMBRYO); + + if ( g_iAlive && !theIsFrozen) + { + VectorCopy( viewangles, cmd->viewangles ); + VectorCopy( viewangles, oldangles ); + } + else + { + VectorCopy( oldangles, cmd->viewangles ); + } + + //Bench_SetViewAngles( 1, (float *)&cmd->viewangles, frametime, cmd ); +} + +/* +============ +CL_IsDead + +Returns 1 if health is <= 0 +============ +*/ +int CL_IsDead( void ) +{ + return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; +} + +/* +============ +CL_ButtonBits + +Returns appropriate button info for keyboard and mouse state +Set bResetState to 1 to clear old state info +============ +*/ +int CL_ButtonBits( int bResetState ) +{ + int bits = 0; + + if ( in_attack.state & 3 ) + { + bits |= IN_ATTACK; + } + + if ( in_speed.state & 3 ) + { + bits |= IN_WALK; + } + + // : duck toggle + if ( g_bDuckToggled ) + { + if (!(in_duck.state & 3)) + { + bits |= IN_DUCK; + } + } + else if (in_duck.state & 3) + { + bits |= IN_DUCK; + } + // : + + if (in_jump.state & 3) + { + bits |= IN_JUMP; + } + + if ( in_forward.state & 3 ) + { + bits |= IN_FORWARD; + } + + if (in_back.state & 3) + { + bits |= IN_BACK; + } + + if (in_use.state & 3) + { + bits |= IN_USE; + } + + if (in_cancel) + { + bits |= IN_CANCEL; + } + + if ( in_left.state & 3 ) + { + bits |= IN_LEFT; + } + + if (in_right.state & 3) + { + bits |= IN_RIGHT; + } + + if ( in_moveleft.state & 3 ) + { + bits |= IN_MOVELEFT; + } + + if (in_moveright.state & 3) + { + bits |= IN_MOVERIGHT; + } + + if (in_attack2.state & 3) + { + bits |= IN_ATTACK2; + } + + if (in_reload.state & 3) + { + bits |= IN_RELOAD; + } + + if (in_alt1.state & 3) + { + bits |= IN_ALT1; + } + + if ( in_score.state & 3 ) + { + bits |= IN_SCORE; + } + + // Dead or in intermission? Shore scoreboard, too + if ( CL_IsDead() || gHUD.m_iIntermission ) + { + bits |= IN_SCORE; + } + + if ( bResetState ) + { + in_attack.state &= ~2; + in_speed.state &= ~2; + in_duck.state &= ~2; + in_jump.state &= ~2; + in_forward.state &= ~2; + in_back.state &= ~2; + in_use.state &= ~2; + in_left.state &= ~2; + in_right.state &= ~2; + in_moveleft.state &= ~2; + in_moveright.state &= ~2; + in_attack2.state &= ~2; + in_reload.state &= ~2; + in_alt1.state &= ~2; + in_score.state &= ~2; + } + + return bits; +} + +/* +============ +CL_ResetButtonBits + +============ +*/ +void CL_ResetButtonBits( int bits ) +{ + int bitsNew = CL_ButtonBits( 0 ) ^ bits; + + // Has the attack button been changed + if ( bitsNew & IN_ATTACK ) + { + // Was it pressed? or let go? + if ( bits & IN_ATTACK ) + { + KeyDown( &in_attack ); + } + else + { + // totally clear state + in_attack.state &= ~7; + in_attack2.state &= ~7; + } + } +} + +/* +============ +InitInput +============ +*/ +void InitInput (void) +{ + gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); + gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); + gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); + gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); + gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); + gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); + gEngfuncs.pfnAddCommand ("+right",IN_RightDown); + gEngfuncs.pfnAddCommand ("-right",IN_RightUp); + gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); + gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); + gEngfuncs.pfnAddCommand ("+back",IN_BackDown); + gEngfuncs.pfnAddCommand ("-back",IN_BackUp); + gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); + gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); + gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); + gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); + gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); + gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); + gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); + gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); + gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); + gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); + gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); + gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); + gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); + gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); + //gEngfuncs.pfnAddCommand ("+movement", IN_Attack2Down); + //gEngfuncs.pfnAddCommand ("-movement", IN_Attack2Up); + gEngfuncs.pfnAddCommand ("+use", IN_UseDown); + gEngfuncs.pfnAddCommand ("-use", IN_UseUp); + gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); + gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); + gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); + gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); + gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); + gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); + gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); + gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); + gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); + gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); + gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); + // : duck toggle + gEngfuncs.pfnAddCommand ("toggleduck", IN_DuckToggle); + // : + gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); + gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); + gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); + gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); + gEngfuncs.pfnAddCommand ("+score", IN_ScoreDown); + gEngfuncs.pfnAddCommand ("-score", IN_ScoreUp); + gEngfuncs.pfnAddCommand ("+showscores", IN_ScoreDown); + gEngfuncs.pfnAddCommand ("-showscores", IN_ScoreUp); + gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); + gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); + gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); + gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); + + lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); + lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); + cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); + cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); + cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); + cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); + cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); + cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); + cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); + cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); + cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); + cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); + + cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); + + m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); + m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); + m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); + m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); + + cl_autohelp = gEngfuncs.pfnRegisterVariable ( kvAutoHelp, "1.0", FCVAR_ARCHIVE ); + cl_centerentityid = gEngfuncs.pfnRegisterVariable ( kvCenterEntityID, "0.0", FCVAR_ARCHIVE ); + cl_musicenabled = gEngfuncs.pfnRegisterVariable ( kvMusicEnabled, "1.0", FCVAR_ARCHIVE ); + cl_musicvolume = gEngfuncs.pfnRegisterVariable ( kvMusicVolume, "155", FCVAR_ARCHIVE ); + cl_musicdir = gEngfuncs.pfnRegisterVariable ( kvMusicDirectory, "", FCVAR_ARCHIVE); + cl_musicdelay = gEngfuncs.pfnRegisterVariable ( kvMusicDelay, "90", FCVAR_ARCHIVE); + cl_forcedefaultfov = gEngfuncs.pfnRegisterVariable ( kvForceDefaultFOV, "0", FCVAR_ARCHIVE ); + cl_dynamiclights = gEngfuncs.pfnRegisterVariable ( kvDynamicLights, "1", FCVAR_ARCHIVE ); + cl_buildmessages = gEngfuncs.pfnRegisterVariable ( kvBuildMessages, "1", FCVAR_ARCHIVE); + cl_quickselecttime = gEngfuncs.pfnRegisterVariable ( kvQuickSelectTime, ".15", FCVAR_ARCHIVE ); + cl_highdetail = gEngfuncs.pfnRegisterVariable ( kvHighDetail, "1", FCVAR_ARCHIVE ); + cl_cmhotkeys = gEngfuncs.pfnRegisterVariable ( kvCMHotkeys, "qwerasdfzxcv", FCVAR_ARCHIVE ); + cl_forcedefaultfov = gEngfuncs.pfnRegisterVariable ( kvForceDefaultFOV, "0", FCVAR_ARCHIVE ); + cl_particleinfo = gEngfuncs.pfnRegisterVariable ( kvParticleInfo, "0", FCVAR_ARCHIVE ); + + // Initialize third person camera controls. + CAM_Init(); + // Initialize inputs + IN_Init(); + // Initialize keyboard + KB_Init(); + // Initialize view system + V_Init(); +} + +/* +============ +ShutdownInput +============ +*/ +void ShutdownInput (void) +{ + IN_Shutdown(); + KB_Shutdown(); +} +#include "interface.h" +void CL_DLLEXPORT HUD_Shutdown( void ) +{ +// RecClShutdown(); + + ShutdownInput(); + + gHUD.Shutdown(); +} diff --git a/main/source/cl_dll/kbutton.h b/main/source/cl_dll/kbutton.h index c3a7c138..cb306770 100644 --- a/main/source/cl_dll/kbutton.h +++ b/main/source/cl_dll/kbutton.h @@ -1,11 +1,11 @@ -#if !defined( KBUTTONH ) -#define KBUTTONH -#pragma once - -typedef struct kbutton_s -{ - int down[2]; // key nums holding it down - int state; // low bit is down state -} kbutton_t; - +#if !defined( KBUTTONH ) +#define KBUTTONH +#pragma once + +typedef struct kbutton_s +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + #endif // !KBUTTONH \ No newline at end of file diff --git a/main/source/cl_dll/menu.cpp b/main/source/cl_dll/menu.cpp index 47e846b5..4ebe7d0c 100644 --- a/main/source/cl_dll/menu.cpp +++ b/main/source/cl_dll/menu.cpp @@ -1,186 +1,186 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// menu.cpp -// -// generic menu handler -// -#include "hud.h" -#include "cl_util.h" -#include "mod/AvHNetworkMessages.h" - -#include -#include - -#include "vgui_TeamFortressViewport.h" - -#define MAX_MENU_STRING 512 -char g_szMenuString[MAX_MENU_STRING]; -char g_szPrelocalisedMenuString[MAX_MENU_STRING]; - -int KB_ConvertString( char *in, char **ppout ); - -DECLARE_MESSAGE( m_Menu, ShowMenu ); - -int CHudMenu :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( ShowMenu ); - - InitHUDData(); - - return 1; -} - -void CHudMenu :: InitHUDData( void ) -{ - m_fMenuDisplayed = 0; - m_bitsValidSlots = 0; - Reset(); -} - -void CHudMenu :: Reset( void ) -{ - g_szPrelocalisedMenuString[0] = 0; - m_fWaitingForMore = FALSE; -} - -int CHudMenu :: VidInit( void ) -{ - return 1; -} - -int CHudMenu :: Draw( float flTime ) -{ - // check for if menu is set to disappear - if ( m_flShutoffTime > 0 ) - { - if ( m_flShutoffTime <= gHUD.m_flTime ) - { // times up, shutoff - m_fMenuDisplayed = 0; - m_iFlags &= ~HUD_ACTIVE; - return 1; - } - } - - // don't draw the menu if the scoreboard is being shown - if ( gViewPort && gViewPort->IsScoreBoardVisible() ) - return 1; - - // draw the menu, along the left-hand side of the screen - - // count the number of newlines - int nlc = 0,i = 0; - for ( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) - { - if ( g_szMenuString[i] == '\n' ) - nlc++; - } - - // center it - int y = (ScreenHeight()/2) - ((nlc/2)*12) - 40; // make sure it is above the say text - int x = 20; - - i = 0; - while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) - { - gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); - y += 12; - - while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) - i++; - if ( g_szMenuString[i] == '\n' ) - i++; - } - - return 1; -} - -// selects an item from the menu -void CHudMenu :: SelectMenuItem( int menu_item ) -{ - // if menu_item is in a valid slot, send a menuselect command to the server - if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) - { - char szbuf[32]; - sprintf( szbuf, "menuselect %d\n", menu_item ); - ClientCmd( szbuf ); - - // remove the menu - m_fMenuDisplayed = 0; - m_iFlags &= ~HUD_ACTIVE; - } -} - - -// Message handler for ShowMenu message -// takes four values: -// short: a bitfield of keys that are valid input -// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. -// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string -// string: menu string to display -// if this message is never received, then scores will simply be the combined totals of the players. -int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) -{ - char *temp = NULL; - - int DisplayTime, NeedMore; - string content; - - NetMsg_ShowMenu( pbuf, iSize, m_bitsValidSlots, DisplayTime, NeedMore, content ); - - if ( DisplayTime > 0 ) - m_flShutoffTime = DisplayTime + gHUD.m_flTime; - else - m_flShutoffTime = -1; - - if ( m_bitsValidSlots ) - { - if ( !m_fWaitingForMore ) // this is the start of a new menu - { - strncpy( g_szPrelocalisedMenuString, content.c_str(), MAX_MENU_STRING ); - } - else - { // append to the current menu string - strncat( g_szPrelocalisedMenuString, content.c_str(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); - } - g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) - - if ( !NeedMore ) - { // we have the whole string, so we can localise it now - strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); - - // Swap in characters - if ( KB_ConvertString( g_szMenuString, &temp ) ) - { - strcpy( g_szMenuString, temp ); - free( temp ); - } - } - - m_fMenuDisplayed = 1; - m_iFlags |= HUD_ACTIVE; - } - else - { - m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off - m_iFlags &= ~HUD_ACTIVE; - } - - m_fWaitingForMore = NeedMore; - - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// menu.cpp +// +// generic menu handler +// +#include "hud.h" +#include "cl_util.h" +#include "mod/AvHNetworkMessages.h" + +#include +#include + +#include "vgui_TeamFortressViewport.h" + +#define MAX_MENU_STRING 512 +char g_szMenuString[MAX_MENU_STRING]; +char g_szPrelocalisedMenuString[MAX_MENU_STRING]; + +int KB_ConvertString( char *in, char **ppout ); + +DECLARE_MESSAGE( m_Menu, ShowMenu ); + +int CHudMenu :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( ShowMenu ); + + InitHUDData(); + + return 1; +} + +void CHudMenu :: InitHUDData( void ) +{ + m_fMenuDisplayed = 0; + m_bitsValidSlots = 0; + Reset(); +} + +void CHudMenu :: Reset( void ) +{ + g_szPrelocalisedMenuString[0] = 0; + m_fWaitingForMore = FALSE; +} + +int CHudMenu :: VidInit( void ) +{ + return 1; +} + +int CHudMenu :: Draw( float flTime ) +{ + // check for if menu is set to disappear + if ( m_flShutoffTime > 0 ) + { + if ( m_flShutoffTime <= gHUD.m_flTime ) + { // times up, shutoff + m_fMenuDisplayed = 0; + m_iFlags &= ~HUD_ACTIVE; + return 1; + } + } + + // don't draw the menu if the scoreboard is being shown + if ( gViewPort && gViewPort->IsScoreBoardVisible() ) + return 1; + + // draw the menu, along the left-hand side of the screen + + // count the number of newlines + int nlc = 0,i = 0; + for ( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) + { + if ( g_szMenuString[i] == '\n' ) + nlc++; + } + + // center it + int y = (ScreenHeight()/2) - ((nlc/2)*12) - 40; // make sure it is above the say text + int x = 20; + + i = 0; + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) + { + gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); + y += 12; + + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) + i++; + if ( g_szMenuString[i] == '\n' ) + i++; + } + + return 1; +} + +// selects an item from the menu +void CHudMenu :: SelectMenuItem( int menu_item ) +{ + // if menu_item is in a valid slot, send a menuselect command to the server + if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) + { + char szbuf[32]; + sprintf( szbuf, "menuselect %d\n", menu_item ); + ClientCmd( szbuf ); + + // remove the menu + m_fMenuDisplayed = 0; + m_iFlags &= ~HUD_ACTIVE; + } +} + + +// Message handler for ShowMenu message +// takes four values: +// short: a bitfield of keys that are valid input +// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. +// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string +// string: menu string to display +// if this message is never received, then scores will simply be the combined totals of the players. +int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) +{ + char *temp = NULL; + + int DisplayTime, NeedMore; + string content; + + NetMsg_ShowMenu( pbuf, iSize, m_bitsValidSlots, DisplayTime, NeedMore, content ); + + if ( DisplayTime > 0 ) + m_flShutoffTime = DisplayTime + gHUD.m_flTime; + else + m_flShutoffTime = -1; + + if ( m_bitsValidSlots ) + { + if ( !m_fWaitingForMore ) // this is the start of a new menu + { + strncpy( g_szPrelocalisedMenuString, content.c_str(), MAX_MENU_STRING ); + } + else + { // append to the current menu string + strncat( g_szPrelocalisedMenuString, content.c_str(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); + } + g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) + + if ( !NeedMore ) + { // we have the whole string, so we can localise it now + strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); + + // Swap in characters + if ( KB_ConvertString( g_szMenuString, &temp ) ) + { + strcpy( g_szMenuString, temp ); + free( temp ); + } + } + + m_fMenuDisplayed = 1; + m_iFlags |= HUD_ACTIVE; + } + else + { + m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off + m_iFlags &= ~HUD_ACTIVE; + } + + m_fWaitingForMore = NeedMore; + + return 1; +} diff --git a/main/source/cl_dll/message.cpp b/main/source/cl_dll/message.cpp index c158a0eb..de264534 100644 --- a/main/source/cl_dll/message.cpp +++ b/main/source/cl_dll/message.cpp @@ -1,717 +1,717 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Message.cpp -// -// implementation of CHudMessage class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "mod/AvHClientVariables.h" -#include "mod/AvHNetworkMessages.h" - -DECLARE_MESSAGE( m_Message, HudText ) -DECLARE_MESSAGE( m_Message, HudText2 ) -DECLARE_MESSAGE( m_Message, GameTitle ) - -// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt -client_textmessage_t g_pCustomMessage; -char *g_pCustomName = "Custom"; -char g_pCustomText[1024]; - -int CHudMessage::Init(void) -{ - HOOK_MESSAGE( HudText ); - HOOK_MESSAGE( HudText2 ); - HOOK_MESSAGE( GameTitle ); - - gHUD.AddHudElem(this); - - Reset(); - - return 1; -}; - -int CHudMessage::VidInit( void ) -{ - m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); - m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); - - return 1; -}; - -const int kDefaultRComp = 25; -const int kDefaultGComp = 255; -const int kDefaultBComp = 25; - -const int kEnemyRComp = 255; -const int kEnemyGComp = 25; -const int kEnemyBComp = 25; - -void CHudMessage::Reset( void ) -{ - memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); - memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); - - m_gameTitleTime = 0; - m_pGameTitle = NULL; - - // Player id stuff - this->mPlayerIDTime = 0; - this->mPlayerID = NULL; - - this->mPlayerIDMessage.effect = 1; - this->mPlayerIDMessage.r1 = kDefaultRComp; - this->mPlayerIDMessage.g1 = kDefaultGComp; - this->mPlayerIDMessage.b1 = kDefaultBComp; - this->mPlayerIDMessage.a1 = 255; - - this->mPlayerIDMessage.g2 = 255; - this->mPlayerIDMessage.r2 = this->mPlayerIDMessage.b2 = 25; - this->mPlayerIDMessage.a2 = 255; - - this->SetPlayerIDPosition(); - - this->mPlayerIDMessage.fadein = 0.04; - this->mPlayerIDMessage.fadeout = 0.5; - this->mPlayerIDMessage.fxtime = 0.25; - this->mPlayerIDMessage.holdtime = 5; - this->mPlayerIDMessage.pName = NULL; - this->mPlayerIDMessage.pMessage = NULL; -} - -void CHudMessage::SetPlayerIDPosition() -{ - if(gEngfuncs.pfnGetCvarFloat(kvCenterEntityID) || gHUD.GetInTopDownMode()) - { - this->mPlayerIDMessage.x = -1; // Centered - this->mPlayerIDMessage.y = -1; // Centered - } - else - { - this->mPlayerIDMessage.x = .3; - this->mPlayerIDMessage.y = .9; - } -} - -float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) -{ - float fadeTime = fadein + hold; - float fadeBlend; - - if ( localTime < 0 ) - return 0; - - if ( localTime < fadein ) - { - fadeBlend = 1 - ((fadein - localTime) / fadein); - } - else if ( localTime > fadeTime ) - { - if ( fadeout > 0 ) - fadeBlend = 1 - ((localTime - fadeTime) / fadeout); - else - fadeBlend = 0; - } - else - fadeBlend = 1; - - return fadeBlend; -} - - -int CHudMessage::XPosition( float x, int width, int totalWidth ) -{ - int xPos; - - if ( x == -1 ) - { - xPos = (ScreenWidth() - width) / 2; - } - else - { - if ( x < 0 ) - xPos = (1.0 + x) * ScreenWidth() - totalWidth; // Alight right - else - xPos = x * ScreenWidth(); - } - - if ( xPos + width > ScreenWidth() ) - xPos = ScreenWidth() - width; - else if ( xPos < 0 ) - xPos = 0; - - return xPos; -} - - -int CHudMessage::YPosition( float y, int height ) -{ - int yPos; - - if ( y == -1 ) // Centered? - yPos = (ScreenHeight() - height) * 0.5; - else - { - // Alight bottom? - if ( y < 0 ) - yPos = (1.0 + y) * ScreenHeight() - height; // Alight bottom - else // align top - yPos = y * ScreenHeight(); - } - - if ( yPos + height > ScreenHeight() ) - yPos = ScreenHeight() - height; - else if ( yPos < 0 ) - yPos = 0; - - return yPos; -} - - -void CHudMessage::MessageScanNextChar( void ) -{ - int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue; - int blend; - - srcRed = m_parms.pMessage->r1; - srcGreen = m_parms.pMessage->g1; - srcBlue = m_parms.pMessage->b1; - blend = 0; // Pure source - - switch( m_parms.pMessage->effect ) - { - // Fade-in / Fade-out - case 0: - case 1: - destRed = destGreen = destBlue = 0; - blend = m_parms.fadeBlend; - break; - - case 2: - m_parms.charTime += m_parms.pMessage->fadein; - if ( m_parms.charTime > m_parms.time ) - { - srcRed = srcGreen = srcBlue = 0; - blend = 0; // pure source - } - else - { - float deltaTime = m_parms.time - m_parms.charTime; - - destRed = destGreen = destBlue = 0; - if ( m_parms.time > m_parms.fadeTime ) - { - blend = m_parms.fadeBlend; - } - else if ( deltaTime > m_parms.pMessage->fxtime ) - blend = 0; // pure dest - else - { - destRed = m_parms.pMessage->r2; - destGreen = m_parms.pMessage->g2; - destBlue = m_parms.pMessage->b2; - blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5); - } - } - break; - } - if ( blend >= 255 ) - { - m_parms.r = destRed; - m_parms.g = destGreen; - m_parms.b = destBlue; - } - else if ( blend <= 0 ) - { - m_parms.r = srcRed; - m_parms.g = srcGreen; - m_parms.b = srcBlue; - } - else - { - m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; - m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; - m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; - } - - if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) - { - if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth() ) - TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); - } -} - - -void CHudMessage::MessageScanStart( void ) -{ - switch( m_parms.pMessage->effect ) - { - // Fade-in / out with flicker - case 1: - case 0: - m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; - - - if ( m_parms.time < m_parms.pMessage->fadein ) - { - m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); - } - else if ( m_parms.time > m_parms.fadeTime ) - { - if ( m_parms.pMessage->fadeout > 0 ) - m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); - else - m_parms.fadeBlend = 255; // Pure dest (off) - } - else - m_parms.fadeBlend = 0; // Pure source (on) - m_parms.charTime = 0; - - if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) - m_parms.charTime = 1; - break; - - case 2: - m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; - - if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) - m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); - else - m_parms.fadeBlend = 0; - break; - } -} - - -void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) -{ - int i, j, length, width; - const char *pText; - //unsigned char line[80]; - unsigned char line[256]; - - pText = pMessage->pMessage; - ASSERT(pText != NULL); - - // Count lines - m_parms.lines = 1; - m_parms.time = time; - m_parms.pMessage = pMessage; - length = 0; - width = 0; - m_parms.totalWidth = 0; - while ( *pText ) - { - if ( *pText == '\n' ) - { - m_parms.lines++; - if ( width > m_parms.totalWidth ) - m_parms.totalWidth = width; - width = 0; - } - else - width += gHUD.m_scrinfo.charWidths[*pText]; - pText++; - length++; - } - m_parms.length = length; - m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight); - - - m_parms.y = YPosition( pMessage->y, m_parms.totalHeight ); - pText = pMessage->pMessage; - - m_parms.charTime = 0; - - MessageScanStart(); - - for ( i = 0; i < m_parms.lines; i++ ) - { - m_parms.lineLength = 0; - m_parms.width = 0; - while ( *pText && *pText != '\n' ) - { - unsigned char c = *pText; - line[m_parms.lineLength] = c; - m_parms.width += gHUD.m_scrinfo.charWidths[c]; - m_parms.lineLength++; - pText++; - } - pText++; // Skip LF - line[m_parms.lineLength] = 0; - - m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); - - for ( j = 0; j < m_parms.lineLength; j++ ) - { - m_parms.text = line[j]; - int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]; - MessageScanNextChar(); - - if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth() ) - TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); - m_parms.x = next; - } - - m_parms.y += gHUD.m_scrinfo.iCharHeight; - } -} - - -int CHudMessage::Draw( float fTime ) -{ - int i, drawn; - client_textmessage_t *pMessage; - - drawn = 0; - - if ( m_gameTitleTime > 0 ) - { - float localTime = gHUD.m_flTime - m_gameTitleTime; - float brightness; - - // Maybe timer isn't set yet - if ( m_gameTitleTime > gHUD.m_flTime ) - m_gameTitleTime = gHUD.m_flTime; - - if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) - m_gameTitleTime = 0; - else - { - brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); - - int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; - int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; - int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; - - int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); - int y = YPosition( m_pGameTitle->y, fullHeight ); - - - SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); - - SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); - - drawn++; - } - } - - // Draw player id -// if(this->mPlayerIDTime > 0) -// { -// float localTime = gHUD.m_flTime - this->mPlayerIDTime; -// //float brightness; -// -// // Maybe timer isn't set yet -// if ( this->mPlayerIDTime > gHUD.m_flTime ) -// this->mPlayerIDTime = gHUD.m_flTime; -// -// if ( localTime > (this->mPlayerIDMessage.fadein + this->mPlayerIDMessage.holdtime + this->mPlayerIDMessage.fadeout) ) -// { -// this->mPlayerIDTime = 0; -// this->mPlayerIDMessage.pName = NULL; -// this->mPlayerIDMessage.pMessage = NULL; -// } -// else -// { -// drawn++; -// } -// } - - // Fixup level transitions - for ( i = 0; i < maxHUDMessages; i++ ) - { - // Assume m_parms.time contains last time - if ( m_pMessages[i] ) - { - pMessage = m_pMessages[i]; - if ( m_startTime[i] > gHUD.m_flTime ) - m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this - } - } - - for ( i = 0; i < maxHUDMessages; i++ ) - { - client_textmessage_t* theMessage = this->m_pMessages[i]; - if(theMessage) - { - if(this->DrawMessage(theMessage, this->m_startTime[i], fTime)) - { - drawn++; - } - else - { - // The message is over - this->m_pMessages[i] = NULL; - } - } - } - - if(this->DrawMessage(&this->mPlayerIDMessage, this->mPlayerIDTime, fTime)) - { - drawn++; - } - else - { - this->mPlayerIDMessage.pName = NULL; - this->mPlayerIDMessage.pMessage = NULL; - } - - - // Remember the time -- to fix up level transitions - m_parms.time = gHUD.m_flTime; - // Don't call until we get another message - if ( !drawn ) - m_iFlags &= ~HUD_ACTIVE; - - return 1; -} - -bool CHudMessage::DrawMessage(client_textmessage_t* inMessage, float inStartTime, float inCurrentTime) -{ - ASSERT(inMessage); - bool theDrewMessage = false; - - if(inMessage->pMessage) - { - float endTime; - - // This is when the message is over - switch( inMessage->effect ) - { - case 0: - case 1: - endTime = inStartTime + inMessage->fadein + inMessage->fadeout + inMessage->holdtime; - break; - - // Fade in is per character in scanning messages - case 2: - endTime = inStartTime + (inMessage->fadein * strlen( inMessage->pMessage )) + inMessage->fadeout + inMessage->holdtime; - break; - } - - if ( inCurrentTime <= endTime ) - { - float messageTime = inCurrentTime - inStartTime; - - // Draw the message - // effect 0 is fade in/fade out - // effect 1 is flickery credits - // effect 2 is write out (training room) - MessageDrawScan( inMessage, messageTime ); - theDrewMessage = true; - } - } - - return theDrewMessage; -} - -void CHudMessage::MessageAdd( const char *pName, float time ) -{ - int i,j; - client_textmessage_t *tempMessage; - - for ( i = 0; i < maxHUDMessages; i++ ) - { - if ( !m_pMessages[i] ) - { - // Trim off a leading # if it's there - if ( pName[0] == '#' ) - tempMessage = TextMessageGet( pName+1 ); - else - tempMessage = TextMessageGet( pName ); - // If we couldnt find it in the titles.txt, just create it - if ( !tempMessage ) - { - g_pCustomMessage.effect = 2; - g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; - g_pCustomMessage.r2 = 240; - g_pCustomMessage.g2 = 110; - g_pCustomMessage.b2 = 0; - g_pCustomMessage.a2 = 0; - g_pCustomMessage.x = -1; // Centered - g_pCustomMessage.y = 0.7; - g_pCustomMessage.fadein = 0.01; - g_pCustomMessage.fadeout = 1.5; - g_pCustomMessage.fxtime = 0.25; - g_pCustomMessage.holdtime = 5; - g_pCustomMessage.pName = g_pCustomName; - strcpy( g_pCustomText, pName ); - g_pCustomMessage.pMessage = g_pCustomText; - - tempMessage = &g_pCustomMessage; - } - - for ( j = 0; j < maxHUDMessages; j++ ) - { - if ( m_pMessages[j] ) - { - // is this message already in the list - if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) - { - return; - } - - // get rid of any other messages in same location (only one displays at a time) - if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) - { - if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) - { - m_pMessages[j] = NULL; - } - } - } - } - - m_pMessages[i] = tempMessage; - m_startTime[i] = time; - return; - } - } -} - -void CHudMessage::MessageAddPlayerID(const char* inName, bool inEnemy) -{ - // If we're already drawing this, extend the time - //if(inName && this->mPlayerIDMessage.pMessage && !strcmp(inName, this->mPlayerIDMessage.pMessage)) - //{ - // //this->mPlayerIDMessage.holdtime = - //} - //else - //{ - // else add this message - this->mPlayerIDMessage.pMessage = inName; - - //strcpy( g_pCustomText, pName ); - //this->mPlayerIDMessage.pMessage = g_pCustomText; - this->mPlayerIDTime = gHUD.m_flTime; - - // Set color depending on if friend or enemy - if(inEnemy) - { - this->mPlayerIDMessage.r1 = kEnemyRComp; - this->mPlayerIDMessage.g1 = kEnemyGComp; - this->mPlayerIDMessage.b1 = kEnemyBComp; - } - else - { - this->mPlayerIDMessage.r1 = kDefaultRComp; - this->mPlayerIDMessage.g1 = kDefaultGComp; - this->mPlayerIDMessage.b1 = kDefaultBComp; - } - - this->SetPlayerIDPosition(); - - // Turn on drawing - if(inName) - { - if ( !(m_iFlags & HUD_ACTIVE) ) - m_iFlags |= HUD_ACTIVE; - } - - //} -} - -bool CHudMessage::MessageRemove(const char *pName) -{ - const char* theMessage = pName; - bool theSuccess = false; - bool theNeedsTranslation = (pName[0] == '#'); - - // Trim off a leading # if it's there - if(theNeedsTranslation) - { - client_textmessage_t* tempMessage = TextMessageGet(pName + 1); - if(tempMessage) - { - theMessage = tempMessage->pMessage; - } - } - - if(theMessage) - { - for (int j = 0; j < maxHUDMessages; j++ ) - { - if ( m_pMessages[j] ) - { - // is this message already in the list - if (!strcmp(theMessage, m_pMessages[j]->pMessage)) - { - m_startTime[j] = -1; - theSuccess = true; - } - } - } - } - return theSuccess; -} - -int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) -{ - string content; - - NetMsg_HudText( pbuf, iSize, content ); - MessageAdd( content.c_str(), gHUD.m_flTime ); - - // Remember the time -- to fix up level transitions - m_parms.time = gHUD.m_flTime; - - // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -int CHudMessage::MsgFunc_HudText2( const char *pszName, int iSize, void *pbuf ) -{ - string content; - int flags; - NetMsg_HudText2( pbuf, iSize, content, flags ); - - switch (flags) - { - case 2: - gHUD.SetCenterText(content.c_str()); - break; - default: - bool theIsAutoHelp = (flags & 1) != 0; - gHUD.AddTooltip(content.c_str(), theIsAutoHelp); - break; - } - - return 2; -} - -int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) -{ - m_pGameTitle = TextMessageGet( "GAMETITLE" ); - if ( m_pGameTitle != NULL ) - { - m_gameTitleTime = gHUD.m_flTime; - - // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) - m_iFlags |= HUD_ACTIVE; - } - - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Message.cpp +// +// implementation of CHudMessage class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "mod/AvHClientVariables.h" +#include "mod/AvHNetworkMessages.h" + +DECLARE_MESSAGE( m_Message, HudText ) +DECLARE_MESSAGE( m_Message, HudText2 ) +DECLARE_MESSAGE( m_Message, GameTitle ) + +// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt +client_textmessage_t g_pCustomMessage; +char *g_pCustomName = "Custom"; +char g_pCustomText[1024]; + +int CHudMessage::Init(void) +{ + HOOK_MESSAGE( HudText ); + HOOK_MESSAGE( HudText2 ); + HOOK_MESSAGE( GameTitle ); + + gHUD.AddHudElem(this); + + Reset(); + + return 1; +}; + +int CHudMessage::VidInit( void ) +{ + m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); + m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); + + return 1; +}; + +const int kDefaultRComp = 25; +const int kDefaultGComp = 255; +const int kDefaultBComp = 25; + +const int kEnemyRComp = 255; +const int kEnemyGComp = 25; +const int kEnemyBComp = 25; + +void CHudMessage::Reset( void ) +{ + memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); + memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); + + m_gameTitleTime = 0; + m_pGameTitle = NULL; + + // Player id stuff + this->mPlayerIDTime = 0; + this->mPlayerID = NULL; + + this->mPlayerIDMessage.effect = 1; + this->mPlayerIDMessage.r1 = kDefaultRComp; + this->mPlayerIDMessage.g1 = kDefaultGComp; + this->mPlayerIDMessage.b1 = kDefaultBComp; + this->mPlayerIDMessage.a1 = 255; + + this->mPlayerIDMessage.g2 = 255; + this->mPlayerIDMessage.r2 = this->mPlayerIDMessage.b2 = 25; + this->mPlayerIDMessage.a2 = 255; + + this->SetPlayerIDPosition(); + + this->mPlayerIDMessage.fadein = 0.04; + this->mPlayerIDMessage.fadeout = 0.5; + this->mPlayerIDMessage.fxtime = 0.25; + this->mPlayerIDMessage.holdtime = 5; + this->mPlayerIDMessage.pName = NULL; + this->mPlayerIDMessage.pMessage = NULL; +} + +void CHudMessage::SetPlayerIDPosition() +{ + if(gEngfuncs.pfnGetCvarFloat(kvCenterEntityID) || gHUD.GetInTopDownMode()) + { + this->mPlayerIDMessage.x = -1; // Centered + this->mPlayerIDMessage.y = -1; // Centered + } + else + { + this->mPlayerIDMessage.x = .3; + this->mPlayerIDMessage.y = .9; + } +} + +float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) +{ + float fadeTime = fadein + hold; + float fadeBlend; + + if ( localTime < 0 ) + return 0; + + if ( localTime < fadein ) + { + fadeBlend = 1 - ((fadein - localTime) / fadein); + } + else if ( localTime > fadeTime ) + { + if ( fadeout > 0 ) + fadeBlend = 1 - ((localTime - fadeTime) / fadeout); + else + fadeBlend = 0; + } + else + fadeBlend = 1; + + return fadeBlend; +} + + +int CHudMessage::XPosition( float x, int width, int totalWidth ) +{ + int xPos; + + if ( x == -1 ) + { + xPos = (ScreenWidth() - width) / 2; + } + else + { + if ( x < 0 ) + xPos = (1.0 + x) * ScreenWidth() - totalWidth; // Alight right + else + xPos = x * ScreenWidth(); + } + + if ( xPos + width > ScreenWidth() ) + xPos = ScreenWidth() - width; + else if ( xPos < 0 ) + xPos = 0; + + return xPos; +} + + +int CHudMessage::YPosition( float y, int height ) +{ + int yPos; + + if ( y == -1 ) // Centered? + yPos = (ScreenHeight() - height) * 0.5; + else + { + // Alight bottom? + if ( y < 0 ) + yPos = (1.0 + y) * ScreenHeight() - height; // Alight bottom + else // align top + yPos = y * ScreenHeight(); + } + + if ( yPos + height > ScreenHeight() ) + yPos = ScreenHeight() - height; + else if ( yPos < 0 ) + yPos = 0; + + return yPos; +} + + +void CHudMessage::MessageScanNextChar( void ) +{ + int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue; + int blend; + + srcRed = m_parms.pMessage->r1; + srcGreen = m_parms.pMessage->g1; + srcBlue = m_parms.pMessage->b1; + blend = 0; // Pure source + + switch( m_parms.pMessage->effect ) + { + // Fade-in / Fade-out + case 0: + case 1: + destRed = destGreen = destBlue = 0; + blend = m_parms.fadeBlend; + break; + + case 2: + m_parms.charTime += m_parms.pMessage->fadein; + if ( m_parms.charTime > m_parms.time ) + { + srcRed = srcGreen = srcBlue = 0; + blend = 0; // pure source + } + else + { + float deltaTime = m_parms.time - m_parms.charTime; + + destRed = destGreen = destBlue = 0; + if ( m_parms.time > m_parms.fadeTime ) + { + blend = m_parms.fadeBlend; + } + else if ( deltaTime > m_parms.pMessage->fxtime ) + blend = 0; // pure dest + else + { + destRed = m_parms.pMessage->r2; + destGreen = m_parms.pMessage->g2; + destBlue = m_parms.pMessage->b2; + blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5); + } + } + break; + } + if ( blend >= 255 ) + { + m_parms.r = destRed; + m_parms.g = destGreen; + m_parms.b = destBlue; + } + else if ( blend <= 0 ) + { + m_parms.r = srcRed; + m_parms.g = srcGreen; + m_parms.b = srcBlue; + } + else + { + m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; + m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; + m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; + } + + if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) + { + if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth() ) + TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); + } +} + + +void CHudMessage::MessageScanStart( void ) +{ + switch( m_parms.pMessage->effect ) + { + // Fade-in / out with flicker + case 1: + case 0: + m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; + + + if ( m_parms.time < m_parms.pMessage->fadein ) + { + m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); + } + else if ( m_parms.time > m_parms.fadeTime ) + { + if ( m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + else + m_parms.fadeBlend = 255; // Pure dest (off) + } + else + m_parms.fadeBlend = 0; // Pure source (on) + m_parms.charTime = 0; + + if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) + m_parms.charTime = 1; + break; + + case 2: + m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; + + if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + else + m_parms.fadeBlend = 0; + break; + } +} + + +void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) +{ + int i, j, length, width; + const char *pText; + //unsigned char line[80]; + unsigned char line[256]; + + pText = pMessage->pMessage; + ASSERT(pText != NULL); + + // Count lines + m_parms.lines = 1; + m_parms.time = time; + m_parms.pMessage = pMessage; + length = 0; + width = 0; + m_parms.totalWidth = 0; + while ( *pText ) + { + if ( *pText == '\n' ) + { + m_parms.lines++; + if ( width > m_parms.totalWidth ) + m_parms.totalWidth = width; + width = 0; + } + else + width += gHUD.m_scrinfo.charWidths[*pText]; + pText++; + length++; + } + m_parms.length = length; + m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight); + + + m_parms.y = YPosition( pMessage->y, m_parms.totalHeight ); + pText = pMessage->pMessage; + + m_parms.charTime = 0; + + MessageScanStart(); + + for ( i = 0; i < m_parms.lines; i++ ) + { + m_parms.lineLength = 0; + m_parms.width = 0; + while ( *pText && *pText != '\n' ) + { + unsigned char c = *pText; + line[m_parms.lineLength] = c; + m_parms.width += gHUD.m_scrinfo.charWidths[c]; + m_parms.lineLength++; + pText++; + } + pText++; // Skip LF + line[m_parms.lineLength] = 0; + + m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); + + for ( j = 0; j < m_parms.lineLength; j++ ) + { + m_parms.text = line[j]; + int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]; + MessageScanNextChar(); + + if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth() ) + TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); + m_parms.x = next; + } + + m_parms.y += gHUD.m_scrinfo.iCharHeight; + } +} + + +int CHudMessage::Draw( float fTime ) +{ + int i, drawn; + client_textmessage_t *pMessage; + + drawn = 0; + + if ( m_gameTitleTime > 0 ) + { + float localTime = gHUD.m_flTime - m_gameTitleTime; + float brightness; + + // Maybe timer isn't set yet + if ( m_gameTitleTime > gHUD.m_flTime ) + m_gameTitleTime = gHUD.m_flTime; + + if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) + m_gameTitleTime = 0; + else + { + brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); + + int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; + int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; + int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; + + int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); + int y = YPosition( m_pGameTitle->y, fullHeight ); + + + SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); + + SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); + + drawn++; + } + } + + // Draw player id +// if(this->mPlayerIDTime > 0) +// { +// float localTime = gHUD.m_flTime - this->mPlayerIDTime; +// //float brightness; +// +// // Maybe timer isn't set yet +// if ( this->mPlayerIDTime > gHUD.m_flTime ) +// this->mPlayerIDTime = gHUD.m_flTime; +// +// if ( localTime > (this->mPlayerIDMessage.fadein + this->mPlayerIDMessage.holdtime + this->mPlayerIDMessage.fadeout) ) +// { +// this->mPlayerIDTime = 0; +// this->mPlayerIDMessage.pName = NULL; +// this->mPlayerIDMessage.pMessage = NULL; +// } +// else +// { +// drawn++; +// } +// } + + // Fixup level transitions + for ( i = 0; i < maxHUDMessages; i++ ) + { + // Assume m_parms.time contains last time + if ( m_pMessages[i] ) + { + pMessage = m_pMessages[i]; + if ( m_startTime[i] > gHUD.m_flTime ) + m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this + } + } + + for ( i = 0; i < maxHUDMessages; i++ ) + { + client_textmessage_t* theMessage = this->m_pMessages[i]; + if(theMessage) + { + if(this->DrawMessage(theMessage, this->m_startTime[i], fTime)) + { + drawn++; + } + else + { + // The message is over + this->m_pMessages[i] = NULL; + } + } + } + + if(this->DrawMessage(&this->mPlayerIDMessage, this->mPlayerIDTime, fTime)) + { + drawn++; + } + else + { + this->mPlayerIDMessage.pName = NULL; + this->mPlayerIDMessage.pMessage = NULL; + } + + + // Remember the time -- to fix up level transitions + m_parms.time = gHUD.m_flTime; + // Don't call until we get another message + if ( !drawn ) + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + +bool CHudMessage::DrawMessage(client_textmessage_t* inMessage, float inStartTime, float inCurrentTime) +{ + ASSERT(inMessage); + bool theDrewMessage = false; + + if(inMessage->pMessage) + { + float endTime; + + // This is when the message is over + switch( inMessage->effect ) + { + case 0: + case 1: + endTime = inStartTime + inMessage->fadein + inMessage->fadeout + inMessage->holdtime; + break; + + // Fade in is per character in scanning messages + case 2: + endTime = inStartTime + (inMessage->fadein * strlen( inMessage->pMessage )) + inMessage->fadeout + inMessage->holdtime; + break; + } + + if ( inCurrentTime <= endTime ) + { + float messageTime = inCurrentTime - inStartTime; + + // Draw the message + // effect 0 is fade in/fade out + // effect 1 is flickery credits + // effect 2 is write out (training room) + MessageDrawScan( inMessage, messageTime ); + theDrewMessage = true; + } + } + + return theDrewMessage; +} + +void CHudMessage::MessageAdd( const char *pName, float time ) +{ + int i,j; + client_textmessage_t *tempMessage; + + for ( i = 0; i < maxHUDMessages; i++ ) + { + if ( !m_pMessages[i] ) + { + // Trim off a leading # if it's there + if ( pName[0] == '#' ) + tempMessage = TextMessageGet( pName+1 ); + else + tempMessage = TextMessageGet( pName ); + // If we couldnt find it in the titles.txt, just create it + if ( !tempMessage ) + { + g_pCustomMessage.effect = 2; + g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; + g_pCustomMessage.r2 = 240; + g_pCustomMessage.g2 = 110; + g_pCustomMessage.b2 = 0; + g_pCustomMessage.a2 = 0; + g_pCustomMessage.x = -1; // Centered + g_pCustomMessage.y = 0.7; + g_pCustomMessage.fadein = 0.01; + g_pCustomMessage.fadeout = 1.5; + g_pCustomMessage.fxtime = 0.25; + g_pCustomMessage.holdtime = 5; + g_pCustomMessage.pName = g_pCustomName; + strcpy( g_pCustomText, pName ); + g_pCustomMessage.pMessage = g_pCustomText; + + tempMessage = &g_pCustomMessage; + } + + for ( j = 0; j < maxHUDMessages; j++ ) + { + if ( m_pMessages[j] ) + { + // is this message already in the list + if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) + { + return; + } + + // get rid of any other messages in same location (only one displays at a time) + if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) + { + if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) + { + m_pMessages[j] = NULL; + } + } + } + } + + m_pMessages[i] = tempMessage; + m_startTime[i] = time; + return; + } + } +} + +void CHudMessage::MessageAddPlayerID(const char* inName, bool inEnemy) +{ + // If we're already drawing this, extend the time + //if(inName && this->mPlayerIDMessage.pMessage && !strcmp(inName, this->mPlayerIDMessage.pMessage)) + //{ + // //this->mPlayerIDMessage.holdtime = + //} + //else + //{ + // else add this message + this->mPlayerIDMessage.pMessage = inName; + + //strcpy( g_pCustomText, pName ); + //this->mPlayerIDMessage.pMessage = g_pCustomText; + this->mPlayerIDTime = gHUD.m_flTime; + + // Set color depending on if friend or enemy + if(inEnemy) + { + this->mPlayerIDMessage.r1 = kEnemyRComp; + this->mPlayerIDMessage.g1 = kEnemyGComp; + this->mPlayerIDMessage.b1 = kEnemyBComp; + } + else + { + this->mPlayerIDMessage.r1 = kDefaultRComp; + this->mPlayerIDMessage.g1 = kDefaultGComp; + this->mPlayerIDMessage.b1 = kDefaultBComp; + } + + this->SetPlayerIDPosition(); + + // Turn on drawing + if(inName) + { + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + } + + //} +} + +bool CHudMessage::MessageRemove(const char *pName) +{ + const char* theMessage = pName; + bool theSuccess = false; + bool theNeedsTranslation = (pName[0] == '#'); + + // Trim off a leading # if it's there + if(theNeedsTranslation) + { + client_textmessage_t* tempMessage = TextMessageGet(pName + 1); + if(tempMessage) + { + theMessage = tempMessage->pMessage; + } + } + + if(theMessage) + { + for (int j = 0; j < maxHUDMessages; j++ ) + { + if ( m_pMessages[j] ) + { + // is this message already in the list + if (!strcmp(theMessage, m_pMessages[j]->pMessage)) + { + m_startTime[j] = -1; + theSuccess = true; + } + } + } + } + return theSuccess; +} + +int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) +{ + string content; + + NetMsg_HudText( pbuf, iSize, content ); + MessageAdd( content.c_str(), gHUD.m_flTime ); + + // Remember the time -- to fix up level transitions + m_parms.time = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +int CHudMessage::MsgFunc_HudText2( const char *pszName, int iSize, void *pbuf ) +{ + string content; + int flags; + NetMsg_HudText2( pbuf, iSize, content, flags ); + + switch (flags) + { + case 2: + gHUD.SetCenterText(content.c_str()); + break; + default: + bool theIsAutoHelp = (flags & 1) != 0; + gHUD.AddTooltip(content.c_str(), theIsAutoHelp); + break; + } + + return 2; +} + +int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) +{ + m_pGameTitle = TextMessageGet( "GAMETITLE" ); + if ( m_pGameTitle != NULL ) + { + m_gameTitleTime = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + } + + return 1; +} diff --git a/main/source/cl_dll/overview.cpp b/main/source/cl_dll/overview.cpp index 5b519f84..25157310 100644 --- a/main/source/cl_dll/overview.cpp +++ b/main/source/cl_dll/overview.cpp @@ -1,163 +1,163 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" -#include "cl_entity.h" -#include "triangleapi.h" -#include "vgui_TeamFortressViewport.h" - -// these are included for the math functions -#include "com_model.h" -#include "studio_util.h" - -#include "MathUtil.h" -#include "chudmisc.h" - -#pragma warning(disable: 4244) - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CHudOverview::Init() -{ - gHUD.AddHudElem(this); - - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: Loads new icons -//----------------------------------------------------------------------------- -int CHudOverview::VidInit() -{ - m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); - m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flTime - -// intermission - -//----------------------------------------------------------------------------- -int CHudOverview::Draw(float flTime) -{ - // only draw in overview mode - if (!gEngfuncs.Overview_GetOverviewState()) - return 1; - - // make sure we have player info - gViewPort->GetAllPlayersInfo(); - - // calculate player size on the overview - int x1, y1, x2, y2; - float v0[3]={0,0,0}, v1[3]={64,64,0}; - gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); - gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); - float scale = abs(x2 - x1); - - // loop through all the players and draw them on the map - for (int i = 1; i <= MAX_PLAYERS; i++) - { - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); - - if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) - { - int x, y, z = 0; - float v[3]={pl->origin[0], pl->origin[1], 0}; - gEngfuncs.Overview_WorldToScreen(v, &x, &y); - - // hack in some team colors - float r, g, bc; - if (g_PlayerExtraInfo[i].teamnumber == 1) - { - r = 0.0f; g = 0.0f; bc = 1.0f; - } - else if (g_PlayerExtraInfo[i].teamnumber == 2) - { - r = 1.0f; g = 0.0f; bc = 0.0f; - } - else - { - // just use the default orange color if the team isn't set - r = 1.0f; g = 0.7f; bc = 0.0f; - } - - // set the current texture - gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); - - // additive render mode - gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); - - // no culling - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - // draw a square - gEngfuncs.pTriAPI->Begin(TRI_QUADS); - - // set the color to be that of the team - gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); - - // calculate rotational matrix - vec3_t a, b, angles; - float rmatrix[3][4]; // transformation matrix - VectorCopy(pl->angles, angles); - angles[0] = 0.0f; - angles[1] += 90.f; - angles[1] = -angles[1]; - angles[2] = 0.0f; - AngleMatrix(angles, rmatrix); - a[2] = 0; - - a[0] = -scale; a[1] = -scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); - - a[0]=-scale; a[1] = scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - a[0]=scale; a[1] = scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - a[0]=scale; a[1] = -scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - // finish up - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - - // draw the players name and health underneath - char string[256]; - sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); - DrawConsoleString(x, y + (1.1 * scale), string); - } - } - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: called every time a server is connected to -//----------------------------------------------------------------------------- -void CHudOverview::InitHUDData() -{ -// this block would force the spectator view to be on -// gEngfuncs.Overview_SetDrawOverview( 1 ); -// gEngfuncs.Overview_SetDrawInset( 0 ); -} - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "vgui_TeamFortressViewport.h" + +// these are included for the math functions +#include "com_model.h" +#include "studio_util.h" + +#include "MathUtil.h" +#include "chudmisc.h" + +#pragma warning(disable: 4244) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudOverview::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudOverview::VidInit() +{ + m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); + m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudOverview::Draw(float flTime) +{ + // only draw in overview mode + if (!gEngfuncs.Overview_GetOverviewState()) + return 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + + // calculate player size on the overview + int x1, y1, x2, y2; + float v0[3]={0,0,0}, v1[3]={64,64,0}; + gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); + gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); + float scale = abs(x2 - x1); + + // loop through all the players and draw them on the map + for (int i = 1; i <= MAX_PLAYERS; i++) + { + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); + + if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) + { + int x, y, z = 0; + float v[3]={pl->origin[0], pl->origin[1], 0}; + gEngfuncs.Overview_WorldToScreen(v, &x, &y); + + // hack in some team colors + float r, g, bc; + if (g_PlayerExtraInfo[i].teamnumber == 1) + { + r = 0.0f; g = 0.0f; bc = 1.0f; + } + else if (g_PlayerExtraInfo[i].teamnumber == 2) + { + r = 1.0f; g = 0.0f; bc = 0.0f; + } + else + { + // just use the default orange color if the team isn't set + r = 1.0f; g = 0.7f; bc = 0.0f; + } + + // set the current texture + gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); + + // additive render mode + gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); + + // no culling + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + // draw a square + gEngfuncs.pTriAPI->Begin(TRI_QUADS); + + // set the color to be that of the team + gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); + + // calculate rotational matrix + vec3_t a, b, angles; + float rmatrix[3][4]; // transformation matrix + VectorCopy(pl->angles, angles); + angles[0] = 0.0f; + angles[1] += 90.f; + angles[1] = -angles[1]; + angles[2] = 0.0f; + AngleMatrix(angles, rmatrix); + a[2] = 0; + + a[0] = -scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); + + a[0]=-scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + // finish up + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + + // draw the players name and health underneath + char string[256]; + sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); + DrawConsoleString(x, y + (1.1 * scale), string); + } + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: called every time a server is connected to +//----------------------------------------------------------------------------- +void CHudOverview::InitHUDData() +{ +// this block would force the spectator view to be on +// gEngfuncs.Overview_SetDrawOverview( 1 ); +// gEngfuncs.Overview_SetDrawInset( 0 ); +} + diff --git a/main/source/cl_dll/overview.h b/main/source/cl_dll/overview.h index 40e13d27..b4fdbc6b 100644 --- a/main/source/cl_dll/overview.h +++ b/main/source/cl_dll/overview.h @@ -1,30 +1,30 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef OVERVIEW_H -#define OVERVIEW_H -#pragma once - -//----------------------------------------------------------------------------- -// Purpose: Handles the drawing of the top-down map and all the things on it -//----------------------------------------------------------------------------- -class CHudOverview : public CHudBase -{ -public: - int Init(); - int VidInit(); - - int Draw(float flTime); - void InitHUDData( void ); - -private: - HSPRITE m_hsprPlayer; - HSPRITE m_hsprViewcone; -}; - - -#endif // OVERVIEW_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef OVERVIEW_H +#define OVERVIEW_H +#pragma once + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the top-down map and all the things on it +//----------------------------------------------------------------------------- +class CHudOverview : public CHudBase +{ +public: + int Init(); + int VidInit(); + + int Draw(float flTime); + void InitHUDData( void ); + +private: + HSPRITE m_hsprPlayer; + HSPRITE m_hsprViewcone; +}; + + +#endif // OVERVIEW_H diff --git a/main/source/cl_dll/parsemsg.cpp b/main/source/cl_dll/parsemsg.cpp index d7070de5..871140a9 100644 --- a/main/source/cl_dll/parsemsg.cpp +++ b/main/source/cl_dll/parsemsg.cpp @@ -1,166 +1,166 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// parsemsg.cpp -// -typedef unsigned char byte; -#define true 1 - -static byte *gpBuf; -static int giSize; -static int giRead; -static int giBadRead; - -void BEGIN_READ( void *buf, int size ) -{ - giRead = 0; - giBadRead = 0; - giSize = size; - gpBuf = (byte*)buf; -} - - -int READ_CHAR( void ) -{ - int c; - - if (giRead + 1 > giSize) - { - giBadRead = true; - return -1; - } - - c = (signed char)gpBuf[giRead]; - giRead++; - - return c; -} - -int READ_BYTE( void ) -{ - int c; - - if (giRead+1 > giSize) - { - giBadRead = true; - return -1; - } - - c = (unsigned char)gpBuf[giRead]; - giRead++; - - return c; -} - -int READ_SHORT( void ) -{ - int c; - - if (giRead+2 > giSize) - { - giBadRead = true; - return -1; - } - - c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); - - giRead += 2; - - return c; -} - -int READ_WORD( void ) -{ - return READ_SHORT(); -} - - -int READ_LONG( void ) -{ - int c; - - if (giRead+4 > giSize) - { - giBadRead = true; - return -1; - } - - c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); - - giRead += 4; - - return c; -} - -float READ_FLOAT( void ) -{ - union - { - byte b[4]; - float f; - int l; - } dat; - - dat.b[0] = gpBuf[giRead]; - dat.b[1] = gpBuf[giRead+1]; - dat.b[2] = gpBuf[giRead+2]; - dat.b[3] = gpBuf[giRead+3]; - giRead += 4; - -// dat.l = LittleLong (dat.l); - - return dat.f; -} - -char* READ_STRING( void ) -{ - static char string[2048]; - int l,c; - - string[0] = 0; - - l = 0; - do - { - if ( giRead+1 > giSize ) - break; // no more characters - - c = READ_CHAR(); - if (c == -1 || c == 0) - break; - string[l] = c; - l++; - } while (l < sizeof(string)-1); - - string[l] = 0; - - return string; -} - -float READ_COORD( void ) -{ - return (float)(READ_SHORT() * (1.0/8)); -} - -float READ_ANGLE( void ) -{ - return (float)(READ_CHAR() * (360.0/256)); -} - -float READ_HIRESANGLE( void ) -{ - return (float)(READ_SHORT() * (360.0/65536)); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// parsemsg.cpp +// +typedef unsigned char byte; +#define true 1 + +static byte *gpBuf; +static int giSize; +static int giRead; +static int giBadRead; + +void BEGIN_READ( void *buf, int size ) +{ + giRead = 0; + giBadRead = 0; + giSize = size; + gpBuf = (byte*)buf; +} + + +int READ_CHAR( void ) +{ + int c; + + if (giRead + 1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (signed char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_BYTE( void ) +{ + int c; + + if (giRead+1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (unsigned char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_SHORT( void ) +{ + int c; + + if (giRead+2 > giSize) + { + giBadRead = true; + return -1; + } + + c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); + + giRead += 2; + + return c; +} + +int READ_WORD( void ) +{ + return READ_SHORT(); +} + + +int READ_LONG( void ) +{ + int c; + + if (giRead+4 > giSize) + { + giBadRead = true; + return -1; + } + + c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); + + giRead += 4; + + return c; +} + +float READ_FLOAT( void ) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = gpBuf[giRead]; + dat.b[1] = gpBuf[giRead+1]; + dat.b[2] = gpBuf[giRead+2]; + dat.b[3] = gpBuf[giRead+3]; + giRead += 4; + +// dat.l = LittleLong (dat.l); + + return dat.f; +} + +char* READ_STRING( void ) +{ + static char string[2048]; + int l,c; + + string[0] = 0; + + l = 0; + do + { + if ( giRead+1 > giSize ) + break; // no more characters + + c = READ_CHAR(); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float READ_COORD( void ) +{ + return (float)(READ_SHORT() * (1.0/8)); +} + +float READ_ANGLE( void ) +{ + return (float)(READ_CHAR() * (360.0/256)); +} + +float READ_HIRESANGLE( void ) +{ + return (float)(READ_SHORT() * (360.0/65536)); +} + diff --git a/main/source/cl_dll/parsemsg.h b/main/source/cl_dll/parsemsg.h index 382ac58a..d586facf 100644 --- a/main/source/cl_dll/parsemsg.h +++ b/main/source/cl_dll/parsemsg.h @@ -1,40 +1,40 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// parsemsg.h -// - -//#define ASSERT( x ) - -void BEGIN_READ( void *buf, int size ); -int READ_CHAR( void ); -int READ_BYTE( void ); -int READ_SHORT( void ); -int READ_WORD( void ); -int READ_LONG( void ); -float READ_FLOAT( void ); -char* READ_STRING( void ); -float READ_COORD( void ); -float READ_ANGLE( void ); -float READ_HIRESANGLE( void ); - - - - - - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// parsemsg.h +// + +//#define ASSERT( x ) + +void BEGIN_READ( void *buf, int size ); +int READ_CHAR( void ); +int READ_BYTE( void ); +int READ_SHORT( void ); +int READ_WORD( void ); +int READ_LONG( void ); +float READ_FLOAT( void ); +char* READ_STRING( void ); +float READ_COORD( void ); +float READ_ANGLE( void ); +float READ_HIRESANGLE( void ); + + + + + + + + + diff --git a/main/source/cl_dll/r_studioint.h b/main/source/cl_dll/r_studioint.h index 973ae182..1ff470cf 100644 --- a/main/source/cl_dll/r_studioint.h +++ b/main/source/cl_dll/r_studioint.h @@ -1,108 +1,108 @@ -#if !defined( R_STUDIOINT_H ) -#define R_STUDIOINT_H -#if defined( _WIN32 ) -#pragma once -#endif - -#define STUDIO_INTERFACE_VERSION 1 - -typedef struct engine_studio_api_s -{ - // Allocate number*size bytes and zero it - void *( *Mem_Calloc ) ( int number, size_t size ); - // Check to see if pointer is in the cache - void *( *Cache_Check ) ( struct cache_user_s *c ); - // Load file into cache ( can be swapped out on demand ) - void ( *LoadCacheFile ) ( char *path, struct cache_user_s *cu ); - // Retrieve model pointer for the named model - struct model_s *( *Mod_ForName ) ( const char *name, int crash_if_missing ); - // Retrieve pointer to studio model data block from a model - void *( *Mod_Extradata ) ( struct model_s *mod ); - // Retrieve indexed model from client side model precache list - struct model_s *( *GetModelByIndex ) ( int index ); - // Get entity that is set for rendering - struct cl_entity_s * ( *GetCurrentEntity ) ( void ); - // Get referenced player_info_t - struct player_info_s *( *PlayerInfo ) ( int index ); - // Get most recently received player state data from network system - struct entity_state_s *( *GetPlayerState ) ( int index ); - // Get viewentity - struct cl_entity_s * ( *GetViewEntity ) ( void ); - // Get current frame count, and last two timestampes on client - void ( *GetTimes ) ( int *framecount, double *current, double *old ); - // Get a pointer to a cvar by name - struct cvar_s *( *GetCvar ) ( const char *name ); - // Get current render origin and view vectors ( up, right and vpn ) - void ( *GetViewInfo ) ( float *origin, float *upv, float *rightv, float *vpnv ); - // Get sprite model used for applying chrome effect - struct model_s *( *GetChromeSprite ) ( void ); - // Get model counters so we can incement instrumentation - void ( *GetModelCounters ) ( int **s, int **a ); - // Get software scaling coefficients - void ( *GetAliasScale ) ( float *x, float *y ); - - // Get bone, light, alias, and rotation matrices - float ****( *StudioGetBoneTransform ) ( void ); - float ****( *StudioGetLightTransform )( void ); - float ***( *StudioGetAliasTransform ) ( void ); - float ***( *StudioGetRotationMatrix ) ( void ); - - // Set up body part, and get submodel pointers - void ( *StudioSetupModel ) ( int bodypart, void **ppbodypart, void **ppsubmodel ); - // Check if entity's bbox is in the view frustum - int ( *StudioCheckBBox ) ( void ); - // Apply lighting effects to model - void ( *StudioDynamicLight ) ( struct cl_entity_s *ent, struct alight_s *plight ); - void ( *StudioEntityLight ) ( struct alight_s *plight ); - void ( *StudioSetupLighting ) ( struct alight_s *plighting ); - - // Draw mesh vertices - void ( *StudioDrawPoints ) ( void ); - - // Draw hulls around bones - void ( *StudioDrawHulls ) ( void ); - // Draw bbox around studio models - void ( *StudioDrawAbsBBox ) ( void ); - // Draws bones - void ( *StudioDrawBones ) ( void ); - // Loads in appropriate texture for model - void ( *StudioSetupSkin ) ( void *ptexturehdr, int index ); - // Sets up for remapped colors - void ( *StudioSetRemapColors ) ( int top, int bottom ); - // Set's player model and returns model pointer - struct model_s *( *SetupPlayerModel ) ( int index ); - // Fires any events embedded in animation - void ( *StudioClientEvents ) ( void ); - // Retrieve/set forced render effects flags - int ( *GetForceFaceFlags ) ( void ); - void ( *SetForceFaceFlags ) ( int flags ); - // Tell engine the value of the studio model header - void ( *StudioSetHeader ) ( void *header ); - // Tell engine which model_t * is being renderered - void ( *SetRenderModel ) ( struct model_s *model ); - - // Final state setup and restore for rendering - void ( *SetupRenderer ) ( int rendermode ); - void ( *RestoreRenderer ) ( void ); - - // Set render origin for applying chrome effect - void ( *SetChromeOrigin ) ( void ); - - // True if using D3D/OpenGL - int ( *IsHardware ) ( void ); - - // Only called by hardware interface - void ( *GL_StudioDrawShadow ) ( void ); - void ( *GL_SetRenderMode ) ( int mode ); -} engine_studio_api_t; - -typedef struct r_studio_interface_s -{ - int version; - int ( *StudioDrawModel ) ( int flags ); - int ( *StudioDrawPlayer ) ( int flags, struct entity_state_s *pplayer ); -} r_studio_interface_t; - -extern r_studio_interface_t *pStudioAPI; - +#if !defined( R_STUDIOINT_H ) +#define R_STUDIOINT_H +#if defined( _WIN32 ) +#pragma once +#endif + +#define STUDIO_INTERFACE_VERSION 1 + +typedef struct engine_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc ) ( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check ) ( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile ) ( char *path, struct cache_user_s *cu ); + // Retrieve model pointer for the named model + struct model_s *( *Mod_ForName ) ( const char *name, int crash_if_missing ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata ) ( struct model_s *mod ); + // Retrieve indexed model from client side model precache list + struct model_s *( *GetModelByIndex ) ( int index ); + // Get entity that is set for rendering + struct cl_entity_s * ( *GetCurrentEntity ) ( void ); + // Get referenced player_info_t + struct player_info_s *( *PlayerInfo ) ( int index ); + // Get most recently received player state data from network system + struct entity_state_s *( *GetPlayerState ) ( int index ); + // Get viewentity + struct cl_entity_s * ( *GetViewEntity ) ( void ); + // Get current frame count, and last two timestampes on client + void ( *GetTimes ) ( int *framecount, double *current, double *old ); + // Get a pointer to a cvar by name + struct cvar_s *( *GetCvar ) ( const char *name ); + // Get current render origin and view vectors ( up, right and vpn ) + void ( *GetViewInfo ) ( float *origin, float *upv, float *rightv, float *vpnv ); + // Get sprite model used for applying chrome effect + struct model_s *( *GetChromeSprite ) ( void ); + // Get model counters so we can incement instrumentation + void ( *GetModelCounters ) ( int **s, int **a ); + // Get software scaling coefficients + void ( *GetAliasScale ) ( float *x, float *y ); + + // Get bone, light, alias, and rotation matrices + float ****( *StudioGetBoneTransform ) ( void ); + float ****( *StudioGetLightTransform )( void ); + float ***( *StudioGetAliasTransform ) ( void ); + float ***( *StudioGetRotationMatrix ) ( void ); + + // Set up body part, and get submodel pointers + void ( *StudioSetupModel ) ( int bodypart, void **ppbodypart, void **ppsubmodel ); + // Check if entity's bbox is in the view frustum + int ( *StudioCheckBBox ) ( void ); + // Apply lighting effects to model + void ( *StudioDynamicLight ) ( struct cl_entity_s *ent, struct alight_s *plight ); + void ( *StudioEntityLight ) ( struct alight_s *plight ); + void ( *StudioSetupLighting ) ( struct alight_s *plighting ); + + // Draw mesh vertices + void ( *StudioDrawPoints ) ( void ); + + // Draw hulls around bones + void ( *StudioDrawHulls ) ( void ); + // Draw bbox around studio models + void ( *StudioDrawAbsBBox ) ( void ); + // Draws bones + void ( *StudioDrawBones ) ( void ); + // Loads in appropriate texture for model + void ( *StudioSetupSkin ) ( void *ptexturehdr, int index ); + // Sets up for remapped colors + void ( *StudioSetRemapColors ) ( int top, int bottom ); + // Set's player model and returns model pointer + struct model_s *( *SetupPlayerModel ) ( int index ); + // Fires any events embedded in animation + void ( *StudioClientEvents ) ( void ); + // Retrieve/set forced render effects flags + int ( *GetForceFaceFlags ) ( void ); + void ( *SetForceFaceFlags ) ( int flags ); + // Tell engine the value of the studio model header + void ( *StudioSetHeader ) ( void *header ); + // Tell engine which model_t * is being renderered + void ( *SetRenderModel ) ( struct model_s *model ); + + // Final state setup and restore for rendering + void ( *SetupRenderer ) ( int rendermode ); + void ( *RestoreRenderer ) ( void ); + + // Set render origin for applying chrome effect + void ( *SetChromeOrigin ) ( void ); + + // True if using D3D/OpenGL + int ( *IsHardware ) ( void ); + + // Only called by hardware interface + void ( *GL_StudioDrawShadow ) ( void ); + void ( *GL_SetRenderMode ) ( int mode ); +} engine_studio_api_t; + +typedef struct r_studio_interface_s +{ + int version; + int ( *StudioDrawModel ) ( int flags ); + int ( *StudioDrawPlayer ) ( int flags, struct entity_state_s *pplayer ); +} r_studio_interface_t; + +extern r_studio_interface_t *pStudioAPI; + #endif // R_STUDIOINT_H \ No newline at end of file diff --git a/main/source/cl_dll/saytext.cpp b/main/source/cl_dll/saytext.cpp index db8abb30..973d2b14 100644 --- a/main/source/cl_dll/saytext.cpp +++ b/main/source/cl_dll/saytext.cpp @@ -1,379 +1,379 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// saytext.cpp -// -// implementation of CHudSayText class -// - -#include "hud.h" -#include "cl_util.h" -#include "mod/AvHNetworkMessages.h" - -#include -#include - -#include "vgui_TeamFortressViewport.h" -#include "mod/AvHClientUtil.h" -#include "ui/ChatPanel.h" - -float* GetClientColor(int clientIndex); - -#define MAX_LINES 5 -#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ - -// allow 20 pixels on either side of the text -#define MAX_LINE_WIDTH ( ScreenWidth() - 40 ) -#define LINE_START 10 -static float SCROLL_SPEED = 5; - -static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; -static float *g_pflNameColors[ MAX_LINES + 1 ]; -static int g_iNameLengths[ MAX_LINES + 1 ]; -static float flScrollTime = 0; // the time at which the lines next scroll up - -static int Y_START = 0; -static int line_height = 0; - -DECLARE_MESSAGE( m_SayText, SayText ); - -int CHudSayText :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( SayText ); - - InitHUDData(); - - m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); - m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); - - m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission - - return 1; -} - - -void CHudSayText :: InitHUDData( void ) -{ - memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); - memset( g_pflNameColors, 0, sizeof g_pflNameColors ); - memset( g_iNameLengths, 0, sizeof g_iNameLengths ); -} - -int CHudSayText :: VidInit( void ) -{ - return 1; -} - - -int ScrollTextUp( void ) -{ - ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer - g_szLineBuffer[MAX_LINES][0] = 0; - memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line - memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); - memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); - g_szLineBuffer[MAX_LINES-1][0] = 0; - - if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines - { - g_szLineBuffer[0][0] = 2; - return 1 + ScrollTextUp(); - } - - return 1; -} - -int CHudSayText :: Draw( float flTime ) -{ - int y = Y_START; - - if ( ( gViewPort && gViewPort->AllowedToPrintText() == FALSE) || !m_HUD_saytext->value ) - return 1; - - // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset - flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); - - // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset - flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); - - if ( flScrollTime <= flTime ) - { - if ( *g_szLineBuffer[0] ) - { - flScrollTime = flTime + m_HUD_saytext_time->value; - // push the console up - ScrollTextUp(); - } - else - { // buffer is empty, just disable drawing of this section - m_iFlags &= ~HUD_ACTIVE; - } - } - - for ( int i = 0; i < MAX_LINES; i++ ) - { - if ( *g_szLineBuffer[i] ) - { - if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) - { - // it's a saytext string - static char buf[MAX_PLAYER_NAME_LENGTH+32]; - - // draw the first x characters in the player color - strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); - buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; - DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); - - // If we're an alien, move chat over a bit so it doesn't overlap energy bar - int theDrawX = LINE_START; - //if(gHUD.GetIsAlien()) - //{ - // theDrawX += .07f*ScreenWidth; - //} - int x = DrawConsoleString(theDrawX, y, buf ); - - // color is reset after each string draw - DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); - } - else - { - // normal draw - DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); - } - } - - y += line_height; - } - - - return 1; -} - -int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) -{ - - int client_index; - string content, location; - NetMsg_SayText( pbuf, iSize, client_index, content, location ); - - string theTranslatedLocation; - if(LocalizeString(location.c_str(), theTranslatedLocation)) - { - // If player is on our team, add location - cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(client_index); - cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer(); - - if(theEntity && theLocalPlayer && (theEntity->curstate.team == theLocalPlayer->curstate.team)) - { - // Search for first : so we can insert location - int theColonIndex = (int)content.find_first_of(":"); - if((theColonIndex > 0) && (theColonIndex < (int)content.length())) - { - AvHCUTrimExtraneousLocationText(theTranslatedLocation); - - // Insert location - string theNewMessage = content.substr(0, theColonIndex); - theNewMessage += " ("; - - theNewMessage += theTranslatedLocation; - theNewMessage += ")"; - theNewMessage += content.substr(theColonIndex); - - // Replace the message with new one - content = theNewMessage; - } - } - } - - SayTextPrint(content.c_str(), (int)content.length(), client_index ); - - return 1; -} - -void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) -{ - if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) - { - // Print it straight to the console - ConsolePrint( pszBuf ); - return; - } - - // find an empty string slot - int i = 0; - for ( i = 0; i < MAX_LINES; i++ ) - { - if ( ! *g_szLineBuffer[i] ) - break; - } - if ( i == MAX_LINES ) - { - // force scroll buffer up - ScrollTextUp(); - i = MAX_LINES - 1; - } - - g_iNameLengths[i] = 0; - g_pflNameColors[i] = NULL; - - // if it's a say message, search for the players name in the string - if ( *pszBuf == 2 && clientIndex > 0 ) - { - GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); - const char *pName = g_PlayerInfoList[clientIndex].name; - - if ( pName ) - { - const char *nameInString = strstr( pszBuf, pName ); - - if ( nameInString ) - { - g_iNameLengths[i] = (int)strlen( pName ) + (nameInString - pszBuf); - g_pflNameColors[i] = GetClientColor(clientIndex); - } - } - } - - // : 0001087 - // don't strip last character ( often resulted in no carriage returns in the log ) - strncpy( g_szLineBuffer[i], pszBuf, min(iBufSize, MAX_CHARS_PER_LINE-1) ); - - // make sure the text fits in one line - EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); - - // Set scroll time - if ( i == 0 ) - { - flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; - } - - m_iFlags |= HUD_ACTIVE; - //PlaySound( "misc/talk.wav", 1 ); - gHUD.PlayHUDSound("misc/talk.wav", 1); - - Y_START = ScreenHeight()*.7f; - /* @linux no chat panel - ChatPanel* theChatPanel = gViewPort->GetChatPanel(); - - if (theChatPanel != NULL) - { - - int theX; - int theY; - int theWidth; - int theHeight; - - gViewPort->GetChatPanel()->getPos(theX, theY); - gViewPort->GetChatPanel()->getSize(theWidth, theHeight); - - //Y_START = theY + theHeight + 5; //: this is too high imo. - //KGP: then move the viewport - Y_START = theY + theHeight + 5; - } - */ -} - -void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) -{ - int line_width = 0; - GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); - - if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) - { // string is too long to fit on line - // scan the string until we find what word is too long, and wrap the end of the sentence after the word - int length = LINE_START; - int tmp_len = 0; - char *last_break = NULL; - for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) - { - // check for a color change, if so skip past it - if ( x[0] == '/' && x[1] == '(' ) - { - x += 2; - // skip forward until past mode specifier - while ( *x != 0 && *x != ')' ) - x++; - - if ( *x != 0 ) - x++; - - if ( *x == 0 ) - break; - } - - char buf[2]; - buf[1] = 0; - - if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character - last_break = x; - - buf[0] = *x; // get the length of the current character - GetConsoleStringSize( buf, &tmp_len, &line_height ); - length += tmp_len; - - if ( length > MAX_LINE_WIDTH ) - { // needs to be broken up - if ( !last_break ) - last_break = x-1; - - x = last_break; - - // find an empty string slot - int j; - do - { - for ( j = 0; j < MAX_LINES; j++ ) - { - if ( ! *g_szLineBuffer[j] ) - break; - } - if ( j == MAX_LINES ) - { - // need to make more room to display text, scroll stuff up then fix the pointers - int linesmoved = ScrollTextUp(); - line -= linesmoved; - last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); - } - } - while ( j == MAX_LINES ); - - // copy remaining string into next buffer, making sure it starts with a space character - if ( (char)*last_break == (char)' ' ) - { - int linelen = (int)strlen(g_szLineBuffer[j]); - int remaininglen = (int)strlen(last_break); - - if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) - strcat( g_szLineBuffer[j], last_break ); - } - else - { - if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) - { - strcat( g_szLineBuffer[j], " " ); - strcat( g_szLineBuffer[j], last_break ); - } - } - - *last_break = 0; // cut off the last string - - EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); - break; - } - } - } +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// saytext.cpp +// +// implementation of CHudSayText class +// + +#include "hud.h" +#include "cl_util.h" +#include "mod/AvHNetworkMessages.h" + +#include +#include + +#include "vgui_TeamFortressViewport.h" +#include "mod/AvHClientUtil.h" +#include "ui/ChatPanel.h" + +float* GetClientColor(int clientIndex); + +#define MAX_LINES 5 +#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ + +// allow 20 pixels on either side of the text +#define MAX_LINE_WIDTH ( ScreenWidth() - 40 ) +#define LINE_START 10 +static float SCROLL_SPEED = 5; + +static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; +static float *g_pflNameColors[ MAX_LINES + 1 ]; +static int g_iNameLengths[ MAX_LINES + 1 ]; +static float flScrollTime = 0; // the time at which the lines next scroll up + +static int Y_START = 0; +static int line_height = 0; + +DECLARE_MESSAGE( m_SayText, SayText ); + +int CHudSayText :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( SayText ); + + InitHUDData(); + + m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); + m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); + + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission + + return 1; +} + + +void CHudSayText :: InitHUDData( void ) +{ + memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); + memset( g_pflNameColors, 0, sizeof g_pflNameColors ); + memset( g_iNameLengths, 0, sizeof g_iNameLengths ); +} + +int CHudSayText :: VidInit( void ) +{ + return 1; +} + + +int ScrollTextUp( void ) +{ + ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer + g_szLineBuffer[MAX_LINES][0] = 0; + memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line + memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); + memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); + g_szLineBuffer[MAX_LINES-1][0] = 0; + + if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines + { + g_szLineBuffer[0][0] = 2; + return 1 + ScrollTextUp(); + } + + return 1; +} + +int CHudSayText :: Draw( float flTime ) +{ + int y = Y_START; + + if ( ( gViewPort && gViewPort->AllowedToPrintText() == FALSE) || !m_HUD_saytext->value ) + return 1; + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + if ( flScrollTime <= flTime ) + { + if ( *g_szLineBuffer[0] ) + { + flScrollTime = flTime + m_HUD_saytext_time->value; + // push the console up + ScrollTextUp(); + } + else + { // buffer is empty, just disable drawing of this section + m_iFlags &= ~HUD_ACTIVE; + } + } + + for ( int i = 0; i < MAX_LINES; i++ ) + { + if ( *g_szLineBuffer[i] ) + { + if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) + { + // it's a saytext string + static char buf[MAX_PLAYER_NAME_LENGTH+32]; + + // draw the first x characters in the player color + strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); + buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; + DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + + // If we're an alien, move chat over a bit so it doesn't overlap energy bar + int theDrawX = LINE_START; + //if(gHUD.GetIsAlien()) + //{ + // theDrawX += .07f*ScreenWidth; + //} + int x = DrawConsoleString(theDrawX, y, buf ); + + // color is reset after each string draw + DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); + } + else + { + // normal draw + DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); + } + } + + y += line_height; + } + + + return 1; +} + +int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) +{ + + int client_index; + string content, location; + NetMsg_SayText( pbuf, iSize, client_index, content, location ); + + string theTranslatedLocation; + if(LocalizeString(location.c_str(), theTranslatedLocation)) + { + // If player is on our team, add location + cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(client_index); + cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer(); + + if(theEntity && theLocalPlayer && (theEntity->curstate.team == theLocalPlayer->curstate.team)) + { + // Search for first : so we can insert location + int theColonIndex = (int)content.find_first_of(":"); + if((theColonIndex > 0) && (theColonIndex < (int)content.length())) + { + AvHCUTrimExtraneousLocationText(theTranslatedLocation); + + // Insert location + string theNewMessage = content.substr(0, theColonIndex); + theNewMessage += " ("; + + theNewMessage += theTranslatedLocation; + theNewMessage += ")"; + theNewMessage += content.substr(theColonIndex); + + // Replace the message with new one + content = theNewMessage; + } + } + } + + SayTextPrint(content.c_str(), (int)content.length(), client_index ); + + return 1; +} + +void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) +{ + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + { + // Print it straight to the console + ConsolePrint( pszBuf ); + return; + } + + // find an empty string slot + int i = 0; + for ( i = 0; i < MAX_LINES; i++ ) + { + if ( ! *g_szLineBuffer[i] ) + break; + } + if ( i == MAX_LINES ) + { + // force scroll buffer up + ScrollTextUp(); + i = MAX_LINES - 1; + } + + g_iNameLengths[i] = 0; + g_pflNameColors[i] = NULL; + + // if it's a say message, search for the players name in the string + if ( *pszBuf == 2 && clientIndex > 0 ) + { + GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); + const char *pName = g_PlayerInfoList[clientIndex].name; + + if ( pName ) + { + const char *nameInString = strstr( pszBuf, pName ); + + if ( nameInString ) + { + g_iNameLengths[i] = (int)strlen( pName ) + (nameInString - pszBuf); + g_pflNameColors[i] = GetClientColor(clientIndex); + } + } + } + + // : 0001087 + // don't strip last character ( often resulted in no carriage returns in the log ) + strncpy( g_szLineBuffer[i], pszBuf, min(iBufSize, MAX_CHARS_PER_LINE-1) ); + + // make sure the text fits in one line + EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); + + // Set scroll time + if ( i == 0 ) + { + flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; + } + + m_iFlags |= HUD_ACTIVE; + //PlaySound( "misc/talk.wav", 1 ); + gHUD.PlayHUDSound("misc/talk.wav", 1); + + Y_START = ScreenHeight()*.7f; + + ChatPanel* theChatPanel = gViewPort->GetChatPanel(); + + if (theChatPanel != NULL) + { + + int theX; + int theY; + int theWidth; + int theHeight; + + gViewPort->GetChatPanel()->getPos(theX, theY); + gViewPort->GetChatPanel()->getSize(theWidth, theHeight); + + //Y_START = theY + theHeight + 5; //: this is too high imo. + //KGP: then move the viewport + Y_START = theY + theHeight + 5; + } + +} + +void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) +{ + int line_width = 0; + GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); + + if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) + { // string is too long to fit on line + // scan the string until we find what word is too long, and wrap the end of the sentence after the word + int length = LINE_START; + int tmp_len = 0; + char *last_break = NULL; + for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) + { + // check for a color change, if so skip past it + if ( x[0] == '/' && x[1] == '(' ) + { + x += 2; + // skip forward until past mode specifier + while ( *x != 0 && *x != ')' ) + x++; + + if ( *x != 0 ) + x++; + + if ( *x == 0 ) + break; + } + + char buf[2]; + buf[1] = 0; + + if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character + last_break = x; + + buf[0] = *x; // get the length of the current character + GetConsoleStringSize( buf, &tmp_len, &line_height ); + length += tmp_len; + + if ( length > MAX_LINE_WIDTH ) + { // needs to be broken up + if ( !last_break ) + last_break = x-1; + + x = last_break; + + // find an empty string slot + int j; + do + { + for ( j = 0; j < MAX_LINES; j++ ) + { + if ( ! *g_szLineBuffer[j] ) + break; + } + if ( j == MAX_LINES ) + { + // need to make more room to display text, scroll stuff up then fix the pointers + int linesmoved = ScrollTextUp(); + line -= linesmoved; + last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); + } + } + while ( j == MAX_LINES ); + + // copy remaining string into next buffer, making sure it starts with a space character + if ( (char)*last_break == (char)' ' ) + { + int linelen = (int)strlen(g_szLineBuffer[j]); + int remaininglen = (int)strlen(last_break); + + if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) + strcat( g_szLineBuffer[j], last_break ); + } + else + { + if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) + { + strcat( g_szLineBuffer[j], " " ); + strcat( g_szLineBuffer[j], last_break ); + } + } + + *last_break = 0; // cut off the last string + + EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); + break; + } + } + } } \ No newline at end of file diff --git a/main/source/cl_dll/soundsystem.cpp b/main/source/cl_dll/soundsystem.cpp index f04fa695..6c2fd194 100644 --- a/main/source/cl_dll/soundsystem.cpp +++ b/main/source/cl_dll/soundsystem.cpp @@ -1,168 +1,168 @@ -//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ======== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: $ -// $Date: 2001/09/13 22:28:00 $ -// -//----------------------------------------------------------------------------- -// $Log: soundsystem.cpp,v $ -// Revision 1.2 2001/09/13 22:28:00 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.1.2.1 2001/09/13 14:42:29 Charlie -// - HL1108 -// -// -// $NoKeywords: $ -//============================================================================= -#include -#include -#include -#include "r_studioint.h" - -extern engine_studio_api_t IEngineStudio; - -#define RENDERTYPE_UNDEFINED 0 -#define RENDERTYPE_SOFTWARE 1 -#define RENDERTYPE_HARDWARE 2 - -#define ENGINE_LAUNCHER_API_VERSION 1 - -LPDIRECTSOUND lpDS = NULL; -LPDIRECTSOUNDBUFFER lpDSBuf = NULL; -LPHWAVEOUT lpHW = NULL; - -static HMODULE hEngine = 0; - -typedef struct engine_api_s -{ - int version; - int rendertype; - int size; - - // Functions - void ( *unused1 ) ( void ); - void ( *unused2 ) ( void ); - void ( *unused3 ) ( void ); - void ( *unused4 ) ( void ); - void ( *unused5 ) ( void ); - void ( *unused6 ) ( void ); - void ( *unused7 ) ( void ); - void ( *unused8 ) ( void ); - void ( *unused9 ) ( void ); - void ( *unused10 ) ( void ); - void ( *unused11 ) ( void ); - void ( *unused12 ) ( void ); - void ( *unused13 ) ( void ); - void ( *unused14 ) ( void ); - void ( *unused15 ) ( void ); - void ( *unused16 ) ( void ); - void ( *unused17 ) ( void ); - void ( *unused18 ) ( void ); - void ( *unused19 ) ( void ); - void ( *unused20 ) ( void ); - void ( *unused21 ) ( void ); - void ( *unused22 ) ( void ); - void ( *unused23 ) ( void ); - void ( *unused24 ) ( void ); - void ( *unused25 ) ( void ); - void ( *unused26 ) ( void ); - void ( *unused27 ) ( void ); - void ( *unused28 ) ( void ); - void ( *unused29 ) ( void ); - void ( *unused30 ) ( void ); - void ( *unused31 ) ( void ); - void ( *unused32 ) ( void ); - void ( *unused33 ) ( void ); - void ( *unused34 ) ( void ); - - void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); - void *( *S_GetWAVPointer ) ( void ); - - void ( *unused35 ) ( void ); - void ( *unused36 ) ( void ); - void ( *unused37 ) ( void ); - void ( *unused38 ) ( void ); - void ( *unused39 ) ( void ); - void ( *unused40 ) ( void ); - void ( *unused41 ) ( void ); - void ( *unused42 ) ( void ); - void ( *unused43 ) ( void ); - void ( *unused44 ) ( void ); - void ( *unused45 ) ( void ); - void ( *unused46 ) ( void ); - void ( *unused47 ) ( void ); - void ( *unused48 ) ( void ); - void ( *unused49 ) ( void ); - void ( *unused50 ) ( void ); - void ( *unused51 ) ( void ); - void ( *unused52 ) ( void ); - void ( *unused53 ) ( void ); - void ( *unused54 ) ( void ); - void ( *unused55 ) ( void ); -} engine_api_t; - -static engine_api_t engineapi; - -typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); - -//----------------------------------------------------------------------------- -// Purpose: Get launcher/engine interface from engine module -// Input : hMod - -// Output : int -//----------------------------------------------------------------------------- -int Eng_LoadFunctions( HMODULE hMod ) -{ - engine_api_func pfnEngineAPI; - - pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); - if ( !pfnEngineAPI ) - return 0; - - if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) - return 0; - - // All is okay - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: Load proper engine .dll and get pointer to either DSound and primary buffer or HWAVEOUT ( NT 4.0, e.g. ) -//----------------------------------------------------------------------------- -void LoadSoundAPIs( void ) -{ - hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); - if ( hEngine ) - { - if ( Eng_LoadFunctions( hEngine ) ) - { - if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) - { - engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); - lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Close engine library, release sound pointers -//----------------------------------------------------------------------------- -void ShutdownSoundAPIs( void ) -{ - if( hEngine ) - { - FreeLibrary( hEngine ); - hEngine = 0; - } - - lpDS = 0; - lpDSBuf = 0; - lpHW = 0; -} +//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ======== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: 2001/09/13 22:28:00 $ +// +//----------------------------------------------------------------------------- +// $Log: soundsystem.cpp,v $ +// Revision 1.2 2001/09/13 22:28:00 Charlie +// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode +// +// Revision 1.1.2.1 2001/09/13 14:42:29 Charlie +// - HL1108 +// +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include "r_studioint.h" + +extern engine_studio_api_t IEngineStudio; + +#define RENDERTYPE_UNDEFINED 0 +#define RENDERTYPE_SOFTWARE 1 +#define RENDERTYPE_HARDWARE 2 + +#define ENGINE_LAUNCHER_API_VERSION 1 + +LPDIRECTSOUND lpDS = NULL; +LPDIRECTSOUNDBUFFER lpDSBuf = NULL; +LPHWAVEOUT lpHW = NULL; + +static HMODULE hEngine = 0; + +typedef struct engine_api_s +{ + int version; + int rendertype; + int size; + + // Functions + void ( *unused1 ) ( void ); + void ( *unused2 ) ( void ); + void ( *unused3 ) ( void ); + void ( *unused4 ) ( void ); + void ( *unused5 ) ( void ); + void ( *unused6 ) ( void ); + void ( *unused7 ) ( void ); + void ( *unused8 ) ( void ); + void ( *unused9 ) ( void ); + void ( *unused10 ) ( void ); + void ( *unused11 ) ( void ); + void ( *unused12 ) ( void ); + void ( *unused13 ) ( void ); + void ( *unused14 ) ( void ); + void ( *unused15 ) ( void ); + void ( *unused16 ) ( void ); + void ( *unused17 ) ( void ); + void ( *unused18 ) ( void ); + void ( *unused19 ) ( void ); + void ( *unused20 ) ( void ); + void ( *unused21 ) ( void ); + void ( *unused22 ) ( void ); + void ( *unused23 ) ( void ); + void ( *unused24 ) ( void ); + void ( *unused25 ) ( void ); + void ( *unused26 ) ( void ); + void ( *unused27 ) ( void ); + void ( *unused28 ) ( void ); + void ( *unused29 ) ( void ); + void ( *unused30 ) ( void ); + void ( *unused31 ) ( void ); + void ( *unused32 ) ( void ); + void ( *unused33 ) ( void ); + void ( *unused34 ) ( void ); + + void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); + void *( *S_GetWAVPointer ) ( void ); + + void ( *unused35 ) ( void ); + void ( *unused36 ) ( void ); + void ( *unused37 ) ( void ); + void ( *unused38 ) ( void ); + void ( *unused39 ) ( void ); + void ( *unused40 ) ( void ); + void ( *unused41 ) ( void ); + void ( *unused42 ) ( void ); + void ( *unused43 ) ( void ); + void ( *unused44 ) ( void ); + void ( *unused45 ) ( void ); + void ( *unused46 ) ( void ); + void ( *unused47 ) ( void ); + void ( *unused48 ) ( void ); + void ( *unused49 ) ( void ); + void ( *unused50 ) ( void ); + void ( *unused51 ) ( void ); + void ( *unused52 ) ( void ); + void ( *unused53 ) ( void ); + void ( *unused54 ) ( void ); + void ( *unused55 ) ( void ); +} engine_api_t; + +static engine_api_t engineapi; + +typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); + +//----------------------------------------------------------------------------- +// Purpose: Get launcher/engine interface from engine module +// Input : hMod - +// Output : int +//----------------------------------------------------------------------------- +int Eng_LoadFunctions( HMODULE hMod ) +{ + engine_api_func pfnEngineAPI; + + pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); + if ( !pfnEngineAPI ) + return 0; + + if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) + return 0; + + // All is okay + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Load proper engine .dll and get pointer to either DSound and primary buffer or HWAVEOUT ( NT 4.0, e.g. ) +//----------------------------------------------------------------------------- +void LoadSoundAPIs( void ) +{ + hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); + if ( hEngine ) + { + if ( Eng_LoadFunctions( hEngine ) ) + { + if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) + { + engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); + lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Close engine library, release sound pointers +//----------------------------------------------------------------------------- +void ShutdownSoundAPIs( void ) +{ + if( hEngine ) + { + FreeLibrary( hEngine ); + hEngine = 0; + } + + lpDS = 0; + lpDSBuf = 0; + lpHW = 0; +} diff --git a/main/source/cl_dll/status_icons.cpp b/main/source/cl_dll/status_icons.cpp index 17a7eba0..423a3e3a 100644 --- a/main/source/cl_dll/status_icons.cpp +++ b/main/source/cl_dll/status_icons.cpp @@ -1,129 +1,129 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// status_icons.cpp -// -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include -#include -#include "common/event_api.h" - -int CHudStatusIcons::Init( void ) -{ - gHUD.AddHudElem( this ); - - Reset(); - - return 1; -} - -int CHudStatusIcons::VidInit( void ) -{ - - return 1; -} - -void CHudStatusIcons::Reset( void ) -{ - memset( m_IconList, 0, sizeof m_IconList ); - m_iFlags &= ~HUD_ACTIVE; -} - -// Draw status icons along the left-hand side of the screen -int CHudStatusIcons::Draw( float flTime ) -{ - if (gEngfuncs.IsSpectateOnly()) - return 1; - // find starting position to draw from, along right-hand side of screen - int x = 5; - int y = ScreenHeight() / 2; - - // loop through icon list, and draw any valid icons drawing up from the middle of screen - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( m_IconList[i].spr ) - { - y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5; - - SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b ); - SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); - } - } - - return 1; -} - -// add the icon to the icon list, and set it's drawing color -void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) -{ - // check to see if the sprite is in the current list - int i = 0; - for ( i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) - break; - } - - if ( i == MAX_ICONSPRITES ) - { - // icon not in list, so find an empty slot to add to - for ( i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( !m_IconList[i].spr ) - break; - } - } - - // if we've run out of space in the list, overwrite the first icon - if ( i == MAX_ICONSPRITES ) - { - i = 0; - } - - // Load the sprite and add it to the list - // the sprite must be listed in hud.txt - int spr_index = gHUD.GetSpriteIndex( pszIconName ); - m_IconList[i].spr = gHUD.GetSprite( spr_index ); - m_IconList[i].rc = gHUD.GetSpriteRect( spr_index ); - m_IconList[i].r = red; - m_IconList[i].g = green; - m_IconList[i].b = blue; - strcpy( m_IconList[i].szSpriteName, pszIconName ); - - // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) - if ( strstr(m_IconList[i].szSpriteName, "grenade") ) - { - cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); - gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - } -} - -void CHudStatusIcons::DisableIcon( char *pszIconName ) -{ - // find the sprite is in the current list - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) - { - // clear the item from the list - memset( &m_IconList[i], 0, sizeof(icon_sprite_t) ); - return; - } - } -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// status_icons.cpp +// +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include +#include +#include "common/event_api.h" + +int CHudStatusIcons::Init( void ) +{ + gHUD.AddHudElem( this ); + + Reset(); + + return 1; +} + +int CHudStatusIcons::VidInit( void ) +{ + + return 1; +} + +void CHudStatusIcons::Reset( void ) +{ + memset( m_IconList, 0, sizeof m_IconList ); + m_iFlags &= ~HUD_ACTIVE; +} + +// Draw status icons along the left-hand side of the screen +int CHudStatusIcons::Draw( float flTime ) +{ + if (gEngfuncs.IsSpectateOnly()) + return 1; + // find starting position to draw from, along right-hand side of screen + int x = 5; + int y = ScreenHeight() / 2; + + // loop through icon list, and draw any valid icons drawing up from the middle of screen + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( m_IconList[i].spr ) + { + y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5; + + SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b ); + SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); + } + } + + return 1; +} + +// add the icon to the icon list, and set it's drawing color +void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) +{ + // check to see if the sprite is in the current list + int i = 0; + for ( i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + break; + } + + if ( i == MAX_ICONSPRITES ) + { + // icon not in list, so find an empty slot to add to + for ( i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !m_IconList[i].spr ) + break; + } + } + + // if we've run out of space in the list, overwrite the first icon + if ( i == MAX_ICONSPRITES ) + { + i = 0; + } + + // Load the sprite and add it to the list + // the sprite must be listed in hud.txt + int spr_index = gHUD.GetSpriteIndex( pszIconName ); + m_IconList[i].spr = gHUD.GetSprite( spr_index ); + m_IconList[i].rc = gHUD.GetSpriteRect( spr_index ); + m_IconList[i].r = red; + m_IconList[i].g = green; + m_IconList[i].b = blue; + strcpy( m_IconList[i].szSpriteName, pszIconName ); + + // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) + if ( strstr(m_IconList[i].szSpriteName, "grenade") ) + { + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + } +} + +void CHudStatusIcons::DisableIcon( char *pszIconName ) +{ + // find the sprite is in the current list + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + { + // clear the item from the list + memset( &m_IconList[i], 0, sizeof(icon_sprite_t) ); + return; + } + } +} diff --git a/main/source/cl_dll/statusbar.cpp b/main/source/cl_dll/statusbar.cpp index 63cdff5a..03a2f6c5 100644 --- a/main/source/cl_dll/statusbar.cpp +++ b/main/source/cl_dll/statusbar.cpp @@ -1,300 +1,300 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// statusbar.cpp -// -// generic text status bar, set by game dll -// runs across bottom of screen -// - -#include "hud.h" -#include "cl_util.h" -#include "mod/AvHNetworkMessages.h" - -#include -#include - -DECLARE_MESSAGE( m_StatusBar, StatusText ); -DECLARE_MESSAGE( m_StatusBar, StatusValue ); - -#define STATUSBAR_ID_LINE 1 - -float *GetClientColor( int clientIndex ); -extern float g_ColorYellow[3]; - -int CHudStatusBar :: Init( void ) -{ - //gHUD.AddHudElem( this ); - - HOOK_MESSAGE( StatusText ); - HOOK_MESSAGE( StatusValue ); - - Reset(); - - CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE ); - - return 1; -} - -int CHudStatusBar :: VidInit( void ) -{ - // Load sprites here - - return 1; -} - -void CHudStatusBar :: Reset( void ) -{ - int i = 0; - - m_iFlags &= ~HUD_ACTIVE; // start out inactive - for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) - { - m_szStatusText[i][0] = 0; - m_iStatusValues[i] = -1; - } - - //memset( m_iStatusValues, 0, sizeof m_iStatusValues ); - - m_iStatusValues[0] = 1; // 0 is the special index, which always returns true - - // reset our colors for the status bar lines (yellow is default) - for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) - m_pflNameColors[i] = g_ColorYellow; -} - -const char* CHudStatusBar::GetStatusString() const -{ - static char kStatusString[1024]; - - memset(kStatusString, 0, 1024); - - for(int i = 0; i < MAX_STATUSBAR_LINES; i++) - { - const char* theCurrentString = m_szStatusBar[i]; - if(strlen(theCurrentString) > 0) - { - strcat(kStatusString, theCurrentString); - } - } - - return kStatusString; -} - -void CHudStatusBar :: ParseStatusString( int line_num ) -{ - // localise string first - char szBuffer[MAX_STATUSTEXT_LENGTH]; - memset( szBuffer, 0, sizeof szBuffer ); - gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH ); - - // parse m_szStatusText & m_iStatusValues into m_szStatusBar - memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH ); - char *src = szBuffer; - char *dst = m_szStatusBar[line_num]; - - char *src_start = src, *dst_start = dst; - - while ( *src != 0 ) - { - while ( *src == '\n' ) - src++; // skip over any newlines - - if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) ) - break; - - int index = atoi( src ); - // should we draw this line? - if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != -1)) - { // parse this line and append result to the status bar - while ( *src >= '0' && *src <= '9' ) - src++; - - if ( *src == '\n' || *src == 0 ) - continue; // no more left in this text line - - // copy the text, char by char, until we hit a % or a \n - while ( *src != '\n' && *src != 0 ) - { - if ( *src != '%' ) - { // just copy the character - *dst = *src; - dst++, src++; - } - else - { - // get the descriptor - char valtype = *(++src); // move over % - - // if it's a %, draw a % sign - if ( valtype == '%' ) - { - *dst = valtype; - dst++, src++; - continue; - } - - // move over descriptor, then get and move over the index - index = atoi( ++src ); - while ( *src >= '0' && *src <= '9' ) - src++; - - if ( index >= 0 && index < MAX_STATUSBAR_VALUES ) - { - int indexval = m_iStatusValues[index]; - - // get the string to substitute in place of the %XX - char szRepString[MAX_PLAYER_NAME_LENGTH]; - switch ( valtype ) - { - case 'p': // player name - GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); - if ( g_PlayerInfoList[indexval].name != NULL ) - { - strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); - m_pflNameColors[line_num] = GetClientColor( indexval ); - } - else - { - strcpy( szRepString, "******" ); - } - - break; - case 'i': // number - sprintf( szRepString, "%d", indexval ); - break; - default: - szRepString[0] = 0; - } - - for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ ) - *dst = *cp; - } - } - } - } - else - { - // skip to next line of text - while ( *src != 0 && *src != '\n' ) - src++; - } - } -} - -void CHudStatusBar::ReparseStringIfNeeded() -{ - if ( m_bReparseString ) - { - for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) - { - m_pflNameColors[i] = g_ColorYellow; - ParseStatusString( i ); - } - m_bReparseString = FALSE; - } - -} - -int CHudStatusBar :: Draw( float fTime ) -{ - - this->ReparseStringIfNeeded(); - - // Draw the status bar lines - for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) - { - int TextHeight, TextWidth; - GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); - - int Y_START; - if ( ScreenHeight() >= 480 ) - Y_START = ScreenHeight() - 55; - else - Y_START = ScreenHeight() - 45; - - int x = 5; - int y = Y_START - ( TextHeight * i ); // draw along bottom of screen - - // let user set status ID bar centering - if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) - { - x = max( 0, max(2, (ScreenWidth() - TextWidth)) / 2 ); - y = (ScreenHeight() / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); - } - - if ( m_pflNameColors[i] ) - DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); - - DrawConsoleString( x, y, m_szStatusBar[i] ); - } - - return 1; -} - -// Message handler for StatusText message -// accepts two values: -// byte: line number of status bar text -// string: status bar text -// this string describes how the status bar should be drawn -// a semi-regular expression: -// ( slotnum ([a..z] [%pX] [%iX])*)* -// where slotnum is an index into the Value table (see below) -// if slotnum is 0, the string is always drawn -// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline -// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] -// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] -int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) -{ - int location; - string content; - NetMsg_StatusText( pbuf, iSize, location, content ); - - if ( location < 0 || location >= MAX_STATUSBAR_LINES ) - return 1; - - strncpy( m_szStatusText[location], content.c_str(), MAX_STATUSTEXT_LENGTH ); - m_szStatusText[location][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) - - if ( m_szStatusText[0] == 0 ) - m_iFlags &= ~HUD_ACTIVE; - else - m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar - - m_bReparseString = TRUE; - this->ReparseStringIfNeeded(); - - return 1; -} - -// Message handler for StatusText message -// accepts two values: -// byte: index into the status value array -// short: value to store -int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) -{ - int location, state; - NetMsg_StatusValue( pbuf, iSize, location, state ); - - if ( location < 1 || location >= MAX_STATUSBAR_VALUES ) - return 1; // index out of range - - m_iStatusValues[location] = state; - - m_bReparseString = TRUE; - this->ReparseStringIfNeeded(); - - return 1; +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// statusbar.cpp +// +// generic text status bar, set by game dll +// runs across bottom of screen +// + +#include "hud.h" +#include "cl_util.h" +#include "mod/AvHNetworkMessages.h" + +#include +#include + +DECLARE_MESSAGE( m_StatusBar, StatusText ); +DECLARE_MESSAGE( m_StatusBar, StatusValue ); + +#define STATUSBAR_ID_LINE 1 + +float *GetClientColor( int clientIndex ); +extern float g_ColorYellow[3]; + +int CHudStatusBar :: Init( void ) +{ + //gHUD.AddHudElem( this ); + + HOOK_MESSAGE( StatusText ); + HOOK_MESSAGE( StatusValue ); + + Reset(); + + CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE ); + + return 1; +} + +int CHudStatusBar :: VidInit( void ) +{ + // Load sprites here + + return 1; +} + +void CHudStatusBar :: Reset( void ) +{ + int i = 0; + + m_iFlags &= ~HUD_ACTIVE; // start out inactive + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + m_szStatusText[i][0] = 0; + m_iStatusValues[i] = -1; + } + + //memset( m_iStatusValues, 0, sizeof m_iStatusValues ); + + m_iStatusValues[0] = 1; // 0 is the special index, which always returns true + + // reset our colors for the status bar lines (yellow is default) + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + m_pflNameColors[i] = g_ColorYellow; +} + +const char* CHudStatusBar::GetStatusString() const +{ + static char kStatusString[1024]; + + memset(kStatusString, 0, 1024); + + for(int i = 0; i < MAX_STATUSBAR_LINES; i++) + { + const char* theCurrentString = m_szStatusBar[i]; + if(strlen(theCurrentString) > 0) + { + strcat(kStatusString, theCurrentString); + } + } + + return kStatusString; +} + +void CHudStatusBar :: ParseStatusString( int line_num ) +{ + // localise string first + char szBuffer[MAX_STATUSTEXT_LENGTH]; + memset( szBuffer, 0, sizeof szBuffer ); + gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH ); + + // parse m_szStatusText & m_iStatusValues into m_szStatusBar + memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH ); + char *src = szBuffer; + char *dst = m_szStatusBar[line_num]; + + char *src_start = src, *dst_start = dst; + + while ( *src != 0 ) + { + while ( *src == '\n' ) + src++; // skip over any newlines + + if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) ) + break; + + int index = atoi( src ); + // should we draw this line? + if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != -1)) + { // parse this line and append result to the status bar + while ( *src >= '0' && *src <= '9' ) + src++; + + if ( *src == '\n' || *src == 0 ) + continue; // no more left in this text line + + // copy the text, char by char, until we hit a % or a \n + while ( *src != '\n' && *src != 0 ) + { + if ( *src != '%' ) + { // just copy the character + *dst = *src; + dst++, src++; + } + else + { + // get the descriptor + char valtype = *(++src); // move over % + + // if it's a %, draw a % sign + if ( valtype == '%' ) + { + *dst = valtype; + dst++, src++; + continue; + } + + // move over descriptor, then get and move over the index + index = atoi( ++src ); + while ( *src >= '0' && *src <= '9' ) + src++; + + if ( index >= 0 && index < MAX_STATUSBAR_VALUES ) + { + int indexval = m_iStatusValues[index]; + + // get the string to substitute in place of the %XX + char szRepString[MAX_PLAYER_NAME_LENGTH]; + switch ( valtype ) + { + case 'p': // player name + GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); + if ( g_PlayerInfoList[indexval].name != NULL ) + { + strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); + m_pflNameColors[line_num] = GetClientColor( indexval ); + } + else + { + strcpy( szRepString, "******" ); + } + + break; + case 'i': // number + sprintf( szRepString, "%d", indexval ); + break; + default: + szRepString[0] = 0; + } + + for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ ) + *dst = *cp; + } + } + } + } + else + { + // skip to next line of text + while ( *src != 0 && *src != '\n' ) + src++; + } + } +} + +void CHudStatusBar::ReparseStringIfNeeded() +{ + if ( m_bReparseString ) + { + for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + m_pflNameColors[i] = g_ColorYellow; + ParseStatusString( i ); + } + m_bReparseString = FALSE; + } + +} + +int CHudStatusBar :: Draw( float fTime ) +{ + + this->ReparseStringIfNeeded(); + + // Draw the status bar lines + for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + int TextHeight, TextWidth; + GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); + + int Y_START; + if ( ScreenHeight() >= 480 ) + Y_START = ScreenHeight() - 55; + else + Y_START = ScreenHeight() - 45; + + int x = 5; + int y = Y_START - ( TextHeight * i ); // draw along bottom of screen + + // let user set status ID bar centering + if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) + { + x = max( 0, max(2, (ScreenWidth() - TextWidth)) / 2 ); + y = (ScreenHeight() / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); + } + + if ( m_pflNameColors[i] ) + DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + + DrawConsoleString( x, y, m_szStatusBar[i] ); + } + + return 1; +} + +// Message handler for StatusText message +// accepts two values: +// byte: line number of status bar text +// string: status bar text +// this string describes how the status bar should be drawn +// a semi-regular expression: +// ( slotnum ([a..z] [%pX] [%iX])*)* +// where slotnum is an index into the Value table (see below) +// if slotnum is 0, the string is always drawn +// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline +// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] +// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] +int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) +{ + int location; + string content; + NetMsg_StatusText( pbuf, iSize, location, content ); + + if ( location < 0 || location >= MAX_STATUSBAR_LINES ) + return 1; + + strncpy( m_szStatusText[location], content.c_str(), MAX_STATUSTEXT_LENGTH ); + m_szStatusText[location][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) + + if ( m_szStatusText[0] == 0 ) + m_iFlags &= ~HUD_ACTIVE; + else + m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar + + m_bReparseString = TRUE; + this->ReparseStringIfNeeded(); + + return 1; +} + +// Message handler for StatusText message +// accepts two values: +// byte: index into the status value array +// short: value to store +int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) +{ + int location, state; + NetMsg_StatusValue( pbuf, iSize, location, state ); + + if ( location < 1 || location >= MAX_STATUSBAR_VALUES ) + return 1; // index out of range + + m_iStatusValues[location] = state; + + m_bReparseString = TRUE; + this->ReparseStringIfNeeded(); + + return 1; } \ No newline at end of file diff --git a/main/source/cl_dll/steam_appid.txt b/main/source/cl_dll/steam_appid.txt index 356ea80c..2bbd69c2 100644 --- a/main/source/cl_dll/steam_appid.txt +++ b/main/source/cl_dll/steam_appid.txt @@ -1 +1 @@ -70 +70 diff --git a/main/source/cl_dll/studio_util.cpp b/main/source/cl_dll/studio_util.cpp index 64d6cd27..5235b324 100644 --- a/main/source/cl_dll/studio_util.cpp +++ b/main/source/cl_dll/studio_util.cpp @@ -1,245 +1,245 @@ -#include -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/com_model.h" -#include "studio_util.h" - -/* -==================== -AngleMatrix - -==================== -*/ - -void AngleMatrix (const float *angles, float (*matrix)[4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[1][0] = cp*sy; - matrix[2][0] = -sp; - matrix[0][1] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[2][1] = sr*cp; - matrix[0][2] = (cr*sp*cy+-sr*-sy); - matrix[1][2] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} - -/* -==================== -VectorCompare - -==================== -*/ -int VectorCompare (const float *v1, const float *v2) -{ - int i; - - for (i=0 ; i<3 ; i++) - if (v1[i] != v2[i]) - return 0; - - return 1; -} - -/* -==================== -CrossProduct - -==================== -*/ -void CrossProduct (const float *v1, const float *v2, float *cross) -{ - cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; - cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; - cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} - -/* -==================== -VectorTransform - -==================== -*/ -void VectorTransform (const float *in1, float in2[3][4], float *out) -{ - out[0] = DotProduct(in1, in2[0]) + in2[0][3]; - out[1] = DotProduct(in1, in2[1]) + in2[1][3]; - out[2] = DotProduct(in1, in2[2]) + in2[2][3]; -} - -/* -================ -ConcatTransforms - -================ -*/ -void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) -{ - out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + - in1[0][2] * in2[2][0]; - out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + - in1[0][2] * in2[2][1]; - out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + - in1[0][2] * in2[2][2]; - out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + - in1[0][2] * in2[2][3] + in1[0][3]; - out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + - in1[1][2] * in2[2][0]; - out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + - in1[1][2] * in2[2][1]; - out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + - in1[1][2] * in2[2][2]; - out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + - in1[1][2] * in2[2][3] + in1[1][3]; - out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + - in1[2][2] * in2[2][0]; - out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + - in1[2][2] * in2[2][1]; - out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + - in1[2][2] * in2[2][2]; - out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + - in1[2][2] * in2[2][3] + in1[2][3]; -} - -// angles index are not the same as ROLL, PITCH, YAW - -/* -==================== -AngleQuaternion - -==================== -*/ -void AngleQuaternion( float *angles, vec4_t quaternion ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - // FIXME: rescale the inputs to 1/2 angle - angle = angles[2] * 0.5; - sy = sin(angle); - cy = cos(angle); - angle = angles[1] * 0.5; - sp = sin(angle); - cp = cos(angle); - angle = angles[0] * 0.5; - sr = sin(angle); - cr = cos(angle); - - quaternion[0] = sr*cp*cy-cr*sp*sy; // X - quaternion[1] = cr*sp*cy+sr*cp*sy; // Y - quaternion[2] = cr*cp*sy-sr*sp*cy; // Z - quaternion[3] = cr*cp*cy+sr*sp*sy; // W -} - -/* -==================== -QuaternionSlerp - -==================== -*/ -void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) -{ - int i; - float omega, cosom, sinom, sclp, sclq; - - // decide if one of the quaternions is backwards - float a = 0; - float b = 0; - - for (i = 0; i < 4; i++) - { - a += (p[i]-q[i])*(p[i]-q[i]); - b += (p[i]+q[i])*(p[i]+q[i]); - } - if (a > b) - { - for (i = 0; i < 4; i++) - { - q[i] = -q[i]; - } - } - - cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; - - if ((1.0 + cosom) > 0.000001) - { - if ((1.0 - cosom) > 0.000001) - { - omega = acos( cosom ); - sinom = sin( omega ); - sclp = sin( (1.0 - t)*omega) / sinom; - sclq = sin( t*omega ) / sinom; - } - else - { - sclp = 1.0 - t; - sclq = t; - } - for (i = 0; i < 4; i++) { - qt[i] = sclp * p[i] + sclq * q[i]; - } - } - else - { - qt[0] = -q[1]; - qt[1] = q[0]; - qt[2] = -q[3]; - qt[3] = q[2]; - sclp = sin( (1.0 - t) * (0.5 * M_PI)); - sclq = sin( t * (0.5 * M_PI)); - for (i = 0; i < 3; i++) - { - qt[i] = sclp * p[i] + sclq * qt[i]; - } - } -} - -/* -==================== -QuaternionMatrix - -==================== -*/ -void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ) -{ - matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; - matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; - matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; - - matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; - matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; - matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; - - matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; - matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; - matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; -} - -/* -==================== -MatrixCopy - -==================== -*/ -void MatrixCopy( float in[3][4], float out[3][4] ) -{ - memcpy( out, in, sizeof( float ) * 3 * 4 ); -} +#include +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/com_model.h" +#include "studio_util.h" + +/* +==================== +AngleMatrix + +==================== +*/ #ifdef WIN32 + +void AngleMatrix (const float *angles, float (*matrix)[4] ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + // matrix = (YAW * PITCH) * ROLL + matrix[0][0] = cp*cy; + matrix[1][0] = cp*sy; + matrix[2][0] = -sp; + matrix[0][1] = sr*sp*cy+cr*-sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[2][1] = sr*cp; + matrix[0][2] = (cr*sp*cy+-sr*-sy); + matrix[1][2] = (cr*sp*sy+-sr*cy); + matrix[2][2] = cr*cp; + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; +} +#endif +/* +==================== +VectorCompare + +==================== +*/ #ifdef WIN32 +int VectorCompare (const float *v1, const float *v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} +#endif +/* +==================== +CrossProduct + +==================== +*/ #ifdef WIN32 +void CrossProduct (const float *v1, const float *v2, float *cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} +#endif +/* +==================== +VectorTransform + +==================== +*/ +void VectorTransform (const float *in1, float in2[3][4], float *out) +{ + out[0] = DotProduct(in1, in2[0]) + in2[0][3]; + out[1] = DotProduct(in1, in2[1]) + in2[1][3]; + out[2] = DotProduct(in1, in2[2]) + in2[2][3]; +} + +/* +================ +ConcatTransforms + +================ +*/ +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + +// angles index are not the same as ROLL, PITCH, YAW + +/* +==================== +AngleQuaternion + +==================== +*/ +void AngleQuaternion( float *angles, vec4_t quaternion ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + // FIXME: rescale the inputs to 1/2 angle + angle = angles[2] * 0.5; + sy = sin(angle); + cy = cos(angle); + angle = angles[1] * 0.5; + sp = sin(angle); + cp = cos(angle); + angle = angles[0] * 0.5; + sr = sin(angle); + cr = cos(angle); + + quaternion[0] = sr*cp*cy-cr*sp*sy; // X + quaternion[1] = cr*sp*cy+sr*cp*sy; // Y + quaternion[2] = cr*cp*sy-sr*sp*cy; // Z + quaternion[3] = cr*cp*cy+sr*sp*sy; // W +} + +/* +==================== +QuaternionSlerp + +==================== +*/ +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) +{ + int i; + float omega, cosom, sinom, sclp, sclq; + + // decide if one of the quaternions is backwards + float a = 0; + float b = 0; + + for (i = 0; i < 4; i++) + { + a += (p[i]-q[i])*(p[i]-q[i]); + b += (p[i]+q[i])*(p[i]+q[i]); + } + if (a > b) + { + for (i = 0; i < 4; i++) + { + q[i] = -q[i]; + } + } + + cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + + if ((1.0 + cosom) > 0.000001) + { + if ((1.0 - cosom) > 0.000001) + { + omega = acos( cosom ); + sinom = sin( omega ); + sclp = sin( (1.0 - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else + { + sclp = 1.0 - t; + sclq = t; + } + for (i = 0; i < 4; i++) { + qt[i] = sclp * p[i] + sclq * q[i]; + } + } + else + { + qt[0] = -q[1]; + qt[1] = q[0]; + qt[2] = -q[3]; + qt[3] = q[2]; + sclp = sin( (1.0 - t) * (0.5 * M_PI)); + sclq = sin( t * (0.5 * M_PI)); + for (i = 0; i < 3; i++) + { + qt[i] = sclp * p[i] + sclq * qt[i]; + } + } +} + +/* +==================== +QuaternionMatrix + +==================== +*/ +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ) +{ + matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; + matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; + matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; + + matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; + matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; + matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; + + matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; + matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; + matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; +} + +/* +==================== +MatrixCopy + +==================== +*/ +void MatrixCopy( float in[3][4], float out[3][4] ) +{ + memcpy( out, in, sizeof( float ) * 3 * 4 ); +} diff --git a/main/source/cl_dll/studio_util.h b/main/source/cl_dll/studio_util.h index 7e303d5e..53f611fc 100644 --- a/main/source/cl_dll/studio_util.h +++ b/main/source/cl_dll/studio_util.h @@ -1,32 +1,32 @@ -#if !defined( STUDIO_UTIL_H ) -#define STUDIO_UTIL_H -#if defined( WIN32 ) -#pragma once -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -#ifndef PITCH -// MOVEMENT INFO -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 -#endif - -#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) -void AngleMatrix (const float *angles, float (*matrix)[4] ); -int VectorCompare (const float *v1, const float *v2); -void CrossProduct (const float *v1, const float *v2, float *cross); -void VectorTransform (const float *in1, float in2[3][4], float *out); -void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); -void MatrixCopy( float in[3][4], float out[3][4] ); -void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); -void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); -void AngleQuaternion( float *angles, vec4_t quaternion ); - -#endif // STUDIO_UTIL_H +#if !defined( STUDIO_UTIL_H ) +#define STUDIO_UTIL_H +#if defined( WIN32 ) +#pragma once +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#ifndef PITCH +// MOVEMENT INFO +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 +#endif + +#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) +void AngleMatrix (const float *angles, float (*matrix)[4] ); +int VectorCompare (const float *v1, const float *v2); +void CrossProduct (const float *v1, const float *v2, float *cross); +void VectorTransform (const float *in1, float in2[3][4], float *out); +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void MatrixCopy( float in[3][4], float out[3][4] ); +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); +void AngleQuaternion( float *angles, vec4_t quaternion ); + +#endif // STUDIO_UTIL_H diff --git a/main/source/cl_dll/text_message.cpp b/main/source/cl_dll/text_message.cpp index 5502b0a6..704f40bb 100644 --- a/main/source/cl_dll/text_message.cpp +++ b/main/source/cl_dll/text_message.cpp @@ -1,215 +1,215 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// text_message.cpp -// -// implementation of CHudTextMessage class -// -// this class routes messages through titles.txt for localisation -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "mod/AvHNetworkMessages.h" - -#include "vgui_TeamFortressViewport.h" - -DECLARE_MESSAGE( m_TextMessage, TextMsg ); - -int CHudTextMessage::Init(void) -{ - HOOK_MESSAGE( TextMsg ); - - gHUD.AddHudElem( this ); - - Reset(); - - return 1; -}; - -// Searches through the string for any msg names (indicated by a '#') -// any found are looked up in titles.txt and the new message substituted -// the new value is pushed into dst_buffer -char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) -{ - char *dst = dst_buffer; - for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) - { - if ( *src == '#' ) - { - // cut msg name out of string - static char word_buf[255]; - char *wdst = word_buf, *word_start = src; - for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) - { - *wdst = *src; - } - *wdst = 0; - - // lookup msg name in titles.txt - client_textmessage_t *clmsg = TextMessageGet( word_buf ); - if ( !clmsg || !(clmsg->pMessage) ) - { - src = word_start; - *dst = *src; - dst++, src++; - continue; - } - - // copy string into message over the msg name - for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) - { - *dst = *wsrc; - } - *dst = 0; - } - else - { - *dst = *src; - dst++, src++; - *dst = 0; - } - } - - dst_buffer[buffer_size-1] = 0; // ensure null termination - return dst_buffer; -} - -// As above, but with a local static buffer -char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) -{ - static char dst_buffer[1024]; - LocaliseTextString( msg, dst_buffer, 1024 ); - return dst_buffer; -} - -// Simplified version of LocaliseTextString; assumes string is only one word -char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) -{ - if ( !msg ) - return ""; - - // '#' character indicates this is a reference to a string in titles.txt, and not the string itself - if ( msg[0] == '#' ) - { - // this is a message name, so look up the real message - client_textmessage_t *clmsg = TextMessageGet( msg+1 ); - - if ( !clmsg || !(clmsg->pMessage) ) - return (char*)msg; // lookup failed, so return the original string - - if ( msg_dest ) - { - // check to see if titles.txt info overrides msg destination - // if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination - if ( clmsg->effect < 0 ) // - *msg_dest = -clmsg->effect; - } - - return (char*)clmsg->pMessage; - } - else - { // nothing special about this message, so just return the same string - return (char*)msg; - } -} - -void StripEndNewlineFromString( char *str ) -{ - int s = (int)strlen( str ) - 1; - if ( str[s] == '\n' || str[s] == '\r' ) - str[s] = 0; -} - -// converts all '\r' characters to '\n', so that the engine can deal with the properly -// returns a pointer to str -char* ConvertCRtoNL( char *str ) -{ - for ( char *ch = str; *ch != 0; ch++ ) - if ( *ch == '\r' ) - *ch = '\n'; - return str; -} - -// Message handler for text messages -// displays a string, looking them up from the titles.txt file, which can be localised -// parameters: -// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) -// string: message -// optional parameters: -// string: message parameter 1 -// string: message parameter 2 -// string: message parameter 3 -// string: message parameter 4 -// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt -// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') -int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ) -{ - int destination; - StringList message; - NetMsg_TextMsg( pbuf, iSize, destination, message ); - - if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) - return 1; - - while( message.size() < 5 ) - { message.push_back( string("") ); } - char psz[1024]; - - char* origin = psz; - if( destination == HUD_PRINTNOTIFY ) - { - psz[0] = 1; - origin = psz + 1; - } - - // Ensure that message[0] does not contain exessive %'s, max 4x%s, all other %'s removed. - size_t lastpos = 0; size_t pos; int count = 0; - while(true) - { - pos = message[0].find("%", lastpos); - - if (pos == string::npos) - break; - - if ((message[0].substr(pos + 1, 1) == "s") && (count < 4)) - count++; - else - message[0].replace(pos, 1, " "); - - lastpos = pos + 1; - } - - sprintf( origin, message[0].c_str(), message[1].c_str(), message[2].c_str(), message[3].c_str(), message[4].c_str() ); - ConvertCRtoNL(psz); - - switch ( destination ) - { - case HUD_PRINTNOTIFY: - case HUD_PRINTCONSOLE: - ConsolePrint(psz); - break; - case HUD_PRINTCENTER: - CenterPrint(psz); - break; - case HUD_PRINTTALK: - gHUD.m_SayText.SayTextPrint(psz, 1024); - break; - } - - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// text_message.cpp +// +// implementation of CHudTextMessage class +// +// this class routes messages through titles.txt for localisation +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "mod/AvHNetworkMessages.h" + +#include "vgui_TeamFortressViewport.h" + +DECLARE_MESSAGE( m_TextMessage, TextMsg ); + +int CHudTextMessage::Init(void) +{ + HOOK_MESSAGE( TextMsg ); + + gHUD.AddHudElem( this ); + + Reset(); + + return 1; +}; + +// Searches through the string for any msg names (indicated by a '#') +// any found are looked up in titles.txt and the new message substituted +// the new value is pushed into dst_buffer +char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) +{ + char *dst = dst_buffer; + for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) + { + if ( *src == '#' ) + { + // cut msg name out of string + static char word_buf[255]; + char *wdst = word_buf, *word_start = src; + for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) + { + *wdst = *src; + } + *wdst = 0; + + // lookup msg name in titles.txt + client_textmessage_t *clmsg = TextMessageGet( word_buf ); + if ( !clmsg || !(clmsg->pMessage) ) + { + src = word_start; + *dst = *src; + dst++, src++; + continue; + } + + // copy string into message over the msg name + for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) + { + *dst = *wsrc; + } + *dst = 0; + } + else + { + *dst = *src; + dst++, src++; + *dst = 0; + } + } + + dst_buffer[buffer_size-1] = 0; // ensure null termination + return dst_buffer; +} + +// As above, but with a local static buffer +char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) +{ + static char dst_buffer[1024]; + LocaliseTextString( msg, dst_buffer, 1024 ); + return dst_buffer; +} + +// Simplified version of LocaliseTextString; assumes string is only one word +char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) +{ + if ( !msg ) + return ""; + + // '#' character indicates this is a reference to a string in titles.txt, and not the string itself + if ( msg[0] == '#' ) + { + // this is a message name, so look up the real message + client_textmessage_t *clmsg = TextMessageGet( msg+1 ); + + if ( !clmsg || !(clmsg->pMessage) ) + return (char*)msg; // lookup failed, so return the original string + + if ( msg_dest ) + { + // check to see if titles.txt info overrides msg destination + // if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination + if ( clmsg->effect < 0 ) // + *msg_dest = -clmsg->effect; + } + + return (char*)clmsg->pMessage; + } + else + { // nothing special about this message, so just return the same string + return (char*)msg; + } +} + +void StripEndNewlineFromString( char *str ) +{ + int s = (int)strlen( str ) - 1; + if ( str[s] == '\n' || str[s] == '\r' ) + str[s] = 0; +} + +// converts all '\r' characters to '\n', so that the engine can deal with the properly +// returns a pointer to str +char* ConvertCRtoNL( char *str ) +{ + for ( char *ch = str; *ch != 0; ch++ ) + if ( *ch == '\r' ) + *ch = '\n'; + return str; +} + +// Message handler for text messages +// displays a string, looking them up from the titles.txt file, which can be localised +// parameters: +// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) +// string: message +// optional parameters: +// string: message parameter 1 +// string: message parameter 2 +// string: message parameter 3 +// string: message parameter 4 +// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt +// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') +int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ) +{ + int destination; + StringList message; + NetMsg_TextMsg( pbuf, iSize, destination, message ); + + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + return 1; + + while( message.size() < 5 ) + { message.push_back( string("") ); } + char psz[1024]; + + char* origin = psz; + if( destination == HUD_PRINTNOTIFY ) + { + psz[0] = 1; + origin = psz + 1; + } + + // Ensure that message[0] does not contain exessive %'s, max 4x%s, all other %'s removed. + size_t lastpos = 0; size_t pos; int count = 0; + while(true) + { + pos = message[0].find("%", lastpos); + + if (pos == string::npos) + break; + + if ((message[0].substr(pos + 1, 1) == "s") && (count < 4)) + count++; + else + message[0].replace(pos, 1, " "); + + lastpos = pos + 1; + } + + sprintf( origin, message[0].c_str(), message[1].c_str(), message[2].c_str(), message[3].c_str(), message[4].c_str() ); + ConvertCRtoNL(psz); + + switch ( destination ) + { + case HUD_PRINTNOTIFY: + case HUD_PRINTCONSOLE: + ConsolePrint(psz); + break; + case HUD_PRINTCENTER: + CenterPrint(psz); + break; + case HUD_PRINTTALK: + gHUD.m_SayText.SayTextPrint(psz, 1024); + break; + } + + return 1; +} diff --git a/main/source/cl_dll/tf_defs.h b/main/source/cl_dll/tf_defs.h index 2e0ead56..c3a0c154 100644 --- a/main/source/cl_dll/tf_defs.h +++ b/main/source/cl_dll/tf_defs.h @@ -1,1387 +1,1387 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -****/ - -#ifndef __TF_DEFS_H -#define __TF_DEFS_H - -//=========================================================================== -// OLD OPTIONS.QC -//=========================================================================== -#define DEFAULT_AUTOZOOM FALSE -#define WEINER_SNIPER // autoaiming for sniper rifle -#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. - -//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server -#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active -#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active - -//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time -//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server -#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into -#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) -#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies - -#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. - // 60 is a mild setting, and won't make too much difference - // increasing it _decreases_ the amount of help the losing team gets - // Minimum setting is 1, which would really help the losing team - -#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to - // appear whenever a player connects -#define NEVER_TEAMFRAGS FALSE // teamfrags options always off -#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on -#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast -#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds - -#define MAPBRIEFING_MAXTEXTLENGTH 512 -#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed - -// Debug Options -//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res - // mode and/or piping the output from the server to a file. -#ifdef MAP_DEBUG - #define MDEBUG(x) x -#else - #define MDEBUG(x) -#endif -//#define VERBOSE // Verbose Debugging on/off - -//=========================================================================== -// OLD QUAKE Defs -//=========================================================================== -// items -#define IT_AXE 4096 -#define IT_SHOTGUN 1 -#define IT_SUPER_SHOTGUN 2 -#define IT_NAILGUN 4 -#define IT_SUPER_NAILGUN 8 -#define IT_GRENADE_LAUNCHER 16 -#define IT_ROCKET_LAUNCHER 32 -#define IT_LIGHTNING 64 -#define IT_EXTRA_WEAPON 128 - -#define IT_SHELLS 256 -#define IT_NAILS 512 -#define IT_ROCKETS 1024 -#define IT_CELLS 2048 - -#define IT_ARMOR1 8192 -#define IT_ARMOR2 16384 -#define IT_ARMOR3 32768 -#define IT_SUPERHEALTH 65536 - -#define IT_KEY1 131072 -#define IT_KEY2 262144 - -#define IT_INVISIBILITY 524288 -#define IT_INVULNERABILITY 1048576 -#define IT_SUIT 2097152 -#define IT_QUAD 4194304 -#define IT_HOOK 8388608 - -#define IT_KEY3 16777216 // Stomp invisibility -#define IT_KEY4 33554432 // Stomp invulnerability - -//=========================================================================== -// TEAMFORTRESS Defs -//=========================================================================== -// TeamFortress State Flags -#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade -#define TFSTATE_RELOADING 2 // Whether the player is reloading -#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE -#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn -#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon -#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) -#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) -#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) -#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) -#define TFSTATE_BURNING 512 // Is on fire -#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade -#define TFSTATE_AIMING 2048 // is using the laser sight -#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming -#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire -#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating -#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised -#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack -#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health - -// Defines used by TF_T_Damage (see combat.qc) -#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target -#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) -#define TF_TD_NOTSELF 4 // Doesn't damage self - -#define TF_TD_OTHER 0 // Ignore armorclass -#define TF_TD_SHOT 1 // Bullet damage -#define TF_TD_NAIL 2 // Nail damage -#define TF_TD_EXPLOSION 4 // Explosion damage -#define TF_TD_ELECTRICITY 8 // Electric damage -#define TF_TD_FIRE 16 // Fire damage -#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc - -/*==================================================*/ -/* Toggleable Game Settings */ -/*==================================================*/ -#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn -#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn -#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn - -#define TEAMPLAY_NORMAL 1 -#define TEAMPLAY_HALFDIRECT 2 -#define TEAMPLAY_NODIRECT 4 -#define TEAMPLAY_HALFEXPLOSIVE 8 -#define TEAMPLAY_NOEXPLOSIVE 16 -#define TEAMPLAY_LESSPLAYERSHELP 32 -#define TEAMPLAY_LESSSCOREHELP 64 -#define TEAMPLAY_HALFDIRECTARMOR 128 -#define TEAMPLAY_NODIRECTARMOR 256 -#define TEAMPLAY_HALFEXPARMOR 512 -#define TEAMPLAY_NOEXPARMOR 1024 -#define TEAMPLAY_HALFDIRMIRROR 2048 -#define TEAMPLAY_FULLDIRMIRROR 4096 -#define TEAMPLAY_HALFEXPMIRROR 8192 -#define TEAMPLAY_FULLEXPMIRROR 16384 - -#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) -// FortressMap stuff -#define TEAM1_CIVILIANS 1 -#define TEAM2_CIVILIANS 2 -#define TEAM3_CIVILIANS 4 -#define TEAM4_CIVILIANS 8 - -// Defines for the playerclass -#define PC_UNDEFINED 0 - -#define PC_SCOUT 1 -#define PC_SNIPER 2 -#define PC_SOLDIER 3 -#define PC_DEMOMAN 4 -#define PC_MEDIC 5 -#define PC_HVYWEAP 6 -#define PC_PYRO 7 -#define PC_SPY 8 -#define PC_ENGINEER 9 - -// Insert new class definitions here - -// PC_RANDOM _MUST_ be the third last class -#define PC_RANDOM 10 // Random playerclass -#define PC_CIVILIAN 11 // Civilians are a special class. They cannot - // be chosen by players, only enforced by maps -#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops - // through the playerclass. - -#define SENTRY_COLOR 10 // will be in the PC_RANDOM slot for team colors -// These are just for the scanner -#define SCAN_SENTRY 13 -#define SCAN_GOALITEM 14 - -// Values returned by CheckArea -enum -{ - CAREA_CLEAR, - CAREA_BLOCKED, - CAREA_NOBUILD -}; - -/*==================================================*/ -/* Impulse Defines */ -/*==================================================*/ -// Alias check to see whether they already have the aliases -#define TF_ALIAS_CHECK 13 - -// CTF Support Impulses -#define HOOK_IMP1 22 -#define FLAG_INFO 23 -#define HOOK_IMP2 39 - -// Axe -#define AXE_IMP 40 - -// Camera Impulse -#define TF_CAM_TARGET 50 -#define TF_CAM_ZOOM 51 -#define TF_CAM_ANGLE 52 -#define TF_CAM_VEC 53 -#define TF_CAM_PROJECTILE 54 -#define TF_CAM_PROJECTILE_Z 55 -#define TF_CAM_REVANGLE 56 -#define TF_CAM_OFFSET 57 -#define TF_CAM_DROP 58 -#define TF_CAM_FADETOBLACK 59 -#define TF_CAM_FADEFROMBLACK 60 -#define TF_CAM_FADETOWHITE 61 -#define TF_CAM_FADEFROMWHITE 62 - -// Last Weapon impulse -#define TF_LAST_WEAPON 69 - -// Status Bar Resolution Settings. Same as CTF to maintain ease of use. -#define TF_STATUSBAR_RES_START 71 -#define TF_STATUSBAR_RES_END 81 - -// Clan Messages -#define TF_MESSAGE_1 82 -#define TF_MESSAGE_2 83 -#define TF_MESSAGE_3 84 -#define TF_MESSAGE_4 85 -#define TF_MESSAGE_5 86 - -#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu - -// Added to PC_??? to get impulse to use if this clashes with your -// own impulses, just change this value, not the PC_?? -#define TF_CHANGEPC 100 -// The next few impulses are all the class selections -//PC_SCOUT 101 -//PC_SNIPER 102 -//PC_SOLDIER 103 -//PC_DEMOMAN 104 -//PC_MEDIC 105 -//PC_HVYWEAP 106 -//PC_PYRO 107 -//PC_RANDOM 108 -//PC_CIVILIAN 109 // Cannot be used -//PC_SPY 110 -//PC_ENGINEER 111 - -// Help impulses -#define TF_DISPLAYLOCATION 118 -#define TF_STATUS_QUERY 119 - -#define TF_HELP_MAP 131 - -// Information impulses -#define TF_INVENTORY 135 -#define TF_SHOWTF 136 -#define TF_SHOWLEGALCLASSES 137 - -// Team Impulses -#define TF_TEAM_1 140 // Join Team 1 -#define TF_TEAM_2 141 // Join Team 2 -#define TF_TEAM_3 142 // Join Team 3 -#define TF_TEAM_4 143 // Join Team 4 -#define TF_TEAM_CLASSES 144 // Impulse to display team classes -#define TF_TEAM_SCORES 145 // Impulse to display team scores -#define TF_TEAM_LIST 146 // Impulse to display the players in each team. - -// Grenade Impulses -#define TF_GRENADE_1 150 // Prime grenade type 1 -#define TF_GRENADE_2 151 // Prime grenade type 2 -#define TF_GRENADE_T 152 // Throw primed grenade - -// Impulses for new items -//#define TF_SCAN 159 // Scanner Pre-Impulse -#define TF_AUTO_SCAN 159 // Scanner On/Off -#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies -#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies -//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) -#define TF_SCAN_SOUND 162 // Scanner sounds on/off -#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) -#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) -#define TF_DETPACK_5 165 // Detpack set to 5 seconds -#define TF_DETPACK_20 166 // Detpack set to 20 seconds -#define TF_DETPACK_50 167 // Detpack set to 50 seconds -#define TF_DETPACK 168 // Detpack Pre-Impulse -#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack -#define TF_PB_DETONATE 170 // Detonate Pipebombs - -// Special skill -#define TF_SPECIAL_SKILL 171 - -// Ammo Drop impulse -#define TF_DROP_AMMO 172 - -// Reload impulse -#define TF_RELOAD 173 - -// auto-zoom toggle -#define TF_AUTOZOOM 174 - -// drop/pass commands -#define TF_DROPKEY 175 - -// Select Medikit -#define TF_MEDIKIT 176 - -// Spy Impulses -#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color -#define TF_SPY_DIE 178 // Feign Death - -// Engineer Impulses -#define TF_ENGINEER_BUILD 179 -#define TF_ENGINEER_SANDBAG 180 - -// Medic -#define TF_MEDIC_HELPME 181 - -// Status bar -#define TF_STATUSBAR_ON 182 -#define TF_STATUSBAR_OFF 183 - -// Discard impulse -#define TF_DISCARD 184 - -// ID Player impulse -#define TF_ID 185 - -// Clan Battle impulses -#define TF_SHOWIDS 186 - -// More Engineer Impulses -#define TF_ENGINEER_DETDISP 187 -#define TF_ENGINEER_DETSENT 188 - -// Admin Commands -#define TF_ADMIN_DEAL_CYCLE 189 -#define TF_ADMIN_KICK 190 -#define TF_ADMIN_BAN 191 -#define TF_ADMIN_COUNTPLAYERS 192 -#define TF_ADMIN_CEASEFIRE 193 - -// Drop Goal Items -#define TF_DROPGOALITEMS 194 - -// More Admin Commands -#define TF_ADMIN_NEXT 195 - -// More Engineer Impulses -#define TF_ENGINEER_DETEXIT 196 -#define TF_ENGINEER_DETENTRANCE 197 - -// Yet MORE Admin Commands -#define TF_ADMIN_LISTIPS 198 - -// Silent Spy Feign -#define TF_SPY_SILENTDIE 199 - - -/*==================================================*/ -/*==================================================*/ -#define TEAM1_COLOR 150 -#define TEAM2_COLOR 250 -#define TEAM3_COLOR 45 -#define TEAM4_COLOR 100 - -/*==================================================*/ -/* Defines for the ENGINEER's Building ability */ -/*==================================================*/ -// Ammo costs -#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell -#define AMMO_COST_NAILS 1 -#define AMMO_COST_ROCKETS 2 -#define AMMO_COST_CELLS 2 - -// Building types -#define BUILD_DISPENSER 1 -#define BUILD_SENTRYGUN 2 -#define BUILD_MORTAR 3 -#define BUILD_TELEPORTER_ENTRANCE 4 -#define BUILD_TELEPORTER_EXIT 5 - -// Building metal costs -#define BUILD_COST_DISPENSER 100 // Metal needed to built -#define BUILD_COST_SENTRYGUN 130 -#define BUILD_COST_MORTAR 150 -#define BUILD_COST_TELEPORTER 125 - -#define BUILD_COST_SANDBAG 20 // Built with a separate alias - -// Building times -#define BUILD_TIME_DISPENSER 2 // seconds to build -#define BUILD_TIME_SENTRYGUN 5 -#define BUILD_TIME_MORTAR 5 -#define BUILD_TIME_TELEPORTER 4 - -// Building health levels -#define BUILD_HEALTH_DISPENSER 150 // Health of the building -#define BUILD_HEALTH_SENTRYGUN 150 -#define BUILD_HEALTH_MORTAR 200 -#define BUILD_HEALTH_TELEPORTER 80 - -// Dispenser's maximum carrying capability -#define BUILD_DISPENSER_MAX_SHELLS 400 -#define BUILD_DISPENSER_MAX_NAILS 600 -#define BUILD_DISPENSER_MAX_ROCKETS 300 -#define BUILD_DISPENSER_MAX_CELLS 400 -#define BUILD_DISPENSER_MAX_ARMOR 500 - -// Build state sent down to client -#define BS_BUILDING (1<<0) -#define BS_HAS_DISPENSER (1<<1) -#define BS_HAS_SENTRYGUN (1<<2) -#define BS_CANB_DISPENSER (1<<3) -#define BS_CANB_SENTRYGUN (1<<4) -/*==================================================*/ -/* Ammo quantities for dropping & dispenser use */ -/*==================================================*/ -#define DROP_SHELLS 20 -#define DROP_NAILS 20 -#define DROP_ROCKETS 10 -#define DROP_CELLS 10 -#define DROP_ARMOR 40 - -/*==================================================*/ -/* Team Defines */ -/*==================================================*/ -#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. - // A new global to hold new team colors is needed, and more flags - // in the spawnpoint spawnflags may need to be used. - // Basically, don't change this unless you know what you're doing :) - -/*==================================================*/ -/* New Weapon Defines */ -/*==================================================*/ -#define WEAP_HOOK 1 -#define WEAP_BIOWEAPON 2 -#define WEAP_MEDIKIT 4 -#define WEAP_SPANNER 8 -#define WEAP_AXE 16 -#define WEAP_SNIPER_RIFLE 32 -#define WEAP_AUTO_RIFLE 64 -#define WEAP_SHOTGUN 128 -#define WEAP_SUPER_SHOTGUN 256 -#define WEAP_NAILGUN 512 -#define WEAP_SUPER_NAILGUN 1024 -#define WEAP_GRENADE_LAUNCHER 2048 -#define WEAP_FLAMETHROWER 4096 -#define WEAP_ROCKET_LAUNCHER 8192 -#define WEAP_INCENDIARY 16384 -#define WEAP_ASSAULT_CANNON 32768 -#define WEAP_LIGHTNING 65536 -#define WEAP_DETPACK 131072 -#define WEAP_TRANQ 262144 -#define WEAP_LASER 524288 -// still room for 12 more weapons -// but we can remove some by giving the weapons -// a weapon mode (like the rifle) - -// HL-compatible weapon numbers -#define WEAPON_HOOK 1 -#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) -#define WEAPON_MEDIKIT (WEAPON_HOOK+2) -#define WEAPON_SPANNER (WEAPON_HOOK+3) -#define WEAPON_AXE (WEAPON_HOOK+4) -#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) -#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) -#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) -#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) -#define WEAPON_NAILGUN (WEAPON_HOOK+9) -#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) -#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) -#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) -#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) -#define WEAPON_INCENDIARY (WEAPON_HOOK+14) -#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) -#define WEAPON_LIGHTNING (WEAPON_HOOK+17) -#define WEAPON_DETPACK (WEAPON_HOOK+18) -#define WEAPON_TRANQ (WEAPON_HOOK+19) -#define WEAPON_LASER (WEAPON_HOOK+20) -#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) -#define WEAPON_KNIFE (WEAPON_HOOK+22) -#define WEAPON_BENCHMARK (WEAPON_HOOK+23) - -/*==================================================*/ -/* New Weapon Related Defines */ -/*==================================================*/ -// shots per reload -#define RE_SHOTGUN 8 -#define RE_SUPER_SHOTGUN 16 // 8 shots -#define RE_GRENADE_LAUNCHER 6 -#define RE_ROCKET_LAUNCHER 4 - -// reload times -#define RE_SHOTGUN_TIME 2 -#define RE_SUPER_SHOTGUN_TIME 3 -#define RE_GRENADE_LAUNCHER_TIME 4 -#define RE_ROCKET_LAUNCHER_TIME 5 - -// Maximum velocity you can move and fire the Sniper Rifle -#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 - -// Medikit -#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit -#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense - -// Spanner -#define WEAP_SPANNER_REPAIR 10 - -// Detpack -#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack -#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack -#define WEAP_DETPACK_SIZE 700 // Explosion Size -#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering -#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into - -// Tranquiliser Gun -#define TRANQ_TIME 15 - -// Grenades -#define GR_PRIMETIME 3 -#define GR_CALTROP_PRIME 0.5 -#define GR_TYPE_NONE 0 -#define GR_TYPE_NORMAL 1 -#define GR_TYPE_CONCUSSION 2 -#define GR_TYPE_NAIL 3 -#define GR_TYPE_MIRV 4 -#define GR_TYPE_NAPALM 5 -//#define GR_TYPE_FLARE 6 -#define GR_TYPE_GAS 7 -#define GR_TYPE_EMP 8 -#define GR_TYPE_CALTROP 9 -//#define GR_TYPE_FLASH 10 - -// Defines for WeaponMode -#define GL_NORMAL 0 -#define GL_PIPEBOMB 1 - -// Defines for OLD Concussion Grenade -#define GR_OLD_CONCUSS_TIME 5 -#define GR_OLD_CONCUSS_DEC 20 - -// Defines for Concussion Grenade -#define GR_CONCUSS_TIME 0.25 -#define GR_CONCUSS_DEC 10 -#define MEDIUM_PING 150 -#define HIGH_PING 200 - -// Defines for the Gas Grenade -#define GR_HALLU_TIME 0.3 -#define GR_OLD_HALLU_TIME 0.5 -#define GR_HALLU_DEC 2.5 - -// Defines for the BioInfection -#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players - -/*==================================================*/ -/* New Items */ -/*==================================================*/ -#define NIT_SCANNER 1 - -#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 -#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 - -/*==================================================*/ -/* New Item Flags */ -/*==================================================*/ -#define NIT_SCANNER_ENEMY 1 // Detect enemies -#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) -#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. - -/*==================================================*/ -/* New Item Related Defines */ -/*==================================================*/ -#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner - // is multiplied by this to get the scanrange. -#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan -#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected - // by scanners that only detect movement - -/*==================================================*/ -/* Variables used for New Weapons and Reloading */ -/*==================================================*/ -// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. -#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% -#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% -#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% -#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% -#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% - -/*==========================================================================*/ -/* TEAMFORTRESS CLASS DETAILS */ -/*==========================================================================*/ -// Class Details for SCOUT -#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. -#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level -#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed -#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed -#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class -#define PC_SCOUT_INITARMOR 25 // Armor level when respawned -#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption -#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned -#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class -#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned -#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN -#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry -#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry -#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry -#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry -#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned -#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned -#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned -#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned -#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has -#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has -#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned -#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned -#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has - -#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range -#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector -#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse -#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range -#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan - -// Class Details for SNIPER -#define PC_SNIPER_SKIN 5 -#define PC_SNIPER_MAXHEALTH 90 -#define PC_SNIPER_MAXSPEED 300 -#define PC_SNIPER_MAXSTRAFESPEED 300 -#define PC_SNIPER_MAXARMOR 50 -#define PC_SNIPER_INITARMOR 0 -#define PC_SNIPER_MAXARMORTYPE 0.3 -#define PC_SNIPER_INITARMORTYPE 0.3 -#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL -#define PC_SNIPER_INITARMORCLASS 0 -#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN -#define PC_SNIPER_MAXAMMO_SHOT 75 -#define PC_SNIPER_MAXAMMO_NAIL 100 -#define PC_SNIPER_MAXAMMO_CELL 50 -#define PC_SNIPER_MAXAMMO_ROCKET 25 -#define PC_SNIPER_INITAMMO_SHOT 60 -#define PC_SNIPER_INITAMMO_NAIL 50 -#define PC_SNIPER_INITAMMO_CELL 0 -#define PC_SNIPER_INITAMMO_ROCKET 0 -#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE -#define PC_SNIPER_GRENADE_INIT_1 2 -#define PC_SNIPER_GRENADE_INIT_2 0 -#define PC_SNIPER_TF_ITEMS 0 - -// Class Details for SOLDIER -#define PC_SOLDIER_SKIN 6 -#define PC_SOLDIER_MAXHEALTH 100 -#define PC_SOLDIER_MAXSPEED 240 -#define PC_SOLDIER_MAXSTRAFESPEED 240 -#define PC_SOLDIER_MAXARMOR 200 -#define PC_SOLDIER_INITARMOR 100 -#define PC_SOLDIER_MAXARMORTYPE 0.8 -#define PC_SOLDIER_INITARMORTYPE 0.8 -#define PC_SOLDIER_ARMORCLASSES 31 // ALL -#define PC_SOLDIER_INITARMORCLASS 0 -#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER -#define PC_SOLDIER_MAXAMMO_SHOT 100 -#define PC_SOLDIER_MAXAMMO_NAIL 100 -#define PC_SOLDIER_MAXAMMO_CELL 50 -#define PC_SOLDIER_MAXAMMO_ROCKET 50 -#define PC_SOLDIER_INITAMMO_SHOT 50 -#define PC_SOLDIER_INITAMMO_NAIL 0 -#define PC_SOLDIER_INITAMMO_CELL 0 -#define PC_SOLDIER_INITAMMO_ROCKET 10 -#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL -#define PC_SOLDIER_GRENADE_INIT_1 2 -#define PC_SOLDIER_GRENADE_INIT_2 1 -#define PC_SOLDIER_TF_ITEMS 0 - -#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active -#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active -#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active -#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's -#define MAX_CONCUSSION_GRENS 3 -#define MAX_CALTROP_CANS 3 - -// Class Details for DEMOLITION MAN -#define PC_DEMOMAN_SKIN 1 -#define PC_DEMOMAN_MAXHEALTH 90 -#define PC_DEMOMAN_MAXSPEED 280 -#define PC_DEMOMAN_MAXSTRAFESPEED 280 -#define PC_DEMOMAN_MAXARMOR 120 -#define PC_DEMOMAN_INITARMOR 50 -#define PC_DEMOMAN_MAXARMORTYPE 0.6 -#define PC_DEMOMAN_INITARMORTYPE 0.6 -#define PC_DEMOMAN_ARMORCLASSES 31 // ALL -#define PC_DEMOMAN_INITARMORCLASS 0 -#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK -#define PC_DEMOMAN_MAXAMMO_SHOT 75 -#define PC_DEMOMAN_MAXAMMO_NAIL 50 -#define PC_DEMOMAN_MAXAMMO_CELL 50 -#define PC_DEMOMAN_MAXAMMO_ROCKET 50 -#define PC_DEMOMAN_MAXAMMO_DETPACK 1 -#define PC_DEMOMAN_INITAMMO_SHOT 30 -#define PC_DEMOMAN_INITAMMO_NAIL 0 -#define PC_DEMOMAN_INITAMMO_CELL 0 -#define PC_DEMOMAN_INITAMMO_ROCKET 20 -#define PC_DEMOMAN_INITAMMO_DETPACK 1 -#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV -#define PC_DEMOMAN_GRENADE_INIT_1 2 -#define PC_DEMOMAN_GRENADE_INIT_2 2 -#define PC_DEMOMAN_TF_ITEMS 0 - -// Class Details for COMBAT MEDIC -#define PC_MEDIC_SKIN 3 -#define PC_MEDIC_MAXHEALTH 90 -#define PC_MEDIC_MAXSPEED 320 -#define PC_MEDIC_MAXSTRAFESPEED 320 -#define PC_MEDIC_MAXARMOR 100 -#define PC_MEDIC_INITARMOR 50 -#define PC_MEDIC_MAXARMORTYPE 0.6 -#define PC_MEDIC_INITARMORTYPE 0.3 -#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION -#define PC_MEDIC_INITARMORCLASS 0 -#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN -#define PC_MEDIC_MAXAMMO_SHOT 75 -#define PC_MEDIC_MAXAMMO_NAIL 150 -#define PC_MEDIC_MAXAMMO_CELL 50 -#define PC_MEDIC_MAXAMMO_ROCKET 25 -#define PC_MEDIC_MAXAMMO_MEDIKIT 100 -#define PC_MEDIC_INITAMMO_SHOT 50 -#define PC_MEDIC_INITAMMO_NAIL 50 -#define PC_MEDIC_INITAMMO_CELL 0 -#define PC_MEDIC_INITAMMO_ROCKET 0 -#define PC_MEDIC_INITAMMO_MEDIKIT 50 -#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION -#define PC_MEDIC_GRENADE_INIT_1 2 -#define PC_MEDIC_GRENADE_INIT_2 2 -#define PC_MEDIC_TF_ITEMS 0 -#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. -#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. - -// Class Details for HVYWEAP -#define PC_HVYWEAP_SKIN 2 -#define PC_HVYWEAP_MAXHEALTH 100 -#define PC_HVYWEAP_MAXSPEED 230 -#define PC_HVYWEAP_MAXSTRAFESPEED 230 -#define PC_HVYWEAP_MAXARMOR 300 -#define PC_HVYWEAP_INITARMOR 150 -#define PC_HVYWEAP_MAXARMORTYPE 0.8 -#define PC_HVYWEAP_INITARMORTYPE 0.8 -#define PC_HVYWEAP_ARMORCLASSES 31 // ALL -#define PC_HVYWEAP_INITARMORCLASS 0 -#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN -#define PC_HVYWEAP_MAXAMMO_SHOT 200 -#define PC_HVYWEAP_MAXAMMO_NAIL 200 -#define PC_HVYWEAP_MAXAMMO_CELL 50 -#define PC_HVYWEAP_MAXAMMO_ROCKET 25 -#define PC_HVYWEAP_INITAMMO_SHOT 200 -#define PC_HVYWEAP_INITAMMO_NAIL 0 -#define PC_HVYWEAP_INITAMMO_CELL 30 -#define PC_HVYWEAP_INITAMMO_ROCKET 0 -#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV -#define PC_HVYWEAP_GRENADE_INIT_1 2 -#define PC_HVYWEAP_GRENADE_INIT_2 1 -#define PC_HVYWEAP_TF_ITEMS 0 -#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon - - - -// Class Details for PYRO -#define PC_PYRO_SKIN 21 -#define PC_PYRO_MAXHEALTH 100 -#define PC_PYRO_MAXSPEED 300 -#define PC_PYRO_MAXSTRAFESPEED 300 -#define PC_PYRO_MAXARMOR 150 -#define PC_PYRO_INITARMOR 50 -#define PC_PYRO_MAXARMORTYPE 0.6 -#define PC_PYRO_INITARMORTYPE 0.6 -#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION -#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE -#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN -#define PC_PYRO_MAXAMMO_SHOT 40 -#define PC_PYRO_MAXAMMO_NAIL 50 -#define PC_PYRO_MAXAMMO_CELL 200 -#define PC_PYRO_MAXAMMO_ROCKET 20 -#define PC_PYRO_INITAMMO_SHOT 20 -#define PC_PYRO_INITAMMO_NAIL 0 -#define PC_PYRO_INITAMMO_CELL 120 -#define PC_PYRO_INITAMMO_ROCKET 5 -#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM -#define PC_PYRO_GRENADE_INIT_1 2 -#define PC_PYRO_GRENADE_INIT_2 4 -#define PC_PYRO_TF_ITEMS 0 -#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot - -// Class Details for SPY -#define PC_SPY_SKIN 22 -#define PC_SPY_MAXHEALTH 90 -#define PC_SPY_MAXSPEED 300 -#define PC_SPY_MAXSTRAFESPEED 300 -#define PC_SPY_MAXARMOR 100 -#define PC_SPY_INITARMOR 25 -#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 -#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 -#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION -#define PC_SPY_INITARMORCLASS 0 -#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN -#define PC_SPY_MAXAMMO_SHOT 40 -#define PC_SPY_MAXAMMO_NAIL 100 -#define PC_SPY_MAXAMMO_CELL 30 -#define PC_SPY_MAXAMMO_ROCKET 15 -#define PC_SPY_INITAMMO_SHOT 40 -#define PC_SPY_INITAMMO_NAIL 50 -#define PC_SPY_INITAMMO_CELL 10 -#define PC_SPY_INITAMMO_ROCKET 0 -#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS -#define PC_SPY_GRENADE_INIT_1 2 -#define PC_SPY_GRENADE_INIT_2 2 -#define PC_SPY_TF_ITEMS 0 -#define PC_SPY_CELL_REGEN_TIME 5 -#define PC_SPY_CELL_REGEN_AMOUNT 1 -#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible -#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover - -// Class Details for ENGINEER -#define PC_ENGINEER_SKIN 22 // Not used anymore -#define PC_ENGINEER_MAXHEALTH 80 -#define PC_ENGINEER_MAXSPEED 300 -#define PC_ENGINEER_MAXSTRAFESPEED 300 -#define PC_ENGINEER_MAXARMOR 50 -#define PC_ENGINEER_INITARMOR 25 -#define PC_ENGINEER_MAXARMORTYPE 0.6 -#define PC_ENGINEER_INITARMORTYPE 0.3 -#define PC_ENGINEER_ARMORCLASSES 31 // ALL -#define PC_ENGINEER_INITARMORCLASS 0 -#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN -#define PC_ENGINEER_MAXAMMO_SHOT 50 -#define PC_ENGINEER_MAXAMMO_NAIL 50 -#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal -#define PC_ENGINEER_MAXAMMO_ROCKET 30 -#define PC_ENGINEER_INITAMMO_SHOT 20 -#define PC_ENGINEER_INITAMMO_NAIL 25 -#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal -#define PC_ENGINEER_INITAMMO_ROCKET 0 -#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP -#define PC_ENGINEER_GRENADE_INIT_1 2 -#define PC_ENGINEER_GRENADE_INIT_2 2 -#define PC_ENGINEER_TF_ITEMS 0 - -// Class Details for CIVILIAN -#define PC_CIVILIAN_SKIN 22 -#define PC_CIVILIAN_MAXHEALTH 50 -#define PC_CIVILIAN_MAXSPEED 240 -#define PC_CIVILIAN_MAXSTRAFESPEED 240 -#define PC_CIVILIAN_MAXARMOR 0 -#define PC_CIVILIAN_INITARMOR 0 -#define PC_CIVILIAN_MAXARMORTYPE 0 -#define PC_CIVILIAN_INITARMORTYPE 0 -#define PC_CIVILIAN_ARMORCLASSES 0 -#define PC_CIVILIAN_INITARMORCLASS 0 -#define PC_CIVILIAN_WEAPONS WEAP_AXE -#define PC_CIVILIAN_MAXAMMO_SHOT 0 -#define PC_CIVILIAN_MAXAMMO_NAIL 0 -#define PC_CIVILIAN_MAXAMMO_CELL 0 -#define PC_CIVILIAN_MAXAMMO_ROCKET 0 -#define PC_CIVILIAN_INITAMMO_SHOT 0 -#define PC_CIVILIAN_INITAMMO_NAIL 0 -#define PC_CIVILIAN_INITAMMO_CELL 0 -#define PC_CIVILIAN_INITAMMO_ROCKET 0 -#define PC_CIVILIAN_GRENADE_TYPE_1 0 -#define PC_CIVILIAN_GRENADE_TYPE_2 0 -#define PC_CIVILIAN_GRENADE_INIT_1 0 -#define PC_CIVILIAN_GRENADE_INIT_2 0 -#define PC_CIVILIAN_TF_ITEMS 0 - - -/*==========================================================================*/ -/* TEAMFORTRESS GOALS */ -/*==========================================================================*/ -// For all these defines, see the tfortmap.txt that came with the zip -// for complete descriptions. -// Defines for Goal Activation types : goal_activation (in goals) -#define TFGA_TOUCH 1 // Activated when touched -#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion -#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met -#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner -#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning - -// Defines for Goal Effects types : goal_effect -#define TFGE_AP 1 // AP is affected. Default. -#define TFGE_AP_TEAM 2 // All of the AP's team. -#define TFGE_NOT_AP_TEAM 4 // All except AP's team. -#define TFGE_NOT_AP 8 // All except AP. -#define TFGE_WALL 16 // If set, walls stop the Radius effects -#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected -#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects - -// Defines for Goal Result types : goal_result -#define TFGR_SINGLE 1 // Goal can only be activated once -#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses -#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level -#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results -#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy -#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point -#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys - -// Defines for Goal Group Result types : goal_group -// None! -// But I'm leaving this variable in there, since it's fairly likely -// that some will show up sometime. - -// Defines for Goal Item types, : goal_activation (in items) -#define TFGI_GLOW 1 // Players carrying this GoalItem will glow -#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed -#define TFGI_DROP 4 // Players dying with this item will drop it -#define TFGI_RETURN_DROP 8 // Return if a player with it dies -#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation -#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE -#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details -#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped -#define TFGI_KEEP 256 // Players keep this item even when they die -#define TFGI_ITEMGLOWS 512 // Item glows when on the ground -#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed -#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning -#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players -#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc - -// Defines for methods of GoalItem returning -#define GI_RET_DROP_DEAD 0 // Dropped by a dead player -#define GI_RET_DROP_LIVING 1 // Dropped by a living player -#define GI_RET_GOAL 2 // Returned by a Goal -#define GI_RET_TIME 3 // Returned due to timeout - -// Defines for TeamSpawnpoints : goal_activation (in teamspawns) -#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times -#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times - -// Defines for TeamSpawnpoints : goal_effects (in teamspawns) -#define TFSP_REMOVESELF 1 // Remove itself after being spawned on - -// Defines for Goal States -#define TFGS_ACTIVE 1 -#define TFGS_INACTIVE 2 -#define TFGS_REMOVED 3 -#define TFGS_DELAYED 4 - -// Defines for GoalItem Removing from Player Methods -#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player -#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal -#define GI_DROP_PLAYERDROP 2 // Dropped by a player - -// Legal Playerclass Handling -#define TF_ILL_SCOUT 1 -#define TF_ILL_SNIPER 2 -#define TF_ILL_SOLDIER 4 -#define TF_ILL_DEMOMAN 8 -#define TF_ILL_MEDIC 16 -#define TF_ILL_HVYWEP 32 -#define TF_ILL_PYRO 64 -#define TF_ILL_RANDOMPC 128 -#define TF_ILL_SPY 256 -#define TF_ILL_ENGINEER 512 - -// Addition classes -#define CLASS_TFGOAL 128 -#define CLASS_TFGOAL_TIMER 129 -#define CLASS_TFGOAL_ITEM 130 -#define CLASS_TFSPAWN 131 - -/*==========================================================================*/ -/* Flamethrower */ -/*==========================================================================*/ -#define FLAME_PLYRMAXTIME 5.0 // lifetime in seconds of a flame on a player -#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) -#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade -#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player -#define FLAME_NUMLIGHTS 1 // maximum number of light flame -#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' -#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode -#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames -#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. -#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn -#define PER_FLAME_DAMAGE 2 // Damage taken per second per flame by burning players - -/*==================================================*/ -/* CTF Support defines */ -/*==================================================*/ -#define CTF_FLAG1 1 -#define CTF_FLAG2 2 -#define CTF_DROPOFF1 3 -#define CTF_DROPOFF2 4 -#define CTF_SCORE1 5 -#define CTF_SCORE2 6 - -//.float hook_out; - -/*==================================================*/ -/* Camera defines */ -/*==================================================*/ -/* -float live_camera; -.float camdist; -.vector camangle; -.entity camera_list; -*/ - -/*==================================================*/ -/* QuakeWorld defines */ -/*==================================================*/ -/* -float already_chosen_map; - -// grappling hook variables -.entity hook; -.float on_hook; -.float fire_held_down;// flag - TRUE if player is still holding down the - // fire button after throwing a hook. -*/ -/*==================================================*/ -/* Server Settings */ -/*==================================================*/ -// Admin modes -#define ADMIN_MODE_NONE 0 -#define ADMIN_MODE_DEAL 1 - -/*==================================================*/ -/* Death Message defines */ -/*==================================================*/ -#define DMSG_SHOTGUN 1 -#define DMSG_SSHOTGUN 2 -#define DMSG_NAILGUN 3 -#define DMSG_SNAILGUN 4 -#define DMSG_GRENADEL 5 -#define DMSG_ROCKETL 6 -#define DMSG_LIGHTNING 7 -#define DMSG_GREN_HAND 8 -#define DMSG_GREN_NAIL 9 -#define DMSG_GREN_MIRV 10 -#define DMSG_GREN_PIPE 11 -#define DMSG_DETPACK 12 -#define DMSG_BIOWEAPON 13 -#define DMSG_BIOWEAPON_ATT 14 -#define DMSG_FLAME 15 -#define DMSG_DETPACK_DIS 16 -#define DMSG_AXE 17 -#define DMSG_SNIPERRIFLE 18 -#define DMSG_AUTORIFLE 19 -#define DMSG_ASSAULTCANNON 20 -#define DMSG_HOOK 21 -#define DMSG_BACKSTAB 22 -#define DMSG_MEDIKIT 23 -#define DMSG_GREN_GAS 24 -#define DMSG_TRANQ 25 -#define DMSG_LASERBOLT 26 -#define DMSG_SENTRYGUN_BULLET 27 -#define DMSG_SNIPERLEGSHOT 28 -#define DMSG_SNIPERHEADSHOT 29 -#define DMSG_GREN_EMP 30 -#define DMSG_GREN_EMP_AMMO 31 -#define DMSG_SPANNER 32 -#define DMSG_INCENDIARY 33 -#define DMSG_SENTRYGUN_ROCKET 34 -#define DMSG_GREN_FLASH 35 -#define DMSG_TRIGGER 36 -#define DMSG_MIRROR 37 -#define DMSG_SENTRYDEATH 38 -#define DMSG_DISPENSERDEATH 39 -#define DMSG_GREN_AIRPIPE 40 -#define DMSG_CALTROP 41 - -/*==================================================*/ -// TOGGLEFLAGS -/*==================================================*/ -// Some of the toggleflags aren't used anymore, but the bits are still -// there to provide compatability with old maps -#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit -#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit -#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit -//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE -#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade -#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE -#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE -#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. -#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore -#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set - // In a map. Cannot be toggled by players. -#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only -#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off -//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags -#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps -#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation - -#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only - -/*======================*/ -// Menu stuff // -/*======================*/ - -#define MENU_DEFAULT 1 -#define MENU_TEAM 2 -#define MENU_CLASS 3 -#define MENU_MAPBRIEFING 4 -#define MENU_INTRO 5 -#define MENU_CLASSHELP 6 -#define MENU_CLASSHELP2 7 -#define MENU_REPEATHELP 8 - -#define MENU_SPECHELP 9 - - -#define MENU_SPY 12 -#define MENU_SPY_SKIN 13 -#define MENU_SPY_COLOR 14 -#define MENU_ENGINEER 15 -#define MENU_ENGINEER_FIX_DISPENSER 16 -#define MENU_ENGINEER_FIX_SENTRYGUN 17 -#define MENU_ENGINEER_FIX_MORTAR 18 -#define MENU_DISPENSER 19 -#define MENU_CLASS_CHANGE 20 -#define MENU_TEAM_CHANGE 21 - -#define MENU_REFRESH_RATE 25 - -#define MENU_VOICETWEAK 50 - -//============================ -// Timer Types -#define TF_TIMER_ANY 0 -#define TF_TIMER_CONCUSSION 1 -#define TF_TIMER_INFECTION 2 -#define TF_TIMER_HALLUCINATION 3 -#define TF_TIMER_TRANQUILISATION 4 -#define TF_TIMER_ROTHEALTH 5 -#define TF_TIMER_REGENERATION 6 -#define TF_TIMER_GRENPRIME 7 -#define TF_TIMER_CELLREGENERATION 8 -#define TF_TIMER_DETPACKSET 9 -#define TF_TIMER_DETPACKDISARM 10 -#define TF_TIMER_BUILD 11 -#define TF_TIMER_CHECKBUILDDISTANCE 12 -#define TF_TIMER_DISGUISE 13 -#define TF_TIMER_DISPENSERREFILL 14 - -// Non Player timers -#define TF_TIMER_RETURNITEM 100 -#define TF_TIMER_DELAYEDGOAL 101 -#define TF_TIMER_ENDROUND 102 - -//============================ -// Teamscore printing -#define TS_PRINT_SHORT 1 -#define TS_PRINT_LONG 2 -#define TS_PRINT_LONG_TO_ALL 3 - -#ifndef TF_DEFS_ONLY -typedef struct -{ - int topColor; - int bottomColor; -} team_color_t; -/*==================================================*/ -/* GLOBAL VARIABLES */ -/*==================================================*/ -// FortressMap stuff -extern float number_of_teams; // number of teams supported by the map -extern int illegalclasses[5]; // Illegal playerclasses for all teams -extern int civilianteams; // Bitfield holding Civilian teams -extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams - -extern team_color_t teamcolors[5][PC_LASTCLASS]; // Colors for each of the 4 teams -extern int teamscores[5]; // Goal Score of each team -extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers -extern int teamfrags[5]; // Total Frags for each team -extern int teamlives[5]; // Number of lives each team's players have -extern int teammaxplayers[5]; // Max number of players allowed in each team -extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set - // stores the damage ratio players take/give -extern int teamallies[5]; // Keeps track of which teams are allied -extern string_t team_names[5]; - -extern BOOL CTF_Map; -extern BOOL birthday; -extern BOOL christmas; - -extern float num_world_flames; - -// Clan Battle stuff -extern float clan_scores_dumped; -extern float cb_prematch_time; -extern float fOldPrematch; -extern float fOldCeaseFire; -extern float cb_ceasefire_time; -extern float last_id; -extern float spy_off; -extern float old_grens; -extern float flagem_checked; -extern float flNextEqualisationCalc; -extern BOOL cease_fire; -extern BOOL no_cease_fire_text; -extern BOOL initial_cease_fire; -extern BOOL last_cease_fire; -// Autokick stuff -extern float autokick_kills; - -extern float deathmsg; // Global, which is set before every T_Damage, to indicate - // the death message that should be used. - -extern char *sTeamSpawnNames[]; -extern char *sClassNames[]; -extern char *sNewClassModelFiles[]; -extern char *sOldClassModelFiles[]; -extern char *sClassModels[]; -extern char *sClassCfgs[]; -extern char *sGrenadeNames[]; -extern string_t team_menu_string; - -extern int toggleflags; // toggleable flags - -extern BOOL g_bFirstClient; - -extern float g_fNextPrematchAlert; - -typedef struct -{ - int ip; - edict_t *pEdict; -} ip_storage_t; - -extern ip_storage_t g_IpStorage[32]; - -class CGhost; -/*==========================================================================*/ -BOOL ClassIsRestricted(float tno, int pc); -char* GetTeamName(int tno); -int TeamFortress_GetNoPlayers(); -void DestroyBuilding(CBaseEntity *eng, char *bld); -void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); -float anglemod( float v ); - -// Team Funcs -BOOL TeamFortress_TeamIsCivilian(float tno); -void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); -BOOL TeamFortress_TeamPutPlayerInTeam(); -void TeamFortress_TeamSetColor(int tno); -void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); -int TeamFortress_TeamGetScoreFrags(int tno); -int TeamFortress_TeamGetNoPlayers(int tno); -float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); -BOOL IsSpawnPointValid( Vector &pos ); -BOOL TeamFortress_SortTeams( void ); -void DumpClanScores( void ); -void CalculateTeamEqualiser(); - -// mapscript funcs -void ParseTFServerSettings(); -void ParseTFMapSettings(); -CBaseEntity* Finditem(int ino); -CBaseEntity* Findgoal(int gno); -CBaseEntity* Findteamspawn(int gno); -void RemoveGoal(CBaseEntity *Goal); -void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); -void dremove( CBaseEntity *te ); -void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); -void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); -void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); -void tfgoalitem_checkgoalreturn(CBaseEntity *Item); -void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); -void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); -void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); -// hooks into the mapscript for all entities -BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); -BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); - -// prematch & ceasefire -void Display_Prematch(); -void Check_Ceasefire(); - -// admin -void KickPlayer( CBaseEntity *pTarget ); -void BanPlayer( CBaseEntity *pTarget ); -CGhost *FindGhost( int iGhostID ); -int GetBattleID( edict_t *pEntity ); - -extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) -extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. -extern cvar_t tfc_spam_limit; // at this many points, gag the spammer -extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; -extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; -extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; -extern cvar_t allow_spectators; - -/*==========================================================================*/ -class CTFFlame : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT FlameThink( void ); - static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); - void FlameDestroy( void ); - - float m_flNextDamageTime; -}; - -/*==========================================================================*/ -// MAPSCRIPT CLASSES -class CTFGoal : public CBaseAnimating -{ -public: - void Spawn( void ); - void StartGoal( void ); - void EXPORT PlaceGoal( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int Classify ( void ) { return CLASS_TFGOAL; } - - void SetObjectCollisionBox( void ); -}; - -class CTFGoalItem : public CTFGoal -{ -public: - void Spawn( void ); - void StartItem( void ); - void EXPORT PlaceItem( void ); - int Classify ( void ) { return CLASS_TFGOAL_ITEM; } - - float m_flDroppedAt; -}; - -class CTFTimerGoal : public CTFGoal -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_TFGOAL_TIMER; } -}; - -class CTFSpawn : public CBaseEntity -{ -public: - void Spawn( void ); - void Activate( void ); - int Classify ( void ) { return CLASS_TFSPAWN; } - BOOL CheckTeam( int iTeamNo ); - EHANDLE m_pTeamCheck; -}; - -class CTFDetect : public CBaseEntity -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_TFGOAL; } -}; - -class CTelefragDeath : public CBaseEntity -{ -public: - void Spawn( void ); - void EXPORT DeathTouch( CBaseEntity *pOther ); -}; - -class CTeamCheck : public CBaseDelay -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - BOOL TeamMatches( int iTeam ); -}; -class CTeamSet : public CBaseDelay -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -#endif // TF_DEFS_ONLY -#endif // __TF_DEFS_H - - +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +****/ + +#ifndef __TF_DEFS_H +#define __TF_DEFS_H + +//=========================================================================== +// OLD OPTIONS.QC +//=========================================================================== +#define DEFAULT_AUTOZOOM FALSE +#define WEINER_SNIPER // autoaiming for sniper rifle +#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. + +//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server +#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active +#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active + +//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time +//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server +#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into +#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) +#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies + +#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. + // 60 is a mild setting, and won't make too much difference + // increasing it _decreases_ the amount of help the losing team gets + // Minimum setting is 1, which would really help the losing team + +#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to + // appear whenever a player connects +#define NEVER_TEAMFRAGS FALSE // teamfrags options always off +#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on +#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast +#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds + +#define MAPBRIEFING_MAXTEXTLENGTH 512 +#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed + +// Debug Options +//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res + // mode and/or piping the output from the server to a file. +#ifdef MAP_DEBUG + #define MDEBUG(x) x +#else + #define MDEBUG(x) +#endif +//#define VERBOSE // Verbose Debugging on/off + +//=========================================================================== +// OLD QUAKE Defs +//=========================================================================== +// items +#define IT_AXE 4096 +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_EXTRA_WEAPON 128 + +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 + +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 + +#define IT_KEY1 131072 +#define IT_KEY2 262144 + +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_HOOK 8388608 + +#define IT_KEY3 16777216 // Stomp invisibility +#define IT_KEY4 33554432 // Stomp invulnerability + +//=========================================================================== +// TEAMFORTRESS Defs +//=========================================================================== +// TeamFortress State Flags +#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade +#define TFSTATE_RELOADING 2 // Whether the player is reloading +#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE +#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn +#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon +#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) +#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) +#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) +#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) +#define TFSTATE_BURNING 512 // Is on fire +#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade +#define TFSTATE_AIMING 2048 // is using the laser sight +#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming +#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire +#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating +#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised +#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack +#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health + +// Defines used by TF_T_Damage (see combat.qc) +#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target +#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) +#define TF_TD_NOTSELF 4 // Doesn't damage self + +#define TF_TD_OTHER 0 // Ignore armorclass +#define TF_TD_SHOT 1 // Bullet damage +#define TF_TD_NAIL 2 // Nail damage +#define TF_TD_EXPLOSION 4 // Explosion damage +#define TF_TD_ELECTRICITY 8 // Electric damage +#define TF_TD_FIRE 16 // Fire damage +#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc + +/*==================================================*/ +/* Toggleable Game Settings */ +/*==================================================*/ +#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn + +#define TEAMPLAY_NORMAL 1 +#define TEAMPLAY_HALFDIRECT 2 +#define TEAMPLAY_NODIRECT 4 +#define TEAMPLAY_HALFEXPLOSIVE 8 +#define TEAMPLAY_NOEXPLOSIVE 16 +#define TEAMPLAY_LESSPLAYERSHELP 32 +#define TEAMPLAY_LESSSCOREHELP 64 +#define TEAMPLAY_HALFDIRECTARMOR 128 +#define TEAMPLAY_NODIRECTARMOR 256 +#define TEAMPLAY_HALFEXPARMOR 512 +#define TEAMPLAY_NOEXPARMOR 1024 +#define TEAMPLAY_HALFDIRMIRROR 2048 +#define TEAMPLAY_FULLDIRMIRROR 4096 +#define TEAMPLAY_HALFEXPMIRROR 8192 +#define TEAMPLAY_FULLEXPMIRROR 16384 + +#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) +// FortressMap stuff +#define TEAM1_CIVILIANS 1 +#define TEAM2_CIVILIANS 2 +#define TEAM3_CIVILIANS 4 +#define TEAM4_CIVILIANS 8 + +// Defines for the playerclass +#define PC_UNDEFINED 0 + +#define PC_SCOUT 1 +#define PC_SNIPER 2 +#define PC_SOLDIER 3 +#define PC_DEMOMAN 4 +#define PC_MEDIC 5 +#define PC_HVYWEAP 6 +#define PC_PYRO 7 +#define PC_SPY 8 +#define PC_ENGINEER 9 + +// Insert new class definitions here + +// PC_RANDOM _MUST_ be the third last class +#define PC_RANDOM 10 // Random playerclass +#define PC_CIVILIAN 11 // Civilians are a special class. They cannot + // be chosen by players, only enforced by maps +#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops + // through the playerclass. + +#define SENTRY_COLOR 10 // will be in the PC_RANDOM slot for team colors +// These are just for the scanner +#define SCAN_SENTRY 13 +#define SCAN_GOALITEM 14 + +// Values returned by CheckArea +enum +{ + CAREA_CLEAR, + CAREA_BLOCKED, + CAREA_NOBUILD +}; + +/*==================================================*/ +/* Impulse Defines */ +/*==================================================*/ +// Alias check to see whether they already have the aliases +#define TF_ALIAS_CHECK 13 + +// CTF Support Impulses +#define HOOK_IMP1 22 +#define FLAG_INFO 23 +#define HOOK_IMP2 39 + +// Axe +#define AXE_IMP 40 + +// Camera Impulse +#define TF_CAM_TARGET 50 +#define TF_CAM_ZOOM 51 +#define TF_CAM_ANGLE 52 +#define TF_CAM_VEC 53 +#define TF_CAM_PROJECTILE 54 +#define TF_CAM_PROJECTILE_Z 55 +#define TF_CAM_REVANGLE 56 +#define TF_CAM_OFFSET 57 +#define TF_CAM_DROP 58 +#define TF_CAM_FADETOBLACK 59 +#define TF_CAM_FADEFROMBLACK 60 +#define TF_CAM_FADETOWHITE 61 +#define TF_CAM_FADEFROMWHITE 62 + +// Last Weapon impulse +#define TF_LAST_WEAPON 69 + +// Status Bar Resolution Settings. Same as CTF to maintain ease of use. +#define TF_STATUSBAR_RES_START 71 +#define TF_STATUSBAR_RES_END 81 + +// Clan Messages +#define TF_MESSAGE_1 82 +#define TF_MESSAGE_2 83 +#define TF_MESSAGE_3 84 +#define TF_MESSAGE_4 85 +#define TF_MESSAGE_5 86 + +#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu + +// Added to PC_??? to get impulse to use if this clashes with your +// own impulses, just change this value, not the PC_?? +#define TF_CHANGEPC 100 +// The next few impulses are all the class selections +//PC_SCOUT 101 +//PC_SNIPER 102 +//PC_SOLDIER 103 +//PC_DEMOMAN 104 +//PC_MEDIC 105 +//PC_HVYWEAP 106 +//PC_PYRO 107 +//PC_RANDOM 108 +//PC_CIVILIAN 109 // Cannot be used +//PC_SPY 110 +//PC_ENGINEER 111 + +// Help impulses +#define TF_DISPLAYLOCATION 118 +#define TF_STATUS_QUERY 119 + +#define TF_HELP_MAP 131 + +// Information impulses +#define TF_INVENTORY 135 +#define TF_SHOWTF 136 +#define TF_SHOWLEGALCLASSES 137 + +// Team Impulses +#define TF_TEAM_1 140 // Join Team 1 +#define TF_TEAM_2 141 // Join Team 2 +#define TF_TEAM_3 142 // Join Team 3 +#define TF_TEAM_4 143 // Join Team 4 +#define TF_TEAM_CLASSES 144 // Impulse to display team classes +#define TF_TEAM_SCORES 145 // Impulse to display team scores +#define TF_TEAM_LIST 146 // Impulse to display the players in each team. + +// Grenade Impulses +#define TF_GRENADE_1 150 // Prime grenade type 1 +#define TF_GRENADE_2 151 // Prime grenade type 2 +#define TF_GRENADE_T 152 // Throw primed grenade + +// Impulses for new items +//#define TF_SCAN 159 // Scanner Pre-Impulse +#define TF_AUTO_SCAN 159 // Scanner On/Off +#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies +#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies +//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) +#define TF_SCAN_SOUND 162 // Scanner sounds on/off +#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) +#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) +#define TF_DETPACK_5 165 // Detpack set to 5 seconds +#define TF_DETPACK_20 166 // Detpack set to 20 seconds +#define TF_DETPACK_50 167 // Detpack set to 50 seconds +#define TF_DETPACK 168 // Detpack Pre-Impulse +#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack +#define TF_PB_DETONATE 170 // Detonate Pipebombs + +// Special skill +#define TF_SPECIAL_SKILL 171 + +// Ammo Drop impulse +#define TF_DROP_AMMO 172 + +// Reload impulse +#define TF_RELOAD 173 + +// auto-zoom toggle +#define TF_AUTOZOOM 174 + +// drop/pass commands +#define TF_DROPKEY 175 + +// Select Medikit +#define TF_MEDIKIT 176 + +// Spy Impulses +#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color +#define TF_SPY_DIE 178 // Feign Death + +// Engineer Impulses +#define TF_ENGINEER_BUILD 179 +#define TF_ENGINEER_SANDBAG 180 + +// Medic +#define TF_MEDIC_HELPME 181 + +// Status bar +#define TF_STATUSBAR_ON 182 +#define TF_STATUSBAR_OFF 183 + +// Discard impulse +#define TF_DISCARD 184 + +// ID Player impulse +#define TF_ID 185 + +// Clan Battle impulses +#define TF_SHOWIDS 186 + +// More Engineer Impulses +#define TF_ENGINEER_DETDISP 187 +#define TF_ENGINEER_DETSENT 188 + +// Admin Commands +#define TF_ADMIN_DEAL_CYCLE 189 +#define TF_ADMIN_KICK 190 +#define TF_ADMIN_BAN 191 +#define TF_ADMIN_COUNTPLAYERS 192 +#define TF_ADMIN_CEASEFIRE 193 + +// Drop Goal Items +#define TF_DROPGOALITEMS 194 + +// More Admin Commands +#define TF_ADMIN_NEXT 195 + +// More Engineer Impulses +#define TF_ENGINEER_DETEXIT 196 +#define TF_ENGINEER_DETENTRANCE 197 + +// Yet MORE Admin Commands +#define TF_ADMIN_LISTIPS 198 + +// Silent Spy Feign +#define TF_SPY_SILENTDIE 199 + + +/*==================================================*/ +/*==================================================*/ +#define TEAM1_COLOR 150 +#define TEAM2_COLOR 250 +#define TEAM3_COLOR 45 +#define TEAM4_COLOR 100 + +/*==================================================*/ +/* Defines for the ENGINEER's Building ability */ +/*==================================================*/ +// Ammo costs +#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell +#define AMMO_COST_NAILS 1 +#define AMMO_COST_ROCKETS 2 +#define AMMO_COST_CELLS 2 + +// Building types +#define BUILD_DISPENSER 1 +#define BUILD_SENTRYGUN 2 +#define BUILD_MORTAR 3 +#define BUILD_TELEPORTER_ENTRANCE 4 +#define BUILD_TELEPORTER_EXIT 5 + +// Building metal costs +#define BUILD_COST_DISPENSER 100 // Metal needed to built +#define BUILD_COST_SENTRYGUN 130 +#define BUILD_COST_MORTAR 150 +#define BUILD_COST_TELEPORTER 125 + +#define BUILD_COST_SANDBAG 20 // Built with a separate alias + +// Building times +#define BUILD_TIME_DISPENSER 2 // seconds to build +#define BUILD_TIME_SENTRYGUN 5 +#define BUILD_TIME_MORTAR 5 +#define BUILD_TIME_TELEPORTER 4 + +// Building health levels +#define BUILD_HEALTH_DISPENSER 150 // Health of the building +#define BUILD_HEALTH_SENTRYGUN 150 +#define BUILD_HEALTH_MORTAR 200 +#define BUILD_HEALTH_TELEPORTER 80 + +// Dispenser's maximum carrying capability +#define BUILD_DISPENSER_MAX_SHELLS 400 +#define BUILD_DISPENSER_MAX_NAILS 600 +#define BUILD_DISPENSER_MAX_ROCKETS 300 +#define BUILD_DISPENSER_MAX_CELLS 400 +#define BUILD_DISPENSER_MAX_ARMOR 500 + +// Build state sent down to client +#define BS_BUILDING (1<<0) +#define BS_HAS_DISPENSER (1<<1) +#define BS_HAS_SENTRYGUN (1<<2) +#define BS_CANB_DISPENSER (1<<3) +#define BS_CANB_SENTRYGUN (1<<4) +/*==================================================*/ +/* Ammo quantities for dropping & dispenser use */ +/*==================================================*/ +#define DROP_SHELLS 20 +#define DROP_NAILS 20 +#define DROP_ROCKETS 10 +#define DROP_CELLS 10 +#define DROP_ARMOR 40 + +/*==================================================*/ +/* Team Defines */ +/*==================================================*/ +#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. + // A new global to hold new team colors is needed, and more flags + // in the spawnpoint spawnflags may need to be used. + // Basically, don't change this unless you know what you're doing :) + +/*==================================================*/ +/* New Weapon Defines */ +/*==================================================*/ +#define WEAP_HOOK 1 +#define WEAP_BIOWEAPON 2 +#define WEAP_MEDIKIT 4 +#define WEAP_SPANNER 8 +#define WEAP_AXE 16 +#define WEAP_SNIPER_RIFLE 32 +#define WEAP_AUTO_RIFLE 64 +#define WEAP_SHOTGUN 128 +#define WEAP_SUPER_SHOTGUN 256 +#define WEAP_NAILGUN 512 +#define WEAP_SUPER_NAILGUN 1024 +#define WEAP_GRENADE_LAUNCHER 2048 +#define WEAP_FLAMETHROWER 4096 +#define WEAP_ROCKET_LAUNCHER 8192 +#define WEAP_INCENDIARY 16384 +#define WEAP_ASSAULT_CANNON 32768 +#define WEAP_LIGHTNING 65536 +#define WEAP_DETPACK 131072 +#define WEAP_TRANQ 262144 +#define WEAP_LASER 524288 +// still room for 12 more weapons +// but we can remove some by giving the weapons +// a weapon mode (like the rifle) + +// HL-compatible weapon numbers +#define WEAPON_HOOK 1 +#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) +#define WEAPON_MEDIKIT (WEAPON_HOOK+2) +#define WEAPON_SPANNER (WEAPON_HOOK+3) +#define WEAPON_AXE (WEAPON_HOOK+4) +#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) +#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) +#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) +#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) +#define WEAPON_NAILGUN (WEAPON_HOOK+9) +#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) +#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) +#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) +#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) +#define WEAPON_INCENDIARY (WEAPON_HOOK+14) +#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) +#define WEAPON_LIGHTNING (WEAPON_HOOK+17) +#define WEAPON_DETPACK (WEAPON_HOOK+18) +#define WEAPON_TRANQ (WEAPON_HOOK+19) +#define WEAPON_LASER (WEAPON_HOOK+20) +#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) +#define WEAPON_KNIFE (WEAPON_HOOK+22) +#define WEAPON_BENCHMARK (WEAPON_HOOK+23) + +/*==================================================*/ +/* New Weapon Related Defines */ +/*==================================================*/ +// shots per reload +#define RE_SHOTGUN 8 +#define RE_SUPER_SHOTGUN 16 // 8 shots +#define RE_GRENADE_LAUNCHER 6 +#define RE_ROCKET_LAUNCHER 4 + +// reload times +#define RE_SHOTGUN_TIME 2 +#define RE_SUPER_SHOTGUN_TIME 3 +#define RE_GRENADE_LAUNCHER_TIME 4 +#define RE_ROCKET_LAUNCHER_TIME 5 + +// Maximum velocity you can move and fire the Sniper Rifle +#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 + +// Medikit +#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit +#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense + +// Spanner +#define WEAP_SPANNER_REPAIR 10 + +// Detpack +#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack +#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack +#define WEAP_DETPACK_SIZE 700 // Explosion Size +#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering +#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into + +// Tranquiliser Gun +#define TRANQ_TIME 15 + +// Grenades +#define GR_PRIMETIME 3 +#define GR_CALTROP_PRIME 0.5 +#define GR_TYPE_NONE 0 +#define GR_TYPE_NORMAL 1 +#define GR_TYPE_CONCUSSION 2 +#define GR_TYPE_NAIL 3 +#define GR_TYPE_MIRV 4 +#define GR_TYPE_NAPALM 5 +//#define GR_TYPE_FLARE 6 +#define GR_TYPE_GAS 7 +#define GR_TYPE_EMP 8 +#define GR_TYPE_CALTROP 9 +//#define GR_TYPE_FLASH 10 + +// Defines for WeaponMode +#define GL_NORMAL 0 +#define GL_PIPEBOMB 1 + +// Defines for OLD Concussion Grenade +#define GR_OLD_CONCUSS_TIME 5 +#define GR_OLD_CONCUSS_DEC 20 + +// Defines for Concussion Grenade +#define GR_CONCUSS_TIME 0.25 +#define GR_CONCUSS_DEC 10 +#define MEDIUM_PING 150 +#define HIGH_PING 200 + +// Defines for the Gas Grenade +#define GR_HALLU_TIME 0.3 +#define GR_OLD_HALLU_TIME 0.5 +#define GR_HALLU_DEC 2.5 + +// Defines for the BioInfection +#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players + +/*==================================================*/ +/* New Items */ +/*==================================================*/ +#define NIT_SCANNER 1 + +#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 +#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 + +/*==================================================*/ +/* New Item Flags */ +/*==================================================*/ +#define NIT_SCANNER_ENEMY 1 // Detect enemies +#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) +#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. + +/*==================================================*/ +/* New Item Related Defines */ +/*==================================================*/ +#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner + // is multiplied by this to get the scanrange. +#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan +#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected + // by scanners that only detect movement + +/*==================================================*/ +/* Variables used for New Weapons and Reloading */ +/*==================================================*/ +// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. +#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% +#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% +#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% +#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% +#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% + +/*==========================================================================*/ +/* TEAMFORTRESS CLASS DETAILS */ +/*==========================================================================*/ +// Class Details for SCOUT +#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. +#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level +#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed +#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed +#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class +#define PC_SCOUT_INITARMOR 25 // Armor level when respawned +#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption +#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned +#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class +#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned +#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN +#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry +#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry +#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry +#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry +#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned +#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned +#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned +#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned +#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned +#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has + +#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range +#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse +#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range +#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan + +// Class Details for SNIPER +#define PC_SNIPER_SKIN 5 +#define PC_SNIPER_MAXHEALTH 90 +#define PC_SNIPER_MAXSPEED 300 +#define PC_SNIPER_MAXSTRAFESPEED 300 +#define PC_SNIPER_MAXARMOR 50 +#define PC_SNIPER_INITARMOR 0 +#define PC_SNIPER_MAXARMORTYPE 0.3 +#define PC_SNIPER_INITARMORTYPE 0.3 +#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL +#define PC_SNIPER_INITARMORCLASS 0 +#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN +#define PC_SNIPER_MAXAMMO_SHOT 75 +#define PC_SNIPER_MAXAMMO_NAIL 100 +#define PC_SNIPER_MAXAMMO_CELL 50 +#define PC_SNIPER_MAXAMMO_ROCKET 25 +#define PC_SNIPER_INITAMMO_SHOT 60 +#define PC_SNIPER_INITAMMO_NAIL 50 +#define PC_SNIPER_INITAMMO_CELL 0 +#define PC_SNIPER_INITAMMO_ROCKET 0 +#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE +#define PC_SNIPER_GRENADE_INIT_1 2 +#define PC_SNIPER_GRENADE_INIT_2 0 +#define PC_SNIPER_TF_ITEMS 0 + +// Class Details for SOLDIER +#define PC_SOLDIER_SKIN 6 +#define PC_SOLDIER_MAXHEALTH 100 +#define PC_SOLDIER_MAXSPEED 240 +#define PC_SOLDIER_MAXSTRAFESPEED 240 +#define PC_SOLDIER_MAXARMOR 200 +#define PC_SOLDIER_INITARMOR 100 +#define PC_SOLDIER_MAXARMORTYPE 0.8 +#define PC_SOLDIER_INITARMORTYPE 0.8 +#define PC_SOLDIER_ARMORCLASSES 31 // ALL +#define PC_SOLDIER_INITARMORCLASS 0 +#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER +#define PC_SOLDIER_MAXAMMO_SHOT 100 +#define PC_SOLDIER_MAXAMMO_NAIL 100 +#define PC_SOLDIER_MAXAMMO_CELL 50 +#define PC_SOLDIER_MAXAMMO_ROCKET 50 +#define PC_SOLDIER_INITAMMO_SHOT 50 +#define PC_SOLDIER_INITAMMO_NAIL 0 +#define PC_SOLDIER_INITAMMO_CELL 0 +#define PC_SOLDIER_INITAMMO_ROCKET 10 +#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL +#define PC_SOLDIER_GRENADE_INIT_1 2 +#define PC_SOLDIER_GRENADE_INIT_2 1 +#define PC_SOLDIER_TF_ITEMS 0 + +#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active +#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active +#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active +#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's +#define MAX_CONCUSSION_GRENS 3 +#define MAX_CALTROP_CANS 3 + +// Class Details for DEMOLITION MAN +#define PC_DEMOMAN_SKIN 1 +#define PC_DEMOMAN_MAXHEALTH 90 +#define PC_DEMOMAN_MAXSPEED 280 +#define PC_DEMOMAN_MAXSTRAFESPEED 280 +#define PC_DEMOMAN_MAXARMOR 120 +#define PC_DEMOMAN_INITARMOR 50 +#define PC_DEMOMAN_MAXARMORTYPE 0.6 +#define PC_DEMOMAN_INITARMORTYPE 0.6 +#define PC_DEMOMAN_ARMORCLASSES 31 // ALL +#define PC_DEMOMAN_INITARMORCLASS 0 +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_MAXAMMO_SHOT 75 +#define PC_DEMOMAN_MAXAMMO_NAIL 50 +#define PC_DEMOMAN_MAXAMMO_CELL 50 +#define PC_DEMOMAN_MAXAMMO_ROCKET 50 +#define PC_DEMOMAN_MAXAMMO_DETPACK 1 +#define PC_DEMOMAN_INITAMMO_SHOT 30 +#define PC_DEMOMAN_INITAMMO_NAIL 0 +#define PC_DEMOMAN_INITAMMO_CELL 0 +#define PC_DEMOMAN_INITAMMO_ROCKET 20 +#define PC_DEMOMAN_INITAMMO_DETPACK 1 +#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_DEMOMAN_GRENADE_INIT_1 2 +#define PC_DEMOMAN_GRENADE_INIT_2 2 +#define PC_DEMOMAN_TF_ITEMS 0 + +// Class Details for COMBAT MEDIC +#define PC_MEDIC_SKIN 3 +#define PC_MEDIC_MAXHEALTH 90 +#define PC_MEDIC_MAXSPEED 320 +#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_MEDIC_MAXARMOR 100 +#define PC_MEDIC_INITARMOR 50 +#define PC_MEDIC_MAXARMORTYPE 0.6 +#define PC_MEDIC_INITARMORTYPE 0.3 +#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION +#define PC_MEDIC_INITARMORCLASS 0 +#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN +#define PC_MEDIC_MAXAMMO_SHOT 75 +#define PC_MEDIC_MAXAMMO_NAIL 150 +#define PC_MEDIC_MAXAMMO_CELL 50 +#define PC_MEDIC_MAXAMMO_ROCKET 25 +#define PC_MEDIC_MAXAMMO_MEDIKIT 100 +#define PC_MEDIC_INITAMMO_SHOT 50 +#define PC_MEDIC_INITAMMO_NAIL 50 +#define PC_MEDIC_INITAMMO_CELL 0 +#define PC_MEDIC_INITAMMO_ROCKET 0 +#define PC_MEDIC_INITAMMO_MEDIKIT 50 +#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION +#define PC_MEDIC_GRENADE_INIT_1 2 +#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_TF_ITEMS 0 +#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. +#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. + +// Class Details for HVYWEAP +#define PC_HVYWEAP_SKIN 2 +#define PC_HVYWEAP_MAXHEALTH 100 +#define PC_HVYWEAP_MAXSPEED 230 +#define PC_HVYWEAP_MAXSTRAFESPEED 230 +#define PC_HVYWEAP_MAXARMOR 300 +#define PC_HVYWEAP_INITARMOR 150 +#define PC_HVYWEAP_MAXARMORTYPE 0.8 +#define PC_HVYWEAP_INITARMORTYPE 0.8 +#define PC_HVYWEAP_ARMORCLASSES 31 // ALL +#define PC_HVYWEAP_INITARMORCLASS 0 +#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN +#define PC_HVYWEAP_MAXAMMO_SHOT 200 +#define PC_HVYWEAP_MAXAMMO_NAIL 200 +#define PC_HVYWEAP_MAXAMMO_CELL 50 +#define PC_HVYWEAP_MAXAMMO_ROCKET 25 +#define PC_HVYWEAP_INITAMMO_SHOT 200 +#define PC_HVYWEAP_INITAMMO_NAIL 0 +#define PC_HVYWEAP_INITAMMO_CELL 30 +#define PC_HVYWEAP_INITAMMO_ROCKET 0 +#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_HVYWEAP_GRENADE_INIT_1 2 +#define PC_HVYWEAP_GRENADE_INIT_2 1 +#define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon + + + +// Class Details for PYRO +#define PC_PYRO_SKIN 21 +#define PC_PYRO_MAXHEALTH 100 +#define PC_PYRO_MAXSPEED 300 +#define PC_PYRO_MAXSTRAFESPEED 300 +#define PC_PYRO_MAXARMOR 150 +#define PC_PYRO_INITARMOR 50 +#define PC_PYRO_MAXARMORTYPE 0.6 +#define PC_PYRO_INITARMORTYPE 0.6 +#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE +#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN +#define PC_PYRO_MAXAMMO_SHOT 40 +#define PC_PYRO_MAXAMMO_NAIL 50 +#define PC_PYRO_MAXAMMO_CELL 200 +#define PC_PYRO_MAXAMMO_ROCKET 20 +#define PC_PYRO_INITAMMO_SHOT 20 +#define PC_PYRO_INITAMMO_NAIL 0 +#define PC_PYRO_INITAMMO_CELL 120 +#define PC_PYRO_INITAMMO_ROCKET 5 +#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM +#define PC_PYRO_GRENADE_INIT_1 2 +#define PC_PYRO_GRENADE_INIT_2 4 +#define PC_PYRO_TF_ITEMS 0 +#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot + +// Class Details for SPY +#define PC_SPY_SKIN 22 +#define PC_SPY_MAXHEALTH 90 +#define PC_SPY_MAXSPEED 300 +#define PC_SPY_MAXSTRAFESPEED 300 +#define PC_SPY_MAXARMOR 100 +#define PC_SPY_INITARMOR 25 +#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_SPY_INITARMORCLASS 0 +#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN +#define PC_SPY_MAXAMMO_SHOT 40 +#define PC_SPY_MAXAMMO_NAIL 100 +#define PC_SPY_MAXAMMO_CELL 30 +#define PC_SPY_MAXAMMO_ROCKET 15 +#define PC_SPY_INITAMMO_SHOT 40 +#define PC_SPY_INITAMMO_NAIL 50 +#define PC_SPY_INITAMMO_CELL 10 +#define PC_SPY_INITAMMO_ROCKET 0 +#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS +#define PC_SPY_GRENADE_INIT_1 2 +#define PC_SPY_GRENADE_INIT_2 2 +#define PC_SPY_TF_ITEMS 0 +#define PC_SPY_CELL_REGEN_TIME 5 +#define PC_SPY_CELL_REGEN_AMOUNT 1 +#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible +#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover + +// Class Details for ENGINEER +#define PC_ENGINEER_SKIN 22 // Not used anymore +#define PC_ENGINEER_MAXHEALTH 80 +#define PC_ENGINEER_MAXSPEED 300 +#define PC_ENGINEER_MAXSTRAFESPEED 300 +#define PC_ENGINEER_MAXARMOR 50 +#define PC_ENGINEER_INITARMOR 25 +#define PC_ENGINEER_MAXARMORTYPE 0.6 +#define PC_ENGINEER_INITARMORTYPE 0.3 +#define PC_ENGINEER_ARMORCLASSES 31 // ALL +#define PC_ENGINEER_INITARMORCLASS 0 +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_MAXAMMO_SHOT 50 +#define PC_ENGINEER_MAXAMMO_NAIL 50 +#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal +#define PC_ENGINEER_MAXAMMO_ROCKET 30 +#define PC_ENGINEER_INITAMMO_SHOT 20 +#define PC_ENGINEER_INITAMMO_NAIL 25 +#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal +#define PC_ENGINEER_INITAMMO_ROCKET 0 +#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP +#define PC_ENGINEER_GRENADE_INIT_1 2 +#define PC_ENGINEER_GRENADE_INIT_2 2 +#define PC_ENGINEER_TF_ITEMS 0 + +// Class Details for CIVILIAN +#define PC_CIVILIAN_SKIN 22 +#define PC_CIVILIAN_MAXHEALTH 50 +#define PC_CIVILIAN_MAXSPEED 240 +#define PC_CIVILIAN_MAXSTRAFESPEED 240 +#define PC_CIVILIAN_MAXARMOR 0 +#define PC_CIVILIAN_INITARMOR 0 +#define PC_CIVILIAN_MAXARMORTYPE 0 +#define PC_CIVILIAN_INITARMORTYPE 0 +#define PC_CIVILIAN_ARMORCLASSES 0 +#define PC_CIVILIAN_INITARMORCLASS 0 +#define PC_CIVILIAN_WEAPONS WEAP_AXE +#define PC_CIVILIAN_MAXAMMO_SHOT 0 +#define PC_CIVILIAN_MAXAMMO_NAIL 0 +#define PC_CIVILIAN_MAXAMMO_CELL 0 +#define PC_CIVILIAN_MAXAMMO_ROCKET 0 +#define PC_CIVILIAN_INITAMMO_SHOT 0 +#define PC_CIVILIAN_INITAMMO_NAIL 0 +#define PC_CIVILIAN_INITAMMO_CELL 0 +#define PC_CIVILIAN_INITAMMO_ROCKET 0 +#define PC_CIVILIAN_GRENADE_TYPE_1 0 +#define PC_CIVILIAN_GRENADE_TYPE_2 0 +#define PC_CIVILIAN_GRENADE_INIT_1 0 +#define PC_CIVILIAN_GRENADE_INIT_2 0 +#define PC_CIVILIAN_TF_ITEMS 0 + + +/*==========================================================================*/ +/* TEAMFORTRESS GOALS */ +/*==========================================================================*/ +// For all these defines, see the tfortmap.txt that came with the zip +// for complete descriptions. +// Defines for Goal Activation types : goal_activation (in goals) +#define TFGA_TOUCH 1 // Activated when touched +#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion +#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met +#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner +#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning + +// Defines for Goal Effects types : goal_effect +#define TFGE_AP 1 // AP is affected. Default. +#define TFGE_AP_TEAM 2 // All of the AP's team. +#define TFGE_NOT_AP_TEAM 4 // All except AP's team. +#define TFGE_NOT_AP 8 // All except AP. +#define TFGE_WALL 16 // If set, walls stop the Radius effects +#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected +#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects + +// Defines for Goal Result types : goal_result +#define TFGR_SINGLE 1 // Goal can only be activated once +#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses +#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level +#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results +#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy +#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point +#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys + +// Defines for Goal Group Result types : goal_group +// None! +// But I'm leaving this variable in there, since it's fairly likely +// that some will show up sometime. + +// Defines for Goal Item types, : goal_activation (in items) +#define TFGI_GLOW 1 // Players carrying this GoalItem will glow +#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed +#define TFGI_DROP 4 // Players dying with this item will drop it +#define TFGI_RETURN_DROP 8 // Return if a player with it dies +#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation +#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE +#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details +#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped +#define TFGI_KEEP 256 // Players keep this item even when they die +#define TFGI_ITEMGLOWS 512 // Item glows when on the ground +#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed +#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning +#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players +#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc + +// Defines for methods of GoalItem returning +#define GI_RET_DROP_DEAD 0 // Dropped by a dead player +#define GI_RET_DROP_LIVING 1 // Dropped by a living player +#define GI_RET_GOAL 2 // Returned by a Goal +#define GI_RET_TIME 3 // Returned due to timeout + +// Defines for TeamSpawnpoints : goal_activation (in teamspawns) +#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times +#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times + +// Defines for TeamSpawnpoints : goal_effects (in teamspawns) +#define TFSP_REMOVESELF 1 // Remove itself after being spawned on + +// Defines for Goal States +#define TFGS_ACTIVE 1 +#define TFGS_INACTIVE 2 +#define TFGS_REMOVED 3 +#define TFGS_DELAYED 4 + +// Defines for GoalItem Removing from Player Methods +#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player +#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal +#define GI_DROP_PLAYERDROP 2 // Dropped by a player + +// Legal Playerclass Handling +#define TF_ILL_SCOUT 1 +#define TF_ILL_SNIPER 2 +#define TF_ILL_SOLDIER 4 +#define TF_ILL_DEMOMAN 8 +#define TF_ILL_MEDIC 16 +#define TF_ILL_HVYWEP 32 +#define TF_ILL_PYRO 64 +#define TF_ILL_RANDOMPC 128 +#define TF_ILL_SPY 256 +#define TF_ILL_ENGINEER 512 + +// Addition classes +#define CLASS_TFGOAL 128 +#define CLASS_TFGOAL_TIMER 129 +#define CLASS_TFGOAL_ITEM 130 +#define CLASS_TFSPAWN 131 + +/*==========================================================================*/ +/* Flamethrower */ +/*==========================================================================*/ +#define FLAME_PLYRMAXTIME 5.0 // lifetime in seconds of a flame on a player +#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) +#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade +#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player +#define FLAME_NUMLIGHTS 1 // maximum number of light flame +#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' +#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode +#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames +#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. +#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn +#define PER_FLAME_DAMAGE 2 // Damage taken per second per flame by burning players + +/*==================================================*/ +/* CTF Support defines */ +/*==================================================*/ +#define CTF_FLAG1 1 +#define CTF_FLAG2 2 +#define CTF_DROPOFF1 3 +#define CTF_DROPOFF2 4 +#define CTF_SCORE1 5 +#define CTF_SCORE2 6 + +//.float hook_out; + +/*==================================================*/ +/* Camera defines */ +/*==================================================*/ +/* +float live_camera; +.float camdist; +.vector camangle; +.entity camera_list; +*/ + +/*==================================================*/ +/* QuakeWorld defines */ +/*==================================================*/ +/* +float already_chosen_map; + +// grappling hook variables +.entity hook; +.float on_hook; +.float fire_held_down;// flag - TRUE if player is still holding down the + // fire button after throwing a hook. +*/ +/*==================================================*/ +/* Server Settings */ +/*==================================================*/ +// Admin modes +#define ADMIN_MODE_NONE 0 +#define ADMIN_MODE_DEAL 1 + +/*==================================================*/ +/* Death Message defines */ +/*==================================================*/ +#define DMSG_SHOTGUN 1 +#define DMSG_SSHOTGUN 2 +#define DMSG_NAILGUN 3 +#define DMSG_SNAILGUN 4 +#define DMSG_GRENADEL 5 +#define DMSG_ROCKETL 6 +#define DMSG_LIGHTNING 7 +#define DMSG_GREN_HAND 8 +#define DMSG_GREN_NAIL 9 +#define DMSG_GREN_MIRV 10 +#define DMSG_GREN_PIPE 11 +#define DMSG_DETPACK 12 +#define DMSG_BIOWEAPON 13 +#define DMSG_BIOWEAPON_ATT 14 +#define DMSG_FLAME 15 +#define DMSG_DETPACK_DIS 16 +#define DMSG_AXE 17 +#define DMSG_SNIPERRIFLE 18 +#define DMSG_AUTORIFLE 19 +#define DMSG_ASSAULTCANNON 20 +#define DMSG_HOOK 21 +#define DMSG_BACKSTAB 22 +#define DMSG_MEDIKIT 23 +#define DMSG_GREN_GAS 24 +#define DMSG_TRANQ 25 +#define DMSG_LASERBOLT 26 +#define DMSG_SENTRYGUN_BULLET 27 +#define DMSG_SNIPERLEGSHOT 28 +#define DMSG_SNIPERHEADSHOT 29 +#define DMSG_GREN_EMP 30 +#define DMSG_GREN_EMP_AMMO 31 +#define DMSG_SPANNER 32 +#define DMSG_INCENDIARY 33 +#define DMSG_SENTRYGUN_ROCKET 34 +#define DMSG_GREN_FLASH 35 +#define DMSG_TRIGGER 36 +#define DMSG_MIRROR 37 +#define DMSG_SENTRYDEATH 38 +#define DMSG_DISPENSERDEATH 39 +#define DMSG_GREN_AIRPIPE 40 +#define DMSG_CALTROP 41 + +/*==================================================*/ +// TOGGLEFLAGS +/*==================================================*/ +// Some of the toggleflags aren't used anymore, but the bits are still +// there to provide compatability with old maps +#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit +#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit +#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit +//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE +#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade +#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE +#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE +#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. +#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore +#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set + // In a map. Cannot be toggled by players. +#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only +#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off +//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags +#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps +#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation + +#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only + +/*======================*/ +// Menu stuff // +/*======================*/ + +#define MENU_DEFAULT 1 +#define MENU_TEAM 2 +#define MENU_CLASS 3 +#define MENU_MAPBRIEFING 4 +#define MENU_INTRO 5 +#define MENU_CLASSHELP 6 +#define MENU_CLASSHELP2 7 +#define MENU_REPEATHELP 8 + +#define MENU_SPECHELP 9 + + +#define MENU_SPY 12 +#define MENU_SPY_SKIN 13 +#define MENU_SPY_COLOR 14 +#define MENU_ENGINEER 15 +#define MENU_ENGINEER_FIX_DISPENSER 16 +#define MENU_ENGINEER_FIX_SENTRYGUN 17 +#define MENU_ENGINEER_FIX_MORTAR 18 +#define MENU_DISPENSER 19 +#define MENU_CLASS_CHANGE 20 +#define MENU_TEAM_CHANGE 21 + +#define MENU_REFRESH_RATE 25 + +#define MENU_VOICETWEAK 50 + +//============================ +// Timer Types +#define TF_TIMER_ANY 0 +#define TF_TIMER_CONCUSSION 1 +#define TF_TIMER_INFECTION 2 +#define TF_TIMER_HALLUCINATION 3 +#define TF_TIMER_TRANQUILISATION 4 +#define TF_TIMER_ROTHEALTH 5 +#define TF_TIMER_REGENERATION 6 +#define TF_TIMER_GRENPRIME 7 +#define TF_TIMER_CELLREGENERATION 8 +#define TF_TIMER_DETPACKSET 9 +#define TF_TIMER_DETPACKDISARM 10 +#define TF_TIMER_BUILD 11 +#define TF_TIMER_CHECKBUILDDISTANCE 12 +#define TF_TIMER_DISGUISE 13 +#define TF_TIMER_DISPENSERREFILL 14 + +// Non Player timers +#define TF_TIMER_RETURNITEM 100 +#define TF_TIMER_DELAYEDGOAL 101 +#define TF_TIMER_ENDROUND 102 + +//============================ +// Teamscore printing +#define TS_PRINT_SHORT 1 +#define TS_PRINT_LONG 2 +#define TS_PRINT_LONG_TO_ALL 3 + +#ifndef TF_DEFS_ONLY +typedef struct +{ + int topColor; + int bottomColor; +} team_color_t; +/*==================================================*/ +/* GLOBAL VARIABLES */ +/*==================================================*/ +// FortressMap stuff +extern float number_of_teams; // number of teams supported by the map +extern int illegalclasses[5]; // Illegal playerclasses for all teams +extern int civilianteams; // Bitfield holding Civilian teams +extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams + +extern team_color_t teamcolors[5][PC_LASTCLASS]; // Colors for each of the 4 teams +extern int teamscores[5]; // Goal Score of each team +extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers +extern int teamfrags[5]; // Total Frags for each team +extern int teamlives[5]; // Number of lives each team's players have +extern int teammaxplayers[5]; // Max number of players allowed in each team +extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set + // stores the damage ratio players take/give +extern int teamallies[5]; // Keeps track of which teams are allied +extern string_t team_names[5]; + +extern BOOL CTF_Map; +extern BOOL birthday; +extern BOOL christmas; + +extern float num_world_flames; + +// Clan Battle stuff +extern float clan_scores_dumped; +extern float cb_prematch_time; +extern float fOldPrematch; +extern float fOldCeaseFire; +extern float cb_ceasefire_time; +extern float last_id; +extern float spy_off; +extern float old_grens; +extern float flagem_checked; +extern float flNextEqualisationCalc; +extern BOOL cease_fire; +extern BOOL no_cease_fire_text; +extern BOOL initial_cease_fire; +extern BOOL last_cease_fire; +// Autokick stuff +extern float autokick_kills; + +extern float deathmsg; // Global, which is set before every T_Damage, to indicate + // the death message that should be used. + +extern char *sTeamSpawnNames[]; +extern char *sClassNames[]; +extern char *sNewClassModelFiles[]; +extern char *sOldClassModelFiles[]; +extern char *sClassModels[]; +extern char *sClassCfgs[]; +extern char *sGrenadeNames[]; +extern string_t team_menu_string; + +extern int toggleflags; // toggleable flags + +extern BOOL g_bFirstClient; + +extern float g_fNextPrematchAlert; + +typedef struct +{ + int ip; + edict_t *pEdict; +} ip_storage_t; + +extern ip_storage_t g_IpStorage[32]; + +class CGhost; +/*==========================================================================*/ +BOOL ClassIsRestricted(float tno, int pc); +char* GetTeamName(int tno); +int TeamFortress_GetNoPlayers(); +void DestroyBuilding(CBaseEntity *eng, char *bld); +void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); +float anglemod( float v ); + +// Team Funcs +BOOL TeamFortress_TeamIsCivilian(float tno); +void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); +BOOL TeamFortress_TeamPutPlayerInTeam(); +void TeamFortress_TeamSetColor(int tno); +void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); +int TeamFortress_TeamGetScoreFrags(int tno); +int TeamFortress_TeamGetNoPlayers(int tno); +float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); +BOOL IsSpawnPointValid( Vector &pos ); +BOOL TeamFortress_SortTeams( void ); +void DumpClanScores( void ); +void CalculateTeamEqualiser(); + +// mapscript funcs +void ParseTFServerSettings(); +void ParseTFMapSettings(); +CBaseEntity* Finditem(int ino); +CBaseEntity* Findgoal(int gno); +CBaseEntity* Findteamspawn(int gno); +void RemoveGoal(CBaseEntity *Goal); +void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); +void dremove( CBaseEntity *te ); +void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); +void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); +void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); +void tfgoalitem_checkgoalreturn(CBaseEntity *Item); +void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); +void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); +void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); +// hooks into the mapscript for all entities +BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); +BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); + +// prematch & ceasefire +void Display_Prematch(); +void Check_Ceasefire(); + +// admin +void KickPlayer( CBaseEntity *pTarget ); +void BanPlayer( CBaseEntity *pTarget ); +CGhost *FindGhost( int iGhostID ); +int GetBattleID( edict_t *pEntity ); + +extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) +extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. +extern cvar_t tfc_spam_limit; // at this many points, gag the spammer +extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; +extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; +extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; +extern cvar_t allow_spectators; + +/*==========================================================================*/ +class CTFFlame : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT FlameThink( void ); + static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); + void FlameDestroy( void ); + + float m_flNextDamageTime; +}; + +/*==========================================================================*/ +// MAPSCRIPT CLASSES +class CTFGoal : public CBaseAnimating +{ +public: + void Spawn( void ); + void StartGoal( void ); + void EXPORT PlaceGoal( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int Classify ( void ) { return CLASS_TFGOAL; } + + void SetObjectCollisionBox( void ); +}; + +class CTFGoalItem : public CTFGoal +{ +public: + void Spawn( void ); + void StartItem( void ); + void EXPORT PlaceItem( void ); + int Classify ( void ) { return CLASS_TFGOAL_ITEM; } + + float m_flDroppedAt; +}; + +class CTFTimerGoal : public CTFGoal +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL_TIMER; } +}; + +class CTFSpawn : public CBaseEntity +{ +public: + void Spawn( void ); + void Activate( void ); + int Classify ( void ) { return CLASS_TFSPAWN; } + BOOL CheckTeam( int iTeamNo ); + EHANDLE m_pTeamCheck; +}; + +class CTFDetect : public CBaseEntity +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL; } +}; + +class CTelefragDeath : public CBaseEntity +{ +public: + void Spawn( void ); + void EXPORT DeathTouch( CBaseEntity *pOther ); +}; + +class CTeamCheck : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + BOOL TeamMatches( int iTeam ); +}; +class CTeamSet : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; +#endif // TF_DEFS_ONLY +#endif // __TF_DEFS_H + + diff --git a/main/source/cl_dll/train.cpp b/main/source/cl_dll/train.cpp index fc80daa8..0d68134f 100644 --- a/main/source/cl_dll/train.cpp +++ b/main/source/cl_dll/train.cpp @@ -1,83 +1,83 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Train.cpp -// -// implementation of CHudAmmo class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "mod/AvHNetworkMessages.h" - -DECLARE_MESSAGE(m_Train, Train ) - - -int CHudTrain::Init(void) -{ - HOOK_MESSAGE( Train ); - - m_iPos = 0; - m_iFlags = 0; - //gHUD.AddHudElem(this); - - return 1; -}; - -int CHudTrain::VidInit(void) -{ - m_hSprite = 0; - - return 1; -}; - -int CHudTrain::Draw(float fTime) -{ - if ( !m_hSprite ) - m_hSprite = LoadSprite("sprites/%d_train.spr"); - - if (m_iPos) - { - int r, g, b, x, y; - - gHUD.GetPrimaryHudColor(r, g, b); - SPR_Set(m_hSprite, r, g, b ); - - // This should show up to the right and part way up the armor number - y = ScreenHeight() - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; - x = ScreenWidth()/3 + SPR_Width(m_hSprite,0)/4; - - SPR_DrawAdditive( m_iPos - 1, x, y, NULL); - - } - - return 1; -} - - -int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) -{ - int state; - NetMsg_Train( pbuf, iSize, state ); - - if (state) - m_iFlags |= HUD_ACTIVE; - else - m_iFlags &= ~HUD_ACTIVE; - - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Train.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "mod/AvHNetworkMessages.h" + +DECLARE_MESSAGE(m_Train, Train ) + + +int CHudTrain::Init(void) +{ + HOOK_MESSAGE( Train ); + + m_iPos = 0; + m_iFlags = 0; + //gHUD.AddHudElem(this); + + return 1; +}; + +int CHudTrain::VidInit(void) +{ + m_hSprite = 0; + + return 1; +}; + +int CHudTrain::Draw(float fTime) +{ + if ( !m_hSprite ) + m_hSprite = LoadSprite("sprites/%d_train.spr"); + + if (m_iPos) + { + int r, g, b, x, y; + + gHUD.GetPrimaryHudColor(r, g, b); + SPR_Set(m_hSprite, r, g, b ); + + // This should show up to the right and part way up the armor number + y = ScreenHeight() - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; + x = ScreenWidth()/3 + SPR_Width(m_hSprite,0)/4; + + SPR_DrawAdditive( m_iPos - 1, x, y, NULL); + + } + + return 1; +} + + +int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) +{ + int state; + NetMsg_Train( pbuf, iSize, state ); + + if (state) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} diff --git a/main/source/cl_dll/tri.cpp b/main/source/cl_dll/tri.cpp index 43cd7987..6571e32c 100644 --- a/main/source/cl_dll/tri.cpp +++ b/main/source/cl_dll/tri.cpp @@ -1,447 +1,447 @@ -// Triangle rendering, if any - -#include "hud.h" -#include "cl_util.h" -#include "cl_dll/in_defs.h" -#include "cl_dll/demo.h" - -// Triangle rendering apis are in gEngfuncs.pTriAPI - -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "common/triangleapi.h" -#include "engine/APIProxy.h" -#include "Exports.h" -#include -#include -#include "mod/AvHParticleSystemManager.h" - -#include "pm_shared/pm_defs.h" -#include "pm_shared/pm_shared.h" -#include "pm_shared/pm_movevars.h" -#include "mod/AvHEvents.h" -#include "mod/AvHScriptManager.h" -#include "mod/AvHClientVariables.h" - -#include "common/com_model.h" -#include "mod/CollisionUtil.h" - - -extern playermove_t *pmove; - -extern vec3_t v_origin; -extern vec3_t gLastCommanderViewpoint; - -// A fountain -/* -================= -Draw_Triangles - - Example routine. Draws a sprite offset from the player origin. - ================= -*/ -//void Draw_Triangles( void ) -//{ -// cl_entity_t *player; -// vec3_t org; -// -// // Load it up with some bogus data -// player = gEngfuncs.GetLocalPlayer(); -// if ( !player ) -// return; -// -// org = player->origin; -// -// org.x += 0; -// org.y += 0; -// -// pVector theView(player->angles.x, player->angles.y, player->angles.z); -// theView.normalize(); -// pVector theUp(0.0f, 0.0f, 1.0f); -// pVector theBase(org.x, org.y, org.z); -// -// // Do what the particles do. -// ComputeParticles(theBase); -// -// // Create a triangle, sigh -// //gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); -// gEngfuncs.pTriAPI->CullFace( TRI_NONE ); -// -// gEngfuncs.pTriAPI->Brightness( 1 ); -// -// if (gHUD.m_hsprCursor == 0) -// { -// char sz[256]; -// //sprintf( sz, "sprites/cursor.spr" ); -// //sprintf( sz, "sprites/myrain.spr" ); -// sprintf( sz, "sprites/haze2.spr" ); -// gHUD.m_hsprCursor = SPR_Load( sz ); -// } -// -// if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) -// { -// return; -// } -// -// gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); -// gEngfuncs.pTriAPI->Color4f(1.0f, 1.0f, 1.0f, .5f); -// gEngfuncs.pTriAPI->CullFace( TRI_NONE ); -// DrawGroupTriSplat(theView, theUp, 70, true, true, true); -// -// //// Create a triangle, sigh -// //gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); -// // -// //gEngfuncs.pTriAPI->Begin( TRI_QUADS ); -// //// Overload p->color with index into tracer palette, p->packedColor with brightness -// //gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); -// //// UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) -// //gEngfuncs.pTriAPI->Brightness( 1 ); -// //gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); -// //gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); -// // -// //gEngfuncs.pTriAPI->Brightness( 1 ); -// //gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); -// //gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); -// // -// //gEngfuncs.pTriAPI->Brightness( 1 ); -// //gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); -// //gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); -// // -// //gEngfuncs.pTriAPI->Brightness( 1 ); -// //gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); -// //gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); -// -// -// gEngfuncs.pTriAPI->End(); -// gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); -//} - -//#endif - -void AngleMatrix (const vec3_t angles, float (*matrix)[4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[2] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[1] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[0] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - // matrix = (Z * Y) * X - matrix[0][0] = cp*cy; - matrix[1][0] = cp*sy; - matrix[2][0] = -sp; - matrix[0][1] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[2][1] = sr*cp; - matrix[0][2] = (cr*sp*cy+-sr*-sy); - matrix[1][2] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} - -void VectorRotate (const vec3_t in1, const float in2[3][4], vec3_t& out) -{ - out[0] = DotProduct(in1, in2[0]); - out[1] = DotProduct(in1, in2[1]); - out[2] = DotProduct(in1, in2[2]); -} - -/* -================= -HUD_DrawNormalTriangles - - Non-transparent triangles-- add them here - ================= -*/ -void CL_DLLEXPORT HUD_DrawNormalTriangles( void ) -{ -// RecClDrawNormalTriangles(); - - // pVector theView; - // cl_entity_t* thePlayer; - // - // thePlayer = gEngfuncs.GetLocalPlayer(); - // if(thePlayer) - // { - // pVector theView(thePlayer->angles.x, thePlayer->angles.y, thePlayer->angles.z); - // theView.normalize(); - // - // //AvHParticleSystemManager::Instance()->Draw(theView); - // static int theAngle = 0; - // //static HSPRITE theSprite = 0; - // DrawCircleOnGroundAtPoint(thePlayer->origin, 6, theAngle++, 100, .5f, .5f, 1.0f, .5f); - // } - - gHUD.PreRenderFrame(); - - //gHUD.m_Spectator.DrawOverview(); - -#if defined( TEST_IT ) - // Draw_Triangles(); -#endif -} - - -void DrawHitBox(const OBBox& inBox) -{ - - HSPRITE sprite = SPR_Load("sprites/white.spr"); - - vec3_t theBoxPoint[8]; - - for (int i = 0; i < 8; ++i) - { - - vec3_t xAmount; - vec3_t yAmount; - vec3_t zAmount; - - if (i & 1) - { - VectorScale(inBox.mAxis[0], inBox.mExtents[0], xAmount); - } - else - { - VectorScale(inBox.mAxis[0], -inBox.mExtents[0], xAmount); - } - - if (i & 2) - { - VectorScale(inBox.mAxis[1], inBox.mExtents[1], yAmount); - } - else - { - VectorScale(inBox.mAxis[1], -inBox.mExtents[1], yAmount); - } - - if (i & 4) - { - VectorScale(inBox.mAxis[2], inBox.mExtents[2], zAmount); - } - else - { - VectorScale(inBox.mAxis[2], -inBox.mExtents[2], zAmount); - } - - VectorAdd(inBox.mOrigin, xAmount, theBoxPoint[i]); - VectorAdd(theBoxPoint[i], yAmount, theBoxPoint[i]); - VectorAdd(theBoxPoint[i], zAmount, theBoxPoint[i]); - - } - - struct model_s* spritePtr = (struct model_s*)(gEngfuncs.GetSpritePointer(sprite)); - gEngfuncs.pTriAPI->SpriteTexture(spritePtr, 0); - - gEngfuncs.pTriAPI->Begin(TRI_LINES); - - gEngfuncs.pTriAPI->Color4f(1, 1, 1, 1); - - // Bottom. - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[0]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[1]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[1]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[3]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[3]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[2]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[2]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[0]); - - // Top. - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[4]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[6]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[6]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[7]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[7]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[5]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[5]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[4]); - - // Sides. - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[0]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[4]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[2]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[6]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[3]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[7]); - - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[1]); - gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[5]); - - gEngfuncs.pTriAPI->End(); - -} - - -void DrawHitBoxes() -{ - - extern int cam_thirdperson; - - for (int j = 1; j < 512; ++j) - { - - cl_entity_t* entity = gEngfuncs.GetEntityByIndex(j); - - if (entity == gEngfuncs.GetLocalPlayer() && !cam_thirdperson) - { - continue; - } - - if (entity->curstate.effects & EF_NODRAW) - { - continue; - } - - if (entity != NULL && entity->model != NULL && entity->model->type == mod_studio) - { - - int theEntityIndex = j; - - OBBox theBox[256]; - int theNumBoxes; - - NS_GetHitBoxesForEntity(theEntityIndex, 256, theBox, theNumBoxes, gEngfuncs.GetClientTime()); - - for (int i = 0; i < theNumBoxes; ++i) - { - DrawHitBox(theBox[i]); - } - - } - - } - -} - - - -/* - - ================= - HUD_DrawTransparentTriangles - - Render any triangles with transparent rendermode needs here - ================= -*/ -void CL_DLLEXPORT HUD_DrawTransparentTriangles( void ) -{ -// RecClDrawTransparentTriangles(); - - cl_entity_t* thePlayer; - - if (gHUD.GetParticlesVisible() && gHUD.GetSafeForSpriteDrawing()) - { - // get local player - thePlayer = gEngfuncs.GetLocalPlayer(); - if(thePlayer) - { - //pVector theView(thePlayer->angles.x, thePlayer->angles.y, thePlayer->angles.z); - //pVector theView(viewangles[0], viewangles[1], viewangles[2]); - //theView.normalize(); - - vec3_t angles, up, right, forward; - // gEngfuncs.pfnAngleVectors(thePlayer->angles, forward, right, up); - - // This view doesn't take pitch into account. Pitch is stored in x. While yaw goes from -180 to 180, - // pitch goes from -10 (looking up) to 10 (looking down). Alter forward[YAW} (forward[0]) so - // the particles can billboard themselves correctly. - - // float thePitch = thePlayer->angles[PITCH]; - // float theNormAngle = thePitch/-10.0f; - // int theAngle = theNormAngle*90; - // //float theYaw = thePlayer->angles[YAW]; - // - // vec3_t theRotationAngles; - // theRotationAngles[0] = theAngle; - // theRotationAngles[1] = 0; - // theRotationAngles[2] = 0; - // - // float theMatrix[3][4]; - // AngleMatrix(theRotationAngles, theMatrix); - // - // vec3_t theOut; - // VectorRotate(forward, theMatrix, theOut); - // pVector theRealView(theOut[0], theOut[1], theOut[2]); - - pVector theRealView; - gEngfuncs.pfnAngleVectors(v_angles, forward, right, up); - - theRealView.x = forward[0]; - theRealView.y = forward[1]; - theRealView.z = forward[2]; - - // Disable fog - float theFogColor[3]; - theFogColor[0] = theFogColor[1] = theFogColor[2] = 0.0f; - gEngfuncs.pTriAPI->Fog(theFogColor, 0, 0, 0); - - // Draw particles via tri API, without z-buffering, unless we're debugging - //if(cl_particleinfo->value == 0) - //{ - AvHParticleSystemManager::Instance()->Draw(theRealView); - //} - - //DrawOrdersForPlayers(gHUD.GetDrawPlayerOrders()); - - //DrawRangeIndicator(); - - //DrawBlips(theRealView); - - //DrawMarineLights(theRealView); - - AvHScriptManager::Instance()->DrawTransparent(); - - //DrawDebugEffects(); - - //static int theAngle = 0; - //DrawCircleOnGroundAtPoint(thePlayer->origin, 6, theAngle++, 100, 1.0f, 1.0f, 1.0f, .2f); - } - - // Draw the hitboxes for all of the objects. - - // Assumes that the only time players don't have view models is when they are commanding, gestating, cocooned - // or when they aren't playing. See the end of StudioModelRenderer::StudioDrawModel(). - //if((gHUD.GetRole() == ROLE_COMMANDER) || (gHUD.GetRole() == ROLE_GESTATING) || (gHUD.GetRole() == ROLE_COCOONED) || (gHUD.GetPlayMode() != PLAYMODE_PLAYING)) - cl_entity_t* theViewEntity = gEngfuncs.GetViewModel(); - if(!theViewEntity || !theViewEntity->model) - { - // This should always be rendered with the commander viewpoint -// vec3_t theCurrentOrigin = v_origin; -// -// if(gHUD.GetInTopDownMode()) -// { -// v_origin = gLastCommanderViewpoint; -// } - - gHUD.RenderNoZBuffering(); - -// if(gHUD.GetInTopDownMode()) -// { -// v_origin = theCurrentOrigin; -// } - } - - gHUD.PostRenderFrame(); - } -} +// Triangle rendering, if any + +#include "hud.h" +#include "cl_util.h" +#include "cl_dll/in_defs.h" +#include "cl_dll/demo.h" + +// Triangle rendering apis are in gEngfuncs.pTriAPI + +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "common/triangleapi.h" +#include "engine/APIProxy.h" +#include "Exports.h" +#include +#include +#include "mod/AvHParticleSystemManager.h" + +#include "pm_shared/pm_defs.h" +#include "pm_shared/pm_shared.h" +#include "pm_shared/pm_movevars.h" +#include "mod/AvHEvents.h" +#include "mod/AvHScriptManager.h" +#include "mod/AvHClientVariables.h" + +#include "common/com_model.h" +#include "mod/CollisionUtil.h" + + +extern playermove_t *pmove; + +extern vec3_t v_origin; +extern vec3_t gLastCommanderViewpoint; + +// A fountain +/* +================= +Draw_Triangles + + Example routine. Draws a sprite offset from the player origin. + ================= +*/ +//void Draw_Triangles( void ) +//{ +// cl_entity_t *player; +// vec3_t org; +// +// // Load it up with some bogus data +// player = gEngfuncs.GetLocalPlayer(); +// if ( !player ) +// return; +// +// org = player->origin; +// +// org.x += 0; +// org.y += 0; +// +// pVector theView(player->angles.x, player->angles.y, player->angles.z); +// theView.normalize(); +// pVector theUp(0.0f, 0.0f, 1.0f); +// pVector theBase(org.x, org.y, org.z); +// +// // Do what the particles do. +// ComputeParticles(theBase); +// +// // Create a triangle, sigh +// //gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +// gEngfuncs.pTriAPI->CullFace( TRI_NONE ); +// +// gEngfuncs.pTriAPI->Brightness( 1 ); +// +// if (gHUD.m_hsprCursor == 0) +// { +// char sz[256]; +// //sprintf( sz, "sprites/cursor.spr" ); +// //sprintf( sz, "sprites/myrain.spr" ); +// sprintf( sz, "sprites/haze2.spr" ); +// gHUD.m_hsprCursor = SPR_Load( sz ); +// } +// +// if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) +// { +// return; +// } +// +// gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); +// gEngfuncs.pTriAPI->Color4f(1.0f, 1.0f, 1.0f, .5f); +// gEngfuncs.pTriAPI->CullFace( TRI_NONE ); +// DrawGroupTriSplat(theView, theUp, 70, true, true, true); +// +// //// Create a triangle, sigh +// //gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +// // +// //gEngfuncs.pTriAPI->Begin( TRI_QUADS ); +// //// Overload p->color with index into tracer palette, p->packedColor with brightness +// //gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); +// //// UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) +// //gEngfuncs.pTriAPI->Brightness( 1 ); +// //gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); +// //gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); +// // +// //gEngfuncs.pTriAPI->Brightness( 1 ); +// //gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); +// //gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); +// // +// //gEngfuncs.pTriAPI->Brightness( 1 ); +// //gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); +// //gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); +// // +// //gEngfuncs.pTriAPI->Brightness( 1 ); +// //gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); +// //gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); +// +// +// gEngfuncs.pTriAPI->End(); +// gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +//} + +//#endif + +void AngleMatrix (const vec3_t angles, float (*matrix)[4] ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[2] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[1] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[0] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + // matrix = (Z * Y) * X + matrix[0][0] = cp*cy; + matrix[1][0] = cp*sy; + matrix[2][0] = -sp; + matrix[0][1] = sr*sp*cy+cr*-sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[2][1] = sr*cp; + matrix[0][2] = (cr*sp*cy+-sr*-sy); + matrix[1][2] = (cr*sp*sy+-sr*cy); + matrix[2][2] = cr*cp; + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; +} + +void VectorRotate (const vec3_t in1, const float in2[3][4], vec3_t& out) +{ + out[0] = DotProduct(in1, in2[0]); + out[1] = DotProduct(in1, in2[1]); + out[2] = DotProduct(in1, in2[2]); +} + +/* +================= +HUD_DrawNormalTriangles + + Non-transparent triangles-- add them here + ================= +*/ +void CL_DLLEXPORT HUD_DrawNormalTriangles( void ) +{ +// RecClDrawNormalTriangles(); + + // pVector theView; + // cl_entity_t* thePlayer; + // + // thePlayer = gEngfuncs.GetLocalPlayer(); + // if(thePlayer) + // { + // pVector theView(thePlayer->angles.x, thePlayer->angles.y, thePlayer->angles.z); + // theView.normalize(); + // + // //AvHParticleSystemManager::Instance()->Draw(theView); + // static int theAngle = 0; + // //static HSPRITE theSprite = 0; + // DrawCircleOnGroundAtPoint(thePlayer->origin, 6, theAngle++, 100, .5f, .5f, 1.0f, .5f); + // } + + gHUD.PreRenderFrame(); + + //gHUD.m_Spectator.DrawOverview(); + +#if defined( TEST_IT ) + // Draw_Triangles(); +#endif +} + + +void DrawHitBox(const OBBox& inBox) +{ + + HSPRITE sprite = SPR_Load("sprites/white.spr"); + + vec3_t theBoxPoint[8]; + + for (int i = 0; i < 8; ++i) + { + + vec3_t xAmount; + vec3_t yAmount; + vec3_t zAmount; + + if (i & 1) + { + VectorScale(inBox.mAxis[0], inBox.mExtents[0], xAmount); + } + else + { + VectorScale(inBox.mAxis[0], -inBox.mExtents[0], xAmount); + } + + if (i & 2) + { + VectorScale(inBox.mAxis[1], inBox.mExtents[1], yAmount); + } + else + { + VectorScale(inBox.mAxis[1], -inBox.mExtents[1], yAmount); + } + + if (i & 4) + { + VectorScale(inBox.mAxis[2], inBox.mExtents[2], zAmount); + } + else + { + VectorScale(inBox.mAxis[2], -inBox.mExtents[2], zAmount); + } + + VectorAdd(inBox.mOrigin, xAmount, theBoxPoint[i]); + VectorAdd(theBoxPoint[i], yAmount, theBoxPoint[i]); + VectorAdd(theBoxPoint[i], zAmount, theBoxPoint[i]); + + } + + struct model_s* spritePtr = (struct model_s*)(gEngfuncs.GetSpritePointer(sprite)); + gEngfuncs.pTriAPI->SpriteTexture(spritePtr, 0); + + gEngfuncs.pTriAPI->Begin(TRI_LINES); + + gEngfuncs.pTriAPI->Color4f(1, 1, 1, 1); + + // Bottom. + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[0]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[1]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[1]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[3]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[3]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[2]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[2]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[0]); + + // Top. + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[4]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[6]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[6]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[7]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[7]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[5]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[5]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[4]); + + // Sides. + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[0]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[4]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[2]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[6]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[3]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[7]); + + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[1]); + gEngfuncs.pTriAPI->Vertex3fv(theBoxPoint[5]); + + gEngfuncs.pTriAPI->End(); + +} + + +void DrawHitBoxes() +{ + + extern int cam_thirdperson; + + for (int j = 1; j < 512; ++j) + { + + cl_entity_t* entity = gEngfuncs.GetEntityByIndex(j); + + if (entity == gEngfuncs.GetLocalPlayer() && !cam_thirdperson) + { + continue; + } + + if (entity->curstate.effects & EF_NODRAW) + { + continue; + } + + if (entity != NULL && entity->model != NULL && entity->model->type == mod_studio) + { + + int theEntityIndex = j; + + OBBox theBox[256]; + int theNumBoxes; + + NS_GetHitBoxesForEntity(theEntityIndex, 256, theBox, theNumBoxes, gEngfuncs.GetClientTime()); + + for (int i = 0; i < theNumBoxes; ++i) + { + DrawHitBox(theBox[i]); + } + + } + + } + +} + + + +/* + + ================= + HUD_DrawTransparentTriangles + + Render any triangles with transparent rendermode needs here + ================= +*/ +void CL_DLLEXPORT HUD_DrawTransparentTriangles( void ) +{ +// RecClDrawTransparentTriangles(); + + cl_entity_t* thePlayer; + + if (gHUD.GetParticlesVisible() && gHUD.GetSafeForSpriteDrawing()) + { + // get local player + thePlayer = gEngfuncs.GetLocalPlayer(); + if(thePlayer) + { + //pVector theView(thePlayer->angles.x, thePlayer->angles.y, thePlayer->angles.z); + //pVector theView(viewangles[0], viewangles[1], viewangles[2]); + //theView.normalize(); + + vec3_t angles, up, right, forward; + // gEngfuncs.pfnAngleVectors(thePlayer->angles, forward, right, up); + + // This view doesn't take pitch into account. Pitch is stored in x. While yaw goes from -180 to 180, + // pitch goes from -10 (looking up) to 10 (looking down). Alter forward[YAW} (forward[0]) so + // the particles can billboard themselves correctly. + + // float thePitch = thePlayer->angles[PITCH]; + // float theNormAngle = thePitch/-10.0f; + // int theAngle = theNormAngle*90; + // //float theYaw = thePlayer->angles[YAW]; + // + // vec3_t theRotationAngles; + // theRotationAngles[0] = theAngle; + // theRotationAngles[1] = 0; + // theRotationAngles[2] = 0; + // + // float theMatrix[3][4]; + // AngleMatrix(theRotationAngles, theMatrix); + // + // vec3_t theOut; + // VectorRotate(forward, theMatrix, theOut); + // pVector theRealView(theOut[0], theOut[1], theOut[2]); + + pVector theRealView; + gEngfuncs.pfnAngleVectors(v_angles, forward, right, up); + + theRealView.x = forward[0]; + theRealView.y = forward[1]; + theRealView.z = forward[2]; + + // Disable fog + float theFogColor[3]; + theFogColor[0] = theFogColor[1] = theFogColor[2] = 0.0f; + gEngfuncs.pTriAPI->Fog(theFogColor, 0, 0, 0); + + // Draw particles via tri API, without z-buffering, unless we're debugging + //if(cl_particleinfo->value == 0) + //{ + AvHParticleSystemManager::Instance()->Draw(theRealView); + //} + + //DrawOrdersForPlayers(gHUD.GetDrawPlayerOrders()); + + //DrawRangeIndicator(); + + //DrawBlips(theRealView); + + //DrawMarineLights(theRealView); + + AvHScriptManager::Instance()->DrawTransparent(); + + //DrawDebugEffects(); + + //static int theAngle = 0; + //DrawCircleOnGroundAtPoint(thePlayer->origin, 6, theAngle++, 100, 1.0f, 1.0f, 1.0f, .2f); + } + + // Draw the hitboxes for all of the objects. + + // Assumes that the only time players don't have view models is when they are commanding, gestating, cocooned + // or when they aren't playing. See the end of StudioModelRenderer::StudioDrawModel(). + //if((gHUD.GetRole() == ROLE_COMMANDER) || (gHUD.GetRole() == ROLE_GESTATING) || (gHUD.GetRole() == ROLE_COCOONED) || (gHUD.GetPlayMode() != PLAYMODE_PLAYING)) + cl_entity_t* theViewEntity = gEngfuncs.GetViewModel(); + if(!theViewEntity || !theViewEntity->model) + { + // This should always be rendered with the commander viewpoint +// vec3_t theCurrentOrigin = v_origin; +// +// if(gHUD.GetInTopDownMode()) +// { +// v_origin = gLastCommanderViewpoint; +// } + + gHUD.RenderNoZBuffering(); + +// if(gHUD.GetInTopDownMode()) +// { +// v_origin = theCurrentOrigin; +// } + } + + gHUD.PostRenderFrame(); + } +} diff --git a/main/source/cl_dll/util.cpp b/main/source/cl_dll/util.cpp index de340e9f..80b9c7b5 100644 --- a/main/source/cl_dll/util.cpp +++ b/main/source/cl_dll/util.cpp @@ -1,314 +1,314 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// util.cpp -// -// implementation of class-less helper functions -// - -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -#include "hud.h" -#include "cl_util.h" -#include "common/cl_entity.h" -#include -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -#include "pm_shared/pm_defs.h" -#include "pm_shared/pm_shared.h" -#include "pm_shared/pm_movevars.h" -extern playermove_t *pmove; - -extern float HUD_GetFOV( void ); -vec3_t vec3_origin( 0, 0, 0 ); -extern vec3_t v_angles; -//double sqrt(double x); -// -//float Length(const float *v) -//{ -// int i; -// float length; -// -// length = 0; -// for (i=0 ; i< 3 ; i++) -// length += v[i]*v[i]; -// length = sqrt (length); // FIXME -// -// return length; -//} -// -//void VectorAngles( const float *forward, float *angles ) -//{ -// float tmp, yaw, pitch; -// -// if (forward[1] == 0 && forward[0] == 0) -// { -// yaw = 0; -// if (forward[2] > 0) -// pitch = 90; -// else -// pitch = 270; -// } -// else -// { -// yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); -// if (yaw < 0) -// yaw += 360; -// -// tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); -// pitch = (atan2(forward[2], tmp) * 180 / M_PI); -// if (pitch < 0) -// pitch += 360; -// } -// -// angles[0] = pitch; -// angles[1] = yaw; -// angles[2] = 0; -//} -// -//float VectorNormalize (float *v) -//{ -// float length, ilength; -// -// length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; -// length = sqrt (length); // FIXME -// -// if (length) -// { -// ilength = 1/length; -// v[0] *= ilength; -// v[1] *= ilength; -// v[2] *= ilength; -// } -// -// return length; -// -//} -// -//void VectorInverse ( float *v ) -//{ -// v[0] = -v[0]; -// v[1] = -v[1]; -// v[2] = -v[2]; -//} -// -//void VectorScale (const float *in, float scale, float *out) -//{ -// out[0] = in[0]*scale; -// out[1] = in[1]*scale; -// out[2] = in[2]*scale; -//} -// -//void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) -//{ -// vecc[0] = veca[0] + scale*vecb[0]; -// vecc[1] = veca[1] + scale*vecb[1]; -// vecc[2] = veca[2] + scale*vecb[2]; -//} - -int ScreenHeight() -{ - // CGC: Replace code when ready to fix overview map - //int theViewport[4]; - //gHUD.GetViewport(theViewport); - //return theViewport[3]; - return gHUD.m_scrinfo.iHeight; -} - -// ScreenWidth returns the width of the screen, in pixels -//#define ScreenWidth ( int theViewport[4]; gHUD.GetViewport(theViewport); return theViewport[2]; ) -int ScreenWidth() -{ - //int theViewport[4]; - //gHUD.GetViewport(theViewport); - //return theViewport[2]; - return gHUD.m_scrinfo.iWidth; -} - -/* -HSPRITE SPR_Load(const char* inSpriteName) -{ - HSPRITE theSpriteHandle = gEngfuncs.pfnSPR_Load(inSpriteName); - - // Check for "Can't allocate 128 HUD sprites" crash - ASSERT(theSpriteHandle < 128); - - return theSpriteHandle; -}*/ - -//----------------------------------------------------------------------------- -// Purpose: -// Given a field of view and mouse/screen positions as well as the current -// render origin and angles, returns a unit vector through the mouse position -// that can be used to trace into the world under the mouse click pixel. -// Input : fov - -// mousex - -// mousey - -// screenwidth - -// screenheight - -// vecRenderAngles - -// c_x - -// vpn - -// vup - -// 360.0 - -//----------------------------------------------------------------------------- -void CreatePickingRay( int mousex, int mousey, Vector& outVecPickingRay ) -{ - float dx, dy; - float c_x, c_y; - float dist; - Vector vpn, vup, vright; - -// char gDebugMessage[256]; - - float fovDegrees = gHUD.m_iFOV; - - //cl_entity_s* theLocalEntity = gEngfuncs.GetLocalPlayer(); - //Vector vecRenderOrigin = theLocalEntity->origin; - //Vector vecRenderAngles = theLocalEntity->angles; - //Vector vecRenderAngles; - vec3_t vecRenderAngles; - //gEngfuncs.GetViewAngles((float*)vecRenderAngles); - VectorCopy(v_angles, vecRenderAngles); - - //vec3_t theForward, theRight, theUp; - //AngleVectors(v_angles, theForward, theRight, theUp); - - //ASSERT(v_angles.x == vecRenderAngles.x); - //ASSERT(v_angles.y == vecRenderAngles.y); - //ASSERT(v_angles.z == vecRenderAngles.z); - - c_x = ScreenWidth() / 2; - c_y = ScreenHeight() / 2; - - - dx = (float)mousex - c_x; - // Invert Y - dy = c_y - (float)mousey; - -// sprintf(gDebugMessage, "inMouseX/Y: %d/%d, dx/dy = %d/%d", (int)mousex, (int)mousey, (int)dx, (int)dy); -// CenterPrint(gDebugMessage); - - // Convert view plane distance - dist = c_x / tan( M_PI * fovDegrees / 360.0 ); - - - // Decompose view angles - AngleVectors( vecRenderAngles, vpn, vright, vup ); - - - // Offset forward by view plane distance, and then by pixel offsets - outVecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy ); - - //sprintf(gDebugMessage, "outVecPickingRay: %.0f, %.0f, %.0f", outVecPickingRay.x, outVecPickingRay.y, outVecPickingRay.z); - //CenterPrint(gDebugMessage); - - // Convert to unit vector - VectorNormalize( outVecPickingRay ); -} - -void FillRGBAClipped(vgui::Panel* inPanel, int inStartX, int inStartY, int inWidth, int inHeight, int r, int g, int b, int a) -{ - int thePanelXPos, thePanelYPos; - inPanel->getPos(thePanelXPos, thePanelYPos); - - int thePanelWidth, thePanelHeight; - inPanel->getSize(thePanelWidth, thePanelHeight); - - // Clip starting point - inStartX = min(max(0, inStartX), thePanelWidth-1); - inStartY = min(max(0, inStartY), thePanelHeight-1); - - // Clip width if it goes too far - ASSERT(inWidth >= 0); - ASSERT(inHeight >= 0); - - if(inStartX + inWidth >= thePanelWidth) - { - inWidth = max(0, thePanelWidth - inStartX); - } - if(inStartY + inHeight >= thePanelHeight) - { - inHeight = max(0, thePanelHeight - inStartY); - } - - // Now we can draw - FillRGBA(inStartX, inStartY, inWidth, inHeight, r, g, b, a); - -} - - -HSPRITE LoadSprite(const char *pszName) -{ - int i; - char sz[256]; - - if (ScreenWidth() < 640) - i = 320; - else - i = 640; - - sprintf(sz, pszName, i); - - return SPR_Load(sz); -} - -bool LocalizeString(const char* inMessage, string& outputString) -{ - #define kMaxLocalizedStringLength 1024 - - bool theSuccess = false; - char theInputString[kMaxLocalizedStringLength]; - char theOutputString[kMaxLocalizedStringLength]; - - // Don't localize empty strings - if(strcmp(inMessage, "")) - { - if(*inMessage != '#') - { - sprintf(theInputString, "#%s", inMessage); - } - else - { - sprintf(theInputString, "%s", inMessage); - } - - if((CHudTextMessage::LocaliseTextString(theInputString, theOutputString, kMaxLocalizedStringLength) != NULL)) - { - outputString = theOutputString; - - if(theOutputString[0] != '#') - { - theSuccess = true; - } - else - { - string theTempString = theOutputString; - theTempString = theTempString.substr(1, theTempString.length()); - outputString = theTempString; - } - } - else - { - outputString = string("err: ") + theInputString; - } - } - - return theSuccess; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// util.cpp +// +// implementation of class-less helper functions +// + +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +#include "hud.h" +#include "cl_util.h" +#include "common/cl_entity.h" +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#include "pm_shared/pm_defs.h" +#include "pm_shared/pm_shared.h" +#include "pm_shared/pm_movevars.h" +extern playermove_t *pmove; + +extern float HUD_GetFOV( void ); +vec3_t vec3_origin( 0, 0, 0 ); +extern vec3_t v_angles; +//double sqrt(double x); +// +//float Length(const float *v) +//{ +// int i; +// float length; +// +// length = 0; +// for (i=0 ; i< 3 ; i++) +// length += v[i]*v[i]; +// length = sqrt (length); // FIXME +// +// return length; +//} +// +//void VectorAngles( const float *forward, float *angles ) +//{ +// float tmp, yaw, pitch; +// +// if (forward[1] == 0 && forward[0] == 0) +// { +// yaw = 0; +// if (forward[2] > 0) +// pitch = 90; +// else +// pitch = 270; +// } +// else +// { +// yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); +// if (yaw < 0) +// yaw += 360; +// +// tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); +// pitch = (atan2(forward[2], tmp) * 180 / M_PI); +// if (pitch < 0) +// pitch += 360; +// } +// +// angles[0] = pitch; +// angles[1] = yaw; +// angles[2] = 0; +//} +// +//float VectorNormalize (float *v) +//{ +// float length, ilength; +// +// length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +// length = sqrt (length); // FIXME +// +// if (length) +// { +// ilength = 1/length; +// v[0] *= ilength; +// v[1] *= ilength; +// v[2] *= ilength; +// } +// +// return length; +// +//} +// +//void VectorInverse ( float *v ) +//{ +// v[0] = -v[0]; +// v[1] = -v[1]; +// v[2] = -v[2]; +//} +// +//void VectorScale (const float *in, float scale, float *out) +//{ +// out[0] = in[0]*scale; +// out[1] = in[1]*scale; +// out[2] = in[2]*scale; +//} +// +//void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) +//{ +// vecc[0] = veca[0] + scale*vecb[0]; +// vecc[1] = veca[1] + scale*vecb[1]; +// vecc[2] = veca[2] + scale*vecb[2]; +//} + +int ScreenHeight() +{ + // CGC: Replace code when ready to fix overview map + //int theViewport[4]; + //gHUD.GetViewport(theViewport); + //return theViewport[3]; + return gHUD.m_scrinfo.iHeight; +} + +// ScreenWidth returns the width of the screen, in pixels +//#define ScreenWidth ( int theViewport[4]; gHUD.GetViewport(theViewport); return theViewport[2]; ) +int ScreenWidth() +{ + //int theViewport[4]; + //gHUD.GetViewport(theViewport); + //return theViewport[2]; + return gHUD.m_scrinfo.iWidth; +} + +/* +HSPRITE SPR_Load(const char* inSpriteName) +{ + HSPRITE theSpriteHandle = gEngfuncs.pfnSPR_Load(inSpriteName); + + // Check for "Can't allocate 128 HUD sprites" crash + ASSERT(theSpriteHandle < 128); + + return theSpriteHandle; +}*/ + +//----------------------------------------------------------------------------- +// Purpose: +// Given a field of view and mouse/screen positions as well as the current +// render origin and angles, returns a unit vector through the mouse position +// that can be used to trace into the world under the mouse click pixel. +// Input : fov - +// mousex - +// mousey - +// screenwidth - +// screenheight - +// vecRenderAngles - +// c_x - +// vpn - +// vup - +// 360.0 - +//----------------------------------------------------------------------------- +void CreatePickingRay( int mousex, int mousey, Vector& outVecPickingRay ) +{ + float dx, dy; + float c_x, c_y; + float dist; + Vector vpn, vup, vright; + +// char gDebugMessage[256]; + + float fovDegrees = gHUD.m_iFOV; + + //cl_entity_s* theLocalEntity = gEngfuncs.GetLocalPlayer(); + //Vector vecRenderOrigin = theLocalEntity->origin; + //Vector vecRenderAngles = theLocalEntity->angles; + //Vector vecRenderAngles; + vec3_t vecRenderAngles; + //gEngfuncs.GetViewAngles((float*)vecRenderAngles); + VectorCopy(v_angles, vecRenderAngles); + + //vec3_t theForward, theRight, theUp; + //AngleVectors(v_angles, theForward, theRight, theUp); + + //ASSERT(v_angles.x == vecRenderAngles.x); + //ASSERT(v_angles.y == vecRenderAngles.y); + //ASSERT(v_angles.z == vecRenderAngles.z); + + c_x = ScreenWidth() / 2; + c_y = ScreenHeight() / 2; + + + dx = (float)mousex - c_x; + // Invert Y + dy = c_y - (float)mousey; + +// sprintf(gDebugMessage, "inMouseX/Y: %d/%d, dx/dy = %d/%d", (int)mousex, (int)mousey, (int)dx, (int)dy); +// CenterPrint(gDebugMessage); + + // Convert view plane distance + dist = c_x / tan( M_PI * fovDegrees / 360.0 ); + + + // Decompose view angles + AngleVectors( vecRenderAngles, vpn, vright, vup ); + + + // Offset forward by view plane distance, and then by pixel offsets + outVecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy ); + + //sprintf(gDebugMessage, "outVecPickingRay: %.0f, %.0f, %.0f", outVecPickingRay.x, outVecPickingRay.y, outVecPickingRay.z); + //CenterPrint(gDebugMessage); + + // Convert to unit vector + VectorNormalize( outVecPickingRay ); +} + +void FillRGBAClipped(vgui::Panel* inPanel, int inStartX, int inStartY, int inWidth, int inHeight, int r, int g, int b, int a) +{ + int thePanelXPos, thePanelYPos; + inPanel->getPos(thePanelXPos, thePanelYPos); + + int thePanelWidth, thePanelHeight; + inPanel->getSize(thePanelWidth, thePanelHeight); + + // Clip starting point + inStartX = min(max(0, inStartX), thePanelWidth-1); + inStartY = min(max(0, inStartY), thePanelHeight-1); + + // Clip width if it goes too far + ASSERT(inWidth >= 0); + ASSERT(inHeight >= 0); + + if(inStartX + inWidth >= thePanelWidth) + { + inWidth = max(0, thePanelWidth - inStartX); + } + if(inStartY + inHeight >= thePanelHeight) + { + inHeight = max(0, thePanelHeight - inStartY); + } + + // Now we can draw + FillRGBA(inStartX, inStartY, inWidth, inHeight, r, g, b, a); + +} + + +HSPRITE LoadSprite(const char *pszName) +{ + int i; + char sz[256]; + + if (ScreenWidth() < 640) + i = 320; + else + i = 640; + + sprintf(sz, pszName, i); + + return SPR_Load(sz); +} + +bool LocalizeString(const char* inMessage, string& outputString) +{ + #define kMaxLocalizedStringLength 1024 + + bool theSuccess = false; + char theInputString[kMaxLocalizedStringLength]; + char theOutputString[kMaxLocalizedStringLength]; + + // Don't localize empty strings + if(strcmp(inMessage, "")) + { + if(*inMessage != '#') + { + sprintf(theInputString, "#%s", inMessage); + } + else + { + sprintf(theInputString, "%s", inMessage); + } + + if((CHudTextMessage::LocaliseTextString(theInputString, theOutputString, kMaxLocalizedStringLength) != NULL)) + { + outputString = theOutputString; + + if(theOutputString[0] != '#') + { + theSuccess = true; + } + else + { + string theTempString = theOutputString; + theTempString = theTempString.substr(1, theTempString.length()); + outputString = theTempString; + } + } + else + { + outputString = string("err: ") + theInputString; + } + } + + return theSuccess; +} diff --git a/main/source/cl_dll/util_vector.h b/main/source/cl_dll/util_vector.h index 4554257c..4d99fe1e 100644 --- a/main/source/cl_dll/util_vector.h +++ b/main/source/cl_dll/util_vector.h @@ -1,39 +1,39 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Vector.h -// A subset of the extdll.h in the project HL Entity DLL -// -#ifndef UTIL_VECTOR_H -#define UTIL_VECTOR_H - -// Misc C-runtime library headers -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - - -// Header file containing definition of globalvars_t and entvars_t -typedef unsigned int func_t; // -typedef unsigned int string_t; // from engine's pr_comp.h; -typedef float vec_t; // needed before including progdefs.h - -#include "vectorclasses.h" - -#ifndef THEVECTOR3T -#define THEVECTOR3T -#define vec3_t Vector -#endif - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Vector.h +// A subset of the extdll.h in the project HL Entity DLL +// +#ifndef UTIL_VECTOR_H +#define UTIL_VECTOR_H + +// Misc C-runtime library headers +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + + +// Header file containing definition of globalvars_t and entvars_t +typedef unsigned int func_t; // +typedef unsigned int string_t; // from engine's pr_comp.h; +typedef float vec_t; // needed before including progdefs.h + +#include "vectorclasses.h" + +#ifndef THEVECTOR3T +#define THEVECTOR3T +#define vec3_t Vector +#endif + +#endif diff --git a/main/source/cl_dll/vgui_ClassMenu.cpp b/main/source/cl_dll/vgui_ClassMenu.cpp index 9dd29115..42f05967 100644 --- a/main/source/cl_dll/vgui_ClassMenu.cpp +++ b/main/source/cl_dll/vgui_ClassMenu.cpp @@ -1,440 +1,440 @@ -//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: TFC Class Menu -// -// $Workfile: $ -// $Date: 2002/07/08 16:15:13 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_ClassMenu.cpp,v $ -// Revision 1.3 2002/07/08 16:15:13 Flayra -// - Refactored team color management -// -// Revision 1.2 2001/09/13 22:28:00 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.1.1.1.2.1 2001/09/13 14:42:29 Charlie -// - HL1108 -// -// -// $NoKeywords: $ -//============================================================================= - -#include "VGUI_Font.h" -#include - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "common/cvardef.h" -#include "common/usercmd.h" -#include "common/const.h" -#include "camera.h" -#include "in_defs.h" - -#include "vgui_int.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ServerBrowser.h" - -// Class Menu Dimensions -#define CLASSMENU_TITLE_X XRES(40) -#define CLASSMENU_TITLE_Y YRES(32) -#define CLASSMENU_TOPLEFT_BUTTON_X XRES(40) -#define CLASSMENU_TOPLEFT_BUTTON_Y YRES(80) -#define CLASSMENU_BUTTON_SIZE_X XRES(124) -#define CLASSMENU_BUTTON_SIZE_Y YRES(24) -#define CLASSMENU_BUTTON_SPACER_Y YRES(8) -#define CLASSMENU_WINDOW_X XRES(176) -#define CLASSMENU_WINDOW_Y YRES(80) -#define CLASSMENU_WINDOW_SIZE_X XRES(424) -#define CLASSMENU_WINDOW_SIZE_Y YRES(312) -#define CLASSMENU_WINDOW_TEXT_X XRES(150) -#define CLASSMENU_WINDOW_TEXT_Y YRES(80) -#define CLASSMENU_WINDOW_NAME_X XRES(150) -#define CLASSMENU_WINDOW_NAME_Y YRES(8) -#define CLASSMENU_WINDOW_PLAYERS_Y YRES(42) - -// Creation -CClassMenuPanel::CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) -{ - // don't show class graphics at below 640x480 resolution - bool bShowClassGraphic = true; - if ( ScreenWidth() < 640 ) - { - bShowClassGraphic = false; - } - - memset( m_pClassImages, 0, sizeof(m_pClassImages) ); - - // Get the scheme used for the Titles - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - - // schemes - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); - SchemeHandle_t hClassWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); - - // color schemes - int r, g, b, a; - - // Create the title - Label *pLabel = new Label( "", CLASSMENU_TITLE_X, CLASSMENU_TITLE_Y ); - pLabel->setParent( this ); - pLabel->setFont( pSchemes->getFont(hTitleScheme) ); - pSchemes->getFgColor( hTitleScheme, r, g, b, a ); - pLabel->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hTitleScheme, r, g, b, a ); - pLabel->setBgColor( r, g, b, a ); - pLabel->setContentAlignment( vgui::Label::a_west ); - pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourClass")); - - // Create the Scroll panel - m_pScrollPanel = new CTFScrollPanel( CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); - m_pScrollPanel->setParent(this); - //force the scrollbars on, so after the validate clientClip will be smaller - m_pScrollPanel->setScrollBarAutoVisible(false, false); - m_pScrollPanel->setScrollBarVisible(true, true); - m_pScrollPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); - m_pScrollPanel->validate(); - - int clientWide=m_pScrollPanel->getClient()->getWide(); - - //turn scrollpanel back into auto show scrollbar mode and validate - m_pScrollPanel->setScrollBarAutoVisible(false,true); - m_pScrollPanel->setScrollBarVisible(false,false); - m_pScrollPanel->validate(); - - // Create the Class buttons - for (int i = 0; i <= PC_RANDOM; i++) - { - char sz[256]; - int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y + ( (CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y) * i ); - - ActionSignal *pASignal = new CMenuHandler_StringCommandClassSelect( sTFClassSelection[i], true ); - - // Class button - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ) ); - m_pButtons[i] = new ClassButton( i, sz, CLASSMENU_TOPLEFT_BUTTON_X, iYPos, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y, true); - // RandomPC uses '0' - if ( i >= 1 && i <= 9 ) - { - sprintf(sz,"%d",i); - } - else - { - sprintf(sz,"0"); - } - m_pButtons[i]->setBoundKey( sz[0] ); - m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); - m_pButtons[i]->addActionSignal( pASignal ); - m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); - m_pButtons[i]->setParent( this ); - - // Create the Class Info Window - //m_pClassInfoPanel[i] = new CTransparentPanel( 255, CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); - m_pClassInfoPanel[i] = new CTransparentPanel( 255, 0, 0, clientWide, CLASSMENU_WINDOW_SIZE_Y ); - m_pClassInfoPanel[i]->setParent( m_pScrollPanel->getClient() ); - //m_pClassInfoPanel[i]->setVisible( false ); - - // don't show class pic in lower resolutions - int textOffs = XRES(8); - - if ( bShowClassGraphic ) - { - textOffs = CLASSMENU_WINDOW_NAME_X; - } - - // Create the Class Name Label - sprintf(sz, "#Title_%s", sTFClassSelection[i]); - char* localName=CHudTextMessage::BufferedLocaliseTextString( sz ); - Label *pNameLabel = new Label( "", textOffs, CLASSMENU_WINDOW_NAME_Y ); - pNameLabel->setFont( pSchemes->getFont(hTitleScheme) ); - pNameLabel->setParent( m_pClassInfoPanel[i] ); - pSchemes->getFgColor( hTitleScheme, r, g, b, a ); - pNameLabel->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hTitleScheme, r, g, b, a ); - pNameLabel->setBgColor( r, g, b, a ); - pNameLabel->setContentAlignment( vgui::Label::a_west ); - //pNameLabel->setBorder(new LineBorder()); - pNameLabel->setText(localName); - - // Create the Class Image - if ( bShowClassGraphic ) - { - for ( int team = 0; team < 2; team++ ) - { - if ( team == 1 ) - { - sprintf( sz, "%sred", sTFClassSelection[i] ); - } - else - { - sprintf( sz, "%sblue", sTFClassSelection[i] ); - } - - m_pClassImages[team][i] = new CImageLabel( sz, 0, 0, CLASSMENU_WINDOW_TEXT_X, CLASSMENU_WINDOW_TEXT_Y ); - - CImageLabel *pLabel = m_pClassImages[team][i]; - pLabel->setParent( m_pClassInfoPanel[i] ); - //pLabel->setBorder(new LineBorder()); - - if ( team != 1 ) - { - pLabel->setVisible( false ); - } - - // Reposition it based upon it's size - int xOut, yOut; - pNameLabel->getTextSize( xOut, yOut ); - pLabel->setPos( (CLASSMENU_WINDOW_TEXT_X - pLabel->getWide()) / 2, yOut /2 ); - } - } - - // Create the Player count string - gHUD.m_TextMessage.LocaliseTextString( "#Title_CurrentlyOnYourTeam", m_sPlayersOnTeamString, STRLENMAX_PLAYERSONTEAM ); - m_pPlayers[i] = new Label( "", textOffs, CLASSMENU_WINDOW_PLAYERS_Y ); - m_pPlayers[i]->setParent( m_pClassInfoPanel[i] ); - m_pPlayers[i]->setBgColor( 0, 0, 0, 255 ); - m_pPlayers[i]->setContentAlignment( vgui::Label::a_west ); - m_pPlayers[i]->setFont( pSchemes->getFont(hClassWindowText) ); - - // Open up the Class Briefing File - sprintf(sz, "classes/short_%s.txt", sTFClassSelection[i]); - char *cText = "Class Description not available."; - char *pfile = (char *)gEngfuncs.COM_LoadFile( sz, 5, NULL ); - if (pfile) - { - cText = pfile; - } - - // Create the Text info window - TextPanel *pTextWindow = new TextPanel(cText, textOffs, CLASSMENU_WINDOW_TEXT_Y, (CLASSMENU_WINDOW_SIZE_X - textOffs)-5, CLASSMENU_WINDOW_SIZE_Y - CLASSMENU_WINDOW_TEXT_Y); - pTextWindow->setParent( m_pClassInfoPanel[i] ); - pTextWindow->setFont( pSchemes->getFont(hClassWindowText) ); - pSchemes->getFgColor( hClassWindowText, r, g, b, a ); - pTextWindow->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hClassWindowText, r, g, b, a ); - pTextWindow->setBgColor( r, g, b, a ); - - // Resize the Info panel to fit it all - int wide,tall; - pTextWindow->getTextImage()->getTextSizeWrapped( wide,tall); - pTextWindow->setSize(wide,tall); - - int xx,yy; - pTextWindow->getPos(xx,yy); - int maxX=xx+wide; - int maxY=yy+tall; - - //check to see if the image goes lower than the text - //just use the red teams [0] images - if(m_pClassImages[0][i]!=null) - { - m_pClassImages[0][i]->getPos(xx,yy); - if((yy+m_pClassImages[0][i]->getTall())>maxY) - { - maxY=yy+m_pClassImages[0][i]->getTall(); - } - } - - m_pClassInfoPanel[i]->setSize( maxX , maxY ); - if (pfile) gEngfuncs.COM_FreeFile( pfile ); - //m_pClassInfoPanel[i]->setBorder(new LineBorder()); - - } - - // Create the Cancel button - m_pCancelButton = new CommandButton( gHUD.m_TextMessage.BufferedLocaliseTextString( "#Menu_Cancel" ), CLASSMENU_TOPLEFT_BUTTON_X, 0, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y); - m_pCancelButton->setParent( this ); - m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); - - m_iCurrentInfo = 0; - -} - - -// Update -void CClassMenuPanel::Update() -{ - // Don't allow the player to join a team if they're not in a team - if (!g_iTeamNumber) - return; - - int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y; - - // Cycle through the rest of the buttons - for (int i = 0; i <= PC_RANDOM; i++) - { - bool bCivilian = (gViewPort->GetValidClasses(g_iTeamNumber) == -1); - - if ( bCivilian ) - { - // If this team can only be civilians, only the civilian button's visible - if (i == 0) - { - m_pButtons[0]->setVisible( true ); - SetActiveInfo( 0 ); - iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; - } - else - { - m_pButtons[i]->setVisible( false ); - } - } - else - { - if ( m_pButtons[i]->IsNotValid() || i == 0 ) - { - m_pButtons[i]->setVisible( false ); - } - else - { - m_pButtons[i]->setVisible( true ); - m_pButtons[i]->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); - iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; - - // Start with the first option up - if (!m_iCurrentInfo) - SetActiveInfo( i ); - } - } - - // Now count the number of teammembers of this class - int iTotal = 0; - for ( int j = 1; j <= MAX_PLAYERS; j++ ) - { - if ( g_PlayerInfoList[j].name == NULL ) - continue; // empty player slot, skip - if ( g_PlayerExtraInfo[j].teamname[0] == 0 ) - continue; // skip over players who are not in a team - if ( g_PlayerInfoList[j].thisplayer ) - continue; // skip this player - if ( g_PlayerExtraInfo[j].teamnumber != g_iTeamNumber ) - continue; // skip over players in other teams - - // If this team is forced to be civilians, just count the number of teammates - if ( g_PlayerExtraInfo[j].playerclass != i && !bCivilian ) - continue; - - iTotal++; - } - - char sz[256]; - sprintf(sz, m_sPlayersOnTeamString, iTotal); - m_pPlayers[i]->setText( sz ); - - // Set the text color to the teamcolor - m_pPlayers[i]->setFgColor( kTeamColors[g_iTeamNumber % iNumberOfTeamColors][0], - kTeamColors[g_iTeamNumber % iNumberOfTeamColors][1], - kTeamColors[g_iTeamNumber % iNumberOfTeamColors][2], - 0 ); - - // set the graphic to be the team pick - for ( int team = 0; team < MAX_TEAMS; team++ ) - { - // unset all the other images - if ( m_pClassImages[team][i] ) - { - m_pClassImages[team][i]->setVisible( false ); - } - - // set the current team image - if ( m_pClassImages[g_iTeamNumber-1][i] != NULL ) - { - m_pClassImages[g_iTeamNumber-1][i]->setVisible( true ); - } - else if ( m_pClassImages[0][i] ) - { - m_pClassImages[0][i]->setVisible( true ); - } - } - } - - // If the player already has a class, make the cancel button visible - if ( g_iPlayerClass ) - { - m_pCancelButton->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); - m_pCancelButton->setVisible( true ); - } - else - { - m_pCancelButton->setVisible( false ); - } -} - -//====================================== -// Key inputs for the Class Menu -bool CClassMenuPanel::SlotInput( int iSlot ) -{ - if ( (iSlot < 0) || (iSlot > 9) ) - return false; - if ( !m_pButtons[ iSlot ] ) - return false; - - // Is the button pushable? (0 is special case) - if (iSlot == 0) - { - // Selects Civilian and RandomPC - if ( gViewPort->GetValidClasses(g_iTeamNumber) == -1 ) - { - m_pButtons[ 0 ]->fireActionSignal(); - return true; - } - - // Select RandomPC - iSlot = 10; - } - - if ( !(m_pButtons[ iSlot ]->IsNotValid()) ) - { - m_pButtons[ iSlot ]->fireActionSignal(); - return true; - } - - return false; -} - -//====================================== -// Update the Class menu before opening it -void CClassMenuPanel::Open( void ) -{ - Update(); - CMenuPanel::Open(); -} - -//----------------------------------------------------------------------------- -// Purpose: Called each time a new level is started. -//----------------------------------------------------------------------------- -void CClassMenuPanel::Initialize( void ) -{ - setVisible( false ); - m_pScrollPanel->setScrollValue( 0, 0 ); -} - -//====================================== -// Mouse is over a class button, bring up the class info -void CClassMenuPanel::SetActiveInfo( int iInput ) -{ - // Remove all the Info panels and bring up the specified one - for (int i = 0; i <= PC_RANDOM; i++) - { - m_pButtons[i]->setArmed( false ); - m_pClassInfoPanel[i]->setVisible( false ); - } - - if ( iInput > PC_RANDOM || iInput < 0 ) - iInput = 0; - - m_pButtons[iInput]->setArmed( true ); - m_pClassInfoPanel[iInput]->setVisible( true ); - m_iCurrentInfo = iInput; - - m_pScrollPanel->setScrollValue(0,0); - m_pScrollPanel->validate(); -} - +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: TFC Class Menu +// +// $Workfile: $ +// $Date: 2002/07/08 16:15:13 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_ClassMenu.cpp,v $ +// Revision 1.3 2002/07/08 16:15:13 Flayra +// - Refactored team color management +// +// Revision 1.2 2001/09/13 22:28:00 Charlie +// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode +// +// Revision 1.1.1.1.2.1 2001/09/13 14:42:29 Charlie +// - HL1108 +// +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "common/cvardef.h" +#include "common/usercmd.h" +#include "common/const.h" +#include "camera.h" +#include "in_defs.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +// Class Menu Dimensions +#define CLASSMENU_TITLE_X XRES(40) +#define CLASSMENU_TITLE_Y YRES(32) +#define CLASSMENU_TOPLEFT_BUTTON_X XRES(40) +#define CLASSMENU_TOPLEFT_BUTTON_Y YRES(80) +#define CLASSMENU_BUTTON_SIZE_X XRES(124) +#define CLASSMENU_BUTTON_SIZE_Y YRES(24) +#define CLASSMENU_BUTTON_SPACER_Y YRES(8) +#define CLASSMENU_WINDOW_X XRES(176) +#define CLASSMENU_WINDOW_Y YRES(80) +#define CLASSMENU_WINDOW_SIZE_X XRES(424) +#define CLASSMENU_WINDOW_SIZE_Y YRES(312) +#define CLASSMENU_WINDOW_TEXT_X XRES(150) +#define CLASSMENU_WINDOW_TEXT_Y YRES(80) +#define CLASSMENU_WINDOW_NAME_X XRES(150) +#define CLASSMENU_WINDOW_NAME_Y YRES(8) +#define CLASSMENU_WINDOW_PLAYERS_Y YRES(42) + +// Creation +CClassMenuPanel::CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) +{ + // don't show class graphics at below 640x480 resolution + bool bShowClassGraphic = true; + if ( ScreenWidth() < 640 ) + { + bShowClassGraphic = false; + } + + memset( m_pClassImages, 0, sizeof(m_pClassImages) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hClassWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", CLASSMENU_TITLE_X, CLASSMENU_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourClass")); + + // Create the Scroll panel + m_pScrollPanel = new CTFScrollPanel( CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); + m_pScrollPanel->setParent(this); + //force the scrollbars on, so after the validate clientClip will be smaller + m_pScrollPanel->setScrollBarAutoVisible(false, false); + m_pScrollPanel->setScrollBarVisible(true, true); + m_pScrollPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); + m_pScrollPanel->validate(); + + int clientWide=m_pScrollPanel->getClient()->getWide(); + + //turn scrollpanel back into auto show scrollbar mode and validate + m_pScrollPanel->setScrollBarAutoVisible(false,true); + m_pScrollPanel->setScrollBarVisible(false,false); + m_pScrollPanel->validate(); + + // Create the Class buttons + for (int i = 0; i <= PC_RANDOM; i++) + { + char sz[256]; + int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y + ( (CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y) * i ); + + ActionSignal *pASignal = new CMenuHandler_StringCommandClassSelect( sTFClassSelection[i], true ); + + // Class button + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ) ); + m_pButtons[i] = new ClassButton( i, sz, CLASSMENU_TOPLEFT_BUTTON_X, iYPos, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y, true); + // RandomPC uses '0' + if ( i >= 1 && i <= 9 ) + { + sprintf(sz,"%d",i); + } + else + { + sprintf(sz,"0"); + } + m_pButtons[i]->setBoundKey( sz[0] ); + m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); + m_pButtons[i]->addActionSignal( pASignal ); + m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); + m_pButtons[i]->setParent( this ); + + // Create the Class Info Window + //m_pClassInfoPanel[i] = new CTransparentPanel( 255, CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); + m_pClassInfoPanel[i] = new CTransparentPanel( 255, 0, 0, clientWide, CLASSMENU_WINDOW_SIZE_Y ); + m_pClassInfoPanel[i]->setParent( m_pScrollPanel->getClient() ); + //m_pClassInfoPanel[i]->setVisible( false ); + + // don't show class pic in lower resolutions + int textOffs = XRES(8); + + if ( bShowClassGraphic ) + { + textOffs = CLASSMENU_WINDOW_NAME_X; + } + + // Create the Class Name Label + sprintf(sz, "#Title_%s", sTFClassSelection[i]); + char* localName=CHudTextMessage::BufferedLocaliseTextString( sz ); + Label *pNameLabel = new Label( "", textOffs, CLASSMENU_WINDOW_NAME_Y ); + pNameLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pNameLabel->setParent( m_pClassInfoPanel[i] ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pNameLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pNameLabel->setBgColor( r, g, b, a ); + pNameLabel->setContentAlignment( vgui::Label::a_west ); + //pNameLabel->setBorder(new LineBorder()); + pNameLabel->setText(localName); + + // Create the Class Image + if ( bShowClassGraphic ) + { + for ( int team = 0; team < 2; team++ ) + { + if ( team == 1 ) + { + sprintf( sz, "%sred", sTFClassSelection[i] ); + } + else + { + sprintf( sz, "%sblue", sTFClassSelection[i] ); + } + + m_pClassImages[team][i] = new CImageLabel( sz, 0, 0, CLASSMENU_WINDOW_TEXT_X, CLASSMENU_WINDOW_TEXT_Y ); + + CImageLabel *pLabel = m_pClassImages[team][i]; + pLabel->setParent( m_pClassInfoPanel[i] ); + //pLabel->setBorder(new LineBorder()); + + if ( team != 1 ) + { + pLabel->setVisible( false ); + } + + // Reposition it based upon it's size + int xOut, yOut; + pNameLabel->getTextSize( xOut, yOut ); + pLabel->setPos( (CLASSMENU_WINDOW_TEXT_X - pLabel->getWide()) / 2, yOut /2 ); + } + } + + // Create the Player count string + gHUD.m_TextMessage.LocaliseTextString( "#Title_CurrentlyOnYourTeam", m_sPlayersOnTeamString, STRLENMAX_PLAYERSONTEAM ); + m_pPlayers[i] = new Label( "", textOffs, CLASSMENU_WINDOW_PLAYERS_Y ); + m_pPlayers[i]->setParent( m_pClassInfoPanel[i] ); + m_pPlayers[i]->setBgColor( 0, 0, 0, 255 ); + m_pPlayers[i]->setContentAlignment( vgui::Label::a_west ); + m_pPlayers[i]->setFont( pSchemes->getFont(hClassWindowText) ); + + // Open up the Class Briefing File + sprintf(sz, "classes/short_%s.txt", sTFClassSelection[i]); + char *cText = "Class Description not available."; + char *pfile = (char *)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + cText = pfile; + } + + // Create the Text info window + TextPanel *pTextWindow = new TextPanel(cText, textOffs, CLASSMENU_WINDOW_TEXT_Y, (CLASSMENU_WINDOW_SIZE_X - textOffs)-5, CLASSMENU_WINDOW_SIZE_Y - CLASSMENU_WINDOW_TEXT_Y); + pTextWindow->setParent( m_pClassInfoPanel[i] ); + pTextWindow->setFont( pSchemes->getFont(hClassWindowText) ); + pSchemes->getFgColor( hClassWindowText, r, g, b, a ); + pTextWindow->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hClassWindowText, r, g, b, a ); + pTextWindow->setBgColor( r, g, b, a ); + + // Resize the Info panel to fit it all + int wide,tall; + pTextWindow->getTextImage()->getTextSizeWrapped( wide,tall); + pTextWindow->setSize(wide,tall); + + int xx,yy; + pTextWindow->getPos(xx,yy); + int maxX=xx+wide; + int maxY=yy+tall; + + //check to see if the image goes lower than the text + //just use the red teams [0] images + if(m_pClassImages[0][i]!=null) + { + m_pClassImages[0][i]->getPos(xx,yy); + if((yy+m_pClassImages[0][i]->getTall())>maxY) + { + maxY=yy+m_pClassImages[0][i]->getTall(); + } + } + + m_pClassInfoPanel[i]->setSize( maxX , maxY ); + if (pfile) gEngfuncs.COM_FreeFile( pfile ); + //m_pClassInfoPanel[i]->setBorder(new LineBorder()); + + } + + // Create the Cancel button + m_pCancelButton = new CommandButton( gHUD.m_TextMessage.BufferedLocaliseTextString( "#Menu_Cancel" ), CLASSMENU_TOPLEFT_BUTTON_X, 0, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y); + m_pCancelButton->setParent( this ); + m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); + + m_iCurrentInfo = 0; + +} + + +// Update +void CClassMenuPanel::Update() +{ + // Don't allow the player to join a team if they're not in a team + if (!g_iTeamNumber) + return; + + int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y; + + // Cycle through the rest of the buttons + for (int i = 0; i <= PC_RANDOM; i++) + { + bool bCivilian = (gViewPort->GetValidClasses(g_iTeamNumber) == -1); + + if ( bCivilian ) + { + // If this team can only be civilians, only the civilian button's visible + if (i == 0) + { + m_pButtons[0]->setVisible( true ); + SetActiveInfo( 0 ); + iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; + } + else + { + m_pButtons[i]->setVisible( false ); + } + } + else + { + if ( m_pButtons[i]->IsNotValid() || i == 0 ) + { + m_pButtons[i]->setVisible( false ); + } + else + { + m_pButtons[i]->setVisible( true ); + m_pButtons[i]->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; + + // Start with the first option up + if (!m_iCurrentInfo) + SetActiveInfo( i ); + } + } + + // Now count the number of teammembers of this class + int iTotal = 0; + for ( int j = 1; j <= MAX_PLAYERS; j++ ) + { + if ( g_PlayerInfoList[j].name == NULL ) + continue; // empty player slot, skip + if ( g_PlayerExtraInfo[j].teamname[0] == 0 ) + continue; // skip over players who are not in a team + if ( g_PlayerInfoList[j].thisplayer ) + continue; // skip this player + if ( g_PlayerExtraInfo[j].teamnumber != g_iTeamNumber ) + continue; // skip over players in other teams + + // If this team is forced to be civilians, just count the number of teammates + if ( g_PlayerExtraInfo[j].playerclass != i && !bCivilian ) + continue; + + iTotal++; + } + + char sz[256]; + sprintf(sz, m_sPlayersOnTeamString, iTotal); + m_pPlayers[i]->setText( sz ); + + // Set the text color to the teamcolor + m_pPlayers[i]->setFgColor( kTeamColors[g_iTeamNumber % iNumberOfTeamColors][0], + kTeamColors[g_iTeamNumber % iNumberOfTeamColors][1], + kTeamColors[g_iTeamNumber % iNumberOfTeamColors][2], + 0 ); + + // set the graphic to be the team pick + for ( int team = 0; team < MAX_TEAMS; team++ ) + { + // unset all the other images + if ( m_pClassImages[team][i] ) + { + m_pClassImages[team][i]->setVisible( false ); + } + + // set the current team image + if ( m_pClassImages[g_iTeamNumber-1][i] != NULL ) + { + m_pClassImages[g_iTeamNumber-1][i]->setVisible( true ); + } + else if ( m_pClassImages[0][i] ) + { + m_pClassImages[0][i]->setVisible( true ); + } + } + } + + // If the player already has a class, make the cancel button visible + if ( g_iPlayerClass ) + { + m_pCancelButton->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); + m_pCancelButton->setVisible( true ); + } + else + { + m_pCancelButton->setVisible( false ); + } +} + +//====================================== +// Key inputs for the Class Menu +bool CClassMenuPanel::SlotInput( int iSlot ) +{ + if ( (iSlot < 0) || (iSlot > 9) ) + return false; + if ( !m_pButtons[ iSlot ] ) + return false; + + // Is the button pushable? (0 is special case) + if (iSlot == 0) + { + // Selects Civilian and RandomPC + if ( gViewPort->GetValidClasses(g_iTeamNumber) == -1 ) + { + m_pButtons[ 0 ]->fireActionSignal(); + return true; + } + + // Select RandomPC + iSlot = 10; + } + + if ( !(m_pButtons[ iSlot ]->IsNotValid()) ) + { + m_pButtons[ iSlot ]->fireActionSignal(); + return true; + } + + return false; +} + +//====================================== +// Update the Class menu before opening it +void CClassMenuPanel::Open( void ) +{ + Update(); + CMenuPanel::Open(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void CClassMenuPanel::Initialize( void ) +{ + setVisible( false ); + m_pScrollPanel->setScrollValue( 0, 0 ); +} + +//====================================== +// Mouse is over a class button, bring up the class info +void CClassMenuPanel::SetActiveInfo( int iInput ) +{ + // Remove all the Info panels and bring up the specified one + for (int i = 0; i <= PC_RANDOM; i++) + { + m_pButtons[i]->setArmed( false ); + m_pClassInfoPanel[i]->setVisible( false ); + } + + if ( iInput > PC_RANDOM || iInput < 0 ) + iInput = 0; + + m_pButtons[iInput]->setArmed( true ); + m_pClassInfoPanel[iInput]->setVisible( true ); + m_iCurrentInfo = iInput; + + m_pScrollPanel->setScrollValue(0,0); + m_pScrollPanel->validate(); +} + diff --git a/main/source/cl_dll/vgui_ConsolePanel.cpp b/main/source/cl_dll/vgui_ConsolePanel.cpp index bb8f9cff..172ec1fa 100644 --- a/main/source/cl_dll/vgui_ConsolePanel.cpp +++ b/main/source/cl_dll/vgui_ConsolePanel.cpp @@ -1,95 +1,95 @@ - -#include"vgui_ConsolePanel.h" -#include"hud.h" -#include -#include -#include -#include -#include - -using namespace vgui; - - -namespace -{ - -class Handler : public ActionSignal -{ -private: - - ConsolePanel* _consolePanel; - -public: - - Handler(ConsolePanel* consolePanel) - { - _consolePanel=consolePanel; - } - -public: - - virtual void actionPerformed(Panel* panel) - { - _consolePanel->doExecCommand(); - } - -}; - -} - - - -ConsolePanel::ConsolePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) -{ - setBorder(new EtchedBorder()); - - _textGrid=new TextGrid(80,21,5,5,200,100); - _textGrid->setBorder(new LoweredBorder()); - _textGrid->setParent(this); - - _textEntry=new TextEntry("",5,5,200,20); - _textEntry->setParent(this); - _textEntry->addActionSignal(new Handler(this)); -} - -int ConsolePanel::print(const char* text) -{ - return _textGrid->printf("%s",text); -} - -int ConsolePanel::vprintf(const char* format,va_list argList) -{ - return _textGrid->vprintf(format,argList); -} - -int ConsolePanel::printf(const char* format,...) -{ - va_list argList; - va_start(argList,format); - int ret=vprintf(format,argList); - va_end(argList); - return ret; -} - -void ConsolePanel::doExecCommand() -{ - char buf[2048]; - _textEntry->getText(0,buf,2048); - _textEntry->setText(null,0); - gEngfuncs.pfnClientCmd(buf); -} - -void ConsolePanel::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - - getPaintSize(wide,tall); - - _textGrid->setBounds(5,5,wide-10,tall-35); - _textEntry->setBounds(5,tall-25,wide-10,20); -} - - - - - + +#include"vgui_ConsolePanel.h" +#include"hud.h" +#include +#include +#include +#include +#include + +using namespace vgui; + + +namespace +{ + +class Handler : public ActionSignal +{ +private: + + ConsolePanel* _consolePanel; + +public: + + Handler(ConsolePanel* consolePanel) + { + _consolePanel=consolePanel; + } + +public: + + virtual void actionPerformed(Panel* panel) + { + _consolePanel->doExecCommand(); + } + +}; + +} + + + +ConsolePanel::ConsolePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder(new EtchedBorder()); + + _textGrid=new TextGrid(80,21,5,5,200,100); + _textGrid->setBorder(new LoweredBorder()); + _textGrid->setParent(this); + + _textEntry=new TextEntry("",5,5,200,20); + _textEntry->setParent(this); + _textEntry->addActionSignal(new Handler(this)); +} + +int ConsolePanel::print(const char* text) +{ + return _textGrid->printf("%s",text); +} + +int ConsolePanel::vprintf(const char* format,va_list argList) +{ + return _textGrid->vprintf(format,argList); +} + +int ConsolePanel::printf(const char* format,...) +{ + va_list argList; + va_start(argList,format); + int ret=vprintf(format,argList); + va_end(argList); + return ret; +} + +void ConsolePanel::doExecCommand() +{ + char buf[2048]; + _textEntry->getText(0,buf,2048); + _textEntry->setText(null,0); + gEngfuncs.pfnClientCmd(buf); +} + +void ConsolePanel::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + getPaintSize(wide,tall); + + _textGrid->setBounds(5,5,wide-10,tall-35); + _textEntry->setBounds(5,tall-25,wide-10,20); +} + + + + + diff --git a/main/source/cl_dll/vgui_ConsolePanel.h b/main/source/cl_dll/vgui_ConsolePanel.h index 8edfc035..7e545e76 100644 --- a/main/source/cl_dll/vgui_ConsolePanel.h +++ b/main/source/cl_dll/vgui_ConsolePanel.h @@ -1,32 +1,32 @@ - -#ifndef CONSOLEPANEL_H -#define CONSOLEPANEL_H - -#include -#include - -namespace vgui -{ -class TextGrid; -class TextEntry; -} - - -class ConsolePanel : public vgui::Panel -{ -private: - vgui::TextGrid* _textGrid; - vgui::TextEntry* _textEntry; -public: - ConsolePanel(int x,int y,int wide,int tall); -public: - virtual void setSize(int wide,int tall); - virtual int print(const char* text); - virtual int vprintf(const char* format,va_list argList); - virtual int printf(const char* format,...); - virtual void doExecCommand(); -}; - - - + +#ifndef CONSOLEPANEL_H +#define CONSOLEPANEL_H + +#include +#include + +namespace vgui +{ +class TextGrid; +class TextEntry; +} + + +class ConsolePanel : public vgui::Panel +{ +private: + vgui::TextGrid* _textGrid; + vgui::TextEntry* _textEntry; +public: + ConsolePanel(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual int print(const char* text); + virtual int vprintf(const char* format,va_list argList); + virtual int printf(const char* format,...); + virtual void doExecCommand(); +}; + + + #endif \ No newline at end of file diff --git a/main/source/cl_dll/vgui_ControlConfigPanel.cpp b/main/source/cl_dll/vgui_ControlConfigPanel.cpp index 777f4a85..ea8cf16c 100644 --- a/main/source/cl_dll/vgui_ControlConfigPanel.cpp +++ b/main/source/cl_dll/vgui_ControlConfigPanel.cpp @@ -1,206 +1,206 @@ - -#include -#include"vgui_ControlConfigPanel.h" -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace vgui; - -namespace -{ -class FooTablePanel : public TablePanel -{ -private: - Label* _label; - TextEntry* _textEntry; - ControlConfigPanel* _controlConfigPanel; -public: - FooTablePanel(ControlConfigPanel* controlConfigPanel,int x,int y,int wide,int tall,int columnCount) : TablePanel(x,y,wide,tall,columnCount) - { - _controlConfigPanel=controlConfigPanel; - _label=new Label("You are a dumb monkey",0,0,100,20); - _label->setBgColor(Scheme::sc_primary3); - _label->setFgColor(Scheme::sc_primary1); - _label->setFont(Scheme::sf_primary3); - - _textEntry=new TextEntry("",0,0,100,20); - //_textEntry->setFont(Scheme::sf_primary3); - } -public: - virtual int getRowCount() - { - return _controlConfigPanel->GetCVarCount(); - } - virtual int getCellTall(int row) - { - return 12; - } - virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) - { - char cvar[128],desc[128],bind[128],bindAlt[128]; - _controlConfigPanel->GetCVar(row,cvar,128,desc,128); - - if(cellSelected) - { - _label->setBgColor(Scheme::sc_primary1); - _label->setFgColor(Scheme::sc_primary3); - } - else - if(rowSelected) - { - _label->setBgColor(Scheme::sc_primary2); - _label->setFgColor(Scheme::sc_primary1); - } - else - { - _label->setBgColor(Scheme::sc_primary3); - _label->setFgColor(Scheme::sc_primary1); - } - - switch(column) - { - case 0: - { - _label->setText(desc); - _label->setContentAlignment(Label::a_west); - break; - } - case 1: - { - _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); - _label->setText(bind); - _label->setContentAlignment(Label::a_center); - break; - } - case 2: - { - _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); - _label->setText(bindAlt); - _label->setContentAlignment(Label::a_center); - break; - } - default: - { - _label->setText(""); - break; - } - } - - return _label; - } - virtual Panel* startCellEditing(int column,int row) - { - _textEntry->setText("Goat",(int)strlen("Goat")); - _textEntry->requestFocus(); - return _textEntry; - } -}; -} - -ControlConfigPanel::ControlConfigPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) -{ - setPaintBorderEnabled(false); - setPaintBackgroundEnabled(false); - setPaintEnabled(false); - - _actionLabel=new Label("Action"); - _actionLabel->setBgColor(Scheme::sc_primary3); - _actionLabel->setFgColor(Scheme::sc_primary3); - - _keyButtonLabel=new Label("Key / Button"); - _keyButtonLabel->setBgColor(Scheme::sc_primary3); - _keyButtonLabel->setFgColor(Scheme::sc_primary3); - - _alternateLabel=new Label("Alternate"); - _alternateLabel->setBgColor(Scheme::sc_primary3); - _alternateLabel->setFgColor(Scheme::sc_primary3); - - _headerPanel=new HeaderPanel(0,0,wide,20); - _headerPanel->setParent(this); - - _headerPanel->addSectionPanel(_actionLabel); - _headerPanel->addSectionPanel(_keyButtonLabel); - _headerPanel->addSectionPanel(_alternateLabel); - - _headerPanel->setSliderPos( 0, wide/2 ); - _headerPanel->setSliderPos( 1, (wide/2) + (wide/4) ); - _headerPanel->setSliderPos( 2, wide ); - - _scrollPanel=new ScrollPanel(0,20,wide,tall-20); - _scrollPanel->setParent(this); - _scrollPanel->setPaintBorderEnabled(false); - _scrollPanel->setPaintBackgroundEnabled(false); - _scrollPanel->setPaintEnabled(false); - _scrollPanel->getClient()->setPaintBorderEnabled(false); - _scrollPanel->getClient()->setPaintBackgroundEnabled(false); - _scrollPanel->getClient()->setPaintEnabled(false); - _scrollPanel->setScrollBarVisible(false,true); - - _tablePanel=new FooTablePanel(this,0,0,_scrollPanel->getClient()->getWide(),800, 3); - _tablePanel->setParent(_scrollPanel->getClient()); - _tablePanel->setHeaderPanel(_headerPanel); - _tablePanel->setBgColor(Color(200,0,0,255)); - _tablePanel->setFgColor(Color(Scheme::sc_primary2)); - _tablePanel->setGridVisible(true,true); - _tablePanel->setGridSize(1,1); -} - -void ControlConfigPanel::AddCVar(const char* cvar,const char* desc) -{ - _cvarDar.addElement(vgui_strdup(cvar)); - _descDar.addElement(vgui_strdup(desc)); -} - -int ControlConfigPanel::GetCVarCount() -{ - return _cvarDar.getCount(); -} - -void ControlConfigPanel::GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen) -{ - vgui_strcpy(cvar,cvarLen,_cvarDar[index]); - vgui_strcpy(desc,descLen,_descDar[index]); -} - -void ControlConfigPanel::AddCVarFromInputStream(InputStream* is) -{ - if(is==null) - { - return; - } - - DataInputStream dis(is); - - bool success; - - while(1) - { - char buf[256],cvar[128],desc[128]; - dis.readLine(buf,256,success); - if(!success) - { - break; - } - if(sscanf(buf,"\"%[^\"]\" \"%[^\"]\"",cvar,desc)==2) - { - AddCVar(cvar,desc); - } - } -} - -void ControlConfigPanel::GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen) -{ - sprintf(bind,"%s : Bind",cvar); - sprintf(bindAlt,"%s : BindAlt",cvar); -} - -void ControlConfigPanel::SetCVarBind(const char* cvar,const char* bind,const char* bindAlt) -{ -} - + +#include +#include"vgui_ControlConfigPanel.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooTablePanel : public TablePanel +{ +private: + Label* _label; + TextEntry* _textEntry; + ControlConfigPanel* _controlConfigPanel; +public: + FooTablePanel(ControlConfigPanel* controlConfigPanel,int x,int y,int wide,int tall,int columnCount) : TablePanel(x,y,wide,tall,columnCount) + { + _controlConfigPanel=controlConfigPanel; + _label=new Label("You are a dumb monkey",0,0,100,20); + _label->setBgColor(Scheme::sc_primary3); + _label->setFgColor(Scheme::sc_primary1); + _label->setFont(Scheme::sf_primary3); + + _textEntry=new TextEntry("",0,0,100,20); + //_textEntry->setFont(Scheme::sf_primary3); + } +public: + virtual int getRowCount() + { + return _controlConfigPanel->GetCVarCount(); + } + virtual int getCellTall(int row) + { + return 12; + } + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + char cvar[128],desc[128],bind[128],bindAlt[128]; + _controlConfigPanel->GetCVar(row,cvar,128,desc,128); + + if(cellSelected) + { + _label->setBgColor(Scheme::sc_primary1); + _label->setFgColor(Scheme::sc_primary3); + } + else + if(rowSelected) + { + _label->setBgColor(Scheme::sc_primary2); + _label->setFgColor(Scheme::sc_primary1); + } + else + { + _label->setBgColor(Scheme::sc_primary3); + _label->setFgColor(Scheme::sc_primary1); + } + + switch(column) + { + case 0: + { + _label->setText(desc); + _label->setContentAlignment(Label::a_west); + break; + } + case 1: + { + _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); + _label->setText(bind); + _label->setContentAlignment(Label::a_center); + break; + } + case 2: + { + _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); + _label->setText(bindAlt); + _label->setContentAlignment(Label::a_center); + break; + } + default: + { + _label->setText(""); + break; + } + } + + return _label; + } + virtual Panel* startCellEditing(int column,int row) + { + _textEntry->setText("Goat",(int)strlen("Goat")); + _textEntry->requestFocus(); + return _textEntry; + } +}; +} + +ControlConfigPanel::ControlConfigPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setPaintBorderEnabled(false); + setPaintBackgroundEnabled(false); + setPaintEnabled(false); + + _actionLabel=new Label("Action"); + _actionLabel->setBgColor(Scheme::sc_primary3); + _actionLabel->setFgColor(Scheme::sc_primary3); + + _keyButtonLabel=new Label("Key / Button"); + _keyButtonLabel->setBgColor(Scheme::sc_primary3); + _keyButtonLabel->setFgColor(Scheme::sc_primary3); + + _alternateLabel=new Label("Alternate"); + _alternateLabel->setBgColor(Scheme::sc_primary3); + _alternateLabel->setFgColor(Scheme::sc_primary3); + + _headerPanel=new HeaderPanel(0,0,wide,20); + _headerPanel->setParent(this); + + _headerPanel->addSectionPanel(_actionLabel); + _headerPanel->addSectionPanel(_keyButtonLabel); + _headerPanel->addSectionPanel(_alternateLabel); + + _headerPanel->setSliderPos( 0, wide/2 ); + _headerPanel->setSliderPos( 1, (wide/2) + (wide/4) ); + _headerPanel->setSliderPos( 2, wide ); + + _scrollPanel=new ScrollPanel(0,20,wide,tall-20); + _scrollPanel->setParent(this); + _scrollPanel->setPaintBorderEnabled(false); + _scrollPanel->setPaintBackgroundEnabled(false); + _scrollPanel->setPaintEnabled(false); + _scrollPanel->getClient()->setPaintBorderEnabled(false); + _scrollPanel->getClient()->setPaintBackgroundEnabled(false); + _scrollPanel->getClient()->setPaintEnabled(false); + _scrollPanel->setScrollBarVisible(false,true); + + _tablePanel=new FooTablePanel(this,0,0,_scrollPanel->getClient()->getWide(),800, 3); + _tablePanel->setParent(_scrollPanel->getClient()); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setBgColor(Color(200,0,0,255)); + _tablePanel->setFgColor(Color(Scheme::sc_primary2)); + _tablePanel->setGridVisible(true,true); + _tablePanel->setGridSize(1,1); +} + +void ControlConfigPanel::AddCVar(const char* cvar,const char* desc) +{ + _cvarDar.addElement(vgui_strdup(cvar)); + _descDar.addElement(vgui_strdup(desc)); +} + +int ControlConfigPanel::GetCVarCount() +{ + return _cvarDar.getCount(); +} + +void ControlConfigPanel::GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen) +{ + vgui_strcpy(cvar,cvarLen,_cvarDar[index]); + vgui_strcpy(desc,descLen,_descDar[index]); +} + +void ControlConfigPanel::AddCVarFromInputStream(InputStream* is) +{ + if(is==null) + { + return; + } + + DataInputStream dis(is); + + bool success; + + while(1) + { + char buf[256],cvar[128],desc[128]; + dis.readLine(buf,256,success); + if(!success) + { + break; + } + if(sscanf(buf,"\"%[^\"]\" \"%[^\"]\"",cvar,desc)==2) + { + AddCVar(cvar,desc); + } + } +} + +void ControlConfigPanel::GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen) +{ + sprintf(bind,"%s : Bind",cvar); + sprintf(bindAlt,"%s : BindAlt",cvar); +} + +void ControlConfigPanel::SetCVarBind(const char* cvar,const char* bind,const char* bindAlt) +{ +} + diff --git a/main/source/cl_dll/vgui_ControlConfigPanel.h b/main/source/cl_dll/vgui_ControlConfigPanel.h index 9a5a41f5..1c362c4a 100644 --- a/main/source/cl_dll/vgui_ControlConfigPanel.h +++ b/main/source/cl_dll/vgui_ControlConfigPanel.h @@ -1,41 +1,41 @@ - -#ifndef CONTROLCONFIGPANEL_H -#define CONTROLCONFIGPANEL_H - -#include -#include - -namespace vgui -{ -class HeaderPanel; -class TablePanel; -class ScrollPanel; -class InputStream; -class Label; -} - -class ControlConfigPanel : public vgui::Panel -{ -private: - vgui::HeaderPanel* _headerPanel; - vgui::TablePanel* _tablePanel; - vgui::ScrollPanel* _scrollPanel; - vgui::Dar _cvarDar; - vgui::Dar _descDar; - vgui::Label* _actionLabel; - vgui::Label* _keyButtonLabel; - vgui::Label* _alternateLabel; -public: - ControlConfigPanel(int x,int y,int wide,int tall); -public: - void AddCVar(const char* cvar,const char* desc); - void AddCVarFromInputStream(vgui::InputStream* is); - int GetCVarCount(); - void GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen); - void GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen); - void SetCVarBind(const char* cvar,const char* bind,const char* bindAlt); -}; - - - + +#ifndef CONTROLCONFIGPANEL_H +#define CONTROLCONFIGPANEL_H + +#include +#include + +namespace vgui +{ +class HeaderPanel; +class TablePanel; +class ScrollPanel; +class InputStream; +class Label; +} + +class ControlConfigPanel : public vgui::Panel +{ +private: + vgui::HeaderPanel* _headerPanel; + vgui::TablePanel* _tablePanel; + vgui::ScrollPanel* _scrollPanel; + vgui::Dar _cvarDar; + vgui::Dar _descDar; + vgui::Label* _actionLabel; + vgui::Label* _keyButtonLabel; + vgui::Label* _alternateLabel; +public: + ControlConfigPanel(int x,int y,int wide,int tall); +public: + void AddCVar(const char* cvar,const char* desc); + void AddCVarFromInputStream(vgui::InputStream* is); + int GetCVarCount(); + void GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen); + void GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen); + void SetCVarBind(const char* cvar,const char* bind,const char* bindAlt); +}; + + + #endif \ No newline at end of file diff --git a/main/source/cl_dll/vgui_CustomObjects.cpp b/main/source/cl_dll/vgui_CustomObjects.cpp index 00013010..5454a40e 100644 --- a/main/source/cl_dll/vgui_CustomObjects.cpp +++ b/main/source/cl_dll/vgui_CustomObjects.cpp @@ -1,539 +1,539 @@ -//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: Contains implementation of various VGUI-derived objects -// -// $Workfile: $ -// $Date: 2001/09/13 22:28:00 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_CustomObjects.cpp,v $ -// Revision 1.2 2001/09/13 22:28:00 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.1.1.1.2.1 2001/09/13 14:42:29 Charlie -// - HL1108 -// -// -// $NoKeywords: $ -//============================================================================= - -#include "VGUI_Font.h" - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "common/cvardef.h" -#include "common/usercmd.h" -#include "common/const.h" -#include "camera.h" -#include "in_defs.h" - -#include "vgui_int.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ServerBrowser.h" -#include "../game_shared/vgui_loadtga.h" - -// Arrow filenames -char *sArrowFilenames[] = -{ - "arrowup", - "arrowdn", - "arrowlt", - "arrowrt", -}; - -// Get the name of TGA file, without a gamedir -char *GetTGANameForRes(const char *pszName) -{ - int i; - char sz[256]; - static char gd[256]; - if (ScreenWidth() < 640) - i = 320; - else - i = 640; - sprintf(sz, pszName, i); - sprintf(gd, "gfx/vgui/%s.tga", sz); - return gd; -} - -//----------------------------------------------------------------------------- -// Purpose: Loads a .tga file and returns a pointer to the VGUI tga object -//----------------------------------------------------------------------------- -BitmapTGA *LoadTGAForRes( const char* pImageName ) -{ - BitmapTGA *pTGA; - - char sz[256]; - sprintf(sz, "%%d_%s", pImageName); - pTGA = vgui_LoadTGA(GetTGANameForRes(sz)); - - return pTGA; -} - -//=========================================================== -// All TFC Hud buttons are derived from this one. -CommandButton::CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight) : Button("",x,y,wide,tall) -{ - m_iPlayerClass = 0; - m_bNoHighlight = bNoHighlight; - m_bFlat = false; - Init(); - setText( text ); -} - -CommandButton::CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall, bool bFlat) : Button("",x,y,wide,tall) -{ - m_iPlayerClass = iPlayerClass; - m_bNoHighlight = false; - m_bFlat = bFlat; - Init(); - setText( text ); -} -CommandButton::CommandButton(const char *text, int x, int y, int wide, int tall, bool bNoHighlight, bool bFlat) : Button("",x,y,wide,tall) -{ - m_iPlayerClass = 0; - m_bFlat = bFlat; - m_bNoHighlight = bNoHighlight; - Init(); - setText( text ); -} - -void CommandButton::Init( void ) -{ - m_pSubMenu = NULL; - m_pSubLabel = NULL; - m_pParentMenu = NULL; - - // Set text color to orange - setFgColor(Scheme::sc_primary1); - - // left align - setContentAlignment( vgui::Label::a_west ); - - // Add the Highlight signal - if (!m_bNoHighlight) - addInputSignal( new CHandler_CommandButtonHighlight(this) ); - - // not bound to any button yet - m_cBoundKey = 0; -} - -//----------------------------------------------------------------------------- -// Purpose: Prepends the button text with the current bound key -// if no bound key, then a clear space ' ' instead -//----------------------------------------------------------------------------- -void CommandButton::RecalculateText( void ) -{ - char szBuf[128]; - - if ( m_cBoundKey != 0 ) - { - if ( m_cBoundKey == (char)255 ) - { - strcpy( szBuf, m_sMainText ); - } - else - { - sprintf( szBuf, " %c %s", m_cBoundKey, m_sMainText ); - } - szBuf[MAX_BUTTON_SIZE-1] = 0; - } - else - { - // just draw a space if no key bound - sprintf( szBuf, " %s", m_sMainText ); - szBuf[MAX_BUTTON_SIZE-1] = 0; - } - - Button::setText( szBuf ); -} - -void CommandButton::setText( const char *text ) -{ - strncpy( m_sMainText, text, MAX_BUTTON_SIZE ); - m_sMainText[MAX_BUTTON_SIZE-1] = 0; - - RecalculateText(); -} - -void CommandButton::setBoundKey( char boundKey ) -{ - m_cBoundKey = boundKey; - RecalculateText(); -} - -char CommandButton::getBoundKey( void ) -{ - return m_cBoundKey; -} - -void CommandButton::AddSubMenu( CCommandMenu *pNewMenu ) -{ - m_pSubMenu = pNewMenu; - - // Prevent this button from being pushed - setMouseClickEnabled( MOUSE_LEFT, false ); -} - -void CommandButton::UpdateSubMenus( int iAdjustment ) -{ - if ( m_pSubMenu ) - m_pSubMenu->RecalculatePositions( iAdjustment ); -} - -void CommandButton::paint() -{ - // Make the sub label paint the same as the button - if ( m_pSubLabel ) - { - if ( isSelected() ) - m_pSubLabel->PushDown(); - else - m_pSubLabel->PushUp(); - } - - // draw armed button text in white - if ( isArmed() ) - { - setFgColor( Scheme::sc_secondary2 ); - } - else - { - setFgColor( Scheme::sc_primary1 ); - } - - Button::paint(); -} - -void CommandButton::paintBackground() -{ - if ( m_bFlat ) - { - if ( isArmed() ) - { - // Orange Border - drawSetColor( Scheme::sc_secondary1 ); - drawOutlinedRect(0,0,_size[0],_size[1]); - } - } - else - { - if ( isArmed() ) - { - // Orange highlight background - drawSetColor( Scheme::sc_primary2 ); - drawFilledRect(0,0,_size[0],_size[1]); - } - - // Orange Border - drawSetColor( Scheme::sc_secondary1 ); - drawOutlinedRect(0,0,_size[0],_size[1]); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Highlights the current button, and all it's parent menus -//----------------------------------------------------------------------------- -void CommandButton::cursorEntered( void ) -{ - // unarm all the other buttons in this menu - CCommandMenu *containingMenu = getParentMenu(); - if ( containingMenu ) - { - containingMenu->ClearButtonsOfArmedState(); - - // make all our higher buttons armed - CCommandMenu *pCParent = containingMenu->GetParentMenu(); - if ( pCParent ) - { - CommandButton *pParentButton = pCParent->FindButtonWithSubmenu( containingMenu ); - - pParentButton->cursorEntered(); - } - } - - // arm ourselves - setArmed( true ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CommandButton::cursorExited( void ) -{ - // only clear ourselves if we have do not have a containing menu - // only stay armed if we have a sub menu - // the buttons only unarm themselves when another button is armed instead - if ( !getParentMenu() || !GetSubMenu() ) - { - setArmed( false ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Returns the command menu that the button is part of, if any -// Output : CCommandMenu * -//----------------------------------------------------------------------------- -CCommandMenu *CommandButton::getParentMenu( void ) -{ - return m_pParentMenu; -} - -//----------------------------------------------------------------------------- -// Purpose: Sets the menu that contains this button -// Input : *pParentMenu - -//----------------------------------------------------------------------------- -void CommandButton::setParentMenu( CCommandMenu *pParentMenu ) -{ - m_pParentMenu = pParentMenu; -} - - -//=========================================================== -int ClassButton::IsNotValid() -{ - // If this is the main ChangeClass button, remove it if the player's only able to be civilians - if ( m_iPlayerClass == -1 ) - { - if (gViewPort->GetValidClasses(g_iTeamNumber) == -1) - return true; - - return false; - } - - // Is it an illegal class? - if ((gViewPort->GetValidClasses(0) & sTFValidClassInts[ m_iPlayerClass ]) || (gViewPort->GetValidClasses(g_iTeamNumber) & sTFValidClassInts[ m_iPlayerClass ])) - return true; - - // Only check current class if they've got autokill on - bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; - if ( bAutoKill ) - { - // Is it the player's current class? - if ( (gViewPort->IsRandomPC() && m_iPlayerClass == PC_RANDOM) || (!gViewPort->IsRandomPC() && (m_iPlayerClass == g_iPlayerClass)) ) - return true; - } - - return false; -} - -//=========================================================== -// Button with Class image beneath it -CImageLabel::CImageLabel( const char* pImageName,int x,int y ) : Label( "", x,y ) -{ - setContentFitted(true); - m_pTGA = LoadTGAForRes(pImageName); - setImage( m_pTGA ); -} - -CImageLabel::CImageLabel( const char* pImageName,int x,int y,int wide,int tall ) : Label( "", x,y,wide,tall ) -{ - setContentFitted(true); - m_pTGA = LoadTGAForRes(pImageName); - setImage( m_pTGA ); -} - -//=========================================================== -// Image size -int CImageLabel::getImageWide( void ) -{ - if( m_pTGA ) - { - int iXSize, iYSize; - m_pTGA->getSize( iXSize, iYSize ); - return iXSize; - } - else - { - return 1; - } -} - -int CImageLabel::getImageTall( void ) -{ - if( m_pTGA ) - { - int iXSize, iYSize; - m_pTGA->getSize( iXSize, iYSize ); - return iYSize; - } - else - { - return 1; - } -} - -void CImageLabel::LoadImage(const char * pImageName) -{ - if ( m_pTGA ) - delete m_pTGA; - - // Load the Image - m_pTGA = LoadTGAForRes(pImageName); - - if ( m_pTGA == NULL ) - { - // we didn't find a matching image file for this resolution - // try to load file resolution independent - - char sz[256]; - sprintf(sz, "%s/%s",gEngfuncs.pfnGetGameDirectory(), pImageName ); - FileInputStream* fis = new FileInputStream( sz, false ); - m_pTGA = new BitmapTGA(fis,true); - fis->close(); - } - - if ( m_pTGA == NULL ) - return; // unable to load image - - int w,t; - - m_pTGA->getSize( w, t ); - - setSize( XRES (w),YRES (t) ); - setImage( m_pTGA ); -} -//=========================================================== -// Various overloaded paint functions for Custom VGUI objects -void CCommandMenu::paintBackground() -{ - // Transparent black background - - if ( m_iSpectCmdMenu ) - drawSetColor( 0, 0, 0, 64 ); - else - drawSetColor(Scheme::sc_primary3); - - drawFilledRect(0,0,_size[0],_size[1]); -} - -//================================================================================= -// CUSTOM SCROLLPANEL -//================================================================================= -CTFScrollButton::CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall) : CommandButton(text,x,y,wide,tall) -{ - // Set text color to orange - setFgColor(Scheme::sc_primary1); - - // Load in the arrow - m_pTGA = LoadTGAForRes( sArrowFilenames[iArrow] ); - setImage( m_pTGA ); - - // Highlight signal - InputSignal *pISignal = new CHandler_CommandButtonHighlight(this); - addInputSignal(pISignal); -} - -void CTFScrollButton::paint( void ) -{ - if (!m_pTGA) - return; - - // draw armed button text in white - if ( isArmed() ) - { - m_pTGA->setColor( Color(255,255,255, 0) ); - } - else - { - m_pTGA->setColor( Color(255,255,255, 128) ); - } - - m_pTGA->doPaint(this); -} - -void CTFScrollButton::paintBackground( void ) -{ -/* - if ( isArmed() ) - { - // Orange highlight background - drawSetColor( Scheme::sc_primary2 ); - drawFilledRect(0,0,_size[0],_size[1]); - } - - // Orange Border - drawSetColor( Scheme::sc_secondary1 ); - drawOutlinedRect(0,0,_size[0]-1,_size[1]); -*/ -} - -void CTFSlider::paintBackground( void ) -{ - int wide,tall,nobx,noby; - getPaintSize(wide,tall); - getNobPos(nobx,noby); - - // Border - drawSetColor( Scheme::sc_secondary1 ); - drawOutlinedRect( 0,0,wide,tall ); - - if( isVertical() ) - { - // Nob Fill - drawSetColor( Scheme::sc_primary2 ); - drawFilledRect( 0,nobx,wide,noby ); - - // Nob Outline - drawSetColor( Scheme::sc_primary1 ); - drawOutlinedRect( 0,nobx,wide,noby ); - } - else - { - // Nob Fill - drawSetColor( Scheme::sc_primary2 ); - drawFilledRect( nobx,0,noby,tall ); - - // Nob Outline - drawSetColor( Scheme::sc_primary1 ); - drawOutlinedRect( nobx,0,noby,tall ); - } -} - -CTFScrollPanel::CTFScrollPanel(int x,int y,int wide,int tall) : ScrollPanel(x,y,wide,tall) -{ - ScrollBar *pScrollBar = getVerticalScrollBar(); - pScrollBar->setButton( new CTFScrollButton( ARROW_UP, "", 0,0,16,16 ), 0 ); - pScrollBar->setButton( new CTFScrollButton( ARROW_DOWN, "", 0,0,16,16 ), 1 ); - pScrollBar->setSlider( new CTFSlider(0,wide-1,wide,(tall-(wide*2))+2,true) ); - pScrollBar->setPaintBorderEnabled(false); - pScrollBar->setPaintBackgroundEnabled(false); - pScrollBar->setPaintEnabled(false); - - pScrollBar = getHorizontalScrollBar(); - pScrollBar->setButton( new CTFScrollButton( ARROW_LEFT, "", 0,0,16,16 ), 0 ); - pScrollBar->setButton( new CTFScrollButton( ARROW_RIGHT, "", 0,0,16,16 ), 1 ); - pScrollBar->setSlider( new CTFSlider(tall,0,wide-(tall*2),tall,false) ); - pScrollBar->setPaintBorderEnabled(false); - pScrollBar->setPaintBackgroundEnabled(false); - pScrollBar->setPaintEnabled(false); -} - - -//================================================================================= -// CUSTOM HANDLERS -//================================================================================= -void CHandler_MenuButtonOver::cursorEntered(Panel *panel) -{ - if ( gViewPort && m_pMenuPanel ) - { - m_pMenuPanel->SetActiveInfo( m_iButton ); - } -} - -void CMenuHandler_StringCommandClassSelect::actionPerformed(Panel* panel) -{ - CMenuHandler_StringCommand::actionPerformed( panel ); - - bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; - if ( bAutoKill && g_iPlayerClass != 0 ) - gEngfuncs.pfnClientCmd("kill"); -} - +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Contains implementation of various VGUI-derived objects +// +// $Workfile: $ +// $Date: 2001/09/13 22:28:00 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_CustomObjects.cpp,v $ +// Revision 1.2 2001/09/13 22:28:00 Charlie +// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode +// +// Revision 1.1.1.1.2.1 2001/09/13 14:42:29 Charlie +// - HL1108 +// +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "common/cvardef.h" +#include "common/usercmd.h" +#include "common/const.h" +#include "camera.h" +#include "in_defs.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" +#include "../game_shared/vgui_loadtga.h" + +// Arrow filenames +char *sArrowFilenames[] = +{ + "arrowup", + "arrowdn", + "arrowlt", + "arrowrt", +}; + +// Get the name of TGA file, without a gamedir +char *GetTGANameForRes(const char *pszName) +{ + int i; + char sz[256]; + static char gd[256]; + if (ScreenWidth() < 640) + i = 320; + else + i = 640; + sprintf(sz, pszName, i); + sprintf(gd, "gfx/vgui/%s.tga", sz); + return gd; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads a .tga file and returns a pointer to the VGUI tga object +//----------------------------------------------------------------------------- +BitmapTGA *LoadTGAForRes( const char* pImageName ) +{ + BitmapTGA *pTGA; + + char sz[256]; + sprintf(sz, "%%d_%s", pImageName); + pTGA = vgui_LoadTGA(GetTGANameForRes(sz)); + + return pTGA; +} + +//=========================================================== +// All TFC Hud buttons are derived from this one. +CommandButton::CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = 0; + m_bNoHighlight = bNoHighlight; + m_bFlat = false; + Init(); + setText( text ); +} + +CommandButton::CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall, bool bFlat) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = iPlayerClass; + m_bNoHighlight = false; + m_bFlat = bFlat; + Init(); + setText( text ); +} +CommandButton::CommandButton(const char *text, int x, int y, int wide, int tall, bool bNoHighlight, bool bFlat) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = 0; + m_bFlat = bFlat; + m_bNoHighlight = bNoHighlight; + Init(); + setText( text ); +} + +void CommandButton::Init( void ) +{ + m_pSubMenu = NULL; + m_pSubLabel = NULL; + m_pParentMenu = NULL; + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + + // left align + setContentAlignment( vgui::Label::a_west ); + + // Add the Highlight signal + if (!m_bNoHighlight) + addInputSignal( new CHandler_CommandButtonHighlight(this) ); + + // not bound to any button yet + m_cBoundKey = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Prepends the button text with the current bound key +// if no bound key, then a clear space ' ' instead +//----------------------------------------------------------------------------- +void CommandButton::RecalculateText( void ) +{ + char szBuf[128]; + + if ( m_cBoundKey != 0 ) + { + if ( m_cBoundKey == (char)255 ) + { + strcpy( szBuf, m_sMainText ); + } + else + { + sprintf( szBuf, " %c %s", m_cBoundKey, m_sMainText ); + } + szBuf[MAX_BUTTON_SIZE-1] = 0; + } + else + { + // just draw a space if no key bound + sprintf( szBuf, " %s", m_sMainText ); + szBuf[MAX_BUTTON_SIZE-1] = 0; + } + + Button::setText( szBuf ); +} + +void CommandButton::setText( const char *text ) +{ + strncpy( m_sMainText, text, MAX_BUTTON_SIZE ); + m_sMainText[MAX_BUTTON_SIZE-1] = 0; + + RecalculateText(); +} + +void CommandButton::setBoundKey( char boundKey ) +{ + m_cBoundKey = boundKey; + RecalculateText(); +} + +char CommandButton::getBoundKey( void ) +{ + return m_cBoundKey; +} + +void CommandButton::AddSubMenu( CCommandMenu *pNewMenu ) +{ + m_pSubMenu = pNewMenu; + + // Prevent this button from being pushed + setMouseClickEnabled( MOUSE_LEFT, false ); +} + +void CommandButton::UpdateSubMenus( int iAdjustment ) +{ + if ( m_pSubMenu ) + m_pSubMenu->RecalculatePositions( iAdjustment ); +} + +void CommandButton::paint() +{ + // Make the sub label paint the same as the button + if ( m_pSubLabel ) + { + if ( isSelected() ) + m_pSubLabel->PushDown(); + else + m_pSubLabel->PushUp(); + } + + // draw armed button text in white + if ( isArmed() ) + { + setFgColor( Scheme::sc_secondary2 ); + } + else + { + setFgColor( Scheme::sc_primary1 ); + } + + Button::paint(); +} + +void CommandButton::paintBackground() +{ + if ( m_bFlat ) + { + if ( isArmed() ) + { + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + else + { + if ( isArmed() ) + { + // Orange highlight background + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect(0,0,_size[0],_size[1]); + } + + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Highlights the current button, and all it's parent menus +//----------------------------------------------------------------------------- +void CommandButton::cursorEntered( void ) +{ + // unarm all the other buttons in this menu + CCommandMenu *containingMenu = getParentMenu(); + if ( containingMenu ) + { + containingMenu->ClearButtonsOfArmedState(); + + // make all our higher buttons armed + CCommandMenu *pCParent = containingMenu->GetParentMenu(); + if ( pCParent ) + { + CommandButton *pParentButton = pCParent->FindButtonWithSubmenu( containingMenu ); + + pParentButton->cursorEntered(); + } + } + + // arm ourselves + setArmed( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CommandButton::cursorExited( void ) +{ + // only clear ourselves if we have do not have a containing menu + // only stay armed if we have a sub menu + // the buttons only unarm themselves when another button is armed instead + if ( !getParentMenu() || !GetSubMenu() ) + { + setArmed( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the command menu that the button is part of, if any +// Output : CCommandMenu * +//----------------------------------------------------------------------------- +CCommandMenu *CommandButton::getParentMenu( void ) +{ + return m_pParentMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the menu that contains this button +// Input : *pParentMenu - +//----------------------------------------------------------------------------- +void CommandButton::setParentMenu( CCommandMenu *pParentMenu ) +{ + m_pParentMenu = pParentMenu; +} + + +//=========================================================== +int ClassButton::IsNotValid() +{ + // If this is the main ChangeClass button, remove it if the player's only able to be civilians + if ( m_iPlayerClass == -1 ) + { + if (gViewPort->GetValidClasses(g_iTeamNumber) == -1) + return true; + + return false; + } + + // Is it an illegal class? + if ((gViewPort->GetValidClasses(0) & sTFValidClassInts[ m_iPlayerClass ]) || (gViewPort->GetValidClasses(g_iTeamNumber) & sTFValidClassInts[ m_iPlayerClass ])) + return true; + + // Only check current class if they've got autokill on + bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; + if ( bAutoKill ) + { + // Is it the player's current class? + if ( (gViewPort->IsRandomPC() && m_iPlayerClass == PC_RANDOM) || (!gViewPort->IsRandomPC() && (m_iPlayerClass == g_iPlayerClass)) ) + return true; + } + + return false; +} + +//=========================================================== +// Button with Class image beneath it +CImageLabel::CImageLabel( const char* pImageName,int x,int y ) : Label( "", x,y ) +{ + setContentFitted(true); + m_pTGA = LoadTGAForRes(pImageName); + setImage( m_pTGA ); +} + +CImageLabel::CImageLabel( const char* pImageName,int x,int y,int wide,int tall ) : Label( "", x,y,wide,tall ) +{ + setContentFitted(true); + m_pTGA = LoadTGAForRes(pImageName); + setImage( m_pTGA ); +} + +//=========================================================== +// Image size +int CImageLabel::getImageWide( void ) +{ + if( m_pTGA ) + { + int iXSize, iYSize; + m_pTGA->getSize( iXSize, iYSize ); + return iXSize; + } + else + { + return 1; + } +} + +int CImageLabel::getImageTall( void ) +{ + if( m_pTGA ) + { + int iXSize, iYSize; + m_pTGA->getSize( iXSize, iYSize ); + return iYSize; + } + else + { + return 1; + } +} + +void CImageLabel::LoadImage(const char * pImageName) +{ + if ( m_pTGA ) + delete m_pTGA; + + // Load the Image + m_pTGA = LoadTGAForRes(pImageName); + + if ( m_pTGA == NULL ) + { + // we didn't find a matching image file for this resolution + // try to load file resolution independent + + char sz[256]; + sprintf(sz, "%s/%s",gEngfuncs.pfnGetGameDirectory(), pImageName ); + FileInputStream* fis = new FileInputStream( sz, false ); + m_pTGA = new BitmapTGA(fis,true); + fis->close(); + } + + if ( m_pTGA == NULL ) + return; // unable to load image + + int w,t; + + m_pTGA->getSize( w, t ); + + setSize( XRES (w),YRES (t) ); + setImage( m_pTGA ); +} +//=========================================================== +// Various overloaded paint functions for Custom VGUI objects +void CCommandMenu::paintBackground() +{ + // Transparent black background + + if ( m_iSpectCmdMenu ) + drawSetColor( 0, 0, 0, 64 ); + else + drawSetColor(Scheme::sc_primary3); + + drawFilledRect(0,0,_size[0],_size[1]); +} + +//================================================================================= +// CUSTOM SCROLLPANEL +//================================================================================= +CTFScrollButton::CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall) : CommandButton(text,x,y,wide,tall) +{ + // Set text color to orange + setFgColor(Scheme::sc_primary1); + + // Load in the arrow + m_pTGA = LoadTGAForRes( sArrowFilenames[iArrow] ); + setImage( m_pTGA ); + + // Highlight signal + InputSignal *pISignal = new CHandler_CommandButtonHighlight(this); + addInputSignal(pISignal); +} + +void CTFScrollButton::paint( void ) +{ + if (!m_pTGA) + return; + + // draw armed button text in white + if ( isArmed() ) + { + m_pTGA->setColor( Color(255,255,255, 0) ); + } + else + { + m_pTGA->setColor( Color(255,255,255, 128) ); + } + + m_pTGA->doPaint(this); +} + +void CTFScrollButton::paintBackground( void ) +{ +/* + if ( isArmed() ) + { + // Orange highlight background + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect(0,0,_size[0],_size[1]); + } + + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0]-1,_size[1]); +*/ +} + +void CTFSlider::paintBackground( void ) +{ + int wide,tall,nobx,noby; + getPaintSize(wide,tall); + getNobPos(nobx,noby); + + // Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect( 0,0,wide,tall ); + + if( isVertical() ) + { + // Nob Fill + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect( 0,nobx,wide,noby ); + + // Nob Outline + drawSetColor( Scheme::sc_primary1 ); + drawOutlinedRect( 0,nobx,wide,noby ); + } + else + { + // Nob Fill + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect( nobx,0,noby,tall ); + + // Nob Outline + drawSetColor( Scheme::sc_primary1 ); + drawOutlinedRect( nobx,0,noby,tall ); + } +} + +CTFScrollPanel::CTFScrollPanel(int x,int y,int wide,int tall) : ScrollPanel(x,y,wide,tall) +{ + ScrollBar *pScrollBar = getVerticalScrollBar(); + pScrollBar->setButton( new CTFScrollButton( ARROW_UP, "", 0,0,16,16 ), 0 ); + pScrollBar->setButton( new CTFScrollButton( ARROW_DOWN, "", 0,0,16,16 ), 1 ); + pScrollBar->setSlider( new CTFSlider(0,wide-1,wide,(tall-(wide*2))+2,true) ); + pScrollBar->setPaintBorderEnabled(false); + pScrollBar->setPaintBackgroundEnabled(false); + pScrollBar->setPaintEnabled(false); + + pScrollBar = getHorizontalScrollBar(); + pScrollBar->setButton( new CTFScrollButton( ARROW_LEFT, "", 0,0,16,16 ), 0 ); + pScrollBar->setButton( new CTFScrollButton( ARROW_RIGHT, "", 0,0,16,16 ), 1 ); + pScrollBar->setSlider( new CTFSlider(tall,0,wide-(tall*2),tall,false) ); + pScrollBar->setPaintBorderEnabled(false); + pScrollBar->setPaintBackgroundEnabled(false); + pScrollBar->setPaintEnabled(false); +} + + +//================================================================================= +// CUSTOM HANDLERS +//================================================================================= +void CHandler_MenuButtonOver::cursorEntered(Panel *panel) +{ + if ( gViewPort && m_pMenuPanel ) + { + m_pMenuPanel->SetActiveInfo( m_iButton ); + } +} + +void CMenuHandler_StringCommandClassSelect::actionPerformed(Panel* panel) +{ + CMenuHandler_StringCommand::actionPerformed( panel ); + + bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; + if ( bAutoKill && g_iPlayerClass != 0 ) + gEngfuncs.pfnClientCmd("kill"); +} + diff --git a/main/source/cl_dll/vgui_MOTDWindow.cpp b/main/source/cl_dll/vgui_MOTDWindow.cpp index 1f45af30..8658a060 100644 --- a/main/source/cl_dll/vgui_MOTDWindow.cpp +++ b/main/source/cl_dll/vgui_MOTDWindow.cpp @@ -1,168 +1,168 @@ -//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: $ -// $Date: 2001/09/13 22:28:00 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_MOTDWindow.cpp,v $ -// Revision 1.3 2001/09/13 22:28:00 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.2 2001/04/09 19:31:35 charlie -// - Quick hacky tests to try out menus for team/class picking...yuck -// Revision 1.1.1.1.2.1 2001/09/13 14:42:29 Charlie -// - HL1108 -// -// Revision 1.1.1.1 2000/06/17 14:12:45 charlie -// Final version of new HL SDK. May not compile. -// Previous versions of my MSVC project files and utility .bat files. -// This is my starting point; there is no mod-specific code in here. -// -// -// $NoKeywords: $ -//============================================================================= - -#include "VGUI_Font.h" -#include "VGUI_ScrollPanel.h" -#include "VGUI_TextImage.h" - -#include - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "common/const.h" - -#include "vgui_int.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ServerBrowser.h" - -#define MOTD_TITLE_X XRES(16) -#define MOTD_TITLE_Y YRES(16) - -#define MOTD_WINDOW_X XRES(112) -#define MOTD_WINDOW_Y YRES(80) -#define MOTD_WINDOW_SIZE_X XRES(424) -#define MOTD_WINDOW_SIZE_Y YRES(312) - -//----------------------------------------------------------------------------- -// Purpose: Displays the MOTD and basic server information -//----------------------------------------------------------------------------- -class CMessageWindowPanel : public CMenuPanel -{ -public: - CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullScreen, int iRemoveMe, int x, int y, int wide, int tall ); - -private: - CTransparentPanel *m_pBackgroundPanel; - -}; - -//----------------------------------------------------------------------------- -// Purpose: Creates a new CMessageWindowPanel -// Output : CMenuPanel - interface to the panel -//----------------------------------------------------------------------------- -CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) -{ - return new CMessageWindowPanel( szMOTD, szTitle, iShadeFullscreen, iRemoveMe, x, y, wide, tall ); -} - -//----------------------------------------------------------------------------- -// Purpose: Constructs a message panel -//----------------------------------------------------------------------------- -CMessageWindowPanel::CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) : CMenuPanel( iShadeFullscreen ? 100 : 255, iRemoveMe, x, y, wide, tall ) -{ - // Get the scheme used for the Titles - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - - // schemes - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); - SchemeHandle_t hMOTDText = pSchemes->getSchemeHandle( "Briefing Text" ); - - // color schemes - int r, g, b, a; - - // Create the window - m_pBackgroundPanel = new CTransparentPanel( iShadeFullscreen ? 255 : 100, MOTD_WINDOW_X, MOTD_WINDOW_Y, MOTD_WINDOW_SIZE_X, MOTD_WINDOW_SIZE_Y ); - m_pBackgroundPanel->setParent( this ); - m_pBackgroundPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); - m_pBackgroundPanel->setVisible( true ); - - int iXSize,iYSize,iXPos,iYPos; - m_pBackgroundPanel->getPos( iXPos,iYPos ); - m_pBackgroundPanel->getSize( iXSize,iYSize ); - - // Create the title - Label *pLabel = new Label( "", iXPos + MOTD_TITLE_X, iYPos + MOTD_TITLE_Y ); - pLabel->setParent( this ); - pLabel->setFont( pSchemes->getFont(hTitleScheme) ); - pLabel->setFont( Scheme::sf_primary1 ); - - pSchemes->getFgColor( hTitleScheme, r, g, b, a ); - pLabel->setFgColor( r, g, b, a ); - pLabel->setFgColor( Scheme::sc_primary1 ); - pSchemes->getBgColor( hTitleScheme, r, g, b, a ); - pLabel->setBgColor( r, g, b, a ); - pLabel->setContentAlignment( vgui::Label::a_west ); - pLabel->setText(szTitle); - - // Create the Scroll panel - ScrollPanel *pScrollPanel = new CTFScrollPanel( iXPos + XRES(16), iYPos + MOTD_TITLE_Y*2 + YRES(16), iXSize - XRES(32), iYSize - (YRES(48) + BUTTON_SIZE_Y*2) ); - pScrollPanel->setParent(this); - - //force the scrollbars on so clientClip will take them in account after the validate - pScrollPanel->setScrollBarAutoVisible(false, false); - pScrollPanel->setScrollBarVisible(true, true); - pScrollPanel->validate(); - - // Create the text panel - TextPanel *pText = new TextPanel( "", 0,0, 64,64); - pText->setParent( pScrollPanel->getClient() ); - - // get the font and colors from the scheme - pText->setFont( pSchemes->getFont(hMOTDText) ); - pSchemes->getFgColor( hMOTDText, r, g, b, a ); - pText->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hMOTDText, r, g, b, a ); - pText->setBgColor( r, g, b, a ); - pText->setText(szMOTD); - - // Get the total size of the MOTD text and resize the text panel - int iScrollSizeX, iScrollSizeY; - - // First, set the size so that the client's wdith is correct at least because the - // width is critical for getting the "wrapped" size right. - // You'll see a horizontal scroll bar if there is a single word that won't wrap in the - // specified width. - pText->getTextImage()->setSize(pScrollPanel->getClientClip()->getWide(), pScrollPanel->getClientClip()->getTall()); - pText->getTextImage()->getTextSizeWrapped( iScrollSizeX, iScrollSizeY ); - - // Now resize the textpanel to fit the scrolled size - pText->setSize( iScrollSizeX , iScrollSizeY ); - - //turn the scrollbars back into automode - pScrollPanel->setScrollBarAutoVisible(true, true); - pScrollPanel->setScrollBarVisible(false, false); - - pScrollPanel->validate(); - - CommandButton *pButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_OK" ), iXPos + XRES(16), iYPos + iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_TextWindow(HIDE_TEXTWINDOW)); - pButton->addActionSignal(new CMenuHandler_TextWindow(SHOW_CLASSDESC)); - pButton->setParent(this); - -} - - - - - - +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: 2001/09/13 22:28:00 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_MOTDWindow.cpp,v $ +// Revision 1.3 2001/09/13 22:28:00 Charlie +// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode +// +// Revision 1.2 2001/04/09 19:31:35 charlie +// - Quick hacky tests to try out menus for team/class picking...yuck +// Revision 1.1.1.1.2.1 2001/09/13 14:42:29 Charlie +// - HL1108 +// +// Revision 1.1.1.1 2000/06/17 14:12:45 charlie +// Final version of new HL SDK. May not compile. +// Previous versions of my MSVC project files and utility .bat files. +// This is my starting point; there is no mod-specific code in here. +// +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "common/const.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +#define MOTD_TITLE_X XRES(16) +#define MOTD_TITLE_Y YRES(16) + +#define MOTD_WINDOW_X XRES(112) +#define MOTD_WINDOW_Y YRES(80) +#define MOTD_WINDOW_SIZE_X XRES(424) +#define MOTD_WINDOW_SIZE_Y YRES(312) + +//----------------------------------------------------------------------------- +// Purpose: Displays the MOTD and basic server information +//----------------------------------------------------------------------------- +class CMessageWindowPanel : public CMenuPanel +{ +public: + CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullScreen, int iRemoveMe, int x, int y, int wide, int tall ); + +private: + CTransparentPanel *m_pBackgroundPanel; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Creates a new CMessageWindowPanel +// Output : CMenuPanel - interface to the panel +//----------------------------------------------------------------------------- +CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) +{ + return new CMessageWindowPanel( szMOTD, szTitle, iShadeFullscreen, iRemoveMe, x, y, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructs a message panel +//----------------------------------------------------------------------------- +CMessageWindowPanel::CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) : CMenuPanel( iShadeFullscreen ? 100 : 255, iRemoveMe, x, y, wide, tall ) +{ + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hMOTDText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the window + m_pBackgroundPanel = new CTransparentPanel( iShadeFullscreen ? 255 : 100, MOTD_WINDOW_X, MOTD_WINDOW_Y, MOTD_WINDOW_SIZE_X, MOTD_WINDOW_SIZE_Y ); + m_pBackgroundPanel->setParent( this ); + m_pBackgroundPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + m_pBackgroundPanel->setVisible( true ); + + int iXSize,iYSize,iXPos,iYPos; + m_pBackgroundPanel->getPos( iXPos,iYPos ); + m_pBackgroundPanel->getSize( iXSize,iYSize ); + + // Create the title + Label *pLabel = new Label( "", iXPos + MOTD_TITLE_X, iYPos + MOTD_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(szTitle); + + // Create the Scroll panel + ScrollPanel *pScrollPanel = new CTFScrollPanel( iXPos + XRES(16), iYPos + MOTD_TITLE_Y*2 + YRES(16), iXSize - XRES(32), iYSize - (YRES(48) + BUTTON_SIZE_Y*2) ); + pScrollPanel->setParent(this); + + //force the scrollbars on so clientClip will take them in account after the validate + pScrollPanel->setScrollBarAutoVisible(false, false); + pScrollPanel->setScrollBarVisible(true, true); + pScrollPanel->validate(); + + // Create the text panel + TextPanel *pText = new TextPanel( "", 0,0, 64,64); + pText->setParent( pScrollPanel->getClient() ); + + // get the font and colors from the scheme + pText->setFont( pSchemes->getFont(hMOTDText) ); + pSchemes->getFgColor( hMOTDText, r, g, b, a ); + pText->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hMOTDText, r, g, b, a ); + pText->setBgColor( r, g, b, a ); + pText->setText(szMOTD); + + // Get the total size of the MOTD text and resize the text panel + int iScrollSizeX, iScrollSizeY; + + // First, set the size so that the client's wdith is correct at least because the + // width is critical for getting the "wrapped" size right. + // You'll see a horizontal scroll bar if there is a single word that won't wrap in the + // specified width. + pText->getTextImage()->setSize(pScrollPanel->getClientClip()->getWide(), pScrollPanel->getClientClip()->getTall()); + pText->getTextImage()->getTextSizeWrapped( iScrollSizeX, iScrollSizeY ); + + // Now resize the textpanel to fit the scrolled size + pText->setSize( iScrollSizeX , iScrollSizeY ); + + //turn the scrollbars back into automode + pScrollPanel->setScrollBarAutoVisible(true, true); + pScrollPanel->setScrollBarVisible(false, false); + + pScrollPanel->validate(); + + CommandButton *pButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_OK" ), iXPos + XRES(16), iYPos + iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_TextWindow(HIDE_TEXTWINDOW)); + pButton->addActionSignal(new CMenuHandler_TextWindow(SHOW_CLASSDESC)); + pButton->setParent(this); + +} + + + + + + diff --git a/main/source/cl_dll/vgui_SchemeManager.cpp b/main/source/cl_dll/vgui_SchemeManager.cpp index 3c175ba1..4a7abd42 100644 --- a/main/source/cl_dll/vgui_SchemeManager.cpp +++ b/main/source/cl_dll/vgui_SchemeManager.cpp @@ -1,560 +1,572 @@ -//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: $ -// $Date: 2001/09/13 15:01:48 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_SchemeManager.cpp,v $ -// Revision 1.3 2001/09/13 15:01:48 Charlie -// - Merging with 1108 -// -// Revision 1.2 2001/09/12 16:34:26 Charlie -// - Slightly better error checking -// Revision 1.1.1.1.2.2 2001/09/13 14:42:30 Charlie -// - HL1108 -// -// Revision 1.1.1.1 2000/06/17 14:12:45 charlie -// Final version of new HL SDK. May not compile. -// Previous versions of my MSVC project files and utility .bat files. -// This is my starting point; there is no mod-specific code in here. -// -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "vgui_SchemeManager.h" -#include "common/cvardef.h" - -#include - - -cvar_t *g_CV_BitmapFonts; - - -void Scheme_Init() -{ - g_CV_BitmapFonts = gEngfuncs.pfnRegisterVariable("bitmapfonts", "1", 0); -} - - - -//----------------------------------------------------------------------------- -// Purpose: Scheme managers data container -//----------------------------------------------------------------------------- -class CSchemeManager::CScheme -{ -public: - enum { - SCHEME_NAME_LENGTH = 32, - FONT_NAME_LENGTH = 48, - FONT_FILENAME_LENGTH = 64, - }; - - // name - char schemeName[SCHEME_NAME_LENGTH]; - - // font - char fontName[FONT_NAME_LENGTH]; - - int fontSize; - int fontWeight; - - vgui::Font *font; - int ownFontPointer; // true if the font is ours to delete - - // scheme - byte fgColor[4]; - byte bgColor[4]; - byte armedFgColor[4]; - byte armedBgColor[4]; - byte mousedownFgColor[4]; - byte mousedownBgColor[4]; - byte borderColor[4]; - - // construction/destruction - CScheme(); - ~CScheme(); -}; - -CSchemeManager::CScheme::CScheme() -{ - schemeName[0] = 0; - fontName[0] = 0; - fontSize = 0; - fontWeight = 0; - font = NULL; - ownFontPointer = false; -} - -CSchemeManager::CScheme::~CScheme() -{ - // only delete our font pointer if we own it - if ( ownFontPointer ) - { - delete font; - } -} - -//----------------------------------------------------------------------------- -// Purpose: resolution information -// !! needs to be shared out -//----------------------------------------------------------------------------- -static int g_ResArray[] = -{ - 320, - 400, - 512, - 640, - 800, - 1024, - 1152, - 1280, - 1600 -}; -static int g_NumReses = sizeof(g_ResArray) / sizeof(int); - -static byte *LoadFileByResolution( const char *filePrefix, int xRes, const char *filePostfix ) -{ - // find our resolution in the res array - int resNum = g_NumReses - 1; - while ( g_ResArray[resNum] > xRes ) - { - resNum--; - - if ( resNum < 0 ) - return NULL; - } - - // try open the file - byte *pFile = NULL; - while ( 1 ) - { - - // try load - char fname[256]; - sprintf( fname, "%s%d%s", filePrefix, g_ResArray[resNum], filePostfix ); - pFile = gEngfuncs.COM_LoadFile( fname, 5, NULL ); - - if ( pFile ) - break; - - if ( resNum == 0 ) - return NULL; - - resNum--; - }; - - return pFile; -} - -static void ParseRGBAFromString( byte colorArray[4], const char *colorVector ) -{ - int r, g, b, a; - sscanf( colorVector, "%d %d %d %d", &r, &g, &b, &a ); - colorArray[0] = r; - colorArray[1] = g; - colorArray[2] = b; - colorArray[3] = a; -} - -//----------------------------------------------------------------------------- -// Purpose: initializes the scheme manager -// loading the scheme files for the current resolution -// Input : xRes - -// yRes - dimensions of output window -//----------------------------------------------------------------------------- -CSchemeManager::CSchemeManager( int xRes, int yRes ) -{ - // basic setup - m_pSchemeList = NULL; - m_iNumSchemes = 0; - - // find the closest matching scheme file to our resolution - char token[1024]; - char *pFile = (char*)LoadFileByResolution( "", xRes, "_textscheme.txt" ); - m_xRes = xRes; - - char *pFileStart = pFile; - - byte *pFontData; - int fontFileLength; - char fontFilename[512]; - - // - // Read the scheme descriptions from the text file, into a temporary array - // format is simply: - // = - // - // a of "SchemeName" signals a new scheme is being described - // - - const static int numTmpSchemes = 64; - static CScheme tmpSchemes[numTmpSchemes]; - memset( tmpSchemes, 0, sizeof(tmpSchemes) ); - int currentScheme = -1; - CScheme *pScheme = NULL; - - if ( !pFile ) - { - gEngfuncs.Con_DPrintf( "Unable to find *_textscheme.txt\n"); - goto buildDefaultFont; - } - - // record what has been entered so we can create defaults from the different values - bool hasFgColor, hasBgColor, hasArmedFgColor, hasArmedBgColor, hasMouseDownFgColor, hasMouseDownBgColor; - - pFile = gEngfuncs.COM_ParseFile( pFile, token ); - while ( strlen(token) > 0 && (currentScheme < numTmpSchemes) ) - { - // get the paramName name - static const int tokenSize = 64; - char paramName[tokenSize], paramValue[tokenSize]; - - strncpy( paramName, token, tokenSize ); - paramName[tokenSize-1] = 0; // ensure null termination - - // get the '=' character - pFile = gEngfuncs.COM_ParseFile( pFile, token ); - if ( stricmp( token, "=" ) ) - { - if ( currentScheme < 0 ) - { - gEngfuncs.Con_Printf( "error parsing font scheme text file at file start - expected '=', found '%s''\n", token ); - } - else - { - gEngfuncs.Con_Printf( "error parsing font scheme text file at scheme '%s' - expected '=', found '%s''\n", tmpSchemes[currentScheme].schemeName, token ); - } - break; - } - - // get paramValue - pFile = gEngfuncs.COM_ParseFile( pFile, token ); - strncpy( paramValue, token, tokenSize ); - paramValue[tokenSize-1] = 0; // ensure null termination - - // is this a new scheme? - if ( !stricmp(paramName, "SchemeName") ) - { - // setup the defaults for the current scheme - if ( pScheme ) - { - // foreground color defaults (normal -> armed -> mouse down) - if ( !hasFgColor ) - { - pScheme->fgColor[0] = pScheme->fgColor[1] = pScheme->fgColor[2] = pScheme->fgColor[3] = 255; - } - if ( !hasArmedFgColor ) - { - memcpy( pScheme->armedFgColor, pScheme->fgColor, sizeof(pScheme->armedFgColor) ); - } - if ( !hasMouseDownFgColor ) - { - memcpy( pScheme->mousedownFgColor, pScheme->armedFgColor, sizeof(pScheme->mousedownFgColor) ); - } - - // background color (normal -> armed -> mouse down) - if ( !hasBgColor ) - { - pScheme->bgColor[0] = pScheme->bgColor[1] = pScheme->bgColor[2] = pScheme->bgColor[3] = 0; - } - if ( !hasArmedBgColor ) - { - memcpy( pScheme->armedBgColor, pScheme->bgColor, sizeof(pScheme->armedBgColor) ); - } - if ( !hasMouseDownBgColor ) - { - memcpy( pScheme->mousedownBgColor, pScheme->armedBgColor, sizeof(pScheme->mousedownBgColor) ); - } - - // font size - if ( !pScheme->fontSize ) - { - pScheme->fontSize = 17; - } - if ( !pScheme->fontName[0] ) - { - strcpy( pScheme->fontName, "Arial" ); - } - } - - // create the new scheme - currentScheme++; - pScheme = &tmpSchemes[currentScheme]; - hasFgColor = hasBgColor = hasArmedFgColor = hasArmedBgColor = hasMouseDownFgColor = hasMouseDownBgColor = false; - - strncpy( pScheme->schemeName, paramValue, CScheme::SCHEME_NAME_LENGTH ); - pScheme->schemeName[CScheme::SCHEME_NAME_LENGTH-1] = '\0'; // ensure null termination of string - } - - if ( !pScheme ) - { - gEngfuncs.Con_Printf( "font scheme text file MUST start with a 'SchemeName'\n"); - break; - } - - // pull the data out into the scheme - if ( !stricmp(paramName, "FontName") ) - { - strncpy( pScheme->fontName, paramValue, CScheme::FONT_NAME_LENGTH ); - pScheme->fontName[CScheme::FONT_NAME_LENGTH-1] = 0; - } - else if ( !stricmp(paramName, "FontSize") ) - { - pScheme->fontSize = atoi( paramValue ); - } - else if ( !stricmp(paramName, "FontWeight") ) - { - pScheme->fontWeight = atoi( paramValue ); - } - else if ( !stricmp(paramName, "FgColor") ) - { - ParseRGBAFromString( pScheme->fgColor, paramValue ); - hasFgColor = true; - } - else if ( !stricmp(paramName, "BgColor") ) - { - ParseRGBAFromString( pScheme->bgColor, paramValue ); - hasBgColor = true; - } - else if ( !stricmp(paramName, "FgColorArmed") ) - { - ParseRGBAFromString( pScheme->armedFgColor, paramValue ); - hasArmedFgColor = true; - } - else if ( !stricmp(paramName, "BgColorArmed") ) - { - ParseRGBAFromString( pScheme->armedBgColor, paramValue ); - hasArmedBgColor = true; - } - else if ( !stricmp(paramName, "FgColorMousedown") ) - { - ParseRGBAFromString( pScheme->mousedownFgColor, paramValue ); - hasMouseDownFgColor = true; - } - else if ( !stricmp(paramName, "BgColorMousedown") ) - { - ParseRGBAFromString( pScheme->mousedownBgColor, paramValue ); - hasMouseDownBgColor = true; - } - else if ( !stricmp(paramName, "BorderColor") ) - { - ParseRGBAFromString( pScheme->borderColor, paramValue ); - hasMouseDownBgColor = true; - } - - // get the new token last, so we now if the loop needs to be continued or not - pFile = gEngfuncs.COM_ParseFile( pFile, token ); - } - - // free the file - gEngfuncs.COM_FreeFile( pFileStart ); - - -buildDefaultFont: - - // make sure we have at least 1 valid font - if ( currentScheme < 0 ) - { - currentScheme = 0; - strcpy( tmpSchemes[0].schemeName, "Default Scheme" ); - strcpy( tmpSchemes[0].fontName, "Arial" ); - tmpSchemes[0].fontSize = 0; - tmpSchemes[0].fgColor[0] = tmpSchemes[0].fgColor[1] = tmpSchemes[0].fgColor[2] = tmpSchemes[0].fgColor[3] = 255; - tmpSchemes[0].armedFgColor[0] = tmpSchemes[0].armedFgColor[1] = tmpSchemes[0].armedFgColor[2] = tmpSchemes[0].armedFgColor[3] = 255; - tmpSchemes[0].mousedownFgColor[0] = tmpSchemes[0].mousedownFgColor[1] = tmpSchemes[0].mousedownFgColor[2] = tmpSchemes[0].mousedownFgColor[3] = 255; - } - - // we have the full list of schemes in the tmpSchemes array - // now allocate the correct sized list - m_iNumSchemes = currentScheme + 1; // 0-based index - m_pSchemeList = new CScheme[ m_iNumSchemes ]; - - // copy in the data - memcpy( m_pSchemeList, tmpSchemes, sizeof(CScheme) * m_iNumSchemes ); - - // create the fonts - for ( int i = 0; i < m_iNumSchemes; i++ ) - { - m_pSchemeList[i].font = NULL; - - // see if the current font values exist in a previously loaded font - for ( int j = 0; j < i; j++ ) - { - // check if the font name, size, and weight are the same - if ( !stricmp(m_pSchemeList[i].fontName, m_pSchemeList[j].fontName) - && m_pSchemeList[i].fontSize == m_pSchemeList[j].fontSize - && m_pSchemeList[i].fontWeight == m_pSchemeList[j].fontWeight ) - { - // copy the pointer, but mark i as not owning it - m_pSchemeList[i].font = m_pSchemeList[j].font; - m_pSchemeList[i].ownFontPointer = false; - } - } - - // if we haven't found the font already, load it ourselves - if ( !m_pSchemeList[i].font ) - { - fontFileLength = -1; - pFontData = NULL; - - if(g_CV_BitmapFonts && g_CV_BitmapFonts->value) - { - sprintf(fontFilename, "gfx\\vgui\\fonts\\%d_%s.tga", m_xRes, m_pSchemeList[i].schemeName); - pFontData = gEngfuncs.COM_LoadFile( fontFilename, 5, &fontFileLength ); - if(!pFontData) - gEngfuncs.Con_Printf("Missing bitmap font: %s\n", fontFilename); - } - - m_pSchemeList[i].font = new vgui::Font( - m_pSchemeList[i].fontName, - pFontData, - fontFileLength, - m_pSchemeList[i].fontSize, - 0, - 0, - m_pSchemeList[i].fontWeight, - false, - false, - false, - false); - - m_pSchemeList[i].ownFontPointer = true; - } - - // fix up alpha values; VGUI uses 1-A (A=0 being solid, A=255 transparent) - m_pSchemeList[i].fgColor[3] = 255 - m_pSchemeList[i].fgColor[3]; - m_pSchemeList[i].bgColor[3] = 255 - m_pSchemeList[i].bgColor[3]; - m_pSchemeList[i].armedFgColor[3] = 255 - m_pSchemeList[i].armedFgColor[3]; - m_pSchemeList[i].armedBgColor[3] = 255 - m_pSchemeList[i].armedBgColor[3]; - m_pSchemeList[i].mousedownFgColor[3] = 255 - m_pSchemeList[i].mousedownFgColor[3]; - m_pSchemeList[i].mousedownBgColor[3] = 255 - m_pSchemeList[i].mousedownBgColor[3]; - } -} - -//----------------------------------------------------------------------------- -// Purpose: frees all the memory used by the scheme manager -//----------------------------------------------------------------------------- -CSchemeManager::~CSchemeManager() -{ - delete [] m_pSchemeList; - m_iNumSchemes = 0; -} - -//----------------------------------------------------------------------------- -// Purpose: Finds a scheme in the list, by name -// Input : char *schemeName - string name of the scheme -// Output : SchemeHandle_t handle to the scheme -//----------------------------------------------------------------------------- -SchemeHandle_t CSchemeManager::getSchemeHandle( const char *schemeName ) -{ - // iterate through the list - for ( int i = 0; i < m_iNumSchemes; i++ ) - { - if ( !stricmp(schemeName, m_pSchemeList[i].schemeName) ) - return i; - } - - return 0; -} - -//----------------------------------------------------------------------------- -// Purpose: always returns a valid scheme handle -// Input : schemeHandle - -// Output : CScheme -//----------------------------------------------------------------------------- -CSchemeManager::CScheme *CSchemeManager::getSafeScheme( SchemeHandle_t schemeHandle ) -{ - ASSERT(schemeHandle >= 0); - ASSERT(schemeHandle < m_iNumSchemes); - - if ( schemeHandle < m_iNumSchemes ) - return m_pSchemeList + schemeHandle; - - return m_pSchemeList; -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns the schemes pointer to a font -// Input : schemeHandle - -// Output : vgui::Font -//----------------------------------------------------------------------------- -vgui::Font *CSchemeManager::getFont( SchemeHandle_t schemeHandle ) -{ - return getSafeScheme( schemeHandle )->font; -} - -void CSchemeManager::getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->fgColor[0]; - g = pScheme->fgColor[1]; - b = pScheme->fgColor[2]; - a = pScheme->fgColor[3]; -} - -void CSchemeManager::getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->bgColor[0]; - g = pScheme->bgColor[1]; - b = pScheme->bgColor[2]; - a = pScheme->bgColor[3]; -} - -void CSchemeManager::getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->armedFgColor[0]; - g = pScheme->armedFgColor[1]; - b = pScheme->armedFgColor[2]; - a = pScheme->armedFgColor[3]; -} - -void CSchemeManager::getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->armedBgColor[0]; - g = pScheme->armedBgColor[1]; - b = pScheme->armedBgColor[2]; - a = pScheme->armedBgColor[3]; -} - -void CSchemeManager::getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->mousedownFgColor[0]; - g = pScheme->mousedownFgColor[1]; - b = pScheme->mousedownFgColor[2]; - a = pScheme->mousedownFgColor[3]; -} - -void CSchemeManager::getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->mousedownBgColor[0]; - g = pScheme->mousedownBgColor[1]; - b = pScheme->mousedownBgColor[2]; - a = pScheme->mousedownBgColor[3]; -} - -void CSchemeManager::getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) -{ - CScheme *pScheme = getSafeScheme( schemeHandle ); - r = pScheme->borderColor[0]; - g = pScheme->borderColor[1]; - b = pScheme->borderColor[2]; - a = pScheme->borderColor[3]; -} - - - +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: 2001/09/13 15:01:48 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_SchemeManager.cpp,v $ +// Revision 1.3 2001/09/13 15:01:48 Charlie +// - Merging with 1108 +// +// Revision 1.2 2001/09/12 16:34:26 Charlie +// - Slightly better error checking +// Revision 1.1.1.1.2.2 2001/09/13 14:42:30 Charlie +// - HL1108 +// +// Revision 1.1.1.1 2000/06/17 14:12:45 charlie +// Final version of new HL SDK. May not compile. +// Previous versions of my MSVC project files and utility .bat files. +// This is my starting point; there is no mod-specific code in here. +// +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "vgui_SchemeManager.h" +#include "common/cvardef.h" + +#include + + +cvar_t *g_CV_BitmapFonts; + + +void Scheme_Init() +{ + g_CV_BitmapFonts = gEngfuncs.pfnRegisterVariable("bitmapfonts", "1", 0); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Scheme managers data container +//----------------------------------------------------------------------------- +class CSchemeManager::CScheme +{ +public: + enum { + SCHEME_NAME_LENGTH = 32, + FONT_NAME_LENGTH = 48, + FONT_FILENAME_LENGTH = 64, + }; + + // name + char schemeName[SCHEME_NAME_LENGTH]; + + // font + char fontName[FONT_NAME_LENGTH]; + + int fontSize; + int fontWeight; + + vgui::Font *font; + int ownFontPointer; // true if the font is ours to delete + + // scheme + byte fgColor[4]; + byte bgColor[4]; + byte armedFgColor[4]; + byte armedBgColor[4]; + byte mousedownFgColor[4]; + byte mousedownBgColor[4]; + byte borderColor[4]; + + // construction/destruction + CScheme(); + ~CScheme(); +}; + +CSchemeManager::CScheme::CScheme() +{ + schemeName[0] = 0; + fontName[0] = 0; + fontSize = 0; + fontWeight = 0; + font = NULL; + ownFontPointer = false; +} + +CSchemeManager::CScheme::~CScheme() +{ + // only delete our font pointer if we own it + if ( ownFontPointer ) + { + delete font; + } +} + +//----------------------------------------------------------------------------- +// Purpose: resolution information +// !! needs to be shared out +//----------------------------------------------------------------------------- +static int g_ResArray[] = +{ + 320, + 400, + 512, + 640, + 800, + 1024, + 1152, + 1280, + 1600 +}; +static int g_NumReses = sizeof(g_ResArray) / sizeof(int); + +static byte *LoadFileByResolution( const char *filePrefix, int xRes, const char *filePostfix ) +{ + // find our resolution in the res array + int resNum = g_NumReses - 1; + while ( g_ResArray[resNum] > xRes ) + { + resNum--; + + if ( resNum < 0 ) + return NULL; + } + + // try open the file + byte *pFile = NULL; + while ( 1 ) + { + + // try load + char fname[256]; + sprintf( fname, "%s%d%s", filePrefix, g_ResArray[resNum], filePostfix ); + pFile = gEngfuncs.COM_LoadFile( fname, 5, NULL ); + + if ( pFile ) + break; + + if ( resNum == 0 ) + return NULL; + + resNum--; + }; + + return pFile; +} + +static void ParseRGBAFromString( byte colorArray[4], const char *colorVector ) +{ + int r, g, b, a; + sscanf( colorVector, "%d %d %d %d", &r, &g, &b, &a ); + colorArray[0] = r; + colorArray[1] = g; + colorArray[2] = b; + colorArray[3] = a; +} + +//----------------------------------------------------------------------------- +// Purpose: initializes the scheme manager +// loading the scheme files for the current resolution +// Input : xRes - +// yRes - dimensions of output window +//----------------------------------------------------------------------------- +CSchemeManager::CSchemeManager( int xRes, int yRes ) +{ + // basic setup + m_pSchemeList = NULL; + m_iNumSchemes = 0; + + // find the closest matching scheme file to our resolution + char token[1024]; + char *pFile = (char*)LoadFileByResolution( "", xRes, "_textscheme.txt" ); + m_xRes = xRes; + + char *pFileStart = pFile; + + byte *pFontData; + int fontFileLength; + char fontFilename[512]; + + // + // Read the scheme descriptions from the text file, into a temporary array + // format is simply: + // = + // + // a of "SchemeName" signals a new scheme is being described + // + + const static int numTmpSchemes = 64; + static CScheme tmpSchemes[numTmpSchemes]; + memset( tmpSchemes, 0, sizeof(tmpSchemes) ); + int currentScheme = -1; + CScheme *pScheme = NULL; + + if ( !pFile ) + { + gEngfuncs.Con_DPrintf( "Unable to find *_textscheme.txt\n"); + goto buildDefaultFont; + } + + // record what has been entered so we can create defaults from the different values + bool hasFgColor, hasBgColor, hasArmedFgColor, hasArmedBgColor, hasMouseDownFgColor, hasMouseDownBgColor; + + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + while ( strlen(token) > 0 && (currentScheme < numTmpSchemes) ) + { + // get the paramName name + static const int tokenSize = 64; + char paramName[tokenSize], paramValue[tokenSize]; + + strncpy( paramName, token, tokenSize ); + paramName[tokenSize-1] = 0; // ensure null termination + + // get the '=' character + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + if ( stricmp( token, "=" ) ) + { + if ( currentScheme < 0 ) + { + gEngfuncs.Con_Printf( "error parsing font scheme text file at file start - expected '=', found '%s''\n", token ); + } + else + { + gEngfuncs.Con_Printf( "error parsing font scheme text file at scheme '%s' - expected '=', found '%s''\n", tmpSchemes[currentScheme].schemeName, token ); + } + break; + } + + // get paramValue + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + strncpy( paramValue, token, tokenSize ); + paramValue[tokenSize-1] = 0; // ensure null termination + + // is this a new scheme? + if ( !stricmp(paramName, "SchemeName") ) + { + // setup the defaults for the current scheme + if ( pScheme ) + { + // foreground color defaults (normal -> armed -> mouse down) + if ( !hasFgColor ) + { + pScheme->fgColor[0] = pScheme->fgColor[1] = pScheme->fgColor[2] = pScheme->fgColor[3] = 255; + } + if ( !hasArmedFgColor ) + { + memcpy( pScheme->armedFgColor, pScheme->fgColor, sizeof(pScheme->armedFgColor) ); + } + if ( !hasMouseDownFgColor ) + { + memcpy( pScheme->mousedownFgColor, pScheme->armedFgColor, sizeof(pScheme->mousedownFgColor) ); + } + + // background color (normal -> armed -> mouse down) + if ( !hasBgColor ) + { + pScheme->bgColor[0] = pScheme->bgColor[1] = pScheme->bgColor[2] = pScheme->bgColor[3] = 0; + } + if ( !hasArmedBgColor ) + { + memcpy( pScheme->armedBgColor, pScheme->bgColor, sizeof(pScheme->armedBgColor) ); + } + if ( !hasMouseDownBgColor ) + { + memcpy( pScheme->mousedownBgColor, pScheme->armedBgColor, sizeof(pScheme->mousedownBgColor) ); + } + + // font size + if ( !pScheme->fontSize ) + { + pScheme->fontSize = 17; + } + if ( !pScheme->fontName[0] ) + { + strcpy( pScheme->fontName, "Arial" ); + } + } + + // create the new scheme + currentScheme++; + pScheme = &tmpSchemes[currentScheme]; + hasFgColor = hasBgColor = hasArmedFgColor = hasArmedBgColor = hasMouseDownFgColor = hasMouseDownBgColor = false; + + strncpy( pScheme->schemeName, paramValue, CScheme::SCHEME_NAME_LENGTH ); + pScheme->schemeName[CScheme::SCHEME_NAME_LENGTH-1] = '\0'; // ensure null termination of string + } + + if ( !pScheme ) + { + gEngfuncs.Con_Printf( "font scheme text file MUST start with a 'SchemeName'\n"); + break; + } + + // pull the data out into the scheme + if ( !stricmp(paramName, "FontName") ) + { + strncpy( pScheme->fontName, paramValue, CScheme::FONT_NAME_LENGTH ); + pScheme->fontName[CScheme::FONT_NAME_LENGTH-1] = 0; + } + else if ( !stricmp(paramName, "FontSize") ) + { + pScheme->fontSize = atoi( paramValue ); + } + else if ( !stricmp(paramName, "FontWeight") ) + { + pScheme->fontWeight = atoi( paramValue ); + } + else if ( !stricmp(paramName, "FgColor") ) + { + ParseRGBAFromString( pScheme->fgColor, paramValue ); + hasFgColor = true; + } + else if ( !stricmp(paramName, "BgColor") ) + { + ParseRGBAFromString( pScheme->bgColor, paramValue ); + hasBgColor = true; + } + else if ( !stricmp(paramName, "FgColorArmed") ) + { + ParseRGBAFromString( pScheme->armedFgColor, paramValue ); + hasArmedFgColor = true; + } + else if ( !stricmp(paramName, "BgColorArmed") ) + { + ParseRGBAFromString( pScheme->armedBgColor, paramValue ); + hasArmedBgColor = true; + } + else if ( !stricmp(paramName, "FgColorMousedown") ) + { + ParseRGBAFromString( pScheme->mousedownFgColor, paramValue ); + hasMouseDownFgColor = true; + } + else if ( !stricmp(paramName, "BgColorMousedown") ) + { + ParseRGBAFromString( pScheme->mousedownBgColor, paramValue ); + hasMouseDownBgColor = true; + } + else if ( !stricmp(paramName, "BorderColor") ) + { + ParseRGBAFromString( pScheme->borderColor, paramValue ); + hasMouseDownBgColor = true; + } + + // get the new token last, so we now if the loop needs to be continued or not + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + } + + // free the file + gEngfuncs.COM_FreeFile( pFileStart ); + + +buildDefaultFont: + + // make sure we have at least 1 valid font + if ( currentScheme < 0 ) + { + currentScheme = 0; + strcpy( tmpSchemes[0].schemeName, "Default Scheme" ); + strcpy( tmpSchemes[0].fontName, "Arial" ); + tmpSchemes[0].fontSize = 0; + tmpSchemes[0].fgColor[0] = tmpSchemes[0].fgColor[1] = tmpSchemes[0].fgColor[2] = tmpSchemes[0].fgColor[3] = 255; + tmpSchemes[0].armedFgColor[0] = tmpSchemes[0].armedFgColor[1] = tmpSchemes[0].armedFgColor[2] = tmpSchemes[0].armedFgColor[3] = 255; + tmpSchemes[0].mousedownFgColor[0] = tmpSchemes[0].mousedownFgColor[1] = tmpSchemes[0].mousedownFgColor[2] = tmpSchemes[0].mousedownFgColor[3] = 255; + } + + // we have the full list of schemes in the tmpSchemes array + // now allocate the correct sized list + m_iNumSchemes = currentScheme + 1; // 0-based index + m_pSchemeList = new CScheme[ m_iNumSchemes ]; + + // copy in the data + memcpy( m_pSchemeList, tmpSchemes, sizeof(CScheme) * m_iNumSchemes ); + + // create the fonts + for ( int i = 0; i < m_iNumSchemes; i++ ) + { + m_pSchemeList[i].font = NULL; + + // see if the current font values exist in a previously loaded font + for ( int j = 0; j < i; j++ ) + { + // check if the font name, size, and weight are the same + if ( !stricmp(m_pSchemeList[i].fontName, m_pSchemeList[j].fontName) + && m_pSchemeList[i].fontSize == m_pSchemeList[j].fontSize + && m_pSchemeList[i].fontWeight == m_pSchemeList[j].fontWeight ) + { + // copy the pointer, but mark i as not owning it + m_pSchemeList[i].font = m_pSchemeList[j].font; + m_pSchemeList[i].ownFontPointer = false; + } + } + + // if we haven't found the font already, load it ourselves + if ( !m_pSchemeList[i].font ) + { + fontFileLength = -1; + pFontData = NULL; + + if(g_CV_BitmapFonts && g_CV_BitmapFonts->value) + { + int fontRes = 640; + if (m_xRes >= 1600) + fontRes = 1600; + else if (m_xRes >= 1280) + fontRes = 1280; + else if (m_xRes >= 1152) + fontRes = 1152; + else if (m_xRes >= 1024) + fontRes = 1024; + else if (m_xRes >= 800) + fontRes = 800; + + sprintf(fontFilename, "gfx/vgui/fonts/%d_%s.tga", fontRes, m_pSchemeList[i].schemeName); + pFontData = gEngfuncs.COM_LoadFile( fontFilename, 5, &fontFileLength ); + if(!pFontData) + gEngfuncs.Con_Printf("Missing bitmap font: %s\n", fontFilename); + } + + m_pSchemeList[i].font = new vgui::Font( + m_pSchemeList[i].fontName, + pFontData, + fontFileLength, + m_pSchemeList[i].fontSize, + 0, + 0, + m_pSchemeList[i].fontWeight, + false, + false, + false, + false); + + m_pSchemeList[i].ownFontPointer = true; + } + + // fix up alpha values; VGUI uses 1-A (A=0 being solid, A=255 transparent) + m_pSchemeList[i].fgColor[3] = 255 - m_pSchemeList[i].fgColor[3]; + m_pSchemeList[i].bgColor[3] = 255 - m_pSchemeList[i].bgColor[3]; + m_pSchemeList[i].armedFgColor[3] = 255 - m_pSchemeList[i].armedFgColor[3]; + m_pSchemeList[i].armedBgColor[3] = 255 - m_pSchemeList[i].armedBgColor[3]; + m_pSchemeList[i].mousedownFgColor[3] = 255 - m_pSchemeList[i].mousedownFgColor[3]; + m_pSchemeList[i].mousedownBgColor[3] = 255 - m_pSchemeList[i].mousedownBgColor[3]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: frees all the memory used by the scheme manager +//----------------------------------------------------------------------------- +CSchemeManager::~CSchemeManager() +{ + delete [] m_pSchemeList; + m_iNumSchemes = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Finds a scheme in the list, by name +// Input : char *schemeName - string name of the scheme +// Output : SchemeHandle_t handle to the scheme +//----------------------------------------------------------------------------- +SchemeHandle_t CSchemeManager::getSchemeHandle( const char *schemeName ) +{ + // iterate through the list + for ( int i = 0; i < m_iNumSchemes; i++ ) + { + if ( !stricmp(schemeName, m_pSchemeList[i].schemeName) ) + return i; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: always returns a valid scheme handle +// Input : schemeHandle - +// Output : CScheme +//----------------------------------------------------------------------------- +CSchemeManager::CScheme *CSchemeManager::getSafeScheme( SchemeHandle_t schemeHandle ) +{ + ASSERT(schemeHandle >= 0); + ASSERT(schemeHandle < m_iNumSchemes); + + if ( schemeHandle < m_iNumSchemes ) + return m_pSchemeList + schemeHandle; + + return m_pSchemeList; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the schemes pointer to a font +// Input : schemeHandle - +// Output : vgui::Font +//----------------------------------------------------------------------------- +vgui::Font *CSchemeManager::getFont( SchemeHandle_t schemeHandle ) +{ + return getSafeScheme( schemeHandle )->font; +} + +void CSchemeManager::getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->fgColor[0]; + g = pScheme->fgColor[1]; + b = pScheme->fgColor[2]; + a = pScheme->fgColor[3]; +} + +void CSchemeManager::getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->bgColor[0]; + g = pScheme->bgColor[1]; + b = pScheme->bgColor[2]; + a = pScheme->bgColor[3]; +} + +void CSchemeManager::getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->armedFgColor[0]; + g = pScheme->armedFgColor[1]; + b = pScheme->armedFgColor[2]; + a = pScheme->armedFgColor[3]; +} + +void CSchemeManager::getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->armedBgColor[0]; + g = pScheme->armedBgColor[1]; + b = pScheme->armedBgColor[2]; + a = pScheme->armedBgColor[3]; +} + +void CSchemeManager::getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->mousedownFgColor[0]; + g = pScheme->mousedownFgColor[1]; + b = pScheme->mousedownFgColor[2]; + a = pScheme->mousedownFgColor[3]; +} + +void CSchemeManager::getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->mousedownBgColor[0]; + g = pScheme->mousedownBgColor[1]; + b = pScheme->mousedownBgColor[2]; + a = pScheme->mousedownBgColor[3]; +} + +void CSchemeManager::getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->borderColor[0]; + g = pScheme->borderColor[1]; + b = pScheme->borderColor[2]; + a = pScheme->borderColor[3]; +} + + + diff --git a/main/source/cl_dll/vgui_SchemeManager.h b/main/source/cl_dll/vgui_SchemeManager.h index 6fed4cc4..9120a332 100644 --- a/main/source/cl_dll/vgui_SchemeManager.h +++ b/main/source/cl_dll/vgui_SchemeManager.h @@ -1,51 +1,51 @@ -#ifndef VGUI_SCHEMEMANAGER_H -#define VGUI_SCHEMEMANAGER_H - -#include - - -// handle to an individual scheme -typedef int SchemeHandle_t; - - -// Register console variables, etc.. -void Scheme_Init(); - - -//----------------------------------------------------------------------------- -// Purpose: Handles the loading of text scheme description from disk -// supports different font/color/size schemes at different resolutions -//----------------------------------------------------------------------------- -class CSchemeManager -{ -public: - // initialization - CSchemeManager( int xRes, int yRes ); - virtual ~CSchemeManager(); - - // scheme handling - SchemeHandle_t getSchemeHandle( const char *schemeName ); - - // getting info from schemes - vgui::Font *getFont( SchemeHandle_t schemeHandle ); - void getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - void getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - void getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - void getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - void getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - void getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - void getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); - -private: - class CScheme; - CScheme *m_pSchemeList; - int m_iNumSchemes; - - // Resolution we were initted at. - int m_xRes; - - CScheme *getSafeScheme( SchemeHandle_t schemeHandle ); -}; - - +#ifndef VGUI_SCHEMEMANAGER_H +#define VGUI_SCHEMEMANAGER_H + +#include + + +// handle to an individual scheme +typedef int SchemeHandle_t; + + +// Register console variables, etc.. +void Scheme_Init(); + + +//----------------------------------------------------------------------------- +// Purpose: Handles the loading of text scheme description from disk +// supports different font/color/size schemes at different resolutions +//----------------------------------------------------------------------------- +class CSchemeManager +{ +public: + // initialization + CSchemeManager( int xRes, int yRes ); + virtual ~CSchemeManager(); + + // scheme handling + SchemeHandle_t getSchemeHandle( const char *schemeName ); + + // getting info from schemes + vgui::Font *getFont( SchemeHandle_t schemeHandle ); + void getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + +private: + class CScheme; + CScheme *m_pSchemeList; + int m_iNumSchemes; + + // Resolution we were initted at. + int m_xRes; + + CScheme *getSafeScheme( SchemeHandle_t schemeHandle ); +}; + + #endif \ No newline at end of file diff --git a/main/source/cl_dll/vgui_ScorePanel.cpp b/main/source/cl_dll/vgui_ScorePanel.cpp index e8beb785..833b305a 100644 --- a/main/source/cl_dll/vgui_ScorePanel.cpp +++ b/main/source/cl_dll/vgui_ScorePanel.cpp @@ -1,1677 +1,1677 @@ -//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: VGUI scoreboard -// -// $Workfile: $ -// $Date: 2002/10/24 21:13:15 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_ScorePanel.cpp,v $ -// Revision 1.15 2002/10/24 21:13:15 Flayra -// - Fixed gamma correction for auth icons -// -// Revision 1.14 2002/10/18 22:13:48 Flayra -// - Gamma-correction for auth icons -// -// Revision 1.13 2002/10/16 00:37:33 Flayra -// - Added support for authentication in scoreboard -// -// Revision 1.12 2002/09/09 19:42:55 Flayra -// - Fixed problem where scores were sometimes displayed for marines -// -// Revision 1.11 2002/08/31 18:02:11 Flayra -// - Work at VALVe -// -// Revision 1.10 2002/08/09 00:11:33 Flayra -// - Fixed scoreboard -// -// Revision 1.9 2002/07/08 16:15:13 Flayra -// - Refactored team color management -// -// Revision 1.8 2002/06/25 17:06:48 Flayra -// - Removed memory overwrite from hlcoder list -// -// Revision 1.7 2002/06/03 16:12:21 Flayra -// - Show player status for players on your team (LEV1, GEST, COMM, etc.) -// -// Revision 1.6 2002/04/16 19:30:21 Charlie -// - Fixed crash when holding tab right when joining server, added "REIN" status -// -// Revision 1.5 2002/03/27 21:17:18 Charlie -// - Scoreboard now shows alien scores, and doesn't show marine scores. Also draws DEAD and COMM indicators, and scoring is handled properly for aliens (points for kills, buildings) -// -// Revision 1.4 2002/03/08 02:37:52 Charlie -// - Refactored crappy-ass score panel. It's not perfect, but it's better. Removed TFC code, added DEAD and COMM tags to scoreboard. -// -// Revision 1.3 2001/11/13 17:51:02 Charlie -// - Increased max teams, changed team colors (allow aliens vs. aliens and fronts vs. fronts), general scoreboard support -// -// Revision 1.2 2001/09/13 22:28:01 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie -// - HL1108 -// -// -// $NoKeywords: $ -//============================================================================= - - -#include - -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ScorePanel.h" -#include "../game_shared/vgui_helpers.h" -#include "../game_shared/vgui_loadtga.h" -#include "mod/AvHConstants.h" -#include "mod/AvHTitles.h" -#include "mod/AvHBasePlayerWeaponConstants.h" -#include "vgui_SpectatorPanel.h" -#include "cl_dll/demo.h" -#include "mod/AvHServerVariables.h" -#include "util/STLUtil.h" -#include "ui/ScoreboardIcon.h" -/* @2014 -#include "common/itrackeruser.h" -extern ITrackerUser *g_pTrackerUser; -*/ -hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine -extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll -team_info_t g_TeamInfo[MAX_TEAMS+1]; -int g_IsSpectator[MAX_PLAYERS+1]; - -int HUD_IsGame( const char *game ); -int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ); - -// Scoreboard dimensions -#define SBOARD_TITLE_SIZE_Y YRES(22) - -#define X_BORDER XRES(4) - -void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable); -void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable); - -int ScorePanel_InitializeDemoPlayback(int inSize, unsigned char* inBuffer) -{ - int theBytesRead = 0; - - LoadData(&g_PlayerInfoList, inBuffer, (MAX_PLAYERS+1)*sizeof(hud_player_info_t), theBytesRead); - LoadData(&g_PlayerExtraInfo, inBuffer, (MAX_PLAYERS+1)*sizeof(extra_player_info_t), theBytesRead); - LoadData(&g_TeamInfo, inBuffer, (MAX_PLAYERS+1)*sizeof(team_info_t), theBytesRead); - LoadData(&g_IsSpectator, inBuffer, (MAX_PLAYERS+1)*sizeof(int), theBytesRead); - - return theBytesRead; -} - -void ScorePanel_InitializeDemoRecording() -{ - // Now save out team info - int theTotalSize = (MAX_PLAYERS + 1)*(sizeof(hud_player_info_t) + sizeof(extra_player_info_t) + sizeof(team_info_t) + sizeof(int)); - unsigned char* theCharArray = new unsigned char[theTotalSize]; - if(theCharArray) - { - int theCounter = 0; - SaveData(theCharArray, &g_PlayerInfoList, (MAX_PLAYERS+1)*sizeof(hud_player_info_t), theCounter); - SaveData(theCharArray, &g_PlayerExtraInfo, (MAX_PLAYERS+1)*sizeof(extra_player_info_t), theCounter); - SaveData(theCharArray, &g_TeamInfo, (MAX_PLAYERS+1)*sizeof(team_info_t), theCounter); - SaveData(theCharArray, &g_IsSpectator, (MAX_PLAYERS+1)*sizeof(int), theCounter); - - Demo_WriteBuffer(TYPE_PLAYERINFO, theTotalSize, theCharArray); - } -} - -// Column sizes -class SBColumnInfo -{ -public: - char *m_pTitle; // If null, ignore, if starts with #, it's localized, otherwise use the string directly. - int m_Width; // Based on 640 width. Scaled to fit other resolutions. - Label::Alignment m_Alignment; -}; - -// grid size is marked out for 640x480 screen - -SBColumnInfo g_ColumnInfo[NUM_COLUMNS] = -{ - {NULL, 24, Label::a_center}, // tracker column - {NULL, 24, Label::a_center}, // status icons - {NULL, 110, Label::a_center}, // name - {NULL, 56, Label::a_center}, // class - {NULL, 40, Label::a_center}, // resources - {NULL, 18, Label::a_center}, // weld - {NULL, 18, Label::a_center}, // weld - {"#SCORE", 35, Label::a_center}, // score - {"#KILLS", 35, Label::a_center}, // kills - {"#DEATHS", 35, Label::a_center}, // deaths - {"#LATENCY", 35, Label::a_center}, // ping - {"#VOICE", 40, Label::a_center}, - {NULL, 2, Label::a_center}, // blank column to take up the slack -}; - - -#define TEAM_NO 0 -#define TEAM_YES 1 -#define TEAM_SPECTATORS 2 -#define TEAM_BLANK 3 - -//----------------------------------------------------------------------------- -// ScorePanel::HitTestPanel. -//----------------------------------------------------------------------------- - -void ScorePanel::HitTestPanel::internalMousePressed(MouseCode code) -{ - for(int i=0;i<_inputSignalDar.getCount();i++) - { - _inputSignalDar[i]->mousePressed(code,this); - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -vgui::Color BuildColor( int R, int G, int B, float gamma ) -{ - ASSERT( gamma != 0 ); - return vgui::Color( R/gamma, G/gamma, B/gamma, 0 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Create the ScoreBoard panel -//----------------------------------------------------------------------------- -ScorePanel::ScorePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) -{ - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); - SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); - SchemeHandle_t hTinyScheme = pSchemes->getSchemeHandle("Scoreboard Tiny Text"); - Font *tfont = pSchemes->getFont(hTitleScheme); - Font *smallfont = pSchemes->getFont(hSmallScheme); - Font *tinyfont = pSchemes->getFont(hTinyScheme); - - setBgColor(0, 0, 0, 96); - m_pCurrentHighlightLabel = NULL; - m_iHighlightRow = -1; - // : 0001073 - m_pTrackerIcon = NULL; - m_pDevIcon = NULL; - m_pPTIcon = NULL; - m_pGuideIcon = NULL; - m_pServerOpIcon = NULL; - m_pContribIcon = NULL; - m_pCheatingDeathIcon = NULL; - m_pVeteranIcon = NULL; - - m_pHMG = NULL; - m_pMine = NULL; - m_pWeld = NULL; - m_pGL = NULL; - m_pSG = NULL; - - - m_pTrackerIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardtracker.tga"); - m_pDevIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboarddev.tga"); - m_pPTIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardpt.tga"); - m_pGuideIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardguide.tga"); - m_pServerOpIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardserverop.tga"); - m_pContribIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardcontrib.tga"); - m_pCheatingDeathIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardcd.tga"); - m_pVeteranIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardveteran.tga"); - - - - m_pHMG = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardhmg.tga"); - m_pMine = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardmine.tga"); - m_pWeld = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardwelder.tga"); - m_pGL = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardgl.tga"); - m_pSG = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardsg.tga"); - - m_iIconFrame = 0; - m_iLastFrameIncrementTime = gHUD.GetTimeOfLastUpdate(); - - // Initialize the top title. - m_TitleLabel.setFont(tfont); - m_TitleLabel.setText(""); - m_TitleLabel.setBgColor( 0, 0, 0, 255 ); - m_TitleLabel.setFgColor( Scheme::sc_primary1 ); - m_TitleLabel.setContentAlignment( vgui::Label::a_center ); - - LineBorder *border = new LineBorder(Color(60, 60, 60, 128)); - setBorder(border); - setPaintBorderEnabled(true); - - int xpos = g_ColumnInfo[0].m_Width + 3; - if (ScreenWidth() >= 640) - { - // only expand column size for res greater than 640 - xpos = XRES(xpos); - } - m_TitleLabel.setBounds(xpos, 4, wide, SBOARD_TITLE_SIZE_Y); - m_TitleLabel.setContentFitted(false); - m_TitleLabel.setParent(this); - - // Setup the header (labels like "name", "class", etc..). - m_HeaderGrid.SetDimensions(NUM_COLUMNS, 1); - m_HeaderGrid.SetSpacing(0, 0); - int i=0; - for( i=0; i < NUM_COLUMNS; i++) - { - if (g_ColumnInfo[i].m_pTitle && g_ColumnInfo[i].m_pTitle[0] == '#') - m_HeaderLabels[i].setText(CHudTextMessage::BufferedLocaliseTextString(g_ColumnInfo[i].m_pTitle)); - else if(g_ColumnInfo[i].m_pTitle) - m_HeaderLabels[i].setText(g_ColumnInfo[i].m_pTitle); - - int xwide = g_ColumnInfo[i].m_Width; - if (ScreenWidth() >= 640) - { - xwide = XRES(xwide); - } - else if (ScreenWidth() == 400) - { - // hack to make 400x300 resolution scoreboard fit - if (i == 1) - { - // reduces size of player name cell - xwide -= 28; - } - else if (i == 0) - { - // tracker icon cell - xwide -= 8; - } - } - - m_HeaderGrid.SetColumnWidth(i, xwide); - m_HeaderGrid.SetEntry(i, 0, &m_HeaderLabels[i]); - - m_HeaderLabels[i].setBgColor(0,0,0,255); - m_HeaderLabels[i].setBgColor(0,0,0,255); - - int theColorIndex = 0; - Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); - int theR, theG, theB, theA; - gammaAdjustedTeamColor.getColor(theR, theG, theB, theA); - m_HeaderLabels[i].setFgColor(theR, theG, theB, theA); - - m_HeaderLabels[i].setFont(smallfont); - m_HeaderLabels[i].setContentAlignment(g_ColumnInfo[i].m_Alignment); - - int yres = 12; - if (ScreenHeight() >= 480) - { - yres = YRES(yres); - } - m_HeaderLabels[i].setSize(50, yres); - } - - // Set the width of the last column to be the remaining space. - int ex, ey, ew, eh; - m_HeaderGrid.GetEntryBox(NUM_COLUMNS - 2, 0, ex, ey, ew, eh); - m_HeaderGrid.SetColumnWidth(NUM_COLUMNS - 1, (wide - X_BORDER) - (ex + ew)); - - m_HeaderGrid.AutoSetRowHeights(); - m_HeaderGrid.setBounds(X_BORDER, SBOARD_TITLE_SIZE_Y, wide - X_BORDER*2, m_HeaderGrid.GetRowHeight(0)); - m_HeaderGrid.setParent(this); - m_HeaderGrid.setBgColor(0,0,0,255); - - - // Now setup the listbox with the actual player data in it. - int headerX, headerY, headerWidth, headerHeight; - m_HeaderGrid.getBounds(headerX, headerY, headerWidth, headerHeight); - m_PlayerList.setBounds(headerX, headerY+headerHeight, headerWidth, tall - headerY - headerHeight - 6); - m_PlayerList.setBgColor(0,0,0,255); - m_PlayerList.setParent(this); - - for(int row=0; row < NUM_ROWS; row++) - { - CGrid *pGridRow = &m_PlayerGrids[row]; - - pGridRow->SetDimensions(NUM_COLUMNS, 1); - - for(int col=0; col < NUM_COLUMNS; col++) - { - m_PlayerEntries[col][row].setContentFitted(false); - m_PlayerEntries[col][row].setRow(row); - m_PlayerEntries[col][row].addInputSignal(this); - pGridRow->SetEntry(col, 0, &m_PlayerEntries[col][row]); - } - - pGridRow->setBgColor(0,0,0,255); -// pGridRow->SetSpacing(2, 0);f - pGridRow->SetSpacing(0, 0); - pGridRow->CopyColumnWidths(&m_HeaderGrid); - pGridRow->AutoSetRowHeights(); - pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); - pGridRow->RepositionContents(); - - m_PlayerList.AddItem(pGridRow); - } - - - // Add the hit test panel. It is invisible and traps mouse clicks so we can go into squelch mode. - m_HitTestPanel.setBgColor(0,0,0,255); - m_HitTestPanel.setParent(this); - m_HitTestPanel.setBounds(0, 0, wide, tall); - m_HitTestPanel.addInputSignal(this); - - m_pCloseButton = new CommandButton( "x", wide-XRES(12 + 4), YRES(2), XRES( 12 ) , YRES( 12 ) ); - m_pCloseButton->setParent( this ); - m_pCloseButton->addActionSignal( new CMenuHandler_StringCommandWatch( "-showscores", true ) ); - m_pCloseButton->setBgColor(0,0,0,255); - m_pCloseButton->setFgColor( 255, 255, 255, 0 ); - m_pCloseButton->setFont(tfont); - m_pCloseButton->setBoundKey( (char)255 ); - m_pCloseButton->setContentAlignment(Label::a_center); - Initialize(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Called each time a new level is started. -//----------------------------------------------------------------------------- -void ScorePanel::Initialize( void ) -{ - // Clear out scoreboard data - m_iLastKilledBy = 0; - m_fLastKillTime = 0; - m_iPlayerNum = 0; - m_iNumTeams = 0; - // : 0001073 -// for( int counter = 0; counter < MAX_PLAYERS+1; counter++ ) -// { -// delete g_PlayerExtraInfo[counter].icon; -// } - - memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); - memset( g_TeamInfo, 0, sizeof g_TeamInfo ); -} - -bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ) -{ - return !!gEngfuncs.GetPlayerUniqueID( iPlayer, playerID ); -} -//----------------------------------------------------------------------------- -// Purpose: Recalculate the internal scoreboard data -//----------------------------------------------------------------------------- -//@linux make snprintf work for win32 -#ifdef _WIN32 -#define snprintf _snprintf -#endif -void ScorePanel::Update() -{ - - // Set the title - char title[128]; - - char theServerName[MAX_SERVERNAME_LENGTH+1]; - if (gViewPort->m_szServerName) - { - memset(theServerName, 0, MAX_SERVERNAME_LENGTH+1); - int iServerNameLength = max((int)strlen(gViewPort->m_szServerName),MAX_SERVERNAME_LENGTH); - //strncat(theServerName, gViewPort->m_szServerName, iServerNameLength); Buffer Overflow? - snprintf(theServerName, MAX_SERVERNAME_LENGTH, "%s%s",theServerName ,gViewPort->m_szServerName); - } - theServerName[MAX_SERVERNAME_LENGTH]=0; - char theMapName[MAX_MAPNAME_LENGTH+1]; - sprintf(theMapName, "%s", gHUD.GetMapName().c_str()); - - int theTimeElapsed = gHUD.GetGameTime(); - char elapsedString[64]; - if ( theTimeElapsed > 0 ) { - int theMinutesElapsed = theTimeElapsed/60; - int theSecondsElapsed = theTimeElapsed%60; - sprintf(elapsedString, "Game time: %d:%02d", theMinutesElapsed, theSecondsElapsed); - } - else { - sprintf(elapsedString, ""); - } - - sprintf(title, "%32s Map: %s %s", theServerName, theMapName, elapsedString); - - m_TitleLabel.setText(title); - - int theColorIndex = 0; - - // Set gamma-correct title color - - Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); - - int theR, theG, theB, theA; - gammaAdjustedTeamColor.getColor(theR, theG, theB, theA); - - m_TitleLabel.setFgColor(theR, theG, theB, theA); - - m_iRows = 0; - gViewPort->GetAllPlayersInfo(); - - // Clear out sorts - int i = 0; - for (i = 0; i < NUM_ROWS; i++) - { - m_iSortedRows[i] = 0; - m_iIsATeam[i] = TEAM_IND; - } - - // Fix for memory overrun bug - - for (i = 0; i < MAX_PLAYERS; i++) - { - m_bHasBeenSorted[i] = false; - } - - SortTeams(); - - // set scrollbar range - m_PlayerList.SetScrollRange(m_iRows); - - FillGrid(); - if ( gViewPort->m_pSpectatorPanel->m_menuVisible ) - { - m_pCloseButton->setVisible ( true ); - } - else - { - m_pCloseButton->setVisible ( false ); - } - -} - -//----------------------------------------------------------------------------- -// Purpose: Sort all the teams -//----------------------------------------------------------------------------- -void ScorePanel::SortTeams() -{ - // clear out team scores - float theCurrentTime = gHUD.GetTimeOfLastUpdate(); - int i=0; - int j=0; - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( !g_TeamInfo[i].scores_overriden ) - { - g_TeamInfo[i].score =0; - } - g_TeamInfo[i].frags = g_TeamInfo[i].deaths = g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; - } - - // recalc the team scores, then draw them - for ( i = 1; i <= MAX_PLAYERS; i++ ) - { - if ( g_PlayerInfoList[i].name == NULL ) - continue; // empty player slot, skip - - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // find what team this player is in - for ( j = 1; j <= m_iNumTeams; j++ ) - { - if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) - break; - } - if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy - continue; - - if ( !g_TeamInfo[j].scores_overriden ) - { - g_TeamInfo[j].score += g_PlayerExtraInfo[i].score; - } - - g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; - g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; - g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; - g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; - - if ( g_PlayerInfoList[i].thisplayer ) - g_TeamInfo[j].ownteam = TRUE; - else - g_TeamInfo[j].ownteam = FALSE; - - // Set the team's number (used for team colors) - g_TeamInfo[j].teamnumber = g_PlayerExtraInfo[i].teamnumber; - } - - // find team ping/packetloss averages - for ( i = 1; i <= m_iNumTeams; i++ ) - { - g_TeamInfo[i].already_drawn = FALSE; - - if ( g_TeamInfo[i].players > 0 ) - { - g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - } - } - vector teams; - if ( gHUD.GetHUDTeam() == TEAM_TWO || gHUD.GetHUDTeam() == TEAM_FOUR ) { - SortActivePlayers(kAlien1Team); - SortActivePlayers(kMarine1Team); - SortActivePlayers(kAlien2Team); - SortActivePlayers(kMarine2Team); - } - else { - SortActivePlayers(kMarine1Team); - SortActivePlayers(kAlien1Team); - SortActivePlayers(kMarine2Team); - SortActivePlayers(kAlien2Team); - } - - SortActivePlayers(kSpectatorTeam); - SortActivePlayers(kUndefinedTeam); -} - -void ScorePanel::SortActivePlayers(char* inTeam, bool inSortByEntityIndex) -{ - for(int i = 1; i <= m_iNumTeams; i++) - { - if(!strcmp(g_TeamInfo[i].name, inTeam)) - { - int best_team = i; - - // Put this team in the sorted list - m_iSortedRows[ m_iRows ] = best_team; - m_iIsATeam[ m_iRows ] = TEAM_YES; - g_TeamInfo[best_team].already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get sorted again - m_iRows++; - - // Now sort all the players on this team - SortPlayers(0, g_TeamInfo[best_team].name, inSortByEntityIndex); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Sort a list of players -//----------------------------------------------------------------------------- -void ScorePanel::SortPlayers( int iTeam, char *team, bool inSortByEntityIndex) -{ - bool bCreatedTeam = false; - - // draw the players, in order, and restricted to team if set - while ( 1 ) - { - // Find the top ranking player - int theBestTotalScore = -99999; - int theBestDeaths = 0; - int theBestPlayer = 0; - - for ( int i = 1; i <= MAX_PLAYERS; i++ ) - { - if ( m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( i ); - - if ( ent && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) - { - extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; - - // Sort by player index to mask marine status - if(inSortByEntityIndex) - { - if((theBestPlayer == 0) || (i < theBestPlayer)) - { - theBestPlayer = i; - } - } - else - { - // overall rank = score + kills (with least deaths breaking ties) - int thePlayerScore = pl_info->score; - int thePlayerDeaths = pl_info->deaths; - if((thePlayerScore > theBestTotalScore) || ((thePlayerScore == theBestTotalScore) && (pl_info->deaths < theBestDeaths))) - { - theBestPlayer = i; - theBestTotalScore = thePlayerScore; - theBestDeaths = thePlayerDeaths; - } - } - } - } - } - - if ( !theBestPlayer ) - break; - - // If we haven't created the Team yet, do it first - if (!bCreatedTeam && iTeam) - { - m_iIsATeam[ m_iRows ] = iTeam; - m_iRows++; - - bCreatedTeam = true; - } - - // Put this player in the sorted list - m_iSortedRows[ m_iRows ] = theBestPlayer; - m_bHasBeenSorted[ theBestPlayer ] = true; - m_iRows++; - } - - if (team) - { - m_iIsATeam[m_iRows++] = TEAM_BLANK; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Recalculate the existing teams in the match -//----------------------------------------------------------------------------- -void ScorePanel::RebuildTeams() -{ - // clear out player counts from teams - int i=0; - int j=0; - for ( i = 1; i <= m_iNumTeams; i++ ) - { - g_TeamInfo[i].players = 0; - } - - // rebuild the team list - gViewPort->GetAllPlayersInfo(); - m_iNumTeams = 0; - for ( i = 1; i <= MAX_PLAYERS; i++ ) - { - if ( g_PlayerInfoList[i].name == NULL ) - continue; - - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // is this player in an existing team? - for ( j = 1; j <= m_iNumTeams; j++ ) - { - if ( g_TeamInfo[j].name[0] == '\0' ) - break; - - if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) - break; - } - - if ( j > m_iNumTeams ) - { // they aren't in a listed team, so make a new one - // search through for an empty team slot - for ( j = 1; j <= m_iNumTeams; j++ ) - { - if ( g_TeamInfo[j].name[0] == '\0' ) - break; - } - m_iNumTeams = max( j, m_iNumTeams ); - strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); - g_TeamInfo[j].players = 0; - } - - g_TeamInfo[j].players++; - } - - // clear out any empty teams - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( g_TeamInfo[i].players < 1 ) - memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); - } - - // Update the scoreboard - Update(); -} - -//----------------------------------------------------------------------------- - -int ScorePanel::GetIconFrame(void) -{ - const static int kIconFrameDuration = 0.25; - - int current_time = gHUD.GetTimeOfLastUpdate(); - if( (m_iLastFrameIncrementTime - current_time) > kIconFrameDuration ) - { - m_iLastFrameIncrementTime = current_time; - m_iIconFrame++; - if( m_iIconFrame >= 1000 ) - { - m_iIconFrame = 0; - } - } - return m_iIconFrame; -} - -//----------------------------------------------------------------------------- - -void ScorePanel::FillGrid() -{ - bool isNsMode=( strnicmp(gHUD.GetMapName().c_str(), "ns_", 3) == 0 ); - - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - SchemeHandle_t hScheme = pSchemes->getSchemeHandle("Scoreboard Text"); - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); - SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); - SchemeHandle_t hTinyScheme = pSchemes->getSchemeHandle("Scoreboard Tiny Text"); - - Font *sfont = pSchemes->getFont(hScheme); - Font *tfont = pSchemes->getFont(hTitleScheme); - Font *smallfont = pSchemes->getFont(hSmallScheme); - Font *tinyfont = pSchemes->getFont(hTinyScheme); - - // update highlight position - int x, y; - getApp()->getCursorPos(x, y); - cursorMoved(x, y, this); - - // remove highlight row if we're not in squelch mode - if (!GetClientVoiceMgr()->IsInSquelchMode()) - { - m_iHighlightRow = -1; - } - - bool bNextRowIsGap = false; - m_HeaderLabels[COLUMN_EXTRA].setText(""); - m_HeaderLabels[COLUMN_MINE].setText(""); - m_HeaderLabels[COLUMN_WELD].setText(""); - if ( isNsMode ) { - if ( gHUD.GetHUDTeam() == TEAM_ONE || gHUD.GetHUDTeam() == TEAM_THREE ) { - m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLWEAP")); - } - else if ( gHUD.GetHUDTeam() == TEAM_TWO || gHUD.GetHUDTeam() == TEAM_FOUR ) { - m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLRES")); - } - } - else { - if ( gHUD.GetHUDTeam() != TEAM_IND && gHUD.GetHUDTeam() != TEAM_SPECT ) - m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLLEVEL")); - } - - for(int row=0; row < NUM_ROWS; row++) - { - CGrid *pGridRow = &m_PlayerGrids[row]; - pGridRow->SetRowUnderline(0, false, 0, 0, 0, 0, 0); - - if(row >= m_iRows) - { - for(int col=0; col < NUM_COLUMNS; col++) - m_PlayerEntries[col][row].setVisible(false); - - continue; - } - - bool bRowIsGap = false; - if (bNextRowIsGap) - { - bNextRowIsGap = false; - bRowIsGap = true; - } - - // Get the player's data - int theSortedRow = m_iSortedRows[row]; - hud_player_info_t* pl_info = &g_PlayerInfoList[theSortedRow]; - extra_player_info_t* theExtraPlayerInfo = &g_PlayerExtraInfo[theSortedRow]; - int thePlayerClass = theExtraPlayerInfo->playerclass; - short theTeamNumber = theExtraPlayerInfo->teamnumber; - string theCustomIcon = (string)theExtraPlayerInfo->customicon; -// : 0001073 - short thePlayerAuthentication = theExtraPlayerInfo->auth; - bool thePlayerIsDead = false; - switch( thePlayerClass ) - { - case PLAYERCLASS_DEAD_MARINE: - case PLAYERCLASS_DEAD_ALIEN: - case PLAYERCLASS_REINFORCING: - thePlayerIsDead = true; - break; - } - - // Code to test DEBUG -#if 0 - #ifdef DEBUG - extern int gGlobalDebugAuth; - thePlayerAuthentication = 1; - thePlayerAuthentication <<= gGlobalDebugAuth; - #endif -#endif - - team_info_t* team_info = &g_TeamInfo[m_iSortedRows[row]]; - int theColorIndex = theTeamNumber % iNumberOfTeamColors; - - int theLocalPlayerTeam = 0; - if(gEngfuncs.GetLocalPlayer()) - { - theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; - } - - for(int col=0; col < NUM_COLUMNS; col++) - { - CLabelHeader *pLabel = &m_PlayerEntries[col][row]; - - pLabel->setVisible(true); - pLabel->setText2(""); - pLabel->setImage(NULL); - pLabel->setFont(sfont); - pLabel->setTextOffset(0, 0); - - int rowheight = 13; - if (ScreenHeight() > 480) - { - rowheight = YRES(rowheight); - } - else - { - // more tweaking, make sure icons fit at low res - rowheight = 15; - } - pLabel->setSize(pLabel->getWide(), rowheight); - pLabel->setBgColor(0, 0, 0, 255); - - char sz[128]; - - Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); - pLabel->setFgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 0); - - if (m_iIsATeam[row] == TEAM_BLANK) - { - pLabel->setText(" "); - continue; - } - else if ( m_iIsATeam[row] == TEAM_YES ) - { - theColorIndex = team_info->teamnumber % iNumberOfTeamColors; - - // team color text for team names - - - - // different height for team header rows - rowheight = 20; - if (ScreenHeight() >= 480) - { - rowheight = YRES(rowheight); - } - pLabel->setSize(pLabel->getWide(), rowheight); - pLabel->setFont(tfont); - - pGridRow->SetRowUnderline( 0, - true, - YRES(3), - gammaAdjustedTeamColor[0], - gammaAdjustedTeamColor[1], - gammaAdjustedTeamColor[2], - 0 ); - } - else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) - { - // grey text for spectators - pLabel->setFgColor(100, 100, 100, 0); - - // different height for team header rows - rowheight = 20; - if (ScreenHeight() >= 480) - { - rowheight = YRES(rowheight); - } - pLabel->setSize(pLabel->getWide(), rowheight); - pLabel->setFont(tfont); - - pGridRow->SetRowUnderline(0, true, YRES(3), 100, 100, 100, 0); - } - else - { - if(thePlayerIsDead) - { - pLabel->setFgColor(255, 0, 0, 0); - } - else - { - // team color text for player names - pLabel->setFgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 0); - } - - // Set background color - if ( pl_info && pl_info->thisplayer ) // if it is their name, draw it a different color - { - // Highlight this player - pLabel->setFgColor(Scheme::sc_white); - pLabel->setBgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 196 ); - } - else if ( theSortedRow == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) - { - // Killer's name - pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); - } - } - - // Align - switch(col) - { - case COLUMN_NAME: - case COLUMN_CLASS: - pLabel->setContentAlignment( vgui::Label::a_west ); - break; - - case COLUMN_TRACKER: - case COLUMN_RANK_ICON: - case COLUMN_VOICE: - pLabel->setContentAlignment( vgui::Label::a_center ); - break; - - case COLUMN_SCORE: - case COLUMN_KILLS: - case COLUMN_EXTRA: - case COLUMN_MINE: - case COLUMN_WELD: - case COLUMN_DEATHS: - case COLUMN_LATENCY: - default: - pLabel->setContentAlignment( vgui::Label::a_center ); - break; - } - - // Fill out with the correct data - strcpy(sz, ""); - if ( m_iIsATeam[row] ) - { - char sz2[128]; - - switch (col) - { - case COLUMN_NAME: - if ( m_iIsATeam[row] == TEAM_SPECTATORS ) - { - sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); - } - else - { - if(team_info) - { - sprintf( sz2, gViewPort->GetTeamName(team_info->teamnumber) ); - } - } - - strcpy(sz, sz2); - - // Append the number of players - if ( m_iIsATeam[row] == TEAM_YES && team_info) - { - if (team_info->players == 1) - { - sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player" ) ); - } - else - { - sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player_plural" ) ); - } - - pLabel->setText2(sz2); - pLabel->setFont2(smallfont); - } - break; - case COLUMN_VOICE: - break; - case COLUMN_CLASS: - break; - case COLUMN_SCORE: - if ((m_iIsATeam[row] == TEAM_YES) && team_info && (theLocalPlayerTeam == team_info->teamnumber || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER))) - sprintf(sz, "%d", team_info->score); - break; - case COLUMN_MINE: - break; - case COLUMN_WELD: - break; - case COLUMN_EXTRA: - break; - case COLUMN_KILLS: - if ((m_iIsATeam[row] == TEAM_YES) && team_info) - sprintf(sz, "%d", team_info->frags ); - break; - case COLUMN_DEATHS: - if ((m_iIsATeam[row] == TEAM_YES) && team_info) - sprintf(sz, "%d", team_info->deaths ); - break; - case COLUMN_LATENCY: - if ((m_iIsATeam[row] == TEAM_YES) && team_info) - sprintf(sz, "%d", team_info->ping ); - break; - default: - break; - } - } - else - { - // Are these stats for an enemy? Score and other stats shouldn't be drawn for enemies. - bool theIsForEnemy = false; - - int theLocalPlayerTeam = 0; - if(gEngfuncs.GetLocalPlayer()) - { - theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; - } - - if((theLocalPlayerTeam != 0) && (theExtraPlayerInfo->teamnumber != theLocalPlayerTeam)) - { - theIsForEnemy = true; - } - - switch (col) - { - case COLUMN_NAME: - /* - if (g_pTrackerUser) - { - int playerSlot = m_iSortedRows[row]; - int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); - const char *trackerName = g_pTrackerUser->GetUserName(trackerID); - if (trackerName && *trackerName) - { - sprintf(sz, " (%s)", trackerName); - pLabel->setText2(sz); - } - } - */ - if(pl_info) - { - sprintf(sz, "%s ", pl_info->name); - } - break; - case COLUMN_VOICE: - sz[0] = 0; - // in HLTV mode allow spectator to turn on/off commentator voice - if (pl_info && (!pl_info->thisplayer || gEngfuncs.IsSpectateOnly())) - { - GetClientVoiceMgr()->UpdateSpeakerImage(pLabel, theSortedRow); - } - break; - case COLUMN_CLASS: - // No class for other team's members (unless allied or spectator, and make sure player is on our team) - strcpy(sz, ""); - - if(team_info && ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER))) - { - switch(thePlayerClass) - { - case (int)(PLAYERCLASS_DEAD_MARINE): - case (int)(PLAYERCLASS_DEAD_ALIEN): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassDead)); - break; - case (int)(PLAYERCLASS_REINFORCING): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassReinforcing)); - break; - case (int)(PLAYERCLASS_REINFORCINGCOMPLETE): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassReinforcingComplete)); - break; - case (int)(PLAYERCLASS_ALIVE_JETPACK_MARINE): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassJetpackMarine)); - break; - case (int)(PLAYERCLASS_ALIVE_HEAVY_MARINE): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassHeavyMarine)); - break; - case (int)(PLAYERCLASS_COMMANDER): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassCommander)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL1): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel1)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL2): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel2)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL3): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel3)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL4): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel4)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL5): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel5)); - break; - case (int)(PLAYERCLASS_ALIVE_DIGESTING): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassDigesting)); - break; - case (int)(PLAYERCLASS_ALIVE_GESTATING): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassGestating)); - break; - default: - break; - } - } - break; - - case COLUMN_RANK_ICON: -// : 0001073 -#ifdef USE_OLDAUTH - // Check if we have authority. Right now these override the tracker icons. Listed in increasing order of "importance". - if(thePlayerAuthentication & PLAYERAUTH_CHEATINGDEATH) - { - // Red - pLabel->setImage(m_pCheatingDeathIcon); - pLabel->setFgColorAsImageColor(false); - m_pCheatingDeathIcon->setColor(BuildColor(255, 69, 9, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_VETERAN) - { - // Yellow - pLabel->setImage(m_pVeteranIcon); - pLabel->setFgColorAsImageColor(false); - m_pVeteranIcon->setColor(BuildColor(248, 252, 0, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_BETASERVEROP) - { - // Whitish - pLabel->setImage(m_pServerOpIcon); - pLabel->setFgColorAsImageColor(false); - m_pServerOpIcon->setColor(BuildColor(220, 220, 220, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_CONTRIBUTOR) - { - // Light blue - pLabel->setImage(m_pContribIcon); - pLabel->setFgColorAsImageColor(false); - m_pContribIcon->setColor(BuildColor(117, 214, 241, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_GUIDE) - { - // Magenta - pLabel->setImage(m_pGuideIcon); - pLabel->setFgColorAsImageColor(false); - m_pGuideIcon->setColor(BuildColor(208, 16, 190, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_PLAYTESTER) - { - // Orange - pLabel->setImage(m_pPTIcon); - pLabel->setFgColorAsImageColor(false); - m_pPTIcon->setColor(BuildColor(255, 167, 54, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_DEVELOPER) - { - // TSA blue - pLabel->setImage(m_pDevIcon); - pLabel->setFgColorAsImageColor(false); - m_pDevIcon->setColor(BuildColor(100, 215, 255, gHUD.GetGammaSlope())); - } - - if(thePlayerAuthentication & PLAYERAUTH_SERVEROP) - { - // Bright green - pLabel->setImage(m_pServerOpIcon); - pLabel->setFgColorAsImageColor(false); - m_pServerOpIcon->setColor(BuildColor(0, 255, 0, gHUD.GetGammaSlope())); - } - - // Allow custom icons to override other general icons - if(thePlayerAuthentication & PLAYERAUTH_CUSTOM) - { - if(theCustomIcon != "") - { - string theIconName = theCustomIcon.substr(0, strlen(theCustomIcon.c_str()) - 3); - string theFullCustomIconString = string("gfx/vgui/640_") + theIconName + string(".tga"); - - vgui::BitmapTGA *pIcon = GetIconPointer(theCustomIcon); - - //Icon hasnt been loaded, load it now and add it to list of icons. - if(pIcon == NULL) - { - pIcon = vgui_LoadTGANoInvertAlpha(theFullCustomIconString.c_str()); - - if(pIcon) - m_CustomIconList.push_back( make_pair(pIcon, theCustomIcon) ); - } - /* //@2014 to do - if(pIcon) - { - pLabel->setImage(pIcon); - pLabel->setFgColorAsImageColor(false); - - // Parse color (last 3 bytes are the RGB values 1-9) - string theColor = theCustomIcon.substr( strlen(theCustomIcon.c_str())-3, 3); - - - - int theRed = (MakeIntFromString(theColor.substr(0, 1))/9.0f)*255; - int theGreen = (MakeIntFromString(theColor.substr(1, 1))/9.0f)*255; - int theBlue = (MakeIntFromString(theColor.substr(2, 1))/9.0f)*255; - - - pIcon->setColor(BuildColor(theRed, theGreen, theBlue, gHUD.GetGammaSlope())); - }*/ - } - } - /* @2014 - if(g_pTrackerUser) - { - int playerSlot = theSortedRow; - int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); - - if (g_pTrackerUser->IsFriend(trackerID) && trackerID != g_pTrackerUser->GetTrackerID()) - { - pLabel->setImage(m_pTrackerIcon); - pLabel->setFgColorAsImageColor(false); - m_pTrackerIcon->setColor(Color(255, 255, 255, 0)); - } - }*/ -#else - if( theExtraPlayerInfo->icon ) - { - vgui::Bitmap* image = theExtraPlayerInfo->icon->getImage( this->GetIconFrame() ); - if( image ) { pLabel->setImage( image ); } - } -#endif - break; - case COLUMN_SCORE: - if(!theIsForEnemy && theLocalPlayerTeam != TEAM_IND || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - const float kDeltaDisplayTime = 3.0f; - float theTimeSinceChange = gHUD.GetTimeOfLastUpdate() - theExtraPlayerInfo->timeOfLastScoreChange; - - if((theExtraPlayerInfo->score > theExtraPlayerInfo->lastScore) && (theTimeSinceChange > 0) && (theTimeSinceChange < kDeltaDisplayTime) && (theExtraPlayerInfo->teamnumber != 0)) - { - // draw score with change - int theDelta = (theExtraPlayerInfo->score - theExtraPlayerInfo->lastScore); - sprintf(sz, "(+%d) %d", theDelta, theExtraPlayerInfo->score); - } - else - { - sprintf(sz, "%d", theExtraPlayerInfo->score); - } - - } - break; - case COLUMN_WELD: - if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - if ( isNsMode ) { - if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { - if ( theExtraPlayerInfo->extra & WEAPON_WELDER ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pWeld); - m_pWeld->setColor(BuildColor(0, 149, 221, gHUD.GetGammaSlope())); - } - } - } - } - break; - - case COLUMN_MINE: - if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - if ( isNsMode ) { - if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { - if ( theExtraPlayerInfo->extra & WEAPON_MINE ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pMine); - m_pMine->setColor(BuildColor(0, 149, 221, gHUD.GetGammaSlope())); - } - } - } - } - break; - - case COLUMN_EXTRA: - if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - if ( isNsMode ) { - if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { - int r=0, g=149, b=221; - if ( theExtraPlayerInfo->extra & WEAPON_HMG ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pHMG); - m_pHMG->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); - } - if ( theExtraPlayerInfo->extra & WEAPON_SG ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pSG); - m_pSG->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); - } - if ( theExtraPlayerInfo->extra & WEAPON_GL ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pGL); - m_pGL->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); - } - } - else if ( theExtraPlayerInfo->teamnumber == TEAM_TWO || theExtraPlayerInfo->teamnumber == TEAM_FOUR ) { - sprintf(sz, "%d", theExtraPlayerInfo->extra); - } - } - else if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_TWO || - theExtraPlayerInfo->teamnumber == TEAM_THREE || theExtraPlayerInfo->teamnumber == TEAM_FOUR ) { - sprintf(sz, "%d", theExtraPlayerInfo->extra); - } - } - break; - case COLUMN_KILLS: - sprintf(sz, "%d", theExtraPlayerInfo->frags); - break; - - case COLUMN_DEATHS: - sprintf(sz, "%d", theExtraPlayerInfo->deaths); - break; - case COLUMN_LATENCY: - if(pl_info) - { - sprintf(sz, "%d", pl_info->ping ); - } - break; - default: - break; - } - } - - pLabel->setText(sz); - } - } - - for(int row=0; row < NUM_ROWS; row++) - { - CGrid *pGridRow = &m_PlayerGrids[row]; - - pGridRow->AutoSetRowHeights(); - pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); - pGridRow->RepositionContents(); - } - - // hack, for the thing to resize - m_PlayerList.getSize(x, y); - m_PlayerList.setSize(x, y); -} - - -//----------------------------------------------------------------------------- -// Purpose: Setup highlights for player names in scoreboard -//----------------------------------------------------------------------------- -void ScorePanel::DeathMsg( int killer, int victim ) -{ - // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide - if ( victim == m_iPlayerNum || killer == 0 ) - { - m_iLastKilledBy = killer ? killer : m_iPlayerNum; - m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds - - if ( killer == m_iPlayerNum ) - m_iLastKilledBy = m_iPlayerNum; - } -} - - -void ScorePanel::Open( void ) -{ - RebuildTeams(); - setVisible(true); - m_HitTestPanel.setVisible(true); -} - -bool ScorePanel::SetSquelchMode(bool inMode) -{ - bool theSuccess = false; - - if(inMode && !GetClientVoiceMgr()->IsInSquelchMode()) - { - GetClientVoiceMgr()->StartSquelchMode(); - m_HitTestPanel.setVisible(false); - theSuccess = true; - } - else if(!inMode && GetClientVoiceMgr()->IsInSquelchMode()) - { - GetClientVoiceMgr()->StopSquelchMode(); - theSuccess = true; - } - - return theSuccess; -} - -void ScorePanel::mousePressed(MouseCode code, Panel* panel) -{ - if(gHUD.m_iIntermission) - return; - - if (!GetClientVoiceMgr()->IsInSquelchMode()) - { - //GetClientVoiceMgr()->StartSquelchMode(); - //m_HitTestPanel.setVisible(false); - this->SetSquelchMode(true); - } - else if (m_iHighlightRow >= 0) - { - // mouse has been pressed, toggle mute state - int iPlayer = m_iSortedRows[m_iHighlightRow]; - if (iPlayer > 0) - { - // print text message - hud_player_info_t *pl_info = &g_PlayerInfoList[iPlayer]; - - if (pl_info && pl_info->name && pl_info->name[0]) - { - char string[256]; - if (GetClientVoiceMgr()->IsPlayerBlocked(iPlayer)) - { - char string1[1024]; - - // remove mute - GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, false); - - sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Unmuted" ), pl_info->name ); - sprintf( string, "%c** %s\n", HUD_PRINTTALK, string1 ); - - gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, (int)strlen(string)+1, string ); - } - else - { - char string1[1024]; - char string2[1024]; - - // mute the player - GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, true); - - sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Muted" ), pl_info->name ); - sprintf( string2, CHudTextMessage::BufferedLocaliseTextString( "#No_longer_hear_that_player" ) ); - sprintf( string, "%c** %s %s\n", HUD_PRINTTALK, string1, string2 ); - - gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, (int)strlen(string)+1, string ); - } - } - } - } -} - -void ScorePanel::cursorMoved(int x, int y, Panel *panel) -{ - if (GetClientVoiceMgr()->IsInSquelchMode()) - { - // look for which cell the mouse is currently over - for (int i = 0; i < NUM_ROWS; i++) - { - int row, col; - if (m_PlayerGrids[i].getCellAtPoint(x, y, row, col)) - { - MouseOverCell(i, col); - return; - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Handles mouse movement over a cell -// Input : row - -// col - -//----------------------------------------------------------------------------- -void ScorePanel::MouseOverCell(int row, int col) -{ - CLabelHeader *label = &m_PlayerEntries[col][row]; - - // clear the previously highlighted label - if (m_pCurrentHighlightLabel != label) - { - m_pCurrentHighlightLabel = NULL; - m_iHighlightRow = -1; - } - if (!label) - return; - - // don't act on teams - if (m_iIsATeam[row] != TEAM_IND) - return; - - // don't act on disconnected players or ourselves - hud_player_info_t *pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; - if (!pl_info->name || !pl_info->name[0]) - return; - - if (pl_info->thisplayer && !gEngfuncs.IsSpectateOnly() ) - return; - - // only act on audible players - //if (!GetClientVoiceMgr()->IsPlayerAudible(m_iSortedRows[row])) - // return; - - // setup the new highlight - m_pCurrentHighlightLabel = label; - m_iHighlightRow = row; -} - -//----------------------------------------------------------------------------- -// Purpose: Label paint functions - take into account current highligh status -//----------------------------------------------------------------------------- -void CLabelHeader::paintBackground() -{ - Color oldBg; - getBgColor(oldBg); - - if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) - { - setBgColor(134, 91, 19, 0); - } - - Panel::paintBackground(); - - setBgColor(oldBg); -} - - -//----------------------------------------------------------------------------- -// Purpose: Label paint functions - take into account current highligh status -//----------------------------------------------------------------------------- -void CLabelHeader::paint() -{ - Color oldFg; - getFgColor(oldFg); - - if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) - { - setFgColor(255, 255, 255, 0); - } - - // draw text - int x, y, iwide, itall; - getTextSize(iwide, itall); - calcAlignment(iwide, itall, x, y); - _dualImage->setPos(x, y); - - int x1, y1; - _dualImage->GetImage(1)->getPos(x1, y1); - _dualImage->GetImage(1)->setPos(_gap, y1); - - _dualImage->doPaint(this); - - // get size of the panel and the image - if (_image) - { - Color imgColor; - getFgColor( imgColor ); - if( _useFgColorAsImageColor ) - { - _image->setColor( imgColor ); - } - _image->getSize(iwide, itall); - calcAlignment(iwide, itall, x, y); - _image->setPos(x, y); - _image->doPaint(this); - } - - setFgColor(oldFg[0], oldFg[1], oldFg[2], oldFg[3]); -} - - -void CLabelHeader::calcAlignment(int iwide, int itall, int &x, int &y) -{ - // calculate alignment ourselves, since vgui is so broken - int wide, tall; - getSize(wide, tall); - - x = 0, y = 0; - - // align left/right - switch (_contentAlignment) - { - // left - case Label::a_northwest: - case Label::a_west: - case Label::a_southwest: - { - x = 0; - break; - } - - // center - case Label::a_north: - case Label::a_center: - case Label::a_south: - { - x = (wide - iwide) / 2; - break; - } - - // right - case Label::a_northeast: - case Label::a_east: - case Label::a_southeast: - { - x = wide - iwide; - break; - } - } - - // top/down - switch (_contentAlignment) - { - // top - case Label::a_northwest: - case Label::a_north: - case Label::a_northeast: - { - y = 0; - break; - } - - // center - case Label::a_west: - case Label::a_center: - case Label::a_east: - { - y = (tall - itall) / 2; - break; - } - - // south - case Label::a_southwest: - case Label::a_south: - case Label::a_southeast: - { - y = tall - itall; - break; - } - } - -// don't clip to Y -// if (y < 0) -// { -// y = 0; -// } - if (x < 0) - { - x = 0; - } - - x += _offset[0]; - y += _offset[1]; -} +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: VGUI scoreboard +// +// $Workfile: $ +// $Date: 2002/10/24 21:13:15 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_ScorePanel.cpp,v $ +// Revision 1.15 2002/10/24 21:13:15 Flayra +// - Fixed gamma correction for auth icons +// +// Revision 1.14 2002/10/18 22:13:48 Flayra +// - Gamma-correction for auth icons +// +// Revision 1.13 2002/10/16 00:37:33 Flayra +// - Added support for authentication in scoreboard +// +// Revision 1.12 2002/09/09 19:42:55 Flayra +// - Fixed problem where scores were sometimes displayed for marines +// +// Revision 1.11 2002/08/31 18:02:11 Flayra +// - Work at VALVe +// +// Revision 1.10 2002/08/09 00:11:33 Flayra +// - Fixed scoreboard +// +// Revision 1.9 2002/07/08 16:15:13 Flayra +// - Refactored team color management +// +// Revision 1.8 2002/06/25 17:06:48 Flayra +// - Removed memory overwrite from hlcoder list +// +// Revision 1.7 2002/06/03 16:12:21 Flayra +// - Show player status for players on your team (LEV1, GEST, COMM, etc.) +// +// Revision 1.6 2002/04/16 19:30:21 Charlie +// - Fixed crash when holding tab right when joining server, added "REIN" status +// +// Revision 1.5 2002/03/27 21:17:18 Charlie +// - Scoreboard now shows alien scores, and doesn't show marine scores. Also draws DEAD and COMM indicators, and scoring is handled properly for aliens (points for kills, buildings) +// +// Revision 1.4 2002/03/08 02:37:52 Charlie +// - Refactored crappy-ass score panel. It's not perfect, but it's better. Removed TFC code, added DEAD and COMM tags to scoreboard. +// +// Revision 1.3 2001/11/13 17:51:02 Charlie +// - Increased max teams, changed team colors (allow aliens vs. aliens and fronts vs. fronts), general scoreboard support +// +// Revision 1.2 2001/09/13 22:28:01 Charlie +// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode +// +// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie +// - HL1108 +// +// +// $NoKeywords: $ +//============================================================================= + + +#include + +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ScorePanel.h" +#include "../game_shared/vgui_helpers.h" +#include "../game_shared/vgui_loadtga.h" +#include "mod/AvHConstants.h" +#include "mod/AvHTitles.h" +#include "mod/AvHBasePlayerWeaponConstants.h" +#include "vgui_SpectatorPanel.h" +#include "cl_dll/demo.h" +#include "mod/AvHServerVariables.h" +#include "util/STLUtil.h" +#include "ui/ScoreboardIcon.h" +/* @2014 +#include "common/itrackeruser.h" +extern ITrackerUser *g_pTrackerUser; +*/ +hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +team_info_t g_TeamInfo[MAX_TEAMS+1]; +int g_IsSpectator[MAX_PLAYERS+1]; + +int HUD_IsGame( const char *game ); +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ); + +// Scoreboard dimensions +#define SBOARD_TITLE_SIZE_Y YRES(22) + +#define X_BORDER XRES(4) + +void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable); +void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable); + +int ScorePanel_InitializeDemoPlayback(int inSize, unsigned char* inBuffer) +{ + int theBytesRead = 0; + + LoadData(&g_PlayerInfoList, inBuffer, (MAX_PLAYERS+1)*sizeof(hud_player_info_t), theBytesRead); + LoadData(&g_PlayerExtraInfo, inBuffer, (MAX_PLAYERS+1)*sizeof(extra_player_info_t), theBytesRead); + LoadData(&g_TeamInfo, inBuffer, (MAX_PLAYERS+1)*sizeof(team_info_t), theBytesRead); + LoadData(&g_IsSpectator, inBuffer, (MAX_PLAYERS+1)*sizeof(int), theBytesRead); + + return theBytesRead; +} + +void ScorePanel_InitializeDemoRecording() +{ + // Now save out team info + int theTotalSize = (MAX_PLAYERS + 1)*(sizeof(hud_player_info_t) + sizeof(extra_player_info_t) + sizeof(team_info_t) + sizeof(int)); + unsigned char* theCharArray = new unsigned char[theTotalSize]; + if(theCharArray) + { + int theCounter = 0; + SaveData(theCharArray, &g_PlayerInfoList, (MAX_PLAYERS+1)*sizeof(hud_player_info_t), theCounter); + SaveData(theCharArray, &g_PlayerExtraInfo, (MAX_PLAYERS+1)*sizeof(extra_player_info_t), theCounter); + SaveData(theCharArray, &g_TeamInfo, (MAX_PLAYERS+1)*sizeof(team_info_t), theCounter); + SaveData(theCharArray, &g_IsSpectator, (MAX_PLAYERS+1)*sizeof(int), theCounter); + + Demo_WriteBuffer(TYPE_PLAYERINFO, theTotalSize, theCharArray); + } +} + +// Column sizes +class SBColumnInfo +{ +public: + char *m_pTitle; // If null, ignore, if starts with #, it's localized, otherwise use the string directly. + int m_Width; // Based on 640 width. Scaled to fit other resolutions. + Label::Alignment m_Alignment; +}; + +// grid size is marked out for 640x480 screen + +SBColumnInfo g_ColumnInfo[NUM_COLUMNS] = +{ + {NULL, 24, Label::a_center}, // tracker column + {NULL, 24, Label::a_center}, // status icons + {NULL, 110, Label::a_center}, // name + {NULL, 56, Label::a_center}, // class + {NULL, 40, Label::a_center}, // resources + {NULL, 18, Label::a_center}, // weld + {NULL, 18, Label::a_center}, // weld + {"#SCORE", 35, Label::a_center}, // score + {"#KILLS", 35, Label::a_center}, // kills + {"#DEATHS", 35, Label::a_center}, // deaths + {"#LATENCY", 35, Label::a_center}, // ping + {"#VOICE", 40, Label::a_center}, + {NULL, 2, Label::a_center}, // blank column to take up the slack +}; + + +#define TEAM_NO 0 +#define TEAM_YES 1 +#define TEAM_SPECTATORS 2 +#define TEAM_BLANK 3 + +//----------------------------------------------------------------------------- +// ScorePanel::HitTestPanel. +//----------------------------------------------------------------------------- + +void ScorePanel::HitTestPanel::internalMousePressed(MouseCode code) +{ + for(int i=0;i<_inputSignalDar.getCount();i++) + { + _inputSignalDar[i]->mousePressed(code,this); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +vgui::Color BuildColor( int R, int G, int B, float gamma ) +{ + ASSERT( gamma != 0 ); + return vgui::Color( R/gamma, G/gamma, B/gamma, 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Create the ScoreBoard panel +//----------------------------------------------------------------------------- +ScorePanel::ScorePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); + SchemeHandle_t hTinyScheme = pSchemes->getSchemeHandle("Scoreboard Tiny Text"); + Font *tfont = pSchemes->getFont(hTitleScheme); + Font *smallfont = pSchemes->getFont(hSmallScheme); + Font *tinyfont = pSchemes->getFont(hTinyScheme); + + setBgColor(0, 0, 0, 96); + m_pCurrentHighlightLabel = NULL; + m_iHighlightRow = -1; + // : 0001073 + m_pTrackerIcon = NULL; + m_pDevIcon = NULL; + m_pPTIcon = NULL; + m_pGuideIcon = NULL; + m_pServerOpIcon = NULL; + m_pContribIcon = NULL; + m_pCheatingDeathIcon = NULL; + m_pVeteranIcon = NULL; + + m_pHMG = NULL; + m_pMine = NULL; + m_pWeld = NULL; + m_pGL = NULL; + m_pSG = NULL; + + + m_pTrackerIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardtracker.tga"); + m_pDevIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboarddev.tga"); + m_pPTIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardpt.tga"); + m_pGuideIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardguide.tga"); + m_pServerOpIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardserverop.tga"); + m_pContribIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardcontrib.tga"); + m_pCheatingDeathIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardcd.tga"); + m_pVeteranIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardveteran.tga"); + + + + m_pHMG = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardhmg.tga"); + m_pMine = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardmine.tga"); + m_pWeld = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardwelder.tga"); + m_pGL = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardgl.tga"); + m_pSG = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardsg.tga"); + + m_iIconFrame = 0; + m_iLastFrameIncrementTime = gHUD.GetTimeOfLastUpdate(); + + // Initialize the top title. + m_TitleLabel.setFont(tfont); + m_TitleLabel.setText(""); + m_TitleLabel.setBgColor( 0, 0, 0, 255 ); + m_TitleLabel.setFgColor( Scheme::sc_primary1 ); + m_TitleLabel.setContentAlignment( vgui::Label::a_center ); + + LineBorder *border = new LineBorder(Color(60, 60, 60, 128)); + setBorder(border); + setPaintBorderEnabled(true); + + int xpos = g_ColumnInfo[0].m_Width + 3; + if (ScreenWidth() >= 640) + { + // only expand column size for res greater than 640 + xpos = XRES(xpos); + } + m_TitleLabel.setBounds(xpos, 4, wide, SBOARD_TITLE_SIZE_Y); + m_TitleLabel.setContentFitted(false); + m_TitleLabel.setParent(this); + + // Setup the header (labels like "name", "class", etc..). + m_HeaderGrid.SetDimensions(NUM_COLUMNS, 1); + m_HeaderGrid.SetSpacing(0, 0); + int i=0; + for( i=0; i < NUM_COLUMNS; i++) + { + if (g_ColumnInfo[i].m_pTitle && g_ColumnInfo[i].m_pTitle[0] == '#') + m_HeaderLabels[i].setText(CHudTextMessage::BufferedLocaliseTextString(g_ColumnInfo[i].m_pTitle)); + else if(g_ColumnInfo[i].m_pTitle) + m_HeaderLabels[i].setText(g_ColumnInfo[i].m_pTitle); + + int xwide = g_ColumnInfo[i].m_Width; + if (ScreenWidth() >= 640) + { + xwide = XRES(xwide); + } + else if (ScreenWidth() == 400) + { + // hack to make 400x300 resolution scoreboard fit + if (i == 1) + { + // reduces size of player name cell + xwide -= 28; + } + else if (i == 0) + { + // tracker icon cell + xwide -= 8; + } + } + + m_HeaderGrid.SetColumnWidth(i, xwide); + m_HeaderGrid.SetEntry(i, 0, &m_HeaderLabels[i]); + + m_HeaderLabels[i].setBgColor(0,0,0,255); + m_HeaderLabels[i].setBgColor(0,0,0,255); + + int theColorIndex = 0; + Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); + int theR, theG, theB, theA; + gammaAdjustedTeamColor.getColor(theR, theG, theB, theA); + m_HeaderLabels[i].setFgColor(theR, theG, theB, theA); + + m_HeaderLabels[i].setFont(smallfont); + m_HeaderLabels[i].setContentAlignment(g_ColumnInfo[i].m_Alignment); + + int yres = 12; + if (ScreenHeight() >= 480) + { + yres = YRES(yres); + } + m_HeaderLabels[i].setSize(50, yres); + } + + // Set the width of the last column to be the remaining space. + int ex, ey, ew, eh; + m_HeaderGrid.GetEntryBox(NUM_COLUMNS - 2, 0, ex, ey, ew, eh); + m_HeaderGrid.SetColumnWidth(NUM_COLUMNS - 1, (wide - X_BORDER) - (ex + ew)); + + m_HeaderGrid.AutoSetRowHeights(); + m_HeaderGrid.setBounds(X_BORDER, SBOARD_TITLE_SIZE_Y, wide - X_BORDER*2, m_HeaderGrid.GetRowHeight(0)); + m_HeaderGrid.setParent(this); + m_HeaderGrid.setBgColor(0,0,0,255); + + + // Now setup the listbox with the actual player data in it. + int headerX, headerY, headerWidth, headerHeight; + m_HeaderGrid.getBounds(headerX, headerY, headerWidth, headerHeight); + m_PlayerList.setBounds(headerX, headerY+headerHeight, headerWidth, tall - headerY - headerHeight - 6); + m_PlayerList.setBgColor(0,0,0,255); + m_PlayerList.setParent(this); + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + + pGridRow->SetDimensions(NUM_COLUMNS, 1); + + for(int col=0; col < NUM_COLUMNS; col++) + { + m_PlayerEntries[col][row].setContentFitted(false); + m_PlayerEntries[col][row].setRow(row); + m_PlayerEntries[col][row].addInputSignal(this); + pGridRow->SetEntry(col, 0, &m_PlayerEntries[col][row]); + } + + pGridRow->setBgColor(0,0,0,255); +// pGridRow->SetSpacing(2, 0);f + pGridRow->SetSpacing(0, 0); + pGridRow->CopyColumnWidths(&m_HeaderGrid); + pGridRow->AutoSetRowHeights(); + pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); + pGridRow->RepositionContents(); + + m_PlayerList.AddItem(pGridRow); + } + + + // Add the hit test panel. It is invisible and traps mouse clicks so we can go into squelch mode. + m_HitTestPanel.setBgColor(0,0,0,255); + m_HitTestPanel.setParent(this); + m_HitTestPanel.setBounds(0, 0, wide, tall); + m_HitTestPanel.addInputSignal(this); + + m_pCloseButton = new CommandButton( "x", wide-XRES(12 + 4), YRES(2), XRES( 12 ) , YRES( 12 ) ); + m_pCloseButton->setParent( this ); + m_pCloseButton->addActionSignal( new CMenuHandler_StringCommandWatch( "-showscores", true ) ); + m_pCloseButton->setBgColor(0,0,0,255); + m_pCloseButton->setFgColor( 255, 255, 255, 0 ); + m_pCloseButton->setFont(tfont); + m_pCloseButton->setBoundKey( (char)255 ); + m_pCloseButton->setContentAlignment(Label::a_center); + Initialize(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void ScorePanel::Initialize( void ) +{ + // Clear out scoreboard data + m_iLastKilledBy = 0; + m_fLastKillTime = 0; + m_iPlayerNum = 0; + m_iNumTeams = 0; + // : 0001073 +// for( int counter = 0; counter < MAX_PLAYERS+1; counter++ ) +// { +// delete g_PlayerExtraInfo[counter].icon; +// } + + memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); + memset( g_TeamInfo, 0, sizeof g_TeamInfo ); +} + +bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ) +{ + return !!gEngfuncs.GetPlayerUniqueID( iPlayer, playerID ); +} +//----------------------------------------------------------------------------- +// Purpose: Recalculate the internal scoreboard data +//----------------------------------------------------------------------------- +//@linux make snprintf work for win32 +#ifdef _WIN32 +#define snprintf _snprintf +#endif +void ScorePanel::Update() +{ + + // Set the title + char title[128]; + + char theServerName[MAX_SERVERNAME_LENGTH+1]; + if (gViewPort->m_szServerName) + { + memset(theServerName, 0, MAX_SERVERNAME_LENGTH+1); + int iServerNameLength = max((int)strlen(gViewPort->m_szServerName),MAX_SERVERNAME_LENGTH); + //strncat(theServerName, gViewPort->m_szServerName, iServerNameLength); Buffer Overflow? + snprintf(theServerName, MAX_SERVERNAME_LENGTH, "%s%s",theServerName ,gViewPort->m_szServerName); + } + theServerName[MAX_SERVERNAME_LENGTH]=0; + char theMapName[MAX_MAPNAME_LENGTH+1]; + sprintf(theMapName, "%s", gHUD.GetMapName().c_str()); + + int theTimeElapsed = gHUD.GetGameTime(); + char elapsedString[64]; + if ( theTimeElapsed > 0 ) { + int theMinutesElapsed = theTimeElapsed/60; + int theSecondsElapsed = theTimeElapsed%60; + sprintf(elapsedString, "Game time: %d:%02d", theMinutesElapsed, theSecondsElapsed); + } + else { + sprintf(elapsedString, ""); + } + + sprintf(title, "%32s Map: %s %s", theServerName, theMapName, elapsedString); + + m_TitleLabel.setText(title); + + int theColorIndex = 0; + + // Set gamma-correct title color + + Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); + + int theR, theG, theB, theA; + gammaAdjustedTeamColor.getColor(theR, theG, theB, theA); + + m_TitleLabel.setFgColor(theR, theG, theB, theA); + + m_iRows = 0; + gViewPort->GetAllPlayersInfo(); + + // Clear out sorts + int i = 0; + for (i = 0; i < NUM_ROWS; i++) + { + m_iSortedRows[i] = 0; + m_iIsATeam[i] = TEAM_IND; + } + + // Fix for memory overrun bug + + for (i = 0; i < MAX_PLAYERS; i++) + { + m_bHasBeenSorted[i] = false; + } + + SortTeams(); + + // set scrollbar range + m_PlayerList.SetScrollRange(m_iRows); + + FillGrid(); + if ( gViewPort->m_pSpectatorPanel->m_menuVisible ) + { + m_pCloseButton->setVisible ( true ); + } + else + { + m_pCloseButton->setVisible ( false ); + } + +} + +//----------------------------------------------------------------------------- +// Purpose: Sort all the teams +//----------------------------------------------------------------------------- +void ScorePanel::SortTeams() +{ + // clear out team scores + float theCurrentTime = gHUD.GetTimeOfLastUpdate(); + int i=0; + int j=0; + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( !g_TeamInfo[i].scores_overriden ) + { + g_TeamInfo[i].score =0; + } + g_TeamInfo[i].frags = g_TeamInfo[i].deaths = g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; + } + + // recalc the team scores, then draw them + for ( i = 1; i <= MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name == NULL ) + continue; // empty player slot, skip + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // find what team this player is in + for ( j = 1; j <= m_iNumTeams; j++ ) + { + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy + continue; + + if ( !g_TeamInfo[j].scores_overriden ) + { + g_TeamInfo[j].score += g_PlayerExtraInfo[i].score; + } + + g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; + g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; + g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; + g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; + + if ( g_PlayerInfoList[i].thisplayer ) + g_TeamInfo[j].ownteam = TRUE; + else + g_TeamInfo[j].ownteam = FALSE; + + // Set the team's number (used for team colors) + g_TeamInfo[j].teamnumber = g_PlayerExtraInfo[i].teamnumber; + } + + // find team ping/packetloss averages + for ( i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].already_drawn = FALSE; + + if ( g_TeamInfo[i].players > 0 ) + { + g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + } + } + vector teams; + if ( gHUD.GetHUDTeam() == TEAM_TWO || gHUD.GetHUDTeam() == TEAM_FOUR ) { + SortActivePlayers(kAlien1Team); + SortActivePlayers(kMarine1Team); + SortActivePlayers(kAlien2Team); + SortActivePlayers(kMarine2Team); + } + else { + SortActivePlayers(kMarine1Team); + SortActivePlayers(kAlien1Team); + SortActivePlayers(kMarine2Team); + SortActivePlayers(kAlien2Team); + } + + SortActivePlayers(kSpectatorTeam); + SortActivePlayers(kUndefinedTeam); +} + +void ScorePanel::SortActivePlayers(char* inTeam, bool inSortByEntityIndex) +{ + for(int i = 1; i <= m_iNumTeams; i++) + { + if(!strcmp(g_TeamInfo[i].name, inTeam)) + { + int best_team = i; + + // Put this team in the sorted list + m_iSortedRows[ m_iRows ] = best_team; + m_iIsATeam[ m_iRows ] = TEAM_YES; + g_TeamInfo[best_team].already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get sorted again + m_iRows++; + + // Now sort all the players on this team + SortPlayers(0, g_TeamInfo[best_team].name, inSortByEntityIndex); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Sort a list of players +//----------------------------------------------------------------------------- +void ScorePanel::SortPlayers( int iTeam, char *team, bool inSortByEntityIndex) +{ + bool bCreatedTeam = false; + + // draw the players, in order, and restricted to team if set + while ( 1 ) + { + // Find the top ranking player + int theBestTotalScore = -99999; + int theBestDeaths = 0; + int theBestPlayer = 0; + + for ( int i = 1; i <= MAX_PLAYERS; i++ ) + { + if ( m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( i ); + + if ( ent && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) + { + extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; + + // Sort by player index to mask marine status + if(inSortByEntityIndex) + { + if((theBestPlayer == 0) || (i < theBestPlayer)) + { + theBestPlayer = i; + } + } + else + { + // overall rank = score + kills (with least deaths breaking ties) + int thePlayerScore = pl_info->score; + int thePlayerDeaths = pl_info->deaths; + if((thePlayerScore > theBestTotalScore) || ((thePlayerScore == theBestTotalScore) && (pl_info->deaths < theBestDeaths))) + { + theBestPlayer = i; + theBestTotalScore = thePlayerScore; + theBestDeaths = thePlayerDeaths; + } + } + } + } + } + + if ( !theBestPlayer ) + break; + + // If we haven't created the Team yet, do it first + if (!bCreatedTeam && iTeam) + { + m_iIsATeam[ m_iRows ] = iTeam; + m_iRows++; + + bCreatedTeam = true; + } + + // Put this player in the sorted list + m_iSortedRows[ m_iRows ] = theBestPlayer; + m_bHasBeenSorted[ theBestPlayer ] = true; + m_iRows++; + } + + if (team) + { + m_iIsATeam[m_iRows++] = TEAM_BLANK; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Recalculate the existing teams in the match +//----------------------------------------------------------------------------- +void ScorePanel::RebuildTeams() +{ + // clear out player counts from teams + int i=0; + int j=0; + for ( i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].players = 0; + } + + // rebuild the team list + gViewPort->GetAllPlayersInfo(); + m_iNumTeams = 0; + for ( i = 1; i <= MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name == NULL ) + continue; + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // is this player in an existing team? + for ( j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + + if ( j > m_iNumTeams ) + { // they aren't in a listed team, so make a new one + // search through for an empty team slot + for ( j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + } + m_iNumTeams = max( j, m_iNumTeams ); + strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); + g_TeamInfo[j].players = 0; + } + + g_TeamInfo[j].players++; + } + + // clear out any empty teams + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 1 ) + memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); + } + + // Update the scoreboard + Update(); +} + +//----------------------------------------------------------------------------- + +int ScorePanel::GetIconFrame(void) +{ + const static int kIconFrameDuration = 0.25; + + int current_time = gHUD.GetTimeOfLastUpdate(); + if( (m_iLastFrameIncrementTime - current_time) > kIconFrameDuration ) + { + m_iLastFrameIncrementTime = current_time; + m_iIconFrame++; + if( m_iIconFrame >= 1000 ) + { + m_iIconFrame = 0; + } + } + return m_iIconFrame; +} + +//----------------------------------------------------------------------------- + +void ScorePanel::FillGrid() +{ + bool isNsMode=( strnicmp(gHUD.GetMapName().c_str(), "ns_", 3) == 0 ); + + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + SchemeHandle_t hScheme = pSchemes->getSchemeHandle("Scoreboard Text"); + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); + SchemeHandle_t hTinyScheme = pSchemes->getSchemeHandle("Scoreboard Tiny Text"); + + Font *sfont = pSchemes->getFont(hScheme); + Font *tfont = pSchemes->getFont(hTitleScheme); + Font *smallfont = pSchemes->getFont(hSmallScheme); + Font *tinyfont = pSchemes->getFont(hTinyScheme); + + // update highlight position + int x, y; + getApp()->getCursorPos(x, y); + cursorMoved(x, y, this); + + // remove highlight row if we're not in squelch mode + if (!GetClientVoiceMgr()->IsInSquelchMode()) + { + m_iHighlightRow = -1; + } + + bool bNextRowIsGap = false; + m_HeaderLabels[COLUMN_EXTRA].setText(""); + m_HeaderLabels[COLUMN_MINE].setText(""); + m_HeaderLabels[COLUMN_WELD].setText(""); + if ( isNsMode ) { + if ( gHUD.GetHUDTeam() == TEAM_ONE || gHUD.GetHUDTeam() == TEAM_THREE ) { + m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLWEAP")); + } + else if ( gHUD.GetHUDTeam() == TEAM_TWO || gHUD.GetHUDTeam() == TEAM_FOUR ) { + m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLRES")); + } + } + else { + if ( gHUD.GetHUDTeam() != TEAM_IND && gHUD.GetHUDTeam() != TEAM_SPECT ) + m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLLEVEL")); + } + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + pGridRow->SetRowUnderline(0, false, 0, 0, 0, 0, 0); + + if(row >= m_iRows) + { + for(int col=0; col < NUM_COLUMNS; col++) + m_PlayerEntries[col][row].setVisible(false); + + continue; + } + + bool bRowIsGap = false; + if (bNextRowIsGap) + { + bNextRowIsGap = false; + bRowIsGap = true; + } + + // Get the player's data + int theSortedRow = m_iSortedRows[row]; + hud_player_info_t* pl_info = &g_PlayerInfoList[theSortedRow]; + extra_player_info_t* theExtraPlayerInfo = &g_PlayerExtraInfo[theSortedRow]; + int thePlayerClass = theExtraPlayerInfo->playerclass; + short theTeamNumber = theExtraPlayerInfo->teamnumber; + string theCustomIcon = (string)theExtraPlayerInfo->customicon; +// : 0001073 + short thePlayerAuthentication = theExtraPlayerInfo->auth; + bool thePlayerIsDead = false; + switch( thePlayerClass ) + { + case PLAYERCLASS_DEAD_MARINE: + case PLAYERCLASS_DEAD_ALIEN: + case PLAYERCLASS_REINFORCING: + thePlayerIsDead = true; + break; + } + + // Code to test DEBUG +#if 0 + #ifdef DEBUG + extern int gGlobalDebugAuth; + thePlayerAuthentication = 1; + thePlayerAuthentication <<= gGlobalDebugAuth; + #endif +#endif + + team_info_t* team_info = &g_TeamInfo[m_iSortedRows[row]]; + int theColorIndex = theTeamNumber % iNumberOfTeamColors; + + int theLocalPlayerTeam = 0; + if(gEngfuncs.GetLocalPlayer()) + { + theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; + } + + for(int col=0; col < NUM_COLUMNS; col++) + { + CLabelHeader *pLabel = &m_PlayerEntries[col][row]; + + pLabel->setVisible(true); + pLabel->setText2(""); + pLabel->setImage(NULL); + pLabel->setFont(sfont); + pLabel->setTextOffset(0, 0); + + int rowheight = 13; + if (ScreenHeight() > 480) + { + rowheight = YRES(rowheight); + } + else + { + // more tweaking, make sure icons fit at low res + rowheight = 15; + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setBgColor(0, 0, 0, 255); + + char sz[128]; + + Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); + pLabel->setFgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 0); + + if (m_iIsATeam[row] == TEAM_BLANK) + { + pLabel->setText(" "); + continue; + } + else if ( m_iIsATeam[row] == TEAM_YES ) + { + theColorIndex = team_info->teamnumber % iNumberOfTeamColors; + + // team color text for team names + + + + // different height for team header rows + rowheight = 20; + if (ScreenHeight() >= 480) + { + rowheight = YRES(rowheight); + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setFont(tfont); + + pGridRow->SetRowUnderline( 0, + true, + YRES(3), + gammaAdjustedTeamColor[0], + gammaAdjustedTeamColor[1], + gammaAdjustedTeamColor[2], + 0 ); + } + else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + // grey text for spectators + pLabel->setFgColor(100, 100, 100, 0); + + // different height for team header rows + rowheight = 20; + if (ScreenHeight() >= 480) + { + rowheight = YRES(rowheight); + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setFont(tfont); + + pGridRow->SetRowUnderline(0, true, YRES(3), 100, 100, 100, 0); + } + else + { + if(thePlayerIsDead) + { + pLabel->setFgColor(255, 0, 0, 0); + } + else + { + // team color text for player names + pLabel->setFgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 0); + } + + // Set background color + if ( pl_info && pl_info->thisplayer ) // if it is their name, draw it a different color + { + // Highlight this player + pLabel->setFgColor(Scheme::sc_white); + pLabel->setBgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 196 ); + } + else if ( theSortedRow == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) + { + // Killer's name + pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); + } + } + + // Align + switch(col) + { + case COLUMN_NAME: + case COLUMN_CLASS: + pLabel->setContentAlignment( vgui::Label::a_west ); + break; + + case COLUMN_TRACKER: + case COLUMN_RANK_ICON: + case COLUMN_VOICE: + pLabel->setContentAlignment( vgui::Label::a_center ); + break; + + case COLUMN_SCORE: + case COLUMN_KILLS: + case COLUMN_EXTRA: + case COLUMN_MINE: + case COLUMN_WELD: + case COLUMN_DEATHS: + case COLUMN_LATENCY: + default: + pLabel->setContentAlignment( vgui::Label::a_center ); + break; + } + + // Fill out with the correct data + strcpy(sz, ""); + if ( m_iIsATeam[row] ) + { + char sz2[128]; + + switch (col) + { + case COLUMN_NAME: + if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); + } + else + { + if(team_info) + { + sprintf( sz2, gViewPort->GetTeamName(team_info->teamnumber) ); + } + } + + strcpy(sz, sz2); + + // Append the number of players + if ( m_iIsATeam[row] == TEAM_YES && team_info) + { + if (team_info->players == 1) + { + sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player" ) ); + } + else + { + sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player_plural" ) ); + } + + pLabel->setText2(sz2); + pLabel->setFont2(smallfont); + } + break; + case COLUMN_VOICE: + break; + case COLUMN_CLASS: + break; + case COLUMN_SCORE: + if ((m_iIsATeam[row] == TEAM_YES) && team_info && (theLocalPlayerTeam == team_info->teamnumber || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER))) + sprintf(sz, "%d", team_info->score); + break; + case COLUMN_MINE: + break; + case COLUMN_WELD: + break; + case COLUMN_EXTRA: + break; + case COLUMN_KILLS: + if ((m_iIsATeam[row] == TEAM_YES) && team_info) + sprintf(sz, "%d", team_info->frags ); + break; + case COLUMN_DEATHS: + if ((m_iIsATeam[row] == TEAM_YES) && team_info) + sprintf(sz, "%d", team_info->deaths ); + break; + case COLUMN_LATENCY: + if ((m_iIsATeam[row] == TEAM_YES) && team_info) + sprintf(sz, "%d", team_info->ping ); + break; + default: + break; + } + } + else + { + // Are these stats for an enemy? Score and other stats shouldn't be drawn for enemies. + bool theIsForEnemy = false; + + int theLocalPlayerTeam = 0; + if(gEngfuncs.GetLocalPlayer()) + { + theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; + } + + if((theLocalPlayerTeam != 0) && (theExtraPlayerInfo->teamnumber != theLocalPlayerTeam)) + { + theIsForEnemy = true; + } + + switch (col) + { + case COLUMN_NAME: + /* + if (g_pTrackerUser) + { + int playerSlot = m_iSortedRows[row]; + int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); + const char *trackerName = g_pTrackerUser->GetUserName(trackerID); + if (trackerName && *trackerName) + { + sprintf(sz, " (%s)", trackerName); + pLabel->setText2(sz); + } + } + */ + if(pl_info) + { + sprintf(sz, "%s ", pl_info->name); + } + break; + case COLUMN_VOICE: + sz[0] = 0; + // in HLTV mode allow spectator to turn on/off commentator voice + if (pl_info && (!pl_info->thisplayer || gEngfuncs.IsSpectateOnly())) + { + GetClientVoiceMgr()->UpdateSpeakerImage(pLabel, theSortedRow); + } + break; + case COLUMN_CLASS: + // No class for other team's members (unless allied or spectator, and make sure player is on our team) + strcpy(sz, ""); + + if(team_info && ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER))) + { + switch(thePlayerClass) + { + case (int)(PLAYERCLASS_DEAD_MARINE): + case (int)(PLAYERCLASS_DEAD_ALIEN): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassDead)); + break; + case (int)(PLAYERCLASS_REINFORCING): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassReinforcing)); + break; + case (int)(PLAYERCLASS_REINFORCINGCOMPLETE): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassReinforcingComplete)); + break; + case (int)(PLAYERCLASS_ALIVE_JETPACK_MARINE): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassJetpackMarine)); + break; + case (int)(PLAYERCLASS_ALIVE_HEAVY_MARINE): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassHeavyMarine)); + break; + case (int)(PLAYERCLASS_COMMANDER): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassCommander)); + break; + case (int)(PLAYERCLASS_ALIVE_LEVEL1): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel1)); + break; + case (int)(PLAYERCLASS_ALIVE_LEVEL2): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel2)); + break; + case (int)(PLAYERCLASS_ALIVE_LEVEL3): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel3)); + break; + case (int)(PLAYERCLASS_ALIVE_LEVEL4): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel4)); + break; + case (int)(PLAYERCLASS_ALIVE_LEVEL5): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel5)); + break; + case (int)(PLAYERCLASS_ALIVE_DIGESTING): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassDigesting)); + break; + case (int)(PLAYERCLASS_ALIVE_GESTATING): + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassGestating)); + break; + default: + break; + } + } + break; + + case COLUMN_RANK_ICON: +// : 0001073 +#ifdef USE_OLDAUTH + // Check if we have authority. Right now these override the tracker icons. Listed in increasing order of "importance". + if(thePlayerAuthentication & PLAYERAUTH_CHEATINGDEATH) + { + // Red + pLabel->setImage(m_pCheatingDeathIcon); + pLabel->setFgColorAsImageColor(false); + m_pCheatingDeathIcon->setColor(BuildColor(255, 69, 9, gHUD.GetGammaSlope())); + } + if(thePlayerAuthentication & PLAYERAUTH_VETERAN) + { + // Yellow + pLabel->setImage(m_pVeteranIcon); + pLabel->setFgColorAsImageColor(false); + m_pVeteranIcon->setColor(BuildColor(248, 252, 0, gHUD.GetGammaSlope())); + } + if(thePlayerAuthentication & PLAYERAUTH_BETASERVEROP) + { + // Whitish + pLabel->setImage(m_pServerOpIcon); + pLabel->setFgColorAsImageColor(false); + m_pServerOpIcon->setColor(BuildColor(220, 220, 220, gHUD.GetGammaSlope())); + } + if(thePlayerAuthentication & PLAYERAUTH_CONTRIBUTOR) + { + // Light blue + pLabel->setImage(m_pContribIcon); + pLabel->setFgColorAsImageColor(false); + m_pContribIcon->setColor(BuildColor(117, 214, 241, gHUD.GetGammaSlope())); + } + if(thePlayerAuthentication & PLAYERAUTH_GUIDE) + { + // Magenta + pLabel->setImage(m_pGuideIcon); + pLabel->setFgColorAsImageColor(false); + m_pGuideIcon->setColor(BuildColor(208, 16, 190, gHUD.GetGammaSlope())); + } + if(thePlayerAuthentication & PLAYERAUTH_PLAYTESTER) + { + // Orange + pLabel->setImage(m_pPTIcon); + pLabel->setFgColorAsImageColor(false); + m_pPTIcon->setColor(BuildColor(255, 167, 54, gHUD.GetGammaSlope())); + } + if(thePlayerAuthentication & PLAYERAUTH_DEVELOPER) + { + // TSA blue + pLabel->setImage(m_pDevIcon); + pLabel->setFgColorAsImageColor(false); + m_pDevIcon->setColor(BuildColor(100, 215, 255, gHUD.GetGammaSlope())); + } + + if(thePlayerAuthentication & PLAYERAUTH_SERVEROP) + { + // Bright green + pLabel->setImage(m_pServerOpIcon); + pLabel->setFgColorAsImageColor(false); + m_pServerOpIcon->setColor(BuildColor(0, 255, 0, gHUD.GetGammaSlope())); + } + + // Allow custom icons to override other general icons + if(thePlayerAuthentication & PLAYERAUTH_CUSTOM) + { + if(theCustomIcon != "") + { + string theIconName = theCustomIcon.substr(0, strlen(theCustomIcon.c_str()) - 3); + string theFullCustomIconString = string("gfx/vgui/640_") + theIconName + string(".tga"); + + vgui::BitmapTGA *pIcon = GetIconPointer(theCustomIcon); + + //Icon hasnt been loaded, load it now and add it to list of icons. + if(pIcon == NULL) + { + pIcon = vgui_LoadTGANoInvertAlpha(theFullCustomIconString.c_str()); + + if(pIcon) + m_CustomIconList.push_back( make_pair(pIcon, theCustomIcon) ); + } + /* //@2014 to do + if(pIcon) + { + pLabel->setImage(pIcon); + pLabel->setFgColorAsImageColor(false); + + // Parse color (last 3 bytes are the RGB values 1-9) + string theColor = theCustomIcon.substr( strlen(theCustomIcon.c_str())-3, 3); + + + + int theRed = (MakeIntFromString(theColor.substr(0, 1))/9.0f)*255; + int theGreen = (MakeIntFromString(theColor.substr(1, 1))/9.0f)*255; + int theBlue = (MakeIntFromString(theColor.substr(2, 1))/9.0f)*255; + + + pIcon->setColor(BuildColor(theRed, theGreen, theBlue, gHUD.GetGammaSlope())); + }*/ + } + } + /* @2014 + if(g_pTrackerUser) + { + int playerSlot = theSortedRow; + int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); + + if (g_pTrackerUser->IsFriend(trackerID) && trackerID != g_pTrackerUser->GetTrackerID()) + { + pLabel->setImage(m_pTrackerIcon); + pLabel->setFgColorAsImageColor(false); + m_pTrackerIcon->setColor(Color(255, 255, 255, 0)); + } + }*/ +#else + if( theExtraPlayerInfo->icon ) + { + vgui::Bitmap* image = theExtraPlayerInfo->icon->getImage( this->GetIconFrame() ); + if( image ) { pLabel->setImage( image ); } + } +#endif + break; + case COLUMN_SCORE: + if(!theIsForEnemy && theLocalPlayerTeam != TEAM_IND || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) + { + const float kDeltaDisplayTime = 3.0f; + float theTimeSinceChange = gHUD.GetTimeOfLastUpdate() - theExtraPlayerInfo->timeOfLastScoreChange; + + if((theExtraPlayerInfo->score > theExtraPlayerInfo->lastScore) && (theTimeSinceChange > 0) && (theTimeSinceChange < kDeltaDisplayTime) && (theExtraPlayerInfo->teamnumber != 0)) + { + // draw score with change + int theDelta = (theExtraPlayerInfo->score - theExtraPlayerInfo->lastScore); + sprintf(sz, "(+%d) %d", theDelta, theExtraPlayerInfo->score); + } + else + { + sprintf(sz, "%d", theExtraPlayerInfo->score); + } + + } + break; + case COLUMN_WELD: + if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) + { + if ( isNsMode ) { + if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { + if ( theExtraPlayerInfo->extra & WEAPON_WELDER ) { + pLabel->setFgColorAsImageColor(false); + pLabel->setImage(m_pWeld); + m_pWeld->setColor(BuildColor(0, 149, 221, gHUD.GetGammaSlope())); + } + } + } + } + break; + + case COLUMN_MINE: + if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) + { + if ( isNsMode ) { + if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { + if ( theExtraPlayerInfo->extra & WEAPON_MINE ) { + pLabel->setFgColorAsImageColor(false); + pLabel->setImage(m_pMine); + m_pMine->setColor(BuildColor(0, 149, 221, gHUD.GetGammaSlope())); + } + } + } + } + break; + + case COLUMN_EXTRA: + if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) + { + if ( isNsMode ) { + if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { + int r=0, g=149, b=221; + if ( theExtraPlayerInfo->extra & WEAPON_HMG ) { + pLabel->setFgColorAsImageColor(false); + pLabel->setImage(m_pHMG); + m_pHMG->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); + } + if ( theExtraPlayerInfo->extra & WEAPON_SG ) { + pLabel->setFgColorAsImageColor(false); + pLabel->setImage(m_pSG); + m_pSG->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); + } + if ( theExtraPlayerInfo->extra & WEAPON_GL ) { + pLabel->setFgColorAsImageColor(false); + pLabel->setImage(m_pGL); + m_pGL->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); + } + } + else if ( theExtraPlayerInfo->teamnumber == TEAM_TWO || theExtraPlayerInfo->teamnumber == TEAM_FOUR ) { + sprintf(sz, "%d", theExtraPlayerInfo->extra); + } + } + else if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_TWO || + theExtraPlayerInfo->teamnumber == TEAM_THREE || theExtraPlayerInfo->teamnumber == TEAM_FOUR ) { + sprintf(sz, "%d", theExtraPlayerInfo->extra); + } + } + break; + case COLUMN_KILLS: + sprintf(sz, "%d", theExtraPlayerInfo->frags); + break; + + case COLUMN_DEATHS: + sprintf(sz, "%d", theExtraPlayerInfo->deaths); + break; + case COLUMN_LATENCY: + if(pl_info) + { + sprintf(sz, "%d", pl_info->ping ); + } + break; + default: + break; + } + } + + pLabel->setText(sz); + } + } + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + + pGridRow->AutoSetRowHeights(); + pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); + pGridRow->RepositionContents(); + } + + // hack, for the thing to resize + m_PlayerList.getSize(x, y); + m_PlayerList.setSize(x, y); +} + + +//----------------------------------------------------------------------------- +// Purpose: Setup highlights for player names in scoreboard +//----------------------------------------------------------------------------- +void ScorePanel::DeathMsg( int killer, int victim ) +{ + // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide + if ( victim == m_iPlayerNum || killer == 0 ) + { + m_iLastKilledBy = killer ? killer : m_iPlayerNum; + m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds + + if ( killer == m_iPlayerNum ) + m_iLastKilledBy = m_iPlayerNum; + } +} + + +void ScorePanel::Open( void ) +{ + RebuildTeams(); + setVisible(true); + m_HitTestPanel.setVisible(true); +} + +bool ScorePanel::SetSquelchMode(bool inMode) +{ + bool theSuccess = false; + + if(inMode && !GetClientVoiceMgr()->IsInSquelchMode()) + { + GetClientVoiceMgr()->StartSquelchMode(); + m_HitTestPanel.setVisible(false); + theSuccess = true; + } + else if(!inMode && GetClientVoiceMgr()->IsInSquelchMode()) + { + GetClientVoiceMgr()->StopSquelchMode(); + theSuccess = true; + } + + return theSuccess; +} + +void ScorePanel::mousePressed(MouseCode code, Panel* panel) +{ + if(gHUD.m_iIntermission) + return; + + if (!GetClientVoiceMgr()->IsInSquelchMode()) + { + //GetClientVoiceMgr()->StartSquelchMode(); + //m_HitTestPanel.setVisible(false); + this->SetSquelchMode(true); + } + else if (m_iHighlightRow >= 0) + { + // mouse has been pressed, toggle mute state + int iPlayer = m_iSortedRows[m_iHighlightRow]; + if (iPlayer > 0) + { + // print text message + hud_player_info_t *pl_info = &g_PlayerInfoList[iPlayer]; + + if (pl_info && pl_info->name && pl_info->name[0]) + { + char string[256]; + if (GetClientVoiceMgr()->IsPlayerBlocked(iPlayer)) + { + char string1[1024]; + + // remove mute + GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, false); + + sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Unmuted" ), pl_info->name ); + sprintf( string, "%c** %s\n", HUD_PRINTTALK, string1 ); + + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, (int)strlen(string)+1, string ); + } + else + { + char string1[1024]; + char string2[1024]; + + // mute the player + GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, true); + + sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Muted" ), pl_info->name ); + sprintf( string2, CHudTextMessage::BufferedLocaliseTextString( "#No_longer_hear_that_player" ) ); + sprintf( string, "%c** %s %s\n", HUD_PRINTTALK, string1, string2 ); + + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, (int)strlen(string)+1, string ); + } + } + } + } +} + +void ScorePanel::cursorMoved(int x, int y, Panel *panel) +{ + if (GetClientVoiceMgr()->IsInSquelchMode()) + { + // look for which cell the mouse is currently over + for (int i = 0; i < NUM_ROWS; i++) + { + int row, col; + if (m_PlayerGrids[i].getCellAtPoint(x, y, row, col)) + { + MouseOverCell(i, col); + return; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles mouse movement over a cell +// Input : row - +// col - +//----------------------------------------------------------------------------- +void ScorePanel::MouseOverCell(int row, int col) +{ + CLabelHeader *label = &m_PlayerEntries[col][row]; + + // clear the previously highlighted label + if (m_pCurrentHighlightLabel != label) + { + m_pCurrentHighlightLabel = NULL; + m_iHighlightRow = -1; + } + if (!label) + return; + + // don't act on teams + if (m_iIsATeam[row] != TEAM_IND) + return; + + // don't act on disconnected players or ourselves + hud_player_info_t *pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; + if (!pl_info->name || !pl_info->name[0]) + return; + + if (pl_info->thisplayer && !gEngfuncs.IsSpectateOnly() ) + return; + + // only act on audible players + //if (!GetClientVoiceMgr()->IsPlayerAudible(m_iSortedRows[row])) + // return; + + // setup the new highlight + m_pCurrentHighlightLabel = label; + m_iHighlightRow = row; +} + +//----------------------------------------------------------------------------- +// Purpose: Label paint functions - take into account current highligh status +//----------------------------------------------------------------------------- +void CLabelHeader::paintBackground() +{ + Color oldBg; + getBgColor(oldBg); + + if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) + { + setBgColor(134, 91, 19, 0); + } + + Panel::paintBackground(); + + setBgColor(oldBg); +} + + +//----------------------------------------------------------------------------- +// Purpose: Label paint functions - take into account current highligh status +//----------------------------------------------------------------------------- +void CLabelHeader::paint() +{ + Color oldFg; + getFgColor(oldFg); + + if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) + { + setFgColor(255, 255, 255, 0); + } + + // draw text + int x, y, iwide, itall; + getTextSize(iwide, itall); + calcAlignment(iwide, itall, x, y); + _dualImage->setPos(x, y); + + int x1, y1; + _dualImage->GetImage(1)->getPos(x1, y1); + _dualImage->GetImage(1)->setPos(_gap, y1); + + _dualImage->doPaint(this); + + // get size of the panel and the image + if (_image) + { + Color imgColor; + getFgColor( imgColor ); + if( _useFgColorAsImageColor ) + { + _image->setColor( imgColor ); + } + _image->getSize(iwide, itall); + calcAlignment(iwide, itall, x, y); + _image->setPos(x, y); + _image->doPaint(this); + } + + setFgColor(oldFg[0], oldFg[1], oldFg[2], oldFg[3]); +} + + +void CLabelHeader::calcAlignment(int iwide, int itall, int &x, int &y) +{ + // calculate alignment ourselves, since vgui is so broken + int wide, tall; + getSize(wide, tall); + + x = 0, y = 0; + + // align left/right + switch (_contentAlignment) + { + // left + case Label::a_northwest: + case Label::a_west: + case Label::a_southwest: + { + x = 0; + break; + } + + // center + case Label::a_north: + case Label::a_center: + case Label::a_south: + { + x = (wide - iwide) / 2; + break; + } + + // right + case Label::a_northeast: + case Label::a_east: + case Label::a_southeast: + { + x = wide - iwide; + break; + } + } + + // top/down + switch (_contentAlignment) + { + // top + case Label::a_northwest: + case Label::a_north: + case Label::a_northeast: + { + y = 0; + break; + } + + // center + case Label::a_west: + case Label::a_center: + case Label::a_east: + { + y = (tall - itall) / 2; + break; + } + + // south + case Label::a_southwest: + case Label::a_south: + case Label::a_southeast: + { + y = tall - itall; + break; + } + } + +// don't clip to Y +// if (y < 0) +// { +// y = 0; +// } + if (x < 0) + { + x = 0; + } + + x += _offset[0]; + y += _offset[1]; +} diff --git a/main/source/cl_dll/vgui_ScorePanel.cpp~ b/main/source/cl_dll/vgui_ScorePanel.cpp~ deleted file mode 100644 index f8a587ad..00000000 --- a/main/source/cl_dll/vgui_ScorePanel.cpp~ +++ /dev/null @@ -1,1672 +0,0 @@ -//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: VGUI scoreboard -// -// $Workfile: $ -// $Date: 2002/10/24 21:13:15 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_ScorePanel.cpp,v $ -// Revision 1.15 2002/10/24 21:13:15 Flayra -// - Fixed gamma correction for auth icons -// -// Revision 1.14 2002/10/18 22:13:48 Flayra -// - Gamma-correction for auth icons -// -// Revision 1.13 2002/10/16 00:37:33 Flayra -// - Added support for authentication in scoreboard -// -// Revision 1.12 2002/09/09 19:42:55 Flayra -// - Fixed problem where scores were sometimes displayed for marines -// -// Revision 1.11 2002/08/31 18:02:11 Flayra -// - Work at VALVe -// -// Revision 1.10 2002/08/09 00:11:33 Flayra -// - Fixed scoreboard -// -// Revision 1.9 2002/07/08 16:15:13 Flayra -// - Refactored team color management -// -// Revision 1.8 2002/06/25 17:06:48 Flayra -// - Removed memory overwrite from hlcoder list -// -// Revision 1.7 2002/06/03 16:12:21 Flayra -// - Show player status for players on your team (LEV1, GEST, COMM, etc.) -// -// Revision 1.6 2002/04/16 19:30:21 Charlie -// - Fixed crash when holding tab right when joining server, added "REIN" status -// -// Revision 1.5 2002/03/27 21:17:18 Charlie -// - Scoreboard now shows alien scores, and doesn't show marine scores. Also draws DEAD and COMM indicators, and scoring is handled properly for aliens (points for kills, buildings) -// -// Revision 1.4 2002/03/08 02:37:52 Charlie -// - Refactored crappy-ass score panel. It's not perfect, but it's better. Removed TFC code, added DEAD and COMM tags to scoreboard. -// -// Revision 1.3 2001/11/13 17:51:02 Charlie -// - Increased max teams, changed team colors (allow aliens vs. aliens and fronts vs. fronts), general scoreboard support -// -// Revision 1.2 2001/09/13 22:28:01 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie -// - HL1108 -// -// -// $NoKeywords: $ -//============================================================================= - - -#include - -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ScorePanel.h" -#include "../game_shared/vgui_helpers.h" -#include "../game_shared/vgui_loadtga.h" -#include "mod/AvHConstants.h" -#include "mod/AvHTitles.h" -#include "mod/AvHBasePlayerWeaponConstants.h" -#include "vgui_SpectatorPanel.h" -#include "cl_dll/demo.h" -#include "mod/AvHServerVariables.h" -#include "util/STLUtil.h" -#include "ui/ScoreboardIcon.h" -/* @2014 -#include "common/itrackeruser.h" -extern ITrackerUser *g_pTrackerUser; -*/ -hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine -extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll -team_info_t g_TeamInfo[MAX_TEAMS+1]; -int g_IsSpectator[MAX_PLAYERS+1]; - -int HUD_IsGame( const char *game ); -int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ); - -// Scoreboard dimensions -#define SBOARD_TITLE_SIZE_Y YRES(22) - -#define X_BORDER XRES(4) - -void LoadData(void* inBuffer, const unsigned char* inData, int inSizeToCopy, int& inSizeVariable); -void SaveData(unsigned char* inBuffer, const void* inData, int inSizeToCopy, int& inSizeVariable); - -int ScorePanel_InitializeDemoPlayback(int inSize, unsigned char* inBuffer) -{ - int theBytesRead = 0; - - LoadData(&g_PlayerInfoList, inBuffer, (MAX_PLAYERS+1)*sizeof(hud_player_info_t), theBytesRead); - LoadData(&g_PlayerExtraInfo, inBuffer, (MAX_PLAYERS+1)*sizeof(extra_player_info_t), theBytesRead); - LoadData(&g_TeamInfo, inBuffer, (MAX_PLAYERS+1)*sizeof(team_info_t), theBytesRead); - LoadData(&g_IsSpectator, inBuffer, (MAX_PLAYERS+1)*sizeof(int), theBytesRead); - - return theBytesRead; -} - -void ScorePanel_InitializeDemoRecording() -{ - // Now save out team info - int theTotalSize = (MAX_PLAYERS + 1)*(sizeof(hud_player_info_t) + sizeof(extra_player_info_t) + sizeof(team_info_t) + sizeof(int)); - unsigned char* theCharArray = new unsigned char[theTotalSize]; - if(theCharArray) - { - int theCounter = 0; - SaveData(theCharArray, &g_PlayerInfoList, (MAX_PLAYERS+1)*sizeof(hud_player_info_t), theCounter); - SaveData(theCharArray, &g_PlayerExtraInfo, (MAX_PLAYERS+1)*sizeof(extra_player_info_t), theCounter); - SaveData(theCharArray, &g_TeamInfo, (MAX_PLAYERS+1)*sizeof(team_info_t), theCounter); - SaveData(theCharArray, &g_IsSpectator, (MAX_PLAYERS+1)*sizeof(int), theCounter); - - Demo_WriteBuffer(TYPE_PLAYERINFO, theTotalSize, theCharArray); - } -} - -// Column sizes -class SBColumnInfo -{ -public: - char *m_pTitle; // If null, ignore, if starts with #, it's localized, otherwise use the string directly. - int m_Width; // Based on 640 width. Scaled to fit other resolutions. - Label::Alignment m_Alignment; -}; - -// grid size is marked out for 640x480 screen - -SBColumnInfo g_ColumnInfo[NUM_COLUMNS] = -{ - {NULL, 24, Label::a_center}, // tracker column - {NULL, 24, Label::a_center}, // status icons - {NULL, 110, Label::a_center}, // name - {NULL, 56, Label::a_center}, // class - {NULL, 40, Label::a_center}, // resources - {NULL, 18, Label::a_center}, // weld - {NULL, 18, Label::a_center}, // weld - {"#SCORE", 35, Label::a_center}, // score - {"#KILLS", 35, Label::a_center}, // kills - {"#DEATHS", 35, Label::a_center}, // deaths - {"#LATENCY", 35, Label::a_center}, // ping - {"#VOICE", 40, Label::a_center}, - {NULL, 2, Label::a_center}, // blank column to take up the slack -}; - - -#define TEAM_NO 0 -#define TEAM_YES 1 -#define TEAM_SPECTATORS 2 -#define TEAM_BLANK 3 - -//----------------------------------------------------------------------------- -// ScorePanel::HitTestPanel. -//----------------------------------------------------------------------------- - -void ScorePanel::HitTestPanel::internalMousePressed(MouseCode code) -{ - for(int i=0;i<_inputSignalDar.getCount();i++) - { - _inputSignalDar[i]->mousePressed(code,this); - } -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -vgui::Color BuildColor( int R, int G, int B, float gamma ) -{ - ASSERT( gamma != 0 ); - return vgui::Color( R/gamma, G/gamma, B/gamma, 0 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Create the ScoreBoard panel -//----------------------------------------------------------------------------- -ScorePanel::ScorePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) -{ - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); - SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); - SchemeHandle_t hTinyScheme = pSchemes->getSchemeHandle("Scoreboard Tiny Text"); - Font *tfont = pSchemes->getFont(hTitleScheme); - Font *smallfont = pSchemes->getFont(hSmallScheme); - Font *tinyfont = pSchemes->getFont(hTinyScheme); - - setBgColor(0, 0, 0, 96); - m_pCurrentHighlightLabel = NULL; - m_iHighlightRow = -1; - // : 0001073 - m_pTrackerIcon = NULL; - m_pDevIcon = NULL; - m_pPTIcon = NULL; - m_pGuideIcon = NULL; - m_pServerOpIcon = NULL; - m_pContribIcon = NULL; - m_pCheatingDeathIcon = NULL; - m_pVeteranIcon = NULL; - - m_pHMG = NULL; - m_pMine = NULL; - m_pWeld = NULL; - m_pGL = NULL; - m_pSG = NULL; - - - m_pTrackerIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardtracker.tga"); - m_pDevIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboarddev.tga"); - m_pPTIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardpt.tga"); - m_pGuideIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardguide.tga"); - m_pServerOpIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardserverop.tga"); - m_pContribIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardcontrib.tga"); - m_pCheatingDeathIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardcd.tga"); - m_pVeteranIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardveteran.tga"); - - - - m_pHMG = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardhmg.tga"); - m_pMine = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardmine.tga"); - m_pWeld = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardwelder.tga"); - m_pGL = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardgl.tga"); - m_pSG = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_scoreboardsg.tga"); - - m_iIconFrame = 0; - m_iLastFrameIncrementTime = gHUD.GetTimeOfLastUpdate(); - - // Initialize the top title. - m_TitleLabel.setFont(tfont); - m_TitleLabel.setText(""); - m_TitleLabel.setBgColor( 0, 0, 0, 255 ); - m_TitleLabel.setFgColor( Scheme::sc_primary1 ); - m_TitleLabel.setContentAlignment( vgui::Label::a_center ); - - LineBorder *border = new LineBorder(Color(60, 60, 60, 128)); - setBorder(border); - setPaintBorderEnabled(true); - - int xpos = g_ColumnInfo[0].m_Width + 3; - if (ScreenWidth() >= 640) - { - // only expand column size for res greater than 640 - xpos = XRES(xpos); - } - m_TitleLabel.setBounds(xpos, 4, wide, SBOARD_TITLE_SIZE_Y); - m_TitleLabel.setContentFitted(false); - m_TitleLabel.setParent(this); - - // Setup the header (labels like "name", "class", etc..). - m_HeaderGrid.SetDimensions(NUM_COLUMNS, 1); - m_HeaderGrid.SetSpacing(0, 0); - int i=0; - for( i=0; i < NUM_COLUMNS; i++) - { - if (g_ColumnInfo[i].m_pTitle && g_ColumnInfo[i].m_pTitle[0] == '#') - m_HeaderLabels[i].setText(CHudTextMessage::BufferedLocaliseTextString(g_ColumnInfo[i].m_pTitle)); - else if(g_ColumnInfo[i].m_pTitle) - m_HeaderLabels[i].setText(g_ColumnInfo[i].m_pTitle); - - int xwide = g_ColumnInfo[i].m_Width; - if (ScreenWidth() >= 640) - { - xwide = XRES(xwide); - } - else if (ScreenWidth() == 400) - { - // hack to make 400x300 resolution scoreboard fit - if (i == 1) - { - // reduces size of player name cell - xwide -= 28; - } - else if (i == 0) - { - // tracker icon cell - xwide -= 8; - } - } - - m_HeaderGrid.SetColumnWidth(i, xwide); - m_HeaderGrid.SetEntry(i, 0, &m_HeaderLabels[i]); - - m_HeaderLabels[i].setBgColor(0,0,0,255); - m_HeaderLabels[i].setBgColor(0,0,0,255); - - int theColorIndex = 0; - Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); - int theR, theG, theB, theA; - gammaAdjustedTeamColor.getColor(theR, theG, theB, theA); - m_HeaderLabels[i].setFgColor(theR, theG, theB, theA); - - m_HeaderLabels[i].setFont(smallfont); - m_HeaderLabels[i].setContentAlignment(g_ColumnInfo[i].m_Alignment); - - int yres = 12; - if (ScreenHeight() >= 480) - { - yres = YRES(yres); - } - m_HeaderLabels[i].setSize(50, yres); - } - - // Set the width of the last column to be the remaining space. - int ex, ey, ew, eh; - m_HeaderGrid.GetEntryBox(NUM_COLUMNS - 2, 0, ex, ey, ew, eh); - m_HeaderGrid.SetColumnWidth(NUM_COLUMNS - 1, (wide - X_BORDER) - (ex + ew)); - - m_HeaderGrid.AutoSetRowHeights(); - m_HeaderGrid.setBounds(X_BORDER, SBOARD_TITLE_SIZE_Y, wide - X_BORDER*2, m_HeaderGrid.GetRowHeight(0)); - m_HeaderGrid.setParent(this); - m_HeaderGrid.setBgColor(0,0,0,255); - - - // Now setup the listbox with the actual player data in it. - int headerX, headerY, headerWidth, headerHeight; - m_HeaderGrid.getBounds(headerX, headerY, headerWidth, headerHeight); - m_PlayerList.setBounds(headerX, headerY+headerHeight, headerWidth, tall - headerY - headerHeight - 6); - m_PlayerList.setBgColor(0,0,0,255); - m_PlayerList.setParent(this); - - for(int row=0; row < NUM_ROWS; row++) - { - CGrid *pGridRow = &m_PlayerGrids[row]; - - pGridRow->SetDimensions(NUM_COLUMNS, 1); - - for(int col=0; col < NUM_COLUMNS; col++) - { - m_PlayerEntries[col][row].setContentFitted(false); - m_PlayerEntries[col][row].setRow(row); - m_PlayerEntries[col][row].addInputSignal(this); - pGridRow->SetEntry(col, 0, &m_PlayerEntries[col][row]); - } - - pGridRow->setBgColor(0,0,0,255); -// pGridRow->SetSpacing(2, 0);f - pGridRow->SetSpacing(0, 0); - pGridRow->CopyColumnWidths(&m_HeaderGrid); - pGridRow->AutoSetRowHeights(); - pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); - pGridRow->RepositionContents(); - - m_PlayerList.AddItem(pGridRow); - } - - - // Add the hit test panel. It is invisible and traps mouse clicks so we can go into squelch mode. - m_HitTestPanel.setBgColor(0,0,0,255); - m_HitTestPanel.setParent(this); - m_HitTestPanel.setBounds(0, 0, wide, tall); - m_HitTestPanel.addInputSignal(this); - - m_pCloseButton = new CommandButton( "x", wide-XRES(12 + 4), YRES(2), XRES( 12 ) , YRES( 12 ) ); - m_pCloseButton->setParent( this ); - m_pCloseButton->addActionSignal( new CMenuHandler_StringCommandWatch( "-showscores", true ) ); - m_pCloseButton->setBgColor(0,0,0,255); - m_pCloseButton->setFgColor( 255, 255, 255, 0 ); - m_pCloseButton->setFont(tfont); - m_pCloseButton->setBoundKey( (char)255 ); - m_pCloseButton->setContentAlignment(Label::a_center); - Initialize(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Called each time a new level is started. -//----------------------------------------------------------------------------- -void ScorePanel::Initialize( void ) -{ - // Clear out scoreboard data - m_iLastKilledBy = 0; - m_fLastKillTime = 0; - m_iPlayerNum = 0; - m_iNumTeams = 0; - // : 0001073 -// for( int counter = 0; counter < MAX_PLAYERS+1; counter++ ) -// { -// delete g_PlayerExtraInfo[counter].icon; -// } - - memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); - memset( g_TeamInfo, 0, sizeof g_TeamInfo ); -} - -bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ) -{ - return !!gEngfuncs.GetPlayerUniqueID( iPlayer, playerID ); -} -//----------------------------------------------------------------------------- -// Purpose: Recalculate the internal scoreboard data -//----------------------------------------------------------------------------- -void ScorePanel::Update() -{ - - // Set the title - char title[128]; - - char theServerName[MAX_SERVERNAME_LENGTH+1]; - if (gViewPort->m_szServerName) - { - memset(theServerName, 0, MAX_SERVERNAME_LENGTH+1); - int iServerNameLength = max((int)strlen(gViewPort->m_szServerName),MAX_SERVERNAME_LENGTH); - strncat(theServerName, gViewPort->m_szServerName, iServerNameLength); - } - theServerName[MAX_SERVERNAME_LENGTH]=0; - char theMapName[MAX_MAPNAME_LENGTH+1]; - sprintf(theMapName, "%s", gHUD.GetMapName().c_str()); - - int theTimeElapsed = gHUD.GetGameTime(); - char elapsedString[64]; - if ( theTimeElapsed > 0 ) { - int theMinutesElapsed = theTimeElapsed/60; - int theSecondsElapsed = theTimeElapsed%60; - sprintf(elapsedString, "Game time: %d:%02d", theMinutesElapsed, theSecondsElapsed); - } - else { - sprintf(elapsedString, ""); - } - - sprintf(title, "%32s Map: %s %s", theServerName, theMapName, elapsedString); - - m_TitleLabel.setText(title); - - int theColorIndex = 0; - - // Set gamma-correct title color - - Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); - - int theR, theG, theB, theA; - gammaAdjustedTeamColor.getColor(theR, theG, theB, theA); - - m_TitleLabel.setFgColor(theR, theG, theB, theA); - - m_iRows = 0; - gViewPort->GetAllPlayersInfo(); - - // Clear out sorts - int i = 0; - for (i = 0; i < NUM_ROWS; i++) - { - m_iSortedRows[i] = 0; - m_iIsATeam[i] = TEAM_IND; - } - - // Fix for memory overrun bug - - for (i = 0; i < MAX_PLAYERS; i++) - { - m_bHasBeenSorted[i] = false; - } - - SortTeams(); - - // set scrollbar range - m_PlayerList.SetScrollRange(m_iRows); - - FillGrid(); - if ( gViewPort->m_pSpectatorPanel->m_menuVisible ) - { - m_pCloseButton->setVisible ( true ); - } - else - { - m_pCloseButton->setVisible ( false ); - } - -} - -//----------------------------------------------------------------------------- -// Purpose: Sort all the teams -//----------------------------------------------------------------------------- -void ScorePanel::SortTeams() -{ - // clear out team scores - float theCurrentTime = gHUD.GetTimeOfLastUpdate(); - int i=0; - int j=0; - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( !g_TeamInfo[i].scores_overriden ) - { - g_TeamInfo[i].score =0; - } - g_TeamInfo[i].frags = g_TeamInfo[i].deaths = g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; - } - - // recalc the team scores, then draw them - for ( i = 1; i <= MAX_PLAYERS; i++ ) - { - if ( g_PlayerInfoList[i].name == NULL ) - continue; // empty player slot, skip - - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // find what team this player is in - for ( j = 1; j <= m_iNumTeams; j++ ) - { - if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) - break; - } - if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy - continue; - - if ( !g_TeamInfo[j].scores_overriden ) - { - g_TeamInfo[j].score += g_PlayerExtraInfo[i].score; - } - - g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; - g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; - g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; - g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; - - if ( g_PlayerInfoList[i].thisplayer ) - g_TeamInfo[j].ownteam = TRUE; - else - g_TeamInfo[j].ownteam = FALSE; - - // Set the team's number (used for team colors) - g_TeamInfo[j].teamnumber = g_PlayerExtraInfo[i].teamnumber; - } - - // find team ping/packetloss averages - for ( i = 1; i <= m_iNumTeams; i++ ) - { - g_TeamInfo[i].already_drawn = FALSE; - - if ( g_TeamInfo[i].players > 0 ) - { - g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - } - } - vector teams; - if ( gHUD.GetHUDTeam() == TEAM_TWO || gHUD.GetHUDTeam() == TEAM_FOUR ) { - SortActivePlayers(kAlien1Team); - SortActivePlayers(kMarine1Team); - SortActivePlayers(kAlien2Team); - SortActivePlayers(kMarine2Team); - } - else { - SortActivePlayers(kMarine1Team); - SortActivePlayers(kAlien1Team); - SortActivePlayers(kMarine2Team); - SortActivePlayers(kAlien2Team); - } - - SortActivePlayers(kSpectatorTeam); - SortActivePlayers(kUndefinedTeam); -} - -void ScorePanel::SortActivePlayers(char* inTeam, bool inSortByEntityIndex) -{ - for(int i = 1; i <= m_iNumTeams; i++) - { - if(!strcmp(g_TeamInfo[i].name, inTeam)) - { - int best_team = i; - - // Put this team in the sorted list - m_iSortedRows[ m_iRows ] = best_team; - m_iIsATeam[ m_iRows ] = TEAM_YES; - g_TeamInfo[best_team].already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get sorted again - m_iRows++; - - // Now sort all the players on this team - SortPlayers(0, g_TeamInfo[best_team].name, inSortByEntityIndex); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Sort a list of players -//----------------------------------------------------------------------------- -void ScorePanel::SortPlayers( int iTeam, char *team, bool inSortByEntityIndex) -{ - bool bCreatedTeam = false; - - // draw the players, in order, and restricted to team if set - while ( 1 ) - { - // Find the top ranking player - int theBestTotalScore = -99999; - int theBestDeaths = 0; - int theBestPlayer = 0; - - for ( int i = 1; i <= MAX_PLAYERS; i++ ) - { - if ( m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( i ); - - if ( ent && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) - { - extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; - - // Sort by player index to mask marine status - if(inSortByEntityIndex) - { - if((theBestPlayer == 0) || (i < theBestPlayer)) - { - theBestPlayer = i; - } - } - else - { - // overall rank = score + kills (with least deaths breaking ties) - int thePlayerScore = pl_info->score; - int thePlayerDeaths = pl_info->deaths; - if((thePlayerScore > theBestTotalScore) || ((thePlayerScore == theBestTotalScore) && (pl_info->deaths < theBestDeaths))) - { - theBestPlayer = i; - theBestTotalScore = thePlayerScore; - theBestDeaths = thePlayerDeaths; - } - } - } - } - } - - if ( !theBestPlayer ) - break; - - // If we haven't created the Team yet, do it first - if (!bCreatedTeam && iTeam) - { - m_iIsATeam[ m_iRows ] = iTeam; - m_iRows++; - - bCreatedTeam = true; - } - - // Put this player in the sorted list - m_iSortedRows[ m_iRows ] = theBestPlayer; - m_bHasBeenSorted[ theBestPlayer ] = true; - m_iRows++; - } - - if (team) - { - m_iIsATeam[m_iRows++] = TEAM_BLANK; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Recalculate the existing teams in the match -//----------------------------------------------------------------------------- -void ScorePanel::RebuildTeams() -{ - // clear out player counts from teams - int i=0; - int j=0; - for ( i = 1; i <= m_iNumTeams; i++ ) - { - g_TeamInfo[i].players = 0; - } - - // rebuild the team list - gViewPort->GetAllPlayersInfo(); - m_iNumTeams = 0; - for ( i = 1; i <= MAX_PLAYERS; i++ ) - { - if ( g_PlayerInfoList[i].name == NULL ) - continue; - - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // is this player in an existing team? - for ( j = 1; j <= m_iNumTeams; j++ ) - { - if ( g_TeamInfo[j].name[0] == '\0' ) - break; - - if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) - break; - } - - if ( j > m_iNumTeams ) - { // they aren't in a listed team, so make a new one - // search through for an empty team slot - for ( j = 1; j <= m_iNumTeams; j++ ) - { - if ( g_TeamInfo[j].name[0] == '\0' ) - break; - } - m_iNumTeams = max( j, m_iNumTeams ); - strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); - g_TeamInfo[j].players = 0; - } - - g_TeamInfo[j].players++; - } - - // clear out any empty teams - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( g_TeamInfo[i].players < 1 ) - memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); - } - - // Update the scoreboard - Update(); -} - -//----------------------------------------------------------------------------- - -int ScorePanel::GetIconFrame(void) -{ - const static int kIconFrameDuration = 0.25; - - int current_time = gHUD.GetTimeOfLastUpdate(); - if( (m_iLastFrameIncrementTime - current_time) > kIconFrameDuration ) - { - m_iLastFrameIncrementTime = current_time; - m_iIconFrame++; - if( m_iIconFrame >= 1000 ) - { - m_iIconFrame = 0; - } - } - return m_iIconFrame; -} - -//----------------------------------------------------------------------------- - -void ScorePanel::FillGrid() -{ - bool isNsMode=( strnicmp(gHUD.GetMapName().c_str(), "ns_", 3) == 0 ); - - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - SchemeHandle_t hScheme = pSchemes->getSchemeHandle("Scoreboard Text"); - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); - SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); - SchemeHandle_t hTinyScheme = pSchemes->getSchemeHandle("Scoreboard Tiny Text"); - - Font *sfont = pSchemes->getFont(hScheme); - Font *tfont = pSchemes->getFont(hTitleScheme); - Font *smallfont = pSchemes->getFont(hSmallScheme); - Font *tinyfont = pSchemes->getFont(hTinyScheme); - - // update highlight position - int x, y; - getApp()->getCursorPos(x, y); - cursorMoved(x, y, this); - - // remove highlight row if we're not in squelch mode - if (!GetClientVoiceMgr()->IsInSquelchMode()) - { - m_iHighlightRow = -1; - } - - bool bNextRowIsGap = false; - m_HeaderLabels[COLUMN_EXTRA].setText(""); - m_HeaderLabels[COLUMN_MINE].setText(""); - m_HeaderLabels[COLUMN_WELD].setText(""); - if ( isNsMode ) { - if ( gHUD.GetHUDTeam() == TEAM_ONE || gHUD.GetHUDTeam() == TEAM_THREE ) { - m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLWEAP")); - } - else if ( gHUD.GetHUDTeam() == TEAM_TWO || gHUD.GetHUDTeam() == TEAM_FOUR ) { - m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLRES")); - } - } - else { - if ( gHUD.GetHUDTeam() != TEAM_IND && gHUD.GetHUDTeam() != TEAM_SPECT ) - m_HeaderLabels[COLUMN_EXTRA].setText(CHudTextMessage::BufferedLocaliseTextString("#COLLEVEL")); - } - - for(int row=0; row < NUM_ROWS; row++) - { - CGrid *pGridRow = &m_PlayerGrids[row]; - pGridRow->SetRowUnderline(0, false, 0, 0, 0, 0, 0); - - if(row >= m_iRows) - { - for(int col=0; col < NUM_COLUMNS; col++) - m_PlayerEntries[col][row].setVisible(false); - - continue; - } - - bool bRowIsGap = false; - if (bNextRowIsGap) - { - bNextRowIsGap = false; - bRowIsGap = true; - } - - // Get the player's data - int theSortedRow = m_iSortedRows[row]; - hud_player_info_t* pl_info = &g_PlayerInfoList[theSortedRow]; - extra_player_info_t* theExtraPlayerInfo = &g_PlayerExtraInfo[theSortedRow]; - int thePlayerClass = theExtraPlayerInfo->playerclass; - short theTeamNumber = theExtraPlayerInfo->teamnumber; - string theCustomIcon = (string)theExtraPlayerInfo->customicon; -// : 0001073 - short thePlayerAuthentication = theExtraPlayerInfo->auth; - bool thePlayerIsDead = false; - switch( thePlayerClass ) - { - case PLAYERCLASS_DEAD_MARINE: - case PLAYERCLASS_DEAD_ALIEN: - case PLAYERCLASS_REINFORCING: - thePlayerIsDead = true; - break; - } - - // Code to test DEBUG -#if 0 - #ifdef DEBUG - extern int gGlobalDebugAuth; - thePlayerAuthentication = 1; - thePlayerAuthentication <<= gGlobalDebugAuth; - #endif -#endif - - team_info_t* team_info = &g_TeamInfo[m_iSortedRows[row]]; - int theColorIndex = theTeamNumber % iNumberOfTeamColors; - - int theLocalPlayerTeam = 0; - if(gEngfuncs.GetLocalPlayer()) - { - theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; - } - - for(int col=0; col < NUM_COLUMNS; col++) - { - CLabelHeader *pLabel = &m_PlayerEntries[col][row]; - - pLabel->setVisible(true); - pLabel->setText2(""); - pLabel->setImage(NULL); - pLabel->setFont(sfont); - pLabel->setTextOffset(0, 0); - - int rowheight = 13; - if (ScreenHeight() > 480) - { - rowheight = YRES(rowheight); - } - else - { - // more tweaking, make sure icons fit at low res - rowheight = 15; - } - pLabel->setSize(pLabel->getWide(), rowheight); - pLabel->setBgColor(0, 0, 0, 255); - - char sz[128]; - - Color gammaAdjustedTeamColor = BuildColor(kTeamColors[theColorIndex][0], kTeamColors[theColorIndex][1], kTeamColors[theColorIndex][2], gHUD.GetGammaSlope()); - pLabel->setFgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 0); - - if (m_iIsATeam[row] == TEAM_BLANK) - { - pLabel->setText(" "); - continue; - } - else if ( m_iIsATeam[row] == TEAM_YES ) - { - theColorIndex = team_info->teamnumber % iNumberOfTeamColors; - - // team color text for team names - - - - // different height for team header rows - rowheight = 20; - if (ScreenHeight() >= 480) - { - rowheight = YRES(rowheight); - } - pLabel->setSize(pLabel->getWide(), rowheight); - pLabel->setFont(tfont); - - pGridRow->SetRowUnderline( 0, - true, - YRES(3), - gammaAdjustedTeamColor[0], - gammaAdjustedTeamColor[1], - gammaAdjustedTeamColor[2], - 0 ); - } - else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) - { - // grey text for spectators - pLabel->setFgColor(100, 100, 100, 0); - - // different height for team header rows - rowheight = 20; - if (ScreenHeight() >= 480) - { - rowheight = YRES(rowheight); - } - pLabel->setSize(pLabel->getWide(), rowheight); - pLabel->setFont(tfont); - - pGridRow->SetRowUnderline(0, true, YRES(3), 100, 100, 100, 0); - } - else - { - if(thePlayerIsDead) - { - pLabel->setFgColor(255, 0, 0, 0); - } - else - { - // team color text for player names - pLabel->setFgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 0); - } - - // Set background color - if ( pl_info && pl_info->thisplayer ) // if it is their name, draw it a different color - { - // Highlight this player - pLabel->setFgColor(Scheme::sc_white); - pLabel->setBgColor(gammaAdjustedTeamColor[0], gammaAdjustedTeamColor[1], gammaAdjustedTeamColor[2], 196 ); - } - else if ( theSortedRow == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) - { - // Killer's name - pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); - } - } - - // Align - switch(col) - { - case COLUMN_NAME: - case COLUMN_CLASS: - pLabel->setContentAlignment( vgui::Label::a_west ); - break; - - case COLUMN_TRACKER: - case COLUMN_RANK_ICON: - case COLUMN_VOICE: - pLabel->setContentAlignment( vgui::Label::a_center ); - break; - - case COLUMN_SCORE: - case COLUMN_KILLS: - case COLUMN_EXTRA: - case COLUMN_MINE: - case COLUMN_WELD: - case COLUMN_DEATHS: - case COLUMN_LATENCY: - default: - pLabel->setContentAlignment( vgui::Label::a_center ); - break; - } - - // Fill out with the correct data - strcpy(sz, ""); - if ( m_iIsATeam[row] ) - { - char sz2[128]; - - switch (col) - { - case COLUMN_NAME: - if ( m_iIsATeam[row] == TEAM_SPECTATORS ) - { - sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); - } - else - { - if(team_info) - { - sprintf( sz2, gViewPort->GetTeamName(team_info->teamnumber) ); - } - } - - strcpy(sz, sz2); - - // Append the number of players - if ( m_iIsATeam[row] == TEAM_YES && team_info) - { - if (team_info->players == 1) - { - sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player" ) ); - } - else - { - sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player_plural" ) ); - } - - pLabel->setText2(sz2); - pLabel->setFont2(smallfont); - } - break; - case COLUMN_VOICE: - break; - case COLUMN_CLASS: - break; - case COLUMN_SCORE: - if ((m_iIsATeam[row] == TEAM_YES) && team_info && (theLocalPlayerTeam == team_info->teamnumber || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER))) - sprintf(sz, "%d", team_info->score); - break; - case COLUMN_MINE: - break; - case COLUMN_WELD: - break; - case COLUMN_EXTRA: - break; - case COLUMN_KILLS: - if ((m_iIsATeam[row] == TEAM_YES) && team_info) - sprintf(sz, "%d", team_info->frags ); - break; - case COLUMN_DEATHS: - if ((m_iIsATeam[row] == TEAM_YES) && team_info) - sprintf(sz, "%d", team_info->deaths ); - break; - case COLUMN_LATENCY: - if ((m_iIsATeam[row] == TEAM_YES) && team_info) - sprintf(sz, "%d", team_info->ping ); - break; - default: - break; - } - } - else - { - // Are these stats for an enemy? Score and other stats shouldn't be drawn for enemies. - bool theIsForEnemy = false; - - int theLocalPlayerTeam = 0; - if(gEngfuncs.GetLocalPlayer()) - { - theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; - } - - if((theLocalPlayerTeam != 0) && (theExtraPlayerInfo->teamnumber != theLocalPlayerTeam)) - { - theIsForEnemy = true; - } - - switch (col) - { - case COLUMN_NAME: - /* - if (g_pTrackerUser) - { - int playerSlot = m_iSortedRows[row]; - int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); - const char *trackerName = g_pTrackerUser->GetUserName(trackerID); - if (trackerName && *trackerName) - { - sprintf(sz, " (%s)", trackerName); - pLabel->setText2(sz); - } - } - */ - if(pl_info) - { - sprintf(sz, "%s ", pl_info->name); - } - break; - case COLUMN_VOICE: - sz[0] = 0; - // in HLTV mode allow spectator to turn on/off commentator voice - if (pl_info && (!pl_info->thisplayer || gEngfuncs.IsSpectateOnly())) - { - GetClientVoiceMgr()->UpdateSpeakerImage(pLabel, theSortedRow); - } - break; - case COLUMN_CLASS: - // No class for other team's members (unless allied or spectator, and make sure player is on our team) - strcpy(sz, ""); - - if(team_info && ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER))) - { - switch(thePlayerClass) - { - case (int)(PLAYERCLASS_DEAD_MARINE): - case (int)(PLAYERCLASS_DEAD_ALIEN): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassDead)); - break; - case (int)(PLAYERCLASS_REINFORCING): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassReinforcing)); - break; - case (int)(PLAYERCLASS_REINFORCINGCOMPLETE): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassReinforcingComplete)); - break; - case (int)(PLAYERCLASS_ALIVE_JETPACK_MARINE): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassJetpackMarine)); - break; - case (int)(PLAYERCLASS_ALIVE_HEAVY_MARINE): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassHeavyMarine)); - break; - case (int)(PLAYERCLASS_COMMANDER): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassCommander)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL1): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel1)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL2): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel2)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL3): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel3)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL4): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel4)); - break; - case (int)(PLAYERCLASS_ALIVE_LEVEL5): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassLevel5)); - break; - case (int)(PLAYERCLASS_ALIVE_DIGESTING): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassDigesting)); - break; - case (int)(PLAYERCLASS_ALIVE_GESTATING): - sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString(kClassGestating)); - break; - default: - break; - } - } - break; - - case COLUMN_RANK_ICON: -// : 0001073 -#ifdef USE_OLDAUTH - // Check if we have authority. Right now these override the tracker icons. Listed in increasing order of "importance". - if(thePlayerAuthentication & PLAYERAUTH_CHEATINGDEATH) - { - // Red - pLabel->setImage(m_pCheatingDeathIcon); - pLabel->setFgColorAsImageColor(false); - m_pCheatingDeathIcon->setColor(BuildColor(255, 69, 9, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_VETERAN) - { - // Yellow - pLabel->setImage(m_pVeteranIcon); - pLabel->setFgColorAsImageColor(false); - m_pVeteranIcon->setColor(BuildColor(248, 252, 0, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_BETASERVEROP) - { - // Whitish - pLabel->setImage(m_pServerOpIcon); - pLabel->setFgColorAsImageColor(false); - m_pServerOpIcon->setColor(BuildColor(220, 220, 220, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_CONTRIBUTOR) - { - // Light blue - pLabel->setImage(m_pContribIcon); - pLabel->setFgColorAsImageColor(false); - m_pContribIcon->setColor(BuildColor(117, 214, 241, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_GUIDE) - { - // Magenta - pLabel->setImage(m_pGuideIcon); - pLabel->setFgColorAsImageColor(false); - m_pGuideIcon->setColor(BuildColor(208, 16, 190, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_PLAYTESTER) - { - // Orange - pLabel->setImage(m_pPTIcon); - pLabel->setFgColorAsImageColor(false); - m_pPTIcon->setColor(BuildColor(255, 167, 54, gHUD.GetGammaSlope())); - } - if(thePlayerAuthentication & PLAYERAUTH_DEVELOPER) - { - // TSA blue - pLabel->setImage(m_pDevIcon); - pLabel->setFgColorAsImageColor(false); - m_pDevIcon->setColor(BuildColor(100, 215, 255, gHUD.GetGammaSlope())); - } - - if(thePlayerAuthentication & PLAYERAUTH_SERVEROP) - { - // Bright green - pLabel->setImage(m_pServerOpIcon); - pLabel->setFgColorAsImageColor(false); - m_pServerOpIcon->setColor(BuildColor(0, 255, 0, gHUD.GetGammaSlope())); - } - - // Allow custom icons to override other general icons - if(thePlayerAuthentication & PLAYERAUTH_CUSTOM) - { - if(theCustomIcon != "") - { - string theIconName = theCustomIcon.substr(0, strlen(theCustomIcon.c_str()) - 3); - string theFullCustomIconString = string("gfx/vgui/640_") + theIconName + string(".tga"); - - vgui::BitmapTGA *pIcon = GetIconPointer(theCustomIcon); - - //Icon hasnt been loaded, load it now and add it to list of icons. - if(pIcon == NULL) - { - pIcon = vgui_LoadTGANoInvertAlpha(theFullCustomIconString.c_str()); - - if(pIcon) - m_CustomIconList.push_back( make_pair(pIcon, theCustomIcon) ); - } - /* //@2014 to do - if(pIcon) - { - pLabel->setImage(pIcon); - pLabel->setFgColorAsImageColor(false); - - // Parse color (last 3 bytes are the RGB values 1-9) - string theColor = theCustomIcon.substr( strlen(theCustomIcon.c_str())-3, 3); - - - - int theRed = (MakeIntFromString(theColor.substr(0, 1))/9.0f)*255; - int theGreen = (MakeIntFromString(theColor.substr(1, 1))/9.0f)*255; - int theBlue = (MakeIntFromString(theColor.substr(2, 1))/9.0f)*255; - - - pIcon->setColor(BuildColor(theRed, theGreen, theBlue, gHUD.GetGammaSlope())); - }*/ - } - } - /* - if(g_pTrackerUser) - { - int playerSlot = theSortedRow; - int trackerID = gEngfuncs.GetTrackerIDForPlayer(playerSlot); - - if (g_pTrackerUser->IsFriend(trackerID) && trackerID != g_pTrackerUser->GetTrackerID()) - { - pLabel->setImage(m_pTrackerIcon); - pLabel->setFgColorAsImageColor(false); - m_pTrackerIcon->setColor(Color(255, 255, 255, 0)); - } - }*/ -#else - if( theExtraPlayerInfo->icon ) - { - vgui::Bitmap* image = theExtraPlayerInfo->icon->getImage( this->GetIconFrame() ); - if( image ) { pLabel->setImage( image ); } - } -#endif - break; - case COLUMN_SCORE: - if(!theIsForEnemy && theLocalPlayerTeam != TEAM_IND || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - const float kDeltaDisplayTime = 3.0f; - float theTimeSinceChange = gHUD.GetTimeOfLastUpdate() - theExtraPlayerInfo->timeOfLastScoreChange; - - if((theExtraPlayerInfo->score > theExtraPlayerInfo->lastScore) && (theTimeSinceChange > 0) && (theTimeSinceChange < kDeltaDisplayTime) && (theExtraPlayerInfo->teamnumber != 0)) - { - // draw score with change - int theDelta = (theExtraPlayerInfo->score - theExtraPlayerInfo->lastScore); - sprintf(sz, "(+%d) %d", theDelta, theExtraPlayerInfo->score); - } - else - { - sprintf(sz, "%d", theExtraPlayerInfo->score); - } - - } - break; - case COLUMN_WELD: - if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - if ( isNsMode ) { - if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { - if ( theExtraPlayerInfo->extra & WEAPON_WELDER ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pWeld); - m_pWeld->setColor(BuildColor(0, 149, 221, gHUD.GetGammaSlope())); - } - } - } - } - break; - - case COLUMN_MINE: - if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - if ( isNsMode ) { - if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { - if ( theExtraPlayerInfo->extra & WEAPON_MINE ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pMine); - m_pMine->setColor(BuildColor(0, 149, 221, gHUD.GetGammaSlope())); - } - } - } - } - break; - - case COLUMN_EXTRA: - if ((theLocalPlayerTeam == theTeamNumber) || (gHUD.GetPlayMode() == PLAYMODE_OBSERVER)) - { - if ( isNsMode ) { - if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_THREE ) { - int r=0, g=149, b=221; - if ( theExtraPlayerInfo->extra & WEAPON_HMG ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pHMG); - m_pHMG->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); - } - if ( theExtraPlayerInfo->extra & WEAPON_SG ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pSG); - m_pSG->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); - } - if ( theExtraPlayerInfo->extra & WEAPON_GL ) { - pLabel->setFgColorAsImageColor(false); - pLabel->setImage(m_pGL); - m_pGL->setColor(BuildColor(r, g, b, gHUD.GetGammaSlope())); - } - } - else if ( theExtraPlayerInfo->teamnumber == TEAM_TWO || theExtraPlayerInfo->teamnumber == TEAM_FOUR ) { - sprintf(sz, "%d", theExtraPlayerInfo->extra); - } - } - else if ( theExtraPlayerInfo->teamnumber == TEAM_ONE || theExtraPlayerInfo->teamnumber == TEAM_TWO || - theExtraPlayerInfo->teamnumber == TEAM_THREE || theExtraPlayerInfo->teamnumber == TEAM_FOUR ) { - sprintf(sz, "%d", theExtraPlayerInfo->extra); - } - } - break; - case COLUMN_KILLS: - sprintf(sz, "%d", theExtraPlayerInfo->frags); - break; - - case COLUMN_DEATHS: - sprintf(sz, "%d", theExtraPlayerInfo->deaths); - break; - case COLUMN_LATENCY: - if(pl_info) - { - sprintf(sz, "%d", pl_info->ping ); - } - break; - default: - break; - } - } - - pLabel->setText(sz); - } - } - - for(int row=0; row < NUM_ROWS; row++) - { - CGrid *pGridRow = &m_PlayerGrids[row]; - - pGridRow->AutoSetRowHeights(); - pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); - pGridRow->RepositionContents(); - } - - // hack, for the thing to resize - m_PlayerList.getSize(x, y); - m_PlayerList.setSize(x, y); -} - - -//----------------------------------------------------------------------------- -// Purpose: Setup highlights for player names in scoreboard -//----------------------------------------------------------------------------- -void ScorePanel::DeathMsg( int killer, int victim ) -{ - // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide - if ( victim == m_iPlayerNum || killer == 0 ) - { - m_iLastKilledBy = killer ? killer : m_iPlayerNum; - m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds - - if ( killer == m_iPlayerNum ) - m_iLastKilledBy = m_iPlayerNum; - } -} - - -void ScorePanel::Open( void ) -{ - RebuildTeams(); - setVisible(true); - m_HitTestPanel.setVisible(true); -} - -bool ScorePanel::SetSquelchMode(bool inMode) -{ - bool theSuccess = false; - - if(inMode && !GetClientVoiceMgr()->IsInSquelchMode()) - { - GetClientVoiceMgr()->StartSquelchMode(); - m_HitTestPanel.setVisible(false); - theSuccess = true; - } - else if(!inMode && GetClientVoiceMgr()->IsInSquelchMode()) - { - GetClientVoiceMgr()->StopSquelchMode(); - theSuccess = true; - } - - return theSuccess; -} - -void ScorePanel::mousePressed(MouseCode code, Panel* panel) -{ - if(gHUD.m_iIntermission) - return; - - if (!GetClientVoiceMgr()->IsInSquelchMode()) - { - //GetClientVoiceMgr()->StartSquelchMode(); - //m_HitTestPanel.setVisible(false); - this->SetSquelchMode(true); - } - else if (m_iHighlightRow >= 0) - { - // mouse has been pressed, toggle mute state - int iPlayer = m_iSortedRows[m_iHighlightRow]; - if (iPlayer > 0) - { - // print text message - hud_player_info_t *pl_info = &g_PlayerInfoList[iPlayer]; - - if (pl_info && pl_info->name && pl_info->name[0]) - { - char string[256]; - if (GetClientVoiceMgr()->IsPlayerBlocked(iPlayer)) - { - char string1[1024]; - - // remove mute - GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, false); - - sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Unmuted" ), pl_info->name ); - sprintf( string, "%c** %s\n", HUD_PRINTTALK, string1 ); - - gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, (int)strlen(string)+1, string ); - } - else - { - char string1[1024]; - char string2[1024]; - - // mute the player - GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, true); - - sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Muted" ), pl_info->name ); - sprintf( string2, CHudTextMessage::BufferedLocaliseTextString( "#No_longer_hear_that_player" ) ); - sprintf( string, "%c** %s %s\n", HUD_PRINTTALK, string1, string2 ); - - gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, (int)strlen(string)+1, string ); - } - } - } - } -} - -void ScorePanel::cursorMoved(int x, int y, Panel *panel) -{ - if (GetClientVoiceMgr()->IsInSquelchMode()) - { - // look for which cell the mouse is currently over - for (int i = 0; i < NUM_ROWS; i++) - { - int row, col; - if (m_PlayerGrids[i].getCellAtPoint(x, y, row, col)) - { - MouseOverCell(i, col); - return; - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Handles mouse movement over a cell -// Input : row - -// col - -//----------------------------------------------------------------------------- -void ScorePanel::MouseOverCell(int row, int col) -{ - CLabelHeader *label = &m_PlayerEntries[col][row]; - - // clear the previously highlighted label - if (m_pCurrentHighlightLabel != label) - { - m_pCurrentHighlightLabel = NULL; - m_iHighlightRow = -1; - } - if (!label) - return; - - // don't act on teams - if (m_iIsATeam[row] != TEAM_IND) - return; - - // don't act on disconnected players or ourselves - hud_player_info_t *pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; - if (!pl_info->name || !pl_info->name[0]) - return; - - if (pl_info->thisplayer && !gEngfuncs.IsSpectateOnly() ) - return; - - // only act on audible players - //if (!GetClientVoiceMgr()->IsPlayerAudible(m_iSortedRows[row])) - // return; - - // setup the new highlight - m_pCurrentHighlightLabel = label; - m_iHighlightRow = row; -} - -//----------------------------------------------------------------------------- -// Purpose: Label paint functions - take into account current highligh status -//----------------------------------------------------------------------------- -void CLabelHeader::paintBackground() -{ - Color oldBg; - getBgColor(oldBg); - - if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) - { - setBgColor(134, 91, 19, 0); - } - - Panel::paintBackground(); - - setBgColor(oldBg); -} - - -//----------------------------------------------------------------------------- -// Purpose: Label paint functions - take into account current highligh status -//----------------------------------------------------------------------------- -void CLabelHeader::paint() -{ - Color oldFg; - getFgColor(oldFg); - - if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) - { - setFgColor(255, 255, 255, 0); - } - - // draw text - int x, y, iwide, itall; - getTextSize(iwide, itall); - calcAlignment(iwide, itall, x, y); - _dualImage->setPos(x, y); - - int x1, y1; - _dualImage->GetImage(1)->getPos(x1, y1); - _dualImage->GetImage(1)->setPos(_gap, y1); - - _dualImage->doPaint(this); - - // get size of the panel and the image - if (_image) - { - Color imgColor; - getFgColor( imgColor ); - if( _useFgColorAsImageColor ) - { - _image->setColor( imgColor ); - } - _image->getSize(iwide, itall); - calcAlignment(iwide, itall, x, y); - _image->setPos(x, y); - _image->doPaint(this); - } - - setFgColor(oldFg[0], oldFg[1], oldFg[2], oldFg[3]); -} - - -void CLabelHeader::calcAlignment(int iwide, int itall, int &x, int &y) -{ - // calculate alignment ourselves, since vgui is so broken - int wide, tall; - getSize(wide, tall); - - x = 0, y = 0; - - // align left/right - switch (_contentAlignment) - { - // left - case Label::a_northwest: - case Label::a_west: - case Label::a_southwest: - { - x = 0; - break; - } - - // center - case Label::a_north: - case Label::a_center: - case Label::a_south: - { - x = (wide - iwide) / 2; - break; - } - - // right - case Label::a_northeast: - case Label::a_east: - case Label::a_southeast: - { - x = wide - iwide; - break; - } - } - - // top/down - switch (_contentAlignment) - { - // top - case Label::a_northwest: - case Label::a_north: - case Label::a_northeast: - { - y = 0; - break; - } - - // center - case Label::a_west: - case Label::a_center: - case Label::a_east: - { - y = (tall - itall) / 2; - break; - } - - // south - case Label::a_southwest: - case Label::a_south: - case Label::a_southeast: - { - y = tall - itall; - break; - } - } - -// don't clip to Y -// if (y < 0) -// { -// y = 0; -// } - if (x < 0) - { - x = 0; - } - - x += _offset[0]; - y += _offset[1]; -} diff --git a/main/source/cl_dll/vgui_ScorePanel.h b/main/source/cl_dll/vgui_ScorePanel.h index 588c6ede..5558a1da 100644 --- a/main/source/cl_dll/vgui_ScorePanel.h +++ b/main/source/cl_dll/vgui_ScorePanel.h @@ -1,181 +1,181 @@ - -#ifndef SCOREPANEL_H -#define SCOREPANEL_H - -#include -#include -#include -#include -#include -#include -#include "vgui_listbox.h" - -#include - -#define MAX_SCORES 10 -#define MAX_SCOREBOARD_TEAMS 5 - -// Scoreboard cells -#define COLUMN_TRACKER 0 -#define COLUMN_RANK_ICON 1 -#define COLUMN_NAME 2 -#define COLUMN_CLASS 3 -#define COLUMN_EXTRA 4 -#define COLUMN_WELD 5 -#define COLUMN_MINE 6 -#define COLUMN_SCORE 7 -#define COLUMN_KILLS 8 -#define COLUMN_DEATHS 9 -#define COLUMN_LATENCY 10 -#define COLUMN_VOICE 11 -#define COLUMN_BLANK 12 -#define NUM_COLUMNS 13 -#define NUM_ROWS (MAX_PLAYERS + (MAX_SCOREBOARD_TEAMS * 2)) - -using namespace vgui; - -#include "CLabelHeader.h" - -class ScoreTablePanel; - -#include "vgui_grid.h" -#include "vgui_defaultinputsignal.h" - -//----------------------------------------------------------------------------- -// Purpose: Scoreboard back panel -//----------------------------------------------------------------------------- -class ScorePanel : public Panel, public vgui::CDefaultInputSignal -{ -private: - // Default panel implementation doesn't forward mouse messages when there is no cursor and we need them. - class HitTestPanel : public Panel - { - public: - virtual void internalMousePressed(MouseCode code); - }; - - -private: - - Label m_TitleLabel; - - // Here is how these controls are arranged hierarchically. - // m_HeaderGrid - // m_HeaderLabels - - // m_PlayerGridScroll - // m_PlayerGrid - // m_PlayerEntries - - CGrid m_HeaderGrid; - CLabelHeader m_HeaderLabels[NUM_COLUMNS]; // Labels above the - CLabelHeader *m_pCurrentHighlightLabel; - int m_iHighlightRow; - - vgui::CListBox m_PlayerList; - CGrid m_PlayerGrids[NUM_ROWS]; // The grid with player and team info. - CLabelHeader m_PlayerEntries[NUM_COLUMNS][NUM_ROWS]; // Labels for the grid entries. - - ScorePanel::HitTestPanel m_HitTestPanel; - CommandButton *m_pCloseButton; - CLabelHeader* GetPlayerEntry(int x, int y) {return &m_PlayerEntries[x][y];} - - vgui::BitmapTGA *m_pTrackerIcon; - - vgui::BitmapTGA *m_pDevIcon; - vgui::BitmapTGA *m_pPTIcon; - vgui::BitmapTGA *m_pGuideIcon; - vgui::BitmapTGA *m_pServerOpIcon; - vgui::BitmapTGA *m_pContribIcon; - vgui::BitmapTGA *m_pCheatingDeathIcon; - vgui::BitmapTGA *m_pVeteranIcon; - - vgui::BitmapTGA *m_pHMG; - vgui::BitmapTGA *m_pMine; - vgui::BitmapTGA *m_pWeld; - vgui::BitmapTGA *m_pGL; - vgui::BitmapTGA *m_pSG; - - vector< pair > m_CustomIconList; - - unsigned int m_iIconFrame; - unsigned int m_iLastFrameIncrementTime; - -public: - - int m_iNumTeams; - int m_iPlayerNum; - int m_iShowscoresHeld; - - int m_iRows; - int m_iSortedRows[NUM_ROWS]; - int m_iIsATeam[NUM_ROWS]; - bool m_bHasBeenSorted[MAX_PLAYERS]; - int m_iLastKilledBy; - int m_fLastKillTime; -public: - - ScorePanel(int x,int y,int wide,int tall); - - void Update( void ); - - int GetIconFrame(void); - - void SortTeams( void ); - void SortActivePlayers(char* inTeam, bool inSortByEntityIndex = false); - void SortPlayers( int iTeam, char *team, bool inSortByEntityIndex = false); - void RebuildTeams( void ); - bool SetSquelchMode(bool inMode); - - void FillGrid(); - - void DeathMsg( int killer, int victim ); - - void Initialize( void ); - - void Open( void ); - - void MouseOverCell(int row, int col); - -// InputSignal overrides. -public: - - virtual void mousePressed(MouseCode code, Panel* panel); - virtual void cursorMoved(int x, int y, Panel *panel); - - vgui::BitmapTGA *GetIconPointer(string inIconName) - { - vgui::BitmapTGA *pIcon = NULL; - - for (int i = 0; i < m_CustomIconList.size(); i++) - { - if(inIconName == m_CustomIconList[i].second) - { - if(m_CustomIconList[i].first) - { - pIcon = m_CustomIconList[i].first; - break; - } - } - } - return pIcon; - } - - void DeleteCustomIcons( void ) - { - for (int i = 0; i < m_CustomIconList.size(); i++) - { - if(m_CustomIconList[i].first) - delete m_CustomIconList[i].first; - - m_CustomIconList[i].first = NULL; - m_CustomIconList[i].second = ""; - } - - m_CustomIconList.clear(); - }; - - friend CLabelHeader; -}; - -#endif + +#ifndef SCOREPANEL_H +#define SCOREPANEL_H + +#include +#include +#include +#include +#include +#include +#include "vgui_listbox.h" + +#include + +#define MAX_SCORES 10 +#define MAX_SCOREBOARD_TEAMS 5 + +// Scoreboard cells +#define COLUMN_TRACKER 0 +#define COLUMN_RANK_ICON 1 +#define COLUMN_NAME 2 +#define COLUMN_CLASS 3 +#define COLUMN_EXTRA 4 +#define COLUMN_WELD 5 +#define COLUMN_MINE 6 +#define COLUMN_SCORE 7 +#define COLUMN_KILLS 8 +#define COLUMN_DEATHS 9 +#define COLUMN_LATENCY 10 +#define COLUMN_VOICE 11 +#define COLUMN_BLANK 12 +#define NUM_COLUMNS 13 +#define NUM_ROWS (MAX_PLAYERS + (MAX_SCOREBOARD_TEAMS * 2)) + +using namespace vgui; + +#include "CLabelHeader.h" + +class ScoreTablePanel; + +#include "vgui_grid.h" +#include "vgui_defaultinputsignal.h" + +//----------------------------------------------------------------------------- +// Purpose: Scoreboard back panel +//----------------------------------------------------------------------------- +class ScorePanel : public Panel, public vgui::CDefaultInputSignal +{ +private: + // Default panel implementation doesn't forward mouse messages when there is no cursor and we need them. + class HitTestPanel : public Panel + { + public: + virtual void internalMousePressed(MouseCode code); + }; + + +private: + + Label m_TitleLabel; + + // Here is how these controls are arranged hierarchically. + // m_HeaderGrid + // m_HeaderLabels + + // m_PlayerGridScroll + // m_PlayerGrid + // m_PlayerEntries + + CGrid m_HeaderGrid; + CLabelHeader m_HeaderLabels[NUM_COLUMNS]; // Labels above the + CLabelHeader *m_pCurrentHighlightLabel; + int m_iHighlightRow; + + vgui::CListBox m_PlayerList; + CGrid m_PlayerGrids[NUM_ROWS]; // The grid with player and team info. + CLabelHeader m_PlayerEntries[NUM_COLUMNS][NUM_ROWS]; // Labels for the grid entries. + + ScorePanel::HitTestPanel m_HitTestPanel; + CommandButton *m_pCloseButton; + CLabelHeader* GetPlayerEntry(int x, int y) {return &m_PlayerEntries[x][y];} + + vgui::BitmapTGA *m_pTrackerIcon; + + vgui::BitmapTGA *m_pDevIcon; + vgui::BitmapTGA *m_pPTIcon; + vgui::BitmapTGA *m_pGuideIcon; + vgui::BitmapTGA *m_pServerOpIcon; + vgui::BitmapTGA *m_pContribIcon; + vgui::BitmapTGA *m_pCheatingDeathIcon; + vgui::BitmapTGA *m_pVeteranIcon; + + vgui::BitmapTGA *m_pHMG; + vgui::BitmapTGA *m_pMine; + vgui::BitmapTGA *m_pWeld; + vgui::BitmapTGA *m_pGL; + vgui::BitmapTGA *m_pSG; + + vector< pair > m_CustomIconList; + + unsigned int m_iIconFrame; + unsigned int m_iLastFrameIncrementTime; + +public: + + int m_iNumTeams; + int m_iPlayerNum; + int m_iShowscoresHeld; + + int m_iRows; + int m_iSortedRows[NUM_ROWS]; + int m_iIsATeam[NUM_ROWS]; + bool m_bHasBeenSorted[MAX_PLAYERS]; + int m_iLastKilledBy; + int m_fLastKillTime; +public: + + ScorePanel(int x,int y,int wide,int tall); + + void Update( void ); + + int GetIconFrame(void); + + void SortTeams( void ); + void SortActivePlayers(char* inTeam, bool inSortByEntityIndex = false); + void SortPlayers( int iTeam, char *team, bool inSortByEntityIndex = false); + void RebuildTeams( void ); + bool SetSquelchMode(bool inMode); + + void FillGrid(); + + void DeathMsg( int killer, int victim ); + + void Initialize( void ); + + void Open( void ); + + void MouseOverCell(int row, int col); + +// InputSignal overrides. +public: + + virtual void mousePressed(MouseCode code, Panel* panel); + virtual void cursorMoved(int x, int y, Panel *panel); + + vgui::BitmapTGA *GetIconPointer(string inIconName) + { + vgui::BitmapTGA *pIcon = NULL; + + for (int i = 0; i < m_CustomIconList.size(); i++) + { + if(inIconName == m_CustomIconList[i].second) + { + if(m_CustomIconList[i].first) + { + pIcon = m_CustomIconList[i].first; + break; + } + } + } + return pIcon; + } + + void DeleteCustomIcons( void ) + { + for (int i = 0; i < m_CustomIconList.size(); i++) + { + if(m_CustomIconList[i].first) + delete m_CustomIconList[i].first; + + m_CustomIconList[i].first = NULL; + m_CustomIconList[i].second = ""; + } + + m_CustomIconList.clear(); + }; + + friend CLabelHeader; +}; + +#endif diff --git a/main/source/cl_dll/vgui_ServerBrowser.cpp b/main/source/cl_dll/vgui_ServerBrowser.cpp index b1086ed6..5c6fa2d7 100644 --- a/main/source/cl_dll/vgui_ServerBrowser.cpp +++ b/main/source/cl_dll/vgui_ServerBrowser.cpp @@ -1,617 +1,617 @@ - -#include -#include -#include -#include -#include -#include - -#include "hud.h" -#include "cl_util.h" -#include "hud_servers.h" -#include "common/net_api.h" - -#include "vgui_TeamFortressViewport.h" -#include "vgui_ServerBrowser.h" - -using namespace vgui; - -namespace -{ - -#define MAX_SB_ROWS 24 - -#define NUM_COLUMNS 5 - -#define HEADER_SIZE_Y YRES(18) - -// Column sizes -#define CSIZE_ADDRESS XRES(200) -#define CSIZE_SERVER XRES(400) -#define CSIZE_MAP XRES(500) -#define CSIZE_CURRENT XRES(570) -#define CSIZE_PING XRES(640) - -#define CELL_HEIGHT YRES(15) - -class ServerBrowserTablePanel; - -class CBrowser_InputSignal : public InputSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; -public: - CBrowser_InputSignal( ServerBrowserTablePanel *pBrowser ) - { - m_pBrowser = pBrowser; - } - - virtual void cursorMoved(int x,int y,Panel* panel) {}; - virtual void cursorEntered(Panel* panel){}; - virtual void cursorExited(Panel* Panel) {}; - - virtual void mousePressed(MouseCode code,Panel* panel); - - virtual void mouseDoublePressed(MouseCode code,Panel* panel); - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; -}; - -class ServerBrowserTablePanel : public TablePanel -{ -private: - Label *m_pLabel; - int m_nMouseOverRow; - -public: - - ServerBrowserTablePanel( int x,int y,int wide,int tall,int columnCount) : TablePanel( x,y,wide,tall,columnCount) - { - m_pLabel = new Label( "", 0, 0 /*,wide, tall*/ ); - - m_nMouseOverRow = 0; - } - -public: - void setMouseOverRow( int row ) - { - m_nMouseOverRow = row; - } - - void DoSort( char *sortkey ) - { - // Request server list and refresh servers... - SortServers( sortkey ); - } - - void DoRefresh( void ) - { - // Request server list and refresh servers... - ServersList(); - BroadcastServersList( 0 ); - } - - void DoBroadcastRefresh( void ) - { - // Request server list and refresh servers... - BroadcastServersList( 1 ); - } - - void DoStop( void ) - { - // Stop requesting - ServersCancel(); - } - - void DoCancel( void ) - { - ClientCmd( "togglebrowser\n" ); - } - - void DoConnect( void ) - { - const char *info; - const char *address; - char sz[ 256 ]; - - info = ServersGetInfo( m_nMouseOverRow ); - if ( !info ) - return; - - address = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); - //gEngfuncs.Con_Printf( "Connecting to %s\n", address ); - - sprintf( sz, "connect %s\n", address ); - - ClientCmd( sz ); - - DoCancel(); - } - - void DoPing( void ) - { - ServerPing( 0 ); - ServerRules( 0 ); - ServerPlayers( 0 ); - } - - virtual int getRowCount() - { - int rowcount; - int height, width; - - getSize( width, height ); - - // Space for buttons - height -= YRES(20); - height = max( 0, height ); - - rowcount = height / CELL_HEIGHT; - - return rowcount; - } - - virtual int getCellTall(int row) - { - return CELL_HEIGHT - 2; - } - - virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) - { - const char *info; - const char *val, *val2; - char sz[ 32 ]; - - info = ServersGetInfo( row ); - - if ( row == m_nMouseOverRow ) - { - m_pLabel->setFgColor( 200, 240, 63, 100 ); - } - else - { - m_pLabel->setFgColor( 255, 255, 255, 0 ); - } - m_pLabel->setBgColor( 0, 0, 0, 200 ); - m_pLabel->setContentAlignment( vgui::Label::a_west ); - m_pLabel->setFont( Scheme::sf_primary2 ); - - if ( info ) - { - // Fill out with the correct data - switch ( column ) - { - case 0: - val = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); - if ( val ) - { - strncpy( sz, val, 31 ); - sz[ 31 ] = '\0'; - // Server Name; - m_pLabel->setText( sz ); - } - break; - case 1: - val = gEngfuncs.pNetAPI->ValueForKey( info, "hostname" ); - if ( val ) - { - strncpy( sz, val, 31 ); - sz[ 31 ] = '\0'; - // Server Map; - m_pLabel->setText( sz ); - } - break; - case 2: - val = gEngfuncs.pNetAPI->ValueForKey( info, "map" ); - if ( val ) - { - strncpy( sz, val, 31 ); - sz[ 31 ] = '\0'; - // Server Name; - m_pLabel->setText( sz ); - } - break; - case 3: - val = gEngfuncs.pNetAPI->ValueForKey( info, "current" ); - val2 = gEngfuncs.pNetAPI->ValueForKey( info, "max" ); - if ( val && val2 ) - { - sprintf( sz, "%s/%s", val, val2 ); - sz[ 31 ] = '\0'; - // Server Map; - m_pLabel->setText( sz ); - } - break; - case 4: - val = gEngfuncs.pNetAPI->ValueForKey( info, "ping" ); - if ( val ) - { - strncpy( sz, val, 31 ); - sz[ 31 ] = '\0'; - // Server Name; - m_pLabel->setText( sz ); - } - break; - default: - break; - } - } - else - { - if ( !row && !column ) - { - if ( ServersIsQuerying() ) - { - m_pLabel->setText( "Waiting for servers to respond..." ); - } - else - { - m_pLabel->setText( "Press 'Refresh' to search for servers..." ); - } - } - else - { - m_pLabel->setText( "" ); - } - } - - return m_pLabel; - } - - virtual Panel* startCellEditing(int column,int row) - { - return null; - } - -}; - -class ConnectHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - ConnectHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoConnect(); - } -}; - -class RefreshHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - RefreshHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoRefresh(); - } -}; - -class BroadcastRefreshHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - BroadcastRefreshHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoBroadcastRefresh(); - } -}; - -class StopHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - StopHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoStop(); - } -}; - -class CancelHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - CancelHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoCancel(); - } -}; - -class PingHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - PingHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoPing(); - } -}; - -class SortHandler : public ActionSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - -public: - SortHandler( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - } - - virtual void actionPerformed( Panel *panel ) - { - m_pBrowser->DoSort( "map" ); - } -}; - -} - -class LabelSortInputHandler : public InputSignal -{ -private: - ServerBrowserTablePanel *m_pBrowser; - char m_szSortKey[ 64 ]; - -public: - LabelSortInputHandler( ServerBrowserTablePanel *pBrowser, char *name ) - { - m_pBrowser = pBrowser; - strcpy( m_szSortKey, name ); - } - - virtual void cursorMoved(int x,int y,Panel* panel) {}; - virtual void cursorEntered(Panel* panel){}; - virtual void cursorExited(Panel* Panel) {}; - - virtual void mousePressed(MouseCode code,Panel* panel) - { - m_pBrowser->DoSort( m_szSortKey ); - } - - virtual void mouseDoublePressed(MouseCode code,Panel* panel) - { - m_pBrowser->DoSort( m_szSortKey ); - } - - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; -}; - -class CSBLabel : public Label -{ - -private: - char m_szSortKey[ 64 ]; - ServerBrowserTablePanel *m_pBrowser; - -public: - CSBLabel( char *name, char *sortkey ) : Label( name ) - { - m_pBrowser = NULL; - - strcpy( m_szSortKey, sortkey ); - - int label_bg_r = 120, - label_bg_g = 75, - label_bg_b = 32, - label_bg_a = 200; - - int label_fg_r = 255, - label_fg_g = 0, - label_fg_b = 0, - label_fg_a = 0; - - setContentAlignment( vgui::Label::a_west ); - setFgColor( label_fg_r, label_fg_g, label_fg_b, label_fg_a ); - setBgColor( label_bg_r, label_bg_g, label_bg_b, label_bg_a ); - setFont( Scheme::sf_primary2 ); - - } - - void setTable( ServerBrowserTablePanel *browser ) - { - m_pBrowser = browser; - - addInputSignal( new LabelSortInputHandler( (ServerBrowserTablePanel * )m_pBrowser, m_szSortKey ) ); - } -}; - -ServerBrowser::ServerBrowser(int x,int y,int wide,int tall) : CTransparentPanel( 100, x,y,wide,tall ) -{ - int i; - - _headerPanel = new HeaderPanel(0,0,wide,HEADER_SIZE_Y); - _headerPanel->setParent(this); - _headerPanel->setFgColor( 100,100,100, 100 ); - _headerPanel->setBgColor( 0, 0, 0, 100 ); - - CSBLabel *pLabel[5]; - - pLabel[0] = new CSBLabel( "Address", "address" ); - pLabel[1] = new CSBLabel( "Server", "hostname" ); - pLabel[2] = new CSBLabel( "Map", "map" ); - pLabel[3] = new CSBLabel( "Current", "current" ); - pLabel[4] = new CSBLabel( "Latency", "ping" ); - - for ( i = 0; i < 5; i++ ) - { - _headerPanel->addSectionPanel( pLabel[i] ); - } - - // _headerPanel->setFont( Scheme::sf_primary1 ); - - _headerPanel->setSliderPos( 0, CSIZE_ADDRESS ); - _headerPanel->setSliderPos( 1, CSIZE_SERVER ); - _headerPanel->setSliderPos( 2, CSIZE_MAP ); - _headerPanel->setSliderPos( 3, CSIZE_CURRENT ); - _headerPanel->setSliderPos( 4, CSIZE_PING ); - - _tablePanel = new ServerBrowserTablePanel( 0, HEADER_SIZE_Y, wide, tall - HEADER_SIZE_Y, NUM_COLUMNS ); - _tablePanel->setParent(this); - _tablePanel->setHeaderPanel(_headerPanel); - _tablePanel->setFgColor( 100,100,100, 100 ); - _tablePanel->setBgColor( 0, 0, 0, 100 ); - - _tablePanel->addInputSignal( new CBrowser_InputSignal( (ServerBrowserTablePanel *)_tablePanel ) ); - - for ( i = 0; i < 5; i++ ) - { - pLabel[i]->setTable( (ServerBrowserTablePanel * )_tablePanel ); - } - - int bw = 80, bh = 15; - int by = tall - HEADER_SIZE_Y; - - int btnx = 10; - - _connectButton = new CommandButton( "Connect", btnx, by, bw, bh ); - _connectButton->setParent( this ); - _connectButton->addActionSignal( new ConnectHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - - btnx += bw; - - _refreshButton = new CommandButton( "Refresh", btnx, by, bw, bh ); - _refreshButton->setParent( this ); - _refreshButton->addActionSignal( new RefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - - /* - btnx += bw; - - _broadcastRefreshButton = new CommandButton( "LAN", btnx, by, bw, bh ); - _broadcastRefreshButton->setParent( this ); - _broadcastRefreshButton->addActionSignal( new BroadcastRefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - */ - - btnx += bw; - - _stopButton = new CommandButton( "Stop", btnx, by, bw, bh ); - _stopButton->setParent( this ); - _stopButton->addActionSignal( new StopHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - - /* - btnx += bw; - - _pingButton = new CommandButton( "Test", btnx, by, bw, bh ); - _pingButton->setParent( this ); - _pingButton->addActionSignal( new PingHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - - btnx += bw; - - _sortButton = new CommandButton( "Sort", btnx, by, bw, bh ); - _sortButton->setParent( this ); - _sortButton->addActionSignal( new SortHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - */ - - btnx += bw; - - _cancelButton = new CommandButton( "Close", btnx, by, bw, bh ); - _cancelButton->setParent( this ); - _cancelButton->addActionSignal( new CancelHandler( (ServerBrowserTablePanel * )_tablePanel ) ); - - setPaintBorderEnabled(false); - setPaintBackgroundEnabled(false); - setPaintEnabled(false); - -} - -void ServerBrowser::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - - _headerPanel->setBounds(0,0,wide,HEADER_SIZE_Y); - _tablePanel->setBounds(0,HEADER_SIZE_Y,wide,tall - HEADER_SIZE_Y); - - _connectButton->setBounds( 5, tall - HEADER_SIZE_Y, 75, 15 ); - _refreshButton->setBounds( 85, tall - HEADER_SIZE_Y, 75, 15 ); - /* - _broadcastRefreshButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); - */ - _stopButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); - /* - _pingButton->setBounds( 325, tall - HEADER_SIZE_Y, 75, 15 ); - */ - _cancelButton->setBounds( 245, tall - HEADER_SIZE_Y, 75, 15 ); -} - -void CBrowser_InputSignal::mousePressed(MouseCode code,Panel* panel) -{ - int x, y; - int therow = 2; - - if ( code != MOUSE_LEFT ) - return; - - panel->getApp()->getCursorPos(x,y); - panel->screenToLocal( x, y ); - - therow = y / CELL_HEIGHT; - - // Figure out which row it's on - m_pBrowser->setMouseOverRow( therow ); -} - -void CBrowser_InputSignal::mouseDoublePressed(MouseCode code,Panel* panel) -{ - int x, y; - int therow = 2; - - if ( code != MOUSE_LEFT ) - return; - - panel->getApp()->getCursorPos(x,y); - panel->screenToLocal( x, y ); - - therow = y / CELL_HEIGHT; - - // Figure out which row it's on - m_pBrowser->setMouseOverRow( therow ); - m_pBrowser->DoConnect(); -} + +#include +#include +#include +#include +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include "hud_servers.h" +#include "common/net_api.h" + +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +using namespace vgui; + +namespace +{ + +#define MAX_SB_ROWS 24 + +#define NUM_COLUMNS 5 + +#define HEADER_SIZE_Y YRES(18) + +// Column sizes +#define CSIZE_ADDRESS XRES(200) +#define CSIZE_SERVER XRES(400) +#define CSIZE_MAP XRES(500) +#define CSIZE_CURRENT XRES(570) +#define CSIZE_PING XRES(640) + +#define CELL_HEIGHT YRES(15) + +class ServerBrowserTablePanel; + +class CBrowser_InputSignal : public InputSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; +public: + CBrowser_InputSignal( ServerBrowserTablePanel *pBrowser ) + { + m_pBrowser = pBrowser; + } + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + + virtual void mousePressed(MouseCode code,Panel* panel); + + virtual void mouseDoublePressed(MouseCode code,Panel* panel); + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class ServerBrowserTablePanel : public TablePanel +{ +private: + Label *m_pLabel; + int m_nMouseOverRow; + +public: + + ServerBrowserTablePanel( int x,int y,int wide,int tall,int columnCount) : TablePanel( x,y,wide,tall,columnCount) + { + m_pLabel = new Label( "", 0, 0 /*,wide, tall*/ ); + + m_nMouseOverRow = 0; + } + +public: + void setMouseOverRow( int row ) + { + m_nMouseOverRow = row; + } + + void DoSort( char *sortkey ) + { + // Request server list and refresh servers... + SortServers( sortkey ); + } + + void DoRefresh( void ) + { + // Request server list and refresh servers... + ServersList(); + BroadcastServersList( 0 ); + } + + void DoBroadcastRefresh( void ) + { + // Request server list and refresh servers... + BroadcastServersList( 1 ); + } + + void DoStop( void ) + { + // Stop requesting + ServersCancel(); + } + + void DoCancel( void ) + { + ClientCmd( "togglebrowser\n" ); + } + + void DoConnect( void ) + { + const char *info; + const char *address; + char sz[ 256 ]; + + info = ServersGetInfo( m_nMouseOverRow ); + if ( !info ) + return; + + address = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); + //gEngfuncs.Con_Printf( "Connecting to %s\n", address ); + + sprintf( sz, "connect %s\n", address ); + + ClientCmd( sz ); + + DoCancel(); + } + + void DoPing( void ) + { + ServerPing( 0 ); + ServerRules( 0 ); + ServerPlayers( 0 ); + } + + virtual int getRowCount() + { + int rowcount; + int height, width; + + getSize( width, height ); + + // Space for buttons + height -= YRES(20); + height = max( 0, height ); + + rowcount = height / CELL_HEIGHT; + + return rowcount; + } + + virtual int getCellTall(int row) + { + return CELL_HEIGHT - 2; + } + + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + const char *info; + const char *val, *val2; + char sz[ 32 ]; + + info = ServersGetInfo( row ); + + if ( row == m_nMouseOverRow ) + { + m_pLabel->setFgColor( 200, 240, 63, 100 ); + } + else + { + m_pLabel->setFgColor( 255, 255, 255, 0 ); + } + m_pLabel->setBgColor( 0, 0, 0, 200 ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setFont( Scheme::sf_primary2 ); + + if ( info ) + { + // Fill out with the correct data + switch ( column ) + { + case 0: + val = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + case 1: + val = gEngfuncs.pNetAPI->ValueForKey( info, "hostname" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Map; + m_pLabel->setText( sz ); + } + break; + case 2: + val = gEngfuncs.pNetAPI->ValueForKey( info, "map" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + case 3: + val = gEngfuncs.pNetAPI->ValueForKey( info, "current" ); + val2 = gEngfuncs.pNetAPI->ValueForKey( info, "max" ); + if ( val && val2 ) + { + sprintf( sz, "%s/%s", val, val2 ); + sz[ 31 ] = '\0'; + // Server Map; + m_pLabel->setText( sz ); + } + break; + case 4: + val = gEngfuncs.pNetAPI->ValueForKey( info, "ping" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + default: + break; + } + } + else + { + if ( !row && !column ) + { + if ( ServersIsQuerying() ) + { + m_pLabel->setText( "Waiting for servers to respond..." ); + } + else + { + m_pLabel->setText( "Press 'Refresh' to search for servers..." ); + } + } + else + { + m_pLabel->setText( "" ); + } + } + + return m_pLabel; + } + + virtual Panel* startCellEditing(int column,int row) + { + return null; + } + +}; + +class ConnectHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + ConnectHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoConnect(); + } +}; + +class RefreshHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + RefreshHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoRefresh(); + } +}; + +class BroadcastRefreshHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + BroadcastRefreshHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoBroadcastRefresh(); + } +}; + +class StopHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + StopHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoStop(); + } +}; + +class CancelHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + CancelHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoCancel(); + } +}; + +class PingHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + PingHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoPing(); + } +}; + +class SortHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + SortHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoSort( "map" ); + } +}; + +} + +class LabelSortInputHandler : public InputSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + char m_szSortKey[ 64 ]; + +public: + LabelSortInputHandler( ServerBrowserTablePanel *pBrowser, char *name ) + { + m_pBrowser = pBrowser; + strcpy( m_szSortKey, name ); + } + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + + virtual void mousePressed(MouseCode code,Panel* panel) + { + m_pBrowser->DoSort( m_szSortKey ); + } + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) + { + m_pBrowser->DoSort( m_szSortKey ); + } + + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class CSBLabel : public Label +{ + +private: + char m_szSortKey[ 64 ]; + ServerBrowserTablePanel *m_pBrowser; + +public: + CSBLabel( char *name, char *sortkey ) : Label( name ) + { + m_pBrowser = NULL; + + strcpy( m_szSortKey, sortkey ); + + int label_bg_r = 120, + label_bg_g = 75, + label_bg_b = 32, + label_bg_a = 200; + + int label_fg_r = 255, + label_fg_g = 0, + label_fg_b = 0, + label_fg_a = 0; + + setContentAlignment( vgui::Label::a_west ); + setFgColor( label_fg_r, label_fg_g, label_fg_b, label_fg_a ); + setBgColor( label_bg_r, label_bg_g, label_bg_b, label_bg_a ); + setFont( Scheme::sf_primary2 ); + + } + + void setTable( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + + addInputSignal( new LabelSortInputHandler( (ServerBrowserTablePanel * )m_pBrowser, m_szSortKey ) ); + } +}; + +ServerBrowser::ServerBrowser(int x,int y,int wide,int tall) : CTransparentPanel( 100, x,y,wide,tall ) +{ + int i; + + _headerPanel = new HeaderPanel(0,0,wide,HEADER_SIZE_Y); + _headerPanel->setParent(this); + _headerPanel->setFgColor( 100,100,100, 100 ); + _headerPanel->setBgColor( 0, 0, 0, 100 ); + + CSBLabel *pLabel[5]; + + pLabel[0] = new CSBLabel( "Address", "address" ); + pLabel[1] = new CSBLabel( "Server", "hostname" ); + pLabel[2] = new CSBLabel( "Map", "map" ); + pLabel[3] = new CSBLabel( "Current", "current" ); + pLabel[4] = new CSBLabel( "Latency", "ping" ); + + for ( i = 0; i < 5; i++ ) + { + _headerPanel->addSectionPanel( pLabel[i] ); + } + + // _headerPanel->setFont( Scheme::sf_primary1 ); + + _headerPanel->setSliderPos( 0, CSIZE_ADDRESS ); + _headerPanel->setSliderPos( 1, CSIZE_SERVER ); + _headerPanel->setSliderPos( 2, CSIZE_MAP ); + _headerPanel->setSliderPos( 3, CSIZE_CURRENT ); + _headerPanel->setSliderPos( 4, CSIZE_PING ); + + _tablePanel = new ServerBrowserTablePanel( 0, HEADER_SIZE_Y, wide, tall - HEADER_SIZE_Y, NUM_COLUMNS ); + _tablePanel->setParent(this); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setFgColor( 100,100,100, 100 ); + _tablePanel->setBgColor( 0, 0, 0, 100 ); + + _tablePanel->addInputSignal( new CBrowser_InputSignal( (ServerBrowserTablePanel *)_tablePanel ) ); + + for ( i = 0; i < 5; i++ ) + { + pLabel[i]->setTable( (ServerBrowserTablePanel * )_tablePanel ); + } + + int bw = 80, bh = 15; + int by = tall - HEADER_SIZE_Y; + + int btnx = 10; + + _connectButton = new CommandButton( "Connect", btnx, by, bw, bh ); + _connectButton->setParent( this ); + _connectButton->addActionSignal( new ConnectHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + btnx += bw; + + _refreshButton = new CommandButton( "Refresh", btnx, by, bw, bh ); + _refreshButton->setParent( this ); + _refreshButton->addActionSignal( new RefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + /* + btnx += bw; + + _broadcastRefreshButton = new CommandButton( "LAN", btnx, by, bw, bh ); + _broadcastRefreshButton->setParent( this ); + _broadcastRefreshButton->addActionSignal( new BroadcastRefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + */ + + btnx += bw; + + _stopButton = new CommandButton( "Stop", btnx, by, bw, bh ); + _stopButton->setParent( this ); + _stopButton->addActionSignal( new StopHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + /* + btnx += bw; + + _pingButton = new CommandButton( "Test", btnx, by, bw, bh ); + _pingButton->setParent( this ); + _pingButton->addActionSignal( new PingHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + btnx += bw; + + _sortButton = new CommandButton( "Sort", btnx, by, bw, bh ); + _sortButton->setParent( this ); + _sortButton->addActionSignal( new SortHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + */ + + btnx += bw; + + _cancelButton = new CommandButton( "Close", btnx, by, bw, bh ); + _cancelButton->setParent( this ); + _cancelButton->addActionSignal( new CancelHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + setPaintBorderEnabled(false); + setPaintBackgroundEnabled(false); + setPaintEnabled(false); + +} + +void ServerBrowser::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + _headerPanel->setBounds(0,0,wide,HEADER_SIZE_Y); + _tablePanel->setBounds(0,HEADER_SIZE_Y,wide,tall - HEADER_SIZE_Y); + + _connectButton->setBounds( 5, tall - HEADER_SIZE_Y, 75, 15 ); + _refreshButton->setBounds( 85, tall - HEADER_SIZE_Y, 75, 15 ); + /* + _broadcastRefreshButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); + */ + _stopButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); + /* + _pingButton->setBounds( 325, tall - HEADER_SIZE_Y, 75, 15 ); + */ + _cancelButton->setBounds( 245, tall - HEADER_SIZE_Y, 75, 15 ); +} + +void CBrowser_InputSignal::mousePressed(MouseCode code,Panel* panel) +{ + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / CELL_HEIGHT; + + // Figure out which row it's on + m_pBrowser->setMouseOverRow( therow ); +} + +void CBrowser_InputSignal::mouseDoublePressed(MouseCode code,Panel* panel) +{ + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / CELL_HEIGHT; + + // Figure out which row it's on + m_pBrowser->setMouseOverRow( therow ); + m_pBrowser->DoConnect(); +} diff --git a/main/source/cl_dll/vgui_ServerBrowser.h b/main/source/cl_dll/vgui_ServerBrowser.h index 7dc819aa..b8267705 100644 --- a/main/source/cl_dll/vgui_ServerBrowser.h +++ b/main/source/cl_dll/vgui_ServerBrowser.h @@ -1,44 +1,44 @@ - -#ifndef ServerBrowser_H -#define ServerBrowser_H - -#include - -namespace vgui -{ -class Button; -class TablePanel; -class HeaderPanel; -} - -class CTransparentPanel; -class CommandButton; - -// Scoreboard positions -#define SB_X_INDENT (20 * ((float)ScreenHeight / 640)) -#define SB_Y_INDENT (20 * ((float)ScreenHeight / 480)) - -class ServerBrowser : public CTransparentPanel -{ -private: - HeaderPanel * _headerPanel; - TablePanel* _tablePanel; - - CommandButton* _connectButton; - CommandButton* _refreshButton; - CommandButton* _broadcastRefreshButton; - CommandButton* _stopButton; - CommandButton* _sortButton; - CommandButton* _cancelButton; - - CommandButton* _pingButton; - -public: - ServerBrowser(int x,int y,int wide,int tall); -public: - virtual void setSize(int wide,int tall); -}; - - - + +#ifndef ServerBrowser_H +#define ServerBrowser_H + +#include + +namespace vgui +{ +class Button; +class TablePanel; +class HeaderPanel; +} + +class CTransparentPanel; +class CommandButton; + +// Scoreboard positions +#define SB_X_INDENT (20 * ((float)ScreenHeight / 640)) +#define SB_Y_INDENT (20 * ((float)ScreenHeight / 480)) + +class ServerBrowser : public CTransparentPanel +{ +private: + HeaderPanel * _headerPanel; + TablePanel* _tablePanel; + + CommandButton* _connectButton; + CommandButton* _refreshButton; + CommandButton* _broadcastRefreshButton; + CommandButton* _stopButton; + CommandButton* _sortButton; + CommandButton* _cancelButton; + + CommandButton* _pingButton; + +public: + ServerBrowser(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); +}; + + + #endif \ No newline at end of file diff --git a/main/source/cl_dll/vgui_SpectatorPanel.cpp b/main/source/cl_dll/vgui_SpectatorPanel.cpp index e4742342..625a8fcd 100644 --- a/main/source/cl_dll/vgui_SpectatorPanel.cpp +++ b/main/source/cl_dll/vgui_SpectatorPanel.cpp @@ -1,443 +1,443 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// vgui_SpectatorPanel.cpp: implementation of the SpectatorPanel class. -// -////////////////////////////////////////////////////////////////////// - -#include "hud.h" -#include "cl_util.h" -#include "common/const.h" -#include "common/entity_state.h" -#include "common/cl_entity.h" -#include "pm_shared/pm_shared.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_SpectatorPanel.h" -#include "vgui_ScorePanel.h" -#include "mod/AvHOverviewControl.h" - - -#define BANNER_WIDTH 256 -#define BANNER_HEIGHT 64 - - -#define OPTIONS_BUTTON_X 96 -#define CAMOPTIONS_BUTTON_X 200 - - -class Spectator_CheckButtonHandler : public ICheckButton2Handler -{ - -public: - - Spectator_CheckButtonHandler(SpectatorPanel * panel) - { - m_pFather = panel; - } - - virtual void StateChanged(CCheckButton2* pButton) - { - m_pFather->StateChanged(pButton); - } - -private: - - SpectatorPanel * m_pFather; - -}; - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -SpectatorPanel::SpectatorPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) -{ - m_overviewButton = NULL; - m_autoDirectorButton = NULL; - m_firstPersonButton = NULL; - m_overviewControl = NULL; -} - -SpectatorPanel::~SpectatorPanel() -{ - -} - -void SpectatorPanel::StateChanged(CCheckButton2* pButton) -{ - bool theOverviewMode = false; - if(m_overviewButton) - { - theOverviewMode = m_overviewButton->IsChecked(); - } - gHUD.m_Spectator.SetOverviewMode(theOverviewMode); - - int theMode = OBS_NONE; - - if (m_firstPersonButton->IsChecked()) - { - theMode = OBS_IN_EYE; - } - else - { - theMode = OBS_CHASE_LOCKED; - } - - gHUD.m_Spectator.SetMode(theMode); - - if (m_autoDirectorButton != NULL && pButton == m_autoDirectorButton ) - { - if (m_autoDirectorButton->IsChecked()) - { - gEngfuncs.Cvar_SetValue("spec_autodirector", 0); - } - else - { - gEngfuncs.Cvar_SetValue("spec_autodirector", 1); - } - } - - Update(); // Update so that the components reflect the new state. - -} - -void SpectatorPanel::ActionSignal(int cmd) -{ - - switch (cmd) - { - /* - case SPECTATOR_PANEL_CMD_NONE : break; - */ - - case SPECTATOR_PANEL_CMD_PLAYERS : - gViewPort->UpdatePlayerMenu(); - gViewPort->ShowCommandMenu(gViewPort->m_SpectatorPlayerMenu); - break; - - case SPECTATOR_PANEL_CMD_NEXTPLAYER : gHUD.m_Spectator.FindNextPlayer(true); - break; - - case SPECTATOR_PANEL_CMD_PREVPLAYER : gHUD.m_Spectator.FindNextPlayer(false); - break; - - /* - case SPECTATOR_PANEL_CMD_HIDEMENU : ShowMenu(false); - break; - - case SPECTATOR_PANEL_CMD_CAMERA : gViewPort->ShowCommandMenu( gViewPort->m_SpectatorCameraMenu ); - break; - - */ - default : gEngfuncs.Con_DPrintf("Unknown SpectatorPanel ActionSingal %i.\n",cmd); break; - } - -} - - -void SpectatorPanel::Initialize() -{ - int x,y,wide,tall; - - getBounds(x,y,wide,tall); - - CSchemeManager * pSchemes = gViewPort->GetSchemeManager(); - - - int colorR = 128 / gHUD.GetGammaSlope(); - int colorG = 128 / gHUD.GetGammaSlope(); - int colorB = 128 / gHUD.GetGammaSlope(); - - int armedColorR = 255 / gHUD.GetGammaSlope(); - int armedColorG = 255 / gHUD.GetGammaSlope(); - int armedColorB = 255 / gHUD.GetGammaSlope(); - - - SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle( /*"Team Info Text"*/ "PieMenuScheme" ); - Font* font = pSchemes->getFont(hSmallScheme); - - //m_TopBorder = new CTransparentPanel(64, 0, 0, ScreenWidth, YRES(PANEL_HEIGHT)); - m_TopBorder = new CTransparentPanel(1, 0, ScreenHeight() - YRES(32), ScreenWidth(), YRES(SPECTATOR_PANEL_HEIGHT)); - m_TopBorder->setParent(this); - - m_BottomBorder = new CTransparentPanel(1, 0, ScreenHeight() - YRES(32), ScreenWidth(), YRES(SPECTATOR_PANEL_HEIGHT)); - m_BottomBorder->setParent(this); - - setPaintBackgroundEnabled(false); - - m_ExtraInfo = new Label( "Extra Info", 0, 0, wide, YRES(SPECTATOR_PANEL_HEIGHT) ); - m_ExtraInfo->setParent(m_TopBorder); - m_ExtraInfo->setFont( font ); - - m_ExtraInfo->setPaintBackgroundEnabled(false); - m_ExtraInfo->setFgColor( 143, 143, 54, 0 ); - m_ExtraInfo->setContentAlignment( vgui::Label::a_west ); - - - - m_TimerImage = new CImageLabel( "timer", 0, 0, 14, 14 ); - m_TimerImage->setParent(m_TopBorder); - - m_TopBanner = new CImageLabel( "banner", 0, 0, XRES(BANNER_WIDTH), YRES(BANNER_HEIGHT) ); - m_TopBanner->setParent(this); - - m_CurrentTime = new Label( "00:00", 0, 0, wide, YRES(SPECTATOR_PANEL_HEIGHT) ); - m_CurrentTime->setParent(m_TopBorder); - m_CurrentTime->setFont( pSchemes->getFont(hSmallScheme) ); - m_CurrentTime->setPaintBackgroundEnabled(false); - m_CurrentTime->setFgColor( 143, 143, 54, 0 ); - m_CurrentTime->setContentAlignment( vgui::Label::a_west ); - - m_Separator = new Panel( 0, 0, XRES( 64 ), YRES( 96 )); - m_Separator->setParent( m_TopBorder ); - m_Separator->setFgColor( 59, 58, 34, 48 ); - m_Separator->setBgColor( 59, 58, 34, 48 ); - - for ( int j= 0; j < TEAM_NUMBER; j++ ) - { - m_TeamScores[j] = new Label( " ", 0, 0, wide, YRES(SPECTATOR_PANEL_HEIGHT) ); - m_TeamScores[j]->setParent( m_TopBorder ); - m_TeamScores[j]->setFont( pSchemes->getFont(hSmallScheme) ); - m_TeamScores[j]->setPaintBackgroundEnabled(false); - m_TeamScores[j]->setFgColor( 143, 143, 54, 0 ); - m_TeamScores[j]->setContentAlignment( vgui::Label::a_west ); - m_TeamScores[j]->setVisible ( false ); - } - - - m_PrevPlayerButton= new ColorButton("<", XRES(390 - 20 - 4), YRES(6), XRES(20), YRES(20), false, false ); - m_PrevPlayerButton->setParent( m_BottomBorder ); - m_PrevPlayerButton->setContentAlignment( vgui::Label::a_center ); - m_PrevPlayerButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name - m_PrevPlayerButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_PREVPLAYER) ); - m_PrevPlayerButton->setUnArmedBorderColor ( colorR, colorG, colorB, 0 ); - m_PrevPlayerButton->setArmedBorderColor ( armedColorR, armedColorR, armedColorR, 0); - m_PrevPlayerButton->setUnArmedColor ( colorR, colorG, colorB, 0 ); - m_PrevPlayerButton->setArmedColor ( armedColorR, armedColorR, armedColorR, 0); - - m_NextPlayerButton= new ColorButton(">", XRES(390 + 200 + 4), YRES(6), XRES(20), YRES(20), false, false ); - m_NextPlayerButton->setParent( m_BottomBorder ); - m_NextPlayerButton->setContentAlignment( vgui::Label::a_center ); - m_NextPlayerButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name - m_NextPlayerButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_NEXTPLAYER) ); - m_NextPlayerButton->setUnArmedBorderColor ( colorR, colorG, colorB, 0 ); - m_NextPlayerButton->setArmedBorderColor ( armedColorR, armedColorR, armedColorR, 0); - m_NextPlayerButton->setUnArmedColor ( colorR, colorG, colorB, 0); - m_NextPlayerButton->setArmedColor ( armedColorR, armedColorR, armedColorR, 0); - - // Initialize the bottom title. - - m_BottomMainLabel = new ColorButton( "Spectator Bottom", XRES(390), YRES(6), XRES(200), YRES(20), false, false ); - m_BottomMainLabel->setFont(font); - m_BottomMainLabel->setParent(m_BottomBorder); - m_BottomMainLabel->setContentAlignment( vgui::Label::a_center ); - m_BottomMainLabel->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_PLAYERS) ); - - m_BottomMainLabel->setUnArmedBorderColor ( colorR, colorG, colorB, 0); - m_BottomMainLabel->setArmedBorderColor ( armedColorR, armedColorR, armedColorR, 0); - m_BottomMainLabel->setUnArmedColor ( colorR, colorG, colorB, 0); - m_BottomMainLabel->setArmedColor ( armedColorR, armedColorR, armedColorR, 0); - - - - m_menuVisible = true; - - m_insetVisible = false; - - m_ExtraInfo->setVisible( false ); - m_Separator->setVisible( false ); - m_TimerImage->setVisible( false ); - - m_TopBorder->setVisible(true); - m_BottomBorder->setVisible( true ); - - m_overviewButton = new CCheckButton2(); - m_overviewButton->setFont(font); - m_overviewButton->setParent( m_BottomBorder ); - m_overviewButton->SetText("Overview"); - m_overviewButton->setPos(XRES(10), YRES(6)); - m_overviewButton->setSize(XRES(100), YRES(20)); - m_overviewButton->SetImages("gfx/vgui/640_checkset.tga", "gfx/vgui/640_checkunset.tga"); - m_overviewButton->SetHandler(new Spectator_CheckButtonHandler(this)); - m_overviewButton->SetTextColor(colorR, colorG, colorB, 0); - - m_firstPersonButton = new CCheckButton2(); - m_firstPersonButton->setFont(font); - m_firstPersonButton->setParent( m_BottomBorder ); - m_firstPersonButton->SetText("First person"); - m_firstPersonButton->setPos(XRES(10 + 100), YRES(6)); - m_firstPersonButton->setSize(XRES(100), YRES(20)); - m_firstPersonButton->SetImages("gfx/vgui/640_checkset.tga", "gfx/vgui/640_checkunset.tga"); - m_firstPersonButton->SetHandler(new Spectator_CheckButtonHandler(this)); - m_firstPersonButton->SetTextColor(colorR, colorG, colorB, 0); - - m_autoDirectorButton = new CCheckButton2(); - m_autoDirectorButton->setFont(font); - m_autoDirectorButton->setParent( m_BottomBorder ); - m_autoDirectorButton->SetText("Auto-director"); - m_autoDirectorButton->setPos(XRES(10 + 200), YRES(6)); - m_autoDirectorButton->setSize(XRES(100), YRES(20)); - m_autoDirectorButton->SetImages("gfx/vgui/640_checkset.tga", "gfx/vgui/640_checkunset.tga"); - m_autoDirectorButton->SetHandler(new Spectator_CheckButtonHandler(this)); - m_autoDirectorButton->SetTextColor(colorR, colorG, colorB, 0); - - -/* - m_OverviewData.insetWindowX = 4; // upper left corner - m_OverviewData.insetWindowY = 4 + SPECTATOR_PANEL_HEIGHT; - m_OverviewData.insetWindowHeight = 180; - m_OverviewData.insetWindowWidth = 240; - - - theDrawInfo.mX = XRES(m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth + 4); - theDrawInfo.mY = YRES(SPECTATOR_PANEL_HEIGHT + 4); - theDrawInfo.mWidth = ScreenWidth() - theDrawInfo.mX - XRES(4); - theDrawInfo.mHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theDrawInfo.mY; -*/ - - int theX = XRES(4 + 240 + 4); - int theY = YRES(SPECTATOR_PANEL_HEIGHT + 4); - int theWidth = ScreenWidth() - theX - XRES(4); - int theHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theY; - - m_overviewControl = new AvHOverviewControl; - m_overviewControl->setPos(theX, theY); - m_overviewControl->setSize(theWidth, theHeight); - m_overviewControl->setParent(this); - -} - -void SpectatorPanel::ShowMenu(bool isVisible) -{ - - if ( !isVisible ) - { - gViewPort->HideCommandMenu(); - } - - m_menuVisible = isVisible; - - gViewPort->UpdateCursorState(); - -} - - -void SpectatorPanel::EnableInsetView(bool isEnabled) -{ - - - int x = gHUD.m_Spectator.m_OverviewData.insetWindowX; - int y = gHUD.m_Spectator.m_OverviewData.insetWindowY; - int wide = gHUD.m_Spectator.m_OverviewData.insetWindowWidth; - int tall = gHUD.m_Spectator.m_OverviewData.insetWindowHeight; - int offset = x + wide + 2; - - if ( isEnabled ) - { - // short black bar to see full inset - m_TopBorder->setBounds( XRES(offset), 0, XRES(640 - offset ), YRES(SPECTATOR_PANEL_HEIGHT) ); - - if ( gEngfuncs.IsSpectateOnly() ) - { - m_TopBanner->setVisible( true ); - m_TopBanner->setPos( XRES(offset), 0 ); - } - else - m_TopBanner->setVisible( false ); - - } - else - { - // full black bar, no inset border - // show banner only in real HLTV mode - if ( gEngfuncs.IsSpectateOnly() ) - { - m_TopBanner->setVisible( true ); - m_TopBanner->setPos( 0,0 ); - } - else - m_TopBanner->setVisible( false ); - - m_TopBorder->setBounds( 0, 0, ScreenWidth(), YRES(SPECTATOR_PANEL_HEIGHT) ); - - } - - m_insetVisible = isEnabled; - - Update(); - -} - - -void SpectatorPanel::Update() -{ - - // Update the check boxes. - m_overviewButton->SetChecked(gHUD.m_Spectator.IsInOverviewMode()); - m_overviewButton->setVisible(gHUD.GetIsNSMode()); - - m_firstPersonButton->SetChecked(g_iUser1 == OBS_IN_EYE); - - m_autoDirectorButton->SetChecked(CVAR_GET_FLOAT("spec_autodirector") != 0); - m_autoDirectorButton->setVisible(gEngfuncs.IsSpectateOnly()); - - m_overviewControl->setVisible(gHUD.m_Spectator.IsInOverviewMode()); - - int iTextWidth, iTextHeight; - int iTimeHeight, iTimeWidth; - int offset,j; - - // TODO Max: Figure out what this is for. - - if ( m_insetVisible ) - offset = gHUD.m_Spectator.m_OverviewData.insetWindowX + gHUD.m_Spectator.m_OverviewData.insetWindowWidth + 2; - else - offset = 0; - - //bool visible = gHUD.m_Spectator.m_drawstatus->value != 0; - bool visible = true; - - m_ExtraInfo->setVisible( visible ); - m_TimerImage->setVisible( visible ); - m_CurrentTime->setVisible( visible ); - m_Separator->setVisible( visible ); - - for ( j= 0; j < TEAM_NUMBER; j++ ) - m_TeamScores[j]->setVisible( visible ); - - if ( !visible ) - return; - - m_ExtraInfo->getTextSize( iTextWidth, iTextHeight ); - m_CurrentTime->getTextSize( iTimeWidth, iTimeHeight ); - - iTimeWidth += XRES ( 14 ); // +timer icon - iTimeWidth += ( 4-(iTimeWidth%4) ); - - if ( iTimeWidth > iTextWidth ) - iTextWidth = iTimeWidth; - - int xPos = ScreenWidth() - ( iTextWidth + XRES ( 4 + offset ) ); - - m_ExtraInfo->setBounds( xPos, YRES( 1 ), iTextWidth, iTextHeight ); - - m_TimerImage->setBounds( xPos, YRES( 2 ) + iTextHeight , XRES(14), YRES(14) ); - - m_CurrentTime->setBounds( xPos + XRES ( 14 + 1 ), YRES( 2 ) + iTextHeight , iTimeWidth, iTimeHeight ); - - m_Separator->setPos( ScreenWidth() - ( iTextWidth + XRES ( 4+2+4+offset ) ) , YRES( 1 ) ); - m_Separator->setSize( XRES( 4 ), YRES( SPECTATOR_PANEL_HEIGHT - 2 ) ); - - for ( j= 0; j < TEAM_NUMBER; j++ ) - { - int iwidth, iheight; - - m_TeamScores[j]->getTextSize( iwidth, iheight ); - m_TeamScores[j]->setBounds( ScreenWidth() - ( iTextWidth + XRES ( 4+2+4+2+offset ) + iwidth ), YRES( 1 ) + ( iheight * j ), iwidth, iheight ); - } - -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// vgui_SpectatorPanel.cpp: implementation of the SpectatorPanel class. +// +////////////////////////////////////////////////////////////////////// + +#include "hud.h" +#include "cl_util.h" +#include "common/const.h" +#include "common/entity_state.h" +#include "common/cl_entity.h" +#include "pm_shared/pm_shared.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_SpectatorPanel.h" +#include "vgui_ScorePanel.h" +#include "mod/AvHOverviewControl.h" + + +#define BANNER_WIDTH 256 +#define BANNER_HEIGHT 64 + + +#define OPTIONS_BUTTON_X 96 +#define CAMOPTIONS_BUTTON_X 200 + + +class Spectator_CheckButtonHandler : public ICheckButton2Handler +{ + +public: + + Spectator_CheckButtonHandler(SpectatorPanel * panel) + { + m_pFather = panel; + } + + virtual void StateChanged(CCheckButton2* pButton) + { + m_pFather->StateChanged(pButton); + } + +private: + + SpectatorPanel * m_pFather; + +}; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +SpectatorPanel::SpectatorPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + m_overviewButton = NULL; + m_autoDirectorButton = NULL; + m_firstPersonButton = NULL; + m_overviewControl = NULL; +} + +SpectatorPanel::~SpectatorPanel() +{ + +} + +void SpectatorPanel::StateChanged(CCheckButton2* pButton) +{ + bool theOverviewMode = false; + if(m_overviewButton) + { + theOverviewMode = m_overviewButton->IsChecked(); + } + gHUD.m_Spectator.SetOverviewMode(theOverviewMode); + + int theMode = OBS_NONE; + + if (m_firstPersonButton->IsChecked()) + { + theMode = OBS_IN_EYE; + } + else + { + theMode = OBS_CHASE_LOCKED; + } + + gHUD.m_Spectator.SetMode(theMode); + + if (m_autoDirectorButton != NULL && pButton == m_autoDirectorButton ) + { + if (m_autoDirectorButton->IsChecked()) + { + gEngfuncs.Cvar_SetValue("spec_autodirector", 0); + } + else + { + gEngfuncs.Cvar_SetValue("spec_autodirector", 1); + } + } + + Update(); // Update so that the components reflect the new state. + +} + +void SpectatorPanel::ActionSignal(int cmd) +{ + + switch (cmd) + { + /* + case SPECTATOR_PANEL_CMD_NONE : break; + */ + + case SPECTATOR_PANEL_CMD_PLAYERS : + gViewPort->UpdatePlayerMenu(); + gViewPort->ShowCommandMenu(gViewPort->m_SpectatorPlayerMenu); + break; + + case SPECTATOR_PANEL_CMD_NEXTPLAYER : gHUD.m_Spectator.FindNextPlayer(true); + break; + + case SPECTATOR_PANEL_CMD_PREVPLAYER : gHUD.m_Spectator.FindNextPlayer(false); + break; + + /* + case SPECTATOR_PANEL_CMD_HIDEMENU : ShowMenu(false); + break; + + case SPECTATOR_PANEL_CMD_CAMERA : gViewPort->ShowCommandMenu( gViewPort->m_SpectatorCameraMenu ); + break; + + */ + default : gEngfuncs.Con_DPrintf("Unknown SpectatorPanel ActionSingal %i.\n",cmd); break; + } + +} + + +void SpectatorPanel::Initialize() +{ + int x,y,wide,tall; + + getBounds(x,y,wide,tall); + + CSchemeManager * pSchemes = gViewPort->GetSchemeManager(); + + + int colorR = 128 / gHUD.GetGammaSlope(); + int colorG = 128 / gHUD.GetGammaSlope(); + int colorB = 128 / gHUD.GetGammaSlope(); + + int armedColorR = 255 / gHUD.GetGammaSlope(); + int armedColorG = 255 / gHUD.GetGammaSlope(); + int armedColorB = 255 / gHUD.GetGammaSlope(); + + + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle( /*"Team Info Text"*/ "PieMenuScheme" ); + Font* font = pSchemes->getFont(hSmallScheme); + + //m_TopBorder = new CTransparentPanel(64, 0, 0, ScreenWidth, YRES(PANEL_HEIGHT)); + m_TopBorder = new CTransparentPanel(1, 0, ScreenHeight() - YRES(32), ScreenWidth(), YRES(SPECTATOR_PANEL_HEIGHT)); + m_TopBorder->setParent(this); + + m_BottomBorder = new CTransparentPanel(1, 0, ScreenHeight() - YRES(32), ScreenWidth(), YRES(SPECTATOR_PANEL_HEIGHT)); + m_BottomBorder->setParent(this); + + setPaintBackgroundEnabled(false); + + m_ExtraInfo = new Label( "Extra Info", 0, 0, wide, YRES(SPECTATOR_PANEL_HEIGHT) ); + m_ExtraInfo->setParent(m_TopBorder); + m_ExtraInfo->setFont( font ); + + m_ExtraInfo->setPaintBackgroundEnabled(false); + m_ExtraInfo->setFgColor( 143, 143, 54, 0 ); + m_ExtraInfo->setContentAlignment( vgui::Label::a_west ); + + + + m_TimerImage = new CImageLabel( "timer", 0, 0, 14, 14 ); + m_TimerImage->setParent(m_TopBorder); + + m_TopBanner = new CImageLabel( "banner", 0, 0, XRES(BANNER_WIDTH), YRES(BANNER_HEIGHT) ); + m_TopBanner->setParent(this); + + m_CurrentTime = new Label( "00:00", 0, 0, wide, YRES(SPECTATOR_PANEL_HEIGHT) ); + m_CurrentTime->setParent(m_TopBorder); + m_CurrentTime->setFont( pSchemes->getFont(hSmallScheme) ); + m_CurrentTime->setPaintBackgroundEnabled(false); + m_CurrentTime->setFgColor( 143, 143, 54, 0 ); + m_CurrentTime->setContentAlignment( vgui::Label::a_west ); + + m_Separator = new Panel( 0, 0, XRES( 64 ), YRES( 96 )); + m_Separator->setParent( m_TopBorder ); + m_Separator->setFgColor( 59, 58, 34, 48 ); + m_Separator->setBgColor( 59, 58, 34, 48 ); + + for ( int j= 0; j < TEAM_NUMBER; j++ ) + { + m_TeamScores[j] = new Label( " ", 0, 0, wide, YRES(SPECTATOR_PANEL_HEIGHT) ); + m_TeamScores[j]->setParent( m_TopBorder ); + m_TeamScores[j]->setFont( pSchemes->getFont(hSmallScheme) ); + m_TeamScores[j]->setPaintBackgroundEnabled(false); + m_TeamScores[j]->setFgColor( 143, 143, 54, 0 ); + m_TeamScores[j]->setContentAlignment( vgui::Label::a_west ); + m_TeamScores[j]->setVisible ( false ); + } + + + m_PrevPlayerButton= new ColorButton("<", XRES(390 - 20 - 4), YRES(6), XRES(20), YRES(20), false, false ); + m_PrevPlayerButton->setParent( m_BottomBorder ); + m_PrevPlayerButton->setContentAlignment( vgui::Label::a_center ); + m_PrevPlayerButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name + m_PrevPlayerButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_PREVPLAYER) ); + m_PrevPlayerButton->setUnArmedBorderColor ( colorR, colorG, colorB, 0 ); + m_PrevPlayerButton->setArmedBorderColor ( armedColorR, armedColorR, armedColorR, 0); + m_PrevPlayerButton->setUnArmedColor ( colorR, colorG, colorB, 0 ); + m_PrevPlayerButton->setArmedColor ( armedColorR, armedColorR, armedColorR, 0); + + m_NextPlayerButton= new ColorButton(">", XRES(390 + 200 + 4), YRES(6), XRES(20), YRES(20), false, false ); + m_NextPlayerButton->setParent( m_BottomBorder ); + m_NextPlayerButton->setContentAlignment( vgui::Label::a_center ); + m_NextPlayerButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name + m_NextPlayerButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_NEXTPLAYER) ); + m_NextPlayerButton->setUnArmedBorderColor ( colorR, colorG, colorB, 0 ); + m_NextPlayerButton->setArmedBorderColor ( armedColorR, armedColorR, armedColorR, 0); + m_NextPlayerButton->setUnArmedColor ( colorR, colorG, colorB, 0); + m_NextPlayerButton->setArmedColor ( armedColorR, armedColorR, armedColorR, 0); + + // Initialize the bottom title. + + m_BottomMainLabel = new ColorButton( "Spectator Bottom", XRES(390), YRES(6), XRES(200), YRES(20), false, false ); + m_BottomMainLabel->setFont(font); + m_BottomMainLabel->setParent(m_BottomBorder); + m_BottomMainLabel->setContentAlignment( vgui::Label::a_center ); + m_BottomMainLabel->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_PLAYERS) ); + + m_BottomMainLabel->setUnArmedBorderColor ( colorR, colorG, colorB, 0); + m_BottomMainLabel->setArmedBorderColor ( armedColorR, armedColorR, armedColorR, 0); + m_BottomMainLabel->setUnArmedColor ( colorR, colorG, colorB, 0); + m_BottomMainLabel->setArmedColor ( armedColorR, armedColorR, armedColorR, 0); + + + + m_menuVisible = true; + + m_insetVisible = false; + + m_ExtraInfo->setVisible( false ); + m_Separator->setVisible( false ); + m_TimerImage->setVisible( false ); + + m_TopBorder->setVisible(true); + m_BottomBorder->setVisible( true ); + + m_overviewButton = new CCheckButton2(); + m_overviewButton->setFont(font); + m_overviewButton->setParent( m_BottomBorder ); + m_overviewButton->SetText("Overview"); + m_overviewButton->setPos(XRES(10), YRES(6)); + m_overviewButton->setSize(XRES(100), YRES(20)); + m_overviewButton->SetImages("gfx/vgui/640_checkset.tga", "gfx/vgui/640_checkunset.tga"); + m_overviewButton->SetHandler(new Spectator_CheckButtonHandler(this)); + m_overviewButton->SetTextColor(colorR, colorG, colorB, 0); + + m_firstPersonButton = new CCheckButton2(); + m_firstPersonButton->setFont(font); + m_firstPersonButton->setParent( m_BottomBorder ); + m_firstPersonButton->SetText("First person"); + m_firstPersonButton->setPos(XRES(10 + 100), YRES(6)); + m_firstPersonButton->setSize(XRES(100), YRES(20)); + m_firstPersonButton->SetImages("gfx/vgui/640_checkset.tga", "gfx/vgui/640_checkunset.tga"); + m_firstPersonButton->SetHandler(new Spectator_CheckButtonHandler(this)); + m_firstPersonButton->SetTextColor(colorR, colorG, colorB, 0); + + m_autoDirectorButton = new CCheckButton2(); + m_autoDirectorButton->setFont(font); + m_autoDirectorButton->setParent( m_BottomBorder ); + m_autoDirectorButton->SetText("Auto-director"); + m_autoDirectorButton->setPos(XRES(10 + 200), YRES(6)); + m_autoDirectorButton->setSize(XRES(100), YRES(20)); + m_autoDirectorButton->SetImages("gfx/vgui/640_checkset.tga", "gfx/vgui/640_checkunset.tga"); + m_autoDirectorButton->SetHandler(new Spectator_CheckButtonHandler(this)); + m_autoDirectorButton->SetTextColor(colorR, colorG, colorB, 0); + + +/* + m_OverviewData.insetWindowX = 4; // upper left corner + m_OverviewData.insetWindowY = 4 + SPECTATOR_PANEL_HEIGHT; + m_OverviewData.insetWindowHeight = 180; + m_OverviewData.insetWindowWidth = 240; + + + theDrawInfo.mX = XRES(m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth + 4); + theDrawInfo.mY = YRES(SPECTATOR_PANEL_HEIGHT + 4); + theDrawInfo.mWidth = ScreenWidth() - theDrawInfo.mX - XRES(4); + theDrawInfo.mHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theDrawInfo.mY; +*/ + + int theX = XRES(4 + 240 + 4); + int theY = YRES(SPECTATOR_PANEL_HEIGHT + 4); + int theWidth = ScreenWidth() - theX - XRES(4); + int theHeight = ScreenHeight() - YRES(SPECTATOR_PANEL_HEIGHT + 4) - theY; + + m_overviewControl = new AvHOverviewControl; + m_overviewControl->setPos(theX, theY); + m_overviewControl->setSize(theWidth, theHeight); + m_overviewControl->setParent(this); + +} + +void SpectatorPanel::ShowMenu(bool isVisible) +{ + + if ( !isVisible ) + { + gViewPort->HideCommandMenu(); + } + + m_menuVisible = isVisible; + + gViewPort->UpdateCursorState(); + +} + + +void SpectatorPanel::EnableInsetView(bool isEnabled) +{ + + + int x = gHUD.m_Spectator.m_OverviewData.insetWindowX; + int y = gHUD.m_Spectator.m_OverviewData.insetWindowY; + int wide = gHUD.m_Spectator.m_OverviewData.insetWindowWidth; + int tall = gHUD.m_Spectator.m_OverviewData.insetWindowHeight; + int offset = x + wide + 2; + + if ( isEnabled ) + { + // short black bar to see full inset + m_TopBorder->setBounds( XRES(offset), 0, XRES(640 - offset ), YRES(SPECTATOR_PANEL_HEIGHT) ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + m_TopBanner->setVisible( true ); + m_TopBanner->setPos( XRES(offset), 0 ); + } + else + m_TopBanner->setVisible( false ); + + } + else + { + // full black bar, no inset border + // show banner only in real HLTV mode + if ( gEngfuncs.IsSpectateOnly() ) + { + m_TopBanner->setVisible( true ); + m_TopBanner->setPos( 0,0 ); + } + else + m_TopBanner->setVisible( false ); + + m_TopBorder->setBounds( 0, 0, ScreenWidth(), YRES(SPECTATOR_PANEL_HEIGHT) ); + + } + + m_insetVisible = isEnabled; + + Update(); + +} + + +void SpectatorPanel::Update() +{ + + // Update the check boxes. + m_overviewButton->SetChecked(gHUD.m_Spectator.IsInOverviewMode()); + m_overviewButton->setVisible(gHUD.GetIsNSMode()); + + m_firstPersonButton->SetChecked(g_iUser1 == OBS_IN_EYE); + + m_autoDirectorButton->SetChecked(CVAR_GET_FLOAT("spec_autodirector") != 0); + m_autoDirectorButton->setVisible(gEngfuncs.IsSpectateOnly()); + + m_overviewControl->setVisible(gHUD.m_Spectator.IsInOverviewMode()); + + int iTextWidth, iTextHeight; + int iTimeHeight, iTimeWidth; + int offset,j; + + // TODO Max: Figure out what this is for. + + if ( m_insetVisible ) + offset = gHUD.m_Spectator.m_OverviewData.insetWindowX + gHUD.m_Spectator.m_OverviewData.insetWindowWidth + 2; + else + offset = 0; + + //bool visible = gHUD.m_Spectator.m_drawstatus->value != 0; + bool visible = true; + + m_ExtraInfo->setVisible( visible ); + m_TimerImage->setVisible( visible ); + m_CurrentTime->setVisible( visible ); + m_Separator->setVisible( visible ); + + for ( j= 0; j < TEAM_NUMBER; j++ ) + m_TeamScores[j]->setVisible( visible ); + + if ( !visible ) + return; + + m_ExtraInfo->getTextSize( iTextWidth, iTextHeight ); + m_CurrentTime->getTextSize( iTimeWidth, iTimeHeight ); + + iTimeWidth += XRES ( 14 ); // +timer icon + iTimeWidth += ( 4-(iTimeWidth%4) ); + + if ( iTimeWidth > iTextWidth ) + iTextWidth = iTimeWidth; + + int xPos = ScreenWidth() - ( iTextWidth + XRES ( 4 + offset ) ); + + m_ExtraInfo->setBounds( xPos, YRES( 1 ), iTextWidth, iTextHeight ); + + m_TimerImage->setBounds( xPos, YRES( 2 ) + iTextHeight , XRES(14), YRES(14) ); + + m_CurrentTime->setBounds( xPos + XRES ( 14 + 1 ), YRES( 2 ) + iTextHeight , iTimeWidth, iTimeHeight ); + + m_Separator->setPos( ScreenWidth() - ( iTextWidth + XRES ( 4+2+4+offset ) ) , YRES( 1 ) ); + m_Separator->setSize( XRES( 4 ), YRES( SPECTATOR_PANEL_HEIGHT - 2 ) ); + + for ( j= 0; j < TEAM_NUMBER; j++ ) + { + int iwidth, iheight; + + m_TeamScores[j]->getTextSize( iwidth, iheight ); + m_TeamScores[j]->setBounds( ScreenWidth() - ( iTextWidth + XRES ( 4+2+4+2+offset ) + iwidth ), YRES( 1 ) + ( iheight * j ), iwidth, iheight ); + } + +} diff --git a/main/source/cl_dll/vgui_SpectatorPanel.h b/main/source/cl_dll/vgui_SpectatorPanel.h index 008fa5fc..884628bc 100644 --- a/main/source/cl_dll/vgui_SpectatorPanel.h +++ b/main/source/cl_dll/vgui_SpectatorPanel.h @@ -1,115 +1,115 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// vgui_SpectatorPanel.h: interface for the SpectatorPanel class. -// -////////////////////////////////////////////////////////////////////// - -#ifndef SPECTATORPANEL_H -#define SPECTATORPANEL_H - -#include -#include -#include - -using namespace vgui; - -#define SPECTATOR_PANEL_CMD_NONE 0 - -#define SPECTATOR_PANEL_CMD_OPTIONS 1 -#define SPECTATOR_PANEL_CMD_PREVPLAYER 2 -#define SPECTATOR_PANEL_CMD_NEXTPLAYER 3 -#define SPECTATOR_PANEL_CMD_HIDEMENU 4 -#define SPECTATOR_PANEL_CMD_TOGGLE_INSET 5 -#define SPECTATOR_PANEL_CMD_CAMERA 6 -#define SPECTATOR_PANEL_CMD_PLAYERS 7 - - -#define SPECTATOR_PANEL_HEIGHT 32 // Height of the letter box strips. - - -#define TEAM_NUMBER 2 - -class AvHOverviewControl; - -class SpectatorPanel : public Panel //, public vgui::CDefaultInputSignal -{ - -public: - SpectatorPanel(int x,int y,int wide,int tall); - virtual ~SpectatorPanel(); - - void ActionSignal(int cmd); - void StateChanged(CCheckButton2* pButton); - - // InputSignal overrides. -public: - void Initialize(); - void Update(); - - - -public: - - void EnableInsetView(bool isEnabled); - void ShowMenu(bool isVisible); - - - //ColorButton * m_OptionButton; - ColorButton * m_PrevPlayerButton; - ColorButton * m_NextPlayerButton; - //ColorButton * m_CamButton; - - CTransparentPanel * m_TopBorder; - CTransparentPanel * m_BottomBorder; - - ColorButton *m_BottomMainLabel; - CImageLabel *m_TimerImage; - Label *m_CurrentTime; - Label *m_ExtraInfo; - Panel *m_Separator; - - Label *m_TeamScores[TEAM_NUMBER]; - - CImageLabel *m_TopBanner; - - bool m_menuVisible; - bool m_insetVisible; - - // Added by mmcguire. - CCheckButton2* m_overviewButton; - CCheckButton2* m_autoDirectorButton; - CCheckButton2* m_firstPersonButton; - - AvHOverviewControl* m_overviewControl; - -}; - - - -class CSpectatorHandler_Command : public ActionSignal -{ - -private: - SpectatorPanel * m_pFather; - int m_cmd; - -public: - CSpectatorHandler_Command( SpectatorPanel * panel, int cmd ) - { - m_pFather = panel; - m_cmd = cmd; - } - - virtual void actionPerformed( Panel * panel ) - { - m_pFather->ActionSignal(m_cmd); - } -}; - - -#endif // !defined SPECTATORPANEL_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// vgui_SpectatorPanel.h: interface for the SpectatorPanel class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SPECTATORPANEL_H +#define SPECTATORPANEL_H + +#include +#include +#include + +using namespace vgui; + +#define SPECTATOR_PANEL_CMD_NONE 0 + +#define SPECTATOR_PANEL_CMD_OPTIONS 1 +#define SPECTATOR_PANEL_CMD_PREVPLAYER 2 +#define SPECTATOR_PANEL_CMD_NEXTPLAYER 3 +#define SPECTATOR_PANEL_CMD_HIDEMENU 4 +#define SPECTATOR_PANEL_CMD_TOGGLE_INSET 5 +#define SPECTATOR_PANEL_CMD_CAMERA 6 +#define SPECTATOR_PANEL_CMD_PLAYERS 7 + + +#define SPECTATOR_PANEL_HEIGHT 32 // Height of the letter box strips. + + +#define TEAM_NUMBER 2 + +class AvHOverviewControl; + +class SpectatorPanel : public Panel //, public vgui::CDefaultInputSignal +{ + +public: + SpectatorPanel(int x,int y,int wide,int tall); + virtual ~SpectatorPanel(); + + void ActionSignal(int cmd); + void StateChanged(CCheckButton2* pButton); + + // InputSignal overrides. +public: + void Initialize(); + void Update(); + + + +public: + + void EnableInsetView(bool isEnabled); + void ShowMenu(bool isVisible); + + + //ColorButton * m_OptionButton; + ColorButton * m_PrevPlayerButton; + ColorButton * m_NextPlayerButton; + //ColorButton * m_CamButton; + + CTransparentPanel * m_TopBorder; + CTransparentPanel * m_BottomBorder; + + ColorButton *m_BottomMainLabel; + CImageLabel *m_TimerImage; + Label *m_CurrentTime; + Label *m_ExtraInfo; + Panel *m_Separator; + + Label *m_TeamScores[TEAM_NUMBER]; + + CImageLabel *m_TopBanner; + + bool m_menuVisible; + bool m_insetVisible; + + // Added by mmcguire. + CCheckButton2* m_overviewButton; + CCheckButton2* m_autoDirectorButton; + CCheckButton2* m_firstPersonButton; + + AvHOverviewControl* m_overviewControl; + +}; + + + +class CSpectatorHandler_Command : public ActionSignal +{ + +private: + SpectatorPanel * m_pFather; + int m_cmd; + +public: + CSpectatorHandler_Command( SpectatorPanel * panel, int cmd ) + { + m_pFather = panel; + m_cmd = cmd; + } + + virtual void actionPerformed( Panel * panel ) + { + m_pFather->ActionSignal(m_cmd); + } +}; + + +#endif // !defined SPECTATORPANEL_H diff --git a/main/source/cl_dll/vgui_TeamFortressViewport.cpp b/main/source/cl_dll/vgui_TeamFortressViewport.cpp index 5f905a54..8247595d 100644 --- a/main/source/cl_dll/vgui_TeamFortressViewport.cpp +++ b/main/source/cl_dll/vgui_TeamFortressViewport.cpp @@ -1,2647 +1,2647 @@ -//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: Client DLL VGUI Viewport -// -// $Workfile: $ -// $Date: 2002/10/28 20:32:17 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_TeamFortressViewport.cpp,v $ -// Revision 1.12 2002/10/28 20:32:17 Flayra -// - Don't display disconcerting error message -// -// Revision 1.11 2002/10/16 00:37:33 Flayra -// - Added support for authentication in scoreboard -// -// Revision 1.10 2002/07/08 16:15:13 Flayra -// - Refactored team color management -// -// Revision 1.9 2002/04/16 19:32:07 Charlie -// - Removed crappy way of handling pop-up menu changes, removed pressing enter to go back to RR (was getting in way of chat, now just use "readyroom" - F4 -) -// -// Revision 1.8 2002/02/25 20:35:41 Charlie -// - Added hotgrouping of units and buildings, moving to units or buildings when double-tapping, and camera tracking -// -// Revision 1.7 2002/01/30 18:34:32 Charlie -// - Fixed doubled-cursor problem with scoreboard (only show sprite cursor, not Windows cursor) -// -// Revision 1.6 2001/11/13 17:51:02 Charlie -// - Increased max teams, changed team colors (allow aliens vs. aliens and fronts vs. fronts), general scoreboard support -// -// Revision 1.5 2001/10/22 19:26:32 Charlie -// - Changes to make scoreboard work in commander mode -// -// Revision 1.4 2001/09/13 15:01:02 Charlie -// - Merging with 1108 -// -// Revision 1.3 2001/06/02 14:26:47 charlie -// - Commented out UpdateCursorState because it was causing problems (look into this) -// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie -// - HL1108 -// -// Revision 1.2 2001/04/09 19:31:35 charlie -// - Quick hacky tests to try out menus for team/class picking...yuck -// -// Revision 1.1.1.1 2000/06/17 14:12:45 charlie -// Final version of new HL SDK. May not compile. -// Previous versions of my MSVC project files and utility .bat files. -// This is my starting point; there is no mod-specific code in here. -// -// -// $NoKeywords: $ -//============================================================================= -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "common/cvardef.h" -#include "common/usercmd.h" -#include "common/const.h" -#include "camera.h" -#include "in_defs.h" -#include "pm_shared/pm_shared.h" -#include "../engine/keydefs.h" -#include "demo.h" -#include "common/demo_api.h" - -#include "vgui_int.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ServerBrowser.h" -#include "vgui_ScorePanel.h" -#include "vgui_SpectatorPanel.h" -#include "vgui_loadtga.h" -#include "mod/AvHConstants.h" -#include "mod/AvHTitles.h" -#include "mod/AvHPieMenuHandler.h" -#include "mod/AvHSharedUtil.h" -#include "mod/AvHCommandConstants.h" -#include "ui/ChatPanel.h" -#include "mod/AvHNetworkMessages.h" -#include "util/STLUtil.h" - -extern int g_iVisibleMouse; -class CCommandMenu; -int g_iPlayerClass; -int g_iTeamNumber; -int g_iUser1; -int g_iUser2; -int g_iUser3; - -// Scoreboard positions -#define SBOARD_INDENT_X XRES(75) -#define SBOARD_INDENT_Y YRES(40) - -// low-res scoreboard indents -#define SBOARD_INDENT_X_512 30 -#define SBOARD_INDENT_Y_512 30 - -#define SBOARD_INDENT_X_400 0 -#define SBOARD_INDENT_Y_400 20 - - -const int kPlayerMenuWidth = 200; - -void IN_ResetMouse( void ); -extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ); -extern float * GetClientColor( int clientIndex ); - -using namespace vgui; - - -class PlayerButton : public CommandButton -{ - -public: - - PlayerButton(int inPlayerNumber, const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat ) - : CommandButton(text, x, y, wide, tall, bNoHighlight, bFlat) - { - mPlayerNumber = inPlayerNumber; - } - - void paint() - { - - // Set the color of the button based on the team color (or red if the player is dead). - - int theTeamNumber = g_PlayerExtraInfo[mPlayerNumber].teamnumber % iNumberOfTeamColors; - int r, g, b; - - switch (g_PlayerExtraInfo[mPlayerNumber].playerclass) - { - - case PLAYERCLASS_DEAD_MARINE: - case PLAYERCLASS_DEAD_ALIEN: - case PLAYERCLASS_REINFORCING: - r = 255 / gHUD.GetGammaSlope(); - g = 0 / gHUD.GetGammaSlope(); - b = 0 / gHUD.GetGammaSlope(); - break; - - default: - r = kTeamColors[theTeamNumber][0] / gHUD.GetGammaSlope(); - g = kTeamColors[theTeamNumber][1] / gHUD.GetGammaSlope(); - b = kTeamColors[theTeamNumber][2] / gHUD.GetGammaSlope(); - break; - - } - - setFgColor(r, g, b, 0); - - Button::paint(); - - } - - void paintBackground() - { - if ( isArmed() ) - { - // Orange Border - drawSetColor(255, 255, 255, 0); - drawOutlinedRect(0,0,_size[0],_size[1]); - } - } - -private: - - int mPlayerNumber; - -}; - - -// Used for Class specific buttons -char *sTFClasses[] = -{ - "", - "SCOUT", - "SNIPER", - "SOLDIER", - "DEMOMAN", - "MEDIC", - "HWGUY", - "PYRO", - "SPY", - "ENGINEER", - "CIVILIAN", -}; - -char *sLocalisedClasses[] = -{ - "#Civilian", - "#Scout", - "#Sniper", - "#Soldier", - "#Demoman", - "#Medic", - "#HWGuy", - "#Pyro", - "#Spy", - "#Engineer", - "#Random", - "#Civilian", -}; - -char *sTFClassSelection[] = -{ - "civilian", - "scout", - "sniper", - "soldier", - "demoman", - "medic", - "hwguy", - "pyro", - "spy", - "engineer", - "randompc", - "civilian", -}; - -const int kNumOptionsButtons = 4; - -char* kOptionsButtons[kNumOptionsButtons*2] = -{ - "#Menu_Marine1Team", "jointeamone", - "#Menu_Alien1Team", "jointeamtwo", - "#Menu_ReadyRoom", "readyroom", - "#Menu_LeaveGame", "escape", -}; - -int iBuildingCosts[] = -{ - BUILD_COST_DISPENSER, - BUILD_COST_SENTRYGUN -}; - -// This maps class numbers to the Invalid Class bit. -// This is needed for backwards compatability in maps that were finished before -// all the classes were in TF. Hence the wacky sequence. -int sTFValidClassInts[] = -{ - 0, - TF_ILL_SCOUT, - TF_ILL_SNIPER, - TF_ILL_SOLDIER, - TF_ILL_DEMOMAN, - TF_ILL_MEDIC, - TF_ILL_HVYWEP, - TF_ILL_PYRO, - TF_ILL_SPY, - TF_ILL_ENGINEER, - TF_ILL_RANDOMPC, -}; - -// Get the name of TGA file, based on GameDir -char* GetVGUITGAName(const char *pszName) -{ - int i; - char sz[256]; - static char gd[256]; - const char *gamedir; - - if (ScreenWidth() < 640) - i = 320; - else - i = 640; - sprintf(sz, pszName, i); - - gamedir = gEngfuncs.pfnGetGameDirectory(); - sprintf(gd, "%s/gfx/vgui/%s.tga",gamedir,sz); - - return gd; -} - -//================================================================ -// COMMAND MENU -//================================================================ -void CCommandMenu::AddButton( CommandButton *pButton ) -{ - if (m_iButtons >= MAX_BUTTONS) - return; - - m_aButtons[m_iButtons] = pButton; - m_iButtons++; - pButton->setParent( this ); - pButton->setFont( Scheme::sf_primary3 ); - - // give the button a default key binding - if ( m_iButtons < 10 ) - { - pButton->setBoundKey( m_iButtons + '0' ); - } - else if ( m_iButtons == 10 ) - { - pButton->setBoundKey( '0' ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Tries to find a button that has a key bound to the input, and -// presses the button if found -// Input : keyNum - the character number of the input key -// Output : Returns true if the command menu should close, false otherwise -//----------------------------------------------------------------------------- -bool CCommandMenu::KeyInput( int keyNum ) -{ - // loop through all our buttons looking for one bound to keyNum - for ( int i = 0; i < m_iButtons; i++ ) - { - if ( !m_aButtons[i]->IsNotValid() ) - { - if ( m_aButtons[i]->getBoundKey() == keyNum ) - { - // hit the button - if ( m_aButtons[i]->GetSubMenu() ) - { - // open the sub menu - gViewPort->SetCurrentCommandMenu( m_aButtons[i]->GetSubMenu() ); - return false; - } - else - { - // run the bound command - m_aButtons[i]->fireActionSignal(); - return true; - } - } - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: clears the current menus buttons of any armed (highlighted) -// state, and all their sub buttons -//----------------------------------------------------------------------------- -void CCommandMenu::ClearButtonsOfArmedState( void ) -{ - for ( int i = 0; i < GetNumButtons(); i++ ) - { - m_aButtons[i]->setArmed( false ); - - if ( m_aButtons[i]->GetSubMenu() ) - { - m_aButtons[i]->GetSubMenu()->ClearButtonsOfArmedState(); - } - } -} - -void CCommandMenu::RemoveAllButtons() -{ - - for ( int i = 0; i < GetNumButtons(); i++ ) - { - - if ( m_aButtons[i]->GetSubMenu() ) - { - m_aButtons[i]->GetSubMenu()->RemoveAllButtons(); - } - - removeChild(m_aButtons[i]); - - delete m_aButtons[i]; - m_aButtons[i] = NULL; - - } - - m_iButtons = 0; - -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pSubMenu - -// Output : CommandButton -//----------------------------------------------------------------------------- -CommandButton *CCommandMenu::FindButtonWithSubmenu( CCommandMenu *pSubMenu ) -{ - for ( int i = 0; i < GetNumButtons(); i++ ) - { - if ( m_aButtons[i]->GetSubMenu() == pSubMenu ) - return m_aButtons[i]; - } - - return NULL; -} - -// Recalculate the visible buttons -bool CCommandMenu::RecalculateVisibles( int iYOffset, bool bHideAll ) -{ - int i, iCurrentY = 0; - int iVisibleButtons = 0; - - // Cycle through all the buttons in this menu, and see which will be visible - for (i = 0; i < m_iButtons; i++) - { - int iClass = m_aButtons[i]->GetPlayerClass(); - if ( (iClass && iClass != g_iPlayerClass ) || ( m_aButtons[i]->IsNotValid() ) || bHideAll ) - { - m_aButtons[i]->setVisible( false ); - if ( m_aButtons[i]->GetSubMenu() != NULL ) - { - (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( 0, true ); - } - } - else - { - // If it's got a submenu, force it to check visibilities - if ( m_aButtons[i]->GetSubMenu() != NULL ) - { - if ( !(m_aButtons[i]->GetSubMenu())->RecalculateVisibles( 0 , false ) ) - { - // The submenu had no visible buttons, so don't display this button - m_aButtons[i]->setVisible( false ); - continue; - } - } - - m_aButtons[i]->setVisible( true ); - iVisibleButtons++; - } - } - - // Set Size - setSize( _size[0], (iVisibleButtons * (m_flButtonSizeY-1)) + 1 ); - - if ( iYOffset ) - { - m_iYOffset = iYOffset; - } - - for (i = 0; i < m_iButtons; i++) - { - if ( m_aButtons[i]->isVisible() ) - { - if ( m_aButtons[i]->GetSubMenu() != NULL ) - (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( iCurrentY + m_iYOffset, false ); - - - // Make sure it's at the right Y position - // m_aButtons[i]->getPos( iXPos, iYPos ); - - if ( m_iDirection ) - { - m_aButtons[i]->setPos( 0, (iVisibleButtons-1) * (m_flButtonSizeY-1) - iCurrentY ); - } - else - { - m_aButtons[i]->setPos( 0, iCurrentY ); - } - - iCurrentY += (m_flButtonSizeY-1); - } - } - - return iVisibleButtons?true:false; -} - -// Make sure all submenus can fit on the screen -void CCommandMenu::RecalculatePositions( int iYOffset ) -{ - int iTop; - int iAdjust = 0; - - m_iYOffset+= iYOffset; - if ( m_iDirection ) - iTop = ScreenHeight() - (m_iYOffset + _size[1] ); - else - iTop = m_iYOffset; - - if ( iTop < 0 ) - iTop = 0; - // Calculate if this is going to fit onscreen, and shuffle it up if it won't - int iBottom = iTop + _size[1]; - if ( iBottom > ScreenHeight() ) - { - // Move in increments of button sizes - while (iAdjust < (iBottom - ScreenHeight())) - { - iAdjust += m_flButtonSizeY - 1; - } - iTop -= iAdjust; - - // Make sure it doesn't move off the top of the screen (the menu's too big to fit it all) - if ( iTop < 0 ) - { - iAdjust -= (0 - iTop); - iTop = 0; - } - } - - setPos( _pos[0], iTop ); - // We need to force all menus below this one to update their positions now, because they - // might have submenus riding off buttons in this menu that have just shifted. - for (int i = 0; i < m_iButtons; i++) - m_aButtons[i]->UpdateSubMenus( iAdjust ); -} - - -// Make this menu and all menus above it in the chain visible -void CCommandMenu::MakeVisible( CCommandMenu *pChildMenu ) -{ - setVisible(true); - if (m_pParentMenu) - m_pParentMenu->MakeVisible( this ); -} - -//================================================================ -// CreateSubMenu -CCommandMenu *TeamFortressViewport::CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu, int iYOffset, int iXOffset ) -{ - int iXPos = 0; - int iYPos = 0; - int iWide = CMENU_SIZE_X; - int iTall = 0; - int iDirection = 0; - - if (pParentMenu) - { - iXPos = m_pCurrentCommandMenu->GetXOffset() + (CMENU_SIZE_X - 1) + iXOffset; - iYPos = m_pCurrentCommandMenu->GetYOffset() + iYOffset; - iDirection = pParentMenu->GetDirection(); - } - - CCommandMenu *pMenu = new CCommandMenu(pParentMenu, iDirection, iXPos, iYPos, iWide, iTall ); - pMenu->setParent(this); - pButton->AddSubMenu( pMenu ); - pButton->setFont( Scheme::sf_primary3 ); - pMenu->m_flButtonSizeY = m_pCurrentCommandMenu->m_flButtonSizeY; - - // Create the Submenu-open signal - InputSignal *pISignal = new CMenuHandler_PopupSubMenuInput(pButton, pMenu); - pButton->addInputSignal(pISignal); - - // Put a > to show it's a submenu - CImageLabel *pLabel = new CImageLabel( "arrow", CMENU_SIZE_X - SUBMENU_SIZE_X, SUBMENU_SIZE_Y ); - pLabel->setParent(pButton); - pLabel->addInputSignal(pISignal); - - // Reposition - pLabel->getPos( iXPos, iYPos ); - pLabel->setPos( CMENU_SIZE_X - pLabel->getImageWide(), (BUTTON_SIZE_Y - pLabel->getImageTall()) / 2 ); - - // Create the mouse off signal for the Label too - if (!pButton->m_bNoHighlight) - pLabel->addInputSignal( new CHandler_CommandButtonHighlight(pButton) ); - - return pMenu; -} - -//----------------------------------------------------------------------------- -// Purpose: Makes sure the memory allocated for TeamFortressViewport is nulled out -// Input : stAllocateBlock - -// Output : void * -//----------------------------------------------------------------------------- -void *TeamFortressViewport::operator new( size_t stAllocateBlock ) -{ -// void *mem = Panel::operator new( stAllocateBlock ); - void *mem = ::operator new( stAllocateBlock ); - memset( mem, 0, stAllocateBlock ); - return mem; -} - -//----------------------------------------------------------------------------- -// Purpose: InputSignal handler for the main viewport -//----------------------------------------------------------------------------- -class CViewPortInputHandler : public InputSignal -{ -public: - bool bPressed; - - CViewPortInputHandler() - { - } - - virtual void cursorMoved(int x,int y,Panel* panel) {} - virtual void cursorEntered(Panel* panel) {} - virtual void cursorExited(Panel* panel) {} - virtual void mousePressed(MouseCode code,Panel* panel) - { - if ( code != MOUSE_LEFT ) - { - // send a message to close the command menu - // this needs to be a message, since a direct call screws the timing - gEngfuncs.pfnClientCmd( "ForceCloseCommandMenu\n" ); - } - } - virtual void mouseReleased(MouseCode code,Panel* panel) - { - } - - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} - virtual void mouseWheeled(int delta,Panel* panel) {} - virtual void keyPressed(KeyCode code,Panel* panel) {} - virtual void keyTyped(KeyCode code,Panel* panel) {} - virtual void keyReleased(KeyCode code,Panel* panel) {} - virtual void keyFocusTicked(Panel* panel) {} -}; - - -//================================================================ -TeamFortressViewport::TeamFortressViewport(int x,int y,int wide,int tall) : Panel(x,y,wide,tall), m_SchemeManager(wide,tall) -{ - gViewPort = this; - m_iInitialized = false; - m_pTeamMenu = NULL; - m_pClassMenu = NULL; - m_pScoreBoard = NULL; - mOptionsScreen = NULL; - mOptionsButtons = new CommandButton*[kNumOptionsButtons]; - - m_pSpectatorPanel = NULL; - m_pCurrentMenu = NULL; - m_pCurrentCommandMenu = NULL; - - Initialize(); - addInputSignal( new CViewPortInputHandler ); - - int r, g, b, a; - - Scheme* pScheme = App::getInstance()->getScheme(); - - // primary text color - // Get the colors - //!! two different types of scheme here, need to integrate - SchemeHandle_t hPrimaryScheme = m_SchemeManager.getSchemeHandle( "Primary Button Text" ); - { - // font - pScheme->setFont( Scheme::sf_primary1, m_SchemeManager.getFont(hPrimaryScheme) ); - - // text color - m_SchemeManager.getFgColor( hPrimaryScheme, r, g, b, a ); - pScheme->setColor(Scheme::sc_primary1, r, g, b, a ); // sc_primary1 is non-transparent orange - - // background color (transparent black) - m_SchemeManager.getBgColor( hPrimaryScheme, r, g, b, a ); - pScheme->setColor(Scheme::sc_primary3, r, g, b, a ); - - // armed foreground color - m_SchemeManager.getFgArmedColor( hPrimaryScheme, r, g, b, a ); - pScheme->setColor(Scheme::sc_secondary2, r, g, b, a ); - - // armed background color - m_SchemeManager.getBgArmedColor( hPrimaryScheme, r, g, b, a ); - pScheme->setColor(Scheme::sc_primary2, r, g, b, a ); - - //!! need to get this color from scheme file - // used for orange borders around buttons - m_SchemeManager.getBorderColor( hPrimaryScheme, r, g, b, a ); - // pScheme->setColor(Scheme::sc_secondary1, r, g, b, a ); - pScheme->setColor(Scheme::sc_secondary1, 255*0.7, 170*0.7, 0, 0); - } - - // Change the second primary font (used in the scoreboard) - SchemeHandle_t hScoreboardScheme = m_SchemeManager.getSchemeHandle( "Scoreboard Text" ); - { - pScheme->setFont(Scheme::sf_primary2, m_SchemeManager.getFont(hScoreboardScheme) ); - } - - // Change the third primary font (used in command menu) - SchemeHandle_t hCommandMenuScheme = m_SchemeManager.getSchemeHandle( "CommandMenu Text" ); - { - pScheme->setFont(Scheme::sf_primary3, m_SchemeManager.getFont(hCommandMenuScheme) ); - } - - App::getInstance()->setScheme(pScheme); - - // VGUI MENUS - CreateTeamMenu(); - CreateClassMenu(); - CreateSpectatorMenu(); - CreateScoreBoard(); - CreateOptionsMenu(); - // Init command menus - m_iNumMenus = 0; - m_iCurrentTeamNumber = m_iUser1 = m_iUser2 = m_iUser3 = 0; - - m_StandardMenu = CreateCommandMenu("commandmenu.txt", 0, CMENU_TOP, false, CMENU_SIZE_X, BUTTON_SIZE_Y, 0 ); - m_SpectatorOptionsMenu = CreateCommandMenu("spectatormenu.txt", 1, YRES(32), true, CMENU_SIZE_X, BUTTON_SIZE_Y / 2, 0 ); // above bottom bar, flat design - m_SpectatorCameraMenu = CreateCommandMenu("spectcammenu.txt", 1, YRES(32), true, XRES( 200 ), BUTTON_SIZE_Y / 2, ScreenWidth() - ( XRES ( 200 ) + 15 ) ); // above bottom bar, flat design - - CreatePlayerMenu(); - - CreateServerBrowser(); - - // : 0000989: - // m_chatPanel = new ChatPanel(10, (ScreenHeight() * 0.75 - 30) / 2, ScreenWidth() - 20, 30); - m_chatPanel = new ChatPanel(10, ScreenHeight() * 0.57f - 30, ScreenWidth() - 20, 30); - // : - m_chatPanel->setParent(this); - m_chatPanel->setVisible(false); - -} - -//----------------------------------------------------------------------------- -// Purpose: Called everytime a new level is started. Viewport clears out it's data. -//----------------------------------------------------------------------------- -void TeamFortressViewport::Initialize( void ) -{ - // Force each menu to Initialize - if (m_pTeamMenu) - { - m_pTeamMenu->Initialize(); - } - if (m_pClassMenu) - { - m_pClassMenu->Initialize(); - } - if (m_pScoreBoard) - { - m_pScoreBoard->Initialize(); - HideScoreBoard(); - } - if (m_pSpectatorPanel) - { - // Spectator menu doesn't need initializing - m_pSpectatorPanel->setVisible( false ); - } - - // Make sure all menus are hidden - HideVGUIMenu(); - HideCommandMenu(); - - // Clear out some data - m_iGotAllMOTD = true; - m_iRandomPC = false; - m_flScoreBoardLastUpdated = 0; - m_flSpectatorPanelLastUpdated = 0; - - // reset player info - g_iPlayerClass = 0; - g_iTeamNumber = 0; - - memset(this->m_sMapName, 0, MAX_MAPNAME_LENGTH); - memset(this->m_szServerName, 0, MAX_SERVERNAME_LENGTH); - for (int i = 0; i < 5; i++) - { - m_iValidClasses[i] = 0; - strcpy(m_sTeamNames[i], ""); - } - - App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::scu_none) ); -} - -class CException; -//----------------------------------------------------------------------------- -// Purpose: Read the Command Menu structure from the txt file and create the menu. -// Returns Index of menu in m_pCommandMenus -//----------------------------------------------------------------------------- -int TeamFortressViewport::CreateCommandMenu( char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ) -{ - // COMMAND MENU - // Create the root of this new Command Menu - - int newIndex = m_iNumMenus; - - m_pCommandMenus[newIndex] = new CCommandMenu(NULL, direction, xOffset, yOffset, flButtonSizeX, 300); // This will be resized once we know how many items are in it - m_pCommandMenus[newIndex]->setParent(this); - m_pCommandMenus[newIndex]->setVisible(false); - m_pCommandMenus[newIndex]->m_flButtonSizeY = flButtonSizeY; - m_pCommandMenus[newIndex]->m_iSpectCmdMenu = direction; - - m_iNumMenus++; - - // Read Command Menu from the txt file - char token[1024]; - char *pfile = (char*)gEngfuncs.COM_LoadFile( menuFile, 5, NULL); - if (!pfile) - { - gEngfuncs.Con_DPrintf( "Unable to open %s\n", menuFile); - SetCurrentCommandMenu( NULL ); - return newIndex; - } - -#ifdef _WIN32 -try -{ -#endif - // First, read in the localisation strings - - // Detpack strings - gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For5Seconds", m_sDetpackStrings[0], MAX_BUTTON_SIZE ); - gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For20Seconds", m_sDetpackStrings[1], MAX_BUTTON_SIZE ); - gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For50Seconds", m_sDetpackStrings[2], MAX_BUTTON_SIZE ); - - // Now start parsing the menu structure - m_pCurrentCommandMenu = m_pCommandMenus[newIndex]; - char szLastButtonText[32] = "file start"; - pfile = gEngfuncs.COM_ParseFile(pfile, token); - while ( ( strlen ( token ) > 0 ) && ( m_iNumMenus < MAX_MENUS ) ) - { - // Keep looping until we hit the end of this menu - while ( token[0] != '}' && ( strlen( token ) > 0 ) ) - { - char cText[32] = ""; - char cBoundKey[32] = ""; - char cCustom[32] = ""; - static const int cCommandLength = 128; - char cCommand[cCommandLength] = ""; - char szMap[MAX_MAPNAME] = ""; - int iPlayerClass = 0; - int iCustom = false; - int iTeamOnly = -1; - int iToggle = 0; - int iButtonY; - bool bGetExtraToken = true; - CommandButton *pButton = NULL; - - // We should never be here without a Command Menu - if (!m_pCurrentCommandMenu) - { - gEngfuncs.Con_Printf("Error in %s file after '%s'.\n",menuFile, szLastButtonText ); - m_iInitialized = false; - return newIndex; - } - - // token should already be the bound key, or the custom name - strncpy( cCustom, token, 32 ); - cCustom[31] = '\0'; - - // See if it's a custom button - if (!strcmp(cCustom, "CUSTOM") ) - { - iCustom = true; - - // Get the next token - pfile = gEngfuncs.COM_ParseFile(pfile, token); - } - // See if it's a map - else if (!strcmp(cCustom, "MAP") ) - { - // Get the mapname - pfile = gEngfuncs.COM_ParseFile(pfile, token); - strncpy( szMap, token, MAX_MAPNAME ); - szMap[MAX_MAPNAME-1] = '\0'; - - // Get the next token - pfile = gEngfuncs.COM_ParseFile(pfile, token); - } - else if ( !strncmp(cCustom, "TEAM", 4) ) // TEAM1, TEAM2, TEAM3, TEAM4 - { - // make it a team only button - iTeamOnly = atoi( cCustom + 4 ); - - // Get the next token - pfile = gEngfuncs.COM_ParseFile(pfile, token); - } - else if ( !strncmp(cCustom, "TOGGLE", 6) ) - { - iToggle = true; - // Get the next token - pfile = gEngfuncs.COM_ParseFile(pfile, token); - } - else - { - // See if it's a Class - for (int i = 1; i <= PC_ENGINEER; i++) - { - if ( !strcmp(token, sTFClasses[i]) ) - { - // Save it off - iPlayerClass = i; - - // Get the button text - pfile = gEngfuncs.COM_ParseFile(pfile, token); - break; - } - } - } - - // Get the button bound key - strncpy( cBoundKey, token, 32 ); - cText[31] = '\0'; - - // Get the button text - pfile = gEngfuncs.COM_ParseFile(pfile, token); - strncpy( cText, token, 32 ); - cText[31] = '\0'; - - // save off the last button text we've come across (for error reporting) - strcpy( szLastButtonText, cText ); - - // Get the button command - pfile = gEngfuncs.COM_ParseFile(pfile, token); - strncpy( cCommand, token, cCommandLength ); - cCommand[cCommandLength - 1] = '\0'; - - iButtonY = (BUTTON_SIZE_Y-1) * m_pCurrentCommandMenu->GetNumButtons(); - // Custom button handling - if ( iCustom ) - { - pButton = CreateCustomButton( cText, cCommand, iButtonY ); - - // Get the next token to see if we're a menu - pfile = gEngfuncs.COM_ParseFile(pfile, token); - - if ( token[0] == '{' ) - { - strcpy( cCommand, token ); - } - else - { - bGetExtraToken = false; - } - } - else if ( szMap[0] != '\0' ) - { - // create a map button - pButton = new MapButton(szMap, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY ); - } - else if ( iTeamOnly != -1) - { - // button that only shows up if the player is on team iTeamOnly - pButton = new TeamOnlyCommandButton( iTeamOnly, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); - } - else if ( iToggle && direction == 0 ) - { - pButton = new ToggleCommandButton( cCommand, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); - } - else if ( direction == 1 ) - { - if ( iToggle ) - pButton = new SpectToggleButton( cCommand, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); - else - pButton = new SpectButton( iPlayerClass, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY ); - } - else - { - // normal button - pButton = new CommandButton( iPlayerClass, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); - } - - // add the button into the command menu - if ( pButton ) - { - m_pCurrentCommandMenu->AddButton( pButton ); - pButton->setBoundKey( cBoundKey[0] ); - pButton->setParentMenu( m_pCurrentCommandMenu ); - - // Override font in CommandMenu - pButton->setFont( Scheme::sf_primary3 ); - } - - // Find out if it's a submenu or a button we're dealing with - if ( cCommand[0] == '{' ) - { - if ( m_iNumMenus >= MAX_MENUS ) - { - gEngfuncs.Con_Printf( "Too many menus in %s past '%s'\n",menuFile, szLastButtonText ); - } - else - { - // Create the menu - m_pCommandMenus[m_iNumMenus] = CreateSubMenu(pButton, m_pCurrentCommandMenu, iButtonY ); - m_pCurrentCommandMenu = m_pCommandMenus[m_iNumMenus]; - m_iNumMenus++; - } - } - else if ( !iCustom ) - { - // Create the button and attach it to the current menu - if ( iToggle ) - pButton->addActionSignal(new CMenuHandler_ToggleCvar(cCommand)); - else - pButton->addActionSignal(new CMenuHandler_StringCommand(cCommand)); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - - // Get the next token - if ( bGetExtraToken ) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - } - } - - // Move back up a menu - m_pCurrentCommandMenu = m_pCurrentCommandMenu->GetParentMenu(); - - pfile = gEngfuncs.COM_ParseFile(pfile, token); - } -#ifdef _WIN32 -} -catch( CException *e ) -{ - e; - //e->Delete(); - e = NULL; - m_iInitialized = false; - return newIndex; -} -#endif - - SetCurrentMenu( NULL ); - SetCurrentCommandMenu( NULL ); - gEngfuncs.COM_FreeFile( pfile ); - - m_iInitialized = true; - return newIndex; -} - -//----------------------------------------------------------------------------- -// Purpose: Creates all the class choices under a spy's disguise menus, and -// maps a command to them -// Output : CCommandMenu -//----------------------------------------------------------------------------- -CCommandMenu *TeamFortressViewport::CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset ) -{ - // create the submenu, under which the class choices will be listed - CCommandMenu *pMenu = CreateSubMenu( pButton, pParentMenu, iYOffset, iXOffset ); - m_pCommandMenus[m_iNumMenus] = pMenu; - m_iNumMenus++; - - // create the class choice buttons - for ( int i = PC_SCOUT; i <= PC_ENGINEER; i++ ) - { - CommandButton *pDisguiseButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); - - char sz[256]; - sprintf(sz, "%s %d", commandText, i ); - pDisguiseButton->addActionSignal(new CMenuHandler_StringCommand(sz)); - - pMenu->AddButton( pDisguiseButton ); - } - - return pMenu; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pButtonText - -// *pButtonName - -// Output : CommandButton -//----------------------------------------------------------------------------- -CommandButton *TeamFortressViewport::CreateCustomButton( char *pButtonText, char *pButtonName, int iYOffset ) -{ - CommandButton *pButton = NULL; - CCommandMenu *pMenu = NULL; - - // ChangeTeam - if ( !strcmp( pButtonName, "!CHANGETEAM" ) ) - { - // ChangeTeam Submenu - pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - - // Create the submenu - pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); - m_pCommandMenus[m_iNumMenus] = pMenu; - m_iNumMenus++; - - // ChangeTeam buttons - for (int i = 0; i < 4; i++) - { - char sz[256]; - sprintf(sz, "jointeam %d", i+1); - m_pTeamButtons[i] = new TeamButton(i+1, "teamname", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - m_pTeamButtons[i]->addActionSignal(new CMenuHandler_StringCommandWatch( sz )); - pMenu->AddButton( m_pTeamButtons[i] ); - } - - // Auto Assign button - m_pTeamButtons[4] = new TeamButton(5, gHUD.m_TextMessage.BufferedLocaliseTextString( "#Team_AutoAssign" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - m_pTeamButtons[4]->addActionSignal(new CMenuHandler_StringCommand( "jointeam 5" )); - pMenu->AddButton( m_pTeamButtons[4] ); - - // Spectate button - m_pTeamButtons[5] = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); - m_pTeamButtons[5]->addActionSignal(new CMenuHandler_StringCommand( "spectate" )); - pMenu->AddButton( m_pTeamButtons[5] ); - } - // ChangeClass - else if ( !strcmp( pButtonName, "!CHANGECLASS" ) ) - { - // Create the Change class menu - pButton = new ClassButton(-1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); - - // ChangeClass Submenu - pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); - m_pCommandMenus[m_iNumMenus] = pMenu; - m_iNumMenus++; - - for (int i = PC_SCOUT; i <= PC_RANDOM; i++ ) - { - char sz[256]; - - // ChangeClass buttons - CHudTextMessage::LocaliseTextString( sLocalisedClasses[i], sz, 256 ); - ClassButton *pClassButton = new ClassButton( i, sz, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); - - sprintf(sz, "%s", sTFClassSelection[i]); - pClassButton->addActionSignal(new CMenuHandler_StringCommandClassSelect(sz)); - pMenu->AddButton( pClassButton ); - } - } - // Map Briefing - else if ( !strcmp( pButtonName, "!MAPBRIEFING" ) ) - { - pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_MAPBRIEFING)); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Class Descriptions - else if ( !strcmp( pButtonName, "!CLASSDESC" ) ) - { - pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); - pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_CLASSHELP)); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!SERVERINFO" ) ) - { - pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); - pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_INTRO)); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Spy abilities - else if ( !strcmp( pButtonName, "!SPY" ) ) - { - pButton = new DisguiseButton( 0, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); - } - // Feign - else if ( !strcmp( pButtonName, "!FEIGN" ) ) - { - pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Feign Silently - else if ( !strcmp( pButtonName, "!FEIGNSILENT" ) ) - { - pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand( "sfeign" )); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Stop Feigning - else if ( !strcmp( pButtonName, "!FEIGNSTOP" ) ) - { - pButton = new FeignButton(TRUE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Disguise - else if ( !strcmp( pButtonName, "!DISGUISEENEMY" ) ) - { - // Create the disguise enemy button, which active only if there are 2 teams - pButton = new DisguiseButton(DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_enemy", iYOffset); - } - else if ( !strcmp( pButtonName, "!DISGUISEFRIENDLY" ) ) - { - // Create the disguise friendly button, which active only if there are 1 or 2 teams - pButton = new DisguiseButton(DISGUISE_TEAM1 | DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_friendly", iYOffset ); - } - else if ( !strcmp( pButtonName, "!DISGUISE" ) ) - { - // Create the Disguise button - pButton = new DisguiseButton( DISGUISE_TEAM3 | DISGUISE_TEAM4, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - CCommandMenu *pDisguiseMenu = CreateSubMenu( pButton, m_pCurrentCommandMenu, iYOffset ); - m_pCommandMenus[m_iNumMenus] = pDisguiseMenu; - m_iNumMenus++; - - // Disguise Enemy submenu buttons - for ( int i = 1; i <= 4; i++ ) - { - // only show the 4th disguise button if we have 4 teams - m_pDisguiseButtons[i] = new DisguiseButton( ((i < 4) ? DISGUISE_TEAM3 : 0) | DISGUISE_TEAM4, "Disguise", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - - pDisguiseMenu->AddButton( m_pDisguiseButtons[i] ); - m_pDisguiseButtons[i]->setParentMenu( pDisguiseMenu ); - - char sz[256]; - sprintf( sz, "disguise %d", i ); - CreateDisguiseSubmenu( m_pDisguiseButtons[i], pDisguiseMenu, sz, iYOffset, CMENU_SIZE_X - 1 ); - } - } - // Start setting a Detpack - else if ( !strcmp( pButtonName, "!DETPACKSTART" ) ) - { - // Detpack Submenu - pButton = new DetpackButton(2, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - - // Create the submenu - pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); - m_pCommandMenus[m_iNumMenus] = pMenu; - m_iNumMenus++; - - // Set detpack buttons - CommandButton *pDetButton; - pDetButton = new CommandButton(m_sDetpackStrings[0], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 5")); - pMenu->AddButton( pDetButton ); - pDetButton = new CommandButton(m_sDetpackStrings[1], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 20")); - pMenu->AddButton( pDetButton ); - pDetButton = new CommandButton(m_sDetpackStrings[2], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 50")); - pMenu->AddButton( pDetButton ); - } - // Stop setting a Detpack - else if ( !strcmp( pButtonName, "!DETPACKSTOP" ) ) - { - pButton = new DetpackButton(1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand( "detstop" )); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Engineer building - else if ( !strcmp( pButtonName, "!BUILD" ) ) - { - // only appears if the player is an engineer, and either they have built something or have enough metal to build - pButton = new BuildButton( BUILDSTATE_BASE, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - } - else if ( !strcmp( pButtonName, "!BUILDSENTRY" ) ) - { - pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("build 2")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!BUILDDISPENSER" ) ) - { - pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("build 1")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!ROTATESENTRY180" ) ) - { - pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry180")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!ROTATESENTRY" ) ) - { - pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!DISMANTLEDISPENSER" ) ) - { - pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 1")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!DISMANTLESENTRY" ) ) - { - pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 2")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!DETONATEDISPENSER" ) ) - { - pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("detdispenser")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - else if ( !strcmp( pButtonName, "!DETONATESENTRY" ) ) - { - pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("detsentry")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - // Stop building - else if ( !strcmp( pButtonName, "!BUILDSTOP" ) ) - { - pButton = new BuildButton( BUILDSTATE_BUILDING, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); - pButton->addActionSignal(new CMenuHandler_StringCommand("build")); - // Create an input signal that'll popup the current menu - pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); - } - - return pButton; -} - -void TeamFortressViewport::ToggleServerBrowser() -{ - if (!m_iInitialized) - return; - - if ( !m_pServerBrowser ) - return; - - if ( m_pServerBrowser->isVisible() ) - { - m_pServerBrowser->setVisible( false ); - } - else - { - m_pServerBrowser->setVisible( true ); - } - - UpdateCursorState(); -} - -//======================================================================= -void TeamFortressViewport::ShowCommandMenu(int menuIndex) -{ - if (!m_iInitialized) - return; - - //Already have a menu open. - if ( m_pCurrentMenu ) - return; - - // is the command menu open? - if ( m_pCurrentCommandMenu == m_pCommandMenus[menuIndex] ) - { - HideCommandMenu(); - return; - } - - // Not visible while in intermission - if ( gHUD.m_iIntermission ) - return; - - // Recalculate visible menus - UpdateCommandMenu( menuIndex ); - HideVGUIMenu(); - - SetCurrentCommandMenu( m_pCommandMenus[menuIndex] ); - m_flMenuOpenTime = gHUD.m_flTime; - UpdateCursorState(); - - // get command menu parameters - for ( int i = 2; i < gEngfuncs.Cmd_Argc(); i++ ) - { - const char *param = gEngfuncs.Cmd_Argv( i - 1 ); - if ( param ) - { - if ( m_pCurrentCommandMenu->KeyInput(param[0]) ) - { - // kill the menu open time, since the key input is final - HideCommandMenu(); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Handles the key input of "-commandmenu" -// Input : -//----------------------------------------------------------------------------- -void TeamFortressViewport::InputSignalHideCommandMenu() -{ - if (!m_iInitialized) - return; - - // if they've just tapped the command menu key, leave it open - if ( (m_flMenuOpenTime + 0.3) > gHUD.m_flTime ) - return; - - HideCommandMenu(); -} - -//----------------------------------------------------------------------------- -// Purpose: Hides the command menu -//----------------------------------------------------------------------------- -void TeamFortressViewport::HideCommandMenu() -{ - if (!m_iInitialized) - return; - - if ( m_pCommandMenus[m_StandardMenu] ) - { - m_pCommandMenus[m_StandardMenu]->ClearButtonsOfArmedState(); - } - - if ( m_pCommandMenus[m_SpectatorOptionsMenu] ) - { - m_pCommandMenus[m_SpectatorOptionsMenu]->ClearButtonsOfArmedState(); - } - - if ( m_pCommandMenus[m_SpectatorCameraMenu] ) - { - m_pCommandMenus[m_SpectatorCameraMenu]->ClearButtonsOfArmedState(); - } - - m_flMenuOpenTime = 0.0f; - SetCurrentCommandMenu( NULL ); - UpdateCursorState(); -} - -//----------------------------------------------------------------------------- -// Purpose: Bring up the scoreboard -//----------------------------------------------------------------------------- -void TeamFortressViewport::ShowScoreBoard( void ) -{ - if (m_pScoreBoard) - { - // No Scoreboard in single-player - if ( gEngfuncs.GetMaxClients() > 1 ) - { - if(gHUD.SwitchUIMode(SCOREBOARD_MODE)) - { - m_pScoreBoard->Open(); - - // TODO: HLSDK 2.3 requires this? - UpdateCursorState(); - - // If cursor is visible, set squelch mode automatically (used for commander) - if(gHUD.GetIsInTopDownMode()) - { - m_pScoreBoard->SetSquelchMode(true); - } - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Returns true if the scoreboard is up -//----------------------------------------------------------------------------- -bool TeamFortressViewport::IsScoreBoardVisible( void ) -{ - if (m_pScoreBoard) - return m_pScoreBoard->isVisible(); - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Hide the scoreboard -//----------------------------------------------------------------------------- -const float kButtonWidth = .15f; -const float kButtonHeight = .08f; -const float kButtonHorizontalSpacing = .15f; -const float kButtonVerticalSpacing = .05f; -const float xInset = .05f; -const float yInset = .07f; - -void TeamFortressViewport::HideScoreBoard( void ) -{ - // Prevent removal of scoreboard during intermission - if ( gHUD.m_iIntermission ) - return; - - if (m_pScoreBoard && m_pScoreBoard->isVisible()) - { - // Hide other components - if(gHUD.SwitchUIMode(MAIN_MODE)) - { - m_pScoreBoard->setVisible(false); - - //GetClientVoiceMgr()->StopSquelchMode(); - m_pScoreBoard->SetSquelchMode(false); - - //UpdateCursorState(); - } - } -} - -void TeamFortressViewport::ShowOptionsMenu() -{ - if(this->mOptionsScreen) - { - const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON); - gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - - this->mOptionsScreen->setVisible(true); - - for(int i = 0; i < kNumOptionsButtons; i++) - { - if(this->mOptionsButtons[i]) - { - this->mOptionsButtons[i]->setVisible(true); - } - } - - gHUD.GetManager().SetMouseVisibility(true); - } -} - -void TeamFortressViewport::HideOptionsMenu() -{ - if(this->mOptionsScreen) - { - const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_OFF); - gHUD.PlayHUDSound(theSound, kHUDSoundVolume); - - this->mOptionsScreen->setVisible(false); - for(int i = 0; i < kNumOptionsButtons; i++) - { - if(this->mOptionsButtons[i]) - { - this->mOptionsButtons[i]->setVisible(false); - } - } - - gHUD.GetManager().SetMouseVisibility(false); - - gEngfuncs.pfnSetMousePos(gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); - } -} - -bool TeamFortressViewport::IsOptionsMenuVisible() -{ - bool theIsVisible = false; - - if(this->mOptionsScreen) - { - theIsVisible = this->mOptionsScreen->isVisible(); - } - - return theIsVisible; -} - -// Set the submenu of the Command Menu -void TeamFortressViewport::SetCurrentCommandMenu( CCommandMenu *pNewMenu ) -{ - for (int i = 0; i < m_iNumMenus; i++) - m_pCommandMenus[i]->setVisible(false); - - m_pCurrentCommandMenu = pNewMenu; - - if (m_pCurrentCommandMenu) - m_pCurrentCommandMenu->MakeVisible( NULL ); - -} - -void TeamFortressViewport::UpdateCommandMenu(int menuIndex) -{ - m_pCommandMenus[menuIndex]->RecalculateVisibles( 0, false ); - m_pCommandMenus[menuIndex]->RecalculatePositions( 0 ); -} - -void COM_FileBase ( const char *in, char *out); - -void TeamFortressViewport::UpdateSpectatorPanel() -{ - m_iUser1 = g_iUser1; - m_iUser2 = g_iUser2; - m_iUser3 = g_iUser3; - - if (!m_pSpectatorPanel) - return; - - if ( g_iUser1 && gHUD.m_pCvarDraw->value && !gHUD.m_iIntermission) // don't draw in dev_overview mode - { - char bottomText[128]; - char helpString2[128]; - char * name; - int player = 0; - - // check if spectator combinations are still valid - gHUD.m_Spectator.CheckSettings(); - - if ( !m_pSpectatorPanel->isVisible() ) - { - m_pSpectatorPanel->setVisible( true ); // show spectator panel, but - m_pSpectatorPanel->ShowMenu( true ); - - // Removed by mmcguire. - // This text isn't applicable anymore. - - /* - char tempString[128]; - - _snprintf( tempString, sizeof( tempString ) - 1, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( "#Spec_Duck" ) ); - tempString[ sizeof( tempString ) - 1 ] = '\0'; - - gHUD.m_TextMessage.MsgFunc_TextMsg( NULL, strlen( tempString ) + 1, tempString ); - */ - } - - sprintf(bottomText,"#Spec_Mode%d", g_iUser1 ); - sprintf(helpString2,"#Spec_Mode%d", g_iUser1 ); - - if ( gEngfuncs.IsSpectateOnly() ) - strcat(helpString2, " - HLTV"); - - // check if we're locked onto a target, show the player's name - if ( (g_iUser2 > 0) && (g_iUser2 <= gEngfuncs.GetMaxClients()) && (g_iUser1 != OBS_ROAMING) ) - { - player = g_iUser2; - } - - name = g_PlayerInfoList[player].name; - - // create player & health string - if ( player && name ) - { - strcpy( bottomText, name ); - if ( gEngfuncs.IsSpectateOnly() ) { - char tmp[32]; - sprintf(tmp, " (%d)", g_PlayerExtraInfo[player].health); - strcat( bottomText, tmp); - } - } -/* - // in first person mode colorize player names - if ( (g_iUser1 == OBS_IN_EYE) && player ) - { - float * color = GetClientColor( player ); - int r = color[0]*255; - int g = color[1]*255; - int b = color[2]*255; - - // set team color, a bit transparent - m_pSpectatorPanel->m_BottomMainLabel->setFgColor(r,g,b,0); - } - else - { // restore GUI color - m_pSpectatorPanel->m_BottomMainLabel->setFgColor( 143, 143, 54, 0 ); - } -*/ - // add sting auto if we are in auto directed mode - if ( CVAR_GET_FLOAT("spec_autodirector") != 0 ) - { - char tempString[128]; - sprintf(tempString, "#Spec_Auto %s", helpString2); - strcpy( helpString2, tempString ); - } - - m_pSpectatorPanel->m_BottomMainLabel->setText( CHudTextMessage::BufferedLocaliseTextString( bottomText ) ); - - - // update extra info field - char szText[64]; - - if ( gEngfuncs.IsSpectateOnly() ) - { - // in HLTV mode show number of spectators - _snprintf( szText, 63, "%s: %d", CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ), gHUD.m_Spectator.m_iSpectatorNumber ); - } - else - { - // otherwise show map name - char szMapName[64]; - COM_FileBase( gEngfuncs.pfnGetLevelName(), szMapName ); - - _snprintf ( szText, 63, "%s: %s",CHudTextMessage::BufferedLocaliseTextString( "#Spec_Map" ), szMapName ); - } - - szText[63] = 0; - - m_pSpectatorPanel->m_ExtraInfo->setText ( szText ); - - /* - int timer = (int)( gHUD.m_roundTimer.m_flTimeEnd - gHUD.m_flTime ); - - if ( timer < 0 ) - timer = 0; - - _snprintf ( szText, 63, "%d:%02d\n", (timer / 60), (timer % 60) ); - - szText[63] = 0; - - m_pSpectatorPanel->m_CurrentTime->setText( szText ); */ - int theTimeToDisplay = gHUD.GetGameTime(); - _snprintf ( szText, 63, "%d:%02d\n", (theTimeToDisplay / 60), (theTimeToDisplay % 60) ); - szText[63] = 0; - m_pSpectatorPanel->m_CurrentTime->setText( szText ); - - // update spectator panel - gViewPort->m_pSpectatorPanel->Update(); - } - else - { - if ( m_pSpectatorPanel->isVisible() ) - { - m_pSpectatorPanel->setVisible( false ); - } - if (m_pSpectatorPanel->m_menuVisible) - { - m_pSpectatorPanel->ShowMenu( false ); // dsiable all menus/buttons - } - - } - - m_flSpectatorPanelLastUpdated = gHUD.m_flTime + 1.0; // update every seconds -} - -//====================================================================== -void TeamFortressViewport::CreateScoreBoard( void ) -{ - int xdent = SBOARD_INDENT_X; - int ydent = SBOARD_INDENT_Y; - if (ScreenWidth() == 512) - { - xdent = SBOARD_INDENT_X_512; - ydent = SBOARD_INDENT_Y_512; - } - else if (ScreenWidth() == 400) - { - xdent = SBOARD_INDENT_X_400; - ydent = SBOARD_INDENT_Y_400; - } - - m_pScoreBoard = new ScorePanel(xdent, ydent, ScreenWidth() - (xdent * 2), ScreenHeight() - (ydent * 2)); - m_pScoreBoard->setParent(this); - m_pScoreBoard->setVisible(false); -} - -void TeamFortressViewport::CreateOptionsMenu() -{ - //this->mOptionsScreen = new ColoredPanel(0, 0, ScreenWidth, ScreenHeight); - this->mOptionsScreen = new CTransparentPanel(128, 0, 0, ScreenWidth(), ScreenHeight()); - this->mOptionsScreen->setBorder( new LineBorder( Color(255*0.7,170*0.7,0,0 )) ); - this->mOptionsScreen->setParent(this); - this->mOptionsScreen->setBgColor(128, 128, 128, 40); - this->mOptionsScreen->setVisible(false); - - int theScreenWidth = ScreenWidth(); - int theScreenHeight = ScreenHeight(); -} - -void TeamFortressViewport::CreateServerBrowser( void ) -{ - m_pServerBrowser = new ServerBrowser( 0, 0, ScreenWidth(), ScreenHeight() ); - m_pServerBrowser->setParent(this); - m_pServerBrowser->setVisible(false); -} - -void TeamFortressViewport::CreatePlayerMenu() -{ - - int newIndex = m_iNumMenus; - - m_pCommandMenus[newIndex] = new CCommandMenu(NULL, 1, XRES(390), YRES(32), XRES(kPlayerMenuWidth), YRES(300)); // This will be resized once we know how many items are in it - - m_pCommandMenus[newIndex]->setParent(this); - m_pCommandMenus[newIndex]->setVisible(false); - m_pCommandMenus[newIndex]->m_flButtonSizeY = BUTTON_SIZE_Y / 2; - m_pCommandMenus[newIndex]->m_iSpectCmdMenu = 1; - - m_iNumMenus++; - - m_SpectatorPlayerMenu = newIndex; - -} - -void TeamFortressViewport::UpdatePlayerMenu() -{ - - CCommandMenu* pMenu = m_pCommandMenus[m_SpectatorPlayerMenu]; - - int xOffset = 0; - - float flButtonSizeX = XRES(kPlayerMenuWidth); - float flButtonSizeY = BUTTON_SIZE_Y / 2; - - // Create a menu item for each of the players. - - pMenu->ClearButtonsOfArmedState(); - pMenu->RemoveAllButtons(); - - // Make sure we have player info - gViewPort->GetAllPlayersInfo(); - - for (int team = 0; team < 4; ++team) - { - - if (gHUD.GetPlayMode() != PLAYMODE_OBSERVER) - { - // Filter out players who aren't on our team. - - int theLocalPlayerTeam = 0; - - if (gEngfuncs.GetLocalPlayer()) - { - theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; - } - - if (theLocalPlayerTeam != team) - { - continue; - } - - } - - for (int i = 1; i <= MAX_PLAYERS; ++i) - { - - if ( g_PlayerInfoList[i].name == NULL ) - continue; // empty player slot, skip - - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - if ( g_PlayerExtraInfo[i].teamnumber != team) - continue; - - switch(g_PlayerExtraInfo[i].playerclass) - { - case PLAYERCLASS_SPECTATOR: - case PLAYERCLASS_COMMANDER: - case PLAYERCLASS_REINFORCING: - continue; - } - - int iButtonY = (BUTTON_SIZE_Y-1) * pMenu->GetNumButtons(); - - PlayerButton* pButton = new PlayerButton(i, g_PlayerInfoList[i].name, 0, iButtonY, flButtonSizeX, flButtonSizeY, false, true); - - //pButton->setArmedColor(teamR, teamG, teamB, 0); - //pButton->setUnArmedColor(teamR, teamG, teamB, 0); - //pButton->setArmedBorderColor(255 / gHUD.GetGammaSlope(), 255 / gHUD.GetGammaSlope(), 255 / gHUD.GetGammaSlope(), 0); - - if ( pButton ) - { - pMenu->AddButton( pButton ); - pButton->setParentMenu( pMenu ); - pButton->setFont( Scheme::sf_primary3 ); - - char command[MAX_COMMAND_SIZE]; - sprintf(command, "follow %d", i); - - pButton->addActionSignal(new CMenuHandler_StringCommand(command)); - - } - - } - } - -} - -//====================================================================== -// Set the VGUI Menu -void TeamFortressViewport::SetCurrentMenu( CMenuPanel *pMenu ) -{ - m_pCurrentMenu = pMenu; - if ( m_pCurrentMenu ) - { - // Don't open menus in demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) - return; - - m_pCurrentMenu->Open(); - } -} - -//================================================================ -// Text Window -CMenuPanel* TeamFortressViewport::CreateTextWindow( int iTextToShow ) -{ - char sz[256]; - char *cText; - char *pfile = NULL; - static const int MAX_TITLE_LENGTH = 32; - char cTitle[MAX_TITLE_LENGTH]; - - if ( iTextToShow == SHOW_MOTD ) - { - if (!m_szServerName || !m_szServerName[0]) - strcpy( cTitle, kAvHGameName ); - else - strncpy( cTitle, m_szServerName, MAX_TITLE_LENGTH ); - cTitle[MAX_TITLE_LENGTH-1] = 0; - cText = m_szMOTD; - } - else if ( iTextToShow == SHOW_MAPBRIEFING ) - { - // Get the current mapname, and open it's map briefing text - if (m_sMapName && m_sMapName[0]) - { - strcpy( sz, "maps/"); - strcat( sz, m_sMapName ); - strcat( sz, ".txt" ); - } - else - { - const char *level = gEngfuncs.pfnGetLevelName(); - if (!level) - return NULL; - - strcpy( sz, level ); - char *ch = strchr( sz, '.' ); - *ch = '\0'; - strcat( sz, ".txt" ); - - // pull out the map name - strcpy( m_sMapName, level ); - ch = strchr( m_sMapName, '.' ); - if ( ch ) - { - *ch = 0; - } - - ch = strchr( m_sMapName, '/' ); - if ( ch ) - { - // move the string back over the '/' - memmove( m_sMapName, ch+1, strlen(ch)+1 ); - } - } - - pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); - - if (!pfile) - return NULL; - - cText = pfile; - - strncpy( cTitle, m_sMapName, MAX_TITLE_LENGTH ); - cTitle[MAX_TITLE_LENGTH-1] = 0; - } - else if ( iTextToShow == SHOW_CLASSDESC ) - { - switch ( g_iPlayerClass ) - { - case PC_SCOUT: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_scout" ); - CHudTextMessage::LocaliseTextString( "#Title_scout", cTitle, MAX_TITLE_LENGTH ); break; - case PC_SNIPER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_sniper" ); - CHudTextMessage::LocaliseTextString( "#Title_sniper", cTitle, MAX_TITLE_LENGTH ); break; - case PC_SOLDIER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_soldier" ); - CHudTextMessage::LocaliseTextString( "#Title_soldier", cTitle, MAX_TITLE_LENGTH ); break; - case PC_DEMOMAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_demoman" ); - CHudTextMessage::LocaliseTextString( "#Title_demoman", cTitle, MAX_TITLE_LENGTH ); break; - case PC_MEDIC: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_medic" ); - CHudTextMessage::LocaliseTextString( "#Title_medic", cTitle, MAX_TITLE_LENGTH ); break; - case PC_HVYWEAP: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_hwguy" ); - CHudTextMessage::LocaliseTextString( "#Title_hwguy", cTitle, MAX_TITLE_LENGTH ); break; - case PC_PYRO: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_pyro" ); - CHudTextMessage::LocaliseTextString( "#Title_pyro", cTitle, MAX_TITLE_LENGTH ); break; - case PC_SPY: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_spy" ); - CHudTextMessage::LocaliseTextString( "#Title_spy", cTitle, MAX_TITLE_LENGTH ); break; - case PC_ENGINEER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_engineer" ); - CHudTextMessage::LocaliseTextString( "#Title_engineer", cTitle, MAX_TITLE_LENGTH ); break; - case PC_CIVILIAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_civilian" ); - CHudTextMessage::LocaliseTextString( "#Title_civilian", cTitle, MAX_TITLE_LENGTH ); break; - default: - return NULL; - } - - if ( g_iPlayerClass == PC_CIVILIAN ) - { - sprintf(sz, "classes/long_civilian.txt"); - } - else - { - sprintf(sz, "classes/long_%s.txt", sTFClassSelection[ g_iPlayerClass ]); - } - char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); - if (pfile) - { - cText = pfile; - } - } - else if ( iTextToShow == SHOW_SPECHELP ) - { - CHudTextMessage::LocaliseTextString( "#Spec_Help_Title", cTitle, MAX_TITLE_LENGTH ); - cTitle[MAX_TITLE_LENGTH-1] = 0; - - char *pfile = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); - if ( pfile ) - { - cText = pfile; - } - } - - // if we're in the game (ie. have selected a class), flag the menu to be only grayed in the dialog box, instead of full screen - CMenuPanel *pMOTDPanel = CMessageWindowPanel_Create( cText, cTitle, g_iPlayerClass == PC_UNDEFINED, false, 0, 0, ScreenWidth(), ScreenHeight() ); - pMOTDPanel->setParent( this ); - - if ( pfile ) - gEngfuncs.COM_FreeFile( pfile ); - - return pMOTDPanel; -} - -char* TeamFortressViewport::GetTeamName( int iTeam ) -{ - return m_sTeamNames[iTeam]; -} - -//================================================================ -// VGUI Menus -void TeamFortressViewport::ShowVGUIMenu( int iMenu ) -{ - CMenuPanel *pNewMenu = NULL; - - gHUD.SetUsingVGUI(true); - - // Don't open menus in demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) - return; - - // Don't open any menus except the MOTD during intermission - // MOTD needs to be accepted because it's sent down to the client - // after map change, before intermission's turned off - if ( gHUD.m_iIntermission && iMenu != MENU_INTRO ) - return; - - // Don't create one if it's already in the list - if (m_pCurrentMenu) - { - CMenuPanel *pMenu = m_pCurrentMenu; - while (pMenu != NULL) - { - if (pMenu->GetMenuID() == iMenu) - return; - pMenu = pMenu->GetNextMenu(); - } - } - - switch ( iMenu ) - { - case MENU_TEAM: - pNewMenu = ShowTeamMenu(); - break; - - // Map Briefing removed now that it appears in the team menu - case MENU_MAPBRIEFING: - pNewMenu = CreateTextWindow( SHOW_MAPBRIEFING ); - break; - - case MENU_INTRO: - pNewMenu = CreateTextWindow( SHOW_MOTD ); - break; - - case MENU_CLASSHELP: - pNewMenu = CreateTextWindow( SHOW_CLASSDESC ); - break; - - case MENU_SPECHELP: - pNewMenu = CreateTextWindow( SHOW_SPECHELP ); - break; - case MENU_CLASS: - pNewMenu = ShowClassMenu(); - break; - - default: - break; - } - - if (!pNewMenu) - return; - - // Close the Command Menu if it's open - HideCommandMenu(); - - pNewMenu->SetMenuID( iMenu ); - pNewMenu->SetActive( true ); - pNewMenu->setParent(this); - - // See if another menu is visible, and if so, cache this one for display once the other one's finished - if (m_pCurrentMenu) - { - if ( m_pCurrentMenu->GetMenuID() == MENU_CLASS && iMenu == MENU_TEAM ) - { - CMenuPanel *temp = m_pCurrentMenu; - m_pCurrentMenu->Close(); - m_pCurrentMenu = pNewMenu; - m_pCurrentMenu->SetNextMenu( temp ); - m_pCurrentMenu->Open(); - UpdateCursorState(); - } - else - { - m_pCurrentMenu->SetNextMenu( pNewMenu ); - } - } - else - { - m_pCurrentMenu = pNewMenu; - m_pCurrentMenu->Open(); - UpdateCursorState(); - } -} - -// Removes all VGUI Menu's onscreen -void TeamFortressViewport::HideVGUIMenu() -{ - while (m_pCurrentMenu) - { - HideTopMenu(); - } - gHUD.SetUsingVGUI(false); -} - -// Remove the top VGUI menu, and bring up the next one -void TeamFortressViewport::HideTopMenu() -{ - if (m_pCurrentMenu) - { - // Close the top one - m_pCurrentMenu->Close(); - - // Bring up the next one - gViewPort->SetCurrentMenu( m_pCurrentMenu->GetNextMenu() ); - } - - UpdateCursorState(); -} - -// Return TRUE if the HUD's allowed to print text messages -bool TeamFortressViewport::AllowedToPrintText( void ) -{ - // Prevent text messages when fullscreen menus are up - if ( m_pCurrentMenu && g_iPlayerClass == 0 ) - { - int iId = m_pCurrentMenu->GetMenuID(); - if ( iId == MENU_TEAM || iId == MENU_CLASS || iId == MENU_INTRO || iId == MENU_CLASSHELP ) - return FALSE; - } - - return TRUE; -} - -//====================================================================================== -// TEAM MENU -//====================================================================================== -// Bring up the Team selection Menu -CMenuPanel* TeamFortressViewport::ShowTeamMenu() -{ - // Don't open menus in demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) - return NULL; - - m_pTeamMenu->Reset(); - return m_pTeamMenu; -} - -void TeamFortressViewport::CreateTeamMenu() -{ - // Create the panel - m_pTeamMenu = new CTeamMenuPanel(100, false, 0, 0, ScreenWidth(), ScreenHeight()); - m_pTeamMenu->setParent( this ); - m_pTeamMenu->setVisible( false ); -} - -//====================================================================================== -// CLASS MENU -//====================================================================================== -// Bring up the Class selection Menu -CMenuPanel* TeamFortressViewport::ShowClassMenu() -{ - // Don't open menus in demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) - return NULL; - - m_pClassMenu->Reset(); - return m_pClassMenu; -} - -void TeamFortressViewport::CreateClassMenu() -{ - // Create the panel - m_pClassMenu = new CClassMenuPanel(100, false, 0, 0, ScreenWidth(), ScreenHeight()); - m_pClassMenu->setParent(this); - m_pClassMenu->setVisible( false ); -} - -//====================================================================================== -//====================================================================================== -// SPECTATOR MENU -//====================================================================================== -// Spectator "Menu" explaining the Spectator buttons -void TeamFortressViewport::CreateSpectatorMenu() -{ - // Create the Panel - m_pSpectatorPanel = new SpectatorPanel(0, 0, ScreenWidth(), ScreenHeight()); - m_pSpectatorPanel->setParent(this); - m_pSpectatorPanel->setVisible(false); - m_pSpectatorPanel->Initialize(); -} - -//====================================================================================== -// UPDATE HUD SECTIONS -//====================================================================================== -// We've got an update on player info -// Recalculate any menus that use it. -void TeamFortressViewport::UpdateOnPlayerInfo() -{ - if (m_pTeamMenu) - m_pTeamMenu->Update(); - if (m_pClassMenu) - m_pClassMenu->Update(); - if (m_pScoreBoard) - m_pScoreBoard->Update(); -} - -void TeamFortressViewport::UpdateCursorState() -{ - - if (gHUD.GetInTopDownMode() || m_pSpectatorPanel->isVisible() || GetClientVoiceMgr()->IsInSquelchMode()) - { - gHUD.GetManager().SetMouseVisibility(true); - } - else - { - - // Don't reset mouse in demo playback - if ( !gEngfuncs.pDemoAPI->IsPlayingback() ) - { - IN_ResetMouse(); - } - - gHUD.GetManager().SetMouseVisibility(false); - - } - - /* - if(!gHUD.GetInTopDownMode()) - { - // Need cursor if any VGUI window is up - if ( m_pSpectatorPanel->m_menuVisible || m_pCurrentMenu || m_pTeamMenu->isVisible() || m_pServerBrowser->isVisible() || GetClientVoiceMgr()->IsInSquelchMode() ) - { - gHUD.GetManager().SetMouseVisibility(true); - //g_iVisibleMouse = true; - //App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); - return; - } - else if ( m_pCurrentCommandMenu ) - { - // commandmenu doesn't have cursor if hud_capturemouse is turned off - if ( gHUD.m_pCvarStealMouse->value != 0.0f ) - { - gHUD.GetManager().SetMouseVisibility(true); - //g_iVisibleMouse = true; - //App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); - return; - } - } - - // Don't reset mouse in demo playback - if ( !gEngfuncs.pDemoAPI->IsPlayingback() ) - { - IN_ResetMouse(); - } - - gHUD.GetManager().SetMouseVisibility(false); - //g_iVisibleMouse = false; - //App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_none) ); - } - */ - -} - -void TeamFortressViewport::UpdateHighlights() -{ - if (m_pCurrentCommandMenu) - m_pCurrentCommandMenu->MakeVisible( NULL ); -} - -void TeamFortressViewport::GetAllPlayersInfo( void ) -{ - for ( int i = 1; i <= MAX_PLAYERS; i++ ) - { - GetPlayerInfo( i, &g_PlayerInfoList[i] ); - - if ( g_PlayerInfoList[i].thisplayer ) - m_pScoreBoard->m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine - } -} - -void TeamFortressViewport::paintBackground() -{ - if (m_pScoreBoard) - { - int x, y; - getApp()->getCursorPos(x, y); - m_pScoreBoard->cursorMoved(x, y, m_pScoreBoard); - } - - // See if the command menu is visible and needs recalculating due to some external change - if ( g_iTeamNumber != m_iCurrentTeamNumber ) - { - UpdateCommandMenu( m_StandardMenu ); - - if ( m_pClassMenu ) - { - m_pClassMenu->Update(); - } - - m_iCurrentTeamNumber = g_iTeamNumber; - } - - if ( g_iPlayerClass != m_iCurrentPlayerClass ) - { - UpdateCommandMenu( m_StandardMenu ); - - m_iCurrentPlayerClass = g_iPlayerClass; - } - - // See if the Spectator Menu needs to be update - if ( ( g_iUser1 != m_iUser1 || g_iUser2 != m_iUser2 ) || - ( m_flSpectatorPanelLastUpdated < gHUD.m_flTime ) ) - { - UpdateSpectatorPanel(); - } - - // Update the Scoreboard, if it's visible - if ( m_pScoreBoard->isVisible() && (m_flScoreBoardLastUpdated < gHUD.m_flTime) ) - { - m_pScoreBoard->Update(); - m_flScoreBoardLastUpdated = gHUD.m_flTime + 0.5; - } - - int extents[4]; - getAbsExtents(extents[0],extents[1],extents[2],extents[3]); - VGui_ViewportPaintBackground(extents); -} - -//================================================================ -// Input Handler for Drag N Drop panels -void CDragNDropHandler::cursorMoved(int x,int y,Panel* panel) -{ - if(m_bDragging) - { - App::getInstance()->getCursorPos(x,y); - m_pPanel->setPos(m_iaDragOrgPos[0]+(x-m_iaDragStart[0]),m_iaDragOrgPos[1]+(y-m_iaDragStart[1])); - - if(m_pPanel->getParent()!=null) - { - m_pPanel->getParent()->repaint(); - } - } -} - -void CDragNDropHandler::mousePressed(MouseCode code,Panel* panel) -{ - int x,y; - App::getInstance()->getCursorPos(x,y); - m_bDragging=true; - m_iaDragStart[0]=x; - m_iaDragStart[1]=y; - m_pPanel->getPos(m_iaDragOrgPos[0],m_iaDragOrgPos[1]); - App::getInstance()->setMouseCapture(panel); - - m_pPanel->setDragged(m_bDragging); - m_pPanel->requestFocus(); -} - -void CDragNDropHandler::mouseReleased(MouseCode code,Panel* panel) -{ - m_bDragging=false; - m_pPanel->setDragged(m_bDragging); - App::getInstance()->setMouseCapture(null); -} - -//================================================================ -// Number Key Input -bool TeamFortressViewport::SlotInput( int iSlot ) -{ - // If there's a menu up, give it the input - if ( m_pCurrentMenu ) - return m_pCurrentMenu->SlotInput( iSlot ); - - if(gHUD.SlotInput(iSlot)) - { - return TRUE; - } - - return FALSE; -} - -// Direct Key Input -int TeamFortressViewport::KeyInput( int down, int keynum, const char *pszCurrentBinding ) -{ - /*@linux remove chat - if (m_chatPanel->isVisible()) - { - // Don't let the game handle the input while the user is typing in the - // chat window. - return 0; - } - - if (down && pszCurrentBinding && !strcmp(pszCurrentBinding, kcGlobalChat)) - { - m_chatPanel->setVisible(true); - m_chatPanel->requestFocus(); - m_chatPanel->SetChatMode(ChatPanel::chatModeAll); - return 0; - } - else if (down && pszCurrentBinding && !strcmp(pszCurrentBinding, kcTeamChat)) - { - m_chatPanel->setVisible(true); - m_chatPanel->requestFocus(); - m_chatPanel->SetChatMode(ChatPanel::chatModeTeam); - return 0; - }*/ - - // Open Text Window? - if (m_pCurrentMenu && gEngfuncs.Con_IsVisible() == false) - { - int iMenuID = m_pCurrentMenu->GetMenuID(); - - // Get number keys as Input for Team/Class menus - if (iMenuID == MENU_TEAM || iMenuID == MENU_CLASS) - { - // Escape gets you out of Team/Class menus if the Cancel button is visible - if ( keynum == K_ESCAPE ) - { - if ( (iMenuID == MENU_TEAM && g_iTeamNumber) || (iMenuID == MENU_CLASS && g_iPlayerClass) ) - { - HideTopMenu(); - return 0; - } - } - - for (int i = '0'; i <= '9'; i++) - { - if ( down && (keynum == i) ) - { - SlotInput( i - '0' ); - return 0; - } - } - } - - // Grab enter keys to close TextWindows - if ( down && (keynum == K_ENTER || keynum == K_KP_ENTER || keynum == K_SPACE || keynum == K_ESCAPE) ) - { - if ( iMenuID == MENU_MAPBRIEFING || iMenuID == MENU_INTRO || iMenuID == MENU_CLASSHELP ) - { - HideTopMenu(); - return 0; - } - } - - // Grab jump key on Team Menu as autoassign - if ( pszCurrentBinding && down && !strcmp(pszCurrentBinding, "+jump") ) - { - if (iMenuID == MENU_TEAM) - { - m_pTeamMenu->SlotInput(5); - return 0; - } - } - - } - - // if we're in a command menu, try hit one of it's buttons - if ( down && m_pCurrentCommandMenu ) - { - // Escape hides the command menu - if ( keynum == K_ESCAPE ) - { - HideCommandMenu(); - return 0; - } - - // only trap the number keys - if ( keynum >= '0' && keynum <= '9' ) - { - if ( m_pCurrentCommandMenu->KeyInput(keynum) ) - { - // a final command has been issued, so close the command menu - HideCommandMenu(); - } - - return 0; - } - } - - return 1; -} - -ChatPanel* TeamFortressViewport::GetChatPanel() -{ - return m_chatPanel; -} - -//================================================================ -// Message Handlers -int TeamFortressViewport::MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ) -{ - StringList team_names; - NetMsg_TeamNames( pbuf, iSize, team_names ); - - char team_translated[128]; - strcpy(team_translated, gHUD.m_TextMessage.LookupString(kTeamTitle)); - - char team_name_translated[MAX_TEAMNAME_SIZE]; - for( int team_number = 0; team_number < team_names.size(); team_number++ ) - { - gHUD.m_TextMessage.LocaliseTextString( team_names[team_number].c_str(), team_name_translated, MAX_TEAMNAME_SIZE ); - - team_names[team_number] = ""; - if( team_number != 0 && team_number < (m_iNumberOfTeams-1) ) //don't prepend information for spectators or team 0 - { - team_names[team_number] += team_translated; - team_names[team_number] += " "; - team_names[team_number] += MakeStringFromInt( team_number ); - team_names[team_number] += ": "; - } - team_names[team_number] += team_name_translated; - strcpy(m_sTeamNames[team_number], team_names[team_number].c_str()); - } - - return 1; -} - -int TeamFortressViewport::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) -{ - if (m_iGotAllMOTD) - m_szMOTD[0] = 0; - - string MOTD; - bool is_finished; - NetMsg_MOTD( pbuf, iSize, is_finished, MOTD ); - - m_iGotAllMOTD = is_finished ? 1 : 0; - - int roomInArray = (int)max( 0, sizeof(m_szMOTD) - strlen(m_szMOTD) - 1); - - strncat( m_szMOTD, MOTD.c_str(), roomInArray ); - m_szMOTD[ sizeof(m_szMOTD)-1 ] = '\0'; - - return 1; -} - -int TeamFortressViewport::MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) -{ - string name; - NetMsg_ServerName( pbuf, iSize, name ); - - memset(this->m_szServerName, 0, MAX_SERVERNAME_LENGTH); - - strncpy( m_szServerName, name.c_str(), MAX_SERVERNAME_LENGTH ); - - return 1; -} - -int TeamFortressViewport::MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) -{ - ScoreInfo info; - NetMsg_ScoreInfo( pbuf, iSize, info ); - - if ( info.player_index > 0 && info.player_index <= MAX_PLAYERS ) - { - // Update score, but show + or - indicator on scoreboard when it changes - g_PlayerExtraInfo[info.player_index].lastScore = g_PlayerExtraInfo[info.player_index].score; - g_PlayerExtraInfo[info.player_index].score = info.score; - if(g_PlayerExtraInfo[info.player_index].score != g_PlayerExtraInfo[info.player_index].lastScore) - { - g_PlayerExtraInfo[info.player_index].timeOfLastScoreChange = gHUD.GetTimeOfLastUpdate(); - } - - // Update other info - g_PlayerExtraInfo[info.player_index].frags = info.frags; - g_PlayerExtraInfo[info.player_index].deaths = info.deaths; - g_PlayerExtraInfo[info.player_index].extra = info.extra; - g_PlayerExtraInfo[info.player_index].playerclass = info.player_class; - // : 0001073 - g_PlayerExtraInfo[info.player_index].auth = info.auth; - g_PlayerExtraInfo[info.player_index].teamnumber = max( info.team, 0 ); - g_PlayerExtraInfo[info.player_index].health = info.health; - - // Icon is now handled through the ProfileInfo update - - UpdateOnPlayerInfo(); - } - - return 1; -} - -// Message handler for TeamScore message -// accepts three values: -// string: team name -// short: teams kills -// short: teams deaths -// if this message is never received, then scores will simply be the combined totals of the players. -int TeamFortressViewport::MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) -{ - string team_name; - int score, reset; - NetMsg_TeamScore( pbuf, iSize, team_name, score, reset); - - // find the team matching the name - int i; - for ( i = 1; i <= m_pScoreBoard->m_iNumTeams; i++ ) - { - if ( !stricmp( team_name.c_str(), g_TeamInfo[i].name ) ) - break; - } - - if ( i > m_pScoreBoard->m_iNumTeams ) - return 1; - - // use this new score data instead of combined player scores - if ( reset ) - g_TeamInfo[i]. scores_overriden = FALSE; - else - g_TeamInfo[i]. scores_overriden = TRUE; - - g_TeamInfo[i].score = score; - - return 1; -} - -// Message handler for TeamInfo message -// accepts two values: -// byte: client number -// string: client team name -int TeamFortressViewport::MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) -{ - if (!m_pScoreBoard) - return 1; - - int player_index; - string team_id; - NetMsg_TeamInfo( pbuf, iSize, player_index, team_id ); - - if ( player_index > 0 && player_index <= MAX_PLAYERS ) - { - // set the players team - strncpy( g_PlayerExtraInfo[player_index].teamname, team_id.c_str(), MAX_TEAM_NAME ); - } - - // rebuild the list of teams - m_pScoreBoard->RebuildTeams(); - - return 1; -} - -void TeamFortressViewport::DeathMsg( int killer, int victim ) -{ - m_pScoreBoard->DeathMsg(killer,victim); -} +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Client DLL VGUI Viewport +// +// $Workfile: $ +// $Date: 2002/10/28 20:32:17 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_TeamFortressViewport.cpp,v $ +// Revision 1.12 2002/10/28 20:32:17 Flayra +// - Don't display disconcerting error message +// +// Revision 1.11 2002/10/16 00:37:33 Flayra +// - Added support for authentication in scoreboard +// +// Revision 1.10 2002/07/08 16:15:13 Flayra +// - Refactored team color management +// +// Revision 1.9 2002/04/16 19:32:07 Charlie +// - Removed crappy way of handling pop-up menu changes, removed pressing enter to go back to RR (was getting in way of chat, now just use "readyroom" - F4 -) +// +// Revision 1.8 2002/02/25 20:35:41 Charlie +// - Added hotgrouping of units and buildings, moving to units or buildings when double-tapping, and camera tracking +// +// Revision 1.7 2002/01/30 18:34:32 Charlie +// - Fixed doubled-cursor problem with scoreboard (only show sprite cursor, not Windows cursor) +// +// Revision 1.6 2001/11/13 17:51:02 Charlie +// - Increased max teams, changed team colors (allow aliens vs. aliens and fronts vs. fronts), general scoreboard support +// +// Revision 1.5 2001/10/22 19:26:32 Charlie +// - Changes to make scoreboard work in commander mode +// +// Revision 1.4 2001/09/13 15:01:02 Charlie +// - Merging with 1108 +// +// Revision 1.3 2001/06/02 14:26:47 charlie +// - Commented out UpdateCursorState because it was causing problems (look into this) +// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie +// - HL1108 +// +// Revision 1.2 2001/04/09 19:31:35 charlie +// - Quick hacky tests to try out menus for team/class picking...yuck +// +// Revision 1.1.1.1 2000/06/17 14:12:45 charlie +// Final version of new HL SDK. May not compile. +// Previous versions of my MSVC project files and utility .bat files. +// This is my starting point; there is no mod-specific code in here. +// +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "common/cvardef.h" +#include "common/usercmd.h" +#include "common/const.h" +#include "camera.h" +#include "in_defs.h" +#include "pm_shared/pm_shared.h" +#include "../engine/keydefs.h" +#include "demo.h" +#include "common/demo_api.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" +#include "vgui_ScorePanel.h" +#include "vgui_SpectatorPanel.h" +#include "vgui_loadtga.h" +#include "mod/AvHConstants.h" +#include "mod/AvHTitles.h" +#include "mod/AvHPieMenuHandler.h" +#include "mod/AvHSharedUtil.h" +#include "mod/AvHCommandConstants.h" +#include "ui/ChatPanel.h" +#include "mod/AvHNetworkMessages.h" +#include "util/STLUtil.h" + +extern int g_iVisibleMouse; +class CCommandMenu; +int g_iPlayerClass; +int g_iTeamNumber; +int g_iUser1; +int g_iUser2; +int g_iUser3; + +// Scoreboard positions +#define SBOARD_INDENT_X XRES(75) +#define SBOARD_INDENT_Y YRES(40) + +// low-res scoreboard indents +#define SBOARD_INDENT_X_512 30 +#define SBOARD_INDENT_Y_512 30 + +#define SBOARD_INDENT_X_400 0 +#define SBOARD_INDENT_Y_400 20 + + +const int kPlayerMenuWidth = 200; + +void IN_ResetMouse( void ); +extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ); +extern float * GetClientColor( int clientIndex ); + +using namespace vgui; + + +class PlayerButton : public CommandButton +{ + +public: + + PlayerButton(int inPlayerNumber, const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat ) + : CommandButton(text, x, y, wide, tall, bNoHighlight, bFlat) + { + mPlayerNumber = inPlayerNumber; + } + + void paint() + { + + // Set the color of the button based on the team color (or red if the player is dead). + + int theTeamNumber = g_PlayerExtraInfo[mPlayerNumber].teamnumber % iNumberOfTeamColors; + int r, g, b; + + switch (g_PlayerExtraInfo[mPlayerNumber].playerclass) + { + + case PLAYERCLASS_DEAD_MARINE: + case PLAYERCLASS_DEAD_ALIEN: + case PLAYERCLASS_REINFORCING: + r = 255 / gHUD.GetGammaSlope(); + g = 0 / gHUD.GetGammaSlope(); + b = 0 / gHUD.GetGammaSlope(); + break; + + default: + r = kTeamColors[theTeamNumber][0] / gHUD.GetGammaSlope(); + g = kTeamColors[theTeamNumber][1] / gHUD.GetGammaSlope(); + b = kTeamColors[theTeamNumber][2] / gHUD.GetGammaSlope(); + break; + + } + + setFgColor(r, g, b, 0); + + Button::paint(); + + } + + void paintBackground() + { + if ( isArmed() ) + { + // Orange Border + drawSetColor(255, 255, 255, 0); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + +private: + + int mPlayerNumber; + +}; + + +// Used for Class specific buttons +char *sTFClasses[] = +{ + "", + "SCOUT", + "SNIPER", + "SOLDIER", + "DEMOMAN", + "MEDIC", + "HWGUY", + "PYRO", + "SPY", + "ENGINEER", + "CIVILIAN", +}; + +char *sLocalisedClasses[] = +{ + "#Civilian", + "#Scout", + "#Sniper", + "#Soldier", + "#Demoman", + "#Medic", + "#HWGuy", + "#Pyro", + "#Spy", + "#Engineer", + "#Random", + "#Civilian", +}; + +char *sTFClassSelection[] = +{ + "civilian", + "scout", + "sniper", + "soldier", + "demoman", + "medic", + "hwguy", + "pyro", + "spy", + "engineer", + "randompc", + "civilian", +}; + +const int kNumOptionsButtons = 4; + +char* kOptionsButtons[kNumOptionsButtons*2] = +{ + "#Menu_Marine1Team", "jointeamone", + "#Menu_Alien1Team", "jointeamtwo", + "#Menu_ReadyRoom", "readyroom", + "#Menu_LeaveGame", "escape", +}; + +int iBuildingCosts[] = +{ + BUILD_COST_DISPENSER, + BUILD_COST_SENTRYGUN +}; + +// This maps class numbers to the Invalid Class bit. +// This is needed for backwards compatability in maps that were finished before +// all the classes were in TF. Hence the wacky sequence. +int sTFValidClassInts[] = +{ + 0, + TF_ILL_SCOUT, + TF_ILL_SNIPER, + TF_ILL_SOLDIER, + TF_ILL_DEMOMAN, + TF_ILL_MEDIC, + TF_ILL_HVYWEP, + TF_ILL_PYRO, + TF_ILL_SPY, + TF_ILL_ENGINEER, + TF_ILL_RANDOMPC, +}; + +// Get the name of TGA file, based on GameDir +char* GetVGUITGAName(const char *pszName) +{ + int i; + char sz[256]; + static char gd[256]; + const char *gamedir; + + if (ScreenWidth() < 640) + i = 320; + else + i = 640; + sprintf(sz, pszName, i); + + gamedir = gEngfuncs.pfnGetGameDirectory(); + sprintf(gd, "%s/gfx/vgui/%s.tga",gamedir,sz); + + return gd; +} + +//================================================================ +// COMMAND MENU +//================================================================ +void CCommandMenu::AddButton( CommandButton *pButton ) +{ + if (m_iButtons >= MAX_BUTTONS) + return; + + m_aButtons[m_iButtons] = pButton; + m_iButtons++; + pButton->setParent( this ); + pButton->setFont( Scheme::sf_primary3 ); + + // give the button a default key binding + if ( m_iButtons < 10 ) + { + pButton->setBoundKey( m_iButtons + '0' ); + } + else if ( m_iButtons == 10 ) + { + pButton->setBoundKey( '0' ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Tries to find a button that has a key bound to the input, and +// presses the button if found +// Input : keyNum - the character number of the input key +// Output : Returns true if the command menu should close, false otherwise +//----------------------------------------------------------------------------- +bool CCommandMenu::KeyInput( int keyNum ) +{ + // loop through all our buttons looking for one bound to keyNum + for ( int i = 0; i < m_iButtons; i++ ) + { + if ( !m_aButtons[i]->IsNotValid() ) + { + if ( m_aButtons[i]->getBoundKey() == keyNum ) + { + // hit the button + if ( m_aButtons[i]->GetSubMenu() ) + { + // open the sub menu + gViewPort->SetCurrentCommandMenu( m_aButtons[i]->GetSubMenu() ); + return false; + } + else + { + // run the bound command + m_aButtons[i]->fireActionSignal(); + return true; + } + } + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: clears the current menus buttons of any armed (highlighted) +// state, and all their sub buttons +//----------------------------------------------------------------------------- +void CCommandMenu::ClearButtonsOfArmedState( void ) +{ + for ( int i = 0; i < GetNumButtons(); i++ ) + { + m_aButtons[i]->setArmed( false ); + + if ( m_aButtons[i]->GetSubMenu() ) + { + m_aButtons[i]->GetSubMenu()->ClearButtonsOfArmedState(); + } + } +} + +void CCommandMenu::RemoveAllButtons() +{ + + for ( int i = 0; i < GetNumButtons(); i++ ) + { + + if ( m_aButtons[i]->GetSubMenu() ) + { + m_aButtons[i]->GetSubMenu()->RemoveAllButtons(); + } + + removeChild(m_aButtons[i]); + + delete m_aButtons[i]; + m_aButtons[i] = NULL; + + } + + m_iButtons = 0; + +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSubMenu - +// Output : CommandButton +//----------------------------------------------------------------------------- +CommandButton *CCommandMenu::FindButtonWithSubmenu( CCommandMenu *pSubMenu ) +{ + for ( int i = 0; i < GetNumButtons(); i++ ) + { + if ( m_aButtons[i]->GetSubMenu() == pSubMenu ) + return m_aButtons[i]; + } + + return NULL; +} + +// Recalculate the visible buttons +bool CCommandMenu::RecalculateVisibles( int iYOffset, bool bHideAll ) +{ + int i, iCurrentY = 0; + int iVisibleButtons = 0; + + // Cycle through all the buttons in this menu, and see which will be visible + for (i = 0; i < m_iButtons; i++) + { + int iClass = m_aButtons[i]->GetPlayerClass(); + if ( (iClass && iClass != g_iPlayerClass ) || ( m_aButtons[i]->IsNotValid() ) || bHideAll ) + { + m_aButtons[i]->setVisible( false ); + if ( m_aButtons[i]->GetSubMenu() != NULL ) + { + (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( 0, true ); + } + } + else + { + // If it's got a submenu, force it to check visibilities + if ( m_aButtons[i]->GetSubMenu() != NULL ) + { + if ( !(m_aButtons[i]->GetSubMenu())->RecalculateVisibles( 0 , false ) ) + { + // The submenu had no visible buttons, so don't display this button + m_aButtons[i]->setVisible( false ); + continue; + } + } + + m_aButtons[i]->setVisible( true ); + iVisibleButtons++; + } + } + + // Set Size + setSize( _size[0], (iVisibleButtons * (m_flButtonSizeY-1)) + 1 ); + + if ( iYOffset ) + { + m_iYOffset = iYOffset; + } + + for (i = 0; i < m_iButtons; i++) + { + if ( m_aButtons[i]->isVisible() ) + { + if ( m_aButtons[i]->GetSubMenu() != NULL ) + (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( iCurrentY + m_iYOffset, false ); + + + // Make sure it's at the right Y position + // m_aButtons[i]->getPos( iXPos, iYPos ); + + if ( m_iDirection ) + { + m_aButtons[i]->setPos( 0, (iVisibleButtons-1) * (m_flButtonSizeY-1) - iCurrentY ); + } + else + { + m_aButtons[i]->setPos( 0, iCurrentY ); + } + + iCurrentY += (m_flButtonSizeY-1); + } + } + + return iVisibleButtons?true:false; +} + +// Make sure all submenus can fit on the screen +void CCommandMenu::RecalculatePositions( int iYOffset ) +{ + int iTop; + int iAdjust = 0; + + m_iYOffset+= iYOffset; + if ( m_iDirection ) + iTop = ScreenHeight() - (m_iYOffset + _size[1] ); + else + iTop = m_iYOffset; + + if ( iTop < 0 ) + iTop = 0; + // Calculate if this is going to fit onscreen, and shuffle it up if it won't + int iBottom = iTop + _size[1]; + if ( iBottom > ScreenHeight() ) + { + // Move in increments of button sizes + while (iAdjust < (iBottom - ScreenHeight())) + { + iAdjust += m_flButtonSizeY - 1; + } + iTop -= iAdjust; + + // Make sure it doesn't move off the top of the screen (the menu's too big to fit it all) + if ( iTop < 0 ) + { + iAdjust -= (0 - iTop); + iTop = 0; + } + } + + setPos( _pos[0], iTop ); + // We need to force all menus below this one to update their positions now, because they + // might have submenus riding off buttons in this menu that have just shifted. + for (int i = 0; i < m_iButtons; i++) + m_aButtons[i]->UpdateSubMenus( iAdjust ); +} + + +// Make this menu and all menus above it in the chain visible +void CCommandMenu::MakeVisible( CCommandMenu *pChildMenu ) +{ + setVisible(true); + if (m_pParentMenu) + m_pParentMenu->MakeVisible( this ); +} + +//================================================================ +// CreateSubMenu +CCommandMenu *TeamFortressViewport::CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu, int iYOffset, int iXOffset ) +{ + int iXPos = 0; + int iYPos = 0; + int iWide = CMENU_SIZE_X; + int iTall = 0; + int iDirection = 0; + + if (pParentMenu) + { + iXPos = m_pCurrentCommandMenu->GetXOffset() + (CMENU_SIZE_X - 1) + iXOffset; + iYPos = m_pCurrentCommandMenu->GetYOffset() + iYOffset; + iDirection = pParentMenu->GetDirection(); + } + + CCommandMenu *pMenu = new CCommandMenu(pParentMenu, iDirection, iXPos, iYPos, iWide, iTall ); + pMenu->setParent(this); + pButton->AddSubMenu( pMenu ); + pButton->setFont( Scheme::sf_primary3 ); + pMenu->m_flButtonSizeY = m_pCurrentCommandMenu->m_flButtonSizeY; + + // Create the Submenu-open signal + InputSignal *pISignal = new CMenuHandler_PopupSubMenuInput(pButton, pMenu); + pButton->addInputSignal(pISignal); + + // Put a > to show it's a submenu + CImageLabel *pLabel = new CImageLabel( "arrow", CMENU_SIZE_X - SUBMENU_SIZE_X, SUBMENU_SIZE_Y ); + pLabel->setParent(pButton); + pLabel->addInputSignal(pISignal); + + // Reposition + pLabel->getPos( iXPos, iYPos ); + pLabel->setPos( CMENU_SIZE_X - pLabel->getImageWide(), (BUTTON_SIZE_Y - pLabel->getImageTall()) / 2 ); + + // Create the mouse off signal for the Label too + if (!pButton->m_bNoHighlight) + pLabel->addInputSignal( new CHandler_CommandButtonHighlight(pButton) ); + + return pMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: Makes sure the memory allocated for TeamFortressViewport is nulled out +// Input : stAllocateBlock - +// Output : void * +//----------------------------------------------------------------------------- +void *TeamFortressViewport::operator new( size_t stAllocateBlock ) +{ +// void *mem = Panel::operator new( stAllocateBlock ); + void *mem = ::operator new( stAllocateBlock ); + memset( mem, 0, stAllocateBlock ); + return mem; +} + +//----------------------------------------------------------------------------- +// Purpose: InputSignal handler for the main viewport +//----------------------------------------------------------------------------- +class CViewPortInputHandler : public InputSignal +{ +public: + bool bPressed; + + CViewPortInputHandler() + { + } + + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) + { + if ( code != MOUSE_LEFT ) + { + // send a message to close the command menu + // this needs to be a message, since a direct call screws the timing + gEngfuncs.pfnClientCmd( "ForceCloseCommandMenu\n" ); + } + } + virtual void mouseReleased(MouseCode code,Panel* panel) + { + } + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} +}; + + +//================================================================ +TeamFortressViewport::TeamFortressViewport(int x,int y,int wide,int tall) : Panel(x,y,wide,tall), m_SchemeManager(wide,tall) +{ + gViewPort = this; + m_iInitialized = false; + m_pTeamMenu = NULL; + m_pClassMenu = NULL; + m_pScoreBoard = NULL; + mOptionsScreen = NULL; + mOptionsButtons = new CommandButton*[kNumOptionsButtons]; + + m_pSpectatorPanel = NULL; + m_pCurrentMenu = NULL; + m_pCurrentCommandMenu = NULL; + + Initialize(); + addInputSignal( new CViewPortInputHandler ); + + int r, g, b, a; + + Scheme* pScheme = App::getInstance()->getScheme(); + + // primary text color + // Get the colors + //!! two different types of scheme here, need to integrate + SchemeHandle_t hPrimaryScheme = m_SchemeManager.getSchemeHandle( "Primary Button Text" ); + { + // font + pScheme->setFont( Scheme::sf_primary1, m_SchemeManager.getFont(hPrimaryScheme) ); + + // text color + m_SchemeManager.getFgColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary1, r, g, b, a ); // sc_primary1 is non-transparent orange + + // background color (transparent black) + m_SchemeManager.getBgColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary3, r, g, b, a ); + + // armed foreground color + m_SchemeManager.getFgArmedColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_secondary2, r, g, b, a ); + + // armed background color + m_SchemeManager.getBgArmedColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary2, r, g, b, a ); + + //!! need to get this color from scheme file + // used for orange borders around buttons + m_SchemeManager.getBorderColor( hPrimaryScheme, r, g, b, a ); + // pScheme->setColor(Scheme::sc_secondary1, r, g, b, a ); + pScheme->setColor(Scheme::sc_secondary1, 255*0.7, 170*0.7, 0, 0); + } + + // Change the second primary font (used in the scoreboard) + SchemeHandle_t hScoreboardScheme = m_SchemeManager.getSchemeHandle( "Scoreboard Text" ); + { + pScheme->setFont(Scheme::sf_primary2, m_SchemeManager.getFont(hScoreboardScheme) ); + } + + // Change the third primary font (used in command menu) + SchemeHandle_t hCommandMenuScheme = m_SchemeManager.getSchemeHandle( "CommandMenu Text" ); + { + pScheme->setFont(Scheme::sf_primary3, m_SchemeManager.getFont(hCommandMenuScheme) ); + } + + App::getInstance()->setScheme(pScheme); + + // VGUI MENUS + CreateTeamMenu(); + CreateClassMenu(); + CreateSpectatorMenu(); + CreateScoreBoard(); + CreateOptionsMenu(); + // Init command menus + m_iNumMenus = 0; + m_iCurrentTeamNumber = m_iUser1 = m_iUser2 = m_iUser3 = 0; + + m_StandardMenu = CreateCommandMenu("commandmenu.txt", 0, CMENU_TOP, false, CMENU_SIZE_X, BUTTON_SIZE_Y, 0 ); + m_SpectatorOptionsMenu = CreateCommandMenu("spectatormenu.txt", 1, YRES(32), true, CMENU_SIZE_X, BUTTON_SIZE_Y / 2, 0 ); // above bottom bar, flat design + m_SpectatorCameraMenu = CreateCommandMenu("spectcammenu.txt", 1, YRES(32), true, XRES( 200 ), BUTTON_SIZE_Y / 2, ScreenWidth() - ( XRES ( 200 ) + 15 ) ); // above bottom bar, flat design + + CreatePlayerMenu(); + + CreateServerBrowser(); + + // : 0000989: + // m_chatPanel = new ChatPanel(10, (ScreenHeight() * 0.75 - 30) / 2, ScreenWidth() - 20, 30); + m_chatPanel = new ChatPanel(10, ScreenHeight() * 0.57f - 30, ScreenWidth() - 20, 30); + // : + m_chatPanel->setParent(this); + m_chatPanel->setVisible(false); + +} + +//----------------------------------------------------------------------------- +// Purpose: Called everytime a new level is started. Viewport clears out it's data. +//----------------------------------------------------------------------------- +void TeamFortressViewport::Initialize( void ) +{ + // Force each menu to Initialize + if (m_pTeamMenu) + { + m_pTeamMenu->Initialize(); + } + if (m_pClassMenu) + { + m_pClassMenu->Initialize(); + } + if (m_pScoreBoard) + { + m_pScoreBoard->Initialize(); + HideScoreBoard(); + } + if (m_pSpectatorPanel) + { + // Spectator menu doesn't need initializing + m_pSpectatorPanel->setVisible( false ); + } + + // Make sure all menus are hidden + HideVGUIMenu(); + HideCommandMenu(); + + // Clear out some data + m_iGotAllMOTD = true; + m_iRandomPC = false; + m_flScoreBoardLastUpdated = 0; + m_flSpectatorPanelLastUpdated = 0; + + // reset player info + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + memset(this->m_sMapName, 0, MAX_MAPNAME_LENGTH); + memset(this->m_szServerName, 0, MAX_SERVERNAME_LENGTH); + for (int i = 0; i < 5; i++) + { + m_iValidClasses[i] = 0; + strcpy(m_sTeamNames[i], ""); + } + + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::scu_none) ); +} + +class CException; +//----------------------------------------------------------------------------- +// Purpose: Read the Command Menu structure from the txt file and create the menu. +// Returns Index of menu in m_pCommandMenus +//----------------------------------------------------------------------------- +int TeamFortressViewport::CreateCommandMenu( char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ) +{ + // COMMAND MENU + // Create the root of this new Command Menu + + int newIndex = m_iNumMenus; + + m_pCommandMenus[newIndex] = new CCommandMenu(NULL, direction, xOffset, yOffset, flButtonSizeX, 300); // This will be resized once we know how many items are in it + m_pCommandMenus[newIndex]->setParent(this); + m_pCommandMenus[newIndex]->setVisible(false); + m_pCommandMenus[newIndex]->m_flButtonSizeY = flButtonSizeY; + m_pCommandMenus[newIndex]->m_iSpectCmdMenu = direction; + + m_iNumMenus++; + + // Read Command Menu from the txt file + char token[1024]; + char *pfile = (char*)gEngfuncs.COM_LoadFile( menuFile, 5, NULL); + if (!pfile) + { + gEngfuncs.Con_DPrintf( "Unable to open %s\n", menuFile); + SetCurrentCommandMenu( NULL ); + return newIndex; + } + +#ifdef _WIN32 +try +{ +#endif + // First, read in the localisation strings + + // Detpack strings + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For5Seconds", m_sDetpackStrings[0], MAX_BUTTON_SIZE ); + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For20Seconds", m_sDetpackStrings[1], MAX_BUTTON_SIZE ); + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For50Seconds", m_sDetpackStrings[2], MAX_BUTTON_SIZE ); + + // Now start parsing the menu structure + m_pCurrentCommandMenu = m_pCommandMenus[newIndex]; + char szLastButtonText[32] = "file start"; + pfile = gEngfuncs.COM_ParseFile(pfile, token); + while ( ( strlen ( token ) > 0 ) && ( m_iNumMenus < MAX_MENUS ) ) + { + // Keep looping until we hit the end of this menu + while ( token[0] != '}' && ( strlen( token ) > 0 ) ) + { + char cText[32] = ""; + char cBoundKey[32] = ""; + char cCustom[32] = ""; + static const int cCommandLength = 128; + char cCommand[cCommandLength] = ""; + char szMap[MAX_MAPNAME] = ""; + int iPlayerClass = 0; + int iCustom = false; + int iTeamOnly = -1; + int iToggle = 0; + int iButtonY; + bool bGetExtraToken = true; + CommandButton *pButton = NULL; + + // We should never be here without a Command Menu + if (!m_pCurrentCommandMenu) + { + gEngfuncs.Con_Printf("Error in %s file after '%s'.\n",menuFile, szLastButtonText ); + m_iInitialized = false; + return newIndex; + } + + // token should already be the bound key, or the custom name + strncpy( cCustom, token, 32 ); + cCustom[31] = '\0'; + + // See if it's a custom button + if (!strcmp(cCustom, "CUSTOM") ) + { + iCustom = true; + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + // See if it's a map + else if (!strcmp(cCustom, "MAP") ) + { + // Get the mapname + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( szMap, token, MAX_MAPNAME ); + szMap[MAX_MAPNAME-1] = '\0'; + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else if ( !strncmp(cCustom, "TEAM", 4) ) // TEAM1, TEAM2, TEAM3, TEAM4 + { + // make it a team only button + iTeamOnly = atoi( cCustom + 4 ); + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else if ( !strncmp(cCustom, "TOGGLE", 6) ) + { + iToggle = true; + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else + { + // See if it's a Class + for (int i = 1; i <= PC_ENGINEER; i++) + { + if ( !strcmp(token, sTFClasses[i]) ) + { + // Save it off + iPlayerClass = i; + + // Get the button text + pfile = gEngfuncs.COM_ParseFile(pfile, token); + break; + } + } + } + + // Get the button bound key + strncpy( cBoundKey, token, 32 ); + cText[31] = '\0'; + + // Get the button text + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( cText, token, 32 ); + cText[31] = '\0'; + + // save off the last button text we've come across (for error reporting) + strcpy( szLastButtonText, cText ); + + // Get the button command + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( cCommand, token, cCommandLength ); + cCommand[cCommandLength - 1] = '\0'; + + iButtonY = (BUTTON_SIZE_Y-1) * m_pCurrentCommandMenu->GetNumButtons(); + // Custom button handling + if ( iCustom ) + { + pButton = CreateCustomButton( cText, cCommand, iButtonY ); + + // Get the next token to see if we're a menu + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if ( token[0] == '{' ) + { + strcpy( cCommand, token ); + } + else + { + bGetExtraToken = false; + } + } + else if ( szMap[0] != '\0' ) + { + // create a map button + pButton = new MapButton(szMap, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY ); + } + else if ( iTeamOnly != -1) + { + // button that only shows up if the player is on team iTeamOnly + pButton = new TeamOnlyCommandButton( iTeamOnly, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + } + else if ( iToggle && direction == 0 ) + { + pButton = new ToggleCommandButton( cCommand, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + } + else if ( direction == 1 ) + { + if ( iToggle ) + pButton = new SpectToggleButton( cCommand, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + else + pButton = new SpectButton( iPlayerClass, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY ); + } + else + { + // normal button + pButton = new CommandButton( iPlayerClass, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + } + + // add the button into the command menu + if ( pButton ) + { + m_pCurrentCommandMenu->AddButton( pButton ); + pButton->setBoundKey( cBoundKey[0] ); + pButton->setParentMenu( m_pCurrentCommandMenu ); + + // Override font in CommandMenu + pButton->setFont( Scheme::sf_primary3 ); + } + + // Find out if it's a submenu or a button we're dealing with + if ( cCommand[0] == '{' ) + { + if ( m_iNumMenus >= MAX_MENUS ) + { + gEngfuncs.Con_Printf( "Too many menus in %s past '%s'\n",menuFile, szLastButtonText ); + } + else + { + // Create the menu + m_pCommandMenus[m_iNumMenus] = CreateSubMenu(pButton, m_pCurrentCommandMenu, iButtonY ); + m_pCurrentCommandMenu = m_pCommandMenus[m_iNumMenus]; + m_iNumMenus++; + } + } + else if ( !iCustom ) + { + // Create the button and attach it to the current menu + if ( iToggle ) + pButton->addActionSignal(new CMenuHandler_ToggleCvar(cCommand)); + else + pButton->addActionSignal(new CMenuHandler_StringCommand(cCommand)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + + // Get the next token + if ( bGetExtraToken ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + } + + // Move back up a menu + m_pCurrentCommandMenu = m_pCurrentCommandMenu->GetParentMenu(); + + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } +#ifdef _WIN32 +} +catch( CException *e ) +{ + e; + //e->Delete(); + e = NULL; + m_iInitialized = false; + return newIndex; +} +#endif + + SetCurrentMenu( NULL ); + SetCurrentCommandMenu( NULL ); + gEngfuncs.COM_FreeFile( pfile ); + + m_iInitialized = true; + return newIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: Creates all the class choices under a spy's disguise menus, and +// maps a command to them +// Output : CCommandMenu +//----------------------------------------------------------------------------- +CCommandMenu *TeamFortressViewport::CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset ) +{ + // create the submenu, under which the class choices will be listed + CCommandMenu *pMenu = CreateSubMenu( pButton, pParentMenu, iYOffset, iXOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // create the class choice buttons + for ( int i = PC_SCOUT; i <= PC_ENGINEER; i++ ) + { + CommandButton *pDisguiseButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); + + char sz[256]; + sprintf(sz, "%s %d", commandText, i ); + pDisguiseButton->addActionSignal(new CMenuHandler_StringCommand(sz)); + + pMenu->AddButton( pDisguiseButton ); + } + + return pMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pButtonText - +// *pButtonName - +// Output : CommandButton +//----------------------------------------------------------------------------- +CommandButton *TeamFortressViewport::CreateCustomButton( char *pButtonText, char *pButtonName, int iYOffset ) +{ + CommandButton *pButton = NULL; + CCommandMenu *pMenu = NULL; + + // ChangeTeam + if ( !strcmp( pButtonName, "!CHANGETEAM" ) ) + { + // ChangeTeam Submenu + pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + + // Create the submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // ChangeTeam buttons + for (int i = 0; i < 4; i++) + { + char sz[256]; + sprintf(sz, "jointeam %d", i+1); + m_pTeamButtons[i] = new TeamButton(i+1, "teamname", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pTeamButtons[i]->addActionSignal(new CMenuHandler_StringCommandWatch( sz )); + pMenu->AddButton( m_pTeamButtons[i] ); + } + + // Auto Assign button + m_pTeamButtons[4] = new TeamButton(5, gHUD.m_TextMessage.BufferedLocaliseTextString( "#Team_AutoAssign" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pTeamButtons[4]->addActionSignal(new CMenuHandler_StringCommand( "jointeam 5" )); + pMenu->AddButton( m_pTeamButtons[4] ); + + // Spectate button + m_pTeamButtons[5] = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + m_pTeamButtons[5]->addActionSignal(new CMenuHandler_StringCommand( "spectate" )); + pMenu->AddButton( m_pTeamButtons[5] ); + } + // ChangeClass + else if ( !strcmp( pButtonName, "!CHANGECLASS" ) ) + { + // Create the Change class menu + pButton = new ClassButton(-1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + + // ChangeClass Submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + for (int i = PC_SCOUT; i <= PC_RANDOM; i++ ) + { + char sz[256]; + + // ChangeClass buttons + CHudTextMessage::LocaliseTextString( sLocalisedClasses[i], sz, 256 ); + ClassButton *pClassButton = new ClassButton( i, sz, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + + sprintf(sz, "%s", sTFClassSelection[i]); + pClassButton->addActionSignal(new CMenuHandler_StringCommandClassSelect(sz)); + pMenu->AddButton( pClassButton ); + } + } + // Map Briefing + else if ( !strcmp( pButtonName, "!MAPBRIEFING" ) ) + { + pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_MAPBRIEFING)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Class Descriptions + else if ( !strcmp( pButtonName, "!CLASSDESC" ) ) + { + pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_CLASSHELP)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!SERVERINFO" ) ) + { + pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_INTRO)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Spy abilities + else if ( !strcmp( pButtonName, "!SPY" ) ) + { + pButton = new DisguiseButton( 0, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); + } + // Feign + else if ( !strcmp( pButtonName, "!FEIGN" ) ) + { + pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Feign Silently + else if ( !strcmp( pButtonName, "!FEIGNSILENT" ) ) + { + pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "sfeign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Stop Feigning + else if ( !strcmp( pButtonName, "!FEIGNSTOP" ) ) + { + pButton = new FeignButton(TRUE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Disguise + else if ( !strcmp( pButtonName, "!DISGUISEENEMY" ) ) + { + // Create the disguise enemy button, which active only if there are 2 teams + pButton = new DisguiseButton(DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_enemy", iYOffset); + } + else if ( !strcmp( pButtonName, "!DISGUISEFRIENDLY" ) ) + { + // Create the disguise friendly button, which active only if there are 1 or 2 teams + pButton = new DisguiseButton(DISGUISE_TEAM1 | DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_friendly", iYOffset ); + } + else if ( !strcmp( pButtonName, "!DISGUISE" ) ) + { + // Create the Disguise button + pButton = new DisguiseButton( DISGUISE_TEAM3 | DISGUISE_TEAM4, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CCommandMenu *pDisguiseMenu = CreateSubMenu( pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pDisguiseMenu; + m_iNumMenus++; + + // Disguise Enemy submenu buttons + for ( int i = 1; i <= 4; i++ ) + { + // only show the 4th disguise button if we have 4 teams + m_pDisguiseButtons[i] = new DisguiseButton( ((i < 4) ? DISGUISE_TEAM3 : 0) | DISGUISE_TEAM4, "Disguise", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + + pDisguiseMenu->AddButton( m_pDisguiseButtons[i] ); + m_pDisguiseButtons[i]->setParentMenu( pDisguiseMenu ); + + char sz[256]; + sprintf( sz, "disguise %d", i ); + CreateDisguiseSubmenu( m_pDisguiseButtons[i], pDisguiseMenu, sz, iYOffset, CMENU_SIZE_X - 1 ); + } + } + // Start setting a Detpack + else if ( !strcmp( pButtonName, "!DETPACKSTART" ) ) + { + // Detpack Submenu + pButton = new DetpackButton(2, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + + // Create the submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // Set detpack buttons + CommandButton *pDetButton; + pDetButton = new CommandButton(m_sDetpackStrings[0], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 5")); + pMenu->AddButton( pDetButton ); + pDetButton = new CommandButton(m_sDetpackStrings[1], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 20")); + pMenu->AddButton( pDetButton ); + pDetButton = new CommandButton(m_sDetpackStrings[2], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 50")); + pMenu->AddButton( pDetButton ); + } + // Stop setting a Detpack + else if ( !strcmp( pButtonName, "!DETPACKSTOP" ) ) + { + pButton = new DetpackButton(1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "detstop" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Engineer building + else if ( !strcmp( pButtonName, "!BUILD" ) ) + { + // only appears if the player is an engineer, and either they have built something or have enough metal to build + pButton = new BuildButton( BUILDSTATE_BASE, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + } + else if ( !strcmp( pButtonName, "!BUILDSENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build 2")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!BUILDDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build 1")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!ROTATESENTRY180" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry180")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!ROTATESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DISMANTLEDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 1")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DISMANTLESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 2")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DETONATEDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("detdispenser")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DETONATESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("detsentry")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Stop building + else if ( !strcmp( pButtonName, "!BUILDSTOP" ) ) + { + pButton = new BuildButton( BUILDSTATE_BUILDING, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + + return pButton; +} + +void TeamFortressViewport::ToggleServerBrowser() +{ + if (!m_iInitialized) + return; + + if ( !m_pServerBrowser ) + return; + + if ( m_pServerBrowser->isVisible() ) + { + m_pServerBrowser->setVisible( false ); + } + else + { + m_pServerBrowser->setVisible( true ); + } + + UpdateCursorState(); +} + +//======================================================================= +void TeamFortressViewport::ShowCommandMenu(int menuIndex) +{ + if (!m_iInitialized) + return; + + //Already have a menu open. + if ( m_pCurrentMenu ) + return; + + // is the command menu open? + if ( m_pCurrentCommandMenu == m_pCommandMenus[menuIndex] ) + { + HideCommandMenu(); + return; + } + + // Not visible while in intermission + if ( gHUD.m_iIntermission ) + return; + + // Recalculate visible menus + UpdateCommandMenu( menuIndex ); + HideVGUIMenu(); + + SetCurrentCommandMenu( m_pCommandMenus[menuIndex] ); + m_flMenuOpenTime = gHUD.m_flTime; + UpdateCursorState(); + + // get command menu parameters + for ( int i = 2; i < gEngfuncs.Cmd_Argc(); i++ ) + { + const char *param = gEngfuncs.Cmd_Argv( i - 1 ); + if ( param ) + { + if ( m_pCurrentCommandMenu->KeyInput(param[0]) ) + { + // kill the menu open time, since the key input is final + HideCommandMenu(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles the key input of "-commandmenu" +// Input : +//----------------------------------------------------------------------------- +void TeamFortressViewport::InputSignalHideCommandMenu() +{ + if (!m_iInitialized) + return; + + // if they've just tapped the command menu key, leave it open + if ( (m_flMenuOpenTime + 0.3) > gHUD.m_flTime ) + return; + + HideCommandMenu(); +} + +//----------------------------------------------------------------------------- +// Purpose: Hides the command menu +//----------------------------------------------------------------------------- +void TeamFortressViewport::HideCommandMenu() +{ + if (!m_iInitialized) + return; + + if ( m_pCommandMenus[m_StandardMenu] ) + { + m_pCommandMenus[m_StandardMenu]->ClearButtonsOfArmedState(); + } + + if ( m_pCommandMenus[m_SpectatorOptionsMenu] ) + { + m_pCommandMenus[m_SpectatorOptionsMenu]->ClearButtonsOfArmedState(); + } + + if ( m_pCommandMenus[m_SpectatorCameraMenu] ) + { + m_pCommandMenus[m_SpectatorCameraMenu]->ClearButtonsOfArmedState(); + } + + m_flMenuOpenTime = 0.0f; + SetCurrentCommandMenu( NULL ); + UpdateCursorState(); +} + +//----------------------------------------------------------------------------- +// Purpose: Bring up the scoreboard +//----------------------------------------------------------------------------- +void TeamFortressViewport::ShowScoreBoard( void ) +{ + if (m_pScoreBoard) + { + // No Scoreboard in single-player + if ( gEngfuncs.GetMaxClients() > 1 ) + { + if(gHUD.SwitchUIMode(SCOREBOARD_MODE)) + { + m_pScoreBoard->Open(); + + // TODO: HLSDK 2.3 requires this? + UpdateCursorState(); + + // If cursor is visible, set squelch mode automatically (used for commander) + if(gHUD.GetIsInTopDownMode()) + { + m_pScoreBoard->SetSquelchMode(true); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the scoreboard is up +//----------------------------------------------------------------------------- +bool TeamFortressViewport::IsScoreBoardVisible( void ) +{ + if (m_pScoreBoard) + return m_pScoreBoard->isVisible(); + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Hide the scoreboard +//----------------------------------------------------------------------------- +const float kButtonWidth = .15f; +const float kButtonHeight = .08f; +const float kButtonHorizontalSpacing = .15f; +const float kButtonVerticalSpacing = .05f; +const float xInset = .05f; +const float yInset = .07f; + +void TeamFortressViewport::HideScoreBoard( void ) +{ + // Prevent removal of scoreboard during intermission + if ( gHUD.m_iIntermission ) + return; + + if (m_pScoreBoard && m_pScoreBoard->isVisible()) + { + // Hide other components + if(gHUD.SwitchUIMode(MAIN_MODE)) + { + m_pScoreBoard->setVisible(false); + + //GetClientVoiceMgr()->StopSquelchMode(); + m_pScoreBoard->SetSquelchMode(false); + + //UpdateCursorState(); + } + } +} + +void TeamFortressViewport::ShowOptionsMenu() +{ + if(this->mOptionsScreen) + { + const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON); + gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + + this->mOptionsScreen->setVisible(true); + + for(int i = 0; i < kNumOptionsButtons; i++) + { + if(this->mOptionsButtons[i]) + { + this->mOptionsButtons[i]->setVisible(true); + } + } + + gHUD.GetManager().SetMouseVisibility(true); + } +} + +void TeamFortressViewport::HideOptionsMenu() +{ + if(this->mOptionsScreen) + { + const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_OFF); + gHUD.PlayHUDSound(theSound, kHUDSoundVolume); + + this->mOptionsScreen->setVisible(false); + for(int i = 0; i < kNumOptionsButtons; i++) + { + if(this->mOptionsButtons[i]) + { + this->mOptionsButtons[i]->setVisible(false); + } + } + + gHUD.GetManager().SetMouseVisibility(false); + + gEngfuncs.pfnSetMousePos(gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } +} + +bool TeamFortressViewport::IsOptionsMenuVisible() +{ + bool theIsVisible = false; + + if(this->mOptionsScreen) + { + theIsVisible = this->mOptionsScreen->isVisible(); + } + + return theIsVisible; +} + +// Set the submenu of the Command Menu +void TeamFortressViewport::SetCurrentCommandMenu( CCommandMenu *pNewMenu ) +{ + for (int i = 0; i < m_iNumMenus; i++) + m_pCommandMenus[i]->setVisible(false); + + m_pCurrentCommandMenu = pNewMenu; + + if (m_pCurrentCommandMenu) + m_pCurrentCommandMenu->MakeVisible( NULL ); + +} + +void TeamFortressViewport::UpdateCommandMenu(int menuIndex) +{ + m_pCommandMenus[menuIndex]->RecalculateVisibles( 0, false ); + m_pCommandMenus[menuIndex]->RecalculatePositions( 0 ); +} + +void COM_FileBase ( const char *in, char *out); + +void TeamFortressViewport::UpdateSpectatorPanel() +{ + m_iUser1 = g_iUser1; + m_iUser2 = g_iUser2; + m_iUser3 = g_iUser3; + + if (!m_pSpectatorPanel) + return; + + if ( g_iUser1 && gHUD.m_pCvarDraw->value && !gHUD.m_iIntermission) // don't draw in dev_overview mode + { + char bottomText[128]; + char helpString2[128]; + char * name; + int player = 0; + + // check if spectator combinations are still valid + gHUD.m_Spectator.CheckSettings(); + + if ( !m_pSpectatorPanel->isVisible() ) + { + m_pSpectatorPanel->setVisible( true ); // show spectator panel, but + m_pSpectatorPanel->ShowMenu( true ); + + // Removed by mmcguire. + // This text isn't applicable anymore. + + /* + char tempString[128]; + + _snprintf( tempString, sizeof( tempString ) - 1, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( "#Spec_Duck" ) ); + tempString[ sizeof( tempString ) - 1 ] = '\0'; + + gHUD.m_TextMessage.MsgFunc_TextMsg( NULL, strlen( tempString ) + 1, tempString ); + */ + } + + sprintf(bottomText,"#Spec_Mode%d", g_iUser1 ); + sprintf(helpString2,"#Spec_Mode%d", g_iUser1 ); + + if ( gEngfuncs.IsSpectateOnly() ) + strcat(helpString2, " - HLTV"); + + // check if we're locked onto a target, show the player's name + if ( (g_iUser2 > 0) && (g_iUser2 <= gEngfuncs.GetMaxClients()) && (g_iUser1 != OBS_ROAMING) ) + { + player = g_iUser2; + } + + name = g_PlayerInfoList[player].name; + + // create player & health string + if ( player && name ) + { + strcpy( bottomText, name ); + if ( gEngfuncs.IsSpectateOnly() ) { + char tmp[32]; + sprintf(tmp, " (%d)", g_PlayerExtraInfo[player].health); + strcat( bottomText, tmp); + } + } +/* + // in first person mode colorize player names + if ( (g_iUser1 == OBS_IN_EYE) && player ) + { + float * color = GetClientColor( player ); + int r = color[0]*255; + int g = color[1]*255; + int b = color[2]*255; + + // set team color, a bit transparent + m_pSpectatorPanel->m_BottomMainLabel->setFgColor(r,g,b,0); + } + else + { // restore GUI color + m_pSpectatorPanel->m_BottomMainLabel->setFgColor( 143, 143, 54, 0 ); + } +*/ + // add sting auto if we are in auto directed mode + if ( CVAR_GET_FLOAT("spec_autodirector") != 0 ) + { + char tempString[128]; + sprintf(tempString, "#Spec_Auto %s", helpString2); + strcpy( helpString2, tempString ); + } + + m_pSpectatorPanel->m_BottomMainLabel->setText( CHudTextMessage::BufferedLocaliseTextString( bottomText ) ); + + + // update extra info field + char szText[64]; + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in HLTV mode show number of spectators + _snprintf( szText, 63, "%s: %d", CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ), gHUD.m_Spectator.m_iSpectatorNumber ); + } + else + { + // otherwise show map name + char szMapName[64]; + COM_FileBase( gEngfuncs.pfnGetLevelName(), szMapName ); + + _snprintf ( szText, 63, "%s: %s",CHudTextMessage::BufferedLocaliseTextString( "#Spec_Map" ), szMapName ); + } + + szText[63] = 0; + + m_pSpectatorPanel->m_ExtraInfo->setText ( szText ); + + /* + int timer = (int)( gHUD.m_roundTimer.m_flTimeEnd - gHUD.m_flTime ); + + if ( timer < 0 ) + timer = 0; + + _snprintf ( szText, 63, "%d:%02d\n", (timer / 60), (timer % 60) ); + + szText[63] = 0; + + m_pSpectatorPanel->m_CurrentTime->setText( szText ); */ + int theTimeToDisplay = gHUD.GetGameTime(); + _snprintf ( szText, 63, "%d:%02d\n", (theTimeToDisplay / 60), (theTimeToDisplay % 60) ); + szText[63] = 0; + m_pSpectatorPanel->m_CurrentTime->setText( szText ); + + // update spectator panel + gViewPort->m_pSpectatorPanel->Update(); + } + else + { + if ( m_pSpectatorPanel->isVisible() ) + { + m_pSpectatorPanel->setVisible( false ); + } + if (m_pSpectatorPanel->m_menuVisible) + { + m_pSpectatorPanel->ShowMenu( false ); // dsiable all menus/buttons + } + + } + + m_flSpectatorPanelLastUpdated = gHUD.m_flTime + 1.0; // update every seconds +} + +//====================================================================== +void TeamFortressViewport::CreateScoreBoard( void ) +{ + int xdent = SBOARD_INDENT_X; + int ydent = SBOARD_INDENT_Y; + if (ScreenWidth() == 512) + { + xdent = SBOARD_INDENT_X_512; + ydent = SBOARD_INDENT_Y_512; + } + else if (ScreenWidth() == 400) + { + xdent = SBOARD_INDENT_X_400; + ydent = SBOARD_INDENT_Y_400; + } + + m_pScoreBoard = new ScorePanel(xdent, ydent, ScreenWidth() - (xdent * 2), ScreenHeight() - (ydent * 2)); + m_pScoreBoard->setParent(this); + m_pScoreBoard->setVisible(false); +} + +void TeamFortressViewport::CreateOptionsMenu() +{ + //this->mOptionsScreen = new ColoredPanel(0, 0, ScreenWidth, ScreenHeight); + this->mOptionsScreen = new CTransparentPanel(128, 0, 0, ScreenWidth(), ScreenHeight()); + this->mOptionsScreen->setBorder( new LineBorder( Color(255*0.7,170*0.7,0,0 )) ); + this->mOptionsScreen->setParent(this); + this->mOptionsScreen->setBgColor(128, 128, 128, 40); + this->mOptionsScreen->setVisible(false); + + int theScreenWidth = ScreenWidth(); + int theScreenHeight = ScreenHeight(); +} + +void TeamFortressViewport::CreateServerBrowser( void ) +{ + m_pServerBrowser = new ServerBrowser( 0, 0, ScreenWidth(), ScreenHeight() ); + m_pServerBrowser->setParent(this); + m_pServerBrowser->setVisible(false); +} + +void TeamFortressViewport::CreatePlayerMenu() +{ + + int newIndex = m_iNumMenus; + + m_pCommandMenus[newIndex] = new CCommandMenu(NULL, 1, XRES(390), YRES(32), XRES(kPlayerMenuWidth), YRES(300)); // This will be resized once we know how many items are in it + + m_pCommandMenus[newIndex]->setParent(this); + m_pCommandMenus[newIndex]->setVisible(false); + m_pCommandMenus[newIndex]->m_flButtonSizeY = BUTTON_SIZE_Y / 2; + m_pCommandMenus[newIndex]->m_iSpectCmdMenu = 1; + + m_iNumMenus++; + + m_SpectatorPlayerMenu = newIndex; + +} + +void TeamFortressViewport::UpdatePlayerMenu() +{ + + CCommandMenu* pMenu = m_pCommandMenus[m_SpectatorPlayerMenu]; + + int xOffset = 0; + + float flButtonSizeX = XRES(kPlayerMenuWidth); + float flButtonSizeY = BUTTON_SIZE_Y / 2; + + // Create a menu item for each of the players. + + pMenu->ClearButtonsOfArmedState(); + pMenu->RemoveAllButtons(); + + // Make sure we have player info + gViewPort->GetAllPlayersInfo(); + + for (int team = 0; team < 4; ++team) + { + + if (gHUD.GetPlayMode() != PLAYMODE_OBSERVER) + { + // Filter out players who aren't on our team. + + int theLocalPlayerTeam = 0; + + if (gEngfuncs.GetLocalPlayer()) + { + theLocalPlayerTeam = gEngfuncs.GetLocalPlayer()->curstate.team; + } + + if (theLocalPlayerTeam != team) + { + continue; + } + + } + + for (int i = 1; i <= MAX_PLAYERS; ++i) + { + + if ( g_PlayerInfoList[i].name == NULL ) + continue; // empty player slot, skip + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + if ( g_PlayerExtraInfo[i].teamnumber != team) + continue; + + switch(g_PlayerExtraInfo[i].playerclass) + { + case PLAYERCLASS_SPECTATOR: + case PLAYERCLASS_COMMANDER: + case PLAYERCLASS_REINFORCING: + continue; + } + + int iButtonY = (BUTTON_SIZE_Y-1) * pMenu->GetNumButtons(); + + PlayerButton* pButton = new PlayerButton(i, g_PlayerInfoList[i].name, 0, iButtonY, flButtonSizeX, flButtonSizeY, false, true); + + //pButton->setArmedColor(teamR, teamG, teamB, 0); + //pButton->setUnArmedColor(teamR, teamG, teamB, 0); + //pButton->setArmedBorderColor(255 / gHUD.GetGammaSlope(), 255 / gHUD.GetGammaSlope(), 255 / gHUD.GetGammaSlope(), 0); + + if ( pButton ) + { + pMenu->AddButton( pButton ); + pButton->setParentMenu( pMenu ); + pButton->setFont( Scheme::sf_primary3 ); + + char command[MAX_COMMAND_SIZE]; + sprintf(command, "follow %d", i); + + pButton->addActionSignal(new CMenuHandler_StringCommand(command)); + + } + + } + } + +} + +//====================================================================== +// Set the VGUI Menu +void TeamFortressViewport::SetCurrentMenu( CMenuPanel *pMenu ) +{ + m_pCurrentMenu = pMenu; + if ( m_pCurrentMenu ) + { + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return; + + m_pCurrentMenu->Open(); + } +} + +//================================================================ +// Text Window +CMenuPanel* TeamFortressViewport::CreateTextWindow( int iTextToShow ) +{ + char sz[256]; + char *cText; + char *pfile = NULL; + static const int MAX_TITLE_LENGTH = 32; + char cTitle[MAX_TITLE_LENGTH]; + + if ( iTextToShow == SHOW_MOTD ) + { + if (!m_szServerName || !m_szServerName[0]) + strcpy( cTitle, kAvHGameName ); + else + strncpy( cTitle, m_szServerName, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + cText = m_szMOTD; + } + else if ( iTextToShow == SHOW_MAPBRIEFING ) + { + // Get the current mapname, and open it's map briefing text + if (m_sMapName && m_sMapName[0]) + { + strcpy( sz, "maps/"); + strcat( sz, m_sMapName ); + strcat( sz, ".txt" ); + } + else + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (!level) + return NULL; + + strcpy( sz, level ); + char *ch = strchr( sz, '.' ); + *ch = '\0'; + strcat( sz, ".txt" ); + + // pull out the map name + strcpy( m_sMapName, level ); + ch = strchr( m_sMapName, '.' ); + if ( ch ) + { + *ch = 0; + } + + ch = strchr( m_sMapName, '/' ); + if ( ch ) + { + // move the string back over the '/' + memmove( m_sMapName, ch+1, strlen(ch)+1 ); + } + } + + pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + + if (!pfile) + return NULL; + + cText = pfile; + + strncpy( cTitle, m_sMapName, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + } + else if ( iTextToShow == SHOW_CLASSDESC ) + { + switch ( g_iPlayerClass ) + { + case PC_SCOUT: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_scout" ); + CHudTextMessage::LocaliseTextString( "#Title_scout", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SNIPER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_sniper" ); + CHudTextMessage::LocaliseTextString( "#Title_sniper", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SOLDIER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_soldier" ); + CHudTextMessage::LocaliseTextString( "#Title_soldier", cTitle, MAX_TITLE_LENGTH ); break; + case PC_DEMOMAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_demoman" ); + CHudTextMessage::LocaliseTextString( "#Title_demoman", cTitle, MAX_TITLE_LENGTH ); break; + case PC_MEDIC: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_medic" ); + CHudTextMessage::LocaliseTextString( "#Title_medic", cTitle, MAX_TITLE_LENGTH ); break; + case PC_HVYWEAP: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_hwguy" ); + CHudTextMessage::LocaliseTextString( "#Title_hwguy", cTitle, MAX_TITLE_LENGTH ); break; + case PC_PYRO: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_pyro" ); + CHudTextMessage::LocaliseTextString( "#Title_pyro", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SPY: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_spy" ); + CHudTextMessage::LocaliseTextString( "#Title_spy", cTitle, MAX_TITLE_LENGTH ); break; + case PC_ENGINEER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_engineer" ); + CHudTextMessage::LocaliseTextString( "#Title_engineer", cTitle, MAX_TITLE_LENGTH ); break; + case PC_CIVILIAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_civilian" ); + CHudTextMessage::LocaliseTextString( "#Title_civilian", cTitle, MAX_TITLE_LENGTH ); break; + default: + return NULL; + } + + if ( g_iPlayerClass == PC_CIVILIAN ) + { + sprintf(sz, "classes/long_civilian.txt"); + } + else + { + sprintf(sz, "classes/long_%s.txt", sTFClassSelection[ g_iPlayerClass ]); + } + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + cText = pfile; + } + } + else if ( iTextToShow == SHOW_SPECHELP ) + { + CHudTextMessage::LocaliseTextString( "#Spec_Help_Title", cTitle, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + + char *pfile = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); + if ( pfile ) + { + cText = pfile; + } + } + + // if we're in the game (ie. have selected a class), flag the menu to be only grayed in the dialog box, instead of full screen + CMenuPanel *pMOTDPanel = CMessageWindowPanel_Create( cText, cTitle, g_iPlayerClass == PC_UNDEFINED, false, 0, 0, ScreenWidth(), ScreenHeight() ); + pMOTDPanel->setParent( this ); + + if ( pfile ) + gEngfuncs.COM_FreeFile( pfile ); + + return pMOTDPanel; +} + +char* TeamFortressViewport::GetTeamName( int iTeam ) +{ + return m_sTeamNames[iTeam]; +} + +//================================================================ +// VGUI Menus +void TeamFortressViewport::ShowVGUIMenu( int iMenu ) +{ + CMenuPanel *pNewMenu = NULL; + + gHUD.SetUsingVGUI(true); + + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return; + + // Don't open any menus except the MOTD during intermission + // MOTD needs to be accepted because it's sent down to the client + // after map change, before intermission's turned off + if ( gHUD.m_iIntermission && iMenu != MENU_INTRO ) + return; + + // Don't create one if it's already in the list + if (m_pCurrentMenu) + { + CMenuPanel *pMenu = m_pCurrentMenu; + while (pMenu != NULL) + { + if (pMenu->GetMenuID() == iMenu) + return; + pMenu = pMenu->GetNextMenu(); + } + } + + switch ( iMenu ) + { + case MENU_TEAM: + pNewMenu = ShowTeamMenu(); + break; + + // Map Briefing removed now that it appears in the team menu + case MENU_MAPBRIEFING: + pNewMenu = CreateTextWindow( SHOW_MAPBRIEFING ); + break; + + case MENU_INTRO: + pNewMenu = CreateTextWindow( SHOW_MOTD ); + break; + + case MENU_CLASSHELP: + pNewMenu = CreateTextWindow( SHOW_CLASSDESC ); + break; + + case MENU_SPECHELP: + pNewMenu = CreateTextWindow( SHOW_SPECHELP ); + break; + case MENU_CLASS: + pNewMenu = ShowClassMenu(); + break; + + default: + break; + } + + if (!pNewMenu) + return; + + // Close the Command Menu if it's open + HideCommandMenu(); + + pNewMenu->SetMenuID( iMenu ); + pNewMenu->SetActive( true ); + pNewMenu->setParent(this); + + // See if another menu is visible, and if so, cache this one for display once the other one's finished + if (m_pCurrentMenu) + { + if ( m_pCurrentMenu->GetMenuID() == MENU_CLASS && iMenu == MENU_TEAM ) + { + CMenuPanel *temp = m_pCurrentMenu; + m_pCurrentMenu->Close(); + m_pCurrentMenu = pNewMenu; + m_pCurrentMenu->SetNextMenu( temp ); + m_pCurrentMenu->Open(); + UpdateCursorState(); + } + else + { + m_pCurrentMenu->SetNextMenu( pNewMenu ); + } + } + else + { + m_pCurrentMenu = pNewMenu; + m_pCurrentMenu->Open(); + UpdateCursorState(); + } +} + +// Removes all VGUI Menu's onscreen +void TeamFortressViewport::HideVGUIMenu() +{ + while (m_pCurrentMenu) + { + HideTopMenu(); + } + gHUD.SetUsingVGUI(false); +} + +// Remove the top VGUI menu, and bring up the next one +void TeamFortressViewport::HideTopMenu() +{ + if (m_pCurrentMenu) + { + // Close the top one + m_pCurrentMenu->Close(); + + // Bring up the next one + gViewPort->SetCurrentMenu( m_pCurrentMenu->GetNextMenu() ); + } + + UpdateCursorState(); +} + +// Return TRUE if the HUD's allowed to print text messages +bool TeamFortressViewport::AllowedToPrintText( void ) +{ + // Prevent text messages when fullscreen menus are up + if ( m_pCurrentMenu && g_iPlayerClass == 0 ) + { + int iId = m_pCurrentMenu->GetMenuID(); + if ( iId == MENU_TEAM || iId == MENU_CLASS || iId == MENU_INTRO || iId == MENU_CLASSHELP ) + return FALSE; + } + + return TRUE; +} + +//====================================================================================== +// TEAM MENU +//====================================================================================== +// Bring up the Team selection Menu +CMenuPanel* TeamFortressViewport::ShowTeamMenu() +{ + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return NULL; + + m_pTeamMenu->Reset(); + return m_pTeamMenu; +} + +void TeamFortressViewport::CreateTeamMenu() +{ + // Create the panel + m_pTeamMenu = new CTeamMenuPanel(100, false, 0, 0, ScreenWidth(), ScreenHeight()); + m_pTeamMenu->setParent( this ); + m_pTeamMenu->setVisible( false ); +} + +//====================================================================================== +// CLASS MENU +//====================================================================================== +// Bring up the Class selection Menu +CMenuPanel* TeamFortressViewport::ShowClassMenu() +{ + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return NULL; + + m_pClassMenu->Reset(); + return m_pClassMenu; +} + +void TeamFortressViewport::CreateClassMenu() +{ + // Create the panel + m_pClassMenu = new CClassMenuPanel(100, false, 0, 0, ScreenWidth(), ScreenHeight()); + m_pClassMenu->setParent(this); + m_pClassMenu->setVisible( false ); +} + +//====================================================================================== +//====================================================================================== +// SPECTATOR MENU +//====================================================================================== +// Spectator "Menu" explaining the Spectator buttons +void TeamFortressViewport::CreateSpectatorMenu() +{ + // Create the Panel + m_pSpectatorPanel = new SpectatorPanel(0, 0, ScreenWidth(), ScreenHeight()); + m_pSpectatorPanel->setParent(this); + m_pSpectatorPanel->setVisible(false); + m_pSpectatorPanel->Initialize(); +} + +//====================================================================================== +// UPDATE HUD SECTIONS +//====================================================================================== +// We've got an update on player info +// Recalculate any menus that use it. +void TeamFortressViewport::UpdateOnPlayerInfo() +{ + if (m_pTeamMenu) + m_pTeamMenu->Update(); + if (m_pClassMenu) + m_pClassMenu->Update(); + if (m_pScoreBoard) + m_pScoreBoard->Update(); +} + +void TeamFortressViewport::UpdateCursorState() +{ + + if (gHUD.GetInTopDownMode() || m_pSpectatorPanel->isVisible() || GetClientVoiceMgr()->IsInSquelchMode()) + { + gHUD.GetManager().SetMouseVisibility(true); + } + else + { + + // Don't reset mouse in demo playback + if ( !gEngfuncs.pDemoAPI->IsPlayingback() ) + { + IN_ResetMouse(); + } + + gHUD.GetManager().SetMouseVisibility(false); + + } + + /* + if(!gHUD.GetInTopDownMode()) + { + // Need cursor if any VGUI window is up + if ( m_pSpectatorPanel->m_menuVisible || m_pCurrentMenu || m_pTeamMenu->isVisible() || m_pServerBrowser->isVisible() || GetClientVoiceMgr()->IsInSquelchMode() ) + { + gHUD.GetManager().SetMouseVisibility(true); + //g_iVisibleMouse = true; + //App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); + return; + } + else if ( m_pCurrentCommandMenu ) + { + // commandmenu doesn't have cursor if hud_capturemouse is turned off + if ( gHUD.m_pCvarStealMouse->value != 0.0f ) + { + gHUD.GetManager().SetMouseVisibility(true); + //g_iVisibleMouse = true; + //App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); + return; + } + } + + // Don't reset mouse in demo playback + if ( !gEngfuncs.pDemoAPI->IsPlayingback() ) + { + IN_ResetMouse(); + } + + gHUD.GetManager().SetMouseVisibility(false); + //g_iVisibleMouse = false; + //App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_none) ); + } + */ + +} + +void TeamFortressViewport::UpdateHighlights() +{ + if (m_pCurrentCommandMenu) + m_pCurrentCommandMenu->MakeVisible( NULL ); +} + +void TeamFortressViewport::GetAllPlayersInfo( void ) +{ + for ( int i = 1; i <= MAX_PLAYERS; i++ ) + { + GetPlayerInfo( i, &g_PlayerInfoList[i] ); + + if ( g_PlayerInfoList[i].thisplayer ) + m_pScoreBoard->m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine + } +} + +void TeamFortressViewport::paintBackground() +{ + if (m_pScoreBoard) + { + int x, y; + getApp()->getCursorPos(x, y); + m_pScoreBoard->cursorMoved(x, y, m_pScoreBoard); + } + + // See if the command menu is visible and needs recalculating due to some external change + if ( g_iTeamNumber != m_iCurrentTeamNumber ) + { + UpdateCommandMenu( m_StandardMenu ); + + if ( m_pClassMenu ) + { + m_pClassMenu->Update(); + } + + m_iCurrentTeamNumber = g_iTeamNumber; + } + + if ( g_iPlayerClass != m_iCurrentPlayerClass ) + { + UpdateCommandMenu( m_StandardMenu ); + + m_iCurrentPlayerClass = g_iPlayerClass; + } + + // See if the Spectator Menu needs to be update + if ( ( g_iUser1 != m_iUser1 || g_iUser2 != m_iUser2 ) || + ( m_flSpectatorPanelLastUpdated < gHUD.m_flTime ) ) + { + UpdateSpectatorPanel(); + } + + // Update the Scoreboard, if it's visible + if ( m_pScoreBoard->isVisible() && (m_flScoreBoardLastUpdated < gHUD.m_flTime) ) + { + m_pScoreBoard->Update(); + m_flScoreBoardLastUpdated = gHUD.m_flTime + 0.5; + } + + int extents[4]; + getAbsExtents(extents[0],extents[1],extents[2],extents[3]); + VGui_ViewportPaintBackground(extents); +} + +//================================================================ +// Input Handler for Drag N Drop panels +void CDragNDropHandler::cursorMoved(int x,int y,Panel* panel) +{ + if(m_bDragging) + { + App::getInstance()->getCursorPos(x,y); + m_pPanel->setPos(m_iaDragOrgPos[0]+(x-m_iaDragStart[0]),m_iaDragOrgPos[1]+(y-m_iaDragStart[1])); + + if(m_pPanel->getParent()!=null) + { + m_pPanel->getParent()->repaint(); + } + } +} + +void CDragNDropHandler::mousePressed(MouseCode code,Panel* panel) +{ + int x,y; + App::getInstance()->getCursorPos(x,y); + m_bDragging=true; + m_iaDragStart[0]=x; + m_iaDragStart[1]=y; + m_pPanel->getPos(m_iaDragOrgPos[0],m_iaDragOrgPos[1]); + App::getInstance()->setMouseCapture(panel); + + m_pPanel->setDragged(m_bDragging); + m_pPanel->requestFocus(); +} + +void CDragNDropHandler::mouseReleased(MouseCode code,Panel* panel) +{ + m_bDragging=false; + m_pPanel->setDragged(m_bDragging); + App::getInstance()->setMouseCapture(null); +} + +//================================================================ +// Number Key Input +bool TeamFortressViewport::SlotInput( int iSlot ) +{ + // If there's a menu up, give it the input + if ( m_pCurrentMenu ) + return m_pCurrentMenu->SlotInput( iSlot ); + + if(gHUD.SlotInput(iSlot)) + { + return TRUE; + } + + return FALSE; +} + +// Direct Key Input +int TeamFortressViewport::KeyInput( int down, int keynum, const char *pszCurrentBinding ) +{ + + if (m_chatPanel->isVisible()) + { + // Don't let the game handle the input while the user is typing in the chat window. + m_chatPanel->KeyEvent(); + return 0; + } + + if (down && pszCurrentBinding && !strcmp(pszCurrentBinding, kcGlobalChat)) + { + m_chatPanel->setVisible(true); + m_chatPanel->requestFocus(); + m_chatPanel->SetChatMode(ChatPanel::chatModeAll); + return 0; + } + else if (down && pszCurrentBinding && !strcmp(pszCurrentBinding, kcTeamChat)) + { + m_chatPanel->setVisible(true); + m_chatPanel->requestFocus(); + m_chatPanel->SetChatMode(ChatPanel::chatModeTeam); + return 0; + } + + // Open Text Window? + if (m_pCurrentMenu && gEngfuncs.Con_IsVisible() == false) + { + int iMenuID = m_pCurrentMenu->GetMenuID(); + + // Get number keys as Input for Team/Class menus + if (iMenuID == MENU_TEAM || iMenuID == MENU_CLASS) + { + // Escape gets you out of Team/Class menus if the Cancel button is visible + if ( keynum == K_ESCAPE ) + { + if ( (iMenuID == MENU_TEAM && g_iTeamNumber) || (iMenuID == MENU_CLASS && g_iPlayerClass) ) + { + HideTopMenu(); + return 0; + } + } + + for (int i = '0'; i <= '9'; i++) + { + if ( down && (keynum == i) ) + { + SlotInput( i - '0' ); + return 0; + } + } + } + + // Grab enter keys to close TextWindows + if ( down && (keynum == K_ENTER || keynum == K_KP_ENTER || keynum == K_SPACE || keynum == K_ESCAPE) ) + { + if ( iMenuID == MENU_MAPBRIEFING || iMenuID == MENU_INTRO || iMenuID == MENU_CLASSHELP ) + { + HideTopMenu(); + return 0; + } + } + + // Grab jump key on Team Menu as autoassign + if ( pszCurrentBinding && down && !strcmp(pszCurrentBinding, "+jump") ) + { + if (iMenuID == MENU_TEAM) + { + m_pTeamMenu->SlotInput(5); + return 0; + } + } + + } + + // if we're in a command menu, try hit one of it's buttons + if ( down && m_pCurrentCommandMenu ) + { + // Escape hides the command menu + if ( keynum == K_ESCAPE ) + { + HideCommandMenu(); + return 0; + } + + // only trap the number keys + if ( keynum >= '0' && keynum <= '9' ) + { + if ( m_pCurrentCommandMenu->KeyInput(keynum) ) + { + // a final command has been issued, so close the command menu + HideCommandMenu(); + } + + return 0; + } + } + + return 1; +} + +ChatPanel* TeamFortressViewport::GetChatPanel() +{ + return m_chatPanel; +} + +//================================================================ +// Message Handlers +int TeamFortressViewport::MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ) +{ + StringList team_names; + NetMsg_TeamNames( pbuf, iSize, team_names ); + + char team_translated[128]; + strcpy(team_translated, gHUD.m_TextMessage.LookupString(kTeamTitle)); + + char team_name_translated[MAX_TEAMNAME_SIZE]; + for( int team_number = 0; team_number < team_names.size(); team_number++ ) + { + gHUD.m_TextMessage.LocaliseTextString( team_names[team_number].c_str(), team_name_translated, MAX_TEAMNAME_SIZE ); + + team_names[team_number] = ""; + if( team_number != 0 && team_number < (m_iNumberOfTeams-1) ) //don't prepend information for spectators or team 0 + { + team_names[team_number] += team_translated; + team_names[team_number] += " "; + team_names[team_number] += MakeStringFromInt( team_number ); + team_names[team_number] += ": "; + } + team_names[team_number] += team_name_translated; + strcpy(m_sTeamNames[team_number], team_names[team_number].c_str()); + } + + return 1; +} + +int TeamFortressViewport::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) +{ + if (m_iGotAllMOTD) + m_szMOTD[0] = 0; + + string MOTD; + bool is_finished; + NetMsg_MOTD( pbuf, iSize, is_finished, MOTD ); + + m_iGotAllMOTD = is_finished ? 1 : 0; + + int roomInArray = (int)max( 0, sizeof(m_szMOTD) - strlen(m_szMOTD) - 1); + + strncat( m_szMOTD, MOTD.c_str(), roomInArray ); + m_szMOTD[ sizeof(m_szMOTD)-1 ] = '\0'; + + return 1; +} + +int TeamFortressViewport::MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) +{ + string name; + NetMsg_ServerName( pbuf, iSize, name ); + + memset(this->m_szServerName, 0, MAX_SERVERNAME_LENGTH); + + strncpy( m_szServerName, name.c_str(), MAX_SERVERNAME_LENGTH ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) +{ + ScoreInfo info; + NetMsg_ScoreInfo( pbuf, iSize, info ); + + if ( info.player_index > 0 && info.player_index <= MAX_PLAYERS ) + { + // Update score, but show + or - indicator on scoreboard when it changes + g_PlayerExtraInfo[info.player_index].lastScore = g_PlayerExtraInfo[info.player_index].score; + g_PlayerExtraInfo[info.player_index].score = info.score; + if(g_PlayerExtraInfo[info.player_index].score != g_PlayerExtraInfo[info.player_index].lastScore) + { + g_PlayerExtraInfo[info.player_index].timeOfLastScoreChange = gHUD.GetTimeOfLastUpdate(); + } + + // Update other info + g_PlayerExtraInfo[info.player_index].frags = info.frags; + g_PlayerExtraInfo[info.player_index].deaths = info.deaths; + g_PlayerExtraInfo[info.player_index].extra = info.extra; + g_PlayerExtraInfo[info.player_index].playerclass = info.player_class; + // : 0001073 + g_PlayerExtraInfo[info.player_index].auth = info.auth; + g_PlayerExtraInfo[info.player_index].teamnumber = max( info.team, 0 ); + g_PlayerExtraInfo[info.player_index].health = info.health; + + // Icon is now handled through the ProfileInfo update + + UpdateOnPlayerInfo(); + } + + return 1; +} + +// Message handler for TeamScore message +// accepts three values: +// string: team name +// short: teams kills +// short: teams deaths +// if this message is never received, then scores will simply be the combined totals of the players. +int TeamFortressViewport::MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) +{ + string team_name; + int score, reset; + NetMsg_TeamScore( pbuf, iSize, team_name, score, reset); + + // find the team matching the name + int i; + for ( i = 1; i <= m_pScoreBoard->m_iNumTeams; i++ ) + { + if ( !stricmp( team_name.c_str(), g_TeamInfo[i].name ) ) + break; + } + + if ( i > m_pScoreBoard->m_iNumTeams ) + return 1; + + // use this new score data instead of combined player scores + if ( reset ) + g_TeamInfo[i]. scores_overriden = FALSE; + else + g_TeamInfo[i]. scores_overriden = TRUE; + + g_TeamInfo[i].score = score; + + return 1; +} + +// Message handler for TeamInfo message +// accepts two values: +// byte: client number +// string: client team name +int TeamFortressViewport::MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) +{ + if (!m_pScoreBoard) + return 1; + + int player_index; + string team_id; + NetMsg_TeamInfo( pbuf, iSize, player_index, team_id ); + + if ( player_index > 0 && player_index <= MAX_PLAYERS ) + { + // set the players team + strncpy( g_PlayerExtraInfo[player_index].teamname, team_id.c_str(), MAX_TEAM_NAME ); + } + + // rebuild the list of teams + m_pScoreBoard->RebuildTeams(); + + return 1; +} + +void TeamFortressViewport::DeathMsg( int killer, int victim ) +{ + m_pScoreBoard->DeathMsg(killer,victim); +} diff --git a/main/source/cl_dll/vgui_TeamFortressViewport.h b/main/source/cl_dll/vgui_TeamFortressViewport.h index e83e80b4..3ae9be5d 100644 --- a/main/source/cl_dll/vgui_TeamFortressViewport.h +++ b/main/source/cl_dll/vgui_TeamFortressViewport.h @@ -1,1766 +1,1766 @@ - -#ifndef TEAMFORTRESSVIEWPORT_H -#define TEAMFORTRESSVIEWPORT_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "CLabelHeader.h" -#include "vgui_listbox.h" -#include "vgui_grid.h" - - -// custom scheme handling -#include "vgui_SchemeManager.h" - -#define TF_DEFS_ONLY -#include "tf_defs.h" - -using namespace vgui; - -class Cursor; -class ScorePanel; -class SpectatorPanel; -class CCommandMenu; -class CommandLabel; -class CommandButton; -class BuildButton; -class ClassButton; -class CMenuPanel; -class ServerBrowser; -class DragNDropPanel; -class CTransparentPanel; -class CClassMenuPanel; -class CTeamMenuPanel; -class ChatPanel; - -char* GetVGUITGAName(const char *pszName); -BitmapTGA *LoadTGAForRes(const char* pImageName); -void ScaleColors( int &r, int &g, int &b, int a ); -extern char *sTFClassSelection[]; -extern int sTFValidClassInts[]; -extern char *sLocalisedClasses[]; - -#define MAX_SERVERNAME_LENGTH 32 -#define MAX_MAPNAME_LENGTH 32 - -// Command Menu positions -#define MAX_MENUS 80 -#define MAX_BUTTONS 100 - -#define BUTTON_SIZE_Y YRES(30) -#define CMENU_SIZE_X XRES(160) - -#define SUBMENU_SIZE_X (CMENU_SIZE_X / 8) -#define SUBMENU_SIZE_Y (BUTTON_SIZE_Y / 6) - -#define CMENU_TOP (BUTTON_SIZE_Y * 4) - -#define MAX_TEAMNAME_SIZE 64 -#define MAX_BUTTON_SIZE 32 - -// Map Briefing Window -#define MAPBRIEF_INDENT 30 - -// Team Menu -#define TMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) -#define TMENU_HEADER 100 -#define TMENU_SIZE_X (ScreenWidth - (TMENU_INDENT_X * 2)) -#define TMENU_SIZE_Y (TMENU_HEADER + BUTTON_SIZE_Y * 7) -#define TMENU_PLAYER_INDENT (((float)TMENU_SIZE_X / 3) * 2) -#define TMENU_INDENT_Y (((float)ScreenHeight - TMENU_SIZE_Y) / 2) - -// Class Menu -#define CLMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) -#define CLMENU_HEADER 100 -#define CLMENU_SIZE_X (ScreenWidth - (CLMENU_INDENT_X * 2)) -#define CLMENU_SIZE_Y (CLMENU_HEADER + BUTTON_SIZE_Y * 11) -#define CLMENU_PLAYER_INDENT (((float)CLMENU_SIZE_X / 3) * 2) -#define CLMENU_INDENT_Y (((float)ScreenHeight - CLMENU_SIZE_Y) / 2) - -// Arrows -enum -{ - ARROW_UP, - ARROW_DOWN, - ARROW_LEFT, - ARROW_RIGHT, -}; - -//============================================================================== -// VIEWPORT PIECES -//============================================================ -// Wrapper for an Image Label without a background -class CImageLabel : public Label -{ -public: - BitmapTGA *m_pTGA; - -public: - void LoadImage(const char * pImageName); - CImageLabel( const char* pImageName,int x,int y ); - CImageLabel( const char* pImageName,int x,int y,int wide,int tall ); - - virtual int getImageTall(); - virtual int getImageWide(); - - virtual void paintBackground() - { - // Do nothing, so the background's left transparent. - } -}; - -// Command Label -// Overridden label so we can darken it when submenus open -class CommandLabel : public Label -{ -private: - int m_iState; - -public: - CommandLabel(const char* text,int x,int y,int wide,int tall) : Label(text,x,y,wide,tall) - { - m_iState = false; - } - - void PushUp() - { - m_iState = false; - repaint(); - } - - void PushDown() - { - m_iState = true; - repaint(); - } -}; - -//============================================================ -// Command Buttons -class CommandButton : public Button -{ -private: - int m_iPlayerClass; - bool m_bFlat; - - // Submenus under this button - CCommandMenu *m_pSubMenu; - CCommandMenu *m_pParentMenu; - CommandLabel *m_pSubLabel; - - char m_sMainText[MAX_BUTTON_SIZE]; - char m_cBoundKey; - - SchemeHandle_t m_hTextScheme; - - void RecalculateText( void ); - -public: - bool m_bNoHighlight; - -public: - CommandButton(const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat); - // Constructors - CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight = false); - CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall, bool bFlat ); - - void Init( void ); - - // Menu Handling - void AddSubMenu( CCommandMenu *pNewMenu ); - void AddSubLabel( CommandLabel *pSubLabel ) - { - m_pSubLabel = pSubLabel; - } - - virtual int IsNotValid( void ) - { - return false; - } - - void UpdateSubMenus( int iAdjustment ); - int GetPlayerClass() { return m_iPlayerClass; }; - CCommandMenu *GetSubMenu() { return m_pSubMenu; }; - - CCommandMenu *getParentMenu( void ); - void setParentMenu( CCommandMenu *pParentMenu ); - - // Overloaded vgui functions - virtual void paint(); - virtual void setText( const char *text ); - virtual void paintBackground(); - - void cursorEntered( void ); - void cursorExited( void ); - - void setBoundKey( char boundKey ); - char getBoundKey( void ); -}; - -class ColorButton : public CommandButton -{ -private: - - Color *ArmedColor; - Color *UnArmedColor; - - Color *ArmedBorderColor; - Color *UnArmedBorderColor; - -public: - ColorButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat ) : - CommandButton( text, x, y, wide, tall, bNoHighlight, bFlat ) - { - ArmedColor = NULL; - UnArmedColor = NULL; - ArmedBorderColor = NULL; - UnArmedBorderColor = NULL; - } - - - virtual void paintBackground() - { - int r, g, b, a; - Color bgcolor; - - if ( isArmed() ) - { - // Highlight background - /* getBgColor(bgcolor); - bgcolor.getColor(r, g, b, a); - drawSetColor( r,g,b,a ); - drawFilledRect(0,0,_size[0],_size[1]);*/ - - if ( ArmedBorderColor ) - { - ArmedBorderColor->getColor( r, g, b, a); - drawSetColor( r, g, b, a ); - drawOutlinedRect(0,0,_size[0],_size[1]); - } - } - else - { - if ( UnArmedBorderColor ) - { - UnArmedBorderColor->getColor( r, g, b, a); - drawSetColor( r, g, b, a ); - drawOutlinedRect(0,0,_size[0],_size[1]); - } - } - } - void paint() - { - int r, g, b, a; - if ( isArmed() ) - { - if (ArmedColor) - { - ArmedColor->getColor(r, g, b, a); - setFgColor(r, g, b, a); - } - else - setFgColor( Scheme::sc_secondary2 ); - } - else - { - if (UnArmedColor) - { - UnArmedColor->getColor(r, g, b, a); - setFgColor(r, g, b, a); - } - else - setFgColor( Scheme::sc_primary1 ); - } - - Button::paint(); - } - - void setArmedColor ( int r, int g, int b, int a ) - { - ArmedColor = new Color( r, g, b, a ); - } - - void setUnArmedColor ( int r, int g, int b, int a ) - { - UnArmedColor = new Color( r, g, b, a ); - } - - void setArmedBorderColor ( int r, int g, int b, int a ) - { - ArmedBorderColor = new Color( r, g, b, a ); - } - - void setUnArmedBorderColor ( int r, int g, int b, int a ) - { - UnArmedBorderColor = new Color( r, g, b, a ); - } -}; - -class SpectButton : public CommandButton -{ -private: - -public: - SpectButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall ) : - CommandButton( text, x, y, wide, tall, false) - { - Init(); - - setText( text ); - } - - virtual void paintBackground() - { - if ( isArmed()) - { - drawSetColor( 143,143, 54, 125 ); - drawFilledRect( 5, 0,_size[0] - 5,_size[1]); - } - } - - virtual void paint() - { - - if ( isArmed() ) - { - setFgColor( 194, 202, 54, 0 ); - } - else - { - setFgColor( 143, 143, 54, 15 ); - } - - Button::paint(); - } -}; -//============================================================ -// Command Menus -class CCommandMenu : public Panel -{ -private: - CCommandMenu *m_pParentMenu; - int m_iXOffset; - int m_iYOffset; - - // Buttons in this menu - CommandButton *m_aButtons[ MAX_BUTTONS ]; - int m_iButtons; - - // opens menu from top to bottom (0 = default), or from bottom to top (1)? - int m_iDirection; -public: - CCommandMenu( CCommandMenu *pParentMenu, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) - { - m_pParentMenu = pParentMenu; - m_iXOffset = x; - m_iYOffset = y; - m_iButtons = 0; - m_iDirection = 0; - } - - CCommandMenu( CCommandMenu *pParentMenu, int direction, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) - { - m_pParentMenu = pParentMenu; - m_iXOffset = x; - m_iYOffset = y; - m_iButtons = 0; - m_iDirection = direction; - } - - float m_flButtonSizeY; - int m_iSpectCmdMenu; - void AddButton( CommandButton *pButton ); - bool RecalculateVisibles( int iNewYPos, bool bHideAll ); - void RecalculatePositions( int iYOffset ); - void MakeVisible( CCommandMenu *pChildMenu ); - - CCommandMenu *GetParentMenu() { return m_pParentMenu; }; - int GetXOffset() { return m_iXOffset; }; - int GetYOffset() { return m_iYOffset; }; - int GetDirection() { return m_iDirection; }; - int GetNumButtons() { return m_iButtons; }; - CommandButton *FindButtonWithSubmenu( CCommandMenu *pSubMenu ); - - void ClearButtonsOfArmedState( void ); - void RemoveAllButtons(void); - - bool KeyInput( int keyNum ); - - virtual void paintBackground(); -}; - -class SmartLabel : public vgui::Label -{ -public: - virtual void setText(int inTextBufferLen, const char* inText) - { - Label::setText(inTextBufferLen, inText); - this->mString = string(inText); - } - - virtual string getText() const - { - return this->mString; - } - -private: - string mString; -}; - -//============================================================================== -class TeamFortressViewport : public Panel -{ -private: - vgui::Cursor* _cursorNone; - vgui::Cursor* _cursorArrow; - - int m_iInitialized; - - CCommandMenu *m_pCommandMenus[ MAX_MENUS ]; - CCommandMenu *m_pCurrentCommandMenu; - float m_flMenuOpenTime; - float m_flScoreBoardLastUpdated; - float m_flSpectatorPanelLastUpdated; - int m_iNumMenus; - int m_iCurrentTeamNumber; - int m_iCurrentPlayerClass; - int m_iUser1; - int m_iUser2; - int m_iUser3; - - // VGUI Menus - void CreateTeamMenu( void ); - CMenuPanel* ShowTeamMenu( void ); - void CreateClassMenu( void ); - CMenuPanel* ShowClassMenu( void ); - void CreateSpectatorMenu( void ); - - // Scheme handler - CSchemeManager m_SchemeManager; - - // MOTD - int m_iGotAllMOTD; - char m_szMOTD[ MAX_MOTD_LENGTH ]; - - // Command Menu Team buttons - CommandButton *m_pTeamButtons[6]; - CommandButton *m_pDisguiseButtons[5]; - BuildButton *m_pBuildButtons[3]; - BuildButton *m_pBuildActiveButtons[3]; - - // Server Browser - ServerBrowser *m_pServerBrowser; - - // Spectator "menu" - CTransparentPanel *m_pSpectatorMenu; - Label *m_pSpectatorLabel; - Label *m_pSpectatorHelpLabel; - int m_iAllowSpectators; - - ChatPanel* m_chatPanel; - - // Data for specific sections of the Command Menu - int m_iValidClasses[5]; - int m_iIsFeigning; - int m_iIsSettingDetpack; - int m_iNumberOfTeams; - int m_iBuildState; - int m_iRandomPC; - char m_sTeamNames[5][MAX_TEAMNAME_SIZE]; - - // Localisation strings - char m_sDetpackStrings[3][MAX_BUTTON_SIZE]; - - char m_sMapName[MAX_MAPNAME_LENGTH]; -public: - TeamFortressViewport(int x,int y,int wide,int tall); - void Initialize( void ); - - int CreateCommandMenu( char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ); - void CreateScoreBoard( void ); - void CreateOptionsMenu(); - - void CreatePlayerMenu(); - void UpdatePlayerMenu(); - - void CreateServerBrowser( void ); - CommandButton * CreateCustomButton( char *pButtonText, char * pButtonName, int iYOffset ); - CCommandMenu * CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset = 0 ); - - void UpdateCursorState( void ); - void UpdateCommandMenu(int menuIndex); - void UpdateOnPlayerInfo( void ); - void UpdateHighlights( void ); - void UpdateSpectatorPanel( void ); - - int KeyInput( int down, int keynum, const char *pszCurrentBinding ); - void GetAllPlayersInfo( void ); - void DeathMsg( int killer, int victim ); - - ChatPanel* GetChatPanel(); - - void ShowCommandMenu(int menuIndex); - void InputSignalHideCommandMenu( void ); - void HideCommandMenu( void ); - void SetCurrentCommandMenu( CCommandMenu *pNewMenu ); - void SetCurrentMenu( CMenuPanel *pMenu ); - - void ShowScoreBoard( void ); - void HideScoreBoard( void ); - bool IsScoreBoardVisible( void ); - - void ShowOptionsMenu(); - void HideOptionsMenu(); - bool IsOptionsMenuVisible(); - - bool AllowedToPrintText( void ); - - void ShowVGUIMenu( int iMenu ); - void HideVGUIMenu( void ); - void HideTopMenu( void ); - - void ToggleServerBrowser( void ); - - CMenuPanel* CreateTextWindow( int iTextToShow ); - - CCommandMenu *CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu, int iYOffset, int iXOffset = 0 ); - - // Data Handlers - int GetValidClasses(int iTeam) { return m_iValidClasses[iTeam]; }; - int GetNumberOfTeams() { return m_iNumberOfTeams; }; - int GetIsFeigning() { return m_iIsFeigning; }; - int GetIsSettingDetpack() { return m_iIsSettingDetpack; }; - int GetBuildState() { return m_iBuildState; }; - int IsRandomPC() { return m_iRandomPC; }; - char *GetTeamName( int iTeam ); - int GetAllowSpectators() { return m_iAllowSpectators; }; - - // Message Handlers - int MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ); - int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); - - // Input - bool SlotInput( int iSlot ); - - virtual void paintBackground(); - - CSchemeManager *GetSchemeManager( void ) { return &m_SchemeManager; } - ScorePanel *GetScoreBoard( void ) { return m_pScoreBoard; } - - void *operator new( size_t stAllocateBlock ); - -public: - // VGUI Menus - CMenuPanel *m_pCurrentMenu; - CTeamMenuPanel *m_pTeamMenu; - int m_StandardMenu; // indexs in m_pCommandMenus - int m_SpectatorOptionsMenu; - int m_SpectatorCameraMenu; - int m_SpectatorPlayerMenu; - CClassMenuPanel *m_pClassMenu; - ScorePanel *m_pScoreBoard; - CTransparentPanel* mOptionsScreen; - CommandButton** mOptionsButtons; - - SpectatorPanel *m_pSpectatorPanel; - char m_szServerName[ MAX_SERVERNAME_LENGTH ]; -}; - -//============================================================ -// Command Menu Button Handlers -#define MAX_COMMAND_SIZE 256 - -class CMenuHandler_StringCommand : public ActionSignal -{ -protected: - char m_pszCommand[MAX_COMMAND_SIZE]; - int m_iCloseVGUIMenu; -public: - CMenuHandler_StringCommand( char *pszCommand ) - { - strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); - m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; - m_iCloseVGUIMenu = false; - } - - CMenuHandler_StringCommand( char *pszCommand, int iClose ) - { - strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); - m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; - m_iCloseVGUIMenu = true; - } - - virtual void actionPerformed(Panel* panel) - { - gEngfuncs.pfnClientCmd(m_pszCommand); - - if (m_iCloseVGUIMenu) - gViewPort->HideTopMenu(); - else - gViewPort->HideCommandMenu(); - } -}; - -class COptionsScreen_StringCommand : public CMenuHandler_StringCommand -{ -public: - COptionsScreen_StringCommand( char *pszCommand ) : CMenuHandler_StringCommand(pszCommand) - { - } - - virtual void actionPerformed(Panel* panel) - { - CMenuHandler_StringCommand::actionPerformed(panel); - - gViewPort->HideOptionsMenu(); - } -}; - - - -// This works the same as CMenuHandler_StringCommand, except it watches the string command -// for specific commands, and modifies client vars based upon them. -class CMenuHandler_StringCommandWatch : public CMenuHandler_StringCommand -{ -private: -public: - CMenuHandler_StringCommandWatch( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) - { - } - - CMenuHandler_StringCommandWatch( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) - { - } - - virtual void actionPerformed(Panel* panel) - { - CMenuHandler_StringCommand::actionPerformed( panel ); - - // Try to guess the player's new team (it'll be corrected if it's wrong) - if ( !strcmp( m_pszCommand, "jointeam 1" ) ) - g_iTeamNumber = 1; - else if ( !strcmp( m_pszCommand, "jointeam 2" ) ) - g_iTeamNumber = 2; - else if ( !strcmp( m_pszCommand, "jointeam 3" ) ) - g_iTeamNumber = 3; - else if ( !strcmp( m_pszCommand, "jointeam 4" ) ) - g_iTeamNumber = 4; - } -}; - -// Used instead of CMenuHandler_StringCommand for Class Selection buttons. -// Checks the state of hud_classautokill and kills the player if set -class CMenuHandler_StringCommandClassSelect : public CMenuHandler_StringCommand -{ -private: -public: - CMenuHandler_StringCommandClassSelect( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) - { - } - - CMenuHandler_StringCommandClassSelect( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) - { - } - - virtual void actionPerformed(Panel* panel); -}; - -class CMenuHandler_PopupSubMenuInput : public InputSignal -{ -private: - CCommandMenu *m_pSubMenu; - Button *m_pButton; -public: - CMenuHandler_PopupSubMenuInput( Button *pButton, CCommandMenu *pSubMenu ) - { - m_pSubMenu = pSubMenu; - m_pButton = pButton; - } - - virtual void cursorMoved(int x,int y,Panel* panel) - { - //gViewPort->SetCurrentCommandMenu( m_pSubMenu ); - } - - virtual void cursorEntered(Panel* panel) - { - gViewPort->SetCurrentCommandMenu( m_pSubMenu ); - - if (m_pButton) - m_pButton->setArmed(true); - }; - virtual void cursorExited(Panel* Panel) {}; - virtual void mousePressed(MouseCode code,Panel* panel) {}; - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; -}; - -class CMenuHandler_LabelInput : public InputSignal -{ -private: - ActionSignal *m_pActionSignal; -public: - CMenuHandler_LabelInput( ActionSignal *pSignal ) - { - m_pActionSignal = pSignal; - } - - virtual void mousePressed(MouseCode code,Panel* panel) - { - m_pActionSignal->actionPerformed( panel ); - } - - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void cursorEntered(Panel* panel) {}; - virtual void cursorExited(Panel* Panel) {}; - virtual void cursorMoved(int x,int y,Panel* panel) {}; - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; -}; - -#define HIDE_TEXTWINDOW 0 -#define SHOW_MAPBRIEFING 1 -#define SHOW_CLASSDESC 2 -#define SHOW_MOTD 3 -#define SHOW_SPECHELP 4 - -class CMenuHandler_TextWindow : public ActionSignal -{ -private: - int m_iState; -public: - CMenuHandler_TextWindow( int iState ) - { - m_iState = iState; - } - - virtual void actionPerformed(Panel* panel) - { - if (m_iState == HIDE_TEXTWINDOW) - { - gViewPort->HideTopMenu(); - } - else - { - gViewPort->HideCommandMenu(); - gViewPort->ShowVGUIMenu( m_iState ); - } - } -}; - -class CMenuHandler_ToggleCvar : public ActionSignal -{ -private: - struct cvar_s * m_cvar; - -public: - CMenuHandler_ToggleCvar( char * cvarname ) - { - m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); - } - - virtual void actionPerformed(Panel* panel) - { - if ( m_cvar->value ) - m_cvar->value = 0.0f; - else - m_cvar->value = 1.0f; - - gViewPort->UpdateSpectatorPanel(); - } - - -}; -class CDragNDropHandler : public InputSignal -{ -private: - DragNDropPanel* m_pPanel; - bool m_bDragging; - int m_iaDragOrgPos[2]; - int m_iaDragStart[2]; - -public: - CDragNDropHandler(DragNDropPanel* pPanel) - { - m_pPanel = pPanel; - m_bDragging = false; - } - - void cursorMoved(int x,int y,Panel* panel); - void mousePressed(MouseCode code,Panel* panel); - void mouseReleased(MouseCode code,Panel* panel); - - void mouseDoublePressed(MouseCode code,Panel* panel) {}; - void cursorEntered(Panel* panel) {}; - void cursorExited(Panel* panel) {}; - void mouseWheeled(int delta,Panel* panel) {}; - void keyPressed(KeyCode code,Panel* panel) {}; - void keyTyped(KeyCode code,Panel* panel) {}; - void keyReleased(KeyCode code,Panel* panel) {}; - void keyFocusTicked(Panel* panel) {}; -}; - -class CHandler_MenuButtonOver : public InputSignal -{ -private: - int m_iButton; - CMenuPanel *m_pMenuPanel; -public: - CHandler_MenuButtonOver( CMenuPanel *pPanel, int iButton ) - { - m_iButton = iButton; - m_pMenuPanel = pPanel; - } - - void cursorEntered(Panel *panel); - - void cursorMoved(int x,int y,Panel* panel) {}; - void mousePressed(MouseCode code,Panel* panel) {}; - void mouseReleased(MouseCode code,Panel* panel) {}; - void mouseDoublePressed(MouseCode code,Panel* panel) {}; - void cursorExited(Panel* panel) {}; - void mouseWheeled(int delta,Panel* panel) {}; - void keyPressed(KeyCode code,Panel* panel) {}; - void keyTyped(KeyCode code,Panel* panel) {}; - void keyReleased(KeyCode code,Panel* panel) {}; - void keyFocusTicked(Panel* panel) {}; -}; - -class CHandler_ButtonHighlight : public InputSignal -{ -private: - Button *m_pButton; -public: - CHandler_ButtonHighlight( Button *pButton ) - { - m_pButton = pButton; - } - - virtual void cursorEntered(Panel* panel) - { - m_pButton->setArmed(true); - }; - virtual void cursorExited(Panel* Panel) - { - m_pButton->setArmed(false); - }; - virtual void mousePressed(MouseCode code,Panel* panel) {}; - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void cursorMoved(int x,int y,Panel* panel) {}; - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; -}; - -//----------------------------------------------------------------------------- -// Purpose: Special handler for highlighting of command menu buttons -//----------------------------------------------------------------------------- -class CHandler_CommandButtonHighlight : public CHandler_ButtonHighlight -{ -private: - CommandButton *m_pCommandButton; -public: - CHandler_CommandButtonHighlight( CommandButton *pButton ) : CHandler_ButtonHighlight( pButton ) - { - m_pCommandButton = pButton; - } - - virtual void cursorEntered( Panel *panel ) - { - m_pCommandButton->cursorEntered(); - } - - virtual void cursorExited( Panel *panel ) - { - m_pCommandButton->cursorExited(); - } -}; - - -//================================================================ -// Overidden Command Buttons for special visibilities -class ClassButton : public CommandButton -{ -protected: - int m_iPlayerClass; - -public: - ClassButton( int iClass, const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) - { - m_iPlayerClass = iClass; - } - - virtual int IsNotValid(); -}; - -class TeamButton : public CommandButton -{ -private: - int m_iTeamNumber; -public: - TeamButton( int iTeam, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) - { - m_iTeamNumber = iTeam; - } - - virtual int IsNotValid() - { - int iTeams = gViewPort->GetNumberOfTeams(); - // Never valid if there's only 1 team - if (iTeams == 1) - return true; - - // Auto Team's always visible - if (m_iTeamNumber == 5) - return false; - - if (iTeams >= m_iTeamNumber && m_iTeamNumber != g_iTeamNumber) - return false; - - return true; - } -}; - -class FeignButton : public CommandButton -{ -private: - int m_iFeignState; -public: - FeignButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) - { - m_iFeignState = iState; - } - - virtual int IsNotValid() - { - // Only visible for spies - if (g_iPlayerClass != PC_SPY) - return true; - - if (m_iFeignState == gViewPort->GetIsFeigning()) - return false; - - return true; - } -}; - -class SpectateButton : public CommandButton -{ -public: - SpectateButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) - { - } - - virtual int IsNotValid() - { - // Only visible if the server allows it - if ( gViewPort->GetAllowSpectators() != 0 ) - return false; - - return true; - } -}; - -#define DISGUISE_TEAM1 (1<<0) -#define DISGUISE_TEAM2 (1<<1) -#define DISGUISE_TEAM3 (1<<2) -#define DISGUISE_TEAM4 (1<<3) - -class DisguiseButton : public CommandButton -{ -private: - int m_iValidTeamsBits; - int m_iThisTeam; -public: - DisguiseButton( int iValidTeamNumsBits, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall,false ) - { - m_iValidTeamsBits = iValidTeamNumsBits; - } - - virtual int IsNotValid() - { - // Only visible for spies - if ( g_iPlayerClass != PC_SPY ) - return true; - - // if it's not tied to a specific team, then always show (for spies) - if ( !m_iValidTeamsBits ) - return false; - - // if we're tied to a team make sure we can change to that team - int iTmp = 1 << (gViewPort->GetNumberOfTeams() - 1); - if ( m_iValidTeamsBits & iTmp ) - return false; - - return true; - } -}; - -class DetpackButton : public CommandButton -{ -private: - int m_iDetpackState; -public: - DetpackButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) - { - m_iDetpackState = iState; - } - - virtual int IsNotValid() - { - // Only visible for demomen - if (g_iPlayerClass != PC_DEMOMAN) - return true; - - if (m_iDetpackState == gViewPort->GetIsSettingDetpack()) - return false; - - return true; - } -}; - -extern int iBuildingCosts[]; -#define BUILDSTATE_HASBUILDING (1<<0) // Data is building ID (1 = Dispenser, 2 = Sentry) -#define BUILDSTATE_BUILDING (1<<1) -#define BUILDSTATE_BASE (1<<2) -#define BUILDSTATE_CANBUILD (1<<3) // Data is building ID (0 = Dispenser, 1 = Sentry) - -class BuildButton : public CommandButton -{ -private: - int m_iBuildState; - int m_iBuildData; - -public: - enum Buildings - { - DISPENSER = 0, - SENTRYGUN = 1, - }; - - BuildButton( int iState, int iData, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) - { - m_iBuildState = iState; - m_iBuildData = iData; - } - - virtual int IsNotValid() - { - // Only visible for engineers - if (g_iPlayerClass != PC_ENGINEER) - return true; - - // If this isn't set, it's only active when they're not building - if (m_iBuildState & BUILDSTATE_BUILDING) - { - // Make sure the player's building - if ( !(gViewPort->GetBuildState() & BS_BUILDING) ) - return true; - } - else - { - // Make sure the player's not building - if ( gViewPort->GetBuildState() & BS_BUILDING ) - return true; - } - - if (m_iBuildState & BUILDSTATE_BASE) - { - // Only appear if we've got enough metal to build something, or something already built - if ( gViewPort->GetBuildState() & (BS_HAS_SENTRYGUN | BS_HAS_DISPENSER | BS_CANB_SENTRYGUN | BS_CANB_DISPENSER) ) - return false; - - return true; - } - - // Must have a building - if (m_iBuildState & BUILDSTATE_HASBUILDING) - { - if ( m_iBuildData == BuildButton::DISPENSER && !(gViewPort->GetBuildState() & BS_HAS_DISPENSER) ) - return true; - if ( m_iBuildData == BuildButton::SENTRYGUN && !(gViewPort->GetBuildState() & BS_HAS_SENTRYGUN) ) - return true; - } - - // Can build something - if (m_iBuildState & BUILDSTATE_CANBUILD) - { - // Make sure they've got the ammo and don't have one already - if ( m_iBuildData == BuildButton::DISPENSER && (gViewPort->GetBuildState() & BS_CANB_DISPENSER) ) - return false; - if ( m_iBuildData == BuildButton::SENTRYGUN && (gViewPort->GetBuildState() & BS_CANB_SENTRYGUN) ) - return false; - - return true; - } - - return false; - } -}; - -#define MAX_MAPNAME 256 - -class MapButton : public CommandButton -{ -private: - char m_szMapName[ MAX_MAPNAME ]; - -public: - MapButton( const char *pMapName, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) - { - sprintf( m_szMapName, "maps/%s.bsp", pMapName ); - } - - virtual int IsNotValid() - { - const char *level = gEngfuncs.pfnGetLevelName(); - if (!level) - return true; - - // Does it match the current map name? - if ( strcmp(m_szMapName, level) ) - return true; - - return false; - } -}; - -//----------------------------------------------------------------------------- -// Purpose: CommandButton which is only displayed if the player is on team X -//----------------------------------------------------------------------------- -class TeamOnlyCommandButton : public CommandButton -{ -private: - int m_iTeamNum; - -public: - TeamOnlyCommandButton( int iTeamNum, const char* text,int x,int y,int wide,int tall, bool flat ) : - CommandButton( text, x, y, wide, tall, false, flat ), m_iTeamNum(iTeamNum) {} - - virtual int IsNotValid() - { - if ( g_iTeamNumber != m_iTeamNum ) - return true; - - return CommandButton::IsNotValid(); - } - - virtual void paintBackground() - { - if ( isArmed() ) - { - drawSetColor( 143,143, 54, 125 ); - drawFilledRect( 5, 0,_size[0] - 5,_size[1]); - } - } - - virtual void paint( void ) - { - if ( isArmed() ) - { - setFgColor( 194, 202, 54, 0 ); - } - else - { - setFgColor( 143, 143, 54, 15 ); - } - - Button::paint(); - } -}; - -//----------------------------------------------------------------------------- -// Purpose: CommandButton which is only displayed if the player is on team X -//----------------------------------------------------------------------------- -class ToggleCommandButton : public CommandButton, public InputSignal -{ -private: - struct cvar_s * m_cvar; - CImageLabel * pLabelOn; - CImageLabel * pLabelOff; - - -public: - ToggleCommandButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : - CommandButton( text, x, y, wide, tall, false, flat ) - { - m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); - - // Put a > to show it's a submenu - pLabelOn = new CImageLabel( "checked", 0, 0 ); - pLabelOn->setParent(this); - pLabelOn->addInputSignal(this); - - pLabelOff = new CImageLabel( "unchecked", 0, 0 ); - pLabelOff->setParent(this); - pLabelOff->setEnabled(true); - pLabelOff->addInputSignal(this); - - int textwide, texttall; - getTextSize( textwide, texttall); - - // Reposition - pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); - - pLabelOff->setPos( textwide, (tall - pLabelOff->getTall()) / 2 ); - - // Set text color to orange - setFgColor(Scheme::sc_primary1); - } - - virtual void cursorEntered(Panel* panel) - { - CommandButton::cursorEntered(); - } - - virtual void cursorExited(Panel* panel) - { - CommandButton::cursorExited(); - } - - virtual void mousePressed(MouseCode code,Panel* panel) - { - doClick(); - }; - - virtual void cursorMoved(int x,int y,Panel* panel) {}; - - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; - - virtual void paint( void ) - { - if ( !m_cvar ) - { - pLabelOff->setVisible(false); - pLabelOn->setVisible(false); - } - else if ( m_cvar->value ) - { - pLabelOff->setVisible(false); - pLabelOn->setVisible(true); - } - else - { - pLabelOff->setVisible(true); - pLabelOn->setVisible(false); - } - - CommandButton::paint(); - - } -}; -class SpectToggleButton : public CommandButton, public InputSignal -{ -private: - struct cvar_s * m_cvar; - CImageLabel * pLabelOn; - -public: - SpectToggleButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : - CommandButton( text, x, y, wide, tall, false, flat ) - { - m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); - - // Put a > to show it's a submenu - pLabelOn = new CImageLabel( "checked", 0, 0 ); - pLabelOn->setParent(this); - pLabelOn->addInputSignal(this); - - - int textwide, texttall; - getTextSize( textwide, texttall); - - // Reposition - pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); - } - - virtual void cursorEntered(Panel* panel) - { - CommandButton::cursorEntered(); - } - - virtual void cursorExited(Panel* panel) - { - CommandButton::cursorExited(); - } - - virtual void mousePressed(MouseCode code,Panel* panel) - { - doClick(); - }; - - virtual void cursorMoved(int x,int y,Panel* panel) {}; - - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; - virtual void mouseReleased(MouseCode code,Panel* panel) {}; - virtual void mouseWheeled(int delta,Panel* panel) {}; - virtual void keyPressed(KeyCode code,Panel* panel) {}; - virtual void keyTyped(KeyCode code,Panel* panel) {}; - virtual void keyReleased(KeyCode code,Panel* panel) {}; - virtual void keyFocusTicked(Panel* panel) {}; - - virtual void paintBackground() - { - if ( isArmed() ) - { - drawSetColor( 143,143, 54, 125 ); - drawFilledRect( 5, 0,_size[0] - 5,_size[1]); - } - } - - virtual void paint( void ) - { - if ( isArmed() ) - { - setFgColor( 194, 202, 54, 0 ); - } - else - { - setFgColor( 143, 143, 54, 15 ); - } - - if ( !m_cvar ) - { - pLabelOn->setVisible(false); - } - else if ( m_cvar->value ) - { - pLabelOn->setVisible(true); - } - else - { - pLabelOn->setVisible(false); - } - - Button::paint(); - } -}; - -/* -class SpectToggleButton : public ToggleCommandButton -{ -private: - struct cvar_s * m_cvar; - CImageLabel * pLabelOn; - CImageLabel * pLabelOff; - -public: - - SpectToggleButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : - ToggleCommandButton( cvarname, text, x, y, wide, tall, flat, TRUE ) - { - m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); - - // Put a > to show it's a submenu - pLabelOn = new CImageLabel( "checked", 0, 0 ); - pLabelOn->setParent(this); - pLabelOn->addInputSignal(this); - - pLabelOff = new CImageLabel( "unchecked", 0, 0 ); - pLabelOff->setParent(this); - pLabelOff->setEnabled(true); - pLabelOff->addInputSignal(this); - - int textwide, texttall; - getTextSize( textwide, texttall); - - // Reposition - pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); - - pLabelOff->setPos( textwide, (tall - pLabelOff->getTall()) / 2 ); - - // Set text color to orange - setFgColor(Scheme::sc_primary1); - } - - virtual void paintBackground() - { - if ( isArmed()) - { - drawSetColor( 143,143, 54, 125 ); - drawFilledRect( 5, 0,_size[0] - 5,_size[1]); - } - } - - virtual void paint() - { - - if ( isArmed() ) - { - setFgColor( 194, 202, 54, 0 ); - } - else - { - setFgColor( 143, 143, 54, 15 ); - } - - if ( !m_cvar ) - { - pLabelOff->setVisible(false); - pLabelOn->setVisible(false); - } - else if ( m_cvar->value ) - { - pLabelOff->setVisible(false); - pLabelOn->setVisible(true); - } - else - { - pLabelOff->setVisible(true); - pLabelOn->setVisible(false); - } - - Button::paint(); - } -}; -*/ -//============================================================ -// Panel that can be dragged around -class DragNDropPanel : public Panel -{ -private: - bool m_bBeingDragged; - LineBorder *m_pBorder; -public: - DragNDropPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) - { - m_bBeingDragged = false; - - // Create the Drag Handler - addInputSignal( new CDragNDropHandler(this) ); - - // Create the border (for dragging) - m_pBorder = new LineBorder(); - } - - virtual void setDragged( bool bState ) - { - m_bBeingDragged = bState; - - if (m_bBeingDragged) - setBorder(m_pBorder); - else - setBorder(NULL); - } -}; - -//================================================================ -// Panel that draws itself with a transparent black background -class CTransparentPanel : public Panel -{ -private: - int m_iTransparency; -public: - CTransparentPanel(int iTrans, int x,int y,int wide,int tall) : Panel(x,y,wide,tall) - { - m_iTransparency = iTrans; - } - - void SetTransparency(int inTransparency) - { - m_iTransparency = inTransparency; - } - - virtual void paintBackground() - { - if (m_iTransparency) - { - // Transparent black background - drawSetColor( 0,0,0, m_iTransparency ); - drawFilledRect(0,0,_size[0],_size[1]); - } - } -}; - -//================================================================ -// Menu Panel that supports buffering of menus -class CMenuPanel : public CTransparentPanel -{ -private: - CMenuPanel *m_pNextMenu; - int m_iMenuID; - int m_iRemoveMe; - int m_iIsActive; - float m_flOpenTime; -public: - CMenuPanel(int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(100, x,y,wide,tall) - { - Reset(); - m_iRemoveMe = iRemoveMe; - } - - CMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(iTrans, x,y,wide,tall) - { - Reset(); - m_iRemoveMe = iRemoveMe; - } - - virtual void Reset( void ) - { - m_pNextMenu = NULL; - m_iIsActive = false; - m_flOpenTime = 0; - } - - void SetNextMenu( CMenuPanel *pNextPanel ) - { - if (m_pNextMenu) - m_pNextMenu->SetNextMenu( pNextPanel ); - else - m_pNextMenu = pNextPanel; - } - - void SetMenuID( int iID ) - { - m_iMenuID = iID; - } - - void SetActive( int iState ) - { - m_iIsActive = iState; - } - - virtual void Open( void ) - { - setVisible( true ); - - // Note the open time, so we can delay input for a bit - m_flOpenTime = gHUD.m_flTime; - } - - virtual void Close( void ) - { - setVisible( false ); - m_iIsActive = false; - - if ( m_iRemoveMe ) - gViewPort->removeChild( this ); - - // This MenuPanel has now been deleted. Don't append code here. - } - - int ShouldBeRemoved() { return m_iRemoveMe; }; - CMenuPanel* GetNextMenu() { return m_pNextMenu; }; - int GetMenuID() { return m_iMenuID; }; - int IsActive() { return m_iIsActive; }; - float GetOpenTime() { return m_flOpenTime; }; - - // Numeric input - virtual bool SlotInput( int iSlot ) { return false; }; - virtual void SetActiveInfo( int iInput ) {}; -}; - -//================================================================ -// Custom drawn scroll bars -class CTFScrollButton : public CommandButton -{ -private: - BitmapTGA *m_pTGA; - -public: - CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall); - - virtual void paint( void ); - virtual void paintBackground( void ); -}; - -// Custom drawn slider bar -class CTFSlider : public Slider -{ -public: - CTFSlider(int x,int y,int wide,int tall,bool vertical) : Slider(x,y,wide,tall,vertical) - { - }; - - virtual void paintBackground( void ); -}; - -// Custom drawn scrollpanel -class CTFScrollPanel : public ScrollPanel -{ -public: - CTFScrollPanel(int x,int y,int wide,int tall); -}; - -//================================================================ -// Menu Panels that take key input -//============================================================ -class CClassMenuPanel : public CMenuPanel -{ -private: - CTransparentPanel *m_pClassInfoPanel[PC_LASTCLASS]; - Label *m_pPlayers[PC_LASTCLASS]; - ClassButton *m_pButtons[PC_LASTCLASS]; - CommandButton *m_pCancelButton; - ScrollPanel *m_pScrollPanel; - - CImageLabel *m_pClassImages[MAX_TEAMS][PC_LASTCLASS]; - - int m_iCurrentInfo; - - enum { STRLENMAX_PLAYERSONTEAM = 128 }; - char m_sPlayersOnTeamString[STRLENMAX_PLAYERSONTEAM]; - -public: - CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall); - - virtual bool SlotInput( int iSlot ); - virtual void Open( void ); - virtual void Update( void ); - virtual void SetActiveInfo( int iInput ); - virtual void Initialize( void ); - - virtual void Reset( void ) - { - CMenuPanel::Reset(); - m_iCurrentInfo = 0; - } -}; - -class CTeamMenuPanel : public CMenuPanel -{ -public: - ScrollPanel *m_pScrollPanel; - CTransparentPanel *m_pTeamWindow; - Label *m_pMapTitle; - TextPanel *m_pBriefing; - TextPanel *m_pTeamInfoPanel[6]; - CommandButton *m_pButtons[6]; - bool m_bUpdatedMapName; - CommandButton *m_pCancelButton; - CommandButton *m_pSpectateButton; - - int m_iCurrentInfo; - -public: - CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall); - - virtual bool SlotInput( int iSlot ); - virtual void Open( void ); - virtual void Update( void ); - virtual void SetActiveInfo( int iInput ); - virtual void paintBackground( void ); - - virtual void Initialize( void ); - - virtual void Reset( void ) - { - CMenuPanel::Reset(); - m_iCurrentInfo = 0; - } -}; - -//========================================================= -// Specific Menus to handle old HUD sections -class CHealthPanel : public DragNDropPanel -{ -private: - BitmapTGA *m_pHealthTGA; - Label *m_pHealthLabel; -public: - CHealthPanel(int x,int y,int wide,int tall) : DragNDropPanel(x,y,wide,tall) - { - // Load the Health icon - FileInputStream* fis = new FileInputStream( GetVGUITGAName("%d_hud_health"), false); - m_pHealthTGA = new BitmapTGA(fis,true); - fis->close(); - - // Create the Health Label - int iXSize,iYSize; - m_pHealthTGA->getSize(iXSize,iYSize); - m_pHealthLabel = new Label("",0,0,iXSize,iYSize); - m_pHealthLabel->setImage(m_pHealthTGA); - m_pHealthLabel->setParent(this); - - // Set panel dimension - // Shouldn't be needed once Billy's fized setImage not recalculating the size - //setSize( iXSize + 100, gHUD.m_iFontHeight + 10 ); - //m_pHealthLabel->setPos( 10, (getTall() - iYSize) / 2 ); - } - - virtual void paintBackground() - { - } - - void paint() - { - // Get the paint color - int r,g,b,a; - // Has health changed? Flash the health # - if (gHUD.m_Health.m_fFade) - { - gHUD.m_Health.m_fFade -= (gHUD.m_flTimeDelta * 20); - if (gHUD.m_Health.m_fFade <= 0) - { - a = MIN_ALPHA; - gHUD.m_Health.m_fFade = 0; - } - - // Fade the health number back to dim - a = MIN_ALPHA + (gHUD.m_Health.m_fFade/FADE_TIME) * 128; - } - else - a = MIN_ALPHA; - - gHUD.m_Health.GetPainColor( r, g, b ); - ScaleColors(r, g, b, a ); - - // If health is getting low, make it bright red - if (gHUD.m_Health.m_iHealth <= 15) - a = 255; - - int iXSize,iYSize, iXPos, iYPos; - m_pHealthTGA->getSize(iXSize,iYSize); - m_pHealthTGA->getPos(iXPos, iYPos); - - // Paint the player's health - int x = gHUD.DrawHudNumber( iXPos + iXSize + 5, iYPos + 5, DHN_3DIGITS | DHN_DRAWZERO, gHUD.m_Health.m_iHealth, r, g, b); - - // Draw the vertical line - int HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - x += HealthWidth / 2; - FillRGBA(x, iYPos + 5, HealthWidth / 10, gHUD.m_iFontHeight, 255, 160, 0, a); - } -}; - -#endif + +#ifndef TEAMFORTRESSVIEWPORT_H +#define TEAMFORTRESSVIEWPORT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CLabelHeader.h" +#include "vgui_listbox.h" +#include "vgui_grid.h" + + +// custom scheme handling +#include "vgui_SchemeManager.h" + +#define TF_DEFS_ONLY +#include "tf_defs.h" + +using namespace vgui; + +class Cursor; +class ScorePanel; +class SpectatorPanel; +class CCommandMenu; +class CommandLabel; +class CommandButton; +class BuildButton; +class ClassButton; +class CMenuPanel; +class ServerBrowser; +class DragNDropPanel; +class CTransparentPanel; +class CClassMenuPanel; +class CTeamMenuPanel; +class ChatPanel; + +char* GetVGUITGAName(const char *pszName); +BitmapTGA *LoadTGAForRes(const char* pImageName); +void ScaleColors( int &r, int &g, int &b, int a ); +extern char *sTFClassSelection[]; +extern int sTFValidClassInts[]; +extern char *sLocalisedClasses[]; + +#define MAX_SERVERNAME_LENGTH 32 +#define MAX_MAPNAME_LENGTH 32 + +// Command Menu positions +#define MAX_MENUS 80 +#define MAX_BUTTONS 100 + +#define BUTTON_SIZE_Y YRES(30) +#define CMENU_SIZE_X XRES(160) + +#define SUBMENU_SIZE_X (CMENU_SIZE_X / 8) +#define SUBMENU_SIZE_Y (BUTTON_SIZE_Y / 6) + +#define CMENU_TOP (BUTTON_SIZE_Y * 4) + +#define MAX_TEAMNAME_SIZE 64 +#define MAX_BUTTON_SIZE 32 + +// Map Briefing Window +#define MAPBRIEF_INDENT 30 + +// Team Menu +#define TMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) +#define TMENU_HEADER 100 +#define TMENU_SIZE_X (ScreenWidth - (TMENU_INDENT_X * 2)) +#define TMENU_SIZE_Y (TMENU_HEADER + BUTTON_SIZE_Y * 7) +#define TMENU_PLAYER_INDENT (((float)TMENU_SIZE_X / 3) * 2) +#define TMENU_INDENT_Y (((float)ScreenHeight - TMENU_SIZE_Y) / 2) + +// Class Menu +#define CLMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) +#define CLMENU_HEADER 100 +#define CLMENU_SIZE_X (ScreenWidth - (CLMENU_INDENT_X * 2)) +#define CLMENU_SIZE_Y (CLMENU_HEADER + BUTTON_SIZE_Y * 11) +#define CLMENU_PLAYER_INDENT (((float)CLMENU_SIZE_X / 3) * 2) +#define CLMENU_INDENT_Y (((float)ScreenHeight - CLMENU_SIZE_Y) / 2) + +// Arrows +enum +{ + ARROW_UP, + ARROW_DOWN, + ARROW_LEFT, + ARROW_RIGHT, +}; + +//============================================================================== +// VIEWPORT PIECES +//============================================================ +// Wrapper for an Image Label without a background +class CImageLabel : public Label +{ +public: + BitmapTGA *m_pTGA; + +public: + void LoadImage(const char * pImageName); + CImageLabel( const char* pImageName,int x,int y ); + CImageLabel( const char* pImageName,int x,int y,int wide,int tall ); + + virtual int getImageTall(); + virtual int getImageWide(); + + virtual void paintBackground() + { + // Do nothing, so the background's left transparent. + } +}; + +// Command Label +// Overridden label so we can darken it when submenus open +class CommandLabel : public Label +{ +private: + int m_iState; + +public: + CommandLabel(const char* text,int x,int y,int wide,int tall) : Label(text,x,y,wide,tall) + { + m_iState = false; + } + + void PushUp() + { + m_iState = false; + repaint(); + } + + void PushDown() + { + m_iState = true; + repaint(); + } +}; + +//============================================================ +// Command Buttons +class CommandButton : public Button +{ +private: + int m_iPlayerClass; + bool m_bFlat; + + // Submenus under this button + CCommandMenu *m_pSubMenu; + CCommandMenu *m_pParentMenu; + CommandLabel *m_pSubLabel; + + char m_sMainText[MAX_BUTTON_SIZE]; + char m_cBoundKey; + + SchemeHandle_t m_hTextScheme; + + void RecalculateText( void ); + +public: + bool m_bNoHighlight; + +public: + CommandButton(const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat); + // Constructors + CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight = false); + CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall, bool bFlat ); + + void Init( void ); + + // Menu Handling + void AddSubMenu( CCommandMenu *pNewMenu ); + void AddSubLabel( CommandLabel *pSubLabel ) + { + m_pSubLabel = pSubLabel; + } + + virtual int IsNotValid( void ) + { + return false; + } + + void UpdateSubMenus( int iAdjustment ); + int GetPlayerClass() { return m_iPlayerClass; }; + CCommandMenu *GetSubMenu() { return m_pSubMenu; }; + + CCommandMenu *getParentMenu( void ); + void setParentMenu( CCommandMenu *pParentMenu ); + + // Overloaded vgui functions + virtual void paint(); + virtual void setText( const char *text ); + virtual void paintBackground(); + + void cursorEntered( void ); + void cursorExited( void ); + + void setBoundKey( char boundKey ); + char getBoundKey( void ); +}; + +class ColorButton : public CommandButton +{ +private: + + Color *ArmedColor; + Color *UnArmedColor; + + Color *ArmedBorderColor; + Color *UnArmedBorderColor; + +public: + ColorButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat ) : + CommandButton( text, x, y, wide, tall, bNoHighlight, bFlat ) + { + ArmedColor = NULL; + UnArmedColor = NULL; + ArmedBorderColor = NULL; + UnArmedBorderColor = NULL; + } + + + virtual void paintBackground() + { + int r, g, b, a; + Color bgcolor; + + if ( isArmed() ) + { + // Highlight background + /* getBgColor(bgcolor); + bgcolor.getColor(r, g, b, a); + drawSetColor( r,g,b,a ); + drawFilledRect(0,0,_size[0],_size[1]);*/ + + if ( ArmedBorderColor ) + { + ArmedBorderColor->getColor( r, g, b, a); + drawSetColor( r, g, b, a ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + else + { + if ( UnArmedBorderColor ) + { + UnArmedBorderColor->getColor( r, g, b, a); + drawSetColor( r, g, b, a ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + } + void paint() + { + int r, g, b, a; + if ( isArmed() ) + { + if (ArmedColor) + { + ArmedColor->getColor(r, g, b, a); + setFgColor(r, g, b, a); + } + else + setFgColor( Scheme::sc_secondary2 ); + } + else + { + if (UnArmedColor) + { + UnArmedColor->getColor(r, g, b, a); + setFgColor(r, g, b, a); + } + else + setFgColor( Scheme::sc_primary1 ); + } + + Button::paint(); + } + + void setArmedColor ( int r, int g, int b, int a ) + { + ArmedColor = new Color( r, g, b, a ); + } + + void setUnArmedColor ( int r, int g, int b, int a ) + { + UnArmedColor = new Color( r, g, b, a ); + } + + void setArmedBorderColor ( int r, int g, int b, int a ) + { + ArmedBorderColor = new Color( r, g, b, a ); + } + + void setUnArmedBorderColor ( int r, int g, int b, int a ) + { + UnArmedBorderColor = new Color( r, g, b, a ); + } +}; + +class SpectButton : public CommandButton +{ +private: + +public: + SpectButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall ) : + CommandButton( text, x, y, wide, tall, false) + { + Init(); + + setText( text ); + } + + virtual void paintBackground() + { + if ( isArmed()) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint() + { + + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + Button::paint(); + } +}; +//============================================================ +// Command Menus +class CCommandMenu : public Panel +{ +private: + CCommandMenu *m_pParentMenu; + int m_iXOffset; + int m_iYOffset; + + // Buttons in this menu + CommandButton *m_aButtons[ MAX_BUTTONS ]; + int m_iButtons; + + // opens menu from top to bottom (0 = default), or from bottom to top (1)? + int m_iDirection; +public: + CCommandMenu( CCommandMenu *pParentMenu, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) + { + m_pParentMenu = pParentMenu; + m_iXOffset = x; + m_iYOffset = y; + m_iButtons = 0; + m_iDirection = 0; + } + + CCommandMenu( CCommandMenu *pParentMenu, int direction, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) + { + m_pParentMenu = pParentMenu; + m_iXOffset = x; + m_iYOffset = y; + m_iButtons = 0; + m_iDirection = direction; + } + + float m_flButtonSizeY; + int m_iSpectCmdMenu; + void AddButton( CommandButton *pButton ); + bool RecalculateVisibles( int iNewYPos, bool bHideAll ); + void RecalculatePositions( int iYOffset ); + void MakeVisible( CCommandMenu *pChildMenu ); + + CCommandMenu *GetParentMenu() { return m_pParentMenu; }; + int GetXOffset() { return m_iXOffset; }; + int GetYOffset() { return m_iYOffset; }; + int GetDirection() { return m_iDirection; }; + int GetNumButtons() { return m_iButtons; }; + CommandButton *FindButtonWithSubmenu( CCommandMenu *pSubMenu ); + + void ClearButtonsOfArmedState( void ); + void RemoveAllButtons(void); + + bool KeyInput( int keyNum ); + + virtual void paintBackground(); +}; + +class SmartLabel : public vgui::Label +{ +public: + virtual void setText(int inTextBufferLen, const char* inText) + { + Label::setText(inTextBufferLen, inText); + this->mString = string(inText); + } + + virtual string getText() const + { + return this->mString; + } + +private: + string mString; +}; + +//============================================================================== +class TeamFortressViewport : public Panel +{ +private: + vgui::Cursor* _cursorNone; + vgui::Cursor* _cursorArrow; + + int m_iInitialized; + + CCommandMenu *m_pCommandMenus[ MAX_MENUS ]; + CCommandMenu *m_pCurrentCommandMenu; + float m_flMenuOpenTime; + float m_flScoreBoardLastUpdated; + float m_flSpectatorPanelLastUpdated; + int m_iNumMenus; + int m_iCurrentTeamNumber; + int m_iCurrentPlayerClass; + int m_iUser1; + int m_iUser2; + int m_iUser3; + + // VGUI Menus + void CreateTeamMenu( void ); + CMenuPanel* ShowTeamMenu( void ); + void CreateClassMenu( void ); + CMenuPanel* ShowClassMenu( void ); + void CreateSpectatorMenu( void ); + + // Scheme handler + CSchemeManager m_SchemeManager; + + // MOTD + int m_iGotAllMOTD; + char m_szMOTD[ MAX_MOTD_LENGTH ]; + + // Command Menu Team buttons + CommandButton *m_pTeamButtons[6]; + CommandButton *m_pDisguiseButtons[5]; + BuildButton *m_pBuildButtons[3]; + BuildButton *m_pBuildActiveButtons[3]; + + // Server Browser + ServerBrowser *m_pServerBrowser; + + // Spectator "menu" + CTransparentPanel *m_pSpectatorMenu; + Label *m_pSpectatorLabel; + Label *m_pSpectatorHelpLabel; + int m_iAllowSpectators; + + ChatPanel* m_chatPanel; + + // Data for specific sections of the Command Menu + int m_iValidClasses[5]; + int m_iIsFeigning; + int m_iIsSettingDetpack; + int m_iNumberOfTeams; + int m_iBuildState; + int m_iRandomPC; + char m_sTeamNames[5][MAX_TEAMNAME_SIZE]; + + // Localisation strings + char m_sDetpackStrings[3][MAX_BUTTON_SIZE]; + + char m_sMapName[MAX_MAPNAME_LENGTH]; +public: + TeamFortressViewport(int x,int y,int wide,int tall); + void Initialize( void ); + + int CreateCommandMenu( char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ); + void CreateScoreBoard( void ); + void CreateOptionsMenu(); + + void CreatePlayerMenu(); + void UpdatePlayerMenu(); + + void CreateServerBrowser( void ); + CommandButton * CreateCustomButton( char *pButtonText, char * pButtonName, int iYOffset ); + CCommandMenu * CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset = 0 ); + + void UpdateCursorState( void ); + void UpdateCommandMenu(int menuIndex); + void UpdateOnPlayerInfo( void ); + void UpdateHighlights( void ); + void UpdateSpectatorPanel( void ); + + int KeyInput( int down, int keynum, const char *pszCurrentBinding ); + void GetAllPlayersInfo( void ); + void DeathMsg( int killer, int victim ); + + ChatPanel* GetChatPanel(); + + void ShowCommandMenu(int menuIndex); + void InputSignalHideCommandMenu( void ); + void HideCommandMenu( void ); + void SetCurrentCommandMenu( CCommandMenu *pNewMenu ); + void SetCurrentMenu( CMenuPanel *pMenu ); + + void ShowScoreBoard( void ); + void HideScoreBoard( void ); + bool IsScoreBoardVisible( void ); + + void ShowOptionsMenu(); + void HideOptionsMenu(); + bool IsOptionsMenuVisible(); + + bool AllowedToPrintText( void ); + + void ShowVGUIMenu( int iMenu ); + void HideVGUIMenu( void ); + void HideTopMenu( void ); + + void ToggleServerBrowser( void ); + + CMenuPanel* CreateTextWindow( int iTextToShow ); + + CCommandMenu *CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu, int iYOffset, int iXOffset = 0 ); + + // Data Handlers + int GetValidClasses(int iTeam) { return m_iValidClasses[iTeam]; }; + int GetNumberOfTeams() { return m_iNumberOfTeams; }; + int GetIsFeigning() { return m_iIsFeigning; }; + int GetIsSettingDetpack() { return m_iIsSettingDetpack; }; + int GetBuildState() { return m_iBuildState; }; + int IsRandomPC() { return m_iRandomPC; }; + char *GetTeamName( int iTeam ); + int GetAllowSpectators() { return m_iAllowSpectators; }; + + // Message Handlers + int MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + + // Input + bool SlotInput( int iSlot ); + + virtual void paintBackground(); + + CSchemeManager *GetSchemeManager( void ) { return &m_SchemeManager; } + ScorePanel *GetScoreBoard( void ) { return m_pScoreBoard; } + + void *operator new( size_t stAllocateBlock ); + +public: + // VGUI Menus + CMenuPanel *m_pCurrentMenu; + CTeamMenuPanel *m_pTeamMenu; + int m_StandardMenu; // indexs in m_pCommandMenus + int m_SpectatorOptionsMenu; + int m_SpectatorCameraMenu; + int m_SpectatorPlayerMenu; + CClassMenuPanel *m_pClassMenu; + ScorePanel *m_pScoreBoard; + CTransparentPanel* mOptionsScreen; + CommandButton** mOptionsButtons; + + SpectatorPanel *m_pSpectatorPanel; + char m_szServerName[ MAX_SERVERNAME_LENGTH ]; +}; + +//============================================================ +// Command Menu Button Handlers +#define MAX_COMMAND_SIZE 256 + +class CMenuHandler_StringCommand : public ActionSignal +{ +protected: + char m_pszCommand[MAX_COMMAND_SIZE]; + int m_iCloseVGUIMenu; +public: + CMenuHandler_StringCommand( char *pszCommand ) + { + strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); + m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; + m_iCloseVGUIMenu = false; + } + + CMenuHandler_StringCommand( char *pszCommand, int iClose ) + { + strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); + m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; + m_iCloseVGUIMenu = true; + } + + virtual void actionPerformed(Panel* panel) + { + gEngfuncs.pfnClientCmd(m_pszCommand); + + if (m_iCloseVGUIMenu) + gViewPort->HideTopMenu(); + else + gViewPort->HideCommandMenu(); + } +}; + +class COptionsScreen_StringCommand : public CMenuHandler_StringCommand +{ +public: + COptionsScreen_StringCommand( char *pszCommand ) : CMenuHandler_StringCommand(pszCommand) + { + } + + virtual void actionPerformed(Panel* panel) + { + CMenuHandler_StringCommand::actionPerformed(panel); + + gViewPort->HideOptionsMenu(); + } +}; + + + +// This works the same as CMenuHandler_StringCommand, except it watches the string command +// for specific commands, and modifies client vars based upon them. +class CMenuHandler_StringCommandWatch : public CMenuHandler_StringCommand +{ +private: +public: + CMenuHandler_StringCommandWatch( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) + { + } + + CMenuHandler_StringCommandWatch( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) + { + } + + virtual void actionPerformed(Panel* panel) + { + CMenuHandler_StringCommand::actionPerformed( panel ); + + // Try to guess the player's new team (it'll be corrected if it's wrong) + if ( !strcmp( m_pszCommand, "jointeam 1" ) ) + g_iTeamNumber = 1; + else if ( !strcmp( m_pszCommand, "jointeam 2" ) ) + g_iTeamNumber = 2; + else if ( !strcmp( m_pszCommand, "jointeam 3" ) ) + g_iTeamNumber = 3; + else if ( !strcmp( m_pszCommand, "jointeam 4" ) ) + g_iTeamNumber = 4; + } +}; + +// Used instead of CMenuHandler_StringCommand for Class Selection buttons. +// Checks the state of hud_classautokill and kills the player if set +class CMenuHandler_StringCommandClassSelect : public CMenuHandler_StringCommand +{ +private: +public: + CMenuHandler_StringCommandClassSelect( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) + { + } + + CMenuHandler_StringCommandClassSelect( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) + { + } + + virtual void actionPerformed(Panel* panel); +}; + +class CMenuHandler_PopupSubMenuInput : public InputSignal +{ +private: + CCommandMenu *m_pSubMenu; + Button *m_pButton; +public: + CMenuHandler_PopupSubMenuInput( Button *pButton, CCommandMenu *pSubMenu ) + { + m_pSubMenu = pSubMenu; + m_pButton = pButton; + } + + virtual void cursorMoved(int x,int y,Panel* panel) + { + //gViewPort->SetCurrentCommandMenu( m_pSubMenu ); + } + + virtual void cursorEntered(Panel* panel) + { + gViewPort->SetCurrentCommandMenu( m_pSubMenu ); + + if (m_pButton) + m_pButton->setArmed(true); + }; + virtual void cursorExited(Panel* Panel) {}; + virtual void mousePressed(MouseCode code,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class CMenuHandler_LabelInput : public InputSignal +{ +private: + ActionSignal *m_pActionSignal; +public: + CMenuHandler_LabelInput( ActionSignal *pSignal ) + { + m_pActionSignal = pSignal; + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + m_pActionSignal->actionPerformed( panel ); + } + + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void cursorEntered(Panel* panel) {}; + virtual void cursorExited(Panel* Panel) {}; + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +#define HIDE_TEXTWINDOW 0 +#define SHOW_MAPBRIEFING 1 +#define SHOW_CLASSDESC 2 +#define SHOW_MOTD 3 +#define SHOW_SPECHELP 4 + +class CMenuHandler_TextWindow : public ActionSignal +{ +private: + int m_iState; +public: + CMenuHandler_TextWindow( int iState ) + { + m_iState = iState; + } + + virtual void actionPerformed(Panel* panel) + { + if (m_iState == HIDE_TEXTWINDOW) + { + gViewPort->HideTopMenu(); + } + else + { + gViewPort->HideCommandMenu(); + gViewPort->ShowVGUIMenu( m_iState ); + } + } +}; + +class CMenuHandler_ToggleCvar : public ActionSignal +{ +private: + struct cvar_s * m_cvar; + +public: + CMenuHandler_ToggleCvar( char * cvarname ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + } + + virtual void actionPerformed(Panel* panel) + { + if ( m_cvar->value ) + m_cvar->value = 0.0f; + else + m_cvar->value = 1.0f; + + gViewPort->UpdateSpectatorPanel(); + } + + +}; +class CDragNDropHandler : public InputSignal +{ +private: + DragNDropPanel* m_pPanel; + bool m_bDragging; + int m_iaDragOrgPos[2]; + int m_iaDragStart[2]; + +public: + CDragNDropHandler(DragNDropPanel* pPanel) + { + m_pPanel = pPanel; + m_bDragging = false; + } + + void cursorMoved(int x,int y,Panel* panel); + void mousePressed(MouseCode code,Panel* panel); + void mouseReleased(MouseCode code,Panel* panel); + + void mouseDoublePressed(MouseCode code,Panel* panel) {}; + void cursorEntered(Panel* panel) {}; + void cursorExited(Panel* panel) {}; + void mouseWheeled(int delta,Panel* panel) {}; + void keyPressed(KeyCode code,Panel* panel) {}; + void keyTyped(KeyCode code,Panel* panel) {}; + void keyReleased(KeyCode code,Panel* panel) {}; + void keyFocusTicked(Panel* panel) {}; +}; + +class CHandler_MenuButtonOver : public InputSignal +{ +private: + int m_iButton; + CMenuPanel *m_pMenuPanel; +public: + CHandler_MenuButtonOver( CMenuPanel *pPanel, int iButton ) + { + m_iButton = iButton; + m_pMenuPanel = pPanel; + } + + void cursorEntered(Panel *panel); + + void cursorMoved(int x,int y,Panel* panel) {}; + void mousePressed(MouseCode code,Panel* panel) {}; + void mouseReleased(MouseCode code,Panel* panel) {}; + void mouseDoublePressed(MouseCode code,Panel* panel) {}; + void cursorExited(Panel* panel) {}; + void mouseWheeled(int delta,Panel* panel) {}; + void keyPressed(KeyCode code,Panel* panel) {}; + void keyTyped(KeyCode code,Panel* panel) {}; + void keyReleased(KeyCode code,Panel* panel) {}; + void keyFocusTicked(Panel* panel) {}; +}; + +class CHandler_ButtonHighlight : public InputSignal +{ +private: + Button *m_pButton; +public: + CHandler_ButtonHighlight( Button *pButton ) + { + m_pButton = pButton; + } + + virtual void cursorEntered(Panel* panel) + { + m_pButton->setArmed(true); + }; + virtual void cursorExited(Panel* Panel) + { + m_pButton->setArmed(false); + }; + virtual void mousePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +//----------------------------------------------------------------------------- +// Purpose: Special handler for highlighting of command menu buttons +//----------------------------------------------------------------------------- +class CHandler_CommandButtonHighlight : public CHandler_ButtonHighlight +{ +private: + CommandButton *m_pCommandButton; +public: + CHandler_CommandButtonHighlight( CommandButton *pButton ) : CHandler_ButtonHighlight( pButton ) + { + m_pCommandButton = pButton; + } + + virtual void cursorEntered( Panel *panel ) + { + m_pCommandButton->cursorEntered(); + } + + virtual void cursorExited( Panel *panel ) + { + m_pCommandButton->cursorExited(); + } +}; + + +//================================================================ +// Overidden Command Buttons for special visibilities +class ClassButton : public CommandButton +{ +protected: + int m_iPlayerClass; + +public: + ClassButton( int iClass, const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) + { + m_iPlayerClass = iClass; + } + + virtual int IsNotValid(); +}; + +class TeamButton : public CommandButton +{ +private: + int m_iTeamNumber; +public: + TeamButton( int iTeam, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iTeamNumber = iTeam; + } + + virtual int IsNotValid() + { + int iTeams = gViewPort->GetNumberOfTeams(); + // Never valid if there's only 1 team + if (iTeams == 1) + return true; + + // Auto Team's always visible + if (m_iTeamNumber == 5) + return false; + + if (iTeams >= m_iTeamNumber && m_iTeamNumber != g_iTeamNumber) + return false; + + return true; + } +}; + +class FeignButton : public CommandButton +{ +private: + int m_iFeignState; +public: + FeignButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iFeignState = iState; + } + + virtual int IsNotValid() + { + // Only visible for spies + if (g_iPlayerClass != PC_SPY) + return true; + + if (m_iFeignState == gViewPort->GetIsFeigning()) + return false; + + return true; + } +}; + +class SpectateButton : public CommandButton +{ +public: + SpectateButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) + { + } + + virtual int IsNotValid() + { + // Only visible if the server allows it + if ( gViewPort->GetAllowSpectators() != 0 ) + return false; + + return true; + } +}; + +#define DISGUISE_TEAM1 (1<<0) +#define DISGUISE_TEAM2 (1<<1) +#define DISGUISE_TEAM3 (1<<2) +#define DISGUISE_TEAM4 (1<<3) + +class DisguiseButton : public CommandButton +{ +private: + int m_iValidTeamsBits; + int m_iThisTeam; +public: + DisguiseButton( int iValidTeamNumsBits, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall,false ) + { + m_iValidTeamsBits = iValidTeamNumsBits; + } + + virtual int IsNotValid() + { + // Only visible for spies + if ( g_iPlayerClass != PC_SPY ) + return true; + + // if it's not tied to a specific team, then always show (for spies) + if ( !m_iValidTeamsBits ) + return false; + + // if we're tied to a team make sure we can change to that team + int iTmp = 1 << (gViewPort->GetNumberOfTeams() - 1); + if ( m_iValidTeamsBits & iTmp ) + return false; + + return true; + } +}; + +class DetpackButton : public CommandButton +{ +private: + int m_iDetpackState; +public: + DetpackButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iDetpackState = iState; + } + + virtual int IsNotValid() + { + // Only visible for demomen + if (g_iPlayerClass != PC_DEMOMAN) + return true; + + if (m_iDetpackState == gViewPort->GetIsSettingDetpack()) + return false; + + return true; + } +}; + +extern int iBuildingCosts[]; +#define BUILDSTATE_HASBUILDING (1<<0) // Data is building ID (1 = Dispenser, 2 = Sentry) +#define BUILDSTATE_BUILDING (1<<1) +#define BUILDSTATE_BASE (1<<2) +#define BUILDSTATE_CANBUILD (1<<3) // Data is building ID (0 = Dispenser, 1 = Sentry) + +class BuildButton : public CommandButton +{ +private: + int m_iBuildState; + int m_iBuildData; + +public: + enum Buildings + { + DISPENSER = 0, + SENTRYGUN = 1, + }; + + BuildButton( int iState, int iData, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iBuildState = iState; + m_iBuildData = iData; + } + + virtual int IsNotValid() + { + // Only visible for engineers + if (g_iPlayerClass != PC_ENGINEER) + return true; + + // If this isn't set, it's only active when they're not building + if (m_iBuildState & BUILDSTATE_BUILDING) + { + // Make sure the player's building + if ( !(gViewPort->GetBuildState() & BS_BUILDING) ) + return true; + } + else + { + // Make sure the player's not building + if ( gViewPort->GetBuildState() & BS_BUILDING ) + return true; + } + + if (m_iBuildState & BUILDSTATE_BASE) + { + // Only appear if we've got enough metal to build something, or something already built + if ( gViewPort->GetBuildState() & (BS_HAS_SENTRYGUN | BS_HAS_DISPENSER | BS_CANB_SENTRYGUN | BS_CANB_DISPENSER) ) + return false; + + return true; + } + + // Must have a building + if (m_iBuildState & BUILDSTATE_HASBUILDING) + { + if ( m_iBuildData == BuildButton::DISPENSER && !(gViewPort->GetBuildState() & BS_HAS_DISPENSER) ) + return true; + if ( m_iBuildData == BuildButton::SENTRYGUN && !(gViewPort->GetBuildState() & BS_HAS_SENTRYGUN) ) + return true; + } + + // Can build something + if (m_iBuildState & BUILDSTATE_CANBUILD) + { + // Make sure they've got the ammo and don't have one already + if ( m_iBuildData == BuildButton::DISPENSER && (gViewPort->GetBuildState() & BS_CANB_DISPENSER) ) + return false; + if ( m_iBuildData == BuildButton::SENTRYGUN && (gViewPort->GetBuildState() & BS_CANB_SENTRYGUN) ) + return false; + + return true; + } + + return false; + } +}; + +#define MAX_MAPNAME 256 + +class MapButton : public CommandButton +{ +private: + char m_szMapName[ MAX_MAPNAME ]; + +public: + MapButton( const char *pMapName, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + sprintf( m_szMapName, "maps/%s.bsp", pMapName ); + } + + virtual int IsNotValid() + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (!level) + return true; + + // Does it match the current map name? + if ( strcmp(m_szMapName, level) ) + return true; + + return false; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: CommandButton which is only displayed if the player is on team X +//----------------------------------------------------------------------------- +class TeamOnlyCommandButton : public CommandButton +{ +private: + int m_iTeamNum; + +public: + TeamOnlyCommandButton( int iTeamNum, const char* text,int x,int y,int wide,int tall, bool flat ) : + CommandButton( text, x, y, wide, tall, false, flat ), m_iTeamNum(iTeamNum) {} + + virtual int IsNotValid() + { + if ( g_iTeamNumber != m_iTeamNum ) + return true; + + return CommandButton::IsNotValid(); + } + + virtual void paintBackground() + { + if ( isArmed() ) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint( void ) + { + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + Button::paint(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: CommandButton which is only displayed if the player is on team X +//----------------------------------------------------------------------------- +class ToggleCommandButton : public CommandButton, public InputSignal +{ +private: + struct cvar_s * m_cvar; + CImageLabel * pLabelOn; + CImageLabel * pLabelOff; + + +public: + ToggleCommandButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : + CommandButton( text, x, y, wide, tall, false, flat ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + + // Put a > to show it's a submenu + pLabelOn = new CImageLabel( "checked", 0, 0 ); + pLabelOn->setParent(this); + pLabelOn->addInputSignal(this); + + pLabelOff = new CImageLabel( "unchecked", 0, 0 ); + pLabelOff->setParent(this); + pLabelOff->setEnabled(true); + pLabelOff->addInputSignal(this); + + int textwide, texttall; + getTextSize( textwide, texttall); + + // Reposition + pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); + + pLabelOff->setPos( textwide, (tall - pLabelOff->getTall()) / 2 ); + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + } + + virtual void cursorEntered(Panel* panel) + { + CommandButton::cursorEntered(); + } + + virtual void cursorExited(Panel* panel) + { + CommandButton::cursorExited(); + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + doClick(); + }; + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; + + virtual void paint( void ) + { + if ( !m_cvar ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(false); + } + else if ( m_cvar->value ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(true); + } + else + { + pLabelOff->setVisible(true); + pLabelOn->setVisible(false); + } + + CommandButton::paint(); + + } +}; +class SpectToggleButton : public CommandButton, public InputSignal +{ +private: + struct cvar_s * m_cvar; + CImageLabel * pLabelOn; + +public: + SpectToggleButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : + CommandButton( text, x, y, wide, tall, false, flat ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + + // Put a > to show it's a submenu + pLabelOn = new CImageLabel( "checked", 0, 0 ); + pLabelOn->setParent(this); + pLabelOn->addInputSignal(this); + + + int textwide, texttall; + getTextSize( textwide, texttall); + + // Reposition + pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); + } + + virtual void cursorEntered(Panel* panel) + { + CommandButton::cursorEntered(); + } + + virtual void cursorExited(Panel* panel) + { + CommandButton::cursorExited(); + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + doClick(); + }; + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; + + virtual void paintBackground() + { + if ( isArmed() ) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint( void ) + { + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + if ( !m_cvar ) + { + pLabelOn->setVisible(false); + } + else if ( m_cvar->value ) + { + pLabelOn->setVisible(true); + } + else + { + pLabelOn->setVisible(false); + } + + Button::paint(); + } +}; + +/* +class SpectToggleButton : public ToggleCommandButton +{ +private: + struct cvar_s * m_cvar; + CImageLabel * pLabelOn; + CImageLabel * pLabelOff; + +public: + + SpectToggleButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : + ToggleCommandButton( cvarname, text, x, y, wide, tall, flat, TRUE ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + + // Put a > to show it's a submenu + pLabelOn = new CImageLabel( "checked", 0, 0 ); + pLabelOn->setParent(this); + pLabelOn->addInputSignal(this); + + pLabelOff = new CImageLabel( "unchecked", 0, 0 ); + pLabelOff->setParent(this); + pLabelOff->setEnabled(true); + pLabelOff->addInputSignal(this); + + int textwide, texttall; + getTextSize( textwide, texttall); + + // Reposition + pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); + + pLabelOff->setPos( textwide, (tall - pLabelOff->getTall()) / 2 ); + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + } + + virtual void paintBackground() + { + if ( isArmed()) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint() + { + + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + if ( !m_cvar ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(false); + } + else if ( m_cvar->value ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(true); + } + else + { + pLabelOff->setVisible(true); + pLabelOn->setVisible(false); + } + + Button::paint(); + } +}; +*/ +//============================================================ +// Panel that can be dragged around +class DragNDropPanel : public Panel +{ +private: + bool m_bBeingDragged; + LineBorder *m_pBorder; +public: + DragNDropPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) + { + m_bBeingDragged = false; + + // Create the Drag Handler + addInputSignal( new CDragNDropHandler(this) ); + + // Create the border (for dragging) + m_pBorder = new LineBorder(); + } + + virtual void setDragged( bool bState ) + { + m_bBeingDragged = bState; + + if (m_bBeingDragged) + setBorder(m_pBorder); + else + setBorder(NULL); + } +}; + +//================================================================ +// Panel that draws itself with a transparent black background +class CTransparentPanel : public Panel +{ +private: + int m_iTransparency; +public: + CTransparentPanel(int iTrans, int x,int y,int wide,int tall) : Panel(x,y,wide,tall) + { + m_iTransparency = iTrans; + } + + void SetTransparency(int inTransparency) + { + m_iTransparency = inTransparency; + } + + virtual void paintBackground() + { + if (m_iTransparency) + { + // Transparent black background + drawSetColor( 0,0,0, m_iTransparency ); + drawFilledRect(0,0,_size[0],_size[1]); + } + } +}; + +//================================================================ +// Menu Panel that supports buffering of menus +class CMenuPanel : public CTransparentPanel +{ +private: + CMenuPanel *m_pNextMenu; + int m_iMenuID; + int m_iRemoveMe; + int m_iIsActive; + float m_flOpenTime; +public: + CMenuPanel(int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(100, x,y,wide,tall) + { + Reset(); + m_iRemoveMe = iRemoveMe; + } + + CMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(iTrans, x,y,wide,tall) + { + Reset(); + m_iRemoveMe = iRemoveMe; + } + + virtual void Reset( void ) + { + m_pNextMenu = NULL; + m_iIsActive = false; + m_flOpenTime = 0; + } + + void SetNextMenu( CMenuPanel *pNextPanel ) + { + if (m_pNextMenu) + m_pNextMenu->SetNextMenu( pNextPanel ); + else + m_pNextMenu = pNextPanel; + } + + void SetMenuID( int iID ) + { + m_iMenuID = iID; + } + + void SetActive( int iState ) + { + m_iIsActive = iState; + } + + virtual void Open( void ) + { + setVisible( true ); + + // Note the open time, so we can delay input for a bit + m_flOpenTime = gHUD.m_flTime; + } + + virtual void Close( void ) + { + setVisible( false ); + m_iIsActive = false; + + if ( m_iRemoveMe ) + gViewPort->removeChild( this ); + + // This MenuPanel has now been deleted. Don't append code here. + } + + int ShouldBeRemoved() { return m_iRemoveMe; }; + CMenuPanel* GetNextMenu() { return m_pNextMenu; }; + int GetMenuID() { return m_iMenuID; }; + int IsActive() { return m_iIsActive; }; + float GetOpenTime() { return m_flOpenTime; }; + + // Numeric input + virtual bool SlotInput( int iSlot ) { return false; }; + virtual void SetActiveInfo( int iInput ) {}; +}; + +//================================================================ +// Custom drawn scroll bars +class CTFScrollButton : public CommandButton +{ +private: + BitmapTGA *m_pTGA; + +public: + CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall); + + virtual void paint( void ); + virtual void paintBackground( void ); +}; + +// Custom drawn slider bar +class CTFSlider : public Slider +{ +public: + CTFSlider(int x,int y,int wide,int tall,bool vertical) : Slider(x,y,wide,tall,vertical) + { + }; + + virtual void paintBackground( void ); +}; + +// Custom drawn scrollpanel +class CTFScrollPanel : public ScrollPanel +{ +public: + CTFScrollPanel(int x,int y,int wide,int tall); +}; + +//================================================================ +// Menu Panels that take key input +//============================================================ +class CClassMenuPanel : public CMenuPanel +{ +private: + CTransparentPanel *m_pClassInfoPanel[PC_LASTCLASS]; + Label *m_pPlayers[PC_LASTCLASS]; + ClassButton *m_pButtons[PC_LASTCLASS]; + CommandButton *m_pCancelButton; + ScrollPanel *m_pScrollPanel; + + CImageLabel *m_pClassImages[MAX_TEAMS][PC_LASTCLASS]; + + int m_iCurrentInfo; + + enum { STRLENMAX_PLAYERSONTEAM = 128 }; + char m_sPlayersOnTeamString[STRLENMAX_PLAYERSONTEAM]; + +public: + CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall); + + virtual bool SlotInput( int iSlot ); + virtual void Open( void ); + virtual void Update( void ); + virtual void SetActiveInfo( int iInput ); + virtual void Initialize( void ); + + virtual void Reset( void ) + { + CMenuPanel::Reset(); + m_iCurrentInfo = 0; + } +}; + +class CTeamMenuPanel : public CMenuPanel +{ +public: + ScrollPanel *m_pScrollPanel; + CTransparentPanel *m_pTeamWindow; + Label *m_pMapTitle; + TextPanel *m_pBriefing; + TextPanel *m_pTeamInfoPanel[6]; + CommandButton *m_pButtons[6]; + bool m_bUpdatedMapName; + CommandButton *m_pCancelButton; + CommandButton *m_pSpectateButton; + + int m_iCurrentInfo; + +public: + CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall); + + virtual bool SlotInput( int iSlot ); + virtual void Open( void ); + virtual void Update( void ); + virtual void SetActiveInfo( int iInput ); + virtual void paintBackground( void ); + + virtual void Initialize( void ); + + virtual void Reset( void ) + { + CMenuPanel::Reset(); + m_iCurrentInfo = 0; + } +}; + +//========================================================= +// Specific Menus to handle old HUD sections +class CHealthPanel : public DragNDropPanel +{ +private: + BitmapTGA *m_pHealthTGA; + Label *m_pHealthLabel; +public: + CHealthPanel(int x,int y,int wide,int tall) : DragNDropPanel(x,y,wide,tall) + { + // Load the Health icon + FileInputStream* fis = new FileInputStream( GetVGUITGAName("%d_hud_health"), false); + m_pHealthTGA = new BitmapTGA(fis,true); + fis->close(); + + // Create the Health Label + int iXSize,iYSize; + m_pHealthTGA->getSize(iXSize,iYSize); + m_pHealthLabel = new Label("",0,0,iXSize,iYSize); + m_pHealthLabel->setImage(m_pHealthTGA); + m_pHealthLabel->setParent(this); + + // Set panel dimension + // Shouldn't be needed once Billy's fized setImage not recalculating the size + //setSize( iXSize + 100, gHUD.m_iFontHeight + 10 ); + //m_pHealthLabel->setPos( 10, (getTall() - iYSize) / 2 ); + } + + virtual void paintBackground() + { + } + + void paint() + { + // Get the paint color + int r,g,b,a; + // Has health changed? Flash the health # + if (gHUD.m_Health.m_fFade) + { + gHUD.m_Health.m_fFade -= (gHUD.m_flTimeDelta * 20); + if (gHUD.m_Health.m_fFade <= 0) + { + a = MIN_ALPHA; + gHUD.m_Health.m_fFade = 0; + } + + // Fade the health number back to dim + a = MIN_ALPHA + (gHUD.m_Health.m_fFade/FADE_TIME) * 128; + } + else + a = MIN_ALPHA; + + gHUD.m_Health.GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + // If health is getting low, make it bright red + if (gHUD.m_Health.m_iHealth <= 15) + a = 255; + + int iXSize,iYSize, iXPos, iYPos; + m_pHealthTGA->getSize(iXSize,iYSize); + m_pHealthTGA->getPos(iXPos, iYPos); + + // Paint the player's health + int x = gHUD.DrawHudNumber( iXPos + iXSize + 5, iYPos + 5, DHN_3DIGITS | DHN_DRAWZERO, gHUD.m_Health.m_iHealth, r, g, b); + + // Draw the vertical line + int HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + x += HealthWidth / 2; + FillRGBA(x, iYPos + 5, HealthWidth / 10, gHUD.m_iFontHeight, 255, 160, 0, a); + } +}; + +#endif diff --git a/main/source/cl_dll/vgui_int.cpp b/main/source/cl_dll/vgui_int.cpp index ad4b85b8..e684fa0d 100644 --- a/main/source/cl_dll/vgui_int.cpp +++ b/main/source/cl_dll/vgui_int.cpp @@ -4,125 +4,125 @@ // // $NoKeywords: $ //============================================================================= - -#include"vgui_int.h" -#include -#include -#include -#include -#include -#include -#include -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" + +#include"vgui_int.h" +#include +#include +#include +#include +#include +#include +#include +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" #include "cvardef.h" #include "usercmd.h" #include "const.h" -#include "camera.h" -#include "in_defs.h" -#include "vgui_TeamFortressViewport.h" -#include "vgui_ControlConfigPanel.h" - -namespace -{ - -class TexturePanel : public Panel , public ActionSignal -{ -private: - int _bindIndex; - TextEntry* _textEntry; -public: - TexturePanel() : Panel(0,0,256,276) - { - _bindIndex=2700; - _textEntry=new TextEntry("2700",0,0,128,20); - _textEntry->setParent(this); - _textEntry->addActionSignal(this); - } -public: - virtual bool isWithin(int x,int y) - { - return _textEntry->isWithin(x,y); - } -public: - virtual void actionPerformed(Panel* panel) - { - char buf[256]; - _textEntry->getText(0,buf,256); - sscanf(buf,"%d",&_bindIndex); - } -protected: - virtual void paintBackground() - { - Panel::paintBackground(); - - int wide,tall; - getPaintSize(wide,tall); - - drawSetColor(0,0,255,0); - drawSetTexture(_bindIndex); - drawTexturedRect(0,19,257,257); - } - -}; - -} - -using namespace vgui; - -void VGui_ViewportPaintBackground(int extents[4]) -{ - gEngfuncs.VGui_ViewportPaintBackground(extents); -} - -void* VGui_GetPanel() -{ - return (Panel*)gEngfuncs.VGui_GetPanel(); -} - -void VGui_Startup() -{ - Panel* root=(Panel*)VGui_GetPanel(); - root->setBgColor(128,128,0,0); - //root->setNonPainted(false); - //root->setBorder(new LineBorder()); - root->setLayout(new BorderLayout(0)); +#include "camera.h" +#include "in_defs.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ControlConfigPanel.h" + +namespace +{ + +class TexturePanel : public Panel , public ActionSignal +{ +private: + int _bindIndex; + TextEntry* _textEntry; +public: + TexturePanel() : Panel(0,0,256,276) + { + _bindIndex=2700; + _textEntry=new TextEntry("2700",0,0,128,20); + _textEntry->setParent(this); + _textEntry->addActionSignal(this); + } +public: + virtual bool isWithin(int x,int y) + { + return _textEntry->isWithin(x,y); + } +public: + virtual void actionPerformed(Panel* panel) + { + char buf[256]; + _textEntry->getText(0,buf,256); + sscanf(buf,"%d",&_bindIndex); + } +protected: + virtual void paintBackground() + { + Panel::paintBackground(); + + int wide,tall; + getPaintSize(wide,tall); + + drawSetColor(0,0,255,0); + drawSetTexture(_bindIndex); + drawTexturedRect(0,19,257,257); + } + +}; + +} + +using namespace vgui; + +void VGui_ViewportPaintBackground(int extents[4]) +{ + gEngfuncs.VGui_ViewportPaintBackground(extents); +} + +void* VGui_GetPanel() +{ + return (Panel*)gEngfuncs.VGui_GetPanel(); +} + +void VGui_Startup() +{ + Panel* root=(Panel*)VGui_GetPanel(); + root->setBgColor(128,128,0,0); + //root->setNonPainted(false); + //root->setBorder(new LineBorder()); + root->setLayout(new BorderLayout(0)); - //root->getSurfaceBase()->setEmulatedCursorVisible(true); - - if (gViewPort != NULL) - { -// root->removeChild(gViewPort); - - // free the memory -// delete gViewPort; -// gViewPort = NULL; - - gViewPort->Initialize(); - } - else - { - gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); - gViewPort->setParent(root); - } - + //root->getSurfaceBase()->setEmulatedCursorVisible(true); + + if (gViewPort != NULL) + { +// root->removeChild(gViewPort); + + // free the memory +// delete gViewPort; +// gViewPort = NULL; + + gViewPort->Initialize(); + } + else + { + gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); + gViewPort->setParent(root); + } + /* TexturePanel* texturePanel=new TexturePanel(); texturePanel->setParent(gViewPort); */ - -} - -void VGui_Shutdown() -{ + +} + +void VGui_Shutdown() +{ delete gViewPort; - gViewPort = NULL; -} - - - - - + gViewPort = NULL; +} + + + + + diff --git a/main/source/cl_dll/vgui_int.h b/main/source/cl_dll/vgui_int.h index 2d1faa80..1b34d6a9 100644 --- a/main/source/cl_dll/vgui_int.h +++ b/main/source/cl_dll/vgui_int.h @@ -4,19 +4,19 @@ // // $NoKeywords: $ //============================================================================= - -#ifndef VGUI_INT_H -#define VGUI_INT_H - -extern "C" -{ -void VGui_Startup(); -void VGui_Shutdown(); -void* VGui_GetPanel(); - -//Only safe to call from inside subclass of Panel::paintBackground -void VGui_ViewportPaintBackground(int extents[4]); -} - - + +#ifndef VGUI_INT_H +#define VGUI_INT_H + +extern "C" +{ +void VGui_Startup(); +void VGui_Shutdown(); +void* VGui_GetPanel(); + +//Only safe to call from inside subclass of Panel::paintBackground +void VGui_ViewportPaintBackground(int extents[4]); +} + + #endif \ No newline at end of file diff --git a/main/source/cl_dll/vgui_teammenu.cpp b/main/source/cl_dll/vgui_teammenu.cpp index f339647a..65bc8f09 100644 --- a/main/source/cl_dll/vgui_teammenu.cpp +++ b/main/source/cl_dll/vgui_teammenu.cpp @@ -1,402 +1,402 @@ -//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: TFC Team Menu -// -// $Workfile: $ -// $Date: 2002/07/08 16:15:13 $ -// -//----------------------------------------------------------------------------- -// $Log: vgui_teammenu.cpp,v $ -// Revision 1.3 2002/07/08 16:15:13 Flayra -// - Refactored team color management -// -// Revision 1.2 2001/09/13 22:28:01 Charlie -// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode -// -// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie -// - HL1108 -// -// -// $NoKeywords: $ -//============================================================================= - -#include "vgui_int.h" -#include "VGUI_Font.h" -#include "VGUI_ScrollPanel.h" -#include "VGUI_TextImage.h" - -#include "hud.h" -#include "cl_util.h" -#include "vgui_TeamFortressViewport.h" - -// Team Menu Dimensions -#define TEAMMENU_TITLE_X XRES(40) -#define TEAMMENU_TITLE_Y YRES(32) -#define TEAMMENU_TOPLEFT_BUTTON_X XRES(40) -#define TEAMMENU_TOPLEFT_BUTTON_Y YRES(80) -#define TEAMMENU_BUTTON_SIZE_X XRES(124) -#define TEAMMENU_BUTTON_SIZE_Y YRES(24) -#define TEAMMENU_BUTTON_SPACER_Y YRES(8) -#define TEAMMENU_WINDOW_X XRES(176) -#define TEAMMENU_WINDOW_Y YRES(80) -#define TEAMMENU_WINDOW_SIZE_X XRES(424) -#define TEAMMENU_WINDOW_SIZE_Y YRES(312) -#define TEAMMENU_WINDOW_TITLE_X XRES(16) -#define TEAMMENU_WINDOW_TITLE_Y YRES(16) -#define TEAMMENU_WINDOW_TEXT_X XRES(16) -#define TEAMMENU_WINDOW_TEXT_Y YRES(48) -#define TEAMMENU_WINDOW_TEXT_SIZE_Y YRES(178) -#define TEAMMENU_WINDOW_INFO_X XRES(16) -#define TEAMMENU_WINDOW_INFO_Y YRES(234) - -// Creation -CTeamMenuPanel::CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) -{ - // Get the scheme used for the Titles - CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); - - // schemes - SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); - SchemeHandle_t hTeamWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); - SchemeHandle_t hTeamInfoText = pSchemes->getSchemeHandle( "Team Info Text" ); - - // get the Font used for the Titles - Font *pTitleFont = pSchemes->getFont( hTitleScheme ); - int r, g, b, a; - - // Create the title - Label *pLabel = new Label( "", TEAMMENU_TITLE_X, TEAMMENU_TITLE_Y ); - pLabel->setParent( this ); - pLabel->setFont( pTitleFont ); - pSchemes->getFgColor( hTitleScheme, r, g, b, a ); - pLabel->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hTitleScheme, r, g, b, a ); - pLabel->setBgColor( r, g, b, a ); - pLabel->setContentAlignment( vgui::Label::a_west ); - pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourTeam")); - - // Create the Info Window - m_pTeamWindow = new CTransparentPanel( 255, TEAMMENU_WINDOW_X, TEAMMENU_WINDOW_Y, TEAMMENU_WINDOW_SIZE_X, TEAMMENU_WINDOW_SIZE_Y ); - m_pTeamWindow->setParent( this ); - m_pTeamWindow->setBorder( new LineBorder( Color(255*0.7,170*0.7,0,0 )) ); - - // Create the Map Name Label - m_pMapTitle = new Label( "", TEAMMENU_WINDOW_TITLE_X, TEAMMENU_WINDOW_TITLE_Y ); - m_pMapTitle->setFont( pTitleFont ); - m_pMapTitle->setParent( m_pTeamWindow ); - pSchemes->getFgColor( hTitleScheme, r, g, b, a ); - m_pMapTitle->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hTitleScheme, r, g, b, a ); - m_pMapTitle->setBgColor( r, g, b, a ); - m_pMapTitle->setContentAlignment( vgui::Label::a_west ); - - // Create the Scroll panel - m_pScrollPanel = new CTFScrollPanel( TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_Y, TEAMMENU_WINDOW_SIZE_X - (TEAMMENU_WINDOW_TEXT_X * 2), TEAMMENU_WINDOW_TEXT_SIZE_Y ); - m_pScrollPanel->setParent(m_pTeamWindow); - m_pScrollPanel->setScrollBarVisible(false, false); - - // Create the Map Briefing panel - m_pBriefing = new TextPanel("", 0,0, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_SIZE_Y ); - m_pBriefing->setParent( m_pScrollPanel->getClient() ); - m_pBriefing->setFont( pSchemes->getFont(hTeamWindowText) ); - pSchemes->getFgColor( hTeamWindowText, r, g, b, a ); - m_pBriefing->setFgColor( r, g, b, a ); - pSchemes->getBgColor( hTeamWindowText, r, g, b, a ); - m_pBriefing->setBgColor( r, g, b, a ); - - m_pBriefing->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Map_Description_not_available") ); - - // Team Menu buttons - for (int i = 1; i <= 5; i++) - { - char sz[256]; - - int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y + ( (TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y) * i ); - - // Team button - m_pButtons[i] = new CommandButton( "", TEAMMENU_TOPLEFT_BUTTON_X, iYPos, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); - m_pButtons[i]->setParent( this ); - m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); - m_pButtons[i]->setVisible( false ); - - // AutoAssign button uses special case - if (i == 5) - { - m_pButtons[5]->setBoundKey( '5' ); - m_pButtons[5]->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Team_AutoAssign") ); - m_pButtons[5]->setVisible( true ); - } - - // Create the Signals - sprintf(sz, "jointeam %d", i); - m_pButtons[i]->addActionSignal( new CMenuHandler_StringCommandWatch( sz, true ) ); - m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); - - // Create the Team Info panel - m_pTeamInfoPanel[i] = new TextPanel("", TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_INFO_Y, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_Y ); - m_pTeamInfoPanel[i]->setParent( m_pTeamWindow ); - m_pTeamInfoPanel[i]->setFont( pSchemes->getFont(hTeamInfoText) ); - m_pTeamInfoPanel[i]->setFgColor( kTeamColors[i % iNumberOfTeamColors][0], - kTeamColors[i % iNumberOfTeamColors][1], - kTeamColors[i % iNumberOfTeamColors][2], - 0 ); - m_pTeamInfoPanel[i]->setBgColor( 0,0,0, 255 ); - } - - // Create the Cancel button - m_pCancelButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Cancel" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y); - m_pCancelButton->setParent( this ); - m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); - - // Create the Spectate button - m_pSpectateButton = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); - m_pSpectateButton->setParent( this ); - m_pSpectateButton->addActionSignal( new CMenuHandler_StringCommand( "spectate", true ) ); - m_pSpectateButton->setBoundKey( '6' ); - m_pSpectateButton->addInputSignal( new CHandler_MenuButtonOver(this, 6) ); - - Initialize(); -} - -//----------------------------------------------------------------------------- -// Purpose: Called each time a new level is started. -//----------------------------------------------------------------------------- -void CTeamMenuPanel::Initialize( void ) -{ - m_bUpdatedMapName = false; - m_iCurrentInfo = 0; - m_pScrollPanel->setScrollValue( 0, 0 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Called everytime the Team Menu is displayed -//----------------------------------------------------------------------------- -void CTeamMenuPanel::Update( void ) -{ - int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y; - - // Set the team buttons - for (int i = 1; i <= 4; i++) - { - if (m_pButtons[i]) - { - if ( i <= gViewPort->GetNumberOfTeams() ) - { - m_pButtons[i]->setText( gViewPort->GetTeamName(i) ); - - // bound key replacement - char sz[32]; - sprintf( sz, "%d", i ); - m_pButtons[i]->setBoundKey( sz[0] ); - - m_pButtons[i]->setVisible( true ); - m_pButtons[i]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); - iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; - - // Start with the first option up - if (!m_iCurrentInfo) - SetActiveInfo( i ); - - char szPlayerList[ (MAX_PLAYER_NAME_LENGTH + 3) * 31 ]; // name + ", " - strcpy(szPlayerList, "\n"); - // Update the Team Info - // Now count the number of teammembers of this class - int iTotal = 0; - for ( int j = 1; j <= MAX_PLAYERS; j++ ) - { - if ( g_PlayerInfoList[j].name == NULL ) - continue; // empty player slot, skip - if ( g_PlayerInfoList[j].thisplayer ) - continue; // skip this player - if ( g_PlayerExtraInfo[j].teamnumber != i ) - continue; // skip over players in other teams - - iTotal++; - if (iTotal > 1) - strncat( szPlayerList, ", ", sizeof(szPlayerList) - strlen(szPlayerList) ); - strncat( szPlayerList, g_PlayerInfoList[j].name, sizeof(szPlayerList) - strlen(szPlayerList) ); - szPlayerList[ sizeof(szPlayerList) - 1 ] = '\0'; - } - - if (iTotal > 0) - { - // Set the text of the info Panel - char szText[ ((MAX_PLAYER_NAME_LENGTH + 3) * 31) + 256 ]; - if (iTotal == 1) - sprintf(szText, "%s: %d Player (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); - else - sprintf(szText, "%s: %d Players (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); - strncat( szText, szPlayerList, sizeof(szText) - strlen(szText) ); - szText[ sizeof(szText) - 1 ] = '\0'; - - m_pTeamInfoPanel[i]->setText( szText ); - } - else - { - m_pTeamInfoPanel[i]->setText( "" ); - } - } - else - { - // Hide the button (may be visible from previous maps) - m_pButtons[i]->setVisible( false ); - } - } - } - - // Move the AutoAssign button into place - m_pButtons[5]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); - iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; - - // Spectate button - if (m_pSpectateButton->IsNotValid()) - { - m_pSpectateButton->setVisible( false ); - } - else - { - m_pSpectateButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); - m_pSpectateButton->setVisible( true ); - iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; - } - - // If the player is already in a team, make the cancel button visible - if ( g_iTeamNumber ) - { - m_pCancelButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); - iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; - m_pCancelButton->setVisible( true ); - } - else - { - m_pCancelButton->setVisible( false ); - } - - // Set the Map Title - if (!m_bUpdatedMapName) - { - const char *level = gEngfuncs.pfnGetLevelName(); - if (level && level[0]) - { - char sz[256]; - char szTitle[256]; - char *ch; - - // Update the level name - strcpy( sz, level ); - ch = strchr( sz, '/' ); - if (!ch) - ch = strchr( sz, '\\' ); - strcpy( szTitle, ch+1 ); - ch = strchr( szTitle, '.' ); - *ch = '\0'; - m_pMapTitle->setText( szTitle ); - *ch = '.'; - - // Update the map briefing - strcpy( sz, level ); - ch = strchr( sz, '.' ); - *ch = '\0'; - strcat( sz, ".txt" ); - char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); - if (pfile) - { - m_pBriefing->setText( pfile ); - - // Get the total size of the Briefing text and resize the text panel - int iXSize, iYSize; - m_pBriefing->getTextImage()->getTextSize( iXSize, iYSize ); - m_pBriefing->setSize( iXSize, iYSize ); - gEngfuncs.COM_FreeFile( pfile ); - } - - m_bUpdatedMapName = true; - } - } - - m_pScrollPanel->validate(); -} - -//===================================== -// Key inputs -bool CTeamMenuPanel::SlotInput( int iSlot ) -{ - // Check for AutoAssign - if ( iSlot == 5) - { - m_pButtons[5]->fireActionSignal(); - return true; - } - - // Spectate - if ( iSlot == 6) - { - m_pSpectateButton->fireActionSignal(); - return true; - } - - // Otherwise, see if a particular team is selectable - if ( (iSlot < 1) || (iSlot > gViewPort->GetNumberOfTeams()) ) - return false; - if ( !m_pButtons[ iSlot ] ) - return false; - - // Is the button pushable? - if ( m_pButtons[ iSlot ]->isVisible() ) - { - m_pButtons[ iSlot ]->fireActionSignal(); - return true; - } - - return false; -} - -//====================================== -// Update the Team menu before opening it -void CTeamMenuPanel::Open( void ) -{ - Update(); - CMenuPanel::Open(); -} - -void CTeamMenuPanel::paintBackground() -{ - // make sure we get the map briefing up - if ( !m_bUpdatedMapName ) - Update(); - - CMenuPanel::paintBackground(); -} - -//====================================== -// Mouse is over a team button, bring up the class info -void CTeamMenuPanel::SetActiveInfo( int iInput ) -{ - // Remove all the Info panels and bring up the specified one - m_pSpectateButton->setArmed( false ); - for (int i = 1; i <= 5; i++) - { - m_pButtons[i]->setArmed( false ); - m_pTeamInfoPanel[i]->setVisible( false ); - } - - // 6 is Spectate - if (iInput == 6) - { - m_pSpectateButton->setArmed( true ); - } - else - { - m_pButtons[iInput]->setArmed( true ); - m_pTeamInfoPanel[iInput]->setVisible( true ); - } - - m_iCurrentInfo = iInput; - - m_pScrollPanel->validate(); -} +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: TFC Team Menu +// +// $Workfile: $ +// $Date: 2002/07/08 16:15:13 $ +// +//----------------------------------------------------------------------------- +// $Log: vgui_teammenu.cpp,v $ +// Revision 1.3 2002/07/08 16:15:13 Flayra +// - Refactored team color management +// +// Revision 1.2 2001/09/13 22:28:01 Charlie +// - Updated NS with new Half-life 1108 patch in preparation for voice support and spectator mode +// +// Revision 1.1.1.1.2.1 2001/09/13 14:42:30 Charlie +// - HL1108 +// +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_int.h" +#include "VGUI_Font.h" +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include "hud.h" +#include "cl_util.h" +#include "vgui_TeamFortressViewport.h" + +// Team Menu Dimensions +#define TEAMMENU_TITLE_X XRES(40) +#define TEAMMENU_TITLE_Y YRES(32) +#define TEAMMENU_TOPLEFT_BUTTON_X XRES(40) +#define TEAMMENU_TOPLEFT_BUTTON_Y YRES(80) +#define TEAMMENU_BUTTON_SIZE_X XRES(124) +#define TEAMMENU_BUTTON_SIZE_Y YRES(24) +#define TEAMMENU_BUTTON_SPACER_Y YRES(8) +#define TEAMMENU_WINDOW_X XRES(176) +#define TEAMMENU_WINDOW_Y YRES(80) +#define TEAMMENU_WINDOW_SIZE_X XRES(424) +#define TEAMMENU_WINDOW_SIZE_Y YRES(312) +#define TEAMMENU_WINDOW_TITLE_X XRES(16) +#define TEAMMENU_WINDOW_TITLE_Y YRES(16) +#define TEAMMENU_WINDOW_TEXT_X XRES(16) +#define TEAMMENU_WINDOW_TEXT_Y YRES(48) +#define TEAMMENU_WINDOW_TEXT_SIZE_Y YRES(178) +#define TEAMMENU_WINDOW_INFO_X XRES(16) +#define TEAMMENU_WINDOW_INFO_Y YRES(234) + +// Creation +CTeamMenuPanel::CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) +{ + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hTeamWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); + SchemeHandle_t hTeamInfoText = pSchemes->getSchemeHandle( "Team Info Text" ); + + // get the Font used for the Titles + Font *pTitleFont = pSchemes->getFont( hTitleScheme ); + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", TEAMMENU_TITLE_X, TEAMMENU_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pTitleFont ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourTeam")); + + // Create the Info Window + m_pTeamWindow = new CTransparentPanel( 255, TEAMMENU_WINDOW_X, TEAMMENU_WINDOW_Y, TEAMMENU_WINDOW_SIZE_X, TEAMMENU_WINDOW_SIZE_Y ); + m_pTeamWindow->setParent( this ); + m_pTeamWindow->setBorder( new LineBorder( Color(255*0.7,170*0.7,0,0 )) ); + + // Create the Map Name Label + m_pMapTitle = new Label( "", TEAMMENU_WINDOW_TITLE_X, TEAMMENU_WINDOW_TITLE_Y ); + m_pMapTitle->setFont( pTitleFont ); + m_pMapTitle->setParent( m_pTeamWindow ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pMapTitle->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pMapTitle->setBgColor( r, g, b, a ); + m_pMapTitle->setContentAlignment( vgui::Label::a_west ); + + // Create the Scroll panel + m_pScrollPanel = new CTFScrollPanel( TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_Y, TEAMMENU_WINDOW_SIZE_X - (TEAMMENU_WINDOW_TEXT_X * 2), TEAMMENU_WINDOW_TEXT_SIZE_Y ); + m_pScrollPanel->setParent(m_pTeamWindow); + m_pScrollPanel->setScrollBarVisible(false, false); + + // Create the Map Briefing panel + m_pBriefing = new TextPanel("", 0,0, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_SIZE_Y ); + m_pBriefing->setParent( m_pScrollPanel->getClient() ); + m_pBriefing->setFont( pSchemes->getFont(hTeamWindowText) ); + pSchemes->getFgColor( hTeamWindowText, r, g, b, a ); + m_pBriefing->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTeamWindowText, r, g, b, a ); + m_pBriefing->setBgColor( r, g, b, a ); + + m_pBriefing->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Map_Description_not_available") ); + + // Team Menu buttons + for (int i = 1; i <= 5; i++) + { + char sz[256]; + + int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y + ( (TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y) * i ); + + // Team button + m_pButtons[i] = new CommandButton( "", TEAMMENU_TOPLEFT_BUTTON_X, iYPos, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); + m_pButtons[i]->setParent( this ); + m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); + m_pButtons[i]->setVisible( false ); + + // AutoAssign button uses special case + if (i == 5) + { + m_pButtons[5]->setBoundKey( '5' ); + m_pButtons[5]->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Team_AutoAssign") ); + m_pButtons[5]->setVisible( true ); + } + + // Create the Signals + sprintf(sz, "jointeam %d", i); + m_pButtons[i]->addActionSignal( new CMenuHandler_StringCommandWatch( sz, true ) ); + m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); + + // Create the Team Info panel + m_pTeamInfoPanel[i] = new TextPanel("", TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_INFO_Y, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_Y ); + m_pTeamInfoPanel[i]->setParent( m_pTeamWindow ); + m_pTeamInfoPanel[i]->setFont( pSchemes->getFont(hTeamInfoText) ); + m_pTeamInfoPanel[i]->setFgColor( kTeamColors[i % iNumberOfTeamColors][0], + kTeamColors[i % iNumberOfTeamColors][1], + kTeamColors[i % iNumberOfTeamColors][2], + 0 ); + m_pTeamInfoPanel[i]->setBgColor( 0,0,0, 255 ); + } + + // Create the Cancel button + m_pCancelButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Cancel" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y); + m_pCancelButton->setParent( this ); + m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); + + // Create the Spectate button + m_pSpectateButton = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); + m_pSpectateButton->setParent( this ); + m_pSpectateButton->addActionSignal( new CMenuHandler_StringCommand( "spectate", true ) ); + m_pSpectateButton->setBoundKey( '6' ); + m_pSpectateButton->addInputSignal( new CHandler_MenuButtonOver(this, 6) ); + + Initialize(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void CTeamMenuPanel::Initialize( void ) +{ + m_bUpdatedMapName = false; + m_iCurrentInfo = 0; + m_pScrollPanel->setScrollValue( 0, 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Called everytime the Team Menu is displayed +//----------------------------------------------------------------------------- +void CTeamMenuPanel::Update( void ) +{ + int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y; + + // Set the team buttons + for (int i = 1; i <= 4; i++) + { + if (m_pButtons[i]) + { + if ( i <= gViewPort->GetNumberOfTeams() ) + { + m_pButtons[i]->setText( gViewPort->GetTeamName(i) ); + + // bound key replacement + char sz[32]; + sprintf( sz, "%d", i ); + m_pButtons[i]->setBoundKey( sz[0] ); + + m_pButtons[i]->setVisible( true ); + m_pButtons[i]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + + // Start with the first option up + if (!m_iCurrentInfo) + SetActiveInfo( i ); + + char szPlayerList[ (MAX_PLAYER_NAME_LENGTH + 3) * 31 ]; // name + ", " + strcpy(szPlayerList, "\n"); + // Update the Team Info + // Now count the number of teammembers of this class + int iTotal = 0; + for ( int j = 1; j <= MAX_PLAYERS; j++ ) + { + if ( g_PlayerInfoList[j].name == NULL ) + continue; // empty player slot, skip + if ( g_PlayerInfoList[j].thisplayer ) + continue; // skip this player + if ( g_PlayerExtraInfo[j].teamnumber != i ) + continue; // skip over players in other teams + + iTotal++; + if (iTotal > 1) + strncat( szPlayerList, ", ", sizeof(szPlayerList) - strlen(szPlayerList) ); + strncat( szPlayerList, g_PlayerInfoList[j].name, sizeof(szPlayerList) - strlen(szPlayerList) ); + szPlayerList[ sizeof(szPlayerList) - 1 ] = '\0'; + } + + if (iTotal > 0) + { + // Set the text of the info Panel + char szText[ ((MAX_PLAYER_NAME_LENGTH + 3) * 31) + 256 ]; + if (iTotal == 1) + sprintf(szText, "%s: %d Player (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); + else + sprintf(szText, "%s: %d Players (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); + strncat( szText, szPlayerList, sizeof(szText) - strlen(szText) ); + szText[ sizeof(szText) - 1 ] = '\0'; + + m_pTeamInfoPanel[i]->setText( szText ); + } + else + { + m_pTeamInfoPanel[i]->setText( "" ); + } + } + else + { + // Hide the button (may be visible from previous maps) + m_pButtons[i]->setVisible( false ); + } + } + } + + // Move the AutoAssign button into place + m_pButtons[5]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + + // Spectate button + if (m_pSpectateButton->IsNotValid()) + { + m_pSpectateButton->setVisible( false ); + } + else + { + m_pSpectateButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + m_pSpectateButton->setVisible( true ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + } + + // If the player is already in a team, make the cancel button visible + if ( g_iTeamNumber ) + { + m_pCancelButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + m_pCancelButton->setVisible( true ); + } + else + { + m_pCancelButton->setVisible( false ); + } + + // Set the Map Title + if (!m_bUpdatedMapName) + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (level && level[0]) + { + char sz[256]; + char szTitle[256]; + char *ch; + + // Update the level name + strcpy( sz, level ); + ch = strchr( sz, '/' ); + if (!ch) + ch = strchr( sz, '\\' ); + strcpy( szTitle, ch+1 ); + ch = strchr( szTitle, '.' ); + *ch = '\0'; + m_pMapTitle->setText( szTitle ); + *ch = '.'; + + // Update the map briefing + strcpy( sz, level ); + ch = strchr( sz, '.' ); + *ch = '\0'; + strcat( sz, ".txt" ); + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + m_pBriefing->setText( pfile ); + + // Get the total size of the Briefing text and resize the text panel + int iXSize, iYSize; + m_pBriefing->getTextImage()->getTextSize( iXSize, iYSize ); + m_pBriefing->setSize( iXSize, iYSize ); + gEngfuncs.COM_FreeFile( pfile ); + } + + m_bUpdatedMapName = true; + } + } + + m_pScrollPanel->validate(); +} + +//===================================== +// Key inputs +bool CTeamMenuPanel::SlotInput( int iSlot ) +{ + // Check for AutoAssign + if ( iSlot == 5) + { + m_pButtons[5]->fireActionSignal(); + return true; + } + + // Spectate + if ( iSlot == 6) + { + m_pSpectateButton->fireActionSignal(); + return true; + } + + // Otherwise, see if a particular team is selectable + if ( (iSlot < 1) || (iSlot > gViewPort->GetNumberOfTeams()) ) + return false; + if ( !m_pButtons[ iSlot ] ) + return false; + + // Is the button pushable? + if ( m_pButtons[ iSlot ]->isVisible() ) + { + m_pButtons[ iSlot ]->fireActionSignal(); + return true; + } + + return false; +} + +//====================================== +// Update the Team menu before opening it +void CTeamMenuPanel::Open( void ) +{ + Update(); + CMenuPanel::Open(); +} + +void CTeamMenuPanel::paintBackground() +{ + // make sure we get the map briefing up + if ( !m_bUpdatedMapName ) + Update(); + + CMenuPanel::paintBackground(); +} + +//====================================== +// Mouse is over a team button, bring up the class info +void CTeamMenuPanel::SetActiveInfo( int iInput ) +{ + // Remove all the Info panels and bring up the specified one + m_pSpectateButton->setArmed( false ); + for (int i = 1; i <= 5; i++) + { + m_pButtons[i]->setArmed( false ); + m_pTeamInfoPanel[i]->setVisible( false ); + } + + // 6 is Spectate + if (iInput == 6) + { + m_pSpectateButton->setArmed( true ); + } + else + { + m_pButtons[iInput]->setArmed( true ); + m_pTeamInfoPanel[iInput]->setVisible( true ); + } + + m_iCurrentInfo = iInput; + + m_pScrollPanel->validate(); +} diff --git a/main/source/cl_dll/view.cpp b/main/source/cl_dll/view.cpp index 802a8472..ece19769 100644 --- a/main/source/cl_dll/view.cpp +++ b/main/source/cl_dll/view.cpp @@ -1,2740 +1,2740 @@ -// view/refresh setup functions - -#include "hud.h" -#include "cl_util.h" -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" - -#include "entity_state.h" -#include "cl_entity.h" -#include "ref_params.h" -#include "in_defs.h" // PITCH YAW ROLL -#include "pm_movevars.h" -#include "pm_shared.h" -#include "pm_defs.h" -#include "event_api.h" -#include "pmtrace.h" -#include "bench.h" -#include "screenfade.h" -#include "engine/shake.h" -#include "mod/AvHClientUtil.h" -#include "engine/APIProxy.h" -#include "hltv.h" -#include "Exports.h" -#include "common/hltv.h" -#include "util/MathUtil.h" -#include "util/STLUtil.h" -#include "mod/AvHMarineEquipmentConstants.h" -#include "mod/AvHMarineWeaponConstants.h" -#include "mod/AvHAlienWeaponConstants.h" -#include "mod/AvHSpecials.h" - -extern float gTopDownViewOrigin[3]; -extern float gTopDownViewAngles[3]; - -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -int CL_IsThirdPerson( void ); -void CL_CameraOffset( float *ofs ); - -void CL_DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); - -void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); -int PM_GetVisEntInfo( int ent ); -int PM_GetPhysEntInfo( int ent ); -//@linux -void InterpolateAngles( float * start, float * end, float * output, float frac ); -void NormalizeAngles( float * angles ); -//extern "C" float Distance(const float * v1, const float * v2); -//float AngleBetweenVectors(const float * v1, const float * v2 ); - -void V_DropPunchAngle ( float frametime, float *ev_punchangle ); -void VectorAngles( const float *forward, float *angles ); -void V_CalcTopDownRefdef ( struct ref_params_s *pparams ); - -extern float vJumpOrigin[3]; -extern float vJumpAngles[3]; - -#include "r_studioint.h" -#include "common/com_model.h" -#include "kbutton.h" - -extern engine_studio_api_t IEngineStudio; - -extern kbutton_t in_mlook; - -/* -The view is allowed to move slightly from it's true position for bobbing, -but if it exceeds 8 pixels linear distance (spherical, not box), the list of -entities sent from the server may not include everything in the pvs, especially -when crossing a water boudnary. -*/ - -extern cvar_t *cl_forwardspeed; -extern cvar_t *chase_active; -extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; -extern cvar_t *cl_vsmoothing; - -#define CAM_MODE_RELAX 1 -#define CAM_MODE_FOCUS 2 - -vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles, v_view_ofs; -float v_frametime, v_lastDistance; -float v_cameraRelaxAngle = 5.0f; -float v_cameraFocusAngle = 35.0f; -int v_cameraMode = CAM_MODE_FOCUS; -qboolean v_resetCamera = 1; - -extern float gTopDownHeight; - -vec3_t gLastCommanderViewpoint; - -vec3_t ev_punchangle; - -cvar_t *scr_ofsx; -cvar_t *scr_ofsy; -cvar_t *scr_ofsz; - -cvar_t *v_centermove; -cvar_t *v_centerspeed; - -cvar_t *cl_bobcycle; -cvar_t *cl_bob; -cvar_t *cl_bobup; -cvar_t *cl_waterdist; -cvar_t *cl_chasedist; -cvar_t *cl_hudcam; - -// These cvars are not registered (so users can't cheat), so set the ->value field directly -// Register these cvars in V_Init() if needed for easy tweaking -cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; -cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; -cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; -cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; -cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; -cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; - -float v_idlescale; // used by TFC for concussion grenade effect - -//@linux - -void NormalizeAngles( float *angles ) -{ - int i; - // Normalize angles - for ( i = 0; i < 3; i++ ) - { - if ( angles[i] > 180.0 ) - { - angles[i] -= 360.0; - } - else if ( angles[i] < -180.0 ) - { - angles[i] += 360.0; - } - } -} - -/* -=================== -InterpolateAngles - -Interpolate Euler angles. -FIXME: Use Quaternions to avoid discontinuities -Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) -=================== -*/ -void InterpolateAngles( float *start, float *end, float *output, float frac ) -{ - int i; - float ang1, ang2; - float d; - - NormalizeAngles( start ); - NormalizeAngles( end ); - - for ( i = 0 ; i < 3 ; i++ ) - { - ang1 = start[i]; - ang2 = end[i]; - - d = ang2 - ang1; - if ( d > 180 ) - { - d -= 360; - } - else if ( d < -180 ) - { - d += 360; - } - - output[i] = ang1 + d * frac; - } - - NormalizeAngles( output ); -} - -/* -=================== -AngleBetweenVectors - -=================== -*/ -float AngleBetweenVectors( float* v1, float* v2 ) -{ - float angle; - float l1 = Length( v1 ); - float l2 = Length( v2 ); - - if ( !l1 || !l2 ) - return 0.0f; - - angle = acos( DotProduct( v1, v2 ) ) / (l1*l2); - angle = ( angle * 180.0f ) / M_PI; - - return angle; -} - -//============================================================================= -/* -void V_NormalizeAngles( float *angles ) -{ - int i; - // Normalize angles - for ( i = 0; i < 3; i++ ) - { - if ( angles[i] > 180.0 ) - { - angles[i] -= 360.0; - } - else if ( angles[i] < -180.0 ) - { - angles[i] += 360.0; - } - } -} - -/* -=================== -V_InterpolateAngles - -Interpolate Euler angles. -FIXME: Use Quaternions to avoid discontinuities -Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) -=================== - -void V_InterpolateAngles( float *start, float *end, float *output, float frac ) -{ - int i; - float ang1, ang2; - float d; - - V_NormalizeAngles( start ); - V_NormalizeAngles( end ); - - for ( i = 0 ; i < 3 ; i++ ) - { - ang1 = start[i]; - ang2 = end[i]; - - d = ang2 - ang1; - if ( d > 180 ) - { - d -= 360; - } - else if ( d < -180 ) - { - d += 360; - } - - output[i] = ang1 + d * frac; - } - - V_NormalizeAngles( output ); -} */ - -// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear -float V_CalcBob ( struct ref_params_s *pparams ) -{ - static double bobtime; - static float bob; - float cycle; - static float lasttime; - vec3_t vel; - - - if ( pparams->onground == -1 || - pparams->time == lasttime ) - { - // just use old value - return bob; - } - - lasttime = pparams->time; - - bobtime += pparams->frametime; - cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; - cycle /= cl_bobcycle->value; - - if ( cycle < cl_bobup->value ) - { - cycle = M_PI * cycle / cl_bobup->value; - } - else - { - cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); - } - - // bob is proportional to simulated velocity in the xy plane - // (don't count Z, or jumping messes it up) - VectorCopy( pparams->simvel, vel ); - vel[2] = 0; - - bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; - bob = bob * 0.3 + bob * 0.7 * sin(cycle); - bob = min( bob, 4 ); - bob = max( bob, -7 ); - return bob; - -} - -/* -=============== -V_CalcRoll -Used by view and sv_user -=============== -*/ -float V_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) -{ - float sign; - float side; - float value; - vec3_t forward, right, up; - - AngleVectors ( angles, forward, right, up ); - - side = DotProduct (velocity, right); - sign = side < 0 ? -1 : 1; - side = fabs( side ); - - value = rollangle; - if (side < rollspeed) - { - side = side * value / rollspeed; - } - else - { - side = value; - } - return side * sign; -} - -typedef struct pitchdrift_s -{ - float pitchvel; - int nodrift; - float driftmove; - double laststop; -} pitchdrift_t; - -static pitchdrift_t pd; - -void V_StartPitchDrift( void ) -{ - if ( pd.laststop == gEngfuncs.GetClientTime() ) - { - return; // something else is keeping it from drifting - } - - if ( pd.nodrift || !pd.pitchvel ) - { - pd.pitchvel = v_centerspeed->value; - pd.nodrift = 0; - pd.driftmove = 0; - } -} - -void V_StopPitchDrift ( void ) -{ - pd.laststop = gEngfuncs.GetClientTime(); - pd.nodrift = 1; - pd.pitchvel = 0; -} - -/* -=============== -V_DriftPitch - -Moves the client pitch angle towards idealpitch sent by the server. - -If the user is adjusting pitch manually, either with lookup/lookdown, -mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. -=============== -*/ -void V_DriftPitch ( struct ref_params_s *pparams ) -{ - float delta, move; - - if ( gEngfuncs.IsNoClipping() || !pparams->onground || pparams->demoplayback || pparams->spectator ) - { - pd.driftmove = 0; - pd.pitchvel = 0; - return; - } - - // don't count small mouse motion - if ( pd.nodrift) - { - if ( v_centermove->value > 0 && !(in_mlook.state & 1) ) - { - // this is for lazy players. if they stopped, looked around and then continued - // to move the view will be centered automatically if they move more than - // v_centermove units. - - if ( fabs( pparams->cmd->forwardmove ) < kForwardSpeed ) - pd.driftmove = 0; - else - pd.driftmove += pparams->frametime; - - if ( pd.driftmove > v_centermove->value) - { - V_StartPitchDrift (); - } - else - { - return; // player didn't move enough - } - } - - return; // don't drift view - } - - delta = pparams->idealpitch - pparams->cl_viewangles[PITCH]; - - if (!delta) - { - pd.pitchvel = 0; - return; - } - - move = pparams->frametime * pd.pitchvel; - //pd.pitchvel += pparams->frametime * v_centerspeed->value; - - pd.pitchvel *= (1.0f+(pparams->frametime*0.25f)); // get faster by time - - if (delta > 0) - { - if (move > delta) - { - pd.pitchvel = 0; - move = delta; - } - pparams->cl_viewangles[PITCH] += move; - } - else if (delta < 0) - { - if (move > -delta) - { - pd.pitchvel = 0; - move = -delta; - } - pparams->cl_viewangles[PITCH] -= move; - } -} - -/* -============================================================================== - VIEW RENDERING -============================================================================== -*/ - -/* -================== -V_CalcGunAngle -================== -*/ -void V_CalcGunAngle ( struct ref_params_s *pparams ) -{ - cl_entity_t *viewent; - - viewent = gEngfuncs.GetViewModel(); - if ( !viewent ) - return; - - viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; - viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; - viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; - - // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. - viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); - viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; - - VectorCopy( viewent->angles, viewent->curstate.angles ); - VectorCopy( viewent->angles, viewent->latched.prevangles ); -} - -/* -============== -V_AddIdle - -Idle swaying -============== -*/ -void V_AddIdle ( struct ref_params_s *pparams ) -{ - pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; - pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; - pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; -} - - -/* -============== -V_CalcViewRoll - -Roll is induced by movement and damage -============== -*/ -void V_CalcViewRoll ( struct ref_params_s *pparams ) -{ - float side; - cl_entity_t *viewentity; - - viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); - if ( !viewentity ) - return; - - side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); - - pparams->viewangles[ROLL] += side; - - if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) - { - // only roll the view if the player is dead and the viewheight[2] is nonzero - // this is so deadcam in multiplayer will work. - pparams->viewangles[ROLL] = 80; // dead view angle - return; - } -} - - -/* -================== -V_CalcIntermissionRefdef - -================== -*/ -void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) -{ - cl_entity_t *ent, *view; - float old; - - // ent is the player model ( visible when out of body ) - ent = gEngfuncs.GetLocalPlayer(); - - // view is the weapon model (only visible from inside body ) - view = gEngfuncs.GetViewModel(); - - VectorCopy ( pparams->simorg, pparams->vieworg ); - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); - - view->model = NULL; - - // allways idle in intermission - old = v_idlescale; - v_idlescale = 1; - - V_AddIdle ( pparams ); - - if ( gEngfuncs.IsSpectateOnly() ) - { - // in HLTV we must go to 'intermission' position by ourself - VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); - VectorCopy( gHUD.m_Spectator.m_cameraAngles, pparams->viewangles ); - } - - v_idlescale = old; - - v_cl_angles = pparams->cl_viewangles; - v_origin = pparams->vieworg; - v_angles = pparams->viewangles; - v_view_ofs = pparams->viewheight; - -} - -#define ORIGIN_BACKUP 64 -#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) - -typedef struct -{ - float Origins[ ORIGIN_BACKUP ][3]; - float OriginTime[ ORIGIN_BACKUP ]; - - float Angles[ ORIGIN_BACKUP ][3]; - float AngleTime[ ORIGIN_BACKUP ]; - - int CurrentOrigin; - int CurrentAngle; -} viewinterp_t; - -/* -================== -V_CalcRefdef - -================== -*/ -void V_CalcNormalRefdef ( struct ref_params_s *pparams ) -{ - cl_entity_t *ent, *view; - int i; - vec3_t angles; - float bob, waterOffset; - static viewinterp_t ViewInterp; - - static float oldz = 0; - static float lasttime; - - vec3_t camAngles, camForward, camRight, camUp; - cl_entity_t *pwater; - - V_DriftPitch ( pparams ); - - if ( gEngfuncs.IsSpectateOnly() ) - { - ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); - } - else - { - // ent is the player model ( visible when out of body ) - ent = gEngfuncs.GetLocalPlayer(); - } - - // view is the weapon model (only visible from inside body ) - view = gEngfuncs.GetViewModel(); - - // transform the view offset by the model's matrix to get the offset from - // model origin for the view - bob = V_CalcBob ( pparams ); - - // refresh position - VectorCopy ( pparams->simorg, pparams->vieworg ); - pparams->vieworg[2] += ( bob ); - VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); - - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); - - gEngfuncs.V_CalcShake(); - gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); - - // never let view origin sit exactly on a node line, because a water plane can - // dissapear when viewed with the eye exactly on it. - // FIXME, we send origin at 1/128 now, change this? - // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis - - pparams->vieworg[0] += 1.0/32; - pparams->vieworg[1] += 1.0/32; - pparams->vieworg[2] += 1.0/32; - - // Check for problems around water, move the viewer artificially if necessary - // -- this prevents drawing errors in GL due to waves - - waterOffset = 0; - if ( pparams->waterlevel >= 2 ) - { - int i, contents, waterDist, waterEntity; - vec3_t point; - waterDist = cl_waterdist->value; - - if ( pparams->hardware ) - { - waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); - if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) - { - pwater = gEngfuncs.GetEntityByIndex( waterEntity ); - if ( pwater && ( pwater->model != NULL ) ) - { - waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height - } - } - } - else - { - waterEntity = 0; // Don't need this in software - } - - VectorCopy( pparams->vieworg, point ); - - // Eyes are above water, make sure we're above the waves - if ( pparams->waterlevel == 2 ) - { - point[2] -= waterDist; - for ( i = 0; i < waterDist; i++ ) - { - contents = gEngfuncs.PM_PointContents( point, NULL ); - if ( contents > CONTENTS_WATER ) - break; - point[2] += 1; - } - waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; - } - else - { - // eyes are under water. Make sure we're far enough under - point[2] += waterDist; - - for ( i = 0; i < waterDist; i++ ) - { - contents = gEngfuncs.PM_PointContents( point, NULL ); - if ( contents <= CONTENTS_WATER ) - break; - point[2] -= 1; - } - waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; - } - } - - pparams->vieworg[2] += waterOffset; - - V_CalcViewRoll ( pparams ); - - V_AddIdle ( pparams ); - - // offsets - VectorCopy( pparams->cl_viewangles, angles ); - - AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); - - // don't allow cheats in multiplayer - if ( pparams->maxclients <= 1 ) - { - for ( i=0 ; i<3 ; i++ ) - { - pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; - } - } - - // Treating cam_ofs[2] as the distance - if( CL_IsThirdPerson() ) - { - vec3_t ofs; - - ofs[0] = ofs[1] = ofs[2] = 0.0; - - CL_CameraOffset( (float *)&ofs ); - - VectorCopy( ofs, camAngles ); - camAngles[ ROLL ] = 0; - - AngleVectors( camAngles, camForward, camRight, camUp ); - - for ( i = 0; i < 3; i++ ) - { - pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; - } - } - - // Give gun our viewangles - VectorCopy ( pparams->cl_viewangles, view->angles ); - - // set up gun position - V_CalcGunAngle ( pparams ); - - // Use predicted origin as view origin. - VectorCopy ( pparams->simorg, view->origin ); - view->origin[2] += ( waterOffset ); - VectorAdd( view->origin, pparams->viewheight, view->origin ); - - // Let the viewmodel shake at about 10% of the amplitude - gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); - - for ( i = 0; i < 3; i++ ) - { - view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; - } - view->origin[2] += bob; - - // throw in a little tilt. - view->angles[YAW] -= bob * 0.5; - view->angles[ROLL] -= bob * 1; - view->angles[PITCH] -= bob * 0.3; - - // pushing the view origin down off of the same X/Z plane as the ent's origin will give the - // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem - // with view model distortion, this may be a cause. (SJB). - view->origin[2] -= 1; - - // fudge position around to keep amount of weapon visible - // roughly equal with different FOV - if (pparams->viewsize == 110) - { - view->origin[2] += 1; - } - else if (pparams->viewsize == 100) - { - view->origin[2] += 2; - } - else if (pparams->viewsize == 90) - { - view->origin[2] += 1; - } - else if (pparams->viewsize == 80) - { - view->origin[2] += 0.5; - } - - // Add in the punchangle, if any - VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); - - // Include client side punch, too - VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); - - V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); - - // smooth out stair step ups -#if 1 - if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) - { - float steptime; - - steptime = pparams->time - lasttime; - if (steptime < 0) - //FIXME I_Error ("steptime < 0"); - steptime = 0; - - oldz += steptime * 150; - if (oldz > pparams->simorg[2]) - oldz = pparams->simorg[2]; - if (pparams->simorg[2] - oldz > 18) - oldz = pparams->simorg[2]- 18; - pparams->vieworg[2] += oldz - pparams->simorg[2]; - view->origin[2] += oldz - pparams->simorg[2]; - } - else - { - oldz = pparams->simorg[2]; - } -#endif - - { - static float lastorg[3]; - vec3_t delta; - - VectorSubtract( pparams->simorg, lastorg, delta ); - - if ( Length( delta ) != 0.0 ) - { - VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); - ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; - ViewInterp.CurrentOrigin++; - - VectorCopy( pparams->simorg, lastorg ); - } - } - - // Smooth out whole view in multiplayer when on trains, lifts - if ( cl_vsmoothing && cl_vsmoothing->value && - ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) - { - int foundidx; - int i; - float t; - - if ( cl_vsmoothing->value < 0.0 ) - { - gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); - } - - t = pparams->time - cl_vsmoothing->value; - - for ( i = 1; i < ORIGIN_MASK; i++ ) - { - foundidx = ViewInterp.CurrentOrigin - 1 - i; - if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) - break; - } - - if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) - { - // Interpolate - vec3_t delta; - double frac; - double dt; - vec3_t neworg; - - dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; - if ( dt > 0.0 ) - { - frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; - frac = min( 1.0, frac ); - VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); - VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); - - // Dont interpolate large changes - if ( Length( delta ) < 64 ) - { - VectorSubtract( neworg, pparams->simorg, delta ); - - VectorAdd( pparams->simorg, delta, pparams->simorg ); - VectorAdd( pparams->vieworg, delta, pparams->vieworg ); - VectorAdd( view->origin, delta, view->origin ); - - } - } - } - } - - // Store off v_angles before munging for third person - v_angles = pparams->viewangles; - v_lastAngles = pparams->viewangles; -// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! - if ( CL_IsThirdPerson() ) - { - VectorCopy( camAngles, pparams->viewangles); - float pitch = camAngles[ 0 ]; - - // Normalize angles - if ( pitch > 180 ) - pitch -= 360.0; - else if ( pitch < -180 ) - pitch += 360; - - // Player pitch is inverted - pitch /= -3.0; - - // Slam local player's pitch value - ent->angles[ 0 ] = pitch; - ent->curstate.angles[ 0 ] = pitch; - ent->prevstate.angles[ 0 ] = pitch; - ent->latched.prevangles[ 0 ] = pitch; - } - - // override all previous settings if the viewent isn't the client - if ( pparams->viewentity > pparams->maxclients ) - { - cl_entity_t *viewentity; - viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); - if ( viewentity ) - { - VectorCopy( viewentity->origin, pparams->vieworg ); - VectorCopy( viewentity->angles, pparams->viewangles ); - - // Store off overridden viewangles - v_angles = pparams->viewangles; - } - } - - lasttime = pparams->time; - - v_origin = pparams->vieworg; - v_view_ofs = pparams->viewheight; - -} - -/* -================== -V_CalcTopDownRefdef - -================== -*/ -void V_CalcTopDownRefdef ( struct ref_params_s *pparams ) -{ - cl_entity_t *ent, *view; - int i; - vec3_t angles; - //float waterOffset; - static viewinterp_t ViewInterp; - - static float oldz = 0; - static float lasttime; - - vec3_t camAngles, camForward, camRight, camUp; - //cl_entity_t *pwater; - - V_DriftPitch ( pparams ); - - if ( gEngfuncs.IsSpectateOnly() ) - { - ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); - } - else - { - // ent is the player model ( visible when out of body ) - ent = gEngfuncs.GetLocalPlayer(); - } - - // view is the weapon model (only visible from inside body ) - view = gEngfuncs.GetViewModel(); - - // Override topdown position and angles from physics code - VectorCopy( gTopDownViewOrigin, pparams->vieworg ); - VectorCopy( gTopDownViewOrigin, pparams->simorg ); - - VectorCopy( gTopDownViewAngles, pparams->cl_viewangles ); - VectorCopy( gTopDownViewAngles, pparams->viewangles ); - - gEngfuncs.V_CalcShake(); - gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); - - - V_CalcViewRoll ( pparams ); - - //V_AddIdle ( pparams ); - - // offsets - VectorCopy( pparams->cl_viewangles, angles ); - - AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); - - // don't allow cheats in multiplayer - if ( pparams->maxclients <= 1 ) - { - for ( i=0 ; i<3 ; i++ ) - { - pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; - } - } - - // smooth out stair step ups -#if 1 - if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) - { - float steptime; - - steptime = pparams->time - lasttime; - if (steptime < 0) - //FIXME I_Error ("steptime < 0"); - steptime = 0; - - oldz += steptime * 150; - if (oldz > pparams->simorg[2]) - oldz = pparams->simorg[2]; - if (pparams->simorg[2] - oldz > 18) - oldz = pparams->simorg[2]- 18; - pparams->vieworg[2] += oldz - pparams->simorg[2]; - view->origin[2] += oldz - pparams->simorg[2]; - } - else - { - oldz = pparams->simorg[2]; - } -#endif - - { - static float lastorg[3]; - vec3_t delta; - - VectorSubtract( pparams->simorg, lastorg, delta ); - - if ( Length( delta ) != 0.0 ) - { - VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); - ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; - ViewInterp.CurrentOrigin++; - - VectorCopy( pparams->simorg, lastorg ); - } - } - - // Smooth out whole view in multiplayer when on trains, lifts - if ( cl_vsmoothing && cl_vsmoothing->value && - ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) - { - int foundidx; - int i; - float t; - - if ( cl_vsmoothing->value < 0.0 ) - { - gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); - } - - t = pparams->time - cl_vsmoothing->value; - - for ( i = 1; i < ORIGIN_MASK; i++ ) - { - foundidx = ViewInterp.CurrentOrigin - 1 - i; - if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) - break; - } - - if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) - { - // Interpolate - vec3_t delta; - double frac; - double dt; - vec3_t neworg; - - dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; - if ( dt > 0.0 ) - { - frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; - frac = min( 1.0, frac ); - VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); - VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); - - // Dont interpolate large changes - if ( Length( delta ) < 64 ) - { - VectorSubtract( neworg, pparams->simorg, delta ); - - VectorAdd( pparams->simorg, delta, pparams->simorg ); - VectorAdd( pparams->vieworg, delta, pparams->vieworg ); - VectorAdd( view->origin, delta, view->origin ); - - //VectorCopy( pparams->simorg, gTopDownViewOrigin ); - } - } - } - } - - // Store off v_angles before munging for third person - v_angles = pparams->viewangles; - v_lastAngles = pparams->viewangles; -// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! -// if ( CL_IsThirdPerson() ) -// { -// VectorCopy( camAngles, pparams->viewangles); -// float pitch = camAngles[ 0 ]; -// -// // Normalize angles -// if ( pitch > 180 ) -// pitch -= 360.0; -// else if ( pitch < -180 ) -// pitch += 360; -// -// // Player pitch is inverted -// pitch /= -3.0; -// -// // Slam local player's pitch value -// ent->angles[ 0 ] = pitch; -// ent->curstate.angles[ 0 ] = pitch; -// ent->prevstate.angles[ 0 ] = pitch; -// ent->latched.prevangles[ 0 ] = pitch; -// } - -// // override all previous settings if the viewent isn't the client -// if ( pparams->viewentity > pparams->maxclients ) -// { -// cl_entity_t *viewentity; -// viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); -// if ( viewentity ) -// { -// VectorCopy( viewentity->origin, pparams->vieworg ); -// VectorCopy( viewentity->angles, pparams->viewangles ); -// -// // Store off overridden viewangles -// v_angles = pparams->viewangles; -// } -// } - - lasttime = pparams->time; - - v_origin = pparams->vieworg; - v_view_ofs = pparams->viewheight; - -} -void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) -{ - float absd,frac,d,threshhold; - - NormalizeAngles( startAngle ); - NormalizeAngles( endAngle ); - - for ( int i = 0 ; i < 3 ; i++ ) - { - d = endAngle[i] - startAngle[i]; - - if ( d > 180.0f ) - { - d -= 360.0f; - } - else if ( d < -180.0f ) - { - d += 360.0f; - } - - absd = fabs(d); - - if ( absd > 0.01f ) - { - frac = degreesPerSec * v_frametime; - - threshhold= degreesPerSec / 4; - - if ( absd < threshhold ) - { - float h = absd / threshhold; - h *= h; - frac*= h; // slow down last degrees - } - - if ( frac > absd ) - { - finalAngle[i] = endAngle[i]; - } - else - { - if ( d>0) - finalAngle[i] = startAngle[i] + frac; - else - finalAngle[i] = startAngle[i] - frac; - } - } - else - { - finalAngle[i] = endAngle[i]; - } - - } - - NormalizeAngles( finalAngle ); -} - -// Get the origin of the Observer based around the target's position and angles -void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) -{ - vec3_t vecEnd; - vec3_t forward; - vec3_t vecStart; - pmtrace_t * trace; - int maxLoops = 8; - - int ignoreent = -1; // first, ignore no entity - - cl_entity_t * ent = NULL; - - // Trace back from the target using the player's view angles - AngleVectors(angles, forward, NULL, NULL); - - VectorScale(forward,-1,forward); - - VectorCopy( origin, vecStart ); - - VectorMA(vecStart, distance , forward, vecEnd); - - while ( maxLoops > 0) - { - trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); - - // WARNING! trace->ent is is the number in physent list not the normal entity number - - if ( trace->ent <= 0) - break; // we hit the world or nothing, stop trace - - ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); - - if ( ent == NULL ) - break; - - // hit non-player solid BSP , stop here - if ( ent->curstate.solid == SOLID_BSP && !ent->player ) - break; - - // if close enought to end pos, stop, otherwise continue trace - if( VectorDistance(trace->endpos, vecEnd ) < 1.0f ) - { - break; - } - else - { - ignoreent = trace->ent; // ignore last hit entity - VectorCopy( trace->endpos, vecStart); - } - - maxLoops--; - } - -/* if ( ent ) - { - gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); - } */ - - VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); - - v_lastDistance = VectorDistance(trace->endpos, origin); // real distance without offset -} - -/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) -{ - float newAngle[3]; float newOrigin[3]; - - float distance = 168.0f; - - v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back - - if ( v_resetCamera ) - v_lastDistance = 64.0f; - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player - - // get new angle towards second target - if ( ent2 ) - { - VectorSubtract( ent2->origin, ent1->origin, newAngle ); - VectorAngles( newAngle, newAngle ); - newAngle[0] = -newAngle[0]; - } - else - { - // if no second target is given, look down to dead player - newAngle[0] = 90.0f; - newAngle[1] = 0.0f; - newAngle[2] = 0; - } - - // and smooth view - V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); - - V_GetChaseOrigin( angle, newOrigin, distance, origin ); - - VectorCopy(angle, v_lastAngles); -}*/ - -void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) -{ - float newAngle[3]; float newOrigin[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; - - // see is target is a dead player - qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; - - float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - else if ( deadPlayer ) - distance*=1.5f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - { - if ( deadPlayer ) - newOrigin[2]+= 2; //laying on ground - else - newOrigin[2]+= 17; // head level of living player - - - } - else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS - - // we have no second target, choose view direction based on - // show front of primary target - VectorCopy(ent1->angles, newAngle); - - // show dead players from front, normal players back - if ( flags & DRC_FLAG_FACEPLAYER ) - newAngle[1]+= 180.0f; - - - newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic - - // if final scene (bomb), show from real high pos - if ( flags & DRC_FLAG_FINAL ) - newAngle[0] = 22.5f; - - // choose side of object/player - if ( flags & DRC_FLAG_SIDE ) - newAngle[1]+=22.5f; - else - newAngle[1]-=22.5f; - - V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); - - // HACK, if player is dead don't clip against his dead body, can't check this - V_GetChaseOrigin( angle, newOrigin, distance, origin ); -} - -float MaxAngleBetweenAngles( float * a1, float * a2 ) -{ - float d, maxd = 0.0f; - - NormalizeAngles( a1 ); - NormalizeAngles( a2 ); - - for ( int i = 0 ; i < 3 ; i++ ) - { - d = a2[i] - a1[i]; - if ( d > 180 ) - { - d -= 360; - } - else if ( d < -180 ) - { - d += 360; - } - - d = fabs(d); - - if ( d > maxd ) - maxd=d; - } - - return maxd; -} - -void V_GetDoubleTargetsCam(cl_entity_t * ent1, const cl_entity_t * ent2,float * angle, float * origin) -{ - float newAngle[3]; float newOrigin[3]; float tempVec[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; - - float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player - else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS - - // get new angle towards second target - VectorSubtract( ent2->origin, ent1->origin, newAngle ); - - VectorAngles( newAngle, newAngle ); - newAngle[0] = -newAngle[0]; - - // set angle diffrent in Dramtaic scenes - newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic - - if ( flags & DRC_FLAG_SIDE ) - newAngle[1]+=22.5f; - else - newAngle[1]-=22.5f; - - float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); - - if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) - { - // difference is to small and we are in relax camera mode, keep viewangles - VectorCopy(v_lastAngles, newAngle ); - } - else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) - { - // we catched up with our target, relax again - v_cameraMode = CAM_MODE_RELAX; - } - else - { - // target move too far away, focus camera again - v_cameraMode = CAM_MODE_FOCUS; - } - - // and smooth view, if not a scene cut - if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) - { - VectorCopy( newAngle, angle ); - } - else - { - V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 180.0f ); - } - - V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); - - // move position up, if very close at target - if ( v_lastDistance < 64.0f ) - origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); - - // calculate angle to second target - VectorSubtract( ent2->origin, origin, tempVec ); - VectorAngles( tempVec, tempVec ); - tempVec[0] = -tempVec[0]; - - /* take middle between two viewangles - InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ - - - -} - -void V_GetDirectedChasePosition(cl_entity_t * ent1, const cl_entity_t * ent2,float * angle, float * origin) -{ - - if ( v_resetCamera ) - { - v_lastDistance = 4096.0f; - // v_cameraMode = CAM_MODE_FOCUS; - } - - if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) - { - // we have no second target or player just died - V_GetSingleTargetCam(ent1, angle, origin); - } - else if ( ent2 ) - { - // keep both target in view - V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); - } - else - { - // second target disappeard somehow (dead) - - // keep last good viewangle - float newOrigin[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; - - float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player - else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS - - V_GetChaseOrigin( angle, newOrigin, distance, origin ); - } - - VectorCopy(angle, v_lastAngles); -} - -void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) -{ - cl_entity_t * ent = NULL; - - if ( target ) - { - ent = gEngfuncs.GetEntityByIndex( target ); - }; - - if (!ent) - { - // just copy a save in-map position - VectorCopy ( vJumpAngles, angles ); - VectorCopy ( vJumpOrigin, origin ); - return; - } - - - - if ( gHUD.m_Spectator.m_autoDirector->value ) - { - if ( g_iUser3 ) - V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), - angles, origin ); - else - V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, - angles, origin ); - } - else - { - if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) - { - VectorCopy ( ent->angles, angles); - angles[0]*=-1; - } - else - VectorCopy ( cl_angles, angles); - - - VectorCopy ( ent->origin, origin); - - origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset - - V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); - } - - v_resetCamera = false; -} - -void V_ResetChaseCam() -{ - v_resetCamera = true; -} - - -void V_GetInEyePos(int target, float * origin, float * angles ) -{ - if ( !target) - { - // just copy a save in-map position - VectorCopy ( vJumpAngles, angles ); - VectorCopy ( vJumpOrigin, origin ); - return; - }; - - - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); - - if ( !ent ) - return; - - VectorCopy ( ent->origin, origin ); - VectorCopy ( ent->angles, angles ); - - angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() - - if ( ent->curstate.solid == SOLID_NOT ) - { - angles[ROLL] = 80; // dead view angle - origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT - } - else if (ent->curstate.usehull == 1 ) - origin[2]+= 12; // VEC_DUCK_VIEW; - else - // exacty eye position can't be caluculated since it depends on - // client values like cl_bobcycle, this offset matches the default values - origin[2]+= 28; // DEFAULT_VIEWHEIGHT -} - -void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) -{ - vec3_t forward; - vec3_t zScaledTarget; - - VectorCopy(cl_angles, angles); - - // modify angles since we don't wanna see map's bottom - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); - - zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; - zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; - zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); - - - AngleVectors(angles, forward, NULL, NULL); - - VectorNormalize(forward); - - VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); -} - -void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) -{ - vec3_t forward; - - if ( target ) - { - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); - - if ( gHUD.m_Spectator.m_autoDirector->value ) - { - // this is done to get the angles made by director mode - V_GetChasePos(target, cl_angles, origin, angles); - VectorCopy(ent->origin, origin); - - // keep fix chase angle horizontal - angles[0] = 45.0f; - } - else - { - VectorCopy(cl_angles, angles); - VectorCopy(ent->origin, origin); - - // modify angles since we don't wanna see map's bottom - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); - } - } - else - { - // keep out roaming position, but modify angles - VectorCopy(cl_angles, angles); - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); - } - - origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); - angles[2] = 0.0f; // don't roll angle (if chased player is dead) - - AngleVectors(angles, forward, NULL, NULL); - - VectorNormalize(forward); - - VectorMA(origin, -1536, forward, origin); -} - -void V_GetMiniMapOriginAndAngle(float * cl_angles, float * origin, float * angles) -{ - // Center map on local player - VectorCopy(gEngfuncs.GetLocalPlayer()->curstate.origin, origin); - //v_origin.z += 300; - - //// Set view height above parsed map settings - origin[2] = gHUD.m_Spectator.m_OverviewData.origin.z + 100; - - //if(gHUD.m_Spectator.m_OverviewData.layers > 0) - //{ - // v_origin.z = gHUD.m_Spectator.m_OverviewData.layersHeights[0]; - //} - // - //v_origin.z += 300; - - //V_GetMapChasePosition(gEngfuncs.GetLocalPlayer()->index, v_cl_angles, v_origin, v_angles ); - - // Set view like top down - cl_angles[0] = angles[0] = 90;//kTopDownYaw; - cl_angles[1] = angles[1] = 90;//kTopDownPitch; - cl_angles[2] = angles[2] = 0;//kTopDownRoll; -} - -int V_FindViewModelByWeaponModel(int weaponindex, int inUser3, int inUser4) -{ - int theViewModelIndex = 0; - - static char * modelmap[][2] = { - { kKNPModel, kKNVModel }, - { kHGPModel, kHGVModel }, - { kMGPModel, kMGVModel }, - { kSGPModel, kSGVModel }, - { kHMGPModel, kHMGVModel }, - { kGGPModel, kGGVModel }, - { kTripminePModel, kTripmineVModel }, - { kWelderPModel, kWelderVModel }, - { NULL, NULL } - }; - - static char * hvymodelmap[][2] = { - { kKNPModel, kKNHVVModel }, - { kHGPModel, kHGHVVModel }, - { kMGPModel, kMGHVVModel }, - { kSGPModel, kSGHVVModel }, - { kHMGPModel, kHMGHVVModel }, - { kGGPModel, kGGHVVModel }, - { kTripminePModel, kTripmineHVVModel }, - { kWelderPModel, kWelderHVVModel }, - { NULL, NULL } - }; - - struct model_s * weaponModel = NULL; - - // If we're an alien, get view model that way - if((inUser3 == AVH_USER3_ALIEN_PLAYER1) || (inUser3 == AVH_USER3_ALIEN_PLAYER2) || (inUser3 == AVH_USER3_ALIEN_PLAYER3) || (inUser3 == AVH_USER3_ALIEN_PLAYER4) || (inUser3 == AVH_USER3_ALIEN_PLAYER5)) - { - const char* theViewModel = ""; - switch(inUser3) - { - case AVH_USER3_ALIEN_PLAYER1: - theViewModel = kLevel1ViewModel; - break; - case AVH_USER3_ALIEN_PLAYER2: - theViewModel = kLevel2ViewModel; - break; - case AVH_USER3_ALIEN_PLAYER3: - theViewModel = kLevel3ViewModel; - break; - case AVH_USER3_ALIEN_PLAYER4: - theViewModel = kLevel4ViewModel; - break; - case AVH_USER3_ALIEN_PLAYER5: - theViewModel = kLevel5ViewModel; - break; - } - - theViewModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex(theViewModel); - } - // else we're holding a weapon - else - { - // Take user3 and user4 into account for heavy armor - if(inUser3 == AVH_USER3_MARINE_PLAYER) - { - weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); - - if ( weaponModel ) - { - //int len = strlen( weaponModel->name ); - int i = 0; - - if(GetHasUpgrade(inUser4, MASK_UPGRADE_13)) - { - while ( *hvymodelmap[i] != NULL ) - { - const char* theCurrentPWeapon = hvymodelmap[i][0]; - const char* theCurrentVWeapon = hvymodelmap[i][1]; - - if ( !SafeStrcmp( weaponModel->name, theCurrentPWeapon) ) - { - theViewModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( theCurrentVWeapon ); - } - i++; - } - } - else - { - while ( *modelmap[i] != NULL ) - { - const char* theCurrentPWeapon = modelmap[i][0]; - const char* theCurrentVWeapon = modelmap[i][1]; - - if ( !SafeStrcmp( weaponModel->name, theCurrentPWeapon) ) - { - theViewModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( theCurrentVWeapon ); - } - i++; - } - } - } - } - } - - return theViewModelIndex; -} - -/* -================== -V_CalcSpectatorRefdef - -================== -*/ - -static int lastWeaponModelIndex = 0; -static int lastViewModelIndex = 0; - -void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) -{ - - vec3_t angles; - static viewinterp_t ViewInterp; - static float bob = 0.0f; - static vec3_t velocity ( 0.0f, 0.0f, 0.0f); - - static float lasttime; - - static float lastang[3]; - static float lastorg[3]; - - vec3_t delta; - pparams->onlyClientDraw = false; - - // refresh position - VectorCopy ( pparams->simorg, v_sim_org ); - - // get old values - VectorCopy ( pparams->cl_viewangles, v_cl_angles ); - VectorCopy ( pparams->viewangles, v_angles ); - VectorCopy ( pparams->vieworg, v_origin ); - VectorCopy ( pparams->viewheight, v_view_ofs); - - v_frametime = pparams->frametime; - - if ( pparams->nextView == 0 ) - { - // first renderer cycle, full screen - - if (!gHUD.m_Spectator.IsInOverviewMode()) - { - - switch ( g_iUser1 ) - { - case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); - break; - - case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); - VectorCopy (v_sim_org, v_origin); - break; - - case OBS_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); - break; - - } - - } - else - { - pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - } - - - // Removed by mmcguire. - /* - switch ( g_iUser1 ) - { - case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); - break; - - case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); - VectorCopy (v_sim_org, v_origin); - break; - - case OBS_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); - break; - - case OBS_MAP_FREE : pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - break; - - case OBS_MAP_CHASE : pparams->onlyClientDraw = true; - V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - } - */ - - if (g_iUser1) - { - - // Adjust the viewport so that the letterbox spectator mode - // doesn't cut anything off. - - pparams->viewport[1] += YRES(32); - pparams->viewport[3] -= YRES(32 * 2); - - } - - if ( gHUD.m_Spectator.IsInOverviewMode()) - { - pparams->nextView = 1; // force a second renderer view - } - - gHUD.m_Spectator.m_iDrawCycle = 0; - - } - else - { - // second renderer cycle, inset window - - // set inset parameters - pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX) + 1; // change viewport to inset window - pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY) + 1; - pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth) - 2; - pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight) - 2; - pparams->nextView = 0; // on further view - pparams->onlyClientDraw = false; - - if (gHUD.m_Spectator.IsInOverviewMode()) - { - if (g_iUser1 == OBS_IN_EYE) - { - V_GetInEyePos( g_iUser2, v_origin, v_angles ); - } - else if (g_iUser1 == OBS_CHASE_FREE) - { - V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - } - else if (g_iUser1 == OBS_CHASE_LOCKED) - - { - V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); - } - else if (g_iUser1 == OBS_ROAMING) - { - VectorCopy (v_cl_angles, v_angles); - VectorCopy (v_sim_org, v_origin); - } - } - - // Removed by mmcguire. - /* - // override some settings in certain modes - switch ( (int)gHUD.m_Spectator.m_pip->value ) - { - case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case INSET_CHASE_LOCKED : V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); - break; - - case INSET_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); - break; - - case INSET_MAP_FREE : pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - break; - - case INSET_MAP_CHASE : pparams->onlyClientDraw = true; - - if ( g_iUser1 == OBS_ROAMING ) - V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); - else - V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); - - break; - } - */ - - gHUD.m_Spectator.m_iDrawCycle = 1; - } - - - // do the smoothing only once per frame, not in roaming or map mode - if ( (gHUD.m_Spectator.m_iDrawCycle == 0) && (g_iUser1 == OBS_IN_EYE) ) - { - // smooth angles - - VectorSubtract( v_angles, lastang, delta ); - if ( Length( delta ) != 0.0f ) - { - VectorCopy( v_angles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); - ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; - ViewInterp.CurrentAngle++; - VectorCopy( v_angles, lastang ); - } - - if ( cl_vsmoothing && cl_vsmoothing->value ) - { - int foundidx; - int i; - float t; - - t = pparams->time - cl_vsmoothing->value; - - for ( i = 1; i < ORIGIN_MASK; i++ ) - { - foundidx = ViewInterp.CurrentAngle - 1 - i; - if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) - break; - } - - if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) - { - // Interpolate - double dt; - float da; - vec3_t v1,v2; - - AngleVectors( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], v1, NULL, NULL ); - AngleVectors( ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v2, NULL, NULL ); - da = AngleBetweenVectors( v1, v2 ); - - dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; - - if ( dt > 0.0 && ( da < 22.5f) ) - { - double frac; - - frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; - frac = min( 1.0, frac ); - - // interpolate angles - InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v_angles, frac ); - } - } - } - - // smooth origin - - VectorSubtract( v_origin, lastorg, delta ); - - if ( Length( delta ) != 0.0 ) - { - VectorCopy( v_origin, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); - ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; - ViewInterp.CurrentOrigin++; - - VectorCopy( v_origin, lastorg ); - } - - // don't smooth in roaming (already smoothd), - if ( cl_vsmoothing && cl_vsmoothing->value ) - { - int foundidx; - int i; - float t; - - t = pparams->time - cl_vsmoothing->value; - - for ( i = 1; i < ORIGIN_MASK; i++ ) - { - foundidx = ViewInterp.CurrentOrigin - 1 - i; - if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) - break; - } - - if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) - { - // Interpolate - vec3_t delta; - double frac; - double dt; - vec3_t neworg; - - dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; - if ( dt > 0.0 ) - { - frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; - frac = min( 1.0, frac ); - VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); - VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); - - // Dont interpolate large changes - if ( Length( delta ) < 64 ) - { - VectorCopy( neworg, v_origin ); - } - } - } - } - } - - // Hack in weapon model: - cl_entity_t* ent = gEngfuncs.GetEntityByIndex(g_iUser2); - cl_entity_t* gunModel = gEngfuncs.GetViewModel(); - if ( (g_iUser1 == OBS_IN_EYE) && ent && g_iUser2 ) - { - // get position for weapon model - VectorCopy( v_origin, gunModel->origin); - VectorCopy( v_angles, gunModel->angles); - - // add idle tremble - gunModel->angles[PITCH]*=-1; - - // calculate player velocity - float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; - - if ( timeDiff > 0 ) - { - vec3_t distance; - VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); - VectorScale(distance, 1/timeDiff, distance ); - - velocity[0] = velocity[0]*0.66f + distance[0]*0.33f; - velocity[1] = velocity[1]*0.66f + distance[1]*0.33f; - velocity[2] = velocity[2]*0.66f + distance[2]*0.33f; - - VectorCopy(velocity, pparams->simvel); - pparams->onground = 1; - - bob = V_CalcBob( pparams ); - } - - vec3_t forward; - AngleVectors(v_angles, forward, NULL, NULL ); - - for ( int i = 0; i < 3; i++ ) - { - gunModel->origin[ i ] += bob * 0.4 * forward[ i ]; - } - - // throw in a little tilt. - gunModel->angles[YAW] -= bob * 0.5; - gunModel->angles[ROLL] -= bob * 1; - gunModel->angles[PITCH] -= bob * 0.3; - - VectorCopy( gunModel->angles, gunModel->curstate.angles ); - VectorCopy( gunModel->angles, gunModel->latched.prevangles ); - - lastWeaponModelIndex = ent->curstate.weaponmodel; - int theCurrentViewModel = V_FindViewModelByWeaponModel( lastWeaponModelIndex, ent->curstate.iuser3, ent->curstate.iuser4); - - //if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) - if ( lastViewModelIndex != theCurrentViewModel ) - { - // weapon model changed - lastViewModelIndex = theCurrentViewModel; - if ( lastViewModelIndex ) - { - gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation - } - else - { - // model not found - gunModel->model = NULL; // disable weaopn model - lastWeaponModelIndex = lastViewModelIndex = 0; - } - } - - if ( lastViewModelIndex ) - { - gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); - gunModel->curstate.modelindex = lastViewModelIndex; - gunModel->curstate.frame = 0; - gunModel->curstate.colormap = 0; - gunModel->index = g_iUser2; - } - else - { - gunModel->model = NULL; // disable weaopn model - } - } - else - { - gunModel->model = NULL; // disable weaopn model - lastWeaponModelIndex = lastViewModelIndex = 0; - } - - lasttime = pparams->time; - - // write back new values into pparams - VectorCopy ( v_cl_angles, pparams->cl_viewangles ); - VectorCopy ( v_angles, pparams->viewangles ) - VectorCopy ( v_origin, pparams->vieworg ); - -} - - - -void CL_DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) -{ -// RecClCalcRefdef(pparams); - - // intermission / finale rendering - if ( pparams->intermission ) - { - V_CalcIntermissionRefdef ( pparams ); - } - else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode - { - V_CalcSpectatorRefdef ( pparams ); - } - else if ( !pparams->paused ) - { - if(gHUD.GetInTopDownMode()) - { - V_CalcTopDownRefdef ( pparams ); - } - else - { - V_CalcNormalRefdef ( pparams ); - } - } - -/* -// Example of how to overlay the whole screen with red at 50 % alpha -#define SF_TEST -#if defined SF_TEST - { - screenfade_t sf; - gEngfuncs.pfnGetScreenFade( &sf ); - - sf.fader = 255; - sf.fadeg = 0; - sf.fadeb = 0; - sf.fadealpha = 128; - sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; - - gEngfuncs.pfnSetScreenFade( &sf ); - } -#endif -*/ -} - -/* -============= -V_DropPunchAngle - -============= -*/ -void V_DropPunchAngle ( float frametime, float *ev_punchangle ) -{ - float len; - - len = VectorNormalize ( ev_punchangle ); - len -= (10.0 + len * 0.5) * frametime; - len = max( len, 0.0 ); - VectorScale ( ev_punchangle, len, ev_punchangle ); -} - -/* -============= -V_PunchAxis - -Client side punch effect -============= -*/ -void V_PunchAxis( int axis, float punch ) -{ - ev_punchangle[ axis ] = punch; -} - -/* -============= -V_Init -============= -*/ -void V_Init (void) -{ - gEngfuncs.pfnAddCommand ("centerview", V_StartPitchDrift ); - - scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); - scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); - scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); - - v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); - v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); - - cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) - cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) - cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); - cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); - cl_hudcam = gEngfuncs.pfnRegisterVariable( "cl_hudcam", "1", 0 ); - cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist", "200", 0 ); -} - - -//#define TRACE_TEST -#if defined( TRACE_TEST ) - -extern float in_fov; -/* -==================== -CalcFov -==================== -*/ -float CalcFov (float fov_x, float width, float height) -{ - float a; - float x; - - if (fov_x < 1 || fov_x > 179) - fov_x = 90; // error, set to 90 - - x = width/tan(fov_x/360*M_PI); - - a = atan (height/x); - - a = a*360/M_PI; - - return a; -} - -int hitent = -1; -extern playermove_t *pmove; -void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert) -{ - float linestep = 2.0f; - float curdist; - float len; - vec3_t curpos; - vec3_t diff; - int i; - // Determine distance; - - VectorSubtract(end, start, diff); - - len = VectorNormalize(diff); - - curdist = 0; - while (curdist <= len) - { - for (i = 0; i < 3; i++) - curpos[i] = start[i] + curdist * diff[i]; - - pmove->PM_Particle( curpos, pcolor, life, 0, vert); - curdist += linestep; - } - -} -void V_Move( int mx, int my ) -{ - float fov; - float fx, fy; - float dx, dy; - float c_x, c_y; - float dX, dY; - vec3_t forward, up, right; - vec3_t newangles; - - vec3_t farpoint; - pmtrace_t tr; - - fov = CalcFov( in_fov, (float)ScreenWidth(), (float)ScreenHeight() ); - - c_x = (float)ScreenWidth() / 2.0; - c_y = (float)ScreenHeight() / 2.0; - - dx = (float)mx - c_x; - dy = (float)my - c_y; - - // Proportion we moved in each direction - fx = dx / c_x; - fy = dy / c_y; - - dX = fx * in_fov / 2.0 ; - dY = fy * fov / 2.0; - - newangles = v_angles; - - newangles[ YAW ] -= dX; - newangles[ PITCH ] += dY; - - // Now rotate v_forward around that point - AngleVectors ( newangles, forward, right, up ); - - farpoint = v_origin + 8192 * forward; - - // Trace - tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); - - if ( tr.fraction != 1.0 && tr.ent != 0 ) - { - hitent = PM_GetPhysEntInfo( tr.ent ); - PM_ParticleLine( (vec3_t)v_origin, (vec3_t)tr.endpos, 5, 1.0, 0.0 ); - } - else - { - hitent = -1; - } -} - -#endif - - - - -///* -//================== -//V_CalcTopDownRefdef -// -//================== -//*/ -//void V_CalcTopDownRefdef ( struct ref_params_s *pparams ) -//{ -// cl_entity_t *ent, *view; -// int i; -// vec3_t angles; -// static viewinterp_t ViewInterp; -// -// static float oldz = 0; -// static float lasttime; -// -// static float lastang[3]; -// vec3_t angdelta; -// -// vec3_t camAngles, camForward, camRight, camUp; -// //cl_entity_t *pwater; -// -// // don't allow cheats in multiplayer -// if ( pparams->maxclients > 1 ) -// { -// scr_ofsx->value = 0.0; -// scr_ofsy->value = 0.0; -// scr_ofsz->value = 0.0; -// } -// -// -// V_DriftPitch ( pparams ); -// -// // ent is the player model ( visible when out of body ) -// ent = gEngfuncs.GetLocalPlayer(); -// -// // view is the weapon model (only visible from inside body ) -// view = gEngfuncs.GetViewModel(); -// -// // Observer angle capturing and smoothing -// if ( iHasNewViewOrigin ) -// { -// // Get the angles from the physics code -// VectorCopy( gTopDownViewOrigin, pparams->vieworg ); -// VectorCopy( gTopDownViewOrigin, pparams->simorg ); -// } -// -// // Override position to commander position -// pparams->vieworg[2] = gTopDownHeight; -// pparams->simorg[2] = gTopDownHeight; -// -// // Override view height when in top down -// pparams->viewheight[2] = 0.0f; -// -// // refresh position -// VectorCopy ( pparams->simorg, pparams->vieworg ); -// VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); -// -// // Observer angle capturing and smoothing -// if ( iHasNewViewAngles ) -// { -// // Get the angles from the physics code -// VectorCopy( gTopDownViewAngles, pparams->cl_viewangles ); -// } -// -// VectorSubtract( pparams->cl_viewangles, lastang, angdelta ); -// if ( Length( angdelta ) != 0.0 ) -// { -// VectorCopy( pparams->cl_viewangles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); -// ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; -// ViewInterp.CurrentAngle++; -// -// VectorCopy( pparams->cl_viewangles, lastang ); -// } -// -// if ( cl_vsmoothing && cl_vsmoothing->value && ( iIsSpectator & SPEC_SMOOTH_ANGLES ) ) -// { -// int foundidx; -// int i; -// float t; -// -// if ( cl_vsmoothing->value < 0.0 ) -// { -// gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); -// } -// -// t = pparams->time - cl_vsmoothing->value; -// -// for ( i = 1; i < ORIGIN_MASK; i++ ) -// { -// foundidx = ViewInterp.CurrentAngle - 1 - i; -// if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) -// break; -// } -// -// if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) -// { -// // Interpolate -// double dt; -// -// dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; -// if ( dt > 0.0 ) -// { -// double frac; -// -// frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; -// frac = min( 1.0, frac ); -// -// // interpolate angles -// InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], pparams->cl_viewangles, frac ); -// -// VectorCopy( pparams->cl_viewangles, gTopDownViewAngles ); -// } -// } -// } -// -// -// VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); -// -// gEngfuncs.V_CalcShake(); -// gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); -// -//// // never let view origin sit exactly on a node line, because a water plane can -//// // dissapear when viewed with the eye exactly on it. -//// // FIXME, we send origin at 1/128 now, change this? -//// // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis -//// -//// pparams->vieworg[0] += 1.0/32; -//// pparams->vieworg[1] += 1.0/32; -//// pparams->vieworg[2] += 1.0/32; -// -// // Check for problems around water, move the viewer artificially if necessary -// // -- this prevents drawing errors in GL due to waves -// -//// if ( pparams->waterlevel >= 2 ) -//// { -//// int waterDist, waterEntity; -//// vec3_t point; -//// waterDist = cl_waterdist->value; -//// -//// if ( pparams->hardware ) -//// { -//// waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); -//// if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) -//// { -//// pwater = gEngfuncs.GetEntityByIndex( waterEntity ); -//// if ( pwater && ( pwater->model != NULL ) ) -//// { -//// waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height -//// } -//// } -//// } -//// else -//// { -//// waterEntity = 0; // Don't need this in software -//// } -//// -//// VectorCopy( pparams->vieworg, point ); -//// } -// -// V_CalcViewRoll ( pparams ); -// -// //V_AddIdle ( pparams ); -// -// // offsets -// VectorCopy( pparams->cl_viewangles, angles ); -// -// AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); -// -// for ( i=0 ; i<3 ; i++ ) -// { -// pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; -// } -// -// // Treating cam_ofs[2] as the distance -//// if( CL_IsThirdPerson() ) -//// { -//// vec3_t ofs; -//// -//// ofs[0] = ofs[1] = ofs[2] = 0.0; -//// -//// CL_CameraOffset( (float *)&ofs ); -//// -//// VectorCopy( ofs, camAngles ); -//// camAngles[ ROLL ] = 0; -//// -//// AngleVectors( camAngles, camForward, camRight, camUp ); -//// -//// for ( i = 0; i < 3; i++ ) -//// { -//// pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; -//// } -//// } -// -// // Give gun our viewangles -//// VectorCopy ( pparams->cl_viewangles, view->angles ); -// -// // set up gun position -//// V_CalcGunAngle ( pparams ); -// -// // Use predicted origin as view origin. -// VectorCopy ( pparams->simorg, view->origin ); -// VectorAdd( view->origin, pparams->viewheight, view->origin ); -// -// // Let the viewmodel shake at about 10% of the amplitude -//// gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); -// -// // smooth out stair step ups -//#if 1 -// if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) -// { -// float steptime; -// -// steptime = pparams->time - lasttime; -// if (steptime < 0) -// //FIXME I_Error ("steptime < 0"); -// steptime = 0; -// -// oldz += steptime * 150; -// if (oldz > pparams->simorg[2]) -// oldz = pparams->simorg[2]; -// if (pparams->simorg[2] - oldz > 18) -// oldz = pparams->simorg[2]- 18; -// pparams->vieworg[2] += oldz - pparams->simorg[2]; -// view->origin[2] += oldz - pparams->simorg[2]; -// } -// else -// { -// oldz = pparams->simorg[2]; -// } -//#endif -// -// { -// static float lastorg[3]; -// vec3_t delta; -// -// VectorSubtract( pparams->simorg, lastorg, delta ); -// -// if ( Length( delta ) != 0.0 ) -// { -// VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); -// ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; -// ViewInterp.CurrentOrigin++; -// -// VectorCopy( pparams->simorg, lastorg ); -// } -// } -// -// // Smooth out whole view in multiplayer when on trains, lifts -// if ( cl_vsmoothing && cl_vsmoothing->value && -// ( ( iIsSpectator & SPEC_SMOOTH_ORIGIN ) || (pparams->smoothing && ( pparams->maxclients > 1 ) ) ) ) -// { -// int foundidx; -// int i; -// float t; -// -// if ( cl_vsmoothing->value < 0.0 ) -// { -// gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); -// } -// -// t = pparams->time - cl_vsmoothing->value; -// -// for ( i = 1; i < ORIGIN_MASK; i++ ) -// { -// foundidx = ViewInterp.CurrentOrigin - 1 - i; -// if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) -// break; -// } -// -// if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) -// { -// // Interpolate -// vec3_t delta; -// double frac; -// double dt; -// vec3_t neworg; -// -// dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; -// if ( dt > 0.0 ) -// { -// frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; -// frac = min( 1.0, frac ); -// VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); -// VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); -// -// // Dont interpolate large changes -// if ( Length( delta ) < 64 ) -// { -// VectorSubtract( neworg, pparams->simorg, delta ); -// -// VectorAdd( pparams->simorg, delta, pparams->simorg ); -// VectorAdd( pparams->vieworg, delta, pparams->vieworg ); -// VectorAdd( view->origin, delta, view->origin ); -// -// VectorCopy( pparams->simorg, gTopDownViewOrigin ); -// } -// } -// } -// } -// -// // Store off v_angles before munging for third person -// v_angles = pparams->viewangles; -// -// // override all previous settings if the viewent isn't the client -// if ( pparams->viewentity > pparams->maxclients ) -// { -// cl_entity_t *viewentity; -// viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); -// if ( viewentity ) -// { -// VectorCopy( viewentity->origin, pparams->vieworg ); -// VectorCopy( viewentity->angles, pparams->viewangles ); -// -// // Store off overridden viewangles -// v_angles = pparams->viewangles; -// } -// } -// -// lasttime = pparams->time; -// -// v_origin = pparams->vieworg; -//} - +// view/refresh setup functions + +#include "hud.h" +#include "cl_util.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" + +#include "entity_state.h" +#include "cl_entity.h" +#include "ref_params.h" +#include "in_defs.h" // PITCH YAW ROLL +#include "pm_movevars.h" +#include "pm_shared.h" +#include "pm_defs.h" +#include "event_api.h" +#include "pmtrace.h" +#include "bench.h" +#include "screenfade.h" +#include "engine/shake.h" +#include "mod/AvHClientUtil.h" +#include "engine/APIProxy.h" +#include "hltv.h" +#include "Exports.h" +#include "common/hltv.h" +#include "util/MathUtil.h" +#include "util/STLUtil.h" +#include "mod/AvHMarineEquipmentConstants.h" +#include "mod/AvHMarineWeaponConstants.h" +#include "mod/AvHAlienWeaponConstants.h" +#include "mod/AvHSpecials.h" + +extern float gTopDownViewOrigin[3]; +extern float gTopDownViewAngles[3]; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +int CL_IsThirdPerson( void ); +void CL_CameraOffset( float *ofs ); + +void CL_DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); + +void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); +int PM_GetVisEntInfo( int ent ); +int PM_GetPhysEntInfo( int ent ); +//@linux +void InterpolateAngles( float * start, float * end, float * output, float frac ); +void NormalizeAngles( float * angles ); +//extern "C" float Distance(const float * v1, const float * v2); +//float AngleBetweenVectors(const float * v1, const float * v2 ); + +void V_DropPunchAngle ( float frametime, float *ev_punchangle ); +void VectorAngles( const float *forward, float *angles ); +void V_CalcTopDownRefdef ( struct ref_params_s *pparams ); + +extern float vJumpOrigin[3]; +extern float vJumpAngles[3]; + +#include "r_studioint.h" +#include "common/com_model.h" +#include "kbutton.h" + +extern engine_studio_api_t IEngineStudio; + +extern kbutton_t in_mlook; + +/* +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. +*/ + +extern cvar_t *cl_forwardspeed; +extern cvar_t *chase_active; +extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; +extern cvar_t *cl_vsmoothing; + +#define CAM_MODE_RELAX 1 +#define CAM_MODE_FOCUS 2 + +vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles, v_view_ofs; +float v_frametime, v_lastDistance; +float v_cameraRelaxAngle = 5.0f; +float v_cameraFocusAngle = 35.0f; +int v_cameraMode = CAM_MODE_FOCUS; +qboolean v_resetCamera = 1; + +extern float gTopDownHeight; + +vec3_t gLastCommanderViewpoint; + +vec3_t ev_punchangle; + +cvar_t *scr_ofsx; +cvar_t *scr_ofsy; +cvar_t *scr_ofsz; + +cvar_t *v_centermove; +cvar_t *v_centerspeed; + +cvar_t *cl_bobcycle; +cvar_t *cl_bob; +cvar_t *cl_bobup; +cvar_t *cl_waterdist; +cvar_t *cl_chasedist; +cvar_t *cl_hudcam; + +// These cvars are not registered (so users can't cheat), so set the ->value field directly +// Register these cvars in V_Init() if needed for easy tweaking +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; + +float v_idlescale; // used by TFC for concussion grenade effect + +//@linux + +void NormalizeAngles( float *angles ) +{ + int i; + // Normalize angles + for ( i = 0; i < 3; i++ ) + { + if ( angles[i] > 180.0 ) + { + angles[i] -= 360.0; + } + else if ( angles[i] < -180.0 ) + { + angles[i] += 360.0; + } + } +} + +/* +=================== +InterpolateAngles + +Interpolate Euler angles. +FIXME: Use Quaternions to avoid discontinuities +Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) +=================== +*/ +void InterpolateAngles( float *start, float *end, float *output, float frac ) +{ + int i; + float ang1, ang2; + float d; + + NormalizeAngles( start ); + NormalizeAngles( end ); + + for ( i = 0 ; i < 3 ; i++ ) + { + ang1 = start[i]; + ang2 = end[i]; + + d = ang2 - ang1; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + output[i] = ang1 + d * frac; + } + + NormalizeAngles( output ); +} + +/* +=================== +AngleBetweenVectors + +=================== +*/ +float AngleBetweenVectors( float* v1, float* v2 ) +{ + float angle; + float l1 = Length( v1 ); + float l2 = Length( v2 ); + + if ( !l1 || !l2 ) + return 0.0f; + + angle = acos( DotProduct( v1, v2 ) ) / (l1*l2); + angle = ( angle * 180.0f ) / M_PI; + + return angle; +} + +//============================================================================= +/* +void V_NormalizeAngles( float *angles ) +{ + int i; + // Normalize angles + for ( i = 0; i < 3; i++ ) + { + if ( angles[i] > 180.0 ) + { + angles[i] -= 360.0; + } + else if ( angles[i] < -180.0 ) + { + angles[i] += 360.0; + } + } +} + +/* +=================== +V_InterpolateAngles + +Interpolate Euler angles. +FIXME: Use Quaternions to avoid discontinuities +Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) +=================== + +void V_InterpolateAngles( float *start, float *end, float *output, float frac ) +{ + int i; + float ang1, ang2; + float d; + + V_NormalizeAngles( start ); + V_NormalizeAngles( end ); + + for ( i = 0 ; i < 3 ; i++ ) + { + ang1 = start[i]; + ang2 = end[i]; + + d = ang2 - ang1; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + output[i] = ang1 + d * frac; + } + + V_NormalizeAngles( output ); +} */ + +// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear +float V_CalcBob ( struct ref_params_s *pparams ) +{ + static double bobtime; + static float bob; + float cycle; + static float lasttime; + vec3_t vel; + + + if ( pparams->onground == -1 || + pparams->time == lasttime ) + { + // just use old value + return bob; + } + + lasttime = pparams->time; + + bobtime += pparams->frametime; + cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; + cycle /= cl_bobcycle->value; + + if ( cycle < cl_bobup->value ) + { + cycle = M_PI * cycle / cl_bobup->value; + } + else + { + cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); + } + + // bob is proportional to simulated velocity in the xy plane + // (don't count Z, or jumping messes it up) + VectorCopy( pparams->simvel, vel ); + vel[2] = 0; + + bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; + bob = bob * 0.3 + bob * 0.7 * sin(cycle); + bob = min( bob, 4 ); + bob = max( bob, -7 ); + return bob; + +} + +/* +=============== +V_CalcRoll +Used by view and sv_user +=============== +*/ +float V_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) +{ + float sign; + float side; + float value; + vec3_t forward, right, up; + + AngleVectors ( angles, forward, right, up ); + + side = DotProduct (velocity, right); + sign = side < 0 ? -1 : 1; + side = fabs( side ); + + value = rollangle; + if (side < rollspeed) + { + side = side * value / rollspeed; + } + else + { + side = value; + } + return side * sign; +} + +typedef struct pitchdrift_s +{ + float pitchvel; + int nodrift; + float driftmove; + double laststop; +} pitchdrift_t; + +static pitchdrift_t pd; + +void V_StartPitchDrift( void ) +{ + if ( pd.laststop == gEngfuncs.GetClientTime() ) + { + return; // something else is keeping it from drifting + } + + if ( pd.nodrift || !pd.pitchvel ) + { + pd.pitchvel = v_centerspeed->value; + pd.nodrift = 0; + pd.driftmove = 0; + } +} + +void V_StopPitchDrift ( void ) +{ + pd.laststop = gEngfuncs.GetClientTime(); + pd.nodrift = 1; + pd.pitchvel = 0; +} + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. +=============== +*/ +void V_DriftPitch ( struct ref_params_s *pparams ) +{ + float delta, move; + + if ( gEngfuncs.IsNoClipping() || !pparams->onground || pparams->demoplayback || pparams->spectator ) + { + pd.driftmove = 0; + pd.pitchvel = 0; + return; + } + + // don't count small mouse motion + if ( pd.nodrift) + { + if ( v_centermove->value > 0 && !(in_mlook.state & 1) ) + { + // this is for lazy players. if they stopped, looked around and then continued + // to move the view will be centered automatically if they move more than + // v_centermove units. + + if ( fabs( pparams->cmd->forwardmove ) < kForwardSpeed ) + pd.driftmove = 0; + else + pd.driftmove += pparams->frametime; + + if ( pd.driftmove > v_centermove->value) + { + V_StartPitchDrift (); + } + else + { + return; // player didn't move enough + } + } + + return; // don't drift view + } + + delta = pparams->idealpitch - pparams->cl_viewangles[PITCH]; + + if (!delta) + { + pd.pitchvel = 0; + return; + } + + move = pparams->frametime * pd.pitchvel; + //pd.pitchvel += pparams->frametime * v_centerspeed->value; + + pd.pitchvel *= (1.0f+(pparams->frametime*0.25f)); // get faster by time + + if (delta > 0) + { + if (move > delta) + { + pd.pitchvel = 0; + move = delta; + } + pparams->cl_viewangles[PITCH] += move; + } + else if (delta < 0) + { + if (move > -delta) + { + pd.pitchvel = 0; + move = -delta; + } + pparams->cl_viewangles[PITCH] -= move; + } +} + +/* +============================================================================== + VIEW RENDERING +============================================================================== +*/ + +/* +================== +V_CalcGunAngle +================== +*/ +void V_CalcGunAngle ( struct ref_params_s *pparams ) +{ + cl_entity_t *viewent; + + viewent = gEngfuncs.GetViewModel(); + if ( !viewent ) + return; + + viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; + viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; + viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + + // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. + viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); + viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + + VectorCopy( viewent->angles, viewent->curstate.angles ); + VectorCopy( viewent->angles, viewent->latched.prevangles ); +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle ( struct ref_params_s *pparams ) +{ + pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; + pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll ( struct ref_params_s *pparams ) +{ + float side; + cl_entity_t *viewentity; + + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( !viewentity ) + return; + + side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); + + pparams->viewangles[ROLL] += side; + + if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) + { + // only roll the view if the player is dead and the viewheight[2] is nonzero + // this is so deadcam in multiplayer will work. + pparams->viewangles[ROLL] = 80; // dead view angle + return; + } +} + + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + float old; + + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + VectorCopy ( pparams->simorg, pparams->vieworg ); + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + view->model = NULL; + + // allways idle in intermission + old = v_idlescale; + v_idlescale = 1; + + V_AddIdle ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in HLTV we must go to 'intermission' position by ourself + VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); + VectorCopy( gHUD.m_Spectator.m_cameraAngles, pparams->viewangles ); + } + + v_idlescale = old; + + v_cl_angles = pparams->cl_viewangles; + v_origin = pparams->vieworg; + v_angles = pparams->viewangles; + v_view_ofs = pparams->viewheight; + +} + +#define ORIGIN_BACKUP 64 +#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) + +typedef struct +{ + float Origins[ ORIGIN_BACKUP ][3]; + float OriginTime[ ORIGIN_BACKUP ]; + + float Angles[ ORIGIN_BACKUP ][3]; + float AngleTime[ ORIGIN_BACKUP ]; + + int CurrentOrigin; + int CurrentAngle; +} viewinterp_t; + +/* +================== +V_CalcRefdef + +================== +*/ +void V_CalcNormalRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + int i; + vec3_t angles; + float bob, waterOffset; + static viewinterp_t ViewInterp; + + static float oldz = 0; + static float lasttime; + + vec3_t camAngles, camForward, camRight, camUp; + cl_entity_t *pwater; + + V_DriftPitch ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + } + else + { + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + } + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + // transform the view offset by the model's matrix to get the offset from + // model origin for the view + bob = V_CalcBob ( pparams ); + + // refresh position + VectorCopy ( pparams->simorg, pparams->vieworg ); + pparams->vieworg[2] += ( bob ); + VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); + + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + gEngfuncs.V_CalcShake(); + gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); + + // never let view origin sit exactly on a node line, because a water plane can + // dissapear when viewed with the eye exactly on it. + // FIXME, we send origin at 1/128 now, change this? + // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + + pparams->vieworg[0] += 1.0/32; + pparams->vieworg[1] += 1.0/32; + pparams->vieworg[2] += 1.0/32; + + // Check for problems around water, move the viewer artificially if necessary + // -- this prevents drawing errors in GL due to waves + + waterOffset = 0; + if ( pparams->waterlevel >= 2 ) + { + int i, contents, waterDist, waterEntity; + vec3_t point; + waterDist = cl_waterdist->value; + + if ( pparams->hardware ) + { + waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); + if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) + { + pwater = gEngfuncs.GetEntityByIndex( waterEntity ); + if ( pwater && ( pwater->model != NULL ) ) + { + waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height + } + } + } + else + { + waterEntity = 0; // Don't need this in software + } + + VectorCopy( pparams->vieworg, point ); + + // Eyes are above water, make sure we're above the waves + if ( pparams->waterlevel == 2 ) + { + point[2] -= waterDist; + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents > CONTENTS_WATER ) + break; + point[2] += 1; + } + waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; + } + else + { + // eyes are under water. Make sure we're far enough under + point[2] += waterDist; + + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents <= CONTENTS_WATER ) + break; + point[2] -= 1; + } + waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; + } + } + + pparams->vieworg[2] += waterOffset; + + V_CalcViewRoll ( pparams ); + + V_AddIdle ( pparams ); + + // offsets + VectorCopy( pparams->cl_viewangles, angles ); + + AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + + // don't allow cheats in multiplayer + if ( pparams->maxclients <= 1 ) + { + for ( i=0 ; i<3 ; i++ ) + { + pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; + } + } + + // Treating cam_ofs[2] as the distance + if( CL_IsThirdPerson() ) + { + vec3_t ofs; + + ofs[0] = ofs[1] = ofs[2] = 0.0; + + CL_CameraOffset( (float *)&ofs ); + + VectorCopy( ofs, camAngles ); + camAngles[ ROLL ] = 0; + + AngleVectors( camAngles, camForward, camRight, camUp ); + + for ( i = 0; i < 3; i++ ) + { + pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; + } + } + + // Give gun our viewangles + VectorCopy ( pparams->cl_viewangles, view->angles ); + + // set up gun position + V_CalcGunAngle ( pparams ); + + // Use predicted origin as view origin. + VectorCopy ( pparams->simorg, view->origin ); + view->origin[2] += ( waterOffset ); + VectorAdd( view->origin, pparams->viewheight, view->origin ); + + // Let the viewmodel shake at about 10% of the amplitude + gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); + + for ( i = 0; i < 3; i++ ) + { + view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; + } + view->origin[2] += bob; + + // throw in a little tilt. + view->angles[YAW] -= bob * 0.5; + view->angles[ROLL] -= bob * 1; + view->angles[PITCH] -= bob * 0.3; + + // pushing the view origin down off of the same X/Z plane as the ent's origin will give the + // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem + // with view model distortion, this may be a cause. (SJB). + view->origin[2] -= 1; + + // fudge position around to keep amount of weapon visible + // roughly equal with different FOV + if (pparams->viewsize == 110) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 100) + { + view->origin[2] += 2; + } + else if (pparams->viewsize == 90) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 80) + { + view->origin[2] += 0.5; + } + + // Add in the punchangle, if any + VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); + + // Include client side punch, too + VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + + V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); + + // smooth out stair step ups +#if 1 + if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + { + float steptime; + + steptime = pparams->time - lasttime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 150; + if (oldz > pparams->simorg[2]) + oldz = pparams->simorg[2]; + if (pparams->simorg[2] - oldz > 18) + oldz = pparams->simorg[2]- 18; + pparams->vieworg[2] += oldz - pparams->simorg[2]; + view->origin[2] += oldz - pparams->simorg[2]; + } + else + { + oldz = pparams->simorg[2]; + } +#endif + + { + static float lastorg[3]; + vec3_t delta; + + VectorSubtract( pparams->simorg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->simorg, lastorg ); + } + } + + // Smooth out whole view in multiplayer when on trains, lifts + if ( cl_vsmoothing && cl_vsmoothing->value && + ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) + { + int foundidx; + int i; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorSubtract( neworg, pparams->simorg, delta ); + + VectorAdd( pparams->simorg, delta, pparams->simorg ); + VectorAdd( pparams->vieworg, delta, pparams->vieworg ); + VectorAdd( view->origin, delta, view->origin ); + + } + } + } + } + + // Store off v_angles before munging for third person + v_angles = pparams->viewangles; + v_lastAngles = pparams->viewangles; +// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! + if ( CL_IsThirdPerson() ) + { + VectorCopy( camAngles, pparams->viewangles); + float pitch = camAngles[ 0 ]; + + // Normalize angles + if ( pitch > 180 ) + pitch -= 360.0; + else if ( pitch < -180 ) + pitch += 360; + + // Player pitch is inverted + pitch /= -3.0; + + // Slam local player's pitch value + ent->angles[ 0 ] = pitch; + ent->curstate.angles[ 0 ] = pitch; + ent->prevstate.angles[ 0 ] = pitch; + ent->latched.prevangles[ 0 ] = pitch; + } + + // override all previous settings if the viewent isn't the client + if ( pparams->viewentity > pparams->maxclients ) + { + cl_entity_t *viewentity; + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( viewentity ) + { + VectorCopy( viewentity->origin, pparams->vieworg ); + VectorCopy( viewentity->angles, pparams->viewangles ); + + // Store off overridden viewangles + v_angles = pparams->viewangles; + } + } + + lasttime = pparams->time; + + v_origin = pparams->vieworg; + v_view_ofs = pparams->viewheight; + +} + +/* +================== +V_CalcTopDownRefdef + +================== +*/ +void V_CalcTopDownRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + int i; + vec3_t angles; + //float waterOffset; + static viewinterp_t ViewInterp; + + static float oldz = 0; + static float lasttime; + + vec3_t camAngles, camForward, camRight, camUp; + //cl_entity_t *pwater; + + V_DriftPitch ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + } + else + { + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + } + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + // Override topdown position and angles from physics code + VectorCopy( gTopDownViewOrigin, pparams->vieworg ); + VectorCopy( gTopDownViewOrigin, pparams->simorg ); + + VectorCopy( gTopDownViewAngles, pparams->cl_viewangles ); + VectorCopy( gTopDownViewAngles, pparams->viewangles ); + + gEngfuncs.V_CalcShake(); + gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); + + + V_CalcViewRoll ( pparams ); + + //V_AddIdle ( pparams ); + + // offsets + VectorCopy( pparams->cl_viewangles, angles ); + + AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + + // don't allow cheats in multiplayer + if ( pparams->maxclients <= 1 ) + { + for ( i=0 ; i<3 ; i++ ) + { + pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; + } + } + + // smooth out stair step ups +#if 1 + if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + { + float steptime; + + steptime = pparams->time - lasttime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 150; + if (oldz > pparams->simorg[2]) + oldz = pparams->simorg[2]; + if (pparams->simorg[2] - oldz > 18) + oldz = pparams->simorg[2]- 18; + pparams->vieworg[2] += oldz - pparams->simorg[2]; + view->origin[2] += oldz - pparams->simorg[2]; + } + else + { + oldz = pparams->simorg[2]; + } +#endif + + { + static float lastorg[3]; + vec3_t delta; + + VectorSubtract( pparams->simorg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->simorg, lastorg ); + } + } + + // Smooth out whole view in multiplayer when on trains, lifts + if ( cl_vsmoothing && cl_vsmoothing->value && + ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) + { + int foundidx; + int i; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorSubtract( neworg, pparams->simorg, delta ); + + VectorAdd( pparams->simorg, delta, pparams->simorg ); + VectorAdd( pparams->vieworg, delta, pparams->vieworg ); + VectorAdd( view->origin, delta, view->origin ); + + //VectorCopy( pparams->simorg, gTopDownViewOrigin ); + } + } + } + } + + // Store off v_angles before munging for third person + v_angles = pparams->viewangles; + v_lastAngles = pparams->viewangles; +// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! +// if ( CL_IsThirdPerson() ) +// { +// VectorCopy( camAngles, pparams->viewangles); +// float pitch = camAngles[ 0 ]; +// +// // Normalize angles +// if ( pitch > 180 ) +// pitch -= 360.0; +// else if ( pitch < -180 ) +// pitch += 360; +// +// // Player pitch is inverted +// pitch /= -3.0; +// +// // Slam local player's pitch value +// ent->angles[ 0 ] = pitch; +// ent->curstate.angles[ 0 ] = pitch; +// ent->prevstate.angles[ 0 ] = pitch; +// ent->latched.prevangles[ 0 ] = pitch; +// } + +// // override all previous settings if the viewent isn't the client +// if ( pparams->viewentity > pparams->maxclients ) +// { +// cl_entity_t *viewentity; +// viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); +// if ( viewentity ) +// { +// VectorCopy( viewentity->origin, pparams->vieworg ); +// VectorCopy( viewentity->angles, pparams->viewangles ); +// +// // Store off overridden viewangles +// v_angles = pparams->viewangles; +// } +// } + + lasttime = pparams->time; + + v_origin = pparams->vieworg; + v_view_ofs = pparams->viewheight; + +} +void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) +{ + float absd,frac,d,threshhold; + + NormalizeAngles( startAngle ); + NormalizeAngles( endAngle ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = endAngle[i] - startAngle[i]; + + if ( d > 180.0f ) + { + d -= 360.0f; + } + else if ( d < -180.0f ) + { + d += 360.0f; + } + + absd = fabs(d); + + if ( absd > 0.01f ) + { + frac = degreesPerSec * v_frametime; + + threshhold= degreesPerSec / 4; + + if ( absd < threshhold ) + { + float h = absd / threshhold; + h *= h; + frac*= h; // slow down last degrees + } + + if ( frac > absd ) + { + finalAngle[i] = endAngle[i]; + } + else + { + if ( d>0) + finalAngle[i] = startAngle[i] + frac; + else + finalAngle[i] = startAngle[i] - frac; + } + } + else + { + finalAngle[i] = endAngle[i]; + } + + } + + NormalizeAngles( finalAngle ); +} + +// Get the origin of the Observer based around the target's position and angles +void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) +{ + vec3_t vecEnd; + vec3_t forward; + vec3_t vecStart; + pmtrace_t * trace; + int maxLoops = 8; + + int ignoreent = -1; // first, ignore no entity + + cl_entity_t * ent = NULL; + + // Trace back from the target using the player's view angles + AngleVectors(angles, forward, NULL, NULL); + + VectorScale(forward,-1,forward); + + VectorCopy( origin, vecStart ); + + VectorMA(vecStart, distance , forward, vecEnd); + + while ( maxLoops > 0) + { + trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); + + // WARNING! trace->ent is is the number in physent list not the normal entity number + + if ( trace->ent <= 0) + break; // we hit the world or nothing, stop trace + + ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); + + if ( ent == NULL ) + break; + + // hit non-player solid BSP , stop here + if ( ent->curstate.solid == SOLID_BSP && !ent->player ) + break; + + // if close enought to end pos, stop, otherwise continue trace + if( VectorDistance(trace->endpos, vecEnd ) < 1.0f ) + { + break; + } + else + { + ignoreent = trace->ent; // ignore last hit entity + VectorCopy( trace->endpos, vecStart); + } + + maxLoops--; + } + +/* if ( ent ) + { + gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); + } */ + + VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); + + v_lastDistance = VectorDistance(trace->endpos, origin); // real distance without offset +} + +/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + float distance = 168.0f; + + v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back + + if ( v_resetCamera ) + v_lastDistance = 64.0f; + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + + // get new angle towards second target + if ( ent2 ) + { + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + } + else + { + // if no second target is given, look down to dead player + newAngle[0] = 90.0f; + newAngle[1] = 0.0f; + newAngle[2] = 0; + } + + // and smooth view + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + + VectorCopy(angle, v_lastAngles); +}*/ + +void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + // see is target is a dead player + qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + else if ( deadPlayer ) + distance*=1.5f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + { + if ( deadPlayer ) + newOrigin[2]+= 2; //laying on ground + else + newOrigin[2]+= 17; // head level of living player + + + } + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // we have no second target, choose view direction based on + // show front of primary target + VectorCopy(ent1->angles, newAngle); + + // show dead players from front, normal players back + if ( flags & DRC_FLAG_FACEPLAYER ) + newAngle[1]+= 180.0f; + + + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + // if final scene (bomb), show from real high pos + if ( flags & DRC_FLAG_FINAL ) + newAngle[0] = 22.5f; + + // choose side of object/player + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + // HACK, if player is dead don't clip against his dead body, can't check this + V_GetChaseOrigin( angle, newOrigin, distance, origin ); +} + +float MaxAngleBetweenAngles( float * a1, float * a2 ) +{ + float d, maxd = 0.0f; + + NormalizeAngles( a1 ); + NormalizeAngles( a2 ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = a2[i] - a1[i]; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + d = fabs(d); + + if ( d > maxd ) + maxd=d; + } + + return maxd; +} + +void V_GetDoubleTargetsCam(cl_entity_t * ent1, const cl_entity_t * ent2,float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; float tempVec[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // get new angle towards second target + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + + // set angle diffrent in Dramtaic scenes + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); + + if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) + { + // difference is to small and we are in relax camera mode, keep viewangles + VectorCopy(v_lastAngles, newAngle ); + } + else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) + { + // we catched up with our target, relax again + v_cameraMode = CAM_MODE_RELAX; + } + else + { + // target move too far away, focus camera again + v_cameraMode = CAM_MODE_FOCUS; + } + + // and smooth view, if not a scene cut + if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) + { + VectorCopy( newAngle, angle ); + } + else + { + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 180.0f ); + } + + V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); + + // move position up, if very close at target + if ( v_lastDistance < 64.0f ) + origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); + + // calculate angle to second target + VectorSubtract( ent2->origin, origin, tempVec ); + VectorAngles( tempVec, tempVec ); + tempVec[0] = -tempVec[0]; + + /* take middle between two viewangles + InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ + + + +} + +void V_GetDirectedChasePosition(cl_entity_t * ent1, const cl_entity_t * ent2,float * angle, float * origin) +{ + + if ( v_resetCamera ) + { + v_lastDistance = 4096.0f; + // v_cameraMode = CAM_MODE_FOCUS; + } + + if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) + { + // we have no second target or player just died + V_GetSingleTargetCam(ent1, angle, origin); + } + else if ( ent2 ) + { + // keep both target in view + V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); + } + else + { + // second target disappeard somehow (dead) + + // keep last good viewangle + float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + } + + VectorCopy(angle, v_lastAngles); +} + +void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) +{ + cl_entity_t * ent = NULL; + + if ( target ) + { + ent = gEngfuncs.GetEntityByIndex( target ); + }; + + if (!ent) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + } + + + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + if ( g_iUser3 ) + V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), + angles, origin ); + else + V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, + angles, origin ); + } + else + { + if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) + { + VectorCopy ( ent->angles, angles); + angles[0]*=-1; + } + else + VectorCopy ( cl_angles, angles); + + + VectorCopy ( ent->origin, origin); + + origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset + + V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); + } + + v_resetCamera = false; +} + +void V_ResetChaseCam() +{ + v_resetCamera = true; +} + + +void V_GetInEyePos(int target, float * origin, float * angles ) +{ + if ( !target) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + }; + + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( !ent ) + return; + + VectorCopy ( ent->origin, origin ); + VectorCopy ( ent->angles, angles ); + + angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + + if ( ent->curstate.solid == SOLID_NOT ) + { + angles[ROLL] = 80; // dead view angle + origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT + } + else if (ent->curstate.usehull == 1 ) + origin[2]+= 12; // VEC_DUCK_VIEW; + else + // exacty eye position can't be caluculated since it depends on + // client values like cl_bobcycle, this offset matches the default values + origin[2]+= 28; // DEFAULT_VIEWHEIGHT +} + +void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) +{ + vec3_t forward; + vec3_t zScaledTarget; + + VectorCopy(cl_angles, angles); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + + zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; + zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; + zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); + + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); +} + +void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) +{ + vec3_t forward; + + if ( target ) + { + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + // this is done to get the angles made by director mode + V_GetChasePos(target, cl_angles, origin, angles); + VectorCopy(ent->origin, origin); + + // keep fix chase angle horizontal + angles[0] = 45.0f; + } + else + { + VectorCopy(cl_angles, angles); + VectorCopy(ent->origin, origin); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + } + else + { + // keep out roaming position, but modify angles + VectorCopy(cl_angles, angles); + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + + origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); + angles[2] = 0.0f; // don't roll angle (if chased player is dead) + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(origin, -1536, forward, origin); +} + +void V_GetMiniMapOriginAndAngle(float * cl_angles, float * origin, float * angles) +{ + // Center map on local player + VectorCopy(gEngfuncs.GetLocalPlayer()->curstate.origin, origin); + //v_origin.z += 300; + + //// Set view height above parsed map settings + origin[2] = gHUD.m_Spectator.m_OverviewData.origin.z + 100; + + //if(gHUD.m_Spectator.m_OverviewData.layers > 0) + //{ + // v_origin.z = gHUD.m_Spectator.m_OverviewData.layersHeights[0]; + //} + // + //v_origin.z += 300; + + //V_GetMapChasePosition(gEngfuncs.GetLocalPlayer()->index, v_cl_angles, v_origin, v_angles ); + + // Set view like top down + cl_angles[0] = angles[0] = 90;//kTopDownYaw; + cl_angles[1] = angles[1] = 90;//kTopDownPitch; + cl_angles[2] = angles[2] = 0;//kTopDownRoll; +} + +int V_FindViewModelByWeaponModel(int weaponindex, int inUser3, int inUser4) +{ + int theViewModelIndex = 0; + + static char * modelmap[][2] = { + { kKNPModel, kKNVModel }, + { kHGPModel, kHGVModel }, + { kMGPModel, kMGVModel }, + { kSGPModel, kSGVModel }, + { kHMGPModel, kHMGVModel }, + { kGGPModel, kGGVModel }, + { kTripminePModel, kTripmineVModel }, + { kWelderPModel, kWelderVModel }, + { NULL, NULL } + }; + + static char * hvymodelmap[][2] = { + { kKNPModel, kKNHVVModel }, + { kHGPModel, kHGHVVModel }, + { kMGPModel, kMGHVVModel }, + { kSGPModel, kSGHVVModel }, + { kHMGPModel, kHMGHVVModel }, + { kGGPModel, kGGHVVModel }, + { kTripminePModel, kTripmineHVVModel }, + { kWelderPModel, kWelderHVVModel }, + { NULL, NULL } + }; + + struct model_s * weaponModel = NULL; + + // If we're an alien, get view model that way + if((inUser3 == AVH_USER3_ALIEN_PLAYER1) || (inUser3 == AVH_USER3_ALIEN_PLAYER2) || (inUser3 == AVH_USER3_ALIEN_PLAYER3) || (inUser3 == AVH_USER3_ALIEN_PLAYER4) || (inUser3 == AVH_USER3_ALIEN_PLAYER5)) + { + const char* theViewModel = ""; + switch(inUser3) + { + case AVH_USER3_ALIEN_PLAYER1: + theViewModel = kLevel1ViewModel; + break; + case AVH_USER3_ALIEN_PLAYER2: + theViewModel = kLevel2ViewModel; + break; + case AVH_USER3_ALIEN_PLAYER3: + theViewModel = kLevel3ViewModel; + break; + case AVH_USER3_ALIEN_PLAYER4: + theViewModel = kLevel4ViewModel; + break; + case AVH_USER3_ALIEN_PLAYER5: + theViewModel = kLevel5ViewModel; + break; + } + + theViewModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex(theViewModel); + } + // else we're holding a weapon + else + { + // Take user3 and user4 into account for heavy armor + if(inUser3 == AVH_USER3_MARINE_PLAYER) + { + weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); + + if ( weaponModel ) + { + //int len = strlen( weaponModel->name ); + int i = 0; + + if(GetHasUpgrade(inUser4, MASK_UPGRADE_13)) + { + while ( *hvymodelmap[i] != NULL ) + { + const char* theCurrentPWeapon = hvymodelmap[i][0]; + const char* theCurrentVWeapon = hvymodelmap[i][1]; + + if ( !SafeStrcmp( weaponModel->name, theCurrentPWeapon) ) + { + theViewModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( theCurrentVWeapon ); + } + i++; + } + } + else + { + while ( *modelmap[i] != NULL ) + { + const char* theCurrentPWeapon = modelmap[i][0]; + const char* theCurrentVWeapon = modelmap[i][1]; + + if ( !SafeStrcmp( weaponModel->name, theCurrentPWeapon) ) + { + theViewModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( theCurrentVWeapon ); + } + i++; + } + } + } + } + } + + return theViewModelIndex; +} + +/* +================== +V_CalcSpectatorRefdef + +================== +*/ + +static int lastWeaponModelIndex = 0; +static int lastViewModelIndex = 0; + +void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) +{ + + vec3_t angles; + static viewinterp_t ViewInterp; + static float bob = 0.0f; + static vec3_t velocity ( 0.0f, 0.0f, 0.0f); + + static float lasttime; + + static float lastang[3]; + static float lastorg[3]; + + vec3_t delta; + pparams->onlyClientDraw = false; + + // refresh position + VectorCopy ( pparams->simorg, v_sim_org ); + + // get old values + VectorCopy ( pparams->cl_viewangles, v_cl_angles ); + VectorCopy ( pparams->viewangles, v_angles ); + VectorCopy ( pparams->vieworg, v_origin ); + VectorCopy ( pparams->viewheight, v_view_ofs); + + v_frametime = pparams->frametime; + + if ( pparams->nextView == 0 ) + { + // first renderer cycle, full screen + + if (!gHUD.m_Spectator.IsInOverviewMode()) + { + + switch ( g_iUser1 ) + { + case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + + case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); + VectorCopy (v_sim_org, v_origin); + break; + + case OBS_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); + break; + + } + + } + else + { + pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + } + + + // Removed by mmcguire. + /* + switch ( g_iUser1 ) + { + case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + + case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); + VectorCopy (v_sim_org, v_origin); + break; + + case OBS_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); + break; + + case OBS_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case OBS_MAP_CHASE : pparams->onlyClientDraw = true; + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + } + */ + + if (g_iUser1) + { + + // Adjust the viewport so that the letterbox spectator mode + // doesn't cut anything off. + + pparams->viewport[1] += YRES(32); + pparams->viewport[3] -= YRES(32 * 2); + + } + + if ( gHUD.m_Spectator.IsInOverviewMode()) + { + pparams->nextView = 1; // force a second renderer view + } + + gHUD.m_Spectator.m_iDrawCycle = 0; + + } + else + { + // second renderer cycle, inset window + + // set inset parameters + pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX) + 1; // change viewport to inset window + pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY) + 1; + pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth) - 2; + pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight) - 2; + pparams->nextView = 0; // on further view + pparams->onlyClientDraw = false; + + if (gHUD.m_Spectator.IsInOverviewMode()) + { + if (g_iUser1 == OBS_IN_EYE) + { + V_GetInEyePos( g_iUser2, v_origin, v_angles ); + } + else if (g_iUser1 == OBS_CHASE_FREE) + { + V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + } + else if (g_iUser1 == OBS_CHASE_LOCKED) + + { + V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + } + else if (g_iUser1 == OBS_ROAMING) + { + VectorCopy (v_cl_angles, v_angles); + VectorCopy (v_sim_org, v_origin); + } + } + + // Removed by mmcguire. + /* + // override some settings in certain modes + switch ( (int)gHUD.m_Spectator.m_pip->value ) + { + case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case INSET_CHASE_LOCKED : V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + + case INSET_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); + break; + + case INSET_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case INSET_MAP_CHASE : pparams->onlyClientDraw = true; + + if ( g_iUser1 == OBS_ROAMING ) + V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); + else + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + + break; + } + */ + + gHUD.m_Spectator.m_iDrawCycle = 1; + } + + + // do the smoothing only once per frame, not in roaming or map mode + if ( (gHUD.m_Spectator.m_iDrawCycle == 0) && (g_iUser1 == OBS_IN_EYE) ) + { + // smooth angles + + VectorSubtract( v_angles, lastang, delta ); + if ( Length( delta ) != 0.0f ) + { + VectorCopy( v_angles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); + ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentAngle++; + VectorCopy( v_angles, lastang ); + } + + if ( cl_vsmoothing && cl_vsmoothing->value ) + { + int foundidx; + int i; + float t; + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentAngle - 1 - i; + if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + double dt; + float da; + vec3_t v1,v2; + + AngleVectors( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], v1, NULL, NULL ); + AngleVectors( ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v2, NULL, NULL ); + da = AngleBetweenVectors( v1, v2 ); + + dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; + + if ( dt > 0.0 && ( da < 22.5f) ) + { + double frac; + + frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + + // interpolate angles + InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v_angles, frac ); + } + } + } + + // smooth origin + + VectorSubtract( v_origin, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( v_origin, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( v_origin, lastorg ); + } + + // don't smooth in roaming (already smoothd), + if ( cl_vsmoothing && cl_vsmoothing->value ) + { + int foundidx; + int i; + float t; + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorCopy( neworg, v_origin ); + } + } + } + } + } + + // Hack in weapon model: + cl_entity_t* ent = gEngfuncs.GetEntityByIndex(g_iUser2); + cl_entity_t* gunModel = gEngfuncs.GetViewModel(); + if ( (g_iUser1 == OBS_IN_EYE) && ent && g_iUser2 ) + { + // get position for weapon model + VectorCopy( v_origin, gunModel->origin); + VectorCopy( v_angles, gunModel->angles); + + // add idle tremble + gunModel->angles[PITCH]*=-1; + + // calculate player velocity + float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; + + if ( timeDiff > 0 ) + { + vec3_t distance; + VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); + VectorScale(distance, 1/timeDiff, distance ); + + velocity[0] = velocity[0]*0.66f + distance[0]*0.33f; + velocity[1] = velocity[1]*0.66f + distance[1]*0.33f; + velocity[2] = velocity[2]*0.66f + distance[2]*0.33f; + + VectorCopy(velocity, pparams->simvel); + pparams->onground = 1; + + bob = V_CalcBob( pparams ); + } + + vec3_t forward; + AngleVectors(v_angles, forward, NULL, NULL ); + + for ( int i = 0; i < 3; i++ ) + { + gunModel->origin[ i ] += bob * 0.4 * forward[ i ]; + } + + // throw in a little tilt. + gunModel->angles[YAW] -= bob * 0.5; + gunModel->angles[ROLL] -= bob * 1; + gunModel->angles[PITCH] -= bob * 0.3; + + VectorCopy( gunModel->angles, gunModel->curstate.angles ); + VectorCopy( gunModel->angles, gunModel->latched.prevangles ); + + lastWeaponModelIndex = ent->curstate.weaponmodel; + int theCurrentViewModel = V_FindViewModelByWeaponModel( lastWeaponModelIndex, ent->curstate.iuser3, ent->curstate.iuser4); + + //if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) + if ( lastViewModelIndex != theCurrentViewModel ) + { + // weapon model changed + lastViewModelIndex = theCurrentViewModel; + if ( lastViewModelIndex ) + { + gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation + } + else + { + // model not found + gunModel->model = NULL; // disable weaopn model + lastWeaponModelIndex = lastViewModelIndex = 0; + } + } + + if ( lastViewModelIndex ) + { + gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); + gunModel->curstate.modelindex = lastViewModelIndex; + gunModel->curstate.frame = 0; + gunModel->curstate.colormap = 0; + gunModel->index = g_iUser2; + } + else + { + gunModel->model = NULL; // disable weaopn model + } + } + else + { + gunModel->model = NULL; // disable weaopn model + lastWeaponModelIndex = lastViewModelIndex = 0; + } + + lasttime = pparams->time; + + // write back new values into pparams + VectorCopy ( v_cl_angles, pparams->cl_viewangles ); + VectorCopy ( v_angles, pparams->viewangles ) + VectorCopy ( v_origin, pparams->vieworg ); + +} + + + +void CL_DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) +{ +// RecClCalcRefdef(pparams); + + // intermission / finale rendering + if ( pparams->intermission ) + { + V_CalcIntermissionRefdef ( pparams ); + } + else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode + { + V_CalcSpectatorRefdef ( pparams ); + } + else if ( !pparams->paused ) + { + if(gHUD.GetInTopDownMode()) + { + V_CalcTopDownRefdef ( pparams ); + } + else + { + V_CalcNormalRefdef ( pparams ); + } + } + +/* +// Example of how to overlay the whole screen with red at 50 % alpha +#define SF_TEST +#if defined SF_TEST + { + screenfade_t sf; + gEngfuncs.pfnGetScreenFade( &sf ); + + sf.fader = 255; + sf.fadeg = 0; + sf.fadeb = 0; + sf.fadealpha = 128; + sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; + + gEngfuncs.pfnSetScreenFade( &sf ); + } +#endif +*/ +} + +/* +============= +V_DropPunchAngle + +============= +*/ +void V_DropPunchAngle ( float frametime, float *ev_punchangle ) +{ + float len; + + len = VectorNormalize ( ev_punchangle ); + len -= (10.0 + len * 0.5) * frametime; + len = max( len, 0.0 ); + VectorScale ( ev_punchangle, len, ev_punchangle ); +} + +/* +============= +V_PunchAxis + +Client side punch effect +============= +*/ +void V_PunchAxis( int axis, float punch ) +{ + ev_punchangle[ axis ] = punch; +} + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + gEngfuncs.pfnAddCommand ("centerview", V_StartPitchDrift ); + + scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); + scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); + scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); + + v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); + v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); + + cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) + cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) + cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); + cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); + cl_hudcam = gEngfuncs.pfnRegisterVariable( "cl_hudcam", "1", 0 ); + cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist", "200", 0 ); +} + + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern float in_fov; +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float x; + + if (fov_x < 1 || fov_x > 179) + fov_x = 90; // error, set to 90 + + x = width/tan(fov_x/360*M_PI); + + a = atan (height/x); + + a = a*360/M_PI; + + return a; +} + +int hitent = -1; +extern playermove_t *pmove; +void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert) +{ + float linestep = 2.0f; + float curdist; + float len; + vec3_t curpos; + vec3_t diff; + int i; + // Determine distance; + + VectorSubtract(end, start, diff); + + len = VectorNormalize(diff); + + curdist = 0; + while (curdist <= len) + { + for (i = 0; i < 3; i++) + curpos[i] = start[i] + curdist * diff[i]; + + pmove->PM_Particle( curpos, pcolor, life, 0, vert); + curdist += linestep; + } + +} +void V_Move( int mx, int my ) +{ + float fov; + float fx, fy; + float dx, dy; + float c_x, c_y; + float dX, dY; + vec3_t forward, up, right; + vec3_t newangles; + + vec3_t farpoint; + pmtrace_t tr; + + fov = CalcFov( in_fov, (float)ScreenWidth(), (float)ScreenHeight() ); + + c_x = (float)ScreenWidth() / 2.0; + c_y = (float)ScreenHeight() / 2.0; + + dx = (float)mx - c_x; + dy = (float)my - c_y; + + // Proportion we moved in each direction + fx = dx / c_x; + fy = dy / c_y; + + dX = fx * in_fov / 2.0 ; + dY = fy * fov / 2.0; + + newangles = v_angles; + + newangles[ YAW ] -= dX; + newangles[ PITCH ] += dY; + + // Now rotate v_forward around that point + AngleVectors ( newangles, forward, right, up ); + + farpoint = v_origin + 8192 * forward; + + // Trace + tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + + if ( tr.fraction != 1.0 && tr.ent != 0 ) + { + hitent = PM_GetPhysEntInfo( tr.ent ); + PM_ParticleLine( (vec3_t)v_origin, (vec3_t)tr.endpos, 5, 1.0, 0.0 ); + } + else + { + hitent = -1; + } +} + +#endif + + + + +///* +//================== +//V_CalcTopDownRefdef +// +//================== +//*/ +//void V_CalcTopDownRefdef ( struct ref_params_s *pparams ) +//{ +// cl_entity_t *ent, *view; +// int i; +// vec3_t angles; +// static viewinterp_t ViewInterp; +// +// static float oldz = 0; +// static float lasttime; +// +// static float lastang[3]; +// vec3_t angdelta; +// +// vec3_t camAngles, camForward, camRight, camUp; +// //cl_entity_t *pwater; +// +// // don't allow cheats in multiplayer +// if ( pparams->maxclients > 1 ) +// { +// scr_ofsx->value = 0.0; +// scr_ofsy->value = 0.0; +// scr_ofsz->value = 0.0; +// } +// +// +// V_DriftPitch ( pparams ); +// +// // ent is the player model ( visible when out of body ) +// ent = gEngfuncs.GetLocalPlayer(); +// +// // view is the weapon model (only visible from inside body ) +// view = gEngfuncs.GetViewModel(); +// +// // Observer angle capturing and smoothing +// if ( iHasNewViewOrigin ) +// { +// // Get the angles from the physics code +// VectorCopy( gTopDownViewOrigin, pparams->vieworg ); +// VectorCopy( gTopDownViewOrigin, pparams->simorg ); +// } +// +// // Override position to commander position +// pparams->vieworg[2] = gTopDownHeight; +// pparams->simorg[2] = gTopDownHeight; +// +// // Override view height when in top down +// pparams->viewheight[2] = 0.0f; +// +// // refresh position +// VectorCopy ( pparams->simorg, pparams->vieworg ); +// VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); +// +// // Observer angle capturing and smoothing +// if ( iHasNewViewAngles ) +// { +// // Get the angles from the physics code +// VectorCopy( gTopDownViewAngles, pparams->cl_viewangles ); +// } +// +// VectorSubtract( pparams->cl_viewangles, lastang, angdelta ); +// if ( Length( angdelta ) != 0.0 ) +// { +// VectorCopy( pparams->cl_viewangles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); +// ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; +// ViewInterp.CurrentAngle++; +// +// VectorCopy( pparams->cl_viewangles, lastang ); +// } +// +// if ( cl_vsmoothing && cl_vsmoothing->value && ( iIsSpectator & SPEC_SMOOTH_ANGLES ) ) +// { +// int foundidx; +// int i; +// float t; +// +// if ( cl_vsmoothing->value < 0.0 ) +// { +// gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); +// } +// +// t = pparams->time - cl_vsmoothing->value; +// +// for ( i = 1; i < ORIGIN_MASK; i++ ) +// { +// foundidx = ViewInterp.CurrentAngle - 1 - i; +// if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) +// break; +// } +// +// if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) +// { +// // Interpolate +// double dt; +// +// dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; +// if ( dt > 0.0 ) +// { +// double frac; +// +// frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; +// frac = min( 1.0, frac ); +// +// // interpolate angles +// InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], pparams->cl_viewangles, frac ); +// +// VectorCopy( pparams->cl_viewangles, gTopDownViewAngles ); +// } +// } +// } +// +// +// VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); +// +// gEngfuncs.V_CalcShake(); +// gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); +// +//// // never let view origin sit exactly on a node line, because a water plane can +//// // dissapear when viewed with the eye exactly on it. +//// // FIXME, we send origin at 1/128 now, change this? +//// // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis +//// +//// pparams->vieworg[0] += 1.0/32; +//// pparams->vieworg[1] += 1.0/32; +//// pparams->vieworg[2] += 1.0/32; +// +// // Check for problems around water, move the viewer artificially if necessary +// // -- this prevents drawing errors in GL due to waves +// +//// if ( pparams->waterlevel >= 2 ) +//// { +//// int waterDist, waterEntity; +//// vec3_t point; +//// waterDist = cl_waterdist->value; +//// +//// if ( pparams->hardware ) +//// { +//// waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); +//// if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) +//// { +//// pwater = gEngfuncs.GetEntityByIndex( waterEntity ); +//// if ( pwater && ( pwater->model != NULL ) ) +//// { +//// waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height +//// } +//// } +//// } +//// else +//// { +//// waterEntity = 0; // Don't need this in software +//// } +//// +//// VectorCopy( pparams->vieworg, point ); +//// } +// +// V_CalcViewRoll ( pparams ); +// +// //V_AddIdle ( pparams ); +// +// // offsets +// VectorCopy( pparams->cl_viewangles, angles ); +// +// AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); +// +// for ( i=0 ; i<3 ; i++ ) +// { +// pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; +// } +// +// // Treating cam_ofs[2] as the distance +//// if( CL_IsThirdPerson() ) +//// { +//// vec3_t ofs; +//// +//// ofs[0] = ofs[1] = ofs[2] = 0.0; +//// +//// CL_CameraOffset( (float *)&ofs ); +//// +//// VectorCopy( ofs, camAngles ); +//// camAngles[ ROLL ] = 0; +//// +//// AngleVectors( camAngles, camForward, camRight, camUp ); +//// +//// for ( i = 0; i < 3; i++ ) +//// { +//// pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; +//// } +//// } +// +// // Give gun our viewangles +//// VectorCopy ( pparams->cl_viewangles, view->angles ); +// +// // set up gun position +//// V_CalcGunAngle ( pparams ); +// +// // Use predicted origin as view origin. +// VectorCopy ( pparams->simorg, view->origin ); +// VectorAdd( view->origin, pparams->viewheight, view->origin ); +// +// // Let the viewmodel shake at about 10% of the amplitude +//// gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); +// +// // smooth out stair step ups +//#if 1 +// if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) +// { +// float steptime; +// +// steptime = pparams->time - lasttime; +// if (steptime < 0) +// //FIXME I_Error ("steptime < 0"); +// steptime = 0; +// +// oldz += steptime * 150; +// if (oldz > pparams->simorg[2]) +// oldz = pparams->simorg[2]; +// if (pparams->simorg[2] - oldz > 18) +// oldz = pparams->simorg[2]- 18; +// pparams->vieworg[2] += oldz - pparams->simorg[2]; +// view->origin[2] += oldz - pparams->simorg[2]; +// } +// else +// { +// oldz = pparams->simorg[2]; +// } +//#endif +// +// { +// static float lastorg[3]; +// vec3_t delta; +// +// VectorSubtract( pparams->simorg, lastorg, delta ); +// +// if ( Length( delta ) != 0.0 ) +// { +// VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); +// ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; +// ViewInterp.CurrentOrigin++; +// +// VectorCopy( pparams->simorg, lastorg ); +// } +// } +// +// // Smooth out whole view in multiplayer when on trains, lifts +// if ( cl_vsmoothing && cl_vsmoothing->value && +// ( ( iIsSpectator & SPEC_SMOOTH_ORIGIN ) || (pparams->smoothing && ( pparams->maxclients > 1 ) ) ) ) +// { +// int foundidx; +// int i; +// float t; +// +// if ( cl_vsmoothing->value < 0.0 ) +// { +// gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); +// } +// +// t = pparams->time - cl_vsmoothing->value; +// +// for ( i = 1; i < ORIGIN_MASK; i++ ) +// { +// foundidx = ViewInterp.CurrentOrigin - 1 - i; +// if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) +// break; +// } +// +// if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) +// { +// // Interpolate +// vec3_t delta; +// double frac; +// double dt; +// vec3_t neworg; +// +// dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; +// if ( dt > 0.0 ) +// { +// frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; +// frac = min( 1.0, frac ); +// VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); +// VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); +// +// // Dont interpolate large changes +// if ( Length( delta ) < 64 ) +// { +// VectorSubtract( neworg, pparams->simorg, delta ); +// +// VectorAdd( pparams->simorg, delta, pparams->simorg ); +// VectorAdd( pparams->vieworg, delta, pparams->vieworg ); +// VectorAdd( view->origin, delta, view->origin ); +// +// VectorCopy( pparams->simorg, gTopDownViewOrigin ); +// } +// } +// } +// } +// +// // Store off v_angles before munging for third person +// v_angles = pparams->viewangles; +// +// // override all previous settings if the viewent isn't the client +// if ( pparams->viewentity > pparams->maxclients ) +// { +// cl_entity_t *viewentity; +// viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); +// if ( viewentity ) +// { +// VectorCopy( viewentity->origin, pparams->vieworg ); +// VectorCopy( viewentity->angles, pparams->viewangles ); +// +// // Store off overridden viewangles +// v_angles = pparams->viewangles; +// } +// } +// +// lasttime = pparams->time; +// +// v_origin = pparams->vieworg; +//} + diff --git a/main/source/cl_dll/view.h b/main/source/cl_dll/view.h index e0a6a2d5..1afbe38e 100644 --- a/main/source/cl_dll/view.h +++ b/main/source/cl_dll/view.h @@ -5,11 +5,11 @@ // $NoKeywords: $ //============================================================================= -#if !defined ( VIEWH ) -#define VIEWH -#pragma once - -void V_StartPitchDrift( void ); -void V_StopPitchDrift( void ); - +#if !defined ( VIEWH ) +#define VIEWH +#pragma once + +void V_StartPitchDrift( void ); +void V_StopPitchDrift( void ); + #endif // !VIEWH \ No newline at end of file diff --git a/main/source/cl_dll/wrect.h b/main/source/cl_dll/wrect.h index 1346fabf..1764057a 100644 --- a/main/source/cl_dll/wrect.h +++ b/main/source/cl_dll/wrect.h @@ -1,9 +1,9 @@ -#if !defined( WRECTH ) -#define WRECTH - -typedef struct rect_s -{ - int left, right, top, bottom; -} wrect_t; - +#if !defined( WRECTH ) +#define WRECTH + +typedef struct rect_s +{ + int left, right, top, bottom; +} wrect_t; + #endif \ No newline at end of file diff --git a/main/source/common/beamdef.h b/main/source/common/beamdef.h index 48ac07b7..51f72f63 100644 --- a/main/source/common/beamdef.h +++ b/main/source/common/beamdef.h @@ -1,62 +1,62 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined ( BEAMDEFH ) -#define BEAMDEFH -#ifdef _WIN32 -#pragma once -#endif - -#define FBEAM_STARTENTITY 0x00000001 -#define FBEAM_ENDENTITY 0x00000002 -#define FBEAM_FADEIN 0x00000004 -#define FBEAM_FADEOUT 0x00000008 -#define FBEAM_SINENOISE 0x00000010 -#define FBEAM_SOLID 0x00000020 -#define FBEAM_SHADEIN 0x00000040 -#define FBEAM_SHADEOUT 0x00000080 -#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? -#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? -#define FBEAM_ISACTIVE 0x40000000 -#define FBEAM_FOREVER 0x80000000 - -typedef struct beam_s BEAM; -struct beam_s -{ - BEAM *next; - int type; - int flags; - vec3_t source; - vec3_t target; - vec3_t delta; - float t; // 0 .. 1 over lifetime of beam - float freq; - float die; - float width; - float amplitude; - float r, g, b; - float brightness; - float speed; - float frameRate; - float frame; - int segments; - int startEntity; - int endEntity; - int modelIndex; - int frameCount; - struct model_s *pFollowModel; - struct particle_s *particles; -}; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( BEAMDEFH ) +#define BEAMDEFH +#ifdef _WIN32 +#pragma once +#endif + +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? +#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? +#define FBEAM_ISACTIVE 0x40000000 +#define FBEAM_FOREVER 0x80000000 + +typedef struct beam_s BEAM; +struct beam_s +{ + BEAM *next; + int type; + int flags; + vec3_t source; + vec3_t target; + vec3_t delta; + float t; // 0 .. 1 over lifetime of beam + float freq; + float die; + float width; + float amplitude; + float r, g, b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + int startEntity; + int endEntity; + int modelIndex; + int frameCount; + struct model_s *pFollowModel; + struct particle_s *particles; +}; + +#endif diff --git a/main/source/common/bullettypes.h b/main/source/common/bullettypes.h index 1b615690..d7ffde14 100644 --- a/main/source/common/bullettypes.h +++ b/main/source/common/bullettypes.h @@ -1,19 +1,19 @@ -#ifndef BULLET_TYPES_H -#define BULLET_TYPES_H - -// bullet types -typedef enum -{ - BULLET_NONE = 0, - BULLET_PLAYER_9MM, // glock - BULLET_PLAYER_MP5, // mp5 - BULLET_PLAYER_357, // python - BULLET_PLAYER_BUCKSHOT, // shotgun - BULLET_PLAYER_CROWBAR, // crowbar swipe - - BULLET_MONSTER_9MM, - BULLET_MONSTER_MP5, - BULLET_MONSTER_12MM, -} Bullet; - +#ifndef BULLET_TYPES_H +#define BULLET_TYPES_H + +// bullet types +typedef enum +{ + BULLET_NONE = 0, + BULLET_PLAYER_9MM, // glock + BULLET_PLAYER_MP5, // mp5 + BULLET_PLAYER_357, // python + BULLET_PLAYER_BUCKSHOT, // shotgun + BULLET_PLAYER_CROWBAR, // crowbar swipe + + BULLET_MONSTER_9MM, + BULLET_MONSTER_MP5, + BULLET_MONSTER_12MM, +} Bullet; + #endif \ No newline at end of file diff --git a/main/source/common/cl_entity.h b/main/source/common/cl_entity.h index 902c0679..ec99e075 100644 --- a/main/source/common/cl_entity.h +++ b/main/source/common/cl_entity.h @@ -1,115 +1,115 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// cl_entity.h -#if !defined( CL_ENTITYH ) -#define CL_ENTITYH -#ifdef _WIN32 -#pragma once -#endif - -typedef struct efrag_s -{ - struct mleaf_s *leaf; - struct efrag_s *leafnext; - struct cl_entity_s *entity; - struct efrag_s *entnext; -} efrag_t; - -typedef struct -{ - byte mouthopen; // 0 = mouth closed, 255 = mouth agape - byte sndcount; // counter for running average - int sndavg; // running average -} mouth_t; - -typedef struct -{ - float prevanimtime; - float sequencetime; - byte prevseqblending[2]; - vec3_t prevorigin; - vec3_t prevangles; - - int prevsequence; - float prevframe; - - byte prevcontroller[4]; - byte prevblending[2]; -} latchedvars_t; - -typedef struct -{ - // Time stamp for this movement - float animtime; - - vec3_t origin; - vec3_t angles; -} position_history_t; - -typedef struct cl_entity_s cl_entity_t; - -#define HISTORY_MAX 64 // Must be power of 2 -#define HISTORY_MASK ( HISTORY_MAX - 1 ) - - -#if !defined( ENTITY_STATEH ) -#include "entity_state.h" -#endif - -#if !defined( PROGS_H ) -#include "progs.h" -#endif - -struct cl_entity_s -{ - int index; // Index into cl_entities ( should match actual slot, but not necessarily ) - - qboolean player; // True if this entity is a "player" - - entity_state_t baseline; // The original state from which to delta during an uncompressed message - entity_state_t prevstate; // The state information from the penultimate message received from the server - entity_state_t curstate; // The state information from the last message received from server - - int current_position; // Last received history update index - position_history_t ph[ HISTORY_MAX ]; // History of position and angle updates for this player - - mouth_t mouth; // For synchronizing mouth movements. - - latchedvars_t latched; // Variables used by studio model rendering routines - - // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. - // - float lastmove; - - // Actual render position and angles - vec3_t origin; - vec3_t angles; - - // Attachment points - vec3_t attachment[4]; - - // Other entity local information - int trivial_accept; - - struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model - struct efrag_s *efrag; // linked list of efrags - struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split - - float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? - int visframe; // last frame this entity was found in an active leaf - colorVec cvFloorColor; -}; - -#endif // !CL_ENTITYH +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// cl_entity.h +#if !defined( CL_ENTITYH ) +#define CL_ENTITYH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct cl_entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct +{ + byte mouthopen; // 0 = mouth closed, 255 = mouth agape + byte sndcount; // counter for running average + int sndavg; // running average +} mouth_t; + +typedef struct +{ + float prevanimtime; + float sequencetime; + byte prevseqblending[2]; + vec3_t prevorigin; + vec3_t prevangles; + + int prevsequence; + float prevframe; + + byte prevcontroller[4]; + byte prevblending[2]; +} latchedvars_t; + +typedef struct +{ + // Time stamp for this movement + float animtime; + + vec3_t origin; + vec3_t angles; +} position_history_t; + +typedef struct cl_entity_s cl_entity_t; + +#define HISTORY_MAX 64 // Must be power of 2 +#define HISTORY_MASK ( HISTORY_MAX - 1 ) + + +#if !defined( ENTITY_STATEH ) +#include "entity_state.h" +#endif + +#if !defined( PROGS_H ) +#include "progs.h" +#endif + +struct cl_entity_s +{ + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) + + qboolean player; // True if this entity is a "player" + + entity_state_t baseline; // The original state from which to delta during an uncompressed message + entity_state_t prevstate; // The state information from the penultimate message received from the server + entity_state_t curstate; // The state information from the last message received from server + + int current_position; // Last received history update index + position_history_t ph[ HISTORY_MAX ]; // History of position and angle updates for this player + + mouth_t mouth; // For synchronizing mouth movements. + + latchedvars_t latched; // Variables used by studio model rendering routines + + // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // + float lastmove; + + // Actual render position and angles + vec3_t origin; + vec3_t angles; + + // Attachment points + vec3_t attachment[4]; + + // Other entity local information + int trivial_accept; + + struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? + int visframe; // last frame this entity was found in an active leaf + colorVec cvFloorColor; +}; + +#endif // !CL_ENTITYH diff --git a/main/source/common/com_model.h b/main/source/common/com_model.h index 97f37436..1730ce4a 100644 --- a/main/source/common/com_model.h +++ b/main/source/common/com_model.h @@ -1,344 +1,344 @@ -// com_model.h -#if !defined( COM_MODEL_H ) -#define COM_MODEL_H -#if defined( _WIN32 ) -#pragma once -#endif - -#define STUDIO_RENDER 1 -#define STUDIO_EVENTS 2 - -#define MAX_CLIENTS 32 -#define MAX_EDICTS 900 - -#define MAX_MODEL_NAME 64 -#define MAX_MAP_HULLS 4 -#define MIPLEVELS 4 -#define NUM_AMBIENTS 4 // automatic ambient sounds -#define MAXLIGHTMAPS 4 -#define PLANE_ANYZ 5 - -#define ALIAS_Z_CLIP_PLANE 5 - -// flags in finalvert_t.flags -#define ALIAS_LEFT_CLIP 0x0001 -#define ALIAS_TOP_CLIP 0x0002 -#define ALIAS_RIGHT_CLIP 0x0004 -#define ALIAS_BOTTOM_CLIP 0x0008 -#define ALIAS_Z_CLIP 0x0010 -#define ALIAS_ONSEAM 0x0020 -#define ALIAS_XY_CLIP_MASK 0x000F - -#define ZISCALE ((float)0x8000) - -#define CACHE_SIZE 32 // used to align key data structures - -typedef enum -{ - mod_brush, - mod_sprite, - mod_alias, - mod_studio -} modtype_t; - -// must match definition in modelgen.h -#ifndef SYNCTYPE_T -#define SYNCTYPE_T - -typedef enum -{ - ST_SYNC=0, - ST_RAND -} synctype_t; - -#endif - -typedef struct -{ - float mins[3], maxs[3]; - float origin[3]; - int headnode[MAX_MAP_HULLS]; - int visleafs; // not including the solid leaf 0 - int firstface, numfaces; -} dmodel_t; - -// plane_t structure -typedef struct mplane_s -{ - vec3_t normal; // surface normal - float dist; // closest appoach to origin - byte type; // for texture axis selection and fast side tests - byte signbits; // signx + signy<<1 + signz<<1 - byte pad[2]; -} mplane_t; - -typedef struct -{ - vec3_t position; -} mvertex_t; - -typedef struct -{ - unsigned short v[2]; - unsigned int cachededgeoffset; -} medge_t; - -typedef struct texture_s -{ - char name[16]; - unsigned width, height; - int anim_total; // total tenths in sequence ( 0 = no) - int anim_min, anim_max; // time for this frame min <=time< max - struct texture_s *anim_next; // in the animation sequence - struct texture_s *alternate_anims; // bmodels in frame 1 use these - unsigned offsets[MIPLEVELS]; // four mip maps stored - unsigned paloffset; -} texture_t; - -typedef struct -{ - float vecs[2][4]; // [s/t] unit vectors in world space. - // [i][3] is the s/t offset relative to the origin. - // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] - float mipadjust; // ?? mipmap limits for very small surfaces - texture_t *texture; - int flags; // sky or slime, no lightmap or 256 subdivision -} mtexinfo_t; - -typedef struct mnode_s -{ -// common with leaf - int contents; // 0, to differentiate from leafs - int visframe; // node needs to be traversed if current - - short minmaxs[6]; // for bounding box culling - - struct mnode_s *parent; - -// node specific - mplane_t *plane; - struct mnode_s *children[2]; - - unsigned short firstsurface; - unsigned short numsurfaces; -} mnode_t; - -typedef struct msurface_s msurface_t; -typedef struct decal_s decal_t; - -// JAY: Compress this as much as possible -struct decal_s -{ - decal_t *pnext; // linked list for each surface - msurface_t *psurface; // Surface id for persistence / unlinking - short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) - short dy; - short texture; // Decal texture - byte scale; // Pixel scale - byte flags; // Decal flags - - short entityIndex; // Entity this is attached to -}; - -typedef struct mleaf_s -{ -// common with node - int contents; // wil be a negative contents number - int visframe; // node needs to be traversed if current - - short minmaxs[6]; // for bounding box culling - - struct mnode_s *parent; - -// leaf specific - byte *compressed_vis; - struct efrag_s *efrags; - - msurface_t **firstmarksurface; - int nummarksurfaces; - int key; // BSP sequence number for leaf's contents - byte ambient_sound_level[NUM_AMBIENTS]; -} mleaf_t; - -struct msurface_s -{ - int visframe; // should be drawn when node is crossed - - int dlightframe; // last frame the surface was checked by an animated light - int dlightbits; // dynamically generated. Indicates if the surface illumination - // is modified by an animated light. - - mplane_t *plane; // pointer to shared plane - int flags; // see SURF_ #defines - - int firstedge; // look up in model->surfedges[], negative numbers - int numedges; // are backwards edges - -// surface generation data - struct surfcache_s *cachespots[MIPLEVELS]; - - short texturemins[2]; // smallest s/t position on the surface. - short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces - - mtexinfo_t *texinfo; - -// lighting info - byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights - // no one surface can be effected by more than 4 - // animated lights. - color24 *samples; - - decal_t *pdecals; -}; - -typedef struct -{ - int planenum; - short children[2]; // negative numbers are contents -} dclipnode_t; - -typedef struct hull_s -{ - dclipnode_t *clipnodes; - mplane_t *planes; - int firstclipnode; - int lastclipnode; - vec3_t clip_mins; - vec3_t clip_maxs; -} hull_t; - -#if !defined( CACHE_USER ) && !defined( QUAKEDEF_H ) -#define CACHE_USER -typedef struct cache_user_s -{ - void *data; -} cache_user_t; -#endif - -typedef struct model_s -{ - char name[ MAX_MODEL_NAME ]; - qboolean needload; // bmodels and sprites don't cache normally - - modtype_t type; - int numframes; - synctype_t synctype; - - int flags; - -// -// volume occupied by the model -// - vec3_t mins, maxs; - float radius; - -// -// brush model -// - int firstmodelsurface, nummodelsurfaces; - - int numsubmodels; - dmodel_t *submodels; - - int numplanes; - mplane_t *planes; - - int numleafs; // number of visible leafs, not counting 0 - struct mleaf_s *leafs; - - int numvertexes; - mvertex_t *vertexes; - - int numedges; - medge_t *edges; - - int numnodes; - mnode_t *nodes; - - int numtexinfo; - mtexinfo_t *texinfo; - - int numsurfaces; - msurface_t *surfaces; - - int numsurfedges; - int *surfedges; - - int numclipnodes; - dclipnode_t *clipnodes; - - int nummarksurfaces; - msurface_t **marksurfaces; - - hull_t hulls[MAX_MAP_HULLS]; - - int numtextures; - texture_t **textures; - - byte *visdata; - - color24 *lightdata; - - char *entities; - -// -// additional model data -// - cache_user_t cache; // only access through Mod_Extradata - -} model_t; - -typedef vec_t vec4_t[4]; - -typedef struct alight_s -{ - int ambientlight; // clip at 128 - int shadelight; // clip at 192 - ambientlight - vec3_t color; - float *plightvec; -} alight_t; - -typedef struct auxvert_s -{ - float fv[3]; // viewspace x, y -} auxvert_t; - -#include "../engine/custom.h" - -#define MAX_INFO_STRING 256 -#define MAX_SCOREBOARDNAME 32 -typedef struct player_info_s -{ - // User id on server - int userid; - - // User info string - char userinfo[ MAX_INFO_STRING ]; - - // Name - char name[ MAX_SCOREBOARDNAME ]; - - // Spectator or not, unused - int spectator; - - int ping; - int packet_loss; - - // skin information - char model[MAX_QPATH]; - int topcolor; - int bottomcolor; - - // last frame rendered - int renderframe; - - // Gait frame estimation - int gaitsequence; - float gaitframe; - float gaityaw; - vec3_t prevgaitorigin; - - customization_t customdata; -} player_info_t; - -#endif // #define COM_MODEL_H +// com_model.h +#if !defined( COM_MODEL_H ) +#define COM_MODEL_H +#if defined( _WIN32 ) +#pragma once +#endif + +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + +#define MAX_CLIENTS 32 +#define MAX_EDICTS 900 + +#define MAX_MODEL_NAME 64 +#define MAX_MAP_HULLS 4 +#define MIPLEVELS 4 +#define NUM_AMBIENTS 4 // automatic ambient sounds +#define MAXLIGHTMAPS 4 +#define PLANE_ANYZ 5 + +#define ALIAS_Z_CLIP_PLANE 5 + +// flags in finalvert_t.flags +#define ALIAS_LEFT_CLIP 0x0001 +#define ALIAS_TOP_CLIP 0x0002 +#define ALIAS_RIGHT_CLIP 0x0004 +#define ALIAS_BOTTOM_CLIP 0x0008 +#define ALIAS_Z_CLIP 0x0010 +#define ALIAS_ONSEAM 0x0020 +#define ALIAS_XY_CLIP_MASK 0x000F + +#define ZISCALE ((float)0x8000) + +#define CACHE_SIZE 32 // used to align key data structures + +typedef enum +{ + mod_brush, + mod_sprite, + mod_alias, + mod_studio +} modtype_t; + +// must match definition in modelgen.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T + +typedef enum +{ + ST_SYNC=0, + ST_RAND +} synctype_t; + +#endif + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; + +// plane_t structure +typedef struct mplane_s +{ + vec3_t normal; // surface normal + float dist; // closest appoach to origin + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +typedef struct +{ + vec3_t position; +} mvertex_t; + +typedef struct +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +typedef struct texture_s +{ + char name[16]; + unsigned width, height; + int anim_total; // total tenths in sequence ( 0 = no) + int anim_min, anim_max; // time for this frame min <=time< max + struct texture_s *anim_next; // in the animation sequence + struct texture_s *alternate_anims; // bmodels in frame 1 use these + unsigned offsets[MIPLEVELS]; // four mip maps stored + unsigned paloffset; +} texture_t; + +typedef struct +{ + float vecs[2][4]; // [s/t] unit vectors in world space. + // [i][3] is the s/t offset relative to the origin. + // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] + float mipadjust; // ?? mipmap limits for very small surfaces + texture_t *texture; + int flags; // sky or slime, no lightmap or 256 subdivision +} mtexinfo_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + +typedef struct msurface_s msurface_t; +typedef struct decal_s decal_t; + +// JAY: Compress this as much as possible +struct decal_s +{ + decal_t *pnext; // linked list for each surface + msurface_t *psurface; // Surface id for persistence / unlinking + short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) + short dy; + short texture; // Decal texture + byte scale; // Pixel scale + byte flags; // Decal flags + + short entityIndex; // Entity this is attached to +}; + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + byte *compressed_vis; + struct efrag_s *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents + byte ambient_sound_level[NUM_AMBIENTS]; +} mleaf_t; + +struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + int dlightframe; // last frame the surface was checked by an animated light + int dlightbits; // dynamically generated. Indicates if the surface illumination + // is modified by an animated light. + + mplane_t *plane; // pointer to shared plane + int flags; // see SURF_ #defines + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + +// surface generation data + struct surfcache_s *cachespots[MIPLEVELS]; + + short texturemins[2]; // smallest s/t position on the surface. + short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces + + mtexinfo_t *texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights + // no one surface can be effected by more than 4 + // animated lights. + color24 *samples; + + decal_t *pdecals; +}; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +typedef struct hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; + +#if !defined( CACHE_USER ) && !defined( QUAKEDEF_H ) +#define CACHE_USER +typedef struct cache_user_s +{ + void *data; +} cache_user_t; +#endif + +typedef struct model_s +{ + char name[ MAX_MODEL_NAME ]; + qboolean needload; // bmodels and sprites don't cache normally + + modtype_t type; + int numframes; + synctype_t synctype; + + int flags; + +// +// volume occupied by the model +// + vec3_t mins, maxs; + float radius; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + struct mleaf_s *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + dclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + + color24 *lightdata; + + char *entities; + +// +// additional model data +// + cache_user_t cache; // only access through Mod_Extradata + +} model_t; + +typedef vec_t vec4_t[4]; + +typedef struct alight_s +{ + int ambientlight; // clip at 128 + int shadelight; // clip at 192 - ambientlight + vec3_t color; + float *plightvec; +} alight_t; + +typedef struct auxvert_s +{ + float fv[3]; // viewspace x, y +} auxvert_t; + +#include "../engine/custom.h" + +#define MAX_INFO_STRING 256 +#define MAX_SCOREBOARDNAME 32 +typedef struct player_info_s +{ + // User id on server + int userid; + + // User info string + char userinfo[ MAX_INFO_STRING ]; + + // Name + char name[ MAX_SCOREBOARDNAME ]; + + // Spectator or not, unused + int spectator; + + int ping; + int packet_loss; + + // skin information + char model[MAX_QPATH]; + int topcolor; + int bottomcolor; + + // last frame rendered + int renderframe; + + // Gait frame estimation + int gaitsequence; + float gaitframe; + float gaityaw; + vec3_t prevgaitorigin; + + customization_t customdata; +} player_info_t; + +#endif // #define COM_MODEL_H diff --git a/main/source/common/con_nprint.h b/main/source/common/con_nprint.h index 5128d87f..d562ed8a 100644 --- a/main/source/common/con_nprint.h +++ b/main/source/common/con_nprint.h @@ -1,31 +1,31 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( CON_NPRINTH ) -#define CON_NPRINTH -#ifdef _WIN32 -#pragma once -#endif - -typedef struct con_nprint_s -{ - int index; // Row # - float time_to_live; // # of seconds before it dissappears - float color[ 3 ]; // RGB colors ( 0.0 -> 1.0 scale ) -} con_nprint_t; - -void Con_NPrintf( int idx, char *fmt, ... ); -void Con_NXPrintf( struct con_nprint_s *info, char *fmt, ... ); - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( CON_NPRINTH ) +#define CON_NPRINTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it dissappears + float color[ 3 ]; // RGB colors ( 0.0 -> 1.0 scale ) +} con_nprint_t; + +void Con_NPrintf( int idx, char *fmt, ... ); +void Con_NXPrintf( struct con_nprint_s *info, char *fmt, ... ); + +#endif diff --git a/main/source/common/const.h b/main/source/common/const.h index a3a99dfb..c44a3d39 100644 --- a/main/source/common/const.h +++ b/main/source/common/const.h @@ -1,744 +1,744 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef CONST_H -#define CONST_H -// -// Constants shared by the engine and dlls -// This header file included by engine files and DLL files. -// Most came from server.h - -// edict->flags -#define FL_FLY (1<<0) // Changes the SV_Movestep() behavior to not need to be on ground -#define FL_SWIM (1<<1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) -#define FL_CONVEYOR (1<<2) -#define FL_CLIENT (1<<3) -#define FL_INWATER (1<<4) -#define FL_MONSTER (1<<5) -#define FL_GODMODE (1<<6) -#define FL_NOTARGET (1<<7) -#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself -#define FL_ONGROUND (1<<9) // At rest / on the ground -#define FL_PARTIALGROUND (1<<10) // not all corners are valid -#define FL_WATERJUMP (1<<11) // player jumping out of water -#define FL_FROZEN (1<<12) // Player is frozen for 3rd person camera -#define FL_FAKECLIENT (1<<13) // JAC: fake client, simulated server side; don't send network messages to them -#define FL_DUCKING (1<<14) // Player flag -- Player is fully crouched -#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water -#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection - -// UNDONE: Do we need these? -#define FL_IMMUNE_WATER (1<<17) -#define FL_IMMUNE_SLIME (1<<18) -#define FL_IMMUNE_LAVA (1<<19) - -#define FL_PROXY (1<<20) // This is a spectator proxy -#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) -#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum) -#define FL_MONSTERCLIP (1<<23) // Only collide in with monsters who have FL_MONSTERCLIP set -#define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction. -#define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) -#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc. -#define FL_CUSTOMENTITY (1<<29) // This is a custom entity -#define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time -#define FL_DORMANT (1<<31) // Entity is dormant, no updates to client - - -// Goes into globalvars_t.trace_flags -#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box - - -// walkmove modes -#define WALKMOVE_NORMAL 0 // normal walkmove -#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type -#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers - -// edict->movetype values -#define MOVETYPE_NONE 0 // never moves -//#define MOVETYPE_ANGLENOCLIP 1 -//#define MOVETYPE_ANGLECLIP 2 -#define MOVETYPE_WALK 3 // Player only - moving on the ground -#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this -#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff -#define MOVETYPE_TOSS 6 // gravity/collisions -#define MOVETYPE_PUSH 7 // no clip to world, push and crush -#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity -#define MOVETYPE_FLYMISSILE 9 // extra size to monsters -#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces -#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity -#define MOVETYPE_FOLLOW 12 // track movement of aiment -#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision) - -// edict->solid values -// NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves -// SOLID only effects OTHER entities colliding with this one when they move - UGH! -#define SOLID_NOT 0 // no interaction with other objects -#define SOLID_TRIGGER 1 // touch on edge, but not blocking -#define SOLID_BBOX 2 // touch on edge, block -#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground -#define SOLID_BSP 4 // bsp clip, touch on edge, block - -// edict->deadflag values -#define DEAD_NO 0 // alive -#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground -#define DEAD_DEAD 2 // dead. lying still. -#define DEAD_RESPAWNABLE 3 -#define DEAD_DISCARDBODY 4 - -#define DAMAGE_NO 0 -#define DAMAGE_YES 1 -#define DAMAGE_AIM 2 - -// entity effects -#define EF_BRIGHTFIELD 1 // swirling cloud of particles -#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0 -#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin -#define EF_DIMLIGHT 8 // player flashlight -#define EF_INVLIGHT 16 // get lighting from ceiling -#define EF_NOINTERP 32 // don't interpolate the next frame -#define EF_LIGHT 64 // rocket flare glow sprite -#define EF_NODRAW 128 // don't draw entity - -// entity flags -#define EFLAG_SLERP 1 // do studio interpolation of this entity - -// -// temp entity events -// -#define TE_BEAMPOINTS 0 // beam effect between two points -// coord coord coord (start position) -// coord coord coord (end position) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMENTPOINT 1 // beam effect between point and entity -// short (start entity) -// coord coord coord (end position) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_GUNSHOT 2 // particle effect plus ricochet sound -// coord coord coord (position) - -#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps -// coord coord coord (position) -// short (sprite index) -// byte (scale in 0.1's) -// byte (framerate) -// byte (flags) -// -// The Explosion effect has some flags to control performance/aesthetic features: -#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion -#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) -#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights -#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound -#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles - - -#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound -// coord coord coord (position) - -#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps -// coord coord coord (position) -// short (sprite index) -// byte (scale in 0.1's) -// byte (framerate) - -#define TE_TRACER 6 // tracer effect from point to point -// coord, coord, coord (start) -// coord, coord, coord (end) - -#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters -// coord, coord, coord (start) -// coord, coord, coord (end) -// byte (life in 0.1's) -// byte (width in 0.1's) -// byte (amplitude in 0.01's) -// short (sprite model index) - -#define TE_BEAMENTS 8 -// short (start entity) -// short (end entity) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite -// coord coord coord (position) - -#define TE_LAVASPLASH 10 // Quake1 lava splash -// coord coord coord (position) - -#define TE_TELEPORT 11 // Quake1 teleport splash -// coord coord coord (position) - -#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound -// coord coord coord (position) -// byte (starting color) -// byte (num colors) - -#define TE_BSPDECAL 13 // Decal from the .BSP file -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// short (texture index of precached decal texture name) -// short (entity index) -// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) - -#define TE_IMPLOSION 14 // tracers moving toward a point -// coord, coord, coord (position) -// byte (radius) -// byte (count) -// byte (life in 0.1's) - -#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions -// coord, coord, coord (start) -// coord, coord, coord (end) -// short (sprite index) -// byte (count) -// byte (life in 0.1's) -// byte (scale in 0.1's) -// byte (velocity along vector in 10's) -// byte (randomness of velocity in 10's) - -#define TE_BEAM 16 // obsolete - -#define TE_SPRITE 17 // additive sprite, plays 1 cycle -// coord, coord, coord (position) -// short (sprite index) -// byte (scale in 0.1's) -// byte (brightness) - -#define TE_BEAMSPRITE 18 // A beam with a sprite at the end -// coord, coord, coord (start position) -// coord, coord, coord (end position) -// short (beam sprite index) -// short (end sprite index) - -#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime -// coord coord coord (center position) -// coord coord coord (axis and radius) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime -// coord coord coord (center position) -// coord coord coord (axis and radius) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime -// coord coord coord (center position) -// coord coord coord (axis and radius) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving -// short (entity:attachment to follow) -// short (sprite index) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte,byte,byte (color) -// byte (brightness) - -#define TE_GLOWSPRITE 23 -// coord, coord, coord (pos) short (model index) byte (scale / 10) - -#define TE_BEAMRING 24 // connect a beam ring to two entities -// short (start entity) -// short (end entity) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_STREAK_SPLASH 25 // oriented shower of tracers -// coord coord coord (start position) -// coord coord coord (direction vector) -// byte (color) -// short (count) -// short (base speed) -// short (ramdon velocity) - -#define TE_BEAMHOSE 26 // obsolete - -#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect -// coord, coord, coord (pos) -// byte (radius in 10's) -// byte byte byte (color) -// byte (brightness) -// byte (life in 10's) -// byte (decay rate in 10's) - -#define TE_ELIGHT 28 // point entity light, no world effect -// short (entity:attachment to follow) -// coord coord coord (initial position) -// coord (radius) -// byte byte byte (color) -// byte (life in 0.1's) -// coord (decay rate) - -#define TE_TEXTMESSAGE 29 -// short 1.2.13 x (-1 = center) -// short 1.2.13 y (-1 = center) -// byte Effect 0 = fade in/fade out - // 1 is flickery credits - // 2 is write out (training room) - -// 4 bytes r,g,b,a color1 (text color) -// 4 bytes r,g,b,a color2 (effect color) -// ushort 8.8 fadein time -// ushort 8.8 fadeout time -// ushort 8.8 hold time -// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) -// string text message (512 chars max sz string) -#define TE_LINE 30 -// coord, coord, coord startpos -// coord, coord, coord endpos -// short life in 0.1 s -// 3 bytes r, g, b - -#define TE_BOX 31 -// coord, coord, coord boxmins -// coord, coord, coord boxmaxs -// short life in 0.1 s -// 3 bytes r, g, b - -#define TE_KILLBEAM 99 // kill all beams attached to entity -// short (entity) - -#define TE_LARGEFUNNEL 100 -// coord coord coord (funnel position) -// short (sprite index) -// short (flags) - -#define TE_BLOODSTREAM 101 // particle spray -// coord coord coord (start position) -// coord coord coord (spray vector) -// byte (color) -// byte (speed) - -#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds -// coord coord coord (start position) -// coord coord coord (end position) - -#define TE_BLOOD 103 // particle spray -// coord coord coord (start position) -// coord coord coord (spray vector) -// byte (color) -// byte (speed) - -#define TE_DECAL 104 // Decal applied to a brush entity (not the world) -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name) -// short (entity index) - -#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards -// short (entity) -// short (sprite index) -// byte (density) - -#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits -// coord, coord, coord (position) -// coord, coord, coord (velocity) -// angle (initial yaw) -// short (model index) -// byte (bounce sound type) -// byte (life in 0.1's) - -#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set -// coord, coord, coord (origin) -// coord (velocity) -// short (model index) -// short (count) -// byte (life in 0.1's) - -#define TE_BREAKMODEL 108 // box of models or sprites -// coord, coord, coord (position) -// coord, coord, coord (size) -// coord, coord, coord (velocity) -// byte (random velocity in 10's) -// short (sprite or model index) -// byte (count) -// byte (life in 0.1 secs) -// byte (flags) - -#define TE_GUNSHOTDECAL 109 // decal and ricochet sound -// coord, coord, coord (position) -// short (entity index???) -// byte (decal???) - -#define TE_SPRITE_SPRAY 110 // spay of alpha sprites -// coord, coord, coord (position) -// coord, coord, coord (velocity) -// short (sprite index) -// byte (count) -// byte (speed) -// byte (noise) - -#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. -// coord, coord, coord (position) -// byte (scale in 0.1's) - -#define TE_PLAYERDECAL 112 // ??? -// byte (playerindex) -// coord, coord, coord (position) -// short (entity???) -// byte (decal number???) -// [optional] short (model index???) - -#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards -// coord, coord, coord (min start position) -// coord, coord, coord (max start position) -// coord (float height) -// short (model index) -// byte (count) -// coord (speed) - -#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards -// coord, coord, coord (min start position) -// coord, coord, coord (max start position) -// coord (float height) -// short (model index) -// byte (count) -// coord (speed) - -#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) -// coord, coord, coord (position) -// short (sprite1 index) -// short (sprite2 index) -// byte (color) -// byte (scale) - -#define TE_WORLDDECAL 116 // Decal applied to the world brush -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name) - -#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name - 256) - -#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name - 256) -// short (entity index) - -#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) -// coord, coord, coord (position) -// coord, coord, coord (velocity) -// short (modelindex) -// byte (life) -// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). - -#define TE_SPRAY 120 // Throws a shower of sprites or models -// coord, coord, coord (position) -// coord, coord, coord (direction) -// short (modelindex) -// byte (count) -// byte (speed) -// byte (noise) -// byte (rendermode) - -#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) -// byte (playernum) -// short (sprite modelindex) -// byte (count) -// byte (variance) (0 = no variance in size) (10 = 10% variance in size) - -#define TE_PARTICLEBURST 122 // very similar to lavasplash. -// coord (origin) -// short (radius) -// byte (particle color) -// byte (duration * 10) (will be randomized a bit) - -#define TE_FIREFIELD 123 // makes a field of fire. -// coord (origin) -// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) -// short (modelindex) -// byte (count) -// byte (flags) -// byte (duration (in seconds) * 10) (will be randomized a bit) -// -// to keep network traffic low, this message has associated flags that fit into a byte: -#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate -#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) -#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. -#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque -#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. - -#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) -// byte (entity index of player) -// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) -// short (model index) -// short (life * 10 ); - -#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. -// byte (entity index of player) - -#define TE_MULTIGUNSHOT 126 // much more compact shotgun message -// This message is used to make a client approximate a 'spray' of gunfire. -// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is -// a good candidate for MULTIGUNSHOT use. (shotguns) -// -// NOTE: This effect makes the client do traces for each bullet, these client traces ignore -// entities that have studio models.Traces are 4096 long. -// -// coord (origin) -// coord (origin) -// coord (origin) -// coord (direction) -// coord (direction) -// coord (direction) -// coord (x noise * 100) -// coord (y noise * 100) -// byte (count) -// byte (bullethole decal texture index) - -#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. -// coord (origin) -// coord (origin) -// coord (origin) -// coord (velocity) -// coord (velocity) -// coord (velocity) -// byte ( life * 10 ) -// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) -// byte ( length * 10 ) - - - -#define MSG_BROADCAST 0 // unreliable to all -#define MSG_ONE 1 // reliable to one (msg_entity) -#define MSG_ALL 2 // reliable to all -#define MSG_INIT 3 // write to the init string -#define MSG_PVS 4 // Ents in PVS of org -#define MSG_PAS 5 // Ents in PAS of org -#define MSG_PVS_R 6 // Reliable to PVS -#define MSG_PAS_R 7 // Reliable to PAS -#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) -#define MSG_SPEC 9 // Sends to all spectator proxies - -// contents of a spot in the world -#define CONTENTS_EMPTY -1 -#define CONTENTS_SOLID -2 -#define CONTENTS_WATER -3 -#define CONTENTS_SLIME -4 -#define CONTENTS_LAVA -5 -#define CONTENTS_SKY -6 -/* These additional contents constants are defined in bspfile.h -#define CONTENTS_ORIGIN -7 // removed at csg time -#define CONTENTS_CLIP -8 // changed to contents_solid -#define CONTENTS_CURRENT_0 -9 -#define CONTENTS_CURRENT_90 -10 -#define CONTENTS_CURRENT_180 -11 -#define CONTENTS_CURRENT_270 -12 -#define CONTENTS_CURRENT_UP -13 -#define CONTENTS_CURRENT_DOWN -14 - -#define CONTENTS_TRANSLUCENT -15 -*/ -#define CONTENTS_LADDER -16 - -// Used when trying to make bsp optimizations -//#define CONTENTS_PORTAL -17 - -#define CONTENT_FLYFIELD -17 -#define CONTENT_GRAVITY_FLYFIELD -18 -#define CONTENT_FOG -19 - -#define CONTENT_EMPTY -1 -#define CONTENT_SOLID -2 -#define CONTENT_WATER -3 -#define CONTENT_SLIME -4 -#define CONTENT_LAVA -5 -#define CONTENT_SKY -6 - -// channels -#define CHAN_AUTO 0 -#define CHAN_WEAPON 1 -#define CHAN_VOICE 2 -#define CHAN_ITEM 3 -#define CHAN_BODY 4 -#define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area -#define CHAN_STATIC 6 // allocate channel from the static area -#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network -#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). - -// attenuation values -#define ATTN_NONE 0 -#define ATTN_NORM (float)0.8 -#define ATTN_IDLE (float)2 -#define ATTN_STATIC (float)1.25 - -// pitch values -#define PITCH_NORM 100 // non-pitch shifted -#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high -#define PITCH_HIGH 120 - -// volume values -#define VOL_NORM 1.0 - -// plats -#define PLAT_LOW_TRIGGER 1 - -// Trains -#define SF_TRAIN_WAIT_RETRIGGER 1 -#define SF_TRAIN_START_ON 4 // Train is initially moving -#define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains - -// buttons -#ifndef IN_BUTTONS_H -#include "in_buttons.h" -#endif - -// Break Model Defines - -#define BREAK_TYPEMASK 0x4F -#define BREAK_GLASS 0x01 -#define BREAK_METAL 0x02 -#define BREAK_FLESH 0x04 -#define BREAK_WOOD 0x08 - -#define BREAK_SMOKE 0x10 -#define BREAK_TRANS 0x20 -#define BREAK_CONCRETE 0x40 -#define BREAK_2 0x80 - -// Colliding temp entity sounds - -#define BOUNCE_GLASS BREAK_GLASS -#define BOUNCE_METAL BREAK_METAL -#define BOUNCE_FLESH BREAK_FLESH -#define BOUNCE_WOOD BREAK_WOOD -#define BOUNCE_SHRAP 0x10 -#define BOUNCE_SHELL 0x20 -#define BOUNCE_CONCRETE BREAK_CONCRETE -#define BOUNCE_SHOTSHELL 0x80 - -// Temp entity bounce sound types -#define TE_BOUNCE_NULL 0 -#define TE_BOUNCE_SHELL 1 -#define TE_BOUNCE_SHOTSHELL 2 - -#include "renderingconst.h" - -typedef unsigned int func_t; -typedef unsigned int string_t; - -typedef unsigned char byte; -typedef unsigned short word; -#define _DEF_BYTE_ - -#undef true -#undef false - -#ifndef __cplusplus -typedef enum {false, true} qboolean; -#else -typedef int qboolean; -#endif - -typedef struct -{ - byte r, g, b; -} color24; - -typedef struct -{ - unsigned r, g, b, a; -} colorVec; - -#ifdef _WIN32 -#pragma pack(push,2) -#endif - -typedef struct -{ - unsigned short r, g, b, a; -} PackedColorVec; - -#ifdef _WIN32 -#pragma pack(pop) -#endif -typedef struct link_s -{ - struct link_s *prev, *next; -} link_t; - -typedef struct edict_s edict_t; - -typedef struct -{ - vec3_t normal; - float dist; -} plane_t; - -typedef struct -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - qboolean inopen, inwater; - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - plane_t plane; // surface normal at impact - edict_t *ent; // entity the surface is on - int hitgroup; // 0 == generic, non zero is specific body part -} trace_t; - -#endif - +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CONST_H +#define CONST_H +// +// Constants shared by the engine and dlls +// This header file included by engine files and DLL files. +// Most came from server.h + +// edict->flags +#define FL_FLY (1<<0) // Changes the SV_Movestep() behavior to not need to be on ground +#define FL_SWIM (1<<1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) +#define FL_CONVEYOR (1<<2) +#define FL_CLIENT (1<<3) +#define FL_INWATER (1<<4) +#define FL_MONSTER (1<<5) +#define FL_GODMODE (1<<6) +#define FL_NOTARGET (1<<7) +#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself +#define FL_ONGROUND (1<<9) // At rest / on the ground +#define FL_PARTIALGROUND (1<<10) // not all corners are valid +#define FL_WATERJUMP (1<<11) // player jumping out of water +#define FL_FROZEN (1<<12) // Player is frozen for 3rd person camera +#define FL_FAKECLIENT (1<<13) // JAC: fake client, simulated server side; don't send network messages to them +#define FL_DUCKING (1<<14) // Player flag -- Player is fully crouched +#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water +#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection + +// UNDONE: Do we need these? +#define FL_IMMUNE_WATER (1<<17) +#define FL_IMMUNE_SLIME (1<<18) +#define FL_IMMUNE_LAVA (1<<19) + +#define FL_PROXY (1<<20) // This is a spectator proxy +#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) +#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum) +#define FL_MONSTERCLIP (1<<23) // Only collide in with monsters who have FL_MONSTERCLIP set +#define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction. +#define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) +#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc. +#define FL_CUSTOMENTITY (1<<29) // This is a custom entity +#define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time +#define FL_DORMANT (1<<31) // Entity is dormant, no updates to client + + +// Goes into globalvars_t.trace_flags +#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box + + +// walkmove modes +#define WALKMOVE_NORMAL 0 // normal walkmove +#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type +#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers + +// edict->movetype values +#define MOVETYPE_NONE 0 // never moves +//#define MOVETYPE_ANGLENOCLIP 1 +//#define MOVETYPE_ANGLECLIP 2 +#define MOVETYPE_WALK 3 // Player only - moving on the ground +#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this +#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff +#define MOVETYPE_TOSS 6 // gravity/collisions +#define MOVETYPE_PUSH 7 // no clip to world, push and crush +#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity +#define MOVETYPE_FLYMISSILE 9 // extra size to monsters +#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces +#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity +#define MOVETYPE_FOLLOW 12 // track movement of aiment +#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision) + +// edict->solid values +// NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves +// SOLID only effects OTHER entities colliding with this one when they move - UGH! +#define SOLID_NOT 0 // no interaction with other objects +#define SOLID_TRIGGER 1 // touch on edge, but not blocking +#define SOLID_BBOX 2 // touch on edge, block +#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground +#define SOLID_BSP 4 // bsp clip, touch on edge, block + +// edict->deadflag values +#define DEAD_NO 0 // alive +#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground +#define DEAD_DEAD 2 // dead. lying still. +#define DEAD_RESPAWNABLE 3 +#define DEAD_DISCARDBODY 4 + +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 + +// entity effects +#define EF_BRIGHTFIELD 1 // swirling cloud of particles +#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0 +#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin +#define EF_DIMLIGHT 8 // player flashlight +#define EF_INVLIGHT 16 // get lighting from ceiling +#define EF_NOINTERP 32 // don't interpolate the next frame +#define EF_LIGHT 64 // rocket flare glow sprite +#define EF_NODRAW 128 // don't draw entity + +// entity flags +#define EFLAG_SLERP 1 // do studio interpolation of this entity + +// +// temp entity events +// +#define TE_BEAMPOINTS 0 // beam effect between two points +// coord coord coord (start position) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMENTPOINT 1 // beam effect between point and entity +// short (start entity) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_GUNSHOT 2 // particle effect plus ricochet sound +// coord coord coord (position) + +#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) +// byte (flags) +// +// The Explosion effect has some flags to control performance/aesthetic features: +#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion +#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) +#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights +#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound +#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles + + +#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound +// coord coord coord (position) + +#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) + +#define TE_TRACER 6 // tracer effect from point to point +// coord, coord, coord (start) +// coord, coord, coord (end) + +#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters +// coord, coord, coord (start) +// coord, coord, coord (end) +// byte (life in 0.1's) +// byte (width in 0.1's) +// byte (amplitude in 0.01's) +// short (sprite model index) + +#define TE_BEAMENTS 8 +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite +// coord coord coord (position) + +#define TE_LAVASPLASH 10 // Quake1 lava splash +// coord coord coord (position) + +#define TE_TELEPORT 11 // Quake1 teleport splash +// coord coord coord (position) + +#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound +// coord coord coord (position) +// byte (starting color) +// byte (num colors) + +#define TE_BSPDECAL 13 // Decal from the .BSP file +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// short (texture index of precached decal texture name) +// short (entity index) +// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) + +#define TE_IMPLOSION 14 // tracers moving toward a point +// coord, coord, coord (position) +// byte (radius) +// byte (count) +// byte (life in 0.1's) + +#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions +// coord, coord, coord (start) +// coord, coord, coord (end) +// short (sprite index) +// byte (count) +// byte (life in 0.1's) +// byte (scale in 0.1's) +// byte (velocity along vector in 10's) +// byte (randomness of velocity in 10's) + +#define TE_BEAM 16 // obsolete + +#define TE_SPRITE 17 // additive sprite, plays 1 cycle +// coord, coord, coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (brightness) + +#define TE_BEAMSPRITE 18 // A beam with a sprite at the end +// coord, coord, coord (start position) +// coord, coord, coord (end position) +// short (beam sprite index) +// short (end sprite index) + +#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving +// short (entity:attachment to follow) +// short (sprite index) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte,byte,byte (color) +// byte (brightness) + +#define TE_GLOWSPRITE 23 +// coord, coord, coord (pos) short (model index) byte (scale / 10) + +#define TE_BEAMRING 24 // connect a beam ring to two entities +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_STREAK_SPLASH 25 // oriented shower of tracers +// coord coord coord (start position) +// coord coord coord (direction vector) +// byte (color) +// short (count) +// short (base speed) +// short (ramdon velocity) + +#define TE_BEAMHOSE 26 // obsolete + +#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect +// coord, coord, coord (pos) +// byte (radius in 10's) +// byte byte byte (color) +// byte (brightness) +// byte (life in 10's) +// byte (decay rate in 10's) + +#define TE_ELIGHT 28 // point entity light, no world effect +// short (entity:attachment to follow) +// coord coord coord (initial position) +// coord (radius) +// byte byte byte (color) +// byte (life in 0.1's) +// coord (decay rate) + +#define TE_TEXTMESSAGE 29 +// short 1.2.13 x (-1 = center) +// short 1.2.13 y (-1 = center) +// byte Effect 0 = fade in/fade out + // 1 is flickery credits + // 2 is write out (training room) + +// 4 bytes r,g,b,a color1 (text color) +// 4 bytes r,g,b,a color2 (effect color) +// ushort 8.8 fadein time +// ushort 8.8 fadeout time +// ushort 8.8 hold time +// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) +// string text message (512 chars max sz string) +#define TE_LINE 30 +// coord, coord, coord startpos +// coord, coord, coord endpos +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_BOX 31 +// coord, coord, coord boxmins +// coord, coord, coord boxmaxs +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_KILLBEAM 99 // kill all beams attached to entity +// short (entity) + +#define TE_LARGEFUNNEL 100 +// coord coord coord (funnel position) +// short (sprite index) +// short (flags) + +#define TE_BLOODSTREAM 101 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds +// coord coord coord (start position) +// coord coord coord (end position) + +#define TE_BLOOD 103 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_DECAL 104 // Decal applied to a brush entity (not the world) +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) +// short (entity index) + +#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards +// short (entity) +// short (sprite index) +// byte (density) + +#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// angle (initial yaw) +// short (model index) +// byte (bounce sound type) +// byte (life in 0.1's) + +#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set +// coord, coord, coord (origin) +// coord (velocity) +// short (model index) +// short (count) +// byte (life in 0.1's) + +#define TE_BREAKMODEL 108 // box of models or sprites +// coord, coord, coord (position) +// coord, coord, coord (size) +// coord, coord, coord (velocity) +// byte (random velocity in 10's) +// short (sprite or model index) +// byte (count) +// byte (life in 0.1 secs) +// byte (flags) + +#define TE_GUNSHOTDECAL 109 // decal and ricochet sound +// coord, coord, coord (position) +// short (entity index???) +// byte (decal???) + +#define TE_SPRITE_SPRAY 110 // spay of alpha sprites +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (sprite index) +// byte (count) +// byte (speed) +// byte (noise) + +#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. +// coord, coord, coord (position) +// byte (scale in 0.1's) + +#define TE_PLAYERDECAL 112 // ??? +// byte (playerindex) +// coord, coord, coord (position) +// short (entity???) +// byte (decal number???) +// [optional] short (model index???) + +#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) +// coord, coord, coord (position) +// short (sprite1 index) +// short (sprite2 index) +// byte (color) +// byte (scale) + +#define TE_WORLDDECAL 116 // Decal applied to the world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) + +#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) + +#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) +// short (entity index) + +#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (modelindex) +// byte (life) +// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). + +#define TE_SPRAY 120 // Throws a shower of sprites or models +// coord, coord, coord (position) +// coord, coord, coord (direction) +// short (modelindex) +// byte (count) +// byte (speed) +// byte (noise) +// byte (rendermode) + +#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) +// byte (playernum) +// short (sprite modelindex) +// byte (count) +// byte (variance) (0 = no variance in size) (10 = 10% variance in size) + +#define TE_PARTICLEBURST 122 // very similar to lavasplash. +// coord (origin) +// short (radius) +// byte (particle color) +// byte (duration * 10) (will be randomized a bit) + +#define TE_FIREFIELD 123 // makes a field of fire. +// coord (origin) +// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) +// short (modelindex) +// byte (count) +// byte (flags) +// byte (duration (in seconds) * 10) (will be randomized a bit) +// +// to keep network traffic low, this message has associated flags that fit into a byte: +#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate +#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) +#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. +#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque +#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. + +#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) +// byte (entity index of player) +// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) +// short (model index) +// short (life * 10 ); + +#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. +// byte (entity index of player) + +#define TE_MULTIGUNSHOT 126 // much more compact shotgun message +// This message is used to make a client approximate a 'spray' of gunfire. +// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is +// a good candidate for MULTIGUNSHOT use. (shotguns) +// +// NOTE: This effect makes the client do traces for each bullet, these client traces ignore +// entities that have studio models.Traces are 4096 long. +// +// coord (origin) +// coord (origin) +// coord (origin) +// coord (direction) +// coord (direction) +// coord (direction) +// coord (x noise * 100) +// coord (y noise * 100) +// byte (count) +// byte (bullethole decal texture index) + +#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. +// coord (origin) +// coord (origin) +// coord (origin) +// coord (velocity) +// coord (velocity) +// coord (velocity) +// byte ( life * 10 ) +// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) +// byte ( length * 10 ) + + + +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string +#define MSG_PVS 4 // Ents in PVS of org +#define MSG_PAS 5 // Ents in PAS of org +#define MSG_PVS_R 6 // Reliable to PVS +#define MSG_PAS_R 7 // Reliable to PAS +#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) +#define MSG_SPEC 9 // Sends to all spectator proxies + +// contents of a spot in the world +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 +/* These additional contents constants are defined in bspfile.h +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + +#define CONTENTS_TRANSLUCENT -15 +*/ +#define CONTENTS_LADDER -16 + +// Used when trying to make bsp optimizations +//#define CONTENTS_PORTAL -17 + +#define CONTENT_FLYFIELD -17 +#define CONTENT_GRAVITY_FLYFIELD -18 +#define CONTENT_FOG -19 + +#define CONTENT_EMPTY -1 +#define CONTENT_SOLID -2 +#define CONTENT_WATER -3 +#define CONTENT_SLIME -4 +#define CONTENT_LAVA -5 +#define CONTENT_SKY -6 + +// channels +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#define CHAN_BODY 4 +#define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area +#define CHAN_STATIC 6 // allocate channel from the static area +#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network +#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). + +// attenuation values +#define ATTN_NONE 0 +#define ATTN_NORM (float)0.8 +#define ATTN_IDLE (float)2 +#define ATTN_STATIC (float)1.25 + +// pitch values +#define PITCH_NORM 100 // non-pitch shifted +#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high +#define PITCH_HIGH 120 + +// volume values +#define VOL_NORM 1.0 + +// plats +#define PLAT_LOW_TRIGGER 1 + +// Trains +#define SF_TRAIN_WAIT_RETRIGGER 1 +#define SF_TRAIN_START_ON 4 // Train is initially moving +#define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains + +// buttons +#ifndef IN_BUTTONS_H +#include "in_buttons.h" +#endif + +// Break Model Defines + +#define BREAK_TYPEMASK 0x4F +#define BREAK_GLASS 0x01 +#define BREAK_METAL 0x02 +#define BREAK_FLESH 0x04 +#define BREAK_WOOD 0x08 + +#define BREAK_SMOKE 0x10 +#define BREAK_TRANS 0x20 +#define BREAK_CONCRETE 0x40 +#define BREAK_2 0x80 + +// Colliding temp entity sounds + +#define BOUNCE_GLASS BREAK_GLASS +#define BOUNCE_METAL BREAK_METAL +#define BOUNCE_FLESH BREAK_FLESH +#define BOUNCE_WOOD BREAK_WOOD +#define BOUNCE_SHRAP 0x10 +#define BOUNCE_SHELL 0x20 +#define BOUNCE_CONCRETE BREAK_CONCRETE +#define BOUNCE_SHOTSHELL 0x80 + +// Temp entity bounce sound types +#define TE_BOUNCE_NULL 0 +#define TE_BOUNCE_SHELL 1 +#define TE_BOUNCE_SHOTSHELL 2 + +#include "renderingconst.h" + +typedef unsigned int func_t; +typedef unsigned int string_t; + +typedef unsigned char byte; +typedef unsigned short word; +#define _DEF_BYTE_ + +#undef true +#undef false + +#ifndef __cplusplus +typedef enum {false, true} qboolean; +#else +typedef int qboolean; +#endif + +typedef struct +{ + byte r, g, b; +} color24; + +typedef struct +{ + unsigned r, g, b, a; +} colorVec; + +#ifdef _WIN32 +#pragma pack(push,2) +#endif + +typedef struct +{ + unsigned short r, g, b, a; +} PackedColorVec; + +#ifdef _WIN32 +#pragma pack(pop) +#endif +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + +typedef struct edict_s edict_t; + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t *ent; // entity the surface is on + int hitgroup; // 0 == generic, non zero is specific body part +} trace_t; + +#endif + diff --git a/main/source/common/crc.h b/main/source/common/crc.h index f2f69abe..1c17d622 100644 --- a/main/source/common/crc.h +++ b/main/source/common/crc.h @@ -1,52 +1,52 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* crc.h */ -#ifndef CRC_H -#define CRC_H -#ifdef _WIN32 -#pragma once -#endif - -// MD5 Hash -typedef struct -{ - unsigned int buf[4]; - unsigned int bits[2]; - unsigned char in[64]; -} MD5Context_t; - - -typedef unsigned long CRC32_t; -void CRC32_Init(CRC32_t *pulCRC); -CRC32_t CRC32_Final(CRC32_t pulCRC); -void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len); -void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); -int CRC_File(CRC32_t *crcvalue, char *pszFileName); - -unsigned char COM_BlockSequenceCRCByte (unsigned char *base, int length, int sequence); - -void MD5Init(MD5Context_t *context); -void MD5Update(MD5Context_t *context, unsigned char const *buf, - unsigned int len); -void MD5Final(unsigned char digest[16], MD5Context_t *context); -void Transform(unsigned int buf[4], unsigned int const in[16]); - -int MD5_Hash_File(unsigned char digest[16], char *pszFileName, int bUsefopen, int bSeed, unsigned int seed[4]); -char *MD5_Print(unsigned char hash[16]); -int MD5_Hash_CachedFile(unsigned char digest[16], unsigned char *pCache, int nFileSize, int bSeed, unsigned int seed[4]); - -int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* crc.h */ +#ifndef CRC_H +#define CRC_H +#ifdef _WIN32 +#pragma once +#endif + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + + +typedef unsigned long CRC32_t; +void CRC32_Init(CRC32_t *pulCRC); +CRC32_t CRC32_Final(CRC32_t pulCRC); +void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len); +void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); +int CRC_File(CRC32_t *crcvalue, char *pszFileName); + +unsigned char COM_BlockSequenceCRCByte (unsigned char *base, int length, int sequence); + +void MD5Init(MD5Context_t *context); +void MD5Update(MD5Context_t *context, unsigned char const *buf, + unsigned int len); +void MD5Final(unsigned char digest[16], MD5Context_t *context); +void Transform(unsigned int buf[4], unsigned int const in[16]); + +int MD5_Hash_File(unsigned char digest[16], char *pszFileName, int bUsefopen, int bSeed, unsigned int seed[4]); +char *MD5_Print(unsigned char hash[16]); +int MD5_Hash_CachedFile(unsigned char digest[16], unsigned char *pCache, int nFileSize, int bSeed, unsigned int seed[4]); + +int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); + +#endif diff --git a/main/source/common/cvardef.h b/main/source/common/cvardef.h index 2d599a35..2e23406c 100644 --- a/main/source/common/cvardef.h +++ b/main/source/common/cvardef.h @@ -1,36 +1,36 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef CVARDEF_H -#define CVARDEF_H - -#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc -#define FCVAR_USERINFO (1<<1) // changes the client's info string -#define FCVAR_SERVER (1<<2) // notifies players when changed -#define FCVAR_EXTDLL (1<<3) // defined by external DLL -#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll -#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value -#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. -#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). -#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log - -typedef struct cvar_s -{ - char *name; - char *string; - int flags; - float value; - struct cvar_s *next; -} cvar_t; -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CVARDEF_H +#define CVARDEF_H + +#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc +#define FCVAR_USERINFO (1<<1) // changes the client's info string +#define FCVAR_SERVER (1<<2) // notifies players when changed +#define FCVAR_EXTDLL (1<<3) // defined by external DLL +#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log + +typedef struct cvar_s +{ + char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; +#endif diff --git a/main/source/common/damagetypes.h b/main/source/common/damagetypes.h index cceea945..dddc2b73 100644 --- a/main/source/common/damagetypes.h +++ b/main/source/common/damagetypes.h @@ -1,58 +1,58 @@ -#ifndef DAMAGETYPES_H -#define DAMAGETYPES_H - -#define DMG_GENERIC 0 // generic damage was done -#define DMG_CRUSH (1 << 0) // crushed by falling or moving object -#define DMG_BULLET (1 << 1) // shot -#define DMG_SLASH (1 << 2) // cut, clawed, stabbed -#define DMG_BURN (1 << 3) // heat burned -#define DMG_FREEZE (1 << 4) // frozen -#define DMG_FALL (1 << 5) // fell too far -#define DMG_BLAST (1 << 6) // explosive blast damage -#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt -#define DMG_SHOCK (1 << 8) // electric shock -#define DMG_SONIC (1 << 9) // sound pulse shockwave -#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam -#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death -#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. -#define DMG_DROWN (1 << 14) // Drowning - -// NS damage types -// Special notes: babblers count as players -#define NS_DMG_NORMAL DMG_BULLET // Normal damage against all targets -#define NS_DMG_PIERCING DMG_SONIC // Normal against players, half vs. structures -#define NS_DMG_BLAST DMG_BLAST // Normal vs. players, double vs. structures -#define NS_DMG_ORGANIC DMG_FREEZE // Only damages living things (players, living structures) -#define NS_DMG_STRUCTURAL DMG_ENERGYBEAM // Doesn't damage players -#define NS_DMG_LIGHT DMG_SHOCK // Half damage to heavily armored targets -#define NS_DMG_ACID DMG_MORTAR // Double armor damage - -// time-based damage -//mask off TF-specific stuff too -#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage - -#define DMG_DROWN (1 << 14) // Drowning -#define DMG_FIRSTTIMEBASED DMG_DROWN - -#define DMG_PARALYZE (1 << 15) // slows affected creature down -#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad -#define DMG_POISON (1 << 17) // blood poisioning -#define DMG_RADIATION (1 << 18) // radiation exposure -#define DMG_DROWNRECOVER (1 << 19) // drowning recovery -#define DMG_ACID (1 << 20) // toxic chemicals or acid burns -#define DMG_SLOWBURN (1 << 21) // in an oven -#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer -#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) - -//TF ADDITIONS -#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn -#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance -#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. -#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor -#define DMG_AIMED (1 << 28) // Does Hit location damage -#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls - -#define DMG_CALTROP (1<<30) -#define DMG_HALLUC (1<<31) - +#ifndef DAMAGETYPES_H +#define DAMAGETYPES_H + +#define DMG_GENERIC 0 // generic damage was done +#define DMG_CRUSH (1 << 0) // crushed by falling or moving object +#define DMG_BULLET (1 << 1) // shot +#define DMG_SLASH (1 << 2) // cut, clawed, stabbed +#define DMG_BURN (1 << 3) // heat burned +#define DMG_FREEZE (1 << 4) // frozen +#define DMG_FALL (1 << 5) // fell too far +#define DMG_BLAST (1 << 6) // explosive blast damage +#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt +#define DMG_SHOCK (1 << 8) // electric shock +#define DMG_SONIC (1 << 9) // sound pulse shockwave +#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam +#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death +#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. +#define DMG_DROWN (1 << 14) // Drowning + +// NS damage types +// Special notes: babblers count as players +#define NS_DMG_NORMAL DMG_BULLET // Normal damage against all targets +#define NS_DMG_PIERCING DMG_SONIC // Normal against players, half vs. structures +#define NS_DMG_BLAST DMG_BLAST // Normal vs. players, double vs. structures +#define NS_DMG_ORGANIC DMG_FREEZE // Only damages living things (players, living structures) +#define NS_DMG_STRUCTURAL DMG_ENERGYBEAM // Doesn't damage players +#define NS_DMG_LIGHT DMG_SHOCK // Half damage to heavily armored targets +#define NS_DMG_ACID DMG_MORTAR // Double armor damage + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#define DMG_PARALYZE (1 << 15) // slows affected creature down +#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +#define DMG_POISON (1 << 17) // blood poisioning +#define DMG_RADIATION (1 << 18) // radiation exposure +#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1 << 21) // in an oven +#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer +#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + #endif \ No newline at end of file diff --git a/main/source/common/demo_api.h b/main/source/common/demo_api.h index f87d5ee8..15989130 100644 --- a/main/source/common/demo_api.h +++ b/main/source/common/demo_api.h @@ -1,31 +1,31 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined ( DEMO_APIH ) -#define DEMO_APIH -#ifdef _WIN32 -#pragma once -#endif - -typedef struct demo_api_s -{ - int ( *IsRecording ) ( void ); - int ( *IsPlayingback ) ( void ); - int ( *IsTimeDemo ) ( void ); - void ( *WriteBuffer ) ( int size, unsigned char *buffer ); -} demo_api_t; - -extern demo_api_t demoapi; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( DEMO_APIH ) +#define DEMO_APIH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct demo_api_s +{ + int ( *IsRecording ) ( void ); + int ( *IsPlayingback ) ( void ); + int ( *IsTimeDemo ) ( void ); + void ( *WriteBuffer ) ( int size, unsigned char *buffer ); +} demo_api_t; + +extern demo_api_t demoapi; + +#endif diff --git a/main/source/common/director_cmds.h b/main/source/common/director_cmds.h index 850ddab7..fc6afc2c 100644 --- a/main/source/common/director_cmds.h +++ b/main/source/common/director_cmds.h @@ -1,31 +1,31 @@ -// director_cmds.h -// sub commands for svc_director - -#define DRC_ACTIVE 0 // tells client that he's an spectator and will get director command -#define DRC_STATUS 1 // send status infos about proxy -#define DRC_CAMERA 2 // set the actual director camera position -#define DRC_EVENT 3 // informs the dircetor about ann important game event - - -#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) -#define DRC_FLAG_SIDE (1<<4) -#define DRC_FLAG_DRAMATIC (1<<5) - - - -// commands of the director API function CallDirectorProc(...) - -#define DRCAPI_NOP 0 // no operation -#define DRCAPI_ACTIVE 1 // de/acivates director mode in engine -#define DRCAPI_STATUS 2 // request proxy information -#define DRCAPI_SETCAM 3 // set camera n to given position and angle -#define DRCAPI_GETCAM 4 // request camera n position and angle -#define DRCAPI_DIRPLAY 5 // set director time and play with normal speed -#define DRCAPI_DIRFREEZE 6 // freeze directo at this time -#define DRCAPI_SETVIEWMODE 7 // overview or 4 cameras -#define DRCAPI_SETOVERVIEWPARAMS 8 // sets parameter for overview mode -#define DRCAPI_SETFOCUS 9 // set the camera which has the input focus -#define DRCAPI_GETTARGETS 10 // queries engine for player list -#define DRCAPI_SETVIEWPOINTS 11 // gives engine all waypoints - - +// director_cmds.h +// sub commands for svc_director + +#define DRC_ACTIVE 0 // tells client that he's an spectator and will get director command +#define DRC_STATUS 1 // send status infos about proxy +#define DRC_CAMERA 2 // set the actual director camera position +#define DRC_EVENT 3 // informs the dircetor about ann important game event + + +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) +#define DRC_FLAG_DRAMATIC (1<<5) + + + +// commands of the director API function CallDirectorProc(...) + +#define DRCAPI_NOP 0 // no operation +#define DRCAPI_ACTIVE 1 // de/acivates director mode in engine +#define DRCAPI_STATUS 2 // request proxy information +#define DRCAPI_SETCAM 3 // set camera n to given position and angle +#define DRCAPI_GETCAM 4 // request camera n position and angle +#define DRCAPI_DIRPLAY 5 // set director time and play with normal speed +#define DRCAPI_DIRFREEZE 6 // freeze directo at this time +#define DRCAPI_SETVIEWMODE 7 // overview or 4 cameras +#define DRCAPI_SETOVERVIEWPARAMS 8 // sets parameter for overview mode +#define DRCAPI_SETFOCUS 9 // set the camera which has the input focus +#define DRCAPI_GETTARGETS 10 // queries engine for player list +#define DRCAPI_SETVIEWPOINTS 11 // gives engine all waypoints + + diff --git a/main/source/common/dlight.h b/main/source/common/dlight.h index ac74c655..a6ca10b8 100644 --- a/main/source/common/dlight.h +++ b/main/source/common/dlight.h @@ -1,33 +1,33 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined ( DLIGHTH ) -#define DLIGHTH -#ifdef _WIN32 -#pragma once -#endif - -typedef struct dlight_s -{ - vec3_t origin; - float radius; - color24 color; - float die; // stop lighting after this time - float decay; // drop this each second - float minlight; // don't add when contributing less - int key; - qboolean dark; // subtracts light instead of adding -} dlight_t; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( DLIGHTH ) +#define DLIGHTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct dlight_s +{ + vec3_t origin; + float radius; + color24 color; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + qboolean dark; // subtracts light instead of adding +} dlight_t; + +#endif diff --git a/main/source/common/dll_state.h b/main/source/common/dll_state.h index 403f591d..9b07af7e 100644 --- a/main/source/common/dll_state.h +++ b/main/source/common/dll_state.h @@ -1,16 +1,16 @@ -//DLL State Flags - -#define DLL_INACTIVE 0 // no dll -#define DLL_ACTIVE 1 // dll is running -#define DLL_PAUSED 2 // dll is paused -#define DLL_CLOSE 3 // closing down dll -#define DLL_TRANS 4 // Level Transition - -// DLL Pause reasons - -#define DLL_NORMAL 0 // User hit Esc or something. -#define DLL_QUIT 4 // Quit now -#define DLL_RESTART 6 // Switch to launcher for linux, does a quit but returns 1 - -// DLL Substate info ( not relevant ) -#define ENG_NORMAL (1<<0) +//DLL State Flags + +#define DLL_INACTIVE 0 // no dll +#define DLL_ACTIVE 1 // dll is running +#define DLL_PAUSED 2 // dll is paused +#define DLL_CLOSE 3 // closing down dll +#define DLL_TRANS 4 // Level Transition + +// DLL Pause reasons + +#define DLL_NORMAL 0 // User hit Esc or something. +#define DLL_QUIT 4 // Quit now +#define DLL_RESTART 6 // Switch to launcher for linux, does a quit but returns 1 + +// DLL Substate info ( not relevant ) +#define ENG_NORMAL (1<<0) diff --git a/main/source/common/engine_launcher_api.h b/main/source/common/engine_launcher_api.h index fef1a650..513bd493 100644 --- a/main/source/common/engine_launcher_api.h +++ b/main/source/common/engine_launcher_api.h @@ -1,103 +1,103 @@ -// engine/launcher interface -#if !defined( ENGINE_LAUNCHER_APIH ) -#define ENGINE_LAUNCHER_APIH -#ifdef _WIN32 -#pragma once -#endif - -//typedef void ( *xcommand_t ) ( void ); - -#define RENDERTYPE_UNDEFINED 0 -#define RENDERTYPE_SOFTWARE 1 -#define RENDERTYPE_HARDWARE 2 - -#define ENGINE_LAUNCHER_API_VERSION 1 - -typedef struct engine_api_s -{ - int version; - int rendertype; - int size; - - // Functions - int ( *GetEngineState ) ( void ); - void ( *Cbuf_AddText ) ( char *text ); // append cmd at end of buf - void ( *Cbuf_InsertText ) ( char *text ); // insert cmd at start of buf - void ( *Cmd_AddCommand ) ( char *cmd_name, void ( *funcname )( void ) ); - int ( *Cmd_Argc ) ( void ); - char *( *Cmd_Args ) ( void ); - char *( *Cmd_Argv ) ( int arg ); - void ( *Con_Printf ) ( char *, ... ); - void ( *Con_SafePrintf ) ( char *, ... ); - void ( *Cvar_Set ) ( char *var_name, char *value ); - void ( *Cvar_SetValue ) ( char *var_name, float value ); - int ( *Cvar_VariableInt ) ( char *var_name ); - char *( *Cvar_VariableString ) ( char *var_name ); - float ( *Cvar_VariableValue ) ( char *var_name ); - void ( *ForceReloadProfile ) ( void ); - int ( *GetGameInfo ) ( struct GameInfo_s *pGI, char *pszChannel ); - void ( *GameSetBackground ) ( int bBack ); - void ( *GameSetState ) ( int iState ); - void ( *GameSetSubState ) ( int iState ); - int ( *GetPauseState ) ( void ); - int ( *Host_Frame ) ( float time, int iState, int *stateInfo ); - void ( *Host_GetHostInfo ) ( float *fps, int *nActive, int *nSpectators, int *nMaxPlayers, char *pszMap ); - void ( *Host_Shutdown ) ( void ); - int ( *Game_Init ) ( char *lpCmdLine, unsigned char *pMem, int iSize, struct exefuncs_s *pef, void *, int ); - void ( *IN_ActivateMouse ) ( void ); - void ( *IN_ClearStates ) ( void ); - void ( *IN_DeactivateMouse ) ( void ); - void ( *IN_MouseEvent ) ( int mstate ); - void ( *Keyboard_ReturnToGame ) ( void ); - void ( *Key_ClearStates ) ( void ); - void ( *Key_Event ) ( int key, int down ); - int ( *LoadGame ) ( const char *pszSlot ); - void ( *S_BlockSound ) ( void ); - void ( *S_ClearBuffer ) ( void ); - void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); - void *( *S_GetWAVPointer ) ( void ); - void ( *S_UnblockSound ) ( void ); - int ( *SaveGame ) ( const char *pszSlot, const char *pszComment ); - void ( *SetAuth ) ( void *pobj ); - void ( *SetMessagePumpDisableMode ) ( int bMode ); - void ( *SetPauseState ) ( int bPause ); - void ( *SetStartupMode ) ( int bMode ); - void ( *SNDDMA_Shutdown ) ( void ); - void ( *Snd_AcquireBuffer ) ( void ); - void ( *Snd_ReleaseBuffer ) ( void ); - void ( *StoreProfile ) ( void ); - double ( *Sys_FloatTime ) ( void ); - void ( *VID_UpdateWindowVars ) ( void *prc, int x, int y ); - void ( *VID_UpdateVID ) ( struct viddef_s *pvid ); - - // VGUI interfaces - void ( *VGui_CallEngineSurfaceProc ) ( void* hwnd, unsigned int msg, unsigned int wparam, long lparam ); - - // notifications that the launcher is taking/giving focus to the engine - void ( *EngineTakingFocus ) ( void ); - void ( *LauncherTakingFocus ) ( void ); - -#ifdef _WIN32 - // Only filled in by rendertype RENDERTYPE_HARDWARE - void ( *GL_Init ) ( void ); - int ( *GL_SetMode ) ( HWND hwndGame, HDC *pmaindc, HGLRC *pbaseRC, int fD3D, const char *p, const char *pszCmdLine ); - void ( *GL_Shutdown ) ( HWND hwnd, HDC hdc, HGLRC hglrc ); - - void ( *QGL_D3DShared ) ( struct tagD3DGlobals *d3dGShared ); - - int ( WINAPI *glSwapBuffers ) ( HDC dc ); - void ( *DirectorProc ) ( unsigned int cmd, void * params ); -#else - // NOT USED IN LINUX!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - void ( *GL_Init ) ( void ); - void ( *GL_SetMode ) ( void ); - void ( *GL_Shutdown ) ( void ); - void ( *QGL_D3DShared ) ( void ); - void ( *glSwapBuffers ) ( void ); - void ( *DirectorProc ) ( void ); - // LINUX -#endif - -} engine_api_t; - -#endif // ENGINE_LAUNCHER_APIH +// engine/launcher interface +#if !defined( ENGINE_LAUNCHER_APIH ) +#define ENGINE_LAUNCHER_APIH +#ifdef _WIN32 +#pragma once +#endif + +//typedef void ( *xcommand_t ) ( void ); + +#define RENDERTYPE_UNDEFINED 0 +#define RENDERTYPE_SOFTWARE 1 +#define RENDERTYPE_HARDWARE 2 + +#define ENGINE_LAUNCHER_API_VERSION 1 + +typedef struct engine_api_s +{ + int version; + int rendertype; + int size; + + // Functions + int ( *GetEngineState ) ( void ); + void ( *Cbuf_AddText ) ( char *text ); // append cmd at end of buf + void ( *Cbuf_InsertText ) ( char *text ); // insert cmd at start of buf + void ( *Cmd_AddCommand ) ( char *cmd_name, void ( *funcname )( void ) ); + int ( *Cmd_Argc ) ( void ); + char *( *Cmd_Args ) ( void ); + char *( *Cmd_Argv ) ( int arg ); + void ( *Con_Printf ) ( char *, ... ); + void ( *Con_SafePrintf ) ( char *, ... ); + void ( *Cvar_Set ) ( char *var_name, char *value ); + void ( *Cvar_SetValue ) ( char *var_name, float value ); + int ( *Cvar_VariableInt ) ( char *var_name ); + char *( *Cvar_VariableString ) ( char *var_name ); + float ( *Cvar_VariableValue ) ( char *var_name ); + void ( *ForceReloadProfile ) ( void ); + int ( *GetGameInfo ) ( struct GameInfo_s *pGI, char *pszChannel ); + void ( *GameSetBackground ) ( int bBack ); + void ( *GameSetState ) ( int iState ); + void ( *GameSetSubState ) ( int iState ); + int ( *GetPauseState ) ( void ); + int ( *Host_Frame ) ( float time, int iState, int *stateInfo ); + void ( *Host_GetHostInfo ) ( float *fps, int *nActive, int *nSpectators, int *nMaxPlayers, char *pszMap ); + void ( *Host_Shutdown ) ( void ); + int ( *Game_Init ) ( char *lpCmdLine, unsigned char *pMem, int iSize, struct exefuncs_s *pef, void *, int ); + void ( *IN_ActivateMouse ) ( void ); + void ( *IN_ClearStates ) ( void ); + void ( *IN_DeactivateMouse ) ( void ); + void ( *IN_MouseEvent ) ( int mstate ); + void ( *Keyboard_ReturnToGame ) ( void ); + void ( *Key_ClearStates ) ( void ); + void ( *Key_Event ) ( int key, int down ); + int ( *LoadGame ) ( const char *pszSlot ); + void ( *S_BlockSound ) ( void ); + void ( *S_ClearBuffer ) ( void ); + void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); + void *( *S_GetWAVPointer ) ( void ); + void ( *S_UnblockSound ) ( void ); + int ( *SaveGame ) ( const char *pszSlot, const char *pszComment ); + void ( *SetAuth ) ( void *pobj ); + void ( *SetMessagePumpDisableMode ) ( int bMode ); + void ( *SetPauseState ) ( int bPause ); + void ( *SetStartupMode ) ( int bMode ); + void ( *SNDDMA_Shutdown ) ( void ); + void ( *Snd_AcquireBuffer ) ( void ); + void ( *Snd_ReleaseBuffer ) ( void ); + void ( *StoreProfile ) ( void ); + double ( *Sys_FloatTime ) ( void ); + void ( *VID_UpdateWindowVars ) ( void *prc, int x, int y ); + void ( *VID_UpdateVID ) ( struct viddef_s *pvid ); + + // VGUI interfaces + void ( *VGui_CallEngineSurfaceProc ) ( void* hwnd, unsigned int msg, unsigned int wparam, long lparam ); + + // notifications that the launcher is taking/giving focus to the engine + void ( *EngineTakingFocus ) ( void ); + void ( *LauncherTakingFocus ) ( void ); + +#ifdef _WIN32 + // Only filled in by rendertype RENDERTYPE_HARDWARE + void ( *GL_Init ) ( void ); + int ( *GL_SetMode ) ( HWND hwndGame, HDC *pmaindc, HGLRC *pbaseRC, int fD3D, const char *p, const char *pszCmdLine ); + void ( *GL_Shutdown ) ( HWND hwnd, HDC hdc, HGLRC hglrc ); + + void ( *QGL_D3DShared ) ( struct tagD3DGlobals *d3dGShared ); + + int ( WINAPI *glSwapBuffers ) ( HDC dc ); + void ( *DirectorProc ) ( unsigned int cmd, void * params ); +#else + // NOT USED IN LINUX!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + void ( *GL_Init ) ( void ); + void ( *GL_SetMode ) ( void ); + void ( *GL_Shutdown ) ( void ); + void ( *QGL_D3DShared ) ( void ); + void ( *glSwapBuffers ) ( void ); + void ( *DirectorProc ) ( void ); + // LINUX +#endif + +} engine_api_t; + +#endif // ENGINE_LAUNCHER_APIH diff --git a/main/source/common/entity_state.h b/main/source/common/entity_state.h index 33cc33f9..1b173495 100644 --- a/main/source/common/entity_state.h +++ b/main/source/common/entity_state.h @@ -1,194 +1,194 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( ENTITY_STATEH ) -#define ENTITY_STATEH -#ifdef _WIN32 -#pragma once -#endif -#include "const.h" - -// For entityType below -#define ENTITY_NORMAL (1<<0) -#define ENTITY_BEAM (1<<1) - -// Entity state is used for the baseline and for delta compression of a packet of -// entities that is sent to a client. -typedef struct entity_state_s entity_state_t; - -struct entity_state_s -{ -// Fields which are filled in by routines outside of delta compression - int entityType; - // Index into cl_entities array for this entity. - int number; - float msg_time; - - // Message number last time the player/entity state was updated. - int messagenum; - - // Fields which can be transitted and reconstructed over the network stream - vec3_t origin; - vec3_t angles; - - int modelindex; - int sequence; - float frame; - int colormap; - short skin; - short solid; - int effects; - float scale; - - byte eflags; - - // Render information - int rendermode; - int renderamt; - color24 rendercolor; - int renderfx; - - int movetype; - float animtime; - float framerate; - int body; - byte controller[4]; - byte blending[4]; - vec3_t velocity; - - // Send bbox down to client for use during prediction. - vec3_t mins; - vec3_t maxs; - - int aiment; - // If owned by a player, the index of that player ( for projectiles ). - int owner; - - // Friction, for prediction. - float friction; - // Gravity multiplier - float gravity; - -// PLAYER SPECIFIC - int team; - int playerclass; - int health; - qboolean spectator; - int weaponmodel; - int gaitsequence; - // If standing on conveyor, e.g. - vec3_t basevelocity; - // Use the crouched hull, or the regular player hull. - int usehull; - // Latched buttons last time state updated. - int oldbuttons; - // -1 = in air, else pmove entity number - int onground; - int iStepLeft; - // How fast we are falling - float flFallVelocity; - - float fov; - int weaponanim; - - // Parametric movement overrides - vec3_t startpos; - vec3_t endpos; - float impacttime; - float starttime; - - // For mods - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; - vec3_t vuser1; - vec3_t vuser2; - vec3_t vuser3; - vec3_t vuser4; -}; - -#include "../pm_shared/pm_info.h" - -typedef struct clientdata_s -{ - vec3_t origin; - vec3_t velocity; - - int viewmodel; - vec3_t punchangle; - int flags; - int waterlevel; - int watertype; - vec3_t view_ofs; - float health; - - int bInDuck; - - int weapons; // remove? - - int flTimeStepSound; - int flDuckTime; - int flSwimTime; - int waterjumptime; - - float maxspeed; - - float fov; - int weaponanim; - - int m_iId; - int ammo_shells; - int ammo_nails; - int ammo_cells; - int ammo_rockets; - float m_flNextAttack; - - int tfstate; - - int pushmsec; - - int deadflag; - - char physinfo[ MAX_PHYSINFO_STRING ]; - - // For mods - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; - vec3_t vuser1; - vec3_t vuser2; - vec3_t vuser3; - vec3_t vuser4; -} clientdata_t; - -#include "weaponinfo.h" - -typedef struct local_state_s -{ - entity_state_t playerstate; - clientdata_t client; - weapon_data_t weapondata[ 32 ]; -} local_state_t; - -#endif // !ENTITY_STATEH +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( ENTITY_STATEH ) +#define ENTITY_STATEH +#ifdef _WIN32 +#pragma once +#endif +#include "const.h" + +// For entityType below +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) + +// Entity state is used for the baseline and for delta compression of a packet of +// entities that is sent to a client. +typedef struct entity_state_s entity_state_t; + +struct entity_state_s +{ +// Fields which are filled in by routines outside of delta compression + int entityType; + // Index into cl_entities array for this entity. + int number; + float msg_time; + + // Message number last time the player/entity state was updated. + int messagenum; + + // Fields which can be transitted and reconstructed over the network stream + vec3_t origin; + vec3_t angles; + + int modelindex; + int sequence; + float frame; + int colormap; + short skin; + short solid; + int effects; + float scale; + + byte eflags; + + // Render information + int rendermode; + int renderamt; + color24 rendercolor; + int renderfx; + + int movetype; + float animtime; + float framerate; + int body; + byte controller[4]; + byte blending[4]; + vec3_t velocity; + + // Send bbox down to client for use during prediction. + vec3_t mins; + vec3_t maxs; + + int aiment; + // If owned by a player, the index of that player ( for projectiles ). + int owner; + + // Friction, for prediction. + float friction; + // Gravity multiplier + float gravity; + +// PLAYER SPECIFIC + int team; + int playerclass; + int health; + qboolean spectator; + int weaponmodel; + int gaitsequence; + // If standing on conveyor, e.g. + vec3_t basevelocity; + // Use the crouched hull, or the regular player hull. + int usehull; + // Latched buttons last time state updated. + int oldbuttons; + // -1 = in air, else pmove entity number + int onground; + int iStepLeft; + // How fast we are falling + float flFallVelocity; + + float fov; + int weaponanim; + + // Parametric movement overrides + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +}; + +#include "../pm_shared/pm_info.h" + +typedef struct clientdata_s +{ + vec3_t origin; + vec3_t velocity; + + int viewmodel; + vec3_t punchangle; + int flags; + int waterlevel; + int watertype; + vec3_t view_ofs; + float health; + + int bInDuck; + + int weapons; // remove? + + int flTimeStepSound; + int flDuckTime; + int flSwimTime; + int waterjumptime; + + float maxspeed; + + float fov; + int weaponanim; + + int m_iId; + int ammo_shells; + int ammo_nails; + int ammo_cells; + int ammo_rockets; + float m_flNextAttack; + + int tfstate; + + int pushmsec; + + int deadflag; + + char physinfo[ MAX_PHYSINFO_STRING ]; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +} clientdata_t; + +#include "weaponinfo.h" + +typedef struct local_state_s +{ + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[ 32 ]; +} local_state_t; + +#endif // !ENTITY_STATEH diff --git a/main/source/common/entity_types.h b/main/source/common/entity_types.h index 856a61bf..defef279 100644 --- a/main/source/common/entity_types.h +++ b/main/source/common/entity_types.h @@ -1,26 +1,26 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// entity_types.h -#if !defined( ENTITY_TYPESH ) -#define ENTITY_TYPESH - -#define ET_NORMAL 0 -#define ET_PLAYER 1 -#define ET_TEMPENTITY 2 -#define ET_BEAM 3 -// BMODEL or SPRITE that was split across BSP nodes -#define ET_FRAGMENTED 4 - -#endif // !ENTITY_TYPESH +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// entity_types.h +#if !defined( ENTITY_TYPESH ) +#define ENTITY_TYPESH + +#define ET_NORMAL 0 +#define ET_PLAYER 1 +#define ET_TEMPENTITY 2 +#define ET_BEAM 3 +// BMODEL or SPRITE that was split across BSP nodes +#define ET_FRAGMENTED 4 + +#endif // !ENTITY_TYPESH diff --git a/main/source/common/event_api.h b/main/source/common/event_api.h index 466f3b40..76564f8e 100644 --- a/main/source/common/event_api.h +++ b/main/source/common/event_api.h @@ -1,51 +1,51 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined ( EVENT_APIH ) -#define EVENT_APIH -#ifdef _WIN32 -#pragma once -#endif - -#define EVENT_API_VERSION 1 - -typedef struct event_api_s -{ - int version; - void ( *EV_PlaySound ) ( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); - void ( *EV_StopSound ) ( int ent, int channel, const char *sample ); - int ( *EV_FindModelIndex )( const char *pmodel ); - int ( *EV_IsLocal ) ( int playernum ); - int ( *EV_LocalPlayerDucking ) ( void ); - void ( *EV_LocalPlayerViewheight ) ( float * ); - void ( *EV_LocalPlayerBounds ) ( int hull, float *mins, float *maxs ); - int ( *EV_IndexFromTrace) ( struct pmtrace_s *pTrace ); - struct physent_s *( *EV_GetPhysent ) ( int idx ); - void ( *EV_SetUpPlayerPrediction ) ( int dopred, int bIncludeLocalClient ); - void ( *EV_PushPMStates ) ( void ); - void ( *EV_PopPMStates ) ( void ); - void ( *EV_SetSolidPlayers ) (int playernum); - void ( *EV_SetTraceHull ) ( int hull ); - void ( *EV_PlayerTrace ) ( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); - void ( *EV_WeaponAnimation ) ( int sequence, int body ); - unsigned short ( *EV_PrecacheEvent ) ( int type, const char* psz ); - void ( *EV_PlaybackEvent ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); - const char *( *EV_TraceTexture ) ( int ground, float *vstart, float *vend ); - void ( *EV_StopAllSounds ) ( int entnum, int entchannel ); - void ( *EV_KillEvents ) ( int entnum, const char *eventname ); -} event_api_t; - -extern event_api_t eventapi; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( EVENT_APIH ) +#define EVENT_APIH +#ifdef _WIN32 +#pragma once +#endif + +#define EVENT_API_VERSION 1 + +typedef struct event_api_s +{ + int version; + void ( *EV_PlaySound ) ( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + void ( *EV_StopSound ) ( int ent, int channel, const char *sample ); + int ( *EV_FindModelIndex )( const char *pmodel ); + int ( *EV_IsLocal ) ( int playernum ); + int ( *EV_LocalPlayerDucking ) ( void ); + void ( *EV_LocalPlayerViewheight ) ( float * ); + void ( *EV_LocalPlayerBounds ) ( int hull, float *mins, float *maxs ); + int ( *EV_IndexFromTrace) ( struct pmtrace_s *pTrace ); + struct physent_s *( *EV_GetPhysent ) ( int idx ); + void ( *EV_SetUpPlayerPrediction ) ( int dopred, int bIncludeLocalClient ); + void ( *EV_PushPMStates ) ( void ); + void ( *EV_PopPMStates ) ( void ); + void ( *EV_SetSolidPlayers ) (int playernum); + void ( *EV_SetTraceHull ) ( int hull ); + void ( *EV_PlayerTrace ) ( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); + void ( *EV_WeaponAnimation ) ( int sequence, int body ); + unsigned short ( *EV_PrecacheEvent ) ( int type, const char* psz ); + void ( *EV_PlaybackEvent ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + const char *( *EV_TraceTexture ) ( int ground, float *vstart, float *vend ); + void ( *EV_StopAllSounds ) ( int entnum, int entchannel ); + void ( *EV_KillEvents ) ( int entnum, const char *eventname ); +} event_api_t; + +extern event_api_t eventapi; + +#endif diff --git a/main/source/common/event_args.h b/main/source/common/event_args.h index acbe8c34..f1ebda3c 100644 --- a/main/source/common/event_args.h +++ b/main/source/common/event_args.h @@ -1,50 +1,50 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( EVENT_ARGSH ) -#define EVENT_ARGSH -#ifdef _WIN32 -#pragma once -#endif - -// Event was invoked with stated origin -#define FEVENT_ORIGIN ( 1<<0 ) - -// Event was invoked with stated angles -#define FEVENT_ANGLES ( 1<<1 ) - -typedef struct event_args_s -{ - int flags; - - // Transmitted - int entindex; - - float origin[3]; - float angles[3]; - float velocity[3]; - - int ducking; - - float fparam1; - float fparam2; - - int iparam1; - int iparam2; - - int bparam1; - int bparam2; -} event_args_t; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( EVENT_ARGSH ) +#define EVENT_ARGSH +#ifdef _WIN32 +#pragma once +#endif + +// Event was invoked with stated origin +#define FEVENT_ORIGIN ( 1<<0 ) + +// Event was invoked with stated angles +#define FEVENT_ANGLES ( 1<<1 ) + +typedef struct event_args_s +{ + int flags; + + // Transmitted + int entindex; + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; +} event_args_t; + +#endif diff --git a/main/source/common/event_flags.h b/main/source/common/event_flags.h index 9e1aa545..453673c8 100644 --- a/main/source/common/event_flags.h +++ b/main/source/common/event_flags.h @@ -1,47 +1,47 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( EVENT_FLAGSH ) -#define EVENT_FLAGSH -#ifdef _WIN32 -#pragma once -#endif - -// Skip local host for event send. -#define FEV_NOTHOST (1<<0) - -// Send the event reliably. You must specify the origin and angles and use -// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything -// that depends on the event origin/angles. I.e., the origin/angles are not -// taken from the invoking edict for reliable events. -#define FEV_RELIABLE (1<<1) - -// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC -// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). -#define FEV_GLOBAL (1<<2) - -// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate -// -#define FEV_UPDATE (1<<3) - -// Only send to entity specified as the invoker -#define FEV_HOSTONLY (1<<4) - -// Only send if the event was created on the server. -#define FEV_SERVER (1<<5) - -// Only issue event client side ( from shared code ) -#define FEV_CLIENT (1<<6) - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( EVENT_FLAGSH ) +#define EVENT_FLAGSH +#ifdef _WIN32 +#pragma once +#endif + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate +// +#define FEV_UPDATE (1<<3) + +// Only send to entity specified as the invoker +#define FEV_HOSTONLY (1<<4) + +// Only send if the event was created on the server. +#define FEV_SERVER (1<<5) + +// Only issue event client side ( from shared code ) +#define FEV_CLIENT (1<<6) + +#endif diff --git a/main/source/common/exefuncs.h b/main/source/common/exefuncs.h index a82f7dce..c647ac46 100644 --- a/main/source/common/exefuncs.h +++ b/main/source/common/exefuncs.h @@ -1,43 +1,43 @@ -// exefuncs.h -#ifndef EXEFUNCS_H -#define EXEFUNCS_H - -// Engine hands this to DLLs for functionality callbacks -typedef struct exefuncs_s -{ - int fMMX; - int iCPUMhz; - void (*unused1)(void); - void (*unused2)(void); - void (*unused3)(void); - void (*unused4)(void); - void (*VID_ForceLockState)(int lk); - int (*VID_ForceUnlockedAndReturnState)(void); - void (*unused5)(void); - void (*unused6)(void); - void (*unused7)(void); - void (*unused8)(void); - void (*unused9)(void); - void (*unused10)(void); - void (*unused11)(void); - void (*unused12)(void); - void (*unused13)(void); - void (*unused14)(void); - void (*unused15)(void); - void (*ErrorMessage)(int nLevel, const char *pszErrorMessage); - void (*unused16)(void); - void (*Sys_Printf)(char *fmt, ...); - void (*unused17)(void); - void (*unused18)(void); - void (*unused19)(void); - void (*unused20)(void); - void (*unused21)(void); - void (*unused22)(void); - void (*unused23)(void); - void (*unused24)(void); - void (*unused25)(void); - void (*unused26)(void); - void (*unused27)(void); -} exefuncs_t; - -#endif +// exefuncs.h +#ifndef EXEFUNCS_H +#define EXEFUNCS_H + +// Engine hands this to DLLs for functionality callbacks +typedef struct exefuncs_s +{ + int fMMX; + int iCPUMhz; + void (*unused1)(void); + void (*unused2)(void); + void (*unused3)(void); + void (*unused4)(void); + void (*VID_ForceLockState)(int lk); + int (*VID_ForceUnlockedAndReturnState)(void); + void (*unused5)(void); + void (*unused6)(void); + void (*unused7)(void); + void (*unused8)(void); + void (*unused9)(void); + void (*unused10)(void); + void (*unused11)(void); + void (*unused12)(void); + void (*unused13)(void); + void (*unused14)(void); + void (*unused15)(void); + void (*ErrorMessage)(int nLevel, const char *pszErrorMessage); + void (*unused16)(void); + void (*Sys_Printf)(char *fmt, ...); + void (*unused17)(void); + void (*unused18)(void); + void (*unused19)(void); + void (*unused20)(void); + void (*unused21)(void); + void (*unused22)(void); + void (*unused23)(void); + void (*unused24)(void); + void (*unused25)(void); + void (*unused26)(void); + void (*unused27)(void); +} exefuncs_t; + +#endif diff --git a/main/source/common/hldm.h b/main/source/common/hldm.h index ba269950..37e1cdb8 100644 --- a/main/source/common/hldm.h +++ b/main/source/common/hldm.h @@ -1,33 +1,33 @@ -//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= -// -// The copyright to the contents herein is the property of Charles G. Cleveland. -// The contents may be used and/or copied only with the written permission of -// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: hldm.h $ -// $Date: 2002/08/02 21:42:34 $ -// -//------------------------------------------------------------------------------- -// $Log: hldm.h,v $ -// Revision 1.4 2002/08/02 21:42:34 Flayra -// - Allow ability to control how often a ricochet sound plays -// -// Revision 1.3 2002/07/08 16:17:46 Flayra -// - Reworked bullet firing to add random spread (bug #236) -// -//=============================================================================== -#ifndef HLDM_H -#define HLDM_H - -#include "pmtrace.h" - -void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName, int inChanceOfSound = 1); -void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType, int inChanceOfSound = 1); -int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); -void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); -void EV_HLDM_FireBulletsPlayer( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, Vector inSpread, int inRandomSeed); - -#endif +//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= +// +// The copyright to the contents herein is the property of Charles G. Cleveland. +// The contents may be used and/or copied only with the written permission of +// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: hldm.h $ +// $Date: 2002/08/02 21:42:34 $ +// +//------------------------------------------------------------------------------- +// $Log: hldm.h,v $ +// Revision 1.4 2002/08/02 21:42:34 Flayra +// - Allow ability to control how often a ricochet sound plays +// +// Revision 1.3 2002/07/08 16:17:46 Flayra +// - Reworked bullet firing to add random spread (bug #236) +// +//=============================================================================== +#ifndef HLDM_H +#define HLDM_H + +#include "pmtrace.h" + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName, int inChanceOfSound = 1); +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType, int inChanceOfSound = 1); +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); +void EV_HLDM_FireBulletsPlayer( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, Vector inSpread, int inRandomSeed); + +#endif diff --git a/main/source/common/hldm.h~ b/main/source/common/hldm.h~ deleted file mode 100644 index c9e77615..00000000 --- a/main/source/common/hldm.h~ +++ /dev/null @@ -1,33 +0,0 @@ -//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= -// -// The copyright to the contents herein is the property of Charles G. Cleveland. -// The contents may be used and/or copied only with the written permission of -// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: hldm.h $ -// $Date: 2002/08/02 21:42:34 $ -// -//------------------------------------------------------------------------------- -// $Log: hldm.h,v $ -// Revision 1.4 2002/08/02 21:42:34 Flayra -// - Allow ability to control how often a ricochet sound plays -// -// Revision 1.3 2002/07/08 16:17:46 Flayra -// - Reworked bullet firing to add random spread (bug #236) -// -//=============================================================================== -#ifndef HLDM_H -#define HLDM_H - -#include "common/pmtrace.h" - -void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName, int inChanceOfSound = 1); -void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType, int inChanceOfSound = 1); -int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); -void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); -void EV_HLDM_FireBulletsPlayer( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, Vector inSpread, int inRandomSeed); - -#endif diff --git a/main/source/common/hltv.h b/main/source/common/hltv.h index ff00d249..4099b7e4 100644 --- a/main/source/common/hltv.h +++ b/main/source/common/hltv.h @@ -1,57 +1,57 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// hltv.h -// all shared consts between server, clients and proxy - -#ifndef HLTV_H -#define HLTV_H - -#define TYPE_CLIENT 0 // client is a normal HL client (default) -#define TYPE_PROXY 1 // client is another proxy -#define TYPE_COMMENTATOR 3 // client is a commentator -#define TYPE_DEMO 4 // client is a demo file -// sub commands of svc_hltv: -#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands -#define HLTV_STATUS 1 // send status infos about proxy -#define HLTV_LISTEN 2 // tell client to listen to a multicast stream - -// sub commands of svc_director: -#define DRC_CMD_NONE 0 // NULL director command -#define DRC_CMD_START 1 // start director mode -#define DRC_CMD_EVENT 2 // informs about director command -#define DRC_CMD_MODE 3 // switches camera modes -#define DRC_CMD_CAMERA 4 // sets camera registers -#define DRC_CMD_TIMESCALE 5 // sets time scale -#define DRC_CMD_MESSAGE 6 // send HUD centerprint -#define DRC_CMD_SOUND 7 // plays a particular sound -#define DRC_CMD_STATUS 8 // status info about broadcast -#define DRC_CMD_BANNER 9 // banner file name for HLTV gui -#define DRC_CMD_FADE 10 // send screen fade command -#define DRC_CMD_SHAKE 11 // send screen shake command -#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command - -#define DRC_CMD_LAST 12 - - - -// HLTV_EVENT event flags -#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) -#define DRC_FLAG_SIDE (1<<4) // -#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene -#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo -#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) -#define DRC_FLAG_INTRO (1<<8) // is a introduction scene -#define DRC_FLAG_FINAL (1<<9) // is a final scene -#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data - - -#define MAX_DIRECTOR_CMD_PARAMETERS 4 -#define MAX_DIRECTOR_CMD_STRING 128 - - -#endif // HLTV_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// hltv.h +// all shared consts between server, clients and proxy + +#ifndef HLTV_H +#define HLTV_H + +#define TYPE_CLIENT 0 // client is a normal HL client (default) +#define TYPE_PROXY 1 // client is another proxy +#define TYPE_COMMENTATOR 3 // client is a commentator +#define TYPE_DEMO 4 // client is a demo file +// sub commands of svc_hltv: +#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands +#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_LISTEN 2 // tell client to listen to a multicast stream + +// sub commands of svc_director: +#define DRC_CMD_NONE 0 // NULL director command +#define DRC_CMD_START 1 // start director mode +#define DRC_CMD_EVENT 2 // informs about director command +#define DRC_CMD_MODE 3 // switches camera modes +#define DRC_CMD_CAMERA 4 // sets camera registers +#define DRC_CMD_TIMESCALE 5 // sets time scale +#define DRC_CMD_MESSAGE 6 // send HUD centerprint +#define DRC_CMD_SOUND 7 // plays a particular sound +#define DRC_CMD_STATUS 8 // status info about broadcast +#define DRC_CMD_BANNER 9 // banner file name for HLTV gui +#define DRC_CMD_FADE 10 // send screen fade command +#define DRC_CMD_SHAKE 11 // send screen shake command +#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command + +#define DRC_CMD_LAST 12 + + + +// HLTV_EVENT event flags +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene +#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo +#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) +#define DRC_FLAG_INTRO (1<<8) // is a introduction scene +#define DRC_FLAG_FINAL (1<<9) // is a final scene +#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data + + +#define MAX_DIRECTOR_CMD_PARAMETERS 4 +#define MAX_DIRECTOR_CMD_STRING 128 + + +#endif // HLTV_H diff --git a/main/source/common/in_buttons.h b/main/source/common/in_buttons.h index 5a499a8c..acaa919b 100644 --- a/main/source/common/in_buttons.h +++ b/main/source/common/in_buttons.h @@ -1,38 +1,38 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef IN_BUTTONS_H -#define IN_BUTTONS_H -#ifdef _WIN32 -#pragma once -#endif - -#define IN_ATTACK (1 << 0) -#define IN_JUMP (1 << 1) -#define IN_DUCK (1 << 2) -#define IN_FORWARD (1 << 3) -#define IN_BACK (1 << 4) -#define IN_USE (1 << 5) -#define IN_CANCEL (1 << 6) -#define IN_LEFT (1 << 7) -#define IN_RIGHT (1 << 8) -#define IN_MOVELEFT (1 << 9) -#define IN_MOVERIGHT (1 << 10) -#define IN_ATTACK2 (1 << 11) -#define IN_WALK (1 << 12) -#define IN_RELOAD (1 << 13) -#define IN_ALT1 (1 << 14) -#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down - -#endif // IN_BUTTONS_H +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef IN_BUTTONS_H +#define IN_BUTTONS_H +#ifdef _WIN32 +#pragma once +#endif + +#define IN_ATTACK (1 << 0) +#define IN_JUMP (1 << 1) +#define IN_DUCK (1 << 2) +#define IN_FORWARD (1 << 3) +#define IN_BACK (1 << 4) +#define IN_USE (1 << 5) +#define IN_CANCEL (1 << 6) +#define IN_LEFT (1 << 7) +#define IN_RIGHT (1 << 8) +#define IN_MOVELEFT (1 << 9) +#define IN_MOVERIGHT (1 << 10) +#define IN_ATTACK2 (1 << 11) +#define IN_WALK (1 << 12) +#define IN_RELOAD (1 << 13) +#define IN_ALT1 (1 << 14) +#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down + +#endif // IN_BUTTONS_H diff --git a/main/source/common/interface.cpp b/main/source/common/interface.cpp index 43c9abf4..69c53450 100644 --- a/main/source/common/interface.cpp +++ b/main/source/common/interface.cpp @@ -4,147 +4,147 @@ // // $NoKeywords: $ //============================================================================= - -#include -#include -#include "interface.h" - -#ifndef _WIN32 // LINUX -#include -#include // getcwd -#include // sprintf -#endif - - -// ------------------------------------------------------------------------------------ // -// InterfaceReg. -// ------------------------------------------------------------------------------------ // -InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; - - -InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : - m_pName(pName) -{ - m_CreateFn = fn; - m_pNext = s_pInterfaceRegs; - s_pInterfaceRegs = this; -} - - - -// ------------------------------------------------------------------------------------ // -// CreateInterface. -// ------------------------------------------------------------------------------------ // -EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) -{ - InterfaceReg *pCur; - - for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) - { - if(strcmp(pCur->m_pName, pName) == 0) - { - if ( pReturnCode ) - { - *pReturnCode = IFACE_OK; - } - return pCur->m_CreateFn(); - } - } - - if ( pReturnCode ) - { - *pReturnCode = IFACE_FAILED; - } - return NULL; -} - - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN + +#include +#include +#include "interface.h" + +#ifndef _WIN32 // LINUX +#include +#include // getcwd +#include // sprintf +#endif + + +// ------------------------------------------------------------------------------------ // +// InterfaceReg. +// ------------------------------------------------------------------------------------ // +InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; + + +InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : + m_pName(pName) +{ + m_CreateFn = fn; + m_pNext = s_pInterfaceRegs; + s_pInterfaceRegs = this; +} + + + +// ------------------------------------------------------------------------------------ // +// CreateInterface. +// ------------------------------------------------------------------------------------ // +EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if(strcmp(pCur->m_pName, pName) == 0) + { + if ( pReturnCode ) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if ( pReturnCode ) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} + + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN #include "windows.h" -#endif - - -#ifdef _WIN32 -HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) -{ - return (HINTERFACEMODULE)LoadLibrary(pModuleName); -} - -#else // LINUX -HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) -{ - // Linux dlopen() doesn't look in the current directory for libraries. - // We tell it to, so people don't have to 'install' libraries as root. - - char szCwd[1024]; - char szAbsoluteLibFilename[1024]; - - getcwd( szCwd, sizeof( szCwd ) ); - if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) - szCwd[ strlen( szCwd ) - 1 ] = 0; - - sprintf( szAbsoluteLibFilename, "%s/%s", szCwd, pModuleName ); - - return (HINTERFACEMODULE)dlopen( szAbsoluteLibFilename, RTLD_NOW ); -} - -#endif - - -#ifdef _WIN32 -void Sys_FreeModule(HINTERFACEMODULE hModule) -{ - if(!hModule) - return; - - FreeLibrary((HMODULE)hModule); -} - -#else // LINUX -void Sys_FreeModule(HINTERFACEMODULE hModule) -{ - if(!hModule) - return; - - dlclose( (void *)hModule ); -} - -#endif - - -//----------------------------------------------------------------------------- -// Purpose: returns the instance of this module -// Output : interface_instance_t -//----------------------------------------------------------------------------- -CreateInterfaceFn Sys_GetFactoryThis( void ) -{ - return CreateInterface; -} - - -//----------------------------------------------------------------------------- -// Purpose: returns the instance of the named module -// Input : *pModuleName - name of the module -// Output : interface_instance_t - instance of that module -//----------------------------------------------------------------------------- - -#ifdef _WIN32 -CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) -{ - if(!hModule) - return NULL; - - return (CreateInterfaceFn)GetProcAddress((HMODULE)hModule, CREATEINTERFACE_PROCNAME); -} - -#else // LINUX -CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) -{ - if(!hModule) - return NULL; - - return (CreateInterfaceFn)dlsym( (void *)hModule, CREATEINTERFACE_PROCNAME ); -} - -#endif +#endif + + +#ifdef _WIN32 +HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) +{ + return (HINTERFACEMODULE)LoadLibrary(pModuleName); +} + +#else // LINUX +HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) +{ + // Linux dlopen() doesn't look in the current directory for libraries. + // We tell it to, so people don't have to 'install' libraries as root. + + char szCwd[1024]; + char szAbsoluteLibFilename[1024]; + + getcwd( szCwd, sizeof( szCwd ) ); + if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) + szCwd[ strlen( szCwd ) - 1 ] = 0; + + sprintf( szAbsoluteLibFilename, "%s/%s", szCwd, pModuleName ); + + return (HINTERFACEMODULE)dlopen( szAbsoluteLibFilename, RTLD_NOW ); +} + +#endif + + +#ifdef _WIN32 +void Sys_FreeModule(HINTERFACEMODULE hModule) +{ + if(!hModule) + return; + + FreeLibrary((HMODULE)hModule); +} + +#else // LINUX +void Sys_FreeModule(HINTERFACEMODULE hModule) +{ + if(!hModule) + return; + + dlclose( (void *)hModule ); +} + +#endif + + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of this module +// Output : interface_instance_t +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactoryThis( void ) +{ + return CreateInterface; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of the named module +// Input : *pModuleName - name of the module +// Output : interface_instance_t - instance of that module +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) +{ + if(!hModule) + return NULL; + + return (CreateInterfaceFn)GetProcAddress((HMODULE)hModule, CREATEINTERFACE_PROCNAME); +} + +#else // LINUX +CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) +{ + if(!hModule) + return NULL; + + return (CreateInterfaceFn)dlsym( (void *)hModule, CREATEINTERFACE_PROCNAME ); +} + +#endif diff --git a/main/source/common/interface.h b/main/source/common/interface.h index 8099662a..69b44180 100644 --- a/main/source/common/interface.h +++ b/main/source/common/interface.h @@ -1,123 +1,123 @@ - -// This header defines the interface convention used in the valve engine. -// To make an interface and expose it: -// 1. Derive from IBaseInterface. -// 2. The interface must be ALL pure virtuals, and have no data members. -// 3. Define a name for it. -// 4. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. - -// Versioning -// There are two versioning cases that are handled by this: -// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, -// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. -// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface -// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and -// expose it for the old interface. - -#ifndef INTERFACE_H -#define INTERFACE_H - -#ifdef __cplusplus - -// All interfaces derive from this. -class IBaseInterface -{ -public: - - virtual ~IBaseInterface() {} -}; - - -#define CREATEINTERFACE_PROCNAME "CreateInterface" -typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); - - -typedef IBaseInterface* (*InstantiateInterfaceFn)(); - - -// Used internally to register classes. -class InterfaceReg -{ -public: - InterfaceReg(InstantiateInterfaceFn fn, const char *pName); - -public: - - InstantiateInterfaceFn m_CreateFn; - const char *m_pName; - - InterfaceReg *m_pNext; // For the global list. - static InterfaceReg *s_pInterfaceRegs; -}; - - -// Use this to expose an interface that can have multiple instances. -// e.g.: -// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) -// This will expose a class called CInterfaceImp that implements IInterface (a pure class) -// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) -// -// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") -// so that each component can use these names/vtables to communicate -// -// A single class can support multiple interfaces through multiple inheritance -// -#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ - static InterfaceReg __g_Create##className##_reg(functionName, versionName); - -#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ - static IBaseInterface* __Create##className##_interface() {return (interfaceName *)new className;}\ - static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); - -// Use this to expose a singleton interface with a global variable you've created. -#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ - static IBaseInterface* __Create##className##interfaceName##_interface() {return (interfaceName *)&globalVarName;}\ - static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); - -// Use this to expose a singleton interface. This creates the global variable for you automatically. -#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ - static className __g_##className##_singleton;\ - EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) - - -#ifdef WIN32 - #define EXPORT_FUNCTION __declspec(dllexport) -#else - #define EXPORT_FUNCTION -#endif - - -// This function is automatically exported and allows you to access any interfaces exposed with the above macros. -// if pReturnCode is set, it will return one of the following values -// extend this for other error conditions/code -enum -{ - IFACE_OK = 0, - IFACE_FAILED -}; - - -extern "C" -{ - EXPORT_FUNCTION IBaseInterface* CreateInterface(const char *pName, int *pReturnCode); -}; - - -// Handle to an interface (HInterfaceModule_t* is just there for type safety). -typedef struct HInterfaceModule_t* HINTERFACEMODULE; - - -// Use these to load and unload a module. -extern HINTERFACEMODULE Sys_LoadModule(const char *pModuleName); -extern void Sys_FreeModule(HINTERFACEMODULE hModule); - -// Use these to get the factory function from either a loaded module or the current module. -extern CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ); -extern CreateInterfaceFn Sys_GetFactoryThis( void ); - -#endif // __cplusplus - -#endif - - - + +// This header defines the interface convention used in the valve engine. +// To make an interface and expose it: +// 1. Derive from IBaseInterface. +// 2. The interface must be ALL pure virtuals, and have no data members. +// 3. Define a name for it. +// 4. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. + +// Versioning +// There are two versioning cases that are handled by this: +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// expose it for the old interface. + +#ifndef INTERFACE_H +#define INTERFACE_H + +#ifdef __cplusplus + +// All interfaces derive from this. +class IBaseInterface +{ +public: + + virtual ~IBaseInterface() {} +}; + + +#define CREATEINTERFACE_PROCNAME "CreateInterface" +typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); + + +typedef IBaseInterface* (*InstantiateInterfaceFn)(); + + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + +public: + + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; + + InterfaceReg *m_pNext; // For the global list. + static InterfaceReg *s_pInterfaceRegs; +}; + + +// Use this to expose an interface that can have multiple instances. +// e.g.: +// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// This will expose a class called CInterfaceImp that implements IInterface (a pure class) +// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// +// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") +// so that each component can use these names/vtables to communicate +// +// A single class can support multiple interfaces through multiple inheritance +// +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##className##_reg(functionName, versionName); + +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static IBaseInterface* __Create##className##_interface() {return (interfaceName *)new className;}\ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); + +// Use this to expose a singleton interface with a global variable you've created. +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + static IBaseInterface* __Create##className##interfaceName##_interface() {return (interfaceName *)&globalVarName;}\ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); + +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton;\ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) + + +#ifdef WIN32 + #define EXPORT_FUNCTION __declspec(dllexport) +#else + #define EXPORT_FUNCTION +#endif + + +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values +// extend this for other error conditions/code +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + + +extern "C" +{ + EXPORT_FUNCTION IBaseInterface* CreateInterface(const char *pName, int *pReturnCode); +}; + + +// Handle to an interface (HInterfaceModule_t* is just there for type safety). +typedef struct HInterfaceModule_t* HINTERFACEMODULE; + + +// Use these to load and unload a module. +extern HINTERFACEMODULE Sys_LoadModule(const char *pModuleName); +extern void Sys_FreeModule(HINTERFACEMODULE hModule); + +// Use these to get the factory function from either a loaded module or the current module. +extern CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ); +extern CreateInterfaceFn Sys_GetFactoryThis( void ); + +#endif // __cplusplus + +#endif + + + diff --git a/main/source/common/itrackeruser.h b/main/source/common/itrackeruser.h index 5ba185c9..49aba5e2 100644 --- a/main/source/common/itrackeruser.h +++ b/main/source/common/itrackeruser.h @@ -1,46 +1,46 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef ITRACKERUSER_H -#define ITRACKERUSER_H -#ifdef _WIN32 -#pragma once -#endif - -#include "interface.h" - -//----------------------------------------------------------------------------- -// Purpose: Interface to accessing information about tracker users -//----------------------------------------------------------------------------- -class ITrackerUser : public IBaseInterface -{ -public: - // returns true if the interface is ready for use - virtual bool IsValid() = 0; - - // returns the tracker ID of the current user - virtual int GetTrackerID() = 0; - - // returns information about a user - // information may not be known about some users, "" will be returned - virtual const char *GetUserName(int trackerID) = 0; - virtual const char *GetFirstName(int trackerID) = 0; - virtual const char *GetLastName(int trackerID) = 0; - virtual const char *GetEmail(int trackerID) = 0; - - // returns true if friendID is a friend of the current user - // ie. the current is authorized to see when the friend is online - virtual bool IsFriend(int friendID) = 0; - - // requests authorization from a user - virtual void RequestAuthorizationFromUser(int potentialFriendID) = 0; -}; - -#define TRACKERUSER_INTERFACE_VERSION "TrackerUser001" - - -#endif // ITRACKERUSER_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef ITRACKERUSER_H +#define ITRACKERUSER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing information about tracker users +//----------------------------------------------------------------------------- +class ITrackerUser : public IBaseInterface +{ +public: + // returns true if the interface is ready for use + virtual bool IsValid() = 0; + + // returns the tracker ID of the current user + virtual int GetTrackerID() = 0; + + // returns information about a user + // information may not be known about some users, "" will be returned + virtual const char *GetUserName(int trackerID) = 0; + virtual const char *GetFirstName(int trackerID) = 0; + virtual const char *GetLastName(int trackerID) = 0; + virtual const char *GetEmail(int trackerID) = 0; + + // returns true if friendID is a friend of the current user + // ie. the current is authorized to see when the friend is online + virtual bool IsFriend(int friendID) = 0; + + // requests authorization from a user + virtual void RequestAuthorizationFromUser(int potentialFriendID) = 0; +}; + +#define TRACKERUSER_INTERFACE_VERSION "TrackerUser001" + + +#endif // ITRACKERUSER_H diff --git a/main/source/common/ivoicetweak.h b/main/source/common/ivoicetweak.h index 9c39a5fe..f30e813b 100644 --- a/main/source/common/ivoicetweak.h +++ b/main/source/common/ivoicetweak.h @@ -1,35 +1,35 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef IVOICETWEAK_H -#define IVOICETWEAK_H -#ifdef _WIN32 -#pragma once -#endif - -// These provide access to the voice controls. -typedef enum -{ - MicrophoneVolume=0, // values 0-1. - OtherSpeakerScale // values 0-1. Scales how loud other players are. -} VoiceTweakControl; - - -typedef struct IVoiceTweak_s -{ - // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back - // without sending to the server. - int (*StartVoiceTweakMode)(); // Returns 0 on error. - void (*EndVoiceTweakMode)(); - - // Get/set control values. - void (*SetControlFloat)(VoiceTweakControl iControl, float value); - float (*GetControlFloat)(VoiceTweakControl iControl); -} IVoiceTweak; - - -#endif // IVOICETWEAK_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef IVOICETWEAK_H +#define IVOICETWEAK_H +#ifdef _WIN32 +#pragma once +#endif + +// These provide access to the voice controls. +typedef enum +{ + MicrophoneVolume=0, // values 0-1. + OtherSpeakerScale // values 0-1. Scales how loud other players are. +} VoiceTweakControl; + + +typedef struct IVoiceTweak_s +{ + // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back + // without sending to the server. + int (*StartVoiceTweakMode)(); // Returns 0 on error. + void (*EndVoiceTweakMode)(); + + // Get/set control values. + void (*SetControlFloat)(VoiceTweakControl iControl, float value); + float (*GetControlFloat)(VoiceTweakControl iControl); +} IVoiceTweak; + + +#endif // IVOICETWEAK_H diff --git a/main/source/common/mathlib.h b/main/source/common/mathlib.h index 931be6c5..b9fbcecd 100644 --- a/main/source/common/mathlib.h +++ b/main/source/common/mathlib.h @@ -1,163 +1,163 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// mathlib.h -#ifndef MATHLIB_H -#define MATHLIB_H - -typedef float vec_t; -#ifndef DID_VEC3_T_DEFINE -#define DID_VEC3_T_DEFINE -typedef vec_t vec3_t[3]; -#endif -typedef vec_t vec4_t[4]; // x,y,z,w -typedef vec_t vec5_t[5]; - -typedef short vec_s_t; -typedef vec_s_t vec3s_t[3]; -typedef vec_s_t vec4s_t[4]; // x,y,z,w -typedef vec_s_t vec5s_t[5]; - -typedef int fixed4_t; -typedef int fixed8_t; -typedef int fixed16_t; -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -struct mplane_s; - -extern vec3_t vec3_origin; -extern int nanmask; - -#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) - -#include "vec_op.h" -//#ifndef VECTOR_H -// #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) -//#endif -// -//#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} -//#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} -//#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} -//#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} - -void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc); - -vec_t _DotProduct (vec3_t v1, vec3_t v2); -void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); -void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); -void _VectorCopy (vec3_t in, vec3_t out); - -int VectorCompare (const vec3_t v1, const vec3_t v2); -float Length (const vec3_t v); -void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); -float VectorNormalize (vec3_t v); // returns vector length -void VectorInverse (vec3_t v); -void VectorScale (const vec3_t in, vec_t scale, vec3_t out); -int Q_log2(int val); - -void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); -void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); - -// Here are some "manual" INLINE routines for doing floating point to integer conversions -extern short new_cw, old_cw; - -typedef union DLONG { - int i[2]; - double d; - float f; - } DLONG; - -extern DLONG dlong; - -#ifdef _WIN32 -void __inline set_fpu_cw(void) -{ -_asm - { wait - fnstcw old_cw - wait - mov ax, word ptr old_cw - or ah, 0xc - mov word ptr new_cw,ax - fldcw new_cw - } -} - -int __inline quick_ftol(float f) -{ - _asm { - // Assumes that we are already in chop mode, and only need a 32-bit int - fld DWORD PTR f - fistp DWORD PTR dlong - } - return dlong.i[0]; -} - -void __inline restore_fpu_cw(void) -{ - _asm fldcw old_cw -} -#else -#define set_fpu_cw() /* */ -#define quick_ftol(f) ftol(f) -#define restore_fpu_cw() /* */ -#endif - -void FloorDivMod (double numer, double denom, int *quotient, - int *rem); -fixed16_t Invert24To16(fixed16_t val); -int GreatestCommonDivisor (int i1, int i2); - -void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -#define AngleIVectors AngleVectorsTranspose - -void AngleMatrix (const vec3_t angles, float (*matrix)[4] ); -void AngleIMatrix (const vec3_t angles, float (*matrix)[4] ); -void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out); - -void NormalizeAngles( vec3_t angles ); -void InterpolateAngles( vec3_t start, vec3_t end, vec3_t output, float frac ); -float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ); - - -void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up); -void VectorAngles( const vec3_t forward, vec3_t angles ); - -int InvertMatrix( const float * m, float *out ); - -int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); -float anglemod(float a); - - - -#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ - (((p)->type < 3)? \ - ( \ - ((p)->dist <= (emins)[(p)->type])? \ - 1 \ - : \ - ( \ - ((p)->dist >= (emaxs)[(p)->type])?\ - 2 \ - : \ - 3 \ - ) \ - ) \ - : \ - BoxOnPlaneSide( (emins), (emaxs), (p))) - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// mathlib.h +#ifndef MATHLIB_H +#define MATHLIB_H + +typedef float vec_t; +#ifndef DID_VEC3_T_DEFINE +#define DID_VEC3_T_DEFINE +typedef vec_t vec3_t[3]; +#endif +typedef vec_t vec4_t[4]; // x,y,z,w +typedef vec_t vec5_t[5]; + +typedef short vec_s_t; +typedef vec_s_t vec3s_t[3]; +typedef vec_s_t vec4s_t[4]; // x,y,z,w +typedef vec_s_t vec5s_t[5]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +struct mplane_s; + +extern vec3_t vec3_origin; +extern int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +#include "vec_op.h" +//#ifndef VECTOR_H +// #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +//#endif +// +//#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +//#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +//#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +//#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} + +void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc); + +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); + +int VectorCompare (const vec3_t v1, const vec3_t v2); +float Length (const vec3_t v); +void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); +float VectorNormalize (vec3_t v); // returns vector length +void VectorInverse (vec3_t v); +void VectorScale (const vec3_t in, vec_t scale, vec3_t out); +int Q_log2(int val); + +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); + +// Here are some "manual" INLINE routines for doing floating point to integer conversions +extern short new_cw, old_cw; + +typedef union DLONG { + int i[2]; + double d; + float f; + } DLONG; + +extern DLONG dlong; + +#ifdef _WIN32 +void __inline set_fpu_cw(void) +{ +_asm + { wait + fnstcw old_cw + wait + mov ax, word ptr old_cw + or ah, 0xc + mov word ptr new_cw,ax + fldcw new_cw + } +} + +int __inline quick_ftol(float f) +{ + _asm { + // Assumes that we are already in chop mode, and only need a 32-bit int + fld DWORD PTR f + fistp DWORD PTR dlong + } + return dlong.i[0]; +} + +void __inline restore_fpu_cw(void) +{ + _asm fldcw old_cw +} +#else +#define set_fpu_cw() /* */ +#define quick_ftol(f) ftol(f) +#define restore_fpu_cw() /* */ +#endif + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem); +fixed16_t Invert24To16(fixed16_t val); +int GreatestCommonDivisor (int i1, int i2); + +void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +#define AngleIVectors AngleVectorsTranspose + +void AngleMatrix (const vec3_t angles, float (*matrix)[4] ); +void AngleIMatrix (const vec3_t angles, float (*matrix)[4] ); +void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out); + +void NormalizeAngles( vec3_t angles ); +void InterpolateAngles( vec3_t start, vec3_t end, vec3_t output, float frac ); +float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ); + + +void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up); +void VectorAngles( const vec3_t forward, vec3_t angles ); + +int InvertMatrix( const float * m, float *out ); + +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); +float anglemod(float a); + + + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) + +#endif diff --git a/main/source/common/net_api.h b/main/source/common/net_api.h index 26f24957..49c39e7f 100644 --- a/main/source/common/net_api.h +++ b/main/source/common/net_api.h @@ -5,95 +5,95 @@ // $NoKeywords: $ //============================================================================= -#if !defined( NET_APIH ) -#define NET_APIH -#ifdef _WIN32 -#pragma once -#endif - -#if !defined ( NETADRH ) -#include "netadr.h" -#endif - -#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address -#define NETAPI_REQUEST_PING ( 1 ) -#define NETAPI_REQUEST_RULES ( 2 ) -#define NETAPI_REQUEST_PLAYERS ( 3 ) -#define NETAPI_REQUEST_DETAILS ( 4 ) - -// Set this flag for things like broadcast requests, etc. where the engine should not -// kill the request hook after receiving the first response -#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) - -typedef void ( *net_api_response_func_t ) ( struct net_response_s *response ); - -#define NET_SUCCESS ( 0 ) -#define NET_ERROR_TIMEOUT ( 1<<0 ) -#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) -#define NET_ERROR_UNDEFINED ( 1<<2 ) - -typedef struct net_adrlist_s -{ - struct net_adrlist_s *next; - netadr_t remote_address; -} net_adrlist_t; - -typedef struct net_response_s -{ - // NET_SUCCESS or an error code - int error; - - // Context ID - int context; - // Type - int type; - - // Server that is responding to the request - netadr_t remote_address; - - // Response RTT ping time - double ping; - // Key/Value pair string ( separated by backlash \ characters ) - // WARNING: You must copy this buffer in the callback function, because it is freed - // by the engine right after the call!!!! - // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's - void *response; -} net_response_t; - -typedef struct net_status_s -{ - // Connected to remote server? 1 == yes, 0 otherwise - int connected; - // Client's IP address - netadr_t local_address; - // Address of remote server - netadr_t remote_address; - // Packet Loss ( as a percentage ) - int packet_loss; - // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) - double latency; - // Connection time, in seconds - double connection_time; - // Rate setting ( for incoming data ) - double rate; -} net_status_t; - -typedef struct net_api_s -{ - // APIs - void ( *InitNetworking )( void ); - void ( *Status ) ( struct net_status_s *status ); - void ( *SendRequest) ( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); - void ( *CancelRequest ) ( int context ); - void ( *CancelAllRequests ) ( void ); - char *( *AdrToString ) ( struct netadr_s *a ); - int ( *CompareAdr ) ( struct netadr_s *a, struct netadr_s *b ); - int ( *StringToAdr ) ( char *s, struct netadr_s *a ); - const char *( *ValueForKey ) ( const char *s, const char *key ); - void ( *RemoveKey ) ( char *s, const char *key ); - void ( *SetValueForKey ) (char *s, const char *key, const char *value, int maxsize ); -} net_api_t; - -extern net_api_t netapi; - +#if !defined( NET_APIH ) +#define NET_APIH +#ifdef _WIN32 +#pragma once +#endif + +#if !defined ( NETADRH ) +#include "netadr.h" +#endif + +#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address +#define NETAPI_REQUEST_PING ( 1 ) +#define NETAPI_REQUEST_RULES ( 2 ) +#define NETAPI_REQUEST_PLAYERS ( 3 ) +#define NETAPI_REQUEST_DETAILS ( 4 ) + +// Set this flag for things like broadcast requests, etc. where the engine should not +// kill the request hook after receiving the first response +#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) + +typedef void ( *net_api_response_func_t ) ( struct net_response_s *response ); + +#define NET_SUCCESS ( 0 ) +#define NET_ERROR_TIMEOUT ( 1<<0 ) +#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) +#define NET_ERROR_UNDEFINED ( 1<<2 ) + +typedef struct net_adrlist_s +{ + struct net_adrlist_s *next; + netadr_t remote_address; +} net_adrlist_t; + +typedef struct net_response_s +{ + // NET_SUCCESS or an error code + int error; + + // Context ID + int context; + // Type + int type; + + // Server that is responding to the request + netadr_t remote_address; + + // Response RTT ping time + double ping; + // Key/Value pair string ( separated by backlash \ characters ) + // WARNING: You must copy this buffer in the callback function, because it is freed + // by the engine right after the call!!!! + // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's + void *response; +} net_response_t; + +typedef struct net_status_s +{ + // Connected to remote server? 1 == yes, 0 otherwise + int connected; + // Client's IP address + netadr_t local_address; + // Address of remote server + netadr_t remote_address; + // Packet Loss ( as a percentage ) + int packet_loss; + // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) + double latency; + // Connection time, in seconds + double connection_time; + // Rate setting ( for incoming data ) + double rate; +} net_status_t; + +typedef struct net_api_s +{ + // APIs + void ( *InitNetworking )( void ); + void ( *Status ) ( struct net_status_s *status ); + void ( *SendRequest) ( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); + void ( *CancelRequest ) ( int context ); + void ( *CancelAllRequests ) ( void ); + char *( *AdrToString ) ( struct netadr_s *a ); + int ( *CompareAdr ) ( struct netadr_s *a, struct netadr_s *b ); + int ( *StringToAdr ) ( char *s, struct netadr_s *a ); + const char *( *ValueForKey ) ( const char *s, const char *key ); + void ( *RemoveKey ) ( char *s, const char *key ); + void ( *SetValueForKey ) (char *s, const char *key, const char *value, int maxsize ); +} net_api_t; + +extern net_api_t netapi; + #endif // NET_APIH \ No newline at end of file diff --git a/main/source/common/netadr.h b/main/source/common/netadr.h index 3702e234..304073cf 100644 --- a/main/source/common/netadr.h +++ b/main/source/common/netadr.h @@ -1,40 +1,40 @@ -/*** -* +/*** +* * Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// netadr.h -#ifndef NETADR_H -#define NETADR_H -#ifdef _WIN32 -#pragma once -#endif - -typedef enum -{ - NA_UNUSED, - NA_LOOPBACK, - NA_BROADCAST, - NA_IP, - NA_IPX, - NA_BROADCAST_IPX, -} netadrtype_t; - -typedef struct netadr_s -{ - netadrtype_t type; - unsigned char ip[4]; - unsigned char ipx[10]; - unsigned short port; -} netadr_t; - -#endif // NETADR_H +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// netadr.h +#ifndef NETADR_H +#define NETADR_H +#ifdef _WIN32 +#pragma once +#endif + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX, +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; +} netadr_t; + +#endif // NETADR_H diff --git a/main/source/common/particledef.h b/main/source/common/particledef.h index 823f4fd6..9e559f3c 100644 --- a/main/source/common/particledef.h +++ b/main/source/common/particledef.h @@ -1,57 +1,57 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( PARTICLEDEFH ) -#define PARTICLEDEFH -#ifdef _WIN32 -#pragma once -#endif - -typedef enum { - pt_static, - pt_grav, - pt_slowgrav, - pt_fire, - pt_explode, - pt_explode2, - pt_blob, - pt_blob2, - pt_vox_slowgrav, - pt_vox_grav, - pt_clientcustom // Must have callback function specified -} ptype_t; - -// !!! if this is changed, it must be changed in d_ifacea.h too !!! -typedef struct particle_s -{ -// driver-usable fields - vec3_t org; - short color; - short packedColor; -// drivers never touch the following fields - struct particle_s *next; - vec3_t vel; - float ramp; - float die; - ptype_t type; - void (*deathfunc)( struct particle_s *particle ); - - // for pt_clientcusttom, we'll call this function each frame - void (*callback)( struct particle_s *particle, float frametime ); - - // For deathfunc, etc. - unsigned char context; -} particle_t; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PARTICLEDEFH ) +#define PARTICLEDEFH +#ifdef _WIN32 +#pragma once +#endif + +typedef enum { + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_clientcustom // Must have callback function specified +} ptype_t; + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +typedef struct particle_s +{ +// driver-usable fields + vec3_t org; + short color; + short packedColor; +// drivers never touch the following fields + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; + void (*deathfunc)( struct particle_s *particle ); + + // for pt_clientcusttom, we'll call this function each frame + void (*callback)( struct particle_s *particle, float frametime ); + + // For deathfunc, etc. + unsigned char context; +} particle_t; + +#endif diff --git a/main/source/common/pmtrace.h b/main/source/common/pmtrace.h index 071185fa..b34a1b57 100644 --- a/main/source/common/pmtrace.h +++ b/main/source/common/pmtrace.h @@ -1,43 +1,43 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( PMTRACEH ) -#define PMTRACEH -#ifdef _WIN32 -#pragma once -#endif - -typedef struct -{ - vec3_t normal; - float dist; -} pmplane_t; - -typedef struct pmtrace_s pmtrace_t; - -struct pmtrace_s -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - qboolean inopen, inwater; // End point is in empty space or in water - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - pmplane_t plane; // surface normal at impact - int ent; // entity at impact - vec3_t deltavelocity; // Change in player's velocity caused by impact. - // Only run on server. - int hitgroup; -}; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PMTRACEH ) +#define PMTRACEH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct +{ + vec3_t normal; + float dist; +} pmplane_t; + +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; // End point is in empty space or in water + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + pmplane_t plane; // surface normal at impact + int ent; // entity at impact + vec3_t deltavelocity; // Change in player's velocity caused by impact. + // Only run on server. + int hitgroup; +}; + +#endif diff --git a/main/source/common/qfont.h b/main/source/common/qfont.h index 3989001a..aaa5e5b2 100644 --- a/main/source/common/qfont.h +++ b/main/source/common/qfont.h @@ -1,40 +1,40 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( QFONTH ) -#define QFONTH -#ifdef _WIN32 -#pragma once -#endif - -// Font stuff - -#define NUM_GLYPHS 256 - -typedef struct -{ - short startoffset; - short charwidth; -} charinfo; - -typedef struct qfont_s -{ - int width, height; - int rowcount; - int rowheight; - charinfo fontinfo[ NUM_GLYPHS ]; - byte data[4]; -} qfont_t; - -#endif // qfont.h +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( QFONTH ) +#define QFONTH +#ifdef _WIN32 +#pragma once +#endif + +// Font stuff + +#define NUM_GLYPHS 256 + +typedef struct +{ + short startoffset; + short charwidth; +} charinfo; + +typedef struct qfont_s +{ + int width, height; + int rowcount; + int rowheight; + charinfo fontinfo[ NUM_GLYPHS ]; + byte data[4]; +} qfont_t; + +#endif // qfont.h diff --git a/main/source/common/r_efx.h b/main/source/common/r_efx.h index cf87cfd5..2bc9d338 100644 --- a/main/source/common/r_efx.h +++ b/main/source/common/r_efx.h @@ -1,196 +1,196 @@ -/*** -* +/*** +* * Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined ( R_EFXH ) -#define R_EFXH -#ifdef _WIN32 -#pragma once -#endif - -// particle_t -#if !defined( PARTICLEDEFH ) -#include "particledef.h" -#endif - -// BEAM -#if !defined( BEAMDEFH ) -#include "beamdef.h" -#endif - -// dlight_t -#if !defined ( DLIGHTH ) -#include "dlight.h" -#endif - -// cl_entity_t -#if !defined( CL_ENTITYH ) -#include "cl_entity.h" -#endif - -/* -// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one -// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings -color24 gTracerColors[] = -{ - { 255, 255, 255 }, // White - { 255, 0, 0 }, // Red - { 0, 255, 0 }, // Green - { 0, 0, 255 }, // Blue - { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. - { 255, 167, 17 }, // Yellow-orange sparks - { 255, 130, 90 }, // Yellowish streaks (garg) - { 55, 60, 144 }, // Blue egon streak - { 255, 130, 90 }, // More Yellowish streaks (garg) - { 255, 140, 90 }, // More Yellowish streaks (garg) - { 200, 130, 90 }, // More red streaks (garg) - { 255, 120, 70 }, // Darker red streaks (garg) -}; -*/ - -// Temporary entity array -#define TENTPRIORITY_LOW 0 -#define TENTPRIORITY_HIGH 1 - -// TEMPENTITY flags -#define FTENT_NONE 0x00000000 -#define FTENT_SINEWAVE 0x00000001 -#define FTENT_GRAVITY 0x00000002 -#define FTENT_ROTATE 0x00000004 -#define FTENT_SLOWGRAVITY 0x00000008 -#define FTENT_SMOKETRAIL 0x00000010 -#define FTENT_COLLIDEWORLD 0x00000020 -#define FTENT_FLICKER 0x00000040 -#define FTENT_FADEOUT 0x00000080 -#define FTENT_SPRANIMATE 0x00000100 -#define FTENT_HITSOUND 0x00000200 -#define FTENT_SPIRAL 0x00000400 -#define FTENT_SPRCYCLE 0x00000800 -#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes -#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw -#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything -#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) -#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed -#define FTENT_SPARKSHOWER 0x00020000 -#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) -#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) - -typedef struct tempent_s -{ - int flags; - float die; - float frameMax; - float x; - float y; - float z; - float fadeSpeed; - float bounceFactor; - int hitSound; - void ( *hitcallback ) ( struct tempent_s *ent, struct pmtrace_s *ptr ); - void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ); +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( R_EFXH ) +#define R_EFXH +#ifdef _WIN32 +#pragma once +#endif + +// particle_t +#if !defined( PARTICLEDEFH ) +#include "particledef.h" +#endif + +// BEAM +#if !defined( BEAMDEFH ) +#include "beamdef.h" +#endif + +// dlight_t +#if !defined ( DLIGHTH ) +#include "dlight.h" +#endif + +// cl_entity_t +#if !defined( CL_ENTITYH ) +#include "cl_entity.h" +#endif + +/* +// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one +// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings +color24 gTracerColors[] = +{ + { 255, 255, 255 }, // White + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 0, 0, 255 }, // Blue + { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. + { 255, 167, 17 }, // Yellow-orange sparks + { 255, 130, 90 }, // Yellowish streaks (garg) + { 55, 60, 144 }, // Blue egon streak + { 255, 130, 90 }, // More Yellowish streaks (garg) + { 255, 140, 90 }, // More Yellowish streaks (garg) + { 200, 130, 90 }, // More red streaks (garg) + { 255, 120, 70 }, // Darker red streaks (garg) +}; +*/ + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SPARKSHOWER 0x00020000 +#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) + +typedef struct tempent_s +{ + int flags; + float die; + float frameMax; + float x; + float y; + float z; + float fadeSpeed; + float bounceFactor; + int hitSound; + void ( *hitcallback ) ( struct tempent_s *ent, struct pmtrace_s *ptr ); + void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ); struct tempent_s *next; - int priority; - short clientIndex; // if attached, this is the index of the client to stick to - // if COLLIDEALL, this is the index of the client to ignore - // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! - - vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. - cl_entity_t entity; - - // baseline.origin - velocity - // baseline.renderamt - starting fadeout intensity - // baseline.angles - angle velocity -} TEMPENTITY; - -typedef struct efx_api_s efx_api_t; - -struct efx_api_s -{ - particle_t *( *R_AllocParticle ) ( void ( *callback ) ( struct particle_s *particle, float frametime ) ); - void ( *R_BlobExplosion ) ( float * org ); - void ( *R_Blood ) ( float * org, float * dir, int pcolor, int speed ); - void ( *R_BloodSprite ) ( float * org, int colorindex, int modelIndex, int modelIndex2, float size ); - void ( *R_BloodStream ) ( float * org, float * dir, int pcolor, int speed ); - void ( *R_BreakModel ) ( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); - void ( *R_Bubbles ) ( float * mins, float * maxs, float height, int modelIndex, int count, float speed ); - void ( *R_BubbleTrail ) ( float * start, float * end, float height, int modelIndex, int count, float speed ); - void ( *R_BulletImpactParticles ) ( float * pos ); - void ( *R_EntityParticles ) ( struct cl_entity_s *ent ); - void ( *R_Explosion ) ( float *pos, int model, float scale, float framerate, int flags ); - void ( *R_FizzEffect ) ( struct cl_entity_s *pent, int modelIndex, int density ); - void ( *R_FireField ) ( float * org, int radius, int modelIndex, int count, int flags, float life ); - void ( *R_FlickerParticles ) ( float * org ); - void ( *R_FunnelSprite ) ( float *org, int modelIndex, int reverse ); - void ( *R_Implosion ) ( float * end, float radius, int count, float life ); - void ( *R_LargeFunnel ) ( float * org, int reverse ); - void ( *R_LavaSplash ) ( float * org ); - void ( *R_MultiGunshot ) ( float * org, float * dir, float * noise, int count, int decalCount, int *decalIndices ); - void ( *R_MuzzleFlash ) ( float *pos1, int type ); - void ( *R_ParticleBox ) ( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); - void ( *R_ParticleBurst ) ( float * pos, int size, int color, float life ); - void ( *R_ParticleExplosion ) ( float * org ); - void ( *R_ParticleExplosion2 ) ( float * org, int colorStart, int colorLength ); - void ( *R_ParticleLine ) ( float * start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); - void ( *R_PlayerSprites ) ( int client, int modelIndex, int count, int size ); - void ( *R_Projectile ) ( float * origin, float * velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); - void ( *R_RicochetSound ) ( float * pos ); - void ( *R_RicochetSprite ) ( float *pos, struct model_s *pmodel, float duration, float scale ); - void ( *R_RocketFlare ) ( float *pos ); - void ( *R_RocketTrail ) ( float * start, float * end, int type ); - void ( *R_RunParticleEffect ) ( float * org, float * dir, int color, int count ); - void ( *R_ShowLine ) ( float * start, float * end ); - void ( *R_SparkEffect ) ( float *pos, int count, int velocityMin, int velocityMax ); - void ( *R_SparkShower ) ( float *pos ); - void ( *R_SparkStreaks ) ( float * pos, int count, int velocityMin, int velocityMax ); - void ( *R_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int spread, int rendermode ); - void ( *R_Sprite_Explode ) ( TEMPENTITY *pTemp, float scale, int flags ); - void ( *R_Sprite_Smoke ) ( TEMPENTITY *pTemp, float scale ); - void ( *R_Sprite_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int iRand ); - void ( *R_Sprite_Trail ) ( int type, float * start, float * end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); - void ( *R_Sprite_WallPuff ) ( TEMPENTITY *pTemp, float scale ); - void ( *R_StreakSplash ) ( float * pos, float * dir, int color, int count, float speed, int velocityMin, int velocityMax ); - void ( *R_TracerEffect ) ( float * start, float * end ); - void ( *R_UserTracerParticle ) ( float * org, float * vel, float life, int colorIndex, float length, unsigned char deathcontext, void ( *deathfunc)( struct particle_s *particle ) ); - particle_t *( *R_TracerParticles ) ( float * org, float * vel, float life ); - void ( *R_TeleportSplash ) ( float * org ); - void ( *R_TempSphereModel ) ( float *pos, float speed, float life, int count, int modelIndex ); - TEMPENTITY *( *R_TempModel ) ( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); - TEMPENTITY *( *R_DefaultSprite ) ( float *pos, int spriteIndex, float framerate ); - TEMPENTITY *( *R_TempSprite ) ( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); - int ( *Draw_DecalIndex ) ( int id ); - int ( *Draw_DecalIndexFromName ) ( char *name ); - void ( *R_DecalShoot ) ( int textureIndex, int entity, int modelIndex, float * position, int flags ); - void ( *R_AttachTentToPlayer ) ( int client, int modelIndex, float zoffset, float life ); - void ( *R_KillAttachedTents ) ( int client ); - BEAM *( *R_BeamCirclePoints ) ( int type, float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *( *R_BeamEntPoint ) ( int startEnt, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *( *R_BeamEnts ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *( *R_BeamFollow ) ( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); - void ( *R_BeamKill ) ( int deadEntity ); - BEAM *( *R_BeamLightning ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); - BEAM *( *R_BeamPoints ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *( *R_BeamRing ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - dlight_t *( *CL_AllocDlight ) ( int key ); - dlight_t *( *CL_AllocElight ) ( int key ); - TEMPENTITY *( *CL_TempEntAlloc ) ( float * org, struct model_s *model ); - TEMPENTITY *( *CL_TempEntAllocNoModel ) ( float * org ); - TEMPENTITY *( *CL_TempEntAllocHigh ) ( float * org, struct model_s *model ); - TEMPENTITY *( *CL_TentEntAllocCustom ) ( float *origin, struct model_s *model, int high, void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ) ); - void ( *R_GetPackedColor ) ( short *packed, short color ); - short ( *R_LookupColor ) ( unsigned char r, unsigned char g, unsigned char b ); - void ( *R_DecalRemoveAll ) ( int textureIndex ); //textureIndex points to the decal index in the array, not the actual texture index. -}; - -extern efx_api_t efx; - -#endif + int priority; + short clientIndex; // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + + vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. + cl_entity_t entity; + + // baseline.origin - velocity + // baseline.renderamt - starting fadeout intensity + // baseline.angles - angle velocity +} TEMPENTITY; + +typedef struct efx_api_s efx_api_t; + +struct efx_api_s +{ + particle_t *( *R_AllocParticle ) ( void ( *callback ) ( struct particle_s *particle, float frametime ) ); + void ( *R_BlobExplosion ) ( float * org ); + void ( *R_Blood ) ( float * org, float * dir, int pcolor, int speed ); + void ( *R_BloodSprite ) ( float * org, int colorindex, int modelIndex, int modelIndex2, float size ); + void ( *R_BloodStream ) ( float * org, float * dir, int pcolor, int speed ); + void ( *R_BreakModel ) ( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); + void ( *R_Bubbles ) ( float * mins, float * maxs, float height, int modelIndex, int count, float speed ); + void ( *R_BubbleTrail ) ( float * start, float * end, float height, int modelIndex, int count, float speed ); + void ( *R_BulletImpactParticles ) ( float * pos ); + void ( *R_EntityParticles ) ( struct cl_entity_s *ent ); + void ( *R_Explosion ) ( float *pos, int model, float scale, float framerate, int flags ); + void ( *R_FizzEffect ) ( struct cl_entity_s *pent, int modelIndex, int density ); + void ( *R_FireField ) ( float * org, int radius, int modelIndex, int count, int flags, float life ); + void ( *R_FlickerParticles ) ( float * org ); + void ( *R_FunnelSprite ) ( float *org, int modelIndex, int reverse ); + void ( *R_Implosion ) ( float * end, float radius, int count, float life ); + void ( *R_LargeFunnel ) ( float * org, int reverse ); + void ( *R_LavaSplash ) ( float * org ); + void ( *R_MultiGunshot ) ( float * org, float * dir, float * noise, int count, int decalCount, int *decalIndices ); + void ( *R_MuzzleFlash ) ( float *pos1, int type ); + void ( *R_ParticleBox ) ( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); + void ( *R_ParticleBurst ) ( float * pos, int size, int color, float life ); + void ( *R_ParticleExplosion ) ( float * org ); + void ( *R_ParticleExplosion2 ) ( float * org, int colorStart, int colorLength ); + void ( *R_ParticleLine ) ( float * start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); + void ( *R_PlayerSprites ) ( int client, int modelIndex, int count, int size ); + void ( *R_Projectile ) ( float * origin, float * velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); + void ( *R_RicochetSound ) ( float * pos ); + void ( *R_RicochetSprite ) ( float *pos, struct model_s *pmodel, float duration, float scale ); + void ( *R_RocketFlare ) ( float *pos ); + void ( *R_RocketTrail ) ( float * start, float * end, int type ); + void ( *R_RunParticleEffect ) ( float * org, float * dir, int color, int count ); + void ( *R_ShowLine ) ( float * start, float * end ); + void ( *R_SparkEffect ) ( float *pos, int count, int velocityMin, int velocityMax ); + void ( *R_SparkShower ) ( float *pos ); + void ( *R_SparkStreaks ) ( float * pos, int count, int velocityMin, int velocityMax ); + void ( *R_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int spread, int rendermode ); + void ( *R_Sprite_Explode ) ( TEMPENTITY *pTemp, float scale, int flags ); + void ( *R_Sprite_Smoke ) ( TEMPENTITY *pTemp, float scale ); + void ( *R_Sprite_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int iRand ); + void ( *R_Sprite_Trail ) ( int type, float * start, float * end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); + void ( *R_Sprite_WallPuff ) ( TEMPENTITY *pTemp, float scale ); + void ( *R_StreakSplash ) ( float * pos, float * dir, int color, int count, float speed, int velocityMin, int velocityMax ); + void ( *R_TracerEffect ) ( float * start, float * end ); + void ( *R_UserTracerParticle ) ( float * org, float * vel, float life, int colorIndex, float length, unsigned char deathcontext, void ( *deathfunc)( struct particle_s *particle ) ); + particle_t *( *R_TracerParticles ) ( float * org, float * vel, float life ); + void ( *R_TeleportSplash ) ( float * org ); + void ( *R_TempSphereModel ) ( float *pos, float speed, float life, int count, int modelIndex ); + TEMPENTITY *( *R_TempModel ) ( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); + TEMPENTITY *( *R_DefaultSprite ) ( float *pos, int spriteIndex, float framerate ); + TEMPENTITY *( *R_TempSprite ) ( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); + int ( *Draw_DecalIndex ) ( int id ); + int ( *Draw_DecalIndexFromName ) ( char *name ); + void ( *R_DecalShoot ) ( int textureIndex, int entity, int modelIndex, float * position, int flags ); + void ( *R_AttachTentToPlayer ) ( int client, int modelIndex, float zoffset, float life ); + void ( *R_KillAttachedTents ) ( int client ); + BEAM *( *R_BeamCirclePoints ) ( int type, float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamEntPoint ) ( int startEnt, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamEnts ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamFollow ) ( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); + void ( *R_BeamKill ) ( int deadEntity ); + BEAM *( *R_BeamLightning ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); + BEAM *( *R_BeamPoints ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamRing ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + dlight_t *( *CL_AllocDlight ) ( int key ); + dlight_t *( *CL_AllocElight ) ( int key ); + TEMPENTITY *( *CL_TempEntAlloc ) ( float * org, struct model_s *model ); + TEMPENTITY *( *CL_TempEntAllocNoModel ) ( float * org ); + TEMPENTITY *( *CL_TempEntAllocHigh ) ( float * org, struct model_s *model ); + TEMPENTITY *( *CL_TentEntAllocCustom ) ( float *origin, struct model_s *model, int high, void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ) ); + void ( *R_GetPackedColor ) ( short *packed, short color ); + short ( *R_LookupColor ) ( unsigned char r, unsigned char g, unsigned char b ); + void ( *R_DecalRemoveAll ) ( int textureIndex ); //textureIndex points to the decal index in the array, not the actual texture index. +}; + +extern efx_api_t efx; + +#endif diff --git a/main/source/common/ref_params.h b/main/source/common/ref_params.h index 974fcc70..01b1cd5b 100644 --- a/main/source/common/ref_params.h +++ b/main/source/common/ref_params.h @@ -1,75 +1,75 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( REF_PARAMSH ) -#define REF_PARAMSH - -typedef struct ref_params_s -{ - // Output - float vieworg[3]; - float viewangles[3]; - - float forward[3]; - float right[3]; - float up[3]; - - // Client frametime; - float frametime; - // Client time - float time; - - // Misc - int intermission; - int paused; - int spectator; - int onground; - int waterlevel; - - float simvel[3]; - float simorg[3]; - - float viewheight[3]; - float idealpitch; - - float cl_viewangles[3]; - - int health; - float crosshairangle[3]; - float viewsize; - - float punchangle[3]; - int maxclients; - int viewentity; - int playernum; - int max_entities; - int demoplayback; - int hardware; - - int smoothing; - - // Last issued usercmd - struct usercmd_s *cmd; - - // Movevars - struct movevars_s *movevars; - - int viewport[4]; // the viewport coordinates x ,y , width, height - - int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview - // so long in cycles until this value is 0 (multiple views) - int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions -} ref_params_t; - -#endif // !REF_PARAMSH +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( REF_PARAMSH ) +#define REF_PARAMSH + +typedef struct ref_params_s +{ + // Output + float vieworg[3]; + float viewangles[3]; + + float forward[3]; + float right[3]; + float up[3]; + + // Client frametime; + float frametime; + // Client time + float time; + + // Misc + int intermission; + int paused; + int spectator; + int onground; + int waterlevel; + + float simvel[3]; + float simorg[3]; + + float viewheight[3]; + float idealpitch; + + float cl_viewangles[3]; + + int health; + float crosshairangle[3]; + float viewsize; + + float punchangle[3]; + int maxclients; + int viewentity; + int playernum; + int max_entities; + int demoplayback; + int hardware; + + int smoothing; + + // Last issued usercmd + struct usercmd_s *cmd; + + // Movevars + struct movevars_s *movevars; + + int viewport[4]; // the viewport coordinates x ,y , width, height + + int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview + // so long in cycles until this value is 0 (multiple views) + int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions +} ref_params_t; + +#endif // !REF_PARAMSH diff --git a/main/source/common/renderingconst.h b/main/source/common/renderingconst.h index f06a60f2..cce6ddad 100644 --- a/main/source/common/renderingconst.h +++ b/main/source/common/renderingconst.h @@ -1,41 +1,41 @@ -#ifndef RENDERINGCONST_H -#define RENDERINGCONST_H - -// Rendering constants -enum -{ - kRenderNormal, // src - kRenderTransColor, // c*a+dest*(1-a) - kRenderTransTexture, // src*a+dest*(1-a) - kRenderGlow, // src*a+dest -- No Z buffer checks - kRenderTransAlpha, // src*srca+dest*(1-srca) - kRenderTransAdd, // src*a+dest -}; - -enum -{ - kRenderFxNone = 0, - kRenderFxPulseSlow, - kRenderFxPulseFast, - kRenderFxPulseSlowWide, - kRenderFxPulseFastWide, - kRenderFxFadeSlow, - kRenderFxFadeFast, - kRenderFxSolidSlow, - kRenderFxSolidFast, - kRenderFxStrobeSlow, - kRenderFxStrobeFast, - kRenderFxStrobeFaster, - kRenderFxFlickerSlow, - kRenderFxFlickerFast, - kRenderFxNoDissipation, - kRenderFxDistort, // Distort/scale/translate flicker - kRenderFxHologram, // kRenderFxDistort + distance fade - kRenderFxDeadPlayer, // kRenderAmt is the player index - kRenderFxExplode, // Scale up really big! - kRenderFxGlowShell, // Glowing Shell - kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) -}; - -#endif - +#ifndef RENDERINGCONST_H +#define RENDERINGCONST_H + +// Rendering constants +enum +{ + kRenderNormal, // src + kRenderTransColor, // c*a+dest*(1-a) + kRenderTransTexture, // src*a+dest*(1-a) + kRenderGlow, // src*a+dest -- No Z buffer checks + kRenderTransAlpha, // src*srca+dest*(1-srca) + kRenderTransAdd, // src*a+dest +}; + +enum +{ + kRenderFxNone = 0, + kRenderFxPulseSlow, + kRenderFxPulseFast, + kRenderFxPulseSlowWide, + kRenderFxPulseFastWide, + kRenderFxFadeSlow, + kRenderFxFadeFast, + kRenderFxSolidSlow, + kRenderFxSolidFast, + kRenderFxStrobeSlow, + kRenderFxStrobeFast, + kRenderFxStrobeFaster, + kRenderFxFlickerSlow, + kRenderFxFlickerFast, + kRenderFxNoDissipation, + kRenderFxDistort, // Distort/scale/translate flicker + kRenderFxHologram, // kRenderFxDistort + distance fade + kRenderFxDeadPlayer, // kRenderAmt is the player index + kRenderFxExplode, // Scale up really big! + kRenderFxGlowShell, // Glowing Shell + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) +}; + +#endif + diff --git a/main/source/common/screenfade.h b/main/source/common/screenfade.h index 2311d06d..fd476515 100644 --- a/main/source/common/screenfade.h +++ b/main/source/common/screenfade.h @@ -1,18 +1,18 @@ -#if !defined( SCREENFADEH ) -#define SCREENFADEH -#ifdef _WIN32 -#pragma once -#endif - - -typedef struct screenfade_s -{ - float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) - float fadeEnd; // When the fading hits maximum - float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) - float fadeReset; // When to reset to not fading (for fadeout and hold) - byte fader, fadeg, fadeb, fadealpha; // Fade color - int fadeFlags; // Fading flags -} screenfade_t; - -#endif // !SCREENFADEH +#if !defined( SCREENFADEH ) +#define SCREENFADEH +#ifdef _WIN32 +#pragma once +#endif + + +typedef struct screenfade_s +{ + float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) + float fadeEnd; // When the fading hits maximum + float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) + float fadeReset; // When to reset to not fading (for fadeout and hold) + byte fader, fadeg, fadeb, fadealpha; // Fade color + int fadeFlags; // Fading flags +} screenfade_t; + +#endif // !SCREENFADEH diff --git a/main/source/common/studio_event.h b/main/source/common/studio_event.h index 8fae6f54..ba9d182b 100644 --- a/main/source/common/studio_event.h +++ b/main/source/common/studio_event.h @@ -1,29 +1,29 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( STUDIO_EVENTH ) -#define STUDIO_EVENTH -#ifdef _WIN32 -#pragma once -#endif - -typedef struct mstudioevent_s -{ - int frame; - int event; - int type; - char options[64]; -} mstudioevent_t; - -#endif // STUDIO_EVENTH +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( STUDIO_EVENTH ) +#define STUDIO_EVENTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct mstudioevent_s +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; + +#endif // STUDIO_EVENTH diff --git a/main/source/common/triangleapi.h b/main/source/common/triangleapi.h index c8fc14c0..e55da691 100644 --- a/main/source/common/triangleapi.h +++ b/main/source/common/triangleapi.h @@ -1,64 +1,64 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( TRIANGLEAPIH ) -#define TRIANGLEAPIH -#ifdef _WIN32 -#pragma once -#endif - -typedef enum -{ - TRI_FRONT = 0, - TRI_NONE = 1, -} TRICULLSTYLE; - -#define TRI_API_VERSION 1 - -#define TRI_TRIANGLES 0 -#define TRI_TRIANGLE_FAN 1 -#define TRI_QUADS 2 -#define TRI_POLYGON 3 -#define TRI_LINES 4 -#define TRI_TRIANGLE_STRIP 5 -#define TRI_QUAD_STRIP 6 - -typedef struct triangleapi_s -{ - int version; - - void ( *RenderMode )( int mode ); - void ( *Begin )( int primitiveCode ); - void ( *End ) ( void ); - - void ( *Color4f ) ( float r, float g, float b, float a ); - void ( *Color4ub ) ( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); - void ( *TexCoord2f ) ( float u, float v ); - void ( *Vertex3fv ) ( float *worldPnt ); - void ( *Vertex3f ) ( float x, float y, float z ); - void ( *Brightness ) ( float brightness ); - void ( *CullFace ) ( TRICULLSTYLE style ); - int ( *SpriteTexture ) ( struct model_s *pSpriteModel, int frame ); - int ( *WorldToScreen ) ( float *world, float *screen ); // Returns 1 if it's z clipped - void ( *Fog ) ( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. - void ( *ScreenToWorld ) ( float *screen, float *world ); - void ( *GetMatrix ) ( const int pname, float *matrix ); - int ( *BoxInPVS ) ( float *mins, float *maxs ); - void ( *LightAtPoint ) ( float *pos, float *value ); - void ( *Color4fRendermode ) ( float r, float g, float b, float a, int rendermode ); - void ( *FogParams ) ( float flDensity, int iFogSkybox ); // Used with Fog()...sets fog density and whether the fog should be applied to the skybox - -} triangleapi_t; - -#endif // !TRIANGLEAPIH +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( TRIANGLEAPIH ) +#define TRIANGLEAPIH +#ifdef _WIN32 +#pragma once +#endif + +typedef enum +{ + TRI_FRONT = 0, + TRI_NONE = 1, +} TRICULLSTYLE; + +#define TRI_API_VERSION 1 + +#define TRI_TRIANGLES 0 +#define TRI_TRIANGLE_FAN 1 +#define TRI_QUADS 2 +#define TRI_POLYGON 3 +#define TRI_LINES 4 +#define TRI_TRIANGLE_STRIP 5 +#define TRI_QUAD_STRIP 6 + +typedef struct triangleapi_s +{ + int version; + + void ( *RenderMode )( int mode ); + void ( *Begin )( int primitiveCode ); + void ( *End ) ( void ); + + void ( *Color4f ) ( float r, float g, float b, float a ); + void ( *Color4ub ) ( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void ( *TexCoord2f ) ( float u, float v ); + void ( *Vertex3fv ) ( float *worldPnt ); + void ( *Vertex3f ) ( float x, float y, float z ); + void ( *Brightness ) ( float brightness ); + void ( *CullFace ) ( TRICULLSTYLE style ); + int ( *SpriteTexture ) ( struct model_s *pSpriteModel, int frame ); + int ( *WorldToScreen ) ( float *world, float *screen ); // Returns 1 if it's z clipped + void ( *Fog ) ( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. + void ( *ScreenToWorld ) ( float *screen, float *world ); + void ( *GetMatrix ) ( const int pname, float *matrix ); + int ( *BoxInPVS ) ( float *mins, float *maxs ); + void ( *LightAtPoint ) ( float *pos, float *value ); + void ( *Color4fRendermode ) ( float r, float g, float b, float a, int rendermode ); + void ( *FogParams ) ( float flDensity, int iFogSkybox ); // Used with Fog()...sets fog density and whether the fog should be applied to the skybox + +} triangleapi_t; + +#endif // !TRIANGLEAPIH diff --git a/main/source/common/usercmd.h b/main/source/common/usercmd.h index 5f9bf82a..f8bde446 100644 --- a/main/source/common/usercmd.h +++ b/main/source/common/usercmd.h @@ -1,41 +1,41 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef USERCMD_H -#define USERCMD_H -#ifdef _WIN32 -#pragma once -#endif - -typedef struct usercmd_s -{ - short lerp_msec; // Interpolation time on client - byte msec; // Duration in ms of command - vec3_t viewangles; // Command view angles. - -// intended velocities - float forwardmove; // Forward velocity. - float sidemove; // Sideways velocity. - float upmove; // Upward velocity. - byte lightlevel; // Light level at spot where we are standing. - unsigned short buttons; // Attack buttons - byte impulse; // Impulse command issued. - byte weaponselect; // Current weapon id - -// Experimental player impact stuff. - int impact_index; - vec3_t impact_position; -} usercmd_t; - -#endif // USERCMD_H +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef USERCMD_H +#define USERCMD_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct usercmd_s +{ + short lerp_msec; // Interpolation time on client + byte msec; // Duration in ms of command + vec3_t viewangles; // Command view angles. + +// intended velocities + float forwardmove; // Forward velocity. + float sidemove; // Sideways velocity. + float upmove; // Upward velocity. + byte lightlevel; // Light level at spot where we are standing. + unsigned short buttons; // Attack buttons + byte impulse; // Impulse command issued. + byte weaponselect; // Current weapon id + +// Experimental player impact stuff. + int impact_index; + vec3_t impact_position; +} usercmd_t; + +#endif // USERCMD_H diff --git a/main/source/common/vec_op.h b/main/source/common/vec_op.h index 1090c923..c0025d86 100644 --- a/main/source/common/vec_op.h +++ b/main/source/common/vec_op.h @@ -1,10 +1,10 @@ -#ifndef VECOP_H -#define VECOP_H - -#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) -#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} -#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} -#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} -#define VectorClear(a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} - +#ifndef VECOP_H +#define VECOP_H + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +#define VectorClear(a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} + #endif \ No newline at end of file diff --git a/main/source/common/vector_util.h b/main/source/common/vector_util.h index f8808fa2..645ced31 100644 --- a/main/source/common/vector_util.h +++ b/main/source/common/vector_util.h @@ -1,14 +1,14 @@ -#ifndef VECTOR_UTIL_H -#define VECTOR_UTIL_H - -#include "vec_op.h" - -float Length(const float *v); -void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); -void VectorScale (const float *in, float scale, float *out); -float VectorNormalize (float *v); -void VectorInverse ( float *v ); - -extern vec3_t vec3_origin; - +#ifndef VECTOR_UTIL_H +#define VECTOR_UTIL_H + +#include "vec_op.h" + +float Length(const float *v); +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); +void VectorScale (const float *in, float scale, float *out); +float VectorNormalize (float *v); +void VectorInverse ( float *v ); + +extern vec3_t vec3_origin; + #endif \ No newline at end of file diff --git a/main/source/common/vector_util.h~ b/main/source/common/vector_util.h~ deleted file mode 100644 index 0a649950..00000000 --- a/main/source/common/vector_util.h~ +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef VECTOR_UTIL_H -#define VECTOR_UTIL_H - -#include "common/vec_op.h" - -float Length(const float *v); -void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); -void VectorScale (const float *in, float scale, float *out); -float VectorNormalize (float *v); -void VectorInverse ( float *v ); - -extern vec3_t vec3_origin; - -#endif \ No newline at end of file diff --git a/main/source/common/vectorclasses.h b/main/source/common/vectorclasses.h index c5b2f115..8c3e26f0 100644 --- a/main/source/common/vectorclasses.h +++ b/main/source/common/vectorclasses.h @@ -1,97 +1,97 @@ -#ifndef VECTORCLASSES_H -#define VECTORCLASSES_H - -//========================================================= -// 2DVector - used for many pathfinding and many other -// operations that are treated as planar rather than 3d. -//========================================================= -class Vector2D -{ -public: - inline Vector2D(void) { } - inline Vector2D(float X, float Y) { x = X; y = Y; } - inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); } - inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); } - inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); } - inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); } - - inline float Length(void) const { return (float)sqrt(x*x + y*y ); } - - inline Vector2D Normalize ( void ) const - { - Vector2D vec2; - - float flLen = Length(); - if ( flLen == 0 ) - { - return Vector2D( (float)0, (float)0 ); - } - else - { - flLen = 1 / flLen; - return Vector2D( x * flLen, y * flLen ); - } - } - - vec_t x, y; -}; - -inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); } -inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; } - -//========================================================= -// 3D Vector -//========================================================= -class Vector // same data-layout as engine's vec3_t, -{ // which is a vec_t[3] -public: - // Construction/destruction - inline Vector(void) { } - inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; } - inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; } - inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; } - inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; } - inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } - - // Operators - inline Vector operator-(void) const { return Vector(-x,-y,-z); } - inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; } - inline int operator!=(const Vector& v) const { return !(*this==v); } - inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); } - inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); } - inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); } - inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); } - - // Methods - inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } - inline float Length(void) const { return (float)sqrt(x*x + y*y + z*z); } - operator float *() { return &x; } // Vectors will now automatically convert to float * when needed - operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed - inline Vector Normalize(void) const - { - float flLen = Length(); - if (flLen == 0) return Vector(0,0,1); // ???? - flLen = 1 / flLen; - return Vector(x * flLen, y * flLen, z * flLen); - } - - inline Vector2D Make2D ( void ) const - { - Vector2D Vec2; - - Vec2.x = x; - Vec2.y = y; - - return Vec2; - } - inline float Length2D(void) const { return (float)sqrt(x*x + y*y); } - - // Members - vec_t x, y, z; -}; - -inline Vector operator*(float fl, const Vector& v) { return v * fl; } -inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); } -inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); } - +#ifndef VECTORCLASSES_H +#define VECTORCLASSES_H + +//========================================================= +// 2DVector - used for many pathfinding and many other +// operations that are treated as planar rather than 3d. +//========================================================= +class Vector2D +{ +public: + inline Vector2D(void) { } + inline Vector2D(float X, float Y) { x = X; y = Y; } + inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); } + inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); } + inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); } + inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); } + + inline float Length(void) const { return (float)sqrt(x*x + y*y ); } + + inline Vector2D Normalize ( void ) const + { + Vector2D vec2; + + float flLen = Length(); + if ( flLen == 0 ) + { + return Vector2D( (float)0, (float)0 ); + } + else + { + flLen = 1 / flLen; + return Vector2D( x * flLen, y * flLen ); + } + } + + vec_t x, y; +}; + +inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); } +inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; } + +//========================================================= +// 3D Vector +//========================================================= +class Vector // same data-layout as engine's vec3_t, +{ // which is a vec_t[3] +public: + // Construction/destruction + inline Vector(void) { } + inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; } + inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; } + inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; } + inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } + + // Operators + inline Vector operator-(void) const { return Vector(-x,-y,-z); } + inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; } + inline int operator!=(const Vector& v) const { return !(*this==v); } + inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); } + inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); } + inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); } + inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); } + + // Methods + inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } + inline float Length(void) const { return (float)sqrt(x*x + y*y + z*z); } + operator float *() { return &x; } // Vectors will now automatically convert to float * when needed + operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed + inline Vector Normalize(void) const + { + float flLen = Length(); + if (flLen == 0) return Vector(0,0,1); // ???? + flLen = 1 / flLen; + return Vector(x * flLen, y * flLen, z * flLen); + } + + inline Vector2D Make2D ( void ) const + { + Vector2D Vec2; + + Vec2.x = x; + Vec2.y = y; + + return Vec2; + } + inline float Length2D(void) const { return (float)sqrt(x*x + y*y); } + + // Members + vec_t x, y, z; +}; + +inline Vector operator*(float fl, const Vector& v) { return v * fl; } +inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); } +inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); } + #endif \ No newline at end of file diff --git a/main/source/common/weaponinfo.h b/main/source/common/weaponinfo.h index 39ee1935..27fb0169 100644 --- a/main/source/common/weaponinfo.h +++ b/main/source/common/weaponinfo.h @@ -1,52 +1,52 @@ -/*** -* -* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined ( WEAPONINFOH ) -#define WEAPONINFOH -#ifdef _WIN32 -#pragma once -#endif - -// Info about weapons player might have in his/her possession -typedef struct weapon_data_s -{ - int m_iId; - int m_iClip; - - float m_flNextPrimaryAttack; - float m_flNextSecondaryAttack; - float m_flTimeWeaponIdle; - - int m_fInReload; - int m_fInSpecialReload; - float m_flNextReload; - float m_flPumpTime; - float m_fReloadTime; - - float m_fAimedDamage; - float m_fNextAimBonus; - int m_fInZoom; - int m_iWeaponState; - - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; -} weapon_data_t; - -#endif +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( WEAPONINFOH ) +#define WEAPONINFOH +#ifdef _WIN32 +#pragma once +#endif + +// Info about weapons player might have in his/her possession +typedef struct weapon_data_s +{ + int m_iId; + int m_iClip; + + float m_flNextPrimaryAttack; + float m_flNextSecondaryAttack; + float m_flTimeWeaponIdle; + + int m_fInReload; + int m_fInSpecialReload; + float m_flNextReload; + float m_flPumpTime; + float m_fReloadTime; + + float m_fAimedDamage; + float m_fNextAimBonus; + int m_fInZoom; + int m_iWeaponState; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; +} weapon_data_t; + +#endif diff --git a/main/source/dlls/AI_BaseNPC_Schedule.cpp b/main/source/dlls/AI_BaseNPC_Schedule.cpp index 2b6058e4..f9ff6db4 100644 --- a/main/source/dlls/AI_BaseNPC_Schedule.cpp +++ b/main/source/dlls/AI_BaseNPC_Schedule.cpp @@ -1,1514 +1,1514 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// schedule.cpp - functions and data pertaining to the -// monsters' AI scheduling system. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "scripted.h" -#include "nodes.h" -#include "defaultai.h" -#include "soundent.h" - -extern CGraph WorldGraph; - -//========================================================= -// FHaveSchedule - Returns TRUE if monster's m_pSchedule -// is anything other than NULL. -//========================================================= -BOOL CBaseMonster :: FHaveSchedule( void ) -{ - if ( m_pSchedule == NULL ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// ClearSchedule - blanks out the caller's schedule pointer -// and index. -//========================================================= -void CBaseMonster :: ClearSchedule( void ) -{ - m_iTaskStatus = TASKSTATUS_NEW; - m_pSchedule = NULL; - m_iScheduleIndex = 0; -} - -//========================================================= -// FScheduleDone - Returns TRUE if the caller is on the -// last task in the schedule -//========================================================= -BOOL CBaseMonster :: FScheduleDone ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - if ( m_iScheduleIndex == m_pSchedule->cTasks ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// ChangeSchedule - replaces the monster's schedule pointer -// with the passed pointer, and sets the ScheduleIndex back -// to 0 -//========================================================= -void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) -{ - ASSERT( pNewSchedule != NULL ); - - m_pSchedule = pNewSchedule; - m_iScheduleIndex = 0; - m_iTaskStatus = TASKSTATUS_NEW; - m_afConditions = 0;// clear all of the conditions - m_failSchedule = SCHED_NONE; - - if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) - { - ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); - } - else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) - { - ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); - } - -#if _DEBUG - if ( !ScheduleFromName( pNewSchedule->pName ) ) - { - ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); - } -#endif - -// this is very useful code if you can isolate a test case in a level with a single monster. It will notify -// you of every schedule selection the monster makes. -#if 0 - if ( FClassnameIs( pev, "monster_human_grunt" ) ) - { - Task_t *pTask = GetTask(); - - if ( pTask ) - { - const char *pName = NULL; - - if ( m_pSchedule ) - { - pName = m_pSchedule->pName; - } - else - { - pName = "No Schedule"; - } - - if ( !pName ) - { - pName = "Unknown"; - } - - ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); - } - } -#endif// 0 - -} - -//========================================================= -// NextScheduledTask - increments the ScheduleIndex -//========================================================= -void CBaseMonster :: NextScheduledTask ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - m_iTaskStatus = TASKSTATUS_NEW; - m_iScheduleIndex++; - - if ( FScheduleDone() ) - { - // just completed last task in schedule, so make it invalid by clearing it. - SetConditions( bits_COND_SCHEDULE_DONE ); - //ClearSchedule(); - } -} - -//========================================================= -// IScheduleFlags - returns an integer with all Conditions -// bits that are currently set and also set in the current -// schedule's Interrupt mask. -//========================================================= -int CBaseMonster :: IScheduleFlags ( void ) -{ - if( !m_pSchedule ) - { - return 0; - } - - // strip off all bits excepts the ones capable of breaking this schedule. - return m_afConditions & m_pSchedule->iInterruptMask; -} - -//========================================================= -// FScheduleValid - returns TRUE as long as the current -// schedule is still the proper schedule to be executing, -// taking into account all conditions -//========================================================= -BOOL CBaseMonster :: FScheduleValid ( void ) -{ - if ( m_pSchedule == NULL ) - { - // schedule is empty, and therefore not valid. - return FALSE; - } - - if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) - { -#ifdef DEBUG - if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) - { - // fail! Send a visual indicator. - ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); - - Vector tmp = pev->origin; - tmp.z = pev->absmax.z + 16; - UTIL_Sparks( tmp ); - } -#endif // DEBUG - - // some condition has interrupted the schedule, or the schedule is done - return FALSE; - } - - return TRUE; -} - -//========================================================= -// MaintainSchedule - does all the per-think schedule maintenance. -// ensures that the monster leaves this function with a valid -// schedule! -//========================================================= -void CBaseMonster :: MaintainSchedule ( void ) -{ - Schedule_t *pNewSchedule; - int i; - - // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible - for ( i = 0; i < 10; i++ ) - { - if ( m_pSchedule != NULL && TaskIsComplete() ) - { - NextScheduledTask(); - } - - // validate existing schedule - if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) - { - // if we come into this block of code, the schedule is going to have to be changed. - // if the previous schedule was interrupted by a condition, GetIdealState will be - // called. Else, a schedule finished normally. - - // Notify the monster that his schedule is changing - ScheduleChange(); - - // Call GetIdealState if we're not dead and one or more of the following... - // - in COMBAT state with no enemy (it died?) - // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, - // - schedule is done but schedule indicates it wants GetIdealState called - // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) - // DEAD & SCRIPT are not suggestions, they are commands! - if ( m_IdealMonsterState != MONSTERSTATE_DEAD && - (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) - { - if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || - (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || - ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == NULL)) ) - { - GetIdealState(); - } - } - if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) - { - if ( m_failSchedule != SCHED_NONE ) - pNewSchedule = GetScheduleOfType( m_failSchedule ); - else - pNewSchedule = GetScheduleOfType( SCHED_FAIL ); - // schedule was invalid because the current task failed to start or complete - ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); - ChangeSchedule( pNewSchedule ); - } - else - { - SetState( m_IdealMonsterState ); - if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) - pNewSchedule = CBaseMonster::GetSchedule(); - else - pNewSchedule = GetSchedule(); - ChangeSchedule( pNewSchedule ); - } - } - - if ( m_iTaskStatus == TASKSTATUS_NEW ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - TaskBegin(); - StartTask( pTask ); - } - - // UNDONE: Twice?!!! - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - - if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) - break; - } - - if ( TaskIsRunning() ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - RunTask( pTask ); - } - - // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation - // RunTask() will always change animations at the end of a script! - // Don't do this twice - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } -} - -//========================================================= -// RunTask -//========================================================= -void CBaseMonster :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - case TASK_TURN_LEFT: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - { - CBaseEntity *pTarget; - - if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) - pTarget = m_hTargetEnt; - else - pTarget = m_hEnemy; - if ( pTarget ) - { - pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - if ( m_fSequenceFinished ) - TaskComplete(); - } - break; - - case TASK_PLAY_SEQUENCE: - case TASK_PLAY_ACTIVE_IDLE: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - - - case TASK_FACE_ENEMY: - { - MakeIdealYaw( m_vecEnemyLKP ); - - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_FACE_HINTNODE: - case TASK_FACE_LASTPOSITION: - case TASK_FACE_TARGET: - case TASK_FACE_IDEAL: - case TASK_FACE_ROUTE: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_PVS: - { - if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_RANDOM: - { - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - float distance; - - if ( m_hTargetEnt == NULL ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK ) - m_movementActivity = ACT_WALK; - else if ( distance >= 270 && m_movementActivity != ACT_RUN ) - m_movementActivity = ACT_RUN; - } - - break; - } - case TASK_WAIT_FOR_MOVEMENT: - { - if (MovementIsComplete()) - { - TaskComplete(); - RouteClear(); // Stop moving - } - break; - } - case TASK_DIE: - { - if ( m_fSequenceFinished && pev->frame >= 255 ) - { - pev->deadflag = DEAD_DEAD; - - SetThink ( NULL ); - StopAnimation(); - - if ( !BBoxFlat() ) - { - // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will - // block the player on a slope or stairs, the corpse is made nonsolid. -// pev->solid = SOLID_NOT; - UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); - } - else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem - UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); - - if ( ShouldFadeOnDeath() ) - { - // this monster was created by a monstermaker... fade the corpse out. - SUB_StartFadeOut(); - } - else - { - // body is gonna be around for a while, so have it stink for a bit. - CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); - } - } - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RELOAD_NOTURN: - { - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_RANGE_ATTACK1: - case TASK_MELEE_ATTACK1: - case TASK_MELEE_ATTACK2: - case TASK_RANGE_ATTACK2: - case TASK_SPECIAL_ATTACK1: - case TASK_SPECIAL_ATTACK2: - case TASK_RELOAD: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_SMALL_FLINCH: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - } - break; - case TASK_WAIT_FOR_SCRIPT: - { - if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) - { - TaskComplete(); - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); - if ( m_fSequenceFinished ) - ClearSchedule(); - pev->framerate = 1.0; - //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - } - break; - } - case TASK_PLAY_SCRIPT: - { - if (m_fSequenceFinished) - { - m_pCine->SequenceDone( this ); - } - break; - } - } -} - -//========================================================= -// SetTurnActivity - measures the difference between the way -// the monster is facing and determines whether or not to -// select one of the 180 turn animations. -//========================================================= -void CBaseMonster :: SetTurnActivity ( void ) -{ - float flYD; - flYD = FlYawDiff(); - - if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) - {// big right turn - m_IdealActivity = ACT_TURN_RIGHT; - } - else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) - {// big left turn - m_IdealActivity = ACT_TURN_LEFT; - } -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CBaseMonster :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_TURN_LEFT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_REMEMBER: - { - Remember ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FORGET: - { - Forget ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FIND_HINTNODE: - { - m_iHintNode = FindHintNode(); - - if ( m_iHintNode != NO_NODE ) - { - TaskComplete(); - } - else - { - TaskFail(); - } - break; - } - case TASK_STORE_LASTPOSITION: - { - m_vecLastPosition = pev->origin; - TaskComplete(); - break; - } - case TASK_CLEAR_LASTPOSITION: - { - m_vecLastPosition = g_vecZero; - TaskComplete(); - break; - } - case TASK_CLEAR_HINTNODE: - { - m_iHintNode = NO_NODE; - TaskComplete(); - break; - } - case TASK_STOP_MOVING: - { - if ( m_IdealActivity == m_movementActivity ) - { - m_IdealActivity = GetStoppedActivity(); - } - - RouteClear(); - TaskComplete(); - break; - } - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - case TASK_PLAY_SEQUENCE: - { - m_IdealActivity = ( Activity )( int )pTask->flData; - break; - } - case TASK_PLAY_ACTIVE_IDLE: - { - // monsters verify that they have a sequence for the node's activity BEFORE - // moving towards the node, so it's ok to just set the activity without checking here. - m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; - break; - } - case TASK_SET_SCHEDULE: - { - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( (int)pTask->flData ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } - else - { - TaskFail(); - } - - break; - } - case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ENEMY: - { - entvars_t *pevCover; - - if ( m_hEnemy == NULL ) - { - // Find cover from self if no enemy available - pevCover = pev; -// TaskFail(); -// return; - } - else - pevCover = m_hEnemy->pev; - - if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ORIGIN: - { - if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no cover! - TaskFail(); - } - } - break; - case TASK_FIND_COVER_FROM_BEST_SOUND: - { - CSound *pBestSound; - - pBestSound = PBestSound(); - - ASSERT( pBestSound != NULL ); - /* - if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - */ - - if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. or no sound in list - TaskFail(); - } - break; - } - case TASK_FACE_HINTNODE: - { - pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; - SetTurnActivity(); - break; - } - - case TASK_FACE_LASTPOSITION: - MakeIdealYaw ( m_vecLastPosition ); - SetTurnActivity(); - break; - - case TASK_FACE_TARGET: - if ( m_hTargetEnt != NULL ) - { - MakeIdealYaw ( m_hTargetEnt->pev->origin ); - SetTurnActivity(); - } - else - TaskFail(); - break; - case TASK_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - SetTurnActivity(); - break; - } - case TASK_FACE_IDEAL: - { - SetTurnActivity(); - break; - } - case TASK_FACE_ROUTE: - { - if (FRouteClear()) - { - ALERT(at_aiconsole, "No route to face!\n"); - TaskFail(); - } - else - { - MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); - SetTurnActivity(); - } - break; - } - case TASK_WAIT_PVS: - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - } - case TASK_WAIT_RANDOM: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK, 2 ) ) - TaskFail(); - } - break; - } - case TASK_RUN_TO_TARGET: - case TASK_WALK_TO_TARGET: - { - Activity newActivity; - - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - if ( pTask->iTask == TASK_WALK_TO_TARGET ) - newActivity = ACT_WALK; - else - newActivity = ACT_RUN; - // This monster can't do this! - if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) - TaskComplete(); - else - { - if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); - RouteClear(); - } - } - } - TaskComplete(); - break; - } - case TASK_CLEAR_MOVE_WAIT: - { - m_flMoveWaitFinished = gpGlobals->time; - TaskComplete(); - break; - } - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1: - { - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - } - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_MELEE_ATTACK2: - { - m_IdealActivity = ACT_MELEE_ATTACK2; - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2: - { - m_IdealActivity = ACT_RANGE_ATTACK2; - break; - } - case TASK_RELOAD_NOTURN: - case TASK_RELOAD: - { - m_IdealActivity = ACT_RELOAD; - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_SPECIAL_ATTACK2: - { - m_IdealActivity = ACT_SPECIAL_ATTACK2; - break; - } - case TASK_SET_ACTIVITY: - { - m_IdealActivity = (Activity)(int)pTask->flData; - TaskComplete(); - break; - } - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - case TASK_GET_PATH_TO_SPOT: - { - CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); - if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - - case TASK_GET_PATH_TO_TARGET: - { - RouteClear(); - if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_HINTNODE:// for active idles! - { - if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_LASTPOSITION: - { - m_vecMoveGoal = m_vecLastPosition; - - if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_BESTSOUND: - { - CSound *pSound; - - pSound = PBestSound(); - - if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); - TaskFail(); - } - break; - } -case TASK_GET_PATH_TO_BESTSCENT: - { - CSound *pScent; - - pScent = PBestScent(); - - if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); - - TaskFail(); - } - break; - } - case TASK_RUN_PATH: - { - // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? - if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_RUN; - } - else - { - m_movementActivity = ACT_WALK; - } - TaskComplete(); - break; - } - case TASK_WALK_PATH: - { - if ( pev->movetype == MOVETYPE_FLY ) - { - m_movementActivity = ACT_FLY; - } - if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_WALK; - } - else - { - m_movementActivity = ACT_RUN; - } - TaskComplete(); - break; - } - case TASK_STRAFE_PATH: - { - Vector2D vec2DirToPoint; - Vector2D vec2RightSide; - - // to start strafing, we have to first figure out if the target is on the left side or right side - UTIL_MakeVectors ( pev->angles ); - - vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); - vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); - - if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) - { - // strafe right - m_movementActivity = ACT_STRAFE_RIGHT; - } - else - { - // strafe left - m_movementActivity = ACT_STRAFE_LEFT; - } - TaskComplete(); - break; - } - - - case TASK_WAIT_FOR_MOVEMENT: - { - if (FRouteClear()) - { - TaskComplete(); - } - break; - } - - case TASK_EAT: - { - Eat( pTask->flData ); - TaskComplete(); - break; - } - case TASK_SMALL_FLINCH: - { - m_IdealActivity = GetSmallFlinchActivity(); - break; - } - case TASK_DIE: - { - RouteClear(); - - m_IdealActivity = GetDeathActivity(); - - pev->deadflag = DEAD_DYING; - break; - } - case TASK_SOUND_WAKE: - { - AlertSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DIE: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_IDLE: - { - IdleSound(); - TaskComplete(); - break; - } - case TASK_SOUND_PAIN: - { - PainSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DEATH: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_ANGRY: - { - // sounds are complete as soon as we get here, cause we've already played them. - ALERT ( at_aiconsole, "SOUND\n" ); - TaskComplete(); - break; - } - case TASK_WAIT_FOR_SCRIPT: - { - if (m_pCine->m_iszIdle) - { - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); - if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) - { - pev->framerate = 0; - } - } - else - m_IdealActivity = ACT_IDLE; - - break; - } - case TASK_PLAY_SCRIPT: - { - pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); - m_scriptState = SCRIPT_PLAYING; - break; - } - case TASK_ENABLE_SCRIPT: - { - m_pCine->DelayStart( 0 ); - TaskComplete(); - break; - } - case TASK_PLANT_ON_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->origin = m_hTargetEnt->pev->origin; // Plant on target - } - - TaskComplete(); - break; - } - case TASK_FACE_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); - } - - TaskComplete(); - m_IdealActivity = ACT_IDLE; - RouteClear(); - break; - } - - case TASK_SUGGEST_STATE: - { - m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; - TaskComplete(); - break; - } - - case TASK_SET_FAIL_SCHEDULE: - m_failSchedule = (int)pTask->flData; - TaskComplete(); - break; - - case TASK_CLEAR_FAIL_SCHEDULE: - m_failSchedule = SCHED_NONE; - TaskComplete(); - break; - - default: - { - ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); - break; - } - } -} - -//========================================================= -// GetTask - returns a pointer to the current -// scheduled task. NULL if there's a problem. -//========================================================= -Task_t *CBaseMonster :: GetTask ( void ) -{ - if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) - { - // m_iScheduleIndex is not within valid range for the monster's current schedule. - return NULL; - } - else - { - return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CBaseMonster :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_PRONE: - { - return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); - break; - } - case MONSTERSTATE_NONE: - { - ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); - break; - } - case MONSTERSTATE_IDLE: - { - if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else if ( FRouteClear() ) - { - // no valid route! - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - else - { - // valid route. Get moving - return GetScheduleOfType( SCHED_IDLE_WALK ); - } - break; - } - case MONSTERSTATE_ALERT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) - { - return GetScheduleOfType ( SCHED_VICTORY_DANCE ); - } - - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) - { - if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); - } - } - - else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_STAND ); - } - break; - } - case MONSTERSTATE_COMBAT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // clear the current (dead) enemy and try to find another. - m_hEnemy = NULL; - - if ( GetEnemy() ) - { - ClearConditions( bits_COND_ENEMY_DEAD ); - return GetSchedule(); - } - else - { - SetState( MONSTERSTATE_ALERT ); - return GetSchedule(); - } - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); - } - else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - else if ( !HasConditions(bits_COND_SEE_ENEMY) ) - { - // we can't see the enemy - if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) - { - // enemy is unseen, but not occluded! - // turn to face enemy - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - // chase! - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - } - else - { - // we can see the enemy - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); - } - if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) - { - // if we can see enemy but can't use either attack type, we must need to get closer to enemy - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - else if ( !FacingIdeal() ) - { - //turn - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); - } - } - break; - } - case MONSTERSTATE_DEAD: - { - return GetScheduleOfType( SCHED_DIE ); - break; - } - case MONSTERSTATE_SCRIPT: - { - ASSERT( m_pCine != NULL ); - if ( !m_pCine ) - { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - - return GetScheduleOfType( SCHED_AISCRIPT ); - } - default: - { - ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); - break; - } - } - - return &slError[ 0 ]; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// schedule.cpp - functions and data pertaining to the +// monsters' AI scheduling system. +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "animation.h" +#include "scripted.h" +#include "nodes.h" +#include "defaultai.h" +#include "soundent.h" + +extern CGraph WorldGraph; + +//========================================================= +// FHaveSchedule - Returns TRUE if monster's m_pSchedule +// is anything other than NULL. +//========================================================= +BOOL CBaseMonster :: FHaveSchedule( void ) +{ + if ( m_pSchedule == NULL ) + { + return FALSE; + } + + return TRUE; +} + +//========================================================= +// ClearSchedule - blanks out the caller's schedule pointer +// and index. +//========================================================= +void CBaseMonster :: ClearSchedule( void ) +{ + m_iTaskStatus = TASKSTATUS_NEW; + m_pSchedule = NULL; + m_iScheduleIndex = 0; +} + +//========================================================= +// FScheduleDone - Returns TRUE if the caller is on the +// last task in the schedule +//========================================================= +BOOL CBaseMonster :: FScheduleDone ( void ) +{ + ASSERT( m_pSchedule != NULL ); + + if ( m_iScheduleIndex == m_pSchedule->cTasks ) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// ChangeSchedule - replaces the monster's schedule pointer +// with the passed pointer, and sets the ScheduleIndex back +// to 0 +//========================================================= +void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) +{ + ASSERT( pNewSchedule != NULL ); + + m_pSchedule = pNewSchedule; + m_iScheduleIndex = 0; + m_iTaskStatus = TASKSTATUS_NEW; + m_afConditions = 0;// clear all of the conditions + m_failSchedule = SCHED_NONE; + + if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) + { + ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); + } + else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) + { + ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); + } + +#if _DEBUG + if ( !ScheduleFromName( pNewSchedule->pName ) ) + { + ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); + } +#endif + +// this is very useful code if you can isolate a test case in a level with a single monster. It will notify +// you of every schedule selection the monster makes. +#if 0 + if ( FClassnameIs( pev, "monster_human_grunt" ) ) + { + Task_t *pTask = GetTask(); + + if ( pTask ) + { + const char *pName = NULL; + + if ( m_pSchedule ) + { + pName = m_pSchedule->pName; + } + else + { + pName = "No Schedule"; + } + + if ( !pName ) + { + pName = "Unknown"; + } + + ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); + } + } +#endif// 0 + +} + +//========================================================= +// NextScheduledTask - increments the ScheduleIndex +//========================================================= +void CBaseMonster :: NextScheduledTask ( void ) +{ + ASSERT( m_pSchedule != NULL ); + + m_iTaskStatus = TASKSTATUS_NEW; + m_iScheduleIndex++; + + if ( FScheduleDone() ) + { + // just completed last task in schedule, so make it invalid by clearing it. + SetConditions( bits_COND_SCHEDULE_DONE ); + //ClearSchedule(); + } +} + +//========================================================= +// IScheduleFlags - returns an integer with all Conditions +// bits that are currently set and also set in the current +// schedule's Interrupt mask. +//========================================================= +int CBaseMonster :: IScheduleFlags ( void ) +{ + if( !m_pSchedule ) + { + return 0; + } + + // strip off all bits excepts the ones capable of breaking this schedule. + return m_afConditions & m_pSchedule->iInterruptMask; +} + +//========================================================= +// FScheduleValid - returns TRUE as long as the current +// schedule is still the proper schedule to be executing, +// taking into account all conditions +//========================================================= +BOOL CBaseMonster :: FScheduleValid ( void ) +{ + if ( m_pSchedule == NULL ) + { + // schedule is empty, and therefore not valid. + return FALSE; + } + + if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) + { +#ifdef DEBUG + if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) + { + // fail! Send a visual indicator. + ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); + + Vector tmp = pev->origin; + tmp.z = pev->absmax.z + 16; + UTIL_Sparks( tmp ); + } +#endif // DEBUG + + // some condition has interrupted the schedule, or the schedule is done + return FALSE; + } + + return TRUE; +} + +//========================================================= +// MaintainSchedule - does all the per-think schedule maintenance. +// ensures that the monster leaves this function with a valid +// schedule! +//========================================================= +void CBaseMonster :: MaintainSchedule ( void ) +{ + Schedule_t *pNewSchedule; + int i; + + // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible + for ( i = 0; i < 10; i++ ) + { + if ( m_pSchedule != NULL && TaskIsComplete() ) + { + NextScheduledTask(); + } + + // validate existing schedule + if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) + { + // if we come into this block of code, the schedule is going to have to be changed. + // if the previous schedule was interrupted by a condition, GetIdealState will be + // called. Else, a schedule finished normally. + + // Notify the monster that his schedule is changing + ScheduleChange(); + + // Call GetIdealState if we're not dead and one or more of the following... + // - in COMBAT state with no enemy (it died?) + // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, + // - schedule is done but schedule indicates it wants GetIdealState called + // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) + // DEAD & SCRIPT are not suggestions, they are commands! + if ( m_IdealMonsterState != MONSTERSTATE_DEAD && + (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) + { + if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || + (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || + ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == NULL)) ) + { + GetIdealState(); + } + } + if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) + { + if ( m_failSchedule != SCHED_NONE ) + pNewSchedule = GetScheduleOfType( m_failSchedule ); + else + pNewSchedule = GetScheduleOfType( SCHED_FAIL ); + // schedule was invalid because the current task failed to start or complete + ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); + ChangeSchedule( pNewSchedule ); + } + else + { + SetState( m_IdealMonsterState ); + if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) + pNewSchedule = CBaseMonster::GetSchedule(); + else + pNewSchedule = GetSchedule(); + ChangeSchedule( pNewSchedule ); + } + } + + if ( m_iTaskStatus == TASKSTATUS_NEW ) + { + Task_t *pTask = GetTask(); + ASSERT( pTask != NULL ); + TaskBegin(); + StartTask( pTask ); + } + + // UNDONE: Twice?!!! + if ( m_Activity != m_IdealActivity ) + { + SetActivity ( m_IdealActivity ); + } + + if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) + break; + } + + if ( TaskIsRunning() ) + { + Task_t *pTask = GetTask(); + ASSERT( pTask != NULL ); + RunTask( pTask ); + } + + // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation + // RunTask() will always change animations at the end of a script! + // Don't do this twice + if ( m_Activity != m_IdealActivity ) + { + SetActivity ( m_IdealActivity ); + } +} + +//========================================================= +// RunTask +//========================================================= +void CBaseMonster :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_TURN_RIGHT: + case TASK_TURN_LEFT: + { + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + TaskComplete(); + } + break; + } + + case TASK_PLAY_SEQUENCE_FACE_ENEMY: + case TASK_PLAY_SEQUENCE_FACE_TARGET: + { + CBaseEntity *pTarget; + + if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) + pTarget = m_hTargetEnt; + else + pTarget = m_hEnemy; + if ( pTarget ) + { + pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); + ChangeYaw( pev->yaw_speed ); + } + if ( m_fSequenceFinished ) + TaskComplete(); + } + break; + + case TASK_PLAY_SEQUENCE: + case TASK_PLAY_ACTIVE_IDLE: + { + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + break; + } + + + case TASK_FACE_ENEMY: + { + MakeIdealYaw( m_vecEnemyLKP ); + + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + TaskComplete(); + } + break; + } + case TASK_FACE_HINTNODE: + case TASK_FACE_LASTPOSITION: + case TASK_FACE_TARGET: + case TASK_FACE_IDEAL: + case TASK_FACE_ROUTE: + { + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + TaskComplete(); + } + break; + } + case TASK_WAIT_PVS: + { + if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) + { + TaskComplete(); + } + break; + } + case TASK_WAIT_INDEFINITE: + { + // don't do anything. + break; + } + case TASK_WAIT: + case TASK_WAIT_RANDOM: + { + if ( gpGlobals->time >= m_flWaitFinished ) + { + TaskComplete(); + } + break; + } + case TASK_WAIT_FACE_ENEMY: + { + MakeIdealYaw ( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); + + if ( gpGlobals->time >= m_flWaitFinished ) + { + TaskComplete(); + } + break; + } + case TASK_MOVE_TO_TARGET_RANGE: + { + float distance; + + if ( m_hTargetEnt == NULL ) + TaskFail(); + else + { + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + // Re-evaluate when you think your finished, or the target has moved too far + if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) + { + m_vecMoveGoal = m_hTargetEnt->pev->origin; + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + FRefreshRoute(); + } + + // Set the appropriate activity based on an overlapping range + // overlap the range to prevent oscillation + if ( distance < pTask->flData ) + { + TaskComplete(); + RouteClear(); // Stop moving + } + else if ( distance < 190 && m_movementActivity != ACT_WALK ) + m_movementActivity = ACT_WALK; + else if ( distance >= 270 && m_movementActivity != ACT_RUN ) + m_movementActivity = ACT_RUN; + } + + break; + } + case TASK_WAIT_FOR_MOVEMENT: + { + if (MovementIsComplete()) + { + TaskComplete(); + RouteClear(); // Stop moving + } + break; + } + case TASK_DIE: + { + if ( m_fSequenceFinished && pev->frame >= 255 ) + { + pev->deadflag = DEAD_DEAD; + + SetThink ( NULL ); + StopAnimation(); + + if ( !BBoxFlat() ) + { + // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will + // block the player on a slope or stairs, the corpse is made nonsolid. +// pev->solid = SOLID_NOT; + UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); + } + else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem + UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); + + if ( ShouldFadeOnDeath() ) + { + // this monster was created by a monstermaker... fade the corpse out. + SUB_StartFadeOut(); + } + else + { + // body is gonna be around for a while, so have it stink for a bit. + CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); + } + } + break; + } + case TASK_RANGE_ATTACK1_NOTURN: + case TASK_MELEE_ATTACK1_NOTURN: + case TASK_MELEE_ATTACK2_NOTURN: + case TASK_RANGE_ATTACK2_NOTURN: + case TASK_RELOAD_NOTURN: + { + if ( m_fSequenceFinished ) + { + m_Activity = ACT_RESET; + TaskComplete(); + } + break; + } + case TASK_RANGE_ATTACK1: + case TASK_MELEE_ATTACK1: + case TASK_MELEE_ATTACK2: + case TASK_RANGE_ATTACK2: + case TASK_SPECIAL_ATTACK1: + case TASK_SPECIAL_ATTACK2: + case TASK_RELOAD: + { + MakeIdealYaw ( m_vecEnemyLKP ); + ChangeYaw ( pev->yaw_speed ); + + if ( m_fSequenceFinished ) + { + m_Activity = ACT_RESET; + TaskComplete(); + } + break; + } + case TASK_SMALL_FLINCH: + { + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + } + break; + case TASK_WAIT_FOR_SCRIPT: + { + if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) + { + TaskComplete(); + m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); + if ( m_fSequenceFinished ) + ClearSchedule(); + pev->framerate = 1.0; + //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); + } + break; + } + case TASK_PLAY_SCRIPT: + { + if (m_fSequenceFinished) + { + m_pCine->SequenceDone( this ); + } + break; + } + } +} + +//========================================================= +// SetTurnActivity - measures the difference between the way +// the monster is facing and determines whether or not to +// select one of the 180 turn animations. +//========================================================= +void CBaseMonster :: SetTurnActivity ( void ) +{ + float flYD; + flYD = FlYawDiff(); + + if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) + {// big right turn + m_IdealActivity = ACT_TURN_RIGHT; + } + else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) + {// big left turn + m_IdealActivity = ACT_TURN_LEFT; + } +} + +//========================================================= +// Start task - selects the correct activity and performs +// any necessary calculations to start the next task on the +// schedule. +//========================================================= +void CBaseMonster :: StartTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_TURN_RIGHT: + { + float flCurrentYaw; + + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); + pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); + SetTurnActivity(); + break; + } + case TASK_TURN_LEFT: + { + float flCurrentYaw; + + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); + pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); + SetTurnActivity(); + break; + } + case TASK_REMEMBER: + { + Remember ( (int)pTask->flData ); + TaskComplete(); + break; + } + case TASK_FORGET: + { + Forget ( (int)pTask->flData ); + TaskComplete(); + break; + } + case TASK_FIND_HINTNODE: + { + m_iHintNode = FindHintNode(); + + if ( m_iHintNode != NO_NODE ) + { + TaskComplete(); + } + else + { + TaskFail(); + } + break; + } + case TASK_STORE_LASTPOSITION: + { + m_vecLastPosition = pev->origin; + TaskComplete(); + break; + } + case TASK_CLEAR_LASTPOSITION: + { + m_vecLastPosition = g_vecZero; + TaskComplete(); + break; + } + case TASK_CLEAR_HINTNODE: + { + m_iHintNode = NO_NODE; + TaskComplete(); + break; + } + case TASK_STOP_MOVING: + { + if ( m_IdealActivity == m_movementActivity ) + { + m_IdealActivity = GetStoppedActivity(); + } + + RouteClear(); + TaskComplete(); + break; + } + case TASK_PLAY_SEQUENCE_FACE_ENEMY: + case TASK_PLAY_SEQUENCE_FACE_TARGET: + case TASK_PLAY_SEQUENCE: + { + m_IdealActivity = ( Activity )( int )pTask->flData; + break; + } + case TASK_PLAY_ACTIVE_IDLE: + { + // monsters verify that they have a sequence for the node's activity BEFORE + // moving towards the node, so it's ok to just set the activity without checking here. + m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; + break; + } + case TASK_SET_SCHEDULE: + { + Schedule_t *pNewSchedule; + + pNewSchedule = GetScheduleOfType( (int)pTask->flData ); + + if ( pNewSchedule ) + { + ChangeSchedule( pNewSchedule ); + } + else + { + TaskFail(); + } + + break; + } + case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: + { + if ( m_hEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) + { + // try for cover farther than the FLData from the schedule. + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: + { + if ( m_hEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) + { + // try for cover farther than the FLData from the schedule. + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_NODE_COVER_FROM_ENEMY: + { + if ( m_hEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) + { + // try for cover farther than the FLData from the schedule. + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_COVER_FROM_ENEMY: + { + entvars_t *pevCover; + + if ( m_hEnemy == NULL ) + { + // Find cover from self if no enemy available + pevCover = pev; +// TaskFail(); +// return; + } + else + pevCover = m_hEnemy->pev; + + if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) + { + // try lateral first + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_COVER_FROM_ORIGIN: + { + if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else + { + // no cover! + TaskFail(); + } + } + break; + case TASK_FIND_COVER_FROM_BEST_SOUND: + { + CSound *pBestSound; + + pBestSound = PBestSound(); + + ASSERT( pBestSound != NULL ); + /* + if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) + { + // try lateral first + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + */ + + if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else + { + // no coverwhatsoever. or no sound in list + TaskFail(); + } + break; + } + case TASK_FACE_HINTNODE: + { + pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; + SetTurnActivity(); + break; + } + + case TASK_FACE_LASTPOSITION: + MakeIdealYaw ( m_vecLastPosition ); + SetTurnActivity(); + break; + + case TASK_FACE_TARGET: + if ( m_hTargetEnt != NULL ) + { + MakeIdealYaw ( m_hTargetEnt->pev->origin ); + SetTurnActivity(); + } + else + TaskFail(); + break; + case TASK_FACE_ENEMY: + { + MakeIdealYaw ( m_vecEnemyLKP ); + SetTurnActivity(); + break; + } + case TASK_FACE_IDEAL: + { + SetTurnActivity(); + break; + } + case TASK_FACE_ROUTE: + { + if (FRouteClear()) + { + ALERT(at_aiconsole, "No route to face!\n"); + TaskFail(); + } + else + { + MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); + SetTurnActivity(); + } + break; + } + case TASK_WAIT_PVS: + case TASK_WAIT_INDEFINITE: + { + // don't do anything. + break; + } + case TASK_WAIT: + case TASK_WAIT_FACE_ENEMY: + {// set a future time that tells us when the wait is over. + m_flWaitFinished = gpGlobals->time + pTask->flData; + break; + } + case TASK_WAIT_RANDOM: + {// set a future time that tells us when the wait is over. + m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); + break; + } + case TASK_MOVE_TO_TARGET_RANGE: + { + if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + TaskComplete(); + else + { + m_vecMoveGoal = m_hTargetEnt->pev->origin; + if ( !MoveToTarget( ACT_WALK, 2 ) ) + TaskFail(); + } + break; + } + case TASK_RUN_TO_TARGET: + case TASK_WALK_TO_TARGET: + { + Activity newActivity; + + if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + TaskComplete(); + else + { + if ( pTask->iTask == TASK_WALK_TO_TARGET ) + newActivity = ACT_WALK; + else + newActivity = ACT_RUN; + // This monster can't do this! + if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) + TaskComplete(); + else + { + if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) + { + TaskFail(); + ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); + RouteClear(); + } + } + } + TaskComplete(); + break; + } + case TASK_CLEAR_MOVE_WAIT: + { + m_flMoveWaitFinished = gpGlobals->time; + TaskComplete(); + break; + } + case TASK_MELEE_ATTACK1_NOTURN: + case TASK_MELEE_ATTACK1: + { + m_IdealActivity = ACT_MELEE_ATTACK1; + break; + } + case TASK_MELEE_ATTACK2_NOTURN: + case TASK_MELEE_ATTACK2: + { + m_IdealActivity = ACT_MELEE_ATTACK2; + break; + } + case TASK_RANGE_ATTACK1_NOTURN: + case TASK_RANGE_ATTACK1: + { + m_IdealActivity = ACT_RANGE_ATTACK1; + break; + } + case TASK_RANGE_ATTACK2_NOTURN: + case TASK_RANGE_ATTACK2: + { + m_IdealActivity = ACT_RANGE_ATTACK2; + break; + } + case TASK_RELOAD_NOTURN: + case TASK_RELOAD: + { + m_IdealActivity = ACT_RELOAD; + break; + } + case TASK_SPECIAL_ATTACK1: + { + m_IdealActivity = ACT_SPECIAL_ATTACK1; + break; + } + case TASK_SPECIAL_ATTACK2: + { + m_IdealActivity = ACT_SPECIAL_ATTACK2; + break; + } + case TASK_SET_ACTIVITY: + { + m_IdealActivity = (Activity)(int)pTask->flData; + TaskComplete(); + break; + } + case TASK_GET_PATH_TO_ENEMY_LKP: + { + if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) + { + TaskComplete(); + } + else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_ENEMY: + { + CBaseEntity *pEnemy = m_hEnemy; + + if ( pEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) + { + TaskComplete(); + } + else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_ENEMY_CORPSE: + { + UTIL_MakeVectors( pev->angles ); + if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) + { + TaskComplete(); + } + else + { + ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); + TaskFail(); + } + } + break; + case TASK_GET_PATH_TO_SPOT: + { + CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); + if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); + TaskFail(); + } + break; + } + + case TASK_GET_PATH_TO_TARGET: + { + RouteClear(); + if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_HINTNODE:// for active idles! + { + if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_LASTPOSITION: + { + m_vecMoveGoal = m_vecLastPosition; + + if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_BESTSOUND: + { + CSound *pSound; + + pSound = PBestSound(); + + if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); + TaskFail(); + } + break; + } +case TASK_GET_PATH_TO_BESTSCENT: + { + CSound *pScent; + + pScent = PBestScent(); + + if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); + + TaskFail(); + } + break; + } + case TASK_RUN_PATH: + { + // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? + if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) + { + m_movementActivity = ACT_RUN; + } + else + { + m_movementActivity = ACT_WALK; + } + TaskComplete(); + break; + } + case TASK_WALK_PATH: + { + if ( pev->movetype == MOVETYPE_FLY ) + { + m_movementActivity = ACT_FLY; + } + if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) + { + m_movementActivity = ACT_WALK; + } + else + { + m_movementActivity = ACT_RUN; + } + TaskComplete(); + break; + } + case TASK_STRAFE_PATH: + { + Vector2D vec2DirToPoint; + Vector2D vec2RightSide; + + // to start strafing, we have to first figure out if the target is on the left side or right side + UTIL_MakeVectors ( pev->angles ); + + vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); + vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); + + if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) + { + // strafe right + m_movementActivity = ACT_STRAFE_RIGHT; + } + else + { + // strafe left + m_movementActivity = ACT_STRAFE_LEFT; + } + TaskComplete(); + break; + } + + + case TASK_WAIT_FOR_MOVEMENT: + { + if (FRouteClear()) + { + TaskComplete(); + } + break; + } + + case TASK_EAT: + { + Eat( pTask->flData ); + TaskComplete(); + break; + } + case TASK_SMALL_FLINCH: + { + m_IdealActivity = GetSmallFlinchActivity(); + break; + } + case TASK_DIE: + { + RouteClear(); + + m_IdealActivity = GetDeathActivity(); + + pev->deadflag = DEAD_DYING; + break; + } + case TASK_SOUND_WAKE: + { + AlertSound(); + TaskComplete(); + break; + } + case TASK_SOUND_DIE: + { + DeathSound(); + TaskComplete(); + break; + } + case TASK_SOUND_IDLE: + { + IdleSound(); + TaskComplete(); + break; + } + case TASK_SOUND_PAIN: + { + PainSound(); + TaskComplete(); + break; + } + case TASK_SOUND_DEATH: + { + DeathSound(); + TaskComplete(); + break; + } + case TASK_SOUND_ANGRY: + { + // sounds are complete as soon as we get here, cause we've already played them. + ALERT ( at_aiconsole, "SOUND\n" ); + TaskComplete(); + break; + } + case TASK_WAIT_FOR_SCRIPT: + { + if (m_pCine->m_iszIdle) + { + m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); + if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) + { + pev->framerate = 0; + } + } + else + m_IdealActivity = ACT_IDLE; + + break; + } + case TASK_PLAY_SCRIPT: + { + pev->movetype = MOVETYPE_FLY; + ClearBits(pev->flags, FL_ONGROUND); + m_scriptState = SCRIPT_PLAYING; + break; + } + case TASK_ENABLE_SCRIPT: + { + m_pCine->DelayStart( 0 ); + TaskComplete(); + break; + } + case TASK_PLANT_ON_SCRIPT: + { + if ( m_hTargetEnt != NULL ) + { + pev->origin = m_hTargetEnt->pev->origin; // Plant on target + } + + TaskComplete(); + break; + } + case TASK_FACE_SCRIPT: + { + if ( m_hTargetEnt != NULL ) + { + pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); + } + + TaskComplete(); + m_IdealActivity = ACT_IDLE; + RouteClear(); + break; + } + + case TASK_SUGGEST_STATE: + { + m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; + TaskComplete(); + break; + } + + case TASK_SET_FAIL_SCHEDULE: + m_failSchedule = (int)pTask->flData; + TaskComplete(); + break; + + case TASK_CLEAR_FAIL_SCHEDULE: + m_failSchedule = SCHED_NONE; + TaskComplete(); + break; + + default: + { + ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); + break; + } + } +} + +//========================================================= +// GetTask - returns a pointer to the current +// scheduled task. NULL if there's a problem. +//========================================================= +Task_t *CBaseMonster :: GetTask ( void ) +{ + if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) + { + // m_iScheduleIndex is not within valid range for the monster's current schedule. + return NULL; + } + else + { + return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; + } +} + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CBaseMonster :: GetSchedule ( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_PRONE: + { + return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); + break; + } + case MONSTERSTATE_NONE: + { + ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); + break; + } + case MONSTERSTATE_IDLE: + { + if ( HasConditions ( bits_COND_HEAR_SOUND ) ) + { + return GetScheduleOfType( SCHED_ALERT_FACE ); + } + else if ( FRouteClear() ) + { + // no valid route! + return GetScheduleOfType( SCHED_IDLE_STAND ); + } + else + { + // valid route. Get moving + return GetScheduleOfType( SCHED_IDLE_WALK ); + } + break; + } + case MONSTERSTATE_ALERT: + { + if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) + { + return GetScheduleOfType ( SCHED_VICTORY_DANCE ); + } + + if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) + { + if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction + { + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); + } + else + { + return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); + } + } + + else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) + { + return GetScheduleOfType( SCHED_ALERT_FACE ); + } + else + { + return GetScheduleOfType( SCHED_ALERT_STAND ); + } + break; + } + case MONSTERSTATE_COMBAT: + { + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // clear the current (dead) enemy and try to find another. + m_hEnemy = NULL; + + if ( GetEnemy() ) + { + ClearConditions( bits_COND_ENEMY_DEAD ); + return GetSchedule(); + } + else + { + SetState( MONSTERSTATE_ALERT ); + return GetSchedule(); + } + } + + if ( HasConditions(bits_COND_NEW_ENEMY) ) + { + return GetScheduleOfType ( SCHED_WAKE_ANGRY ); + } + else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) + { + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + else if ( !HasConditions(bits_COND_SEE_ENEMY) ) + { + // we can't see the enemy + if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) + { + // enemy is unseen, but not occluded! + // turn to face enemy + return GetScheduleOfType( SCHED_COMBAT_FACE ); + } + else + { + // chase! + return GetScheduleOfType( SCHED_CHASE_ENEMY ); + } + } + else + { + // we can see the enemy + if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) + { + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); + } + if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) + { + return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); + } + if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) + { + return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); + } + if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) + { + return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); + } + if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) + { + // if we can see enemy but can't use either attack type, we must need to get closer to enemy + return GetScheduleOfType( SCHED_CHASE_ENEMY ); + } + else if ( !FacingIdeal() ) + { + //turn + return GetScheduleOfType( SCHED_COMBAT_FACE ); + } + else + { + ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); + } + } + break; + } + case MONSTERSTATE_DEAD: + { + return GetScheduleOfType( SCHED_DIE ); + break; + } + case MONSTERSTATE_SCRIPT: + { + ASSERT( m_pCine != NULL ); + if ( !m_pCine ) + { + ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); + CineCleanup(); + return GetScheduleOfType( SCHED_IDLE_STAND ); + } + + return GetScheduleOfType( SCHED_AISCRIPT ); + } + default: + { + ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); + break; + } + } + + return &slError[ 0 ]; +} diff --git a/main/source/dlls/Wxdebug.cpp b/main/source/dlls/Wxdebug.cpp index d3902d6c..26d0d381 100644 --- a/main/source/dlls/Wxdebug.cpp +++ b/main/source/dlls/Wxdebug.cpp @@ -1,395 +1,395 @@ -//==========================================================================; -// -// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY -// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR -// PURPOSE. -// -// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. -// -//--------------------------------------------------------------------------; - - -// For every module and executable we store a debugging level and flags -// for the types of output that are desired. Constants for the types are -// defined in WXDEBUG.H and more can be added. -// The keys are stored in the registry under the -// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Type and -// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Level key values -// -// There are also global values under SOFTWARE\Debug\Global which are loaded -// after the module-specific values. The Types specified there are OR'ed with -// the module specific types and m_dwLevel is set to the greater of the global -// and the module specific settings. - -#include -#include - -#include "extdll.h" -#include "util.h" -#include "wxdebug.h" - -#include - -#ifdef _DEBUG - -void WINAPI DbgInitModuleName(void); -void WINAPI DbgInitModuleSettings(void); -void WINAPI DbgInitGlobalSettings(void); -void WINAPI DbgInitLogTo(HKEY hKey); -void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel); - - - -const INT iDEBUGINFO = 512; // Used to format strings - -HINSTANCE m_hInst; // Module instance handle -TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name -//CRITICAL_SECTION m_CSDebug; // Controls access to list -BOOL m_bInit = FALSE; // Have we been initialised -HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here -DWORD m_dwTypes = 0; -DWORD m_dwLevel = 0; - -const TCHAR *m_pBaseKey = TEXT("SOFTWARE\\Debug"); -const TCHAR *m_pGlobalKey = TEXT("GLOBAL"); -TCHAR *pKeyNames[] = -{ - TEXT("Types"), - TEXT("Level") -}; - - -// DbgInitialize -// This sets the instance handle that the debug library uses to find -// the module's file name from the Win32 GetModuleFileName function -void WINAPI DbgInitialise(HINSTANCE hInst) -{ - if (!m_bInit) - { - //InitializeCriticalSection(&m_CSDebug); - m_bInit = TRUE; - m_hInst = hInst; - DbgInitModuleName(); - DbgInitModuleSettings(); - DbgInitGlobalSettings(); - } -} - - -// DbgTerminate -// This is called to clear up any resources the debug library uses - at the -// moment we delete our critical section and the handle of the output file. -void WINAPI DbgTerminate() -{ - if (m_bInit) - { - if (m_hOutput != INVALID_HANDLE_VALUE) - { - DBGASSERTEXECUTE(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - //DeleteCriticalSection(&m_CSDebug); - m_bInit = FALSE; - } -} - - -// DbgInitModuleName -// Initialise the module file name -void WINAPI DbgInitModuleName() -{ - TCHAR FullName[iDEBUGINFO]; // Load the full path and module name - TCHAR *pName; // Searches from the end for a backslash - - GetModuleFileName(m_hInst,FullName,iDEBUGINFO); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) - { - pName = FullName; - } - else - { - pName++; - } - lstrcpy(m_ModuleName,pName); -} - - -// DbgInitModuleSettings -// Retrieve the module-specific settings -void WINAPI DbgInitModuleSettings() -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hModuleKey; // Module key handle - - // Construct the base key name - wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_ModuleName); - - // Create or open the key for this module - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD)0, // Reserved value - NULL, // Address of class name - (DWORD)0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access module key")); - return; - } - - DbgInitLogTo(hModuleKey); - DbgInitKeyLevels(hModuleKey, &m_dwTypes, &m_dwLevel); - RegCloseKey(hModuleKey); -} - - -// DbgInitGlobalSettings -// This is called by DbgInitialize to read the global debug settings for -// Level and Type from the registry. The Types are OR'ed together and m_dwLevel -// is set to the greater of the global and module-specific values. -void WINAPI DbgInitGlobalSettings() -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hGlobalKey; // Global override key - DWORD dwTypes = 0; - DWORD dwLevel = 0; - - // Construct the global base key name - wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_pGlobalKey); - - // Create or open the key for this module - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD)0, // Reserved value - NULL, // Address of class name - (DWORD)0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access GLOBAL module key")); - return; - } - - DbgInitKeyLevels(hGlobalKey, &dwTypes, &dwLevel); - RegCloseKey(hGlobalKey); - - m_dwTypes |= dwTypes; - if (dwLevel > m_dwLevel) - m_dwLevel = dwLevel; -} - - -// DbgInitLogTo -// Called by DbgInitModuleSettings to setup alternate logging destinations -void WINAPI DbgInitLogTo(HKEY hKey) -{ - LONG lReturn; - DWORD dwKeyType; - DWORD dwKeySize; - TCHAR szFile[MAX_PATH] = {0}; - static const TCHAR cszKey[] = TEXT("LogToFile"); - - dwKeySize = MAX_PATH; - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - cszKey, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) szFile, // Returns the field's value - &dwKeySize); // Number of bytes transferred - - // create an empty key if it does not already exist - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) - { - dwKeySize = 1; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - cszKey, // Address of subkey name - (DWORD) 0, // Reserved field - REG_SZ, // Type of the key field - (PBYTE)szFile, // Value for the field - dwKeySize); // Size of the field buffer - } - - // if an output-to was specified. try to open it. - if (m_hOutput != INVALID_HANDLE_VALUE) - { - DBGASSERTEXECUTE(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - if (szFile[0] != 0) - { - if (!lstrcmpi(szFile, TEXT("Console"))) - { - m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - if (m_hOutput == INVALID_HANDLE_VALUE) - { - AllocConsole(); - m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - } - SetConsoleTitle (TEXT("Valve Debug Output")); - } else if (szFile[0] && - lstrcmpi(szFile, TEXT("Debug")) && - lstrcmpi(szFile, TEXT("Debugger")) && - lstrcmpi(szFile, TEXT("Deb"))) - { - m_hOutput = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE != m_hOutput) - { - static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); - SetFilePointer (m_hOutput, 0, NULL, FILE_END); - DbgOutString (cszBar); - } - } - } -} - - -// DbgInitKeyLevels -// This is called by DbgInitModuleSettings and DbgInitGlobalSettings to read -// settings for Types and Level from the registry -void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel) -{ - LONG lReturn; // Create key return value - DWORD dwKeySize; // Size of the key value - DWORD dwKeyType; // Receives it's type - - // Get the Types value - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[0], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE)pdwTypes, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - // If either the key was not available or it was not a DWORD value - // then we ensure only the high priority debug logging is output - // but we try and update the field to a zero filled DWORD value - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) - { - *pdwTypes = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[0], // Address of subkey name - (DWORD)0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE)pdwTypes, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[0]); - *pdwTypes = 0; - } - } - - // Get the Level value - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[1], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE)pdwLevel, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - // If either the key was not available or it was not a DWORD value - // then we ensure only the high priority debug logging is output - // but we try and update the field to a zero filled DWORD value - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) - { - *pdwLevel = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[1], // Address of subkey name - (DWORD)0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE)pdwLevel, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[1]); - *pdwLevel = 0; - } - } -} - - -// DbgOutString -void WINAPI DbgOutString(LPCTSTR psz) -{ - if (!m_bInit) - return; - if (m_hOutput != INVALID_HANDLE_VALUE) { - UINT cb = lstrlen(psz); - DWORD dw; - WriteFile (m_hOutput, psz, cb, &dw, NULL); - } else { - OutputDebugString (psz); - } -} - - -// DbgLogInfo -// Print a formatted string to the debugger prefixed with this module's name -// Because the debug code is linked statically every module loaded will -// have its own copy of this code. It therefore helps if the module name is -// included on the output so that the offending code can be easily found -void WINAPI DbgLogInfo(DWORD Type, DWORD Level, const TCHAR *pFormat,...) -{ - if (!m_bInit) - return; - // Check the current level for this type combination */ - if (((Type & m_dwTypes) == 0) || (m_dwLevel < Level)) - return; - - TCHAR szInfo[2000]; - - // Format the variable length parameter list - - va_list va; - va_start(va, pFormat); - - //lstrcpy(szInfo, m_ModuleName); - //lstrcat(szInfo, TEXT(": ")); - wvsprintf(szInfo /* + lstrlen(szInfo) */, pFormat, va); - //lstrcat(szInfo, TEXT("\r\n")); - DbgOutString(szInfo); - - va_end(va); -} - - -// DbgKernelAssert -// If we are executing as a pure kernel filter we cannot display message -// boxes to the user, this provides an alternative which puts the error -// condition on the debugger output with a suitable eye catching message -void WINAPI DbgKernelAssert(const TCHAR *pCondition, const TCHAR *pFileName, INT iLine) -{ - if (!m_bInit) - return; - DbgLogInfo(LOG_ERROR, 0, TEXT(m_ModuleName)); - DbgLogInfo(LOG_ERROR, 0, TEXT(": Assertion FAILED (%s) at line %d in file %s\r\n"), pCondition, iLine, pFileName); - DebugBreak(); -} - -#endif // _DEBUG - - +//==========================================================================; +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. +// +// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. +// +//--------------------------------------------------------------------------; + + +// For every module and executable we store a debugging level and flags +// for the types of output that are desired. Constants for the types are +// defined in WXDEBUG.H and more can be added. +// The keys are stored in the registry under the +// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Type and +// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Level key values +// +// There are also global values under SOFTWARE\Debug\Global which are loaded +// after the module-specific values. The Types specified there are OR'ed with +// the module specific types and m_dwLevel is set to the greater of the global +// and the module specific settings. + +#include +#include + +#include "extdll.h" +#include "util.h" +#include "wxdebug.h" + +#include + +#ifdef _DEBUG + +void WINAPI DbgInitModuleName(void); +void WINAPI DbgInitModuleSettings(void); +void WINAPI DbgInitGlobalSettings(void); +void WINAPI DbgInitLogTo(HKEY hKey); +void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel); + + + +const INT iDEBUGINFO = 512; // Used to format strings + +HINSTANCE m_hInst; // Module instance handle +TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name +//CRITICAL_SECTION m_CSDebug; // Controls access to list +BOOL m_bInit = FALSE; // Have we been initialised +HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here +DWORD m_dwTypes = 0; +DWORD m_dwLevel = 0; + +const TCHAR *m_pBaseKey = TEXT("SOFTWARE\\Debug"); +const TCHAR *m_pGlobalKey = TEXT("GLOBAL"); +TCHAR *pKeyNames[] = +{ + TEXT("Types"), + TEXT("Level") +}; + + +// DbgInitialize +// This sets the instance handle that the debug library uses to find +// the module's file name from the Win32 GetModuleFileName function +void WINAPI DbgInitialise(HINSTANCE hInst) +{ + if (!m_bInit) + { + //InitializeCriticalSection(&m_CSDebug); + m_bInit = TRUE; + m_hInst = hInst; + DbgInitModuleName(); + DbgInitModuleSettings(); + DbgInitGlobalSettings(); + } +} + + +// DbgTerminate +// This is called to clear up any resources the debug library uses - at the +// moment we delete our critical section and the handle of the output file. +void WINAPI DbgTerminate() +{ + if (m_bInit) + { + if (m_hOutput != INVALID_HANDLE_VALUE) + { + DBGASSERTEXECUTE(CloseHandle(m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + //DeleteCriticalSection(&m_CSDebug); + m_bInit = FALSE; + } +} + + +// DbgInitModuleName +// Initialise the module file name +void WINAPI DbgInitModuleName() +{ + TCHAR FullName[iDEBUGINFO]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(m_hInst,FullName,iDEBUGINFO); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) + { + pName = FullName; + } + else + { + pName++; + } + lstrcpy(m_ModuleName,pName); +} + + +// DbgInitModuleSettings +// Retrieve the module-specific settings +void WINAPI DbgInitModuleSettings() +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hModuleKey; // Module key handle + + // Construct the base key name + wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_ModuleName); + + // Create or open the key for this module + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD)0, // Reserved value + NULL, // Address of class name + (DWORD)0, // Special options flags + KEY_ALL_ACCESS, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) + { + DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access module key")); + return; + } + + DbgInitLogTo(hModuleKey); + DbgInitKeyLevels(hModuleKey, &m_dwTypes, &m_dwLevel); + RegCloseKey(hModuleKey); +} + + +// DbgInitGlobalSettings +// This is called by DbgInitialize to read the global debug settings for +// Level and Type from the registry. The Types are OR'ed together and m_dwLevel +// is set to the greater of the global and module-specific values. +void WINAPI DbgInitGlobalSettings() +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hGlobalKey; // Global override key + DWORD dwTypes = 0; + DWORD dwLevel = 0; + + // Construct the global base key name + wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_pGlobalKey); + + // Create or open the key for this module + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD)0, // Reserved value + NULL, // Address of class name + (DWORD)0, // Special options flags + KEY_ALL_ACCESS, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) + { + DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access GLOBAL module key")); + return; + } + + DbgInitKeyLevels(hGlobalKey, &dwTypes, &dwLevel); + RegCloseKey(hGlobalKey); + + m_dwTypes |= dwTypes; + if (dwLevel > m_dwLevel) + m_dwLevel = dwLevel; +} + + +// DbgInitLogTo +// Called by DbgInitModuleSettings to setup alternate logging destinations +void WINAPI DbgInitLogTo(HKEY hKey) +{ + LONG lReturn; + DWORD dwKeyType; + DWORD dwKeySize; + TCHAR szFile[MAX_PATH] = {0}; + static const TCHAR cszKey[] = TEXT("LogToFile"); + + dwKeySize = MAX_PATH; + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + cszKey, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) szFile, // Returns the field's value + &dwKeySize); // Number of bytes transferred + + // create an empty key if it does not already exist + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) + { + dwKeySize = 1; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + cszKey, // Address of subkey name + (DWORD) 0, // Reserved field + REG_SZ, // Type of the key field + (PBYTE)szFile, // Value for the field + dwKeySize); // Size of the field buffer + } + + // if an output-to was specified. try to open it. + if (m_hOutput != INVALID_HANDLE_VALUE) + { + DBGASSERTEXECUTE(CloseHandle(m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + if (szFile[0] != 0) + { + if (!lstrcmpi(szFile, TEXT("Console"))) + { + m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + if (m_hOutput == INVALID_HANDLE_VALUE) + { + AllocConsole(); + m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + } + SetConsoleTitle (TEXT("Valve Debug Output")); + } else if (szFile[0] && + lstrcmpi(szFile, TEXT("Debug")) && + lstrcmpi(szFile, TEXT("Debugger")) && + lstrcmpi(szFile, TEXT("Deb"))) + { + m_hOutput = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE != m_hOutput) + { + static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); + SetFilePointer (m_hOutput, 0, NULL, FILE_END); + DbgOutString (cszBar); + } + } + } +} + + +// DbgInitKeyLevels +// This is called by DbgInitModuleSettings and DbgInitGlobalSettings to read +// settings for Types and Level from the registry +void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel) +{ + LONG lReturn; // Create key return value + DWORD dwKeySize; // Size of the key value + DWORD dwKeyType; // Receives it's type + + // Get the Types value + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + pKeyNames[0], // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE)pdwTypes, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + // If either the key was not available or it was not a DWORD value + // then we ensure only the high priority debug logging is output + // but we try and update the field to a zero filled DWORD value + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) + { + *pdwTypes = 0; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + pKeyNames[0], // Address of subkey name + (DWORD)0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE)pdwTypes, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) + { + DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[0]); + *pdwTypes = 0; + } + } + + // Get the Level value + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + pKeyNames[1], // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE)pdwLevel, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + // If either the key was not available or it was not a DWORD value + // then we ensure only the high priority debug logging is output + // but we try and update the field to a zero filled DWORD value + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) + { + *pdwLevel = 0; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + pKeyNames[1], // Address of subkey name + (DWORD)0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE)pdwLevel, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) + { + DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[1]); + *pdwLevel = 0; + } + } +} + + +// DbgOutString +void WINAPI DbgOutString(LPCTSTR psz) +{ + if (!m_bInit) + return; + if (m_hOutput != INVALID_HANDLE_VALUE) { + UINT cb = lstrlen(psz); + DWORD dw; + WriteFile (m_hOutput, psz, cb, &dw, NULL); + } else { + OutputDebugString (psz); + } +} + + +// DbgLogInfo +// Print a formatted string to the debugger prefixed with this module's name +// Because the debug code is linked statically every module loaded will +// have its own copy of this code. It therefore helps if the module name is +// included on the output so that the offending code can be easily found +void WINAPI DbgLogInfo(DWORD Type, DWORD Level, const TCHAR *pFormat,...) +{ + if (!m_bInit) + return; + // Check the current level for this type combination */ + if (((Type & m_dwTypes) == 0) || (m_dwLevel < Level)) + return; + + TCHAR szInfo[2000]; + + // Format the variable length parameter list + + va_list va; + va_start(va, pFormat); + + //lstrcpy(szInfo, m_ModuleName); + //lstrcat(szInfo, TEXT(": ")); + wvsprintf(szInfo /* + lstrlen(szInfo) */, pFormat, va); + //lstrcat(szInfo, TEXT("\r\n")); + DbgOutString(szInfo); + + va_end(va); +} + + +// DbgKernelAssert +// If we are executing as a pure kernel filter we cannot display message +// boxes to the user, this provides an alternative which puts the error +// condition on the debugger output with a suitable eye catching message +void WINAPI DbgKernelAssert(const TCHAR *pCondition, const TCHAR *pFileName, INT iLine) +{ + if (!m_bInit) + return; + DbgLogInfo(LOG_ERROR, 0, TEXT(m_ModuleName)); + DbgLogInfo(LOG_ERROR, 0, TEXT(": Assertion FAILED (%s) at line %d in file %s\r\n"), pCondition, iLine, pFileName); + DebugBreak(); +} + +#endif // _DEBUG + + diff --git a/main/source/dlls/activity.h b/main/source/dlls/activity.h index fa90cab9..5944e363 100644 --- a/main/source/dlls/activity.h +++ b/main/source/dlls/activity.h @@ -1,113 +1,113 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef ACTIVITY_H -#define ACTIVITY_H - - -typedef enum { - ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity - ACT_IDLE = 1, - ACT_GUARD, - ACT_WALK, - ACT_RUN, - ACT_FLY, // Fly (and flap if appropriate) - ACT_SWIM, - ACT_HOP, // vertical jump - ACT_LEAP, // long forward jump - ACT_FALL, - ACT_LAND, - ACT_STRAFE_LEFT, - ACT_STRAFE_RIGHT, - ACT_ROLL_LEFT, // tuck and roll, left - ACT_ROLL_RIGHT, // tuck and roll, right - ACT_TURN_LEFT, // turn quickly left (stationary) - ACT_TURN_RIGHT, // turn quickly right (stationary) - ACT_CROUCH, // the act of crouching down from a standing position - ACT_CROUCHIDLE, // holding body in crouched position (loops) - ACT_STAND, // the act of standing from a crouched position - ACT_USE, - ACT_SIGNAL1, - ACT_SIGNAL2, - ACT_SIGNAL3, - ACT_TWITCH, - ACT_COWER, - ACT_SMALL_FLINCH, - ACT_BIG_FLINCH, - ACT_RANGE_ATTACK1, - ACT_RANGE_ATTACK2, - ACT_MELEE_ATTACK1, - ACT_MELEE_ATTACK2, - ACT_RELOAD, - ACT_RELOAD_START, // added by elven for multipart reload animations - ACT_RELOAD_INSERT, - ACT_RELOAD_END, - ACT_ARM, // pull out gun, for instance - ACT_DISARM, // reholster gun - ACT_EAT, // monster chowing on a large food item (loop) - ACT_DIESIMPLE, - ACT_DIEBACKWARD, - ACT_DIEFORWARD, - ACT_DIEVIOLENT, - ACT_BARNACLE_HIT, // barnacle tongue hits a monster - ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop ) - ACT_BARNACLE_CHOMP, // barnacle latches on to the monster - ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop ) - ACT_SLEEP, - ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor - ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall ) - ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop) - ACT_WALK_HURT, // limp (loop) - ACT_RUN_HURT, // limp (loop) - ACT_HOVER, // Idle while in flight - ACT_GLIDE, // Fly (don't flap) - ACT_FLY_LEFT, // Turn left in flight - ACT_FLY_RIGHT, // Turn right in flight - ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air - ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster - ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops. - ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc ) - ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of - ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever. - ACT_SPECIAL_ATTACK1, // very monster specific special attacks. - ACT_SPECIAL_ATTACK2, - ACT_COMBAT_IDLE, // agitated idle. - ACT_WALK_SCARED, - ACT_RUN_SCARED, - ACT_VICTORY_DANCE, // killed a player, do a victory dance. - ACT_DIE_HEADSHOT, // die, hit in head. - ACT_DIE_CHESTSHOT, // die, hit in chest - ACT_DIE_GUTSHOT, // die, hit in gut - ACT_DIE_BACKSHOT, // die, hit in back - ACT_FLINCH_HEAD, - ACT_FLINCH_CHEST, - ACT_FLINCH_STOMACH, - ACT_FLINCH_LEFTARM, - ACT_FLINCH_RIGHTARM, - ACT_FLINCH_LEFTLEG, - ACT_FLINCH_RIGHTLEG, - ACT_RANGE_PRIME, // Priming a ranged weapon -} Activity; - - -typedef struct { - int type; - char *name; -} activity_map_t; - -extern activity_map_t activity_map[]; - - -#endif //ACTIVITY_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef ACTIVITY_H +#define ACTIVITY_H + + +typedef enum { + ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity + ACT_IDLE = 1, + ACT_GUARD, + ACT_WALK, + ACT_RUN, + ACT_FLY, // Fly (and flap if appropriate) + ACT_SWIM, + ACT_HOP, // vertical jump + ACT_LEAP, // long forward jump + ACT_FALL, + ACT_LAND, + ACT_STRAFE_LEFT, + ACT_STRAFE_RIGHT, + ACT_ROLL_LEFT, // tuck and roll, left + ACT_ROLL_RIGHT, // tuck and roll, right + ACT_TURN_LEFT, // turn quickly left (stationary) + ACT_TURN_RIGHT, // turn quickly right (stationary) + ACT_CROUCH, // the act of crouching down from a standing position + ACT_CROUCHIDLE, // holding body in crouched position (loops) + ACT_STAND, // the act of standing from a crouched position + ACT_USE, + ACT_SIGNAL1, + ACT_SIGNAL2, + ACT_SIGNAL3, + ACT_TWITCH, + ACT_COWER, + ACT_SMALL_FLINCH, + ACT_BIG_FLINCH, + ACT_RANGE_ATTACK1, + ACT_RANGE_ATTACK2, + ACT_MELEE_ATTACK1, + ACT_MELEE_ATTACK2, + ACT_RELOAD, + ACT_RELOAD_START, // added by elven for multipart reload animations + ACT_RELOAD_INSERT, + ACT_RELOAD_END, + ACT_ARM, // pull out gun, for instance + ACT_DISARM, // reholster gun + ACT_EAT, // monster chowing on a large food item (loop) + ACT_DIESIMPLE, + ACT_DIEBACKWARD, + ACT_DIEFORWARD, + ACT_DIEVIOLENT, + ACT_BARNACLE_HIT, // barnacle tongue hits a monster + ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop ) + ACT_BARNACLE_CHOMP, // barnacle latches on to the monster + ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop ) + ACT_SLEEP, + ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor + ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall ) + ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop) + ACT_WALK_HURT, // limp (loop) + ACT_RUN_HURT, // limp (loop) + ACT_HOVER, // Idle while in flight + ACT_GLIDE, // Fly (don't flap) + ACT_FLY_LEFT, // Turn left in flight + ACT_FLY_RIGHT, // Turn right in flight + ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air + ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster + ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops. + ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc ) + ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of + ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever. + ACT_SPECIAL_ATTACK1, // very monster specific special attacks. + ACT_SPECIAL_ATTACK2, + ACT_COMBAT_IDLE, // agitated idle. + ACT_WALK_SCARED, + ACT_RUN_SCARED, + ACT_VICTORY_DANCE, // killed a player, do a victory dance. + ACT_DIE_HEADSHOT, // die, hit in head. + ACT_DIE_CHESTSHOT, // die, hit in chest + ACT_DIE_GUTSHOT, // die, hit in gut + ACT_DIE_BACKSHOT, // die, hit in back + ACT_FLINCH_HEAD, + ACT_FLINCH_CHEST, + ACT_FLINCH_STOMACH, + ACT_FLINCH_LEFTARM, + ACT_FLINCH_RIGHTARM, + ACT_FLINCH_LEFTLEG, + ACT_FLINCH_RIGHTLEG, + ACT_RANGE_PRIME, // Priming a ranged weapon +} Activity; + + +typedef struct { + int type; + char *name; +} activity_map_t; + +extern activity_map_t activity_map[]; + + +#endif //ACTIVITY_H diff --git a/main/source/dlls/activitymap.h b/main/source/dlls/activitymap.h index e4536b84..86d154d4 100644 --- a/main/source/dlls/activitymap.h +++ b/main/source/dlls/activitymap.h @@ -1,101 +1,101 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#define _A( a ) { a, #a } - -activity_map_t activity_map[] = -{ -_A( ACT_IDLE ), -_A( ACT_GUARD ), -_A( ACT_WALK ), -_A( ACT_RUN ), -_A( ACT_FLY ), -_A( ACT_SWIM ), -_A( ACT_HOP ), -_A( ACT_LEAP ), -_A( ACT_FALL ), -_A( ACT_LAND ), -_A( ACT_STRAFE_LEFT ), -_A( ACT_STRAFE_RIGHT ), -_A( ACT_ROLL_LEFT ), -_A( ACT_ROLL_RIGHT ), -_A( ACT_TURN_LEFT ), -_A( ACT_TURN_RIGHT ), -_A( ACT_CROUCH ), -_A( ACT_CROUCHIDLE ), -_A( ACT_STAND ), -_A( ACT_USE ), -_A( ACT_SIGNAL1 ), -_A( ACT_SIGNAL2 ), -_A( ACT_SIGNAL3 ), -_A( ACT_TWITCH ), -_A( ACT_COWER ), -_A( ACT_SMALL_FLINCH ), -_A( ACT_BIG_FLINCH ), -_A( ACT_RANGE_ATTACK1 ), -_A( ACT_RANGE_ATTACK2 ), -_A( ACT_MELEE_ATTACK1 ), -_A( ACT_MELEE_ATTACK2 ), -_A( ACT_RELOAD ), -_A( ACT_RELOAD_START), // added by elven -_A( ACT_RELOAD_INSERT), -_A( ACT_RELOAD_END), -_A( ACT_ARM ), -_A( ACT_DISARM ), -_A( ACT_EAT ), -_A( ACT_DIESIMPLE ), -_A( ACT_DIEBACKWARD ), -_A( ACT_DIEFORWARD ), -_A( ACT_DIEVIOLENT ), -_A( ACT_BARNACLE_HIT ), -_A( ACT_BARNACLE_PULL ), -_A( ACT_BARNACLE_CHOMP ), -_A( ACT_BARNACLE_CHEW ), -_A( ACT_SLEEP ), -_A( ACT_INSPECT_FLOOR ), -_A( ACT_INSPECT_WALL ), -_A( ACT_IDLE_ANGRY ), -_A( ACT_WALK_HURT ), -_A( ACT_RUN_HURT ), -_A( ACT_HOVER ), -_A( ACT_GLIDE ), -_A( ACT_FLY_LEFT ), -_A( ACT_FLY_RIGHT ), -_A( ACT_DETECT_SCENT ), -_A( ACT_SNIFF ), -_A( ACT_BITE ), -_A( ACT_THREAT_DISPLAY ), -_A( ACT_FEAR_DISPLAY ), -_A( ACT_EXCITED ), -_A( ACT_SPECIAL_ATTACK1 ), -_A( ACT_SPECIAL_ATTACK2 ), -_A( ACT_COMBAT_IDLE ), -_A( ACT_WALK_SCARED ), -_A( ACT_RUN_SCARED ), -_A( ACT_VICTORY_DANCE ), -_A( ACT_DIE_HEADSHOT ), -_A( ACT_DIE_CHESTSHOT ), -_A( ACT_DIE_GUTSHOT ), -_A( ACT_DIE_BACKSHOT ), -_A( ACT_FLINCH_HEAD ), -_A( ACT_FLINCH_CHEST ), -_A( ACT_FLINCH_STOMACH ), -_A( ACT_FLINCH_LEFTARM ), -_A( ACT_FLINCH_RIGHTARM ), -_A( ACT_FLINCH_LEFTLEG ), -_A( ACT_FLINCH_RIGHTLEG ), -_A( ACT_RANGE_PRIME ), -0, NULL -}; +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#define _A( a ) { a, #a } + +activity_map_t activity_map[] = +{ +_A( ACT_IDLE ), +_A( ACT_GUARD ), +_A( ACT_WALK ), +_A( ACT_RUN ), +_A( ACT_FLY ), +_A( ACT_SWIM ), +_A( ACT_HOP ), +_A( ACT_LEAP ), +_A( ACT_FALL ), +_A( ACT_LAND ), +_A( ACT_STRAFE_LEFT ), +_A( ACT_STRAFE_RIGHT ), +_A( ACT_ROLL_LEFT ), +_A( ACT_ROLL_RIGHT ), +_A( ACT_TURN_LEFT ), +_A( ACT_TURN_RIGHT ), +_A( ACT_CROUCH ), +_A( ACT_CROUCHIDLE ), +_A( ACT_STAND ), +_A( ACT_USE ), +_A( ACT_SIGNAL1 ), +_A( ACT_SIGNAL2 ), +_A( ACT_SIGNAL3 ), +_A( ACT_TWITCH ), +_A( ACT_COWER ), +_A( ACT_SMALL_FLINCH ), +_A( ACT_BIG_FLINCH ), +_A( ACT_RANGE_ATTACK1 ), +_A( ACT_RANGE_ATTACK2 ), +_A( ACT_MELEE_ATTACK1 ), +_A( ACT_MELEE_ATTACK2 ), +_A( ACT_RELOAD ), +_A( ACT_RELOAD_START), // added by elven +_A( ACT_RELOAD_INSERT), +_A( ACT_RELOAD_END), +_A( ACT_ARM ), +_A( ACT_DISARM ), +_A( ACT_EAT ), +_A( ACT_DIESIMPLE ), +_A( ACT_DIEBACKWARD ), +_A( ACT_DIEFORWARD ), +_A( ACT_DIEVIOLENT ), +_A( ACT_BARNACLE_HIT ), +_A( ACT_BARNACLE_PULL ), +_A( ACT_BARNACLE_CHOMP ), +_A( ACT_BARNACLE_CHEW ), +_A( ACT_SLEEP ), +_A( ACT_INSPECT_FLOOR ), +_A( ACT_INSPECT_WALL ), +_A( ACT_IDLE_ANGRY ), +_A( ACT_WALK_HURT ), +_A( ACT_RUN_HURT ), +_A( ACT_HOVER ), +_A( ACT_GLIDE ), +_A( ACT_FLY_LEFT ), +_A( ACT_FLY_RIGHT ), +_A( ACT_DETECT_SCENT ), +_A( ACT_SNIFF ), +_A( ACT_BITE ), +_A( ACT_THREAT_DISPLAY ), +_A( ACT_FEAR_DISPLAY ), +_A( ACT_EXCITED ), +_A( ACT_SPECIAL_ATTACK1 ), +_A( ACT_SPECIAL_ATTACK2 ), +_A( ACT_COMBAT_IDLE ), +_A( ACT_WALK_SCARED ), +_A( ACT_RUN_SCARED ), +_A( ACT_VICTORY_DANCE ), +_A( ACT_DIE_HEADSHOT ), +_A( ACT_DIE_CHESTSHOT ), +_A( ACT_DIE_GUTSHOT ), +_A( ACT_DIE_BACKSHOT ), +_A( ACT_FLINCH_HEAD ), +_A( ACT_FLINCH_CHEST ), +_A( ACT_FLINCH_STOMACH ), +_A( ACT_FLINCH_LEFTARM ), +_A( ACT_FLINCH_RIGHTARM ), +_A( ACT_FLINCH_LEFTLEG ), +_A( ACT_FLINCH_RIGHTLEG ), +_A( ACT_RANGE_PRIME ), +0, NULL +}; diff --git a/main/source/dlls/aflock.cpp b/main/source/dlls/aflock.cpp index 515482e6..bf78835f 100644 --- a/main/source/dlls/aflock.cpp +++ b/main/source/dlls/aflock.cpp @@ -1,910 +1,910 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "squadmonster.h" - -#define AFLOCK_MAX_RECRUIT_RADIUS 1024 -#define AFLOCK_FLY_SPEED 125 -#define AFLOCK_TURN_RATE 75 -#define AFLOCK_ACCELERATE 10 -#define AFLOCK_CHECK_DIST 192 -#define AFLOCK_TOO_CLOSE 100 -#define AFLOCK_TOO_FAR 256 - -//========================================================= -//========================================================= -class CFlockingFlyerFlock : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void SpawnFlock( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - // Sounds are shared by the flock - static void PrecacheFlockSounds( void ); - - int m_cFlockSize; - float m_flFlockRadius; -}; - -TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = -{ - DEFINE_FIELD( CFlockingFlyerFlock, m_cFlockSize, FIELD_INTEGER ), - DEFINE_FIELD( CFlockingFlyerFlock, m_flFlockRadius, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CFlockingFlyerFlock, CBaseMonster ); - -//========================================================= -//========================================================= -class CFlockingFlyer : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SpawnCommonCode( void ); - void EXPORT IdleThink( void ); - void BoidAdvanceFrame( void ); - void EXPORT FormFlock( void ); - void EXPORT Start( void ); - void EXPORT FlockLeaderThink( void ); - void EXPORT FlockFollowerThink( void ); - void EXPORT FallHack( void ); - void MakeSound( void ); - void AlertFlock( void ); - void SpreadFlock( void ); - void SpreadFlock2( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - void Poop ( void ); - BOOL FPathBlocked( void ); - //void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int IsLeader( void ) { return m_pSquadLeader == this; } - int InSquad( void ) { return m_pSquadLeader != NULL; } - int SquadCount( void ); - void SquadRemove( CFlockingFlyer *pRemove ); - void SquadUnlink( void ); - void SquadAdd( CFlockingFlyer *pAdd ); - void SquadDisband( void ); - - CFlockingFlyer *m_pSquadLeader; - CFlockingFlyer *m_pSquadNext; - BOOL m_fTurning;// is this boid turning? - BOOL m_fCourseAdjust;// followers set this flag TRUE to override flocking while they avoid something - BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead - Vector m_vecReferencePoint;// last place we saw leader - Vector m_vecAdjustedVelocity;// adjusted velocity (used when fCourseAdjust is TRUE) - float m_flGoalSpeed; - float m_flLastBlockedTime; - float m_flFakeBlockedTime; - float m_flAlertTime; - float m_flFlockNextSoundTime; -}; -LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer ); -LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock ); - -TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = -{ - DEFINE_FIELD( CFlockingFlyer, m_pSquadLeader, FIELD_CLASSPTR ), - DEFINE_FIELD( CFlockingFlyer, m_pSquadNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CFlockingFlyer, m_fTurning, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_fCourseAdjust, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_fPathBlocked, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_vecReferencePoint, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CFlockingFlyer, m_vecAdjustedVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CFlockingFlyer, m_flGoalSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFlockingFlyer, m_flLastBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CFlockingFlyer, m_flFakeBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CFlockingFlyer, m_flAlertTime, FIELD_TIME ), -// DEFINE_FIELD( CFlockingFlyer, m_flFlockNextSoundTime, FIELD_TIME ), // don't need to save -}; - -IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ); - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iFlockSize")) - { - m_cFlockSize = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "flFlockRadius")) - { - m_flFlockRadius = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: Spawn( ) -{ - Precache( ); - SpawnFlock(); - - REMOVE_ENTITY(ENT(pev)); // dump the spawn ent -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: Precache( ) -{ - //PRECACHE_MODEL("models/aflock.mdl"); - PRECACHE_MODEL("models/boid.mdl"); - - PrecacheFlockSounds(); -} - - -void CFlockingFlyerFlock :: PrecacheFlockSounds( void ) -{ - PRECACHE_SOUND("boid/boid_alert1.wav" ); - PRECACHE_SOUND("boid/boid_alert2.wav" ); - - PRECACHE_SOUND("boid/boid_idle1.wav" ); - PRECACHE_SOUND("boid/boid_idle2.wav" ); -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: SpawnFlock( void ) -{ - float R = m_flFlockRadius; - int iCount; - Vector vecSpot; - CFlockingFlyer *pBoid, *pLeader; - - pLeader = pBoid = NULL; - - for ( iCount = 0 ; iCount < m_cFlockSize ; iCount++ ) - { - pBoid = GetClassPtr( (CFlockingFlyer *)NULL ); - - if ( !pLeader ) - { - // make this guy the leader. - pLeader = pBoid; - - pLeader->m_pSquadLeader = pLeader; - pLeader->m_pSquadNext = NULL; - } - - vecSpot.x = RANDOM_FLOAT( -R, R ); - vecSpot.y = RANDOM_FLOAT( -R, R ); - vecSpot.z = RANDOM_FLOAT( 0, 16 ); - vecSpot = pev->origin + vecSpot; - - UTIL_SetOrigin(pBoid->pev, vecSpot); - pBoid->pev->movetype = MOVETYPE_FLY; - pBoid->SpawnCommonCode(); - pBoid->pev->flags &= ~FL_ONGROUND; - pBoid->pev->velocity = g_vecZero; - pBoid->pev->angles = pev->angles; - - pBoid->pev->frame = 0; - pBoid->pev->nextthink = gpGlobals->time + 0.2; - pBoid->SetThink( &CFlockingFlyer :: IdleThink ); - - if ( pBoid != pLeader ) - { - pLeader->SquadAdd( pBoid ); - } - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: Spawn( ) -{ - Precache( ); - SpawnCommonCode(); - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CFlockingFlyer::IdleThink ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: Precache( ) -{ - //PRECACHE_MODEL("models/aflock.mdl"); - PRECACHE_MODEL("models/boid.mdl"); - CFlockingFlyerFlock::PrecacheFlockSounds(); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: MakeSound( void ) -{ - if ( m_flAlertTime > gpGlobals->time ) - { - // make agitated sounds - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_alert1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_alert2.wav", 1, ATTN_NORM ); break; - } - - return; - } - - // make normal sound - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle2.wav", 1, ATTN_NORM ); break; - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CFlockingFlyer *pSquad; - - pSquad = (CFlockingFlyer *)m_pSquadLeader; - - while ( pSquad ) - { - pSquad->m_flAlertTime = gpGlobals->time + 15; - pSquad = (CFlockingFlyer *)pSquad->m_pSquadNext; - } - - if ( m_pSquadLeader ) - { - m_pSquadLeader->SquadRemove( this ); - } - - pev->deadflag = DEAD_DEAD; - - pev->framerate = 0; - pev->effects = EF_NOINTERP; - - UTIL_SetSize( pev, Vector(0,0,0), Vector(0,0,0) ); - pev->movetype = MOVETYPE_TOSS; - - SetThink ( &CFlockingFlyer::FallHack ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CFlockingFlyer :: FallHack( void ) -{ - if ( pev->flags & FL_ONGROUND ) - { - if ( !FClassnameIs ( pev->groundentity, "worldspawn" ) ) - { - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - pev->velocity = g_vecZero; - SetThink( NULL ); - } - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: SpawnCommonCode( ) -{ - pev->deadflag = DEAD_NO; - pev->classname = MAKE_STRING("monster_flyer"); - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->takedamage = DAMAGE_NO; - pev->health = 1; - - m_fPathBlocked = FALSE;// obstacles will be detected - m_flFieldOfView = 0.2; - - //SET_MODEL(ENT(pev), "models/aflock.mdl"); - SET_MODEL(ENT(pev), "models/boid.mdl"); - -// UTIL_SetSize(pev, Vector(0,0,0), Vector(0,0,0)); - UTIL_SetSize(pev, Vector(-5,-5,0), Vector(5,5,2)); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: BoidAdvanceFrame ( ) -{ - float flapspeed = (pev->speed - pev->armorvalue) / AFLOCK_ACCELERATE; - pev->armorvalue = pev->armorvalue * .8 + pev->speed * .2; - - if (flapspeed < 0) flapspeed = -flapspeed; - if (flapspeed < 0.25) flapspeed = 0.25; - if (flapspeed > 1.9) flapspeed = 1.9; - - pev->framerate = flapspeed; - - // lean - pev->avelocity.x = - (pev->angles.x + flapspeed * 5); - - // bank - pev->avelocity.z = - (pev->angles.z + pev->avelocity.y); - - // pev->framerate = flapspeed; - StudioFrameAdvance( 0.1 ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: IdleThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.2; - - // see if there's a client in the same pvs as the monster - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - SetThink( &CFlockingFlyer::Start ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -//========================================================= -// Start - player enters the pvs, so get things going. -//========================================================= -void CFlockingFlyer :: Start( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( IsLeader() ) - { - SetThink( &CFlockingFlyer::FlockLeaderThink ); - } - else - { - SetThink( &CFlockingFlyer::FlockFollowerThink ); - } - -/* - Vector vecTakeOff; - vecTakeOff = Vector ( 0 , 0 , 0 ); - - vecTakeOff.z = 50 + RANDOM_FLOAT ( 0, 100 ); - vecTakeOff.x = 20 - RANDOM_FLOAT ( 0, 40); - vecTakeOff.y = 20 - RANDOM_FLOAT ( 0, 40); - - pev->velocity = vecTakeOff; - - - pev->speed = pev->velocity.Length(); - pev->sequence = 0; -*/ - SetActivity ( ACT_FLY ); - ResetSequenceInfo( ); - BoidAdvanceFrame( ); - - pev->speed = AFLOCK_FLY_SPEED;// no delay! -} - -//========================================================= -// Leader boid calls this to form a flock from surrounding boids -//========================================================= -void CFlockingFlyer :: FormFlock( void ) -{ - if ( !InSquad() ) - { - // I am my own leader - m_pSquadLeader = this; - m_pSquadNext = NULL; - int squadCount = 1; - - CBaseEntity *pEntity = NULL; - - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, AFLOCK_MAX_RECRUIT_RADIUS )) != NULL) - { - CBaseMonster *pRecruit = pEntity->MyMonsterPointer( ); - - if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) - { - // Can we recruit this guy? - if ( FClassnameIs ( pRecruit->pev, "monster_flyer" ) ) - { - squadCount++; - SquadAdd( (CFlockingFlyer *)pRecruit ); - } - } - } - } - - SetThink( &CFlockingFlyer::IdleThink );// now that flock is formed, go to idle and wait for a player to come along. - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// Searches for boids that are too close and pushes them away -//========================================================= -void CFlockingFlyer :: SpreadFlock( ) -{ - Vector vecDir; - float flSpeed;// holds vector magnitude while we fiddle with the direction - - CFlockingFlyer *pList = m_pSquadLeader; - while ( pList ) - { - if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) - { - // push the other away - vecDir = ( pList->pev->origin - pev->origin ); - vecDir = vecDir.Normalize(); - - // store the magnitude of the other boid's velocity, and normalize it so we - // can average in a course that points away from the leader. - flSpeed = pList->pev->velocity.Length(); - pList->pev->velocity = pList->pev->velocity.Normalize(); - pList->pev->velocity = ( pList->pev->velocity + vecDir ) * 0.5; - pList->pev->velocity = pList->pev->velocity * flSpeed; - } - - pList = pList->m_pSquadNext; - } -} - -//========================================================= -// Alters the caller's course if he's too close to others -// -// This function should **ONLY** be called when Caller's velocity is normalized!! -//========================================================= -void CFlockingFlyer :: SpreadFlock2 ( ) -{ - Vector vecDir; - - CFlockingFlyer *pList = m_pSquadLeader; - while ( pList ) - { - if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) - { - vecDir = ( pev->origin - pList->pev->origin ); - vecDir = vecDir.Normalize(); - - pev->velocity = (pev->velocity + vecDir); - } - - pList = pList->m_pSquadNext; - } -} - -//========================================================= -// FBoidPathBlocked - returns TRUE if there is an obstacle ahead -//========================================================= -BOOL CFlockingFlyer :: FPathBlocked( ) -{ - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - BOOL fBlocked; - - if ( m_flFakeBlockedTime > gpGlobals->time ) - { - m_flLastBlockedTime = gpGlobals->time; - return TRUE; - } - - // use VELOCITY, not angles, not all boids point the direction they are flying - //vecDir = UTIL_VecToAngles( pevBoid->velocity ); - UTIL_MakeVectors ( pev->angles ); - - fBlocked = FALSE;// assume the way ahead is clear - - // check for obstacle ahead - UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - // extra wide checks - UTIL_TraceLine(pev->origin + gpGlobals->v_right * 12, pev->origin + gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - UTIL_TraceLine(pev->origin - gpGlobals->v_right * 12, pev->origin - gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - if ( !fBlocked && gpGlobals->time - m_flLastBlockedTime > 6 ) - { - // not blocked, and it's been a few seconds since we've actually been blocked. - m_flFakeBlockedTime = gpGlobals->time + RANDOM_LONG(1, 3); - } - - return fBlocked; -} - - -//========================================================= -// Leader boids use this think every tenth -//========================================================= -void CFlockingFlyer :: FlockLeaderThink( void ) -{ - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - int cProcessed = 0;// keep track of how many other boids we've processed - float flLeftSide; - float flRightSide; - - - pev->nextthink = gpGlobals->time + 0.1; - - UTIL_MakeVectors ( pev->angles ); - - // is the way ahead clear? - if ( !FPathBlocked () ) - { - // if the boid is turning, stop the trend. - if ( m_fTurning ) - { - m_fTurning = FALSE; - pev->avelocity.y = 0; - } - - m_fPathBlocked = FALSE; - - if (pev->speed <= AFLOCK_FLY_SPEED ) - pev->speed+= 5; - - pev->velocity = gpGlobals->v_forward * pev->speed; - - BoidAdvanceFrame( ); - - return; - } - - // IF we get this far in the function, the leader's path is blocked! - m_fPathBlocked = TRUE; - - if ( !m_fTurning)// something in the way and boid is not already turning to avoid - { - // measure clearance on left and right to pick the best dir to turn - UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flRightSide = vecDist.Length(); - - UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flLeftSide = vecDist.Length(); - - // turn right if more clearance on right side - if ( flRightSide > flLeftSide ) - { - pev->avelocity.y = -AFLOCK_TURN_RATE; - m_fTurning = TRUE; - } - // default to left turn :) - else if ( flLeftSide > flRightSide ) - { - pev->avelocity.y = AFLOCK_TURN_RATE; - m_fTurning = TRUE; - } - else - { - // equidistant. Pick randomly between left and right. - m_fTurning = TRUE; - - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - pev->avelocity.y = AFLOCK_TURN_RATE; - } - else - { - pev->avelocity.y = -AFLOCK_TURN_RATE; - } - } - } - SpreadFlock( ); - - pev->velocity = gpGlobals->v_forward * pev->speed; - - // check and make sure we aren't about to plow into the ground, don't let it happen - UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_up * 16, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0 && pev->velocity.z < 0 ) - pev->velocity.z = 0; - - // maybe it did, though. - if ( FBitSet (pev->flags, FL_ONGROUND) ) - { - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1 ) ); - pev->velocity.z = 0; - } - - if ( m_flFlockNextSoundTime < gpGlobals->time ) - { - MakeSound(); - m_flFlockNextSoundTime = gpGlobals->time + RANDOM_FLOAT( 1, 3 ); - } - - BoidAdvanceFrame( ); - - return; -} - -//========================================================= -// follower boids execute this code when flocking -//========================================================= -void CFlockingFlyer :: FlockFollowerThink( void ) -{ - TraceResult tr; - Vector vecDist; - Vector vecDir; - Vector vecDirToLeader; - float flDistToLeader; - - pev->nextthink = gpGlobals->time + 0.1; - - if ( IsLeader() || !InSquad() ) - { - // the leader has been killed and this flyer suddenly finds himself the leader. - SetThink ( &CFlockingFlyer::FlockLeaderThink ); - return; - } - - vecDirToLeader = ( m_pSquadLeader->pev->origin - pev->origin ); - flDistToLeader = vecDirToLeader.Length(); - - // match heading with leader - pev->angles = m_pSquadLeader->pev->angles; - - // - // We can see the leader, so try to catch up to it - // - if ( FInViewCone ( m_pSquadLeader ) ) - { - // if we're too far away, speed up - if ( flDistToLeader > AFLOCK_TOO_FAR ) - { - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 1.5; - } - - // if we're too close, slow down - else if ( flDistToLeader < AFLOCK_TOO_CLOSE ) - { - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; - } - } - else - { - // wait up! the leader isn't out in front, so we slow down to let him pass - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; - } - - SpreadFlock2(); - - pev->speed = pev->velocity.Length(); - pev->velocity = pev->velocity.Normalize(); - - // if we are too far from leader, average a vector towards it into our current velocity - if ( flDistToLeader > AFLOCK_TOO_FAR ) - { - vecDirToLeader = vecDirToLeader.Normalize(); - pev->velocity = (pev->velocity + vecDirToLeader) * 0.5; - } - - // clamp speeds and handle acceleration - if ( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 ) - { - m_flGoalSpeed = AFLOCK_FLY_SPEED * 2; - } - - if ( pev->speed < m_flGoalSpeed ) - { - pev->speed += AFLOCK_ACCELERATE; - } - else if ( pev->speed > m_flGoalSpeed ) - { - pev->speed -= AFLOCK_ACCELERATE; - } - - pev->velocity = pev->velocity * pev->speed; - - BoidAdvanceFrame( ); -} - -/* - // Is this boid's course blocked? - if ( FBoidPathBlocked (pev) ) - { - // course is still blocked from last time. Just keep flying along adjusted - // velocity - if ( m_fCourseAdjust ) - { - pev->velocity = m_vecAdjustedVelocity * pev->speed; - return; - } - else // set course adjust flag and calculate adjusted velocity - { - m_fCourseAdjust = TRUE; - - // use VELOCITY, not angles, not all boids point the direction they are flying - //vecDir = UTIL_VecToAngles( pev->velocity ); - //UTIL_MakeVectors ( vecDir ); - - UTIL_MakeVectors ( pev->angles ); - - // measure clearance on left and right to pick the best dir to turn - UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flRightSide = vecDist.Length(); - - UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flLeftSide = vecDist.Length(); - - // slide right if more clearance on right side - if ( flRightSide > flLeftSide ) - { - m_vecAdjustedVelocity = gpGlobals->v_right; - } - // else slide left - else - { - m_vecAdjustedVelocity = gpGlobals->v_right * -1; - } - } - return; - } - - // if we make it this far, boids path is CLEAR! - m_fCourseAdjust = FALSE; -*/ - - -//========================================================= -// -// SquadUnlink(), Unlink the squad pointers. -// -//========================================================= -void CFlockingFlyer :: SquadUnlink( void ) -{ - m_pSquadLeader = NULL; - m_pSquadNext = NULL; -} - -//========================================================= -// -// SquadAdd(), add pAdd to my squad -// -//========================================================= -void CFlockingFlyer :: SquadAdd( CFlockingFlyer *pAdd ) -{ - ASSERT( pAdd!=NULL ); - ASSERT( !pAdd->InSquad() ); - ASSERT( this->IsLeader() ); - - pAdd->m_pSquadNext = m_pSquadNext; - m_pSquadNext = pAdd; - pAdd->m_pSquadLeader = this; -} -//========================================================= -// -// SquadRemove(), remove pRemove from my squad. -// If I am pRemove, promote m_pSquadNext to leader -// -//========================================================= -void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) -{ - ASSERT( pRemove!=NULL ); - ASSERT( this->IsLeader() ); - ASSERT( pRemove->m_pSquadLeader == this ); - - if ( SquadCount() > 2 ) - { - // Removing the leader, promote m_pSquadNext to leader - if ( pRemove == this ) - { - CFlockingFlyer *pLeader = m_pSquadNext; - - // copy the enemy LKP to the new leader - pLeader->m_vecEnemyLKP = m_vecEnemyLKP; - - if ( pLeader ) - { - CFlockingFlyer *pList = pLeader; - - while ( pList ) - { - pList->m_pSquadLeader = pLeader; - pList = pList->m_pSquadNext; - } - - } - SquadUnlink(); - } - else // removing a node - { - CFlockingFlyer *pList = this; - - // Find the node before pRemove - while ( pList->m_pSquadNext != pRemove ) - { - // assert to test valid list construction - ASSERT( pList->m_pSquadNext != NULL ); - pList = pList->m_pSquadNext; - } - // List validity - ASSERT( pList->m_pSquadNext == pRemove ); - - // Relink without pRemove - pList->m_pSquadNext = pRemove->m_pSquadNext; - - // Unlink pRemove - pRemove->SquadUnlink(); - } - } - else - SquadDisband(); -} -//========================================================= -// -// SquadCount(), return the number of members of this squad -// callable from leaders & followers -// -//========================================================= -int CFlockingFlyer :: SquadCount( void ) -{ - CFlockingFlyer *pList = m_pSquadLeader; - int squadCount = 0; - while ( pList ) - { - squadCount++; - pList = pList->m_pSquadNext; - } - - return squadCount; -} - -//========================================================= -// -// SquadDisband(), Unlink all squad members -// -//========================================================= -void CFlockingFlyer :: SquadDisband( void ) -{ - CFlockingFlyer *pList = m_pSquadLeader; - CFlockingFlyer *pNext; - - while ( pList ) - { - pNext = pList->m_pSquadNext; - pList->SquadUnlink(); - pList = pNext; - } -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "squadmonster.h" + +#define AFLOCK_MAX_RECRUIT_RADIUS 1024 +#define AFLOCK_FLY_SPEED 125 +#define AFLOCK_TURN_RATE 75 +#define AFLOCK_ACCELERATE 10 +#define AFLOCK_CHECK_DIST 192 +#define AFLOCK_TOO_CLOSE 100 +#define AFLOCK_TOO_FAR 256 + +//========================================================= +//========================================================= +class CFlockingFlyerFlock : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + void SpawnFlock( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + // Sounds are shared by the flock + static void PrecacheFlockSounds( void ); + + int m_cFlockSize; + float m_flFlockRadius; +}; + +TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = +{ + DEFINE_FIELD( CFlockingFlyerFlock, m_cFlockSize, FIELD_INTEGER ), + DEFINE_FIELD( CFlockingFlyerFlock, m_flFlockRadius, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CFlockingFlyerFlock, CBaseMonster ); + +//========================================================= +//========================================================= +class CFlockingFlyer : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SpawnCommonCode( void ); + void EXPORT IdleThink( void ); + void BoidAdvanceFrame( void ); + void EXPORT FormFlock( void ); + void EXPORT Start( void ); + void EXPORT FlockLeaderThink( void ); + void EXPORT FlockFollowerThink( void ); + void EXPORT FallHack( void ); + void MakeSound( void ); + void AlertFlock( void ); + void SpreadFlock( void ); + void SpreadFlock2( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + void Poop ( void ); + BOOL FPathBlocked( void ); + //void KeyValue( KeyValueData *pkvd ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int IsLeader( void ) { return m_pSquadLeader == this; } + int InSquad( void ) { return m_pSquadLeader != NULL; } + int SquadCount( void ); + void SquadRemove( CFlockingFlyer *pRemove ); + void SquadUnlink( void ); + void SquadAdd( CFlockingFlyer *pAdd ); + void SquadDisband( void ); + + CFlockingFlyer *m_pSquadLeader; + CFlockingFlyer *m_pSquadNext; + BOOL m_fTurning;// is this boid turning? + BOOL m_fCourseAdjust;// followers set this flag TRUE to override flocking while they avoid something + BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead + Vector m_vecReferencePoint;// last place we saw leader + Vector m_vecAdjustedVelocity;// adjusted velocity (used when fCourseAdjust is TRUE) + float m_flGoalSpeed; + float m_flLastBlockedTime; + float m_flFakeBlockedTime; + float m_flAlertTime; + float m_flFlockNextSoundTime; +}; +LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer ); +LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock ); + +TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = +{ + DEFINE_FIELD( CFlockingFlyer, m_pSquadLeader, FIELD_CLASSPTR ), + DEFINE_FIELD( CFlockingFlyer, m_pSquadNext, FIELD_CLASSPTR ), + DEFINE_FIELD( CFlockingFlyer, m_fTurning, FIELD_BOOLEAN ), + DEFINE_FIELD( CFlockingFlyer, m_fCourseAdjust, FIELD_BOOLEAN ), + DEFINE_FIELD( CFlockingFlyer, m_fPathBlocked, FIELD_BOOLEAN ), + DEFINE_FIELD( CFlockingFlyer, m_vecReferencePoint, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CFlockingFlyer, m_vecAdjustedVelocity, FIELD_VECTOR ), + DEFINE_FIELD( CFlockingFlyer, m_flGoalSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CFlockingFlyer, m_flLastBlockedTime, FIELD_TIME ), + DEFINE_FIELD( CFlockingFlyer, m_flFakeBlockedTime, FIELD_TIME ), + DEFINE_FIELD( CFlockingFlyer, m_flAlertTime, FIELD_TIME ), +// DEFINE_FIELD( CFlockingFlyer, m_flFlockNextSoundTime, FIELD_TIME ), // don't need to save +}; + +IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ); + +//========================================================= +//========================================================= +void CFlockingFlyerFlock :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "iFlockSize")) + { + m_cFlockSize = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "flFlockRadius")) + { + m_flFlockRadius = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } +} + +//========================================================= +//========================================================= +void CFlockingFlyerFlock :: Spawn( ) +{ + Precache( ); + SpawnFlock(); + + REMOVE_ENTITY(ENT(pev)); // dump the spawn ent +} + +//========================================================= +//========================================================= +void CFlockingFlyerFlock :: Precache( ) +{ + //PRECACHE_MODEL("models/aflock.mdl"); + PRECACHE_MODEL("models/boid.mdl"); + + PrecacheFlockSounds(); +} + + +void CFlockingFlyerFlock :: PrecacheFlockSounds( void ) +{ + PRECACHE_SOUND("boid/boid_alert1.wav" ); + PRECACHE_SOUND("boid/boid_alert2.wav" ); + + PRECACHE_SOUND("boid/boid_idle1.wav" ); + PRECACHE_SOUND("boid/boid_idle2.wav" ); +} + +//========================================================= +//========================================================= +void CFlockingFlyerFlock :: SpawnFlock( void ) +{ + float R = m_flFlockRadius; + int iCount; + Vector vecSpot; + CFlockingFlyer *pBoid, *pLeader; + + pLeader = pBoid = NULL; + + for ( iCount = 0 ; iCount < m_cFlockSize ; iCount++ ) + { + pBoid = GetClassPtr( (CFlockingFlyer *)NULL ); + + if ( !pLeader ) + { + // make this guy the leader. + pLeader = pBoid; + + pLeader->m_pSquadLeader = pLeader; + pLeader->m_pSquadNext = NULL; + } + + vecSpot.x = RANDOM_FLOAT( -R, R ); + vecSpot.y = RANDOM_FLOAT( -R, R ); + vecSpot.z = RANDOM_FLOAT( 0, 16 ); + vecSpot = pev->origin + vecSpot; + + UTIL_SetOrigin(pBoid->pev, vecSpot); + pBoid->pev->movetype = MOVETYPE_FLY; + pBoid->SpawnCommonCode(); + pBoid->pev->flags &= ~FL_ONGROUND; + pBoid->pev->velocity = g_vecZero; + pBoid->pev->angles = pev->angles; + + pBoid->pev->frame = 0; + pBoid->pev->nextthink = gpGlobals->time + 0.2; + pBoid->SetThink( &CFlockingFlyer :: IdleThink ); + + if ( pBoid != pLeader ) + { + pLeader->SquadAdd( pBoid ); + } + } +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: Spawn( ) +{ + Precache( ); + SpawnCommonCode(); + + pev->frame = 0; + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CFlockingFlyer::IdleThink ); +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: Precache( ) +{ + //PRECACHE_MODEL("models/aflock.mdl"); + PRECACHE_MODEL("models/boid.mdl"); + CFlockingFlyerFlock::PrecacheFlockSounds(); +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: MakeSound( void ) +{ + if ( m_flAlertTime > gpGlobals->time ) + { + // make agitated sounds + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_alert1.wav", 1, ATTN_NORM ); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_alert2.wav", 1, ATTN_NORM ); break; + } + + return; + } + + // make normal sound + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle1.wav", 1, ATTN_NORM ); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle2.wav", 1, ATTN_NORM ); break; + } +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: Killed( entvars_t *pevAttacker, int iGib ) +{ + CFlockingFlyer *pSquad; + + pSquad = (CFlockingFlyer *)m_pSquadLeader; + + while ( pSquad ) + { + pSquad->m_flAlertTime = gpGlobals->time + 15; + pSquad = (CFlockingFlyer *)pSquad->m_pSquadNext; + } + + if ( m_pSquadLeader ) + { + m_pSquadLeader->SquadRemove( this ); + } + + pev->deadflag = DEAD_DEAD; + + pev->framerate = 0; + pev->effects = EF_NOINTERP; + + UTIL_SetSize( pev, Vector(0,0,0), Vector(0,0,0) ); + pev->movetype = MOVETYPE_TOSS; + + SetThink ( &CFlockingFlyer::FallHack ); + pev->nextthink = gpGlobals->time + 0.1; +} + +void CFlockingFlyer :: FallHack( void ) +{ + if ( pev->flags & FL_ONGROUND ) + { + if ( !FClassnameIs ( pev->groundentity, "worldspawn" ) ) + { + pev->flags &= ~FL_ONGROUND; + pev->nextthink = gpGlobals->time + 0.1; + } + else + { + pev->velocity = g_vecZero; + SetThink( NULL ); + } + } +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: SpawnCommonCode( ) +{ + pev->deadflag = DEAD_NO; + pev->classname = MAKE_STRING("monster_flyer"); + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_FLY; + pev->takedamage = DAMAGE_NO; + pev->health = 1; + + m_fPathBlocked = FALSE;// obstacles will be detected + m_flFieldOfView = 0.2; + + //SET_MODEL(ENT(pev), "models/aflock.mdl"); + SET_MODEL(ENT(pev), "models/boid.mdl"); + +// UTIL_SetSize(pev, Vector(0,0,0), Vector(0,0,0)); + UTIL_SetSize(pev, Vector(-5,-5,0), Vector(5,5,2)); +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: BoidAdvanceFrame ( ) +{ + float flapspeed = (pev->speed - pev->armorvalue) / AFLOCK_ACCELERATE; + pev->armorvalue = pev->armorvalue * .8 + pev->speed * .2; + + if (flapspeed < 0) flapspeed = -flapspeed; + if (flapspeed < 0.25) flapspeed = 0.25; + if (flapspeed > 1.9) flapspeed = 1.9; + + pev->framerate = flapspeed; + + // lean + pev->avelocity.x = - (pev->angles.x + flapspeed * 5); + + // bank + pev->avelocity.z = - (pev->angles.z + pev->avelocity.y); + + // pev->framerate = flapspeed; + StudioFrameAdvance( 0.1 ); +} + +//========================================================= +//========================================================= +void CFlockingFlyer :: IdleThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.2; + + // see if there's a client in the same pvs as the monster + if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + { + SetThink( &CFlockingFlyer::Start ); + pev->nextthink = gpGlobals->time + 0.1; + } +} + +//========================================================= +// Start - player enters the pvs, so get things going. +//========================================================= +void CFlockingFlyer :: Start( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if ( IsLeader() ) + { + SetThink( &CFlockingFlyer::FlockLeaderThink ); + } + else + { + SetThink( &CFlockingFlyer::FlockFollowerThink ); + } + +/* + Vector vecTakeOff; + vecTakeOff = Vector ( 0 , 0 , 0 ); + + vecTakeOff.z = 50 + RANDOM_FLOAT ( 0, 100 ); + vecTakeOff.x = 20 - RANDOM_FLOAT ( 0, 40); + vecTakeOff.y = 20 - RANDOM_FLOAT ( 0, 40); + + pev->velocity = vecTakeOff; + + + pev->speed = pev->velocity.Length(); + pev->sequence = 0; +*/ + SetActivity ( ACT_FLY ); + ResetSequenceInfo( ); + BoidAdvanceFrame( ); + + pev->speed = AFLOCK_FLY_SPEED;// no delay! +} + +//========================================================= +// Leader boid calls this to form a flock from surrounding boids +//========================================================= +void CFlockingFlyer :: FormFlock( void ) +{ + if ( !InSquad() ) + { + // I am my own leader + m_pSquadLeader = this; + m_pSquadNext = NULL; + int squadCount = 1; + + CBaseEntity *pEntity = NULL; + + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, AFLOCK_MAX_RECRUIT_RADIUS )) != NULL) + { + CBaseMonster *pRecruit = pEntity->MyMonsterPointer( ); + + if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) + { + // Can we recruit this guy? + if ( FClassnameIs ( pRecruit->pev, "monster_flyer" ) ) + { + squadCount++; + SquadAdd( (CFlockingFlyer *)pRecruit ); + } + } + } + } + + SetThink( &CFlockingFlyer::IdleThink );// now that flock is formed, go to idle and wait for a player to come along. + pev->nextthink = gpGlobals->time; +} + +//========================================================= +// Searches for boids that are too close and pushes them away +//========================================================= +void CFlockingFlyer :: SpreadFlock( ) +{ + Vector vecDir; + float flSpeed;// holds vector magnitude while we fiddle with the direction + + CFlockingFlyer *pList = m_pSquadLeader; + while ( pList ) + { + if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) + { + // push the other away + vecDir = ( pList->pev->origin - pev->origin ); + vecDir = vecDir.Normalize(); + + // store the magnitude of the other boid's velocity, and normalize it so we + // can average in a course that points away from the leader. + flSpeed = pList->pev->velocity.Length(); + pList->pev->velocity = pList->pev->velocity.Normalize(); + pList->pev->velocity = ( pList->pev->velocity + vecDir ) * 0.5; + pList->pev->velocity = pList->pev->velocity * flSpeed; + } + + pList = pList->m_pSquadNext; + } +} + +//========================================================= +// Alters the caller's course if he's too close to others +// +// This function should **ONLY** be called when Caller's velocity is normalized!! +//========================================================= +void CFlockingFlyer :: SpreadFlock2 ( ) +{ + Vector vecDir; + + CFlockingFlyer *pList = m_pSquadLeader; + while ( pList ) + { + if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) + { + vecDir = ( pev->origin - pList->pev->origin ); + vecDir = vecDir.Normalize(); + + pev->velocity = (pev->velocity + vecDir); + } + + pList = pList->m_pSquadNext; + } +} + +//========================================================= +// FBoidPathBlocked - returns TRUE if there is an obstacle ahead +//========================================================= +BOOL CFlockingFlyer :: FPathBlocked( ) +{ + TraceResult tr; + Vector vecDist;// used for general measurements + Vector vecDir;// used for general measurements + BOOL fBlocked; + + if ( m_flFakeBlockedTime > gpGlobals->time ) + { + m_flLastBlockedTime = gpGlobals->time; + return TRUE; + } + + // use VELOCITY, not angles, not all boids point the direction they are flying + //vecDir = UTIL_VecToAngles( pevBoid->velocity ); + UTIL_MakeVectors ( pev->angles ); + + fBlocked = FALSE;// assume the way ahead is clear + + // check for obstacle ahead + UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + m_flLastBlockedTime = gpGlobals->time; + fBlocked = TRUE; + } + + // extra wide checks + UTIL_TraceLine(pev->origin + gpGlobals->v_right * 12, pev->origin + gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + m_flLastBlockedTime = gpGlobals->time; + fBlocked = TRUE; + } + + UTIL_TraceLine(pev->origin - gpGlobals->v_right * 12, pev->origin - gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + m_flLastBlockedTime = gpGlobals->time; + fBlocked = TRUE; + } + + if ( !fBlocked && gpGlobals->time - m_flLastBlockedTime > 6 ) + { + // not blocked, and it's been a few seconds since we've actually been blocked. + m_flFakeBlockedTime = gpGlobals->time + RANDOM_LONG(1, 3); + } + + return fBlocked; +} + + +//========================================================= +// Leader boids use this think every tenth +//========================================================= +void CFlockingFlyer :: FlockLeaderThink( void ) +{ + TraceResult tr; + Vector vecDist;// used for general measurements + Vector vecDir;// used for general measurements + int cProcessed = 0;// keep track of how many other boids we've processed + float flLeftSide; + float flRightSide; + + + pev->nextthink = gpGlobals->time + 0.1; + + UTIL_MakeVectors ( pev->angles ); + + // is the way ahead clear? + if ( !FPathBlocked () ) + { + // if the boid is turning, stop the trend. + if ( m_fTurning ) + { + m_fTurning = FALSE; + pev->avelocity.y = 0; + } + + m_fPathBlocked = FALSE; + + if (pev->speed <= AFLOCK_FLY_SPEED ) + pev->speed+= 5; + + pev->velocity = gpGlobals->v_forward * pev->speed; + + BoidAdvanceFrame( ); + + return; + } + + // IF we get this far in the function, the leader's path is blocked! + m_fPathBlocked = TRUE; + + if ( !m_fTurning)// something in the way and boid is not already turning to avoid + { + // measure clearance on left and right to pick the best dir to turn + UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + vecDist = (tr.vecEndPos - pev->origin); + flRightSide = vecDist.Length(); + + UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + vecDist = (tr.vecEndPos - pev->origin); + flLeftSide = vecDist.Length(); + + // turn right if more clearance on right side + if ( flRightSide > flLeftSide ) + { + pev->avelocity.y = -AFLOCK_TURN_RATE; + m_fTurning = TRUE; + } + // default to left turn :) + else if ( flLeftSide > flRightSide ) + { + pev->avelocity.y = AFLOCK_TURN_RATE; + m_fTurning = TRUE; + } + else + { + // equidistant. Pick randomly between left and right. + m_fTurning = TRUE; + + if ( RANDOM_LONG( 0, 1 ) == 0 ) + { + pev->avelocity.y = AFLOCK_TURN_RATE; + } + else + { + pev->avelocity.y = -AFLOCK_TURN_RATE; + } + } + } + SpreadFlock( ); + + pev->velocity = gpGlobals->v_forward * pev->speed; + + // check and make sure we aren't about to plow into the ground, don't let it happen + UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_up * 16, ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0 && pev->velocity.z < 0 ) + pev->velocity.z = 0; + + // maybe it did, though. + if ( FBitSet (pev->flags, FL_ONGROUND) ) + { + UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1 ) ); + pev->velocity.z = 0; + } + + if ( m_flFlockNextSoundTime < gpGlobals->time ) + { + MakeSound(); + m_flFlockNextSoundTime = gpGlobals->time + RANDOM_FLOAT( 1, 3 ); + } + + BoidAdvanceFrame( ); + + return; +} + +//========================================================= +// follower boids execute this code when flocking +//========================================================= +void CFlockingFlyer :: FlockFollowerThink( void ) +{ + TraceResult tr; + Vector vecDist; + Vector vecDir; + Vector vecDirToLeader; + float flDistToLeader; + + pev->nextthink = gpGlobals->time + 0.1; + + if ( IsLeader() || !InSquad() ) + { + // the leader has been killed and this flyer suddenly finds himself the leader. + SetThink ( &CFlockingFlyer::FlockLeaderThink ); + return; + } + + vecDirToLeader = ( m_pSquadLeader->pev->origin - pev->origin ); + flDistToLeader = vecDirToLeader.Length(); + + // match heading with leader + pev->angles = m_pSquadLeader->pev->angles; + + // + // We can see the leader, so try to catch up to it + // + if ( FInViewCone ( m_pSquadLeader ) ) + { + // if we're too far away, speed up + if ( flDistToLeader > AFLOCK_TOO_FAR ) + { + m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 1.5; + } + + // if we're too close, slow down + else if ( flDistToLeader < AFLOCK_TOO_CLOSE ) + { + m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; + } + } + else + { + // wait up! the leader isn't out in front, so we slow down to let him pass + m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; + } + + SpreadFlock2(); + + pev->speed = pev->velocity.Length(); + pev->velocity = pev->velocity.Normalize(); + + // if we are too far from leader, average a vector towards it into our current velocity + if ( flDistToLeader > AFLOCK_TOO_FAR ) + { + vecDirToLeader = vecDirToLeader.Normalize(); + pev->velocity = (pev->velocity + vecDirToLeader) * 0.5; + } + + // clamp speeds and handle acceleration + if ( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 ) + { + m_flGoalSpeed = AFLOCK_FLY_SPEED * 2; + } + + if ( pev->speed < m_flGoalSpeed ) + { + pev->speed += AFLOCK_ACCELERATE; + } + else if ( pev->speed > m_flGoalSpeed ) + { + pev->speed -= AFLOCK_ACCELERATE; + } + + pev->velocity = pev->velocity * pev->speed; + + BoidAdvanceFrame( ); +} + +/* + // Is this boid's course blocked? + if ( FBoidPathBlocked (pev) ) + { + // course is still blocked from last time. Just keep flying along adjusted + // velocity + if ( m_fCourseAdjust ) + { + pev->velocity = m_vecAdjustedVelocity * pev->speed; + return; + } + else // set course adjust flag and calculate adjusted velocity + { + m_fCourseAdjust = TRUE; + + // use VELOCITY, not angles, not all boids point the direction they are flying + //vecDir = UTIL_VecToAngles( pev->velocity ); + //UTIL_MakeVectors ( vecDir ); + + UTIL_MakeVectors ( pev->angles ); + + // measure clearance on left and right to pick the best dir to turn + UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + vecDist = (tr.vecEndPos - pev->origin); + flRightSide = vecDist.Length(); + + UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); + vecDist = (tr.vecEndPos - pev->origin); + flLeftSide = vecDist.Length(); + + // slide right if more clearance on right side + if ( flRightSide > flLeftSide ) + { + m_vecAdjustedVelocity = gpGlobals->v_right; + } + // else slide left + else + { + m_vecAdjustedVelocity = gpGlobals->v_right * -1; + } + } + return; + } + + // if we make it this far, boids path is CLEAR! + m_fCourseAdjust = FALSE; +*/ + + +//========================================================= +// +// SquadUnlink(), Unlink the squad pointers. +// +//========================================================= +void CFlockingFlyer :: SquadUnlink( void ) +{ + m_pSquadLeader = NULL; + m_pSquadNext = NULL; +} + +//========================================================= +// +// SquadAdd(), add pAdd to my squad +// +//========================================================= +void CFlockingFlyer :: SquadAdd( CFlockingFlyer *pAdd ) +{ + ASSERT( pAdd!=NULL ); + ASSERT( !pAdd->InSquad() ); + ASSERT( this->IsLeader() ); + + pAdd->m_pSquadNext = m_pSquadNext; + m_pSquadNext = pAdd; + pAdd->m_pSquadLeader = this; +} +//========================================================= +// +// SquadRemove(), remove pRemove from my squad. +// If I am pRemove, promote m_pSquadNext to leader +// +//========================================================= +void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) +{ + ASSERT( pRemove!=NULL ); + ASSERT( this->IsLeader() ); + ASSERT( pRemove->m_pSquadLeader == this ); + + if ( SquadCount() > 2 ) + { + // Removing the leader, promote m_pSquadNext to leader + if ( pRemove == this ) + { + CFlockingFlyer *pLeader = m_pSquadNext; + + // copy the enemy LKP to the new leader + pLeader->m_vecEnemyLKP = m_vecEnemyLKP; + + if ( pLeader ) + { + CFlockingFlyer *pList = pLeader; + + while ( pList ) + { + pList->m_pSquadLeader = pLeader; + pList = pList->m_pSquadNext; + } + + } + SquadUnlink(); + } + else // removing a node + { + CFlockingFlyer *pList = this; + + // Find the node before pRemove + while ( pList->m_pSquadNext != pRemove ) + { + // assert to test valid list construction + ASSERT( pList->m_pSquadNext != NULL ); + pList = pList->m_pSquadNext; + } + // List validity + ASSERT( pList->m_pSquadNext == pRemove ); + + // Relink without pRemove + pList->m_pSquadNext = pRemove->m_pSquadNext; + + // Unlink pRemove + pRemove->SquadUnlink(); + } + } + else + SquadDisband(); +} +//========================================================= +// +// SquadCount(), return the number of members of this squad +// callable from leaders & followers +// +//========================================================= +int CFlockingFlyer :: SquadCount( void ) +{ + CFlockingFlyer *pList = m_pSquadLeader; + int squadCount = 0; + while ( pList ) + { + squadCount++; + pList = pList->m_pSquadNext; + } + + return squadCount; +} + +//========================================================= +// +// SquadDisband(), Unlink all squad members +// +//========================================================= +void CFlockingFlyer :: SquadDisband( void ) +{ + CFlockingFlyer *pList = m_pSquadLeader; + CFlockingFlyer *pNext; + + while ( pList ) + { + pNext = pList->m_pSquadNext; + pList->SquadUnlink(); + pList = pNext; + } +} diff --git a/main/source/dlls/agrunt.cpp b/main/source/dlls/agrunt.cpp index 5c60c459..b1294c5c 100644 --- a/main/source/dlls/agrunt.cpp +++ b/main/source/dlls/agrunt.cpp @@ -1,1177 +1,1177 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Agrunt - Dominant, warlike alien grunt monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "weapons.h" -#include "soundent.h" -#include "hornet.h" - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_AGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_AGRUNT_THREAT_DISPLAY, -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_AGRUNT_SETUP_HIDE_ATTACK = LAST_COMMON_TASK + 1, - TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, -}; - -int iAgruntMuzzleFlash; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define AGRUNT_AE_HORNET1 ( 1 ) -#define AGRUNT_AE_HORNET2 ( 2 ) -#define AGRUNT_AE_HORNET3 ( 3 ) -#define AGRUNT_AE_HORNET4 ( 4 ) -#define AGRUNT_AE_HORNET5 ( 5 ) -// some events are set up in the QC file that aren't recognized by the code yet. -#define AGRUNT_AE_PUNCH ( 6 ) -#define AGRUNT_AE_BITE ( 7 ) - -#define AGRUNT_AE_LEFT_FOOT ( 10 ) -#define AGRUNT_AE_RIGHT_FOOT ( 11 ) - -#define AGRUNT_AE_LEFT_PUNCH ( 12 ) -#define AGRUNT_AE_RIGHT_PUNCH ( 13 ) - - - -#define AGRUNT_MELEE_DIST 100 - -class CAGrunt : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -32, -32, 0 ); - pev->absmax = pev->origin + Vector( 32, 32, 85 ); - } - - Schedule_t* GetSchedule ( void ); - Schedule_t* GetScheduleOfType ( int Type ); - BOOL FCanCheckAttacks ( void ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - void StartTask ( Task_t *pTask ); - void AlertSound( void ); - void DeathSound ( void ); - void PainSound ( void ); - void AttackSound ( void ); - void PrescheduleThink ( void ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int IRelationship( CBaseEntity *pTarget ); - void StopTalking ( void ); - BOOL ShouldSpeak( void ); - CUSTOM_SCHEDULES; - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - static const char *pAttackSounds[]; - static const char *pDieSounds[]; - static const char *pPainSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - - BOOL m_fCanHornetAttack; - float m_flNextHornetAttackCheck; - - float m_flNextPainTime; - - // three hacky fields for speech stuff. These don't really need to be saved. - float m_flNextSpeakTime; - float m_flNextWordTime; - int m_iLastWord; -}; -LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ); - -TYPEDESCRIPTION CAGrunt::m_SaveData[] = -{ - DEFINE_FIELD( CAGrunt, m_fCanHornetAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CAGrunt, m_flNextHornetAttackCheck, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextPainTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextSpeakTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextWordTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_iLastWord, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ); - -const char *CAGrunt::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CAGrunt::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CAGrunt::pAttackSounds[] = -{ - "agrunt/ag_attack1.wav", - "agrunt/ag_attack2.wav", - "agrunt/ag_attack3.wav", -}; - -const char *CAGrunt::pDieSounds[] = -{ - "agrunt/ag_die1.wav", - "agrunt/ag_die4.wav", - "agrunt/ag_die5.wav", -}; - -const char *CAGrunt::pPainSounds[] = -{ - "agrunt/ag_pain1.wav", - "agrunt/ag_pain2.wav", - "agrunt/ag_pain3.wav", - "agrunt/ag_pain4.wav", - "agrunt/ag_pain5.wav", -}; - -const char *CAGrunt::pIdleSounds[] = -{ - "agrunt/ag_idle1.wav", - "agrunt/ag_idle2.wav", - "agrunt/ag_idle3.wav", - "agrunt/ag_idle4.wav", -}; - -const char *CAGrunt::pAlertSounds[] = -{ - "agrunt/ag_alert1.wav", - "agrunt/ag_alert3.wav", - "agrunt/ag_alert4.wav", - "agrunt/ag_alert5.wav", -}; - -//========================================================= -// IRelationship - overridden because Human Grunts are -// Alien Grunt's nemesis. -//========================================================= -int CAGrunt::IRelationship ( CBaseEntity *pTarget ) -{ - if ( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) - { - return R_NM; - } - - return CSquadMonster :: IRelationship( pTarget ); -} - -//========================================================= -// ISoundMask -//========================================================= -int CAGrunt :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// TraceAttack -//========================================================= -void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( ptr->iHitgroup == 10 && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))) - { - // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - Vector vecTracerDir = vecDir; - - vecTracerDir.x += RANDOM_FLOAT( -0.3, 0.3 ); - vecTracerDir.y += RANDOM_FLOAT( -0.3, 0.3 ); - vecTracerDir.z += RANDOM_FLOAT( -0.3, 0.3 ); - - vecTracerDir = vecTracerDir * -512; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, ptr->vecEndPos ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( vecTracerDir.x ); - WRITE_COORD( vecTracerDir.y ); - WRITE_COORD( vecTracerDir.z ); - MESSAGE_END(); - } - - flDamage -= 20; - if (flDamage <= 0) - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - else - { - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -//========================================================= -// StopTalking - won't speak again for 10-20 seconds. -//========================================================= -void CAGrunt::StopTalking( void ) -{ - m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); -} - -//========================================================= -// ShouldSpeak - Should this agrunt be talking? -//========================================================= -BOOL CAGrunt::ShouldSpeak( void ) -{ - if ( m_flNextSpeakTime > gpGlobals->time ) - { - // my time to talk is still in the future. - return FALSE; - } - - if ( pev->spawnflags & SF_MONSTER_GAG ) - { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // if gagged, don't talk outside of combat. - // if not going to talk because of this, put the talk time - // into the future a bit, so we don't talk immediately after - // going into combat - m_flNextSpeakTime = gpGlobals->time + 3; - return FALSE; - } - } - - return TRUE; -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CAGrunt :: PrescheduleThink ( void ) -{ - if ( ShouldSpeak() ) - { - if ( m_flNextWordTime < gpGlobals->time ) - { - int num = -1; - - do - { - num = RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1); - } while( num == m_iLastWord ); - - m_iLastWord = num; - - // play a new sound - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pIdleSounds[ num ], 1.0, ATTN_NORM ); - - // is this word our last? - if ( RANDOM_LONG( 1, 10 ) <= 1 ) - { - // stop talking. - StopTalking(); - } - else - { - m_flNextWordTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); - } - } - } -} - -//========================================================= -// DieSound -//========================================================= -void CAGrunt :: DeathSound ( void ) -{ - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pDieSounds[RANDOM_LONG(0,ARRAYSIZE(pDieSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// AlertSound -//========================================================= -void CAGrunt :: AlertSound ( void ) -{ - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAlertSounds[RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// AttackSound -//========================================================= -void CAGrunt :: AttackSound ( void ) -{ - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAttackSounds[RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// PainSound -//========================================================= -void CAGrunt :: PainSound ( void ) -{ - if ( m_flNextPainTime > gpGlobals->time ) - { - return; - } - - m_flNextPainTime = gpGlobals->time + 0.6; - - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pPainSounds[RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CAGrunt :: Classify ( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CAGrunt :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 110; - break; - default: ys = 100; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case AGRUNT_AE_HORNET1: - case AGRUNT_AE_HORNET2: - case AGRUNT_AE_HORNET3: - case AGRUNT_AE_HORNET4: - case AGRUNT_AE_HORNET5: - { - // m_vecEnemyLKP should be center of enemy body - Vector vecArmPos, vecArmDir; - Vector vecDirToEnemy; - Vector angDir; - - if (HasConditions( bits_COND_SEE_ENEMY)) - { - vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); - angDir = UTIL_VecToAngles( vecDirToEnemy ); - vecDirToEnemy = vecDirToEnemy.Normalize(); - } - else - { - angDir = pev->angles; - UTIL_MakeAimVectors( angDir ); - vecDirToEnemy = gpGlobals->v_forward; - } - - pev->effects = EF_MUZZLEFLASH; - - // make angles +-180 - if (angDir.x > 180) - { - angDir.x = angDir.x - 360; - } - - SetBlending( 0, angDir.x ); - GetAttachment( 0, vecArmPos, vecArmDir ); - - vecArmPos = vecArmPos + vecDirToEnemy * 32; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecArmPos ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecArmPos.x ); // pos - WRITE_COORD( vecArmPos.y ); - WRITE_COORD( vecArmPos.z ); - WRITE_SHORT( iAgruntMuzzleFlash ); // model - WRITE_BYTE( 6 ); // size * 10 - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); - - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); - UTIL_MakeVectors ( pHornet->pev->angles ); - pHornet->pev->velocity = gpGlobals->v_forward * 300; - - CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer(); - - if ( pHornetMonster ) - { - pHornetMonster->m_hEnemy = m_hEnemy; - } - } - break; - - case AGRUNT_AE_LEFT_FOOT: - switch (RANDOM_LONG(0,1)) - { - // left foot - case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); break; - case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); break; - } - break; - case AGRUNT_AE_RIGHT_FOOT: - // right foot - switch (RANDOM_LONG(0,1)) - { - case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); break; - case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); break; - } - break; - - case AGRUNT_AE_LEFT_PUNCH: - { - CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); - - if ( pHurt ) - { - pHurt->pev->punchangle.y = -25; - pHurt->pev->punchangle.x = 8; - - // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. - if ( pHurt->IsPlayer() ) - { - // this is a player. Knock him around. - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 250; - } - - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - Vector vecArmPos, vecArmAng; - GetAttachment( 0, vecArmPos, vecArmAng ); - SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - } - break; - - case AGRUNT_AE_RIGHT_PUNCH: - { - CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); - - if ( pHurt ) - { - pHurt->pev->punchangle.y = 25; - pHurt->pev->punchangle.x = 8; - - // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. - if ( pHurt->IsPlayer() ) - { - // this is a player. Knock him around. - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -250; - } - - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - Vector vecArmPos, vecArmAng; - GetAttachment( 0, vecArmPos, vecArmAng ); - SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - } - break; - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CAGrunt :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/agrunt.mdl"); - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.agruntHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = 0; - m_afCapability |= bits_CAP_SQUAD; - - m_HackedGunPos = Vector( 24, 64, 48 ); - - m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); - - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CAGrunt :: Precache() -{ - int i; - - PRECACHE_MODEL("models/agrunt.mdl"); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ ) - PRECACHE_SOUND((char *)pDieSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); - - - PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); - - iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" ); - - UTIL_PrecacheOther( "hornet" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// Fail Schedule -//========================================================= -Task_t tlAGruntFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slAGruntFail[] = -{ - { - tlAGruntFail, - ARRAYSIZE ( tlAGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AGrunt Fail" - }, -}; - -//========================================================= -// Combat Fail Schedule -//========================================================= -Task_t tlAGruntCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slAGruntCombatFail[] = -{ - { - tlAGruntCombatFail, - ARRAYSIZE ( tlAGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AGrunt Combat Fail" - }, -}; - -//========================================================= -// Standoff schedule. Used in combat when a monster is -// hiding in cover or the enemy has moved out of sight. -// Should we look around in this schedule? -//========================================================= -Task_t tlAGruntStandoff[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, -}; - -Schedule_t slAGruntStandoff[] = -{ - { - tlAGruntStandoff, - ARRAYSIZE ( tlAGruntStandoff ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Agrunt Standoff" - } -}; - -//========================================================= -// Suppress -//========================================================= -Task_t tlAGruntSuppressHornet[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slAGruntSuppress[] = -{ - { - tlAGruntSuppressHornet, - ARRAYSIZE ( tlAGruntSuppressHornet ), - 0, - 0, - "AGrunt Suppress Hornet", - }, -}; - -//========================================================= -// primary range attacks -//========================================================= -Task_t tlAGruntRangeAttack1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slAGruntRangeAttack1[] = -{ - { - tlAGruntRangeAttack1, - ARRAYSIZE ( tlAGruntRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE, - - 0, - "AGrunt Range Attack1" - }, -}; - - -Task_t tlAGruntHiddenRangeAttack1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_STANDOFF }, - { TASK_AGRUNT_SETUP_HIDE_ATTACK, 0 }, - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, 0 }, - { TASK_RANGE_ATTACK1_NOTURN, (float)0 }, -}; - -Schedule_t slAGruntHiddenRangeAttack[] = -{ - { - tlAGruntHiddenRangeAttack1, - ARRAYSIZE ( tlAGruntHiddenRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AGrunt Hidden Range Attack1" - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAGruntTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAGruntTakeCoverFromEnemy[] = -{ - { - tlAGruntTakeCoverFromEnemy, - ARRAYSIZE ( tlAGruntTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY, - 0, - "AGruntTakeCoverFromEnemy" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlAGruntVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_AGRUNT_THREAT_DISPLAY }, - { TASK_WAIT, (float)0.2 }, - { TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, -}; - -Schedule_t slAGruntVictoryDance[] = -{ - { - tlAGruntVictoryDance, - ARRAYSIZE ( tlAGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "AGruntVictoryDance" - }, -}; - -//========================================================= -//========================================================= -Task_t tlAGruntThreatDisplay[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, -}; - -Schedule_t slAGruntThreatDisplay[] = -{ - { - tlAGruntThreatDisplay, - ARRAYSIZE ( tlAGruntThreatDisplay ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - - bits_SOUND_PLAYER | - bits_SOUND_COMBAT | - bits_SOUND_WORLD, - "AGruntThreatDisplay" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CAGrunt ) -{ - slAGruntFail, - slAGruntCombatFail, - slAGruntStandoff, - slAGruntSuppress, - slAGruntRangeAttack1, - slAGruntHiddenRangeAttack, - slAGruntTakeCoverFromEnemy, - slAGruntVictoryDance, - slAGruntThreatDisplay, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ); - -//========================================================= -// FCanCheckAttacks - this is overridden for alien grunts -// because they can use their smart weapons against unseen -// enemies. Base class doesn't attack anyone it can't see. -//========================================================= -BOOL CAGrunt :: FCanCheckAttacks ( void ) -{ - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// CheckMeleeAttack1 - alien grunts zap the crap out of -// any enemy that gets too close. -//========================================================= -BOOL CAGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( HasConditions ( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != NULL ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 -// -// !!!LATER - we may want to load balance this. Several -// tracelines are done, so we may not want to do this every -// server frame. Definitely not while firing. -//========================================================= -BOOL CAGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( gpGlobals->time < m_flNextHornetAttackCheck ) - { - return m_fCanHornetAttack; - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - Vector vecArmPos, vecArmDir; - - // verify that a shot fired from the gun will hit the enemy before the world. - // !!!LATER - we may wish to do something different for projectile weapons as opposed to instant-hit - UTIL_MakeVectors( pev->angles ); - GetAttachment( 0, vecArmPos, vecArmDir ); -// UTIL_TraceLine( vecArmPos, vecArmPos + gpGlobals->v_forward * 256, ignore_monsters, ENT(pev), &tr); - UTIL_TraceLine( vecArmPos, m_hEnemy->BodyTarget(vecArmPos), dont_ignore_monsters, ENT(pev), &tr); - - if ( tr.flFraction == 1.0 || tr.pHit == m_hEnemy->edict() ) - { - m_flNextHornetAttackCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - m_fCanHornetAttack = TRUE; - return m_fCanHornetAttack; - } - } - - m_flNextHornetAttackCheck = gpGlobals->time + 0.2;// don't check for half second if this check wasn't successful - m_fCanHornetAttack = FALSE; - return m_fCanHornetAttack; -} - -//========================================================= -// StartTask -//========================================================= -void CAGrunt :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 50, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "AGruntGetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - - case TASK_AGRUNT_SETUP_HIDE_ATTACK: - // alien grunt shoots hornets back out into the open from a concealed location. - // try to find a spot to throw that gives the smart weapon a good chance of finding the enemy. - // ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy. - - CBaseMonster *pEnemyMonsterPtr; - - pEnemyMonsterPtr = m_hEnemy->MyMonsterPointer(); - - if ( pEnemyMonsterPtr ) - { - Vector vecCenter; - TraceResult tr; - BOOL fSkip; - - fSkip = FALSE; - vecCenter = Center(); - - UTIL_VecToAngles( m_vecEnemyLKP - pev->origin ); - - UTIL_TraceLine( Center() + gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin + gpGlobals->v_right * 128 ); - fSkip = TRUE; - TaskComplete(); - } - - if ( !fSkip ) - { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin - gpGlobals->v_right * 128 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if ( !fSkip ) - { - UTIL_TraceLine( Center() + gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin + gpGlobals->v_right * 256 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if ( !fSkip ) - { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin - gpGlobals->v_right * 256 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if ( !fSkip ) - { - TaskFail(); - } - } - else - { - ALERT ( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); - TaskFail(); - } - break; - - default: - CSquadMonster :: StartTask ( pTask ); - break; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CAGrunt :: GetSchedule ( void ) -{ - if ( HasConditions(bits_COND_HEAR_SOUND) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - { - // dangerous sound nearby! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - } - - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - return GetScheduleOfType( SCHED_WAKE_ANGRY ); - } - - // zap player! - if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - AttackSound();// this is a total hack. Should be parto f the schedule - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } - - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - // can attack - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) - { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - if ( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) - { - return GetScheduleOfType ( SCHED_CHASE_ENEMY ); - } - - return GetScheduleOfType ( SCHED_STANDOFF ); - } - } - - return CSquadMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CAGrunt :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - return &slAGruntTakeCoverFromEnemy[ 0 ]; - break; - - case SCHED_RANGE_ATTACK1: - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - { - //normal attack - return &slAGruntRangeAttack1[ 0 ]; - } - else - { - // attack an unseen enemy - // return &slAGruntHiddenRangeAttack[ 0 ]; - return &slAGruntRangeAttack1[ 0 ]; - } - break; - - case SCHED_AGRUNT_THREAT_DISPLAY: - return &slAGruntThreatDisplay[ 0 ]; - break; - - case SCHED_AGRUNT_SUPPRESS: - return &slAGruntSuppress[ 0 ]; - break; - - case SCHED_STANDOFF: - return &slAGruntStandoff[ 0 ]; - break; - - case SCHED_VICTORY_DANCE: - return &slAGruntVictoryDance[ 0 ]; - break; - - case SCHED_FAIL: - // no fail schedule specified, so pick a good generic one. - { - if ( m_hEnemy != NULL ) - { - // I have an enemy - // !!!LATER - what if this enemy is really far away and i'm chasing him? - // this schedule will make me stop, face his last known position for 2 - // seconds, and then try to move again - return &slAGruntCombatFail[ 0 ]; - } - - return &slAGruntFail[ 0 ]; - } - break; - - } - - return CSquadMonster :: GetScheduleOfType( Type ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Agrunt - Dominant, warlike alien grunt monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "squadmonster.h" +#include "weapons.h" +#include "soundent.h" +#include "hornet.h" + +//========================================================= +// monster-specific schedule types +//========================================================= +enum +{ + SCHED_AGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, + SCHED_AGRUNT_THREAT_DISPLAY, +}; + +//========================================================= +// monster-specific tasks +//========================================================= +enum +{ + TASK_AGRUNT_SETUP_HIDE_ATTACK = LAST_COMMON_TASK + 1, + TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, +}; + +int iAgruntMuzzleFlash; + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define AGRUNT_AE_HORNET1 ( 1 ) +#define AGRUNT_AE_HORNET2 ( 2 ) +#define AGRUNT_AE_HORNET3 ( 3 ) +#define AGRUNT_AE_HORNET4 ( 4 ) +#define AGRUNT_AE_HORNET5 ( 5 ) +// some events are set up in the QC file that aren't recognized by the code yet. +#define AGRUNT_AE_PUNCH ( 6 ) +#define AGRUNT_AE_BITE ( 7 ) + +#define AGRUNT_AE_LEFT_FOOT ( 10 ) +#define AGRUNT_AE_RIGHT_FOOT ( 11 ) + +#define AGRUNT_AE_LEFT_PUNCH ( 12 ) +#define AGRUNT_AE_RIGHT_PUNCH ( 13 ) + + + +#define AGRUNT_MELEE_DIST 100 + +class CAGrunt : public CSquadMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed ( void ); + int Classify ( void ); + int ISoundMask ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -32, -32, 0 ); + pev->absmax = pev->origin + Vector( 32, 32, 85 ); + } + + Schedule_t* GetSchedule ( void ); + Schedule_t* GetScheduleOfType ( int Type ); + BOOL FCanCheckAttacks ( void ); + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + void StartTask ( Task_t *pTask ); + void AlertSound( void ); + void DeathSound ( void ); + void PainSound ( void ); + void AttackSound ( void ); + void PrescheduleThink ( void ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + int IRelationship( CBaseEntity *pTarget ); + void StopTalking ( void ); + BOOL ShouldSpeak( void ); + CUSTOM_SCHEDULES; + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + static const char *pAttackHitSounds[]; + static const char *pAttackMissSounds[]; + static const char *pAttackSounds[]; + static const char *pDieSounds[]; + static const char *pPainSounds[]; + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + + BOOL m_fCanHornetAttack; + float m_flNextHornetAttackCheck; + + float m_flNextPainTime; + + // three hacky fields for speech stuff. These don't really need to be saved. + float m_flNextSpeakTime; + float m_flNextWordTime; + int m_iLastWord; +}; +LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ); + +TYPEDESCRIPTION CAGrunt::m_SaveData[] = +{ + DEFINE_FIELD( CAGrunt, m_fCanHornetAttack, FIELD_BOOLEAN ), + DEFINE_FIELD( CAGrunt, m_flNextHornetAttackCheck, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_flNextPainTime, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_flNextSpeakTime, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_flNextWordTime, FIELD_TIME ), + DEFINE_FIELD( CAGrunt, m_iLastWord, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ); + +const char *CAGrunt::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CAGrunt::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + +const char *CAGrunt::pAttackSounds[] = +{ + "agrunt/ag_attack1.wav", + "agrunt/ag_attack2.wav", + "agrunt/ag_attack3.wav", +}; + +const char *CAGrunt::pDieSounds[] = +{ + "agrunt/ag_die1.wav", + "agrunt/ag_die4.wav", + "agrunt/ag_die5.wav", +}; + +const char *CAGrunt::pPainSounds[] = +{ + "agrunt/ag_pain1.wav", + "agrunt/ag_pain2.wav", + "agrunt/ag_pain3.wav", + "agrunt/ag_pain4.wav", + "agrunt/ag_pain5.wav", +}; + +const char *CAGrunt::pIdleSounds[] = +{ + "agrunt/ag_idle1.wav", + "agrunt/ag_idle2.wav", + "agrunt/ag_idle3.wav", + "agrunt/ag_idle4.wav", +}; + +const char *CAGrunt::pAlertSounds[] = +{ + "agrunt/ag_alert1.wav", + "agrunt/ag_alert3.wav", + "agrunt/ag_alert4.wav", + "agrunt/ag_alert5.wav", +}; + +//========================================================= +// IRelationship - overridden because Human Grunts are +// Alien Grunt's nemesis. +//========================================================= +int CAGrunt::IRelationship ( CBaseEntity *pTarget ) +{ + if ( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) + { + return R_NM; + } + + return CSquadMonster :: IRelationship( pTarget ); +} + +//========================================================= +// ISoundMask +//========================================================= +int CAGrunt :: ISoundMask ( void ) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER | + bits_SOUND_DANGER; +} + +//========================================================= +// TraceAttack +//========================================================= +void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if ( ptr->iHitgroup == 10 && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))) + { + // hit armor + if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + { + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); + pev->dmgtime = gpGlobals->time; + } + + if ( RANDOM_LONG( 0, 1 ) == 0 ) + { + Vector vecTracerDir = vecDir; + + vecTracerDir.x += RANDOM_FLOAT( -0.3, 0.3 ); + vecTracerDir.y += RANDOM_FLOAT( -0.3, 0.3 ); + vecTracerDir.z += RANDOM_FLOAT( -0.3, 0.3 ); + + vecTracerDir = vecTracerDir * -512; + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, ptr->vecEndPos ); + WRITE_BYTE( TE_TRACER ); + WRITE_COORD( ptr->vecEndPos.x ); + WRITE_COORD( ptr->vecEndPos.y ); + WRITE_COORD( ptr->vecEndPos.z ); + + WRITE_COORD( vecTracerDir.x ); + WRITE_COORD( vecTracerDir.y ); + WRITE_COORD( vecTracerDir.z ); + MESSAGE_END(); + } + + flDamage -= 20; + if (flDamage <= 0) + flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated + } + else + { + SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. + TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); + } + + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); +} + +//========================================================= +// StopTalking - won't speak again for 10-20 seconds. +//========================================================= +void CAGrunt::StopTalking( void ) +{ + m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); +} + +//========================================================= +// ShouldSpeak - Should this agrunt be talking? +//========================================================= +BOOL CAGrunt::ShouldSpeak( void ) +{ + if ( m_flNextSpeakTime > gpGlobals->time ) + { + // my time to talk is still in the future. + return FALSE; + } + + if ( pev->spawnflags & SF_MONSTER_GAG ) + { + if ( m_MonsterState != MONSTERSTATE_COMBAT ) + { + // if gagged, don't talk outside of combat. + // if not going to talk because of this, put the talk time + // into the future a bit, so we don't talk immediately after + // going into combat + m_flNextSpeakTime = gpGlobals->time + 3; + return FALSE; + } + } + + return TRUE; +} + +//========================================================= +// PrescheduleThink +//========================================================= +void CAGrunt :: PrescheduleThink ( void ) +{ + if ( ShouldSpeak() ) + { + if ( m_flNextWordTime < gpGlobals->time ) + { + int num = -1; + + do + { + num = RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1); + } while( num == m_iLastWord ); + + m_iLastWord = num; + + // play a new sound + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pIdleSounds[ num ], 1.0, ATTN_NORM ); + + // is this word our last? + if ( RANDOM_LONG( 1, 10 ) <= 1 ) + { + // stop talking. + StopTalking(); + } + else + { + m_flNextWordTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); + } + } + } +} + +//========================================================= +// DieSound +//========================================================= +void CAGrunt :: DeathSound ( void ) +{ + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pDieSounds[RANDOM_LONG(0,ARRAYSIZE(pDieSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// AlertSound +//========================================================= +void CAGrunt :: AlertSound ( void ) +{ + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAlertSounds[RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// AttackSound +//========================================================= +void CAGrunt :: AttackSound ( void ) +{ + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAttackSounds[RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// PainSound +//========================================================= +void CAGrunt :: PainSound ( void ) +{ + if ( m_flNextPainTime > gpGlobals->time ) + { + return; + } + + m_flNextPainTime = gpGlobals->time + 0.6; + + StopTalking(); + + EMIT_SOUND ( ENT(pev), CHAN_VOICE, pPainSounds[RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1)], 1.0, ATTN_NORM ); +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CAGrunt :: Classify ( void ) +{ + return CLASS_ALIEN_MILITARY; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CAGrunt :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 110; + break; + default: ys = 100; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case AGRUNT_AE_HORNET1: + case AGRUNT_AE_HORNET2: + case AGRUNT_AE_HORNET3: + case AGRUNT_AE_HORNET4: + case AGRUNT_AE_HORNET5: + { + // m_vecEnemyLKP should be center of enemy body + Vector vecArmPos, vecArmDir; + Vector vecDirToEnemy; + Vector angDir; + + if (HasConditions( bits_COND_SEE_ENEMY)) + { + vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); + angDir = UTIL_VecToAngles( vecDirToEnemy ); + vecDirToEnemy = vecDirToEnemy.Normalize(); + } + else + { + angDir = pev->angles; + UTIL_MakeAimVectors( angDir ); + vecDirToEnemy = gpGlobals->v_forward; + } + + pev->effects = EF_MUZZLEFLASH; + + // make angles +-180 + if (angDir.x > 180) + { + angDir.x = angDir.x - 360; + } + + SetBlending( 0, angDir.x ); + GetAttachment( 0, vecArmPos, vecArmDir ); + + vecArmPos = vecArmPos + vecDirToEnemy * 32; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecArmPos ); + WRITE_BYTE( TE_SPRITE ); + WRITE_COORD( vecArmPos.x ); // pos + WRITE_COORD( vecArmPos.y ); + WRITE_COORD( vecArmPos.z ); + WRITE_SHORT( iAgruntMuzzleFlash ); // model + WRITE_BYTE( 6 ); // size * 10 + WRITE_BYTE( 128 ); // brightness + MESSAGE_END(); + + CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); + UTIL_MakeVectors ( pHornet->pev->angles ); + pHornet->pev->velocity = gpGlobals->v_forward * 300; + + CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer(); + + if ( pHornetMonster ) + { + pHornetMonster->m_hEnemy = m_hEnemy; + } + } + break; + + case AGRUNT_AE_LEFT_FOOT: + switch (RANDOM_LONG(0,1)) + { + // left foot + case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); break; + case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); break; + } + break; + case AGRUNT_AE_RIGHT_FOOT: + // right foot + switch (RANDOM_LONG(0,1)) + { + case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); break; + case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); break; + } + break; + + case AGRUNT_AE_LEFT_PUNCH: + { + CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); + + if ( pHurt ) + { + pHurt->pev->punchangle.y = -25; + pHurt->pev->punchangle.x = 8; + + // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. + if ( pHurt->IsPlayer() ) + { + // this is a player. Knock him around. + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 250; + } + + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + Vector vecArmPos, vecArmAng; + GetAttachment( 0, vecArmPos, vecArmAng ); + SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. + } + else + { + // Play a random attack miss sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + } + break; + + case AGRUNT_AE_RIGHT_PUNCH: + { + CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); + + if ( pHurt ) + { + pHurt->pev->punchangle.y = 25; + pHurt->pev->punchangle.x = 8; + + // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. + if ( pHurt->IsPlayer() ) + { + // this is a player. Knock him around. + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -250; + } + + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + Vector vecArmPos, vecArmAng; + GetAttachment( 0, vecArmPos, vecArmAng ); + SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. + } + else + { + // Play a random attack miss sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + } + break; + + default: + CSquadMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CAGrunt :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/agrunt.mdl"); + UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->effects = 0; + pev->health = gSkillData.agruntHealth; + m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_afCapability = 0; + m_afCapability |= bits_CAP_SQUAD; + + m_HackedGunPos = Vector( 24, 64, 48 ); + + m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); + + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CAGrunt :: Precache() +{ + int i; + + PRECACHE_MODEL("models/agrunt.mdl"); + + for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackHitSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackMissSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) + PRECACHE_SOUND((char *)pIdleSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ ) + PRECACHE_SOUND((char *)pDieSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) + PRECACHE_SOUND((char *)pPainSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) + PRECACHE_SOUND((char *)pAlertSounds[i]); + + + PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); + + iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" ); + + UTIL_PrecacheOther( "hornet" ); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +//========================================================= +// Fail Schedule +//========================================================= +Task_t tlAGruntFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slAGruntFail[] = +{ + { + tlAGruntFail, + ARRAYSIZE ( tlAGruntFail ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1, + 0, + "AGrunt Fail" + }, +}; + +//========================================================= +// Combat Fail Schedule +//========================================================= +Task_t tlAGruntCombatFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slAGruntCombatFail[] = +{ + { + tlAGruntCombatFail, + ARRAYSIZE ( tlAGruntCombatFail ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1, + 0, + "AGrunt Combat Fail" + }, +}; + +//========================================================= +// Standoff schedule. Used in combat when a monster is +// hiding in cover or the enemy has moved out of sight. +// Should we look around in this schedule? +//========================================================= +Task_t tlAGruntStandoff[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, +}; + +Schedule_t slAGruntStandoff[] = +{ + { + tlAGruntStandoff, + ARRAYSIZE ( tlAGruntStandoff ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_SEE_ENEMY | + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Agrunt Standoff" + } +}; + +//========================================================= +// Suppress +//========================================================= +Task_t tlAGruntSuppressHornet[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slAGruntSuppress[] = +{ + { + tlAGruntSuppressHornet, + ARRAYSIZE ( tlAGruntSuppressHornet ), + 0, + 0, + "AGrunt Suppress Hornet", + }, +}; + +//========================================================= +// primary range attacks +//========================================================= +Task_t tlAGruntRangeAttack1[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slAGruntRangeAttack1[] = +{ + { + tlAGruntRangeAttack1, + ARRAYSIZE ( tlAGruntRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_HEAVY_DAMAGE, + + 0, + "AGrunt Range Attack1" + }, +}; + + +Task_t tlAGruntHiddenRangeAttack1[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_STANDOFF }, + { TASK_AGRUNT_SETUP_HIDE_ATTACK, 0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, 0 }, + { TASK_RANGE_ATTACK1_NOTURN, (float)0 }, +}; + +Schedule_t slAGruntHiddenRangeAttack[] = +{ + { + tlAGruntHiddenRangeAttack1, + ARRAYSIZE ( tlAGruntHiddenRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "AGrunt Hidden Range Attack1" + }, +}; + +//========================================================= +// Take cover from enemy! Tries lateral cover before node +// cover! +//========================================================= +Task_t tlAGruntTakeCoverFromEnemy[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_WAIT, (float)0.2 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_FACE_ENEMY, (float)0 }, +}; + +Schedule_t slAGruntTakeCoverFromEnemy[] = +{ + { + tlAGruntTakeCoverFromEnemy, + ARRAYSIZE ( tlAGruntTakeCoverFromEnemy ), + bits_COND_NEW_ENEMY, + 0, + "AGruntTakeCoverFromEnemy" + }, +}; + +//========================================================= +// Victory dance! +//========================================================= +Task_t tlAGruntVictoryDance[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_AGRUNT_THREAT_DISPLAY }, + { TASK_WAIT, (float)0.2 }, + { TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, + { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, + { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, +}; + +Schedule_t slAGruntVictoryDance[] = +{ + { + tlAGruntVictoryDance, + ARRAYSIZE ( tlAGruntVictoryDance ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "AGruntVictoryDance" + }, +}; + +//========================================================= +//========================================================= +Task_t tlAGruntThreatDisplay[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, +}; + +Schedule_t slAGruntThreatDisplay[] = +{ + { + tlAGruntThreatDisplay, + ARRAYSIZE ( tlAGruntThreatDisplay ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + + bits_SOUND_PLAYER | + bits_SOUND_COMBAT | + bits_SOUND_WORLD, + "AGruntThreatDisplay" + }, +}; + +DEFINE_CUSTOM_SCHEDULES( CAGrunt ) +{ + slAGruntFail, + slAGruntCombatFail, + slAGruntStandoff, + slAGruntSuppress, + slAGruntRangeAttack1, + slAGruntHiddenRangeAttack, + slAGruntTakeCoverFromEnemy, + slAGruntVictoryDance, + slAGruntThreatDisplay, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ); + +//========================================================= +// FCanCheckAttacks - this is overridden for alien grunts +// because they can use their smart weapons against unseen +// enemies. Base class doesn't attack anyone it can't see. +//========================================================= +BOOL CAGrunt :: FCanCheckAttacks ( void ) +{ + if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +//========================================================= +// CheckMeleeAttack1 - alien grunts zap the crap out of +// any enemy that gets too close. +//========================================================= +BOOL CAGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + if ( HasConditions ( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != NULL ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack1 +// +// !!!LATER - we may want to load balance this. Several +// tracelines are done, so we may not want to do this every +// server frame. Definitely not while firing. +//========================================================= +BOOL CAGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( gpGlobals->time < m_flNextHornetAttackCheck ) + { + return m_fCanHornetAttack; + } + + if ( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) + { + TraceResult tr; + Vector vecArmPos, vecArmDir; + + // verify that a shot fired from the gun will hit the enemy before the world. + // !!!LATER - we may wish to do something different for projectile weapons as opposed to instant-hit + UTIL_MakeVectors( pev->angles ); + GetAttachment( 0, vecArmPos, vecArmDir ); +// UTIL_TraceLine( vecArmPos, vecArmPos + gpGlobals->v_forward * 256, ignore_monsters, ENT(pev), &tr); + UTIL_TraceLine( vecArmPos, m_hEnemy->BodyTarget(vecArmPos), dont_ignore_monsters, ENT(pev), &tr); + + if ( tr.flFraction == 1.0 || tr.pHit == m_hEnemy->edict() ) + { + m_flNextHornetAttackCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); + m_fCanHornetAttack = TRUE; + return m_fCanHornetAttack; + } + } + + m_flNextHornetAttackCheck = gpGlobals->time + 0.2;// don't check for half second if this check wasn't successful + m_fCanHornetAttack = FALSE; + return m_fCanHornetAttack; +} + +//========================================================= +// StartTask +//========================================================= +void CAGrunt :: StartTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE: + { + UTIL_MakeVectors( pev->angles ); + if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 50, bits_MF_TO_LOCATION, NULL ) ) + { + TaskComplete(); + } + else + { + ALERT ( at_aiconsole, "AGruntGetPathToEnemyCorpse failed!!\n" ); + TaskFail(); + } + } + break; + + case TASK_AGRUNT_SETUP_HIDE_ATTACK: + // alien grunt shoots hornets back out into the open from a concealed location. + // try to find a spot to throw that gives the smart weapon a good chance of finding the enemy. + // ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy. + + CBaseMonster *pEnemyMonsterPtr; + + pEnemyMonsterPtr = m_hEnemy->MyMonsterPointer(); + + if ( pEnemyMonsterPtr ) + { + Vector vecCenter; + TraceResult tr; + BOOL fSkip; + + fSkip = FALSE; + vecCenter = Center(); + + UTIL_VecToAngles( m_vecEnemyLKP - pev->origin ); + + UTIL_TraceLine( Center() + gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin + gpGlobals->v_right * 128 ); + fSkip = TRUE; + TaskComplete(); + } + + if ( !fSkip ) + { + UTIL_TraceLine( Center() - gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin - gpGlobals->v_right * 128 ); + fSkip = TRUE; + TaskComplete(); + } + } + + if ( !fSkip ) + { + UTIL_TraceLine( Center() + gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin + gpGlobals->v_right * 256 ); + fSkip = TRUE; + TaskComplete(); + } + } + + if ( !fSkip ) + { + UTIL_TraceLine( Center() - gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction == 1.0 ) + { + MakeIdealYaw ( pev->origin - gpGlobals->v_right * 256 ); + fSkip = TRUE; + TaskComplete(); + } + } + + if ( !fSkip ) + { + TaskFail(); + } + } + else + { + ALERT ( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); + TaskFail(); + } + break; + + default: + CSquadMonster :: StartTask ( pTask ); + break; + } +} + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CAGrunt :: GetSchedule ( void ) +{ + if ( HasConditions(bits_COND_HEAR_SOUND) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + { + // dangerous sound nearby! + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + } + + switch ( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + if ( HasConditions(bits_COND_NEW_ENEMY) ) + { + return GetScheduleOfType( SCHED_WAKE_ANGRY ); + } + + // zap player! + if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + { + AttackSound();// this is a total hack. Should be parto f the schedule + return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + } + + if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + { + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + + // can attack + if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) + { + return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + } + + if ( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) + { + return GetScheduleOfType ( SCHED_CHASE_ENEMY ); + } + + return GetScheduleOfType ( SCHED_STANDOFF ); + } + } + + return CSquadMonster :: GetSchedule(); +} + +//========================================================= +//========================================================= +Schedule_t* CAGrunt :: GetScheduleOfType ( int Type ) +{ + switch ( Type ) + { + case SCHED_TAKE_COVER_FROM_ENEMY: + return &slAGruntTakeCoverFromEnemy[ 0 ]; + break; + + case SCHED_RANGE_ATTACK1: + if ( HasConditions( bits_COND_SEE_ENEMY ) ) + { + //normal attack + return &slAGruntRangeAttack1[ 0 ]; + } + else + { + // attack an unseen enemy + // return &slAGruntHiddenRangeAttack[ 0 ]; + return &slAGruntRangeAttack1[ 0 ]; + } + break; + + case SCHED_AGRUNT_THREAT_DISPLAY: + return &slAGruntThreatDisplay[ 0 ]; + break; + + case SCHED_AGRUNT_SUPPRESS: + return &slAGruntSuppress[ 0 ]; + break; + + case SCHED_STANDOFF: + return &slAGruntStandoff[ 0 ]; + break; + + case SCHED_VICTORY_DANCE: + return &slAGruntVictoryDance[ 0 ]; + break; + + case SCHED_FAIL: + // no fail schedule specified, so pick a good generic one. + { + if ( m_hEnemy != NULL ) + { + // I have an enemy + // !!!LATER - what if this enemy is really far away and i'm chasing him? + // this schedule will make me stop, face his last known position for 2 + // seconds, and then try to move again + return &slAGruntCombatFail[ 0 ]; + } + + return &slAGruntFail[ 0 ]; + } + break; + + } + + return CSquadMonster :: GetScheduleOfType( Type ); +} + diff --git a/main/source/dlls/airtank.cpp b/main/source/dlls/airtank.cpp index 5559222a..bca41b28 100644 --- a/main/source/dlls/airtank.cpp +++ b/main/source/dlls/airtank.cpp @@ -1,118 +1,118 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -class CAirtank : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void EXPORT TankThink( void ); - void EXPORT TankTouch( CBaseEntity *pOther ); - int BloodColor( void ) { return DONT_BLEED; }; - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_state; -}; - - -LINK_ENTITY_TO_CLASS( item_airtank, CAirtank ); -TYPEDESCRIPTION CAirtank::m_SaveData[] = -{ - DEFINE_FIELD( CAirtank, m_state, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CAirtank, CGrenade ); - - -void CAirtank :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_oxygen.mdl"); - UTIL_SetSize(pev, Vector( -16, -16, 0), Vector(16, 16, 36)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( TankTouch ); - SetThink( TankThink ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_YES; - pev->health = 20; - pev->dmg = 50; - m_state = 1; -} - -void CAirtank::Precache( void ) -{ - PRECACHE_MODEL("models/w_oxygen.mdl"); - PRECACHE_SOUND("doors/aliendoor3.wav"); -} - - -void CAirtank :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->owner = ENT( pevAttacker ); - - // UNDONE: this should make a big bubble cloud, not an explosion - - Explode( pev->origin, Vector( 0, 0, -1 ) ); -} - - -void CAirtank::TankThink( void ) -{ - // Fire trigger - m_state = 1; - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - -void CAirtank::TankTouch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - return; - - if (!m_state) - { - // "no oxygen" sound - EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 1.0, ATTN_NORM ); - return; - } - - // give player 12 more seconds of air - pOther->pev->air_finished = gpGlobals->time + 12; - - // suit recharge sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "doors/aliendoor3.wav", 1.0, ATTN_NORM ); - - // recharge airtank in 30 seconds - pev->nextthink = gpGlobals->time + 30; - m_state = 0; - SUB_UseTargets( this, USE_TOGGLE, 1 ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + +class CAirtank : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + void EXPORT TankThink( void ); + void EXPORT TankTouch( CBaseEntity *pOther ); + int BloodColor( void ) { return DONT_BLEED; }; + void Killed( entvars_t *pevAttacker, int iGib ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + int m_state; +}; + + +LINK_ENTITY_TO_CLASS( item_airtank, CAirtank ); +TYPEDESCRIPTION CAirtank::m_SaveData[] = +{ + DEFINE_FIELD( CAirtank, m_state, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CAirtank, CGrenade ); + + +void CAirtank :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/w_oxygen.mdl"); + UTIL_SetSize(pev, Vector( -16, -16, 0), Vector(16, 16, 36)); + UTIL_SetOrigin( pev, pev->origin ); + + SetTouch( TankTouch ); + SetThink( TankThink ); + + pev->flags |= FL_MONSTER; + pev->takedamage = DAMAGE_YES; + pev->health = 20; + pev->dmg = 50; + m_state = 1; +} + +void CAirtank::Precache( void ) +{ + PRECACHE_MODEL("models/w_oxygen.mdl"); + PRECACHE_SOUND("doors/aliendoor3.wav"); +} + + +void CAirtank :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->owner = ENT( pevAttacker ); + + // UNDONE: this should make a big bubble cloud, not an explosion + + Explode( pev->origin, Vector( 0, 0, -1 ) ); +} + + +void CAirtank::TankThink( void ) +{ + // Fire trigger + m_state = 1; + SUB_UseTargets( this, USE_TOGGLE, 0 ); +} + + +void CAirtank::TankTouch( CBaseEntity *pOther ) +{ + if ( !pOther->IsPlayer() ) + return; + + if (!m_state) + { + // "no oxygen" sound + EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 1.0, ATTN_NORM ); + return; + } + + // give player 12 more seconds of air + pOther->pev->air_finished = gpGlobals->time + 12; + + // suit recharge sound + EMIT_SOUND( ENT(pev), CHAN_VOICE, "doors/aliendoor3.wav", 1.0, ATTN_NORM ); + + // recharge airtank in 30 seconds + pev->nextthink = gpGlobals->time + 30; + m_state = 0; + SUB_UseTargets( this, USE_TOGGLE, 1 ); +} diff --git a/main/source/dlls/animating.cpp b/main/source/dlls/animating.cpp index 4c4cd7d8..2a41fcfe 100644 --- a/main/source/dlls/animating.cpp +++ b/main/source/dlls/animating.cpp @@ -1,331 +1,331 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== monsters.cpp ======================================================== - - Monster-related utility code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "animation.h" -#include "saverestore.h" - -TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMonster, m_flFrameRate, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flGroundSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flLastEventCheck, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_fSequenceFinished, FIELD_BOOLEAN ), - DEFINE_FIELD( CBaseMonster, m_fSequenceLoops, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay ); - - -//========================================================= -// StudioFrameAdvance - advance the animation frame up to the current time -// if an flInterval is passed in, only advance animation that number of seconds -//========================================================= -float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) -{ - if (flInterval == 0.0) - { - flInterval = (gpGlobals->time - pev->animtime); - if (flInterval <= 0.001) - { - pev->animtime = gpGlobals->time; - return 0.0; - } - } - if (! pev->animtime) - flInterval = 0.0; - - pev->frame += flInterval * m_flFrameRate * pev->framerate; - pev->animtime = gpGlobals->time; - - if (pev->frame < 0.0 || pev->frame >= 256.0) - { - if (m_fSequenceLoops) - pev->frame -= (int)(pev->frame / 256.0) * 256.0; - else - pev->frame = (pev->frame < 0.0) ? 0 : 255; - m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents - } - - return flInterval; -} - -//========================================================= -// LookupActivity -//========================================================= -int CBaseAnimating :: LookupActivity ( int activity ) -{ - ASSERT( activity != 0 ); - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupActivity( pmodel, pev, activity ); -} - -//========================================================= -// LookupActivityHeaviest -// -// Get activity with highest 'weight' -// -//========================================================= -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupActivityHeaviest( pmodel, pev, activity ); -} - -//========================================================= -//========================================================= -int CBaseAnimating :: LookupSequence ( const char *label, int queue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if (strcmp(label, this->mPreviousLookupString[queue]) == 0) - { - return this->mPreviousLookupSequence[queue]; - } - - strcpy(this->mPreviousLookupString[queue], label); - this->mPreviousLookupSequence[queue] = ::LookupSequence( pmodel, label ); - return this->mPreviousLookupSequence[queue]; -} - -const char* CBaseAnimating::LookupSequence(int inSequence) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupSequence( pmodel, inSequence); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: ResetSequenceInfo ( ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed ); - m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0); - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; - m_fSequenceFinished = FALSE; - m_flLastEventCheck = gpGlobals->time; -} - - - -//========================================================= -//========================================================= -BOOL CBaseAnimating :: GetSequenceFlags( ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::GetSequenceFlags( pmodel, pev ); -} - -//========================================================= -// DispatchAnimEvents -//========================================================= -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) -{ - MonsterEvent_t event; - - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if ( !pmodel ) - { - ALERT( at_aiconsole, "Gibbed monster is thinking!\n" ); - return; - } - - // FIXME: I have to do this or some events get missed, and this is probably causing the problem below - flInterval = 0.1; - - // FIX: this still sometimes hits events twice - float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate; - float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate; - m_flLastEventCheck = pev->animtime + flInterval; - - m_fSequenceFinished = FALSE; - if (flEnd >= 256 || flEnd <= 0.0) - m_fSequenceFinished = TRUE; - - int index = 0; - - while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) - { - HandleAnimEvent( &event ); - } -} - - -//========================================================= -//========================================================= -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return SetController( pmodel, pev, iController, flValue ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: InitBoneControllers ( void ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - SetController( pmodel, pev, 0, 0.0 ); - SetController( pmodel, pev, 1, 0.0 ); - SetController( pmodel, pev, 2, 0.0 ); - SetController( pmodel, pev, 3, 0.0 ); -} - -//========================================================= -//========================================================= -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::SetBlending( pmodel, pev, iBlender, flValue ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) -{ - GET_BONE_POSITION( ENT(pev), iBone, origin, angles ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) -{ - GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles ); -} - -//========================================================= -//========================================================= -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if (piDir == NULL) - { - int iDir; - int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir ); - if (iDir != 1) - return -1; - else - return sequence; - } - - return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) -{ - -} - -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) -{ - ::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue ); -} - -int CBaseAnimating :: GetBodygroup( int iGroup ) -{ - return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup ); -} - - -int CBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs ) -{ - return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs ); -} - -//========================================================= -//========================================================= - -void CBaseAnimating :: SetSequenceBox( void ) -{ - Vector mins, maxs; - - // Get sequence bbox - if ( ExtractBbox( pev->sequence, mins, maxs ) ) - { - // expand box for rotation - // find min / max for rotations - float yaw = pev->angles.y * (M_PI / 180.0); - - Vector xvector, yvector; - xvector.x = cos(yaw); - xvector.y = sin(yaw); - yvector.x = -sin(yaw); - yvector.y = cos(yaw); - Vector bounds[2]; - - bounds[0] = mins; - bounds[1] = maxs; - - Vector rmin( 9999, 9999, 9999 ); - Vector rmax( -9999, -9999, -9999 ); - Vector base, transformed; - - for (int i = 0; i <= 1; i++ ) - { - base.x = bounds[i].x; - for ( int j = 0; j <= 1; j++ ) - { - base.y = bounds[j].y; - for ( int k = 0; k <= 1; k++ ) - { - base.z = bounds[k].z; - - // transform the point - transformed.x = xvector.x*base.x + yvector.x*base.y; - transformed.y = xvector.y*base.x + yvector.y*base.y; - transformed.z = base.z; - - if (transformed.x < rmin.x) - rmin.x = transformed.x; - if (transformed.x > rmax.x) - rmax.x = transformed.x; - if (transformed.y < rmin.y) - rmin.y = transformed.y; - if (transformed.y > rmax.y) - rmax.y = transformed.y; - if (transformed.z < rmin.z) - rmin.z = transformed.z; - if (transformed.z > rmax.z) - rmax.z = transformed.z; - } - } - } - rmin.z = 0; - rmax.z = rmin.z + 1; - UTIL_SetSize( pev, rmin, rmax ); - } -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== monsters.cpp ======================================================== + + Monster-related utility code + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "animation.h" +#include "saverestore.h" + +TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = +{ + DEFINE_FIELD( CBaseMonster, m_flFrameRate, FIELD_FLOAT ), + DEFINE_FIELD( CBaseMonster, m_flGroundSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CBaseMonster, m_flLastEventCheck, FIELD_TIME ), + DEFINE_FIELD( CBaseMonster, m_fSequenceFinished, FIELD_BOOLEAN ), + DEFINE_FIELD( CBaseMonster, m_fSequenceLoops, FIELD_BOOLEAN ), +}; + +IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay ); + + +//========================================================= +// StudioFrameAdvance - advance the animation frame up to the current time +// if an flInterval is passed in, only advance animation that number of seconds +//========================================================= +float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) +{ + if (flInterval == 0.0) + { + flInterval = (gpGlobals->time - pev->animtime); + if (flInterval <= 0.001) + { + pev->animtime = gpGlobals->time; + return 0.0; + } + } + if (! pev->animtime) + flInterval = 0.0; + + pev->frame += flInterval * m_flFrameRate * pev->framerate; + pev->animtime = gpGlobals->time; + + if (pev->frame < 0.0 || pev->frame >= 256.0) + { + if (m_fSequenceLoops) + pev->frame -= (int)(pev->frame / 256.0) * 256.0; + else + pev->frame = (pev->frame < 0.0) ? 0 : 255; + m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents + } + + return flInterval; +} + +//========================================================= +// LookupActivity +//========================================================= +int CBaseAnimating :: LookupActivity ( int activity ) +{ + ASSERT( activity != 0 ); + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + return ::LookupActivity( pmodel, pev, activity ); +} + +//========================================================= +// LookupActivityHeaviest +// +// Get activity with highest 'weight' +// +//========================================================= +int CBaseAnimating :: LookupActivityHeaviest ( int activity ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + return ::LookupActivityHeaviest( pmodel, pev, activity ); +} + +//========================================================= +//========================================================= +int CBaseAnimating :: LookupSequence ( const char *label, int queue ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + if (strcmp(label, this->mPreviousLookupString[queue]) == 0) + { + return this->mPreviousLookupSequence[queue]; + } + + strcpy(this->mPreviousLookupString[queue], label); + this->mPreviousLookupSequence[queue] = ::LookupSequence( pmodel, label ); + return this->mPreviousLookupSequence[queue]; +} + +const char* CBaseAnimating::LookupSequence(int inSequence) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + return ::LookupSequence( pmodel, inSequence); +} + +//========================================================= +//========================================================= +void CBaseAnimating :: ResetSequenceInfo ( ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed ); + m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0); + pev->animtime = gpGlobals->time; + pev->framerate = 1.0; + m_fSequenceFinished = FALSE; + m_flLastEventCheck = gpGlobals->time; +} + + + +//========================================================= +//========================================================= +BOOL CBaseAnimating :: GetSequenceFlags( ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + return ::GetSequenceFlags( pmodel, pev ); +} + +//========================================================= +// DispatchAnimEvents +//========================================================= +void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) +{ + MonsterEvent_t event; + + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + if ( !pmodel ) + { + ALERT( at_aiconsole, "Gibbed monster is thinking!\n" ); + return; + } + + // FIXME: I have to do this or some events get missed, and this is probably causing the problem below + flInterval = 0.1; + + // FIX: this still sometimes hits events twice + float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate; + float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate; + m_flLastEventCheck = pev->animtime + flInterval; + + m_fSequenceFinished = FALSE; + if (flEnd >= 256 || flEnd <= 0.0) + m_fSequenceFinished = TRUE; + + int index = 0; + + while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) + { + HandleAnimEvent( &event ); + } +} + + +//========================================================= +//========================================================= +float CBaseAnimating :: SetBoneController ( int iController, float flValue ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + return SetController( pmodel, pev, iController, flValue ); +} + +//========================================================= +//========================================================= +void CBaseAnimating :: InitBoneControllers ( void ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + SetController( pmodel, pev, 0, 0.0 ); + SetController( pmodel, pev, 1, 0.0 ); + SetController( pmodel, pev, 2, 0.0 ); + SetController( pmodel, pev, 3, 0.0 ); +} + +//========================================================= +//========================================================= +float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + return ::SetBlending( pmodel, pev, iBlender, flValue ); +} + +//========================================================= +//========================================================= +void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) +{ + GET_BONE_POSITION( ENT(pev), iBone, origin, angles ); +} + +//========================================================= +//========================================================= +void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) +{ + GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles ); +} + +//========================================================= +//========================================================= +int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) +{ + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + if (piDir == NULL) + { + int iDir; + int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir ); + if (iDir != 1) + return -1; + else + return sequence; + } + + return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir ); +} + +//========================================================= +//========================================================= +void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) +{ + +} + +void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) +{ + ::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue ); +} + +int CBaseAnimating :: GetBodygroup( int iGroup ) +{ + return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup ); +} + + +int CBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs ) +{ + return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs ); +} + +//========================================================= +//========================================================= + +void CBaseAnimating :: SetSequenceBox( void ) +{ + Vector mins, maxs; + + // Get sequence bbox + if ( ExtractBbox( pev->sequence, mins, maxs ) ) + { + // expand box for rotation + // find min / max for rotations + float yaw = pev->angles.y * (M_PI / 180.0); + + Vector xvector, yvector; + xvector.x = cos(yaw); + xvector.y = sin(yaw); + yvector.x = -sin(yaw); + yvector.y = cos(yaw); + Vector bounds[2]; + + bounds[0] = mins; + bounds[1] = maxs; + + Vector rmin( 9999, 9999, 9999 ); + Vector rmax( -9999, -9999, -9999 ); + Vector base, transformed; + + for (int i = 0; i <= 1; i++ ) + { + base.x = bounds[i].x; + for ( int j = 0; j <= 1; j++ ) + { + base.y = bounds[j].y; + for ( int k = 0; k <= 1; k++ ) + { + base.z = bounds[k].z; + + // transform the point + transformed.x = xvector.x*base.x + yvector.x*base.y; + transformed.y = xvector.y*base.x + yvector.y*base.y; + transformed.z = base.z; + + if (transformed.x < rmin.x) + rmin.x = transformed.x; + if (transformed.x > rmax.x) + rmax.x = transformed.x; + if (transformed.y < rmin.y) + rmin.y = transformed.y; + if (transformed.y > rmax.y) + rmax.y = transformed.y; + if (transformed.z < rmin.z) + rmin.z = transformed.z; + if (transformed.z > rmax.z) + rmax.z = transformed.z; + } + } + } + rmin.z = 0; + rmax.z = rmin.z + 1; + UTIL_SetSize( pev, rmin, rmax ); + } +} + diff --git a/main/source/dlls/animation.cpp b/main/source/dlls/animation.cpp index 79e952a2..a29e37ea 100644 --- a/main/source/dlls/animation.cpp +++ b/main/source/dlls/animation.cpp @@ -1,576 +1,576 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include -#include -#include - -#include "../common/nowin.h" - -typedef int BOOL; -#define TRUE 1 -#define FALSE 0 - -// hack into header files that we can ship -typedef int qboolean; -typedef unsigned char byte; -#include "hl/mathlib.h" -#include "../common/const.h" -#include "../engine/progdefs.h" -#include "../engine/edict.h" -#include "../engine/eiface.h" -#include "../engine/studio.h" - -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#include "activitymap.h" - -#ifndef ANIMATION_H -#include "animation.h" -#endif - -#ifndef SCRIPTEVENT_H -#include "scriptevent.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif - -#include "../mod/AvHServerVariables.h" - -extern globalvars_t *gpGlobals; - -#pragma warning( disable : 4244 ) - - -int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - mins[0] = pseqdesc[ sequence ].bbmin[0]; - mins[1] = pseqdesc[ sequence ].bbmin[1]; - mins[2] = pseqdesc[ sequence ].bbmin[2]; - - maxs[0] = pseqdesc[ sequence ].bbmax[0]; - maxs[1] = pseqdesc[ sequence ].bbmax[1]; - maxs[2] = pseqdesc[ sequence ].bbmax[2]; - - return 1; -} - - -int LookupActivity( void *pmodel, entvars_t *pev, int activity ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - int weighttotal = 0; - int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].activity == activity) - { - weighttotal += pseqdesc[i].actweight; - if (!weighttotal || RANDOM_LONG(0,weighttotal-1) < pseqdesc[i].actweight) - seq = i; - } - } - - return seq; -} - - -int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr ) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - int weight = 0; - int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].activity == activity) - { - if ( pseqdesc[i].actweight > weight ) - { - weight = pseqdesc[i].actweight; - seq = i; - } - } - } - - return seq; -} - -void GetEyePosition ( void *pmodel, float *vecEyePosition ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - - if ( !pstudiohdr ) - { - ALERT ( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" ); - return; - } - - VectorCopy ( pstudiohdr->eyeposition, vecEyePosition ); -} - -int LookupSequence( void *pmodel, const char *label ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (stricmp( pseqdesc[i].label, label ) == 0) - return i; - } - - //if(GetGameRules()->GetIsTesting()) - //if(CVAR_GET_FLOAT(kvTesting) > 0) - //{ - // char theMessage[256]; - // sprintf(theMessage, "%s%s\n", "Couldn't find animation: ", label); - // ALERT(at_console, theMessage); - //} - - return -1; -} - -const char* LookupSequence( void *pmodel, int inSequence) -{ - const char* theSequenceName = NULL; - - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (pstudiohdr) - { - mstudioseqdesc_t* pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - if((inSequence >= 0) && (inSequence < pstudiohdr->numseq)) - { - theSequenceName = pseqdesc[inSequence].label; - } - } - - return theSequenceName; -} - -int IsSoundEvent( int eventNumber ) -{ - if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) - return 1; - return 0; -} - - -void SequencePrecache( void *pmodel, const char *pSequenceName ) -{ - int index = LookupSequence( pmodel, pSequenceName ); - if ( index >= 0 ) - { - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || index >= pstudiohdr->numseq ) - return; - - mstudioseqdesc_t *pseqdesc; - mstudioevent_t *pevent; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; - pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); - - for (int i = 0; i < pseqdesc->numevents; i++) - { - // Don't send client-side events to the server AI - if ( pevent[i].event >= EVENT_CLIENT ) - continue; - - // UNDONE: Add a callback to check to see if a sound is precached yet and don't allocate a copy - // of it's name if it is. - if ( IsSoundEvent( pevent[i].event ) ) - { - if ( !strlen(pevent[i].options) ) - { - ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options ); - } - - PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) ); - } - } - } -} - -float GetSequenceDuration( void *pmodel, entvars_t *pev) -{ - float theSequenceDuration = 0.0f; - - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if(pstudiohdr) - { - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if(pseqdesc->fps > 0) - { - theSequenceDuration = (pseqdesc->numframes - 1)/pseqdesc->fps; - } - } - - return theSequenceDuration; -} - -void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - mstudioseqdesc_t *pseqdesc; - - if (pev->sequence >= pstudiohdr->numseq) - { - *pflFrameRate = 0.0; - *pflGroundSpeed = 0.0; - return; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->numframes > 1) - { - *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); - *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); - *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); - } - else - { - *pflFrameRate = 256.0; - *pflGroundSpeed = 0.0; - } -} - - -int GetSequenceFlags( void *pmodel, entvars_t *pev ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) - return 0; - - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - return pseqdesc->flags; -} - - -int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) - return 0; - - int events = 0; - - mstudioseqdesc_t *pseqdesc; - mstudioevent_t *pevent; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); - - if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) - return 0; - - - if (pseqdesc->numframes > 1) - { - flStart *= (pseqdesc->numframes - 1) / 256.0; - flEnd *= (pseqdesc->numframes - 1) / 256.0; - } - else - { - flStart = 0; - flEnd = 1.0; - } - - for (; index < pseqdesc->numevents; index++) - { - // Don't send client-side events to the server AI - if ( pevent[index].event >= EVENT_CLIENT ) - continue; - - if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) || - ((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) ) - { - pMonsterEvent->event = pevent[index].event; - pMonsterEvent->options = pevent[index].options; - return index + 1; - } - } - return 0; -} - -float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return flValue; - - mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); - - // find first controller that matches the index - int i=0; - for (i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) - { - if (pbonecontroller->index == iController) - break; - } - if (i >= pstudiohdr->numbonecontrollers) - return flValue; - - // wrap 0..360 if it's a rotational controller - - if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if (pbonecontroller->end < pbonecontroller->start) - flValue = -flValue; - - // does the controller not wrap? - if (pbonecontroller->start + 359.0 >= pbonecontroller->end) - { - if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180) - flValue = flValue - 360; - if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180) - flValue = flValue + 360; - } - else - { - if (flValue > 360) - flValue = flValue - (int)(flValue / 360.0) * 360.0; - else if (flValue < 0) - flValue = flValue + (int)((flValue / -360.0) + 1) * 360.0; - } - } - - int setting = 255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start); - - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; - pev->controller[iController] = setting; - - return setting * (1.0 / 255.0) * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start; -} - - -float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return flValue; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->blendtype[iBlender] == 0) - return flValue; - - if (pseqdesc->blendtype[iBlender] & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if (pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender]) - flValue = -flValue; - - // does the controller not wrap? - if (pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender]) - { - if (flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) + 180) - flValue = flValue - 360; - if (flValue < ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) - 180) - flValue = flValue + 360; - } - } - - int setting = 255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]); - - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; - - pev->blending[iBlender] = setting; - - return setting * (1.0 / 255.0) * (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]) + pseqdesc->blendstart[iBlender]; -} - - - - -int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return iGoalAnim; - - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - // bail if we're going to or from a node 0 - if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0) - { - return iGoalAnim; - } - - int iEndNode; - - // ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode ); - - if (*piDir > 0) - { - iEndNode = pseqdesc[iEndingAnim].exitnode; - } - else - { - iEndNode = pseqdesc[iEndingAnim].entrynode; - } - - if (iEndNode == pseqdesc[iGoalAnim].entrynode) - { - *piDir = 1; - return iGoalAnim; - } - - byte *pTransition = ((byte *)pstudiohdr + pstudiohdr->transitionindex); - - int iInternNode = pTransition[(iEndNode-1)*pstudiohdr->numtransitions + (pseqdesc[iGoalAnim].entrynode-1)]; - - if (iInternNode == 0) - return iGoalAnim; - - int i; - - // look for someone going - for (i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode) - { - *piDir = 1; - return i; - } - if (pseqdesc[i].nodeflags) - { - if (pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode) - { - *piDir = -1; - return i; - } - } - } - - ALERT( at_console, "error in transition graph" ); - return iGoalAnim; -} - -void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - if (iGroup > pstudiohdr->numbodyparts) - return; - - mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; - - if (iValue >= pbodypart->nummodels) - return; - - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; - - pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base)); -} - - -int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - if (iGroup > pstudiohdr->numbodyparts) - return 0; - - mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; - - if (pbodypart->nummodels <= 1) - return 0; - - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; - - return iCurrent; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include +#include +#include + +#include "../common/nowin.h" + +typedef int BOOL; +#define TRUE 1 +#define FALSE 0 + +// hack into header files that we can ship +typedef int qboolean; +typedef unsigned char byte; +#include "hl/mathlib.h" +#include "../common/const.h" +#include "../engine/progdefs.h" +#include "../engine/edict.h" +#include "../engine/eiface.h" +#include "../engine/studio.h" + +#ifndef ACTIVITY_H +#include "activity.h" +#endif + +#include "activitymap.h" + +#ifndef ANIMATION_H +#include "animation.h" +#endif + +#ifndef SCRIPTEVENT_H +#include "scriptevent.h" +#endif + +#ifndef ENGINECALLBACK_H +#include "enginecallback.h" +#endif + +#include "../mod/AvHServerVariables.h" + +extern globalvars_t *gpGlobals; + +#pragma warning( disable : 4244 ) + + +int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return 0; + + mstudioseqdesc_t *pseqdesc; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + + mins[0] = pseqdesc[ sequence ].bbmin[0]; + mins[1] = pseqdesc[ sequence ].bbmin[1]; + mins[2] = pseqdesc[ sequence ].bbmin[2]; + + maxs[0] = pseqdesc[ sequence ].bbmax[0]; + maxs[1] = pseqdesc[ sequence ].bbmax[1]; + maxs[2] = pseqdesc[ sequence ].bbmax[2]; + + return 1; +} + + +int LookupActivity( void *pmodel, entvars_t *pev, int activity ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return 0; + + mstudioseqdesc_t *pseqdesc; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + + int weighttotal = 0; + int seq = ACTIVITY_NOT_AVAILABLE; + for (int i = 0; i < pstudiohdr->numseq; i++) + { + if (pseqdesc[i].activity == activity) + { + weighttotal += pseqdesc[i].actweight; + if (!weighttotal || RANDOM_LONG(0,weighttotal-1) < pseqdesc[i].actweight) + seq = i; + } + } + + return seq; +} + + +int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if ( !pstudiohdr ) + return 0; + + mstudioseqdesc_t *pseqdesc; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + + int weight = 0; + int seq = ACTIVITY_NOT_AVAILABLE; + for (int i = 0; i < pstudiohdr->numseq; i++) + { + if (pseqdesc[i].activity == activity) + { + if ( pseqdesc[i].actweight > weight ) + { + weight = pseqdesc[i].actweight; + seq = i; + } + } + } + + return seq; +} + +void GetEyePosition ( void *pmodel, float *vecEyePosition ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + + if ( !pstudiohdr ) + { + ALERT ( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" ); + return; + } + + VectorCopy ( pstudiohdr->eyeposition, vecEyePosition ); +} + +int LookupSequence( void *pmodel, const char *label ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return 0; + + mstudioseqdesc_t *pseqdesc; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + + for (int i = 0; i < pstudiohdr->numseq; i++) + { + if (stricmp( pseqdesc[i].label, label ) == 0) + return i; + } + + //if(GetGameRules()->GetIsTesting()) + //if(CVAR_GET_FLOAT(kvTesting) > 0) + //{ + // char theMessage[256]; + // sprintf(theMessage, "%s%s\n", "Couldn't find animation: ", label); + // ALERT(at_console, theMessage); + //} + + return -1; +} + +const char* LookupSequence( void *pmodel, int inSequence) +{ + const char* theSequenceName = NULL; + + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (pstudiohdr) + { + mstudioseqdesc_t* pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + + if((inSequence >= 0) && (inSequence < pstudiohdr->numseq)) + { + theSequenceName = pseqdesc[inSequence].label; + } + } + + return theSequenceName; +} + +int IsSoundEvent( int eventNumber ) +{ + if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) + return 1; + return 0; +} + + +void SequencePrecache( void *pmodel, const char *pSequenceName ) +{ + int index = LookupSequence( pmodel, pSequenceName ); + if ( index >= 0 ) + { + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if ( !pstudiohdr || index >= pstudiohdr->numseq ) + return; + + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; + pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + + for (int i = 0; i < pseqdesc->numevents; i++) + { + // Don't send client-side events to the server AI + if ( pevent[i].event >= EVENT_CLIENT ) + continue; + + // UNDONE: Add a callback to check to see if a sound is precached yet and don't allocate a copy + // of it's name if it is. + if ( IsSoundEvent( pevent[i].event ) ) + { + if ( !strlen(pevent[i].options) ) + { + ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options ); + } + + PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) ); + } + } + } +} + +float GetSequenceDuration( void *pmodel, entvars_t *pev) +{ + float theSequenceDuration = 0.0f; + + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if(pstudiohdr) + { + mstudioseqdesc_t *pseqdesc; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + if(pseqdesc->fps > 0) + { + theSequenceDuration = (pseqdesc->numframes - 1)/pseqdesc->fps; + } + } + + return theSequenceDuration; +} + +void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return; + + mstudioseqdesc_t *pseqdesc; + + if (pev->sequence >= pstudiohdr->numseq) + { + *pflFrameRate = 0.0; + *pflGroundSpeed = 0.0; + return; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + if (pseqdesc->numframes > 1) + { + *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); + *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); + *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); + } + else + { + *pflFrameRate = 256.0; + *pflGroundSpeed = 0.0; + } +} + + +int GetSequenceFlags( void *pmodel, entvars_t *pev ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) + return 0; + + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + return pseqdesc->flags; +} + + +int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) + return 0; + + int events = 0; + + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + + if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) + return 0; + + + if (pseqdesc->numframes > 1) + { + flStart *= (pseqdesc->numframes - 1) / 256.0; + flEnd *= (pseqdesc->numframes - 1) / 256.0; + } + else + { + flStart = 0; + flEnd = 1.0; + } + + for (; index < pseqdesc->numevents; index++) + { + // Don't send client-side events to the server AI + if ( pevent[index].event >= EVENT_CLIENT ) + continue; + + if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) || + ((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) ) + { + pMonsterEvent->event = pevent[index].event; + pMonsterEvent->options = pevent[index].options; + return index + 1; + } + } + return 0; +} + +float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return flValue; + + mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); + + // find first controller that matches the index + int i=0; + for (i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) + { + if (pbonecontroller->index == iController) + break; + } + if (i >= pstudiohdr->numbonecontrollers) + return flValue; + + // wrap 0..360 if it's a rotational controller + + if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) + { + // ugly hack, invert value if end < start + if (pbonecontroller->end < pbonecontroller->start) + flValue = -flValue; + + // does the controller not wrap? + if (pbonecontroller->start + 359.0 >= pbonecontroller->end) + { + if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180) + flValue = flValue - 360; + if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180) + flValue = flValue + 360; + } + else + { + if (flValue > 360) + flValue = flValue - (int)(flValue / 360.0) * 360.0; + else if (flValue < 0) + flValue = flValue + (int)((flValue / -360.0) + 1) * 360.0; + } + } + + int setting = 255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start); + + if (setting < 0) setting = 0; + if (setting > 255) setting = 255; + pev->controller[iController] = setting; + + return setting * (1.0 / 255.0) * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start; +} + + +float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return flValue; + + mstudioseqdesc_t *pseqdesc; + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + if (pseqdesc->blendtype[iBlender] == 0) + return flValue; + + if (pseqdesc->blendtype[iBlender] & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) + { + // ugly hack, invert value if end < start + if (pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender]) + flValue = -flValue; + + // does the controller not wrap? + if (pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender]) + { + if (flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) + 180) + flValue = flValue - 360; + if (flValue < ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) - 180) + flValue = flValue + 360; + } + } + + int setting = 255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]); + + if (setting < 0) setting = 0; + if (setting > 255) setting = 255; + + pev->blending[iBlender] = setting; + + return setting * (1.0 / 255.0) * (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]) + pseqdesc->blendstart[iBlender]; +} + + + + +int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return iGoalAnim; + + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + + // bail if we're going to or from a node 0 + if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0) + { + return iGoalAnim; + } + + int iEndNode; + + // ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode ); + + if (*piDir > 0) + { + iEndNode = pseqdesc[iEndingAnim].exitnode; + } + else + { + iEndNode = pseqdesc[iEndingAnim].entrynode; + } + + if (iEndNode == pseqdesc[iGoalAnim].entrynode) + { + *piDir = 1; + return iGoalAnim; + } + + byte *pTransition = ((byte *)pstudiohdr + pstudiohdr->transitionindex); + + int iInternNode = pTransition[(iEndNode-1)*pstudiohdr->numtransitions + (pseqdesc[iGoalAnim].entrynode-1)]; + + if (iInternNode == 0) + return iGoalAnim; + + int i; + + // look for someone going + for (i = 0; i < pstudiohdr->numseq; i++) + { + if (pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode) + { + *piDir = 1; + return i; + } + if (pseqdesc[i].nodeflags) + { + if (pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode) + { + *piDir = -1; + return i; + } + } + } + + ALERT( at_console, "error in transition graph" ); + return iGoalAnim; +} + +void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return; + + if (iGroup > pstudiohdr->numbodyparts) + return; + + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + + if (iValue >= pbodypart->nummodels) + return; + + int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; + + pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base)); +} + + +int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return 0; + + if (iGroup > pstudiohdr->numbodyparts) + return 0; + + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + + if (pbodypart->nummodels <= 1) + return 0; + + int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; + + return iCurrent; +} diff --git a/main/source/dlls/animation.h b/main/source/dlls/animation.h index b5f1687f..0910d876 100644 --- a/main/source/dlls/animation.h +++ b/main/source/dlls/animation.h @@ -1,49 +1,49 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ANIMATION_H -#define ANIMATION_H - -#define ACTIVITY_NOT_AVAILABLE -1 - -#ifndef MONSTEREVENT_H -#include "monsterevent.h" -#endif - -extern int IsSoundEvent( int eventNumber ); - -int LookupActivity( void *pmodel, entvars_t *pev, int activity ); -int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ); -int LookupSequence( void *pmodel, const char *label ); -const char* LookupSequence( void *pmodel, int inSequence); -float GetSequenceDuration( void *pmodel, entvars_t *pev ); -void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ); -int GetSequenceFlags( void *pmodel, entvars_t *pev ); -int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd ); -float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ); -float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ); -void GetEyePosition( void *pmodel, float *vecEyePosition ); -void SequencePrecache( void *pmodel, const char *pSequenceName ); -int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ); -void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ); -int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ); - -int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ); -int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ); - -// From /engine/studio.h -#define STUDIO_LOOPING 0x0001 - - -#endif //ANIMATION_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ANIMATION_H +#define ANIMATION_H + +#define ACTIVITY_NOT_AVAILABLE -1 + +#ifndef MONSTEREVENT_H +#include "monsterevent.h" +#endif + +extern int IsSoundEvent( int eventNumber ); + +int LookupActivity( void *pmodel, entvars_t *pev, int activity ); +int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ); +int LookupSequence( void *pmodel, const char *label ); +const char* LookupSequence( void *pmodel, int inSequence); +float GetSequenceDuration( void *pmodel, entvars_t *pev ); +void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ); +int GetSequenceFlags( void *pmodel, entvars_t *pev ); +int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd ); +float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ); +float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ); +void GetEyePosition( void *pmodel, float *vecEyePosition ); +void SequencePrecache( void *pmodel, const char *pSequenceName ); +int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ); +void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ); +int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ); + +int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ); +int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ); + +// From /engine/studio.h +#define STUDIO_LOOPING 0x0001 + + +#endif //ANIMATION_H diff --git a/main/source/dlls/apache.cpp b/main/source/dlls/apache.cpp index 86c82591..0c4e7e2c 100644 --- a/main/source/dlls/apache.cpp +++ b/main/source/dlls/apache.cpp @@ -1,1050 +1,1050 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -#define SF_WAITFORTRIGGER (0x04 | 0x40) // UNDONE: Fix! -#define SF_NOWRECKAGE 0x08 - -class CApache : public CBaseMonster -{ - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_HUMAN_MILITARY; }; - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -300, -300, -172); - pev->absmax = pev->origin + Vector(300, 300, 8); - } - - void EXPORT HuntThink( void ); - void EXPORT FlyTouch( CBaseEntity *pOther ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT NullThink( void ); - - void ShowDamage( void ); - void Flight( void ); - void FireRocket( void ); - BOOL FireGun( void ); - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - int m_iRockets; - float m_flForce; - float m_flNextRocket; - - Vector m_vecTarget; - Vector m_posTarget; - - Vector m_vecDesired; - Vector m_posDesired; - - Vector m_vecGoal; - - Vector m_angGun; - float m_flLastSeen; - float m_flPrevSeen; - - int m_iSoundState; // don't save this - - int m_iSpriteTexture; - int m_iExplode; - int m_iBodyGibs; - - float m_flGoalSpeed; - - int m_iDoSmokePuff; - CBeam *m_pBeam; -}; -LINK_ENTITY_TO_CLASS( monster_apache, CApache ); - -TYPEDESCRIPTION CApache::m_SaveData[] = -{ - DEFINE_FIELD( CApache, m_iRockets, FIELD_INTEGER ), - DEFINE_FIELD( CApache, m_flForce, FIELD_FLOAT ), - DEFINE_FIELD( CApache, m_flNextRocket, FIELD_TIME ), - DEFINE_FIELD( CApache, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_posTarget, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CApache, m_vecDesired, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_posDesired, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CApache, m_vecGoal, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_angGun, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_flLastSeen, FIELD_TIME ), - DEFINE_FIELD( CApache, m_flPrevSeen, FIELD_TIME ), -// DEFINE_FIELD( CApache, m_iSoundState, FIELD_INTEGER ), // Don't save, precached -// DEFINE_FIELD( CApache, m_iSpriteTexture, FIELD_INTEGER ), -// DEFINE_FIELD( CApache, m_iExplode, FIELD_INTEGER ), -// DEFINE_FIELD( CApache, m_iBodyGibs, FIELD_INTEGER ), - DEFINE_FIELD( CApache, m_pBeam, FIELD_CLASSPTR ), - DEFINE_FIELD( CApache, m_flGoalSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CApache, m_iDoSmokePuff, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ); - - -void CApache :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/apache.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.apacheHealth; - - m_flFieldOfView = -0.707; // 270 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0, 0xFF); - - InitBoneControllers(); - - if (pev->spawnflags & SF_WAITFORTRIGGER) - { - SetUse( StartupUse ); - } - else - { - SetThink( HuntThink ); - SetTouch( FlyTouch ); - pev->nextthink = gpGlobals->time + 1.0; - } - - m_iRockets = 10; -} - - -void CApache::Precache( void ) -{ - PRECACHE_MODEL("models/apache.mdl"); - - PRECACHE_SOUND("apache/ap_rotor1.wav"); - PRECACHE_SOUND("apache/ap_rotor2.wav"); - PRECACHE_SOUND("apache/ap_rotor3.wav"); - PRECACHE_SOUND("apache/ap_whine1.wav"); - - PRECACHE_SOUND("weapons/mortarhit.wav"); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" ); - - PRECACHE_SOUND("turret/tu_fire1.wav"); - - PRECACHE_MODEL("sprites/lgtning.spr"); - - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); - m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" ); - - UTIL_PrecacheOther( "hvr_rocket" ); -} - - - -void CApache::NullThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.5; -} - - -void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( HuntThink ); - SetTouch( FlyTouch ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse( NULL ); -} - -void CApache :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - - STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( DyingThink ); - SetTouch( CrashTouch ); - pev->nextthink = gpGlobals->time + 0.1; - pev->health = 0; - pev->takedamage = DAMAGE_NO; - - if (pev->spawnflags & SF_NOWRECKAGE) - { - m_flNextRocket = gpGlobals->time + 4.0; - } - else - { - m_flNextRocket = gpGlobals->time + 15.0; - } -} - -void CApache :: DyingThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->avelocity = pev->avelocity * 1.02; - - // still falling? - if (m_flNextRocket > gpGlobals->time ) - { - // random explosions - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 100 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( 400 ); - WRITE_COORD( 400 ); - WRITE_COORD( 132 ); - - // velocity - WRITE_COORD( pev->velocity.x ); - WRITE_COORD( pev->velocity.y ); - WRITE_COORD( pev->velocity.z ); - - // randomization - WRITE_BYTE( 50 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 4 ); // let client decide - - // duration - WRITE_BYTE( 30 );// 3.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - // don't stop it we touch a entity - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.2; - return; - } - else - { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 300 ); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 8 ); // framerate - MESSAGE_END(); - */ - - // fireball - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 256 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 120 ); // scale * 10 - WRITE_BYTE( 255 ); // brightness - MESSAGE_END(); - - // big smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 5 ); // framerate - MESSAGE_END(); - - // blast circle - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 4 ); // life - WRITE_BYTE( 32 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 192 ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); - - RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); - - if (/*!(pev->spawnflags & SF_NOWRECKAGE) && */(pev->flags & FL_ONGROUND)) - { - CBaseEntity *pWreckage = Create( "cycler_wreckage", pev->origin, pev->angles ); - // SET_MODEL( ENT(pWreckage->pev), STRING(pev->model) ); - UTIL_SetSize( pWreckage->pev, Vector( -200, -200, -128 ), Vector( 200, 200, -32 ) ); - pWreckage->pev->frame = pev->frame; - pWreckage->pev->sequence = pev->sequence; - pWreckage->pev->framerate = 0; - pWreckage->pev->dmgtime = gpGlobals->time + 5; - } - - // gibs - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 64); - - // size - WRITE_COORD( 400 ); - WRITE_COORD( 400 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 200 ); - - // randomization - WRITE_BYTE( 30 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 200 ); - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - SetThink( SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - - -void CApache::FlyTouch( CBaseEntity *pOther ) -{ - // bounce if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - - // UNDONE, do a real bounce - pev->velocity = pev->velocity + tr.vecPlaneNormal * (pev->velocity.Length() + 200); - } -} - - -void CApache::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - SetTouch( NULL ); - m_flNextRocket = gpGlobals->time; - pev->nextthink = gpGlobals->time; - } -} - - - -void CApache :: GibMonster( void ) -{ - // EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - - -void CApache :: HuntThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - ShowDamage( ); - - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); - if (m_pGoalEnt) - { - m_posDesired = m_pGoalEnt->pev->origin; - UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); - m_vecGoal = gpGlobals->v_forward; - } - } - - // if (m_hEnemy == NULL) - { - Look( 4092 ); - m_hEnemy = BestVisibleEnemy( ); - } - - // generic speed up - if (m_flGoalSpeed < 800) - m_flGoalSpeed += 5; - - if (m_hEnemy != NULL) - { - // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); - if (FVisible( m_hEnemy )) - { - if (m_flLastSeen < gpGlobals->time - 5) - m_flPrevSeen = gpGlobals->time; - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->Center( ); - } - else - { - m_hEnemy = NULL; - } - } - - m_vecTarget = (m_posTarget - pev->origin).Normalize(); - - float flLength = (pev->origin - m_posDesired).Length(); - - if (m_pGoalEnt) - { - // ALERT( at_console, "%.0f\n", flLength ); - - if (flLength < 128) - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); - if (m_pGoalEnt) - { - m_posDesired = m_pGoalEnt->pev->origin; - UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); - m_vecGoal = gpGlobals->v_forward; - flLength = (pev->origin - m_posDesired).Length(); - } - } - } - else - { - m_posDesired = pev->origin; - } - - if (flLength > 250) // 500 - { - // float flLength2 = (m_posTarget - pev->origin).Length() * (1.5 - DotProduct((m_posTarget - pev->origin).Normalize(), pev->velocity.Normalize() )); - // if (flLength2 < flLength) - if (m_flLastSeen + 90 > gpGlobals->time && DotProduct( (m_posTarget - pev->origin).Normalize(), (m_posDesired - pev->origin).Normalize( )) > 0.25) - { - m_vecDesired = (m_posTarget - pev->origin).Normalize( ); - } - else - { - m_vecDesired = (m_posDesired - pev->origin).Normalize( ); - } - } - else - { - m_vecDesired = m_vecGoal; - } - - Flight( ); - - // ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->time, m_flLastSeen, m_flPrevSeen ); - if ((m_flLastSeen + 1 > gpGlobals->time) && (m_flPrevSeen + 2 < gpGlobals->time)) - { - if (FireGun( )) - { - // slow down if we're fireing - if (m_flGoalSpeed > 400) - m_flGoalSpeed = 400; - } - - // don't fire rockets and gun on easy mode - if (g_iSkillLevel == SKILL_EASY) - m_flNextRocket = gpGlobals->time + 10.0; - } - - UTIL_MakeAimVectors( pev->angles ); - Vector vecEst = (gpGlobals->v_forward * 800 + pev->velocity).Normalize( ); - // ALERT( at_console, "%d %d %d %4.2f\n", pev->angles.x < 0, DotProduct( pev->velocity, gpGlobals->v_forward ) > -100, m_flNextRocket < gpGlobals->time, DotProduct( m_vecTarget, vecEst ) ); - - if ((m_iRockets % 2) == 1) - { - FireRocket( ); - m_flNextRocket = gpGlobals->time + 0.5; - if (m_iRockets <= 0) - { - m_flNextRocket = gpGlobals->time + 10; - m_iRockets = 10; - } - } - else if (pev->angles.x < 0 && DotProduct( pev->velocity, gpGlobals->v_forward ) > -100 && m_flNextRocket < gpGlobals->time) - { - if (m_flLastSeen + 60 > gpGlobals->time) - { - if (m_hEnemy != NULL) - { - // make sure it's a good shot - if (DotProduct( m_vecTarget, vecEst) > .965) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, ignore_monsters, edict(), &tr ); - if ((tr.vecEndPos - m_posTarget).Length() < 512) - FireRocket( ); - } - } - else - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, dont_ignore_monsters, edict(), &tr ); - // just fire when close - if ((tr.vecEndPos - m_posTarget).Length() < 512) - FireRocket( ); - } - } - } -} - - -void CApache :: Flight( void ) -{ - // tilt model 5 degrees - Vector vecAdj = Vector( 5.0, 0, 0 ); - - // estimate where I'll be facing in one seconds - UTIL_MakeAimVectors( pev->angles + pev->avelocity * 2 + vecAdj); - // Vector vecEst1 = pev->origin + pev->velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); - // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); - - float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - - if (flSide < 0) - { - if (pev->avelocity.y < 60) - { - pev->avelocity.y += 8; // 9 * (3.0/2.0); - } - } - else - { - if (pev->avelocity.y > -60) - { - pev->avelocity.y -= 8; // 9 * (3.0/2.0); - } - } - pev->avelocity.y *= 0.98; - - // estimate where I'll be in two seconds - UTIL_MakeAimVectors( pev->angles + pev->avelocity * 1 + vecAdj); - Vector vecEst = pev->origin + pev->velocity * 2.0 + gpGlobals->v_up * m_flForce * 20 - Vector( 0, 0, 384 * 2 ); - - // add immediate force - UTIL_MakeAimVectors( pev->angles + vecAdj); - pev->velocity.x += gpGlobals->v_up.x * m_flForce; - pev->velocity.y += gpGlobals->v_up.y * m_flForce; - pev->velocity.z += gpGlobals->v_up.z * m_flForce; - // add gravity - pev->velocity.z -= 38.4; // 32ft/sec - - - float flSpeed = pev->velocity.Length(); - float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( pev->velocity.x, pev->velocity.y, 0 ) ); - if (flDir < 0) - flSpeed = -flSpeed; - - float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); - - // float flSlip = DotProduct( pev->velocity, gpGlobals->v_right ); - float flSlip = -DotProduct( m_posDesired - vecEst, gpGlobals->v_right ); - - // fly sideways - if (flSlip > 0) - { - if (pev->angles.z > -30 && pev->avelocity.z > -15) - pev->avelocity.z -= 4; - else - pev->avelocity.z += 2; - } - else - { - - if (pev->angles.z < 30 && pev->avelocity.z < 15) - pev->avelocity.z += 4; - else - pev->avelocity.z -= 2; - } - - // sideways drag - pev->velocity.x = pev->velocity.x * (1.0 - fabs( gpGlobals->v_right.x ) * 0.05); - pev->velocity.y = pev->velocity.y * (1.0 - fabs( gpGlobals->v_right.y ) * 0.05); - pev->velocity.z = pev->velocity.z * (1.0 - fabs( gpGlobals->v_right.z ) * 0.05); - - // general drag - pev->velocity = pev->velocity * 0.995; - - // apply power to stay correct height - if (m_flForce < 80 && vecEst.z < m_posDesired.z) - { - m_flForce += 12; - } - else if (m_flForce > 30) - { - if (vecEst.z > m_posDesired.z) - m_flForce -= 8; - } - - // pitch forward or back to get to target - if (flDist > 0 && flSpeed < m_flGoalSpeed /* && flSpeed < flDist */ && pev->angles.x + pev->avelocity.x > -40) - { - // ALERT( at_console, "F " ); - // lean forward - pev->avelocity.x -= 12.0; - } - else if (flDist < 0 && flSpeed > -50 && pev->angles.x + pev->avelocity.x < 20) - { - // ALERT( at_console, "B " ); - // lean backward - pev->avelocity.x += 12.0; - } - else if (pev->angles.x + pev->avelocity.x > 0) - { - // ALERT( at_console, "f " ); - pev->avelocity.x -= 4.0; - } - else if (pev->angles.x + pev->avelocity.x < 0) - { - // ALERT( at_console, "b " ); - pev->avelocity.x += 4.0; - } - - // ALERT( at_console, "%.0f %.0f : %.0f %.0f : %.0f %.0f : %.0f\n", pev->origin.x, pev->velocity.x, flDist, flSpeed, pev->angles.x, pev->avelocity.x, m_flForce ); - // ALERT( at_console, "%.0f %.0f : %.0f %0.f : %.0f\n", pev->origin.z, pev->velocity.z, vecEst.z, m_posDesired.z, m_flForce ); - - // make rotor, engine sounds - if (m_iSoundState == 0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, 0, 110 ); - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - } - else - { - CBaseEntity *pPlayer = NULL; - - pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - // UNDONE: this needs to send different sounds to every player for multiplayer. - if (pPlayer) - { - - float pitch = DotProduct( pev->velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); - - pitch = (int)(100 + pitch / 50.0); - - if (pitch > 250) - pitch = 250; - if (pitch < 50) - pitch = 50; - if (pitch == 100) - pitch = 101; - - float flVol = (m_flForce / 100.0) + .1; - if (flVol > 1.0) - flVol = 1.0; - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - } - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - - // ALERT( at_console, "%.0f %.2f\n", pitch, flVol ); - } -} - - -void CApache :: FireRocket( void ) -{ - static float side = 1.0; - static int count; - - if (m_iRockets <= 0) - return; - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + 1.5 * (gpGlobals->v_forward * 21 + gpGlobals->v_right * 70 * side + gpGlobals->v_up * -79); - - switch( m_iRockets % 5) - { - case 0: vecSrc = vecSrc + gpGlobals->v_right * 10; break; - case 1: vecSrc = vecSrc - gpGlobals->v_right * 10; break; - case 2: vecSrc = vecSrc + gpGlobals->v_up * 10; break; - case 3: vecSrc = vecSrc - gpGlobals->v_up * 10; break; - case 4: break; - } - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - - CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, edict() ); - if (pRocket) - pRocket->pev->velocity = pev->velocity + gpGlobals->v_forward * 100; - - m_iRockets--; - - side = - side; -} - - - -BOOL CApache :: FireGun( ) -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector posGun, angGun; - GetAttachment( 1, posGun, angGun ); - - Vector vecTarget = (m_posTarget - posGun).Normalize( ); - - Vector vecOut; - - vecOut.x = DotProduct( gpGlobals->v_forward, vecTarget ); - vecOut.y = -DotProduct( gpGlobals->v_right, vecTarget ); - vecOut.z = DotProduct( gpGlobals->v_up, vecTarget ); - - Vector angles = UTIL_VecToAngles (vecOut); - - angles.x = -angles.x; - if (angles.y > 180) - angles.y = angles.y - 360; - if (angles.y < -180) - angles.y = angles.y + 360; - if (angles.x > 180) - angles.x = angles.x - 360; - if (angles.x < -180) - angles.x = angles.x + 360; - - if (angles.x > m_angGun.x) - m_angGun.x = min( angles.x, m_angGun.x + 12 ); - if (angles.x < m_angGun.x) - m_angGun.x = max( angles.x, m_angGun.x - 12 ); - if (angles.y > m_angGun.y) - m_angGun.y = min( angles.y, m_angGun.y + 12 ); - if (angles.y < m_angGun.y) - m_angGun.y = max( angles.y, m_angGun.y - 12 ); - - m_angGun.y = SetBoneController( 0, m_angGun.y ); - m_angGun.x = SetBoneController( 1, m_angGun.x ); - - Vector posBarrel, angBarrel; - GetAttachment( 0, posBarrel, angBarrel ); - Vector vecGun = (posBarrel - posGun).Normalize( ); - - if (DotProduct( vecGun, vecTarget ) > 0.98) - { -#if 1 - FireBullets( 1, posGun, vecGun, VECTOR_CONE_4DEGREES, 8192, BULLET_MONSTER_12MM, 1 ); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.3); -#else - static float flNext; - TraceResult tr; - UTIL_TraceLine( posGun, posGun + vecGun * 8192, dont_ignore_monsters, ENT( pev ), &tr ); - - if (!m_pBeam) - { - m_pBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 80 ); - m_pBeam->PointEntInit( pev->origin, entindex( ) ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->SetColor( 255, 180, 96 ); - m_pBeam->SetBrightness( 192 ); - } - - if (flNext < gpGlobals->time) - { - flNext = gpGlobals->time + 0.5; - m_pBeam->SetStartPos( tr.vecEndPos ); - } -#endif - return TRUE; - } - else - { - if (m_pBeam) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - } - return FALSE; -} - - - -void CApache :: ShowDamage( void ) -{ - if (m_iDoSmokePuff > 0 || RANDOM_LONG(0,99) > pev->health) - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z - 32 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - if (m_iDoSmokePuff > 0) - m_iDoSmokePuff--; -} - - -int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (pevInflictor->owner == edict()) - return 0; - - if (bitsDamageType & DMG_BLAST) - { - flDamage *= 2; - } - - /* - if ( (bitsDamageType & DMG_BULLET) && flDamage > 50) - { - // clip bullet damage at 50 - flDamage = 50; - } - */ - - // ALERT( at_console, "%.0f\n", flDamage ); - return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - - -void CApache::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); - - // ignore blades - if (ptr->iHitgroup == 6 && (bitsDamageType & (DMG_ENERGYBEAM|DMG_BULLET|DMG_CLUB))) - return; - - // hit hard, hits cockpit, hits engines - if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2) - { - // ALERT( at_console, "%.0f\n", flDamage ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - m_iDoSmokePuff = 3 + (flDamage / 5.0); - } - else - { - // do half damage in the body - // AddMultiDamage( pevAttacker, this, flDamage / 2.0, bitsDamageType ); - UTIL_Ricochet( ptr->vecEndPos, 2.0 ); - } -} - - - - - -class CApacheHVR : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void EXPORT IgniteThink( void ); - void EXPORT AccelerateThink( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iTrail; - Vector m_vecForward; -}; -LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ); - -TYPEDESCRIPTION CApacheHVR::m_SaveData[] = -{ -// DEFINE_FIELD( CApacheHVR, m_iTrail, FIELD_INTEGER ), // Dont' save, precache - DEFINE_FIELD( CApacheHVR, m_vecForward, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CApacheHVR, CGrenade ); - -void CApacheHVR :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/HVR.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( IgniteThink ); - SetTouch( ExplodeTouch ); - - UTIL_MakeAimVectors( pev->angles ); - m_vecForward = gpGlobals->v_forward; - pev->gravity = 0.5; - - pev->nextthink = gpGlobals->time + 0.1; - - pev->dmg = 150; -} - - -void CApacheHVR :: Precache( void ) -{ - PRECACHE_MODEL("models/HVR.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); -} - - -void CApacheHVR :: IgniteThink( void ) -{ - // pev->movetype = MOVETYPE_TOSS; - - // pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); - - // rocket trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT(entindex()); // entity - WRITE_SHORT(m_iTrail ); // model - WRITE_BYTE( 15 ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - - MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - // set to accelerate - SetThink( AccelerateThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CApacheHVR :: AccelerateThink( void ) -{ - // check world boundaries - if (pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - UTIL_Remove( this ); - return; - } - - // accelerate - float flSpeed = pev->velocity.Length(); - if (flSpeed < 1800) - { - pev->velocity = pev->velocity + m_vecForward * 200; - } - - // re-aim - pev->angles = UTIL_VecToAngles( pev->velocity ); - - pev->nextthink = gpGlobals->time + 0.1; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef OEM_BUILD + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "effects.h" + +extern DLL_GLOBAL int g_iSkillLevel; + +#define SF_WAITFORTRIGGER (0x04 | 0x40) // UNDONE: Fix! +#define SF_NOWRECKAGE 0x08 + +class CApache : public CBaseMonster +{ + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + int Classify( void ) { return CLASS_HUMAN_MILITARY; }; + int BloodColor( void ) { return DONT_BLEED; } + void Killed( entvars_t *pevAttacker, int iGib ); + void GibMonster( void ); + + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -300, -300, -172); + pev->absmax = pev->origin + Vector(300, 300, 8); + } + + void EXPORT HuntThink( void ); + void EXPORT FlyTouch( CBaseEntity *pOther ); + void EXPORT CrashTouch( CBaseEntity *pOther ); + void EXPORT DyingThink( void ); + void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT NullThink( void ); + + void ShowDamage( void ); + void Flight( void ); + void FireRocket( void ); + BOOL FireGun( void ); + + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + + int m_iRockets; + float m_flForce; + float m_flNextRocket; + + Vector m_vecTarget; + Vector m_posTarget; + + Vector m_vecDesired; + Vector m_posDesired; + + Vector m_vecGoal; + + Vector m_angGun; + float m_flLastSeen; + float m_flPrevSeen; + + int m_iSoundState; // don't save this + + int m_iSpriteTexture; + int m_iExplode; + int m_iBodyGibs; + + float m_flGoalSpeed; + + int m_iDoSmokePuff; + CBeam *m_pBeam; +}; +LINK_ENTITY_TO_CLASS( monster_apache, CApache ); + +TYPEDESCRIPTION CApache::m_SaveData[] = +{ + DEFINE_FIELD( CApache, m_iRockets, FIELD_INTEGER ), + DEFINE_FIELD( CApache, m_flForce, FIELD_FLOAT ), + DEFINE_FIELD( CApache, m_flNextRocket, FIELD_TIME ), + DEFINE_FIELD( CApache, m_vecTarget, FIELD_VECTOR ), + DEFINE_FIELD( CApache, m_posTarget, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CApache, m_vecDesired, FIELD_VECTOR ), + DEFINE_FIELD( CApache, m_posDesired, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CApache, m_vecGoal, FIELD_VECTOR ), + DEFINE_FIELD( CApache, m_angGun, FIELD_VECTOR ), + DEFINE_FIELD( CApache, m_flLastSeen, FIELD_TIME ), + DEFINE_FIELD( CApache, m_flPrevSeen, FIELD_TIME ), +// DEFINE_FIELD( CApache, m_iSoundState, FIELD_INTEGER ), // Don't save, precached +// DEFINE_FIELD( CApache, m_iSpriteTexture, FIELD_INTEGER ), +// DEFINE_FIELD( CApache, m_iExplode, FIELD_INTEGER ), +// DEFINE_FIELD( CApache, m_iBodyGibs, FIELD_INTEGER ), + DEFINE_FIELD( CApache, m_pBeam, FIELD_CLASSPTR ), + DEFINE_FIELD( CApache, m_flGoalSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CApache, m_iDoSmokePuff, FIELD_INTEGER ), +}; +IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ); + + +void CApache :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/apache.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); + UTIL_SetOrigin( pev, pev->origin ); + + pev->flags |= FL_MONSTER; + pev->takedamage = DAMAGE_AIM; + pev->health = gSkillData.apacheHealth; + + m_flFieldOfView = -0.707; // 270 degrees + + pev->sequence = 0; + ResetSequenceInfo( ); + pev->frame = RANDOM_LONG(0, 0xFF); + + InitBoneControllers(); + + if (pev->spawnflags & SF_WAITFORTRIGGER) + { + SetUse( StartupUse ); + } + else + { + SetThink( HuntThink ); + SetTouch( FlyTouch ); + pev->nextthink = gpGlobals->time + 1.0; + } + + m_iRockets = 10; +} + + +void CApache::Precache( void ) +{ + PRECACHE_MODEL("models/apache.mdl"); + + PRECACHE_SOUND("apache/ap_rotor1.wav"); + PRECACHE_SOUND("apache/ap_rotor2.wav"); + PRECACHE_SOUND("apache/ap_rotor3.wav"); + PRECACHE_SOUND("apache/ap_whine1.wav"); + + PRECACHE_SOUND("weapons/mortarhit.wav"); + + m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" ); + + PRECACHE_SOUND("turret/tu_fire1.wav"); + + PRECACHE_MODEL("sprites/lgtning.spr"); + + m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); + m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" ); + + UTIL_PrecacheOther( "hvr_rocket" ); +} + + + +void CApache::NullThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.5; +} + + +void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( HuntThink ); + SetTouch( FlyTouch ); + pev->nextthink = gpGlobals->time + 0.1; + SetUse( NULL ); +} + +void CApache :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->movetype = MOVETYPE_TOSS; + pev->gravity = 0.3; + + STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav" ); + + UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); + SetThink( DyingThink ); + SetTouch( CrashTouch ); + pev->nextthink = gpGlobals->time + 0.1; + pev->health = 0; + pev->takedamage = DAMAGE_NO; + + if (pev->spawnflags & SF_NOWRECKAGE) + { + m_flNextRocket = gpGlobals->time + 4.0; + } + else + { + m_flNextRocket = gpGlobals->time + 15.0; + } +} + +void CApache :: DyingThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + pev->avelocity = pev->avelocity * 1.02; + + // still falling? + if (m_flNextRocket > gpGlobals->time ) + { + // random explosions + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now + WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); + WRITE_SHORT( g_sModelIndexFireball ); + WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + + // lots of smoke + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 100 ); // scale * 10 + WRITE_BYTE( 10 ); // framerate + MESSAGE_END(); + + Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_BREAKMODEL); + + // position + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z ); + + // size + WRITE_COORD( 400 ); + WRITE_COORD( 400 ); + WRITE_COORD( 132 ); + + // velocity + WRITE_COORD( pev->velocity.x ); + WRITE_COORD( pev->velocity.y ); + WRITE_COORD( pev->velocity.z ); + + // randomization + WRITE_BYTE( 50 ); + + // Model + WRITE_SHORT( m_iBodyGibs ); //model id# + + // # of shards + WRITE_BYTE( 4 ); // let client decide + + // duration + WRITE_BYTE( 30 );// 3.0 seconds + + // flags + + WRITE_BYTE( BREAK_METAL ); + MESSAGE_END(); + + // don't stop it we touch a entity + pev->flags &= ~FL_ONGROUND; + pev->nextthink = gpGlobals->time + 0.2; + return; + } + else + { + Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + + /* + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 300 ); + WRITE_SHORT( g_sModelIndexFireball ); + WRITE_BYTE( 250 ); // scale * 10 + WRITE_BYTE( 8 ); // framerate + MESSAGE_END(); + */ + + // fireball + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_SPRITE ); + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 256 ); + WRITE_SHORT( m_iExplode ); + WRITE_BYTE( 120 ); // scale * 10 + WRITE_BYTE( 255 ); // brightness + MESSAGE_END(); + + // big smoke + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 512 ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 250 ); // scale * 10 + WRITE_BYTE( 5 ); // framerate + MESSAGE_END(); + + // blast circle + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_BEAMCYLINDER ); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds + WRITE_SHORT( m_iSpriteTexture ); + WRITE_BYTE( 0 ); // startframe + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 4 ); // life + WRITE_BYTE( 32 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 192 ); // r, g, b + WRITE_BYTE( 128 ); // brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); + + EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); + + RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); + + if (/*!(pev->spawnflags & SF_NOWRECKAGE) && */(pev->flags & FL_ONGROUND)) + { + CBaseEntity *pWreckage = Create( "cycler_wreckage", pev->origin, pev->angles ); + // SET_MODEL( ENT(pWreckage->pev), STRING(pev->model) ); + UTIL_SetSize( pWreckage->pev, Vector( -200, -200, -128 ), Vector( 200, 200, -32 ) ); + pWreckage->pev->frame = pev->frame; + pWreckage->pev->sequence = pev->sequence; + pWreckage->pev->framerate = 0; + pWreckage->pev->dmgtime = gpGlobals->time + 5; + } + + // gibs + vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_BREAKMODEL); + + // position + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 64); + + // size + WRITE_COORD( 400 ); + WRITE_COORD( 400 ); + WRITE_COORD( 128 ); + + // velocity + WRITE_COORD( 0 ); + WRITE_COORD( 0 ); + WRITE_COORD( 200 ); + + // randomization + WRITE_BYTE( 30 ); + + // Model + WRITE_SHORT( m_iBodyGibs ); //model id# + + // # of shards + WRITE_BYTE( 200 ); + + // duration + WRITE_BYTE( 200 );// 10.0 seconds + + // flags + + WRITE_BYTE( BREAK_METAL ); + MESSAGE_END(); + + SetThink( SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + } +} + + +void CApache::FlyTouch( CBaseEntity *pOther ) +{ + // bounce if we hit something solid + if ( pOther->pev->solid == SOLID_BSP) + { + TraceResult tr = UTIL_GetGlobalTrace( ); + + // UNDONE, do a real bounce + pev->velocity = pev->velocity + tr.vecPlaneNormal * (pev->velocity.Length() + 200); + } +} + + +void CApache::CrashTouch( CBaseEntity *pOther ) +{ + // only crash if we hit something solid + if ( pOther->pev->solid == SOLID_BSP) + { + SetTouch( NULL ); + m_flNextRocket = gpGlobals->time; + pev->nextthink = gpGlobals->time; + } +} + + + +void CApache :: GibMonster( void ) +{ + // EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); +} + + +void CApache :: HuntThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + ShowDamage( ); + + if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target + { + m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); + if (m_pGoalEnt) + { + m_posDesired = m_pGoalEnt->pev->origin; + UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); + m_vecGoal = gpGlobals->v_forward; + } + } + + // if (m_hEnemy == NULL) + { + Look( 4092 ); + m_hEnemy = BestVisibleEnemy( ); + } + + // generic speed up + if (m_flGoalSpeed < 800) + m_flGoalSpeed += 5; + + if (m_hEnemy != NULL) + { + // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); + if (FVisible( m_hEnemy )) + { + if (m_flLastSeen < gpGlobals->time - 5) + m_flPrevSeen = gpGlobals->time; + m_flLastSeen = gpGlobals->time; + m_posTarget = m_hEnemy->Center( ); + } + else + { + m_hEnemy = NULL; + } + } + + m_vecTarget = (m_posTarget - pev->origin).Normalize(); + + float flLength = (pev->origin - m_posDesired).Length(); + + if (m_pGoalEnt) + { + // ALERT( at_console, "%.0f\n", flLength ); + + if (flLength < 128) + { + m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); + if (m_pGoalEnt) + { + m_posDesired = m_pGoalEnt->pev->origin; + UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); + m_vecGoal = gpGlobals->v_forward; + flLength = (pev->origin - m_posDesired).Length(); + } + } + } + else + { + m_posDesired = pev->origin; + } + + if (flLength > 250) // 500 + { + // float flLength2 = (m_posTarget - pev->origin).Length() * (1.5 - DotProduct((m_posTarget - pev->origin).Normalize(), pev->velocity.Normalize() )); + // if (flLength2 < flLength) + if (m_flLastSeen + 90 > gpGlobals->time && DotProduct( (m_posTarget - pev->origin).Normalize(), (m_posDesired - pev->origin).Normalize( )) > 0.25) + { + m_vecDesired = (m_posTarget - pev->origin).Normalize( ); + } + else + { + m_vecDesired = (m_posDesired - pev->origin).Normalize( ); + } + } + else + { + m_vecDesired = m_vecGoal; + } + + Flight( ); + + // ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->time, m_flLastSeen, m_flPrevSeen ); + if ((m_flLastSeen + 1 > gpGlobals->time) && (m_flPrevSeen + 2 < gpGlobals->time)) + { + if (FireGun( )) + { + // slow down if we're fireing + if (m_flGoalSpeed > 400) + m_flGoalSpeed = 400; + } + + // don't fire rockets and gun on easy mode + if (g_iSkillLevel == SKILL_EASY) + m_flNextRocket = gpGlobals->time + 10.0; + } + + UTIL_MakeAimVectors( pev->angles ); + Vector vecEst = (gpGlobals->v_forward * 800 + pev->velocity).Normalize( ); + // ALERT( at_console, "%d %d %d %4.2f\n", pev->angles.x < 0, DotProduct( pev->velocity, gpGlobals->v_forward ) > -100, m_flNextRocket < gpGlobals->time, DotProduct( m_vecTarget, vecEst ) ); + + if ((m_iRockets % 2) == 1) + { + FireRocket( ); + m_flNextRocket = gpGlobals->time + 0.5; + if (m_iRockets <= 0) + { + m_flNextRocket = gpGlobals->time + 10; + m_iRockets = 10; + } + } + else if (pev->angles.x < 0 && DotProduct( pev->velocity, gpGlobals->v_forward ) > -100 && m_flNextRocket < gpGlobals->time) + { + if (m_flLastSeen + 60 > gpGlobals->time) + { + if (m_hEnemy != NULL) + { + // make sure it's a good shot + if (DotProduct( m_vecTarget, vecEst) > .965) + { + TraceResult tr; + + UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, ignore_monsters, edict(), &tr ); + if ((tr.vecEndPos - m_posTarget).Length() < 512) + FireRocket( ); + } + } + else + { + TraceResult tr; + + UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, dont_ignore_monsters, edict(), &tr ); + // just fire when close + if ((tr.vecEndPos - m_posTarget).Length() < 512) + FireRocket( ); + } + } + } +} + + +void CApache :: Flight( void ) +{ + // tilt model 5 degrees + Vector vecAdj = Vector( 5.0, 0, 0 ); + + // estimate where I'll be facing in one seconds + UTIL_MakeAimVectors( pev->angles + pev->avelocity * 2 + vecAdj); + // Vector vecEst1 = pev->origin + pev->velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); + // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); + + float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); + + if (flSide < 0) + { + if (pev->avelocity.y < 60) + { + pev->avelocity.y += 8; // 9 * (3.0/2.0); + } + } + else + { + if (pev->avelocity.y > -60) + { + pev->avelocity.y -= 8; // 9 * (3.0/2.0); + } + } + pev->avelocity.y *= 0.98; + + // estimate where I'll be in two seconds + UTIL_MakeAimVectors( pev->angles + pev->avelocity * 1 + vecAdj); + Vector vecEst = pev->origin + pev->velocity * 2.0 + gpGlobals->v_up * m_flForce * 20 - Vector( 0, 0, 384 * 2 ); + + // add immediate force + UTIL_MakeAimVectors( pev->angles + vecAdj); + pev->velocity.x += gpGlobals->v_up.x * m_flForce; + pev->velocity.y += gpGlobals->v_up.y * m_flForce; + pev->velocity.z += gpGlobals->v_up.z * m_flForce; + // add gravity + pev->velocity.z -= 38.4; // 32ft/sec + + + float flSpeed = pev->velocity.Length(); + float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( pev->velocity.x, pev->velocity.y, 0 ) ); + if (flDir < 0) + flSpeed = -flSpeed; + + float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); + + // float flSlip = DotProduct( pev->velocity, gpGlobals->v_right ); + float flSlip = -DotProduct( m_posDesired - vecEst, gpGlobals->v_right ); + + // fly sideways + if (flSlip > 0) + { + if (pev->angles.z > -30 && pev->avelocity.z > -15) + pev->avelocity.z -= 4; + else + pev->avelocity.z += 2; + } + else + { + + if (pev->angles.z < 30 && pev->avelocity.z < 15) + pev->avelocity.z += 4; + else + pev->avelocity.z -= 2; + } + + // sideways drag + pev->velocity.x = pev->velocity.x * (1.0 - fabs( gpGlobals->v_right.x ) * 0.05); + pev->velocity.y = pev->velocity.y * (1.0 - fabs( gpGlobals->v_right.y ) * 0.05); + pev->velocity.z = pev->velocity.z * (1.0 - fabs( gpGlobals->v_right.z ) * 0.05); + + // general drag + pev->velocity = pev->velocity * 0.995; + + // apply power to stay correct height + if (m_flForce < 80 && vecEst.z < m_posDesired.z) + { + m_flForce += 12; + } + else if (m_flForce > 30) + { + if (vecEst.z > m_posDesired.z) + m_flForce -= 8; + } + + // pitch forward or back to get to target + if (flDist > 0 && flSpeed < m_flGoalSpeed /* && flSpeed < flDist */ && pev->angles.x + pev->avelocity.x > -40) + { + // ALERT( at_console, "F " ); + // lean forward + pev->avelocity.x -= 12.0; + } + else if (flDist < 0 && flSpeed > -50 && pev->angles.x + pev->avelocity.x < 20) + { + // ALERT( at_console, "B " ); + // lean backward + pev->avelocity.x += 12.0; + } + else if (pev->angles.x + pev->avelocity.x > 0) + { + // ALERT( at_console, "f " ); + pev->avelocity.x -= 4.0; + } + else if (pev->angles.x + pev->avelocity.x < 0) + { + // ALERT( at_console, "b " ); + pev->avelocity.x += 4.0; + } + + // ALERT( at_console, "%.0f %.0f : %.0f %.0f : %.0f %.0f : %.0f\n", pev->origin.x, pev->velocity.x, flDist, flSpeed, pev->angles.x, pev->avelocity.x, m_flForce ); + // ALERT( at_console, "%.0f %.0f : %.0f %0.f : %.0f\n", pev->origin.z, pev->velocity.z, vecEst.z, m_posDesired.z, m_flForce ); + + // make rotor, engine sounds + if (m_iSoundState == 0) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, 0, 110 ); + // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); + + m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions + } + else + { + CBaseEntity *pPlayer = NULL; + + pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); + // UNDONE: this needs to send different sounds to every player for multiplayer. + if (pPlayer) + { + + float pitch = DotProduct( pev->velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); + + pitch = (int)(100 + pitch / 50.0); + + if (pitch > 250) + pitch = 250; + if (pitch < 50) + pitch = 50; + if (pitch == 100) + pitch = 101; + + float flVol = (m_flForce / 100.0) + .1; + if (flVol > 1.0) + flVol = 1.0; + + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); + } + // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); + + // ALERT( at_console, "%.0f %.2f\n", pitch, flVol ); + } +} + + +void CApache :: FireRocket( void ) +{ + static float side = 1.0; + static int count; + + if (m_iRockets <= 0) + return; + + UTIL_MakeAimVectors( pev->angles ); + Vector vecSrc = pev->origin + 1.5 * (gpGlobals->v_forward * 21 + gpGlobals->v_right * 70 * side + gpGlobals->v_up * -79); + + switch( m_iRockets % 5) + { + case 0: vecSrc = vecSrc + gpGlobals->v_right * 10; break; + case 1: vecSrc = vecSrc - gpGlobals->v_right * 10; break; + case 2: vecSrc = vecSrc + gpGlobals->v_up * 10; break; + case 3: vecSrc = vecSrc - gpGlobals->v_up * 10; break; + case 4: break; + } + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSrc.x ); + WRITE_COORD( vecSrc.y ); + WRITE_COORD( vecSrc.z ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 20 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + MESSAGE_END(); + + CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, edict() ); + if (pRocket) + pRocket->pev->velocity = pev->velocity + gpGlobals->v_forward * 100; + + m_iRockets--; + + side = - side; +} + + + +BOOL CApache :: FireGun( ) +{ + UTIL_MakeAimVectors( pev->angles ); + + Vector posGun, angGun; + GetAttachment( 1, posGun, angGun ); + + Vector vecTarget = (m_posTarget - posGun).Normalize( ); + + Vector vecOut; + + vecOut.x = DotProduct( gpGlobals->v_forward, vecTarget ); + vecOut.y = -DotProduct( gpGlobals->v_right, vecTarget ); + vecOut.z = DotProduct( gpGlobals->v_up, vecTarget ); + + Vector angles = UTIL_VecToAngles (vecOut); + + angles.x = -angles.x; + if (angles.y > 180) + angles.y = angles.y - 360; + if (angles.y < -180) + angles.y = angles.y + 360; + if (angles.x > 180) + angles.x = angles.x - 360; + if (angles.x < -180) + angles.x = angles.x + 360; + + if (angles.x > m_angGun.x) + m_angGun.x = min( angles.x, m_angGun.x + 12 ); + if (angles.x < m_angGun.x) + m_angGun.x = max( angles.x, m_angGun.x - 12 ); + if (angles.y > m_angGun.y) + m_angGun.y = min( angles.y, m_angGun.y + 12 ); + if (angles.y < m_angGun.y) + m_angGun.y = max( angles.y, m_angGun.y - 12 ); + + m_angGun.y = SetBoneController( 0, m_angGun.y ); + m_angGun.x = SetBoneController( 1, m_angGun.x ); + + Vector posBarrel, angBarrel; + GetAttachment( 0, posBarrel, angBarrel ); + Vector vecGun = (posBarrel - posGun).Normalize( ); + + if (DotProduct( vecGun, vecTarget ) > 0.98) + { +#if 1 + FireBullets( 1, posGun, vecGun, VECTOR_CONE_4DEGREES, 8192, BULLET_MONSTER_12MM, 1 ); + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.3); +#else + static float flNext; + TraceResult tr; + UTIL_TraceLine( posGun, posGun + vecGun * 8192, dont_ignore_monsters, ENT( pev ), &tr ); + + if (!m_pBeam) + { + m_pBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 80 ); + m_pBeam->PointEntInit( pev->origin, entindex( ) ); + m_pBeam->SetEndAttachment( 1 ); + m_pBeam->SetColor( 255, 180, 96 ); + m_pBeam->SetBrightness( 192 ); + } + + if (flNext < gpGlobals->time) + { + flNext = gpGlobals->time + 0.5; + m_pBeam->SetStartPos( tr.vecEndPos ); + } +#endif + return TRUE; + } + else + { + if (m_pBeam) + { + UTIL_Remove( m_pBeam ); + m_pBeam = NULL; + } + } + return FALSE; +} + + + +void CApache :: ShowDamage( void ) +{ + if (m_iDoSmokePuff > 0 || RANDOM_LONG(0,99) > pev->health) + { + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z - 32 ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + MESSAGE_END(); + } + if (m_iDoSmokePuff > 0) + m_iDoSmokePuff--; +} + + +int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if (pevInflictor->owner == edict()) + return 0; + + if (bitsDamageType & DMG_BLAST) + { + flDamage *= 2; + } + + /* + if ( (bitsDamageType & DMG_BULLET) && flDamage > 50) + { + // clip bullet damage at 50 + flDamage = 50; + } + */ + + // ALERT( at_console, "%.0f\n", flDamage ); + return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + + + +void CApache::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); + + // ignore blades + if (ptr->iHitgroup == 6 && (bitsDamageType & (DMG_ENERGYBEAM|DMG_BULLET|DMG_CLUB))) + return; + + // hit hard, hits cockpit, hits engines + if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2) + { + // ALERT( at_console, "%.0f\n", flDamage ); + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + m_iDoSmokePuff = 3 + (flDamage / 5.0); + } + else + { + // do half damage in the body + // AddMultiDamage( pevAttacker, this, flDamage / 2.0, bitsDamageType ); + UTIL_Ricochet( ptr->vecEndPos, 2.0 ); + } +} + + + + + +class CApacheHVR : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + void EXPORT IgniteThink( void ); + void EXPORT AccelerateThink( void ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_iTrail; + Vector m_vecForward; +}; +LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ); + +TYPEDESCRIPTION CApacheHVR::m_SaveData[] = +{ +// DEFINE_FIELD( CApacheHVR, m_iTrail, FIELD_INTEGER ), // Dont' save, precache + DEFINE_FIELD( CApacheHVR, m_vecForward, FIELD_VECTOR ), +}; + +IMPLEMENT_SAVERESTORE( CApacheHVR, CGrenade ); + +void CApacheHVR :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/HVR.mdl"); + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetOrigin( pev, pev->origin ); + + SetThink( IgniteThink ); + SetTouch( ExplodeTouch ); + + UTIL_MakeAimVectors( pev->angles ); + m_vecForward = gpGlobals->v_forward; + pev->gravity = 0.5; + + pev->nextthink = gpGlobals->time + 0.1; + + pev->dmg = 150; +} + + +void CApacheHVR :: Precache( void ) +{ + PRECACHE_MODEL("models/HVR.mdl"); + m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); + PRECACHE_SOUND ("weapons/rocket1.wav"); +} + + +void CApacheHVR :: IgniteThink( void ) +{ + // pev->movetype = MOVETYPE_TOSS; + + // pev->movetype = MOVETYPE_FLY; + pev->effects |= EF_LIGHT; + + // make rocket sound + EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); + + // rocket trail + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + + WRITE_BYTE( TE_BEAMFOLLOW ); + WRITE_SHORT(entindex()); // entity + WRITE_SHORT(m_iTrail ); // model + WRITE_BYTE( 15 ); // life + WRITE_BYTE( 5 ); // width + WRITE_BYTE( 224 ); // r, g, b + WRITE_BYTE( 224 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + + MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) + + // set to accelerate + SetThink( AccelerateThink ); + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CApacheHVR :: AccelerateThink( void ) +{ + // check world boundaries + if (pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + { + UTIL_Remove( this ); + return; + } + + // accelerate + float flSpeed = pev->velocity.Length(); + if (flSpeed < 1800) + { + pev->velocity = pev->velocity + m_vecForward * 200; + } + + // re-aim + pev->angles = UTIL_VecToAngles( pev->velocity ); + + pev->nextthink = gpGlobals->time + 0.1; +} + + #endif \ No newline at end of file diff --git a/main/source/dlls/barnacle.cpp b/main/source/dlls/barnacle.cpp index 49ba76d1..8648f27e 100644 --- a/main/source/dlls/barnacle.cpp +++ b/main/source/dlls/barnacle.cpp @@ -1,428 +1,428 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// barnacle - stationary ceiling mounted 'fishing' monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -#define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is. -#define BARNACLE_PULL_SPEED 8 -#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them. - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BARNACLE_AE_PUKEGIB 2 - -class CBarnacle : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - CBaseEntity *TongueTouchEnt ( float *pflLength ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void EXPORT BarnacleThink ( void ); - void EXPORT WaitTillDead ( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flAltitude; - float m_flKillVictimTime; - int m_cGibs;// barnacle loads up on gibs each time it kills something. - BOOL m_fTongueExtended; - BOOL m_fLiftingPrey; - float m_flTongueAdj; -}; -LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ); - -TYPEDESCRIPTION CBarnacle::m_SaveData[] = -{ - DEFINE_FIELD( CBarnacle, m_flAltitude, FIELD_FLOAT ), - DEFINE_FIELD( CBarnacle, m_flKillVictimTime, FIELD_TIME ), - DEFINE_FIELD( CBarnacle, m_cGibs, FIELD_INTEGER ),// barnacle loads up on gibs each time it kills something. - DEFINE_FIELD( CBarnacle, m_fTongueExtended, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarnacle, m_fLiftingPrey, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarnacle, m_flTongueAdj, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ); - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBarnacle :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BARNACLE_AE_PUKEGIB: - CGib::SpawnRandomGibs( pev, 1, 1 ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarnacle :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/barnacle.mdl"); - UTIL_SetSize( pev, Vector(-16, -16, -32), Vector(16, 16, 0) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_AIM; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = EF_INVLIGHT; // take light from the ceiling - pev->health = 25; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flKillVictimTime = 0; - m_cGibs = 0; - m_fLiftingPrey = FALSE; - m_flTongueAdj = -100; - - InitBoneControllers(); - - SetActivity ( ACT_IDLE ); - - SetThink ( &CBarnacle::BarnacleThink ); - pev->nextthink = gpGlobals->time + 0.5; - - UTIL_SetOrigin ( pev, pev->origin ); -} - -int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( bitsDamageType & DMG_CLUB ) - { - flDamage = pev->health; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -//========================================================= -void CBarnacle :: BarnacleThink ( void ) -{ - CBaseEntity *pTouchEnt; - CBaseMonster *pVictim; - float flLength; - - pev->nextthink = gpGlobals->time + 0.1; - - if ( m_hEnemy != NULL ) - { -// barnacle has prey. - - if ( !m_hEnemy->IsAlive() ) - { - // someone (maybe even the barnacle) killed the prey. Reset barnacle. - m_fLiftingPrey = FALSE;// indicate that we're not lifting prey. - m_hEnemy = NULL; - return; - } - - if ( m_fLiftingPrey ) - { - if ( m_hEnemy != NULL && m_hEnemy->pev->deadflag != DEAD_NO ) - { - // crap, someone killed the prey on the way up. - m_hEnemy = NULL; - m_fLiftingPrey = FALSE; - return; - } - - // still pulling prey. - Vector vecNewEnemyOrigin = m_hEnemy->pev->origin; - vecNewEnemyOrigin.x = pev->origin.x; - vecNewEnemyOrigin.y = pev->origin.y; - - // guess as to where their neck is - vecNewEnemyOrigin.x -= 6 * cos(m_hEnemy->pev->angles.y * M_PI/180.0); - vecNewEnemyOrigin.y -= 6 * sin(m_hEnemy->pev->angles.y * M_PI/180.0); - - m_flAltitude -= BARNACLE_PULL_SPEED; - vecNewEnemyOrigin.z += BARNACLE_PULL_SPEED; - - if ( fabs( pev->origin.z - ( vecNewEnemyOrigin.z + m_hEnemy->pev->view_ofs.z - 8 ) ) < BARNACLE_BODY_HEIGHT ) - { - // prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body ) - m_fLiftingPrey = FALSE; - - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_bite3.wav", 1, ATTN_NORM ); - - pVictim = m_hEnemy->MyMonsterPointer(); - - m_flKillVictimTime = gpGlobals->time + 10;// now that the victim is in place, the killing bite will be administered in 10 seconds. - - if ( pVictim ) - { - pVictim->BarnacleVictimBitten( pev ); - SetActivity ( ACT_EAT ); - } - } - - UTIL_SetOrigin ( m_hEnemy->pev, vecNewEnemyOrigin ); - } - else - { - // prey is lifted fully into feeding position and is dangling there. - - pVictim = m_hEnemy->MyMonsterPointer(); - - if ( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) - { - // kill! - if ( pVictim ) - { - pVictim->TakeDamage ( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); - m_cGibs = 3; - } - - return; - } - - // bite prey every once in a while - if ( pVictim && ( RANDOM_LONG(0,49) == 0 ) ) - { - switch ( RANDOM_LONG(0,2) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; - } - - pVictim->BarnacleVictimBitten( pev ); - } - - } - } - else - { -// barnacle has no prey right now, so just idle and check to see if anything is touching the tongue. - - // If idle and no nearby client, don't think so often - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); // Stagger a bit to keep barnacles from thinking on the same frame - - if ( m_fSequenceFinished ) - {// this is done so barnacle will fidget. - SetActivity ( ACT_IDLE ); - m_flTongueAdj = -100; - } - - if ( m_cGibs && RANDOM_LONG(0,99) == 1 ) - { - // cough up a gib. - CGib::SpawnRandomGibs( pev, 1, 1 ); - m_cGibs--; - - switch ( RANDOM_LONG(0,2) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; - } - } - - pTouchEnt = TongueTouchEnt( &flLength ); - - if ( pTouchEnt != NULL && m_fTongueExtended ) - { - // tongue is fully extended, and is touching someone. - if ( pTouchEnt->FBecomeProne() ) - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); - - SetSequenceByName ( "attack1" ); - m_flTongueAdj = -20; - - m_hEnemy = pTouchEnt; - - pTouchEnt->pev->movetype = MOVETYPE_FLY; - pTouchEnt->pev->velocity = g_vecZero; - pTouchEnt->pev->basevelocity = g_vecZero; - pTouchEnt->pev->origin.x = pev->origin.x; - pTouchEnt->pev->origin.y = pev->origin.y; - - m_fLiftingPrey = TRUE;// indicate that we should be lifting prey. - m_flKillVictimTime = -1;// set this to a bogus time while the victim is lifted. - - m_flAltitude = (pev->origin.z - pTouchEnt->EyePosition().z); - } - } - else - { - // calculate a new length for the tongue to be clear of anything else that moves under it. - if ( m_flAltitude < flLength ) - { - // if tongue is higher than is should be, lower it kind of slowly. - m_flAltitude += BARNACLE_PULL_SPEED; - m_fTongueExtended = FALSE; - } - else - { - m_flAltitude = flLength; - m_fTongueExtended = TRUE; - } - - } - - } - - // ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj ); - SetBoneController( 0, -(m_flAltitude + m_flTongueAdj) ); - StudioFrameAdvance( 0.1 ); -} - -//========================================================= -// Killed. -//========================================================= -void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster *pVictim; - - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - - if ( m_hEnemy != NULL ) - { - pVictim = m_hEnemy->MyMonsterPointer(); - - if ( pVictim ) - { - pVictim->BarnacleVictimReleased(); - } - } - -// CGib::SpawnRandomGibs( pev, 4, 1 ); - - switch ( RANDOM_LONG ( 0, 1 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_die1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_die3.wav", 1, ATTN_NORM ); break; - } - - SetActivity ( ACT_DIESIMPLE ); - SetBoneController( 0, 0 ); - - StudioFrameAdvance( 0.1 ); - - pev->nextthink = gpGlobals->time + 0.1; - SetThink ( &CBarnacle::WaitTillDead ); -} - -//========================================================= -//========================================================= -void CBarnacle :: WaitTillDead ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - float flInterval = StudioFrameAdvance( 0.1 ); - DispatchAnimEvents ( flInterval ); - - if ( m_fSequenceFinished ) - { - // death anim finished. - StopAnimation(); - SetThink ( NULL ); - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarnacle :: Precache() -{ - PRECACHE_MODEL("models/barnacle.mdl"); - - PRECACHE_SOUND("barnacle/bcl_alert2.wav");//happy, lifting food up - PRECACHE_SOUND("barnacle/bcl_bite3.wav");//just got food to mouth - PRECACHE_SOUND("barnacle/bcl_chew1.wav"); - PRECACHE_SOUND("barnacle/bcl_chew2.wav"); - PRECACHE_SOUND("barnacle/bcl_chew3.wav"); - PRECACHE_SOUND("barnacle/bcl_die1.wav" ); - PRECACHE_SOUND("barnacle/bcl_die3.wav" ); -} - -//========================================================= -// TongueTouchEnt - does a trace along the barnacle's tongue -// to see if any entity is touching it. Also stores the length -// of the trace in the int pointer provided. -//========================================================= -#define BARNACLE_CHECK_SPACING 8 -CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength ) -{ - TraceResult tr; - float length; - - // trace once to hit architecture and see if the tongue needs to change position. - UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0 , 0 , 2048 ), ignore_monsters, ENT(pev), &tr ); - length = fabs( pev->origin.z - tr.vecEndPos.z ); - if ( pflLength ) - { - *pflLength = length; - } - - Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 ); - Vector mins = pev->origin - delta; - Vector maxs = pev->origin + delta; - maxs.z = pev->origin.z; - mins.z -= length; - - CBaseEntity *pList[10]; - int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_MONSTER) ); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - // only clients and monsters - if ( pList[i] != this && IRelationship( pList[i] ) > R_NO && pList[ i ]->pev->deadflag == DEAD_NO ) // this ent is one of our enemies. Barnacle tries to eat it. - { - return pList[i]; - } - } - } - - return NULL; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// barnacle - stationary ceiling mounted 'fishing' monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + +#define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is. +#define BARNACLE_PULL_SPEED 8 +#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them. + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define BARNACLE_AE_PUKEGIB 2 + +class CBarnacle : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + CBaseEntity *TongueTouchEnt ( float *pflLength ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void EXPORT BarnacleThink ( void ); + void EXPORT WaitTillDead ( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + float m_flAltitude; + float m_flKillVictimTime; + int m_cGibs;// barnacle loads up on gibs each time it kills something. + BOOL m_fTongueExtended; + BOOL m_fLiftingPrey; + float m_flTongueAdj; +}; +LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ); + +TYPEDESCRIPTION CBarnacle::m_SaveData[] = +{ + DEFINE_FIELD( CBarnacle, m_flAltitude, FIELD_FLOAT ), + DEFINE_FIELD( CBarnacle, m_flKillVictimTime, FIELD_TIME ), + DEFINE_FIELD( CBarnacle, m_cGibs, FIELD_INTEGER ),// barnacle loads up on gibs each time it kills something. + DEFINE_FIELD( CBarnacle, m_fTongueExtended, FIELD_BOOLEAN ), + DEFINE_FIELD( CBarnacle, m_fLiftingPrey, FIELD_BOOLEAN ), + DEFINE_FIELD( CBarnacle, m_flTongueAdj, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ); + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CBarnacle :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case BARNACLE_AE_PUKEGIB: + CGib::SpawnRandomGibs( pev, 1, 1 ); + break; + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CBarnacle :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/barnacle.mdl"); + UTIL_SetSize( pev, Vector(-16, -16, -32), Vector(16, 16, 0) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_NONE; + pev->takedamage = DAMAGE_AIM; + m_bloodColor = BLOOD_COLOR_RED; + pev->effects = EF_INVLIGHT; // take light from the ceiling + pev->health = 25; + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_flKillVictimTime = 0; + m_cGibs = 0; + m_fLiftingPrey = FALSE; + m_flTongueAdj = -100; + + InitBoneControllers(); + + SetActivity ( ACT_IDLE ); + + SetThink ( &CBarnacle::BarnacleThink ); + pev->nextthink = gpGlobals->time + 0.5; + + UTIL_SetOrigin ( pev, pev->origin ); +} + +int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + if ( bitsDamageType & DMG_CLUB ) + { + flDamage = pev->health; + } + + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +//========================================================= +//========================================================= +void CBarnacle :: BarnacleThink ( void ) +{ + CBaseEntity *pTouchEnt; + CBaseMonster *pVictim; + float flLength; + + pev->nextthink = gpGlobals->time + 0.1; + + if ( m_hEnemy != NULL ) + { +// barnacle has prey. + + if ( !m_hEnemy->IsAlive() ) + { + // someone (maybe even the barnacle) killed the prey. Reset barnacle. + m_fLiftingPrey = FALSE;// indicate that we're not lifting prey. + m_hEnemy = NULL; + return; + } + + if ( m_fLiftingPrey ) + { + if ( m_hEnemy != NULL && m_hEnemy->pev->deadflag != DEAD_NO ) + { + // crap, someone killed the prey on the way up. + m_hEnemy = NULL; + m_fLiftingPrey = FALSE; + return; + } + + // still pulling prey. + Vector vecNewEnemyOrigin = m_hEnemy->pev->origin; + vecNewEnemyOrigin.x = pev->origin.x; + vecNewEnemyOrigin.y = pev->origin.y; + + // guess as to where their neck is + vecNewEnemyOrigin.x -= 6 * cos(m_hEnemy->pev->angles.y * M_PI/180.0); + vecNewEnemyOrigin.y -= 6 * sin(m_hEnemy->pev->angles.y * M_PI/180.0); + + m_flAltitude -= BARNACLE_PULL_SPEED; + vecNewEnemyOrigin.z += BARNACLE_PULL_SPEED; + + if ( fabs( pev->origin.z - ( vecNewEnemyOrigin.z + m_hEnemy->pev->view_ofs.z - 8 ) ) < BARNACLE_BODY_HEIGHT ) + { + // prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body ) + m_fLiftingPrey = FALSE; + + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_bite3.wav", 1, ATTN_NORM ); + + pVictim = m_hEnemy->MyMonsterPointer(); + + m_flKillVictimTime = gpGlobals->time + 10;// now that the victim is in place, the killing bite will be administered in 10 seconds. + + if ( pVictim ) + { + pVictim->BarnacleVictimBitten( pev ); + SetActivity ( ACT_EAT ); + } + } + + UTIL_SetOrigin ( m_hEnemy->pev, vecNewEnemyOrigin ); + } + else + { + // prey is lifted fully into feeding position and is dangling there. + + pVictim = m_hEnemy->MyMonsterPointer(); + + if ( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) + { + // kill! + if ( pVictim ) + { + pVictim->TakeDamage ( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); + m_cGibs = 3; + } + + return; + } + + // bite prey every once in a while + if ( pVictim && ( RANDOM_LONG(0,49) == 0 ) ) + { + switch ( RANDOM_LONG(0,2) ) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; + case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; + } + + pVictim->BarnacleVictimBitten( pev ); + } + + } + } + else + { +// barnacle has no prey right now, so just idle and check to see if anything is touching the tongue. + + // If idle and no nearby client, don't think so often + if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); // Stagger a bit to keep barnacles from thinking on the same frame + + if ( m_fSequenceFinished ) + {// this is done so barnacle will fidget. + SetActivity ( ACT_IDLE ); + m_flTongueAdj = -100; + } + + if ( m_cGibs && RANDOM_LONG(0,99) == 1 ) + { + // cough up a gib. + CGib::SpawnRandomGibs( pev, 1, 1 ); + m_cGibs--; + + switch ( RANDOM_LONG(0,2) ) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; + case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; + } + } + + pTouchEnt = TongueTouchEnt( &flLength ); + + if ( pTouchEnt != NULL && m_fTongueExtended ) + { + // tongue is fully extended, and is touching someone. + if ( pTouchEnt->FBecomeProne() ) + { + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); + + SetSequenceByName ( "attack1" ); + m_flTongueAdj = -20; + + m_hEnemy = pTouchEnt; + + pTouchEnt->pev->movetype = MOVETYPE_FLY; + pTouchEnt->pev->velocity = g_vecZero; + pTouchEnt->pev->basevelocity = g_vecZero; + pTouchEnt->pev->origin.x = pev->origin.x; + pTouchEnt->pev->origin.y = pev->origin.y; + + m_fLiftingPrey = TRUE;// indicate that we should be lifting prey. + m_flKillVictimTime = -1;// set this to a bogus time while the victim is lifted. + + m_flAltitude = (pev->origin.z - pTouchEnt->EyePosition().z); + } + } + else + { + // calculate a new length for the tongue to be clear of anything else that moves under it. + if ( m_flAltitude < flLength ) + { + // if tongue is higher than is should be, lower it kind of slowly. + m_flAltitude += BARNACLE_PULL_SPEED; + m_fTongueExtended = FALSE; + } + else + { + m_flAltitude = flLength; + m_fTongueExtended = TRUE; + } + + } + + } + + // ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj ); + SetBoneController( 0, -(m_flAltitude + m_flTongueAdj) ); + StudioFrameAdvance( 0.1 ); +} + +//========================================================= +// Killed. +//========================================================= +void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) +{ + CBaseMonster *pVictim; + + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + + if ( m_hEnemy != NULL ) + { + pVictim = m_hEnemy->MyMonsterPointer(); + + if ( pVictim ) + { + pVictim->BarnacleVictimReleased(); + } + } + +// CGib::SpawnRandomGibs( pev, 4, 1 ); + + switch ( RANDOM_LONG ( 0, 1 ) ) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_die1.wav", 1, ATTN_NORM ); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_die3.wav", 1, ATTN_NORM ); break; + } + + SetActivity ( ACT_DIESIMPLE ); + SetBoneController( 0, 0 ); + + StudioFrameAdvance( 0.1 ); + + pev->nextthink = gpGlobals->time + 0.1; + SetThink ( &CBarnacle::WaitTillDead ); +} + +//========================================================= +//========================================================= +void CBarnacle :: WaitTillDead ( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + float flInterval = StudioFrameAdvance( 0.1 ); + DispatchAnimEvents ( flInterval ); + + if ( m_fSequenceFinished ) + { + // death anim finished. + StopAnimation(); + SetThink ( NULL ); + } +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CBarnacle :: Precache() +{ + PRECACHE_MODEL("models/barnacle.mdl"); + + PRECACHE_SOUND("barnacle/bcl_alert2.wav");//happy, lifting food up + PRECACHE_SOUND("barnacle/bcl_bite3.wav");//just got food to mouth + PRECACHE_SOUND("barnacle/bcl_chew1.wav"); + PRECACHE_SOUND("barnacle/bcl_chew2.wav"); + PRECACHE_SOUND("barnacle/bcl_chew3.wav"); + PRECACHE_SOUND("barnacle/bcl_die1.wav" ); + PRECACHE_SOUND("barnacle/bcl_die3.wav" ); +} + +//========================================================= +// TongueTouchEnt - does a trace along the barnacle's tongue +// to see if any entity is touching it. Also stores the length +// of the trace in the int pointer provided. +//========================================================= +#define BARNACLE_CHECK_SPACING 8 +CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength ) +{ + TraceResult tr; + float length; + + // trace once to hit architecture and see if the tongue needs to change position. + UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0 , 0 , 2048 ), ignore_monsters, ENT(pev), &tr ); + length = fabs( pev->origin.z - tr.vecEndPos.z ); + if ( pflLength ) + { + *pflLength = length; + } + + Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 ); + Vector mins = pev->origin - delta; + Vector maxs = pev->origin + delta; + maxs.z = pev->origin.z; + mins.z -= length; + + CBaseEntity *pList[10]; + int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_MONSTER) ); + if ( count ) + { + for ( int i = 0; i < count; i++ ) + { + // only clients and monsters + if ( pList[i] != this && IRelationship( pList[i] ) > R_NO && pList[ i ]->pev->deadflag == DEAD_NO ) // this ent is one of our enemies. Barnacle tries to eat it. + { + return pList[i]; + } + } + } + + return NULL; +} diff --git a/main/source/dlls/barney.cpp b/main/source/dlls/barney.cpp index 8bc39c71..e71253b7 100644 --- a/main/source/dlls/barney.cpp +++ b/main/source/dlls/barney.cpp @@ -1,842 +1,842 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monster template -//========================================================= -// UNDONE: Holster weapon? - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "weapons.h" -#include "soundent.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -// first flag is barney dying for scripted sequences? -#define BARNEY_AE_DRAW ( 2 ) -#define BARNEY_AE_SHOOT ( 3 ) -#define BARNEY_AE_HOLSTER ( 4 ) - -#define BARNEY_BODY_GUNHOLSTERED 0 -#define BARNEY_BODY_GUNDRAWN 1 -#define BARNEY_BODY_GUNGONE 2 - -class CBarney : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - void BarneyFirePistol( void ); - void AlertSound( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - - void DeclineFollowing( void ); - - // Override these to set behavior - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule ( void ); - MONSTERSTATE GetIdealState ( void ); - - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); - - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL m_fGunDrawn; - float m_painTime; - float m_checkAttackTime; - BOOL m_lastAttackCheck; - - // UNDONE: What is this for? It isn't used? - float m_flPlayerDamage;// how much pain has the player inflicted on me? - - CUSTOM_SCHEDULES; -}; - -LINK_ENTITY_TO_CLASS( monster_barney, CBarney ); - -TYPEDESCRIPTION CBarney::m_SaveData[] = -{ - DEFINE_FIELD( CBarney, m_fGunDrawn, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarney, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CBarney, m_checkAttackTime, FIELD_TIME ), - DEFINE_FIELD( CBarney, m_lastAttackCheck, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarney, m_flPlayerDamage, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ); - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlBaFollow[] = -{ - { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slBaFollow[] = -{ - { - tlBaFollow, - ARRAYSIZE ( tlBaFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "Follow" - }, -}; - -//========================================================= -// BarneyDraw- much better looking draw schedule for when -// barney knows who he's gonna attack. -//========================================================= -Task_t tlBarneyEnemyDraw[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, 0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, -}; - -Schedule_t slBarneyEnemyDraw[] = -{ - { - tlBarneyEnemyDraw, - ARRAYSIZE ( tlBarneyEnemyDraw ), - 0, - 0, - "Barney Enemy Draw" - } -}; - -Task_t tlBaFaceTarget[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, -}; - -Schedule_t slBaFaceTarget[] = -{ - { - tlBaFaceTarget, - ARRAYSIZE ( tlBaFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "FaceTarget" - }, -}; - - -Task_t tlIdleBaStand[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. - { TASK_TLK_HEADRESET, (float)0 }, // reset head position -}; - -Schedule_t slIdleBaStand[] = -{ - { - tlIdleBaStand, - ARRAYSIZE ( tlIdleBaStand ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleStand" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CBarney ) -{ - slBaFollow, - slBarneyEnemyDraw, - slBaFaceTarget, - slIdleBaStand, -}; - - -IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ); - -void CBarney :: StartTask( Task_t *pTask ) -{ - CTalkMonster::StartTask( pTask ); -} - -void CBarney :: RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - if (m_hEnemy != NULL && (m_hEnemy->IsPlayer())) - { - pev->framerate = 1.5; - } - CTalkMonster::RunTask( pTask ); - break; - default: - CTalkMonster::RunTask( pTask ); - break; - } -} - - - - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CBarney :: ISoundMask ( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBarney :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// ALertSound - barney says "Freeze!" -//========================================================= -void CBarney :: AlertSound( void ) -{ - if ( m_hEnemy != NULL ) - { - if ( FOkToSpeak() ) - { - PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - } - } - -} -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBarney :: SetYawSpeed ( void ) -{ - int ys; - - ys = 0; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 70; - break; - case ACT_WALK: - ys = 70; - break; - case ACT_RUN: - ys = 90; - break; - default: - ys = 70; - break; - } - - pev->yaw_speed = ys; -} - - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDist <= 1024 && flDot >= 0.5 ) - { - if ( gpGlobals->time > m_checkAttackTime ) - { - TraceResult tr; - - Vector shootOrigin = pev->origin + Vector( 0, 0, 55 ); - CBaseEntity *pEnemy = m_hEnemy; - Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP ); - UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr ); - m_checkAttackTime = gpGlobals->time + 1; - if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) ) - m_lastAttackCheck = TRUE; - else - m_lastAttackCheck = FALSE; - m_checkAttackTime = gpGlobals->time + 1.5; - } - return m_lastAttackCheck; - } - return FALSE; -} - - -//========================================================= -// BarneyFirePistol - shoots one round from the pistol at -// the enemy barney is facing. -//========================================================= -void CBarney :: BarneyFirePistol ( void ) -{ - Vector vecShootOrigin; - - UTIL_MakeVectors(pev->angles); - vecShootOrigin = pev->origin + Vector( 0, 0, 55 ); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - pev->effects = EF_MUZZLEFLASH; - - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM ); - - int pitchShift = RANDOM_LONG( 0, 20 ); - - // Only shift about half the time - if ( pitchShift > 10 ) - pitchShift = 0; - else - pitchShift -= 5; - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift ); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); - - // UNDONE: Reload? - m_cAmmoLoaded--;// take away a bullet! -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBarney :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BARNEY_AE_SHOOT: - BarneyFirePistol(); - break; - - case BARNEY_AE_DRAW: - // barney's bodygroup switches here so he can pull gun from holster - pev->body = BARNEY_BODY_GUNDRAWN; - m_fGunDrawn = TRUE; - break; - - case BARNEY_AE_HOLSTER: - // change bodygroup to replace gun in holster - pev->body = BARNEY_BODY_GUNHOLSTERED; - m_fGunDrawn = FALSE; - break; - - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarney :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/barney.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.barneyHealth; - pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - - pev->body = 0; // gun in holster - m_fGunDrawn = FALSE; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - MonsterInit(); - SetUse( &CBarney::FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarney :: Precache() -{ - PRECACHE_MODEL("models/barney.mdl"); - - PRECACHE_SOUND("barney/ba_attack1.wav" ); - PRECACHE_SOUND("barney/ba_attack2.wav" ); - - PRECACHE_SOUND("barney/ba_pain1.wav"); - PRECACHE_SOUND("barney/ba_pain2.wav"); - PRECACHE_SOUND("barney/ba_pain3.wav"); - - PRECACHE_SOUND("barney/ba_die1.wav"); - PRECACHE_SOUND("barney/ba_die2.wav"); - PRECACHE_SOUND("barney/ba_die3.wav"); - - // every new barney must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - CTalkMonster::Precache(); -} - -// Init talk data -void CBarney :: TalkInit() -{ - - CTalkMonster::TalkInit(); - - // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "BA_ANSWER"; - m_szGrp[TLK_QUESTION] = "BA_QUESTION"; - m_szGrp[TLK_IDLE] = "BA_IDLE"; - m_szGrp[TLK_STARE] = "BA_STARE"; - m_szGrp[TLK_USE] = "BA_OK"; - m_szGrp[TLK_UNUSE] = "BA_WAIT"; - m_szGrp[TLK_STOP] = "BA_STOP"; - - m_szGrp[TLK_NOSHOOT] = "BA_SCARED"; - m_szGrp[TLK_HELLO] = "BA_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!BA_CUREA"; - m_szGrp[TLK_PLHURT2] = "!BA_CUREB"; - m_szGrp[TLK_PLHURT3] = "!BA_CUREC"; - - m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE - m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE - m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE - - m_szGrp[TLK_SMELL] = "BA_SMELL"; - - m_szGrp[TLK_WOUND] = "BA_WOUND"; - m_szGrp[TLK_MORTAL] = "BA_MORTAL"; - - // get voice for head - just one barney voice for now - m_voicePitch = 100; -} - - -static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) -{ - Vector vecDir = (reference - pevTest->origin); - vecDir.z = 0; - vecDir = vecDir.Normalize(); - Vector forward, angle; - angle = pevTest->v_angle; - angle.x = 0; - UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL ); - // He's facing me, he meant it - if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so - { - return TRUE; - } - return FALSE; -} - - -int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) -{ - // make sure friends talk about it if player hurts talkmonsters... - int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); - if ( !IsAlive() || pev->deadflag == DEAD_DYING ) - return ret; - - if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) ) - { - m_flPlayerDamage += flDamage; - - // This is a heurstic to determine if the player intended to harm me - // If I have an enemy, we can't establish intent (may just be crossfire) - if ( m_hEnemy == NULL ) - { - // If the player was facing directly at me, or I'm already suspicious, get mad - if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) ) - { - // Alright, now I'm pissed! - PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); - - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - else - { - // Hey, be careful with that - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - Remember( bits_MEMORY_SUSPICIOUS ); - } - } - else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) - { - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - } - } - - return ret; -} - - -//========================================================= -// PainSound -//========================================================= -void CBarney :: PainSound ( void ) -{ - if (gpGlobals->time < m_painTime) - return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CBarney :: DeathSound ( void ) -{ - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - } -} - - -void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - switch( ptr->iHitgroup) - { - case HITGROUP_CHEST: - case HITGROUP_STOMACH: - if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST)) - { - flDamage = flDamage / 2; - } - break; - case 10: - if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB)) - { - flDamage -= 20; - if (flDamage <= 0) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // always a head shot - ptr->iHitgroup = HITGROUP_HEAD; - break; - } - - CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -void CBarney::Killed( entvars_t *pevAttacker, int iGib ) -{ - if ( pev->body < BARNEY_BODY_GUNGONE ) - {// drop the gun! - Vector vecGunPos; - Vector vecGunAngles; - - pev->body = BARNEY_BODY_GUNGONE; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - // Removed because AvH doesn't use this weapon - //CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); - } - - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -Schedule_t* CBarney :: GetScheduleOfType ( int Type ) -{ - Schedule_t *psched; - - switch( Type ) - { - case SCHED_ARM_WEAPON: - if ( m_hEnemy != NULL ) - { - // face enemy, then draw. - return slBarneyEnemyDraw; - } - break; - - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that barney will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slBaFaceTarget; // override this for different target face behavior - else - return psched; - - case SCHED_TARGET_CHASE: - return slBaFollow; - - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - { - // just look straight ahead. - return slIdleBaStand; - } - else - return psched; - } - - return CTalkMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CBarney :: GetSchedule ( void ) -{ - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() ) - { - PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM ); - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - // always act surprized with a new enemy - if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) ) - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - - // wait for one schedule to draw gun - if (!m_fGunDrawn ) - return GetScheduleOfType( SCHED_ARM_WEAPON ); - - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) - { - // flinch if hurt - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - if ( m_hEnemy == NULL && IsFollowing() ) - { - if ( !m_hTargetEnt->IsAlive() ) - { - // UNDONE: Comment about the recently dead player here? - StopFollowing( FALSE ); - break; - } - else - { - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) - { - return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); - } - return GetScheduleOfType( SCHED_TARGET_FACE ); - } - } - - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) - { - return GetScheduleOfType( SCHED_MOVE_AWAY ); - } - - // try to say something about smells - TrySmellTalk(); - break; - } - - return CTalkMonster::GetSchedule(); -} - -MONSTERSTATE CBarney :: GetIdealState ( void ) -{ - return CTalkMonster::GetIdealState(); -} - - - -void CBarney::DeclineFollowing( void ) -{ - PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM ); -} - - - - - -//========================================================= -// DEAD BARNEY PROP -// -// Designer selects a pose in worldcraft, 0 through num_poses-1 -// this value is added to what is selected as the 'first dead pose' -// among the monster's normal animations. All dead poses must -// appear sequentially in the model file. Be sure and set -// the m_iFirstPose properly! -// -//========================================================= -class CDeadBarney : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_PLAYER_ALLY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[3]; -}; - -char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; - -void CDeadBarney::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ); - -//========================================================= -// ********** DeadBarney SPAWN ********** -//========================================================= -void CDeadBarney :: Spawn( ) -{ - PRECACHE_MODEL("models/barney.mdl"); - SET_MODEL(ENT(pev), "models/barney.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead barney with bad pose\n" ); - } - // Corpses have less health - pev->health = 8;//gSkillData.barneyHealth; - - MonsterInitDead(); -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// monster template +//========================================================= +// UNDONE: Holster weapon? + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "talkmonster.h" +#include "schedule.h" +#include "defaultai.h" +#include "scripted.h" +#include "weapons.h" +#include "soundent.h" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +// first flag is barney dying for scripted sequences? +#define BARNEY_AE_DRAW ( 2 ) +#define BARNEY_AE_SHOOT ( 3 ) +#define BARNEY_AE_HOLSTER ( 4 ) + +#define BARNEY_BODY_GUNHOLSTERED 0 +#define BARNEY_BODY_GUNDRAWN 1 +#define BARNEY_BODY_GUNGONE 2 + +class CBarney : public CTalkMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int ISoundMask( void ); + void BarneyFirePistol( void ); + void AlertSound( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + + void RunTask( Task_t *pTask ); + void StartTask( Task_t *pTask ); + virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + + void DeclineFollowing( void ); + + // Override these to set behavior + Schedule_t *GetScheduleOfType ( int Type ); + Schedule_t *GetSchedule ( void ); + MONSTERSTATE GetIdealState ( void ); + + void DeathSound( void ); + void PainSound( void ); + + void TalkInit( void ); + + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + void Killed( entvars_t *pevAttacker, int iGib ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + BOOL m_fGunDrawn; + float m_painTime; + float m_checkAttackTime; + BOOL m_lastAttackCheck; + + // UNDONE: What is this for? It isn't used? + float m_flPlayerDamage;// how much pain has the player inflicted on me? + + CUSTOM_SCHEDULES; +}; + +LINK_ENTITY_TO_CLASS( monster_barney, CBarney ); + +TYPEDESCRIPTION CBarney::m_SaveData[] = +{ + DEFINE_FIELD( CBarney, m_fGunDrawn, FIELD_BOOLEAN ), + DEFINE_FIELD( CBarney, m_painTime, FIELD_TIME ), + DEFINE_FIELD( CBarney, m_checkAttackTime, FIELD_TIME ), + DEFINE_FIELD( CBarney, m_lastAttackCheck, FIELD_BOOLEAN ), + DEFINE_FIELD( CBarney, m_flPlayerDamage, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ); + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= +Task_t tlBaFollow[] = +{ + { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, +}; + +Schedule_t slBaFollow[] = +{ + { + tlBaFollow, + ARRAYSIZE ( tlBaFollow ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_PROVOKED, + bits_SOUND_DANGER, + "Follow" + }, +}; + +//========================================================= +// BarneyDraw- much better looking draw schedule for when +// barney knows who he's gonna attack. +//========================================================= +Task_t tlBarneyEnemyDraw[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, 0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, +}; + +Schedule_t slBarneyEnemyDraw[] = +{ + { + tlBarneyEnemyDraw, + ARRAYSIZE ( tlBarneyEnemyDraw ), + 0, + 0, + "Barney Enemy Draw" + } +}; + +Task_t tlBaFaceTarget[] = +{ + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_TARGET, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, +}; + +Schedule_t slBaFaceTarget[] = +{ + { + tlBaFaceTarget, + ARRAYSIZE ( tlBaFaceTarget ), + bits_COND_CLIENT_PUSH | + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_PROVOKED, + bits_SOUND_DANGER, + "FaceTarget" + }, +}; + + +Task_t tlIdleBaStand[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. + { TASK_TLK_HEADRESET, (float)0 }, // reset head position +}; + +Schedule_t slIdleBaStand[] = +{ + { + tlIdleBaStand, + ARRAYSIZE ( tlIdleBaStand ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_SMELL | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. + //bits_SOUND_PLAYER | + //bits_SOUND_WORLD | + + bits_SOUND_DANGER | + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "IdleStand" + }, +}; + +DEFINE_CUSTOM_SCHEDULES( CBarney ) +{ + slBaFollow, + slBarneyEnemyDraw, + slBaFaceTarget, + slIdleBaStand, +}; + + +IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ); + +void CBarney :: StartTask( Task_t *pTask ) +{ + CTalkMonster::StartTask( pTask ); +} + +void CBarney :: RunTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_RANGE_ATTACK1: + if (m_hEnemy != NULL && (m_hEnemy->IsPlayer())) + { + pev->framerate = 1.5; + } + CTalkMonster::RunTask( pTask ); + break; + default: + CTalkMonster::RunTask( pTask ); + break; + } +} + + + + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. +//========================================================= +int CBarney :: ISoundMask ( void) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_CARCASS | + bits_SOUND_MEAT | + bits_SOUND_GARBAGE | + bits_SOUND_DANGER | + bits_SOUND_PLAYER; +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CBarney :: Classify ( void ) +{ + return CLASS_PLAYER_ALLY; +} + +//========================================================= +// ALertSound - barney says "Freeze!" +//========================================================= +void CBarney :: AlertSound( void ) +{ + if ( m_hEnemy != NULL ) + { + if ( FOkToSpeak() ) + { + PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + } + } + +} +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CBarney :: SetYawSpeed ( void ) +{ + int ys; + + ys = 0; + + switch ( m_Activity ) + { + case ACT_IDLE: + ys = 70; + break; + case ACT_WALK: + ys = 70; + break; + case ACT_RUN: + ys = 90; + break; + default: + ys = 70; + break; + } + + pev->yaw_speed = ys; +} + + +//========================================================= +// CheckRangeAttack1 +//========================================================= +BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( flDist <= 1024 && flDot >= 0.5 ) + { + if ( gpGlobals->time > m_checkAttackTime ) + { + TraceResult tr; + + Vector shootOrigin = pev->origin + Vector( 0, 0, 55 ); + CBaseEntity *pEnemy = m_hEnemy; + Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP ); + UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr ); + m_checkAttackTime = gpGlobals->time + 1; + if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) ) + m_lastAttackCheck = TRUE; + else + m_lastAttackCheck = FALSE; + m_checkAttackTime = gpGlobals->time + 1.5; + } + return m_lastAttackCheck; + } + return FALSE; +} + + +//========================================================= +// BarneyFirePistol - shoots one round from the pistol at +// the enemy barney is facing. +//========================================================= +void CBarney :: BarneyFirePistol ( void ) +{ + Vector vecShootOrigin; + + UTIL_MakeVectors(pev->angles); + vecShootOrigin = pev->origin + Vector( 0, 0, 55 ); + Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); + + Vector angDir = UTIL_VecToAngles( vecShootDir ); + SetBlending( 0, angDir.x ); + pev->effects = EF_MUZZLEFLASH; + + FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM ); + + int pitchShift = RANDOM_LONG( 0, 20 ); + + // Only shift about half the time + if ( pitchShift > 10 ) + pitchShift = 0; + else + pitchShift -= 5; + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift ); + + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); + + // UNDONE: Reload? + m_cAmmoLoaded--;// take away a bullet! +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CBarney :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case BARNEY_AE_SHOOT: + BarneyFirePistol(); + break; + + case BARNEY_AE_DRAW: + // barney's bodygroup switches here so he can pull gun from holster + pev->body = BARNEY_BODY_GUNDRAWN; + m_fGunDrawn = TRUE; + break; + + case BARNEY_AE_HOLSTER: + // change bodygroup to replace gun in holster + pev->body = BARNEY_BODY_GUNHOLSTERED; + m_fGunDrawn = FALSE; + break; + + default: + CTalkMonster::HandleAnimEvent( pEvent ); + } +} + +//========================================================= +// Spawn +//========================================================= +void CBarney :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/barney.mdl"); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->health = gSkillData.barneyHealth; + pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. + m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello + m_MonsterState = MONSTERSTATE_NONE; + + pev->body = 0; // gun in holster + m_fGunDrawn = FALSE; + + m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; + + MonsterInit(); + SetUse( &CBarney::FollowerUse ); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CBarney :: Precache() +{ + PRECACHE_MODEL("models/barney.mdl"); + + PRECACHE_SOUND("barney/ba_attack1.wav" ); + PRECACHE_SOUND("barney/ba_attack2.wav" ); + + PRECACHE_SOUND("barney/ba_pain1.wav"); + PRECACHE_SOUND("barney/ba_pain2.wav"); + PRECACHE_SOUND("barney/ba_pain3.wav"); + + PRECACHE_SOUND("barney/ba_die1.wav"); + PRECACHE_SOUND("barney/ba_die2.wav"); + PRECACHE_SOUND("barney/ba_die3.wav"); + + // every new barney must call this, otherwise + // when a level is loaded, nobody will talk (time is reset to 0) + TalkInit(); + CTalkMonster::Precache(); +} + +// Init talk data +void CBarney :: TalkInit() +{ + + CTalkMonster::TalkInit(); + + // scientists speach group names (group names are in sentences.txt) + + m_szGrp[TLK_ANSWER] = "BA_ANSWER"; + m_szGrp[TLK_QUESTION] = "BA_QUESTION"; + m_szGrp[TLK_IDLE] = "BA_IDLE"; + m_szGrp[TLK_STARE] = "BA_STARE"; + m_szGrp[TLK_USE] = "BA_OK"; + m_szGrp[TLK_UNUSE] = "BA_WAIT"; + m_szGrp[TLK_STOP] = "BA_STOP"; + + m_szGrp[TLK_NOSHOOT] = "BA_SCARED"; + m_szGrp[TLK_HELLO] = "BA_HELLO"; + + m_szGrp[TLK_PLHURT1] = "!BA_CUREA"; + m_szGrp[TLK_PLHURT2] = "!BA_CUREB"; + m_szGrp[TLK_PLHURT3] = "!BA_CUREC"; + + m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE + m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE + m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE + + m_szGrp[TLK_SMELL] = "BA_SMELL"; + + m_szGrp[TLK_WOUND] = "BA_WOUND"; + m_szGrp[TLK_MORTAL] = "BA_MORTAL"; + + // get voice for head - just one barney voice for now + m_voicePitch = 100; +} + + +static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) +{ + Vector vecDir = (reference - pevTest->origin); + vecDir.z = 0; + vecDir = vecDir.Normalize(); + Vector forward, angle; + angle = pevTest->v_angle; + angle.x = 0; + UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL ); + // He's facing me, he meant it + if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so + { + return TRUE; + } + return FALSE; +} + + +int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +{ + // make sure friends talk about it if player hurts talkmonsters... + int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); + if ( !IsAlive() || pev->deadflag == DEAD_DYING ) + return ret; + + if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) ) + { + m_flPlayerDamage += flDamage; + + // This is a heurstic to determine if the player intended to harm me + // If I have an enemy, we can't establish intent (may just be crossfire) + if ( m_hEnemy == NULL ) + { + // If the player was facing directly at me, or I'm already suspicious, get mad + if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) ) + { + // Alright, now I'm pissed! + PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); + + Remember( bits_MEMORY_PROVOKED ); + StopFollowing( TRUE ); + } + else + { + // Hey, be careful with that + PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); + Remember( bits_MEMORY_SUSPICIOUS ); + } + } + else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) + { + PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); + } + } + + return ret; +} + + +//========================================================= +// PainSound +//========================================================= +void CBarney :: PainSound ( void ) +{ + if (gpGlobals->time < m_painTime) + return; + + m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); + + switch (RANDOM_LONG(0,2)) + { + case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + } +} + +//========================================================= +// DeathSound +//========================================================= +void CBarney :: DeathSound ( void ) +{ + switch (RANDOM_LONG(0,2)) + { + case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + } +} + + +void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + switch( ptr->iHitgroup) + { + case HITGROUP_CHEST: + case HITGROUP_STOMACH: + if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST)) + { + flDamage = flDamage / 2; + } + break; + case 10: + if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB)) + { + flDamage -= 20; + if (flDamage <= 0) + { + UTIL_Ricochet( ptr->vecEndPos, 1.0 ); + flDamage = 0.01; + } + } + // always a head shot + ptr->iHitgroup = HITGROUP_HEAD; + break; + } + + CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); +} + + +void CBarney::Killed( entvars_t *pevAttacker, int iGib ) +{ + if ( pev->body < BARNEY_BODY_GUNGONE ) + {// drop the gun! + Vector vecGunPos; + Vector vecGunAngles; + + pev->body = BARNEY_BODY_GUNGONE; + + GetAttachment( 0, vecGunPos, vecGunAngles ); + + // Removed because AvH doesn't use this weapon + //CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); + } + + SetUse( NULL ); + CTalkMonster::Killed( pevAttacker, iGib ); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +Schedule_t* CBarney :: GetScheduleOfType ( int Type ) +{ + Schedule_t *psched; + + switch( Type ) + { + case SCHED_ARM_WEAPON: + if ( m_hEnemy != NULL ) + { + // face enemy, then draw. + return slBarneyEnemyDraw; + } + break; + + // Hook these to make a looping schedule + case SCHED_TARGET_FACE: + // call base class default so that barney will talk + // when 'used' + psched = CTalkMonster::GetScheduleOfType(Type); + + if (psched == slIdleStand) + return slBaFaceTarget; // override this for different target face behavior + else + return psched; + + case SCHED_TARGET_CHASE: + return slBaFollow; + + case SCHED_IDLE_STAND: + // call base class default so that scientist will talk + // when standing during idle + psched = CTalkMonster::GetScheduleOfType(Type); + + if (psched == slIdleStand) + { + // just look straight ahead. + return slIdleBaStand; + } + else + return psched; + } + + return CTalkMonster::GetScheduleOfType( Type ); +} + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CBarney :: GetSchedule ( void ) +{ + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() ) + { + PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM ); + } + + switch( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + // always act surprized with a new enemy + if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) ) + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + + // wait for one schedule to draw gun + if (!m_fGunDrawn ) + return GetScheduleOfType( SCHED_ARM_WEAPON ); + + if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); + } + break; + + case MONSTERSTATE_ALERT: + case MONSTERSTATE_IDLE: + if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) + { + // flinch if hurt + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + + if ( m_hEnemy == NULL && IsFollowing() ) + { + if ( !m_hTargetEnt->IsAlive() ) + { + // UNDONE: Comment about the recently dead player here? + StopFollowing( FALSE ); + break; + } + else + { + if ( HasConditions( bits_COND_CLIENT_PUSH ) ) + { + return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); + } + return GetScheduleOfType( SCHED_TARGET_FACE ); + } + } + + if ( HasConditions( bits_COND_CLIENT_PUSH ) ) + { + return GetScheduleOfType( SCHED_MOVE_AWAY ); + } + + // try to say something about smells + TrySmellTalk(); + break; + } + + return CTalkMonster::GetSchedule(); +} + +MONSTERSTATE CBarney :: GetIdealState ( void ) +{ + return CTalkMonster::GetIdealState(); +} + + + +void CBarney::DeclineFollowing( void ) +{ + PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM ); +} + + + + + +//========================================================= +// DEAD BARNEY PROP +// +// Designer selects a pose in worldcraft, 0 through num_poses-1 +// this value is added to what is selected as the 'first dead pose' +// among the monster's normal animations. All dead poses must +// appear sequentially in the model file. Be sure and set +// the m_iFirstPose properly! +// +//========================================================= +class CDeadBarney : public CBaseMonster +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_PLAYER_ALLY; } + + void KeyValue( KeyValueData *pkvd ); + + int m_iPose;// which sequence to display -- temporary, don't need to save + static char *m_szPoses[3]; +}; + +char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; + +void CDeadBarney::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "pose")) + { + m_iPose = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseMonster::KeyValue( pkvd ); +} + +LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ); + +//========================================================= +// ********** DeadBarney SPAWN ********** +//========================================================= +void CDeadBarney :: Spawn( ) +{ + PRECACHE_MODEL("models/barney.mdl"); + SET_MODEL(ENT(pev), "models/barney.mdl"); + + pev->effects = 0; + pev->yaw_speed = 8; + pev->sequence = 0; + m_bloodColor = BLOOD_COLOR_RED; + + pev->sequence = LookupSequence( m_szPoses[m_iPose] ); + if (pev->sequence == -1) + { + ALERT ( at_console, "Dead barney with bad pose\n" ); + } + // Corpses have less health + pev->health = 8;//gSkillData.barneyHealth; + + MonsterInitDead(); +} + + diff --git a/main/source/dlls/basemonster.h b/main/source/dlls/basemonster.h index d17db81d..fcfdaec2 100644 --- a/main/source/dlls/basemonster.h +++ b/main/source/dlls/basemonster.h @@ -1,95 +1,95 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef BASEMONSTER_H -#define BASEMONSTER_H - -class CBaseMonster : public CBaseToggle -{ -public: - Activity m_Activity;// what the monster is doing (animation) - Activity m_IdealActivity;// monster should switch to this activity - int m_LastHitGroup; // the last body region that took damage - int m_bitsDamageType; // what types of damage has monster (player) taken - BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; - MONSTERSTATE m_MonsterState;// monster's current state - MONSTERSTATE m_IdealMonsterState;// monster should change to this state - int m_afConditions; - int m_afMemory; - float m_flNextAttack; // cannot attack again until this time - EHANDLE m_hEnemy; // the entity that the monster is fighting. - EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach - float m_flFieldOfView;// width of monster's field of view ( dot product ) - int m_bloodColor; // color of blood particless - Vector m_HackedGunPos; // HACK until we can query end of gun - Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) - - - void KeyValue( KeyValueData *pkvd ); - - void MakeIdealYaw( Vector vecTarget ); - virtual float ChangeYaw ( int speed ); - virtual BOOL HasHumanGibs( void ); - virtual BOOL HasAlienGibs( void ); - virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled - virtual void GibMonster( void ); - virtual Activity GetDeathActivity ( void ); - Activity GetSmallFlinchActivity( void ); - virtual void BecomeDead( void ); - BOOL ShouldGibMonster( int iGib ); - void CallGibMonster( void ); - virtual BOOL ShouldFadeOnDeath( void ); - BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. - virtual int IRelationship ( CBaseEntity *pTarget ); - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - float DamageForce( float damage ); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void PainSound ( void ) { return; }; - - void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - - inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; } - inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; } - inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; } - inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; } - - inline void Remember( int iMemory ) { m_afMemory |= iMemory; } - inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } - inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } - inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } - - // This will stop animation until you call ResetSequenceInfo() at some point in the future - inline void StopAnimation( void ) { pev->framerate = 0; } - - virtual void ReportAIState( void ); - virtual void MonsterInitDead( void ); // Call after animation/pose is set up - void EXPORT CorpseFallThink( void ); - - virtual void Look ( int iDistance );// basic sight function for monsters - virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack - CBaseEntity *CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ); - virtual int GetHull() const; - virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone - virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); - virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } - -}; - - -#endif +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef BASEMONSTER_H +#define BASEMONSTER_H + +class CBaseMonster : public CBaseToggle +{ +public: + Activity m_Activity;// what the monster is doing (animation) + Activity m_IdealActivity;// monster should switch to this activity + int m_LastHitGroup; // the last body region that took damage + int m_bitsDamageType; // what types of damage has monster (player) taken + BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; + MONSTERSTATE m_MonsterState;// monster's current state + MONSTERSTATE m_IdealMonsterState;// monster should change to this state + int m_afConditions; + int m_afMemory; + float m_flNextAttack; // cannot attack again until this time + EHANDLE m_hEnemy; // the entity that the monster is fighting. + EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach + float m_flFieldOfView;// width of monster's field of view ( dot product ) + int m_bloodColor; // color of blood particless + Vector m_HackedGunPos; // HACK until we can query end of gun + Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) + + + void KeyValue( KeyValueData *pkvd ); + + void MakeIdealYaw( Vector vecTarget ); + virtual float ChangeYaw ( int speed ); + virtual BOOL HasHumanGibs( void ); + virtual BOOL HasAlienGibs( void ); + virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled + virtual void GibMonster( void ); + virtual Activity GetDeathActivity ( void ); + Activity GetSmallFlinchActivity( void ); + virtual void BecomeDead( void ); + BOOL ShouldGibMonster( int iGib ); + void CallGibMonster( void ); + virtual BOOL ShouldFadeOnDeath( void ); + BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. + virtual int IRelationship ( CBaseEntity *pTarget ); + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + float DamageForce( float damage ); + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual void PainSound ( void ) { return; }; + + void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); + void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); + + inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; } + inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; } + inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; } + inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; } + + inline void Remember( int iMemory ) { m_afMemory |= iMemory; } + inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } + inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } + inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } + + // This will stop animation until you call ResetSequenceInfo() at some point in the future + inline void StopAnimation( void ) { pev->framerate = 0; } + + virtual void ReportAIState( void ); + virtual void MonsterInitDead( void ); // Call after animation/pose is set up + void EXPORT CorpseFallThink( void ); + + virtual void Look ( int iDistance );// basic sight function for monsters + virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack + CBaseEntity *CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ); + virtual int GetHull() const; + virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone + virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); + virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } + +}; + + +#endif diff --git a/main/source/dlls/bigmomma.cpp b/main/source/dlls/bigmomma.cpp index f49e160b..8f225ef6 100644 --- a/main/source/dlls/bigmomma.cpp +++ b/main/source/dlls/bigmomma.cpp @@ -1,1251 +1,1251 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// monster template -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "decals.h" -#include "weapons.h" -#include "game.h" - -#define SF_INFOBM_RUN 0x0001 -#define SF_INFOBM_WAIT 0x0002 - -// AI Nodes for Big Momma -class CInfoBM : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData* pkvd ); - - // name in pev->targetname - // next in pev->target - // radius in pev->scale - // health in pev->health - // Reach target in pev->message - // Reach delay in pev->speed - // Reach sequence in pev->netname - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_preSequence; -}; - -LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ); - -TYPEDESCRIPTION CInfoBM::m_SaveData[] = -{ - DEFINE_FIELD( CInfoBM, m_preSequence, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CInfoBM, CPointEntity ); - -void CInfoBM::Spawn( void ) -{ -} - - -void CInfoBM::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->scale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "reachdelay")) - { - pev->speed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "reachtarget")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "reachsequence")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "presequence")) - { - m_preSequence = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -//========================================================= -// Mortar shot entity -//========================================================= -class CBMortar : public CBaseEntity -{ -public: - void Spawn( void ); - - static CBMortar *Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ); - void Touch( CBaseEntity *pOther ); - void EXPORT Animate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( bmortar, CBMortar ); - -TYPEDESCRIPTION CBMortar::m_SaveData[] = -{ - DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ); - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BIG_AE_STEP1 1 // Footstep left -#define BIG_AE_STEP2 2 // Footstep right -#define BIG_AE_STEP3 3 // Footstep back left -#define BIG_AE_STEP4 4 // Footstep back right -#define BIG_AE_SACK 5 // Sack slosh -#define BIG_AE_DEATHSOUND 6 // Death sound - -#define BIG_AE_MELEE_ATTACKBR 8 // Leg attack -#define BIG_AE_MELEE_ATTACKBL 9 // Leg attack -#define BIG_AE_MELEE_ATTACK1 10 // Leg attack -#define BIG_AE_MORTAR_ATTACK1 11 // Launch a mortar -#define BIG_AE_LAY_CRAB 12 // Lay a headcrab -#define BIG_AE_JUMP_FORWARD 13 // Jump up and forward -#define BIG_AE_SCREAM 14 // alert sound -#define BIG_AE_PAIN_SOUND 15 // pain sound -#define BIG_AE_ATTACK_SOUND 16 // attack sound -#define BIG_AE_BIRTH_SOUND 17 // birth sound -#define BIG_AE_EARLY_TARGET 50 // Fire target early - - - -// User defined conditions -#define bits_COND_NODE_SEQUENCE ( bits_COND_SPECIAL1 ) // pev->netname contains the name of a sequence to play - -// Attack distance constants -#define BIG_ATTACKDIST 170 -#define BIG_MORTARDIST 800 -#define BIG_MAXCHILDREN 20 // Max # of live headcrab children - - -#define bits_MEMORY_CHILDPAIR (bits_MEMORY_CUSTOM1) -#define bits_MEMORY_ADVANCE_NODE (bits_MEMORY_CUSTOM2) -#define bits_MEMORY_COMPLETED_NODE (bits_MEMORY_CUSTOM3) -#define bits_MEMORY_FIRED_NODE (bits_MEMORY_CUSTOM4) - -int gSpitSprite, gSpitDebrisSprite; -Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ); -void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ); - - -// UNDONE: -// -#define BIG_CHILDCLASS "monster_babycrab" - -class CBigMomma : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - void NodeStart( int iszNextNode ); - void NodeReach( void ); - BOOL ShouldGoToNode( void ); - - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void LayHeadcrab( void ); - - int GetNodeSequence( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - return pTarget->pev->netname; // netname holds node sequence - } - return 0; - } - - - int GetNodePresequence( void ) - { - CInfoBM *pTarget = (CInfoBM *)(CBaseEntity *)m_hTargetEnt; - if ( pTarget ) - { - return pTarget->m_preSequence; - } - return 0; - } - - float GetNodeDelay( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - return pTarget->pev->speed; // Speed holds node delay - } - return 0; - } - - float GetNodeRange( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - return pTarget->pev->scale; // Scale holds node delay - } - return 1e6; - } - - float GetNodeYaw( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - if ( pTarget->pev->angles.y != 0 ) - return pTarget->pev->angles.y; - } - return pev->angles.y; - } - - // Restart the crab count on each new level - void OverrideReset( void ) - { - m_crabCount = 0; - } - - void DeathNotice( entvars_t *pevChild ); - - BOOL CanLayCrab( void ) - { - if ( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) - { - // Don't spawn crabs inside each other - Vector mins = pev->origin - Vector( 32, 32, 0 ); - Vector maxs = pev->origin + Vector( 32, 32, 0 ); - - CBaseEntity *pList[2]; - int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER ); - for ( int i = 0; i < count; i++ ) - { - if ( pList[i] != this ) // Don't hurt yourself! - return FALSE; - } - return TRUE; - } - - return FALSE; - } - - void LaunchMortar( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -95, -95, 0 ); - pev->absmax = pev->origin + Vector( 95, 95, 190 ); - } - - BOOL CheckMeleeAttack1( float flDot, float flDist ); // Slash - BOOL CheckMeleeAttack2( float flDot, float flDist ); // Lay a crab - BOOL CheckRangeAttack1( float flDot, float flDist ); // Mortar launch - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pChildDieSounds[]; - static const char *pSackSounds[]; - static const char *pDeathSounds[]; - static const char *pAttackSounds[]; - static const char *pAttackHitSounds[]; - static const char *pBirthSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pFootSounds[]; - - CUSTOM_SCHEDULES; - -private: - float m_nodeTime; - float m_crabTime; - float m_mortarTime; - float m_painSoundTime; - int m_crabCount; -}; -LINK_ENTITY_TO_CLASS( monster_bigmomma, CBigMomma ); - -TYPEDESCRIPTION CBigMomma::m_SaveData[] = -{ - DEFINE_FIELD( CBigMomma, m_nodeTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_crabTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_mortarTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_painSoundTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_crabCount, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ); - -const char *CBigMomma::pChildDieSounds[] = -{ - "gonarch/gon_childdie1.wav", - "gonarch/gon_childdie2.wav", - "gonarch/gon_childdie3.wav", -}; - -const char *CBigMomma::pSackSounds[] = -{ - "gonarch/gon_sack1.wav", - "gonarch/gon_sack2.wav", - "gonarch/gon_sack3.wav", -}; - -const char *CBigMomma::pDeathSounds[] = -{ - "gonarch/gon_die1.wav", -}; - -const char *CBigMomma::pAttackSounds[] = -{ - "gonarch/gon_attack1.wav", - "gonarch/gon_attack2.wav", - "gonarch/gon_attack3.wav", -}; -const char *CBigMomma::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CBigMomma::pBirthSounds[] = -{ - "gonarch/gon_birth1.wav", - "gonarch/gon_birth2.wav", - "gonarch/gon_birth3.wav", -}; - -const char *CBigMomma::pAlertSounds[] = -{ - "gonarch/gon_alert1.wav", - "gonarch/gon_alert2.wav", - "gonarch/gon_alert3.wav", -}; - -const char *CBigMomma::pPainSounds[] = -{ - "gonarch/gon_pain2.wav", - "gonarch/gon_pain4.wav", - "gonarch/gon_pain5.wav", -}; - -const char *CBigMomma::pFootSounds[] = -{ - "gonarch/gon_step1.wav", - "gonarch/gon_step2.wav", - "gonarch/gon_step3.wav", -}; - - - -void CBigMomma :: KeyValue( KeyValueData *pkvd ) -{ -#if 0 - if (FStrEq(pkvd->szKeyName, "volume")) - { - m_volume = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else -#endif - CBaseMonster::KeyValue( pkvd ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBigMomma :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBigMomma :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 100; - break; - default: - ys = 90; - } - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BIG_AE_MELEE_ATTACKBR: - case BIG_AE_MELEE_ATTACKBL: - case BIG_AE_MELEE_ATTACK1: - { - Vector forward, right; - - UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); - - Vector center = pev->origin + forward * 128; - Vector mins = center - Vector( 64, 64, 0 ); - Vector maxs = center + Vector( 64, 64, 64 ); - - CBaseEntity *pList[8]; - int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT ); - CBaseEntity *pHurt = NULL; - - for ( int i = 0; i < count && !pHurt; i++ ) - { - if ( pList[i] != this ) - { - if ( pList[i]->pev->owner != edict() ) - pHurt = pList[i]; - } - } - - if ( pHurt ) - { - pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH ); - pHurt->pev->punchangle.x = 15; - switch( pEvent->event ) - { - case BIG_AE_MELEE_ATTACKBR: - pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) - (right * 200); - break; - - case BIG_AE_MELEE_ATTACKBL: - pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) + (right * 200); - break; - - case BIG_AE_MELEE_ATTACK1: - pHurt->pev->velocity = pHurt->pev->velocity + (forward * 220) + Vector(0,0,200); - break; - } - - pHurt->pev->flags &= ~FL_ONGROUND; - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - } - break; - - case BIG_AE_SCREAM: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); - break; - - case BIG_AE_PAIN_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); - break; - - case BIG_AE_ATTACK_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds ); - break; - - case BIG_AE_BIRTH_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds ); - break; - - case BIG_AE_SACK: - if ( RANDOM_LONG(0,100) < 30 ) - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds ); - break; - - case BIG_AE_DEATHSOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); - break; - - case BIG_AE_STEP1: // Footstep left - case BIG_AE_STEP3: // Footstep back left - EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds ); - break; - - case BIG_AE_STEP4: // Footstep back right - case BIG_AE_STEP2: // Footstep right - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds ); - break; - - case BIG_AE_MORTAR_ATTACK1: - LaunchMortar(); - break; - - case BIG_AE_LAY_CRAB: - LayHeadcrab(); - break; - - case BIG_AE_JUMP_FORWARD: - ClearBits( pev->flags, FL_ONGROUND ); - - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground - UTIL_MakeVectors ( pev->angles ); - - pev->velocity = (gpGlobals->v_forward * 200) + gpGlobals->v_up * 500; - break; - - case BIG_AE_EARLY_TARGET: - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget && pTarget->pev->message ) - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - Remember( bits_MEMORY_FIRED_NODE ); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -void CBigMomma :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if ( ptr->iHitgroup != 1 ) - { - // didn't hit the sack? - - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - else if ( gpGlobals->time > m_painSoundTime ) - { - m_painSoundTime = gpGlobals->time + RANDOM_LONG(1, 3); - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); - } - - - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -int CBigMomma :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if ( bitsDamageType & DMG_ACID ) - flDamage = 0; - - if ( !HasMemory(bits_MEMORY_PATH_FINISHED) ) - { - if ( pev->health <= flDamage ) - { - pev->health = flDamage + 1; - Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); - ALERT( at_aiconsole, "BM: Finished node health!!!\n" ); - } - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CBigMomma :: LayHeadcrab( void ) -{ - CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, edict() ); - - pChild->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; - - // Is this the second crab in a pair? - if ( HasMemory( bits_MEMORY_CHILDPAIR ) ) - { - m_crabTime = gpGlobals->time + RANDOM_FLOAT( 5, 10 ); - Forget( bits_MEMORY_CHILDPAIR ); - } - else - { - m_crabTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 2.5 ); - Remember( bits_MEMORY_CHILDPAIR ); - } - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,100), ignore_monsters, edict(), &tr); - UTIL_DecalTrace( &tr, DECAL_MOMMABIRTH ); - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBirthSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - m_crabCount++; -} - - - -void CBigMomma::DeathNotice( entvars_t *pevChild ) -{ - if ( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then - m_crabCount--; - if ( IsAlive() ) - { - // Make the "my baby's dead" noise! - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pChildDieSounds ); - } -} - - -void CBigMomma::LaunchMortar( void ) -{ - m_mortarTime = gpGlobals->time + RANDOM_FLOAT( 2, 15 ); - - Vector startPos = pev->origin; - startPos.z += 180; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pSackSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - CBMortar *pBomb = CBMortar::Shoot( edict(), startPos, pev->movedir ); - pBomb->pev->gravity = 1.0; - MortarSpray( startPos, Vector(0,0,1), gSpitSprite, 24 ); -} - -//========================================================= -// Spawn -//========================================================= -void CBigMomma :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/big_mom.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 150 * gSkillData.bigmommaHealthFactor; - pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBigMomma :: Precache() -{ - PRECACHE_MODEL("models/big_mom.mdl"); - - PRECACHE_SOUND_ARRAY( pChildDieSounds ); - PRECACHE_SOUND_ARRAY( pSackSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pAttackHitSounds ); - PRECACHE_SOUND_ARRAY( pBirthSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pFootSounds ); - - UTIL_PrecacheOther( BIG_CHILDCLASS ); - - // TEMP: Squid - PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile. - gSpitSprite = PRECACHE_MODEL("sprites/mommaspout.spr");// client side spittle. - gSpitDebrisSprite = PRECACHE_MODEL("sprites/mommablob.spr" ); - - PRECACHE_SOUND( "bullchicken/bc_acid1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" ); -} - - -void CBigMomma::Activate( void ) -{ - if ( m_hTargetEnt == NULL ) - Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up -} - - -void CBigMomma::NodeStart( int iszNextNode ) -{ - pev->netname = iszNextNode; - - CBaseEntity *pTarget = NULL; - - if ( pev->netname ) - { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->netname) ); - - if ( !FNullEnt(pentTarget) ) - pTarget = Instance( pentTarget ); - } - - - if ( !pTarget ) - { - ALERT( at_aiconsole, "BM: Finished the path!!\n" ); - Remember( bits_MEMORY_PATH_FINISHED ); - return; - } - Remember( bits_MEMORY_ON_PATH ); - m_hTargetEnt = pTarget; -} - - -void CBigMomma::NodeReach( void ) -{ - CBaseEntity *pTarget = m_hTargetEnt; - - Forget( bits_MEMORY_ADVANCE_NODE ); - - if ( !pTarget ) - return; - - if ( pTarget->pev->health ) - pev->max_health = pev->health = pTarget->pev->health * gSkillData.bigmommaHealthFactor; - - if ( !HasMemory( bits_MEMORY_FIRED_NODE ) ) - { - if ( pTarget->pev->message ) - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - } - Forget( bits_MEMORY_FIRED_NODE ); - - pev->netname = pTarget->pev->target; - if ( pTarget->pev->health == 0 ) - Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node -} - - - // Slash -BOOL CBigMomma::CheckMeleeAttack1( float flDot, float flDist ) -{ - if (flDot >= 0.7) - { - if ( flDist <= BIG_ATTACKDIST ) - return TRUE; - } - return FALSE; -} - - -// Lay a crab -BOOL CBigMomma::CheckMeleeAttack2( float flDot, float flDist ) -{ - return CanLayCrab(); -} - - -// Mortar launch -BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) -{ - if ( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->time ) - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy ) - { - Vector startPos = pev->origin; - startPos.z += 180; - pev->movedir = VecCheckSplatToss( pev, startPos, pEnemy->BodyTarget( pev->origin ), RANDOM_FLOAT( 150, 500 ) ); - if ( pev->movedir != g_vecZero ) - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -enum -{ - SCHED_BIG_NODE = LAST_COMMON_SCHEDULE + 1, - SCHED_NODE_FAIL, -}; - -enum -{ - TASK_MOVE_TO_NODE_RANGE = LAST_COMMON_TASK + 1, // Move within node range - TASK_FIND_NODE, // Find my next node - TASK_PLAY_NODE_PRESEQUENCE, // Play node pre-script - TASK_PLAY_NODE_SEQUENCE, // Play node script - TASK_PROCESS_NODE, // Fire targets, etc. - TASK_WAIT_NODE, // Wait at the node - TASK_NODE_DELAY, // Delay walking toward node for a bit. You've failed to get there - TASK_NODE_YAW, // Get the best facing direction for this node -}; - - -Task_t tlBigNode[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_NODE_FAIL }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_NODE, (float)0 }, // Find my next node - { TASK_PLAY_NODE_PRESEQUENCE,(float)0 }, // Play the pre-approach sequence if any - { TASK_MOVE_TO_NODE_RANGE, (float)0 }, // Move within node range - { TASK_STOP_MOVING, (float)0 }, - { TASK_NODE_YAW, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_NODE, (float)0 }, // Wait for node delay - { TASK_PLAY_NODE_SEQUENCE, (float)0 }, // Play the sequence if one exists - { TASK_PROCESS_NODE, (float)0 }, // Fire targets, etc. - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slBigNode[] = -{ - { - tlBigNode, - ARRAYSIZE ( tlBigNode ), - 0, - 0, - "Big Node" - }, -}; - - -Task_t tlNodeFail[] = -{ - { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slNodeFail[] = -{ - { - tlNodeFail, - ARRAYSIZE ( tlNodeFail ), - 0, - 0, - "NodeFail" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CBigMomma ) -{ - slBigNode, - slNodeFail, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBigMomma, CBaseMonster ); - - - - -Schedule_t *CBigMomma::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_BIG_NODE: - return slBigNode; - break; - - case SCHED_NODE_FAIL: - return slNodeFail; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -BOOL CBigMomma::ShouldGoToNode( void ) -{ - if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) - { - if ( m_nodeTime < gpGlobals->time ) - return TRUE; - } - return FALSE; -} - - - -Schedule_t *CBigMomma::GetSchedule( void ) -{ - if ( ShouldGoToNode() ) - { - return GetScheduleOfType( SCHED_BIG_NODE ); - } - - return CBaseMonster::GetSchedule(); -} - - -void CBigMomma::StartTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_FIND_NODE: - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) - { - if ( pTarget ) - pev->netname = m_hTargetEnt->pev->target; - } - NodeStart( pev->netname ); - TaskComplete(); - ALERT( at_aiconsole, "BM: Found node %s\n", STRING(pev->netname) ); - } - break; - - case TASK_NODE_DELAY: - m_nodeTime = gpGlobals->time + pTask->flData; - TaskComplete(); - ALERT( at_aiconsole, "BM: FAIL! Delay %.2f\n", pTask->flData ); - break; - - case TASK_PROCESS_NODE: - ALERT( at_aiconsole, "BM: Reached node %s\n", STRING(pev->netname) ); - NodeReach(); - TaskComplete(); - break; - - case TASK_PLAY_NODE_PRESEQUENCE: - case TASK_PLAY_NODE_SEQUENCE: - { - int sequence; - if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE ) - sequence = GetNodeSequence(); - else - sequence = GetNodePresequence(); - - ALERT( at_aiconsole, "BM: Playing node sequence %s\n", STRING(sequence) ); - if ( sequence ) - { - sequence = LookupSequence( STRING( sequence ) ); - if ( sequence != -1 ) - { - pev->sequence = sequence; - pev->frame = 0; - ResetSequenceInfo( ); - ALERT( at_aiconsole, "BM: Sequence %s\n", STRING(GetNodeSequence()) ); - return; - } - } - TaskComplete(); - } - break; - - case TASK_NODE_YAW: - pev->ideal_yaw = GetNodeYaw(); - TaskComplete(); - break; - - case TASK_WAIT_NODE: - m_flWait = gpGlobals->time + GetNodeDelay(); - if ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) - ALERT( at_aiconsole, "BM: Wait at node %s forever\n", STRING(pev->netname) ); - else - ALERT( at_aiconsole, "BM: Wait at node %s for %.2f\n", STRING(pev->netname), GetNodeDelay() ); - break; - - - case TASK_MOVE_TO_NODE_RANGE: - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( !pTarget ) - TaskFail(); - else - { - if ( (pTarget->pev->origin - pev->origin).Length() < GetNodeRange() ) - TaskComplete(); - else - { - Activity act = ACT_WALK; - if ( pTarget->pev->spawnflags & SF_INFOBM_RUN ) - act = ACT_RUN; - - m_vecMoveGoal = pTarget->pev->origin; - if ( !MoveToTarget( act, 2 ) ) - { - TaskFail(); - } - } - } - } - ALERT( at_aiconsole, "BM: Moving to node %s\n", STRING(pev->netname) ); - - break; - - case TASK_MELEE_ATTACK1: - // Play an attack sound here - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), 1.0, ATTN_NORM, 0, PITCH_NORM ); - CBaseMonster::StartTask( pTask ); - break; - - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CBigMomma::RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_MOVE_TO_NODE_RANGE: - { - float distance; - - if ( m_hTargetEnt == NULL ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( (distance < GetNodeRange()) || MovementIsComplete() ) - { - ALERT( at_aiconsole, "BM: Reached node!\n" ); - TaskComplete(); - RouteClear(); // Stop moving - } - } - } - - break; - - case TASK_WAIT_NODE: - if ( m_hTargetEnt != NULL && (m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT) ) - return; - - if ( gpGlobals->time > m_flWaitFinished ) - TaskComplete(); - ALERT( at_aiconsole, "BM: The WAIT is over!\n" ); - break; - - case TASK_PLAY_NODE_PRESEQUENCE: - case TASK_PLAY_NODE_SEQUENCE: - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - - - -Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ) -{ - TraceResult tr; - Vector vecMidPoint;// halfway point between Spot1 and Spot2 - Vector vecApex;// highest point - Vector vecScale; - Vector vecGrenadeVel; - Vector vecTemp; - float flGravity = g_psv_gravity->value; - - // calculate the midpoint and apex of the 'triangle' - vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector((float)0, (float)0, (float)maxHeight), ignore_monsters, ENT(pev), &tr); - vecApex = tr.vecEndPos; - - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - // Don't worry about actually hitting the target, this won't hurt us! - - // How high should the grenade travel (subtract 15 so the grenade doesn't hit the ceiling)? - float height = (vecApex.z - vecSpot1.z) - 15; - // How fast does the grenade need to travel to reach that height given gravity? - float speed = sqrt( 2 * flGravity * height ); - - // How much time does it take to get there? - float time = speed / flGravity; - vecGrenadeVel = (vecSpot2 - vecSpot1); - vecGrenadeVel.z = 0; - float distance = vecGrenadeVel.Length(); - - // Travel half the distance to the target in that time (apex is at the midpoint) - vecGrenadeVel = vecGrenadeVel * ( 0.5 / time ); - // Speed to offset gravity at the desired height - vecGrenadeVel.z = speed; - - return vecGrenadeVel; -} - - - - -// --------------------------------- -// -// Mortar -// -// --------------------------------- -void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( position.x); // pos - WRITE_COORD( position.y); - WRITE_COORD( position.z); - WRITE_COORD( direction.x); // dir - WRITE_COORD( direction.y); - WRITE_COORD( direction.z); - WRITE_SHORT( spriteModel ); // model - WRITE_BYTE ( count ); // count - WRITE_BYTE ( 130 ); // speed - WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) - MESSAGE_END(); -} - - -// UNDONE: right now this is pretty much a copy of the squid spit with minor changes to the way it does damage -void CBMortar:: Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->classname = MAKE_STRING( "bmortar" ); - - pev->solid = SOLID_BBOX; - pev->rendermode = kRenderTransAlpha; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/mommaspit.spr"); - pev->frame = 0; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - pev->dmgtime = gpGlobals->time + 0.4; -} - -void CBMortar::Animate( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( gpGlobals->time > pev->dmgtime ) - { - pev->dmgtime = gpGlobals->time + 0.2; - MortarSpray( pev->origin, -pev->velocity.Normalize(), gSpitSprite, 3 ); - } - if ( pev->frame++ ) - { - if ( pev->frame > m_maxFrame ) - { - pev->frame = 0; - } - } -} - -CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ) -{ - CBMortar *pSpit = GetClassPtr( (CBMortar *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = pOwner; - pSpit->pev->scale = 2.5; - pSpit->SetThink ( Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; - - return pSpit; -} - - -void CBMortar::Touch( CBaseEntity *pOther ) -{ - TraceResult tr; - int iPitch; - - // splat sound - iPitch = RANDOM_FLOAT( 90, 110 ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - if ( pOther->IsBSPModel() ) - { - - // make a splat on the wall - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); - UTIL_DecalTrace(&tr, DECAL_MOMMASPLAT); - } - else - { - tr.vecEndPos = pev->origin; - tr.vecPlaneNormal = -1 * pev->velocity.Normalize(); - } - // make some flecks - MortarSpray( tr.vecEndPos, tr.vecPlaneNormal, gSpitSprite, 24 ); - - entvars_t *pevOwner = NULL; - if ( pev->owner ) - pevOwner = VARS(pev->owner); - - RadiusDamage( pev->origin, pev, pevOwner, gSkillData.bigmommaDmgBlast, gSkillData.bigmommaRadiusBlast, CLASS_NONE, DMG_ACID ); - UTIL_Remove( this ); -} - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +//========================================================= +// monster template +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "decals.h" +#include "weapons.h" +#include "game.h" + +#define SF_INFOBM_RUN 0x0001 +#define SF_INFOBM_WAIT 0x0002 + +// AI Nodes for Big Momma +class CInfoBM : public CPointEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData* pkvd ); + + // name in pev->targetname + // next in pev->target + // radius in pev->scale + // health in pev->health + // Reach target in pev->message + // Reach delay in pev->speed + // Reach sequence in pev->netname + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_preSequence; +}; + +LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ); + +TYPEDESCRIPTION CInfoBM::m_SaveData[] = +{ + DEFINE_FIELD( CInfoBM, m_preSequence, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CInfoBM, CPointEntity ); + +void CInfoBM::Spawn( void ) +{ +} + + +void CInfoBM::KeyValue( KeyValueData* pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "radius")) + { + pev->scale = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "reachdelay")) + { + pev->speed = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "reachtarget")) + { + pev->message = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "reachsequence")) + { + pev->netname = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "presequence")) + { + m_preSequence = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +//========================================================= +// Mortar shot entity +//========================================================= +class CBMortar : public CBaseEntity +{ +public: + void Spawn( void ); + + static CBMortar *Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ); + void Touch( CBaseEntity *pOther ); + void EXPORT Animate( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_maxFrame; +}; + +LINK_ENTITY_TO_CLASS( bmortar, CBMortar ); + +TYPEDESCRIPTION CBMortar::m_SaveData[] = +{ + DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ); + + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define BIG_AE_STEP1 1 // Footstep left +#define BIG_AE_STEP2 2 // Footstep right +#define BIG_AE_STEP3 3 // Footstep back left +#define BIG_AE_STEP4 4 // Footstep back right +#define BIG_AE_SACK 5 // Sack slosh +#define BIG_AE_DEATHSOUND 6 // Death sound + +#define BIG_AE_MELEE_ATTACKBR 8 // Leg attack +#define BIG_AE_MELEE_ATTACKBL 9 // Leg attack +#define BIG_AE_MELEE_ATTACK1 10 // Leg attack +#define BIG_AE_MORTAR_ATTACK1 11 // Launch a mortar +#define BIG_AE_LAY_CRAB 12 // Lay a headcrab +#define BIG_AE_JUMP_FORWARD 13 // Jump up and forward +#define BIG_AE_SCREAM 14 // alert sound +#define BIG_AE_PAIN_SOUND 15 // pain sound +#define BIG_AE_ATTACK_SOUND 16 // attack sound +#define BIG_AE_BIRTH_SOUND 17 // birth sound +#define BIG_AE_EARLY_TARGET 50 // Fire target early + + + +// User defined conditions +#define bits_COND_NODE_SEQUENCE ( bits_COND_SPECIAL1 ) // pev->netname contains the name of a sequence to play + +// Attack distance constants +#define BIG_ATTACKDIST 170 +#define BIG_MORTARDIST 800 +#define BIG_MAXCHILDREN 20 // Max # of live headcrab children + + +#define bits_MEMORY_CHILDPAIR (bits_MEMORY_CUSTOM1) +#define bits_MEMORY_ADVANCE_NODE (bits_MEMORY_CUSTOM2) +#define bits_MEMORY_COMPLETED_NODE (bits_MEMORY_CUSTOM3) +#define bits_MEMORY_FIRED_NODE (bits_MEMORY_CUSTOM4) + +int gSpitSprite, gSpitDebrisSprite; +Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ); +void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ); + + +// UNDONE: +// +#define BIG_CHILDCLASS "monster_babycrab" + +class CBigMomma : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + void Activate( void ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + void RunTask( Task_t *pTask ); + void StartTask( Task_t *pTask ); + Schedule_t *GetSchedule( void ); + Schedule_t *GetScheduleOfType( int Type ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); + + void NodeStart( int iszNextNode ); + void NodeReach( void ); + BOOL ShouldGoToNode( void ); + + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void LayHeadcrab( void ); + + int GetNodeSequence( void ) + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( pTarget ) + { + return pTarget->pev->netname; // netname holds node sequence + } + return 0; + } + + + int GetNodePresequence( void ) + { + CInfoBM *pTarget = (CInfoBM *)(CBaseEntity *)m_hTargetEnt; + if ( pTarget ) + { + return pTarget->m_preSequence; + } + return 0; + } + + float GetNodeDelay( void ) + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( pTarget ) + { + return pTarget->pev->speed; // Speed holds node delay + } + return 0; + } + + float GetNodeRange( void ) + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( pTarget ) + { + return pTarget->pev->scale; // Scale holds node delay + } + return 1e6; + } + + float GetNodeYaw( void ) + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( pTarget ) + { + if ( pTarget->pev->angles.y != 0 ) + return pTarget->pev->angles.y; + } + return pev->angles.y; + } + + // Restart the crab count on each new level + void OverrideReset( void ) + { + m_crabCount = 0; + } + + void DeathNotice( entvars_t *pevChild ); + + BOOL CanLayCrab( void ) + { + if ( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) + { + // Don't spawn crabs inside each other + Vector mins = pev->origin - Vector( 32, 32, 0 ); + Vector maxs = pev->origin + Vector( 32, 32, 0 ); + + CBaseEntity *pList[2]; + int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER ); + for ( int i = 0; i < count; i++ ) + { + if ( pList[i] != this ) // Don't hurt yourself! + return FALSE; + } + return TRUE; + } + + return FALSE; + } + + void LaunchMortar( void ); + + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -95, -95, 0 ); + pev->absmax = pev->origin + Vector( 95, 95, 190 ); + } + + BOOL CheckMeleeAttack1( float flDot, float flDist ); // Slash + BOOL CheckMeleeAttack2( float flDot, float flDist ); // Lay a crab + BOOL CheckRangeAttack1( float flDot, float flDist ); // Mortar launch + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + static const char *pChildDieSounds[]; + static const char *pSackSounds[]; + static const char *pDeathSounds[]; + static const char *pAttackSounds[]; + static const char *pAttackHitSounds[]; + static const char *pBirthSounds[]; + static const char *pAlertSounds[]; + static const char *pPainSounds[]; + static const char *pFootSounds[]; + + CUSTOM_SCHEDULES; + +private: + float m_nodeTime; + float m_crabTime; + float m_mortarTime; + float m_painSoundTime; + int m_crabCount; +}; +LINK_ENTITY_TO_CLASS( monster_bigmomma, CBigMomma ); + +TYPEDESCRIPTION CBigMomma::m_SaveData[] = +{ + DEFINE_FIELD( CBigMomma, m_nodeTime, FIELD_TIME ), + DEFINE_FIELD( CBigMomma, m_crabTime, FIELD_TIME ), + DEFINE_FIELD( CBigMomma, m_mortarTime, FIELD_TIME ), + DEFINE_FIELD( CBigMomma, m_painSoundTime, FIELD_TIME ), + DEFINE_FIELD( CBigMomma, m_crabCount, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ); + +const char *CBigMomma::pChildDieSounds[] = +{ + "gonarch/gon_childdie1.wav", + "gonarch/gon_childdie2.wav", + "gonarch/gon_childdie3.wav", +}; + +const char *CBigMomma::pSackSounds[] = +{ + "gonarch/gon_sack1.wav", + "gonarch/gon_sack2.wav", + "gonarch/gon_sack3.wav", +}; + +const char *CBigMomma::pDeathSounds[] = +{ + "gonarch/gon_die1.wav", +}; + +const char *CBigMomma::pAttackSounds[] = +{ + "gonarch/gon_attack1.wav", + "gonarch/gon_attack2.wav", + "gonarch/gon_attack3.wav", +}; +const char *CBigMomma::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CBigMomma::pBirthSounds[] = +{ + "gonarch/gon_birth1.wav", + "gonarch/gon_birth2.wav", + "gonarch/gon_birth3.wav", +}; + +const char *CBigMomma::pAlertSounds[] = +{ + "gonarch/gon_alert1.wav", + "gonarch/gon_alert2.wav", + "gonarch/gon_alert3.wav", +}; + +const char *CBigMomma::pPainSounds[] = +{ + "gonarch/gon_pain2.wav", + "gonarch/gon_pain4.wav", + "gonarch/gon_pain5.wav", +}; + +const char *CBigMomma::pFootSounds[] = +{ + "gonarch/gon_step1.wav", + "gonarch/gon_step2.wav", + "gonarch/gon_step3.wav", +}; + + + +void CBigMomma :: KeyValue( KeyValueData *pkvd ) +{ +#if 0 + if (FStrEq(pkvd->szKeyName, "volume")) + { + m_volume = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else +#endif + CBaseMonster::KeyValue( pkvd ); +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CBigMomma :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CBigMomma :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + ys = 100; + break; + default: + ys = 90; + } + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case BIG_AE_MELEE_ATTACKBR: + case BIG_AE_MELEE_ATTACKBL: + case BIG_AE_MELEE_ATTACK1: + { + Vector forward, right; + + UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); + + Vector center = pev->origin + forward * 128; + Vector mins = center - Vector( 64, 64, 0 ); + Vector maxs = center + Vector( 64, 64, 64 ); + + CBaseEntity *pList[8]; + int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT ); + CBaseEntity *pHurt = NULL; + + for ( int i = 0; i < count && !pHurt; i++ ) + { + if ( pList[i] != this ) + { + if ( pList[i]->pev->owner != edict() ) + pHurt = pList[i]; + } + } + + if ( pHurt ) + { + pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH ); + pHurt->pev->punchangle.x = 15; + switch( pEvent->event ) + { + case BIG_AE_MELEE_ATTACKBR: + pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) - (right * 200); + break; + + case BIG_AE_MELEE_ATTACKBL: + pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) + (right * 200); + break; + + case BIG_AE_MELEE_ATTACK1: + pHurt->pev->velocity = pHurt->pev->velocity + (forward * 220) + Vector(0,0,200); + break; + } + + pHurt->pev->flags &= ~FL_ONGROUND; + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + } + break; + + case BIG_AE_SCREAM: + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); + break; + + case BIG_AE_PAIN_SOUND: + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); + break; + + case BIG_AE_ATTACK_SOUND: + EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds ); + break; + + case BIG_AE_BIRTH_SOUND: + EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds ); + break; + + case BIG_AE_SACK: + if ( RANDOM_LONG(0,100) < 30 ) + EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds ); + break; + + case BIG_AE_DEATHSOUND: + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); + break; + + case BIG_AE_STEP1: // Footstep left + case BIG_AE_STEP3: // Footstep back left + EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds ); + break; + + case BIG_AE_STEP4: // Footstep back right + case BIG_AE_STEP2: // Footstep right + EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds ); + break; + + case BIG_AE_MORTAR_ATTACK1: + LaunchMortar(); + break; + + case BIG_AE_LAY_CRAB: + LayHeadcrab(); + break; + + case BIG_AE_JUMP_FORWARD: + ClearBits( pev->flags, FL_ONGROUND ); + + UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground + UTIL_MakeVectors ( pev->angles ); + + pev->velocity = (gpGlobals->v_forward * 200) + gpGlobals->v_up * 500; + break; + + case BIG_AE_EARLY_TARGET: + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( pTarget && pTarget->pev->message ) + FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); + Remember( bits_MEMORY_FIRED_NODE ); + } + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +void CBigMomma :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) +{ + if ( ptr->iHitgroup != 1 ) + { + // didn't hit the sack? + + if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + { + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); + pev->dmgtime = gpGlobals->time; + } + + flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated + } + else if ( gpGlobals->time > m_painSoundTime ) + { + m_painSoundTime = gpGlobals->time + RANDOM_LONG(1, 3); + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); + } + + + CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); +} + + +int CBigMomma :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + // Don't take any acid damage -- BigMomma's mortar is acid + if ( bitsDamageType & DMG_ACID ) + flDamage = 0; + + if ( !HasMemory(bits_MEMORY_PATH_FINISHED) ) + { + if ( pev->health <= flDamage ) + { + pev->health = flDamage + 1; + Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); + ALERT( at_aiconsole, "BM: Finished node health!!!\n" ); + } + } + + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +void CBigMomma :: LayHeadcrab( void ) +{ + CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, edict() ); + + pChild->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; + + // Is this the second crab in a pair? + if ( HasMemory( bits_MEMORY_CHILDPAIR ) ) + { + m_crabTime = gpGlobals->time + RANDOM_FLOAT( 5, 10 ); + Forget( bits_MEMORY_CHILDPAIR ); + } + else + { + m_crabTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 2.5 ); + Remember( bits_MEMORY_CHILDPAIR ); + } + + TraceResult tr; + UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,100), ignore_monsters, edict(), &tr); + UTIL_DecalTrace( &tr, DECAL_MOMMABIRTH ); + + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBirthSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + m_crabCount++; +} + + + +void CBigMomma::DeathNotice( entvars_t *pevChild ) +{ + if ( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then + m_crabCount--; + if ( IsAlive() ) + { + // Make the "my baby's dead" noise! + EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pChildDieSounds ); + } +} + + +void CBigMomma::LaunchMortar( void ) +{ + m_mortarTime = gpGlobals->time + RANDOM_FLOAT( 2, 15 ); + + Vector startPos = pev->origin; + startPos.z += 180; + + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pSackSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + CBMortar *pBomb = CBMortar::Shoot( edict(), startPos, pev->movedir ); + pBomb->pev->gravity = 1.0; + MortarSpray( startPos, Vector(0,0,1), gSpitSprite, 24 ); +} + +//========================================================= +// Spawn +//========================================================= +void CBigMomma :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/big_mom.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = 150 * gSkillData.bigmommaHealthFactor; + pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin. + m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CBigMomma :: Precache() +{ + PRECACHE_MODEL("models/big_mom.mdl"); + + PRECACHE_SOUND_ARRAY( pChildDieSounds ); + PRECACHE_SOUND_ARRAY( pSackSounds ); + PRECACHE_SOUND_ARRAY( pDeathSounds ); + PRECACHE_SOUND_ARRAY( pAttackSounds ); + PRECACHE_SOUND_ARRAY( pAttackHitSounds ); + PRECACHE_SOUND_ARRAY( pBirthSounds ); + PRECACHE_SOUND_ARRAY( pAlertSounds ); + PRECACHE_SOUND_ARRAY( pPainSounds ); + PRECACHE_SOUND_ARRAY( pFootSounds ); + + UTIL_PrecacheOther( BIG_CHILDCLASS ); + + // TEMP: Squid + PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile. + gSpitSprite = PRECACHE_MODEL("sprites/mommaspout.spr");// client side spittle. + gSpitDebrisSprite = PRECACHE_MODEL("sprites/mommablob.spr" ); + + PRECACHE_SOUND( "bullchicken/bc_acid1.wav" ); + PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" ); + PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" ); +} + + +void CBigMomma::Activate( void ) +{ + if ( m_hTargetEnt == NULL ) + Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up +} + + +void CBigMomma::NodeStart( int iszNextNode ) +{ + pev->netname = iszNextNode; + + CBaseEntity *pTarget = NULL; + + if ( pev->netname ) + { + edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->netname) ); + + if ( !FNullEnt(pentTarget) ) + pTarget = Instance( pentTarget ); + } + + + if ( !pTarget ) + { + ALERT( at_aiconsole, "BM: Finished the path!!\n" ); + Remember( bits_MEMORY_PATH_FINISHED ); + return; + } + Remember( bits_MEMORY_ON_PATH ); + m_hTargetEnt = pTarget; +} + + +void CBigMomma::NodeReach( void ) +{ + CBaseEntity *pTarget = m_hTargetEnt; + + Forget( bits_MEMORY_ADVANCE_NODE ); + + if ( !pTarget ) + return; + + if ( pTarget->pev->health ) + pev->max_health = pev->health = pTarget->pev->health * gSkillData.bigmommaHealthFactor; + + if ( !HasMemory( bits_MEMORY_FIRED_NODE ) ) + { + if ( pTarget->pev->message ) + FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); + } + Forget( bits_MEMORY_FIRED_NODE ); + + pev->netname = pTarget->pev->target; + if ( pTarget->pev->health == 0 ) + Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node +} + + + // Slash +BOOL CBigMomma::CheckMeleeAttack1( float flDot, float flDist ) +{ + if (flDot >= 0.7) + { + if ( flDist <= BIG_ATTACKDIST ) + return TRUE; + } + return FALSE; +} + + +// Lay a crab +BOOL CBigMomma::CheckMeleeAttack2( float flDot, float flDist ) +{ + return CanLayCrab(); +} + + +// Mortar launch +BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) +{ + if ( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->time ) + { + CBaseEntity *pEnemy = m_hEnemy; + + if ( pEnemy ) + { + Vector startPos = pev->origin; + startPos.z += 180; + pev->movedir = VecCheckSplatToss( pev, startPos, pEnemy->BodyTarget( pev->origin ), RANDOM_FLOAT( 150, 500 ) ); + if ( pev->movedir != g_vecZero ) + return TRUE; + } + } + return FALSE; +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +enum +{ + SCHED_BIG_NODE = LAST_COMMON_SCHEDULE + 1, + SCHED_NODE_FAIL, +}; + +enum +{ + TASK_MOVE_TO_NODE_RANGE = LAST_COMMON_TASK + 1, // Move within node range + TASK_FIND_NODE, // Find my next node + TASK_PLAY_NODE_PRESEQUENCE, // Play node pre-script + TASK_PLAY_NODE_SEQUENCE, // Play node script + TASK_PROCESS_NODE, // Fire targets, etc. + TASK_WAIT_NODE, // Wait at the node + TASK_NODE_DELAY, // Delay walking toward node for a bit. You've failed to get there + TASK_NODE_YAW, // Get the best facing direction for this node +}; + + +Task_t tlBigNode[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_NODE_FAIL }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_NODE, (float)0 }, // Find my next node + { TASK_PLAY_NODE_PRESEQUENCE,(float)0 }, // Play the pre-approach sequence if any + { TASK_MOVE_TO_NODE_RANGE, (float)0 }, // Move within node range + { TASK_STOP_MOVING, (float)0 }, + { TASK_NODE_YAW, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_WAIT_NODE, (float)0 }, // Wait for node delay + { TASK_PLAY_NODE_SEQUENCE, (float)0 }, // Play the sequence if one exists + { TASK_PROCESS_NODE, (float)0 }, // Fire targets, etc. + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, +}; + +Schedule_t slBigNode[] = +{ + { + tlBigNode, + ARRAYSIZE ( tlBigNode ), + 0, + 0, + "Big Node" + }, +}; + + +Task_t tlNodeFail[] = +{ + { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, +}; + +Schedule_t slNodeFail[] = +{ + { + tlNodeFail, + ARRAYSIZE ( tlNodeFail ), + 0, + 0, + "NodeFail" + }, +}; + +DEFINE_CUSTOM_SCHEDULES( CBigMomma ) +{ + slBigNode, + slNodeFail, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CBigMomma, CBaseMonster ); + + + + +Schedule_t *CBigMomma::GetScheduleOfType( int Type ) +{ + switch( Type ) + { + case SCHED_BIG_NODE: + return slBigNode; + break; + + case SCHED_NODE_FAIL: + return slNodeFail; + break; + } + + return CBaseMonster::GetScheduleOfType( Type ); +} + + +BOOL CBigMomma::ShouldGoToNode( void ) +{ + if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) + { + if ( m_nodeTime < gpGlobals->time ) + return TRUE; + } + return FALSE; +} + + + +Schedule_t *CBigMomma::GetSchedule( void ) +{ + if ( ShouldGoToNode() ) + { + return GetScheduleOfType( SCHED_BIG_NODE ); + } + + return CBaseMonster::GetSchedule(); +} + + +void CBigMomma::StartTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_FIND_NODE: + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) + { + if ( pTarget ) + pev->netname = m_hTargetEnt->pev->target; + } + NodeStart( pev->netname ); + TaskComplete(); + ALERT( at_aiconsole, "BM: Found node %s\n", STRING(pev->netname) ); + } + break; + + case TASK_NODE_DELAY: + m_nodeTime = gpGlobals->time + pTask->flData; + TaskComplete(); + ALERT( at_aiconsole, "BM: FAIL! Delay %.2f\n", pTask->flData ); + break; + + case TASK_PROCESS_NODE: + ALERT( at_aiconsole, "BM: Reached node %s\n", STRING(pev->netname) ); + NodeReach(); + TaskComplete(); + break; + + case TASK_PLAY_NODE_PRESEQUENCE: + case TASK_PLAY_NODE_SEQUENCE: + { + int sequence; + if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE ) + sequence = GetNodeSequence(); + else + sequence = GetNodePresequence(); + + ALERT( at_aiconsole, "BM: Playing node sequence %s\n", STRING(sequence) ); + if ( sequence ) + { + sequence = LookupSequence( STRING( sequence ) ); + if ( sequence != -1 ) + { + pev->sequence = sequence; + pev->frame = 0; + ResetSequenceInfo( ); + ALERT( at_aiconsole, "BM: Sequence %s\n", STRING(GetNodeSequence()) ); + return; + } + } + TaskComplete(); + } + break; + + case TASK_NODE_YAW: + pev->ideal_yaw = GetNodeYaw(); + TaskComplete(); + break; + + case TASK_WAIT_NODE: + m_flWait = gpGlobals->time + GetNodeDelay(); + if ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) + ALERT( at_aiconsole, "BM: Wait at node %s forever\n", STRING(pev->netname) ); + else + ALERT( at_aiconsole, "BM: Wait at node %s for %.2f\n", STRING(pev->netname), GetNodeDelay() ); + break; + + + case TASK_MOVE_TO_NODE_RANGE: + { + CBaseEntity *pTarget = m_hTargetEnt; + if ( !pTarget ) + TaskFail(); + else + { + if ( (pTarget->pev->origin - pev->origin).Length() < GetNodeRange() ) + TaskComplete(); + else + { + Activity act = ACT_WALK; + if ( pTarget->pev->spawnflags & SF_INFOBM_RUN ) + act = ACT_RUN; + + m_vecMoveGoal = pTarget->pev->origin; + if ( !MoveToTarget( act, 2 ) ) + { + TaskFail(); + } + } + } + } + ALERT( at_aiconsole, "BM: Moving to node %s\n", STRING(pev->netname) ); + + break; + + case TASK_MELEE_ATTACK1: + // Play an attack sound here + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), 1.0, ATTN_NORM, 0, PITCH_NORM ); + CBaseMonster::StartTask( pTask ); + break; + + default: + CBaseMonster::StartTask( pTask ); + break; + } +} + +//========================================================= +// RunTask +//========================================================= +void CBigMomma::RunTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_MOVE_TO_NODE_RANGE: + { + float distance; + + if ( m_hTargetEnt == NULL ) + TaskFail(); + else + { + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + // Set the appropriate activity based on an overlapping range + // overlap the range to prevent oscillation + if ( (distance < GetNodeRange()) || MovementIsComplete() ) + { + ALERT( at_aiconsole, "BM: Reached node!\n" ); + TaskComplete(); + RouteClear(); // Stop moving + } + } + } + + break; + + case TASK_WAIT_NODE: + if ( m_hTargetEnt != NULL && (m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT) ) + return; + + if ( gpGlobals->time > m_flWaitFinished ) + TaskComplete(); + ALERT( at_aiconsole, "BM: The WAIT is over!\n" ); + break; + + case TASK_PLAY_NODE_PRESEQUENCE: + case TASK_PLAY_NODE_SEQUENCE: + if ( m_fSequenceFinished ) + { + m_Activity = ACT_RESET; + TaskComplete(); + } + break; + + default: + CBaseMonster::RunTask( pTask ); + break; + } +} + + + +Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ) +{ + TraceResult tr; + Vector vecMidPoint;// halfway point between Spot1 and Spot2 + Vector vecApex;// highest point + Vector vecScale; + Vector vecGrenadeVel; + Vector vecTemp; + float flGravity = g_psv_gravity->value; + + // calculate the midpoint and apex of the 'triangle' + vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; + UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector((float)0, (float)0, (float)maxHeight), ignore_monsters, ENT(pev), &tr); + vecApex = tr.vecEndPos; + + UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + // fail! + return g_vecZero; + } + + // Don't worry about actually hitting the target, this won't hurt us! + + // How high should the grenade travel (subtract 15 so the grenade doesn't hit the ceiling)? + float height = (vecApex.z - vecSpot1.z) - 15; + // How fast does the grenade need to travel to reach that height given gravity? + float speed = sqrt( 2 * flGravity * height ); + + // How much time does it take to get there? + float time = speed / flGravity; + vecGrenadeVel = (vecSpot2 - vecSpot1); + vecGrenadeVel.z = 0; + float distance = vecGrenadeVel.Length(); + + // Travel half the distance to the target in that time (apex is at the midpoint) + vecGrenadeVel = vecGrenadeVel * ( 0.5 / time ); + // Speed to offset gravity at the desired height + vecGrenadeVel.z = speed; + + return vecGrenadeVel; +} + + + + +// --------------------------------- +// +// Mortar +// +// --------------------------------- +void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ) +{ + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); + WRITE_BYTE( TE_SPRITE_SPRAY ); + WRITE_COORD( position.x); // pos + WRITE_COORD( position.y); + WRITE_COORD( position.z); + WRITE_COORD( direction.x); // dir + WRITE_COORD( direction.y); + WRITE_COORD( direction.z); + WRITE_SHORT( spriteModel ); // model + WRITE_BYTE ( count ); // count + WRITE_BYTE ( 130 ); // speed + WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) + MESSAGE_END(); +} + + +// UNDONE: right now this is pretty much a copy of the squid spit with minor changes to the way it does damage +void CBMortar:: Spawn( void ) +{ + pev->movetype = MOVETYPE_TOSS; + pev->classname = MAKE_STRING( "bmortar" ); + + pev->solid = SOLID_BBOX; + pev->rendermode = kRenderTransAlpha; + pev->renderamt = 255; + + SET_MODEL(ENT(pev), "sprites/mommaspit.spr"); + pev->frame = 0; + pev->scale = 0.5; + + UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); + + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + pev->dmgtime = gpGlobals->time + 0.4; +} + +void CBMortar::Animate( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if ( gpGlobals->time > pev->dmgtime ) + { + pev->dmgtime = gpGlobals->time + 0.2; + MortarSpray( pev->origin, -pev->velocity.Normalize(), gSpitSprite, 3 ); + } + if ( pev->frame++ ) + { + if ( pev->frame > m_maxFrame ) + { + pev->frame = 0; + } + } +} + +CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ) +{ + CBMortar *pSpit = GetClassPtr( (CBMortar *)NULL ); + pSpit->Spawn(); + + UTIL_SetOrigin( pSpit->pev, vecStart ); + pSpit->pev->velocity = vecVelocity; + pSpit->pev->owner = pOwner; + pSpit->pev->scale = 2.5; + pSpit->SetThink ( Animate ); + pSpit->pev->nextthink = gpGlobals->time + 0.1; + + return pSpit; +} + + +void CBMortar::Touch( CBaseEntity *pOther ) +{ + TraceResult tr; + int iPitch; + + // splat sound + iPitch = RANDOM_FLOAT( 90, 110 ); + + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); + + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 1: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); + break; + } + + if ( pOther->IsBSPModel() ) + { + + // make a splat on the wall + UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); + UTIL_DecalTrace(&tr, DECAL_MOMMASPLAT); + } + else + { + tr.vecEndPos = pev->origin; + tr.vecPlaneNormal = -1 * pev->velocity.Normalize(); + } + // make some flecks + MortarSpray( tr.vecEndPos, tr.vecPlaneNormal, gSpitSprite, 24 ); + + entvars_t *pevOwner = NULL; + if ( pev->owner ) + pevOwner = VARS(pev->owner); + + RadiusDamage( pev->origin, pev, pevOwner, gSkillData.bigmommaDmgBlast, gSkillData.bigmommaRadiusBlast, CLASS_NONE, DMG_ACID ); + UTIL_Remove( this ); +} + +#endif diff --git a/main/source/dlls/bloater.cpp b/main/source/dlls/bloater.cpp index f5bc67e1..5d91c345 100644 --- a/main/source/dlls/bloater.cpp +++ b/main/source/dlls/bloater.cpp @@ -1,219 +1,219 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Bloater -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BLOATER_AE_ATTACK_MELEE1 0x01 - - -class CBloater : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSnd( void ); - - // No range attacks - BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); -}; - -LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBloater :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBloater :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - -#if 0 - switch ( m_Activity ) - { - } -#endif - - pev->yaw_speed = ys; -} - -int CBloater :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CBloater :: PainSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,5)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain1.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain2.wav", 1.0, ATTN_NORM, 0, pitch); - break; - default: - break; - } -#endif -} - -void CBloater :: AlertSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,2)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert10.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert20.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 2: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert30.wav", 1.0, ATTN_NORM, 0, pitch); - break; - } -#endif -} - -void CBloater :: IdleSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,2)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle1.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle2.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 2: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle3.wav", 1.0, ATTN_NORM, 0, pitch); - break; - } -#endif -} - -void CBloater :: AttackSnd( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack1.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack2.wav", 1.0, ATTN_NORM, 0, pitch); - break; - } -#endif -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BLOATER_AE_ATTACK_MELEE1: - { - // do stuff for this event. - AttackSnd(); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBloater :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/floater.mdl"); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->spawnflags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 40; - pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBloater :: Precache() -{ - PRECACHE_MODEL("models/floater.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Bloater +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define BLOATER_AE_ATTACK_MELEE1 0x01 + + +class CBloater : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + + void PainSound( void ); + void AlertSound( void ); + void IdleSound( void ); + void AttackSnd( void ); + + // No range attacks + BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } + BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); +}; + +LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CBloater :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CBloater :: SetYawSpeed ( void ) +{ + int ys; + + ys = 120; + +#if 0 + switch ( m_Activity ) + { + } +#endif + + pev->yaw_speed = ys; +} + +int CBloater :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + PainSound(); + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +void CBloater :: PainSound( void ) +{ +#if 0 + int pitch = 95 + RANDOM_LONG(0,9); + + switch (RANDOM_LONG(0,5)) + { + case 0: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain1.wav", 1.0, ATTN_NORM, 0, pitch); + break; + case 1: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain2.wav", 1.0, ATTN_NORM, 0, pitch); + break; + default: + break; + } +#endif +} + +void CBloater :: AlertSound( void ) +{ +#if 0 + int pitch = 95 + RANDOM_LONG(0,9); + + switch (RANDOM_LONG(0,2)) + { + case 0: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert10.wav", 1.0, ATTN_NORM, 0, pitch); + break; + case 1: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert20.wav", 1.0, ATTN_NORM, 0, pitch); + break; + case 2: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert30.wav", 1.0, ATTN_NORM, 0, pitch); + break; + } +#endif +} + +void CBloater :: IdleSound( void ) +{ +#if 0 + int pitch = 95 + RANDOM_LONG(0,9); + + switch (RANDOM_LONG(0,2)) + { + case 0: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle1.wav", 1.0, ATTN_NORM, 0, pitch); + break; + case 1: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle2.wav", 1.0, ATTN_NORM, 0, pitch); + break; + case 2: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle3.wav", 1.0, ATTN_NORM, 0, pitch); + break; + } +#endif +} + +void CBloater :: AttackSnd( void ) +{ +#if 0 + int pitch = 95 + RANDOM_LONG(0,9); + + switch (RANDOM_LONG(0,1)) + { + case 0: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack1.wav", 1.0, ATTN_NORM, 0, pitch); + break; + case 1: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack2.wav", 1.0, ATTN_NORM, 0, pitch); + break; + } +#endif +} + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case BLOATER_AE_ATTACK_MELEE1: + { + // do stuff for this event. + AttackSnd(); + } + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CBloater :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/floater.mdl"); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_FLY; + pev->spawnflags |= FL_FLY; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = 40; + pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CBloater :: Precache() +{ + PRECACHE_MODEL("models/floater.mdl"); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + diff --git a/main/source/dlls/bmodels.cpp b/main/source/dlls/bmodels.cpp index 62c3c36b..cbba1259 100644 --- a/main/source/dlls/bmodels.cpp +++ b/main/source/dlls/bmodels.cpp @@ -1,950 +1,950 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== bmodels.cpp ======================================================== - - spawn, think, and use functions for entities that use brush models - -*/ -#include -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" -#include "../mod/AvHSpecials.h" -#include "../mod/AvHServerVariables.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -#define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled -#define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed -#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid. - -// covering cheesy noise1, noise2, & noise3 fields so they make more sense (for rotating fans) -#define noiseStart noise1 -#define noiseStop noise2 -#define noiseRunning noise3 - -#define SF_PENDULUM_SWING 2 // spawnflag that makes a pendulum a rope swing. -// -// BModelOrigin - calculates origin of a bmodel from absmin/size because all bmodel origins are 0 0 0 -// -Vector VecBModelOrigin( entvars_t* pevBModel ) -{ - return pevBModel->absmin + ( pevBModel->size * 0.5 ); -} - -// =================== FUNC_WALL ============================================== - -#include "cfuncwall.h" - -LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); - -void CFuncWall :: Spawn( void ) -{ - pev->angles = g_vecZero; - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - // If it can't move/go away, it's really part of the world - pev->flags |= FL_WORLDBRUSH; -} - - -void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( ShouldToggle( useType, (int)(pev->frame)) ) - pev->frame = 1 - pev->frame; -} - - -#define SF_WALL_START_OFF 0x0001 - -class CFuncWallToggle : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void TurnOff( void ); - void TurnOn( void ); - BOOL IsOn( void ); -}; - -LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ); - -void CFuncWallToggle :: Spawn( void ) -{ - CFuncWall::Spawn(); - if ( pev->spawnflags & SF_WALL_START_OFF ) - TurnOff(); -} - - -void CFuncWallToggle :: TurnOff( void ) -{ - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - UTIL_SetOrigin( pev, pev->origin ); -} - - -void CFuncWallToggle :: TurnOn( void ) -{ - pev->solid = SOLID_BSP; - pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( pev, pev->origin ); -} - - -BOOL CFuncWallToggle :: IsOn( void ) -{ - if ( pev->solid == SOLID_NOT ) - return FALSE; - return TRUE; -} - - -void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int status = IsOn(); - - if ( ShouldToggle( useType, status ) ) - { - if ( status ) - TurnOff(); - else - TurnOn(); - } -} - - -#define SF_CONVEYOR_VISUAL 0x0001 -#define SF_CONVEYOR_NOTSOLID 0x0002 - -class CFuncConveyor : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void UpdateSpeed( float speed ); -}; - -LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); -void CFuncConveyor :: Spawn( void ) -{ - SetMovedir( pev ); - CFuncWall::Spawn(); - - if ( !(pev->spawnflags & SF_CONVEYOR_VISUAL) ) - SetBits( pev->flags, FL_CONVEYOR ); - - // HACKHACK - This is to allow for some special effects - if ( pev->spawnflags & SF_CONVEYOR_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->skin = 0; // Don't want the engine thinking we've got special contents on this brush - } - - if ( pev->speed == 0 ) - pev->speed = 100; - - UpdateSpeed( pev->speed ); -} - - -// HACKHACK -- This is ugly, but encode the speed in the rendercolor to avoid adding more data to the network stream -void CFuncConveyor :: UpdateSpeed( float speed ) -{ - // Encode it as an integer with 4 fractional bits - int speedCode = (int)(fabs(speed) * 16.0); - - if ( speed < 0 ) - pev->rendercolor.x = 1; - else - pev->rendercolor.x = 0; - - pev->rendercolor.y = (speedCode >> 8); - pev->rendercolor.z = (speedCode & 0xFF); -} - - -void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->speed = -pev->speed; - UpdateSpeed( pev->speed ); -} - - - -// =================== FUNC_ILLUSIONARY ============================================== - - -/*QUAKED func_illusionary (0 .5 .8) ? -A simple entity that looks solid but lets you walk through it. -*/ -class CFuncIllusionary : public CBaseToggle -{ -public: - void Spawn( void ); - void EXPORT SloshTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ); - -void CFuncIllusionary :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type - { - pev->skin = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CFuncIllusionary :: Spawn( void ) -{ - pev->angles = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT;// always solid_not - SET_MODEL( ENT(pev), STRING(pev->model) ); - pev->iuser3 = AVH_USER3_FUNC_ILLUSIONARY; - - // I'd rather eat the network bandwidth of this than figure out how to save/restore - // these entities after they have been moved to the client, or respawn them ala Quake - // Perhaps we can do this in deathmatch only. - // MAKE_STATIC(ENT(pev)); -} - - -// ------------------------------------------------------------------------------- -// -// Monster only clip brush -// -// This brush will be solid for any entity who has the FL_MONSTERCLIP flag set -// in pev->flags -// -// otherwise it will be invisible and not solid. This can be used to keep -// specific monsters out of certain areas -// -// ------------------------------------------------------------------------------- -class CFuncMonsterClip : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) {} // Clear out func_wall's use function -}; - -LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip ); - -void CFuncMonsterClip::Spawn( void ) -{ - CFuncWall::Spawn(); - if ( ns_cvar_float(showtriggers) == 0 ) - pev->effects = EF_NODRAW; - pev->flags |= FL_MONSTERCLIP; -} - - -// =================== FUNC_ROTATING ============================================== -class CFuncRotating : public CBaseEntity -{ -public: - // basic functions - void Spawn( void ); - void Precache( void ); - void EXPORT SpinUp ( void ); - void EXPORT SpinDown ( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT HurtTouch ( CBaseEntity *pOther ); - void EXPORT RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Rotate( void ); - void RampPitchVol (int fUp ); - void Blocked( CBaseEntity *pOther ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flFanFriction; - float m_flAttenuation; - float m_flVolume; - float m_pitch; - int m_sounds; -}; - -TYPEDESCRIPTION CFuncRotating::m_SaveData[] = -{ - DEFINE_FIELD( CFuncRotating, m_flFanFriction, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_pitch, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_sounds, FIELD_INTEGER ) -}; - -IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ); - - -LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); - -void CFuncRotating :: KeyValue( KeyValueData* pkvd) -{ - if (FStrEq(pkvd->szKeyName, "fanfriction")) - { - m_flFanFriction = atof(pkvd->szValue)/100; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Volume")) - { - m_flVolume = atof(pkvd->szValue)/10.0; - - if (m_flVolume > 1.0) - m_flVolume = 1.0; - if (m_flVolume < 0.0) - m_flVolume = 0.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spawnorigin")) - { - Vector tmp; - UTIL_StringToVector( (float *)tmp, pkvd->szValue ); - if ( tmp != g_vecZero ) - pev->origin = tmp; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS -You need to have an origin brush as part of this entity. The -center of that brush will be -the point around which it is rotated. It will rotate around the Z -axis by default. You can -check either the X_AXIS or Y_AXIS box to change that. - -"speed" determines how fast it moves; default value is 100. -"dmg" damage to inflict when blocked (2 default) - -REVERSE will cause the it to rotate in the opposite direction. -*/ - - -void CFuncRotating :: Spawn( ) -{ - // set final pitch. Must not be PITCH_NORM, since we - // plan on pitch shifting later. - - m_pitch = PITCH_NORM - 1; - - // maintain compatibility with previous maps - if (m_flVolume == 0.0) - m_flVolume = 1.0; - - // if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_NORM; - - if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - - // prevent divide by zero if level designer forgets friction! - if ( m_flFanFriction == 0 ) - { - m_flFanFriction = 1; - } - - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS) ) - pev->movedir = Vector(0,0,1); - else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS) ) - pev->movedir = Vector(1,0,0); - else - pev->movedir = Vector(0,1,0); // y-axis - - // check for reverse rotation - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - // some rotating objects like fake volumetric lights will not be solid. - if ( FBitSet(pev->spawnflags, SF_ROTATING_NOT_SOLID) ) - { - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_EMPTY; - pev->movetype = MOVETYPE_PUSH; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - SetUse( &CFuncRotating::RotatingUse ); - // did level designer forget to assign speed? - if (pev->speed <= 0) - pev->speed = 0; - - // Removed this per level designers request. -- JAY - // if (pev->dmg == 0) - // pev->dmg = 2; - - // instant-use brush? - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { - SetThink( &CFuncRotating::SUB_CallUseToggle ); - pev->nextthink = pev->ltime + 1.5; // leave a magic delay for client to start up - } - // can this brush inflict pain? - if ( FBitSet (pev->spawnflags, SF_BRUSH_HURT) ) - { - SetTouch( &CFuncRotating::HurtTouch ); - } - - Precache( ); -} - - -void CFuncRotating :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - // set up fan sounds - - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) - { - // if a path is set for a wave, use it - - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); - } else - { - // otherwise use preset sound - switch (m_sounds) - { - case 1: - PRECACHE_SOUND ("fans/fan1.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan1.wav"); - break; - case 2: - PRECACHE_SOUND ("fans/fan2.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan2.wav"); - break; - case 3: - PRECACHE_SOUND ("fans/fan3.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan3.wav"); - break; - case 4: - PRECACHE_SOUND ("fans/fan4.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan4.wav"); - break; - case 5: - PRECACHE_SOUND ("fans/fan5.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan5.wav"); - break; - - case 0: - default: - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) - { - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); - break; - } else - { - pev->noiseRunning = ALLOC_STRING("common/null.wav"); - break; - } - } - } - - if (pev->avelocity != g_vecZero ) - { - // if fan was spinning, and we went through transition or save/restore, - // make sure we restart the sound. 1.5 sec delay is magic number. KDB - - SetThink ( &CFuncRotating::SpinUp ); - pev->nextthink = pev->ltime + 1.5; - } -} - - - -// -// Touch - will hurt others based on how fast the brush is spinning -// -void CFuncRotating :: HurtTouch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) - return; - - // calculate damage based on rotation speed - pev->dmg = pev->avelocity.Length() / 10; - - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg; -} - -// -// RampPitchVol - ramp pitch and volume up to final values, based on difference -// between how fast we're going vs how fast we plan to go -// -#define FANPITCHMIN 30 -#define FANPITCHMAX 100 - -void CFuncRotating :: RampPitchVol (int fUp) -{ - - Vector vecAVel = pev->avelocity; - vec_t vecCur; - vec_t vecFinal; - float fpct; - float fvol; - float fpitch; - int pitch; - - // get current angular velocity - - vecCur = abs(vecAVel.x != 0 ? vecAVel.x : (vecAVel.y != 0 ? vecAVel.y : vecAVel.z)); - - // get target angular velocity - - vecFinal = (pev->movedir.x != 0 ? pev->movedir.x : (pev->movedir.y != 0 ? pev->movedir.y : pev->movedir.z)); - vecFinal *= pev->speed; - vecFinal = abs(vecFinal); - - // calc volume and pitch as % of final vol and pitch - - fpct = vecCur / vecFinal; -// if (fUp) -// fvol = m_flVolume * (0.5 + fpct/2.0); // spinup volume ramps up from 50% max vol -// else - fvol = m_flVolume * fpct; // slowdown volume ramps down to 0 - - fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct; - - pitch = (int) fpitch; - if (pitch == PITCH_NORM) - pitch = PITCH_NORM-1; - - // change the fan's vol and pitch - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - fvol, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - -} - -// -// SpinUp - accelerates a non-moving func_rotating up to it's speed -// -void CFuncRotating :: SpinUp( void ) -{ - Vector vecAVel;//rotational velocity - - pev->nextthink = pev->ltime + 0.1; - pev->avelocity = pev->avelocity + ( pev->movedir * ( pev->speed * m_flFanFriction ) ); - - vecAVel = pev->avelocity;// cache entity's rotational velocity - - // if we've met or exceeded target speed, set target speed and stop thinking - if ( abs(vecAVel.x) >= abs(pev->movedir.x * pev->speed) && - abs(vecAVel.y) >= abs(pev->movedir.y * pev->speed) && - abs(vecAVel.z) >= abs(pev->movedir.z * pev->speed) ) - { - pev->avelocity = pev->movedir * pev->speed;// set speed in case we overshot - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX); - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - else - { - RampPitchVol(TRUE); - } -} - -// -// SpinDown - decelerates a moving func_rotating to a standstill. -// -void CFuncRotating :: SpinDown( void ) -{ - Vector vecAVel;//rotational velocity - vec_t vecdir; - - pev->nextthink = pev->ltime + 0.1; - - pev->avelocity = pev->avelocity - ( pev->movedir * ( pev->speed * m_flFanFriction ) );//spin down slower than spinup - - vecAVel = pev->avelocity;// cache entity's rotational velocity - - if (pev->movedir.x != 0) - vecdir = pev->movedir.x; - else if (pev->movedir.y != 0) - vecdir = pev->movedir.y; - else - vecdir = pev->movedir.z; - - // if we've met or exceeded target speed, set target speed and stop thinking - // (note: must check for movedir > 0 or < 0) - if (((vecdir > 0) && (vecAVel.x <= 0 && vecAVel.y <= 0 && vecAVel.z <= 0)) || - ((vecdir < 0) && (vecAVel.x >= 0 && vecAVel.y >= 0 && vecAVel.z >= 0))) - { - pev->avelocity = g_vecZero;// set speed in case we overshot - - // stop sound, we're done - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), - 0, 0, SND_STOP, m_pitch); - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - else - { - RampPitchVol(FALSE); - } -} - -void CFuncRotating :: Rotate( void ) -{ - pev->nextthink = pev->ltime + 10; -} - -//========================================================= -// Rotating Use - when a rotating brush is triggered -//========================================================= -void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // is this a brush that should accelerate and decelerate when turned on/off (fan)? - if ( FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) ) - { - // fan is spinning, so stop it. - if ( pev->avelocity != g_vecZero ) - { - SetThink ( &CFuncRotating::SpinDown ); - //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), - // m_flVolume, m_flAttenuation, 0, m_pitch); - - pev->nextthink = pev->ltime + 0.1; - } - else// fan is not moving, so start it - { - SetThink ( &CFuncRotating::SpinUp ); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - 0.01, m_flAttenuation, 0, FANPITCHMIN); - - pev->nextthink = pev->ltime + 0.1; - } - } - else if ( !FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) )//this is a normal start/stop brush. - { - if ( pev->avelocity != g_vecZero ) - { - // play stopping sound here - SetThink ( &CFuncRotating::SpinDown ); - - // EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), - // m_flVolume, m_flAttenuation, 0, m_pitch); - - pev->nextthink = pev->ltime + 0.1; - // pev->avelocity = g_vecZero; - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - m_flVolume, m_flAttenuation, 0, FANPITCHMAX); - pev->avelocity = pev->movedir * pev->speed; - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - } -} - - -// -// RotatingBlocked - An entity has blocked the brush -// -void CFuncRotating :: Blocked( CBaseEntity *pOther ) - -{ - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); -} - - - - - - -//#endif - - -class CPendulum : public CBaseEntity -{ -public: - void Spawn ( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT Swing( void ); - void EXPORT PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Stop( void ); - void Touch( CBaseEntity *pOther ); - void EXPORT RopeTouch ( CBaseEntity *pOther );// this touch func makes the pendulum a rope - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void Blocked( CBaseEntity *pOther ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_accel; // Acceleration - float m_distance; // - float m_time; - float m_damp; - float m_maxSpeed; - float m_dampSpeed; - vec3_t m_center; - vec3_t m_start; -}; - -LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ); - -TYPEDESCRIPTION CPendulum::m_SaveData[] = -{ - DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_time, FIELD_TIME ), - DEFINE_FIELD( CPendulum, m_damp, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_maxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_dampSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_center, FIELD_VECTOR ), - DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ); - - - -void CPendulum :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "distance")) - { - m_distance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damp")) - { - m_damp = atof(pkvd->szValue) * 0.001; - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CPendulum :: Spawn( void ) -{ - // set the axis of rotation - CBaseToggle :: AxisDir( pev ); - - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if ( m_distance == 0 ) - return; - - if (pev->speed == 0) - pev->speed = 100; - - m_accel = (pev->speed * pev->speed) / (2 * fabs(m_distance)); // Calculate constant acceleration from speed and distance - m_maxSpeed = pev->speed; - m_start = pev->angles; - m_center = pev->angles + (m_distance * 0.5) * pev->movedir; - - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { - SetThink( &CPendulum::SUB_CallUseToggle ); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->speed = 0; - SetUse( &CPendulum::PendulumUse ); - - if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) - { - SetTouch ( &CPendulum::RopeTouch ); - } -} - - -void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->speed ) // Pendulum is moving, stop it and auto-return if necessary - { - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) ) - { - float delta; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_start ); - - pev->avelocity = m_maxSpeed * pev->movedir; - pev->nextthink = pev->ltime + (delta / m_maxSpeed); - SetThink( &CPendulum::Stop ); - } - else - { - pev->speed = 0; // Dead stop - SetThink( NULL ); - pev->avelocity = g_vecZero; - } - } - else - { - pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving - m_time = gpGlobals->time; // Save time to calculate dt - SetThink( &CPendulum::Swing ); - m_dampSpeed = m_maxSpeed; - } -} - - -void CPendulum :: Stop( void ) -{ - pev->angles = m_start; - pev->speed = 0; - SetThink( NULL ); - pev->avelocity = g_vecZero; -} - - -void CPendulum::Blocked( CBaseEntity *pOther ) -{ - m_time = gpGlobals->time; -} - - -void CPendulum :: Swing( void ) -{ - float delta, dt; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_center ); - dt = gpGlobals->time - m_time; // How much time has passed? - m_time = gpGlobals->time; // Remember the last time called - - if ( delta > 0 && m_accel > 0 ) - pev->speed -= m_accel * dt; // Integrate velocity - else - pev->speed += m_accel * dt; - - if ( pev->speed > m_maxSpeed ) - pev->speed = m_maxSpeed; - else if ( pev->speed < -m_maxSpeed ) - pev->speed = -m_maxSpeed; - // scale the destdelta vector by the time spent traveling to get velocity - pev->avelocity = pev->speed * pev->movedir; - - // Call this again - pev->nextthink = pev->ltime + 0.1; - - if ( m_damp ) - { - m_dampSpeed -= m_damp * m_dampSpeed * dt; - if ( m_dampSpeed < 30.0 ) - { - pev->angles = m_center; - pev->speed = 0; - SetThink( NULL ); - pev->avelocity = g_vecZero; - } - else if ( pev->speed > m_dampSpeed ) - pev->speed = m_dampSpeed; - else if ( pev->speed < -m_dampSpeed ) - pev->speed = -m_dampSpeed; - - } -} - - -void CPendulum :: Touch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( pev->dmg <= 0 ) - return; - - // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) - return; - - // calculate damage based on rotation speed - float damage = pev->dmg * pev->speed * 0.01; - - if ( damage < 0 ) - damage = -damage; - - pOther->TakeDamage( pev, pev, damage, DMG_CRUSH ); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * damage; -} - -void CPendulum :: RopeTouch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( !pOther->IsPlayer() ) - {// not a player! - ALERT ( at_console, "Not a client\n" ); - return; - } - - if ( ENT(pevOther) == pev->enemy ) - {// this player already on the rope. - return; - } - - pev->enemy = pOther->edict(); - pevOther->velocity = g_vecZero; - pevOther->movetype = MOVETYPE_NONE; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== bmodels.cpp ======================================================== + + spawn, think, and use functions for entities that use brush models + +*/ +#include +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "doors.h" +#include "../mod/AvHSpecials.h" +#include "../mod/AvHServerVariables.h" + +extern DLL_GLOBAL Vector g_vecAttackDir; + +#define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled +#define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed +#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid. + +// covering cheesy noise1, noise2, & noise3 fields so they make more sense (for rotating fans) +#define noiseStart noise1 +#define noiseStop noise2 +#define noiseRunning noise3 + +#define SF_PENDULUM_SWING 2 // spawnflag that makes a pendulum a rope swing. +// +// BModelOrigin - calculates origin of a bmodel from absmin/size because all bmodel origins are 0 0 0 +// +Vector VecBModelOrigin( entvars_t* pevBModel ) +{ + return pevBModel->absmin + ( pevBModel->size * 0.5 ); +} + +// =================== FUNC_WALL ============================================== + +#include "cfuncwall.h" + +LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); + +void CFuncWall :: Spawn( void ) +{ + pev->angles = g_vecZero; + pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything + pev->solid = SOLID_BSP; + SET_MODEL( ENT(pev), STRING(pev->model) ); + + // If it can't move/go away, it's really part of the world + pev->flags |= FL_WORLDBRUSH; +} + + +void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( ShouldToggle( useType, (int)(pev->frame)) ) + pev->frame = 1 - pev->frame; +} + + +#define SF_WALL_START_OFF 0x0001 + +class CFuncWallToggle : public CFuncWall +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void TurnOff( void ); + void TurnOn( void ); + BOOL IsOn( void ); +}; + +LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ); + +void CFuncWallToggle :: Spawn( void ) +{ + CFuncWall::Spawn(); + if ( pev->spawnflags & SF_WALL_START_OFF ) + TurnOff(); +} + + +void CFuncWallToggle :: TurnOff( void ) +{ + pev->solid = SOLID_NOT; + pev->effects |= EF_NODRAW; + UTIL_SetOrigin( pev, pev->origin ); +} + + +void CFuncWallToggle :: TurnOn( void ) +{ + pev->solid = SOLID_BSP; + pev->effects &= ~EF_NODRAW; + UTIL_SetOrigin( pev, pev->origin ); +} + + +BOOL CFuncWallToggle :: IsOn( void ) +{ + if ( pev->solid == SOLID_NOT ) + return FALSE; + return TRUE; +} + + +void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int status = IsOn(); + + if ( ShouldToggle( useType, status ) ) + { + if ( status ) + TurnOff(); + else + TurnOn(); + } +} + + +#define SF_CONVEYOR_VISUAL 0x0001 +#define SF_CONVEYOR_NOTSOLID 0x0002 + +class CFuncConveyor : public CFuncWall +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void UpdateSpeed( float speed ); +}; + +LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); +void CFuncConveyor :: Spawn( void ) +{ + SetMovedir( pev ); + CFuncWall::Spawn(); + + if ( !(pev->spawnflags & SF_CONVEYOR_VISUAL) ) + SetBits( pev->flags, FL_CONVEYOR ); + + // HACKHACK - This is to allow for some special effects + if ( pev->spawnflags & SF_CONVEYOR_NOTSOLID ) + { + pev->solid = SOLID_NOT; + pev->skin = 0; // Don't want the engine thinking we've got special contents on this brush + } + + if ( pev->speed == 0 ) + pev->speed = 100; + + UpdateSpeed( pev->speed ); +} + + +// HACKHACK -- This is ugly, but encode the speed in the rendercolor to avoid adding more data to the network stream +void CFuncConveyor :: UpdateSpeed( float speed ) +{ + // Encode it as an integer with 4 fractional bits + int speedCode = (int)(fabs(speed) * 16.0); + + if ( speed < 0 ) + pev->rendercolor.x = 1; + else + pev->rendercolor.x = 0; + + pev->rendercolor.y = (speedCode >> 8); + pev->rendercolor.z = (speedCode & 0xFF); +} + + +void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + pev->speed = -pev->speed; + UpdateSpeed( pev->speed ); +} + + + +// =================== FUNC_ILLUSIONARY ============================================== + + +/*QUAKED func_illusionary (0 .5 .8) ? +A simple entity that looks solid but lets you walk through it. +*/ +class CFuncIllusionary : public CBaseToggle +{ +public: + void Spawn( void ); + void EXPORT SloshTouch( CBaseEntity *pOther ); + void KeyValue( KeyValueData *pkvd ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +}; + +LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ); + +void CFuncIllusionary :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type + { + pev->skin = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +void CFuncIllusionary :: Spawn( void ) +{ + pev->angles = g_vecZero; + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT;// always solid_not + SET_MODEL( ENT(pev), STRING(pev->model) ); + pev->iuser3 = AVH_USER3_FUNC_ILLUSIONARY; + + // I'd rather eat the network bandwidth of this than figure out how to save/restore + // these entities after they have been moved to the client, or respawn them ala Quake + // Perhaps we can do this in deathmatch only. + // MAKE_STATIC(ENT(pev)); +} + + +// ------------------------------------------------------------------------------- +// +// Monster only clip brush +// +// This brush will be solid for any entity who has the FL_MONSTERCLIP flag set +// in pev->flags +// +// otherwise it will be invisible and not solid. This can be used to keep +// specific monsters out of certain areas +// +// ------------------------------------------------------------------------------- +class CFuncMonsterClip : public CFuncWall +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) {} // Clear out func_wall's use function +}; + +LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip ); + +void CFuncMonsterClip::Spawn( void ) +{ + CFuncWall::Spawn(); + if ( ns_cvar_float(showtriggers) == 0 ) + pev->effects = EF_NODRAW; + pev->flags |= FL_MONSTERCLIP; +} + + +// =================== FUNC_ROTATING ============================================== +class CFuncRotating : public CBaseEntity +{ +public: + // basic functions + void Spawn( void ); + void Precache( void ); + void EXPORT SpinUp ( void ); + void EXPORT SpinDown ( void ); + void KeyValue( KeyValueData* pkvd); + void EXPORT HurtTouch ( CBaseEntity *pOther ); + void EXPORT RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT Rotate( void ); + void RampPitchVol (int fUp ); + void Blocked( CBaseEntity *pOther ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + float m_flFanFriction; + float m_flAttenuation; + float m_flVolume; + float m_pitch; + int m_sounds; +}; + +TYPEDESCRIPTION CFuncRotating::m_SaveData[] = +{ + DEFINE_FIELD( CFuncRotating, m_flFanFriction, FIELD_FLOAT ), + DEFINE_FIELD( CFuncRotating, m_flAttenuation, FIELD_FLOAT ), + DEFINE_FIELD( CFuncRotating, m_flVolume, FIELD_FLOAT ), + DEFINE_FIELD( CFuncRotating, m_pitch, FIELD_FLOAT ), + DEFINE_FIELD( CFuncRotating, m_sounds, FIELD_INTEGER ) +}; + +IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ); + + +LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); + +void CFuncRotating :: KeyValue( KeyValueData* pkvd) +{ + if (FStrEq(pkvd->szKeyName, "fanfriction")) + { + m_flFanFriction = atof(pkvd->szValue)/100; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "Volume")) + { + m_flVolume = atof(pkvd->szValue)/10.0; + + if (m_flVolume > 1.0) + m_flVolume = 1.0; + if (m_flVolume < 0.0) + m_flVolume = 0.0; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "spawnorigin")) + { + Vector tmp; + UTIL_StringToVector( (float *)tmp, pkvd->szValue ); + if ( tmp != g_vecZero ) + pev->origin = tmp; + } + else if (FStrEq(pkvd->szKeyName, "sounds")) + { + m_sounds = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS +You need to have an origin brush as part of this entity. The +center of that brush will be +the point around which it is rotated. It will rotate around the Z +axis by default. You can +check either the X_AXIS or Y_AXIS box to change that. + +"speed" determines how fast it moves; default value is 100. +"dmg" damage to inflict when blocked (2 default) + +REVERSE will cause the it to rotate in the opposite direction. +*/ + + +void CFuncRotating :: Spawn( ) +{ + // set final pitch. Must not be PITCH_NORM, since we + // plan on pitch shifting later. + + m_pitch = PITCH_NORM - 1; + + // maintain compatibility with previous maps + if (m_flVolume == 0.0) + m_flVolume = 1.0; + + // if the designer didn't set a sound attenuation, default to one. + m_flAttenuation = ATTN_NORM; + + if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) ) + { + m_flAttenuation = ATTN_IDLE; + } + else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) ) + { + m_flAttenuation = ATTN_STATIC; + } + else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) ) + { + m_flAttenuation = ATTN_NORM; + } + + // prevent divide by zero if level designer forgets friction! + if ( m_flFanFriction == 0 ) + { + m_flFanFriction = 1; + } + + if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS) ) + pev->movedir = Vector(0,0,1); + else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS) ) + pev->movedir = Vector(1,0,0); + else + pev->movedir = Vector(0,1,0); // y-axis + + // check for reverse rotation + if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) ) + pev->movedir = pev->movedir * -1; + + // some rotating objects like fake volumetric lights will not be solid. + if ( FBitSet(pev->spawnflags, SF_ROTATING_NOT_SOLID) ) + { + pev->solid = SOLID_NOT; + pev->skin = CONTENTS_EMPTY; + pev->movetype = MOVETYPE_PUSH; + } + else + { + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + } + + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL( ENT(pev), STRING(pev->model) ); + + SetUse( &CFuncRotating::RotatingUse ); + // did level designer forget to assign speed? + if (pev->speed <= 0) + pev->speed = 0; + + // Removed this per level designers request. -- JAY + // if (pev->dmg == 0) + // pev->dmg = 2; + + // instant-use brush? + if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) + { + SetThink( &CFuncRotating::SUB_CallUseToggle ); + pev->nextthink = pev->ltime + 1.5; // leave a magic delay for client to start up + } + // can this brush inflict pain? + if ( FBitSet (pev->spawnflags, SF_BRUSH_HURT) ) + { + SetTouch( &CFuncRotating::HurtTouch ); + } + + Precache( ); +} + + +void CFuncRotating :: Precache( void ) +{ + char* szSoundFile = (char*) STRING(pev->message); + + // set up fan sounds + + if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) + { + // if a path is set for a wave, use it + + PRECACHE_SOUND(szSoundFile); + + pev->noiseRunning = ALLOC_STRING(szSoundFile); + } else + { + // otherwise use preset sound + switch (m_sounds) + { + case 1: + PRECACHE_SOUND ("fans/fan1.wav"); + pev->noiseRunning = ALLOC_STRING("fans/fan1.wav"); + break; + case 2: + PRECACHE_SOUND ("fans/fan2.wav"); + pev->noiseRunning = ALLOC_STRING("fans/fan2.wav"); + break; + case 3: + PRECACHE_SOUND ("fans/fan3.wav"); + pev->noiseRunning = ALLOC_STRING("fans/fan3.wav"); + break; + case 4: + PRECACHE_SOUND ("fans/fan4.wav"); + pev->noiseRunning = ALLOC_STRING("fans/fan4.wav"); + break; + case 5: + PRECACHE_SOUND ("fans/fan5.wav"); + pev->noiseRunning = ALLOC_STRING("fans/fan5.wav"); + break; + + case 0: + default: + if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) + { + PRECACHE_SOUND(szSoundFile); + + pev->noiseRunning = ALLOC_STRING(szSoundFile); + break; + } else + { + pev->noiseRunning = ALLOC_STRING("common/null.wav"); + break; + } + } + } + + if (pev->avelocity != g_vecZero ) + { + // if fan was spinning, and we went through transition or save/restore, + // make sure we restart the sound. 1.5 sec delay is magic number. KDB + + SetThink ( &CFuncRotating::SpinUp ); + pev->nextthink = pev->ltime + 1.5; + } +} + + + +// +// Touch - will hurt others based on how fast the brush is spinning +// +void CFuncRotating :: HurtTouch ( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + // we can't hurt this thing, so we're not concerned with it + if ( !pevOther->takedamage ) + return; + + // calculate damage based on rotation speed + pev->dmg = pev->avelocity.Length() / 10; + + pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); + + pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg; +} + +// +// RampPitchVol - ramp pitch and volume up to final values, based on difference +// between how fast we're going vs how fast we plan to go +// +#define FANPITCHMIN 30 +#define FANPITCHMAX 100 + +void CFuncRotating :: RampPitchVol (int fUp) +{ + + Vector vecAVel = pev->avelocity; + vec_t vecCur; + vec_t vecFinal; + float fpct; + float fvol; + float fpitch; + int pitch; + + // get current angular velocity + + vecCur = abs(vecAVel.x != 0 ? vecAVel.x : (vecAVel.y != 0 ? vecAVel.y : vecAVel.z)); + + // get target angular velocity + + vecFinal = (pev->movedir.x != 0 ? pev->movedir.x : (pev->movedir.y != 0 ? pev->movedir.y : pev->movedir.z)); + vecFinal *= pev->speed; + vecFinal = abs(vecFinal); + + // calc volume and pitch as % of final vol and pitch + + fpct = vecCur / vecFinal; +// if (fUp) +// fvol = m_flVolume * (0.5 + fpct/2.0); // spinup volume ramps up from 50% max vol +// else + fvol = m_flVolume * fpct; // slowdown volume ramps down to 0 + + fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct; + + pitch = (int) fpitch; + if (pitch == PITCH_NORM) + pitch = PITCH_NORM-1; + + // change the fan's vol and pitch + + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), + fvol, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); + +} + +// +// SpinUp - accelerates a non-moving func_rotating up to it's speed +// +void CFuncRotating :: SpinUp( void ) +{ + Vector vecAVel;//rotational velocity + + pev->nextthink = pev->ltime + 0.1; + pev->avelocity = pev->avelocity + ( pev->movedir * ( pev->speed * m_flFanFriction ) ); + + vecAVel = pev->avelocity;// cache entity's rotational velocity + + // if we've met or exceeded target speed, set target speed and stop thinking + if ( abs(vecAVel.x) >= abs(pev->movedir.x * pev->speed) && + abs(vecAVel.y) >= abs(pev->movedir.y * pev->speed) && + abs(vecAVel.z) >= abs(pev->movedir.z * pev->speed) ) + { + pev->avelocity = pev->movedir * pev->speed;// set speed in case we overshot + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), + m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX); + + SetThink( &CFuncRotating::Rotate ); + Rotate(); + } + else + { + RampPitchVol(TRUE); + } +} + +// +// SpinDown - decelerates a moving func_rotating to a standstill. +// +void CFuncRotating :: SpinDown( void ) +{ + Vector vecAVel;//rotational velocity + vec_t vecdir; + + pev->nextthink = pev->ltime + 0.1; + + pev->avelocity = pev->avelocity - ( pev->movedir * ( pev->speed * m_flFanFriction ) );//spin down slower than spinup + + vecAVel = pev->avelocity;// cache entity's rotational velocity + + if (pev->movedir.x != 0) + vecdir = pev->movedir.x; + else if (pev->movedir.y != 0) + vecdir = pev->movedir.y; + else + vecdir = pev->movedir.z; + + // if we've met or exceeded target speed, set target speed and stop thinking + // (note: must check for movedir > 0 or < 0) + if (((vecdir > 0) && (vecAVel.x <= 0 && vecAVel.y <= 0 && vecAVel.z <= 0)) || + ((vecdir < 0) && (vecAVel.x >= 0 && vecAVel.y >= 0 && vecAVel.z >= 0))) + { + pev->avelocity = g_vecZero;// set speed in case we overshot + + // stop sound, we're done + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), + 0, 0, SND_STOP, m_pitch); + + SetThink( &CFuncRotating::Rotate ); + Rotate(); + } + else + { + RampPitchVol(FALSE); + } +} + +void CFuncRotating :: Rotate( void ) +{ + pev->nextthink = pev->ltime + 10; +} + +//========================================================= +// Rotating Use - when a rotating brush is triggered +//========================================================= +void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // is this a brush that should accelerate and decelerate when turned on/off (fan)? + if ( FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) ) + { + // fan is spinning, so stop it. + if ( pev->avelocity != g_vecZero ) + { + SetThink ( &CFuncRotating::SpinDown ); + //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), + // m_flVolume, m_flAttenuation, 0, m_pitch); + + pev->nextthink = pev->ltime + 0.1; + } + else// fan is not moving, so start it + { + SetThink ( &CFuncRotating::SpinUp ); + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), + 0.01, m_flAttenuation, 0, FANPITCHMIN); + + pev->nextthink = pev->ltime + 0.1; + } + } + else if ( !FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) )//this is a normal start/stop brush. + { + if ( pev->avelocity != g_vecZero ) + { + // play stopping sound here + SetThink ( &CFuncRotating::SpinDown ); + + // EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), + // m_flVolume, m_flAttenuation, 0, m_pitch); + + pev->nextthink = pev->ltime + 0.1; + // pev->avelocity = g_vecZero; + } + else + { + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), + m_flVolume, m_flAttenuation, 0, FANPITCHMAX); + pev->avelocity = pev->movedir * pev->speed; + + SetThink( &CFuncRotating::Rotate ); + Rotate(); + } + } +} + + +// +// RotatingBlocked - An entity has blocked the brush +// +void CFuncRotating :: Blocked( CBaseEntity *pOther ) + +{ + pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); +} + + + + + + +//#endif + + +class CPendulum : public CBaseEntity +{ +public: + void Spawn ( void ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT Swing( void ); + void EXPORT PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT Stop( void ); + void Touch( CBaseEntity *pOther ); + void EXPORT RopeTouch ( CBaseEntity *pOther );// this touch func makes the pendulum a rope + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + void Blocked( CBaseEntity *pOther ); + + static TYPEDESCRIPTION m_SaveData[]; + + float m_accel; // Acceleration + float m_distance; // + float m_time; + float m_damp; + float m_maxSpeed; + float m_dampSpeed; + vec3_t m_center; + vec3_t m_start; +}; + +LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ); + +TYPEDESCRIPTION CPendulum::m_SaveData[] = +{ + DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ), + DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ), + DEFINE_FIELD( CPendulum, m_time, FIELD_TIME ), + DEFINE_FIELD( CPendulum, m_damp, FIELD_FLOAT ), + DEFINE_FIELD( CPendulum, m_maxSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CPendulum, m_dampSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CPendulum, m_center, FIELD_VECTOR ), + DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ), +}; + +IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ); + + + +void CPendulum :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "distance")) + { + m_distance = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "damp")) + { + m_damp = atof(pkvd->szValue) * 0.001; + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + + +void CPendulum :: Spawn( void ) +{ + // set the axis of rotation + CBaseToggle :: AxisDir( pev ); + + if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL(ENT(pev), STRING(pev->model) ); + + if ( m_distance == 0 ) + return; + + if (pev->speed == 0) + pev->speed = 100; + + m_accel = (pev->speed * pev->speed) / (2 * fabs(m_distance)); // Calculate constant acceleration from speed and distance + m_maxSpeed = pev->speed; + m_start = pev->angles; + m_center = pev->angles + (m_distance * 0.5) * pev->movedir; + + if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) + { + SetThink( &CPendulum::SUB_CallUseToggle ); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->speed = 0; + SetUse( &CPendulum::PendulumUse ); + + if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) + { + SetTouch ( &CPendulum::RopeTouch ); + } +} + + +void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( pev->speed ) // Pendulum is moving, stop it and auto-return if necessary + { + if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) ) + { + float delta; + + delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_start ); + + pev->avelocity = m_maxSpeed * pev->movedir; + pev->nextthink = pev->ltime + (delta / m_maxSpeed); + SetThink( &CPendulum::Stop ); + } + else + { + pev->speed = 0; // Dead stop + SetThink( NULL ); + pev->avelocity = g_vecZero; + } + } + else + { + pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving + m_time = gpGlobals->time; // Save time to calculate dt + SetThink( &CPendulum::Swing ); + m_dampSpeed = m_maxSpeed; + } +} + + +void CPendulum :: Stop( void ) +{ + pev->angles = m_start; + pev->speed = 0; + SetThink( NULL ); + pev->avelocity = g_vecZero; +} + + +void CPendulum::Blocked( CBaseEntity *pOther ) +{ + m_time = gpGlobals->time; +} + + +void CPendulum :: Swing( void ) +{ + float delta, dt; + + delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_center ); + dt = gpGlobals->time - m_time; // How much time has passed? + m_time = gpGlobals->time; // Remember the last time called + + if ( delta > 0 && m_accel > 0 ) + pev->speed -= m_accel * dt; // Integrate velocity + else + pev->speed += m_accel * dt; + + if ( pev->speed > m_maxSpeed ) + pev->speed = m_maxSpeed; + else if ( pev->speed < -m_maxSpeed ) + pev->speed = -m_maxSpeed; + // scale the destdelta vector by the time spent traveling to get velocity + pev->avelocity = pev->speed * pev->movedir; + + // Call this again + pev->nextthink = pev->ltime + 0.1; + + if ( m_damp ) + { + m_dampSpeed -= m_damp * m_dampSpeed * dt; + if ( m_dampSpeed < 30.0 ) + { + pev->angles = m_center; + pev->speed = 0; + SetThink( NULL ); + pev->avelocity = g_vecZero; + } + else if ( pev->speed > m_dampSpeed ) + pev->speed = m_dampSpeed; + else if ( pev->speed < -m_dampSpeed ) + pev->speed = -m_dampSpeed; + + } +} + + +void CPendulum :: Touch ( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + if ( pev->dmg <= 0 ) + return; + + // we can't hurt this thing, so we're not concerned with it + if ( !pevOther->takedamage ) + return; + + // calculate damage based on rotation speed + float damage = pev->dmg * pev->speed * 0.01; + + if ( damage < 0 ) + damage = -damage; + + pOther->TakeDamage( pev, pev, damage, DMG_CRUSH ); + + pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * damage; +} + +void CPendulum :: RopeTouch ( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + if ( !pOther->IsPlayer() ) + {// not a player! + ALERT ( at_console, "Not a client\n" ); + return; + } + + if ( ENT(pevOther) == pev->enemy ) + {// this player already on the rope. + return; + } + + pev->enemy = pOther->edict(); + pevOther->velocity = g_vecZero; + pevOther->movetype = MOVETYPE_NONE; +} + + diff --git a/main/source/dlls/bmodels.cpp~ b/main/source/dlls/bmodels.cpp~ deleted file mode 100644 index 65225890..00000000 --- a/main/source/dlls/bmodels.cpp~ +++ /dev/null @@ -1,950 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== bmodels.cpp ======================================================== - - spawn, think, and use functions for entities that use brush models - -*/ -#include -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" -#include "../mod/AvHSpecials.h" -#include "../mod/AvHServerVariables.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -#define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled -#define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed -#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid. - -// covering cheesy noise1, noise2, & noise3 fields so they make more sense (for rotating fans) -#define noiseStart noise1 -#define noiseStop noise2 -#define noiseRunning noise3 - -#define SF_PENDULUM_SWING 2 // spawnflag that makes a pendulum a rope swing. -// -// BModelOrigin - calculates origin of a bmodel from absmin/size because all bmodel origins are 0 0 0 -// -Vector VecBModelOrigin( entvars_t* pevBModel ) -{ - return pevBModel->absmin + ( pevBModel->size * 0.5 ); -} - -// =================== FUNC_WALL ============================================== - -#include "dlls/cfuncwall.h" - -LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); - -void CFuncWall :: Spawn( void ) -{ - pev->angles = g_vecZero; - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - // If it can't move/go away, it's really part of the world - pev->flags |= FL_WORLDBRUSH; -} - - -void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( ShouldToggle( useType, (int)(pev->frame)) ) - pev->frame = 1 - pev->frame; -} - - -#define SF_WALL_START_OFF 0x0001 - -class CFuncWallToggle : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void TurnOff( void ); - void TurnOn( void ); - BOOL IsOn( void ); -}; - -LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ); - -void CFuncWallToggle :: Spawn( void ) -{ - CFuncWall::Spawn(); - if ( pev->spawnflags & SF_WALL_START_OFF ) - TurnOff(); -} - - -void CFuncWallToggle :: TurnOff( void ) -{ - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - UTIL_SetOrigin( pev, pev->origin ); -} - - -void CFuncWallToggle :: TurnOn( void ) -{ - pev->solid = SOLID_BSP; - pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( pev, pev->origin ); -} - - -BOOL CFuncWallToggle :: IsOn( void ) -{ - if ( pev->solid == SOLID_NOT ) - return FALSE; - return TRUE; -} - - -void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int status = IsOn(); - - if ( ShouldToggle( useType, status ) ) - { - if ( status ) - TurnOff(); - else - TurnOn(); - } -} - - -#define SF_CONVEYOR_VISUAL 0x0001 -#define SF_CONVEYOR_NOTSOLID 0x0002 - -class CFuncConveyor : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void UpdateSpeed( float speed ); -}; - -LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); -void CFuncConveyor :: Spawn( void ) -{ - SetMovedir( pev ); - CFuncWall::Spawn(); - - if ( !(pev->spawnflags & SF_CONVEYOR_VISUAL) ) - SetBits( pev->flags, FL_CONVEYOR ); - - // HACKHACK - This is to allow for some special effects - if ( pev->spawnflags & SF_CONVEYOR_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->skin = 0; // Don't want the engine thinking we've got special contents on this brush - } - - if ( pev->speed == 0 ) - pev->speed = 100; - - UpdateSpeed( pev->speed ); -} - - -// HACKHACK -- This is ugly, but encode the speed in the rendercolor to avoid adding more data to the network stream -void CFuncConveyor :: UpdateSpeed( float speed ) -{ - // Encode it as an integer with 4 fractional bits - int speedCode = (int)(fabs(speed) * 16.0); - - if ( speed < 0 ) - pev->rendercolor.x = 1; - else - pev->rendercolor.x = 0; - - pev->rendercolor.y = (speedCode >> 8); - pev->rendercolor.z = (speedCode & 0xFF); -} - - -void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->speed = -pev->speed; - UpdateSpeed( pev->speed ); -} - - - -// =================== FUNC_ILLUSIONARY ============================================== - - -/*QUAKED func_illusionary (0 .5 .8) ? -A simple entity that looks solid but lets you walk through it. -*/ -class CFuncIllusionary : public CBaseToggle -{ -public: - void Spawn( void ); - void EXPORT SloshTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ); - -void CFuncIllusionary :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type - { - pev->skin = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CFuncIllusionary :: Spawn( void ) -{ - pev->angles = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT;// always solid_not - SET_MODEL( ENT(pev), STRING(pev->model) ); - pev->iuser3 = AVH_USER3_FUNC_ILLUSIONARY; - - // I'd rather eat the network bandwidth of this than figure out how to save/restore - // these entities after they have been moved to the client, or respawn them ala Quake - // Perhaps we can do this in deathmatch only. - // MAKE_STATIC(ENT(pev)); -} - - -// ------------------------------------------------------------------------------- -// -// Monster only clip brush -// -// This brush will be solid for any entity who has the FL_MONSTERCLIP flag set -// in pev->flags -// -// otherwise it will be invisible and not solid. This can be used to keep -// specific monsters out of certain areas -// -// ------------------------------------------------------------------------------- -class CFuncMonsterClip : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) {} // Clear out func_wall's use function -}; - -LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip ); - -void CFuncMonsterClip::Spawn( void ) -{ - CFuncWall::Spawn(); - if ( ns_cvar_float(showtriggers) == 0 ) - pev->effects = EF_NODRAW; - pev->flags |= FL_MONSTERCLIP; -} - - -// =================== FUNC_ROTATING ============================================== -class CFuncRotating : public CBaseEntity -{ -public: - // basic functions - void Spawn( void ); - void Precache( void ); - void EXPORT SpinUp ( void ); - void EXPORT SpinDown ( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT HurtTouch ( CBaseEntity *pOther ); - void EXPORT RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Rotate( void ); - void RampPitchVol (int fUp ); - void Blocked( CBaseEntity *pOther ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flFanFriction; - float m_flAttenuation; - float m_flVolume; - float m_pitch; - int m_sounds; -}; - -TYPEDESCRIPTION CFuncRotating::m_SaveData[] = -{ - DEFINE_FIELD( CFuncRotating, m_flFanFriction, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_pitch, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_sounds, FIELD_INTEGER ) -}; - -IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ); - - -LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); - -void CFuncRotating :: KeyValue( KeyValueData* pkvd) -{ - if (FStrEq(pkvd->szKeyName, "fanfriction")) - { - m_flFanFriction = atof(pkvd->szValue)/100; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Volume")) - { - m_flVolume = atof(pkvd->szValue)/10.0; - - if (m_flVolume > 1.0) - m_flVolume = 1.0; - if (m_flVolume < 0.0) - m_flVolume = 0.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spawnorigin")) - { - Vector tmp; - UTIL_StringToVector( (float *)tmp, pkvd->szValue ); - if ( tmp != g_vecZero ) - pev->origin = tmp; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS -You need to have an origin brush as part of this entity. The -center of that brush will be -the point around which it is rotated. It will rotate around the Z -axis by default. You can -check either the X_AXIS or Y_AXIS box to change that. - -"speed" determines how fast it moves; default value is 100. -"dmg" damage to inflict when blocked (2 default) - -REVERSE will cause the it to rotate in the opposite direction. -*/ - - -void CFuncRotating :: Spawn( ) -{ - // set final pitch. Must not be PITCH_NORM, since we - // plan on pitch shifting later. - - m_pitch = PITCH_NORM - 1; - - // maintain compatibility with previous maps - if (m_flVolume == 0.0) - m_flVolume = 1.0; - - // if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_NORM; - - if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - - // prevent divide by zero if level designer forgets friction! - if ( m_flFanFriction == 0 ) - { - m_flFanFriction = 1; - } - - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS) ) - pev->movedir = Vector(0,0,1); - else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS) ) - pev->movedir = Vector(1,0,0); - else - pev->movedir = Vector(0,1,0); // y-axis - - // check for reverse rotation - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - // some rotating objects like fake volumetric lights will not be solid. - if ( FBitSet(pev->spawnflags, SF_ROTATING_NOT_SOLID) ) - { - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_EMPTY; - pev->movetype = MOVETYPE_PUSH; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - SetUse( &CFuncRotating::RotatingUse ); - // did level designer forget to assign speed? - if (pev->speed <= 0) - pev->speed = 0; - - // Removed this per level designers request. -- JAY - // if (pev->dmg == 0) - // pev->dmg = 2; - - // instant-use brush? - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { - SetThink( &CFuncRotating::SUB_CallUseToggle ); - pev->nextthink = pev->ltime + 1.5; // leave a magic delay for client to start up - } - // can this brush inflict pain? - if ( FBitSet (pev->spawnflags, SF_BRUSH_HURT) ) - { - SetTouch( &CFuncRotating::HurtTouch ); - } - - Precache( ); -} - - -void CFuncRotating :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - // set up fan sounds - - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) - { - // if a path is set for a wave, use it - - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); - } else - { - // otherwise use preset sound - switch (m_sounds) - { - case 1: - PRECACHE_SOUND ("fans/fan1.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan1.wav"); - break; - case 2: - PRECACHE_SOUND ("fans/fan2.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan2.wav"); - break; - case 3: - PRECACHE_SOUND ("fans/fan3.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan3.wav"); - break; - case 4: - PRECACHE_SOUND ("fans/fan4.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan4.wav"); - break; - case 5: - PRECACHE_SOUND ("fans/fan5.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan5.wav"); - break; - - case 0: - default: - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) - { - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); - break; - } else - { - pev->noiseRunning = ALLOC_STRING("common/null.wav"); - break; - } - } - } - - if (pev->avelocity != g_vecZero ) - { - // if fan was spinning, and we went through transition or save/restore, - // make sure we restart the sound. 1.5 sec delay is magic number. KDB - - SetThink ( &CFuncRotating::SpinUp ); - pev->nextthink = pev->ltime + 1.5; - } -} - - - -// -// Touch - will hurt others based on how fast the brush is spinning -// -void CFuncRotating :: HurtTouch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) - return; - - // calculate damage based on rotation speed - pev->dmg = pev->avelocity.Length() / 10; - - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg; -} - -// -// RampPitchVol - ramp pitch and volume up to final values, based on difference -// between how fast we're going vs how fast we plan to go -// -#define FANPITCHMIN 30 -#define FANPITCHMAX 100 - -void CFuncRotating :: RampPitchVol (int fUp) -{ - - Vector vecAVel = pev->avelocity; - vec_t vecCur; - vec_t vecFinal; - float fpct; - float fvol; - float fpitch; - int pitch; - - // get current angular velocity - - vecCur = abs(vecAVel.x != 0 ? vecAVel.x : (vecAVel.y != 0 ? vecAVel.y : vecAVel.z)); - - // get target angular velocity - - vecFinal = (pev->movedir.x != 0 ? pev->movedir.x : (pev->movedir.y != 0 ? pev->movedir.y : pev->movedir.z)); - vecFinal *= pev->speed; - vecFinal = abs(vecFinal); - - // calc volume and pitch as % of final vol and pitch - - fpct = vecCur / vecFinal; -// if (fUp) -// fvol = m_flVolume * (0.5 + fpct/2.0); // spinup volume ramps up from 50% max vol -// else - fvol = m_flVolume * fpct; // slowdown volume ramps down to 0 - - fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct; - - pitch = (int) fpitch; - if (pitch == PITCH_NORM) - pitch = PITCH_NORM-1; - - // change the fan's vol and pitch - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - fvol, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - -} - -// -// SpinUp - accelerates a non-moving func_rotating up to it's speed -// -void CFuncRotating :: SpinUp( void ) -{ - Vector vecAVel;//rotational velocity - - pev->nextthink = pev->ltime + 0.1; - pev->avelocity = pev->avelocity + ( pev->movedir * ( pev->speed * m_flFanFriction ) ); - - vecAVel = pev->avelocity;// cache entity's rotational velocity - - // if we've met or exceeded target speed, set target speed and stop thinking - if ( abs(vecAVel.x) >= abs(pev->movedir.x * pev->speed) && - abs(vecAVel.y) >= abs(pev->movedir.y * pev->speed) && - abs(vecAVel.z) >= abs(pev->movedir.z * pev->speed) ) - { - pev->avelocity = pev->movedir * pev->speed;// set speed in case we overshot - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX); - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - else - { - RampPitchVol(TRUE); - } -} - -// -// SpinDown - decelerates a moving func_rotating to a standstill. -// -void CFuncRotating :: SpinDown( void ) -{ - Vector vecAVel;//rotational velocity - vec_t vecdir; - - pev->nextthink = pev->ltime + 0.1; - - pev->avelocity = pev->avelocity - ( pev->movedir * ( pev->speed * m_flFanFriction ) );//spin down slower than spinup - - vecAVel = pev->avelocity;// cache entity's rotational velocity - - if (pev->movedir.x != 0) - vecdir = pev->movedir.x; - else if (pev->movedir.y != 0) - vecdir = pev->movedir.y; - else - vecdir = pev->movedir.z; - - // if we've met or exceeded target speed, set target speed and stop thinking - // (note: must check for movedir > 0 or < 0) - if (((vecdir > 0) && (vecAVel.x <= 0 && vecAVel.y <= 0 && vecAVel.z <= 0)) || - ((vecdir < 0) && (vecAVel.x >= 0 && vecAVel.y >= 0 && vecAVel.z >= 0))) - { - pev->avelocity = g_vecZero;// set speed in case we overshot - - // stop sound, we're done - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), - 0, 0, SND_STOP, m_pitch); - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - else - { - RampPitchVol(FALSE); - } -} - -void CFuncRotating :: Rotate( void ) -{ - pev->nextthink = pev->ltime + 10; -} - -//========================================================= -// Rotating Use - when a rotating brush is triggered -//========================================================= -void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // is this a brush that should accelerate and decelerate when turned on/off (fan)? - if ( FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) ) - { - // fan is spinning, so stop it. - if ( pev->avelocity != g_vecZero ) - { - SetThink ( &CFuncRotating::SpinDown ); - //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), - // m_flVolume, m_flAttenuation, 0, m_pitch); - - pev->nextthink = pev->ltime + 0.1; - } - else// fan is not moving, so start it - { - SetThink ( &CFuncRotating::SpinUp ); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - 0.01, m_flAttenuation, 0, FANPITCHMIN); - - pev->nextthink = pev->ltime + 0.1; - } - } - else if ( !FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) )//this is a normal start/stop brush. - { - if ( pev->avelocity != g_vecZero ) - { - // play stopping sound here - SetThink ( &CFuncRotating::SpinDown ); - - // EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), - // m_flVolume, m_flAttenuation, 0, m_pitch); - - pev->nextthink = pev->ltime + 0.1; - // pev->avelocity = g_vecZero; - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - m_flVolume, m_flAttenuation, 0, FANPITCHMAX); - pev->avelocity = pev->movedir * pev->speed; - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - } -} - - -// -// RotatingBlocked - An entity has blocked the brush -// -void CFuncRotating :: Blocked( CBaseEntity *pOther ) - -{ - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); -} - - - - - - -//#endif - - -class CPendulum : public CBaseEntity -{ -public: - void Spawn ( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT Swing( void ); - void EXPORT PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Stop( void ); - void Touch( CBaseEntity *pOther ); - void EXPORT RopeTouch ( CBaseEntity *pOther );// this touch func makes the pendulum a rope - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void Blocked( CBaseEntity *pOther ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_accel; // Acceleration - float m_distance; // - float m_time; - float m_damp; - float m_maxSpeed; - float m_dampSpeed; - vec3_t m_center; - vec3_t m_start; -}; - -LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ); - -TYPEDESCRIPTION CPendulum::m_SaveData[] = -{ - DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_time, FIELD_TIME ), - DEFINE_FIELD( CPendulum, m_damp, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_maxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_dampSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_center, FIELD_VECTOR ), - DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ); - - - -void CPendulum :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "distance")) - { - m_distance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damp")) - { - m_damp = atof(pkvd->szValue) * 0.001; - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CPendulum :: Spawn( void ) -{ - // set the axis of rotation - CBaseToggle :: AxisDir( pev ); - - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if ( m_distance == 0 ) - return; - - if (pev->speed == 0) - pev->speed = 100; - - m_accel = (pev->speed * pev->speed) / (2 * fabs(m_distance)); // Calculate constant acceleration from speed and distance - m_maxSpeed = pev->speed; - m_start = pev->angles; - m_center = pev->angles + (m_distance * 0.5) * pev->movedir; - - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { - SetThink( &CPendulum::SUB_CallUseToggle ); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->speed = 0; - SetUse( &CPendulum::PendulumUse ); - - if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) - { - SetTouch ( &CPendulum::RopeTouch ); - } -} - - -void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->speed ) // Pendulum is moving, stop it and auto-return if necessary - { - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) ) - { - float delta; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_start ); - - pev->avelocity = m_maxSpeed * pev->movedir; - pev->nextthink = pev->ltime + (delta / m_maxSpeed); - SetThink( &CPendulum::Stop ); - } - else - { - pev->speed = 0; // Dead stop - SetThink( NULL ); - pev->avelocity = g_vecZero; - } - } - else - { - pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving - m_time = gpGlobals->time; // Save time to calculate dt - SetThink( &CPendulum::Swing ); - m_dampSpeed = m_maxSpeed; - } -} - - -void CPendulum :: Stop( void ) -{ - pev->angles = m_start; - pev->speed = 0; - SetThink( NULL ); - pev->avelocity = g_vecZero; -} - - -void CPendulum::Blocked( CBaseEntity *pOther ) -{ - m_time = gpGlobals->time; -} - - -void CPendulum :: Swing( void ) -{ - float delta, dt; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_center ); - dt = gpGlobals->time - m_time; // How much time has passed? - m_time = gpGlobals->time; // Remember the last time called - - if ( delta > 0 && m_accel > 0 ) - pev->speed -= m_accel * dt; // Integrate velocity - else - pev->speed += m_accel * dt; - - if ( pev->speed > m_maxSpeed ) - pev->speed = m_maxSpeed; - else if ( pev->speed < -m_maxSpeed ) - pev->speed = -m_maxSpeed; - // scale the destdelta vector by the time spent traveling to get velocity - pev->avelocity = pev->speed * pev->movedir; - - // Call this again - pev->nextthink = pev->ltime + 0.1; - - if ( m_damp ) - { - m_dampSpeed -= m_damp * m_dampSpeed * dt; - if ( m_dampSpeed < 30.0 ) - { - pev->angles = m_center; - pev->speed = 0; - SetThink( NULL ); - pev->avelocity = g_vecZero; - } - else if ( pev->speed > m_dampSpeed ) - pev->speed = m_dampSpeed; - else if ( pev->speed < -m_dampSpeed ) - pev->speed = -m_dampSpeed; - - } -} - - -void CPendulum :: Touch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( pev->dmg <= 0 ) - return; - - // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) - return; - - // calculate damage based on rotation speed - float damage = pev->dmg * pev->speed * 0.01; - - if ( damage < 0 ) - damage = -damage; - - pOther->TakeDamage( pev, pev, damage, DMG_CRUSH ); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * damage; -} - -void CPendulum :: RopeTouch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( !pOther->IsPlayer() ) - {// not a player! - ALERT ( at_console, "Not a client\n" ); - return; - } - - if ( ENT(pevOther) == pev->enemy ) - {// this player already on the rope. - return; - } - - pev->enemy = pOther->edict(); - pevOther->velocity = g_vecZero; - pevOther->movetype = MOVETYPE_NONE; -} - - diff --git a/main/source/dlls/bullsquid.cpp b/main/source/dlls/bullsquid.cpp index fad94582..85d21a9f 100644 --- a/main/source/dlls/bullsquid.cpp +++ b/main/source/dlls/bullsquid.cpp @@ -1,1276 +1,1276 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// bullsquid - big, spotty tentacle-mouthed meanie. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "nodes.h" -#include "effects.h" -#include "decals.h" -#include "soundent.h" -#include "game.h" - -#define SQUID_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve - -int iSquidSpitSprite; - - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_SQUID_HURTHOP = LAST_COMMON_SCHEDULE + 1, - SCHED_SQUID_SMELLFOOD, - SCHED_SQUID_SEECRAB, - SCHED_SQUID_EAT, - SCHED_SQUID_SNIFF_AND_EAT, - SCHED_SQUID_WALLOW, -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_SQUID_HOPTURN = LAST_COMMON_TASK + 1, -}; - -//========================================================= -// Bullsquid's spit projectile -//========================================================= -class CSquidSpit : public CBaseEntity -{ -public: - void Spawn( void ); - - static void Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - void Touch( CBaseEntity *pOther ); - void EXPORT Animate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ); - -TYPEDESCRIPTION CSquidSpit::m_SaveData[] = -{ - DEFINE_FIELD( CSquidSpit, m_maxFrame, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ); - -void CSquidSpit:: Spawn( void ) -{ - pev->movetype = MOVETYPE_FLY; - pev->classname = MAKE_STRING( "squidspit" ); - - pev->solid = SOLID_BBOX; - pev->rendermode = kRenderTransAlpha; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/bigspit.spr"); - pev->frame = 0; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; -} - -void CSquidSpit::Animate( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( pev->frame++ ) - { - if ( pev->frame > m_maxFrame ) - { - pev->frame = 0; - } - } -} - -void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CSquidSpit *pSpit = GetClassPtr( (CSquidSpit *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = ENT(pevOwner); - - pSpit->SetThink ( &CSquidSpit::Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; -} - -void CSquidSpit :: Touch ( CBaseEntity *pOther ) -{ - TraceResult tr; - int iPitch; - - // splat sound - iPitch = RANDOM_FLOAT( 90, 110 ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - if ( !pOther->pev->takedamage ) - { - - // make a splat on the wall - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); - UTIL_DecalTrace(&tr, DECAL_SPIT1 + RANDOM_LONG(0,1)); - - // make some flecks - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( tr.vecEndPos.x); // pos - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_COORD( tr.vecPlaneNormal.x); // dir - WRITE_COORD( tr.vecPlaneNormal.y); - WRITE_COORD( tr.vecPlaneNormal.z); - WRITE_SHORT( iSquidSpitSprite ); // model - WRITE_BYTE ( 5 ); // count - WRITE_BYTE ( 30 ); // speed - WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) - MESSAGE_END(); - } - else - { - pOther->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); - } - - SetThink ( &CSquidSpit::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BSQUID_AE_SPIT ( 1 ) -#define BSQUID_AE_BITE ( 2 ) -#define BSQUID_AE_BLINK ( 3 ) -#define BSQUID_AE_TAILWHIP ( 4 ) -#define BSQUID_AE_HOP ( 5 ) -#define BSQUID_AE_THROW ( 6 ) - -class CBullsquid : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void IdleSound( void ); - void PainSound( void ); - void DeathSound( void ); - void AlertSound ( void ); - void AttackSound( void ); - void StartTask ( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckMeleeAttack2 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - void RunAI( void ); - BOOL FValidateHintType ( short sHint ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - int IRelationship ( CBaseEntity *pTarget ); - int IgnoreConditions ( void ); - MONSTERSTATE GetIdealState ( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CUSTOM_SCHEDULES; - static TYPEDESCRIPTION m_SaveData[]; - - BOOL m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time. - - float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while. - float m_flNextSpitTime;// last time the bullsquid used the spit attack. -}; -LINK_ENTITY_TO_CLASS( monster_bullchicken, CBullsquid ); - -TYPEDESCRIPTION CBullsquid::m_SaveData[] = -{ - DEFINE_FIELD( CBullsquid, m_fCanThreatDisplay, FIELD_BOOLEAN ), - DEFINE_FIELD( CBullsquid, m_flLastHurtTime, FIELD_TIME ), - DEFINE_FIELD( CBullsquid, m_flNextSpitTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CBullsquid, CBaseMonster ); - -//========================================================= -// IgnoreConditions -//========================================================= -int CBullsquid::IgnoreConditions ( void ) -{ - int iIgnore = CBaseMonster::IgnoreConditions(); - - if ( gpGlobals->time - m_flLastHurtTime <= 20 ) - { - // haven't been hurt in 20 seconds, so let the squid care about stink. - iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; - } - - if ( m_hEnemy != NULL ) - { - if ( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) - { - // (Unless after a tasty headcrab) - iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; - } - } - - - return iIgnore; -} - -//========================================================= -// IRelationship - overridden for bullsquid so that it can -// be made to ignore its love of headcrabs for a while. -//========================================================= -int CBullsquid::IRelationship ( CBaseEntity *pTarget ) -{ - if ( gpGlobals->time - m_flLastHurtTime < 5 && FClassnameIs ( pTarget->pev, "monster_headcrab" ) ) - { - // if squid has been hurt in the last 5 seconds, and is getting relationship for a headcrab, - // tell squid to disregard crab. - return R_NO; - } - - return CBaseMonster :: IRelationship ( pTarget ); -} - -//========================================================= -// TakeDamage - overridden for bullsquid so we can keep track -// of how much time has passed since it was last injured -//========================================================= -int CBullsquid :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flDist; - Vector vecApex; - - // if the squid is running, has an enemy, was hurt by the enemy, hasn't been hurt in the last 3 seconds, and isn't too close to the enemy, - // it will swerve. (whew). - if ( m_hEnemy != NULL && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) - { - flDist = ( pev->origin - m_hEnemy->pev->origin ).Length2D(); - - if ( flDist > SQUID_SPRINT_DIST ) - { - flDist = ( pev->origin - m_Route[ m_iRouteIndex ].vecLocation ).Length2D();// reusing flDist. - - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist * 0.5, m_hEnemy, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR | bits_MF_DONT_SIMPLIFY ); - } - } - } - - if ( !FClassnameIs ( pevAttacker, "monster_headcrab" ) ) - { - // don't forget about headcrabs if it was a headcrab that hurt the squid. - m_flLastHurtTime = gpGlobals->time; - } - - return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBullsquid :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( IsMoving() && flDist >= 512 ) - { - // squid will far too far behind if he stops running to spit at this distance from the enemy. - return FALSE; - } - - if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime ) - { - if ( m_hEnemy != NULL ) - { - if ( fabs( pev->origin.z - m_hEnemy->pev->origin.z ) > 256 ) - { - // don't try to spit at someone up really high or down really low. - return FALSE; - } - } - - if ( IsMoving() ) - { - // don't spit again for a long time, resume chasing enemy. - m_flNextSpitTime = gpGlobals->time + 5; - } - else - { - // not moving, so spit again pretty soon. - m_flNextSpitTime = gpGlobals->time + 0.5; - } - - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckMeleeAttack1 - bullsquid is a big guy, so has a longer -// melee range than most monsters. This is the tailwhip attack -//========================================================= -BOOL CBullsquid :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( m_hEnemy->pev->health <= gSkillData.bullsquidDmgWhip && flDist <= 85 && flDot >= 0.7 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack2 - bullsquid is a big guy, so has a longer -// melee range than most monsters. This is the bite attack. -// this attack will not be performed if the tailwhip attack -// is valid. -//========================================================= -BOOL CBullsquid :: CheckMeleeAttack2 ( float flDot, float flDist ) -{ - if ( flDist <= 85 && flDot >= 0.7 && !HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) // The player & bullsquid can be as much as their bboxes - { // apart (48 * sqrt(3)) and he can still attack (85 is a little more than 48*sqrt(3)) - return TRUE; - } - return FALSE; -} - -//========================================================= -// FValidateHintType -//========================================================= -BOOL CBullsquid :: FValidateHintType ( short sHint ) -{ - int i; - - static short sSquidHints[] = - { - HINT_WORLD_HUMAN_BLOOD, - }; - - for ( i = 0 ; i < ARRAYSIZE ( sSquidHints ) ; i++ ) - { - if ( sSquidHints[ i ] == sHint ) - { - return TRUE; - } - } - - ALERT ( at_aiconsole, "Couldn't validate hint type" ); - return FALSE; -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CBullsquid :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBullsquid :: Classify ( void ) -{ - return CLASS_ALIEN_PREDATOR; -} - -//========================================================= -// IdleSound -//========================================================= -#define SQUID_ATTN_IDLE (float)1.5 -void CBullsquid :: IdleSound ( void ) -{ - switch ( RANDOM_LONG(0,4) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, SQUID_ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, SQUID_ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle3.wav", 1, SQUID_ATTN_IDLE ); - break; - case 3: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle4.wav", 1, SQUID_ATTN_IDLE ); - break; - case 4: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle5.wav", 1, SQUID_ATTN_IDLE ); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CBullsquid :: PainSound ( void ) -{ - int iPitch = RANDOM_LONG( 85, 120 ); - - switch ( RANDOM_LONG(0,3) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 2: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain3.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 3: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain4.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CBullsquid :: AlertSound ( void ) -{ - int iPitch = RANDOM_LONG( 140, 160 ); - - switch ( RANDOM_LONG ( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBullsquid :: SetYawSpeed ( void ) -{ - int ys; - - ys = 0; - - switch ( m_Activity ) - { - case ACT_WALK: ys = 90; break; - case ACT_RUN: ys = 90; break; - case ACT_IDLE: ys = 90; break; - case ACT_RANGE_ATTACK1: ys = 90; break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BSQUID_AE_SPIT: - { - Vector vecSpitOffset; - Vector vecSpitDir; - - UTIL_MakeVectors ( pev->angles ); - - // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. - // we should be able to read the position of bones at runtime for this info. - vecSpitOffset = ( gpGlobals->v_right * 8 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 23 ); - vecSpitOffset = ( pev->origin + vecSpitOffset ); - vecSpitDir = ( ( m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs ) - vecSpitOffset ).Normalize(); - - vecSpitDir.x += RANDOM_FLOAT( -0.05, 0.05 ); - vecSpitDir.y += RANDOM_FLOAT( -0.05, 0.05 ); - vecSpitDir.z += RANDOM_FLOAT( -0.05, 0 ); - - - // do stuff for this event. - AttackSound(); - - // spew the spittle temporary ents. - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpitOffset ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( vecSpitOffset.x); // pos - WRITE_COORD( vecSpitOffset.y); - WRITE_COORD( vecSpitOffset.z); - WRITE_COORD( vecSpitDir.x); // dir - WRITE_COORD( vecSpitDir.y); - WRITE_COORD( vecSpitDir.z); - WRITE_SHORT( iSquidSpitSprite ); // model - WRITE_BYTE ( 15 ); // count - WRITE_BYTE ( 210 ); // speed - WRITE_BYTE ( 25 ); // noise ( client will divide by 100 ) - MESSAGE_END(); - - CSquidSpit::Shoot( pev, vecSpitOffset, vecSpitDir * 900 ); - } - break; - - case BSQUID_AE_BITE: - { - // SOUND HERE! - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgBite, DMG_SLASH ); - - if ( pHurt ) - { - //pHurt->pev->punchangle.z = -15; - //pHurt->pev->punchangle.x = -45; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 100; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; - } - } - break; - - case BSQUID_AE_TAILWHIP: - { - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgWhip, DMG_CLUB | DMG_ALWAYSGIB ); - if ( pHurt ) - { - pHurt->pev->punchangle.z = -20; - pHurt->pev->punchangle.x = 20; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 200; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; - } - } - break; - - case BSQUID_AE_BLINK: - { - // close eye. - pev->skin = 1; - } - break; - - case BSQUID_AE_HOP: - { - float flGravity = g_psv_gravity->value; - - // throw the squid up into the air on this frame. - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - pev->flags -= FL_ONGROUND; - } - - // jump into air for 0.8 (24/30) seconds -// pev->velocity.z += (0.875 * flGravity) * 0.5; - pev->velocity.z += (0.625 * flGravity) * 0.5; - } - break; - - case BSQUID_AE_THROW: - { - int iPitch; - - // squid throws its prey IF the prey is a client. - float theDamage = 0; - CBaseEntity *pHurt = CheckTraceHullAttack( 70, theDamage, 0 ); - - - if ( pHurt ) - { - // croonchy bite sound - iPitch = RANDOM_FLOAT( 90, 110 ); - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite3.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - - //pHurt->pev->punchangle.x = RANDOM_LONG(0,34) - 5; - //pHurt->pev->punchangle.z = RANDOM_LONG(0,49) - 25; - //pHurt->pev->punchangle.y = RANDOM_LONG(0,89) - 45; - - // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. - UTIL_ScreenShake( pHurt->pev->origin, 25.0, 1.5, 0.7, 2 ); - - if ( pHurt->IsPlayer() ) - { - UTIL_MakeVectors( pev->angles ); - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 300 + gpGlobals->v_up * 300; - } - } - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBullsquid :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/bullsquid.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.bullsquidHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - m_fCanThreatDisplay = TRUE; - m_flNextSpitTime = gpGlobals->time; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBullsquid :: Precache() -{ - PRECACHE_MODEL("models/bullsquid.mdl"); - - PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile. - - iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle. - - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event - - PRECACHE_SOUND("bullchicken/bc_attack2.wav"); - PRECACHE_SOUND("bullchicken/bc_attack3.wav"); - - PRECACHE_SOUND("bullchicken/bc_die1.wav"); - PRECACHE_SOUND("bullchicken/bc_die2.wav"); - PRECACHE_SOUND("bullchicken/bc_die3.wav"); - - PRECACHE_SOUND("bullchicken/bc_idle1.wav"); - PRECACHE_SOUND("bullchicken/bc_idle2.wav"); - PRECACHE_SOUND("bullchicken/bc_idle3.wav"); - PRECACHE_SOUND("bullchicken/bc_idle4.wav"); - PRECACHE_SOUND("bullchicken/bc_idle5.wav"); - - PRECACHE_SOUND("bullchicken/bc_pain1.wav"); - PRECACHE_SOUND("bullchicken/bc_pain2.wav"); - PRECACHE_SOUND("bullchicken/bc_pain3.wav"); - PRECACHE_SOUND("bullchicken/bc_pain4.wav"); - - PRECACHE_SOUND("bullchicken/bc_attackgrowl.wav"); - PRECACHE_SOUND("bullchicken/bc_attackgrowl2.wav"); - PRECACHE_SOUND("bullchicken/bc_attackgrowl3.wav"); - - PRECACHE_SOUND("bullchicken/bc_acid1.wav"); - - PRECACHE_SOUND("bullchicken/bc_bite2.wav"); - PRECACHE_SOUND("bullchicken/bc_bite3.wav"); - - PRECACHE_SOUND("bullchicken/bc_spithit1.wav"); - PRECACHE_SOUND("bullchicken/bc_spithit2.wav"); - -} - -//========================================================= -// DeathSound -//========================================================= -void CBullsquid :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// AttackSound -//========================================================= -void CBullsquid :: AttackSound ( void ) -{ - switch ( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM ); - break; - } -} - - -//======================================================== -// RunAI - overridden for bullsquid because there are things -// that need to be checked every think. -//======================================================== -void CBullsquid :: RunAI ( void ) -{ - // first, do base class stuff - CBaseMonster :: RunAI(); - - if ( pev->skin != 0 ) - { - // close eye if it was open. - pev->skin = 0; - } - - if ( RANDOM_LONG(0,39) == 0 ) - { - pev->skin = 1; - } - - if ( m_hEnemy != NULL && m_Activity == ACT_RUN ) - { - // chasing enemy. Sprint for last bit - if ( (pev->origin - m_hEnemy->pev->origin).Length2D() < SQUID_SPRINT_DIST ) - { - pev->framerate = 1.25; - } - } - -} - -//======================================================== -// AI Schedules Specific to this monster -//========================================================= - -// primary range attack -Task_t tlSquidRangeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slSquidRangeAttack1[] = -{ - { - tlSquidRangeAttack1, - ARRAYSIZE ( tlSquidRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "Squid Range Attack1" - }, -}; - -// Chase enemy schedule -Task_t tlSquidChaseEnemy1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 },// !!!OEM - this will stop nasty squid oscillation. - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slSquidChaseEnemy[] = -{ - { - tlSquidChaseEnemy1, - ARRAYSIZE ( tlSquidChaseEnemy1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_SMELL_FOOD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_TASK_FAILED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_MEAT, - "Squid Chase Enemy" - }, -}; - -Task_t tlSquidHurtHop[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_SQUID_HOPTURN, (float)0 }, - { TASK_FACE_ENEMY, (float)0 },// in case squid didn't turn all the way in the air. -}; - -Schedule_t slSquidHurtHop[] = -{ - { - tlSquidHurtHop, - ARRAYSIZE ( tlSquidHurtHop ), - 0, - 0, - "SquidHurtHop" - } -}; - -Task_t tlSquidSeeCrab[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EXCITED }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slSquidSeeCrab[] = -{ - { - tlSquidSeeCrab, - ARRAYSIZE ( tlSquidSeeCrab ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "SquidSeeCrab" - } -}; - -// squid walks to something tasty and eats it. -Task_t tlSquidEat[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the food - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_EAT, (float)50 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidEat[] = -{ - { - tlSquidEat, - ARRAYSIZE( tlSquidEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_MEAT | - bits_SOUND_CARCASS, - "SquidEat" - } -}; - -// this is a bit different than just Eat. We use this schedule when the food is far away, occluded, or behind -// the squid. This schedule plays a sniff animation before going to the source of food. -Task_t tlSquidSniffAndEat[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the food - { TASK_PLAY_SEQUENCE, (float)ACT_DETECT_SCENT }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_EAT, (float)50 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidSniffAndEat[] = -{ - { - tlSquidSniffAndEat, - ARRAYSIZE( tlSquidSniffAndEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_MEAT | - bits_SOUND_CARCASS, - "SquidSniffAndEat" - } -}; - -// squid does this to stinky things. -Task_t tlSquidWallow[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the stinkiness - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_INSPECT_FLOOR}, - { TASK_EAT, (float)50 },// keeps squid from eating or sniffing anything else for a while. - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidWallow[] = -{ - { - tlSquidWallow, - ARRAYSIZE( tlSquidWallow ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_GARBAGE, - - "SquidWallow" - } -}; - -DEFINE_CUSTOM_SCHEDULES( CBullsquid ) -{ - slSquidRangeAttack1, - slSquidChaseEnemy, - slSquidHurtHop, - slSquidSeeCrab, - slSquidEat, - slSquidSniffAndEat, - slSquidWallow -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ); - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t *CBullsquid :: GetSchedule( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - { - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) - { - return GetScheduleOfType ( SCHED_SQUID_HURTHOP ); - } - - if ( HasConditions(bits_COND_SMELL_FOOD) ) - { - CSound *pSound; - - pSound = PBestScent(); - - if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) - { - // scent is behind or occluded - return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); - } - - // food is right out in the open. Just go get it. - return GetScheduleOfType( SCHED_SQUID_EAT ); - } - - if ( HasConditions(bits_COND_SMELL) ) - { - // there's something stinky. - CSound *pSound; - - pSound = PBestScent(); - if ( pSound ) - return GetScheduleOfType( SCHED_SQUID_WALLOW); - } - - break; - } - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - if ( m_fCanThreatDisplay && IRelationship( m_hEnemy ) == R_HT ) - { - // this means squid sees a headcrab! - m_fCanThreatDisplay = FALSE;// only do the headcrab dance once per lifetime. - return GetScheduleOfType ( SCHED_SQUID_SEECRAB ); - } - else - { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); - } - } - - if ( HasConditions(bits_COND_SMELL_FOOD) ) - { - CSound *pSound; - - pSound = PBestScent(); - - if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) - { - // scent is behind or occluded - return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); - } - - // food is right out in the open. Just go get it. - return GetScheduleOfType( SCHED_SQUID_EAT ); - } - - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } - - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK2 ); - } - - return GetScheduleOfType ( SCHED_CHASE_ENEMY ); - - break; - } - } - - return CBaseMonster :: GetSchedule(); -} - -//========================================================= -// GetScheduleOfType -//========================================================= -Schedule_t* CBullsquid :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_RANGE_ATTACK1: - return &slSquidRangeAttack1[ 0 ]; - break; - case SCHED_SQUID_HURTHOP: - return &slSquidHurtHop[ 0 ]; - break; - case SCHED_SQUID_SEECRAB: - return &slSquidSeeCrab[ 0 ]; - break; - case SCHED_SQUID_EAT: - return &slSquidEat[ 0 ]; - break; - case SCHED_SQUID_SNIFF_AND_EAT: - return &slSquidSniffAndEat[ 0 ]; - break; - case SCHED_SQUID_WALLOW: - return &slSquidWallow[ 0 ]; - break; - case SCHED_CHASE_ENEMY: - return &slSquidChaseEnemy[ 0 ]; - break; - } - - return CBaseMonster :: GetScheduleOfType ( Type ); -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. OVERRIDDEN for bullsquid because it needs to -// know explicitly when the last attempt to chase the enemy -// failed, since that impacts its attack choices. -//========================================================= -void CBullsquid :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_MELEE_ATTACK2: - { - switch ( RANDOM_LONG ( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl3.wav", 1, ATTN_NORM ); - break; - } - - CBaseMonster :: StartTask ( pTask ); - break; - } - case TASK_SQUID_HOPTURN: - { - SetActivity ( ACT_HOP ); - MakeIdealYaw ( m_vecEnemyLKP ); - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - if ( BuildRoute ( m_hEnemy->pev->origin, bits_MF_TO_ENEMY, m_hEnemy ) ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - default: - { - CBaseMonster :: StartTask ( pTask ); - break; - } - } -} - -//========================================================= -// RunTask -//========================================================= -void CBullsquid :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_SQUID_HOPTURN: - { - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CBaseMonster :: RunTask( pTask ); - break; - } - } -} - - -//========================================================= -// GetIdealState - Overridden for Bullsquid to deal with -// the feature that makes it lose interest in headcrabs for -// a while if something injures it. -//========================================================= -MONSTERSTATE CBullsquid :: GetIdealState ( void ) -{ - int iConditions; - - iConditions = IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - /* - COMBAT goes to ALERT upon death of enemy - */ - { - if ( m_hEnemy != NULL && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) - { - // if the squid has a headcrab enemy and something hurts it, it's going to forget about the crab for a while. - m_hEnemy = NULL; - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - break; - } - } - - m_IdealMonsterState = CBaseMonster :: GetIdealState(); - - return m_IdealMonsterState; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// bullsquid - big, spotty tentacle-mouthed meanie. +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "nodes.h" +#include "effects.h" +#include "decals.h" +#include "soundent.h" +#include "game.h" + +#define SQUID_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve + +int iSquidSpitSprite; + + +//========================================================= +// monster-specific schedule types +//========================================================= +enum +{ + SCHED_SQUID_HURTHOP = LAST_COMMON_SCHEDULE + 1, + SCHED_SQUID_SMELLFOOD, + SCHED_SQUID_SEECRAB, + SCHED_SQUID_EAT, + SCHED_SQUID_SNIFF_AND_EAT, + SCHED_SQUID_WALLOW, +}; + +//========================================================= +// monster-specific tasks +//========================================================= +enum +{ + TASK_SQUID_HOPTURN = LAST_COMMON_TASK + 1, +}; + +//========================================================= +// Bullsquid's spit projectile +//========================================================= +class CSquidSpit : public CBaseEntity +{ +public: + void Spawn( void ); + + static void Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + void Touch( CBaseEntity *pOther ); + void EXPORT Animate( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_maxFrame; +}; + +LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ); + +TYPEDESCRIPTION CSquidSpit::m_SaveData[] = +{ + DEFINE_FIELD( CSquidSpit, m_maxFrame, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ); + +void CSquidSpit:: Spawn( void ) +{ + pev->movetype = MOVETYPE_FLY; + pev->classname = MAKE_STRING( "squidspit" ); + + pev->solid = SOLID_BBOX; + pev->rendermode = kRenderTransAlpha; + pev->renderamt = 255; + + SET_MODEL(ENT(pev), "sprites/bigspit.spr"); + pev->frame = 0; + pev->scale = 0.5; + + UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); + + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; +} + +void CSquidSpit::Animate( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if ( pev->frame++ ) + { + if ( pev->frame > m_maxFrame ) + { + pev->frame = 0; + } + } +} + +void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) +{ + CSquidSpit *pSpit = GetClassPtr( (CSquidSpit *)NULL ); + pSpit->Spawn(); + + UTIL_SetOrigin( pSpit->pev, vecStart ); + pSpit->pev->velocity = vecVelocity; + pSpit->pev->owner = ENT(pevOwner); + + pSpit->SetThink ( &CSquidSpit::Animate ); + pSpit->pev->nextthink = gpGlobals->time + 0.1; +} + +void CSquidSpit :: Touch ( CBaseEntity *pOther ) +{ + TraceResult tr; + int iPitch; + + // splat sound + iPitch = RANDOM_FLOAT( 90, 110 ); + + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); + + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 1: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); + break; + } + + if ( !pOther->pev->takedamage ) + { + + // make a splat on the wall + UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); + UTIL_DecalTrace(&tr, DECAL_SPIT1 + RANDOM_LONG(0,1)); + + // make some flecks + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); + WRITE_BYTE( TE_SPRITE_SPRAY ); + WRITE_COORD( tr.vecEndPos.x); // pos + WRITE_COORD( tr.vecEndPos.y); + WRITE_COORD( tr.vecEndPos.z); + WRITE_COORD( tr.vecPlaneNormal.x); // dir + WRITE_COORD( tr.vecPlaneNormal.y); + WRITE_COORD( tr.vecPlaneNormal.z); + WRITE_SHORT( iSquidSpitSprite ); // model + WRITE_BYTE ( 5 ); // count + WRITE_BYTE ( 30 ); // speed + WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) + MESSAGE_END(); + } + else + { + pOther->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); + } + + SetThink ( &CSquidSpit::SUB_Remove ); + pev->nextthink = gpGlobals->time; +} + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define BSQUID_AE_SPIT ( 1 ) +#define BSQUID_AE_BITE ( 2 ) +#define BSQUID_AE_BLINK ( 3 ) +#define BSQUID_AE_TAILWHIP ( 4 ) +#define BSQUID_AE_HOP ( 5 ) +#define BSQUID_AE_THROW ( 6 ) + +class CBullsquid : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int ISoundMask( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void IdleSound( void ); + void PainSound( void ); + void DeathSound( void ); + void AlertSound ( void ); + void AttackSound( void ); + void StartTask ( Task_t *pTask ); + void RunTask ( Task_t *pTask ); + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); + BOOL CheckMeleeAttack2 ( float flDot, float flDist ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + void RunAI( void ); + BOOL FValidateHintType ( short sHint ); + Schedule_t *GetSchedule( void ); + Schedule_t *GetScheduleOfType ( int Type ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + int IRelationship ( CBaseEntity *pTarget ); + int IgnoreConditions ( void ); + MONSTERSTATE GetIdealState ( void ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + + CUSTOM_SCHEDULES; + static TYPEDESCRIPTION m_SaveData[]; + + BOOL m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time. + + float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while. + float m_flNextSpitTime;// last time the bullsquid used the spit attack. +}; +LINK_ENTITY_TO_CLASS( monster_bullchicken, CBullsquid ); + +TYPEDESCRIPTION CBullsquid::m_SaveData[] = +{ + DEFINE_FIELD( CBullsquid, m_fCanThreatDisplay, FIELD_BOOLEAN ), + DEFINE_FIELD( CBullsquid, m_flLastHurtTime, FIELD_TIME ), + DEFINE_FIELD( CBullsquid, m_flNextSpitTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CBullsquid, CBaseMonster ); + +//========================================================= +// IgnoreConditions +//========================================================= +int CBullsquid::IgnoreConditions ( void ) +{ + int iIgnore = CBaseMonster::IgnoreConditions(); + + if ( gpGlobals->time - m_flLastHurtTime <= 20 ) + { + // haven't been hurt in 20 seconds, so let the squid care about stink. + iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; + } + + if ( m_hEnemy != NULL ) + { + if ( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) + { + // (Unless after a tasty headcrab) + iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; + } + } + + + return iIgnore; +} + +//========================================================= +// IRelationship - overridden for bullsquid so that it can +// be made to ignore its love of headcrabs for a while. +//========================================================= +int CBullsquid::IRelationship ( CBaseEntity *pTarget ) +{ + if ( gpGlobals->time - m_flLastHurtTime < 5 && FClassnameIs ( pTarget->pev, "monster_headcrab" ) ) + { + // if squid has been hurt in the last 5 seconds, and is getting relationship for a headcrab, + // tell squid to disregard crab. + return R_NO; + } + + return CBaseMonster :: IRelationship ( pTarget ); +} + +//========================================================= +// TakeDamage - overridden for bullsquid so we can keep track +// of how much time has passed since it was last injured +//========================================================= +int CBullsquid :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + float flDist; + Vector vecApex; + + // if the squid is running, has an enemy, was hurt by the enemy, hasn't been hurt in the last 3 seconds, and isn't too close to the enemy, + // it will swerve. (whew). + if ( m_hEnemy != NULL && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) + { + flDist = ( pev->origin - m_hEnemy->pev->origin ).Length2D(); + + if ( flDist > SQUID_SPRINT_DIST ) + { + flDist = ( pev->origin - m_Route[ m_iRouteIndex ].vecLocation ).Length2D();// reusing flDist. + + if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist * 0.5, m_hEnemy, &vecApex ) ) + { + InsertWaypoint( vecApex, bits_MF_TO_DETOUR | bits_MF_DONT_SIMPLIFY ); + } + } + } + + if ( !FClassnameIs ( pevAttacker, "monster_headcrab" ) ) + { + // don't forget about headcrabs if it was a headcrab that hurt the squid. + m_flLastHurtTime = gpGlobals->time; + } + + return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +//========================================================= +// CheckRangeAttack1 +//========================================================= +BOOL CBullsquid :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( IsMoving() && flDist >= 512 ) + { + // squid will far too far behind if he stops running to spit at this distance from the enemy. + return FALSE; + } + + if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime ) + { + if ( m_hEnemy != NULL ) + { + if ( fabs( pev->origin.z - m_hEnemy->pev->origin.z ) > 256 ) + { + // don't try to spit at someone up really high or down really low. + return FALSE; + } + } + + if ( IsMoving() ) + { + // don't spit again for a long time, resume chasing enemy. + m_flNextSpitTime = gpGlobals->time + 5; + } + else + { + // not moving, so spit again pretty soon. + m_flNextSpitTime = gpGlobals->time + 0.5; + } + + return TRUE; + } + + return FALSE; +} + +//========================================================= +// CheckMeleeAttack1 - bullsquid is a big guy, so has a longer +// melee range than most monsters. This is the tailwhip attack +//========================================================= +BOOL CBullsquid :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + if ( m_hEnemy->pev->health <= gSkillData.bullsquidDmgWhip && flDist <= 85 && flDot >= 0.7 ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckMeleeAttack2 - bullsquid is a big guy, so has a longer +// melee range than most monsters. This is the bite attack. +// this attack will not be performed if the tailwhip attack +// is valid. +//========================================================= +BOOL CBullsquid :: CheckMeleeAttack2 ( float flDot, float flDist ) +{ + if ( flDist <= 85 && flDot >= 0.7 && !HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) // The player & bullsquid can be as much as their bboxes + { // apart (48 * sqrt(3)) and he can still attack (85 is a little more than 48*sqrt(3)) + return TRUE; + } + return FALSE; +} + +//========================================================= +// FValidateHintType +//========================================================= +BOOL CBullsquid :: FValidateHintType ( short sHint ) +{ + int i; + + static short sSquidHints[] = + { + HINT_WORLD_HUMAN_BLOOD, + }; + + for ( i = 0 ; i < ARRAYSIZE ( sSquidHints ) ; i++ ) + { + if ( sSquidHints[ i ] == sHint ) + { + return TRUE; + } + } + + ALERT ( at_aiconsole, "Couldn't validate hint type" ); + return FALSE; +} + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. In the base class implementation, +// monsters care about all sounds, but no scents. +//========================================================= +int CBullsquid :: ISoundMask ( void ) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_CARCASS | + bits_SOUND_MEAT | + bits_SOUND_GARBAGE | + bits_SOUND_PLAYER; +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CBullsquid :: Classify ( void ) +{ + return CLASS_ALIEN_PREDATOR; +} + +//========================================================= +// IdleSound +//========================================================= +#define SQUID_ATTN_IDLE (float)1.5 +void CBullsquid :: IdleSound ( void ) +{ + switch ( RANDOM_LONG(0,4) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, SQUID_ATTN_IDLE ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, SQUID_ATTN_IDLE ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle3.wav", 1, SQUID_ATTN_IDLE ); + break; + case 3: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle4.wav", 1, SQUID_ATTN_IDLE ); + break; + case 4: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle5.wav", 1, SQUID_ATTN_IDLE ); + break; + } +} + +//========================================================= +// PainSound +//========================================================= +void CBullsquid :: PainSound ( void ) +{ + int iPitch = RANDOM_LONG( 85, 120 ); + + switch ( RANDOM_LONG(0,3) ) + { + case 0: + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain1.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 1: + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain2.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 2: + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain3.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 3: + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain4.wav", 1, ATTN_NORM, 0, iPitch ); + break; + } +} + +//========================================================= +// AlertSound +//========================================================= +void CBullsquid :: AlertSound ( void ) +{ + int iPitch = RANDOM_LONG( 140, 160 ); + + switch ( RANDOM_LONG ( 0, 1 ) ) + { + case 0: + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 1: + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, ATTN_NORM, 0, iPitch ); + break; + } +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CBullsquid :: SetYawSpeed ( void ) +{ + int ys; + + ys = 0; + + switch ( m_Activity ) + { + case ACT_WALK: ys = 90; break; + case ACT_RUN: ys = 90; break; + case ACT_IDLE: ys = 90; break; + case ACT_RANGE_ATTACK1: ys = 90; break; + default: + ys = 90; + break; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case BSQUID_AE_SPIT: + { + Vector vecSpitOffset; + Vector vecSpitDir; + + UTIL_MakeVectors ( pev->angles ); + + // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. + // we should be able to read the position of bones at runtime for this info. + vecSpitOffset = ( gpGlobals->v_right * 8 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 23 ); + vecSpitOffset = ( pev->origin + vecSpitOffset ); + vecSpitDir = ( ( m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs ) - vecSpitOffset ).Normalize(); + + vecSpitDir.x += RANDOM_FLOAT( -0.05, 0.05 ); + vecSpitDir.y += RANDOM_FLOAT( -0.05, 0.05 ); + vecSpitDir.z += RANDOM_FLOAT( -0.05, 0 ); + + + // do stuff for this event. + AttackSound(); + + // spew the spittle temporary ents. + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpitOffset ); + WRITE_BYTE( TE_SPRITE_SPRAY ); + WRITE_COORD( vecSpitOffset.x); // pos + WRITE_COORD( vecSpitOffset.y); + WRITE_COORD( vecSpitOffset.z); + WRITE_COORD( vecSpitDir.x); // dir + WRITE_COORD( vecSpitDir.y); + WRITE_COORD( vecSpitDir.z); + WRITE_SHORT( iSquidSpitSprite ); // model + WRITE_BYTE ( 15 ); // count + WRITE_BYTE ( 210 ); // speed + WRITE_BYTE ( 25 ); // noise ( client will divide by 100 ) + MESSAGE_END(); + + CSquidSpit::Shoot( pev, vecSpitOffset, vecSpitDir * 900 ); + } + break; + + case BSQUID_AE_BITE: + { + // SOUND HERE! + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgBite, DMG_SLASH ); + + if ( pHurt ) + { + //pHurt->pev->punchangle.z = -15; + //pHurt->pev->punchangle.x = -45; + pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 100; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; + } + } + break; + + case BSQUID_AE_TAILWHIP: + { + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgWhip, DMG_CLUB | DMG_ALWAYSGIB ); + if ( pHurt ) + { + pHurt->pev->punchangle.z = -20; + pHurt->pev->punchangle.x = 20; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 200; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; + } + } + break; + + case BSQUID_AE_BLINK: + { + // close eye. + pev->skin = 1; + } + break; + + case BSQUID_AE_HOP: + { + float flGravity = g_psv_gravity->value; + + // throw the squid up into the air on this frame. + if ( FBitSet ( pev->flags, FL_ONGROUND ) ) + { + pev->flags -= FL_ONGROUND; + } + + // jump into air for 0.8 (24/30) seconds +// pev->velocity.z += (0.875 * flGravity) * 0.5; + pev->velocity.z += (0.625 * flGravity) * 0.5; + } + break; + + case BSQUID_AE_THROW: + { + int iPitch; + + // squid throws its prey IF the prey is a client. + float theDamage = 0; + CBaseEntity *pHurt = CheckTraceHullAttack( 70, theDamage, 0 ); + + + if ( pHurt ) + { + // croonchy bite sound + iPitch = RANDOM_FLOAT( 90, 110 ); + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 1: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite3.wav", 1, ATTN_NORM, 0, iPitch ); + break; + } + + + //pHurt->pev->punchangle.x = RANDOM_LONG(0,34) - 5; + //pHurt->pev->punchangle.z = RANDOM_LONG(0,49) - 25; + //pHurt->pev->punchangle.y = RANDOM_LONG(0,89) - 45; + + // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. + UTIL_ScreenShake( pHurt->pev->origin, 25.0, 1.5, 0.7, 2 ); + + if ( pHurt->IsPlayer() ) + { + UTIL_MakeVectors( pev->angles ); + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 300 + gpGlobals->v_up * 300; + } + } + } + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + } +} + +//========================================================= +// Spawn +//========================================================= +void CBullsquid :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/bullsquid.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->effects = 0; + pev->health = gSkillData.bullsquidHealth; + m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + m_fCanThreatDisplay = TRUE; + m_flNextSpitTime = gpGlobals->time; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CBullsquid :: Precache() +{ + PRECACHE_MODEL("models/bullsquid.mdl"); + + PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile. + + iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle. + + PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event + + PRECACHE_SOUND("bullchicken/bc_attack2.wav"); + PRECACHE_SOUND("bullchicken/bc_attack3.wav"); + + PRECACHE_SOUND("bullchicken/bc_die1.wav"); + PRECACHE_SOUND("bullchicken/bc_die2.wav"); + PRECACHE_SOUND("bullchicken/bc_die3.wav"); + + PRECACHE_SOUND("bullchicken/bc_idle1.wav"); + PRECACHE_SOUND("bullchicken/bc_idle2.wav"); + PRECACHE_SOUND("bullchicken/bc_idle3.wav"); + PRECACHE_SOUND("bullchicken/bc_idle4.wav"); + PRECACHE_SOUND("bullchicken/bc_idle5.wav"); + + PRECACHE_SOUND("bullchicken/bc_pain1.wav"); + PRECACHE_SOUND("bullchicken/bc_pain2.wav"); + PRECACHE_SOUND("bullchicken/bc_pain3.wav"); + PRECACHE_SOUND("bullchicken/bc_pain4.wav"); + + PRECACHE_SOUND("bullchicken/bc_attackgrowl.wav"); + PRECACHE_SOUND("bullchicken/bc_attackgrowl2.wav"); + PRECACHE_SOUND("bullchicken/bc_attackgrowl3.wav"); + + PRECACHE_SOUND("bullchicken/bc_acid1.wav"); + + PRECACHE_SOUND("bullchicken/bc_bite2.wav"); + PRECACHE_SOUND("bullchicken/bc_bite3.wav"); + + PRECACHE_SOUND("bullchicken/bc_spithit1.wav"); + PRECACHE_SOUND("bullchicken/bc_spithit2.wav"); + +} + +//========================================================= +// DeathSound +//========================================================= +void CBullsquid :: DeathSound ( void ) +{ + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die1.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die2.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die3.wav", 1, ATTN_NORM ); + break; + } +} + +//========================================================= +// AttackSound +//========================================================= +void CBullsquid :: AttackSound ( void ) +{ + switch ( RANDOM_LONG(0,1) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM ); + break; + } +} + + +//======================================================== +// RunAI - overridden for bullsquid because there are things +// that need to be checked every think. +//======================================================== +void CBullsquid :: RunAI ( void ) +{ + // first, do base class stuff + CBaseMonster :: RunAI(); + + if ( pev->skin != 0 ) + { + // close eye if it was open. + pev->skin = 0; + } + + if ( RANDOM_LONG(0,39) == 0 ) + { + pev->skin = 1; + } + + if ( m_hEnemy != NULL && m_Activity == ACT_RUN ) + { + // chasing enemy. Sprint for last bit + if ( (pev->origin - m_hEnemy->pev->origin).Length2D() < SQUID_SPRINT_DIST ) + { + pev->framerate = 1.25; + } + } + +} + +//======================================================== +// AI Schedules Specific to this monster +//========================================================= + +// primary range attack +Task_t tlSquidRangeAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, +}; + +Schedule_t slSquidRangeAttack1[] = +{ + { + tlSquidRangeAttack1, + ARRAYSIZE ( tlSquidRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED, + 0, + "Squid Range Attack1" + }, +}; + +// Chase enemy schedule +Task_t tlSquidChaseEnemy1[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 },// !!!OEM - this will stop nasty squid oscillation. + { TASK_GET_PATH_TO_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, +}; + +Schedule_t slSquidChaseEnemy[] = +{ + { + tlSquidChaseEnemy1, + ARRAYSIZE ( tlSquidChaseEnemy1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_SMELL_FOOD | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK2 | + bits_COND_TASK_FAILED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER | + bits_SOUND_MEAT, + "Squid Chase Enemy" + }, +}; + +Task_t tlSquidHurtHop[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SOUND_WAKE, (float)0 }, + { TASK_SQUID_HOPTURN, (float)0 }, + { TASK_FACE_ENEMY, (float)0 },// in case squid didn't turn all the way in the air. +}; + +Schedule_t slSquidHurtHop[] = +{ + { + tlSquidHurtHop, + ARRAYSIZE ( tlSquidHurtHop ), + 0, + 0, + "SquidHurtHop" + } +}; + +Task_t tlSquidSeeCrab[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SOUND_WAKE, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_EXCITED }, + { TASK_FACE_ENEMY, (float)0 }, +}; + +Schedule_t slSquidSeeCrab[] = +{ + { + tlSquidSeeCrab, + ARRAYSIZE ( tlSquidSeeCrab ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "SquidSeeCrab" + } +}; + +// squid walks to something tasty and eats it. +Task_t tlSquidEat[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_EAT, (float)10 },// this is in case the squid can't get to the food + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, + { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, + { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, + { TASK_EAT, (float)50 }, + { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_CLEAR_LASTPOSITION, (float)0 }, +}; + +Schedule_t slSquidEat[] = +{ + { + tlSquidEat, + ARRAYSIZE( tlSquidEat ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_NEW_ENEMY , + + // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask + // here or the monster won't detect these sounds at ALL while running this schedule. + bits_SOUND_MEAT | + bits_SOUND_CARCASS, + "SquidEat" + } +}; + +// this is a bit different than just Eat. We use this schedule when the food is far away, occluded, or behind +// the squid. This schedule plays a sniff animation before going to the source of food. +Task_t tlSquidSniffAndEat[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_EAT, (float)10 },// this is in case the squid can't get to the food + { TASK_PLAY_SEQUENCE, (float)ACT_DETECT_SCENT }, + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, + { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, + { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, + { TASK_EAT, (float)50 }, + { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_CLEAR_LASTPOSITION, (float)0 }, +}; + +Schedule_t slSquidSniffAndEat[] = +{ + { + tlSquidSniffAndEat, + ARRAYSIZE( tlSquidSniffAndEat ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_NEW_ENEMY , + + // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask + // here or the monster won't detect these sounds at ALL while running this schedule. + bits_SOUND_MEAT | + bits_SOUND_CARCASS, + "SquidSniffAndEat" + } +}; + +// squid does this to stinky things. +Task_t tlSquidWallow[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_EAT, (float)10 },// this is in case the squid can't get to the stinkiness + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_INSPECT_FLOOR}, + { TASK_EAT, (float)50 },// keeps squid from eating or sniffing anything else for a while. + { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_CLEAR_LASTPOSITION, (float)0 }, +}; + +Schedule_t slSquidWallow[] = +{ + { + tlSquidWallow, + ARRAYSIZE( tlSquidWallow ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_NEW_ENEMY , + + // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask + // here or the monster won't detect these sounds at ALL while running this schedule. + bits_SOUND_GARBAGE, + + "SquidWallow" + } +}; + +DEFINE_CUSTOM_SCHEDULES( CBullsquid ) +{ + slSquidRangeAttack1, + slSquidChaseEnemy, + slSquidHurtHop, + slSquidSeeCrab, + slSquidEat, + slSquidSniffAndEat, + slSquidWallow +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ); + +//========================================================= +// GetSchedule +//========================================================= +Schedule_t *CBullsquid :: GetSchedule( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_ALERT: + { + if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) + { + return GetScheduleOfType ( SCHED_SQUID_HURTHOP ); + } + + if ( HasConditions(bits_COND_SMELL_FOOD) ) + { + CSound *pSound; + + pSound = PBestScent(); + + if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) + { + // scent is behind or occluded + return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); + } + + // food is right out in the open. Just go get it. + return GetScheduleOfType( SCHED_SQUID_EAT ); + } + + if ( HasConditions(bits_COND_SMELL) ) + { + // there's something stinky. + CSound *pSound; + + pSound = PBestScent(); + if ( pSound ) + return GetScheduleOfType( SCHED_SQUID_WALLOW); + } + + break; + } + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + if ( HasConditions(bits_COND_NEW_ENEMY) ) + { + if ( m_fCanThreatDisplay && IRelationship( m_hEnemy ) == R_HT ) + { + // this means squid sees a headcrab! + m_fCanThreatDisplay = FALSE;// only do the headcrab dance once per lifetime. + return GetScheduleOfType ( SCHED_SQUID_SEECRAB ); + } + else + { + return GetScheduleOfType ( SCHED_WAKE_ANGRY ); + } + } + + if ( HasConditions(bits_COND_SMELL_FOOD) ) + { + CSound *pSound; + + pSound = PBestScent(); + + if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) + { + // scent is behind or occluded + return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); + } + + // food is right out in the open. Just go get it. + return GetScheduleOfType( SCHED_SQUID_EAT ); + } + + if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + } + + if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + { + return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + } + + if ( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) ) + { + return GetScheduleOfType ( SCHED_MELEE_ATTACK2 ); + } + + return GetScheduleOfType ( SCHED_CHASE_ENEMY ); + + break; + } + } + + return CBaseMonster :: GetSchedule(); +} + +//========================================================= +// GetScheduleOfType +//========================================================= +Schedule_t* CBullsquid :: GetScheduleOfType ( int Type ) +{ + switch ( Type ) + { + case SCHED_RANGE_ATTACK1: + return &slSquidRangeAttack1[ 0 ]; + break; + case SCHED_SQUID_HURTHOP: + return &slSquidHurtHop[ 0 ]; + break; + case SCHED_SQUID_SEECRAB: + return &slSquidSeeCrab[ 0 ]; + break; + case SCHED_SQUID_EAT: + return &slSquidEat[ 0 ]; + break; + case SCHED_SQUID_SNIFF_AND_EAT: + return &slSquidSniffAndEat[ 0 ]; + break; + case SCHED_SQUID_WALLOW: + return &slSquidWallow[ 0 ]; + break; + case SCHED_CHASE_ENEMY: + return &slSquidChaseEnemy[ 0 ]; + break; + } + + return CBaseMonster :: GetScheduleOfType ( Type ); +} + +//========================================================= +// Start task - selects the correct activity and performs +// any necessary calculations to start the next task on the +// schedule. OVERRIDDEN for bullsquid because it needs to +// know explicitly when the last attempt to chase the enemy +// failed, since that impacts its attack choices. +//========================================================= +void CBullsquid :: StartTask ( Task_t *pTask ) +{ + m_iTaskStatus = TASKSTATUS_RUNNING; + + switch ( pTask->iTask ) + { + case TASK_MELEE_ATTACK2: + { + switch ( RANDOM_LONG ( 0, 2 ) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl2.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl3.wav", 1, ATTN_NORM ); + break; + } + + CBaseMonster :: StartTask ( pTask ); + break; + } + case TASK_SQUID_HOPTURN: + { + SetActivity ( ACT_HOP ); + MakeIdealYaw ( m_vecEnemyLKP ); + break; + } + case TASK_GET_PATH_TO_ENEMY: + { + if ( BuildRoute ( m_hEnemy->pev->origin, bits_MF_TO_ENEMY, m_hEnemy ) ) + { + m_iTaskStatus = TASKSTATUS_COMPLETE; + } + else + { + ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); + TaskFail(); + } + break; + } + default: + { + CBaseMonster :: StartTask ( pTask ); + break; + } + } +} + +//========================================================= +// RunTask +//========================================================= +void CBullsquid :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_SQUID_HOPTURN: + { + MakeIdealYaw( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); + + if ( m_fSequenceFinished ) + { + m_iTaskStatus = TASKSTATUS_COMPLETE; + } + break; + } + default: + { + CBaseMonster :: RunTask( pTask ); + break; + } + } +} + + +//========================================================= +// GetIdealState - Overridden for Bullsquid to deal with +// the feature that makes it lose interest in headcrabs for +// a while if something injures it. +//========================================================= +MONSTERSTATE CBullsquid :: GetIdealState ( void ) +{ + int iConditions; + + iConditions = IScheduleFlags(); + + // If no schedule conditions, the new ideal state is probably the reason we're in here. + switch ( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + /* + COMBAT goes to ALERT upon death of enemy + */ + { + if ( m_hEnemy != NULL && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) + { + // if the squid has a headcrab enemy and something hurts it, it's going to forget about the crab for a while. + m_hEnemy = NULL; + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + break; + } + } + + m_IdealMonsterState = CBaseMonster :: GetIdealState(); + + return m_IdealMonsterState; +} + diff --git a/main/source/dlls/buttons.cpp b/main/source/dlls/buttons.cpp index 605e7bf4..62560519 100644 --- a/main/source/dlls/buttons.cpp +++ b/main/source/dlls/buttons.cpp @@ -1,1288 +1,1288 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== buttons.cpp ======================================================== - - button-related code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "doors.h" - - -#define SF_BUTTON_DONTMOVE 1 -#define SF_ROTBUTTON_NOTSOLID 1 -#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated -#define SF_BUTTON_SPARK_IF_OFF 64 // button sparks in OFF state -#define SF_BUTTON_TOUCH_ONLY 256 // button only fires as a result of USE key. - -#define SF_GLOBAL_SET 1 // Set global state to initial state on spawn - -class CEnvGlobal : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_globalstate; - int m_triggermode; - int m_initialstate; -}; - -TYPEDESCRIPTION CEnvGlobal::m_SaveData[] = -{ - DEFINE_FIELD( CEnvGlobal, m_globalstate, FIELD_STRING ), - DEFINE_FIELD( CEnvGlobal, m_triggermode, FIELD_INTEGER ), - DEFINE_FIELD( CEnvGlobal, m_initialstate, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CEnvGlobal, CBaseEntity ); - -LINK_ENTITY_TO_CLASS( env_global, CEnvGlobal ); - -void CEnvGlobal::KeyValue( KeyValueData *pkvd ) -{ - pkvd->fHandled = TRUE; - - if ( FStrEq(pkvd->szKeyName, "globalstate") ) // State name - m_globalstate = ALLOC_STRING( pkvd->szValue ); - else if ( FStrEq(pkvd->szKeyName, "triggermode") ) - m_triggermode = atoi( pkvd->szValue ); - else if ( FStrEq(pkvd->szKeyName, "initialstate") ) - m_initialstate = atoi( pkvd->szValue ); - else - CPointEntity::KeyValue( pkvd ); -} - -void CEnvGlobal::Spawn( void ) -{ - if ( !m_globalstate ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - if ( FBitSet( pev->spawnflags, SF_GLOBAL_SET ) ) - { - if ( !gGlobalState.EntityInTable( m_globalstate ) ) - gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)m_initialstate ); - } -} - - -void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - GLOBALESTATE oldState = gGlobalState.EntityGetState( m_globalstate ); - GLOBALESTATE newState; - - switch( m_triggermode ) - { - case 0: - newState = GLOBAL_OFF; - break; - - case 1: - newState = GLOBAL_ON; - break; - - case 2: - newState = GLOBAL_DEAD; - break; - - default: - case 3: - if ( oldState == GLOBAL_ON ) - newState = GLOBAL_OFF; - else if ( oldState == GLOBAL_OFF ) - newState = GLOBAL_ON; - else - newState = oldState; - } - - if ( gGlobalState.EntityInTable( m_globalstate ) ) - gGlobalState.EntitySetState( m_globalstate, newState ); - else - gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, newState ); -} - - - -TYPEDESCRIPTION CMultiSource::m_SaveData[] = -{ - //!!!BUGBUG FIX - DEFINE_ARRAY( CMultiSource, m_rgEntities, FIELD_EHANDLE, MS_MAX_TARGETS ), - DEFINE_ARRAY( CMultiSource, m_rgTriggered, FIELD_INTEGER, MS_MAX_TARGETS ), - DEFINE_FIELD( CMultiSource, m_iTotal, FIELD_INTEGER ), - DEFINE_FIELD( CMultiSource, m_globalstate, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CMultiSource, CBaseEntity ); - -LINK_ENTITY_TO_CLASS( multisource, CMultiSource ); -// -// Cache user-entity-field values until spawn is called. -// - -void CMultiSource::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "killtarget") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else if ( FStrEq(pkvd->szKeyName, "globalstate") ) - { - m_globalstate = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -#define SF_MULTI_INIT 1 - -void CMultiSource::Spawn() -{ - // set up think for later registration - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time + 0.1; - pev->spawnflags |= SF_MULTI_INIT; // Until it's initialized - SetThink(&CMultiSource::Register); -} - -void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int i = 0; - - // Find the entity in our list - while (i < m_iTotal) - if ( m_rgEntities[i++] == pCaller ) - break; - - // if we didn't find it, report error and leave - if (i > m_iTotal) - { - ALERT(at_console, "MultiSrc:Used by non member %s.\n", STRING(pCaller->pev->classname)); - return; - } - - // CONSIDER: a Use input to the multisource always toggles. Could check useType for ON/OFF/TOGGLE - - m_rgTriggered[i-1] ^= 1; - - // - if ( IsTriggered( pActivator ) ) - { - ALERT( at_aiconsole, "Multisource %s enabled (%d inputs)\n", STRING(pev->targetname), m_iTotal ); - USE_TYPE useType = USE_TOGGLE; - if ( m_globalstate ) - useType = USE_ON; - SUB_UseTargets( NULL, useType, 0 ); - } -} - - -BOOL CMultiSource::IsTriggered( CBaseEntity * ) -{ - // Is everything triggered? - int i = 0; - - // Still initializing? - if ( pev->spawnflags & SF_MULTI_INIT ) - return 0; - - while (i < m_iTotal) - { - if (m_rgTriggered[i] == 0) - break; - i++; - } - - if (i == m_iTotal) - { - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) - return 1; - } - - return 0; -} - -void CMultiSource::Register(void) -{ - edict_t *pentTarget = NULL; - - m_iTotal = 0; - memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof(EHANDLE) ); - - SetThink(&CMultiSource::SUB_DoNothing); - - // search for all entities which target this multisource (pev->targetname) - - pentTarget = FIND_ENTITY_BY_STRING(NULL, "target", STRING(pev->targetname)); - - while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) - { - CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); - if ( pTarget ) - m_rgEntities[m_iTotal++] = pTarget; - - pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "target", STRING(pev->targetname)); - } - - pentTarget = FIND_ENTITY_BY_STRING(NULL, "classname", "multi_manager"); - while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) - { - CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); - if ( pTarget && pTarget->HasTarget(pev->targetname) ) - m_rgEntities[m_iTotal++] = pTarget; - - pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "classname", "multi_manager" ); - } - - pev->spawnflags &= ~SF_MULTI_INIT; -} - -// CBaseButton -TYPEDESCRIPTION CBaseButton::m_SaveData[] = -{ - DEFINE_FIELD( CBaseButton, m_fStayPushed, FIELD_BOOLEAN ), - DEFINE_FIELD( CBaseButton, m_fRotating, FIELD_BOOLEAN ), - - DEFINE_FIELD( CBaseButton, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CBaseButton, m_bLockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_bLockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_bUnlockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_bUnlockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_strChangeTarget, FIELD_STRING ), -// DEFINE_FIELD( CBaseButton, m_ls, FIELD_??? ), // This is restored in Precache() -}; - - -IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ); - -void CBaseButton::SaveDataForReset() -{ -} - -void CBaseButton::ResetEntity() -{ -} - -void CBaseButton::Precache( void ) -{ - char *pszSound; - - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state - { - PRECACHE_SOUND ("buttons/spark1.wav"); - PRECACHE_SOUND ("buttons/spark2.wav"); - PRECACHE_SOUND ("buttons/spark3.wav"); - PRECACHE_SOUND ("buttons/spark4.wav"); - PRECACHE_SOUND ("buttons/spark5.wav"); - PRECACHE_SOUND ("buttons/spark6.wav"); - } - - // get door button sounds, for doors which require buttons to open - - if (m_bLockedSound) - { - pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); - } - - if (m_bUnlockedSound) - { - pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); - } - - // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) - { - case 1: m_ls.sLockedSentence = MAKE_STRING("NA"); break; // access denied - case 2: m_ls.sLockedSentence = MAKE_STRING("ND"); break; // security lockout - case 3: m_ls.sLockedSentence = MAKE_STRING("NF"); break; // blast door - case 4: m_ls.sLockedSentence = MAKE_STRING("NFIRE"); break; // fire door - case 5: m_ls.sLockedSentence = MAKE_STRING("NCHEM"); break; // chemical door - case 6: m_ls.sLockedSentence = MAKE_STRING("NRAD"); break; // radiation door - case 7: m_ls.sLockedSentence = MAKE_STRING("NCON"); break; // gen containment - case 8: m_ls.sLockedSentence = MAKE_STRING("NH"); break; // maintenance door - case 9: m_ls.sLockedSentence = MAKE_STRING("NG"); break; // broken door - - default: m_ls.sLockedSentence = 0; break; - } - - switch (m_bUnlockedSentence) - { - case 1: m_ls.sUnlockedSentence = MAKE_STRING("EA"); break; // access granted - case 2: m_ls.sUnlockedSentence = MAKE_STRING("ED"); break; // security door - case 3: m_ls.sUnlockedSentence = MAKE_STRING("EF"); break; // blast door - case 4: m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); break; // fire door - case 5: m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); break; // chemical door - case 6: m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); break; // radiation door - case 7: m_ls.sUnlockedSentence = MAKE_STRING("ECON"); break; // gen containment - case 8: m_ls.sUnlockedSentence = MAKE_STRING("EH"); break; // maintenance door - - default: m_ls.sUnlockedSentence = 0; break; - } -} - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseButton::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "changetarget")) - { - m_strChangeTarget = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_bLockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -// -// ButtonShot -// -int CBaseButton::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) - return 0; - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - // Caused an ASSERT/crash when an offensive chamber spit hit the button at the bottom of the elevator in the bast start - if(pevAttacker == NULL) - return 0; - - m_hActivator = CBaseEntity::Instance( pevAttacker ); - if ( m_hActivator == NULL ) - return 0; - - if ( code == BUTTON_RETURN ) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - // Toggle buttons fire when they get back to their "home" position - if ( !(pev->spawnflags & SF_BUTTON_TOGGLE) ) - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - ButtonReturn(); - } - else // code == BUTTON_ACTIVATE - ButtonActivate( ); - - return 0; -} - -/*QUAKED func_button (0 .5 .8) ? -When a button is touched, it moves some distance in the direction of it's angle, -triggers all of it's targets, waits some time, then returns to it's original position -where it can be triggered again. - -"angle" determines the opening direction -"target" all entities with a matching targetname will be used -"speed" override the default 40 speed -"wait" override the default 1 second wait (-1 = never return) -"lip" override the default 4 pixel lip remaining at end of move -"health" if set, the button must be killed instead of touched -"sounds" -0) steam metal -1) wooden clunk -2) metallic click -3) in-out -*/ -LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); - - -void CBaseButton::Spawn( ) -{ - char *pszSound; - - //---------------------------------------------------- - //determine sounds for buttons - //a sound of 0 should not make a sound - //---------------------------------------------------- - pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); - - Precache(); - - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state - { - SetThink ( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + 0.5;// no hurry, make sure everything else spawns - } - - SetMovedir(pev); - - pev->movetype = MOVETYPE_PUSH; - pev->solid = SOLID_BSP; - SET_MODEL(ENT(pev), STRING(pev->model)); - - if (pev->speed == 0) - pev->speed = 40; - - if (pev->health > 0) - { - pev->takedamage = DAMAGE_YES; - } - - if (m_flWait == 0) - m_flWait = 1; - if (m_flLip == 0) - m_flLip = 4; - - m_toggle_state = TS_AT_BOTTOM; - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - - - // Is this a non-moving button? - if ( ((m_vecPosition2 - m_vecPosition1).Length() < 1) || (pev->spawnflags & SF_BUTTON_DONTMOVE) ) - m_vecPosition2 = m_vecPosition1; - - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); - m_fRotating = FALSE; - - // if the button is flagged for USE button activation only, take away it's touch function and add a use function - - if ( FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // touchable button - { - SetTouch( &CBaseButton::ButtonTouch ); - } - else - { - SetTouch ( NULL ); - SetUse ( &CBaseButton::ButtonUse ); - } -} - - -// Button sound table. -// Also used by CBaseDoor to get 'touched' door lock/unlock sounds - -char *ButtonSound( int sound ) -{ - char *pszSound; - - switch ( sound ) - { - case 0: pszSound = "common/null.wav"; break; - case 1: pszSound = "buttons/button1.wav"; break; - case 2: pszSound = "buttons/button2.wav"; break; - case 3: pszSound = "buttons/button3.wav"; break; - case 4: pszSound = "buttons/button4.wav"; break; - case 5: pszSound = "buttons/button5.wav"; break; - case 6: pszSound = "buttons/button6.wav"; break; - case 7: pszSound = "buttons/button7.wav"; break; - case 8: pszSound = "buttons/button8.wav"; break; - case 9: pszSound = "buttons/button9.wav"; break; - case 10: pszSound = "buttons/button10.wav"; break; - case 11: pszSound = "buttons/button11.wav"; break; - case 12: pszSound = "buttons/latchlocked1.wav"; break; - case 13: pszSound = "buttons/latchunlocked1.wav"; break; - case 14: pszSound = "buttons/lightswitch2.wav";break; - -// next 6 slots reserved for any additional sliding button sounds we may add - - case 21: pszSound = "buttons/lever1.wav"; break; - case 22: pszSound = "buttons/lever2.wav"; break; - case 23: pszSound = "buttons/lever3.wav"; break; - case 24: pszSound = "buttons/lever4.wav"; break; - case 25: pszSound = "buttons/lever5.wav"; break; - - default:pszSound = "buttons/button9.wav"; break; - } - - return pszSound; -} - -// -// Makes flagged buttons spark when turned off -// - -void DoSpark(entvars_t *pev, const Vector &location ) -{ - Vector tmp = location + pev->size * 0.5; - UTIL_Sparks( tmp ); - - float flVolume = RANDOM_FLOAT ( 0.25 , 0.75 ) * 0.4;//random volume range - switch ( (int)(RANDOM_FLOAT(0,1) * 6) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark1.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark2.wav", flVolume, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark3.wav", flVolume, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark4.wav", flVolume, ATTN_NORM); break; - case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } -} - -void CBaseButton::ButtonSpark ( void ) -{ - SetThink ( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) );// spark again at random interval - - DoSpark( pev, pev->mins ); -} - - -// -// Button's Use function -// -void CBaseButton::ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. - // UNDONE: Should this use ButtonResponseToTouch() too? - if (m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) - return; - - m_hActivator = pActivator; - if ( m_toggle_state == TS_AT_TOP) - { - if (!m_fStayPushed && FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE)) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - //SUB_UseTargets( m_eoActivator ); - ButtonReturn(); - } - } - else - ButtonActivate( ); -} - - -CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) -{ - // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. - if (m_toggle_state == TS_GOING_UP || - m_toggle_state == TS_GOING_DOWN || - (m_toggle_state == TS_AT_TOP && !m_fStayPushed && !FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) ) - return BUTTON_NOTHING; - - if (m_toggle_state == TS_AT_TOP) - { - if((FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) && !m_fStayPushed) - { - return BUTTON_RETURN; - } - } - else - return BUTTON_ACTIVATE; - - return BUTTON_NOTHING; -} - - -// -// Touching a button simply "activates" it. -// -void CBaseButton:: ButtonTouch( CBaseEntity *pOther ) -{ - // Ignore touches by anything but players - if (!FClassnameIs(pOther->pev, "player")) - return; - - m_hActivator = pOther; - - BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) - return; - - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) - { - // play button locked sound - PlayLockSounds(pev, &m_ls, TRUE, TRUE); - return; - } - - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - if ( code == BUTTON_RETURN ) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - ButtonReturn(); - } - else // code == BUTTON_ACTIVATE - ButtonActivate( ); -} - -// -// Starts the button moving "in/up". -// -void CBaseButton::ButtonActivate( ) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - { - // button is locked, play locked sound - PlayLockSounds(pev, &m_ls, TRUE, TRUE); - return; - } - else - { - // button is unlocked, play unlocked sound - PlayLockSounds(pev, &m_ls, FALSE, TRUE); - } - - ASSERT(m_toggle_state == TS_AT_BOTTOM); - m_toggle_state = TS_GOING_UP; - - SetMoveDone( &CBaseButton::TriggerAndWait ); - if (!m_fRotating) - LinearMove( m_vecPosition2, pev->speed); - else - AngularMove( m_vecAngle2, pev->speed); -} - -// -// Button has reached the "in/up" position. Activate its "targets", and pause before "popping out". -// -void CBaseButton::TriggerAndWait( void ) -{ - ASSERT(m_toggle_state == TS_GOING_UP); - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return; - - m_toggle_state = TS_AT_TOP; - - // If button automatically comes back out, start it moving out. - // Else re-instate touch method - if (m_fStayPushed || FBitSet ( pev->spawnflags, SF_BUTTON_TOGGLE ) ) - { - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! - { - // ALL buttons are now use only - SetTouch ( NULL ); - } - else - SetTouch( &CBaseButton::ButtonTouch ); - } - else - { - pev->nextthink = pev->ltime + m_flWait; - SetThink( &CBaseButton::ButtonReturn ); - } - - pev->frame = 1; // use alternate textures - - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); -} - - -// -// Starts the button moving "out/down". -// -void CBaseButton::ButtonReturn( void ) -{ - ASSERT(m_toggle_state == TS_AT_TOP); - m_toggle_state = TS_GOING_DOWN; - - SetMoveDone( &CBaseButton::ButtonBackHome ); - if (!m_fRotating) - LinearMove( m_vecPosition1, pev->speed); - else - AngularMove( m_vecAngle1, pev->speed); - - pev->frame = 0; // use normal textures -} - - -// -// Button has returned to start state. Quiesce it. -// -void CBaseButton::ButtonBackHome( void ) -{ - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; - - if ( FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) - { - //EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - } - - - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - - if (FNullEnt(pentTarget)) - break; - - if (!FClassnameIs(pentTarget, "multisource")) - continue; - CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); - - if ( pTarget ) - pTarget->Use( m_hActivator, this, USE_TOGGLE, 0 ); - } - } - -// Re-instate touch method, movement cycle is complete. - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! - { - // All buttons are now use only - SetTouch ( NULL ); - } - else - SetTouch( &CBaseButton::ButtonTouch ); - -// reset think for a sparking button - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) - { - SetThink ( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + 0.5;// no hurry. - } -} - - - -// -// Rotating button (aka "lever") -// -class CRotButton : public CBaseButton -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ); - -void CRotButton::Spawn( void ) -{ - char *pszSound; - //---------------------------------------------------- - //determine sounds for buttons - //a sound of 0 should not make a sound - //---------------------------------------------------- - pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); - - // set the axis of rotation - CBaseToggle::AxisDir( pev ); - - // check for clockwise rotation - if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - pev->movetype = MOVETYPE_PUSH; - - if ( pev->spawnflags & SF_ROTBUTTON_NOTSOLID ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - SET_MODEL(ENT(pev), STRING(pev->model)); - - if (pev->speed == 0) - pev->speed = 40; - - if (m_flWait == 0) - m_flWait = 1; - - if (pev->health > 0) - { - pev->takedamage = DAMAGE_YES; - } - - m_toggle_state = TS_AT_BOTTOM; - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating button start/end positions are equal"); - - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); - m_fRotating = TRUE; - - // if the button is flagged for USE button activation only, take away it's touch function and add a use function - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) - { - SetTouch ( NULL ); - SetUse ( &CRotButton::ButtonUse ); - } - else // touchable button - SetTouch( &CRotButton::ButtonTouch ); - - //SetTouch( ButtonTouch ); -} - - -// Make this button behave like a door (HACKHACK) -// This will disable use and make the button solid -// rotating buttons were made SOLID_NOT by default since their were some -// collision problems with them... -#define SF_MOMENTARY_DOOR 0x0001 - -class CMomentaryRotButton : public CBaseToggle -{ -public: - void Spawn ( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) - { - int flags = CBaseToggle :: ObjectCaps() & (~FCAP_ACROSS_TRANSITION); - if ( pev->spawnflags & SF_MOMENTARY_DOOR ) - return flags; - return flags | FCAP_CONTINUOUS_USE; - } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Off( void ); - void EXPORT Return( void ); - void UpdateSelf( float value ); - void UpdateSelfReturn( float value ); - void UpdateAllButtons( float value, int start ); - - void PlaySound( void ); - void UpdateTarget( float value ); - - static CMomentaryRotButton *Instance( edict_t *pent ) { return (CMomentaryRotButton *)GET_PRIVATE(pent);}; - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_lastUsed; - int m_direction; - float m_returnSpeed; - vec3_t m_start; - vec3_t m_end; - int m_sounds; -}; -TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] = -{ - DEFINE_FIELD( CMomentaryRotButton, m_lastUsed, FIELD_INTEGER ), - DEFINE_FIELD( CMomentaryRotButton, m_direction, FIELD_INTEGER ), - DEFINE_FIELD( CMomentaryRotButton, m_returnSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CMomentaryRotButton, m_start, FIELD_VECTOR ), - DEFINE_FIELD( CMomentaryRotButton, m_end, FIELD_VECTOR ), - DEFINE_FIELD( CMomentaryRotButton, m_sounds, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CMomentaryRotButton, CBaseToggle ); - -LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ); - -void CMomentaryRotButton::Spawn( void ) -{ - CBaseToggle::AxisDir( pev ); - - if ( pev->speed == 0 ) - pev->speed = 100; - - if ( m_flMoveDistance < 0 ) - { - m_start = pev->angles + pev->movedir * m_flMoveDistance; - m_end = pev->angles; - m_direction = 1; // This will toggle to -1 on the first use() - m_flMoveDistance = -m_flMoveDistance; - } - else - { - m_start = pev->angles; - m_end = pev->angles + pev->movedir * m_flMoveDistance; - m_direction = -1; // This will toggle to +1 on the first use() - } - - if ( pev->spawnflags & SF_MOMENTARY_DOOR ) - pev->solid = SOLID_BSP; - else - pev->solid = SOLID_NOT; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - char *pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); - m_lastUsed = 0; -} - -void CMomentaryRotButton::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "returnspeed")) - { - m_returnSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CMomentaryRotButton::PlaySound( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); -} - -// BUGBUG: This design causes a latentcy. When the button is retriggered, the first impulse -// will send the target in the wrong direction because the parameter is calculated based on the -// current, not future position. -void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->ideal_yaw = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; - - UpdateAllButtons( pev->ideal_yaw, 1 ); - UpdateTarget( pev->ideal_yaw ); -} - -void CMomentaryRotButton::UpdateAllButtons( float value, int start ) -{ - // Update all rot buttons attached to the same target - edict_t *pentTarget = NULL; - for (;;) - { - - pentTarget = FIND_ENTITY_BY_STRING(pentTarget, "target", STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs( VARS(pentTarget), "momentary_rot_button" ) ) - { - CMomentaryRotButton *pEntity = CMomentaryRotButton::Instance(pentTarget); - if ( pEntity ) - { - if ( start ) - pEntity->UpdateSelf( value ); - else - pEntity->UpdateSelfReturn( value ); - } - } - } -} - -void CMomentaryRotButton::UpdateSelf( float value ) -{ - BOOL fplaysound = FALSE; - - if ( !m_lastUsed ) - { - fplaysound = TRUE; - m_direction = -m_direction; - } - m_lastUsed = 1; - - pev->nextthink = pev->ltime + 0.1; - if ( m_direction > 0 && value >= 1.0 ) - { - pev->avelocity = g_vecZero; - pev->angles = m_end; - return; - } - else if ( m_direction < 0 && value <= 0 ) - { - pev->avelocity = g_vecZero; - pev->angles = m_start; - return; - } - - if (fplaysound) - PlaySound(); - - // HACKHACK -- If we're going slow, we'll get multiple player packets per frame, bump nexthink on each one to avoid stalling - if ( pev->nextthink < pev->ltime ) - pev->nextthink = pev->ltime + 0.1; - else - pev->nextthink += 0.1; - - pev->avelocity = (m_direction * pev->speed) * pev->movedir; - SetThink( &CMomentaryRotButton::Off ); -} - -void CMomentaryRotButton::UpdateTarget( float value ) -{ - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - CBaseEntity *pEntity = CBaseEntity::Instance(pentTarget); - if ( pEntity ) - { - pEntity->Use( this, this, USE_SET, value ); - } - } - } -} - -void CMomentaryRotButton::Off( void ) -{ - pev->avelocity = g_vecZero; - m_lastUsed = 0; - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) - { - SetThink( &CMomentaryRotButton::Return ); - pev->nextthink = pev->ltime + 0.1; - m_direction = -1; - } - else - SetThink( NULL ); -} - -void CMomentaryRotButton::Return( void ) -{ - float value = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; - - UpdateAllButtons( value, 0 ); // This will end up calling UpdateSelfReturn() n times, but it still works right - if ( value > 0 ) - UpdateTarget( value ); -} - - -void CMomentaryRotButton::UpdateSelfReturn( float value ) -{ - if ( value <= 0 ) - { - pev->avelocity = g_vecZero; - pev->angles = m_start; - pev->nextthink = -1; - SetThink( NULL ); - } - else - { - pev->avelocity = -m_returnSpeed * pev->movedir; - pev->nextthink = pev->ltime + 0.1; - } -} - - -//---------------------------------------------------------------- -// Spark -//---------------------------------------------------------------- - -class CEnvSpark : public CBaseEntity -{ -public: - void Spawn(void); - void Precache(void); - void EXPORT SparkThink(void); - void EXPORT SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT SparkStop(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue(KeyValueData *pkvd); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flDelay; -}; - - -TYPEDESCRIPTION CEnvSpark::m_SaveData[] = -{ - DEFINE_FIELD( CEnvSpark, m_flDelay, FIELD_FLOAT), -}; - -IMPLEMENT_SAVERESTORE( CEnvSpark, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(env_spark, CEnvSpark); -LINK_ENTITY_TO_CLASS(env_debris, CEnvSpark); - -void CEnvSpark::Spawn(void) -{ - SetThink( NULL ); - SetUse( NULL ); - - if (FBitSet(pev->spawnflags, 32)) // Use for on/off - { - if (FBitSet(pev->spawnflags, 64)) // Start on - { - SetThink(&CEnvSpark::SparkThink); // start sparking - SetUse(&CEnvSpark::SparkStop); // set up +USE to stop sparking - } - else - SetUse(&CEnvSpark::SparkStart); - } - else - SetThink(&CEnvSpark::SparkThink); - - pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) ); - - if (m_flDelay <= 0) - m_flDelay = 1.5; - - Precache( ); -} - - -void CEnvSpark::Precache(void) -{ - PRECACHE_SOUND( "buttons/spark1.wav" ); - PRECACHE_SOUND( "buttons/spark2.wav" ); - PRECACHE_SOUND( "buttons/spark3.wav" ); - PRECACHE_SOUND( "buttons/spark4.wav" ); - PRECACHE_SOUND( "buttons/spark5.wav" ); - PRECACHE_SOUND( "buttons/spark6.wav" ); -} - -void CEnvSpark::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "MaxDelay")) - { - m_flDelay = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "killtarget") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else - CBaseEntity::KeyValue( pkvd ); -} - -void EXPORT CEnvSpark::SparkThink(void) -{ - pev->nextthink = gpGlobals->time + 0.1 + RANDOM_FLOAT (0, m_flDelay); - DoSpark( pev, pev->origin ); -} - -void EXPORT CEnvSpark::SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetUse(&CEnvSpark::SparkStop); - SetThink(&CEnvSpark::SparkThink); - pev->nextthink = gpGlobals->time + (0.1 + RANDOM_FLOAT ( 0, m_flDelay)); -} - -void EXPORT CEnvSpark::SparkStop(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetUse(&CEnvSpark::SparkStart); - SetThink(NULL); -} - -#define SF_BTARGET_USE 0x0001 -#define SF_BTARGET_ON 0x0002 - -class CButtonTarget : public CBaseEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - int ObjectCaps( void ); - -}; - -LINK_ENTITY_TO_CLASS( button_target, CButtonTarget ); - -void CButtonTarget::Spawn( void ) -{ - pev->movetype = MOVETYPE_PUSH; - pev->solid = SOLID_BSP; - SET_MODEL(ENT(pev), STRING(pev->model)); - pev->takedamage = DAMAGE_YES; - - if ( FBitSet( pev->spawnflags, SF_BTARGET_ON ) ) - pev->frame = 1; -} - -void CButtonTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, (int)pev->frame ) ) - return; - pev->frame = 1-pev->frame; - if ( pev->frame ) - SUB_UseTargets( pActivator, USE_ON, 0 ); - else - SUB_UseTargets( pActivator, USE_OFF, 0 ); -} - - -int CButtonTarget :: ObjectCaps( void ) -{ - int caps = CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; - - if ( FBitSet(pev->spawnflags, SF_BTARGET_USE) ) - return caps | FCAP_IMPULSE_USE; - else - return caps; -} - - -int CButtonTarget::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Use( Instance(pevAttacker), this, USE_TOGGLE, 0 ); - - return 1; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== buttons.cpp ======================================================== + + button-related code + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "doors.h" + + +#define SF_BUTTON_DONTMOVE 1 +#define SF_ROTBUTTON_NOTSOLID 1 +#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated +#define SF_BUTTON_SPARK_IF_OFF 64 // button sparks in OFF state +#define SF_BUTTON_TOUCH_ONLY 256 // button only fires as a result of USE key. + +#define SF_GLOBAL_SET 1 // Set global state to initial state on spawn + +class CEnvGlobal : public CPointEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + string_t m_globalstate; + int m_triggermode; + int m_initialstate; +}; + +TYPEDESCRIPTION CEnvGlobal::m_SaveData[] = +{ + DEFINE_FIELD( CEnvGlobal, m_globalstate, FIELD_STRING ), + DEFINE_FIELD( CEnvGlobal, m_triggermode, FIELD_INTEGER ), + DEFINE_FIELD( CEnvGlobal, m_initialstate, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CEnvGlobal, CBaseEntity ); + +LINK_ENTITY_TO_CLASS( env_global, CEnvGlobal ); + +void CEnvGlobal::KeyValue( KeyValueData *pkvd ) +{ + pkvd->fHandled = TRUE; + + if ( FStrEq(pkvd->szKeyName, "globalstate") ) // State name + m_globalstate = ALLOC_STRING( pkvd->szValue ); + else if ( FStrEq(pkvd->szKeyName, "triggermode") ) + m_triggermode = atoi( pkvd->szValue ); + else if ( FStrEq(pkvd->szKeyName, "initialstate") ) + m_initialstate = atoi( pkvd->szValue ); + else + CPointEntity::KeyValue( pkvd ); +} + +void CEnvGlobal::Spawn( void ) +{ + if ( !m_globalstate ) + { + REMOVE_ENTITY( ENT(pev) ); + return; + } + if ( FBitSet( pev->spawnflags, SF_GLOBAL_SET ) ) + { + if ( !gGlobalState.EntityInTable( m_globalstate ) ) + gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)m_initialstate ); + } +} + + +void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + GLOBALESTATE oldState = gGlobalState.EntityGetState( m_globalstate ); + GLOBALESTATE newState; + + switch( m_triggermode ) + { + case 0: + newState = GLOBAL_OFF; + break; + + case 1: + newState = GLOBAL_ON; + break; + + case 2: + newState = GLOBAL_DEAD; + break; + + default: + case 3: + if ( oldState == GLOBAL_ON ) + newState = GLOBAL_OFF; + else if ( oldState == GLOBAL_OFF ) + newState = GLOBAL_ON; + else + newState = oldState; + } + + if ( gGlobalState.EntityInTable( m_globalstate ) ) + gGlobalState.EntitySetState( m_globalstate, newState ); + else + gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, newState ); +} + + + +TYPEDESCRIPTION CMultiSource::m_SaveData[] = +{ + //!!!BUGBUG FIX + DEFINE_ARRAY( CMultiSource, m_rgEntities, FIELD_EHANDLE, MS_MAX_TARGETS ), + DEFINE_ARRAY( CMultiSource, m_rgTriggered, FIELD_INTEGER, MS_MAX_TARGETS ), + DEFINE_FIELD( CMultiSource, m_iTotal, FIELD_INTEGER ), + DEFINE_FIELD( CMultiSource, m_globalstate, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CMultiSource, CBaseEntity ); + +LINK_ENTITY_TO_CLASS( multisource, CMultiSource ); +// +// Cache user-entity-field values until spawn is called. +// + +void CMultiSource::KeyValue( KeyValueData *pkvd ) +{ + if ( FStrEq(pkvd->szKeyName, "style") || + FStrEq(pkvd->szKeyName, "height") || + FStrEq(pkvd->szKeyName, "killtarget") || + FStrEq(pkvd->szKeyName, "value1") || + FStrEq(pkvd->szKeyName, "value2") || + FStrEq(pkvd->szKeyName, "value3")) + pkvd->fHandled = TRUE; + else if ( FStrEq(pkvd->szKeyName, "globalstate") ) + { + m_globalstate = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +#define SF_MULTI_INIT 1 + +void CMultiSource::Spawn() +{ + // set up think for later registration + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->nextthink = gpGlobals->time + 0.1; + pev->spawnflags |= SF_MULTI_INIT; // Until it's initialized + SetThink(&CMultiSource::Register); +} + +void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int i = 0; + + // Find the entity in our list + while (i < m_iTotal) + if ( m_rgEntities[i++] == pCaller ) + break; + + // if we didn't find it, report error and leave + if (i > m_iTotal) + { + ALERT(at_console, "MultiSrc:Used by non member %s.\n", STRING(pCaller->pev->classname)); + return; + } + + // CONSIDER: a Use input to the multisource always toggles. Could check useType for ON/OFF/TOGGLE + + m_rgTriggered[i-1] ^= 1; + + // + if ( IsTriggered( pActivator ) ) + { + ALERT( at_aiconsole, "Multisource %s enabled (%d inputs)\n", STRING(pev->targetname), m_iTotal ); + USE_TYPE useType = USE_TOGGLE; + if ( m_globalstate ) + useType = USE_ON; + SUB_UseTargets( NULL, useType, 0 ); + } +} + + +BOOL CMultiSource::IsTriggered( CBaseEntity * ) +{ + // Is everything triggered? + int i = 0; + + // Still initializing? + if ( pev->spawnflags & SF_MULTI_INIT ) + return 0; + + while (i < m_iTotal) + { + if (m_rgTriggered[i] == 0) + break; + i++; + } + + if (i == m_iTotal) + { + if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) + return 1; + } + + return 0; +} + +void CMultiSource::Register(void) +{ + edict_t *pentTarget = NULL; + + m_iTotal = 0; + memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof(EHANDLE) ); + + SetThink(&CMultiSource::SUB_DoNothing); + + // search for all entities which target this multisource (pev->targetname) + + pentTarget = FIND_ENTITY_BY_STRING(NULL, "target", STRING(pev->targetname)); + + while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) + { + CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); + if ( pTarget ) + m_rgEntities[m_iTotal++] = pTarget; + + pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "target", STRING(pev->targetname)); + } + + pentTarget = FIND_ENTITY_BY_STRING(NULL, "classname", "multi_manager"); + while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) + { + CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); + if ( pTarget && pTarget->HasTarget(pev->targetname) ) + m_rgEntities[m_iTotal++] = pTarget; + + pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "classname", "multi_manager" ); + } + + pev->spawnflags &= ~SF_MULTI_INIT; +} + +// CBaseButton +TYPEDESCRIPTION CBaseButton::m_SaveData[] = +{ + DEFINE_FIELD( CBaseButton, m_fStayPushed, FIELD_BOOLEAN ), + DEFINE_FIELD( CBaseButton, m_fRotating, FIELD_BOOLEAN ), + + DEFINE_FIELD( CBaseButton, m_sounds, FIELD_INTEGER ), + DEFINE_FIELD( CBaseButton, m_bLockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseButton, m_bLockedSentence, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseButton, m_bUnlockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseButton, m_bUnlockedSentence, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseButton, m_strChangeTarget, FIELD_STRING ), +// DEFINE_FIELD( CBaseButton, m_ls, FIELD_??? ), // This is restored in Precache() +}; + + +IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ); + +void CBaseButton::SaveDataForReset() +{ +} + +void CBaseButton::ResetEntity() +{ +} + +void CBaseButton::Precache( void ) +{ + char *pszSound; + + if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state + { + PRECACHE_SOUND ("buttons/spark1.wav"); + PRECACHE_SOUND ("buttons/spark2.wav"); + PRECACHE_SOUND ("buttons/spark3.wav"); + PRECACHE_SOUND ("buttons/spark4.wav"); + PRECACHE_SOUND ("buttons/spark5.wav"); + PRECACHE_SOUND ("buttons/spark6.wav"); + } + + // get door button sounds, for doors which require buttons to open + + if (m_bLockedSound) + { + pszSound = ButtonSound( (int)m_bLockedSound ); + PRECACHE_SOUND(pszSound); + m_ls.sLockedSound = ALLOC_STRING(pszSound); + } + + if (m_bUnlockedSound) + { + pszSound = ButtonSound( (int)m_bUnlockedSound ); + PRECACHE_SOUND(pszSound); + m_ls.sUnlockedSound = ALLOC_STRING(pszSound); + } + + // get sentence group names, for doors which are directly 'touched' to open + + switch (m_bLockedSentence) + { + case 1: m_ls.sLockedSentence = MAKE_STRING("NA"); break; // access denied + case 2: m_ls.sLockedSentence = MAKE_STRING("ND"); break; // security lockout + case 3: m_ls.sLockedSentence = MAKE_STRING("NF"); break; // blast door + case 4: m_ls.sLockedSentence = MAKE_STRING("NFIRE"); break; // fire door + case 5: m_ls.sLockedSentence = MAKE_STRING("NCHEM"); break; // chemical door + case 6: m_ls.sLockedSentence = MAKE_STRING("NRAD"); break; // radiation door + case 7: m_ls.sLockedSentence = MAKE_STRING("NCON"); break; // gen containment + case 8: m_ls.sLockedSentence = MAKE_STRING("NH"); break; // maintenance door + case 9: m_ls.sLockedSentence = MAKE_STRING("NG"); break; // broken door + + default: m_ls.sLockedSentence = 0; break; + } + + switch (m_bUnlockedSentence) + { + case 1: m_ls.sUnlockedSentence = MAKE_STRING("EA"); break; // access granted + case 2: m_ls.sUnlockedSentence = MAKE_STRING("ED"); break; // security door + case 3: m_ls.sUnlockedSentence = MAKE_STRING("EF"); break; // blast door + case 4: m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); break; // fire door + case 5: m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); break; // chemical door + case 6: m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); break; // radiation door + case 7: m_ls.sUnlockedSentence = MAKE_STRING("ECON"); break; // gen containment + case 8: m_ls.sUnlockedSentence = MAKE_STRING("EH"); break; // maintenance door + + default: m_ls.sUnlockedSentence = 0; break; + } +} + +// +// Cache user-entity-field values until spawn is called. +// + +void CBaseButton::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "changetarget")) + { + m_strChangeTarget = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sound")) + { + m_bLockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "sounds")) + { + m_sounds = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +// +// ButtonShot +// +int CBaseButton::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + BUTTON_CODE code = ButtonResponseToTouch(); + + if ( code == BUTTON_NOTHING ) + return 0; + // Temporarily disable the touch function, until movement is finished. + SetTouch( NULL ); + + // Caused an ASSERT/crash when an offensive chamber spit hit the button at the bottom of the elevator in the bast start + if(pevAttacker == NULL) + return 0; + + m_hActivator = CBaseEntity::Instance( pevAttacker ); + if ( m_hActivator == NULL ) + return 0; + + if ( code == BUTTON_RETURN ) + { + EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + + // Toggle buttons fire when they get back to their "home" position + if ( !(pev->spawnflags & SF_BUTTON_TOGGLE) ) + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); + ButtonReturn(); + } + else // code == BUTTON_ACTIVATE + ButtonActivate( ); + + return 0; +} + +/*QUAKED func_button (0 .5 .8) ? +When a button is touched, it moves some distance in the direction of it's angle, +triggers all of it's targets, waits some time, then returns to it's original position +where it can be triggered again. + +"angle" determines the opening direction +"target" all entities with a matching targetname will be used +"speed" override the default 40 speed +"wait" override the default 1 second wait (-1 = never return) +"lip" override the default 4 pixel lip remaining at end of move +"health" if set, the button must be killed instead of touched +"sounds" +0) steam metal +1) wooden clunk +2) metallic click +3) in-out +*/ +LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); + + +void CBaseButton::Spawn( ) +{ + char *pszSound; + + //---------------------------------------------------- + //determine sounds for buttons + //a sound of 0 should not make a sound + //---------------------------------------------------- + pszSound = ButtonSound( m_sounds ); + PRECACHE_SOUND(pszSound); + pev->noise = ALLOC_STRING(pszSound); + + Precache(); + + if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state + { + SetThink ( &CBaseButton::ButtonSpark ); + pev->nextthink = gpGlobals->time + 0.5;// no hurry, make sure everything else spawns + } + + SetMovedir(pev); + + pev->movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + SET_MODEL(ENT(pev), STRING(pev->model)); + + if (pev->speed == 0) + pev->speed = 40; + + if (pev->health > 0) + { + pev->takedamage = DAMAGE_YES; + } + + if (m_flWait == 0) + m_flWait = 1; + if (m_flLip == 0) + m_flLip = 4; + + m_toggle_state = TS_AT_BOTTOM; + m_vecPosition1 = pev->origin; + // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big + m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); + + + // Is this a non-moving button? + if ( ((m_vecPosition2 - m_vecPosition1).Length() < 1) || (pev->spawnflags & SF_BUTTON_DONTMOVE) ) + m_vecPosition2 = m_vecPosition1; + + m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); + m_fRotating = FALSE; + + // if the button is flagged for USE button activation only, take away it's touch function and add a use function + + if ( FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // touchable button + { + SetTouch( &CBaseButton::ButtonTouch ); + } + else + { + SetTouch ( NULL ); + SetUse ( &CBaseButton::ButtonUse ); + } +} + + +// Button sound table. +// Also used by CBaseDoor to get 'touched' door lock/unlock sounds + +char *ButtonSound( int sound ) +{ + char *pszSound; + + switch ( sound ) + { + case 0: pszSound = "common/null.wav"; break; + case 1: pszSound = "buttons/button1.wav"; break; + case 2: pszSound = "buttons/button2.wav"; break; + case 3: pszSound = "buttons/button3.wav"; break; + case 4: pszSound = "buttons/button4.wav"; break; + case 5: pszSound = "buttons/button5.wav"; break; + case 6: pszSound = "buttons/button6.wav"; break; + case 7: pszSound = "buttons/button7.wav"; break; + case 8: pszSound = "buttons/button8.wav"; break; + case 9: pszSound = "buttons/button9.wav"; break; + case 10: pszSound = "buttons/button10.wav"; break; + case 11: pszSound = "buttons/button11.wav"; break; + case 12: pszSound = "buttons/latchlocked1.wav"; break; + case 13: pszSound = "buttons/latchunlocked1.wav"; break; + case 14: pszSound = "buttons/lightswitch2.wav";break; + +// next 6 slots reserved for any additional sliding button sounds we may add + + case 21: pszSound = "buttons/lever1.wav"; break; + case 22: pszSound = "buttons/lever2.wav"; break; + case 23: pszSound = "buttons/lever3.wav"; break; + case 24: pszSound = "buttons/lever4.wav"; break; + case 25: pszSound = "buttons/lever5.wav"; break; + + default:pszSound = "buttons/button9.wav"; break; + } + + return pszSound; +} + +// +// Makes flagged buttons spark when turned off +// + +void DoSpark(entvars_t *pev, const Vector &location ) +{ + Vector tmp = location + pev->size * 0.5; + UTIL_Sparks( tmp ); + + float flVolume = RANDOM_FLOAT ( 0.25 , 0.75 ) * 0.4;//random volume range + switch ( (int)(RANDOM_FLOAT(0,1) * 6) ) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark1.wav", flVolume, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark2.wav", flVolume, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark3.wav", flVolume, ATTN_NORM); break; + case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark4.wav", flVolume, ATTN_NORM); break; + case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; + case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; + } +} + +void CBaseButton::ButtonSpark ( void ) +{ + SetThink ( &CBaseButton::ButtonSpark ); + pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) );// spark again at random interval + + DoSpark( pev, pev->mins ); +} + + +// +// Button's Use function +// +void CBaseButton::ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. + // UNDONE: Should this use ButtonResponseToTouch() too? + if (m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) + return; + + m_hActivator = pActivator; + if ( m_toggle_state == TS_AT_TOP) + { + if (!m_fStayPushed && FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE)) + { + EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + + //SUB_UseTargets( m_eoActivator ); + ButtonReturn(); + } + } + else + ButtonActivate( ); +} + + +CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) +{ + // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. + if (m_toggle_state == TS_GOING_UP || + m_toggle_state == TS_GOING_DOWN || + (m_toggle_state == TS_AT_TOP && !m_fStayPushed && !FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) ) + return BUTTON_NOTHING; + + if (m_toggle_state == TS_AT_TOP) + { + if((FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) && !m_fStayPushed) + { + return BUTTON_RETURN; + } + } + else + return BUTTON_ACTIVATE; + + return BUTTON_NOTHING; +} + + +// +// Touching a button simply "activates" it. +// +void CBaseButton:: ButtonTouch( CBaseEntity *pOther ) +{ + // Ignore touches by anything but players + if (!FClassnameIs(pOther->pev, "player")) + return; + + m_hActivator = pOther; + + BUTTON_CODE code = ButtonResponseToTouch(); + + if ( code == BUTTON_NOTHING ) + return; + + if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) + { + // play button locked sound + PlayLockSounds(pev, &m_ls, TRUE, TRUE); + return; + } + + // Temporarily disable the touch function, until movement is finished. + SetTouch( NULL ); + + if ( code == BUTTON_RETURN ) + { + EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); + ButtonReturn(); + } + else // code == BUTTON_ACTIVATE + ButtonActivate( ); +} + +// +// Starts the button moving "in/up". +// +void CBaseButton::ButtonActivate( ) +{ + EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + + if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + { + // button is locked, play locked sound + PlayLockSounds(pev, &m_ls, TRUE, TRUE); + return; + } + else + { + // button is unlocked, play unlocked sound + PlayLockSounds(pev, &m_ls, FALSE, TRUE); + } + + ASSERT(m_toggle_state == TS_AT_BOTTOM); + m_toggle_state = TS_GOING_UP; + + SetMoveDone( &CBaseButton::TriggerAndWait ); + if (!m_fRotating) + LinearMove( m_vecPosition2, pev->speed); + else + AngularMove( m_vecAngle2, pev->speed); +} + +// +// Button has reached the "in/up" position. Activate its "targets", and pause before "popping out". +// +void CBaseButton::TriggerAndWait( void ) +{ + ASSERT(m_toggle_state == TS_GOING_UP); + + if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + return; + + m_toggle_state = TS_AT_TOP; + + // If button automatically comes back out, start it moving out. + // Else re-instate touch method + if (m_fStayPushed || FBitSet ( pev->spawnflags, SF_BUTTON_TOGGLE ) ) + { + if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! + { + // ALL buttons are now use only + SetTouch ( NULL ); + } + else + SetTouch( &CBaseButton::ButtonTouch ); + } + else + { + pev->nextthink = pev->ltime + m_flWait; + SetThink( &CBaseButton::ButtonReturn ); + } + + pev->frame = 1; // use alternate textures + + + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); +} + + +// +// Starts the button moving "out/down". +// +void CBaseButton::ButtonReturn( void ) +{ + ASSERT(m_toggle_state == TS_AT_TOP); + m_toggle_state = TS_GOING_DOWN; + + SetMoveDone( &CBaseButton::ButtonBackHome ); + if (!m_fRotating) + LinearMove( m_vecPosition1, pev->speed); + else + AngularMove( m_vecAngle1, pev->speed); + + pev->frame = 0; // use normal textures +} + + +// +// Button has returned to start state. Quiesce it. +// +void CBaseButton::ButtonBackHome( void ) +{ + ASSERT(m_toggle_state == TS_GOING_DOWN); + m_toggle_state = TS_AT_BOTTOM; + + if ( FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) + { + //EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); + } + + + if (!FStringNull(pev->target)) + { + edict_t* pentTarget = NULL; + for (;;) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); + + if (FNullEnt(pentTarget)) + break; + + if (!FClassnameIs(pentTarget, "multisource")) + continue; + CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); + + if ( pTarget ) + pTarget->Use( m_hActivator, this, USE_TOGGLE, 0 ); + } + } + +// Re-instate touch method, movement cycle is complete. + if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! + { + // All buttons are now use only + SetTouch ( NULL ); + } + else + SetTouch( &CBaseButton::ButtonTouch ); + +// reset think for a sparking button + if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) + { + SetThink ( &CBaseButton::ButtonSpark ); + pev->nextthink = gpGlobals->time + 0.5;// no hurry. + } +} + + + +// +// Rotating button (aka "lever") +// +class CRotButton : public CBaseButton +{ +public: + void Spawn( void ); +}; + +LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ); + +void CRotButton::Spawn( void ) +{ + char *pszSound; + //---------------------------------------------------- + //determine sounds for buttons + //a sound of 0 should not make a sound + //---------------------------------------------------- + pszSound = ButtonSound( m_sounds ); + PRECACHE_SOUND(pszSound); + pev->noise = ALLOC_STRING(pszSound); + + // set the axis of rotation + CBaseToggle::AxisDir( pev ); + + // check for clockwise rotation + if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) + pev->movedir = pev->movedir * -1; + + pev->movetype = MOVETYPE_PUSH; + + if ( pev->spawnflags & SF_ROTBUTTON_NOTSOLID ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + + SET_MODEL(ENT(pev), STRING(pev->model)); + + if (pev->speed == 0) + pev->speed = 40; + + if (m_flWait == 0) + m_flWait = 1; + + if (pev->health > 0) + { + pev->takedamage = DAMAGE_YES; + } + + m_toggle_state = TS_AT_BOTTOM; + m_vecAngle1 = pev->angles; + m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; + ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating button start/end positions are equal"); + + m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); + m_fRotating = TRUE; + + // if the button is flagged for USE button activation only, take away it's touch function and add a use function + if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) + { + SetTouch ( NULL ); + SetUse ( &CRotButton::ButtonUse ); + } + else // touchable button + SetTouch( &CRotButton::ButtonTouch ); + + //SetTouch( ButtonTouch ); +} + + +// Make this button behave like a door (HACKHACK) +// This will disable use and make the button solid +// rotating buttons were made SOLID_NOT by default since their were some +// collision problems with them... +#define SF_MOMENTARY_DOOR 0x0001 + +class CMomentaryRotButton : public CBaseToggle +{ +public: + void Spawn ( void ); + void KeyValue( KeyValueData *pkvd ); + virtual int ObjectCaps( void ) + { + int flags = CBaseToggle :: ObjectCaps() & (~FCAP_ACROSS_TRANSITION); + if ( pev->spawnflags & SF_MOMENTARY_DOOR ) + return flags; + return flags | FCAP_CONTINUOUS_USE; + } + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT Off( void ); + void EXPORT Return( void ); + void UpdateSelf( float value ); + void UpdateSelfReturn( float value ); + void UpdateAllButtons( float value, int start ); + + void PlaySound( void ); + void UpdateTarget( float value ); + + static CMomentaryRotButton *Instance( edict_t *pent ) { return (CMomentaryRotButton *)GET_PRIVATE(pent);}; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + int m_lastUsed; + int m_direction; + float m_returnSpeed; + vec3_t m_start; + vec3_t m_end; + int m_sounds; +}; +TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] = +{ + DEFINE_FIELD( CMomentaryRotButton, m_lastUsed, FIELD_INTEGER ), + DEFINE_FIELD( CMomentaryRotButton, m_direction, FIELD_INTEGER ), + DEFINE_FIELD( CMomentaryRotButton, m_returnSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CMomentaryRotButton, m_start, FIELD_VECTOR ), + DEFINE_FIELD( CMomentaryRotButton, m_end, FIELD_VECTOR ), + DEFINE_FIELD( CMomentaryRotButton, m_sounds, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CMomentaryRotButton, CBaseToggle ); + +LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ); + +void CMomentaryRotButton::Spawn( void ) +{ + CBaseToggle::AxisDir( pev ); + + if ( pev->speed == 0 ) + pev->speed = 100; + + if ( m_flMoveDistance < 0 ) + { + m_start = pev->angles + pev->movedir * m_flMoveDistance; + m_end = pev->angles; + m_direction = 1; // This will toggle to -1 on the first use() + m_flMoveDistance = -m_flMoveDistance; + } + else + { + m_start = pev->angles; + m_end = pev->angles + pev->movedir * m_flMoveDistance; + m_direction = -1; // This will toggle to +1 on the first use() + } + + if ( pev->spawnflags & SF_MOMENTARY_DOOR ) + pev->solid = SOLID_BSP; + else + pev->solid = SOLID_NOT; + + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL(ENT(pev), STRING(pev->model) ); + + char *pszSound = ButtonSound( m_sounds ); + PRECACHE_SOUND(pszSound); + pev->noise = ALLOC_STRING(pszSound); + m_lastUsed = 0; +} + +void CMomentaryRotButton::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "returnspeed")) + { + m_returnSpeed = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "sounds")) + { + m_sounds = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +void CMomentaryRotButton::PlaySound( void ) +{ + EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); +} + +// BUGBUG: This design causes a latentcy. When the button is retriggered, the first impulse +// will send the target in the wrong direction because the parameter is calculated based on the +// current, not future position. +void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + pev->ideal_yaw = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; + + UpdateAllButtons( pev->ideal_yaw, 1 ); + UpdateTarget( pev->ideal_yaw ); +} + +void CMomentaryRotButton::UpdateAllButtons( float value, int start ) +{ + // Update all rot buttons attached to the same target + edict_t *pentTarget = NULL; + for (;;) + { + + pentTarget = FIND_ENTITY_BY_STRING(pentTarget, "target", STRING(pev->target)); + if (FNullEnt(pentTarget)) + break; + + if ( FClassnameIs( VARS(pentTarget), "momentary_rot_button" ) ) + { + CMomentaryRotButton *pEntity = CMomentaryRotButton::Instance(pentTarget); + if ( pEntity ) + { + if ( start ) + pEntity->UpdateSelf( value ); + else + pEntity->UpdateSelfReturn( value ); + } + } + } +} + +void CMomentaryRotButton::UpdateSelf( float value ) +{ + BOOL fplaysound = FALSE; + + if ( !m_lastUsed ) + { + fplaysound = TRUE; + m_direction = -m_direction; + } + m_lastUsed = 1; + + pev->nextthink = pev->ltime + 0.1; + if ( m_direction > 0 && value >= 1.0 ) + { + pev->avelocity = g_vecZero; + pev->angles = m_end; + return; + } + else if ( m_direction < 0 && value <= 0 ) + { + pev->avelocity = g_vecZero; + pev->angles = m_start; + return; + } + + if (fplaysound) + PlaySound(); + + // HACKHACK -- If we're going slow, we'll get multiple player packets per frame, bump nexthink on each one to avoid stalling + if ( pev->nextthink < pev->ltime ) + pev->nextthink = pev->ltime + 0.1; + else + pev->nextthink += 0.1; + + pev->avelocity = (m_direction * pev->speed) * pev->movedir; + SetThink( &CMomentaryRotButton::Off ); +} + +void CMomentaryRotButton::UpdateTarget( float value ) +{ + if (!FStringNull(pev->target)) + { + edict_t* pentTarget = NULL; + for (;;) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); + if (FNullEnt(pentTarget)) + break; + CBaseEntity *pEntity = CBaseEntity::Instance(pentTarget); + if ( pEntity ) + { + pEntity->Use( this, this, USE_SET, value ); + } + } + } +} + +void CMomentaryRotButton::Off( void ) +{ + pev->avelocity = g_vecZero; + m_lastUsed = 0; + if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) + { + SetThink( &CMomentaryRotButton::Return ); + pev->nextthink = pev->ltime + 0.1; + m_direction = -1; + } + else + SetThink( NULL ); +} + +void CMomentaryRotButton::Return( void ) +{ + float value = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; + + UpdateAllButtons( value, 0 ); // This will end up calling UpdateSelfReturn() n times, but it still works right + if ( value > 0 ) + UpdateTarget( value ); +} + + +void CMomentaryRotButton::UpdateSelfReturn( float value ) +{ + if ( value <= 0 ) + { + pev->avelocity = g_vecZero; + pev->angles = m_start; + pev->nextthink = -1; + SetThink( NULL ); + } + else + { + pev->avelocity = -m_returnSpeed * pev->movedir; + pev->nextthink = pev->ltime + 0.1; + } +} + + +//---------------------------------------------------------------- +// Spark +//---------------------------------------------------------------- + +class CEnvSpark : public CBaseEntity +{ +public: + void Spawn(void); + void Precache(void); + void EXPORT SparkThink(void); + void EXPORT SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT SparkStop(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue(KeyValueData *pkvd); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + float m_flDelay; +}; + + +TYPEDESCRIPTION CEnvSpark::m_SaveData[] = +{ + DEFINE_FIELD( CEnvSpark, m_flDelay, FIELD_FLOAT), +}; + +IMPLEMENT_SAVERESTORE( CEnvSpark, CBaseEntity ); + +LINK_ENTITY_TO_CLASS(env_spark, CEnvSpark); +LINK_ENTITY_TO_CLASS(env_debris, CEnvSpark); + +void CEnvSpark::Spawn(void) +{ + SetThink( NULL ); + SetUse( NULL ); + + if (FBitSet(pev->spawnflags, 32)) // Use for on/off + { + if (FBitSet(pev->spawnflags, 64)) // Start on + { + SetThink(&CEnvSpark::SparkThink); // start sparking + SetUse(&CEnvSpark::SparkStop); // set up +USE to stop sparking + } + else + SetUse(&CEnvSpark::SparkStart); + } + else + SetThink(&CEnvSpark::SparkThink); + + pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) ); + + if (m_flDelay <= 0) + m_flDelay = 1.5; + + Precache( ); +} + + +void CEnvSpark::Precache(void) +{ + PRECACHE_SOUND( "buttons/spark1.wav" ); + PRECACHE_SOUND( "buttons/spark2.wav" ); + PRECACHE_SOUND( "buttons/spark3.wav" ); + PRECACHE_SOUND( "buttons/spark4.wav" ); + PRECACHE_SOUND( "buttons/spark5.wav" ); + PRECACHE_SOUND( "buttons/spark6.wav" ); +} + +void CEnvSpark::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "MaxDelay")) + { + m_flDelay = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "style") || + FStrEq(pkvd->szKeyName, "height") || + FStrEq(pkvd->szKeyName, "killtarget") || + FStrEq(pkvd->szKeyName, "value1") || + FStrEq(pkvd->szKeyName, "value2") || + FStrEq(pkvd->szKeyName, "value3")) + pkvd->fHandled = TRUE; + else + CBaseEntity::KeyValue( pkvd ); +} + +void EXPORT CEnvSpark::SparkThink(void) +{ + pev->nextthink = gpGlobals->time + 0.1 + RANDOM_FLOAT (0, m_flDelay); + DoSpark( pev, pev->origin ); +} + +void EXPORT CEnvSpark::SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetUse(&CEnvSpark::SparkStop); + SetThink(&CEnvSpark::SparkThink); + pev->nextthink = gpGlobals->time + (0.1 + RANDOM_FLOAT ( 0, m_flDelay)); +} + +void EXPORT CEnvSpark::SparkStop(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetUse(&CEnvSpark::SparkStart); + SetThink(NULL); +} + +#define SF_BTARGET_USE 0x0001 +#define SF_BTARGET_ON 0x0002 + +class CButtonTarget : public CBaseEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + int ObjectCaps( void ); + +}; + +LINK_ENTITY_TO_CLASS( button_target, CButtonTarget ); + +void CButtonTarget::Spawn( void ) +{ + pev->movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + SET_MODEL(ENT(pev), STRING(pev->model)); + pev->takedamage = DAMAGE_YES; + + if ( FBitSet( pev->spawnflags, SF_BTARGET_ON ) ) + pev->frame = 1; +} + +void CButtonTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, (int)pev->frame ) ) + return; + pev->frame = 1-pev->frame; + if ( pev->frame ) + SUB_UseTargets( pActivator, USE_ON, 0 ); + else + SUB_UseTargets( pActivator, USE_OFF, 0 ); +} + + +int CButtonTarget :: ObjectCaps( void ) +{ + int caps = CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; + + if ( FBitSet(pev->spawnflags, SF_BTARGET_USE) ) + return caps | FCAP_IMPULSE_USE; + else + return caps; +} + + +int CButtonTarget::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + Use( Instance(pevAttacker), this, USE_TOGGLE, 0 ); + + return 1; +} diff --git a/main/source/dlls/cbase.cpp b/main/source/dlls/cbase.cpp index c9ddbaf9..344e8c22 100644 --- a/main/source/dlls/cbase.cpp +++ b/main/source/dlls/cbase.cpp @@ -1,830 +1,830 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "client.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" - -//extern "C" void PM_Move ( struct playermove_s *ppmove, int server ); -//extern "C" void PM_Init ( struct playermove_s *ppmove ); -//extern "C" char PM_FindTextureType( char *name ); - -void PM_Move ( struct playermove_s *ppmove, int server ); -void PM_Init ( struct playermove_s *ppmove ); -char PM_FindTextureType( char *name ); - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL int g_iSkillLevel; - -static DLL_FUNCTIONS gFunctionTable = -{ - GameDLLInit, //pfnGameInit - DispatchSpawn, //pfnSpawn - DispatchThink, //pfnThink - DispatchUse, //pfnUse - DispatchTouch, //pfnTouch - DispatchBlocked, //pfnBlocked - DispatchKeyValue, //pfnKeyValue - DispatchSave, //pfnSave - DispatchRestore, //pfnRestore - DispatchObjectCollsionBox, //pfnAbsBox - - SaveWriteFields, //pfnSaveWriteFields - SaveReadFields, //pfnSaveReadFields - - SaveGlobalState, //pfnSaveGlobalState - RestoreGlobalState, //pfnRestoreGlobalState - ResetGlobalState, //pfnResetGlobalState - - ClientConnect, //pfnClientConnect - ClientDisconnect, //pfnClientDisconnect - ClientKill, //pfnClientKill - ClientPutInServer, //pfnClientPutInServer - ClientCommand, //pfnClientCommand - ClientUserInfoChanged, //pfnClientUserInfoChanged - ServerActivate, //pfnServerActivate - ServerDeactivate, //pfnServerDeactivate - - PlayerPreThink, //pfnPlayerPreThink - PlayerPostThink, //pfnPlayerPostThink - - StartFrame, //pfnStartFrame - ParmsNewLevel, //pfnParmsNewLevel - ParmsChangeLevel, //pfnParmsChangeLevel - - GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. - PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player. - - SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server - SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server - SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) - - Sys_Error, //pfnSys_Error Called when engine has encountered an error - - PM_Move, //pfnPM_Move - PM_Init, //pfnPM_Init Server version of player movement initialization - PM_FindTextureType, //pfnPM_FindTextureType - - SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client - UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client - AddToFullPack, //pfnAddToFullPack - CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. - RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding - GetWeaponData, //pfnGetWeaponData - CmdStart, //pfnCmdStart - CmdEnd, //pfnCmdEnd - ConnectionlessPacket, //pfnConnectionlessPacket - GetHullBounds, //pfnGetHullBounds - CreateInstancedBaselines, //pfnCreateInstancedBaselines - InconsistentFile, //pfnInconsistentFile - AllowLagCompensation, //pfnAllowLagCompensation -}; - -static void SetObjectCollisionBox( entvars_t *pev ); - -extern "C" { - int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) - { - if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) - { - return FALSE; - } - - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); - return TRUE; - } - - int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) - { - if ( !pFunctionTable || *interfaceVersion != INTERFACE_VERSION ) - { - // Tell engine what version we had, so it can figure out who is out of date. - *interfaceVersion = INTERFACE_VERSION; - return FALSE; - } - - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); - return TRUE; - } -} - - -int DispatchSpawn( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if (pEntity) - { - // Initialize these or entities who don't link to the world won't have anything in here - pEntity->pev->absmin = pEntity->pev->origin - Vector(1,1,1); - pEntity->pev->absmax = pEntity->pev->origin + Vector(1,1,1); - - pEntity->Spawn(); - - // Try to get the pointer again, in case the spawn function deleted the entity. - // UNDONE: Spawn() should really return a code to ask that the entity be deleted, but - // that would touch too much code for me to do that right now. - pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity ) - { - if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) - return -1; // return that this entity should be deleted - if ( pEntity->pev->flags & FL_KILLME ) - return -1; - } - - - // Handle global stuff here - if ( pEntity && pEntity->pev->globalname ) - { - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) - { - // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) - return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) - pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive - // In this level & not dead, continue on as normal - } - else - { - // Spawned entities default to 'On' - gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); -// ALERT( at_console, "Added global entity %s (%s)\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->globalname) ); - } - } - - } - - return 0; -} - -void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) -{ - if ( !pkvd || !pentKeyvalue ) - return; - - EntvarsKeyvalue( VARS(pentKeyvalue), pkvd ); - - // If the key was an entity variable, or there's no class set yet, don't look for the object, it may - // not exist yet. - if ( pkvd->fHandled || pkvd->szClassName == NULL ) - return; - - // Get the actualy entity object - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue); - - if ( !pEntity ) - return; - - pEntity->KeyValue( pkvd ); -} - - -// HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers) -// while it builds the graph -BOOL gTouchDisabled = FALSE; -void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) -{ - if ( gTouchDisabled ) - return; - - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - - if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) ) - pEntity->Touch( pOther ); -} - - -void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther); - - if (pEntity && !(pEntity->pev->flags & FL_KILLME) ) - pEntity->Use( pOther, pOther, USE_TOGGLE, 0 ); -} - -void DispatchThink( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if (pEntity) - { - if ( FBitSet( pEntity->pev->flags, FL_DORMANT ) ) - ALERT( at_error, "Dormant entity %s is thinking!!\n", STRING(pEntity->pev->classname) ); - - pEntity->Think(); - } -} - -void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked ); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - - if (pEntity) - pEntity->Blocked( pOther ); -} - -void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity && pSaveData ) - { - ENTITYTABLE *pTable = &pSaveData->pTable[ pSaveData->currentIndex ]; - - if ( pTable->pent != pent ) - ALERT( at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n" ); - - if ( pEntity->ObjectCaps() & FCAP_DONT_SAVE ) - return; - - // These don't use ltime & nextthink as times really, but we'll fudge around it. - if ( pEntity->pev->movetype == MOVETYPE_PUSH ) - { - float delta = pEntity->pev->nextthink - pEntity->pev->ltime; - pEntity->pev->ltime = gpGlobals->time; - pEntity->pev->nextthink = pEntity->pev->ltime + delta; - } - - pTable->location = pSaveData->size; // Remember entity position for file I/O - pTable->classname = pEntity->pev->classname; // Remember entity class for respawn - - CSave saveHelper( pSaveData ); - pEntity->Save( saveHelper ); - - pTable->size = pSaveData->size - pTable->location; // Size of entity block is data size written to block - } -} - - -// Find the matching global entity. Spit out an error if the designer made entities of -// different classes with the same global name -CBaseEntity *FindGlobalEntity( string_t classname, string_t globalname ) -{ - edict_t *pent = FIND_ENTITY_BY_STRING( NULL, "globalname", STRING(globalname) ); - CBaseEntity *pReturn = CBaseEntity::Instance( pent ); - if ( pReturn ) - { - if ( !FClassnameIs( pReturn->pev, STRING(classname) ) ) - { - ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname) ); - pReturn = NULL; - } - } - - return pReturn; -} - - -int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity && pSaveData ) - { - entvars_t tmpVars; - Vector oldOffset; - - CRestore restoreHelper( pSaveData ); - if ( globalEntity ) - { - CRestore tmpRestore( pSaveData ); - tmpRestore.PrecacheMode( 0 ); - tmpRestore.ReadEntVars( "ENTVARS", &tmpVars ); - - // HACKHACK - reset the save pointers, we're going to restore for real this time - pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location; - pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size; - // ------------------- - - - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( tmpVars.globalname ); - - // Don't overlay any instance of the global that isn't the latest - // pSaveData->szCurrentMapName is the level this entity is coming from - // pGlobla->levelName is the last level the global entity was active in. - // If they aren't the same, then this global update is out of date. - if ( !FStrEq( pSaveData->szCurrentMapName, pGlobal->levelName ) ) - return 0; - - // Compute the new global offset - oldOffset = pSaveData->vecLandmarkOffset; - CBaseEntity *pNewEntity = FindGlobalEntity( tmpVars.classname, tmpVars.globalname ); - if ( pNewEntity ) - { -// ALERT( at_console, "Overlay %s with %s\n", STRING(pNewEntity->pev->classname), STRING(tmpVars.classname) ); - // Tell the restore code we're overlaying a global entity from another level - restoreHelper.SetGlobalMode( 1 ); // Don't overwrite global fields - pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins; - pEntity = pNewEntity;// we're going to restore this data OVER the old entity - pent = ENT( pEntity->pev ); - // Update the global table to say that the global definition of this entity should come from this level - gGlobalState.EntityUpdate( pEntity->pev->globalname, gpGlobals->mapname ); - } - else - { - // This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below) - // or call EntityUpdate() to move it to this level, we haven't changed global state at all. - return 0; - } - - } - - if ( pEntity->ObjectCaps() & FCAP_MUST_SPAWN ) - { - pEntity->Restore( restoreHelper ); - pEntity->Spawn(); - } - else - { - pEntity->Restore( restoreHelper ); - pEntity->Precache( ); - } - - // Again, could be deleted, get the pointer again. - pEntity = (CBaseEntity *)GET_PRIVATE(pent); - -#if 0 - if ( pEntity && pEntity->pev->globalname && globalEntity ) - { - ALERT( at_console, "Global %s is %s\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->model) ); - } -#endif - - // Is this an overriding global entity (coming over the transition), or one restoring in a level - if ( globalEntity ) - { -// ALERT( at_console, "After: %f %f %f %s\n", pEntity->pev->origin.x, pEntity->pev->origin.y, pEntity->pev->origin.z, STRING(pEntity->pev->model) ); - pSaveData->vecLandmarkOffset = oldOffset; - if ( pEntity ) - { - UTIL_SetOrigin( pEntity->pev, pEntity->pev->origin ); - pEntity->OverrideReset(); - } - } - else if ( pEntity && pEntity->pev->globalname ) - { - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) - { - // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) - return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) - { - pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive - } - // In this level & not dead, continue on as normal - } - else - { - ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) ); - // Spawned entities default to 'On' - gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); - } - } - } - return 0; -} - - -void DispatchObjectCollsionBox( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if (pEntity) - { - pEntity->SetObjectCollisionBox(); - } - else - SetObjectCollisionBox( &pent->v ); -} - - -void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - CSave saveHelper( pSaveData ); - saveHelper.WriteFields( pname, pBaseData, pFields, fieldCount ); -} - - -void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - CRestore restoreHelper( pSaveData ); - restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount ); -} - - -edict_t * EHANDLE::Get( void ) -{ - if (m_pent) - { - if (m_pent->serialnumber == m_serialnumber) - return m_pent; - else - return NULL; - } - return NULL; -}; - -edict_t * EHANDLE::Set( edict_t *pent ) -{ - m_pent = pent; - if (pent) - m_serialnumber = m_pent->serialnumber; - return pent; -}; - - -EHANDLE :: operator CBaseEntity *() -{ - return (CBaseEntity *)GET_PRIVATE( Get( ) ); -}; - - -CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity) -{ - if (pEntity) - { - m_pent = ENT( pEntity->pev ); - if (m_pent) - m_serialnumber = m_pent->serialnumber; - } - else - { - m_pent = NULL; - m_serialnumber = 0; - } - return pEntity; -} - -EHANDLE :: operator int () -{ - return Get() != NULL; -} - -CBaseEntity * EHANDLE :: operator -> () -{ - return (CBaseEntity *)GET_PRIVATE( Get( ) ); -} - - -// give health -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) -{ - if (!pev->takedamage) - return 0; - -// heal - if ( pev->health >= pev->max_health ) - return 0; - - pev->health += flHealth; - - if (pev->health > pev->max_health) - pev->health = pev->max_health; - - return 1; -} - -// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH - -int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - if (!pev->takedamage) - return 0; - - // UNDONE: some entity types may be immune or resistant to some bitsDamageType - if((bitsDamageType == NS_DMG_ORGANIC) && !this->IsPlayer()) - { - return 0; - } - - // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. - // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); - } - else - // an actual missile was involved. - { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); - } - -// this global is still used for glass and other non-monster killables, along with decals. - g_vecAttackDir = vecTemp.Normalize(); - - // When players take damage, don't move target at all - -// save damage based on the target's armor level - -// figure momentum add (don't let hurt brushes or other triggers move player) - if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) && !this->IsPlayer()) - { - Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; - vecDir = vecDir.Normalize(); - - float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if (flForce > 1000.0) - flForce = 1000.0; - pev->velocity = pev->velocity + vecDir * flForce; - } - -// do the damage - pev->health -= flDamage; - - // Killed when health cast to an int is 0 - if((int)(pev->health) <= 0) - { - this->pev->health = 0.0f; - } - - if (pev->health <= 0) - { - Killed( pevAttacker, GIB_NORMAL ); - return 0; - } - - return 1; -} - - -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->takedamage = DAMAGE_NO; - pev->deadflag = DEAD_DEAD; - UTIL_Remove( this ); -} - - -CBaseEntity *CBaseEntity::GetNextTarget( void ) -{ - if ( FStringNull( pev->target ) ) - return NULL; - edict_t *pTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ); - if ( FNullEnt(pTarget) ) - return NULL; - - return Instance( pTarget ); -} - -// Global Savedata for Delay -TYPEDESCRIPTION CBaseEntity::m_SaveData[] = -{ - DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ), - - DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION ), // UNDONE: Build table of these!!! - DEFINE_FIELD( CBaseEntity, m_pfnTouch, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnUse, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ), -}; - - -int CBaseEntity::Save( CSave &save ) -{ - if ( save.WriteEntVars( "ENTVARS", pev ) ) - return save.WriteFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - - return 0; -} - -int CBaseEntity::Restore( CRestore &restore ) -{ - int status; - - status = restore.ReadEntVars( "ENTVARS", pev ); - if ( status ) - status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - - if ( pev->modelindex != 0 && !FStringNull(pev->model) ) - { - Vector mins, maxs; - mins = pev->mins; // Set model is about to destroy these - maxs = pev->maxs; - - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL(ENT(pev), STRING(pev->model)); - UTIL_SetSize(pev, mins, maxs); // Reset them - } - - return status; -} - - -// Initialize absmin & absmax to the appropriate box -void SetObjectCollisionBox( entvars_t *pev ) -{ - if ( (pev->solid == SOLID_BSP) && - (pev->angles.x || pev->angles.y|| pev->angles.z) ) - { // expand for rotation - float max, v; - int i; - - max = 0; - for (i=0 ; i<3 ; i++) - { - v = fabs( ((float *)pev->mins)[i]); - if (v > max) - max = v; - v = fabs( ((float *)pev->maxs)[i]); - if (v > max) - max = v; - } - for (i=0 ; i<3 ; i++) - { - ((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max; - ((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max; - } - } - else - { - pev->absmin = pev->origin + pev->mins; - pev->absmax = pev->origin + pev->maxs; - } - - pev->absmin.x -= 1; - pev->absmin.y -= 1; - pev->absmin.z -= 1; - pev->absmax.x += 1; - pev->absmax.y += 1; - pev->absmax.z += 1; -} - - -void CBaseEntity::SetObjectCollisionBox( void ) -{ - ::SetObjectCollisionBox( pev ); -} - - -int CBaseEntity :: Intersects( CBaseEntity *pOther ) -{ - if ( pOther->pev->absmin.x > pev->absmax.x || - pOther->pev->absmin.y > pev->absmax.y || - pOther->pev->absmin.z > pev->absmax.z || - pOther->pev->absmax.x < pev->absmin.x || - pOther->pev->absmax.y < pev->absmin.y || - pOther->pev->absmax.z < pev->absmin.z ) - return 0; - return 1; -} - -void CBaseEntity :: MakeDormant( void ) -{ - SetBits( pev->flags, FL_DORMANT ); - - // Don't touch - pev->solid = SOLID_NOT; - // Don't move - pev->movetype = MOVETYPE_NONE; - // Don't draw - SetBits( pev->effects, EF_NODRAW ); - // Don't think - pev->nextthink = 0; - // Relink - UTIL_SetOrigin( pev, pev->origin ); -} - -int CBaseEntity :: IsDormant( void ) -{ - return FBitSet( pev->flags, FL_DORMANT ); -} - -BOOL CBaseEntity :: IsInWorld( void ) -{ - // position - if (pev->origin.x >= 4096) return FALSE; - if (pev->origin.y >= 4096) return FALSE; - if (pev->origin.z >= 4096) return FALSE; - if (pev->origin.x <= -4096) return FALSE; - if (pev->origin.y <= -4096) return FALSE; - if (pev->origin.z <= -4096) return FALSE; - // speed - if (pev->velocity.x >= 2000) return FALSE; - if (pev->velocity.y >= 2000) return FALSE; - if (pev->velocity.z >= 2000) return FALSE; - if (pev->velocity.x <= -2000) return FALSE; - if (pev->velocity.y <= -2000) return FALSE; - if (pev->velocity.z <= -2000) return FALSE; - - return TRUE; -} - -int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) -{ - if ( useType != USE_TOGGLE && useType != USE_SET ) - { - if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) ) - return 0; - } - return 1; -} - - -int CBaseEntity :: DamageDecal( int bitsDamageType ) -{ - if ( pev->rendermode == kRenderTransAlpha ) - return -1; - - if ( pev->rendermode != kRenderNormal ) - return DECAL_BPROOF1; - - return DECAL_GUNSHOT1 + RANDOM_LONG(0,4); -} - - - -// NOTE: szName must be a pointer to constant memory, e.g. "monster_class" because the entity -// will keep a pointer to it after this call. -CBaseEntity * CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) -{ - edict_t *pent; - CBaseEntity *pEntity; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szName )); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in Create!\n" ); - return NULL; - } - pEntity = Instance( pent ); - if(pEntity) - { - pEntity->pev->owner = pentOwner; - pEntity->pev->origin = vecOrigin; - pEntity->pev->angles = vecAngles; - DispatchSpawn( pEntity->edict() ); - } - else - { - ALERT(at_console, "NULL CBaseEntity after non-null edict_t in CBaseEntity::Create!\n"); - REMOVE_ENTITY(ENT(pent)); - } - - return pEntity; -} - -// Compute checksum of entity for testing purposes -void CBaseEntity::AddChecksum(Checksum& inChecksum) -{ - if(this->pev) - { - // Entity index - int theEntityIndex = this->entindex(); - inChecksum.AddChecksum("CBaseEntity::EntIndexChecksum", theEntityIndex); - - // Take into account entity pos, angle - int thePositionChecksum = 5*((this->pev->origin.x + this->pev->origin.y + this->pev->origin.z)/.1f); - thePositionChecksum += 11*((this->pev->angles.x + this->pev->angles.y + this->pev->angles.z)/.1f); - inChecksum.AddChecksum("CBaseEntity::PositionChecksum", thePositionChecksum); - - // Take into account user vars - int theUserVarsChecksum = this->pev->iuser1 + 5*this->pev->iuser2 + 7*this->pev->iuser3 + 11*this->pev->iuser4; - inChecksum.AddChecksum("CBaseEntity::UserVarsChecksum", theUserVarsChecksum); - - // Take into account model? - - // Classname? - //int theClassNameChecksum = this->pev - - // Take into account rendermode, renderamt - int theRenderChecksum = this->pev->renderamt + 3*this->pev->rendermode; - inChecksum.AddChecksum("CBaseEntity::RenderChecksum", theRenderChecksum); - - // Health, takedamage - int theHealthChecksum = this->pev->takedamage + 3*this->pev->health + 7*this->pev->armorvalue; - inChecksum.AddChecksum("CBaseEntity::HealthChecksum", theHealthChecksum); - } - else - { - inChecksum.AddChecksum("CBaseEntity::NullPEV", 0); - } -} +/*** +* +* Copyright (c) 1996-2001, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "client.h" +#include "decals.h" +#include "gamerules.h" +#include "game.h" + +//extern "C" void PM_Move ( struct playermove_s *ppmove, int server ); +//extern "C" void PM_Init ( struct playermove_s *ppmove ); +//extern "C" char PM_FindTextureType( char *name ); + +void PM_Move ( struct playermove_s *ppmove, int server ); +void PM_Init ( struct playermove_s *ppmove ); +char PM_FindTextureType( char *name ); + +void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); + +extern Vector VecBModelOrigin( entvars_t* pevBModel ); +extern DLL_GLOBAL Vector g_vecAttackDir; +extern DLL_GLOBAL int g_iSkillLevel; + +static DLL_FUNCTIONS gFunctionTable = +{ + GameDLLInit, //pfnGameInit + DispatchSpawn, //pfnSpawn + DispatchThink, //pfnThink + DispatchUse, //pfnUse + DispatchTouch, //pfnTouch + DispatchBlocked, //pfnBlocked + DispatchKeyValue, //pfnKeyValue + DispatchSave, //pfnSave + DispatchRestore, //pfnRestore + DispatchObjectCollsionBox, //pfnAbsBox + + SaveWriteFields, //pfnSaveWriteFields + SaveReadFields, //pfnSaveReadFields + + SaveGlobalState, //pfnSaveGlobalState + RestoreGlobalState, //pfnRestoreGlobalState + ResetGlobalState, //pfnResetGlobalState + + ClientConnect, //pfnClientConnect + ClientDisconnect, //pfnClientDisconnect + ClientKill, //pfnClientKill + ClientPutInServer, //pfnClientPutInServer + ClientCommand, //pfnClientCommand + ClientUserInfoChanged, //pfnClientUserInfoChanged + ServerActivate, //pfnServerActivate + ServerDeactivate, //pfnServerDeactivate + + PlayerPreThink, //pfnPlayerPreThink + PlayerPostThink, //pfnPlayerPostThink + + StartFrame, //pfnStartFrame + ParmsNewLevel, //pfnParmsNewLevel + ParmsChangeLevel, //pfnParmsChangeLevel + + GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. + PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player. + + SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server + SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server + SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) + + Sys_Error, //pfnSys_Error Called when engine has encountered an error + + PM_Move, //pfnPM_Move + PM_Init, //pfnPM_Init Server version of player movement initialization + PM_FindTextureType, //pfnPM_FindTextureType + + SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client + UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client + AddToFullPack, //pfnAddToFullPack + CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. + RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding + GetWeaponData, //pfnGetWeaponData + CmdStart, //pfnCmdStart + CmdEnd, //pfnCmdEnd + ConnectionlessPacket, //pfnConnectionlessPacket + GetHullBounds, //pfnGetHullBounds + CreateInstancedBaselines, //pfnCreateInstancedBaselines + InconsistentFile, //pfnInconsistentFile + AllowLagCompensation, //pfnAllowLagCompensation +}; + +static void SetObjectCollisionBox( entvars_t *pev ); + +extern "C" { + int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) + { + if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) + { + return FALSE; + } + + memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); + return TRUE; + } + + int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) + { + if ( !pFunctionTable || *interfaceVersion != INTERFACE_VERSION ) + { + // Tell engine what version we had, so it can figure out who is out of date. + *interfaceVersion = INTERFACE_VERSION; + return FALSE; + } + + memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); + return TRUE; + } +} + + +int DispatchSpawn( edict_t *pent ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + + if (pEntity) + { + // Initialize these or entities who don't link to the world won't have anything in here + pEntity->pev->absmin = pEntity->pev->origin - Vector(1,1,1); + pEntity->pev->absmax = pEntity->pev->origin + Vector(1,1,1); + + pEntity->Spawn(); + + // Try to get the pointer again, in case the spawn function deleted the entity. + // UNDONE: Spawn() should really return a code to ask that the entity be deleted, but + // that would touch too much code for me to do that right now. + pEntity = (CBaseEntity *)GET_PRIVATE(pent); + + if ( pEntity ) + { + if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) + return -1; // return that this entity should be deleted + if ( pEntity->pev->flags & FL_KILLME ) + return -1; + } + + + // Handle global stuff here + if ( pEntity && pEntity->pev->globalname ) + { + const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); + if ( pGlobal ) + { + // Already dead? delete + if ( pGlobal->state == GLOBAL_DEAD ) + return -1; + else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) + pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive + // In this level & not dead, continue on as normal + } + else + { + // Spawned entities default to 'On' + gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); +// ALERT( at_console, "Added global entity %s (%s)\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->globalname) ); + } + } + + } + + return 0; +} + +void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) +{ + if ( !pkvd || !pentKeyvalue ) + return; + + EntvarsKeyvalue( VARS(pentKeyvalue), pkvd ); + + // If the key was an entity variable, or there's no class set yet, don't look for the object, it may + // not exist yet. + if ( pkvd->fHandled || pkvd->szClassName == NULL ) + return; + + // Get the actualy entity object + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue); + + if ( !pEntity ) + return; + + pEntity->KeyValue( pkvd ); +} + + +// HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers) +// while it builds the graph +BOOL gTouchDisabled = FALSE; +void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) +{ + if ( gTouchDisabled ) + return; + + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched); + CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); + + if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) ) + pEntity->Touch( pOther ); +} + + +void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed); + CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther); + + if (pEntity && !(pEntity->pev->flags & FL_KILLME) ) + pEntity->Use( pOther, pOther, USE_TOGGLE, 0 ); +} + +void DispatchThink( edict_t *pent ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + if (pEntity) + { + if ( FBitSet( pEntity->pev->flags, FL_DORMANT ) ) + ALERT( at_error, "Dormant entity %s is thinking!!\n", STRING(pEntity->pev->classname) ); + + pEntity->Think(); + } +} + +void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked ); + CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); + + if (pEntity) + pEntity->Blocked( pOther ); +} + +void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + + if ( pEntity && pSaveData ) + { + ENTITYTABLE *pTable = &pSaveData->pTable[ pSaveData->currentIndex ]; + + if ( pTable->pent != pent ) + ALERT( at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n" ); + + if ( pEntity->ObjectCaps() & FCAP_DONT_SAVE ) + return; + + // These don't use ltime & nextthink as times really, but we'll fudge around it. + if ( pEntity->pev->movetype == MOVETYPE_PUSH ) + { + float delta = pEntity->pev->nextthink - pEntity->pev->ltime; + pEntity->pev->ltime = gpGlobals->time; + pEntity->pev->nextthink = pEntity->pev->ltime + delta; + } + + pTable->location = pSaveData->size; // Remember entity position for file I/O + pTable->classname = pEntity->pev->classname; // Remember entity class for respawn + + CSave saveHelper( pSaveData ); + pEntity->Save( saveHelper ); + + pTable->size = pSaveData->size - pTable->location; // Size of entity block is data size written to block + } +} + + +// Find the matching global entity. Spit out an error if the designer made entities of +// different classes with the same global name +CBaseEntity *FindGlobalEntity( string_t classname, string_t globalname ) +{ + edict_t *pent = FIND_ENTITY_BY_STRING( NULL, "globalname", STRING(globalname) ); + CBaseEntity *pReturn = CBaseEntity::Instance( pent ); + if ( pReturn ) + { + if ( !FClassnameIs( pReturn->pev, STRING(classname) ) ) + { + ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname) ); + pReturn = NULL; + } + } + + return pReturn; +} + + +int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + + if ( pEntity && pSaveData ) + { + entvars_t tmpVars; + Vector oldOffset; + + CRestore restoreHelper( pSaveData ); + if ( globalEntity ) + { + CRestore tmpRestore( pSaveData ); + tmpRestore.PrecacheMode( 0 ); + tmpRestore.ReadEntVars( "ENTVARS", &tmpVars ); + + // HACKHACK - reset the save pointers, we're going to restore for real this time + pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location; + pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size; + // ------------------- + + + const globalentity_t *pGlobal = gGlobalState.EntityFromTable( tmpVars.globalname ); + + // Don't overlay any instance of the global that isn't the latest + // pSaveData->szCurrentMapName is the level this entity is coming from + // pGlobla->levelName is the last level the global entity was active in. + // If they aren't the same, then this global update is out of date. + if ( !FStrEq( pSaveData->szCurrentMapName, pGlobal->levelName ) ) + return 0; + + // Compute the new global offset + oldOffset = pSaveData->vecLandmarkOffset; + CBaseEntity *pNewEntity = FindGlobalEntity( tmpVars.classname, tmpVars.globalname ); + if ( pNewEntity ) + { +// ALERT( at_console, "Overlay %s with %s\n", STRING(pNewEntity->pev->classname), STRING(tmpVars.classname) ); + // Tell the restore code we're overlaying a global entity from another level + restoreHelper.SetGlobalMode( 1 ); // Don't overwrite global fields + pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins; + pEntity = pNewEntity;// we're going to restore this data OVER the old entity + pent = ENT( pEntity->pev ); + // Update the global table to say that the global definition of this entity should come from this level + gGlobalState.EntityUpdate( pEntity->pev->globalname, gpGlobals->mapname ); + } + else + { + // This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below) + // or call EntityUpdate() to move it to this level, we haven't changed global state at all. + return 0; + } + + } + + if ( pEntity->ObjectCaps() & FCAP_MUST_SPAWN ) + { + pEntity->Restore( restoreHelper ); + pEntity->Spawn(); + } + else + { + pEntity->Restore( restoreHelper ); + pEntity->Precache( ); + } + + // Again, could be deleted, get the pointer again. + pEntity = (CBaseEntity *)GET_PRIVATE(pent); + +#if 0 + if ( pEntity && pEntity->pev->globalname && globalEntity ) + { + ALERT( at_console, "Global %s is %s\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->model) ); + } +#endif + + // Is this an overriding global entity (coming over the transition), or one restoring in a level + if ( globalEntity ) + { +// ALERT( at_console, "After: %f %f %f %s\n", pEntity->pev->origin.x, pEntity->pev->origin.y, pEntity->pev->origin.z, STRING(pEntity->pev->model) ); + pSaveData->vecLandmarkOffset = oldOffset; + if ( pEntity ) + { + UTIL_SetOrigin( pEntity->pev, pEntity->pev->origin ); + pEntity->OverrideReset(); + } + } + else if ( pEntity && pEntity->pev->globalname ) + { + const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); + if ( pGlobal ) + { + // Already dead? delete + if ( pGlobal->state == GLOBAL_DEAD ) + return -1; + else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) + { + pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive + } + // In this level & not dead, continue on as normal + } + else + { + ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) ); + // Spawned entities default to 'On' + gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); + } + } + } + return 0; +} + + +void DispatchObjectCollsionBox( edict_t *pent ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + if (pEntity) + { + pEntity->SetObjectCollisionBox(); + } + else + SetObjectCollisionBox( &pent->v ); +} + + +void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + CSave saveHelper( pSaveData ); + saveHelper.WriteFields( pname, pBaseData, pFields, fieldCount ); +} + + +void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + CRestore restoreHelper( pSaveData ); + restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount ); +} + + +edict_t * EHANDLE::Get( void ) +{ + if (m_pent) + { + if (m_pent->serialnumber == m_serialnumber) + return m_pent; + else + return NULL; + } + return NULL; +}; + +edict_t * EHANDLE::Set( edict_t *pent ) +{ + m_pent = pent; + if (pent) + m_serialnumber = m_pent->serialnumber; + return pent; +}; + + +EHANDLE :: operator CBaseEntity *() +{ + return (CBaseEntity *)GET_PRIVATE( Get( ) ); +}; + + +CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity) +{ + if (pEntity) + { + m_pent = ENT( pEntity->pev ); + if (m_pent) + m_serialnumber = m_pent->serialnumber; + } + else + { + m_pent = NULL; + m_serialnumber = 0; + } + return pEntity; +} + +EHANDLE :: operator int () +{ + return Get() != NULL; +} + +CBaseEntity * EHANDLE :: operator -> () +{ + return (CBaseEntity *)GET_PRIVATE( Get( ) ); +} + + +// give health +int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) +{ + if (!pev->takedamage) + return 0; + +// heal + if ( pev->health >= pev->max_health ) + return 0; + + pev->health += flHealth; + + if (pev->health > pev->max_health) + pev->health = pev->max_health; + + return 1; +} + +// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH + +int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + Vector vecTemp; + + if (!pev->takedamage) + return 0; + + // UNDONE: some entity types may be immune or resistant to some bitsDamageType + if((bitsDamageType == NS_DMG_ORGANIC) && !this->IsPlayer()) + { + return 0; + } + + // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. + // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). + if ( pevAttacker == pevInflictor ) + { + vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); + } + else + // an actual missile was involved. + { + vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); + } + +// this global is still used for glass and other non-monster killables, along with decals. + g_vecAttackDir = vecTemp.Normalize(); + + // When players take damage, don't move target at all + +// save damage based on the target's armor level + +// figure momentum add (don't let hurt brushes or other triggers move player) + if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) && !this->IsPlayer()) + { + Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; + vecDir = vecDir.Normalize(); + + float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; + + if (flForce > 1000.0) + flForce = 1000.0; + pev->velocity = pev->velocity + vecDir * flForce; + } + +// do the damage + pev->health -= flDamage; + + // Killed when health cast to an int is 0 + if((int)(pev->health) <= 0) + { + this->pev->health = 0.0f; + } + + if (pev->health <= 0) + { + Killed( pevAttacker, GIB_NORMAL ); + return 0; + } + + return 1; +} + + +void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->takedamage = DAMAGE_NO; + pev->deadflag = DEAD_DEAD; + UTIL_Remove( this ); +} + + +CBaseEntity *CBaseEntity::GetNextTarget( void ) +{ + if ( FStringNull( pev->target ) ) + return NULL; + edict_t *pTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ); + if ( FNullEnt(pTarget) ) + return NULL; + + return Instance( pTarget ); +} + +// Global Savedata for Delay +TYPEDESCRIPTION CBaseEntity::m_SaveData[] = +{ + DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ), + + DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION ), // UNDONE: Build table of these!!! + DEFINE_FIELD( CBaseEntity, m_pfnTouch, FIELD_FUNCTION ), + DEFINE_FIELD( CBaseEntity, m_pfnUse, FIELD_FUNCTION ), + DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ), +}; + + +int CBaseEntity::Save( CSave &save ) +{ + if ( save.WriteEntVars( "ENTVARS", pev ) ) + return save.WriteFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); + + return 0; +} + +int CBaseEntity::Restore( CRestore &restore ) +{ + int status; + + status = restore.ReadEntVars( "ENTVARS", pev ); + if ( status ) + status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); + + if ( pev->modelindex != 0 && !FStringNull(pev->model) ) + { + Vector mins, maxs; + mins = pev->mins; // Set model is about to destroy these + maxs = pev->maxs; + + + PRECACHE_MODEL( (char *)STRING(pev->model) ); + SET_MODEL(ENT(pev), STRING(pev->model)); + UTIL_SetSize(pev, mins, maxs); // Reset them + } + + return status; +} + + +// Initialize absmin & absmax to the appropriate box +void SetObjectCollisionBox( entvars_t *pev ) +{ + if ( (pev->solid == SOLID_BSP) && + (pev->angles.x || pev->angles.y|| pev->angles.z) ) + { // expand for rotation + float max, v; + int i; + + max = 0; + for (i=0 ; i<3 ; i++) + { + v = fabs( ((float *)pev->mins)[i]); + if (v > max) + max = v; + v = fabs( ((float *)pev->maxs)[i]); + if (v > max) + max = v; + } + for (i=0 ; i<3 ; i++) + { + ((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max; + ((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max; + } + } + else + { + pev->absmin = pev->origin + pev->mins; + pev->absmax = pev->origin + pev->maxs; + } + + pev->absmin.x -= 1; + pev->absmin.y -= 1; + pev->absmin.z -= 1; + pev->absmax.x += 1; + pev->absmax.y += 1; + pev->absmax.z += 1; +} + + +void CBaseEntity::SetObjectCollisionBox( void ) +{ + ::SetObjectCollisionBox( pev ); +} + + +int CBaseEntity :: Intersects( CBaseEntity *pOther ) +{ + if ( pOther->pev->absmin.x > pev->absmax.x || + pOther->pev->absmin.y > pev->absmax.y || + pOther->pev->absmin.z > pev->absmax.z || + pOther->pev->absmax.x < pev->absmin.x || + pOther->pev->absmax.y < pev->absmin.y || + pOther->pev->absmax.z < pev->absmin.z ) + return 0; + return 1; +} + +void CBaseEntity :: MakeDormant( void ) +{ + SetBits( pev->flags, FL_DORMANT ); + + // Don't touch + pev->solid = SOLID_NOT; + // Don't move + pev->movetype = MOVETYPE_NONE; + // Don't draw + SetBits( pev->effects, EF_NODRAW ); + // Don't think + pev->nextthink = 0; + // Relink + UTIL_SetOrigin( pev, pev->origin ); +} + +int CBaseEntity :: IsDormant( void ) +{ + return FBitSet( pev->flags, FL_DORMANT ); +} + +BOOL CBaseEntity :: IsInWorld( void ) +{ + // position + if (pev->origin.x >= 4096) return FALSE; + if (pev->origin.y >= 4096) return FALSE; + if (pev->origin.z >= 4096) return FALSE; + if (pev->origin.x <= -4096) return FALSE; + if (pev->origin.y <= -4096) return FALSE; + if (pev->origin.z <= -4096) return FALSE; + // speed + if (pev->velocity.x >= 2000) return FALSE; + if (pev->velocity.y >= 2000) return FALSE; + if (pev->velocity.z >= 2000) return FALSE; + if (pev->velocity.x <= -2000) return FALSE; + if (pev->velocity.y <= -2000) return FALSE; + if (pev->velocity.z <= -2000) return FALSE; + + return TRUE; +} + +int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) +{ + if ( useType != USE_TOGGLE && useType != USE_SET ) + { + if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) ) + return 0; + } + return 1; +} + + +int CBaseEntity :: DamageDecal( int bitsDamageType ) +{ + if ( pev->rendermode == kRenderTransAlpha ) + return -1; + + if ( pev->rendermode != kRenderNormal ) + return DECAL_BPROOF1; + + return DECAL_GUNSHOT1 + RANDOM_LONG(0,4); +} + + + +// NOTE: szName must be a pointer to constant memory, e.g. "monster_class" because the entity +// will keep a pointer to it after this call. +CBaseEntity * CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) +{ + edict_t *pent; + CBaseEntity *pEntity; + + pent = CREATE_NAMED_ENTITY( MAKE_STRING( szName )); + if ( FNullEnt( pent ) ) + { + ALERT ( at_console, "NULL Ent in Create!\n" ); + return NULL; + } + pEntity = Instance( pent ); + if(pEntity) + { + pEntity->pev->owner = pentOwner; + pEntity->pev->origin = vecOrigin; + pEntity->pev->angles = vecAngles; + DispatchSpawn( pEntity->edict() ); + } + else + { + ALERT(at_console, "NULL CBaseEntity after non-null edict_t in CBaseEntity::Create!\n"); + REMOVE_ENTITY(ENT(pent)); + } + + return pEntity; +} + +// Compute checksum of entity for testing purposes +void CBaseEntity::AddChecksum(Checksum& inChecksum) +{ + if(this->pev) + { + // Entity index + int theEntityIndex = this->entindex(); + inChecksum.AddChecksum("CBaseEntity::EntIndexChecksum", theEntityIndex); + + // Take into account entity pos, angle + int thePositionChecksum = 5*((this->pev->origin.x + this->pev->origin.y + this->pev->origin.z)/.1f); + thePositionChecksum += 11*((this->pev->angles.x + this->pev->angles.y + this->pev->angles.z)/.1f); + inChecksum.AddChecksum("CBaseEntity::PositionChecksum", thePositionChecksum); + + // Take into account user vars + int theUserVarsChecksum = this->pev->iuser1 + 5*this->pev->iuser2 + 7*this->pev->iuser3 + 11*this->pev->iuser4; + inChecksum.AddChecksum("CBaseEntity::UserVarsChecksum", theUserVarsChecksum); + + // Take into account model? + + // Classname? + //int theClassNameChecksum = this->pev + + // Take into account rendermode, renderamt + int theRenderChecksum = this->pev->renderamt + 3*this->pev->rendermode; + inChecksum.AddChecksum("CBaseEntity::RenderChecksum", theRenderChecksum); + + // Health, takedamage + int theHealthChecksum = this->pev->takedamage + 3*this->pev->health + 7*this->pev->armorvalue; + inChecksum.AddChecksum("CBaseEntity::HealthChecksum", theHealthChecksum); + } + else + { + inChecksum.AddChecksum("CBaseEntity::NullPEV", 0); + } +} diff --git a/main/source/dlls/cbase.h b/main/source/dlls/cbase.h index ad2546f6..b3d1920f 100644 --- a/main/source/dlls/cbase.h +++ b/main/source/dlls/cbase.h @@ -1,839 +1,839 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -Class Hierachy - -CBaseEntity - CBaseDelay - CBaseToggle - CBaseItem - CBaseMonster - CBaseCycler - CBasePlayer - CBaseGroup -*/ -#ifndef CBASE_H -#define CBASE_H - -#include "damagetypes.h" -#include "../util/Checksum.h" -#include "../types.h" - -#define MAX_PATH_SIZE 10 // max number of nodes available for a path. - -// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions) -#define FCAP_CUSTOMSAVE 0x00000001 -#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions -#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore -#define FCAP_DONT_SAVE 0x80000000 // Don't save this -#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player -#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player -#define FCAP_ONOFF_USE 0x00000020 // can be used by the player -#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains) -#define FCAP_MASTER 0x00000080 // Can be used to "master" other entities (like multisource) - -// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! -#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions - -#include "archtypes.h" // DAL -#include "saverestore.h" -#include "schedule.h" - -#ifndef MONSTEREVENT_H -#include "monsterevent.h" -#endif - -// C functions for external declarations that call the appropriate C++ methods - -#ifndef CBASE_DLLEXPORT -#ifdef _WIN32 -#define CBASE_DLLEXPORT _declspec( dllexport ) -#else -#define CBASE_DLLEXPORT __attribute__ ((visibility("default"))) -#endif -#endif -#ifndef EXPORT -#define EXPORT CBASE_DLLEXPORT -#endif -extern "C" CBASE_DLLEXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); -extern "C" CBASE_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); - -extern int DispatchSpawn( edict_t *pent ); -extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ); -extern void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ); -extern void DispatchUse( edict_t *pentUsed, edict_t *pentOther ); -extern void DispatchThink( edict_t *pent ); -extern void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ); -extern void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ); -extern int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); -extern void DispatchObjectCollsionBox( edict_t *pent ); -extern void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); -extern void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); -extern void SaveGlobalState( SAVERESTOREDATA *pSaveData ); -extern void RestoreGlobalState( SAVERESTOREDATA *pSaveData ); -extern void ResetGlobalState( void ); - -typedef enum { USE_OFF = 0, USE_ON = 1, USE_SET = 2, USE_TOGGLE = 3 } USE_TYPE; - -extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -typedef void (CBaseEntity::*BASEPTR)(void); -typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther ); -typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -// For CLASSIFY -#define CLASS_NONE 0 -#define CLASS_MACHINE 1 -#define CLASS_PLAYER 2 -#define CLASS_HUMAN_PASSIVE 3 -#define CLASS_HUMAN_MILITARY 4 -#define CLASS_ALIEN_MILITARY 5 -#define CLASS_ALIEN_PASSIVE 6 -#define CLASS_ALIEN_MONSTER 7 -#define CLASS_ALIEN_PREY 8 -#define CLASS_ALIEN_PREDATOR 9 -#define CLASS_INSECT 10 -#define CLASS_PLAYER_ALLY 11 -#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players -#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace -#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. - -class CBaseEntity; -class CBaseMonster; -class CBasePlayerItem; -class CSquadMonster; - - -#define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn. - -// -// EHANDLE. Safe way to point to CBaseEntities who may die between frames -// -class EHANDLE -{ -private: - edict_t *m_pent; - int m_serialnumber; -public: - edict_t *Get( void ); - edict_t *Set( edict_t *pent ); - - operator int (); - - operator CBaseEntity *(); - - CBaseEntity * operator = (CBaseEntity *pEntity); - CBaseEntity * operator ->(); -}; - - -// -// Base Entity. All entity types derive from this -// -class CBaseEntity -{ -public: - // Constructor. Set engine to use C/C++ callback functions - // pointers to engine data - entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it - - // path corners - CBaseEntity *m_pGoalEnt;// path corner we are heading towards - CBaseEntity *m_pLink;// used for temporary link-list operations. - - // initialization functions - virtual void Spawn( void ) { return; } - virtual void Precache( void ) { return; } - virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; } - virtual void Activate( void ) {} - - // Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box) - virtual void SetObjectCollisionBox( void ); - -// Classify - returns the type of group (i.e, "houndeye", or "human military" so that monsters with different classnames -// still realize that they are teammates. (overridden for monsters that form groups) - virtual int Classify ( void ) { return CLASS_NONE; }; - virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died. - - - static TYPEDESCRIPTION m_SaveData[]; - - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual int GetPointValue(void) const { return 0; } - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void AwardKill( entvars_t* pevTarget) {} - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE;} - virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;} - virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;} - virtual int GetToggleState( void ) { return TS_AT_TOP; } - virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {} - virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {} - virtual BOOL AddPlayerItem( CBasePlayerItem *pItem ) { return 0; } - virtual BOOL RemovePlayerItem( CBasePlayerItem *pItem ) { return 0; } - virtual int GiveAmmo( int iAmount, char *szName, int iMax ) { return -1; }; - virtual float GetDelay( void ) { return 0; } - virtual int IsMoving( void ) { return pev->velocity != g_vecZero; } - virtual void OverrideReset( void ) {} - virtual int DamageDecal( int bitsDamageType ); - // This is ONLY used by the node graph to test movement through a door - virtual void SetToggleState( int state ) {} - virtual void StartSneaking( void ) {} - virtual void StopSneaking( void ) {} - virtual BOOL OnControls( entvars_t *pev ) { return FALSE; } - virtual BOOL IsSneaking( void ) { return FALSE; } - virtual BOOL IsAlive( void ) const { return (pev->deadflag == DEAD_NO) && pev->health > 0; } - virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; } - virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); } - virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); } - virtual BOOL IsInWorld( void ); - virtual BOOL IsPlayer( void ) { return FALSE; } - virtual BOOL IsNetClient( void ) { return FALSE; } - virtual char* TeamID( void ) { return ""; } - - // Added to allow resetting of entities when a game starts - virtual void AddChecksum(Checksum& inChecksum); - virtual void ResetEntity(void) {} - -// virtual void SetActivator( CBaseEntity *pActivator ) {} - virtual CBaseEntity *GetNextTarget( void ); - - // fundamental callbacks - void (CBaseEntity ::*m_pfnThink)(void); - void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther ); - void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther ); - - virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); }; - virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); }; - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - if (m_pfnUse) - (this->*m_pfnUse)( pActivator, pCaller, useType, value ); - } - virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); }; - - // allow engine to allocate instance data - void *operator new( size_t stAllocateBlock, entvars_t *pev ) - { - return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock); - }; - - // don't use this. -#if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher - void operator delete(void *pMem, entvars_t *pev) - { - pev->flags |= FL_KILLME; - }; -#endif - - virtual void UpdateOnRemove( void ); - - // common member functions - void EXPORT SUB_Remove( void ); - void EXPORT SUB_DoNothing( void ); - void EXPORT SUB_StartFadeOut ( void ); - void EXPORT SUB_FadeOut ( void ); - void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); } - int ShouldToggle( USE_TYPE useType, BOOL currentState ); - void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL, int inDamageType = DMG_BULLET | DMG_NEVERGIB); - Vector FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL, int shared_rand = 0 ); - - virtual CBaseEntity *Respawn( void ) { return NULL; } - - void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); - // Do the bounding boxes of these two intersect? - int Intersects( CBaseEntity *pOther ); - void MakeDormant( void ); - int IsDormant( void ); - BOOL IsLockedByMaster( void ) { return FALSE; } - - static CBaseEntity *Instance( edict_t *pent ) - { - if ( !pent ) - pent = ENT(0); - CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); - return pEnt; - } - - static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); } - static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); } - - CBaseMonster *GetMonsterPointer( entvars_t *pevMonster ) - { - CBaseEntity *pEntity = Instance( pevMonster ); - if ( pEntity ) - return pEntity->MyMonsterPointer(); - return NULL; - } - CBaseMonster *GetMonsterPointer( edict_t *pentMonster ) - { - CBaseEntity *pEntity = Instance( pentMonster ); - if ( pEntity ) - return pEntity->MyMonsterPointer(); - return NULL; - } - - - // Ugly code to lookup all functions to make sure they are exported when set. -#ifdef _DEBUG - void FunctionCheck( void *pFunction, char *name ) - { -//#ifdef _WIN32 -// if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) ) -// ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction ); -//#endif // _WIN32 - } - -#pragma warning(push) -#pragma warning(disable: 312) - - BASEPTR ThinkSet( BASEPTR func, char *name ) - { - m_pfnThink = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name ); - return func; - } - ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) - { - m_pfnTouch = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name ); - return func; - } - USEPTR UseSet( USEPTR func, char *name ) - { - m_pfnUse = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name ); - return func; - } - ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) - { - m_pfnBlocked = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name ); - return func; - } - -#pragma - -#endif - - - // virtual functions used by a few classes - - // used by monsters that are created by the MonsterMaker - virtual void UpdateOwner( void ) { return; }; - - - // - static CBaseEntity *Create(const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL ); - - virtual BOOL FBecomeProne( void ) {return FALSE;}; - edict_t *edict() { return ENT( pev ); }; - EOFFSET eoffset( ) { return OFFSET( pev ); }; - int entindex( ) { return ENTINDEX( edict() ); }; - - virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity - virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes - virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at - - virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); }; - - virtual BOOL FVisible ( CBaseEntity *pEntity ); - virtual BOOL FVisible ( const Vector &vecOrigin ); - - //We use this variables to store each ammo count. - int ammo_9mm; - int ammo_357; - int ammo_bolts; - int ammo_buckshot; - int ammo_rockets; - int ammo_uranium; - int ammo_hornets; - int ammo_argrens; - //Special stuff for grenades and satchels. - float m_flStartThrow; - float m_flReleaseThrow; - int m_chargeReady; - int m_fInAttack; - - enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; - int m_fireState; -}; - - - -// Ugly technique to override base member functions -// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a -// member function of a base class. static_cast is a sleezy way around that problem. - -#ifdef _DEBUG - -#define SetThink( a ) ThinkSet( static_cast (a), #a ) -#define SetTouch( a ) TouchSet( static_cast (a), #a ) -#define SetUse( a ) UseSet( static_cast (a), #a ) -#define SetBlocked( a ) BlockedSet( static_cast (a), #a ) - -#else - -#define SetThink( a ) m_pfnThink = static_cast (a) -#define SetTouch( a ) m_pfnTouch = static_cast (a) -#define SetUse( a ) m_pfnUse = static_cast (a) -#define SetBlocked( a ) m_pfnBlocked = static_cast (a) - -#endif - - -class CPointEntity : public CBaseEntity -{ -public: - void Spawn( void ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -private: -}; - - -typedef struct locksounds // sounds that doors and buttons make when locked/unlocked -{ - string_t sLockedSound; // sound a door makes when it's locked - string_t sLockedSentence; // sentence group played when door is locked - string_t sUnlockedSound; // sound a door makes when it's unlocked - string_t sUnlockedSentence; // sentence group played when door is unlocked - - int iLockedSentence; // which sentence in sentence group to play next - int iUnlockedSentence; // which sentence in sentence group to play next - - float flwaitSound; // time delay between playing consecutive 'locked/unlocked' sounds - float flwaitSentence; // time delay between playing consecutive sentences - BYTE bEOFLocked; // true if hit end of list of locked sentences - BYTE bEOFUnlocked; // true if hit end of list of unlocked sentences -} locksound_t; - -void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton); - -// -// MultiSouce -// - -#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned. -#define MS_MAX_TARGETS 32 - -class CMultiSource : public CPointEntity -{ -public: - void Spawn( ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return (CPointEntity::ObjectCaps() | FCAP_MASTER); } - BOOL IsTriggered( CBaseEntity *pActivator ); - void EXPORT Register( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - EHANDLE m_rgEntities[MS_MAX_TARGETS]; - int m_rgTriggered[MS_MAX_TARGETS]; - - int m_iTotal; - string_t m_globalstate; -}; - - -// -// generic Delay entity. -// -class CBaseDelay : public CBaseEntity -{ -public: - float m_flDelay; - int m_iszKillTarget; - - virtual void KeyValue( KeyValueData* pkvd); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - // common member functions - void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); - void EXPORT DelayThink( void ); -}; - - -class CBaseAnimating : public CBaseDelay -{ -public: - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // Basic Monster Animation functions - float StudioFrameAdvance( float flInterval = 0.0 ); // accumulate animation frame time from last time called until now - int GetSequenceFlags( void ); - int LookupActivity ( int activity ); - int LookupActivityHeaviest ( int activity ); - int LookupSequence ( const char *label, int queue = 0 ); - const char* LookupSequence(int inSequence); - void ResetSequenceInfo ( ); - void DispatchAnimEvents ( float flFutureInterval = 0.1 ); // Handle events that have happend since last time called up until X seconds into the future - virtual void HandleAnimEvent( MonsterEvent_t *pEvent ) { return; }; - virtual float SetBoneController ( int iController, float flValue ); - void InitBoneControllers ( void ); - float SetBlending ( int iBlender, float flValue ); - void GetBonePosition ( int iBone, Vector &origin, Vector &angles ); - void GetAutomovement( Vector &origin, Vector &angles, float flInterval = 0.1 ); - int FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ); - void GetAttachment ( int iAttachment, Vector &origin, Vector &angles ); - void SetBodygroup( int iGroup, int iValue ); - int GetBodygroup( int iGroup ); - int ExtractBbox( int sequence, float *mins, float *maxs ); - void SetSequenceBox( void ); - - // animation needs - float m_flFrameRate; // computed FPS for current sequence - float m_flGroundSpeed; // computed linear movement rate for current sequence - float m_flLastEventCheck; // last time the event list was checked - BOOL m_fSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry - BOOL m_fSequenceLoops; // true if the sequence loops - - // For performance gain during LookupSequence - char mPreviousLookupString[3][64]; - int mPreviousLookupSequence[3]; -}; - - -// -// generic Toggle entity. -// -#define SF_ITEM_USE_ONLY 256 // ITEM_USE_ONLY = BUTTON_USE_ONLY = DOOR_USE_ONLY!!! - -class CBaseToggle : public CBaseAnimating -{ -public: - void KeyValue( KeyValueData *pkvd ); - - TOGGLE_STATE m_toggle_state; - float m_flActivateFinished;//like attack_finished, but for doors - float m_flMoveDistance;// how far a door should slide or rotate - float m_flWait; - float m_flLip; - float m_flTWidth;// for plats - float m_flTLength;// for plats - - Vector m_vecPosition1; - Vector m_vecPosition2; - Vector m_vecAngle1; - Vector m_vecAngle2; - - int m_cTriggersLeft; // trigger_counter only, # of activations remaining - float m_flHeight; - EHANDLE m_hActivator; - void (CBaseToggle::*m_pfnCallWhenMoveDone)(void); - Vector m_vecFinalDest; - Vector m_vecFinalAngle; - - int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - virtual int GetToggleState( void ) { return m_toggle_state; } - virtual float GetDelay( void ) { return m_flWait; } - - // common member functions - void LinearMove( Vector vecDest, float flSpeed ); - void EXPORT LinearMoveDone( void ); - void AngularMove( Vector vecDestAngle, float flSpeed ); - void EXPORT AngularMoveDone( void ); - BOOL IsLockedByMaster( void ); - - virtual void SaveDataForReset(); - virtual void ResetEntity(); - - static float AxisValue( int flags, const Vector &angles ); - static void AxisDir( entvars_t *pev ); - static float AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ); - - string_t m_sMaster; // If this button has a master switch, this is the targetname. - // A master switch must be of the multisource type. If all - // of the switches in the multisource have been triggered, then - // the button will be allowed to operate. Otherwise, it will be - // deactivated. -private: - vec3_t mSavedOrigin; - float mSavedWait; - float mSavedLip; -}; -#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) - - -// people gib if their health is <= this at the time of death -#define GIB_HEALTH_VALUE -30 - -#define ROUTE_SIZE 8 // how many waypoints a monster can store at one time -#define MAX_OLD_ENEMIES 4 // how many old enemies to remember - -#define bits_CAP_DUCK ( 1 << 0 )// crouch -#define bits_CAP_JUMP ( 1 << 1 )// jump/leap -#define bits_CAP_STRAFE ( 1 << 2 )// strafe ( walk/run sideways) -#define bits_CAP_SQUAD ( 1 << 3 )// can form squads -#define bits_CAP_SWIM ( 1 << 4 )// proficiently navigate in water -#define bits_CAP_CLIMB ( 1 << 5 )// climb ladders/ropes -#define bits_CAP_USE ( 1 << 6 )// open doors/push buttons/pull levers -#define bits_CAP_HEAR ( 1 << 7 )// can hear forced sounds -#define bits_CAP_AUTO_DOORS ( 1 << 8 )// can trigger auto doors -#define bits_CAP_OPEN_DOORS ( 1 << 9 )// can open manual doors -#define bits_CAP_TURN_HEAD ( 1 << 10)// can turn head, always bone controller 0 - -#define bits_CAP_RANGE_ATTACK1 ( 1 << 11)// can do a range attack 1 -#define bits_CAP_RANGE_ATTACK2 ( 1 << 12)// can do a range attack 2 -#define bits_CAP_MELEE_ATTACK1 ( 1 << 13)// can do a melee attack 1 -#define bits_CAP_MELEE_ATTACK2 ( 1 << 14)// can do a melee attack 2 - -#define bits_CAP_FLY ( 1 << 15)// can fly, move all around - -#define bits_CAP_DOORS_GROUP (bits_CAP_USE | bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS) - -// used by suit voice to indicate damage sustained and repaired type to player - -// instant damage - -// time-based damage -//#define DMG_TIMEBASED (~(0x3fff)) // mask for time-based damage -#include "../common/damagetypes.h" - -#define DMG_PARALYZE (1 << 15) // slows affected creature down -#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad -#define DMG_POISON (1 << 17) // blood poisioning -#define DMG_RADIATION (1 << 18) // radiation exposure -#define DMG_DROWNRECOVER (1 << 19) // drowning recovery -#define DMG_ACID (1 << 20) // toxic chemicals or acid burns -#define DMG_SLOWBURN (1 << 21) // in an oven -#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer -#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) - -// these are the damage types that are allowed to gib corpses -#define DMG_GIB_CORPSE ( DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB ) - -// these are the damage types that have client hud art -#define DMG_SHOWNHUD (DMG_POISON | /*DMG_ACID |*/ DMG_FREEZE | DMG_SLOWFREEZE /*| DMG_DROWN*/ | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION /*| DMG_SHOCK*/) - -// NOTE: tweak these values based on gameplay feedback: - -#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage -#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval - -#define NERVEGAS_DURATION 2 -#define NERVEGAS_DAMAGE 5.0 - -#define POISON_DURATION 5 -#define POISON_DAMAGE 2.0 - -#define RADIATION_DURATION 2 -#define RADIATION_DAMAGE 1.0 - -#define ACID_DURATION 2 -#define ACID_DAMAGE 5.0 - -#define SLOWBURN_DURATION 2 -#define SLOWBURN_DAMAGE 1.0 - -#define SLOWFREEZE_DURATION 2 -#define SLOWFREEZE_DAMAGE 1.0 - - -#define itbd_Paralyze 0 -#define itbd_NerveGas 1 -#define itbd_Poison 2 -#define itbd_Radiation 3 -#define itbd_DrownRecover 4 -#define itbd_Acid 5 -#define itbd_SlowBurn 6 -#define itbd_SlowFreeze 7 -#define CDMG_TIMEBASED 8 - -// when calling KILLED(), a value that governs gib behavior is expected to be -// one of these three values -#define GIB_NORMAL 0// gib if entity was overkilled -#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc ) -#define GIB_ALWAYS 2// always gib ( Houndeye Shock, Barnacle Bite ) -// : 980 -// Use gib paramater to control death of recycled buildings -#define GIB_RECYCLED 3// always gib ( Houndeye Shock, Barnacle Bite ) -// : - -class CBaseMonster; -class CCineMonster; -class CSound; - -#include "basemonster.h" - - -char *ButtonSound( int sound ); // get string of button sound number - - -// -// Generic Button -// -class CBaseButton : public CBaseToggle -{ -public: - void Spawn( void ); - virtual void Precache( void ); - void RotSpawn( void ); - virtual void KeyValue( KeyValueData* pkvd); - - void ButtonActivate( ); - void SparkSoundCache( void ); - - void EXPORT ButtonShot( void ); - void EXPORT ButtonTouch( CBaseEntity *pOther ); - void EXPORT ButtonSpark ( void ); - void EXPORT TriggerAndWait( void ); - void EXPORT ButtonReturn( void ); - void EXPORT ButtonBackHome( void ); - void EXPORT ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - virtual void SaveDataForReset(); - virtual void ResetEntity(); - - enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN }; - BUTTON_CODE ButtonResponseToTouch( void ); - - static TYPEDESCRIPTION m_SaveData[]; - // Buttons that don't take damage can be IMPULSE used - virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); } - - BOOL m_fStayPushed; // button stays pushed in until touched again? - BOOL m_fRotating; // a rotating button? default is a sliding button. - - string_t m_strChangeTarget; // if this field is not null, this is an index into the engine string array. - // when this button is touched, it's target entity's TARGET field will be set - // to the button's ChangeTarget. This allows you to make a func_train switch paths, etc. - - locksound_t m_ls; // door lock sounds - - BYTE m_bLockedSound; // ordinals from entity selection - BYTE m_bLockedSentence; - BYTE m_bUnlockedSound; - BYTE m_bUnlockedSentence; - int m_sounds; - -private: - float mSavedSpeed; - float mSavedHealth; - vec3_t mSavedMoveDir; - int mSavedSpawnFlags; - BOOL mSavedStayPushed; - float mSavedRotation; - int mSavedFrame; - int mSavedSkin; -}; - -// -// Weapons -// - -#define BAD_WEAPON 0x00007FFF - -// -// Converts a entvars_t * to a class pointer -// It will allocate the class and entity if necessary -// -template T * GetClassPtr( T *a ) -{ - entvars_t *pev = (entvars_t *)a; - - // allocate entity if necessary - if (pev == NULL) - pev = VARS(CREATE_ENTITY()); - - // get the private data - a = (T *)GET_PRIVATE(ENT(pev)); - - if (a == NULL) - { - // allocate private data - a = new(pev) T; - a->pev = pev; - } - return a; -} - - -/* -bit_PUSHBRUSH_DATA | bit_TOGGLE_DATA -bit_MONSTER_DATA -bit_DELAY_DATA -bit_TOGGLE_DATA | bit_DELAY_DATA | bit_MONSTER_DATA -bit_PLAYER_DATA | bit_MONSTER_DATA -bit_MONSTER_DATA | CYCLER_DATA -bit_LIGHT_DATA -path_corner_data -bit_MONSTER_DATA | wildcard_data -bit_MONSTER_DATA | bit_GROUP_DATA -boid_flock_data -boid_data -CYCLER_DATA -bit_ITEM_DATA -bit_ITEM_DATA | func_hud_data -bit_TOGGLE_DATA | bit_ITEM_DATA -EOFFSET -env_sound_data -env_sound_data -push_trigger_data -*/ - -#define TRACER_FREQ 4 // Tracers fire every 4 bullets - -typedef struct _SelAmmo -{ - BYTE Ammo1Type; - BYTE Ammo1; - BYTE Ammo2Type; - BYTE Ammo2; -} SelAmmo; - - -// this moved here from world.cpp, to allow classes to be derived from it -//======================= -// CWorld -// -// This spawns first when each level begins. -//======================= -class CWorld : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); -}; - -typedef vector BaseEntityListType; - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +Class Hierachy + +CBaseEntity + CBaseDelay + CBaseToggle + CBaseItem + CBaseMonster + CBaseCycler + CBasePlayer + CBaseGroup +*/ +#ifndef CBASE_H +#define CBASE_H + +#include "damagetypes.h" +#include "../util/Checksum.h" +#include "../types.h" + +#define MAX_PATH_SIZE 10 // max number of nodes available for a path. + +// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions) +#define FCAP_CUSTOMSAVE 0x00000001 +#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions +#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore +#define FCAP_DONT_SAVE 0x80000000 // Don't save this +#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player +#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player +#define FCAP_ONOFF_USE 0x00000020 // can be used by the player +#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains) +#define FCAP_MASTER 0x00000080 // Can be used to "master" other entities (like multisource) + +// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! +#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions + +#include "archtypes.h" // DAL +#include "saverestore.h" +#include "schedule.h" + +#ifndef MONSTEREVENT_H +#include "monsterevent.h" +#endif + +// C functions for external declarations that call the appropriate C++ methods + +#ifndef CBASE_DLLEXPORT +#ifdef _WIN32 +#define CBASE_DLLEXPORT _declspec( dllexport ) +#else +#define CBASE_DLLEXPORT __attribute__ ((visibility("default"))) +#endif +#endif +#ifndef EXPORT +#define EXPORT CBASE_DLLEXPORT +#endif +extern "C" CBASE_DLLEXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); +extern "C" CBASE_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); + +extern int DispatchSpawn( edict_t *pent ); +extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ); +extern void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ); +extern void DispatchUse( edict_t *pentUsed, edict_t *pentOther ); +extern void DispatchThink( edict_t *pent ); +extern void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ); +extern void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ); +extern int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); +extern void DispatchObjectCollsionBox( edict_t *pent ); +extern void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); +extern void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); +extern void SaveGlobalState( SAVERESTOREDATA *pSaveData ); +extern void RestoreGlobalState( SAVERESTOREDATA *pSaveData ); +extern void ResetGlobalState( void ); + +typedef enum { USE_OFF = 0, USE_ON = 1, USE_SET = 2, USE_TOGGLE = 3 } USE_TYPE; + +extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +typedef void (CBaseEntity::*BASEPTR)(void); +typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther ); +typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +// For CLASSIFY +#define CLASS_NONE 0 +#define CLASS_MACHINE 1 +#define CLASS_PLAYER 2 +#define CLASS_HUMAN_PASSIVE 3 +#define CLASS_HUMAN_MILITARY 4 +#define CLASS_ALIEN_MILITARY 5 +#define CLASS_ALIEN_PASSIVE 6 +#define CLASS_ALIEN_MONSTER 7 +#define CLASS_ALIEN_PREY 8 +#define CLASS_ALIEN_PREDATOR 9 +#define CLASS_INSECT 10 +#define CLASS_PLAYER_ALLY 11 +#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players +#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace +#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. + +class CBaseEntity; +class CBaseMonster; +class CBasePlayerItem; +class CSquadMonster; + + +#define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn. + +// +// EHANDLE. Safe way to point to CBaseEntities who may die between frames +// +class EHANDLE +{ +private: + edict_t *m_pent; + int m_serialnumber; +public: + edict_t *Get( void ); + edict_t *Set( edict_t *pent ); + + operator int (); + + operator CBaseEntity *(); + + CBaseEntity * operator = (CBaseEntity *pEntity); + CBaseEntity * operator ->(); +}; + + +// +// Base Entity. All entity types derive from this +// +class CBaseEntity +{ +public: + // Constructor. Set engine to use C/C++ callback functions + // pointers to engine data + entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it + + // path corners + CBaseEntity *m_pGoalEnt;// path corner we are heading towards + CBaseEntity *m_pLink;// used for temporary link-list operations. + + // initialization functions + virtual void Spawn( void ) { return; } + virtual void Precache( void ) { return; } + virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; } + virtual void Activate( void ) {} + + // Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box) + virtual void SetObjectCollisionBox( void ); + +// Classify - returns the type of group (i.e, "houndeye", or "human military" so that monsters with different classnames +// still realize that they are teammates. (overridden for monsters that form groups) + virtual int Classify ( void ) { return CLASS_NONE; }; + virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died. + + + static TYPEDESCRIPTION m_SaveData[]; + + virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual int GetPointValue(void) const { return 0; } + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual void AwardKill( entvars_t* pevTarget) {} + virtual int BloodColor( void ) { return DONT_BLEED; } + virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); + virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE;} + virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;} + virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;} + virtual int GetToggleState( void ) { return TS_AT_TOP; } + virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {} + virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {} + virtual BOOL AddPlayerItem( CBasePlayerItem *pItem ) { return 0; } + virtual BOOL RemovePlayerItem( CBasePlayerItem *pItem ) { return 0; } + virtual int GiveAmmo( int iAmount, char *szName, int iMax ) { return -1; }; + virtual float GetDelay( void ) { return 0; } + virtual int IsMoving( void ) { return pev->velocity != g_vecZero; } + virtual void OverrideReset( void ) {} + virtual int DamageDecal( int bitsDamageType ); + // This is ONLY used by the node graph to test movement through a door + virtual void SetToggleState( int state ) {} + virtual void StartSneaking( void ) {} + virtual void StopSneaking( void ) {} + virtual BOOL OnControls( entvars_t *pev ) { return FALSE; } + virtual BOOL IsSneaking( void ) { return FALSE; } + virtual BOOL IsAlive( void ) const { return (pev->deadflag == DEAD_NO) && pev->health > 0; } + virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; } + virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); } + virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); } + virtual BOOL IsInWorld( void ); + virtual BOOL IsPlayer( void ) { return FALSE; } + virtual BOOL IsNetClient( void ) { return FALSE; } + virtual char* TeamID( void ) { return ""; } + + // Added to allow resetting of entities when a game starts + virtual void AddChecksum(Checksum& inChecksum); + virtual void ResetEntity(void) {} + +// virtual void SetActivator( CBaseEntity *pActivator ) {} + virtual CBaseEntity *GetNextTarget( void ); + + // fundamental callbacks + void (CBaseEntity ::*m_pfnThink)(void); + void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther ); + void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther ); + + virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); }; + virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); }; + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) + { + if (m_pfnUse) + (this->*m_pfnUse)( pActivator, pCaller, useType, value ); + } + virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); }; + + // allow engine to allocate instance data + void *operator new( size_t stAllocateBlock, entvars_t *pev ) + { + return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock); + }; + + // don't use this. +#if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher + void operator delete(void *pMem, entvars_t *pev) + { + pev->flags |= FL_KILLME; + }; +#endif + + virtual void UpdateOnRemove( void ); + + // common member functions + void EXPORT SUB_Remove( void ); + void EXPORT SUB_DoNothing( void ); + void EXPORT SUB_StartFadeOut ( void ); + void EXPORT SUB_FadeOut ( void ); + void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); } + int ShouldToggle( USE_TYPE useType, BOOL currentState ); + void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL, int inDamageType = DMG_BULLET | DMG_NEVERGIB); + Vector FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL, int shared_rand = 0 ); + + virtual CBaseEntity *Respawn( void ) { return NULL; } + + void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); + // Do the bounding boxes of these two intersect? + int Intersects( CBaseEntity *pOther ); + void MakeDormant( void ); + int IsDormant( void ); + BOOL IsLockedByMaster( void ) { return FALSE; } + + static CBaseEntity *Instance( edict_t *pent ) + { + if ( !pent ) + pent = ENT(0); + CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); + return pEnt; + } + + static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); } + static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); } + + CBaseMonster *GetMonsterPointer( entvars_t *pevMonster ) + { + CBaseEntity *pEntity = Instance( pevMonster ); + if ( pEntity ) + return pEntity->MyMonsterPointer(); + return NULL; + } + CBaseMonster *GetMonsterPointer( edict_t *pentMonster ) + { + CBaseEntity *pEntity = Instance( pentMonster ); + if ( pEntity ) + return pEntity->MyMonsterPointer(); + return NULL; + } + + + // Ugly code to lookup all functions to make sure they are exported when set. +#ifdef _DEBUG + void FunctionCheck( void *pFunction, char *name ) + { +//#ifdef _WIN32 +// if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) ) +// ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction ); +//#endif // _WIN32 + } + +#pragma warning(push) +#pragma warning(disable: 312) + + BASEPTR ThinkSet( BASEPTR func, char *name ) + { + m_pfnThink = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name ); + return func; + } + ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) + { + m_pfnTouch = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name ); + return func; + } + USEPTR UseSet( USEPTR func, char *name ) + { + m_pfnUse = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name ); + return func; + } + ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) + { + m_pfnBlocked = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name ); + return func; + } + +#pragma + +#endif + + + // virtual functions used by a few classes + + // used by monsters that are created by the MonsterMaker + virtual void UpdateOwner( void ) { return; }; + + + // + static CBaseEntity *Create(const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL ); + + virtual BOOL FBecomeProne( void ) {return FALSE;}; + edict_t *edict() { return ENT( pev ); }; + EOFFSET eoffset( ) { return OFFSET( pev ); }; + int entindex( ) { return ENTINDEX( edict() ); }; + + virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity + virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes + virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears + virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at + + virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); }; + + virtual BOOL FVisible ( CBaseEntity *pEntity ); + virtual BOOL FVisible ( const Vector &vecOrigin ); + + //We use this variables to store each ammo count. + int ammo_9mm; + int ammo_357; + int ammo_bolts; + int ammo_buckshot; + int ammo_rockets; + int ammo_uranium; + int ammo_hornets; + int ammo_argrens; + //Special stuff for grenades and satchels. + float m_flStartThrow; + float m_flReleaseThrow; + int m_chargeReady; + int m_fInAttack; + + enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; + int m_fireState; +}; + + + +// Ugly technique to override base member functions +// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a +// member function of a base class. static_cast is a sleezy way around that problem. + +#ifdef _DEBUG + +#define SetThink( a ) ThinkSet( static_cast (a), #a ) +#define SetTouch( a ) TouchSet( static_cast (a), #a ) +#define SetUse( a ) UseSet( static_cast (a), #a ) +#define SetBlocked( a ) BlockedSet( static_cast (a), #a ) + +#else + +#define SetThink( a ) m_pfnThink = static_cast (a) +#define SetTouch( a ) m_pfnTouch = static_cast (a) +#define SetUse( a ) m_pfnUse = static_cast (a) +#define SetBlocked( a ) m_pfnBlocked = static_cast (a) + +#endif + + +class CPointEntity : public CBaseEntity +{ +public: + void Spawn( void ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +private: +}; + + +typedef struct locksounds // sounds that doors and buttons make when locked/unlocked +{ + string_t sLockedSound; // sound a door makes when it's locked + string_t sLockedSentence; // sentence group played when door is locked + string_t sUnlockedSound; // sound a door makes when it's unlocked + string_t sUnlockedSentence; // sentence group played when door is unlocked + + int iLockedSentence; // which sentence in sentence group to play next + int iUnlockedSentence; // which sentence in sentence group to play next + + float flwaitSound; // time delay between playing consecutive 'locked/unlocked' sounds + float flwaitSentence; // time delay between playing consecutive sentences + BYTE bEOFLocked; // true if hit end of list of locked sentences + BYTE bEOFUnlocked; // true if hit end of list of unlocked sentences +} locksound_t; + +void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton); + +// +// MultiSouce +// + +#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned. +#define MS_MAX_TARGETS 32 + +class CMultiSource : public CPointEntity +{ +public: + void Spawn( ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int ObjectCaps( void ) { return (CPointEntity::ObjectCaps() | FCAP_MASTER); } + BOOL IsTriggered( CBaseEntity *pActivator ); + void EXPORT Register( void ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + EHANDLE m_rgEntities[MS_MAX_TARGETS]; + int m_rgTriggered[MS_MAX_TARGETS]; + + int m_iTotal; + string_t m_globalstate; +}; + + +// +// generic Delay entity. +// +class CBaseDelay : public CBaseEntity +{ +public: + float m_flDelay; + int m_iszKillTarget; + + virtual void KeyValue( KeyValueData* pkvd); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + // common member functions + void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); + void EXPORT DelayThink( void ); +}; + + +class CBaseAnimating : public CBaseDelay +{ +public: + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + // Basic Monster Animation functions + float StudioFrameAdvance( float flInterval = 0.0 ); // accumulate animation frame time from last time called until now + int GetSequenceFlags( void ); + int LookupActivity ( int activity ); + int LookupActivityHeaviest ( int activity ); + int LookupSequence ( const char *label, int queue = 0 ); + const char* LookupSequence(int inSequence); + void ResetSequenceInfo ( ); + void DispatchAnimEvents ( float flFutureInterval = 0.1 ); // Handle events that have happend since last time called up until X seconds into the future + virtual void HandleAnimEvent( MonsterEvent_t *pEvent ) { return; }; + virtual float SetBoneController ( int iController, float flValue ); + void InitBoneControllers ( void ); + float SetBlending ( int iBlender, float flValue ); + void GetBonePosition ( int iBone, Vector &origin, Vector &angles ); + void GetAutomovement( Vector &origin, Vector &angles, float flInterval = 0.1 ); + int FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ); + void GetAttachment ( int iAttachment, Vector &origin, Vector &angles ); + void SetBodygroup( int iGroup, int iValue ); + int GetBodygroup( int iGroup ); + int ExtractBbox( int sequence, float *mins, float *maxs ); + void SetSequenceBox( void ); + + // animation needs + float m_flFrameRate; // computed FPS for current sequence + float m_flGroundSpeed; // computed linear movement rate for current sequence + float m_flLastEventCheck; // last time the event list was checked + BOOL m_fSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry + BOOL m_fSequenceLoops; // true if the sequence loops + + // For performance gain during LookupSequence + char mPreviousLookupString[3][64]; + int mPreviousLookupSequence[3]; +}; + + +// +// generic Toggle entity. +// +#define SF_ITEM_USE_ONLY 256 // ITEM_USE_ONLY = BUTTON_USE_ONLY = DOOR_USE_ONLY!!! + +class CBaseToggle : public CBaseAnimating +{ +public: + void KeyValue( KeyValueData *pkvd ); + + TOGGLE_STATE m_toggle_state; + float m_flActivateFinished;//like attack_finished, but for doors + float m_flMoveDistance;// how far a door should slide or rotate + float m_flWait; + float m_flLip; + float m_flTWidth;// for plats + float m_flTLength;// for plats + + Vector m_vecPosition1; + Vector m_vecPosition2; + Vector m_vecAngle1; + Vector m_vecAngle2; + + int m_cTriggersLeft; // trigger_counter only, # of activations remaining + float m_flHeight; + EHANDLE m_hActivator; + void (CBaseToggle::*m_pfnCallWhenMoveDone)(void); + Vector m_vecFinalDest; + Vector m_vecFinalAngle; + + int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + virtual int GetToggleState( void ) { return m_toggle_state; } + virtual float GetDelay( void ) { return m_flWait; } + + // common member functions + void LinearMove( Vector vecDest, float flSpeed ); + void EXPORT LinearMoveDone( void ); + void AngularMove( Vector vecDestAngle, float flSpeed ); + void EXPORT AngularMoveDone( void ); + BOOL IsLockedByMaster( void ); + + virtual void SaveDataForReset(); + virtual void ResetEntity(); + + static float AxisValue( int flags, const Vector &angles ); + static void AxisDir( entvars_t *pev ); + static float AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ); + + string_t m_sMaster; // If this button has a master switch, this is the targetname. + // A master switch must be of the multisource type. If all + // of the switches in the multisource have been triggered, then + // the button will be allowed to operate. Otherwise, it will be + // deactivated. +private: + vec3_t mSavedOrigin; + float mSavedWait; + float mSavedLip; +}; +#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) + + +// people gib if their health is <= this at the time of death +#define GIB_HEALTH_VALUE -30 + +#define ROUTE_SIZE 8 // how many waypoints a monster can store at one time +#define MAX_OLD_ENEMIES 4 // how many old enemies to remember + +#define bits_CAP_DUCK ( 1 << 0 )// crouch +#define bits_CAP_JUMP ( 1 << 1 )// jump/leap +#define bits_CAP_STRAFE ( 1 << 2 )// strafe ( walk/run sideways) +#define bits_CAP_SQUAD ( 1 << 3 )// can form squads +#define bits_CAP_SWIM ( 1 << 4 )// proficiently navigate in water +#define bits_CAP_CLIMB ( 1 << 5 )// climb ladders/ropes +#define bits_CAP_USE ( 1 << 6 )// open doors/push buttons/pull levers +#define bits_CAP_HEAR ( 1 << 7 )// can hear forced sounds +#define bits_CAP_AUTO_DOORS ( 1 << 8 )// can trigger auto doors +#define bits_CAP_OPEN_DOORS ( 1 << 9 )// can open manual doors +#define bits_CAP_TURN_HEAD ( 1 << 10)// can turn head, always bone controller 0 + +#define bits_CAP_RANGE_ATTACK1 ( 1 << 11)// can do a range attack 1 +#define bits_CAP_RANGE_ATTACK2 ( 1 << 12)// can do a range attack 2 +#define bits_CAP_MELEE_ATTACK1 ( 1 << 13)// can do a melee attack 1 +#define bits_CAP_MELEE_ATTACK2 ( 1 << 14)// can do a melee attack 2 + +#define bits_CAP_FLY ( 1 << 15)// can fly, move all around + +#define bits_CAP_DOORS_GROUP (bits_CAP_USE | bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS) + +// used by suit voice to indicate damage sustained and repaired type to player + +// instant damage + +// time-based damage +//#define DMG_TIMEBASED (~(0x3fff)) // mask for time-based damage +#include "../common/damagetypes.h" + +#define DMG_PARALYZE (1 << 15) // slows affected creature down +#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +#define DMG_POISON (1 << 17) // blood poisioning +#define DMG_RADIATION (1 << 18) // radiation exposure +#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1 << 21) // in an oven +#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer +#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) + +// these are the damage types that are allowed to gib corpses +#define DMG_GIB_CORPSE ( DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB ) + +// these are the damage types that have client hud art +#define DMG_SHOWNHUD (DMG_POISON | /*DMG_ACID |*/ DMG_FREEZE | DMG_SLOWFREEZE /*| DMG_DROWN*/ | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION /*| DMG_SHOCK*/) + +// NOTE: tweak these values based on gameplay feedback: + +#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage +#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval + +#define NERVEGAS_DURATION 2 +#define NERVEGAS_DAMAGE 5.0 + +#define POISON_DURATION 5 +#define POISON_DAMAGE 2.0 + +#define RADIATION_DURATION 2 +#define RADIATION_DAMAGE 1.0 + +#define ACID_DURATION 2 +#define ACID_DAMAGE 5.0 + +#define SLOWBURN_DURATION 2 +#define SLOWBURN_DAMAGE 1.0 + +#define SLOWFREEZE_DURATION 2 +#define SLOWFREEZE_DAMAGE 1.0 + + +#define itbd_Paralyze 0 +#define itbd_NerveGas 1 +#define itbd_Poison 2 +#define itbd_Radiation 3 +#define itbd_DrownRecover 4 +#define itbd_Acid 5 +#define itbd_SlowBurn 6 +#define itbd_SlowFreeze 7 +#define CDMG_TIMEBASED 8 + +// when calling KILLED(), a value that governs gib behavior is expected to be +// one of these three values +#define GIB_NORMAL 0// gib if entity was overkilled +#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc ) +#define GIB_ALWAYS 2// always gib ( Houndeye Shock, Barnacle Bite ) +// : 980 +// Use gib paramater to control death of recycled buildings +#define GIB_RECYCLED 3// always gib ( Houndeye Shock, Barnacle Bite ) +// : + +class CBaseMonster; +class CCineMonster; +class CSound; + +#include "basemonster.h" + + +char *ButtonSound( int sound ); // get string of button sound number + + +// +// Generic Button +// +class CBaseButton : public CBaseToggle +{ +public: + void Spawn( void ); + virtual void Precache( void ); + void RotSpawn( void ); + virtual void KeyValue( KeyValueData* pkvd); + + void ButtonActivate( ); + void SparkSoundCache( void ); + + void EXPORT ButtonShot( void ); + void EXPORT ButtonTouch( CBaseEntity *pOther ); + void EXPORT ButtonSpark ( void ); + void EXPORT TriggerAndWait( void ); + void EXPORT ButtonReturn( void ); + void EXPORT ButtonBackHome( void ); + void EXPORT ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + virtual void SaveDataForReset(); + virtual void ResetEntity(); + + enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN }; + BUTTON_CODE ButtonResponseToTouch( void ); + + static TYPEDESCRIPTION m_SaveData[]; + // Buttons that don't take damage can be IMPULSE used + virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); } + + BOOL m_fStayPushed; // button stays pushed in until touched again? + BOOL m_fRotating; // a rotating button? default is a sliding button. + + string_t m_strChangeTarget; // if this field is not null, this is an index into the engine string array. + // when this button is touched, it's target entity's TARGET field will be set + // to the button's ChangeTarget. This allows you to make a func_train switch paths, etc. + + locksound_t m_ls; // door lock sounds + + BYTE m_bLockedSound; // ordinals from entity selection + BYTE m_bLockedSentence; + BYTE m_bUnlockedSound; + BYTE m_bUnlockedSentence; + int m_sounds; + +private: + float mSavedSpeed; + float mSavedHealth; + vec3_t mSavedMoveDir; + int mSavedSpawnFlags; + BOOL mSavedStayPushed; + float mSavedRotation; + int mSavedFrame; + int mSavedSkin; +}; + +// +// Weapons +// + +#define BAD_WEAPON 0x00007FFF + +// +// Converts a entvars_t * to a class pointer +// It will allocate the class and entity if necessary +// +template T * GetClassPtr( T *a ) +{ + entvars_t *pev = (entvars_t *)a; + + // allocate entity if necessary + if (pev == NULL) + pev = VARS(CREATE_ENTITY()); + + // get the private data + a = (T *)GET_PRIVATE(ENT(pev)); + + if (a == NULL) + { + // allocate private data + a = new(pev) T; + a->pev = pev; + } + return a; +} + + +/* +bit_PUSHBRUSH_DATA | bit_TOGGLE_DATA +bit_MONSTER_DATA +bit_DELAY_DATA +bit_TOGGLE_DATA | bit_DELAY_DATA | bit_MONSTER_DATA +bit_PLAYER_DATA | bit_MONSTER_DATA +bit_MONSTER_DATA | CYCLER_DATA +bit_LIGHT_DATA +path_corner_data +bit_MONSTER_DATA | wildcard_data +bit_MONSTER_DATA | bit_GROUP_DATA +boid_flock_data +boid_data +CYCLER_DATA +bit_ITEM_DATA +bit_ITEM_DATA | func_hud_data +bit_TOGGLE_DATA | bit_ITEM_DATA +EOFFSET +env_sound_data +env_sound_data +push_trigger_data +*/ + +#define TRACER_FREQ 4 // Tracers fire every 4 bullets + +typedef struct _SelAmmo +{ + BYTE Ammo1Type; + BYTE Ammo1; + BYTE Ammo2Type; + BYTE Ammo2; +} SelAmmo; + + +// this moved here from world.cpp, to allow classes to be derived from it +//======================= +// CWorld +// +// This spawns first when each level begins. +//======================= +class CWorld : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); +}; + +typedef vector BaseEntityListType; + +#endif diff --git a/main/source/dlls/cbasedoor.h b/main/source/dlls/cbasedoor.h index c47da00f..cbf41054 100644 --- a/main/source/dlls/cbasedoor.h +++ b/main/source/dlls/cbasedoor.h @@ -1,104 +1,104 @@ -#ifndef CBASE_DOOR_H -#define CBASE_DOOR_H - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" - -class CBaseDoor : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - virtual void KeyValue( KeyValueData *pkvd ); - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void Blocked( CBaseEntity *pOther ); - - - virtual int ObjectCaps( void ) - { - if (pev->spawnflags & SF_ITEM_USE_ONLY) - return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; - else - return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); - }; - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - virtual void ResetEntity(); - virtual void SetToggleState( int state ); - - // used to selectivly override defaults - void EXPORT DoorTouch( CBaseEntity *pOther ); - - // local functions - int DoorActivate( ); - void EXPORT DoorGoUp( void ); - void EXPORT DoorGoDown( void ); - void EXPORT DoorHitTop( void ); - void EXPORT DoorHitBottom( void ); - - BYTE m_bHealthValue;// some doors are medi-kit doors, they give players health - - BYTE m_bMoveSnd; // sound a door makes while moving - BYTE m_bStopSnd; // sound a door makes when it stops - - locksound_t m_ls; // door lock sounds - - BYTE m_bLockedSound; // ordinals from entity selection - BYTE m_bLockedSentence; - BYTE m_bUnlockedSound; - BYTE m_bUnlockedSentence; - -}; - -/*QUAKED FuncRotDoorSpawn (0 .5 .8) ? START_OPEN REVERSE -DOOR_DONT_LINK TOGGLE X_AXIS Y_AXIS -if two doors touch, they are assumed to be connected and operate as -a unit. - -TOGGLE causes the door to wait in both the start and end states for -a trigger event. - -START_OPEN causes the door to move to its destination when spawned, -and operate in reverse. It is used to temporarily or permanently -close off an area when triggered (not usefull for touch or -takedamage doors). - -You need to have an origin brush as part of this entity. The -center of that brush will be -the point around which it is rotated. It will rotate around the Z -axis by default. You can -check either the X_AXIS or Y_AXIS box to change that. - -"distance" is how many degrees the door will be rotated. -"speed" determines how fast the door moves; default value is 100. - -REVERSE will cause the door to rotate in the opposite direction. - -"angle" determines the opening direction -"targetname" if set, no touch field will be spawned and a remote -button or trigger field activates the door. -"health" if set, door must be shot open -"speed" movement speed (100 default) -"wait" wait before returning (3 default, -1 = never return) -"dmg" damage to inflict when blocked (2 default) -"sounds" -0) no sound -1) stone -2) base -3) stone chain -4) screechy metal -*/ -class CRotDoor : public CBaseDoor -{ -public: - void Spawn( void ); - virtual void SetToggleState( int state ); -}; - - +#ifndef CBASE_DOOR_H +#define CBASE_DOOR_H + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "doors.h" + +class CBaseDoor : public CBaseToggle +{ +public: + void Spawn( void ); + void Precache( void ); + virtual void KeyValue( KeyValueData *pkvd ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void Blocked( CBaseEntity *pOther ); + + + virtual int ObjectCaps( void ) + { + if (pev->spawnflags & SF_ITEM_USE_ONLY) + return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; + else + return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); + }; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + virtual void ResetEntity(); + virtual void SetToggleState( int state ); + + // used to selectivly override defaults + void EXPORT DoorTouch( CBaseEntity *pOther ); + + // local functions + int DoorActivate( ); + void EXPORT DoorGoUp( void ); + void EXPORT DoorGoDown( void ); + void EXPORT DoorHitTop( void ); + void EXPORT DoorHitBottom( void ); + + BYTE m_bHealthValue;// some doors are medi-kit doors, they give players health + + BYTE m_bMoveSnd; // sound a door makes while moving + BYTE m_bStopSnd; // sound a door makes when it stops + + locksound_t m_ls; // door lock sounds + + BYTE m_bLockedSound; // ordinals from entity selection + BYTE m_bLockedSentence; + BYTE m_bUnlockedSound; + BYTE m_bUnlockedSentence; + +}; + +/*QUAKED FuncRotDoorSpawn (0 .5 .8) ? START_OPEN REVERSE +DOOR_DONT_LINK TOGGLE X_AXIS Y_AXIS +if two doors touch, they are assumed to be connected and operate as +a unit. + +TOGGLE causes the door to wait in both the start and end states for +a trigger event. + +START_OPEN causes the door to move to its destination when spawned, +and operate in reverse. It is used to temporarily or permanently +close off an area when triggered (not usefull for touch or +takedamage doors). + +You need to have an origin brush as part of this entity. The +center of that brush will be +the point around which it is rotated. It will rotate around the Z +axis by default. You can +check either the X_AXIS or Y_AXIS box to change that. + +"distance" is how many degrees the door will be rotated. +"speed" determines how fast the door moves; default value is 100. + +REVERSE will cause the door to rotate in the opposite direction. + +"angle" determines the opening direction +"targetname" if set, no touch field will be spawned and a remote +button or trigger field activates the door. +"health" if set, door must be shot open +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return) +"dmg" damage to inflict when blocked (2 default) +"sounds" +0) no sound +1) stone +2) base +3) stone chain +4) screechy metal +*/ +class CRotDoor : public CBaseDoor +{ +public: + void Spawn( void ); + virtual void SetToggleState( int state ); +}; + + #endif \ No newline at end of file diff --git a/main/source/dlls/cdll_dll.h b/main/source/dlls/cdll_dll.h index 51be618c..b1249fcd 100644 --- a/main/source/dlls/cdll_dll.h +++ b/main/source/dlls/cdll_dll.h @@ -1,47 +1,47 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cdll_dll.h - -// this file is included by both the game-dll and the client-dll, - -#ifndef CDLL_DLL_H -#define CDLL_DLL_H - -#define MAX_WEAPONS 32 // ??? - -#define MAX_WEAPON_SLOTS 5 // hud item selection slots -#define MAX_ITEM_TYPES 6 // hud item selection slots - -#define MAX_ITEMS 5 // hard coded item types - -#define HIDEHUD_WEAPONS ( 1<<0 ) -#define HIDEHUD_FLASHLIGHT ( 1<<1 ) -#define HIDEHUD_ALL ( 1<<2 ) -#define HIDEHUD_HEALTH ( 1<<3 ) -#define HIDEHUD_CHAT ( 1<<4 ) - -#define MAX_AMMO_TYPES 32 // ??? -#define MAX_AMMO_SLOTS 32 // not really slots - -#define HUD_PRINTNOTIFY 1 -#define HUD_PRINTCONSOLE 2 -#define HUD_PRINTTALK 3 -#define HUD_PRINTCENTER 4 - - -#define WEAPON_SUIT 31 - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cdll_dll.h + +// this file is included by both the game-dll and the client-dll, + +#ifndef CDLL_DLL_H +#define CDLL_DLL_H + +#define MAX_WEAPONS 32 // ??? + +#define MAX_WEAPON_SLOTS 5 // hud item selection slots +#define MAX_ITEM_TYPES 6 // hud item selection slots + +#define MAX_ITEMS 5 // hard coded item types + +#define HIDEHUD_WEAPONS ( 1<<0 ) +#define HIDEHUD_FLASHLIGHT ( 1<<1 ) +#define HIDEHUD_ALL ( 1<<2 ) +#define HIDEHUD_HEALTH ( 1<<3 ) +#define HIDEHUD_CHAT ( 1<<4 ) + +#define MAX_AMMO_TYPES 32 // ??? +#define MAX_AMMO_SLOTS 32 // not really slots + +#define HUD_PRINTNOTIFY 1 +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 + + +#define WEAPON_SUIT 31 + #endif \ No newline at end of file diff --git a/main/source/dlls/cfuncwall.h b/main/source/dlls/cfuncwall.h index a8e4d2dd..9f9c500f 100644 --- a/main/source/dlls/cfuncwall.h +++ b/main/source/dlls/cfuncwall.h @@ -1,22 +1,22 @@ -#ifndef CFUNC_WALL_H -#define CFUNC_WALL_H - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" - -/*QUAKED func_wall (0 .5 .8) ? -This is just a solid wall if not inhibited -*/ -class CFuncWall : public CBaseEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - +#ifndef CFUNC_WALL_H +#define CFUNC_WALL_H + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "doors.h" + +/*QUAKED func_wall (0 .5 .8) ? +This is just a solid wall if not inhibited +*/ +class CFuncWall : public CBaseEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + // Bmodels don't go across transitions + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/client.cpp b/main/source/dlls/client.cpp index f14503c8..2a2b6402 100644 --- a/main/source/dlls/client.cpp +++ b/main/source/dlls/client.cpp @@ -1,2930 +1,2930 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to -// have one without a hardcoded player.mdl in tf_client.cpp -// -//===== client.cpp ======================================================== -// -// client/server game specific stuff -// -// $Workfile: client.cpp $ -// $Date: 2002/11/22 21:09:09 $ -// -//------------------------------------------------------------------------------- -// $Log: client.cpp,v $ -// Revision 1.69 2002/11/22 21:09:09 Flayra -// - Added "lastinv" command back in -// - mp_consistency changes -// -// Revision 1.68 2002/11/15 23:31:01 Flayra -// - Added "ready" verification for tourny mode -// -// Revision 1.67 2002/11/15 05:08:31 Flayra -// - Little tweak for refinery -// -// Revision 1.66 2002/11/15 04:48:40 Flayra -// - Oops -// -// Revision 1.65 2002/11/15 04:41:32 Flayra -// - Big performance improvements for AddToFullPack (whew) -// -// Revision 1.64 2002/11/12 02:17:48 Flayra -// - Renamed "avhplayer" to "player" -// - Tweaked enhanced sight to actually be useful at lower levels -// -// Revision 1.63 2002/11/03 04:53:20 Flayra -// - AddToFullPack optimizations and cleanup -// -// Revision 1.62 2002/10/25 21:50:01 Flayra -// - New attempted fix for overflows. Propagate skin and playerclass in new way, so entities outside the ready room aren't propagated to all clients that go back to the ready room immediately on game end. -// -// Revision 1.61 2002/10/24 21:16:10 Flayra -// - Log Sys_Errors -// - Allow players to change their name before they first leave the ready room -// -// Revision 1.60 2002/10/20 17:25:04 Flayra -// - Redid performance improvement (agh) -// -// Revision 1.59 2002/10/20 16:34:09 Flayra -// - Returned code back to normal -// -// Revision 1.58 2002/10/19 22:33:48 Flayra -// - Various server optimizations -// -// Revision 1.57 2002/10/18 22:14:23 Flayra -// - Server optimizations (untested though, may need backing out) -// -// Revision 1.56 2002/10/16 00:38:50 Flayra -// - Queue up name change until end of game -// - Removed precaching of unneeded sounds -// - Optimized AvHDetermineVisibility (being called 1000s of times per tick) -// -// Revision 1.55 2002/10/03 18:27:39 Flayra -// - Moved order completion sounds into HUD sounds -// -// Revision 1.54 2002/09/25 20:37:53 Flayra -// - Precache more sayings -// -// Revision 1.53 2002/09/23 22:01:02 Flayra -// - Propagate skin -// - Don't treat unclaimed hives at world objects (even though team is 0) for visibility purposes -// - Added heavy model -// - Removed old mapper build preprocessor directives -// -// Revision 1.52 2002/08/31 18:01:17 Flayra -// - Work at VALVe -// -// Revision 1.51 2002/08/16 02:24:31 Flayra -// - Removed "give" cheat -// -// Revision 1.50 2002/08/09 00:15:46 Flayra -// - Removed behavior where "drop" would drop alien weapons in a disconcerting manner -// -// Revision 1.49 2002/07/25 16:50:15 flayra -// - Linux build changes -// -// Revision 1.48 2002/07/24 18:46:19 Flayra -// - Linux and scripting changes -// -// Revision 1.47 2002/07/23 16:46:38 Flayra -// - Added power-armor drawing, tweaked invul drawing -// -// Revision 1.46 2002/07/10 14:36:21 Flayra -// - .mp3 and particle fixes -// -// Revision 1.45 2002/07/08 16:38:57 Flayra -// - Draw invulnerable players differently -// -//=============================================================================== -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "player.h" -#include "spectator.h" -#include "client.h" -#include "soundent.h" -#include "gamerules.h" -#include "game.h" -#include "../engine/customentity.h" -#include "weapons.h" -#include "../common/weaponinfo.h" -#include "../common/usercmd.h" -#include "../common/netadr.h" -#include "../util/nowarnings.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHSoundListManager.h" -#include "game.h" -#include "../mod/AvHParticleTemplateServer.h" -#include "../mod/AvHMarineEquipmentConstants.h" -#include "../mod/AvHSpecials.h" -#include "../util/Zassert.h" -#include "cbasedoor.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHMovementUtil.h" -#include "../mod/AvHSoundConstants.h" -#include "../mod/AvHHulls.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHSharedUtil.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHAlienEquipmentConstants.h" -#include "triggers.h" -#include "../util/MathUtil.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHCloakable.h" -#include "../mod/AvHAlienAbilityConstants.h" -#include "../mod/AvHNetworkMessages.h" -#include "../mod/AvHNexusServer.h" - -#include "../game_shared/voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - -extern AvHSoundListManager gSoundListManager; - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL int g_iSkillLevel; -extern DLL_GLOBAL ULONG g_ulFrameCount; - -extern void CopyToBodyQue(entvars_t* pev); -extern int g_teamplay; - -/* - * used by kill command and disconnect command - * ROBIN: Moved here from player.cpp, to allow multiple player models - */ -void set_suicide_frame(entvars_t* pev) -{ - if (!FStrEq(STRING(pev->model), "models/player.mdl")) - return; // allready gibbed - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - pev->deadflag = DEAD_DEAD; - pev->nextthink = -1; -} - - -/* -=========== -LogStringForPlayer - -generates string for player event logging - KGP -============ -*/ - -std::string GetLogStringForPlayer( edict_t *pEntity ) -{ - // outputs "netname" if g_teamplay - // or "netname" if not g_teamplay - std::string result = "\""; - result += STRING( pEntity->v.netname ); - result += "<"; - result += MakeStringFromInt( GETPLAYERUSERID( pEntity ) ); - result += "><"; - result += AvHSUGetPlayerAuthIDString( pEntity ).c_str(); - result += "><"; - result += AvHSUGetTeamName( pEntity->v.team ); - result += ">\""; - return result; -} - -/* -=========== -ClientConnect - -called when a player connects to a server -============ -*/ -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); - - // a client connecting during an intermission can cause problems - // if (intermission_running) - // ExitIntermission (); - -} - - -/* -=========== -ClientDisconnect - - called when a player disconnects from a server - - GLOBALS ASSUMED SET: g_fGameOver - ============ -*/ -void ClientDisconnect( edict_t *pEntity ) -{ - if (g_fGameOver) - return; - - char text[256]; - sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) ); - - CBaseEntity* theBaseEntity = CBaseEntity::Instance(ENT(pEntity)); - UTIL_SayTextAll(text, theBaseEntity); - - CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); - { - // since this client isn't around to think anymore, reset their sound. - if ( pSound ) - { - pSound->Reset(); - } - } - - // since the edict doesn't get deleted, fix it so it doesn't interfere. - pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim - pEntity->v.solid = SOLID_NOT;// nonsolid - UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin ); - - g_pGameRules->ClientDisconnected( pEntity ); - - //: If this isnt set, clients around this player will crash. - pEntity->v.effects |= EF_NODRAW; -} - - -// called by ClientKill and DeadThink -void respawn(entvars_t* pev, BOOL fCopyCorpse) -{ - // AVH isn't dm, coop or single-player. - //if (gpGlobals->coop || gpGlobals->deathmatch) - //{ - if ( fCopyCorpse ) - { - // make a copy of the dead body for appearances sake - CopyToBodyQue(pev); - } - - // respawn player - GetClassPtr( (AvHPlayer *)pev)->Spawn( ); - //} - //else - //{ // restart the entire server - // SERVER_COMMAND("reload\n"); - //} -} - -/* -============ -ClientKill - -Player entered the suicide command - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -============ -*/ -void ClientKill( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - - CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); - - //if(GetGameRules()->GetCheatsEnabled()) - //{ - if ( pl->m_fNextSuicideTime > gpGlobals->time ) - return; // prevent suiciding too ofter - - pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding - - bool theIsCombatModeForSuicide = GetGameRules()->GetIsCombatMode(); - - #ifdef DEBUG - if(GetGameRules()->GetIsCombatMode()) - { - theIsCombatModeForSuicide = false; - } - #endif - - bool theCanSuicide = GetGameRules()->CanPlayerBeKilled(pl) && !theIsCombatModeForSuicide; - - if(theCanSuicide) - { - pl->Suicide(); - - // pev->modelindex = g_ulModelIndexPlayer; - // pev->frags -= 2; // extra penalty - // respawn( pev ); - } - //} -} - -/* -=========== -ClientPutInServer - -called each time a player is spawned -============ -*/ -void ClientPutInServer( edict_t *pEntity ) -{ - //CBasePlayer *pPlayer; - AvHPlayer *pPlayer; - - entvars_t *pev = &pEntity->v; - - if(pev->flags & FL_PROXY) - { - ALERT(at_logged, "Player with FL_PROXY put in server.\n"); - } - - if(pev->flags & FL_PROXY) - { - pev->flags |= FL_PROXY; - } - - pPlayer = GetClassPtr((AvHPlayer *)pev); - pPlayer->SetCustomDecalFrames(-1); // Assume none; - - // Allocate a CBasePlayer for pev, and call spawn - pPlayer->SetPlayMode(PLAYMODE_READYROOM); - //pPlayer->Spawn(); - - // Reset interpolation during first frame - pPlayer->pev->effects |= EF_NOINTERP; -} - -//// HOST_SAY -// String comes in as -// say blah blah blah -// or as -// blah blah blah -// -void Host_Say( edict_t *pEntity, int teamonly ) -{ - AvHPlayer* client; - AvHPlayer* theTalkingPlayer = dynamic_cast(CBaseEntity::Instance(pEntity)); - int j; - char* p; - char text[256]; - char szTemp[256]; - const char* cpSay = "say"; - const char* cpSayTeam = "say_team"; - const char* pcmd = CMD_ARGV(0); - bool theTalkerInReadyRoom = theTalkingPlayer->GetInReadyRoom(); - //bool theTalkerIsObserver = (theTalkingPlayer->GetPlayMode() == PLAYMODE_OBSERVER) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT); - - // We can get a raw string now, without the "say " prepended - if ( CMD_ARGC() == 0 ) - return; - - //Not yet. - if ( theTalkingPlayer->m_flNextChatTime > gpGlobals->time ) - return; - - if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) - { - if ( CMD_ARGC() >= 2 ) - { - p = (char *)CMD_ARGS(); - - if(GetGameRules()->GetIsTournamentMode() && !GetGameRules()->GetGameStarted()) - { - if(!strcmp(CMD_ARGV(1), kReadyNotification)) - { - // Team is ready - AvHTeam* theTeam = GetGameRules()->GetTeam((AvHTeamNumber)(pEntity->v.team)); - if(theTeam && !theTeam->GetIsReady()) - { - theTeam->SetIsReady(); - } - } - else if (!strcmp(CMD_ARGV(1), kNotReadyNotification)) - { - // Team is no longer ready - AvHTeam* theTeam = GetGameRules()->GetTeam((AvHTeamNumber)(pEntity->v.team)); - if(theTeam && theTeam->GetIsReady()) - { - theTeam->SetIsReady(false); - } - } - } - } - else - { - // say with a blank message, nothing to do - return; - } - } - else // Raw text, need to prepend argv[0] - { - if ( CMD_ARGC() >= 2 ) - { - sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); - } - else - { - // Just a one word command, use the first word...sigh - sprintf( szTemp, "%s", ( char * )pcmd ); - } - p = szTemp; - } - -// remove quotes if present - if (*p == '"') - { - p++; - p[strlen(p)-1] = 0; - } - -// make sure the text has content - char *pc=p; - for ( pc = p; pc != NULL && *pc != 0; pc++ ) - { - if ( isprint( *pc ) && !isspace( *pc ) ) - { - pc = NULL; // we've found an alphanumeric character, so text is valid - break; - } - } - if ( pc != NULL ) - return; // no character found, so say nothing - -// turn on color set 2 (color on, no sound) - if ( teamonly ) - sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); - else - sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); - - j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator - if ( (int)strlen(p) > j ) - p[j] = 0; - - strcat( text, p ); - strcat( text, "\n" ); - - theTalkingPlayer->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL; - // loop through all players - // Start with the first player. - // This may return the world in single player if the client types something between levels or during spawn - // so check it, or it will infinite loop - - client = NULL; - while ( ((client = (AvHPlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) - { - if ( !client->pev ) - continue; - - if ( client->edict() == pEntity ) - continue; - - if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) - continue; - - // can the receiver hear the sender? or has he muted him? - if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, theTalkingPlayer ) ) - continue; - - // Don't differentiate between team and non-team when not playing - bool theTalkingPlayerIsPlaying = ((theTalkingPlayer->GetPlayMode() == PLAYMODE_PLAYING) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_REINFORCING)); - bool theClientIsPlaying = ((client->GetPlayMode() == PLAYMODE_PLAYING) || (client->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (client->GetPlayMode() == PLAYMODE_REINFORCING)); - bool theTalkerIsObserver = theTalkingPlayer->IsObserver(); - bool theClientIsObserver = client->IsObserver(); - bool theClientIsHLTV = (client->pev->flags & FL_PROXY); - - bool theClientInReadyRoom = client->GetInReadyRoom(); - - if (theClientInReadyRoom != theTalkerInReadyRoom && !theClientIsHLTV) - { - continue; - } - - if (!theClientIsObserver || theClientIsPlaying ) // Non-playing Observers hear everything. - { - - if ( theTalkingPlayerIsPlaying && teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) - continue; - - // chat can never go between play area and non-play area - if(theTalkingPlayerIsPlaying != theClientIsPlaying && !theClientIsHLTV ) - continue; - - // chat of any kind doesn't go from ready room to play area in tournament mode - if(theTalkerInReadyRoom && GetGameRules()->GetIsTournamentMode() && theClientIsPlaying && !theClientIsHLTV) - continue; - - } - - UTIL_SayText(text, client, ENTINDEX(pEntity)); - - } - - // print to the sending client - UTIL_SayText(text, CBaseEntity::Instance(ENT(pEntity))); - - // echo to server console - g_engfuncs.pfnServerPrint( text ); - - char * temp; - if ( teamonly ) - temp = "say_team"; - else - temp = "say"; - -// UTIL_LogPrintf( "%s %s \"%s\"\n", GetLogStringForPlayer( pEntity ).c_str(), temp, p ); -} - - -/* -=========== -ClientCommand -called each time a player uses a "cmd" command -============ -*/ - -// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command. -void ClientCommand( edict_t *pEntity ) -{ - const char *pcmd = CMD_ARGV(0); - const char *pstr; - - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - entvars_t *pev = &pEntity->v; - - AvHPlayer* thePlayer = GetClassPtr((AvHPlayer *)pev); - bool thePlayerCanAct = thePlayer->GetIsAbleToAct(); - - if ( FStrEq(pcmd, "say" ) ) - { - Host_Say( pEntity, 0 ); - } - else if ( FStrEq(pcmd, "say_team" ) ) - { - Host_Say( pEntity, 1 ); - } - else if ( FStrEq(pcmd, "fullupdate" ) ) - { - GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); - } - else if ( FStrEq(pcmd, "give" ) ) - { - if(GetGameRules()->GetCheatsEnabled()) - { - int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname - GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); - } - } - - else if ( FStrEq(pcmd, "drop" )) - { - if (thePlayerCanAct) - { - // player is dropping an item. - GetClassPtr((AvHPlayer *)pev)->DropItem((char *)CMD_ARGV(1)); - } - } - else if ( FStrEq(pcmd, "fov" ) ) - { - if (GetGameRules()->GetCheatsEnabled() && (CMD_ARGC() > 1)) - { - GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) ); - } - else - { - CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) ); - } - } - else if ( FStrEq(pcmd, "use" )) - { - if (thePlayerCanAct) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); - } - } - else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) - { - if (thePlayerCanAct) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); - } - } - else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) ) - { - // MenuSelect returns true only if the command is properly handled, so don't print a warning - } - else if ( FStrEq( pcmd, "specmode" ) ) // new spectator mode - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) - { - int theMode = atoi(CMD_ARGV(1)); - pPlayer->Observer_SetMode(theMode); - pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); - } - } - else if (FStrEq( pcmd, "follow")) // follow a specific player - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) - { - pPlayer->Observer_SpectatePlayer(atoi( CMD_ARGV(1) )); - pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); - } - } - else if ( FStrEq( pcmd, "follownext" ) ) // follow next player - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) - { - pPlayer->Observer_FindNextPlayer(atoi( CMD_ARGV(1) )); - pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); - } - } - else - { - // tell the user they entered an unknown command - char command[128]; - - // check the length of the command (prevents crash) - // max total length is 192 ...and we're adding a string below ("Unknown command: %s\n") - strncpy( command, pcmd, 127 ); - command[127] = '\0'; - // : 1071 - // Remove printf formatting - for ( int i=0; i < 127; i++ ) { - if ( command[i] == '%' ) { - command[i] = ' '; - } - } - // : - // tell the user they entered an unknown command - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) ); - } - //else if(!AvHClientCommand(pEntity)) - //{ - // // tell the user they entered an unknown command - // ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pcmd ) ); - //} -} - -//bool AvHClientCommand( edict_t *pEntity ) -//{ -//} - -/* -======================== -ClientUserInfoChanged - -called after the player changes -userinfo - gives dll a chance to modify it before -it gets sent into the rest of the engine. -======================== -*/ -void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) -{ - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - const char* theCurrentNetName = STRING(pEntity->v.netname); - const char* theNameKeyValue = g_engfuncs.pfnInfoKeyValue(infobuffer, "name"); - - // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq(theCurrentNetName, theNameKeyValue) ) - { - AvHPlayer* thePlayer = dynamic_cast(CBaseEntity::Instance(pEntity)); - - // Don't change player info after match has started unless player hasn't left ready room - if(!GetGameRules()->GetArePlayersAllowedToJoinImmediately() && thePlayer && theNameKeyValue && thePlayer->GetHasLeftReadyRoom()) - { - thePlayer->SetDesiredNetName(string(theNameKeyValue)); - - char text[256]; - sprintf( text, "* Name will be changed to %s next game.\n", theNameKeyValue); - UTIL_SayText(text, CBaseEntity::Instance(ENT(pEntity))); - - // Restore name key value changed by engine - char theName[256]; - strcpy(theName, theCurrentNetName); - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", theName); - } - else - { - char sName[256]; - char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); - strncpy( sName, pName, sizeof(sName) - 1 ); - sName[ sizeof(sName) - 1 ] = '\0'; - - // First parse the name and remove any %'s - for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) - { - // Replace it with a space - if ( *pApersand == '%' ) - *pApersand = ' '; - } - - // Set the name - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); - //thePlayer->SetDesiredNetName(MAKE_STRING(sName)); - - char text[256]; - sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - - UTIL_SayTextAll(text, CBaseEntity::Instance(ENT(pEntity))); - -// UTIL_LogPrintf( "%s changed name to \"%s\"\n", GetLogStringForPlayer( pEntity ).c_str(), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - } - - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); -} - -static int g_serveractive = 0; - -void ServerDeactivate( void ) -{ - // It's possible that the engine will call this function more times than is necessary - // Therefore, only run it one time for each call to ServerActivate - if ( g_serveractive != 1 ) - { - return; - } - - g_serveractive = 0; - - // Peform any shutdown operations here... - // -} - -void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) -{ - int i; - CBaseEntity *pClass; - - // Every call to ServerActivate should be matched by a call to ServerDeactivate - g_serveractive = 1; - - // Clients have not been initialized yet - for ( i = 0; i < edictCount; i++ ) - { - if ( pEdictList[i].free ) - continue; - - // Clients aren't necessarily initialized until ClientPutInServer() - if ( i < clientMax || !pEdictList[i].pvPrivateData ) - continue; - - pClass = CBaseEntity::Instance( &pEdictList[i] ); - // Activate this entity if it's got a class & isn't dormant - if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) - { - pClass->Activate(); - } - else - { - ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); - } - } - - Net_InitializeMessages(); -} - - -/* -================ -PlayerPreThink - -Called every frame before physics are run -================ -*/ -void PlayerPreThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PreThink( ); -} - -/* -================ -PlayerPostThink - -Called every frame after physics are run -================ -*/ -void PlayerPostThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PostThink( ); -} - - - -void ParmsNewLevel( void ) -{ -} - - -void ParmsChangeLevel( void ) -{ - // retrieve the pointer to the save data - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - - if ( pSaveData ) - pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); -} - -void ShowMenu(entvars_s *pev, int ValidSlots, int DisplayTime, BOOL ShowLater, char Menu[500]) -{ - NetMsg_ShowMenu( pev, ValidSlots, DisplayTime, ShowLater ? 1 : 0, string(Menu) ); -} - -// -// GLOBALS ASSUMED SET: g_ulFrameCount -// -void StartFrame( void ) -{ - if ( g_pGameRules ) - g_pGameRules->Think(); - - if ( g_fGameOver ) - return; - - gpGlobals->teamplay = teamplay.value; - - g_ulFrameCount++; -} - -void ClientPrecache( void ) -{ - // Precache sound lists for all player types - gSoundListManager.Clear(); - - int i=0; - for(i = ((int)AVH_USER3_NONE + 1); i < (int)AVH_USER3_ALIEN_EMBRYO; i++) - { - char theSoundListName[256]; - bool theIsAlien = (i > 3); - AvHUser3 theUser3 = (AvHUser3)(i); - - bool theLoadSounds = false; - - // No squad leader and commander sounds - switch(theUser3) - { - case AVH_USER3_MARINE_PLAYER: - case AVH_USER3_ALIEN_PLAYER1: - case AVH_USER3_ALIEN_PLAYER2: - case AVH_USER3_ALIEN_PLAYER3: - case AVH_USER3_ALIEN_PLAYER4: - case AVH_USER3_ALIEN_PLAYER5: - theLoadSounds = true; - } - - if(theLoadSounds) - { - // Die sounds - sprintf(theSoundListName, kPlayerLevelDieSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Spawn sounds - sprintf(theSoundListName, kPlayerLevelSpawnSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Pain sounds - sprintf(theSoundListName, kPlayerLevelPainSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Wound sounds - sprintf(theSoundListName, kPlayerLevelWoundSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Attack sounds (aliens only) - if(theIsAlien) - { - sprintf(theSoundListName, kPlayerLevelAttackSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Idle sounds - sprintf(theSoundListName, kPlayerLevelIdleSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Movement sounds - sprintf(theSoundListName, kPlayerLevelMoveSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - } - } - } - - // Precache misc. alien sounds - //PRECACHE_SOUND(kAdrenalineSound); - PRECACHE_UNMODIFIED_SOUND(kGestationSound); - PRECACHE_UNMODIFIED_SOUND(kEggDestroyedSound); - PRECACHE_UNMODIFIED_SOUND(kEggIdleSound); - PRECACHE_UNMODIFIED_SOUND(kPrimalScreamResponseSound); - - // Preacache sayings sound list - for(i = 1; i <= 9; i++) - { - char theSoundListName[256]; - - sprintf(theSoundListName, kSoldierSayingList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - sprintf(theSoundListName, kCommanderSayingList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - sprintf(theSoundListName, kAlienSayingList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - } - - // Precache order sounds - gSoundListManager.PrecacheSoundList(kSoldierOrderRequestList); - gSoundListManager.PrecacheSoundList(kSoldierOrderAckList); - - // Precache other sound lists - gSoundListManager.PrecacheSoundList(kResourceTowerSoundList); - gSoundListManager.PrecacheSoundList(kAlienResourceTowerSoundList); - gSoundListManager.PrecacheSoundList(kHiveWoundSoundList); - gSoundListManager.PrecacheSoundList(kMarineConstructionSoundList); - gSoundListManager.PrecacheSoundList(kElectricSparkSoundList); - gSoundListManager.PrecacheSoundList(kAlienConstructionSoundList); - - // Other equipment and effect sounds - PRECACHE_UNMODIFIED_SOUND(kMarineBuildingDeploy); - PRECACHE_UNMODIFIED_SOUND(kJetpackSound); - PRECACHE_UNMODIFIED_SOUND(kWeldingSound); - PRECACHE_UNMODIFIED_SOUND(kWeldingHitSound); - //PRECACHE_UNMODIFIED_SOUND(kOverwatchStartSound); - //PRECACHE_UNMODIFIED_SOUND(kOverwatchEndSound); - PRECACHE_UNMODIFIED_SOUND(kRegenerationSound); - PRECACHE_UNMODIFIED_SOUND(kStartCloakSound); - PRECACHE_UNMODIFIED_SOUND(kEndCloakSound); - //PRECACHE_UNMODIFIED_SOUND(kWallJumpSound); - PRECACHE_UNMODIFIED_SOUND(kWingFlapSound1); - PRECACHE_UNMODIFIED_SOUND(kWingFlapSound2); - PRECACHE_UNMODIFIED_SOUND(kWingFlapSound3); - PRECACHE_UNMODIFIED_SOUND(kSiegeHitSound1); - PRECACHE_UNMODIFIED_SOUND(kSiegeHitSound2); - - // setup precaches always needed - PRECACHE_UNMODIFIED_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha - - // PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound - - // Alien step sounds - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a1.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a5.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-h.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-h.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-h.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-h.wav"); - - // Marine step sounds - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-6.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-7.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-8.wav"); - PRECACHE_UNMODIFIED_SOUND(kDigestingSound); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1.wav"); // walk on concrete - PRECACHE_UNMODIFIED_SOUND("player/pl_step2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4.wav"); - - PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete - PRECACHE_SOUND("common/npc_step2.wav"); - PRECACHE_SOUND("common/npc_step3.wav"); - PRECACHE_SOUND("common/npc_step4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_metal1.wav"); // walk on metal - PRECACHE_UNMODIFIED_SOUND("player/pl_metal2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_metal3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_metal4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt1.wav"); // walk on dirt - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_duct1.wav"); // walk in duct - PRECACHE_UNMODIFIED_SOUND("player/pl_duct2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_duct3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_duct4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_grate1.wav"); // walk on grate - PRECACHE_UNMODIFIED_SOUND("player/pl_grate2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_grate3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_grate4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh1.wav"); // walk in shallow water - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_tile1.wav"); // walk on tile - PRECACHE_UNMODIFIED_SOUND("player/pl_tile2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_tile3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_tile4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_tile5.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_swim1.wav"); // breathe bubbles - PRECACHE_UNMODIFIED_SOUND("player/pl_swim2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_swim3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_swim4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder1.wav"); // climb ladder rung - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_wade1.wav"); // wade in water - PRECACHE_UNMODIFIED_SOUND("player/pl_wade2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_wade3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_wade4.wav"); - - PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.wav"); - - PRECACHE_UNMODIFIED_SOUND("plats/train_use1.wav"); // use a train - - PRECACHE_UNMODIFIED_SOUND("buttons/spark5.wav"); // hit computer texture - PRECACHE_UNMODIFIED_SOUND("buttons/spark6.wav"); - PRECACHE_SOUND("debris/glass1.wav"); - PRECACHE_SOUND("debris/glass2.wav"); - PRECACHE_SOUND("debris/glass3.wav"); - - PRECACHE_UNMODIFIED_SOUND( SOUND_FLASHLIGHT_ON ); - PRECACHE_UNMODIFIED_SOUND( SOUND_FLASHLIGHT_OFF ); - -// player gib sounds - PRECACHE_SOUND("common/bodysplat.wav"); - -// player pain sounds - PRECACHE_UNMODIFIED_SOUND("player/pl_pain2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain6.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain7.wav"); - - PRECACHE_UNMODIFIED_MODEL("models/player.mdl"); - PRECACHE_UNMODIFIED_MODEL(kReadyRoomModel); - - PRECACHE_UNMODIFIED_MODEL(kMarineSoldierModel); - PRECACHE_UNMODIFIED_MODEL(kHeavySoldierModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelOneModel); - - PRECACHE_UNMODIFIED_MODEL(kAlienLevelTwoModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelThreeModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFourModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFiveModel); - - PRECACHE_UNMODIFIED_MODEL(kMarineCommanderModel); - PRECACHE_UNMODIFIED_MODEL(kAlienGestateModel); - - - // hud sounds, for marines and aliens (change AvHSharedUtil::AvHSHUGetCommonSoundName if these sound names change) - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudoff.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudon.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_moveselect.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_select.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_denyselect.wav"); - - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudoff-a.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudon-a.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_moveselect-a.wav"); - - PRECACHE_UNMODIFIED_SOUND("common/wpn_select-a.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_denyselect-a.wav"); - - // geiger sounds - PRECACHE_UNMODIFIED_SOUND("player/geiger6.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger1.wav"); - - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash1.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash3.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/digesting.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/membrane.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/hera_fog.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/webstrand.spr"); - - PRECACHE_UNMODIFIED_GENERIC("ns.wad"); - PRECACHE_UNMODIFIED_GENERIC("ns2.wad"); - PRECACHE_UNMODIFIED_GENERIC("v_wad.wad"); -/* PRECACHE_UNMODIFIED_GENERIC("maps/co_angst_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_core_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_daimos_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_ether_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_faceoff_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_kestrel_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_niveus_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_pulse_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_sava_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_ulysses_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_umbra_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_altair_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_ayumi_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_bast_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_caged_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_eclipse_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_eon_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_hera_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_lost_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_lucid_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_machina_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_metal_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_nancy_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_nothing_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_origin_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_prometheus_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_shiva_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_tanith_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_veil_detail.txt"); - - CStringList list; - string modDir=string(getModDirectory()) + "/"; - if(BuildFileList(modDir, "maps/", "*_detail.txt", list)) - { - for(CStringList::iterator it=list.begin(); it != list.end(); it++ ) { - int iString = ALLOC_STRING((char*)it);//: We cant do "(char*)theSoundToPrecache" directly cause it causes some wierd problems. - PRECACHE_UNMODIFIED_GENERIC((char*)STRING(iString)); - } - } - */ -} - -/* -================ -Sys_Error - - Engine is going to shut down, allows setting a breakpoint in game .dll to catch that occasion - ================ - */ - void Sys_Error( const char *error_string ) - { -#ifdef DEBUG -#ifdef WIN32 - // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls - _asm { int 3 }; -#endif -#else - char theDebugString[2056]; - sprintf(theDebugString, "Sys_Error: %s\n", error_string); - ALERT(at_error, theDebugString); -#endif - -} - -/* -=============== -GetGameDescription - -Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 -=============== -*/ -const char *GetGameDescription() -{ - if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized - return g_pGameRules->GetGameDescription(); - else - return "Half-Life"; -} - -/* -================ -PlayerCustomization - -A new player customization has been registered on the server -UNDONE: This only sets the # of frames of the spray can logo -animation right now. -================ -*/ -void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (!pPlayer) - { - ALERT(at_console, "PlayerCustomization: Couldn't get player!\n"); - return; - } - - if (!pCust) - { - ALERT(at_console, "PlayerCustomization: NULL customization!\n"); - return; - } - - switch (pCust->resource.type) - { - case t_decal: - pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames. - break; - case t_sound: - case t_skin: - case t_model: - // Ignore for now. - break; - default: - ALERT(at_console, "PlayerCustomization: Unknown customization type!\n"); - break; - } -} - -/* -================ -SpectatorConnect - -A spectator has joined the game -================ -*/ -void SpectatorConnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorConnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has left the game -================ -*/ -void SpectatorDisconnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorDisconnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has sent a usercmd -================ -*/ -void SpectatorThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorThink( ); -} - -//////////////////////////////////////////////////////// -// PAS and PVS routines for client messaging -// - -/* -================ -SetupVisibility - -A client can have a separate "view entity" indicating that his/her view should depend on the origin of that -view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current -entity's origin is used. Either is offset by the view_ofs to get the eye position. - -From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could - override the actual PAS or PVS values, or use a different origin. - -NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame -================ -*/ -void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) -{ - Vector org; - edict_t *pView = pClient; - bool theUseSpecialPASOrigin = false; - Vector theSpecialPASOrigin; - - // Find the client's PVS - if ( pViewEntity ) - { - pView = pViewEntity; - } - - // Proxy sees and hears all - if ( (pClient->v.flags & FL_PROXY) || GetGameRules()->GetIsCheatEnabled(kcViewAll)) - { - //ALERT(at_logged, "Setting PVS and PAS to NULL for FL_PROXY\n"); - *pvs = NULL; // the spectator proxy sees - *pas = NULL; // and hears everything - return; - } - - // Tracking Spectators use the visibility of their target - CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - if ( (pPlayer->pev->iuser2 != 0) && (pPlayer->m_hObserverTarget != NULL) && (pPlayer->m_afPhysicsFlags & PFLAG_OBSERVER) && pPlayer->IsAlive()) - { - pView = pPlayer->m_hObserverTarget->edict(); - UTIL_SetOrigin( pPlayer->pev, pPlayer->m_hObserverTarget->pev->origin ); - } - - // Tracking Spectators use the visibility of their target -// AvHPlayer *thePlayer = dynamic_cast(CBaseEntity::Instance(pClient)); - - // cgc - something could be wrong here, crashing from Robin's spectator code...did I do something wrong? -// if(thePlayer) -// { -// if ( (thePlayer->pev->iuser2 != 0) && (thePlayer->m_hObserverTarget != NULL) ) -// { -// pView = thePlayer->m_hObserverTarget->edict(); -// } -// -// if(thePlayer->GetRole() == ROLE_COMMANDER) -// { -// thePlayer->GetSpecialPASOrigin(theSpecialPASOrigin); -// theUseSpecialPASOrigin = true; -// } -// } - - org = pView->v.origin + pView->v.view_ofs; - if ( pView->v.flags & FL_DUCKING ) - { - org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - *pvs = ENGINE_SET_PVS ( (float *)&org ); - - if(theUseSpecialPASOrigin) - { - *pas = ENGINE_SET_PAS ( (float *)&theSpecialPASOrigin ); - } - else - { - *pas = ENGINE_SET_PAS ( (float *)&org ); - } -} - -#include "../common/entity_state.h" - -//CachedEntity gCachedEntities[kMaxPlayers][kMaxEntities]; -// -//void ResetCachedEntities() -//{ -// for(int i = 0; i < kMaxPlayers; i++) -// { -// for(int j = 0; j < kMaxEntities; j++) -// { -// gCachedEntities[i][j].ResetCachedEntity(); -// } -// } -//} - - - -// Array sizes ( memory is 5624 * 32 = 179968 bytes ) -#define MAX_CLIENTS ( 32 ) -#define MAX_ENTITIES ( 900 + MAX_CLIENTS * 15 ) - -// Re-check entities only this often once they are found to be in the PVS -// NOTE: We could have a separate timeout for players if we wanted to tweak the coherency time for them ( you'd have -// to check the entitynum against 1 to gpGlobals->maxclients ), etc. -//#define PVS_COHERENCY_TIME 1.0f - -extern float kPVSCoherencyTime; - -typedef struct -{ - bool mLastVisibility; - float m_fTimeEnteredPVS; -} ENTITYPVSSTATUS; - -typedef struct -{ - ENTITYPVSSTATUS m_Status[ MAX_ENTITIES ]; - - // Remember player leaf data so we can invalidate pvs history when leaf changes - int headnode; // -1 to use normal leaf check - int num_leafs; - short leafnums[ MAX_ENT_LEAFS ]; - -} PLAYERPVSSTATUS; - -static PLAYERPVSSTATUS g_PVSStatus[ MAX_CLIENTS ]; - -void ResetPlayerPVS( edict_t *client, int clientnum ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - - memset( pvs, 0, sizeof( PLAYERPVSSTATUS ) ); - - // Copy leaf data in right away - pvs->headnode = client->headnode; - pvs->num_leafs = client->num_leafs; - memcpy( pvs->leafnums, client->leafnums, sizeof( pvs->leafnums ) ); -} - -bool TimeToResetPVS( edict_t *client, int clientnum ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - - if ( (pvs->headnode != client->headnode) || (pvs->num_leafs != client->num_leafs)) - return true; - - if ( client->num_leafs > 0 ) - { - for ( int i = 0; i < client->num_leafs; i++ ) - { - if ( client->leafnums[ i ] != pvs->leafnums[ i ] ) - { - return true; - } - } - } - - // Still the same - return false; -} - -void MarkEntityInPVS( int clientnum, int entitynum, float time, bool inpvs ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; - - es->m_fTimeEnteredPVS = time; - es->mLastVisibility = inpvs; -} - -bool GetTimeToRecompute( int clientnum, int entitynum, float currenttime, bool& outCachedVisibility) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; - - bool theTimeToRecompute = false; - - int theUseCaching = BALANCE_VAR(kDebugServerCaching); - if(theUseCaching) - { - // Always recompute players? - if((entitynum > 0) && (entitynum < MAX_CLIENTS)) - { - theTimeToRecompute = true; - } - // If we haven't computed for awhile, or our PVS has been reset - else if((currenttime > (es->m_fTimeEnteredPVS + kPVSCoherencyTime)) || (es->m_fTimeEnteredPVS == 0.0f)) - { - theTimeToRecompute = true; - } - else - { - outCachedVisibility = es->mLastVisibility; - } - } - else - { - theTimeToRecompute = true; - } - - return theTimeToRecompute; -} - -bool CheckEntityRecentlyInPVS( int clientnum, int entitynum, float currenttime ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; - - int theUseCaching = BALANCE_VAR(kDebugServerCaching); - if(!theUseCaching) - { - return false; - } - - // Wasn't in pvs before, sigh... - if ( es->m_fTimeEnteredPVS == 0.0f ) - { - return false; - } - - // If we've been saying yes for kPVSCoherencyTime, say no now instead so that we'll do a full check - if ( es->m_fTimeEnteredPVS + kPVSCoherencyTime < currenttime ) - { - return false; - } - - // Keep assuming it's in the pvs for a bit of time (trivial inclusion) - return true; -} - - -int kNumReturn0 = 0; -int kNumReturn1 = 0; -int kNumCached = 0; -int kNumComputed = 0; -int kMaxE = 0; -int kNumEntsProcessedForPlayerOne = 0; -int kMaxEProcessedForPlayerOne = 0; -extern int kServerFrameRate; - -// ENGINE_CHECK_VISIBILITY, from Yahn, with his comments: -// -// Here's the engine code. You'll note a slow path if the ent leaf cache is missed, which causes a recomputation via the much more expensive -// CM_HeadnodeVisible call. That does change the cache data on the entity, so that's likely your problem with blinking if you are doing some -// kind of memcpy operation on the old data. -//#ifdef 0 -//int DLL_CALLBACK SV_CheckVisibility( const struct edict_s *entity, unsigned char *pset ) -//{ -// int i; -// qboolean visible; -// edict_t *e; -// -// if ( !pset ) -// return 1; -// -// if ( entity->headnode >= 0 ) // -// { -// // we use num_leafs as a cache/counter, it will circle around, but so what -// // if we don't find the leaf we want here, we'll end up doing the full test anyway -// int leaf; -// i = 0; -// -// do -// { -// leaf = entity->leafnums[i]; -// // Cache is all -1 to start... -// if ( leaf == -1 ) -// break; -// -// if ( pset[ leaf >> 3 ] & (1 << (leaf & 7 ) ) ) -// { -// return 1; -// } -// -// i++; -// if ( i >= MAX_ENT_LEAFS ) -// break; -// -// } while ( 1 ); -// -// // Didn't find it in "cache" -// -// visible = CM_HeadnodeVisible( sv.worldmodel->nodes + entity->headnode, pset, &leaf ); -// if ( !visible ) -// { -// return 0; -// } -// -// // Cache leaf that was visible -// // -// e = ( edict_t * )entity; -// -// e->leafnums[ entity->num_leafs ] = (short)leaf; -// e->num_leafs = ( entity->num_leafs + 1 ) % MAX_ENT_LEAFS; -// -// return 2; -// } -// else -// { -// for (i=0 ; i < entity->num_leafs ; i++) -// { -// if ( pset[entity->leafnums[i] >> 3] & (1 << (entity->leafnums[i]&7) )) -// break; -// } -// -// visible = ( i < entity->num_leafs ); -// if ( !visible ) -// { -// return 0; -// } -// } -// -// return 1; -//} -//#endif - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 - -/* -=================== -CreateBaseline - -Creates baselines used for network encoding, especially for player data since players are not spawned until connect time. -=================== -*/ -void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) -{ - baseline->origin = entity->v.origin; - baseline->angles = entity->v.angles; - baseline->frame = entity->v.frame; - baseline->skin = (short)entity->v.skin; - - // render information - baseline->rendermode = (byte)entity->v.rendermode; - baseline->renderamt = (byte)entity->v.renderamt; - baseline->rendercolor.r = (byte)entity->v.rendercolor.x; - baseline->rendercolor.g = (byte)entity->v.rendercolor.y; - baseline->rendercolor.b = (byte)entity->v.rendercolor.z; - baseline->renderfx = (byte)entity->v.renderfx; - - if ( player ) - { - baseline->mins = player_mins; - baseline->maxs = player_maxs; - - baseline->colormap = eindex; - baseline->modelindex = playermodelindex; - baseline->friction = 1.0; - baseline->movetype = MOVETYPE_WALK; - - baseline->scale = entity->v.scale; - baseline->solid = SOLID_SLIDEBOX; - baseline->framerate = 1.0; - baseline->gravity = 1.0; - - } - else - { - baseline->mins = entity->v.mins; - baseline->maxs = entity->v.maxs; - - baseline->colormap = 0; - baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); - baseline->movetype = entity->v.movetype; - - baseline->scale = entity->v.scale; - baseline->solid = entity->v.solid; - baseline->framerate = entity->v.framerate; - baseline->gravity = entity->v.gravity; - } -} - -typedef struct -{ - char name[32]; - int field; -} entity_field_alias_t; - -#define FIELD_ORIGIN0 0 -#define FIELD_ORIGIN1 1 -#define FIELD_ORIGIN2 2 -#define FIELD_ANGLES0 3 -#define FIELD_ANGLES1 4 -#define FIELD_ANGLES2 5 - -static entity_field_alias_t entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, -}; - -void Entity_FieldInit( struct delta_s *pFields ) -{ - entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); - entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); - entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); - entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); - entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); - entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); -} - -/* -================== -Entity_Encode - -Callback for sending entity_state_t info over network. -FIXME: Move to script -================== -*/ -void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->impacttime != 0 ) && ( t->starttime != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -static entity_field_alias_t player_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, -}; - -void Player_FieldInit( struct delta_s *pFields ) -{ - player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); - player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); - player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); -} - -/* -================== -Player_Encode - -Callback for sending entity_state_t for players info over network. -================== -*/ -void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Player_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -#define CUSTOMFIELD_ORIGIN0 0 -#define CUSTOMFIELD_ORIGIN1 1 -#define CUSTOMFIELD_ORIGIN2 2 -#define CUSTOMFIELD_ANGLES0 3 -#define CUSTOMFIELD_ANGLES1 4 -#define CUSTOMFIELD_ANGLES2 5 -#define CUSTOMFIELD_SKIN 6 -#define CUSTOMFIELD_SEQUENCE 7 -#define CUSTOMFIELD_ANIMTIME 8 - -entity_field_alias_t custom_entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, - { "skin", 0 }, - { "sequence", 0 }, - { "animtime", 0 }, -}; - -void Custom_Entity_FieldInit( struct delta_s *pFields ) -{ - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); -} - -/* -================== -Custom_Encode - -Callback for sending entity_state_t info ( for custom entities ) over network. -FIXME: Move to script -================== -*/ -void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int beamType; - static int initialized = 0; - - if ( !initialized ) - { - Custom_Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - beamType = t->rendermode & 0x0f; - - if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); - } - - if ( beamType != BEAM_POINTS ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); - } - - if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); - } - - // animtime is compared by rounding first - // see if we really shouldn't actually send it - if ( (int)f->animtime == (int)t->animtime ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); - } -} - -/* -================= -RegisterEncoders - -Allows game .dll to override network encoding of certain types of entities and tweak values, etc. -================= -*/ -void RegisterEncoders( void ) -{ - DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); - DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); - DELTA_ADDENCODER( "Player_Encode", Player_Encode ); -} - -int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) -{ - int i; - weapon_data_t *item; - entvars_t *pev = &player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - AvHPlayer* thePlayer = dynamic_cast(pl); - CBasePlayerWeapon *gun; - - ItemInfo II; - - memset( info, 0, 32 * sizeof( weapon_data_t ) ); - - if ( !pl ) - return 1; - - // go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( pl->m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) - { - // Get The ID. - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - ASSERT((II.iId >= 0) && (II.iId < 32)); - - if ( II.iId >= 0 && II.iId < 32 ) - { - item = &info[ II.iId ]; - - item->m_iId = II.iId; - item->m_iClip = gun->m_iClip; - - item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001f ); - item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001f ); - item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001f ); - item->m_fInReload = gun->m_fInReload; - - //thePlayer->SetDebugCSP(item); - - //item->m_fInSpecialReload = gun->m_fInSpecialReload; - //item->fuser1 = max( gun->pev->fuser1, -0.001 ); - item->fuser2 = gun->m_flStartThrow; - item->fuser3 = gun->m_flReleaseThrow; - //item->iuser1 = gun->m_chargeReady; - //item->iuser2 = gun->m_fInAttack; - - // Pass along enabled state in iuser3 (for when hives and ensnare enable and disable weapons) - item->iuser3 = gun->pev->iuser3; - - //item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); - } - } - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - return 1; -} - -/* -================= -UpdateClientData - -Data sent to current client only -engine sets cd to 0 before calling. -================= -*/ -void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) -{ - cd->flags = ent->v.flags; - cd->health = ent->v.health; - - cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); - - cd->waterlevel = ent->v.waterlevel; - cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; - - // Vectors - cd->origin = ent->v.origin; - cd->velocity = ent->v.velocity; - cd->view_ofs = ent->v.view_ofs; - cd->punchangle = ent->v.punchangle; - - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; - cd->flDuckTime = ent->v.flDuckTime; - cd->flSwimTime = ent->v.flSwimTime; - cd->waterjumptime = ent->v.teleport_time; - - strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - - cd->maxspeed = ent->v.maxspeed; - cd->fov = ent->v.fov; - cd->weaponanim = ent->v.weaponanim; - - cd->pushmsec = ent->v.pushmsec; - - // Spectator - cd->iuser1 = ent->v.iuser1; - cd->iuser2 = ent->v.iuser2; - - // AvH specials - cd->iuser3 = ent->v.iuser3; - cd->iuser4 = ent->v.iuser4; - cd->fuser1 = ent->v.fuser1; - cd->fuser2 = ent->v.fuser2; - cd->fuser3 = ent->v.fuser3; - - // Added by mmcguire for oriented skulk player models. - cd->vuser1 = ent->v.vuser1; - - // Added for extra player info for first-person spectating - cd->vuser4 = ent->v.vuser4; - - if ( sendweapons ) - { - entvars_t *pev = (entvars_t *)&ent->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - - if ( pl ) - { - cd->m_flNextAttack = pl->m_flNextAttack; - //cd->fuser2 = pl->m_flNextAmmoBurn; - //cd->fuser3 = pl->m_flAmmoStartCharge; - //cd->vuser1.x = pl->ammo_9mm; - //cd->vuser1.y = pl->ammo_357; - //cd->vuser1.z = pl->ammo_argrens; - //cd->ammo_nails = pl->ammo_bolts; - //cd->ammo_shells = pl->ammo_buckshot; - //cd->ammo_rockets = pl->ammo_rockets; - //cd->ammo_cells = pl->ammo_uranium; - //cd->vuser2.x = pl->ammo_hornets; - - if ( pl->m_pActiveItem ) - { - CBasePlayerWeapon *gun; - gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) - { - ItemInfo II; - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - cd->m_iId = II.iId; - -// cd->vuser3.z = gun->m_iSecondaryAmmoType; -// cd->vuser4.x = gun->m_iPrimaryAmmoType; -// cd->vuser4.y = pl->m_rgAmmo[gun->m_iPrimaryAmmoType]; -// cd->vuser4.z = pl->m_rgAmmo[gun->m_iSecondaryAmmoType]; -// -// if ( pl->m_pActiveItem->m_iId == WEAPON_RPG ) -// { -// cd->vuser2.y = ( ( CRpg * )pl->m_pActiveItem)->m_fSpotActive; -// cd->vuser2.z = ( ( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; -// } - } - } - } - } -} - -/* -================= -CmdStart - -We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. -This is the time to examine the usercmd for anything extra. This call happens even if think does not. -================= -*/ -void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) -{ - entvars_t *pev = (entvars_t *)&player->v; - AvHPlayer *pl = ( AvHPlayer *) CBasePlayer::Instance( pev ); - - if( !pl ) - return; - - pl->SetCurrentCommand(cmd); - - pl->SetSizeForUser3(); - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); - } - - pl->random_seed = random_seed; -} - -/* -================= -CmdEnd - -Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here -================= -*/ -void CmdEnd ( const edict_t *player ) -{ - entvars_t *pev = (entvars_t *)&player->v; - AvHPlayer *pl = ( AvHPlayer *) CBasePlayer::Instance( pev ); - - if( !pl ) - return; - - pl->SetSizeForUser3(); - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_UnsetGroupTrace(); - } -} - -/* -================================ -ConnectionlessPacket - - Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max - size of the response_buffer, so you must zero it out if you choose not to respond. -================================ -*/ -int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - // Parse stuff from args - int max_buffer_size = *response_buffer_size; - - // Zero it out since we aren't going to respond. - // If we wanted to response, we'd write data into response_buffer - *response_buffer_size = 0; - - // Since we don't listen for anything here, just respond that it's a bogus message - // If we didn't reject the message, we'd return 1 for success instead. - return 0; -} - -/* -================================ -GetHullBounds - - Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. -================================ -*/ -int GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - int iret = 0; - - switch ( hullnumber ) - { - case 0: - HULL0_MIN.CopyToArray(mins); - HULL0_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 1: - HULL1_MIN.CopyToArray(mins); - HULL1_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 2: - HULL2_MIN.CopyToArray(mins); - HULL2_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 3: - HULL3_MIN.CopyToArray(mins); - HULL3_MAX.CopyToArray(maxs); - iret = 1; - break; - } - - return iret; -} - -/* -================================ -CreateInstancedBaselines - -Create pseudo-baselines for items that aren't placed in the map at spawn time, but which are likely -to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) -================================ -*/ -void CreateInstancedBaselines ( void ) -{ - int iret = 0; - entity_state_t state; - - memset( &state, 0, sizeof( state ) ); - - // Create any additional baselines here for things like grendates, etc. - // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); - - // Destroy objects. - //UTIL_Remove( pc ); -} - -/* -================================ -InconsistentFile - -One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the specified player - Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) -================================ -*/ - -static char *ignoreInConsistencyCheck[] = { - "sound/vox/ssay82.wav", - "sound/vox/ssay83.wav", - 0 -}; - -int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) -{ - // Server doesn't care? - if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) - return 0; - - int i=0; - while ( ignoreInConsistencyCheck[i] != 0 ) { - if ( !strcmp(ignoreInConsistencyCheck[i], filename) ) - return 0; - i++; - } - - /*if ( strstr(filename, "_detail.txt") != NULL ) { - ALERT(at_console, "Checking consistency of %s\n", filename); - string detailFilename=string("maps/") + STRING(gpGlobals->mapname) + string("_detail.txt"); - if ( strcmp(filename, detailFilename.c_str()) != 0 ) { - ALERT(at_console, "Skipping != %s\n", detailFilename.c_str()); - return 0; - } - }*/ - - // Default behavior is to kick the player - sprintf( disconnect_message, "Server is enforcing file consistency for %s\n", filename ); - - // Kick now with specified disconnect message. - return 1; -} - -/* -================================ -AllowLagCompensation - - The game .dll should return 1 if lag compensation should be allowed ( could also just set - the sv_unlag cvar. - Most games right now should return 0, until client-side weapon prediction code is written - and tested for them ( note you can predict weapons, but not do lag compensation, too, - if you want. -================================ -*/ -int AllowLagCompensation( void ) -{ - return 1; -} - -inline bool AvHDetermineVisibility(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, unsigned char *pSet, bool& outIsParticleSystemEntity, bool& outIsParticleSystemEntityVisible) -{ - bool theIsVisible = false; - bool theIsParticleSystemEntity = (ent->v.classname == MAKE_STRING(kesParticlesCustom)); - outIsParticleSystemEntity = theIsParticleSystemEntity; - outIsParticleSystemEntityVisible = false; - - // Always propagate ourself - if(ent != host) - { - //if(GET_RUN_CODE(256)) - - bool theEntityIsAWeldable = ent->v.iuser3 == AVH_USER3_WELD;//(ent->v.classname == MAKE_STRING(kesWeldable)); - bool theIsNoBuild = ent->v.iuser3 == AVH_USER3_NOBUILD;//(ent->v.classname == MAKE_STRING(kesNoBuild)); - - // Don't send if EF_NODRAW objects that aren't the host (with some exceptions) - // This is a little convoluted because of performance (this function gets called many thousands of time per server tick) - - // Elven - edited out the !(ent->v.effects & EF_NODRAW) because it will always evaluate to true. - // Reasoning: if (v.effects & EF_NODRAW) and (ent!=host) were ever true, there would have been a return call in - // AddToFullPack before this function was called. - // Therefore, (ent->v.effects & EF_NODRAW) will always be false and !false will always be true. - // - undid this change as it was causing problems in comm mode. Structures, players etc. were not visible to the comm. - if(!(ent->v.effects & EF_NODRAW) || theEntityIsAWeldable || theIsNoBuild || (ent->v.classname == MAKE_STRING(kesMP3Audio))) - { - // This is duplicated from the above line for possible efficiency - bool theIsMp3Entity = (ent->v.classname == MAKE_STRING(kesMP3Audio)); - - // Ignore ents without valid / visible models - // ...but don't cull out particle systems ever. - // This should use an approximate bounding radius and cull it with the PVS normally but - // I can't figure out how to make it work. This would only cause more net traffic if - // the particle system entity was out of sight and moving around due to map triggers, not - // through normal operation - if(ent->v.modelindex || STRING(ent->v.model) || theIsParticleSystemEntity || theIsMp3Entity) - { - if(theIsMp3Entity) - { - CBaseEntity* theEntity = CBaseEntity::Instance(ent); - AvHMP3Audio* theMP3Audio = dynamic_cast(theEntity); - if(theMP3Audio) - { - float theDistanceToEntity = VectorDistance(host->v.origin, ent->v.origin); - int theFadeDistance = theMP3Audio->GetFadeDistance(); - if((theFadeDistance <= 0) || (theDistanceToEntity <= theFadeDistance)) - { - theIsVisible = true; - } - } - } - - // If we're in top down - bool thePlayerInTopDown = (host->v.iuser4 & MASK_TOPDOWN); - if(thePlayerInTopDown) - { - // Possible visible entities are world entities, sighted enemy entities, or entities on our team - bool theEntityIsWorldEntity = (ent->v.team == 0) && (ent->v.iuser3 != AVH_USER3_HIVE); - bool theIsSighted = (ent->v.iuser4 & MASK_VIS_SIGHTED); - bool theOnSameTeam = (host->v.team == ent->v.team); - - if(theEntityIsWorldEntity || theIsSighted || theOnSameTeam) - { - CBaseEntity* theEntity = CBaseEntity::Instance(ent); - bool theIsDoor = (dynamic_cast(theEntity) != NULL); - - // If entity is in front of the player and within visibility range - vec3_t theEntityOrigin = ent->v.origin; - float theMagnitude = theEntityOrigin.x + theEntityOrigin.y + theEntityOrigin.z; - if((theMagnitude < 5.0f) || theIsDoor) - { - theEntityOrigin.x = (ent->v.absmin.x + ent->v.absmax.x)/2.0f; - theEntityOrigin.y = (ent->v.absmin.y + ent->v.absmax.y)/2.0f; - theEntityOrigin.z = (ent->v.absmin.z + ent->v.absmax.z)/2.0f; - } - bool theIsRelevantForTopDownPlayer = AvHSUGetIsRelevantForTopDownPlayer(host->v.origin, theEntityOrigin); - if(!theIsRelevantForTopDownPlayer) - { - AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); - - // If the entity is selected, it's relevant - if(theEntity && theReceivingPlayer && theReceivingPlayer->GetIsSelected(theEntity->entindex())) - { - theIsRelevantForTopDownPlayer = true; - } - } - if(theIsRelevantForTopDownPlayer) - { - theIsVisible = true; - if(theIsParticleSystemEntity) - { - outIsParticleSystemEntityVisible = true; - } - } - } - } -// else -// { -// // Check visibility with the engine -// if(ENGINE_CHECK_VISIBILITY((const struct edict_s *)ent, pSet)) -// { -// theIsVisible = true; -// -// // If it's a particle system entity, save visibility for it -// if(theIsParticleSystemEntity) -// { -// outIsParticleSystemEntityVisible = true; -// } -// } -// else if(theIsParticleSystemEntity) -// { -// outIsParticleSystemEntityVisible = false; -// } -// } - } - } - } - else - { - theIsVisible = true; - } - - return theIsVisible; -} - -/* -AddToFullPack - -Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise - -state is the server maintained copy of the state info that is transmitted to the client -a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. -e and ent are the entity that is being added to the update, if 1 is returned -host is the player's edict of the player whom we are sending the update to -player is 1 if the ent/e is a player and 0 otherwise -pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. -we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame -*/ -int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) -{ - int i; - - if(e > kMaxEProcessedForPlayerOne) - { - kNumEntsProcessedForPlayerOne++; - kMaxEProcessedForPlayerOne = e; - } - - if((ent != host) && !(GET_RUN_CODE(512))) - { - kNumReturn0++; - return 0; - } - - // This is a common case - // Ignore ents without valid / visible models - if ( !ent->v.modelindex || !STRING( ent->v.model ) ) - { - kNumReturn0++; - return 0; - } - - // don't send if flagged for NODRAW and it's not the host getting the message - if ( ( ent->v.effects & EF_NODRAW ) && - ( ent != host ) ) - { - kNumReturn0++; - return 0; - } - - // Don't send spectators to other players - if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) ) - { - kNumReturn0++; - return 0; - } - - AvHUser3 theUser3 = (AvHUser3)ent->v.iuser3; - bool theCanBeTargetted = ent->v.targetname != 0; - - //if(!strcmp(theEntNameString, "func_illusionary")) - if(theUser3 == AVH_USER3_FUNC_ILLUSIONARY) - { - // Check invisibility flags - if(host->v.iuser4 & MASK_TOPDOWN) - { - if(FBitSet(ent->v.spawnflags, 1)) - { - if(pSet != NULL) - { - kNumReturn0++; - return 0; - } - } - } - // If we're not commander, and "invisible for player" is set - else - { - if(FBitSet(ent->v.spawnflags, 2)) - { - if(pSet != NULL) - { - kNumReturn0++; - return 0; - } - } - } - } - - - // Some entities can be determined to be visible without the engine check - bool theIsParticleSystemEntity = false; - bool theIsParticleSystemEntityVisible = false; - bool theIsVisible = AvHDetermineVisibility(state, e, ent, host, pSet, theIsParticleSystemEntity, theIsParticleSystemEntityVisible); - if(!theIsVisible) - { - // Check to see if the player has left their previous leaf. If so, reset player's PVS info. - int hostnum = ENTINDEX( host ) - 1; - if ( TimeToResetPVS( host, hostnum ) ) - { - ResetPlayerPVS( host, hostnum ); - } - - // Ignore if not the host and not touching a PVS/PAS leaf - // If pSet is NULL, then the test will always succeed and the entity will be added to the update - if ( ent != host ) - { - if(GetTimeToRecompute( hostnum, e, gpGlobals->time, theIsVisible)) - { - // Do time consuming check - theIsVisible = ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ); - - MarkEntityInPVS( hostnum, e, gpGlobals->time, theIsVisible); - - kNumComputed++; - } - - if(!theIsVisible) - { - kNumReturn0++; - return 0; - } - } - - // Don't send entity to local client if the client says it's predicting the entity itself. - if ( ent->v.flags & FL_SKIPLOCALHOST ) - { - if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) - { - kNumReturn0++; - return 0; - } - } - - if ( host->v.groupinfo ) - { - UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); - - // Should always be set, of course - if ( ent->v.groupinfo ) - { - if ( g_groupop == GROUP_OP_AND ) - { - if ( !(ent->v.groupinfo & host->v.groupinfo ) ) - { - kNumReturn0++; - return 0; - } - } - else if ( g_groupop == GROUP_OP_NAND ) - { - if ( ent->v.groupinfo & host->v.groupinfo ) - { - kNumReturn0++; - return 0; - } - } - } - - UTIL_UnsetGroupTrace(); - } - } - - memset( state, 0, sizeof( *state ) ); - - // Assign index so we can track this entity from frame to frame and - // delta from it. - state->number = e; - state->entityType = ENTITY_NORMAL; - - // Flag custom entities. - if ( ent->v.flags & FL_CUSTOMENTITY ) - { - state->entityType = ENTITY_BEAM; - } - - // - // Copy state data - // - - // Round animtime to nearest millisecond - state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; - - //memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) ); - state->origin = ent->v.origin; - - //memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) ); - state->angles = ent->v.angles; - - //memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) ); - state->mins = ent->v.mins; - - //memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) ); - state->maxs = ent->v.maxs; - - //memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); - state->startpos = ent->v.startpos; - - //memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); - state->endpos = ent->v.endpos; - - state->impacttime = ent->v.impacttime; - state->starttime = ent->v.starttime; - - state->modelindex = ent->v.modelindex; - - state->frame = ent->v.frame; - - state->skin = ent->v.skin; - state->effects = ent->v.effects; - - // This non-player entity is being moved by the game .dll and not the physics simulation system - // make sure that we interpolate it's position on the client if it moves - if ( !player && - ent->v.animtime && - ent->v.velocity[ 0 ] == 0 && - ent->v.velocity[ 1 ] == 0 && - ent->v.velocity[ 2 ] == 0 ) - { - state->eflags |= EFLAG_SLERP; - } - - state->scale = ent->v.scale; - state->solid = ent->v.solid; - state->colormap = ent->v.colormap; - state->movetype = ent->v.movetype; - state->sequence = ent->v.sequence; - state->framerate = ent->v.framerate; - state->body = ent->v.body; - - for (i = 0; i < 4; i++) - { - state->controller[i] = ent->v.controller[i]; - } - - for (i = 0; i < 2; i++) - { - state->blending[i] = ent->v.blending[i]; - } - - state->rendermode = ent->v.rendermode; - state->renderamt = ent->v.renderamt; - state->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor[0]; - state->rendercolor.g = ent->v.rendercolor[1]; - state->rendercolor.b = ent->v.rendercolor[2]; - - - // If classname indicates an entity that fades depending on viewing player role - const char* theEntNameString = STRING(ent->v.classname); - - if(!player && AvHSSUGetIsClassNameFadeable(theEntNameString)) - { - CBaseEntity* theSeethrough = CBaseEntity::Instance(ent); - ASSERT(theSeethrough); - - // Default to player is full visibility - state->rendermode = kRenderNormal; - - int theAlphaValue = theSeethrough->pev->fuser2; - if(host->v.iuser4 & MASK_TOPDOWN) - { - theAlphaValue = theSeethrough->pev->fuser1; - } - - if(theAlphaValue != 255) - { - //state->rendermode = kRenderTransAdd; - state->rendermode = kRenderTransTexture; - state->renderamt = theAlphaValue; - if(state->renderamt == 0) - { - state->effects |= EF_NODRAW; - } - - if(host->v.iuser4 & MASK_TOPDOWN) - { - state->solid = SOLID_NOT; - } - - } - - } - - // Inactive hives should be drawn for players on their team - if((ent->v.iuser3 == AVH_USER3_HIVE) && (!GetHasUpgrade(ent->v.iuser4, MASK_BUILDABLE))) - { - // Assumes that aliens of both teams can build on the same hive location - AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); - if(theReceivingPlayer && theReceivingPlayer->GetIsAlien()) - { - state->renderamt = 128; - } - } - - // Handle cloakables here - if(!AvHSUGetIsExternalClassName(theEntNameString)) - { - AvHCloakable* theCloakable = dynamic_cast(CBaseEntity::Instance(ent)); - if(theCloakable) - { - // Now updated in gamerules - theCloakable->Update(); - - float theOpacityScalar = theCloakable->GetOpacity(); - if(theOpacityScalar < 1.0f) - { - int theBaseOpacity = kAlienStructureCloakAmount; - int theOpacityRange = 255 - kAlienStructureCloakAmount; - - // Allow spectators to see cloaked entities as if they are the player they are following, or as if they are on the same team as the alien otherwise - bool theCanSeeCloaked = (host->v.team == ent->v.team); - if(!theCanSeeCloaked) - { - int theHostIUserOne = host->v.iuser1; - if((theHostIUserOne == OBS_CHASE_LOCKED) || (theHostIUserOne == OBS_CHASE_FREE) || (theHostIUserOne == OBS_IN_EYE) ) - { - // View entities as player we're tracking - int theHostIUserTwo = host->v.iuser2; - CBaseEntity* theSpectatingEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theHostIUserTwo)); - if(theSpectatingEntity) - { - int theSpectatingEntityTeamNumber = theSpectatingEntity->pev->team; - if((theSpectatingEntityTeamNumber == ent->v.team) || (host->v.team == TEAM_IND)) - { - theCanSeeCloaked = true; - } - } - } - } - - if(theCanSeeCloaked) - { - theBaseOpacity = kAlienSelfCloakingBaseOpacity; - theOpacityRange = 255 - theBaseOpacity; - } - - int theOpacity = theBaseOpacity + theOpacityScalar*theOpacityRange; - theOpacity = max(min(255, theOpacity), 0); - - state->rendermode = kRenderTransTexture; - state->renderamt = theOpacity; - } - } - } - - // Spectator - state->iuser1 = ent->v.iuser1; - state->iuser2 = ent->v.iuser2; - - // AvH specials - state->iuser3 = ent->v.iuser3; - state->iuser4 = ent->v.iuser4; - - // Slightly different processing for particle system entities -// if(theIsParticleSystemEntity) -// { -// // propagate weapon model as custom data) -// state->weaponmodel = ent->v.weaponmodel; -// } - - state->fuser1 = ent->v.fuser1; - state->fuser2 = ent->v.fuser2; - state->fuser3 = ent->v.fuser3; - state->vuser4 = ent->v.vuser4; - - - - - - - state->aiment = 0; - if ( ent->v.aiment ) - { - state->aiment = ENTINDEX( ent->v.aiment ); - } - - state->owner = 0; - if ( ent->v.owner ) - { - int owner = ENTINDEX( ent->v.owner ); - - // Only care if owned by a player - if ( owner >= 1 && owner <= gpGlobals->maxClients ) - { - state->owner = owner; - } - } - - // HACK: Somewhat... - // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) - if ( !player ) - { - state->playerclass = ent->v.playerclass; - } - - // Propagate team for all entities (mainly needed for client-side lasso selection) - state->team = ent->v.team; - - // Check special vision mode - AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); - if(theReceivingPlayer && (theReceivingPlayer->GetIsAlienSightActive())) - { - bool marineGlow = false; - if (player) - { - // Uncomment below to enable range for the alien flashlight - // vec3_t theDistanceVec; - // VectorSubtract(theReceivingPlayer->pev->origin, ent->v.origin, theDistanceVec); - - // int theDistance = theDistanceVec[0] * theDistanceVec[0] + theDistanceVec[1] * theDistanceVec[1] + theDistanceVec[2] * theDistanceVec[2]; - // int theRange = BALANCE_VAR(kAlienFlashlightRange); - // marineGlow = (theDistance < ( theRange * theRange)); - marineGlow = true; - } - - if(( marineGlow || (ent->v.team == theReceivingPlayer->pev->team)) && (ent != theReceivingPlayer->edict()) && (ent->v.team != TEAM_IND) && (ent->v.team != TEAM_SPECT ) && (ent->v.classname != MAKE_STRING(kesTeamWebStrand)) ) - { - state->rendermode = kRenderTransAdd; - state->renderamt = 150; - } - } - - // Special stuff for players only - if(player) - { - state->basevelocity = ent->v.basevelocity; - - state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); - state->gaitsequence = ent->v.gaitsequence; - state->spectator = ent->v.flags & FL_SPECTATOR; - state->friction = ent->v.friction; - - state->gravity = ent->v.gravity; - - // New SDK doesn't propagate team for a reason? - //state->playerclass = ent->v.playerclass; - //state->team = ent->v.team; - - bool theIsDucking = ent->v.flags & FL_DUCKING; - state->usehull = AvHMUGetHull(theIsDucking, ent->v.iuser3); - - // Propagate "energy level" - state->fuser3 = ent->v.fuser3; - - // For skulk oriented player model - state->vuser1 = ent->v.vuser1; - - // For weapons - state->vuser4 = ent->v.vuser4; - - //state->skin = theTargetPlayer->GetSkin(); - state->skin = ent->v.skin; - state->playerclass = ent->v.playerclass; - // state->armorvalue = ent->v.armorvalue; - - AvHPlayer* thePlayerEntity = dynamic_cast(CBaseEntity::Instance(ent)); - if(thePlayerEntity && thePlayerEntity->GetIsTemporarilyInvulnerable()) - { - int theTeamIndex = ent->v.team; - ASSERT(theTeamIndex >= 0); - ASSERT(theTeamIndex < iNumberOfTeamColors); - - state->renderfx = kRenderFxGlowShell; - state->rendercolor.r = kTeamColors[theTeamIndex][0]; - state->rendercolor.g = kTeamColors[theTeamIndex][1]; - state->rendercolor.b = kTeamColors[theTeamIndex][2]; - state->renderamt = kInvulShellRenderAmount; - } - } - - state->health = ent->v.health; - - kNumReturn1++; - - return 1; -} - +// +// Copyright (c) 1999, Valve LLC. All rights reserved. +// +// This product contains software technology licensed from Id +// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +// All Rights Reserved. +// +// Use, distribution, and modification of this source code and/or resulting +// object code is restricted to non-commercial enhancements to products from +// Valve LLC. All other use, distribution, or modification is prohibited +// without written permission from Valve LLC. +// +// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to +// have one without a hardcoded player.mdl in tf_client.cpp +// +//===== client.cpp ======================================================== +// +// client/server game specific stuff +// +// $Workfile: client.cpp $ +// $Date: 2002/11/22 21:09:09 $ +// +//------------------------------------------------------------------------------- +// $Log: client.cpp,v $ +// Revision 1.69 2002/11/22 21:09:09 Flayra +// - Added "lastinv" command back in +// - mp_consistency changes +// +// Revision 1.68 2002/11/15 23:31:01 Flayra +// - Added "ready" verification for tourny mode +// +// Revision 1.67 2002/11/15 05:08:31 Flayra +// - Little tweak for refinery +// +// Revision 1.66 2002/11/15 04:48:40 Flayra +// - Oops +// +// Revision 1.65 2002/11/15 04:41:32 Flayra +// - Big performance improvements for AddToFullPack (whew) +// +// Revision 1.64 2002/11/12 02:17:48 Flayra +// - Renamed "avhplayer" to "player" +// - Tweaked enhanced sight to actually be useful at lower levels +// +// Revision 1.63 2002/11/03 04:53:20 Flayra +// - AddToFullPack optimizations and cleanup +// +// Revision 1.62 2002/10/25 21:50:01 Flayra +// - New attempted fix for overflows. Propagate skin and playerclass in new way, so entities outside the ready room aren't propagated to all clients that go back to the ready room immediately on game end. +// +// Revision 1.61 2002/10/24 21:16:10 Flayra +// - Log Sys_Errors +// - Allow players to change their name before they first leave the ready room +// +// Revision 1.60 2002/10/20 17:25:04 Flayra +// - Redid performance improvement (agh) +// +// Revision 1.59 2002/10/20 16:34:09 Flayra +// - Returned code back to normal +// +// Revision 1.58 2002/10/19 22:33:48 Flayra +// - Various server optimizations +// +// Revision 1.57 2002/10/18 22:14:23 Flayra +// - Server optimizations (untested though, may need backing out) +// +// Revision 1.56 2002/10/16 00:38:50 Flayra +// - Queue up name change until end of game +// - Removed precaching of unneeded sounds +// - Optimized AvHDetermineVisibility (being called 1000s of times per tick) +// +// Revision 1.55 2002/10/03 18:27:39 Flayra +// - Moved order completion sounds into HUD sounds +// +// Revision 1.54 2002/09/25 20:37:53 Flayra +// - Precache more sayings +// +// Revision 1.53 2002/09/23 22:01:02 Flayra +// - Propagate skin +// - Don't treat unclaimed hives at world objects (even though team is 0) for visibility purposes +// - Added heavy model +// - Removed old mapper build preprocessor directives +// +// Revision 1.52 2002/08/31 18:01:17 Flayra +// - Work at VALVe +// +// Revision 1.51 2002/08/16 02:24:31 Flayra +// - Removed "give" cheat +// +// Revision 1.50 2002/08/09 00:15:46 Flayra +// - Removed behavior where "drop" would drop alien weapons in a disconcerting manner +// +// Revision 1.49 2002/07/25 16:50:15 flayra +// - Linux build changes +// +// Revision 1.48 2002/07/24 18:46:19 Flayra +// - Linux and scripting changes +// +// Revision 1.47 2002/07/23 16:46:38 Flayra +// - Added power-armor drawing, tweaked invul drawing +// +// Revision 1.46 2002/07/10 14:36:21 Flayra +// - .mp3 and particle fixes +// +// Revision 1.45 2002/07/08 16:38:57 Flayra +// - Draw invulnerable players differently +// +//=============================================================================== +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "player.h" +#include "spectator.h" +#include "client.h" +#include "soundent.h" +#include "gamerules.h" +#include "game.h" +#include "../engine/customentity.h" +#include "weapons.h" +#include "../common/weaponinfo.h" +#include "../common/usercmd.h" +#include "../common/netadr.h" +#include "../util/nowarnings.h" +#include "../mod/AvHPlayer.h" +#include "../mod/AvHSoundListManager.h" +#include "game.h" +#include "../mod/AvHParticleTemplateServer.h" +#include "../mod/AvHMarineEquipmentConstants.h" +#include "../mod/AvHSpecials.h" +#include "../util/Zassert.h" +#include "cbasedoor.h" +#include "../mod/AvHServerUtil.h" +#include "../mod/AvHMovementUtil.h" +#include "../mod/AvHSoundConstants.h" +#include "../mod/AvHHulls.h" +#include "../mod/AvHServerVariables.h" +#include "../mod/AvHSharedUtil.h" +#include "../mod/AvHGamerules.h" +#include "../mod/AvHAlienEquipmentConstants.h" +#include "triggers.h" +#include "../util/MathUtil.h" +#include "../mod/AvHServerUtil.h" +#include "../mod/AvHCloakable.h" +#include "../mod/AvHAlienAbilityConstants.h" +#include "../mod/AvHNetworkMessages.h" +#include "../mod/AvHNexusServer.h" + +#include "../game_shared/voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + +extern AvHSoundListManager gSoundListManager; + +extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; +extern DLL_GLOBAL BOOL g_fGameOver; +extern DLL_GLOBAL int g_iSkillLevel; +extern DLL_GLOBAL ULONG g_ulFrameCount; + +extern void CopyToBodyQue(entvars_t* pev); +extern int g_teamplay; + +/* + * used by kill command and disconnect command + * ROBIN: Moved here from player.cpp, to allow multiple player models + */ +void set_suicide_frame(entvars_t* pev) +{ + if (!FStrEq(STRING(pev->model), "models/player.mdl")) + return; // allready gibbed + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_TOSS; + pev->deadflag = DEAD_DEAD; + pev->nextthink = -1; +} + + +/* +=========== +LogStringForPlayer + +generates string for player event logging - KGP +============ +*/ + +std::string GetLogStringForPlayer( edict_t *pEntity ) +{ + // outputs "netname" if g_teamplay + // or "netname" if not g_teamplay + std::string result = "\""; + result += STRING( pEntity->v.netname ); + result += "<"; + result += MakeStringFromInt( GETPLAYERUSERID( pEntity ) ); + result += "><"; + result += AvHSUGetPlayerAuthIDString( pEntity ).c_str(); + result += "><"; + result += AvHSUGetTeamName( pEntity->v.team ); + result += ">\""; + return result; +} + +/* +=========== +ClientConnect + +called when a player connects to a server +============ +*/ +BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +{ + return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); + + // a client connecting during an intermission can cause problems + // if (intermission_running) + // ExitIntermission (); + +} + + +/* +=========== +ClientDisconnect + + called when a player disconnects from a server + + GLOBALS ASSUMED SET: g_fGameOver + ============ +*/ +void ClientDisconnect( edict_t *pEntity ) +{ + if (g_fGameOver) + return; + + char text[256]; + sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) ); + + CBaseEntity* theBaseEntity = CBaseEntity::Instance(ENT(pEntity)); + UTIL_SayTextAll(text, theBaseEntity); + + CSound *pSound; + pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); + { + // since this client isn't around to think anymore, reset their sound. + if ( pSound ) + { + pSound->Reset(); + } + } + + // since the edict doesn't get deleted, fix it so it doesn't interfere. + pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim + pEntity->v.solid = SOLID_NOT;// nonsolid + UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin ); + + g_pGameRules->ClientDisconnected( pEntity ); + + //: If this isnt set, clients around this player will crash. + pEntity->v.effects |= EF_NODRAW; +} + + +// called by ClientKill and DeadThink +void respawn(entvars_t* pev, BOOL fCopyCorpse) +{ + // AVH isn't dm, coop or single-player. + //if (gpGlobals->coop || gpGlobals->deathmatch) + //{ + if ( fCopyCorpse ) + { + // make a copy of the dead body for appearances sake + CopyToBodyQue(pev); + } + + // respawn player + GetClassPtr( (AvHPlayer *)pev)->Spawn( ); + //} + //else + //{ // restart the entire server + // SERVER_COMMAND("reload\n"); + //} +} + +/* +============ +ClientKill + +Player entered the suicide command + +GLOBALS ASSUMED SET: g_ulModelIndexPlayer +============ +*/ +void ClientKill( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + + CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); + + //if(GetGameRules()->GetCheatsEnabled()) + //{ + if ( pl->m_fNextSuicideTime > gpGlobals->time ) + return; // prevent suiciding too ofter + + pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding + + bool theIsCombatModeForSuicide = GetGameRules()->GetIsCombatMode(); + + #ifdef DEBUG + if(GetGameRules()->GetIsCombatMode()) + { + theIsCombatModeForSuicide = false; + } + #endif + + bool theCanSuicide = GetGameRules()->CanPlayerBeKilled(pl) && !theIsCombatModeForSuicide; + + if(theCanSuicide) + { + pl->Suicide(); + + // pev->modelindex = g_ulModelIndexPlayer; + // pev->frags -= 2; // extra penalty + // respawn( pev ); + } + //} +} + +/* +=========== +ClientPutInServer + +called each time a player is spawned +============ +*/ +void ClientPutInServer( edict_t *pEntity ) +{ + //CBasePlayer *pPlayer; + AvHPlayer *pPlayer; + + entvars_t *pev = &pEntity->v; + + if(pev->flags & FL_PROXY) + { + ALERT(at_logged, "Player with FL_PROXY put in server.\n"); + } + + if(pev->flags & FL_PROXY) + { + pev->flags |= FL_PROXY; + } + + pPlayer = GetClassPtr((AvHPlayer *)pev); + pPlayer->SetCustomDecalFrames(-1); // Assume none; + + // Allocate a CBasePlayer for pev, and call spawn + pPlayer->SetPlayMode(PLAYMODE_READYROOM); + //pPlayer->Spawn(); + + // Reset interpolation during first frame + pPlayer->pev->effects |= EF_NOINTERP; +} + +//// HOST_SAY +// String comes in as +// say blah blah blah +// or as +// blah blah blah +// +void Host_Say( edict_t *pEntity, int teamonly ) +{ + AvHPlayer* client; + AvHPlayer* theTalkingPlayer = dynamic_cast(CBaseEntity::Instance(pEntity)); + int j; + char* p; + char text[256]; + char szTemp[256]; + const char* cpSay = "say"; + const char* cpSayTeam = "say_team"; + const char* pcmd = CMD_ARGV(0); + bool theTalkerInReadyRoom = theTalkingPlayer->GetInReadyRoom(); + //bool theTalkerIsObserver = (theTalkingPlayer->GetPlayMode() == PLAYMODE_OBSERVER) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT); + + // We can get a raw string now, without the "say " prepended + if ( CMD_ARGC() == 0 ) + return; + + //Not yet. + if ( theTalkingPlayer->m_flNextChatTime > gpGlobals->time ) + return; + + if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) + { + if ( CMD_ARGC() >= 2 ) + { + p = (char *)CMD_ARGS(); + + if(GetGameRules()->GetIsTournamentMode() && !GetGameRules()->GetGameStarted()) + { + if(!strcmp(CMD_ARGV(1), kReadyNotification)) + { + // Team is ready + AvHTeam* theTeam = GetGameRules()->GetTeam((AvHTeamNumber)(pEntity->v.team)); + if(theTeam && !theTeam->GetIsReady()) + { + theTeam->SetIsReady(); + } + } + else if (!strcmp(CMD_ARGV(1), kNotReadyNotification)) + { + // Team is no longer ready + AvHTeam* theTeam = GetGameRules()->GetTeam((AvHTeamNumber)(pEntity->v.team)); + if(theTeam && theTeam->GetIsReady()) + { + theTeam->SetIsReady(false); + } + } + } + } + else + { + // say with a blank message, nothing to do + return; + } + } + else // Raw text, need to prepend argv[0] + { + if ( CMD_ARGC() >= 2 ) + { + sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); + } + else + { + // Just a one word command, use the first word...sigh + sprintf( szTemp, "%s", ( char * )pcmd ); + } + p = szTemp; + } + +// remove quotes if present + if (*p == '"') + { + p++; + p[strlen(p)-1] = 0; + } + +// make sure the text has content + char *pc=p; + for ( pc = p; pc != NULL && *pc != 0; pc++ ) + { + if ( isprint( *pc ) && !isspace( *pc ) ) + { + pc = NULL; // we've found an alphanumeric character, so text is valid + break; + } + } + if ( pc != NULL ) + return; // no character found, so say nothing + +// turn on color set 2 (color on, no sound) + if ( teamonly ) + sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); + else + sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); + + j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator + if ( (int)strlen(p) > j ) + p[j] = 0; + + strcat( text, p ); + strcat( text, "\n" ); + + theTalkingPlayer->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL; + // loop through all players + // Start with the first player. + // This may return the world in single player if the client types something between levels or during spawn + // so check it, or it will infinite loop + + client = NULL; + while ( ((client = (AvHPlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) + { + if ( !client->pev ) + continue; + + if ( client->edict() == pEntity ) + continue; + + if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) + continue; + + // can the receiver hear the sender? or has he muted him? + if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, theTalkingPlayer ) ) + continue; + + // Don't differentiate between team and non-team when not playing + bool theTalkingPlayerIsPlaying = ((theTalkingPlayer->GetPlayMode() == PLAYMODE_PLAYING) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_REINFORCING)); + bool theClientIsPlaying = ((client->GetPlayMode() == PLAYMODE_PLAYING) || (client->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (client->GetPlayMode() == PLAYMODE_REINFORCING)); + bool theTalkerIsObserver = theTalkingPlayer->IsObserver(); + bool theClientIsObserver = client->IsObserver(); + bool theClientIsHLTV = (client->pev->flags & FL_PROXY); + + bool theClientInReadyRoom = client->GetInReadyRoom(); + + if (theClientInReadyRoom != theTalkerInReadyRoom && !theClientIsHLTV) + { + continue; + } + + if (!theClientIsObserver || theClientIsPlaying ) // Non-playing Observers hear everything. + { + + if ( theTalkingPlayerIsPlaying && teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) + continue; + + // chat can never go between play area and non-play area + if(theTalkingPlayerIsPlaying != theClientIsPlaying && !theClientIsHLTV ) + continue; + + // chat of any kind doesn't go from ready room to play area in tournament mode + if(theTalkerInReadyRoom && GetGameRules()->GetIsTournamentMode() && theClientIsPlaying && !theClientIsHLTV) + continue; + + } + + UTIL_SayText(text, client, ENTINDEX(pEntity)); + + } + + // print to the sending client + UTIL_SayText(text, CBaseEntity::Instance(ENT(pEntity))); + + // echo to server console + g_engfuncs.pfnServerPrint( text ); + + char * temp; + if ( teamonly ) + temp = "say_team"; + else + temp = "say"; + +// UTIL_LogPrintf( "%s %s \"%s\"\n", GetLogStringForPlayer( pEntity ).c_str(), temp, p ); +} + + +/* +=========== +ClientCommand +called each time a player uses a "cmd" command +============ +*/ + +// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command. +void ClientCommand( edict_t *pEntity ) +{ + const char *pcmd = CMD_ARGV(0); + const char *pstr; + + // Is the client spawned yet? + if ( !pEntity->pvPrivateData ) + return; + + entvars_t *pev = &pEntity->v; + + AvHPlayer* thePlayer = GetClassPtr((AvHPlayer *)pev); + bool thePlayerCanAct = thePlayer->GetIsAbleToAct(); + + if ( FStrEq(pcmd, "say" ) ) + { + Host_Say( pEntity, 0 ); + } + else if ( FStrEq(pcmd, "say_team" ) ) + { + Host_Say( pEntity, 1 ); + } + else if ( FStrEq(pcmd, "fullupdate" ) ) + { + GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); + } + else if ( FStrEq(pcmd, "give" ) ) + { + if(GetGameRules()->GetCheatsEnabled()) + { + int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname + GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); + } + } + + else if ( FStrEq(pcmd, "drop" )) + { + if (thePlayerCanAct) + { + // player is dropping an item. + GetClassPtr((AvHPlayer *)pev)->DropItem((char *)CMD_ARGV(1)); + } + } + else if ( FStrEq(pcmd, "fov" ) ) + { + if (GetGameRules()->GetCheatsEnabled() && (CMD_ARGC() > 1)) + { + GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) ); + } + else + { + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) ); + } + } + else if ( FStrEq(pcmd, "use" )) + { + if (thePlayerCanAct) + { + GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); + } + } + else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) + { + if (thePlayerCanAct) + { + GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); + } + } + else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) ) + { + // MenuSelect returns true only if the command is properly handled, so don't print a warning + } + else if ( FStrEq( pcmd, "specmode" ) ) // new spectator mode + { + CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); + if ( pPlayer->IsObserver() ) + { + int theMode = atoi(CMD_ARGV(1)); + pPlayer->Observer_SetMode(theMode); + pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); + } + } + else if (FStrEq( pcmd, "follow")) // follow a specific player + { + CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); + if ( pPlayer->IsObserver() ) + { + pPlayer->Observer_SpectatePlayer(atoi( CMD_ARGV(1) )); + pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); + } + } + else if ( FStrEq( pcmd, "follownext" ) ) // follow next player + { + CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); + if ( pPlayer->IsObserver() ) + { + pPlayer->Observer_FindNextPlayer(atoi( CMD_ARGV(1) )); + pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); + } + } + else + { + // tell the user they entered an unknown command + char command[128]; + + // check the length of the command (prevents crash) + // max total length is 192 ...and we're adding a string below ("Unknown command: %s\n") + strncpy( command, pcmd, 127 ); + command[127] = '\0'; + // : 1071 + // Remove printf formatting + for ( int i=0; i < 127; i++ ) { + if ( command[i] == '%' ) { + command[i] = ' '; + } + } + // : + // tell the user they entered an unknown command + ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) ); + } + //else if(!AvHClientCommand(pEntity)) + //{ + // // tell the user they entered an unknown command + // ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pcmd ) ); + //} +} + +//bool AvHClientCommand( edict_t *pEntity ) +//{ +//} + +/* +======================== +ClientUserInfoChanged + +called after the player changes +userinfo - gives dll a chance to modify it before +it gets sent into the rest of the engine. +======================== +*/ +void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) +{ + // Is the client spawned yet? + if ( !pEntity->pvPrivateData ) + return; + + const char* theCurrentNetName = STRING(pEntity->v.netname); + const char* theNameKeyValue = g_engfuncs.pfnInfoKeyValue(infobuffer, "name"); + + // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) + if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq(theCurrentNetName, theNameKeyValue) ) + { + AvHPlayer* thePlayer = dynamic_cast(CBaseEntity::Instance(pEntity)); + + // Don't change player info after match has started unless player hasn't left ready room + if(!GetGameRules()->GetArePlayersAllowedToJoinImmediately() && thePlayer && theNameKeyValue && thePlayer->GetHasLeftReadyRoom()) + { + thePlayer->SetDesiredNetName(string(theNameKeyValue)); + + char text[256]; + sprintf( text, "* Name will be changed to %s next game.\n", theNameKeyValue); + UTIL_SayText(text, CBaseEntity::Instance(ENT(pEntity))); + + // Restore name key value changed by engine + char theName[256]; + strcpy(theName, theCurrentNetName); + g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", theName); + } + else + { + char sName[256]; + char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); + strncpy( sName, pName, sizeof(sName) - 1 ); + sName[ sizeof(sName) - 1 ] = '\0'; + + // First parse the name and remove any %'s + for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) + { + // Replace it with a space + if ( *pApersand == '%' ) + *pApersand = ' '; + } + + // Set the name + g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); + //thePlayer->SetDesiredNetName(MAKE_STRING(sName)); + + char text[256]; + sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + + UTIL_SayTextAll(text, CBaseEntity::Instance(ENT(pEntity))); + +// UTIL_LogPrintf( "%s changed name to \"%s\"\n", GetLogStringForPlayer( pEntity ).c_str(), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + } + } + + g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); +} + +static int g_serveractive = 0; + +void ServerDeactivate( void ) +{ + // It's possible that the engine will call this function more times than is necessary + // Therefore, only run it one time for each call to ServerActivate + if ( g_serveractive != 1 ) + { + return; + } + + g_serveractive = 0; + + // Peform any shutdown operations here... + // +} + +void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) +{ + int i; + CBaseEntity *pClass; + + // Every call to ServerActivate should be matched by a call to ServerDeactivate + g_serveractive = 1; + + // Clients have not been initialized yet + for ( i = 0; i < edictCount; i++ ) + { + if ( pEdictList[i].free ) + continue; + + // Clients aren't necessarily initialized until ClientPutInServer() + if ( i < clientMax || !pEdictList[i].pvPrivateData ) + continue; + + pClass = CBaseEntity::Instance( &pEdictList[i] ); + // Activate this entity if it's got a class & isn't dormant + if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) + { + pClass->Activate(); + } + else + { + ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); + } + } + + Net_InitializeMessages(); +} + + +/* +================ +PlayerPreThink + +Called every frame before physics are run +================ +*/ +void PlayerPreThink( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->PreThink( ); +} + +/* +================ +PlayerPostThink + +Called every frame after physics are run +================ +*/ +void PlayerPostThink( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->PostThink( ); +} + + + +void ParmsNewLevel( void ) +{ +} + + +void ParmsChangeLevel( void ) +{ + // retrieve the pointer to the save data + SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; + + if ( pSaveData ) + pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); +} + +void ShowMenu(entvars_s *pev, int ValidSlots, int DisplayTime, BOOL ShowLater, char Menu[500]) +{ + NetMsg_ShowMenu( pev, ValidSlots, DisplayTime, ShowLater ? 1 : 0, string(Menu) ); +} + +// +// GLOBALS ASSUMED SET: g_ulFrameCount +// +void StartFrame( void ) +{ + if ( g_pGameRules ) + g_pGameRules->Think(); + + if ( g_fGameOver ) + return; + + gpGlobals->teamplay = teamplay.value; + + g_ulFrameCount++; +} + +void ClientPrecache( void ) +{ + // Precache sound lists for all player types + gSoundListManager.Clear(); + + int i=0; + for(i = ((int)AVH_USER3_NONE + 1); i < (int)AVH_USER3_ALIEN_EMBRYO; i++) + { + char theSoundListName[256]; + bool theIsAlien = (i > 3); + AvHUser3 theUser3 = (AvHUser3)(i); + + bool theLoadSounds = false; + + // No squad leader and commander sounds + switch(theUser3) + { + case AVH_USER3_MARINE_PLAYER: + case AVH_USER3_ALIEN_PLAYER1: + case AVH_USER3_ALIEN_PLAYER2: + case AVH_USER3_ALIEN_PLAYER3: + case AVH_USER3_ALIEN_PLAYER4: + case AVH_USER3_ALIEN_PLAYER5: + theLoadSounds = true; + } + + if(theLoadSounds) + { + // Die sounds + sprintf(theSoundListName, kPlayerLevelDieSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + // Spawn sounds + sprintf(theSoundListName, kPlayerLevelSpawnSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + // Pain sounds + sprintf(theSoundListName, kPlayerLevelPainSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + // Wound sounds + sprintf(theSoundListName, kPlayerLevelWoundSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + // Attack sounds (aliens only) + if(theIsAlien) + { + sprintf(theSoundListName, kPlayerLevelAttackSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + // Idle sounds + sprintf(theSoundListName, kPlayerLevelIdleSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + // Movement sounds + sprintf(theSoundListName, kPlayerLevelMoveSoundList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + } + } + } + + // Precache misc. alien sounds + //PRECACHE_SOUND(kAdrenalineSound); + PRECACHE_UNMODIFIED_SOUND(kGestationSound); + PRECACHE_UNMODIFIED_SOUND(kEggDestroyedSound); + PRECACHE_UNMODIFIED_SOUND(kEggIdleSound); + PRECACHE_UNMODIFIED_SOUND(kPrimalScreamResponseSound); + + // Preacache sayings sound list + for(i = 1; i <= 9; i++) + { + char theSoundListName[256]; + + sprintf(theSoundListName, kSoldierSayingList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + sprintf(theSoundListName, kCommanderSayingList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + + sprintf(theSoundListName, kAlienSayingList, i); + gSoundListManager.PrecacheSoundList(theSoundListName); + } + + // Precache order sounds + gSoundListManager.PrecacheSoundList(kSoldierOrderRequestList); + gSoundListManager.PrecacheSoundList(kSoldierOrderAckList); + + // Precache other sound lists + gSoundListManager.PrecacheSoundList(kResourceTowerSoundList); + gSoundListManager.PrecacheSoundList(kAlienResourceTowerSoundList); + gSoundListManager.PrecacheSoundList(kHiveWoundSoundList); + gSoundListManager.PrecacheSoundList(kMarineConstructionSoundList); + gSoundListManager.PrecacheSoundList(kElectricSparkSoundList); + gSoundListManager.PrecacheSoundList(kAlienConstructionSoundList); + + // Other equipment and effect sounds + PRECACHE_UNMODIFIED_SOUND(kMarineBuildingDeploy); + PRECACHE_UNMODIFIED_SOUND(kJetpackSound); + PRECACHE_UNMODIFIED_SOUND(kWeldingSound); + PRECACHE_UNMODIFIED_SOUND(kWeldingHitSound); + //PRECACHE_UNMODIFIED_SOUND(kOverwatchStartSound); + //PRECACHE_UNMODIFIED_SOUND(kOverwatchEndSound); + PRECACHE_UNMODIFIED_SOUND(kRegenerationSound); + PRECACHE_UNMODIFIED_SOUND(kStartCloakSound); + PRECACHE_UNMODIFIED_SOUND(kEndCloakSound); + //PRECACHE_UNMODIFIED_SOUND(kWallJumpSound); + PRECACHE_UNMODIFIED_SOUND(kWingFlapSound1); + PRECACHE_UNMODIFIED_SOUND(kWingFlapSound2); + PRECACHE_UNMODIFIED_SOUND(kWingFlapSound3); + PRECACHE_UNMODIFIED_SOUND(kSiegeHitSound1); + PRECACHE_UNMODIFIED_SOUND(kSiegeHitSound2); + + // setup precaches always needed + PRECACHE_UNMODIFIED_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha + + // PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound + + // Alien step sounds + PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a1.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a1.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a1.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a1.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a5.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a5.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a5.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a5.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_step1-h.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step2-h.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step3-h.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step4-h.wav"); + + // Marine step sounds + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-1.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-4.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-5.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-6.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-7.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-8.wav"); + PRECACHE_UNMODIFIED_SOUND(kDigestingSound); + + PRECACHE_UNMODIFIED_SOUND("player/pl_step1.wav"); // walk on concrete + PRECACHE_UNMODIFIED_SOUND("player/pl_step2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_step4.wav"); + + PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete + PRECACHE_SOUND("common/npc_step2.wav"); + PRECACHE_SOUND("common/npc_step3.wav"); + PRECACHE_SOUND("common/npc_step4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_metal1.wav"); // walk on metal + PRECACHE_UNMODIFIED_SOUND("player/pl_metal2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_metal3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_metal4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_dirt1.wav"); // walk on dirt + PRECACHE_UNMODIFIED_SOUND("player/pl_dirt2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_dirt3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_dirt4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_duct1.wav"); // walk in duct + PRECACHE_UNMODIFIED_SOUND("player/pl_duct2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_duct3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_duct4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_grate1.wav"); // walk on grate + PRECACHE_UNMODIFIED_SOUND("player/pl_grate2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_grate3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_grate4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_slosh1.wav"); // walk in shallow water + PRECACHE_UNMODIFIED_SOUND("player/pl_slosh2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_slosh3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_slosh4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_tile1.wav"); // walk on tile + PRECACHE_UNMODIFIED_SOUND("player/pl_tile2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_tile3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_tile4.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_tile5.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_swim1.wav"); // breathe bubbles + PRECACHE_UNMODIFIED_SOUND("player/pl_swim2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_swim3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_swim4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_ladder1.wav"); // climb ladder rung + PRECACHE_UNMODIFIED_SOUND("player/pl_ladder2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_ladder3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_ladder4.wav"); + + PRECACHE_UNMODIFIED_SOUND("player/pl_wade1.wav"); // wade in water + PRECACHE_UNMODIFIED_SOUND("player/pl_wade2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_wade3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_wade4.wav"); + + PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture + PRECACHE_SOUND("debris/wood2.wav"); + PRECACHE_SOUND("debris/wood3.wav"); + + PRECACHE_UNMODIFIED_SOUND("plats/train_use1.wav"); // use a train + + PRECACHE_UNMODIFIED_SOUND("buttons/spark5.wav"); // hit computer texture + PRECACHE_UNMODIFIED_SOUND("buttons/spark6.wav"); + PRECACHE_SOUND("debris/glass1.wav"); + PRECACHE_SOUND("debris/glass2.wav"); + PRECACHE_SOUND("debris/glass3.wav"); + + PRECACHE_UNMODIFIED_SOUND( SOUND_FLASHLIGHT_ON ); + PRECACHE_UNMODIFIED_SOUND( SOUND_FLASHLIGHT_OFF ); + +// player gib sounds + PRECACHE_SOUND("common/bodysplat.wav"); + +// player pain sounds + PRECACHE_UNMODIFIED_SOUND("player/pl_pain2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_pain4.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_pain5.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_pain6.wav"); + PRECACHE_UNMODIFIED_SOUND("player/pl_pain7.wav"); + + PRECACHE_UNMODIFIED_MODEL("models/player.mdl"); + PRECACHE_UNMODIFIED_MODEL(kReadyRoomModel); + + PRECACHE_UNMODIFIED_MODEL(kMarineSoldierModel); + PRECACHE_UNMODIFIED_MODEL(kHeavySoldierModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelOneModel); + + PRECACHE_UNMODIFIED_MODEL(kAlienLevelTwoModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelThreeModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelFourModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelFiveModel); + + PRECACHE_UNMODIFIED_MODEL(kMarineCommanderModel); + PRECACHE_UNMODIFIED_MODEL(kAlienGestateModel); + + + // hud sounds, for marines and aliens (change AvHSharedUtil::AvHSHUGetCommonSoundName if these sound names change) + PRECACHE_UNMODIFIED_SOUND("common/wpn_hudoff.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_hudon.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_moveselect.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_select.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_denyselect.wav"); + + PRECACHE_UNMODIFIED_SOUND("common/wpn_hudoff-a.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_hudon-a.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_moveselect-a.wav"); + + PRECACHE_UNMODIFIED_SOUND("common/wpn_select-a.wav"); + PRECACHE_UNMODIFIED_SOUND("common/wpn_denyselect-a.wav"); + + // geiger sounds + PRECACHE_UNMODIFIED_SOUND("player/geiger6.wav"); + PRECACHE_UNMODIFIED_SOUND("player/geiger5.wav"); + PRECACHE_UNMODIFIED_SOUND("player/geiger4.wav"); + PRECACHE_UNMODIFIED_SOUND("player/geiger3.wav"); + PRECACHE_UNMODIFIED_SOUND("player/geiger2.wav"); + PRECACHE_UNMODIFIED_SOUND("player/geiger1.wav"); + + PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash1.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash2.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash3.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/digesting.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/membrane.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/hera_fog.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/spore.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/spore2.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/umbra.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/umbra2.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/webstrand.spr"); + + PRECACHE_UNMODIFIED_GENERIC("ns.wad"); + PRECACHE_UNMODIFIED_GENERIC("ns2.wad"); + PRECACHE_UNMODIFIED_GENERIC("v_wad.wad"); +/* PRECACHE_UNMODIFIED_GENERIC("maps/co_angst_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_core_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_daimos_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_ether_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_faceoff_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_kestrel_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_niveus_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_pulse_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_sava_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_ulysses_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/co_umbra_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_altair_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_ayumi_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_bast_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_caged_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_eclipse_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_eon_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_hera_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_lost_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_lucid_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_machina_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_metal_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_nancy_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_nothing_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_origin_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_prometheus_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_shiva_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_tanith_detail.txt"); + PRECACHE_UNMODIFIED_GENERIC("maps/ns_veil_detail.txt"); + + CStringList list; + string modDir=string(getModDirectory()) + "/"; + if(BuildFileList(modDir, "maps/", "*_detail.txt", list)) + { + for(CStringList::iterator it=list.begin(); it != list.end(); it++ ) { + int iString = ALLOC_STRING((char*)it);//: We cant do "(char*)theSoundToPrecache" directly cause it causes some wierd problems. + PRECACHE_UNMODIFIED_GENERIC((char*)STRING(iString)); + } + } + */ +} + +/* +================ +Sys_Error + + Engine is going to shut down, allows setting a breakpoint in game .dll to catch that occasion + ================ + */ + void Sys_Error( const char *error_string ) + { +#ifdef DEBUG +#ifdef WIN32 + // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls + _asm { int 3 }; +#endif +#else + char theDebugString[2056]; + sprintf(theDebugString, "Sys_Error: %s\n", error_string); + ALERT(at_error, theDebugString); +#endif + +} + +/* +=============== +GetGameDescription + +Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 +=============== +*/ +const char *GetGameDescription() +{ + if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized + return g_pGameRules->GetGameDescription(); + else + return "Half-Life"; +} + +/* +================ +PlayerCustomization + +A new player customization has been registered on the server +UNDONE: This only sets the # of frames of the spray can logo +animation right now. +================ +*/ +void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) +{ + entvars_t *pev = &pEntity->v; + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + + if (!pPlayer) + { + ALERT(at_console, "PlayerCustomization: Couldn't get player!\n"); + return; + } + + if (!pCust) + { + ALERT(at_console, "PlayerCustomization: NULL customization!\n"); + return; + } + + switch (pCust->resource.type) + { + case t_decal: + pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames. + break; + case t_sound: + case t_skin: + case t_model: + // Ignore for now. + break; + default: + ALERT(at_console, "PlayerCustomization: Unknown customization type!\n"); + break; + } +} + +/* +================ +SpectatorConnect + +A spectator has joined the game +================ +*/ +void SpectatorConnect( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorConnect( ); +} + +/* +================ +SpectatorConnect + +A spectator has left the game +================ +*/ +void SpectatorDisconnect( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorDisconnect( ); +} + +/* +================ +SpectatorConnect + +A spectator has sent a usercmd +================ +*/ +void SpectatorThink( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorThink( ); +} + +//////////////////////////////////////////////////////// +// PAS and PVS routines for client messaging +// + +/* +================ +SetupVisibility + +A client can have a separate "view entity" indicating that his/her view should depend on the origin of that +view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current +entity's origin is used. Either is offset by the view_ofs to get the eye position. + +From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could + override the actual PAS or PVS values, or use a different origin. + +NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame +================ +*/ +void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) +{ + Vector org; + edict_t *pView = pClient; + bool theUseSpecialPASOrigin = false; + Vector theSpecialPASOrigin; + + // Find the client's PVS + if ( pViewEntity ) + { + pView = pViewEntity; + } + + // Proxy sees and hears all + if ( (pClient->v.flags & FL_PROXY) || GetGameRules()->GetIsCheatEnabled(kcViewAll)) + { + //ALERT(at_logged, "Setting PVS and PAS to NULL for FL_PROXY\n"); + *pvs = NULL; // the spectator proxy sees + *pas = NULL; // and hears everything + return; + } + + // Tracking Spectators use the visibility of their target + CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); + if ( (pPlayer->pev->iuser2 != 0) && (pPlayer->m_hObserverTarget != NULL) && (pPlayer->m_afPhysicsFlags & PFLAG_OBSERVER) && pPlayer->IsAlive()) + { + pView = pPlayer->m_hObserverTarget->edict(); + UTIL_SetOrigin( pPlayer->pev, pPlayer->m_hObserverTarget->pev->origin ); + } + + // Tracking Spectators use the visibility of their target +// AvHPlayer *thePlayer = dynamic_cast(CBaseEntity::Instance(pClient)); + + // cgc - something could be wrong here, crashing from Robin's spectator code...did I do something wrong? +// if(thePlayer) +// { +// if ( (thePlayer->pev->iuser2 != 0) && (thePlayer->m_hObserverTarget != NULL) ) +// { +// pView = thePlayer->m_hObserverTarget->edict(); +// } +// +// if(thePlayer->GetRole() == ROLE_COMMANDER) +// { +// thePlayer->GetSpecialPASOrigin(theSpecialPASOrigin); +// theUseSpecialPASOrigin = true; +// } +// } + + org = pView->v.origin + pView->v.view_ofs; + if ( pView->v.flags & FL_DUCKING ) + { + org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + } + + *pvs = ENGINE_SET_PVS ( (float *)&org ); + + if(theUseSpecialPASOrigin) + { + *pas = ENGINE_SET_PAS ( (float *)&theSpecialPASOrigin ); + } + else + { + *pas = ENGINE_SET_PAS ( (float *)&org ); + } +} + +#include "../common/entity_state.h" + +//CachedEntity gCachedEntities[kMaxPlayers][kMaxEntities]; +// +//void ResetCachedEntities() +//{ +// for(int i = 0; i < kMaxPlayers; i++) +// { +// for(int j = 0; j < kMaxEntities; j++) +// { +// gCachedEntities[i][j].ResetCachedEntity(); +// } +// } +//} + + + +// Array sizes ( memory is 5624 * 32 = 179968 bytes ) +#define MAX_CLIENTS ( 32 ) +#define MAX_ENTITIES ( 900 + MAX_CLIENTS * 15 ) + +// Re-check entities only this often once they are found to be in the PVS +// NOTE: We could have a separate timeout for players if we wanted to tweak the coherency time for them ( you'd have +// to check the entitynum against 1 to gpGlobals->maxclients ), etc. +//#define PVS_COHERENCY_TIME 1.0f + +extern float kPVSCoherencyTime; + +typedef struct +{ + bool mLastVisibility; + float m_fTimeEnteredPVS; +} ENTITYPVSSTATUS; + +typedef struct +{ + ENTITYPVSSTATUS m_Status[ MAX_ENTITIES ]; + + // Remember player leaf data so we can invalidate pvs history when leaf changes + int headnode; // -1 to use normal leaf check + int num_leafs; + short leafnums[ MAX_ENT_LEAFS ]; + +} PLAYERPVSSTATUS; + +static PLAYERPVSSTATUS g_PVSStatus[ MAX_CLIENTS ]; + +void ResetPlayerPVS( edict_t *client, int clientnum ) +{ + ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); + + PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; + + memset( pvs, 0, sizeof( PLAYERPVSSTATUS ) ); + + // Copy leaf data in right away + pvs->headnode = client->headnode; + pvs->num_leafs = client->num_leafs; + memcpy( pvs->leafnums, client->leafnums, sizeof( pvs->leafnums ) ); +} + +bool TimeToResetPVS( edict_t *client, int clientnum ) +{ + ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); + + PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; + + if ( (pvs->headnode != client->headnode) || (pvs->num_leafs != client->num_leafs)) + return true; + + if ( client->num_leafs > 0 ) + { + for ( int i = 0; i < client->num_leafs; i++ ) + { + if ( client->leafnums[ i ] != pvs->leafnums[ i ] ) + { + return true; + } + } + } + + // Still the same + return false; +} + +void MarkEntityInPVS( int clientnum, int entitynum, float time, bool inpvs ) +{ + ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); + ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); + + PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; + ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; + + es->m_fTimeEnteredPVS = time; + es->mLastVisibility = inpvs; +} + +bool GetTimeToRecompute( int clientnum, int entitynum, float currenttime, bool& outCachedVisibility) +{ + ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); + ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); + + PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; + ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; + + bool theTimeToRecompute = false; + + int theUseCaching = BALANCE_VAR(kDebugServerCaching); + if(theUseCaching) + { + // Always recompute players? + if((entitynum > 0) && (entitynum < MAX_CLIENTS)) + { + theTimeToRecompute = true; + } + // If we haven't computed for awhile, or our PVS has been reset + else if((currenttime > (es->m_fTimeEnteredPVS + kPVSCoherencyTime)) || (es->m_fTimeEnteredPVS == 0.0f)) + { + theTimeToRecompute = true; + } + else + { + outCachedVisibility = es->mLastVisibility; + } + } + else + { + theTimeToRecompute = true; + } + + return theTimeToRecompute; +} + +bool CheckEntityRecentlyInPVS( int clientnum, int entitynum, float currenttime ) +{ + ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); + ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); + + PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; + ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; + + int theUseCaching = BALANCE_VAR(kDebugServerCaching); + if(!theUseCaching) + { + return false; + } + + // Wasn't in pvs before, sigh... + if ( es->m_fTimeEnteredPVS == 0.0f ) + { + return false; + } + + // If we've been saying yes for kPVSCoherencyTime, say no now instead so that we'll do a full check + if ( es->m_fTimeEnteredPVS + kPVSCoherencyTime < currenttime ) + { + return false; + } + + // Keep assuming it's in the pvs for a bit of time (trivial inclusion) + return true; +} + + +int kNumReturn0 = 0; +int kNumReturn1 = 0; +int kNumCached = 0; +int kNumComputed = 0; +int kMaxE = 0; +int kNumEntsProcessedForPlayerOne = 0; +int kMaxEProcessedForPlayerOne = 0; +extern int kServerFrameRate; + +// ENGINE_CHECK_VISIBILITY, from Yahn, with his comments: +// +// Here's the engine code. You'll note a slow path if the ent leaf cache is missed, which causes a recomputation via the much more expensive +// CM_HeadnodeVisible call. That does change the cache data on the entity, so that's likely your problem with blinking if you are doing some +// kind of memcpy operation on the old data. +//#ifdef 0 +//int DLL_CALLBACK SV_CheckVisibility( const struct edict_s *entity, unsigned char *pset ) +//{ +// int i; +// qboolean visible; +// edict_t *e; +// +// if ( !pset ) +// return 1; +// +// if ( entity->headnode >= 0 ) // +// { +// // we use num_leafs as a cache/counter, it will circle around, but so what +// // if we don't find the leaf we want here, we'll end up doing the full test anyway +// int leaf; +// i = 0; +// +// do +// { +// leaf = entity->leafnums[i]; +// // Cache is all -1 to start... +// if ( leaf == -1 ) +// break; +// +// if ( pset[ leaf >> 3 ] & (1 << (leaf & 7 ) ) ) +// { +// return 1; +// } +// +// i++; +// if ( i >= MAX_ENT_LEAFS ) +// break; +// +// } while ( 1 ); +// +// // Didn't find it in "cache" +// +// visible = CM_HeadnodeVisible( sv.worldmodel->nodes + entity->headnode, pset, &leaf ); +// if ( !visible ) +// { +// return 0; +// } +// +// // Cache leaf that was visible +// // +// e = ( edict_t * )entity; +// +// e->leafnums[ entity->num_leafs ] = (short)leaf; +// e->num_leafs = ( entity->num_leafs + 1 ) % MAX_ENT_LEAFS; +// +// return 2; +// } +// else +// { +// for (i=0 ; i < entity->num_leafs ; i++) +// { +// if ( pset[entity->leafnums[i] >> 3] & (1 << (entity->leafnums[i]&7) )) +// break; +// } +// +// visible = ( i < entity->num_leafs ); +// if ( !visible ) +// { +// return 0; +// } +// } +// +// return 1; +//} +//#endif + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 + +/* +=================== +CreateBaseline + +Creates baselines used for network encoding, especially for player data since players are not spawned until connect time. +=================== +*/ +void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) +{ + baseline->origin = entity->v.origin; + baseline->angles = entity->v.angles; + baseline->frame = entity->v.frame; + baseline->skin = (short)entity->v.skin; + + // render information + baseline->rendermode = (byte)entity->v.rendermode; + baseline->renderamt = (byte)entity->v.renderamt; + baseline->rendercolor.r = (byte)entity->v.rendercolor.x; + baseline->rendercolor.g = (byte)entity->v.rendercolor.y; + baseline->rendercolor.b = (byte)entity->v.rendercolor.z; + baseline->renderfx = (byte)entity->v.renderfx; + + if ( player ) + { + baseline->mins = player_mins; + baseline->maxs = player_maxs; + + baseline->colormap = eindex; + baseline->modelindex = playermodelindex; + baseline->friction = 1.0; + baseline->movetype = MOVETYPE_WALK; + + baseline->scale = entity->v.scale; + baseline->solid = SOLID_SLIDEBOX; + baseline->framerate = 1.0; + baseline->gravity = 1.0; + + } + else + { + baseline->mins = entity->v.mins; + baseline->maxs = entity->v.maxs; + + baseline->colormap = 0; + baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); + baseline->movetype = entity->v.movetype; + + baseline->scale = entity->v.scale; + baseline->solid = entity->v.solid; + baseline->framerate = entity->v.framerate; + baseline->gravity = entity->v.gravity; + } +} + +typedef struct +{ + char name[32]; + int field; +} entity_field_alias_t; + +#define FIELD_ORIGIN0 0 +#define FIELD_ORIGIN1 1 +#define FIELD_ORIGIN2 2 +#define FIELD_ANGLES0 3 +#define FIELD_ANGLES1 4 +#define FIELD_ANGLES2 5 + +static entity_field_alias_t entity_field_alias[]= +{ + { "origin[0]", 0 }, + { "origin[1]", 0 }, + { "origin[2]", 0 }, + { "angles[0]", 0 }, + { "angles[1]", 0 }, + { "angles[2]", 0 }, +}; + +void Entity_FieldInit( struct delta_s *pFields ) +{ + entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); + entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); + entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); + entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); + entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); + entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); +} + +/* +================== +Entity_Encode + +Callback for sending entity_state_t info over network. +FIXME: Move to script +================== +*/ +void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) +{ + entity_state_t *f, *t; + int localplayer = 0; + static int initialized = 0; + + if ( !initialized ) + { + Entity_FieldInit( pFields ); + initialized = 1; + } + + f = (entity_state_t *)from; + t = (entity_state_t *)to; + + // Never send origin to local player, it's sent with more resolution in clientdata_t structure + localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); + if ( localplayer ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + + if ( ( t->impacttime != 0 ) && ( t->starttime != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES2 ].field ); + } + + if ( ( t->movetype == MOVETYPE_FOLLOW ) && + ( t->aiment != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + else if ( t->aiment != f->aiment ) + { + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } +} + +static entity_field_alias_t player_field_alias[]= +{ + { "origin[0]", 0 }, + { "origin[1]", 0 }, + { "origin[2]", 0 }, +}; + +void Player_FieldInit( struct delta_s *pFields ) +{ + player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); + player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); + player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); +} + +/* +================== +Player_Encode + +Callback for sending entity_state_t for players info over network. +================== +*/ +void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) +{ + entity_state_t *f, *t; + int localplayer = 0; + static int initialized = 0; + + if ( !initialized ) + { + Player_FieldInit( pFields ); + initialized = 1; + } + + f = (entity_state_t *)from; + t = (entity_state_t *)to; + + // Never send origin to local player, it's sent with more resolution in clientdata_t structure + localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); + if ( localplayer ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + + if ( ( t->movetype == MOVETYPE_FOLLOW ) && + ( t->aiment != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + else if ( t->aiment != f->aiment ) + { + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } +} + +#define CUSTOMFIELD_ORIGIN0 0 +#define CUSTOMFIELD_ORIGIN1 1 +#define CUSTOMFIELD_ORIGIN2 2 +#define CUSTOMFIELD_ANGLES0 3 +#define CUSTOMFIELD_ANGLES1 4 +#define CUSTOMFIELD_ANGLES2 5 +#define CUSTOMFIELD_SKIN 6 +#define CUSTOMFIELD_SEQUENCE 7 +#define CUSTOMFIELD_ANIMTIME 8 + +entity_field_alias_t custom_entity_field_alias[]= +{ + { "origin[0]", 0 }, + { "origin[1]", 0 }, + { "origin[2]", 0 }, + { "angles[0]", 0 }, + { "angles[1]", 0 }, + { "angles[2]", 0 }, + { "skin", 0 }, + { "sequence", 0 }, + { "animtime", 0 }, +}; + +void Custom_Entity_FieldInit( struct delta_s *pFields ) +{ + custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); + custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); +} + +/* +================== +Custom_Encode + +Callback for sending entity_state_t info ( for custom entities ) over network. +FIXME: Move to script +================== +*/ +void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) +{ + entity_state_t *f, *t; + int beamType; + static int initialized = 0; + + if ( !initialized ) + { + Custom_Entity_FieldInit( pFields ); + initialized = 1; + } + + f = (entity_state_t *)from; + t = (entity_state_t *)to; + + beamType = t->rendermode & 0x0f; + + if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); + } + + if ( beamType != BEAM_POINTS ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); + } + + if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); + } + + // animtime is compared by rounding first + // see if we really shouldn't actually send it + if ( (int)f->animtime == (int)t->animtime ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); + } +} + +/* +================= +RegisterEncoders + +Allows game .dll to override network encoding of certain types of entities and tweak values, etc. +================= +*/ +void RegisterEncoders( void ) +{ + DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); + DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); + DELTA_ADDENCODER( "Player_Encode", Player_Encode ); +} + +int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) +{ + int i; + weapon_data_t *item; + entvars_t *pev = &player->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + AvHPlayer* thePlayer = dynamic_cast(pl); + CBasePlayerWeapon *gun; + + ItemInfo II; + + memset( info, 0, 32 * sizeof( weapon_data_t ) ); + + if ( !pl ) + return 1; + + // go through all of the weapons and make a list of the ones to pack + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( pl->m_rgpPlayerItems[ i ] ) + { + // there's a weapon here. Should I pack it? + CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; + + while ( pPlayerItem ) + { + gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); + if ( gun && gun->UseDecrement() ) + { + // Get The ID. + memset( &II, 0, sizeof( II ) ); + gun->GetItemInfo( &II ); + + ASSERT((II.iId >= 0) && (II.iId < 32)); + + if ( II.iId >= 0 && II.iId < 32 ) + { + item = &info[ II.iId ]; + + item->m_iId = II.iId; + item->m_iClip = gun->m_iClip; + + item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001f ); + item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001f ); + item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001f ); + item->m_fInReload = gun->m_fInReload; + + //thePlayer->SetDebugCSP(item); + + //item->m_fInSpecialReload = gun->m_fInSpecialReload; + //item->fuser1 = max( gun->pev->fuser1, -0.001 ); + item->fuser2 = gun->m_flStartThrow; + item->fuser3 = gun->m_flReleaseThrow; + //item->iuser1 = gun->m_chargeReady; + //item->iuser2 = gun->m_fInAttack; + + // Pass along enabled state in iuser3 (for when hives and ensnare enable and disable weapons) + item->iuser3 = gun->pev->iuser3; + + //item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); + } + } + pPlayerItem = pPlayerItem->m_pNext; + } + } + } + return 1; +} + +/* +================= +UpdateClientData + +Data sent to current client only +engine sets cd to 0 before calling. +================= +*/ +void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +{ + cd->flags = ent->v.flags; + cd->health = ent->v.health; + + cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); + + cd->waterlevel = ent->v.waterlevel; + cd->watertype = ent->v.watertype; + cd->weapons = ent->v.weapons; + + // Vectors + cd->origin = ent->v.origin; + cd->velocity = ent->v.velocity; + cd->view_ofs = ent->v.view_ofs; + cd->punchangle = ent->v.punchangle; + + cd->bInDuck = ent->v.bInDuck; + cd->flTimeStepSound = ent->v.flTimeStepSound; + cd->flDuckTime = ent->v.flDuckTime; + cd->flSwimTime = ent->v.flSwimTime; + cd->waterjumptime = ent->v.teleport_time; + + strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); + + cd->maxspeed = ent->v.maxspeed; + cd->fov = ent->v.fov; + cd->weaponanim = ent->v.weaponanim; + + cd->pushmsec = ent->v.pushmsec; + + // Spectator + cd->iuser1 = ent->v.iuser1; + cd->iuser2 = ent->v.iuser2; + + // AvH specials + cd->iuser3 = ent->v.iuser3; + cd->iuser4 = ent->v.iuser4; + cd->fuser1 = ent->v.fuser1; + cd->fuser2 = ent->v.fuser2; + cd->fuser3 = ent->v.fuser3; + + // Added by mmcguire for oriented skulk player models. + cd->vuser1 = ent->v.vuser1; + + // Added for extra player info for first-person spectating + cd->vuser4 = ent->v.vuser4; + + if ( sendweapons ) + { + entvars_t *pev = (entvars_t *)&ent->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + + if ( pl ) + { + cd->m_flNextAttack = pl->m_flNextAttack; + //cd->fuser2 = pl->m_flNextAmmoBurn; + //cd->fuser3 = pl->m_flAmmoStartCharge; + //cd->vuser1.x = pl->ammo_9mm; + //cd->vuser1.y = pl->ammo_357; + //cd->vuser1.z = pl->ammo_argrens; + //cd->ammo_nails = pl->ammo_bolts; + //cd->ammo_shells = pl->ammo_buckshot; + //cd->ammo_rockets = pl->ammo_rockets; + //cd->ammo_cells = pl->ammo_uranium; + //cd->vuser2.x = pl->ammo_hornets; + + if ( pl->m_pActiveItem ) + { + CBasePlayerWeapon *gun; + gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); + if ( gun && gun->UseDecrement() ) + { + ItemInfo II; + memset( &II, 0, sizeof( II ) ); + gun->GetItemInfo( &II ); + + cd->m_iId = II.iId; + +// cd->vuser3.z = gun->m_iSecondaryAmmoType; +// cd->vuser4.x = gun->m_iPrimaryAmmoType; +// cd->vuser4.y = pl->m_rgAmmo[gun->m_iPrimaryAmmoType]; +// cd->vuser4.z = pl->m_rgAmmo[gun->m_iSecondaryAmmoType]; +// +// if ( pl->m_pActiveItem->m_iId == WEAPON_RPG ) +// { +// cd->vuser2.y = ( ( CRpg * )pl->m_pActiveItem)->m_fSpotActive; +// cd->vuser2.z = ( ( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; +// } + } + } + } + } +} + +/* +================= +CmdStart + +We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. +This is the time to examine the usercmd for anything extra. This call happens even if think does not. +================= +*/ +void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) +{ + entvars_t *pev = (entvars_t *)&player->v; + AvHPlayer *pl = ( AvHPlayer *) CBasePlayer::Instance( pev ); + + if( !pl ) + return; + + pl->SetCurrentCommand(cmd); + + pl->SetSizeForUser3(); + + if ( pl->pev->groupinfo != 0 ) + { + UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); + } + + pl->random_seed = random_seed; +} + +/* +================= +CmdEnd + +Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here +================= +*/ +void CmdEnd ( const edict_t *player ) +{ + entvars_t *pev = (entvars_t *)&player->v; + AvHPlayer *pl = ( AvHPlayer *) CBasePlayer::Instance( pev ); + + if( !pl ) + return; + + pl->SetSizeForUser3(); + + if ( pl->pev->groupinfo != 0 ) + { + UTIL_UnsetGroupTrace(); + } +} + +/* +================================ +ConnectionlessPacket + + Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max + size of the response_buffer, so you must zero it out if you choose not to respond. +================================ +*/ +int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + // Parse stuff from args + int max_buffer_size = *response_buffer_size; + + // Zero it out since we aren't going to respond. + // If we wanted to response, we'd write data into response_buffer + *response_buffer_size = 0; + + // Since we don't listen for anything here, just respond that it's a bogus message + // If we didn't reject the message, we'd return 1 for success instead. + return 0; +} + +/* +================================ +GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + int iret = 0; + + switch ( hullnumber ) + { + case 0: + HULL0_MIN.CopyToArray(mins); + HULL0_MAX.CopyToArray(maxs); + iret = 1; + break; + + case 1: + HULL1_MIN.CopyToArray(mins); + HULL1_MAX.CopyToArray(maxs); + iret = 1; + break; + + case 2: + HULL2_MIN.CopyToArray(mins); + HULL2_MAX.CopyToArray(maxs); + iret = 1; + break; + + case 3: + HULL3_MIN.CopyToArray(mins); + HULL3_MAX.CopyToArray(maxs); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +CreateInstancedBaselines + +Create pseudo-baselines for items that aren't placed in the map at spawn time, but which are likely +to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) +================================ +*/ +void CreateInstancedBaselines ( void ) +{ + int iret = 0; + entity_state_t state; + + memset( &state, 0, sizeof( state ) ); + + // Create any additional baselines here for things like grendates, etc. + // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); + + // Destroy objects. + //UTIL_Remove( pc ); +} + +/* +================================ +InconsistentFile + +One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the specified player + Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) +================================ +*/ + +static char *ignoreInConsistencyCheck[] = { + "sound/vox/ssay82.wav", + "sound/vox/ssay83.wav", + 0 +}; + +int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) +{ + // Server doesn't care? + if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) + return 0; + + int i=0; + while ( ignoreInConsistencyCheck[i] != 0 ) { + if ( !strcmp(ignoreInConsistencyCheck[i], filename) ) + return 0; + i++; + } + + /*if ( strstr(filename, "_detail.txt") != NULL ) { + ALERT(at_console, "Checking consistency of %s\n", filename); + string detailFilename=string("maps/") + STRING(gpGlobals->mapname) + string("_detail.txt"); + if ( strcmp(filename, detailFilename.c_str()) != 0 ) { + ALERT(at_console, "Skipping != %s\n", detailFilename.c_str()); + return 0; + } + }*/ + + // Default behavior is to kick the player + sprintf( disconnect_message, "Server is enforcing file consistency for %s\n", filename ); + + // Kick now with specified disconnect message. + return 1; +} + +/* +================================ +AllowLagCompensation + + The game .dll should return 1 if lag compensation should be allowed ( could also just set + the sv_unlag cvar. + Most games right now should return 0, until client-side weapon prediction code is written + and tested for them ( note you can predict weapons, but not do lag compensation, too, + if you want. +================================ +*/ +int AllowLagCompensation( void ) +{ + return 1; +} + +inline bool AvHDetermineVisibility(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, unsigned char *pSet, bool& outIsParticleSystemEntity, bool& outIsParticleSystemEntityVisible) +{ + bool theIsVisible = false; + bool theIsParticleSystemEntity = (ent->v.classname == MAKE_STRING(kesParticlesCustom)); + outIsParticleSystemEntity = theIsParticleSystemEntity; + outIsParticleSystemEntityVisible = false; + + // Always propagate ourself + if(ent != host) + { + //if(GET_RUN_CODE(256)) + + bool theEntityIsAWeldable = ent->v.iuser3 == AVH_USER3_WELD;//(ent->v.classname == MAKE_STRING(kesWeldable)); + bool theIsNoBuild = ent->v.iuser3 == AVH_USER3_NOBUILD;//(ent->v.classname == MAKE_STRING(kesNoBuild)); + + // Don't send if EF_NODRAW objects that aren't the host (with some exceptions) + // This is a little convoluted because of performance (this function gets called many thousands of time per server tick) + + // Elven - edited out the !(ent->v.effects & EF_NODRAW) because it will always evaluate to true. + // Reasoning: if (v.effects & EF_NODRAW) and (ent!=host) were ever true, there would have been a return call in + // AddToFullPack before this function was called. + // Therefore, (ent->v.effects & EF_NODRAW) will always be false and !false will always be true. + // - undid this change as it was causing problems in comm mode. Structures, players etc. were not visible to the comm. + if(!(ent->v.effects & EF_NODRAW) || theEntityIsAWeldable || theIsNoBuild || (ent->v.classname == MAKE_STRING(kesMP3Audio))) + { + // This is duplicated from the above line for possible efficiency + bool theIsMp3Entity = (ent->v.classname == MAKE_STRING(kesMP3Audio)); + + // Ignore ents without valid / visible models + // ...but don't cull out particle systems ever. + // This should use an approximate bounding radius and cull it with the PVS normally but + // I can't figure out how to make it work. This would only cause more net traffic if + // the particle system entity was out of sight and moving around due to map triggers, not + // through normal operation + if(ent->v.modelindex || STRING(ent->v.model) || theIsParticleSystemEntity || theIsMp3Entity) + { + if(theIsMp3Entity) + { + CBaseEntity* theEntity = CBaseEntity::Instance(ent); + AvHMP3Audio* theMP3Audio = dynamic_cast(theEntity); + if(theMP3Audio) + { + float theDistanceToEntity = VectorDistance(host->v.origin, ent->v.origin); + int theFadeDistance = theMP3Audio->GetFadeDistance(); + if((theFadeDistance <= 0) || (theDistanceToEntity <= theFadeDistance)) + { + theIsVisible = true; + } + } + } + + // If we're in top down + bool thePlayerInTopDown = (host->v.iuser4 & MASK_TOPDOWN); + if(thePlayerInTopDown) + { + // Possible visible entities are world entities, sighted enemy entities, or entities on our team + bool theEntityIsWorldEntity = (ent->v.team == 0) && (ent->v.iuser3 != AVH_USER3_HIVE); + bool theIsSighted = (ent->v.iuser4 & MASK_VIS_SIGHTED); + bool theOnSameTeam = (host->v.team == ent->v.team); + + if(theEntityIsWorldEntity || theIsSighted || theOnSameTeam) + { + CBaseEntity* theEntity = CBaseEntity::Instance(ent); + bool theIsDoor = (dynamic_cast(theEntity) != NULL); + + // If entity is in front of the player and within visibility range + vec3_t theEntityOrigin = ent->v.origin; + float theMagnitude = theEntityOrigin.x + theEntityOrigin.y + theEntityOrigin.z; + if((theMagnitude < 5.0f) || theIsDoor) + { + theEntityOrigin.x = (ent->v.absmin.x + ent->v.absmax.x)/2.0f; + theEntityOrigin.y = (ent->v.absmin.y + ent->v.absmax.y)/2.0f; + theEntityOrigin.z = (ent->v.absmin.z + ent->v.absmax.z)/2.0f; + } + bool theIsRelevantForTopDownPlayer = AvHSUGetIsRelevantForTopDownPlayer(host->v.origin, theEntityOrigin); + if(!theIsRelevantForTopDownPlayer) + { + AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); + + // If the entity is selected, it's relevant + if(theEntity && theReceivingPlayer && theReceivingPlayer->GetIsSelected(theEntity->entindex())) + { + theIsRelevantForTopDownPlayer = true; + } + } + if(theIsRelevantForTopDownPlayer) + { + theIsVisible = true; + if(theIsParticleSystemEntity) + { + outIsParticleSystemEntityVisible = true; + } + } + } + } +// else +// { +// // Check visibility with the engine +// if(ENGINE_CHECK_VISIBILITY((const struct edict_s *)ent, pSet)) +// { +// theIsVisible = true; +// +// // If it's a particle system entity, save visibility for it +// if(theIsParticleSystemEntity) +// { +// outIsParticleSystemEntityVisible = true; +// } +// } +// else if(theIsParticleSystemEntity) +// { +// outIsParticleSystemEntityVisible = false; +// } +// } + } + } + } + else + { + theIsVisible = true; + } + + return theIsVisible; +} + +/* +AddToFullPack + +Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise + +state is the server maintained copy of the state info that is transmitted to the client +a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. +e and ent are the entity that is being added to the update, if 1 is returned +host is the player's edict of the player whom we are sending the update to +player is 1 if the ent/e is a player and 0 otherwise +pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. +we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame +*/ +int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) +{ + int i; + + if(e > kMaxEProcessedForPlayerOne) + { + kNumEntsProcessedForPlayerOne++; + kMaxEProcessedForPlayerOne = e; + } + + if((ent != host) && !(GET_RUN_CODE(512))) + { + kNumReturn0++; + return 0; + } + + // This is a common case + // Ignore ents without valid / visible models + if ( !ent->v.modelindex || !STRING( ent->v.model ) ) + { + kNumReturn0++; + return 0; + } + + // don't send if flagged for NODRAW and it's not the host getting the message + if ( ( ent->v.effects & EF_NODRAW ) && + ( ent != host ) ) + { + kNumReturn0++; + return 0; + } + + // Don't send spectators to other players + if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) ) + { + kNumReturn0++; + return 0; + } + + AvHUser3 theUser3 = (AvHUser3)ent->v.iuser3; + bool theCanBeTargetted = ent->v.targetname != 0; + + //if(!strcmp(theEntNameString, "func_illusionary")) + if(theUser3 == AVH_USER3_FUNC_ILLUSIONARY) + { + // Check invisibility flags + if(host->v.iuser4 & MASK_TOPDOWN) + { + if(FBitSet(ent->v.spawnflags, 1)) + { + if(pSet != NULL) + { + kNumReturn0++; + return 0; + } + } + } + // If we're not commander, and "invisible for player" is set + else + { + if(FBitSet(ent->v.spawnflags, 2)) + { + if(pSet != NULL) + { + kNumReturn0++; + return 0; + } + } + } + } + + + // Some entities can be determined to be visible without the engine check + bool theIsParticleSystemEntity = false; + bool theIsParticleSystemEntityVisible = false; + bool theIsVisible = AvHDetermineVisibility(state, e, ent, host, pSet, theIsParticleSystemEntity, theIsParticleSystemEntityVisible); + if(!theIsVisible) + { + // Check to see if the player has left their previous leaf. If so, reset player's PVS info. + int hostnum = ENTINDEX( host ) - 1; + if ( TimeToResetPVS( host, hostnum ) ) + { + ResetPlayerPVS( host, hostnum ); + } + + // Ignore if not the host and not touching a PVS/PAS leaf + // If pSet is NULL, then the test will always succeed and the entity will be added to the update + if ( ent != host ) + { + if(GetTimeToRecompute( hostnum, e, gpGlobals->time, theIsVisible)) + { + // Do time consuming check + theIsVisible = ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ); + + MarkEntityInPVS( hostnum, e, gpGlobals->time, theIsVisible); + + kNumComputed++; + } + + if(!theIsVisible) + { + kNumReturn0++; + return 0; + } + } + + // Don't send entity to local client if the client says it's predicting the entity itself. + if ( ent->v.flags & FL_SKIPLOCALHOST ) + { + if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) + { + kNumReturn0++; + return 0; + } + } + + if ( host->v.groupinfo ) + { + UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); + + // Should always be set, of course + if ( ent->v.groupinfo ) + { + if ( g_groupop == GROUP_OP_AND ) + { + if ( !(ent->v.groupinfo & host->v.groupinfo ) ) + { + kNumReturn0++; + return 0; + } + } + else if ( g_groupop == GROUP_OP_NAND ) + { + if ( ent->v.groupinfo & host->v.groupinfo ) + { + kNumReturn0++; + return 0; + } + } + } + + UTIL_UnsetGroupTrace(); + } + } + + memset( state, 0, sizeof( *state ) ); + + // Assign index so we can track this entity from frame to frame and + // delta from it. + state->number = e; + state->entityType = ENTITY_NORMAL; + + // Flag custom entities. + if ( ent->v.flags & FL_CUSTOMENTITY ) + { + state->entityType = ENTITY_BEAM; + } + + // + // Copy state data + // + + // Round animtime to nearest millisecond + state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; + + //memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) ); + state->origin = ent->v.origin; + + //memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) ); + state->angles = ent->v.angles; + + //memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) ); + state->mins = ent->v.mins; + + //memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) ); + state->maxs = ent->v.maxs; + + //memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); + state->startpos = ent->v.startpos; + + //memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); + state->endpos = ent->v.endpos; + + state->impacttime = ent->v.impacttime; + state->starttime = ent->v.starttime; + + state->modelindex = ent->v.modelindex; + + state->frame = ent->v.frame; + + state->skin = ent->v.skin; + state->effects = ent->v.effects; + + // This non-player entity is being moved by the game .dll and not the physics simulation system + // make sure that we interpolate it's position on the client if it moves + if ( !player && + ent->v.animtime && + ent->v.velocity[ 0 ] == 0 && + ent->v.velocity[ 1 ] == 0 && + ent->v.velocity[ 2 ] == 0 ) + { + state->eflags |= EFLAG_SLERP; + } + + state->scale = ent->v.scale; + state->solid = ent->v.solid; + state->colormap = ent->v.colormap; + state->movetype = ent->v.movetype; + state->sequence = ent->v.sequence; + state->framerate = ent->v.framerate; + state->body = ent->v.body; + + for (i = 0; i < 4; i++) + { + state->controller[i] = ent->v.controller[i]; + } + + for (i = 0; i < 2; i++) + { + state->blending[i] = ent->v.blending[i]; + } + + state->rendermode = ent->v.rendermode; + state->renderamt = ent->v.renderamt; + state->renderfx = ent->v.renderfx; + state->rendercolor.r = ent->v.rendercolor[0]; + state->rendercolor.g = ent->v.rendercolor[1]; + state->rendercolor.b = ent->v.rendercolor[2]; + + + // If classname indicates an entity that fades depending on viewing player role + const char* theEntNameString = STRING(ent->v.classname); + + if(!player && AvHSSUGetIsClassNameFadeable(theEntNameString)) + { + CBaseEntity* theSeethrough = CBaseEntity::Instance(ent); + ASSERT(theSeethrough); + + // Default to player is full visibility + state->rendermode = kRenderNormal; + + int theAlphaValue = theSeethrough->pev->fuser2; + if(host->v.iuser4 & MASK_TOPDOWN) + { + theAlphaValue = theSeethrough->pev->fuser1; + } + + if(theAlphaValue != 255) + { + //state->rendermode = kRenderTransAdd; + state->rendermode = kRenderTransTexture; + state->renderamt = theAlphaValue; + if(state->renderamt == 0) + { + state->effects |= EF_NODRAW; + } + + if(host->v.iuser4 & MASK_TOPDOWN) + { + state->solid = SOLID_NOT; + } + + } + + } + + // Inactive hives should be drawn for players on their team + if((ent->v.iuser3 == AVH_USER3_HIVE) && (!GetHasUpgrade(ent->v.iuser4, MASK_BUILDABLE))) + { + // Assumes that aliens of both teams can build on the same hive location + AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); + if(theReceivingPlayer && theReceivingPlayer->GetIsAlien()) + { + state->renderamt = 128; + } + } + + // Handle cloakables here + if(!AvHSUGetIsExternalClassName(theEntNameString)) + { + AvHCloakable* theCloakable = dynamic_cast(CBaseEntity::Instance(ent)); + if(theCloakable) + { + // Now updated in gamerules + theCloakable->Update(); + + float theOpacityScalar = theCloakable->GetOpacity(); + if(theOpacityScalar < 1.0f) + { + int theBaseOpacity = kAlienStructureCloakAmount; + int theOpacityRange = 255 - kAlienStructureCloakAmount; + + // Allow spectators to see cloaked entities as if they are the player they are following, or as if they are on the same team as the alien otherwise + bool theCanSeeCloaked = (host->v.team == ent->v.team); + if(!theCanSeeCloaked) + { + int theHostIUserOne = host->v.iuser1; + if((theHostIUserOne == OBS_CHASE_LOCKED) || (theHostIUserOne == OBS_CHASE_FREE) || (theHostIUserOne == OBS_IN_EYE) ) + { + // View entities as player we're tracking + int theHostIUserTwo = host->v.iuser2; + CBaseEntity* theSpectatingEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theHostIUserTwo)); + if(theSpectatingEntity) + { + int theSpectatingEntityTeamNumber = theSpectatingEntity->pev->team; + if((theSpectatingEntityTeamNumber == ent->v.team) || (host->v.team == TEAM_IND)) + { + theCanSeeCloaked = true; + } + } + } + } + + if(theCanSeeCloaked) + { + theBaseOpacity = kAlienSelfCloakingBaseOpacity; + theOpacityRange = 255 - theBaseOpacity; + } + + int theOpacity = theBaseOpacity + theOpacityScalar*theOpacityRange; + theOpacity = max(min(255, theOpacity), 0); + + state->rendermode = kRenderTransTexture; + state->renderamt = theOpacity; + } + } + } + + // Spectator + state->iuser1 = ent->v.iuser1; + state->iuser2 = ent->v.iuser2; + + // AvH specials + state->iuser3 = ent->v.iuser3; + state->iuser4 = ent->v.iuser4; + + // Slightly different processing for particle system entities +// if(theIsParticleSystemEntity) +// { +// // propagate weapon model as custom data) +// state->weaponmodel = ent->v.weaponmodel; +// } + + state->fuser1 = ent->v.fuser1; + state->fuser2 = ent->v.fuser2; + state->fuser3 = ent->v.fuser3; + state->vuser4 = ent->v.vuser4; + + + + + + + state->aiment = 0; + if ( ent->v.aiment ) + { + state->aiment = ENTINDEX( ent->v.aiment ); + } + + state->owner = 0; + if ( ent->v.owner ) + { + int owner = ENTINDEX( ent->v.owner ); + + // Only care if owned by a player + if ( owner >= 1 && owner <= gpGlobals->maxClients ) + { + state->owner = owner; + } + } + + // HACK: Somewhat... + // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) + if ( !player ) + { + state->playerclass = ent->v.playerclass; + } + + // Propagate team for all entities (mainly needed for client-side lasso selection) + state->team = ent->v.team; + + // Check special vision mode + AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); + if(theReceivingPlayer && (theReceivingPlayer->GetIsAlienSightActive())) + { + bool marineGlow = false; + if (player) + { + // Uncomment below to enable range for the alien flashlight + // vec3_t theDistanceVec; + // VectorSubtract(theReceivingPlayer->pev->origin, ent->v.origin, theDistanceVec); + + // int theDistance = theDistanceVec[0] * theDistanceVec[0] + theDistanceVec[1] * theDistanceVec[1] + theDistanceVec[2] * theDistanceVec[2]; + // int theRange = BALANCE_VAR(kAlienFlashlightRange); + // marineGlow = (theDistance < ( theRange * theRange)); + marineGlow = true; + } + + if(( marineGlow || (ent->v.team == theReceivingPlayer->pev->team)) && (ent != theReceivingPlayer->edict()) && (ent->v.team != TEAM_IND) && (ent->v.team != TEAM_SPECT ) && (ent->v.classname != MAKE_STRING(kesTeamWebStrand)) ) + { + state->rendermode = kRenderTransAdd; + state->renderamt = 150; + } + } + + // Special stuff for players only + if(player) + { + state->basevelocity = ent->v.basevelocity; + + state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); + state->gaitsequence = ent->v.gaitsequence; + state->spectator = ent->v.flags & FL_SPECTATOR; + state->friction = ent->v.friction; + + state->gravity = ent->v.gravity; + + // New SDK doesn't propagate team for a reason? + //state->playerclass = ent->v.playerclass; + //state->team = ent->v.team; + + bool theIsDucking = ent->v.flags & FL_DUCKING; + state->usehull = AvHMUGetHull(theIsDucking, ent->v.iuser3); + + // Propagate "energy level" + state->fuser3 = ent->v.fuser3; + + // For skulk oriented player model + state->vuser1 = ent->v.vuser1; + + // For weapons + state->vuser4 = ent->v.vuser4; + + //state->skin = theTargetPlayer->GetSkin(); + state->skin = ent->v.skin; + state->playerclass = ent->v.playerclass; + // state->armorvalue = ent->v.armorvalue; + + AvHPlayer* thePlayerEntity = dynamic_cast(CBaseEntity::Instance(ent)); + if(thePlayerEntity && thePlayerEntity->GetIsTemporarilyInvulnerable()) + { + int theTeamIndex = ent->v.team; + ASSERT(theTeamIndex >= 0); + ASSERT(theTeamIndex < iNumberOfTeamColors); + + state->renderfx = kRenderFxGlowShell; + state->rendercolor.r = kTeamColors[theTeamIndex][0]; + state->rendercolor.g = kTeamColors[theTeamIndex][1]; + state->rendercolor.b = kTeamColors[theTeamIndex][2]; + state->renderamt = kInvulShellRenderAmount; + } + } + + state->health = ent->v.health; + + kNumReturn1++; + + return 1; +} + diff --git a/main/source/dlls/client.cpp~ b/main/source/dlls/client.cpp~ deleted file mode 100644 index 65f25f74..00000000 --- a/main/source/dlls/client.cpp~ +++ /dev/null @@ -1,2930 +0,0 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to -// have one without a hardcoded player.mdl in tf_client.cpp -// -//===== client.cpp ======================================================== -// -// client/server game specific stuff -// -// $Workfile: client.cpp $ -// $Date: 2002/11/22 21:09:09 $ -// -//------------------------------------------------------------------------------- -// $Log: client.cpp,v $ -// Revision 1.69 2002/11/22 21:09:09 Flayra -// - Added "lastinv" command back in -// - mp_consistency changes -// -// Revision 1.68 2002/11/15 23:31:01 Flayra -// - Added "ready" verification for tourny mode -// -// Revision 1.67 2002/11/15 05:08:31 Flayra -// - Little tweak for refinery -// -// Revision 1.66 2002/11/15 04:48:40 Flayra -// - Oops -// -// Revision 1.65 2002/11/15 04:41:32 Flayra -// - Big performance improvements for AddToFullPack (whew) -// -// Revision 1.64 2002/11/12 02:17:48 Flayra -// - Renamed "avhplayer" to "player" -// - Tweaked enhanced sight to actually be useful at lower levels -// -// Revision 1.63 2002/11/03 04:53:20 Flayra -// - AddToFullPack optimizations and cleanup -// -// Revision 1.62 2002/10/25 21:50:01 Flayra -// - New attempted fix for overflows. Propagate skin and playerclass in new way, so entities outside the ready room aren't propagated to all clients that go back to the ready room immediately on game end. -// -// Revision 1.61 2002/10/24 21:16:10 Flayra -// - Log Sys_Errors -// - Allow players to change their name before they first leave the ready room -// -// Revision 1.60 2002/10/20 17:25:04 Flayra -// - Redid performance improvement (agh) -// -// Revision 1.59 2002/10/20 16:34:09 Flayra -// - Returned code back to normal -// -// Revision 1.58 2002/10/19 22:33:48 Flayra -// - Various server optimizations -// -// Revision 1.57 2002/10/18 22:14:23 Flayra -// - Server optimizations (untested though, may need backing out) -// -// Revision 1.56 2002/10/16 00:38:50 Flayra -// - Queue up name change until end of game -// - Removed precaching of unneeded sounds -// - Optimized AvHDetermineVisibility (being called 1000s of times per tick) -// -// Revision 1.55 2002/10/03 18:27:39 Flayra -// - Moved order completion sounds into HUD sounds -// -// Revision 1.54 2002/09/25 20:37:53 Flayra -// - Precache more sayings -// -// Revision 1.53 2002/09/23 22:01:02 Flayra -// - Propagate skin -// - Don't treat unclaimed hives at world objects (even though team is 0) for visibility purposes -// - Added heavy model -// - Removed old mapper build preprocessor directives -// -// Revision 1.52 2002/08/31 18:01:17 Flayra -// - Work at VALVe -// -// Revision 1.51 2002/08/16 02:24:31 Flayra -// - Removed "give" cheat -// -// Revision 1.50 2002/08/09 00:15:46 Flayra -// - Removed behavior where "drop" would drop alien weapons in a disconcerting manner -// -// Revision 1.49 2002/07/25 16:50:15 flayra -// - Linux build changes -// -// Revision 1.48 2002/07/24 18:46:19 Flayra -// - Linux and scripting changes -// -// Revision 1.47 2002/07/23 16:46:38 Flayra -// - Added power-armor drawing, tweaked invul drawing -// -// Revision 1.46 2002/07/10 14:36:21 Flayra -// - .mp3 and particle fixes -// -// Revision 1.45 2002/07/08 16:38:57 Flayra -// - Draw invulnerable players differently -// -//=============================================================================== -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "player.h" -#include "spectator.h" -#include "client.h" -#include "soundent.h" -#include "gamerules.h" -#include "game.h" -#include "../engine/customentity.h" -#include "weapons.h" -#include "../common/weaponinfo.h" -#include "../common/usercmd.h" -#include "../common/netadr.h" -#include "../util/nowarnings.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHSoundListManager.h" -#include "game.h" -#include "../mod/AvHParticleTemplateServer.h" -#include "../mod/AvHMarineEquipmentConstants.h" -#include "../mod/AvHSpecials.h" -#include "../util/Zassert.h" -#include "cbasedoor.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHMovementUtil.h" -#include "../mod/AvHSoundConstants.h" -#include "../mod/AvHHulls.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHSharedUtil.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHAlienEquipmentConstants.h" -#include "triggers.h" -#include "../util/MathUtil.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHCloakable.h" -#include "../mod/AvHAlienAbilityConstants.h" -#include "../mod/AvHNetworkMessages.h" -#include "../mod/AvHNexusServer.h" - -#include "game_shared/voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - -extern AvHSoundListManager gSoundListManager; - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL int g_iSkillLevel; -extern DLL_GLOBAL ULONG g_ulFrameCount; - -extern void CopyToBodyQue(entvars_t* pev); -extern int g_teamplay; - -/* - * used by kill command and disconnect command - * ROBIN: Moved here from player.cpp, to allow multiple player models - */ -void set_suicide_frame(entvars_t* pev) -{ - if (!FStrEq(STRING(pev->model), "models/player.mdl")) - return; // allready gibbed - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - pev->deadflag = DEAD_DEAD; - pev->nextthink = -1; -} - - -/* -=========== -LogStringForPlayer - -generates string for player event logging - KGP -============ -*/ - -std::string GetLogStringForPlayer( edict_t *pEntity ) -{ - // outputs "netname" if g_teamplay - // or "netname" if not g_teamplay - std::string result = "\""; - result += STRING( pEntity->v.netname ); - result += "<"; - result += MakeStringFromInt( GETPLAYERUSERID( pEntity ) ); - result += "><"; - result += AvHSUGetPlayerAuthIDString( pEntity ).c_str(); - result += "><"; - result += AvHSUGetTeamName( pEntity->v.team ); - result += ">\""; - return result; -} - -/* -=========== -ClientConnect - -called when a player connects to a server -============ -*/ -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); - - // a client connecting during an intermission can cause problems - // if (intermission_running) - // ExitIntermission (); - -} - - -/* -=========== -ClientDisconnect - - called when a player disconnects from a server - - GLOBALS ASSUMED SET: g_fGameOver - ============ -*/ -void ClientDisconnect( edict_t *pEntity ) -{ - if (g_fGameOver) - return; - - char text[256]; - sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) ); - - CBaseEntity* theBaseEntity = CBaseEntity::Instance(ENT(pEntity)); - UTIL_SayTextAll(text, theBaseEntity); - - CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); - { - // since this client isn't around to think anymore, reset their sound. - if ( pSound ) - { - pSound->Reset(); - } - } - - // since the edict doesn't get deleted, fix it so it doesn't interfere. - pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim - pEntity->v.solid = SOLID_NOT;// nonsolid - UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin ); - - g_pGameRules->ClientDisconnected( pEntity ); - - //: If this isnt set, clients around this player will crash. - pEntity->v.effects |= EF_NODRAW; -} - - -// called by ClientKill and DeadThink -void respawn(entvars_t* pev, BOOL fCopyCorpse) -{ - // AVH isn't dm, coop or single-player. - //if (gpGlobals->coop || gpGlobals->deathmatch) - //{ - if ( fCopyCorpse ) - { - // make a copy of the dead body for appearances sake - CopyToBodyQue(pev); - } - - // respawn player - GetClassPtr( (AvHPlayer *)pev)->Spawn( ); - //} - //else - //{ // restart the entire server - // SERVER_COMMAND("reload\n"); - //} -} - -/* -============ -ClientKill - -Player entered the suicide command - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -============ -*/ -void ClientKill( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - - CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); - - //if(GetGameRules()->GetCheatsEnabled()) - //{ - if ( pl->m_fNextSuicideTime > gpGlobals->time ) - return; // prevent suiciding too ofter - - pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding - - bool theIsCombatModeForSuicide = GetGameRules()->GetIsCombatMode(); - - #ifdef DEBUG - if(GetGameRules()->GetIsCombatMode()) - { - theIsCombatModeForSuicide = false; - } - #endif - - bool theCanSuicide = GetGameRules()->CanPlayerBeKilled(pl) && !theIsCombatModeForSuicide; - - if(theCanSuicide) - { - pl->Suicide(); - - // pev->modelindex = g_ulModelIndexPlayer; - // pev->frags -= 2; // extra penalty - // respawn( pev ); - } - //} -} - -/* -=========== -ClientPutInServer - -called each time a player is spawned -============ -*/ -void ClientPutInServer( edict_t *pEntity ) -{ - //CBasePlayer *pPlayer; - AvHPlayer *pPlayer; - - entvars_t *pev = &pEntity->v; - - if(pev->flags & FL_PROXY) - { - ALERT(at_logged, "Player with FL_PROXY put in server.\n"); - } - - if(pev->flags & FL_PROXY) - { - pev->flags |= FL_PROXY; - } - - pPlayer = GetClassPtr((AvHPlayer *)pev); - pPlayer->SetCustomDecalFrames(-1); // Assume none; - - // Allocate a CBasePlayer for pev, and call spawn - pPlayer->SetPlayMode(PLAYMODE_READYROOM); - //pPlayer->Spawn(); - - // Reset interpolation during first frame - pPlayer->pev->effects |= EF_NOINTERP; -} - -//// HOST_SAY -// String comes in as -// say blah blah blah -// or as -// blah blah blah -// -void Host_Say( edict_t *pEntity, int teamonly ) -{ - AvHPlayer* client; - AvHPlayer* theTalkingPlayer = dynamic_cast(CBaseEntity::Instance(pEntity)); - int j; - char* p; - char text[256]; - char szTemp[256]; - const char* cpSay = "say"; - const char* cpSayTeam = "say_team"; - const char* pcmd = CMD_ARGV(0); - bool theTalkerInReadyRoom = theTalkingPlayer->GetInReadyRoom(); - //bool theTalkerIsObserver = (theTalkingPlayer->GetPlayMode() == PLAYMODE_OBSERVER) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT); - - // We can get a raw string now, without the "say " prepended - if ( CMD_ARGC() == 0 ) - return; - - //Not yet. - if ( theTalkingPlayer->m_flNextChatTime > gpGlobals->time ) - return; - - if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) - { - if ( CMD_ARGC() >= 2 ) - { - p = (char *)CMD_ARGS(); - - if(GetGameRules()->GetIsTournamentMode() && !GetGameRules()->GetGameStarted()) - { - if(!strcmp(CMD_ARGV(1), kReadyNotification)) - { - // Team is ready - AvHTeam* theTeam = GetGameRules()->GetTeam((AvHTeamNumber)(pEntity->v.team)); - if(theTeam && !theTeam->GetIsReady()) - { - theTeam->SetIsReady(); - } - } - else if (!strcmp(CMD_ARGV(1), kNotReadyNotification)) - { - // Team is no longer ready - AvHTeam* theTeam = GetGameRules()->GetTeam((AvHTeamNumber)(pEntity->v.team)); - if(theTeam && theTeam->GetIsReady()) - { - theTeam->SetIsReady(false); - } - } - } - } - else - { - // say with a blank message, nothing to do - return; - } - } - else // Raw text, need to prepend argv[0] - { - if ( CMD_ARGC() >= 2 ) - { - sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); - } - else - { - // Just a one word command, use the first word...sigh - sprintf( szTemp, "%s", ( char * )pcmd ); - } - p = szTemp; - } - -// remove quotes if present - if (*p == '"') - { - p++; - p[strlen(p)-1] = 0; - } - -// make sure the text has content - char *pc=p; - for ( pc = p; pc != NULL && *pc != 0; pc++ ) - { - if ( isprint( *pc ) && !isspace( *pc ) ) - { - pc = NULL; // we've found an alphanumeric character, so text is valid - break; - } - } - if ( pc != NULL ) - return; // no character found, so say nothing - -// turn on color set 2 (color on, no sound) - if ( teamonly ) - sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); - else - sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); - - j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator - if ( (int)strlen(p) > j ) - p[j] = 0; - - strcat( text, p ); - strcat( text, "\n" ); - - theTalkingPlayer->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL; - // loop through all players - // Start with the first player. - // This may return the world in single player if the client types something between levels or during spawn - // so check it, or it will infinite loop - - client = NULL; - while ( ((client = (AvHPlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) - { - if ( !client->pev ) - continue; - - if ( client->edict() == pEntity ) - continue; - - if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) - continue; - - // can the receiver hear the sender? or has he muted him? - if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, theTalkingPlayer ) ) - continue; - - // Don't differentiate between team and non-team when not playing - bool theTalkingPlayerIsPlaying = ((theTalkingPlayer->GetPlayMode() == PLAYMODE_PLAYING) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theTalkingPlayer->GetPlayMode() == PLAYMODE_REINFORCING)); - bool theClientIsPlaying = ((client->GetPlayMode() == PLAYMODE_PLAYING) || (client->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (client->GetPlayMode() == PLAYMODE_REINFORCING)); - bool theTalkerIsObserver = theTalkingPlayer->IsObserver(); - bool theClientIsObserver = client->IsObserver(); - bool theClientIsHLTV = (client->pev->flags & FL_PROXY); - - bool theClientInReadyRoom = client->GetInReadyRoom(); - - if (theClientInReadyRoom != theTalkerInReadyRoom && !theClientIsHLTV) - { - continue; - } - - if (!theClientIsObserver || theClientIsPlaying ) // Non-playing Observers hear everything. - { - - if ( theTalkingPlayerIsPlaying && teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) - continue; - - // chat can never go between play area and non-play area - if(theTalkingPlayerIsPlaying != theClientIsPlaying && !theClientIsHLTV ) - continue; - - // chat of any kind doesn't go from ready room to play area in tournament mode - if(theTalkerInReadyRoom && GetGameRules()->GetIsTournamentMode() && theClientIsPlaying && !theClientIsHLTV) - continue; - - } - - UTIL_SayText(text, client, ENTINDEX(pEntity)); - - } - - // print to the sending client - UTIL_SayText(text, CBaseEntity::Instance(ENT(pEntity))); - - // echo to server console - g_engfuncs.pfnServerPrint( text ); - - char * temp; - if ( teamonly ) - temp = "say_team"; - else - temp = "say"; - -// UTIL_LogPrintf( "%s %s \"%s\"\n", GetLogStringForPlayer( pEntity ).c_str(), temp, p ); -} - - -/* -=========== -ClientCommand -called each time a player uses a "cmd" command -============ -*/ - -// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command. -void ClientCommand( edict_t *pEntity ) -{ - const char *pcmd = CMD_ARGV(0); - const char *pstr; - - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - entvars_t *pev = &pEntity->v; - - AvHPlayer* thePlayer = GetClassPtr((AvHPlayer *)pev); - bool thePlayerCanAct = thePlayer->GetIsAbleToAct(); - - if ( FStrEq(pcmd, "say" ) ) - { - Host_Say( pEntity, 0 ); - } - else if ( FStrEq(pcmd, "say_team" ) ) - { - Host_Say( pEntity, 1 ); - } - else if ( FStrEq(pcmd, "fullupdate" ) ) - { - GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); - } - else if ( FStrEq(pcmd, "give" ) ) - { - if(GetGameRules()->GetCheatsEnabled()) - { - int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname - GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); - } - } - - else if ( FStrEq(pcmd, "drop" )) - { - if (thePlayerCanAct) - { - // player is dropping an item. - GetClassPtr((AvHPlayer *)pev)->DropItem((char *)CMD_ARGV(1)); - } - } - else if ( FStrEq(pcmd, "fov" ) ) - { - if (GetGameRules()->GetCheatsEnabled() && (CMD_ARGC() > 1)) - { - GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) ); - } - else - { - CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) ); - } - } - else if ( FStrEq(pcmd, "use" )) - { - if (thePlayerCanAct) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); - } - } - else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) - { - if (thePlayerCanAct) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); - } - } - else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) ) - { - // MenuSelect returns true only if the command is properly handled, so don't print a warning - } - else if ( FStrEq( pcmd, "specmode" ) ) // new spectator mode - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) - { - int theMode = atoi(CMD_ARGV(1)); - pPlayer->Observer_SetMode(theMode); - pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); - } - } - else if (FStrEq( pcmd, "follow")) // follow a specific player - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) - { - pPlayer->Observer_SpectatePlayer(atoi( CMD_ARGV(1) )); - pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); - } - } - else if ( FStrEq( pcmd, "follownext" ) ) // follow next player - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) - { - pPlayer->Observer_FindNextPlayer(atoi( CMD_ARGV(1) )); - pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); - } - } - else - { - // tell the user they entered an unknown command - char command[128]; - - // check the length of the command (prevents crash) - // max total length is 192 ...and we're adding a string below ("Unknown command: %s\n") - strncpy( command, pcmd, 127 ); - command[127] = '\0'; - // : 1071 - // Remove printf formatting - for ( int i=0; i < 127; i++ ) { - if ( command[i] == '%' ) { - command[i] = ' '; - } - } - // : - // tell the user they entered an unknown command - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) ); - } - //else if(!AvHClientCommand(pEntity)) - //{ - // // tell the user they entered an unknown command - // ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pcmd ) ); - //} -} - -//bool AvHClientCommand( edict_t *pEntity ) -//{ -//} - -/* -======================== -ClientUserInfoChanged - -called after the player changes -userinfo - gives dll a chance to modify it before -it gets sent into the rest of the engine. -======================== -*/ -void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) -{ - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - const char* theCurrentNetName = STRING(pEntity->v.netname); - const char* theNameKeyValue = g_engfuncs.pfnInfoKeyValue(infobuffer, "name"); - - // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq(theCurrentNetName, theNameKeyValue) ) - { - AvHPlayer* thePlayer = dynamic_cast(CBaseEntity::Instance(pEntity)); - - // Don't change player info after match has started unless player hasn't left ready room - if(!GetGameRules()->GetArePlayersAllowedToJoinImmediately() && thePlayer && theNameKeyValue && thePlayer->GetHasLeftReadyRoom()) - { - thePlayer->SetDesiredNetName(string(theNameKeyValue)); - - char text[256]; - sprintf( text, "* Name will be changed to %s next game.\n", theNameKeyValue); - UTIL_SayText(text, CBaseEntity::Instance(ENT(pEntity))); - - // Restore name key value changed by engine - char theName[256]; - strcpy(theName, theCurrentNetName); - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", theName); - } - else - { - char sName[256]; - char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); - strncpy( sName, pName, sizeof(sName) - 1 ); - sName[ sizeof(sName) - 1 ] = '\0'; - - // First parse the name and remove any %'s - for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) - { - // Replace it with a space - if ( *pApersand == '%' ) - *pApersand = ' '; - } - - // Set the name - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); - //thePlayer->SetDesiredNetName(MAKE_STRING(sName)); - - char text[256]; - sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - - UTIL_SayTextAll(text, CBaseEntity::Instance(ENT(pEntity))); - -// UTIL_LogPrintf( "%s changed name to \"%s\"\n", GetLogStringForPlayer( pEntity ).c_str(), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - } - - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); -} - -static int g_serveractive = 0; - -void ServerDeactivate( void ) -{ - // It's possible that the engine will call this function more times than is necessary - // Therefore, only run it one time for each call to ServerActivate - if ( g_serveractive != 1 ) - { - return; - } - - g_serveractive = 0; - - // Peform any shutdown operations here... - // -} - -void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) -{ - int i; - CBaseEntity *pClass; - - // Every call to ServerActivate should be matched by a call to ServerDeactivate - g_serveractive = 1; - - // Clients have not been initialized yet - for ( i = 0; i < edictCount; i++ ) - { - if ( pEdictList[i].free ) - continue; - - // Clients aren't necessarily initialized until ClientPutInServer() - if ( i < clientMax || !pEdictList[i].pvPrivateData ) - continue; - - pClass = CBaseEntity::Instance( &pEdictList[i] ); - // Activate this entity if it's got a class & isn't dormant - if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) - { - pClass->Activate(); - } - else - { - ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); - } - } - - Net_InitializeMessages(); -} - - -/* -================ -PlayerPreThink - -Called every frame before physics are run -================ -*/ -void PlayerPreThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PreThink( ); -} - -/* -================ -PlayerPostThink - -Called every frame after physics are run -================ -*/ -void PlayerPostThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PostThink( ); -} - - - -void ParmsNewLevel( void ) -{ -} - - -void ParmsChangeLevel( void ) -{ - // retrieve the pointer to the save data - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - - if ( pSaveData ) - pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); -} - -void ShowMenu(entvars_s *pev, int ValidSlots, int DisplayTime, BOOL ShowLater, char Menu[500]) -{ - NetMsg_ShowMenu( pev, ValidSlots, DisplayTime, ShowLater ? 1 : 0, string(Menu) ); -} - -// -// GLOBALS ASSUMED SET: g_ulFrameCount -// -void StartFrame( void ) -{ - if ( g_pGameRules ) - g_pGameRules->Think(); - - if ( g_fGameOver ) - return; - - gpGlobals->teamplay = teamplay.value; - - g_ulFrameCount++; -} - -void ClientPrecache( void ) -{ - // Precache sound lists for all player types - gSoundListManager.Clear(); - - int i=0; - for(i = ((int)AVH_USER3_NONE + 1); i < (int)AVH_USER3_ALIEN_EMBRYO; i++) - { - char theSoundListName[256]; - bool theIsAlien = (i > 3); - AvHUser3 theUser3 = (AvHUser3)(i); - - bool theLoadSounds = false; - - // No squad leader and commander sounds - switch(theUser3) - { - case AVH_USER3_MARINE_PLAYER: - case AVH_USER3_ALIEN_PLAYER1: - case AVH_USER3_ALIEN_PLAYER2: - case AVH_USER3_ALIEN_PLAYER3: - case AVH_USER3_ALIEN_PLAYER4: - case AVH_USER3_ALIEN_PLAYER5: - theLoadSounds = true; - } - - if(theLoadSounds) - { - // Die sounds - sprintf(theSoundListName, kPlayerLevelDieSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Spawn sounds - sprintf(theSoundListName, kPlayerLevelSpawnSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Pain sounds - sprintf(theSoundListName, kPlayerLevelPainSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Wound sounds - sprintf(theSoundListName, kPlayerLevelWoundSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Attack sounds (aliens only) - if(theIsAlien) - { - sprintf(theSoundListName, kPlayerLevelAttackSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Idle sounds - sprintf(theSoundListName, kPlayerLevelIdleSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - // Movement sounds - sprintf(theSoundListName, kPlayerLevelMoveSoundList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - } - } - } - - // Precache misc. alien sounds - //PRECACHE_SOUND(kAdrenalineSound); - PRECACHE_UNMODIFIED_SOUND(kGestationSound); - PRECACHE_UNMODIFIED_SOUND(kEggDestroyedSound); - PRECACHE_UNMODIFIED_SOUND(kEggIdleSound); - PRECACHE_UNMODIFIED_SOUND(kPrimalScreamResponseSound); - - // Preacache sayings sound list - for(i = 1; i <= 9; i++) - { - char theSoundListName[256]; - - sprintf(theSoundListName, kSoldierSayingList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - sprintf(theSoundListName, kCommanderSayingList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - - sprintf(theSoundListName, kAlienSayingList, i); - gSoundListManager.PrecacheSoundList(theSoundListName); - } - - // Precache order sounds - gSoundListManager.PrecacheSoundList(kSoldierOrderRequestList); - gSoundListManager.PrecacheSoundList(kSoldierOrderAckList); - - // Precache other sound lists - gSoundListManager.PrecacheSoundList(kResourceTowerSoundList); - gSoundListManager.PrecacheSoundList(kAlienResourceTowerSoundList); - gSoundListManager.PrecacheSoundList(kHiveWoundSoundList); - gSoundListManager.PrecacheSoundList(kMarineConstructionSoundList); - gSoundListManager.PrecacheSoundList(kElectricSparkSoundList); - gSoundListManager.PrecacheSoundList(kAlienConstructionSoundList); - - // Other equipment and effect sounds - PRECACHE_UNMODIFIED_SOUND(kMarineBuildingDeploy); - PRECACHE_UNMODIFIED_SOUND(kJetpackSound); - PRECACHE_UNMODIFIED_SOUND(kWeldingSound); - PRECACHE_UNMODIFIED_SOUND(kWeldingHitSound); - //PRECACHE_UNMODIFIED_SOUND(kOverwatchStartSound); - //PRECACHE_UNMODIFIED_SOUND(kOverwatchEndSound); - PRECACHE_UNMODIFIED_SOUND(kRegenerationSound); - PRECACHE_UNMODIFIED_SOUND(kStartCloakSound); - PRECACHE_UNMODIFIED_SOUND(kEndCloakSound); - //PRECACHE_UNMODIFIED_SOUND(kWallJumpSound); - PRECACHE_UNMODIFIED_SOUND(kWingFlapSound1); - PRECACHE_UNMODIFIED_SOUND(kWingFlapSound2); - PRECACHE_UNMODIFIED_SOUND(kWingFlapSound3); - PRECACHE_UNMODIFIED_SOUND(kSiegeHitSound1); - PRECACHE_UNMODIFIED_SOUND(kSiegeHitSound2); - - // setup precaches always needed - PRECACHE_UNMODIFIED_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha - - // PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound - - // Alien step sounds - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a1.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-a5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-a5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-a5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-a5.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1-h.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step2-h.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3-h.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4-h.wav"); - - // Marine step sounds - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-1.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-6.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-7.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_fallpain3-8.wav"); - PRECACHE_UNMODIFIED_SOUND(kDigestingSound); - - PRECACHE_UNMODIFIED_SOUND("player/pl_step1.wav"); // walk on concrete - PRECACHE_UNMODIFIED_SOUND("player/pl_step2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_step4.wav"); - - PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete - PRECACHE_SOUND("common/npc_step2.wav"); - PRECACHE_SOUND("common/npc_step3.wav"); - PRECACHE_SOUND("common/npc_step4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_metal1.wav"); // walk on metal - PRECACHE_UNMODIFIED_SOUND("player/pl_metal2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_metal3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_metal4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt1.wav"); // walk on dirt - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_dirt4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_duct1.wav"); // walk in duct - PRECACHE_UNMODIFIED_SOUND("player/pl_duct2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_duct3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_duct4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_grate1.wav"); // walk on grate - PRECACHE_UNMODIFIED_SOUND("player/pl_grate2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_grate3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_grate4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh1.wav"); // walk in shallow water - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_slosh4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_tile1.wav"); // walk on tile - PRECACHE_UNMODIFIED_SOUND("player/pl_tile2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_tile3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_tile4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_tile5.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_swim1.wav"); // breathe bubbles - PRECACHE_UNMODIFIED_SOUND("player/pl_swim2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_swim3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_swim4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder1.wav"); // climb ladder rung - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_ladder4.wav"); - - PRECACHE_UNMODIFIED_SOUND("player/pl_wade1.wav"); // wade in water - PRECACHE_UNMODIFIED_SOUND("player/pl_wade2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_wade3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_wade4.wav"); - - PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.wav"); - - PRECACHE_UNMODIFIED_SOUND("plats/train_use1.wav"); // use a train - - PRECACHE_UNMODIFIED_SOUND("buttons/spark5.wav"); // hit computer texture - PRECACHE_UNMODIFIED_SOUND("buttons/spark6.wav"); - PRECACHE_SOUND("debris/glass1.wav"); - PRECACHE_SOUND("debris/glass2.wav"); - PRECACHE_SOUND("debris/glass3.wav"); - - PRECACHE_UNMODIFIED_SOUND( SOUND_FLASHLIGHT_ON ); - PRECACHE_UNMODIFIED_SOUND( SOUND_FLASHLIGHT_OFF ); - -// player gib sounds - PRECACHE_SOUND("common/bodysplat.wav"); - -// player pain sounds - PRECACHE_UNMODIFIED_SOUND("player/pl_pain2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain6.wav"); - PRECACHE_UNMODIFIED_SOUND("player/pl_pain7.wav"); - - PRECACHE_UNMODIFIED_MODEL("models/player.mdl"); - PRECACHE_UNMODIFIED_MODEL(kReadyRoomModel); - - PRECACHE_UNMODIFIED_MODEL(kMarineSoldierModel); - PRECACHE_UNMODIFIED_MODEL(kHeavySoldierModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelOneModel); - - PRECACHE_UNMODIFIED_MODEL(kAlienLevelTwoModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelThreeModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFourModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFiveModel); - - PRECACHE_UNMODIFIED_MODEL(kMarineCommanderModel); - PRECACHE_UNMODIFIED_MODEL(kAlienGestateModel); - - - // hud sounds, for marines and aliens (change AvHSharedUtil::AvHSHUGetCommonSoundName if these sound names change) - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudoff.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudon.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_moveselect.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_select.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_denyselect.wav"); - - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudoff-a.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_hudon-a.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_moveselect-a.wav"); - - PRECACHE_UNMODIFIED_SOUND("common/wpn_select-a.wav"); - PRECACHE_UNMODIFIED_SOUND("common/wpn_denyselect-a.wav"); - - // geiger sounds - PRECACHE_UNMODIFIED_SOUND("player/geiger6.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger5.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger4.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger3.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger2.wav"); - PRECACHE_UNMODIFIED_SOUND("player/geiger1.wav"); - - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash1.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash3.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/digesting.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/membrane.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/hera_fog.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/webstrand.spr"); - - PRECACHE_UNMODIFIED_GENERIC("ns.wad"); - PRECACHE_UNMODIFIED_GENERIC("ns2.wad"); - PRECACHE_UNMODIFIED_GENERIC("v_wad.wad"); -/* PRECACHE_UNMODIFIED_GENERIC("maps/co_angst_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_core_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_daimos_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_ether_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_faceoff_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_kestrel_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_niveus_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_pulse_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_sava_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_ulysses_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/co_umbra_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_altair_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_ayumi_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_bast_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_caged_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_eclipse_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_eon_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_hera_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_lost_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_lucid_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_machina_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_metal_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_nancy_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_nothing_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_origin_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_prometheus_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_shiva_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_tanith_detail.txt"); - PRECACHE_UNMODIFIED_GENERIC("maps/ns_veil_detail.txt"); - - CStringList list; - string modDir=string(getModDirectory()) + "/"; - if(BuildFileList(modDir, "maps/", "*_detail.txt", list)) - { - for(CStringList::iterator it=list.begin(); it != list.end(); it++ ) { - int iString = ALLOC_STRING((char*)it);//: We cant do "(char*)theSoundToPrecache" directly cause it causes some wierd problems. - PRECACHE_UNMODIFIED_GENERIC((char*)STRING(iString)); - } - } - */ -} - -/* -================ -Sys_Error - - Engine is going to shut down, allows setting a breakpoint in game .dll to catch that occasion - ================ - */ - void Sys_Error( const char *error_string ) - { -#ifdef DEBUG -#ifdef WIN32 - // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls - _asm { int 3 }; -#endif -#else - char theDebugString[2056]; - sprintf(theDebugString, "Sys_Error: %s\n", error_string); - ALERT(at_error, theDebugString); -#endif - -} - -/* -=============== -GetGameDescription - -Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 -=============== -*/ -const char *GetGameDescription() -{ - if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized - return g_pGameRules->GetGameDescription(); - else - return "Half-Life"; -} - -/* -================ -PlayerCustomization - -A new player customization has been registered on the server -UNDONE: This only sets the # of frames of the spray can logo -animation right now. -================ -*/ -void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) -{ - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (!pPlayer) - { - ALERT(at_console, "PlayerCustomization: Couldn't get player!\n"); - return; - } - - if (!pCust) - { - ALERT(at_console, "PlayerCustomization: NULL customization!\n"); - return; - } - - switch (pCust->resource.type) - { - case t_decal: - pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames. - break; - case t_sound: - case t_skin: - case t_model: - // Ignore for now. - break; - default: - ALERT(at_console, "PlayerCustomization: Unknown customization type!\n"); - break; - } -} - -/* -================ -SpectatorConnect - -A spectator has joined the game -================ -*/ -void SpectatorConnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorConnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has left the game -================ -*/ -void SpectatorDisconnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorDisconnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has sent a usercmd -================ -*/ -void SpectatorThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorThink( ); -} - -//////////////////////////////////////////////////////// -// PAS and PVS routines for client messaging -// - -/* -================ -SetupVisibility - -A client can have a separate "view entity" indicating that his/her view should depend on the origin of that -view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current -entity's origin is used. Either is offset by the view_ofs to get the eye position. - -From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could - override the actual PAS or PVS values, or use a different origin. - -NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame -================ -*/ -void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) -{ - Vector org; - edict_t *pView = pClient; - bool theUseSpecialPASOrigin = false; - Vector theSpecialPASOrigin; - - // Find the client's PVS - if ( pViewEntity ) - { - pView = pViewEntity; - } - - // Proxy sees and hears all - if ( (pClient->v.flags & FL_PROXY) || GetGameRules()->GetIsCheatEnabled(kcViewAll)) - { - //ALERT(at_logged, "Setting PVS and PAS to NULL for FL_PROXY\n"); - *pvs = NULL; // the spectator proxy sees - *pas = NULL; // and hears everything - return; - } - - // Tracking Spectators use the visibility of their target - CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - if ( (pPlayer->pev->iuser2 != 0) && (pPlayer->m_hObserverTarget != NULL) && (pPlayer->m_afPhysicsFlags & PFLAG_OBSERVER) && pPlayer->IsAlive()) - { - pView = pPlayer->m_hObserverTarget->edict(); - UTIL_SetOrigin( pPlayer->pev, pPlayer->m_hObserverTarget->pev->origin ); - } - - // Tracking Spectators use the visibility of their target -// AvHPlayer *thePlayer = dynamic_cast(CBaseEntity::Instance(pClient)); - - // cgc - something could be wrong here, crashing from Robin's spectator code...did I do something wrong? -// if(thePlayer) -// { -// if ( (thePlayer->pev->iuser2 != 0) && (thePlayer->m_hObserverTarget != NULL) ) -// { -// pView = thePlayer->m_hObserverTarget->edict(); -// } -// -// if(thePlayer->GetRole() == ROLE_COMMANDER) -// { -// thePlayer->GetSpecialPASOrigin(theSpecialPASOrigin); -// theUseSpecialPASOrigin = true; -// } -// } - - org = pView->v.origin + pView->v.view_ofs; - if ( pView->v.flags & FL_DUCKING ) - { - org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - *pvs = ENGINE_SET_PVS ( (float *)&org ); - - if(theUseSpecialPASOrigin) - { - *pas = ENGINE_SET_PAS ( (float *)&theSpecialPASOrigin ); - } - else - { - *pas = ENGINE_SET_PAS ( (float *)&org ); - } -} - -#include "../common/entity_state.h" - -//CachedEntity gCachedEntities[kMaxPlayers][kMaxEntities]; -// -//void ResetCachedEntities() -//{ -// for(int i = 0; i < kMaxPlayers; i++) -// { -// for(int j = 0; j < kMaxEntities; j++) -// { -// gCachedEntities[i][j].ResetCachedEntity(); -// } -// } -//} - - - -// Array sizes ( memory is 5624 * 32 = 179968 bytes ) -#define MAX_CLIENTS ( 32 ) -#define MAX_ENTITIES ( 900 + MAX_CLIENTS * 15 ) - -// Re-check entities only this often once they are found to be in the PVS -// NOTE: We could have a separate timeout for players if we wanted to tweak the coherency time for them ( you'd have -// to check the entitynum against 1 to gpGlobals->maxclients ), etc. -//#define PVS_COHERENCY_TIME 1.0f - -extern float kPVSCoherencyTime; - -typedef struct -{ - bool mLastVisibility; - float m_fTimeEnteredPVS; -} ENTITYPVSSTATUS; - -typedef struct -{ - ENTITYPVSSTATUS m_Status[ MAX_ENTITIES ]; - - // Remember player leaf data so we can invalidate pvs history when leaf changes - int headnode; // -1 to use normal leaf check - int num_leafs; - short leafnums[ MAX_ENT_LEAFS ]; - -} PLAYERPVSSTATUS; - -static PLAYERPVSSTATUS g_PVSStatus[ MAX_CLIENTS ]; - -void ResetPlayerPVS( edict_t *client, int clientnum ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - - memset( pvs, 0, sizeof( PLAYERPVSSTATUS ) ); - - // Copy leaf data in right away - pvs->headnode = client->headnode; - pvs->num_leafs = client->num_leafs; - memcpy( pvs->leafnums, client->leafnums, sizeof( pvs->leafnums ) ); -} - -bool TimeToResetPVS( edict_t *client, int clientnum ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - - if ( (pvs->headnode != client->headnode) || (pvs->num_leafs != client->num_leafs)) - return true; - - if ( client->num_leafs > 0 ) - { - for ( int i = 0; i < client->num_leafs; i++ ) - { - if ( client->leafnums[ i ] != pvs->leafnums[ i ] ) - { - return true; - } - } - } - - // Still the same - return false; -} - -void MarkEntityInPVS( int clientnum, int entitynum, float time, bool inpvs ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; - - es->m_fTimeEnteredPVS = time; - es->mLastVisibility = inpvs; -} - -bool GetTimeToRecompute( int clientnum, int entitynum, float currenttime, bool& outCachedVisibility) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; - - bool theTimeToRecompute = false; - - int theUseCaching = BALANCE_VAR(kDebugServerCaching); - if(theUseCaching) - { - // Always recompute players? - if((entitynum > 0) && (entitynum < MAX_CLIENTS)) - { - theTimeToRecompute = true; - } - // If we haven't computed for awhile, or our PVS has been reset - else if((currenttime > (es->m_fTimeEnteredPVS + kPVSCoherencyTime)) || (es->m_fTimeEnteredPVS == 0.0f)) - { - theTimeToRecompute = true; - } - else - { - outCachedVisibility = es->mLastVisibility; - } - } - else - { - theTimeToRecompute = true; - } - - return theTimeToRecompute; -} - -bool CheckEntityRecentlyInPVS( int clientnum, int entitynum, float currenttime ) -{ - ASSERT( clientnum >=0 && clientnum < MAX_CLIENTS ); - ASSERT( entitynum >= 0 && entitynum < MAX_ENTITIES ); - - PLAYERPVSSTATUS *pvs = &g_PVSStatus[ clientnum ]; - ENTITYPVSSTATUS *es = &pvs->m_Status[ entitynum ]; - - int theUseCaching = BALANCE_VAR(kDebugServerCaching); - if(!theUseCaching) - { - return false; - } - - // Wasn't in pvs before, sigh... - if ( es->m_fTimeEnteredPVS == 0.0f ) - { - return false; - } - - // If we've been saying yes for kPVSCoherencyTime, say no now instead so that we'll do a full check - if ( es->m_fTimeEnteredPVS + kPVSCoherencyTime < currenttime ) - { - return false; - } - - // Keep assuming it's in the pvs for a bit of time (trivial inclusion) - return true; -} - - -int kNumReturn0 = 0; -int kNumReturn1 = 0; -int kNumCached = 0; -int kNumComputed = 0; -int kMaxE = 0; -int kNumEntsProcessedForPlayerOne = 0; -int kMaxEProcessedForPlayerOne = 0; -extern int kServerFrameRate; - -// ENGINE_CHECK_VISIBILITY, from Yahn, with his comments: -// -// Here's the engine code. You'll note a slow path if the ent leaf cache is missed, which causes a recomputation via the much more expensive -// CM_HeadnodeVisible call. That does change the cache data on the entity, so that's likely your problem with blinking if you are doing some -// kind of memcpy operation on the old data. -//#ifdef 0 -//int DLL_CALLBACK SV_CheckVisibility( const struct edict_s *entity, unsigned char *pset ) -//{ -// int i; -// qboolean visible; -// edict_t *e; -// -// if ( !pset ) -// return 1; -// -// if ( entity->headnode >= 0 ) // -// { -// // we use num_leafs as a cache/counter, it will circle around, but so what -// // if we don't find the leaf we want here, we'll end up doing the full test anyway -// int leaf; -// i = 0; -// -// do -// { -// leaf = entity->leafnums[i]; -// // Cache is all -1 to start... -// if ( leaf == -1 ) -// break; -// -// if ( pset[ leaf >> 3 ] & (1 << (leaf & 7 ) ) ) -// { -// return 1; -// } -// -// i++; -// if ( i >= MAX_ENT_LEAFS ) -// break; -// -// } while ( 1 ); -// -// // Didn't find it in "cache" -// -// visible = CM_HeadnodeVisible( sv.worldmodel->nodes + entity->headnode, pset, &leaf ); -// if ( !visible ) -// { -// return 0; -// } -// -// // Cache leaf that was visible -// // -// e = ( edict_t * )entity; -// -// e->leafnums[ entity->num_leafs ] = (short)leaf; -// e->num_leafs = ( entity->num_leafs + 1 ) % MAX_ENT_LEAFS; -// -// return 2; -// } -// else -// { -// for (i=0 ; i < entity->num_leafs ; i++) -// { -// if ( pset[entity->leafnums[i] >> 3] & (1 << (entity->leafnums[i]&7) )) -// break; -// } -// -// visible = ( i < entity->num_leafs ); -// if ( !visible ) -// { -// return 0; -// } -// } -// -// return 1; -//} -//#endif - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 - -/* -=================== -CreateBaseline - -Creates baselines used for network encoding, especially for player data since players are not spawned until connect time. -=================== -*/ -void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) -{ - baseline->origin = entity->v.origin; - baseline->angles = entity->v.angles; - baseline->frame = entity->v.frame; - baseline->skin = (short)entity->v.skin; - - // render information - baseline->rendermode = (byte)entity->v.rendermode; - baseline->renderamt = (byte)entity->v.renderamt; - baseline->rendercolor.r = (byte)entity->v.rendercolor.x; - baseline->rendercolor.g = (byte)entity->v.rendercolor.y; - baseline->rendercolor.b = (byte)entity->v.rendercolor.z; - baseline->renderfx = (byte)entity->v.renderfx; - - if ( player ) - { - baseline->mins = player_mins; - baseline->maxs = player_maxs; - - baseline->colormap = eindex; - baseline->modelindex = playermodelindex; - baseline->friction = 1.0; - baseline->movetype = MOVETYPE_WALK; - - baseline->scale = entity->v.scale; - baseline->solid = SOLID_SLIDEBOX; - baseline->framerate = 1.0; - baseline->gravity = 1.0; - - } - else - { - baseline->mins = entity->v.mins; - baseline->maxs = entity->v.maxs; - - baseline->colormap = 0; - baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); - baseline->movetype = entity->v.movetype; - - baseline->scale = entity->v.scale; - baseline->solid = entity->v.solid; - baseline->framerate = entity->v.framerate; - baseline->gravity = entity->v.gravity; - } -} - -typedef struct -{ - char name[32]; - int field; -} entity_field_alias_t; - -#define FIELD_ORIGIN0 0 -#define FIELD_ORIGIN1 1 -#define FIELD_ORIGIN2 2 -#define FIELD_ANGLES0 3 -#define FIELD_ANGLES1 4 -#define FIELD_ANGLES2 5 - -static entity_field_alias_t entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, -}; - -void Entity_FieldInit( struct delta_s *pFields ) -{ - entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); - entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); - entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); - entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); - entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); - entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); -} - -/* -================== -Entity_Encode - -Callback for sending entity_state_t info over network. -FIXME: Move to script -================== -*/ -void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->impacttime != 0 ) && ( t->starttime != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -static entity_field_alias_t player_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, -}; - -void Player_FieldInit( struct delta_s *pFields ) -{ - player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); - player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); - player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); -} - -/* -================== -Player_Encode - -Callback for sending entity_state_t for players info over network. -================== -*/ -void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Player_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -#define CUSTOMFIELD_ORIGIN0 0 -#define CUSTOMFIELD_ORIGIN1 1 -#define CUSTOMFIELD_ORIGIN2 2 -#define CUSTOMFIELD_ANGLES0 3 -#define CUSTOMFIELD_ANGLES1 4 -#define CUSTOMFIELD_ANGLES2 5 -#define CUSTOMFIELD_SKIN 6 -#define CUSTOMFIELD_SEQUENCE 7 -#define CUSTOMFIELD_ANIMTIME 8 - -entity_field_alias_t custom_entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, - { "skin", 0 }, - { "sequence", 0 }, - { "animtime", 0 }, -}; - -void Custom_Entity_FieldInit( struct delta_s *pFields ) -{ - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); -} - -/* -================== -Custom_Encode - -Callback for sending entity_state_t info ( for custom entities ) over network. -FIXME: Move to script -================== -*/ -void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int beamType; - static int initialized = 0; - - if ( !initialized ) - { - Custom_Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - beamType = t->rendermode & 0x0f; - - if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); - } - - if ( beamType != BEAM_POINTS ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); - } - - if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); - } - - // animtime is compared by rounding first - // see if we really shouldn't actually send it - if ( (int)f->animtime == (int)t->animtime ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); - } -} - -/* -================= -RegisterEncoders - -Allows game .dll to override network encoding of certain types of entities and tweak values, etc. -================= -*/ -void RegisterEncoders( void ) -{ - DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); - DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); - DELTA_ADDENCODER( "Player_Encode", Player_Encode ); -} - -int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) -{ - int i; - weapon_data_t *item; - entvars_t *pev = &player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - AvHPlayer* thePlayer = dynamic_cast(pl); - CBasePlayerWeapon *gun; - - ItemInfo II; - - memset( info, 0, 32 * sizeof( weapon_data_t ) ); - - if ( !pl ) - return 1; - - // go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( pl->m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) - { - // Get The ID. - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - ASSERT((II.iId >= 0) && (II.iId < 32)); - - if ( II.iId >= 0 && II.iId < 32 ) - { - item = &info[ II.iId ]; - - item->m_iId = II.iId; - item->m_iClip = gun->m_iClip; - - item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001f ); - item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001f ); - item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001f ); - item->m_fInReload = gun->m_fInReload; - - //thePlayer->SetDebugCSP(item); - - //item->m_fInSpecialReload = gun->m_fInSpecialReload; - //item->fuser1 = max( gun->pev->fuser1, -0.001 ); - item->fuser2 = gun->m_flStartThrow; - item->fuser3 = gun->m_flReleaseThrow; - //item->iuser1 = gun->m_chargeReady; - //item->iuser2 = gun->m_fInAttack; - - // Pass along enabled state in iuser3 (for when hives and ensnare enable and disable weapons) - item->iuser3 = gun->pev->iuser3; - - //item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); - } - } - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - return 1; -} - -/* -================= -UpdateClientData - -Data sent to current client only -engine sets cd to 0 before calling. -================= -*/ -void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) -{ - cd->flags = ent->v.flags; - cd->health = ent->v.health; - - cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); - - cd->waterlevel = ent->v.waterlevel; - cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; - - // Vectors - cd->origin = ent->v.origin; - cd->velocity = ent->v.velocity; - cd->view_ofs = ent->v.view_ofs; - cd->punchangle = ent->v.punchangle; - - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; - cd->flDuckTime = ent->v.flDuckTime; - cd->flSwimTime = ent->v.flSwimTime; - cd->waterjumptime = ent->v.teleport_time; - - strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - - cd->maxspeed = ent->v.maxspeed; - cd->fov = ent->v.fov; - cd->weaponanim = ent->v.weaponanim; - - cd->pushmsec = ent->v.pushmsec; - - // Spectator - cd->iuser1 = ent->v.iuser1; - cd->iuser2 = ent->v.iuser2; - - // AvH specials - cd->iuser3 = ent->v.iuser3; - cd->iuser4 = ent->v.iuser4; - cd->fuser1 = ent->v.fuser1; - cd->fuser2 = ent->v.fuser2; - cd->fuser3 = ent->v.fuser3; - - // Added by mmcguire for oriented skulk player models. - cd->vuser1 = ent->v.vuser1; - - // Added for extra player info for first-person spectating - cd->vuser4 = ent->v.vuser4; - - if ( sendweapons ) - { - entvars_t *pev = (entvars_t *)&ent->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - - if ( pl ) - { - cd->m_flNextAttack = pl->m_flNextAttack; - //cd->fuser2 = pl->m_flNextAmmoBurn; - //cd->fuser3 = pl->m_flAmmoStartCharge; - //cd->vuser1.x = pl->ammo_9mm; - //cd->vuser1.y = pl->ammo_357; - //cd->vuser1.z = pl->ammo_argrens; - //cd->ammo_nails = pl->ammo_bolts; - //cd->ammo_shells = pl->ammo_buckshot; - //cd->ammo_rockets = pl->ammo_rockets; - //cd->ammo_cells = pl->ammo_uranium; - //cd->vuser2.x = pl->ammo_hornets; - - if ( pl->m_pActiveItem ) - { - CBasePlayerWeapon *gun; - gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) - { - ItemInfo II; - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - cd->m_iId = II.iId; - -// cd->vuser3.z = gun->m_iSecondaryAmmoType; -// cd->vuser4.x = gun->m_iPrimaryAmmoType; -// cd->vuser4.y = pl->m_rgAmmo[gun->m_iPrimaryAmmoType]; -// cd->vuser4.z = pl->m_rgAmmo[gun->m_iSecondaryAmmoType]; -// -// if ( pl->m_pActiveItem->m_iId == WEAPON_RPG ) -// { -// cd->vuser2.y = ( ( CRpg * )pl->m_pActiveItem)->m_fSpotActive; -// cd->vuser2.z = ( ( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; -// } - } - } - } - } -} - -/* -================= -CmdStart - -We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. -This is the time to examine the usercmd for anything extra. This call happens even if think does not. -================= -*/ -void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) -{ - entvars_t *pev = (entvars_t *)&player->v; - AvHPlayer *pl = ( AvHPlayer *) CBasePlayer::Instance( pev ); - - if( !pl ) - return; - - pl->SetCurrentCommand(cmd); - - pl->SetSizeForUser3(); - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); - } - - pl->random_seed = random_seed; -} - -/* -================= -CmdEnd - -Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here -================= -*/ -void CmdEnd ( const edict_t *player ) -{ - entvars_t *pev = (entvars_t *)&player->v; - AvHPlayer *pl = ( AvHPlayer *) CBasePlayer::Instance( pev ); - - if( !pl ) - return; - - pl->SetSizeForUser3(); - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_UnsetGroupTrace(); - } -} - -/* -================================ -ConnectionlessPacket - - Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max - size of the response_buffer, so you must zero it out if you choose not to respond. -================================ -*/ -int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - // Parse stuff from args - int max_buffer_size = *response_buffer_size; - - // Zero it out since we aren't going to respond. - // If we wanted to response, we'd write data into response_buffer - *response_buffer_size = 0; - - // Since we don't listen for anything here, just respond that it's a bogus message - // If we didn't reject the message, we'd return 1 for success instead. - return 0; -} - -/* -================================ -GetHullBounds - - Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. -================================ -*/ -int GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - int iret = 0; - - switch ( hullnumber ) - { - case 0: - HULL0_MIN.CopyToArray(mins); - HULL0_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 1: - HULL1_MIN.CopyToArray(mins); - HULL1_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 2: - HULL2_MIN.CopyToArray(mins); - HULL2_MAX.CopyToArray(maxs); - iret = 1; - break; - - case 3: - HULL3_MIN.CopyToArray(mins); - HULL3_MAX.CopyToArray(maxs); - iret = 1; - break; - } - - return iret; -} - -/* -================================ -CreateInstancedBaselines - -Create pseudo-baselines for items that aren't placed in the map at spawn time, but which are likely -to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) -================================ -*/ -void CreateInstancedBaselines ( void ) -{ - int iret = 0; - entity_state_t state; - - memset( &state, 0, sizeof( state ) ); - - // Create any additional baselines here for things like grendates, etc. - // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); - - // Destroy objects. - //UTIL_Remove( pc ); -} - -/* -================================ -InconsistentFile - -One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the specified player - Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) -================================ -*/ - -static char *ignoreInConsistencyCheck[] = { - "sound/vox/ssay82.wav", - "sound/vox/ssay83.wav", - 0 -}; - -int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) -{ - // Server doesn't care? - if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) - return 0; - - int i=0; - while ( ignoreInConsistencyCheck[i] != 0 ) { - if ( !strcmp(ignoreInConsistencyCheck[i], filename) ) - return 0; - i++; - } - - /*if ( strstr(filename, "_detail.txt") != NULL ) { - ALERT(at_console, "Checking consistency of %s\n", filename); - string detailFilename=string("maps/") + STRING(gpGlobals->mapname) + string("_detail.txt"); - if ( strcmp(filename, detailFilename.c_str()) != 0 ) { - ALERT(at_console, "Skipping != %s\n", detailFilename.c_str()); - return 0; - } - }*/ - - // Default behavior is to kick the player - sprintf( disconnect_message, "Server is enforcing file consistency for %s\n", filename ); - - // Kick now with specified disconnect message. - return 1; -} - -/* -================================ -AllowLagCompensation - - The game .dll should return 1 if lag compensation should be allowed ( could also just set - the sv_unlag cvar. - Most games right now should return 0, until client-side weapon prediction code is written - and tested for them ( note you can predict weapons, but not do lag compensation, too, - if you want. -================================ -*/ -int AllowLagCompensation( void ) -{ - return 1; -} - -inline bool AvHDetermineVisibility(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, unsigned char *pSet, bool& outIsParticleSystemEntity, bool& outIsParticleSystemEntityVisible) -{ - bool theIsVisible = false; - bool theIsParticleSystemEntity = (ent->v.classname == MAKE_STRING(kesParticlesCustom)); - outIsParticleSystemEntity = theIsParticleSystemEntity; - outIsParticleSystemEntityVisible = false; - - // Always propagate ourself - if(ent != host) - { - //if(GET_RUN_CODE(256)) - - bool theEntityIsAWeldable = ent->v.iuser3 == AVH_USER3_WELD;//(ent->v.classname == MAKE_STRING(kesWeldable)); - bool theIsNoBuild = ent->v.iuser3 == AVH_USER3_NOBUILD;//(ent->v.classname == MAKE_STRING(kesNoBuild)); - - // Don't send if EF_NODRAW objects that aren't the host (with some exceptions) - // This is a little convoluted because of performance (this function gets called many thousands of time per server tick) - - // Elven - edited out the !(ent->v.effects & EF_NODRAW) because it will always evaluate to true. - // Reasoning: if (v.effects & EF_NODRAW) and (ent!=host) were ever true, there would have been a return call in - // AddToFullPack before this function was called. - // Therefore, (ent->v.effects & EF_NODRAW) will always be false and !false will always be true. - // - undid this change as it was causing problems in comm mode. Structures, players etc. were not visible to the comm. - if(!(ent->v.effects & EF_NODRAW) || theEntityIsAWeldable || theIsNoBuild || (ent->v.classname == MAKE_STRING(kesMP3Audio))) - { - // This is duplicated from the above line for possible efficiency - bool theIsMp3Entity = (ent->v.classname == MAKE_STRING(kesMP3Audio)); - - // Ignore ents without valid / visible models - // ...but don't cull out particle systems ever. - // This should use an approximate bounding radius and cull it with the PVS normally but - // I can't figure out how to make it work. This would only cause more net traffic if - // the particle system entity was out of sight and moving around due to map triggers, not - // through normal operation - if(ent->v.modelindex || STRING(ent->v.model) || theIsParticleSystemEntity || theIsMp3Entity) - { - if(theIsMp3Entity) - { - CBaseEntity* theEntity = CBaseEntity::Instance(ent); - AvHMP3Audio* theMP3Audio = dynamic_cast(theEntity); - if(theMP3Audio) - { - float theDistanceToEntity = VectorDistance(host->v.origin, ent->v.origin); - int theFadeDistance = theMP3Audio->GetFadeDistance(); - if((theFadeDistance <= 0) || (theDistanceToEntity <= theFadeDistance)) - { - theIsVisible = true; - } - } - } - - // If we're in top down - bool thePlayerInTopDown = (host->v.iuser4 & MASK_TOPDOWN); - if(thePlayerInTopDown) - { - // Possible visible entities are world entities, sighted enemy entities, or entities on our team - bool theEntityIsWorldEntity = (ent->v.team == 0) && (ent->v.iuser3 != AVH_USER3_HIVE); - bool theIsSighted = (ent->v.iuser4 & MASK_VIS_SIGHTED); - bool theOnSameTeam = (host->v.team == ent->v.team); - - if(theEntityIsWorldEntity || theIsSighted || theOnSameTeam) - { - CBaseEntity* theEntity = CBaseEntity::Instance(ent); - bool theIsDoor = (dynamic_cast(theEntity) != NULL); - - // If entity is in front of the player and within visibility range - vec3_t theEntityOrigin = ent->v.origin; - float theMagnitude = theEntityOrigin.x + theEntityOrigin.y + theEntityOrigin.z; - if((theMagnitude < 5.0f) || theIsDoor) - { - theEntityOrigin.x = (ent->v.absmin.x + ent->v.absmax.x)/2.0f; - theEntityOrigin.y = (ent->v.absmin.y + ent->v.absmax.y)/2.0f; - theEntityOrigin.z = (ent->v.absmin.z + ent->v.absmax.z)/2.0f; - } - bool theIsRelevantForTopDownPlayer = AvHSUGetIsRelevantForTopDownPlayer(host->v.origin, theEntityOrigin); - if(!theIsRelevantForTopDownPlayer) - { - AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); - - // If the entity is selected, it's relevant - if(theEntity && theReceivingPlayer && theReceivingPlayer->GetIsSelected(theEntity->entindex())) - { - theIsRelevantForTopDownPlayer = true; - } - } - if(theIsRelevantForTopDownPlayer) - { - theIsVisible = true; - if(theIsParticleSystemEntity) - { - outIsParticleSystemEntityVisible = true; - } - } - } - } -// else -// { -// // Check visibility with the engine -// if(ENGINE_CHECK_VISIBILITY((const struct edict_s *)ent, pSet)) -// { -// theIsVisible = true; -// -// // If it's a particle system entity, save visibility for it -// if(theIsParticleSystemEntity) -// { -// outIsParticleSystemEntityVisible = true; -// } -// } -// else if(theIsParticleSystemEntity) -// { -// outIsParticleSystemEntityVisible = false; -// } -// } - } - } - } - else - { - theIsVisible = true; - } - - return theIsVisible; -} - -/* -AddToFullPack - -Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise - -state is the server maintained copy of the state info that is transmitted to the client -a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. -e and ent are the entity that is being added to the update, if 1 is returned -host is the player's edict of the player whom we are sending the update to -player is 1 if the ent/e is a player and 0 otherwise -pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. -we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame -*/ -int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) -{ - int i; - - if(e > kMaxEProcessedForPlayerOne) - { - kNumEntsProcessedForPlayerOne++; - kMaxEProcessedForPlayerOne = e; - } - - if((ent != host) && !(GET_RUN_CODE(512))) - { - kNumReturn0++; - return 0; - } - - // This is a common case - // Ignore ents without valid / visible models - if ( !ent->v.modelindex || !STRING( ent->v.model ) ) - { - kNumReturn0++; - return 0; - } - - // don't send if flagged for NODRAW and it's not the host getting the message - if ( ( ent->v.effects & EF_NODRAW ) && - ( ent != host ) ) - { - kNumReturn0++; - return 0; - } - - // Don't send spectators to other players - if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) ) - { - kNumReturn0++; - return 0; - } - - AvHUser3 theUser3 = (AvHUser3)ent->v.iuser3; - bool theCanBeTargetted = ent->v.targetname != 0; - - //if(!strcmp(theEntNameString, "func_illusionary")) - if(theUser3 == AVH_USER3_FUNC_ILLUSIONARY) - { - // Check invisibility flags - if(host->v.iuser4 & MASK_TOPDOWN) - { - if(FBitSet(ent->v.spawnflags, 1)) - { - if(pSet != NULL) - { - kNumReturn0++; - return 0; - } - } - } - // If we're not commander, and "invisible for player" is set - else - { - if(FBitSet(ent->v.spawnflags, 2)) - { - if(pSet != NULL) - { - kNumReturn0++; - return 0; - } - } - } - } - - - // Some entities can be determined to be visible without the engine check - bool theIsParticleSystemEntity = false; - bool theIsParticleSystemEntityVisible = false; - bool theIsVisible = AvHDetermineVisibility(state, e, ent, host, pSet, theIsParticleSystemEntity, theIsParticleSystemEntityVisible); - if(!theIsVisible) - { - // Check to see if the player has left their previous leaf. If so, reset player's PVS info. - int hostnum = ENTINDEX( host ) - 1; - if ( TimeToResetPVS( host, hostnum ) ) - { - ResetPlayerPVS( host, hostnum ); - } - - // Ignore if not the host and not touching a PVS/PAS leaf - // If pSet is NULL, then the test will always succeed and the entity will be added to the update - if ( ent != host ) - { - if(GetTimeToRecompute( hostnum, e, gpGlobals->time, theIsVisible)) - { - // Do time consuming check - theIsVisible = ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ); - - MarkEntityInPVS( hostnum, e, gpGlobals->time, theIsVisible); - - kNumComputed++; - } - - if(!theIsVisible) - { - kNumReturn0++; - return 0; - } - } - - // Don't send entity to local client if the client says it's predicting the entity itself. - if ( ent->v.flags & FL_SKIPLOCALHOST ) - { - if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) - { - kNumReturn0++; - return 0; - } - } - - if ( host->v.groupinfo ) - { - UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); - - // Should always be set, of course - if ( ent->v.groupinfo ) - { - if ( g_groupop == GROUP_OP_AND ) - { - if ( !(ent->v.groupinfo & host->v.groupinfo ) ) - { - kNumReturn0++; - return 0; - } - } - else if ( g_groupop == GROUP_OP_NAND ) - { - if ( ent->v.groupinfo & host->v.groupinfo ) - { - kNumReturn0++; - return 0; - } - } - } - - UTIL_UnsetGroupTrace(); - } - } - - memset( state, 0, sizeof( *state ) ); - - // Assign index so we can track this entity from frame to frame and - // delta from it. - state->number = e; - state->entityType = ENTITY_NORMAL; - - // Flag custom entities. - if ( ent->v.flags & FL_CUSTOMENTITY ) - { - state->entityType = ENTITY_BEAM; - } - - // - // Copy state data - // - - // Round animtime to nearest millisecond - state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; - - //memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) ); - state->origin = ent->v.origin; - - //memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) ); - state->angles = ent->v.angles; - - //memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) ); - state->mins = ent->v.mins; - - //memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) ); - state->maxs = ent->v.maxs; - - //memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); - state->startpos = ent->v.startpos; - - //memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); - state->endpos = ent->v.endpos; - - state->impacttime = ent->v.impacttime; - state->starttime = ent->v.starttime; - - state->modelindex = ent->v.modelindex; - - state->frame = ent->v.frame; - - state->skin = ent->v.skin; - state->effects = ent->v.effects; - - // This non-player entity is being moved by the game .dll and not the physics simulation system - // make sure that we interpolate it's position on the client if it moves - if ( !player && - ent->v.animtime && - ent->v.velocity[ 0 ] == 0 && - ent->v.velocity[ 1 ] == 0 && - ent->v.velocity[ 2 ] == 0 ) - { - state->eflags |= EFLAG_SLERP; - } - - state->scale = ent->v.scale; - state->solid = ent->v.solid; - state->colormap = ent->v.colormap; - state->movetype = ent->v.movetype; - state->sequence = ent->v.sequence; - state->framerate = ent->v.framerate; - state->body = ent->v.body; - - for (i = 0; i < 4; i++) - { - state->controller[i] = ent->v.controller[i]; - } - - for (i = 0; i < 2; i++) - { - state->blending[i] = ent->v.blending[i]; - } - - state->rendermode = ent->v.rendermode; - state->renderamt = ent->v.renderamt; - state->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor[0]; - state->rendercolor.g = ent->v.rendercolor[1]; - state->rendercolor.b = ent->v.rendercolor[2]; - - - // If classname indicates an entity that fades depending on viewing player role - const char* theEntNameString = STRING(ent->v.classname); - - if(!player && AvHSSUGetIsClassNameFadeable(theEntNameString)) - { - CBaseEntity* theSeethrough = CBaseEntity::Instance(ent); - ASSERT(theSeethrough); - - // Default to player is full visibility - state->rendermode = kRenderNormal; - - int theAlphaValue = theSeethrough->pev->fuser2; - if(host->v.iuser4 & MASK_TOPDOWN) - { - theAlphaValue = theSeethrough->pev->fuser1; - } - - if(theAlphaValue != 255) - { - //state->rendermode = kRenderTransAdd; - state->rendermode = kRenderTransTexture; - state->renderamt = theAlphaValue; - if(state->renderamt == 0) - { - state->effects |= EF_NODRAW; - } - - if(host->v.iuser4 & MASK_TOPDOWN) - { - state->solid = SOLID_NOT; - } - - } - - } - - // Inactive hives should be drawn for players on their team - if((ent->v.iuser3 == AVH_USER3_HIVE) && (!GetHasUpgrade(ent->v.iuser4, MASK_BUILDABLE))) - { - // Assumes that aliens of both teams can build on the same hive location - AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); - if(theReceivingPlayer && theReceivingPlayer->GetIsAlien()) - { - state->renderamt = 128; - } - } - - // Handle cloakables here - if(!AvHSUGetIsExternalClassName(theEntNameString)) - { - AvHCloakable* theCloakable = dynamic_cast(CBaseEntity::Instance(ent)); - if(theCloakable) - { - // Now updated in gamerules - theCloakable->Update(); - - float theOpacityScalar = theCloakable->GetOpacity(); - if(theOpacityScalar < 1.0f) - { - int theBaseOpacity = kAlienStructureCloakAmount; - int theOpacityRange = 255 - kAlienStructureCloakAmount; - - // Allow spectators to see cloaked entities as if they are the player they are following, or as if they are on the same team as the alien otherwise - bool theCanSeeCloaked = (host->v.team == ent->v.team); - if(!theCanSeeCloaked) - { - int theHostIUserOne = host->v.iuser1; - if((theHostIUserOne == OBS_CHASE_LOCKED) || (theHostIUserOne == OBS_CHASE_FREE) || (theHostIUserOne == OBS_IN_EYE) ) - { - // View entities as player we're tracking - int theHostIUserTwo = host->v.iuser2; - CBaseEntity* theSpectatingEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theHostIUserTwo)); - if(theSpectatingEntity) - { - int theSpectatingEntityTeamNumber = theSpectatingEntity->pev->team; - if((theSpectatingEntityTeamNumber == ent->v.team) || (host->v.team == TEAM_IND)) - { - theCanSeeCloaked = true; - } - } - } - } - - if(theCanSeeCloaked) - { - theBaseOpacity = kAlienSelfCloakingBaseOpacity; - theOpacityRange = 255 - theBaseOpacity; - } - - int theOpacity = theBaseOpacity + theOpacityScalar*theOpacityRange; - theOpacity = max(min(255, theOpacity), 0); - - state->rendermode = kRenderTransTexture; - state->renderamt = theOpacity; - } - } - } - - // Spectator - state->iuser1 = ent->v.iuser1; - state->iuser2 = ent->v.iuser2; - - // AvH specials - state->iuser3 = ent->v.iuser3; - state->iuser4 = ent->v.iuser4; - - // Slightly different processing for particle system entities -// if(theIsParticleSystemEntity) -// { -// // propagate weapon model as custom data) -// state->weaponmodel = ent->v.weaponmodel; -// } - - state->fuser1 = ent->v.fuser1; - state->fuser2 = ent->v.fuser2; - state->fuser3 = ent->v.fuser3; - state->vuser4 = ent->v.vuser4; - - - - - - - state->aiment = 0; - if ( ent->v.aiment ) - { - state->aiment = ENTINDEX( ent->v.aiment ); - } - - state->owner = 0; - if ( ent->v.owner ) - { - int owner = ENTINDEX( ent->v.owner ); - - // Only care if owned by a player - if ( owner >= 1 && owner <= gpGlobals->maxClients ) - { - state->owner = owner; - } - } - - // HACK: Somewhat... - // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) - if ( !player ) - { - state->playerclass = ent->v.playerclass; - } - - // Propagate team for all entities (mainly needed for client-side lasso selection) - state->team = ent->v.team; - - // Check special vision mode - AvHPlayer* theReceivingPlayer = dynamic_cast(CBaseEntity::Instance(host)); - if(theReceivingPlayer && (theReceivingPlayer->GetIsAlienSightActive())) - { - bool marineGlow = false; - if (player) - { - // Uncomment below to enable range for the alien flashlight - // vec3_t theDistanceVec; - // VectorSubtract(theReceivingPlayer->pev->origin, ent->v.origin, theDistanceVec); - - // int theDistance = theDistanceVec[0] * theDistanceVec[0] + theDistanceVec[1] * theDistanceVec[1] + theDistanceVec[2] * theDistanceVec[2]; - // int theRange = BALANCE_VAR(kAlienFlashlightRange); - // marineGlow = (theDistance < ( theRange * theRange)); - marineGlow = true; - } - - if(( marineGlow || (ent->v.team == theReceivingPlayer->pev->team)) && (ent != theReceivingPlayer->edict()) && (ent->v.team != TEAM_IND) && (ent->v.team != TEAM_SPECT ) && (ent->v.classname != MAKE_STRING(kesTeamWebStrand)) ) - { - state->rendermode = kRenderTransAdd; - state->renderamt = 150; - } - } - - // Special stuff for players only - if(player) - { - state->basevelocity = ent->v.basevelocity; - - state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); - state->gaitsequence = ent->v.gaitsequence; - state->spectator = ent->v.flags & FL_SPECTATOR; - state->friction = ent->v.friction; - - state->gravity = ent->v.gravity; - - // New SDK doesn't propagate team for a reason? - //state->playerclass = ent->v.playerclass; - //state->team = ent->v.team; - - bool theIsDucking = ent->v.flags & FL_DUCKING; - state->usehull = AvHMUGetHull(theIsDucking, ent->v.iuser3); - - // Propagate "energy level" - state->fuser3 = ent->v.fuser3; - - // For skulk oriented player model - state->vuser1 = ent->v.vuser1; - - // For weapons - state->vuser4 = ent->v.vuser4; - - //state->skin = theTargetPlayer->GetSkin(); - state->skin = ent->v.skin; - state->playerclass = ent->v.playerclass; - // state->armorvalue = ent->v.armorvalue; - - AvHPlayer* thePlayerEntity = dynamic_cast(CBaseEntity::Instance(ent)); - if(thePlayerEntity && thePlayerEntity->GetIsTemporarilyInvulnerable()) - { - int theTeamIndex = ent->v.team; - ASSERT(theTeamIndex >= 0); - ASSERT(theTeamIndex < iNumberOfTeamColors); - - state->renderfx = kRenderFxGlowShell; - state->rendercolor.r = kTeamColors[theTeamIndex][0]; - state->rendercolor.g = kTeamColors[theTeamIndex][1]; - state->rendercolor.b = kTeamColors[theTeamIndex][2]; - state->renderamt = kInvulShellRenderAmount; - } - } - - state->health = ent->v.health; - - kNumReturn1++; - - return 1; -} - diff --git a/main/source/dlls/client.h b/main/source/dlls/client.h index ccf69c1f..d3d9a0c5 100644 --- a/main/source/dlls/client.h +++ b/main/source/dlls/client.h @@ -1,68 +1,68 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef CLIENT_H -#define CLIENT_H - -extern void respawn( entvars_t* pev, BOOL fCopyCorpse ); -extern BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); -extern void ClientDisconnect( edict_t *pEntity ); -extern void ClientKill( edict_t *pEntity ); -extern void ClientPutInServer( edict_t *pEntity ); -extern void ClientCommand( edict_t *pEntity ); -extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ); -extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); -extern void ServerDeactivate( void ); -extern void StartFrame( void ); -extern void PlayerPostThink( edict_t *pEntity ); -extern void PlayerPreThink( edict_t *pEntity ); -extern void ParmsNewLevel( void ); -extern void ParmsChangeLevel( void ); - -extern void ClientPrecache( void ); - -extern const char *GetGameDescription( void ); -extern void PlayerCustomization( edict_t *pEntity, customization_t *pCust ); - -extern void ShowMenu(entvars_s *pev, int ValidSlots, int DisplayTime, BOOL ShowLater, char Menu[500]); -extern void SpectatorConnect ( edict_t *pEntity ); -extern void SpectatorDisconnect ( edict_t *pEntity ); -extern void SpectatorThink ( edict_t *pEntity ); - -extern void Sys_Error( const char *error_string ); - -extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ); -extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); -extern int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); -extern void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); -extern void RegisterEncoders( void ); - -extern int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ); - -extern void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); -extern void CmdEnd ( const edict_t *player ); - -extern int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); - -extern int GetHullBounds( int hullnumber, float *mins, float *maxs ); - -extern void CreateInstancedBaselines ( void ); - -extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); - -extern int AllowLagCompensation( void ); - -//extern bool AvHClientCommand( edict_t *pEntity ); - -#endif // CLIENT_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CLIENT_H +#define CLIENT_H + +extern void respawn( entvars_t* pev, BOOL fCopyCorpse ); +extern BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); +extern void ClientDisconnect( edict_t *pEntity ); +extern void ClientKill( edict_t *pEntity ); +extern void ClientPutInServer( edict_t *pEntity ); +extern void ClientCommand( edict_t *pEntity ); +extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ); +extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); +extern void ServerDeactivate( void ); +extern void StartFrame( void ); +extern void PlayerPostThink( edict_t *pEntity ); +extern void PlayerPreThink( edict_t *pEntity ); +extern void ParmsNewLevel( void ); +extern void ParmsChangeLevel( void ); + +extern void ClientPrecache( void ); + +extern const char *GetGameDescription( void ); +extern void PlayerCustomization( edict_t *pEntity, customization_t *pCust ); + +extern void ShowMenu(entvars_s *pev, int ValidSlots, int DisplayTime, BOOL ShowLater, char Menu[500]); +extern void SpectatorConnect ( edict_t *pEntity ); +extern void SpectatorDisconnect ( edict_t *pEntity ); +extern void SpectatorThink ( edict_t *pEntity ); + +extern void Sys_Error( const char *error_string ); + +extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ); +extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); +extern int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); +extern void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); +extern void RegisterEncoders( void ); + +extern int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ); + +extern void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); +extern void CmdEnd ( const edict_t *player ); + +extern int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); + +extern int GetHullBounds( int hullnumber, float *mins, float *maxs ); + +extern void CreateInstancedBaselines ( void ); + +extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); + +extern int AllowLagCompensation( void ); + +//extern bool AvHClientCommand( edict_t *pEntity ); + +#endif // CLIENT_H diff --git a/main/source/dlls/combat.cpp b/main/source/dlls/combat.cpp index 13f04b37..2b9952bc 100644 --- a/main/source/dlls/combat.cpp +++ b/main/source/dlls/combat.cpp @@ -1,1914 +1,1914 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== combat.cpp ======================================================== - - functions dealing with damage infliction & death - -*/ -// -// $Workfile: combat.cpp $ -// $Date: 2002/11/22 23:26:35 $ -// -//------------------------------------------------------------------------------- -// $Log: combat.cpp,v $ -// Revision 1.19 2002/11/22 23:26:35 Flayra -// - Skulks had to aim too high to hit structures, so trying this approach to fixing the melee in vents bug -// -// Revision 1.18 2002/11/22 21:09:50 Flayra -// - Explosion fixes (oops!) -// - Fix melee when in vents (I think) -// -// Revision 1.17 2002/11/13 01:49:33 Flayra -// - Proper death message logging for Psychostats -// -// Revision 1.16 2002/11/12 02:18:08 Flayra -// - Pass on inflictor properly for standard logging -// -// Revision 1.15 2002/11/06 01:36:16 Flayra -// - Allow scalar to apply to damage from gamerules (used for friendly fire) -// -// Revision 1.14 2002/10/03 18:26:36 Flayra -// - Removed all pushback and forces when doing damage to players -// -// Revision 1.13 2002/08/16 02:25:21 Flayra -// - New damage types -// -// Revision 1.12 2002/07/10 14:36:13 Flayra -// - Removed major cause of lag: redundant server-side decals. Also removed duplicate texture sound. -// -// Revision 1.11 2002/07/08 16:40:05 Flayra -// - Fix bug where melee attacks couldn't aim up or down, reworked bullet firing to add random spread (bug #236) -// -//=============================================================================== - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" -#include "decals.h" -#include "animation.h" -#include "weapons.h" -#include "func_break.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHAlienWeaponConstants.h" -#include "../mod/AvHTurret.h" -#include "../mod/AvHServerVariables.h" -//#include "../mod/AvHMovementUtil.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL int g_iSkillLevel; - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern entvars_t *g_pevLastInflictor; - -#define GERMAN_GIB_COUNT 4 -#define HUMAN_GIB_COUNT 6 -#define ALIEN_GIB_COUNT 4 - - -// HACKHACK -- The gib velocity equations don't work -void CGib :: LimitVelocity( void ) -{ - float length = pev->velocity.Length(); - - // ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it - // in 3 separate places again, I'll just limit it here. - if ( length > 1500.0 ) - pev->velocity = pev->velocity.Normalize() * 1500; // This should really be sv_maxvelocity * 0.75 or something -} - - -void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ) -{ - int i; - - if ( g_Language == LANGUAGE_GERMAN ) - { - // no sticky gibs in germany right now! - return; - } - - for ( i = 0 ; i < cGibs ; i++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( "models/stickygib.mdl" ); - pGib->pev->body = RANDOM_LONG(0,2); - - if ( pevVictim ) - { - pGib->pev->origin.x = vecOrigin.x + RANDOM_FLOAT( -3, 3 ); - pGib->pev->origin.y = vecOrigin.y + RANDOM_FLOAT( -3, 3 ); - pGib->pev->origin.z = vecOrigin.z + RANDOM_FLOAT( -3, 3 ); - - /* - pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ); - */ - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.15, 0.15 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.15, 0.15 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.15, 0.15 ); - - pGib->pev->velocity = pGib->pev->velocity * 900; - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 250, 400 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 250, 400 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - - - pGib->pev->movetype = MOVETYPE_TOSS; - pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) ); - pGib->SetTouch ( &CGib::StickyGibTouch ); - pGib->SetThink (NULL); - } - pGib->LimitVelocity(); - } -} - -void CGib :: SpawnHeadGib( entvars_t *pevVictim ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - if ( g_Language == LANGUAGE_GERMAN ) - { - pGib->Spawn( "models/germangibs.mdl" );// throw one head - pGib->pev->body = 0; - } - else - { - pGib->Spawn( "models/hgibs.mdl" );// throw one head - pGib->pev->body = 0; - } - - if ( pevVictim ) - { - pGib->pev->origin = pevVictim->origin + pevVictim->view_ofs; - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict() ); - - if ( RANDOM_LONG ( 0, 100 ) <= 5 && pentPlayer ) - { - // 5% chance head will be thrown at player's face. - entvars_t *pevPlayer; - - pevPlayer = VARS( pentPlayer ); - pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300; - pGib->pev->velocity.z += 100; - } - else - { - pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - } - - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - } - pGib->LimitVelocity(); -} - -void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) -{ - int cSplat; - - for ( cSplat = 0 ; cSplat < cGibs ; cSplat++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - if ( g_Language == LANGUAGE_GERMAN ) - { - pGib->Spawn( "models/germangibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,GERMAN_GIB_COUNT-1); - } - else - { - if ( human ) - { - // human pieces - pGib->Spawn( "models/hgibs.mdl" ); - pGib->pev->body = RANDOM_LONG(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib) - } - else - { - // aliens - pGib->Spawn( "models/agibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,ALIEN_GIB_COUNT-1); - } - } - - if ( pevVictim ) - { - // spawn the gib somewhere in the monster's bounding volume - pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ) + 1; // absmin.z is in the floor because the engine subtracts 1 to enlarge the box - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.25, 0.25 ); - - pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT ( 300, 400 ); - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - - pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector( 0 , 0 , 0 ), Vector ( 0, 0, 0 ) ); - } - pGib->LimitVelocity(); - } -} - - -BOOL CBaseMonster :: HasHumanGibs( void ) -{ - int myClass = Classify(); - - if ( myClass == CLASS_HUMAN_MILITARY || - myClass == CLASS_PLAYER_ALLY || - myClass == CLASS_HUMAN_PASSIVE || - myClass == CLASS_PLAYER ) - - return TRUE; - - return FALSE; -} - - -BOOL CBaseMonster :: HasAlienGibs( void ) -{ - int myClass = Classify(); - - if ( myClass == CLASS_ALIEN_MILITARY || - myClass == CLASS_ALIEN_MONSTER || - myClass == CLASS_ALIEN_PASSIVE || - myClass == CLASS_INSECT || - myClass == CLASS_ALIEN_PREDATOR || - myClass == CLASS_ALIEN_PREY ) - - return TRUE; - - return FALSE; -} - - -void CBaseMonster::FadeMonster( void ) -{ - StopAnimation(); - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->avelocity = g_vecZero; - pev->animtime = gpGlobals->time; - pev->effects |= EF_NOINTERP; - SUB_StartFadeOut(); -} - -//========================================================= -// GibMonster - create some gore and get rid of a monster's -// model. -//========================================================= -void CBaseMonster :: GibMonster( void ) -{ - TraceResult tr; - BOOL gibbed = FALSE; - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM); - - // only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs - if ( HasHumanGibs() ) - { - if ( ns_cvar_float(violence_hgibs) != 0 ) // Only the player will ever get here - { - CGib::SpawnHeadGib( pev ); - CGib::SpawnRandomGibs( pev, 4, 1 ); // throw some human gibs. - } - gibbed = TRUE; - } - else if ( HasAlienGibs() ) - { - if ( ns_cvar_float(violence_hgibs) != 0 ) // Should never get here, but someone might call it directly - { - CGib::SpawnRandomGibs( pev, 4, 0 ); // Throw alien gibs - } - gibbed = TRUE; - } - - if ( !IsPlayer() ) - { - if ( gibbed ) - { - // don't remove players! - SetThink ( &CBaseMonster::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - else - { - FadeMonster(); - } - } -} - -//========================================================= -// GetDeathActivity - determines the best type of death -// anim to play. -//========================================================= -Activity CBaseMonster :: GetDeathActivity ( void ) -{ - Activity deathActivity; - BOOL fTriedDirection; - float flDot; - TraceResult tr; - Vector vecSrc; - - if ( pev->deadflag != DEAD_NO ) - { - // don't run this while dying. - return m_IdealActivity; - } - - vecSrc = Center(); - - fTriedDirection = FALSE; - deathActivity = ACT_DIESIMPLE;// in case we can't find any special deaths to do. - - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // try to pick a region-specific death. - case HITGROUP_HEAD: - deathActivity = ACT_DIE_HEADSHOT; - break; - - case HITGROUP_STOMACH: - deathActivity = ACT_DIE_GUTSHOT; - break; - - case HITGROUP_GENERIC: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - - default: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - } - - - // can we perform the prescribed death? - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // no! did we fail to perform a directional death? - if ( fTriedDirection ) - { - // if yes, we're out of options. Go simple. - deathActivity = ACT_DIESIMPLE; - } - else - { - // cannot perform the ideal region-specific death, so try a direction. - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - } - } - - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // if we're still invalid, simple is our only option. - deathActivity = ACT_DIESIMPLE; - } - - if ( deathActivity == ACT_DIEFORWARD ) - { - // make sure there's room to fall forward - UTIL_TraceHull ( vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - if ( deathActivity == ACT_DIEBACKWARD ) - { - // make sure there's room to fall backward - UTIL_TraceHull ( vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - return deathActivity; -} - -//========================================================= -// GetSmallFlinchActivity - determines the best type of flinch -// anim to play. -//========================================================= -Activity CBaseMonster :: GetSmallFlinchActivity ( void ) -{ - Activity flinchActivity; - BOOL fTriedDirection; - float flDot; - - fTriedDirection = FALSE; - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // pick a region-specific flinch - case HITGROUP_HEAD: - flinchActivity = ACT_FLINCH_HEAD; - break; - case HITGROUP_STOMACH: - flinchActivity = ACT_FLINCH_STOMACH; - break; - case HITGROUP_LEFTARM: - flinchActivity = ACT_FLINCH_LEFTARM; - break; - case HITGROUP_RIGHTARM: - flinchActivity = ACT_FLINCH_RIGHTARM; - break; - case HITGROUP_LEFTLEG: - flinchActivity = ACT_FLINCH_LEFTLEG; - break; - case HITGROUP_RIGHTLEG: - flinchActivity = ACT_FLINCH_RIGHTLEG; - break; - case HITGROUP_GENERIC: - default: - // just get a generic flinch. - flinchActivity = ACT_SMALL_FLINCH; - break; - } - - - // do we have a sequence for the ideal activity? - if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - flinchActivity = ACT_SMALL_FLINCH; - } - - return flinchActivity; -} - - -void CBaseMonster::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. - - // make the corpse fly away from the attack vector - pev->movetype = MOVETYPE_TOSS; - //pev->flags &= ~FL_ONGROUND; - //pev->origin.z += 2; - //pev->velocity = g_vecAttackDir * -1; - //pev->velocity = pev->velocity * RANDOM_FLOAT( 300, 400 ); -} - - -BOOL CBaseMonster::ShouldGibMonster( int iGib ) -{ - if ( ( iGib == GIB_NORMAL && pev->health < GIB_HEALTH_VALUE ) || ( iGib == GIB_ALWAYS ) ) - return TRUE; - - return FALSE; -} - - -void CBaseMonster::CallGibMonster( void ) -{ - BOOL fade = FALSE; - - if ( HasHumanGibs() ) - { - if ( ns_cvar_float(violence_hgibs) == 0 ) - fade = TRUE; - } - else if ( HasAlienGibs() ) - { - if ( ns_cvar_float(violence_agibs) == 0 ) - fade = TRUE; - } - - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT;// do something with the body. while monster blows up - - if ( fade ) - { - FadeMonster(); - } - else - { - pev->effects = EF_NODRAW; // make the model invisible. - GibMonster(); - } - - pev->deadflag = DEAD_DEAD; - FCheckAITrigger(); - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) - { - pev->health = 0; - } - - if ( ShouldFadeOnDeath() && !fade ) - UTIL_Remove(this); -} - - -/* -============ -Killed -============ -*/ -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - unsigned int cCount = 0; - BOOL fDone = FALSE; - - CBaseEntity* theBaseEntity = CBaseEntity::Instance(pevAttacker->owner); - if(!theBaseEntity) - { - theBaseEntity = CBaseEntity::Instance(pevAttacker); - } - ASSERT(theBaseEntity); - theBaseEntity->AwardKill(this->pev); - - if ( HasMemory( bits_MEMORY_KILLED ) ) - { - if ( ShouldGibMonster( iGib ) ) - CallGibMonster(); - return; - } - - Remember( bits_MEMORY_KILLED ); - - // clear the deceased's sound channels.(may have been firing or reloading when killed) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM); - m_IdealMonsterState = MONSTERSTATE_DEAD; - // Make sure this condition is fired too (TakeDamage breaks out before this happens on death) - SetConditions( bits_COND_LIGHT_DAMAGE ); - - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) - { - pOwner->DeathNotice( pev ); - } - - if ( ShouldGibMonster( iGib ) ) - { - CallGibMonster(); - return; - } - else if ( pev->flags & FL_MONSTER ) - { - SetTouch( NULL ); - BecomeDead(); - } - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) - { - pev->health = 0; - } - - //pev->enemy = ENT( pevAttacker );//why? (sjb) - - m_IdealMonsterState = MONSTERSTATE_DEAD; - -} - -// -// fade out - slowly fades a entity out, then removes it. -// -// DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER! -// SET A FUTURE THINK AND A RENDERMODE!! -void CBaseEntity :: SUB_StartFadeOut ( void ) -{ - if (pev->rendermode == kRenderNormal) - { - pev->renderamt = 255; - pev->rendermode = kRenderTransTexture; - } - - pev->solid = SOLID_NOT; - pev->avelocity = g_vecZero; - - pev->nextthink = gpGlobals->time + 0.1; - SetThink ( &CBaseEntity::SUB_FadeOut ); -} - -void CBaseEntity :: SUB_FadeOut ( void ) -{ - if ( pev->renderamt > 7 ) - { - pev->renderamt -= 7; - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - pev->renderamt = 0; - pev->nextthink = gpGlobals->time + 0.2; - SetThink ( &CBaseEntity::SUB_Remove ); - } -} - -//========================================================= -// WaitTillLand - in order to emit their meaty scent from -// the proper location, gibs should wait until they stop -// bouncing to emit their scent. That's what this function -// does. -//========================================================= -void CGib :: WaitTillLand ( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - if ( pev->velocity == g_vecZero ) - { - SetThink (&CGib::SUB_StartFadeOut); - pev->nextthink = gpGlobals->time + m_lifeTime; - - // If you bleed, you stink! - if ( m_bloodColor != DONT_BLEED ) - { - // ok, start stinkin! - CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 ); - } - } - else - { - // wait and check again in another half second. - pev->nextthink = gpGlobals->time + 0.5; - } -} - -// -// Gib bounces on the ground or wall, sponges some blood down, too! -// -void CGib :: BounceGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - //if ( RANDOM_LONG(0,1) ) - // return;// don't bleed everytime - - if (pev->flags & FL_ONGROUND) - { - pev->velocity = pev->velocity * 0.9; - pev->angles.x = 0; - pev->angles.z = 0; - pev->avelocity.x = 0; - pev->avelocity.z = 0; - } - else - { - if ( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) - { - vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); - - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - m_cBloodDecals--; - } - - if ( m_material != matNone && RANDOM_LONG(0,2) == 0 ) - { - float volume; - float zvel = fabs(pev->velocity.z); - - volume = 0.8 * min(1.0, ((float)zvel) / 450.0); - - CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); - } - } -} - -// -// Sticky gib puts blood on the wall and stays put. -// -void CGib :: StickyGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - SetThink ( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 10; - - if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) - { - pev->nextthink = gpGlobals->time; - return; - } - - UTIL_TraceLine ( pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), & tr); - - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - pev->velocity = tr.vecPlaneNormal * -1; - pev->angles = UTIL_VecToAngles ( pev->velocity ); - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; -} - -// -// Throw a chunk -// -void CGib :: Spawn( const char *szGibModel ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->friction = 0.55; // deading the bounce a bit - - // sometimes an entity inherits the edict from a former piece of glass, - // and will spawn using the same render FX or rendermode! bad! - pev->renderamt = 255; - pev->rendermode = kRenderNormal; - pev->renderfx = kRenderFxNone; - pev->solid = SOLID_SLIDEBOX;/// hopefully this will fix the VELOCITY TOO LOW crap - pev->classname = MAKE_STRING("gib"); - - SET_MODEL(ENT(pev), szGibModel); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pev->nextthink = gpGlobals->time + 4; - m_lifeTime = 25; - SetThink ( &CGib::WaitTillLand ); - SetTouch ( &CGib::BounceGibTouch ); - - m_material = matNone; - m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain). -} - -// take health -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) -{ - if (!pev->takedamage) - return 0; - - // clear out any damage types we healed. - // UNDONE: generic health should not heal any - // UNDONE: time-based damage - - m_bitsDamageType &= ~(bitsDamageType & ~DMG_TIMEBASED); - - return CBaseEntity::TakeHealth(flHealth, bitsDamageType); -} - -/* -============ -TakeDamage - -The damage is coming from inflictor, but get mad at attacker -This should be the only function that ever reduces health. -bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK - -Time-based damage: only occurs while the monster is within the trigger_hurt. -When a monster is poisoned via an arrow etc it takes all the poison damage at once. - - - -GLOBALS ASSUMED SET: g_iSkillLevel -============ -*/ -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flTake; - Vector vecDir; - - if (!pev->takedamage) - return 0; - - if ( !IsAlive() ) - { - return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - } - - if ( pev->deadflag == DEAD_NO ) - { - // no pain sound during death animation. - PainSound();// "Ouch!" - } - - //!!!LATER - make armor consideration here! - flTake = flDamage; - - // set damage type sustained - m_bitsDamageType |= bitsDamageType; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - - // add to the damage total for clients, which will be sent as a single - // message at the end of the frame - // todo: remove after combining shotgun blasts? - if ( IsPlayer() ) - { - if ( pevInflictor ) - pev->dmg_inflictor = ENT(pevInflictor); - - pev->dmg_take += flTake; - - // check for godmode or invincibility - if ( pev->flags & FL_GODMODE ) - { - return 0; - } - } - - // HL: if this is a player, move him around! - // NS: Don't move players - if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) && !IsPlayer()) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - - // do the damage - pev->health -= flTake; - - - // HACKHACK Don't kill monsters in a script. Let them break their scripts first - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - SetConditions( bits_COND_LIGHT_DAMAGE ); - return 0; - } - - if ( (int)(pev->health) <= 0 ) - { - g_pevLastInflictor = pevInflictor; - -// Removed gibbing, as death animations weren't playing with gibs off -// if ( bitsDamageType & DMG_ALWAYSGIB ) -// { -// Killed( pevAttacker, GIB_ALWAYS ); -// } -// else if ( bitsDamageType & DMG_NEVERGIB ) -// { - Killed( pevAttacker, GIB_NEVER ); -// } -// else -// { -// Killed( pevAttacker, GIB_NORMAL ); -// } - - // Trigger log message if needed -// AvHPlayer* theDeadPlayer = dynamic_cast(this); -// AvHPlayer* theAttackingPlayer = dynamic_cast(CBaseEntity::Instance(ENT(pevAttacker))); -// const char* inWeaponName = STRING(pevInflictor->classname); -// if(theDeadPlayer && theAttackingPlayer && inWeaponName) -// { -// theDeadPlayer->LogPlayerKilledPlayer(theAttackingPlayer, inWeaponName); -// } - - g_pevLastInflictor = NULL; - - return 0; - } - - // react to the damage (get mad) - if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) - { - if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) - {// only if the attack was a monster or client! - - // enemy's last known position is somewhere down the vector that the attack came from. - if (pevInflictor) - { - if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) - { - m_vecEnemyLKP = pevInflictor->origin; - } - } - else - { - m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); - } - - MakeIdealYaw( m_vecEnemyLKP ); - - // add pain to the conditions - // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and - // heavy damage per monster class? - if ( flDamage > 0 ) - { - SetConditions(bits_COND_LIGHT_DAMAGE); - } - - if ( flDamage >= 20 ) - { - SetConditions(bits_COND_HEAVY_DAMAGE); - } - } - } - - return 1; -} - -//========================================================= -// DeadTakeDamage - takedamage function called when a monster's -// corpse is damaged. -//========================================================= -int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecDir; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - -#if 0// turn this back on when the bounding box issues are resolved. - - pev->flags &= ~FL_ONGROUND; - pev->origin.z += 1; - - // let the damage scoot the corpse around a bit. - if ( !FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER) ) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - -#endif - - // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. - if ( bitsDamageType & DMG_GIB_CORPSE ) - { - if ( pev->health <= flDamage ) - { - pev->health = -50; - Killed( pevAttacker, GIB_ALWAYS ); - return 0; - } - // Accumulate corpse gibbing damage, so you can gib with multiple hits - pev->health -= flDamage * 0.1; - } - - return 1; -} - - -float CBaseMonster :: DamageForce( float damage ) -{ - float force = damage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if ( force > 1000.0) - { - force = 1000.0; - } - - return force; -} - -// -// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range. -// -// only damage ents that can clearly be seen by the explosion! - - -void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float inDamage, float flRadius, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage, falloff; - Vector vecSpot; - - if ( flRadius ) - falloff = inDamage / flRadius; - else - falloff = 1.0; - - int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); - - vecSrc.z += 1;// in case grenade is lying on the ground - - if ( !pevAttacker ) - pevAttacker = pevInflictor; - - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) - { - // NOTE: Should this be inflictor or attacker? - CBaseEntity* theInflictingEntity = CBaseEntity::Instance(pevInflictor); - CBaseEntity* theAttackingEntity = CBaseEntity::Instance(pevAttacker); - float theScalar = 1.0f; - bool aCanDamage=GetGameRules()->CanEntityDoDamageTo(theAttackingEntity, pEntity, &theScalar) || theInflictingEntity->pev->classname == MAKE_STRING(kwsDeployedMine);; - bool iCanDamage=GetGameRules()->CanEntityDoDamageTo(theInflictingEntity, pEntity, &theScalar); - - if(pEntity && ( aCanDamage && iCanDamage )) - { - // Multiply damage by scalar for tourny mode, etc. - float theDamage = inDamage*theScalar; - - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - - // UNDONE: this should check a damage mask, not an ignore - if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - {// houndeyes don't hurt other houndeyes with their attack - continue; - } - - // blast's don't tavel into or out of water - if (bInWater && pEntity->pev->waterlevel == 0) - continue; - if (!bInWater && pEntity->pev->waterlevel == 3) - continue; - - vecSpot = pEntity->BodyTarget( vecSrc ); - - // Clear pevInflictor's owner temporarily so it can apply damage to it - edict_t* theInflictorOwner = pevInflictor->owner; - pevInflictor->owner = NULL; - - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); - - // Restore owner - pevInflictor->owner = theInflictorOwner; - - if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - {// the explosion can 'see' this entity, so hurt them! - if (tr.fStartSolid) - { - // if we're stuck inside them, fixup the position and distance - tr.vecEndPos = vecSrc; - tr.flFraction = 0.0; - } - - // decrease damage for an ent that's farther from the bomb. - flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; - flAdjustedDamage = theDamage - flAdjustedDamage; - - if ( flAdjustedDamage > 0 ) - { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } - } -} - - -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - - -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - -int CBaseMonster::GetHull() const -{ - return head_hull; -} - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// -// Used for many contact-range melee attacks. Bites, claws, etc. -//========================================================= -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ) -{ - Vector vecStart = pev->origin; - - if(this->IsPlayer()) - { - // Melee attacks always originate where the view is - vecStart.x += this->pev->view_ofs.x; - vecStart.y += this->pev->view_ofs.y; - vecStart.z += this->pev->view_ofs.z; - } - - if (IsPlayer()) - UTIL_MakeVectors( pev->v_angle ); - else - UTIL_MakeAimVectors( pev->angles ); - - //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecStart); - - // First do a tracehull. If that misses, try three tracelines (dead-on center, then randomly left and randomly right). - bool theHitTarget = false; - for(int i = 0; (i < 4) && !theHitTarget; i++) - { - const float kAmount = 0.4f; - float theXAmount = 0.0f; - - if(i == 2) - { - theXAmount = kAmount; - } - else if(i == 3) - { - theXAmount = -kAmount; - } - - Vector vecDir = gpGlobals->v_forward + theXAmount*gpGlobals->v_right; - vecDir.Normalize(); - - Vector vecEnd = vecStart + (vecDir * flDist ); - TraceResult tr; - - if(i == 0) - { - int theOurHull = this->GetHull(); - int theHull = AvHSUGetValveHull(theOurHull); - UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, theHull, this->edict(), &tr); - } - else - { - //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecEnd); - - UTIL_TraceLine(vecStart, vecEnd, dont_ignore_monsters, dont_ignore_glass, ENT(this->pev), &tr); - } - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( ioDamage > 0 ) - { - float theScalar = 1.0f; - if(GetGameRules()->CanEntityDoDamageTo(this, pEntity, &theScalar)) - { - theHitTarget = true; - - // Multiply damage by scalar for tourny mode, etc. - ioDamage *= theScalar; - - entvars_t* theInflictor = this->pev; - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer) - { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(thePlayer->m_pActiveItem); - if(theBasePlayerWeapon) - { - theInflictor = theBasePlayerWeapon->pev; - } - } - - pEntity->TakeDamage(theInflictor, pev, ioDamage, iDmgType ); - - // Spawn blood - if(ioDamage > 0.0f) - { - // a little surface blood. - SpawnBlood(tr.vecEndPos, pEntity->BloodColor(), ioDamage); - - // on the wall/floor (don't play because blood decal is green) - //TraceBleed(ioDamage, vecDir, &tr, iDmgType); - } - - return pEntity; - } - } - } - } - - return NULL; -} - - -//========================================================= -// FInViewCone - returns true is the passed ent is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FInViewCone - returns true is the passed vector is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( *pOrigin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target -//========================================================= -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) -{ - TraceResult tr; - Vector vecLookerOrigin; - Vector vecTargetOrigin; - - if (FBitSet( pEntity->pev->flags, FL_NOTARGET )) - return FALSE; - - // don't look through water //edit by Elven Thief to prevent bug #728 - // if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - // || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - // return FALSE; - - vecLookerOrigin = this->EyePosition();//look through the caller's 'eyes' - vecTargetOrigin = pEntity->EyePosition(); - - return AvHCheckLineOfSight(vecLookerOrigin, vecTargetOrigin, ENT(pev)); - -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target vector -//========================================================= -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) -{ - TraceResult tr; - Vector vecLookerOrigin; - - vecLookerOrigin = EyePosition();//look through the caller's 'eyes' - - return AvHCheckLineOfSight(vecLookerOrigin, vecOrigin, ENT(pev)); - -} - -/* -================ -TraceAttack -================ -*/ -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - } -} - - -/* -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - ALERT ( at_console, "%d\n", ptr->iHitgroup ); - - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - } - } -} -*/ - -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= gSkillData.monHead; - break; - case HITGROUP_CHEST: - flDamage *= gSkillData.monChest; - break; - case HITGROUP_STOMACH: - flDamage *= gSkillData.monStomach; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= gSkillData.monArm; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= gSkillData.monLeg; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. - -This version is used by Monsters. -================ -*/ -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int inDamageType) -{ - static int tracerCount; - int tracer; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - ClearMultiDamage(); - gMultiDamage.type = inDamageType; - - for (ULONG iShot = 1; iShot <= cShots; iShot++) - { - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - - Vector vecDir = vecDirShooting + - x * vecSpread.x * vecRight + - y * vecSpread.y * vecUp; - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - //UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - bool theProtected = false; - AvHSUServerTraceBullets(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), tr, theProtected); - CBaseEntity* theEntityHit = CBaseEntity::Instance(tr.pHit); - - if(theProtected && theEntityHit) - { - // : experiment - EMIT_SOUND(theEntityHit->edict(), CHAN_AUTO, kUmbraBlockedSound, 1.0f, ATTN_NORM); - // : - } - else - { - tracer = 0; - if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0) - { - Vector vecTracerSrc; - - if ( IsPlayer() ) - {// adjust tracer position for player - vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16; - } - else - { - vecTracerSrc = vecSrc; - } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal - tracer = 1; - switch( iBulletType ) - { - case BULLET_MONSTER_MP5: - case BULLET_MONSTER_9MM: - case BULLET_MONSTER_12MM: - default: - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( vecTracerSrc.x ); - WRITE_COORD( vecTracerSrc.y ); - WRITE_COORD( vecTracerSrc.z ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - MESSAGE_END(); - break; - } - } - // do damage, paint decals - if (tr.flFraction != 1.0) - { - float theScalar = 1.0f; - if(theEntityHit && GetGameRules()->CanEntityDoDamageTo(this, theEntityHit, &theScalar)) - { - // Multiply damage by scalar for tourny mode, etc. - iDamage *= theScalar; - - if ( iDamage ) - { - theEntityHit->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - //DecalGunshot( &tr, 0 ); - } - else switch(iBulletType) - { - default: - case BULLET_MONSTER_9MM: - theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MONSTER_MP5: - theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MONSTER_12MM: - theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_NONE: // FIX - theEntityHit->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB); - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - // only decal glass - if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0) - { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); - } - - break; - } - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); - } - } - ApplyMultiDamage(pev, pevAttacker); -} - - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. - -This version is used by Players, uses the random seed generator to sync client and server side shots. -================ -*/ -Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) -{ - static int tracerCount; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - entvars_t* theInflictor = this->pev; - //float x, y, z; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - int theDamageType = DMG_BULLET; - bool isShotgun=false; - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && thePlayer->m_pActiveItem) - { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(thePlayer->m_pActiveItem); - if(theBasePlayerWeapon) - { - theDamageType = theBasePlayerWeapon->GetDamageType(); - theInflictor = theBasePlayerWeapon->pev; - } - AvHSonicGun* theSonicGun = dynamic_cast(thePlayer->m_pActiveItem); - if ( theSonicGun ) - { - isShotgun=true; - } - } - else - { - AvHTurret* theTurret = dynamic_cast(this); - if(theTurret) - { - theDamageType = theTurret->GetDamageType(); - } - } - - ClearMultiDamage(); - gMultiDamage.type = theDamageType; - - for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) - { - //Use player's random seed. - // get circular gaussian spread - //x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); - //y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); - //z = x * x + y * y; - // - //Vector vecDir = vecDirShooting + - // x * vecSpread.x * vecRight + - // y * vecSpread.y * vecUp; - - Vector vecDir; - // : 0000973 - // added inner cone for half of the shots - if (isShotgun) - { - vecSpread = kSGInnerSpread; - Vector vecMinSpread; - - if ((iShot > (cShots/3)) && (iShot < (cShots*2/3))) - { - vecSpread = kSGMidSpread; - vecMinSpread = kSGInnerSpread; - vecDir = UTIL_GetRandomSpreadDirFrom(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread, vecMinSpread); - } - else - if ((iShot > (cShots*2/3))) - { - vecMinSpread = kSGMidSpread; - vecDir = UTIL_GetRandomSpreadDirFrom(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread, vecMinSpread); - } - else - { - vecSpread = kSGInnerSpread; - vecDir = UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread); - } - } - // : - else - { - vecDir = UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread); - } - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - //UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - bool theProtected = false; - AvHSUServerTraceBullets(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), tr, theProtected); - CBaseEntity* theEntityHit = CBaseEntity::Instance(tr.pHit); - - if(theProtected) - { - // : experiment - EMIT_SOUND(theEntityHit->edict(), CHAN_AUTO, kUmbraBlockedSound, 1.0f, ATTN_NORM); - // : - } - else - { - - // do damage, paint decals - if (tr.flFraction != 1.0) - { - float theScalar = 1.0f; - if(GetGameRules()->CanEntityDoDamageTo(thePlayer, theEntityHit, &theScalar)) - { - int theAdjustedDamage = iDamage*theScalar; - - if(theAdjustedDamage) - { - // : 0000973 - // removed shotgun fallof - //if ( isShotgun && !( theEntityHit->pev->iuser3 & AVH_USER3_BREAKABLE) ) - //{ - // float distance=fabs((vecSrc - theEntityHit->pev->origin).Length()); - // if ( distance > BALANCE_VAR(kShotgunDamageRange) ) - // { - // float fallOffDistance=distance-BALANCE_VAR(kShotgunDamageRange); - // float fallOff=max(0.0, 1.0f-(fallOffDistance/(kSGRange/2))); - // theAdjustedDamage*=fallOff; - // } - //} - // : - if ( theAdjustedDamage ) { - theEntityHit->TraceAttack(pevAttacker, theAdjustedDamage, vecDir, &tr, theDamageType | ((theAdjustedDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - } - -// TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); -// DecalGunshot( &tr, iBulletType ); - } - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); - } - } - ApplyMultiDamage(theInflictor, pevAttacker); - - //return Vector( (float)(x * vecSpread.x), (float)(y * vecSpread.y), 0.0f ); - return vecSpread; -} - -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if (BloodColor() == DONT_BLEED) - return; - - if (flDamage == 0) - return; - - if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB /*| DMG_MORTAR*/ ))) - return; - - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - float flNoise; - int cCount; - int i; - -/* - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } -*/ - - if (flDamage < 10) - { - flNoise = 0.1; - cCount = 1; - } - else if (flDamage < 25) - { - flNoise = 0.2; - cCount = 2; - } - else - { - flNoise = 0.3; - cCount = 4; - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr); - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} - -//========================================================= -//========================================================= -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) -{ - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - int i; - - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir; - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); - -/* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( Bloodtr.vecEndPos.x ); - WRITE_COORD( Bloodtr.vecEndPos.y ); - WRITE_COORD( Bloodtr.vecEndPos.z ); - MESSAGE_END(); -*/ - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== combat.cpp ======================================================== + + functions dealing with damage infliction & death + +*/ +// +// $Workfile: combat.cpp $ +// $Date: 2002/11/22 23:26:35 $ +// +//------------------------------------------------------------------------------- +// $Log: combat.cpp,v $ +// Revision 1.19 2002/11/22 23:26:35 Flayra +// - Skulks had to aim too high to hit structures, so trying this approach to fixing the melee in vents bug +// +// Revision 1.18 2002/11/22 21:09:50 Flayra +// - Explosion fixes (oops!) +// - Fix melee when in vents (I think) +// +// Revision 1.17 2002/11/13 01:49:33 Flayra +// - Proper death message logging for Psychostats +// +// Revision 1.16 2002/11/12 02:18:08 Flayra +// - Pass on inflictor properly for standard logging +// +// Revision 1.15 2002/11/06 01:36:16 Flayra +// - Allow scalar to apply to damage from gamerules (used for friendly fire) +// +// Revision 1.14 2002/10/03 18:26:36 Flayra +// - Removed all pushback and forces when doing damage to players +// +// Revision 1.13 2002/08/16 02:25:21 Flayra +// - New damage types +// +// Revision 1.12 2002/07/10 14:36:13 Flayra +// - Removed major cause of lag: redundant server-side decals. Also removed duplicate texture sound. +// +// Revision 1.11 2002/07/08 16:40:05 Flayra +// - Fix bug where melee attacks couldn't aim up or down, reworked bullet firing to add random spread (bug #236) +// +//=============================================================================== + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "soundent.h" +#include "decals.h" +#include "animation.h" +#include "weapons.h" +#include "func_break.h" +#include "../mod/AvHPlayer.h" +#include "../mod/AvHGamerules.h" +#include "../mod/AvHServerUtil.h" +#include "../mod/AvHAlienWeaponConstants.h" +#include "../mod/AvHTurret.h" +#include "../mod/AvHServerVariables.h" +//#include "../mod/AvHMovementUtil.h" + +extern DLL_GLOBAL Vector g_vecAttackDir; +extern DLL_GLOBAL int g_iSkillLevel; + +extern Vector VecBModelOrigin( entvars_t* pevBModel ); +extern entvars_t *g_pevLastInflictor; + +#define GERMAN_GIB_COUNT 4 +#define HUMAN_GIB_COUNT 6 +#define ALIEN_GIB_COUNT 4 + + +// HACKHACK -- The gib velocity equations don't work +void CGib :: LimitVelocity( void ) +{ + float length = pev->velocity.Length(); + + // ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it + // in 3 separate places again, I'll just limit it here. + if ( length > 1500.0 ) + pev->velocity = pev->velocity.Normalize() * 1500; // This should really be sv_maxvelocity * 0.75 or something +} + + +void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ) +{ + int i; + + if ( g_Language == LANGUAGE_GERMAN ) + { + // no sticky gibs in germany right now! + return; + } + + for ( i = 0 ; i < cGibs ; i++ ) + { + CGib *pGib = GetClassPtr( (CGib *)NULL ); + + pGib->Spawn( "models/stickygib.mdl" ); + pGib->pev->body = RANDOM_LONG(0,2); + + if ( pevVictim ) + { + pGib->pev->origin.x = vecOrigin.x + RANDOM_FLOAT( -3, 3 ); + pGib->pev->origin.y = vecOrigin.y + RANDOM_FLOAT( -3, 3 ); + pGib->pev->origin.z = vecOrigin.z + RANDOM_FLOAT( -3, 3 ); + + /* + pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); + pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); + pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ); + */ + + // make the gib fly away from the attack vector + pGib->pev->velocity = g_vecAttackDir * -1; + + // mix in some noise + pGib->pev->velocity.x += RANDOM_FLOAT ( -0.15, 0.15 ); + pGib->pev->velocity.y += RANDOM_FLOAT ( -0.15, 0.15 ); + pGib->pev->velocity.z += RANDOM_FLOAT ( -0.15, 0.15 ); + + pGib->pev->velocity = pGib->pev->velocity * 900; + + pGib->pev->avelocity.x = RANDOM_FLOAT ( 250, 400 ); + pGib->pev->avelocity.y = RANDOM_FLOAT ( 250, 400 ); + + // copy owner's blood color + pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); + + if ( pevVictim->health > -50) + { + pGib->pev->velocity = pGib->pev->velocity * 0.7; + } + else if ( pevVictim->health > -200) + { + pGib->pev->velocity = pGib->pev->velocity * 2; + } + else + { + pGib->pev->velocity = pGib->pev->velocity * 4; + } + + + pGib->pev->movetype = MOVETYPE_TOSS; + pGib->pev->solid = SOLID_BBOX; + UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) ); + pGib->SetTouch ( &CGib::StickyGibTouch ); + pGib->SetThink (NULL); + } + pGib->LimitVelocity(); + } +} + +void CGib :: SpawnHeadGib( entvars_t *pevVictim ) +{ + CGib *pGib = GetClassPtr( (CGib *)NULL ); + + if ( g_Language == LANGUAGE_GERMAN ) + { + pGib->Spawn( "models/germangibs.mdl" );// throw one head + pGib->pev->body = 0; + } + else + { + pGib->Spawn( "models/hgibs.mdl" );// throw one head + pGib->pev->body = 0; + } + + if ( pevVictim ) + { + pGib->pev->origin = pevVictim->origin + pevVictim->view_ofs; + + edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict() ); + + if ( RANDOM_LONG ( 0, 100 ) <= 5 && pentPlayer ) + { + // 5% chance head will be thrown at player's face. + entvars_t *pevPlayer; + + pevPlayer = VARS( pentPlayer ); + pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300; + pGib->pev->velocity.z += 100; + } + else + { + pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); + } + + + pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); + pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); + + // copy owner's blood color + pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); + + if ( pevVictim->health > -50) + { + pGib->pev->velocity = pGib->pev->velocity * 0.7; + } + else if ( pevVictim->health > -200) + { + pGib->pev->velocity = pGib->pev->velocity * 2; + } + else + { + pGib->pev->velocity = pGib->pev->velocity * 4; + } + } + pGib->LimitVelocity(); +} + +void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) +{ + int cSplat; + + for ( cSplat = 0 ; cSplat < cGibs ; cSplat++ ) + { + CGib *pGib = GetClassPtr( (CGib *)NULL ); + + if ( g_Language == LANGUAGE_GERMAN ) + { + pGib->Spawn( "models/germangibs.mdl" ); + pGib->pev->body = RANDOM_LONG(0,GERMAN_GIB_COUNT-1); + } + else + { + if ( human ) + { + // human pieces + pGib->Spawn( "models/hgibs.mdl" ); + pGib->pev->body = RANDOM_LONG(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib) + } + else + { + // aliens + pGib->Spawn( "models/agibs.mdl" ); + pGib->pev->body = RANDOM_LONG(0,ALIEN_GIB_COUNT-1); + } + } + + if ( pevVictim ) + { + // spawn the gib somewhere in the monster's bounding volume + pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); + pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); + pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ) + 1; // absmin.z is in the floor because the engine subtracts 1 to enlarge the box + + // make the gib fly away from the attack vector + pGib->pev->velocity = g_vecAttackDir * -1; + + // mix in some noise + pGib->pev->velocity.x += RANDOM_FLOAT ( -0.25, 0.25 ); + pGib->pev->velocity.y += RANDOM_FLOAT ( -0.25, 0.25 ); + pGib->pev->velocity.z += RANDOM_FLOAT ( -0.25, 0.25 ); + + pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT ( 300, 400 ); + + pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); + pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); + + // copy owner's blood color + pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); + + if ( pevVictim->health > -50) + { + pGib->pev->velocity = pGib->pev->velocity * 0.7; + } + else if ( pevVictim->health > -200) + { + pGib->pev->velocity = pGib->pev->velocity * 2; + } + else + { + pGib->pev->velocity = pGib->pev->velocity * 4; + } + + pGib->pev->solid = SOLID_BBOX; + UTIL_SetSize ( pGib->pev, Vector( 0 , 0 , 0 ), Vector ( 0, 0, 0 ) ); + } + pGib->LimitVelocity(); + } +} + + +BOOL CBaseMonster :: HasHumanGibs( void ) +{ + int myClass = Classify(); + + if ( myClass == CLASS_HUMAN_MILITARY || + myClass == CLASS_PLAYER_ALLY || + myClass == CLASS_HUMAN_PASSIVE || + myClass == CLASS_PLAYER ) + + return TRUE; + + return FALSE; +} + + +BOOL CBaseMonster :: HasAlienGibs( void ) +{ + int myClass = Classify(); + + if ( myClass == CLASS_ALIEN_MILITARY || + myClass == CLASS_ALIEN_MONSTER || + myClass == CLASS_ALIEN_PASSIVE || + myClass == CLASS_INSECT || + myClass == CLASS_ALIEN_PREDATOR || + myClass == CLASS_ALIEN_PREY ) + + return TRUE; + + return FALSE; +} + + +void CBaseMonster::FadeMonster( void ) +{ + StopAnimation(); + pev->velocity = g_vecZero; + pev->movetype = MOVETYPE_NONE; + pev->avelocity = g_vecZero; + pev->animtime = gpGlobals->time; + pev->effects |= EF_NOINTERP; + SUB_StartFadeOut(); +} + +//========================================================= +// GibMonster - create some gore and get rid of a monster's +// model. +//========================================================= +void CBaseMonster :: GibMonster( void ) +{ + TraceResult tr; + BOOL gibbed = FALSE; + + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM); + + // only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs + if ( HasHumanGibs() ) + { + if ( ns_cvar_float(violence_hgibs) != 0 ) // Only the player will ever get here + { + CGib::SpawnHeadGib( pev ); + CGib::SpawnRandomGibs( pev, 4, 1 ); // throw some human gibs. + } + gibbed = TRUE; + } + else if ( HasAlienGibs() ) + { + if ( ns_cvar_float(violence_hgibs) != 0 ) // Should never get here, but someone might call it directly + { + CGib::SpawnRandomGibs( pev, 4, 0 ); // Throw alien gibs + } + gibbed = TRUE; + } + + if ( !IsPlayer() ) + { + if ( gibbed ) + { + // don't remove players! + SetThink ( &CBaseMonster::SUB_Remove ); + pev->nextthink = gpGlobals->time; + } + else + { + FadeMonster(); + } + } +} + +//========================================================= +// GetDeathActivity - determines the best type of death +// anim to play. +//========================================================= +Activity CBaseMonster :: GetDeathActivity ( void ) +{ + Activity deathActivity; + BOOL fTriedDirection; + float flDot; + TraceResult tr; + Vector vecSrc; + + if ( pev->deadflag != DEAD_NO ) + { + // don't run this while dying. + return m_IdealActivity; + } + + vecSrc = Center(); + + fTriedDirection = FALSE; + deathActivity = ACT_DIESIMPLE;// in case we can't find any special deaths to do. + + UTIL_MakeVectors ( pev->angles ); + flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); + + switch ( m_LastHitGroup ) + { + // try to pick a region-specific death. + case HITGROUP_HEAD: + deathActivity = ACT_DIE_HEADSHOT; + break; + + case HITGROUP_STOMACH: + deathActivity = ACT_DIE_GUTSHOT; + break; + + case HITGROUP_GENERIC: + // try to pick a death based on attack direction + fTriedDirection = TRUE; + + if ( flDot > 0.3 ) + { + deathActivity = ACT_DIEFORWARD; + } + else if ( flDot <= -0.3 ) + { + deathActivity = ACT_DIEBACKWARD; + } + break; + + default: + // try to pick a death based on attack direction + fTriedDirection = TRUE; + + if ( flDot > 0.3 ) + { + deathActivity = ACT_DIEFORWARD; + } + else if ( flDot <= -0.3 ) + { + deathActivity = ACT_DIEBACKWARD; + } + break; + } + + + // can we perform the prescribed death? + if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) + { + // no! did we fail to perform a directional death? + if ( fTriedDirection ) + { + // if yes, we're out of options. Go simple. + deathActivity = ACT_DIESIMPLE; + } + else + { + // cannot perform the ideal region-specific death, so try a direction. + if ( flDot > 0.3 ) + { + deathActivity = ACT_DIEFORWARD; + } + else if ( flDot <= -0.3 ) + { + deathActivity = ACT_DIEBACKWARD; + } + } + } + + if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) + { + // if we're still invalid, simple is our only option. + deathActivity = ACT_DIESIMPLE; + } + + if ( deathActivity == ACT_DIEFORWARD ) + { + // make sure there's room to fall forward + UTIL_TraceHull ( vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); + + if ( tr.flFraction != 1.0 ) + { + deathActivity = ACT_DIESIMPLE; + } + } + + if ( deathActivity == ACT_DIEBACKWARD ) + { + // make sure there's room to fall backward + UTIL_TraceHull ( vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); + + if ( tr.flFraction != 1.0 ) + { + deathActivity = ACT_DIESIMPLE; + } + } + + return deathActivity; +} + +//========================================================= +// GetSmallFlinchActivity - determines the best type of flinch +// anim to play. +//========================================================= +Activity CBaseMonster :: GetSmallFlinchActivity ( void ) +{ + Activity flinchActivity; + BOOL fTriedDirection; + float flDot; + + fTriedDirection = FALSE; + UTIL_MakeVectors ( pev->angles ); + flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); + + switch ( m_LastHitGroup ) + { + // pick a region-specific flinch + case HITGROUP_HEAD: + flinchActivity = ACT_FLINCH_HEAD; + break; + case HITGROUP_STOMACH: + flinchActivity = ACT_FLINCH_STOMACH; + break; + case HITGROUP_LEFTARM: + flinchActivity = ACT_FLINCH_LEFTARM; + break; + case HITGROUP_RIGHTARM: + flinchActivity = ACT_FLINCH_RIGHTARM; + break; + case HITGROUP_LEFTLEG: + flinchActivity = ACT_FLINCH_LEFTLEG; + break; + case HITGROUP_RIGHTLEG: + flinchActivity = ACT_FLINCH_RIGHTLEG; + break; + case HITGROUP_GENERIC: + default: + // just get a generic flinch. + flinchActivity = ACT_SMALL_FLINCH; + break; + } + + + // do we have a sequence for the ideal activity? + if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) + { + flinchActivity = ACT_SMALL_FLINCH; + } + + return flinchActivity; +} + + +void CBaseMonster::BecomeDead( void ) +{ + pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. + + // give the corpse half of the monster's original maximum health. + pev->health = pev->max_health / 2; + pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. + + // make the corpse fly away from the attack vector + pev->movetype = MOVETYPE_TOSS; + //pev->flags &= ~FL_ONGROUND; + //pev->origin.z += 2; + //pev->velocity = g_vecAttackDir * -1; + //pev->velocity = pev->velocity * RANDOM_FLOAT( 300, 400 ); +} + + +BOOL CBaseMonster::ShouldGibMonster( int iGib ) +{ + if ( ( iGib == GIB_NORMAL && pev->health < GIB_HEALTH_VALUE ) || ( iGib == GIB_ALWAYS ) ) + return TRUE; + + return FALSE; +} + + +void CBaseMonster::CallGibMonster( void ) +{ + BOOL fade = FALSE; + + if ( HasHumanGibs() ) + { + if ( ns_cvar_float(violence_hgibs) == 0 ) + fade = TRUE; + } + else if ( HasAlienGibs() ) + { + if ( ns_cvar_float(violence_agibs) == 0 ) + fade = TRUE; + } + + pev->takedamage = DAMAGE_NO; + pev->solid = SOLID_NOT;// do something with the body. while monster blows up + + if ( fade ) + { + FadeMonster(); + } + else + { + pev->effects = EF_NODRAW; // make the model invisible. + GibMonster(); + } + + pev->deadflag = DEAD_DEAD; + FCheckAITrigger(); + + // don't let the status bar glitch for players.with <0 health. + if (pev->health < -99) + { + pev->health = 0; + } + + if ( ShouldFadeOnDeath() && !fade ) + UTIL_Remove(this); +} + + +/* +============ +Killed +============ +*/ +void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) +{ + unsigned int cCount = 0; + BOOL fDone = FALSE; + + CBaseEntity* theBaseEntity = CBaseEntity::Instance(pevAttacker->owner); + if(!theBaseEntity) + { + theBaseEntity = CBaseEntity::Instance(pevAttacker); + } + ASSERT(theBaseEntity); + theBaseEntity->AwardKill(this->pev); + + if ( HasMemory( bits_MEMORY_KILLED ) ) + { + if ( ShouldGibMonster( iGib ) ) + CallGibMonster(); + return; + } + + Remember( bits_MEMORY_KILLED ); + + // clear the deceased's sound channels.(may have been firing or reloading when killed) + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM); + m_IdealMonsterState = MONSTERSTATE_DEAD; + // Make sure this condition is fired too (TakeDamage breaks out before this happens on death) + SetConditions( bits_COND_LIGHT_DAMAGE ); + + // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. + CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); + if ( pOwner ) + { + pOwner->DeathNotice( pev ); + } + + if ( ShouldGibMonster( iGib ) ) + { + CallGibMonster(); + return; + } + else if ( pev->flags & FL_MONSTER ) + { + SetTouch( NULL ); + BecomeDead(); + } + + // don't let the status bar glitch for players.with <0 health. + if (pev->health < -99) + { + pev->health = 0; + } + + //pev->enemy = ENT( pevAttacker );//why? (sjb) + + m_IdealMonsterState = MONSTERSTATE_DEAD; + +} + +// +// fade out - slowly fades a entity out, then removes it. +// +// DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER! +// SET A FUTURE THINK AND A RENDERMODE!! +void CBaseEntity :: SUB_StartFadeOut ( void ) +{ + if (pev->rendermode == kRenderNormal) + { + pev->renderamt = 255; + pev->rendermode = kRenderTransTexture; + } + + pev->solid = SOLID_NOT; + pev->avelocity = g_vecZero; + + pev->nextthink = gpGlobals->time + 0.1; + SetThink ( &CBaseEntity::SUB_FadeOut ); +} + +void CBaseEntity :: SUB_FadeOut ( void ) +{ + if ( pev->renderamt > 7 ) + { + pev->renderamt -= 7; + pev->nextthink = gpGlobals->time + 0.1; + } + else + { + pev->renderamt = 0; + pev->nextthink = gpGlobals->time + 0.2; + SetThink ( &CBaseEntity::SUB_Remove ); + } +} + +//========================================================= +// WaitTillLand - in order to emit their meaty scent from +// the proper location, gibs should wait until they stop +// bouncing to emit their scent. That's what this function +// does. +//========================================================= +void CGib :: WaitTillLand ( void ) +{ + if (!IsInWorld()) + { + UTIL_Remove( this ); + return; + } + + if ( pev->velocity == g_vecZero ) + { + SetThink (&CGib::SUB_StartFadeOut); + pev->nextthink = gpGlobals->time + m_lifeTime; + + // If you bleed, you stink! + if ( m_bloodColor != DONT_BLEED ) + { + // ok, start stinkin! + CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 ); + } + } + else + { + // wait and check again in another half second. + pev->nextthink = gpGlobals->time + 0.5; + } +} + +// +// Gib bounces on the ground or wall, sponges some blood down, too! +// +void CGib :: BounceGibTouch ( CBaseEntity *pOther ) +{ + Vector vecSpot; + TraceResult tr; + + //if ( RANDOM_LONG(0,1) ) + // return;// don't bleed everytime + + if (pev->flags & FL_ONGROUND) + { + pev->velocity = pev->velocity * 0.9; + pev->angles.x = 0; + pev->angles.z = 0; + pev->avelocity.x = 0; + pev->avelocity.z = 0; + } + else + { + if ( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) + { + vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. + UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); + + UTIL_BloodDecalTrace( &tr, m_bloodColor ); + + m_cBloodDecals--; + } + + if ( m_material != matNone && RANDOM_LONG(0,2) == 0 ) + { + float volume; + float zvel = fabs(pev->velocity.z); + + volume = 0.8 * min(1.0, ((float)zvel) / 450.0); + + CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); + } + } +} + +// +// Sticky gib puts blood on the wall and stays put. +// +void CGib :: StickyGibTouch ( CBaseEntity *pOther ) +{ + Vector vecSpot; + TraceResult tr; + + SetThink ( &CBaseEntity::SUB_Remove ); + pev->nextthink = gpGlobals->time + 10; + + if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) + { + pev->nextthink = gpGlobals->time; + return; + } + + UTIL_TraceLine ( pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), & tr); + + UTIL_BloodDecalTrace( &tr, m_bloodColor ); + + pev->velocity = tr.vecPlaneNormal * -1; + pev->angles = UTIL_VecToAngles ( pev->velocity ); + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + pev->movetype = MOVETYPE_NONE; +} + +// +// Throw a chunk +// +void CGib :: Spawn( const char *szGibModel ) +{ + pev->movetype = MOVETYPE_BOUNCE; + pev->friction = 0.55; // deading the bounce a bit + + // sometimes an entity inherits the edict from a former piece of glass, + // and will spawn using the same render FX or rendermode! bad! + pev->renderamt = 255; + pev->rendermode = kRenderNormal; + pev->renderfx = kRenderFxNone; + pev->solid = SOLID_SLIDEBOX;/// hopefully this will fix the VELOCITY TOO LOW crap + pev->classname = MAKE_STRING("gib"); + + SET_MODEL(ENT(pev), szGibModel); + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + + pev->nextthink = gpGlobals->time + 4; + m_lifeTime = 25; + SetThink ( &CGib::WaitTillLand ); + SetTouch ( &CGib::BounceGibTouch ); + + m_material = matNone; + m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain). +} + +// take health +int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) +{ + if (!pev->takedamage) + return 0; + + // clear out any damage types we healed. + // UNDONE: generic health should not heal any + // UNDONE: time-based damage + + m_bitsDamageType &= ~(bitsDamageType & ~DMG_TIMEBASED); + + return CBaseEntity::TakeHealth(flHealth, bitsDamageType); +} + +/* +============ +TakeDamage + +The damage is coming from inflictor, but get mad at attacker +This should be the only function that ever reduces health. +bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK + +Time-based damage: only occurs while the monster is within the trigger_hurt. +When a monster is poisoned via an arrow etc it takes all the poison damage at once. + + + +GLOBALS ASSUMED SET: g_iSkillLevel +============ +*/ +int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + float flTake; + Vector vecDir; + + if (!pev->takedamage) + return 0; + + if ( !IsAlive() ) + { + return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); + } + + if ( pev->deadflag == DEAD_NO ) + { + // no pain sound during death animation. + PainSound();// "Ouch!" + } + + //!!!LATER - make armor consideration here! + flTake = flDamage; + + // set damage type sustained + m_bitsDamageType |= bitsDamageType; + + // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). + vecDir = Vector( 0, 0, 0 ); + if (!FNullEnt( pevInflictor )) + { + CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); + if (pInflictor) + { + vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); + vecDir = g_vecAttackDir = vecDir.Normalize(); + } + } + + // add to the damage total for clients, which will be sent as a single + // message at the end of the frame + // todo: remove after combining shotgun blasts? + if ( IsPlayer() ) + { + if ( pevInflictor ) + pev->dmg_inflictor = ENT(pevInflictor); + + pev->dmg_take += flTake; + + // check for godmode or invincibility + if ( pev->flags & FL_GODMODE ) + { + return 0; + } + } + + // HL: if this is a player, move him around! + // NS: Don't move players + if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) && !IsPlayer()) + { + pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); + } + + // do the damage + pev->health -= flTake; + + + // HACKHACK Don't kill monsters in a script. Let them break their scripts first + if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + { + SetConditions( bits_COND_LIGHT_DAMAGE ); + return 0; + } + + if ( (int)(pev->health) <= 0 ) + { + g_pevLastInflictor = pevInflictor; + +// Removed gibbing, as death animations weren't playing with gibs off +// if ( bitsDamageType & DMG_ALWAYSGIB ) +// { +// Killed( pevAttacker, GIB_ALWAYS ); +// } +// else if ( bitsDamageType & DMG_NEVERGIB ) +// { + Killed( pevAttacker, GIB_NEVER ); +// } +// else +// { +// Killed( pevAttacker, GIB_NORMAL ); +// } + + // Trigger log message if needed +// AvHPlayer* theDeadPlayer = dynamic_cast(this); +// AvHPlayer* theAttackingPlayer = dynamic_cast(CBaseEntity::Instance(ENT(pevAttacker))); +// const char* inWeaponName = STRING(pevInflictor->classname); +// if(theDeadPlayer && theAttackingPlayer && inWeaponName) +// { +// theDeadPlayer->LogPlayerKilledPlayer(theAttackingPlayer, inWeaponName); +// } + + g_pevLastInflictor = NULL; + + return 0; + } + + // react to the damage (get mad) + if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) + { + if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) + {// only if the attack was a monster or client! + + // enemy's last known position is somewhere down the vector that the attack came from. + if (pevInflictor) + { + if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) + { + m_vecEnemyLKP = pevInflictor->origin; + } + } + else + { + m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); + } + + MakeIdealYaw( m_vecEnemyLKP ); + + // add pain to the conditions + // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and + // heavy damage per monster class? + if ( flDamage > 0 ) + { + SetConditions(bits_COND_LIGHT_DAMAGE); + } + + if ( flDamage >= 20 ) + { + SetConditions(bits_COND_HEAVY_DAMAGE); + } + } + } + + return 1; +} + +//========================================================= +// DeadTakeDamage - takedamage function called when a monster's +// corpse is damaged. +//========================================================= +int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + Vector vecDir; + + // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). + vecDir = Vector( 0, 0, 0 ); + if (!FNullEnt( pevInflictor )) + { + CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); + if (pInflictor) + { + vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); + vecDir = g_vecAttackDir = vecDir.Normalize(); + } + } + +#if 0// turn this back on when the bounding box issues are resolved. + + pev->flags &= ~FL_ONGROUND; + pev->origin.z += 1; + + // let the damage scoot the corpse around a bit. + if ( !FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER) ) + { + pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); + } + +#endif + + // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. + if ( bitsDamageType & DMG_GIB_CORPSE ) + { + if ( pev->health <= flDamage ) + { + pev->health = -50; + Killed( pevAttacker, GIB_ALWAYS ); + return 0; + } + // Accumulate corpse gibbing damage, so you can gib with multiple hits + pev->health -= flDamage * 0.1; + } + + return 1; +} + + +float CBaseMonster :: DamageForce( float damage ) +{ + float force = damage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; + + if ( force > 1000.0) + { + force = 1000.0; + } + + return force; +} + +// +// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range. +// +// only damage ents that can clearly be seen by the explosion! + + +void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float inDamage, float flRadius, int iClassIgnore, int bitsDamageType ) +{ + CBaseEntity *pEntity = NULL; + TraceResult tr; + float flAdjustedDamage, falloff; + Vector vecSpot; + + if ( flRadius ) + falloff = inDamage / flRadius; + else + falloff = 1.0; + + int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); + + vecSrc.z += 1;// in case grenade is lying on the ground + + if ( !pevAttacker ) + pevAttacker = pevInflictor; + + // iterate on all entities in the vicinity. + while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) + { + // NOTE: Should this be inflictor or attacker? + CBaseEntity* theInflictingEntity = CBaseEntity::Instance(pevInflictor); + CBaseEntity* theAttackingEntity = CBaseEntity::Instance(pevAttacker); + float theScalar = 1.0f; + bool aCanDamage=GetGameRules()->CanEntityDoDamageTo(theAttackingEntity, pEntity, &theScalar) || theInflictingEntity->pev->classname == MAKE_STRING(kwsDeployedMine);; + bool iCanDamage=GetGameRules()->CanEntityDoDamageTo(theInflictingEntity, pEntity, &theScalar); + + if(pEntity && ( aCanDamage && iCanDamage )) + { + // Multiply damage by scalar for tourny mode, etc. + float theDamage = inDamage*theScalar; + + if ( pEntity->pev->takedamage != DAMAGE_NO ) + { + + // UNDONE: this should check a damage mask, not an ignore + if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) + {// houndeyes don't hurt other houndeyes with their attack + continue; + } + + // blast's don't tavel into or out of water + if (bInWater && pEntity->pev->waterlevel == 0) + continue; + if (!bInWater && pEntity->pev->waterlevel == 3) + continue; + + vecSpot = pEntity->BodyTarget( vecSrc ); + + // Clear pevInflictor's owner temporarily so it can apply damage to it + edict_t* theInflictorOwner = pevInflictor->owner; + pevInflictor->owner = NULL; + + UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); + + // Restore owner + pevInflictor->owner = theInflictorOwner; + + if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) + {// the explosion can 'see' this entity, so hurt them! + if (tr.fStartSolid) + { + // if we're stuck inside them, fixup the position and distance + tr.vecEndPos = vecSrc; + tr.flFraction = 0.0; + } + + // decrease damage for an ent that's farther from the bomb. + flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; + flAdjustedDamage = theDamage - flAdjustedDamage; + + if ( flAdjustedDamage > 0 ) + { + pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); + } + } + } + } + } +} + + +void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) +{ + ::RadiusDamage( pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); +} + + +void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) +{ + ::RadiusDamage( vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); +} + +int CBaseMonster::GetHull() const +{ + return head_hull; +} + +//========================================================= +// CheckTraceHullAttack - expects a length to trace, amount +// of damage to do, and damage type. Returns a pointer to +// the damaged entity in case the monster wishes to do +// other stuff to the victim (punchangle, etc) +// +// Used for many contact-range melee attacks. Bites, claws, etc. +//========================================================= +CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ) +{ + Vector vecStart = pev->origin; + + if(this->IsPlayer()) + { + // Melee attacks always originate where the view is + vecStart.x += this->pev->view_ofs.x; + vecStart.y += this->pev->view_ofs.y; + vecStart.z += this->pev->view_ofs.z; + } + + if (IsPlayer()) + UTIL_MakeVectors( pev->v_angle ); + else + UTIL_MakeAimVectors( pev->angles ); + + //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecStart); + + // First do a tracehull. If that misses, try three tracelines (dead-on center, then randomly left and randomly right). + bool theHitTarget = false; + for(int i = 0; (i < 4) && !theHitTarget; i++) + { + const float kAmount = 0.4f; + float theXAmount = 0.0f; + + if(i == 2) + { + theXAmount = kAmount; + } + else if(i == 3) + { + theXAmount = -kAmount; + } + + Vector vecDir = gpGlobals->v_forward + theXAmount*gpGlobals->v_right; + vecDir.Normalize(); + + Vector vecEnd = vecStart + (vecDir * flDist ); + TraceResult tr; + + if(i == 0) + { + int theOurHull = this->GetHull(); + int theHull = AvHSUGetValveHull(theOurHull); + UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, theHull, this->edict(), &tr); + } + else + { + //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecEnd); + + UTIL_TraceLine(vecStart, vecEnd, dont_ignore_monsters, dont_ignore_glass, ENT(this->pev), &tr); + } + + if ( tr.pHit ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + + if ( ioDamage > 0 ) + { + float theScalar = 1.0f; + if(GetGameRules()->CanEntityDoDamageTo(this, pEntity, &theScalar)) + { + theHitTarget = true; + + // Multiply damage by scalar for tourny mode, etc. + ioDamage *= theScalar; + + entvars_t* theInflictor = this->pev; + AvHPlayer* thePlayer = dynamic_cast(this); + if(thePlayer) + { + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(thePlayer->m_pActiveItem); + if(theBasePlayerWeapon) + { + theInflictor = theBasePlayerWeapon->pev; + } + } + + pEntity->TakeDamage(theInflictor, pev, ioDamage, iDmgType ); + + // Spawn blood + if(ioDamage > 0.0f) + { + // a little surface blood. + SpawnBlood(tr.vecEndPos, pEntity->BloodColor(), ioDamage); + + // on the wall/floor (don't play because blood decal is green) + //TraceBleed(ioDamage, vecDir, &tr, iDmgType); + } + + return pEntity; + } + } + } + } + + return NULL; +} + + +//========================================================= +// FInViewCone - returns true is the passed ent is in +// the caller's forward view cone. The dot product is performed +// in 2d, making the view cone infinitely tall. +//========================================================= +BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) +{ + Vector2D vec2LOS; + float flDot; + + UTIL_MakeVectors ( pev->angles ); + + vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D(); + vec2LOS = vec2LOS.Normalize(); + + flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + + if ( flDot > m_flFieldOfView ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +//========================================================= +// FInViewCone - returns true is the passed vector is in +// the caller's forward view cone. The dot product is performed +// in 2d, making the view cone infinitely tall. +//========================================================= +BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) +{ + Vector2D vec2LOS; + float flDot; + + UTIL_MakeVectors ( pev->angles ); + + vec2LOS = ( *pOrigin - pev->origin ).Make2D(); + vec2LOS = vec2LOS.Normalize(); + + flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + + if ( flDot > m_flFieldOfView ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +//========================================================= +// FVisible - returns true if a line can be traced from +// the caller's eyes to the target +//========================================================= +BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) +{ + TraceResult tr; + Vector vecLookerOrigin; + Vector vecTargetOrigin; + + if (FBitSet( pEntity->pev->flags, FL_NOTARGET )) + return FALSE; + + // don't look through water //edit by Elven Thief to prevent bug #728 + // if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) + // || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) + // return FALSE; + + vecLookerOrigin = this->EyePosition();//look through the caller's 'eyes' + vecTargetOrigin = pEntity->EyePosition(); + + return AvHCheckLineOfSight(vecLookerOrigin, vecTargetOrigin, ENT(pev)); + +} + +//========================================================= +// FVisible - returns true if a line can be traced from +// the caller's eyes to the target vector +//========================================================= +BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) +{ + TraceResult tr; + Vector vecLookerOrigin; + + vecLookerOrigin = EyePosition();//look through the caller's 'eyes' + + return AvHCheckLineOfSight(vecLookerOrigin, vecOrigin, ENT(pev)); + +} + +/* +================ +TraceAttack +================ +*/ +void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + Vector vecOrigin = ptr->vecEndPos - vecDir * 4; + + if ( pev->takedamage ) + { + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + + int blood = BloodColor(); + + if ( blood != DONT_BLEED ) + { + SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. + TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); + } + } +} + + +/* +//========================================================= +// TraceAttack +//========================================================= +void CBaseMonster::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + Vector vecOrigin = ptr->vecEndPos - vecDir * 4; + + ALERT ( at_console, "%d\n", ptr->iHitgroup ); + + + if ( pev->takedamage ) + { + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + + int blood = BloodColor(); + + if ( blood != DONT_BLEED ) + { + SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. + } + } +} +*/ + +//========================================================= +// TraceAttack +//========================================================= +void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if ( pev->takedamage ) + { + m_LastHitGroup = ptr->iHitgroup; + + switch ( ptr->iHitgroup ) + { + case HITGROUP_GENERIC: + break; + case HITGROUP_HEAD: + flDamage *= gSkillData.monHead; + break; + case HITGROUP_CHEST: + flDamage *= gSkillData.monChest; + break; + case HITGROUP_STOMACH: + flDamage *= gSkillData.monStomach; + break; + case HITGROUP_LEFTARM: + case HITGROUP_RIGHTARM: + flDamage *= gSkillData.monArm; + break; + case HITGROUP_LEFTLEG: + case HITGROUP_RIGHTLEG: + flDamage *= gSkillData.monLeg; + break; + default: + break; + } + + SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. + TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + } +} + +/* +================ +FireBullets + +Go to the trouble of combining multiple pellets into a single damage call. + +This version is used by Monsters. +================ +*/ +void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int inDamageType) +{ + static int tracerCount; + int tracer; + TraceResult tr; + Vector vecRight = gpGlobals->v_right; + Vector vecUp = gpGlobals->v_up; + + if ( pevAttacker == NULL ) + pevAttacker = pev; // the default attacker is ourselves + + ClearMultiDamage(); + gMultiDamage.type = inDamageType; + + for (ULONG iShot = 1; iShot <= cShots; iShot++) + { + // get circular gaussian spread + float x, y, z; + do { + x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); + y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); + z = x*x+y*y; + } while (z > 1); + + Vector vecDir = vecDirShooting + + x * vecSpread.x * vecRight + + y * vecSpread.y * vecUp; + Vector vecEnd; + + vecEnd = vecSrc + vecDir * flDistance; + //UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); + bool theProtected = false; + AvHSUServerTraceBullets(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), tr, theProtected); + CBaseEntity* theEntityHit = CBaseEntity::Instance(tr.pHit); + + if(theProtected && theEntityHit) + { + // : experiment + EMIT_SOUND(theEntityHit->edict(), CHAN_AUTO, kUmbraBlockedSound, 1.0f, ATTN_NORM); + // : + } + else + { + tracer = 0; + if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0) + { + Vector vecTracerSrc; + + if ( IsPlayer() ) + {// adjust tracer position for player + vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16; + } + else + { + vecTracerSrc = vecSrc; + } + + if ( iTracerFreq != 1 ) // guns that always trace also always decal + tracer = 1; + switch( iBulletType ) + { + case BULLET_MONSTER_MP5: + case BULLET_MONSTER_9MM: + case BULLET_MONSTER_12MM: + default: + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc ); + WRITE_BYTE( TE_TRACER ); + WRITE_COORD( vecTracerSrc.x ); + WRITE_COORD( vecTracerSrc.y ); + WRITE_COORD( vecTracerSrc.z ); + WRITE_COORD( tr.vecEndPos.x ); + WRITE_COORD( tr.vecEndPos.y ); + WRITE_COORD( tr.vecEndPos.z ); + MESSAGE_END(); + break; + } + } + // do damage, paint decals + if (tr.flFraction != 1.0) + { + float theScalar = 1.0f; + if(theEntityHit && GetGameRules()->CanEntityDoDamageTo(this, theEntityHit, &theScalar)) + { + // Multiply damage by scalar for tourny mode, etc. + iDamage *= theScalar; + + if ( iDamage ) + { + theEntityHit->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); + + TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + DecalGunshot( &tr, iBulletType ); + //DecalGunshot( &tr, 0 ); + } + else switch(iBulletType) + { + default: + case BULLET_MONSTER_9MM: + theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET); + + TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + DecalGunshot( &tr, iBulletType ); + + break; + + case BULLET_MONSTER_MP5: + theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET); + + TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + DecalGunshot( &tr, iBulletType ); + + break; + + case BULLET_MONSTER_12MM: + theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET); + if ( !tracer ) + { + TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + DecalGunshot( &tr, iBulletType ); + } + break; + + case BULLET_NONE: // FIX + theEntityHit->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB); + TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + // only decal glass + if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0) + { + UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); + } + + break; + } + } + } + // make bullet trails + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); + } + } + ApplyMultiDamage(pev, pevAttacker); +} + + +/* +================ +FireBullets + +Go to the trouble of combining multiple pellets into a single damage call. + +This version is used by Players, uses the random seed generator to sync client and server side shots. +================ +*/ +Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) +{ + static int tracerCount; + TraceResult tr; + Vector vecRight = gpGlobals->v_right; + Vector vecUp = gpGlobals->v_up; + entvars_t* theInflictor = this->pev; + //float x, y, z; + + if ( pevAttacker == NULL ) + pevAttacker = pev; // the default attacker is ourselves + + int theDamageType = DMG_BULLET; + bool isShotgun=false; + AvHPlayer* thePlayer = dynamic_cast(this); + if(thePlayer && thePlayer->m_pActiveItem) + { + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(thePlayer->m_pActiveItem); + if(theBasePlayerWeapon) + { + theDamageType = theBasePlayerWeapon->GetDamageType(); + theInflictor = theBasePlayerWeapon->pev; + } + AvHSonicGun* theSonicGun = dynamic_cast(thePlayer->m_pActiveItem); + if ( theSonicGun ) + { + isShotgun=true; + } + } + else + { + AvHTurret* theTurret = dynamic_cast(this); + if(theTurret) + { + theDamageType = theTurret->GetDamageType(); + } + } + + ClearMultiDamage(); + gMultiDamage.type = theDamageType; + + for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) + { + //Use player's random seed. + // get circular gaussian spread + //x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); + //y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); + //z = x * x + y * y; + // + //Vector vecDir = vecDirShooting + + // x * vecSpread.x * vecRight + + // y * vecSpread.y * vecUp; + + Vector vecDir; + // : 0000973 + // added inner cone for half of the shots + if (isShotgun) + { + vecSpread = kSGInnerSpread; + Vector vecMinSpread; + + if ((iShot > (cShots/3)) && (iShot < (cShots*2/3))) + { + vecSpread = kSGMidSpread; + vecMinSpread = kSGInnerSpread; + vecDir = UTIL_GetRandomSpreadDirFrom(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread, vecMinSpread); + } + else + if ((iShot > (cShots*2/3))) + { + vecMinSpread = kSGMidSpread; + vecDir = UTIL_GetRandomSpreadDirFrom(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread, vecMinSpread); + } + else + { + vecSpread = kSGInnerSpread; + vecDir = UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread); + } + } + // : + else + { + vecDir = UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread); + } + Vector vecEnd; + + vecEnd = vecSrc + vecDir * flDistance; + //UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); + bool theProtected = false; + AvHSUServerTraceBullets(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), tr, theProtected); + CBaseEntity* theEntityHit = CBaseEntity::Instance(tr.pHit); + + if(theProtected) + { + // : experiment + EMIT_SOUND(theEntityHit->edict(), CHAN_AUTO, kUmbraBlockedSound, 1.0f, ATTN_NORM); + // : + } + else + { + + // do damage, paint decals + if (tr.flFraction != 1.0) + { + float theScalar = 1.0f; + if(GetGameRules()->CanEntityDoDamageTo(thePlayer, theEntityHit, &theScalar)) + { + int theAdjustedDamage = iDamage*theScalar; + + if(theAdjustedDamage) + { + // : 0000973 + // removed shotgun fallof + //if ( isShotgun && !( theEntityHit->pev->iuser3 & AVH_USER3_BREAKABLE) ) + //{ + // float distance=fabs((vecSrc - theEntityHit->pev->origin).Length()); + // if ( distance > BALANCE_VAR(kShotgunDamageRange) ) + // { + // float fallOffDistance=distance-BALANCE_VAR(kShotgunDamageRange); + // float fallOff=max(0.0, 1.0f-(fallOffDistance/(kSGRange/2))); + // theAdjustedDamage*=fallOff; + // } + //} + // : + if ( theAdjustedDamage ) { + theEntityHit->TraceAttack(pevAttacker, theAdjustedDamage, vecDir, &tr, theDamageType | ((theAdjustedDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); + } + +// TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); +// DecalGunshot( &tr, iBulletType ); + } + } + } + // make bullet trails + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); + } + } + ApplyMultiDamage(theInflictor, pevAttacker); + + //return Vector( (float)(x * vecSpread.x), (float)(y * vecSpread.y), 0.0f ); + return vecSpread; +} + +void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) +{ + if (BloodColor() == DONT_BLEED) + return; + + if (flDamage == 0) + return; + + if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB /*| DMG_MORTAR*/ ))) + return; + + // make blood decal on the wall! + TraceResult Bloodtr; + Vector vecTraceDir; + float flNoise; + int cCount; + int i; + +/* + if ( !IsAlive() ) + { + // dealing with a dead monster. + if ( pev->max_health <= 0 ) + { + // no blood decal for a monster that has already decalled its limit. + return; + } + else + { + pev->max_health--; + } + } +*/ + + if (flDamage < 10) + { + flNoise = 0.1; + cCount = 1; + } + else if (flDamage < 25) + { + flNoise = 0.2; + cCount = 2; + } + else + { + flNoise = 0.3; + cCount = 4; + } + + for ( i = 0 ; i < cCount ; i++ ) + { + vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) + + vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); + vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); + vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); + + UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr); + + if ( Bloodtr.flFraction != 1.0 ) + { + UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); + } + } +} + +//========================================================= +//========================================================= +void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) +{ + // make blood decal on the wall! + TraceResult Bloodtr; + Vector vecTraceDir; + int i; + + if ( !IsAlive() ) + { + // dealing with a dead monster. + if ( pev->max_health <= 0 ) + { + // no blood decal for a monster that has already decalled its limit. + return; + } + else + { + pev->max_health--; + } + } + + for ( i = 0 ; i < cCount ; i++ ) + { + vecTraceDir = vecDir; + + vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); + vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); + vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); + + UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); + +/* + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + WRITE_COORD( ptr->vecEndPos.x ); + WRITE_COORD( ptr->vecEndPos.y ); + WRITE_COORD( ptr->vecEndPos.z ); + + WRITE_COORD( Bloodtr.vecEndPos.x ); + WRITE_COORD( Bloodtr.vecEndPos.y ); + WRITE_COORD( Bloodtr.vecEndPos.z ); + MESSAGE_END(); +*/ + + if ( Bloodtr.flFraction != 1.0 ) + { + UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); + } + } +} diff --git a/main/source/dlls/combat.cpp~ b/main/source/dlls/combat.cpp~ deleted file mode 100644 index dbe811a6..00000000 --- a/main/source/dlls/combat.cpp~ +++ /dev/null @@ -1,1914 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== combat.cpp ======================================================== - - functions dealing with damage infliction & death - -*/ -// -// $Workfile: combat.cpp $ -// $Date: 2002/11/22 23:26:35 $ -// -//------------------------------------------------------------------------------- -// $Log: combat.cpp,v $ -// Revision 1.19 2002/11/22 23:26:35 Flayra -// - Skulks had to aim too high to hit structures, so trying this approach to fixing the melee in vents bug -// -// Revision 1.18 2002/11/22 21:09:50 Flayra -// - Explosion fixes (oops!) -// - Fix melee when in vents (I think) -// -// Revision 1.17 2002/11/13 01:49:33 Flayra -// - Proper death message logging for Psychostats -// -// Revision 1.16 2002/11/12 02:18:08 Flayra -// - Pass on inflictor properly for standard logging -// -// Revision 1.15 2002/11/06 01:36:16 Flayra -// - Allow scalar to apply to damage from gamerules (used for friendly fire) -// -// Revision 1.14 2002/10/03 18:26:36 Flayra -// - Removed all pushback and forces when doing damage to players -// -// Revision 1.13 2002/08/16 02:25:21 Flayra -// - New damage types -// -// Revision 1.12 2002/07/10 14:36:13 Flayra -// - Removed major cause of lag: redundant server-side decals. Also removed duplicate texture sound. -// -// Revision 1.11 2002/07/08 16:40:05 Flayra -// - Fix bug where melee attacks couldn't aim up or down, reworked bullet firing to add random spread (bug #236) -// -//=============================================================================== - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" -#include "decals.h" -#include "animation.h" -#include "weapons.h" -#include "func_break.h" -#include "..mod/AvHPlayer.h" -#include "..mod/AvHGamerules.h" -#include "..mod/AvHServerUtil.h" -#include "..mod/AvHAlienWeaponConstants.h" -#include "..mod/AvHTurret.h" -#include "..mod/AvHServerVariables.h" -//#include "..mod/AvHMovementUtil.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL int g_iSkillLevel; - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern entvars_t *g_pevLastInflictor; - -#define GERMAN_GIB_COUNT 4 -#define HUMAN_GIB_COUNT 6 -#define ALIEN_GIB_COUNT 4 - - -// HACKHACK -- The gib velocity equations don't work -void CGib :: LimitVelocity( void ) -{ - float length = pev->velocity.Length(); - - // ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it - // in 3 separate places again, I'll just limit it here. - if ( length > 1500.0 ) - pev->velocity = pev->velocity.Normalize() * 1500; // This should really be sv_maxvelocity * 0.75 or something -} - - -void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ) -{ - int i; - - if ( g_Language == LANGUAGE_GERMAN ) - { - // no sticky gibs in germany right now! - return; - } - - for ( i = 0 ; i < cGibs ; i++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( "models/stickygib.mdl" ); - pGib->pev->body = RANDOM_LONG(0,2); - - if ( pevVictim ) - { - pGib->pev->origin.x = vecOrigin.x + RANDOM_FLOAT( -3, 3 ); - pGib->pev->origin.y = vecOrigin.y + RANDOM_FLOAT( -3, 3 ); - pGib->pev->origin.z = vecOrigin.z + RANDOM_FLOAT( -3, 3 ); - - /* - pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ); - */ - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.15, 0.15 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.15, 0.15 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.15, 0.15 ); - - pGib->pev->velocity = pGib->pev->velocity * 900; - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 250, 400 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 250, 400 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - - - pGib->pev->movetype = MOVETYPE_TOSS; - pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) ); - pGib->SetTouch ( &CGib::StickyGibTouch ); - pGib->SetThink (NULL); - } - pGib->LimitVelocity(); - } -} - -void CGib :: SpawnHeadGib( entvars_t *pevVictim ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - if ( g_Language == LANGUAGE_GERMAN ) - { - pGib->Spawn( "models/germangibs.mdl" );// throw one head - pGib->pev->body = 0; - } - else - { - pGib->Spawn( "models/hgibs.mdl" );// throw one head - pGib->pev->body = 0; - } - - if ( pevVictim ) - { - pGib->pev->origin = pevVictim->origin + pevVictim->view_ofs; - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict() ); - - if ( RANDOM_LONG ( 0, 100 ) <= 5 && pentPlayer ) - { - // 5% chance head will be thrown at player's face. - entvars_t *pevPlayer; - - pevPlayer = VARS( pentPlayer ); - pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300; - pGib->pev->velocity.z += 100; - } - else - { - pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - } - - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - } - pGib->LimitVelocity(); -} - -void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) -{ - int cSplat; - - for ( cSplat = 0 ; cSplat < cGibs ; cSplat++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - if ( g_Language == LANGUAGE_GERMAN ) - { - pGib->Spawn( "models/germangibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,GERMAN_GIB_COUNT-1); - } - else - { - if ( human ) - { - // human pieces - pGib->Spawn( "models/hgibs.mdl" ); - pGib->pev->body = RANDOM_LONG(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib) - } - else - { - // aliens - pGib->Spawn( "models/agibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,ALIEN_GIB_COUNT-1); - } - } - - if ( pevVictim ) - { - // spawn the gib somewhere in the monster's bounding volume - pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ) + 1; // absmin.z is in the floor because the engine subtracts 1 to enlarge the box - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.25, 0.25 ); - - pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT ( 300, 400 ); - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - - pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector( 0 , 0 , 0 ), Vector ( 0, 0, 0 ) ); - } - pGib->LimitVelocity(); - } -} - - -BOOL CBaseMonster :: HasHumanGibs( void ) -{ - int myClass = Classify(); - - if ( myClass == CLASS_HUMAN_MILITARY || - myClass == CLASS_PLAYER_ALLY || - myClass == CLASS_HUMAN_PASSIVE || - myClass == CLASS_PLAYER ) - - return TRUE; - - return FALSE; -} - - -BOOL CBaseMonster :: HasAlienGibs( void ) -{ - int myClass = Classify(); - - if ( myClass == CLASS_ALIEN_MILITARY || - myClass == CLASS_ALIEN_MONSTER || - myClass == CLASS_ALIEN_PASSIVE || - myClass == CLASS_INSECT || - myClass == CLASS_ALIEN_PREDATOR || - myClass == CLASS_ALIEN_PREY ) - - return TRUE; - - return FALSE; -} - - -void CBaseMonster::FadeMonster( void ) -{ - StopAnimation(); - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->avelocity = g_vecZero; - pev->animtime = gpGlobals->time; - pev->effects |= EF_NOINTERP; - SUB_StartFadeOut(); -} - -//========================================================= -// GibMonster - create some gore and get rid of a monster's -// model. -//========================================================= -void CBaseMonster :: GibMonster( void ) -{ - TraceResult tr; - BOOL gibbed = FALSE; - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM); - - // only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs - if ( HasHumanGibs() ) - { - if ( ns_cvar_float(violence_hgibs) != 0 ) // Only the player will ever get here - { - CGib::SpawnHeadGib( pev ); - CGib::SpawnRandomGibs( pev, 4, 1 ); // throw some human gibs. - } - gibbed = TRUE; - } - else if ( HasAlienGibs() ) - { - if ( ns_cvar_float(violence_hgibs) != 0 ) // Should never get here, but someone might call it directly - { - CGib::SpawnRandomGibs( pev, 4, 0 ); // Throw alien gibs - } - gibbed = TRUE; - } - - if ( !IsPlayer() ) - { - if ( gibbed ) - { - // don't remove players! - SetThink ( &CBaseMonster::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - else - { - FadeMonster(); - } - } -} - -//========================================================= -// GetDeathActivity - determines the best type of death -// anim to play. -//========================================================= -Activity CBaseMonster :: GetDeathActivity ( void ) -{ - Activity deathActivity; - BOOL fTriedDirection; - float flDot; - TraceResult tr; - Vector vecSrc; - - if ( pev->deadflag != DEAD_NO ) - { - // don't run this while dying. - return m_IdealActivity; - } - - vecSrc = Center(); - - fTriedDirection = FALSE; - deathActivity = ACT_DIESIMPLE;// in case we can't find any special deaths to do. - - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // try to pick a region-specific death. - case HITGROUP_HEAD: - deathActivity = ACT_DIE_HEADSHOT; - break; - - case HITGROUP_STOMACH: - deathActivity = ACT_DIE_GUTSHOT; - break; - - case HITGROUP_GENERIC: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - - default: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - } - - - // can we perform the prescribed death? - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // no! did we fail to perform a directional death? - if ( fTriedDirection ) - { - // if yes, we're out of options. Go simple. - deathActivity = ACT_DIESIMPLE; - } - else - { - // cannot perform the ideal region-specific death, so try a direction. - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - } - } - - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // if we're still invalid, simple is our only option. - deathActivity = ACT_DIESIMPLE; - } - - if ( deathActivity == ACT_DIEFORWARD ) - { - // make sure there's room to fall forward - UTIL_TraceHull ( vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - if ( deathActivity == ACT_DIEBACKWARD ) - { - // make sure there's room to fall backward - UTIL_TraceHull ( vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - return deathActivity; -} - -//========================================================= -// GetSmallFlinchActivity - determines the best type of flinch -// anim to play. -//========================================================= -Activity CBaseMonster :: GetSmallFlinchActivity ( void ) -{ - Activity flinchActivity; - BOOL fTriedDirection; - float flDot; - - fTriedDirection = FALSE; - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // pick a region-specific flinch - case HITGROUP_HEAD: - flinchActivity = ACT_FLINCH_HEAD; - break; - case HITGROUP_STOMACH: - flinchActivity = ACT_FLINCH_STOMACH; - break; - case HITGROUP_LEFTARM: - flinchActivity = ACT_FLINCH_LEFTARM; - break; - case HITGROUP_RIGHTARM: - flinchActivity = ACT_FLINCH_RIGHTARM; - break; - case HITGROUP_LEFTLEG: - flinchActivity = ACT_FLINCH_LEFTLEG; - break; - case HITGROUP_RIGHTLEG: - flinchActivity = ACT_FLINCH_RIGHTLEG; - break; - case HITGROUP_GENERIC: - default: - // just get a generic flinch. - flinchActivity = ACT_SMALL_FLINCH; - break; - } - - - // do we have a sequence for the ideal activity? - if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - flinchActivity = ACT_SMALL_FLINCH; - } - - return flinchActivity; -} - - -void CBaseMonster::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. - - // make the corpse fly away from the attack vector - pev->movetype = MOVETYPE_TOSS; - //pev->flags &= ~FL_ONGROUND; - //pev->origin.z += 2; - //pev->velocity = g_vecAttackDir * -1; - //pev->velocity = pev->velocity * RANDOM_FLOAT( 300, 400 ); -} - - -BOOL CBaseMonster::ShouldGibMonster( int iGib ) -{ - if ( ( iGib == GIB_NORMAL && pev->health < GIB_HEALTH_VALUE ) || ( iGib == GIB_ALWAYS ) ) - return TRUE; - - return FALSE; -} - - -void CBaseMonster::CallGibMonster( void ) -{ - BOOL fade = FALSE; - - if ( HasHumanGibs() ) - { - if ( ns_cvar_float(violence_hgibs) == 0 ) - fade = TRUE; - } - else if ( HasAlienGibs() ) - { - if ( ns_cvar_float(violence_agibs) == 0 ) - fade = TRUE; - } - - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT;// do something with the body. while monster blows up - - if ( fade ) - { - FadeMonster(); - } - else - { - pev->effects = EF_NODRAW; // make the model invisible. - GibMonster(); - } - - pev->deadflag = DEAD_DEAD; - FCheckAITrigger(); - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) - { - pev->health = 0; - } - - if ( ShouldFadeOnDeath() && !fade ) - UTIL_Remove(this); -} - - -/* -============ -Killed -============ -*/ -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - unsigned int cCount = 0; - BOOL fDone = FALSE; - - CBaseEntity* theBaseEntity = CBaseEntity::Instance(pevAttacker->owner); - if(!theBaseEntity) - { - theBaseEntity = CBaseEntity::Instance(pevAttacker); - } - ASSERT(theBaseEntity); - theBaseEntity->AwardKill(this->pev); - - if ( HasMemory( bits_MEMORY_KILLED ) ) - { - if ( ShouldGibMonster( iGib ) ) - CallGibMonster(); - return; - } - - Remember( bits_MEMORY_KILLED ); - - // clear the deceased's sound channels.(may have been firing or reloading when killed) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM); - m_IdealMonsterState = MONSTERSTATE_DEAD; - // Make sure this condition is fired too (TakeDamage breaks out before this happens on death) - SetConditions( bits_COND_LIGHT_DAMAGE ); - - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) - { - pOwner->DeathNotice( pev ); - } - - if ( ShouldGibMonster( iGib ) ) - { - CallGibMonster(); - return; - } - else if ( pev->flags & FL_MONSTER ) - { - SetTouch( NULL ); - BecomeDead(); - } - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) - { - pev->health = 0; - } - - //pev->enemy = ENT( pevAttacker );//why? (sjb) - - m_IdealMonsterState = MONSTERSTATE_DEAD; - -} - -// -// fade out - slowly fades a entity out, then removes it. -// -// DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER! -// SET A FUTURE THINK AND A RENDERMODE!! -void CBaseEntity :: SUB_StartFadeOut ( void ) -{ - if (pev->rendermode == kRenderNormal) - { - pev->renderamt = 255; - pev->rendermode = kRenderTransTexture; - } - - pev->solid = SOLID_NOT; - pev->avelocity = g_vecZero; - - pev->nextthink = gpGlobals->time + 0.1; - SetThink ( &CBaseEntity::SUB_FadeOut ); -} - -void CBaseEntity :: SUB_FadeOut ( void ) -{ - if ( pev->renderamt > 7 ) - { - pev->renderamt -= 7; - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - pev->renderamt = 0; - pev->nextthink = gpGlobals->time + 0.2; - SetThink ( &CBaseEntity::SUB_Remove ); - } -} - -//========================================================= -// WaitTillLand - in order to emit their meaty scent from -// the proper location, gibs should wait until they stop -// bouncing to emit their scent. That's what this function -// does. -//========================================================= -void CGib :: WaitTillLand ( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - if ( pev->velocity == g_vecZero ) - { - SetThink (&CGib::SUB_StartFadeOut); - pev->nextthink = gpGlobals->time + m_lifeTime; - - // If you bleed, you stink! - if ( m_bloodColor != DONT_BLEED ) - { - // ok, start stinkin! - CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 ); - } - } - else - { - // wait and check again in another half second. - pev->nextthink = gpGlobals->time + 0.5; - } -} - -// -// Gib bounces on the ground or wall, sponges some blood down, too! -// -void CGib :: BounceGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - //if ( RANDOM_LONG(0,1) ) - // return;// don't bleed everytime - - if (pev->flags & FL_ONGROUND) - { - pev->velocity = pev->velocity * 0.9; - pev->angles.x = 0; - pev->angles.z = 0; - pev->avelocity.x = 0; - pev->avelocity.z = 0; - } - else - { - if ( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) - { - vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); - - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - m_cBloodDecals--; - } - - if ( m_material != matNone && RANDOM_LONG(0,2) == 0 ) - { - float volume; - float zvel = fabs(pev->velocity.z); - - volume = 0.8 * min(1.0, ((float)zvel) / 450.0); - - CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); - } - } -} - -// -// Sticky gib puts blood on the wall and stays put. -// -void CGib :: StickyGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - SetThink ( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 10; - - if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) - { - pev->nextthink = gpGlobals->time; - return; - } - - UTIL_TraceLine ( pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), & tr); - - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - pev->velocity = tr.vecPlaneNormal * -1; - pev->angles = UTIL_VecToAngles ( pev->velocity ); - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; -} - -// -// Throw a chunk -// -void CGib :: Spawn( const char *szGibModel ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->friction = 0.55; // deading the bounce a bit - - // sometimes an entity inherits the edict from a former piece of glass, - // and will spawn using the same render FX or rendermode! bad! - pev->renderamt = 255; - pev->rendermode = kRenderNormal; - pev->renderfx = kRenderFxNone; - pev->solid = SOLID_SLIDEBOX;/// hopefully this will fix the VELOCITY TOO LOW crap - pev->classname = MAKE_STRING("gib"); - - SET_MODEL(ENT(pev), szGibModel); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pev->nextthink = gpGlobals->time + 4; - m_lifeTime = 25; - SetThink ( &CGib::WaitTillLand ); - SetTouch ( &CGib::BounceGibTouch ); - - m_material = matNone; - m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain). -} - -// take health -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) -{ - if (!pev->takedamage) - return 0; - - // clear out any damage types we healed. - // UNDONE: generic health should not heal any - // UNDONE: time-based damage - - m_bitsDamageType &= ~(bitsDamageType & ~DMG_TIMEBASED); - - return CBaseEntity::TakeHealth(flHealth, bitsDamageType); -} - -/* -============ -TakeDamage - -The damage is coming from inflictor, but get mad at attacker -This should be the only function that ever reduces health. -bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK - -Time-based damage: only occurs while the monster is within the trigger_hurt. -When a monster is poisoned via an arrow etc it takes all the poison damage at once. - - - -GLOBALS ASSUMED SET: g_iSkillLevel -============ -*/ -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flTake; - Vector vecDir; - - if (!pev->takedamage) - return 0; - - if ( !IsAlive() ) - { - return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - } - - if ( pev->deadflag == DEAD_NO ) - { - // no pain sound during death animation. - PainSound();// "Ouch!" - } - - //!!!LATER - make armor consideration here! - flTake = flDamage; - - // set damage type sustained - m_bitsDamageType |= bitsDamageType; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - - // add to the damage total for clients, which will be sent as a single - // message at the end of the frame - // todo: remove after combining shotgun blasts? - if ( IsPlayer() ) - { - if ( pevInflictor ) - pev->dmg_inflictor = ENT(pevInflictor); - - pev->dmg_take += flTake; - - // check for godmode or invincibility - if ( pev->flags & FL_GODMODE ) - { - return 0; - } - } - - // HL: if this is a player, move him around! - // NS: Don't move players - if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) && !IsPlayer()) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - - // do the damage - pev->health -= flTake; - - - // HACKHACK Don't kill monsters in a script. Let them break their scripts first - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - SetConditions( bits_COND_LIGHT_DAMAGE ); - return 0; - } - - if ( (int)(pev->health) <= 0 ) - { - g_pevLastInflictor = pevInflictor; - -// Removed gibbing, as death animations weren't playing with gibs off -// if ( bitsDamageType & DMG_ALWAYSGIB ) -// { -// Killed( pevAttacker, GIB_ALWAYS ); -// } -// else if ( bitsDamageType & DMG_NEVERGIB ) -// { - Killed( pevAttacker, GIB_NEVER ); -// } -// else -// { -// Killed( pevAttacker, GIB_NORMAL ); -// } - - // Trigger log message if needed -// AvHPlayer* theDeadPlayer = dynamic_cast(this); -// AvHPlayer* theAttackingPlayer = dynamic_cast(CBaseEntity::Instance(ENT(pevAttacker))); -// const char* inWeaponName = STRING(pevInflictor->classname); -// if(theDeadPlayer && theAttackingPlayer && inWeaponName) -// { -// theDeadPlayer->LogPlayerKilledPlayer(theAttackingPlayer, inWeaponName); -// } - - g_pevLastInflictor = NULL; - - return 0; - } - - // react to the damage (get mad) - if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) - { - if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) - {// only if the attack was a monster or client! - - // enemy's last known position is somewhere down the vector that the attack came from. - if (pevInflictor) - { - if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) - { - m_vecEnemyLKP = pevInflictor->origin; - } - } - else - { - m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); - } - - MakeIdealYaw( m_vecEnemyLKP ); - - // add pain to the conditions - // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and - // heavy damage per monster class? - if ( flDamage > 0 ) - { - SetConditions(bits_COND_LIGHT_DAMAGE); - } - - if ( flDamage >= 20 ) - { - SetConditions(bits_COND_HEAVY_DAMAGE); - } - } - } - - return 1; -} - -//========================================================= -// DeadTakeDamage - takedamage function called when a monster's -// corpse is damaged. -//========================================================= -int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecDir; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - -#if 0// turn this back on when the bounding box issues are resolved. - - pev->flags &= ~FL_ONGROUND; - pev->origin.z += 1; - - // let the damage scoot the corpse around a bit. - if ( !FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER) ) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - -#endif - - // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. - if ( bitsDamageType & DMG_GIB_CORPSE ) - { - if ( pev->health <= flDamage ) - { - pev->health = -50; - Killed( pevAttacker, GIB_ALWAYS ); - return 0; - } - // Accumulate corpse gibbing damage, so you can gib with multiple hits - pev->health -= flDamage * 0.1; - } - - return 1; -} - - -float CBaseMonster :: DamageForce( float damage ) -{ - float force = damage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if ( force > 1000.0) - { - force = 1000.0; - } - - return force; -} - -// -// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range. -// -// only damage ents that can clearly be seen by the explosion! - - -void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float inDamage, float flRadius, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage, falloff; - Vector vecSpot; - - if ( flRadius ) - falloff = inDamage / flRadius; - else - falloff = 1.0; - - int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); - - vecSrc.z += 1;// in case grenade is lying on the ground - - if ( !pevAttacker ) - pevAttacker = pevInflictor; - - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) - { - // NOTE: Should this be inflictor or attacker? - CBaseEntity* theInflictingEntity = CBaseEntity::Instance(pevInflictor); - CBaseEntity* theAttackingEntity = CBaseEntity::Instance(pevAttacker); - float theScalar = 1.0f; - bool aCanDamage=GetGameRules()->CanEntityDoDamageTo(theAttackingEntity, pEntity, &theScalar) || theInflictingEntity->pev->classname == MAKE_STRING(kwsDeployedMine);; - bool iCanDamage=GetGameRules()->CanEntityDoDamageTo(theInflictingEntity, pEntity, &theScalar); - - if(pEntity && ( aCanDamage && iCanDamage )) - { - // Multiply damage by scalar for tourny mode, etc. - float theDamage = inDamage*theScalar; - - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - - // UNDONE: this should check a damage mask, not an ignore - if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - {// houndeyes don't hurt other houndeyes with their attack - continue; - } - - // blast's don't tavel into or out of water - if (bInWater && pEntity->pev->waterlevel == 0) - continue; - if (!bInWater && pEntity->pev->waterlevel == 3) - continue; - - vecSpot = pEntity->BodyTarget( vecSrc ); - - // Clear pevInflictor's owner temporarily so it can apply damage to it - edict_t* theInflictorOwner = pevInflictor->owner; - pevInflictor->owner = NULL; - - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); - - // Restore owner - pevInflictor->owner = theInflictorOwner; - - if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - {// the explosion can 'see' this entity, so hurt them! - if (tr.fStartSolid) - { - // if we're stuck inside them, fixup the position and distance - tr.vecEndPos = vecSrc; - tr.flFraction = 0.0; - } - - // decrease damage for an ent that's farther from the bomb. - flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; - flAdjustedDamage = theDamage - flAdjustedDamage; - - if ( flAdjustedDamage > 0 ) - { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } - } -} - - -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - - -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - -int CBaseMonster::GetHull() const -{ - return head_hull; -} - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// -// Used for many contact-range melee attacks. Bites, claws, etc. -//========================================================= -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ) -{ - Vector vecStart = pev->origin; - - if(this->IsPlayer()) - { - // Melee attacks always originate where the view is - vecStart.x += this->pev->view_ofs.x; - vecStart.y += this->pev->view_ofs.y; - vecStart.z += this->pev->view_ofs.z; - } - - if (IsPlayer()) - UTIL_MakeVectors( pev->v_angle ); - else - UTIL_MakeAimVectors( pev->angles ); - - //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecStart); - - // First do a tracehull. If that misses, try three tracelines (dead-on center, then randomly left and randomly right). - bool theHitTarget = false; - for(int i = 0; (i < 4) && !theHitTarget; i++) - { - const float kAmount = 0.4f; - float theXAmount = 0.0f; - - if(i == 2) - { - theXAmount = kAmount; - } - else if(i == 3) - { - theXAmount = -kAmount; - } - - Vector vecDir = gpGlobals->v_forward + theXAmount*gpGlobals->v_right; - vecDir.Normalize(); - - Vector vecEnd = vecStart + (vecDir * flDist ); - TraceResult tr; - - if(i == 0) - { - int theOurHull = this->GetHull(); - int theHull = AvHSUGetValveHull(theOurHull); - UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, theHull, this->edict(), &tr); - } - else - { - //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecEnd); - - UTIL_TraceLine(vecStart, vecEnd, dont_ignore_monsters, dont_ignore_glass, ENT(this->pev), &tr); - } - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( ioDamage > 0 ) - { - float theScalar = 1.0f; - if(GetGameRules()->CanEntityDoDamageTo(this, pEntity, &theScalar)) - { - theHitTarget = true; - - // Multiply damage by scalar for tourny mode, etc. - ioDamage *= theScalar; - - entvars_t* theInflictor = this->pev; - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer) - { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(thePlayer->m_pActiveItem); - if(theBasePlayerWeapon) - { - theInflictor = theBasePlayerWeapon->pev; - } - } - - pEntity->TakeDamage(theInflictor, pev, ioDamage, iDmgType ); - - // Spawn blood - if(ioDamage > 0.0f) - { - // a little surface blood. - SpawnBlood(tr.vecEndPos, pEntity->BloodColor(), ioDamage); - - // on the wall/floor (don't play because blood decal is green) - //TraceBleed(ioDamage, vecDir, &tr, iDmgType); - } - - return pEntity; - } - } - } - } - - return NULL; -} - - -//========================================================= -// FInViewCone - returns true is the passed ent is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FInViewCone - returns true is the passed vector is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( *pOrigin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target -//========================================================= -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) -{ - TraceResult tr; - Vector vecLookerOrigin; - Vector vecTargetOrigin; - - if (FBitSet( pEntity->pev->flags, FL_NOTARGET )) - return FALSE; - - // don't look through water //edit by Elven Thief to prevent bug #728 - // if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - // || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - // return FALSE; - - vecLookerOrigin = this->EyePosition();//look through the caller's 'eyes' - vecTargetOrigin = pEntity->EyePosition(); - - return AvHCheckLineOfSight(vecLookerOrigin, vecTargetOrigin, ENT(pev)); - -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target vector -//========================================================= -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) -{ - TraceResult tr; - Vector vecLookerOrigin; - - vecLookerOrigin = EyePosition();//look through the caller's 'eyes' - - return AvHCheckLineOfSight(vecLookerOrigin, vecOrigin, ENT(pev)); - -} - -/* -================ -TraceAttack -================ -*/ -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - } -} - - -/* -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - ALERT ( at_console, "%d\n", ptr->iHitgroup ); - - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - } - } -} -*/ - -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= gSkillData.monHead; - break; - case HITGROUP_CHEST: - flDamage *= gSkillData.monChest; - break; - case HITGROUP_STOMACH: - flDamage *= gSkillData.monStomach; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= gSkillData.monArm; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= gSkillData.monLeg; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. - -This version is used by Monsters. -================ -*/ -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int inDamageType) -{ - static int tracerCount; - int tracer; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - ClearMultiDamage(); - gMultiDamage.type = inDamageType; - - for (ULONG iShot = 1; iShot <= cShots; iShot++) - { - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - - Vector vecDir = vecDirShooting + - x * vecSpread.x * vecRight + - y * vecSpread.y * vecUp; - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - //UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - bool theProtected = false; - AvHSUServerTraceBullets(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), tr, theProtected); - CBaseEntity* theEntityHit = CBaseEntity::Instance(tr.pHit); - - if(theProtected && theEntityHit) - { - // : experiment - EMIT_SOUND(theEntityHit->edict(), CHAN_AUTO, kUmbraBlockedSound, 1.0f, ATTN_NORM); - // : - } - else - { - tracer = 0; - if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0) - { - Vector vecTracerSrc; - - if ( IsPlayer() ) - {// adjust tracer position for player - vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16; - } - else - { - vecTracerSrc = vecSrc; - } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal - tracer = 1; - switch( iBulletType ) - { - case BULLET_MONSTER_MP5: - case BULLET_MONSTER_9MM: - case BULLET_MONSTER_12MM: - default: - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( vecTracerSrc.x ); - WRITE_COORD( vecTracerSrc.y ); - WRITE_COORD( vecTracerSrc.z ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - MESSAGE_END(); - break; - } - } - // do damage, paint decals - if (tr.flFraction != 1.0) - { - float theScalar = 1.0f; - if(theEntityHit && GetGameRules()->CanEntityDoDamageTo(this, theEntityHit, &theScalar)) - { - // Multiply damage by scalar for tourny mode, etc. - iDamage *= theScalar; - - if ( iDamage ) - { - theEntityHit->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - //DecalGunshot( &tr, 0 ); - } - else switch(iBulletType) - { - default: - case BULLET_MONSTER_9MM: - theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MONSTER_MP5: - theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MONSTER_12MM: - theEntityHit->TraceAttack(pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_NONE: // FIX - theEntityHit->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB); - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - // only decal glass - if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0) - { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); - } - - break; - } - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); - } - } - ApplyMultiDamage(pev, pevAttacker); -} - - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. - -This version is used by Players, uses the random seed generator to sync client and server side shots. -================ -*/ -Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) -{ - static int tracerCount; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - entvars_t* theInflictor = this->pev; - //float x, y, z; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - int theDamageType = DMG_BULLET; - bool isShotgun=false; - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && thePlayer->m_pActiveItem) - { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(thePlayer->m_pActiveItem); - if(theBasePlayerWeapon) - { - theDamageType = theBasePlayerWeapon->GetDamageType(); - theInflictor = theBasePlayerWeapon->pev; - } - AvHSonicGun* theSonicGun = dynamic_cast(thePlayer->m_pActiveItem); - if ( theSonicGun ) - { - isShotgun=true; - } - } - else - { - AvHTurret* theTurret = dynamic_cast(this); - if(theTurret) - { - theDamageType = theTurret->GetDamageType(); - } - } - - ClearMultiDamage(); - gMultiDamage.type = theDamageType; - - for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) - { - //Use player's random seed. - // get circular gaussian spread - //x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); - //y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); - //z = x * x + y * y; - // - //Vector vecDir = vecDirShooting + - // x * vecSpread.x * vecRight + - // y * vecSpread.y * vecUp; - - Vector vecDir; - // : 0000973 - // added inner cone for half of the shots - if (isShotgun) - { - vecSpread = kSGInnerSpread; - Vector vecMinSpread; - - if ((iShot > (cShots/3)) && (iShot < (cShots*2/3))) - { - vecSpread = kSGMidSpread; - vecMinSpread = kSGInnerSpread; - vecDir = UTIL_GetRandomSpreadDirFrom(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread, vecMinSpread); - } - else - if ((iShot > (cShots*2/3))) - { - vecMinSpread = kSGMidSpread; - vecDir = UTIL_GetRandomSpreadDirFrom(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread, vecMinSpread); - } - else - { - vecSpread = kSGInnerSpread; - vecDir = UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread); - } - } - // : - else - { - vecDir = UTIL_GetRandomSpreadDir(shared_rand, iShot, vecDirShooting, vecRight, vecUp, vecSpread); - } - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - //UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - bool theProtected = false; - AvHSUServerTraceBullets(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), tr, theProtected); - CBaseEntity* theEntityHit = CBaseEntity::Instance(tr.pHit); - - if(theProtected) - { - // : experiment - EMIT_SOUND(theEntityHit->edict(), CHAN_AUTO, kUmbraBlockedSound, 1.0f, ATTN_NORM); - // : - } - else - { - - // do damage, paint decals - if (tr.flFraction != 1.0) - { - float theScalar = 1.0f; - if(GetGameRules()->CanEntityDoDamageTo(thePlayer, theEntityHit, &theScalar)) - { - int theAdjustedDamage = iDamage*theScalar; - - if(theAdjustedDamage) - { - // : 0000973 - // removed shotgun fallof - //if ( isShotgun && !( theEntityHit->pev->iuser3 & AVH_USER3_BREAKABLE) ) - //{ - // float distance=fabs((vecSrc - theEntityHit->pev->origin).Length()); - // if ( distance > BALANCE_VAR(kShotgunDamageRange) ) - // { - // float fallOffDistance=distance-BALANCE_VAR(kShotgunDamageRange); - // float fallOff=max(0.0, 1.0f-(fallOffDistance/(kSGRange/2))); - // theAdjustedDamage*=fallOff; - // } - //} - // : - if ( theAdjustedDamage ) { - theEntityHit->TraceAttack(pevAttacker, theAdjustedDamage, vecDir, &tr, theDamageType | ((theAdjustedDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - } - -// TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); -// DecalGunshot( &tr, iBulletType ); - } - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); - } - } - ApplyMultiDamage(theInflictor, pevAttacker); - - //return Vector( (float)(x * vecSpread.x), (float)(y * vecSpread.y), 0.0f ); - return vecSpread; -} - -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if (BloodColor() == DONT_BLEED) - return; - - if (flDamage == 0) - return; - - if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB /*| DMG_MORTAR*/ ))) - return; - - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - float flNoise; - int cCount; - int i; - -/* - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } -*/ - - if (flDamage < 10) - { - flNoise = 0.1; - cCount = 1; - } - else if (flDamage < 25) - { - flNoise = 0.2; - cCount = 2; - } - else - { - flNoise = 0.3; - cCount = 4; - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr); - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} - -//========================================================= -//========================================================= -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) -{ - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - int i; - - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir; - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); - -/* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( Bloodtr.vecEndPos.x ); - WRITE_COORD( Bloodtr.vecEndPos.y ); - WRITE_COORD( Bloodtr.vecEndPos.z ); - MESSAGE_END(); -*/ - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} diff --git a/main/source/dlls/controller.cpp b/main/source/dlls/controller.cpp index b3074852..7b771078 100644 --- a/main/source/dlls/controller.cpp +++ b/main/source/dlls/controller.cpp @@ -1,1427 +1,1427 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// CONTROLLER -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "effects.h" -#include "schedule.h" -#include "weapons.h" -#include "squadmonster.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define CONTROLLER_AE_HEAD_OPEN 1 -#define CONTROLLER_AE_BALL_SHOOT 2 -#define CONTROLLER_AE_SMALL_SHOOT 3 -#define CONTROLLER_AE_POWERUP_FULL 4 -#define CONTROLLER_AE_POWERUP_HALF 5 - -#define CONTROLLER_FLINCH_DELAY 2 // at most one flinch every n secs - -class CController : public CSquadMonster -{ -public: - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void RunAI( void ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); // balls - BOOL CheckRangeAttack2 ( float flDot, float flDist ); // head - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); // block, throw - Schedule_t* GetSchedule ( void ); - Schedule_t* GetScheduleOfType ( int Type ); - void StartTask ( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - CUSTOM_SCHEDULES; - - void Stop( void ); - void Move ( float flInterval ); - int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void SetActivity ( Activity NewActivity ); - BOOL ShouldAdvanceRoute( float flWaypointDist ); - int LookupFloat( ); - - float m_flNextFlinch; - - float m_flShootTime; - float m_flShootEnd; - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSound( void ); - void DeathSound( void ); - - static const char *pAttackSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pDeathSounds[]; - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - CSprite *m_pBall[2]; // hand balls - int m_iBall[2]; // how bright it should be - float m_iBallTime[2]; // when it should be that color - int m_iBallCurrent[2]; // current brightness - - Vector m_vecEstVelocity; - - Vector m_velocity; - int m_fInCombat; -}; - -LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ); - -TYPEDESCRIPTION CController::m_SaveData[] = -{ - DEFINE_ARRAY( CController, m_pBall, FIELD_CLASSPTR, 2 ), - DEFINE_ARRAY( CController, m_iBall, FIELD_INTEGER, 2 ), - DEFINE_ARRAY( CController, m_iBallTime, FIELD_TIME, 2 ), - DEFINE_ARRAY( CController, m_iBallCurrent, FIELD_INTEGER, 2 ), - DEFINE_FIELD( CController, m_vecEstVelocity, FIELD_VECTOR ), -}; -IMPLEMENT_SAVERESTORE( CController, CSquadMonster ); - - -const char *CController::pAttackSounds[] = -{ - "controller/con_attack1.wav", - "controller/con_attack2.wav", - "controller/con_attack3.wav", -}; - -const char *CController::pIdleSounds[] = -{ - "controller/con_idle1.wav", - "controller/con_idle2.wav", - "controller/con_idle3.wav", - "controller/con_idle4.wav", - "controller/con_idle5.wav", -}; - -const char *CController::pAlertSounds[] = -{ - "controller/con_alert1.wav", - "controller/con_alert2.wav", - "controller/con_alert3.wav", -}; - -const char *CController::pPainSounds[] = -{ - "controller/con_pain1.wav", - "controller/con_pain2.wav", - "controller/con_pain3.wav", -}; - -const char *CController::pDeathSounds[] = -{ - "controller/con_die1.wav", - "controller/con_die2.wav", -}; - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CController :: Classify ( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CController :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - -#if 0 - switch ( m_Activity ) - { - } -#endif - - pev->yaw_speed = ys; -} - -int CController :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // HACK HACK -- until we fix this. - if ( IsAlive() ) - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - -void CController::Killed( entvars_t *pevAttacker, int iGib ) -{ - // shut off balls - /* - m_iBall[0] = 0; - m_iBallTime[0] = gpGlobals->time + 4.0; - m_iBall[1] = 0; - m_iBallTime[1] = gpGlobals->time + 4.0; - */ - - // fade balls - if (m_pBall[0]) - { - m_pBall[0]->SUB_StartFadeOut(); - m_pBall[0] = NULL; - } - if (m_pBall[1]) - { - m_pBall[1]->SUB_StartFadeOut(); - m_pBall[1] = NULL; - } - - CSquadMonster::Killed( pevAttacker, iGib ); -} - - -void CController::GibMonster( void ) -{ - // delete balls - if (m_pBall[0]) - { - UTIL_Remove( m_pBall[0] ); - m_pBall[0] = NULL; - } - if (m_pBall[1]) - { - UTIL_Remove( m_pBall[1] ); - m_pBall[1] = NULL; - } - CSquadMonster::GibMonster( ); -} - - - - -void CController :: PainSound( void ) -{ - if (RANDOM_LONG(0,5) < 2) - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); -} - -void CController :: AlertSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); -} - -void CController :: IdleSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pIdleSounds ); -} - -void CController :: AttackSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAttackSounds ); -} - -void CController :: DeathSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case CONTROLLER_AE_HEAD_OPEN: - { - Vector vecStart, angleGun; - - GetAttachment( 0, vecStart, angleGun ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( 1 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 20 ); // life * 10 - WRITE_COORD( -32 ); // decay - MESSAGE_END(); - - m_iBall[0] = 192; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 255; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - - } - break; - - case CONTROLLER_AE_BALL_SHOOT: - { - Vector vecStart, angleGun; - - GetAttachment( 0, vecStart, angleGun ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment - WRITE_COORD( 0 ); // origin - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 32 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 32 ); // decay - MESSAGE_END(); - - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, pev->angles, edict() ); - - pBall->pev->velocity = Vector( 0, 0, 32 ); - pBall->m_hEnemy = m_hEnemy; - - m_iBall[0] = 0; - m_iBall[1] = 0; - } - break; - - case CONTROLLER_AE_SMALL_SHOOT: - { - AttackSound( ); - m_flShootTime = gpGlobals->time; - m_flShootEnd = m_flShootTime + atoi( pEvent->options ) / 15.0; - } - break; - case CONTROLLER_AE_POWERUP_FULL: - { - m_iBall[0] = 255; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 255; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - } - break; - case CONTROLLER_AE_POWERUP_HALF: - { - m_iBall[0] = 192; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 192; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CController :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/controller.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 )); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->flags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.controllerHealth; - pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CController :: Precache() -{ - PRECACHE_MODEL("models/controller.mdl"); - - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - - PRECACHE_MODEL( "sprites/xspark4.spr"); - - UTIL_PrecacheOther( "controller_energy_ball" ); - UTIL_PrecacheOther( "controller_head_ball" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - -// Chase enemy schedule -Task_t tlControllerChaseEnemy[] = -{ - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - -}; - -Schedule_t slControllerChaseEnemy[] = -{ - { - tlControllerChaseEnemy, - ARRAYSIZE ( tlControllerChaseEnemy ), - bits_COND_NEW_ENEMY | - bits_COND_TASK_FAILED, - 0, - "ControllerChaseEnemy" - }, -}; - - - -Task_t tlControllerStrafe[] = -{ - { TASK_WAIT, (float)0.2 }, - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slControllerStrafe[] = -{ - { - tlControllerStrafe, - ARRAYSIZE ( tlControllerStrafe ), - bits_COND_NEW_ENEMY, - 0, - "ControllerStrafe" - }, -}; - - -Task_t tlControllerTakeCover[] = -{ - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slControllerTakeCover[] = -{ - { - tlControllerTakeCover, - ARRAYSIZE ( tlControllerTakeCover ), - bits_COND_NEW_ENEMY, - 0, - "ControllerTakeCover" - }, -}; - - -Task_t tlControllerFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slControllerFail[] = -{ - { - tlControllerFail, - ARRAYSIZE ( tlControllerFail ), - 0, - 0, - "ControllerFail" - }, -}; - - - -DEFINE_CUSTOM_SCHEDULES( CController ) -{ - slControllerChaseEnemy, - slControllerStrafe, - slControllerTakeCover, - slControllerFail, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ); - - - -//========================================================= -// StartTask -//========================================================= -void CController :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - CSquadMonster :: StartTask ( pTask ); - break; - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, pTask->flData, (m_vecEnemyLKP - pev->origin).Length() + 1024 )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, pTask->flData, (pEnemy->pev->origin - pev->origin).Length() + 1024 )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - default: - CSquadMonster :: StartTask ( pTask ); - break; - } -} - - -Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) -{ - Vector vecTo = vecDst - vecSrc; - - float a = DotProduct( vecMove, vecMove ) - flSpeed * flSpeed; - float b = 0 * DotProduct(vecTo, vecMove); // why does this work? - float c = DotProduct( vecTo, vecTo ); - - float t; - if (a == 0) - { - t = c / (flSpeed * flSpeed); - } - else - { - t = b * b - 4 * a * c; - t = sqrt( t ) / (2.0 * a); - float t1 = -b +t; - float t2 = -b -t; - - if (t1 < 0 || t2 < t1) - t = t2; - else - t = t1; - } - - // ALERT( at_console, "Intersect %f\n", t ); - - if (t < 0.1) - t = 0.1; - if (t > 10.0) - t = 10.0; - - Vector vecHit = vecTo + vecMove * t; - return vecHit.Normalize( ) * flSpeed; -} - - -int CController::LookupFloat( ) -{ - if (m_velocity.Length( ) < 32.0) - { - return LookupSequence( "up" ); - } - - UTIL_MakeAimVectors( pev->angles ); - float x = DotProduct( gpGlobals->v_forward, m_velocity ); - float y = DotProduct( gpGlobals->v_right, m_velocity ); - float z = DotProduct( gpGlobals->v_up, m_velocity ); - - if (fabs(x) > fabs(y) && fabs(x) > fabs(z)) - { - if (x > 0) - return LookupSequence( "forward"); - else - return LookupSequence( "backward"); - } - else if (fabs(y) > fabs(z)) - { - if (y > 0) - return LookupSequence( "right"); - else - return LookupSequence( "left"); - } - else - { - if (z > 0) - return LookupSequence( "up"); - else - return LookupSequence( "down"); - } -} - - -//========================================================= -// RunTask -//========================================================= -void CController :: RunTask ( Task_t *pTask ) -{ - - if (m_flShootEnd > gpGlobals->time) - { - Vector vecHand, vecAngle; - - GetAttachment( 2, vecHand, vecAngle ); - - while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) - { - Vector vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); - Vector vecDir; - - if (m_hEnemy != NULL) - { - if (HasConditions( bits_COND_SEE_ENEMY )) - { - m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5; - } - else - { - m_vecEstVelocity = m_vecEstVelocity * 0.8; - } - vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); - float delta = 0.03490; // +-2 degree - vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall; - - vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() ); - pBall->pev->velocity = vecDir; - } - m_flShootTime += 0.2; - } - - if (m_flShootTime > m_flShootEnd) - { - m_iBall[0] = 64; - m_iBallTime[0] = m_flShootEnd; - m_iBall[1] = 64; - m_iBallTime[1] = m_flShootEnd; - m_fInCombat = FALSE; - } - } - - switch ( pTask->iTask ) - { - case TASK_WAIT_FOR_MOVEMENT: - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - case TASK_WAIT_PVS: - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if (m_fSequenceFinished) - { - m_fInCombat = FALSE; - } - - CSquadMonster :: RunTask ( pTask ); - - if (!m_fInCombat) - { - if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) - { - pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 ); - pev->frame = 0; - ResetSequenceInfo( ); - m_fInCombat = TRUE; - } - else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) - { - pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 ); - pev->frame = 0; - ResetSequenceInfo( ); - m_fInCombat = TRUE; - } - else - { - int iFloat = LookupFloat( ); - if (m_fSequenceFinished || iFloat != pev->sequence) - { - pev->sequence = iFloat; - pev->frame = 0; - ResetSequenceInfo( ); - } - } - } - break; - default: - CSquadMonster :: RunTask ( pTask ); - break; - } -} - - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CController :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - break; - - case MONSTERSTATE_ALERT: - break; - - case MONSTERSTATE_COMBAT: - { - Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); - - // dead enemy - if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) - { - // m_iFrustration++; - } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) - { - // m_iFrustration++; - } - } - break; - } - - return CSquadMonster :: GetSchedule(); -} - - - -//========================================================= -//========================================================= -Schedule_t* CController :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "%d\n", m_iFrustration ); - switch ( Type ) - { - case SCHED_CHASE_ENEMY: - return slControllerChaseEnemy; - case SCHED_RANGE_ATTACK1: - return slControllerStrafe; - case SCHED_RANGE_ATTACK2: - case SCHED_MELEE_ATTACK1: - case SCHED_MELEE_ATTACK2: - case SCHED_TAKE_COVER_FROM_ENEMY: - return slControllerTakeCover; - case SCHED_FAIL: - return slControllerFail; - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - - - - - -//========================================================= -// CheckRangeAttack1 - shoot a bigass energy ball out of their head -// -//========================================================= -BOOL CController :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDot > 0.5 && flDist > 256 && flDist <= 2048 ) - { - return TRUE; - } - return FALSE; -} - - -BOOL CController :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if ( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) - { - return TRUE; - } - return FALSE; -} - - -BOOL CController :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - return FALSE; -} - - -void CController :: SetActivity ( Activity NewActivity ) -{ - CBaseMonster::SetActivity( NewActivity ); - - switch ( m_Activity) - { - case ACT_WALK: - m_flGroundSpeed = 100; - break; - default: - m_flGroundSpeed = 100; - break; - } -} - - - -//========================================================= -// RunAI -//========================================================= -void CController :: RunAI( void ) -{ - CBaseMonster :: RunAI(); - Vector vecStart, angleGun; - - if ( HasMemory( bits_MEMORY_KILLED ) ) - return; - - for (int i = 0; i < 2; i++) - { - if (m_pBall[i] == NULL) - { - m_pBall[i] = CSprite::SpriteCreate( "sprites/xspark4.spr", pev->origin, TRUE ); - m_pBall[i]->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pBall[i]->SetAttachment( edict(), (i + 3) ); - m_pBall[i]->SetScale( 1.0 ); - } - - float t = m_iBallTime[i] - gpGlobals->time; - if (t > 0.1) - t = 0.1 / t; - else - t = 1.0; - - m_iBallCurrent[i] += (m_iBall[i] - m_iBallCurrent[i]) * t; - - m_pBall[i]->SetBrightness( m_iBallCurrent[i] ); - - GetAttachment( i + 2, vecStart, angleGun ); - UTIL_SetOrigin( m_pBall[i]->pev, vecStart ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 * (i + 3) ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( m_iBallCurrent[i] / 8 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 5 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } -} - - -extern void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ); - -void CController::Stop( void ) -{ - m_IdealActivity = GetStoppedActivity(); -} - - -#define DIST_TO_CHECK 200 -void CController :: Move ( float flInterval ) -{ - float flWaypointDist; - float flCheckDist; - float flDist;// how far the lookahead check got before hitting an object. - float flMoveDist; - Vector vecDir; - Vector vecApex; - CBaseEntity *pTargetEnt; - - // Don't move if no valid route - if ( FRouteClear() ) - { - ALERT( at_aiconsole, "Tried to move with no route!\n" ); - TaskFail(); - return; - } - - if ( m_flMoveWaitFinished > gpGlobals->time ) - return; - -// Debug, test movement code -#if 0 -// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) - { - if ( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - return; - } -#else -// Debug, draw the route -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); -#endif - - // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer - // to that entity for the CheckLocalMove and Triangulate functions. - pTargetEnt = NULL; - - if (m_flGroundSpeed == 0) - { - m_flGroundSpeed = 100; - // TaskFail( ); - // return; - } - - flMoveDist = m_flGroundSpeed * flInterval; - - do - { - // local move to waypoint. - vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); - - // MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); - // ChangeYaw ( pev->yaw_speed ); - - // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint - if ( flWaypointDist < DIST_TO_CHECK ) - { - flCheckDist = flWaypointDist; - } - else - { - flCheckDist = DIST_TO_CHECK; - } - - if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) - { - // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) - pTargetEnt = m_hEnemy; - } - else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) - { - pTargetEnt = m_hTargetEnt; - } - - // !!!BUGBUG - CheckDist should be derived from ground speed. - // If this fails, it should be because of some dynamic entity blocking this guy. - // We've already checked this path, so we should wait and time out if the entity doesn't move - flDist = 0; - if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) - { - CBaseEntity *pBlocker; - - // Can't move, stop - Stop(); - // Blocking entity is in global trace_ent - pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if (pBlocker) - { - DispatchBlocked( edict(), pBlocker->edict() ); - } - if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) - { - // Can we still move toward our target? - if ( flDist < m_flGroundSpeed ) - { - // Wait for a second - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; - // ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); - return; - } - } - else - { - // try to triangulate around whatever is in the way. - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); - RouteSimplify( pTargetEnt ); - } - else - { - ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); - Stop(); - if ( m_moveWaitTime > 0 ) - { - FRefreshRoute(); - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime * 0.5; - } - else - { - TaskFail(); - ALERT( at_aiconsole, "Failed to move!\n" ); - //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); - } - return; - } - } - } - - // UNDONE: this is a hack to quit moving farther than it has looked ahead. - if (flCheckDist < flMoveDist) - { - MoveExecute( pTargetEnt, vecDir, flCheckDist / m_flGroundSpeed ); - - // ALERT( at_console, "%.02f\n", flInterval ); - AdvanceRoute( flWaypointDist ); - flMoveDist -= flCheckDist; - } - else - { - MoveExecute( pTargetEnt, vecDir, flMoveDist / m_flGroundSpeed ); - - if ( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) - { - AdvanceRoute( flWaypointDist ); - } - flMoveDist = 0; - } - - if ( MovementIsComplete() ) - { - Stop(); - RouteClear(); - } - } while (flMoveDist > 0 && flCheckDist > 0); - - // cut corner? - if (flWaypointDist < 128) - { - if ( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - - if (m_flGroundSpeed > 100) - m_flGroundSpeed -= 40; - } - else - { - if (m_flGroundSpeed < 400) - m_flGroundSpeed += 10; - } -} - - - -BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) -{ - if ( flWaypointDist <= 32 ) - { - return TRUE; - } - - return FALSE; -} - - -int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - TraceResult tr; - - UTIL_TraceHull( vecStart + Vector( 0, 0, 32), vecEnd + Vector( 0, 0, 32), dont_ignore_monsters, large_hull, edict(), &tr ); - - // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); - // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); - - if (pflDist) - { - *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. - } - - // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); - if (tr.fStartSolid || tr.flFraction < 1.0) - { - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - return LOCALMOVE_VALID; - return LOCALMOVE_INVALID; - } - - return LOCALMOVE_VALID; -} - - -void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - if ( m_IdealActivity != m_movementActivity ) - m_IdealActivity = m_movementActivity; - - // ALERT( at_console, "move %.4f %.4f %.4f : %f\n", vecDir.x, vecDir.y, vecDir.z, flInterval ); - - // float flTotal = m_flGroundSpeed * pev->framerate * flInterval; - // UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flTotal, MOVE_STRAFE ); - - m_velocity = m_velocity * 0.8 + m_flGroundSpeed * vecDir * 0.2; - - UTIL_MoveToOrigin ( ENT(pev), pev->origin + m_velocity, m_velocity.Length() * flInterval, MOVE_STRAFE ); - -} - - - - -//========================================================= -// Controller bouncy ball attack -//========================================================= -class CControllerHeadBall : public CBaseMonster -{ - void Spawn( void ); - void Precache( void ); - void EXPORT HuntThink( void ); - void EXPORT DieThink( void ); - void EXPORT BounceTouch( CBaseEntity *pOther ); - void MovetoTarget( Vector vecTarget ); - void Crawl( void ); - int m_iTrail; - int m_flNextAttack; - Vector m_vecIdeal; - EHANDLE m_hOwner; -}; -LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ); - - - -void CControllerHeadBall :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "sprites/xspark4.spr"); - pev->rendermode = kRenderTransAdd; - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->renderamt = 255; - pev->scale = 2.0; - - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CControllerHeadBall::HuntThink ); - SetTouch( &CControllerHeadBall::BounceTouch ); - - m_vecIdeal = Vector( 0, 0, 0 ); - - pev->nextthink = gpGlobals->time + 0.1; - - m_hOwner = Instance( pev->owner ); - pev->dmgtime = gpGlobals->time; -} - - -void CControllerHeadBall :: Precache( void ) -{ - PRECACHE_MODEL("sprites/xspark1.spr"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); -} - - -void CControllerHeadBall :: HuntThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - pev->renderamt -= 5; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( pev->renderamt / 16 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - - // check world boundaries - if (gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == NULL || m_hOwner == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - MovetoTarget( m_hEnemy->Center( ) ); - - if ((m_hEnemy->Center() - pev->origin).Length() < 64) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, ENT(pev), &tr ); - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - if (pEntity != NULL && pEntity->pev->takedamage) - { - ClearMultiDamage( ); - pEntity->TraceAttack( m_hOwner->pev, gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK ); - ApplyMultiDamage( pev, m_hOwner->pev ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - - m_flNextAttack = gpGlobals->time + 3.0; - - SetThink( &CControllerHeadBall::DieThink ); - pev->nextthink = gpGlobals->time + 0.3; - } - - // Crawl( ); -} - - -void CControllerHeadBall :: DieThink( void ) -{ - UTIL_Remove( this ); -} - - -void CControllerHeadBall :: MovetoTarget( Vector vecTarget ) -{ - // accelerate - float flSpeed = m_vecIdeal.Length(); - if (flSpeed == 0) - { - m_vecIdeal = pev->velocity; - flSpeed = m_vecIdeal.Length(); - } - - if (flSpeed > 400) - { - m_vecIdeal = m_vecIdeal.Normalize( ) * 400; - } - m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 100; - pev->velocity = m_vecIdeal; -} - - - -void CControllerHeadBall :: Crawl( void ) -{ - - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); - Vector vecPnt = pev->origin + pev->velocity * 0.3 + vecAim * 64; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( vecPnt.x); - WRITE_COORD( vecPnt.y); - WRITE_COORD( vecPnt.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); -} - - -void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) -{ - Vector vecDir = m_vecIdeal.Normalize( ); - - TraceResult tr = UTIL_GetGlobalTrace( ); - - float n = -DotProduct(tr.vecPlaneNormal, vecDir); - - vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; - - m_vecIdeal = vecDir * m_vecIdeal.Length(); -} - - - - -class CControllerZapBall : public CBaseMonster -{ - void Spawn( void ); - void Precache( void ); - void EXPORT AnimateThink( void ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - - EHANDLE m_hOwner; -}; -LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ); - - -void CControllerZapBall :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "sprites/xspark4.spr"); - pev->rendermode = kRenderTransAdd; - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->renderamt = 255; - pev->scale = 0.5; - - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CControllerZapBall::AnimateThink ); - SetTouch( &CControllerZapBall::ExplodeTouch ); - - m_hOwner = Instance( pev->owner ); - pev->dmgtime = gpGlobals->time; // keep track of when ball spawned - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CControllerZapBall :: Precache( void ) -{ - PRECACHE_MODEL("sprites/xspark4.spr"); - // PRECACHE_SOUND("debris/zap4.wav"); - // PRECACHE_SOUND("weapons/electro4.wav"); -} - - -void CControllerZapBall :: AnimateThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - pev->frame = ((int)pev->frame + 1) % 11; - - if (gpGlobals->time - pev->dmgtime > 5 || pev->velocity.Length() < 10) - { - SetTouch( NULL ); - UTIL_Remove( this ); - } -} - - -void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) -{ - if (pOther->pev->takedamage) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - - entvars_t *pevOwner; - if (m_hOwner != NULL) - { - pevOwner = m_hOwner->pev; - } - else - { - pevOwner = pev; - } - - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pevOwner, pevOwner ); - - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) ); - - } - - UTIL_Remove( this ); -} - - - -#endif // !OEM && !HLDEMO +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +//========================================================= +// CONTROLLER +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "effects.h" +#include "schedule.h" +#include "weapons.h" +#include "squadmonster.h" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define CONTROLLER_AE_HEAD_OPEN 1 +#define CONTROLLER_AE_BALL_SHOOT 2 +#define CONTROLLER_AE_SMALL_SHOOT 3 +#define CONTROLLER_AE_POWERUP_FULL 4 +#define CONTROLLER_AE_POWERUP_HALF 5 + +#define CONTROLLER_FLINCH_DELAY 2 // at most one flinch every n secs + +class CController : public CSquadMonster +{ +public: + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + + void RunAI( void ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); // balls + BOOL CheckRangeAttack2 ( float flDot, float flDist ); // head + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); // block, throw + Schedule_t* GetSchedule ( void ); + Schedule_t* GetScheduleOfType ( int Type ); + void StartTask ( Task_t *pTask ); + void RunTask ( Task_t *pTask ); + CUSTOM_SCHEDULES; + + void Stop( void ); + void Move ( float flInterval ); + int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ); + void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); + void SetActivity ( Activity NewActivity ); + BOOL ShouldAdvanceRoute( float flWaypointDist ); + int LookupFloat( ); + + float m_flNextFlinch; + + float m_flShootTime; + float m_flShootEnd; + + void PainSound( void ); + void AlertSound( void ); + void IdleSound( void ); + void AttackSound( void ); + void DeathSound( void ); + + static const char *pAttackSounds[]; + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + static const char *pPainSounds[]; + static const char *pDeathSounds[]; + + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + void Killed( entvars_t *pevAttacker, int iGib ); + void GibMonster( void ); + + CSprite *m_pBall[2]; // hand balls + int m_iBall[2]; // how bright it should be + float m_iBallTime[2]; // when it should be that color + int m_iBallCurrent[2]; // current brightness + + Vector m_vecEstVelocity; + + Vector m_velocity; + int m_fInCombat; +}; + +LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ); + +TYPEDESCRIPTION CController::m_SaveData[] = +{ + DEFINE_ARRAY( CController, m_pBall, FIELD_CLASSPTR, 2 ), + DEFINE_ARRAY( CController, m_iBall, FIELD_INTEGER, 2 ), + DEFINE_ARRAY( CController, m_iBallTime, FIELD_TIME, 2 ), + DEFINE_ARRAY( CController, m_iBallCurrent, FIELD_INTEGER, 2 ), + DEFINE_FIELD( CController, m_vecEstVelocity, FIELD_VECTOR ), +}; +IMPLEMENT_SAVERESTORE( CController, CSquadMonster ); + + +const char *CController::pAttackSounds[] = +{ + "controller/con_attack1.wav", + "controller/con_attack2.wav", + "controller/con_attack3.wav", +}; + +const char *CController::pIdleSounds[] = +{ + "controller/con_idle1.wav", + "controller/con_idle2.wav", + "controller/con_idle3.wav", + "controller/con_idle4.wav", + "controller/con_idle5.wav", +}; + +const char *CController::pAlertSounds[] = +{ + "controller/con_alert1.wav", + "controller/con_alert2.wav", + "controller/con_alert3.wav", +}; + +const char *CController::pPainSounds[] = +{ + "controller/con_pain1.wav", + "controller/con_pain2.wav", + "controller/con_pain3.wav", +}; + +const char *CController::pDeathSounds[] = +{ + "controller/con_die1.wav", + "controller/con_die2.wav", +}; + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CController :: Classify ( void ) +{ + return CLASS_ALIEN_MILITARY; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CController :: SetYawSpeed ( void ) +{ + int ys; + + ys = 120; + +#if 0 + switch ( m_Activity ) + { + } +#endif + + pev->yaw_speed = ys; +} + +int CController :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + // HACK HACK -- until we fix this. + if ( IsAlive() ) + PainSound(); + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + + +void CController::Killed( entvars_t *pevAttacker, int iGib ) +{ + // shut off balls + /* + m_iBall[0] = 0; + m_iBallTime[0] = gpGlobals->time + 4.0; + m_iBall[1] = 0; + m_iBallTime[1] = gpGlobals->time + 4.0; + */ + + // fade balls + if (m_pBall[0]) + { + m_pBall[0]->SUB_StartFadeOut(); + m_pBall[0] = NULL; + } + if (m_pBall[1]) + { + m_pBall[1]->SUB_StartFadeOut(); + m_pBall[1] = NULL; + } + + CSquadMonster::Killed( pevAttacker, iGib ); +} + + +void CController::GibMonster( void ) +{ + // delete balls + if (m_pBall[0]) + { + UTIL_Remove( m_pBall[0] ); + m_pBall[0] = NULL; + } + if (m_pBall[1]) + { + UTIL_Remove( m_pBall[1] ); + m_pBall[1] = NULL; + } + CSquadMonster::GibMonster( ); +} + + + + +void CController :: PainSound( void ) +{ + if (RANDOM_LONG(0,5) < 2) + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); +} + +void CController :: AlertSound( void ) +{ + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); +} + +void CController :: IdleSound( void ) +{ + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pIdleSounds ); +} + +void CController :: AttackSound( void ) +{ + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAttackSounds ); +} + +void CController :: DeathSound( void ) +{ + EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case CONTROLLER_AE_HEAD_OPEN: + { + Vector vecStart, angleGun; + + GetAttachment( 0, vecStart, angleGun ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment + WRITE_COORD( vecStart.x ); // origin + WRITE_COORD( vecStart.y ); + WRITE_COORD( vecStart.z ); + WRITE_COORD( 1 ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 192 ); // G + WRITE_BYTE( 64 ); // B + WRITE_BYTE( 20 ); // life * 10 + WRITE_COORD( -32 ); // decay + MESSAGE_END(); + + m_iBall[0] = 192; + m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; + m_iBall[1] = 255; + m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; + + } + break; + + case CONTROLLER_AE_BALL_SHOOT: + { + Vector vecStart, angleGun; + + GetAttachment( 0, vecStart, angleGun ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment + WRITE_COORD( 0 ); // origin + WRITE_COORD( 0 ); + WRITE_COORD( 0 ); + WRITE_COORD( 32 ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 192 ); // G + WRITE_BYTE( 64 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 32 ); // decay + MESSAGE_END(); + + CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, pev->angles, edict() ); + + pBall->pev->velocity = Vector( 0, 0, 32 ); + pBall->m_hEnemy = m_hEnemy; + + m_iBall[0] = 0; + m_iBall[1] = 0; + } + break; + + case CONTROLLER_AE_SMALL_SHOOT: + { + AttackSound( ); + m_flShootTime = gpGlobals->time; + m_flShootEnd = m_flShootTime + atoi( pEvent->options ) / 15.0; + } + break; + case CONTROLLER_AE_POWERUP_FULL: + { + m_iBall[0] = 255; + m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; + m_iBall[1] = 255; + m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; + } + break; + case CONTROLLER_AE_POWERUP_HALF: + { + m_iBall[0] = 192; + m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; + m_iBall[1] = 192; + m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; + } + break; + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CController :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/controller.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 )); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_FLY; + pev->flags |= FL_FLY; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = gSkillData.controllerHealth; + pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin. + m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CController :: Precache() +{ + PRECACHE_MODEL("models/controller.mdl"); + + PRECACHE_SOUND_ARRAY( pAttackSounds ); + PRECACHE_SOUND_ARRAY( pIdleSounds ); + PRECACHE_SOUND_ARRAY( pAlertSounds ); + PRECACHE_SOUND_ARRAY( pPainSounds ); + PRECACHE_SOUND_ARRAY( pDeathSounds ); + + PRECACHE_MODEL( "sprites/xspark4.spr"); + + UTIL_PrecacheOther( "controller_energy_ball" ); + UTIL_PrecacheOther( "controller_head_ball" ); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + + +// Chase enemy schedule +Task_t tlControllerChaseEnemy[] = +{ + { TASK_GET_PATH_TO_ENEMY, (float)128 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + +}; + +Schedule_t slControllerChaseEnemy[] = +{ + { + tlControllerChaseEnemy, + ARRAYSIZE ( tlControllerChaseEnemy ), + bits_COND_NEW_ENEMY | + bits_COND_TASK_FAILED, + 0, + "ControllerChaseEnemy" + }, +}; + + + +Task_t tlControllerStrafe[] = +{ + { TASK_WAIT, (float)0.2 }, + { TASK_GET_PATH_TO_ENEMY, (float)128 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_WAIT, (float)1 }, +}; + +Schedule_t slControllerStrafe[] = +{ + { + tlControllerStrafe, + ARRAYSIZE ( tlControllerStrafe ), + bits_COND_NEW_ENEMY, + 0, + "ControllerStrafe" + }, +}; + + +Task_t tlControllerTakeCover[] = +{ + { TASK_WAIT, (float)0.2 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_WAIT, (float)1 }, +}; + +Schedule_t slControllerTakeCover[] = +{ + { + tlControllerTakeCover, + ARRAYSIZE ( tlControllerTakeCover ), + bits_COND_NEW_ENEMY, + 0, + "ControllerTakeCover" + }, +}; + + +Task_t tlControllerFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slControllerFail[] = +{ + { + tlControllerFail, + ARRAYSIZE ( tlControllerFail ), + 0, + 0, + "ControllerFail" + }, +}; + + + +DEFINE_CUSTOM_SCHEDULES( CController ) +{ + slControllerChaseEnemy, + slControllerStrafe, + slControllerTakeCover, + slControllerFail, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ); + + + +//========================================================= +// StartTask +//========================================================= +void CController :: StartTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_RANGE_ATTACK1: + CSquadMonster :: StartTask ( pTask ); + break; + case TASK_GET_PATH_TO_ENEMY_LKP: + { + if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, pTask->flData, (m_vecEnemyLKP - pev->origin).Length() + 1024 )) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_ENEMY: + { + CBaseEntity *pEnemy = m_hEnemy; + + if ( pEnemy == NULL ) + { + TaskFail(); + return; + } + + if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, pTask->flData, (pEnemy->pev->origin - pev->origin).Length() + 1024 )) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); + TaskFail(); + } + break; + } + default: + CSquadMonster :: StartTask ( pTask ); + break; + } +} + + +Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) +{ + Vector vecTo = vecDst - vecSrc; + + float a = DotProduct( vecMove, vecMove ) - flSpeed * flSpeed; + float b = 0 * DotProduct(vecTo, vecMove); // why does this work? + float c = DotProduct( vecTo, vecTo ); + + float t; + if (a == 0) + { + t = c / (flSpeed * flSpeed); + } + else + { + t = b * b - 4 * a * c; + t = sqrt( t ) / (2.0 * a); + float t1 = -b +t; + float t2 = -b -t; + + if (t1 < 0 || t2 < t1) + t = t2; + else + t = t1; + } + + // ALERT( at_console, "Intersect %f\n", t ); + + if (t < 0.1) + t = 0.1; + if (t > 10.0) + t = 10.0; + + Vector vecHit = vecTo + vecMove * t; + return vecHit.Normalize( ) * flSpeed; +} + + +int CController::LookupFloat( ) +{ + if (m_velocity.Length( ) < 32.0) + { + return LookupSequence( "up" ); + } + + UTIL_MakeAimVectors( pev->angles ); + float x = DotProduct( gpGlobals->v_forward, m_velocity ); + float y = DotProduct( gpGlobals->v_right, m_velocity ); + float z = DotProduct( gpGlobals->v_up, m_velocity ); + + if (fabs(x) > fabs(y) && fabs(x) > fabs(z)) + { + if (x > 0) + return LookupSequence( "forward"); + else + return LookupSequence( "backward"); + } + else if (fabs(y) > fabs(z)) + { + if (y > 0) + return LookupSequence( "right"); + else + return LookupSequence( "left"); + } + else + { + if (z > 0) + return LookupSequence( "up"); + else + return LookupSequence( "down"); + } +} + + +//========================================================= +// RunTask +//========================================================= +void CController :: RunTask ( Task_t *pTask ) +{ + + if (m_flShootEnd > gpGlobals->time) + { + Vector vecHand, vecAngle; + + GetAttachment( 2, vecHand, vecAngle ); + + while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) + { + Vector vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); + Vector vecDir; + + if (m_hEnemy != NULL) + { + if (HasConditions( bits_COND_SEE_ENEMY )) + { + m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5; + } + else + { + m_vecEstVelocity = m_vecEstVelocity * 0.8; + } + vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); + float delta = 0.03490; // +-2 degree + vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall; + + vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); + CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() ); + pBall->pev->velocity = vecDir; + } + m_flShootTime += 0.2; + } + + if (m_flShootTime > m_flShootEnd) + { + m_iBall[0] = 64; + m_iBallTime[0] = m_flShootEnd; + m_iBall[1] = 64; + m_iBallTime[1] = m_flShootEnd; + m_fInCombat = FALSE; + } + } + + switch ( pTask->iTask ) + { + case TASK_WAIT_FOR_MOVEMENT: + case TASK_WAIT: + case TASK_WAIT_FACE_ENEMY: + case TASK_WAIT_PVS: + MakeIdealYaw( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); + + if (m_fSequenceFinished) + { + m_fInCombat = FALSE; + } + + CSquadMonster :: RunTask ( pTask ); + + if (!m_fInCombat) + { + if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) + { + pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 ); + pev->frame = 0; + ResetSequenceInfo( ); + m_fInCombat = TRUE; + } + else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) + { + pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 ); + pev->frame = 0; + ResetSequenceInfo( ); + m_fInCombat = TRUE; + } + else + { + int iFloat = LookupFloat( ); + if (m_fSequenceFinished || iFloat != pev->sequence) + { + pev->sequence = iFloat; + pev->frame = 0; + ResetSequenceInfo( ); + } + } + } + break; + default: + CSquadMonster :: RunTask ( pTask ); + break; + } +} + + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CController :: GetSchedule ( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_IDLE: + break; + + case MONSTERSTATE_ALERT: + break; + + case MONSTERSTATE_COMBAT: + { + Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); + + // dead enemy + if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) + { + // m_iFrustration++; + } + if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + { + // m_iFrustration++; + } + } + break; + } + + return CSquadMonster :: GetSchedule(); +} + + + +//========================================================= +//========================================================= +Schedule_t* CController :: GetScheduleOfType ( int Type ) +{ + // ALERT( at_console, "%d\n", m_iFrustration ); + switch ( Type ) + { + case SCHED_CHASE_ENEMY: + return slControllerChaseEnemy; + case SCHED_RANGE_ATTACK1: + return slControllerStrafe; + case SCHED_RANGE_ATTACK2: + case SCHED_MELEE_ATTACK1: + case SCHED_MELEE_ATTACK2: + case SCHED_TAKE_COVER_FROM_ENEMY: + return slControllerTakeCover; + case SCHED_FAIL: + return slControllerFail; + } + + return CBaseMonster :: GetScheduleOfType( Type ); +} + + + + + +//========================================================= +// CheckRangeAttack1 - shoot a bigass energy ball out of their head +// +//========================================================= +BOOL CController :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( flDot > 0.5 && flDist > 256 && flDist <= 2048 ) + { + return TRUE; + } + return FALSE; +} + + +BOOL CController :: CheckRangeAttack2 ( float flDot, float flDist ) +{ + if ( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) + { + return TRUE; + } + return FALSE; +} + + +BOOL CController :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + return FALSE; +} + + +void CController :: SetActivity ( Activity NewActivity ) +{ + CBaseMonster::SetActivity( NewActivity ); + + switch ( m_Activity) + { + case ACT_WALK: + m_flGroundSpeed = 100; + break; + default: + m_flGroundSpeed = 100; + break; + } +} + + + +//========================================================= +// RunAI +//========================================================= +void CController :: RunAI( void ) +{ + CBaseMonster :: RunAI(); + Vector vecStart, angleGun; + + if ( HasMemory( bits_MEMORY_KILLED ) ) + return; + + for (int i = 0; i < 2; i++) + { + if (m_pBall[i] == NULL) + { + m_pBall[i] = CSprite::SpriteCreate( "sprites/xspark4.spr", pev->origin, TRUE ); + m_pBall[i]->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); + m_pBall[i]->SetAttachment( edict(), (i + 3) ); + m_pBall[i]->SetScale( 1.0 ); + } + + float t = m_iBallTime[i] - gpGlobals->time; + if (t > 0.1) + t = 0.1 / t; + else + t = 1.0; + + m_iBallCurrent[i] += (m_iBall[i] - m_iBallCurrent[i]) * t; + + m_pBall[i]->SetBrightness( m_iBallCurrent[i] ); + + GetAttachment( i + 2, vecStart, angleGun ); + UTIL_SetOrigin( m_pBall[i]->pev, vecStart ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x1000 * (i + 3) ); // entity, attachment + WRITE_COORD( vecStart.x ); // origin + WRITE_COORD( vecStart.y ); + WRITE_COORD( vecStart.z ); + WRITE_COORD( m_iBallCurrent[i] / 8 ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 192 ); // G + WRITE_BYTE( 64 ); // B + WRITE_BYTE( 5 ); // life * 10 + WRITE_COORD( 0 ); // decay + MESSAGE_END(); + } +} + + +extern void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ); + +void CController::Stop( void ) +{ + m_IdealActivity = GetStoppedActivity(); +} + + +#define DIST_TO_CHECK 200 +void CController :: Move ( float flInterval ) +{ + float flWaypointDist; + float flCheckDist; + float flDist;// how far the lookahead check got before hitting an object. + float flMoveDist; + Vector vecDir; + Vector vecApex; + CBaseEntity *pTargetEnt; + + // Don't move if no valid route + if ( FRouteClear() ) + { + ALERT( at_aiconsole, "Tried to move with no route!\n" ); + TaskFail(); + return; + } + + if ( m_flMoveWaitFinished > gpGlobals->time ) + return; + +// Debug, test movement code +#if 0 +// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) + { + if ( m_movementGoal == MOVEGOAL_ENEMY ) + RouteSimplify( m_hEnemy ); + else + RouteSimplify( m_hTargetEnt ); + FRefreshRoute(); + return; + } +#else +// Debug, draw the route +// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); +#endif + + // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer + // to that entity for the CheckLocalMove and Triangulate functions. + pTargetEnt = NULL; + + if (m_flGroundSpeed == 0) + { + m_flGroundSpeed = 100; + // TaskFail( ); + // return; + } + + flMoveDist = m_flGroundSpeed * flInterval; + + do + { + // local move to waypoint. + vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); + flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); + + // MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); + // ChangeYaw ( pev->yaw_speed ); + + // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint + if ( flWaypointDist < DIST_TO_CHECK ) + { + flCheckDist = flWaypointDist; + } + else + { + flCheckDist = DIST_TO_CHECK; + } + + if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) + { + // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) + pTargetEnt = m_hEnemy; + } + else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) + { + pTargetEnt = m_hTargetEnt; + } + + // !!!BUGBUG - CheckDist should be derived from ground speed. + // If this fails, it should be because of some dynamic entity blocking this guy. + // We've already checked this path, so we should wait and time out if the entity doesn't move + flDist = 0; + if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) + { + CBaseEntity *pBlocker; + + // Can't move, stop + Stop(); + // Blocking entity is in global trace_ent + pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); + if (pBlocker) + { + DispatchBlocked( edict(), pBlocker->edict() ); + } + if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) + { + // Can we still move toward our target? + if ( flDist < m_flGroundSpeed ) + { + // Wait for a second + m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; + // ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); + return; + } + } + else + { + // try to triangulate around whatever is in the way. + if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) + { + InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); + RouteSimplify( pTargetEnt ); + } + else + { + ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); + Stop(); + if ( m_moveWaitTime > 0 ) + { + FRefreshRoute(); + m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime * 0.5; + } + else + { + TaskFail(); + ALERT( at_aiconsole, "Failed to move!\n" ); + //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); + } + return; + } + } + } + + // UNDONE: this is a hack to quit moving farther than it has looked ahead. + if (flCheckDist < flMoveDist) + { + MoveExecute( pTargetEnt, vecDir, flCheckDist / m_flGroundSpeed ); + + // ALERT( at_console, "%.02f\n", flInterval ); + AdvanceRoute( flWaypointDist ); + flMoveDist -= flCheckDist; + } + else + { + MoveExecute( pTargetEnt, vecDir, flMoveDist / m_flGroundSpeed ); + + if ( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) + { + AdvanceRoute( flWaypointDist ); + } + flMoveDist = 0; + } + + if ( MovementIsComplete() ) + { + Stop(); + RouteClear(); + } + } while (flMoveDist > 0 && flCheckDist > 0); + + // cut corner? + if (flWaypointDist < 128) + { + if ( m_movementGoal == MOVEGOAL_ENEMY ) + RouteSimplify( m_hEnemy ); + else + RouteSimplify( m_hTargetEnt ); + FRefreshRoute(); + + if (m_flGroundSpeed > 100) + m_flGroundSpeed -= 40; + } + else + { + if (m_flGroundSpeed < 400) + m_flGroundSpeed += 10; + } +} + + + +BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) +{ + if ( flWaypointDist <= 32 ) + { + return TRUE; + } + + return FALSE; +} + + +int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) +{ + TraceResult tr; + + UTIL_TraceHull( vecStart + Vector( 0, 0, 32), vecEnd + Vector( 0, 0, 32), dont_ignore_monsters, large_hull, edict(), &tr ); + + // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); + // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); + + if (pflDist) + { + *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. + } + + // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); + if (tr.fStartSolid || tr.flFraction < 1.0) + { + if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) + return LOCALMOVE_VALID; + return LOCALMOVE_INVALID; + } + + return LOCALMOVE_VALID; +} + + +void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) +{ + if ( m_IdealActivity != m_movementActivity ) + m_IdealActivity = m_movementActivity; + + // ALERT( at_console, "move %.4f %.4f %.4f : %f\n", vecDir.x, vecDir.y, vecDir.z, flInterval ); + + // float flTotal = m_flGroundSpeed * pev->framerate * flInterval; + // UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flTotal, MOVE_STRAFE ); + + m_velocity = m_velocity * 0.8 + m_flGroundSpeed * vecDir * 0.2; + + UTIL_MoveToOrigin ( ENT(pev), pev->origin + m_velocity, m_velocity.Length() * flInterval, MOVE_STRAFE ); + +} + + + + +//========================================================= +// Controller bouncy ball attack +//========================================================= +class CControllerHeadBall : public CBaseMonster +{ + void Spawn( void ); + void Precache( void ); + void EXPORT HuntThink( void ); + void EXPORT DieThink( void ); + void EXPORT BounceTouch( CBaseEntity *pOther ); + void MovetoTarget( Vector vecTarget ); + void Crawl( void ); + int m_iTrail; + int m_flNextAttack; + Vector m_vecIdeal; + EHANDLE m_hOwner; +}; +LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ); + + + +void CControllerHeadBall :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "sprites/xspark4.spr"); + pev->rendermode = kRenderTransAdd; + pev->rendercolor.x = 255; + pev->rendercolor.y = 255; + pev->rendercolor.z = 255; + pev->renderamt = 255; + pev->scale = 2.0; + + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetOrigin( pev, pev->origin ); + + SetThink( &CControllerHeadBall::HuntThink ); + SetTouch( &CControllerHeadBall::BounceTouch ); + + m_vecIdeal = Vector( 0, 0, 0 ); + + pev->nextthink = gpGlobals->time + 0.1; + + m_hOwner = Instance( pev->owner ); + pev->dmgtime = gpGlobals->time; +} + + +void CControllerHeadBall :: Precache( void ) +{ + PRECACHE_MODEL("sprites/xspark1.spr"); + PRECACHE_SOUND("debris/zap4.wav"); + PRECACHE_SOUND("weapons/electro4.wav"); +} + + +void CControllerHeadBall :: HuntThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + pev->renderamt -= 5; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( pev->renderamt / 16 ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 255 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 2 ); // life * 10 + WRITE_COORD( 0 ); // decay + MESSAGE_END(); + + // check world boundaries + if (gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == NULL || m_hOwner == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + { + SetTouch( NULL ); + UTIL_Remove( this ); + return; + } + + MovetoTarget( m_hEnemy->Center( ) ); + + if ((m_hEnemy->Center() - pev->origin).Length() < 64) + { + TraceResult tr; + + UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, ENT(pev), &tr ); + + CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + if (pEntity != NULL && pEntity->pev->takedamage) + { + ClearMultiDamage( ); + pEntity->TraceAttack( m_hOwner->pev, gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK ); + ApplyMultiDamage( pev, m_hOwner->pev ); + } + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTPOINT ); + WRITE_SHORT( entindex() ); + WRITE_COORD( tr.vecEndPos.x ); + WRITE_COORD( tr.vecEndPos.y ); + WRITE_COORD( tr.vecEndPos.z ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 3 ); // life + WRITE_BYTE( 20 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); + + UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); + + m_flNextAttack = gpGlobals->time + 3.0; + + SetThink( &CControllerHeadBall::DieThink ); + pev->nextthink = gpGlobals->time + 0.3; + } + + // Crawl( ); +} + + +void CControllerHeadBall :: DieThink( void ) +{ + UTIL_Remove( this ); +} + + +void CControllerHeadBall :: MovetoTarget( Vector vecTarget ) +{ + // accelerate + float flSpeed = m_vecIdeal.Length(); + if (flSpeed == 0) + { + m_vecIdeal = pev->velocity; + flSpeed = m_vecIdeal.Length(); + } + + if (flSpeed > 400) + { + m_vecIdeal = m_vecIdeal.Normalize( ) * 400; + } + m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 100; + pev->velocity = m_vecIdeal; +} + + + +void CControllerHeadBall :: Crawl( void ) +{ + + Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); + Vector vecPnt = pev->origin + pev->velocity * 0.3 + vecAim * 64; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTPOINT ); + WRITE_SHORT( entindex() ); + WRITE_COORD( vecPnt.x); + WRITE_COORD( vecPnt.y); + WRITE_COORD( vecPnt.z); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 3 ); // life + WRITE_BYTE( 20 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); +} + + +void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) +{ + Vector vecDir = m_vecIdeal.Normalize( ); + + TraceResult tr = UTIL_GetGlobalTrace( ); + + float n = -DotProduct(tr.vecPlaneNormal, vecDir); + + vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; + + m_vecIdeal = vecDir * m_vecIdeal.Length(); +} + + + + +class CControllerZapBall : public CBaseMonster +{ + void Spawn( void ); + void Precache( void ); + void EXPORT AnimateThink( void ); + void EXPORT ExplodeTouch( CBaseEntity *pOther ); + + EHANDLE m_hOwner; +}; +LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ); + + +void CControllerZapBall :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "sprites/xspark4.spr"); + pev->rendermode = kRenderTransAdd; + pev->rendercolor.x = 255; + pev->rendercolor.y = 255; + pev->rendercolor.z = 255; + pev->renderamt = 255; + pev->scale = 0.5; + + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetOrigin( pev, pev->origin ); + + SetThink( &CControllerZapBall::AnimateThink ); + SetTouch( &CControllerZapBall::ExplodeTouch ); + + m_hOwner = Instance( pev->owner ); + pev->dmgtime = gpGlobals->time; // keep track of when ball spawned + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CControllerZapBall :: Precache( void ) +{ + PRECACHE_MODEL("sprites/xspark4.spr"); + // PRECACHE_SOUND("debris/zap4.wav"); + // PRECACHE_SOUND("weapons/electro4.wav"); +} + + +void CControllerZapBall :: AnimateThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + pev->frame = ((int)pev->frame + 1) % 11; + + if (gpGlobals->time - pev->dmgtime > 5 || pev->velocity.Length() < 10) + { + SetTouch( NULL ); + UTIL_Remove( this ); + } +} + + +void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) +{ + if (pOther->pev->takedamage) + { + TraceResult tr = UTIL_GetGlobalTrace( ); + + entvars_t *pevOwner; + if (m_hOwner != NULL) + { + pevOwner = m_hOwner->pev; + } + else + { + pevOwner = pev; + } + + ClearMultiDamage( ); + pOther->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM ); + ApplyMultiDamage( pevOwner, pevOwner ); + + UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) ); + + } + + UTIL_Remove( this ); +} + + + +#endif // !OEM && !HLDEMO diff --git a/main/source/dlls/cpushable.h b/main/source/dlls/cpushable.h index 9bba5a2d..27ffd071 100644 --- a/main/source/dlls/cpushable.h +++ b/main/source/dlls/cpushable.h @@ -1,33 +1,33 @@ -#ifndef CPUSHABLE_H -#define CPUSHABLE_H - -class CPushable : public CBreakable -{ -public: - void Spawn ( void ); - void Precache( void ); - void Touch ( CBaseEntity *pOther ); - void Move( CBaseEntity *pMover, int push ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT StopSound( void ); -// virtual void SetActivator( CBaseEntity *pActivator ) { m_pPusher = pActivator; } - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_CONTINUOUS_USE; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - inline float MaxSpeed( void ) { return m_maxSpeed; } - - // breakables use an overridden takedamage - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - - static TYPEDESCRIPTION m_SaveData[]; - - static char *m_soundNames[3]; - int m_lastSound; // no need to save/restore, just keeps the same sound from playing twice in a row - float m_maxSpeed; - float m_soundTime; -}; - +#ifndef CPUSHABLE_H +#define CPUSHABLE_H + +class CPushable : public CBreakable +{ +public: + void Spawn ( void ); + void Precache( void ); + void Touch ( CBaseEntity *pOther ); + void Move( CBaseEntity *pMover, int push ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT StopSound( void ); +// virtual void SetActivator( CBaseEntity *pActivator ) { m_pPusher = pActivator; } + + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_CONTINUOUS_USE; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + inline float MaxSpeed( void ) { return m_maxSpeed; } + + // breakables use an overridden takedamage + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + + static TYPEDESCRIPTION m_SaveData[]; + + static char *m_soundNames[3]; + int m_lastSound; // no need to save/restore, just keeps the same sound from playing twice in a row + float m_maxSpeed; + float m_soundTime; +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/crossbow.cpp b/main/source/dlls/crossbow.cpp index 6feaec3b..dda92b28 100644 --- a/main/source/dlls/crossbow.cpp +++ b/main/source/dlls/crossbow.cpp @@ -1,548 +1,548 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -#ifndef CLIENT_DLL -#define BOLT_AIR_VELOCITY 2000 -#define BOLT_WATER_VELOCITY 1000 - -// UNDONE: Save/restore this? Don't forget to set classname and LINK_ENTITY_TO_CLASS() -// -// OVERLOADS SOME ENTVARS: -// -// speed - the ideal magnitude of my velocity -class CCrossbowBolt : public CBaseEntity -{ - void Spawn( void ); - void Precache( void ); - int Classify ( void ); - void EXPORT BubbleThink( void ); - void EXPORT BoltTouch( CBaseEntity *pOther ); - void EXPORT ExplodeThink( void ); - - int m_iTrail; - -public: - static CCrossbowBolt *BoltCreate( void ); -}; -LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ); - -CCrossbowBolt *CCrossbowBolt::BoltCreate( void ) -{ - // Create a new entity with CCrossbowBolt private data - CCrossbowBolt *pBolt = GetClassPtr( (CCrossbowBolt *)NULL ); - pBolt->pev->classname = MAKE_STRING("bolt"); - pBolt->Spawn(); - - return pBolt; -} - -void CCrossbowBolt::Spawn( ) -{ - Precache( ); - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->gravity = 0.5; - - SET_MODEL(ENT(pev), "models/crossbow_bolt.mdl"); - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - - SetTouch( &CCrossbowBolt::BoltTouch ); - SetThink( &CCrossbowBolt::BubbleThink ); - pev->nextthink = gpGlobals->time + 0.2; -} - - -void CCrossbowBolt::Precache( ) -{ - PRECACHE_MODEL ("models/crossbow_bolt.mdl"); - PRECACHE_SOUND("weapons/xbow_hitbod1.wav"); - PRECACHE_SOUND("weapons/xbow_hitbod2.wav"); - PRECACHE_SOUND("weapons/xbow_fly1.wav"); - PRECACHE_SOUND("weapons/xbow_hit1.wav"); - PRECACHE_SOUND("fvox/beep.wav"); - m_iTrail = PRECACHE_MODEL("sprites/streak.spr"); -} - - -int CCrossbowBolt :: Classify ( void ) -{ - return CLASS_NONE; -} - -void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) -{ - SetTouch( NULL ); - SetThink( NULL ); - - if (pOther->pev->takedamage) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - entvars_t *pevOwner; - - pevOwner = VARS( pev->owner ); - - // UNDONE: this needs to call TraceAttack instead - ClearMultiDamage( ); - - if ( pOther->IsPlayer() ) - { - pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); - } - else - { - pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB ); - } - - ApplyMultiDamage( pev, pevOwner ); - - pev->velocity = Vector( 0, 0, 0 ); - // play body "thwack" sound - switch( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break; - } - - if ( !g_pGameRules->IsMultiplayer() ) - { - Killed( pev, GIB_NEVER ); - } - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7)); - - SetThink( &CCrossbowBolt::SUB_Remove ); - pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit. - - if ( FClassnameIs( pOther->pev, "worldspawn" ) ) - { - // if what we hit is static architecture, can stay around for a while. - Vector vecDir = pev->velocity.Normalize( ); - UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); - pev->angles = UTIL_VecToAngles( vecDir ); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_FLY; - pev->velocity = Vector( 0, 0, 0 ); - pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG(0,360); - pev->nextthink = gpGlobals->time + 10.0; - } - - if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) - { - UTIL_Sparks( pev->origin ); - } - } - - if ( g_pGameRules->IsMultiplayer() ) - { - SetThink( &CCrossbowBolt::ExplodeThink ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -void CCrossbowBolt::BubbleThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->waterlevel == 0) - return; - - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); -} - -void CCrossbowBolt::ExplodeThink( void ) -{ - int iContents = UTIL_PointContents ( pev->origin ); - int iScale; - - pev->dmg = 40; - iScale = 10; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - if (iContents != CONTENTS_WATER) - { - WRITE_SHORT( g_sModelIndexFireball ); - } - else - { - WRITE_SHORT( g_sModelIndexWExplosion ); - } - WRITE_BYTE( iScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - entvars_t *pevOwner; - - if ( pev->owner ) - pevOwner = VARS( pev->owner ); - else - pevOwner = NULL; - - pev->owner = NULL; // can't traceline attack owner if this is set - - ::RadiusDamage( pev->origin, pev, pevOwner, pev->dmg, 128, CLASS_NONE, DMG_BLAST | DMG_ALWAYSGIB ); - - UTIL_Remove(this); -} -#endif - -enum crossbow_e { - CROSSBOW_IDLE1 = 0, // full - CROSSBOW_IDLE2, // empty - CROSSBOW_FIDGET1, // full - CROSSBOW_FIDGET2, // empty - CROSSBOW_FIRE1, // full - CROSSBOW_FIRE2, // reload - CROSSBOW_FIRE3, // empty - CROSSBOW_RELOAD, // from empty - CROSSBOW_DRAW1, // full - CROSSBOW_DRAW2, // empty - CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2, // empty -}; - -LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ); - -void CCrossbow::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_CROSSBOW; - SET_MODEL(ENT(pev), "models/w_crossbow.mdl"); - - m_iDefaultAmmo = CROSSBOW_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -int CCrossbow::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CCrossbow::Precache( void ) -{ - PRECACHE_MODEL("models/w_crossbow.mdl"); - PRECACHE_MODEL("models/v_crossbow.mdl"); - PRECACHE_MODEL("models/p_crossbow.mdl"); - - PRECACHE_SOUND("weapons/xbow_fire1.wav"); - PRECACHE_SOUND("weapons/xbow_reload1.wav"); - - UTIL_PrecacheOther( "crossbow_bolt" ); - - m_usCrossbow = PRECACHE_EVENT( 1, "events/crossbow1.sc" ); - m_usCrossbow2 = PRECACHE_EVENT( 1, "events/crossbow2.sc" ); -} - - -int CCrossbow::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "bolts"; - p->iMaxAmmo1 = BOLT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = CROSSBOW_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 2; - p->iId = WEAPON_CROSSBOW; - p->iFlags = 0; - p->iWeight = CROSSBOW_WEIGHT; - return 1; -} - - -BOOL CCrossbow::Deploy( ) -{ - if (m_iClip) - return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW1, "bow" ); - return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" ); -} - -void CCrossbow::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - if ( m_fInZoom ) - { - SecondaryAttack( ); - } - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if (m_iClip) - SendWeaponAnim( CROSSBOW_HOLSTER1 ); - else - SendWeaponAnim( CROSSBOW_HOLSTER2 ); -} - -void CCrossbow::PrimaryAttack( void ) -{ - -#ifdef CLIENT_DLL - if ( m_fInZoom && bIsMultiplayer() ) -#else - if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) -#endif - { - FireSniperBolt(); - return; - } - - FireBolt(); -} - -// this function only gets called in multiplayer -void CCrossbow::FireSniperBolt() -{ - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; - - if (m_iClip == 0) - { - PlayEmptySound( ); - return; - } - - TraceResult tr; - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - - UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr); - -#ifndef CLIENT_DLL - if ( tr.pHit->v.takedamage ) - { - ClearMultiDamage( ); - CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); - ApplyMultiDamage( pev, m_pPlayer->pev ); - } -#endif -} - -void CCrossbow::FireBolt() -{ - TraceResult tr; - - if (m_iClip == 0) - { - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - - anglesAim.x = -anglesAim.x; - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - -#ifndef CLIENT_DLL - CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); - pBolt->pev->origin = vecSrc; - pBolt->pev->angles = anglesAim; - pBolt->pev->owner = m_pPlayer->edict(); - - if (m_pPlayer->pev->waterlevel == 3) - { - pBolt->pev->velocity = vecDir * BOLT_WATER_VELOCITY; - pBolt->pev->speed = BOLT_WATER_VELOCITY; - } - else - { - pBolt->pev->velocity = vecDir * BOLT_AIR_VELOCITY; - pBolt->pev->speed = BOLT_AIR_VELOCITY; - } - pBolt->pev->avelocity.z = 10; -#endif - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; -} - - -void CCrossbow::SecondaryAttack() -{ - if ( m_pPlayer->pev->fov != 0 ) - { - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - m_fInZoom = 0; - } - else if ( m_pPlayer->pev->fov != 20 ) - { - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 20; - m_fInZoom = 1; - } - - pev->nextthink = UTIL_WeaponTimeBase() + 0.1; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; -} - - -void CCrossbow::Reload( void ) -{ - if ( m_pPlayer->ammo_bolts <= 0 ) - return; - - if ( m_pPlayer->pev->fov != 0 ) - { - SecondaryAttack(); - } - - if ( DefaultReload( 5, CROSSBOW_RELOAD, 4.5 ) ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF)); - } -} - - -void CCrossbow::WeaponIdle( void ) -{ - m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM - - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - if (m_iClip) - { - SendWeaponAnim( CROSSBOW_IDLE1 ); - } - else - { - SendWeaponAnim( CROSSBOW_IDLE2 ); - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - if (m_iClip) - { - SendWeaponAnim( CROSSBOW_FIDGET1 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; - } - else - { - SendWeaponAnim( CROSSBOW_FIDGET2 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 30.0; - } - } - } -} - - - -class CCrossbowAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_crossbow_clip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_crossbow_clip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ); - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" + +#ifndef CLIENT_DLL +#define BOLT_AIR_VELOCITY 2000 +#define BOLT_WATER_VELOCITY 1000 + +// UNDONE: Save/restore this? Don't forget to set classname and LINK_ENTITY_TO_CLASS() +// +// OVERLOADS SOME ENTVARS: +// +// speed - the ideal magnitude of my velocity +class CCrossbowBolt : public CBaseEntity +{ + void Spawn( void ); + void Precache( void ); + int Classify ( void ); + void EXPORT BubbleThink( void ); + void EXPORT BoltTouch( CBaseEntity *pOther ); + void EXPORT ExplodeThink( void ); + + int m_iTrail; + +public: + static CCrossbowBolt *BoltCreate( void ); +}; +LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ); + +CCrossbowBolt *CCrossbowBolt::BoltCreate( void ) +{ + // Create a new entity with CCrossbowBolt private data + CCrossbowBolt *pBolt = GetClassPtr( (CCrossbowBolt *)NULL ); + pBolt->pev->classname = MAKE_STRING("bolt"); + pBolt->Spawn(); + + return pBolt; +} + +void CCrossbowBolt::Spawn( ) +{ + Precache( ); + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + pev->gravity = 0.5; + + SET_MODEL(ENT(pev), "models/crossbow_bolt.mdl"); + + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); + + SetTouch( &CCrossbowBolt::BoltTouch ); + SetThink( &CCrossbowBolt::BubbleThink ); + pev->nextthink = gpGlobals->time + 0.2; +} + + +void CCrossbowBolt::Precache( ) +{ + PRECACHE_MODEL ("models/crossbow_bolt.mdl"); + PRECACHE_SOUND("weapons/xbow_hitbod1.wav"); + PRECACHE_SOUND("weapons/xbow_hitbod2.wav"); + PRECACHE_SOUND("weapons/xbow_fly1.wav"); + PRECACHE_SOUND("weapons/xbow_hit1.wav"); + PRECACHE_SOUND("fvox/beep.wav"); + m_iTrail = PRECACHE_MODEL("sprites/streak.spr"); +} + + +int CCrossbowBolt :: Classify ( void ) +{ + return CLASS_NONE; +} + +void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) +{ + SetTouch( NULL ); + SetThink( NULL ); + + if (pOther->pev->takedamage) + { + TraceResult tr = UTIL_GetGlobalTrace( ); + entvars_t *pevOwner; + + pevOwner = VARS( pev->owner ); + + // UNDONE: this needs to call TraceAttack instead + ClearMultiDamage( ); + + if ( pOther->IsPlayer() ) + { + pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); + } + else + { + pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB ); + } + + ApplyMultiDamage( pev, pevOwner ); + + pev->velocity = Vector( 0, 0, 0 ); + // play body "thwack" sound + switch( RANDOM_LONG(0,1) ) + { + case 0: + EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; + case 1: + EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break; + } + + if ( !g_pGameRules->IsMultiplayer() ) + { + Killed( pev, GIB_NEVER ); + } + } + else + { + EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7)); + + SetThink( &CCrossbowBolt::SUB_Remove ); + pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit. + + if ( FClassnameIs( pOther->pev, "worldspawn" ) ) + { + // if what we hit is static architecture, can stay around for a while. + Vector vecDir = pev->velocity.Normalize( ); + UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); + pev->angles = UTIL_VecToAngles( vecDir ); + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_FLY; + pev->velocity = Vector( 0, 0, 0 ); + pev->avelocity.z = 0; + pev->angles.z = RANDOM_LONG(0,360); + pev->nextthink = gpGlobals->time + 10.0; + } + + if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) + { + UTIL_Sparks( pev->origin ); + } + } + + if ( g_pGameRules->IsMultiplayer() ) + { + SetThink( &CCrossbowBolt::ExplodeThink ); + pev->nextthink = gpGlobals->time + 0.1; + } +} + +void CCrossbowBolt::BubbleThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if (pev->waterlevel == 0) + return; + + UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); +} + +void CCrossbowBolt::ExplodeThink( void ) +{ + int iContents = UTIL_PointContents ( pev->origin ); + int iScale; + + pev->dmg = 40; + iScale = 10; + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_EXPLOSION); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + if (iContents != CONTENTS_WATER) + { + WRITE_SHORT( g_sModelIndexFireball ); + } + else + { + WRITE_SHORT( g_sModelIndexWExplosion ); + } + WRITE_BYTE( iScale ); // scale * 10 + WRITE_BYTE( 15 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + + entvars_t *pevOwner; + + if ( pev->owner ) + pevOwner = VARS( pev->owner ); + else + pevOwner = NULL; + + pev->owner = NULL; // can't traceline attack owner if this is set + + ::RadiusDamage( pev->origin, pev, pevOwner, pev->dmg, 128, CLASS_NONE, DMG_BLAST | DMG_ALWAYSGIB ); + + UTIL_Remove(this); +} +#endif + +enum crossbow_e { + CROSSBOW_IDLE1 = 0, // full + CROSSBOW_IDLE2, // empty + CROSSBOW_FIDGET1, // full + CROSSBOW_FIDGET2, // empty + CROSSBOW_FIRE1, // full + CROSSBOW_FIRE2, // reload + CROSSBOW_FIRE3, // empty + CROSSBOW_RELOAD, // from empty + CROSSBOW_DRAW1, // full + CROSSBOW_DRAW2, // empty + CROSSBOW_HOLSTER1, // full + CROSSBOW_HOLSTER2, // empty +}; + +LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ); + +void CCrossbow::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_CROSSBOW; + SET_MODEL(ENT(pev), "models/w_crossbow.mdl"); + + m_iDefaultAmmo = CROSSBOW_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + +int CCrossbow::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); + WRITE_BYTE( m_iId ); + MESSAGE_END(); + return TRUE; + } + return FALSE; +} + +void CCrossbow::Precache( void ) +{ + PRECACHE_MODEL("models/w_crossbow.mdl"); + PRECACHE_MODEL("models/v_crossbow.mdl"); + PRECACHE_MODEL("models/p_crossbow.mdl"); + + PRECACHE_SOUND("weapons/xbow_fire1.wav"); + PRECACHE_SOUND("weapons/xbow_reload1.wav"); + + UTIL_PrecacheOther( "crossbow_bolt" ); + + m_usCrossbow = PRECACHE_EVENT( 1, "events/crossbow1.sc" ); + m_usCrossbow2 = PRECACHE_EVENT( 1, "events/crossbow2.sc" ); +} + + +int CCrossbow::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "bolts"; + p->iMaxAmmo1 = BOLT_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = CROSSBOW_MAX_CLIP; + p->iSlot = 2; + p->iPosition = 2; + p->iId = WEAPON_CROSSBOW; + p->iFlags = 0; + p->iWeight = CROSSBOW_WEIGHT; + return 1; +} + + +BOOL CCrossbow::Deploy( ) +{ + if (m_iClip) + return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW1, "bow" ); + return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" ); +} + +void CCrossbow::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE;// cancel any reload in progress. + + if ( m_fInZoom ) + { + SecondaryAttack( ); + } + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + if (m_iClip) + SendWeaponAnim( CROSSBOW_HOLSTER1 ); + else + SendWeaponAnim( CROSSBOW_HOLSTER2 ); +} + +void CCrossbow::PrimaryAttack( void ) +{ + +#ifdef CLIENT_DLL + if ( m_fInZoom && bIsMultiplayer() ) +#else + if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) +#endif + { + FireSniperBolt(); + return; + } + + FireBolt(); +} + +// this function only gets called in multiplayer +void CCrossbow::FireSniperBolt() +{ + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + + if (m_iClip == 0) + { + PlayEmptySound( ); + return; + } + + TraceResult tr; + + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + m_iClip--; + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; + UTIL_MakeVectors( anglesAim ); + Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; + Vector vecDir = gpGlobals->v_forward; + + UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr); + +#ifndef CLIENT_DLL + if ( tr.pHit->v.takedamage ) + { + ClearMultiDamage( ); + CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); + ApplyMultiDamage( pev, m_pPlayer->pev ); + } +#endif +} + +void CCrossbow::FireBolt() +{ + TraceResult tr; + + if (m_iClip == 0) + { + PlayEmptySound( ); + return; + } + + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + + m_iClip--; + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; + UTIL_MakeVectors( anglesAim ); + + anglesAim.x = -anglesAim.x; + Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; + Vector vecDir = gpGlobals->v_forward; + +#ifndef CLIENT_DLL + CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); + pBolt->pev->origin = vecSrc; + pBolt->pev->angles = anglesAim; + pBolt->pev->owner = m_pPlayer->edict(); + + if (m_pPlayer->pev->waterlevel == 3) + { + pBolt->pev->velocity = vecDir * BOLT_WATER_VELOCITY; + pBolt->pev->speed = BOLT_WATER_VELOCITY; + } + else + { + pBolt->pev->velocity = vecDir * BOLT_AIR_VELOCITY; + pBolt->pev->speed = BOLT_AIR_VELOCITY; + } + pBolt->pev->avelocity.z = 10; +#endif + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; + + if (m_iClip != 0) + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; + else + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; +} + + +void CCrossbow::SecondaryAttack() +{ + if ( m_pPlayer->pev->fov != 0 ) + { + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov + m_fInZoom = 0; + } + else if ( m_pPlayer->pev->fov != 20 ) + { + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 20; + m_fInZoom = 1; + } + + pev->nextthink = UTIL_WeaponTimeBase() + 0.1; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; +} + + +void CCrossbow::Reload( void ) +{ + if ( m_pPlayer->ammo_bolts <= 0 ) + return; + + if ( m_pPlayer->pev->fov != 0 ) + { + SecondaryAttack(); + } + + if ( DefaultReload( 5, CROSSBOW_RELOAD, 4.5 ) ) + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF)); + } +} + + +void CCrossbow::WeaponIdle( void ) +{ + m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM + + ResetEmptySound( ); + + if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) + { + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if (flRand <= 0.75) + { + if (m_iClip) + { + SendWeaponAnim( CROSSBOW_IDLE1 ); + } + else + { + SendWeaponAnim( CROSSBOW_IDLE2 ); + } + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } + else + { + if (m_iClip) + { + SendWeaponAnim( CROSSBOW_FIDGET1 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; + } + else + { + SendWeaponAnim( CROSSBOW_FIDGET2 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 30.0; + } + } + } +} + + + +class CCrossbowAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_crossbow_clip.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_crossbow_clip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ); + + + #endif \ No newline at end of file diff --git a/main/source/dlls/crowbar.cpp b/main/source/dlls/crowbar.cpp index e4f008c8..fae6741b 100644 --- a/main/source/dlls/crowbar.cpp +++ b/main/source/dlls/crowbar.cpp @@ -1,334 +1,334 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - - -#define CROWBAR_BODYHIT_VOLUME 128 -#define CROWBAR_WALLHIT_VOLUME 512 - -//class CCrowbar : public CBasePlayerWeapon -//{ -//public: -// void Spawn( void ); -// void Precache( void ); -// int iItemSlot( void ) { return 1; } -// void EXPORT SwingAgain( void ); -// void EXPORT Smack( void ); -// int GetItemInfo(ItemInfo *p); -// -// void PrimaryAttack( void ); -// int Swing( int fFirst ); -// BOOL Deploy( void ); -// void Holster( int skiplocal = 0 ); -// int m_iSwing; -// TraceResult m_trHit; -//}; -//LINK_ENTITY_TO_CLASS( weapon_rowbar, CCrowbar ); -LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ); - -enum gauss_e { - CROWBAR_IDLE = 0, - CROWBAR_DRAW, - CROWBAR_HOLSTER, - CROWBAR_ATTACK1HIT, - CROWBAR_ATTACK1MISS, - CROWBAR_ATTACK2MISS, - CROWBAR_ATTACK2HIT, - CROWBAR_ATTACK3MISS, - CROWBAR_ATTACK3HIT -}; - - -void CCrowbar::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_CROWBAR; - SET_MODEL(ENT(pev), "models/w_crowbar.mdl"); - m_iClip = -1; - - FallInit();// get ready to fall down. -} - - -void CCrowbar::Precache( void ) -{ - PRECACHE_MODEL("models/v_crowbar.mdl"); - PRECACHE_MODEL("models/w_crowbar.mdl"); - PRECACHE_MODEL("models/p_crowbar.mdl"); - PRECACHE_SOUND("weapons/cbar_hit1.wav"); - PRECACHE_SOUND("weapons/cbar_hit2.wav"); - PRECACHE_SOUND("weapons/cbar_hitbod1.wav"); - PRECACHE_SOUND("weapons/cbar_hitbod2.wav"); - PRECACHE_SOUND("weapons/cbar_hitbod3.wav"); - PRECACHE_SOUND("weapons/cbar_miss1.wav"); - - m_usCrowbar = PRECACHE_EVENT ( 1, "events/crowbar.sc" ); -} - -int CCrowbar::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = NULL; - p->iMaxAmmo1 = -1; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 0; - p->iPosition = 0; - p->iId = WEAPON_CROWBAR; - p->iWeight = CROWBAR_WEIGHT; - return 1; -} - - - -BOOL CCrowbar::Deploy( ) -{ - return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); -} - -void CCrowbar::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( CROWBAR_HOLSTER ); -} - - -void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ) -{ - int i, j, k; - float distance; - float *minmaxs[2] = {mins, maxs}; - TraceResult tmpTrace; - Vector vecHullEnd = tr.vecEndPos; - Vector vecEnd; - - distance = 1e6f; - - vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); - UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) - { - tr = tmpTrace; - return; - } - - for ( i = 0; i < 2; i++ ) - { - for ( j = 0; j < 2; j++ ) - { - for ( k = 0; k < 2; k++ ) - { - vecEnd.x = vecHullEnd.x + minmaxs[i][0]; - vecEnd.y = vecHullEnd.y + minmaxs[j][1]; - vecEnd.z = vecHullEnd.z + minmaxs[k][2]; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) - { - float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length(); - if ( thisDistance < distance ) - { - tr = tmpTrace; - distance = thisDistance; - } - } - } - } - } -} - - -void CCrowbar::PrimaryAttack() -{ - if (! Swing( 1 )) - { - SetThink( &CCrowbar::SwingAgain ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - - -void CCrowbar::Smack( ) -{ - DecalGunshot( &m_trHit, BULLET_PLAYER_CROWBAR ); -} - - -void CCrowbar::SwingAgain( void ) -{ - Swing( 0 ); -} - - -int CCrowbar::Swing( int fFirst ) -{ - int fDidHit = FALSE; - - TraceResult tr; - - UTIL_MakeVectors (m_pPlayer->pev->v_angle); - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecEnd = vecSrc + gpGlobals->v_forward * 32; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); - -#ifndef CLIENT_DLL - if ( tr.flFraction >= 1.0 ) - { - UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr ); - if ( tr.flFraction < 1.0 ) - { - // Calculate the point of intersection of the line (or hull) and the object we hit - // This is and approximation of the "best" intersection - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - if ( !pHit || pHit->IsBSPModel() ) - FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() ); - vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space) - } - } -#endif - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar, - 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, - 0.0, 0, 0.0 ); - - - if ( tr.flFraction >= 1.0 ) - { - if (fFirst) - { - // miss - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - } - else - { - switch( ((m_iSwing++) % 2) + 1 ) - { - case 0: - SendWeaponAnim( CROWBAR_ATTACK1HIT ); break; - case 1: - SendWeaponAnim( CROWBAR_ATTACK2HIT ); break; - case 2: - SendWeaponAnim( CROWBAR_ATTACK3HIT ); break; - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#ifndef CLIENT_DLL - - // hit - fDidHit = TRUE; - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - ClearMultiDamage( ); - - if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) - { - // first swing does full damage - pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB ); - } - else - { - // subsequent swings do half - pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB ); - } - ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - - // play thwack, smack, or dong sound - float flVol = 1.0; - int fHitWorld = TRUE; - - if (pEntity) - { - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) - { - // play thwack or smack sound - switch( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break; - case 1: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break; - case 2: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break; - } - m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME; - if (!pEntity->IsAlive() ) - return TRUE; - else - flVol = 0.1; - - fHitWorld = FALSE; - } - } - - // play texture hit sound - // UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line - - if (fHitWorld) - { - float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR); - - if ( g_pGameRules->IsMultiplayer() ) - { - // override the volume here, cause we don't play texture sounds in multiplayer, - // and fvolbar is going to be 0 from the above call. - - fvolbar = 1; - } - - // also play crowbar strike - switch( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); - break; - case 1: - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); - break; - } - - // delay the decal a bit - m_trHit = tr; - } - - m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; -#endif - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - - SetThink( &CCrowbar::Smack ); - pev->nextthink = UTIL_WeaponTimeBase() + 0.2; - - - } - return fDidHit; -} - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" + + +#define CROWBAR_BODYHIT_VOLUME 128 +#define CROWBAR_WALLHIT_VOLUME 512 + +//class CCrowbar : public CBasePlayerWeapon +//{ +//public: +// void Spawn( void ); +// void Precache( void ); +// int iItemSlot( void ) { return 1; } +// void EXPORT SwingAgain( void ); +// void EXPORT Smack( void ); +// int GetItemInfo(ItemInfo *p); +// +// void PrimaryAttack( void ); +// int Swing( int fFirst ); +// BOOL Deploy( void ); +// void Holster( int skiplocal = 0 ); +// int m_iSwing; +// TraceResult m_trHit; +//}; +//LINK_ENTITY_TO_CLASS( weapon_rowbar, CCrowbar ); +LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ); + +enum gauss_e { + CROWBAR_IDLE = 0, + CROWBAR_DRAW, + CROWBAR_HOLSTER, + CROWBAR_ATTACK1HIT, + CROWBAR_ATTACK1MISS, + CROWBAR_ATTACK2MISS, + CROWBAR_ATTACK2HIT, + CROWBAR_ATTACK3MISS, + CROWBAR_ATTACK3HIT +}; + + +void CCrowbar::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_CROWBAR; + SET_MODEL(ENT(pev), "models/w_crowbar.mdl"); + m_iClip = -1; + + FallInit();// get ready to fall down. +} + + +void CCrowbar::Precache( void ) +{ + PRECACHE_MODEL("models/v_crowbar.mdl"); + PRECACHE_MODEL("models/w_crowbar.mdl"); + PRECACHE_MODEL("models/p_crowbar.mdl"); + PRECACHE_SOUND("weapons/cbar_hit1.wav"); + PRECACHE_SOUND("weapons/cbar_hit2.wav"); + PRECACHE_SOUND("weapons/cbar_hitbod1.wav"); + PRECACHE_SOUND("weapons/cbar_hitbod2.wav"); + PRECACHE_SOUND("weapons/cbar_hitbod3.wav"); + PRECACHE_SOUND("weapons/cbar_miss1.wav"); + + m_usCrowbar = PRECACHE_EVENT ( 1, "events/crowbar.sc" ); +} + +int CCrowbar::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = NULL; + p->iMaxAmmo1 = -1; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 0; + p->iPosition = 0; + p->iId = WEAPON_CROWBAR; + p->iWeight = CROWBAR_WEIGHT; + return 1; +} + + + +BOOL CCrowbar::Deploy( ) +{ + return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); +} + +void CCrowbar::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + SendWeaponAnim( CROWBAR_HOLSTER ); +} + + +void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ) +{ + int i, j, k; + float distance; + float *minmaxs[2] = {mins, maxs}; + TraceResult tmpTrace; + Vector vecHullEnd = tr.vecEndPos; + Vector vecEnd; + + distance = 1e6f; + + vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); + UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace ); + if ( tmpTrace.flFraction < 1.0 ) + { + tr = tmpTrace; + return; + } + + for ( i = 0; i < 2; i++ ) + { + for ( j = 0; j < 2; j++ ) + { + for ( k = 0; k < 2; k++ ) + { + vecEnd.x = vecHullEnd.x + minmaxs[i][0]; + vecEnd.y = vecHullEnd.y + minmaxs[j][1]; + vecEnd.z = vecHullEnd.z + minmaxs[k][2]; + + UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace ); + if ( tmpTrace.flFraction < 1.0 ) + { + float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length(); + if ( thisDistance < distance ) + { + tr = tmpTrace; + distance = thisDistance; + } + } + } + } + } +} + + +void CCrowbar::PrimaryAttack() +{ + if (! Swing( 1 )) + { + SetThink( &CCrowbar::SwingAgain ); + pev->nextthink = gpGlobals->time + 0.1; + } +} + + +void CCrowbar::Smack( ) +{ + DecalGunshot( &m_trHit, BULLET_PLAYER_CROWBAR ); +} + + +void CCrowbar::SwingAgain( void ) +{ + Swing( 0 ); +} + + +int CCrowbar::Swing( int fFirst ) +{ + int fDidHit = FALSE; + + TraceResult tr; + + UTIL_MakeVectors (m_pPlayer->pev->v_angle); + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecEnd = vecSrc + gpGlobals->v_forward * 32; + + UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); + +#ifndef CLIENT_DLL + if ( tr.flFraction >= 1.0 ) + { + UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr ); + if ( tr.flFraction < 1.0 ) + { + // Calculate the point of intersection of the line (or hull) and the object we hit + // This is and approximation of the "best" intersection + CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); + if ( !pHit || pHit->IsBSPModel() ) + FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() ); + vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space) + } + } +#endif + + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar, + 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, + 0.0, 0, 0.0 ); + + + if ( tr.flFraction >= 1.0 ) + { + if (fFirst) + { + // miss + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + } + } + else + { + switch( ((m_iSwing++) % 2) + 1 ) + { + case 0: + SendWeaponAnim( CROWBAR_ATTACK1HIT ); break; + case 1: + SendWeaponAnim( CROWBAR_ATTACK2HIT ); break; + case 2: + SendWeaponAnim( CROWBAR_ATTACK3HIT ); break; + } + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + +#ifndef CLIENT_DLL + + // hit + fDidHit = TRUE; + CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + + ClearMultiDamage( ); + + if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) + { + // first swing does full damage + pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB ); + } + else + { + // subsequent swings do half + pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB ); + } + ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); + + // play thwack, smack, or dong sound + float flVol = 1.0; + int fHitWorld = TRUE; + + if (pEntity) + { + if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) + { + // play thwack or smack sound + switch( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break; + case 1: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break; + case 2: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break; + } + m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME; + if (!pEntity->IsAlive() ) + return TRUE; + else + flVol = 0.1; + + fHitWorld = FALSE; + } + } + + // play texture hit sound + // UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line + + if (fHitWorld) + { + float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR); + + if ( g_pGameRules->IsMultiplayer() ) + { + // override the volume here, cause we don't play texture sounds in multiplayer, + // and fvolbar is going to be 0 from the above call. + + fvolbar = 1; + } + + // also play crowbar strike + switch( RANDOM_LONG(0,1) ) + { + case 0: + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); + break; + case 1: + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); + break; + } + + // delay the decal a bit + m_trHit = tr; + } + + m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; +#endif + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + + SetThink( &CCrowbar::Smack ); + pev->nextthink = UTIL_WeaponTimeBase() + 0.2; + + + } + return fDidHit; +} + + + diff --git a/main/source/dlls/ctripmine.h b/main/source/dlls/ctripmine.h index 4bfddc1c..6cd9bd95 100644 --- a/main/source/dlls/ctripmine.h +++ b/main/source/dlls/ctripmine.h @@ -1,47 +1,47 @@ -#ifndef CTRIPMINE_H -#define CTRIPMINE_H - -#include "../mod/AvHBasePlayerWeapon.h" -#include "../mod/AvHMarineEquipmentConstants.h" - -////class CTripmine : public CBasePlayerWeapon -//class CTripmine : public AvHBasePlayerWeapon -//{ -//public: -// -// int GetBarrelLength() const -// { -// return kMineBarrellLength; -// } -// -// void Spawn( void ); -// void Precache( void ); -// int iItemSlot( void ) { return 5; } -// int GetItemInfo(ItemInfo *p); -// void SetObjectCollisionBox( void ) -// { -// //!!!BUGBUG - fix the model! -// pev->absmin = pev->origin + Vector(-16, -16, -5); -// pev->absmax = pev->origin + Vector(16, 16, 28); -// } -// -// void PrimaryAttack( void ); -// BOOL Deploy( void ); -// void Holster( int skiplocal = 0 ); -// void WeaponIdle( void ); -// -// virtual BOOL UseDecrement( void ) -// { -//#if defined( CLIENT_WEAPONS ) -// return TRUE; -//#else -// return FALSE; -//#endif -// } -// -//private: -// unsigned short m_usTripFire; -// -//}; - +#ifndef CTRIPMINE_H +#define CTRIPMINE_H + +#include "../mod/AvHBasePlayerWeapon.h" +#include "../mod/AvHMarineEquipmentConstants.h" + +////class CTripmine : public CBasePlayerWeapon +//class CTripmine : public AvHBasePlayerWeapon +//{ +//public: +// +// int GetBarrelLength() const +// { +// return kMineBarrellLength; +// } +// +// void Spawn( void ); +// void Precache( void ); +// int iItemSlot( void ) { return 5; } +// int GetItemInfo(ItemInfo *p); +// void SetObjectCollisionBox( void ) +// { +// //!!!BUGBUG - fix the model! +// pev->absmin = pev->origin + Vector(-16, -16, -5); +// pev->absmax = pev->origin + Vector(16, 16, 28); +// } +// +// void PrimaryAttack( void ); +// BOOL Deploy( void ); +// void Holster( int skiplocal = 0 ); +// void WeaponIdle( void ); +// +// virtual BOOL UseDecrement( void ) +// { +//#if defined( CLIENT_WEAPONS ) +// return TRUE; +//#else +// return FALSE; +//#endif +// } +// +//private: +// unsigned short m_usTripFire; +// +//}; + #endif \ No newline at end of file diff --git a/main/source/dlls/ctripmine.h~ b/main/source/dlls/ctripmine.h~ deleted file mode 100644 index 24c79d0a..00000000 --- a/main/source/dlls/ctripmine.h~ +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef CTRIPMINE_H -#define CTRIPMINE_H - -#include "..mod/AvHBasePlayerWeapon.h" -#include "..mod/AvHMarineEquipmentConstants.h" - -////class CTripmine : public CBasePlayerWeapon -//class CTripmine : public AvHBasePlayerWeapon -//{ -//public: -// -// int GetBarrelLength() const -// { -// return kMineBarrellLength; -// } -// -// void Spawn( void ); -// void Precache( void ); -// int iItemSlot( void ) { return 5; } -// int GetItemInfo(ItemInfo *p); -// void SetObjectCollisionBox( void ) -// { -// //!!!BUGBUG - fix the model! -// pev->absmin = pev->origin + Vector(-16, -16, -5); -// pev->absmax = pev->origin + Vector(16, 16, 28); -// } -// -// void PrimaryAttack( void ); -// BOOL Deploy( void ); -// void Holster( int skiplocal = 0 ); -// void WeaponIdle( void ); -// -// virtual BOOL UseDecrement( void ) -// { -//#if defined( CLIENT_WEAPONS ) -// return TRUE; -//#else -// return FALSE; -//#endif -// } -// -//private: -// unsigned short m_usTripFire; -// -//}; - -#endif \ No newline at end of file diff --git a/main/source/dlls/decals.h b/main/source/dlls/decals.h index bfb3ed59..5eed7fce 100644 --- a/main/source/dlls/decals.h +++ b/main/source/dlls/decals.h @@ -1,75 +1,75 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef DECALS_H -#define DECALS_H - -// -// Dynamic Decals -// -enum decal_e -{ - DECAL_GUNSHOT1 = 0, - DECAL_GUNSHOT2, - DECAL_GUNSHOT3, - DECAL_GUNSHOT4, - DECAL_GUNSHOT5, - DECAL_LAMBDA1, - DECAL_LAMBDA2, - DECAL_LAMBDA3, - DECAL_LAMBDA4, - DECAL_LAMBDA5, - DECAL_LAMBDA6, - DECAL_SCORCH1, - DECAL_SCORCH2, - DECAL_BLOOD1, - DECAL_BLOOD2, - DECAL_BLOOD3, - DECAL_BLOOD4, - DECAL_BLOOD5, - DECAL_BLOOD6, - DECAL_YBLOOD1, - DECAL_YBLOOD2, - DECAL_YBLOOD3, - DECAL_YBLOOD4, - DECAL_YBLOOD5, - DECAL_YBLOOD6, - DECAL_GLASSBREAK1, - DECAL_GLASSBREAK2, - DECAL_GLASSBREAK3, - DECAL_BIGSHOT1, - DECAL_BIGSHOT2, - DECAL_BIGSHOT3, - DECAL_BIGSHOT4, - DECAL_BIGSHOT5, - DECAL_SPIT1, - DECAL_SPIT2, - DECAL_BPROOF1, // Bulletproof glass decal - DECAL_GARGSTOMP1, // Gargantua stomp crack - DECAL_SMALLSCORCH1, // Small scorch mark - DECAL_SMALLSCORCH2, // Small scorch mark - DECAL_SMALLSCORCH3, // Small scorch mark - DECAL_MOMMABIRTH, // Big momma birth splatter - DECAL_MOMMASPLAT, -}; - -typedef struct -{ - char *name; - int index; -} DLL_DECALLIST; - -extern DLL_DECALLIST gDecals[]; - -#endif // DECALS_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef DECALS_H +#define DECALS_H + +// +// Dynamic Decals +// +enum decal_e +{ + DECAL_GUNSHOT1 = 0, + DECAL_GUNSHOT2, + DECAL_GUNSHOT3, + DECAL_GUNSHOT4, + DECAL_GUNSHOT5, + DECAL_LAMBDA1, + DECAL_LAMBDA2, + DECAL_LAMBDA3, + DECAL_LAMBDA4, + DECAL_LAMBDA5, + DECAL_LAMBDA6, + DECAL_SCORCH1, + DECAL_SCORCH2, + DECAL_BLOOD1, + DECAL_BLOOD2, + DECAL_BLOOD3, + DECAL_BLOOD4, + DECAL_BLOOD5, + DECAL_BLOOD6, + DECAL_YBLOOD1, + DECAL_YBLOOD2, + DECAL_YBLOOD3, + DECAL_YBLOOD4, + DECAL_YBLOOD5, + DECAL_YBLOOD6, + DECAL_GLASSBREAK1, + DECAL_GLASSBREAK2, + DECAL_GLASSBREAK3, + DECAL_BIGSHOT1, + DECAL_BIGSHOT2, + DECAL_BIGSHOT3, + DECAL_BIGSHOT4, + DECAL_BIGSHOT5, + DECAL_SPIT1, + DECAL_SPIT2, + DECAL_BPROOF1, // Bulletproof glass decal + DECAL_GARGSTOMP1, // Gargantua stomp crack + DECAL_SMALLSCORCH1, // Small scorch mark + DECAL_SMALLSCORCH2, // Small scorch mark + DECAL_SMALLSCORCH3, // Small scorch mark + DECAL_MOMMABIRTH, // Big momma birth splatter + DECAL_MOMMASPLAT, +}; + +typedef struct +{ + char *name; + int index; +} DLL_DECALLIST; + +extern DLL_DECALLIST gDecals[]; + +#endif // DECALS_H diff --git a/main/source/dlls/defaultai.cpp b/main/source/dlls/defaultai.cpp index fd74789d..847a0650 100644 --- a/main/source/dlls/defaultai.cpp +++ b/main/source/dlls/defaultai.cpp @@ -1,1232 +1,1232 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Default behaviors. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "defaultai.h" -#include "soundent.h" -#include "nodes.h" -#include "scripted.h" - -//========================================================= -// Fail -//========================================================= -Task_t tlFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slFail[] = -{ - { - tlFail, - ARRAYSIZE ( tlFail ), - bits_COND_CAN_ATTACK, - 0, - "Fail" - }, -}; - -//========================================================= -// Idle Schedules -//========================================================= -Task_t tlIdleStand1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)5 },// repick IDLESTAND every five seconds. gives us a chance to pick an active idle, fidget, etc. -}; - -Schedule_t slIdleStand[] = -{ - { - tlIdleStand1, - ARRAYSIZE ( tlIdleStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL_FOOD | - bits_COND_SMELL | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_PLAYER | - bits_SOUND_DANGER | - - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleStand" - }, -}; - -Schedule_t slIdleTrigger[] = -{ - { - tlIdleStand1, - ARRAYSIZE ( tlIdleStand1 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Trigger" - }, -}; - - -Task_t tlIdleWalk1[] = -{ - { TASK_WALK_PATH, (float)9999 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slIdleWalk[] = -{ - { - tlIdleWalk1, - ARRAYSIZE ( tlIdleWalk1 ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL_FOOD | - bits_COND_SMELL | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "Idle Walk" - }, -}; - -//========================================================= -// Ambush - monster stands in place and waits for a new -// enemy, or chance to attack an existing enemy. -//========================================================= -Task_t tlAmbush[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_INDEFINITE, (float)0 }, -}; - -Schedule_t slAmbush[] = -{ - { - tlAmbush, - ARRAYSIZE ( tlAmbush ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED, - - 0, - "Ambush" - }, -}; - -//========================================================= -// ActiveIdle schedule - !!!BUGBUG - if this schedule doesn't -// complete on its own, the monster's HintNode will not be -// cleared, and the rest of the monster's group will avoid -// that node because they think the group member that was -// previously interrupted is still using that node to active -// idle. -///========================================================= -Task_t tlActiveIdle[] = -{ - { TASK_FIND_HINTNODE, (float)0 }, - { TASK_GET_PATH_TO_HINTNODE, (float)0 }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_HINTNODE, (float)0 }, - { TASK_PLAY_ACTIVE_IDLE, (float)0 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, - { TASK_CLEAR_HINTNODE, (float)0 }, -}; - -Schedule_t slActiveIdle[] = -{ - { - tlActiveIdle, - ARRAYSIZE( tlActiveIdle ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT | - bits_SOUND_WORLD | - bits_SOUND_PLAYER | - bits_SOUND_DANGER, - "Active Idle" - } -}; - -//========================================================= -// Wake Schedules -//========================================================= -Task_t tlWakeAngry1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, -}; - -Schedule_t slWakeAngry[] = -{ - { - tlWakeAngry1, - ARRAYSIZE ( tlWakeAngry1 ), - 0, - 0, - "Wake Angry" - } -}; - -//========================================================= -// AlertFace Schedules -//========================================================= -Task_t tlAlertFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_IDEAL, (float)0 }, -}; - -Schedule_t slAlertFace[] = -{ - { - tlAlertFace1, - ARRAYSIZE ( tlAlertFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED, - 0, - "Alert Face" - }, -}; - -//========================================================= -// AlertSmallFlinch Schedule - shot, but didn't see attacker, -// flinch then face -//========================================================= -Task_t tlAlertSmallFlinch[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, - { TASK_SMALL_FLINCH, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_ALERT_FACE }, -}; - -Schedule_t slAlertSmallFlinch[] = -{ - { - tlAlertSmallFlinch, - ARRAYSIZE ( tlAlertSmallFlinch ), - 0, - 0, - "Alert Small Flinch" - }, -}; - -//========================================================= -// AlertIdle Schedules -//========================================================= -Task_t tlAlertStand1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)20 }, - { TASK_SUGGEST_STATE, (float)MONSTERSTATE_IDLE }, -}; - -Schedule_t slAlertStand[] = -{ - { - tlAlertStand1, - ARRAYSIZE ( tlAlertStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_SMELL | - bits_COND_SMELL_FOOD | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_PLAYER | - bits_SOUND_DANGER | - - bits_SOUND_MEAT |// scent flags - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "Alert Stand" - }, -}; - -//========================================================= -// InvestigateSound - sends a monster to the location of the -// sound that was just heard, to check things out. -//========================================================= -Task_t tlInvestigateSound[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSOUND, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_IDLE }, - { TASK_WAIT, (float)10 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slInvestigateSound[] = -{ - { - tlInvestigateSound, - ARRAYSIZE ( tlInvestigateSound ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "InvestigateSound" - }, -}; - -//========================================================= -// CombatIdle Schedule -//========================================================= -Task_t tlCombatStand1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_INDEFINITE, (float)0 }, -}; - -Schedule_t slCombatStand[] = -{ - { - tlCombatStand1, - ARRAYSIZE ( tlCombatStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_ATTACK, - 0, - "Combat Stand" - }, -}; - -//========================================================= -// CombatFace Schedule -//========================================================= -Task_t tlCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slCombatFace[] = -{ - { - tlCombatFace1, - ARRAYSIZE ( tlCombatFace1 ), - bits_COND_CAN_ATTACK | - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Standoff schedule. Used in combat when a monster is -// hiding in cover or the enemy has moved out of sight. -// Should we look around in this schedule? -//========================================================= -Task_t tlStandoff[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, -}; - -Schedule_t slStandoff[] = -{ - { - tlStandoff, - ARRAYSIZE ( tlStandoff ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_ENEMY_DEAD | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Standoff" - } -}; - -//========================================================= -// Arm weapon (draw gun) -//========================================================= -Task_t tlArmWeapon[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float) ACT_ARM } -}; - -Schedule_t slArmWeapon[] = -{ - { - tlArmWeapon, - ARRAYSIZE ( tlArmWeapon ), - 0, - 0, - "Arm Weapon" - } -}; - -//========================================================= -// reload schedule -//========================================================= -Task_t tlReload[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, float(ACT_RELOAD) }, -}; - -Schedule_t slReload[] = -{ - { - tlReload, - ARRAYSIZE ( tlReload ), - bits_COND_HEAVY_DAMAGE, - 0, - "Reload" - } -}; - -//========================================================= -// Attack Schedules -//========================================================= - -// primary range attack -Task_t tlRangeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slRangeAttack1[] = -{ - { - tlRangeAttack1, - ARRAYSIZE ( tlRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack1" - }, -}; - -// secondary range attack -Task_t tlRangeAttack2[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, -}; - -Schedule_t slRangeAttack2[] = -{ - { - tlRangeAttack2, - ARRAYSIZE ( tlRangeAttack2 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack2" - }, -}; - -// primary melee attack -Task_t tlPrimaryMeleeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, -}; - -Schedule_t slPrimaryMeleeAttack[] = -{ - { - tlPrimaryMeleeAttack1, - ARRAYSIZE ( tlPrimaryMeleeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - 0, - "Primary Melee Attack" - }, -}; - -// secondary melee attack -Task_t tlSecondaryMeleeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK2, (float)0 }, -}; - -Schedule_t slSecondaryMeleeAttack[] = -{ - { - tlSecondaryMeleeAttack1, - ARRAYSIZE ( tlSecondaryMeleeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - 0, - "Secondary Melee Attack" - }, -}; - -// special attack1 -Task_t tlSpecialAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPECIAL_ATTACK1, (float)0 }, -}; - -Schedule_t slSpecialAttack1[] = -{ - { - tlSpecialAttack1, - ARRAYSIZE ( tlSpecialAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Special Attack1" - }, -}; - -// special attack2 -Task_t tlSpecialAttack2[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPECIAL_ATTACK2, (float)0 }, -}; - -Schedule_t slSpecialAttack2[] = -{ - { - tlSpecialAttack2, - ARRAYSIZE ( tlSpecialAttack2 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Special Attack2" - }, -}; - -// Chase enemy schedule -Task_t tlChaseEnemy1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CHASE_ENEMY_FAILED }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slChaseEnemy[] = -{ - { - tlChaseEnemy1, - ARRAYSIZE ( tlChaseEnemy1 ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_TASK_FAILED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Chase Enemy" - }, -}; - - -// Chase enemy failure schedule -Task_t tlChaseEnemyFailed[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, -// { TASK_TURN_LEFT, (float)179 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slChaseEnemyFailed[] = -{ - { - tlChaseEnemyFailed, - ARRAYSIZE ( tlChaseEnemyFailed ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "tlChaseEnemyFailed" - }, -}; - - -//========================================================= -// small flinch, played when minor damage is taken. -//========================================================= -Task_t tlSmallFlinch[] = -{ - { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, - { TASK_STOP_MOVING, 0 }, - { TASK_SMALL_FLINCH, 0 }, -}; - -Schedule_t slSmallFlinch[] = -{ - { - tlSmallFlinch, - ARRAYSIZE ( tlSmallFlinch ), - 0, - 0, - "Small Flinch" - }, -}; - -//========================================================= -// Die! -//========================================================= -Task_t tlDie1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, -}; - -Schedule_t slDie[] = -{ - { - tlDie1, - ARRAYSIZE( tlDie1 ), - 0, - 0, - "Die" - }, -}; - -//========================================================= -// Victory Dance -//========================================================= -Task_t tlVictoryDance[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_WAIT, (float)0 }, -}; - -Schedule_t slVictoryDance[] = -{ - { - tlVictoryDance, - ARRAYSIZE( tlVictoryDance ), - 0, - 0, - "Victory Dance" - }, -}; - -//========================================================= -// BarnacleVictimGrab - barnacle tongue just hit the monster, -// so play a hit animation, then play a cycling pull animation -// as the creature is hoisting the monster. -//========================================================= -Task_t tlBarnacleVictimGrab[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_HIT }, - { TASK_SET_ACTIVITY, (float)ACT_BARNACLE_PULL }, - { TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. -}; - -Schedule_t slBarnacleVictimGrab[] = -{ - { - tlBarnacleVictimGrab, - ARRAYSIZE ( tlBarnacleVictimGrab ), - 0, - 0, - "Barnacle Victim" - } -}; - -//========================================================= -// BarnacleVictimChomp - barnacle has pulled the prey to its -// mouth. Victim should play the BARNCLE_CHOMP animation -// once, then loop the BARNACLE_CHEW animation indefinitely -//========================================================= -Task_t tlBarnacleVictimChomp[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_CHOMP }, - { TASK_SET_ACTIVITY, (float)ACT_BARNACLE_CHEW }, - { TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. -}; - -Schedule_t slBarnacleVictimChomp[] = -{ - { - tlBarnacleVictimChomp, - ARRAYSIZE ( tlBarnacleVictimChomp ), - 0, - 0, - "Barnacle Chomp" - } -}; - - -// Universal Error Schedule -Task_t tlError[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_WAIT_INDEFINITE, (float)0 }, -}; - -Schedule_t slError[] = -{ - { - tlError, - ARRAYSIZE ( tlError ), - 0, - 0, - "Error" - }, -}; - -Task_t tlScriptedWalk[] = -{ - { TASK_WALK_TO_TARGET, (float)TARGET_MOVE_SCRIPTED }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slWalkToScript[] = -{ - { - tlScriptedWalk, - ARRAYSIZE ( tlScriptedWalk ), - SCRIPT_BREAK_CONDITIONS, - 0, - "WalkToScript" - }, -}; - - -Task_t tlScriptedRun[] = -{ - { TASK_RUN_TO_TARGET, (float)TARGET_MOVE_SCRIPTED }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slRunToScript[] = -{ - { - tlScriptedRun, - ARRAYSIZE ( tlScriptedRun ), - SCRIPT_BREAK_CONDITIONS, - 0, - "RunToScript" - }, -}; - -Task_t tlScriptedWait[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slWaitScript[] = -{ - { - tlScriptedWait, - ARRAYSIZE ( tlScriptedWait ), - SCRIPT_BREAK_CONDITIONS, - 0, - "WaitForScript" - }, -}; - -Task_t tlScriptedFace[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slFaceScript[] = -{ - { - tlScriptedFace, - ARRAYSIZE ( tlScriptedFace ), - SCRIPT_BREAK_CONDITIONS, - 0, - "FaceScript" - }, -}; - -//========================================================= -// Cower - this is what is usually done when attempts -// to escape danger fail. -//========================================================= -Task_t tlCower[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_COWER }, -}; - -Schedule_t slCower[] = -{ - { - tlCower, - ARRAYSIZE ( tlCower ), - 0, - 0, - "Cower" - }, -}; - -//========================================================= -// move away from where you're currently standing. -//========================================================= -Task_t tlTakeCoverFromOrigin[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ORIGIN, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slTakeCoverFromOrigin[] = -{ - { - tlTakeCoverFromOrigin, - ARRAYSIZE ( tlTakeCoverFromOrigin ), - bits_COND_NEW_ENEMY, - 0, - "TakeCoverFromOrigin" - }, -}; - -//========================================================= -// hide from the loudest sound source -//========================================================= -Task_t tlTakeCoverFromBestSound[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slTakeCoverFromBestSound[] = -{ - { - tlTakeCoverFromBestSound, - ARRAYSIZE ( tlTakeCoverFromBestSound ), - bits_COND_NEW_ENEMY, - 0, - "TakeCoverFromBestSound" - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, -// { TASK_TURN_LEFT, (float)179 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slTakeCoverFromEnemy[] = -{ - { - tlTakeCoverFromEnemy, - ARRAYSIZE ( tlTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY, - 0, - "tlTakeCoverFromEnemy" - }, -}; - -Schedule_t *CBaseMonster::m_scheduleList[] = -{ - slIdleStand, - slIdleTrigger, - slIdleWalk, - slAmbush, - slActiveIdle, - slWakeAngry, - slAlertFace, - slAlertSmallFlinch, - slAlertStand, - slInvestigateSound, - slCombatStand, - slCombatFace, - slStandoff, - slArmWeapon, - slReload, - slRangeAttack1, - slRangeAttack2, - slPrimaryMeleeAttack, - slSecondaryMeleeAttack, - slSpecialAttack1, - slSpecialAttack2, - slChaseEnemy, - slChaseEnemyFailed, - slSmallFlinch, - slDie, - slVictoryDance, - slBarnacleVictimGrab, - slBarnacleVictimChomp, - slError, - slWalkToScript, - slRunToScript, - slWaitScript, - slFaceScript, - slCower, - slTakeCoverFromOrigin, - slTakeCoverFromBestSound, - slTakeCoverFromEnemy, - slFail -}; - -Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) -{ - return ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) ); -} - - -Schedule_t *CBaseMonster :: ScheduleInList( const char *pName, Schedule_t **pList, int listCount ) -{ - int i; - - if ( !pName ) - { - ALERT( at_console, "%s set to unnamed schedule!\n", STRING(pev->classname) ); - return NULL; - } - - - for ( i = 0; i < listCount; i++ ) - { - if ( !pList[i]->pName ) - { - ALERT( at_console, "Unnamed schedule!\n" ); - continue; - } - if ( stricmp( pName, pList[i]->pName ) == 0 ) - return pList[i]; - } - return NULL; -} - -//========================================================= -// GetScheduleOfType - returns a pointer to one of the -// monster's available schedules of the indicated type. -//========================================================= -Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) -{ -// ALERT ( at_console, "Sched Type:%d\n", Type ); - switch ( Type ) - { - // This is the schedule for scripted sequences AND scripted AI - case SCHED_AISCRIPT: - { - ASSERT( m_pCine != NULL ); - if ( !m_pCine ) - { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } -// else -// ALERT( at_aiconsole, "Starting script %s for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - - switch ( m_pCine->m_fMoveTo ) - { - case 0: - case 4: - return slWaitScript; - case 1: - return slWalkToScript; - case 2: - return slRunToScript; - case 5: - return slFaceScript; - } - break; - } - case SCHED_IDLE_STAND: - { - if ( RANDOM_LONG(0,14) == 0 && FCanActiveIdle() ) - { - return &slActiveIdle[ 0 ]; - } - - return &slIdleStand[ 0 ]; - } - case SCHED_IDLE_WALK: - { - return &slIdleWalk[ 0 ]; - } - case SCHED_WAIT_TRIGGER: - { - return &slIdleTrigger[ 0 ]; - } - case SCHED_WAKE_ANGRY: - { - return &slWakeAngry[ 0 ]; - } - case SCHED_ALERT_FACE: - { - return &slAlertFace[ 0 ]; - } - case SCHED_ALERT_STAND: - { - return &slAlertStand[ 0 ]; - } - case SCHED_COMBAT_STAND: - { - return &slCombatStand[ 0 ]; - } - case SCHED_COMBAT_FACE: - { - return &slCombatFace[ 0 ]; - } - case SCHED_CHASE_ENEMY: - { - return &slChaseEnemy[ 0 ]; - } - case SCHED_CHASE_ENEMY_FAILED: - { - return &slFail[ 0 ]; - } - case SCHED_SMALL_FLINCH: - { - return &slSmallFlinch[ 0 ]; - } - case SCHED_ALERT_SMALL_FLINCH: - { - return &slAlertSmallFlinch[ 0 ]; - } - case SCHED_RELOAD: - { - return &slReload[ 0 ]; - } - case SCHED_ARM_WEAPON: - { - return &slArmWeapon[ 0 ]; - } - case SCHED_STANDOFF: - { - return &slStandoff[ 0 ]; - } - case SCHED_RANGE_ATTACK1: - { - return &slRangeAttack1[ 0 ]; - } - case SCHED_RANGE_ATTACK2: - { - return &slRangeAttack2[ 0 ]; - } - case SCHED_MELEE_ATTACK1: - { - return &slPrimaryMeleeAttack[ 0 ]; - } - case SCHED_MELEE_ATTACK2: - { - return &slSecondaryMeleeAttack[ 0 ]; - } - case SCHED_SPECIAL_ATTACK1: - { - return &slSpecialAttack1[ 0 ]; - } - case SCHED_SPECIAL_ATTACK2: - { - return &slSpecialAttack2[ 0 ]; - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slTakeCoverFromBestSound[ 0 ]; - } - case SCHED_TAKE_COVER_FROM_ENEMY: - { - return &slTakeCoverFromEnemy[ 0 ]; - } - case SCHED_COWER: - { - return &slCower[ 0 ]; - } - case SCHED_AMBUSH: - { - return &slAmbush[ 0 ]; - } - case SCHED_BARNACLE_VICTIM_GRAB: - { - return &slBarnacleVictimGrab[ 0 ]; - } - case SCHED_BARNACLE_VICTIM_CHOMP: - { - return &slBarnacleVictimChomp[ 0 ]; - } - case SCHED_INVESTIGATE_SOUND: - { - return &slInvestigateSound[ 0 ]; - } - case SCHED_DIE: - { - return &slDie[ 0 ]; - } - case SCHED_TAKE_COVER_FROM_ORIGIN: - { - return &slTakeCoverFromOrigin[ 0 ]; - } - case SCHED_VICTORY_DANCE: - { - return &slVictoryDance[ 0 ]; - } - case SCHED_FAIL: - { - return slFail; - } - default: - { - ALERT ( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); - - return &slIdleStand[ 0 ]; - break; - } - } - - return NULL; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Default behaviors. +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "defaultai.h" +#include "soundent.h" +#include "nodes.h" +#include "scripted.h" + +//========================================================= +// Fail +//========================================================= +Task_t tlFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slFail[] = +{ + { + tlFail, + ARRAYSIZE ( tlFail ), + bits_COND_CAN_ATTACK, + 0, + "Fail" + }, +}; + +//========================================================= +// Idle Schedules +//========================================================= +Task_t tlIdleStand1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)5 },// repick IDLESTAND every five seconds. gives us a chance to pick an active idle, fidget, etc. +}; + +Schedule_t slIdleStand[] = +{ + { + tlIdleStand1, + ARRAYSIZE ( tlIdleStand1 ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_FEAR | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_SMELL_FOOD | + bits_COND_SMELL | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT |// sound flags + bits_SOUND_WORLD | + bits_SOUND_PLAYER | + bits_SOUND_DANGER | + + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "IdleStand" + }, +}; + +Schedule_t slIdleTrigger[] = +{ + { + tlIdleStand1, + ARRAYSIZE ( tlIdleStand1 ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "Idle Trigger" + }, +}; + + +Task_t tlIdleWalk1[] = +{ + { TASK_WALK_PATH, (float)9999 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, +}; + +Schedule_t slIdleWalk[] = +{ + { + tlIdleWalk1, + ARRAYSIZE ( tlIdleWalk1 ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_SMELL_FOOD | + bits_COND_SMELL | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT |// sound flags + + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "Idle Walk" + }, +}; + +//========================================================= +// Ambush - monster stands in place and waits for a new +// enemy, or chance to attack an existing enemy. +//========================================================= +Task_t tlAmbush[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_INDEFINITE, (float)0 }, +}; + +Schedule_t slAmbush[] = +{ + { + tlAmbush, + ARRAYSIZE ( tlAmbush ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED, + + 0, + "Ambush" + }, +}; + +//========================================================= +// ActiveIdle schedule - !!!BUGBUG - if this schedule doesn't +// complete on its own, the monster's HintNode will not be +// cleared, and the rest of the monster's group will avoid +// that node because they think the group member that was +// previously interrupted is still using that node to active +// idle. +///========================================================= +Task_t tlActiveIdle[] = +{ + { TASK_FIND_HINTNODE, (float)0 }, + { TASK_GET_PATH_TO_HINTNODE, (float)0 }, + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_FACE_HINTNODE, (float)0 }, + { TASK_PLAY_ACTIVE_IDLE, (float)0 }, + { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_CLEAR_LASTPOSITION, (float)0 }, + { TASK_CLEAR_HINTNODE, (float)0 }, +}; + +Schedule_t slActiveIdle[] = +{ + { + tlActiveIdle, + ARRAYSIZE( tlActiveIdle ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED | + bits_COND_HEAR_SOUND, + + bits_SOUND_COMBAT | + bits_SOUND_WORLD | + bits_SOUND_PLAYER | + bits_SOUND_DANGER, + "Active Idle" + } +}; + +//========================================================= +// Wake Schedules +//========================================================= +Task_t tlWakeAngry1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_SOUND_WAKE, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, +}; + +Schedule_t slWakeAngry[] = +{ + { + tlWakeAngry1, + ARRAYSIZE ( tlWakeAngry1 ), + 0, + 0, + "Wake Angry" + } +}; + +//========================================================= +// AlertFace Schedules +//========================================================= +Task_t tlAlertFace1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_IDEAL, (float)0 }, +}; + +Schedule_t slAlertFace[] = +{ + { + tlAlertFace1, + ARRAYSIZE ( tlAlertFace1 ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_FEAR | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED, + 0, + "Alert Face" + }, +}; + +//========================================================= +// AlertSmallFlinch Schedule - shot, but didn't see attacker, +// flinch then face +//========================================================= +Task_t tlAlertSmallFlinch[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, + { TASK_SMALL_FLINCH, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_ALERT_FACE }, +}; + +Schedule_t slAlertSmallFlinch[] = +{ + { + tlAlertSmallFlinch, + ARRAYSIZE ( tlAlertSmallFlinch ), + 0, + 0, + "Alert Small Flinch" + }, +}; + +//========================================================= +// AlertIdle Schedules +//========================================================= +Task_t tlAlertStand1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)20 }, + { TASK_SUGGEST_STATE, (float)MONSTERSTATE_IDLE }, +}; + +Schedule_t slAlertStand[] = +{ + { + tlAlertStand1, + ARRAYSIZE ( tlAlertStand1 ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_ENEMY | + bits_COND_SEE_FEAR | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED | + bits_COND_SMELL | + bits_COND_SMELL_FOOD | + bits_COND_HEAR_SOUND, + + bits_SOUND_COMBAT |// sound flags + bits_SOUND_WORLD | + bits_SOUND_PLAYER | + bits_SOUND_DANGER | + + bits_SOUND_MEAT |// scent flags + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "Alert Stand" + }, +}; + +//========================================================= +// InvestigateSound - sends a monster to the location of the +// sound that was just heard, to check things out. +//========================================================= +Task_t tlInvestigateSound[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_GET_PATH_TO_BESTSOUND, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_IDLE }, + { TASK_WAIT, (float)10 }, + { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_CLEAR_LASTPOSITION, (float)0 }, +}; + +Schedule_t slInvestigateSound[] = +{ + { + tlInvestigateSound, + ARRAYSIZE ( tlInvestigateSound ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_FEAR | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "InvestigateSound" + }, +}; + +//========================================================= +// CombatIdle Schedule +//========================================================= +Task_t tlCombatStand1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_INDEFINITE, (float)0 }, +}; + +Schedule_t slCombatStand[] = +{ + { + tlCombatStand1, + ARRAYSIZE ( tlCombatStand1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_CAN_ATTACK, + 0, + "Combat Stand" + }, +}; + +//========================================================= +// CombatFace Schedule +//========================================================= +Task_t tlCombatFace1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_ENEMY, (float)0 }, +}; + +Schedule_t slCombatFace[] = +{ + { + tlCombatFace1, + ARRAYSIZE ( tlCombatFace1 ), + bits_COND_CAN_ATTACK | + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD, + 0, + "Combat Face" + }, +}; + +//========================================================= +// Standoff schedule. Used in combat when a monster is +// hiding in cover or the enemy has moved out of sight. +// Should we look around in this schedule? +//========================================================= +Task_t tlStandoff[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, +}; + +Schedule_t slStandoff[] = +{ + { + tlStandoff, + ARRAYSIZE ( tlStandoff ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_ENEMY_DEAD | + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Standoff" + } +}; + +//========================================================= +// Arm weapon (draw gun) +//========================================================= +Task_t tlArmWeapon[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float) ACT_ARM } +}; + +Schedule_t slArmWeapon[] = +{ + { + tlArmWeapon, + ARRAYSIZE ( tlArmWeapon ), + 0, + 0, + "Arm Weapon" + } +}; + +//========================================================= +// reload schedule +//========================================================= +Task_t tlReload[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, float(ACT_RELOAD) }, +}; + +Schedule_t slReload[] = +{ + { + tlReload, + ARRAYSIZE ( tlReload ), + bits_COND_HEAVY_DAMAGE, + 0, + "Reload" + } +}; + +//========================================================= +// Attack Schedules +//========================================================= + +// primary range attack +Task_t tlRangeAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slRangeAttack1[] = +{ + { + tlRangeAttack1, + ARRAYSIZE ( tlRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Range Attack1" + }, +}; + +// secondary range attack +Task_t tlRangeAttack2[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK2, (float)0 }, +}; + +Schedule_t slRangeAttack2[] = +{ + { + tlRangeAttack2, + ARRAYSIZE ( tlRangeAttack2 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Range Attack2" + }, +}; + +// primary melee attack +Task_t tlPrimaryMeleeAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_MELEE_ATTACK1, (float)0 }, +}; + +Schedule_t slPrimaryMeleeAttack[] = +{ + { + tlPrimaryMeleeAttack1, + ARRAYSIZE ( tlPrimaryMeleeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED, + 0, + "Primary Melee Attack" + }, +}; + +// secondary melee attack +Task_t tlSecondaryMeleeAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_MELEE_ATTACK2, (float)0 }, +}; + +Schedule_t slSecondaryMeleeAttack[] = +{ + { + tlSecondaryMeleeAttack1, + ARRAYSIZE ( tlSecondaryMeleeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED, + 0, + "Secondary Melee Attack" + }, +}; + +// special attack1 +Task_t tlSpecialAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SPECIAL_ATTACK1, (float)0 }, +}; + +Schedule_t slSpecialAttack1[] = +{ + { + tlSpecialAttack1, + ARRAYSIZE ( tlSpecialAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Special Attack1" + }, +}; + +// special attack2 +Task_t tlSpecialAttack2[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SPECIAL_ATTACK2, (float)0 }, +}; + +Schedule_t slSpecialAttack2[] = +{ + { + tlSpecialAttack2, + ARRAYSIZE ( tlSpecialAttack2 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Special Attack2" + }, +}; + +// Chase enemy schedule +Task_t tlChaseEnemy1[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CHASE_ENEMY_FAILED }, + { TASK_GET_PATH_TO_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, +}; + +Schedule_t slChaseEnemy[] = +{ + { + tlChaseEnemy1, + ARRAYSIZE ( tlChaseEnemy1 ), + bits_COND_NEW_ENEMY | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK2 | + bits_COND_TASK_FAILED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Chase Enemy" + }, +}; + + +// Chase enemy failure schedule +Task_t tlChaseEnemyFailed[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_WAIT, (float)0.2 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, +// { TASK_TURN_LEFT, (float)179 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_WAIT, (float)1 }, +}; + +Schedule_t slChaseEnemyFailed[] = +{ + { + tlChaseEnemyFailed, + ARRAYSIZE ( tlChaseEnemyFailed ), + bits_COND_NEW_ENEMY | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK2 | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "tlChaseEnemyFailed" + }, +}; + + +//========================================================= +// small flinch, played when minor damage is taken. +//========================================================= +Task_t tlSmallFlinch[] = +{ + { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, + { TASK_STOP_MOVING, 0 }, + { TASK_SMALL_FLINCH, 0 }, +}; + +Schedule_t slSmallFlinch[] = +{ + { + tlSmallFlinch, + ARRAYSIZE ( tlSmallFlinch ), + 0, + 0, + "Small Flinch" + }, +}; + +//========================================================= +// Die! +//========================================================= +Task_t tlDie1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SOUND_DIE, (float)0 }, + { TASK_DIE, (float)0 }, +}; + +Schedule_t slDie[] = +{ + { + tlDie1, + ARRAYSIZE( tlDie1 ), + 0, + 0, + "Die" + }, +}; + +//========================================================= +// Victory Dance +//========================================================= +Task_t tlVictoryDance[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_WAIT, (float)0 }, +}; + +Schedule_t slVictoryDance[] = +{ + { + tlVictoryDance, + ARRAYSIZE( tlVictoryDance ), + 0, + 0, + "Victory Dance" + }, +}; + +//========================================================= +// BarnacleVictimGrab - barnacle tongue just hit the monster, +// so play a hit animation, then play a cycling pull animation +// as the creature is hoisting the monster. +//========================================================= +Task_t tlBarnacleVictimGrab[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_HIT }, + { TASK_SET_ACTIVITY, (float)ACT_BARNACLE_PULL }, + { TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. +}; + +Schedule_t slBarnacleVictimGrab[] = +{ + { + tlBarnacleVictimGrab, + ARRAYSIZE ( tlBarnacleVictimGrab ), + 0, + 0, + "Barnacle Victim" + } +}; + +//========================================================= +// BarnacleVictimChomp - barnacle has pulled the prey to its +// mouth. Victim should play the BARNCLE_CHOMP animation +// once, then loop the BARNACLE_CHEW animation indefinitely +//========================================================= +Task_t tlBarnacleVictimChomp[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_CHOMP }, + { TASK_SET_ACTIVITY, (float)ACT_BARNACLE_CHEW }, + { TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. +}; + +Schedule_t slBarnacleVictimChomp[] = +{ + { + tlBarnacleVictimChomp, + ARRAYSIZE ( tlBarnacleVictimChomp ), + 0, + 0, + "Barnacle Chomp" + } +}; + + +// Universal Error Schedule +Task_t tlError[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_WAIT_INDEFINITE, (float)0 }, +}; + +Schedule_t slError[] = +{ + { + tlError, + ARRAYSIZE ( tlError ), + 0, + 0, + "Error" + }, +}; + +Task_t tlScriptedWalk[] = +{ + { TASK_WALK_TO_TARGET, (float)TARGET_MOVE_SCRIPTED }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_PLANT_ON_SCRIPT, (float)0 }, + { TASK_FACE_SCRIPT, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_ENABLE_SCRIPT, (float)0 }, + { TASK_WAIT_FOR_SCRIPT, (float)0 }, + { TASK_PLAY_SCRIPT, (float)0 }, +}; + +Schedule_t slWalkToScript[] = +{ + { + tlScriptedWalk, + ARRAYSIZE ( tlScriptedWalk ), + SCRIPT_BREAK_CONDITIONS, + 0, + "WalkToScript" + }, +}; + + +Task_t tlScriptedRun[] = +{ + { TASK_RUN_TO_TARGET, (float)TARGET_MOVE_SCRIPTED }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_PLANT_ON_SCRIPT, (float)0 }, + { TASK_FACE_SCRIPT, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_ENABLE_SCRIPT, (float)0 }, + { TASK_WAIT_FOR_SCRIPT, (float)0 }, + { TASK_PLAY_SCRIPT, (float)0 }, +}; + +Schedule_t slRunToScript[] = +{ + { + tlScriptedRun, + ARRAYSIZE ( tlScriptedRun ), + SCRIPT_BREAK_CONDITIONS, + 0, + "RunToScript" + }, +}; + +Task_t tlScriptedWait[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_WAIT_FOR_SCRIPT, (float)0 }, + { TASK_PLAY_SCRIPT, (float)0 }, +}; + +Schedule_t slWaitScript[] = +{ + { + tlScriptedWait, + ARRAYSIZE ( tlScriptedWait ), + SCRIPT_BREAK_CONDITIONS, + 0, + "WaitForScript" + }, +}; + +Task_t tlScriptedFace[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_SCRIPT, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_WAIT_FOR_SCRIPT, (float)0 }, + { TASK_PLAY_SCRIPT, (float)0 }, +}; + +Schedule_t slFaceScript[] = +{ + { + tlScriptedFace, + ARRAYSIZE ( tlScriptedFace ), + SCRIPT_BREAK_CONDITIONS, + 0, + "FaceScript" + }, +}; + +//========================================================= +// Cower - this is what is usually done when attempts +// to escape danger fail. +//========================================================= +Task_t tlCower[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_COWER }, +}; + +Schedule_t slCower[] = +{ + { + tlCower, + ARRAYSIZE ( tlCower ), + 0, + 0, + "Cower" + }, +}; + +//========================================================= +// move away from where you're currently standing. +//========================================================= +Task_t tlTakeCoverFromOrigin[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_COVER_FROM_ORIGIN, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_TURN_LEFT, (float)179 }, +}; + +Schedule_t slTakeCoverFromOrigin[] = +{ + { + tlTakeCoverFromOrigin, + ARRAYSIZE ( tlTakeCoverFromOrigin ), + bits_COND_NEW_ENEMY, + 0, + "TakeCoverFromOrigin" + }, +}; + +//========================================================= +// hide from the loudest sound source +//========================================================= +Task_t tlTakeCoverFromBestSound[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_TURN_LEFT, (float)179 }, +}; + +Schedule_t slTakeCoverFromBestSound[] = +{ + { + tlTakeCoverFromBestSound, + ARRAYSIZE ( tlTakeCoverFromBestSound ), + bits_COND_NEW_ENEMY, + 0, + "TakeCoverFromBestSound" + }, +}; + +//========================================================= +// Take cover from enemy! Tries lateral cover before node +// cover! +//========================================================= +Task_t tlTakeCoverFromEnemy[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_WAIT, (float)0.2 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, +// { TASK_TURN_LEFT, (float)179 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_WAIT, (float)1 }, +}; + +Schedule_t slTakeCoverFromEnemy[] = +{ + { + tlTakeCoverFromEnemy, + ARRAYSIZE ( tlTakeCoverFromEnemy ), + bits_COND_NEW_ENEMY, + 0, + "tlTakeCoverFromEnemy" + }, +}; + +Schedule_t *CBaseMonster::m_scheduleList[] = +{ + slIdleStand, + slIdleTrigger, + slIdleWalk, + slAmbush, + slActiveIdle, + slWakeAngry, + slAlertFace, + slAlertSmallFlinch, + slAlertStand, + slInvestigateSound, + slCombatStand, + slCombatFace, + slStandoff, + slArmWeapon, + slReload, + slRangeAttack1, + slRangeAttack2, + slPrimaryMeleeAttack, + slSecondaryMeleeAttack, + slSpecialAttack1, + slSpecialAttack2, + slChaseEnemy, + slChaseEnemyFailed, + slSmallFlinch, + slDie, + slVictoryDance, + slBarnacleVictimGrab, + slBarnacleVictimChomp, + slError, + slWalkToScript, + slRunToScript, + slWaitScript, + slFaceScript, + slCower, + slTakeCoverFromOrigin, + slTakeCoverFromBestSound, + slTakeCoverFromEnemy, + slFail +}; + +Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) +{ + return ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) ); +} + + +Schedule_t *CBaseMonster :: ScheduleInList( const char *pName, Schedule_t **pList, int listCount ) +{ + int i; + + if ( !pName ) + { + ALERT( at_console, "%s set to unnamed schedule!\n", STRING(pev->classname) ); + return NULL; + } + + + for ( i = 0; i < listCount; i++ ) + { + if ( !pList[i]->pName ) + { + ALERT( at_console, "Unnamed schedule!\n" ); + continue; + } + if ( stricmp( pName, pList[i]->pName ) == 0 ) + return pList[i]; + } + return NULL; +} + +//========================================================= +// GetScheduleOfType - returns a pointer to one of the +// monster's available schedules of the indicated type. +//========================================================= +Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) +{ +// ALERT ( at_console, "Sched Type:%d\n", Type ); + switch ( Type ) + { + // This is the schedule for scripted sequences AND scripted AI + case SCHED_AISCRIPT: + { + ASSERT( m_pCine != NULL ); + if ( !m_pCine ) + { + ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); + CineCleanup(); + return GetScheduleOfType( SCHED_IDLE_STAND ); + } +// else +// ALERT( at_aiconsole, "Starting script %s for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); + + switch ( m_pCine->m_fMoveTo ) + { + case 0: + case 4: + return slWaitScript; + case 1: + return slWalkToScript; + case 2: + return slRunToScript; + case 5: + return slFaceScript; + } + break; + } + case SCHED_IDLE_STAND: + { + if ( RANDOM_LONG(0,14) == 0 && FCanActiveIdle() ) + { + return &slActiveIdle[ 0 ]; + } + + return &slIdleStand[ 0 ]; + } + case SCHED_IDLE_WALK: + { + return &slIdleWalk[ 0 ]; + } + case SCHED_WAIT_TRIGGER: + { + return &slIdleTrigger[ 0 ]; + } + case SCHED_WAKE_ANGRY: + { + return &slWakeAngry[ 0 ]; + } + case SCHED_ALERT_FACE: + { + return &slAlertFace[ 0 ]; + } + case SCHED_ALERT_STAND: + { + return &slAlertStand[ 0 ]; + } + case SCHED_COMBAT_STAND: + { + return &slCombatStand[ 0 ]; + } + case SCHED_COMBAT_FACE: + { + return &slCombatFace[ 0 ]; + } + case SCHED_CHASE_ENEMY: + { + return &slChaseEnemy[ 0 ]; + } + case SCHED_CHASE_ENEMY_FAILED: + { + return &slFail[ 0 ]; + } + case SCHED_SMALL_FLINCH: + { + return &slSmallFlinch[ 0 ]; + } + case SCHED_ALERT_SMALL_FLINCH: + { + return &slAlertSmallFlinch[ 0 ]; + } + case SCHED_RELOAD: + { + return &slReload[ 0 ]; + } + case SCHED_ARM_WEAPON: + { + return &slArmWeapon[ 0 ]; + } + case SCHED_STANDOFF: + { + return &slStandoff[ 0 ]; + } + case SCHED_RANGE_ATTACK1: + { + return &slRangeAttack1[ 0 ]; + } + case SCHED_RANGE_ATTACK2: + { + return &slRangeAttack2[ 0 ]; + } + case SCHED_MELEE_ATTACK1: + { + return &slPrimaryMeleeAttack[ 0 ]; + } + case SCHED_MELEE_ATTACK2: + { + return &slSecondaryMeleeAttack[ 0 ]; + } + case SCHED_SPECIAL_ATTACK1: + { + return &slSpecialAttack1[ 0 ]; + } + case SCHED_SPECIAL_ATTACK2: + { + return &slSpecialAttack2[ 0 ]; + } + case SCHED_TAKE_COVER_FROM_BEST_SOUND: + { + return &slTakeCoverFromBestSound[ 0 ]; + } + case SCHED_TAKE_COVER_FROM_ENEMY: + { + return &slTakeCoverFromEnemy[ 0 ]; + } + case SCHED_COWER: + { + return &slCower[ 0 ]; + } + case SCHED_AMBUSH: + { + return &slAmbush[ 0 ]; + } + case SCHED_BARNACLE_VICTIM_GRAB: + { + return &slBarnacleVictimGrab[ 0 ]; + } + case SCHED_BARNACLE_VICTIM_CHOMP: + { + return &slBarnacleVictimChomp[ 0 ]; + } + case SCHED_INVESTIGATE_SOUND: + { + return &slInvestigateSound[ 0 ]; + } + case SCHED_DIE: + { + return &slDie[ 0 ]; + } + case SCHED_TAKE_COVER_FROM_ORIGIN: + { + return &slTakeCoverFromOrigin[ 0 ]; + } + case SCHED_VICTORY_DANCE: + { + return &slVictoryDance[ 0 ]; + } + case SCHED_FAIL: + { + return slFail; + } + default: + { + ALERT ( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); + + return &slIdleStand[ 0 ]; + break; + } + } + + return NULL; +} diff --git a/main/source/dlls/defaultai.h b/main/source/dlls/defaultai.h index 23754e64..097e574a 100644 --- a/main/source/dlls/defaultai.h +++ b/main/source/dlls/defaultai.h @@ -1,98 +1,98 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef DEFAULTAI_H -#define DEFAULTAI_H - -//========================================================= -// Failed -//========================================================= -extern Schedule_t slFail[]; - -//========================================================= -// Idle Schedules -//========================================================= -extern Schedule_t slIdleStand[]; -extern Schedule_t slIdleTrigger[]; -extern Schedule_t slIdleWalk[]; - -//========================================================= -// Wake Schedules -//========================================================= -extern Schedule_t slWakeAngry[]; - -//========================================================= -// AlertTurn Schedules -//========================================================= -extern Schedule_t slAlertFace[]; - -//========================================================= -// AlertIdle Schedules -//========================================================= -extern Schedule_t slAlertStand[]; - -//========================================================= -// CombatIdle Schedule -//========================================================= -extern Schedule_t slCombatStand[]; - -//========================================================= -// CombatFace Schedule -//========================================================= -extern Schedule_t slCombatFace[]; - -//========================================================= -// reload schedule -//========================================================= -extern Schedule_t slReload[]; - -//========================================================= -// Attack Schedules -//========================================================= - -extern Schedule_t slRangeAttack1[]; -extern Schedule_t slRangeAttack2[]; - -extern Schedule_t slTakeCoverFromBestSound[]; - -// primary melee attack -extern Schedule_t slMeleeAttack[]; - -// Chase enemy schedule -extern Schedule_t slChaseEnemy[]; - -//========================================================= -// small flinch, used when a relatively minor bit of damage -// is inflicted. -//========================================================= -extern Schedule_t slSmallFlinch[]; - -//========================================================= -// Die! -//========================================================= -extern Schedule_t slDie[]; - -//========================================================= -// Universal Error Schedule -//========================================================= -extern Schedule_t slError[]; - -//========================================================= -// Scripted sequences -//========================================================= -extern Schedule_t slWalkToScript[]; -extern Schedule_t slRunToScript[]; -extern Schedule_t slWaitScript[]; - -#endif // DEFAULTAI_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef DEFAULTAI_H +#define DEFAULTAI_H + +//========================================================= +// Failed +//========================================================= +extern Schedule_t slFail[]; + +//========================================================= +// Idle Schedules +//========================================================= +extern Schedule_t slIdleStand[]; +extern Schedule_t slIdleTrigger[]; +extern Schedule_t slIdleWalk[]; + +//========================================================= +// Wake Schedules +//========================================================= +extern Schedule_t slWakeAngry[]; + +//========================================================= +// AlertTurn Schedules +//========================================================= +extern Schedule_t slAlertFace[]; + +//========================================================= +// AlertIdle Schedules +//========================================================= +extern Schedule_t slAlertStand[]; + +//========================================================= +// CombatIdle Schedule +//========================================================= +extern Schedule_t slCombatStand[]; + +//========================================================= +// CombatFace Schedule +//========================================================= +extern Schedule_t slCombatFace[]; + +//========================================================= +// reload schedule +//========================================================= +extern Schedule_t slReload[]; + +//========================================================= +// Attack Schedules +//========================================================= + +extern Schedule_t slRangeAttack1[]; +extern Schedule_t slRangeAttack2[]; + +extern Schedule_t slTakeCoverFromBestSound[]; + +// primary melee attack +extern Schedule_t slMeleeAttack[]; + +// Chase enemy schedule +extern Schedule_t slChaseEnemy[]; + +//========================================================= +// small flinch, used when a relatively minor bit of damage +// is inflicted. +//========================================================= +extern Schedule_t slSmallFlinch[]; + +//========================================================= +// Die! +//========================================================= +extern Schedule_t slDie[]; + +//========================================================= +// Universal Error Schedule +//========================================================= +extern Schedule_t slError[]; + +//========================================================= +// Scripted sequences +//========================================================= +extern Schedule_t slWalkToScript[]; +extern Schedule_t slRunToScript[]; +extern Schedule_t slWaitScript[]; + +#endif // DEFAULTAI_H diff --git a/main/source/dlls/doors.cpp b/main/source/dlls/doors.cpp index 32657d84..b7d5b16b 100644 --- a/main/source/dlls/doors.cpp +++ b/main/source/dlls/doors.cpp @@ -1,962 +1,962 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== doors.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" -#include "../mod/AvHConstants.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHMarineEquipment.h" - -extern void SetMovedir(entvars_t* ev); - -#define noiseMoving noise1 -#define noiseArrived noise2 - -#include "cbasedoor.h" - -TYPEDESCRIPTION CBaseDoor::m_SaveData[] = -{ - DEFINE_FIELD( CBaseDoor, m_bHealthValue, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bStopSnd, FIELD_CHARACTER ), - - DEFINE_FIELD( CBaseDoor, m_bLockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bLockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bUnlockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bUnlockedSentence, FIELD_CHARACTER ), - -}; - -IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ); - - -#define DOOR_SENTENCEWAIT 6 -#define DOOR_SOUNDWAIT 3 -#define BUTTON_SOUNDWAIT 0.5 - -// play door or button locked or unlocked sounds. -// pass in pointer to valid locksound struct. -// if flocked is true, play 'door is locked' sound, -// otherwise play 'door is unlocked' sound -// NOTE: this routine is shared by doors and buttons - -void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton) -{ - // LOCKED SOUND - - // CONSIDER: consolidate the locksound_t struct (all entries are duplicates for lock/unlock) - // CONSIDER: and condense this code. - float flsoundwait; - - if (fbutton) - flsoundwait = BUTTON_SOUNDWAIT; - else - flsoundwait = DOOR_SOUNDWAIT; - - if (flocked) - { - int fplaysound = (pls->sLockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence); - float fvol; - - if (fplaysound && fplaysentence) - fvol = 0.25; - else - fvol = 1.0; - - // if there is a locked sound, and we've debounced, play sound - if (fplaysound) - { - // play 'door locked' sound - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sLockedSound), fvol, ATTN_NORM); - pls->flwaitSound = gpGlobals->time + flsoundwait; - } - - // if there is a sentence, we've not played all in list, and we've debounced, play sound - if (fplaysentence) - { - // play next 'door locked' sentence in group - int iprev = pls->iLockedSentence; - - pls->iLockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sLockedSentence), - 0.85, ATTN_NORM, 0, 100, pls->iLockedSentence, FALSE); - pls->iUnlockedSentence = 0; - - // make sure we don't keep calling last sentence in list - pls->bEOFLocked = (iprev == pls->iLockedSentence); - - pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; - } - } - else - { - // UNLOCKED SOUND - - int fplaysound = (pls->sUnlockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sUnlockedSentence && !pls->bEOFUnlocked && gpGlobals->time > pls->flwaitSentence); - float fvol; - - // if playing both sentence and sound, lower sound volume so we hear sentence - if (fplaysound && fplaysentence) - fvol = 0.25; - else - fvol = 1.0; - - // play 'door unlocked' sound if set - if (fplaysound) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sUnlockedSound), fvol, ATTN_NORM); - pls->flwaitSound = gpGlobals->time + flsoundwait; - } - - // play next 'door unlocked' sentence in group - if (fplaysentence) - { - int iprev = pls->iUnlockedSentence; - - pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sUnlockedSentence), - 0.85, ATTN_NORM, 0, 100, pls->iUnlockedSentence, FALSE); - pls->iLockedSentence = 0; - - // make sure we don't keep calling last sentence in list - pls->bEOFUnlocked = (iprev == pls->iUnlockedSentence); - pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; - } - } -} - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type - { - pev->skin = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) - { - m_bHealthValue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_bLockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "WaveHeight")) - { - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE -if two doors touch, they are assumed to be connected and operate as a unit. - -TOGGLE causes the door to wait in both the start and end states for a trigger event. - -START_OPEN causes the door to move to its destination when spawned, and operate in reverse. -It is used to temporarily or permanently close off an area when triggered (not usefull for -touch or takedamage doors). - -"angle" determines the opening direction -"targetname" if set, no touch field will be spawned and a remote button or trigger - field activates the door. -"health" if set, door must be shot open -"speed" movement speed (100 default) -"wait" wait before returning (3 default, -1 = never return) -"lip" lip remaining at end of move (8 default) -"dmg" damage to inflict when blocked (2 default) -"sounds" -0) no sound -1) stone -2) base -3) stone chain -4) screechy metal -*/ - -LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); -// -// func_water - same as a door. -// -LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ); - -void CBaseDoor::ResetEntity() -{ - this->SetToggleState(TS_AT_BOTTOM); -} - -void CBaseDoor::Spawn( ) -{ - Precache(); - SetMovedir (pev); - - if ( pev->skin == 0 ) - {//normal door - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - } - else - {// special contents - pev->solid = SOLID_NOT; - SetBits( pev->spawnflags, SF_DOOR_SILENT ); // water is silent for now - } - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2 - UTIL_SetOrigin(pev, m_vecPosition2); - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = pev->origin; - } - - m_toggle_state = TS_AT_BOTTOM; - - // if the door is flagged for USE button activation only, use NULL touch function - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - { - SetTouch ( NULL ); - } - else // touchable button - SetTouch(&CBaseDoor::DoorTouch ); -} - - -void CBaseDoor :: SetToggleState( int state ) -{ - if ( state == TS_AT_TOP ) - UTIL_SetOrigin( pev, m_vecPosition2 ); - else - UTIL_SetOrigin( pev, m_vecPosition1 ); - - this->m_toggle_state = (TOGGLE_STATE)state; -} - - -void CBaseDoor::Precache( void ) -{ - char *pszSound; - -// set the door's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doormove2.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doormove3.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doormove4.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doormove5.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doormove6.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doormove7.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doormove8.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); - break; - case 9: - PRECACHE_SOUND ("doors/doormove9.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove9.wav"); - break; - case 10: - PRECACHE_SOUND ("doors/doormove10.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove10.wav"); - break; - default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - } - -// set the door's 'reached destination' stop sound - switch (m_bStopSnd) - { - case 0: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doorstop1.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doorstop2.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doorstop3.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doorstop4.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doorstop5.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doorstop6.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doorstop7.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doorstop8.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop8.wav"); - break; - default: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); - break; - } - - // get door button sounds, for doors which are directly 'touched' to open - - if (m_bLockedSound) - { - pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); - } - - if (m_bUnlockedSound) - { - pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); - } - - // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) - { - case 1: m_ls.sLockedSentence = ALLOC_STRING("NA"); break; // access denied - case 2: m_ls.sLockedSentence = ALLOC_STRING("ND"); break; // security lockout - case 3: m_ls.sLockedSentence = ALLOC_STRING("NF"); break; // blast door - case 4: m_ls.sLockedSentence = ALLOC_STRING("NFIRE"); break; // fire door - case 5: m_ls.sLockedSentence = ALLOC_STRING("NCHEM"); break; // chemical door - case 6: m_ls.sLockedSentence = ALLOC_STRING("NRAD"); break; // radiation door - case 7: m_ls.sLockedSentence = ALLOC_STRING("NCON"); break; // gen containment - case 8: m_ls.sLockedSentence = ALLOC_STRING("NH"); break; // maintenance door - case 9: m_ls.sLockedSentence = ALLOC_STRING("NG"); break; // broken door - - default: m_ls.sLockedSentence = 0; break; - } - - switch (m_bUnlockedSentence) - { - case 1: m_ls.sUnlockedSentence = ALLOC_STRING("EA"); break; // access granted - case 2: m_ls.sUnlockedSentence = ALLOC_STRING("ED"); break; // security door - case 3: m_ls.sUnlockedSentence = ALLOC_STRING("EF"); break; // blast door - case 4: m_ls.sUnlockedSentence = ALLOC_STRING("EFIRE"); break; // fire door - case 5: m_ls.sUnlockedSentence = ALLOC_STRING("ECHEM"); break; // chemical door - case 6: m_ls.sUnlockedSentence = ALLOC_STRING("ERAD"); break; // radiation door - case 7: m_ls.sUnlockedSentence = ALLOC_STRING("ECON"); break; // gen containment - case 8: m_ls.sUnlockedSentence = ALLOC_STRING("EH"); break; // maintenance door - - default: m_ls.sUnlockedSentence = 0; break; - } -} - -// -// Doors not tied to anything (e.g. button, another door) can be touched, to make them activate. -// -void CBaseDoor::DoorTouch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - // Ignore touches by anything but players - if (!FClassnameIs(pevToucher, "player")) - return; - - // If door has master, and it's not ready to trigger, - // play 'locked' sound - - if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, pOther)) - PlayLockSounds(pev, &m_ls, TRUE, FALSE); - - // If door is somebody's target, then touching does nothing. - // You have to activate the owner (e.g. button). - - if (!FStringNull(pev->targetname)) - { - // play locked sound - PlayLockSounds(pev, &m_ls, TRUE, FALSE); - return; - } - - m_hActivator = pOther;// remember who activated the door - - if (DoorActivate( )) - SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. -} - - -// -// Used by SUB_UseTargets, when a door is the target of a button. -// -void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - // if not ready to be used, ignore "use" command. - if (m_toggle_state == TS_AT_BOTTOM || FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) - DoorActivate(); -} - -// -// Causes the door to "do its thing", i.e. start moving, and cascade activation. -// -int CBaseDoor::DoorActivate( ) -{ - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return 0; - - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) - {// door should close - DoorGoDown(); - } - else - {// door should open - - if ( m_hActivator != NULL && m_hActivator->IsPlayer() ) - {// give health if player opened the door (medikit) - // VARS( m_eoActivator )->health += m_bHealthValue; - - m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); - - } - - // play door unlock sounds - PlayLockSounds(pev, &m_ls, FALSE, FALSE); - - DoorGoUp(); - } - - return 1; -} - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -// -// Starts the door going to its "up" position (simply ToggleData->vecPosition2). -// -void CBaseDoor::DoorGoUp( void ) -{ - entvars_t *pevActivator; - - // It could be going-down, if blocked. - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); - - // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't - // filter them out and leave a client stuck with looping door sounds! - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - - m_toggle_state = TS_GOING_UP; - - SetMoveDone( &CBaseDoor::DoorHitTop ); - if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet - { - float sign = 1.0; - - if ( m_hActivator != NULL ) - { - pevActivator = m_hActivator->pev; - - if ( !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y ) // Y axis rotation, move away from the player - { - Vector vec = pevActivator->origin - pev->origin; - Vector angles = pevActivator->angles; - angles.x = 0; - angles.z = 0; - UTIL_MakeVectors (angles); - // Vector vnext = (pevToucher->origin + (pevToucher->velocity * 10)) - pev->origin; - UTIL_MakeVectors ( pevActivator->angles ); - Vector vnext = (pevActivator->origin + (gpGlobals->v_forward * 10)) - pev->origin; - if ( (vec.x*vnext.y - vec.y*vnext.x) < 0 ) - sign = -1.0; - } - } - AngularMove(m_vecAngle2*sign, pev->speed); - } - else - LinearMove(m_vecPosition2, pev->speed); -} - - -// -// The door has reached the "up" position. Either go back down, or wait for another activation. -// -void CBaseDoor::DoorHitTop( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); - } - - // This line is crashing...fix it? I think it's because doors are being manually reset - //ASSERT(m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_AT_TOP; - - // toggle-doors don't come down automatically, they wait for refire. - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN)) - { - // Re-instate touch method, movement is complete - if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - SetTouch(&CBaseDoor::DoorTouch ); - } - else - { - // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open - pev->nextthink = pev->ltime + m_flWait; - SetThink(&CBaseDoor::DoorGoDown ); - - if ( m_flWait == -1 ) - { - pev->nextthink = -1; - } - } - - // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target - if ( pev->netname && (pev->spawnflags & SF_DOOR_START_OPEN) ) - FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished -} - - -// -// Starts the door going to its "down" position (simply ToggleData->vecPosition1). -// -void CBaseDoor::DoorGoDown( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - -#ifdef DOOR_ASSERT - ASSERT(m_toggle_state == TS_AT_TOP); -#endif // DOOR_ASSERT - m_toggle_state = TS_GOING_DOWN; - - SetMoveDone( &CBaseDoor::DoorHitBottom ); - if ( FClassnameIs(pev, "func_door_rotating"))//rotating door - AngularMove( m_vecAngle1, pev->speed); - else - LinearMove( m_vecPosition1, pev->speed); -} - -// -// The door has reached the "down" position. Back to quiescence. -// -void CBaseDoor::DoorHitBottom( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); - } - - ASSERT((m_toggle_state == TS_GOING_DOWN) || (m_toggle_state == TS_AT_BOTTOM)); - m_toggle_state = TS_AT_BOTTOM; - - // Re-instate touch method, cycle is complete - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - {// use only door - SetTouch ( NULL ); - } - else // touchable door - SetTouch(&CBaseDoor::DoorTouch ); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished - - // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target - if ( pev->netname && !(pev->spawnflags & SF_DOOR_START_OPEN) ) - FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); -} - -void CBaseDoor::Blocked( CBaseEntity *pOther ) -{ - edict_t *pentTarget = NULL; - CBaseDoor *pDoor = NULL; - - - // Hurt the blocker a little. - if ( pev->dmg ) - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); - - // if a door has a negative wait, it would never come back if blocked, - // so let it just squash the object to death real fast - if (m_flWait >= 0) - { - -// Valve fix for super-loud doors! -// if (m_flWait >= 0) -// { -// if (m_toggle_state == TS_GOING_DOWN) - - if(!FBitSet( pev->spawnflags, SF_DOOR_SILENT)) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - } - - if (m_toggle_state == TS_GOING_DOWN) - { - DoorGoUp(); - } - else - { - DoorGoDown(); - } - } - - if(!AvHSUGetIsExternalClassName(STRING(pOther->pev->classname))) - { - AvHDeployedMine* theMine = dynamic_cast(pOther); - if(theMine) - { - theMine->Detonate(); - } - } - - // Block all door pieces with the same targetname here. - if ( !FStringNull ( pev->targetname ) ) - { - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->targetname)); - - if ( VARS( pentTarget ) != pev ) - { - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs ( pentTarget, "func_door" ) || FClassnameIs ( pentTarget, "func_door_rotating" ) ) - { - - pDoor = GetClassPtr( (CBaseDoor *) VARS(pentTarget) ); - - if ( pDoor->m_flWait >= 0) - { - if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity) - { - // this is the most hacked, evil, bastardized thing I've ever seen. kjb - if ( FClassnameIs ( pentTarget, kesFuncDoor ) ) - {// set origin to realign normal doors - pDoor->pev->origin = pev->origin; - pDoor->pev->velocity = g_vecZero;// stop! - } - else - {// set angles to realign rotating doors - pDoor->pev->angles = pev->angles; - pDoor->pev->avelocity = g_vecZero; - } - } - - if ( pDoor->m_toggle_state == TS_GOING_DOWN) - pDoor->DoorGoUp(); - else - pDoor->DoorGoDown(); - } - } - } - } - } -} - -LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); - - -void CRotDoor::Spawn( void ) -{ - Precache(); - // set the axis of rotation - CBaseToggle::AxisDir( pev ); - - // check for clockwise rotation - if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - //m_flWait = 2; who the hell did this? (sjb) - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal"); - - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - -// DOOR_START_OPEN is to allow an entity to be lighted in the closed position -// but spawn in the open position - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2, invert movement direction - pev->angles = m_vecAngle2; - Vector vecSav = m_vecAngle1; - m_vecAngle2 = m_vecAngle1; - m_vecAngle1 = vecSav; - pev->movedir = pev->movedir * -1; - } - - m_toggle_state = TS_AT_BOTTOM; - - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - { - SetTouch ( NULL ); - } - else // touchable button - SetTouch(&CRotDoor::DoorTouch ); -} - - -void CRotDoor :: SetToggleState( int state ) -{ - if ( state == TS_AT_TOP ) - pev->angles = m_vecAngle2; - else - pev->angles = m_vecAngle1; - - UTIL_SetOrigin( pev, pev->origin ); -} - - -class CMomentaryDoor : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BYTE m_bMoveSnd; // sound a door makes while moving -}; - -LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); - -TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = -{ - DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), -}; - -IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ); - -void CMomentaryDoor::Spawn( void ) -{ - SetMovedir (pev); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - if (pev->dmg == 0) - pev->dmg = 2; - - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2 - UTIL_SetOrigin(pev, m_vecPosition2); - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = pev->origin; - } - SetTouch( NULL ); - - Precache(); -} - -void CMomentaryDoor::Precache( void ) -{ - -// set the door's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doormove2.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doormove3.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doormove4.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doormove5.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doormove6.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doormove7.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doormove8.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); - break; - default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - } -} - -void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { -// m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) - { -// m_bHealthValue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType != USE_SET ) // Momentary buttons will pass down a float in here - return; - - if ( value > 1.0 ) - value = 1.0; - Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); - - Vector delta = move - pev->origin; - float speed = delta.Length() * 10; - - if ( speed != 0 ) - { - // This entity only thinks when it moves, so if it's thinking, it's in the process of moving - // play the sound when it starts moving - if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - - LinearMove( move, speed ); - } - -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== doors.cpp ======================================================== + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "doors.h" +#include "../mod/AvHConstants.h" +#include "../mod/AvHServerUtil.h" +#include "../mod/AvHMarineEquipment.h" + +extern void SetMovedir(entvars_t* ev); + +#define noiseMoving noise1 +#define noiseArrived noise2 + +#include "cbasedoor.h" + +TYPEDESCRIPTION CBaseDoor::m_SaveData[] = +{ + DEFINE_FIELD( CBaseDoor, m_bHealthValue, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseDoor, m_bMoveSnd, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseDoor, m_bStopSnd, FIELD_CHARACTER ), + + DEFINE_FIELD( CBaseDoor, m_bLockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseDoor, m_bLockedSentence, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseDoor, m_bUnlockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseDoor, m_bUnlockedSentence, FIELD_CHARACTER ), + +}; + +IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ); + + +#define DOOR_SENTENCEWAIT 6 +#define DOOR_SOUNDWAIT 3 +#define BUTTON_SOUNDWAIT 0.5 + +// play door or button locked or unlocked sounds. +// pass in pointer to valid locksound struct. +// if flocked is true, play 'door is locked' sound, +// otherwise play 'door is unlocked' sound +// NOTE: this routine is shared by doors and buttons + +void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton) +{ + // LOCKED SOUND + + // CONSIDER: consolidate the locksound_t struct (all entries are duplicates for lock/unlock) + // CONSIDER: and condense this code. + float flsoundwait; + + if (fbutton) + flsoundwait = BUTTON_SOUNDWAIT; + else + flsoundwait = DOOR_SOUNDWAIT; + + if (flocked) + { + int fplaysound = (pls->sLockedSound && gpGlobals->time > pls->flwaitSound); + int fplaysentence = (pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence); + float fvol; + + if (fplaysound && fplaysentence) + fvol = 0.25; + else + fvol = 1.0; + + // if there is a locked sound, and we've debounced, play sound + if (fplaysound) + { + // play 'door locked' sound + EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sLockedSound), fvol, ATTN_NORM); + pls->flwaitSound = gpGlobals->time + flsoundwait; + } + + // if there is a sentence, we've not played all in list, and we've debounced, play sound + if (fplaysentence) + { + // play next 'door locked' sentence in group + int iprev = pls->iLockedSentence; + + pls->iLockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sLockedSentence), + 0.85, ATTN_NORM, 0, 100, pls->iLockedSentence, FALSE); + pls->iUnlockedSentence = 0; + + // make sure we don't keep calling last sentence in list + pls->bEOFLocked = (iprev == pls->iLockedSentence); + + pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; + } + } + else + { + // UNLOCKED SOUND + + int fplaysound = (pls->sUnlockedSound && gpGlobals->time > pls->flwaitSound); + int fplaysentence = (pls->sUnlockedSentence && !pls->bEOFUnlocked && gpGlobals->time > pls->flwaitSentence); + float fvol; + + // if playing both sentence and sound, lower sound volume so we hear sentence + if (fplaysound && fplaysentence) + fvol = 0.25; + else + fvol = 1.0; + + // play 'door unlocked' sound if set + if (fplaysound) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sUnlockedSound), fvol, ATTN_NORM); + pls->flwaitSound = gpGlobals->time + flsoundwait; + } + + // play next 'door unlocked' sentence in group + if (fplaysentence) + { + int iprev = pls->iUnlockedSentence; + + pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sUnlockedSentence), + 0.85, ATTN_NORM, 0, 100, pls->iUnlockedSentence, FALSE); + pls->iLockedSentence = 0; + + // make sure we don't keep calling last sentence in list + pls->bEOFUnlocked = (iprev == pls->iUnlockedSentence); + pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; + } + } +} + +// +// Cache user-entity-field values until spawn is called. +// + +void CBaseDoor::KeyValue( KeyValueData *pkvd ) +{ + + if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type + { + pev->skin = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "stopsnd")) + { + m_bStopSnd = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "healthvalue")) + { + m_bHealthValue = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sound")) + { + m_bLockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "WaveHeight")) + { + pev->scale = atof(pkvd->szValue) * (1.0/8.0); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. +It is used to temporarily or permanently close off an area when triggered (not usefull for +touch or takedamage doors). + +"angle" determines the opening direction +"targetname" if set, no touch field will be spawned and a remote button or trigger + field activates the door. +"health" if set, door must be shot open +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (2 default) +"sounds" +0) no sound +1) stone +2) base +3) stone chain +4) screechy metal +*/ + +LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); +// +// func_water - same as a door. +// +LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ); + +void CBaseDoor::ResetEntity() +{ + this->SetToggleState(TS_AT_BOTTOM); +} + +void CBaseDoor::Spawn( ) +{ + Precache(); + SetMovedir (pev); + + if ( pev->skin == 0 ) + {//normal door + if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + } + else + {// special contents + pev->solid = SOLID_NOT; + SetBits( pev->spawnflags, SF_DOOR_SILENT ); // water is silent for now + } + + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL( ENT(pev), STRING(pev->model) ); + + if (pev->speed == 0) + pev->speed = 100; + + m_vecPosition1 = pev->origin; + // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big + m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); + ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); + if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) + { // swap pos1 and pos2, put door at pos2 + UTIL_SetOrigin(pev, m_vecPosition2); + m_vecPosition2 = m_vecPosition1; + m_vecPosition1 = pev->origin; + } + + m_toggle_state = TS_AT_BOTTOM; + + // if the door is flagged for USE button activation only, use NULL touch function + if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) + { + SetTouch ( NULL ); + } + else // touchable button + SetTouch(&CBaseDoor::DoorTouch ); +} + + +void CBaseDoor :: SetToggleState( int state ) +{ + if ( state == TS_AT_TOP ) + UTIL_SetOrigin( pev, m_vecPosition2 ); + else + UTIL_SetOrigin( pev, m_vecPosition1 ); + + this->m_toggle_state = (TOGGLE_STATE)state; +} + + +void CBaseDoor::Precache( void ) +{ + char *pszSound; + +// set the door's "in-motion" sound + switch (m_bMoveSnd) + { + case 0: + pev->noiseMoving = ALLOC_STRING("common/null.wav"); + break; + case 1: + PRECACHE_SOUND ("doors/doormove1.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); + break; + case 2: + PRECACHE_SOUND ("doors/doormove2.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); + break; + case 3: + PRECACHE_SOUND ("doors/doormove3.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); + break; + case 4: + PRECACHE_SOUND ("doors/doormove4.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); + break; + case 5: + PRECACHE_SOUND ("doors/doormove5.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); + break; + case 6: + PRECACHE_SOUND ("doors/doormove6.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); + break; + case 7: + PRECACHE_SOUND ("doors/doormove7.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); + break; + case 8: + PRECACHE_SOUND ("doors/doormove8.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); + break; + case 9: + PRECACHE_SOUND ("doors/doormove9.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove9.wav"); + break; + case 10: + PRECACHE_SOUND ("doors/doormove10.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove10.wav"); + break; + default: + pev->noiseMoving = ALLOC_STRING("common/null.wav"); + break; + } + +// set the door's 'reached destination' stop sound + switch (m_bStopSnd) + { + case 0: + pev->noiseArrived = ALLOC_STRING("common/null.wav"); + break; + case 1: + PRECACHE_SOUND ("doors/doorstop1.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop1.wav"); + break; + case 2: + PRECACHE_SOUND ("doors/doorstop2.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop2.wav"); + break; + case 3: + PRECACHE_SOUND ("doors/doorstop3.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop3.wav"); + break; + case 4: + PRECACHE_SOUND ("doors/doorstop4.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop4.wav"); + break; + case 5: + PRECACHE_SOUND ("doors/doorstop5.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop5.wav"); + break; + case 6: + PRECACHE_SOUND ("doors/doorstop6.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop6.wav"); + break; + case 7: + PRECACHE_SOUND ("doors/doorstop7.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop7.wav"); + break; + case 8: + PRECACHE_SOUND ("doors/doorstop8.wav"); + pev->noiseArrived = ALLOC_STRING("doors/doorstop8.wav"); + break; + default: + pev->noiseArrived = ALLOC_STRING("common/null.wav"); + break; + } + + // get door button sounds, for doors which are directly 'touched' to open + + if (m_bLockedSound) + { + pszSound = ButtonSound( (int)m_bLockedSound ); + PRECACHE_SOUND(pszSound); + m_ls.sLockedSound = ALLOC_STRING(pszSound); + } + + if (m_bUnlockedSound) + { + pszSound = ButtonSound( (int)m_bUnlockedSound ); + PRECACHE_SOUND(pszSound); + m_ls.sUnlockedSound = ALLOC_STRING(pszSound); + } + + // get sentence group names, for doors which are directly 'touched' to open + + switch (m_bLockedSentence) + { + case 1: m_ls.sLockedSentence = ALLOC_STRING("NA"); break; // access denied + case 2: m_ls.sLockedSentence = ALLOC_STRING("ND"); break; // security lockout + case 3: m_ls.sLockedSentence = ALLOC_STRING("NF"); break; // blast door + case 4: m_ls.sLockedSentence = ALLOC_STRING("NFIRE"); break; // fire door + case 5: m_ls.sLockedSentence = ALLOC_STRING("NCHEM"); break; // chemical door + case 6: m_ls.sLockedSentence = ALLOC_STRING("NRAD"); break; // radiation door + case 7: m_ls.sLockedSentence = ALLOC_STRING("NCON"); break; // gen containment + case 8: m_ls.sLockedSentence = ALLOC_STRING("NH"); break; // maintenance door + case 9: m_ls.sLockedSentence = ALLOC_STRING("NG"); break; // broken door + + default: m_ls.sLockedSentence = 0; break; + } + + switch (m_bUnlockedSentence) + { + case 1: m_ls.sUnlockedSentence = ALLOC_STRING("EA"); break; // access granted + case 2: m_ls.sUnlockedSentence = ALLOC_STRING("ED"); break; // security door + case 3: m_ls.sUnlockedSentence = ALLOC_STRING("EF"); break; // blast door + case 4: m_ls.sUnlockedSentence = ALLOC_STRING("EFIRE"); break; // fire door + case 5: m_ls.sUnlockedSentence = ALLOC_STRING("ECHEM"); break; // chemical door + case 6: m_ls.sUnlockedSentence = ALLOC_STRING("ERAD"); break; // radiation door + case 7: m_ls.sUnlockedSentence = ALLOC_STRING("ECON"); break; // gen containment + case 8: m_ls.sUnlockedSentence = ALLOC_STRING("EH"); break; // maintenance door + + default: m_ls.sUnlockedSentence = 0; break; + } +} + +// +// Doors not tied to anything (e.g. button, another door) can be touched, to make them activate. +// +void CBaseDoor::DoorTouch( CBaseEntity *pOther ) +{ + entvars_t* pevToucher = pOther->pev; + + // Ignore touches by anything but players + if (!FClassnameIs(pevToucher, "player")) + return; + + // If door has master, and it's not ready to trigger, + // play 'locked' sound + + if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, pOther)) + PlayLockSounds(pev, &m_ls, TRUE, FALSE); + + // If door is somebody's target, then touching does nothing. + // You have to activate the owner (e.g. button). + + if (!FStringNull(pev->targetname)) + { + // play locked sound + PlayLockSounds(pev, &m_ls, TRUE, FALSE); + return; + } + + m_hActivator = pOther;// remember who activated the door + + if (DoorActivate( )) + SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. +} + + +// +// Used by SUB_UseTargets, when a door is the target of a button. +// +void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + m_hActivator = pActivator; + // if not ready to be used, ignore "use" command. + if (m_toggle_state == TS_AT_BOTTOM || FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) + DoorActivate(); +} + +// +// Causes the door to "do its thing", i.e. start moving, and cascade activation. +// +int CBaseDoor::DoorActivate( ) +{ + if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + return 0; + + if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) + {// door should close + DoorGoDown(); + } + else + {// door should open + + if ( m_hActivator != NULL && m_hActivator->IsPlayer() ) + {// give health if player opened the door (medikit) + // VARS( m_eoActivator )->health += m_bHealthValue; + + m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); + + } + + // play door unlock sounds + PlayLockSounds(pev, &m_ls, FALSE, FALSE); + + DoorGoUp(); + } + + return 1; +} + +extern Vector VecBModelOrigin( entvars_t* pevBModel ); + +// +// Starts the door going to its "up" position (simply ToggleData->vecPosition2). +// +void CBaseDoor::DoorGoUp( void ) +{ + entvars_t *pevActivator; + + // It could be going-down, if blocked. + ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); + + // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't + // filter them out and leave a client stuck with looping door sounds! + if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + + m_toggle_state = TS_GOING_UP; + + SetMoveDone( &CBaseDoor::DoorHitTop ); + if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet + { + float sign = 1.0; + + if ( m_hActivator != NULL ) + { + pevActivator = m_hActivator->pev; + + if ( !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y ) // Y axis rotation, move away from the player + { + Vector vec = pevActivator->origin - pev->origin; + Vector angles = pevActivator->angles; + angles.x = 0; + angles.z = 0; + UTIL_MakeVectors (angles); + // Vector vnext = (pevToucher->origin + (pevToucher->velocity * 10)) - pev->origin; + UTIL_MakeVectors ( pevActivator->angles ); + Vector vnext = (pevActivator->origin + (gpGlobals->v_forward * 10)) - pev->origin; + if ( (vec.x*vnext.y - vec.y*vnext.x) < 0 ) + sign = -1.0; + } + } + AngularMove(m_vecAngle2*sign, pev->speed); + } + else + LinearMove(m_vecPosition2, pev->speed); +} + + +// +// The door has reached the "up" position. Either go back down, or wait for another activation. +// +void CBaseDoor::DoorHitTop( void ) +{ + if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + { + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); + } + + // This line is crashing...fix it? I think it's because doors are being manually reset + //ASSERT(m_toggle_state == TS_GOING_UP); + m_toggle_state = TS_AT_TOP; + + // toggle-doors don't come down automatically, they wait for refire. + if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN)) + { + // Re-instate touch method, movement is complete + if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) + SetTouch(&CBaseDoor::DoorTouch ); + } + else + { + // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open + pev->nextthink = pev->ltime + m_flWait; + SetThink(&CBaseDoor::DoorGoDown ); + + if ( m_flWait == -1 ) + { + pev->nextthink = -1; + } + } + + // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target + if ( pev->netname && (pev->spawnflags & SF_DOOR_START_OPEN) ) + FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); + + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished +} + + +// +// Starts the door going to its "down" position (simply ToggleData->vecPosition1). +// +void CBaseDoor::DoorGoDown( void ) +{ + if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + +#ifdef DOOR_ASSERT + ASSERT(m_toggle_state == TS_AT_TOP); +#endif // DOOR_ASSERT + m_toggle_state = TS_GOING_DOWN; + + SetMoveDone( &CBaseDoor::DoorHitBottom ); + if ( FClassnameIs(pev, "func_door_rotating"))//rotating door + AngularMove( m_vecAngle1, pev->speed); + else + LinearMove( m_vecPosition1, pev->speed); +} + +// +// The door has reached the "down" position. Back to quiescence. +// +void CBaseDoor::DoorHitBottom( void ) +{ + if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + { + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); + } + + ASSERT((m_toggle_state == TS_GOING_DOWN) || (m_toggle_state == TS_AT_BOTTOM)); + m_toggle_state = TS_AT_BOTTOM; + + // Re-instate touch method, cycle is complete + if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) + {// use only door + SetTouch ( NULL ); + } + else // touchable door + SetTouch(&CBaseDoor::DoorTouch ); + + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished + + // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target + if ( pev->netname && !(pev->spawnflags & SF_DOOR_START_OPEN) ) + FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); +} + +void CBaseDoor::Blocked( CBaseEntity *pOther ) +{ + edict_t *pentTarget = NULL; + CBaseDoor *pDoor = NULL; + + + // Hurt the blocker a little. + if ( pev->dmg ) + pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); + + // if a door has a negative wait, it would never come back if blocked, + // so let it just squash the object to death real fast + if (m_flWait >= 0) + { + +// Valve fix for super-loud doors! +// if (m_flWait >= 0) +// { +// if (m_toggle_state == TS_GOING_DOWN) + + if(!FBitSet( pev->spawnflags, SF_DOOR_SILENT)) + { + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); + } + + if (m_toggle_state == TS_GOING_DOWN) + { + DoorGoUp(); + } + else + { + DoorGoDown(); + } + } + + if(!AvHSUGetIsExternalClassName(STRING(pOther->pev->classname))) + { + AvHDeployedMine* theMine = dynamic_cast(pOther); + if(theMine) + { + theMine->Detonate(); + } + } + + // Block all door pieces with the same targetname here. + if ( !FStringNull ( pev->targetname ) ) + { + for (;;) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->targetname)); + + if ( VARS( pentTarget ) != pev ) + { + if (FNullEnt(pentTarget)) + break; + + if ( FClassnameIs ( pentTarget, "func_door" ) || FClassnameIs ( pentTarget, "func_door_rotating" ) ) + { + + pDoor = GetClassPtr( (CBaseDoor *) VARS(pentTarget) ); + + if ( pDoor->m_flWait >= 0) + { + if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity) + { + // this is the most hacked, evil, bastardized thing I've ever seen. kjb + if ( FClassnameIs ( pentTarget, kesFuncDoor ) ) + {// set origin to realign normal doors + pDoor->pev->origin = pev->origin; + pDoor->pev->velocity = g_vecZero;// stop! + } + else + {// set angles to realign rotating doors + pDoor->pev->angles = pev->angles; + pDoor->pev->avelocity = g_vecZero; + } + } + + if ( pDoor->m_toggle_state == TS_GOING_DOWN) + pDoor->DoorGoUp(); + else + pDoor->DoorGoDown(); + } + } + } + } + } +} + +LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); + + +void CRotDoor::Spawn( void ) +{ + Precache(); + // set the axis of rotation + CBaseToggle::AxisDir( pev ); + + // check for clockwise rotation + if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) + pev->movedir = pev->movedir * -1; + + //m_flWait = 2; who the hell did this? (sjb) + m_vecAngle1 = pev->angles; + m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; + + ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal"); + + if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL(ENT(pev), STRING(pev->model) ); + + if (pev->speed == 0) + pev->speed = 100; + +// DOOR_START_OPEN is to allow an entity to be lighted in the closed position +// but spawn in the open position + if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) + { // swap pos1 and pos2, put door at pos2, invert movement direction + pev->angles = m_vecAngle2; + Vector vecSav = m_vecAngle1; + m_vecAngle2 = m_vecAngle1; + m_vecAngle1 = vecSav; + pev->movedir = pev->movedir * -1; + } + + m_toggle_state = TS_AT_BOTTOM; + + if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) + { + SetTouch ( NULL ); + } + else // touchable button + SetTouch(&CRotDoor::DoorTouch ); +} + + +void CRotDoor :: SetToggleState( int state ) +{ + if ( state == TS_AT_TOP ) + pev->angles = m_vecAngle2; + else + pev->angles = m_vecAngle1; + + UTIL_SetOrigin( pev, pev->origin ); +} + + +class CMomentaryDoor : public CBaseToggle +{ +public: + void Spawn( void ); + void Precache( void ); + + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + BYTE m_bMoveSnd; // sound a door makes while moving +}; + +LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); + +TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = +{ + DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), +}; + +IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ); + +void CMomentaryDoor::Spawn( void ) +{ + SetMovedir (pev); + + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL( ENT(pev), STRING(pev->model) ); + + if (pev->speed == 0) + pev->speed = 100; + if (pev->dmg == 0) + pev->dmg = 2; + + m_vecPosition1 = pev->origin; + // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big + m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); + ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); + + if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) + { // swap pos1 and pos2, put door at pos2 + UTIL_SetOrigin(pev, m_vecPosition2); + m_vecPosition2 = m_vecPosition1; + m_vecPosition1 = pev->origin; + } + SetTouch( NULL ); + + Precache(); +} + +void CMomentaryDoor::Precache( void ) +{ + +// set the door's "in-motion" sound + switch (m_bMoveSnd) + { + case 0: + pev->noiseMoving = ALLOC_STRING("common/null.wav"); + break; + case 1: + PRECACHE_SOUND ("doors/doormove1.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); + break; + case 2: + PRECACHE_SOUND ("doors/doormove2.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); + break; + case 3: + PRECACHE_SOUND ("doors/doormove3.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); + break; + case 4: + PRECACHE_SOUND ("doors/doormove4.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); + break; + case 5: + PRECACHE_SOUND ("doors/doormove5.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); + break; + case 6: + PRECACHE_SOUND ("doors/doormove6.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); + break; + case 7: + PRECACHE_SOUND ("doors/doormove7.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); + break; + case 8: + PRECACHE_SOUND ("doors/doormove8.wav"); + pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); + break; + default: + pev->noiseMoving = ALLOC_STRING("common/null.wav"); + break; + } +} + +void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) +{ + + if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "stopsnd")) + { +// m_bStopSnd = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "healthvalue")) + { +// m_bHealthValue = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( useType != USE_SET ) // Momentary buttons will pass down a float in here + return; + + if ( value > 1.0 ) + value = 1.0; + Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); + + Vector delta = move - pev->origin; + float speed = delta.Length() * 10; + + if ( speed != 0 ) + { + // This entity only thinks when it moves, so if it's thinking, it's in the process of moving + // play the sound when it starts moving + if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + + LinearMove( move, speed ); + } + +} diff --git a/main/source/dlls/doors.cpp~ b/main/source/dlls/doors.cpp~ deleted file mode 100644 index 4ff5ae4d..00000000 --- a/main/source/dlls/doors.cpp~ +++ /dev/null @@ -1,962 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== doors.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" -#include "..mod/AvHConstants.h" -#include "..mod/AvHServerUtil.h" -#include "..mod/AvHMarineEquipment.h" - -extern void SetMovedir(entvars_t* ev); - -#define noiseMoving noise1 -#define noiseArrived noise2 - -#include "cbasedoor.h" - -TYPEDESCRIPTION CBaseDoor::m_SaveData[] = -{ - DEFINE_FIELD( CBaseDoor, m_bHealthValue, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bStopSnd, FIELD_CHARACTER ), - - DEFINE_FIELD( CBaseDoor, m_bLockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bLockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bUnlockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bUnlockedSentence, FIELD_CHARACTER ), - -}; - -IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ); - - -#define DOOR_SENTENCEWAIT 6 -#define DOOR_SOUNDWAIT 3 -#define BUTTON_SOUNDWAIT 0.5 - -// play door or button locked or unlocked sounds. -// pass in pointer to valid locksound struct. -// if flocked is true, play 'door is locked' sound, -// otherwise play 'door is unlocked' sound -// NOTE: this routine is shared by doors and buttons - -void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton) -{ - // LOCKED SOUND - - // CONSIDER: consolidate the locksound_t struct (all entries are duplicates for lock/unlock) - // CONSIDER: and condense this code. - float flsoundwait; - - if (fbutton) - flsoundwait = BUTTON_SOUNDWAIT; - else - flsoundwait = DOOR_SOUNDWAIT; - - if (flocked) - { - int fplaysound = (pls->sLockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence); - float fvol; - - if (fplaysound && fplaysentence) - fvol = 0.25; - else - fvol = 1.0; - - // if there is a locked sound, and we've debounced, play sound - if (fplaysound) - { - // play 'door locked' sound - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sLockedSound), fvol, ATTN_NORM); - pls->flwaitSound = gpGlobals->time + flsoundwait; - } - - // if there is a sentence, we've not played all in list, and we've debounced, play sound - if (fplaysentence) - { - // play next 'door locked' sentence in group - int iprev = pls->iLockedSentence; - - pls->iLockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sLockedSentence), - 0.85, ATTN_NORM, 0, 100, pls->iLockedSentence, FALSE); - pls->iUnlockedSentence = 0; - - // make sure we don't keep calling last sentence in list - pls->bEOFLocked = (iprev == pls->iLockedSentence); - - pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; - } - } - else - { - // UNLOCKED SOUND - - int fplaysound = (pls->sUnlockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sUnlockedSentence && !pls->bEOFUnlocked && gpGlobals->time > pls->flwaitSentence); - float fvol; - - // if playing both sentence and sound, lower sound volume so we hear sentence - if (fplaysound && fplaysentence) - fvol = 0.25; - else - fvol = 1.0; - - // play 'door unlocked' sound if set - if (fplaysound) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sUnlockedSound), fvol, ATTN_NORM); - pls->flwaitSound = gpGlobals->time + flsoundwait; - } - - // play next 'door unlocked' sentence in group - if (fplaysentence) - { - int iprev = pls->iUnlockedSentence; - - pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sUnlockedSentence), - 0.85, ATTN_NORM, 0, 100, pls->iUnlockedSentence, FALSE); - pls->iLockedSentence = 0; - - // make sure we don't keep calling last sentence in list - pls->bEOFUnlocked = (iprev == pls->iUnlockedSentence); - pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; - } - } -} - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type - { - pev->skin = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) - { - m_bHealthValue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_bLockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "WaveHeight")) - { - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE -if two doors touch, they are assumed to be connected and operate as a unit. - -TOGGLE causes the door to wait in both the start and end states for a trigger event. - -START_OPEN causes the door to move to its destination when spawned, and operate in reverse. -It is used to temporarily or permanently close off an area when triggered (not usefull for -touch or takedamage doors). - -"angle" determines the opening direction -"targetname" if set, no touch field will be spawned and a remote button or trigger - field activates the door. -"health" if set, door must be shot open -"speed" movement speed (100 default) -"wait" wait before returning (3 default, -1 = never return) -"lip" lip remaining at end of move (8 default) -"dmg" damage to inflict when blocked (2 default) -"sounds" -0) no sound -1) stone -2) base -3) stone chain -4) screechy metal -*/ - -LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); -// -// func_water - same as a door. -// -LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ); - -void CBaseDoor::ResetEntity() -{ - this->SetToggleState(TS_AT_BOTTOM); -} - -void CBaseDoor::Spawn( ) -{ - Precache(); - SetMovedir (pev); - - if ( pev->skin == 0 ) - {//normal door - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - } - else - {// special contents - pev->solid = SOLID_NOT; - SetBits( pev->spawnflags, SF_DOOR_SILENT ); // water is silent for now - } - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2 - UTIL_SetOrigin(pev, m_vecPosition2); - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = pev->origin; - } - - m_toggle_state = TS_AT_BOTTOM; - - // if the door is flagged for USE button activation only, use NULL touch function - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - { - SetTouch ( NULL ); - } - else // touchable button - SetTouch(&CBaseDoor::DoorTouch ); -} - - -void CBaseDoor :: SetToggleState( int state ) -{ - if ( state == TS_AT_TOP ) - UTIL_SetOrigin( pev, m_vecPosition2 ); - else - UTIL_SetOrigin( pev, m_vecPosition1 ); - - this->m_toggle_state = (TOGGLE_STATE)state; -} - - -void CBaseDoor::Precache( void ) -{ - char *pszSound; - -// set the door's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doormove2.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doormove3.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doormove4.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doormove5.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doormove6.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doormove7.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doormove8.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); - break; - case 9: - PRECACHE_SOUND ("doors/doormove9.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove9.wav"); - break; - case 10: - PRECACHE_SOUND ("doors/doormove10.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove10.wav"); - break; - default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - } - -// set the door's 'reached destination' stop sound - switch (m_bStopSnd) - { - case 0: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doorstop1.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doorstop2.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doorstop3.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doorstop4.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doorstop5.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doorstop6.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doorstop7.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doorstop8.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop8.wav"); - break; - default: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); - break; - } - - // get door button sounds, for doors which are directly 'touched' to open - - if (m_bLockedSound) - { - pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); - } - - if (m_bUnlockedSound) - { - pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); - } - - // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) - { - case 1: m_ls.sLockedSentence = ALLOC_STRING("NA"); break; // access denied - case 2: m_ls.sLockedSentence = ALLOC_STRING("ND"); break; // security lockout - case 3: m_ls.sLockedSentence = ALLOC_STRING("NF"); break; // blast door - case 4: m_ls.sLockedSentence = ALLOC_STRING("NFIRE"); break; // fire door - case 5: m_ls.sLockedSentence = ALLOC_STRING("NCHEM"); break; // chemical door - case 6: m_ls.sLockedSentence = ALLOC_STRING("NRAD"); break; // radiation door - case 7: m_ls.sLockedSentence = ALLOC_STRING("NCON"); break; // gen containment - case 8: m_ls.sLockedSentence = ALLOC_STRING("NH"); break; // maintenance door - case 9: m_ls.sLockedSentence = ALLOC_STRING("NG"); break; // broken door - - default: m_ls.sLockedSentence = 0; break; - } - - switch (m_bUnlockedSentence) - { - case 1: m_ls.sUnlockedSentence = ALLOC_STRING("EA"); break; // access granted - case 2: m_ls.sUnlockedSentence = ALLOC_STRING("ED"); break; // security door - case 3: m_ls.sUnlockedSentence = ALLOC_STRING("EF"); break; // blast door - case 4: m_ls.sUnlockedSentence = ALLOC_STRING("EFIRE"); break; // fire door - case 5: m_ls.sUnlockedSentence = ALLOC_STRING("ECHEM"); break; // chemical door - case 6: m_ls.sUnlockedSentence = ALLOC_STRING("ERAD"); break; // radiation door - case 7: m_ls.sUnlockedSentence = ALLOC_STRING("ECON"); break; // gen containment - case 8: m_ls.sUnlockedSentence = ALLOC_STRING("EH"); break; // maintenance door - - default: m_ls.sUnlockedSentence = 0; break; - } -} - -// -// Doors not tied to anything (e.g. button, another door) can be touched, to make them activate. -// -void CBaseDoor::DoorTouch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - // Ignore touches by anything but players - if (!FClassnameIs(pevToucher, "player")) - return; - - // If door has master, and it's not ready to trigger, - // play 'locked' sound - - if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, pOther)) - PlayLockSounds(pev, &m_ls, TRUE, FALSE); - - // If door is somebody's target, then touching does nothing. - // You have to activate the owner (e.g. button). - - if (!FStringNull(pev->targetname)) - { - // play locked sound - PlayLockSounds(pev, &m_ls, TRUE, FALSE); - return; - } - - m_hActivator = pOther;// remember who activated the door - - if (DoorActivate( )) - SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. -} - - -// -// Used by SUB_UseTargets, when a door is the target of a button. -// -void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - // if not ready to be used, ignore "use" command. - if (m_toggle_state == TS_AT_BOTTOM || FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) - DoorActivate(); -} - -// -// Causes the door to "do its thing", i.e. start moving, and cascade activation. -// -int CBaseDoor::DoorActivate( ) -{ - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return 0; - - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) - {// door should close - DoorGoDown(); - } - else - {// door should open - - if ( m_hActivator != NULL && m_hActivator->IsPlayer() ) - {// give health if player opened the door (medikit) - // VARS( m_eoActivator )->health += m_bHealthValue; - - m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); - - } - - // play door unlock sounds - PlayLockSounds(pev, &m_ls, FALSE, FALSE); - - DoorGoUp(); - } - - return 1; -} - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -// -// Starts the door going to its "up" position (simply ToggleData->vecPosition2). -// -void CBaseDoor::DoorGoUp( void ) -{ - entvars_t *pevActivator; - - // It could be going-down, if blocked. - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); - - // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't - // filter them out and leave a client stuck with looping door sounds! - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - - m_toggle_state = TS_GOING_UP; - - SetMoveDone( &CBaseDoor::DoorHitTop ); - if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet - { - float sign = 1.0; - - if ( m_hActivator != NULL ) - { - pevActivator = m_hActivator->pev; - - if ( !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y ) // Y axis rotation, move away from the player - { - Vector vec = pevActivator->origin - pev->origin; - Vector angles = pevActivator->angles; - angles.x = 0; - angles.z = 0; - UTIL_MakeVectors (angles); - // Vector vnext = (pevToucher->origin + (pevToucher->velocity * 10)) - pev->origin; - UTIL_MakeVectors ( pevActivator->angles ); - Vector vnext = (pevActivator->origin + (gpGlobals->v_forward * 10)) - pev->origin; - if ( (vec.x*vnext.y - vec.y*vnext.x) < 0 ) - sign = -1.0; - } - } - AngularMove(m_vecAngle2*sign, pev->speed); - } - else - LinearMove(m_vecPosition2, pev->speed); -} - - -// -// The door has reached the "up" position. Either go back down, or wait for another activation. -// -void CBaseDoor::DoorHitTop( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); - } - - // This line is crashing...fix it? I think it's because doors are being manually reset - //ASSERT(m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_AT_TOP; - - // toggle-doors don't come down automatically, they wait for refire. - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN)) - { - // Re-instate touch method, movement is complete - if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - SetTouch(&CBaseDoor::DoorTouch ); - } - else - { - // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open - pev->nextthink = pev->ltime + m_flWait; - SetThink(&CBaseDoor::DoorGoDown ); - - if ( m_flWait == -1 ) - { - pev->nextthink = -1; - } - } - - // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target - if ( pev->netname && (pev->spawnflags & SF_DOOR_START_OPEN) ) - FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished -} - - -// -// Starts the door going to its "down" position (simply ToggleData->vecPosition1). -// -void CBaseDoor::DoorGoDown( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - -#ifdef DOOR_ASSERT - ASSERT(m_toggle_state == TS_AT_TOP); -#endif // DOOR_ASSERT - m_toggle_state = TS_GOING_DOWN; - - SetMoveDone( &CBaseDoor::DoorHitBottom ); - if ( FClassnameIs(pev, "func_door_rotating"))//rotating door - AngularMove( m_vecAngle1, pev->speed); - else - LinearMove( m_vecPosition1, pev->speed); -} - -// -// The door has reached the "down" position. Back to quiescence. -// -void CBaseDoor::DoorHitBottom( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); - } - - ASSERT((m_toggle_state == TS_GOING_DOWN) || (m_toggle_state == TS_AT_BOTTOM)); - m_toggle_state = TS_AT_BOTTOM; - - // Re-instate touch method, cycle is complete - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - {// use only door - SetTouch ( NULL ); - } - else // touchable door - SetTouch(&CBaseDoor::DoorTouch ); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished - - // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target - if ( pev->netname && !(pev->spawnflags & SF_DOOR_START_OPEN) ) - FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); -} - -void CBaseDoor::Blocked( CBaseEntity *pOther ) -{ - edict_t *pentTarget = NULL; - CBaseDoor *pDoor = NULL; - - - // Hurt the blocker a little. - if ( pev->dmg ) - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); - - // if a door has a negative wait, it would never come back if blocked, - // so let it just squash the object to death real fast - if (m_flWait >= 0) - { - -// Valve fix for super-loud doors! -// if (m_flWait >= 0) -// { -// if (m_toggle_state == TS_GOING_DOWN) - - if(!FBitSet( pev->spawnflags, SF_DOOR_SILENT)) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - } - - if (m_toggle_state == TS_GOING_DOWN) - { - DoorGoUp(); - } - else - { - DoorGoDown(); - } - } - - if(!AvHSUGetIsExternalClassName(STRING(pOther->pev->classname))) - { - AvHDeployedMine* theMine = dynamic_cast(pOther); - if(theMine) - { - theMine->Detonate(); - } - } - - // Block all door pieces with the same targetname here. - if ( !FStringNull ( pev->targetname ) ) - { - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->targetname)); - - if ( VARS( pentTarget ) != pev ) - { - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs ( pentTarget, "func_door" ) || FClassnameIs ( pentTarget, "func_door_rotating" ) ) - { - - pDoor = GetClassPtr( (CBaseDoor *) VARS(pentTarget) ); - - if ( pDoor->m_flWait >= 0) - { - if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity) - { - // this is the most hacked, evil, bastardized thing I've ever seen. kjb - if ( FClassnameIs ( pentTarget, kesFuncDoor ) ) - {// set origin to realign normal doors - pDoor->pev->origin = pev->origin; - pDoor->pev->velocity = g_vecZero;// stop! - } - else - {// set angles to realign rotating doors - pDoor->pev->angles = pev->angles; - pDoor->pev->avelocity = g_vecZero; - } - } - - if ( pDoor->m_toggle_state == TS_GOING_DOWN) - pDoor->DoorGoUp(); - else - pDoor->DoorGoDown(); - } - } - } - } - } -} - -LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); - - -void CRotDoor::Spawn( void ) -{ - Precache(); - // set the axis of rotation - CBaseToggle::AxisDir( pev ); - - // check for clockwise rotation - if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - //m_flWait = 2; who the hell did this? (sjb) - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal"); - - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - -// DOOR_START_OPEN is to allow an entity to be lighted in the closed position -// but spawn in the open position - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2, invert movement direction - pev->angles = m_vecAngle2; - Vector vecSav = m_vecAngle1; - m_vecAngle2 = m_vecAngle1; - m_vecAngle1 = vecSav; - pev->movedir = pev->movedir * -1; - } - - m_toggle_state = TS_AT_BOTTOM; - - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - { - SetTouch ( NULL ); - } - else // touchable button - SetTouch(&CRotDoor::DoorTouch ); -} - - -void CRotDoor :: SetToggleState( int state ) -{ - if ( state == TS_AT_TOP ) - pev->angles = m_vecAngle2; - else - pev->angles = m_vecAngle1; - - UTIL_SetOrigin( pev, pev->origin ); -} - - -class CMomentaryDoor : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BYTE m_bMoveSnd; // sound a door makes while moving -}; - -LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); - -TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = -{ - DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), -}; - -IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ); - -void CMomentaryDoor::Spawn( void ) -{ - SetMovedir (pev); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - if (pev->dmg == 0) - pev->dmg = 2; - - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2 - UTIL_SetOrigin(pev, m_vecPosition2); - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = pev->origin; - } - SetTouch( NULL ); - - Precache(); -} - -void CMomentaryDoor::Precache( void ) -{ - -// set the door's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doormove2.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doormove3.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doormove4.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doormove5.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doormove6.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doormove7.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doormove8.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); - break; - default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - } -} - -void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { -// m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) - { -// m_bHealthValue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType != USE_SET ) // Momentary buttons will pass down a float in here - return; - - if ( value > 1.0 ) - value = 1.0; - Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); - - Vector delta = move - pev->origin; - float speed = delta.Length() * 10; - - if ( speed != 0 ) - { - // This entity only thinks when it moves, so if it's thinking, it's in the process of moving - // play the sound when it starts moving - if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - - LinearMove( move, speed ); - } - -} diff --git a/main/source/dlls/doors.h b/main/source/dlls/doors.h index 724ad577..600a3a1b 100644 --- a/main/source/dlls/doors.h +++ b/main/source/dlls/doors.h @@ -1,33 +1,33 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef DOORS_H -#define DOORS_H - -// doors -#define SF_DOOR_ROTATE_Y 0 -#define SF_DOOR_START_OPEN 1 -#define SF_DOOR_ROTATE_BACKWARDS 2 -#define SF_DOOR_PASSABLE 8 -#define SF_DOOR_ONEWAY 16 -#define SF_DOOR_NO_AUTO_RETURN 32 -#define SF_DOOR_ROTATE_Z 64 -#define SF_DOOR_ROTATE_X 128 -#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button. -#define SF_DOOR_NOMONSTERS 512 // Monster can't open -#define SF_DOOR_SILENT 0x80000000 - - - -#endif //DOORS_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef DOORS_H +#define DOORS_H + +// doors +#define SF_DOOR_ROTATE_Y 0 +#define SF_DOOR_START_OPEN 1 +#define SF_DOOR_ROTATE_BACKWARDS 2 +#define SF_DOOR_PASSABLE 8 +#define SF_DOOR_ONEWAY 16 +#define SF_DOOR_NO_AUTO_RETURN 32 +#define SF_DOOR_ROTATE_Z 64 +#define SF_DOOR_ROTATE_X 128 +#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button. +#define SF_DOOR_NOMONSTERS 512 // Monster can't open +#define SF_DOOR_SILENT 0x80000000 + + + +#endif //DOORS_H diff --git a/main/source/dlls/effects.cpp b/main/source/dlls/effects.cpp index 79c8705b..c350faac 100644 --- a/main/source/dlls/effects.cpp +++ b/main/source/dlls/effects.cpp @@ -1,2270 +1,2270 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "../engine/customentity.h" -#include "effects.h" -#include "weapons.h" -#include "decals.h" -#include "func_break.h" -#include "../engine/shake.h" -#include "../mod/AvHServerVariables.h" -extern cvar_t avh_killdelay; - -#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired - -#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. - - -// Lightning target, just alias landmark -LINK_ENTITY_TO_CLASS( info_target, CPointEntity ); - - -class CBubbling : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - void EXPORT FizzThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; - - int m_density; - int m_frequency; - int m_bubbleModel; - int m_state; -}; - -LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling ); - -TYPEDESCRIPTION CBubbling::m_SaveData[] = -{ - DEFINE_FIELD( CBubbling, m_density, FIELD_INTEGER ), - DEFINE_FIELD( CBubbling, m_frequency, FIELD_INTEGER ), - DEFINE_FIELD( CBubbling, m_state, FIELD_INTEGER ), - // Let spawn restore this! - // DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ); - - -#define SF_BUBBLES_STARTOFF 0x0001 - -void CBubbling::Spawn( void ) -{ - Precache( ); - SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size - - pev->solid = SOLID_NOT; // Remove model & collisions - pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on - pev->rendermode = kRenderTransTexture; - int speed = pev->speed > 0 ? pev->speed : -pev->speed; - - // HACKHACK!!! - Speed in rendercolor - pev->rendercolor.x = speed >> 8; - pev->rendercolor.y = speed & 255; - pev->rendercolor.z = (pev->speed < 0) ? 1 : 0; - - - if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) - { - SetThink( &CBubbling::FizzThink ); - pev->nextthink = gpGlobals->time + 2.0; - m_state = 1; - } - else - m_state = 0; -} - -void CBubbling::Precache( void ) -{ - m_bubbleModel = PRECACHE_MODEL("sprites/bubble2.spr"); // Precache bubble sprite -} - - -void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( ShouldToggle( useType, m_state ) ) - m_state = !m_state; - - if ( m_state ) - { - SetThink( &CBubbling::FizzThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - SetThink( NULL ); - pev->nextthink = 0; - } -} - - -void CBubbling::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "density")) - { - m_density = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency")) - { - m_frequency = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "current")) - { - pev->speed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CBubbling::FizzThink( void ) -{ - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) ); - WRITE_BYTE( TE_FIZZ ); - WRITE_SHORT( (short)ENTINDEX( edict() ) ); - WRITE_SHORT( (short)m_bubbleModel ); - WRITE_BYTE( m_density ); - MESSAGE_END(); - - if ( m_frequency > 19 ) - pev->nextthink = gpGlobals->time + 0.5; - else - pev->nextthink = gpGlobals->time + 2.5 - (0.1 * m_frequency); -} - -// -------------------------------------------------- -// -// Beams -// -// -------------------------------------------------- - -LINK_ENTITY_TO_CLASS( beam, CBeam ); - -void CBeam::Spawn( void ) -{ - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); -} - -void CBeam::Precache( void ) -{ - if ( pev->owner ) - SetStartEntity( ENTINDEX( pev->owner ) ); - if ( pev->aiment ) - SetEndEntity( ENTINDEX( pev->aiment ) ); -} - -void CBeam::SetStartEntity( int entityIndex ) -{ - pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12); - pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); -} - -void CBeam::SetEndEntity( int entityIndex ) -{ - pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12); - pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); -} - - -// These don't take attachments into account -const Vector &CBeam::GetStartPos( void ) -{ - if ( GetType() == BEAM_ENTS ) - { - edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() ); - return pent->v.origin; - } - return pev->origin; -} - - -const Vector &CBeam::GetEndPos( void ) -{ - int type = GetType(); - if ( type == BEAM_POINTS || type == BEAM_HOSE ) - { - return pev->angles; - } - - edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() ); - if ( pent ) - return pent->v.origin; - return pev->angles; -} - - -CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) -{ - // Create a new entity with CBeam private data - CBeam *pBeam = GetClassPtr( (CBeam *)NULL ); - pBeam->pev->classname = MAKE_STRING("beam"); - - pBeam->BeamInit( pSpriteName, width ); - - return pBeam; -} - - -void CBeam::BeamInit( const char *pSpriteName, int width ) -{ - pev->flags |= FL_CUSTOMENTITY; - SetColor( 255, 255, 255 ); - SetBrightness( 255 ); - SetNoise( 0 ); - SetFrame( 0 ); - SetScrollRate( 0 ); - pev->model = MAKE_STRING( pSpriteName ); - SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) ); - SetWidth( width ); - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; -} - - -void CBeam::PointsInit( const Vector &start, const Vector &end ) -{ - SetType( BEAM_POINTS ); - SetStartPos( start ); - SetEndPos( end ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::HoseInit( const Vector &start, const Vector &direction ) -{ - SetType( BEAM_HOSE ); - SetStartPos( start ); - SetEndPos( direction ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::PointEntInit( const Vector &start, int endIndex ) -{ - SetType( BEAM_ENTPOINT ); - SetStartPos( start ); - SetEndEntity( endIndex ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::EntsInit( int startIndex, int endIndex ) -{ - SetType( BEAM_ENTS ); - SetStartEntity( startIndex ); - SetEndEntity( endIndex ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::RelinkBeam( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->mins.x = min( startPos.x, endPos.x ); - pev->mins.y = min( startPos.y, endPos.y ); - pev->mins.z = min( startPos.z, endPos.z ); - pev->maxs.x = max( startPos.x, endPos.x ); - pev->maxs.y = max( startPos.y, endPos.y ); - pev->maxs.z = max( startPos.z, endPos.z ); - pev->mins = pev->mins - pev->origin; - pev->maxs = pev->maxs - pev->origin; - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); -} - -#if 0 -void CBeam::SetObjectCollisionBox( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->absmin.x = min( startPos.x, endPos.x ); - pev->absmin.y = min( startPos.y, endPos.y ); - pev->absmin.z = min( startPos.z, endPos.z ); - pev->absmax.x = max( startPos.x, endPos.x ); - pev->absmax.y = max( startPos.y, endPos.y ); - pev->absmax.z = max( startPos.z, endPos.z ); -} -#endif - - -void CBeam::TriggerTouch( CBaseEntity *pOther ) -{ - if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) - { - if ( pev->owner ) - { - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - pOwner->Use( pOther, this, USE_TOGGLE, 0 ); - } - ALERT( at_console, "Firing targets!!!\n" ); - } -} - - -CBaseEntity *CBeam::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - - -void CBeam::DoSparks( const Vector &start, const Vector &end ) -{ - if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) - { - if ( pev->spawnflags & SF_BEAM_SPARKSTART ) - { - UTIL_Sparks( start ); - } - if ( pev->spawnflags & SF_BEAM_SPARKEND ) - { - UTIL_Sparks( end ); - } - } -} - - -class CLightning : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - - void EXPORT StrikeThink( void ); - void EXPORT DamageThink( void ); - void RandomArea( void ); - void RandomPoint( Vector &vecSrc ); - void Zap( const Vector &vecSrc, const Vector &vecDest ); - void EXPORT StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL ServerSide( void ) - { - if ( m_life == 0 && !(pev->spawnflags & SF_BEAM_RING) ) - return TRUE; - return FALSE; - } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void BeamUpdateVars( void ); - - int m_active; - int m_iszStartEntity; - int m_iszEndEntity; - float m_life; - int m_boltWidth; - int m_noiseAmplitude; - int m_brightness; - int m_speed; - float m_restrike; - int m_spriteTexture; - int m_iszSpriteName; - int m_frameStart; - - float m_radius; -}; - -LINK_ENTITY_TO_CLASS( env_lightning, CLightning ); -LINK_ENTITY_TO_CLASS( env_beam, CLightning ); - -// UNDONE: Jay -- This is only a test -#if _DEBUG -class CTripBeam : public CLightning -{ - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ); - -void CTripBeam::Spawn( void ) -{ - CLightning::Spawn(); - SetTouch( &CTripBeam::TriggerTouch ); - pev->solid = SOLID_TRIGGER; - RelinkBeam(); -} -#endif - - - -TYPEDESCRIPTION CLightning::m_SaveData[] = -{ - DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_iszStartEntity, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_iszEndEntity, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_life, FIELD_FLOAT ), - DEFINE_FIELD( CLightning, m_boltWidth, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_noiseAmplitude, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_brightness, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_speed, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_restrike, FIELD_FLOAT ), - DEFINE_FIELD( CLightning, m_spriteTexture, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_iszSpriteName, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_frameStart, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_radius, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CLightning, CBeam ); - - -void CLightning::Spawn( void ) -{ - if ( FStringNull( m_iszSpriteName ) ) - { - SetThink( &CLightning::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); - - pev->dmgtime = gpGlobals->time; - - if ( ServerSide() ) - { - SetThink( NULL ); - if ( pev->dmg > 0 ) - { - SetThink( &CLightning::DamageThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - if ( pev->targetname ) - { - if ( !(pev->spawnflags & SF_BEAM_STARTON) ) - { - pev->effects = EF_NODRAW; - m_active = 0; - pev->nextthink = 0; - } - else - m_active = 1; - - SetUse( &CLightning::ToggleUse ); - } - } - else - { - m_active = 0; - if ( !FStringNull(pev->targetname) ) - { - SetUse( &CLightning::StrikeUse ); - } - if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) - { - SetThink( &CLightning::StrikeThink ); - pev->nextthink = gpGlobals->time + 1.0; - } - } -} - -void CLightning::Precache( void ) -{ - m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); - CBeam::Precache(); -} - - -void CLightning::Activate( void ) -{ - if ( ServerSide() ) - BeamUpdateVars(); -} - - -void CLightning::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "LightningStart")) - { - m_iszStartEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "LightningEnd")) - { - m_iszEndEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "life")) - { - m_life = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "BoltWidth")) - { - m_boltWidth = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) - { - m_noiseAmplitude = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) - { - m_speed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "StrikeTime")) - { - m_restrike = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "texture")) - { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "framestart")) - { - m_frameStart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Radius")) - { - m_radius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBeam::KeyValue( pkvd ); -} - - -void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_active ) ) - return; - if ( m_active ) - { - m_active = 0; - pev->effects |= EF_NODRAW; - pev->nextthink = 0; - } - else - { - m_active = 1; - pev->effects &= ~EF_NODRAW; - DoSparks( GetStartPos(), GetEndPos() ); - if ( pev->dmg > 0 ) - { - pev->nextthink = gpGlobals->time; - pev->dmgtime = gpGlobals->time; - } - } -} - - -void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_active ) ) - return; - - if ( m_active ) - { - m_active = 0; - SetThink( NULL ); - } - else - { - SetThink( &CLightning::StrikeThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - - if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) - SetUse( NULL ); -} - - -int IsPointEntity( CBaseEntity *pEnt ) -{ - if ( !pEnt->pev->modelindex ) - return 1; - if ( FClassnameIs( pEnt->pev, "info_target" ) || FClassnameIs( pEnt->pev, "info_landmark" ) || FClassnameIs( pEnt->pev, "path_corner" ) ) - return 1; - - return 0; -} - - -void CLightning::StrikeThink( void ) -{ - if ( m_life != 0 ) - { - if ( pev->spawnflags & SF_BEAM_RANDOM ) - pev->nextthink = gpGlobals->time + m_life + RANDOM_FLOAT( 0, m_restrike ); - else - pev->nextthink = gpGlobals->time + m_life + m_restrike; - } - m_active = 1; - - if (FStringNull(m_iszEndEntity)) - { - if (FStringNull(m_iszStartEntity)) - { - RandomArea( ); - } - else - { - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - if (pStart != NULL) - RandomPoint( pStart->pev->origin ); - else - ALERT( at_console, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) ); - } - return; - } - - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) ); - - if ( pStart != NULL && pEnd != NULL ) - { - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) - { - if ( pev->spawnflags & SF_BEAM_RING) - { - // don't work - return; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) - { - if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd - { - CBaseEntity *pTemp; - pTemp = pStart; - pStart = pEnd; - pEnd = pTemp; - } - if ( !IsPointEntity( pStart ) ) // One sided - { - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( pStart->entindex() ); - WRITE_COORD( pEnd->pev->origin.x); - WRITE_COORD( pEnd->pev->origin.y); - WRITE_COORD( pEnd->pev->origin.z); - } - else - { - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD( pStart->pev->origin.x); - WRITE_COORD( pStart->pev->origin.y); - WRITE_COORD( pStart->pev->origin.z); - WRITE_COORD( pEnd->pev->origin.x); - WRITE_COORD( pEnd->pev->origin.y); - WRITE_COORD( pEnd->pev->origin.z); - } - - - } - else - { - if ( pev->spawnflags & SF_BEAM_RING) - WRITE_BYTE( TE_BEAMRING ); - else - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( pStart->entindex() ); - WRITE_SHORT( pEnd->entindex() ); - } - - WRITE_SHORT( m_spriteTexture ); - WRITE_BYTE( m_frameStart ); // framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(m_life*10.0) ); // life - WRITE_BYTE( m_boltWidth ); // width - WRITE_BYTE( m_noiseAmplitude ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( pev->renderamt ); // brightness - WRITE_BYTE( m_speed ); // speed - MESSAGE_END(); - DoSparks( pStart->pev->origin, pEnd->pev->origin ); - if ( pev->dmg > 0 ) - { - TraceResult tr; - UTIL_TraceLine( pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr ); - BeamDamageInstant( &tr, pev->dmg ); - } - } -} - - -void CBeam::BeamDamage( TraceResult *ptr ) -{ - RelinkBeam(); - if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) - { - CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); - if ( pHit ) - { - ClearMultiDamage(); - pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pev, pev ); - if ( pev->spawnflags & SF_BEAM_DECALS ) - { - if ( pHit->IsBSPModel() ) - UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); - } - } - } - pev->dmgtime = gpGlobals->time; -} - - -void CLightning::DamageThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - TraceResult tr; - UTIL_TraceLine( GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr ); - BeamDamage( &tr ); -} - - - -void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) -{ -#if 1 - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_SHORT( m_spriteTexture ); - WRITE_BYTE( m_frameStart ); // framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(m_life*10.0) ); // life - WRITE_BYTE( m_boltWidth ); // width - WRITE_BYTE( m_noiseAmplitude ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( pev->renderamt ); // brightness - WRITE_BYTE( m_speed ); // speed - MESSAGE_END(); -#else - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE(TE_LIGHTNING); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_BYTE(10); - WRITE_BYTE(50); - WRITE_BYTE(40); - WRITE_SHORT(m_spriteTexture); - MESSAGE_END(); -#endif - DoSparks( vecSrc, vecDest ); -} - -void CLightning::RandomArea( void ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecSrc = pev->origin; - - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); - - if (tr1.flFraction == 1.0) - continue; - - Vector vecDir2; - do { - vecDir2 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - } while (DotProduct(vecDir1, vecDir2 ) > 0); - vecDir2 = vecDir2.Normalize(); - TraceResult tr2; - UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2 ); - - if (tr2.flFraction == 1.0) - continue; - - if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1) - continue; - - UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2 ); - - if (tr2.flFraction != 1.0) - continue; - - Zap( tr1.vecEndPos, tr2.vecEndPos ); - - break; - } -} - - -void CLightning::RandomPoint( Vector &vecSrc ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); - - if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1) - continue; - - if (tr1.flFraction == 1.0) - continue; - - Zap( vecSrc, tr1.vecEndPos ); - break; - } -} - - - -void CLightning::BeamUpdateVars( void ) -{ - int beamType; - int pointStart, pointEnd; - - edict_t *pStart = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszStartEntity) ); - edict_t *pEnd = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszEndEntity) ); - pointStart = IsPointEntity( CBaseEntity::Instance(pStart) ); - pointEnd = IsPointEntity( CBaseEntity::Instance(pEnd) ); - - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; - pev->flags |= FL_CUSTOMENTITY; - pev->model = m_iszSpriteName; - SetTexture( m_spriteTexture ); - - beamType = BEAM_ENTS; - if ( pointStart || pointEnd ) - { - if ( !pointStart ) // One point entity must be in pStart - { - edict_t *pTemp; - // Swap start & end - pTemp = pStart; - pStart = pEnd; - pEnd = pTemp; - int swap = pointStart; - pointStart = pointEnd; - pointEnd = swap; - } - if ( !pointEnd ) - beamType = BEAM_ENTPOINT; - else - beamType = BEAM_POINTS; - } - - SetType( beamType ); - if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) - { - SetStartPos( pStart->v.origin ); - if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) - SetEndPos( pEnd->v.origin ); - else - SetEndEntity( ENTINDEX(pEnd) ); - } - else - { - SetStartEntity( ENTINDEX(pStart) ); - SetEndEntity( ENTINDEX(pEnd) ); - } - - RelinkBeam(); - - SetWidth( m_boltWidth ); - SetNoise( m_noiseAmplitude ); - SetFrame( m_frameStart ); - SetScrollRate( m_speed ); - if ( pev->spawnflags & SF_BEAM_SHADEIN ) - SetFlags( BEAM_FSHADEIN ); - else if ( pev->spawnflags & SF_BEAM_SHADEOUT ) - SetFlags( BEAM_FSHADEOUT ); -} - - -LINK_ENTITY_TO_CLASS( env_laser, CLaser ); - -TYPEDESCRIPTION CLaser::m_SaveData[] = -{ - DEFINE_FIELD( CLaser, m_pSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CLaser, m_iszSpriteName, FIELD_STRING ), - DEFINE_FIELD( CLaser, m_firePosition, FIELD_POSITION_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CLaser, CBeam ); - -void CLaser::Spawn( void ) -{ - if ( FStringNull( pev->model ) ) - { - SetThink( &CLaser::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); - - SetThink( &CLaser::StrikeThink ); - pev->flags |= FL_CUSTOMENTITY; - - PointsInit( pev->origin, pev->origin ); - - if ( !m_pSprite && m_iszSpriteName ) - m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), pev->origin, TRUE ); - else - m_pSprite = NULL; - - if ( m_pSprite ) - m_pSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); - - if ( pev->targetname && !(pev->spawnflags & SF_BEAM_STARTON) ) - TurnOff(); - else - TurnOn(); -} - -void CLaser::Precache( void ) -{ - pev->modelindex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - if ( m_iszSpriteName ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); -} - - -void CLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "LaserTarget")) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - SetWidth( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) - { - SetNoise( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) - { - SetScrollRate( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->model = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "EndSprite")) - { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "framestart")) - { - pev->frame = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBeam::KeyValue( pkvd ); -} - - -int CLaser::IsOn( void ) -{ - if (pev->effects & EF_NODRAW) - return 0; - return 1; -} - - -void CLaser::TurnOff( void ) -{ - pev->effects |= EF_NODRAW; - pev->nextthink = 0; - if ( m_pSprite ) - m_pSprite->TurnOff(); -} - - -void CLaser::TurnOn( void ) -{ - pev->effects &= ~EF_NODRAW; - if ( m_pSprite ) - m_pSprite->TurnOn(); - pev->dmgtime = gpGlobals->time; - pev->nextthink = gpGlobals->time; -} - - -void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int active = IsOn(); - - if ( !ShouldToggle( useType, active ) ) - return; - if ( active ) - { - TurnOff(); - } - else - { - TurnOn(); - } -} - - -void CLaser::FireAtPoint( TraceResult &tr ) -{ - SetEndPos( tr.vecEndPos ); - if ( m_pSprite ) - UTIL_SetOrigin( m_pSprite->pev, tr.vecEndPos ); - - BeamDamage( &tr ); - DoSparks( GetStartPos(), tr.vecEndPos ); -} - -void CLaser::StrikeThink( void ) -{ - CBaseEntity *pEnd = RandomTargetname( STRING(pev->message) ); - - if ( pEnd ) - m_firePosition = pEnd->pev->origin; - - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_firePosition, dont_ignore_monsters, NULL, &tr ); - FireAtPoint( tr ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -class CGlow : public CPointEntity -{ -public: - void Spawn( void ); - void Think( void ); - void Animate( float frames ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_lastTime; - float m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( env_glow, CGlow ); - -TYPEDESCRIPTION CGlow::m_SaveData[] = -{ - DEFINE_FIELD( CGlow, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ); - -void CGlow::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( m_maxFrame > 1.0 && pev->framerate != 0 ) - pev->nextthink = gpGlobals->time + 0.1; - - m_lastTime = gpGlobals->time; -} - - -void CGlow::Think( void ) -{ - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - - -void CGlow::Animate( float frames ) -{ - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame + frames, m_maxFrame ); -} - - -LINK_ENTITY_TO_CLASS( env_sprite, CSprite ); - -TYPEDESCRIPTION CSprite::m_SaveData[] = -{ - DEFINE_FIELD( CSprite, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ); - -void CSprite::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - Precache(); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) ) - TurnOff(); - else - TurnOn(); - - // Worldcraft only sets y rotation, copy to Z - if ( pev->angles.y != 0 && pev->angles.z == 0 ) - { - pev->angles.z = pev->angles.y; - pev->angles.y = 0; - } -} - - -void CSprite::Precache( void ) -{ - PRECACHE_MODEL( (char *)STRING(pev->model) ); - - // Reset attachment after save/restore - if ( pev->aiment ) - SetAttachment( pev->aiment, pev->body ); - else - { - // Clear attachment - pev->skin = 0; - pev->body = 0; - } -} - - -void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) -{ - pev->model = MAKE_STRING(pSpriteName); - pev->origin = origin; - Spawn(); -} - -CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) -{ - CSprite *pSprite = GetClassPtr( (CSprite *)NULL ); - pSprite->SpriteInit( pSpriteName, origin ); - pSprite->pev->classname = MAKE_STRING("env_sprite"); - pSprite->pev->solid = SOLID_NOT; - pSprite->pev->movetype = MOVETYPE_NOCLIP; - if ( animate ) - pSprite->TurnOn(); - - return pSprite; -} - - -void CSprite::AnimateThink( void ) -{ - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - -void CSprite::AnimateUntilDead( void ) -{ - if ( gpGlobals->time > pev->dmgtime ) - UTIL_Remove(this); - else - { - AnimateThink(); - pev->nextthink = gpGlobals->time; - } -} - -void CSprite::Expand( float scaleSpeed, float fadeSpeed ) -{ - pev->speed = scaleSpeed; - pev->health = fadeSpeed; - SetThink( &CSprite::ExpandThink ); - - pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; -} - - -void CSprite::ExpandThink( void ) -{ - float frametime = gpGlobals->time - m_lastTime; - pev->scale += pev->speed * frametime; - pev->renderamt -= pev->health * frametime; - if ( pev->renderamt <= 0 ) - { - pev->renderamt = 0; - UTIL_Remove( this ); - } - else - { - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; - } -} - - -void CSprite::Animate( float frames ) -{ - pev->frame += frames; - if ( pev->frame > m_maxFrame ) - { - if ( pev->spawnflags & SF_SPRITE_ONCE ) - { - TurnOff(); - } - else - { - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame, m_maxFrame ); - } - } -} - - -void CSprite::TurnOff( void ) -{ - pev->effects = EF_NODRAW; - pev->nextthink = 0; -} - - -void CSprite::TurnOn( void ) -{ - pev->effects = 0; - if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) - { - SetThink( &CSprite::AnimateThink ); - pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; - } - pev->frame = 0; -} - - -void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int on = pev->effects != EF_NODRAW; - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - { - TurnOff(); - } - else - { - TurnOn(); - } - } -} - - -class CGibShooter : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT ShootThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual CGib *CreateGib( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iGibs; - int m_iGibCapacity; - int m_iGibMaterial; - int m_iGibModelIndex; - float m_flGibVelocity; - float m_flVariance; - float m_flGibLife; -}; - -TYPEDESCRIPTION CGibShooter::m_SaveData[] = -{ - DEFINE_FIELD( CGibShooter, m_iGibs, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibCapacity, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibMaterial, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibModelIndex, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_flGibVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CGibShooter, m_flVariance, FIELD_FLOAT ), - DEFINE_FIELD( CGibShooter, m_flGibLife, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ); -LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ); - - -void CGibShooter :: Precache ( void ) -{ - if ( g_Language == LANGUAGE_GERMAN ) - { - m_iGibModelIndex = PRECACHE_MODEL ("models/germanygibs.mdl"); - } - else - { - m_iGibModelIndex = PRECACHE_MODEL ("models/hgibs.mdl"); - } -} - - -void CGibShooter::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iGibs")) - { - m_iGibs = m_iGibCapacity = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flVelocity")) - { - m_flGibVelocity = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flVariance")) - { - m_flVariance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flGibLife")) - { - m_flGibLife = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - { - CBaseDelay::KeyValue( pkvd ); - } -} - -void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CGibShooter::ShootThink ); - pev->nextthink = gpGlobals->time; -} - -void CGibShooter::Spawn( void ) -{ - Precache(); - - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - - if ( m_flDelay == 0 ) - { - m_flDelay = 0.1; - } - - if ( m_flGibLife == 0 ) - { - m_flGibLife = 25; - } - - SetMovedir ( pev ); - pev->body = MODEL_FRAMES( m_iGibModelIndex ); -} - - -CGib *CGibShooter :: CreateGib ( void ) -{ - if ( ns_cvar_float(violence_hgibs) == 0 ) - return NULL; - - CGib *pGib = GetClassPtr( (CGib *)NULL ); - pGib->Spawn( "models/hgibs.mdl" ); - pGib->m_bloodColor = BLOOD_COLOR_RED; - - if ( pev->body <= 1 ) - { - ALERT ( at_aiconsole, "GibShooter Body is <= 1!\n" ); - } - - pGib->pev->body = RANDOM_LONG ( 1, pev->body - 1 );// avoid throwing random amounts of the 0th gib. (skull). - - return pGib; -} - - -void CGibShooter :: ShootThink ( void ) -{ - pev->nextthink = gpGlobals->time + m_flDelay; - - Vector vecShootDir; - - vecShootDir = pev->movedir; - - vecShootDir = vecShootDir + gpGlobals->v_right * RANDOM_FLOAT( -1, 1) * m_flVariance;; - vecShootDir = vecShootDir + gpGlobals->v_forward * RANDOM_FLOAT( -1, 1) * m_flVariance;; - vecShootDir = vecShootDir + gpGlobals->v_up * RANDOM_FLOAT( -1, 1) * m_flVariance;; - - vecShootDir = vecShootDir.Normalize(); - CGib *pGib = CreateGib(); - - if ( pGib ) - { - pGib->pev->origin = pev->origin; - pGib->pev->velocity = vecShootDir * m_flGibVelocity; - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - float thinkTime = pGib->pev->nextthink - gpGlobals->time; - - pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT( 0.95, 1.05 )); // +/- 5% - if ( pGib->m_lifeTime < thinkTime ) - { - pGib->pev->nextthink = gpGlobals->time + pGib->m_lifeTime; - pGib->m_lifeTime = 0; - } - - } - - if ( --m_iGibs <= 0 ) - { - if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) - { - m_iGibs = m_iGibCapacity; - SetThink ( NULL ); - pev->nextthink = gpGlobals->time; - } - else - { - SetThink ( &CGibShooter::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - } -} - - -class CEnvShooter : public CGibShooter -{ - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - CGib *CreateGib( void ); -}; - -LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ); - -void CEnvShooter :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "shootmodel")) - { - pev->model = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shootsounds")) - { - int iNoise = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - switch( iNoise ) - { - case 0: - m_iGibMaterial = matGlass; - break; - case 1: - m_iGibMaterial = matWood; - break; - case 2: - m_iGibMaterial = matMetal; - break; - case 3: - m_iGibMaterial = matFlesh; - break; - case 4: - m_iGibMaterial = matRocks; - break; - - default: - case -1: - m_iGibMaterial = matNone; - break; - } - } - else - { - CGibShooter::KeyValue( pkvd ); - } -} - - -void CEnvShooter :: Precache ( void ) -{ - m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial ); -} - - -CGib *CEnvShooter :: CreateGib ( void ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( STRING(pev->model) ); - - int bodyPart = 0; - - if ( pev->body > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body-1 ); - - pGib->pev->body = bodyPart; - pGib->m_bloodColor = DONT_BLEED; - pGib->m_material = m_iGibMaterial; - - pGib->pev->rendermode = pev->rendermode; - pGib->pev->renderamt = pev->renderamt; - pGib->pev->rendercolor = pev->rendercolor; - pGib->pev->renderfx = pev->renderfx; - pGib->pev->scale = pev->scale; - pGib->pev->skin = pev->skin; - - return pGib; -} - - - - -class CTestEffect : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - // void KeyValue( KeyValueData *pkvd ); - void EXPORT TestThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iLoop; - int m_iBeam; - CBeam *m_pBeam[24]; - float m_flBeamTime[24]; - float m_flStartTime; -}; - - -LINK_ENTITY_TO_CLASS( test_effect, CTestEffect ); - -void CTestEffect::Spawn( void ) -{ - Precache( ); -} - -void CTestEffect::Precache( void ) -{ - PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - -void CTestEffect::TestThink( void ) -{ - int i; - float t = (gpGlobals->time - m_flStartTime); - - if (m_iBeam < 24) - { - CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.spr", 100 ); - - TraceResult tr; - - Vector vecSrc = pev->origin; - Vector vecDir = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir = vecDir.Normalize(); - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT(pev), &tr); - - pbeam->PointsInit( vecSrc, tr.vecEndPos ); - // pbeam->SetColor( 80, 100, 255 ); - pbeam->SetColor( 255, 180, 100 ); - pbeam->SetWidth( 100 ); - pbeam->SetScrollRate( 12 ); - - m_flBeamTime[m_iBeam] = gpGlobals->time; - m_pBeam[m_iBeam] = pbeam; - m_iBeam++; - -#if 0 - Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5; - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecMid.x); // X - WRITE_COORD(vecMid.y); // Y - WRITE_COORD(vecMid.z); // Z - WRITE_BYTE( 20 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 100 ); // b - WRITE_BYTE( 20 ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); -#endif - } - - if (t < 3.0) - { - for (i = 0; i < m_iBeam; i++) - { - t = (gpGlobals->time - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]); - m_pBeam[i]->SetBrightness( 255 * t ); - // m_pBeam[i]->SetScrollRate( 20 * t ); - } - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - for (i = 0; i < m_iBeam; i++) - { - UTIL_Remove( m_pBeam[i] ); - } - m_flStartTime = gpGlobals->time; - m_iBeam = 0; - // pev->nextthink = gpGlobals->time; - SetThink( NULL ); - } -} - - -void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CTestEffect::TestThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flStartTime = gpGlobals->time; -} - - - -// Blood effects -class CBlood : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Color( void ) { return pev->impulse; } - inline float BloodAmount( void ) { return pev->dmg; } - - inline void SetColor( int color ) { pev->impulse = color; } - inline void SetBloodAmount( float amount ) { pev->dmg = amount; } - - Vector Direction( void ); - Vector BloodPosition( CBaseEntity *pActivator ); - -private: -}; - -LINK_ENTITY_TO_CLASS( env_blood, CBlood ); - - - -#define SF_BLOOD_RANDOM 0x0001 -#define SF_BLOOD_STREAM 0x0002 -#define SF_BLOOD_PLAYER 0x0004 -#define SF_BLOOD_DECAL 0x0008 - -void CBlood::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - SetMovedir( pev ); -} - - -void CBlood::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "color")) - { - int color = atoi(pkvd->szValue); - switch( color ) - { - case 1: - SetColor( BLOOD_COLOR_YELLOW ); - break; - default: - SetColor( BLOOD_COLOR_RED ); - break; - } - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "amount")) - { - SetBloodAmount( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -Vector CBlood::Direction( void ) -{ - if ( pev->spawnflags & SF_BLOOD_RANDOM ) - return UTIL_RandomBloodVector(); - - return pev->movedir; -} - - -Vector CBlood::BloodPosition( CBaseEntity *pActivator ) -{ - if ( pev->spawnflags & SF_BLOOD_PLAYER ) - { - edict_t *pPlayer; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = pActivator->edict(); - } - else - pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - if ( pPlayer ) - return (pPlayer->v.origin + pPlayer->v.view_ofs) + Vector( RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10) ); - } - - return pev->origin; -} - - -void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_BLOOD_STREAM ) - UTIL_BloodStream( BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), BloodAmount() ); - else - UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); - - if ( pev->spawnflags & SF_BLOOD_DECAL ) - { - Vector forward = Direction(); - Vector start = BloodPosition( pActivator ); - TraceResult tr; - - UTIL_TraceLine( start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr ); - if ( tr.flFraction != 1.0 ) - UTIL_BloodDecalTrace( &tr, Color() ); - } -} - - - -// Screen shake -class CShake : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline float Amplitude( void ) { return pev->scale; } - inline float Frequency( void ) { return pev->dmg_save; } - inline float Duration( void ) { return pev->dmg_take; } - inline float Radius( void ) { return pev->dmg; } - - inline void SetAmplitude( float amplitude ) { pev->scale = amplitude; } - inline void SetFrequency( float frequency ) { pev->dmg_save = frequency; } - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetRadius( float radius ) { pev->dmg = radius; } -private: -}; - -LINK_ENTITY_TO_CLASS( env_shake, CShake ); - -// pev->scale is amplitude -// pev->dmg_save is frequency -// pev->dmg_take is duration -// pev->dmg is radius -// radius of 0 means all players -// NOTE: UTIL_ScreenShake() will only shake players who are on the ground - -#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius -// UNDONE: These don't work yet -#define SF_SHAKE_DISRUPT 0x0002 // Disrupt controls -#define SF_SHAKE_INAIR 0x0004 // Shake players in air - -void CShake::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - if ( pev->spawnflags & SF_SHAKE_EVERYONE ) - pev->dmg = 0; -} - - -void CShake::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "amplitude")) - { - SetAmplitude( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency")) - { - SetFrequency( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - SetRadius( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() ); -} - - -class CFade : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } -private: -}; - -LINK_ENTITY_TO_CLASS( env_fade, CFade ); - -// pev->dmg_take is duration -// pev->dmg_save is hold duration -#define SF_FADE_IN 0x0001 // Fade in, not out -#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend -#define SF_FADE_ONLYONE 0x0004 - -void CFade::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; -} - - -void CFade::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fadeFlags = 0; - - if ( !(pev->spawnflags & SF_FADE_IN) ) - fadeFlags |= FFADE_OUT; - - if ( pev->spawnflags & SF_FADE_MODULATE ) - fadeFlags |= FFADE_MODULATE; - - if ( pev->spawnflags & SF_FADE_ONLYONE ) - { - if ( pActivator->IsNetClient() ) - { - UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); - } - } - else - { - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - -class CMessage : public CPointEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); -private: -}; - -LINK_ENTITY_TO_CLASS( env_message, CMessage ); - - -void CMessage::Spawn( void ) -{ - Precache(); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - switch( pev->impulse ) - { - case 1: // Medium radius - pev->speed = ATTN_STATIC; - break; - - case 2: // Large radius - pev->speed = ATTN_NORM; - break; - - case 3: //EVERYWHERE - pev->speed = ATTN_NONE; - break; - - default: - case 0: // Small radius - pev->speed = ATTN_IDLE; - break; - } - pev->impulse = 0; - - // No volume, use normal - if ( pev->scale <= 0 ) - pev->scale = 1.0; -} - - -void CMessage::Precache( void ) -{ - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); -} - -void CMessage::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "messagesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagevolume")) - { - pev->scale = atof(pkvd->szValue) * 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messageattenuation")) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pPlayer = NULL; - - if ( pev->spawnflags & SF_MESSAGE_ALL ) - UTIL_ShowMessageAll( STRING(pev->message) ); - else - { - if ( pActivator && pActivator->IsPlayer() ) - pPlayer = pActivator; - else - { - pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - } - if ( pPlayer ) - UTIL_ShowMessage( STRING(pev->message), pPlayer ); - } - if ( pev->noise ) - { - EMIT_SOUND( edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed ); - } - if ( pev->spawnflags & SF_MESSAGE_ONCE ) - UTIL_Remove( this ); - - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - - -//========================================================= -// FunnelEffect -//========================================================= -class CEnvFunnel : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iSprite; // Don't save, precache -}; - -void CEnvFunnel :: Precache ( void ) -{ - m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); -} - -LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ); - -void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_LARGEFUNNEL ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( m_iSprite ); - - if ( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse? - { - WRITE_SHORT( 1 ); - } - else - { - WRITE_SHORT( 0 ); - } - - - MESSAGE_END(); - - SetThink( &CEnvFunnel::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -void CEnvFunnel::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; -} - -//========================================================= -// Beverage Dispenser -// overloaded pev->frags, is now a flag for whether or not a can is stuck in the dispenser. -// overloaded pev->health, is now how many cans remain in the machine. -//========================================================= -class CEnvBeverage : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -void CEnvBeverage :: Precache ( void ) -{ - PRECACHE_MODEL( "models/can.mdl" ); - PRECACHE_SOUND( "weapons/g_bounce3.wav" ); -} - -LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage ); - -void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->frags != 0 || pev->health <= 0 ) - { - // no more cans while one is waiting in the dispenser, or if I'm out of cans. - return; - } - - CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", pev->origin, pev->angles, edict() ); - - if ( pev->skin == 6 ) - { - // random - pCan->pev->skin = RANDOM_LONG( 0, 5 ); - } - else - { - pCan->pev->skin = pev->skin; - } - - pev->frags = 1; - pev->health--; - - //SetThink (SUB_Remove); - //pev->nextthink = gpGlobals->time; -} - -void CEnvBeverage::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - pev->frags = 0; - - if ( pev->health == 0 ) - { - pev->health = 10; - } -} - -//========================================================= -// Soda can -//========================================================= -class CItemSoda : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT CanThink ( void ); - void EXPORT CanTouch ( CBaseEntity *pOther ); -}; - -void CItemSoda :: Precache ( void ) -{ -} - -LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ); - -void CItemSoda::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - - SET_MODEL ( ENT(pev), "models/can.mdl" ); - UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) ); - - SetThink (&CItemSoda::CanThink); - pev->nextthink = gpGlobals->time + 0.5; -} - -void CItemSoda::CanThink ( void ) -{ - EMIT_SOUND (ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM ); - - pev->solid = SOLID_TRIGGER; - UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) ); - SetThink ( NULL ); - SetTouch ( &CItemSoda::CanTouch ); -} - -void CItemSoda::CanTouch ( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - { - return; - } - - // spoit sound here - - pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health. - - if ( !FNullEnt( pev->owner ) ) - { - // tell the machine the can was taken - pev->owner->v.frags = 0; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; - SetTouch ( NULL ); - SetThink ( &CItemSoda::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "../engine/customentity.h" +#include "effects.h" +#include "weapons.h" +#include "decals.h" +#include "func_break.h" +#include "../engine/shake.h" +#include "../mod/AvHServerVariables.h" +extern cvar_t avh_killdelay; + +#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired + +#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. + + +// Lightning target, just alias landmark +LINK_ENTITY_TO_CLASS( info_target, CPointEntity ); + + +class CBubbling : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + + void EXPORT FizzThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + static TYPEDESCRIPTION m_SaveData[]; + + int m_density; + int m_frequency; + int m_bubbleModel; + int m_state; +}; + +LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling ); + +TYPEDESCRIPTION CBubbling::m_SaveData[] = +{ + DEFINE_FIELD( CBubbling, m_density, FIELD_INTEGER ), + DEFINE_FIELD( CBubbling, m_frequency, FIELD_INTEGER ), + DEFINE_FIELD( CBubbling, m_state, FIELD_INTEGER ), + // Let spawn restore this! + // DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ); + + +#define SF_BUBBLES_STARTOFF 0x0001 + +void CBubbling::Spawn( void ) +{ + Precache( ); + SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size + + pev->solid = SOLID_NOT; // Remove model & collisions + pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on + pev->rendermode = kRenderTransTexture; + int speed = pev->speed > 0 ? pev->speed : -pev->speed; + + // HACKHACK!!! - Speed in rendercolor + pev->rendercolor.x = speed >> 8; + pev->rendercolor.y = speed & 255; + pev->rendercolor.z = (pev->speed < 0) ? 1 : 0; + + + if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) + { + SetThink( &CBubbling::FizzThink ); + pev->nextthink = gpGlobals->time + 2.0; + m_state = 1; + } + else + m_state = 0; +} + +void CBubbling::Precache( void ) +{ + m_bubbleModel = PRECACHE_MODEL("sprites/bubble2.spr"); // Precache bubble sprite +} + + +void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( ShouldToggle( useType, m_state ) ) + m_state = !m_state; + + if ( m_state ) + { + SetThink( &CBubbling::FizzThink ); + pev->nextthink = gpGlobals->time + 0.1; + } + else + { + SetThink( NULL ); + pev->nextthink = 0; + } +} + + +void CBubbling::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "density")) + { + m_density = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "frequency")) + { + m_frequency = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "current")) + { + pev->speed = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + + +void CBubbling::FizzThink( void ) +{ + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) ); + WRITE_BYTE( TE_FIZZ ); + WRITE_SHORT( (short)ENTINDEX( edict() ) ); + WRITE_SHORT( (short)m_bubbleModel ); + WRITE_BYTE( m_density ); + MESSAGE_END(); + + if ( m_frequency > 19 ) + pev->nextthink = gpGlobals->time + 0.5; + else + pev->nextthink = gpGlobals->time + 2.5 - (0.1 * m_frequency); +} + +// -------------------------------------------------- +// +// Beams +// +// -------------------------------------------------- + +LINK_ENTITY_TO_CLASS( beam, CBeam ); + +void CBeam::Spawn( void ) +{ + pev->solid = SOLID_NOT; // Remove model & collisions + Precache( ); +} + +void CBeam::Precache( void ) +{ + if ( pev->owner ) + SetStartEntity( ENTINDEX( pev->owner ) ); + if ( pev->aiment ) + SetEndEntity( ENTINDEX( pev->aiment ) ); +} + +void CBeam::SetStartEntity( int entityIndex ) +{ + pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12); + pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); +} + +void CBeam::SetEndEntity( int entityIndex ) +{ + pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12); + pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); +} + + +// These don't take attachments into account +const Vector &CBeam::GetStartPos( void ) +{ + if ( GetType() == BEAM_ENTS ) + { + edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() ); + return pent->v.origin; + } + return pev->origin; +} + + +const Vector &CBeam::GetEndPos( void ) +{ + int type = GetType(); + if ( type == BEAM_POINTS || type == BEAM_HOSE ) + { + return pev->angles; + } + + edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() ); + if ( pent ) + return pent->v.origin; + return pev->angles; +} + + +CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) +{ + // Create a new entity with CBeam private data + CBeam *pBeam = GetClassPtr( (CBeam *)NULL ); + pBeam->pev->classname = MAKE_STRING("beam"); + + pBeam->BeamInit( pSpriteName, width ); + + return pBeam; +} + + +void CBeam::BeamInit( const char *pSpriteName, int width ) +{ + pev->flags |= FL_CUSTOMENTITY; + SetColor( 255, 255, 255 ); + SetBrightness( 255 ); + SetNoise( 0 ); + SetFrame( 0 ); + SetScrollRate( 0 ); + pev->model = MAKE_STRING( pSpriteName ); + SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) ); + SetWidth( width ); + pev->skin = 0; + pev->sequence = 0; + pev->rendermode = 0; +} + + +void CBeam::PointsInit( const Vector &start, const Vector &end ) +{ + SetType( BEAM_POINTS ); + SetStartPos( start ); + SetEndPos( end ); + SetStartAttachment( 0 ); + SetEndAttachment( 0 ); + RelinkBeam(); +} + + +void CBeam::HoseInit( const Vector &start, const Vector &direction ) +{ + SetType( BEAM_HOSE ); + SetStartPos( start ); + SetEndPos( direction ); + SetStartAttachment( 0 ); + SetEndAttachment( 0 ); + RelinkBeam(); +} + + +void CBeam::PointEntInit( const Vector &start, int endIndex ) +{ + SetType( BEAM_ENTPOINT ); + SetStartPos( start ); + SetEndEntity( endIndex ); + SetStartAttachment( 0 ); + SetEndAttachment( 0 ); + RelinkBeam(); +} + +void CBeam::EntsInit( int startIndex, int endIndex ) +{ + SetType( BEAM_ENTS ); + SetStartEntity( startIndex ); + SetEndEntity( endIndex ); + SetStartAttachment( 0 ); + SetEndAttachment( 0 ); + RelinkBeam(); +} + + +void CBeam::RelinkBeam( void ) +{ + const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); + + pev->mins.x = min( startPos.x, endPos.x ); + pev->mins.y = min( startPos.y, endPos.y ); + pev->mins.z = min( startPos.z, endPos.z ); + pev->maxs.x = max( startPos.x, endPos.x ); + pev->maxs.y = max( startPos.y, endPos.y ); + pev->maxs.z = max( startPos.z, endPos.z ); + pev->mins = pev->mins - pev->origin; + pev->maxs = pev->maxs - pev->origin; + + UTIL_SetSize( pev, pev->mins, pev->maxs ); + UTIL_SetOrigin( pev, pev->origin ); +} + +#if 0 +void CBeam::SetObjectCollisionBox( void ) +{ + const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); + + pev->absmin.x = min( startPos.x, endPos.x ); + pev->absmin.y = min( startPos.y, endPos.y ); + pev->absmin.z = min( startPos.z, endPos.z ); + pev->absmax.x = max( startPos.x, endPos.x ); + pev->absmax.y = max( startPos.y, endPos.y ); + pev->absmax.z = max( startPos.z, endPos.z ); +} +#endif + + +void CBeam::TriggerTouch( CBaseEntity *pOther ) +{ + if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) + { + if ( pev->owner ) + { + CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); + pOwner->Use( pOther, this, USE_TOGGLE, 0 ); + } + ALERT( at_console, "Firing targets!!!\n" ); + } +} + + +CBaseEntity *CBeam::RandomTargetname( const char *szName ) +{ + int total = 0; + + CBaseEntity *pEntity = NULL; + CBaseEntity *pNewEntity = NULL; + while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) + { + total++; + if (RANDOM_LONG(0,total-1) < 1) + pEntity = pNewEntity; + } + return pEntity; +} + + +void CBeam::DoSparks( const Vector &start, const Vector &end ) +{ + if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) + { + if ( pev->spawnflags & SF_BEAM_SPARKSTART ) + { + UTIL_Sparks( start ); + } + if ( pev->spawnflags & SF_BEAM_SPARKEND ) + { + UTIL_Sparks( end ); + } + } +} + + +class CLightning : public CBeam +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + void Activate( void ); + + void EXPORT StrikeThink( void ); + void EXPORT DamageThink( void ); + void RandomArea( void ); + void RandomPoint( Vector &vecSrc ); + void Zap( const Vector &vecSrc, const Vector &vecDest ); + void EXPORT StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + inline BOOL ServerSide( void ) + { + if ( m_life == 0 && !(pev->spawnflags & SF_BEAM_RING) ) + return TRUE; + return FALSE; + } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void BeamUpdateVars( void ); + + int m_active; + int m_iszStartEntity; + int m_iszEndEntity; + float m_life; + int m_boltWidth; + int m_noiseAmplitude; + int m_brightness; + int m_speed; + float m_restrike; + int m_spriteTexture; + int m_iszSpriteName; + int m_frameStart; + + float m_radius; +}; + +LINK_ENTITY_TO_CLASS( env_lightning, CLightning ); +LINK_ENTITY_TO_CLASS( env_beam, CLightning ); + +// UNDONE: Jay -- This is only a test +#if _DEBUG +class CTripBeam : public CLightning +{ + void Spawn( void ); +}; +LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ); + +void CTripBeam::Spawn( void ) +{ + CLightning::Spawn(); + SetTouch( &CTripBeam::TriggerTouch ); + pev->solid = SOLID_TRIGGER; + RelinkBeam(); +} +#endif + + + +TYPEDESCRIPTION CLightning::m_SaveData[] = +{ + DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_iszStartEntity, FIELD_STRING ), + DEFINE_FIELD( CLightning, m_iszEndEntity, FIELD_STRING ), + DEFINE_FIELD( CLightning, m_life, FIELD_FLOAT ), + DEFINE_FIELD( CLightning, m_boltWidth, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_noiseAmplitude, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_brightness, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_speed, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_restrike, FIELD_FLOAT ), + DEFINE_FIELD( CLightning, m_spriteTexture, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_iszSpriteName, FIELD_STRING ), + DEFINE_FIELD( CLightning, m_frameStart, FIELD_INTEGER ), + DEFINE_FIELD( CLightning, m_radius, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CLightning, CBeam ); + + +void CLightning::Spawn( void ) +{ + if ( FStringNull( m_iszSpriteName ) ) + { + SetThink( &CLightning::SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; // Remove model & collisions + Precache( ); + + pev->dmgtime = gpGlobals->time; + + if ( ServerSide() ) + { + SetThink( NULL ); + if ( pev->dmg > 0 ) + { + SetThink( &CLightning::DamageThink ); + pev->nextthink = gpGlobals->time + 0.1; + } + if ( pev->targetname ) + { + if ( !(pev->spawnflags & SF_BEAM_STARTON) ) + { + pev->effects = EF_NODRAW; + m_active = 0; + pev->nextthink = 0; + } + else + m_active = 1; + + SetUse( &CLightning::ToggleUse ); + } + } + else + { + m_active = 0; + if ( !FStringNull(pev->targetname) ) + { + SetUse( &CLightning::StrikeUse ); + } + if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) + { + SetThink( &CLightning::StrikeThink ); + pev->nextthink = gpGlobals->time + 1.0; + } + } +} + +void CLightning::Precache( void ) +{ + m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); + CBeam::Precache(); +} + + +void CLightning::Activate( void ) +{ + if ( ServerSide() ) + BeamUpdateVars(); +} + + +void CLightning::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "LightningStart")) + { + m_iszStartEntity = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "LightningEnd")) + { + m_iszEndEntity = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "life")) + { + m_life = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "BoltWidth")) + { + m_boltWidth = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) + { + m_noiseAmplitude = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "TextureScroll")) + { + m_speed = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "StrikeTime")) + { + m_restrike = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "texture")) + { + m_iszSpriteName = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "framestart")) + { + m_frameStart = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "Radius")) + { + m_radius = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "damage")) + { + pev->dmg = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBeam::KeyValue( pkvd ); +} + + +void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_active ) ) + return; + if ( m_active ) + { + m_active = 0; + pev->effects |= EF_NODRAW; + pev->nextthink = 0; + } + else + { + m_active = 1; + pev->effects &= ~EF_NODRAW; + DoSparks( GetStartPos(), GetEndPos() ); + if ( pev->dmg > 0 ) + { + pev->nextthink = gpGlobals->time; + pev->dmgtime = gpGlobals->time; + } + } +} + + +void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_active ) ) + return; + + if ( m_active ) + { + m_active = 0; + SetThink( NULL ); + } + else + { + SetThink( &CLightning::StrikeThink ); + pev->nextthink = gpGlobals->time + 0.1; + } + + if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) + SetUse( NULL ); +} + + +int IsPointEntity( CBaseEntity *pEnt ) +{ + if ( !pEnt->pev->modelindex ) + return 1; + if ( FClassnameIs( pEnt->pev, "info_target" ) || FClassnameIs( pEnt->pev, "info_landmark" ) || FClassnameIs( pEnt->pev, "path_corner" ) ) + return 1; + + return 0; +} + + +void CLightning::StrikeThink( void ) +{ + if ( m_life != 0 ) + { + if ( pev->spawnflags & SF_BEAM_RANDOM ) + pev->nextthink = gpGlobals->time + m_life + RANDOM_FLOAT( 0, m_restrike ); + else + pev->nextthink = gpGlobals->time + m_life + m_restrike; + } + m_active = 1; + + if (FStringNull(m_iszEndEntity)) + { + if (FStringNull(m_iszStartEntity)) + { + RandomArea( ); + } + else + { + CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); + if (pStart != NULL) + RandomPoint( pStart->pev->origin ); + else + ALERT( at_console, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) ); + } + return; + } + + CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); + CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) ); + + if ( pStart != NULL && pEnd != NULL ) + { + if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) + { + if ( pev->spawnflags & SF_BEAM_RING) + { + // don't work + return; + } + } + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) + { + if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd + { + CBaseEntity *pTemp; + pTemp = pStart; + pStart = pEnd; + pEnd = pTemp; + } + if ( !IsPointEntity( pStart ) ) // One sided + { + WRITE_BYTE( TE_BEAMENTPOINT ); + WRITE_SHORT( pStart->entindex() ); + WRITE_COORD( pEnd->pev->origin.x); + WRITE_COORD( pEnd->pev->origin.y); + WRITE_COORD( pEnd->pev->origin.z); + } + else + { + WRITE_BYTE( TE_BEAMPOINTS); + WRITE_COORD( pStart->pev->origin.x); + WRITE_COORD( pStart->pev->origin.y); + WRITE_COORD( pStart->pev->origin.z); + WRITE_COORD( pEnd->pev->origin.x); + WRITE_COORD( pEnd->pev->origin.y); + WRITE_COORD( pEnd->pev->origin.z); + } + + + } + else + { + if ( pev->spawnflags & SF_BEAM_RING) + WRITE_BYTE( TE_BEAMRING ); + else + WRITE_BYTE( TE_BEAMENTS ); + WRITE_SHORT( pStart->entindex() ); + WRITE_SHORT( pEnd->entindex() ); + } + + WRITE_SHORT( m_spriteTexture ); + WRITE_BYTE( m_frameStart ); // framestart + WRITE_BYTE( (int)pev->framerate); // framerate + WRITE_BYTE( (int)(m_life*10.0) ); // life + WRITE_BYTE( m_boltWidth ); // width + WRITE_BYTE( m_noiseAmplitude ); // noise + WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b + WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b + WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b + WRITE_BYTE( pev->renderamt ); // brightness + WRITE_BYTE( m_speed ); // speed + MESSAGE_END(); + DoSparks( pStart->pev->origin, pEnd->pev->origin ); + if ( pev->dmg > 0 ) + { + TraceResult tr; + UTIL_TraceLine( pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr ); + BeamDamageInstant( &tr, pev->dmg ); + } + } +} + + +void CBeam::BeamDamage( TraceResult *ptr ) +{ + RelinkBeam(); + if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) + { + CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); + if ( pHit ) + { + ClearMultiDamage(); + pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); + ApplyMultiDamage( pev, pev ); + if ( pev->spawnflags & SF_BEAM_DECALS ) + { + if ( pHit->IsBSPModel() ) + UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); + } + } + } + pev->dmgtime = gpGlobals->time; +} + + +void CLightning::DamageThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + TraceResult tr; + UTIL_TraceLine( GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr ); + BeamDamage( &tr ); +} + + + +void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) +{ +#if 1 + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS); + WRITE_COORD(vecSrc.x); + WRITE_COORD(vecSrc.y); + WRITE_COORD(vecSrc.z); + WRITE_COORD(vecDest.x); + WRITE_COORD(vecDest.y); + WRITE_COORD(vecDest.z); + WRITE_SHORT( m_spriteTexture ); + WRITE_BYTE( m_frameStart ); // framestart + WRITE_BYTE( (int)pev->framerate); // framerate + WRITE_BYTE( (int)(m_life*10.0) ); // life + WRITE_BYTE( m_boltWidth ); // width + WRITE_BYTE( m_noiseAmplitude ); // noise + WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b + WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b + WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b + WRITE_BYTE( pev->renderamt ); // brightness + WRITE_BYTE( m_speed ); // speed + MESSAGE_END(); +#else + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE(TE_LIGHTNING); + WRITE_COORD(vecSrc.x); + WRITE_COORD(vecSrc.y); + WRITE_COORD(vecSrc.z); + WRITE_COORD(vecDest.x); + WRITE_COORD(vecDest.y); + WRITE_COORD(vecDest.z); + WRITE_BYTE(10); + WRITE_BYTE(50); + WRITE_BYTE(40); + WRITE_SHORT(m_spriteTexture); + MESSAGE_END(); +#endif + DoSparks( vecSrc, vecDest ); +} + +void CLightning::RandomArea( void ) +{ + int iLoops = 0; + + for (iLoops = 0; iLoops < 10; iLoops++) + { + Vector vecSrc = pev->origin; + + Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); + vecDir1 = vecDir1.Normalize(); + TraceResult tr1; + UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); + + if (tr1.flFraction == 1.0) + continue; + + Vector vecDir2; + do { + vecDir2 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); + } while (DotProduct(vecDir1, vecDir2 ) > 0); + vecDir2 = vecDir2.Normalize(); + TraceResult tr2; + UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2 ); + + if (tr2.flFraction == 1.0) + continue; + + if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1) + continue; + + UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2 ); + + if (tr2.flFraction != 1.0) + continue; + + Zap( tr1.vecEndPos, tr2.vecEndPos ); + + break; + } +} + + +void CLightning::RandomPoint( Vector &vecSrc ) +{ + int iLoops = 0; + + for (iLoops = 0; iLoops < 10; iLoops++) + { + Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); + vecDir1 = vecDir1.Normalize(); + TraceResult tr1; + UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); + + if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1) + continue; + + if (tr1.flFraction == 1.0) + continue; + + Zap( vecSrc, tr1.vecEndPos ); + break; + } +} + + + +void CLightning::BeamUpdateVars( void ) +{ + int beamType; + int pointStart, pointEnd; + + edict_t *pStart = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszStartEntity) ); + edict_t *pEnd = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszEndEntity) ); + pointStart = IsPointEntity( CBaseEntity::Instance(pStart) ); + pointEnd = IsPointEntity( CBaseEntity::Instance(pEnd) ); + + pev->skin = 0; + pev->sequence = 0; + pev->rendermode = 0; + pev->flags |= FL_CUSTOMENTITY; + pev->model = m_iszSpriteName; + SetTexture( m_spriteTexture ); + + beamType = BEAM_ENTS; + if ( pointStart || pointEnd ) + { + if ( !pointStart ) // One point entity must be in pStart + { + edict_t *pTemp; + // Swap start & end + pTemp = pStart; + pStart = pEnd; + pEnd = pTemp; + int swap = pointStart; + pointStart = pointEnd; + pointEnd = swap; + } + if ( !pointEnd ) + beamType = BEAM_ENTPOINT; + else + beamType = BEAM_POINTS; + } + + SetType( beamType ); + if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) + { + SetStartPos( pStart->v.origin ); + if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) + SetEndPos( pEnd->v.origin ); + else + SetEndEntity( ENTINDEX(pEnd) ); + } + else + { + SetStartEntity( ENTINDEX(pStart) ); + SetEndEntity( ENTINDEX(pEnd) ); + } + + RelinkBeam(); + + SetWidth( m_boltWidth ); + SetNoise( m_noiseAmplitude ); + SetFrame( m_frameStart ); + SetScrollRate( m_speed ); + if ( pev->spawnflags & SF_BEAM_SHADEIN ) + SetFlags( BEAM_FSHADEIN ); + else if ( pev->spawnflags & SF_BEAM_SHADEOUT ) + SetFlags( BEAM_FSHADEOUT ); +} + + +LINK_ENTITY_TO_CLASS( env_laser, CLaser ); + +TYPEDESCRIPTION CLaser::m_SaveData[] = +{ + DEFINE_FIELD( CLaser, m_pSprite, FIELD_CLASSPTR ), + DEFINE_FIELD( CLaser, m_iszSpriteName, FIELD_STRING ), + DEFINE_FIELD( CLaser, m_firePosition, FIELD_POSITION_VECTOR ), +}; + +IMPLEMENT_SAVERESTORE( CLaser, CBeam ); + +void CLaser::Spawn( void ) +{ + if ( FStringNull( pev->model ) ) + { + SetThink( &CLaser::SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; // Remove model & collisions + Precache( ); + + SetThink( &CLaser::StrikeThink ); + pev->flags |= FL_CUSTOMENTITY; + + PointsInit( pev->origin, pev->origin ); + + if ( !m_pSprite && m_iszSpriteName ) + m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), pev->origin, TRUE ); + else + m_pSprite = NULL; + + if ( m_pSprite ) + m_pSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); + + if ( pev->targetname && !(pev->spawnflags & SF_BEAM_STARTON) ) + TurnOff(); + else + TurnOn(); +} + +void CLaser::Precache( void ) +{ + pev->modelindex = PRECACHE_MODEL( (char *)STRING(pev->model) ); + if ( m_iszSpriteName ) + PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); +} + + +void CLaser::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "LaserTarget")) + { + pev->message = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "width")) + { + SetWidth( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) + { + SetNoise( atoi(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "TextureScroll")) + { + SetScrollRate( atoi(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "texture")) + { + pev->model = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "EndSprite")) + { + m_iszSpriteName = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "framestart")) + { + pev->frame = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "damage")) + { + pev->dmg = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBeam::KeyValue( pkvd ); +} + + +int CLaser::IsOn( void ) +{ + if (pev->effects & EF_NODRAW) + return 0; + return 1; +} + + +void CLaser::TurnOff( void ) +{ + pev->effects |= EF_NODRAW; + pev->nextthink = 0; + if ( m_pSprite ) + m_pSprite->TurnOff(); +} + + +void CLaser::TurnOn( void ) +{ + pev->effects &= ~EF_NODRAW; + if ( m_pSprite ) + m_pSprite->TurnOn(); + pev->dmgtime = gpGlobals->time; + pev->nextthink = gpGlobals->time; +} + + +void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int active = IsOn(); + + if ( !ShouldToggle( useType, active ) ) + return; + if ( active ) + { + TurnOff(); + } + else + { + TurnOn(); + } +} + + +void CLaser::FireAtPoint( TraceResult &tr ) +{ + SetEndPos( tr.vecEndPos ); + if ( m_pSprite ) + UTIL_SetOrigin( m_pSprite->pev, tr.vecEndPos ); + + BeamDamage( &tr ); + DoSparks( GetStartPos(), tr.vecEndPos ); +} + +void CLaser::StrikeThink( void ) +{ + CBaseEntity *pEnd = RandomTargetname( STRING(pev->message) ); + + if ( pEnd ) + m_firePosition = pEnd->pev->origin; + + TraceResult tr; + + UTIL_TraceLine( pev->origin, m_firePosition, dont_ignore_monsters, NULL, &tr ); + FireAtPoint( tr ); + pev->nextthink = gpGlobals->time + 0.1; +} + + + +class CGlow : public CPointEntity +{ +public: + void Spawn( void ); + void Think( void ); + void Animate( float frames ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + float m_lastTime; + float m_maxFrame; +}; + +LINK_ENTITY_TO_CLASS( env_glow, CGlow ); + +TYPEDESCRIPTION CGlow::m_SaveData[] = +{ + DEFINE_FIELD( CGlow, m_lastTime, FIELD_TIME ), + DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ); + +void CGlow::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; + + PRECACHE_MODEL( (char *)STRING(pev->model) ); + SET_MODEL( ENT(pev), STRING(pev->model) ); + + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + if ( m_maxFrame > 1.0 && pev->framerate != 0 ) + pev->nextthink = gpGlobals->time + 0.1; + + m_lastTime = gpGlobals->time; +} + + +void CGlow::Think( void ) +{ + Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); + + pev->nextthink = gpGlobals->time + 0.1; + m_lastTime = gpGlobals->time; +} + + +void CGlow::Animate( float frames ) +{ + if ( m_maxFrame > 0 ) + pev->frame = fmod( pev->frame + frames, m_maxFrame ); +} + + +LINK_ENTITY_TO_CLASS( env_sprite, CSprite ); + +TYPEDESCRIPTION CSprite::m_SaveData[] = +{ + DEFINE_FIELD( CSprite, m_lastTime, FIELD_TIME ), + DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ); + +void CSprite::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; + + Precache(); + SET_MODEL( ENT(pev), STRING(pev->model) ); + + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) ) + TurnOff(); + else + TurnOn(); + + // Worldcraft only sets y rotation, copy to Z + if ( pev->angles.y != 0 && pev->angles.z == 0 ) + { + pev->angles.z = pev->angles.y; + pev->angles.y = 0; + } +} + + +void CSprite::Precache( void ) +{ + PRECACHE_MODEL( (char *)STRING(pev->model) ); + + // Reset attachment after save/restore + if ( pev->aiment ) + SetAttachment( pev->aiment, pev->body ); + else + { + // Clear attachment + pev->skin = 0; + pev->body = 0; + } +} + + +void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) +{ + pev->model = MAKE_STRING(pSpriteName); + pev->origin = origin; + Spawn(); +} + +CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) +{ + CSprite *pSprite = GetClassPtr( (CSprite *)NULL ); + pSprite->SpriteInit( pSpriteName, origin ); + pSprite->pev->classname = MAKE_STRING("env_sprite"); + pSprite->pev->solid = SOLID_NOT; + pSprite->pev->movetype = MOVETYPE_NOCLIP; + if ( animate ) + pSprite->TurnOn(); + + return pSprite; +} + + +void CSprite::AnimateThink( void ) +{ + Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); + + pev->nextthink = gpGlobals->time + 0.1; + m_lastTime = gpGlobals->time; +} + +void CSprite::AnimateUntilDead( void ) +{ + if ( gpGlobals->time > pev->dmgtime ) + UTIL_Remove(this); + else + { + AnimateThink(); + pev->nextthink = gpGlobals->time; + } +} + +void CSprite::Expand( float scaleSpeed, float fadeSpeed ) +{ + pev->speed = scaleSpeed; + pev->health = fadeSpeed; + SetThink( &CSprite::ExpandThink ); + + pev->nextthink = gpGlobals->time; + m_lastTime = gpGlobals->time; +} + + +void CSprite::ExpandThink( void ) +{ + float frametime = gpGlobals->time - m_lastTime; + pev->scale += pev->speed * frametime; + pev->renderamt -= pev->health * frametime; + if ( pev->renderamt <= 0 ) + { + pev->renderamt = 0; + UTIL_Remove( this ); + } + else + { + pev->nextthink = gpGlobals->time + 0.1; + m_lastTime = gpGlobals->time; + } +} + + +void CSprite::Animate( float frames ) +{ + pev->frame += frames; + if ( pev->frame > m_maxFrame ) + { + if ( pev->spawnflags & SF_SPRITE_ONCE ) + { + TurnOff(); + } + else + { + if ( m_maxFrame > 0 ) + pev->frame = fmod( pev->frame, m_maxFrame ); + } + } +} + + +void CSprite::TurnOff( void ) +{ + pev->effects = EF_NODRAW; + pev->nextthink = 0; +} + + +void CSprite::TurnOn( void ) +{ + pev->effects = 0; + if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) + { + SetThink( &CSprite::AnimateThink ); + pev->nextthink = gpGlobals->time; + m_lastTime = gpGlobals->time; + } + pev->frame = 0; +} + + +void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int on = pev->effects != EF_NODRAW; + if ( ShouldToggle( useType, on ) ) + { + if ( on ) + { + TurnOff(); + } + else + { + TurnOn(); + } + } +} + + +class CGibShooter : public CBaseDelay +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT ShootThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual CGib *CreateGib( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_iGibs; + int m_iGibCapacity; + int m_iGibMaterial; + int m_iGibModelIndex; + float m_flGibVelocity; + float m_flVariance; + float m_flGibLife; +}; + +TYPEDESCRIPTION CGibShooter::m_SaveData[] = +{ + DEFINE_FIELD( CGibShooter, m_iGibs, FIELD_INTEGER ), + DEFINE_FIELD( CGibShooter, m_iGibCapacity, FIELD_INTEGER ), + DEFINE_FIELD( CGibShooter, m_iGibMaterial, FIELD_INTEGER ), + DEFINE_FIELD( CGibShooter, m_iGibModelIndex, FIELD_INTEGER ), + DEFINE_FIELD( CGibShooter, m_flGibVelocity, FIELD_FLOAT ), + DEFINE_FIELD( CGibShooter, m_flVariance, FIELD_FLOAT ), + DEFINE_FIELD( CGibShooter, m_flGibLife, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ); +LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ); + + +void CGibShooter :: Precache ( void ) +{ + if ( g_Language == LANGUAGE_GERMAN ) + { + m_iGibModelIndex = PRECACHE_MODEL ("models/germanygibs.mdl"); + } + else + { + m_iGibModelIndex = PRECACHE_MODEL ("models/hgibs.mdl"); + } +} + + +void CGibShooter::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "m_iGibs")) + { + m_iGibs = m_iGibCapacity = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_flVelocity")) + { + m_flGibVelocity = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_flVariance")) + { + m_flVariance = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_flGibLife")) + { + m_flGibLife = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + { + CBaseDelay::KeyValue( pkvd ); + } +} + +void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( &CGibShooter::ShootThink ); + pev->nextthink = gpGlobals->time; +} + +void CGibShooter::Spawn( void ) +{ + Precache(); + + pev->solid = SOLID_NOT; + pev->effects = EF_NODRAW; + + if ( m_flDelay == 0 ) + { + m_flDelay = 0.1; + } + + if ( m_flGibLife == 0 ) + { + m_flGibLife = 25; + } + + SetMovedir ( pev ); + pev->body = MODEL_FRAMES( m_iGibModelIndex ); +} + + +CGib *CGibShooter :: CreateGib ( void ) +{ + if ( ns_cvar_float(violence_hgibs) == 0 ) + return NULL; + + CGib *pGib = GetClassPtr( (CGib *)NULL ); + pGib->Spawn( "models/hgibs.mdl" ); + pGib->m_bloodColor = BLOOD_COLOR_RED; + + if ( pev->body <= 1 ) + { + ALERT ( at_aiconsole, "GibShooter Body is <= 1!\n" ); + } + + pGib->pev->body = RANDOM_LONG ( 1, pev->body - 1 );// avoid throwing random amounts of the 0th gib. (skull). + + return pGib; +} + + +void CGibShooter :: ShootThink ( void ) +{ + pev->nextthink = gpGlobals->time + m_flDelay; + + Vector vecShootDir; + + vecShootDir = pev->movedir; + + vecShootDir = vecShootDir + gpGlobals->v_right * RANDOM_FLOAT( -1, 1) * m_flVariance;; + vecShootDir = vecShootDir + gpGlobals->v_forward * RANDOM_FLOAT( -1, 1) * m_flVariance;; + vecShootDir = vecShootDir + gpGlobals->v_up * RANDOM_FLOAT( -1, 1) * m_flVariance;; + + vecShootDir = vecShootDir.Normalize(); + CGib *pGib = CreateGib(); + + if ( pGib ) + { + pGib->pev->origin = pev->origin; + pGib->pev->velocity = vecShootDir * m_flGibVelocity; + + pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); + pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); + + float thinkTime = pGib->pev->nextthink - gpGlobals->time; + + pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT( 0.95, 1.05 )); // +/- 5% + if ( pGib->m_lifeTime < thinkTime ) + { + pGib->pev->nextthink = gpGlobals->time + pGib->m_lifeTime; + pGib->m_lifeTime = 0; + } + + } + + if ( --m_iGibs <= 0 ) + { + if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) + { + m_iGibs = m_iGibCapacity; + SetThink ( NULL ); + pev->nextthink = gpGlobals->time; + } + else + { + SetThink ( &CGibShooter::SUB_Remove ); + pev->nextthink = gpGlobals->time; + } + } +} + + +class CEnvShooter : public CGibShooter +{ + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + + CGib *CreateGib( void ); +}; + +LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ); + +void CEnvShooter :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "shootmodel")) + { + pev->model = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "shootsounds")) + { + int iNoise = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + switch( iNoise ) + { + case 0: + m_iGibMaterial = matGlass; + break; + case 1: + m_iGibMaterial = matWood; + break; + case 2: + m_iGibMaterial = matMetal; + break; + case 3: + m_iGibMaterial = matFlesh; + break; + case 4: + m_iGibMaterial = matRocks; + break; + + default: + case -1: + m_iGibMaterial = matNone; + break; + } + } + else + { + CGibShooter::KeyValue( pkvd ); + } +} + + +void CEnvShooter :: Precache ( void ) +{ + m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING(pev->model) ); + CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial ); +} + + +CGib *CEnvShooter :: CreateGib ( void ) +{ + CGib *pGib = GetClassPtr( (CGib *)NULL ); + + pGib->Spawn( STRING(pev->model) ); + + int bodyPart = 0; + + if ( pev->body > 1 ) + bodyPart = RANDOM_LONG( 0, pev->body-1 ); + + pGib->pev->body = bodyPart; + pGib->m_bloodColor = DONT_BLEED; + pGib->m_material = m_iGibMaterial; + + pGib->pev->rendermode = pev->rendermode; + pGib->pev->renderamt = pev->renderamt; + pGib->pev->rendercolor = pev->rendercolor; + pGib->pev->renderfx = pev->renderfx; + pGib->pev->scale = pev->scale; + pGib->pev->skin = pev->skin; + + return pGib; +} + + + + +class CTestEffect : public CBaseDelay +{ +public: + void Spawn( void ); + void Precache( void ); + // void KeyValue( KeyValueData *pkvd ); + void EXPORT TestThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + int m_iLoop; + int m_iBeam; + CBeam *m_pBeam[24]; + float m_flBeamTime[24]; + float m_flStartTime; +}; + + +LINK_ENTITY_TO_CLASS( test_effect, CTestEffect ); + +void CTestEffect::Spawn( void ) +{ + Precache( ); +} + +void CTestEffect::Precache( void ) +{ + PRECACHE_MODEL( "sprites/lgtning.spr" ); +} + +void CTestEffect::TestThink( void ) +{ + int i; + float t = (gpGlobals->time - m_flStartTime); + + if (m_iBeam < 24) + { + CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.spr", 100 ); + + TraceResult tr; + + Vector vecSrc = pev->origin; + Vector vecDir = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); + vecDir = vecDir.Normalize(); + UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT(pev), &tr); + + pbeam->PointsInit( vecSrc, tr.vecEndPos ); + // pbeam->SetColor( 80, 100, 255 ); + pbeam->SetColor( 255, 180, 100 ); + pbeam->SetWidth( 100 ); + pbeam->SetScrollRate( 12 ); + + m_flBeamTime[m_iBeam] = gpGlobals->time; + m_pBeam[m_iBeam] = pbeam; + m_iBeam++; + +#if 0 + Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5; + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE(TE_DLIGHT); + WRITE_COORD(vecMid.x); // X + WRITE_COORD(vecMid.y); // Y + WRITE_COORD(vecMid.z); // Z + WRITE_BYTE( 20 ); // radius * 0.1 + WRITE_BYTE( 255 ); // r + WRITE_BYTE( 180 ); // g + WRITE_BYTE( 100 ); // b + WRITE_BYTE( 20 ); // time * 10 + WRITE_BYTE( 0 ); // decay * 0.1 + MESSAGE_END( ); +#endif + } + + if (t < 3.0) + { + for (i = 0; i < m_iBeam; i++) + { + t = (gpGlobals->time - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]); + m_pBeam[i]->SetBrightness( 255 * t ); + // m_pBeam[i]->SetScrollRate( 20 * t ); + } + pev->nextthink = gpGlobals->time + 0.1; + } + else + { + for (i = 0; i < m_iBeam; i++) + { + UTIL_Remove( m_pBeam[i] ); + } + m_flStartTime = gpGlobals->time; + m_iBeam = 0; + // pev->nextthink = gpGlobals->time; + SetThink( NULL ); + } +} + + +void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( &CTestEffect::TestThink ); + pev->nextthink = gpGlobals->time + 0.1; + m_flStartTime = gpGlobals->time; +} + + + +// Blood effects +class CBlood : public CPointEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + + inline int Color( void ) { return pev->impulse; } + inline float BloodAmount( void ) { return pev->dmg; } + + inline void SetColor( int color ) { pev->impulse = color; } + inline void SetBloodAmount( float amount ) { pev->dmg = amount; } + + Vector Direction( void ); + Vector BloodPosition( CBaseEntity *pActivator ); + +private: +}; + +LINK_ENTITY_TO_CLASS( env_blood, CBlood ); + + + +#define SF_BLOOD_RANDOM 0x0001 +#define SF_BLOOD_STREAM 0x0002 +#define SF_BLOOD_PLAYER 0x0004 +#define SF_BLOOD_DECAL 0x0008 + +void CBlood::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; + SetMovedir( pev ); +} + + +void CBlood::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "color")) + { + int color = atoi(pkvd->szValue); + switch( color ) + { + case 1: + SetColor( BLOOD_COLOR_YELLOW ); + break; + default: + SetColor( BLOOD_COLOR_RED ); + break; + } + + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "amount")) + { + SetBloodAmount( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + + +Vector CBlood::Direction( void ) +{ + if ( pev->spawnflags & SF_BLOOD_RANDOM ) + return UTIL_RandomBloodVector(); + + return pev->movedir; +} + + +Vector CBlood::BloodPosition( CBaseEntity *pActivator ) +{ + if ( pev->spawnflags & SF_BLOOD_PLAYER ) + { + edict_t *pPlayer; + + if ( pActivator && pActivator->IsPlayer() ) + { + pPlayer = pActivator->edict(); + } + else + pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + if ( pPlayer ) + return (pPlayer->v.origin + pPlayer->v.view_ofs) + Vector( RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10) ); + } + + return pev->origin; +} + + +void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( pev->spawnflags & SF_BLOOD_STREAM ) + UTIL_BloodStream( BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), BloodAmount() ); + else + UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); + + if ( pev->spawnflags & SF_BLOOD_DECAL ) + { + Vector forward = Direction(); + Vector start = BloodPosition( pActivator ); + TraceResult tr; + + UTIL_TraceLine( start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr ); + if ( tr.flFraction != 1.0 ) + UTIL_BloodDecalTrace( &tr, Color() ); + } +} + + + +// Screen shake +class CShake : public CPointEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + + inline float Amplitude( void ) { return pev->scale; } + inline float Frequency( void ) { return pev->dmg_save; } + inline float Duration( void ) { return pev->dmg_take; } + inline float Radius( void ) { return pev->dmg; } + + inline void SetAmplitude( float amplitude ) { pev->scale = amplitude; } + inline void SetFrequency( float frequency ) { pev->dmg_save = frequency; } + inline void SetDuration( float duration ) { pev->dmg_take = duration; } + inline void SetRadius( float radius ) { pev->dmg = radius; } +private: +}; + +LINK_ENTITY_TO_CLASS( env_shake, CShake ); + +// pev->scale is amplitude +// pev->dmg_save is frequency +// pev->dmg_take is duration +// pev->dmg is radius +// radius of 0 means all players +// NOTE: UTIL_ScreenShake() will only shake players who are on the ground + +#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius +// UNDONE: These don't work yet +#define SF_SHAKE_DISRUPT 0x0002 // Disrupt controls +#define SF_SHAKE_INAIR 0x0004 // Shake players in air + +void CShake::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; + + if ( pev->spawnflags & SF_SHAKE_EVERYONE ) + pev->dmg = 0; +} + + +void CShake::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "amplitude")) + { + SetAmplitude( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "frequency")) + { + SetFrequency( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "duration")) + { + SetDuration( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "radius")) + { + SetRadius( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + + +void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() ); +} + + +class CFade : public CPointEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + + inline float Duration( void ) { return pev->dmg_take; } + inline float HoldTime( void ) { return pev->dmg_save; } + + inline void SetDuration( float duration ) { pev->dmg_take = duration; } + inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } +private: +}; + +LINK_ENTITY_TO_CLASS( env_fade, CFade ); + +// pev->dmg_take is duration +// pev->dmg_save is hold duration +#define SF_FADE_IN 0x0001 // Fade in, not out +#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend +#define SF_FADE_ONLYONE 0x0004 + +void CFade::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; +} + + +void CFade::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "duration")) + { + SetDuration( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "holdtime")) + { + SetHoldTime( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + + +void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int fadeFlags = 0; + + if ( !(pev->spawnflags & SF_FADE_IN) ) + fadeFlags |= FFADE_OUT; + + if ( pev->spawnflags & SF_FADE_MODULATE ) + fadeFlags |= FFADE_MODULATE; + + if ( pev->spawnflags & SF_FADE_ONLYONE ) + { + if ( pActivator->IsNetClient() ) + { + UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); + } + } + else + { + UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); + } + SUB_UseTargets( this, USE_TOGGLE, 0 ); +} + + +class CMessage : public CPointEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); +private: +}; + +LINK_ENTITY_TO_CLASS( env_message, CMessage ); + + +void CMessage::Spawn( void ) +{ + Precache(); + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + + switch( pev->impulse ) + { + case 1: // Medium radius + pev->speed = ATTN_STATIC; + break; + + case 2: // Large radius + pev->speed = ATTN_NORM; + break; + + case 3: //EVERYWHERE + pev->speed = ATTN_NONE; + break; + + default: + case 0: // Small radius + pev->speed = ATTN_IDLE; + break; + } + pev->impulse = 0; + + // No volume, use normal + if ( pev->scale <= 0 ) + pev->scale = 1.0; +} + + +void CMessage::Precache( void ) +{ + if ( pev->noise ) + PRECACHE_SOUND( (char *)STRING(pev->noise) ); +} + +void CMessage::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "messagesound")) + { + pev->noise = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "messagevolume")) + { + pev->scale = atof(pkvd->szValue) * 0.1; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "messageattenuation")) + { + pev->impulse = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + + +void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CBaseEntity *pPlayer = NULL; + + if ( pev->spawnflags & SF_MESSAGE_ALL ) + UTIL_ShowMessageAll( STRING(pev->message) ); + else + { + if ( pActivator && pActivator->IsPlayer() ) + pPlayer = pActivator; + else + { + pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); + } + if ( pPlayer ) + UTIL_ShowMessage( STRING(pev->message), pPlayer ); + } + if ( pev->noise ) + { + EMIT_SOUND( edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed ); + } + if ( pev->spawnflags & SF_MESSAGE_ONCE ) + UTIL_Remove( this ); + + SUB_UseTargets( this, USE_TOGGLE, 0 ); +} + + + +//========================================================= +// FunnelEffect +//========================================================= +class CEnvFunnel : public CBaseDelay +{ +public: + void Spawn( void ); + void Precache( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + int m_iSprite; // Don't save, precache +}; + +void CEnvFunnel :: Precache ( void ) +{ + m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); +} + +LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ); + +void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_LARGEFUNNEL ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_SHORT( m_iSprite ); + + if ( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse? + { + WRITE_SHORT( 1 ); + } + else + { + WRITE_SHORT( 0 ); + } + + + MESSAGE_END(); + + SetThink( &CEnvFunnel::SUB_Remove ); + pev->nextthink = gpGlobals->time; +} + +void CEnvFunnel::Spawn( void ) +{ + Precache(); + pev->solid = SOLID_NOT; + pev->effects = EF_NODRAW; +} + +//========================================================= +// Beverage Dispenser +// overloaded pev->frags, is now a flag for whether or not a can is stuck in the dispenser. +// overloaded pev->health, is now how many cans remain in the machine. +//========================================================= +class CEnvBeverage : public CBaseDelay +{ +public: + void Spawn( void ); + void Precache( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +void CEnvBeverage :: Precache ( void ) +{ + PRECACHE_MODEL( "models/can.mdl" ); + PRECACHE_SOUND( "weapons/g_bounce3.wav" ); +} + +LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage ); + +void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( pev->frags != 0 || pev->health <= 0 ) + { + // no more cans while one is waiting in the dispenser, or if I'm out of cans. + return; + } + + CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", pev->origin, pev->angles, edict() ); + + if ( pev->skin == 6 ) + { + // random + pCan->pev->skin = RANDOM_LONG( 0, 5 ); + } + else + { + pCan->pev->skin = pev->skin; + } + + pev->frags = 1; + pev->health--; + + //SetThink (SUB_Remove); + //pev->nextthink = gpGlobals->time; +} + +void CEnvBeverage::Spawn( void ) +{ + Precache(); + pev->solid = SOLID_NOT; + pev->effects = EF_NODRAW; + pev->frags = 0; + + if ( pev->health == 0 ) + { + pev->health = 10; + } +} + +//========================================================= +// Soda can +//========================================================= +class CItemSoda : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT CanThink ( void ); + void EXPORT CanTouch ( CBaseEntity *pOther ); +}; + +void CItemSoda :: Precache ( void ) +{ +} + +LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ); + +void CItemSoda::Spawn( void ) +{ + Precache(); + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_TOSS; + + SET_MODEL ( ENT(pev), "models/can.mdl" ); + UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) ); + + SetThink (&CItemSoda::CanThink); + pev->nextthink = gpGlobals->time + 0.5; +} + +void CItemSoda::CanThink ( void ) +{ + EMIT_SOUND (ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM ); + + pev->solid = SOLID_TRIGGER; + UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) ); + SetThink ( NULL ); + SetTouch ( &CItemSoda::CanTouch ); +} + +void CItemSoda::CanTouch ( CBaseEntity *pOther ) +{ + if ( !pOther->IsPlayer() ) + { + return; + } + + // spoit sound here + + pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health. + + if ( !FNullEnt( pev->owner ) ) + { + // tell the machine the can was taken + pev->owner->v.frags = 0; + } + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = EF_NODRAW; + SetTouch ( NULL ); + SetThink ( &CItemSoda::SUB_Remove ); + pev->nextthink = gpGlobals->time; +} diff --git a/main/source/dlls/effects.cpp~ b/main/source/dlls/effects.cpp~ deleted file mode 100644 index 32e761f7..00000000 --- a/main/source/dlls/effects.cpp~ +++ /dev/null @@ -1,2270 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "..engine/customentity.h" -#include "effects.h" -#include "weapons.h" -#include "decals.h" -#include "func_break.h" -#include "../engine/shake.h" -#include "../mod/AvHServerVariables.h" -extern cvar_t avh_killdelay; - -#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired - -#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. - - -// Lightning target, just alias landmark -LINK_ENTITY_TO_CLASS( info_target, CPointEntity ); - - -class CBubbling : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - void EXPORT FizzThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; - - int m_density; - int m_frequency; - int m_bubbleModel; - int m_state; -}; - -LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling ); - -TYPEDESCRIPTION CBubbling::m_SaveData[] = -{ - DEFINE_FIELD( CBubbling, m_density, FIELD_INTEGER ), - DEFINE_FIELD( CBubbling, m_frequency, FIELD_INTEGER ), - DEFINE_FIELD( CBubbling, m_state, FIELD_INTEGER ), - // Let spawn restore this! - // DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ); - - -#define SF_BUBBLES_STARTOFF 0x0001 - -void CBubbling::Spawn( void ) -{ - Precache( ); - SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size - - pev->solid = SOLID_NOT; // Remove model & collisions - pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on - pev->rendermode = kRenderTransTexture; - int speed = pev->speed > 0 ? pev->speed : -pev->speed; - - // HACKHACK!!! - Speed in rendercolor - pev->rendercolor.x = speed >> 8; - pev->rendercolor.y = speed & 255; - pev->rendercolor.z = (pev->speed < 0) ? 1 : 0; - - - if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) - { - SetThink( &CBubbling::FizzThink ); - pev->nextthink = gpGlobals->time + 2.0; - m_state = 1; - } - else - m_state = 0; -} - -void CBubbling::Precache( void ) -{ - m_bubbleModel = PRECACHE_MODEL("sprites/bubble2.spr"); // Precache bubble sprite -} - - -void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( ShouldToggle( useType, m_state ) ) - m_state = !m_state; - - if ( m_state ) - { - SetThink( &CBubbling::FizzThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - SetThink( NULL ); - pev->nextthink = 0; - } -} - - -void CBubbling::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "density")) - { - m_density = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency")) - { - m_frequency = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "current")) - { - pev->speed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CBubbling::FizzThink( void ) -{ - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) ); - WRITE_BYTE( TE_FIZZ ); - WRITE_SHORT( (short)ENTINDEX( edict() ) ); - WRITE_SHORT( (short)m_bubbleModel ); - WRITE_BYTE( m_density ); - MESSAGE_END(); - - if ( m_frequency > 19 ) - pev->nextthink = gpGlobals->time + 0.5; - else - pev->nextthink = gpGlobals->time + 2.5 - (0.1 * m_frequency); -} - -// -------------------------------------------------- -// -// Beams -// -// -------------------------------------------------- - -LINK_ENTITY_TO_CLASS( beam, CBeam ); - -void CBeam::Spawn( void ) -{ - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); -} - -void CBeam::Precache( void ) -{ - if ( pev->owner ) - SetStartEntity( ENTINDEX( pev->owner ) ); - if ( pev->aiment ) - SetEndEntity( ENTINDEX( pev->aiment ) ); -} - -void CBeam::SetStartEntity( int entityIndex ) -{ - pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12); - pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); -} - -void CBeam::SetEndEntity( int entityIndex ) -{ - pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12); - pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); -} - - -// These don't take attachments into account -const Vector &CBeam::GetStartPos( void ) -{ - if ( GetType() == BEAM_ENTS ) - { - edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() ); - return pent->v.origin; - } - return pev->origin; -} - - -const Vector &CBeam::GetEndPos( void ) -{ - int type = GetType(); - if ( type == BEAM_POINTS || type == BEAM_HOSE ) - { - return pev->angles; - } - - edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() ); - if ( pent ) - return pent->v.origin; - return pev->angles; -} - - -CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) -{ - // Create a new entity with CBeam private data - CBeam *pBeam = GetClassPtr( (CBeam *)NULL ); - pBeam->pev->classname = MAKE_STRING("beam"); - - pBeam->BeamInit( pSpriteName, width ); - - return pBeam; -} - - -void CBeam::BeamInit( const char *pSpriteName, int width ) -{ - pev->flags |= FL_CUSTOMENTITY; - SetColor( 255, 255, 255 ); - SetBrightness( 255 ); - SetNoise( 0 ); - SetFrame( 0 ); - SetScrollRate( 0 ); - pev->model = MAKE_STRING( pSpriteName ); - SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) ); - SetWidth( width ); - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; -} - - -void CBeam::PointsInit( const Vector &start, const Vector &end ) -{ - SetType( BEAM_POINTS ); - SetStartPos( start ); - SetEndPos( end ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::HoseInit( const Vector &start, const Vector &direction ) -{ - SetType( BEAM_HOSE ); - SetStartPos( start ); - SetEndPos( direction ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::PointEntInit( const Vector &start, int endIndex ) -{ - SetType( BEAM_ENTPOINT ); - SetStartPos( start ); - SetEndEntity( endIndex ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::EntsInit( int startIndex, int endIndex ) -{ - SetType( BEAM_ENTS ); - SetStartEntity( startIndex ); - SetEndEntity( endIndex ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::RelinkBeam( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->mins.x = min( startPos.x, endPos.x ); - pev->mins.y = min( startPos.y, endPos.y ); - pev->mins.z = min( startPos.z, endPos.z ); - pev->maxs.x = max( startPos.x, endPos.x ); - pev->maxs.y = max( startPos.y, endPos.y ); - pev->maxs.z = max( startPos.z, endPos.z ); - pev->mins = pev->mins - pev->origin; - pev->maxs = pev->maxs - pev->origin; - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); -} - -#if 0 -void CBeam::SetObjectCollisionBox( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->absmin.x = min( startPos.x, endPos.x ); - pev->absmin.y = min( startPos.y, endPos.y ); - pev->absmin.z = min( startPos.z, endPos.z ); - pev->absmax.x = max( startPos.x, endPos.x ); - pev->absmax.y = max( startPos.y, endPos.y ); - pev->absmax.z = max( startPos.z, endPos.z ); -} -#endif - - -void CBeam::TriggerTouch( CBaseEntity *pOther ) -{ - if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) - { - if ( pev->owner ) - { - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - pOwner->Use( pOther, this, USE_TOGGLE, 0 ); - } - ALERT( at_console, "Firing targets!!!\n" ); - } -} - - -CBaseEntity *CBeam::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - - -void CBeam::DoSparks( const Vector &start, const Vector &end ) -{ - if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) - { - if ( pev->spawnflags & SF_BEAM_SPARKSTART ) - { - UTIL_Sparks( start ); - } - if ( pev->spawnflags & SF_BEAM_SPARKEND ) - { - UTIL_Sparks( end ); - } - } -} - - -class CLightning : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - - void EXPORT StrikeThink( void ); - void EXPORT DamageThink( void ); - void RandomArea( void ); - void RandomPoint( Vector &vecSrc ); - void Zap( const Vector &vecSrc, const Vector &vecDest ); - void EXPORT StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL ServerSide( void ) - { - if ( m_life == 0 && !(pev->spawnflags & SF_BEAM_RING) ) - return TRUE; - return FALSE; - } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void BeamUpdateVars( void ); - - int m_active; - int m_iszStartEntity; - int m_iszEndEntity; - float m_life; - int m_boltWidth; - int m_noiseAmplitude; - int m_brightness; - int m_speed; - float m_restrike; - int m_spriteTexture; - int m_iszSpriteName; - int m_frameStart; - - float m_radius; -}; - -LINK_ENTITY_TO_CLASS( env_lightning, CLightning ); -LINK_ENTITY_TO_CLASS( env_beam, CLightning ); - -// UNDONE: Jay -- This is only a test -#if _DEBUG -class CTripBeam : public CLightning -{ - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ); - -void CTripBeam::Spawn( void ) -{ - CLightning::Spawn(); - SetTouch( &CTripBeam::TriggerTouch ); - pev->solid = SOLID_TRIGGER; - RelinkBeam(); -} -#endif - - - -TYPEDESCRIPTION CLightning::m_SaveData[] = -{ - DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_iszStartEntity, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_iszEndEntity, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_life, FIELD_FLOAT ), - DEFINE_FIELD( CLightning, m_boltWidth, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_noiseAmplitude, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_brightness, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_speed, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_restrike, FIELD_FLOAT ), - DEFINE_FIELD( CLightning, m_spriteTexture, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_iszSpriteName, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_frameStart, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_radius, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CLightning, CBeam ); - - -void CLightning::Spawn( void ) -{ - if ( FStringNull( m_iszSpriteName ) ) - { - SetThink( &CLightning::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); - - pev->dmgtime = gpGlobals->time; - - if ( ServerSide() ) - { - SetThink( NULL ); - if ( pev->dmg > 0 ) - { - SetThink( &CLightning::DamageThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - if ( pev->targetname ) - { - if ( !(pev->spawnflags & SF_BEAM_STARTON) ) - { - pev->effects = EF_NODRAW; - m_active = 0; - pev->nextthink = 0; - } - else - m_active = 1; - - SetUse( &CLightning::ToggleUse ); - } - } - else - { - m_active = 0; - if ( !FStringNull(pev->targetname) ) - { - SetUse( &CLightning::StrikeUse ); - } - if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) - { - SetThink( &CLightning::StrikeThink ); - pev->nextthink = gpGlobals->time + 1.0; - } - } -} - -void CLightning::Precache( void ) -{ - m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); - CBeam::Precache(); -} - - -void CLightning::Activate( void ) -{ - if ( ServerSide() ) - BeamUpdateVars(); -} - - -void CLightning::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "LightningStart")) - { - m_iszStartEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "LightningEnd")) - { - m_iszEndEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "life")) - { - m_life = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "BoltWidth")) - { - m_boltWidth = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) - { - m_noiseAmplitude = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) - { - m_speed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "StrikeTime")) - { - m_restrike = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "texture")) - { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "framestart")) - { - m_frameStart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Radius")) - { - m_radius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBeam::KeyValue( pkvd ); -} - - -void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_active ) ) - return; - if ( m_active ) - { - m_active = 0; - pev->effects |= EF_NODRAW; - pev->nextthink = 0; - } - else - { - m_active = 1; - pev->effects &= ~EF_NODRAW; - DoSparks( GetStartPos(), GetEndPos() ); - if ( pev->dmg > 0 ) - { - pev->nextthink = gpGlobals->time; - pev->dmgtime = gpGlobals->time; - } - } -} - - -void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_active ) ) - return; - - if ( m_active ) - { - m_active = 0; - SetThink( NULL ); - } - else - { - SetThink( &CLightning::StrikeThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - - if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) - SetUse( NULL ); -} - - -int IsPointEntity( CBaseEntity *pEnt ) -{ - if ( !pEnt->pev->modelindex ) - return 1; - if ( FClassnameIs( pEnt->pev, "info_target" ) || FClassnameIs( pEnt->pev, "info_landmark" ) || FClassnameIs( pEnt->pev, "path_corner" ) ) - return 1; - - return 0; -} - - -void CLightning::StrikeThink( void ) -{ - if ( m_life != 0 ) - { - if ( pev->spawnflags & SF_BEAM_RANDOM ) - pev->nextthink = gpGlobals->time + m_life + RANDOM_FLOAT( 0, m_restrike ); - else - pev->nextthink = gpGlobals->time + m_life + m_restrike; - } - m_active = 1; - - if (FStringNull(m_iszEndEntity)) - { - if (FStringNull(m_iszStartEntity)) - { - RandomArea( ); - } - else - { - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - if (pStart != NULL) - RandomPoint( pStart->pev->origin ); - else - ALERT( at_console, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) ); - } - return; - } - - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) ); - - if ( pStart != NULL && pEnd != NULL ) - { - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) - { - if ( pev->spawnflags & SF_BEAM_RING) - { - // don't work - return; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) - { - if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd - { - CBaseEntity *pTemp; - pTemp = pStart; - pStart = pEnd; - pEnd = pTemp; - } - if ( !IsPointEntity( pStart ) ) // One sided - { - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( pStart->entindex() ); - WRITE_COORD( pEnd->pev->origin.x); - WRITE_COORD( pEnd->pev->origin.y); - WRITE_COORD( pEnd->pev->origin.z); - } - else - { - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD( pStart->pev->origin.x); - WRITE_COORD( pStart->pev->origin.y); - WRITE_COORD( pStart->pev->origin.z); - WRITE_COORD( pEnd->pev->origin.x); - WRITE_COORD( pEnd->pev->origin.y); - WRITE_COORD( pEnd->pev->origin.z); - } - - - } - else - { - if ( pev->spawnflags & SF_BEAM_RING) - WRITE_BYTE( TE_BEAMRING ); - else - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( pStart->entindex() ); - WRITE_SHORT( pEnd->entindex() ); - } - - WRITE_SHORT( m_spriteTexture ); - WRITE_BYTE( m_frameStart ); // framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(m_life*10.0) ); // life - WRITE_BYTE( m_boltWidth ); // width - WRITE_BYTE( m_noiseAmplitude ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( pev->renderamt ); // brightness - WRITE_BYTE( m_speed ); // speed - MESSAGE_END(); - DoSparks( pStart->pev->origin, pEnd->pev->origin ); - if ( pev->dmg > 0 ) - { - TraceResult tr; - UTIL_TraceLine( pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr ); - BeamDamageInstant( &tr, pev->dmg ); - } - } -} - - -void CBeam::BeamDamage( TraceResult *ptr ) -{ - RelinkBeam(); - if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) - { - CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); - if ( pHit ) - { - ClearMultiDamage(); - pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pev, pev ); - if ( pev->spawnflags & SF_BEAM_DECALS ) - { - if ( pHit->IsBSPModel() ) - UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); - } - } - } - pev->dmgtime = gpGlobals->time; -} - - -void CLightning::DamageThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - TraceResult tr; - UTIL_TraceLine( GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr ); - BeamDamage( &tr ); -} - - - -void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) -{ -#if 1 - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_SHORT( m_spriteTexture ); - WRITE_BYTE( m_frameStart ); // framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(m_life*10.0) ); // life - WRITE_BYTE( m_boltWidth ); // width - WRITE_BYTE( m_noiseAmplitude ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( pev->renderamt ); // brightness - WRITE_BYTE( m_speed ); // speed - MESSAGE_END(); -#else - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE(TE_LIGHTNING); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_BYTE(10); - WRITE_BYTE(50); - WRITE_BYTE(40); - WRITE_SHORT(m_spriteTexture); - MESSAGE_END(); -#endif - DoSparks( vecSrc, vecDest ); -} - -void CLightning::RandomArea( void ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecSrc = pev->origin; - - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); - - if (tr1.flFraction == 1.0) - continue; - - Vector vecDir2; - do { - vecDir2 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - } while (DotProduct(vecDir1, vecDir2 ) > 0); - vecDir2 = vecDir2.Normalize(); - TraceResult tr2; - UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2 ); - - if (tr2.flFraction == 1.0) - continue; - - if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1) - continue; - - UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2 ); - - if (tr2.flFraction != 1.0) - continue; - - Zap( tr1.vecEndPos, tr2.vecEndPos ); - - break; - } -} - - -void CLightning::RandomPoint( Vector &vecSrc ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); - - if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1) - continue; - - if (tr1.flFraction == 1.0) - continue; - - Zap( vecSrc, tr1.vecEndPos ); - break; - } -} - - - -void CLightning::BeamUpdateVars( void ) -{ - int beamType; - int pointStart, pointEnd; - - edict_t *pStart = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszStartEntity) ); - edict_t *pEnd = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszEndEntity) ); - pointStart = IsPointEntity( CBaseEntity::Instance(pStart) ); - pointEnd = IsPointEntity( CBaseEntity::Instance(pEnd) ); - - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; - pev->flags |= FL_CUSTOMENTITY; - pev->model = m_iszSpriteName; - SetTexture( m_spriteTexture ); - - beamType = BEAM_ENTS; - if ( pointStart || pointEnd ) - { - if ( !pointStart ) // One point entity must be in pStart - { - edict_t *pTemp; - // Swap start & end - pTemp = pStart; - pStart = pEnd; - pEnd = pTemp; - int swap = pointStart; - pointStart = pointEnd; - pointEnd = swap; - } - if ( !pointEnd ) - beamType = BEAM_ENTPOINT; - else - beamType = BEAM_POINTS; - } - - SetType( beamType ); - if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) - { - SetStartPos( pStart->v.origin ); - if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) - SetEndPos( pEnd->v.origin ); - else - SetEndEntity( ENTINDEX(pEnd) ); - } - else - { - SetStartEntity( ENTINDEX(pStart) ); - SetEndEntity( ENTINDEX(pEnd) ); - } - - RelinkBeam(); - - SetWidth( m_boltWidth ); - SetNoise( m_noiseAmplitude ); - SetFrame( m_frameStart ); - SetScrollRate( m_speed ); - if ( pev->spawnflags & SF_BEAM_SHADEIN ) - SetFlags( BEAM_FSHADEIN ); - else if ( pev->spawnflags & SF_BEAM_SHADEOUT ) - SetFlags( BEAM_FSHADEOUT ); -} - - -LINK_ENTITY_TO_CLASS( env_laser, CLaser ); - -TYPEDESCRIPTION CLaser::m_SaveData[] = -{ - DEFINE_FIELD( CLaser, m_pSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CLaser, m_iszSpriteName, FIELD_STRING ), - DEFINE_FIELD( CLaser, m_firePosition, FIELD_POSITION_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CLaser, CBeam ); - -void CLaser::Spawn( void ) -{ - if ( FStringNull( pev->model ) ) - { - SetThink( &CLaser::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); - - SetThink( &CLaser::StrikeThink ); - pev->flags |= FL_CUSTOMENTITY; - - PointsInit( pev->origin, pev->origin ); - - if ( !m_pSprite && m_iszSpriteName ) - m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), pev->origin, TRUE ); - else - m_pSprite = NULL; - - if ( m_pSprite ) - m_pSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); - - if ( pev->targetname && !(pev->spawnflags & SF_BEAM_STARTON) ) - TurnOff(); - else - TurnOn(); -} - -void CLaser::Precache( void ) -{ - pev->modelindex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - if ( m_iszSpriteName ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); -} - - -void CLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "LaserTarget")) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - SetWidth( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) - { - SetNoise( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) - { - SetScrollRate( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->model = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "EndSprite")) - { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "framestart")) - { - pev->frame = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBeam::KeyValue( pkvd ); -} - - -int CLaser::IsOn( void ) -{ - if (pev->effects & EF_NODRAW) - return 0; - return 1; -} - - -void CLaser::TurnOff( void ) -{ - pev->effects |= EF_NODRAW; - pev->nextthink = 0; - if ( m_pSprite ) - m_pSprite->TurnOff(); -} - - -void CLaser::TurnOn( void ) -{ - pev->effects &= ~EF_NODRAW; - if ( m_pSprite ) - m_pSprite->TurnOn(); - pev->dmgtime = gpGlobals->time; - pev->nextthink = gpGlobals->time; -} - - -void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int active = IsOn(); - - if ( !ShouldToggle( useType, active ) ) - return; - if ( active ) - { - TurnOff(); - } - else - { - TurnOn(); - } -} - - -void CLaser::FireAtPoint( TraceResult &tr ) -{ - SetEndPos( tr.vecEndPos ); - if ( m_pSprite ) - UTIL_SetOrigin( m_pSprite->pev, tr.vecEndPos ); - - BeamDamage( &tr ); - DoSparks( GetStartPos(), tr.vecEndPos ); -} - -void CLaser::StrikeThink( void ) -{ - CBaseEntity *pEnd = RandomTargetname( STRING(pev->message) ); - - if ( pEnd ) - m_firePosition = pEnd->pev->origin; - - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_firePosition, dont_ignore_monsters, NULL, &tr ); - FireAtPoint( tr ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -class CGlow : public CPointEntity -{ -public: - void Spawn( void ); - void Think( void ); - void Animate( float frames ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_lastTime; - float m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( env_glow, CGlow ); - -TYPEDESCRIPTION CGlow::m_SaveData[] = -{ - DEFINE_FIELD( CGlow, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ); - -void CGlow::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( m_maxFrame > 1.0 && pev->framerate != 0 ) - pev->nextthink = gpGlobals->time + 0.1; - - m_lastTime = gpGlobals->time; -} - - -void CGlow::Think( void ) -{ - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - - -void CGlow::Animate( float frames ) -{ - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame + frames, m_maxFrame ); -} - - -LINK_ENTITY_TO_CLASS( env_sprite, CSprite ); - -TYPEDESCRIPTION CSprite::m_SaveData[] = -{ - DEFINE_FIELD( CSprite, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ); - -void CSprite::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - Precache(); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) ) - TurnOff(); - else - TurnOn(); - - // Worldcraft only sets y rotation, copy to Z - if ( pev->angles.y != 0 && pev->angles.z == 0 ) - { - pev->angles.z = pev->angles.y; - pev->angles.y = 0; - } -} - - -void CSprite::Precache( void ) -{ - PRECACHE_MODEL( (char *)STRING(pev->model) ); - - // Reset attachment after save/restore - if ( pev->aiment ) - SetAttachment( pev->aiment, pev->body ); - else - { - // Clear attachment - pev->skin = 0; - pev->body = 0; - } -} - - -void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) -{ - pev->model = MAKE_STRING(pSpriteName); - pev->origin = origin; - Spawn(); -} - -CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) -{ - CSprite *pSprite = GetClassPtr( (CSprite *)NULL ); - pSprite->SpriteInit( pSpriteName, origin ); - pSprite->pev->classname = MAKE_STRING("env_sprite"); - pSprite->pev->solid = SOLID_NOT; - pSprite->pev->movetype = MOVETYPE_NOCLIP; - if ( animate ) - pSprite->TurnOn(); - - return pSprite; -} - - -void CSprite::AnimateThink( void ) -{ - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - -void CSprite::AnimateUntilDead( void ) -{ - if ( gpGlobals->time > pev->dmgtime ) - UTIL_Remove(this); - else - { - AnimateThink(); - pev->nextthink = gpGlobals->time; - } -} - -void CSprite::Expand( float scaleSpeed, float fadeSpeed ) -{ - pev->speed = scaleSpeed; - pev->health = fadeSpeed; - SetThink( &CSprite::ExpandThink ); - - pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; -} - - -void CSprite::ExpandThink( void ) -{ - float frametime = gpGlobals->time - m_lastTime; - pev->scale += pev->speed * frametime; - pev->renderamt -= pev->health * frametime; - if ( pev->renderamt <= 0 ) - { - pev->renderamt = 0; - UTIL_Remove( this ); - } - else - { - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; - } -} - - -void CSprite::Animate( float frames ) -{ - pev->frame += frames; - if ( pev->frame > m_maxFrame ) - { - if ( pev->spawnflags & SF_SPRITE_ONCE ) - { - TurnOff(); - } - else - { - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame, m_maxFrame ); - } - } -} - - -void CSprite::TurnOff( void ) -{ - pev->effects = EF_NODRAW; - pev->nextthink = 0; -} - - -void CSprite::TurnOn( void ) -{ - pev->effects = 0; - if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) - { - SetThink( &CSprite::AnimateThink ); - pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; - } - pev->frame = 0; -} - - -void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int on = pev->effects != EF_NODRAW; - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - { - TurnOff(); - } - else - { - TurnOn(); - } - } -} - - -class CGibShooter : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT ShootThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual CGib *CreateGib( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iGibs; - int m_iGibCapacity; - int m_iGibMaterial; - int m_iGibModelIndex; - float m_flGibVelocity; - float m_flVariance; - float m_flGibLife; -}; - -TYPEDESCRIPTION CGibShooter::m_SaveData[] = -{ - DEFINE_FIELD( CGibShooter, m_iGibs, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibCapacity, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibMaterial, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibModelIndex, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_flGibVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CGibShooter, m_flVariance, FIELD_FLOAT ), - DEFINE_FIELD( CGibShooter, m_flGibLife, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ); -LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ); - - -void CGibShooter :: Precache ( void ) -{ - if ( g_Language == LANGUAGE_GERMAN ) - { - m_iGibModelIndex = PRECACHE_MODEL ("models/germanygibs.mdl"); - } - else - { - m_iGibModelIndex = PRECACHE_MODEL ("models/hgibs.mdl"); - } -} - - -void CGibShooter::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iGibs")) - { - m_iGibs = m_iGibCapacity = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flVelocity")) - { - m_flGibVelocity = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flVariance")) - { - m_flVariance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flGibLife")) - { - m_flGibLife = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - { - CBaseDelay::KeyValue( pkvd ); - } -} - -void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CGibShooter::ShootThink ); - pev->nextthink = gpGlobals->time; -} - -void CGibShooter::Spawn( void ) -{ - Precache(); - - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - - if ( m_flDelay == 0 ) - { - m_flDelay = 0.1; - } - - if ( m_flGibLife == 0 ) - { - m_flGibLife = 25; - } - - SetMovedir ( pev ); - pev->body = MODEL_FRAMES( m_iGibModelIndex ); -} - - -CGib *CGibShooter :: CreateGib ( void ) -{ - if ( ns_cvar_float(violence_hgibs) == 0 ) - return NULL; - - CGib *pGib = GetClassPtr( (CGib *)NULL ); - pGib->Spawn( "models/hgibs.mdl" ); - pGib->m_bloodColor = BLOOD_COLOR_RED; - - if ( pev->body <= 1 ) - { - ALERT ( at_aiconsole, "GibShooter Body is <= 1!\n" ); - } - - pGib->pev->body = RANDOM_LONG ( 1, pev->body - 1 );// avoid throwing random amounts of the 0th gib. (skull). - - return pGib; -} - - -void CGibShooter :: ShootThink ( void ) -{ - pev->nextthink = gpGlobals->time + m_flDelay; - - Vector vecShootDir; - - vecShootDir = pev->movedir; - - vecShootDir = vecShootDir + gpGlobals->v_right * RANDOM_FLOAT( -1, 1) * m_flVariance;; - vecShootDir = vecShootDir + gpGlobals->v_forward * RANDOM_FLOAT( -1, 1) * m_flVariance;; - vecShootDir = vecShootDir + gpGlobals->v_up * RANDOM_FLOAT( -1, 1) * m_flVariance;; - - vecShootDir = vecShootDir.Normalize(); - CGib *pGib = CreateGib(); - - if ( pGib ) - { - pGib->pev->origin = pev->origin; - pGib->pev->velocity = vecShootDir * m_flGibVelocity; - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - float thinkTime = pGib->pev->nextthink - gpGlobals->time; - - pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT( 0.95, 1.05 )); // +/- 5% - if ( pGib->m_lifeTime < thinkTime ) - { - pGib->pev->nextthink = gpGlobals->time + pGib->m_lifeTime; - pGib->m_lifeTime = 0; - } - - } - - if ( --m_iGibs <= 0 ) - { - if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) - { - m_iGibs = m_iGibCapacity; - SetThink ( NULL ); - pev->nextthink = gpGlobals->time; - } - else - { - SetThink ( &CGibShooter::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - } -} - - -class CEnvShooter : public CGibShooter -{ - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - CGib *CreateGib( void ); -}; - -LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ); - -void CEnvShooter :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "shootmodel")) - { - pev->model = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shootsounds")) - { - int iNoise = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - switch( iNoise ) - { - case 0: - m_iGibMaterial = matGlass; - break; - case 1: - m_iGibMaterial = matWood; - break; - case 2: - m_iGibMaterial = matMetal; - break; - case 3: - m_iGibMaterial = matFlesh; - break; - case 4: - m_iGibMaterial = matRocks; - break; - - default: - case -1: - m_iGibMaterial = matNone; - break; - } - } - else - { - CGibShooter::KeyValue( pkvd ); - } -} - - -void CEnvShooter :: Precache ( void ) -{ - m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial ); -} - - -CGib *CEnvShooter :: CreateGib ( void ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( STRING(pev->model) ); - - int bodyPart = 0; - - if ( pev->body > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body-1 ); - - pGib->pev->body = bodyPart; - pGib->m_bloodColor = DONT_BLEED; - pGib->m_material = m_iGibMaterial; - - pGib->pev->rendermode = pev->rendermode; - pGib->pev->renderamt = pev->renderamt; - pGib->pev->rendercolor = pev->rendercolor; - pGib->pev->renderfx = pev->renderfx; - pGib->pev->scale = pev->scale; - pGib->pev->skin = pev->skin; - - return pGib; -} - - - - -class CTestEffect : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - // void KeyValue( KeyValueData *pkvd ); - void EXPORT TestThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iLoop; - int m_iBeam; - CBeam *m_pBeam[24]; - float m_flBeamTime[24]; - float m_flStartTime; -}; - - -LINK_ENTITY_TO_CLASS( test_effect, CTestEffect ); - -void CTestEffect::Spawn( void ) -{ - Precache( ); -} - -void CTestEffect::Precache( void ) -{ - PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - -void CTestEffect::TestThink( void ) -{ - int i; - float t = (gpGlobals->time - m_flStartTime); - - if (m_iBeam < 24) - { - CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.spr", 100 ); - - TraceResult tr; - - Vector vecSrc = pev->origin; - Vector vecDir = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir = vecDir.Normalize(); - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT(pev), &tr); - - pbeam->PointsInit( vecSrc, tr.vecEndPos ); - // pbeam->SetColor( 80, 100, 255 ); - pbeam->SetColor( 255, 180, 100 ); - pbeam->SetWidth( 100 ); - pbeam->SetScrollRate( 12 ); - - m_flBeamTime[m_iBeam] = gpGlobals->time; - m_pBeam[m_iBeam] = pbeam; - m_iBeam++; - -#if 0 - Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5; - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecMid.x); // X - WRITE_COORD(vecMid.y); // Y - WRITE_COORD(vecMid.z); // Z - WRITE_BYTE( 20 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 100 ); // b - WRITE_BYTE( 20 ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); -#endif - } - - if (t < 3.0) - { - for (i = 0; i < m_iBeam; i++) - { - t = (gpGlobals->time - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]); - m_pBeam[i]->SetBrightness( 255 * t ); - // m_pBeam[i]->SetScrollRate( 20 * t ); - } - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - for (i = 0; i < m_iBeam; i++) - { - UTIL_Remove( m_pBeam[i] ); - } - m_flStartTime = gpGlobals->time; - m_iBeam = 0; - // pev->nextthink = gpGlobals->time; - SetThink( NULL ); - } -} - - -void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CTestEffect::TestThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flStartTime = gpGlobals->time; -} - - - -// Blood effects -class CBlood : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Color( void ) { return pev->impulse; } - inline float BloodAmount( void ) { return pev->dmg; } - - inline void SetColor( int color ) { pev->impulse = color; } - inline void SetBloodAmount( float amount ) { pev->dmg = amount; } - - Vector Direction( void ); - Vector BloodPosition( CBaseEntity *pActivator ); - -private: -}; - -LINK_ENTITY_TO_CLASS( env_blood, CBlood ); - - - -#define SF_BLOOD_RANDOM 0x0001 -#define SF_BLOOD_STREAM 0x0002 -#define SF_BLOOD_PLAYER 0x0004 -#define SF_BLOOD_DECAL 0x0008 - -void CBlood::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - SetMovedir( pev ); -} - - -void CBlood::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "color")) - { - int color = atoi(pkvd->szValue); - switch( color ) - { - case 1: - SetColor( BLOOD_COLOR_YELLOW ); - break; - default: - SetColor( BLOOD_COLOR_RED ); - break; - } - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "amount")) - { - SetBloodAmount( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -Vector CBlood::Direction( void ) -{ - if ( pev->spawnflags & SF_BLOOD_RANDOM ) - return UTIL_RandomBloodVector(); - - return pev->movedir; -} - - -Vector CBlood::BloodPosition( CBaseEntity *pActivator ) -{ - if ( pev->spawnflags & SF_BLOOD_PLAYER ) - { - edict_t *pPlayer; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = pActivator->edict(); - } - else - pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - if ( pPlayer ) - return (pPlayer->v.origin + pPlayer->v.view_ofs) + Vector( RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10) ); - } - - return pev->origin; -} - - -void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_BLOOD_STREAM ) - UTIL_BloodStream( BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), BloodAmount() ); - else - UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); - - if ( pev->spawnflags & SF_BLOOD_DECAL ) - { - Vector forward = Direction(); - Vector start = BloodPosition( pActivator ); - TraceResult tr; - - UTIL_TraceLine( start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr ); - if ( tr.flFraction != 1.0 ) - UTIL_BloodDecalTrace( &tr, Color() ); - } -} - - - -// Screen shake -class CShake : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline float Amplitude( void ) { return pev->scale; } - inline float Frequency( void ) { return pev->dmg_save; } - inline float Duration( void ) { return pev->dmg_take; } - inline float Radius( void ) { return pev->dmg; } - - inline void SetAmplitude( float amplitude ) { pev->scale = amplitude; } - inline void SetFrequency( float frequency ) { pev->dmg_save = frequency; } - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetRadius( float radius ) { pev->dmg = radius; } -private: -}; - -LINK_ENTITY_TO_CLASS( env_shake, CShake ); - -// pev->scale is amplitude -// pev->dmg_save is frequency -// pev->dmg_take is duration -// pev->dmg is radius -// radius of 0 means all players -// NOTE: UTIL_ScreenShake() will only shake players who are on the ground - -#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius -// UNDONE: These don't work yet -#define SF_SHAKE_DISRUPT 0x0002 // Disrupt controls -#define SF_SHAKE_INAIR 0x0004 // Shake players in air - -void CShake::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - if ( pev->spawnflags & SF_SHAKE_EVERYONE ) - pev->dmg = 0; -} - - -void CShake::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "amplitude")) - { - SetAmplitude( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency")) - { - SetFrequency( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - SetRadius( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() ); -} - - -class CFade : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } -private: -}; - -LINK_ENTITY_TO_CLASS( env_fade, CFade ); - -// pev->dmg_take is duration -// pev->dmg_save is hold duration -#define SF_FADE_IN 0x0001 // Fade in, not out -#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend -#define SF_FADE_ONLYONE 0x0004 - -void CFade::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; -} - - -void CFade::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fadeFlags = 0; - - if ( !(pev->spawnflags & SF_FADE_IN) ) - fadeFlags |= FFADE_OUT; - - if ( pev->spawnflags & SF_FADE_MODULATE ) - fadeFlags |= FFADE_MODULATE; - - if ( pev->spawnflags & SF_FADE_ONLYONE ) - { - if ( pActivator->IsNetClient() ) - { - UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); - } - } - else - { - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - -class CMessage : public CPointEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); -private: -}; - -LINK_ENTITY_TO_CLASS( env_message, CMessage ); - - -void CMessage::Spawn( void ) -{ - Precache(); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - switch( pev->impulse ) - { - case 1: // Medium radius - pev->speed = ATTN_STATIC; - break; - - case 2: // Large radius - pev->speed = ATTN_NORM; - break; - - case 3: //EVERYWHERE - pev->speed = ATTN_NONE; - break; - - default: - case 0: // Small radius - pev->speed = ATTN_IDLE; - break; - } - pev->impulse = 0; - - // No volume, use normal - if ( pev->scale <= 0 ) - pev->scale = 1.0; -} - - -void CMessage::Precache( void ) -{ - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); -} - -void CMessage::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "messagesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagevolume")) - { - pev->scale = atof(pkvd->szValue) * 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messageattenuation")) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pPlayer = NULL; - - if ( pev->spawnflags & SF_MESSAGE_ALL ) - UTIL_ShowMessageAll( STRING(pev->message) ); - else - { - if ( pActivator && pActivator->IsPlayer() ) - pPlayer = pActivator; - else - { - pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - } - if ( pPlayer ) - UTIL_ShowMessage( STRING(pev->message), pPlayer ); - } - if ( pev->noise ) - { - EMIT_SOUND( edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed ); - } - if ( pev->spawnflags & SF_MESSAGE_ONCE ) - UTIL_Remove( this ); - - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - - -//========================================================= -// FunnelEffect -//========================================================= -class CEnvFunnel : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iSprite; // Don't save, precache -}; - -void CEnvFunnel :: Precache ( void ) -{ - m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); -} - -LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ); - -void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_LARGEFUNNEL ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( m_iSprite ); - - if ( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse? - { - WRITE_SHORT( 1 ); - } - else - { - WRITE_SHORT( 0 ); - } - - - MESSAGE_END(); - - SetThink( &CEnvFunnel::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -void CEnvFunnel::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; -} - -//========================================================= -// Beverage Dispenser -// overloaded pev->frags, is now a flag for whether or not a can is stuck in the dispenser. -// overloaded pev->health, is now how many cans remain in the machine. -//========================================================= -class CEnvBeverage : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -void CEnvBeverage :: Precache ( void ) -{ - PRECACHE_MODEL( "models/can.mdl" ); - PRECACHE_SOUND( "weapons/g_bounce3.wav" ); -} - -LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage ); - -void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->frags != 0 || pev->health <= 0 ) - { - // no more cans while one is waiting in the dispenser, or if I'm out of cans. - return; - } - - CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", pev->origin, pev->angles, edict() ); - - if ( pev->skin == 6 ) - { - // random - pCan->pev->skin = RANDOM_LONG( 0, 5 ); - } - else - { - pCan->pev->skin = pev->skin; - } - - pev->frags = 1; - pev->health--; - - //SetThink (SUB_Remove); - //pev->nextthink = gpGlobals->time; -} - -void CEnvBeverage::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - pev->frags = 0; - - if ( pev->health == 0 ) - { - pev->health = 10; - } -} - -//========================================================= -// Soda can -//========================================================= -class CItemSoda : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT CanThink ( void ); - void EXPORT CanTouch ( CBaseEntity *pOther ); -}; - -void CItemSoda :: Precache ( void ) -{ -} - -LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ); - -void CItemSoda::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - - SET_MODEL ( ENT(pev), "models/can.mdl" ); - UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) ); - - SetThink (&CItemSoda::CanThink); - pev->nextthink = gpGlobals->time + 0.5; -} - -void CItemSoda::CanThink ( void ) -{ - EMIT_SOUND (ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM ); - - pev->solid = SOLID_TRIGGER; - UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) ); - SetThink ( NULL ); - SetTouch ( &CItemSoda::CanTouch ); -} - -void CItemSoda::CanTouch ( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - { - return; - } - - // spoit sound here - - pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health. - - if ( !FNullEnt( pev->owner ) ) - { - // tell the machine the can was taken - pev->owner->v.frags = 0; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; - SetTouch ( NULL ); - SetThink ( &CItemSoda::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} diff --git a/main/source/dlls/effects.h b/main/source/dlls/effects.h index 99104234..3a8ab665 100644 --- a/main/source/dlls/effects.h +++ b/main/source/dlls/effects.h @@ -1,209 +1,209 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EFFECTS_H -#define EFFECTS_H - -#define SF_BEAM_STARTON 0x0001 -#define SF_BEAM_TOGGLE 0x0002 -#define SF_BEAM_RANDOM 0x0004 -#define SF_BEAM_RING 0x0008 -#define SF_BEAM_SPARKSTART 0x0010 -#define SF_BEAM_SPARKEND 0x0020 -#define SF_BEAM_DECALS 0x0040 -#define SF_BEAM_SHADEIN 0x0080 -#define SF_BEAM_SHADEOUT 0x0100 -#define SF_BEAM_TEMPORARY 0x8000 - -#define SF_SPRITE_STARTON 0x0001 -#define SF_SPRITE_ONCE 0x0002 -#define SF_SPRITE_TEMPORARY 0x8000 - -class CSprite : public CPointEntity -{ -public: - void Spawn( void ); - void Precache( void ); - - int ObjectCaps( void ) - { - int flags = 0; - if ( pev->spawnflags & SF_SPRITE_TEMPORARY ) - flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; - } - void EXPORT AnimateThink( void ); - void EXPORT ExpandThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Animate( float frames ); - void Expand( float scaleSpeed, float fadeSpeed ); - void SpriteInit( const char *pSpriteName, const Vector &origin ); - - inline void SetAttachment( edict_t *pEntity, int attachment ) - { - if ( pEntity ) - { - pev->skin = ENTINDEX(pEntity); - pev->body = attachment; - pev->aiment = pEntity; - pev->movetype = MOVETYPE_FOLLOW; - } - } - void TurnOff( void ); - void TurnOn( void ); - inline float Frames( void ) { return m_maxFrame; } - inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx ) - { - pev->rendermode = rendermode; - pev->rendercolor.x = r; - pev->rendercolor.y = g; - pev->rendercolor.z = b; - pev->renderamt = a; - pev->renderfx = fx; - } - inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } - inline void SetScale( float scale ) { pev->scale = scale; } - inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } - - inline void AnimateAndDie( float framerate ) - { - SetThink(&CSprite::AnimateUntilDead); - pev->framerate = framerate; - pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); - pev->nextthink = gpGlobals->time; - } - - void EXPORT AnimateUntilDead( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ); - -private: - - float m_lastTime; - float m_maxFrame; -}; - - -class CBeam : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - int ObjectCaps( void ) - { - int flags = 0; - if ( pev->spawnflags & SF_BEAM_TEMPORARY ) - flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; - } - - void EXPORT TriggerTouch( CBaseEntity *pOther ); - - // These functions are here to show the way beams are encoded as entities. - // Encoding beams as entities simplifies their management in the client/server architecture - inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); } - inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); } - inline void SetStartPos( const Vector& pos ) { pev->origin = pos; } - inline void SetEndPos( const Vector& pos ) { pev->angles = pos; } - void SetStartEntity( int entityIndex ); - void SetEndEntity( int entityIndex ); - - inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); } - inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); } - - inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } - inline void SetWidth( int width ) { pev->scale = width; } - inline void SetNoise( int amplitude ) { pev->body = amplitude; } - inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } - inline void SetFrame( float frame ) { pev->frame = frame; } - inline void SetScrollRate( int speed ) { pev->animtime = speed; } - - inline int GetType( void ) { return pev->rendermode & 0x0F; } - inline int GetFlags( void ) { return pev->rendermode & 0xF0; } - inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; } - inline int GetEndEntity( void ) { return pev->skin & 0xFFF; } - - const Vector &GetStartPos( void ); - const Vector &GetEndPos( void ); - - Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam - - inline int GetTexture( void ) { return pev->modelindex; } - inline int GetWidth( void ) { return pev->scale; } - inline int GetNoise( void ) { return pev->body; } - // inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline int GetBrightness( void ) { return pev->renderamt; } - inline int GetFrame( void ) { return pev->frame; } - inline int GetScrollRate( void ) { return pev->animtime; } - - // Call after you change start/end positions - void RelinkBeam( void ); -// void SetObjectCollisionBox( void ); - - void DoSparks( const Vector &start, const Vector &end ); - CBaseEntity *RandomTargetname( const char *szName ); - void BeamDamage( TraceResult *ptr ); - // Init after BeamCreate() - void BeamInit( const char *pSpriteName, int width ); - void PointsInit( const Vector &start, const Vector &end ); - void PointEntInit( const Vector &start, int endIndex ); - void EntsInit( int startIndex, int endIndex ); - void HoseInit( const Vector &start, const Vector &direction ); - - static CBeam *BeamCreate( const char *pSpriteName, int width ); - - inline void LiveForTime( float time ) { SetThink(&CBeam::SUB_Remove); pev->nextthink = gpGlobals->time + time; } - inline void BeamDamageInstant( TraceResult *ptr, float damage ) - { - pev->dmg = damage; - pev->dmgtime = gpGlobals->time - 1; - BeamDamage(ptr); - } -}; - - -#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out -#define SF_MESSAGE_ALL 0x0002 // Send to all clients - - -class CLaser : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - void TurnOn( void ); - void TurnOff( void ); - int IsOn( void ); - - void FireAtPoint( TraceResult &point ); - - void EXPORT StrikeThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CSprite *m_pSprite; - int m_iszSpriteName; - Vector m_firePosition; -}; - -#endif //EFFECTS_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EFFECTS_H +#define EFFECTS_H + +#define SF_BEAM_STARTON 0x0001 +#define SF_BEAM_TOGGLE 0x0002 +#define SF_BEAM_RANDOM 0x0004 +#define SF_BEAM_RING 0x0008 +#define SF_BEAM_SPARKSTART 0x0010 +#define SF_BEAM_SPARKEND 0x0020 +#define SF_BEAM_DECALS 0x0040 +#define SF_BEAM_SHADEIN 0x0080 +#define SF_BEAM_SHADEOUT 0x0100 +#define SF_BEAM_TEMPORARY 0x8000 + +#define SF_SPRITE_STARTON 0x0001 +#define SF_SPRITE_ONCE 0x0002 +#define SF_SPRITE_TEMPORARY 0x8000 + +class CSprite : public CPointEntity +{ +public: + void Spawn( void ); + void Precache( void ); + + int ObjectCaps( void ) + { + int flags = 0; + if ( pev->spawnflags & SF_SPRITE_TEMPORARY ) + flags = FCAP_DONT_SAVE; + return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + } + void EXPORT AnimateThink( void ); + void EXPORT ExpandThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Animate( float frames ); + void Expand( float scaleSpeed, float fadeSpeed ); + void SpriteInit( const char *pSpriteName, const Vector &origin ); + + inline void SetAttachment( edict_t *pEntity, int attachment ) + { + if ( pEntity ) + { + pev->skin = ENTINDEX(pEntity); + pev->body = attachment; + pev->aiment = pEntity; + pev->movetype = MOVETYPE_FOLLOW; + } + } + void TurnOff( void ); + void TurnOn( void ); + inline float Frames( void ) { return m_maxFrame; } + inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx ) + { + pev->rendermode = rendermode; + pev->rendercolor.x = r; + pev->rendercolor.y = g; + pev->rendercolor.z = b; + pev->renderamt = a; + pev->renderfx = fx; + } + inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } + inline void SetScale( float scale ) { pev->scale = scale; } + inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } + + inline void AnimateAndDie( float framerate ) + { + SetThink(&CSprite::AnimateUntilDead); + pev->framerate = framerate; + pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); + pev->nextthink = gpGlobals->time; + } + + void EXPORT AnimateUntilDead( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ); + +private: + + float m_lastTime; + float m_maxFrame; +}; + + +class CBeam : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + int ObjectCaps( void ) + { + int flags = 0; + if ( pev->spawnflags & SF_BEAM_TEMPORARY ) + flags = FCAP_DONT_SAVE; + return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + } + + void EXPORT TriggerTouch( CBaseEntity *pOther ); + + // These functions are here to show the way beams are encoded as entities. + // Encoding beams as entities simplifies their management in the client/server architecture + inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); } + inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); } + inline void SetStartPos( const Vector& pos ) { pev->origin = pos; } + inline void SetEndPos( const Vector& pos ) { pev->angles = pos; } + void SetStartEntity( int entityIndex ); + void SetEndEntity( int entityIndex ); + + inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); } + inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); } + + inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } + inline void SetWidth( int width ) { pev->scale = width; } + inline void SetNoise( int amplitude ) { pev->body = amplitude; } + inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } + inline void SetFrame( float frame ) { pev->frame = frame; } + inline void SetScrollRate( int speed ) { pev->animtime = speed; } + + inline int GetType( void ) { return pev->rendermode & 0x0F; } + inline int GetFlags( void ) { return pev->rendermode & 0xF0; } + inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; } + inline int GetEndEntity( void ) { return pev->skin & 0xFFF; } + + const Vector &GetStartPos( void ); + const Vector &GetEndPos( void ); + + Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam + + inline int GetTexture( void ) { return pev->modelindex; } + inline int GetWidth( void ) { return pev->scale; } + inline int GetNoise( void ) { return pev->body; } + // inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + inline int GetBrightness( void ) { return pev->renderamt; } + inline int GetFrame( void ) { return pev->frame; } + inline int GetScrollRate( void ) { return pev->animtime; } + + // Call after you change start/end positions + void RelinkBeam( void ); +// void SetObjectCollisionBox( void ); + + void DoSparks( const Vector &start, const Vector &end ); + CBaseEntity *RandomTargetname( const char *szName ); + void BeamDamage( TraceResult *ptr ); + // Init after BeamCreate() + void BeamInit( const char *pSpriteName, int width ); + void PointsInit( const Vector &start, const Vector &end ); + void PointEntInit( const Vector &start, int endIndex ); + void EntsInit( int startIndex, int endIndex ); + void HoseInit( const Vector &start, const Vector &direction ); + + static CBeam *BeamCreate( const char *pSpriteName, int width ); + + inline void LiveForTime( float time ) { SetThink(&CBeam::SUB_Remove); pev->nextthink = gpGlobals->time + time; } + inline void BeamDamageInstant( TraceResult *ptr, float damage ) + { + pev->dmg = damage; + pev->dmgtime = gpGlobals->time - 1; + BeamDamage(ptr); + } +}; + + +#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out +#define SF_MESSAGE_ALL 0x0002 // Send to all clients + + +class CLaser : public CBeam +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + + void TurnOn( void ); + void TurnOff( void ); + int IsOn( void ); + + void FireAtPoint( TraceResult &point ); + + void EXPORT StrikeThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + CSprite *m_pSprite; + int m_iszSpriteName; + Vector m_firePosition; +}; + +#endif //EFFECTS_H diff --git a/main/source/dlls/egon.cpp b/main/source/dlls/egon.cpp index 922e61e1..54c9c07d 100644 --- a/main/source/dlls/egon.cpp +++ b/main/source/dlls/egon.cpp @@ -1,562 +1,562 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" -#include "../engine/customentity.h" -#include "gamerules.h" -#include "../mod/AvHNetworkMessages.h" - -#define EGON_PRIMARY_VOLUME 450 -#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" -#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" -#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" - -#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes -#define EGON_SWITCH_WIDE_TIME 1.5 - -enum egon_e { - EGON_IDLE1 = 0, - EGON_FIDGET1, - EGON_ALTFIREON, - EGON_ALTFIRECYCLE, - EGON_ALTFIREOFF, - EGON_FIRE1, - EGON_FIRE2, - EGON_FIRE3, - EGON_FIRE4, - EGON_DRAW, - EGON_HOLSTER -}; - -LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); - -void CEgon::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_EGON; - SET_MODEL(ENT(pev), "models/w_egon.mdl"); - - m_iDefaultAmmo = EGON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CEgon::Precache( void ) -{ - PRECACHE_MODEL("models/w_egon.mdl"); - PRECACHE_MODEL("models/v_egon.mdl"); - PRECACHE_MODEL("models/p_egon.mdl"); - - PRECACHE_MODEL("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND( EGON_SOUND_OFF ); - PRECACHE_SOUND( EGON_SOUND_RUN ); - PRECACHE_SOUND( EGON_SOUND_STARTUP ); - - PRECACHE_MODEL( EGON_BEAM_SPRITE ); - PRECACHE_MODEL( EGON_FLARE_SPRITE ); - - PRECACHE_SOUND ("weapons/357_cock1.wav"); - - m_usEgonFire = PRECACHE_EVENT ( 1, "events/egon_fire.sc" ); - m_usEgonStop = PRECACHE_EVENT ( 1, "events/egon_stop.sc" ); -} - - -BOOL CEgon::Deploy( void ) -{ - m_deployed = FALSE; - m_fireState = FIRE_OFF; - return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" ); -} - -int CEgon::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pPlayer->pev, m_iId ); - return TRUE; - } - return FALSE; -} - - - -void CEgon::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( EGON_HOLSTER ); - - EndAttack(); -} - -int CEgon::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 2; - p->iId = m_iId = WEAPON_EGON; - p->iFlags = 0; - p->iWeight = EGON_WEIGHT; - - return 1; -} - -#define EGON_PULSE_INTERVAL 0.1 -#define EGON_DISCHARGE_INTERVAL 0.1 - -float CEgon::GetPulseInterval( void ) -{ - return EGON_PULSE_INTERVAL; -} - -float CEgon::GetDischargeInterval( void ) -{ - return EGON_DISCHARGE_INTERVAL; -} - -BOOL CEgon::HasAmmo( void ) -{ - if ( m_pPlayer->ammo_uranium <= 0 ) - return FALSE; - - return TRUE; -} - -void CEgon::UseAmmo( int count ) -{ - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; - else - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; -} - -void CEgon::Attack( void ) -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - - if ( m_fireState != FIRE_OFF || m_pBeam ) - { - EndAttack(); - } - else - { - PlayEmptySound( ); - } - return; - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); - - int flags = FEV_NOTHOST; - - switch( m_fireState ) - { - case FIRE_OFF: - { - if ( !HasAmmo() ) - { - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; - PlayEmptySound( ); - return; - } - - m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 ); - - m_shakeTime = 0; - - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - pev->fuser1 = UTIL_WeaponTimeBase() + 2; - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - m_fireState = FIRE_CHARGE; - } - break; - - case FIRE_CHARGE: - { - Fire( vecSrc, vecAiming ); - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - - if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) - { - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); - pev->fuser1 = 1000; - } - - if ( !HasAmmo() ) - { - EndAttack(); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - } - - } - break; - } -} - -void CEgon::PrimaryAttack( void ) -{ - m_fireMode = FIRE_WIDE; - Attack(); - -} - -void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) -{ - Vector vecDest = vecOrigSrc + vecDir * 2048; - edict_t *pentIgnore; - TraceResult tr; - - pentIgnore = m_pPlayer->edict(); - Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; - - // ALERT( at_console, "." ); - - UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - - if (tr.fAllSolid) - return; - -#ifndef CLIENT_DLL - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if (pEntity == NULL) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - if ( m_pSprite && pEntity->pev->takedamage ) - { - m_pSprite->pev->effects &= ~EF_NODRAW; - } - else if ( m_pSprite ) - { - m_pSprite->pev->effects |= EF_NODRAW; - } - } - - -#endif - - float timedist; - - switch ( m_fireMode ) - { - case FIRE_NARROW: -#ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) - { - // Narrow mode only does damage to the entity it hits - ClearMultiDamage(); - if (pEntity->pev->takedamage) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); - } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - - if ( g_pGameRules->IsMultiplayer() ) - { - // multiplayer uses 1 ammo every 1/10th second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - else - { - // single player, use 3 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.166; - } - } - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); - break; - - case FIRE_WIDE: -#ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) - { - // wide mode does damage to the ent, and radius damage - ClearMultiDamage(); - if (pEntity->pev->takedamage) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB); - } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - - if ( g_pGameRules->IsMultiplayer() ) - { - // radius damage a little more potent in multiplayer. - ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); - } - - if ( !m_pPlayer->IsAlive() ) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - //multiplayer uses 5 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.2; - } - } - else - { - // Wide mode uses 10 charges per second in single player - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - - pev->dmgtime = gpGlobals->time + GetDischargeInterval(); - if ( m_shakeTime < gpGlobals->time ) - { - UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); - m_shakeTime = gpGlobals->time + 1.5; - } - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); - break; - } - - if ( timedist < 0 ) - timedist = 0; - else if ( timedist > 1 ) - timedist = 1; - timedist = 1-timedist; - - UpdateEffect( tmpSrc, tr.vecEndPos, timedist ); -} - - -void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) -{ -#ifndef CLIENT_DLL - if ( !m_pBeam ) - { - CreateEffect(); - } - - m_pBeam->SetStartPos( endPoint ); - m_pBeam->SetBrightness( 255 - (timeBlend*180) ); - m_pBeam->SetWidth( 40 - (timeBlend*20) ); - - if ( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); - else - m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); - - - UTIL_SetOrigin( m_pSprite->pev, endPoint ); - m_pSprite->pev->frame += 8 * gpGlobals->frametime; - if ( m_pSprite->pev->frame > m_pSprite->Frames() ) - m_pSprite->pev->frame = 0; - - m_pNoise->SetStartPos( endPoint ); - -#endif - -} - -void CEgon::CreateEffect( void ) -{ - -#ifndef CLIENT_DLL - DestroyEffect(); - - m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); - m_pBeam->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pBeam->SetFlags( BEAM_FSINE ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition - m_pBeam->pev->flags |= FL_SKIPLOCALHOST; - m_pBeam->pev->owner = m_pPlayer->edict(); - - m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 ); - m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pNoise->SetScrollRate( 25 ); - m_pNoise->SetBrightness( 100 ); - m_pNoise->SetEndAttachment( 1 ); - m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY; - m_pNoise->pev->flags |= FL_SKIPLOCALHOST; - m_pNoise->pev->owner = m_pPlayer->edict(); - - m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE ); - m_pSprite->pev->scale = 1.0; - m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; - m_pSprite->pev->flags |= FL_SKIPLOCALHOST; - m_pSprite->pev->owner = m_pPlayer->edict(); - - if ( m_fireMode == FIRE_WIDE ) - { - m_pBeam->SetScrollRate( 50 ); - m_pBeam->SetNoise( 20 ); - m_pNoise->SetColor( 50, 50, 255 ); - m_pNoise->SetNoise( 8 ); - } - else - { - m_pBeam->SetScrollRate( 110 ); - m_pBeam->SetNoise( 5 ); - m_pNoise->SetColor( 80, 120, 255 ); - m_pNoise->SetNoise( 2 ); - } -#endif - -} - - -void CEgon::DestroyEffect( void ) -{ - -#ifndef CLIENT_DLL - if ( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - if ( m_pNoise ) - { - UTIL_Remove( m_pNoise ); - m_pNoise = NULL; - } - if ( m_pSprite ) - { - if ( m_fireMode == FIRE_WIDE ) - m_pSprite->Expand( 10, 500 ); - else - UTIL_Remove( m_pSprite ); - m_pSprite = NULL; - } -#endif - -} - - - -void CEgon::WeaponIdle( void ) -{ - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle > gpGlobals->time ) - return; - - if ( m_fireState != FIRE_OFF ) - EndAttack(); - - int iAnim; - - float flRand = RANDOM_FLOAT(0,1); - - if ( flRand <= 0.5 ) - { - iAnim = EGON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = EGON_FIDGET1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - SendWeaponAnim( iAnim ); - m_deployed = TRUE; -} - - - -void CEgon::EndAttack( void ) -{ - bool bMakeNoise = false; - - if ( m_fireState != FIRE_OFF ) //Checking the button just in case!. - bMakeNoise = true; - - PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 ); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - - m_fireState = FIRE_OFF; - - DestroyEffect(); -} - - - -class CEgonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_chainammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ); - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "effects.h" +#include "../engine/customentity.h" +#include "gamerules.h" +#include "../mod/AvHNetworkMessages.h" + +#define EGON_PRIMARY_VOLUME 450 +#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" +#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" +#define EGON_SOUND_OFF "weapons/egon_off1.wav" +#define EGON_SOUND_RUN "weapons/egon_run3.wav" +#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" + +#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes +#define EGON_SWITCH_WIDE_TIME 1.5 + +enum egon_e { + EGON_IDLE1 = 0, + EGON_FIDGET1, + EGON_ALTFIREON, + EGON_ALTFIRECYCLE, + EGON_ALTFIREOFF, + EGON_FIRE1, + EGON_FIRE2, + EGON_FIRE3, + EGON_FIRE4, + EGON_DRAW, + EGON_HOLSTER +}; + +LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); + +void CEgon::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_EGON; + SET_MODEL(ENT(pev), "models/w_egon.mdl"); + + m_iDefaultAmmo = EGON_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CEgon::Precache( void ) +{ + PRECACHE_MODEL("models/w_egon.mdl"); + PRECACHE_MODEL("models/v_egon.mdl"); + PRECACHE_MODEL("models/p_egon.mdl"); + + PRECACHE_MODEL("models/w_9mmclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + + PRECACHE_SOUND( EGON_SOUND_OFF ); + PRECACHE_SOUND( EGON_SOUND_RUN ); + PRECACHE_SOUND( EGON_SOUND_STARTUP ); + + PRECACHE_MODEL( EGON_BEAM_SPRITE ); + PRECACHE_MODEL( EGON_FLARE_SPRITE ); + + PRECACHE_SOUND ("weapons/357_cock1.wav"); + + m_usEgonFire = PRECACHE_EVENT ( 1, "events/egon_fire.sc" ); + m_usEgonStop = PRECACHE_EVENT ( 1, "events/egon_stop.sc" ); +} + + +BOOL CEgon::Deploy( void ) +{ + m_deployed = FALSE; + m_fireState = FIRE_OFF; + return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" ); +} + +int CEgon::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + NetMsg_WeapPickup( pPlayer->pev, m_iId ); + return TRUE; + } + return FALSE; +} + + + +void CEgon::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + SendWeaponAnim( EGON_HOLSTER ); + + EndAttack(); +} + +int CEgon::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "uranium"; + p->iMaxAmmo1 = URANIUM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 3; + p->iPosition = 2; + p->iId = m_iId = WEAPON_EGON; + p->iFlags = 0; + p->iWeight = EGON_WEIGHT; + + return 1; +} + +#define EGON_PULSE_INTERVAL 0.1 +#define EGON_DISCHARGE_INTERVAL 0.1 + +float CEgon::GetPulseInterval( void ) +{ + return EGON_PULSE_INTERVAL; +} + +float CEgon::GetDischargeInterval( void ) +{ + return EGON_DISCHARGE_INTERVAL; +} + +BOOL CEgon::HasAmmo( void ) +{ + if ( m_pPlayer->ammo_uranium <= 0 ) + return FALSE; + + return TRUE; +} + +void CEgon::UseAmmo( int count ) +{ + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; + else + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; +} + +void CEgon::Attack( void ) +{ + // don't fire underwater + if ( m_pPlayer->pev->waterlevel == 3 ) + { + + if ( m_fireState != FIRE_OFF || m_pBeam ) + { + EndAttack(); + } + else + { + PlayEmptySound( ); + } + return; + } + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + Vector vecAiming = gpGlobals->v_forward; + Vector vecSrc = m_pPlayer->GetGunPosition( ); + + int flags = FEV_NOTHOST; + + switch( m_fireState ) + { + case FIRE_OFF: + { + if ( !HasAmmo() ) + { + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; + PlayEmptySound( ); + return; + } + + m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 ); + + m_shakeTime = 0; + + m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; + pev->fuser1 = UTIL_WeaponTimeBase() + 2; + + pev->dmgtime = gpGlobals->time + GetPulseInterval(); + m_fireState = FIRE_CHARGE; + } + break; + + case FIRE_CHARGE: + { + Fire( vecSrc, vecAiming ); + m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; + + if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) + { + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); + pev->fuser1 = 1000; + } + + if ( !HasAmmo() ) + { + EndAttack(); + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; + } + + } + break; + } +} + +void CEgon::PrimaryAttack( void ) +{ + m_fireMode = FIRE_WIDE; + Attack(); + +} + +void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) +{ + Vector vecDest = vecOrigSrc + vecDir * 2048; + edict_t *pentIgnore; + TraceResult tr; + + pentIgnore = m_pPlayer->edict(); + Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; + + // ALERT( at_console, "." ); + + UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); + + if (tr.fAllSolid) + return; + +#ifndef CLIENT_DLL + CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + + if (pEntity == NULL) + return; + + if ( g_pGameRules->IsMultiplayer() ) + { + if ( m_pSprite && pEntity->pev->takedamage ) + { + m_pSprite->pev->effects &= ~EF_NODRAW; + } + else if ( m_pSprite ) + { + m_pSprite->pev->effects |= EF_NODRAW; + } + } + + +#endif + + float timedist; + + switch ( m_fireMode ) + { + case FIRE_NARROW: +#ifndef CLIENT_DLL + if ( pev->dmgtime < gpGlobals->time ) + { + // Narrow mode only does damage to the entity it hits + ClearMultiDamage(); + if (pEntity->pev->takedamage) + { + pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); + } + ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + + if ( g_pGameRules->IsMultiplayer() ) + { + // multiplayer uses 1 ammo every 1/10th second + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.1; + } + } + else + { + // single player, use 3 ammo/second + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.166; + } + } + + pev->dmgtime = gpGlobals->time + GetPulseInterval(); + } +#endif + timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); + break; + + case FIRE_WIDE: +#ifndef CLIENT_DLL + if ( pev->dmgtime < gpGlobals->time ) + { + // wide mode does damage to the ent, and radius damage + ClearMultiDamage(); + if (pEntity->pev->takedamage) + { + pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB); + } + ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + + if ( g_pGameRules->IsMultiplayer() ) + { + // radius damage a little more potent in multiplayer. + ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); + } + + if ( !m_pPlayer->IsAlive() ) + return; + + if ( g_pGameRules->IsMultiplayer() ) + { + //multiplayer uses 5 ammo/second + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.2; + } + } + else + { + // Wide mode uses 10 charges per second in single player + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.1; + } + } + + pev->dmgtime = gpGlobals->time + GetDischargeInterval(); + if ( m_shakeTime < gpGlobals->time ) + { + UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); + m_shakeTime = gpGlobals->time + 1.5; + } + } +#endif + timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); + break; + } + + if ( timedist < 0 ) + timedist = 0; + else if ( timedist > 1 ) + timedist = 1; + timedist = 1-timedist; + + UpdateEffect( tmpSrc, tr.vecEndPos, timedist ); +} + + +void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) +{ +#ifndef CLIENT_DLL + if ( !m_pBeam ) + { + CreateEffect(); + } + + m_pBeam->SetStartPos( endPoint ); + m_pBeam->SetBrightness( 255 - (timeBlend*180) ); + m_pBeam->SetWidth( 40 - (timeBlend*20) ); + + if ( m_fireMode == FIRE_WIDE ) + m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + else + m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + + + UTIL_SetOrigin( m_pSprite->pev, endPoint ); + m_pSprite->pev->frame += 8 * gpGlobals->frametime; + if ( m_pSprite->pev->frame > m_pSprite->Frames() ) + m_pSprite->pev->frame = 0; + + m_pNoise->SetStartPos( endPoint ); + +#endif + +} + +void CEgon::CreateEffect( void ) +{ + +#ifndef CLIENT_DLL + DestroyEffect(); + + m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); + m_pBeam->PointEntInit( pev->origin, m_pPlayer->entindex() ); + m_pBeam->SetFlags( BEAM_FSINE ); + m_pBeam->SetEndAttachment( 1 ); + m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition + m_pBeam->pev->flags |= FL_SKIPLOCALHOST; + m_pBeam->pev->owner = m_pPlayer->edict(); + + m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 ); + m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() ); + m_pNoise->SetScrollRate( 25 ); + m_pNoise->SetBrightness( 100 ); + m_pNoise->SetEndAttachment( 1 ); + m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY; + m_pNoise->pev->flags |= FL_SKIPLOCALHOST; + m_pNoise->pev->owner = m_pPlayer->edict(); + + m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE ); + m_pSprite->pev->scale = 1.0; + m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); + m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; + m_pSprite->pev->flags |= FL_SKIPLOCALHOST; + m_pSprite->pev->owner = m_pPlayer->edict(); + + if ( m_fireMode == FIRE_WIDE ) + { + m_pBeam->SetScrollRate( 50 ); + m_pBeam->SetNoise( 20 ); + m_pNoise->SetColor( 50, 50, 255 ); + m_pNoise->SetNoise( 8 ); + } + else + { + m_pBeam->SetScrollRate( 110 ); + m_pBeam->SetNoise( 5 ); + m_pNoise->SetColor( 80, 120, 255 ); + m_pNoise->SetNoise( 2 ); + } +#endif + +} + + +void CEgon::DestroyEffect( void ) +{ + +#ifndef CLIENT_DLL + if ( m_pBeam ) + { + UTIL_Remove( m_pBeam ); + m_pBeam = NULL; + } + if ( m_pNoise ) + { + UTIL_Remove( m_pNoise ); + m_pNoise = NULL; + } + if ( m_pSprite ) + { + if ( m_fireMode == FIRE_WIDE ) + m_pSprite->Expand( 10, 500 ); + else + UTIL_Remove( m_pSprite ); + m_pSprite = NULL; + } +#endif + +} + + + +void CEgon::WeaponIdle( void ) +{ + ResetEmptySound( ); + + if ( m_flTimeWeaponIdle > gpGlobals->time ) + return; + + if ( m_fireState != FIRE_OFF ) + EndAttack(); + + int iAnim; + + float flRand = RANDOM_FLOAT(0,1); + + if ( flRand <= 0.5 ) + { + iAnim = EGON_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } + else + { + iAnim = EGON_FIDGET1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; + } + + SendWeaponAnim( iAnim ); + m_deployed = TRUE; +} + + + +void CEgon::EndAttack( void ) +{ + bool bMakeNoise = false; + + if ( m_fireState != FIRE_OFF ) //Checking the button just in case!. + bMakeNoise = true; + + PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 ); + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + + m_fireState = FIRE_OFF; + + DestroyEffect(); +} + + + +class CEgonAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_chainammo.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ); + #endif \ No newline at end of file diff --git a/main/source/dlls/egon.cpp~ b/main/source/dlls/egon.cpp~ deleted file mode 100644 index f2f20dc1..00000000 --- a/main/source/dlls/egon.cpp~ +++ /dev/null @@ -1,562 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" -#include "../engine/customentity.h" -#include "gamerules.h" -#include "..mod/AvHNetworkMessages.h" - -#define EGON_PRIMARY_VOLUME 450 -#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" -#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" -#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" - -#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes -#define EGON_SWITCH_WIDE_TIME 1.5 - -enum egon_e { - EGON_IDLE1 = 0, - EGON_FIDGET1, - EGON_ALTFIREON, - EGON_ALTFIRECYCLE, - EGON_ALTFIREOFF, - EGON_FIRE1, - EGON_FIRE2, - EGON_FIRE3, - EGON_FIRE4, - EGON_DRAW, - EGON_HOLSTER -}; - -LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); - -void CEgon::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_EGON; - SET_MODEL(ENT(pev), "models/w_egon.mdl"); - - m_iDefaultAmmo = EGON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CEgon::Precache( void ) -{ - PRECACHE_MODEL("models/w_egon.mdl"); - PRECACHE_MODEL("models/v_egon.mdl"); - PRECACHE_MODEL("models/p_egon.mdl"); - - PRECACHE_MODEL("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND( EGON_SOUND_OFF ); - PRECACHE_SOUND( EGON_SOUND_RUN ); - PRECACHE_SOUND( EGON_SOUND_STARTUP ); - - PRECACHE_MODEL( EGON_BEAM_SPRITE ); - PRECACHE_MODEL( EGON_FLARE_SPRITE ); - - PRECACHE_SOUND ("weapons/357_cock1.wav"); - - m_usEgonFire = PRECACHE_EVENT ( 1, "events/egon_fire.sc" ); - m_usEgonStop = PRECACHE_EVENT ( 1, "events/egon_stop.sc" ); -} - - -BOOL CEgon::Deploy( void ) -{ - m_deployed = FALSE; - m_fireState = FIRE_OFF; - return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" ); -} - -int CEgon::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pPlayer->pev, m_iId ); - return TRUE; - } - return FALSE; -} - - - -void CEgon::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( EGON_HOLSTER ); - - EndAttack(); -} - -int CEgon::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 2; - p->iId = m_iId = WEAPON_EGON; - p->iFlags = 0; - p->iWeight = EGON_WEIGHT; - - return 1; -} - -#define EGON_PULSE_INTERVAL 0.1 -#define EGON_DISCHARGE_INTERVAL 0.1 - -float CEgon::GetPulseInterval( void ) -{ - return EGON_PULSE_INTERVAL; -} - -float CEgon::GetDischargeInterval( void ) -{ - return EGON_DISCHARGE_INTERVAL; -} - -BOOL CEgon::HasAmmo( void ) -{ - if ( m_pPlayer->ammo_uranium <= 0 ) - return FALSE; - - return TRUE; -} - -void CEgon::UseAmmo( int count ) -{ - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; - else - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; -} - -void CEgon::Attack( void ) -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - - if ( m_fireState != FIRE_OFF || m_pBeam ) - { - EndAttack(); - } - else - { - PlayEmptySound( ); - } - return; - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); - - int flags = FEV_NOTHOST; - - switch( m_fireState ) - { - case FIRE_OFF: - { - if ( !HasAmmo() ) - { - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; - PlayEmptySound( ); - return; - } - - m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 ); - - m_shakeTime = 0; - - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - pev->fuser1 = UTIL_WeaponTimeBase() + 2; - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - m_fireState = FIRE_CHARGE; - } - break; - - case FIRE_CHARGE: - { - Fire( vecSrc, vecAiming ); - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - - if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) - { - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); - pev->fuser1 = 1000; - } - - if ( !HasAmmo() ) - { - EndAttack(); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - } - - } - break; - } -} - -void CEgon::PrimaryAttack( void ) -{ - m_fireMode = FIRE_WIDE; - Attack(); - -} - -void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) -{ - Vector vecDest = vecOrigSrc + vecDir * 2048; - edict_t *pentIgnore; - TraceResult tr; - - pentIgnore = m_pPlayer->edict(); - Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; - - // ALERT( at_console, "." ); - - UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - - if (tr.fAllSolid) - return; - -#ifndef CLIENT_DLL - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if (pEntity == NULL) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - if ( m_pSprite && pEntity->pev->takedamage ) - { - m_pSprite->pev->effects &= ~EF_NODRAW; - } - else if ( m_pSprite ) - { - m_pSprite->pev->effects |= EF_NODRAW; - } - } - - -#endif - - float timedist; - - switch ( m_fireMode ) - { - case FIRE_NARROW: -#ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) - { - // Narrow mode only does damage to the entity it hits - ClearMultiDamage(); - if (pEntity->pev->takedamage) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); - } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - - if ( g_pGameRules->IsMultiplayer() ) - { - // multiplayer uses 1 ammo every 1/10th second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - else - { - // single player, use 3 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.166; - } - } - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); - break; - - case FIRE_WIDE: -#ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) - { - // wide mode does damage to the ent, and radius damage - ClearMultiDamage(); - if (pEntity->pev->takedamage) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB); - } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - - if ( g_pGameRules->IsMultiplayer() ) - { - // radius damage a little more potent in multiplayer. - ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); - } - - if ( !m_pPlayer->IsAlive() ) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - //multiplayer uses 5 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.2; - } - } - else - { - // Wide mode uses 10 charges per second in single player - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - - pev->dmgtime = gpGlobals->time + GetDischargeInterval(); - if ( m_shakeTime < gpGlobals->time ) - { - UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); - m_shakeTime = gpGlobals->time + 1.5; - } - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); - break; - } - - if ( timedist < 0 ) - timedist = 0; - else if ( timedist > 1 ) - timedist = 1; - timedist = 1-timedist; - - UpdateEffect( tmpSrc, tr.vecEndPos, timedist ); -} - - -void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) -{ -#ifndef CLIENT_DLL - if ( !m_pBeam ) - { - CreateEffect(); - } - - m_pBeam->SetStartPos( endPoint ); - m_pBeam->SetBrightness( 255 - (timeBlend*180) ); - m_pBeam->SetWidth( 40 - (timeBlend*20) ); - - if ( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); - else - m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); - - - UTIL_SetOrigin( m_pSprite->pev, endPoint ); - m_pSprite->pev->frame += 8 * gpGlobals->frametime; - if ( m_pSprite->pev->frame > m_pSprite->Frames() ) - m_pSprite->pev->frame = 0; - - m_pNoise->SetStartPos( endPoint ); - -#endif - -} - -void CEgon::CreateEffect( void ) -{ - -#ifndef CLIENT_DLL - DestroyEffect(); - - m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); - m_pBeam->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pBeam->SetFlags( BEAM_FSINE ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition - m_pBeam->pev->flags |= FL_SKIPLOCALHOST; - m_pBeam->pev->owner = m_pPlayer->edict(); - - m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 ); - m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pNoise->SetScrollRate( 25 ); - m_pNoise->SetBrightness( 100 ); - m_pNoise->SetEndAttachment( 1 ); - m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY; - m_pNoise->pev->flags |= FL_SKIPLOCALHOST; - m_pNoise->pev->owner = m_pPlayer->edict(); - - m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE ); - m_pSprite->pev->scale = 1.0; - m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; - m_pSprite->pev->flags |= FL_SKIPLOCALHOST; - m_pSprite->pev->owner = m_pPlayer->edict(); - - if ( m_fireMode == FIRE_WIDE ) - { - m_pBeam->SetScrollRate( 50 ); - m_pBeam->SetNoise( 20 ); - m_pNoise->SetColor( 50, 50, 255 ); - m_pNoise->SetNoise( 8 ); - } - else - { - m_pBeam->SetScrollRate( 110 ); - m_pBeam->SetNoise( 5 ); - m_pNoise->SetColor( 80, 120, 255 ); - m_pNoise->SetNoise( 2 ); - } -#endif - -} - - -void CEgon::DestroyEffect( void ) -{ - -#ifndef CLIENT_DLL - if ( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - if ( m_pNoise ) - { - UTIL_Remove( m_pNoise ); - m_pNoise = NULL; - } - if ( m_pSprite ) - { - if ( m_fireMode == FIRE_WIDE ) - m_pSprite->Expand( 10, 500 ); - else - UTIL_Remove( m_pSprite ); - m_pSprite = NULL; - } -#endif - -} - - - -void CEgon::WeaponIdle( void ) -{ - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle > gpGlobals->time ) - return; - - if ( m_fireState != FIRE_OFF ) - EndAttack(); - - int iAnim; - - float flRand = RANDOM_FLOAT(0,1); - - if ( flRand <= 0.5 ) - { - iAnim = EGON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = EGON_FIDGET1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - SendWeaponAnim( iAnim ); - m_deployed = TRUE; -} - - - -void CEgon::EndAttack( void ) -{ - bool bMakeNoise = false; - - if ( m_fireState != FIRE_OFF ) //Checking the button just in case!. - bMakeNoise = true; - - PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 ); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - - m_fireState = FIRE_OFF; - - DestroyEffect(); -} - - - -class CEgonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_chainammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ); - -#endif \ No newline at end of file diff --git a/main/source/dlls/enginecallback.h b/main/source/dlls/enginecallback.h index e9fb08a7..185843f2 100644 --- a/main/source/dlls/enginecallback.h +++ b/main/source/dlls/enginecallback.h @@ -1,202 +1,202 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ENGINECALLBACK_H -#define ENGINECALLBACK_H - -#pragma once - -#include "event_flags.h" - -// Must be provided by user of this code -extern enginefuncs_t g_engfuncs; - -// The actual engine callbacks -#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId) -#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel) -#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound) -#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric) -#define SET_MODEL (*g_engfuncs.pfnSetModel) -#define MODEL_INDEX (*g_engfuncs.pfnModelIndex) -#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames) -#define SET_SIZE (*g_engfuncs.pfnSetSize) -#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel) -#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms) -#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms) -#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw) -#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles) -#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin) -#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw) -#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch) -#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors) -#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity) -#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity) -#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity) -#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic) -#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor) -#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor) -#define WALK_MOVE (*g_engfuncs.pfnWalkMove) -#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin) -#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound) -#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg) -#define TRACE_LINE (*g_engfuncs.pfnTraceLine) -#define TRACE_TOSS (*g_engfuncs.pfnTraceToss) -#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull) -#define TRACE_HULL (*g_engfuncs.pfnTraceHull) -#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) -#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) -#ifdef SERVER_EXECUTE -#undef SERVER_EXECUTE -#endif -#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) - -#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) -#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) -#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) -#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex) -#define POINT_CONTENTS (*g_engfuncs.pfnPointContents) -#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init) -#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer) -#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte) -#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final) -#define RANDOM_LONG (*g_engfuncs.pfnRandomLong) -#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) -//#define AvHSUGetPlayerAuthIDString (*g_engfuncs.pfnGetPlayerAuthId) // 23.04.2014 added -// Note: Use AvHSUGetPlayerAuthIDString instead -//#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) -//#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerWONId) - - - -#ifdef AVH_SERVER -#define PRECACHE_UNMODIFIED_MODEL(s) \ -(*g_engfuncs.pfnPrecacheModel)(s); \ -ENGINE_FORCE_UNMODIFIED(force_exactfile, NULL, NULL, s); -#else -#define PRECACHE_UNMODIFIED_MODEL(s) \ -(*g_engfuncs.pfnPrecacheModel)(s); -#endif - -#ifdef AVH_SERVER -#define PRECACHE_UNMODIFIED_GENERIC(s) \ -(*g_engfuncs.pfnPrecacheGeneric)(s); \ -ENGINE_FORCE_UNMODIFIED(force_exactfile, NULL, NULL, s); -#else -#define PRECACHE_UNMODIFIED_GENERIC(s) \ -(*g_engfuncs.pfnPrecacheGeneric)(s); -#endif - -#ifdef AVH_SERVER -#define PRECACHE_UNMODIFIED_SOUND(s) \ -(*g_engfuncs.pfnPrecacheSound)(s); \ -ENGINE_FORCE_UNMODIFIED(force_exactfile, NULL, NULL, s); -#else -#define PRECACHE_UNMODIFIED_SOUND(s) \ -(*g_engfuncs.pfnPrecacheSound)(s); -#endif - -// Functions now defined in NetworkMeter.cpp -void MESSAGE_END(); -void WRITE_BYTE(int inData); -void WRITE_CHAR(int inData); -void WRITE_SHORT(int inData); -void WRITE_LONG(int inData); -void WRITE_ANGLE(float inData); -void WRITE_COORD(float inData); -void WRITE_STRING(const char* inData); - -#ifdef AVH_SERVER - -#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) -#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) -#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) -#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) -#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) -#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString) -#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) - -#endif // AVH_SERVER - -#define ALERT (*g_engfuncs.pfnAlertMessage) -#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf) -#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData) -inline void *GET_PRIVATE( edict_t *pent ) -{ - if ( pent ) - return pent->pvPrivateData; - return NULL; -} - -#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData) -//#define STRING (*g_engfuncs.pfnSzFromIndex) -#define ALLOC_STRING (*g_engfuncs.pfnAllocString) -#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString) -#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum) -#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere) -#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) -#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound) -#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr) - -//#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg) -int REG_USER_MSG(const char* inMessageName, int inMessageSize); - -#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition) -#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName) -#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction) -#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture) -#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf) -#define CMD_ARGS (*g_engfuncs.pfnCmd_Args) -#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc) -#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv) -#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment) -#define SET_VIEW (*g_engfuncs.pfnSetView) -#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle) -#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe) -#define FREE_FILE (*g_engfuncs.pfnFreeFile) -#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime) -#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir) -#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid) -#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) -#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) - -#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) -#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) - -#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) -#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) - -#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) - -#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField ) -#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField ) -#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder ) -#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer ) - -#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer ) - -#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField ) -#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex ) -#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex ) - -#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString ) - -#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask ) - -#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline ) - -#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified ) - -#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats ) - -#endif //ENGINECALLBACK_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ENGINECALLBACK_H +#define ENGINECALLBACK_H + +#pragma once + +#include "event_flags.h" + +// Must be provided by user of this code +extern enginefuncs_t g_engfuncs; + +// The actual engine callbacks +#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId) +#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel) +#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound) +#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric) +#define SET_MODEL (*g_engfuncs.pfnSetModel) +#define MODEL_INDEX (*g_engfuncs.pfnModelIndex) +#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames) +#define SET_SIZE (*g_engfuncs.pfnSetSize) +#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel) +#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms) +#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms) +#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw) +#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles) +#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin) +#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw) +#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch) +#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors) +#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity) +#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity) +#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity) +#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic) +#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor) +#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor) +#define WALK_MOVE (*g_engfuncs.pfnWalkMove) +#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin) +#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound) +#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg) +#define TRACE_LINE (*g_engfuncs.pfnTraceLine) +#define TRACE_TOSS (*g_engfuncs.pfnTraceToss) +#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull) +#define TRACE_HULL (*g_engfuncs.pfnTraceHull) +#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) +#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) +#ifdef SERVER_EXECUTE +#undef SERVER_EXECUTE +#endif +#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) + +#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) +#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) +#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) +#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex) +#define POINT_CONTENTS (*g_engfuncs.pfnPointContents) +#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init) +#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer) +#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte) +#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final) +#define RANDOM_LONG (*g_engfuncs.pfnRandomLong) +#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) +//#define AvHSUGetPlayerAuthIDString (*g_engfuncs.pfnGetPlayerAuthId) // 23.04.2014 added +// Note: Use AvHSUGetPlayerAuthIDString instead +//#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) +//#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerWONId) + + + +#ifdef AVH_SERVER +#define PRECACHE_UNMODIFIED_MODEL(s) \ +(*g_engfuncs.pfnPrecacheModel)(s); \ +ENGINE_FORCE_UNMODIFIED(force_exactfile, NULL, NULL, s); +#else +#define PRECACHE_UNMODIFIED_MODEL(s) \ +(*g_engfuncs.pfnPrecacheModel)(s); +#endif + +#ifdef AVH_SERVER +#define PRECACHE_UNMODIFIED_GENERIC(s) \ +(*g_engfuncs.pfnPrecacheGeneric)(s); \ +ENGINE_FORCE_UNMODIFIED(force_exactfile, NULL, NULL, s); +#else +#define PRECACHE_UNMODIFIED_GENERIC(s) \ +(*g_engfuncs.pfnPrecacheGeneric)(s); +#endif + +#ifdef AVH_SERVER +#define PRECACHE_UNMODIFIED_SOUND(s) \ +(*g_engfuncs.pfnPrecacheSound)(s); \ +ENGINE_FORCE_UNMODIFIED(force_exactfile, NULL, NULL, s); +#else +#define PRECACHE_UNMODIFIED_SOUND(s) \ +(*g_engfuncs.pfnPrecacheSound)(s); +#endif + +// Functions now defined in NetworkMeter.cpp +void MESSAGE_END(); +void WRITE_BYTE(int inData); +void WRITE_CHAR(int inData); +void WRITE_SHORT(int inData); +void WRITE_LONG(int inData); +void WRITE_ANGLE(float inData); +void WRITE_COORD(float inData); +void WRITE_STRING(const char* inData); + +#ifdef AVH_SERVER + +#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) +#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) +#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) +#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) +#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) +#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString) +#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) + +#endif // AVH_SERVER + +#define ALERT (*g_engfuncs.pfnAlertMessage) +#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf) +#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData) +inline void *GET_PRIVATE( edict_t *pent ) +{ + if ( pent ) + return pent->pvPrivateData; + return NULL; +} + +#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData) +//#define STRING (*g_engfuncs.pfnSzFromIndex) +#define ALLOC_STRING (*g_engfuncs.pfnAllocString) +#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString) +#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum) +#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere) +#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) +#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound) +#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr) + +//#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg) +int REG_USER_MSG(const char* inMessageName, int inMessageSize); + +#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition) +#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName) +#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction) +#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture) +#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf) +#define CMD_ARGS (*g_engfuncs.pfnCmd_Args) +#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc) +#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv) +#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment) +#define SET_VIEW (*g_engfuncs.pfnSetView) +#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle) +#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe) +#define FREE_FILE (*g_engfuncs.pfnFreeFile) +#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime) +#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir) +#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid) +#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) +#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) + +#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) +#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) + +#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) +#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) + +#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) + +#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField ) +#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField ) +#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder ) +#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer ) + +#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer ) + +#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField ) +#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex ) +#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex ) + +#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString ) + +#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask ) + +#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline ) + +#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified ) + +#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats ) + +#endif //ENGINECALLBACK_H diff --git a/main/source/dlls/explode.cpp b/main/source/dlls/explode.cpp index 402908f7..5f2e7723 100644 --- a/main/source/dlls/explode.cpp +++ b/main/source/dlls/explode.cpp @@ -1,277 +1,277 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== explode.cpp ======================================================== - - Explosion-related code - -*/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "decals.h" -#include "explode.h" - -// Spark Shower -class CShower : public CBaseEntity -{ - void Spawn( void ); - void Think( void ); - void Touch( CBaseEntity *pOther ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -LINK_ENTITY_TO_CLASS( spark_shower, CShower ); - -void CShower::Spawn( void ) -{ - pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles; - pev->velocity.x += RANDOM_FLOAT(-100.f,100.f); - pev->velocity.y += RANDOM_FLOAT(-100.f,100.f); - if ( pev->velocity.z >= 0 ) - pev->velocity.z += 200; - else - pev->velocity.z -= 200; - pev->movetype = MOVETYPE_BOUNCE; - pev->gravity = 0.5; - pev->nextthink = gpGlobals->time + 0.1; - pev->solid = SOLID_NOT; - SET_MODEL( edict(), "models/grenade.mdl"); // Need a model, just use the grenade, we don't draw it anyway - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->speed = RANDOM_FLOAT( 0.5, 1.5 ); - - pev->angles = g_vecZero; -} - - -void CShower::Think( void ) -{ - UTIL_Sparks( pev->origin ); - - pev->speed -= 0.1; - if ( pev->speed > 0 ) - pev->nextthink = gpGlobals->time + 0.1; - else - UTIL_Remove( this ); - pev->flags &= ~FL_ONGROUND; -} - -void CShower::Touch( CBaseEntity *pOther ) -{ - if ( pev->flags & FL_ONGROUND ) - pev->velocity = pev->velocity * 0.1; - else - pev->velocity = pev->velocity * 0.6; - - if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.0 ) - pev->speed = 0; -} - -class CEnvExplosion : public CBaseMonster -{ -public: - void Spawn( ); - void EXPORT Smoke ( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iMagnitude;// how large is the fireball? how much damage? - int m_spriteScale; // what's the exact fireball sprite scale? -}; - -TYPEDESCRIPTION CEnvExplosion::m_SaveData[] = -{ - DEFINE_FIELD( CEnvExplosion, m_iMagnitude, FIELD_INTEGER ), - DEFINE_FIELD( CEnvExplosion, m_spriteScale, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CEnvExplosion, CBaseMonster ); -LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ); - -void CEnvExplosion::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iMagnitude")) - { - m_iMagnitude = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -void CEnvExplosion::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - - pev->movetype = MOVETYPE_NONE; - /* - if ( m_iMagnitude > 250 ) - { - m_iMagnitude = 250; - } - */ - - float flSpriteScale; - flSpriteScale = ( m_iMagnitude - 50) * 0.6; - - /* - if ( flSpriteScale > 50 ) - { - flSpriteScale = 50; - } - */ - if ( flSpriteScale < 10 ) - { - flSpriteScale = 10; - } - - m_spriteScale = (int)flSpriteScale; -} - -void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - TraceResult tr; - - pev->model = iStringNull;//invisible - pev->solid = SOLID_NOT;// intangible - - Vector vecSpot;// trace starts here! - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); - - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); - - // Pull out of the wall a bit - if ( tr.flFraction != 1.0 ) - { - pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6); - } - else - { - pev->origin = pev->origin; - } - - // draw decal - if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL)) - { - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( &tr, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( &tr, DECAL_SCORCH2 ); - } - } - - // draw fireball - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) ) - { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - } - else - { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( 0 ); // no sprite - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - } - - // do damage - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) ) - { - RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); - } - - SetThink( &CEnvExplosion::Smoke ); - pev->nextthink = gpGlobals->time + 0.3; - - // draw sparks - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) ) - { - int sparkCount = RANDOM_LONG(0,3); - - for ( int i = 0; i < sparkCount; i++ ) - { - Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL ); - } - } -} - -void CEnvExplosion::Smoke( void ) -{ - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) ) - { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - - if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) ) - { - UTIL_Remove( this ); - } -} - - -// HACKHACK -- create one of these and fake a keyvalue to get the right explosion setup -void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage, int inExplosionTeam) -{ - KeyValueData kvd; - char buf[128]; - - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, angles, pOwner ); - CEnvExplosion* theExplosion = dynamic_cast(pExplosion); - ASSERT(theExplosion); - - pExplosion->pev->team = inExplosionTeam; - sprintf( buf, "%3d", magnitude ); - kvd.szKeyName = "iMagnitude"; - kvd.szValue = buf; - pExplosion->KeyValue( &kvd ); - if ( !doDamage ) - pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; - - pExplosion->Spawn(); - pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== explode.cpp ======================================================== + + Explosion-related code + +*/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "decals.h" +#include "explode.h" + +// Spark Shower +class CShower : public CBaseEntity +{ + void Spawn( void ); + void Think( void ); + void Touch( CBaseEntity *pOther ); + int ObjectCaps( void ) { return FCAP_DONT_SAVE; } +}; + +LINK_ENTITY_TO_CLASS( spark_shower, CShower ); + +void CShower::Spawn( void ) +{ + pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles; + pev->velocity.x += RANDOM_FLOAT(-100.f,100.f); + pev->velocity.y += RANDOM_FLOAT(-100.f,100.f); + if ( pev->velocity.z >= 0 ) + pev->velocity.z += 200; + else + pev->velocity.z -= 200; + pev->movetype = MOVETYPE_BOUNCE; + pev->gravity = 0.5; + pev->nextthink = gpGlobals->time + 0.1; + pev->solid = SOLID_NOT; + SET_MODEL( edict(), "models/grenade.mdl"); // Need a model, just use the grenade, we don't draw it anyway + UTIL_SetSize(pev, g_vecZero, g_vecZero ); + pev->effects |= EF_NODRAW; + pev->speed = RANDOM_FLOAT( 0.5, 1.5 ); + + pev->angles = g_vecZero; +} + + +void CShower::Think( void ) +{ + UTIL_Sparks( pev->origin ); + + pev->speed -= 0.1; + if ( pev->speed > 0 ) + pev->nextthink = gpGlobals->time + 0.1; + else + UTIL_Remove( this ); + pev->flags &= ~FL_ONGROUND; +} + +void CShower::Touch( CBaseEntity *pOther ) +{ + if ( pev->flags & FL_ONGROUND ) + pev->velocity = pev->velocity * 0.1; + else + pev->velocity = pev->velocity * 0.6; + + if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.0 ) + pev->speed = 0; +} + +class CEnvExplosion : public CBaseMonster +{ +public: + void Spawn( ); + void EXPORT Smoke ( void ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_iMagnitude;// how large is the fireball? how much damage? + int m_spriteScale; // what's the exact fireball sprite scale? +}; + +TYPEDESCRIPTION CEnvExplosion::m_SaveData[] = +{ + DEFINE_FIELD( CEnvExplosion, m_iMagnitude, FIELD_INTEGER ), + DEFINE_FIELD( CEnvExplosion, m_spriteScale, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CEnvExplosion, CBaseMonster ); +LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ); + +void CEnvExplosion::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "iMagnitude")) + { + m_iMagnitude = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +void CEnvExplosion::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->effects = EF_NODRAW; + + pev->movetype = MOVETYPE_NONE; + /* + if ( m_iMagnitude > 250 ) + { + m_iMagnitude = 250; + } + */ + + float flSpriteScale; + flSpriteScale = ( m_iMagnitude - 50) * 0.6; + + /* + if ( flSpriteScale > 50 ) + { + flSpriteScale = 50; + } + */ + if ( flSpriteScale < 10 ) + { + flSpriteScale = 10; + } + + m_spriteScale = (int)flSpriteScale; +} + +void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + TraceResult tr; + + pev->model = iStringNull;//invisible + pev->solid = SOLID_NOT;// intangible + + Vector vecSpot;// trace starts here! + + vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); + + UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); + + // Pull out of the wall a bit + if ( tr.flFraction != 1.0 ) + { + pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6); + } + else + { + pev->origin = pev->origin; + } + + // draw decal + if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL)) + { + if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) + { + UTIL_DecalTrace( &tr, DECAL_SCORCH1 ); + } + else + { + UTIL_DecalTrace( &tr, DECAL_SCORCH2 ); + } + } + + // draw fireball + if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) ) + { + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_EXPLOSION); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_SHORT( g_sModelIndexFireball ); + WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 + WRITE_BYTE( 15 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + } + else + { + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_EXPLOSION); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_SHORT( g_sModelIndexFireball ); + WRITE_BYTE( 0 ); // no sprite + WRITE_BYTE( 15 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + } + + // do damage + if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) ) + { + RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); + } + + SetThink( &CEnvExplosion::Smoke ); + pev->nextthink = gpGlobals->time + 0.3; + + // draw sparks + if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) ) + { + int sparkCount = RANDOM_LONG(0,3); + + for ( int i = 0; i < sparkCount; i++ ) + { + Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL ); + } + } +} + +void CEnvExplosion::Smoke( void ) +{ + if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) ) + { + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + MESSAGE_END(); + } + + if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) ) + { + UTIL_Remove( this ); + } +} + + +// HACKHACK -- create one of these and fake a keyvalue to get the right explosion setup +void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage, int inExplosionTeam) +{ + KeyValueData kvd; + char buf[128]; + + CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, angles, pOwner ); + CEnvExplosion* theExplosion = dynamic_cast(pExplosion); + ASSERT(theExplosion); + + pExplosion->pev->team = inExplosionTeam; + sprintf( buf, "%3d", magnitude ); + kvd.szKeyName = "iMagnitude"; + kvd.szValue = buf; + pExplosion->KeyValue( &kvd ); + if ( !doDamage ) + pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; + + pExplosion->Spawn(); + pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 ); +} diff --git a/main/source/dlls/explode.h b/main/source/dlls/explode.h index 598401ba..5a1a564f 100644 --- a/main/source/dlls/explode.h +++ b/main/source/dlls/explode.h @@ -1,32 +1,32 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EXPLODE_H -#define EXPLODE_H - - -#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage -#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired? -#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball -#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke -#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark -#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark - -extern DLL_GLOBAL short g_sModelIndexFireball; -extern DLL_GLOBAL short g_sModelIndexSmoke; - - -extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage, int inExplosionTeam = 0); - -#endif //EXPLODE_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EXPLODE_H +#define EXPLODE_H + + +#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage +#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired? +#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball +#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke +#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark +#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark + +extern DLL_GLOBAL short g_sModelIndexFireball; +extern DLL_GLOBAL short g_sModelIndexSmoke; + + +extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage, int inExplosionTeam = 0); + +#endif //EXPLODE_H diff --git a/main/source/dlls/extdll.h b/main/source/dlls/extdll.h index 32a349b7..956377d4 100644 --- a/main/source/dlls/extdll.h +++ b/main/source/dlls/extdll.h @@ -1,94 +1,94 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EXTDLL_H -#define EXTDLL_H - - -// -// Global header file for extension DLLs -// - -// Allow "DEBUG" in addition to default "_DEBUG" -#ifdef _DEBUG -#define DEBUG 1 -#endif - -// Silence certain warnings -#pragma warning(disable : 4244) // int or float down-conversion -#pragma warning(disable : 4305) // int or float data truncation -#pragma warning(disable : 4201) // nameless struct/union -#pragma warning(disable : 4514) // unreferenced inline function removed -#pragma warning(disable : 4100) // unreferenced formal parameter - -#include "../public/archtypes.h" // DAL - -// Prevent tons of unused windows definitions -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOWINRES -#define NOSERVICE -#define NOMCX -#define NOIME -#include "../common/winsani_in.h" -#include "windows.h" -#include "../common/winsani_out.h" -#else // _WIN32 -#define FALSE 0 -#define TRUE (!FALSE) -typedef uint32 ULONG; -typedef unsigned char BYTE; -typedef int BOOL; -#define MAX_PATH PATH_MAX -#include -#include -#include // memset - -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) - -#endif //_WIN32 - -// Misc C-runtime library headers -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -// Header file containing definition of globalvars_t and entvars_t -typedef unsigned int func_t; // -typedef unsigned int string_t; // from engine's pr_comp.h; -typedef float vec_t; // needed before including progdefs.h - -// Vector class -#include "vector.h" - -// Defining it as a (bogus) struct helps enforce type-checking -#ifndef THEVECTOR3T -#define THEVECTOR3T -#define vec3_t Vector -#endif - -// Shared engine/DLL constants -#include "../common/const.h" -#include "../engine/progdefs.h" -#include "../engine/edict.h" - -// Shared header describing protocol between engine and DLLs -#include "../engine/eiface.h" - -// Shared header between the client DLL and the game DLLs -#include "cdll_dll.h" - -#endif //EXTDLL_H +/*** +* +* Copyright (c) 1996-2001, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EXTDLL_H +#define EXTDLL_H + + +// +// Global header file for extension DLLs +// + +// Allow "DEBUG" in addition to default "_DEBUG" +#ifdef _DEBUG +#define DEBUG 1 +#endif + +// Silence certain warnings +#pragma warning(disable : 4244) // int or float down-conversion +#pragma warning(disable : 4305) // int or float data truncation +#pragma warning(disable : 4201) // nameless struct/union +#pragma warning(disable : 4514) // unreferenced inline function removed +#pragma warning(disable : 4100) // unreferenced formal parameter + +#include "../public/archtypes.h" // DAL + +// Prevent tons of unused windows definitions +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOWINRES +#define NOSERVICE +#define NOMCX +#define NOIME +#include "../common/winsani_in.h" +#include "windows.h" +#include "../common/winsani_out.h" +#else // _WIN32 +#define FALSE 0 +#define TRUE (!FALSE) +typedef uint32 ULONG; +typedef unsigned char BYTE; +typedef int BOOL; +#define MAX_PATH PATH_MAX +#include +#include +#include // memset + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) + +#endif //_WIN32 + +// Misc C-runtime library headers +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +// Header file containing definition of globalvars_t and entvars_t +typedef unsigned int func_t; // +typedef unsigned int string_t; // from engine's pr_comp.h; +typedef float vec_t; // needed before including progdefs.h + +// Vector class +#include "vector.h" + +// Defining it as a (bogus) struct helps enforce type-checking +#ifndef THEVECTOR3T +#define THEVECTOR3T +#define vec3_t Vector +#endif + +// Shared engine/DLL constants +#include "../common/const.h" +#include "../engine/progdefs.h" +#include "../engine/edict.h" + +// Shared header describing protocol between engine and DLLs +#include "../engine/eiface.h" + +// Shared header between the client DLL and the game DLLs +#include "cdll_dll.h" + +#endif //EXTDLL_H diff --git a/main/source/dlls/extdll.h~ b/main/source/dlls/extdll.h~ deleted file mode 100644 index 393664b3..00000000 --- a/main/source/dlls/extdll.h~ +++ /dev/null @@ -1,96 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EXTDLL_H -#define EXTDLL_H - - -// -// Global header file for extension DLLs -// - -// Allow "DEBUG" in addition to default "_DEBUG" -#ifdef _DEBUG -#define DEBUG 1 -#endif - -// Silence certain warnings -#pragma warning(disable : 4244) // int or float down-conversion -#pragma warning(disable : 4305) // int or float data truncation -#pragma warning(disable : 4201) // nameless struct/union -#pragma warning(disable : 4514) // unreferenced inline function removed -#pragma warning(disable : 4100) // unreferenced formal parameter - -#include "../public/archtypes.h" // DAL - -// Prevent tons of unused windows definitions -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOWINRES -#define NOSERVICE -#define NOMCX -#define NOIME -#include "../common/winsani_in.h" -#include "windows.h" -#include "../common/winsani_out.h" -#else // _WIN32 -#define FALSE 0 -#define TRUE (!FALSE) -typedef uint32 ULONG; -typedef unsigned char BYTE; -typedef int BOOL; -#define MAX_PATH PATH_MAX -#include -#include -#include // memset -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) -#endif -#endif //_WIN32 - -// Misc C-runtime library headers -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -// Header file containing definition of globalvars_t and entvars_t -typedef unsigned int func_t; // -typedef unsigned int string_t; // from engine's pr_comp.h; -typedef float vec_t; // needed before including progdefs.h - -// Vector class -#include "vector.h" - -// Defining it as a (bogus) struct helps enforce type-checking -#ifndef THEVECTOR3T -#define THEVECTOR3T -#define vec3_t Vector -#endif - -// Shared engine/DLL constants -#include "const.h" -#include "progdefs.h" -#include "edict.h" - -// Shared header describing protocol between engine and DLLs -#include "eiface.h" - -// Shared header between the client DLL and the game DLLs -#include "cdll_dll.h" - -#endif //EXTDLL_H diff --git a/main/source/dlls/flyingmonster.cpp b/main/source/dlls/flyingmonster.cpp index 892418ee..89692c9f 100644 --- a/main/source/dlls/flyingmonster.cpp +++ b/main/source/dlls/flyingmonster.cpp @@ -1,281 +1,281 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "flyingmonster.h" - -#define FLYING_AE_FLAP (8) -#define FLYING_AE_FLAPSOUND (9) - - -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; - -int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - // UNDONE: need to check more than the endpoint - if (FBitSet(pev->flags, FL_SWIM) && (UTIL_PointContents(vecEnd) != CONTENTS_WATER)) - { - // ALERT(at_aiconsole, "can't swim out of water\n"); - return FALSE; - } - - TraceResult tr; - - UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr ); - - // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); - // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); - - if (pflDist) - { - *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. - } - - // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); - if (tr.fStartSolid || tr.flFraction < 1.0) - { - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - return LOCALMOVE_VALID; - return LOCALMOVE_INVALID; - } - - return LOCALMOVE_VALID; -} - - -BOOL CFlyingMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) -{ - return CBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex ); -} - - -Activity CFlyingMonster :: GetStoppedActivity( void ) -{ - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - - return ACT_HOVER; -} - - -void CFlyingMonster :: Stop( void ) -{ - Activity stopped = GetStoppedActivity(); - if ( m_IdealActivity != stopped ) - { - m_flightSpeed = 0; - m_IdealActivity = stopped; - } - pev->angles.z = 0; - pev->angles.x = 0; - m_vecTravel = g_vecZero; -} - - -float CFlyingMonster :: ChangeYaw( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if ( m_IdealActivity != GetStoppedActivity() ) - { - if ( diff < -20 ) - target = 90; - else if ( diff > 20 ) - target = -90; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime ); - } - return CBaseMonster::ChangeYaw( speed ); -} - - -void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_STEP; - ClearBits( pev->flags, FL_ONGROUND ); - pev->angles.z = 0; - pev->angles.x = 0; - CBaseMonster::Killed( pevAttacker, iGib ); -} - - -void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case FLYING_AE_FLAP: - m_flightSpeed = 400; - break; - - case FLYING_AE_FLAPSOUND: - if ( m_pFlapSound ) - EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM ); - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - - -void CFlyingMonster :: Move( float flInterval ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - m_flGroundSpeed = m_flightSpeed; - CBaseMonster::Move( flInterval ); -} - - -BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) -{ - // Get true 3D distance to the goal so we actually reach the correct height - if ( m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL ) - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); - - if ( flWaypointDist <= 64 + (m_flGroundSpeed * gpGlobals->frametime) ) - return TRUE; - - return FALSE; -} - - -void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - if ( gpGlobals->time - m_stopTime > 1.0 ) - { - if ( m_IdealActivity != m_movementActivity ) - { - m_IdealActivity = m_movementActivity; - m_flGroundSpeed = m_flightSpeed = 200; - } - } - Vector vecMove = pev->origin + (( vecDir + (m_vecTravel * m_momentum) ).Normalize() * (m_flGroundSpeed * flInterval)); - - if ( m_IdealActivity != m_movementActivity ) - { - m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime ); - if ( m_flightSpeed < 100 ) - m_stopTime = gpGlobals->time; - } - else - m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime ); - - if ( CheckLocalMove ( pev->origin, vecMove, pTargetEnt, NULL ) ) - { - m_vecTravel = (vecMove - pev->origin); - m_vecTravel = m_vecTravel.Normalize(); - UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE); - } - else - { - m_IdealActivity = GetStoppedActivity(); - m_stopTime = gpGlobals->time; - m_vecTravel = g_vecZero; - } - } - else - CBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval ); -} - - -float CFlyingMonster::CeilingZ( const Vector &position ) -{ - TraceResult tr; - - Vector minUp = position; - Vector maxUp = position; - maxUp.z += 4096.0; - - UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr); - if (tr.flFraction != 1.0) - maxUp.z = tr.vecEndPos.z; - - if ((pev->flags) & FL_SWIM) - { - return UTIL_WaterLevel( position, minUp.z, maxUp.z ); - } - return maxUp.z; -} - -BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction) -{ - int conPosition = UTIL_PointContents(position); - if ( (((pev->flags) & FL_SWIM) == FL_SWIM) ^ (conPosition == CONTENTS_WATER)) - { - // SWIMING & !WATER - // or FLYING & WATER - // - *pFraction = 0.0; - return TRUE; // We hit a water boundary because we are where we don't belong. - } - int conProbe = UTIL_PointContents(probe); - if (conProbe == conPosition) - { - // The probe is either entirely inside the water (for fish) or entirely - // outside the water (for birds). - // - *pFraction = 1.0; - return FALSE; - } - - Vector ProbeUnit = (probe-position).Normalize(); - float ProbeLength = (probe-position).Length(); - float maxProbeLength = ProbeLength; - float minProbeLength = 0; - - float diff = maxProbeLength - minProbeLength; - while (diff > 1.0) - { - float midProbeLength = minProbeLength + diff/2.0; - Vector midProbeVec = midProbeLength * ProbeUnit; - if (UTIL_PointContents(position+midProbeVec) == conPosition) - { - minProbeLength = midProbeLength; - } - else - { - maxProbeLength = midProbeLength; - } - diff = maxProbeLength - minProbeLength; - } - *pFraction = minProbeLength/ProbeLength; - - return TRUE; -} - -float CFlyingMonster::FloorZ( const Vector &position ) -{ - TraceResult tr; - - Vector down = position; - down.z -= 2048; - - UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr ); - - if ( tr.flFraction != 1.0 ) - return tr.vecEndPos.z; - - return down.z; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "flyingmonster.h" + +#define FLYING_AE_FLAP (8) +#define FLYING_AE_FLAPSOUND (9) + + +extern DLL_GLOBAL edict_t *g_pBodyQueueHead; + +int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) +{ + // UNDONE: need to check more than the endpoint + if (FBitSet(pev->flags, FL_SWIM) && (UTIL_PointContents(vecEnd) != CONTENTS_WATER)) + { + // ALERT(at_aiconsole, "can't swim out of water\n"); + return FALSE; + } + + TraceResult tr; + + UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr ); + + // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); + // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); + + if (pflDist) + { + *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. + } + + // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); + if (tr.fStartSolid || tr.flFraction < 1.0) + { + if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) + return LOCALMOVE_VALID; + return LOCALMOVE_INVALID; + } + + return LOCALMOVE_VALID; +} + + +BOOL CFlyingMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) +{ + return CBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex ); +} + + +Activity CFlyingMonster :: GetStoppedActivity( void ) +{ + if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else + return ACT_IDLE; + + return ACT_HOVER; +} + + +void CFlyingMonster :: Stop( void ) +{ + Activity stopped = GetStoppedActivity(); + if ( m_IdealActivity != stopped ) + { + m_flightSpeed = 0; + m_IdealActivity = stopped; + } + pev->angles.z = 0; + pev->angles.x = 0; + m_vecTravel = g_vecZero; +} + + +float CFlyingMonster :: ChangeYaw( int speed ) +{ + if ( pev->movetype == MOVETYPE_FLY ) + { + float diff = FlYawDiff(); + float target = 0; + + if ( m_IdealActivity != GetStoppedActivity() ) + { + if ( diff < -20 ) + target = 90; + else if ( diff > 20 ) + target = -90; + } + pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime ); + } + return CBaseMonster::ChangeYaw( speed ); +} + + +void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->movetype = MOVETYPE_STEP; + ClearBits( pev->flags, FL_ONGROUND ); + pev->angles.z = 0; + pev->angles.x = 0; + CBaseMonster::Killed( pevAttacker, iGib ); +} + + +void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case FLYING_AE_FLAP: + m_flightSpeed = 400; + break; + + case FLYING_AE_FLAPSOUND: + if ( m_pFlapSound ) + EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM ); + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + + +void CFlyingMonster :: Move( float flInterval ) +{ + if ( pev->movetype == MOVETYPE_FLY ) + m_flGroundSpeed = m_flightSpeed; + CBaseMonster::Move( flInterval ); +} + + +BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) +{ + // Get true 3D distance to the goal so we actually reach the correct height + if ( m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL ) + flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); + + if ( flWaypointDist <= 64 + (m_flGroundSpeed * gpGlobals->frametime) ) + return TRUE; + + return FALSE; +} + + +void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) +{ + if ( pev->movetype == MOVETYPE_FLY ) + { + if ( gpGlobals->time - m_stopTime > 1.0 ) + { + if ( m_IdealActivity != m_movementActivity ) + { + m_IdealActivity = m_movementActivity; + m_flGroundSpeed = m_flightSpeed = 200; + } + } + Vector vecMove = pev->origin + (( vecDir + (m_vecTravel * m_momentum) ).Normalize() * (m_flGroundSpeed * flInterval)); + + if ( m_IdealActivity != m_movementActivity ) + { + m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime ); + if ( m_flightSpeed < 100 ) + m_stopTime = gpGlobals->time; + } + else + m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime ); + + if ( CheckLocalMove ( pev->origin, vecMove, pTargetEnt, NULL ) ) + { + m_vecTravel = (vecMove - pev->origin); + m_vecTravel = m_vecTravel.Normalize(); + UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE); + } + else + { + m_IdealActivity = GetStoppedActivity(); + m_stopTime = gpGlobals->time; + m_vecTravel = g_vecZero; + } + } + else + CBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval ); +} + + +float CFlyingMonster::CeilingZ( const Vector &position ) +{ + TraceResult tr; + + Vector minUp = position; + Vector maxUp = position; + maxUp.z += 4096.0; + + UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr); + if (tr.flFraction != 1.0) + maxUp.z = tr.vecEndPos.z; + + if ((pev->flags) & FL_SWIM) + { + return UTIL_WaterLevel( position, minUp.z, maxUp.z ); + } + return maxUp.z; +} + +BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction) +{ + int conPosition = UTIL_PointContents(position); + if ( (((pev->flags) & FL_SWIM) == FL_SWIM) ^ (conPosition == CONTENTS_WATER)) + { + // SWIMING & !WATER + // or FLYING & WATER + // + *pFraction = 0.0; + return TRUE; // We hit a water boundary because we are where we don't belong. + } + int conProbe = UTIL_PointContents(probe); + if (conProbe == conPosition) + { + // The probe is either entirely inside the water (for fish) or entirely + // outside the water (for birds). + // + *pFraction = 1.0; + return FALSE; + } + + Vector ProbeUnit = (probe-position).Normalize(); + float ProbeLength = (probe-position).Length(); + float maxProbeLength = ProbeLength; + float minProbeLength = 0; + + float diff = maxProbeLength - minProbeLength; + while (diff > 1.0) + { + float midProbeLength = minProbeLength + diff/2.0; + Vector midProbeVec = midProbeLength * ProbeUnit; + if (UTIL_PointContents(position+midProbeVec) == conPosition) + { + minProbeLength = midProbeLength; + } + else + { + maxProbeLength = midProbeLength; + } + diff = maxProbeLength - minProbeLength; + } + *pFraction = minProbeLength/ProbeLength; + + return TRUE; +} + +float CFlyingMonster::FloorZ( const Vector &position ) +{ + TraceResult tr; + + Vector down = position; + down.z -= 2048; + + UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr ); + + if ( tr.flFraction != 1.0 ) + return tr.vecEndPos.z; + + return down.z; +} + diff --git a/main/source/dlls/flyingmonster.h b/main/source/dlls/flyingmonster.h index 7c1f12e9..a24f55e1 100644 --- a/main/source/dlls/flyingmonster.h +++ b/main/source/dlls/flyingmonster.h @@ -1,53 +1,53 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -// Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster - -#ifndef FLYINGMONSTER_H -#define FLYINGMONSTER_H - -class CFlyingMonster : public CBaseMonster -{ -public: - int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space - BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); - Activity GetStoppedActivity( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - void Stop( void ); - float ChangeYaw( int speed ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void Move( float flInterval = 0.1 ); - BOOL ShouldAdvanceRoute( float flWaypointDist ); - - inline void SetFlyingMomentum( float momentum ) { m_momentum = momentum; } - inline void SetFlyingFlapSound( const char *pFlapSound ) { m_pFlapSound = pFlapSound; } - inline void SetFlyingSpeed( float speed ) { m_flightSpeed = speed; } - float CeilingZ( const Vector &position ); - float FloorZ( const Vector &position ); - BOOL ProbeZ( const Vector &position, const Vector &probe, float *pFraction ); - - - // UNDONE: Save/restore this stuff!!! -protected: - Vector m_vecTravel; // Current direction - float m_flightSpeed; // Current flight speed (decays when not flapping or gliding) - float m_stopTime; // Last time we stopped (to avoid switching states too soon) - float m_momentum; // Weight for desired vs. momentum velocity - const char *m_pFlapSound; -}; - - -#endif //FLYINGMONSTER_H - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +// Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster + +#ifndef FLYINGMONSTER_H +#define FLYINGMONSTER_H + +class CFlyingMonster : public CBaseMonster +{ +public: + int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space + BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); + Activity GetStoppedActivity( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + void Stop( void ); + float ChangeYaw( int speed ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); + void Move( float flInterval = 0.1 ); + BOOL ShouldAdvanceRoute( float flWaypointDist ); + + inline void SetFlyingMomentum( float momentum ) { m_momentum = momentum; } + inline void SetFlyingFlapSound( const char *pFlapSound ) { m_pFlapSound = pFlapSound; } + inline void SetFlyingSpeed( float speed ) { m_flightSpeed = speed; } + float CeilingZ( const Vector &position ); + float FloorZ( const Vector &position ); + BOOL ProbeZ( const Vector &position, const Vector &probe, float *pFraction ); + + + // UNDONE: Save/restore this stuff!!! +protected: + Vector m_vecTravel; // Current direction + float m_flightSpeed; // Current flight speed (decays when not flapping or gliding) + float m_stopTime; // Last time we stopped (to avoid switching states too soon) + float m_momentum; // Weight for desired vs. momentum velocity + const char *m_pFlapSound; +}; + + +#endif //FLYINGMONSTER_H + diff --git a/main/source/dlls/func_break.cpp b/main/source/dlls/func_break.cpp index 92ea3dfb..65205a23 100644 --- a/main/source/dlls/func_break.cpp +++ b/main/source/dlls/func_break.cpp @@ -1,1054 +1,1054 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== bmodels.cpp ======================================================== - - spawn, think, and use functions for entities that use brush models - -*/ -#include -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "func_break.h" -#include "decals.h" -#include "explode.h" -#include "../mod/AvHSpecials.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -// =================== FUNC_Breakable ============================================== - -// Just add more items to the bottom of this array and they will automagically be supported -// This is done instead of just a classname in the FGD so we can control which entities can -// be spawned, and still remain fairly flexible -const char *CBreakable::pSpawnObjects[] = -{ - NULL, // 0 - "item_battery", // 1 - "item_healthkit", // 2 - "weapon_9mmhandgun",// 3 - "ammo_9mmclip", // 4 - "weapon_9mmAR", // 5 - "ammo_9mmAR", // 6 - "ammo_ARgrenades", // 7 - "weapon_shotgun", // 8 - "ammo_buckshot", // 9 - "weapon_crossbow", // 10 - "ammo_crossbow", // 11 - "weapon_357", // 12 - "ammo_357", // 13 - "weapon_rpg", // 14 - "ammo_rpgclip", // 15 - "ammo_gaussclip", // 16 - "weapon_handgrenade",// 17 - "weapon_tripmine", // 18 - "weapon_satchel", // 19 - "weapon_snark", // 20 - "weapon_hornetgun", // 21 -}; - -CBreakable::~CBreakable() -{ -} - -void CBreakable::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "strength")) - { - } - else - - // UNDONE_WC: explicitly ignoring these fields, but they shouldn't be in the map file! - if (FStrEq(pkvd->szKeyName, "explosion")) - { - if (!stricmp(pkvd->szValue, "directed")) - m_Explosion = expDirected; - else if (!stricmp(pkvd->szValue, "random")) - m_Explosion = expRandom; - else - m_Explosion = expRandom; - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "material")) - { - int i = atoi( pkvd->szValue); - - // 0:glass, 1:metal, 2:flesh, 3:wood - - if ((i < 0) || (i >= matLastMaterial)) - m_Material = matWood; - else - m_Material = (Materials)i; - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "deadmodel")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shards")) - { -// m_iShards = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibmodel") ) - { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spawnobject") ) - { - int object = atoi( pkvd->szValue ); - if ( object > 0 && object < ARRAYSIZE(pSpawnObjects) ) - m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) - { - ExplosionSetMagnitude( atoi( pkvd->szValue ) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "lip") ) - pkvd->fHandled = TRUE; - else - CBaseDelay::KeyValue( pkvd ); -} - - -// -// func_breakable - bmodel that breaks into pieces after taking damage -// -LINK_ENTITY_TO_CLASS( func_breakable, CBreakable ); -TYPEDESCRIPTION CBreakable::m_SaveData[] = -{ - DEFINE_FIELD( CBreakable, m_Material, FIELD_INTEGER ), - DEFINE_FIELD( CBreakable, m_Explosion, FIELD_INTEGER ), - -// Don't need to save/restore these because we precache after restore -// DEFINE_FIELD( CBreakable, m_idShard, FIELD_INTEGER ), - - DEFINE_FIELD( CBreakable, m_angle, FIELD_FLOAT ), - DEFINE_FIELD( CBreakable, m_iszGibModel, FIELD_STRING ), - DEFINE_FIELD( CBreakable, m_iszSpawnObject, FIELD_STRING ), - - // Explosion magnitude is stored in pev->impulse -}; - -IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ); - -void CBreakable::SetMaterial(Materials inMaterial) -{ - this->m_Material = inMaterial; -} - -void CBreakable::Spawn( void ) -{ - Precache( ); - - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) - pev->takedamage = DAMAGE_NO; - else - pev->takedamage = DAMAGE_YES; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - m_angle = pev->angles.y; - pev->angles.y = 0; - - // HACK: matGlass can receive decals, we need the client to know about this - // so use class to store the material flag - if ( m_Material == matGlass ) - { - pev->playerclass = 1; - } - - SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. - - SetTouch( &CBreakable::BreakTouch ); - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger - SetTouch( NULL ); - - // << cgc >> Save max_health so we can reset the entity - this->pev->max_health = this->pev->health; - - // Flag unbreakable glass as "worldbrush" so it will block ALL tracelines - if ( !IsBreakable() && pev->rendermode != kRenderNormal ) - pev->flags |= FL_WORLDBRUSH; - - this->pev->iuser3 = AVH_USER3_BREAKABLE; -} - - -const char *CBreakable::pSoundsWood[] = -{ - "debris/wood1.wav", - "debris/wood2.wav", - "debris/wood3.wav", -}; - -const char *CBreakable::pSoundsFlesh[] = -{ - "debris/flesh1.wav", - "debris/flesh2.wav", - "debris/flesh3.wav", - "debris/flesh5.wav", - "debris/flesh6.wav", - "debris/flesh7.wav", -}; - -const char *CBreakable::pSoundsMetal[] = -{ - "debris/metal1.wav", - "debris/metal2.wav", - "debris/metal3.wav", -}; - -const char *CBreakable::pSoundsConcrete[] = -{ - "debris/concrete1.wav", - "debris/concrete2.wav", - "debris/concrete3.wav", -}; - - -const char *CBreakable::pSoundsGlass[] = -{ - "debris/glass1.wav", - "debris/glass2.wav", - "debris/glass3.wav", -}; - -const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &soundCount ) -{ - const char **pSoundList = NULL; - - switch ( precacheMaterial ) - { - case matWood: - pSoundList = pSoundsWood; - soundCount = ARRAYSIZE(pSoundsWood); - break; - case matFlesh: - pSoundList = pSoundsFlesh; - soundCount = ARRAYSIZE(pSoundsFlesh); - break; - case matComputer: - case matUnbreakableGlass: - case matGlass: - pSoundList = pSoundsGlass; - soundCount = ARRAYSIZE(pSoundsGlass); - break; - - case matMetal: - pSoundList = pSoundsMetal; - soundCount = ARRAYSIZE(pSoundsMetal); - break; - - case matCinderBlock: - case matRocks: - pSoundList = pSoundsConcrete; - soundCount = ARRAYSIZE(pSoundsConcrete); - break; - - - case matCeilingTile: - case matNone: - default: - soundCount = 0; - break; - } - - return pSoundList; -} - -void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) -{ - const char **pSoundList; - int i, soundCount = 0; - - pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - - for ( i = 0; i < soundCount; i++ ) - { - PRECACHE_SOUND( (char *)pSoundList[i] ); - } -} - -void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) -{ - const char **pSoundList; - int soundCount = 0; - - pSoundList = MaterialSoundList( soundMaterial, soundCount ); - - if ( soundCount ) - EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 ); -} - - -void CBreakable::Precache( void ) -{ - const char *pGibName; - - switch (m_Material) - { - case matWood: - pGibName = "models/woodgibs.mdl"; - - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); - break; - case matFlesh: - pGibName = "models/fleshgibs.mdl"; - - PRECACHE_SOUND("debris/bustflesh1.wav"); - PRECACHE_SOUND("debris/bustflesh2.wav"); - break; - case matComputer: - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); - pGibName = "models/computergibs.mdl"; - - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - - case matUnbreakableGlass: - case matGlass: - pGibName = "models/glassgibs.mdl"; - - PRECACHE_SOUND("debris/bustglass1.wav"); - PRECACHE_SOUND("debris/bustglass2.wav"); - break; - case matMetal: - pGibName = "models/metalplategibs.mdl"; - - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - case matCinderBlock: - pGibName = "models/cindergibs.mdl"; - - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matRocks: - pGibName = "models/rockgibs.mdl"; - - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matCeilingTile: - pGibName = "models/ceilinggibs.mdl"; - - PRECACHE_SOUND ("debris/bustceiling.wav"); - break; - } - MaterialSoundPrecache( m_Material ); - if ( m_iszGibModel ) - pGibName = STRING(m_iszGibModel); - - m_idShard = PRECACHE_MODEL( (char *)pGibName ); - - // Precache the spawn item's data - if ( m_iszSpawnObject ) - UTIL_PrecacheOther( (char *)STRING( m_iszSpawnObject ) ); -} - -// play shard sound when func_breakable takes damage. -// the more damage, the louder the shard sound. - - -void CBreakable::DamageSound( void ) -{ - int pitch; - float fvol; - char *rgpsz[6]; - int i; - int material = m_Material; - -// if (RANDOM_LONG(0,1)) -// return; - - if (RANDOM_LONG(0,2)) - pitch = PITCH_NORM; - else - pitch = 95 + RANDOM_LONG(0,34); - - fvol = RANDOM_FLOAT(0.75, 1.0); - - if (material == matComputer && RANDOM_LONG(0,1)) - material = matMetal; - - switch (material) - { - case matComputer: - case matGlass: - case matUnbreakableGlass: - rgpsz[0] = "debris/glass1.wav"; - rgpsz[1] = "debris/glass2.wav"; - rgpsz[2] = "debris/glass3.wav"; - i = 3; - break; - - case matWood: - rgpsz[0] = "debris/wood1.wav"; - rgpsz[1] = "debris/wood2.wav"; - rgpsz[2] = "debris/wood3.wav"; - i = 3; - break; - - case matMetal: - rgpsz[0] = "debris/metal1.wav"; - rgpsz[1] = "debris/metal3.wav"; - rgpsz[2] = "debris/metal2.wav"; - i = 2; - break; - - case matFlesh: - rgpsz[0] = "debris/flesh1.wav"; - rgpsz[1] = "debris/flesh2.wav"; - rgpsz[2] = "debris/flesh3.wav"; - rgpsz[3] = "debris/flesh5.wav"; - rgpsz[4] = "debris/flesh6.wav"; - rgpsz[5] = "debris/flesh7.wav"; - i = 6; - break; - - case matRocks: - case matCinderBlock: - rgpsz[0] = "debris/concrete1.wav"; - rgpsz[1] = "debris/concrete2.wav"; - rgpsz[2] = "debris/concrete3.wav"; - i = 3; - break; - - case matCeilingTile: - // UNDONE: no ceiling tile shard sound yet - i = 0; - break; - } - - if (i) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); -} - -void CBreakable::BreakTouch( CBaseEntity *pOther ) -{ - float flDamage; - entvars_t* pevToucher = pOther->pev; - - // only players can break these right now - if ( !pOther->IsPlayer() || !IsBreakable() ) - { - return; - } - - if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) ) - {// can be broken when run into - flDamage = pevToucher->velocity.Length() * 0.01; - - if (flDamage >= pev->health) - { - SetTouch( NULL ); - TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH); - - // do a little damage to player if we broke glass or computer - pOther->TakeDamage( pev, pev, flDamage/4, DMG_SLASH ); - } - } - - if ( FBitSet ( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 ) - {// can be broken when stood upon - - // play creaking sound here. - DamageSound(); - - SetThink ( &CBreakable::Die ); - SetTouch( NULL ); - - if ( m_flDelay == 0 ) - {// !!!BUGBUG - why doesn't zero delay work? - m_flDelay = 0.1; - } - - pev->nextthink = pev->ltime + m_flDelay; - - } - -} - - -// -// Smash the our breakable object -// - -// Break when triggered -void CBreakable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsBreakable() ) - { - pev->angles.y = m_angle; - UTIL_MakeVectors(pev->angles); - g_vecAttackDir = gpGlobals->v_forward; - - Die(); - } -} - - -void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - // random spark if this is a 'computer' object - if (RANDOM_LONG(0,1) ) - { - switch( m_Material ) - { - case matComputer: - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } - } - break; - - case matUnbreakableGlass: - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - break; - } - } - - CBaseDelay::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -//========================================================= -// Special takedamage for func_breakable. Allows us to make -// exceptions that are breakable-specific -// bitsDamageType indicates the type of damage sustained ie: DMG_CRUSH -//========================================================= -int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. - // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - - // if a client hit the breakable with a crowbar, and breakable is crowbar-sensitive, break it now. - if ( FBitSet ( pevAttacker->flags, FL_CLIENT ) && - FBitSet ( pev->spawnflags, SF_BREAK_CROWBAR ) && (bitsDamageType & DMG_CLUB)) - flDamage = pev->health; - } - else - // an actual missile was involved. - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - } - - if (!IsBreakable()) - return 0; - - // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) - flDamage *= 2; - - // Boxes / glass / etc. don't take much poison damage, just the impact of the dart - consider that 10% - if ( bitsDamageType & DMG_POISON ) - flDamage *= 0.1; - -// this global is still used for glass and other non-monster killables, along with decals. - g_vecAttackDir = vecTemp.Normalize(); - -// do the damage - pev->health -= flDamage; - if (pev->health <= 0) - { - //Killed( pevAttacker, GIB_NORMAL ); - pev->takedamage = DAMAGE_NO; - pev->deadflag = DEAD_DEAD; - pev->effects = EF_NODRAW; - Die(); - return 0; - } - - // Make a shard noise each time func breakable is hit. - // Don't play shard noise if cbreakable actually died. - - DamageSound(); - - return 1; -} - - -void CBreakable::Die( void ) -{ - Vector vecSpot;// shard origin - Vector vecVelocity;// shard velocity - CBaseEntity *pEntity = NULL; - char cFlag = 0; - int pitch; - float fvol; - - pitch = 95 + RANDOM_LONG(0,29); - - if (pitch > 97 && pitch < 103) - pitch = 100; - - // The more negative pev->health, the louder - // the sound should be. - - fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0); - - if (fvol > 1.0) - fvol = 1.0; - - - switch (m_Material) - { - case matGlass: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_GLASS; - break; - - case matWood: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_WOOD; - break; - - case matComputer: - case matMetal: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_METAL; - break; - - case matFlesh: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_FLESH; - break; - - case matRocks: - case matCinderBlock: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_CONCRETE; - break; - - case matCeilingTile: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - - - if (m_Explosion == expDirected) - vecVelocity = g_vecAttackDir * 200; - else - { - vecVelocity.x = 0; - vecVelocity.y = 0; - vecVelocity.z = 0; - } - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( pev->size.x); - WRITE_COORD( pev->size.y); - WRITE_COORD( pev->size.z); - - // velocity - WRITE_COORD( vecVelocity.x ); - WRITE_COORD( vecVelocity.y ); - WRITE_COORD( vecVelocity.z ); - - // randomization - WRITE_BYTE( 10 ); - - // Model - WRITE_SHORT( m_idShard ); //model id# - - // # of shards - WRITE_BYTE( 0 ); // let client decide - - // duration - WRITE_BYTE( 25 );// 2.5 seconds - - // flags - WRITE_BYTE( cFlag ); - MESSAGE_END(); - - float size = pev->size.x; - if ( size < pev->size.y ) - size = pev->size.y; - if ( size < pev->size.z ) - size = pev->size.z; - - // !!! HACK This should work! - // Build a box above the entity that looks like an 8 pixel high sheet - Vector mins = pev->absmin; - Vector maxs = pev->absmax; - mins.z = pev->absmax.z; - maxs.z += 8; - - // BUGBUG -- can only find 256 entities on a breakable -- should be enough - CBaseEntity *pList[256]; - int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - ClearBits( pList[i]->pev->flags, FL_ONGROUND ); - pList[i]->pev->groundentity = NULL; - } - } - - // Don't fire something that could fire myself - pev->targetname = 0; - - pev->solid = SOLID_NOT; - - // Fire targets on break - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - - // << cgc >> Don't remove entity on death, we need to be able to reset it - //SetThink( SUB_Remove ); - //pev->nextthink = pev->ltime + 0.1; - this->pev->effects = EF_NODRAW; - - if ( m_iszSpawnObject ) - CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); - - - if ( Explodable() ) - { - ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE ); - } -} - - -void CBreakable::ResetEntity() -{ - this->mHasBeenBroken = false; - - this->pev->effects &= ~EF_NODRAW; - this->pev->solid = SOLID_BSP; - this->pev->movetype = MOVETYPE_PUSH; - this->pev->takedamage = DAMAGE_YES; - - // Set health again - this->pev->health = this->pev->max_health; -} - -BOOL CBreakable::IsBreakable( void ) -{ - return (m_Material != matUnbreakableGlass) && (!this->mHasBeenBroken); -} - - -int CBreakable :: DamageDecal( int bitsDamageType ) -{ - if ( m_Material == matGlass ) - return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); - - if ( m_Material == matUnbreakableGlass ) - return DECAL_BPROOF1; - - return CBaseEntity::DamageDecal( bitsDamageType ); -} - -void CBreakable::PrecacheAll() -{ - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); - PRECACHE_MODEL("models/fleshgibs.mdl"); - PRECACHE_SOUND("debris/bustflesh1.wav"); - PRECACHE_SOUND("debris/bustflesh2.wav"); - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); - PRECACHE_MODEL("models/computergibs.mdl"); - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - PRECACHE_MODEL("models/glassgibs.mdl"); - PRECACHE_SOUND("debris/bustglass1.wav"); - PRECACHE_SOUND("debris/bustglass2.wav"); - PRECACHE_MODEL("models/metalplategibs.mdl"); - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - PRECACHE_MODEL("models/cindergibs.mdl"); - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - PRECACHE_MODEL("models/rockgibs.mdl"); - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - PRECACHE_MODEL("models/ceilinggibs.mdl"); - PRECACHE_SOUND("debris/bustceiling.wav"); - PRECACHE_SOUND("debris/wood1.wav"); - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.wav"); - PRECACHE_MODEL("models/woodgibs.mdl"); - - for(int i = matGlass; i < matNone; i++) - { - Materials theMaterial = (Materials)(i); - MaterialSoundPrecache(theMaterial); - } -} - -#include "cpushable.h" - -TYPEDESCRIPTION CPushable::m_SaveData[] = -{ - DEFINE_FIELD( CPushable, m_maxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPushable, m_soundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CPushable, CBreakable ); - -LINK_ENTITY_TO_CLASS( func_pushable, CPushable ); - -char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" }; - - -void CPushable :: Spawn( void ) -{ - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Spawn(); - else - Precache( ); - - pev->movetype = MOVETYPE_PUSHSTEP; - pev->solid = SOLID_BBOX; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if ( pev->friction > 399 ) - pev->friction = 399; - - m_maxSpeed = 400 - pev->friction; - SetBits( pev->flags, FL_FLOAT ); - pev->friction = 0; - - pev->origin.z += 1; // Pick up off of the floor - UTIL_SetOrigin( pev, pev->origin ); - - // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) - pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005; - m_soundTime = 0; -} - - -void CPushable :: Precache( void ) -{ - for ( int i = 0; i < 3; i++ ) - PRECACHE_SOUND( m_soundNames[i] ); - - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Precache( ); -} - - -void CPushable :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "size") ) - { - int bbox = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - switch( bbox ) - { - case 0: // Point - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - break; - - case 2: // Big Hull!?!? !!!BUGBUG Figure out what this hull really is - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN*2, VEC_DUCK_HULL_MAX*2); - break; - - case 3: // Player duck - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - break; - - default: - case 1: // Player - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - break; - } - - } - else if ( FStrEq(pkvd->szKeyName, "buoyancy") ) - { - pev->skin = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBreakable::KeyValue( pkvd ); -} - - -// Pull the func_pushable -void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !pActivator || !pActivator->IsPlayer() ) - { - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - this->CBreakable::Use( pActivator, pCaller, useType, value ); - return; - } - - if ( pActivator->pev->velocity != g_vecZero ) - Move( pActivator, 0 ); -} - - -void CPushable :: Touch( CBaseEntity *pOther ) -{ - if ( FClassnameIs( pOther->pev, "worldspawn" ) ) - return; - - Move( pOther, 1 ); -} - - -void CPushable :: Move( CBaseEntity *pOther, int push ) -{ - entvars_t* pevToucher = pOther->pev; - int playerTouch = 0; - - // Is entity standing on this pushable ? - if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev ) - { - // Only push if floating - if ( pev->waterlevel > 0 ) - pev->velocity.z += pevToucher->velocity.z * 0.1; - - return; - } - - - if ( pOther->IsPlayer() ) - { - if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull) - return; - playerTouch = 1; - } - - float factor; - - if ( playerTouch ) - { - if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water - { - if ( pev->waterlevel < 1 ) - return; - else - factor = 0.1; - } - else - factor = 1; - } - else - factor = 0.25; - - pev->velocity.x += pevToucher->velocity.x * factor; - pev->velocity.y += pevToucher->velocity.y * factor; - - float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ); - if ( push && (length > MaxSpeed()) ) - { - pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); - pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); - } - if ( playerTouch ) - { - pevToucher->velocity.x = pev->velocity.x; - pevToucher->velocity.y = pev->velocity.y; - if ( (gpGlobals->time - m_soundTime) > 0.7 ) - { - m_soundTime = gpGlobals->time; - if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) ) - { - m_lastSound = RANDOM_LONG(0,2); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM); - // SetThink( StopSound ); - // pev->nextthink = pev->ltime + 0.1; - } - else - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); - } - } -} - -#if 0 -void CPushable::StopSound( void ) -{ - Vector dist = pev->oldorigin - pev->origin; - if ( dist.Length() <= 0 ) - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); -} -#endif - -int CPushable::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - - return 1; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== bmodels.cpp ======================================================== + + spawn, think, and use functions for entities that use brush models + +*/ +#include +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "func_break.h" +#include "decals.h" +#include "explode.h" +#include "../mod/AvHSpecials.h" + +extern DLL_GLOBAL Vector g_vecAttackDir; + +// =================== FUNC_Breakable ============================================== + +// Just add more items to the bottom of this array and they will automagically be supported +// This is done instead of just a classname in the FGD so we can control which entities can +// be spawned, and still remain fairly flexible +const char *CBreakable::pSpawnObjects[] = +{ + NULL, // 0 + "item_battery", // 1 + "item_healthkit", // 2 + "weapon_9mmhandgun",// 3 + "ammo_9mmclip", // 4 + "weapon_9mmAR", // 5 + "ammo_9mmAR", // 6 + "ammo_ARgrenades", // 7 + "weapon_shotgun", // 8 + "ammo_buckshot", // 9 + "weapon_crossbow", // 10 + "ammo_crossbow", // 11 + "weapon_357", // 12 + "ammo_357", // 13 + "weapon_rpg", // 14 + "ammo_rpgclip", // 15 + "ammo_gaussclip", // 16 + "weapon_handgrenade",// 17 + "weapon_tripmine", // 18 + "weapon_satchel", // 19 + "weapon_snark", // 20 + "weapon_hornetgun", // 21 +}; + +CBreakable::~CBreakable() +{ +} + +void CBreakable::KeyValue( KeyValueData* pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "strength")) + { + } + else + + // UNDONE_WC: explicitly ignoring these fields, but they shouldn't be in the map file! + if (FStrEq(pkvd->szKeyName, "explosion")) + { + if (!stricmp(pkvd->szValue, "directed")) + m_Explosion = expDirected; + else if (!stricmp(pkvd->szValue, "random")) + m_Explosion = expRandom; + else + m_Explosion = expRandom; + + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "material")) + { + int i = atoi( pkvd->szValue); + + // 0:glass, 1:metal, 2:flesh, 3:wood + + if ((i < 0) || (i >= matLastMaterial)) + m_Material = matWood; + else + m_Material = (Materials)i; + + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "deadmodel")) + { + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "shards")) + { +// m_iShards = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "gibmodel") ) + { + m_iszGibModel = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "spawnobject") ) + { + int object = atoi( pkvd->szValue ); + if ( object > 0 && object < ARRAYSIZE(pSpawnObjects) ) + m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) + { + ExplosionSetMagnitude( atoi( pkvd->szValue ) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "lip") ) + pkvd->fHandled = TRUE; + else + CBaseDelay::KeyValue( pkvd ); +} + + +// +// func_breakable - bmodel that breaks into pieces after taking damage +// +LINK_ENTITY_TO_CLASS( func_breakable, CBreakable ); +TYPEDESCRIPTION CBreakable::m_SaveData[] = +{ + DEFINE_FIELD( CBreakable, m_Material, FIELD_INTEGER ), + DEFINE_FIELD( CBreakable, m_Explosion, FIELD_INTEGER ), + +// Don't need to save/restore these because we precache after restore +// DEFINE_FIELD( CBreakable, m_idShard, FIELD_INTEGER ), + + DEFINE_FIELD( CBreakable, m_angle, FIELD_FLOAT ), + DEFINE_FIELD( CBreakable, m_iszGibModel, FIELD_STRING ), + DEFINE_FIELD( CBreakable, m_iszSpawnObject, FIELD_STRING ), + + // Explosion magnitude is stored in pev->impulse +}; + +IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ); + +void CBreakable::SetMaterial(Materials inMaterial) +{ + this->m_Material = inMaterial; +} + +void CBreakable::Spawn( void ) +{ + Precache( ); + + if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) + pev->takedamage = DAMAGE_NO; + else + pev->takedamage = DAMAGE_YES; + + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + m_angle = pev->angles.y; + pev->angles.y = 0; + + // HACK: matGlass can receive decals, we need the client to know about this + // so use class to store the material flag + if ( m_Material == matGlass ) + { + pev->playerclass = 1; + } + + SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. + + SetTouch( &CBreakable::BreakTouch ); + if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger + SetTouch( NULL ); + + // << cgc >> Save max_health so we can reset the entity + this->pev->max_health = this->pev->health; + + // Flag unbreakable glass as "worldbrush" so it will block ALL tracelines + if ( !IsBreakable() && pev->rendermode != kRenderNormal ) + pev->flags |= FL_WORLDBRUSH; + + this->pev->iuser3 = AVH_USER3_BREAKABLE; +} + + +const char *CBreakable::pSoundsWood[] = +{ + "debris/wood1.wav", + "debris/wood2.wav", + "debris/wood3.wav", +}; + +const char *CBreakable::pSoundsFlesh[] = +{ + "debris/flesh1.wav", + "debris/flesh2.wav", + "debris/flesh3.wav", + "debris/flesh5.wav", + "debris/flesh6.wav", + "debris/flesh7.wav", +}; + +const char *CBreakable::pSoundsMetal[] = +{ + "debris/metal1.wav", + "debris/metal2.wav", + "debris/metal3.wav", +}; + +const char *CBreakable::pSoundsConcrete[] = +{ + "debris/concrete1.wav", + "debris/concrete2.wav", + "debris/concrete3.wav", +}; + + +const char *CBreakable::pSoundsGlass[] = +{ + "debris/glass1.wav", + "debris/glass2.wav", + "debris/glass3.wav", +}; + +const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &soundCount ) +{ + const char **pSoundList = NULL; + + switch ( precacheMaterial ) + { + case matWood: + pSoundList = pSoundsWood; + soundCount = ARRAYSIZE(pSoundsWood); + break; + case matFlesh: + pSoundList = pSoundsFlesh; + soundCount = ARRAYSIZE(pSoundsFlesh); + break; + case matComputer: + case matUnbreakableGlass: + case matGlass: + pSoundList = pSoundsGlass; + soundCount = ARRAYSIZE(pSoundsGlass); + break; + + case matMetal: + pSoundList = pSoundsMetal; + soundCount = ARRAYSIZE(pSoundsMetal); + break; + + case matCinderBlock: + case matRocks: + pSoundList = pSoundsConcrete; + soundCount = ARRAYSIZE(pSoundsConcrete); + break; + + + case matCeilingTile: + case matNone: + default: + soundCount = 0; + break; + } + + return pSoundList; +} + +void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) +{ + const char **pSoundList; + int i, soundCount = 0; + + pSoundList = MaterialSoundList( precacheMaterial, soundCount ); + + for ( i = 0; i < soundCount; i++ ) + { + PRECACHE_SOUND( (char *)pSoundList[i] ); + } +} + +void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) +{ + const char **pSoundList; + int soundCount = 0; + + pSoundList = MaterialSoundList( soundMaterial, soundCount ); + + if ( soundCount ) + EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 ); +} + + +void CBreakable::Precache( void ) +{ + const char *pGibName; + + switch (m_Material) + { + case matWood: + pGibName = "models/woodgibs.mdl"; + + PRECACHE_SOUND("debris/bustcrate1.wav"); + PRECACHE_SOUND("debris/bustcrate2.wav"); + break; + case matFlesh: + pGibName = "models/fleshgibs.mdl"; + + PRECACHE_SOUND("debris/bustflesh1.wav"); + PRECACHE_SOUND("debris/bustflesh2.wav"); + break; + case matComputer: + PRECACHE_SOUND("buttons/spark5.wav"); + PRECACHE_SOUND("buttons/spark6.wav"); + pGibName = "models/computergibs.mdl"; + + PRECACHE_SOUND("debris/bustmetal1.wav"); + PRECACHE_SOUND("debris/bustmetal2.wav"); + break; + + case matUnbreakableGlass: + case matGlass: + pGibName = "models/glassgibs.mdl"; + + PRECACHE_SOUND("debris/bustglass1.wav"); + PRECACHE_SOUND("debris/bustglass2.wav"); + break; + case matMetal: + pGibName = "models/metalplategibs.mdl"; + + PRECACHE_SOUND("debris/bustmetal1.wav"); + PRECACHE_SOUND("debris/bustmetal2.wav"); + break; + case matCinderBlock: + pGibName = "models/cindergibs.mdl"; + + PRECACHE_SOUND("debris/bustconcrete1.wav"); + PRECACHE_SOUND("debris/bustconcrete2.wav"); + break; + case matRocks: + pGibName = "models/rockgibs.mdl"; + + PRECACHE_SOUND("debris/bustconcrete1.wav"); + PRECACHE_SOUND("debris/bustconcrete2.wav"); + break; + case matCeilingTile: + pGibName = "models/ceilinggibs.mdl"; + + PRECACHE_SOUND ("debris/bustceiling.wav"); + break; + } + MaterialSoundPrecache( m_Material ); + if ( m_iszGibModel ) + pGibName = STRING(m_iszGibModel); + + m_idShard = PRECACHE_MODEL( (char *)pGibName ); + + // Precache the spawn item's data + if ( m_iszSpawnObject ) + UTIL_PrecacheOther( (char *)STRING( m_iszSpawnObject ) ); +} + +// play shard sound when func_breakable takes damage. +// the more damage, the louder the shard sound. + + +void CBreakable::DamageSound( void ) +{ + int pitch; + float fvol; + char *rgpsz[6]; + int i; + int material = m_Material; + +// if (RANDOM_LONG(0,1)) +// return; + + if (RANDOM_LONG(0,2)) + pitch = PITCH_NORM; + else + pitch = 95 + RANDOM_LONG(0,34); + + fvol = RANDOM_FLOAT(0.75, 1.0); + + if (material == matComputer && RANDOM_LONG(0,1)) + material = matMetal; + + switch (material) + { + case matComputer: + case matGlass: + case matUnbreakableGlass: + rgpsz[0] = "debris/glass1.wav"; + rgpsz[1] = "debris/glass2.wav"; + rgpsz[2] = "debris/glass3.wav"; + i = 3; + break; + + case matWood: + rgpsz[0] = "debris/wood1.wav"; + rgpsz[1] = "debris/wood2.wav"; + rgpsz[2] = "debris/wood3.wav"; + i = 3; + break; + + case matMetal: + rgpsz[0] = "debris/metal1.wav"; + rgpsz[1] = "debris/metal3.wav"; + rgpsz[2] = "debris/metal2.wav"; + i = 2; + break; + + case matFlesh: + rgpsz[0] = "debris/flesh1.wav"; + rgpsz[1] = "debris/flesh2.wav"; + rgpsz[2] = "debris/flesh3.wav"; + rgpsz[3] = "debris/flesh5.wav"; + rgpsz[4] = "debris/flesh6.wav"; + rgpsz[5] = "debris/flesh7.wav"; + i = 6; + break; + + case matRocks: + case matCinderBlock: + rgpsz[0] = "debris/concrete1.wav"; + rgpsz[1] = "debris/concrete2.wav"; + rgpsz[2] = "debris/concrete3.wav"; + i = 3; + break; + + case matCeilingTile: + // UNDONE: no ceiling tile shard sound yet + i = 0; + break; + } + + if (i) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); +} + +void CBreakable::BreakTouch( CBaseEntity *pOther ) +{ + float flDamage; + entvars_t* pevToucher = pOther->pev; + + // only players can break these right now + if ( !pOther->IsPlayer() || !IsBreakable() ) + { + return; + } + + if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) ) + {// can be broken when run into + flDamage = pevToucher->velocity.Length() * 0.01; + + if (flDamage >= pev->health) + { + SetTouch( NULL ); + TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH); + + // do a little damage to player if we broke glass or computer + pOther->TakeDamage( pev, pev, flDamage/4, DMG_SLASH ); + } + } + + if ( FBitSet ( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 ) + {// can be broken when stood upon + + // play creaking sound here. + DamageSound(); + + SetThink ( &CBreakable::Die ); + SetTouch( NULL ); + + if ( m_flDelay == 0 ) + {// !!!BUGBUG - why doesn't zero delay work? + m_flDelay = 0.1; + } + + pev->nextthink = pev->ltime + m_flDelay; + + } + +} + + +// +// Smash the our breakable object +// + +// Break when triggered +void CBreakable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( IsBreakable() ) + { + pev->angles.y = m_angle; + UTIL_MakeVectors(pev->angles); + g_vecAttackDir = gpGlobals->v_forward; + + Die(); + } +} + + +void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) +{ + // random spark if this is a 'computer' object + if (RANDOM_LONG(0,1) ) + { + switch( m_Material ) + { + case matComputer: + { + UTIL_Sparks( ptr->vecEndPos ); + + float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range + switch ( RANDOM_LONG(0,1) ) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; + } + } + break; + + case matUnbreakableGlass: + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); + break; + } + } + + CBaseDelay::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); +} + +//========================================================= +// Special takedamage for func_breakable. Allows us to make +// exceptions that are breakable-specific +// bitsDamageType indicates the type of damage sustained ie: DMG_CRUSH +//========================================================= +int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + Vector vecTemp; + + // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. + // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). + if ( pevAttacker == pevInflictor ) + { + vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); + + // if a client hit the breakable with a crowbar, and breakable is crowbar-sensitive, break it now. + if ( FBitSet ( pevAttacker->flags, FL_CLIENT ) && + FBitSet ( pev->spawnflags, SF_BREAK_CROWBAR ) && (bitsDamageType & DMG_CLUB)) + flDamage = pev->health; + } + else + // an actual missile was involved. + { + vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); + } + + if (!IsBreakable()) + return 0; + + // Breakables take double damage from the crowbar + if ( bitsDamageType & DMG_CLUB ) + flDamage *= 2; + + // Boxes / glass / etc. don't take much poison damage, just the impact of the dart - consider that 10% + if ( bitsDamageType & DMG_POISON ) + flDamage *= 0.1; + +// this global is still used for glass and other non-monster killables, along with decals. + g_vecAttackDir = vecTemp.Normalize(); + +// do the damage + pev->health -= flDamage; + if (pev->health <= 0) + { + //Killed( pevAttacker, GIB_NORMAL ); + pev->takedamage = DAMAGE_NO; + pev->deadflag = DEAD_DEAD; + pev->effects = EF_NODRAW; + Die(); + return 0; + } + + // Make a shard noise each time func breakable is hit. + // Don't play shard noise if cbreakable actually died. + + DamageSound(); + + return 1; +} + + +void CBreakable::Die( void ) +{ + Vector vecSpot;// shard origin + Vector vecVelocity;// shard velocity + CBaseEntity *pEntity = NULL; + char cFlag = 0; + int pitch; + float fvol; + + pitch = 95 + RANDOM_LONG(0,29); + + if (pitch > 97 && pitch < 103) + pitch = 100; + + // The more negative pev->health, the louder + // the sound should be. + + fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0); + + if (fvol > 1.0) + fvol = 1.0; + + + switch (m_Material) + { + case matGlass: + switch ( RANDOM_LONG(0,1) ) + { + case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); + break; + case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); + break; + } + cFlag = BREAK_GLASS; + break; + + case matWood: + switch ( RANDOM_LONG(0,1) ) + { + case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); + break; + case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); + break; + } + cFlag = BREAK_WOOD; + break; + + case matComputer: + case matMetal: + switch ( RANDOM_LONG(0,1) ) + { + case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); + break; + case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); + break; + } + cFlag = BREAK_METAL; + break; + + case matFlesh: + switch ( RANDOM_LONG(0,1) ) + { + case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); + break; + case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); + break; + } + cFlag = BREAK_FLESH; + break; + + case matRocks: + case matCinderBlock: + switch ( RANDOM_LONG(0,1) ) + { + case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); + break; + case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch); + break; + } + cFlag = BREAK_CONCRETE; + break; + + case matCeilingTile: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); + break; + } + + + if (m_Explosion == expDirected) + vecVelocity = g_vecAttackDir * 200; + else + { + vecVelocity.x = 0; + vecVelocity.y = 0; + vecVelocity.z = 0; + } + + vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_BREAKMODEL); + + // position + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z ); + + // size + WRITE_COORD( pev->size.x); + WRITE_COORD( pev->size.y); + WRITE_COORD( pev->size.z); + + // velocity + WRITE_COORD( vecVelocity.x ); + WRITE_COORD( vecVelocity.y ); + WRITE_COORD( vecVelocity.z ); + + // randomization + WRITE_BYTE( 10 ); + + // Model + WRITE_SHORT( m_idShard ); //model id# + + // # of shards + WRITE_BYTE( 0 ); // let client decide + + // duration + WRITE_BYTE( 25 );// 2.5 seconds + + // flags + WRITE_BYTE( cFlag ); + MESSAGE_END(); + + float size = pev->size.x; + if ( size < pev->size.y ) + size = pev->size.y; + if ( size < pev->size.z ) + size = pev->size.z; + + // !!! HACK This should work! + // Build a box above the entity that looks like an 8 pixel high sheet + Vector mins = pev->absmin; + Vector maxs = pev->absmax; + mins.z = pev->absmax.z; + maxs.z += 8; + + // BUGBUG -- can only find 256 entities on a breakable -- should be enough + CBaseEntity *pList[256]; + int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); + if ( count ) + { + for ( int i = 0; i < count; i++ ) + { + ClearBits( pList[i]->pev->flags, FL_ONGROUND ); + pList[i]->pev->groundentity = NULL; + } + } + + // Don't fire something that could fire myself + pev->targetname = 0; + + pev->solid = SOLID_NOT; + + // Fire targets on break + SUB_UseTargets( NULL, USE_TOGGLE, 0 ); + + // << cgc >> Don't remove entity on death, we need to be able to reset it + //SetThink( SUB_Remove ); + //pev->nextthink = pev->ltime + 0.1; + this->pev->effects = EF_NODRAW; + + if ( m_iszSpawnObject ) + CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); + + + if ( Explodable() ) + { + ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE ); + } +} + + +void CBreakable::ResetEntity() +{ + this->mHasBeenBroken = false; + + this->pev->effects &= ~EF_NODRAW; + this->pev->solid = SOLID_BSP; + this->pev->movetype = MOVETYPE_PUSH; + this->pev->takedamage = DAMAGE_YES; + + // Set health again + this->pev->health = this->pev->max_health; +} + +BOOL CBreakable::IsBreakable( void ) +{ + return (m_Material != matUnbreakableGlass) && (!this->mHasBeenBroken); +} + + +int CBreakable :: DamageDecal( int bitsDamageType ) +{ + if ( m_Material == matGlass ) + return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); + + if ( m_Material == matUnbreakableGlass ) + return DECAL_BPROOF1; + + return CBaseEntity::DamageDecal( bitsDamageType ); +} + +void CBreakable::PrecacheAll() +{ + PRECACHE_SOUND("debris/bustcrate1.wav"); + PRECACHE_SOUND("debris/bustcrate2.wav"); + PRECACHE_MODEL("models/fleshgibs.mdl"); + PRECACHE_SOUND("debris/bustflesh1.wav"); + PRECACHE_SOUND("debris/bustflesh2.wav"); + PRECACHE_SOUND("buttons/spark5.wav"); + PRECACHE_SOUND("buttons/spark6.wav"); + PRECACHE_MODEL("models/computergibs.mdl"); + PRECACHE_SOUND("debris/bustmetal1.wav"); + PRECACHE_SOUND("debris/bustmetal2.wav"); + PRECACHE_MODEL("models/glassgibs.mdl"); + PRECACHE_SOUND("debris/bustglass1.wav"); + PRECACHE_SOUND("debris/bustglass2.wav"); + PRECACHE_MODEL("models/metalplategibs.mdl"); + PRECACHE_SOUND("debris/bustmetal1.wav"); + PRECACHE_SOUND("debris/bustmetal2.wav"); + PRECACHE_MODEL("models/cindergibs.mdl"); + PRECACHE_SOUND("debris/bustconcrete1.wav"); + PRECACHE_SOUND("debris/bustconcrete2.wav"); + PRECACHE_MODEL("models/rockgibs.mdl"); + PRECACHE_SOUND("debris/bustconcrete1.wav"); + PRECACHE_SOUND("debris/bustconcrete2.wav"); + PRECACHE_MODEL("models/ceilinggibs.mdl"); + PRECACHE_SOUND("debris/bustceiling.wav"); + PRECACHE_SOUND("debris/wood1.wav"); + PRECACHE_SOUND("debris/wood2.wav"); + PRECACHE_SOUND("debris/wood3.wav"); + PRECACHE_MODEL("models/woodgibs.mdl"); + + for(int i = matGlass; i < matNone; i++) + { + Materials theMaterial = (Materials)(i); + MaterialSoundPrecache(theMaterial); + } +} + +#include "cpushable.h" + +TYPEDESCRIPTION CPushable::m_SaveData[] = +{ + DEFINE_FIELD( CPushable, m_maxSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CPushable, m_soundTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CPushable, CBreakable ); + +LINK_ENTITY_TO_CLASS( func_pushable, CPushable ); + +char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" }; + + +void CPushable :: Spawn( void ) +{ + if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + CBreakable::Spawn(); + else + Precache( ); + + pev->movetype = MOVETYPE_PUSHSTEP; + pev->solid = SOLID_BBOX; + SET_MODEL( ENT(pev), STRING(pev->model) ); + + if ( pev->friction > 399 ) + pev->friction = 399; + + m_maxSpeed = 400 - pev->friction; + SetBits( pev->flags, FL_FLOAT ); + pev->friction = 0; + + pev->origin.z += 1; // Pick up off of the floor + UTIL_SetOrigin( pev, pev->origin ); + + // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) + pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005; + m_soundTime = 0; +} + + +void CPushable :: Precache( void ) +{ + for ( int i = 0; i < 3; i++ ) + PRECACHE_SOUND( m_soundNames[i] ); + + if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + CBreakable::Precache( ); +} + + +void CPushable :: KeyValue( KeyValueData *pkvd ) +{ + if ( FStrEq(pkvd->szKeyName, "size") ) + { + int bbox = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + + switch( bbox ) + { + case 0: // Point + UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); + break; + + case 2: // Big Hull!?!? !!!BUGBUG Figure out what this hull really is + UTIL_SetSize(pev, VEC_DUCK_HULL_MIN*2, VEC_DUCK_HULL_MAX*2); + break; + + case 3: // Player duck + UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); + break; + + default: + case 1: // Player + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + break; + } + + } + else if ( FStrEq(pkvd->szKeyName, "buoyancy") ) + { + pev->skin = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBreakable::KeyValue( pkvd ); +} + + +// Pull the func_pushable +void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !pActivator || !pActivator->IsPlayer() ) + { + if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + this->CBreakable::Use( pActivator, pCaller, useType, value ); + return; + } + + if ( pActivator->pev->velocity != g_vecZero ) + Move( pActivator, 0 ); +} + + +void CPushable :: Touch( CBaseEntity *pOther ) +{ + if ( FClassnameIs( pOther->pev, "worldspawn" ) ) + return; + + Move( pOther, 1 ); +} + + +void CPushable :: Move( CBaseEntity *pOther, int push ) +{ + entvars_t* pevToucher = pOther->pev; + int playerTouch = 0; + + // Is entity standing on this pushable ? + if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev ) + { + // Only push if floating + if ( pev->waterlevel > 0 ) + pev->velocity.z += pevToucher->velocity.z * 0.1; + + return; + } + + + if ( pOther->IsPlayer() ) + { + if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull) + return; + playerTouch = 1; + } + + float factor; + + if ( playerTouch ) + { + if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water + { + if ( pev->waterlevel < 1 ) + return; + else + factor = 0.1; + } + else + factor = 1; + } + else + factor = 0.25; + + pev->velocity.x += pevToucher->velocity.x * factor; + pev->velocity.y += pevToucher->velocity.y * factor; + + float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ); + if ( push && (length > MaxSpeed()) ) + { + pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); + pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); + } + if ( playerTouch ) + { + pevToucher->velocity.x = pev->velocity.x; + pevToucher->velocity.y = pev->velocity.y; + if ( (gpGlobals->time - m_soundTime) > 0.7 ) + { + m_soundTime = gpGlobals->time; + if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) ) + { + m_lastSound = RANDOM_LONG(0,2); + EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM); + // SetThink( StopSound ); + // pev->nextthink = pev->ltime + 0.1; + } + else + STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); + } + } +} + +#if 0 +void CPushable::StopSound( void ) +{ + Vector dist = pev->oldorigin - pev->origin; + if ( dist.Length() <= 0 ) + STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); +} +#endif + +int CPushable::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); + + return 1; +} + diff --git a/main/source/dlls/func_break.cpp~ b/main/source/dlls/func_break.cpp~ deleted file mode 100644 index ba16309c..00000000 --- a/main/source/dlls/func_break.cpp~ +++ /dev/null @@ -1,1054 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== bmodels.cpp ======================================================== - - spawn, think, and use functions for entities that use brush models - -*/ -#include -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "func_break.h" -#include "decals.h" -#include "explode.h" -#include "../mod/AvHSpecials.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -// =================== FUNC_Breakable ============================================== - -// Just add more items to the bottom of this array and they will automagically be supported -// This is done instead of just a classname in the FGD so we can control which entities can -// be spawned, and still remain fairly flexible -const char *CBreakable::pSpawnObjects[] = -{ - NULL, // 0 - "item_battery", // 1 - "item_healthkit", // 2 - "weapon_9mmhandgun",// 3 - "ammo_9mmclip", // 4 - "weapon_9mmAR", // 5 - "ammo_9mmAR", // 6 - "ammo_ARgrenades", // 7 - "weapon_shotgun", // 8 - "ammo_buckshot", // 9 - "weapon_crossbow", // 10 - "ammo_crossbow", // 11 - "weapon_357", // 12 - "ammo_357", // 13 - "weapon_rpg", // 14 - "ammo_rpgclip", // 15 - "ammo_gaussclip", // 16 - "weapon_handgrenade",// 17 - "weapon_tripmine", // 18 - "weapon_satchel", // 19 - "weapon_snark", // 20 - "weapon_hornetgun", // 21 -}; - -CBreakable::~CBreakable() -{ -} - -void CBreakable::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "strength")) - { - } - else - - // UNDONE_WC: explicitly ignoring these fields, but they shouldn't be in the map file! - if (FStrEq(pkvd->szKeyName, "explosion")) - { - if (!stricmp(pkvd->szValue, "directed")) - m_Explosion = expDirected; - else if (!stricmp(pkvd->szValue, "random")) - m_Explosion = expRandom; - else - m_Explosion = expRandom; - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "material")) - { - int i = atoi( pkvd->szValue); - - // 0:glass, 1:metal, 2:flesh, 3:wood - - if ((i < 0) || (i >= matLastMaterial)) - m_Material = matWood; - else - m_Material = (Materials)i; - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "deadmodel")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shards")) - { -// m_iShards = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibmodel") ) - { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spawnobject") ) - { - int object = atoi( pkvd->szValue ); - if ( object > 0 && object < ARRAYSIZE(pSpawnObjects) ) - m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) - { - ExplosionSetMagnitude( atoi( pkvd->szValue ) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "lip") ) - pkvd->fHandled = TRUE; - else - CBaseDelay::KeyValue( pkvd ); -} - - -// -// func_breakable - bmodel that breaks into pieces after taking damage -// -LINK_ENTITY_TO_CLASS( func_breakable, CBreakable ); -TYPEDESCRIPTION CBreakable::m_SaveData[] = -{ - DEFINE_FIELD( CBreakable, m_Material, FIELD_INTEGER ), - DEFINE_FIELD( CBreakable, m_Explosion, FIELD_INTEGER ), - -// Don't need to save/restore these because we precache after restore -// DEFINE_FIELD( CBreakable, m_idShard, FIELD_INTEGER ), - - DEFINE_FIELD( CBreakable, m_angle, FIELD_FLOAT ), - DEFINE_FIELD( CBreakable, m_iszGibModel, FIELD_STRING ), - DEFINE_FIELD( CBreakable, m_iszSpawnObject, FIELD_STRING ), - - // Explosion magnitude is stored in pev->impulse -}; - -IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ); - -void CBreakable::SetMaterial(Materials inMaterial) -{ - this->m_Material = inMaterial; -} - -void CBreakable::Spawn( void ) -{ - Precache( ); - - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) - pev->takedamage = DAMAGE_NO; - else - pev->takedamage = DAMAGE_YES; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - m_angle = pev->angles.y; - pev->angles.y = 0; - - // HACK: matGlass can receive decals, we need the client to know about this - // so use class to store the material flag - if ( m_Material == matGlass ) - { - pev->playerclass = 1; - } - - SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. - - SetTouch( &CBreakable::BreakTouch ); - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger - SetTouch( NULL ); - - // << cgc >> Save max_health so we can reset the entity - this->pev->max_health = this->pev->health; - - // Flag unbreakable glass as "worldbrush" so it will block ALL tracelines - if ( !IsBreakable() && pev->rendermode != kRenderNormal ) - pev->flags |= FL_WORLDBRUSH; - - this->pev->iuser3 = AVH_USER3_BREAKABLE; -} - - -const char *CBreakable::pSoundsWood[] = -{ - "debris/wood1.wav", - "debris/wood2.wav", - "debris/wood3.wav", -}; - -const char *CBreakable::pSoundsFlesh[] = -{ - "debris/flesh1.wav", - "debris/flesh2.wav", - "debris/flesh3.wav", - "debris/flesh5.wav", - "debris/flesh6.wav", - "debris/flesh7.wav", -}; - -const char *CBreakable::pSoundsMetal[] = -{ - "debris/metal1.wav", - "debris/metal2.wav", - "debris/metal3.wav", -}; - -const char *CBreakable::pSoundsConcrete[] = -{ - "debris/concrete1.wav", - "debris/concrete2.wav", - "debris/concrete3.wav", -}; - - -const char *CBreakable::pSoundsGlass[] = -{ - "debris/glass1.wav", - "debris/glass2.wav", - "debris/glass3.wav", -}; - -const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &soundCount ) -{ - const char **pSoundList = NULL; - - switch ( precacheMaterial ) - { - case matWood: - pSoundList = pSoundsWood; - soundCount = ARRAYSIZE(pSoundsWood); - break; - case matFlesh: - pSoundList = pSoundsFlesh; - soundCount = ARRAYSIZE(pSoundsFlesh); - break; - case matComputer: - case matUnbreakableGlass: - case matGlass: - pSoundList = pSoundsGlass; - soundCount = ARRAYSIZE(pSoundsGlass); - break; - - case matMetal: - pSoundList = pSoundsMetal; - soundCount = ARRAYSIZE(pSoundsMetal); - break; - - case matCinderBlock: - case matRocks: - pSoundList = pSoundsConcrete; - soundCount = ARRAYSIZE(pSoundsConcrete); - break; - - - case matCeilingTile: - case matNone: - default: - soundCount = 0; - break; - } - - return pSoundList; -} - -void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) -{ - const char **pSoundList; - int i, soundCount = 0; - - pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - - for ( i = 0; i < soundCount; i++ ) - { - PRECACHE_SOUND( (char *)pSoundList[i] ); - } -} - -void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) -{ - const char **pSoundList; - int soundCount = 0; - - pSoundList = MaterialSoundList( soundMaterial, soundCount ); - - if ( soundCount ) - EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 ); -} - - -void CBreakable::Precache( void ) -{ - const char *pGibName; - - switch (m_Material) - { - case matWood: - pGibName = "models/woodgibs.mdl"; - - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); - break; - case matFlesh: - pGibName = "models/fleshgibs.mdl"; - - PRECACHE_SOUND("debris/bustflesh1.wav"); - PRECACHE_SOUND("debris/bustflesh2.wav"); - break; - case matComputer: - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); - pGibName = "models/computergibs.mdl"; - - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - - case matUnbreakableGlass: - case matGlass: - pGibName = "models/glassgibs.mdl"; - - PRECACHE_SOUND("debris/bustglass1.wav"); - PRECACHE_SOUND("debris/bustglass2.wav"); - break; - case matMetal: - pGibName = "models/metalplategibs.mdl"; - - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - case matCinderBlock: - pGibName = "models/cindergibs.mdl"; - - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matRocks: - pGibName = "models/rockgibs.mdl"; - - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matCeilingTile: - pGibName = "models/ceilinggibs.mdl"; - - PRECACHE_SOUND ("debris/bustceiling.wav"); - break; - } - MaterialSoundPrecache( m_Material ); - if ( m_iszGibModel ) - pGibName = STRING(m_iszGibModel); - - m_idShard = PRECACHE_MODEL( (char *)pGibName ); - - // Precache the spawn item's data - if ( m_iszSpawnObject ) - UTIL_PrecacheOther( (char *)STRING( m_iszSpawnObject ) ); -} - -// play shard sound when func_breakable takes damage. -// the more damage, the louder the shard sound. - - -void CBreakable::DamageSound( void ) -{ - int pitch; - float fvol; - char *rgpsz[6]; - int i; - int material = m_Material; - -// if (RANDOM_LONG(0,1)) -// return; - - if (RANDOM_LONG(0,2)) - pitch = PITCH_NORM; - else - pitch = 95 + RANDOM_LONG(0,34); - - fvol = RANDOM_FLOAT(0.75, 1.0); - - if (material == matComputer && RANDOM_LONG(0,1)) - material = matMetal; - - switch (material) - { - case matComputer: - case matGlass: - case matUnbreakableGlass: - rgpsz[0] = "debris/glass1.wav"; - rgpsz[1] = "debris/glass2.wav"; - rgpsz[2] = "debris/glass3.wav"; - i = 3; - break; - - case matWood: - rgpsz[0] = "debris/wood1.wav"; - rgpsz[1] = "debris/wood2.wav"; - rgpsz[2] = "debris/wood3.wav"; - i = 3; - break; - - case matMetal: - rgpsz[0] = "debris/metal1.wav"; - rgpsz[1] = "debris/metal3.wav"; - rgpsz[2] = "debris/metal2.wav"; - i = 2; - break; - - case matFlesh: - rgpsz[0] = "debris/flesh1.wav"; - rgpsz[1] = "debris/flesh2.wav"; - rgpsz[2] = "debris/flesh3.wav"; - rgpsz[3] = "debris/flesh5.wav"; - rgpsz[4] = "debris/flesh6.wav"; - rgpsz[5] = "debris/flesh7.wav"; - i = 6; - break; - - case matRocks: - case matCinderBlock: - rgpsz[0] = "debris/concrete1.wav"; - rgpsz[1] = "debris/concrete2.wav"; - rgpsz[2] = "debris/concrete3.wav"; - i = 3; - break; - - case matCeilingTile: - // UNDONE: no ceiling tile shard sound yet - i = 0; - break; - } - - if (i) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); -} - -void CBreakable::BreakTouch( CBaseEntity *pOther ) -{ - float flDamage; - entvars_t* pevToucher = pOther->pev; - - // only players can break these right now - if ( !pOther->IsPlayer() || !IsBreakable() ) - { - return; - } - - if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) ) - {// can be broken when run into - flDamage = pevToucher->velocity.Length() * 0.01; - - if (flDamage >= pev->health) - { - SetTouch( NULL ); - TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH); - - // do a little damage to player if we broke glass or computer - pOther->TakeDamage( pev, pev, flDamage/4, DMG_SLASH ); - } - } - - if ( FBitSet ( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 ) - {// can be broken when stood upon - - // play creaking sound here. - DamageSound(); - - SetThink ( &CBreakable::Die ); - SetTouch( NULL ); - - if ( m_flDelay == 0 ) - {// !!!BUGBUG - why doesn't zero delay work? - m_flDelay = 0.1; - } - - pev->nextthink = pev->ltime + m_flDelay; - - } - -} - - -// -// Smash the our breakable object -// - -// Break when triggered -void CBreakable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsBreakable() ) - { - pev->angles.y = m_angle; - UTIL_MakeVectors(pev->angles); - g_vecAttackDir = gpGlobals->v_forward; - - Die(); - } -} - - -void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - // random spark if this is a 'computer' object - if (RANDOM_LONG(0,1) ) - { - switch( m_Material ) - { - case matComputer: - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } - } - break; - - case matUnbreakableGlass: - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - break; - } - } - - CBaseDelay::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -//========================================================= -// Special takedamage for func_breakable. Allows us to make -// exceptions that are breakable-specific -// bitsDamageType indicates the type of damage sustained ie: DMG_CRUSH -//========================================================= -int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. - // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - - // if a client hit the breakable with a crowbar, and breakable is crowbar-sensitive, break it now. - if ( FBitSet ( pevAttacker->flags, FL_CLIENT ) && - FBitSet ( pev->spawnflags, SF_BREAK_CROWBAR ) && (bitsDamageType & DMG_CLUB)) - flDamage = pev->health; - } - else - // an actual missile was involved. - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - } - - if (!IsBreakable()) - return 0; - - // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) - flDamage *= 2; - - // Boxes / glass / etc. don't take much poison damage, just the impact of the dart - consider that 10% - if ( bitsDamageType & DMG_POISON ) - flDamage *= 0.1; - -// this global is still used for glass and other non-monster killables, along with decals. - g_vecAttackDir = vecTemp.Normalize(); - -// do the damage - pev->health -= flDamage; - if (pev->health <= 0) - { - //Killed( pevAttacker, GIB_NORMAL ); - pev->takedamage = DAMAGE_NO; - pev->deadflag = DEAD_DEAD; - pev->effects = EF_NODRAW; - Die(); - return 0; - } - - // Make a shard noise each time func breakable is hit. - // Don't play shard noise if cbreakable actually died. - - DamageSound(); - - return 1; -} - - -void CBreakable::Die( void ) -{ - Vector vecSpot;// shard origin - Vector vecVelocity;// shard velocity - CBaseEntity *pEntity = NULL; - char cFlag = 0; - int pitch; - float fvol; - - pitch = 95 + RANDOM_LONG(0,29); - - if (pitch > 97 && pitch < 103) - pitch = 100; - - // The more negative pev->health, the louder - // the sound should be. - - fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0); - - if (fvol > 1.0) - fvol = 1.0; - - - switch (m_Material) - { - case matGlass: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_GLASS; - break; - - case matWood: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_WOOD; - break; - - case matComputer: - case matMetal: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_METAL; - break; - - case matFlesh: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_FLESH; - break; - - case matRocks: - case matCinderBlock: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_CONCRETE; - break; - - case matCeilingTile: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - - - if (m_Explosion == expDirected) - vecVelocity = g_vecAttackDir * 200; - else - { - vecVelocity.x = 0; - vecVelocity.y = 0; - vecVelocity.z = 0; - } - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( pev->size.x); - WRITE_COORD( pev->size.y); - WRITE_COORD( pev->size.z); - - // velocity - WRITE_COORD( vecVelocity.x ); - WRITE_COORD( vecVelocity.y ); - WRITE_COORD( vecVelocity.z ); - - // randomization - WRITE_BYTE( 10 ); - - // Model - WRITE_SHORT( m_idShard ); //model id# - - // # of shards - WRITE_BYTE( 0 ); // let client decide - - // duration - WRITE_BYTE( 25 );// 2.5 seconds - - // flags - WRITE_BYTE( cFlag ); - MESSAGE_END(); - - float size = pev->size.x; - if ( size < pev->size.y ) - size = pev->size.y; - if ( size < pev->size.z ) - size = pev->size.z; - - // !!! HACK This should work! - // Build a box above the entity that looks like an 8 pixel high sheet - Vector mins = pev->absmin; - Vector maxs = pev->absmax; - mins.z = pev->absmax.z; - maxs.z += 8; - - // BUGBUG -- can only find 256 entities on a breakable -- should be enough - CBaseEntity *pList[256]; - int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - ClearBits( pList[i]->pev->flags, FL_ONGROUND ); - pList[i]->pev->groundentity = NULL; - } - } - - // Don't fire something that could fire myself - pev->targetname = 0; - - pev->solid = SOLID_NOT; - - // Fire targets on break - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - - // << cgc >> Don't remove entity on death, we need to be able to reset it - //SetThink( SUB_Remove ); - //pev->nextthink = pev->ltime + 0.1; - this->pev->effects = EF_NODRAW; - - if ( m_iszSpawnObject ) - CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); - - - if ( Explodable() ) - { - ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE ); - } -} - - -void CBreakable::ResetEntity() -{ - this->mHasBeenBroken = false; - - this->pev->effects &= ~EF_NODRAW; - this->pev->solid = SOLID_BSP; - this->pev->movetype = MOVETYPE_PUSH; - this->pev->takedamage = DAMAGE_YES; - - // Set health again - this->pev->health = this->pev->max_health; -} - -BOOL CBreakable::IsBreakable( void ) -{ - return (m_Material != matUnbreakableGlass) && (!this->mHasBeenBroken); -} - - -int CBreakable :: DamageDecal( int bitsDamageType ) -{ - if ( m_Material == matGlass ) - return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); - - if ( m_Material == matUnbreakableGlass ) - return DECAL_BPROOF1; - - return CBaseEntity::DamageDecal( bitsDamageType ); -} - -void CBreakable::PrecacheAll() -{ - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); - PRECACHE_MODEL("models/fleshgibs.mdl"); - PRECACHE_SOUND("debris/bustflesh1.wav"); - PRECACHE_SOUND("debris/bustflesh2.wav"); - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); - PRECACHE_MODEL("models/computergibs.mdl"); - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - PRECACHE_MODEL("models/glassgibs.mdl"); - PRECACHE_SOUND("debris/bustglass1.wav"); - PRECACHE_SOUND("debris/bustglass2.wav"); - PRECACHE_MODEL("models/metalplategibs.mdl"); - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - PRECACHE_MODEL("models/cindergibs.mdl"); - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - PRECACHE_MODEL("models/rockgibs.mdl"); - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - PRECACHE_MODEL("models/ceilinggibs.mdl"); - PRECACHE_SOUND("debris/bustceiling.wav"); - PRECACHE_SOUND("debris/wood1.wav"); - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.wav"); - PRECACHE_MODEL("models/woodgibs.mdl"); - - for(int i = matGlass; i < matNone; i++) - { - Materials theMaterial = (Materials)(i); - MaterialSoundPrecache(theMaterial); - } -} - -#include "dlls/cpushable.h" - -TYPEDESCRIPTION CPushable::m_SaveData[] = -{ - DEFINE_FIELD( CPushable, m_maxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPushable, m_soundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CPushable, CBreakable ); - -LINK_ENTITY_TO_CLASS( func_pushable, CPushable ); - -char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" }; - - -void CPushable :: Spawn( void ) -{ - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Spawn(); - else - Precache( ); - - pev->movetype = MOVETYPE_PUSHSTEP; - pev->solid = SOLID_BBOX; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if ( pev->friction > 399 ) - pev->friction = 399; - - m_maxSpeed = 400 - pev->friction; - SetBits( pev->flags, FL_FLOAT ); - pev->friction = 0; - - pev->origin.z += 1; // Pick up off of the floor - UTIL_SetOrigin( pev, pev->origin ); - - // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) - pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005; - m_soundTime = 0; -} - - -void CPushable :: Precache( void ) -{ - for ( int i = 0; i < 3; i++ ) - PRECACHE_SOUND( m_soundNames[i] ); - - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Precache( ); -} - - -void CPushable :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "size") ) - { - int bbox = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - switch( bbox ) - { - case 0: // Point - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - break; - - case 2: // Big Hull!?!? !!!BUGBUG Figure out what this hull really is - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN*2, VEC_DUCK_HULL_MAX*2); - break; - - case 3: // Player duck - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - break; - - default: - case 1: // Player - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - break; - } - - } - else if ( FStrEq(pkvd->szKeyName, "buoyancy") ) - { - pev->skin = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBreakable::KeyValue( pkvd ); -} - - -// Pull the func_pushable -void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !pActivator || !pActivator->IsPlayer() ) - { - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - this->CBreakable::Use( pActivator, pCaller, useType, value ); - return; - } - - if ( pActivator->pev->velocity != g_vecZero ) - Move( pActivator, 0 ); -} - - -void CPushable :: Touch( CBaseEntity *pOther ) -{ - if ( FClassnameIs( pOther->pev, "worldspawn" ) ) - return; - - Move( pOther, 1 ); -} - - -void CPushable :: Move( CBaseEntity *pOther, int push ) -{ - entvars_t* pevToucher = pOther->pev; - int playerTouch = 0; - - // Is entity standing on this pushable ? - if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev ) - { - // Only push if floating - if ( pev->waterlevel > 0 ) - pev->velocity.z += pevToucher->velocity.z * 0.1; - - return; - } - - - if ( pOther->IsPlayer() ) - { - if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull) - return; - playerTouch = 1; - } - - float factor; - - if ( playerTouch ) - { - if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water - { - if ( pev->waterlevel < 1 ) - return; - else - factor = 0.1; - } - else - factor = 1; - } - else - factor = 0.25; - - pev->velocity.x += pevToucher->velocity.x * factor; - pev->velocity.y += pevToucher->velocity.y * factor; - - float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ); - if ( push && (length > MaxSpeed()) ) - { - pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); - pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); - } - if ( playerTouch ) - { - pevToucher->velocity.x = pev->velocity.x; - pevToucher->velocity.y = pev->velocity.y; - if ( (gpGlobals->time - m_soundTime) > 0.7 ) - { - m_soundTime = gpGlobals->time; - if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) ) - { - m_lastSound = RANDOM_LONG(0,2); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM); - // SetThink( StopSound ); - // pev->nextthink = pev->ltime + 0.1; - } - else - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); - } - } -} - -#if 0 -void CPushable::StopSound( void ) -{ - Vector dist = pev->oldorigin - pev->origin; - if ( dist.Length() <= 0 ) - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); -} -#endif - -int CPushable::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - - return 1; -} - diff --git a/main/source/dlls/func_break.h b/main/source/dlls/func_break.h index 23fb6cda..c2960916 100644 --- a/main/source/dlls/func_break.h +++ b/main/source/dlls/func_break.h @@ -1,80 +1,80 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef FUNC_BREAK_H -#define FUNC_BREAK_H - -typedef enum { expRandom, expDirected} Explosions; -typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials; - -#define NUM_SHARDS 6 // this many shards spawned when breakable objects break; - -class CBreakable : public CBaseDelay -{ -public: - // basic functions - void SetMaterial(Materials inMaterial); - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT BreakTouch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void DamageSound( void ); - virtual void ResetEntity(); - static void PrecacheAll(); - ~CBreakable(); - - // breakables use an overridden takedamage - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - // To spark when hit - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - BOOL IsBreakable( void ); - BOOL SparkWhenHit( void ); - - int DamageDecal( int bitsDamageType ); - - void EXPORT Die( void ); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; } - inline int ExplosionMagnitude( void ) { return pev->impulse; } - inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; } - - static void MaterialSoundPrecache( Materials precacheMaterial ); - static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ); - static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount ); - - static const char *pSoundsWood[]; - static const char *pSoundsFlesh[]; - static const char *pSoundsGlass[]; - static const char *pSoundsMetal[]; - static const char *pSoundsConcrete[]; - static const char *pSpawnObjects[]; - - static TYPEDESCRIPTION m_SaveData[]; - - Materials m_Material; - Explosions m_Explosion; - int m_idShard; - float m_angle; - int m_iszGibModel; - int m_iszSpawnObject; - - bool mHasBeenBroken; -}; - -#endif // FUNC_BREAK_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef FUNC_BREAK_H +#define FUNC_BREAK_H + +typedef enum { expRandom, expDirected} Explosions; +typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials; + +#define NUM_SHARDS 6 // this many shards spawned when breakable objects break; + +class CBreakable : public CBaseDelay +{ +public: + // basic functions + void SetMaterial(Materials inMaterial); + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData* pkvd); + void EXPORT BreakTouch( CBaseEntity *pOther ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void DamageSound( void ); + virtual void ResetEntity(); + static void PrecacheAll(); + ~CBreakable(); + + // breakables use an overridden takedamage + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + // To spark when hit + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); + + BOOL IsBreakable( void ); + BOOL SparkWhenHit( void ); + + int DamageDecal( int bitsDamageType ); + + void EXPORT Die( void ); + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; } + inline int ExplosionMagnitude( void ) { return pev->impulse; } + inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; } + + static void MaterialSoundPrecache( Materials precacheMaterial ); + static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ); + static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount ); + + static const char *pSoundsWood[]; + static const char *pSoundsFlesh[]; + static const char *pSoundsGlass[]; + static const char *pSoundsMetal[]; + static const char *pSoundsConcrete[]; + static const char *pSpawnObjects[]; + + static TYPEDESCRIPTION m_SaveData[]; + + Materials m_Material; + Explosions m_Explosion; + int m_idShard; + float m_angle; + int m_iszGibModel; + int m_iszSpawnObject; + + bool mHasBeenBroken; +}; + +#endif // FUNC_BREAK_H diff --git a/main/source/dlls/func_tank.cpp b/main/source/dlls/func_tank.cpp index 626bac13..9b87d34a 100644 --- a/main/source/dlls/func_tank.cpp +++ b/main/source/dlls/func_tank.cpp @@ -1,1039 +1,1039 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "effects.h" -#include "weapons.h" -#include "explode.h" -#include -#include "player.h" - - -#define SF_TANK_ACTIVE 0x0001 -#define SF_TANK_PLAYER 0x0002 -#define SF_TANK_HUMANS 0x0004 -#define SF_TANK_ALIENS 0x0008 -#define SF_TANK_LINEOFSIGHT 0x0010 -#define SF_TANK_CANCONTROL 0x0020 -#define SF_TANK_SOUNDON 0x8000 - -enum TANKBULLET -{ - TANK_BULLET_NONE = 0, - TANK_BULLET_9MM = 1, - TANK_BULLET_MP5 = 2, - TANK_BULLET_12MM = 3, -}; - -// Custom damage -// env_laser (duration is 0.5 rate of fire) -// rockets -// explosion? - -class CFuncTank : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void TrackTarget( void ); - - virtual void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - virtual Vector UpdateTargetPosition( CBaseEntity *pTarget ) - { - return pTarget->BodyTarget( pev->origin ); - } - - void StartRotSound( void ); - void StopRotSound( void ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - inline BOOL IsActive( void ) { return (pev->spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } - inline void TankActivate( void ) { pev->spawnflags |= SF_TANK_ACTIVE; pev->nextthink = pev->ltime + 0.1; m_fireLast = 0; } - inline void TankDeactivate( void ) { pev->spawnflags &= ~SF_TANK_ACTIVE; m_fireLast = 0; StopRotSound(); } - inline BOOL CanFire( void ) { return (gpGlobals->time - m_lastSightTime) < m_persist; } - BOOL InRange( float range ); - - // Acquire a target. pPlayer is a player in the PVS - edict_t *FindTarget( edict_t *pPlayer ); - - void TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ); - - Vector BarrelPosition( void ) - { - Vector forward, right, up; - UTIL_MakeVectorsPrivate( pev->angles, forward, right, up ); - return pev->origin + (forward * m_barrelPos.x) + (right * m_barrelPos.y) + (up * m_barrelPos.z); - } - - void AdjustAnglesForBarrel( Vector &angles, float distance ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL OnControls( entvars_t *pevTest ); - BOOL StartControl( CBasePlayer* pController ); - void StopControl( void ); - void ControllerPostFrame( void ); - - -protected: - CBasePlayer* m_pController; - float m_flNextAttack; - Vector m_vecControllerUsePos; - - float m_yawCenter; // "Center" yaw - float m_yawRate; // Max turn rate to track targets - float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) - // Zero is full rotation - float m_yawTolerance; // Tolerance angle - - float m_pitchCenter; // "Center" pitch - float m_pitchRate; // Max turn rate on pitch - float m_pitchRange; // Range of pitch motion as above - float m_pitchTolerance; // Tolerance angle - - float m_fireLast; // Last time I fired - float m_fireRate; // How many rounds/second - float m_lastSightTime;// Last time I saw target - float m_persist; // Persistence of firing (how long do I shoot when I can't see) - float m_minRange; // Minimum range to aim/track - float m_maxRange; // Max range to aim/track - - Vector m_barrelPos; // Length of the freakin barrel - float m_spriteScale; // Scale of any sprites we shoot - int m_iszSpriteSmoke; - int m_iszSpriteFlash; - TANKBULLET m_bulletType; // Bullet type - int m_iBulletDamage; // 0 means use Bullet type's default damage - - Vector m_sightOrigin; // Last sight of target - int m_spread; // firing spread - int m_iszMaster; // Master entity (game_team_master or multisource) -}; - - -TYPEDESCRIPTION CFuncTank::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_fireLast, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_fireRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_lastSightTime, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_persist, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_minRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_maxRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_barrelPos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spriteScale, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_iszSpriteSmoke, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_iszSpriteFlash, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_bulletType, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_sightOrigin, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spread, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_pController, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTank, m_vecControllerUsePos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_flNextAttack, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_iBulletDamage, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_iszMaster, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ); - -static Vector gTankSpread[] = -{ - Vector( 0, 0, 0 ), // perfect - Vector( 0.025, 0.025, 0.025 ), // small cone - Vector( 0.05, 0.05, 0.05 ), // medium cone - Vector( 0.1, 0.1, 0.1 ), // large cone - Vector( 0.25, 0.25, 0.25 ), // extra-large cone -}; -#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) - - -void CFuncTank :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_yawCenter = pev->angles.y; - m_pitchCenter = pev->angles.x; - - if ( IsActive() ) - pev->nextthink = pev->ltime + 1.0; - - m_sightOrigin = BarrelPosition(); // Point at the end of the barrel - - if ( m_fireRate <= 0 ) - m_fireRate = 1; - if ( m_spread > MAX_FIRING_SPREADS ) - m_spread = 0; - - pev->oldorigin = pev->origin; -} - - -void CFuncTank :: Precache( void ) -{ - if ( m_iszSpriteSmoke ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteSmoke) ); - if ( m_iszSpriteFlash ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteFlash) ); - - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); -} - - -void CFuncTank :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "yawrate")) - { - m_yawRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawrange")) - { - m_yawRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawtolerance")) - { - m_yawTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrange")) - { - m_pitchRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrate")) - { - m_pitchRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchtolerance")) - { - m_pitchTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firerate")) - { - m_fireRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrel")) - { - m_barrelPos.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrely")) - { - m_barrelPos.y = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrelz")) - { - m_barrelPos.z = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritescale")) - { - m_spriteScale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritesmoke")) - { - m_iszSpriteSmoke = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spriteflash")) - { - m_iszSpriteFlash = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotatesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "persistence")) - { - m_persist = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bullet")) - { - m_bulletType = (TANKBULLET)atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bullet_damage" )) - { - m_iBulletDamage = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firespread")) - { - m_spread = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "minRange")) - { - m_minRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "maxRange")) - { - m_maxRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_iszMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -////////////// START NEW STUFF ////////////// - -//================================================================================== -// TANK CONTROLLING -BOOL CFuncTank :: OnControls( entvars_t *pevTest ) -{ - if ( !(pev->spawnflags & SF_TANK_CANCONTROL) ) - return FALSE; - - Vector offset = pevTest->origin - pev->origin; - - if ( (m_vecControllerUsePos - pevTest->origin).Length() < 30 ) - return TRUE; - - return FALSE; -} - -BOOL CFuncTank :: StartControl( CBasePlayer *pController ) -{ - if ( m_pController != NULL ) - return FALSE; - - // Team only or disabled? - if ( m_iszMaster ) - { - if ( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) - return FALSE; - } - - ALERT( at_console, "using TANK!\n"); - - m_pController = pController; - if ( m_pController->m_pActiveItem ) - { - m_pController->m_pActiveItem->Holster(); - m_pController->pev->weaponmodel = 0; - m_pController->pev->viewmodel = 0; - - } - - m_pController->m_iHideHUD |= HIDEHUD_WEAPONS; - m_vecControllerUsePos = m_pController->pev->origin; - - pev->nextthink = pev->ltime + 0.1; - - return TRUE; -} - -void CFuncTank :: StopControl() -{ - // TODO: bring back the controllers current weapon - if ( !m_pController ) - return; - - if ( m_pController->m_pActiveItem ) - m_pController->m_pActiveItem->Deploy(); - - ALERT( at_console, "stopped using TANK\n"); - - m_pController->m_iHideHUD &= ~HIDEHUD_WEAPONS; - - pev->nextthink = 0; - m_pController = NULL; - - if ( IsActive() ) - pev->nextthink = pev->ltime + 1.0; -} - -// Called each frame by the player's ItemPostFrame -void CFuncTank :: ControllerPostFrame( void ) -{ - ASSERT(m_pController != NULL); - - if ( gpGlobals->time < m_flNextAttack ) - return; - - if ( m_pController->pev->button & IN_ATTACK ) - { - Vector vecForward; - UTIL_MakeVectorsPrivate( pev->angles, vecForward, NULL, NULL ); - - m_fireLast = gpGlobals->time - (1/m_fireRate) - 0.01; // to make sure the gun doesn't fire too many bullets - - Fire( BarrelPosition(), vecForward, m_pController->pev ); - - // HACKHACK -- make some noise (that the AI can hear) - if ( m_pController && m_pController->IsPlayer() ) - ((CBasePlayer *)m_pController)->m_iWeaponVolume = LOUD_GUN_VOLUME; - - m_flNextAttack = gpGlobals->time + (1/m_fireRate); - } -} -////////////// END NEW STUFF ////////////// - - -void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TANK_CANCONTROL ) - { // player controlled turret - - if ( pActivator->Classify() != CLASS_PLAYER ) - return; - - if ( value == 2 && useType == USE_SET ) - { - ControllerPostFrame(); - } - else if ( !m_pController && useType != USE_OFF ) - { - ((CBasePlayer*)pActivator)->m_pTank = this; - StartControl( (CBasePlayer*)pActivator ); - } - else - { - StopControl(); - } - } - else - { - if ( !ShouldToggle( useType, IsActive() ) ) - return; - - if ( IsActive() ) - TankDeactivate(); - else - TankActivate(); - } -} - - -edict_t *CFuncTank :: FindTarget( edict_t *pPlayer ) -{ - return pPlayer; -} - - - -BOOL CFuncTank :: InRange( float range ) -{ - if ( range < m_minRange ) - return FALSE; - if ( m_maxRange > 0 && range > m_maxRange ) - return FALSE; - - return TRUE; -} - - -void CFuncTank :: Think( void ) -{ - pev->avelocity = g_vecZero; - TrackTarget(); - - if ( fabs(pev->avelocity.x) > 1 || fabs(pev->avelocity.y) > 1 ) - StartRotSound(); - else - StopRotSound(); -} - -void CFuncTank::TrackTarget( void ) -{ - TraceResult tr; - edict_t *pPlayer = FIND_CLIENT_IN_PVS( edict() ); - BOOL updateTime = FALSE, lineOfSight; - Vector angles, direction, targetPosition, barrelEnd; - edict_t *pTarget; - - // Get a position to aim for - if (m_pController) - { - // Tanks attempt to mirror the player's angles - angles = m_pController->pev->v_angle; - angles[0] = 0 - angles[0]; - pev->nextthink = pev->ltime + 0.05; - } - else - { - if ( IsActive() ) - pev->nextthink = pev->ltime + 0.1; - else - return; - - if ( FNullEnt( pPlayer ) ) - { - if ( IsActive() ) - pev->nextthink = pev->ltime + 2; // Wait 2 secs - return; - } - pTarget = FindTarget( pPlayer ); - if ( !pTarget ) - return; - - // Calculate angle needed to aim at target - barrelEnd = BarrelPosition(); - targetPosition = pTarget->v.origin + pTarget->v.view_ofs; - float range = (targetPosition - barrelEnd).Length(); - - if ( !InRange( range ) ) - return; - - UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); - - lineOfSight = FALSE; - // No line of sight, don't track - if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) - { - lineOfSight = TRUE; - - CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); - if ( InRange( range ) && pInstance && pInstance->IsAlive() ) - { - updateTime = TRUE; - m_sightOrigin = UpdateTargetPosition( pInstance ); - } - } - - // Track sight origin - -// !!! I'm not sure what i changed - direction = m_sightOrigin - pev->origin; -// direction = m_sightOrigin - barrelEnd; - angles = UTIL_VecToAngles( direction ); - - // Calculate the additional rotation to point the end of the barrel at the target (not the gun's center) - AdjustAnglesForBarrel( angles, direction.Length() ); - } - - angles.x = -angles.x; - - // Force the angles to be relative to the center position - angles.y = m_yawCenter + UTIL_AngleDistance( angles.y, m_yawCenter ); - angles.x = m_pitchCenter + UTIL_AngleDistance( angles.x, m_pitchCenter ); - - // Limit against range in y - if ( angles.y > m_yawCenter + m_yawRange ) - { - angles.y = m_yawCenter + m_yawRange; - updateTime = FALSE; // Don't update if you saw the player, but out of range - } - else if ( angles.y < (m_yawCenter - m_yawRange) ) - { - angles.y = (m_yawCenter - m_yawRange); - updateTime = FALSE; // Don't update if you saw the player, but out of range - } - - if ( updateTime ) - m_lastSightTime = gpGlobals->time; - - // Move toward target at rate or less - float distY = UTIL_AngleDistance( angles.y, pev->angles.y ); - pev->avelocity.y = distY * 10; - if ( pev->avelocity.y > m_yawRate ) - pev->avelocity.y = m_yawRate; - else if ( pev->avelocity.y < -m_yawRate ) - pev->avelocity.y = -m_yawRate; - - // Limit against range in x - if ( angles.x > m_pitchCenter + m_pitchRange ) - angles.x = m_pitchCenter + m_pitchRange; - else if ( angles.x < m_pitchCenter - m_pitchRange ) - angles.x = m_pitchCenter - m_pitchRange; - - // Move toward target at rate or less - float distX = UTIL_AngleDistance( angles.x, pev->angles.x ); - pev->avelocity.x = distX * 10; - - if ( pev->avelocity.x > m_pitchRate ) - pev->avelocity.x = m_pitchRate; - else if ( pev->avelocity.x < -m_pitchRate ) - pev->avelocity.x = -m_pitchRate; - - if ( m_pController ) - return; - - if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT) ) ) - { - BOOL fire = FALSE; - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - if ( pev->spawnflags & SF_TANK_LINEOFSIGHT ) - { - float length = direction.Length(); - UTIL_TraceLine( barrelEnd, barrelEnd + forward * length, dont_ignore_monsters, edict(), &tr ); - if ( tr.pHit == pTarget ) - fire = TRUE; - } - else - fire = TRUE; - - if ( fire ) - { - Fire( BarrelPosition(), forward, pev ); - } - else - m_fireLast = 0; - } - else - m_fireLast = 0; -} - - -// If barrel is offset, add in additional rotation -void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) -{ - float r2, d2; - - - if ( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) - { - distance -= m_barrelPos.z; - d2 = distance * distance; - if ( m_barrelPos.y ) - { - r2 = m_barrelPos.y * m_barrelPos.y; - angles.y += (180.0 / M_PI) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); - } - if ( m_barrelPos.z ) - { - r2 = m_barrelPos.z * m_barrelPos.z; - angles.x += (180.0 / M_PI) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); - } - } -} - - -// Fire targets and spawn sprites -void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - if ( m_iszSpriteSmoke ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteSmoke), barrelEnd, TRUE ); - pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); - pSprite->SetTransparency( kRenderTransAlpha, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, 255, kRenderFxNone ); - pSprite->pev->velocity.z = RANDOM_FLOAT(40, 80); - pSprite->SetScale( m_spriteScale ); - } - if ( m_iszSpriteFlash ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteFlash), barrelEnd, TRUE ); - pSprite->AnimateAndDie( 60 ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - pSprite->SetScale( m_spriteScale ); - - // Hack Hack, make it stick around for at least 100 ms. - pSprite->pev->nextthink += 0.1; - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); - } - m_fireLast = gpGlobals->time; -} - - -void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ) -{ - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - Vector vecDir = vecForward + - x * vecSpread.x * gpGlobals->v_right + - y * vecSpread.y * gpGlobals->v_up; - Vector vecEnd; - - vecEnd = vecStart + vecDir * 4096; - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &tr ); -} - - -void CFuncTank::StartRotSound( void ) -{ - if ( !pev->noise || (pev->spawnflags & SF_TANK_SOUNDON) ) - return; - pev->spawnflags |= SF_TANK_SOUNDON; - EMIT_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise), 0.85, ATTN_NORM); -} - - -void CFuncTank::StopRotSound( void ) -{ - if ( pev->spawnflags & SF_TANK_SOUNDON ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); - pev->spawnflags &= ~SF_TANK_SOUNDON; -} - -class CFuncTankGun : public CFuncTank -{ -public: - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ); - -void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - // FireBullets needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - switch( m_bulletType ) - { - case TANK_BULLET_9MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_9MM, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_MP5: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_MP5, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_12MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_12MM, 1, m_iBulletDamage, pevAttacker ); - break; - - default: - case TANK_BULLET_NONE: - break; - } - } - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); -} - - - -class CFuncTankLaser : public CFuncTank -{ -public: - void Activate( void ); - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - void Think( void ); - CLaser *GetLaser( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - CLaser *m_pLaser; - float m_laserTime; -}; -LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ); - -TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankLaser, m_pLaser, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ); - -void CFuncTankLaser::Activate( void ) -{ - if ( !GetLaser() ) - { - UTIL_Remove(this); - ALERT( at_error, "Laser tank with no env_laser!\n" ); - } - else - { - m_pLaser->TurnOff(); - } -} - - -void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "laserentity")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -CLaser *CFuncTankLaser::GetLaser( void ) -{ - if ( m_pLaser ) - return m_pLaser; - - edict_t *pentLaser; - - pentLaser = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->message) ); - while ( !FNullEnt( pentLaser ) ) - { - // Found the landmark - if ( FClassnameIs( pentLaser, "env_laser" ) ) - { - m_pLaser = (CLaser *)CBaseEntity::Instance(pentLaser); - break; - } - else - pentLaser = FIND_ENTITY_BY_TARGETNAME( pentLaser, STRING(pev->message) ); - } - - return m_pLaser; -} - - -void CFuncTankLaser::Think( void ) -{ - if ( m_pLaser && (gpGlobals->time > m_laserTime) ) - m_pLaser->TurnOff(); - - CFuncTank::Think(); -} - - -void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - TraceResult tr; - - if ( m_fireLast != 0 && GetLaser() ) - { - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount ) - { - for ( i = 0; i < bulletCount; i++ ) - { - m_pLaser->pev->origin = barrelEnd; - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - m_laserTime = gpGlobals->time; - m_pLaser->TurnOn(); - m_pLaser->pev->dmgtime = gpGlobals->time - 1.0; - m_pLaser->FireAtPoint( tr ); - m_pLaser->pev->nextthink = 0; - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - { - CFuncTank::Fire( barrelEnd, forward, pev ); - } -} - -class CFuncTankRocket : public CFuncTank -{ -public: - void Precache( void ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ); - -void CFuncTankRocket::Precache( void ) -{ - UTIL_PrecacheOther( "rpg_rocket" ); - CFuncTank::Precache(); -} - - - -void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - CBaseEntity *pRocket = CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pev ); -} - - -class CFuncTankMortar : public CFuncTank -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); - - -void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iMagnitude")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - // Only create 1 explosion - if ( bulletCount > 0 ) - { - TraceResult tr; - - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE ); - - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pev ); -} - - - -//============================================================================ -// FUNC TANK CONTROLS -//============================================================================ -class CFuncTankControls : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CFuncTank *m_pTank; -}; -LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ); - -TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankControls, m_pTank, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ); - -int CFuncTankControls :: ObjectCaps( void ) -{ - return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; -} - - -void CFuncTankControls :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ // pass the Use command onto the controls - if ( m_pTank ) - m_pTank->Use( pActivator, pCaller, useType, value ); - - ASSERT( m_pTank != NULL ); // if this fails, most likely means save/restore hasn't worked properly -} - - -void CFuncTankControls :: Think( void ) -{ - edict_t *pTarget = NULL; - - do - { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && strncmp( STRING(pTarget->v.classname), "func_tank", 9 ) ); - - if ( FNullEnt( pTarget ) ) - { - ALERT( at_console, "No tank %s\n", STRING(pev->target) ); - return; - } - - m_pTank = (CFuncTank*)Instance(pTarget); -} - -void CFuncTankControls::Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NODRAW; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->nextthink = gpGlobals->time + 0.3; // After all the func_tank's have spawned - - CBaseEntity::Spawn(); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "effects.h" +#include "weapons.h" +#include "explode.h" +#include +#include "player.h" + + +#define SF_TANK_ACTIVE 0x0001 +#define SF_TANK_PLAYER 0x0002 +#define SF_TANK_HUMANS 0x0004 +#define SF_TANK_ALIENS 0x0008 +#define SF_TANK_LINEOFSIGHT 0x0010 +#define SF_TANK_CANCONTROL 0x0020 +#define SF_TANK_SOUNDON 0x8000 + +enum TANKBULLET +{ + TANK_BULLET_NONE = 0, + TANK_BULLET_9MM = 1, + TANK_BULLET_MP5 = 2, + TANK_BULLET_12MM = 3, +}; + +// Custom damage +// env_laser (duration is 0.5 rate of fire) +// rockets +// explosion? + +class CFuncTank : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Think( void ); + void TrackTarget( void ); + + virtual void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); + virtual Vector UpdateTargetPosition( CBaseEntity *pTarget ) + { + return pTarget->BodyTarget( pev->origin ); + } + + void StartRotSound( void ); + void StopRotSound( void ); + + // Bmodels don't go across transitions + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + inline BOOL IsActive( void ) { return (pev->spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } + inline void TankActivate( void ) { pev->spawnflags |= SF_TANK_ACTIVE; pev->nextthink = pev->ltime + 0.1; m_fireLast = 0; } + inline void TankDeactivate( void ) { pev->spawnflags &= ~SF_TANK_ACTIVE; m_fireLast = 0; StopRotSound(); } + inline BOOL CanFire( void ) { return (gpGlobals->time - m_lastSightTime) < m_persist; } + BOOL InRange( float range ); + + // Acquire a target. pPlayer is a player in the PVS + edict_t *FindTarget( edict_t *pPlayer ); + + void TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ); + + Vector BarrelPosition( void ) + { + Vector forward, right, up; + UTIL_MakeVectorsPrivate( pev->angles, forward, right, up ); + return pev->origin + (forward * m_barrelPos.x) + (right * m_barrelPos.y) + (up * m_barrelPos.z); + } + + void AdjustAnglesForBarrel( Vector &angles, float distance ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + BOOL OnControls( entvars_t *pevTest ); + BOOL StartControl( CBasePlayer* pController ); + void StopControl( void ); + void ControllerPostFrame( void ); + + +protected: + CBasePlayer* m_pController; + float m_flNextAttack; + Vector m_vecControllerUsePos; + + float m_yawCenter; // "Center" yaw + float m_yawRate; // Max turn rate to track targets + float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) + // Zero is full rotation + float m_yawTolerance; // Tolerance angle + + float m_pitchCenter; // "Center" pitch + float m_pitchRate; // Max turn rate on pitch + float m_pitchRange; // Range of pitch motion as above + float m_pitchTolerance; // Tolerance angle + + float m_fireLast; // Last time I fired + float m_fireRate; // How many rounds/second + float m_lastSightTime;// Last time I saw target + float m_persist; // Persistence of firing (how long do I shoot when I can't see) + float m_minRange; // Minimum range to aim/track + float m_maxRange; // Max range to aim/track + + Vector m_barrelPos; // Length of the freakin barrel + float m_spriteScale; // Scale of any sprites we shoot + int m_iszSpriteSmoke; + int m_iszSpriteFlash; + TANKBULLET m_bulletType; // Bullet type + int m_iBulletDamage; // 0 means use Bullet type's default damage + + Vector m_sightOrigin; // Last sight of target + int m_spread; // firing spread + int m_iszMaster; // Master entity (game_team_master or multisource) +}; + + +TYPEDESCRIPTION CFuncTank::m_SaveData[] = +{ + DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_yawRate, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_yawRange, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_yawTolerance, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_pitchCenter, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_pitchRate, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_pitchRange, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_pitchTolerance, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_fireLast, FIELD_TIME ), + DEFINE_FIELD( CFuncTank, m_fireRate, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_lastSightTime, FIELD_TIME ), + DEFINE_FIELD( CFuncTank, m_persist, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_minRange, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_maxRange, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_barrelPos, FIELD_VECTOR ), + DEFINE_FIELD( CFuncTank, m_spriteScale, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTank, m_iszSpriteSmoke, FIELD_STRING ), + DEFINE_FIELD( CFuncTank, m_iszSpriteFlash, FIELD_STRING ), + DEFINE_FIELD( CFuncTank, m_bulletType, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTank, m_sightOrigin, FIELD_VECTOR ), + DEFINE_FIELD( CFuncTank, m_spread, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTank, m_pController, FIELD_CLASSPTR ), + DEFINE_FIELD( CFuncTank, m_vecControllerUsePos, FIELD_VECTOR ), + DEFINE_FIELD( CFuncTank, m_flNextAttack, FIELD_TIME ), + DEFINE_FIELD( CFuncTank, m_iBulletDamage, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTank, m_iszMaster, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ); + +static Vector gTankSpread[] = +{ + Vector( 0, 0, 0 ), // perfect + Vector( 0.025, 0.025, 0.025 ), // small cone + Vector( 0.05, 0.05, 0.05 ), // medium cone + Vector( 0.1, 0.1, 0.1 ), // large cone + Vector( 0.25, 0.25, 0.25 ), // extra-large cone +}; +#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) + + +void CFuncTank :: Spawn( void ) +{ + Precache(); + + pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything + pev->solid = SOLID_BSP; + SET_MODEL( ENT(pev), STRING(pev->model) ); + + m_yawCenter = pev->angles.y; + m_pitchCenter = pev->angles.x; + + if ( IsActive() ) + pev->nextthink = pev->ltime + 1.0; + + m_sightOrigin = BarrelPosition(); // Point at the end of the barrel + + if ( m_fireRate <= 0 ) + m_fireRate = 1; + if ( m_spread > MAX_FIRING_SPREADS ) + m_spread = 0; + + pev->oldorigin = pev->origin; +} + + +void CFuncTank :: Precache( void ) +{ + if ( m_iszSpriteSmoke ) + PRECACHE_MODEL( (char *)STRING(m_iszSpriteSmoke) ); + if ( m_iszSpriteFlash ) + PRECACHE_MODEL( (char *)STRING(m_iszSpriteFlash) ); + + if ( pev->noise ) + PRECACHE_SOUND( (char *)STRING(pev->noise) ); +} + + +void CFuncTank :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "yawrate")) + { + m_yawRate = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "yawrange")) + { + m_yawRange = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "yawtolerance")) + { + m_yawTolerance = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "pitchrange")) + { + m_pitchRange = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "pitchrate")) + { + m_pitchRate = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "pitchtolerance")) + { + m_pitchTolerance = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "firerate")) + { + m_fireRate = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "barrel")) + { + m_barrelPos.x = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "barrely")) + { + m_barrelPos.y = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "barrelz")) + { + m_barrelPos.z = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "spritescale")) + { + m_spriteScale = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "spritesmoke")) + { + m_iszSpriteSmoke = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "spriteflash")) + { + m_iszSpriteFlash = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "rotatesound")) + { + pev->noise = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "persistence")) + { + m_persist = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "bullet")) + { + m_bulletType = (TANKBULLET)atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "bullet_damage" )) + { + m_iBulletDamage = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "firespread")) + { + m_spread = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "minRange")) + { + m_minRange = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "maxRange")) + { + m_maxRange = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "master")) + { + m_iszMaster = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +////////////// START NEW STUFF ////////////// + +//================================================================================== +// TANK CONTROLLING +BOOL CFuncTank :: OnControls( entvars_t *pevTest ) +{ + if ( !(pev->spawnflags & SF_TANK_CANCONTROL) ) + return FALSE; + + Vector offset = pevTest->origin - pev->origin; + + if ( (m_vecControllerUsePos - pevTest->origin).Length() < 30 ) + return TRUE; + + return FALSE; +} + +BOOL CFuncTank :: StartControl( CBasePlayer *pController ) +{ + if ( m_pController != NULL ) + return FALSE; + + // Team only or disabled? + if ( m_iszMaster ) + { + if ( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) + return FALSE; + } + + ALERT( at_console, "using TANK!\n"); + + m_pController = pController; + if ( m_pController->m_pActiveItem ) + { + m_pController->m_pActiveItem->Holster(); + m_pController->pev->weaponmodel = 0; + m_pController->pev->viewmodel = 0; + + } + + m_pController->m_iHideHUD |= HIDEHUD_WEAPONS; + m_vecControllerUsePos = m_pController->pev->origin; + + pev->nextthink = pev->ltime + 0.1; + + return TRUE; +} + +void CFuncTank :: StopControl() +{ + // TODO: bring back the controllers current weapon + if ( !m_pController ) + return; + + if ( m_pController->m_pActiveItem ) + m_pController->m_pActiveItem->Deploy(); + + ALERT( at_console, "stopped using TANK\n"); + + m_pController->m_iHideHUD &= ~HIDEHUD_WEAPONS; + + pev->nextthink = 0; + m_pController = NULL; + + if ( IsActive() ) + pev->nextthink = pev->ltime + 1.0; +} + +// Called each frame by the player's ItemPostFrame +void CFuncTank :: ControllerPostFrame( void ) +{ + ASSERT(m_pController != NULL); + + if ( gpGlobals->time < m_flNextAttack ) + return; + + if ( m_pController->pev->button & IN_ATTACK ) + { + Vector vecForward; + UTIL_MakeVectorsPrivate( pev->angles, vecForward, NULL, NULL ); + + m_fireLast = gpGlobals->time - (1/m_fireRate) - 0.01; // to make sure the gun doesn't fire too many bullets + + Fire( BarrelPosition(), vecForward, m_pController->pev ); + + // HACKHACK -- make some noise (that the AI can hear) + if ( m_pController && m_pController->IsPlayer() ) + ((CBasePlayer *)m_pController)->m_iWeaponVolume = LOUD_GUN_VOLUME; + + m_flNextAttack = gpGlobals->time + (1/m_fireRate); + } +} +////////////// END NEW STUFF ////////////// + + +void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( pev->spawnflags & SF_TANK_CANCONTROL ) + { // player controlled turret + + if ( pActivator->Classify() != CLASS_PLAYER ) + return; + + if ( value == 2 && useType == USE_SET ) + { + ControllerPostFrame(); + } + else if ( !m_pController && useType != USE_OFF ) + { + ((CBasePlayer*)pActivator)->m_pTank = this; + StartControl( (CBasePlayer*)pActivator ); + } + else + { + StopControl(); + } + } + else + { + if ( !ShouldToggle( useType, IsActive() ) ) + return; + + if ( IsActive() ) + TankDeactivate(); + else + TankActivate(); + } +} + + +edict_t *CFuncTank :: FindTarget( edict_t *pPlayer ) +{ + return pPlayer; +} + + + +BOOL CFuncTank :: InRange( float range ) +{ + if ( range < m_minRange ) + return FALSE; + if ( m_maxRange > 0 && range > m_maxRange ) + return FALSE; + + return TRUE; +} + + +void CFuncTank :: Think( void ) +{ + pev->avelocity = g_vecZero; + TrackTarget(); + + if ( fabs(pev->avelocity.x) > 1 || fabs(pev->avelocity.y) > 1 ) + StartRotSound(); + else + StopRotSound(); +} + +void CFuncTank::TrackTarget( void ) +{ + TraceResult tr; + edict_t *pPlayer = FIND_CLIENT_IN_PVS( edict() ); + BOOL updateTime = FALSE, lineOfSight; + Vector angles, direction, targetPosition, barrelEnd; + edict_t *pTarget; + + // Get a position to aim for + if (m_pController) + { + // Tanks attempt to mirror the player's angles + angles = m_pController->pev->v_angle; + angles[0] = 0 - angles[0]; + pev->nextthink = pev->ltime + 0.05; + } + else + { + if ( IsActive() ) + pev->nextthink = pev->ltime + 0.1; + else + return; + + if ( FNullEnt( pPlayer ) ) + { + if ( IsActive() ) + pev->nextthink = pev->ltime + 2; // Wait 2 secs + return; + } + pTarget = FindTarget( pPlayer ); + if ( !pTarget ) + return; + + // Calculate angle needed to aim at target + barrelEnd = BarrelPosition(); + targetPosition = pTarget->v.origin + pTarget->v.view_ofs; + float range = (targetPosition - barrelEnd).Length(); + + if ( !InRange( range ) ) + return; + + UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); + + lineOfSight = FALSE; + // No line of sight, don't track + if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) + { + lineOfSight = TRUE; + + CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); + if ( InRange( range ) && pInstance && pInstance->IsAlive() ) + { + updateTime = TRUE; + m_sightOrigin = UpdateTargetPosition( pInstance ); + } + } + + // Track sight origin + +// !!! I'm not sure what i changed + direction = m_sightOrigin - pev->origin; +// direction = m_sightOrigin - barrelEnd; + angles = UTIL_VecToAngles( direction ); + + // Calculate the additional rotation to point the end of the barrel at the target (not the gun's center) + AdjustAnglesForBarrel( angles, direction.Length() ); + } + + angles.x = -angles.x; + + // Force the angles to be relative to the center position + angles.y = m_yawCenter + UTIL_AngleDistance( angles.y, m_yawCenter ); + angles.x = m_pitchCenter + UTIL_AngleDistance( angles.x, m_pitchCenter ); + + // Limit against range in y + if ( angles.y > m_yawCenter + m_yawRange ) + { + angles.y = m_yawCenter + m_yawRange; + updateTime = FALSE; // Don't update if you saw the player, but out of range + } + else if ( angles.y < (m_yawCenter - m_yawRange) ) + { + angles.y = (m_yawCenter - m_yawRange); + updateTime = FALSE; // Don't update if you saw the player, but out of range + } + + if ( updateTime ) + m_lastSightTime = gpGlobals->time; + + // Move toward target at rate or less + float distY = UTIL_AngleDistance( angles.y, pev->angles.y ); + pev->avelocity.y = distY * 10; + if ( pev->avelocity.y > m_yawRate ) + pev->avelocity.y = m_yawRate; + else if ( pev->avelocity.y < -m_yawRate ) + pev->avelocity.y = -m_yawRate; + + // Limit against range in x + if ( angles.x > m_pitchCenter + m_pitchRange ) + angles.x = m_pitchCenter + m_pitchRange; + else if ( angles.x < m_pitchCenter - m_pitchRange ) + angles.x = m_pitchCenter - m_pitchRange; + + // Move toward target at rate or less + float distX = UTIL_AngleDistance( angles.x, pev->angles.x ); + pev->avelocity.x = distX * 10; + + if ( pev->avelocity.x > m_pitchRate ) + pev->avelocity.x = m_pitchRate; + else if ( pev->avelocity.x < -m_pitchRate ) + pev->avelocity.x = -m_pitchRate; + + if ( m_pController ) + return; + + if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT) ) ) + { + BOOL fire = FALSE; + Vector forward; + UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); + + if ( pev->spawnflags & SF_TANK_LINEOFSIGHT ) + { + float length = direction.Length(); + UTIL_TraceLine( barrelEnd, barrelEnd + forward * length, dont_ignore_monsters, edict(), &tr ); + if ( tr.pHit == pTarget ) + fire = TRUE; + } + else + fire = TRUE; + + if ( fire ) + { + Fire( BarrelPosition(), forward, pev ); + } + else + m_fireLast = 0; + } + else + m_fireLast = 0; +} + + +// If barrel is offset, add in additional rotation +void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) +{ + float r2, d2; + + + if ( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) + { + distance -= m_barrelPos.z; + d2 = distance * distance; + if ( m_barrelPos.y ) + { + r2 = m_barrelPos.y * m_barrelPos.y; + angles.y += (180.0 / M_PI) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); + } + if ( m_barrelPos.z ) + { + r2 = m_barrelPos.z * m_barrelPos.z; + angles.x += (180.0 / M_PI) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); + } + } +} + + +// Fire targets and spawn sprites +void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) +{ + if ( m_fireLast != 0 ) + { + if ( m_iszSpriteSmoke ) + { + CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteSmoke), barrelEnd, TRUE ); + pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); + pSprite->SetTransparency( kRenderTransAlpha, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, 255, kRenderFxNone ); + pSprite->pev->velocity.z = RANDOM_FLOAT(40, 80); + pSprite->SetScale( m_spriteScale ); + } + if ( m_iszSpriteFlash ) + { + CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteFlash), barrelEnd, TRUE ); + pSprite->AnimateAndDie( 60 ); + pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); + pSprite->SetScale( m_spriteScale ); + + // Hack Hack, make it stick around for at least 100 ms. + pSprite->pev->nextthink += 0.1; + } + SUB_UseTargets( this, USE_TOGGLE, 0 ); + } + m_fireLast = gpGlobals->time; +} + + +void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ) +{ + // get circular gaussian spread + float x, y, z; + do { + x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); + y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); + z = x*x+y*y; + } while (z > 1); + Vector vecDir = vecForward + + x * vecSpread.x * gpGlobals->v_right + + y * vecSpread.y * gpGlobals->v_up; + Vector vecEnd; + + vecEnd = vecStart + vecDir * 4096; + UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &tr ); +} + + +void CFuncTank::StartRotSound( void ) +{ + if ( !pev->noise || (pev->spawnflags & SF_TANK_SOUNDON) ) + return; + pev->spawnflags |= SF_TANK_SOUNDON; + EMIT_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise), 0.85, ATTN_NORM); +} + + +void CFuncTank::StopRotSound( void ) +{ + if ( pev->spawnflags & SF_TANK_SOUNDON ) + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); + pev->spawnflags &= ~SF_TANK_SOUNDON; +} + +class CFuncTankGun : public CFuncTank +{ +public: + void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); +}; +LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ); + +void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) +{ + int i; + + if ( m_fireLast != 0 ) + { + // FireBullets needs gpGlobals->v_up, etc. + UTIL_MakeAimVectors(pev->angles); + + int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; + if ( bulletCount > 0 ) + { + for ( i = 0; i < bulletCount; i++ ) + { + switch( m_bulletType ) + { + case TANK_BULLET_9MM: + FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_9MM, 1, m_iBulletDamage, pevAttacker ); + break; + + case TANK_BULLET_MP5: + FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_MP5, 1, m_iBulletDamage, pevAttacker ); + break; + + case TANK_BULLET_12MM: + FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_12MM, 1, m_iBulletDamage, pevAttacker ); + break; + + default: + case TANK_BULLET_NONE: + break; + } + } + CFuncTank::Fire( barrelEnd, forward, pevAttacker ); + } + } + else + CFuncTank::Fire( barrelEnd, forward, pevAttacker ); +} + + + +class CFuncTankLaser : public CFuncTank +{ +public: + void Activate( void ); + void KeyValue( KeyValueData *pkvd ); + void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); + void Think( void ); + CLaser *GetLaser( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + +private: + CLaser *m_pLaser; + float m_laserTime; +}; +LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ); + +TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = +{ + DEFINE_FIELD( CFuncTankLaser, m_pLaser, FIELD_CLASSPTR ), + DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ); + +void CFuncTankLaser::Activate( void ) +{ + if ( !GetLaser() ) + { + UTIL_Remove(this); + ALERT( at_error, "Laser tank with no env_laser!\n" ); + } + else + { + m_pLaser->TurnOff(); + } +} + + +void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "laserentity")) + { + pev->message = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CFuncTank::KeyValue( pkvd ); +} + + +CLaser *CFuncTankLaser::GetLaser( void ) +{ + if ( m_pLaser ) + return m_pLaser; + + edict_t *pentLaser; + + pentLaser = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->message) ); + while ( !FNullEnt( pentLaser ) ) + { + // Found the landmark + if ( FClassnameIs( pentLaser, "env_laser" ) ) + { + m_pLaser = (CLaser *)CBaseEntity::Instance(pentLaser); + break; + } + else + pentLaser = FIND_ENTITY_BY_TARGETNAME( pentLaser, STRING(pev->message) ); + } + + return m_pLaser; +} + + +void CFuncTankLaser::Think( void ) +{ + if ( m_pLaser && (gpGlobals->time > m_laserTime) ) + m_pLaser->TurnOff(); + + CFuncTank::Think(); +} + + +void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) +{ + int i; + TraceResult tr; + + if ( m_fireLast != 0 && GetLaser() ) + { + // TankTrace needs gpGlobals->v_up, etc. + UTIL_MakeAimVectors(pev->angles); + + int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; + if ( bulletCount ) + { + for ( i = 0; i < bulletCount; i++ ) + { + m_pLaser->pev->origin = barrelEnd; + TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); + + m_laserTime = gpGlobals->time; + m_pLaser->TurnOn(); + m_pLaser->pev->dmgtime = gpGlobals->time - 1.0; + m_pLaser->FireAtPoint( tr ); + m_pLaser->pev->nextthink = 0; + } + CFuncTank::Fire( barrelEnd, forward, pev ); + } + } + else + { + CFuncTank::Fire( barrelEnd, forward, pev ); + } +} + +class CFuncTankRocket : public CFuncTank +{ +public: + void Precache( void ); + void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); +}; +LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ); + +void CFuncTankRocket::Precache( void ) +{ + UTIL_PrecacheOther( "rpg_rocket" ); + CFuncTank::Precache(); +} + + + +void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) +{ + int i; + + if ( m_fireLast != 0 ) + { + int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; + if ( bulletCount > 0 ) + { + for ( i = 0; i < bulletCount; i++ ) + { + CBaseEntity *pRocket = CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); + } + CFuncTank::Fire( barrelEnd, forward, pev ); + } + } + else + CFuncTank::Fire( barrelEnd, forward, pev ); +} + + +class CFuncTankMortar : public CFuncTank +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); +}; +LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); + + +void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "iMagnitude")) + { + pev->impulse = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CFuncTank::KeyValue( pkvd ); +} + + +void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) +{ + if ( m_fireLast != 0 ) + { + int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; + // Only create 1 explosion + if ( bulletCount > 0 ) + { + TraceResult tr; + + // TankTrace needs gpGlobals->v_up, etc. + UTIL_MakeAimVectors(pev->angles); + + TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); + + ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE ); + + CFuncTank::Fire( barrelEnd, forward, pev ); + } + } + else + CFuncTank::Fire( barrelEnd, forward, pev ); +} + + + +//============================================================================ +// FUNC TANK CONTROLS +//============================================================================ +class CFuncTankControls : public CBaseEntity +{ +public: + virtual int ObjectCaps( void ); + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Think( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + CFuncTank *m_pTank; +}; +LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ); + +TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = +{ + DEFINE_FIELD( CFuncTankControls, m_pTank, FIELD_CLASSPTR ), +}; + +IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ); + +int CFuncTankControls :: ObjectCaps( void ) +{ + return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; +} + + +void CFuncTankControls :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ // pass the Use command onto the controls + if ( m_pTank ) + m_pTank->Use( pActivator, pCaller, useType, value ); + + ASSERT( m_pTank != NULL ); // if this fails, most likely means save/restore hasn't worked properly +} + + +void CFuncTankControls :: Think( void ) +{ + edict_t *pTarget = NULL; + + do + { + pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); + } while ( !FNullEnt(pTarget) && strncmp( STRING(pTarget->v.classname), "func_tank", 9 ) ); + + if ( FNullEnt( pTarget ) ) + { + ALERT( at_console, "No tank %s\n", STRING(pev->target) ); + return; + } + + m_pTank = (CFuncTank*)Instance(pTarget); +} + +void CFuncTankControls::Spawn( void ) +{ + pev->solid = SOLID_TRIGGER; + pev->movetype = MOVETYPE_NONE; + pev->effects |= EF_NODRAW; + SET_MODEL( ENT(pev), STRING(pev->model) ); + + UTIL_SetSize( pev, pev->mins, pev->maxs ); + UTIL_SetOrigin( pev, pev->origin ); + + pev->nextthink = gpGlobals->time + 0.3; // After all the func_tank's have spawned + + CBaseEntity::Spawn(); +} diff --git a/main/source/dlls/func_tank.cpp~ b/main/source/dlls/func_tank.cpp~ deleted file mode 100644 index 648f8309..00000000 --- a/main/source/dlls/func_tank.cpp~ +++ /dev/null @@ -1,1039 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "effects.h" -#include "weapons.h" -#include "explode.h" - -#include "player.h" - - -#define SF_TANK_ACTIVE 0x0001 -#define SF_TANK_PLAYER 0x0002 -#define SF_TANK_HUMANS 0x0004 -#define SF_TANK_ALIENS 0x0008 -#define SF_TANK_LINEOFSIGHT 0x0010 -#define SF_TANK_CANCONTROL 0x0020 -#define SF_TANK_SOUNDON 0x8000 - -enum TANKBULLET -{ - TANK_BULLET_NONE = 0, - TANK_BULLET_9MM = 1, - TANK_BULLET_MP5 = 2, - TANK_BULLET_12MM = 3, -}; - -// Custom damage -// env_laser (duration is 0.5 rate of fire) -// rockets -// explosion? - -class CFuncTank : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void TrackTarget( void ); - - virtual void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - virtual Vector UpdateTargetPosition( CBaseEntity *pTarget ) - { - return pTarget->BodyTarget( pev->origin ); - } - - void StartRotSound( void ); - void StopRotSound( void ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - inline BOOL IsActive( void ) { return (pev->spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } - inline void TankActivate( void ) { pev->spawnflags |= SF_TANK_ACTIVE; pev->nextthink = pev->ltime + 0.1; m_fireLast = 0; } - inline void TankDeactivate( void ) { pev->spawnflags &= ~SF_TANK_ACTIVE; m_fireLast = 0; StopRotSound(); } - inline BOOL CanFire( void ) { return (gpGlobals->time - m_lastSightTime) < m_persist; } - BOOL InRange( float range ); - - // Acquire a target. pPlayer is a player in the PVS - edict_t *FindTarget( edict_t *pPlayer ); - - void TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ); - - Vector BarrelPosition( void ) - { - Vector forward, right, up; - UTIL_MakeVectorsPrivate( pev->angles, forward, right, up ); - return pev->origin + (forward * m_barrelPos.x) + (right * m_barrelPos.y) + (up * m_barrelPos.z); - } - - void AdjustAnglesForBarrel( Vector &angles, float distance ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL OnControls( entvars_t *pevTest ); - BOOL StartControl( CBasePlayer* pController ); - void StopControl( void ); - void ControllerPostFrame( void ); - - -protected: - CBasePlayer* m_pController; - float m_flNextAttack; - Vector m_vecControllerUsePos; - - float m_yawCenter; // "Center" yaw - float m_yawRate; // Max turn rate to track targets - float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) - // Zero is full rotation - float m_yawTolerance; // Tolerance angle - - float m_pitchCenter; // "Center" pitch - float m_pitchRate; // Max turn rate on pitch - float m_pitchRange; // Range of pitch motion as above - float m_pitchTolerance; // Tolerance angle - - float m_fireLast; // Last time I fired - float m_fireRate; // How many rounds/second - float m_lastSightTime;// Last time I saw target - float m_persist; // Persistence of firing (how long do I shoot when I can't see) - float m_minRange; // Minimum range to aim/track - float m_maxRange; // Max range to aim/track - - Vector m_barrelPos; // Length of the freakin barrel - float m_spriteScale; // Scale of any sprites we shoot - int m_iszSpriteSmoke; - int m_iszSpriteFlash; - TANKBULLET m_bulletType; // Bullet type - int m_iBulletDamage; // 0 means use Bullet type's default damage - - Vector m_sightOrigin; // Last sight of target - int m_spread; // firing spread - int m_iszMaster; // Master entity (game_team_master or multisource) -}; - - -TYPEDESCRIPTION CFuncTank::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_fireLast, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_fireRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_lastSightTime, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_persist, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_minRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_maxRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_barrelPos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spriteScale, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_iszSpriteSmoke, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_iszSpriteFlash, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_bulletType, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_sightOrigin, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spread, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_pController, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTank, m_vecControllerUsePos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_flNextAttack, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_iBulletDamage, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_iszMaster, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ); - -static Vector gTankSpread[] = -{ - Vector( 0, 0, 0 ), // perfect - Vector( 0.025, 0.025, 0.025 ), // small cone - Vector( 0.05, 0.05, 0.05 ), // medium cone - Vector( 0.1, 0.1, 0.1 ), // large cone - Vector( 0.25, 0.25, 0.25 ), // extra-large cone -}; -#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) - - -void CFuncTank :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_yawCenter = pev->angles.y; - m_pitchCenter = pev->angles.x; - - if ( IsActive() ) - pev->nextthink = pev->ltime + 1.0; - - m_sightOrigin = BarrelPosition(); // Point at the end of the barrel - - if ( m_fireRate <= 0 ) - m_fireRate = 1; - if ( m_spread > MAX_FIRING_SPREADS ) - m_spread = 0; - - pev->oldorigin = pev->origin; -} - - -void CFuncTank :: Precache( void ) -{ - if ( m_iszSpriteSmoke ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteSmoke) ); - if ( m_iszSpriteFlash ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteFlash) ); - - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); -} - - -void CFuncTank :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "yawrate")) - { - m_yawRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawrange")) - { - m_yawRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawtolerance")) - { - m_yawTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrange")) - { - m_pitchRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrate")) - { - m_pitchRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchtolerance")) - { - m_pitchTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firerate")) - { - m_fireRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrel")) - { - m_barrelPos.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrely")) - { - m_barrelPos.y = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrelz")) - { - m_barrelPos.z = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritescale")) - { - m_spriteScale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritesmoke")) - { - m_iszSpriteSmoke = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spriteflash")) - { - m_iszSpriteFlash = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotatesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "persistence")) - { - m_persist = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bullet")) - { - m_bulletType = (TANKBULLET)atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bullet_damage" )) - { - m_iBulletDamage = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firespread")) - { - m_spread = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "minRange")) - { - m_minRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "maxRange")) - { - m_maxRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_iszMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -////////////// START NEW STUFF ////////////// - -//================================================================================== -// TANK CONTROLLING -BOOL CFuncTank :: OnControls( entvars_t *pevTest ) -{ - if ( !(pev->spawnflags & SF_TANK_CANCONTROL) ) - return FALSE; - - Vector offset = pevTest->origin - pev->origin; - - if ( (m_vecControllerUsePos - pevTest->origin).Length() < 30 ) - return TRUE; - - return FALSE; -} - -BOOL CFuncTank :: StartControl( CBasePlayer *pController ) -{ - if ( m_pController != NULL ) - return FALSE; - - // Team only or disabled? - if ( m_iszMaster ) - { - if ( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) - return FALSE; - } - - ALERT( at_console, "using TANK!\n"); - - m_pController = pController; - if ( m_pController->m_pActiveItem ) - { - m_pController->m_pActiveItem->Holster(); - m_pController->pev->weaponmodel = 0; - m_pController->pev->viewmodel = 0; - - } - - m_pController->m_iHideHUD |= HIDEHUD_WEAPONS; - m_vecControllerUsePos = m_pController->pev->origin; - - pev->nextthink = pev->ltime + 0.1; - - return TRUE; -} - -void CFuncTank :: StopControl() -{ - // TODO: bring back the controllers current weapon - if ( !m_pController ) - return; - - if ( m_pController->m_pActiveItem ) - m_pController->m_pActiveItem->Deploy(); - - ALERT( at_console, "stopped using TANK\n"); - - m_pController->m_iHideHUD &= ~HIDEHUD_WEAPONS; - - pev->nextthink = 0; - m_pController = NULL; - - if ( IsActive() ) - pev->nextthink = pev->ltime + 1.0; -} - -// Called each frame by the player's ItemPostFrame -void CFuncTank :: ControllerPostFrame( void ) -{ - ASSERT(m_pController != NULL); - - if ( gpGlobals->time < m_flNextAttack ) - return; - - if ( m_pController->pev->button & IN_ATTACK ) - { - Vector vecForward; - UTIL_MakeVectorsPrivate( pev->angles, vecForward, NULL, NULL ); - - m_fireLast = gpGlobals->time - (1/m_fireRate) - 0.01; // to make sure the gun doesn't fire too many bullets - - Fire( BarrelPosition(), vecForward, m_pController->pev ); - - // HACKHACK -- make some noise (that the AI can hear) - if ( m_pController && m_pController->IsPlayer() ) - ((CBasePlayer *)m_pController)->m_iWeaponVolume = LOUD_GUN_VOLUME; - - m_flNextAttack = gpGlobals->time + (1/m_fireRate); - } -} -////////////// END NEW STUFF ////////////// - - -void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TANK_CANCONTROL ) - { // player controlled turret - - if ( pActivator->Classify() != CLASS_PLAYER ) - return; - - if ( value == 2 && useType == USE_SET ) - { - ControllerPostFrame(); - } - else if ( !m_pController && useType != USE_OFF ) - { - ((CBasePlayer*)pActivator)->m_pTank = this; - StartControl( (CBasePlayer*)pActivator ); - } - else - { - StopControl(); - } - } - else - { - if ( !ShouldToggle( useType, IsActive() ) ) - return; - - if ( IsActive() ) - TankDeactivate(); - else - TankActivate(); - } -} - - -edict_t *CFuncTank :: FindTarget( edict_t *pPlayer ) -{ - return pPlayer; -} - - - -BOOL CFuncTank :: InRange( float range ) -{ - if ( range < m_minRange ) - return FALSE; - if ( m_maxRange > 0 && range > m_maxRange ) - return FALSE; - - return TRUE; -} - - -void CFuncTank :: Think( void ) -{ - pev->avelocity = g_vecZero; - TrackTarget(); - - if ( fabs(pev->avelocity.x) > 1 || fabs(pev->avelocity.y) > 1 ) - StartRotSound(); - else - StopRotSound(); -} - -void CFuncTank::TrackTarget( void ) -{ - TraceResult tr; - edict_t *pPlayer = FIND_CLIENT_IN_PVS( edict() ); - BOOL updateTime = FALSE, lineOfSight; - Vector angles, direction, targetPosition, barrelEnd; - edict_t *pTarget; - - // Get a position to aim for - if (m_pController) - { - // Tanks attempt to mirror the player's angles - angles = m_pController->pev->v_angle; - angles[0] = 0 - angles[0]; - pev->nextthink = pev->ltime + 0.05; - } - else - { - if ( IsActive() ) - pev->nextthink = pev->ltime + 0.1; - else - return; - - if ( FNullEnt( pPlayer ) ) - { - if ( IsActive() ) - pev->nextthink = pev->ltime + 2; // Wait 2 secs - return; - } - pTarget = FindTarget( pPlayer ); - if ( !pTarget ) - return; - - // Calculate angle needed to aim at target - barrelEnd = BarrelPosition(); - targetPosition = pTarget->v.origin + pTarget->v.view_ofs; - float range = (targetPosition - barrelEnd).Length(); - - if ( !InRange( range ) ) - return; - - UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); - - lineOfSight = FALSE; - // No line of sight, don't track - if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) - { - lineOfSight = TRUE; - - CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); - if ( InRange( range ) && pInstance && pInstance->IsAlive() ) - { - updateTime = TRUE; - m_sightOrigin = UpdateTargetPosition( pInstance ); - } - } - - // Track sight origin - -// !!! I'm not sure what i changed - direction = m_sightOrigin - pev->origin; -// direction = m_sightOrigin - barrelEnd; - angles = UTIL_VecToAngles( direction ); - - // Calculate the additional rotation to point the end of the barrel at the target (not the gun's center) - AdjustAnglesForBarrel( angles, direction.Length() ); - } - - angles.x = -angles.x; - - // Force the angles to be relative to the center position - angles.y = m_yawCenter + UTIL_AngleDistance( angles.y, m_yawCenter ); - angles.x = m_pitchCenter + UTIL_AngleDistance( angles.x, m_pitchCenter ); - - // Limit against range in y - if ( angles.y > m_yawCenter + m_yawRange ) - { - angles.y = m_yawCenter + m_yawRange; - updateTime = FALSE; // Don't update if you saw the player, but out of range - } - else if ( angles.y < (m_yawCenter - m_yawRange) ) - { - angles.y = (m_yawCenter - m_yawRange); - updateTime = FALSE; // Don't update if you saw the player, but out of range - } - - if ( updateTime ) - m_lastSightTime = gpGlobals->time; - - // Move toward target at rate or less - float distY = UTIL_AngleDistance( angles.y, pev->angles.y ); - pev->avelocity.y = distY * 10; - if ( pev->avelocity.y > m_yawRate ) - pev->avelocity.y = m_yawRate; - else if ( pev->avelocity.y < -m_yawRate ) - pev->avelocity.y = -m_yawRate; - - // Limit against range in x - if ( angles.x > m_pitchCenter + m_pitchRange ) - angles.x = m_pitchCenter + m_pitchRange; - else if ( angles.x < m_pitchCenter - m_pitchRange ) - angles.x = m_pitchCenter - m_pitchRange; - - // Move toward target at rate or less - float distX = UTIL_AngleDistance( angles.x, pev->angles.x ); - pev->avelocity.x = distX * 10; - - if ( pev->avelocity.x > m_pitchRate ) - pev->avelocity.x = m_pitchRate; - else if ( pev->avelocity.x < -m_pitchRate ) - pev->avelocity.x = -m_pitchRate; - - if ( m_pController ) - return; - - if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT) ) ) - { - BOOL fire = FALSE; - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - if ( pev->spawnflags & SF_TANK_LINEOFSIGHT ) - { - float length = direction.Length(); - UTIL_TraceLine( barrelEnd, barrelEnd + forward * length, dont_ignore_monsters, edict(), &tr ); - if ( tr.pHit == pTarget ) - fire = TRUE; - } - else - fire = TRUE; - - if ( fire ) - { - Fire( BarrelPosition(), forward, pev ); - } - else - m_fireLast = 0; - } - else - m_fireLast = 0; -} - - -// If barrel is offset, add in additional rotation -void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) -{ - float r2, d2; - - - if ( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) - { - distance -= m_barrelPos.z; - d2 = distance * distance; - if ( m_barrelPos.y ) - { - r2 = m_barrelPos.y * m_barrelPos.y; - angles.y += (180.0 / M_PI) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); - } - if ( m_barrelPos.z ) - { - r2 = m_barrelPos.z * m_barrelPos.z; - angles.x += (180.0 / M_PI) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); - } - } -} - - -// Fire targets and spawn sprites -void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - if ( m_iszSpriteSmoke ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteSmoke), barrelEnd, TRUE ); - pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); - pSprite->SetTransparency( kRenderTransAlpha, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, 255, kRenderFxNone ); - pSprite->pev->velocity.z = RANDOM_FLOAT(40, 80); - pSprite->SetScale( m_spriteScale ); - } - if ( m_iszSpriteFlash ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteFlash), barrelEnd, TRUE ); - pSprite->AnimateAndDie( 60 ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - pSprite->SetScale( m_spriteScale ); - - // Hack Hack, make it stick around for at least 100 ms. - pSprite->pev->nextthink += 0.1; - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); - } - m_fireLast = gpGlobals->time; -} - - -void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ) -{ - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - Vector vecDir = vecForward + - x * vecSpread.x * gpGlobals->v_right + - y * vecSpread.y * gpGlobals->v_up; - Vector vecEnd; - - vecEnd = vecStart + vecDir * 4096; - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &tr ); -} - - -void CFuncTank::StartRotSound( void ) -{ - if ( !pev->noise || (pev->spawnflags & SF_TANK_SOUNDON) ) - return; - pev->spawnflags |= SF_TANK_SOUNDON; - EMIT_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise), 0.85, ATTN_NORM); -} - - -void CFuncTank::StopRotSound( void ) -{ - if ( pev->spawnflags & SF_TANK_SOUNDON ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); - pev->spawnflags &= ~SF_TANK_SOUNDON; -} - -class CFuncTankGun : public CFuncTank -{ -public: - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ); - -void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - // FireBullets needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - switch( m_bulletType ) - { - case TANK_BULLET_9MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_9MM, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_MP5: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_MP5, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_12MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_12MM, 1, m_iBulletDamage, pevAttacker ); - break; - - default: - case TANK_BULLET_NONE: - break; - } - } - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); -} - - - -class CFuncTankLaser : public CFuncTank -{ -public: - void Activate( void ); - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - void Think( void ); - CLaser *GetLaser( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - CLaser *m_pLaser; - float m_laserTime; -}; -LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ); - -TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankLaser, m_pLaser, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ); - -void CFuncTankLaser::Activate( void ) -{ - if ( !GetLaser() ) - { - UTIL_Remove(this); - ALERT( at_error, "Laser tank with no env_laser!\n" ); - } - else - { - m_pLaser->TurnOff(); - } -} - - -void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "laserentity")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -CLaser *CFuncTankLaser::GetLaser( void ) -{ - if ( m_pLaser ) - return m_pLaser; - - edict_t *pentLaser; - - pentLaser = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->message) ); - while ( !FNullEnt( pentLaser ) ) - { - // Found the landmark - if ( FClassnameIs( pentLaser, "env_laser" ) ) - { - m_pLaser = (CLaser *)CBaseEntity::Instance(pentLaser); - break; - } - else - pentLaser = FIND_ENTITY_BY_TARGETNAME( pentLaser, STRING(pev->message) ); - } - - return m_pLaser; -} - - -void CFuncTankLaser::Think( void ) -{ - if ( m_pLaser && (gpGlobals->time > m_laserTime) ) - m_pLaser->TurnOff(); - - CFuncTank::Think(); -} - - -void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - TraceResult tr; - - if ( m_fireLast != 0 && GetLaser() ) - { - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount ) - { - for ( i = 0; i < bulletCount; i++ ) - { - m_pLaser->pev->origin = barrelEnd; - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - m_laserTime = gpGlobals->time; - m_pLaser->TurnOn(); - m_pLaser->pev->dmgtime = gpGlobals->time - 1.0; - m_pLaser->FireAtPoint( tr ); - m_pLaser->pev->nextthink = 0; - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - { - CFuncTank::Fire( barrelEnd, forward, pev ); - } -} - -class CFuncTankRocket : public CFuncTank -{ -public: - void Precache( void ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ); - -void CFuncTankRocket::Precache( void ) -{ - UTIL_PrecacheOther( "rpg_rocket" ); - CFuncTank::Precache(); -} - - - -void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - CBaseEntity *pRocket = CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pev ); -} - - -class CFuncTankMortar : public CFuncTank -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); - - -void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iMagnitude")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - // Only create 1 explosion - if ( bulletCount > 0 ) - { - TraceResult tr; - - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE ); - - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pev ); -} - - - -//============================================================================ -// FUNC TANK CONTROLS -//============================================================================ -class CFuncTankControls : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CFuncTank *m_pTank; -}; -LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ); - -TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankControls, m_pTank, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ); - -int CFuncTankControls :: ObjectCaps( void ) -{ - return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; -} - - -void CFuncTankControls :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ // pass the Use command onto the controls - if ( m_pTank ) - m_pTank->Use( pActivator, pCaller, useType, value ); - - ASSERT( m_pTank != NULL ); // if this fails, most likely means save/restore hasn't worked properly -} - - -void CFuncTankControls :: Think( void ) -{ - edict_t *pTarget = NULL; - - do - { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && strncmp( STRING(pTarget->v.classname), "func_tank", 9 ) ); - - if ( FNullEnt( pTarget ) ) - { - ALERT( at_console, "No tank %s\n", STRING(pev->target) ); - return; - } - - m_pTank = (CFuncTank*)Instance(pTarget); -} - -void CFuncTankControls::Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NODRAW; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->nextthink = gpGlobals->time + 0.3; // After all the func_tank's have spawned - - CBaseEntity::Spawn(); -} diff --git a/main/source/dlls/furniture.h b/main/source/dlls/furniture.h index ce34a6b6..2ff2e65d 100644 --- a/main/source/dlls/furniture.h +++ b/main/source/dlls/furniture.h @@ -1,16 +1,16 @@ -#ifndef CFURNITURE_H -#define CFURNITURE_H - -//========================================================= -// Furniture - this is the cool comment I cut-and-pasted -//========================================================= -class CFurniture : public CBaseMonster -{ -public: - void Spawn ( void ); - void Die( void ); - int Classify ( void ); - virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } -}; - +#ifndef CFURNITURE_H +#define CFURNITURE_H + +//========================================================= +// Furniture - this is the cool comment I cut-and-pasted +//========================================================= +class CFurniture : public CBaseMonster +{ +public: + void Spawn ( void ); + void Die( void ); + int Classify ( void ); + virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/game.cpp b/main/source/dlls/game.cpp index 8b0be09e..b6d76dd5 100644 --- a/main/source/dlls/game.cpp +++ b/main/source/dlls/game.cpp @@ -1,261 +1,261 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// -// $Workfile: game.cpp $ -// $Date: 2002/11/22 21:11:38 $ -// -//------------------------------------------------------------------------------- -// $Log: game.cpp,v $ -// Revision 1.37 2002/11/22 21:11:38 Flayra -// - Changed default timelimit to 60 -// - Added mp_version for All-Seeing Eye -// -// Revision 1.36 2002/11/15 04:30:08 Flayra -// - Changed mp_authicons default to 1 -// -// Revision 1.35 2002/11/12 18:52:32 Flayra -// - Added mp_logdetail -// -// Revision 1.34 2002/11/03 04:53:59 Flayra -// - Removed variables, hard-coded instead -// -// Revision 1.33 2002/10/24 21:17:02 Flayra -// - Added authicons variable -// -// Revision 1.32 2002/10/18 22:15:24 Flayra -// - Added easter eggs -// -// Revision 1.31 2002/10/16 00:39:09 Flayra -// - Removed demoing variable, added serverops variable -// -// Revision 1.30 2002/10/04 18:02:52 Flayra -// - Regular update -// -// Revision 1.29 2002/10/03 18:26:19 Flayra -// - Made voting percentage and min votes server variables (mp_votepercentneeded and mp_minvotesneeded) -// -// Revision 1.28 2002/09/23 22:01:23 Flayra -// - Regular update -// -// Revision 1.27 2002/09/09 19:44:16 Flayra -// - Added marine respawn time back in -// - Added vote time variable -// -// Revision 1.26 2002/08/09 00:15:54 Flayra -// - Regular update -// -// Revision 1.25 2002/07/26 23:00:53 Flayra -// - Added mp_drawdamage variable -// -// Revision 1.24 2002/07/24 18:46:19 Flayra -// - Linux and scripting changes -// -// Revision 1.23 2002/07/23 16:46:57 Flayra -// - Regular update -// -// Revision 1.22 2002/07/08 16:27:57 Flayra -// - Regular update, added document header -// -//=============================================================================== -#include "extdll.h" -#include "../engine/eiface.h" -#include "util.h" -#include "game.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHServerUtil.h" - -cvar_t displaysoundlist = {"displaysoundlist","0"}; - -// multiplayer server rules -cvar_t fragsleft = {"mp_fragsleft","0", FCVAR_SERVER | FCVAR_UNLOGGED }; // Don't spam console/log files/users with this changing -cvar_t timeleft = {"mp_timeleft","0" , FCVAR_SERVER | FCVAR_UNLOGGED }; // " " -cvar_t allow_spectators = { "mp_allowspectators", "1.0", FCVAR_SERVER }; // 0 prevents players from being spectators - -// multiplayer server rules -cvar_t teamplay = {"mp_teamplay","0", FCVAR_SERVER }; -cvar_t fraglimit = {"mp_fraglimit","0", FCVAR_SERVER }; -cvar_t timelimit = {"mp_timelimit","60", FCVAR_SERVER }; -cvar_t friendlyfire= {"mp_friendlyfire","0", FCVAR_SERVER }; -cvar_t falldamage = {"mp_falldamage","1", FCVAR_SERVER }; -cvar_t weaponstay = {"mp_weaponstay",".5", FCVAR_SERVER }; -cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; -cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; -cvar_t aimcrosshair= {"mp_autocrosshair","0", FCVAR_SERVER }; -cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER }; -cvar_t teamlist = {"mp_teamlist","marine1;alien2", FCVAR_SERVER }; -cvar_t teamoverride = {"mp_teamoverride","1" }; -cvar_t defaultteam = {"mp_defaultteam","0" }; -cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER }; -cvar_t mp_chattime = {"mp_chattime","10", FCVAR_SERVER }; - -// AvH server variables -cvar_t avh_drawdamage = {kvDrawDamage, "0", FCVAR_SERVER }; -cvar_t avh_tournamentmode = {kvTournamentMode,"0", FCVAR_SERVER }; -cvar_t avh_deathmatchmode = {kvDeathMatchMode, "0", FCVAR_SERVER }; -cvar_t avh_countdowntime = {kvCountDownTime, ".2", FCVAR_SERVER }; -cvar_t avh_latejointime = {kvLateJoinTime, "1", FCVAR_SERVER}; -cvar_t avh_logdetail = {kvLogDetail, "0", FCVAR_SERVER}; -//cvar_t avh_teamsizehandicapping = {kvTeamSizeHandicapping, "0", FCVAR_SERVER}; -cvar_t avh_team1damagepercent = {kvTeam1DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_team2damagepercent = {kvTeam2DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_team3damagepercent = {kvTeam3DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_team4damagepercent = {kvTeam4DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_structurelimit = {kvStructureLimit, "300", FCVAR_SERVER}; -cvar_t avh_votecasttime = {kvVoteCastTime, "2", FCVAR_SERVER}; -cvar_t avh_votedowntime = {kvVoteDownTime, "180", FCVAR_SERVER}; -cvar_t avh_minvotesneeded = {kvMinVotesNeeded, "2", FCVAR_SERVER}; -cvar_t avh_serverops = {kvServerOps, "", FCVAR_PROTECTED}; -cvar_t avh_limitteams = {kvLimitTeams, "2", FCVAR_PROTECTED}; -cvar_t avh_votepercentneeded = {kvVotePercentNeeded, ".3", FCVAR_SERVER}; -cvar_t avh_autoconcede = {kvAutoConcede, "4", FCVAR_SERVER}; -cvar_t avh_combattime = {kvCombatTime, "10", FCVAR_SERVER}; -cvar_t avh_mapvoteratio = {kvMapVoteRatio, ".6", FCVAR_SERVER}; -cvar_t avh_blockscripts = {kvBlockScripts, "1", FCVAR_SERVER}; -#ifdef DEBUG - cvar_t avh_testing = {kvTesting, "0", FCVAR_SERVER}; -#endif -cvar_t *avh_cheats=0; -cvar_t *showtriggers=0; -cvar_t *violence_ablood=0; -cvar_t *violence_agibs=0; -cvar_t *violence_hblood=0; -cvar_t *violence_hgibs=0; - -// TODO: Remove -cvar_t avh_ironman = {kvIronMan, "0", FCVAR_SERVER}; -cvar_t avh_ironmantime = {kvIronManTime, "2", FCVAR_SERVER}; - -#ifdef DEBUG -cvar_t avh_spawninvulnerabletime = {kvSpawnInvulnerableTime, "0", FCVAR_SERVER}; -cvar_t avh_trainingmode = {kvTrainingMode,"0", FCVAR_SERVER }; -cvar_t avh_assert = {kvAssert, "1", FCVAR_SERVER }; -cvar_t avh_bulletcam = {kvBulletCam, "0", FCVAR_SERVER }; -cvar_t avh_drawinvisible = {kvDrawInvisible, "0", FCVAR_SERVER }; -cvar_t avh_serverscripts = {kvServerScripts, "0", FCVAR_SERVER}; -#endif - -#ifdef USE_NETWORK_METERING -cvar_t avh_networkdebug = {kvNetworkDebug, "0", FCVAR_SERVER }; -cvar_t avh_networkmeterrate = {kvNetworkMeterRate, "3000", FCVAR_SERVER }; -#endif - -#ifdef PROFILE_BUILD -cvar_t avh_performance = {kvPerformance,"8191", FCVAR_SERVER}; -#endif - -// Other constants -cvar_t avh_eastereggchance = {kvEasterEggChance, "5", FCVAR_SERVER}; -cvar_t avh_uplink = {kvUplink, "0", FCVAR_SERVER}; -cvar_t avh_killdelay = {kvKillDelay, "0", FCVAR_SERVER}; - -// Engine Cvars -cvar_t *g_psv_gravity = NULL; -cvar_t *g_psv_aim = NULL; -cvar_t *g_footsteps = NULL; - -// END Cvars for Skill Level settings - -// Register your console variables here -// This gets called one time when the game is initialied -void GameDLLInit( void ) -{ - // Register cvars here: - - g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); - g_psv_aim = CVAR_GET_POINTER( "sv_aim" ); - g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); - - CVAR_REGISTER (&displaysoundlist); - - CVAR_REGISTER (&teamplay); - CVAR_REGISTER (&fraglimit); - CVAR_REGISTER (&timelimit); - - CVAR_REGISTER (&fragsleft); - CVAR_REGISTER (&timeleft); - CVAR_REGISTER (&allow_spectators); - - CVAR_REGISTER (&friendlyfire); - CVAR_REGISTER (&falldamage); - CVAR_REGISTER (&weaponstay); - CVAR_REGISTER (&forcerespawn); - CVAR_REGISTER (&flashlight); - CVAR_REGISTER (&aimcrosshair); - CVAR_REGISTER (&decalfrequency); - CVAR_REGISTER (&teamlist); - CVAR_REGISTER (&teamoverride); - CVAR_REGISTER (&defaultteam); - CVAR_REGISTER (&allowmonsters); - CVAR_REGISTER (&mp_chattime); - - // Register AvH variables - CVAR_REGISTER (&avh_drawdamage); - CVAR_REGISTER (&avh_tournamentmode); - CVAR_REGISTER (&avh_deathmatchmode); - CVAR_REGISTER (&avh_countdowntime); - - avh_cheats=CVAR_GET_POINTER("sv_cheats"); - showtriggers=CVAR_GET_POINTER("showtriggers"); - violence_ablood=CVAR_GET_POINTER("violence_ablood"); - violence_agibs=CVAR_GET_POINTER("violence_agibs"); - violence_hblood=CVAR_GET_POINTER("violence_hblood"); - violence_hgibs=CVAR_GET_POINTER("violence_hgibs"); - - - CVAR_REGISTER (&avh_latejointime); - CVAR_REGISTER (&avh_logdetail); - //CVAR_REGISTER (&avh_teamsizehandicapping); - CVAR_REGISTER (&avh_team1damagepercent); - CVAR_REGISTER (&avh_team2damagepercent); - CVAR_REGISTER (&avh_team3damagepercent); - CVAR_REGISTER (&avh_team4damagepercent); - CVAR_REGISTER (&avh_structurelimit); - CVAR_REGISTER (&avh_votecasttime); - CVAR_REGISTER (&avh_votedowntime); - CVAR_REGISTER (&avh_minvotesneeded); - CVAR_REGISTER (&avh_serverops); - CVAR_REGISTER (&avh_limitteams); - CVAR_REGISTER (&avh_votepercentneeded); - CVAR_REGISTER (&avh_autoconcede); - CVAR_REGISTER (&avh_combattime); - CVAR_REGISTER (&avh_mapvoteratio); - CVAR_REGISTER (&avh_blockscripts); - - // TODO: Remove - CVAR_REGISTER (&avh_ironman); - CVAR_REGISTER (&avh_ironmantime); - -#ifdef DEBUG - CVAR_REGISTER (&avh_spawninvulnerabletime); - CVAR_REGISTER (&avh_trainingmode); - CVAR_REGISTER (&avh_assert); - CVAR_REGISTER (&avh_bulletcam); - CVAR_REGISTER (&avh_testing); - CVAR_REGISTER (&avh_serverscripts); -#endif - -#ifdef USE_NETWORK_METERING - CVAR_REGISTER (&avh_networkdebug); - CVAR_REGISTER (&avh_drawinvisible); -#endif - -#ifdef PROFILE_BUILD - CVAR_REGISTER (&avh_performance); -#endif - - CVAR_REGISTER (&avh_eastereggchance); - CVAR_REGISTER (&avh_uplink); - CVAR_REGISTER (&avh_killdelay); - -} - +// +// Copyright (c) 1999, Valve LLC. All rights reserved. +// +// This product contains software technology licensed from Id +// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +// All Rights Reserved. +// +// Use, distribution, and modification of this source code and/or resulting +// object code is restricted to non-commercial enhancements to products from +// Valve LLC. All other use, distribution, or modification is prohibited +// without written permission from Valve LLC. +// +// +// $Workfile: game.cpp $ +// $Date: 2002/11/22 21:11:38 $ +// +//------------------------------------------------------------------------------- +// $Log: game.cpp,v $ +// Revision 1.37 2002/11/22 21:11:38 Flayra +// - Changed default timelimit to 60 +// - Added mp_version for All-Seeing Eye +// +// Revision 1.36 2002/11/15 04:30:08 Flayra +// - Changed mp_authicons default to 1 +// +// Revision 1.35 2002/11/12 18:52:32 Flayra +// - Added mp_logdetail +// +// Revision 1.34 2002/11/03 04:53:59 Flayra +// - Removed variables, hard-coded instead +// +// Revision 1.33 2002/10/24 21:17:02 Flayra +// - Added authicons variable +// +// Revision 1.32 2002/10/18 22:15:24 Flayra +// - Added easter eggs +// +// Revision 1.31 2002/10/16 00:39:09 Flayra +// - Removed demoing variable, added serverops variable +// +// Revision 1.30 2002/10/04 18:02:52 Flayra +// - Regular update +// +// Revision 1.29 2002/10/03 18:26:19 Flayra +// - Made voting percentage and min votes server variables (mp_votepercentneeded and mp_minvotesneeded) +// +// Revision 1.28 2002/09/23 22:01:23 Flayra +// - Regular update +// +// Revision 1.27 2002/09/09 19:44:16 Flayra +// - Added marine respawn time back in +// - Added vote time variable +// +// Revision 1.26 2002/08/09 00:15:54 Flayra +// - Regular update +// +// Revision 1.25 2002/07/26 23:00:53 Flayra +// - Added mp_drawdamage variable +// +// Revision 1.24 2002/07/24 18:46:19 Flayra +// - Linux and scripting changes +// +// Revision 1.23 2002/07/23 16:46:57 Flayra +// - Regular update +// +// Revision 1.22 2002/07/08 16:27:57 Flayra +// - Regular update, added document header +// +//=============================================================================== +#include "extdll.h" +#include "../engine/eiface.h" +#include "util.h" +#include "game.h" +#include "../mod/AvHServerVariables.h" +#include "../mod/AvHServerUtil.h" + +cvar_t displaysoundlist = {"displaysoundlist","0"}; + +// multiplayer server rules +cvar_t fragsleft = {"mp_fragsleft","0", FCVAR_SERVER | FCVAR_UNLOGGED }; // Don't spam console/log files/users with this changing +cvar_t timeleft = {"mp_timeleft","0" , FCVAR_SERVER | FCVAR_UNLOGGED }; // " " +cvar_t allow_spectators = { "mp_allowspectators", "1.0", FCVAR_SERVER }; // 0 prevents players from being spectators + +// multiplayer server rules +cvar_t teamplay = {"mp_teamplay","0", FCVAR_SERVER }; +cvar_t fraglimit = {"mp_fraglimit","0", FCVAR_SERVER }; +cvar_t timelimit = {"mp_timelimit","60", FCVAR_SERVER }; +cvar_t friendlyfire= {"mp_friendlyfire","0", FCVAR_SERVER }; +cvar_t falldamage = {"mp_falldamage","1", FCVAR_SERVER }; +cvar_t weaponstay = {"mp_weaponstay",".5", FCVAR_SERVER }; +cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; +cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; +cvar_t aimcrosshair= {"mp_autocrosshair","0", FCVAR_SERVER }; +cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER }; +cvar_t teamlist = {"mp_teamlist","marine1;alien2", FCVAR_SERVER }; +cvar_t teamoverride = {"mp_teamoverride","1" }; +cvar_t defaultteam = {"mp_defaultteam","0" }; +cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER }; +cvar_t mp_chattime = {"mp_chattime","10", FCVAR_SERVER }; + +// AvH server variables +cvar_t avh_drawdamage = {kvDrawDamage, "0", FCVAR_SERVER }; +cvar_t avh_tournamentmode = {kvTournamentMode,"0", FCVAR_SERVER }; +cvar_t avh_deathmatchmode = {kvDeathMatchMode, "0", FCVAR_SERVER }; +cvar_t avh_countdowntime = {kvCountDownTime, ".2", FCVAR_SERVER }; +cvar_t avh_latejointime = {kvLateJoinTime, "1", FCVAR_SERVER}; +cvar_t avh_logdetail = {kvLogDetail, "0", FCVAR_SERVER}; +//cvar_t avh_teamsizehandicapping = {kvTeamSizeHandicapping, "0", FCVAR_SERVER}; +cvar_t avh_team1damagepercent = {kvTeam1DamagePercent, "100", FCVAR_SERVER}; +cvar_t avh_team2damagepercent = {kvTeam2DamagePercent, "100", FCVAR_SERVER}; +cvar_t avh_team3damagepercent = {kvTeam3DamagePercent, "100", FCVAR_SERVER}; +cvar_t avh_team4damagepercent = {kvTeam4DamagePercent, "100", FCVAR_SERVER}; +cvar_t avh_structurelimit = {kvStructureLimit, "300", FCVAR_SERVER}; +cvar_t avh_votecasttime = {kvVoteCastTime, "2", FCVAR_SERVER}; +cvar_t avh_votedowntime = {kvVoteDownTime, "180", FCVAR_SERVER}; +cvar_t avh_minvotesneeded = {kvMinVotesNeeded, "2", FCVAR_SERVER}; +cvar_t avh_serverops = {kvServerOps, "", FCVAR_PROTECTED}; +cvar_t avh_limitteams = {kvLimitTeams, "2", FCVAR_PROTECTED}; +cvar_t avh_votepercentneeded = {kvVotePercentNeeded, ".3", FCVAR_SERVER}; +cvar_t avh_autoconcede = {kvAutoConcede, "4", FCVAR_SERVER}; +cvar_t avh_combattime = {kvCombatTime, "10", FCVAR_SERVER}; +cvar_t avh_mapvoteratio = {kvMapVoteRatio, ".6", FCVAR_SERVER}; +cvar_t avh_blockscripts = {kvBlockScripts, "1", FCVAR_SERVER}; +#ifdef DEBUG + cvar_t avh_testing = {kvTesting, "0", FCVAR_SERVER}; +#endif +cvar_t *avh_cheats=0; +cvar_t *showtriggers=0; +cvar_t *violence_ablood=0; +cvar_t *violence_agibs=0; +cvar_t *violence_hblood=0; +cvar_t *violence_hgibs=0; + +// TODO: Remove +cvar_t avh_ironman = {kvIronMan, "0", FCVAR_SERVER}; +cvar_t avh_ironmantime = {kvIronManTime, "2", FCVAR_SERVER}; + +#ifdef DEBUG +cvar_t avh_spawninvulnerabletime = {kvSpawnInvulnerableTime, "0", FCVAR_SERVER}; +cvar_t avh_trainingmode = {kvTrainingMode,"0", FCVAR_SERVER }; +cvar_t avh_assert = {kvAssert, "1", FCVAR_SERVER }; +cvar_t avh_bulletcam = {kvBulletCam, "0", FCVAR_SERVER }; +cvar_t avh_drawinvisible = {kvDrawInvisible, "0", FCVAR_SERVER }; +cvar_t avh_serverscripts = {kvServerScripts, "0", FCVAR_SERVER}; +#endif + +#ifdef USE_NETWORK_METERING +cvar_t avh_networkdebug = {kvNetworkDebug, "0", FCVAR_SERVER }; +cvar_t avh_networkmeterrate = {kvNetworkMeterRate, "3000", FCVAR_SERVER }; +#endif + +#ifdef PROFILE_BUILD +cvar_t avh_performance = {kvPerformance,"8191", FCVAR_SERVER}; +#endif + +// Other constants +cvar_t avh_eastereggchance = {kvEasterEggChance, "5", FCVAR_SERVER}; +cvar_t avh_uplink = {kvUplink, "0", FCVAR_SERVER}; +cvar_t avh_killdelay = {kvKillDelay, "0", FCVAR_SERVER}; + +// Engine Cvars +cvar_t *g_psv_gravity = NULL; +cvar_t *g_psv_aim = NULL; +cvar_t *g_footsteps = NULL; + +// END Cvars for Skill Level settings + +// Register your console variables here +// This gets called one time when the game is initialied +void GameDLLInit( void ) +{ + // Register cvars here: + + g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); + g_psv_aim = CVAR_GET_POINTER( "sv_aim" ); + g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); + + CVAR_REGISTER (&displaysoundlist); + + CVAR_REGISTER (&teamplay); + CVAR_REGISTER (&fraglimit); + CVAR_REGISTER (&timelimit); + + CVAR_REGISTER (&fragsleft); + CVAR_REGISTER (&timeleft); + CVAR_REGISTER (&allow_spectators); + + CVAR_REGISTER (&friendlyfire); + CVAR_REGISTER (&falldamage); + CVAR_REGISTER (&weaponstay); + CVAR_REGISTER (&forcerespawn); + CVAR_REGISTER (&flashlight); + CVAR_REGISTER (&aimcrosshair); + CVAR_REGISTER (&decalfrequency); + CVAR_REGISTER (&teamlist); + CVAR_REGISTER (&teamoverride); + CVAR_REGISTER (&defaultteam); + CVAR_REGISTER (&allowmonsters); + CVAR_REGISTER (&mp_chattime); + + // Register AvH variables + CVAR_REGISTER (&avh_drawdamage); + CVAR_REGISTER (&avh_tournamentmode); + CVAR_REGISTER (&avh_deathmatchmode); + CVAR_REGISTER (&avh_countdowntime); + + avh_cheats=CVAR_GET_POINTER("sv_cheats"); + showtriggers=CVAR_GET_POINTER("showtriggers"); + violence_ablood=CVAR_GET_POINTER("violence_ablood"); + violence_agibs=CVAR_GET_POINTER("violence_agibs"); + violence_hblood=CVAR_GET_POINTER("violence_hblood"); + violence_hgibs=CVAR_GET_POINTER("violence_hgibs"); + + + CVAR_REGISTER (&avh_latejointime); + CVAR_REGISTER (&avh_logdetail); + //CVAR_REGISTER (&avh_teamsizehandicapping); + CVAR_REGISTER (&avh_team1damagepercent); + CVAR_REGISTER (&avh_team2damagepercent); + CVAR_REGISTER (&avh_team3damagepercent); + CVAR_REGISTER (&avh_team4damagepercent); + CVAR_REGISTER (&avh_structurelimit); + CVAR_REGISTER (&avh_votecasttime); + CVAR_REGISTER (&avh_votedowntime); + CVAR_REGISTER (&avh_minvotesneeded); + CVAR_REGISTER (&avh_serverops); + CVAR_REGISTER (&avh_limitteams); + CVAR_REGISTER (&avh_votepercentneeded); + CVAR_REGISTER (&avh_autoconcede); + CVAR_REGISTER (&avh_combattime); + CVAR_REGISTER (&avh_mapvoteratio); + CVAR_REGISTER (&avh_blockscripts); + + // TODO: Remove + CVAR_REGISTER (&avh_ironman); + CVAR_REGISTER (&avh_ironmantime); + +#ifdef DEBUG + CVAR_REGISTER (&avh_spawninvulnerabletime); + CVAR_REGISTER (&avh_trainingmode); + CVAR_REGISTER (&avh_assert); + CVAR_REGISTER (&avh_bulletcam); + CVAR_REGISTER (&avh_testing); + CVAR_REGISTER (&avh_serverscripts); +#endif + +#ifdef USE_NETWORK_METERING + CVAR_REGISTER (&avh_networkdebug); + CVAR_REGISTER (&avh_drawinvisible); +#endif + +#ifdef PROFILE_BUILD + CVAR_REGISTER (&avh_performance); +#endif + + CVAR_REGISTER (&avh_eastereggchance); + CVAR_REGISTER (&avh_uplink); + CVAR_REGISTER (&avh_killdelay); + +} + diff --git a/main/source/dlls/game.cpp~ b/main/source/dlls/game.cpp~ deleted file mode 100644 index b9adf280..00000000 --- a/main/source/dlls/game.cpp~ +++ /dev/null @@ -1,261 +0,0 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// -// $Workfile: game.cpp $ -// $Date: 2002/11/22 21:11:38 $ -// -//------------------------------------------------------------------------------- -// $Log: game.cpp,v $ -// Revision 1.37 2002/11/22 21:11:38 Flayra -// - Changed default timelimit to 60 -// - Added mp_version for All-Seeing Eye -// -// Revision 1.36 2002/11/15 04:30:08 Flayra -// - Changed mp_authicons default to 1 -// -// Revision 1.35 2002/11/12 18:52:32 Flayra -// - Added mp_logdetail -// -// Revision 1.34 2002/11/03 04:53:59 Flayra -// - Removed variables, hard-coded instead -// -// Revision 1.33 2002/10/24 21:17:02 Flayra -// - Added authicons variable -// -// Revision 1.32 2002/10/18 22:15:24 Flayra -// - Added easter eggs -// -// Revision 1.31 2002/10/16 00:39:09 Flayra -// - Removed demoing variable, added serverops variable -// -// Revision 1.30 2002/10/04 18:02:52 Flayra -// - Regular update -// -// Revision 1.29 2002/10/03 18:26:19 Flayra -// - Made voting percentage and min votes server variables (mp_votepercentneeded and mp_minvotesneeded) -// -// Revision 1.28 2002/09/23 22:01:23 Flayra -// - Regular update -// -// Revision 1.27 2002/09/09 19:44:16 Flayra -// - Added marine respawn time back in -// - Added vote time variable -// -// Revision 1.26 2002/08/09 00:15:54 Flayra -// - Regular update -// -// Revision 1.25 2002/07/26 23:00:53 Flayra -// - Added mp_drawdamage variable -// -// Revision 1.24 2002/07/24 18:46:19 Flayra -// - Linux and scripting changes -// -// Revision 1.23 2002/07/23 16:46:57 Flayra -// - Regular update -// -// Revision 1.22 2002/07/08 16:27:57 Flayra -// - Regular update, added document header -// -//=============================================================================== -#include "extdll.h" -#include "../engine/eiface.h" -#include "util.h" -#include "game.h" -#include "..mod/AvHServerVariables.h" -#include "..mod/AvHServerUtil.h" - -cvar_t displaysoundlist = {"displaysoundlist","0"}; - -// multiplayer server rules -cvar_t fragsleft = {"mp_fragsleft","0", FCVAR_SERVER | FCVAR_UNLOGGED }; // Don't spam console/log files/users with this changing -cvar_t timeleft = {"mp_timeleft","0" , FCVAR_SERVER | FCVAR_UNLOGGED }; // " " -cvar_t allow_spectators = { "mp_allowspectators", "1.0", FCVAR_SERVER }; // 0 prevents players from being spectators - -// multiplayer server rules -cvar_t teamplay = {"mp_teamplay","0", FCVAR_SERVER }; -cvar_t fraglimit = {"mp_fraglimit","0", FCVAR_SERVER }; -cvar_t timelimit = {"mp_timelimit","60", FCVAR_SERVER }; -cvar_t friendlyfire= {"mp_friendlyfire","0", FCVAR_SERVER }; -cvar_t falldamage = {"mp_falldamage","1", FCVAR_SERVER }; -cvar_t weaponstay = {"mp_weaponstay",".5", FCVAR_SERVER }; -cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; -cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; -cvar_t aimcrosshair= {"mp_autocrosshair","0", FCVAR_SERVER }; -cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER }; -cvar_t teamlist = {"mp_teamlist","marine1;alien2", FCVAR_SERVER }; -cvar_t teamoverride = {"mp_teamoverride","1" }; -cvar_t defaultteam = {"mp_defaultteam","0" }; -cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER }; -cvar_t mp_chattime = {"mp_chattime","10", FCVAR_SERVER }; - -// AvH server variables -cvar_t avh_drawdamage = {kvDrawDamage, "0", FCVAR_SERVER }; -cvar_t avh_tournamentmode = {kvTournamentMode,"0", FCVAR_SERVER }; -cvar_t avh_deathmatchmode = {kvDeathMatchMode, "0", FCVAR_SERVER }; -cvar_t avh_countdowntime = {kvCountDownTime, ".2", FCVAR_SERVER }; -cvar_t avh_latejointime = {kvLateJoinTime, "1", FCVAR_SERVER}; -cvar_t avh_logdetail = {kvLogDetail, "0", FCVAR_SERVER}; -//cvar_t avh_teamsizehandicapping = {kvTeamSizeHandicapping, "0", FCVAR_SERVER}; -cvar_t avh_team1damagepercent = {kvTeam1DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_team2damagepercent = {kvTeam2DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_team3damagepercent = {kvTeam3DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_team4damagepercent = {kvTeam4DamagePercent, "100", FCVAR_SERVER}; -cvar_t avh_structurelimit = {kvStructureLimit, "300", FCVAR_SERVER}; -cvar_t avh_votecasttime = {kvVoteCastTime, "2", FCVAR_SERVER}; -cvar_t avh_votedowntime = {kvVoteDownTime, "180", FCVAR_SERVER}; -cvar_t avh_minvotesneeded = {kvMinVotesNeeded, "2", FCVAR_SERVER}; -cvar_t avh_serverops = {kvServerOps, "", FCVAR_PROTECTED}; -cvar_t avh_limitteams = {kvLimitTeams, "2", FCVAR_PROTECTED}; -cvar_t avh_votepercentneeded = {kvVotePercentNeeded, ".3", FCVAR_SERVER}; -cvar_t avh_autoconcede = {kvAutoConcede, "4", FCVAR_SERVER}; -cvar_t avh_combattime = {kvCombatTime, "10", FCVAR_SERVER}; -cvar_t avh_mapvoteratio = {kvMapVoteRatio, ".6", FCVAR_SERVER}; -cvar_t avh_blockscripts = {kvBlockScripts, "1", FCVAR_SERVER}; -#ifdef DEBUG - cvar_t avh_testing = {kvTesting, "0", FCVAR_SERVER}; -#endif -cvar_t *avh_cheats=0; -cvar_t *showtriggers=0; -cvar_t *violence_ablood=0; -cvar_t *violence_agibs=0; -cvar_t *violence_hblood=0; -cvar_t *violence_hgibs=0; - -// TODO: Remove -cvar_t avh_ironman = {kvIronMan, "0", FCVAR_SERVER}; -cvar_t avh_ironmantime = {kvIronManTime, "2", FCVAR_SERVER}; - -#ifdef DEBUG -cvar_t avh_spawninvulnerabletime = {kvSpawnInvulnerableTime, "0", FCVAR_SERVER}; -cvar_t avh_trainingmode = {kvTrainingMode,"0", FCVAR_SERVER }; -cvar_t avh_assert = {kvAssert, "1", FCVAR_SERVER }; -cvar_t avh_bulletcam = {kvBulletCam, "0", FCVAR_SERVER }; -cvar_t avh_drawinvisible = {kvDrawInvisible, "0", FCVAR_SERVER }; -cvar_t avh_serverscripts = {kvServerScripts, "0", FCVAR_SERVER}; -#endif - -#ifdef USE_NETWORK_METERING -cvar_t avh_networkdebug = {kvNetworkDebug, "0", FCVAR_SERVER }; -cvar_t avh_networkmeterrate = {kvNetworkMeterRate, "3000", FCVAR_SERVER }; -#endif - -#ifdef PROFILE_BUILD -cvar_t avh_performance = {kvPerformance,"8191", FCVAR_SERVER}; -#endif - -// Other constants -cvar_t avh_eastereggchance = {kvEasterEggChance, "5", FCVAR_SERVER}; -cvar_t avh_uplink = {kvUplink, "0", FCVAR_SERVER}; -cvar_t avh_killdelay = {kvKillDelay, "0", FCVAR_SERVER}; - -// Engine Cvars -cvar_t *g_psv_gravity = NULL; -cvar_t *g_psv_aim = NULL; -cvar_t *g_footsteps = NULL; - -// END Cvars for Skill Level settings - -// Register your console variables here -// This gets called one time when the game is initialied -void GameDLLInit( void ) -{ - // Register cvars here: - - g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); - g_psv_aim = CVAR_GET_POINTER( "sv_aim" ); - g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); - - CVAR_REGISTER (&displaysoundlist); - - CVAR_REGISTER (&teamplay); - CVAR_REGISTER (&fraglimit); - CVAR_REGISTER (&timelimit); - - CVAR_REGISTER (&fragsleft); - CVAR_REGISTER (&timeleft); - CVAR_REGISTER (&allow_spectators); - - CVAR_REGISTER (&friendlyfire); - CVAR_REGISTER (&falldamage); - CVAR_REGISTER (&weaponstay); - CVAR_REGISTER (&forcerespawn); - CVAR_REGISTER (&flashlight); - CVAR_REGISTER (&aimcrosshair); - CVAR_REGISTER (&decalfrequency); - CVAR_REGISTER (&teamlist); - CVAR_REGISTER (&teamoverride); - CVAR_REGISTER (&defaultteam); - CVAR_REGISTER (&allowmonsters); - CVAR_REGISTER (&mp_chattime); - - // Register AvH variables - CVAR_REGISTER (&avh_drawdamage); - CVAR_REGISTER (&avh_tournamentmode); - CVAR_REGISTER (&avh_deathmatchmode); - CVAR_REGISTER (&avh_countdowntime); - - avh_cheats=CVAR_GET_POINTER("sv_cheats"); - showtriggers=CVAR_GET_POINTER("showtriggers"); - violence_ablood=CVAR_GET_POINTER("violence_ablood"); - violence_agibs=CVAR_GET_POINTER("violence_agibs"); - violence_hblood=CVAR_GET_POINTER("violence_hblood"); - violence_hgibs=CVAR_GET_POINTER("violence_hgibs"); - - - CVAR_REGISTER (&avh_latejointime); - CVAR_REGISTER (&avh_logdetail); - //CVAR_REGISTER (&avh_teamsizehandicapping); - CVAR_REGISTER (&avh_team1damagepercent); - CVAR_REGISTER (&avh_team2damagepercent); - CVAR_REGISTER (&avh_team3damagepercent); - CVAR_REGISTER (&avh_team4damagepercent); - CVAR_REGISTER (&avh_structurelimit); - CVAR_REGISTER (&avh_votecasttime); - CVAR_REGISTER (&avh_votedowntime); - CVAR_REGISTER (&avh_minvotesneeded); - CVAR_REGISTER (&avh_serverops); - CVAR_REGISTER (&avh_limitteams); - CVAR_REGISTER (&avh_votepercentneeded); - CVAR_REGISTER (&avh_autoconcede); - CVAR_REGISTER (&avh_combattime); - CVAR_REGISTER (&avh_mapvoteratio); - CVAR_REGISTER (&avh_blockscripts); - - // TODO: Remove - CVAR_REGISTER (&avh_ironman); - CVAR_REGISTER (&avh_ironmantime); - -#ifdef DEBUG - CVAR_REGISTER (&avh_spawninvulnerabletime); - CVAR_REGISTER (&avh_trainingmode); - CVAR_REGISTER (&avh_assert); - CVAR_REGISTER (&avh_bulletcam); - CVAR_REGISTER (&avh_testing); - CVAR_REGISTER (&avh_serverscripts); -#endif - -#ifdef USE_NETWORK_METERING - CVAR_REGISTER (&avh_networkdebug); - CVAR_REGISTER (&avh_drawinvisible); -#endif - -#ifdef PROFILE_BUILD - CVAR_REGISTER (&avh_performance); -#endif - - CVAR_REGISTER (&avh_eastereggchance); - CVAR_REGISTER (&avh_uplink); - CVAR_REGISTER (&avh_killdelay); - -} - diff --git a/main/source/dlls/game.h b/main/source/dlls/game.h index 2536b025..5ad6f401 100644 --- a/main/source/dlls/game.h +++ b/main/source/dlls/game.h @@ -1,45 +1,45 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef GAME_H -#define GAME_H - -extern void GameDLLInit( void ); - - -extern cvar_t displaysoundlist; - -// multiplayer server rules -extern cvar_t teamplay; -extern cvar_t fraglimit; -extern cvar_t timelimit; -extern cvar_t friendlyfire; -extern cvar_t falldamage; -extern cvar_t weaponstay; -extern cvar_t forcerespawn; -extern cvar_t flashlight; -extern cvar_t aimcrosshair; -extern cvar_t decalfrequency; -extern cvar_t teamlist; -extern cvar_t teamoverride; -extern cvar_t defaultteam; -extern cvar_t allowmonsters; - -// Engine Cvars -extern cvar_t *g_psv_gravity; -extern cvar_t *g_psv_aim; -extern cvar_t *g_footsteps; - -#endif // GAME_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef GAME_H +#define GAME_H + +extern void GameDLLInit( void ); + + +extern cvar_t displaysoundlist; + +// multiplayer server rules +extern cvar_t teamplay; +extern cvar_t fraglimit; +extern cvar_t timelimit; +extern cvar_t friendlyfire; +extern cvar_t falldamage; +extern cvar_t weaponstay; +extern cvar_t forcerespawn; +extern cvar_t flashlight; +extern cvar_t aimcrosshair; +extern cvar_t decalfrequency; +extern cvar_t teamlist; +extern cvar_t teamoverride; +extern cvar_t defaultteam; +extern cvar_t allowmonsters; + +// Engine Cvars +extern cvar_t *g_psv_gravity; +extern cvar_t *g_psv_aim; +extern cvar_t *g_footsteps; + +#endif // GAME_H diff --git a/main/source/dlls/gamerules.cpp b/main/source/dlls/gamerules.cpp index 72610797..6afc44b6 100644 --- a/main/source/dlls/gamerules.cpp +++ b/main/source/dlls/gamerules.cpp @@ -1,153 +1,153 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// GameRules.cpp -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "skill.h" -#include "game.h" -#include "mod/AvHSpecials.h" -#include "mod/AvHHulls.h" - -DLL_GLOBAL CGameRules* g_pGameRules = NULL; -extern DLL_GLOBAL BOOL g_fGameOver; - -int g_teamplay = 1; - -//========================================================= -//========================================================= -BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry ) -{ - int iAmmoIndex; - - if ( pszAmmoName ) - { - iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName ); - - if ( iAmmoIndex > -1 ) - { - if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry ) - { - // player has room for more of this type of ammo - return TRUE; - } - } - } - - return FALSE; -} - -//========================================================= -//========================================================= -edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ -// edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); -// -// pPlayer->InitPlayerFromSpawn(pentSpawnSpot); -// -// return pentSpawnSpot; - - ASSERT(FALSE); - - return NULL; -} - -//========================================================= -//========================================================= -BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - // only living players can have items - if ( pPlayer->pev->deadflag != DEAD_NO ) - return FALSE; - - if ( pWeapon->pszAmmo1() ) - { - if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) ) - { - // we can't carry anymore ammo for this gun. We can only - // have the gun if we aren't already carrying one of this type - if ( pPlayer->HasPlayerItem( pWeapon ) ) - { - return FALSE; - } - } - } - else - { - // weapon doesn't use ammo, don't take another if you already have it. - if ( pPlayer->HasPlayerItem( pWeapon ) ) - { - return FALSE; - } - } - - // note: will fall through to here if GetItemInfo doesn't fill the struct! - return TRUE; -} - -//========================================================= -// load the SkillData struct with the proper values based on the skill level. -//========================================================= -void CGameRules::RefreshSkillData ( void ) -{ -} - -//========================================================= -// instantiate the proper game rules object -//========================================================= -//CGameRules *InstallGameRules( void ) -//{ -// SERVER_COMMAND( "exec game.cfg\n" ); -// SERVER_EXECUTE( ); -// -// if ( !gpGlobals->deathmatch ) -// { -// // generic half-life -// g_teamplay = 0; -// return new CHalfLifeRules; -// } -// else -// { -// if ( teamplay.value > 0 ) -// { -// // teamplay -// -// g_teamplay = 1; -// return new CHalfLifeTeamplay; -// } -// if ((int)gpGlobals->deathmatch == 1) -// { -// // vanilla deathmatch -// g_teamplay = 0; -// return new CHalfLifeMultiplay; -// } -// else -// { -// // vanilla deathmatch?? -// g_teamplay = 0; -// return new CHalfLifeMultiplay; -// } -// } -//} - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// GameRules.cpp +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "teamplay_gamerules.h" +#include "skill.h" +#include "game.h" +#include "mod/AvHSpecials.h" +#include "mod/AvHHulls.h" + +DLL_GLOBAL CGameRules* g_pGameRules = NULL; +extern DLL_GLOBAL BOOL g_fGameOver; + +int g_teamplay = 1; + +//========================================================= +//========================================================= +BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry ) +{ + int iAmmoIndex; + + if ( pszAmmoName ) + { + iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName ); + + if ( iAmmoIndex > -1 ) + { + if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry ) + { + // player has room for more of this type of ammo + return TRUE; + } + } + } + + return FALSE; +} + +//========================================================= +//========================================================= +edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) +{ +// edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); +// +// pPlayer->InitPlayerFromSpawn(pentSpawnSpot); +// +// return pentSpawnSpot; + + ASSERT(FALSE); + + return NULL; +} + +//========================================================= +//========================================================= +BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ + // only living players can have items + if ( pPlayer->pev->deadflag != DEAD_NO ) + return FALSE; + + if ( pWeapon->pszAmmo1() ) + { + if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) ) + { + // we can't carry anymore ammo for this gun. We can only + // have the gun if we aren't already carrying one of this type + if ( pPlayer->HasPlayerItem( pWeapon ) ) + { + return FALSE; + } + } + } + else + { + // weapon doesn't use ammo, don't take another if you already have it. + if ( pPlayer->HasPlayerItem( pWeapon ) ) + { + return FALSE; + } + } + + // note: will fall through to here if GetItemInfo doesn't fill the struct! + return TRUE; +} + +//========================================================= +// load the SkillData struct with the proper values based on the skill level. +//========================================================= +void CGameRules::RefreshSkillData ( void ) +{ +} + +//========================================================= +// instantiate the proper game rules object +//========================================================= +//CGameRules *InstallGameRules( void ) +//{ +// SERVER_COMMAND( "exec game.cfg\n" ); +// SERVER_EXECUTE( ); +// +// if ( !gpGlobals->deathmatch ) +// { +// // generic half-life +// g_teamplay = 0; +// return new CHalfLifeRules; +// } +// else +// { +// if ( teamplay.value > 0 ) +// { +// // teamplay +// +// g_teamplay = 1; +// return new CHalfLifeTeamplay; +// } +// if ((int)gpGlobals->deathmatch == 1) +// { +// // vanilla deathmatch +// g_teamplay = 0; +// return new CHalfLifeMultiplay; +// } +// else +// { +// // vanilla deathmatch?? +// g_teamplay = 0; +// return new CHalfLifeMultiplay; +// } +// } +//} + + + diff --git a/main/source/dlls/gamerules.h b/main/source/dlls/gamerules.h index f2956497..7033f2b8 100644 --- a/main/source/dlls/gamerules.h +++ b/main/source/dlls/gamerules.h @@ -1,367 +1,367 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef GAMERULES_H -#define GAMERULES_H - -//========================================================= -// GameRules -//========================================================= - -//#include "weapons.h" -//#include "items.h" -class CBasePlayerItem; -class CBasePlayer; -class CItem; -class CBasePlayerAmmo; - -// weapon respawning return codes -enum -{ - GR_NONE = 0, - - GR_WEAPON_RESPAWN_YES, - GR_WEAPON_RESPAWN_NO, - - GR_AMMO_RESPAWN_YES, - GR_AMMO_RESPAWN_NO, - - GR_ITEM_RESPAWN_YES, - GR_ITEM_RESPAWN_NO, - - GR_PLR_DROP_GUN_ALL, - GR_PLR_DROP_GUN_ACTIVE, - GR_PLR_DROP_GUN_NO, - - GR_PLR_DROP_AMMO_ALL, - GR_PLR_DROP_AMMO_ACTIVE, - GR_PLR_DROP_AMMO_NO, -}; - -// Player relationship return codes -enum -{ - GR_NOTTEAMMATE = 0, - GR_TEAMMATE, - GR_ENEMY, - GR_ALLY, - GR_NEUTRAL, -}; - -class CGameRules -{ -public: - virtual ~CGameRules() {} - - virtual void RefreshSkillData( void );// fill skill data struct with proper values - virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch). - - virtual BOOL FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// should the player switch to this weapon? - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) = 0;// I can't use this weapon anymore, get me the next best one. - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) - virtual BOOL IsDeathmatch( void ) = 0;//is this a deathmatch game? - virtual BOOL IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? - virtual BOOL IsCoOp( void ) = 0;// is this a coop game? - virtual const char *GetGameDescription( void ) { return "Half-Life"; } // this is the game name that gets seen in the server browser - -// Client connection/disconnection - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) = 0;// a client just connected to the server (player hasn't spawned yet) - virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker? - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game - virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. - - virtual BOOL AllowAutoTargetCrosshair( void ) { return TRUE; }; - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { return FALSE; }; // handles the user commands; returns TRUE if command handled properly - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) {} // the player has changed userinfo; can change it now - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) = 0;// Called each time a player dies - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )= 0;// Call this from within a GameRules class to report an obituary. - virtual bool CanPlayerBeKilled(CBasePlayer* inPlayer) { return true; } -// Weapon retrieval - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// Called each time a player picks up a weapon from the ground - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ) = 0;// should this weapon respawn? - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) = 0;// when may this weapon respawn? - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) = 0;// where in the world should this weapon respawn? - -// Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item? - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit, longjump) - -// Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn? - virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn? - virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn? - -// Ammo retrieval - virtual BOOL CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry );// can this player take more of this ammo? - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world - -// Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) = 0;// should this ammo item respawn? - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) = 0;// when should this ammo item respawn? - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) = 0;// where in the world should this ammo item respawn? - // by default, everything spawns - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? - virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on? - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? - virtual int GetTeamIndex( const char *pTeamName ) { return -1; } - virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } - virtual BOOL IsValidTeam( const char *pTeamName ) { return TRUE; } - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} - virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } - -// Sounds - virtual BOOL PlayTextureSounds( void ) { return TRUE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } - -// Monsters - virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) {} -}; - -extern void InstallGameRules( void ); - - -//========================================================= -// CHalfLifeRules - rules for the single player Half-Life -// game. -//========================================================= -class CHalfLifeRules : public CGameRules -{ -public: - CHalfLifeRules ( void ); - -// GR_Think - virtual void Think( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ) { return TRUE; }; - - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - -// Client connection/disconnection - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - -// Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); - -// Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); - -// Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ); - virtual float FlItemRespawnTime( CItem *pItem ); - virtual Vector VecItemRespawnSpot( CItem *pItem ); - -// Ammo retrieval - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); - -// Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - -// Monsters - virtual BOOL FAllowMonsters( void ); - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); -}; - -//========================================================= -// CHalfLifeMultiplay - rules for the basic half life multiplayer -// competition -//========================================================= -class CHalfLifeMultiplay : public CGameRules -{ -public: - CHalfLifeMultiplay(); - -// GR_Think - virtual void Think( void ); - virtual void RefreshSkillData( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ); - - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - -// Client connection/disconnection - // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in - // svRejectReason - // Only the client's name and remote address are provided to the dll for verification. - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - -// Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); - -// Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); - -// Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ); - virtual float FlItemRespawnTime( CItem *pItem ); - virtual Vector VecItemRespawnSpot( CItem *pItem ); - -// Ammo retrieval - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); - -// Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - virtual float FlHEVChargerRechargeTime( void ); - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - - virtual BOOL PlayTextureSounds( void ) { return FALSE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ); - -// Monsters - virtual BOOL FAllowMonsters( void ); - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) { GoToIntermission(); } - -protected: - virtual void ChangeLevel( void ); - virtual void GoToIntermission( void ); - float m_flIntermissionEndTime; - BOOL m_iEndIntermissionButtonHit; - virtual void SendMOTDToClient( edict_t *client ); -}; - -extern DLL_GLOBAL CGameRules* g_pGameRules; - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef GAMERULES_H +#define GAMERULES_H + +//========================================================= +// GameRules +//========================================================= + +//#include "weapons.h" +//#include "items.h" +class CBasePlayerItem; +class CBasePlayer; +class CItem; +class CBasePlayerAmmo; + +// weapon respawning return codes +enum +{ + GR_NONE = 0, + + GR_WEAPON_RESPAWN_YES, + GR_WEAPON_RESPAWN_NO, + + GR_AMMO_RESPAWN_YES, + GR_AMMO_RESPAWN_NO, + + GR_ITEM_RESPAWN_YES, + GR_ITEM_RESPAWN_NO, + + GR_PLR_DROP_GUN_ALL, + GR_PLR_DROP_GUN_ACTIVE, + GR_PLR_DROP_GUN_NO, + + GR_PLR_DROP_AMMO_ALL, + GR_PLR_DROP_AMMO_ACTIVE, + GR_PLR_DROP_AMMO_NO, +}; + +// Player relationship return codes +enum +{ + GR_NOTTEAMMATE = 0, + GR_TEAMMATE, + GR_ENEMY, + GR_ALLY, + GR_NEUTRAL, +}; + +class CGameRules +{ +public: + virtual ~CGameRules() {} + + virtual void RefreshSkillData( void );// fill skill data struct with proper values + virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch). + + virtual BOOL FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// should the player switch to this weapon? + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) = 0;// I can't use this weapon anymore, get me the next best one. + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) + virtual BOOL IsDeathmatch( void ) = 0;//is this a deathmatch game? + virtual BOOL IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? + virtual BOOL IsCoOp( void ) = 0;// is this a coop game? + virtual const char *GetGameDescription( void ) { return "Half-Life"; } // this is the game name that gets seen in the server browser + +// Client connection/disconnection + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) = 0;// a client just connected to the server (player hasn't spawned yet) + virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker? + virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game + virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? + virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. + + virtual BOOL AllowAutoTargetCrosshair( void ) { return TRUE; }; + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { return FALSE; }; // handles the user commands; returns TRUE if command handled properly + virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) {} // the player has changed userinfo; can change it now + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) = 0;// Called each time a player dies + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )= 0;// Call this from within a GameRules class to report an obituary. + virtual bool CanPlayerBeKilled(CBasePlayer* inPlayer) { return true; } +// Weapon retrieval + virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// Called each time a player picks up a weapon from the ground + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ) = 0;// should this weapon respawn? + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) = 0;// when may this weapon respawn? + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) = 0;// where in the world should this weapon respawn? + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item? + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit, longjump) + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn? + virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn? + virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn? + +// Ammo retrieval + virtual BOOL CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry );// can this player take more of this ammo? + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) = 0;// should this ammo item respawn? + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) = 0;// when should this ammo item respawn? + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) = 0;// where in the world should this ammo item respawn? + // by default, everything spawns + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? + virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on? + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? + virtual int GetTeamIndex( const char *pTeamName ) { return -1; } + virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } + virtual BOOL IsValidTeam( const char *pTeamName ) { return TRUE; } + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} + virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } + +// Sounds + virtual BOOL PlayTextureSounds( void ) { return TRUE; } + virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } + +// Monsters + virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) {} +}; + +extern void InstallGameRules( void ); + + +//========================================================= +// CHalfLifeRules - rules for the single player Half-Life +// game. +//========================================================= +class CHalfLifeRules : public CGameRules +{ +public: + CHalfLifeRules ( void ); + +// GR_Think + virtual void Think( void ); + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual BOOL FAllowFlashlight( void ) { return TRUE; }; + + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ); + virtual BOOL IsDeathmatch( void ); + virtual BOOL IsCoOp( void ); + +// Client connection/disconnection + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + + virtual BOOL AllowAutoTargetCrosshair( void ); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + +// Weapon retrieval + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// Monsters + virtual BOOL FAllowMonsters( void ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); +}; + +//========================================================= +// CHalfLifeMultiplay - rules for the basic half life multiplayer +// competition +//========================================================= +class CHalfLifeMultiplay : public CGameRules +{ +public: + CHalfLifeMultiplay(); + +// GR_Think + virtual void Think( void ); + virtual void RefreshSkillData( void ); + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual BOOL FAllowFlashlight( void ); + + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ); + virtual BOOL IsDeathmatch( void ); + virtual BOOL IsCoOp( void ); + +// Client connection/disconnection + // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in + // svRejectReason + // Only the client's name and remote address are provided to the dll for verification. + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); + + virtual BOOL AllowAutoTargetCrosshair( void ); + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + +// Weapon retrieval + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + virtual float FlHEVChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + + virtual BOOL PlayTextureSounds( void ) { return FALSE; } + virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ); + +// Monsters + virtual BOOL FAllowMonsters( void ); + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) { GoToIntermission(); } + +protected: + virtual void ChangeLevel( void ); + virtual void GoToIntermission( void ); + float m_flIntermissionEndTime; + BOOL m_iEndIntermissionButtonHit; + virtual void SendMOTDToClient( edict_t *client ); +}; + +extern DLL_GLOBAL CGameRules* g_pGameRules; + #endif \ No newline at end of file diff --git a/main/source/dlls/gargantua.cpp b/main/source/dlls/gargantua.cpp index 3a77d743..a7bcc547 100644 --- a/main/source/dlls/gargantua.cpp +++ b/main/source/dlls/gargantua.cpp @@ -1,1368 +1,1368 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -//========================================================= -// Gargantua -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "schedule.h" -#include "customentity.h" -#include "weapons.h" -#include "effects.h" -#include "soundent.h" -#include "decals.h" -#include "explode.h" -#include "func_break.h" - -//========================================================= -// Gargantua Monster -//========================================================= -const float GARG_ATTACKDIST = 80.0; - -// Garg animation events -#define GARG_AE_SLASH_LEFT 1 -//#define GARG_AE_BEAM_ATTACK_RIGHT 2 // No longer used -#define GARG_AE_LEFT_FOOT 3 -#define GARG_AE_RIGHT_FOOT 4 -#define GARG_AE_STOMP 5 -#define GARG_AE_BREATHE 6 - - -// Gargantua is immune to any damage but this -#define GARG_DAMAGE (DMG_ENERGYBEAM|DMG_CRUSH|DMG_MORTAR|DMG_BLAST) -#define GARG_EYE_SPRITE_NAME "sprites/gargeye1.spr" -#define GARG_BEAM_SPRITE_NAME "sprites/xbeam3.spr" -#define GARG_BEAM_SPRITE2 "sprites/xbeam3.spr" -#define GARG_STOMP_SPRITE_NAME "sprites/gargeye1.spr" -#define GARG_STOMP_BUZZ_SOUND "weapons/mine_charge.wav" -#define GARG_FLAME_LENGTH 330 -#define GARG_GIB_MODEL "models/metalplategibs.mdl" - -#define ATTN_GARG (ATTN_NORM) - -#define STOMP_SPRITE_COUNT 10 - -int gStompSprite = 0, gGargGibModel = 0; -void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ); - -class CSmoker; - -// Spiral Effect -class CSpiral : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - static CSpiral *Create( const Vector &origin, float height, float radius, float duration ); -}; -LINK_ENTITY_TO_CLASS( streak_spiral, CSpiral ); - - -class CStomp : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed ); - -private: -// UNDONE: re-use this sprite list instead of creating new ones all the time -// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ]; -}; - -LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ); -CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed ) -{ - CStomp *pStomp = GetClassPtr( (CStomp *)NULL ); - - pStomp->pev->origin = origin; - Vector dir = (end - origin); - pStomp->pev->scale = dir.Length(); - pStomp->pev->movedir = dir.Normalize(); - pStomp->pev->speed = speed; - pStomp->Spawn(); - - return pStomp; -} - -void CStomp::Spawn( void ) -{ - pev->nextthink = gpGlobals->time; - pev->classname = MAKE_STRING("garg_stomp"); - pev->dmgtime = gpGlobals->time; - - pev->framerate = 30; - pev->model = MAKE_STRING(GARG_STOMP_SPRITE_NAME); - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; - EMIT_SOUND_DYN( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55); -} - - -#define STOMP_INTERVAL 0.025 - -void CStomp::Think( void ) -{ - TraceResult tr; - - pev->nextthink = gpGlobals->time + 0.1; - - // Do damage for this frame - Vector vecStart = pev->origin; - vecStart.z += 30; - Vector vecEnd = vecStart + (pev->movedir * pev->speed * gpGlobals->frametime); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit && tr.pHit != pev->owner ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - entvars_t *pevOwner = pev; - if ( pev->owner ) - pevOwner = VARS(pev->owner); - - if ( pEntity ) - pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC ); - } - - // Accelerate the effect - pev->speed = pev->speed + (gpGlobals->frametime) * pev->framerate; - pev->framerate = pev->framerate + (gpGlobals->frametime) * 1500; - - // Move and spawn trails - while ( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) - { - pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL; - for ( int i = 0; i < 2; i++ ) - { - CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, pev->origin, TRUE ); - if ( pSprite ) - { - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,500), ignore_monsters, edict(), &tr ); - pSprite->pev->origin = tr.vecEndPos; - pSprite->pev->velocity = Vector(RANDOM_FLOAT(-200,200),RANDOM_FLOAT(-200,200),175); - // pSprite->AnimateAndDie( RANDOM_FLOAT( 8.0, 12.0 ) ); - pSprite->pev->nextthink = gpGlobals->time + 0.3; - pSprite->SetThink( &CStomp::SUB_Remove ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); - } - } - pev->dmgtime += STOMP_INTERVAL; - // Scale has the "life" of this effect - pev->scale -= STOMP_INTERVAL * pev->speed; - if ( pev->scale <= 0 ) - { - // Life has run out - UTIL_Remove(this); - STOP_SOUND( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND ); - } - - } -} - - -void StreakSplash( const Vector &origin, const Vector &direction, int color, int count, int speed, int velocityRange ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_STREAK_SPLASH ); - WRITE_COORD( origin.x ); // origin - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); // direction - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); // Streak color 6 - WRITE_SHORT( count ); // count - WRITE_SHORT( speed ); - WRITE_SHORT( velocityRange ); // Random velocity modifier - MESSAGE_END(); -} - - -class CGargantua : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - BOOL CheckMeleeAttack1( float flDot, float flDist ); // Swipe - BOOL CheckMeleeAttack2( float flDot, float flDist ); // Flames - BOOL CheckRangeAttack1( float flDot, float flDist ); // Stomp attack - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -80, -80, 0 ); - pev->absmax = pev->origin + Vector( 80, 80, 214 ); - } - - Schedule_t *GetScheduleOfType( int Type ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - - void PrescheduleThink( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - void DeathEffect( void ); - - void EyeOff( void ); - void EyeOn( int level ); - void EyeUpdate( void ); - void Leap( void ); - void StompAttack( void ); - void FlameCreate( void ); - void FlameUpdate( void ); - void FlameControls( float angleX, float angleY ); - void FlameDestroy( void ); - inline BOOL FlameIsOn( void ) { return m_pFlame[0] != NULL; } - - void FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CUSTOM_SCHEDULES; - -private: - static const char *pAttackHitSounds[]; - static const char *pBeamAttackSounds[]; - static const char *pAttackMissSounds[]; - static const char *pRicSounds[]; - static const char *pFootSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackSounds[]; - static const char *pStompSounds[]; - static const char *pBreatheSounds[]; - - CBaseEntity* GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType); - - CSprite *m_pEyeGlow; // Glow around the eyes - CBeam *m_pFlame[4]; // Flame beams - - int m_eyeBrightness; // Brightness target - float m_seeTime; // Time to attack (when I see the enemy, I set this) - float m_flameTime; // Time of next flame attack - float m_painSoundTime; // Time of next pain sound - float m_streakTime; // streak timer (don't send too many) - float m_flameX; // Flame thrower aim - float m_flameY; -}; - -LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ); - -TYPEDESCRIPTION CGargantua::m_SaveData[] = -{ - DEFINE_FIELD( CGargantua, m_pEyeGlow, FIELD_CLASSPTR ), - DEFINE_FIELD( CGargantua, m_eyeBrightness, FIELD_INTEGER ), - DEFINE_FIELD( CGargantua, m_seeTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_flameTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_streakTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_painSoundTime, FIELD_TIME ), - DEFINE_ARRAY( CGargantua, m_pFlame, FIELD_CLASSPTR, 4 ), - DEFINE_FIELD( CGargantua, m_flameX, FIELD_FLOAT ), - DEFINE_FIELD( CGargantua, m_flameY, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ); - -const char *CGargantua::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CGargantua::pBeamAttackSounds[] = -{ - "garg/gar_flameoff1.wav", - "garg/gar_flameon1.wav", - "garg/gar_flamerun1.wav", -}; - - -const char *CGargantua::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CGargantua::pRicSounds[] = -{ -#if 0 - "weapons/ric1.wav", - "weapons/ric2.wav", - "weapons/ric3.wav", - "weapons/ric4.wav", - "weapons/ric5.wav", -#else - "debris/metal4.wav", - "debris/metal6.wav", - "weapons/ric4.wav", - "weapons/ric5.wav", -#endif -}; - -const char *CGargantua::pFootSounds[] = -{ - "garg/gar_step1.wav", - "garg/gar_step2.wav", -}; - - -const char *CGargantua::pIdleSounds[] = -{ - "garg/gar_idle1.wav", - "garg/gar_idle2.wav", - "garg/gar_idle3.wav", - "garg/gar_idle4.wav", - "garg/gar_idle5.wav", -}; - - -const char *CGargantua::pAttackSounds[] = -{ - "garg/gar_attack1.wav", - "garg/gar_attack2.wav", - "garg/gar_attack3.wav", -}; - -const char *CGargantua::pAlertSounds[] = -{ - "garg/gar_alert1.wav", - "garg/gar_alert2.wav", - "garg/gar_alert3.wav", -}; - -const char *CGargantua::pPainSounds[] = -{ - "garg/gar_pain1.wav", - "garg/gar_pain2.wav", - "garg/gar_pain3.wav", -}; - -const char *CGargantua::pStompSounds[] = -{ - "garg/gar_stomp1.wav", -}; - -const char *CGargantua::pBreatheSounds[] = -{ - "garg/gar_breathe1.wav", - "garg/gar_breathe2.wav", - "garg/gar_breathe3.wav", -}; -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -#if 0 -enum -{ - SCHED_ = LAST_COMMON_SCHEDULE + 1, -}; -#endif - -enum -{ - TASK_SOUND_ATTACK = LAST_COMMON_TASK + 1, - TASK_FLAME_SWEEP, -}; - -Task_t tlGargFlame[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SOUND_ATTACK, (float)0 }, - // { TASK_PLAY_SEQUENCE, (float)ACT_SIGNAL1 }, - { TASK_SET_ACTIVITY, (float)ACT_MELEE_ATTACK2 }, - { TASK_FLAME_SWEEP, (float)4.5 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slGargFlame[] = -{ - { - tlGargFlame, - ARRAYSIZE ( tlGargFlame ), - 0, - 0, - "GargFlame" - }, -}; - - -// primary melee attack -Task_t tlGargSwipe[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, -}; - -Schedule_t slGargSwipe[] = -{ - { - tlGargSwipe, - ARRAYSIZE ( tlGargSwipe ), - bits_COND_CAN_MELEE_ATTACK2, - 0, - "GargSwipe" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CGargantua ) -{ - slGargFlame, - slGargSwipe, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CGargantua, CBaseMonster ); - - -void CGargantua::EyeOn( int level ) -{ - m_eyeBrightness = level; -} - - -void CGargantua::EyeOff( void ) -{ - m_eyeBrightness = 0; -} - - -void CGargantua::EyeUpdate( void ) -{ - if ( m_pEyeGlow ) - { - m_pEyeGlow->pev->renderamt = UTIL_Approach( m_eyeBrightness, m_pEyeGlow->pev->renderamt, 26 ); - if ( m_pEyeGlow->pev->renderamt == 0 ) - m_pEyeGlow->pev->effects |= EF_NODRAW; - else - m_pEyeGlow->pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( m_pEyeGlow->pev, pev->origin ); - } -} - - -void CGargantua::StompAttack( void ) -{ - TraceResult trace; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin + Vector(0,0,60) + 35 * gpGlobals->v_forward; - Vector vecAim = ShootAtEnemy( vecStart ); - Vector vecEnd = (vecAim * 1024) + vecStart; - - UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace ); - CStomp::StompCreate( vecStart, trace.vecEndPos, 0 ); - UTIL_ScreenShake( pev->origin, 12.0, 100.0, 2.0, 1000 ); - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pStompSounds[ RANDOM_LONG(0,ARRAYSIZE(pStompSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); - - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,20), ignore_monsters, edict(), &trace ); - if ( trace.flFraction < 1.0 ) - UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 ); -} - - -void CGargantua :: FlameCreate( void ) -{ - int i; - Vector posGun, angleGun; - TraceResult trace; - - UTIL_MakeVectors( pev->angles ); - - for ( i = 0; i < 4; i++ ) - { - if ( i < 2 ) - m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE_NAME, 240 ); - else - m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE2, 140 ); - if ( m_pFlame[i] ) - { - int attach = i%2; - // attachment is 0 based in GetAttachment - GetAttachment( attach+1, posGun, angleGun ); - - Vector vecEnd = (gpGlobals->v_forward * GARG_FLAME_LENGTH) + posGun; - UTIL_TraceLine( posGun, vecEnd, dont_ignore_monsters, edict(), &trace ); - - m_pFlame[i]->PointEntInit( trace.vecEndPos, entindex() ); - if ( i < 2 ) - m_pFlame[i]->SetColor( 255, 130, 90 ); - else - m_pFlame[i]->SetColor( 0, 120, 255 ); - m_pFlame[i]->SetBrightness( 190 ); - m_pFlame[i]->SetFlags( BEAM_FSHADEIN ); - m_pFlame[i]->SetScrollRate( 20 ); - // attachment is 1 based in SetEndAttachment - m_pFlame[i]->SetEndAttachment( attach + 2 ); - CSoundEnt::InsertSound( bits_SOUND_COMBAT, posGun, 384, 0.3 ); - } - } - EMIT_SOUND_DYN ( edict(), CHAN_BODY, pBeamAttackSounds[ 1 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 2 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); -} - - -void CGargantua :: FlameControls( float angleX, float angleY ) -{ - if ( angleY < -180 ) - angleY += 360; - else if ( angleY > 180 ) - angleY -= 360; - - if ( angleY < -45 ) - angleY = -45; - else if ( angleY > 45 ) - angleY = 45; - - m_flameX = UTIL_ApproachAngle( angleX, m_flameX, 4 ); - m_flameY = UTIL_ApproachAngle( angleY, m_flameY, 8 ); - SetBoneController( 0, m_flameY ); - SetBoneController( 1, m_flameX ); -} - - -void CGargantua :: FlameUpdate( void ) -{ - int i; - static float offset[2] = { 60, -60 }; - TraceResult trace; - Vector vecStart, angleGun; - BOOL streaks = FALSE; - - for ( i = 0; i < 2; i++ ) - { - if ( m_pFlame[i] ) - { - Vector vecAim = pev->angles; - vecAim.x += m_flameX; - vecAim.y += m_flameY; - - UTIL_MakeVectors( vecAim ); - - GetAttachment( i+1, vecStart, angleGun ); - Vector vecEnd = vecStart + (gpGlobals->v_forward * GARG_FLAME_LENGTH); // - offset[i] * gpGlobals->v_right; - - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &trace ); - - m_pFlame[i]->SetStartPos( trace.vecEndPos ); - m_pFlame[i+2]->SetStartPos( (vecStart * 0.6) + (trace.vecEndPos * 0.4) ); - - if ( trace.flFraction != 1.0 && gpGlobals->time > m_streakTime ) - { - StreakSplash( trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400 ); - streaks = TRUE; - UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0,2) ); - } - // RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); - FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 * (i + 2) ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( RANDOM_FLOAT( 32, 48 ) ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } - } - if ( streaks ) - m_streakTime = gpGlobals->time; -} - - - -void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage; - Vector vecSpot; - - Vector vecMid = (vecStart + vecEnd) * 0.5; - - float searchRadius = (vecStart - vecMid).Length(); - - Vector vecAim = (vecEnd - vecStart).Normalize( ); - - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius )) != NULL) - { - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - // UNDONE: this should check a damage mask, not an ignore - if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - {// houndeyes don't hurt other houndeyes with their attack - continue; - } - - vecSpot = pEntity->BodyTarget( vecMid ); - - float dist = DotProduct( vecAim, vecSpot - vecMid ); - if (dist > searchRadius) - dist = searchRadius; - else if (dist < -searchRadius) - dist = searchRadius; - - Vector vecSrc = vecMid + dist * vecAim; - - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pev), &tr ); - - if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - {// the explosion can 'see' this entity, so hurt them! - // decrease damage for an ent that's farther from the flame. - dist = ( vecSrc - tr.vecEndPos ).Length(); - - if (dist > 64) - { - flAdjustedDamage = flDamage - (dist - 64) * 0.4; - if (flAdjustedDamage <= 0) - continue; - } - else - { - flAdjustedDamage = flDamage; - } - - // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if (tr.flFraction != 1.0) - { - ClearMultiDamage( ); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); - ApplyMultiDamage( pevInflictor, pevAttacker ); - } - else - { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } -} - - -void CGargantua :: FlameDestroy( void ) -{ - int i; - - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 0 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - for ( i = 0; i < 4; i++ ) - { - if ( m_pFlame[i] ) - { - UTIL_Remove( m_pFlame[i] ); - m_pFlame[i] = NULL; - } - } -} - - -void CGargantua :: PrescheduleThink( void ) -{ - if ( !HasConditions( bits_COND_SEE_ENEMY ) ) - { - m_seeTime = gpGlobals->time + 5; - EyeOff(); - } - else - EyeOn( 200 ); - - EyeUpdate(); -} - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGargantua :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGargantua :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 60; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_WALK: - case ACT_RUN: - ys = 60; - break; - - default: - ys = 60; - break; - } - - pev->yaw_speed = ys; -} - - -//========================================================= -// Spawn -//========================================================= -void CGargantua :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/garg.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.gargantuaHealth; - //pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file - m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - - m_pEyeGlow = CSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetAttachment( edict(), 1 ); - EyeOff(); - m_seeTime = gpGlobals->time + 5; - m_flameTime = gpGlobals->time + 2; -} - - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGargantua :: Precache() -{ - int i; - - PRECACHE_MODEL("models/garg.mdl"); - PRECACHE_MODEL( GARG_EYE_SPRITE_NAME ); - PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME ); - PRECACHE_MODEL( GARG_BEAM_SPRITE2 ); - gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME ); - gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL ); - PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND ); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pBeamAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ ) - PRECACHE_SOUND((char *)pRicSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ ) - PRECACHE_SOUND((char *)pFootSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ ) - PRECACHE_SOUND((char *)pStompSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ ) - PRECACHE_SOUND((char *)pBreatheSounds[i]); -} - - -void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - ALERT( at_aiconsole, "CGargantua::TraceAttack\n"); - - if ( !IsAlive() ) - { - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); - return; - } - - // UNDONE: Hit group specific damage? - if ( bitsDamageType & (GARG_DAMAGE|DMG_BLAST) ) - { - if ( m_painSoundTime < gpGlobals->time ) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM ); - m_painSoundTime = gpGlobals->time + RANDOM_FLOAT( 2.5, 4 ); - } - } - - bitsDamageType &= GARG_DAMAGE; - - if ( bitsDamageType == 0) - { - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,100) < 20) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - pev->dmgtime = gpGlobals->time; -// if ( RANDOM_LONG(0,100) < 25 ) -// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - } - flDamage = 0; - } - - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); - -} - - - -int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - ALERT( at_aiconsole, "CGargantua::TakeDamage\n"); - - if ( IsAlive() ) - { - if ( !(bitsDamageType & GARG_DAMAGE) ) - flDamage *= 0.01; - if ( bitsDamageType & DMG_BLAST ) - SetConditions( bits_COND_LIGHT_DAMAGE ); - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - -void CGargantua::DeathEffect( void ) -{ - int i; - UTIL_MakeVectors(pev->angles); - Vector deathPos = pev->origin + gpGlobals->v_forward * 100; - - // Create a spiral of streaks - CSpiral::Create( deathPos, (pev->absmax.z - pev->absmin.z) * 0.6, 125, 1.5 ); - - Vector position = pev->origin; - position.z += 32; - for ( i = 0; i < 7; i+=2 ) - { - SpawnExplosion( position, 70, (i * 0.3), 60 + (i*20) ); - position.z += 15; - } - - CBaseEntity *pSmoker = CBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL ); - pSmoker->pev->health = 1; // 1 smoke balls - pSmoker->pev->scale = 46; // 4.6X normal size - pSmoker->pev->dmg = 0; // 0 radial distribution - pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds -} - - -void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) -{ - EyeOff(); - UTIL_Remove( m_pEyeGlow ); - m_pEyeGlow = NULL; - CBaseMonster::Killed( pevAttacker, GIB_NEVER ); -} - -//========================================================= -// CheckMeleeAttack1 -// Garg swipe attack -// -//========================================================= -BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) -{ -// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); - - if (flDot >= 0.7) - { - if (flDist <= GARG_ATTACKDIST) - return TRUE; - } - return FALSE; -} - - -// Flame thrower madness! -BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) -{ -// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); - - if ( gpGlobals->time > m_flameTime ) - { - if (flDot >= 0.8 && flDist > GARG_ATTACKDIST) - { - if ( flDist <= GARG_FLAME_LENGTH ) - return TRUE; - } - } - return FALSE; -} - - -//========================================================= -// CheckRangeAttack1 -// flDot is the cos of the angle of the cone within which -// the attack can occur. -//========================================================= -// -// Stomp attack -// -//========================================================= -BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) -{ - if ( gpGlobals->time > m_seeTime ) - { - if (flDot >= 0.7 && flDist > GARG_ATTACKDIST) - { - return TRUE; - } - } - return FALSE; -} - - - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGargantua::HandleAnimEvent(MonsterEvent_t *pEvent) -{ - switch( pEvent->event ) - { - case GARG_AE_SLASH_LEFT: - { - // HACKHACK!!! - CBaseEntity *pHurt = GargantuaCheckTraceHullAttack( GARG_ATTACKDIST + 10.0, gSkillData.gargantuaDmgSlash, DMG_SLASH ); - if (pHurt) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.x = -30; // pitch - pHurt->pev->punchangle.y = -30; // yaw - pHurt->pev->punchangle.z = 30; // roll - //UTIL_MakeVectors(pev->angles); // called by CheckTraceHullAttack - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; - } - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) ); - } - else // Play a random attack miss sound - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) ); - - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - } - break; - - case GARG_AE_RIGHT_FOOT: - case GARG_AE_LEFT_FOOT: - UTIL_ScreenShake( pev->origin, 4.0, 3.0, 1.0, 750 ); - EMIT_SOUND_DYN ( edict(), CHAN_BODY, pFootSounds[ RANDOM_LONG(0,ARRAYSIZE(pFootSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); - break; - - case GARG_AE_STOMP: - StompAttack(); - m_seeTime = gpGlobals->time + 12; - break; - - case GARG_AE_BREATHE: - EMIT_SOUND_DYN ( edict(), CHAN_VOICE, pBreatheSounds[ RANDOM_LONG(0,ARRAYSIZE(pBreatheSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); - break; - - default: - CBaseMonster::HandleAnimEvent(pEvent); - break; - } -} - - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// Used for many contact-range melee attacks. Bites, claws, etc. - -// Overridden for Gargantua because his swing starts lower as -// a percentage of his height (otherwise he swings over the -// players head) -//========================================================= -CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += 64; - Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist) - (gpGlobals->v_up * flDist * 0.3); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( iDamage > 0 ) - { - pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); - } - - return pEntity; - } - - return NULL; -} - - -Schedule_t *CGargantua::GetScheduleOfType( int Type ) -{ - // HACKHACK - turn off the flames if they are on and garg goes scripted / dead - if ( FlameIsOn() ) - FlameDestroy(); - - switch( Type ) - { - case SCHED_MELEE_ATTACK2: - return slGargFlame; - case SCHED_MELEE_ATTACK1: - return slGargSwipe; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -void CGargantua::StartTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_FLAME_SWEEP: - FlameCreate(); - m_flWaitFinished = gpGlobals->time + pTask->flData; - m_flameTime = gpGlobals->time + 6; - m_flameX = 0; - m_flameY = 0; - break; - - case TASK_SOUND_ATTACK: - if ( RANDOM_LONG(0,100) < 30 ) - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM ); - TaskComplete(); - break; - - case TASK_DIE: - m_flWaitFinished = gpGlobals->time + 1.6; - DeathEffect(); - // FALL THROUGH - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CGargantua::RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_DIE: - if ( gpGlobals->time > m_flWaitFinished ) - { - pev->renderfx = kRenderFxExplode; - pev->rendercolor.x = 255; - pev->rendercolor.y = 0; - pev->rendercolor.z = 0; - StopAnimation(); - pev->nextthink = gpGlobals->time + 0.15; - SetThink( &CGargantua::SUB_Remove ); - int i; - int parts = MODEL_FRAMES( gGargGibModel ); - for ( i = 0; i < 10; i++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( GARG_GIB_MODEL ); - - int bodyPart = 0; - if ( parts > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body-1 ); - - pGib->pev->body = bodyPart; - pGib->m_bloodColor = BLOOD_COLOR_YELLOW; - pGib->m_material = matNone; - pGib->pev->origin = pev->origin; - pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ); - pGib->pev->nextthink = gpGlobals->time + 1.25; - pGib->SetThink( &CGargantua::SUB_FadeOut ); - } - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - - // size - WRITE_COORD( 200 ); - WRITE_COORD( 200 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - - // randomization - WRITE_BYTE( 200 ); - - // Model - WRITE_SHORT( gGargGibModel ); //model id# - - // # of shards - WRITE_BYTE( 50 ); - - // duration - WRITE_BYTE( 20 );// 3.0 seconds - - // flags - - WRITE_BYTE( BREAK_FLESH ); - MESSAGE_END(); - - return; - } - else - CBaseMonster::RunTask(pTask); - break; - - case TASK_FLAME_SWEEP: - if ( gpGlobals->time > m_flWaitFinished ) - { - FlameDestroy(); - TaskComplete(); - FlameControls( 0, 0 ); - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - } - else - { - BOOL cancel = FALSE; - - Vector angles = g_vecZero; - - FlameUpdate(); - CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy ) - { - Vector org = pev->origin; - org.z += 64; - Vector dir = pEnemy->BodyTarget(org) - org; - angles = UTIL_VecToAngles( dir ); - angles.x = -angles.x; - angles.y -= pev->angles.y; - if ( dir.Length() > 400 ) - cancel = TRUE; - } - if ( fabs(angles.y) > 60 ) - cancel = TRUE; - - if ( cancel ) - { - m_flWaitFinished -= 0.5; - m_flameTime -= 0.5; - } - // FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) ); - FlameControls( angles.x, angles.y ); - } - break; - - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - - -class CSmoker : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( env_smoker, CSmoker ); - -void CSmoker::Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time; - pev->solid = SOLID_NOT; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->angles = g_vecZero; -} - - -void CSmoker::Think( void ) -{ - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg )); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg )); - WRITE_COORD( pev->origin.z); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) ); - WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate - MESSAGE_END(); - - pev->health--; - if ( pev->health > 0 ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2); - else - UTIL_Remove( this ); -} - - -void CSpiral::Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time; - pev->solid = SOLID_NOT; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->angles = g_vecZero; -} - - -CSpiral *CSpiral::Create( const Vector &origin, float height, float radius, float duration ) -{ - if ( duration <= 0 ) - return NULL; - - CSpiral *pSpiral = GetClassPtr( (CSpiral *)NULL ); - pSpiral->Spawn(); - pSpiral->pev->dmgtime = pSpiral->pev->nextthink; - pSpiral->pev->origin = origin; - pSpiral->pev->scale = radius; - pSpiral->pev->dmg = height; - pSpiral->pev->speed = duration; - pSpiral->pev->health = 0; - pSpiral->pev->angles = g_vecZero; - - return pSpiral; -} - -#define SPIRAL_INTERVAL 0.1 //025 - -void CSpiral::Think( void ) -{ - float time = gpGlobals->time - pev->dmgtime; - - while ( time > SPIRAL_INTERVAL ) - { - Vector position = pev->origin; - Vector direction = Vector(0,0,1); - - float fraction = 1.0 / pev->speed; - - float radius = (pev->scale * pev->health) * fraction; - - position.z += (pev->health * pev->dmg) * fraction; - pev->angles.y = (pev->health * 360 * 8) * fraction; - UTIL_MakeVectors( pev->angles ); - position = position + gpGlobals->v_forward * radius; - direction = (direction + gpGlobals->v_forward).Normalize(); - - StreakSplash( position, Vector(0,0,1), RANDOM_LONG(8,11), 20, RANDOM_LONG(50,150), 400 ); - - // Jeez, how many counters should this take ? :) - pev->dmgtime += SPIRAL_INTERVAL; - pev->health += SPIRAL_INTERVAL; - time -= SPIRAL_INTERVAL; - } - - pev->nextthink = gpGlobals->time; - - if ( pev->health >= pev->speed ) - UTIL_Remove( this ); -} - - -// HACKHACK Cut and pasted from explode.cpp -void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ) -{ - KeyValueData kvd; - char buf[128]; - - center.x += RANDOM_FLOAT( -randomRange, randomRange ); - center.y += RANDOM_FLOAT( -randomRange, randomRange ); - - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero, NULL ); - sprintf( buf, "%3d", magnitude ); - kvd.szKeyName = "iMagnitude"; - kvd.szValue = buf; - pExplosion->KeyValue( &kvd ); - pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; - - pExplosion->Spawn(); - pExplosion->SetThink( CBaseEntity::SUB_CallUseToggle ); - pExplosion->pev->nextthink = gpGlobals->time + time; -} - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef OEM_BUILD + +//========================================================= +// Gargantua +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "nodes.h" +#include "monsters.h" +#include "schedule.h" +#include "customentity.h" +#include "weapons.h" +#include "effects.h" +#include "soundent.h" +#include "decals.h" +#include "explode.h" +#include "func_break.h" + +//========================================================= +// Gargantua Monster +//========================================================= +const float GARG_ATTACKDIST = 80.0; + +// Garg animation events +#define GARG_AE_SLASH_LEFT 1 +//#define GARG_AE_BEAM_ATTACK_RIGHT 2 // No longer used +#define GARG_AE_LEFT_FOOT 3 +#define GARG_AE_RIGHT_FOOT 4 +#define GARG_AE_STOMP 5 +#define GARG_AE_BREATHE 6 + + +// Gargantua is immune to any damage but this +#define GARG_DAMAGE (DMG_ENERGYBEAM|DMG_CRUSH|DMG_MORTAR|DMG_BLAST) +#define GARG_EYE_SPRITE_NAME "sprites/gargeye1.spr" +#define GARG_BEAM_SPRITE_NAME "sprites/xbeam3.spr" +#define GARG_BEAM_SPRITE2 "sprites/xbeam3.spr" +#define GARG_STOMP_SPRITE_NAME "sprites/gargeye1.spr" +#define GARG_STOMP_BUZZ_SOUND "weapons/mine_charge.wav" +#define GARG_FLAME_LENGTH 330 +#define GARG_GIB_MODEL "models/metalplategibs.mdl" + +#define ATTN_GARG (ATTN_NORM) + +#define STOMP_SPRITE_COUNT 10 + +int gStompSprite = 0, gGargGibModel = 0; +void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ); + +class CSmoker; + +// Spiral Effect +class CSpiral : public CBaseEntity +{ +public: + void Spawn( void ); + void Think( void ); + int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + static CSpiral *Create( const Vector &origin, float height, float radius, float duration ); +}; +LINK_ENTITY_TO_CLASS( streak_spiral, CSpiral ); + + +class CStomp : public CBaseEntity +{ +public: + void Spawn( void ); + void Think( void ); + static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed ); + +private: +// UNDONE: re-use this sprite list instead of creating new ones all the time +// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ]; +}; + +LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ); +CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed ) +{ + CStomp *pStomp = GetClassPtr( (CStomp *)NULL ); + + pStomp->pev->origin = origin; + Vector dir = (end - origin); + pStomp->pev->scale = dir.Length(); + pStomp->pev->movedir = dir.Normalize(); + pStomp->pev->speed = speed; + pStomp->Spawn(); + + return pStomp; +} + +void CStomp::Spawn( void ) +{ + pev->nextthink = gpGlobals->time; + pev->classname = MAKE_STRING("garg_stomp"); + pev->dmgtime = gpGlobals->time; + + pev->framerate = 30; + pev->model = MAKE_STRING(GARG_STOMP_SPRITE_NAME); + pev->rendermode = kRenderTransTexture; + pev->renderamt = 0; + EMIT_SOUND_DYN( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55); +} + + +#define STOMP_INTERVAL 0.025 + +void CStomp::Think( void ) +{ + TraceResult tr; + + pev->nextthink = gpGlobals->time + 0.1; + + // Do damage for this frame + Vector vecStart = pev->origin; + vecStart.z += 30; + Vector vecEnd = vecStart + (pev->movedir * pev->speed * gpGlobals->frametime); + + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); + + if ( tr.pHit && tr.pHit != pev->owner ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + entvars_t *pevOwner = pev; + if ( pev->owner ) + pevOwner = VARS(pev->owner); + + if ( pEntity ) + pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC ); + } + + // Accelerate the effect + pev->speed = pev->speed + (gpGlobals->frametime) * pev->framerate; + pev->framerate = pev->framerate + (gpGlobals->frametime) * 1500; + + // Move and spawn trails + while ( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) + { + pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL; + for ( int i = 0; i < 2; i++ ) + { + CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, pev->origin, TRUE ); + if ( pSprite ) + { + UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,500), ignore_monsters, edict(), &tr ); + pSprite->pev->origin = tr.vecEndPos; + pSprite->pev->velocity = Vector(RANDOM_FLOAT(-200,200),RANDOM_FLOAT(-200,200),175); + // pSprite->AnimateAndDie( RANDOM_FLOAT( 8.0, 12.0 ) ); + pSprite->pev->nextthink = gpGlobals->time + 0.3; + pSprite->SetThink( &CStomp::SUB_Remove ); + pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); + } + } + pev->dmgtime += STOMP_INTERVAL; + // Scale has the "life" of this effect + pev->scale -= STOMP_INTERVAL * pev->speed; + if ( pev->scale <= 0 ) + { + // Life has run out + UTIL_Remove(this); + STOP_SOUND( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND ); + } + + } +} + + +void StreakSplash( const Vector &origin, const Vector &direction, int color, int count, int speed, int velocityRange ) +{ + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); + WRITE_BYTE( TE_STREAK_SPLASH ); + WRITE_COORD( origin.x ); // origin + WRITE_COORD( origin.y ); + WRITE_COORD( origin.z ); + WRITE_COORD( direction.x ); // direction + WRITE_COORD( direction.y ); + WRITE_COORD( direction.z ); + WRITE_BYTE( color ); // Streak color 6 + WRITE_SHORT( count ); // count + WRITE_SHORT( speed ); + WRITE_SHORT( velocityRange ); // Random velocity modifier + MESSAGE_END(); +} + + +class CGargantua : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + + BOOL CheckMeleeAttack1( float flDot, float flDist ); // Swipe + BOOL CheckMeleeAttack2( float flDot, float flDist ); // Flames + BOOL CheckRangeAttack1( float flDot, float flDist ); // Stomp attack + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -80, -80, 0 ); + pev->absmax = pev->origin + Vector( 80, 80, 214 ); + } + + Schedule_t *GetScheduleOfType( int Type ); + void StartTask( Task_t *pTask ); + void RunTask( Task_t *pTask ); + + void PrescheduleThink( void ); + + void Killed( entvars_t *pevAttacker, int iGib ); + void DeathEffect( void ); + + void EyeOff( void ); + void EyeOn( int level ); + void EyeUpdate( void ); + void Leap( void ); + void StompAttack( void ); + void FlameCreate( void ); + void FlameUpdate( void ); + void FlameControls( float angleX, float angleY ); + void FlameDestroy( void ); + inline BOOL FlameIsOn( void ) { return m_pFlame[0] != NULL; } + + void FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + CUSTOM_SCHEDULES; + +private: + static const char *pAttackHitSounds[]; + static const char *pBeamAttackSounds[]; + static const char *pAttackMissSounds[]; + static const char *pRicSounds[]; + static const char *pFootSounds[]; + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + static const char *pPainSounds[]; + static const char *pAttackSounds[]; + static const char *pStompSounds[]; + static const char *pBreatheSounds[]; + + CBaseEntity* GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType); + + CSprite *m_pEyeGlow; // Glow around the eyes + CBeam *m_pFlame[4]; // Flame beams + + int m_eyeBrightness; // Brightness target + float m_seeTime; // Time to attack (when I see the enemy, I set this) + float m_flameTime; // Time of next flame attack + float m_painSoundTime; // Time of next pain sound + float m_streakTime; // streak timer (don't send too many) + float m_flameX; // Flame thrower aim + float m_flameY; +}; + +LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ); + +TYPEDESCRIPTION CGargantua::m_SaveData[] = +{ + DEFINE_FIELD( CGargantua, m_pEyeGlow, FIELD_CLASSPTR ), + DEFINE_FIELD( CGargantua, m_eyeBrightness, FIELD_INTEGER ), + DEFINE_FIELD( CGargantua, m_seeTime, FIELD_TIME ), + DEFINE_FIELD( CGargantua, m_flameTime, FIELD_TIME ), + DEFINE_FIELD( CGargantua, m_streakTime, FIELD_TIME ), + DEFINE_FIELD( CGargantua, m_painSoundTime, FIELD_TIME ), + DEFINE_ARRAY( CGargantua, m_pFlame, FIELD_CLASSPTR, 4 ), + DEFINE_FIELD( CGargantua, m_flameX, FIELD_FLOAT ), + DEFINE_FIELD( CGargantua, m_flameY, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ); + +const char *CGargantua::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CGargantua::pBeamAttackSounds[] = +{ + "garg/gar_flameoff1.wav", + "garg/gar_flameon1.wav", + "garg/gar_flamerun1.wav", +}; + + +const char *CGargantua::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + +const char *CGargantua::pRicSounds[] = +{ +#if 0 + "weapons/ric1.wav", + "weapons/ric2.wav", + "weapons/ric3.wav", + "weapons/ric4.wav", + "weapons/ric5.wav", +#else + "debris/metal4.wav", + "debris/metal6.wav", + "weapons/ric4.wav", + "weapons/ric5.wav", +#endif +}; + +const char *CGargantua::pFootSounds[] = +{ + "garg/gar_step1.wav", + "garg/gar_step2.wav", +}; + + +const char *CGargantua::pIdleSounds[] = +{ + "garg/gar_idle1.wav", + "garg/gar_idle2.wav", + "garg/gar_idle3.wav", + "garg/gar_idle4.wav", + "garg/gar_idle5.wav", +}; + + +const char *CGargantua::pAttackSounds[] = +{ + "garg/gar_attack1.wav", + "garg/gar_attack2.wav", + "garg/gar_attack3.wav", +}; + +const char *CGargantua::pAlertSounds[] = +{ + "garg/gar_alert1.wav", + "garg/gar_alert2.wav", + "garg/gar_alert3.wav", +}; + +const char *CGargantua::pPainSounds[] = +{ + "garg/gar_pain1.wav", + "garg/gar_pain2.wav", + "garg/gar_pain3.wav", +}; + +const char *CGargantua::pStompSounds[] = +{ + "garg/gar_stomp1.wav", +}; + +const char *CGargantua::pBreatheSounds[] = +{ + "garg/gar_breathe1.wav", + "garg/gar_breathe2.wav", + "garg/gar_breathe3.wav", +}; +//========================================================= +// AI Schedules Specific to this monster +//========================================================= +#if 0 +enum +{ + SCHED_ = LAST_COMMON_SCHEDULE + 1, +}; +#endif + +enum +{ + TASK_SOUND_ATTACK = LAST_COMMON_TASK + 1, + TASK_FLAME_SWEEP, +}; + +Task_t tlGargFlame[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SOUND_ATTACK, (float)0 }, + // { TASK_PLAY_SEQUENCE, (float)ACT_SIGNAL1 }, + { TASK_SET_ACTIVITY, (float)ACT_MELEE_ATTACK2 }, + { TASK_FLAME_SWEEP, (float)4.5 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, +}; + +Schedule_t slGargFlame[] = +{ + { + tlGargFlame, + ARRAYSIZE ( tlGargFlame ), + 0, + 0, + "GargFlame" + }, +}; + + +// primary melee attack +Task_t tlGargSwipe[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_MELEE_ATTACK1, (float)0 }, +}; + +Schedule_t slGargSwipe[] = +{ + { + tlGargSwipe, + ARRAYSIZE ( tlGargSwipe ), + bits_COND_CAN_MELEE_ATTACK2, + 0, + "GargSwipe" + }, +}; + + +DEFINE_CUSTOM_SCHEDULES( CGargantua ) +{ + slGargFlame, + slGargSwipe, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CGargantua, CBaseMonster ); + + +void CGargantua::EyeOn( int level ) +{ + m_eyeBrightness = level; +} + + +void CGargantua::EyeOff( void ) +{ + m_eyeBrightness = 0; +} + + +void CGargantua::EyeUpdate( void ) +{ + if ( m_pEyeGlow ) + { + m_pEyeGlow->pev->renderamt = UTIL_Approach( m_eyeBrightness, m_pEyeGlow->pev->renderamt, 26 ); + if ( m_pEyeGlow->pev->renderamt == 0 ) + m_pEyeGlow->pev->effects |= EF_NODRAW; + else + m_pEyeGlow->pev->effects &= ~EF_NODRAW; + UTIL_SetOrigin( m_pEyeGlow->pev, pev->origin ); + } +} + + +void CGargantua::StompAttack( void ) +{ + TraceResult trace; + + UTIL_MakeVectors( pev->angles ); + Vector vecStart = pev->origin + Vector(0,0,60) + 35 * gpGlobals->v_forward; + Vector vecAim = ShootAtEnemy( vecStart ); + Vector vecEnd = (vecAim * 1024) + vecStart; + + UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace ); + CStomp::StompCreate( vecStart, trace.vecEndPos, 0 ); + UTIL_ScreenShake( pev->origin, 12.0, 100.0, 2.0, 1000 ); + EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pStompSounds[ RANDOM_LONG(0,ARRAYSIZE(pStompSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); + + UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,20), ignore_monsters, edict(), &trace ); + if ( trace.flFraction < 1.0 ) + UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 ); +} + + +void CGargantua :: FlameCreate( void ) +{ + int i; + Vector posGun, angleGun; + TraceResult trace; + + UTIL_MakeVectors( pev->angles ); + + for ( i = 0; i < 4; i++ ) + { + if ( i < 2 ) + m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE_NAME, 240 ); + else + m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE2, 140 ); + if ( m_pFlame[i] ) + { + int attach = i%2; + // attachment is 0 based in GetAttachment + GetAttachment( attach+1, posGun, angleGun ); + + Vector vecEnd = (gpGlobals->v_forward * GARG_FLAME_LENGTH) + posGun; + UTIL_TraceLine( posGun, vecEnd, dont_ignore_monsters, edict(), &trace ); + + m_pFlame[i]->PointEntInit( trace.vecEndPos, entindex() ); + if ( i < 2 ) + m_pFlame[i]->SetColor( 255, 130, 90 ); + else + m_pFlame[i]->SetColor( 0, 120, 255 ); + m_pFlame[i]->SetBrightness( 190 ); + m_pFlame[i]->SetFlags( BEAM_FSHADEIN ); + m_pFlame[i]->SetScrollRate( 20 ); + // attachment is 1 based in SetEndAttachment + m_pFlame[i]->SetEndAttachment( attach + 2 ); + CSoundEnt::InsertSound( bits_SOUND_COMBAT, posGun, 384, 0.3 ); + } + } + EMIT_SOUND_DYN ( edict(), CHAN_BODY, pBeamAttackSounds[ 1 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); + EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 2 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); +} + + +void CGargantua :: FlameControls( float angleX, float angleY ) +{ + if ( angleY < -180 ) + angleY += 360; + else if ( angleY > 180 ) + angleY -= 360; + + if ( angleY < -45 ) + angleY = -45; + else if ( angleY > 45 ) + angleY = 45; + + m_flameX = UTIL_ApproachAngle( angleX, m_flameX, 4 ); + m_flameY = UTIL_ApproachAngle( angleY, m_flameY, 8 ); + SetBoneController( 0, m_flameY ); + SetBoneController( 1, m_flameX ); +} + + +void CGargantua :: FlameUpdate( void ) +{ + int i; + static float offset[2] = { 60, -60 }; + TraceResult trace; + Vector vecStart, angleGun; + BOOL streaks = FALSE; + + for ( i = 0; i < 2; i++ ) + { + if ( m_pFlame[i] ) + { + Vector vecAim = pev->angles; + vecAim.x += m_flameX; + vecAim.y += m_flameY; + + UTIL_MakeVectors( vecAim ); + + GetAttachment( i+1, vecStart, angleGun ); + Vector vecEnd = vecStart + (gpGlobals->v_forward * GARG_FLAME_LENGTH); // - offset[i] * gpGlobals->v_right; + + UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &trace ); + + m_pFlame[i]->SetStartPos( trace.vecEndPos ); + m_pFlame[i+2]->SetStartPos( (vecStart * 0.6) + (trace.vecEndPos * 0.4) ); + + if ( trace.flFraction != 1.0 && gpGlobals->time > m_streakTime ) + { + StreakSplash( trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400 ); + streaks = TRUE; + UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0,2) ); + } + // RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); + FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x1000 * (i + 2) ); // entity, attachment + WRITE_COORD( vecStart.x ); // origin + WRITE_COORD( vecStart.y ); + WRITE_COORD( vecStart.z ); + WRITE_COORD( RANDOM_FLOAT( 32, 48 ) ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 255 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 2 ); // life * 10 + WRITE_COORD( 0 ); // decay + MESSAGE_END(); + } + } + if ( streaks ) + m_streakTime = gpGlobals->time; +} + + + +void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) +{ + CBaseEntity *pEntity = NULL; + TraceResult tr; + float flAdjustedDamage; + Vector vecSpot; + + Vector vecMid = (vecStart + vecEnd) * 0.5; + + float searchRadius = (vecStart - vecMid).Length(); + + Vector vecAim = (vecEnd - vecStart).Normalize( ); + + // iterate on all entities in the vicinity. + while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius )) != NULL) + { + if ( pEntity->pev->takedamage != DAMAGE_NO ) + { + // UNDONE: this should check a damage mask, not an ignore + if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) + {// houndeyes don't hurt other houndeyes with their attack + continue; + } + + vecSpot = pEntity->BodyTarget( vecMid ); + + float dist = DotProduct( vecAim, vecSpot - vecMid ); + if (dist > searchRadius) + dist = searchRadius; + else if (dist < -searchRadius) + dist = searchRadius; + + Vector vecSrc = vecMid + dist * vecAim; + + UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pev), &tr ); + + if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) + {// the explosion can 'see' this entity, so hurt them! + // decrease damage for an ent that's farther from the flame. + dist = ( vecSrc - tr.vecEndPos ).Length(); + + if (dist > 64) + { + flAdjustedDamage = flDamage - (dist - 64) * 0.4; + if (flAdjustedDamage <= 0) + continue; + } + else + { + flAdjustedDamage = flDamage; + } + + // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); + if (tr.flFraction != 1.0) + { + ClearMultiDamage( ); + pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); + ApplyMultiDamage( pevInflictor, pevAttacker ); + } + else + { + pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); + } + } + } + } +} + + +void CGargantua :: FlameDestroy( void ) +{ + int i; + + EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 0 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); + for ( i = 0; i < 4; i++ ) + { + if ( m_pFlame[i] ) + { + UTIL_Remove( m_pFlame[i] ); + m_pFlame[i] = NULL; + } + } +} + + +void CGargantua :: PrescheduleThink( void ) +{ + if ( !HasConditions( bits_COND_SEE_ENEMY ) ) + { + m_seeTime = gpGlobals->time + 5; + EyeOff(); + } + else + EyeOn( 200 ); + + EyeUpdate(); +} + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CGargantua :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CGargantua :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + ys = 60; + break; + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 180; + break; + case ACT_WALK: + case ACT_RUN: + ys = 60; + break; + + default: + ys = 60; + break; + } + + pev->yaw_speed = ys; +} + + +//========================================================= +// Spawn +//========================================================= +void CGargantua :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/garg.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = gSkillData.gargantuaHealth; + //pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file + m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); + + m_pEyeGlow = CSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, pev->origin, FALSE ); + m_pEyeGlow->SetTransparency( kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation ); + m_pEyeGlow->SetAttachment( edict(), 1 ); + EyeOff(); + m_seeTime = gpGlobals->time + 5; + m_flameTime = gpGlobals->time + 2; +} + + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CGargantua :: Precache() +{ + int i; + + PRECACHE_MODEL("models/garg.mdl"); + PRECACHE_MODEL( GARG_EYE_SPRITE_NAME ); + PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME ); + PRECACHE_MODEL( GARG_BEAM_SPRITE2 ); + gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME ); + gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL ); + PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND ); + + for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackHitSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ ) + PRECACHE_SOUND((char *)pBeamAttackSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackMissSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ ) + PRECACHE_SOUND((char *)pRicSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ ) + PRECACHE_SOUND((char *)pFootSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) + PRECACHE_SOUND((char *)pIdleSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) + PRECACHE_SOUND((char *)pAlertSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) + PRECACHE_SOUND((char *)pPainSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ ) + PRECACHE_SOUND((char *)pStompSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ ) + PRECACHE_SOUND((char *)pBreatheSounds[i]); +} + + +void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) +{ + ALERT( at_aiconsole, "CGargantua::TraceAttack\n"); + + if ( !IsAlive() ) + { + CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); + return; + } + + // UNDONE: Hit group specific damage? + if ( bitsDamageType & (GARG_DAMAGE|DMG_BLAST) ) + { + if ( m_painSoundTime < gpGlobals->time ) + { + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM ); + m_painSoundTime = gpGlobals->time + RANDOM_FLOAT( 2.5, 4 ); + } + } + + bitsDamageType &= GARG_DAMAGE; + + if ( bitsDamageType == 0) + { + if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,100) < 20) ) + { + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); + pev->dmgtime = gpGlobals->time; +// if ( RANDOM_LONG(0,100) < 25 ) +// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM ); + } + flDamage = 0; + } + + CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); + +} + + + +int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + ALERT( at_aiconsole, "CGargantua::TakeDamage\n"); + + if ( IsAlive() ) + { + if ( !(bitsDamageType & GARG_DAMAGE) ) + flDamage *= 0.01; + if ( bitsDamageType & DMG_BLAST ) + SetConditions( bits_COND_LIGHT_DAMAGE ); + } + + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + + +void CGargantua::DeathEffect( void ) +{ + int i; + UTIL_MakeVectors(pev->angles); + Vector deathPos = pev->origin + gpGlobals->v_forward * 100; + + // Create a spiral of streaks + CSpiral::Create( deathPos, (pev->absmax.z - pev->absmin.z) * 0.6, 125, 1.5 ); + + Vector position = pev->origin; + position.z += 32; + for ( i = 0; i < 7; i+=2 ) + { + SpawnExplosion( position, 70, (i * 0.3), 60 + (i*20) ); + position.z += 15; + } + + CBaseEntity *pSmoker = CBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL ); + pSmoker->pev->health = 1; // 1 smoke balls + pSmoker->pev->scale = 46; // 4.6X normal size + pSmoker->pev->dmg = 0; // 0 radial distribution + pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds +} + + +void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) +{ + EyeOff(); + UTIL_Remove( m_pEyeGlow ); + m_pEyeGlow = NULL; + CBaseMonster::Killed( pevAttacker, GIB_NEVER ); +} + +//========================================================= +// CheckMeleeAttack1 +// Garg swipe attack +// +//========================================================= +BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) +{ +// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); + + if (flDot >= 0.7) + { + if (flDist <= GARG_ATTACKDIST) + return TRUE; + } + return FALSE; +} + + +// Flame thrower madness! +BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) +{ +// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); + + if ( gpGlobals->time > m_flameTime ) + { + if (flDot >= 0.8 && flDist > GARG_ATTACKDIST) + { + if ( flDist <= GARG_FLAME_LENGTH ) + return TRUE; + } + } + return FALSE; +} + + +//========================================================= +// CheckRangeAttack1 +// flDot is the cos of the angle of the cone within which +// the attack can occur. +//========================================================= +// +// Stomp attack +// +//========================================================= +BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) +{ + if ( gpGlobals->time > m_seeTime ) + { + if (flDot >= 0.7 && flDist > GARG_ATTACKDIST) + { + return TRUE; + } + } + return FALSE; +} + + + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CGargantua::HandleAnimEvent(MonsterEvent_t *pEvent) +{ + switch( pEvent->event ) + { + case GARG_AE_SLASH_LEFT: + { + // HACKHACK!!! + CBaseEntity *pHurt = GargantuaCheckTraceHullAttack( GARG_ATTACKDIST + 10.0, gSkillData.gargantuaDmgSlash, DMG_SLASH ); + if (pHurt) + { + if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + { + pHurt->pev->punchangle.x = -30; // pitch + pHurt->pev->punchangle.y = -30; // yaw + pHurt->pev->punchangle.z = 30; // roll + //UTIL_MakeVectors(pev->angles); // called by CheckTraceHullAttack + pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; + } + EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) ); + } + else // Play a random attack miss sound + EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) ); + + Vector forward; + UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); + } + break; + + case GARG_AE_RIGHT_FOOT: + case GARG_AE_LEFT_FOOT: + UTIL_ScreenShake( pev->origin, 4.0, 3.0, 1.0, 750 ); + EMIT_SOUND_DYN ( edict(), CHAN_BODY, pFootSounds[ RANDOM_LONG(0,ARRAYSIZE(pFootSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); + break; + + case GARG_AE_STOMP: + StompAttack(); + m_seeTime = gpGlobals->time + 12; + break; + + case GARG_AE_BREATHE: + EMIT_SOUND_DYN ( edict(), CHAN_VOICE, pBreatheSounds[ RANDOM_LONG(0,ARRAYSIZE(pBreatheSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); + break; + + default: + CBaseMonster::HandleAnimEvent(pEvent); + break; + } +} + + +//========================================================= +// CheckTraceHullAttack - expects a length to trace, amount +// of damage to do, and damage type. Returns a pointer to +// the damaged entity in case the monster wishes to do +// other stuff to the victim (punchangle, etc) +// Used for many contact-range melee attacks. Bites, claws, etc. + +// Overridden for Gargantua because his swing starts lower as +// a percentage of his height (otherwise he swings over the +// players head) +//========================================================= +CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType) +{ + TraceResult tr; + + UTIL_MakeVectors( pev->angles ); + Vector vecStart = pev->origin; + vecStart.z += 64; + Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist) - (gpGlobals->v_up * flDist * 0.3); + + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); + + if ( tr.pHit ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + + if ( iDamage > 0 ) + { + pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); + } + + return pEntity; + } + + return NULL; +} + + +Schedule_t *CGargantua::GetScheduleOfType( int Type ) +{ + // HACKHACK - turn off the flames if they are on and garg goes scripted / dead + if ( FlameIsOn() ) + FlameDestroy(); + + switch( Type ) + { + case SCHED_MELEE_ATTACK2: + return slGargFlame; + case SCHED_MELEE_ATTACK1: + return slGargSwipe; + break; + } + + return CBaseMonster::GetScheduleOfType( Type ); +} + + +void CGargantua::StartTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_FLAME_SWEEP: + FlameCreate(); + m_flWaitFinished = gpGlobals->time + pTask->flData; + m_flameTime = gpGlobals->time + 6; + m_flameX = 0; + m_flameY = 0; + break; + + case TASK_SOUND_ATTACK: + if ( RANDOM_LONG(0,100) < 30 ) + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM ); + TaskComplete(); + break; + + case TASK_DIE: + m_flWaitFinished = gpGlobals->time + 1.6; + DeathEffect(); + // FALL THROUGH + default: + CBaseMonster::StartTask( pTask ); + break; + } +} + +//========================================================= +// RunTask +//========================================================= +void CGargantua::RunTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_DIE: + if ( gpGlobals->time > m_flWaitFinished ) + { + pev->renderfx = kRenderFxExplode; + pev->rendercolor.x = 255; + pev->rendercolor.y = 0; + pev->rendercolor.z = 0; + StopAnimation(); + pev->nextthink = gpGlobals->time + 0.15; + SetThink( &CGargantua::SUB_Remove ); + int i; + int parts = MODEL_FRAMES( gGargGibModel ); + for ( i = 0; i < 10; i++ ) + { + CGib *pGib = GetClassPtr( (CGib *)NULL ); + + pGib->Spawn( GARG_GIB_MODEL ); + + int bodyPart = 0; + if ( parts > 1 ) + bodyPart = RANDOM_LONG( 0, pev->body-1 ); + + pGib->pev->body = bodyPart; + pGib->m_bloodColor = BLOOD_COLOR_YELLOW; + pGib->m_material = matNone; + pGib->pev->origin = pev->origin; + pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ); + pGib->pev->nextthink = gpGlobals->time + 1.25; + pGib->SetThink( &CGargantua::SUB_FadeOut ); + } + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_BREAKMODEL); + + // position + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + + // size + WRITE_COORD( 200 ); + WRITE_COORD( 200 ); + WRITE_COORD( 128 ); + + // velocity + WRITE_COORD( 0 ); + WRITE_COORD( 0 ); + WRITE_COORD( 0 ); + + // randomization + WRITE_BYTE( 200 ); + + // Model + WRITE_SHORT( gGargGibModel ); //model id# + + // # of shards + WRITE_BYTE( 50 ); + + // duration + WRITE_BYTE( 20 );// 3.0 seconds + + // flags + + WRITE_BYTE( BREAK_FLESH ); + MESSAGE_END(); + + return; + } + else + CBaseMonster::RunTask(pTask); + break; + + case TASK_FLAME_SWEEP: + if ( gpGlobals->time > m_flWaitFinished ) + { + FlameDestroy(); + TaskComplete(); + FlameControls( 0, 0 ); + SetBoneController( 0, 0 ); + SetBoneController( 1, 0 ); + } + else + { + BOOL cancel = FALSE; + + Vector angles = g_vecZero; + + FlameUpdate(); + CBaseEntity *pEnemy = m_hEnemy; + if ( pEnemy ) + { + Vector org = pev->origin; + org.z += 64; + Vector dir = pEnemy->BodyTarget(org) - org; + angles = UTIL_VecToAngles( dir ); + angles.x = -angles.x; + angles.y -= pev->angles.y; + if ( dir.Length() > 400 ) + cancel = TRUE; + } + if ( fabs(angles.y) > 60 ) + cancel = TRUE; + + if ( cancel ) + { + m_flWaitFinished -= 0.5; + m_flameTime -= 0.5; + } + // FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) ); + FlameControls( angles.x, angles.y ); + } + break; + + default: + CBaseMonster::RunTask( pTask ); + break; + } +} + + +class CSmoker : public CBaseEntity +{ +public: + void Spawn( void ); + void Think( void ); +}; + +LINK_ENTITY_TO_CLASS( env_smoker, CSmoker ); + +void CSmoker::Spawn( void ) +{ + pev->movetype = MOVETYPE_NONE; + pev->nextthink = gpGlobals->time; + pev->solid = SOLID_NOT; + UTIL_SetSize(pev, g_vecZero, g_vecZero ); + pev->effects |= EF_NODRAW; + pev->angles = g_vecZero; +} + + +void CSmoker::Think( void ) +{ + // lots of smoke + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg )); + WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg )); + WRITE_COORD( pev->origin.z); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) ); + WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate + MESSAGE_END(); + + pev->health--; + if ( pev->health > 0 ) + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2); + else + UTIL_Remove( this ); +} + + +void CSpiral::Spawn( void ) +{ + pev->movetype = MOVETYPE_NONE; + pev->nextthink = gpGlobals->time; + pev->solid = SOLID_NOT; + UTIL_SetSize(pev, g_vecZero, g_vecZero ); + pev->effects |= EF_NODRAW; + pev->angles = g_vecZero; +} + + +CSpiral *CSpiral::Create( const Vector &origin, float height, float radius, float duration ) +{ + if ( duration <= 0 ) + return NULL; + + CSpiral *pSpiral = GetClassPtr( (CSpiral *)NULL ); + pSpiral->Spawn(); + pSpiral->pev->dmgtime = pSpiral->pev->nextthink; + pSpiral->pev->origin = origin; + pSpiral->pev->scale = radius; + pSpiral->pev->dmg = height; + pSpiral->pev->speed = duration; + pSpiral->pev->health = 0; + pSpiral->pev->angles = g_vecZero; + + return pSpiral; +} + +#define SPIRAL_INTERVAL 0.1 //025 + +void CSpiral::Think( void ) +{ + float time = gpGlobals->time - pev->dmgtime; + + while ( time > SPIRAL_INTERVAL ) + { + Vector position = pev->origin; + Vector direction = Vector(0,0,1); + + float fraction = 1.0 / pev->speed; + + float radius = (pev->scale * pev->health) * fraction; + + position.z += (pev->health * pev->dmg) * fraction; + pev->angles.y = (pev->health * 360 * 8) * fraction; + UTIL_MakeVectors( pev->angles ); + position = position + gpGlobals->v_forward * radius; + direction = (direction + gpGlobals->v_forward).Normalize(); + + StreakSplash( position, Vector(0,0,1), RANDOM_LONG(8,11), 20, RANDOM_LONG(50,150), 400 ); + + // Jeez, how many counters should this take ? :) + pev->dmgtime += SPIRAL_INTERVAL; + pev->health += SPIRAL_INTERVAL; + time -= SPIRAL_INTERVAL; + } + + pev->nextthink = gpGlobals->time; + + if ( pev->health >= pev->speed ) + UTIL_Remove( this ); +} + + +// HACKHACK Cut and pasted from explode.cpp +void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ) +{ + KeyValueData kvd; + char buf[128]; + + center.x += RANDOM_FLOAT( -randomRange, randomRange ); + center.y += RANDOM_FLOAT( -randomRange, randomRange ); + + CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero, NULL ); + sprintf( buf, "%3d", magnitude ); + kvd.szKeyName = "iMagnitude"; + kvd.szValue = buf; + pExplosion->KeyValue( &kvd ); + pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; + + pExplosion->Spawn(); + pExplosion->SetThink( CBaseEntity::SUB_CallUseToggle ); + pExplosion->pev->nextthink = gpGlobals->time + time; +} + + + #endif \ No newline at end of file diff --git a/main/source/dlls/gauss.cpp b/main/source/dlls/gauss.cpp index b58f6530..800bcc34 100644 --- a/main/source/dlls/gauss.cpp +++ b/main/source/dlls/gauss.cpp @@ -1,613 +1,613 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "../engine/shake.h" -#include "gamerules.h" -#include "../mod/AvHNetworkMessages.h" - - -#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging -#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged - -enum gauss_e { - GAUSS_IDLE = 0, - GAUSS_IDLE2, - GAUSS_FIDGET, - GAUSS_SPINUP, - GAUSS_SPIN, - GAUSS_FIRE, - GAUSS_FIRE2, - GAUSS_HOLSTER, - GAUSS_DRAW -}; - -LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); - -float CGauss::GetFullChargeTime( void ) -{ -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - return 1.5; - } - - return 4; -} - -void CGauss::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_GAUSS; - SET_MODEL(ENT(pev), "models/w_gauss.mdl"); - - m_iDefaultAmmo = GAUSS_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGauss::Precache( void ) -{ - PRECACHE_MODEL("models/w_gauss.mdl"); - PRECACHE_MODEL("models/v_gauss.mdl"); - PRECACHE_MODEL("models/p_gauss.mdl"); - - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND("weapons/gauss2.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("weapons/electro5.wav"); - PRECACHE_SOUND("weapons/electro6.wav"); - PRECACHE_SOUND("ambience/pulsemachine.wav"); - - m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" ); - - m_usGaussFire = PRECACHE_EVENT( 1, "events/gauss.sc" ); - m_usGaussSpin = PRECACHE_EVENT( 1, "events/gaussspin.sc" ); -} - -int CGauss::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pPlayer->pev, m_iId ); - return TRUE; - } - return FALSE; -} - -int CGauss::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 1; - p->iId = m_iId = WEAPON_GAUSS; - p->iFlags = 0; - p->iWeight = GAUSS_WEIGHT; - - return 1; -} - -BOOL CGauss::Deploy( ) -{ - m_pPlayer->m_flPlayAftershock = 0.0; - return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); -} - -void CGauss::Holster( int skiplocal /* = 0 */ ) -{ - PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( GAUSS_HOLSTER ); - m_fInAttack = 0; -} - - -void CGauss::PrimaryAttack() -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound( ); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; - return; - } - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] < 2 ) - { - PlayEmptySound( ); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - m_fPrimaryFire = TRUE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2; - - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; -} - -void CGauss::SecondaryAttack() -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - if ( m_fInAttack != 0 ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); - SendWeaponAnim( GAUSS_IDLE ); - m_fInAttack = 0; - } - else - { - PlayEmptySound( ); - } - - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - if ( m_fInAttack == 0 ) - { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_fPrimaryFire = FALSE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); - - // spin up - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - SendWeaponAnim( GAUSS_SPINUP ); - m_fInAttack = 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->m_flStartCharge = gpGlobals->time; - m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; - } - else if (m_fInAttack == 1) - { - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) - { - SendWeaponAnim( GAUSS_SPIN ); - m_fInAttack = 2; - } - } - else - { - // during the charging process, eat one bit of ammo every once in a while - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) - { -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; - } - else - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.3; - } - } - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - // out of ammo! force the gun to fire - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; - return; - } - - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) - { - // don't eat any more ammo after gun is fully charged. - m_pPlayer->m_flNextAmmoBurn = 1000; - } - - int pitch = ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100; - if ( pitch > 250 ) - pitch = 250; - - // ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch ); - - if ( m_iSoundState == 0 ) - ALERT( at_console, "sound state %d\n", m_iSoundState ); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - // m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - if ( m_pPlayer->m_flStartCharge < gpGlobals->time - 10 ) - { - // Player charged up too long. Zap him. - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG(0,0x3f)); - - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - -#ifndef CLIENT_DLL - m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK ); - UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN ); -#endif - SendWeaponAnim( GAUSS_IDLE ); - - // Player may have been killed and this weapon dropped, don't execute any more code after this! - return; - } - } -} - -//========================================================= -// StartFire- since all of this code has to run and then -// call Fire(), it was easier at this point to rip it out -// of weaponidle() and make its own function then to try to -// merge this into Fire(), which has some identical variable names -//========================================================= -void CGauss::StartFire( void ) -{ - float flDamage; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; - - if ( gpGlobals->time - m_pPlayer->m_flStartCharge > GetFullChargeTime() ) - { - flDamage = 200; - } - else - { - flDamage = 200 * (( gpGlobals->time - m_pPlayer->m_flStartCharge) / GetFullChargeTime() ); - } - - if ( m_fPrimaryFire ) - { - // fixed damage on primary attack -#ifdef CLIENT_DLL - flDamage = 20; -#else - flDamage = gSkillData.plrDmgGauss; -#endif - } - - if (m_fInAttack != 3) - { - //ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_pPlayer->m_flStartCharge, flDamage ); - -#ifndef CLIENT_DLL - float flZVel = m_pPlayer->pev->velocity.z; - - if ( !m_fPrimaryFire ) - { - m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; - } - - if ( !g_pGameRules->IsMultiplayer() ) - - { - // in deathmatch, gauss can pop you up into the air. Not in single play. - m_pPlayer->pev->velocity.z = flZVel; - } -#endif - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - - // time until aftershock 'static discharge' sound - m_pPlayer->m_flPlayAftershock = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.3, 0.8 ); - - Fire( vecSrc, vecAiming, flDamage ); -} - -void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) -{ - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - - Vector vecSrc = vecOrigSrc; - Vector vecDest = vecSrc + vecDir * 8192; - edict_t *pentIgnore; - TraceResult tr, beam_tr; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - - pentIgnore = ENT( m_pPlayer->pev ); - - // The main firing event is sent unreliably so it won't be delayed. - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); - - // This reliable event is used to stop the spinning sound - // It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client - // It's sent reliably anyway, which could lead to other delays - - PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - - /*ALERT( at_console, "%f %f %f\n%f %f %f\n", - vecSrc.x, vecSrc.y, vecSrc.z, - vecDest.x, vecDest.y, vecDest.z );*/ - - -// ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); - -#ifndef CLIENT_DLL - while (flDamage > 10 && nMaxHits > 0) - { - nMaxHits--; - - // ALERT( at_console, "." ); - UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr); - - if (tr.fAllSolid) - break; - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if (pEntity == NULL) - break; - - if ( fFirstBeam ) - { - m_pPlayer->pev->effects |= EF_MUZZLEFLASH; - fFirstBeam = 0; - - nTotal += 26; - } - - if (pEntity->pev->takedamage) - { - ClearMultiDamage(); - pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - } - - if ( pEntity->ReflectGauss() ) - { - float n; - - pentIgnore = NULL; - - n = -DotProduct(tr.vecPlaneNormal, vecDir); - - if (n < 0.5) // 60 degrees - { - // ALERT( at_console, "reflect %f\n", n ); - // reflect - Vector r; - - r = 2.0 * tr.vecPlaneNormal * n + vecDir; - flMaxFrac = flMaxFrac - tr.flFraction; - vecDir = r; - vecSrc = tr.vecEndPos + vecDir * 8; - vecDest = vecSrc + vecDir * 8192; - - // explode a bit - m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); - - nTotal += 34; - - // lose energy - if (n == 0) n = 0.1; - flDamage = flDamage * (1 - n); - } - else - { - nTotal += 13; - - // limit it to one hole punch - if (fHasPunched) - break; - fHasPunched = 1; - - // try punching through wall if secondary attack (primary is incapable of breaking through) - if ( !m_fPrimaryFire ) - { - UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr); - if (!beam_tr.fAllSolid) - { - // trace backwards to find exit point - UTIL_TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, &beam_tr); - - float n = (beam_tr.vecEndPos - tr.vecEndPos).Length( ); - - if (n < flDamage) - { - if (n == 0) n = 1; - flDamage -= n; - - // ALERT( at_console, "punch %f\n", n ); - nTotal += 21; - - // exit blast damage - //m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); - float damage_radius; - - - if ( g_pGameRules->IsMultiplayer() ) - { - damage_radius = flDamage * 1.75; // Old code == 2.5 - } - else - { - damage_radius = flDamage * 2.5; - } - - ::RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST ); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - nTotal += 53; - - vecSrc = beam_tr.vecEndPos + vecDir; - } - } - else - { - //ALERT( at_console, "blocked %f\n", n ); - flDamage = 0; - } - } - else - { - //ALERT( at_console, "blocked solid\n" ); - - flDamage = 0; - } - - } - } - else - { - vecSrc = tr.vecEndPos + vecDir; - pentIgnore = ENT( pEntity->pev ); - } - } -#endif - // ALERT( at_console, "%d bytes\n", nTotal ); -} - - - - -void CGauss::WeaponIdle( void ) -{ - ResetEmptySound( ); - - // play aftershock static discharge - if ( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro5.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro6.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 3: break; // no sound - } - m_pPlayer->m_flPlayAftershock = 0.0; - } - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - - if (m_fInAttack != 0) - { - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - } - else - { - int iAnim; - float flRand = RANDOM_FLOAT(0, 1); - if (flRand <= 0.5) - { - iAnim = GAUSS_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else if (flRand <= 0.75) - { - iAnim = GAUSS_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = GAUSS_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - return; - SendWeaponAnim( iAnim ); - - } -} - - - - - - -class CGaussAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_gaussammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_gaussammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "soundent.h" +#include "../engine/shake.h" +#include "gamerules.h" +#include "../mod/AvHNetworkMessages.h" + + +#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging +#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged + +enum gauss_e { + GAUSS_IDLE = 0, + GAUSS_IDLE2, + GAUSS_FIDGET, + GAUSS_SPINUP, + GAUSS_SPIN, + GAUSS_FIRE, + GAUSS_FIRE2, + GAUSS_HOLSTER, + GAUSS_DRAW +}; + +LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); + +float CGauss::GetFullChargeTime( void ) +{ +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + return 1.5; + } + + return 4; +} + +void CGauss::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_GAUSS; + SET_MODEL(ENT(pev), "models/w_gauss.mdl"); + + m_iDefaultAmmo = GAUSS_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CGauss::Precache( void ) +{ + PRECACHE_MODEL("models/w_gauss.mdl"); + PRECACHE_MODEL("models/v_gauss.mdl"); + PRECACHE_MODEL("models/p_gauss.mdl"); + + PRECACHE_SOUND("items/9mmclip1.wav"); + + PRECACHE_SOUND("weapons/gauss2.wav"); + PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_SOUND("weapons/electro5.wav"); + PRECACHE_SOUND("weapons/electro6.wav"); + PRECACHE_SOUND("ambience/pulsemachine.wav"); + + m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" ); + m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" ); + m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" ); + + m_usGaussFire = PRECACHE_EVENT( 1, "events/gauss.sc" ); + m_usGaussSpin = PRECACHE_EVENT( 1, "events/gaussspin.sc" ); +} + +int CGauss::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + NetMsg_WeapPickup( pPlayer->pev, m_iId ); + return TRUE; + } + return FALSE; +} + +int CGauss::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "uranium"; + p->iMaxAmmo1 = URANIUM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 3; + p->iPosition = 1; + p->iId = m_iId = WEAPON_GAUSS; + p->iFlags = 0; + p->iWeight = GAUSS_WEIGHT; + + return 1; +} + +BOOL CGauss::Deploy( ) +{ + m_pPlayer->m_flPlayAftershock = 0.0; + return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); +} + +void CGauss::Holster( int skiplocal /* = 0 */ ) +{ + PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + + SendWeaponAnim( GAUSS_HOLSTER ); + m_fInAttack = 0; +} + + +void CGauss::PrimaryAttack() +{ + // don't fire underwater + if ( m_pPlayer->pev->waterlevel == 3 ) + { + PlayEmptySound( ); + m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + return; + } + + if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] < 2 ) + { + PlayEmptySound( ); + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + return; + } + + m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + m_fPrimaryFire = TRUE; + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2; + + StartFire(); + m_fInAttack = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; +} + +void CGauss::SecondaryAttack() +{ + // don't fire underwater + if ( m_pPlayer->pev->waterlevel == 3 ) + { + if ( m_fInAttack != 0 ) + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); + SendWeaponAnim( GAUSS_IDLE ); + m_fInAttack = 0; + } + else + { + PlayEmptySound( ); + } + + m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + return; + } + + if ( m_fInAttack == 0 ) + { + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) + { + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + return; + } + + m_fPrimaryFire = FALSE; + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); + + // spin up + m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; + + SendWeaponAnim( GAUSS_SPINUP ); + m_fInAttack = 1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + m_pPlayer->m_flStartCharge = gpGlobals->time; + m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); + + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); + + m_iSoundState = SND_CHANGE_PITCH; + } + else if (m_fInAttack == 1) + { + if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) + { + SendWeaponAnim( GAUSS_SPIN ); + m_fInAttack = 2; + } + } + else + { + // during the charging process, eat one bit of ammo every once in a while + if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) + { +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; + } + else + { + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.3; + } + } + + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) + { + // out of ammo! force the gun to fire + StartFire(); + m_fInAttack = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; + return; + } + + if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) + { + // don't eat any more ammo after gun is fully charged. + m_pPlayer->m_flNextAmmoBurn = 1000; + } + + int pitch = ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100; + if ( pitch > 250 ) + pitch = 250; + + // ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch ); + + if ( m_iSoundState == 0 ) + ALERT( at_console, "sound state %d\n", m_iSoundState ); + + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); + + m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions + + m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; + + // m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; + if ( m_pPlayer->m_flStartCharge < gpGlobals->time - 10 ) + { + // Player charged up too long. Zap him. + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG(0,0x3f)); + + m_fInAttack = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; + +#ifndef CLIENT_DLL + m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK ); + UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN ); +#endif + SendWeaponAnim( GAUSS_IDLE ); + + // Player may have been killed and this weapon dropped, don't execute any more code after this! + return; + } + } +} + +//========================================================= +// StartFire- since all of this code has to run and then +// call Fire(), it was easier at this point to rip it out +// of weaponidle() and make its own function then to try to +// merge this into Fire(), which has some identical variable names +//========================================================= +void CGauss::StartFire( void ) +{ + float flDamage; + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + Vector vecAiming = gpGlobals->v_forward; + Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; + + if ( gpGlobals->time - m_pPlayer->m_flStartCharge > GetFullChargeTime() ) + { + flDamage = 200; + } + else + { + flDamage = 200 * (( gpGlobals->time - m_pPlayer->m_flStartCharge) / GetFullChargeTime() ); + } + + if ( m_fPrimaryFire ) + { + // fixed damage on primary attack +#ifdef CLIENT_DLL + flDamage = 20; +#else + flDamage = gSkillData.plrDmgGauss; +#endif + } + + if (m_fInAttack != 3) + { + //ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_pPlayer->m_flStartCharge, flDamage ); + +#ifndef CLIENT_DLL + float flZVel = m_pPlayer->pev->velocity.z; + + if ( !m_fPrimaryFire ) + { + m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; + } + + if ( !g_pGameRules->IsMultiplayer() ) + + { + // in deathmatch, gauss can pop you up into the air. Not in single play. + m_pPlayer->pev->velocity.z = flZVel; + } +#endif + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + } + + // time until aftershock 'static discharge' sound + m_pPlayer->m_flPlayAftershock = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.3, 0.8 ); + + Fire( vecSrc, vecAiming, flDamage ); +} + +void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) +{ + m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + + Vector vecSrc = vecOrigSrc; + Vector vecDest = vecSrc + vecDir * 8192; + edict_t *pentIgnore; + TraceResult tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + + pentIgnore = ENT( m_pPlayer->pev ); + + // The main firing event is sent unreliably so it won't be delayed. + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); + + // This reliable event is used to stop the spinning sound + // It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client + // It's sent reliably anyway, which could lead to other delays + + PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); + + + /*ALERT( at_console, "%f %f %f\n%f %f %f\n", + vecSrc.x, vecSrc.y, vecSrc.z, + vecDest.x, vecDest.y, vecDest.z );*/ + + +// ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); + +#ifndef CLIENT_DLL + while (flDamage > 10 && nMaxHits > 0) + { + nMaxHits--; + + // ALERT( at_console, "." ); + UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr); + + if (tr.fAllSolid) + break; + + CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + + if (pEntity == NULL) + break; + + if ( fFirstBeam ) + { + m_pPlayer->pev->effects |= EF_MUZZLEFLASH; + fFirstBeam = 0; + + nTotal += 26; + } + + if (pEntity->pev->takedamage) + { + ClearMultiDamage(); + pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); + ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + } + + if ( pEntity->ReflectGauss() ) + { + float n; + + pentIgnore = NULL; + + n = -DotProduct(tr.vecPlaneNormal, vecDir); + + if (n < 0.5) // 60 degrees + { + // ALERT( at_console, "reflect %f\n", n ); + // reflect + Vector r; + + r = 2.0 * tr.vecPlaneNormal * n + vecDir; + flMaxFrac = flMaxFrac - tr.flFraction; + vecDir = r; + vecSrc = tr.vecEndPos + vecDir * 8; + vecDest = vecSrc + vecDir * 8192; + + // explode a bit + m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); + + nTotal += 34; + + // lose energy + if (n == 0) n = 0.1; + flDamage = flDamage * (1 - n); + } + else + { + nTotal += 13; + + // limit it to one hole punch + if (fHasPunched) + break; + fHasPunched = 1; + + // try punching through wall if secondary attack (primary is incapable of breaking through) + if ( !m_fPrimaryFire ) + { + UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr); + if (!beam_tr.fAllSolid) + { + // trace backwards to find exit point + UTIL_TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, &beam_tr); + + float n = (beam_tr.vecEndPos - tr.vecEndPos).Length( ); + + if (n < flDamage) + { + if (n == 0) n = 1; + flDamage -= n; + + // ALERT( at_console, "punch %f\n", n ); + nTotal += 21; + + // exit blast damage + //m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); + float damage_radius; + + + if ( g_pGameRules->IsMultiplayer() ) + { + damage_radius = flDamage * 1.75; // Old code == 2.5 + } + else + { + damage_radius = flDamage * 2.5; + } + + ::RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST ); + + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + + nTotal += 53; + + vecSrc = beam_tr.vecEndPos + vecDir; + } + } + else + { + //ALERT( at_console, "blocked %f\n", n ); + flDamage = 0; + } + } + else + { + //ALERT( at_console, "blocked solid\n" ); + + flDamage = 0; + } + + } + } + else + { + vecSrc = tr.vecEndPos + vecDir; + pentIgnore = ENT( pEntity->pev ); + } + } +#endif + // ALERT( at_console, "%d bytes\n", nTotal ); +} + + + + +void CGauss::WeaponIdle( void ) +{ + ResetEmptySound( ); + + // play aftershock static discharge + if ( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) + { + switch (RANDOM_LONG(0,3)) + { + case 0: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro5.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro6.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; + case 3: break; // no sound + } + m_pPlayer->m_flPlayAftershock = 0.0; + } + + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + return; + + if (m_fInAttack != 0) + { + StartFire(); + m_fInAttack = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; + } + else + { + int iAnim; + float flRand = RANDOM_FLOAT(0, 1); + if (flRand <= 0.5) + { + iAnim = GAUSS_IDLE; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } + else if (flRand <= 0.75) + { + iAnim = GAUSS_IDLE2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } + else + { + iAnim = GAUSS_FIDGET; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; + } + + return; + SendWeaponAnim( iAnim ); + + } +} + + + + + + +class CGaussAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_gaussammo.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_gaussammo.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); + +#endif diff --git a/main/source/dlls/gauss.cpp~ b/main/source/dlls/gauss.cpp~ deleted file mode 100644 index 6346c588..00000000 --- a/main/source/dlls/gauss.cpp~ +++ /dev/null @@ -1,613 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "../engine/shake.h" -#include "gamerules.h" -#include "..mod/AvHNetworkMessages.h" - - -#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging -#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged - -enum gauss_e { - GAUSS_IDLE = 0, - GAUSS_IDLE2, - GAUSS_FIDGET, - GAUSS_SPINUP, - GAUSS_SPIN, - GAUSS_FIRE, - GAUSS_FIRE2, - GAUSS_HOLSTER, - GAUSS_DRAW -}; - -LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); - -float CGauss::GetFullChargeTime( void ) -{ -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - return 1.5; - } - - return 4; -} - -void CGauss::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_GAUSS; - SET_MODEL(ENT(pev), "models/w_gauss.mdl"); - - m_iDefaultAmmo = GAUSS_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGauss::Precache( void ) -{ - PRECACHE_MODEL("models/w_gauss.mdl"); - PRECACHE_MODEL("models/v_gauss.mdl"); - PRECACHE_MODEL("models/p_gauss.mdl"); - - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND("weapons/gauss2.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("weapons/electro5.wav"); - PRECACHE_SOUND("weapons/electro6.wav"); - PRECACHE_SOUND("ambience/pulsemachine.wav"); - - m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" ); - - m_usGaussFire = PRECACHE_EVENT( 1, "events/gauss.sc" ); - m_usGaussSpin = PRECACHE_EVENT( 1, "events/gaussspin.sc" ); -} - -int CGauss::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pPlayer->pev, m_iId ); - return TRUE; - } - return FALSE; -} - -int CGauss::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 1; - p->iId = m_iId = WEAPON_GAUSS; - p->iFlags = 0; - p->iWeight = GAUSS_WEIGHT; - - return 1; -} - -BOOL CGauss::Deploy( ) -{ - m_pPlayer->m_flPlayAftershock = 0.0; - return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); -} - -void CGauss::Holster( int skiplocal /* = 0 */ ) -{ - PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( GAUSS_HOLSTER ); - m_fInAttack = 0; -} - - -void CGauss::PrimaryAttack() -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound( ); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; - return; - } - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] < 2 ) - { - PlayEmptySound( ); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - m_fPrimaryFire = TRUE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2; - - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; -} - -void CGauss::SecondaryAttack() -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - if ( m_fInAttack != 0 ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); - SendWeaponAnim( GAUSS_IDLE ); - m_fInAttack = 0; - } - else - { - PlayEmptySound( ); - } - - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - if ( m_fInAttack == 0 ) - { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_fPrimaryFire = FALSE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); - - // spin up - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - SendWeaponAnim( GAUSS_SPINUP ); - m_fInAttack = 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->m_flStartCharge = gpGlobals->time; - m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; - } - else if (m_fInAttack == 1) - { - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) - { - SendWeaponAnim( GAUSS_SPIN ); - m_fInAttack = 2; - } - } - else - { - // during the charging process, eat one bit of ammo every once in a while - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) - { -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; - } - else - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.3; - } - } - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - // out of ammo! force the gun to fire - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; - return; - } - - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) - { - // don't eat any more ammo after gun is fully charged. - m_pPlayer->m_flNextAmmoBurn = 1000; - } - - int pitch = ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100; - if ( pitch > 250 ) - pitch = 250; - - // ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch ); - - if ( m_iSoundState == 0 ) - ALERT( at_console, "sound state %d\n", m_iSoundState ); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - // m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - if ( m_pPlayer->m_flStartCharge < gpGlobals->time - 10 ) - { - // Player charged up too long. Zap him. - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG(0,0x3f)); - - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - -#ifndef CLIENT_DLL - m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK ); - UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN ); -#endif - SendWeaponAnim( GAUSS_IDLE ); - - // Player may have been killed and this weapon dropped, don't execute any more code after this! - return; - } - } -} - -//========================================================= -// StartFire- since all of this code has to run and then -// call Fire(), it was easier at this point to rip it out -// of weaponidle() and make its own function then to try to -// merge this into Fire(), which has some identical variable names -//========================================================= -void CGauss::StartFire( void ) -{ - float flDamage; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; - - if ( gpGlobals->time - m_pPlayer->m_flStartCharge > GetFullChargeTime() ) - { - flDamage = 200; - } - else - { - flDamage = 200 * (( gpGlobals->time - m_pPlayer->m_flStartCharge) / GetFullChargeTime() ); - } - - if ( m_fPrimaryFire ) - { - // fixed damage on primary attack -#ifdef CLIENT_DLL - flDamage = 20; -#else - flDamage = gSkillData.plrDmgGauss; -#endif - } - - if (m_fInAttack != 3) - { - //ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_pPlayer->m_flStartCharge, flDamage ); - -#ifndef CLIENT_DLL - float flZVel = m_pPlayer->pev->velocity.z; - - if ( !m_fPrimaryFire ) - { - m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; - } - - if ( !g_pGameRules->IsMultiplayer() ) - - { - // in deathmatch, gauss can pop you up into the air. Not in single play. - m_pPlayer->pev->velocity.z = flZVel; - } -#endif - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - - // time until aftershock 'static discharge' sound - m_pPlayer->m_flPlayAftershock = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.3, 0.8 ); - - Fire( vecSrc, vecAiming, flDamage ); -} - -void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) -{ - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - - Vector vecSrc = vecOrigSrc; - Vector vecDest = vecSrc + vecDir * 8192; - edict_t *pentIgnore; - TraceResult tr, beam_tr; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - - pentIgnore = ENT( m_pPlayer->pev ); - - // The main firing event is sent unreliably so it won't be delayed. - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); - - // This reliable event is used to stop the spinning sound - // It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client - // It's sent reliably anyway, which could lead to other delays - - PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - - /*ALERT( at_console, "%f %f %f\n%f %f %f\n", - vecSrc.x, vecSrc.y, vecSrc.z, - vecDest.x, vecDest.y, vecDest.z );*/ - - -// ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); - -#ifndef CLIENT_DLL - while (flDamage > 10 && nMaxHits > 0) - { - nMaxHits--; - - // ALERT( at_console, "." ); - UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr); - - if (tr.fAllSolid) - break; - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if (pEntity == NULL) - break; - - if ( fFirstBeam ) - { - m_pPlayer->pev->effects |= EF_MUZZLEFLASH; - fFirstBeam = 0; - - nTotal += 26; - } - - if (pEntity->pev->takedamage) - { - ClearMultiDamage(); - pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - } - - if ( pEntity->ReflectGauss() ) - { - float n; - - pentIgnore = NULL; - - n = -DotProduct(tr.vecPlaneNormal, vecDir); - - if (n < 0.5) // 60 degrees - { - // ALERT( at_console, "reflect %f\n", n ); - // reflect - Vector r; - - r = 2.0 * tr.vecPlaneNormal * n + vecDir; - flMaxFrac = flMaxFrac - tr.flFraction; - vecDir = r; - vecSrc = tr.vecEndPos + vecDir * 8; - vecDest = vecSrc + vecDir * 8192; - - // explode a bit - m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); - - nTotal += 34; - - // lose energy - if (n == 0) n = 0.1; - flDamage = flDamage * (1 - n); - } - else - { - nTotal += 13; - - // limit it to one hole punch - if (fHasPunched) - break; - fHasPunched = 1; - - // try punching through wall if secondary attack (primary is incapable of breaking through) - if ( !m_fPrimaryFire ) - { - UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr); - if (!beam_tr.fAllSolid) - { - // trace backwards to find exit point - UTIL_TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, &beam_tr); - - float n = (beam_tr.vecEndPos - tr.vecEndPos).Length( ); - - if (n < flDamage) - { - if (n == 0) n = 1; - flDamage -= n; - - // ALERT( at_console, "punch %f\n", n ); - nTotal += 21; - - // exit blast damage - //m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); - float damage_radius; - - - if ( g_pGameRules->IsMultiplayer() ) - { - damage_radius = flDamage * 1.75; // Old code == 2.5 - } - else - { - damage_radius = flDamage * 2.5; - } - - ::RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST ); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - nTotal += 53; - - vecSrc = beam_tr.vecEndPos + vecDir; - } - } - else - { - //ALERT( at_console, "blocked %f\n", n ); - flDamage = 0; - } - } - else - { - //ALERT( at_console, "blocked solid\n" ); - - flDamage = 0; - } - - } - } - else - { - vecSrc = tr.vecEndPos + vecDir; - pentIgnore = ENT( pEntity->pev ); - } - } -#endif - // ALERT( at_console, "%d bytes\n", nTotal ); -} - - - - -void CGauss::WeaponIdle( void ) -{ - ResetEmptySound( ); - - // play aftershock static discharge - if ( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro5.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro6.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 3: break; // no sound - } - m_pPlayer->m_flPlayAftershock = 0.0; - } - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - - if (m_fInAttack != 0) - { - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - } - else - { - int iAnim; - float flRand = RANDOM_FLOAT(0, 1); - if (flRand <= 0.5) - { - iAnim = GAUSS_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else if (flRand <= 0.75) - { - iAnim = GAUSS_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = GAUSS_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - return; - SendWeaponAnim( iAnim ); - - } -} - - - - - - -class CGaussAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_gaussammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_gaussammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); - -#endif diff --git a/main/source/dlls/genericmonster.cpp b/main/source/dlls/genericmonster.cpp index 1c8c6eea..ece186e6 100644 --- a/main/source/dlls/genericmonster.cpp +++ b/main/source/dlls/genericmonster.cpp @@ -1,140 +1,140 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Generic Monster - purely for scripted sequence work. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -// For holograms, make them not solid so the player can walk through them -#define SF_GENERICMONSTER_NOTSOLID 4 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CGenericMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); -}; -LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGenericMonster :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGenericMonster :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGenericMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGenericMonster :: ISoundMask ( void ) -{ - return NULL; -} - -//========================================================= -// Spawn -//========================================================= -void CGenericMonster :: Spawn() -{ - Precache(); - - SET_MODEL( ENT(pev), STRING(pev->model) ); - -/* - if ( FStrEq( STRING(pev->model), "models/player.mdl" ) ) - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); -*/ - - if ( FStrEq( STRING(pev->model), "models/player.mdl" ) || FStrEq( STRING(pev->model), "models/holo.mdl" ) ) - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - - if ( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGenericMonster :: Precache() -{ - PRECACHE_MODEL( (char *)STRING(pev->model) ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Generic Monster - purely for scripted sequence work. +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + +// For holograms, make them not solid so the player can walk through them +#define SF_GENERICMONSTER_NOTSOLID 4 + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= + +class CGenericMonster : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + int ISoundMask ( void ); +}; +LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CGenericMonster :: Classify ( void ) +{ + return CLASS_PLAYER_ALLY; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CGenericMonster :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + default: + ys = 90; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CGenericMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case 0: + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// ISoundMask - generic monster can't hear. +//========================================================= +int CGenericMonster :: ISoundMask ( void ) +{ + return NULL; +} + +//========================================================= +// Spawn +//========================================================= +void CGenericMonster :: Spawn() +{ + Precache(); + + SET_MODEL( ENT(pev), STRING(pev->model) ); + +/* + if ( FStrEq( STRING(pev->model), "models/player.mdl" ) ) + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + else + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); +*/ + + if ( FStrEq( STRING(pev->model), "models/player.mdl" ) || FStrEq( STRING(pev->model), "models/holo.mdl" ) ) + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + else + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->health = 8; + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); + + if ( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) + { + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + } +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CGenericMonster :: Precache() +{ + PRECACHE_MODEL( (char *)STRING(pev->model) ); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= diff --git a/main/source/dlls/ggrenade.cpp b/main/source/dlls/ggrenade.cpp index cf8cce70..17355130 100644 --- a/main/source/dlls/ggrenade.cpp +++ b/main/source/dlls/ggrenade.cpp @@ -1,613 +1,613 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== generic grenade.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "decals.h" -#include "../mod/AvHPlayerUpgrade.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHMarineWeaponConstants.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHServerVariables.h" - -#include "../util/MathUtil.h" -#include "../common/vec_op.h" - -//===================grenade - - -LINK_ENTITY_TO_CLASS( grenade, CGrenade ); - -// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges -#define SF_DETONATE 0x0001 - -// -// Grenade Explode -// -void CGrenade::SetDamageType(int inDamageType) { - this->m_damageType=inDamageType; -} - -void CGrenade::Explode( Vector vecSrc, Vector vecAim) -{ - TraceResult tr; - UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr); - - Explode( &tr,this->m_damageType); -} - -// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution. -void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) -{ - float flRndSound;// sound randomizer - - pev->model = iStringNull;//invisible - pev->solid = SOLID_NOT;// intangible - - float theDamageModifier; - int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); - int theDamage = this->pev->dmg*theDamageModifier; - - pev->takedamage = DAMAGE_NO; - - // TODO: Look at upgrade and mark up damage - - // Pull out of the wall a bit - if ( pTrace->flFraction != 1.0 ) - { - Vector theCollisionPoint = pTrace->vecEndPos; - Vector theDesiredPoint = theCollisionPoint + (pTrace->vecPlaneNormal * (theDamage - 24) * 0.6); - UTIL_TraceLine(theCollisionPoint,theDesiredPoint,ignore_monsters,ENT(pev),pTrace); - if(pTrace->flFraction != 1.0) //hit a ceiling of some sort - { - //go halfway between floor and ceiling - theDesiredPoint = theCollisionPoint + (pTrace->vecEndPos - theCollisionPoint) * 0.5; - } - pev->origin = theDesiredPoint; - } - - int iContents = UTIL_PointContents ( pev->origin ); - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound - WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - if (iContents != CONTENTS_WATER) - { - WRITE_SHORT( g_sModelIndexFireball ); - } - else - { - WRITE_SHORT( g_sModelIndexWExplosion ); - } - WRITE_BYTE( (theDamage - 50) * .60 ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - entvars_t *pevOwner; - if ( pev->owner ) - pevOwner = VARS( pev->owner ); - else - pevOwner = NULL; - -// pev->owner = NULL; // can't traceline attack owner if this is set - - // Current radius = 2.5*140 = 350 - float theRadius = BALANCE_VAR(kGrenadeRadius); - ::RadiusDamage(this->pev->origin, this->pev, pevOwner, theDamage, theRadius, CLASS_NONE, bitsDamageType); - - // Play view shake here - float theShakeAmplitude = 80; - float theShakeFrequency = 100; - float theShakeDuration = 1.0f; - float theShakeRadius = 700; - UTIL_ScreenShake(this->pev->origin, theShakeAmplitude, theShakeFrequency, theShakeDuration, theShakeRadius); - - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); - } - - flRndSound = RANDOM_FLOAT( 0 , 1 ); - - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break; - } - - pev->effects |= EF_NODRAW; - SetThink( &CGrenade::Smoke ); - pev->velocity = g_vecZero; - pev->nextthink = gpGlobals->time + 0.3; - - if (iContents != CONTENTS_WATER) - { - int sparkCount = RANDOM_LONG(0,3); - for ( int i = 0; i < sparkCount; i++ ) - Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL ); - } -} - - -void CGrenade::Smoke( void ) -{ - if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) - { - UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 ); - } - else - { - float theDamageModifier; - int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); - int theDamage = this->pev->dmg*theDamageModifier; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( (theDamage - 50) * 0.80 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - UTIL_Remove( this ); -} - -void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - Detonate( ); -} - - -// Timed grenade, this think is called when time runs out. -void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CGrenade::Detonate ); - pev->nextthink = gpGlobals->time; -} - -void CGrenade::PreDetonate( void ) -{ - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); - - SetThink( &CGrenade::Detonate ); - pev->nextthink = gpGlobals->time + 1; -} - - -void CGrenade::Detonate( void ) -{ - TraceResult tr; - Vector vecSpot;// trace starts here! - -#ifdef DEBUG - if(ns_cvar_float(&avh_bulletcam)) - { - SET_VIEW(this->pev->owner, this->pev->owner); - } -#endif - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); - - Explode( &tr, this->m_damageType); -} - -// -// Contact grenade, explode when it touches something -// -void CGrenade::ExplosiveBounceTouch( CBaseEntity *pOther ) -{ - if(pOther) - { - bool theCanHurtEntity = GetGameRules()->CanEntityDoDamageTo(this, pOther); - if(theCanHurtEntity) - { - // If we hit an enemy, explode - ExplodeTouch(pOther); - } - // Otherwise, bounce - else - { - BounceTouch(pOther); - } - } -} - -// -// Contact grenade, explode when it touches something -// -void CGrenade::ExplodeTouch( CBaseEntity *pOther ) -{ - TraceResult tr; - Vector vecSpot;// trace starts here! - - pev->enemy = pOther->edict(); - - vecSpot = pev->origin - pev->velocity.Normalize() * 32; - UTIL_TraceLine( vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr ); - - Explode( &tr, this->m_damageType); -} - - -void CGrenade::DangerSoundThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length( ), 0.2 ); - pev->nextthink = gpGlobals->time + 0.2; - - if (pev->waterlevel != 0) - { - pev->velocity = pev->velocity * 0.5; - } -} - - -void CGrenade::BounceTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - - // Grenades to tend to get "stuck" on sloped surfaces due to the HL physics - // system, so move it away from whatever we're colliding with. - - // Get the surface normal. - - - - Vector theVelocityDirection; - VectorCopy(pev->velocity, theVelocityDirection); - VectorNormalize(theVelocityDirection); - - Vector theTraceStart; - Vector theTraceEnd; - - VectorMA(pev->origin, -10, theVelocityDirection, theTraceStart); - VectorMA(pev->origin, 10, theVelocityDirection, theTraceEnd); - - TraceResult tr; - UTIL_TraceLine(theTraceStart, theTraceEnd, dont_ignore_monsters, dont_ignore_glass, ENT(pev), &tr); - - if (tr.flFraction < 1) // Should always be the case. - { - VectorMA(pev->origin, 2, tr.vecPlaneNormal, pev->origin); - UTIL_SetOrigin(pev, pev->origin); - } - - // only do damage if we're moving fairly fast - if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100) - { - entvars_t *pevOwner = VARS( pev->owner ); - if (pevOwner) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, this->m_damageType); - ApplyMultiDamage( pev, pevOwner); - } - m_flNextAttack = gpGlobals->time + 1.0; // debounce - } - - Vector vecTestVelocity; - // pev->avelocity = Vector (300, 300, 300); - - float theDamageModifier; - int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); - int theDamage = this->pev->dmg*theDamageModifier; - - // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical - // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. - // trimming the Z velocity a bit seems to help quite a bit. - vecTestVelocity = pev->velocity; - vecTestVelocity.z *= 0.45; - - if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 ) - { - //ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() ); - - // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. - // go ahead and emit the danger sound. - - // register a radius louder than the explosion, so we make sure everyone gets out of the way - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, theDamage / 0.4, 0.3 ); - m_fRegisteredSound = TRUE; - } - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.8; - - pev->sequence = 0;//RANDOM_LONG( 1, 1 ); - } - else - { - // play bounce sound - BounceSound(); - } - pev->framerate = pev->velocity.Length() / 200.0; - if (pev->framerate > 1.0) - pev->framerate = 1; - else if (pev->framerate < 0.5) - pev->framerate = 0; - - pev->velocity = pev->velocity * 0.8; - -} - - - -void CGrenade::SlideTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector (300, 300, 300); - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - - if (pev->velocity.x != 0 || pev->velocity.y != 0) - { - // maintain sliding sound - } - } - else - { - BounceSound(); - } -} - -void CGrenade :: BounceSound( void ) -{ - // Play different sounds for contact or timed grenade - if(this->m_pfnTouch == static_cast (&CGrenade::ExplosiveBounceTouch)) - { - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound1, 0.25, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound2, 0.25, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound3, 0.25, ATTN_NORM); break; - } - } - else - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, kGRHitSound, 0.5, ATTN_NORM); - } - -} - -void CGrenade :: TumbleThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->dmgtime - 1 < gpGlobals->time) - { - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); - } - - if (pev->dmgtime <= gpGlobals->time) - { - SetThink( &CGrenade::Detonate ); - } - if (pev->waterlevel != 0) - { - pev->velocity = pev->velocity * 0.5; - pev->framerate = 0.2; - } -} - - -void CGrenade:: Spawn( void ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->classname = MAKE_STRING( "grenade" ); - - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/grenade.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - m_fRegisteredSound = FALSE; - m_damageType = NS_DMG_BLAST; -} - - -CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - // contact grenades arc lower - pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it. - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - - // make monsters afaid of it while in the air - pGrenade->SetThink( &CGrenade::DangerSoundThink ); - pGrenade->pev->nextthink = gpGlobals->time; - - // Tumble in air - pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); - - // Explode on contact - pGrenade->SetTouch( &CGrenade::ExplodeTouch ); - - pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade; - - return pGrenade; -} - -CGrenade* CGrenade::ShootExplosiveTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, int inDamageType) -{ - CGrenade *pGrenade = CGrenade::ShootTimed(pevOwner, vecStart, vecVelocity, time); - pGrenade->SetDamageType(inDamageType); - pGrenade->SetTouch(&CGrenade::ExplosiveBounceTouch); - return pGrenade; -} - - -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - - pGrenade->SetTouch( &CGrenade::BounceTouch ); // Bounce if touched - -#ifdef DEBUG - if(ns_cvar_float(&avh_bulletcam)) - { - SET_VIEW(ENT(pevOwner), ENT(pGrenade->pev)); - } -#endif - - // Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate - // will insert a DANGER sound into the world sound list and delay detonation for one second so that - // the grenade explodes after the exact amount of time specified in the call to ShootTimed(). - - pGrenade->pev->dmgtime = gpGlobals->time + time; - pGrenade->SetThink( &CGrenade::TumbleThink ); - pGrenade->pev->nextthink = gpGlobals->time + 0.1; - if (time < 0.1) - { - pGrenade->pev->nextthink = gpGlobals->time; - pGrenade->pev->velocity = Vector( 0, 0, 0 ); - } - - pGrenade->pev->sequence = 0;//RANDOM_LONG( 3, 6 ); - pGrenade->pev->framerate = 1.0; - - // Tumble through the air - pGrenade->pev->avelocity.x = RANDOM_LONG(-800, -300); - - // Also explode on contact - //pGrenade->SetTouch( ExplodeTouch ); - - pGrenade->pev->gravity = 0.5; - pGrenade->pev->friction = 0.8; - - SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl"); - - return pGrenade; -} - - -CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->pev->movetype = MOVETYPE_BOUNCE; - pGrenade->pev->classname = MAKE_STRING( "grenade" ); - - pGrenade->pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model - - UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pGrenade->pev->dmg = 200; - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = g_vecZero; - pGrenade->pev->owner = ENT(pevOwner); - - // Detonate in "time" seconds - pGrenade->SetThink( &CGrenade::SUB_DoNothing ); - pGrenade->SetUse( &CGrenade::DetonateUse ); - pGrenade->SetTouch( &CGrenade::SlideTouch ); - pGrenade->pev->spawnflags = SF_DETONATE; - - pGrenade->pev->friction = 0.9; - - return pGrenade; -} - - - -void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) -{ - edict_t *pentFind; - edict_t *pentOwner; - - if ( !pevOwner ) - return; - - CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner ); - - pentOwner = pOwner->edict(); - - pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "grenade" ); - while ( !FNullEnt( pentFind ) ) - { - CBaseEntity *pEnt = Instance( pentFind ); - if ( pEnt ) - { - if ( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner ) - { - if ( code == SATCHEL_DETONATE ) - pEnt->Use( pOwner, pOwner, USE_ON, 0 ); - else // SATCHEL_RELEASE - pEnt->pev->owner = NULL; - } - } - pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" ); - } -} - -//======================end grenade - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== generic grenade.cpp ======================================================== + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "decals.h" +#include "../mod/AvHPlayerUpgrade.h" +#include "../mod/AvHServerVariables.h" +#include "../mod/AvHMarineWeaponConstants.h" +#include "../mod/AvHGamerules.h" +#include "../mod/AvHServerVariables.h" + +#include "../util/MathUtil.h" +#include "../common/vec_op.h" + +//===================grenade + + +LINK_ENTITY_TO_CLASS( grenade, CGrenade ); + +// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges +#define SF_DETONATE 0x0001 + +// +// Grenade Explode +// +void CGrenade::SetDamageType(int inDamageType) { + this->m_damageType=inDamageType; +} + +void CGrenade::Explode( Vector vecSrc, Vector vecAim) +{ + TraceResult tr; + UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr); + + Explode( &tr,this->m_damageType); +} + +// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution. +void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) +{ + float flRndSound;// sound randomizer + + pev->model = iStringNull;//invisible + pev->solid = SOLID_NOT;// intangible + + float theDamageModifier; + int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); + int theDamage = this->pev->dmg*theDamageModifier; + + pev->takedamage = DAMAGE_NO; + + // TODO: Look at upgrade and mark up damage + + // Pull out of the wall a bit + if ( pTrace->flFraction != 1.0 ) + { + Vector theCollisionPoint = pTrace->vecEndPos; + Vector theDesiredPoint = theCollisionPoint + (pTrace->vecPlaneNormal * (theDamage - 24) * 0.6); + UTIL_TraceLine(theCollisionPoint,theDesiredPoint,ignore_monsters,ENT(pev),pTrace); + if(pTrace->flFraction != 1.0) //hit a ceiling of some sort + { + //go halfway between floor and ceiling + theDesiredPoint = theCollisionPoint + (pTrace->vecEndPos - theCollisionPoint) * 0.5; + } + pev->origin = theDesiredPoint; + } + + int iContents = UTIL_PointContents ( pev->origin ); + + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound + WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + if (iContents != CONTENTS_WATER) + { + WRITE_SHORT( g_sModelIndexFireball ); + } + else + { + WRITE_SHORT( g_sModelIndexWExplosion ); + } + WRITE_BYTE( (theDamage - 50) * .60 ); // scale * 10 + WRITE_BYTE( 15 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + + entvars_t *pevOwner; + if ( pev->owner ) + pevOwner = VARS( pev->owner ); + else + pevOwner = NULL; + +// pev->owner = NULL; // can't traceline attack owner if this is set + + // Current radius = 2.5*140 = 350 + float theRadius = BALANCE_VAR(kGrenadeRadius); + ::RadiusDamage(this->pev->origin, this->pev, pevOwner, theDamage, theRadius, CLASS_NONE, bitsDamageType); + + // Play view shake here + float theShakeAmplitude = 80; + float theShakeFrequency = 100; + float theShakeDuration = 1.0f; + float theShakeRadius = 700; + UTIL_ScreenShake(this->pev->origin, theShakeAmplitude, theShakeFrequency, theShakeDuration, theShakeRadius); + + if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) + { + UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); + } + else + { + UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); + } + + flRndSound = RANDOM_FLOAT( 0 , 1 ); + + switch ( RANDOM_LONG( 0, 2 ) ) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break; + } + + pev->effects |= EF_NODRAW; + SetThink( &CGrenade::Smoke ); + pev->velocity = g_vecZero; + pev->nextthink = gpGlobals->time + 0.3; + + if (iContents != CONTENTS_WATER) + { + int sparkCount = RANDOM_LONG(0,3); + for ( int i = 0; i < sparkCount; i++ ) + Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL ); + } +} + + +void CGrenade::Smoke( void ) +{ + if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) + { + UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 ); + } + else + { + float theDamageModifier; + int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); + int theDamage = this->pev->dmg*theDamageModifier; + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( (theDamage - 50) * 0.80 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + MESSAGE_END(); + } + UTIL_Remove( this ); +} + +void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) +{ + Detonate( ); +} + + +// Timed grenade, this think is called when time runs out. +void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( &CGrenade::Detonate ); + pev->nextthink = gpGlobals->time; +} + +void CGrenade::PreDetonate( void ) +{ + CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); + + SetThink( &CGrenade::Detonate ); + pev->nextthink = gpGlobals->time + 1; +} + + +void CGrenade::Detonate( void ) +{ + TraceResult tr; + Vector vecSpot;// trace starts here! + +#ifdef DEBUG + if(ns_cvar_float(&avh_bulletcam)) + { + SET_VIEW(this->pev->owner, this->pev->owner); + } +#endif + + vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); + UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); + + Explode( &tr, this->m_damageType); +} + +// +// Contact grenade, explode when it touches something +// +void CGrenade::ExplosiveBounceTouch( CBaseEntity *pOther ) +{ + if(pOther) + { + bool theCanHurtEntity = GetGameRules()->CanEntityDoDamageTo(this, pOther); + if(theCanHurtEntity) + { + // If we hit an enemy, explode + ExplodeTouch(pOther); + } + // Otherwise, bounce + else + { + BounceTouch(pOther); + } + } +} + +// +// Contact grenade, explode when it touches something +// +void CGrenade::ExplodeTouch( CBaseEntity *pOther ) +{ + TraceResult tr; + Vector vecSpot;// trace starts here! + + pev->enemy = pOther->edict(); + + vecSpot = pev->origin - pev->velocity.Normalize() * 32; + UTIL_TraceLine( vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr ); + + Explode( &tr, this->m_damageType); +} + + +void CGrenade::DangerSoundThink( void ) +{ + if (!IsInWorld()) + { + UTIL_Remove( this ); + return; + } + + CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length( ), 0.2 ); + pev->nextthink = gpGlobals->time + 0.2; + + if (pev->waterlevel != 0) + { + pev->velocity = pev->velocity * 0.5; + } +} + + +void CGrenade::BounceTouch( CBaseEntity *pOther ) +{ + // don't hit the guy that launched this grenade + if ( pOther->edict() == pev->owner ) + return; + + + // Grenades to tend to get "stuck" on sloped surfaces due to the HL physics + // system, so move it away from whatever we're colliding with. + + // Get the surface normal. + + + + Vector theVelocityDirection; + VectorCopy(pev->velocity, theVelocityDirection); + VectorNormalize(theVelocityDirection); + + Vector theTraceStart; + Vector theTraceEnd; + + VectorMA(pev->origin, -10, theVelocityDirection, theTraceStart); + VectorMA(pev->origin, 10, theVelocityDirection, theTraceEnd); + + TraceResult tr; + UTIL_TraceLine(theTraceStart, theTraceEnd, dont_ignore_monsters, dont_ignore_glass, ENT(pev), &tr); + + if (tr.flFraction < 1) // Should always be the case. + { + VectorMA(pev->origin, 2, tr.vecPlaneNormal, pev->origin); + UTIL_SetOrigin(pev, pev->origin); + } + + // only do damage if we're moving fairly fast + if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100) + { + entvars_t *pevOwner = VARS( pev->owner ); + if (pevOwner) + { + TraceResult tr = UTIL_GetGlobalTrace( ); + ClearMultiDamage( ); + pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, this->m_damageType); + ApplyMultiDamage( pev, pevOwner); + } + m_flNextAttack = gpGlobals->time + 1.0; // debounce + } + + Vector vecTestVelocity; + // pev->avelocity = Vector (300, 300, 300); + + float theDamageModifier; + int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); + int theDamage = this->pev->dmg*theDamageModifier; + + // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical + // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. + // trimming the Z velocity a bit seems to help quite a bit. + vecTestVelocity = pev->velocity; + vecTestVelocity.z *= 0.45; + + if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 ) + { + //ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() ); + + // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. + // go ahead and emit the danger sound. + + // register a radius louder than the explosion, so we make sure everyone gets out of the way + CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, theDamage / 0.4, 0.3 ); + m_fRegisteredSound = TRUE; + } + + if (pev->flags & FL_ONGROUND) + { + // add a bit of static friction + pev->velocity = pev->velocity * 0.8; + + pev->sequence = 0;//RANDOM_LONG( 1, 1 ); + } + else + { + // play bounce sound + BounceSound(); + } + pev->framerate = pev->velocity.Length() / 200.0; + if (pev->framerate > 1.0) + pev->framerate = 1; + else if (pev->framerate < 0.5) + pev->framerate = 0; + + pev->velocity = pev->velocity * 0.8; + +} + + + +void CGrenade::SlideTouch( CBaseEntity *pOther ) +{ + // don't hit the guy that launched this grenade + if ( pOther->edict() == pev->owner ) + return; + + // pev->avelocity = Vector (300, 300, 300); + + if (pev->flags & FL_ONGROUND) + { + // add a bit of static friction + pev->velocity = pev->velocity * 0.95; + + if (pev->velocity.x != 0 || pev->velocity.y != 0) + { + // maintain sliding sound + } + } + else + { + BounceSound(); + } +} + +void CGrenade :: BounceSound( void ) +{ + // Play different sounds for contact or timed grenade + if(this->m_pfnTouch == static_cast (&CGrenade::ExplosiveBounceTouch)) + { + switch ( RANDOM_LONG( 0, 2 ) ) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound1, 0.25, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound2, 0.25, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound3, 0.25, ATTN_NORM); break; + } + } + else + { + EMIT_SOUND(ENT(pev), CHAN_VOICE, kGRHitSound, 0.5, ATTN_NORM); + } + +} + +void CGrenade :: TumbleThink( void ) +{ + if (!IsInWorld()) + { + UTIL_Remove( this ); + return; + } + + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + if (pev->dmgtime - 1 < gpGlobals->time) + { + CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); + } + + if (pev->dmgtime <= gpGlobals->time) + { + SetThink( &CGrenade::Detonate ); + } + if (pev->waterlevel != 0) + { + pev->velocity = pev->velocity * 0.5; + pev->framerate = 0.2; + } +} + + +void CGrenade:: Spawn( void ) +{ + pev->movetype = MOVETYPE_BOUNCE; + pev->classname = MAKE_STRING( "grenade" ); + + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/grenade.mdl"); + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + + m_fRegisteredSound = FALSE; + m_damageType = NS_DMG_BLAST; +} + + +CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) +{ + CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); + pGrenade->Spawn(); + // contact grenades arc lower + pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it. + UTIL_SetOrigin( pGrenade->pev, vecStart ); + pGrenade->pev->velocity = vecVelocity; + pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity); + pGrenade->pev->owner = ENT(pevOwner); + + // make monsters afaid of it while in the air + pGrenade->SetThink( &CGrenade::DangerSoundThink ); + pGrenade->pev->nextthink = gpGlobals->time; + + // Tumble in air + pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); + + // Explode on contact + pGrenade->SetTouch( &CGrenade::ExplodeTouch ); + + pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade; + + return pGrenade; +} + +CGrenade* CGrenade::ShootExplosiveTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, int inDamageType) +{ + CGrenade *pGrenade = CGrenade::ShootTimed(pevOwner, vecStart, vecVelocity, time); + pGrenade->SetDamageType(inDamageType); + pGrenade->SetTouch(&CGrenade::ExplosiveBounceTouch); + return pGrenade; +} + + +CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) +{ + CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); + pGrenade->Spawn(); + UTIL_SetOrigin( pGrenade->pev, vecStart ); + pGrenade->pev->velocity = vecVelocity; + pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); + pGrenade->pev->owner = ENT(pevOwner); + + pGrenade->SetTouch( &CGrenade::BounceTouch ); // Bounce if touched + +#ifdef DEBUG + if(ns_cvar_float(&avh_bulletcam)) + { + SET_VIEW(ENT(pevOwner), ENT(pGrenade->pev)); + } +#endif + + // Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate + // will insert a DANGER sound into the world sound list and delay detonation for one second so that + // the grenade explodes after the exact amount of time specified in the call to ShootTimed(). + + pGrenade->pev->dmgtime = gpGlobals->time + time; + pGrenade->SetThink( &CGrenade::TumbleThink ); + pGrenade->pev->nextthink = gpGlobals->time + 0.1; + if (time < 0.1) + { + pGrenade->pev->nextthink = gpGlobals->time; + pGrenade->pev->velocity = Vector( 0, 0, 0 ); + } + + pGrenade->pev->sequence = 0;//RANDOM_LONG( 3, 6 ); + pGrenade->pev->framerate = 1.0; + + // Tumble through the air + pGrenade->pev->avelocity.x = RANDOM_LONG(-800, -300); + + // Also explode on contact + //pGrenade->SetTouch( ExplodeTouch ); + + pGrenade->pev->gravity = 0.5; + pGrenade->pev->friction = 0.8; + + SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl"); + + return pGrenade; +} + + +CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) +{ + CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); + pGrenade->pev->movetype = MOVETYPE_BOUNCE; + pGrenade->pev->classname = MAKE_STRING( "grenade" ); + + pGrenade->pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model + + UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + + pGrenade->pev->dmg = 200; + UTIL_SetOrigin( pGrenade->pev, vecStart ); + pGrenade->pev->velocity = vecVelocity; + pGrenade->pev->angles = g_vecZero; + pGrenade->pev->owner = ENT(pevOwner); + + // Detonate in "time" seconds + pGrenade->SetThink( &CGrenade::SUB_DoNothing ); + pGrenade->SetUse( &CGrenade::DetonateUse ); + pGrenade->SetTouch( &CGrenade::SlideTouch ); + pGrenade->pev->spawnflags = SF_DETONATE; + + pGrenade->pev->friction = 0.9; + + return pGrenade; +} + + + +void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) +{ + edict_t *pentFind; + edict_t *pentOwner; + + if ( !pevOwner ) + return; + + CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner ); + + pentOwner = pOwner->edict(); + + pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "grenade" ); + while ( !FNullEnt( pentFind ) ) + { + CBaseEntity *pEnt = Instance( pentFind ); + if ( pEnt ) + { + if ( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner ) + { + if ( code == SATCHEL_DETONATE ) + pEnt->Use( pOwner, pOwner, USE_ON, 0 ); + else // SATCHEL_RELEASE + pEnt->pev->owner = NULL; + } + } + pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" ); + } +} + +//======================end grenade + diff --git a/main/source/dlls/ggrenade.cpp~ b/main/source/dlls/ggrenade.cpp~ deleted file mode 100644 index d91bb5f3..00000000 --- a/main/source/dlls/ggrenade.cpp~ +++ /dev/null @@ -1,613 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== generic grenade.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "decals.h" -#include "../mod/AvHPlayerUpgrade.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHMarineWeaponConstants.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHServerVariables.h" - -#include "util/MathUtil.h" -#include "../common/vec_op.h" - -//===================grenade - - -LINK_ENTITY_TO_CLASS( grenade, CGrenade ); - -// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges -#define SF_DETONATE 0x0001 - -// -// Grenade Explode -// -void CGrenade::SetDamageType(int inDamageType) { - this->m_damageType=inDamageType; -} - -void CGrenade::Explode( Vector vecSrc, Vector vecAim) -{ - TraceResult tr; - UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr); - - Explode( &tr, this->m_damageType); -} - -// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution. -void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) -{ - float flRndSound;// sound randomizer - - pev->model = iStringNull;//invisible - pev->solid = SOLID_NOT;// intangible - - float theDamageModifier; - int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); - int theDamage = this->pev->dmg*theDamageModifier; - - pev->takedamage = DAMAGE_NO; - - // TODO: Look at upgrade and mark up damage - - // Pull out of the wall a bit - if ( pTrace->flFraction != 1.0 ) - { - Vector theCollisionPoint = pTrace->vecEndPos; - Vector theDesiredPoint = theCollisionPoint + (pTrace->vecPlaneNormal * (theDamage - 24) * 0.6); - UTIL_TraceLine(theCollisionPoint,theDesiredPoint,ignore_monsters,ENT(pev),pTrace); - if(pTrace->flFraction != 1.0) //hit a ceiling of some sort - { - //go halfway between floor and ceiling - theDesiredPoint = theCollisionPoint + (pTrace->vecEndPos - theCollisionPoint) * 0.5; - } - pev->origin = theDesiredPoint; - } - - int iContents = UTIL_PointContents ( pev->origin ); - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound - WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - if (iContents != CONTENTS_WATER) - { - WRITE_SHORT( g_sModelIndexFireball ); - } - else - { - WRITE_SHORT( g_sModelIndexWExplosion ); - } - WRITE_BYTE( (theDamage - 50) * .60 ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - entvars_t *pevOwner; - if ( pev->owner ) - pevOwner = VARS( pev->owner ); - else - pevOwner = NULL; - -// pev->owner = NULL; // can't traceline attack owner if this is set - - // Current radius = 2.5*140 = 350 - float theRadius = BALANCE_VAR(kGrenadeRadius); - ::RadiusDamage(this->pev->origin, this->pev, pevOwner, theDamage, theRadius, CLASS_NONE, bitsDamageType); - - // Play view shake here - float theShakeAmplitude = 80; - float theShakeFrequency = 100; - float theShakeDuration = 1.0f; - float theShakeRadius = 700; - UTIL_ScreenShake(this->pev->origin, theShakeAmplitude, theShakeFrequency, theShakeDuration, theShakeRadius); - - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); - } - - flRndSound = RANDOM_FLOAT( 0 , 1 ); - - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break; - } - - pev->effects |= EF_NODRAW; - SetThink( &CGrenade::Smoke ); - pev->velocity = g_vecZero; - pev->nextthink = gpGlobals->time + 0.3; - - if (iContents != CONTENTS_WATER) - { - int sparkCount = RANDOM_LONG(0,3); - for ( int i = 0; i < sparkCount; i++ ) - Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL ); - } -} - - -void CGrenade::Smoke( void ) -{ - if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) - { - UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 ); - } - else - { - float theDamageModifier; - int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); - int theDamage = this->pev->dmg*theDamageModifier; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( (theDamage - 50) * 0.80 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - UTIL_Remove( this ); -} - -void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - Detonate( ); -} - - -// Timed grenade, this think is called when time runs out. -void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CGrenade::Detonate ); - pev->nextthink = gpGlobals->time; -} - -void CGrenade::PreDetonate( void ) -{ - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); - - SetThink( &CGrenade::Detonate ); - pev->nextthink = gpGlobals->time + 1; -} - - -void CGrenade::Detonate( void ) -{ - TraceResult tr; - Vector vecSpot;// trace starts here! - -#ifdef DEBUG - if(ns_cvar_float(&avh_bulletcam)) - { - SET_VIEW(this->pev->owner, this->pev->owner); - } -#endif - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); - - Explode( &tr, this->m_damageType); -} - -// -// Contact grenade, explode when it touches something -// -void CGrenade::ExplosiveBounceTouch( CBaseEntity *pOther ) -{ - if(pOther) - { - bool theCanHurtEntity = GetGameRules()->CanEntityDoDamageTo(this, pOther); - if(theCanHurtEntity) - { - // If we hit an enemy, explode - ExplodeTouch(pOther); - } - // Otherwise, bounce - else - { - BounceTouch(pOther); - } - } -} - -// -// Contact grenade, explode when it touches something -// -void CGrenade::ExplodeTouch( CBaseEntity *pOther ) -{ - TraceResult tr; - Vector vecSpot;// trace starts here! - - pev->enemy = pOther->edict(); - - vecSpot = pev->origin - pev->velocity.Normalize() * 32; - UTIL_TraceLine( vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr ); - - Explode( &tr, this->m_damageType); -} - - -void CGrenade::DangerSoundThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length( ), 0.2 ); - pev->nextthink = gpGlobals->time + 0.2; - - if (pev->waterlevel != 0) - { - pev->velocity = pev->velocity * 0.5; - } -} - - -void CGrenade::BounceTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - - // Grenades to tend to get "stuck" on sloped surfaces due to the HL physics - // system, so move it away from whatever we're colliding with. - - // Get the surface normal. - - - - Vector theVelocityDirection; - VectorCopy(pev->velocity, theVelocityDirection); - VectorNormalize(theVelocityDirection); - - Vector theTraceStart; - Vector theTraceEnd; - - VectorMA(pev->origin, -10, theVelocityDirection, theTraceStart); - VectorMA(pev->origin, 10, theVelocityDirection, theTraceEnd); - - TraceResult tr; - UTIL_TraceLine(theTraceStart, theTraceEnd, dont_ignore_monsters, dont_ignore_glass, ENT(pev), &tr); - - if (tr.flFraction < 1) // Should always be the case. - { - VectorMA(pev->origin, 2, tr.vecPlaneNormal, pev->origin); - UTIL_SetOrigin(pev, pev->origin); - } - - // only do damage if we're moving fairly fast - if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100) - { - entvars_t *pevOwner = VARS( pev->owner ); - if (pevOwner) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, this->m_damageType); - ApplyMultiDamage( pev, pevOwner); - } - m_flNextAttack = gpGlobals->time + 1.0; // debounce - } - - Vector vecTestVelocity; - // pev->avelocity = Vector (300, 300, 300); - - float theDamageModifier; - int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier); - int theDamage = this->pev->dmg*theDamageModifier; - - // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical - // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. - // trimming the Z velocity a bit seems to help quite a bit. - vecTestVelocity = pev->velocity; - vecTestVelocity.z *= 0.45; - - if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 ) - { - //ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() ); - - // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. - // go ahead and emit the danger sound. - - // register a radius louder than the explosion, so we make sure everyone gets out of the way - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, theDamage / 0.4, 0.3 ); - m_fRegisteredSound = TRUE; - } - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.8; - - pev->sequence = 0;//RANDOM_LONG( 1, 1 ); - } - else - { - // play bounce sound - BounceSound(); - } - pev->framerate = pev->velocity.Length() / 200.0; - if (pev->framerate > 1.0) - pev->framerate = 1; - else if (pev->framerate < 0.5) - pev->framerate = 0; - - pev->velocity = pev->velocity * 0.8; - -} - - - -void CGrenade::SlideTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector (300, 300, 300); - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - - if (pev->velocity.x != 0 || pev->velocity.y != 0) - { - // maintain sliding sound - } - } - else - { - BounceSound(); - } -} - -void CGrenade :: BounceSound( void ) -{ - // Play different sounds for contact or timed grenade - if(this->m_pfnTouch == static_cast (&CGrenade::ExplosiveBounceTouch)) - { - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound1, 0.25, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound2, 0.25, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, kGrenadeBounceSound3, 0.25, ATTN_NORM); break; - } - } - else - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, kGRHitSound, 0.5, ATTN_NORM); - } - -} - -void CGrenade :: TumbleThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->dmgtime - 1 < gpGlobals->time) - { - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); - } - - if (pev->dmgtime <= gpGlobals->time) - { - SetThink( &CGrenade::Detonate ); - } - if (pev->waterlevel != 0) - { - pev->velocity = pev->velocity * 0.5; - pev->framerate = 0.2; - } -} - - -void CGrenade:: Spawn( void ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->classname = MAKE_STRING( "grenade" ); - - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/grenade.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - m_fRegisteredSound = FALSE; - m_damageType = NS_DMG_BLAST; -} - - -CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - // contact grenades arc lower - pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it. - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - - // make monsters afaid of it while in the air - pGrenade->SetThink( &CGrenade::DangerSoundThink ); - pGrenade->pev->nextthink = gpGlobals->time; - - // Tumble in air - pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); - - // Explode on contact - pGrenade->SetTouch( &CGrenade::ExplodeTouch ); - - pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade; - - return pGrenade; -} - -CGrenade* CGrenade::ShootExplosiveTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, int inDamageType) -{ - CGrenade *pGrenade = CGrenade::ShootTimed(pevOwner, vecStart, vecVelocity, time); - pGrenade->SetDamageType(inDamageType); - pGrenade->SetTouch(&CGrenade::ExplosiveBounceTouch); - return pGrenade; -} - - -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - - pGrenade->SetTouch( &CGrenade::BounceTouch ); // Bounce if touched - -#ifdef DEBUG - if(ns_cvar_float(&avh_bulletcam)) - { - SET_VIEW(ENT(pevOwner), ENT(pGrenade->pev)); - } -#endif - - // Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate - // will insert a DANGER sound into the world sound list and delay detonation for one second so that - // the grenade explodes after the exact amount of time specified in the call to ShootTimed(). - - pGrenade->pev->dmgtime = gpGlobals->time + time; - pGrenade->SetThink( &CGrenade::TumbleThink ); - pGrenade->pev->nextthink = gpGlobals->time + 0.1; - if (time < 0.1) - { - pGrenade->pev->nextthink = gpGlobals->time; - pGrenade->pev->velocity = Vector( 0, 0, 0 ); - } - - pGrenade->pev->sequence = 0;//RANDOM_LONG( 3, 6 ); - pGrenade->pev->framerate = 1.0; - - // Tumble through the air - pGrenade->pev->avelocity.x = RANDOM_LONG(-800, -300); - - // Also explode on contact - //pGrenade->SetTouch( ExplodeTouch ); - - pGrenade->pev->gravity = 0.5; - pGrenade->pev->friction = 0.8; - - SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl"); - - return pGrenade; -} - - -CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->pev->movetype = MOVETYPE_BOUNCE; - pGrenade->pev->classname = MAKE_STRING( "grenade" ); - - pGrenade->pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model - - UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pGrenade->pev->dmg = 200; - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = g_vecZero; - pGrenade->pev->owner = ENT(pevOwner); - - // Detonate in "time" seconds - pGrenade->SetThink( &CGrenade::SUB_DoNothing ); - pGrenade->SetUse( &CGrenade::DetonateUse ); - pGrenade->SetTouch( &CGrenade::SlideTouch ); - pGrenade->pev->spawnflags = SF_DETONATE; - - pGrenade->pev->friction = 0.9; - - return pGrenade; -} - - - -void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) -{ - edict_t *pentFind; - edict_t *pentOwner; - - if ( !pevOwner ) - return; - - CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner ); - - pentOwner = pOwner->edict(); - - pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "grenade" ); - while ( !FNullEnt( pentFind ) ) - { - CBaseEntity *pEnt = Instance( pentFind ); - if ( pEnt ) - { - if ( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner ) - { - if ( code == SATCHEL_DETONATE ) - pEnt->Use( pOwner, pOwner, USE_ON, 0 ); - else // SATCHEL_RELEASE - pEnt->pev->owner = NULL; - } - } - pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" ); - } -} - -//======================end grenade - diff --git a/main/source/dlls/globals.cpp b/main/source/dlls/globals.cpp index b5c734b5..293ff16a 100644 --- a/main/source/dlls/globals.cpp +++ b/main/source/dlls/globals.cpp @@ -1,39 +1,39 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== globals.cpp ======================================================== - - DLL-wide global variable definitions. - They're all defined here, for convenient centralization. - Source files that need them should "extern ..." declare each - variable, to better document what globals they care about. - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "soundent.h" - -DLL_GLOBAL ULONG g_ulFrameCount; -DLL_GLOBAL ULONG g_ulModelIndexEyes; -DLL_GLOBAL ULONG g_ulModelIndexPlayer; -DLL_GLOBAL Vector g_vecAttackDir; -DLL_GLOBAL int g_iSkillLevel; -DLL_GLOBAL int gDisplayTitle; -DLL_GLOBAL BOOL g_fGameOver; -DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); -DLL_GLOBAL int g_Language; +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== globals.cpp ======================================================== + + DLL-wide global variable definitions. + They're all defined here, for convenient centralization. + Source files that need them should "extern ..." declare each + variable, to better document what globals they care about. + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "soundent.h" + +DLL_GLOBAL ULONG g_ulFrameCount; +DLL_GLOBAL ULONG g_ulModelIndexEyes; +DLL_GLOBAL ULONG g_ulModelIndexPlayer; +DLL_GLOBAL Vector g_vecAttackDir; +DLL_GLOBAL int g_iSkillLevel; +DLL_GLOBAL int gDisplayTitle; +DLL_GLOBAL BOOL g_fGameOver; +DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); +DLL_GLOBAL int g_Language; diff --git a/main/source/dlls/glock.cpp b/main/source/dlls/glock.cpp index ae2485b1..1e891f0a 100644 --- a/main/source/dlls/glock.cpp +++ b/main/source/dlls/glock.cpp @@ -1,325 +1,325 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -enum glock_e { - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -class CGlock : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 2; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); - BOOL Deploy( void ); - void Reload( void ); - void WeaponIdle( void ); - -private: - int m_iShell; - - - unsigned short m_usFireGlock1; - unsigned short m_usFireGlock2; -}; -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); - - -void CGlock::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_GLOCK; - SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); - - m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGlock::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmhandgun.mdl"); - PRECACHE_MODEL("models/w_9mmhandgun.mdl"); - PRECACHE_MODEL("models/p_9mmhandgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - PRECACHE_SOUND("items/9mmclip2.wav"); - - PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun - - m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); - m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); -} - -int CGlock::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = GLOCK_MAX_CLIP; - p->iSlot = 1; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_GLOCK; - p->iWeight = GLOCK_WEIGHT; - - return 1; -} - -BOOL CGlock::Deploy( ) -{ - // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded" ); -} - -void CGlock::SecondaryAttack( void ) -{ - GlockFire( 0.1, 0.2, FALSE ); -} - -void CGlock::PrimaryAttack( void ) -{ - GlockFire( 0.01, 0.3, TRUE ); -} - -void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) -{ - if (m_iClip <= 0) - { - if (m_fFireOnEmpty) - { - PlayEmptySound(); - m_flNextPrimaryAttack = gpGlobals->time + 0.2; - } - - return; - } - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - -#if defined ( OLD_WEAPONS ) - if (m_iClip != 0) - SendWeaponAnim( GLOCK_SHOOT ); - else - SendWeaponAnim( GLOCK_SHOOT_EMPTY ); -#endif - - if ( fUseAutoAim ) - { - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock1, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - } - else - { - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#if defined ( OLD_WEAPONS ) - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); -#endif - - // silenced - if (pev->body == 1) - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; -#if defined ( OLD_WEAPONS ) - switch(RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); - break; - } -#endif - } - else - { - // non-silenced - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; -#if defined ( OLD_WEAPONS ) - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); -#endif - } - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming; - - if ( fUseAutoAim ) - { - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - } - else - { - vecAiming = gpGlobals->v_forward; - } - - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime; - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - -#if defined ( OLD_WEAPONS ) - m_pPlayer->pev->punchangle.x -= 2; -#endif -} - - -void CGlock::Reload( void ) -{ - int iResult; - - if (m_iClip == 0) - iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); - else - iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - - if (iResult) - { - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - } -} - - - -void CGlock::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if (m_flTimeWeaponIdle > gpGlobals->time) - return; - - // only idle if the slid isn't back - if (m_iClip != 0) - { - int iAnim; - float flRand = RANDOM_FLOAT(0, 1); - if (flRand <= 0.3 + 0 * 0.75) - { - iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16; - } - else if (flRand <= 0.6 + 0 * 0.875) - { - iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0; - } - else - { - iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; - } - SendWeaponAnim( iAnim ); - } -} - - - - - - - - -class CGlockAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); - - - - - - - - - - - - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + +enum glock_e { + GLOCK_IDLE1 = 0, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD, + GLOCK_RELOAD_NOT_EMPTY, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_ADD_SILENCER +}; + +class CGlock : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 2; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); + BOOL Deploy( void ); + void Reload( void ); + void WeaponIdle( void ); + +private: + int m_iShell; + + + unsigned short m_usFireGlock1; + unsigned short m_usFireGlock2; +}; +LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); +LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); + + +void CGlock::Spawn( ) +{ + pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names + Precache( ); + m_iId = WEAPON_GLOCK; + SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); + + m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CGlock::Precache( void ) +{ + PRECACHE_MODEL("models/v_9mmhandgun.mdl"); + PRECACHE_MODEL("models/w_9mmhandgun.mdl"); + PRECACHE_MODEL("models/p_9mmhandgun.mdl"); + + m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell + + PRECACHE_SOUND("items/9mmclip1.wav"); + PRECACHE_SOUND("items/9mmclip2.wav"); + + PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun + + m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); + m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); +} + +int CGlock::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "9mm"; + p->iMaxAmmo1 = _9MM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = GLOCK_MAX_CLIP; + p->iSlot = 1; + p->iPosition = 0; + p->iFlags = 0; + p->iId = m_iId = WEAPON_GLOCK; + p->iWeight = GLOCK_WEIGHT; + + return 1; +} + +BOOL CGlock::Deploy( ) +{ + // pev->body = 1; + return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded" ); +} + +void CGlock::SecondaryAttack( void ) +{ + GlockFire( 0.1, 0.2, FALSE ); +} + +void CGlock::PrimaryAttack( void ) +{ + GlockFire( 0.01, 0.3, TRUE ); +} + +void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) +{ + if (m_iClip <= 0) + { + if (m_fFireOnEmpty) + { + PlayEmptySound(); + m_flNextPrimaryAttack = gpGlobals->time + 0.2; + } + + return; + } + + m_iClip--; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + +#if defined ( OLD_WEAPONS ) + if (m_iClip != 0) + SendWeaponAnim( GLOCK_SHOOT ); + else + SendWeaponAnim( GLOCK_SHOOT_EMPTY ); +#endif + + if ( fUseAutoAim ) + { + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock1, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); + } + else + { + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); + } + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + +#if defined ( OLD_WEAPONS ) + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + + Vector vecShellVelocity = m_pPlayer->pev->velocity + + gpGlobals->v_right * RANDOM_FLOAT(50,70) + + gpGlobals->v_up * RANDOM_FLOAT(100,150) + + gpGlobals->v_forward * 25; + EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); +#endif + + // silenced + if (pev->body == 1) + { + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; +#if defined ( OLD_WEAPONS ) + switch(RANDOM_LONG(0,1)) + { + case 0: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); + break; + case 1: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); + break; + } +#endif + } + else + { + // non-silenced + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; +#if defined ( OLD_WEAPONS ) + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); +#endif + } + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming; + + if ( fUseAutoAim ) + { + vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + else + { + vecAiming = gpGlobals->v_forward; + } + + m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime; + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + +#if defined ( OLD_WEAPONS ) + m_pPlayer->pev->punchangle.x -= 2; +#endif +} + + +void CGlock::Reload( void ) +{ + int iResult; + + if (m_iClip == 0) + iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); + else + iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + + if (iResult) + { + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + } +} + + + +void CGlock::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + if (m_flTimeWeaponIdle > gpGlobals->time) + return; + + // only idle if the slid isn't back + if (m_iClip != 0) + { + int iAnim; + float flRand = RANDOM_FLOAT(0, 1); + if (flRand <= 0.3 + 0 * 0.75) + { + iAnim = GLOCK_IDLE3; + m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16; + } + else if (flRand <= 0.6 + 0 * 0.875) + { + iAnim = GLOCK_IDLE1; + m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0; + } + else + { + iAnim = GLOCK_IDLE2; + m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; + } + SendWeaponAnim( iAnim ); + } +} + + + + + + + + +class CGlockAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_9mmclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); +LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); + + + + + + + + + + + + + + + diff --git a/main/source/dlls/gman.cpp b/main/source/dlls/gman.cpp index a45d6a4a..6d3569a6 100644 --- a/main/source/dlls/gman.cpp +++ b/main/source/dlls/gman.cpp @@ -1,237 +1,237 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// GMan - misunderstood servant of the people -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "weapons.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CGMan : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - - EHANDLE m_hPlayer; - EHANDLE m_hTalkTarget; - float m_flTalkTime; -}; -LINK_ENTITY_TO_CLASS( monster_gman, CGMan ); - - -TYPEDESCRIPTION CGMan::m_SaveData[] = -{ - DEFINE_FIELD( CGMan, m_hTalkTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CGMan, m_flTalkTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CGMan, CBaseMonster ); - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGMan :: Classify ( void ) -{ - return CLASS_NONE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGMan :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGMan :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGMan :: ISoundMask ( void ) -{ - return NULL; -} - -//========================================================= -// Spawn -//========================================================= -void CGMan :: Spawn() -{ - Precache(); - - SET_MODEL( ENT(pev), "models/gman.mdl" ); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = DONT_BLEED; - pev->health = 100; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGMan :: Precache() -{ - PRECACHE_MODEL( "models/gman.mdl" ); -} - - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - -void CGMan :: StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_WAIT: - if (m_hPlayer == NULL) - { - m_hPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - } - break; - } - CBaseMonster::StartTask( pTask ); -} - -void CGMan :: RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_WAIT: - // look at who I'm talking to - if (m_flTalkTime > gpGlobals->time && m_hTalkTarget != NULL) - { - float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } - // look at player, but only if playing a "safe" idle animation - else if (m_hPlayer != NULL && pev->sequence == 0) - { - float yaw = VecToYaw(m_hPlayer->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } - else - { - SetBoneController( 0, 0 ); - } - CBaseMonster::RunTask( pTask ); - break; - default: - SetBoneController( 0, 0 ); - CBaseMonster::RunTask( pTask ); - break; - } -} - - -//========================================================= -// Override all damage -//========================================================= -int CGMan :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->health = pev->max_health / 2; // always trigger the 50% damage aitrigger - - if ( flDamage > 0 ) - { - SetConditions(bits_COND_LIGHT_DAMAGE); - } - - if ( flDamage >= 20 ) - { - SetConditions(bits_COND_HEAVY_DAMAGE); - } - return TRUE; -} - - -void CGMan::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - - -void CGMan::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - CBaseMonster::PlayScriptedSentence( pszSentence, duration, volume, attenuation, bConcurrent, pListener ); - - m_flTalkTime = gpGlobals->time + duration; - m_hTalkTarget = pListener; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// GMan - misunderstood servant of the people +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "weapons.h" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= + +class CGMan : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + int ISoundMask ( void ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void StartTask( Task_t *pTask ); + void RunTask( Task_t *pTask ); + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + + void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); + + EHANDLE m_hPlayer; + EHANDLE m_hTalkTarget; + float m_flTalkTime; +}; +LINK_ENTITY_TO_CLASS( monster_gman, CGMan ); + + +TYPEDESCRIPTION CGMan::m_SaveData[] = +{ + DEFINE_FIELD( CGMan, m_hTalkTarget, FIELD_EHANDLE ), + DEFINE_FIELD( CGMan, m_flTalkTime, FIELD_TIME ), +}; +IMPLEMENT_SAVERESTORE( CGMan, CBaseMonster ); + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CGMan :: Classify ( void ) +{ + return CLASS_NONE; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CGMan :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + default: + ys = 90; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CGMan :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case 0: + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// ISoundMask - generic monster can't hear. +//========================================================= +int CGMan :: ISoundMask ( void ) +{ + return NULL; +} + +//========================================================= +// Spawn +//========================================================= +void CGMan :: Spawn() +{ + Precache(); + + SET_MODEL( ENT(pev), "models/gman.mdl" ); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = DONT_BLEED; + pev->health = 100; + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CGMan :: Precache() +{ + PRECACHE_MODEL( "models/gman.mdl" ); +} + + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + + +void CGMan :: StartTask( Task_t *pTask ) +{ + switch( pTask->iTask ) + { + case TASK_WAIT: + if (m_hPlayer == NULL) + { + m_hPlayer = UTIL_FindEntityByClassname( NULL, "player" ); + } + break; + } + CBaseMonster::StartTask( pTask ); +} + +void CGMan :: RunTask( Task_t *pTask ) +{ + switch( pTask->iTask ) + { + case TASK_WAIT: + // look at who I'm talking to + if (m_flTalkTime > gpGlobals->time && m_hTalkTarget != NULL) + { + float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; + + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + + // turn towards vector + SetBoneController( 0, yaw ); + } + // look at player, but only if playing a "safe" idle animation + else if (m_hPlayer != NULL && pev->sequence == 0) + { + float yaw = VecToYaw(m_hPlayer->pev->origin - pev->origin) - pev->angles.y; + + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + + // turn towards vector + SetBoneController( 0, yaw ); + } + else + { + SetBoneController( 0, 0 ); + } + CBaseMonster::RunTask( pTask ); + break; + default: + SetBoneController( 0, 0 ); + CBaseMonster::RunTask( pTask ); + break; + } +} + + +//========================================================= +// Override all damage +//========================================================= +int CGMan :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + pev->health = pev->max_health / 2; // always trigger the 50% damage aitrigger + + if ( flDamage > 0 ) + { + SetConditions(bits_COND_LIGHT_DAMAGE); + } + + if ( flDamage >= 20 ) + { + SetConditions(bits_COND_HEAVY_DAMAGE); + } + return TRUE; +} + + +void CGMan::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + UTIL_Ricochet( ptr->vecEndPos, 1.0 ); + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); +} + + +void CGMan::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) +{ + CBaseMonster::PlayScriptedSentence( pszSentence, duration, volume, attenuation, bConcurrent, pListener ); + + m_flTalkTime = gpGlobals->time + duration; + m_hTalkTarget = pListener; +} diff --git a/main/source/dlls/h_ai.cpp b/main/source/dlls/h_ai.cpp index e64ad3f0..94ef2a74 100644 --- a/main/source/dlls/h_ai.cpp +++ b/main/source/dlls/h_ai.cpp @@ -1,200 +1,200 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - - h_ai.cpp - halflife specific ai code - -*/ - - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "game.h" - -#define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a monster looking for lateral cover -#define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a monster looking for lateral cover - -//float flRandom = RANDOM_FLOAT(0,1); - -DLL_GLOBAL BOOL g_fDrawLines = FALSE; - -//========================================================= -// -// AI UTILITY FUNCTIONS -// -// !!!UNDONE - move CBaseMonster functions to monsters.cpp -//========================================================= - -//========================================================= -// FBoxVisible - a more accurate ( and slower ) version -// of FVisible. -// -// !!!UNDONE - make this CBaseMonster? -//========================================================= -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize ) -{ - // don't look through water //OR SHOULD WE? Changed by Elven Thief - kills bug #728 - /* - if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3) - || (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0)) - return FALSE; - */ - TraceResult tr; - Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes' - for (int i = 0; i < 5; i++) - { - Vector vecTarget = pevTarget->origin; - vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize); - vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize); - vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize); - - UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr); - - if (tr.flFraction == 1.0) - { - vecTargetOrigin = vecTarget; - return TRUE;// line of sight is valid. - } - } - return FALSE;// Line of sight is not established -} - -// -// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2. -// returns g_vecZero if toss is not feasible. -// -Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj ) -{ - TraceResult tr; - Vector vecMidPoint;// halfway point between Spot1 and Spot2 - Vector vecApex;// highest point - Vector vecScale; - Vector vecGrenadeVel; - Vector vecTemp; - float flGravity = g_psv_gravity->value * flGravityAdj; - - if (vecSpot2.z - vecSpot1.z > 500) - { - // to high, fail - return g_vecZero; - } - - UTIL_MakeVectors (pev->angles); - - // toss a little bit to the left or right, not right down on the enemy's bean (head). - vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); - vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); - - // calculate the midpoint and apex of the 'triangle' - // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT - - // How much time does it take to get there? - - // get a rough idea of how high it can be thrown - vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr); - vecMidPoint = tr.vecEndPos; - // (subtract 15 so the grenade doesn't hit the ceiling) - vecMidPoint.z -= 15; - - if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z) - { - // to not enough space, fail - return g_vecZero; - } - - // How high should the grenade travel to reach the apex - float distance1 = (vecMidPoint.z - vecSpot1.z); - float distance2 = (vecMidPoint.z - vecSpot2.z); - - // How long will it take for the grenade to travel this distance - float time1 = sqrt( distance1 / (0.5 * flGravity) ); - float time2 = sqrt( distance2 / (0.5 * flGravity) ); - - if (time1 < 0.1) - { - // too close - return g_vecZero; - } - - // how hard to throw sideways to get there in time. - vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2); - // how hard upwards to reach the apex at the right time. - vecGrenadeVel.z = flGravity * time1; - - // find the apex - vecApex = vecSpot1 + vecGrenadeVel * time1; - vecApex.z = vecMidPoint.z; - - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - // UNDONE: either ignore monsters or change it to not care if we hit our enemy - UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - return vecGrenadeVel; -} - - -// -// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2. -// returns g_vecZero if throw is not feasible. -// -Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj ) -{ - float flGravity = g_psv_gravity->value * flGravityAdj; - - Vector vecGrenadeVel = (vecSpot2 - vecSpot1); - - // throw at a constant time - float time = vecGrenadeVel.Length( ) / flSpeed; - vecGrenadeVel = vecGrenadeVel * (1.0 / time); - - // adjust upward toss to compensate for gravity loss - vecGrenadeVel.z += flGravity * time * 0.5; - - Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5); - - TraceResult tr; - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - return vecGrenadeVel; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + + h_ai.cpp - halflife specific ai code + +*/ + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "game.h" + +#define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a monster looking for lateral cover +#define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a monster looking for lateral cover + +//float flRandom = RANDOM_FLOAT(0,1); + +DLL_GLOBAL BOOL g_fDrawLines = FALSE; + +//========================================================= +// +// AI UTILITY FUNCTIONS +// +// !!!UNDONE - move CBaseMonster functions to monsters.cpp +//========================================================= + +//========================================================= +// FBoxVisible - a more accurate ( and slower ) version +// of FVisible. +// +// !!!UNDONE - make this CBaseMonster? +//========================================================= +BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize ) +{ + // don't look through water //OR SHOULD WE? Changed by Elven Thief - kills bug #728 + /* + if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3) + || (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0)) + return FALSE; + */ + TraceResult tr; + Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes' + for (int i = 0; i < 5; i++) + { + Vector vecTarget = pevTarget->origin; + vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize); + vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize); + vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize); + + UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr); + + if (tr.flFraction == 1.0) + { + vecTargetOrigin = vecTarget; + return TRUE;// line of sight is valid. + } + } + return FALSE;// Line of sight is not established +} + +// +// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2. +// returns g_vecZero if toss is not feasible. +// +Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj ) +{ + TraceResult tr; + Vector vecMidPoint;// halfway point between Spot1 and Spot2 + Vector vecApex;// highest point + Vector vecScale; + Vector vecGrenadeVel; + Vector vecTemp; + float flGravity = g_psv_gravity->value * flGravityAdj; + + if (vecSpot2.z - vecSpot1.z > 500) + { + // to high, fail + return g_vecZero; + } + + UTIL_MakeVectors (pev->angles); + + // toss a little bit to the left or right, not right down on the enemy's bean (head). + vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); + vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); + + // calculate the midpoint and apex of the 'triangle' + // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT + + // How much time does it take to get there? + + // get a rough idea of how high it can be thrown + vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; + UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr); + vecMidPoint = tr.vecEndPos; + // (subtract 15 so the grenade doesn't hit the ceiling) + vecMidPoint.z -= 15; + + if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z) + { + // to not enough space, fail + return g_vecZero; + } + + // How high should the grenade travel to reach the apex + float distance1 = (vecMidPoint.z - vecSpot1.z); + float distance2 = (vecMidPoint.z - vecSpot2.z); + + // How long will it take for the grenade to travel this distance + float time1 = sqrt( distance1 / (0.5 * flGravity) ); + float time2 = sqrt( distance2 / (0.5 * flGravity) ); + + if (time1 < 0.1) + { + // too close + return g_vecZero; + } + + // how hard to throw sideways to get there in time. + vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2); + // how hard upwards to reach the apex at the right time. + vecGrenadeVel.z = flGravity * time1; + + // find the apex + vecApex = vecSpot1 + vecGrenadeVel * time1; + vecApex.z = vecMidPoint.z; + + UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + // fail! + return g_vecZero; + } + + // UNDONE: either ignore monsters or change it to not care if we hit our enemy + UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + // fail! + return g_vecZero; + } + + return vecGrenadeVel; +} + + +// +// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2. +// returns g_vecZero if throw is not feasible. +// +Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj ) +{ + float flGravity = g_psv_gravity->value * flGravityAdj; + + Vector vecGrenadeVel = (vecSpot2 - vecSpot1); + + // throw at a constant time + float time = vecGrenadeVel.Length( ) / flSpeed; + vecGrenadeVel = vecGrenadeVel * (1.0 / time); + + // adjust upward toss to compensate for gravity loss + vecGrenadeVel.z += flGravity * time * 0.5; + + Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; + vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5); + + TraceResult tr; + UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + // fail! + return g_vecZero; + } + + UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); + if (tr.flFraction != 1.0) + { + // fail! + return g_vecZero; + } + + return vecGrenadeVel; +} + + diff --git a/main/source/dlls/h_battery.cpp b/main/source/dlls/h_battery.cpp index 09ca89da..f4542347 100644 --- a/main/source/dlls/h_battery.cpp +++ b/main/source/dlls/h_battery.cpp @@ -1,200 +1,200 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== h_battery.cpp ======================================================== - - battery-related code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "skill.h" -#include "gamerules.h" - -class CRecharge : public CBaseToggle -{ -public: - void Spawn( ); - void Precache( void ); - void EXPORT Off(void); - void EXPORT Recharge(void); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flNextCharge; - int m_iReactivate ; // DeathMatch Delay until reactvated - int m_iJuice; - int m_iOn; // 0 = off, 1 = startup, 2 = going - float m_flSoundTime; -}; - -TYPEDESCRIPTION CRecharge::m_SaveData[] = -{ - DEFINE_FIELD( CRecharge, m_flNextCharge, FIELD_TIME ), - DEFINE_FIELD( CRecharge, m_iReactivate, FIELD_INTEGER), - DEFINE_FIELD( CRecharge, m_iJuice, FIELD_INTEGER), - DEFINE_FIELD( CRecharge, m_iOn, FIELD_INTEGER), - DEFINE_FIELD( CRecharge, m_flSoundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CRecharge, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(func_recharge, CRecharge); - - -void CRecharge::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "dmdelay")) - { - m_iReactivate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CRecharge::Spawn() -{ - Precache( ); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - m_iJuice = gSkillData.suitchargerCapacity; - pev->frame = 0; -} - -void CRecharge::Precache() -{ - PRECACHE_SOUND("items/suitcharge1.wav"); - PRECACHE_SOUND("items/suitchargeno1.wav"); - PRECACHE_SOUND("items/suitchargeok1.wav"); -} - - -void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // if it's not a player, ignore - if (!FClassnameIs(pActivator->pev, "player")) - return; - - // if there is no juice left, turn it off - if (m_iJuice <= 0) - { - pev->frame = 1; - Off(); - } - - // if the player doesn't have the suit, or there is no juice left, make the deny noise - if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<time) - { - m_flSoundTime = gpGlobals->time + 0.62; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM ); - } - return; - } - - pev->nextthink = pev->ltime + 0.25; - SetThink(&CRecharge::Off); - - // Time to recharge yet? - - if (m_flNextCharge >= gpGlobals->time) - return; - - // Make sure that we have a caller - if (!pActivator) - return; - - m_hActivator = pActivator; - - //only recharge the player - - if (!m_hActivator->IsPlayer() ) - return; - - // Play the on sound or the looping charging sound - if (!m_iOn) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeok1.wav", 0.85, ATTN_NORM ); - m_flSoundTime = 0.56 + gpGlobals->time; - } - if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time)) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM ); - } - - - // charge the player - if (m_hActivator->pev->armorvalue < 100) - { - m_iJuice--; - m_hActivator->pev->armorvalue += 1; - - if (m_hActivator->pev->armorvalue > 100) - m_hActivator->pev->armorvalue = 100; - } - - // govern the rate of charge - m_flNextCharge = gpGlobals->time + 0.1; -} - -void CRecharge::Recharge(void) -{ - m_iJuice = gSkillData.suitchargerCapacity; - pev->frame = 0; - SetThink( &CRecharge::SUB_DoNothing ); -} - -void CRecharge::Off(void) -{ - // Stop looping sound. - if (m_iOn > 1) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" ); - - m_iOn = 0; - - if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) - { - pev->nextthink = pev->ltime + m_iReactivate; - SetThink(&CRecharge::Recharge); - } - else - SetThink( &CRecharge::SUB_DoNothing ); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== h_battery.cpp ======================================================== + + battery-related code + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "skill.h" +#include "gamerules.h" + +class CRecharge : public CBaseToggle +{ +public: + void Spawn( ); + void Precache( void ); + void EXPORT Off(void); + void EXPORT Recharge(void); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + float m_flNextCharge; + int m_iReactivate ; // DeathMatch Delay until reactvated + int m_iJuice; + int m_iOn; // 0 = off, 1 = startup, 2 = going + float m_flSoundTime; +}; + +TYPEDESCRIPTION CRecharge::m_SaveData[] = +{ + DEFINE_FIELD( CRecharge, m_flNextCharge, FIELD_TIME ), + DEFINE_FIELD( CRecharge, m_iReactivate, FIELD_INTEGER), + DEFINE_FIELD( CRecharge, m_iJuice, FIELD_INTEGER), + DEFINE_FIELD( CRecharge, m_iOn, FIELD_INTEGER), + DEFINE_FIELD( CRecharge, m_flSoundTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CRecharge, CBaseEntity ); + +LINK_ENTITY_TO_CLASS(func_recharge, CRecharge); + + +void CRecharge::KeyValue( KeyValueData *pkvd ) +{ + if ( FStrEq(pkvd->szKeyName, "style") || + FStrEq(pkvd->szKeyName, "height") || + FStrEq(pkvd->szKeyName, "value1") || + FStrEq(pkvd->szKeyName, "value2") || + FStrEq(pkvd->szKeyName, "value3")) + { + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "dmdelay")) + { + m_iReactivate = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +void CRecharge::Spawn() +{ + Precache( ); + + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + + UTIL_SetOrigin(pev, pev->origin); // set size and link into world + UTIL_SetSize(pev, pev->mins, pev->maxs); + SET_MODEL(ENT(pev), STRING(pev->model) ); + m_iJuice = gSkillData.suitchargerCapacity; + pev->frame = 0; +} + +void CRecharge::Precache() +{ + PRECACHE_SOUND("items/suitcharge1.wav"); + PRECACHE_SOUND("items/suitchargeno1.wav"); + PRECACHE_SOUND("items/suitchargeok1.wav"); +} + + +void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // if it's not a player, ignore + if (!FClassnameIs(pActivator->pev, "player")) + return; + + // if there is no juice left, turn it off + if (m_iJuice <= 0) + { + pev->frame = 1; + Off(); + } + + // if the player doesn't have the suit, or there is no juice left, make the deny noise + if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<time) + { + m_flSoundTime = gpGlobals->time + 0.62; + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM ); + } + return; + } + + pev->nextthink = pev->ltime + 0.25; + SetThink(&CRecharge::Off); + + // Time to recharge yet? + + if (m_flNextCharge >= gpGlobals->time) + return; + + // Make sure that we have a caller + if (!pActivator) + return; + + m_hActivator = pActivator; + + //only recharge the player + + if (!m_hActivator->IsPlayer() ) + return; + + // Play the on sound or the looping charging sound + if (!m_iOn) + { + m_iOn++; + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeok1.wav", 0.85, ATTN_NORM ); + m_flSoundTime = 0.56 + gpGlobals->time; + } + if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time)) + { + m_iOn++; + EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM ); + } + + + // charge the player + if (m_hActivator->pev->armorvalue < 100) + { + m_iJuice--; + m_hActivator->pev->armorvalue += 1; + + if (m_hActivator->pev->armorvalue > 100) + m_hActivator->pev->armorvalue = 100; + } + + // govern the rate of charge + m_flNextCharge = gpGlobals->time + 0.1; +} + +void CRecharge::Recharge(void) +{ + m_iJuice = gSkillData.suitchargerCapacity; + pev->frame = 0; + SetThink( &CRecharge::SUB_DoNothing ); +} + +void CRecharge::Off(void) +{ + // Stop looping sound. + if (m_iOn > 1) + STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" ); + + m_iOn = 0; + + if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) + { + pev->nextthink = pev->ltime + m_iReactivate; + SetThink(&CRecharge::Recharge); + } + else + SetThink( &CRecharge::SUB_DoNothing ); } \ No newline at end of file diff --git a/main/source/dlls/h_cine.cpp b/main/source/dlls/h_cine.cpp index 798d8f75..2bf7a721 100644 --- a/main/source/dlls/h_cine.cpp +++ b/main/source/dlls/h_cine.cpp @@ -1,241 +1,241 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== h_cine.cpp ======================================================== - - The Halflife hard coded "scripted sequence". - - I'm pretty sure all this code is obsolete - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "decals.h" - - -class CLegacyCineMonster : public CBaseMonster -{ -public: - void CineSpawn( char *szModel ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CineThink( void ); - void Pain( void ); - void Die( void ); -}; - -class CCineScientist : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine-scientist.mdl"); } -}; -class CCine2Scientist : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine2-scientist.mdl"); } -}; -class CCinePanther : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine-panther.mdl"); } -}; - -class CCineBarney : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine-barney.mdl"); } -}; - -class CCine2HeavyWeapons : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine2_hvyweapons.mdl"); } -}; - -class CCine2Slave : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine2_slave.mdl"); } -}; - -class CCine3Scientist : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine3-scientist.mdl"); } -}; - -class CCine3Barney : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine3-barney.mdl"); } -}; - -// -// ********** Scientist SPAWN ********** -// - -LINK_ENTITY_TO_CLASS( monster_cine_scientist, CCineScientist ); -LINK_ENTITY_TO_CLASS( monster_cine_panther, CCinePanther ); -LINK_ENTITY_TO_CLASS( monster_cine_barney, CCineBarney ); -LINK_ENTITY_TO_CLASS( monster_cine2_scientist, CCine2Scientist ); -LINK_ENTITY_TO_CLASS( monster_cine2_hvyweapons, CCine2HeavyWeapons ); -LINK_ENTITY_TO_CLASS( monster_cine2_slave, CCine2Slave ); -LINK_ENTITY_TO_CLASS( monster_cine3_scientist, CCine3Scientist ); -LINK_ENTITY_TO_CLASS( monster_cine3_barney, CCine3Barney ); - -// -// ********** Scientist SPAWN ********** -// - -void CLegacyCineMonster :: CineSpawn( char *szModel ) -{ - PRECACHE_MODEL(szModel); - SET_MODEL(ENT(pev), szModel); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 64)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 1; - pev->yaw_speed = 10; - - // ugly alpha hack, can't set ints from the bsp. - pev->sequence = (int)pev->impulse; - ResetSequenceInfo( ); - pev->framerate = 0.0; - - m_bloodColor = BLOOD_COLOR_RED; - - // if no targetname, start now - if ( FStringNull(pev->targetname) ) - { - SetThink( &CLegacyCineMonster::CineThink ); - pev->nextthink += 1.0; - } -} - - -// -// CineStart -// -void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->animtime = 0; // reset the sequence - SetThink( &CLegacyCineMonster::CineThink ); - pev->nextthink = gpGlobals->time; -} - -// -// ********** Scientist DIE ********** -// -void CLegacyCineMonster :: Die( void ) -{ - SetThink( &CLegacyCineMonster::SUB_Remove ); -} - -// -// ********** Scientist PAIN ********** -// -void CLegacyCineMonster :: Pain( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pain3.wav", 1, ATTN_NORM); -} - -void CLegacyCineMonster :: CineThink( void ) -{ - // DBG_CheckMonsterData(pev); - - // Emit particles from origin (double check animator's placement of model) - // THIS is a test feature - //UTIL_ParticleEffect(pev->origin, g_vecZero, 255, 20); - - if (!pev->animtime) - ResetSequenceInfo( ); - - pev->nextthink = gpGlobals->time + 1.0; - - if (pev->spawnflags != 0 && m_fSequenceFinished) - { - Die(); - return; - } - - StudioFrameAdvance ( ); -} - -// -// cine_blood -// -// e3/prealpha only. -class CCineBlood : public CBaseEntity -{ -public: - void Spawn( void ); - void EXPORT BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT BloodGush ( void ); -}; - -LINK_ENTITY_TO_CLASS( cine_blood, CCineBlood ); - - -void CCineBlood :: BloodGush ( void ) -{ - Vector vecSplatDir; - TraceResult tr; - pev->nextthink = gpGlobals->time + 0.1; - - UTIL_MakeVectors(pev->angles); - if ( pev->health-- < 0 ) - REMOVE_ENTITY(ENT(pev)); -// CHANGE_METHOD ( ENT(pev), em_think, SUB_Remove ); - - if ( RANDOM_FLOAT ( 0 , 1 ) < 0.7 )// larger chance of globs - { - UTIL_BloodDrips( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 10 ); - } - else// slim chance of geyser - { - UTIL_BloodStream( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, RANDOM_LONG(50, 150) ); - } - - if ( RANDOM_FLOAT ( 0, 1 ) < 0.75 ) - {// decals the floor with blood. - vecSplatDir = Vector ( 0 , 0 , -1 ); - vecSplatDir = vecSplatDir + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_right) + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_forward);// randomize a bit - UTIL_TraceLine( pev->origin + Vector ( 0, 0 , 64) , pev->origin + vecSplatDir * 256, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction != 1.0 ) - { - // Decal with a bloodsplat - UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - } - } -} - -void CCineBlood :: BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CCineBlood::BloodGush ); - pev->nextthink = gpGlobals->time;// now! -} - -void CCineBlood :: Spawn ( void ) -{ - pev->solid = SOLID_NOT; - SetUse ( &CCineBlood::BloodStart ); - pev->health = 20;//hacked health to count iterations -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +/* + +===== h_cine.cpp ======================================================== + + The Halflife hard coded "scripted sequence". + + I'm pretty sure all this code is obsolete + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "decals.h" + + +class CLegacyCineMonster : public CBaseMonster +{ +public: + void CineSpawn( char *szModel ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT CineThink( void ); + void Pain( void ); + void Die( void ); +}; + +class CCineScientist : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine-scientist.mdl"); } +}; +class CCine2Scientist : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine2-scientist.mdl"); } +}; +class CCinePanther : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine-panther.mdl"); } +}; + +class CCineBarney : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine-barney.mdl"); } +}; + +class CCine2HeavyWeapons : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine2_hvyweapons.mdl"); } +}; + +class CCine2Slave : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine2_slave.mdl"); } +}; + +class CCine3Scientist : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine3-scientist.mdl"); } +}; + +class CCine3Barney : public CLegacyCineMonster +{ +public: + void Spawn( void ) { CineSpawn("models/cine3-barney.mdl"); } +}; + +// +// ********** Scientist SPAWN ********** +// + +LINK_ENTITY_TO_CLASS( monster_cine_scientist, CCineScientist ); +LINK_ENTITY_TO_CLASS( monster_cine_panther, CCinePanther ); +LINK_ENTITY_TO_CLASS( monster_cine_barney, CCineBarney ); +LINK_ENTITY_TO_CLASS( monster_cine2_scientist, CCine2Scientist ); +LINK_ENTITY_TO_CLASS( monster_cine2_hvyweapons, CCine2HeavyWeapons ); +LINK_ENTITY_TO_CLASS( monster_cine2_slave, CCine2Slave ); +LINK_ENTITY_TO_CLASS( monster_cine3_scientist, CCine3Scientist ); +LINK_ENTITY_TO_CLASS( monster_cine3_barney, CCine3Barney ); + +// +// ********** Scientist SPAWN ********** +// + +void CLegacyCineMonster :: CineSpawn( char *szModel ) +{ + PRECACHE_MODEL(szModel); + SET_MODEL(ENT(pev), szModel); + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 64)); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + pev->effects = 0; + pev->health = 1; + pev->yaw_speed = 10; + + // ugly alpha hack, can't set ints from the bsp. + pev->sequence = (int)pev->impulse; + ResetSequenceInfo( ); + pev->framerate = 0.0; + + m_bloodColor = BLOOD_COLOR_RED; + + // if no targetname, start now + if ( FStringNull(pev->targetname) ) + { + SetThink( &CLegacyCineMonster::CineThink ); + pev->nextthink += 1.0; + } +} + + +// +// CineStart +// +void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + pev->animtime = 0; // reset the sequence + SetThink( &CLegacyCineMonster::CineThink ); + pev->nextthink = gpGlobals->time; +} + +// +// ********** Scientist DIE ********** +// +void CLegacyCineMonster :: Die( void ) +{ + SetThink( &CLegacyCineMonster::SUB_Remove ); +} + +// +// ********** Scientist PAIN ********** +// +void CLegacyCineMonster :: Pain( void ) +{ + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pain3.wav", 1, ATTN_NORM); +} + +void CLegacyCineMonster :: CineThink( void ) +{ + // DBG_CheckMonsterData(pev); + + // Emit particles from origin (double check animator's placement of model) + // THIS is a test feature + //UTIL_ParticleEffect(pev->origin, g_vecZero, 255, 20); + + if (!pev->animtime) + ResetSequenceInfo( ); + + pev->nextthink = gpGlobals->time + 1.0; + + if (pev->spawnflags != 0 && m_fSequenceFinished) + { + Die(); + return; + } + + StudioFrameAdvance ( ); +} + +// +// cine_blood +// +// e3/prealpha only. +class CCineBlood : public CBaseEntity +{ +public: + void Spawn( void ); + void EXPORT BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT BloodGush ( void ); +}; + +LINK_ENTITY_TO_CLASS( cine_blood, CCineBlood ); + + +void CCineBlood :: BloodGush ( void ) +{ + Vector vecSplatDir; + TraceResult tr; + pev->nextthink = gpGlobals->time + 0.1; + + UTIL_MakeVectors(pev->angles); + if ( pev->health-- < 0 ) + REMOVE_ENTITY(ENT(pev)); +// CHANGE_METHOD ( ENT(pev), em_think, SUB_Remove ); + + if ( RANDOM_FLOAT ( 0 , 1 ) < 0.7 )// larger chance of globs + { + UTIL_BloodDrips( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 10 ); + } + else// slim chance of geyser + { + UTIL_BloodStream( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, RANDOM_LONG(50, 150) ); + } + + if ( RANDOM_FLOAT ( 0, 1 ) < 0.75 ) + {// decals the floor with blood. + vecSplatDir = Vector ( 0 , 0 , -1 ); + vecSplatDir = vecSplatDir + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_right) + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_forward);// randomize a bit + UTIL_TraceLine( pev->origin + Vector ( 0, 0 , 64) , pev->origin + vecSplatDir * 256, ignore_monsters, ENT(pev), &tr); + if ( tr.flFraction != 1.0 ) + { + // Decal with a bloodsplat + UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); + } + } +} + +void CCineBlood :: BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( &CCineBlood::BloodGush ); + pev->nextthink = gpGlobals->time;// now! +} + +void CCineBlood :: Spawn ( void ) +{ + pev->solid = SOLID_NOT; + SetUse ( &CCineBlood::BloodStart ); + pev->health = 20;//hacked health to count iterations +} + diff --git a/main/source/dlls/h_cycler.cpp b/main/source/dlls/h_cycler.cpp index d9c95b99..dd8f3d5e 100644 --- a/main/source/dlls/h_cycler.cpp +++ b/main/source/dlls/h_cycler.cpp @@ -1,471 +1,471 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== h_cycler.cpp ======================================================== - - The Halflife Cycler Monsters - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "weapons.h" -#include "player.h" - - -#define TEMP_FOR_SCREEN_SHOTS -#ifdef TEMP_FOR_SCREEN_SHOTS //=================================================== - -class CCycler : public CBaseMonster -{ -public: - void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_IMPULSE_USE); } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void Spawn( void ); - void Think( void ); - //void Pain( float flDamage ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // Don't treat as a live target - virtual BOOL IsAlive( void ) const { return FALSE; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_animate; -}; - -TYPEDESCRIPTION CCycler::m_SaveData[] = -{ - DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster ); - - -// -// we should get rid of all the other cyclers and replace them with this. -// -class CGenericCycler : public CCycler -{ -public: - void Spawn( void ) { GenericCyclerSpawn( (char *)STRING(pev->model), Vector(-16, -16, 0), Vector(16, 16, 72) ); } -}; -LINK_ENTITY_TO_CLASS( cycler, CGenericCycler ); - - - -// Probe droid imported for tech demo compatibility -// -// PROBE DROID -// -class CCyclerProbe : public CCycler -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe ); -void CCyclerProbe :: Spawn( void ) -{ - pev->origin = pev->origin + Vector ( 0, 0, 16 ); - GenericCyclerSpawn( "models/prdroid.mdl", Vector(-16,-16,-16), Vector(16,16,16)); -} - - - -// Cycler member functions - -void CCycler :: GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax) -{ - if (!szModel || !*szModel) - { - ALERT(at_error, "cycler at %.0f %.0f %0.f missing modelname", pev->origin.x, pev->origin.y, pev->origin.z ); - REMOVE_ENTITY(ENT(pev)); - return; - } - - pev->classname = MAKE_STRING("cycler"); - PRECACHE_MODEL( szModel ); - SET_MODEL(ENT(pev), szModel); - - CCycler::Spawn( ); - - UTIL_SetSize(pev, vecMin, vecMax); -} - - -void CCycler :: Spawn( ) -{ - InitBoneControllers(); - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_YES; - pev->effects = 0; - pev->health = 80000;// no cycler should die - pev->yaw_speed = 5; - pev->ideal_yaw = pev->angles.y; - ChangeYaw( 360 ); - - m_flFrameRate = 75; - m_flGroundSpeed = 0; - - pev->nextthink += 1.0; - - ResetSequenceInfo( ); - - if (pev->sequence != 0 || pev->frame != 0) - { - m_animate = 0; - pev->framerate = 0; - } - else - { - m_animate = 1; - } -} - - - - -// -// cycler think -// -void CCycler :: Think( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (m_animate) - { - StudioFrameAdvance ( ); - } - if (m_fSequenceFinished && !m_fSequenceLoops) - { - // ResetSequenceInfo(); - // hack to avoid reloading model every frame - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; - m_fSequenceFinished = FALSE; - m_flLastEventCheck = gpGlobals->time; - pev->frame = 0; - if (!m_animate) - pev->framerate = 0.0; // FIX: don't reset framerate - } -} - -// -// CyclerUse - starts a rotation trend -// -void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_animate = !m_animate; - if (m_animate) - pev->framerate = 1.0; - else - pev->framerate = 0.0; -} - -// -// CyclerPain , changes sequences when shot -// -//void CCycler :: Pain( float flDamage ) -int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (m_animate) - { - pev->sequence++; - - ResetSequenceInfo( ); - - if (m_flFrameRate == 0.0) - { - pev->sequence = 0; - ResetSequenceInfo( ); - } - pev->frame = 0; - } - else - { - pev->framerate = 1.0; - StudioFrameAdvance ( 0.1 ); - pev->framerate = 0; - ALERT( at_console, "sequence: %d, frame %.0f\n", pev->sequence, pev->frame ); - } - - return 0; -} - -#endif - - -class CCyclerSprite : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_DONT_SAVE | FCAP_IMPULSE_USE); } - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void Animate( float frames ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline int ShouldAnimate( void ) { return m_animate && m_maxFrame > 1.0; } - int m_animate; - float m_lastTime; - float m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite ); - -TYPEDESCRIPTION CCyclerSprite::m_SaveData[] = -{ - DEFINE_FIELD( CCyclerSprite, m_animate, FIELD_INTEGER ), - DEFINE_FIELD( CCyclerSprite, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CCyclerSprite, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity ); - - -void CCyclerSprite::Spawn( void ) -{ - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_YES; - pev->effects = 0; - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - m_animate = 1; - m_lastTime = gpGlobals->time; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; -} - - -void CCyclerSprite::Think( void ) -{ - if ( ShouldAnimate() ) - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - - -void CCyclerSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_animate = !m_animate; - ALERT( at_console, "Sprite: %s\n", STRING(pev->model) ); -} - - -int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( m_maxFrame > 1.0 ) - { - Animate( 1.0 ); - } - return 1; -} - -void CCyclerSprite::Animate( float frames ) -{ - pev->frame += frames; - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame, m_maxFrame ); -} - - - - - - - -class CWeaponCycler : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - int iItemSlot( void ) { return 1; } - int GetItemInfo(ItemInfo *p) {return 0; } - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - int m_iszModel; - int m_iModel; -}; -LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler ); - - -void CWeaponCycler::Spawn( ) -{ - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - m_iszModel = pev->model; - m_iModel = pev->modelindex; - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch( &CWeaponCycler::DefaultTouch ); -} - - - -BOOL CWeaponCycler::Deploy( ) -{ - m_pPlayer->pev->viewmodel = m_iszModel; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - SendWeaponAnim( 0 ); - m_iClip = 0; - return TRUE; -} - - -void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; -} - - -void CWeaponCycler::PrimaryAttack() -{ - - SendWeaponAnim( pev->sequence ); - - m_flNextPrimaryAttack = gpGlobals->time + 0.3; -} - - -void CWeaponCycler::SecondaryAttack( void ) -{ - float flFrameRate, flGroundSpeed; - - pev->sequence = (pev->sequence + 1) % 8; - - pev->modelindex = m_iModel; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - GetSequenceInfo( pmodel, pev, &flFrameRate, &flGroundSpeed ); - pev->modelindex = 0; - - if (flFrameRate == 0.0) - { - pev->sequence = 0; - } - - SendWeaponAnim( pev->sequence ); - - m_flNextSecondaryAttack = gpGlobals->time + 0.3; -} - - - -// Flaming Wreakage -class CWreckage : public CBaseMonster -{ - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void Think( void ); - - int m_flStartTime; -}; -TYPEDESCRIPTION CWreckage::m_SaveData[] = -{ - DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster ); - - -LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage ); - -void CWreckage::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = 0; - pev->effects = 0; - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->model) - { - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - } - // pev->scale = 5.0; - - m_flStartTime = gpGlobals->time; -} - -void CWreckage::Precache( ) -{ - if ( pev->model ) - PRECACHE_MODEL( (char *)STRING(pev->model) ); -} - -void CWreckage::Think( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.2; - - if (pev->dmgtime) - { - if (pev->dmgtime < gpGlobals->time) - { - UTIL_Remove( this ); - return; - } - else if (RANDOM_FLOAT( 0, pev->dmgtime - m_flStartTime ) > pev->dmgtime - gpGlobals->time) - { - return; - } - } - - Vector VecSrc; - - VecSrc.x = RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ); - VecSrc.y = RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ); - VecSrc.z = RANDOM_FLOAT( pev->absmin.z, pev->absmax.z ); - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, VecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( VecSrc.x ); - WRITE_COORD( VecSrc.y ); - WRITE_COORD( VecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,49) + 50 ); // scale * 10 - WRITE_BYTE( RANDOM_LONG(0, 3) + 8 ); // framerate - MESSAGE_END(); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== h_cycler.cpp ======================================================== + + The Halflife Cycler Monsters + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "animation.h" +#include "weapons.h" +#include "player.h" + + +#define TEMP_FOR_SCREEN_SHOTS +#ifdef TEMP_FOR_SCREEN_SHOTS //=================================================== + +class CCycler : public CBaseMonster +{ +public: + void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax); + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_IMPULSE_USE); } + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void Spawn( void ); + void Think( void ); + //void Pain( float flDamage ); + void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + // Don't treat as a live target + virtual BOOL IsAlive( void ) const { return FALSE; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + int m_animate; +}; + +TYPEDESCRIPTION CCycler::m_SaveData[] = +{ + DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster ); + + +// +// we should get rid of all the other cyclers and replace them with this. +// +class CGenericCycler : public CCycler +{ +public: + void Spawn( void ) { GenericCyclerSpawn( (char *)STRING(pev->model), Vector(-16, -16, 0), Vector(16, 16, 72) ); } +}; +LINK_ENTITY_TO_CLASS( cycler, CGenericCycler ); + + + +// Probe droid imported for tech demo compatibility +// +// PROBE DROID +// +class CCyclerProbe : public CCycler +{ +public: + void Spawn( void ); +}; +LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe ); +void CCyclerProbe :: Spawn( void ) +{ + pev->origin = pev->origin + Vector ( 0, 0, 16 ); + GenericCyclerSpawn( "models/prdroid.mdl", Vector(-16,-16,-16), Vector(16,16,16)); +} + + + +// Cycler member functions + +void CCycler :: GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax) +{ + if (!szModel || !*szModel) + { + ALERT(at_error, "cycler at %.0f %.0f %0.f missing modelname", pev->origin.x, pev->origin.y, pev->origin.z ); + REMOVE_ENTITY(ENT(pev)); + return; + } + + pev->classname = MAKE_STRING("cycler"); + PRECACHE_MODEL( szModel ); + SET_MODEL(ENT(pev), szModel); + + CCycler::Spawn( ); + + UTIL_SetSize(pev, vecMin, vecMax); +} + + +void CCycler :: Spawn( ) +{ + InitBoneControllers(); + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_NONE; + pev->takedamage = DAMAGE_YES; + pev->effects = 0; + pev->health = 80000;// no cycler should die + pev->yaw_speed = 5; + pev->ideal_yaw = pev->angles.y; + ChangeYaw( 360 ); + + m_flFrameRate = 75; + m_flGroundSpeed = 0; + + pev->nextthink += 1.0; + + ResetSequenceInfo( ); + + if (pev->sequence != 0 || pev->frame != 0) + { + m_animate = 0; + pev->framerate = 0; + } + else + { + m_animate = 1; + } +} + + + + +// +// cycler think +// +void CCycler :: Think( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if (m_animate) + { + StudioFrameAdvance ( ); + } + if (m_fSequenceFinished && !m_fSequenceLoops) + { + // ResetSequenceInfo(); + // hack to avoid reloading model every frame + pev->animtime = gpGlobals->time; + pev->framerate = 1.0; + m_fSequenceFinished = FALSE; + m_flLastEventCheck = gpGlobals->time; + pev->frame = 0; + if (!m_animate) + pev->framerate = 0.0; // FIX: don't reset framerate + } +} + +// +// CyclerUse - starts a rotation trend +// +void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + m_animate = !m_animate; + if (m_animate) + pev->framerate = 1.0; + else + pev->framerate = 0.0; +} + +// +// CyclerPain , changes sequences when shot +// +//void CCycler :: Pain( float flDamage ) +int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if (m_animate) + { + pev->sequence++; + + ResetSequenceInfo( ); + + if (m_flFrameRate == 0.0) + { + pev->sequence = 0; + ResetSequenceInfo( ); + } + pev->frame = 0; + } + else + { + pev->framerate = 1.0; + StudioFrameAdvance ( 0.1 ); + pev->framerate = 0; + ALERT( at_console, "sequence: %d, frame %.0f\n", pev->sequence, pev->frame ); + } + + return 0; +} + +#endif + + +class CCyclerSprite : public CBaseEntity +{ +public: + void Spawn( void ); + void Think( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_DONT_SAVE | FCAP_IMPULSE_USE); } + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void Animate( float frames ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + inline int ShouldAnimate( void ) { return m_animate && m_maxFrame > 1.0; } + int m_animate; + float m_lastTime; + float m_maxFrame; +}; + +LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite ); + +TYPEDESCRIPTION CCyclerSprite::m_SaveData[] = +{ + DEFINE_FIELD( CCyclerSprite, m_animate, FIELD_INTEGER ), + DEFINE_FIELD( CCyclerSprite, m_lastTime, FIELD_TIME ), + DEFINE_FIELD( CCyclerSprite, m_maxFrame, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity ); + + +void CCyclerSprite::Spawn( void ) +{ + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_NONE; + pev->takedamage = DAMAGE_YES; + pev->effects = 0; + + pev->frame = 0; + pev->nextthink = gpGlobals->time + 0.1; + m_animate = 1; + m_lastTime = gpGlobals->time; + + PRECACHE_MODEL( (char *)STRING(pev->model) ); + SET_MODEL( ENT(pev), STRING(pev->model) ); + + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; +} + + +void CCyclerSprite::Think( void ) +{ + if ( ShouldAnimate() ) + Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); + + pev->nextthink = gpGlobals->time + 0.1; + m_lastTime = gpGlobals->time; +} + + +void CCyclerSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + m_animate = !m_animate; + ALERT( at_console, "Sprite: %s\n", STRING(pev->model) ); +} + + +int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if ( m_maxFrame > 1.0 ) + { + Animate( 1.0 ); + } + return 1; +} + +void CCyclerSprite::Animate( float frames ) +{ + pev->frame += frames; + if ( m_maxFrame > 0 ) + pev->frame = fmod( pev->frame, m_maxFrame ); +} + + + + + + + +class CWeaponCycler : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + int iItemSlot( void ) { return 1; } + int GetItemInfo(ItemInfo *p) {return 0; } + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + int m_iszModel; + int m_iModel; +}; +LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler ); + + +void CWeaponCycler::Spawn( ) +{ + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_NONE; + + PRECACHE_MODEL( (char *)STRING(pev->model) ); + SET_MODEL( ENT(pev), STRING(pev->model) ); + m_iszModel = pev->model; + m_iModel = pev->modelindex; + + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + SetTouch( &CWeaponCycler::DefaultTouch ); +} + + + +BOOL CWeaponCycler::Deploy( ) +{ + m_pPlayer->pev->viewmodel = m_iszModel; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; + SendWeaponAnim( 0 ); + m_iClip = 0; + return TRUE; +} + + +void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; +} + + +void CWeaponCycler::PrimaryAttack() +{ + + SendWeaponAnim( pev->sequence ); + + m_flNextPrimaryAttack = gpGlobals->time + 0.3; +} + + +void CWeaponCycler::SecondaryAttack( void ) +{ + float flFrameRate, flGroundSpeed; + + pev->sequence = (pev->sequence + 1) % 8; + + pev->modelindex = m_iModel; + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + GetSequenceInfo( pmodel, pev, &flFrameRate, &flGroundSpeed ); + pev->modelindex = 0; + + if (flFrameRate == 0.0) + { + pev->sequence = 0; + } + + SendWeaponAnim( pev->sequence ); + + m_flNextSecondaryAttack = gpGlobals->time + 0.3; +} + + + +// Flaming Wreakage +class CWreckage : public CBaseMonster +{ + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + void Think( void ); + + int m_flStartTime; +}; +TYPEDESCRIPTION CWreckage::m_SaveData[] = +{ + DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ), +}; +IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster ); + + +LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage ); + +void CWreckage::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->takedamage = 0; + pev->effects = 0; + + pev->frame = 0; + pev->nextthink = gpGlobals->time + 0.1; + + if (pev->model) + { + PRECACHE_MODEL( (char *)STRING(pev->model) ); + SET_MODEL( ENT(pev), STRING(pev->model) ); + } + // pev->scale = 5.0; + + m_flStartTime = gpGlobals->time; +} + +void CWreckage::Precache( ) +{ + if ( pev->model ) + PRECACHE_MODEL( (char *)STRING(pev->model) ); +} + +void CWreckage::Think( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.2; + + if (pev->dmgtime) + { + if (pev->dmgtime < gpGlobals->time) + { + UTIL_Remove( this ); + return; + } + else if (RANDOM_FLOAT( 0, pev->dmgtime - m_flStartTime ) > pev->dmgtime - gpGlobals->time) + { + return; + } + } + + Vector VecSrc; + + VecSrc.x = RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ); + VecSrc.y = RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ); + VecSrc.z = RANDOM_FLOAT( pev->absmin.z, pev->absmax.z ); + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, VecSrc ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( VecSrc.x ); + WRITE_COORD( VecSrc.y ); + WRITE_COORD( VecSrc.z ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( RANDOM_LONG(0,49) + 50 ); // scale * 10 + WRITE_BYTE( RANDOM_LONG(0, 3) + 8 ); // framerate + MESSAGE_END(); +} diff --git a/main/source/dlls/h_export.cpp b/main/source/dlls/h_export.cpp index a9cd0086..51e68a7d 100644 --- a/main/source/dlls/h_export.cpp +++ b/main/source/dlls/h_export.cpp @@ -1,61 +1,61 @@ -/*** -* +/*** +* * Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== h_export.cpp ======================================================== - - Entity classes exported by Halflife. - -*/ - -#include "extdll.h" -#include "util.h" - -#include "cbase.h" - -// Holds engine functionality callbacks -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; - +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== h_export.cpp ======================================================== + + Entity classes exported by Halflife. + +*/ + +#include "extdll.h" +#include "util.h" + +#include "cbase.h" + +// Holds engine functionality callbacks +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + #undef DLLEXPORT #ifdef _WIN32 #define DLLEXPORT __stdcall #else #define DLLEXPORT __attribute__ ((visibility("default"))) #endif - -#ifdef _WIN32 - -// Required DLL entry point -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - } - return TRUE; -} + +#ifdef _WIN32 + +// Required DLL entry point +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + } + return TRUE; +} #endif - + extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -{ - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; +{ + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; } \ No newline at end of file diff --git a/main/source/dlls/handgrenade.cpp b/main/source/dlls/handgrenade.cpp index 7f81319f..bad00442 100644 --- a/main/source/dlls/handgrenade.cpp +++ b/main/source/dlls/handgrenade.cpp @@ -1,233 +1,233 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - - -#define HANDGRENADE_PRIMARY_VOLUME 450 - -enum handgrenade_e { - HANDGRENADE_IDLE = 0, - HANDGRENADE_FIDGET, - HANDGRENADE_PINPULL, - HANDGRENADE_THROW1, // toss - HANDGRENADE_THROW2, // medium - HANDGRENADE_THROW3, // hard - HANDGRENADE_HOLSTER, - HANDGRENADE_DRAW -}; - - -LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ); - - -void CHandGrenade::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_HANDGRENADE; - SET_MODEL(ENT(pev), "models/w_grenade.mdl"); - -#ifndef CLIENT_DLL - pev->dmg = gSkillData.plrDmgHandGrenade; -#endif - - m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CHandGrenade::Precache( void ) -{ - PRECACHE_MODEL("models/w_grenade.mdl"); - PRECACHE_MODEL("models/v_grenade.mdl"); - PRECACHE_MODEL("models/p_grenade.mdl"); -} - -int CHandGrenade::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Hand Grenade"; - p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 0; - p->iId = m_iId = WEAPON_HANDGRENADE; - p->iWeight = HANDGRENADE_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - - -BOOL CHandGrenade::Deploy( ) -{ - m_flReleaseThrow = -1; - return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" ); -} - -BOOL CHandGrenade::CanHolster( void ) -{ - // can only holster hand grenades when not primed! - return ( m_flStartThrow == 0 ); -} - -void CHandGrenade::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - SendWeaponAnim( HANDGRENADE_HOLSTER ); - } - else - { - // no more grenades! - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - } - - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); -} - -void CHandGrenade::PrimaryAttack() -{ - if ( !m_flStartThrow && m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] > 0 ) - { - m_flStartThrow = gpGlobals->time; - m_flReleaseThrow = 0; - - SendWeaponAnim( HANDGRENADE_PINPULL ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - } -} - - -void CHandGrenade::WeaponIdle( void ) -{ - if ( m_flReleaseThrow == 0 && m_flStartThrow ) - m_flReleaseThrow = gpGlobals->time; - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if ( m_flStartThrow ) - { - Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - - if ( angThrow.x < 0 ) - angThrow.x = -10 + angThrow.x * ( ( 90 - 10 ) / 90.0 ); - else - angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); - - float flVel = ( 90 - angThrow.x ) * 4; - if ( flVel > 500 ) - flVel = 500; - - UTIL_MakeVectors( angThrow ); - - Vector vecSrc = m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16; - - Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->pev->velocity; - - // alway explode 3 seconds after the pin was pulled - float time = m_flStartThrow - gpGlobals->time + 3.0; - if (time < 0) - time = 0; - - CGrenade::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time ); - - if ( flVel < 500 ) - { - SendWeaponAnim( HANDGRENADE_THROW1 ); - } - else if ( flVel < 1000 ) - { - SendWeaponAnim( HANDGRENADE_THROW2 ); - } - else - { - SendWeaponAnim( HANDGRENADE_THROW3 ); - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flReleaseThrow = 0; - m_flStartThrow = 0; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - - m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ]--; - - if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - // just threw last grenade - // set attack times in the future, and weapon idle in the future so we can see the whole throw - // animation, weapon idle will automatically retire the weapon for us. - m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing - } - return; - } - else if ( m_flReleaseThrow > 0 ) - { - // we've finished the throw, restart. - m_flStartThrow = 0; - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - SendWeaponAnim( HANDGRENADE_DRAW ); - } - else - { - RetireWeapon(); - return; - } - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - m_flReleaseThrow = -1; - return; - } - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - iAnim = HANDGRENADE_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. - } - else - { - iAnim = HANDGRENADE_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 75.0 / 30.0; - } - - SendWeaponAnim( iAnim ); - } -} - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + + +#define HANDGRENADE_PRIMARY_VOLUME 450 + +enum handgrenade_e { + HANDGRENADE_IDLE = 0, + HANDGRENADE_FIDGET, + HANDGRENADE_PINPULL, + HANDGRENADE_THROW1, // toss + HANDGRENADE_THROW2, // medium + HANDGRENADE_THROW3, // hard + HANDGRENADE_HOLSTER, + HANDGRENADE_DRAW +}; + + +LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ); + + +void CHandGrenade::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_HANDGRENADE; + SET_MODEL(ENT(pev), "models/w_grenade.mdl"); + +#ifndef CLIENT_DLL + pev->dmg = gSkillData.plrDmgHandGrenade; +#endif + + m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CHandGrenade::Precache( void ) +{ + PRECACHE_MODEL("models/w_grenade.mdl"); + PRECACHE_MODEL("models/v_grenade.mdl"); + PRECACHE_MODEL("models/p_grenade.mdl"); +} + +int CHandGrenade::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "Hand Grenade"; + p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 4; + p->iPosition = 0; + p->iId = m_iId = WEAPON_HANDGRENADE; + p->iWeight = HANDGRENADE_WEIGHT; + p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; + + return 1; +} + + +BOOL CHandGrenade::Deploy( ) +{ + m_flReleaseThrow = -1; + return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" ); +} + +BOOL CHandGrenade::CanHolster( void ) +{ + // can only holster hand grenades when not primed! + return ( m_flStartThrow == 0 ); +} + +void CHandGrenade::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + + if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + { + SendWeaponAnim( HANDGRENADE_HOLSTER ); + } + else + { + // no more grenades! + m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; + } + + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); +} + +void CHandGrenade::PrimaryAttack() +{ + if ( !m_flStartThrow && m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] > 0 ) + { + m_flStartThrow = gpGlobals->time; + m_flReleaseThrow = 0; + + SendWeaponAnim( HANDGRENADE_PINPULL ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + } +} + + +void CHandGrenade::WeaponIdle( void ) +{ + if ( m_flReleaseThrow == 0 && m_flStartThrow ) + m_flReleaseThrow = gpGlobals->time; + + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + if ( m_flStartThrow ) + { + Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; + + if ( angThrow.x < 0 ) + angThrow.x = -10 + angThrow.x * ( ( 90 - 10 ) / 90.0 ); + else + angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); + + float flVel = ( 90 - angThrow.x ) * 4; + if ( flVel > 500 ) + flVel = 500; + + UTIL_MakeVectors( angThrow ); + + Vector vecSrc = m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16; + + Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->pev->velocity; + + // alway explode 3 seconds after the pin was pulled + float time = m_flStartThrow - gpGlobals->time + 3.0; + if (time < 0) + time = 0; + + CGrenade::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time ); + + if ( flVel < 500 ) + { + SendWeaponAnim( HANDGRENADE_THROW1 ); + } + else if ( flVel < 1000 ) + { + SendWeaponAnim( HANDGRENADE_THROW2 ); + } + else + { + SendWeaponAnim( HANDGRENADE_THROW3 ); + } + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flReleaseThrow = 0; + m_flStartThrow = 0; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + + m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ]--; + + if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + { + // just threw last grenade + // set attack times in the future, and weapon idle in the future so we can see the whole throw + // animation, weapon idle will automatically retire the weapon for us. + m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing + } + return; + } + else if ( m_flReleaseThrow > 0 ) + { + // we've finished the throw, restart. + m_flStartThrow = 0; + + if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + { + SendWeaponAnim( HANDGRENADE_DRAW ); + } + else + { + RetireWeapon(); + return; + } + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flReleaseThrow = -1; + return; + } + + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + { + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if (flRand <= 0.75) + { + iAnim = HANDGRENADE_IDLE; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. + } + else + { + iAnim = HANDGRENADE_FIDGET; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 75.0 / 30.0; + } + + SendWeaponAnim( iAnim ); + } +} + + + + diff --git a/main/source/dlls/hassassin.cpp b/main/source/dlls/hassassin.cpp index cf62d508..c5bba5ac 100644 --- a/main/source/dlls/hassassin.cpp +++ b/main/source/dlls/hassassin.cpp @@ -1,1015 +1,1015 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// hassassin - Human assassin, fast and stealthy -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "weapons.h" -#include "soundent.h" -#include "game.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_ASSASSIN_EXPOSED = LAST_COMMON_SCHEDULE + 1,// cover was blown. - SCHED_ASSASSIN_JUMP, // fly through the air - SCHED_ASSASSIN_JUMP_ATTACK, // fly through the air and shoot - SCHED_ASSASSIN_JUMP_LAND, // hit and run away -}; - -//========================================================= -// monster-specific tasks -//========================================================= - -enum -{ - TASK_ASSASSIN_FALL_TO_GROUND = LAST_COMMON_TASK + 1, // falling and waiting to hit ground -}; - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ASSASSIN_AE_SHOOT1 1 -#define ASSASSIN_AE_TOSS1 2 -#define ASSASSIN_AE_JUMP 3 - - -#define bits_MEMORY_BADJUMP (bits_MEMORY_CUSTOM1) - -class CHAssassin : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void); - void Shoot( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - Schedule_t* GetSchedule ( void ); - Schedule_t* GetScheduleOfType ( int Type ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); // jump - // BOOL CheckMeleeAttack2 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); // shoot - BOOL CheckRangeAttack2 ( float flDot, float flDist ); // throw grenade - void StartTask ( Task_t *pTask ); - void RunAI( void ); - void RunTask ( Task_t *pTask ); - void DeathSound ( void ); - void IdleSound ( void ); - CUSTOM_SCHEDULES; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flLastShot; - float m_flDiviation; - - float m_flNextJump; - Vector m_vecJumpVelocity; - - float m_flNextGrenadeCheck; - Vector m_vecTossVelocity; - BOOL m_fThrowGrenade; - - int m_iTargetRanderamt; - - int m_iFrustration; - - int m_iShell; -}; -LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ); - - -TYPEDESCRIPTION CHAssassin::m_SaveData[] = -{ - DEFINE_FIELD( CHAssassin, m_flLastShot, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_flDiviation, FIELD_FLOAT ), - - DEFINE_FIELD( CHAssassin, m_flNextJump, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_vecJumpVelocity, FIELD_VECTOR ), - - DEFINE_FIELD( CHAssassin, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CHAssassin, m_fThrowGrenade, FIELD_BOOLEAN ), - - DEFINE_FIELD( CHAssassin, m_iTargetRanderamt, FIELD_INTEGER ), - DEFINE_FIELD( CHAssassin, m_iFrustration, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ); - - -//========================================================= -// DieSound -//========================================================= -void CHAssassin :: DeathSound ( void ) -{ -} - -//========================================================= -// IdleSound -//========================================================= -void CHAssassin :: IdleSound ( void ) -{ -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CHAssassin :: ISoundMask ( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHAssassin :: Classify ( void ) -{ - return CLASS_HUMAN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHAssassin :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 360; - break; - default: - ys = 360; - break; - } - - pev->yaw_speed = ys; -} - - -//========================================================= -// Shoot -//========================================================= -void CHAssassin :: Shoot ( void ) -{ - if (m_hEnemy == NULL) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - if (m_flLastShot + 2 < gpGlobals->time) - { - m_flDiviation = 0.10; - } - else - { - m_flDiviation -= 0.01; - if (m_flDiviation < 0.02) - m_flDiviation = 0.02; - } - m_flLastShot = gpGlobals->time; - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( pev->origin + gpGlobals->v_up * 32 + gpGlobals->v_forward * 12, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL); - FireBullets(1, vecShootOrigin, vecShootDir, Vector( m_flDiviation, m_flDiviation, m_flDiviation ), 2048, BULLET_MONSTER_9MM ); // shoot +-8 degrees - - switch(RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM); - break; - } - - pev->effects |= EF_MUZZLEFLASH; - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - - m_cAmmoLoaded--; -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CHAssassin :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case ASSASSIN_AE_SHOOT1: - Shoot( ); - break; - case ASSASSIN_AE_TOSS1: - { - UTIL_MakeVectors( pev->angles ); - CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 2.0 ); - - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - m_fThrowGrenade = FALSE; - // !!!LATER - when in a group, only try to throw grenade if ordered. - } - break; - case ASSASSIN_AE_JUMP: - { - // ALERT( at_console, "jumping"); - UTIL_MakeAimVectors( pev->angles ); - pev->movetype = MOVETYPE_TOSS; - pev->flags &= ~FL_ONGROUND; - pev->velocity = m_vecJumpVelocity; - m_flNextJump = gpGlobals->time + 3.0; - } - return; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHAssassin :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/hassassin.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = 0; - pev->health = gSkillData.hassassinHealth; - m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP; - pev->friction = 1; - - m_HackedGunPos = Vector( 0, 24, 48 ); - - m_iTargetRanderamt = 20; - pev->renderamt = 20; - pev->rendermode = kRenderTransTexture; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHAssassin :: Precache() -{ - PRECACHE_MODEL("models/hassassin.mdl"); - - PRECACHE_SOUND("weapons/pl_gun1.wav"); - PRECACHE_SOUND("weapons/pl_gun2.wav"); - - PRECACHE_SOUND("debris/beamstart1.wav"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell -} - - - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// Fail Schedule -//========================================================= -Task_t tlAssassinFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - // { TASK_WAIT_PVS, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, -}; - -Schedule_t slAssassinFail[] = -{ - { - tlAssassinFail, - ARRAYSIZE ( tlAssassinFail ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - "AssassinFail" - }, -}; - - -//========================================================= -// Enemy exposed Agrunt's cover -//========================================================= -Task_t tlAssassinExposed[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slAssassinExposed[] = -{ - { - tlAssassinExposed, - ARRAYSIZE ( tlAssassinExposed ), - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AssassinExposed", - }, -}; - - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAssassinTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAssassinTakeCoverFromEnemy[] = -{ - { - tlAssassinTakeCoverFromEnemy, - ARRAYSIZE ( tlAssassinTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinTakeCoverFromEnemy" - }, -}; - - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAssassinTakeCoverFromEnemy2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK2 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAssassinTakeCoverFromEnemy2[] = -{ - { - tlAssassinTakeCoverFromEnemy2, - ARRAYSIZE ( tlAssassinTakeCoverFromEnemy2 ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinTakeCoverFromEnemy2" - }, -}; - - -//========================================================= -// hide from the loudest sound source -//========================================================= -Task_t tlAssassinTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slAssassinTakeCoverFromBestSound[] = -{ - { - tlAssassinTakeCoverFromBestSound, - ARRAYSIZE ( tlAssassinTakeCoverFromBestSound ), - bits_COND_NEW_ENEMY, - 0, - "AssassinTakeCoverFromBestSound" - }, -}; - - - - - -//========================================================= -// AlertIdle Schedules -//========================================================= -Task_t tlAssassinHide[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, -}; - -Schedule_t slAssassinHide[] = -{ - { - tlAssassinHide, - ARRAYSIZE ( tlAssassinHide ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinHide" - }, -}; - - - -//========================================================= -// HUNT Schedules -//========================================================= -Task_t tlAssassinHunt[] = -{ - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slAssassinHunt[] = -{ - { - tlAssassinHunt, - ARRAYSIZE ( tlAssassinHunt ), - bits_COND_NEW_ENEMY | - // bits_COND_SEE_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinHunt" - }, -}; - - -//========================================================= -// Jumping Schedules -//========================================================= -Task_t tlAssassinJump[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_SET_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_ATTACK }, -}; - -Schedule_t slAssassinJump[] = -{ - { - tlAssassinJump, - ARRAYSIZE ( tlAssassinJump ), - 0, - 0, - "AssassinJump" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlAssassinJumpAttack[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_LAND }, - // { TASK_SET_ACTIVITY, (float)ACT_FLY }, - { TASK_ASSASSIN_FALL_TO_GROUND, (float)0 }, -}; - - -Schedule_t slAssassinJumpAttack[] = -{ - { - tlAssassinJumpAttack, - ARRAYSIZE ( tlAssassinJumpAttack ), - 0, - 0, - "AssassinJumpAttack" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlAssassinJumpLand[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_EXPOSED }, - // { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_REMEMBER, (float)bits_MEMORY_BADJUMP }, - { TASK_FIND_NODE_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_FORGET, (float)bits_MEMORY_BADJUMP }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, -}; - -Schedule_t slAssassinJumpLand[] = -{ - { - tlAssassinJumpLand, - ARRAYSIZE ( tlAssassinJumpLand ), - 0, - 0, - "AssassinJumpLand" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CHAssassin ) -{ - slAssassinFail, - slAssassinExposed, - slAssassinTakeCoverFromEnemy, - slAssassinTakeCoverFromEnemy2, - slAssassinTakeCoverFromBestSound, - slAssassinHide, - slAssassinHunt, - slAssassinJump, - slAssassinJumpAttack, - slAssassinJumpLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ); - - -//========================================================= -// CheckMeleeAttack1 - jump like crazy if the enemy gets too close. -//========================================================= -BOOL CHAssassin :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( m_flNextJump < gpGlobals->time && (flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP )) && m_hEnemy != NULL ) - { - TraceResult tr; - - Vector vecDest = pev->origin + Vector( RANDOM_FLOAT( -64, 64), RANDOM_FLOAT( -64, 64 ), 160 ); - - UTIL_TraceHull( pev->origin + Vector( 0, 0, 36 ), vecDest + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, ENT(pev), &tr); - - if ( tr.fStartSolid || tr.flFraction < 1.0) - { - return FALSE; - } - - float flGravity = g_psv_gravity->value; - - float time = sqrt( 160 / (0.5 * flGravity)); - float speed = flGravity * time / 160; - m_vecJumpVelocity = (vecDest - pev->origin) * speed; - - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 - drop a cap in their ass -// -//========================================================= -BOOL CHAssassin :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) - { - TraceResult tr; - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), dont_ignore_monsters, ENT(pev), &tr); - - if ( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() ) - { - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - toss grenade is enemy gets in the way and is too close. -//========================================================= -BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - m_fThrowGrenade = FALSE; - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) - { - // don't throw grenades at anything that isn't on the ground! - return FALSE; - } - - // don't get grenade happy unless the player starts to piss you off - if ( m_iFrustration <= 2) - return FALSE; - - if ( m_flNextGrenadeCheck < gpGlobals->time && !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 512 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition( ), m_hEnemy->Center(), flDist, 0.5 ); // use dist as speed to get there in 1 second - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - - return TRUE; - } - } - - return FALSE; -} - - -//========================================================= -// RunAI -//========================================================= -void CHAssassin :: RunAI( void ) -{ - CBaseMonster :: RunAI(); - - // always visible if moving - // always visible is not on hard - if (g_iSkillLevel != SKILL_HARD || m_hEnemy == NULL || pev->deadflag != DEAD_NO || m_Activity == ACT_RUN || m_Activity == ACT_WALK || !(pev->flags & FL_ONGROUND)) - m_iTargetRanderamt = 255; - else - m_iTargetRanderamt = 20; - - if (pev->renderamt > m_iTargetRanderamt) - { - if (pev->renderamt == 255) - { - EMIT_SOUND (ENT(pev), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM ); - } - - pev->renderamt = max( pev->renderamt - 50, m_iTargetRanderamt ); - pev->rendermode = kRenderTransTexture; - } - else if (pev->renderamt < m_iTargetRanderamt) - { - pev->renderamt = min( pev->renderamt + 50, m_iTargetRanderamt ); - if (pev->renderamt == 255) - pev->rendermode = kRenderNormal; - } - - if (m_Activity == ACT_RUN || m_Activity == ACT_WALK) - { - static int iStep = 0; - iStep = ! iStep; - if (iStep) - { - switch( RANDOM_LONG( 0, 3 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step1.wav", 0.5, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step3.wav", 0.5, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step2.wav", 0.5, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step4.wav", 0.5, ATTN_NORM); break; - } - } - } -} - - -//========================================================= -// StartTask -//========================================================= -void CHAssassin :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK2: - if (!m_fThrowGrenade) - { - TaskComplete( ); - } - else - { - CBaseMonster :: StartTask ( pTask ); - } - break; - case TASK_ASSASSIN_FALL_TO_GROUND: - break; - default: - CBaseMonster :: StartTask ( pTask ); - break; - } -} - - -//========================================================= -// RunTask -//========================================================= -void CHAssassin :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_ASSASSIN_FALL_TO_GROUND: - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if (m_fSequenceFinished) - { - if (pev->velocity.z > 0) - { - pev->sequence = LookupSequence( "fly_up" ); - } - else if (HasConditions ( bits_COND_SEE_ENEMY )) - { - pev->sequence = LookupSequence( "fly_attack" ); - pev->frame = 0; - } - else - { - pev->sequence = LookupSequence( "fly_down" ); - pev->frame = 0; - } - - ResetSequenceInfo( ); - SetYawSpeed(); - } - if (pev->flags & FL_ONGROUND) - { - // ALERT( at_console, "on ground\n"); - TaskComplete( ); - } - break; - default: - CBaseMonster :: RunTask ( pTask ); - break; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CHAssassin :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - case MONSTERSTATE_ALERT: - { - if ( HasConditions ( bits_COND_HEAR_SOUND )) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - if ( pSound && (pSound->m_iType & bits_SOUND_COMBAT) ) - { - return GetScheduleOfType( SCHED_INVESTIGATE_SOUND ); - } - } - } - break; - - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - // flying? - if ( pev->movetype == MOVETYPE_TOSS) - { - if (pev->flags & FL_ONGROUND) - { - // ALERT( at_console, "landed\n"); - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_LAND ); - } - else - { - // ALERT( at_console, "jump\n"); - // jump or jump/shoot - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP ); - else - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_ATTACK ); - } - } - - if ( HasConditions ( bits_COND_HEAR_SOUND )) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - } - - if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) - { - m_iFrustration++; - } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) - { - m_iFrustration++; - } - - // jump player! - if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - // ALERT( at_console, "melee attack 1\n"); - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } - - // throw grenade - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) ) - { - // ALERT( at_console, "range attack 2\n"); - return GetScheduleOfType ( SCHED_RANGE_ATTACK2 ); - } - - // spotted - if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - // ALERT( at_console, "exposed\n"); - m_iFrustration++; - return GetScheduleOfType ( SCHED_ASSASSIN_EXPOSED ); - } - - // can attack - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - // ALERT( at_console, "range attack 1\n"); - m_iFrustration = 0; - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - // ALERT( at_console, "face\n"); - return GetScheduleOfType ( SCHED_COMBAT_FACE ); - } - - // new enemy - if ( HasConditions ( bits_COND_NEW_ENEMY ) ) - { - // ALERT( at_console, "take cover\n"); - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - - // ALERT( at_console, "stand\n"); - return GetScheduleOfType ( SCHED_ALERT_STAND ); - } - break; - } - - return CBaseMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "%d\n", m_iFrustration ); - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - if (pev->health > 30) - return slAssassinTakeCoverFromEnemy; - else - return slAssassinTakeCoverFromEnemy2; - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - return slAssassinTakeCoverFromBestSound; - case SCHED_ASSASSIN_EXPOSED: - return slAssassinExposed; - case SCHED_FAIL: - if (m_MonsterState == MONSTERSTATE_COMBAT) - return slAssassinFail; - break; - case SCHED_ALERT_STAND: - if (m_MonsterState == MONSTERSTATE_COMBAT) - return slAssassinHide; - break; - case SCHED_CHASE_ENEMY: - return slAssassinHunt; - case SCHED_MELEE_ATTACK1: - if (pev->flags & FL_ONGROUND) - { - if (m_flNextJump > gpGlobals->time) - { - // can't jump yet, go ahead and fail - return slAssassinFail; - } - else - { - return slAssassinJump; - } - } - else - { - return slAssassinJumpAttack; - } - case SCHED_ASSASSIN_JUMP: - case SCHED_ASSASSIN_JUMP_ATTACK: - return slAssassinJumpAttack; - case SCHED_ASSASSIN_JUMP_LAND: - return slAssassinJumpLand; - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +//========================================================= +// hassassin - Human assassin, fast and stealthy +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "squadmonster.h" +#include "weapons.h" +#include "soundent.h" +#include "game.h" + +extern DLL_GLOBAL int g_iSkillLevel; + +//========================================================= +// monster-specific schedule types +//========================================================= +enum +{ + SCHED_ASSASSIN_EXPOSED = LAST_COMMON_SCHEDULE + 1,// cover was blown. + SCHED_ASSASSIN_JUMP, // fly through the air + SCHED_ASSASSIN_JUMP_ATTACK, // fly through the air and shoot + SCHED_ASSASSIN_JUMP_LAND, // hit and run away +}; + +//========================================================= +// monster-specific tasks +//========================================================= + +enum +{ + TASK_ASSASSIN_FALL_TO_GROUND = LAST_COMMON_TASK + 1, // falling and waiting to hit ground +}; + + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define ASSASSIN_AE_SHOOT1 1 +#define ASSASSIN_AE_TOSS1 2 +#define ASSASSIN_AE_JUMP 3 + + +#define bits_MEMORY_BADJUMP (bits_MEMORY_CUSTOM1) + +class CHAssassin : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed ( void ); + int Classify ( void ); + int ISoundMask ( void); + void Shoot( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + Schedule_t* GetSchedule ( void ); + Schedule_t* GetScheduleOfType ( int Type ); + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); // jump + // BOOL CheckMeleeAttack2 ( float flDot, float flDist ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); // shoot + BOOL CheckRangeAttack2 ( float flDot, float flDist ); // throw grenade + void StartTask ( Task_t *pTask ); + void RunAI( void ); + void RunTask ( Task_t *pTask ); + void DeathSound ( void ); + void IdleSound ( void ); + CUSTOM_SCHEDULES; + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + float m_flLastShot; + float m_flDiviation; + + float m_flNextJump; + Vector m_vecJumpVelocity; + + float m_flNextGrenadeCheck; + Vector m_vecTossVelocity; + BOOL m_fThrowGrenade; + + int m_iTargetRanderamt; + + int m_iFrustration; + + int m_iShell; +}; +LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ); + + +TYPEDESCRIPTION CHAssassin::m_SaveData[] = +{ + DEFINE_FIELD( CHAssassin, m_flLastShot, FIELD_TIME ), + DEFINE_FIELD( CHAssassin, m_flDiviation, FIELD_FLOAT ), + + DEFINE_FIELD( CHAssassin, m_flNextJump, FIELD_TIME ), + DEFINE_FIELD( CHAssassin, m_vecJumpVelocity, FIELD_VECTOR ), + + DEFINE_FIELD( CHAssassin, m_flNextGrenadeCheck, FIELD_TIME ), + DEFINE_FIELD( CHAssassin, m_vecTossVelocity, FIELD_VECTOR ), + DEFINE_FIELD( CHAssassin, m_fThrowGrenade, FIELD_BOOLEAN ), + + DEFINE_FIELD( CHAssassin, m_iTargetRanderamt, FIELD_INTEGER ), + DEFINE_FIELD( CHAssassin, m_iFrustration, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ); + + +//========================================================= +// DieSound +//========================================================= +void CHAssassin :: DeathSound ( void ) +{ +} + +//========================================================= +// IdleSound +//========================================================= +void CHAssassin :: IdleSound ( void ) +{ +} + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. +//========================================================= +int CHAssassin :: ISoundMask ( void) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_DANGER | + bits_SOUND_PLAYER; +} + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CHAssassin :: Classify ( void ) +{ + return CLASS_HUMAN_MILITARY; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CHAssassin :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 360; + break; + default: + ys = 360; + break; + } + + pev->yaw_speed = ys; +} + + +//========================================================= +// Shoot +//========================================================= +void CHAssassin :: Shoot ( void ) +{ + if (m_hEnemy == NULL) + { + return; + } + + Vector vecShootOrigin = GetGunPosition(); + Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); + + if (m_flLastShot + 2 < gpGlobals->time) + { + m_flDiviation = 0.10; + } + else + { + m_flDiviation -= 0.01; + if (m_flDiviation < 0.02) + m_flDiviation = 0.02; + } + m_flLastShot = gpGlobals->time; + + UTIL_MakeVectors ( pev->angles ); + + Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); + EjectBrass ( pev->origin + gpGlobals->v_up * 32 + gpGlobals->v_forward * 12, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL); + FireBullets(1, vecShootOrigin, vecShootDir, Vector( m_flDiviation, m_flDiviation, m_flDiviation ), 2048, BULLET_MONSTER_9MM ); // shoot +-8 degrees + + switch(RANDOM_LONG(0,1)) + { + case 0: + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM); + break; + case 1: + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM); + break; + } + + pev->effects |= EF_MUZZLEFLASH; + + Vector angDir = UTIL_VecToAngles( vecShootDir ); + SetBlending( 0, angDir.x ); + + m_cAmmoLoaded--; +} + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CHAssassin :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case ASSASSIN_AE_SHOOT1: + Shoot( ); + break; + case ASSASSIN_AE_TOSS1: + { + UTIL_MakeVectors( pev->angles ); + CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 2.0 ); + + m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. + m_fThrowGrenade = FALSE; + // !!!LATER - when in a group, only try to throw grenade if ordered. + } + break; + case ASSASSIN_AE_JUMP: + { + // ALERT( at_console, "jumping"); + UTIL_MakeAimVectors( pev->angles ); + pev->movetype = MOVETYPE_TOSS; + pev->flags &= ~FL_ONGROUND; + pev->velocity = m_vecJumpVelocity; + m_flNextJump = gpGlobals->time + 3.0; + } + return; + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CHAssassin :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/hassassin.mdl"); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->effects = 0; + pev->health = gSkillData.hassassinHealth; + m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP; + pev->friction = 1; + + m_HackedGunPos = Vector( 0, 24, 48 ); + + m_iTargetRanderamt = 20; + pev->renderamt = 20; + pev->rendermode = kRenderTransTexture; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CHAssassin :: Precache() +{ + PRECACHE_MODEL("models/hassassin.mdl"); + + PRECACHE_SOUND("weapons/pl_gun1.wav"); + PRECACHE_SOUND("weapons/pl_gun2.wav"); + + PRECACHE_SOUND("debris/beamstart1.wav"); + + m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell +} + + + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +//========================================================= +// Fail Schedule +//========================================================= +Task_t tlAssassinFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + // { TASK_WAIT_PVS, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, +}; + +Schedule_t slAssassinFail[] = +{ + { + tlAssassinFail, + ARRAYSIZE ( tlAssassinFail ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER | + bits_SOUND_PLAYER, + "AssassinFail" + }, +}; + + +//========================================================= +// Enemy exposed Agrunt's cover +//========================================================= +Task_t tlAssassinExposed[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP }, + { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, +}; + +Schedule_t slAssassinExposed[] = +{ + { + tlAssassinExposed, + ARRAYSIZE ( tlAssassinExposed ), + bits_COND_CAN_MELEE_ATTACK1, + 0, + "AssassinExposed", + }, +}; + + +//========================================================= +// Take cover from enemy! Tries lateral cover before node +// cover! +//========================================================= +Task_t tlAssassinTakeCoverFromEnemy[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_WAIT, (float)0.2 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_FACE_ENEMY, (float)0 }, +}; + +Schedule_t slAssassinTakeCoverFromEnemy[] = +{ + { + tlAssassinTakeCoverFromEnemy, + ARRAYSIZE ( tlAssassinTakeCoverFromEnemy ), + bits_COND_NEW_ENEMY | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "AssassinTakeCoverFromEnemy" + }, +}; + + +//========================================================= +// Take cover from enemy! Tries lateral cover before node +// cover! +//========================================================= +Task_t tlAssassinTakeCoverFromEnemy2[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_WAIT, (float)0.2 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK2 }, + { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_FACE_ENEMY, (float)0 }, +}; + +Schedule_t slAssassinTakeCoverFromEnemy2[] = +{ + { + tlAssassinTakeCoverFromEnemy2, + ARRAYSIZE ( tlAssassinTakeCoverFromEnemy2 ), + bits_COND_NEW_ENEMY | + bits_COND_CAN_MELEE_ATTACK2 | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "AssassinTakeCoverFromEnemy2" + }, +}; + + +//========================================================= +// hide from the loudest sound source +//========================================================= +Task_t tlAssassinTakeCoverFromBestSound[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_TURN_LEFT, (float)179 }, +}; + +Schedule_t slAssassinTakeCoverFromBestSound[] = +{ + { + tlAssassinTakeCoverFromBestSound, + ARRAYSIZE ( tlAssassinTakeCoverFromBestSound ), + bits_COND_NEW_ENEMY, + 0, + "AssassinTakeCoverFromBestSound" + }, +}; + + + + + +//========================================================= +// AlertIdle Schedules +//========================================================= +Task_t tlAssassinHide[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, +}; + +Schedule_t slAssassinHide[] = +{ + { + tlAssassinHide, + ARRAYSIZE ( tlAssassinHide ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_ENEMY | + bits_COND_SEE_FEAR | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "AssassinHide" + }, +}; + + + +//========================================================= +// HUNT Schedules +//========================================================= +Task_t tlAssassinHunt[] = +{ + { TASK_GET_PATH_TO_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, +}; + +Schedule_t slAssassinHunt[] = +{ + { + tlAssassinHunt, + ARRAYSIZE ( tlAssassinHunt ), + bits_COND_NEW_ENEMY | + // bits_COND_SEE_ENEMY | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "AssassinHunt" + }, +}; + + +//========================================================= +// Jumping Schedules +//========================================================= +Task_t tlAssassinJump[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, + { TASK_SET_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_ATTACK }, +}; + +Schedule_t slAssassinJump[] = +{ + { + tlAssassinJump, + ARRAYSIZE ( tlAssassinJump ), + 0, + 0, + "AssassinJump" + }, +}; + + +//========================================================= +// repel +//========================================================= +Task_t tlAssassinJumpAttack[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_LAND }, + // { TASK_SET_ACTIVITY, (float)ACT_FLY }, + { TASK_ASSASSIN_FALL_TO_GROUND, (float)0 }, +}; + + +Schedule_t slAssassinJumpAttack[] = +{ + { + tlAssassinJumpAttack, + ARRAYSIZE ( tlAssassinJumpAttack ), + 0, + 0, + "AssassinJumpAttack" + }, +}; + + +//========================================================= +// repel +//========================================================= +Task_t tlAssassinJumpLand[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_EXPOSED }, + // { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_REMEMBER, (float)bits_MEMORY_BADJUMP }, + { TASK_FIND_NODE_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_FORGET, (float)bits_MEMORY_BADJUMP }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, +}; + +Schedule_t slAssassinJumpLand[] = +{ + { + tlAssassinJumpLand, + ARRAYSIZE ( tlAssassinJumpLand ), + 0, + 0, + "AssassinJumpLand" + }, +}; + +DEFINE_CUSTOM_SCHEDULES( CHAssassin ) +{ + slAssassinFail, + slAssassinExposed, + slAssassinTakeCoverFromEnemy, + slAssassinTakeCoverFromEnemy2, + slAssassinTakeCoverFromBestSound, + slAssassinHide, + slAssassinHunt, + slAssassinJump, + slAssassinJumpAttack, + slAssassinJumpLand, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ); + + +//========================================================= +// CheckMeleeAttack1 - jump like crazy if the enemy gets too close. +//========================================================= +BOOL CHAssassin :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + if ( m_flNextJump < gpGlobals->time && (flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP )) && m_hEnemy != NULL ) + { + TraceResult tr; + + Vector vecDest = pev->origin + Vector( RANDOM_FLOAT( -64, 64), RANDOM_FLOAT( -64, 64 ), 160 ); + + UTIL_TraceHull( pev->origin + Vector( 0, 0, 36 ), vecDest + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, ENT(pev), &tr); + + if ( tr.fStartSolid || tr.flFraction < 1.0) + { + return FALSE; + } + + float flGravity = g_psv_gravity->value; + + float time = sqrt( 160 / (0.5 * flGravity)); + float speed = flGravity * time / 160; + m_vecJumpVelocity = (vecDest - pev->origin) * speed; + + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack1 - drop a cap in their ass +// +//========================================================= +BOOL CHAssassin :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) + { + TraceResult tr; + + Vector vecSrc = GetGunPosition(); + + // verify that a bullet fired from the gun will hit the enemy before the world. + UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), dont_ignore_monsters, ENT(pev), &tr); + + if ( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() ) + { + return TRUE; + } + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack2 - toss grenade is enemy gets in the way and is too close. +//========================================================= +BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist ) +{ + m_fThrowGrenade = FALSE; + if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) + { + // don't throw grenades at anything that isn't on the ground! + return FALSE; + } + + // don't get grenade happy unless the player starts to piss you off + if ( m_iFrustration <= 2) + return FALSE; + + if ( m_flNextGrenadeCheck < gpGlobals->time && !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 512 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) + { + Vector vecToss = VecCheckThrow( pev, GetGunPosition( ), m_hEnemy->Center(), flDist, 0.5 ); // use dist as speed to get there in 1 second + + if ( vecToss != g_vecZero ) + { + m_vecTossVelocity = vecToss; + + // throw a hand grenade + m_fThrowGrenade = TRUE; + + return TRUE; + } + } + + return FALSE; +} + + +//========================================================= +// RunAI +//========================================================= +void CHAssassin :: RunAI( void ) +{ + CBaseMonster :: RunAI(); + + // always visible if moving + // always visible is not on hard + if (g_iSkillLevel != SKILL_HARD || m_hEnemy == NULL || pev->deadflag != DEAD_NO || m_Activity == ACT_RUN || m_Activity == ACT_WALK || !(pev->flags & FL_ONGROUND)) + m_iTargetRanderamt = 255; + else + m_iTargetRanderamt = 20; + + if (pev->renderamt > m_iTargetRanderamt) + { + if (pev->renderamt == 255) + { + EMIT_SOUND (ENT(pev), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM ); + } + + pev->renderamt = max( pev->renderamt - 50, m_iTargetRanderamt ); + pev->rendermode = kRenderTransTexture; + } + else if (pev->renderamt < m_iTargetRanderamt) + { + pev->renderamt = min( pev->renderamt + 50, m_iTargetRanderamt ); + if (pev->renderamt == 255) + pev->rendermode = kRenderNormal; + } + + if (m_Activity == ACT_RUN || m_Activity == ACT_WALK) + { + static int iStep = 0; + iStep = ! iStep; + if (iStep) + { + switch( RANDOM_LONG( 0, 3 ) ) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step1.wav", 0.5, ATTN_NORM); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step3.wav", 0.5, ATTN_NORM); break; + case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step2.wav", 0.5, ATTN_NORM); break; + case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step4.wav", 0.5, ATTN_NORM); break; + } + } + } +} + + +//========================================================= +// StartTask +//========================================================= +void CHAssassin :: StartTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_RANGE_ATTACK2: + if (!m_fThrowGrenade) + { + TaskComplete( ); + } + else + { + CBaseMonster :: StartTask ( pTask ); + } + break; + case TASK_ASSASSIN_FALL_TO_GROUND: + break; + default: + CBaseMonster :: StartTask ( pTask ); + break; + } +} + + +//========================================================= +// RunTask +//========================================================= +void CHAssassin :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_ASSASSIN_FALL_TO_GROUND: + MakeIdealYaw( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); + + if (m_fSequenceFinished) + { + if (pev->velocity.z > 0) + { + pev->sequence = LookupSequence( "fly_up" ); + } + else if (HasConditions ( bits_COND_SEE_ENEMY )) + { + pev->sequence = LookupSequence( "fly_attack" ); + pev->frame = 0; + } + else + { + pev->sequence = LookupSequence( "fly_down" ); + pev->frame = 0; + } + + ResetSequenceInfo( ); + SetYawSpeed(); + } + if (pev->flags & FL_ONGROUND) + { + // ALERT( at_console, "on ground\n"); + TaskComplete( ); + } + break; + default: + CBaseMonster :: RunTask ( pTask ); + break; + } +} + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CHAssassin :: GetSchedule ( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_IDLE: + case MONSTERSTATE_ALERT: + { + if ( HasConditions ( bits_COND_HEAR_SOUND )) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + { + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + if ( pSound && (pSound->m_iType & bits_SOUND_COMBAT) ) + { + return GetScheduleOfType( SCHED_INVESTIGATE_SOUND ); + } + } + } + break; + + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + // flying? + if ( pev->movetype == MOVETYPE_TOSS) + { + if (pev->flags & FL_ONGROUND) + { + // ALERT( at_console, "landed\n"); + // just landed + pev->movetype = MOVETYPE_STEP; + return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_LAND ); + } + else + { + // ALERT( at_console, "jump\n"); + // jump or jump/shoot + if ( m_MonsterState == MONSTERSTATE_COMBAT ) + return GetScheduleOfType ( SCHED_ASSASSIN_JUMP ); + else + return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_ATTACK ); + } + } + + if ( HasConditions ( bits_COND_HEAR_SOUND )) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + { + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + } + + if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) + { + m_iFrustration++; + } + if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + { + m_iFrustration++; + } + + // jump player! + if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + { + // ALERT( at_console, "melee attack 1\n"); + return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + } + + // throw grenade + if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) ) + { + // ALERT( at_console, "range attack 2\n"); + return GetScheduleOfType ( SCHED_RANGE_ATTACK2 ); + } + + // spotted + if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) + { + // ALERT( at_console, "exposed\n"); + m_iFrustration++; + return GetScheduleOfType ( SCHED_ASSASSIN_EXPOSED ); + } + + // can attack + if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + // ALERT( at_console, "range attack 1\n"); + m_iFrustration = 0; + return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + } + + if ( HasConditions ( bits_COND_SEE_ENEMY ) ) + { + // ALERT( at_console, "face\n"); + return GetScheduleOfType ( SCHED_COMBAT_FACE ); + } + + // new enemy + if ( HasConditions ( bits_COND_NEW_ENEMY ) ) + { + // ALERT( at_console, "take cover\n"); + return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + } + + // ALERT( at_console, "stand\n"); + return GetScheduleOfType ( SCHED_ALERT_STAND ); + } + break; + } + + return CBaseMonster :: GetSchedule(); +} + +//========================================================= +//========================================================= +Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) +{ + // ALERT( at_console, "%d\n", m_iFrustration ); + switch ( Type ) + { + case SCHED_TAKE_COVER_FROM_ENEMY: + if (pev->health > 30) + return slAssassinTakeCoverFromEnemy; + else + return slAssassinTakeCoverFromEnemy2; + case SCHED_TAKE_COVER_FROM_BEST_SOUND: + return slAssassinTakeCoverFromBestSound; + case SCHED_ASSASSIN_EXPOSED: + return slAssassinExposed; + case SCHED_FAIL: + if (m_MonsterState == MONSTERSTATE_COMBAT) + return slAssassinFail; + break; + case SCHED_ALERT_STAND: + if (m_MonsterState == MONSTERSTATE_COMBAT) + return slAssassinHide; + break; + case SCHED_CHASE_ENEMY: + return slAssassinHunt; + case SCHED_MELEE_ATTACK1: + if (pev->flags & FL_ONGROUND) + { + if (m_flNextJump > gpGlobals->time) + { + // can't jump yet, go ahead and fail + return slAssassinFail; + } + else + { + return slAssassinJump; + } + } + else + { + return slAssassinJumpAttack; + } + case SCHED_ASSASSIN_JUMP: + case SCHED_ASSASSIN_JUMP_ATTACK: + return slAssassinJumpAttack; + case SCHED_ASSASSIN_JUMP_LAND: + return slAssassinJumpLand; + } + + return CBaseMonster :: GetScheduleOfType( Type ); +} + #endif \ No newline at end of file diff --git a/main/source/dlls/headcrab.cpp b/main/source/dlls/headcrab.cpp index 1a426027..0d980888 100644 --- a/main/source/dlls/headcrab.cpp +++ b/main/source/dlls/headcrab.cpp @@ -1,555 +1,555 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// headcrab.cpp - tiny, jumpy alien parasite -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "game.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HC_AE_JUMPATTACK ( 2 ) - -Task_t tlHCRangeAttack1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_RANDOM, (float)0.5 }, -}; - -Schedule_t slHCRangeAttack1[] = -{ - { - tlHCRangeAttack1, - ARRAYSIZE ( tlHCRangeAttack1 ), - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "HCRangeAttack1" - }, -}; - -Task_t tlHCRangeAttack1Fast[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slHCRangeAttack1Fast[] = -{ - { - tlHCRangeAttack1Fast, - ARRAYSIZE ( tlHCRangeAttack1Fast ), - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "HCRAFast" - }, -}; - -class CHeadCrab : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void RunTask ( Task_t *pTask ); - void StartTask ( Task_t *pTask ); - void SetYawSpeed ( void ); - void EXPORT LeapTouch ( CBaseEntity *pOther ); - Vector Center( void ); - Vector BodyTarget( const Vector &posSrc ); - void PainSound( void ); - void DeathSound( void ); - void IdleSound( void ); - void AlertSound( void ); - void PrescheduleThink( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; } - virtual int GetVoicePitch( void ) { return 100; } - virtual float GetSoundVolue( void ) { return 1.0; } - Schedule_t* GetScheduleOfType ( int Type ); - - CUSTOM_SCHEDULES; - - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackSounds[]; - static const char *pDeathSounds[]; - static const char *pBiteSounds[]; -}; -LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab ); - -DEFINE_CUSTOM_SCHEDULES( CHeadCrab ) -{ - slHCRangeAttack1, - slHCRangeAttack1Fast, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHeadCrab, CBaseMonster ); - -const char *CHeadCrab::pIdleSounds[] = -{ - "headcrab/hc_idle1.wav", - "headcrab/hc_idle2.wav", - "headcrab/hc_idle3.wav", -}; -const char *CHeadCrab::pAlertSounds[] = -{ - "headcrab/hc_alert1.wav", -}; -const char *CHeadCrab::pPainSounds[] = -{ - "headcrab/hc_pain1.wav", - "headcrab/hc_pain2.wav", - "headcrab/hc_pain3.wav", -}; -const char *CHeadCrab::pAttackSounds[] = -{ - "headcrab/hc_attack1.wav", - "headcrab/hc_attack2.wav", - "headcrab/hc_attack3.wav", -}; - -const char *CHeadCrab::pDeathSounds[] = -{ - "headcrab/hc_die1.wav", - "headcrab/hc_die2.wav", -}; - -const char *CHeadCrab::pBiteSounds[] = -{ - "headcrab/hc_headbite.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHeadCrab :: Classify ( void ) -{ - return CLASS_ALIEN_PREY; -} - -//========================================================= -// Center - returns the real center of the headcrab. The -// bounding box is much larger than the actual creature so -// this is needed for targeting -//========================================================= -Vector CHeadCrab :: Center ( void ) -{ - return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 ); -} - - -Vector CHeadCrab :: BodyTarget( const Vector &posSrc ) -{ - return Center( ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHeadCrab :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 30; - break; - case ACT_RUN: - case ACT_WALK: - ys = 20; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 60; - break; - case ACT_RANGE_ATTACK1: - ys = 30; - break; - default: - ys = 30; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case HC_AE_JUMPATTACK: - { - ClearBits( pev->flags, FL_ONGROUND ); - - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground - UTIL_MakeVectors ( pev->angles ); - - Vector vecJumpDir; - if (m_hEnemy != NULL) - { - float gravity = g_psv_gravity->value; - if (gravity <= 1) - gravity = 1; - - // How fast does the headcrab need to travel to reach that height given gravity? - float height = (m_hEnemy->pev->origin.z + m_hEnemy->pev->view_ofs.z - pev->origin.z); - if (height < 16) - height = 16; - float speed = sqrt( 2 * gravity * height ); - float time = speed / gravity; - - // Scale the sideways velocity to get there at the right time - vecJumpDir = (m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - pev->origin); - vecJumpDir = vecJumpDir * ( 1.0 / time ); - - // Speed to offset gravity at the desired height - vecJumpDir.z = speed; - - // Don't jump too far/fast - float distance = vecJumpDir.Length(); - - if (distance > 650) - { - vecJumpDir = vecJumpDir * ( 650.0 / distance ); - } - } - else - { - // jump hop, don't care where - vecJumpDir = Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_up.z ) * 350; - } - - int iSound = RANDOM_LONG(0,2); - if ( iSound != 0 ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pev->velocity = vecJumpDir; - m_flNextAttack = gpGlobals->time + 2; - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHeadCrab :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/headcrab.mdl"); - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.headcrabHealth; - pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin. - pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHeadCrab :: Precache() -{ - PRECACHE_SOUND_ARRAY(pIdleSounds); - PRECACHE_SOUND_ARRAY(pAlertSounds); - PRECACHE_SOUND_ARRAY(pPainSounds); - PRECACHE_SOUND_ARRAY(pAttackSounds); - PRECACHE_SOUND_ARRAY(pDeathSounds); - PRECACHE_SOUND_ARRAY(pBiteSounds); - - PRECACHE_MODEL("models/headcrab.mdl"); -} - - -//========================================================= -// RunTask -//========================================================= -void CHeadCrab :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - case TASK_RANGE_ATTACK2: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - SetTouch( NULL ); - m_IdealActivity = ACT_IDLE; - } - break; - } - default: - { - CBaseMonster :: RunTask(pTask); - } - } -} - -//========================================================= -// LeapTouch - this is the headcrab's touch function when it -// is in the air -//========================================================= -void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) -{ - if ( !pOther->pev->takedamage ) - { - return; - } - - if ( pOther->Classify() == Classify() ) - { - return; - } - - // Don't hit if back on ground - if ( !FBitSet( pev->flags, FL_ONGROUND ) ) - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); - } - - SetTouch( NULL ); -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHeadCrab :: PrescheduleThink ( void ) -{ - // make the crab coo a little bit in combat state - if ( m_MonsterState == MONSTERSTATE_COMBAT && RANDOM_FLOAT( 0, 5 ) < 0.1 ) - { - IdleSound(); - } -} - -void CHeadCrab :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - m_IdealActivity = ACT_RANGE_ATTACK1; - SetTouch ( LeapTouch ); - break; - } - default: - { - CBaseMonster :: StartTask( pTask ); - } - } -} - - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CHeadCrab :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 -//========================================================= -BOOL CHeadCrab :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - return FALSE; - // BUGBUG: Why is this code here? There is no ACT_RANGE_ATTACK2 animation. I've disabled it for now. -#if 0 - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist > 64 && flDist <= 256 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -#endif -} - -int CHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if ( bitsDamageType & DMG_ACID ) - flDamage = 0; - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// IdleSound -//========================================================= -#define CRAB_ATTN_IDLE (float)1.5 -void CHeadCrab :: IdleSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab :: AlertSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab :: PainSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// DeathSound -//========================================================= -void CHeadCrab :: DeathSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -Schedule_t* CHeadCrab :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_RANGE_ATTACK1: - { - return &slHCRangeAttack1[ 0 ]; - } - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -class CBabyCrab : public CHeadCrab -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite * 0.3; } - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - Schedule_t* GetScheduleOfType ( int Type ); - virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG(40,50); } - virtual float GetSoundVolue( void ) { return 0.8; } -}; -LINK_ENTITY_TO_CLASS( monster_babycrab, CBabyCrab ); - -void CBabyCrab :: Spawn( void ) -{ - CHeadCrab::Spawn(); - SET_MODEL(ENT(pev), "models/baby_headcrab.mdl"); - pev->rendermode = kRenderTransTexture; - pev->renderamt = 192; - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - - pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown -} - -void CBabyCrab :: Precache( void ) -{ - PRECACHE_MODEL( "models/baby_headcrab.mdl" ); - CHeadCrab::Precache(); -} - - -void CBabyCrab :: SetYawSpeed ( void ) -{ - pev->yaw_speed = 120; -} - - -BOOL CBabyCrab :: CheckRangeAttack1( float flDot, float flDist ) -{ - if ( pev->flags & FL_ONGROUND ) - { - if ( pev->groundentity && (pev->groundentity->v.flags & (FL_CLIENT|FL_MONSTER)) ) - return TRUE; - - // A little less accurate, but jump from closer - if ( flDist <= 180 && flDot >= 0.55 ) - return TRUE; - } - - return FALSE; -} - - -Schedule_t* CBabyCrab :: GetScheduleOfType ( int Type ) -{ - switch( Type ) - { - case SCHED_FAIL: // If you fail, try to jump! - if ( m_hEnemy != NULL ) - return slHCRangeAttack1Fast; - break; - - case SCHED_RANGE_ATTACK1: - { - return slHCRangeAttack1Fast; - } - break; - } - - return CHeadCrab::GetScheduleOfType( Type ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// headcrab.cpp - tiny, jumpy alien parasite +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "game.h" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define HC_AE_JUMPATTACK ( 2 ) + +Task_t tlHCRangeAttack1[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_WAIT_RANDOM, (float)0.5 }, +}; + +Schedule_t slHCRangeAttack1[] = +{ + { + tlHCRangeAttack1, + ARRAYSIZE ( tlHCRangeAttack1 ), + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED, + 0, + "HCRangeAttack1" + }, +}; + +Task_t tlHCRangeAttack1Fast[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, +}; + +Schedule_t slHCRangeAttack1Fast[] = +{ + { + tlHCRangeAttack1Fast, + ARRAYSIZE ( tlHCRangeAttack1Fast ), + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED, + 0, + "HCRAFast" + }, +}; + +class CHeadCrab : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void RunTask ( Task_t *pTask ); + void StartTask ( Task_t *pTask ); + void SetYawSpeed ( void ); + void EXPORT LeapTouch ( CBaseEntity *pOther ); + Vector Center( void ); + Vector BodyTarget( const Vector &posSrc ); + void PainSound( void ); + void DeathSound( void ); + void IdleSound( void ); + void AlertSound( void ); + void PrescheduleThink( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack2 ( float flDot, float flDist ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; } + virtual int GetVoicePitch( void ) { return 100; } + virtual float GetSoundVolue( void ) { return 1.0; } + Schedule_t* GetScheduleOfType ( int Type ); + + CUSTOM_SCHEDULES; + + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + static const char *pPainSounds[]; + static const char *pAttackSounds[]; + static const char *pDeathSounds[]; + static const char *pBiteSounds[]; +}; +LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab ); + +DEFINE_CUSTOM_SCHEDULES( CHeadCrab ) +{ + slHCRangeAttack1, + slHCRangeAttack1Fast, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CHeadCrab, CBaseMonster ); + +const char *CHeadCrab::pIdleSounds[] = +{ + "headcrab/hc_idle1.wav", + "headcrab/hc_idle2.wav", + "headcrab/hc_idle3.wav", +}; +const char *CHeadCrab::pAlertSounds[] = +{ + "headcrab/hc_alert1.wav", +}; +const char *CHeadCrab::pPainSounds[] = +{ + "headcrab/hc_pain1.wav", + "headcrab/hc_pain2.wav", + "headcrab/hc_pain3.wav", +}; +const char *CHeadCrab::pAttackSounds[] = +{ + "headcrab/hc_attack1.wav", + "headcrab/hc_attack2.wav", + "headcrab/hc_attack3.wav", +}; + +const char *CHeadCrab::pDeathSounds[] = +{ + "headcrab/hc_die1.wav", + "headcrab/hc_die2.wav", +}; + +const char *CHeadCrab::pBiteSounds[] = +{ + "headcrab/hc_headbite.wav", +}; + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CHeadCrab :: Classify ( void ) +{ + return CLASS_ALIEN_PREY; +} + +//========================================================= +// Center - returns the real center of the headcrab. The +// bounding box is much larger than the actual creature so +// this is needed for targeting +//========================================================= +Vector CHeadCrab :: Center ( void ) +{ + return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 ); +} + + +Vector CHeadCrab :: BodyTarget( const Vector &posSrc ) +{ + return Center( ); +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CHeadCrab :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + ys = 30; + break; + case ACT_RUN: + case ACT_WALK: + ys = 20; + break; + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 60; + break; + case ACT_RANGE_ATTACK1: + ys = 30; + break; + default: + ys = 30; + break; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case HC_AE_JUMPATTACK: + { + ClearBits( pev->flags, FL_ONGROUND ); + + UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground + UTIL_MakeVectors ( pev->angles ); + + Vector vecJumpDir; + if (m_hEnemy != NULL) + { + float gravity = g_psv_gravity->value; + if (gravity <= 1) + gravity = 1; + + // How fast does the headcrab need to travel to reach that height given gravity? + float height = (m_hEnemy->pev->origin.z + m_hEnemy->pev->view_ofs.z - pev->origin.z); + if (height < 16) + height = 16; + float speed = sqrt( 2 * gravity * height ); + float time = speed / gravity; + + // Scale the sideways velocity to get there at the right time + vecJumpDir = (m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - pev->origin); + vecJumpDir = vecJumpDir * ( 1.0 / time ); + + // Speed to offset gravity at the desired height + vecJumpDir.z = speed; + + // Don't jump too far/fast + float distance = vecJumpDir.Length(); + + if (distance > 650) + { + vecJumpDir = vecJumpDir * ( 650.0 / distance ); + } + } + else + { + // jump hop, don't care where + vecJumpDir = Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_up.z ) * 350; + } + + int iSound = RANDOM_LONG(0,2); + if ( iSound != 0 ) + EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + + pev->velocity = vecJumpDir; + m_flNextAttack = gpGlobals->time + 2; + } + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CHeadCrab :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/headcrab.mdl"); + UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->effects = 0; + pev->health = gSkillData.headcrabHealth; + pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin. + pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CHeadCrab :: Precache() +{ + PRECACHE_SOUND_ARRAY(pIdleSounds); + PRECACHE_SOUND_ARRAY(pAlertSounds); + PRECACHE_SOUND_ARRAY(pPainSounds); + PRECACHE_SOUND_ARRAY(pAttackSounds); + PRECACHE_SOUND_ARRAY(pDeathSounds); + PRECACHE_SOUND_ARRAY(pBiteSounds); + + PRECACHE_MODEL("models/headcrab.mdl"); +} + + +//========================================================= +// RunTask +//========================================================= +void CHeadCrab :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_RANGE_ATTACK1: + case TASK_RANGE_ATTACK2: + { + if ( m_fSequenceFinished ) + { + TaskComplete(); + SetTouch( NULL ); + m_IdealActivity = ACT_IDLE; + } + break; + } + default: + { + CBaseMonster :: RunTask(pTask); + } + } +} + +//========================================================= +// LeapTouch - this is the headcrab's touch function when it +// is in the air +//========================================================= +void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) +{ + if ( !pOther->pev->takedamage ) + { + return; + } + + if ( pOther->Classify() == Classify() ) + { + return; + } + + // Don't hit if back on ground + if ( !FBitSet( pev->flags, FL_ONGROUND ) ) + { + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + + pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); + } + + SetTouch( NULL ); +} + +//========================================================= +// PrescheduleThink +//========================================================= +void CHeadCrab :: PrescheduleThink ( void ) +{ + // make the crab coo a little bit in combat state + if ( m_MonsterState == MONSTERSTATE_COMBAT && RANDOM_FLOAT( 0, 5 ) < 0.1 ) + { + IdleSound(); + } +} + +void CHeadCrab :: StartTask ( Task_t *pTask ) +{ + m_iTaskStatus = TASKSTATUS_RUNNING; + + switch ( pTask->iTask ) + { + case TASK_RANGE_ATTACK1: + { + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + m_IdealActivity = ACT_RANGE_ATTACK1; + SetTouch ( LeapTouch ); + break; + } + default: + { + CBaseMonster :: StartTask( pTask ); + } + } +} + + +//========================================================= +// CheckRangeAttack1 +//========================================================= +BOOL CHeadCrab :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack2 +//========================================================= +BOOL CHeadCrab :: CheckRangeAttack2 ( float flDot, float flDist ) +{ + return FALSE; + // BUGBUG: Why is this code here? There is no ACT_RANGE_ATTACK2 animation. I've disabled it for now. +#if 0 + if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist > 64 && flDist <= 256 && flDot >= 0.5 ) + { + return TRUE; + } + return FALSE; +#endif +} + +int CHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + // Don't take any acid damage -- BigMomma's mortar is acid + if ( bitsDamageType & DMG_ACID ) + flDamage = 0; + + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +//========================================================= +// IdleSound +//========================================================= +#define CRAB_ATTN_IDLE (float)1.5 +void CHeadCrab :: IdleSound ( void ) +{ + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); +} + +//========================================================= +// AlertSound +//========================================================= +void CHeadCrab :: AlertSound ( void ) +{ + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); +} + +//========================================================= +// AlertSound +//========================================================= +void CHeadCrab :: PainSound ( void ) +{ + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); +} + +//========================================================= +// DeathSound +//========================================================= +void CHeadCrab :: DeathSound ( void ) +{ + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); +} + +Schedule_t* CHeadCrab :: GetScheduleOfType ( int Type ) +{ + switch ( Type ) + { + case SCHED_RANGE_ATTACK1: + { + return &slHCRangeAttack1[ 0 ]; + } + break; + } + + return CBaseMonster::GetScheduleOfType( Type ); +} + + +class CBabyCrab : public CHeadCrab +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed ( void ); + float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite * 0.3; } + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + Schedule_t* GetScheduleOfType ( int Type ); + virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG(40,50); } + virtual float GetSoundVolue( void ) { return 0.8; } +}; +LINK_ENTITY_TO_CLASS( monster_babycrab, CBabyCrab ); + +void CBabyCrab :: Spawn( void ) +{ + CHeadCrab::Spawn(); + SET_MODEL(ENT(pev), "models/baby_headcrab.mdl"); + pev->rendermode = kRenderTransTexture; + pev->renderamt = 192; + UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); + + pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown +} + +void CBabyCrab :: Precache( void ) +{ + PRECACHE_MODEL( "models/baby_headcrab.mdl" ); + CHeadCrab::Precache(); +} + + +void CBabyCrab :: SetYawSpeed ( void ) +{ + pev->yaw_speed = 120; +} + + +BOOL CBabyCrab :: CheckRangeAttack1( float flDot, float flDist ) +{ + if ( pev->flags & FL_ONGROUND ) + { + if ( pev->groundentity && (pev->groundentity->v.flags & (FL_CLIENT|FL_MONSTER)) ) + return TRUE; + + // A little less accurate, but jump from closer + if ( flDist <= 180 && flDot >= 0.55 ) + return TRUE; + } + + return FALSE; +} + + +Schedule_t* CBabyCrab :: GetScheduleOfType ( int Type ) +{ + switch( Type ) + { + case SCHED_FAIL: // If you fail, try to jump! + if ( m_hEnemy != NULL ) + return slHCRangeAttack1Fast; + break; + + case SCHED_RANGE_ATTACK1: + { + return slHCRangeAttack1Fast; + } + break; + } + + return CHeadCrab::GetScheduleOfType( Type ); +} diff --git a/main/source/dlls/healthkit.cpp b/main/source/dlls/healthkit.cpp index 645b5765..ae82cbd2 100644 --- a/main/source/dlls/healthkit.cpp +++ b/main/source/dlls/healthkit.cpp @@ -1,264 +1,264 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "items.h" -#include "gamerules.h" - -extern int gmsgItemPickup; - -class CHealthKit : public CItem -{ - void Spawn( void ); - void Precache( void ); - BOOL MyTouch( CBasePlayer *pPlayer ); - -/* - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; -*/ - -}; - - -LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ); - -/* -TYPEDESCRIPTION CHealthKit::m_SaveData[] = -{ - -}; - - -IMPLEMENT_SAVERESTORE( CHealthKit, CItem); -*/ - -void CHealthKit :: Spawn( void ) -{ - Precache( ); - SET_MODEL(ENT(pev), "models/w_medkit.mdl"); - - CItem::Spawn(); -} - -void CHealthKit::Precache( void ) -{ - PRECACHE_MODEL("models/w_medkit.mdl"); - PRECACHE_SOUND("items/smallmedkit1.wav"); -} - -BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ) -{ - if ( pPlayer->pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - if ( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM); - - if ( g_pGameRules->ItemShouldRespawn( this ) ) - { - Respawn(); - } - else - { - UTIL_Remove(this); - } - - return TRUE; - } - - return FALSE; -} - - - -//------------------------------------------------------------- -// Wall mounted health kit -//------------------------------------------------------------- -class CWallHealth : public CBaseToggle -{ -public: - void Spawn( ); - void Precache( void ); - void EXPORT Off(void); - void EXPORT Recharge(void); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flNextCharge; - int m_iReactivate ; // DeathMatch Delay until reactvated - int m_iJuice; - int m_iOn; // 0 = off, 1 = startup, 2 = going - float m_flSoundTime; -}; - -TYPEDESCRIPTION CWallHealth::m_SaveData[] = -{ - DEFINE_FIELD( CWallHealth, m_flNextCharge, FIELD_TIME), - DEFINE_FIELD( CWallHealth, m_iReactivate, FIELD_INTEGER), - DEFINE_FIELD( CWallHealth, m_iJuice, FIELD_INTEGER), - DEFINE_FIELD( CWallHealth, m_iOn, FIELD_INTEGER), - DEFINE_FIELD( CWallHealth, m_flSoundTime, FIELD_TIME), -}; - -IMPLEMENT_SAVERESTORE( CWallHealth, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth); - - -void CWallHealth::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "dmdelay")) - { - m_iReactivate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CWallHealth::Spawn() -{ - Precache( ); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - m_iJuice = gSkillData.healthchargerCapacity; - pev->frame = 0; - -} - -void CWallHealth::Precache() -{ - PRECACHE_SOUND("items/medshot4.wav"); - PRECACHE_SOUND("items/medshotno1.wav"); - PRECACHE_SOUND("items/medcharge4.wav"); -} - - -void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Make sure that we have a caller - if (!pActivator) - return; - // if it's not a player, ignore - if ( !pActivator->IsPlayer() ) - return; - - // if there is no juice left, turn it off - if (m_iJuice <= 0) - { - pev->frame = 1; - Off(); - } - - // if the player doesn't have the suit, or there is no juice left, make the deny noise - if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<time) - { - m_flSoundTime = gpGlobals->time + 0.62; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM ); - } - return; - } - - pev->nextthink = pev->ltime + 0.25; - SetThink(&CWallHealth::Off); - - // Time to recharge yet? - - if (m_flNextCharge >= gpGlobals->time) - return; - - // Play the on sound or the looping charging sound - if (!m_iOn) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); - m_flSoundTime = 0.56 + gpGlobals->time; - } - if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time)) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM ); - } - - - // charge the player - if ( pActivator->TakeHealth( 1, DMG_GENERIC ) ) - { - m_iJuice--; - } - - // govern the rate of charge - m_flNextCharge = gpGlobals->time + 0.1; -} - -void CWallHealth::Recharge(void) -{ - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); - m_iJuice = gSkillData.healthchargerCapacity; - pev->frame = 0; - SetThink( &CWallHealth::SUB_DoNothing ); -} - -void CWallHealth::Off(void) -{ - // Stop looping sound. - if (m_iOn > 1) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" ); - - m_iOn = 0; - - if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) - { - pev->nextthink = pev->ltime + m_iReactivate; - SetThink(&CWallHealth::Recharge); - } - else - SetThink( &CWallHealth::SUB_DoNothing ); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "items.h" +#include "gamerules.h" + +extern int gmsgItemPickup; + +class CHealthKit : public CItem +{ + void Spawn( void ); + void Precache( void ); + BOOL MyTouch( CBasePlayer *pPlayer ); + +/* + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; +*/ + +}; + + +LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ); + +/* +TYPEDESCRIPTION CHealthKit::m_SaveData[] = +{ + +}; + + +IMPLEMENT_SAVERESTORE( CHealthKit, CItem); +*/ + +void CHealthKit :: Spawn( void ) +{ + Precache( ); + SET_MODEL(ENT(pev), "models/w_medkit.mdl"); + + CItem::Spawn(); +} + +void CHealthKit::Precache( void ) +{ + PRECACHE_MODEL("models/w_medkit.mdl"); + PRECACHE_SOUND("items/smallmedkit1.wav"); +} + +BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ) +{ + if ( pPlayer->pev->deadflag != DEAD_NO ) + { + return FALSE; + } + + if ( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); + WRITE_STRING( STRING(pev->classname) ); + MESSAGE_END(); + + EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM); + + if ( g_pGameRules->ItemShouldRespawn( this ) ) + { + Respawn(); + } + else + { + UTIL_Remove(this); + } + + return TRUE; + } + + return FALSE; +} + + + +//------------------------------------------------------------- +// Wall mounted health kit +//------------------------------------------------------------- +class CWallHealth : public CBaseToggle +{ +public: + void Spawn( ); + void Precache( void ); + void EXPORT Off(void); + void EXPORT Recharge(void); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + float m_flNextCharge; + int m_iReactivate ; // DeathMatch Delay until reactvated + int m_iJuice; + int m_iOn; // 0 = off, 1 = startup, 2 = going + float m_flSoundTime; +}; + +TYPEDESCRIPTION CWallHealth::m_SaveData[] = +{ + DEFINE_FIELD( CWallHealth, m_flNextCharge, FIELD_TIME), + DEFINE_FIELD( CWallHealth, m_iReactivate, FIELD_INTEGER), + DEFINE_FIELD( CWallHealth, m_iJuice, FIELD_INTEGER), + DEFINE_FIELD( CWallHealth, m_iOn, FIELD_INTEGER), + DEFINE_FIELD( CWallHealth, m_flSoundTime, FIELD_TIME), +}; + +IMPLEMENT_SAVERESTORE( CWallHealth, CBaseEntity ); + +LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth); + + +void CWallHealth::KeyValue( KeyValueData *pkvd ) +{ + if ( FStrEq(pkvd->szKeyName, "style") || + FStrEq(pkvd->szKeyName, "height") || + FStrEq(pkvd->szKeyName, "value1") || + FStrEq(pkvd->szKeyName, "value2") || + FStrEq(pkvd->szKeyName, "value3")) + { + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "dmdelay")) + { + m_iReactivate = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +void CWallHealth::Spawn() +{ + Precache( ); + + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + + UTIL_SetOrigin(pev, pev->origin); // set size and link into world + UTIL_SetSize(pev, pev->mins, pev->maxs); + SET_MODEL(ENT(pev), STRING(pev->model) ); + m_iJuice = gSkillData.healthchargerCapacity; + pev->frame = 0; + +} + +void CWallHealth::Precache() +{ + PRECACHE_SOUND("items/medshot4.wav"); + PRECACHE_SOUND("items/medshotno1.wav"); + PRECACHE_SOUND("items/medcharge4.wav"); +} + + +void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // Make sure that we have a caller + if (!pActivator) + return; + // if it's not a player, ignore + if ( !pActivator->IsPlayer() ) + return; + + // if there is no juice left, turn it off + if (m_iJuice <= 0) + { + pev->frame = 1; + Off(); + } + + // if the player doesn't have the suit, or there is no juice left, make the deny noise + if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<time) + { + m_flSoundTime = gpGlobals->time + 0.62; + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM ); + } + return; + } + + pev->nextthink = pev->ltime + 0.25; + SetThink(&CWallHealth::Off); + + // Time to recharge yet? + + if (m_flNextCharge >= gpGlobals->time) + return; + + // Play the on sound or the looping charging sound + if (!m_iOn) + { + m_iOn++; + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); + m_flSoundTime = 0.56 + gpGlobals->time; + } + if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time)) + { + m_iOn++; + EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM ); + } + + + // charge the player + if ( pActivator->TakeHealth( 1, DMG_GENERIC ) ) + { + m_iJuice--; + } + + // govern the rate of charge + m_flNextCharge = gpGlobals->time + 0.1; +} + +void CWallHealth::Recharge(void) +{ + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); + m_iJuice = gSkillData.healthchargerCapacity; + pev->frame = 0; + SetThink( &CWallHealth::SUB_DoNothing ); +} + +void CWallHealth::Off(void) +{ + // Stop looping sound. + if (m_iOn > 1) + STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" ); + + m_iOn = 0; + + if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) + { + pev->nextthink = pev->ltime + m_iReactivate; + SetThink(&CWallHealth::Recharge); + } + else + SetThink( &CWallHealth::SUB_DoNothing ); } \ No newline at end of file diff --git a/main/source/dlls/hgrunt.cpp b/main/source/dlls/hgrunt.cpp index 38867823..287fb1ba 100644 --- a/main/source/dlls/hgrunt.cpp +++ b/main/source/dlls/hgrunt.cpp @@ -1,2517 +1,2517 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// hgrunt -//========================================================= - -//========================================================= -// Hit groups! -//========================================================= -/* - - 1 - Head - 2 - Stomach - 3 - Gun - -*/ - - -#include "extdll.h" -#include "plane.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "squadmonster.h" -#include "weapons.h" -#include "talkmonster.h" -#include "soundent.h" -#include "effects.h" -#include "customentity.h" - -int g_fGruntQuestion; // true if an idle grunt asked a question. Cleared when someone answers. - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// monster-specific DEFINE's -//========================================================= -#define GRUNT_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x! -#define GRUNT_VOL 0.35 // volume of grunt sounds -#define GRUNT_ATTN ATTN_NORM // attenutation of grunt sentences -#define HGRUNT_LIMP_HEALTH 20 -#define HGRUNT_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot. -#define HGRUNT_NUM_HEADS 2 // how many grunt heads are there? -#define HGRUNT_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill -#define HGRUNT_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences - -#define HGRUNT_9MMAR ( 1 << 0) -#define HGRUNT_HANDGRENADE ( 1 << 1) -#define HGRUNT_GRENADELAUNCHER ( 1 << 2) -#define HGRUNT_SHOTGUN ( 1 << 3) - -#define HEAD_GROUP 1 -#define HEAD_GRUNT 0 -#define HEAD_COMMANDER 1 -#define HEAD_SHOTGUN 2 -#define HEAD_M203 3 -#define GUN_GROUP 2 -#define GUN_MP5 0 -#define GUN_SHOTGUN 1 -#define GUN_NONE 2 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HGRUNT_AE_RELOAD ( 2 ) -#define HGRUNT_AE_KICK ( 3 ) -#define HGRUNT_AE_BURST1 ( 4 ) -#define HGRUNT_AE_BURST2 ( 5 ) -#define HGRUNT_AE_BURST3 ( 6 ) -#define HGRUNT_AE_GREN_TOSS ( 7 ) -#define HGRUNT_AE_GREN_LAUNCH ( 8 ) -#define HGRUNT_AE_GREN_DROP ( 9 ) -#define HGRUNT_AE_CAUGHT_ENEMY ( 10) // grunt established sight with an enemy (player only) that had previously eluded the squad. -#define HGRUNT_AE_DROP_GUN ( 11) // grunt (probably dead) is dropping his mp5. - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_GRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way). - SCHED_GRUNT_COVER_AND_RELOAD, - SCHED_GRUNT_SWEEP, - SCHED_GRUNT_FOUND_ENEMY, - SCHED_GRUNT_REPEL, - SCHED_GRUNT_REPEL_ATTACK, - SCHED_GRUNT_REPEL_LAND, - SCHED_GRUNT_WAIT_FACE_ENEMY, - SCHED_GRUNT_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure. - SCHED_GRUNT_ELOF_FAIL, -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_GRUNT_FACE_TOSS_DIR = LAST_COMMON_TASK + 1, - TASK_GRUNT_SPEAK_SENTENCE, - TASK_GRUNT_CHECK_FIRE, -}; - -//========================================================= -// monster-specific conditions -//========================================================= -#define bits_COND_GRUNT_NOFIRE ( bits_COND_SPECIAL1 ) - -class CHGrunt : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL FCanCheckAttacks ( void ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - void CheckAmmo ( void ); - void SetActivity ( Activity NewActivity ); - void StartTask ( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - void DeathSound( void ); - void PainSound( void ); - void IdleSound ( void ); - Vector GetGunPosition( void ); - void Shoot ( void ); - void Shotgun ( void ); - void PrescheduleThink ( void ); - void GibMonster( void ); - void SpeakSentence( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CBaseEntity *Kick( void ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - int IRelationship ( CBaseEntity *pTarget ); - - BOOL FOkToSpeak( void ); - void JustSpoke( void ); - - CUSTOM_SCHEDULES; - static TYPEDESCRIPTION m_SaveData[]; - - // checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds, - // not every server frame. - float m_flNextGrenadeCheck; - float m_flNextPainTime; - float m_flLastEnemySightTime; - - Vector m_vecTossVelocity; - - BOOL m_fThrowGrenade; - BOOL m_fStanding; - BOOL m_fFirstEncounter;// only put on the handsign show in the squad's first encounter. - int m_cClipSize; - - int m_voicePitch; - - int m_iBrassShell; - int m_iShotgunShell; - - int m_iSentence; - - static const char *pGruntSentences[]; -}; - -LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt ); - -TYPEDESCRIPTION CHGrunt::m_SaveData[] = -{ - DEFINE_FIELD( CHGrunt, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CHGrunt, m_flNextPainTime, FIELD_TIME ), -// DEFINE_FIELD( CHGrunt, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero - DEFINE_FIELD( CHGrunt, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CHGrunt, m_fThrowGrenade, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_fStanding, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_fFirstEncounter, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_cClipSize, FIELD_INTEGER ), - DEFINE_FIELD( CHGrunt, m_voicePitch, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), - DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster ); - -const char *CHGrunt::pGruntSentences[] = -{ - "HG_GREN", // grenade scared grunt - "HG_ALERT", // sees player - "HG_MONSTER", // sees monster - "HG_COVER", // running to cover - "HG_THROW", // about to throw grenade - "HG_CHARGE", // running out to get the enemy - "HG_TAUNT", // say rude things -}; - -enum -{ - HGRUNT_SENT_NONE = -1, - HGRUNT_SENT_GREN = 0, - HGRUNT_SENT_ALERT, - HGRUNT_SENT_MONSTER, - HGRUNT_SENT_COVER, - HGRUNT_SENT_THROW, - HGRUNT_SENT_CHARGE, - HGRUNT_SENT_TAUNT, -} HGRUNT_SENTENCE_TYPES; - -//========================================================= -// Speak Sentence - say your cued up sentence. -// -// Some grunt sentences (take cover and charge) rely on actually -// being able to execute the intended action. It's really lame -// when a grunt says 'COVER ME' and then doesn't move. The problem -// is that the sentences were played when the decision to TRY -// to move to cover was made. Now the sentence is played after -// we know for sure that there is a valid path. The schedule -// may still fail but in most cases, well after the grunt has -// started moving. -//========================================================= -void CHGrunt :: SpeakSentence( void ) -{ - if ( m_iSentence == HGRUNT_SENT_NONE ) - { - // no sentence cued up. - return; - } - - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } -} - -//========================================================= -// IRelationship - overridden because Alien Grunts are -// Human Grunt's nemesis. -//========================================================= -int CHGrunt::IRelationship ( CBaseEntity *pTarget ) -{ - if ( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev, "monster_gargantua" ) ) ) - { - return R_NM; - } - - return CSquadMonster::IRelationship( pTarget ); -} - -//========================================================= -// GibMonster - make gun fly through the air. -//========================================================= -void CHGrunt :: GibMonster ( void ) -{ - Vector vecGunPos; - Vector vecGunAngles; - - if ( GetBodygroup( 2 ) != 2 ) - {// throw a gun if the grunt has one - GetAttachment( 0, vecGunPos, vecGunAngles ); - - CBaseEntity *pGun; - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); - } - else - { - pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); - } - if ( pGun ) - { - pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - pGun->pev->avelocity = Vector ( (float)0, (float)RANDOM_FLOAT( 200, 400 ), (float)0 ); - } - - if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) - { - pGun = DropItem( "ammo_ARgrenades", vecGunPos, vecGunAngles ); - if ( pGun ) - { - pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - pGun->pev->avelocity = Vector ( (float)0, (float)RANDOM_FLOAT( 200, 400 ), (float)0 ); - } - } - } - - CBaseMonster :: GibMonster(); -} - -//========================================================= -// ISoundMask - Overidden for human grunts because they -// hear the DANGER sound that is made by hand grenades and -// other dangerous items. -//========================================================= -int CHGrunt :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// someone else is talking - don't speak -//========================================================= -BOOL CHGrunt :: FOkToSpeak( void ) -{ -// if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - return FALSE; - - if ( pev->spawnflags & SF_MONSTER_GAG ) - { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // no talking outside of combat if gagged. - return FALSE; - } - } - - // if player is not in pvs, don't speak -// if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) -// return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -void CHGrunt :: JustSpoke( void ) -{ - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0); - m_iSentence = HGRUNT_SENT_NONE; -} - -//========================================================= -// PrescheduleThink - this function runs after conditions -// are collected and before scheduling code is run. -//========================================================= -void CHGrunt :: PrescheduleThink ( void ) -{ - if ( InSquad() && m_hEnemy != NULL ) - { - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - // update the squad's last enemy sighting time. - MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time; - } - else - { - if ( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) - { - // been a while since we've seen the enemy - MySquadLeader()->m_fEnemyEluded = TRUE; - } - } - } -} - -//========================================================= -// FCanCheckAttacks - this is overridden for human grunts -// because they can throw/shoot grenades when they can't see their -// target and the base class doesn't check attacks if the monster -// cannot see its enemy. -// -// !!!BUGBUG - this gets called before a 3-round burst is fired -// which means that a friendly can still be hit with up to 2 rounds. -// ALSO, grenades will not be tossed if there is a friendly in front, -// this is a bad bug. Friendly machine gun fire avoidance -// will unecessarily prevent the throwing of a grenade as well. -//========================================================= -BOOL CHGrunt :: FCanCheckAttacks ( void ) -{ - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CHGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - CBaseMonster *pEnemy; - - if ( m_hEnemy != NULL ) - { - pEnemy = m_hEnemy->MyMonsterPointer(); - - if ( !pEnemy ) - { - return FALSE; - } - } - - if ( flDist <= 64 && flDot >= 0.7 && - pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON && - pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 - overridden for HGrunt, cause -// FCanCheckAttacks() doesn't disqualify all attacks based -// on whether or not the enemy is occluded because unlike -// the base class, the HGrunt can attack when the enemy is -// occluded (throw grenade over wall, etc). We must -// disqualify the machine gun attack if the enemy is occluded. -//========================================================= -BOOL CHGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - - if ( !m_hEnemy->IsPlayer() && flDist <= 64 ) - { - // kick nonclients, but don't shoot at them. - return FALSE; - } - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr); - - if ( tr.flFraction == 1.0 ) - { - return TRUE; - } - } - - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - this checks the Grunt's grenade -// attack. -//========================================================= -BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if (! FBitSet(pev->weapons, (HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER))) - { - return FALSE; - } - - // if the grunt isn't moving, it's ok to check. - if ( m_flGroundSpeed != 0 ) - { - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - // assume things haven't changed too much since last time - if (gpGlobals->time < m_flNextGrenadeCheck ) - { - return m_fThrowGrenade; - } - - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z ) - { - //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to - // be grenaded. - // don't throw grenades at anything that isn't on the ground! - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - Vector vecTarget; - - if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) - { - // find feet - if (RANDOM_LONG(0,1)) - { - // magically know where they are - vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z ); - } - else - { - // toss it to where you last saw them - vecTarget = m_vecEnemyLKP; - } - // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2; - } - else - { - // find target - // vecTarget = m_hEnemy->BodyTarget( pev->origin ); - vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - if (HasConditions( bits_COND_SEE_ENEMY)) - vecTarget = vecTarget + ((vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed) * m_hEnemy->pev->velocity; - } - - // are any of my squad members near the intended grenade impact area? - if ( InSquad() ) - { - if (SquadMemberInRange( vecTarget, 256 )) - { - // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - } - } - - if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) - { - // crap, I don't want to blow myself up - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - - if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) - { - Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - else - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - - - - return m_fThrowGrenade; -} - - -//========================================================= -// TraceAttack - make sure we're not taking it in the helmet -//========================================================= -void CHGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // check for helmet shot - if (ptr->iHitgroup == 11) - { - // make sure we're wearing one - if (GetBodygroup( 1 ) == HEAD_GRUNT && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB))) - { - // absorb damage - flDamage -= 20; - if (flDamage <= 0) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // it's head shot anyways - ptr->iHitgroup = HITGROUP_HEAD; - } - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -//========================================================= -// TakeDamage - overridden for the grunt because the grunt -// needs to forget that he is in cover if he's hurt. (Obviously -// not in a safe place anymore). -//========================================================= -int CHGrunt :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Forget( bits_MEMORY_INCOVER ); - - return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHGrunt :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 150; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RANGE_ATTACK1: - ys = 120; - break; - case ACT_RANGE_ATTACK2: - ys = 120; - break; - case ACT_MELEE_ATTACK1: - ys = 120; - break; - case ACT_MELEE_ATTACK2: - ys = 120; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_GLIDE: - case ACT_FLY: - ys = 30; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -void CHGrunt :: IdleSound( void ) -{ - if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1))) - { - if (!g_fGruntQuestion) - { - // ask question or make statement - switch (RANDOM_LONG(0,2)) - { - case 0: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - g_fGruntQuestion = 1; - break; - case 1: // question - SENTENCEG_PlayRndSz(ENT(pev), "HG_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - g_fGruntQuestion = 2; - break; - case 2: // statement - SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - } - } - else - { - switch (g_fGruntQuestion) - { - case 1: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - case 2: // question - SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - } - g_fGruntQuestion = 0; - } - JustSpoke(); - } -} - -//========================================================= -// CheckAmmo - overridden for the grunt because he actually -// uses ammo! (base class doesn't) -//========================================================= -void CHGrunt :: CheckAmmo ( void ) -{ - if ( m_cAmmoLoaded <= 0 ) - { - SetConditions(bits_COND_NO_AMMO_LOADED); - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHGrunt :: Classify ( void ) -{ - return CLASS_HUMAN_MILITARY; -} - -//========================================================= -//========================================================= -CBaseEntity *CHGrunt :: Kick( void ) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + (gpGlobals->v_forward * 70); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - return pEntity; - } - - return NULL; -} - -//========================================================= -// GetGunPosition return the end of the barrel -//========================================================= - -Vector CHGrunt :: GetGunPosition( ) -{ - if (m_fStanding ) - { - return pev->origin + Vector( 0, 0, 60 ); - } - else - { - return pev->origin + Vector( 0, 0, 48 ); - } -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt :: Shoot ( void ) -{ - if (m_hEnemy == NULL) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5 ); // shoot +-5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt :: Shotgun ( void ) -{ - if (m_hEnemy == NULL) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL); - FireBullets(gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - Vector vecShootDir; - Vector vecShootOrigin; - - switch( pEvent->event ) - { - case HGRUNT_AE_DROP_GUN: - { - Vector vecGunPos; - Vector vecGunAngles; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - // switch to body group with no gun. - SetBodygroup( GUN_GROUP, GUN_NONE ); - - // now spawn a gun. - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); - } - else - { - DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); - } - if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) - { - DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles ); - } - - } - break; - - case HGRUNT_AE_RELOAD: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM ); - m_cAmmoLoaded = m_cClipSize; - ClearConditions(bits_COND_NO_AMMO_LOADED); - break; - - case HGRUNT_AE_GREN_TOSS: - { - UTIL_MakeVectors( pev->angles ); - // CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 ); - CGrenade::ShootTimed( pev, GetGunPosition(), m_vecTossVelocity, 3.5 ); - - m_fThrowGrenade = FALSE; - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - // !!!LATER - when in a group, only try to throw grenade if ordered. - } - break; - - case HGRUNT_AE_GREN_LAUNCH: - { - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM); - CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity ); - m_fThrowGrenade = FALSE; - if (g_iSkillLevel == SKILL_HARD) - m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 );// wait a random amount of time before shooting again - else - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - } - break; - - case HGRUNT_AE_GREN_DROP: - { - UTIL_MakeVectors( pev->angles ); - CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 17 - gpGlobals->v_right * 27 + gpGlobals->v_up * 6, g_vecZero, 3 ); - } - break; - - case HGRUNT_AE_BURST1: - { - if ( FBitSet( pev->weapons, HGRUNT_9MMAR )) - { - Shoot(); - - // the first round of the three round burst plays the sound and puts a sound in the world sound list. - if ( RANDOM_LONG(0,1) ) - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM ); - } - else - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM ); - } - } - else - { - Shotgun( ); - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); - } - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); - } - break; - - case HGRUNT_AE_BURST2: - case HGRUNT_AE_BURST3: - Shoot(); - break; - - case HGRUNT_AE_KICK: - { - CBaseEntity *pHurt = Kick(); - - if ( pHurt ) - { - // SOUND HERE! - UTIL_MakeVectors( pev->angles ); - pHurt->pev->punchangle.x = 15; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50; - pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB ); - } - } - break; - - case HGRUNT_AE_CAUGHT_ENEMY: - { - if ( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - - } - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHGrunt :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/hgrunt.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = 0; - pev->health = gSkillData.hgruntHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flNextGrenadeCheck = gpGlobals->time + 1; - m_flNextPainTime = gpGlobals->time; - m_iSentence = HGRUNT_SENT_NONE; - - m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - m_fEnemyEluded = FALSE; - m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet. - - m_HackedGunPos = Vector ( 0, 0, 55 ); - - if (pev->weapons == 0) - { - // initialize to original values - pev->weapons = HGRUNT_9MMAR | HGRUNT_HANDGRENADE; - // pev->weapons = HGRUNT_SHOTGUN; - // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER; - } - - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); - m_cClipSize = 8; - } - else - { - m_cClipSize = GRUNT_CLIP_SIZE; - } - m_cAmmoLoaded = m_cClipSize; - - if (RANDOM_LONG( 0, 99 ) < 80) - pev->skin = 0; // light skin - else - pev->skin = 1; // dark skin - - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN); - } - else if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) - { - SetBodygroup( HEAD_GROUP, HEAD_M203 ); - pev->skin = 1; // alway dark skin - } - - CTalkMonster::g_talkWaitTime = 0; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHGrunt :: Precache() -{ - PRECACHE_MODEL("models/hgrunt.mdl"); - - PRECACHE_SOUND( "hgrunt/gr_mgun1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_mgun2.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_die1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_die2.wav" ); - PRECACHE_SOUND( "hgrunt/gr_die3.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_pain1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain2.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain3.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain4.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain5.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_reload1.wav" ); - - PRECACHE_SOUND( "weapons/glauncher.wav" ); - - PRECACHE_SOUND( "weapons/sbarrel1.wav" ); - - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event - - // get voice pitch - if (RANDOM_LONG(0,1)) - m_voicePitch = 109 + RANDOM_LONG(0,7); - else - m_voicePitch = 100; - - m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl"); -} - -//========================================================= -// start task -//========================================================= -void CHGrunt :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_GRUNT_CHECK_FIRE: - if ( !NoFriendlyFire() ) - { - SetConditions( bits_COND_GRUNT_NOFIRE ); - } - TaskComplete(); - break; - - case TASK_GRUNT_SPEAK_SENTENCE: - SpeakSentence(); - TaskComplete(); - break; - - case TASK_WALK_PATH: - case TASK_RUN_PATH: - // grunt no longer assumes he is covered if he moves - Forget( bits_MEMORY_INCOVER ); - CSquadMonster ::StartTask( pTask ); - break; - - case TASK_RELOAD: - m_IdealActivity = ACT_RELOAD; - break; - - case TASK_GRUNT_FACE_TOSS_DIR: - break; - - case TASK_FACE_IDEAL: - case TASK_FACE_ENEMY: - CSquadMonster :: StartTask( pTask ); - if (pev->movetype == MOVETYPE_FLY) - { - m_IdealActivity = ACT_GLIDE; - } - break; - - default: - CSquadMonster :: StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CHGrunt :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_GRUNT_FACE_TOSS_DIR: - { - // project a point along the toss vector and turn to face that point. - MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CSquadMonster :: RunTask( pTask ); - break; - } - } -} - -//========================================================= -// PainSound -//========================================================= -void CHGrunt :: PainSound ( void ) -{ - if ( gpGlobals->time > m_flNextPainTime ) - { -#if 0 - if ( RANDOM_LONG(0,99) < 5 ) - { - // pain sentences are rare - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM); - JustSpoke(); - return; - } - } -#endif - switch ( RANDOM_LONG(0,6) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain5.wav", 1, ATTN_NORM ); - break; - case 3: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain1.wav", 1, ATTN_NORM ); - break; - case 4: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); - break; - } - - m_flNextPainTime = gpGlobals->time + 1; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CHGrunt :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die2.wav", 1, ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); - break; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// GruntFail -//========================================================= -Task_t tlGruntFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slGruntFail[] = -{ - { - tlGruntFail, - ARRAYSIZE ( tlGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - 0, - "Grunt Fail" - }, -}; - -//========================================================= -// Grunt Combat Fail -//========================================================= -Task_t tlGruntCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slGruntCombatFail[] = -{ - { - tlGruntCombatFail, - ARRAYSIZE ( tlGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Grunt Combat Fail" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlGruntVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, -}; - -Schedule_t slGruntVictoryDance[] = -{ - { - tlGruntVictoryDance, - ARRAYSIZE ( tlGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "GruntVictoryDance" - }, -}; - -//========================================================= -// Establish line of fire - move to a position that allows -// the grunt to attack. -//========================================================= -Task_t tlGruntEstablishLineOfFire[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_ELOF_FAIL }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_GRUNT_SPEAK_SENTENCE,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slGruntEstablishLineOfFire[] = -{ - { - tlGruntEstablishLineOfFire, - ARRAYSIZE ( tlGruntEstablishLineOfFire ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "GruntEstablishLineOfFire" - }, -}; - -//========================================================= -// GruntFoundEnemy - grunt established sight with an enemy -// that was hiding from the squad. -//========================================================= -Task_t tlGruntFoundEnemy[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1 }, -}; - -Schedule_t slGruntFoundEnemy[] = -{ - { - tlGruntFoundEnemy, - ARRAYSIZE ( tlGruntFoundEnemy ), - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "GruntFoundEnemy" - }, -}; - -//========================================================= -// GruntCombatFace Schedule -//========================================================= -Task_t tlGruntCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_SWEEP }, -}; - -Schedule_t slGruntCombatFace[] = -{ - { - tlGruntCombatFace1, - ARRAYSIZE ( tlGruntCombatFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Suppressing fire - don't stop shooting until the clip is -// empty or grunt gets hurt. -//========================================================= -Task_t tlGruntSignalSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntSignalSuppress[] = -{ - { - tlGruntSignalSuppress, - ARRAYSIZE ( tlGruntSignalSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "SignalSuppress" - }, -}; - -Task_t tlGruntSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntSuppress[] = -{ - { - tlGruntSuppress, - ARRAYSIZE ( tlGruntSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Suppress" - }, -}; - - -//========================================================= -// grunt wait in cover - we don't allow danger or the ability -// to attack to break a grunt's run to cover schedule, but -// when a grunt is in cover, we do want them to attack if they can. -//========================================================= -Task_t tlGruntWaitInCover[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slGruntWaitInCover[] = -{ - { - tlGruntWaitInCover, - ARRAYSIZE ( tlGruntWaitInCover ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - - bits_SOUND_DANGER, - "GruntWaitInCover" - }, -}; - -//========================================================= -// run to cover. -// !!!BUGBUG - set a decent fail schedule here. -//========================================================= -Task_t tlGruntTakeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_TAKECOVER_FAILED }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_GRUNT_SPEAK_SENTENCE, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, -}; - -Schedule_t slGruntTakeCover[] = -{ - { - tlGruntTakeCover1, - ARRAYSIZE ( tlGruntTakeCover1 ), - 0, - 0, - "TakeCover" - }, -}; - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlGruntGrenadeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)99 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_PLAY_SEQUENCE, (float)ACT_SPECIAL_ATTACK1 }, - { TASK_CLEAR_MOVE_WAIT, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, -}; - -Schedule_t slGruntGrenadeCover[] = -{ - { - tlGruntGrenadeCover1, - ARRAYSIZE ( tlGruntGrenadeCover1 ), - 0, - 0, - "GrenadeCover" - }, -}; - - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlGruntTossGrenadeCover1[] = -{ - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slGruntTossGrenadeCover[] = -{ - { - tlGruntTossGrenadeCover1, - ARRAYSIZE ( tlGruntTossGrenadeCover1 ), - 0, - 0, - "TossGrenadeCover" - }, -}; - -//========================================================= -// hide from the loudest sound source (to run from grenade) -//========================================================= -Task_t tlGruntTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_COWER },// duck and cover if cannot move from explosion - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slGruntTakeCoverFromBestSound[] = -{ - { - tlGruntTakeCoverFromBestSound, - ARRAYSIZE ( tlGruntTakeCoverFromBestSound ), - 0, - 0, - "GruntTakeCoverFromBestSound" - }, -}; - -//========================================================= -// Grunt reload schedule -//========================================================= -Task_t tlGruntHideReload[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RELOAD }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RELOAD }, -}; - -Schedule_t slGruntHideReload[] = -{ - { - tlGruntHideReload, - ARRAYSIZE ( tlGruntHideReload ), - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "GruntHideReload" - } -}; - -//========================================================= -// Do a turning sweep of the area -//========================================================= -Task_t tlGruntSweep[] = -{ - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slGruntSweep[] = -{ - { - tlGruntSweep, - ARRAYSIZE ( tlGruntSweep ), - - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_WORLD |// sound flags - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - - "Grunt Sweep" - }, -}; - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack1A[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntRangeAttack1A[] = -{ - { - tlGruntRangeAttack1A, - ARRAYSIZE ( tlGruntRangeAttack1A ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Range Attack1A" - }, -}; - - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack1B[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntRangeAttack1B[] = -{ - { - tlGruntRangeAttack1B, - ARRAYSIZE ( tlGruntRangeAttack1B ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_GRUNT_NOFIRE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack1B" - }, -}; - -//========================================================= -// secondary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_GRUNT_FACE_TOSS_DIR, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RANGE_ATTACK2 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY },// don't run immediately after throwing grenade. -}; - -Schedule_t slGruntRangeAttack2[] = -{ - { - tlGruntRangeAttack2, - ARRAYSIZE ( tlGruntRangeAttack2 ), - 0, - 0, - "RangeAttack2" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlGruntRepel[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, -}; - -Schedule_t slGruntRepel[] = -{ - { - tlGruntRepel, - ARRAYSIZE ( tlGruntRepel ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlGruntRepelAttack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, -}; - -Schedule_t slGruntRepelAttack[] = -{ - { - tlGruntRepelAttack, - ARRAYSIZE ( tlGruntRepelAttack ), - bits_COND_ENEMY_OCCLUDED, - 0, - "Repel Attack" - }, -}; - -//========================================================= -// repel land -//========================================================= -Task_t tlGruntRepelLand[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_LAND }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slGruntRepelLand[] = -{ - { - tlGruntRepelLand, - ARRAYSIZE ( tlGruntRepelLand ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel Land" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CHGrunt ) -{ - slGruntFail, - slGruntCombatFail, - slGruntVictoryDance, - slGruntEstablishLineOfFire, - slGruntFoundEnemy, - slGruntCombatFace, - slGruntSignalSuppress, - slGruntSuppress, - slGruntWaitInCover, - slGruntTakeCover, - slGruntGrenadeCover, - slGruntTossGrenadeCover, - slGruntTakeCoverFromBestSound, - slGruntHideReload, - slGruntSweep, - slGruntRangeAttack1A, - slGruntRangeAttack1B, - slGruntRangeAttack2, - slGruntRepel, - slGruntRepelAttack, - slGruntRepelLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ); - -//========================================================= -// SetActivity -//========================================================= -void CHGrunt :: SetActivity ( Activity NewActivity ) -{ - int iSequence = ACTIVITY_NOT_AVAILABLE; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - switch ( NewActivity) - { - case ACT_RANGE_ATTACK1: - // grunt is either shooting standing or shooting crouched - if (FBitSet( pev->weapons, HGRUNT_9MMAR)) - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_mp5" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_mp5" ); - } - } - else - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_shotgun" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_shotgun" ); - } - } - break; - case ACT_RANGE_ATTACK2: - // grunt is going to a secondary long range attack. This may be a thrown - // grenade or fired grenade, we must determine which and pick proper sequence - if ( pev->weapons & HGRUNT_HANDGRENADE ) - { - // get toss anim - iSequence = LookupSequence( "throwgrenade" ); - } - else - { - // get launch anim - iSequence = LookupSequence( "launchgrenade" ); - } - break; - case ACT_RUN: - if ( pev->health <= HGRUNT_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_RUN_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_WALK: - if ( pev->health <= HGRUNT_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_WALK_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_IDLE: - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - NewActivity = ACT_IDLE_ANGRY; - } - iSequence = LookupActivity ( NewActivity ); - break; - default: - iSequence = LookupActivity ( NewActivity ); - break; - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} - -//========================================================= -// Get Schedule! -//========================================================= -Schedule_t *CHGrunt :: GetSchedule( void ) -{ - - // clear old sentence - m_iSentence = HGRUNT_SENT_NONE; - - // flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling. - if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE ) - { - if (pev->flags & FL_ONGROUND) - { - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_GRUNT_REPEL_LAND ); - } - else - { - // repel down a rope, - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_GRUNT_REPEL_ATTACK ); - else - return GetScheduleOfType ( SCHED_GRUNT_REPEL ); - } - } - - // grunts place HIGH priority on running away from danger sounds. - if ( HasConditions(bits_COND_HEAR_SOUND) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound) - { - if (pSound->m_iType & bits_SOUND_DANGER) - { - // dangerous sound nearby! - - //!!!KELLY - currently, this is the grunt's signal that a grenade has landed nearby, - // and the grunt should find cover from the blast - // good place for "SHIT!" or some other colorful verbal indicator of dismay. - // It's not safe to play a verbal order here "Scatter", etc cause - // this may only affect a single individual in a squad. - - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_GREN", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - /* - if (!HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & (bits_SOUND_PLAYER | bits_SOUND_COMBAT) )) - { - MakeIdealYaw( pSound->m_vecOrigin ); - } - */ - } - } - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - -// new enemy - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - if ( InSquad() ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - - if ( !IsLeader() ) - { - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - //!!!KELLY - the leader of a squad of grunts has just seen the player or a - // monster and has made it the squad's enemy. You - // can check pev->flags for FL_CLIENT to determine whether this is the player - // or a monster. He's going to immediately start - // firing, though. If you'd like, we can make an alternate "first sight" - // schedule where the leader plays a handsign anim - // that gives us enough time to hear a short sentence or spoken command - // before he starts pluggin away. - if (FOkToSpeak())// && RANDOM_LONG(0,1)) - { - if ((m_hEnemy != NULL) && m_hEnemy->IsPlayer()) - // player - SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - else if ((m_hEnemy != NULL) && - (m_hEnemy->Classify() != CLASS_PLAYER_ALLY) && - (m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) && - (m_hEnemy->Classify() != CLASS_MACHINE)) - // monster - SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - - JustSpoke(); - } - - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS ); - } - else - { - return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - } - } - } -// no ammo - else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) - { - //!!!KELLY - this individual just realized he's out of bullet ammo. - // He's going to try to find cover to run to and reload, but rarely, if - // none is available, he'll drop and reload in the open here. - return GetScheduleOfType ( SCHED_GRUNT_COVER_AND_RELOAD ); - } - -// damaged just a little - else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) ) - { - // if hurt: - // 90% chance of taking cover - // 10% chance of flinch. - int iPercent = RANDOM_LONG(0,99); - - if ( iPercent <= 90 && m_hEnemy != NULL ) - { - // only try to take cover if we actually have an enemy! - - //!!!KELLY - this grunt was hit and is going to run to cover. - if (FOkToSpeak()) // && RANDOM_LONG(0,1)) - { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - m_iSentence = HGRUNT_SENT_COVER; - //JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - } -// can kick - else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } -// can grenade launch - - else if ( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER) && HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // shoot a grenade if you can - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } -// can shoot - else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if ( InSquad() ) - { - // if the enemy has eluded the squad and a squad member has just located the enemy - // and the enemy does not see the squad member, issue a call to the squad to waste a - // little time and give the player a chance to turn. - if ( MySquadLeader()->m_fEnemyEluded && !HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - return GetScheduleOfType ( SCHED_GRUNT_FOUND_ENEMY ); - } - } - - if ( OccupySlot ( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - // try to take an available ENGAGE slot - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // throw a grenade if can and no engage slots are available - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else - { - // hide! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } -// can't see enemy - else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - //!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else if ( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - //!!!KELLY - grunt cannot see the enemy and has just decided to - // charge the enemy's position. - if (FOkToSpeak())// && RANDOM_LONG(0,1)) - { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - m_iSentence = HGRUNT_SENT_CHARGE; - //JustSpoke(); - } - - return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - else - { - //!!!KELLY - grunt is going to stay put for a couple seconds to see if - // the enemy wanders back out into the open, or approaches the - // grunt's covered position. Good place for a taunt, I guess? - if (FOkToSpeak() && RANDOM_LONG(0,1)) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_TAUNT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_STANDOFF ); - } - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - } - } - - // no special cases here, call the base class - return CSquadMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CHGrunt :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - { - if ( InSquad() ) - { - if ( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return slGruntTossGrenadeCover; - } - else - { - return &slGruntTakeCover[ 0 ]; - } - } - else - { - if ( RANDOM_LONG(0,1) ) - { - return &slGruntTakeCover[ 0 ]; - } - else - { - return &slGruntGrenadeCover[ 0 ]; - } - } - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slGruntTakeCoverFromBestSound[ 0 ]; - } - case SCHED_GRUNT_TAKECOVER_FAILED: - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType ( SCHED_FAIL ); - } - break; - case SCHED_GRUNT_ELOF_FAIL: - { - // human grunt is unable to move to a position that allows him to attack the enemy. - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: - { - return &slGruntEstablishLineOfFire[ 0 ]; - } - break; - case SCHED_RANGE_ATTACK1: - { - // randomly stand or crouch - if (RANDOM_LONG(0,9) == 0) - m_fStanding = RANDOM_LONG(0,1); - - if (m_fStanding) - return &slGruntRangeAttack1B[ 0 ]; - else - return &slGruntRangeAttack1A[ 0 ]; - } - case SCHED_RANGE_ATTACK2: - { - return &slGruntRangeAttack2[ 0 ]; - } - case SCHED_COMBAT_FACE: - { - return &slGruntCombatFace[ 0 ]; - } - case SCHED_GRUNT_WAIT_FACE_ENEMY: - { - return &slGruntWaitInCover[ 0 ]; - } - case SCHED_GRUNT_SWEEP: - { - return &slGruntSweep[ 0 ]; - } - case SCHED_GRUNT_COVER_AND_RELOAD: - { - return &slGruntHideReload[ 0 ]; - } - case SCHED_GRUNT_FOUND_ENEMY: - { - return &slGruntFoundEnemy[ 0 ]; - } - case SCHED_VICTORY_DANCE: - { - if ( InSquad() ) - { - if ( !IsLeader() ) - { - return &slGruntFail[ 0 ]; - } - } - - return &slGruntVictoryDance[ 0 ]; - } - case SCHED_GRUNT_SUPPRESS: - { - if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) - { - m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return &slGruntSignalSuppress[ 0 ]; - } - else - { - return &slGruntSuppress[ 0 ]; - } - } - case SCHED_FAIL: - { - if ( m_hEnemy != NULL ) - { - // grunt has an enemy, so pick a different default fail schedule most likely to help recover. - return &slGruntCombatFail[ 0 ]; - } - - return &slGruntFail[ 0 ]; - } - case SCHED_GRUNT_REPEL: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slGruntRepel[ 0 ]; - } - case SCHED_GRUNT_REPEL_ATTACK: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slGruntRepelAttack[ 0 ]; - } - case SCHED_GRUNT_REPEL_LAND: - { - return &slGruntRepelLand[ 0 ]; - } - default: - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } -} - - -//========================================================= -// CHGruntRepel - when triggered, spawns a monster_human_grunt -// repelling down a line. -//========================================================= - -class CHGruntRepel : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_iSpriteTexture; // Don't save, precache -}; - -LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ); - -void CHGruntRepel::Spawn( void ) -{ - Precache( ); - pev->solid = SOLID_NOT; - - SetUse( &CHGruntRepel::RepelUse ); -} - -void CHGruntRepel::Precache( void ) -{ - UTIL_PrecacheOther( "monster_human_grunt" ); - m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); -} - -void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( (int)0, (int)0, (int)-4096.0), dont_ignore_monsters, ENT(pev), &tr); - /* - if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) - return NULL; - */ - - CBaseEntity *pEntity = Create( "monster_human_grunt", pev->origin, pev->angles ); - CBaseMonster *pGrunt = pEntity->MyMonsterPointer( ); - pGrunt->pev->movetype = MOVETYPE_FLY; - pGrunt->pev->velocity = Vector( (float)0, (float)0, (float)RANDOM_FLOAT( -196, -128 ) ); - pGrunt->SetActivity( ACT_GLIDE ); - // UNDONE: position? - pGrunt->m_vecLastPosition = tr.vecEndPos; - - CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); - pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() ); - pBeam->SetFlags( BEAM_FSOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &CHGruntRepel::SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; - - UTIL_Remove( this ); -} - - - -//========================================================= -// DEAD HGRUNT PROP -//========================================================= -class CDeadHGrunt : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[3]; -}; - -char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; - -void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ); - -//========================================================= -// ********** DeadHGrunt SPAWN ********** -//========================================================= -void CDeadHGrunt :: Spawn( void ) -{ - PRECACHE_MODEL("models/hgrunt.mdl"); - SET_MODEL(ENT(pev), "models/hgrunt.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead hgrunt with bad pose\n" ); - } - - // Corpses have less health - pev->health = 8; - - // map old bodies onto new bodies - switch( pev->body ) - { - case 0: // Grunt with Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 1: // Commander with Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 2: // Grunt no Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - case 3: // Commander no Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - } - - MonsterInitDead(); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// hgrunt +//========================================================= + +//========================================================= +// Hit groups! +//========================================================= +/* + + 1 - Head + 2 - Stomach + 3 - Gun + +*/ + + +#include "extdll.h" +#include "plane.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "animation.h" +#include "squadmonster.h" +#include "weapons.h" +#include "talkmonster.h" +#include "soundent.h" +#include "effects.h" +#include "customentity.h" + +int g_fGruntQuestion; // true if an idle grunt asked a question. Cleared when someone answers. + +extern DLL_GLOBAL int g_iSkillLevel; + +//========================================================= +// monster-specific DEFINE's +//========================================================= +#define GRUNT_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x! +#define GRUNT_VOL 0.35 // volume of grunt sounds +#define GRUNT_ATTN ATTN_NORM // attenutation of grunt sentences +#define HGRUNT_LIMP_HEALTH 20 +#define HGRUNT_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot. +#define HGRUNT_NUM_HEADS 2 // how many grunt heads are there? +#define HGRUNT_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill +#define HGRUNT_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences + +#define HGRUNT_9MMAR ( 1 << 0) +#define HGRUNT_HANDGRENADE ( 1 << 1) +#define HGRUNT_GRENADELAUNCHER ( 1 << 2) +#define HGRUNT_SHOTGUN ( 1 << 3) + +#define HEAD_GROUP 1 +#define HEAD_GRUNT 0 +#define HEAD_COMMANDER 1 +#define HEAD_SHOTGUN 2 +#define HEAD_M203 3 +#define GUN_GROUP 2 +#define GUN_MP5 0 +#define GUN_SHOTGUN 1 +#define GUN_NONE 2 + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define HGRUNT_AE_RELOAD ( 2 ) +#define HGRUNT_AE_KICK ( 3 ) +#define HGRUNT_AE_BURST1 ( 4 ) +#define HGRUNT_AE_BURST2 ( 5 ) +#define HGRUNT_AE_BURST3 ( 6 ) +#define HGRUNT_AE_GREN_TOSS ( 7 ) +#define HGRUNT_AE_GREN_LAUNCH ( 8 ) +#define HGRUNT_AE_GREN_DROP ( 9 ) +#define HGRUNT_AE_CAUGHT_ENEMY ( 10) // grunt established sight with an enemy (player only) that had previously eluded the squad. +#define HGRUNT_AE_DROP_GUN ( 11) // grunt (probably dead) is dropping his mp5. + +//========================================================= +// monster-specific schedule types +//========================================================= +enum +{ + SCHED_GRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, + SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way). + SCHED_GRUNT_COVER_AND_RELOAD, + SCHED_GRUNT_SWEEP, + SCHED_GRUNT_FOUND_ENEMY, + SCHED_GRUNT_REPEL, + SCHED_GRUNT_REPEL_ATTACK, + SCHED_GRUNT_REPEL_LAND, + SCHED_GRUNT_WAIT_FACE_ENEMY, + SCHED_GRUNT_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure. + SCHED_GRUNT_ELOF_FAIL, +}; + +//========================================================= +// monster-specific tasks +//========================================================= +enum +{ + TASK_GRUNT_FACE_TOSS_DIR = LAST_COMMON_TASK + 1, + TASK_GRUNT_SPEAK_SENTENCE, + TASK_GRUNT_CHECK_FIRE, +}; + +//========================================================= +// monster-specific conditions +//========================================================= +#define bits_COND_GRUNT_NOFIRE ( bits_COND_SPECIAL1 ) + +class CHGrunt : public CSquadMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed ( void ); + int Classify ( void ); + int ISoundMask ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + BOOL FCanCheckAttacks ( void ); + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack2 ( float flDot, float flDist ); + void CheckAmmo ( void ); + void SetActivity ( Activity NewActivity ); + void StartTask ( Task_t *pTask ); + void RunTask ( Task_t *pTask ); + void DeathSound( void ); + void PainSound( void ); + void IdleSound ( void ); + Vector GetGunPosition( void ); + void Shoot ( void ); + void Shotgun ( void ); + void PrescheduleThink ( void ); + void GibMonster( void ); + void SpeakSentence( void ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + + CBaseEntity *Kick( void ); + Schedule_t *GetSchedule( void ); + Schedule_t *GetScheduleOfType ( int Type ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + int IRelationship ( CBaseEntity *pTarget ); + + BOOL FOkToSpeak( void ); + void JustSpoke( void ); + + CUSTOM_SCHEDULES; + static TYPEDESCRIPTION m_SaveData[]; + + // checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds, + // not every server frame. + float m_flNextGrenadeCheck; + float m_flNextPainTime; + float m_flLastEnemySightTime; + + Vector m_vecTossVelocity; + + BOOL m_fThrowGrenade; + BOOL m_fStanding; + BOOL m_fFirstEncounter;// only put on the handsign show in the squad's first encounter. + int m_cClipSize; + + int m_voicePitch; + + int m_iBrassShell; + int m_iShotgunShell; + + int m_iSentence; + + static const char *pGruntSentences[]; +}; + +LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt ); + +TYPEDESCRIPTION CHGrunt::m_SaveData[] = +{ + DEFINE_FIELD( CHGrunt, m_flNextGrenadeCheck, FIELD_TIME ), + DEFINE_FIELD( CHGrunt, m_flNextPainTime, FIELD_TIME ), +// DEFINE_FIELD( CHGrunt, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero + DEFINE_FIELD( CHGrunt, m_vecTossVelocity, FIELD_VECTOR ), + DEFINE_FIELD( CHGrunt, m_fThrowGrenade, FIELD_BOOLEAN ), + DEFINE_FIELD( CHGrunt, m_fStanding, FIELD_BOOLEAN ), + DEFINE_FIELD( CHGrunt, m_fFirstEncounter, FIELD_BOOLEAN ), + DEFINE_FIELD( CHGrunt, m_cClipSize, FIELD_INTEGER ), + DEFINE_FIELD( CHGrunt, m_voicePitch, FIELD_INTEGER ), +// DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ), +// DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), + DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster ); + +const char *CHGrunt::pGruntSentences[] = +{ + "HG_GREN", // grenade scared grunt + "HG_ALERT", // sees player + "HG_MONSTER", // sees monster + "HG_COVER", // running to cover + "HG_THROW", // about to throw grenade + "HG_CHARGE", // running out to get the enemy + "HG_TAUNT", // say rude things +}; + +enum +{ + HGRUNT_SENT_NONE = -1, + HGRUNT_SENT_GREN = 0, + HGRUNT_SENT_ALERT, + HGRUNT_SENT_MONSTER, + HGRUNT_SENT_COVER, + HGRUNT_SENT_THROW, + HGRUNT_SENT_CHARGE, + HGRUNT_SENT_TAUNT, +} HGRUNT_SENTENCE_TYPES; + +//========================================================= +// Speak Sentence - say your cued up sentence. +// +// Some grunt sentences (take cover and charge) rely on actually +// being able to execute the intended action. It's really lame +// when a grunt says 'COVER ME' and then doesn't move. The problem +// is that the sentences were played when the decision to TRY +// to move to cover was made. Now the sentence is played after +// we know for sure that there is a valid path. The schedule +// may still fail but in most cases, well after the grunt has +// started moving. +//========================================================= +void CHGrunt :: SpeakSentence( void ) +{ + if ( m_iSentence == HGRUNT_SENT_NONE ) + { + // no sentence cued up. + return; + } + + if (FOkToSpeak()) + { + SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + JustSpoke(); + } +} + +//========================================================= +// IRelationship - overridden because Alien Grunts are +// Human Grunt's nemesis. +//========================================================= +int CHGrunt::IRelationship ( CBaseEntity *pTarget ) +{ + if ( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev, "monster_gargantua" ) ) ) + { + return R_NM; + } + + return CSquadMonster::IRelationship( pTarget ); +} + +//========================================================= +// GibMonster - make gun fly through the air. +//========================================================= +void CHGrunt :: GibMonster ( void ) +{ + Vector vecGunPos; + Vector vecGunAngles; + + if ( GetBodygroup( 2 ) != 2 ) + {// throw a gun if the grunt has one + GetAttachment( 0, vecGunPos, vecGunAngles ); + + CBaseEntity *pGun; + if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + { + pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); + } + else + { + pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); + } + if ( pGun ) + { + pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); + pGun->pev->avelocity = Vector ( (float)0, (float)RANDOM_FLOAT( 200, 400 ), (float)0 ); + } + + if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) + { + pGun = DropItem( "ammo_ARgrenades", vecGunPos, vecGunAngles ); + if ( pGun ) + { + pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); + pGun->pev->avelocity = Vector ( (float)0, (float)RANDOM_FLOAT( 200, 400 ), (float)0 ); + } + } + } + + CBaseMonster :: GibMonster(); +} + +//========================================================= +// ISoundMask - Overidden for human grunts because they +// hear the DANGER sound that is made by hand grenades and +// other dangerous items. +//========================================================= +int CHGrunt :: ISoundMask ( void ) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER | + bits_SOUND_DANGER; +} + +//========================================================= +// someone else is talking - don't speak +//========================================================= +BOOL CHGrunt :: FOkToSpeak( void ) +{ +// if someone else is talking, don't speak + if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) + return FALSE; + + if ( pev->spawnflags & SF_MONSTER_GAG ) + { + if ( m_MonsterState != MONSTERSTATE_COMBAT ) + { + // no talking outside of combat if gagged. + return FALSE; + } + } + + // if player is not in pvs, don't speak +// if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) +// return FALSE; + + return TRUE; +} + +//========================================================= +//========================================================= +void CHGrunt :: JustSpoke( void ) +{ + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0); + m_iSentence = HGRUNT_SENT_NONE; +} + +//========================================================= +// PrescheduleThink - this function runs after conditions +// are collected and before scheduling code is run. +//========================================================= +void CHGrunt :: PrescheduleThink ( void ) +{ + if ( InSquad() && m_hEnemy != NULL ) + { + if ( HasConditions ( bits_COND_SEE_ENEMY ) ) + { + // update the squad's last enemy sighting time. + MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time; + } + else + { + if ( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) + { + // been a while since we've seen the enemy + MySquadLeader()->m_fEnemyEluded = TRUE; + } + } + } +} + +//========================================================= +// FCanCheckAttacks - this is overridden for human grunts +// because they can throw/shoot grenades when they can't see their +// target and the base class doesn't check attacks if the monster +// cannot see its enemy. +// +// !!!BUGBUG - this gets called before a 3-round burst is fired +// which means that a friendly can still be hit with up to 2 rounds. +// ALSO, grenades will not be tossed if there is a friendly in front, +// this is a bad bug. Friendly machine gun fire avoidance +// will unecessarily prevent the throwing of a grenade as well. +//========================================================= +BOOL CHGrunt :: FCanCheckAttacks ( void ) +{ + if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +//========================================================= +// CheckMeleeAttack1 +//========================================================= +BOOL CHGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + CBaseMonster *pEnemy; + + if ( m_hEnemy != NULL ) + { + pEnemy = m_hEnemy->MyMonsterPointer(); + + if ( !pEnemy ) + { + return FALSE; + } + } + + if ( flDist <= 64 && flDot >= 0.7 && + pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON && + pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack1 - overridden for HGrunt, cause +// FCanCheckAttacks() doesn't disqualify all attacks based +// on whether or not the enemy is occluded because unlike +// the base class, the HGrunt can attack when the enemy is +// occluded (throw grenade over wall, etc). We must +// disqualify the machine gun attack if the enemy is occluded. +//========================================================= +BOOL CHGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) + { + TraceResult tr; + + if ( !m_hEnemy->IsPlayer() && flDist <= 64 ) + { + // kick nonclients, but don't shoot at them. + return FALSE; + } + + Vector vecSrc = GetGunPosition(); + + // verify that a bullet fired from the gun will hit the enemy before the world. + UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr); + + if ( tr.flFraction == 1.0 ) + { + return TRUE; + } + } + + return FALSE; +} + +//========================================================= +// CheckRangeAttack2 - this checks the Grunt's grenade +// attack. +//========================================================= +BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) +{ + if (! FBitSet(pev->weapons, (HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER))) + { + return FALSE; + } + + // if the grunt isn't moving, it's ok to check. + if ( m_flGroundSpeed != 0 ) + { + m_fThrowGrenade = FALSE; + return m_fThrowGrenade; + } + + // assume things haven't changed too much since last time + if (gpGlobals->time < m_flNextGrenadeCheck ) + { + return m_fThrowGrenade; + } + + if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z ) + { + //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to + // be grenaded. + // don't throw grenades at anything that isn't on the ground! + m_fThrowGrenade = FALSE; + return m_fThrowGrenade; + } + + Vector vecTarget; + + if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) + { + // find feet + if (RANDOM_LONG(0,1)) + { + // magically know where they are + vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z ); + } + else + { + // toss it to where you last saw them + vecTarget = m_vecEnemyLKP; + } + // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); + // estimate position + // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2; + } + else + { + // find target + // vecTarget = m_hEnemy->BodyTarget( pev->origin ); + vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); + // estimate position + if (HasConditions( bits_COND_SEE_ENEMY)) + vecTarget = vecTarget + ((vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed) * m_hEnemy->pev->velocity; + } + + // are any of my squad members near the intended grenade impact area? + if ( InSquad() ) + { + if (SquadMemberInRange( vecTarget, 256 )) + { + // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. + m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. + m_fThrowGrenade = FALSE; + } + } + + if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) + { + // crap, I don't want to blow myself up + m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. + m_fThrowGrenade = FALSE; + return m_fThrowGrenade; + } + + + if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) + { + Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); + + if ( vecToss != g_vecZero ) + { + m_vecTossVelocity = vecToss; + + // throw a hand grenade + m_fThrowGrenade = TRUE; + // don't check again for a while. + m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second. + } + else + { + // don't throw + m_fThrowGrenade = FALSE; + // don't check again for a while. + m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. + } + } + else + { + Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); + + if ( vecToss != g_vecZero ) + { + m_vecTossVelocity = vecToss; + + // throw a hand grenade + m_fThrowGrenade = TRUE; + // don't check again for a while. + m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second. + } + else + { + // don't throw + m_fThrowGrenade = FALSE; + // don't check again for a while. + m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. + } + } + + + + return m_fThrowGrenade; +} + + +//========================================================= +// TraceAttack - make sure we're not taking it in the helmet +//========================================================= +void CHGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + // check for helmet shot + if (ptr->iHitgroup == 11) + { + // make sure we're wearing one + if (GetBodygroup( 1 ) == HEAD_GRUNT && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB))) + { + // absorb damage + flDamage -= 20; + if (flDamage <= 0) + { + UTIL_Ricochet( ptr->vecEndPos, 1.0 ); + flDamage = 0.01; + } + } + // it's head shot anyways + ptr->iHitgroup = HITGROUP_HEAD; + } + CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); +} + + +//========================================================= +// TakeDamage - overridden for the grunt because the grunt +// needs to forget that he is in cover if he's hurt. (Obviously +// not in a safe place anymore). +//========================================================= +int CHGrunt :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + Forget( bits_MEMORY_INCOVER ); + + return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CHGrunt :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + ys = 150; + break; + case ACT_RUN: + ys = 150; + break; + case ACT_WALK: + ys = 180; + break; + case ACT_RANGE_ATTACK1: + ys = 120; + break; + case ACT_RANGE_ATTACK2: + ys = 120; + break; + case ACT_MELEE_ATTACK1: + ys = 120; + break; + case ACT_MELEE_ATTACK2: + ys = 120; + break; + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 180; + break; + case ACT_GLIDE: + case ACT_FLY: + ys = 30; + break; + default: + ys = 90; + break; + } + + pev->yaw_speed = ys; +} + +void CHGrunt :: IdleSound( void ) +{ + if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1))) + { + if (!g_fGruntQuestion) + { + // ask question or make statement + switch (RANDOM_LONG(0,2)) + { + case 0: // check in + SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + g_fGruntQuestion = 1; + break; + case 1: // question + SENTENCEG_PlayRndSz(ENT(pev), "HG_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + g_fGruntQuestion = 2; + break; + case 2: // statement + SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + break; + } + } + else + { + switch (g_fGruntQuestion) + { + case 1: // check in + SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + break; + case 2: // question + SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + break; + } + g_fGruntQuestion = 0; + } + JustSpoke(); + } +} + +//========================================================= +// CheckAmmo - overridden for the grunt because he actually +// uses ammo! (base class doesn't) +//========================================================= +void CHGrunt :: CheckAmmo ( void ) +{ + if ( m_cAmmoLoaded <= 0 ) + { + SetConditions(bits_COND_NO_AMMO_LOADED); + } +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CHGrunt :: Classify ( void ) +{ + return CLASS_HUMAN_MILITARY; +} + +//========================================================= +//========================================================= +CBaseEntity *CHGrunt :: Kick( void ) +{ + TraceResult tr; + + UTIL_MakeVectors( pev->angles ); + Vector vecStart = pev->origin; + vecStart.z += pev->size.z * 0.5; + Vector vecEnd = vecStart + (gpGlobals->v_forward * 70); + + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); + + if ( tr.pHit ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + return pEntity; + } + + return NULL; +} + +//========================================================= +// GetGunPosition return the end of the barrel +//========================================================= + +Vector CHGrunt :: GetGunPosition( ) +{ + if (m_fStanding ) + { + return pev->origin + Vector( 0, 0, 60 ); + } + else + { + return pev->origin + Vector( 0, 0, 48 ); + } +} + +//========================================================= +// Shoot +//========================================================= +void CHGrunt :: Shoot ( void ) +{ + if (m_hEnemy == NULL) + { + return; + } + + Vector vecShootOrigin = GetGunPosition(); + Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); + + UTIL_MakeVectors ( pev->angles ); + + Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); + EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); + FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5 ); // shoot +-5 degrees + + pev->effects |= EF_MUZZLEFLASH; + + m_cAmmoLoaded--;// take away a bullet! + + Vector angDir = UTIL_VecToAngles( vecShootDir ); + SetBlending( 0, angDir.x ); +} + +//========================================================= +// Shoot +//========================================================= +void CHGrunt :: Shotgun ( void ) +{ + if (m_hEnemy == NULL) + { + return; + } + + Vector vecShootOrigin = GetGunPosition(); + Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); + + UTIL_MakeVectors ( pev->angles ); + + Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); + EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL); + FireBullets(gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees + + pev->effects |= EF_MUZZLEFLASH; + + m_cAmmoLoaded--;// take away a bullet! + + Vector angDir = UTIL_VecToAngles( vecShootDir ); + SetBlending( 0, angDir.x ); +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + Vector vecShootDir; + Vector vecShootOrigin; + + switch( pEvent->event ) + { + case HGRUNT_AE_DROP_GUN: + { + Vector vecGunPos; + Vector vecGunAngles; + + GetAttachment( 0, vecGunPos, vecGunAngles ); + + // switch to body group with no gun. + SetBodygroup( GUN_GROUP, GUN_NONE ); + + // now spawn a gun. + if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + { + DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); + } + else + { + DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); + } + if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) + { + DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles ); + } + + } + break; + + case HGRUNT_AE_RELOAD: + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM ); + m_cAmmoLoaded = m_cClipSize; + ClearConditions(bits_COND_NO_AMMO_LOADED); + break; + + case HGRUNT_AE_GREN_TOSS: + { + UTIL_MakeVectors( pev->angles ); + // CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 ); + CGrenade::ShootTimed( pev, GetGunPosition(), m_vecTossVelocity, 3.5 ); + + m_fThrowGrenade = FALSE; + m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. + // !!!LATER - when in a group, only try to throw grenade if ordered. + } + break; + + case HGRUNT_AE_GREN_LAUNCH: + { + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM); + CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity ); + m_fThrowGrenade = FALSE; + if (g_iSkillLevel == SKILL_HARD) + m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 );// wait a random amount of time before shooting again + else + m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. + } + break; + + case HGRUNT_AE_GREN_DROP: + { + UTIL_MakeVectors( pev->angles ); + CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 17 - gpGlobals->v_right * 27 + gpGlobals->v_up * 6, g_vecZero, 3 ); + } + break; + + case HGRUNT_AE_BURST1: + { + if ( FBitSet( pev->weapons, HGRUNT_9MMAR )) + { + Shoot(); + + // the first round of the three round burst plays the sound and puts a sound in the world sound list. + if ( RANDOM_LONG(0,1) ) + { + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM ); + } + else + { + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM ); + } + } + else + { + Shotgun( ); + + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); + } + + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); + } + break; + + case HGRUNT_AE_BURST2: + case HGRUNT_AE_BURST3: + Shoot(); + break; + + case HGRUNT_AE_KICK: + { + CBaseEntity *pHurt = Kick(); + + if ( pHurt ) + { + // SOUND HERE! + UTIL_MakeVectors( pev->angles ); + pHurt->pev->punchangle.x = 15; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50; + pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB ); + } + } + break; + + case HGRUNT_AE_CAUGHT_ENEMY: + { + if ( FOkToSpeak() ) + { + SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + JustSpoke(); + } + + } + + default: + CSquadMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CHGrunt :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/hgrunt.mdl"); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->effects = 0; + pev->health = gSkillData.hgruntHealth; + m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_flNextGrenadeCheck = gpGlobals->time + 1; + m_flNextPainTime = gpGlobals->time; + m_iSentence = HGRUNT_SENT_NONE; + + m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; + + m_fEnemyEluded = FALSE; + m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet. + + m_HackedGunPos = Vector ( 0, 0, 55 ); + + if (pev->weapons == 0) + { + // initialize to original values + pev->weapons = HGRUNT_9MMAR | HGRUNT_HANDGRENADE; + // pev->weapons = HGRUNT_SHOTGUN; + // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER; + } + + if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + { + SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); + m_cClipSize = 8; + } + else + { + m_cClipSize = GRUNT_CLIP_SIZE; + } + m_cAmmoLoaded = m_cClipSize; + + if (RANDOM_LONG( 0, 99 ) < 80) + pev->skin = 0; // light skin + else + pev->skin = 1; // dark skin + + if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + { + SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN); + } + else if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) + { + SetBodygroup( HEAD_GROUP, HEAD_M203 ); + pev->skin = 1; // alway dark skin + } + + CTalkMonster::g_talkWaitTime = 0; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CHGrunt :: Precache() +{ + PRECACHE_MODEL("models/hgrunt.mdl"); + + PRECACHE_SOUND( "hgrunt/gr_mgun1.wav" ); + PRECACHE_SOUND( "hgrunt/gr_mgun2.wav" ); + + PRECACHE_SOUND( "hgrunt/gr_die1.wav" ); + PRECACHE_SOUND( "hgrunt/gr_die2.wav" ); + PRECACHE_SOUND( "hgrunt/gr_die3.wav" ); + + PRECACHE_SOUND( "hgrunt/gr_pain1.wav" ); + PRECACHE_SOUND( "hgrunt/gr_pain2.wav" ); + PRECACHE_SOUND( "hgrunt/gr_pain3.wav" ); + PRECACHE_SOUND( "hgrunt/gr_pain4.wav" ); + PRECACHE_SOUND( "hgrunt/gr_pain5.wav" ); + + PRECACHE_SOUND( "hgrunt/gr_reload1.wav" ); + + PRECACHE_SOUND( "weapons/glauncher.wav" ); + + PRECACHE_SOUND( "weapons/sbarrel1.wav" ); + + PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event + + // get voice pitch + if (RANDOM_LONG(0,1)) + m_voicePitch = 109 + RANDOM_LONG(0,7); + else + m_voicePitch = 100; + + m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell + m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl"); +} + +//========================================================= +// start task +//========================================================= +void CHGrunt :: StartTask ( Task_t *pTask ) +{ + m_iTaskStatus = TASKSTATUS_RUNNING; + + switch ( pTask->iTask ) + { + case TASK_GRUNT_CHECK_FIRE: + if ( !NoFriendlyFire() ) + { + SetConditions( bits_COND_GRUNT_NOFIRE ); + } + TaskComplete(); + break; + + case TASK_GRUNT_SPEAK_SENTENCE: + SpeakSentence(); + TaskComplete(); + break; + + case TASK_WALK_PATH: + case TASK_RUN_PATH: + // grunt no longer assumes he is covered if he moves + Forget( bits_MEMORY_INCOVER ); + CSquadMonster ::StartTask( pTask ); + break; + + case TASK_RELOAD: + m_IdealActivity = ACT_RELOAD; + break; + + case TASK_GRUNT_FACE_TOSS_DIR: + break; + + case TASK_FACE_IDEAL: + case TASK_FACE_ENEMY: + CSquadMonster :: StartTask( pTask ); + if (pev->movetype == MOVETYPE_FLY) + { + m_IdealActivity = ACT_GLIDE; + } + break; + + default: + CSquadMonster :: StartTask( pTask ); + break; + } +} + +//========================================================= +// RunTask +//========================================================= +void CHGrunt :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_GRUNT_FACE_TOSS_DIR: + { + // project a point along the toss vector and turn to face that point. + MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + m_iTaskStatus = TASKSTATUS_COMPLETE; + } + break; + } + default: + { + CSquadMonster :: RunTask( pTask ); + break; + } + } +} + +//========================================================= +// PainSound +//========================================================= +void CHGrunt :: PainSound ( void ) +{ + if ( gpGlobals->time > m_flNextPainTime ) + { +#if 0 + if ( RANDOM_LONG(0,99) < 5 ) + { + // pain sentences are rare + if (FOkToSpeak()) + { + SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM); + JustSpoke(); + return; + } + } +#endif + switch ( RANDOM_LONG(0,6) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain4.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain5.wav", 1, ATTN_NORM ); + break; + case 3: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain1.wav", 1, ATTN_NORM ); + break; + case 4: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); + break; + } + + m_flNextPainTime = gpGlobals->time + 1; + } +} + +//========================================================= +// DeathSound +//========================================================= +void CHGrunt :: DeathSound ( void ) +{ + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die2.wav", 1, ATTN_IDLE ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); + break; + } +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +//========================================================= +// GruntFail +//========================================================= +Task_t tlGruntFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slGruntFail[] = +{ + { + tlGruntFail, + ARRAYSIZE ( tlGruntFail ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK2, + 0, + "Grunt Fail" + }, +}; + +//========================================================= +// Grunt Combat Fail +//========================================================= +Task_t tlGruntCombatFail[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, +}; + +Schedule_t slGruntCombatFail[] = +{ + { + tlGruntCombatFail, + ARRAYSIZE ( tlGruntCombatFail ), + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2, + 0, + "Grunt Combat Fail" + }, +}; + +//========================================================= +// Victory dance! +//========================================================= +Task_t tlGruntVictoryDance[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_WAIT, (float)1.5 }, + { TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, + { TASK_WALK_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, +}; + +Schedule_t slGruntVictoryDance[] = +{ + { + tlGruntVictoryDance, + ARRAYSIZE ( tlGruntVictoryDance ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "GruntVictoryDance" + }, +}; + +//========================================================= +// Establish line of fire - move to a position that allows +// the grunt to attack. +//========================================================= +Task_t tlGruntEstablishLineOfFire[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_ELOF_FAIL }, + { TASK_GET_PATH_TO_ENEMY, (float)0 }, + { TASK_GRUNT_SPEAK_SENTENCE,(float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, +}; + +Schedule_t slGruntEstablishLineOfFire[] = +{ + { + tlGruntEstablishLineOfFire, + ARRAYSIZE ( tlGruntEstablishLineOfFire ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK2 | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "GruntEstablishLineOfFire" + }, +}; + +//========================================================= +// GruntFoundEnemy - grunt established sight with an enemy +// that was hiding from the squad. +//========================================================= +Task_t tlGruntFoundEnemy[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1 }, +}; + +Schedule_t slGruntFoundEnemy[] = +{ + { + tlGruntFoundEnemy, + ARRAYSIZE ( tlGruntFoundEnemy ), + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "GruntFoundEnemy" + }, +}; + +//========================================================= +// GruntCombatFace Schedule +//========================================================= +Task_t tlGruntCombatFace1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_WAIT, (float)1.5 }, + { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_SWEEP }, +}; + +Schedule_t slGruntCombatFace[] = +{ + { + tlGruntCombatFace1, + ARRAYSIZE ( tlGruntCombatFace1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2, + 0, + "Combat Face" + }, +}; + +//========================================================= +// Suppressing fire - don't stop shooting until the clip is +// empty or grunt gets hurt. +//========================================================= +Task_t tlGruntSignalSuppress[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL2 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slGruntSignalSuppress[] = +{ + { + tlGruntSignalSuppress, + ARRAYSIZE ( tlGruntSignalSuppress ), + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_GRUNT_NOFIRE | + bits_COND_NO_AMMO_LOADED, + + bits_SOUND_DANGER, + "SignalSuppress" + }, +}; + +Task_t tlGruntSuppress[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slGruntSuppress[] = +{ + { + tlGruntSuppress, + ARRAYSIZE ( tlGruntSuppress ), + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_GRUNT_NOFIRE | + bits_COND_NO_AMMO_LOADED, + + bits_SOUND_DANGER, + "Suppress" + }, +}; + + +//========================================================= +// grunt wait in cover - we don't allow danger or the ability +// to attack to break a grunt's run to cover schedule, but +// when a grunt is in cover, we do want them to attack if they can. +//========================================================= +Task_t tlGruntWaitInCover[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)1 }, +}; + +Schedule_t slGruntWaitInCover[] = +{ + { + tlGruntWaitInCover, + ARRAYSIZE ( tlGruntWaitInCover ), + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK2, + + bits_SOUND_DANGER, + "GruntWaitInCover" + }, +}; + +//========================================================= +// run to cover. +// !!!BUGBUG - set a decent fail schedule here. +//========================================================= +Task_t tlGruntTakeCover1[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_TAKECOVER_FAILED }, + { TASK_WAIT, (float)0.2 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_GRUNT_SPEAK_SENTENCE, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, +}; + +Schedule_t slGruntTakeCover[] = +{ + { + tlGruntTakeCover1, + ARRAYSIZE ( tlGruntTakeCover1 ), + 0, + 0, + "TakeCover" + }, +}; + +//========================================================= +// drop grenade then run to cover. +//========================================================= +Task_t tlGruntGrenadeCover1[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)99 }, + { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, + { TASK_PLAY_SEQUENCE, (float)ACT_SPECIAL_ATTACK1 }, + { TASK_CLEAR_MOVE_WAIT, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, +}; + +Schedule_t slGruntGrenadeCover[] = +{ + { + tlGruntGrenadeCover1, + ARRAYSIZE ( tlGruntGrenadeCover1 ), + 0, + 0, + "GrenadeCover" + }, +}; + + +//========================================================= +// drop grenade then run to cover. +//========================================================= +Task_t tlGruntTossGrenadeCover1[] = +{ + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK2, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, +}; + +Schedule_t slGruntTossGrenadeCover[] = +{ + { + tlGruntTossGrenadeCover1, + ARRAYSIZE ( tlGruntTossGrenadeCover1 ), + 0, + 0, + "TossGrenadeCover" + }, +}; + +//========================================================= +// hide from the loudest sound source (to run from grenade) +//========================================================= +Task_t tlGruntTakeCoverFromBestSound[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_COWER },// duck and cover if cannot move from explosion + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_TURN_LEFT, (float)179 }, +}; + +Schedule_t slGruntTakeCoverFromBestSound[] = +{ + { + tlGruntTakeCoverFromBestSound, + ARRAYSIZE ( tlGruntTakeCoverFromBestSound ), + 0, + 0, + "GruntTakeCoverFromBestSound" + }, +}; + +//========================================================= +// Grunt reload schedule +//========================================================= +Task_t tlGruntHideReload[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RELOAD }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_RELOAD }, +}; + +Schedule_t slGruntHideReload[] = +{ + { + tlGruntHideReload, + ARRAYSIZE ( tlGruntHideReload ), + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "GruntHideReload" + } +}; + +//========================================================= +// Do a turning sweep of the area +//========================================================= +Task_t tlGruntSweep[] = +{ + { TASK_TURN_LEFT, (float)179 }, + { TASK_WAIT, (float)1 }, + { TASK_TURN_LEFT, (float)179 }, + { TASK_WAIT, (float)1 }, +}; + +Schedule_t slGruntSweep[] = +{ + { + tlGruntSweep, + ARRAYSIZE ( tlGruntSweep ), + + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_CAN_RANGE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK2 | + bits_COND_HEAR_SOUND, + + bits_SOUND_WORLD |// sound flags + bits_SOUND_DANGER | + bits_SOUND_PLAYER, + + "Grunt Sweep" + }, +}; + +//========================================================= +// primary range attack. Overriden because base class stops attacking when the enemy is occluded. +// grunt's grenade toss requires the enemy be occluded. +//========================================================= +Task_t tlGruntRangeAttack1A[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slGruntRangeAttack1A[] = +{ + { + tlGruntRangeAttack1A, + ARRAYSIZE ( tlGruntRangeAttack1A ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_HEAR_SOUND | + bits_COND_GRUNT_NOFIRE | + bits_COND_NO_AMMO_LOADED, + + bits_SOUND_DANGER, + "Range Attack1A" + }, +}; + + +//========================================================= +// primary range attack. Overriden because base class stops attacking when the enemy is occluded. +// grunt's grenade toss requires the enemy be occluded. +//========================================================= +Task_t tlGruntRangeAttack1B[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_GRUNT_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slGruntRangeAttack1B[] = +{ + { + tlGruntRangeAttack1B, + ARRAYSIZE ( tlGruntRangeAttack1B ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED | + bits_COND_GRUNT_NOFIRE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER, + "Range Attack1B" + }, +}; + +//========================================================= +// secondary range attack. Overriden because base class stops attacking when the enemy is occluded. +// grunt's grenade toss requires the enemy be occluded. +//========================================================= +Task_t tlGruntRangeAttack2[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_GRUNT_FACE_TOSS_DIR, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_RANGE_ATTACK2 }, + { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY },// don't run immediately after throwing grenade. +}; + +Schedule_t slGruntRangeAttack2[] = +{ + { + tlGruntRangeAttack2, + ARRAYSIZE ( tlGruntRangeAttack2 ), + 0, + 0, + "RangeAttack2" + }, +}; + + +//========================================================= +// repel +//========================================================= +Task_t tlGruntRepel[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, +}; + +Schedule_t slGruntRepel[] = +{ + { + tlGruntRepel, + ARRAYSIZE ( tlGruntRepel ), + bits_COND_SEE_ENEMY | + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER, + "Repel" + }, +}; + + +//========================================================= +// repel +//========================================================= +Task_t tlGruntRepelAttack[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, +}; + +Schedule_t slGruntRepelAttack[] = +{ + { + tlGruntRepelAttack, + ARRAYSIZE ( tlGruntRepelAttack ), + bits_COND_ENEMY_OCCLUDED, + 0, + "Repel Attack" + }, +}; + +//========================================================= +// repel land +//========================================================= +Task_t tlGruntRepelLand[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_LAND }, + { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, + { TASK_RUN_PATH, (float)0 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_CLEAR_LASTPOSITION, (float)0 }, +}; + +Schedule_t slGruntRepelLand[] = +{ + { + tlGruntRepelLand, + ARRAYSIZE ( tlGruntRepelLand ), + bits_COND_SEE_ENEMY | + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + + bits_SOUND_DANGER | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER, + "Repel Land" + }, +}; + + +DEFINE_CUSTOM_SCHEDULES( CHGrunt ) +{ + slGruntFail, + slGruntCombatFail, + slGruntVictoryDance, + slGruntEstablishLineOfFire, + slGruntFoundEnemy, + slGruntCombatFace, + slGruntSignalSuppress, + slGruntSuppress, + slGruntWaitInCover, + slGruntTakeCover, + slGruntGrenadeCover, + slGruntTossGrenadeCover, + slGruntTakeCoverFromBestSound, + slGruntHideReload, + slGruntSweep, + slGruntRangeAttack1A, + slGruntRangeAttack1B, + slGruntRangeAttack2, + slGruntRepel, + slGruntRepelAttack, + slGruntRepelLand, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ); + +//========================================================= +// SetActivity +//========================================================= +void CHGrunt :: SetActivity ( Activity NewActivity ) +{ + int iSequence = ACTIVITY_NOT_AVAILABLE; + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + switch ( NewActivity) + { + case ACT_RANGE_ATTACK1: + // grunt is either shooting standing or shooting crouched + if (FBitSet( pev->weapons, HGRUNT_9MMAR)) + { + if ( m_fStanding ) + { + // get aimable sequence + iSequence = LookupSequence( "standing_mp5" ); + } + else + { + // get crouching shoot + iSequence = LookupSequence( "crouching_mp5" ); + } + } + else + { + if ( m_fStanding ) + { + // get aimable sequence + iSequence = LookupSequence( "standing_shotgun" ); + } + else + { + // get crouching shoot + iSequence = LookupSequence( "crouching_shotgun" ); + } + } + break; + case ACT_RANGE_ATTACK2: + // grunt is going to a secondary long range attack. This may be a thrown + // grenade or fired grenade, we must determine which and pick proper sequence + if ( pev->weapons & HGRUNT_HANDGRENADE ) + { + // get toss anim + iSequence = LookupSequence( "throwgrenade" ); + } + else + { + // get launch anim + iSequence = LookupSequence( "launchgrenade" ); + } + break; + case ACT_RUN: + if ( pev->health <= HGRUNT_LIMP_HEALTH ) + { + // limp! + iSequence = LookupActivity ( ACT_RUN_HURT ); + } + else + { + iSequence = LookupActivity ( NewActivity ); + } + break; + case ACT_WALK: + if ( pev->health <= HGRUNT_LIMP_HEALTH ) + { + // limp! + iSequence = LookupActivity ( ACT_WALK_HURT ); + } + else + { + iSequence = LookupActivity ( NewActivity ); + } + break; + case ACT_IDLE: + if ( m_MonsterState == MONSTERSTATE_COMBAT ) + { + NewActivity = ACT_IDLE_ANGRY; + } + iSequence = LookupActivity ( NewActivity ); + break; + default: + iSequence = LookupActivity ( NewActivity ); + break; + } + + m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present + + // Set to the desired anim, or default anim if the desired is not present + if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + { + if ( pev->sequence != iSequence || !m_fSequenceLoops ) + { + pev->frame = 0; + } + + pev->sequence = iSequence; // Set to the reset anim (if it's there) + ResetSequenceInfo( ); + SetYawSpeed(); + } + else + { + // Not available try to get default anim + ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); + pev->sequence = 0; // Set to the reset anim (if it's there) + } +} + +//========================================================= +// Get Schedule! +//========================================================= +Schedule_t *CHGrunt :: GetSchedule( void ) +{ + + // clear old sentence + m_iSentence = HGRUNT_SENT_NONE; + + // flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling. + if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE ) + { + if (pev->flags & FL_ONGROUND) + { + // just landed + pev->movetype = MOVETYPE_STEP; + return GetScheduleOfType ( SCHED_GRUNT_REPEL_LAND ); + } + else + { + // repel down a rope, + if ( m_MonsterState == MONSTERSTATE_COMBAT ) + return GetScheduleOfType ( SCHED_GRUNT_REPEL_ATTACK ); + else + return GetScheduleOfType ( SCHED_GRUNT_REPEL ); + } + } + + // grunts place HIGH priority on running away from danger sounds. + if ( HasConditions(bits_COND_HEAR_SOUND) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound) + { + if (pSound->m_iType & bits_SOUND_DANGER) + { + // dangerous sound nearby! + + //!!!KELLY - currently, this is the grunt's signal that a grenade has landed nearby, + // and the grunt should find cover from the blast + // good place for "SHIT!" or some other colorful verbal indicator of dismay. + // It's not safe to play a verbal order here "Scatter", etc cause + // this may only affect a single individual in a squad. + + if (FOkToSpeak()) + { + SENTENCEG_PlayRndSz( ENT(pev), "HG_GREN", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + JustSpoke(); + } + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + /* + if (!HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & (bits_SOUND_PLAYER | bits_SOUND_COMBAT) )) + { + MakeIdealYaw( pSound->m_vecOrigin ); + } + */ + } + } + switch ( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + +// new enemy + if ( HasConditions(bits_COND_NEW_ENEMY) ) + { + if ( InSquad() ) + { + MySquadLeader()->m_fEnemyEluded = FALSE; + + if ( !IsLeader() ) + { + return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + } + else + { + //!!!KELLY - the leader of a squad of grunts has just seen the player or a + // monster and has made it the squad's enemy. You + // can check pev->flags for FL_CLIENT to determine whether this is the player + // or a monster. He's going to immediately start + // firing, though. If you'd like, we can make an alternate "first sight" + // schedule where the leader plays a handsign anim + // that gives us enough time to hear a short sentence or spoken command + // before he starts pluggin away. + if (FOkToSpeak())// && RANDOM_LONG(0,1)) + { + if ((m_hEnemy != NULL) && m_hEnemy->IsPlayer()) + // player + SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + else if ((m_hEnemy != NULL) && + (m_hEnemy->Classify() != CLASS_PLAYER_ALLY) && + (m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) && + (m_hEnemy->Classify() != CLASS_MACHINE)) + // monster + SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + + JustSpoke(); + } + + if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS ); + } + else + { + return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); + } + } + } + } +// no ammo + else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) + { + //!!!KELLY - this individual just realized he's out of bullet ammo. + // He's going to try to find cover to run to and reload, but rarely, if + // none is available, he'll drop and reload in the open here. + return GetScheduleOfType ( SCHED_GRUNT_COVER_AND_RELOAD ); + } + +// damaged just a little + else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) ) + { + // if hurt: + // 90% chance of taking cover + // 10% chance of flinch. + int iPercent = RANDOM_LONG(0,99); + + if ( iPercent <= 90 && m_hEnemy != NULL ) + { + // only try to take cover if we actually have an enemy! + + //!!!KELLY - this grunt was hit and is going to run to cover. + if (FOkToSpeak()) // && RANDOM_LONG(0,1)) + { + //SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + m_iSentence = HGRUNT_SENT_COVER; + //JustSpoke(); + } + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); + } + else + { + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + } +// can kick + else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + { + return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + } +// can grenade launch + + else if ( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER) && HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) + { + // shoot a grenade if you can + return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); + } +// can shoot + else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + if ( InSquad() ) + { + // if the enemy has eluded the squad and a squad member has just located the enemy + // and the enemy does not see the squad member, issue a call to the squad to waste a + // little time and give the player a chance to turn. + if ( MySquadLeader()->m_fEnemyEluded && !HasConditions ( bits_COND_ENEMY_FACING_ME ) ) + { + MySquadLeader()->m_fEnemyEluded = FALSE; + return GetScheduleOfType ( SCHED_GRUNT_FOUND_ENEMY ); + } + } + + if ( OccupySlot ( bits_SLOTS_HGRUNT_ENGAGE ) ) + { + // try to take an available ENGAGE slot + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); + } + else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) + { + // throw a grenade if can and no engage slots are available + return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); + } + else + { + // hide! + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); + } + } +// can't see enemy + else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) + { + if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) + { + //!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc + if (FOkToSpeak()) + { + SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + JustSpoke(); + } + return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); + } + else if ( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) + { + //!!!KELLY - grunt cannot see the enemy and has just decided to + // charge the enemy's position. + if (FOkToSpeak())// && RANDOM_LONG(0,1)) + { + //SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + m_iSentence = HGRUNT_SENT_CHARGE; + //JustSpoke(); + } + + return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); + } + else + { + //!!!KELLY - grunt is going to stay put for a couple seconds to see if + // the enemy wanders back out into the open, or approaches the + // grunt's covered position. Good place for a taunt, I guess? + if (FOkToSpeak() && RANDOM_LONG(0,1)) + { + SENTENCEG_PlayRndSz( ENT(pev), "HG_TAUNT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + JustSpoke(); + } + return GetScheduleOfType( SCHED_STANDOFF ); + } + } + + if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); + } + } + } + + // no special cases here, call the base class + return CSquadMonster :: GetSchedule(); +} + +//========================================================= +//========================================================= +Schedule_t* CHGrunt :: GetScheduleOfType ( int Type ) +{ + switch ( Type ) + { + case SCHED_TAKE_COVER_FROM_ENEMY: + { + if ( InSquad() ) + { + if ( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) + { + if (FOkToSpeak()) + { + SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + JustSpoke(); + } + return slGruntTossGrenadeCover; + } + else + { + return &slGruntTakeCover[ 0 ]; + } + } + else + { + if ( RANDOM_LONG(0,1) ) + { + return &slGruntTakeCover[ 0 ]; + } + else + { + return &slGruntGrenadeCover[ 0 ]; + } + } + } + case SCHED_TAKE_COVER_FROM_BEST_SOUND: + { + return &slGruntTakeCoverFromBestSound[ 0 ]; + } + case SCHED_GRUNT_TAKECOVER_FAILED: + { + if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) + { + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); + } + + return GetScheduleOfType ( SCHED_FAIL ); + } + break; + case SCHED_GRUNT_ELOF_FAIL: + { + // human grunt is unable to move to a position that allows him to attack the enemy. + return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + } + break; + case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: + { + return &slGruntEstablishLineOfFire[ 0 ]; + } + break; + case SCHED_RANGE_ATTACK1: + { + // randomly stand or crouch + if (RANDOM_LONG(0,9) == 0) + m_fStanding = RANDOM_LONG(0,1); + + if (m_fStanding) + return &slGruntRangeAttack1B[ 0 ]; + else + return &slGruntRangeAttack1A[ 0 ]; + } + case SCHED_RANGE_ATTACK2: + { + return &slGruntRangeAttack2[ 0 ]; + } + case SCHED_COMBAT_FACE: + { + return &slGruntCombatFace[ 0 ]; + } + case SCHED_GRUNT_WAIT_FACE_ENEMY: + { + return &slGruntWaitInCover[ 0 ]; + } + case SCHED_GRUNT_SWEEP: + { + return &slGruntSweep[ 0 ]; + } + case SCHED_GRUNT_COVER_AND_RELOAD: + { + return &slGruntHideReload[ 0 ]; + } + case SCHED_GRUNT_FOUND_ENEMY: + { + return &slGruntFoundEnemy[ 0 ]; + } + case SCHED_VICTORY_DANCE: + { + if ( InSquad() ) + { + if ( !IsLeader() ) + { + return &slGruntFail[ 0 ]; + } + } + + return &slGruntVictoryDance[ 0 ]; + } + case SCHED_GRUNT_SUPPRESS: + { + if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) + { + m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy + return &slGruntSignalSuppress[ 0 ]; + } + else + { + return &slGruntSuppress[ 0 ]; + } + } + case SCHED_FAIL: + { + if ( m_hEnemy != NULL ) + { + // grunt has an enemy, so pick a different default fail schedule most likely to help recover. + return &slGruntCombatFail[ 0 ]; + } + + return &slGruntFail[ 0 ]; + } + case SCHED_GRUNT_REPEL: + { + if (pev->velocity.z > -128) + pev->velocity.z -= 32; + return &slGruntRepel[ 0 ]; + } + case SCHED_GRUNT_REPEL_ATTACK: + { + if (pev->velocity.z > -128) + pev->velocity.z -= 32; + return &slGruntRepelAttack[ 0 ]; + } + case SCHED_GRUNT_REPEL_LAND: + { + return &slGruntRepelLand[ 0 ]; + } + default: + { + return CSquadMonster :: GetScheduleOfType ( Type ); + } + } +} + + +//========================================================= +// CHGruntRepel - when triggered, spawns a monster_human_grunt +// repelling down a line. +//========================================================= + +class CHGruntRepel : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int m_iSpriteTexture; // Don't save, precache +}; + +LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ); + +void CHGruntRepel::Spawn( void ) +{ + Precache( ); + pev->solid = SOLID_NOT; + + SetUse( &CHGruntRepel::RepelUse ); +} + +void CHGruntRepel::Precache( void ) +{ + UTIL_PrecacheOther( "monster_human_grunt" ); + m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); +} + +void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + TraceResult tr; + UTIL_TraceLine( pev->origin, pev->origin + Vector( (int)0, (int)0, (int)-4096.0), dont_ignore_monsters, ENT(pev), &tr); + /* + if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) + return NULL; + */ + + CBaseEntity *pEntity = Create( "monster_human_grunt", pev->origin, pev->angles ); + CBaseMonster *pGrunt = pEntity->MyMonsterPointer( ); + pGrunt->pev->movetype = MOVETYPE_FLY; + pGrunt->pev->velocity = Vector( (float)0, (float)0, (float)RANDOM_FLOAT( -196, -128 ) ); + pGrunt->SetActivity( ACT_GLIDE ); + // UNDONE: position? + pGrunt->m_vecLastPosition = tr.vecEndPos; + + CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); + pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() ); + pBeam->SetFlags( BEAM_FSOLID ); + pBeam->SetColor( 255, 255, 255 ); + pBeam->SetThink( &CHGruntRepel::SUB_Remove ); + pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; + + UTIL_Remove( this ); +} + + + +//========================================================= +// DEAD HGRUNT PROP +//========================================================= +class CDeadHGrunt : public CBaseMonster +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_HUMAN_MILITARY; } + + void KeyValue( KeyValueData *pkvd ); + + int m_iPose;// which sequence to display -- temporary, don't need to save + static char *m_szPoses[3]; +}; + +char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; + +void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "pose")) + { + m_iPose = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseMonster::KeyValue( pkvd ); +} + +LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ); + +//========================================================= +// ********** DeadHGrunt SPAWN ********** +//========================================================= +void CDeadHGrunt :: Spawn( void ) +{ + PRECACHE_MODEL("models/hgrunt.mdl"); + SET_MODEL(ENT(pev), "models/hgrunt.mdl"); + + pev->effects = 0; + pev->yaw_speed = 8; + pev->sequence = 0; + m_bloodColor = BLOOD_COLOR_RED; + + pev->sequence = LookupSequence( m_szPoses[m_iPose] ); + + if (pev->sequence == -1) + { + ALERT ( at_console, "Dead hgrunt with bad pose\n" ); + } + + // Corpses have less health + pev->health = 8; + + // map old bodies onto new bodies + switch( pev->body ) + { + case 0: // Grunt with Gun + pev->body = 0; + pev->skin = 0; + SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); + SetBodygroup( GUN_GROUP, GUN_MP5 ); + break; + case 1: // Commander with Gun + pev->body = 0; + pev->skin = 0; + SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); + SetBodygroup( GUN_GROUP, GUN_MP5 ); + break; + case 2: // Grunt no Gun + pev->body = 0; + pev->skin = 0; + SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); + SetBodygroup( GUN_GROUP, GUN_NONE ); + break; + case 3: // Commander no Gun + pev->body = 0; + pev->skin = 0; + SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); + SetBodygroup( GUN_GROUP, GUN_NONE ); + break; + } + + MonsterInitDead(); +} diff --git a/main/source/dlls/hl.def b/main/source/dlls/hl.def index 2ed4893a..fa6476df 100644 --- a/main/source/dlls/hl.def +++ b/main/source/dlls/hl.def @@ -1,5 +1,5 @@ -LIBRARY ns -EXPORTS - GiveFnptrsToDll @1 -SECTIONS - .data READ WRITE +LIBRARY ns +EXPORTS + GiveFnptrsToDll @1 +SECTIONS + .data READ WRITE diff --git a/main/source/dlls/hl.vcproj b/main/source/dlls/hl.vcproj index bfc1b406..d1cf5a48 100644 --- a/main/source/dlls/hl.vcproj +++ b/main/source/dlls/hl.vcproj @@ -1,5055 +1,5055 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/source/dlls/hl.vcxproj b/main/source/dlls/hl.vcxproj index 1873caf7..9d0a51ff 100644 --- a/main/source/dlls/hl.vcxproj +++ b/main/source/dlls/hl.vcxproj @@ -1,1818 +1,1824 @@ - - - - - Developer - debug - Win32 - - - Developer - release - Win32 - - - Playtest - balance disabled - Win32 - - - Playtest - Win32 - - - - ns.dll - hl - - - - - - - - DynamicLibrary - false - - - DynamicLibrary - false - MultiByte - - - DynamicLibrary - false - - - DynamicLibrary - false - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - V:\temp\$(ProjectName)\$(Configuration)/\ - V:\temp\$(ProjectName)\$(Configuration)/\ - false - V:\temp\$(ProjectName)\$(Configuration)\ - V:\temp\$(ProjectName)\$(Configuration)\ - true - .\Playtest - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - ns - - - - Full - AnySuitable - true - $(SolutionDir);U:\include\stlport;U:\include\nexus;U:\include\lua;U:\include\particle;U:\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;AVH_SECURE_PRERELEASE_BUILD;USE_OLDAUTH - true - true - MultiThreaded - true - true - - - .\Releasehl/hl.pch - $(IntDir) - $(IntDir) - $(IntDir) - Level3 - true - ProgramDatabase - Default - - - winmm.lib;ws2_32.lib;particles.lib;liblua.lib;liblualib.lib;ssleay32.lib;libeay32.lib;libcurl.lib;%(AdditionalDependencies) - $(SolutionDir)..\dlls\ns.dll - true - U:\release;%(AdditionalLibraryDirectories) - gdi32.lib user32.lib;%(IgnoreSpecificDefaultLibraries) - .\hl.def - - - Windows - $(OutDir)ns.lib - MachineX86 - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Releasehl/hl.tlb - - - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - ..\engine;%(AdditionalIncludeDirectories) - - - - - Disabled - $(SolutionDir);U:\include\stlport;U:\include\nexus;U:\include\lua;U:\include\particle;U:\include;%(AdditionalIncludeDirectories) - _DEBUG;DEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;AVH_SECURE_PRERELEASE_BUILD;USE_OLDAUTH - MultiThreadedDebug - true - - - .\debughl/hl.pch - $(IntDir) - $(IntDir) - $(IntDir) - Level3 - true - true - EditAndContinue - Default - - - winmm.lib;ws2_32.lib;particles.lib;liblua.lib;liblualib.lib;nexus_server.lib;ssleay32.lib;libeay32.lib;libcurl.lib;%(AdditionalDependencies) - $(SolutionDir)..\dlls\ns.dll - true - U:\debug;%(AdditionalLibraryDirectories) - libcmt;%(IgnoreSpecificDefaultLibraries) - .\hl.def - true - $(OutDir)ns.pdb - true - $(OutDir)ns.map - true - Windows - false - false - $(OutDir)ns.lib - MachineX86 - - - _DEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\debughl/hl.tlb - - - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - ..\engine;%(AdditionalIncludeDirectories) - - - - - Full - AnySuitable - true - $(SolutionDir);$(SolutionDir)\includes\lua\include;$(SolutionDir)\particles\;$(SolutionDir)\includes\vgui\include;$(SolutionDir)\includes\libcurl-7.18-nossl\include\;$(SolutionDir)\common;$(SolutionDir)\public;$(SolutionDir)\util;$(SolutionDir)\engine;$(SolutionDir)\;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;AVH_NO_NEXUS;USE_OLDAUTH - true - true - MultiThreaded - true - true - - - .\Releasehl/hl.pch - $(IntDir) - $(IntDir) - $(IntDir) - Level2 - true - ProgramDatabase - Default - - - winmm.lib;ws2_32.lib;particles.lib;lua5.1.lib;libcurl.lib;%(AdditionalDependencies) - true - gdi32.lib user32.lib;%(IgnoreSpecificDefaultLibraries) - .\hl.def - - - Windows - $(OutDir)ns.lib - MachineX86 - false - false - /NODEFAULTLIB:LIBCMT %(AdditionalOptions) - $(SolutionDir)\includes\lua\lib;$(SolutionDir)\particles\WIN32_Release;$(SolutionDir)\includes\libcurl-7.18-nossl\;$(SolutionDir)\includes\vgui\lib\win32_vc6;%(AdditionalLibraryDirectories) - false - false - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Releasehl/hl.tlb - - - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - ..\engine;%(AdditionalIncludeDirectories) - - - - - Full - AnySuitable - true - $(SolutionDir);U:\include\stlport;U:\include\nexus;U:\include\lua;U:\include\particle;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;SERVER;AVH_PLAYTEST_BUILD - true - true - MultiThreaded - true - true - - - .\Releasehl/hl.pch - $(IntDir) - $(IntDir) - $(IntDir) - Level3 - true - ProgramDatabase - Default - - - winmm.lib;ws2_32.lib;particles.lib;liblua.lib;liblualib.lib;ssleay32.lib;libeay32.lib;%(AdditionalDependencies) - $(SolutionDir)..\dlls\ns.dll - true - U:\release;%(AdditionalLibraryDirectories) - gdi32.lib user32.lib;%(IgnoreSpecificDefaultLibraries) - .\hl.def - - - Windows - $(OutDir)ns.lib - MachineX86 - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Releasehl/hl.tlb - - - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - ..\engine;%(AdditionalIncludeDirectories) - - - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - Disabled - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - MaxSpeed - %(AdditionalIncludeDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Developer - debug + Win32 + + + Developer - release + Win32 + + + Playtest - balance disabled + Win32 + + + Playtest + Win32 + + + + ns.dll + hl + + + + + {BC87A180-F17B-83FC-5D7D-470FAD003ABC} + 8.1 + + + + DynamicLibrary + false + v140 + + + DynamicLibrary + false + MultiByte + v100 + + + DynamicLibrary + false + v140 + + + DynamicLibrary + false + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + V:\temp\$(ProjectName)\$(Configuration)/\ + V:\temp\$(ProjectName)\$(Configuration)/\ + false + V:\temp\$(ProjectName)\$(Configuration)\ + V:\temp\$(ProjectName)\$(Configuration)\ + true + .\Playtest\ + $(Configuration)\ + false + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + ns + + + + Full + AnySuitable + true + $(SolutionDir);U:\include\stlport;U:\include\nexus;U:\include\lua;U:\include\particle;U:\include;%(AdditionalIncludeDirectories) + NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;AVH_SECURE_PRERELEASE_BUILD;USE_OLDAUTH + true + true + MultiThreaded + true + true + + + .\Releasehl/hl.pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + ProgramDatabase + Default + + + winmm.lib;ws2_32.lib;particles.lib;liblua.lib;liblualib.lib;ssleay32.lib;libeay32.lib;libcurl.lib;%(AdditionalDependencies) + $(SolutionDir)..\dlls\ns.dll + true + U:\release;%(AdditionalLibraryDirectories) + gdi32.lib user32.lib;%(IgnoreSpecificDefaultLibraries) + .\hl.def + + + Windows + $(OutDir)ns.lib + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Releasehl/hl.tlb + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\engine;%(AdditionalIncludeDirectories) + + + + + Disabled + $(SolutionDir);U:\include\stlport;U:\include\nexus;U:\include\lua;U:\include\particle;U:\include;%(AdditionalIncludeDirectories) + _DEBUG;DEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;AVH_SECURE_PRERELEASE_BUILD;USE_OLDAUTH + MultiThreadedDebug + true + + + .\debughl/hl.pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + true + EditAndContinue + Default + + + winmm.lib;ws2_32.lib;particles.lib;liblua.lib;liblualib.lib;nexus_server.lib;ssleay32.lib;libeay32.lib;libcurl.lib;%(AdditionalDependencies) + $(SolutionDir)..\dlls\ns.dll + true + U:\debug;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + .\hl.def + true + $(OutDir)ns.pdb + true + $(OutDir)ns.map + true + Windows + false + false + $(OutDir)ns.lib + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\debughl/hl.tlb + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\engine;%(AdditionalIncludeDirectories) + + + + + Full + AnySuitable + true + $(SolutionDir);$(SolutionDir)\includes\lua\include;$(SolutionDir)\particles\;$(SolutionDir)\includes\vgui\include;$(SolutionDir)\includes\libcurl-7.50-nossl\include;$(SolutionDir)\common;$(SolutionDir)\public;$(SolutionDir)\util;$(SolutionDir)\engine;%(AdditionalIncludeDirectories) + NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;AVH_NO_NEXUS;USE_OLDAUTH + true + true + MultiThreaded + true + true + + + .\Releasehl/hl.pch + $(IntDir) + $(IntDir) + $(IntDir) + Level2 + true + ProgramDatabase + Default + + + winmm.lib;ws2_32.lib;particles.lib;lua5.1.lib;libcurl_a.lib;%(AdditionalDependencies) + true + gdi32.lib user32.lib;%(IgnoreSpecificDefaultLibraries) + .\hl.def + + + Windows + $(OutDir)ns.lib + MachineX86 + false + false + /NODEFAULTLIB:LIBCMT %(AdditionalOptions) + $(SolutionDir)\includes\lua\lib;$(SolutionDir)\particles\WIN32_Release;$(SolutionDir)\includes\libcurl-7.50-nossl;$(SolutionDir)\includes\vgui\lib\win32_vc6;%(AdditionalLibraryDirectories) + false + false + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Releasehl/hl.tlb + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\engine;%(AdditionalIncludeDirectories) + + + + + Full + AnySuitable + true + $(SolutionDir);U:\include\stlport;U:\include\nexus;U:\include\lua;U:\include\particle;%(AdditionalIncludeDirectories) + NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;AVH_SERVER;SERVER;AVH_PLAYTEST_BUILD + true + true + MultiThreaded + true + true + + + .\Releasehl/hl.pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + ProgramDatabase + Default + + + winmm.lib;ws2_32.lib;particles.lib;liblua.lib;liblualib.lib;ssleay32.lib;libeay32.lib;%(AdditionalDependencies) + $(SolutionDir)..\dlls\ns.dll + true + U:\release;%(AdditionalLibraryDirectories) + gdi32.lib user32.lib;%(IgnoreSpecificDefaultLibraries) + .\hl.def + + + Windows + $(OutDir)ns.lib + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Releasehl/hl.tlb + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + ..\engine;%(AdditionalIncludeDirectories) + + + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + Disabled + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + MaxSpeed + %(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main/source/dlls/hl.vcxproj.filters b/main/source/dlls/hl.vcxproj.filters index 1a21388a..22e30c57 100644 --- a/main/source/dlls/hl.vcxproj.filters +++ b/main/source/dlls/hl.vcxproj.filters @@ -1,902 +1,902 @@ - - - - - {efbe09c8-e8c3-49f4-9ad5-9a4a914ef151} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90 - - - {30433973-1799-46e0-b1fa-5db4f546c14c} - h;hpp;hxx;hm;inl;fi;fd - - - {78edcdfc-2917-4e57-b46d-337ce1517be8} - - - {b9e068b6-65ef-42b9-ad7f-f9b5f5efcc3f} - - - {cfe6fb7f-e4ae-4764-9431-431bb5e6f04c} - - - {1ea05df2-deef-432a-be01-0b6d7a613888} - - - {bdec0058-6589-4e1b-ab38-ecebc623b07f} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - textrep - - - textrep - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\weapons - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - mod\particles - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - util - - - textrep - - - textrep - - - textrep - - - textrep - - + + + + + {efbe09c8-e8c3-49f4-9ad5-9a4a914ef151} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90 + + + {30433973-1799-46e0-b1fa-5db4f546c14c} + h;hpp;hxx;hm;inl;fi;fd + + + {78edcdfc-2917-4e57-b46d-337ce1517be8} + + + {b9e068b6-65ef-42b9-ad7f-f9b5f5efcc3f} + + + {cfe6fb7f-e4ae-4764-9431-431bb5e6f04c} + + + {1ea05df2-deef-432a-be01-0b6d7a613888} + + + {bdec0058-6589-4e1b-ab38-ecebc623b07f} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + textrep + + + textrep + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\weapons + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + mod\particles + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + util + + + textrep + + + textrep + + + textrep + + + textrep + + \ No newline at end of file diff --git a/main/source/dlls/hl.vcxproj.user b/main/source/dlls/hl.vcxproj.user index 1f4deec5..b6c25d8a 100644 --- a/main/source/dlls/hl.vcxproj.user +++ b/main/source/dlls/hl.vcxproj.user @@ -1,9 +1,9 @@ - - - - - - WindowsLocalDebugger - -game ns - + + + + + + WindowsLocalDebugger + -game ns + \ No newline at end of file diff --git a/main/source/dlls/hl_wpn_glock.cpp b/main/source/dlls/hl_wpn_glock.cpp index 3f622743..01e13f6c 100644 --- a/main/source/dlls/hl_wpn_glock.cpp +++ b/main/source/dlls/hl_wpn_glock.cpp @@ -1,277 +1,277 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -enum glock_e { - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); - -char sDebugString[128]; - -void CGlock::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_GLOCK; - SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); - - m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGlock::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmhandgun.mdl"); - PRECACHE_MODEL("models/w_9mmhandgun.mdl"); - PRECACHE_MODEL("models/p_9mmhandgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - PRECACHE_SOUND("items/9mmclip2.wav"); - - PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun - - m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); - m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); -} - -int CGlock::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = GLOCK_MAX_CLIP; - p->iSlot = 1; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_GLOCK; - p->iWeight = GLOCK_WEIGHT; - - return 1; -} - -BOOL CGlock::Deploy( ) -{ - // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); -} - -void CGlock::SecondaryAttack( void ) -{ - GlockFire( 0.1, 0.2, FALSE ); -} - -void CGlock::PrimaryAttack( void ) -{ -#ifdef AVH_CLIENT - static float sTimeOfLastShot = 0; - float theTimeOfThisShot = gpGlobals->time; - float theTimeBetweenShots = theTimeOfThisShot - sTimeOfLastShot; - sTimeOfLastShot = theTimeOfThisShot; - - sprintf(sDebugString, "time between this and last shot: %f", theTimeBetweenShots); - //CenterPrint(theString); -#endif - - //GlockFire( 0.01, 0.3, TRUE ); - GlockFire( 0.01, 0.2, TRUE ); -} - -void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) -{ - if (m_iClip <= 0) - { - if (m_fFireOnEmpty) - { - PlayEmptySound(); - //m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + flCycleTime; - } - - return; - } - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - int flags = FEV_NOTHOST; - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - // silenced - if (pev->body == 1) - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - } - else - { - // non-silenced - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - } - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming; - - if ( fUseAutoAim ) - { - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - } - else - { - vecAiming = gpGlobals->v_forward; - } - - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime; - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CGlock::Reload( void ) -{ - int iResult; - - if (m_iClip == 0) - iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); - else - iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - - if (iResult) - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } -} - - - -void CGlock::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - // only idle if the slid isn't back - if (m_iClip != 0) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); - - if (flRand <= 0.3 + 0 * 0.75) - { - iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; - } - else if (flRand <= 0.6 + 0 * 0.875) - { - iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; - } - else - { - iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - SendWeaponAnim( iAnim, 1 ); - } -} - - - - - - - - -class CGlockAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); - - - - - - - - - - - - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + +enum glock_e { + GLOCK_IDLE1 = 0, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD, + GLOCK_RELOAD_NOT_EMPTY, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_ADD_SILENCER +}; + +LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); +LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); + +char sDebugString[128]; + +void CGlock::Spawn( ) +{ + pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names + Precache( ); + m_iId = WEAPON_GLOCK; + SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); + + m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CGlock::Precache( void ) +{ + PRECACHE_MODEL("models/v_9mmhandgun.mdl"); + PRECACHE_MODEL("models/w_9mmhandgun.mdl"); + PRECACHE_MODEL("models/p_9mmhandgun.mdl"); + + m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell + + PRECACHE_SOUND("items/9mmclip1.wav"); + PRECACHE_SOUND("items/9mmclip2.wav"); + + PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun + + m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); + m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); +} + +int CGlock::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "9mm"; + p->iMaxAmmo1 = _9MM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = GLOCK_MAX_CLIP; + p->iSlot = 1; + p->iPosition = 0; + p->iFlags = 0; + p->iId = m_iId = WEAPON_GLOCK; + p->iWeight = GLOCK_WEIGHT; + + return 1; +} + +BOOL CGlock::Deploy( ) +{ + // pev->body = 1; + return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); +} + +void CGlock::SecondaryAttack( void ) +{ + GlockFire( 0.1, 0.2, FALSE ); +} + +void CGlock::PrimaryAttack( void ) +{ +#ifdef AVH_CLIENT + static float sTimeOfLastShot = 0; + float theTimeOfThisShot = gpGlobals->time; + float theTimeBetweenShots = theTimeOfThisShot - sTimeOfLastShot; + sTimeOfLastShot = theTimeOfThisShot; + + sprintf(sDebugString, "time between this and last shot: %f", theTimeBetweenShots); + //CenterPrint(theString); +#endif + + //GlockFire( 0.01, 0.3, TRUE ); + GlockFire( 0.01, 0.2, TRUE ); +} + +void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) +{ + if (m_iClip <= 0) + { + if (m_fFireOnEmpty) + { + PlayEmptySound(); + //m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + flCycleTime; + } + + return; + } + + m_iClip--; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + + int flags = FEV_NOTHOST; + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + // silenced + if (pev->body == 1) + { + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; + } + else + { + // non-silenced + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; + } + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming; + + if ( fUseAutoAim ) + { + vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + else + { + vecAiming = gpGlobals->v_forward; + } + + m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime; + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +} + + +void CGlock::Reload( void ) +{ + int iResult; + + if (m_iClip == 0) + iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); + else + iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + + if (iResult) + { + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } +} + + + +void CGlock::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + // only idle if the slid isn't back + if (m_iClip != 0) + { + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); + + if (flRand <= 0.3 + 0 * 0.75) + { + iAnim = GLOCK_IDLE3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; + } + else if (flRand <= 0.6 + 0 * 0.875) + { + iAnim = GLOCK_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; + } + else + { + iAnim = GLOCK_IDLE2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; + } + SendWeaponAnim( iAnim, 1 ); + } +} + + + + + + + + +class CGlockAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_9mmclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); +LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); + + + + + + + + + + + + + + + diff --git a/main/source/dlls/hl_wpn_glock.cpp~ b/main/source/dlls/hl_wpn_glock.cpp~ deleted file mode 100644 index 37ea97ce..00000000 --- a/main/source/dlls/hl_wpn_glock.cpp~ +++ /dev/null @@ -1,277 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "dlls/extdll.h" -#include "dlls/util.h" -#include "dlls/cbase.h" -#include "dlls/monsters.h" -#include "dlls/weapons.h" -#include "dlls/nodes.h" -#include "dlls/player.h" - -enum glock_e { - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); - -char sDebugString[128]; - -void CGlock::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_GLOCK; - SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); - - m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGlock::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmhandgun.mdl"); - PRECACHE_MODEL("models/w_9mmhandgun.mdl"); - PRECACHE_MODEL("models/p_9mmhandgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - PRECACHE_SOUND("items/9mmclip2.wav"); - - PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun - - m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); - m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); -} - -int CGlock::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = GLOCK_MAX_CLIP; - p->iSlot = 1; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_GLOCK; - p->iWeight = GLOCK_WEIGHT; - - return 1; -} - -BOOL CGlock::Deploy( ) -{ - // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); -} - -void CGlock::SecondaryAttack( void ) -{ - GlockFire( 0.1, 0.2, FALSE ); -} - -void CGlock::PrimaryAttack( void ) -{ -#ifdef AVH_CLIENT - static float sTimeOfLastShot = 0; - float theTimeOfThisShot = gpGlobals->time; - float theTimeBetweenShots = theTimeOfThisShot - sTimeOfLastShot; - sTimeOfLastShot = theTimeOfThisShot; - - sprintf(sDebugString, "time between this and last shot: %f", theTimeBetweenShots); - //CenterPrint(theString); -#endif - - //GlockFire( 0.01, 0.3, TRUE ); - GlockFire( 0.01, 0.2, TRUE ); -} - -void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) -{ - if (m_iClip <= 0) - { - if (m_fFireOnEmpty) - { - PlayEmptySound(); - //m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + flCycleTime; - } - - return; - } - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - int flags = FEV_NOTHOST; - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - // silenced - if (pev->body == 1) - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - } - else - { - // non-silenced - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - } - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming; - - if ( fUseAutoAim ) - { - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - } - else - { - vecAiming = gpGlobals->v_forward; - } - - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime; - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CGlock::Reload( void ) -{ - int iResult; - - if (m_iClip == 0) - iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); - else - iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - - if (iResult) - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } -} - - - -void CGlock::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - // only idle if the slid isn't back - if (m_iClip != 0) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); - - if (flRand <= 0.3 + 0 * 0.75) - { - iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; - } - else if (flRand <= 0.6 + 0 * 0.875) - { - iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; - } - else - { - iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - SendWeaponAnim( iAnim, 1 ); - } -} - - - - - - - - -class CGlockAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); - - - - - - - - - - - - - - - diff --git a/main/source/dlls/hornet.cpp b/main/source/dlls/hornet.cpp index 8517b974..c17736ec 100644 --- a/main/source/dlls/hornet.cpp +++ b/main/source/dlls/hornet.cpp @@ -1,419 +1,419 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Hornets -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "soundent.h" -#include "hornet.h" -#include "gamerules.h" - - -int iHornetTrail; -int iHornetPuff; - -LINK_ENTITY_TO_CLASS( hornet, CHornet ); - -//========================================================= -// Save/Restore -//========================================================= -TYPEDESCRIPTION CHornet::m_SaveData[] = -{ - DEFINE_FIELD( CHornet, m_flStopAttack, FIELD_TIME ), - DEFINE_FIELD( CHornet, m_iHornetType, FIELD_INTEGER ), - DEFINE_FIELD( CHornet, m_flFlySpeed, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster ); - -//========================================================= -// don't let hornets gib, ever. -//========================================================= -int CHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // filter these bits a little. - bitsDamageType &= ~ ( DMG_ALWAYSGIB ); - bitsDamageType |= DMG_NEVERGIB; - - return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -//========================================================= -void CHornet :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - pev->takedamage = DAMAGE_YES; - pev->flags |= FL_MONSTER; - pev->health = 1;// weak! - - if ( g_pGameRules->IsMultiplayer() ) - { - // hornets don't live as long in multiplayer - m_flStopAttack = gpGlobals->time + 3.5; - } - else - { - m_flStopAttack = gpGlobals->time + 5.0; - } - - m_flFieldOfView = 0.9; // +- 25 degrees - - if ( RANDOM_LONG ( 1, 5 ) <= 2 ) - { - m_iHornetType = HORNET_TYPE_RED; - m_flFlySpeed = HORNET_RED_SPEED; - } - else - { - m_iHornetType = HORNET_TYPE_ORANGE; - m_flFlySpeed = HORNET_ORANGE_SPEED; - } - - SET_MODEL(ENT( pev ), "models/hornet.mdl"); - UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); - - SetTouch( &CHornet::DieTouch ); - SetThink( &CHornet::StartTrack ); - - edict_t *pSoundEnt = pev->owner; - if ( !pSoundEnt ) - pSoundEnt = edict(); - - if ( !FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT) ) - { - pev->dmg = gSkillData.plrDmgHornet; - } - else - { - // no real owner, or owner isn't a client. - pev->dmg = gSkillData.monDmgHornet; - } - - pev->nextthink = gpGlobals->time + 0.1; - ResetSequenceInfo( ); -} - - -void CHornet :: Precache() -{ - PRECACHE_MODEL("models/hornet.mdl"); - - PRECACHE_SOUND( "agrunt/ag_fire1.wav" ); - PRECACHE_SOUND( "agrunt/ag_fire2.wav" ); - PRECACHE_SOUND( "agrunt/ag_fire3.wav" ); - - PRECACHE_SOUND( "hornet/ag_buzz1.wav" ); - PRECACHE_SOUND( "hornet/ag_buzz2.wav" ); - PRECACHE_SOUND( "hornet/ag_buzz3.wav" ); - - PRECACHE_SOUND( "hornet/ag_hornethit1.wav" ); - PRECACHE_SOUND( "hornet/ag_hornethit2.wav" ); - PRECACHE_SOUND( "hornet/ag_hornethit3.wav" ); - - iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" ); - iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr"); -} - -//========================================================= -// hornets will never get mad at each other, no matter who the owner is. -//========================================================= -int CHornet::IRelationship ( CBaseEntity *pTarget ) -{ - if ( pTarget->pev->modelindex == pev->modelindex ) - { - return R_NO; - } - - return CBaseMonster :: IRelationship( pTarget ); -} - -//========================================================= -// ID's Hornet as their owner -//========================================================= -int CHornet::Classify ( void ) -{ - - if ( pev->owner && pev->owner->v.flags & FL_CLIENT) - { - return CLASS_PLAYER_BIOWEAPON; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -//========================================================= -// StartTrack - starts a hornet out tracking its target -//========================================================= -void CHornet :: StartTrack ( void ) -{ - IgniteTrail(); - - SetTouch( &CHornet::TrackTouch ); - SetThink( &CHornet::TrackTarget ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -//========================================================= -// StartDart - starts a hornet out just flying straight. -//========================================================= -void CHornet :: StartDart ( void ) -{ - IgniteTrail(); - - SetTouch( &CHornet::DartTouch ); - - SetThink( &CHornet::SUB_Remove ); - pev->nextthink = gpGlobals->time + 4; -} - -void CHornet::IgniteTrail( void ) -{ -/* - - ted's suggested trail colors: - -r161 -g25 -b97 - -r173 -g39 -b14 - -old colors - case HORNET_TYPE_RED: - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - break; - case HORNET_TYPE_ORANGE: - WRITE_BYTE( 0 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - break; - -*/ - - // trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT( entindex() ); // entity - WRITE_SHORT( iHornetTrail ); // model - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 2 ); // width - - switch ( m_iHornetType ) - { - case HORNET_TYPE_RED: - WRITE_BYTE( 179 ); // r, g, b - WRITE_BYTE( 39 ); // r, g, b - WRITE_BYTE( 14 ); // r, g, b - break; - case HORNET_TYPE_ORANGE: - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - break; - } - - WRITE_BYTE( 128 ); // brightness - - MESSAGE_END(); -} - -//========================================================= -// Hornet is flying, gently tracking target -//========================================================= -void CHornet :: TrackTarget ( void ) -{ - Vector vecFlightDir; - Vector vecDirToEnemy; - float flDelta; - - StudioFrameAdvance( ); - - if (gpGlobals->time > m_flStopAttack) - { - SetTouch( NULL ); - SetThink( &CHornet::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - // UNDONE: The player pointer should come back after returning from another level - if ( m_hEnemy == NULL ) - {// enemy is dead. - Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); - } - - if ( m_hEnemy != NULL && FVisible( m_hEnemy )) - { - m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin ); - } - else - { - m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1; - } - - vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize(); - - if (pev->velocity.Length() < 0.1) - vecFlightDir = vecDirToEnemy; - else - vecFlightDir = pev->velocity.Normalize(); - - // measure how far the turn is, the wider the turn, the slow we'll go this time. - flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); - - if ( flDelta < 0.5 ) - {// hafta turn wide again. play sound - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - } - } - - if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) - {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. - flDelta = 0.25; - } - - pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize(); - - if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) ) - { - // random pattern only applies to hornets fired by monsters, not players. - - pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit. - pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 ); - pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 ); - } - - switch ( m_iHornetType ) - { - case HORNET_TYPE_RED: - pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); - break; - case HORNET_TYPE_ORANGE: - pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn. - pev->nextthink = gpGlobals->time + 0.1;// fixed think time - break; - } - - pev->angles = UTIL_VecToAngles (pev->velocity); - - pev->solid = SOLID_BBOX; - - // if hornet is close to the enemy, jet in a straight line for a half second. - // (only in the single player game) - if ( m_hEnemy != NULL && !g_pGameRules->IsMultiplayer() ) - { - if ( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 ) - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( pev->origin.x); // pos - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z); - WRITE_SHORT( iHornetPuff ); // model - // WRITE_BYTE( 0 ); // life * 10 - WRITE_BYTE( 2 ); // size * 10 - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); - - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - } - pev->velocity = pev->velocity * 2; - pev->nextthink = gpGlobals->time + 1.0; - // don't attack again - m_flStopAttack = gpGlobals->time; - } - } -} - -//========================================================= -// Tracking Hornet hit something -//========================================================= -void CHornet :: TrackTouch ( CBaseEntity *pOther ) -{ - if ( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex ) - {// bumped into the guy that shot it. - pev->solid = SOLID_NOT; - return; - } - - if ( IRelationship( pOther ) <= R_NO ) - { - // hit something we don't want to hurt, so turn around. - - pev->velocity = pev->velocity.Normalize(); - - pev->velocity.x *= -1; - pev->velocity.y *= -1; - - pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit. - pev->velocity = pev->velocity * m_flFlySpeed; - - return; - } - - DieTouch( pOther ); -} - -void CHornet::DartTouch( CBaseEntity *pOther ) -{ - DieTouch( pOther ); -} - -void CHornet::DieTouch ( CBaseEntity *pOther ) -{ - if ( pOther && pOther->pev->takedamage ) - {// do the damage - - switch (RANDOM_LONG(0,2)) - {// buzz when you plug someone - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM); break; - } - - pOther->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET ); - } - - pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid - pev->solid = SOLID_NOT; - - SetThink &CHornet::( SUB_Remove ); - pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Hornets +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "soundent.h" +#include "hornet.h" +#include "gamerules.h" + + +int iHornetTrail; +int iHornetPuff; + +LINK_ENTITY_TO_CLASS( hornet, CHornet ); + +//========================================================= +// Save/Restore +//========================================================= +TYPEDESCRIPTION CHornet::m_SaveData[] = +{ + DEFINE_FIELD( CHornet, m_flStopAttack, FIELD_TIME ), + DEFINE_FIELD( CHornet, m_iHornetType, FIELD_INTEGER ), + DEFINE_FIELD( CHornet, m_flFlySpeed, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster ); + +//========================================================= +// don't let hornets gib, ever. +//========================================================= +int CHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + // filter these bits a little. + bitsDamageType &= ~ ( DMG_ALWAYSGIB ); + bitsDamageType |= DMG_NEVERGIB; + + return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +//========================================================= +//========================================================= +void CHornet :: Spawn( void ) +{ + Precache(); + + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + pev->takedamage = DAMAGE_YES; + pev->flags |= FL_MONSTER; + pev->health = 1;// weak! + + if ( g_pGameRules->IsMultiplayer() ) + { + // hornets don't live as long in multiplayer + m_flStopAttack = gpGlobals->time + 3.5; + } + else + { + m_flStopAttack = gpGlobals->time + 5.0; + } + + m_flFieldOfView = 0.9; // +- 25 degrees + + if ( RANDOM_LONG ( 1, 5 ) <= 2 ) + { + m_iHornetType = HORNET_TYPE_RED; + m_flFlySpeed = HORNET_RED_SPEED; + } + else + { + m_iHornetType = HORNET_TYPE_ORANGE; + m_flFlySpeed = HORNET_ORANGE_SPEED; + } + + SET_MODEL(ENT( pev ), "models/hornet.mdl"); + UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); + + SetTouch( &CHornet::DieTouch ); + SetThink( &CHornet::StartTrack ); + + edict_t *pSoundEnt = pev->owner; + if ( !pSoundEnt ) + pSoundEnt = edict(); + + if ( !FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT) ) + { + pev->dmg = gSkillData.plrDmgHornet; + } + else + { + // no real owner, or owner isn't a client. + pev->dmg = gSkillData.monDmgHornet; + } + + pev->nextthink = gpGlobals->time + 0.1; + ResetSequenceInfo( ); +} + + +void CHornet :: Precache() +{ + PRECACHE_MODEL("models/hornet.mdl"); + + PRECACHE_SOUND( "agrunt/ag_fire1.wav" ); + PRECACHE_SOUND( "agrunt/ag_fire2.wav" ); + PRECACHE_SOUND( "agrunt/ag_fire3.wav" ); + + PRECACHE_SOUND( "hornet/ag_buzz1.wav" ); + PRECACHE_SOUND( "hornet/ag_buzz2.wav" ); + PRECACHE_SOUND( "hornet/ag_buzz3.wav" ); + + PRECACHE_SOUND( "hornet/ag_hornethit1.wav" ); + PRECACHE_SOUND( "hornet/ag_hornethit2.wav" ); + PRECACHE_SOUND( "hornet/ag_hornethit3.wav" ); + + iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" ); + iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr"); +} + +//========================================================= +// hornets will never get mad at each other, no matter who the owner is. +//========================================================= +int CHornet::IRelationship ( CBaseEntity *pTarget ) +{ + if ( pTarget->pev->modelindex == pev->modelindex ) + { + return R_NO; + } + + return CBaseMonster :: IRelationship( pTarget ); +} + +//========================================================= +// ID's Hornet as their owner +//========================================================= +int CHornet::Classify ( void ) +{ + + if ( pev->owner && pev->owner->v.flags & FL_CLIENT) + { + return CLASS_PLAYER_BIOWEAPON; + } + + return CLASS_ALIEN_BIOWEAPON; +} + +//========================================================= +// StartTrack - starts a hornet out tracking its target +//========================================================= +void CHornet :: StartTrack ( void ) +{ + IgniteTrail(); + + SetTouch( &CHornet::TrackTouch ); + SetThink( &CHornet::TrackTarget ); + + pev->nextthink = gpGlobals->time + 0.1; +} + +//========================================================= +// StartDart - starts a hornet out just flying straight. +//========================================================= +void CHornet :: StartDart ( void ) +{ + IgniteTrail(); + + SetTouch( &CHornet::DartTouch ); + + SetThink( &CHornet::SUB_Remove ); + pev->nextthink = gpGlobals->time + 4; +} + +void CHornet::IgniteTrail( void ) +{ +/* + + ted's suggested trail colors: + +r161 +g25 +b97 + +r173 +g39 +b14 + +old colors + case HORNET_TYPE_RED: + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 0 ); // r, g, b + break; + case HORNET_TYPE_ORANGE: + WRITE_BYTE( 0 ); // r, g, b + WRITE_BYTE( 100 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + break; + +*/ + + // trail + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMFOLLOW ); + WRITE_SHORT( entindex() ); // entity + WRITE_SHORT( iHornetTrail ); // model + WRITE_BYTE( 10 ); // life + WRITE_BYTE( 2 ); // width + + switch ( m_iHornetType ) + { + case HORNET_TYPE_RED: + WRITE_BYTE( 179 ); // r, g, b + WRITE_BYTE( 39 ); // r, g, b + WRITE_BYTE( 14 ); // r, g, b + break; + case HORNET_TYPE_ORANGE: + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 0 ); // r, g, b + break; + } + + WRITE_BYTE( 128 ); // brightness + + MESSAGE_END(); +} + +//========================================================= +// Hornet is flying, gently tracking target +//========================================================= +void CHornet :: TrackTarget ( void ) +{ + Vector vecFlightDir; + Vector vecDirToEnemy; + float flDelta; + + StudioFrameAdvance( ); + + if (gpGlobals->time > m_flStopAttack) + { + SetTouch( NULL ); + SetThink( &CHornet::SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + return; + } + + // UNDONE: The player pointer should come back after returning from another level + if ( m_hEnemy == NULL ) + {// enemy is dead. + Look( 512 ); + m_hEnemy = BestVisibleEnemy( ); + } + + if ( m_hEnemy != NULL && FVisible( m_hEnemy )) + { + m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin ); + } + else + { + m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1; + } + + vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize(); + + if (pev->velocity.Length() < 0.1) + vecFlightDir = vecDirToEnemy; + else + vecFlightDir = pev->velocity.Normalize(); + + // measure how far the turn is, the wider the turn, the slow we'll go this time. + flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); + + if ( flDelta < 0.5 ) + {// hafta turn wide again. play sound + switch (RANDOM_LONG(0,2)) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; + case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; + } + } + + if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) + {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. + flDelta = 0.25; + } + + pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize(); + + if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) ) + { + // random pattern only applies to hornets fired by monsters, not players. + + pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit. + pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 ); + pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 ); + } + + switch ( m_iHornetType ) + { + case HORNET_TYPE_RED: + pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn ) + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); + break; + case HORNET_TYPE_ORANGE: + pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn. + pev->nextthink = gpGlobals->time + 0.1;// fixed think time + break; + } + + pev->angles = UTIL_VecToAngles (pev->velocity); + + pev->solid = SOLID_BBOX; + + // if hornet is close to the enemy, jet in a straight line for a half second. + // (only in the single player game) + if ( m_hEnemy != NULL && !g_pGameRules->IsMultiplayer() ) + { + if ( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 ) + { + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SPRITE ); + WRITE_COORD( pev->origin.x); // pos + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z); + WRITE_SHORT( iHornetPuff ); // model + // WRITE_BYTE( 0 ); // life * 10 + WRITE_BYTE( 2 ); // size * 10 + WRITE_BYTE( 128 ); // brightness + MESSAGE_END(); + + switch (RANDOM_LONG(0,2)) + { + case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; + case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; + } + pev->velocity = pev->velocity * 2; + pev->nextthink = gpGlobals->time + 1.0; + // don't attack again + m_flStopAttack = gpGlobals->time; + } + } +} + +//========================================================= +// Tracking Hornet hit something +//========================================================= +void CHornet :: TrackTouch ( CBaseEntity *pOther ) +{ + if ( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex ) + {// bumped into the guy that shot it. + pev->solid = SOLID_NOT; + return; + } + + if ( IRelationship( pOther ) <= R_NO ) + { + // hit something we don't want to hurt, so turn around. + + pev->velocity = pev->velocity.Normalize(); + + pev->velocity.x *= -1; + pev->velocity.y *= -1; + + pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit. + pev->velocity = pev->velocity * m_flFlySpeed; + + return; + } + + DieTouch( pOther ); +} + +void CHornet::DartTouch( CBaseEntity *pOther ) +{ + DieTouch( pOther ); +} + +void CHornet::DieTouch ( CBaseEntity *pOther ) +{ + if ( pOther && pOther->pev->takedamage ) + {// do the damage + + switch (RANDOM_LONG(0,2)) + {// buzz when you plug someone + case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM); break; + case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM); break; + case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM); break; + } + + pOther->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET ); + } + + pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid + pev->solid = SOLID_NOT; + + SetThink &CHornet::( SUB_Remove ); + pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! +} + diff --git a/main/source/dlls/hornet.h b/main/source/dlls/hornet.h index 2145c76f..ac0ac18d 100644 --- a/main/source/dlls/hornet.h +++ b/main/source/dlls/hornet.h @@ -1,58 +1,58 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Hornets -//========================================================= - -//========================================================= -// Hornet Defines -//========================================================= -#define HORNET_TYPE_RED 0 -#define HORNET_TYPE_ORANGE 1 -#define HORNET_RED_SPEED (float)600 -#define HORNET_ORANGE_SPEED (float)800 -#define HORNET_BUZZ_VOLUME (float)0.8 - -extern int iHornetPuff; - -//========================================================= -// Hornet - this is the projectile that the Alien Grunt fires. -//========================================================= -class CHornet : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - int Classify ( void ); - int IRelationship ( CBaseEntity *pTarget ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void IgniteTrail( void ); - void EXPORT StartTrack ( void ); - void EXPORT StartDart ( void ); - void EXPORT TrackTarget ( void ); - void EXPORT TrackTouch ( CBaseEntity *pOther ); - void EXPORT DartTouch( CBaseEntity *pOther ); - void EXPORT DieTouch ( CBaseEntity *pOther ); - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - float m_flStopAttack; - int m_iHornetType; - float m_flFlySpeed; -}; - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Hornets +//========================================================= + +//========================================================= +// Hornet Defines +//========================================================= +#define HORNET_TYPE_RED 0 +#define HORNET_TYPE_ORANGE 1 +#define HORNET_RED_SPEED (float)600 +#define HORNET_ORANGE_SPEED (float)800 +#define HORNET_BUZZ_VOLUME (float)0.8 + +extern int iHornetPuff; + +//========================================================= +// Hornet - this is the projectile that the Alien Grunt fires. +//========================================================= +class CHornet : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + int Classify ( void ); + int IRelationship ( CBaseEntity *pTarget ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void IgniteTrail( void ); + void EXPORT StartTrack ( void ); + void EXPORT StartDart ( void ); + void EXPORT TrackTarget ( void ); + void EXPORT TrackTouch ( CBaseEntity *pOther ); + void EXPORT DartTouch( CBaseEntity *pOther ); + void EXPORT DieTouch ( CBaseEntity *pOther ); + + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + float m_flStopAttack; + int m_iHornetType; + float m_flFlySpeed; +}; + diff --git a/main/source/dlls/hornetgun.cpp b/main/source/dlls/hornetgun.cpp index d56e4916..624100ff 100644 --- a/main/source/dlls/hornetgun.cpp +++ b/main/source/dlls/hornetgun.cpp @@ -1,305 +1,305 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "hornet.h" -#include "gamerules.h" - - -enum hgun_e { - HGUN_IDLE1 = 0, - HGUN_FIDGETSWAY, - HGUN_FIDGETSHAKE, - HGUN_DOWN, - HGUN_UP, - HGUN_SHOOT -}; - -enum firemode_e -{ - FIREMODE_TRACK = 0, - FIREMODE_FAST -}; - - -LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ); - -BOOL CHgun::IsUseable( void ) -{ - return TRUE; -} - -void CHgun::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_HORNETGUN; - SET_MODEL(ENT(pev), "models/w_hgun.mdl"); - - m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE; - m_iFirePhase = 0; - - FallInit();// get ready to fall down. -} - - -void CHgun::Precache( void ) -{ - PRECACHE_MODEL("models/v_hgun.mdl"); - PRECACHE_MODEL("models/w_hgun.mdl"); - PRECACHE_MODEL("models/p_hgun.mdl"); - - m_usHornetFire = PRECACHE_EVENT ( 1, "events/firehornet.sc" ); - - UTIL_PrecacheOther("hornet"); -} - -int CHgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - -#ifndef CLIENT_DLL - if ( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, all hivehands come full. - pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY; - } -#endif - - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -int CHgun::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Hornets"; - p->iMaxAmmo1 = HORNET_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 3; - p->iId = m_iId = WEAPON_HORNETGUN; - p->iFlags = ITEM_FLAG_NOAUTOSWITCHEMPTY | ITEM_FLAG_NOAUTORELOAD; - p->iWeight = HORNETGUN_WEIGHT; - - return 1; -} - - -BOOL CHgun::Deploy( ) -{ - return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); -} - -void CHgun::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( HGUN_DOWN ); - - //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. - if ( !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ) - { - m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = 1; - } -} - - -void CHgun::PrimaryAttack() -{ - Reload( ); - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - { - return; - } - -#ifndef CLIENT_DLL - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pHornet->pev->velocity = gpGlobals->v_forward * 300; - - m_flRechargeTime = gpGlobals->time + 0.5; -#endif - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 ); - - - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25; - - if (m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - { - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - } - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - - -void CHgun::SecondaryAttack( void ) -{ - Reload(); - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - { - return; - } - - //Wouldn't be a bad idea to completely predict these, since they fly so fast... -#ifndef CLIENT_DLL - CBaseEntity *pHornet; - Vector vecSrc; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - - vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; - - m_iFirePhase++; - switch ( m_iFirePhase ) - { - case 1: - vecSrc = vecSrc + gpGlobals->v_up * 8; - break; - case 2: - vecSrc = vecSrc + gpGlobals->v_up * 8; - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 3: - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 4: - vecSrc = vecSrc + gpGlobals->v_up * -8; - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 5: - vecSrc = vecSrc + gpGlobals->v_up * -8; - break; - case 6: - vecSrc = vecSrc + gpGlobals->v_up * -8; - vecSrc = vecSrc + gpGlobals->v_right * -8; - break; - case 7: - vecSrc = vecSrc + gpGlobals->v_right * -8; - break; - case 8: - vecSrc = vecSrc + gpGlobals->v_up * 8; - vecSrc = vecSrc + gpGlobals->v_right * -8; - m_iFirePhase = 0; - break; - } - - pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pHornet->pev->velocity = gpGlobals->v_forward * 1200; - pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); - - pHornet->SetThink( &CHornet::StartDart ); - - m_flRechargeTime = gpGlobals->time + 0.5; -#endif - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); - - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CHgun::Reload( void ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY) - return; - - while (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time) - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++; - m_flRechargeTime += 0.5; - } -} - - -void CHgun::WeaponIdle( void ) -{ - Reload( ); - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - iAnim = HGUN_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); - } - else if (flRand <= 0.875) - { - iAnim = HGUN_FIDGETSWAY; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - else - { - iAnim = HGUN_FIDGETSHAKE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0; - } - SendWeaponAnim( iAnim ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "hornet.h" +#include "gamerules.h" + + +enum hgun_e { + HGUN_IDLE1 = 0, + HGUN_FIDGETSWAY, + HGUN_FIDGETSHAKE, + HGUN_DOWN, + HGUN_UP, + HGUN_SHOOT +}; + +enum firemode_e +{ + FIREMODE_TRACK = 0, + FIREMODE_FAST +}; + + +LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ); + +BOOL CHgun::IsUseable( void ) +{ + return TRUE; +} + +void CHgun::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_HORNETGUN; + SET_MODEL(ENT(pev), "models/w_hgun.mdl"); + + m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE; + m_iFirePhase = 0; + + FallInit();// get ready to fall down. +} + + +void CHgun::Precache( void ) +{ + PRECACHE_MODEL("models/v_hgun.mdl"); + PRECACHE_MODEL("models/w_hgun.mdl"); + PRECACHE_MODEL("models/p_hgun.mdl"); + + m_usHornetFire = PRECACHE_EVENT ( 1, "events/firehornet.sc" ); + + UTIL_PrecacheOther("hornet"); +} + +int CHgun::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + +#ifndef CLIENT_DLL + if ( g_pGameRules->IsMultiplayer() ) + { + // in multiplayer, all hivehands come full. + pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY; + } +#endif + + MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); + WRITE_BYTE( m_iId ); + MESSAGE_END(); + return TRUE; + } + return FALSE; +} + +int CHgun::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "Hornets"; + p->iMaxAmmo1 = HORNET_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 3; + p->iPosition = 3; + p->iId = m_iId = WEAPON_HORNETGUN; + p->iFlags = ITEM_FLAG_NOAUTOSWITCHEMPTY | ITEM_FLAG_NOAUTORELOAD; + p->iWeight = HORNETGUN_WEIGHT; + + return 1; +} + + +BOOL CHgun::Deploy( ) +{ + return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); +} + +void CHgun::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + SendWeaponAnim( HGUN_DOWN ); + + //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. + if ( !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ) + { + m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = 1; + } +} + + +void CHgun::PrimaryAttack() +{ + Reload( ); + + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + { + return; + } + +#ifndef CLIENT_DLL + UTIL_MakeVectors( m_pPlayer->pev->v_angle ); + + CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); + pHornet->pev->velocity = gpGlobals->v_forward * 300; + + m_flRechargeTime = gpGlobals->time + 0.5; +#endif + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + + + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 ); + + + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25; + + if (m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) + { + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + } + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +} + + + +void CHgun::SecondaryAttack( void ) +{ + Reload(); + + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + { + return; + } + + //Wouldn't be a bad idea to completely predict these, since they fly so fast... +#ifndef CLIENT_DLL + CBaseEntity *pHornet; + Vector vecSrc; + + UTIL_MakeVectors( m_pPlayer->pev->v_angle ); + + vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; + + m_iFirePhase++; + switch ( m_iFirePhase ) + { + case 1: + vecSrc = vecSrc + gpGlobals->v_up * 8; + break; + case 2: + vecSrc = vecSrc + gpGlobals->v_up * 8; + vecSrc = vecSrc + gpGlobals->v_right * 8; + break; + case 3: + vecSrc = vecSrc + gpGlobals->v_right * 8; + break; + case 4: + vecSrc = vecSrc + gpGlobals->v_up * -8; + vecSrc = vecSrc + gpGlobals->v_right * 8; + break; + case 5: + vecSrc = vecSrc + gpGlobals->v_up * -8; + break; + case 6: + vecSrc = vecSrc + gpGlobals->v_up * -8; + vecSrc = vecSrc + gpGlobals->v_right * -8; + break; + case 7: + vecSrc = vecSrc + gpGlobals->v_right * -8; + break; + case 8: + vecSrc = vecSrc + gpGlobals->v_up * 8; + vecSrc = vecSrc + gpGlobals->v_right * -8; + m_iFirePhase = 0; + break; + } + + pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); + pHornet->pev->velocity = gpGlobals->v_forward * 1200; + pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); + + pHornet->SetThink( &CHornet::StartDart ); + + m_flRechargeTime = gpGlobals->time + 0.5; +#endif + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); + + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +} + + +void CHgun::Reload( void ) +{ + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY) + return; + + while (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time) + { + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++; + m_flRechargeTime += 0.5; + } +} + + +void CHgun::WeaponIdle( void ) +{ + Reload( ); + + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + return; + + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if (flRand <= 0.75) + { + iAnim = HGUN_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); + } + else if (flRand <= 0.875) + { + iAnim = HGUN_FIDGETSWAY; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; + } + else + { + iAnim = HGUN_FIDGETSHAKE; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0; + } + SendWeaponAnim( iAnim ); +} + #endif \ No newline at end of file diff --git a/main/source/dlls/houndeye.cpp b/main/source/dlls/houndeye.cpp index ae5c9ec8..9f05e91f 100644 --- a/main/source/dlls/houndeye.cpp +++ b/main/source/dlls/houndeye.cpp @@ -1,1304 +1,1304 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Houndeye - spooky sonic dog. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "nodes.h" -#include "squadmonster.h" -#include "soundent.h" -#include "game.h" - -extern CGraph WorldGraph; - -// houndeye does 20 points of damage spread over a sphere 384 units in diameter, and each additional -// squad member increases the BASE damage by 110%, per the spec. -#define HOUNDEYE_MAX_SQUAD_SIZE 4 -#define HOUNDEYE_MAX_ATTACK_RADIUS 384 -#define HOUNDEYE_SQUAD_BONUS (float)1.1 - -#define HOUNDEYE_EYE_FRAMES 4 // how many different switchable maps for the eye - -#define HOUNDEYE_SOUND_STARTLE_VOLUME 128 // how loud a sound has to be to badly scare a sleeping houndeye - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_HOUND_CLOSE_EYE = LAST_COMMON_TASK + 1, - TASK_HOUND_OPEN_EYE, - TASK_HOUND_THREAT_DISPLAY, - TASK_HOUND_FALL_ASLEEP, - TASK_HOUND_WAKE_UP, - TASK_HOUND_HOP_BACK -}; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_HOUND_AGITATED = LAST_COMMON_SCHEDULE + 1, - SCHED_HOUND_HOP_RETREAT, - SCHED_HOUND_FAIL, -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HOUND_AE_WARN 1 -#define HOUND_AE_STARTATTACK 2 -#define HOUND_AE_THUMP 3 -#define HOUND_AE_ANGERSOUND1 4 -#define HOUND_AE_ANGERSOUND2 5 -#define HOUND_AE_HOPBACK 6 -#define HOUND_AE_CLOSE_EYE 7 - -class CHoundeye : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetYawSpeed ( void ); - void WarmUpSound ( void ); - void AlertSound( void ); - void DeathSound( void ); - void WarnSound( void ); - void PainSound( void ); - void IdleSound( void ); - void StartTask( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - void SonicAttack( void ); - void PrescheduleThink( void ); - void SetActivity ( Activity NewActivity ); - void WriteBeamColor ( void ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL FValidateHintType ( short sHint ); - BOOL FCanActiveIdle ( void ); - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *CHoundeye :: GetSchedule( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CUSTOM_SCHEDULES; - static TYPEDESCRIPTION m_SaveData[]; - - int m_iSpriteTexture; - BOOL m_fAsleep;// some houndeyes sleep in idle mode if this is set, the houndeye is lying down - BOOL m_fDontBlink;// don't try to open/close eye if this bit is set! - Vector m_vecPackCenter; // the center of the pack. The leader maintains this by averaging the origins of all pack members. -}; -LINK_ENTITY_TO_CLASS( monster_houndeye, CHoundeye ); - -TYPEDESCRIPTION CHoundeye::m_SaveData[] = -{ - DEFINE_FIELD( CHoundeye, m_iSpriteTexture, FIELD_INTEGER ), - DEFINE_FIELD( CHoundeye, m_fAsleep, FIELD_BOOLEAN ), - DEFINE_FIELD( CHoundeye, m_fDontBlink, FIELD_BOOLEAN ), - DEFINE_FIELD( CHoundeye, m_vecPackCenter, FIELD_POSITION_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHoundeye :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// FValidateHintType -//========================================================= -BOOL CHoundeye :: FValidateHintType ( short sHint ) -{ - int i; - - static short sHoundHints[] = - { - HINT_WORLD_MACHINERY, - HINT_WORLD_BLINKING_LIGHT, - HINT_WORLD_HUMAN_BLOOD, - HINT_WORLD_ALIEN_BLOOD, - }; - - for ( i = 0 ; i < ARRAYSIZE ( sHoundHints ) ; i++ ) - { - if ( sHoundHints[ i ] == sHint ) - { - return TRUE; - } - } - - ALERT ( at_aiconsole, "Couldn't validate hint type" ); - return FALSE; -} - - -//========================================================= -// FCanActiveIdle -//========================================================= -BOOL CHoundeye :: FCanActiveIdle ( void ) -{ - if ( InSquad() ) - { - CSquadMonster *pSquadLeader = MySquadLeader(); - - for (int i = 0; i < MAX_SQUAD_MEMBERS;i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - - if ( pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE ) - { - // someone else in the group is active idling right now! - return FALSE; - } - } - - return TRUE; - } - - return TRUE; -} - - -//========================================================= -// CheckRangeAttack1 - overridden for houndeyes so that they -// try to get within half of their max attack radius before -// attacking, so as to increase their chances of doing damage. -//========================================================= -BOOL CHoundeye :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDist <= ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 ) && flDot >= 0.3 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHoundeye :: SetYawSpeed ( void ) -{ - int ys; - - ys = 90; - - switch ( m_Activity ) - { - case ACT_CROUCHIDLE://sleeping! - ys = 0; - break; - case ACT_IDLE: - ys = 60; - break; - case ACT_WALK: - ys = 90; - break; - case ACT_RUN: - ys = 90; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// SetActivity -//========================================================= -void CHoundeye :: SetActivity ( Activity NewActivity ) -{ - int iSequence; - - if ( NewActivity == m_Activity ) - return; - - if ( m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG(0,1) ) - { - // play pissed idle. - iSequence = LookupSequence( "madidle" ); - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // In case someone calls this with something other than the ideal activity - m_IdealActivity = m_Activity; - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = iSequence; // Set to the reset anim (if it's there) - pev->frame = 0; // FIX: frame counter shouldn't be reset when its the same activity as before - ResetSequenceInfo(); - SetYawSpeed(); - } - } - else - { - CSquadMonster :: SetActivity ( NewActivity ); - } -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHoundeye :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch ( pEvent->event ) - { - case HOUND_AE_WARN: - // do stuff for this event. - WarnSound(); - break; - - case HOUND_AE_STARTATTACK: - WarmUpSound(); - break; - - case HOUND_AE_HOPBACK: - { - float flGravity = g_psv_gravity->value; - - pev->flags &= ~FL_ONGROUND; - - pev->velocity = gpGlobals->v_forward * -200; - pev->velocity.z += (0.6 * flGravity) * 0.5; - - break; - } - - case HOUND_AE_THUMP: - // emit the shockwaves - SonicAttack(); - break; - - case HOUND_AE_ANGERSOUND1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM); - break; - - case HOUND_AE_ANGERSOUND2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain1.wav", 1, ATTN_NORM); - break; - - case HOUND_AE_CLOSE_EYE: - if ( !m_fDontBlink ) - { - pev->skin = HOUNDEYE_EYE_FRAMES - 1; - } - break; - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHoundeye :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/houndeye.mdl"); - UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_YELLOW; - pev->effects = 0; - pev->health = gSkillData.houndeyeHealth; - pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_fAsleep = FALSE; // everyone spawns awake - m_fDontBlink = FALSE; - m_afCapability |= bits_CAP_SQUAD; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHoundeye :: Precache() -{ - PRECACHE_MODEL("models/houndeye.mdl"); - - PRECACHE_SOUND("houndeye/he_alert1.wav"); - PRECACHE_SOUND("houndeye/he_alert2.wav"); - PRECACHE_SOUND("houndeye/he_alert3.wav"); - - PRECACHE_SOUND("houndeye/he_die1.wav"); - PRECACHE_SOUND("houndeye/he_die2.wav"); - PRECACHE_SOUND("houndeye/he_die3.wav"); - - PRECACHE_SOUND("houndeye/he_idle1.wav"); - PRECACHE_SOUND("houndeye/he_idle2.wav"); - PRECACHE_SOUND("houndeye/he_idle3.wav"); - - PRECACHE_SOUND("houndeye/he_hunt1.wav"); - PRECACHE_SOUND("houndeye/he_hunt2.wav"); - PRECACHE_SOUND("houndeye/he_hunt3.wav"); - - PRECACHE_SOUND("houndeye/he_pain1.wav"); - PRECACHE_SOUND("houndeye/he_pain3.wav"); - PRECACHE_SOUND("houndeye/he_pain4.wav"); - PRECACHE_SOUND("houndeye/he_pain5.wav"); - - PRECACHE_SOUND("houndeye/he_attack1.wav"); - PRECACHE_SOUND("houndeye/he_attack3.wav"); - - PRECACHE_SOUND("houndeye/he_blast1.wav"); - PRECACHE_SOUND("houndeye/he_blast2.wav"); - PRECACHE_SOUND("houndeye/he_blast3.wav"); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" ); -} - -//========================================================= -// IdleSound -//========================================================= -void CHoundeye :: IdleSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// IdleSound -//========================================================= -void CHoundeye :: WarmUpSound ( void ) -{ - switch ( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack1.wav", 0.7, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack3.wav", 0.7, ATTN_NORM ); - break; - } -} - -//========================================================= -// WarnSound -//========================================================= -void CHoundeye :: WarnSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CHoundeye :: AlertSound ( void ) -{ - - if ( InSquad() && !IsLeader() ) - { - return; // only leader makes ALERT sound. - } - - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CHoundeye :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CHoundeye :: PainSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain5.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// WriteBeamColor - writes a color vector to the network -// based on the size of the group. -//========================================================= -void CHoundeye :: WriteBeamColor ( void ) -{ - BYTE bRed, bGreen, bBlue; - - if ( InSquad() ) - { - switch ( SquadCount() ) - { - case 2: - // no case for 0 or 1, cause those are impossible for monsters in Squads. - bRed = 101; - bGreen = 133; - bBlue = 221; - break; - case 3: - bRed = 67; - bGreen = 85; - bBlue = 255; - break; - case 4: - bRed = 62; - bGreen = 33; - bBlue = 211; - break; - default: - ALERT ( at_aiconsole, "Unsupported Houndeye SquadSize!\n" ); - bRed = 188; - bGreen = 220; - bBlue = 255; - break; - } - } - else - { - // solo houndeye - weakest beam - bRed = 188; - bGreen = 220; - bBlue = 255; - } - - WRITE_BYTE( bRed ); - WRITE_BYTE( bGreen ); - WRITE_BYTE( bBlue ); -} - - -//========================================================= -// SonicAttack -//========================================================= -void CHoundeye :: SonicAttack ( void ) -{ - float flAdjustedDamage; - float flDist; - - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast3.wav", 1, ATTN_NORM); break; - } - - // blast circles - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16 + HOUNDEYE_MAX_ATTACK_RADIUS / .2); // reach damage radius over .3 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - - WriteBeamColor(); - - WRITE_BYTE( 255 ); //brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16 + ( HOUNDEYE_MAX_ATTACK_RADIUS / 2 ) / .2); // reach damage radius over .3 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - - WriteBeamColor(); - - WRITE_BYTE( 255 ); //brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - - CBaseEntity *pEntity = NULL; - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS )) != NULL) - { - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - if ( !FClassnameIs(pEntity->pev, "monster_houndeye") ) - {// houndeyes don't hurt other houndeyes with their attack - - // houndeyes do FULL damage if the ent in question is visible. Half damage otherwise. - // This means that you must get out of the houndeye's attack range entirely to avoid damage. - // Calculate full damage first - - if ( SquadCount() > 1 ) - { - // squad gets attack bonus. - flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * ( HOUNDEYE_SQUAD_BONUS * ( SquadCount() - 1 ) ); - } - else - { - // solo - flAdjustedDamage = gSkillData.houndeyeDmgBlast; - } - - flDist = (pEntity->Center() - pev->origin).Length(); - - flAdjustedDamage -= ( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ) * flAdjustedDamage; - - if ( !FVisible( pEntity ) ) - { - if ( pEntity->IsPlayer() ) - { - // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still - // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients - // so that monsters in other parts of the level don't take the damage and get pissed. - flAdjustedDamage *= 0.5; - } - else if ( !FClassnameIs( pEntity->pev, "func_breakable" ) && !FClassnameIs( pEntity->pev, "func_pushable" ) ) - { - // do not hurt nonclients through walls, but allow damage to be done to breakables - flAdjustedDamage = 0; - } - } - - //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); - - if (flAdjustedDamage > 0 ) - { - pEntity->TakeDamage ( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); - } - } - } - } -} - -//========================================================= -// start task -//========================================================= -void CHoundeye :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_HOUND_FALL_ASLEEP: - { - m_fAsleep = TRUE; // signal that hound is lying down (must stand again before doing anything else!) - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_WAKE_UP: - { - m_fAsleep = FALSE; // signal that hound is standing again - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_OPEN_EYE: - { - m_fDontBlink = FALSE; // turn blinking back on and that code will automatically open the eye - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_CLOSE_EYE: - { - pev->skin = 0; - m_fDontBlink = TRUE; // tell blink code to leave the eye alone. - break; - } - case TASK_HOUND_THREAT_DISPLAY: - { - m_IdealActivity = ACT_IDLE_ANGRY; - break; - } - case TASK_HOUND_HOP_BACK: - { - m_IdealActivity = ACT_LEAP; - break; - } - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - -/* - if ( InSquad() ) - { - // see if there is a battery to connect to. - CSquadMonster *pSquad = m_pSquadLeader; - - while ( pSquad ) - { - if ( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY ) - { - // draw a beam. - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( ENTINDEX( this->edict() ) ); - WRITE_SHORT( ENTINDEX( pSquad->edict() ) ); - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 10 ); // noise - WRITE_BYTE( 0 ); // r, g, b - WRITE_BYTE( 50 ); // r, g, b - WRITE_BYTE( 250); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); - break; - } - - pSquad = pSquad->m_pSquadNext; - } - } -*/ - - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_GUARD: - { - m_IdealActivity = ACT_GUARD; - break; - } - default: - { - CSquadMonster :: StartTask(pTask); - break; - } - } -} - -//========================================================= -// RunTask -//========================================================= -void CHoundeye :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_HOUND_THREAT_DISPLAY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - - break; - } - case TASK_HOUND_CLOSE_EYE: - { - if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) - { - pev->skin++; - } - break; - } - case TASK_HOUND_HOP_BACK: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - case TASK_SPECIAL_ATTACK1: - { - pev->skin = RANDOM_LONG(0, HOUNDEYE_EYE_FRAMES - 1); - - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - float life; - life = ((255 - pev->frame) / (pev->framerate * m_flFrameRate)); - if (life < 0.1) life = 0.1; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_IMPLOSION); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16); - WRITE_BYTE( 50 * life + 100); // radius - WRITE_BYTE( pev->frame / 25.0 ); // count - WRITE_BYTE( life * 10 ); // life - MESSAGE_END(); - - if ( m_fSequenceFinished ) - { - SonicAttack(); - TaskComplete(); - } - - break; - } - default: - { - CSquadMonster :: RunTask(pTask); - break; - } - } -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHoundeye::PrescheduleThink ( void ) -{ - // if the hound is mad and is running, make hunt noises. - if ( m_MonsterState == MONSTERSTATE_COMBAT && m_Activity == ACT_RUN && RANDOM_FLOAT( 0, 1 ) < 0.2 ) - { - WarnSound(); - } - - // at random, initiate a blink if not already blinking or sleeping - if ( !m_fDontBlink ) - { - if ( ( pev->skin == 0 ) && RANDOM_LONG(0,0x7F) == 0 ) - {// start blinking! - pev->skin = HOUNDEYE_EYE_FRAMES - 1; - } - else if ( pev->skin != 0 ) - {// already blinking - pev->skin--; - } - } - - // if you are the leader, average the origins of each pack member to get an approximate center. - if ( IsLeader() ) - { - CSquadMonster *pSquadMember; - int iSquadCount = 0; - - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - pSquadMember = MySquadMember(i); - - if (pSquadMember) - { - iSquadCount++; - m_vecPackCenter = m_vecPackCenter + pSquadMember->pev->origin; - } - } - - m_vecPackCenter = m_vecPackCenter / iSquadCount; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlHoundGuardPack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_GUARD, (float)0 }, -}; - -Schedule_t slHoundGuardPack[] = -{ - { - tlHoundGuardPack, - ARRAYSIZE ( tlHoundGuardPack ), - bits_COND_SEE_HATE | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_MEAT | - bits_SOUND_PLAYER, - "GuardPack" - }, -}; - -// primary range attack -Task_t tlHoundYell1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_HOUND_AGITATED }, -}; - -Task_t tlHoundYell2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slHoundRangeAttack[] = -{ - { - tlHoundYell1, - ARRAYSIZE ( tlHoundYell1 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundRangeAttack1" - }, - { - tlHoundYell2, - ARRAYSIZE ( tlHoundYell2 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundRangeAttack2" - }, -}; - -// lie down and fall asleep -Task_t tlHoundSleep[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_RANDOM, (float)5 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_HOUND_FALL_ASLEEP, (float)0 }, - { TASK_WAIT_RANDOM, (float)25 }, - { TASK_HOUND_CLOSE_EYE, (float)0 }, - //{ TASK_WAIT, (float)10 }, - //{ TASK_WAIT_RANDOM, (float)10 }, -}; - -Schedule_t slHoundSleep[] = -{ - { - tlHoundSleep, - ARRAYSIZE ( tlHoundSleep ), - bits_COND_HEAR_SOUND | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY, - - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_WORLD, - "Hound Sleep" - }, -}; - -// wake and stand up lazily -Task_t tlHoundWakeLazy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_HOUND_OPEN_EYE, (float)0 }, - { TASK_WAIT_RANDOM, (float)2.5 }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, - { TASK_HOUND_WAKE_UP, (float)0 }, -}; - -Schedule_t slHoundWakeLazy[] = -{ - { - tlHoundWakeLazy, - ARRAYSIZE ( tlHoundWakeLazy ), - 0, - 0, - "WakeLazy" - }, -}; - -// wake and stand up with great urgency! -Task_t tlHoundWakeUrgent[] = -{ - { TASK_HOUND_OPEN_EYE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_HOUND_WAKE_UP, (float)0 }, -}; - -Schedule_t slHoundWakeUrgent[] = -{ - { - tlHoundWakeUrgent, - ARRAYSIZE ( tlHoundWakeUrgent ), - 0, - 0, - "WakeUrgent" - }, -}; - - -Task_t tlHoundSpecialAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SPECIAL_ATTACK1, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_IDLE_ANGRY }, -}; - -Schedule_t slHoundSpecialAttack1[] = -{ - { - tlHoundSpecialAttack1, - ARRAYSIZE ( tlHoundSpecialAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - - 0, - "Hound Special Attack1" - }, -}; - -Task_t tlHoundAgitated[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, -}; - -Schedule_t slHoundAgitated[] = -{ - { - tlHoundAgitated, - ARRAYSIZE ( tlHoundAgitated ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Hound Agitated" - }, -}; - -Task_t tlHoundHopRetreat[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_HOP_BACK, 0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slHoundHopRetreat[] = -{ - { - tlHoundHopRetreat, - ARRAYSIZE ( tlHoundHopRetreat ), - 0, - 0, - "Hound Hop Retreat" - }, -}; - -// hound fails in combat with client in the PVS -Task_t tlHoundCombatFailPVS[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slHoundCombatFailPVS[] = -{ - { - tlHoundCombatFailPVS, - ARRAYSIZE ( tlHoundCombatFailPVS ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundCombatFailPVS" - }, -}; - -// hound fails in combat with no client in the PVS. Don't keep peeping! -Task_t tlHoundCombatFailNoPVS[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_PVS, 0 }, -}; - -Schedule_t slHoundCombatFailNoPVS[] = -{ - { - tlHoundCombatFailNoPVS, - ARRAYSIZE ( tlHoundCombatFailNoPVS ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundCombatFailNoPVS" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CHoundeye ) -{ - slHoundGuardPack, - slHoundRangeAttack, - &slHoundRangeAttack[ 1 ], - slHoundSleep, - slHoundWakeLazy, - slHoundWakeUrgent, - slHoundSpecialAttack1, - slHoundAgitated, - slHoundHopRetreat, - slHoundCombatFailPVS, - slHoundCombatFailNoPVS, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ); - -//========================================================= -// GetScheduleOfType -//========================================================= -Schedule_t* CHoundeye :: GetScheduleOfType ( int Type ) -{ - if ( m_fAsleep ) - { - // if the hound is sleeping, must wake and stand! - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pWakeSound; - - pWakeSound = PBestSound(); - ASSERT( pWakeSound != NULL ); - if ( pWakeSound ) - { - MakeIdealYaw ( pWakeSound->m_vecOrigin ); - - if ( FLSoundVolume ( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME ) - { - // awakened by a loud sound - return &slHoundWakeUrgent[ 0 ]; - } - } - // sound was not loud enough to scare the bejesus out of houndeye - return &slHoundWakeLazy[ 0 ]; - } - else if ( HasConditions( bits_COND_NEW_ENEMY ) ) - { - // get up fast, to fight. - return &slHoundWakeUrgent[ 0 ]; - } - - else - { - // hound is waking up on its own - return &slHoundWakeLazy[ 0 ]; - } - } - switch ( Type ) - { - case SCHED_IDLE_STAND: - { - // we may want to sleep instead of stand! - if ( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG(0,29) < 1 ) - { - return &slHoundSleep[ 0 ]; - } - else - { - return CSquadMonster :: GetScheduleOfType( Type ); - } - } - case SCHED_RANGE_ATTACK1: - { - return &slHoundRangeAttack[ 0 ]; -/* - if ( InSquad() ) - { - return &slHoundRangeAttack[ RANDOM_LONG( 0, 1 ) ]; - } - - return &slHoundRangeAttack[ 1 ]; -*/ - } - case SCHED_SPECIAL_ATTACK1: - { - return &slHoundSpecialAttack1[ 0 ]; - } - case SCHED_GUARD: - { - return &slHoundGuardPack[ 0 ]; - } - case SCHED_HOUND_AGITATED: - { - return &slHoundAgitated[ 0 ]; - } - case SCHED_HOUND_HOP_RETREAT: - { - return &slHoundHopRetreat[ 0 ]; - } - case SCHED_FAIL: - { - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - // client in PVS - return &slHoundCombatFailPVS[ 0 ]; - } - else - { - // client has taken off! - return &slHoundCombatFailNoPVS[ 0 ]; - } - } - else - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } - default: - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } -} - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t *CHoundeye :: GetSchedule( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - if ( RANDOM_FLOAT( 0 , 1 ) <= 0.4 ) - { - TraceResult tr; - UTIL_MakeVectors( pev->angles ); - UTIL_TraceHull( pev->origin, pev->origin + gpGlobals->v_forward * -128, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); - - if ( tr.flFraction == 1.0 ) - { - // it's clear behind, so the hound will jump - return GetScheduleOfType ( SCHED_HOUND_HOP_RETREAT ); - } - } - - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if ( OccupySlot ( bits_SLOTS_HOUND_ATTACK ) ) - { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType ( SCHED_HOUND_AGITATED ); - } - break; - } - } - - return CSquadMonster :: GetSchedule(); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Houndeye - spooky sonic dog. +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "animation.h" +#include "nodes.h" +#include "squadmonster.h" +#include "soundent.h" +#include "game.h" + +extern CGraph WorldGraph; + +// houndeye does 20 points of damage spread over a sphere 384 units in diameter, and each additional +// squad member increases the BASE damage by 110%, per the spec. +#define HOUNDEYE_MAX_SQUAD_SIZE 4 +#define HOUNDEYE_MAX_ATTACK_RADIUS 384 +#define HOUNDEYE_SQUAD_BONUS (float)1.1 + +#define HOUNDEYE_EYE_FRAMES 4 // how many different switchable maps for the eye + +#define HOUNDEYE_SOUND_STARTLE_VOLUME 128 // how loud a sound has to be to badly scare a sleeping houndeye + +//========================================================= +// monster-specific tasks +//========================================================= +enum +{ + TASK_HOUND_CLOSE_EYE = LAST_COMMON_TASK + 1, + TASK_HOUND_OPEN_EYE, + TASK_HOUND_THREAT_DISPLAY, + TASK_HOUND_FALL_ASLEEP, + TASK_HOUND_WAKE_UP, + TASK_HOUND_HOP_BACK +}; + +//========================================================= +// monster-specific schedule types +//========================================================= +enum +{ + SCHED_HOUND_AGITATED = LAST_COMMON_SCHEDULE + 1, + SCHED_HOUND_HOP_RETREAT, + SCHED_HOUND_FAIL, +}; + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define HOUND_AE_WARN 1 +#define HOUND_AE_STARTATTACK 2 +#define HOUND_AE_THUMP 3 +#define HOUND_AE_ANGERSOUND1 4 +#define HOUND_AE_ANGERSOUND2 5 +#define HOUND_AE_HOPBACK 6 +#define HOUND_AE_CLOSE_EYE 7 + +class CHoundeye : public CSquadMonster +{ +public: + void Spawn( void ); + void Precache( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void SetYawSpeed ( void ); + void WarmUpSound ( void ); + void AlertSound( void ); + void DeathSound( void ); + void WarnSound( void ); + void PainSound( void ); + void IdleSound( void ); + void StartTask( Task_t *pTask ); + void RunTask ( Task_t *pTask ); + void SonicAttack( void ); + void PrescheduleThink( void ); + void SetActivity ( Activity NewActivity ); + void WriteBeamColor ( void ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + BOOL FValidateHintType ( short sHint ); + BOOL FCanActiveIdle ( void ); + Schedule_t *GetScheduleOfType ( int Type ); + Schedule_t *CHoundeye :: GetSchedule( void ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + + CUSTOM_SCHEDULES; + static TYPEDESCRIPTION m_SaveData[]; + + int m_iSpriteTexture; + BOOL m_fAsleep;// some houndeyes sleep in idle mode if this is set, the houndeye is lying down + BOOL m_fDontBlink;// don't try to open/close eye if this bit is set! + Vector m_vecPackCenter; // the center of the pack. The leader maintains this by averaging the origins of all pack members. +}; +LINK_ENTITY_TO_CLASS( monster_houndeye, CHoundeye ); + +TYPEDESCRIPTION CHoundeye::m_SaveData[] = +{ + DEFINE_FIELD( CHoundeye, m_iSpriteTexture, FIELD_INTEGER ), + DEFINE_FIELD( CHoundeye, m_fAsleep, FIELD_BOOLEAN ), + DEFINE_FIELD( CHoundeye, m_fDontBlink, FIELD_BOOLEAN ), + DEFINE_FIELD( CHoundeye, m_vecPackCenter, FIELD_POSITION_VECTOR ), +}; + +IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CHoundeye :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// FValidateHintType +//========================================================= +BOOL CHoundeye :: FValidateHintType ( short sHint ) +{ + int i; + + static short sHoundHints[] = + { + HINT_WORLD_MACHINERY, + HINT_WORLD_BLINKING_LIGHT, + HINT_WORLD_HUMAN_BLOOD, + HINT_WORLD_ALIEN_BLOOD, + }; + + for ( i = 0 ; i < ARRAYSIZE ( sHoundHints ) ; i++ ) + { + if ( sHoundHints[ i ] == sHint ) + { + return TRUE; + } + } + + ALERT ( at_aiconsole, "Couldn't validate hint type" ); + return FALSE; +} + + +//========================================================= +// FCanActiveIdle +//========================================================= +BOOL CHoundeye :: FCanActiveIdle ( void ) +{ + if ( InSquad() ) + { + CSquadMonster *pSquadLeader = MySquadLeader(); + + for (int i = 0; i < MAX_SQUAD_MEMBERS;i++) + { + CSquadMonster *pMember = pSquadLeader->MySquadMember(i); + + if ( pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE ) + { + // someone else in the group is active idling right now! + return FALSE; + } + } + + return TRUE; + } + + return TRUE; +} + + +//========================================================= +// CheckRangeAttack1 - overridden for houndeyes so that they +// try to get within half of their max attack radius before +// attacking, so as to increase their chances of doing damage. +//========================================================= +BOOL CHoundeye :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( flDist <= ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 ) && flDot >= 0.3 ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CHoundeye :: SetYawSpeed ( void ) +{ + int ys; + + ys = 90; + + switch ( m_Activity ) + { + case ACT_CROUCHIDLE://sleeping! + ys = 0; + break; + case ACT_IDLE: + ys = 60; + break; + case ACT_WALK: + ys = 90; + break; + case ACT_RUN: + ys = 90; + break; + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 90; + break; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// SetActivity +//========================================================= +void CHoundeye :: SetActivity ( Activity NewActivity ) +{ + int iSequence; + + if ( NewActivity == m_Activity ) + return; + + if ( m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG(0,1) ) + { + // play pissed idle. + iSequence = LookupSequence( "madidle" ); + + m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present + + // In case someone calls this with something other than the ideal activity + m_IdealActivity = m_Activity; + + // Set to the desired anim, or default anim if the desired is not present + if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + { + pev->sequence = iSequence; // Set to the reset anim (if it's there) + pev->frame = 0; // FIX: frame counter shouldn't be reset when its the same activity as before + ResetSequenceInfo(); + SetYawSpeed(); + } + } + else + { + CSquadMonster :: SetActivity ( NewActivity ); + } +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CHoundeye :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch ( pEvent->event ) + { + case HOUND_AE_WARN: + // do stuff for this event. + WarnSound(); + break; + + case HOUND_AE_STARTATTACK: + WarmUpSound(); + break; + + case HOUND_AE_HOPBACK: + { + float flGravity = g_psv_gravity->value; + + pev->flags &= ~FL_ONGROUND; + + pev->velocity = gpGlobals->v_forward * -200; + pev->velocity.z += (0.6 * flGravity) * 0.5; + + break; + } + + case HOUND_AE_THUMP: + // emit the shockwaves + SonicAttack(); + break; + + case HOUND_AE_ANGERSOUND1: + EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM); + break; + + case HOUND_AE_ANGERSOUND2: + EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain1.wav", 1, ATTN_NORM); + break; + + case HOUND_AE_CLOSE_EYE: + if ( !m_fDontBlink ) + { + pev->skin = HOUNDEYE_EYE_FRAMES - 1; + } + break; + + default: + CSquadMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CHoundeye :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/houndeye.mdl"); + UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_YELLOW; + pev->effects = 0; + pev->health = gSkillData.houndeyeHealth; + pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_fAsleep = FALSE; // everyone spawns awake + m_fDontBlink = FALSE; + m_afCapability |= bits_CAP_SQUAD; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CHoundeye :: Precache() +{ + PRECACHE_MODEL("models/houndeye.mdl"); + + PRECACHE_SOUND("houndeye/he_alert1.wav"); + PRECACHE_SOUND("houndeye/he_alert2.wav"); + PRECACHE_SOUND("houndeye/he_alert3.wav"); + + PRECACHE_SOUND("houndeye/he_die1.wav"); + PRECACHE_SOUND("houndeye/he_die2.wav"); + PRECACHE_SOUND("houndeye/he_die3.wav"); + + PRECACHE_SOUND("houndeye/he_idle1.wav"); + PRECACHE_SOUND("houndeye/he_idle2.wav"); + PRECACHE_SOUND("houndeye/he_idle3.wav"); + + PRECACHE_SOUND("houndeye/he_hunt1.wav"); + PRECACHE_SOUND("houndeye/he_hunt2.wav"); + PRECACHE_SOUND("houndeye/he_hunt3.wav"); + + PRECACHE_SOUND("houndeye/he_pain1.wav"); + PRECACHE_SOUND("houndeye/he_pain3.wav"); + PRECACHE_SOUND("houndeye/he_pain4.wav"); + PRECACHE_SOUND("houndeye/he_pain5.wav"); + + PRECACHE_SOUND("houndeye/he_attack1.wav"); + PRECACHE_SOUND("houndeye/he_attack3.wav"); + + PRECACHE_SOUND("houndeye/he_blast1.wav"); + PRECACHE_SOUND("houndeye/he_blast2.wav"); + PRECACHE_SOUND("houndeye/he_blast3.wav"); + + m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" ); +} + +//========================================================= +// IdleSound +//========================================================= +void CHoundeye :: IdleSound ( void ) +{ + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle1.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle2.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle3.wav", 1, ATTN_NORM ); + break; + } +} + +//========================================================= +// IdleSound +//========================================================= +void CHoundeye :: WarmUpSound ( void ) +{ + switch ( RANDOM_LONG(0,1) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack1.wav", 0.7, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack3.wav", 0.7, ATTN_NORM ); + break; + } +} + +//========================================================= +// WarnSound +//========================================================= +void CHoundeye :: WarnSound ( void ) +{ + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt1.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt2.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt3.wav", 1, ATTN_NORM ); + break; + } +} + +//========================================================= +// AlertSound +//========================================================= +void CHoundeye :: AlertSound ( void ) +{ + + if ( InSquad() && !IsLeader() ) + { + return; // only leader makes ALERT sound. + } + + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert2.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM ); + break; + } +} + +//========================================================= +// DeathSound +//========================================================= +void CHoundeye :: DeathSound ( void ) +{ + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die1.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die2.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die3.wav", 1, ATTN_NORM ); + break; + } +} + +//========================================================= +// PainSound +//========================================================= +void CHoundeye :: PainSound ( void ) +{ + switch ( RANDOM_LONG(0,2) ) + { + case 0: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM ); + break; + case 1: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain4.wav", 1, ATTN_NORM ); + break; + case 2: + EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain5.wav", 1, ATTN_NORM ); + break; + } +} + +//========================================================= +// WriteBeamColor - writes a color vector to the network +// based on the size of the group. +//========================================================= +void CHoundeye :: WriteBeamColor ( void ) +{ + BYTE bRed, bGreen, bBlue; + + if ( InSquad() ) + { + switch ( SquadCount() ) + { + case 2: + // no case for 0 or 1, cause those are impossible for monsters in Squads. + bRed = 101; + bGreen = 133; + bBlue = 221; + break; + case 3: + bRed = 67; + bGreen = 85; + bBlue = 255; + break; + case 4: + bRed = 62; + bGreen = 33; + bBlue = 211; + break; + default: + ALERT ( at_aiconsole, "Unsupported Houndeye SquadSize!\n" ); + bRed = 188; + bGreen = 220; + bBlue = 255; + break; + } + } + else + { + // solo houndeye - weakest beam + bRed = 188; + bGreen = 220; + bBlue = 255; + } + + WRITE_BYTE( bRed ); + WRITE_BYTE( bGreen ); + WRITE_BYTE( bBlue ); +} + + +//========================================================= +// SonicAttack +//========================================================= +void CHoundeye :: SonicAttack ( void ) +{ + float flAdjustedDamage; + float flDist; + + switch ( RANDOM_LONG( 0, 2 ) ) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast1.wav", 1, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast2.wav", 1, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast3.wav", 1, ATTN_NORM); break; + } + + // blast circles + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_BEAMCYLINDER ); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 16); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 16 + HOUNDEYE_MAX_ATTACK_RADIUS / .2); // reach damage radius over .3 seconds + WRITE_SHORT( m_iSpriteTexture ); + WRITE_BYTE( 0 ); // startframe + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 2 ); // life + WRITE_BYTE( 16 ); // width + WRITE_BYTE( 0 ); // noise + + WriteBeamColor(); + + WRITE_BYTE( 255 ); //brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_BEAMCYLINDER ); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 16); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 16 + ( HOUNDEYE_MAX_ATTACK_RADIUS / 2 ) / .2); // reach damage radius over .3 seconds + WRITE_SHORT( m_iSpriteTexture ); + WRITE_BYTE( 0 ); // startframe + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 2 ); // life + WRITE_BYTE( 16 ); // width + WRITE_BYTE( 0 ); // noise + + WriteBeamColor(); + + WRITE_BYTE( 255 ); //brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); + + + CBaseEntity *pEntity = NULL; + // iterate on all entities in the vicinity. + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS )) != NULL) + { + if ( pEntity->pev->takedamage != DAMAGE_NO ) + { + if ( !FClassnameIs(pEntity->pev, "monster_houndeye") ) + {// houndeyes don't hurt other houndeyes with their attack + + // houndeyes do FULL damage if the ent in question is visible. Half damage otherwise. + // This means that you must get out of the houndeye's attack range entirely to avoid damage. + // Calculate full damage first + + if ( SquadCount() > 1 ) + { + // squad gets attack bonus. + flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * ( HOUNDEYE_SQUAD_BONUS * ( SquadCount() - 1 ) ); + } + else + { + // solo + flAdjustedDamage = gSkillData.houndeyeDmgBlast; + } + + flDist = (pEntity->Center() - pev->origin).Length(); + + flAdjustedDamage -= ( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ) * flAdjustedDamage; + + if ( !FVisible( pEntity ) ) + { + if ( pEntity->IsPlayer() ) + { + // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still + // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients + // so that monsters in other parts of the level don't take the damage and get pissed. + flAdjustedDamage *= 0.5; + } + else if ( !FClassnameIs( pEntity->pev, "func_breakable" ) && !FClassnameIs( pEntity->pev, "func_pushable" ) ) + { + // do not hurt nonclients through walls, but allow damage to be done to breakables + flAdjustedDamage = 0; + } + } + + //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); + + if (flAdjustedDamage > 0 ) + { + pEntity->TakeDamage ( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); + } + } + } + } +} + +//========================================================= +// start task +//========================================================= +void CHoundeye :: StartTask ( Task_t *pTask ) +{ + m_iTaskStatus = TASKSTATUS_RUNNING; + + switch ( pTask->iTask ) + { + case TASK_HOUND_FALL_ASLEEP: + { + m_fAsleep = TRUE; // signal that hound is lying down (must stand again before doing anything else!) + m_iTaskStatus = TASKSTATUS_COMPLETE; + break; + } + case TASK_HOUND_WAKE_UP: + { + m_fAsleep = FALSE; // signal that hound is standing again + m_iTaskStatus = TASKSTATUS_COMPLETE; + break; + } + case TASK_HOUND_OPEN_EYE: + { + m_fDontBlink = FALSE; // turn blinking back on and that code will automatically open the eye + m_iTaskStatus = TASKSTATUS_COMPLETE; + break; + } + case TASK_HOUND_CLOSE_EYE: + { + pev->skin = 0; + m_fDontBlink = TRUE; // tell blink code to leave the eye alone. + break; + } + case TASK_HOUND_THREAT_DISPLAY: + { + m_IdealActivity = ACT_IDLE_ANGRY; + break; + } + case TASK_HOUND_HOP_BACK: + { + m_IdealActivity = ACT_LEAP; + break; + } + case TASK_RANGE_ATTACK1: + { + m_IdealActivity = ACT_RANGE_ATTACK1; + +/* + if ( InSquad() ) + { + // see if there is a battery to connect to. + CSquadMonster *pSquad = m_pSquadLeader; + + while ( pSquad ) + { + if ( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY ) + { + // draw a beam. + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTS ); + WRITE_SHORT( ENTINDEX( this->edict() ) ); + WRITE_SHORT( ENTINDEX( pSquad->edict() ) ); + WRITE_SHORT( m_iSpriteTexture ); + WRITE_BYTE( 0 ); // framestart + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 10 ); // life + WRITE_BYTE( 40 ); // width + WRITE_BYTE( 10 ); // noise + WRITE_BYTE( 0 ); // r, g, b + WRITE_BYTE( 50 ); // r, g, b + WRITE_BYTE( 250); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 30 ); // speed + MESSAGE_END(); + break; + } + + pSquad = pSquad->m_pSquadNext; + } + } +*/ + + break; + } + case TASK_SPECIAL_ATTACK1: + { + m_IdealActivity = ACT_SPECIAL_ATTACK1; + break; + } + case TASK_GUARD: + { + m_IdealActivity = ACT_GUARD; + break; + } + default: + { + CSquadMonster :: StartTask(pTask); + break; + } + } +} + +//========================================================= +// RunTask +//========================================================= +void CHoundeye :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_HOUND_THREAT_DISPLAY: + { + MakeIdealYaw ( m_vecEnemyLKP ); + ChangeYaw ( pev->yaw_speed ); + + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + + break; + } + case TASK_HOUND_CLOSE_EYE: + { + if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) + { + pev->skin++; + } + break; + } + case TASK_HOUND_HOP_BACK: + { + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + break; + } + case TASK_SPECIAL_ATTACK1: + { + pev->skin = RANDOM_LONG(0, HOUNDEYE_EYE_FRAMES - 1); + + MakeIdealYaw ( m_vecEnemyLKP ); + ChangeYaw ( pev->yaw_speed ); + + float life; + life = ((255 - pev->frame) / (pev->framerate * m_flFrameRate)); + if (life < 0.1) life = 0.1; + + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_IMPLOSION); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 16); + WRITE_BYTE( 50 * life + 100); // radius + WRITE_BYTE( pev->frame / 25.0 ); // count + WRITE_BYTE( life * 10 ); // life + MESSAGE_END(); + + if ( m_fSequenceFinished ) + { + SonicAttack(); + TaskComplete(); + } + + break; + } + default: + { + CSquadMonster :: RunTask(pTask); + break; + } + } +} + +//========================================================= +// PrescheduleThink +//========================================================= +void CHoundeye::PrescheduleThink ( void ) +{ + // if the hound is mad and is running, make hunt noises. + if ( m_MonsterState == MONSTERSTATE_COMBAT && m_Activity == ACT_RUN && RANDOM_FLOAT( 0, 1 ) < 0.2 ) + { + WarnSound(); + } + + // at random, initiate a blink if not already blinking or sleeping + if ( !m_fDontBlink ) + { + if ( ( pev->skin == 0 ) && RANDOM_LONG(0,0x7F) == 0 ) + {// start blinking! + pev->skin = HOUNDEYE_EYE_FRAMES - 1; + } + else if ( pev->skin != 0 ) + {// already blinking + pev->skin--; + } + } + + // if you are the leader, average the origins of each pack member to get an approximate center. + if ( IsLeader() ) + { + CSquadMonster *pSquadMember; + int iSquadCount = 0; + + for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + { + pSquadMember = MySquadMember(i); + + if (pSquadMember) + { + iSquadCount++; + m_vecPackCenter = m_vecPackCenter + pSquadMember->pev->origin; + } + } + + m_vecPackCenter = m_vecPackCenter / iSquadCount; + } +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= +Task_t tlHoundGuardPack[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_GUARD, (float)0 }, +}; + +Schedule_t slHoundGuardPack[] = +{ + { + tlHoundGuardPack, + ARRAYSIZE ( tlHoundGuardPack ), + bits_COND_SEE_HATE | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_PROVOKED | + bits_COND_HEAR_SOUND, + + bits_SOUND_COMBAT |// sound flags + bits_SOUND_WORLD | + bits_SOUND_MEAT | + bits_SOUND_PLAYER, + "GuardPack" + }, +}; + +// primary range attack +Task_t tlHoundYell1[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_HOUND_AGITATED }, +}; + +Task_t tlHoundYell2[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slHoundRangeAttack[] = +{ + { + tlHoundYell1, + ARRAYSIZE ( tlHoundYell1 ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "HoundRangeAttack1" + }, + { + tlHoundYell2, + ARRAYSIZE ( tlHoundYell2 ), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "HoundRangeAttack2" + }, +}; + +// lie down and fall asleep +Task_t tlHoundSleep[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_RANDOM, (float)5 }, + { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, + { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, + { TASK_HOUND_FALL_ASLEEP, (float)0 }, + { TASK_WAIT_RANDOM, (float)25 }, + { TASK_HOUND_CLOSE_EYE, (float)0 }, + //{ TASK_WAIT, (float)10 }, + //{ TASK_WAIT_RANDOM, (float)10 }, +}; + +Schedule_t slHoundSleep[] = +{ + { + tlHoundSleep, + ARRAYSIZE ( tlHoundSleep ), + bits_COND_HEAR_SOUND | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_NEW_ENEMY, + + bits_SOUND_COMBAT | + bits_SOUND_PLAYER | + bits_SOUND_WORLD, + "Hound Sleep" + }, +}; + +// wake and stand up lazily +Task_t tlHoundWakeLazy[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_HOUND_OPEN_EYE, (float)0 }, + { TASK_WAIT_RANDOM, (float)2.5 }, + { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, + { TASK_HOUND_WAKE_UP, (float)0 }, +}; + +Schedule_t slHoundWakeLazy[] = +{ + { + tlHoundWakeLazy, + ARRAYSIZE ( tlHoundWakeLazy ), + 0, + 0, + "WakeLazy" + }, +}; + +// wake and stand up with great urgency! +Task_t tlHoundWakeUrgent[] = +{ + { TASK_HOUND_OPEN_EYE, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_HOUND_WAKE_UP, (float)0 }, +}; + +Schedule_t slHoundWakeUrgent[] = +{ + { + tlHoundWakeUrgent, + ARRAYSIZE ( tlHoundWakeUrgent ), + 0, + 0, + "WakeUrgent" + }, +}; + + +Task_t tlHoundSpecialAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_SPECIAL_ATTACK1, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_IDLE_ANGRY }, +}; + +Schedule_t slHoundSpecialAttack1[] = +{ + { + tlHoundSpecialAttack1, + ARRAYSIZE ( tlHoundSpecialAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED, + + 0, + "Hound Special Attack1" + }, +}; + +Task_t tlHoundAgitated[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_HOUND_THREAT_DISPLAY, 0 }, +}; + +Schedule_t slHoundAgitated[] = +{ + { + tlHoundAgitated, + ARRAYSIZE ( tlHoundAgitated ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "Hound Agitated" + }, +}; + +Task_t tlHoundHopRetreat[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_HOUND_HOP_BACK, 0 }, + { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, +}; + +Schedule_t slHoundHopRetreat[] = +{ + { + tlHoundHopRetreat, + ARRAYSIZE ( tlHoundHopRetreat ), + 0, + 0, + "Hound Hop Retreat" + }, +}; + +// hound fails in combat with client in the PVS +Task_t tlHoundCombatFailPVS[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_HOUND_THREAT_DISPLAY, 0 }, + { TASK_WAIT_FACE_ENEMY, (float)1 }, +}; + +Schedule_t slHoundCombatFailPVS[] = +{ + { + tlHoundCombatFailPVS, + ARRAYSIZE ( tlHoundCombatFailPVS ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "HoundCombatFailPVS" + }, +}; + +// hound fails in combat with no client in the PVS. Don't keep peeping! +Task_t tlHoundCombatFailNoPVS[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_HOUND_THREAT_DISPLAY, 0 }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_PVS, 0 }, +}; + +Schedule_t slHoundCombatFailNoPVS[] = +{ + { + tlHoundCombatFailNoPVS, + ARRAYSIZE ( tlHoundCombatFailNoPVS ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "HoundCombatFailNoPVS" + }, +}; + +DEFINE_CUSTOM_SCHEDULES( CHoundeye ) +{ + slHoundGuardPack, + slHoundRangeAttack, + &slHoundRangeAttack[ 1 ], + slHoundSleep, + slHoundWakeLazy, + slHoundWakeUrgent, + slHoundSpecialAttack1, + slHoundAgitated, + slHoundHopRetreat, + slHoundCombatFailPVS, + slHoundCombatFailNoPVS, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ); + +//========================================================= +// GetScheduleOfType +//========================================================= +Schedule_t* CHoundeye :: GetScheduleOfType ( int Type ) +{ + if ( m_fAsleep ) + { + // if the hound is sleeping, must wake and stand! + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + { + CSound *pWakeSound; + + pWakeSound = PBestSound(); + ASSERT( pWakeSound != NULL ); + if ( pWakeSound ) + { + MakeIdealYaw ( pWakeSound->m_vecOrigin ); + + if ( FLSoundVolume ( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME ) + { + // awakened by a loud sound + return &slHoundWakeUrgent[ 0 ]; + } + } + // sound was not loud enough to scare the bejesus out of houndeye + return &slHoundWakeLazy[ 0 ]; + } + else if ( HasConditions( bits_COND_NEW_ENEMY ) ) + { + // get up fast, to fight. + return &slHoundWakeUrgent[ 0 ]; + } + + else + { + // hound is waking up on its own + return &slHoundWakeLazy[ 0 ]; + } + } + switch ( Type ) + { + case SCHED_IDLE_STAND: + { + // we may want to sleep instead of stand! + if ( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG(0,29) < 1 ) + { + return &slHoundSleep[ 0 ]; + } + else + { + return CSquadMonster :: GetScheduleOfType( Type ); + } + } + case SCHED_RANGE_ATTACK1: + { + return &slHoundRangeAttack[ 0 ]; +/* + if ( InSquad() ) + { + return &slHoundRangeAttack[ RANDOM_LONG( 0, 1 ) ]; + } + + return &slHoundRangeAttack[ 1 ]; +*/ + } + case SCHED_SPECIAL_ATTACK1: + { + return &slHoundSpecialAttack1[ 0 ]; + } + case SCHED_GUARD: + { + return &slHoundGuardPack[ 0 ]; + } + case SCHED_HOUND_AGITATED: + { + return &slHoundAgitated[ 0 ]; + } + case SCHED_HOUND_HOP_RETREAT: + { + return &slHoundHopRetreat[ 0 ]; + } + case SCHED_FAIL: + { + if ( m_MonsterState == MONSTERSTATE_COMBAT ) + { + if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + { + // client in PVS + return &slHoundCombatFailPVS[ 0 ]; + } + else + { + // client has taken off! + return &slHoundCombatFailNoPVS[ 0 ]; + } + } + else + { + return CSquadMonster :: GetScheduleOfType ( Type ); + } + } + default: + { + return CSquadMonster :: GetScheduleOfType ( Type ); + } + } +} + +//========================================================= +// GetSchedule +//========================================================= +Schedule_t *CHoundeye :: GetSchedule( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + { +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + { + if ( RANDOM_FLOAT( 0 , 1 ) <= 0.4 ) + { + TraceResult tr; + UTIL_MakeVectors( pev->angles ); + UTIL_TraceHull( pev->origin, pev->origin + gpGlobals->v_forward * -128, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); + + if ( tr.flFraction == 1.0 ) + { + // it's clear behind, so the hound will jump + return GetScheduleOfType ( SCHED_HOUND_HOP_RETREAT ); + } + } + + return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + } + + if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + if ( OccupySlot ( bits_SLOTS_HOUND_ATTACK ) ) + { + return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + } + + return GetScheduleOfType ( SCHED_HOUND_AGITATED ); + } + break; + } + } + + return CSquadMonster :: GetSchedule(); +} diff --git a/main/source/dlls/ichthyosaur.cpp b/main/source/dlls/ichthyosaur.cpp index e793c7f6..2a46e3f3 100644 --- a/main/source/dlls/ichthyosaur.cpp +++ b/main/source/dlls/ichthyosaur.cpp @@ -1,1108 +1,1108 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// icthyosaur - evin, satan fish monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "flyingmonster.h" -#include "nodes.h" -#include "soundent.h" -#include "animation.h" -#include "effects.h" -#include "weapons.h" - -#define SEARCH_RETRY 16 - -#define ICHTHYOSAUR_SPEED 150 - -extern CGraph WorldGraph; - -#define EYE_MAD 0 -#define EYE_BASE 1 -#define EYE_CLOSED 2 -#define EYE_BACK 3 -#define EYE_LOOK 4 - - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -// UNDONE: Save/restore here -class CIchthyosaur : public CFlyingMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - CUSTOM_SCHEDULES; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - - void Killed( entvars_t *pevAttacker, int iGib ); - void BecomeDead( void ); - - void EXPORT CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT BiteTouch( CBaseEntity *pOther ); - - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - - float ChangeYaw( int speed ); - Activity GetStoppedActivity( void ); - - void Move( float flInterval ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void MonsterThink( void ); - void Stop( void ); - void Swim( void ); - Vector DoProbe(const Vector &Probe); - - float VectorToPitch( const Vector &vec); - float FlPitchDiff( void ); - float ChangePitch( int speed ); - - Vector m_SaveVelocity; - float m_idealDist; - - float m_flBlink; - - float m_flEnemyTouched; - BOOL m_bOnAttack; - - float m_flMaxSpeed; - float m_flMinSpeed; - float m_flMaxDist; - - CBeam *m_pBeam; - - float m_flNextAlert; - - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pAttackSounds[]; - static const char *pBiteSounds[]; - static const char *pDieSounds[]; - static const char *pPainSounds[]; - - void IdleSound( void ); - void AlertSound( void ); - void AttackSound( void ); - void BiteSound( void ); - void DeathSound( void ); - void PainSound( void ); -}; - -LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur ); - -TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = -{ - DEFINE_FIELD( CIchthyosaur, m_SaveVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CIchthyosaur, m_idealDist, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flBlink, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flEnemyTouched, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_bOnAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CIchthyosaur, m_flMaxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flMinSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flMaxDist, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flNextAlert, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CIchthyosaur, CFlyingMonster ); - - -const char *CIchthyosaur::pIdleSounds[] = -{ - "ichy/ichy_idle1.wav", - "ichy/ichy_idle2.wav", - "ichy/ichy_idle3.wav", - "ichy/ichy_idle4.wav", -}; - -const char *CIchthyosaur::pAlertSounds[] = -{ - "ichy/ichy_alert2.wav", - "ichy/ichy_alert3.wav", -}; - -const char *CIchthyosaur::pAttackSounds[] = -{ - "ichy/ichy_attack1.wav", - "ichy/ichy_attack2.wav", -}; - -const char *CIchthyosaur::pBiteSounds[] = -{ - "ichy/ichy_bite1.wav", - "ichy/ichy_bite2.wav", -}; - -const char *CIchthyosaur::pPainSounds[] = -{ - "ichy/ichy_pain2.wav", - "ichy/ichy_pain3.wav", - "ichy/ichy_pain5.wav", -}; - -const char *CIchthyosaur::pDieSounds[] = -{ - "ichy/ichy_die2.wav", - "ichy/ichy_die4.wav", -}; - -#define EMIT_ICKY_SOUND( chan, array ) \ - EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, 0.6, 0, RANDOM_LONG(95,105) ); - - -void CIchthyosaur :: IdleSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pIdleSounds ); -} - -void CIchthyosaur :: AlertSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pAlertSounds ); -} - -void CIchthyosaur :: AttackSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pAttackSounds ); -} - -void CIchthyosaur :: BiteSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_WEAPON, pBiteSounds ); -} - -void CIchthyosaur :: DeathSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pDieSounds ); -} - -void CIchthyosaur :: PainSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pPainSounds ); -} - -//========================================================= -// monster-specific tasks and states -//========================================================= -enum -{ - TASK_ICHTHYOSAUR_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, - TASK_ICHTHYOSAUR_SWIM, - TASK_ICHTHYOSAUR_FLOAT, -}; - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -static Task_t tlSwimAround[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ICHTHYOSAUR_SWIM, 0.0 }, -}; - -static Schedule_t slSwimAround[] = -{ - { - tlSwimAround, - ARRAYSIZE(tlSwimAround), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_PLAYER | - bits_SOUND_COMBAT, - "SwimAround" - }, -}; - -static Task_t tlSwimAgitated[] = -{ - { TASK_STOP_MOVING, (float) 0 }, - { TASK_SET_ACTIVITY, (float)ACT_RUN }, - { TASK_WAIT, (float)2.0 }, -}; - -static Schedule_t slSwimAgitated[] = -{ - { - tlSwimAgitated, - ARRAYSIZE(tlSwimAgitated), - 0, - 0, - "SwimAgitated" - }, -}; - - -static Task_t tlCircleEnemy[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ICHTHYOSAUR_CIRCLE_ENEMY, 0.0 }, -}; - -static Schedule_t slCircleEnemy[] = -{ - { - tlCircleEnemy, - ARRAYSIZE(tlCircleEnemy), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK1, - 0, - "CircleEnemy" - }, -}; - - -Task_t tlTwitchDie[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, - { TASK_ICHTHYOSAUR_FLOAT, (float)0 }, -}; - -Schedule_t slTwitchDie[] = -{ - { - tlTwitchDie, - ARRAYSIZE( tlTwitchDie ), - 0, - 0, - "Die" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES(CIchthyosaur) -{ - slSwimAround, - slSwimAgitated, - slCircleEnemy, - slTwitchDie, -}; -IMPLEMENT_CUSTOM_SCHEDULES(CIchthyosaur, CFlyingMonster); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CIchthyosaur :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CIchthyosaur :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) - { - return TRUE; - } - return FALSE; -} - -void CIchthyosaur::BiteTouch( CBaseEntity *pOther ) -{ - // bite if we hit who we want to eat - if ( pOther == m_hEnemy ) - { - m_flEnemyTouched = gpGlobals->time; - m_bOnAttack = TRUE; - } -} - -void CIchthyosaur::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_bOnAttack ) ) - return; - - if (m_bOnAttack) - { - m_bOnAttack = 0; - } - else - { - m_bOnAttack = 1; - } -} - -//========================================================= -// CheckRangeAttack1 - swim in for a chomp -// -//========================================================= -BOOL CIchthyosaur :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192))) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CIchthyosaur :: SetYawSpeed ( void ) -{ - pev->yaw_speed = 100; -} - - - -//========================================================= -// Killed - overrides CFlyingMonster. -// -void CIchthyosaur :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); - pev->velocity = Vector( 0, 0, 0 ); -} - -void CIchthyosaur::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. -} - -#define ICHTHYOSAUR_AE_SHAKE_RIGHT 1 -#define ICHTHYOSAUR_AE_SHAKE_LEFT 2 - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - int bDidAttack = FALSE; - switch( pEvent->event ) - { - case ICHTHYOSAUR_AE_SHAKE_RIGHT: - case ICHTHYOSAUR_AE_SHAKE_LEFT: - { - if (m_hEnemy != NULL && FVisible( m_hEnemy )) - { - CBaseEntity *pHurt = m_hEnemy; - - if (m_flEnemyTouched < gpGlobals->time - 0.2 && (m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > (32+16+32)) - break; - - Vector vecShootDir = ShootAtEnemy( pev->origin ); - UTIL_MakeAimVectors ( pev->angles ); - - if (DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707) - { - m_bOnAttack = TRUE; - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 300; - if (pHurt->IsPlayer()) - { - pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 ); - pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 ); - pHurt->pev->angles.z = 0; - pHurt->pev->fixangle = TRUE; - } - pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake, DMG_SLASH ); - } - } - BiteSound(); - - bDidAttack = TRUE; - } - break; - default: - CFlyingMonster::HandleAnimEvent( pEvent ); - break; - } - - if (bDidAttack) - { - Vector vecSrc = pev->origin + gpGlobals->v_forward * 32; - UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CIchthyosaur :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/icky.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) ); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.ichthyosaurHealth; - pev->view_ofs = Vector ( 0, 0, 16 ); - m_flFieldOfView = VIEW_FIELD_WIDE; - m_MonsterState = MONSTERSTATE_NONE; - SetBits(pev->flags, FL_SWIM); - SetFlyingSpeed( ICHTHYOSAUR_SPEED ); - SetFlyingMomentum( 2.5 ); // Set momentum constant - - m_afCapability = bits_CAP_RANGE_ATTACK1 | bits_CAP_SWIM; - - MonsterInit(); - - SetTouch( BiteTouch ); - SetUse( CombatUse ); - - m_idealDist = 384; - m_flMinSpeed = 80; - m_flMaxSpeed = 300; - m_flMaxDist = 384; - - Vector Forward; - UTIL_MakeVectorsPrivate(pev->angles, Forward, 0, 0); - pev->velocity = m_flightSpeed * Forward.Normalize(); - m_SaveVelocity = pev->velocity; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CIchthyosaur :: Precache() -{ - PRECACHE_MODEL("models/icky.mdl"); - - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pBiteSounds ); - PRECACHE_SOUND_ARRAY( pDieSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); -} - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t* CIchthyosaur::GetSchedule() -{ - // ALERT( at_console, "GetSchedule( )\n" ); - switch(m_MonsterState) - { - case MONSTERSTATE_IDLE: - m_flightSpeed = 80; - return GetScheduleOfType( SCHED_IDLE_WALK ); - - case MONSTERSTATE_ALERT: - m_flightSpeed = 150; - return GetScheduleOfType( SCHED_IDLE_WALK ); - - case MONSTERSTATE_COMBAT: - m_flMaxSpeed = 400; - // eat them - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - // chase them down and eat them - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - { - m_bOnAttack = TRUE; - } - if ( pev->health < pev->max_health - 20 ) - { - m_bOnAttack = TRUE; - } - - return GetScheduleOfType( SCHED_STANDOFF ); - } - - return CFlyingMonster :: GetSchedule(); -} - - -//========================================================= -//========================================================= -Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); - switch ( Type ) - { - case SCHED_IDLE_WALK: - return slSwimAround; - case SCHED_STANDOFF: - return slCircleEnemy; - case SCHED_FAIL: - return slSwimAgitated; - case SCHED_DIE: - return slTwitchDie; - case SCHED_CHASE_ENEMY: - AttackSound( ); - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - - - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CIchthyosaur::StartTask(Task_t *pTask) -{ - switch (pTask->iTask) - { - case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - break; - case TASK_ICHTHYOSAUR_SWIM: - break; - case TASK_SMALL_FLINCH: - if (m_idealDist > 128) - { - m_flMaxDist = 512; - m_idealDist = 512; - } - else - { - m_bOnAttack = TRUE; - } - CFlyingMonster::StartTask(pTask); - break; - - case TASK_ICHTHYOSAUR_FLOAT: - pev->skin = EYE_BASE; - SetSequenceByName( "bellyup" ); - break; - - default: - CFlyingMonster::StartTask(pTask); - break; - } -} - -void CIchthyosaur :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - if (m_hEnemy == NULL) - { - TaskComplete( ); - } - else if (FVisible( m_hEnemy )) - { - Vector vecFrom = m_hEnemy->EyePosition( ); - - Vector vecDelta = (pev->origin - vecFrom).Normalize( ); - Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize( ); - - if (DotProduct( vecSwim, m_SaveVelocity ) < 0) - vecSwim = vecSwim * -1.0; - - Vector vecPos = vecFrom + vecDelta * m_idealDist + vecSwim * 32; - - // ALERT( at_console, "vecPos %.0f %.0f %.0f\n", vecPos.x, vecPos.y, vecPos.z ); - - TraceResult tr; - - UTIL_TraceHull( vecFrom, vecPos, ignore_monsters, large_hull, m_hEnemy->edict(), &tr ); - - if (tr.flFraction > 0.5) - vecPos = tr.vecEndPos; - - m_SaveVelocity = m_SaveVelocity * 0.8 + 0.2 * (vecPos - pev->origin).Normalize() * m_flightSpeed; - - // ALERT( at_console, "m_SaveVelocity %.2f %.2f %.2f\n", m_SaveVelocity.x, m_SaveVelocity.y, m_SaveVelocity.z ); - - if (HasConditions( bits_COND_ENEMY_FACING_ME ) && m_hEnemy->FVisible( this )) - { - m_flNextAlert -= 0.1; - - if (m_idealDist < m_flMaxDist) - { - m_idealDist += 4; - } - if (m_flightSpeed > m_flMinSpeed) - { - m_flightSpeed -= 2; - } - else if (m_flightSpeed < m_flMinSpeed) - { - m_flightSpeed += 2; - } - if (m_flMinSpeed < m_flMaxSpeed) - { - m_flMinSpeed += 0.5; - } - } - else - { - m_flNextAlert += 0.1; - - if (m_idealDist > 128) - { - m_idealDist -= 4; - } - if (m_flightSpeed < m_flMaxSpeed) - { - m_flightSpeed += 4; - } - } - // ALERT( at_console, "%.0f\n", m_idealDist ); - } - else - { - m_flNextAlert = gpGlobals->time + 0.2; - } - - if (m_flNextAlert < gpGlobals->time) - { - // ALERT( at_console, "AlertSound()\n"); - AlertSound( ); - m_flNextAlert = gpGlobals->time + RANDOM_FLOAT( 3, 5 ); - } - - break; - case TASK_ICHTHYOSAUR_SWIM: - if (m_fSequenceFinished) - { - TaskComplete( ); - } - break; - case TASK_DIE: - if ( m_fSequenceFinished ) - { - pev->deadflag = DEAD_DEAD; - - TaskComplete( ); - } - break; - - case TASK_ICHTHYOSAUR_FLOAT: - pev->angles.x = UTIL_ApproachAngle( 0, pev->angles.x, 20 ); - pev->velocity = pev->velocity * 0.8; - if (pev->waterlevel > 1 && pev->velocity.z < 64) - { - pev->velocity.z += 8; - } - else - { - pev->velocity.z -= 8; - } - // ALERT( at_console, "%f\n", pev->velocity.z ); - break; - - default: - CFlyingMonster :: RunTask ( pTask ); - break; - } -} - - - -float CIchthyosaur::VectorToPitch( const Vector &vec ) -{ - float pitch; - if (vec.z == 0 && vec.x == 0) - pitch = 0; - else - { - pitch = (int) (atan2(vec.z, sqrt(vec.x*vec.x+vec.y*vec.y)) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - return pitch; -} - -//========================================================= -void CIchthyosaur::Move(float flInterval) -{ - CFlyingMonster::Move( flInterval ); -} - -float CIchthyosaur::FlPitchDiff( void ) -{ - float flPitchDiff; - float flCurrentPitch; - - flCurrentPitch = UTIL_AngleMod( pev->angles.z ); - - if ( flCurrentPitch == pev->idealpitch ) - { - return 0; - } - - flPitchDiff = pev->idealpitch - flCurrentPitch; - - if ( pev->idealpitch > flCurrentPitch ) - { - if (flPitchDiff >= 180) - flPitchDiff = flPitchDiff - 360; - } - else - { - if (flPitchDiff <= -180) - flPitchDiff = flPitchDiff + 360; - } - return flPitchDiff; -} - -float CIchthyosaur :: ChangePitch( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlPitchDiff(); - float target = 0; - if ( m_IdealActivity != GetStoppedActivity() ) - { - if (diff < -20) - target = 45; - else if (diff > 20) - target = -45; - } - pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 ); - } - return 0; -} - -float CIchthyosaur::ChangeYaw( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if ( m_IdealActivity != GetStoppedActivity() ) - { - if ( diff < -20 ) - target = 20; - else if ( diff > 20 ) - target = -20; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 ); - } - return CFlyingMonster::ChangeYaw( speed ); -} - - -Activity CIchthyosaur:: GetStoppedActivity( void ) -{ - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - return ACT_WALK; -} - -void CIchthyosaur::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - m_SaveVelocity = vecDir * m_flightSpeed; -} - - -void CIchthyosaur::MonsterThink ( void ) -{ - CFlyingMonster::MonsterThink( ); - - if (pev->deadflag == DEAD_NO) - { - if (m_MonsterState != MONSTERSTATE_SCRIPT) - { - Swim( ); - - // blink the eye - if (m_flBlink < gpGlobals->time) - { - pev->skin = EYE_CLOSED; - if (m_flBlink + 0.2 < gpGlobals->time) - { - m_flBlink = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); - if (m_bOnAttack) - pev->skin = EYE_MAD; - else - pev->skin = EYE_BASE; - } - } - } - } -} - -void CIchthyosaur :: Stop( void ) -{ - if (!m_bOnAttack) - m_flightSpeed = 80.0; -} - -void CIchthyosaur::Swim( ) -{ - int retValue = 0; - - Vector start = pev->origin; - - Vector Angles; - Vector Forward, Right, Up; - - if (FBitSet( pev->flags, FL_ONGROUND)) - { - pev->angles.x = 0; - pev->angles.y += RANDOM_FLOAT( -45, 45 ); - ClearBits( pev->flags, FL_ONGROUND ); - - Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); - - pev->velocity = Forward * 200 + Up * 200; - - return; - } - - if (m_bOnAttack && m_flightSpeed < m_flMaxSpeed) - { - m_flightSpeed += 40; - } - if (m_flightSpeed < 180) - { - if (m_IdealActivity == ACT_RUN) - SetActivity( ACT_WALK ); - if (m_IdealActivity == ACT_WALK) - pev->framerate = m_flightSpeed / 150.0; - // ALERT( at_console, "walk %.2f\n", pev->framerate ); - } - else - { - if (m_IdealActivity == ACT_WALK) - SetActivity( ACT_RUN ); - if (m_IdealActivity == ACT_RUN) - pev->framerate = m_flightSpeed / 150.0; - // ALERT( at_console, "run %.2f\n", pev->framerate ); - } - -/* - if (!m_pBeam) - { - m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); - m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex( ) ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->SetColor( 255, 180, 96 ); - m_pBeam->SetBrightness( 192 ); - } -*/ -#define PROBE_LENGTH 150 - Angles = UTIL_VecToAngles( m_SaveVelocity ); - Angles.x = -Angles.x; - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); - - Vector f, u, l, r, d; - f = DoProbe(start + PROBE_LENGTH * Forward); - r = DoProbe(start + PROBE_LENGTH/3 * Forward+Right); - l = DoProbe(start + PROBE_LENGTH/3 * Forward-Right); - u = DoProbe(start + PROBE_LENGTH/3 * Forward+Up); - d = DoProbe(start + PROBE_LENGTH/3 * Forward-Up); - - Vector SteeringVector = f+r+l+u+d; - m_SaveVelocity = (m_SaveVelocity + SteeringVector/2).Normalize(); - - Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); - // ALERT( at_console, "%f : %f\n", Angles.x, Forward.z ); - - float flDot = DotProduct( Forward, m_SaveVelocity ); - if (flDot > 0.5) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed; - else if (flDot > 0) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * (flDot + 0.5); - else - pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; - - // ALERT( at_console, "%.0f %.0f\n", m_flightSpeed, pev->velocity.Length() ); - - - // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); - -/* - m_pBeam->SetStartPos( pev->origin + pev->velocity ); - m_pBeam->RelinkBeam( ); -*/ - - // ALERT( at_console, "speed %f\n", m_flightSpeed ); - - Angles = UTIL_VecToAngles( m_SaveVelocity ); - - // Smooth Pitch - // - if (Angles.x > 180) - Angles.x = Angles.x - 360; - pev->angles.x = UTIL_Approach(Angles.x, pev->angles.x, 50 * 0.1 ); - if (pev->angles.x < -80) pev->angles.x = -80; - if (pev->angles.x > 80) pev->angles.x = 80; - - // Smooth Yaw and generate Roll - // - float turn = 360; - // ALERT( at_console, "Y %.0f %.0f\n", Angles.y, pev->angles.y ); - - if (fabs(Angles.y - pev->angles.y) < fabs(turn)) - { - turn = Angles.y - pev->angles.y; - } - if (fabs(Angles.y - pev->angles.y + 360) < fabs(turn)) - { - turn = Angles.y - pev->angles.y + 360; - } - if (fabs(Angles.y - pev->angles.y - 360) < fabs(turn)) - { - turn = Angles.y - pev->angles.y - 360; - } - - float speed = m_flightSpeed * 0.1; - - // ALERT( at_console, "speed %.0f %f\n", turn, speed ); - if (fabs(turn) > speed) - { - if (turn < 0.0) - { - turn = -speed; - } - else - { - turn = speed; - } - } - pev->angles.y += turn; - pev->angles.z -= turn; - pev->angles.y = fmod((pev->angles.y + 360.0), 360.0); - - static float yaw_adj; - - yaw_adj = yaw_adj * 0.8 + turn; - - // ALERT( at_console, "yaw %f : %f\n", turn, yaw_adj ); - - SetBoneController( 0, -yaw_adj / 4.0 ); - - // Roll Smoothing - // - turn = 360; - if (fabs(Angles.z - pev->angles.z) < fabs(turn)) - { - turn = Angles.z - pev->angles.z; - } - if (fabs(Angles.z - pev->angles.z + 360) < fabs(turn)) - { - turn = Angles.z - pev->angles.z + 360; - } - if (fabs(Angles.z - pev->angles.z - 360) < fabs(turn)) - { - turn = Angles.z - pev->angles.z - 360; - } - speed = m_flightSpeed/2 * 0.1; - if (fabs(turn) < speed) - { - pev->angles.z += turn; - } - else - { - if (turn < 0.0) - { - pev->angles.z -= speed; - } - else - { - pev->angles.z += speed; - } - } - if (pev->angles.z < -20) pev->angles.z = -20; - if (pev->angles.z > 20) pev->angles.z = 20; - - UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up); - - // UTIL_MoveToOrigin ( ENT(pev), pev->origin + Forward * speed, speed, MOVE_STRAFE ); -} - - -Vector CIchthyosaur::DoProbe(const Vector &Probe) -{ - Vector WallNormal = Vector(0,0,-1); // WATER normal is Straight Down for fish. - float frac; - BOOL bBumpedSomething = ProbeZ(pev->origin, Probe, &frac); - - TraceResult tr; - TRACE_MONSTER_HULL(edict(), pev->origin, Probe, dont_ignore_monsters, edict(), &tr); - if ( tr.fAllSolid || tr.flFraction < 0.99 ) - { - if (tr.flFraction < 0.0) tr.flFraction = 0.0; - if (tr.flFraction > 1.0) tr.flFraction = 1.0; - if (tr.flFraction < frac) - { - frac = tr.flFraction; - bBumpedSomething = TRUE; - WallNormal = tr.vecPlaneNormal; - } - } - - if (bBumpedSomething && (m_hEnemy == NULL || tr.pHit != m_hEnemy->edict())) - { - Vector ProbeDir = Probe - pev->origin; - - Vector NormalToProbeAndWallNormal = CrossProduct(ProbeDir, WallNormal); - Vector SteeringVector = CrossProduct( NormalToProbeAndWallNormal, ProbeDir); - - float SteeringForce = m_flightSpeed * (1-frac) * (DotProduct(WallNormal.Normalize(), m_SaveVelocity.Normalize())); - if (SteeringForce < 0.0) - { - SteeringForce = -SteeringForce; - } - SteeringVector = SteeringForce * SteeringVector.Normalize(); - - return SteeringVector; - } - return Vector(0, 0, 0); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +//========================================================= +// icthyosaur - evin, satan fish monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "flyingmonster.h" +#include "nodes.h" +#include "soundent.h" +#include "animation.h" +#include "effects.h" +#include "weapons.h" + +#define SEARCH_RETRY 16 + +#define ICHTHYOSAUR_SPEED 150 + +extern CGraph WorldGraph; + +#define EYE_MAD 0 +#define EYE_BASE 1 +#define EYE_CLOSED 2 +#define EYE_BACK 3 +#define EYE_LOOK 4 + + + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= + +// UNDONE: Save/restore here +class CIchthyosaur : public CFlyingMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + CUSTOM_SCHEDULES; + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + Schedule_t *GetSchedule( void ); + Schedule_t *GetScheduleOfType ( int Type ); + + void Killed( entvars_t *pevAttacker, int iGib ); + void BecomeDead( void ); + + void EXPORT CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT BiteTouch( CBaseEntity *pOther ); + + void StartTask( Task_t *pTask ); + void RunTask( Task_t *pTask ); + + BOOL CheckMeleeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + + float ChangeYaw( int speed ); + Activity GetStoppedActivity( void ); + + void Move( float flInterval ); + void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); + void MonsterThink( void ); + void Stop( void ); + void Swim( void ); + Vector DoProbe(const Vector &Probe); + + float VectorToPitch( const Vector &vec); + float FlPitchDiff( void ); + float ChangePitch( int speed ); + + Vector m_SaveVelocity; + float m_idealDist; + + float m_flBlink; + + float m_flEnemyTouched; + BOOL m_bOnAttack; + + float m_flMaxSpeed; + float m_flMinSpeed; + float m_flMaxDist; + + CBeam *m_pBeam; + + float m_flNextAlert; + + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + static const char *pAttackSounds[]; + static const char *pBiteSounds[]; + static const char *pDieSounds[]; + static const char *pPainSounds[]; + + void IdleSound( void ); + void AlertSound( void ); + void AttackSound( void ); + void BiteSound( void ); + void DeathSound( void ); + void PainSound( void ); +}; + +LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur ); + +TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = +{ + DEFINE_FIELD( CIchthyosaur, m_SaveVelocity, FIELD_VECTOR ), + DEFINE_FIELD( CIchthyosaur, m_idealDist, FIELD_FLOAT ), + DEFINE_FIELD( CIchthyosaur, m_flBlink, FIELD_FLOAT ), + DEFINE_FIELD( CIchthyosaur, m_flEnemyTouched, FIELD_FLOAT ), + DEFINE_FIELD( CIchthyosaur, m_bOnAttack, FIELD_BOOLEAN ), + DEFINE_FIELD( CIchthyosaur, m_flMaxSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CIchthyosaur, m_flMinSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CIchthyosaur, m_flMaxDist, FIELD_FLOAT ), + DEFINE_FIELD( CIchthyosaur, m_flNextAlert, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CIchthyosaur, CFlyingMonster ); + + +const char *CIchthyosaur::pIdleSounds[] = +{ + "ichy/ichy_idle1.wav", + "ichy/ichy_idle2.wav", + "ichy/ichy_idle3.wav", + "ichy/ichy_idle4.wav", +}; + +const char *CIchthyosaur::pAlertSounds[] = +{ + "ichy/ichy_alert2.wav", + "ichy/ichy_alert3.wav", +}; + +const char *CIchthyosaur::pAttackSounds[] = +{ + "ichy/ichy_attack1.wav", + "ichy/ichy_attack2.wav", +}; + +const char *CIchthyosaur::pBiteSounds[] = +{ + "ichy/ichy_bite1.wav", + "ichy/ichy_bite2.wav", +}; + +const char *CIchthyosaur::pPainSounds[] = +{ + "ichy/ichy_pain2.wav", + "ichy/ichy_pain3.wav", + "ichy/ichy_pain5.wav", +}; + +const char *CIchthyosaur::pDieSounds[] = +{ + "ichy/ichy_die2.wav", + "ichy/ichy_die4.wav", +}; + +#define EMIT_ICKY_SOUND( chan, array ) \ + EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, 0.6, 0, RANDOM_LONG(95,105) ); + + +void CIchthyosaur :: IdleSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_VOICE, pIdleSounds ); +} + +void CIchthyosaur :: AlertSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_VOICE, pAlertSounds ); +} + +void CIchthyosaur :: AttackSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_VOICE, pAttackSounds ); +} + +void CIchthyosaur :: BiteSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_WEAPON, pBiteSounds ); +} + +void CIchthyosaur :: DeathSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_VOICE, pDieSounds ); +} + +void CIchthyosaur :: PainSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_VOICE, pPainSounds ); +} + +//========================================================= +// monster-specific tasks and states +//========================================================= +enum +{ + TASK_ICHTHYOSAUR_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, + TASK_ICHTHYOSAUR_SWIM, + TASK_ICHTHYOSAUR_FLOAT, +}; + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + +static Task_t tlSwimAround[] = +{ + { TASK_SET_ACTIVITY, (float)ACT_WALK }, + { TASK_ICHTHYOSAUR_SWIM, 0.0 }, +}; + +static Schedule_t slSwimAround[] = +{ + { + tlSwimAround, + ARRAYSIZE(tlSwimAround), + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_SEE_ENEMY | + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND, + bits_SOUND_PLAYER | + bits_SOUND_COMBAT, + "SwimAround" + }, +}; + +static Task_t tlSwimAgitated[] = +{ + { TASK_STOP_MOVING, (float) 0 }, + { TASK_SET_ACTIVITY, (float)ACT_RUN }, + { TASK_WAIT, (float)2.0 }, +}; + +static Schedule_t slSwimAgitated[] = +{ + { + tlSwimAgitated, + ARRAYSIZE(tlSwimAgitated), + 0, + 0, + "SwimAgitated" + }, +}; + + +static Task_t tlCircleEnemy[] = +{ + { TASK_SET_ACTIVITY, (float)ACT_WALK }, + { TASK_ICHTHYOSAUR_CIRCLE_ENEMY, 0.0 }, +}; + +static Schedule_t slCircleEnemy[] = +{ + { + tlCircleEnemy, + ARRAYSIZE(tlCircleEnemy), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_RANGE_ATTACK1, + 0, + "CircleEnemy" + }, +}; + + +Task_t tlTwitchDie[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SOUND_DIE, (float)0 }, + { TASK_DIE, (float)0 }, + { TASK_ICHTHYOSAUR_FLOAT, (float)0 }, +}; + +Schedule_t slTwitchDie[] = +{ + { + tlTwitchDie, + ARRAYSIZE( tlTwitchDie ), + 0, + 0, + "Die" + }, +}; + + +DEFINE_CUSTOM_SCHEDULES(CIchthyosaur) +{ + slSwimAround, + slSwimAgitated, + slCircleEnemy, + slTwitchDie, +}; +IMPLEMENT_CUSTOM_SCHEDULES(CIchthyosaur, CFlyingMonster); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CIchthyosaur :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + + +//========================================================= +// CheckMeleeAttack1 +//========================================================= +BOOL CIchthyosaur :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + if ( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) + { + return TRUE; + } + return FALSE; +} + +void CIchthyosaur::BiteTouch( CBaseEntity *pOther ) +{ + // bite if we hit who we want to eat + if ( pOther == m_hEnemy ) + { + m_flEnemyTouched = gpGlobals->time; + m_bOnAttack = TRUE; + } +} + +void CIchthyosaur::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_bOnAttack ) ) + return; + + if (m_bOnAttack) + { + m_bOnAttack = 0; + } + else + { + m_bOnAttack = 1; + } +} + +//========================================================= +// CheckRangeAttack1 - swim in for a chomp +// +//========================================================= +BOOL CIchthyosaur :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192))) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CIchthyosaur :: SetYawSpeed ( void ) +{ + pev->yaw_speed = 100; +} + + + +//========================================================= +// Killed - overrides CFlyingMonster. +// +void CIchthyosaur :: Killed( entvars_t *pevAttacker, int iGib ) +{ + CBaseMonster::Killed( pevAttacker, iGib ); + pev->velocity = Vector( 0, 0, 0 ); +} + +void CIchthyosaur::BecomeDead( void ) +{ + pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. + + // give the corpse half of the monster's original maximum health. + pev->health = pev->max_health / 2; + pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. +} + +#define ICHTHYOSAUR_AE_SHAKE_RIGHT 1 +#define ICHTHYOSAUR_AE_SHAKE_LEFT 2 + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + int bDidAttack = FALSE; + switch( pEvent->event ) + { + case ICHTHYOSAUR_AE_SHAKE_RIGHT: + case ICHTHYOSAUR_AE_SHAKE_LEFT: + { + if (m_hEnemy != NULL && FVisible( m_hEnemy )) + { + CBaseEntity *pHurt = m_hEnemy; + + if (m_flEnemyTouched < gpGlobals->time - 0.2 && (m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > (32+16+32)) + break; + + Vector vecShootDir = ShootAtEnemy( pev->origin ); + UTIL_MakeAimVectors ( pev->angles ); + + if (DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707) + { + m_bOnAttack = TRUE; + pHurt->pev->punchangle.z = -18; + pHurt->pev->punchangle.x = 5; + pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 300; + if (pHurt->IsPlayer()) + { + pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 ); + pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 ); + pHurt->pev->angles.z = 0; + pHurt->pev->fixangle = TRUE; + } + pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake, DMG_SLASH ); + } + } + BiteSound(); + + bDidAttack = TRUE; + } + break; + default: + CFlyingMonster::HandleAnimEvent( pEvent ); + break; + } + + if (bDidAttack) + { + Vector vecSrc = pev->origin + gpGlobals->v_forward * 32; + UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 ); + } +} + +//========================================================= +// Spawn +//========================================================= +void CIchthyosaur :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/icky.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) ); + + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_FLY; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = gSkillData.ichthyosaurHealth; + pev->view_ofs = Vector ( 0, 0, 16 ); + m_flFieldOfView = VIEW_FIELD_WIDE; + m_MonsterState = MONSTERSTATE_NONE; + SetBits(pev->flags, FL_SWIM); + SetFlyingSpeed( ICHTHYOSAUR_SPEED ); + SetFlyingMomentum( 2.5 ); // Set momentum constant + + m_afCapability = bits_CAP_RANGE_ATTACK1 | bits_CAP_SWIM; + + MonsterInit(); + + SetTouch( BiteTouch ); + SetUse( CombatUse ); + + m_idealDist = 384; + m_flMinSpeed = 80; + m_flMaxSpeed = 300; + m_flMaxDist = 384; + + Vector Forward; + UTIL_MakeVectorsPrivate(pev->angles, Forward, 0, 0); + pev->velocity = m_flightSpeed * Forward.Normalize(); + m_SaveVelocity = pev->velocity; +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CIchthyosaur :: Precache() +{ + PRECACHE_MODEL("models/icky.mdl"); + + PRECACHE_SOUND_ARRAY( pIdleSounds ); + PRECACHE_SOUND_ARRAY( pAlertSounds ); + PRECACHE_SOUND_ARRAY( pAttackSounds ); + PRECACHE_SOUND_ARRAY( pBiteSounds ); + PRECACHE_SOUND_ARRAY( pDieSounds ); + PRECACHE_SOUND_ARRAY( pPainSounds ); +} + +//========================================================= +// GetSchedule +//========================================================= +Schedule_t* CIchthyosaur::GetSchedule() +{ + // ALERT( at_console, "GetSchedule( )\n" ); + switch(m_MonsterState) + { + case MONSTERSTATE_IDLE: + m_flightSpeed = 80; + return GetScheduleOfType( SCHED_IDLE_WALK ); + + case MONSTERSTATE_ALERT: + m_flightSpeed = 150; + return GetScheduleOfType( SCHED_IDLE_WALK ); + + case MONSTERSTATE_COMBAT: + m_flMaxSpeed = 400; + // eat them + if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + { + return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); + } + // chase them down and eat them + if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) + { + return GetScheduleOfType( SCHED_CHASE_ENEMY ); + } + if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) + { + m_bOnAttack = TRUE; + } + if ( pev->health < pev->max_health - 20 ) + { + m_bOnAttack = TRUE; + } + + return GetScheduleOfType( SCHED_STANDOFF ); + } + + return CFlyingMonster :: GetSchedule(); +} + + +//========================================================= +//========================================================= +Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) +{ + // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); + switch ( Type ) + { + case SCHED_IDLE_WALK: + return slSwimAround; + case SCHED_STANDOFF: + return slCircleEnemy; + case SCHED_FAIL: + return slSwimAgitated; + case SCHED_DIE: + return slTwitchDie; + case SCHED_CHASE_ENEMY: + AttackSound( ); + } + + return CBaseMonster :: GetScheduleOfType( Type ); +} + + + +//========================================================= +// Start task - selects the correct activity and performs +// any necessary calculations to start the next task on the +// schedule. +//========================================================= +void CIchthyosaur::StartTask(Task_t *pTask) +{ + switch (pTask->iTask) + { + case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: + break; + case TASK_ICHTHYOSAUR_SWIM: + break; + case TASK_SMALL_FLINCH: + if (m_idealDist > 128) + { + m_flMaxDist = 512; + m_idealDist = 512; + } + else + { + m_bOnAttack = TRUE; + } + CFlyingMonster::StartTask(pTask); + break; + + case TASK_ICHTHYOSAUR_FLOAT: + pev->skin = EYE_BASE; + SetSequenceByName( "bellyup" ); + break; + + default: + CFlyingMonster::StartTask(pTask); + break; + } +} + +void CIchthyosaur :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: + if (m_hEnemy == NULL) + { + TaskComplete( ); + } + else if (FVisible( m_hEnemy )) + { + Vector vecFrom = m_hEnemy->EyePosition( ); + + Vector vecDelta = (pev->origin - vecFrom).Normalize( ); + Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize( ); + + if (DotProduct( vecSwim, m_SaveVelocity ) < 0) + vecSwim = vecSwim * -1.0; + + Vector vecPos = vecFrom + vecDelta * m_idealDist + vecSwim * 32; + + // ALERT( at_console, "vecPos %.0f %.0f %.0f\n", vecPos.x, vecPos.y, vecPos.z ); + + TraceResult tr; + + UTIL_TraceHull( vecFrom, vecPos, ignore_monsters, large_hull, m_hEnemy->edict(), &tr ); + + if (tr.flFraction > 0.5) + vecPos = tr.vecEndPos; + + m_SaveVelocity = m_SaveVelocity * 0.8 + 0.2 * (vecPos - pev->origin).Normalize() * m_flightSpeed; + + // ALERT( at_console, "m_SaveVelocity %.2f %.2f %.2f\n", m_SaveVelocity.x, m_SaveVelocity.y, m_SaveVelocity.z ); + + if (HasConditions( bits_COND_ENEMY_FACING_ME ) && m_hEnemy->FVisible( this )) + { + m_flNextAlert -= 0.1; + + if (m_idealDist < m_flMaxDist) + { + m_idealDist += 4; + } + if (m_flightSpeed > m_flMinSpeed) + { + m_flightSpeed -= 2; + } + else if (m_flightSpeed < m_flMinSpeed) + { + m_flightSpeed += 2; + } + if (m_flMinSpeed < m_flMaxSpeed) + { + m_flMinSpeed += 0.5; + } + } + else + { + m_flNextAlert += 0.1; + + if (m_idealDist > 128) + { + m_idealDist -= 4; + } + if (m_flightSpeed < m_flMaxSpeed) + { + m_flightSpeed += 4; + } + } + // ALERT( at_console, "%.0f\n", m_idealDist ); + } + else + { + m_flNextAlert = gpGlobals->time + 0.2; + } + + if (m_flNextAlert < gpGlobals->time) + { + // ALERT( at_console, "AlertSound()\n"); + AlertSound( ); + m_flNextAlert = gpGlobals->time + RANDOM_FLOAT( 3, 5 ); + } + + break; + case TASK_ICHTHYOSAUR_SWIM: + if (m_fSequenceFinished) + { + TaskComplete( ); + } + break; + case TASK_DIE: + if ( m_fSequenceFinished ) + { + pev->deadflag = DEAD_DEAD; + + TaskComplete( ); + } + break; + + case TASK_ICHTHYOSAUR_FLOAT: + pev->angles.x = UTIL_ApproachAngle( 0, pev->angles.x, 20 ); + pev->velocity = pev->velocity * 0.8; + if (pev->waterlevel > 1 && pev->velocity.z < 64) + { + pev->velocity.z += 8; + } + else + { + pev->velocity.z -= 8; + } + // ALERT( at_console, "%f\n", pev->velocity.z ); + break; + + default: + CFlyingMonster :: RunTask ( pTask ); + break; + } +} + + + +float CIchthyosaur::VectorToPitch( const Vector &vec ) +{ + float pitch; + if (vec.z == 0 && vec.x == 0) + pitch = 0; + else + { + pitch = (int) (atan2(vec.z, sqrt(vec.x*vec.x+vec.y*vec.y)) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + return pitch; +} + +//========================================================= +void CIchthyosaur::Move(float flInterval) +{ + CFlyingMonster::Move( flInterval ); +} + +float CIchthyosaur::FlPitchDiff( void ) +{ + float flPitchDiff; + float flCurrentPitch; + + flCurrentPitch = UTIL_AngleMod( pev->angles.z ); + + if ( flCurrentPitch == pev->idealpitch ) + { + return 0; + } + + flPitchDiff = pev->idealpitch - flCurrentPitch; + + if ( pev->idealpitch > flCurrentPitch ) + { + if (flPitchDiff >= 180) + flPitchDiff = flPitchDiff - 360; + } + else + { + if (flPitchDiff <= -180) + flPitchDiff = flPitchDiff + 360; + } + return flPitchDiff; +} + +float CIchthyosaur :: ChangePitch( int speed ) +{ + if ( pev->movetype == MOVETYPE_FLY ) + { + float diff = FlPitchDiff(); + float target = 0; + if ( m_IdealActivity != GetStoppedActivity() ) + { + if (diff < -20) + target = 45; + else if (diff > 20) + target = -45; + } + pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 ); + } + return 0; +} + +float CIchthyosaur::ChangeYaw( int speed ) +{ + if ( pev->movetype == MOVETYPE_FLY ) + { + float diff = FlYawDiff(); + float target = 0; + + if ( m_IdealActivity != GetStoppedActivity() ) + { + if ( diff < -20 ) + target = 20; + else if ( diff > 20 ) + target = -20; + } + pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 ); + } + return CFlyingMonster::ChangeYaw( speed ); +} + + +Activity CIchthyosaur:: GetStoppedActivity( void ) +{ + if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else + return ACT_IDLE; + return ACT_WALK; +} + +void CIchthyosaur::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) +{ + m_SaveVelocity = vecDir * m_flightSpeed; +} + + +void CIchthyosaur::MonsterThink ( void ) +{ + CFlyingMonster::MonsterThink( ); + + if (pev->deadflag == DEAD_NO) + { + if (m_MonsterState != MONSTERSTATE_SCRIPT) + { + Swim( ); + + // blink the eye + if (m_flBlink < gpGlobals->time) + { + pev->skin = EYE_CLOSED; + if (m_flBlink + 0.2 < gpGlobals->time) + { + m_flBlink = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); + if (m_bOnAttack) + pev->skin = EYE_MAD; + else + pev->skin = EYE_BASE; + } + } + } + } +} + +void CIchthyosaur :: Stop( void ) +{ + if (!m_bOnAttack) + m_flightSpeed = 80.0; +} + +void CIchthyosaur::Swim( ) +{ + int retValue = 0; + + Vector start = pev->origin; + + Vector Angles; + Vector Forward, Right, Up; + + if (FBitSet( pev->flags, FL_ONGROUND)) + { + pev->angles.x = 0; + pev->angles.y += RANDOM_FLOAT( -45, 45 ); + ClearBits( pev->flags, FL_ONGROUND ); + + Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); + UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + + pev->velocity = Forward * 200 + Up * 200; + + return; + } + + if (m_bOnAttack && m_flightSpeed < m_flMaxSpeed) + { + m_flightSpeed += 40; + } + if (m_flightSpeed < 180) + { + if (m_IdealActivity == ACT_RUN) + SetActivity( ACT_WALK ); + if (m_IdealActivity == ACT_WALK) + pev->framerate = m_flightSpeed / 150.0; + // ALERT( at_console, "walk %.2f\n", pev->framerate ); + } + else + { + if (m_IdealActivity == ACT_WALK) + SetActivity( ACT_RUN ); + if (m_IdealActivity == ACT_RUN) + pev->framerate = m_flightSpeed / 150.0; + // ALERT( at_console, "run %.2f\n", pev->framerate ); + } + +/* + if (!m_pBeam) + { + m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); + m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex( ) ); + m_pBeam->SetEndAttachment( 1 ); + m_pBeam->SetColor( 255, 180, 96 ); + m_pBeam->SetBrightness( 192 ); + } +*/ +#define PROBE_LENGTH 150 + Angles = UTIL_VecToAngles( m_SaveVelocity ); + Angles.x = -Angles.x; + UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + + Vector f, u, l, r, d; + f = DoProbe(start + PROBE_LENGTH * Forward); + r = DoProbe(start + PROBE_LENGTH/3 * Forward+Right); + l = DoProbe(start + PROBE_LENGTH/3 * Forward-Right); + u = DoProbe(start + PROBE_LENGTH/3 * Forward+Up); + d = DoProbe(start + PROBE_LENGTH/3 * Forward-Up); + + Vector SteeringVector = f+r+l+u+d; + m_SaveVelocity = (m_SaveVelocity + SteeringVector/2).Normalize(); + + Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); + UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + // ALERT( at_console, "%f : %f\n", Angles.x, Forward.z ); + + float flDot = DotProduct( Forward, m_SaveVelocity ); + if (flDot > 0.5) + pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed; + else if (flDot > 0) + pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * (flDot + 0.5); + else + pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; + + // ALERT( at_console, "%.0f %.0f\n", m_flightSpeed, pev->velocity.Length() ); + + + // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); + +/* + m_pBeam->SetStartPos( pev->origin + pev->velocity ); + m_pBeam->RelinkBeam( ); +*/ + + // ALERT( at_console, "speed %f\n", m_flightSpeed ); + + Angles = UTIL_VecToAngles( m_SaveVelocity ); + + // Smooth Pitch + // + if (Angles.x > 180) + Angles.x = Angles.x - 360; + pev->angles.x = UTIL_Approach(Angles.x, pev->angles.x, 50 * 0.1 ); + if (pev->angles.x < -80) pev->angles.x = -80; + if (pev->angles.x > 80) pev->angles.x = 80; + + // Smooth Yaw and generate Roll + // + float turn = 360; + // ALERT( at_console, "Y %.0f %.0f\n", Angles.y, pev->angles.y ); + + if (fabs(Angles.y - pev->angles.y) < fabs(turn)) + { + turn = Angles.y - pev->angles.y; + } + if (fabs(Angles.y - pev->angles.y + 360) < fabs(turn)) + { + turn = Angles.y - pev->angles.y + 360; + } + if (fabs(Angles.y - pev->angles.y - 360) < fabs(turn)) + { + turn = Angles.y - pev->angles.y - 360; + } + + float speed = m_flightSpeed * 0.1; + + // ALERT( at_console, "speed %.0f %f\n", turn, speed ); + if (fabs(turn) > speed) + { + if (turn < 0.0) + { + turn = -speed; + } + else + { + turn = speed; + } + } + pev->angles.y += turn; + pev->angles.z -= turn; + pev->angles.y = fmod((pev->angles.y + 360.0), 360.0); + + static float yaw_adj; + + yaw_adj = yaw_adj * 0.8 + turn; + + // ALERT( at_console, "yaw %f : %f\n", turn, yaw_adj ); + + SetBoneController( 0, -yaw_adj / 4.0 ); + + // Roll Smoothing + // + turn = 360; + if (fabs(Angles.z - pev->angles.z) < fabs(turn)) + { + turn = Angles.z - pev->angles.z; + } + if (fabs(Angles.z - pev->angles.z + 360) < fabs(turn)) + { + turn = Angles.z - pev->angles.z + 360; + } + if (fabs(Angles.z - pev->angles.z - 360) < fabs(turn)) + { + turn = Angles.z - pev->angles.z - 360; + } + speed = m_flightSpeed/2 * 0.1; + if (fabs(turn) < speed) + { + pev->angles.z += turn; + } + else + { + if (turn < 0.0) + { + pev->angles.z -= speed; + } + else + { + pev->angles.z += speed; + } + } + if (pev->angles.z < -20) pev->angles.z = -20; + if (pev->angles.z > 20) pev->angles.z = 20; + + UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up); + + // UTIL_MoveToOrigin ( ENT(pev), pev->origin + Forward * speed, speed, MOVE_STRAFE ); +} + + +Vector CIchthyosaur::DoProbe(const Vector &Probe) +{ + Vector WallNormal = Vector(0,0,-1); // WATER normal is Straight Down for fish. + float frac; + BOOL bBumpedSomething = ProbeZ(pev->origin, Probe, &frac); + + TraceResult tr; + TRACE_MONSTER_HULL(edict(), pev->origin, Probe, dont_ignore_monsters, edict(), &tr); + if ( tr.fAllSolid || tr.flFraction < 0.99 ) + { + if (tr.flFraction < 0.0) tr.flFraction = 0.0; + if (tr.flFraction > 1.0) tr.flFraction = 1.0; + if (tr.flFraction < frac) + { + frac = tr.flFraction; + bBumpedSomething = TRUE; + WallNormal = tr.vecPlaneNormal; + } + } + + if (bBumpedSomething && (m_hEnemy == NULL || tr.pHit != m_hEnemy->edict())) + { + Vector ProbeDir = Probe - pev->origin; + + Vector NormalToProbeAndWallNormal = CrossProduct(ProbeDir, WallNormal); + Vector SteeringVector = CrossProduct( NormalToProbeAndWallNormal, ProbeDir); + + float SteeringForce = m_flightSpeed * (1-frac) * (DotProduct(WallNormal.Normalize(), m_SaveVelocity.Normalize())); + if (SteeringForce < 0.0) + { + SteeringForce = -SteeringForce; + } + SteeringVector = SteeringForce * SteeringVector.Normalize(); + + return SteeringVector; + } + return Vector(0, 0, 0); +} + #endif \ No newline at end of file diff --git a/main/source/dlls/islave.cpp b/main/source/dlls/islave.cpp index a42ece21..22152fb3 100644 --- a/main/source/dlls/islave.cpp +++ b/main/source/dlls/islave.cpp @@ -1,866 +1,866 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Alien slave monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "squadmonster.h" -#include "schedule.h" -#include "effects.h" -#include "weapons.h" -#include "soundent.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ISLAVE_AE_CLAW ( 1 ) -#define ISLAVE_AE_CLAWRAKE ( 2 ) -#define ISLAVE_AE_ZAP_POWERUP ( 3 ) -#define ISLAVE_AE_ZAP_SHOOT ( 4 ) -#define ISLAVE_AE_ZAP_DONE ( 5 ) - -#define ISLAVE_MAX_BEAMS 8 - -class CISlave : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify ( void ); - int IRelationship( CBaseEntity *pTarget ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - void CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - - void DeathSound( void ); - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - - void StartTask ( Task_t *pTask ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - CUSTOM_SCHEDULES; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void ClearBeams( ); - void ArmBeam( int side ); - void WackBeam( int side, CBaseEntity *pEntity ); - void ZapBeam( int side ); - void BeamGlow( void ); - - int m_iBravery; - - CBeam *m_pBeam[ISLAVE_MAX_BEAMS]; - - int m_iBeams; - float m_flNextAttack; - - int m_voicePitch; - - EHANDLE m_hDead; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - static const char *pPainSounds[]; - static const char *pDeathSounds[]; -}; -LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ); -LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ); - - -TYPEDESCRIPTION CISlave::m_SaveData[] = -{ - DEFINE_FIELD( CISlave, m_iBravery, FIELD_INTEGER ), - - DEFINE_ARRAY( CISlave, m_pBeam, FIELD_CLASSPTR, ISLAVE_MAX_BEAMS ), - DEFINE_FIELD( CISlave, m_iBeams, FIELD_INTEGER ), - DEFINE_FIELD( CISlave, m_flNextAttack, FIELD_TIME ), - - DEFINE_FIELD( CISlave, m_voicePitch, FIELD_INTEGER ), - - DEFINE_FIELD( CISlave, m_hDead, FIELD_EHANDLE ), - -}; - -IMPLEMENT_SAVERESTORE( CISlave, CSquadMonster ); - - - - -const char *CISlave::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CISlave::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CISlave::pPainSounds[] = -{ - "aslave/slv_pain1.wav", - "aslave/slv_pain2.wav", -}; - -const char *CISlave::pDeathSounds[] = -{ - "aslave/slv_die1.wav", - "aslave/slv_die2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CISlave :: Classify ( void ) -{ - return CLASS_ALIEN_MILITARY; -} - - -int CISlave::IRelationship( CBaseEntity *pTarget ) -{ - if ( (pTarget->IsPlayer()) ) - if ( (pev->spawnflags & SF_MONSTER_WAIT_UNTIL_PROVOKED ) && ! (m_afMemory & bits_MEMORY_PROVOKED )) - return R_NO; - return CBaseMonster::IRelationship( pTarget ); -} - - -void CISlave :: CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) -{ - // ALERT( at_aiconsole, "help " ); - - // skip ones not on my netname - if ( FStringNull( pev->netname )) - return; - - CBaseEntity *pEntity = NULL; - - while ((pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ))) != NULL) - { - float d = (pev->origin - pEntity->pev->origin).Length(); - if (d < flDist) - { - CBaseMonster *pMonster = pEntity->MyMonsterPointer( ); - if (pMonster) - { - pMonster->m_afMemory |= bits_MEMORY_PROVOKED; - pMonster->PushEnemy( hEnemy, vecLocation ); - } - } - } -} - - -//========================================================= -// ALertSound - scream -//========================================================= -void CISlave :: AlertSound( void ) -{ - if ( m_hEnemy != NULL ) - { - SENTENCEG_PlayRndSz(ENT(pev), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch); - - CallForHelp( "monster_alien_slave", 512, m_hEnemy, m_vecEnemyLKP ); - } -} - -//========================================================= -// IdleSound -//========================================================= -void CISlave :: IdleSound( void ) -{ - if (RANDOM_LONG( 0, 2 ) == 0) - { - SENTENCEG_PlayRndSz(ENT(pev), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch); - } - -#if 0 - int side = RANDOM_LONG( 0, 1 ) * 2 - 1; - - ClearBeams( ); - ArmBeam( side ); - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + gpGlobals->v_right * 2 * side; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecSrc.x); // X - WRITE_COORD(vecSrc.y); // Y - WRITE_COORD(vecSrc.z); // Z - WRITE_BYTE( 8 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 96 ); // b - WRITE_BYTE( 10 ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 ); -#endif -} - -//========================================================= -// PainSound -//========================================================= -void CISlave :: PainSound( void ) -{ - if (RANDOM_LONG( 0, 2 ) == 0) - { - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } -} - -//========================================================= -// DieSound -//========================================================= - -void CISlave :: DeathSound( void ) -{ - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pDeathSounds[ RANDOM_LONG(0,ARRAYSIZE(pDeathSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); -} - - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CISlave :: ISoundMask ( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - - -void CISlave::Killed( entvars_t *pevAttacker, int iGib ) -{ - ClearBeams( ); - CSquadMonster::Killed( pevAttacker, iGib ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CISlave :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_WALK: - ys = 50; - break; - case ACT_RUN: - ys = 70; - break; - case ACT_IDLE: - ys = 50; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); - switch( pEvent->event ) - { - case ISLAVE_AE_CLAW: - { - // SOUND HERE! - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClaw, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - } - // Play a random attack hit sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - } - break; - - case ISLAVE_AE_CLAWRAKE: - { - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClawrake, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - } - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - else - { - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - } - break; - - case ISLAVE_AE_ZAP_POWERUP: - { - // speed up attack when on hard - if (g_iSkillLevel == SKILL_HARD) - pev->framerate = 1.5; - - UTIL_MakeAimVectors( pev->angles ); - - if (m_iBeams == 0) - { - Vector vecSrc = pev->origin + gpGlobals->v_forward * 2; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecSrc.x); // X - WRITE_COORD(vecSrc.y); // Y - WRITE_COORD(vecSrc.z); // Z - WRITE_BYTE( 12 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 96 ); // b - WRITE_BYTE( 20 / pev->framerate ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); - - } - if (m_hDead != NULL) - { - WackBeam( -1, m_hDead ); - WackBeam( 1, m_hDead ); - } - else - { - ArmBeam( -1 ); - ArmBeam( 1 ); - BeamGlow( ); - } - - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); - pev->skin = m_iBeams / 2; - } - break; - - case ISLAVE_AE_ZAP_SHOOT: - { - ClearBeams( ); - - if (m_hDead != NULL) - { - Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 ); - TraceResult trace; - UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace ); - - if ( !trace.fStartSolid ) - { - CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); - CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); - pNew->pev->spawnflags |= 1; - WackBeam( -1, pNew ); - WackBeam( 1, pNew ); - UTIL_Remove( m_hDead ); - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); - - /* - CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles ); - pEffect->Use( this, this, USE_ON, 1 ); - */ - break; - } - } - ClearMultiDamage(); - - UTIL_MakeAimVectors( pev->angles ); - - ZapBeam( -1 ); - ZapBeam( 1 ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); - // STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); - ApplyMultiDamage(pev, pev); - - m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); - } - break; - - case ISLAVE_AE_ZAP_DONE: - { - ClearBeams( ); - } - break; - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// CheckRangeAttack1 - normal beam attack -//========================================================= -BOOL CISlave :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if (m_flNextAttack > gpGlobals->time) - { - return FALSE; - } - - return CSquadMonster::CheckRangeAttack1( flDot, flDist ); -} - -//========================================================= -// CheckRangeAttack2 - check bravery and try to resurect dead comrades -//========================================================= -BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - return FALSE; - - if (m_flNextAttack > gpGlobals->time) - { - return FALSE; - } - - m_hDead = NULL; - m_iBravery = 0; - - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_slave" )) != NULL) - { - TraceResult tr; - - UTIL_TraceLine( EyePosition( ), pEntity->EyePosition( ), ignore_monsters, ENT(pev), &tr ); - if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict()) - { - if (pEntity->pev->deadflag == DEAD_DEAD) - { - float d = (pev->origin - pEntity->pev->origin).Length(); - if (d < flDist) - { - m_hDead = pEntity; - flDist = d; - } - m_iBravery--; - } - else - { - m_iBravery++; - } - } - } - if (m_hDead != NULL) - return TRUE; - else - return FALSE; -} - - -//========================================================= -// StartTask -//========================================================= -void CISlave :: StartTask ( Task_t *pTask ) -{ - ClearBeams( ); - - CSquadMonster :: StartTask ( pTask ); -} - - -//========================================================= -// Spawn -//========================================================= -void CISlave :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/islave.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.slaveHealth; - pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP; - - m_voicePitch = RANDOM_LONG( 85, 110 ); - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CISlave :: Precache() -{ - int i; - - PRECACHE_MODEL("models/islave.mdl"); - PRECACHE_MODEL("sprites/lgtning.spr"); - PRECACHE_SOUND("debris/zap1.wav"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("hassault/hw_shoot1.wav"); - PRECACHE_SOUND("zombie/zo_pain2.wav"); - PRECACHE_SOUND("headcrab/hc_headbite.wav"); - PRECACHE_SOUND("weapons/cbar_miss1.wav"); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ ) - PRECACHE_SOUND((char *)pDeathSounds[i]); - - UTIL_PrecacheOther( "test_effect" ); -} - - -//========================================================= -// TakeDamage - get provoked when injured -//========================================================= - -int CISlave :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) -{ - // don't slash one of your own - if ((bitsDamageType & DMG_SLASH) && pevAttacker && IRelationship( Instance(pevAttacker) ) < R_DL) - return 0; - - m_afMemory |= bits_MEMORY_PROVOKED; - return CSquadMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -void CISlave::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if (bitsDamageType & DMG_SHOCK) - return; - - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - - -// primary range attack -Task_t tlSlaveAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSlaveAttack1[] = -{ - { - tlSlaveAttack1, - ARRAYSIZE ( tlSlaveAttack1 ), - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND | - bits_COND_HEAVY_DAMAGE, - - bits_SOUND_DANGER, - "Slave Range Attack1" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CISlave ) -{ - slSlaveAttack1, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ); - - -//========================================================= -//========================================================= -Schedule_t *CISlave :: GetSchedule( void ) -{ - ClearBeams( ); - -/* - if (pev->spawnflags) - { - pev->spawnflags = 0; - return GetScheduleOfType( SCHED_RELOAD ); - } -*/ - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - if ( pSound->m_iType & bits_SOUND_COMBAT ) - m_afMemory |= bits_MEMORY_PROVOKED; - } - - switch (m_MonsterState) - { - case MONSTERSTATE_COMBAT: -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if (pev->health < 20 || m_iBravery < 0) - { - if (!HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) - { - m_failSchedule = SCHED_CHASE_ENEMY; - if (HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - // ALERT( at_console, "exposed\n"); - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } - } - break; - } - return CSquadMonster::GetSchedule( ); -} - - -Schedule_t *CISlave :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_FAIL: - if (HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) - { - return CSquadMonster :: GetScheduleOfType( SCHED_MELEE_ATTACK1 ); ; - } - break; - case SCHED_RANGE_ATTACK1: - return slSlaveAttack1; - case SCHED_RANGE_ATTACK2: - return slSlaveAttack1; - } - return CSquadMonster :: GetScheduleOfType( Type ); -} - - -//========================================================= -// ArmBeam - small beam from arm to nearby geometry -//========================================================= - -void CISlave :: ArmBeam( int side ) -{ - TraceResult tr; - float flDist = 1.0; - - if (m_iBeams >= ISLAVE_MAX_BEAMS) - return; - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + gpGlobals->v_up * 36 + gpGlobals->v_right * side * 16 + gpGlobals->v_forward * 32; - - for (int i = 0; i < 3; i++) - { - Vector vecAim = gpGlobals->v_right * side * RANDOM_FLOAT( 0, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 ); - TraceResult tr1; - UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1); - if (flDist > tr1.flFraction) - { - tr = tr1; - flDist = tr.flFraction; - } - } - - // Couldn't find anything close enough - if ( flDist == 1.0 ) - return; - - DecalGunshot( &tr, BULLET_PLAYER_CROWBAR ); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - // m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); - m_pBeam[m_iBeams]->SetBrightness( 64 ); - m_pBeam[m_iBeams]->SetNoise( 80 ); - m_iBeams++; -} - - -//========================================================= -// BeamGlow - brighten all beams -//========================================================= -void CISlave :: BeamGlow( ) -{ - int b = m_iBeams * 32; - if (b > 255) - b = 255; - - for (int i = 0; i < m_iBeams; i++) - { - if (m_pBeam[i]->GetBrightness() != 255) - { - m_pBeam[i]->SetBrightness( b ); - } - } -} - - -//========================================================= -// WackBeam - regenerate dead colleagues -//========================================================= -void CISlave :: WackBeam( int side, CBaseEntity *pEntity ) -{ - Vector vecDest; - float flDist = 1.0; - - if (m_iBeams >= ISLAVE_MAX_BEAMS) - return; - - if (pEntity == NULL) - return; - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex( ) ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 80 ); - m_iBeams++; -} - -//========================================================= -// ZapBeam - heavy damage directly forward -//========================================================= -void CISlave :: ZapBeam( int side ) -{ - Vector vecSrc, vecAim; - TraceResult tr; - CBaseEntity *pEntity; - - if (m_iBeams >= ISLAVE_MAX_BEAMS) - return; - - vecSrc = pev->origin + gpGlobals->v_up * 36; - vecAim = ShootAtEnemy( vecSrc ); - float deflection = 0.01; - vecAim = vecAim + side * gpGlobals->v_right * RANDOM_FLOAT( 0, deflection ) + gpGlobals->v_up * RANDOM_FLOAT( -deflection, deflection ); - UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 1024, dont_ignore_monsters, ENT( pev ), &tr); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 20 ); - m_iBeams++; - - pEntity = CBaseEntity::Instance(tr.pHit); - if (pEntity != NULL && pEntity->pev->takedamage) - { - pEntity->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK ); - } - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); -} - - -//========================================================= -// ClearBeams - remove all beams -//========================================================= -void CISlave :: ClearBeams( ) -{ - for (int i = 0; i < ISLAVE_MAX_BEAMS; i++) - { - if (m_pBeam[i]) - { - UTIL_Remove( m_pBeam[i] ); - m_pBeam[i] = NULL; - } - } - m_iBeams = 0; - pev->skin = 0; - - STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Alien slave monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "squadmonster.h" +#include "schedule.h" +#include "effects.h" +#include "weapons.h" +#include "soundent.h" + +extern DLL_GLOBAL int g_iSkillLevel; + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define ISLAVE_AE_CLAW ( 1 ) +#define ISLAVE_AE_CLAWRAKE ( 2 ) +#define ISLAVE_AE_ZAP_POWERUP ( 3 ) +#define ISLAVE_AE_ZAP_SHOOT ( 4 ) +#define ISLAVE_AE_ZAP_DONE ( 5 ) + +#define ISLAVE_MAX_BEAMS 8 + +class CISlave : public CSquadMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int ISoundMask( void ); + int Classify ( void ); + int IRelationship( CBaseEntity *pTarget ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + BOOL CheckRangeAttack1 ( float flDot, float flDist ); + BOOL CheckRangeAttack2 ( float flDot, float flDist ); + void CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + + void DeathSound( void ); + void PainSound( void ); + void AlertSound( void ); + void IdleSound( void ); + + void Killed( entvars_t *pevAttacker, int iGib ); + + void StartTask ( Task_t *pTask ); + Schedule_t *GetSchedule( void ); + Schedule_t *GetScheduleOfType ( int Type ); + CUSTOM_SCHEDULES; + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void ClearBeams( ); + void ArmBeam( int side ); + void WackBeam( int side, CBaseEntity *pEntity ); + void ZapBeam( int side ); + void BeamGlow( void ); + + int m_iBravery; + + CBeam *m_pBeam[ISLAVE_MAX_BEAMS]; + + int m_iBeams; + float m_flNextAttack; + + int m_voicePitch; + + EHANDLE m_hDead; + + static const char *pAttackHitSounds[]; + static const char *pAttackMissSounds[]; + static const char *pPainSounds[]; + static const char *pDeathSounds[]; +}; +LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ); +LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ); + + +TYPEDESCRIPTION CISlave::m_SaveData[] = +{ + DEFINE_FIELD( CISlave, m_iBravery, FIELD_INTEGER ), + + DEFINE_ARRAY( CISlave, m_pBeam, FIELD_CLASSPTR, ISLAVE_MAX_BEAMS ), + DEFINE_FIELD( CISlave, m_iBeams, FIELD_INTEGER ), + DEFINE_FIELD( CISlave, m_flNextAttack, FIELD_TIME ), + + DEFINE_FIELD( CISlave, m_voicePitch, FIELD_INTEGER ), + + DEFINE_FIELD( CISlave, m_hDead, FIELD_EHANDLE ), + +}; + +IMPLEMENT_SAVERESTORE( CISlave, CSquadMonster ); + + + + +const char *CISlave::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CISlave::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + +const char *CISlave::pPainSounds[] = +{ + "aslave/slv_pain1.wav", + "aslave/slv_pain2.wav", +}; + +const char *CISlave::pDeathSounds[] = +{ + "aslave/slv_die1.wav", + "aslave/slv_die2.wav", +}; + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CISlave :: Classify ( void ) +{ + return CLASS_ALIEN_MILITARY; +} + + +int CISlave::IRelationship( CBaseEntity *pTarget ) +{ + if ( (pTarget->IsPlayer()) ) + if ( (pev->spawnflags & SF_MONSTER_WAIT_UNTIL_PROVOKED ) && ! (m_afMemory & bits_MEMORY_PROVOKED )) + return R_NO; + return CBaseMonster::IRelationship( pTarget ); +} + + +void CISlave :: CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) +{ + // ALERT( at_aiconsole, "help " ); + + // skip ones not on my netname + if ( FStringNull( pev->netname )) + return; + + CBaseEntity *pEntity = NULL; + + while ((pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ))) != NULL) + { + float d = (pev->origin - pEntity->pev->origin).Length(); + if (d < flDist) + { + CBaseMonster *pMonster = pEntity->MyMonsterPointer( ); + if (pMonster) + { + pMonster->m_afMemory |= bits_MEMORY_PROVOKED; + pMonster->PushEnemy( hEnemy, vecLocation ); + } + } + } +} + + +//========================================================= +// ALertSound - scream +//========================================================= +void CISlave :: AlertSound( void ) +{ + if ( m_hEnemy != NULL ) + { + SENTENCEG_PlayRndSz(ENT(pev), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch); + + CallForHelp( "monster_alien_slave", 512, m_hEnemy, m_vecEnemyLKP ); + } +} + +//========================================================= +// IdleSound +//========================================================= +void CISlave :: IdleSound( void ) +{ + if (RANDOM_LONG( 0, 2 ) == 0) + { + SENTENCEG_PlayRndSz(ENT(pev), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch); + } + +#if 0 + int side = RANDOM_LONG( 0, 1 ) * 2 - 1; + + ClearBeams( ); + ArmBeam( side ); + + UTIL_MakeAimVectors( pev->angles ); + Vector vecSrc = pev->origin + gpGlobals->v_right * 2 * side; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); + WRITE_BYTE(TE_DLIGHT); + WRITE_COORD(vecSrc.x); // X + WRITE_COORD(vecSrc.y); // Y + WRITE_COORD(vecSrc.z); // Z + WRITE_BYTE( 8 ); // radius * 0.1 + WRITE_BYTE( 255 ); // r + WRITE_BYTE( 180 ); // g + WRITE_BYTE( 96 ); // b + WRITE_BYTE( 10 ); // time * 10 + WRITE_BYTE( 0 ); // decay * 0.1 + MESSAGE_END( ); + + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 ); +#endif +} + +//========================================================= +// PainSound +//========================================================= +void CISlave :: PainSound( void ) +{ + if (RANDOM_LONG( 0, 2 ) == 0) + { + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); + } +} + +//========================================================= +// DieSound +//========================================================= + +void CISlave :: DeathSound( void ) +{ + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pDeathSounds[ RANDOM_LONG(0,ARRAYSIZE(pDeathSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); +} + + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. +//========================================================= +int CISlave :: ISoundMask ( void) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_DANGER | + bits_SOUND_PLAYER; +} + + +void CISlave::Killed( entvars_t *pevAttacker, int iGib ) +{ + ClearBeams( ); + CSquadMonster::Killed( pevAttacker, iGib ); +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CISlave :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_WALK: + ys = 50; + break; + case ACT_RUN: + ys = 70; + break; + case ACT_IDLE: + ys = 50; + break; + default: + ys = 90; + break; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +// +// Returns number of events handled, 0 if none. +//========================================================= +void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); + switch( pEvent->event ) + { + case ISLAVE_AE_CLAW: + { + // SOUND HERE! + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClaw, DMG_SLASH ); + if ( pHurt ) + { + if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + { + pHurt->pev->punchangle.z = -18; + pHurt->pev->punchangle.x = 5; + } + // Play a random attack hit sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); + } + else + { + // Play a random attack miss sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); + } + } + break; + + case ISLAVE_AE_CLAWRAKE: + { + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClawrake, DMG_SLASH ); + if ( pHurt ) + { + if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + { + pHurt->pev->punchangle.z = -18; + pHurt->pev->punchangle.x = 5; + } + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); + } + else + { + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); + } + } + break; + + case ISLAVE_AE_ZAP_POWERUP: + { + // speed up attack when on hard + if (g_iSkillLevel == SKILL_HARD) + pev->framerate = 1.5; + + UTIL_MakeAimVectors( pev->angles ); + + if (m_iBeams == 0) + { + Vector vecSrc = pev->origin + gpGlobals->v_forward * 2; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); + WRITE_BYTE(TE_DLIGHT); + WRITE_COORD(vecSrc.x); // X + WRITE_COORD(vecSrc.y); // Y + WRITE_COORD(vecSrc.z); // Z + WRITE_BYTE( 12 ); // radius * 0.1 + WRITE_BYTE( 255 ); // r + WRITE_BYTE( 180 ); // g + WRITE_BYTE( 96 ); // b + WRITE_BYTE( 20 / pev->framerate ); // time * 10 + WRITE_BYTE( 0 ); // decay * 0.1 + MESSAGE_END( ); + + } + if (m_hDead != NULL) + { + WackBeam( -1, m_hDead ); + WackBeam( 1, m_hDead ); + } + else + { + ArmBeam( -1 ); + ArmBeam( 1 ); + BeamGlow( ); + } + + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); + pev->skin = m_iBeams / 2; + } + break; + + case ISLAVE_AE_ZAP_SHOOT: + { + ClearBeams( ); + + if (m_hDead != NULL) + { + Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 ); + TraceResult trace; + UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace ); + + if ( !trace.fStartSolid ) + { + CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); + CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); + pNew->pev->spawnflags |= 1; + WackBeam( -1, pNew ); + WackBeam( 1, pNew ); + UTIL_Remove( m_hDead ); + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); + + /* + CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles ); + pEffect->Use( this, this, USE_ON, 1 ); + */ + break; + } + } + ClearMultiDamage(); + + UTIL_MakeAimVectors( pev->angles ); + + ZapBeam( -1 ); + ZapBeam( 1 ); + + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); + // STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); + ApplyMultiDamage(pev, pev); + + m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); + } + break; + + case ISLAVE_AE_ZAP_DONE: + { + ClearBeams( ); + } + break; + + default: + CSquadMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// CheckRangeAttack1 - normal beam attack +//========================================================= +BOOL CISlave :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if (m_flNextAttack > gpGlobals->time) + { + return FALSE; + } + + return CSquadMonster::CheckRangeAttack1( flDot, flDist ); +} + +//========================================================= +// CheckRangeAttack2 - check bravery and try to resurect dead comrades +//========================================================= +BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) +{ + return FALSE; + + if (m_flNextAttack > gpGlobals->time) + { + return FALSE; + } + + m_hDead = NULL; + m_iBravery = 0; + + CBaseEntity *pEntity = NULL; + while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_slave" )) != NULL) + { + TraceResult tr; + + UTIL_TraceLine( EyePosition( ), pEntity->EyePosition( ), ignore_monsters, ENT(pev), &tr ); + if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict()) + { + if (pEntity->pev->deadflag == DEAD_DEAD) + { + float d = (pev->origin - pEntity->pev->origin).Length(); + if (d < flDist) + { + m_hDead = pEntity; + flDist = d; + } + m_iBravery--; + } + else + { + m_iBravery++; + } + } + } + if (m_hDead != NULL) + return TRUE; + else + return FALSE; +} + + +//========================================================= +// StartTask +//========================================================= +void CISlave :: StartTask ( Task_t *pTask ) +{ + ClearBeams( ); + + CSquadMonster :: StartTask ( pTask ); +} + + +//========================================================= +// Spawn +//========================================================= +void CISlave :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/islave.mdl"); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->effects = 0; + pev->health = gSkillData.slaveHealth; + pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin. + m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello + m_MonsterState = MONSTERSTATE_NONE; + m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP; + + m_voicePitch = RANDOM_LONG( 85, 110 ); + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CISlave :: Precache() +{ + int i; + + PRECACHE_MODEL("models/islave.mdl"); + PRECACHE_MODEL("sprites/lgtning.spr"); + PRECACHE_SOUND("debris/zap1.wav"); + PRECACHE_SOUND("debris/zap4.wav"); + PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_SOUND("hassault/hw_shoot1.wav"); + PRECACHE_SOUND("zombie/zo_pain2.wav"); + PRECACHE_SOUND("headcrab/hc_headbite.wav"); + PRECACHE_SOUND("weapons/cbar_miss1.wav"); + + for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackHitSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackMissSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) + PRECACHE_SOUND((char *)pPainSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ ) + PRECACHE_SOUND((char *)pDeathSounds[i]); + + UTIL_PrecacheOther( "test_effect" ); +} + + +//========================================================= +// TakeDamage - get provoked when injured +//========================================================= + +int CISlave :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +{ + // don't slash one of your own + if ((bitsDamageType & DMG_SLASH) && pevAttacker && IRelationship( Instance(pevAttacker) ) < R_DL) + return 0; + + m_afMemory |= bits_MEMORY_PROVOKED; + return CSquadMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); +} + + +void CISlave::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if (bitsDamageType & DMG_SHOCK) + return; + + CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); +} + + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + + + +// primary range attack +Task_t tlSlaveAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slSlaveAttack1[] = +{ + { + tlSlaveAttack1, + ARRAYSIZE ( tlSlaveAttack1 ), + bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_HEAR_SOUND | + bits_COND_HEAVY_DAMAGE, + + bits_SOUND_DANGER, + "Slave Range Attack1" + }, +}; + + +DEFINE_CUSTOM_SCHEDULES( CISlave ) +{ + slSlaveAttack1, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ); + + +//========================================================= +//========================================================= +Schedule_t *CISlave :: GetSchedule( void ) +{ + ClearBeams( ); + +/* + if (pev->spawnflags) + { + pev->spawnflags = 0; + return GetScheduleOfType( SCHED_RELOAD ); + } +*/ + + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + if ( pSound->m_iType & bits_SOUND_COMBAT ) + m_afMemory |= bits_MEMORY_PROVOKED; + } + + switch (m_MonsterState) + { + case MONSTERSTATE_COMBAT: +// dead enemy + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // call base class, all code to handle dead enemies is centralized there. + return CBaseMonster :: GetSchedule(); + } + + if (pev->health < 20 || m_iBravery < 0) + { + if (!HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) + { + m_failSchedule = SCHED_CHASE_ENEMY; + if (HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) + { + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); + } + if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) + { + // ALERT( at_console, "exposed\n"); + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); + } + } + } + break; + } + return CSquadMonster::GetSchedule( ); +} + + +Schedule_t *CISlave :: GetScheduleOfType ( int Type ) +{ + switch ( Type ) + { + case SCHED_FAIL: + if (HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) + { + return CSquadMonster :: GetScheduleOfType( SCHED_MELEE_ATTACK1 ); ; + } + break; + case SCHED_RANGE_ATTACK1: + return slSlaveAttack1; + case SCHED_RANGE_ATTACK2: + return slSlaveAttack1; + } + return CSquadMonster :: GetScheduleOfType( Type ); +} + + +//========================================================= +// ArmBeam - small beam from arm to nearby geometry +//========================================================= + +void CISlave :: ArmBeam( int side ) +{ + TraceResult tr; + float flDist = 1.0; + + if (m_iBeams >= ISLAVE_MAX_BEAMS) + return; + + UTIL_MakeAimVectors( pev->angles ); + Vector vecSrc = pev->origin + gpGlobals->v_up * 36 + gpGlobals->v_right * side * 16 + gpGlobals->v_forward * 32; + + for (int i = 0; i < 3; i++) + { + Vector vecAim = gpGlobals->v_right * side * RANDOM_FLOAT( 0, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 ); + TraceResult tr1; + UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1); + if (flDist > tr1.flFraction) + { + tr = tr1; + flDist = tr.flFraction; + } + } + + // Couldn't find anything close enough + if ( flDist == 1.0 ) + return; + + DecalGunshot( &tr, BULLET_PLAYER_CROWBAR ); + + m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); + if (!m_pBeam[m_iBeams]) + return; + + m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); + m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); + // m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); + m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); + m_pBeam[m_iBeams]->SetBrightness( 64 ); + m_pBeam[m_iBeams]->SetNoise( 80 ); + m_iBeams++; +} + + +//========================================================= +// BeamGlow - brighten all beams +//========================================================= +void CISlave :: BeamGlow( ) +{ + int b = m_iBeams * 32; + if (b > 255) + b = 255; + + for (int i = 0; i < m_iBeams; i++) + { + if (m_pBeam[i]->GetBrightness() != 255) + { + m_pBeam[i]->SetBrightness( b ); + } + } +} + + +//========================================================= +// WackBeam - regenerate dead colleagues +//========================================================= +void CISlave :: WackBeam( int side, CBaseEntity *pEntity ) +{ + Vector vecDest; + float flDist = 1.0; + + if (m_iBeams >= ISLAVE_MAX_BEAMS) + return; + + if (pEntity == NULL) + return; + + m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); + if (!m_pBeam[m_iBeams]) + return; + + m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex( ) ); + m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); + m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); + m_pBeam[m_iBeams]->SetBrightness( 255 ); + m_pBeam[m_iBeams]->SetNoise( 80 ); + m_iBeams++; +} + +//========================================================= +// ZapBeam - heavy damage directly forward +//========================================================= +void CISlave :: ZapBeam( int side ) +{ + Vector vecSrc, vecAim; + TraceResult tr; + CBaseEntity *pEntity; + + if (m_iBeams >= ISLAVE_MAX_BEAMS) + return; + + vecSrc = pev->origin + gpGlobals->v_up * 36; + vecAim = ShootAtEnemy( vecSrc ); + float deflection = 0.01; + vecAim = vecAim + side * gpGlobals->v_right * RANDOM_FLOAT( 0, deflection ) + gpGlobals->v_up * RANDOM_FLOAT( -deflection, deflection ); + UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 1024, dont_ignore_monsters, ENT( pev ), &tr); + + m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 ); + if (!m_pBeam[m_iBeams]) + return; + + m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); + m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); + m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); + m_pBeam[m_iBeams]->SetBrightness( 255 ); + m_pBeam[m_iBeams]->SetNoise( 20 ); + m_iBeams++; + + pEntity = CBaseEntity::Instance(tr.pHit); + if (pEntity != NULL && pEntity->pev->takedamage) + { + pEntity->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK ); + } + UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); +} + + +//========================================================= +// ClearBeams - remove all beams +//========================================================= +void CISlave :: ClearBeams( ) +{ + for (int i = 0; i < ISLAVE_MAX_BEAMS; i++) + { + if (m_pBeam[i]) + { + UTIL_Remove( m_pBeam[i] ); + m_pBeam[i] = NULL; + } + } + m_iBeams = 0; + pev->skin = 0; + + STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); +} diff --git a/main/source/dlls/items.cpp b/main/source/dlls/items.cpp index 1e891249..fa6594dc 100644 --- a/main/source/dlls/items.cpp +++ b/main/source/dlls/items.cpp @@ -1,337 +1,337 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== items.cpp ======================================================== - - functions governing the selection/use of weapons for players - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "player.h" -#include "skill.h" -#include "items.h" -#include "gamerules.h" - -#include "../mod/AvHNetworkMessages.h" - -class CWorldItem : public CBaseEntity -{ -public: - void KeyValue(KeyValueData *pkvd ); - void Spawn( void ); - int m_iType; -}; - -LINK_ENTITY_TO_CLASS(world_items, CWorldItem); - -void CWorldItem::KeyValue(KeyValueData *pkvd) -{ - if (FStrEq(pkvd->szKeyName, "type")) - { - m_iType = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -void CWorldItem::Spawn( void ) -{ - CBaseEntity *pEntity = NULL; - - switch (m_iType) - { - case 44: // ITEM_BATTERY: - pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); - break; - case 42: // ITEM_ANTIDOTE: - pEntity = CBaseEntity::Create( "item_antidote", pev->origin, pev->angles ); - break; - case 43: // ITEM_SECURITY: - pEntity = CBaseEntity::Create( "item_security", pev->origin, pev->angles ); - break; - case 45: // ITEM_SUIT: - pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles ); - break; - } - - if (!pEntity) - { - ALERT( at_console, "unable to create world_item %d\n", m_iType ); - } - else - { - pEntity->pev->target = pev->target; - pEntity->pev->targetname = pev->targetname; - pEntity->pev->spawnflags = pev->spawnflags; - } - - REMOVE_ENTITY(edict()); -} - - -void CItem::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch(&CItem::ItemTouch); - - if (DROP_TO_FLOOR(ENT(pev)) == 0) - { - ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z); - UTIL_Remove( this ); - return; - } -} - -extern int gEvilImpulse101; - -void CItem::ItemTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) - { - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // ok, a player is touching this item, but can he have it? - if ( !g_pGameRules->CanHaveItem( pPlayer, this ) ) - { - // no? Ignore the touch. - return; - } - - if (MyTouch( pPlayer )) - { - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - SetTouch( NULL ); - - // player grabbed the item. - g_pGameRules->PlayerGotItem( pPlayer, this ); - if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) - { - Respawn(); - } - else - { - UTIL_Remove( this ); - } - } - else if (gEvilImpulse101) - { - UTIL_Remove( this ); - } -} - -CBaseEntity* CItem::Respawn( void ) -{ - SetTouch( NULL ); - pev->effects |= EF_NODRAW; - - UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. - - SetThink ( &CItem::Materialize ); - pev->nextthink = g_pGameRules->FlItemRespawnTime( this ); - return this; -} - -void CItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - SetTouch( &CItem::ItemTouch ); -} - -#define SF_SUIT_SHORTLOGON 0x0001 - -class CItemSuit : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_suit.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_suit.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ( pPlayer->pev->weapons & (1<spawnflags & SF_SUIT_SHORTLOGON ) - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon, - else - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon - - pPlayer->pev->weapons |= (1<pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && - (pPlayer->pev->weapons & (1<pev->armorvalue += gSkillData.batteryCapacity; - pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, (float)MAX_NORMAL_BATTERY); - - EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - - NetMsg_ItemPickup( pPlayer->pev, string( STRING( pev->classname ) ) ); - - // Suit reports new power level - // For some reason this wasn't working in release build -- round it. - pct = (int)( (float)(pPlayer->pev->armorvalue * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5); - pct = (pct / 5); - if (pct > 0) - pct--; - - sprintf( szcharge,"!HEV_%1dP", pct ); - - //EMIT_SOUND_SUIT(ENT(pev), szcharge); - pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); - - -class CItemAntidote : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_antidote.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_antidote.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - pPlayer->SetSuitUpdate("!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN); - - pPlayer->m_rgItems[ITEM_ANTIDOTE] += 1; - return TRUE; - } -}; - -LINK_ENTITY_TO_CLASS(item_antidote, CItemAntidote); - - -class CItemSecurity : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_security.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_security.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - pPlayer->m_rgItems[ITEM_SECURITY] += 1; - return TRUE; - } -}; - -LINK_ENTITY_TO_CLASS(item_security, CItemSecurity); - -class CItemLongJump : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_longjump.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_longjump.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ( pPlayer->m_fLongJump ) - { - return FALSE; - } - - if ( ( pPlayer->pev->weapons & (1<m_fLongJump = TRUE;// player now has longjump module - - g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); - - NetMsg_ItemPickup( pPlayer->pev, string( STRING( pev->classname ) ) ); - - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound? - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== items.cpp ======================================================== + + functions governing the selection/use of weapons for players + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "weapons.h" +#include "player.h" +#include "skill.h" +#include "items.h" +#include "gamerules.h" + +#include "../mod/AvHNetworkMessages.h" + +class CWorldItem : public CBaseEntity +{ +public: + void KeyValue(KeyValueData *pkvd ); + void Spawn( void ); + int m_iType; +}; + +LINK_ENTITY_TO_CLASS(world_items, CWorldItem); + +void CWorldItem::KeyValue(KeyValueData *pkvd) +{ + if (FStrEq(pkvd->szKeyName, "type")) + { + m_iType = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +void CWorldItem::Spawn( void ) +{ + CBaseEntity *pEntity = NULL; + + switch (m_iType) + { + case 44: // ITEM_BATTERY: + pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); + break; + case 42: // ITEM_ANTIDOTE: + pEntity = CBaseEntity::Create( "item_antidote", pev->origin, pev->angles ); + break; + case 43: // ITEM_SECURITY: + pEntity = CBaseEntity::Create( "item_security", pev->origin, pev->angles ); + break; + case 45: // ITEM_SUIT: + pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles ); + break; + } + + if (!pEntity) + { + ALERT( at_console, "unable to create world_item %d\n", m_iType ); + } + else + { + pEntity->pev->target = pev->target; + pEntity->pev->targetname = pev->targetname; + pEntity->pev->spawnflags = pev->spawnflags; + } + + REMOVE_ENTITY(edict()); +} + + +void CItem::Spawn( void ) +{ + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + SetTouch(&CItem::ItemTouch); + + if (DROP_TO_FLOOR(ENT(pev)) == 0) + { + ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z); + UTIL_Remove( this ); + return; + } +} + +extern int gEvilImpulse101; + +void CItem::ItemTouch( CBaseEntity *pOther ) +{ + // if it's not a player, ignore + if ( !pOther->IsPlayer() ) + { + return; + } + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + + // ok, a player is touching this item, but can he have it? + if ( !g_pGameRules->CanHaveItem( pPlayer, this ) ) + { + // no? Ignore the touch. + return; + } + + if (MyTouch( pPlayer )) + { + SUB_UseTargets( pOther, USE_TOGGLE, 0 ); + SetTouch( NULL ); + + // player grabbed the item. + g_pGameRules->PlayerGotItem( pPlayer, this ); + if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) + { + Respawn(); + } + else + { + UTIL_Remove( this ); + } + } + else if (gEvilImpulse101) + { + UTIL_Remove( this ); + } +} + +CBaseEntity* CItem::Respawn( void ) +{ + SetTouch( NULL ); + pev->effects |= EF_NODRAW; + + UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. + + SetThink ( &CItem::Materialize ); + pev->nextthink = g_pGameRules->FlItemRespawnTime( this ); + return this; +} + +void CItem::Materialize( void ) +{ + if ( pev->effects & EF_NODRAW ) + { + // changing from invisible state to visible. + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); + pev->effects &= ~EF_NODRAW; + pev->effects |= EF_MUZZLEFLASH; + } + + SetTouch( &CItem::ItemTouch ); +} + +#define SF_SUIT_SHORTLOGON 0x0001 + +class CItemSuit : public CItem +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_suit.mdl"); + CItem::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_suit.mdl"); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + if ( pPlayer->pev->weapons & (1<spawnflags & SF_SUIT_SHORTLOGON ) + EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon, + else + EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon + + pPlayer->pev->weapons |= (1<pev->deadflag != DEAD_NO ) + { + return FALSE; + } + + if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && + (pPlayer->pev->weapons & (1<pev->armorvalue += gSkillData.batteryCapacity; + pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, (float)MAX_NORMAL_BATTERY); + + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + + NetMsg_ItemPickup( pPlayer->pev, string( STRING( pev->classname ) ) ); + + // Suit reports new power level + // For some reason this wasn't working in release build -- round it. + pct = (int)( (float)(pPlayer->pev->armorvalue * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5); + pct = (pct / 5); + if (pct > 0) + pct--; + + sprintf( szcharge,"!HEV_%1dP", pct ); + + //EMIT_SOUND_SUIT(ENT(pev), szcharge); + pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC); + return TRUE; + } + return FALSE; + } +}; + +LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); + + +class CItemAntidote : public CItem +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_antidote.mdl"); + CItem::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_antidote.mdl"); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + pPlayer->SetSuitUpdate("!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN); + + pPlayer->m_rgItems[ITEM_ANTIDOTE] += 1; + return TRUE; + } +}; + +LINK_ENTITY_TO_CLASS(item_antidote, CItemAntidote); + + +class CItemSecurity : public CItem +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_security.mdl"); + CItem::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_security.mdl"); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + pPlayer->m_rgItems[ITEM_SECURITY] += 1; + return TRUE; + } +}; + +LINK_ENTITY_TO_CLASS(item_security, CItemSecurity); + +class CItemLongJump : public CItem +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_longjump.mdl"); + CItem::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_longjump.mdl"); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + if ( pPlayer->m_fLongJump ) + { + return FALSE; + } + + if ( ( pPlayer->pev->weapons & (1<m_fLongJump = TRUE;// player now has longjump module + + g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); + + NetMsg_ItemPickup( pPlayer->pev, string( STRING( pev->classname ) ) ); + + EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound? + return TRUE; + } + return FALSE; + } +}; + +LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); diff --git a/main/source/dlls/items.cpp~ b/main/source/dlls/items.cpp~ deleted file mode 100644 index 3cfd375d..00000000 --- a/main/source/dlls/items.cpp~ +++ /dev/null @@ -1,337 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== items.cpp ======================================================== - - functions governing the selection/use of weapons for players - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "player.h" -#include "skill.h" -#include "items.h" -#include "gamerules.h" - -#include "..mod/AvHNetworkMessages.h" - -class CWorldItem : public CBaseEntity -{ -public: - void KeyValue(KeyValueData *pkvd ); - void Spawn( void ); - int m_iType; -}; - -LINK_ENTITY_TO_CLASS(world_items, CWorldItem); - -void CWorldItem::KeyValue(KeyValueData *pkvd) -{ - if (FStrEq(pkvd->szKeyName, "type")) - { - m_iType = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -void CWorldItem::Spawn( void ) -{ - CBaseEntity *pEntity = NULL; - - switch (m_iType) - { - case 44: // ITEM_BATTERY: - pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); - break; - case 42: // ITEM_ANTIDOTE: - pEntity = CBaseEntity::Create( "item_antidote", pev->origin, pev->angles ); - break; - case 43: // ITEM_SECURITY: - pEntity = CBaseEntity::Create( "item_security", pev->origin, pev->angles ); - break; - case 45: // ITEM_SUIT: - pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles ); - break; - } - - if (!pEntity) - { - ALERT( at_console, "unable to create world_item %d\n", m_iType ); - } - else - { - pEntity->pev->target = pev->target; - pEntity->pev->targetname = pev->targetname; - pEntity->pev->spawnflags = pev->spawnflags; - } - - REMOVE_ENTITY(edict()); -} - - -void CItem::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch(&CItem::ItemTouch); - - if (DROP_TO_FLOOR(ENT(pev)) == 0) - { - ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z); - UTIL_Remove( this ); - return; - } -} - -extern int gEvilImpulse101; - -void CItem::ItemTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) - { - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // ok, a player is touching this item, but can he have it? - if ( !g_pGameRules->CanHaveItem( pPlayer, this ) ) - { - // no? Ignore the touch. - return; - } - - if (MyTouch( pPlayer )) - { - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - SetTouch( NULL ); - - // player grabbed the item. - g_pGameRules->PlayerGotItem( pPlayer, this ); - if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) - { - Respawn(); - } - else - { - UTIL_Remove( this ); - } - } - else if (gEvilImpulse101) - { - UTIL_Remove( this ); - } -} - -CBaseEntity* CItem::Respawn( void ) -{ - SetTouch( NULL ); - pev->effects |= EF_NODRAW; - - UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. - - SetThink ( &CItem::Materialize ); - pev->nextthink = g_pGameRules->FlItemRespawnTime( this ); - return this; -} - -void CItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - SetTouch( &CItem::ItemTouch ); -} - -#define SF_SUIT_SHORTLOGON 0x0001 - -class CItemSuit : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_suit.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_suit.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ( pPlayer->pev->weapons & (1<spawnflags & SF_SUIT_SHORTLOGON ) - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon, - else - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon - - pPlayer->pev->weapons |= (1<pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && - (pPlayer->pev->weapons & (1<pev->armorvalue += gSkillData.batteryCapacity; - pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, (float)MAX_NORMAL_BATTERY); - - EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - - NetMsg_ItemPickup( pPlayer->pev, string( STRING( pev->classname ) ) ); - - // Suit reports new power level - // For some reason this wasn't working in release build -- round it. - pct = (int)( (float)(pPlayer->pev->armorvalue * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5); - pct = (pct / 5); - if (pct > 0) - pct--; - - sprintf( szcharge,"!HEV_%1dP", pct ); - - //EMIT_SOUND_SUIT(ENT(pev), szcharge); - pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); - - -class CItemAntidote : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_antidote.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_antidote.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - pPlayer->SetSuitUpdate("!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN); - - pPlayer->m_rgItems[ITEM_ANTIDOTE] += 1; - return TRUE; - } -}; - -LINK_ENTITY_TO_CLASS(item_antidote, CItemAntidote); - - -class CItemSecurity : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_security.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_security.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - pPlayer->m_rgItems[ITEM_SECURITY] += 1; - return TRUE; - } -}; - -LINK_ENTITY_TO_CLASS(item_security, CItemSecurity); - -class CItemLongJump : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_longjump.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_longjump.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ( pPlayer->m_fLongJump ) - { - return FALSE; - } - - if ( ( pPlayer->pev->weapons & (1<m_fLongJump = TRUE;// player now has longjump module - - g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); - - NetMsg_ItemPickup( pPlayer->pev, string( STRING( pev->classname ) ) ); - - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound? - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); diff --git a/main/source/dlls/items.h b/main/source/dlls/items.h index d4c00e8b..4f883697 100644 --- a/main/source/dlls/items.h +++ b/main/source/dlls/items.h @@ -1,29 +1,29 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ITEMS_H -#define ITEMS_H - - -class CItem : public CBaseEntity -{ -public: - void Spawn( void ); - CBaseEntity* Respawn( void ); - void EXPORT ItemTouch( CBaseEntity *pOther ); - void EXPORT Materialize( void ); - virtual BOOL MyTouch( CBasePlayer *pPlayer ) { return FALSE; }; -}; - -#endif // ITEMS_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ITEMS_H +#define ITEMS_H + + +class CItem : public CBaseEntity +{ +public: + void Spawn( void ); + CBaseEntity* Respawn( void ); + void EXPORT ItemTouch( CBaseEntity *pOther ); + void EXPORT Materialize( void ); + virtual BOOL MyTouch( CBasePlayer *pPlayer ) { return FALSE; }; +}; + +#endif // ITEMS_H diff --git a/main/source/dlls/leech.cpp b/main/source/dlls/leech.cpp index ff465ba0..4bac91f6 100644 --- a/main/source/dlls/leech.cpp +++ b/main/source/dlls/leech.cpp @@ -1,723 +1,723 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// leech - basic little swimming monster -//========================================================= -// -// UNDONE: -// DONE:Steering force model for attack -// DONE:Attack animation control / damage -// DONE:Establish range of up/down motion and steer around vertical obstacles -// DONE:Re-evaluate height periodically -// DONE:Fall (MOVETYPE_TOSS) and play different anim if out of water -// Test in complex room (c2a3?) -// DONE:Sounds? - Kelly will fix -// Blood cloud? Hurt effect? -// Group behavior? -// DONE:Save/restore -// Flop animation - just bind to ACT_TWITCH -// Fix fatal push into wall case -// -// Try this on a bird -// Try this on a model with hulls/tracehull? -// - - -#include "float.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" - - - - -// Animation events -#define LEECH_AE_ATTACK 1 -#define LEECH_AE_FLOP 2 - - -// Movement constants - -#define LEECH_ACCELERATE 10 -#define LEECH_CHECK_DIST 45 -#define LEECH_SWIM_SPEED 50 -#define LEECH_SWIM_ACCEL 80 -#define LEECH_SWIM_DECEL 10 -#define LEECH_TURN_RATE 90 -#define LEECH_SIZEX 10 -#define LEECH_FRAMETIME 0.1 - - - -#define DEBUG_BEAMS 0 - -#if DEBUG_BEAMS -#include "effects.h" -#endif - - -class CLeech : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SwimThink( void ); - void EXPORT DeadThink( void ); - void Touch( CBaseEntity *pOther ) - { - if ( pOther->IsPlayer() ) - { - // If the client is pushing me, give me some base velocity - if ( gpGlobals->trace_ent && gpGlobals->trace_ent == edict() ) - { - pev->basevelocity = pOther->pev->velocity; - pev->flags |= FL_BASEVELOCITY; - } - } - } - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector(-8,-8,0); - pev->absmax = pev->origin + Vector(8,8,2); - } - - void AttackSound( void ); - void AlertSound( void ); - void UpdateMotion( void ); - float ObstacleDistance( CBaseEntity *pTarget ); - void MakeVectors( void ); - void RecalculateWaterlevel( void ); - void SwitchLeechState( void ); - - // Base entity functions - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - void Activate( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - int Classify( void ) { return CLASS_INSECT; } - int IRelationship( CBaseEntity *pTarget ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackSounds[]; - static const char *pAlertSounds[]; - -private: - // UNDONE: Remove unused boid vars, do group behavior - float m_flTurning;// is this boid turning? - BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead - float m_flAccelerate; - float m_obstacle; - float m_top; - float m_bottom; - float m_height; - float m_waterTime; - float m_sideTime; // Timer to randomly check clearance on sides - float m_zTime; - float m_stateTime; - float m_attackSoundTime; - -#if DEBUG_BEAMS - CBeam *m_pb; - CBeam *m_pt; -#endif -}; - - - -LINK_ENTITY_TO_CLASS( monster_leech, CLeech ); - -TYPEDESCRIPTION CLeech::m_SaveData[] = -{ - DEFINE_FIELD( CLeech, m_flTurning, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_fPathBlocked, FIELD_BOOLEAN ), - DEFINE_FIELD( CLeech, m_flAccelerate, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_obstacle, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_top, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_bottom, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_waterTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_sideTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_zTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_stateTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_attackSoundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CLeech, CBaseMonster ); - - -const char *CLeech::pAttackSounds[] = -{ - "leech/leech_bite1.wav", - "leech/leech_bite2.wav", - "leech/leech_bite3.wav", -}; - -const char *CLeech::pAlertSounds[] = -{ - "leech/leech_alert1.wav", - "leech/leech_alert2.wav", -}; - - -void CLeech::Spawn( void ) -{ - Precache(); - SET_MODEL(ENT(pev), "models/leech.mdl"); - // Just for fun - // SET_MODEL(ENT(pev), "models/icky.mdl"); - -// UTIL_SetSize( pev, g_vecZero, g_vecZero ); - UTIL_SetSize( pev, Vector(-1,-1,0), Vector(1,1,2)); - // Don't push the minz down too much or the water check will fail because this entity is really point-sized - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - SetBits(pev->flags, FL_SWIM); - pev->health = gSkillData.leechHealth; - - m_flFieldOfView = -0.5; // 180 degree FOV - m_flDistLook = 750; - MonsterInit(); - SetThink( &CLeech::SwimThink ); - SetUse( NULL ); - SetTouch( NULL ); - pev->view_ofs = g_vecZero; - - m_flTurning = 0; - m_fPathBlocked = FALSE; - SetActivity( ACT_SWIM ); - SetState( MONSTERSTATE_IDLE ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 1, 5 ); -} - - -void CLeech::Activate( void ) -{ - RecalculateWaterlevel(); -} - - - -void CLeech::RecalculateWaterlevel( void ) -{ - // Calculate boundaries - Vector vecTest = pev->origin - Vector(0,0,400); - - TraceResult tr; - - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if ( tr.flFraction != 1.0 ) - m_bottom = tr.vecEndPos.z + 1; - else - m_bottom = vecTest.z; - - m_top = UTIL_WaterLevel( pev->origin, pev->origin.z, pev->origin.z + 400 ) - 1; - - // Chop off 20% of the outside range - float newBottom = m_bottom * 0.8 + m_top * 0.2; - m_top = m_bottom * 0.2 + m_top * 0.8; - m_bottom = newBottom; - m_height = RANDOM_FLOAT( m_bottom, m_top ); - m_waterTime = gpGlobals->time + RANDOM_FLOAT( 5, 7 ); -} - - -void CLeech::SwitchLeechState( void ) -{ - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - m_hEnemy = NULL; - SetState( MONSTERSTATE_IDLE ); - // We may be up against the player, so redo the side checks - m_sideTime = 0; - } - else - { - Look( m_flDistLook ); - CBaseEntity *pEnemy = BestVisibleEnemy(); - if ( pEnemy && pEnemy->pev->waterlevel != 0 ) - { - m_hEnemy = pEnemy; - SetState( MONSTERSTATE_COMBAT ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 18, 25 ); - AlertSound(); - } - } -} - - -int CLeech::IRelationship( CBaseEntity *pTarget ) -{ - if ( pTarget->IsPlayer() ) - return R_DL; - return CBaseMonster::IRelationship( pTarget ); -} - - - -void CLeech::AttackSound( void ) -{ - if ( gpGlobals->time > m_attackSoundTime ) - { - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - m_attackSoundTime = gpGlobals->time + 0.5; - } -} - - -void CLeech::AlertSound( void ) -{ - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM * 0.5, 0, PITCH_NORM ); -} - - -void CLeech::Precache( void ) -{ - int i; - - //PRECACHE_MODEL("models/icky.mdl"); - PRECACHE_MODEL("models/leech.mdl"); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); -} - - -int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->velocity = g_vecZero; - - // Nudge the leech away from the damage - if ( pevInflictor ) - { - pev->velocity = (pev->origin - pevInflictor->origin).Normalize() * 25; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - -void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case LEECH_AE_ATTACK: - AttackSound(); - CBaseEntity *pEnemy; - - pEnemy = m_hEnemy; - if ( pEnemy != NULL ) - { - Vector dir, face; - - UTIL_MakeVectorsPrivate( pev->angles, face, NULL, NULL ); - face.z = 0; - dir = (pEnemy->pev->origin - pev->origin); - dir.z = 0; - dir = dir.Normalize(); - face = face.Normalize(); - - - if ( DotProduct(dir, face) > 0.9 ) // Only take damage if the leech is facing the prey - pEnemy->TakeDamage( pev, pev, gSkillData.leechDmgBite, DMG_SLASH ); - } - m_stateTime -= 2; - break; - - case LEECH_AE_FLOP: - // Play flop sound - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - - -void CLeech::MakeVectors( void ) -{ - Vector tmp = pev->angles; - tmp.x = -tmp.x; - UTIL_MakeVectors ( tmp ); -} - - -// -// ObstacleDistance - returns normalized distance to obstacle -// -float CLeech::ObstacleDistance( CBaseEntity *pTarget ) -{ - TraceResult tr; - Vector vecTest; - - // use VELOCITY, not angles, not all boids point the direction they are flying - //Vector vecDir = UTIL_VecToAngles( pev->velocity ); - MakeVectors(); - - // check for obstacle ahead - vecTest = pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - - if ( tr.fStartSolid ) - { - pev->speed = -LEECH_SWIM_SPEED * 0.5; -// ALERT( at_console, "Stuck from (%f %f %f) to (%f %f %f)\n", pev->oldorigin.x, pev->oldorigin.y, pev->oldorigin.z, pev->origin.x, pev->origin.y, pev->origin.z ); -// UTIL_SetOrigin( pev, pev->oldorigin ); - } - - if ( tr.flFraction != 1.0 ) - { - if ( (pTarget == NULL || tr.pHit != pTarget->edict()) ) - { - return tr.flFraction; - } - else - { - if ( fabs(m_height - pev->origin.z) > 10 ) - return tr.flFraction; - } - } - - if ( m_sideTime < gpGlobals->time ) - { - // extra wide checks - vecTest = pev->origin + gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if (tr.flFraction != 1.0) - return tr.flFraction; - - vecTest = pev->origin - gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if (tr.flFraction != 1.0) - return tr.flFraction; - - // Didn't hit either side, so stop testing for another 0.5 - 1 seconds - m_sideTime = gpGlobals->time + RANDOM_FLOAT(0.5,1); - } - return 1.0; -} - - -void CLeech::DeadThink( void ) -{ - if ( m_fSequenceFinished ) - { - if ( m_Activity == ACT_DIEFORWARD ) - { - SetThink( NULL ); - StopAnimation(); - return; - } - else if ( pev->flags & FL_ONGROUND ) - { - pev->solid = SOLID_NOT; - SetActivity(ACT_DIEFORWARD); - } - } - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - // Apply damage velocity, but keep out of the walls - if ( pev->velocity.x != 0 || pev->velocity.y != 0 ) - { - TraceResult tr; - - // Look 0.5 seconds ahead - UTIL_TraceLine(pev->origin, pev->origin + pev->velocity * 0.5, missile, edict(), &tr); - if (tr.flFraction != 1.0) - { - pev->velocity.x = 0; - pev->velocity.y = 0; - } - } -} - - - -void CLeech::UpdateMotion( void ) -{ - float flapspeed = (pev->speed - m_flAccelerate) / LEECH_ACCELERATE; - m_flAccelerate = m_flAccelerate * 0.8 + pev->speed * 0.2; - - if (flapspeed < 0) - flapspeed = -flapspeed; - flapspeed += 1.0; - if (flapspeed < 0.5) - flapspeed = 0.5; - if (flapspeed > 1.9) - flapspeed = 1.9; - - pev->framerate = flapspeed; - - if ( !m_fPathBlocked ) - pev->avelocity.y = pev->ideal_yaw; - else - pev->avelocity.y = pev->ideal_yaw * m_obstacle; - - if ( pev->avelocity.y > 150 ) - m_IdealActivity = ACT_TURN_LEFT; - else if ( pev->avelocity.y < -150 ) - m_IdealActivity = ACT_TURN_RIGHT; - else - m_IdealActivity = ACT_SWIM; - - // lean - float targetPitch, delta; - delta = m_height - pev->origin.z; - - if ( delta < -10 ) - targetPitch = -30; - else if ( delta > 10 ) - targetPitch = 30; - else - targetPitch = 0; - - pev->angles.x = UTIL_Approach( targetPitch, pev->angles.x, 60 * LEECH_FRAMETIME ); - - // bank - pev->avelocity.z = - (pev->angles.z + (pev->avelocity.y * 0.25)); - - if ( m_MonsterState == MONSTERSTATE_COMBAT && HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - m_IdealActivity = ACT_MELEE_ATTACK1; - - // Out of water check - if ( !pev->waterlevel ) - { - pev->movetype = MOVETYPE_TOSS; - m_IdealActivity = ACT_TWITCH; - pev->velocity = g_vecZero; - - // Animation will intersect the floor if either of these is non-zero - pev->angles.z = 0; - pev->angles.x = 0; - - if ( pev->framerate < 1.0 ) - pev->framerate = 1.0; - } - else if ( pev->movetype == MOVETYPE_TOSS ) - { - pev->movetype = MOVETYPE_FLY; - pev->flags &= ~FL_ONGROUND; - RecalculateWaterlevel(); - m_waterTime = gpGlobals->time + 2; // Recalc again soon, water may be rising - } - - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - float flInterval = StudioFrameAdvance(); - DispatchAnimEvents ( flInterval ); - -#if DEBUG_BEAMS - if ( !m_pb ) - m_pb = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - if ( !m_pt ) - m_pt = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - m_pb->PointsInit( pev->origin, pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST ); - m_pt->PointsInit( pev->origin, pev->origin - gpGlobals->v_right * (pev->avelocity.y*0.25) ); - if ( m_fPathBlocked ) - { - float color = m_obstacle * 30; - if ( m_obstacle == 1.0 ) - color = 0; - if ( color > 255 ) - color = 255; - m_pb->SetColor( 255, (int)color, (int)color ); - } - else - m_pb->SetColor( 255, 255, 0 ); - m_pt->SetColor( 0, 0, 255 ); -#endif -} - - -void CLeech::SwimThink( void ) -{ - TraceResult tr; - float flLeftSide; - float flRightSide; - float targetSpeed; - float targetYaw = 0; - CBaseEntity *pTarget; - - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); - pev->velocity = g_vecZero; - return; - } - else - pev->nextthink = gpGlobals->time + 0.1; - - targetSpeed = LEECH_SWIM_SPEED; - - if ( m_waterTime < gpGlobals->time ) - RecalculateWaterlevel(); - - if ( m_stateTime < gpGlobals->time ) - SwitchLeechState(); - - ClearConditions( bits_COND_CAN_MELEE_ATTACK1 ); - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - pTarget = m_hEnemy; - if ( !pTarget ) - SwitchLeechState(); - else - { - // Chase the enemy's eyes - m_height = pTarget->pev->origin.z + pTarget->pev->view_ofs.z - 5; - // Clip to viable water area - if ( m_height < m_bottom ) - m_height = m_bottom; - else if ( m_height > m_top ) - m_height = m_top; - Vector location = pTarget->pev->origin - pev->origin; - location.z += (pTarget->pev->view_ofs.z); - if ( location.Length() < 40 ) - SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); - // Turn towards target ent - targetYaw = UTIL_VecToYaw( location ); - - targetYaw = UTIL_AngleDiff( targetYaw, UTIL_AngleMod( pev->angles.y ) ); - - if ( targetYaw < (-LEECH_TURN_RATE*0.75) ) - targetYaw = (-LEECH_TURN_RATE*0.75); - else if ( targetYaw > (LEECH_TURN_RATE*0.75) ) - targetYaw = (LEECH_TURN_RATE*0.75); - else - targetSpeed *= 2; - } - - break; - - default: - if ( m_zTime < gpGlobals->time ) - { - float newHeight = RANDOM_FLOAT( m_bottom, m_top ); - m_height = 0.5 * m_height + 0.5 * newHeight; - m_zTime = gpGlobals->time + RANDOM_FLOAT( 1, 4 ); - } - if ( RANDOM_LONG( 0, 100 ) < 10 ) - targetYaw = RANDOM_LONG( -30, 30 ); - pTarget = NULL; - // oldorigin test - if ( (pev->origin - pev->oldorigin).Length() < 1 ) - { - // If leech didn't move, there must be something blocking it, so try to turn - m_sideTime = 0; - } - - break; - } - - m_obstacle = ObstacleDistance( pTarget ); - pev->oldorigin = pev->origin; - if ( m_obstacle < 0.1 ) - m_obstacle = 0.1; - - // is the way ahead clear? - if ( m_obstacle == 1.0 ) - { - // if the leech is turning, stop the trend. - if ( m_flTurning != 0 ) - { - m_flTurning = 0; - } - - m_fPathBlocked = FALSE; - pev->speed = UTIL_Approach( targetSpeed, pev->speed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME ); - pev->velocity = gpGlobals->v_forward * pev->speed; - - } - else - { - m_obstacle = 1.0 / m_obstacle; - // IF we get this far in the function, the leader's path is blocked! - m_fPathBlocked = TRUE; - - if ( m_flTurning == 0 )// something in the way and leech is not already turning to avoid - { - Vector vecTest; - // measure clearance on left and right to pick the best dir to turn - vecTest = pev->origin + (gpGlobals->v_right * LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - flRightSide = tr.flFraction; - - vecTest = pev->origin + (gpGlobals->v_right * -LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - flLeftSide = tr.flFraction; - - // turn left, right or random depending on clearance ratio - float delta = (flRightSide - flLeftSide); - if ( delta > 0.1 || (delta > -0.1 && RANDOM_LONG(0,100)<50) ) - m_flTurning = -LEECH_TURN_RATE; - else - m_flTurning = LEECH_TURN_RATE; - } - pev->speed = UTIL_Approach( -(LEECH_SWIM_SPEED*0.5), pev->speed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle ); - pev->velocity = gpGlobals->v_forward * pev->speed; - } - pev->ideal_yaw = m_flTurning + targetYaw; - UpdateMotion(); -} - - -void CLeech::Killed(entvars_t *pevAttacker, int iGib) -{ - Vector vecSplatDir; - TraceResult tr; - - //ALERT(at_aiconsole, "Leech: killed\n"); - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if (pOwner) - pOwner->DeathNotice(pev); - - // When we hit the ground, play the "death_end" activity - if ( pev->waterlevel ) - { - pev->angles.z = 0; - pev->angles.x = 0; - pev->origin.z += 1; - pev->avelocity = g_vecZero; - if ( RANDOM_LONG( 0, 99 ) < 70 ) - pev->avelocity.y = RANDOM_LONG( -720, 720 ); - - pev->gravity = 0.02; - ClearBits(pev->flags, FL_ONGROUND); - SetActivity( ACT_DIESIMPLE ); - } - else - SetActivity( ACT_DIEFORWARD ); - - pev->movetype = MOVETYPE_TOSS; - pev->takedamage = DAMAGE_NO; - SetThink( &CLeech::DeadThink ); -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// leech - basic little swimming monster +//========================================================= +// +// UNDONE: +// DONE:Steering force model for attack +// DONE:Attack animation control / damage +// DONE:Establish range of up/down motion and steer around vertical obstacles +// DONE:Re-evaluate height periodically +// DONE:Fall (MOVETYPE_TOSS) and play different anim if out of water +// Test in complex room (c2a3?) +// DONE:Sounds? - Kelly will fix +// Blood cloud? Hurt effect? +// Group behavior? +// DONE:Save/restore +// Flop animation - just bind to ACT_TWITCH +// Fix fatal push into wall case +// +// Try this on a bird +// Try this on a model with hulls/tracehull? +// + + +#include "float.h" +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" + + + + +// Animation events +#define LEECH_AE_ATTACK 1 +#define LEECH_AE_FLOP 2 + + +// Movement constants + +#define LEECH_ACCELERATE 10 +#define LEECH_CHECK_DIST 45 +#define LEECH_SWIM_SPEED 50 +#define LEECH_SWIM_ACCEL 80 +#define LEECH_SWIM_DECEL 10 +#define LEECH_TURN_RATE 90 +#define LEECH_SIZEX 10 +#define LEECH_FRAMETIME 0.1 + + + +#define DEBUG_BEAMS 0 + +#if DEBUG_BEAMS +#include "effects.h" +#endif + + +class CLeech : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + + void EXPORT SwimThink( void ); + void EXPORT DeadThink( void ); + void Touch( CBaseEntity *pOther ) + { + if ( pOther->IsPlayer() ) + { + // If the client is pushing me, give me some base velocity + if ( gpGlobals->trace_ent && gpGlobals->trace_ent == edict() ) + { + pev->basevelocity = pOther->pev->velocity; + pev->flags |= FL_BASEVELOCITY; + } + } + } + + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector(-8,-8,0); + pev->absmax = pev->origin + Vector(8,8,2); + } + + void AttackSound( void ); + void AlertSound( void ); + void UpdateMotion( void ); + float ObstacleDistance( CBaseEntity *pTarget ); + void MakeVectors( void ); + void RecalculateWaterlevel( void ); + void SwitchLeechState( void ); + + // Base entity functions + void HandleAnimEvent( MonsterEvent_t *pEvent ); + int BloodColor( void ) { return DONT_BLEED; } + void Killed( entvars_t *pevAttacker, int iGib ); + void Activate( void ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + int Classify( void ) { return CLASS_INSECT; } + int IRelationship( CBaseEntity *pTarget ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + static const char *pAttackSounds[]; + static const char *pAlertSounds[]; + +private: + // UNDONE: Remove unused boid vars, do group behavior + float m_flTurning;// is this boid turning? + BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead + float m_flAccelerate; + float m_obstacle; + float m_top; + float m_bottom; + float m_height; + float m_waterTime; + float m_sideTime; // Timer to randomly check clearance on sides + float m_zTime; + float m_stateTime; + float m_attackSoundTime; + +#if DEBUG_BEAMS + CBeam *m_pb; + CBeam *m_pt; +#endif +}; + + + +LINK_ENTITY_TO_CLASS( monster_leech, CLeech ); + +TYPEDESCRIPTION CLeech::m_SaveData[] = +{ + DEFINE_FIELD( CLeech, m_flTurning, FIELD_FLOAT ), + DEFINE_FIELD( CLeech, m_fPathBlocked, FIELD_BOOLEAN ), + DEFINE_FIELD( CLeech, m_flAccelerate, FIELD_FLOAT ), + DEFINE_FIELD( CLeech, m_obstacle, FIELD_FLOAT ), + DEFINE_FIELD( CLeech, m_top, FIELD_FLOAT ), + DEFINE_FIELD( CLeech, m_bottom, FIELD_FLOAT ), + DEFINE_FIELD( CLeech, m_height, FIELD_FLOAT ), + DEFINE_FIELD( CLeech, m_waterTime, FIELD_TIME ), + DEFINE_FIELD( CLeech, m_sideTime, FIELD_TIME ), + DEFINE_FIELD( CLeech, m_zTime, FIELD_TIME ), + DEFINE_FIELD( CLeech, m_stateTime, FIELD_TIME ), + DEFINE_FIELD( CLeech, m_attackSoundTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CLeech, CBaseMonster ); + + +const char *CLeech::pAttackSounds[] = +{ + "leech/leech_bite1.wav", + "leech/leech_bite2.wav", + "leech/leech_bite3.wav", +}; + +const char *CLeech::pAlertSounds[] = +{ + "leech/leech_alert1.wav", + "leech/leech_alert2.wav", +}; + + +void CLeech::Spawn( void ) +{ + Precache(); + SET_MODEL(ENT(pev), "models/leech.mdl"); + // Just for fun + // SET_MODEL(ENT(pev), "models/icky.mdl"); + +// UTIL_SetSize( pev, g_vecZero, g_vecZero ); + UTIL_SetSize( pev, Vector(-1,-1,0), Vector(1,1,2)); + // Don't push the minz down too much or the water check will fail because this entity is really point-sized + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_FLY; + SetBits(pev->flags, FL_SWIM); + pev->health = gSkillData.leechHealth; + + m_flFieldOfView = -0.5; // 180 degree FOV + m_flDistLook = 750; + MonsterInit(); + SetThink( &CLeech::SwimThink ); + SetUse( NULL ); + SetTouch( NULL ); + pev->view_ofs = g_vecZero; + + m_flTurning = 0; + m_fPathBlocked = FALSE; + SetActivity( ACT_SWIM ); + SetState( MONSTERSTATE_IDLE ); + m_stateTime = gpGlobals->time + RANDOM_FLOAT( 1, 5 ); +} + + +void CLeech::Activate( void ) +{ + RecalculateWaterlevel(); +} + + + +void CLeech::RecalculateWaterlevel( void ) +{ + // Calculate boundaries + Vector vecTest = pev->origin - Vector(0,0,400); + + TraceResult tr; + + UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + if ( tr.flFraction != 1.0 ) + m_bottom = tr.vecEndPos.z + 1; + else + m_bottom = vecTest.z; + + m_top = UTIL_WaterLevel( pev->origin, pev->origin.z, pev->origin.z + 400 ) - 1; + + // Chop off 20% of the outside range + float newBottom = m_bottom * 0.8 + m_top * 0.2; + m_top = m_bottom * 0.2 + m_top * 0.8; + m_bottom = newBottom; + m_height = RANDOM_FLOAT( m_bottom, m_top ); + m_waterTime = gpGlobals->time + RANDOM_FLOAT( 5, 7 ); +} + + +void CLeech::SwitchLeechState( void ) +{ + m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); + if ( m_MonsterState == MONSTERSTATE_COMBAT ) + { + m_hEnemy = NULL; + SetState( MONSTERSTATE_IDLE ); + // We may be up against the player, so redo the side checks + m_sideTime = 0; + } + else + { + Look( m_flDistLook ); + CBaseEntity *pEnemy = BestVisibleEnemy(); + if ( pEnemy && pEnemy->pev->waterlevel != 0 ) + { + m_hEnemy = pEnemy; + SetState( MONSTERSTATE_COMBAT ); + m_stateTime = gpGlobals->time + RANDOM_FLOAT( 18, 25 ); + AlertSound(); + } + } +} + + +int CLeech::IRelationship( CBaseEntity *pTarget ) +{ + if ( pTarget->IsPlayer() ) + return R_DL; + return CBaseMonster::IRelationship( pTarget ); +} + + + +void CLeech::AttackSound( void ) +{ + if ( gpGlobals->time > m_attackSoundTime ) + { + EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM ); + m_attackSoundTime = gpGlobals->time + 0.5; + } +} + + +void CLeech::AlertSound( void ) +{ + EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM * 0.5, 0, PITCH_NORM ); +} + + +void CLeech::Precache( void ) +{ + int i; + + //PRECACHE_MODEL("models/icky.mdl"); + PRECACHE_MODEL("models/leech.mdl"); + + for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackSounds[i]); + for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) + PRECACHE_SOUND((char *)pAlertSounds[i]); +} + + +int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + pev->velocity = g_vecZero; + + // Nudge the leech away from the damage + if ( pevInflictor ) + { + pev->velocity = (pev->origin - pevInflictor->origin).Normalize() * 25; + } + + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + + +void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case LEECH_AE_ATTACK: + AttackSound(); + CBaseEntity *pEnemy; + + pEnemy = m_hEnemy; + if ( pEnemy != NULL ) + { + Vector dir, face; + + UTIL_MakeVectorsPrivate( pev->angles, face, NULL, NULL ); + face.z = 0; + dir = (pEnemy->pev->origin - pev->origin); + dir.z = 0; + dir = dir.Normalize(); + face = face.Normalize(); + + + if ( DotProduct(dir, face) > 0.9 ) // Only take damage if the leech is facing the prey + pEnemy->TakeDamage( pev, pev, gSkillData.leechDmgBite, DMG_SLASH ); + } + m_stateTime -= 2; + break; + + case LEECH_AE_FLOP: + // Play flop sound + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + + +void CLeech::MakeVectors( void ) +{ + Vector tmp = pev->angles; + tmp.x = -tmp.x; + UTIL_MakeVectors ( tmp ); +} + + +// +// ObstacleDistance - returns normalized distance to obstacle +// +float CLeech::ObstacleDistance( CBaseEntity *pTarget ) +{ + TraceResult tr; + Vector vecTest; + + // use VELOCITY, not angles, not all boids point the direction they are flying + //Vector vecDir = UTIL_VecToAngles( pev->velocity ); + MakeVectors(); + + // check for obstacle ahead + vecTest = pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST; + UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + + if ( tr.fStartSolid ) + { + pev->speed = -LEECH_SWIM_SPEED * 0.5; +// ALERT( at_console, "Stuck from (%f %f %f) to (%f %f %f)\n", pev->oldorigin.x, pev->oldorigin.y, pev->oldorigin.z, pev->origin.x, pev->origin.y, pev->origin.z ); +// UTIL_SetOrigin( pev, pev->oldorigin ); + } + + if ( tr.flFraction != 1.0 ) + { + if ( (pTarget == NULL || tr.pHit != pTarget->edict()) ) + { + return tr.flFraction; + } + else + { + if ( fabs(m_height - pev->origin.z) > 10 ) + return tr.flFraction; + } + } + + if ( m_sideTime < gpGlobals->time ) + { + // extra wide checks + vecTest = pev->origin + gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; + UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + if (tr.flFraction != 1.0) + return tr.flFraction; + + vecTest = pev->origin - gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; + UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + if (tr.flFraction != 1.0) + return tr.flFraction; + + // Didn't hit either side, so stop testing for another 0.5 - 1 seconds + m_sideTime = gpGlobals->time + RANDOM_FLOAT(0.5,1); + } + return 1.0; +} + + +void CLeech::DeadThink( void ) +{ + if ( m_fSequenceFinished ) + { + if ( m_Activity == ACT_DIEFORWARD ) + { + SetThink( NULL ); + StopAnimation(); + return; + } + else if ( pev->flags & FL_ONGROUND ) + { + pev->solid = SOLID_NOT; + SetActivity(ACT_DIEFORWARD); + } + } + StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + + // Apply damage velocity, but keep out of the walls + if ( pev->velocity.x != 0 || pev->velocity.y != 0 ) + { + TraceResult tr; + + // Look 0.5 seconds ahead + UTIL_TraceLine(pev->origin, pev->origin + pev->velocity * 0.5, missile, edict(), &tr); + if (tr.flFraction != 1.0) + { + pev->velocity.x = 0; + pev->velocity.y = 0; + } + } +} + + + +void CLeech::UpdateMotion( void ) +{ + float flapspeed = (pev->speed - m_flAccelerate) / LEECH_ACCELERATE; + m_flAccelerate = m_flAccelerate * 0.8 + pev->speed * 0.2; + + if (flapspeed < 0) + flapspeed = -flapspeed; + flapspeed += 1.0; + if (flapspeed < 0.5) + flapspeed = 0.5; + if (flapspeed > 1.9) + flapspeed = 1.9; + + pev->framerate = flapspeed; + + if ( !m_fPathBlocked ) + pev->avelocity.y = pev->ideal_yaw; + else + pev->avelocity.y = pev->ideal_yaw * m_obstacle; + + if ( pev->avelocity.y > 150 ) + m_IdealActivity = ACT_TURN_LEFT; + else if ( pev->avelocity.y < -150 ) + m_IdealActivity = ACT_TURN_RIGHT; + else + m_IdealActivity = ACT_SWIM; + + // lean + float targetPitch, delta; + delta = m_height - pev->origin.z; + + if ( delta < -10 ) + targetPitch = -30; + else if ( delta > 10 ) + targetPitch = 30; + else + targetPitch = 0; + + pev->angles.x = UTIL_Approach( targetPitch, pev->angles.x, 60 * LEECH_FRAMETIME ); + + // bank + pev->avelocity.z = - (pev->angles.z + (pev->avelocity.y * 0.25)); + + if ( m_MonsterState == MONSTERSTATE_COMBAT && HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + m_IdealActivity = ACT_MELEE_ATTACK1; + + // Out of water check + if ( !pev->waterlevel ) + { + pev->movetype = MOVETYPE_TOSS; + m_IdealActivity = ACT_TWITCH; + pev->velocity = g_vecZero; + + // Animation will intersect the floor if either of these is non-zero + pev->angles.z = 0; + pev->angles.x = 0; + + if ( pev->framerate < 1.0 ) + pev->framerate = 1.0; + } + else if ( pev->movetype == MOVETYPE_TOSS ) + { + pev->movetype = MOVETYPE_FLY; + pev->flags &= ~FL_ONGROUND; + RecalculateWaterlevel(); + m_waterTime = gpGlobals->time + 2; // Recalc again soon, water may be rising + } + + if ( m_Activity != m_IdealActivity ) + { + SetActivity ( m_IdealActivity ); + } + float flInterval = StudioFrameAdvance(); + DispatchAnimEvents ( flInterval ); + +#if DEBUG_BEAMS + if ( !m_pb ) + m_pb = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); + if ( !m_pt ) + m_pt = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); + m_pb->PointsInit( pev->origin, pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST ); + m_pt->PointsInit( pev->origin, pev->origin - gpGlobals->v_right * (pev->avelocity.y*0.25) ); + if ( m_fPathBlocked ) + { + float color = m_obstacle * 30; + if ( m_obstacle == 1.0 ) + color = 0; + if ( color > 255 ) + color = 255; + m_pb->SetColor( 255, (int)color, (int)color ); + } + else + m_pb->SetColor( 255, 255, 0 ); + m_pt->SetColor( 0, 0, 255 ); +#endif +} + + +void CLeech::SwimThink( void ) +{ + TraceResult tr; + float flLeftSide; + float flRightSide; + float targetSpeed; + float targetYaw = 0; + CBaseEntity *pTarget; + + if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + { + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); + pev->velocity = g_vecZero; + return; + } + else + pev->nextthink = gpGlobals->time + 0.1; + + targetSpeed = LEECH_SWIM_SPEED; + + if ( m_waterTime < gpGlobals->time ) + RecalculateWaterlevel(); + + if ( m_stateTime < gpGlobals->time ) + SwitchLeechState(); + + ClearConditions( bits_COND_CAN_MELEE_ATTACK1 ); + switch( m_MonsterState ) + { + case MONSTERSTATE_COMBAT: + pTarget = m_hEnemy; + if ( !pTarget ) + SwitchLeechState(); + else + { + // Chase the enemy's eyes + m_height = pTarget->pev->origin.z + pTarget->pev->view_ofs.z - 5; + // Clip to viable water area + if ( m_height < m_bottom ) + m_height = m_bottom; + else if ( m_height > m_top ) + m_height = m_top; + Vector location = pTarget->pev->origin - pev->origin; + location.z += (pTarget->pev->view_ofs.z); + if ( location.Length() < 40 ) + SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); + // Turn towards target ent + targetYaw = UTIL_VecToYaw( location ); + + targetYaw = UTIL_AngleDiff( targetYaw, UTIL_AngleMod( pev->angles.y ) ); + + if ( targetYaw < (-LEECH_TURN_RATE*0.75) ) + targetYaw = (-LEECH_TURN_RATE*0.75); + else if ( targetYaw > (LEECH_TURN_RATE*0.75) ) + targetYaw = (LEECH_TURN_RATE*0.75); + else + targetSpeed *= 2; + } + + break; + + default: + if ( m_zTime < gpGlobals->time ) + { + float newHeight = RANDOM_FLOAT( m_bottom, m_top ); + m_height = 0.5 * m_height + 0.5 * newHeight; + m_zTime = gpGlobals->time + RANDOM_FLOAT( 1, 4 ); + } + if ( RANDOM_LONG( 0, 100 ) < 10 ) + targetYaw = RANDOM_LONG( -30, 30 ); + pTarget = NULL; + // oldorigin test + if ( (pev->origin - pev->oldorigin).Length() < 1 ) + { + // If leech didn't move, there must be something blocking it, so try to turn + m_sideTime = 0; + } + + break; + } + + m_obstacle = ObstacleDistance( pTarget ); + pev->oldorigin = pev->origin; + if ( m_obstacle < 0.1 ) + m_obstacle = 0.1; + + // is the way ahead clear? + if ( m_obstacle == 1.0 ) + { + // if the leech is turning, stop the trend. + if ( m_flTurning != 0 ) + { + m_flTurning = 0; + } + + m_fPathBlocked = FALSE; + pev->speed = UTIL_Approach( targetSpeed, pev->speed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME ); + pev->velocity = gpGlobals->v_forward * pev->speed; + + } + else + { + m_obstacle = 1.0 / m_obstacle; + // IF we get this far in the function, the leader's path is blocked! + m_fPathBlocked = TRUE; + + if ( m_flTurning == 0 )// something in the way and leech is not already turning to avoid + { + Vector vecTest; + // measure clearance on left and right to pick the best dir to turn + vecTest = pev->origin + (gpGlobals->v_right * LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); + UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + flRightSide = tr.flFraction; + + vecTest = pev->origin + (gpGlobals->v_right * -LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); + UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + flLeftSide = tr.flFraction; + + // turn left, right or random depending on clearance ratio + float delta = (flRightSide - flLeftSide); + if ( delta > 0.1 || (delta > -0.1 && RANDOM_LONG(0,100)<50) ) + m_flTurning = -LEECH_TURN_RATE; + else + m_flTurning = LEECH_TURN_RATE; + } + pev->speed = UTIL_Approach( -(LEECH_SWIM_SPEED*0.5), pev->speed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle ); + pev->velocity = gpGlobals->v_forward * pev->speed; + } + pev->ideal_yaw = m_flTurning + targetYaw; + UpdateMotion(); +} + + +void CLeech::Killed(entvars_t *pevAttacker, int iGib) +{ + Vector vecSplatDir; + TraceResult tr; + + //ALERT(at_aiconsole, "Leech: killed\n"); + // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. + CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); + if (pOwner) + pOwner->DeathNotice(pev); + + // When we hit the ground, play the "death_end" activity + if ( pev->waterlevel ) + { + pev->angles.z = 0; + pev->angles.x = 0; + pev->origin.z += 1; + pev->avelocity = g_vecZero; + if ( RANDOM_LONG( 0, 99 ) < 70 ) + pev->avelocity.y = RANDOM_LONG( -720, 720 ); + + pev->gravity = 0.02; + ClearBits(pev->flags, FL_ONGROUND); + SetActivity( ACT_DIESIMPLE ); + } + else + SetActivity( ACT_DIEFORWARD ); + + pev->movetype = MOVETYPE_TOSS; + pev->takedamage = DAMAGE_NO; + SetThink( &CLeech::DeadThink ); +} + + diff --git a/main/source/dlls/lights.cpp b/main/source/dlls/lights.cpp index 3aec4054..e9a9a2f7 100644 --- a/main/source/dlls/lights.cpp +++ b/main/source/dlls/lights.cpp @@ -1,222 +1,222 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== lights.cpp ======================================================== - - spawn and think functions for editor-placed lights - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" - - - -class CLight : public CPointEntity -{ -public: - virtual void KeyValue( KeyValueData* pkvd ); - virtual void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual void SaveDataForReset(); - virtual void ResetEntity(); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_iStyle; - int m_iszPattern; - - int mSavedSpawnFlags; - int mSavedStyle; - int mSavedPattern; - -}; -LINK_ENTITY_TO_CLASS( light, CLight ); - -TYPEDESCRIPTION CLight::m_SaveData[] = -{ - DEFINE_FIELD( CLight, m_iStyle, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CLight, CPointEntity ); - - -// -// Cache user-entity-field values until spawn is called. -// -void CLight :: KeyValue( KeyValueData* pkvd) -{ - if (FStrEq(pkvd->szKeyName, "style")) - { - m_iStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - pev->angles.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pattern")) - { - m_iszPattern = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CPointEntity::KeyValue( pkvd ); - } -} - -/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) LIGHT_START_OFF -Non-displayed light. -Default light value is 300 -Default style is 0 -If targeted, it will toggle between on or off. -*/ - -void CLight :: Spawn( void ) -{ - if (FStringNull(pev->targetname)) - { // inert light - REMOVE_ENTITY(ENT(pev)); - return; - } - - this->SaveDataForReset(); -} - -void CLight::SaveDataForReset() -{ - this->mSavedSpawnFlags = this->pev->spawnflags; - this->mSavedStyle = this->m_iStyle; - this->mSavedPattern = this->m_iszPattern; -} - -void CLight::ResetEntity() -{ - this->pev->spawnflags = this->mSavedSpawnFlags; - this->m_iStyle = this->mSavedStyle; - this->m_iszPattern = this->mSavedPattern; - - if (m_iStyle >= 32) - { - // CHANGE_METHOD(ENT(pev), em_use, light_use); - if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) - LIGHT_STYLE(m_iStyle, "a"); - else if (m_iszPattern) - LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern )); - else - LIGHT_STYLE(m_iStyle, "m"); - } -} - -void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (m_iStyle >= 32) - { - if ( !ShouldToggle( useType, !FBitSet(pev->spawnflags, SF_LIGHT_START_OFF) ) ) - return; - - if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) - { - if (m_iszPattern) - LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern )); - else - LIGHT_STYLE(m_iStyle, "m"); - ClearBits(pev->spawnflags, SF_LIGHT_START_OFF); - } - else - { - LIGHT_STYLE(m_iStyle, "a"); - SetBits(pev->spawnflags, SF_LIGHT_START_OFF); - } - } -} - -// -// shut up spawn functions for new spotlights -// -LINK_ENTITY_TO_CLASS( light_spot, CLight ); - - -class CEnvLight : public CLight -{ -public: - void KeyValue( KeyValueData* pkvd ); - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ); - -void CEnvLight::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "_light")) - { - int r, g, b, v, j; - char szColor[64]; - j = sscanf( pkvd->szValue, "%d %d %d %d\n", &r, &g, &b, &v ); - if (j == 1) - { - g = b = r; - } - else if (j == 4) - { - r = r * (v / 255.0); - g = g * (v / 255.0); - b = b * (v / 255.0); - } - - // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling - r = pow( r / 114.0, 0.6 ) * 264; - g = pow( g / 114.0, 0.6 ) * 264; - b = pow( b / 114.0, 0.6 ) * 264; - - pkvd->fHandled = TRUE; - sprintf( szColor, "%d", r ); - CVAR_SET_STRING( "sv_skycolor_r", szColor ); - sprintf( szColor, "%d", g ); - CVAR_SET_STRING( "sv_skycolor_g", szColor ); - sprintf( szColor, "%d", b ); - CVAR_SET_STRING( "sv_skycolor_b", szColor ); - } - else - { - CLight::KeyValue( pkvd ); - } -} - - -void CEnvLight :: Spawn( void ) -{ - char szVector[64]; - UTIL_MakeAimVectors( pev->angles ); - - sprintf( szVector, "%f", gpGlobals->v_forward.x ); - CVAR_SET_STRING( "sv_skyvec_x", szVector ); - sprintf( szVector, "%f", gpGlobals->v_forward.y ); - CVAR_SET_STRING( "sv_skyvec_y", szVector ); - sprintf( szVector, "%f", gpGlobals->v_forward.z ); - CVAR_SET_STRING( "sv_skyvec_z", szVector ); - - CLight::Spawn( ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== lights.cpp ======================================================== + + spawn and think functions for editor-placed lights + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" + + + +class CLight : public CPointEntity +{ +public: + virtual void KeyValue( KeyValueData* pkvd ); + virtual void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual void SaveDataForReset(); + virtual void ResetEntity(); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + int m_iStyle; + int m_iszPattern; + + int mSavedSpawnFlags; + int mSavedStyle; + int mSavedPattern; + +}; +LINK_ENTITY_TO_CLASS( light, CLight ); + +TYPEDESCRIPTION CLight::m_SaveData[] = +{ + DEFINE_FIELD( CLight, m_iStyle, FIELD_INTEGER ), + DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CLight, CPointEntity ); + + +// +// Cache user-entity-field values until spawn is called. +// +void CLight :: KeyValue( KeyValueData* pkvd) +{ + if (FStrEq(pkvd->szKeyName, "style")) + { + m_iStyle = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "pitch")) + { + pev->angles.x = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "pattern")) + { + m_iszPattern = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + { + CPointEntity::KeyValue( pkvd ); + } +} + +/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) LIGHT_START_OFF +Non-displayed light. +Default light value is 300 +Default style is 0 +If targeted, it will toggle between on or off. +*/ + +void CLight :: Spawn( void ) +{ + if (FStringNull(pev->targetname)) + { // inert light + REMOVE_ENTITY(ENT(pev)); + return; + } + + this->SaveDataForReset(); +} + +void CLight::SaveDataForReset() +{ + this->mSavedSpawnFlags = this->pev->spawnflags; + this->mSavedStyle = this->m_iStyle; + this->mSavedPattern = this->m_iszPattern; +} + +void CLight::ResetEntity() +{ + this->pev->spawnflags = this->mSavedSpawnFlags; + this->m_iStyle = this->mSavedStyle; + this->m_iszPattern = this->mSavedPattern; + + if (m_iStyle >= 32) + { + // CHANGE_METHOD(ENT(pev), em_use, light_use); + if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) + LIGHT_STYLE(m_iStyle, "a"); + else if (m_iszPattern) + LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern )); + else + LIGHT_STYLE(m_iStyle, "m"); + } +} + +void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if (m_iStyle >= 32) + { + if ( !ShouldToggle( useType, !FBitSet(pev->spawnflags, SF_LIGHT_START_OFF) ) ) + return; + + if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) + { + if (m_iszPattern) + LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern )); + else + LIGHT_STYLE(m_iStyle, "m"); + ClearBits(pev->spawnflags, SF_LIGHT_START_OFF); + } + else + { + LIGHT_STYLE(m_iStyle, "a"); + SetBits(pev->spawnflags, SF_LIGHT_START_OFF); + } + } +} + +// +// shut up spawn functions for new spotlights +// +LINK_ENTITY_TO_CLASS( light_spot, CLight ); + + +class CEnvLight : public CLight +{ +public: + void KeyValue( KeyValueData* pkvd ); + void Spawn( void ); +}; + +LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ); + +void CEnvLight::KeyValue( KeyValueData* pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "_light")) + { + int r, g, b, v, j; + char szColor[64]; + j = sscanf( pkvd->szValue, "%d %d %d %d\n", &r, &g, &b, &v ); + if (j == 1) + { + g = b = r; + } + else if (j == 4) + { + r = r * (v / 255.0); + g = g * (v / 255.0); + b = b * (v / 255.0); + } + + // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling + r = pow( r / 114.0, 0.6 ) * 264; + g = pow( g / 114.0, 0.6 ) * 264; + b = pow( b / 114.0, 0.6 ) * 264; + + pkvd->fHandled = TRUE; + sprintf( szColor, "%d", r ); + CVAR_SET_STRING( "sv_skycolor_r", szColor ); + sprintf( szColor, "%d", g ); + CVAR_SET_STRING( "sv_skycolor_g", szColor ); + sprintf( szColor, "%d", b ); + CVAR_SET_STRING( "sv_skycolor_b", szColor ); + } + else + { + CLight::KeyValue( pkvd ); + } +} + + +void CEnvLight :: Spawn( void ) +{ + char szVector[64]; + UTIL_MakeAimVectors( pev->angles ); + + sprintf( szVector, "%f", gpGlobals->v_forward.x ); + CVAR_SET_STRING( "sv_skyvec_x", szVector ); + sprintf( szVector, "%f", gpGlobals->v_forward.y ); + CVAR_SET_STRING( "sv_skyvec_y", szVector ); + sprintf( szVector, "%f", gpGlobals->v_forward.z ); + CVAR_SET_STRING( "sv_skyvec_z", szVector ); + + CLight::Spawn( ); +} diff --git a/main/source/dlls/maprules.cpp b/main/source/dlls/maprules.cpp index faacb817..9ff894b3 100644 --- a/main/source/dlls/maprules.cpp +++ b/main/source/dlls/maprules.cpp @@ -1,918 +1,918 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// ------------------------------------------- -// -// maprules.cpp -// -// This module contains entities for implementing/changing game -// rules dynamically within each map (.BSP) -// -// ------------------------------------------- - -#include "extdll.h" -#include "../engine/eiface.h" -#include "util.h" -#include "gamerules.h" -#include "maprules.h" -#include "cbase.h" -#include "player.h" - -class CRuleEntity : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } - -protected: - BOOL CanFireForActivator( CBaseEntity *pActivator ); - -private: - string_t m_iszMaster; -}; - -TYPEDESCRIPTION CRuleEntity::m_SaveData[] = -{ - DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), -}; - -IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ); - - -void CRuleEntity::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; -} - - -void CRuleEntity::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - SetMaster( ALLOC_STRING(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) -{ - if ( m_iszMaster ) - { - if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) - return TRUE; - else - return FALSE; - } - - return TRUE; -} - -// -// CRulePointEntity -- base class for all rule "point" entities (not brushes) -// -class CRulePointEntity : public CRuleEntity -{ -public: - void Spawn( void ); -}; - -void CRulePointEntity::Spawn( void ) -{ - CRuleEntity::Spawn(); - pev->frame = 0; - pev->model = 0; -} - -// -// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) -// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing -// -class CRuleBrushEntity : public CRuleEntity -{ -public: - void Spawn( void ); - -private: -}; - -void CRuleBrushEntity::Spawn( void ) -{ - SET_MODEL( edict(), STRING(pev->model) ); - CRuleEntity::Spawn(); -} - - -// CGameScore / game_score -- award points to player / team -// Points +/- total -// Flag: Allow negative scores SF_SCORE_NEGATIVE -// Flag: Award points to team in teamplay SF_SCORE_TEAM - -#define SF_SCORE_NEGATIVE 0x0001 -#define SF_SCORE_TEAM 0x0002 - -class CGameScore : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Points( void ) { return pev->frags; } - inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } - inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } - - inline void SetPoints( int points ) { pev->frags = points; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_score, CGameScore ); - - -void CGameScore::Spawn( void ) -{ - CRulePointEntity::Spawn(); -} - - -void CGameScore::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "points")) - { - SetPoints( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - - -void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - // Only players can use this - if ( pActivator->IsPlayer() ) - { - if ( AwardToTeam() ) - { - pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); - } - else - { - pActivator->AddPoints( Points(), AllowNegativeScore() ); - } - } -} - - -// CGameEnd / game_end -- Ends the game in MP - -class CGameEnd : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -private: -}; - -LINK_ENTITY_TO_CLASS( game_end, CGameEnd ); - - -void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - g_pGameRules->EndMultiplayerGame(); -} - - -// -// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) -// Flag: All players SF_ENVTEXT_ALLPLAYERS -// - - -#define SF_ENVTEXT_ALLPLAYERS 0x0001 - - -class CGameText : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } - inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); } - inline const char *MessageGet( void ) { return STRING(pev->message); } - -private: - - hudtextparms_t m_textParms; -}; - -LINK_ENTITY_TO_CLASS( game_text, CGameText ); - -// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so -// it can't impact saved Half-Life games. -TYPEDESCRIPTION CGameText::m_SaveData[] = -{ - DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), -}; - -IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ); - - -void CGameText::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "channel")) - { - m_textParms.channel = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "x")) - { - m_textParms.x = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "y")) - { - m_textParms.y = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "effect")) - { - m_textParms.effect = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r1 = color[0]; - m_textParms.g1 = color[1]; - m_textParms.b1 = color[2]; - m_textParms.a1 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color2")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r2 = color[0]; - m_textParms.g2 = color[1]; - m_textParms.b2 = color[2]; - m_textParms.a2 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_textParms.fadeinTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_textParms.fadeoutTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - m_textParms.holdTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fxtime")) - { - m_textParms.fxTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( MessageToAll() ) - { - UTIL_HudMessageAll( m_textParms, MessageGet() ); - } - else - { - if ( pActivator->IsNetClient() ) - { - UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); - } - } -} - - -// -// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator -// Only allows mastered entity to fire if the team matches my team -// -// team index (pulled from server team list "mp_teamlist" -// Flag: Remove on Fire -// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) -// - -#define SF_TEAMMASTER_FIREONCE 0x0001 -#define SF_TEAMMASTER_ANYTEAM 0x0002 - -class CGameTeamMaster : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } - - BOOL IsTriggered( CBaseEntity *pActivator ); - char* TeamID( void ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } - inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } - -private: - BOOL TeamMatch( CBaseEntity *pActivator ); - - int m_teamIndex; - USE_TYPE triggerType; -}; - -LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ); - -void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "teamindex")) - { - m_teamIndex = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( useType == USE_SET ) - { - if ( value < 0 ) - { - m_teamIndex = -1; - } - else - { - m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); - } - return; - } - - if ( TeamMatch( pActivator ) ) - { - SUB_UseTargets( pActivator, triggerType, value ); - if ( RemoveOnFire() ) - UTIL_Remove( this ); - } -} - - -BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) -{ - return TeamMatch( pActivator ); -} - - -char *CGameTeamMaster::TeamID( void ) -{ - if ( m_teamIndex < 0 ) // Currently set to "no team" - return ""; - - return const_cast(g_pGameRules->GetIndexedTeamName( m_teamIndex )); // UNDONE: Fill this in with the team from the "teamlist" -} - - -BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) -{ - if ( m_teamIndex < 0 && AnyTeam() ) - return TRUE; - - if ( !pActivator ) - return FALSE; - - return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); -} - - -// -// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team -// Flag: Fire once -// Flag: Clear team -- Sets the team to "NONE" instead of activator - -#define SF_TEAMSET_FIREONCE 0x0001 -#define SF_TEAMSET_CLEARTEAM 0x0002 - -class CGameTeamSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ); - - -void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( ShouldClearTeam() ) - { - SUB_UseTargets( pActivator, USE_SET, -1 ); - } - else - { - SUB_UseTargets( pActivator, USE_SET, 0 ); - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired -// -// Needs master? -class CGamePlayerZone : public CRuleBrushEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - string_t m_iszInTarget; - string_t m_iszOutTarget; - string_t m_iszInCount; - string_t m_iszOutCount; -}; - -LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ); -TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = -{ - DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ); - -void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "intarget")) - { - m_iszInTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outtarget")) - { - m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "incount")) - { - m_iszInCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outcount")) - { - m_iszOutCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRuleBrushEntity::KeyValue( pkvd ); -} - -void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int playersInCount = 0; - int playersOutCount = 0; - - if ( !CanFireForActivator( pActivator ) ) - return; - - CBaseEntity *pPlayer = NULL; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - { - TraceResult trace; - int hullNumber; - - hullNumber = human_hull; - if ( pPlayer->pev->flags & FL_DUCKING ) - { - hullNumber = head_hull; - } - - UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); - - if ( trace.fStartSolid ) - { - playersInCount++; - if ( m_iszInTarget ) - { - FireTargets( STRING(m_iszInTarget), pPlayer, pActivator, useType, value ); - } - } - else - { - playersOutCount++; - if ( m_iszOutTarget ) - { - FireTargets( STRING(m_iszOutTarget), pPlayer, pActivator, useType, value ); - } - } - } - } - - if ( m_iszInCount ) - { - FireTargets( STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount ); - } - - if ( m_iszOutCount ) - { - FireTargets( STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount ); - } -} - - - -// -// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it -// Flag: Fire once - -#define SF_PKILL_FIREONCE 0x0001 -class CGamePlayerHurt : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ); - - -void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - if ( pev->dmg < 0 ) - pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); - else - pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); - } - - SUB_UseTargets( pActivator, useType, value ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - - -// -// CGameCounter / game_counter -- Counts events and fires target -// Flag: Fire once -// Flag: Reset on Fire - -#define SF_GAMECOUNT_FIREONCE 0x0001 -#define SF_GAMECOUNT_RESET 0x0002 - -class CGameCounter : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } - inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } - - inline void CountUp( void ) { pev->frags++; } - inline void CountDown( void ) { pev->frags--; } - inline void ResetCount( void ) { pev->frags = pev->dmg; } - inline int CountValue( void ) { return pev->frags; } - inline int LimitValue( void ) { return pev->health; } - - inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } - -private: - - inline void SetCountValue( int value ) { pev->frags = value; } - inline void SetInitialValue( int value ) { pev->dmg = value; } -}; - -LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ); - -void CGameCounter::Spawn( void ) -{ - // Save off the initial count - SetInitialValue( CountValue() ); - CRulePointEntity::Spawn(); -} - - -void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - switch( useType ) - { - case USE_ON: - case USE_TOGGLE: - CountUp(); - break; - - case USE_OFF: - CountDown(); - break; - - case USE_SET: - SetCountValue( (int)value ); - break; - } - - if ( HitLimit() ) - { - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } - - if ( ResetOnFire() ) - { - ResetCount(); - } - } -} - - - -// -// CGameCounterSet / game_counter_set -- Sets the counter's value -// Flag: Fire once - -#define SF_GAMECOUNTSET_FIREONCE 0x0001 - -class CGameCounterSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ); - - -void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - SUB_UseTargets( pActivator, USE_SET, pev->frags ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerEquip / game_playerequip -- Sets the default player equipment -// Flag: USE Only - -#define SF_PLAYEREQUIP_USEONLY 0x0001 -#define MAX_EQUIP 32 - -class CGamePlayerEquip : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } - -private: - - void EquipPlayer( CBaseEntity *pPlayer ); - - string_t m_weaponNames[MAX_EQUIP]; - int m_weaponCount[MAX_EQUIP]; -}; - -LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ); - - -void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) -{ - CRulePointEntity::KeyValue( pkvd ); - - if ( !pkvd->fHandled ) - { - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - - m_weaponNames[i] = ALLOC_STRING(tmp); - m_weaponCount[i] = atoi(pkvd->szValue); - m_weaponCount[i] = max(1,m_weaponCount[i]); - pkvd->fHandled = TRUE; - break; - } - } - } -} - - -void CGamePlayerEquip::Touch( CBaseEntity *pOther ) -{ - if ( !CanFireForActivator( pOther ) ) - return; - - if ( UseOnly() ) - return; - - EquipPlayer( pOther ); -} - -void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pEntity->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pEntity; - } - - if ( !pPlayer ) - return; - - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - break; - for ( int j = 0; j < m_weaponCount[i]; j++ ) - { - pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) ); - } - } -} - - -void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - EquipPlayer( pActivator ); -} - - -// -// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it -// Flag: Fire once -// Flag: Kill Player -// Flag: Gib Player - -#define SF_PTEAM_FIREONCE 0x0001 -#define SF_PTEAM_KILL 0x0002 -#define SF_PTEAM_GIB 0x0004 - -class CGamePlayerTeam : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: - - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } - inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } - - const char *TargetTeamName( const char *pszTargetName ); -}; - -LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ); - - -const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) -{ - CBaseEntity *pTeamEntity = NULL; - - while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL) - { - if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) - return pTeamEntity->TeamID(); - } - - return NULL; -} - - -void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); - if ( pszTargetTeam ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pActivator; - g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); - } - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// ------------------------------------------- +// +// maprules.cpp +// +// This module contains entities for implementing/changing game +// rules dynamically within each map (.BSP) +// +// ------------------------------------------- + +#include "extdll.h" +#include "../engine/eiface.h" +#include "util.h" +#include "gamerules.h" +#include "maprules.h" +#include "cbase.h" +#include "player.h" + +class CRuleEntity : public CBaseEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } + +protected: + BOOL CanFireForActivator( CBaseEntity *pActivator ); + +private: + string_t m_iszMaster; +}; + +TYPEDESCRIPTION CRuleEntity::m_SaveData[] = +{ + DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), +}; + +IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ); + + +void CRuleEntity::Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = EF_NODRAW; +} + + +void CRuleEntity::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "master")) + { + SetMaster( ALLOC_STRING(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) +{ + if ( m_iszMaster ) + { + if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) + return TRUE; + else + return FALSE; + } + + return TRUE; +} + +// +// CRulePointEntity -- base class for all rule "point" entities (not brushes) +// +class CRulePointEntity : public CRuleEntity +{ +public: + void Spawn( void ); +}; + +void CRulePointEntity::Spawn( void ) +{ + CRuleEntity::Spawn(); + pev->frame = 0; + pev->model = 0; +} + +// +// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) +// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing +// +class CRuleBrushEntity : public CRuleEntity +{ +public: + void Spawn( void ); + +private: +}; + +void CRuleBrushEntity::Spawn( void ) +{ + SET_MODEL( edict(), STRING(pev->model) ); + CRuleEntity::Spawn(); +} + + +// CGameScore / game_score -- award points to player / team +// Points +/- total +// Flag: Allow negative scores SF_SCORE_NEGATIVE +// Flag: Award points to team in teamplay SF_SCORE_TEAM + +#define SF_SCORE_NEGATIVE 0x0001 +#define SF_SCORE_TEAM 0x0002 + +class CGameScore : public CRulePointEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + + inline int Points( void ) { return pev->frags; } + inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } + inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } + + inline void SetPoints( int points ) { pev->frags = points; } + +private: +}; + +LINK_ENTITY_TO_CLASS( game_score, CGameScore ); + + +void CGameScore::Spawn( void ) +{ + CRulePointEntity::Spawn(); +} + + +void CGameScore::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "points")) + { + SetPoints( atoi(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else + CRulePointEntity::KeyValue( pkvd ); +} + + + +void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + // Only players can use this + if ( pActivator->IsPlayer() ) + { + if ( AwardToTeam() ) + { + pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); + } + else + { + pActivator->AddPoints( Points(), AllowNegativeScore() ); + } + } +} + + +// CGameEnd / game_end -- Ends the game in MP + +class CGameEnd : public CRulePointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +private: +}; + +LINK_ENTITY_TO_CLASS( game_end, CGameEnd ); + + +void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + g_pGameRules->EndMultiplayerGame(); +} + + +// +// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) +// Flag: All players SF_ENVTEXT_ALLPLAYERS +// + + +#define SF_ENVTEXT_ALLPLAYERS 0x0001 + + +class CGameText : public CRulePointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } + inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); } + inline const char *MessageGet( void ) { return STRING(pev->message); } + +private: + + hudtextparms_t m_textParms; +}; + +LINK_ENTITY_TO_CLASS( game_text, CGameText ); + +// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so +// it can't impact saved Half-Life games. +TYPEDESCRIPTION CGameText::m_SaveData[] = +{ + DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), +}; + +IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ); + + +void CGameText::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "channel")) + { + m_textParms.channel = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "x")) + { + m_textParms.x = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "y")) + { + m_textParms.y = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "effect")) + { + m_textParms.effect = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "color")) + { + int color[4]; + UTIL_StringToIntArray( color, 4, pkvd->szValue ); + m_textParms.r1 = color[0]; + m_textParms.g1 = color[1]; + m_textParms.b1 = color[2]; + m_textParms.a1 = color[3]; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "color2")) + { + int color[4]; + UTIL_StringToIntArray( color, 4, pkvd->szValue ); + m_textParms.r2 = color[0]; + m_textParms.g2 = color[1]; + m_textParms.b2 = color[2]; + m_textParms.a2 = color[3]; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "fadein")) + { + m_textParms.fadeinTime = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "fadeout")) + { + m_textParms.fadeoutTime = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "holdtime")) + { + m_textParms.holdTime = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "fxtime")) + { + m_textParms.fxTime = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CRulePointEntity::KeyValue( pkvd ); +} + + +void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + if ( MessageToAll() ) + { + UTIL_HudMessageAll( m_textParms, MessageGet() ); + } + else + { + if ( pActivator->IsNetClient() ) + { + UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); + } + } +} + + +// +// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator +// Only allows mastered entity to fire if the team matches my team +// +// team index (pulled from server team list "mp_teamlist" +// Flag: Remove on Fire +// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) +// + +#define SF_TEAMMASTER_FIREONCE 0x0001 +#define SF_TEAMMASTER_ANYTEAM 0x0002 + +class CGameTeamMaster : public CRulePointEntity +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } + + BOOL IsTriggered( CBaseEntity *pActivator ); + char* TeamID( void ); + inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } + inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } + +private: + BOOL TeamMatch( CBaseEntity *pActivator ); + + int m_teamIndex; + USE_TYPE triggerType; +}; + +LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ); + +void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "teamindex")) + { + m_teamIndex = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "triggerstate")) + { + int type = atoi( pkvd->szValue ); + switch( type ) + { + case 0: + triggerType = USE_OFF; + break; + case 2: + triggerType = USE_TOGGLE; + break; + default: + triggerType = USE_ON; + break; + } + pkvd->fHandled = TRUE; + } + else + CRulePointEntity::KeyValue( pkvd ); +} + + +void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + if ( useType == USE_SET ) + { + if ( value < 0 ) + { + m_teamIndex = -1; + } + else + { + m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); + } + return; + } + + if ( TeamMatch( pActivator ) ) + { + SUB_UseTargets( pActivator, triggerType, value ); + if ( RemoveOnFire() ) + UTIL_Remove( this ); + } +} + + +BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) +{ + return TeamMatch( pActivator ); +} + + +char *CGameTeamMaster::TeamID( void ) +{ + if ( m_teamIndex < 0 ) // Currently set to "no team" + return ""; + + return const_cast(g_pGameRules->GetIndexedTeamName( m_teamIndex )); // UNDONE: Fill this in with the team from the "teamlist" +} + + +BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) +{ + if ( m_teamIndex < 0 && AnyTeam() ) + return TRUE; + + if ( !pActivator ) + return FALSE; + + return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); +} + + +// +// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team +// Flag: Fire once +// Flag: Clear team -- Sets the team to "NONE" instead of activator + +#define SF_TEAMSET_FIREONCE 0x0001 +#define SF_TEAMSET_CLEARTEAM 0x0002 + +class CGameTeamSet : public CRulePointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } + inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } + +private: +}; + +LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ); + + +void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + if ( ShouldClearTeam() ) + { + SUB_UseTargets( pActivator, USE_SET, -1 ); + } + else + { + SUB_UseTargets( pActivator, USE_SET, 0 ); + } + + if ( RemoveOnFire() ) + { + UTIL_Remove( this ); + } +} + + +// +// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired +// +// Needs master? +class CGamePlayerZone : public CRuleBrushEntity +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + +private: + string_t m_iszInTarget; + string_t m_iszOutTarget; + string_t m_iszInCount; + string_t m_iszOutCount; +}; + +LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ); +TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = +{ + DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), + DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), + DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), + DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ); + +void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "intarget")) + { + m_iszInTarget = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "outtarget")) + { + m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "incount")) + { + m_iszInCount = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "outcount")) + { + m_iszOutCount = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CRuleBrushEntity::KeyValue( pkvd ); +} + +void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int playersInCount = 0; + int playersOutCount = 0; + + if ( !CanFireForActivator( pActivator ) ) + return; + + CBaseEntity *pPlayer = NULL; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + pPlayer = UTIL_PlayerByIndex( i ); + if ( pPlayer ) + { + TraceResult trace; + int hullNumber; + + hullNumber = human_hull; + if ( pPlayer->pev->flags & FL_DUCKING ) + { + hullNumber = head_hull; + } + + UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); + + if ( trace.fStartSolid ) + { + playersInCount++; + if ( m_iszInTarget ) + { + FireTargets( STRING(m_iszInTarget), pPlayer, pActivator, useType, value ); + } + } + else + { + playersOutCount++; + if ( m_iszOutTarget ) + { + FireTargets( STRING(m_iszOutTarget), pPlayer, pActivator, useType, value ); + } + } + } + } + + if ( m_iszInCount ) + { + FireTargets( STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount ); + } + + if ( m_iszOutCount ) + { + FireTargets( STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount ); + } +} + + + +// +// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it +// Flag: Fire once + +#define SF_PKILL_FIREONCE 0x0001 +class CGamePlayerHurt : public CRulePointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } + +private: +}; + +LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ); + + +void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + if ( pActivator->IsPlayer() ) + { + if ( pev->dmg < 0 ) + pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); + else + pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); + } + + SUB_UseTargets( pActivator, useType, value ); + + if ( RemoveOnFire() ) + { + UTIL_Remove( this ); + } +} + + + +// +// CGameCounter / game_counter -- Counts events and fires target +// Flag: Fire once +// Flag: Reset on Fire + +#define SF_GAMECOUNT_FIREONCE 0x0001 +#define SF_GAMECOUNT_RESET 0x0002 + +class CGameCounter : public CRulePointEntity +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } + inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } + + inline void CountUp( void ) { pev->frags++; } + inline void CountDown( void ) { pev->frags--; } + inline void ResetCount( void ) { pev->frags = pev->dmg; } + inline int CountValue( void ) { return pev->frags; } + inline int LimitValue( void ) { return pev->health; } + + inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } + +private: + + inline void SetCountValue( int value ) { pev->frags = value; } + inline void SetInitialValue( int value ) { pev->dmg = value; } +}; + +LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ); + +void CGameCounter::Spawn( void ) +{ + // Save off the initial count + SetInitialValue( CountValue() ); + CRulePointEntity::Spawn(); +} + + +void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + switch( useType ) + { + case USE_ON: + case USE_TOGGLE: + CountUp(); + break; + + case USE_OFF: + CountDown(); + break; + + case USE_SET: + SetCountValue( (int)value ); + break; + } + + if ( HitLimit() ) + { + SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); + if ( RemoveOnFire() ) + { + UTIL_Remove( this ); + } + + if ( ResetOnFire() ) + { + ResetCount(); + } + } +} + + + +// +// CGameCounterSet / game_counter_set -- Sets the counter's value +// Flag: Fire once + +#define SF_GAMECOUNTSET_FIREONCE 0x0001 + +class CGameCounterSet : public CRulePointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } + +private: +}; + +LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ); + + +void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + SUB_UseTargets( pActivator, USE_SET, pev->frags ); + + if ( RemoveOnFire() ) + { + UTIL_Remove( this ); + } +} + + +// +// CGamePlayerEquip / game_playerequip -- Sets the default player equipment +// Flag: USE Only + +#define SF_PLAYEREQUIP_USEONLY 0x0001 +#define MAX_EQUIP 32 + +class CGamePlayerEquip : public CRulePointEntity +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Touch( CBaseEntity *pOther ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } + +private: + + void EquipPlayer( CBaseEntity *pPlayer ); + + string_t m_weaponNames[MAX_EQUIP]; + int m_weaponCount[MAX_EQUIP]; +}; + +LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ); + + +void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) +{ + CRulePointEntity::KeyValue( pkvd ); + + if ( !pkvd->fHandled ) + { + for ( int i = 0; i < MAX_EQUIP; i++ ) + { + if ( !m_weaponNames[i] ) + { + char tmp[128]; + + UTIL_StripToken( pkvd->szKeyName, tmp ); + + m_weaponNames[i] = ALLOC_STRING(tmp); + m_weaponCount[i] = atoi(pkvd->szValue); + m_weaponCount[i] = max(1,m_weaponCount[i]); + pkvd->fHandled = TRUE; + break; + } + } + } +} + + +void CGamePlayerEquip::Touch( CBaseEntity *pOther ) +{ + if ( !CanFireForActivator( pOther ) ) + return; + + if ( UseOnly() ) + return; + + EquipPlayer( pOther ); +} + +void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) +{ + CBasePlayer *pPlayer = NULL; + + if ( pEntity->IsPlayer() ) + { + pPlayer = (CBasePlayer *)pEntity; + } + + if ( !pPlayer ) + return; + + for ( int i = 0; i < MAX_EQUIP; i++ ) + { + if ( !m_weaponNames[i] ) + break; + for ( int j = 0; j < m_weaponCount[i]; j++ ) + { + pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) ); + } + } +} + + +void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + EquipPlayer( pActivator ); +} + + +// +// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it +// Flag: Fire once +// Flag: Kill Player +// Flag: Gib Player + +#define SF_PTEAM_FIREONCE 0x0001 +#define SF_PTEAM_KILL 0x0002 +#define SF_PTEAM_GIB 0x0004 + +class CGamePlayerTeam : public CRulePointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +private: + + inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } + inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } + inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } + + const char *TargetTeamName( const char *pszTargetName ); +}; + +LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ); + + +const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) +{ + CBaseEntity *pTeamEntity = NULL; + + while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL) + { + if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) + return pTeamEntity->TeamID(); + } + + return NULL; +} + + +void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !CanFireForActivator( pActivator ) ) + return; + + if ( pActivator->IsPlayer() ) + { + const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); + if ( pszTargetTeam ) + { + CBasePlayer *pPlayer = (CBasePlayer *)pActivator; + g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); + } + } + + if ( RemoveOnFire() ) + { + UTIL_Remove( this ); + } +} + + diff --git a/main/source/dlls/maprules.cpp~ b/main/source/dlls/maprules.cpp~ deleted file mode 100644 index 1b2df2c3..00000000 --- a/main/source/dlls/maprules.cpp~ +++ /dev/null @@ -1,918 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// ------------------------------------------- -// -// maprules.cpp -// -// This module contains entities for implementing/changing game -// rules dynamically within each map (.BSP) -// -// ------------------------------------------- - -#include "extdll.h" -#include "..engine/eiface.h" -#include "util.h" -#include "gamerules.h" -#include "maprules.h" -#include "cbase.h" -#include "player.h" - -class CRuleEntity : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } - -protected: - BOOL CanFireForActivator( CBaseEntity *pActivator ); - -private: - string_t m_iszMaster; -}; - -TYPEDESCRIPTION CRuleEntity::m_SaveData[] = -{ - DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), -}; - -IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ); - - -void CRuleEntity::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; -} - - -void CRuleEntity::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - SetMaster( ALLOC_STRING(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) -{ - if ( m_iszMaster ) - { - if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) - return TRUE; - else - return FALSE; - } - - return TRUE; -} - -// -// CRulePointEntity -- base class for all rule "point" entities (not brushes) -// -class CRulePointEntity : public CRuleEntity -{ -public: - void Spawn( void ); -}; - -void CRulePointEntity::Spawn( void ) -{ - CRuleEntity::Spawn(); - pev->frame = 0; - pev->model = 0; -} - -// -// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) -// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing -// -class CRuleBrushEntity : public CRuleEntity -{ -public: - void Spawn( void ); - -private: -}; - -void CRuleBrushEntity::Spawn( void ) -{ - SET_MODEL( edict(), STRING(pev->model) ); - CRuleEntity::Spawn(); -} - - -// CGameScore / game_score -- award points to player / team -// Points +/- total -// Flag: Allow negative scores SF_SCORE_NEGATIVE -// Flag: Award points to team in teamplay SF_SCORE_TEAM - -#define SF_SCORE_NEGATIVE 0x0001 -#define SF_SCORE_TEAM 0x0002 - -class CGameScore : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Points( void ) { return pev->frags; } - inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } - inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } - - inline void SetPoints( int points ) { pev->frags = points; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_score, CGameScore ); - - -void CGameScore::Spawn( void ) -{ - CRulePointEntity::Spawn(); -} - - -void CGameScore::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "points")) - { - SetPoints( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - - -void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - // Only players can use this - if ( pActivator->IsPlayer() ) - { - if ( AwardToTeam() ) - { - pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); - } - else - { - pActivator->AddPoints( Points(), AllowNegativeScore() ); - } - } -} - - -// CGameEnd / game_end -- Ends the game in MP - -class CGameEnd : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -private: -}; - -LINK_ENTITY_TO_CLASS( game_end, CGameEnd ); - - -void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - g_pGameRules->EndMultiplayerGame(); -} - - -// -// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) -// Flag: All players SF_ENVTEXT_ALLPLAYERS -// - - -#define SF_ENVTEXT_ALLPLAYERS 0x0001 - - -class CGameText : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } - inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); } - inline const char *MessageGet( void ) { return STRING(pev->message); } - -private: - - hudtextparms_t m_textParms; -}; - -LINK_ENTITY_TO_CLASS( game_text, CGameText ); - -// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so -// it can't impact saved Half-Life games. -TYPEDESCRIPTION CGameText::m_SaveData[] = -{ - DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), -}; - -IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ); - - -void CGameText::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "channel")) - { - m_textParms.channel = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "x")) - { - m_textParms.x = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "y")) - { - m_textParms.y = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "effect")) - { - m_textParms.effect = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r1 = color[0]; - m_textParms.g1 = color[1]; - m_textParms.b1 = color[2]; - m_textParms.a1 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color2")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r2 = color[0]; - m_textParms.g2 = color[1]; - m_textParms.b2 = color[2]; - m_textParms.a2 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_textParms.fadeinTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_textParms.fadeoutTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - m_textParms.holdTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fxtime")) - { - m_textParms.fxTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( MessageToAll() ) - { - UTIL_HudMessageAll( m_textParms, MessageGet() ); - } - else - { - if ( pActivator->IsNetClient() ) - { - UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); - } - } -} - - -// -// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator -// Only allows mastered entity to fire if the team matches my team -// -// team index (pulled from server team list "mp_teamlist" -// Flag: Remove on Fire -// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) -// - -#define SF_TEAMMASTER_FIREONCE 0x0001 -#define SF_TEAMMASTER_ANYTEAM 0x0002 - -class CGameTeamMaster : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } - - BOOL IsTriggered( CBaseEntity *pActivator ); - char* TeamID( void ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } - inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } - -private: - BOOL TeamMatch( CBaseEntity *pActivator ); - - int m_teamIndex; - USE_TYPE triggerType; -}; - -LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ); - -void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "teamindex")) - { - m_teamIndex = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( useType == USE_SET ) - { - if ( value < 0 ) - { - m_teamIndex = -1; - } - else - { - m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); - } - return; - } - - if ( TeamMatch( pActivator ) ) - { - SUB_UseTargets( pActivator, triggerType, value ); - if ( RemoveOnFire() ) - UTIL_Remove( this ); - } -} - - -BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) -{ - return TeamMatch( pActivator ); -} - - -char *CGameTeamMaster::TeamID( void ) -{ - if ( m_teamIndex < 0 ) // Currently set to "no team" - return ""; - - return const_cast(g_pGameRules->GetIndexedTeamName( m_teamIndex )); // UNDONE: Fill this in with the team from the "teamlist" -} - - -BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) -{ - if ( m_teamIndex < 0 && AnyTeam() ) - return TRUE; - - if ( !pActivator ) - return FALSE; - - return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); -} - - -// -// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team -// Flag: Fire once -// Flag: Clear team -- Sets the team to "NONE" instead of activator - -#define SF_TEAMSET_FIREONCE 0x0001 -#define SF_TEAMSET_CLEARTEAM 0x0002 - -class CGameTeamSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ); - - -void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( ShouldClearTeam() ) - { - SUB_UseTargets( pActivator, USE_SET, -1 ); - } - else - { - SUB_UseTargets( pActivator, USE_SET, 0 ); - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired -// -// Needs master? -class CGamePlayerZone : public CRuleBrushEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - string_t m_iszInTarget; - string_t m_iszOutTarget; - string_t m_iszInCount; - string_t m_iszOutCount; -}; - -LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ); -TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = -{ - DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ); - -void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "intarget")) - { - m_iszInTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outtarget")) - { - m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "incount")) - { - m_iszInCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outcount")) - { - m_iszOutCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRuleBrushEntity::KeyValue( pkvd ); -} - -void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int playersInCount = 0; - int playersOutCount = 0; - - if ( !CanFireForActivator( pActivator ) ) - return; - - CBaseEntity *pPlayer = NULL; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - { - TraceResult trace; - int hullNumber; - - hullNumber = human_hull; - if ( pPlayer->pev->flags & FL_DUCKING ) - { - hullNumber = head_hull; - } - - UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); - - if ( trace.fStartSolid ) - { - playersInCount++; - if ( m_iszInTarget ) - { - FireTargets( STRING(m_iszInTarget), pPlayer, pActivator, useType, value ); - } - } - else - { - playersOutCount++; - if ( m_iszOutTarget ) - { - FireTargets( STRING(m_iszOutTarget), pPlayer, pActivator, useType, value ); - } - } - } - } - - if ( m_iszInCount ) - { - FireTargets( STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount ); - } - - if ( m_iszOutCount ) - { - FireTargets( STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount ); - } -} - - - -// -// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it -// Flag: Fire once - -#define SF_PKILL_FIREONCE 0x0001 -class CGamePlayerHurt : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ); - - -void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - if ( pev->dmg < 0 ) - pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); - else - pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); - } - - SUB_UseTargets( pActivator, useType, value ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - - -// -// CGameCounter / game_counter -- Counts events and fires target -// Flag: Fire once -// Flag: Reset on Fire - -#define SF_GAMECOUNT_FIREONCE 0x0001 -#define SF_GAMECOUNT_RESET 0x0002 - -class CGameCounter : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } - inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } - - inline void CountUp( void ) { pev->frags++; } - inline void CountDown( void ) { pev->frags--; } - inline void ResetCount( void ) { pev->frags = pev->dmg; } - inline int CountValue( void ) { return pev->frags; } - inline int LimitValue( void ) { return pev->health; } - - inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } - -private: - - inline void SetCountValue( int value ) { pev->frags = value; } - inline void SetInitialValue( int value ) { pev->dmg = value; } -}; - -LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ); - -void CGameCounter::Spawn( void ) -{ - // Save off the initial count - SetInitialValue( CountValue() ); - CRulePointEntity::Spawn(); -} - - -void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - switch( useType ) - { - case USE_ON: - case USE_TOGGLE: - CountUp(); - break; - - case USE_OFF: - CountDown(); - break; - - case USE_SET: - SetCountValue( (int)value ); - break; - } - - if ( HitLimit() ) - { - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } - - if ( ResetOnFire() ) - { - ResetCount(); - } - } -} - - - -// -// CGameCounterSet / game_counter_set -- Sets the counter's value -// Flag: Fire once - -#define SF_GAMECOUNTSET_FIREONCE 0x0001 - -class CGameCounterSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ); - - -void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - SUB_UseTargets( pActivator, USE_SET, pev->frags ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerEquip / game_playerequip -- Sets the default player equipment -// Flag: USE Only - -#define SF_PLAYEREQUIP_USEONLY 0x0001 -#define MAX_EQUIP 32 - -class CGamePlayerEquip : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } - -private: - - void EquipPlayer( CBaseEntity *pPlayer ); - - string_t m_weaponNames[MAX_EQUIP]; - int m_weaponCount[MAX_EQUIP]; -}; - -LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ); - - -void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) -{ - CRulePointEntity::KeyValue( pkvd ); - - if ( !pkvd->fHandled ) - { - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - - m_weaponNames[i] = ALLOC_STRING(tmp); - m_weaponCount[i] = atoi(pkvd->szValue); - m_weaponCount[i] = max(1,m_weaponCount[i]); - pkvd->fHandled = TRUE; - break; - } - } - } -} - - -void CGamePlayerEquip::Touch( CBaseEntity *pOther ) -{ - if ( !CanFireForActivator( pOther ) ) - return; - - if ( UseOnly() ) - return; - - EquipPlayer( pOther ); -} - -void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pEntity->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pEntity; - } - - if ( !pPlayer ) - return; - - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - break; - for ( int j = 0; j < m_weaponCount[i]; j++ ) - { - pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) ); - } - } -} - - -void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - EquipPlayer( pActivator ); -} - - -// -// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it -// Flag: Fire once -// Flag: Kill Player -// Flag: Gib Player - -#define SF_PTEAM_FIREONCE 0x0001 -#define SF_PTEAM_KILL 0x0002 -#define SF_PTEAM_GIB 0x0004 - -class CGamePlayerTeam : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: - - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } - inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } - - const char *TargetTeamName( const char *pszTargetName ); -}; - -LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ); - - -const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) -{ - CBaseEntity *pTeamEntity = NULL; - - while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL) - { - if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) - return pTeamEntity->TeamID(); - } - - return NULL; -} - - -void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); - if ( pszTargetTeam ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pActivator; - g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); - } - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - diff --git a/main/source/dlls/maprules.h b/main/source/dlls/maprules.h index 8b4867c6..f817e1e9 100644 --- a/main/source/dlls/maprules.h +++ b/main/source/dlls/maprules.h @@ -1,22 +1,22 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef MAPRULES_H -#define MAPRULES_H - - - -#endif // MAPRULES_H - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef MAPRULES_H +#define MAPRULES_H + + + +#endif // MAPRULES_H + diff --git a/main/source/dlls/monsterevent.h b/main/source/dlls/monsterevent.h index 34de4467..df0b0124 100644 --- a/main/source/dlls/monsterevent.h +++ b/main/source/dlls/monsterevent.h @@ -1,34 +1,34 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef MONSTEREVENT_H -#define MONSTEREVENT_H - -typedef struct -{ - int event; - char *options; -} MonsterEvent_t; - -#define EVENT_SPECIFIC 0 -#define EVENT_SCRIPTED 1000 -#define EVENT_SHARED 2000 -#define EVENT_CLIENT 5000 - -#define MONSTER_EVENT_BODYDROP_LIGHT 2001 -#define MONSTER_EVENT_BODYDROP_HEAVY 2002 - -#define MONSTER_EVENT_SWISHSOUND 2010 - -#endif // MONSTEREVENT_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef MONSTEREVENT_H +#define MONSTEREVENT_H + +typedef struct +{ + int event; + char *options; +} MonsterEvent_t; + +#define EVENT_SPECIFIC 0 +#define EVENT_SCRIPTED 1000 +#define EVENT_SHARED 2000 +#define EVENT_CLIENT 5000 + +#define MONSTER_EVENT_BODYDROP_LIGHT 2001 +#define MONSTER_EVENT_BODYDROP_HEAVY 2002 + +#define MONSTER_EVENT_SWISHSOUND 2010 + +#endif // MONSTEREVENT_H diff --git a/main/source/dlls/monstermaker.cpp b/main/source/dlls/monstermaker.cpp index dd53e23d..c9ac768c 100644 --- a/main/source/dlls/monstermaker.cpp +++ b/main/source/dlls/monstermaker.cpp @@ -1,292 +1,292 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Monster Maker - this is an entity that creates monsters -// in the game. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "saverestore.h" - -// Monstermaker spawnflags -#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname ) -#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired. -#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip - -//========================================================= -// MonsterMaker - this ent creates monsters during the game. -//========================================================= -class CMonsterMaker : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MakerThink ( void ); - void DeathNotice ( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died. - void MakeMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_iszMonsterClassname;// classname of the monster(s) that will be created. - - int m_cNumMonsters;// max number of monsters this ent can create - - - int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive - int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time. - - float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child - - BOOL m_fActive; - BOOL m_fFadeChildren;// should we make the children fadeout? -}; - -LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ); - -TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = -{ - DEFINE_FIELD( CMonsterMaker, m_iszMonsterClassname, FIELD_STRING ), - DEFINE_FIELD( CMonsterMaker, m_cNumMonsters, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_cLiveChildren, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_flGround, FIELD_FLOAT ), - DEFINE_FIELD( CMonsterMaker, m_iMaxLiveChildren, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ), -}; - - -IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ); - -void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) -{ - - if ( FStrEq(pkvd->szKeyName, "monstercount") ) - { - m_cNumMonsters = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") ) - { - m_iMaxLiveChildren = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "monstertype") ) - { - m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CMonsterMaker :: Spawn( ) -{ - pev->solid = SOLID_NOT; - - m_cLiveChildren = 0; - Precache(); - if ( !FStringNull ( pev->targetname ) ) - { - if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) - { - SetUse ( &CMonsterMaker::CyclicUse );// drop one monster each time we fire - } - else - { - SetUse ( &CMonsterMaker::ToggleUse );// so can be turned on/off - } - - if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) - {// start making monsters as soon as monstermaker spawns - m_fActive = TRUE; - SetThink ( &CMonsterMaker::MakerThink ); - } - else - {// wait to be activated. - m_fActive = FALSE; - SetThink ( &CMonsterMaker::SUB_DoNothing ); - } - } - else - {// no targetname, just start. - pev->nextthink = gpGlobals->time + m_flDelay; - m_fActive = TRUE; - SetThink ( &CMonsterMaker::MakerThink ); - } - - if ( m_cNumMonsters == 1 ) - { - m_fFadeChildren = FALSE; - } - else - { - m_fFadeChildren = TRUE; - } - - m_flGround = 0; -} - -void CMonsterMaker :: Precache( void ) -{ - CBaseMonster::Precache(); - - UTIL_PrecacheOther( STRING( m_iszMonsterClassname ) ); -} - -//========================================================= -// MakeMonster- this is the code that drops the monster -//========================================================= -void CMonsterMaker::MakeMonster( void ) -{ - edict_t *pent; - entvars_t *pevCreate; - - if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) - {// not allowed to make a new one yet. Too many live ones out right now. - return; - } - - if ( !m_flGround ) - { - // set altitude. Now that I'm activated, any breakables, etc should be out from under me. - TraceResult tr; - - UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); - m_flGround = tr.vecEndPos.z; - } - - Vector mins = pev->origin - Vector( 34, 34, 0 ); - Vector maxs = pev->origin + Vector( 34, 34, 0 ); - maxs.z = pev->origin.z; - mins.z = m_flGround; - - CBaseEntity *pList[2]; - int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); - if ( count ) - { - // don't build a stack of monsters! - return; - } - - pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); - - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); - return; - } - - // If I have a target, fire! - if ( !FStringNull ( pev->target ) ) - { - // delay already overloaded for this entity, so can't call SUB_UseTargets() - FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 ); - } - - pevCreate = VARS( pent ); - pevCreate->origin = pev->origin; - pevCreate->angles = pev->angles; - SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); - - // Children hit monsterclip brushes - if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) - SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); - - DispatchSpawn( ENT( pevCreate ) ); - pevCreate->owner = edict(); - - if ( !FStringNull( pev->netname ) ) - { - // if I have a netname (overloaded), give the child monster that name as a targetname - pevCreate->targetname = pev->netname; - } - - m_cLiveChildren++;// count this monster - m_cNumMonsters--; - - if ( m_cNumMonsters == 0 ) - { - // Disable this forever. Don't kill it because it still gets death notices - SetThink( NULL ); - SetUse( NULL ); - } -} - -//========================================================= -// CyclicUse - drops one monster from the monstermaker -// each time we call this. -//========================================================= -void CMonsterMaker::CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - MakeMonster(); -} - -//========================================================= -// ToggleUse - activates/deactivates the monster maker -//========================================================= -void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_fActive ) ) - return; - - if ( m_fActive ) - { - m_fActive = FALSE; - SetThink ( NULL ); - } - else - { - m_fActive = TRUE; - SetThink ( &CMonsterMaker::MakerThink ); - } - - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// MakerThink - creates a new monster every so often -//========================================================= -void CMonsterMaker :: MakerThink ( void ) -{ - pev->nextthink = gpGlobals->time + m_flDelay; - - MakeMonster(); -} - - -//========================================================= -//========================================================= -void CMonsterMaker :: DeathNotice ( entvars_t *pevChild ) -{ - // ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade. - m_cLiveChildren--; - - if ( !m_fFadeChildren ) - { - pevChild->owner = NULL; - } -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Monster Maker - this is an entity that creates monsters +// in the game. +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "saverestore.h" + +// Monstermaker spawnflags +#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname ) +#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired. +#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip + +//========================================================= +// MonsterMaker - this ent creates monsters during the game. +//========================================================= +class CMonsterMaker : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData* pkvd); + void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT MakerThink ( void ); + void DeathNotice ( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died. + void MakeMonster( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + string_t m_iszMonsterClassname;// classname of the monster(s) that will be created. + + int m_cNumMonsters;// max number of monsters this ent can create + + + int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive + int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time. + + float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child + + BOOL m_fActive; + BOOL m_fFadeChildren;// should we make the children fadeout? +}; + +LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ); + +TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = +{ + DEFINE_FIELD( CMonsterMaker, m_iszMonsterClassname, FIELD_STRING ), + DEFINE_FIELD( CMonsterMaker, m_cNumMonsters, FIELD_INTEGER ), + DEFINE_FIELD( CMonsterMaker, m_cLiveChildren, FIELD_INTEGER ), + DEFINE_FIELD( CMonsterMaker, m_flGround, FIELD_FLOAT ), + DEFINE_FIELD( CMonsterMaker, m_iMaxLiveChildren, FIELD_INTEGER ), + DEFINE_FIELD( CMonsterMaker, m_fActive, FIELD_BOOLEAN ), + DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ), +}; + + +IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ); + +void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) +{ + + if ( FStrEq(pkvd->szKeyName, "monstercount") ) + { + m_cNumMonsters = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") ) + { + m_iMaxLiveChildren = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "monstertype") ) + { + m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseMonster::KeyValue( pkvd ); +} + + +void CMonsterMaker :: Spawn( ) +{ + pev->solid = SOLID_NOT; + + m_cLiveChildren = 0; + Precache(); + if ( !FStringNull ( pev->targetname ) ) + { + if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) + { + SetUse ( &CMonsterMaker::CyclicUse );// drop one monster each time we fire + } + else + { + SetUse ( &CMonsterMaker::ToggleUse );// so can be turned on/off + } + + if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) + {// start making monsters as soon as monstermaker spawns + m_fActive = TRUE; + SetThink ( &CMonsterMaker::MakerThink ); + } + else + {// wait to be activated. + m_fActive = FALSE; + SetThink ( &CMonsterMaker::SUB_DoNothing ); + } + } + else + {// no targetname, just start. + pev->nextthink = gpGlobals->time + m_flDelay; + m_fActive = TRUE; + SetThink ( &CMonsterMaker::MakerThink ); + } + + if ( m_cNumMonsters == 1 ) + { + m_fFadeChildren = FALSE; + } + else + { + m_fFadeChildren = TRUE; + } + + m_flGround = 0; +} + +void CMonsterMaker :: Precache( void ) +{ + CBaseMonster::Precache(); + + UTIL_PrecacheOther( STRING( m_iszMonsterClassname ) ); +} + +//========================================================= +// MakeMonster- this is the code that drops the monster +//========================================================= +void CMonsterMaker::MakeMonster( void ) +{ + edict_t *pent; + entvars_t *pevCreate; + + if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) + {// not allowed to make a new one yet. Too many live ones out right now. + return; + } + + if ( !m_flGround ) + { + // set altitude. Now that I'm activated, any breakables, etc should be out from under me. + TraceResult tr; + + UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); + m_flGround = tr.vecEndPos.z; + } + + Vector mins = pev->origin - Vector( 34, 34, 0 ); + Vector maxs = pev->origin + Vector( 34, 34, 0 ); + maxs.z = pev->origin.z; + mins.z = m_flGround; + + CBaseEntity *pList[2]; + int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); + if ( count ) + { + // don't build a stack of monsters! + return; + } + + pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); + + if ( FNullEnt( pent ) ) + { + ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); + return; + } + + // If I have a target, fire! + if ( !FStringNull ( pev->target ) ) + { + // delay already overloaded for this entity, so can't call SUB_UseTargets() + FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 ); + } + + pevCreate = VARS( pent ); + pevCreate->origin = pev->origin; + pevCreate->angles = pev->angles; + SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); + + // Children hit monsterclip brushes + if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) + SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); + + DispatchSpawn( ENT( pevCreate ) ); + pevCreate->owner = edict(); + + if ( !FStringNull( pev->netname ) ) + { + // if I have a netname (overloaded), give the child monster that name as a targetname + pevCreate->targetname = pev->netname; + } + + m_cLiveChildren++;// count this monster + m_cNumMonsters--; + + if ( m_cNumMonsters == 0 ) + { + // Disable this forever. Don't kill it because it still gets death notices + SetThink( NULL ); + SetUse( NULL ); + } +} + +//========================================================= +// CyclicUse - drops one monster from the monstermaker +// each time we call this. +//========================================================= +void CMonsterMaker::CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + MakeMonster(); +} + +//========================================================= +// ToggleUse - activates/deactivates the monster maker +//========================================================= +void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_fActive ) ) + return; + + if ( m_fActive ) + { + m_fActive = FALSE; + SetThink ( NULL ); + } + else + { + m_fActive = TRUE; + SetThink ( &CMonsterMaker::MakerThink ); + } + + pev->nextthink = gpGlobals->time; +} + +//========================================================= +// MakerThink - creates a new monster every so often +//========================================================= +void CMonsterMaker :: MakerThink ( void ) +{ + pev->nextthink = gpGlobals->time + m_flDelay; + + MakeMonster(); +} + + +//========================================================= +//========================================================= +void CMonsterMaker :: DeathNotice ( entvars_t *pevChild ) +{ + // ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade. + m_cLiveChildren--; + + if ( !m_fFadeChildren ) + { + pevChild->owner = NULL; + } +} + + diff --git a/main/source/dlls/monsters.cpp b/main/source/dlls/monsters.cpp index 5f8ae7ed..90928daa 100644 --- a/main/source/dlls/monsters.cpp +++ b/main/source/dlls/monsters.cpp @@ -1,3448 +1,3448 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== monsters.cpp ======================================================== - - Monster-related utility code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "weapons.h" -#include "scripted.h" -#include "squadmonster.h" -#include "decals.h" -#include "soundent.h" -#include "gamerules.h" - -#define MONSTER_CUT_CORNER_DIST 8 // 8 means the monster's bounding box is contained without the box of the node in WC - - -Vector VecBModelOrigin( entvars_t* pevBModel ); - -extern DLL_GLOBAL BOOL g_fDrawLines; -extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam -extern DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot - -extern CGraph WorldGraph;// the world node graph - - - -// Global Savedata for monster -// UNDONE: Save schedule data? Can this be done? We may -// lose our enemy pointer or other data (goal ent, target, etc) -// that make the current schedule invalid, perhaps it's best -// to just pick a new one when we start up again. -TYPEDESCRIPTION CBaseMonster::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMonster, m_hEnemy, FIELD_EHANDLE ), - DEFINE_FIELD( CBaseMonster, m_hTargetEnt, FIELD_EHANDLE ), - DEFINE_ARRAY( CBaseMonster, m_hOldEnemy, FIELD_EHANDLE, MAX_OLD_ENEMIES ), - DEFINE_ARRAY( CBaseMonster, m_vecOldEnemy, FIELD_POSITION_VECTOR, MAX_OLD_ENEMIES ), - DEFINE_FIELD( CBaseMonster, m_flFieldOfView, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flWaitFinished, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_flMoveWaitFinished, FIELD_TIME ), - - DEFINE_FIELD( CBaseMonster, m_Activity, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_IdealActivity, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_LastHitGroup, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_MonsterState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_IdealMonsterState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iTaskStatus, FIELD_INTEGER ), - - //Schedule_t *m_pSchedule; - - DEFINE_FIELD( CBaseMonster, m_iScheduleIndex, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_afConditions, FIELD_INTEGER ), - //WayPoint_t m_Route[ ROUTE_SIZE ]; -// DEFINE_FIELD( CBaseMonster, m_movementGoal, FIELD_INTEGER ), -// DEFINE_FIELD( CBaseMonster, m_iRouteIndex, FIELD_INTEGER ), -// DEFINE_FIELD( CBaseMonster, m_moveWaitTime, FIELD_FLOAT ), - - DEFINE_FIELD( CBaseMonster, m_vecMoveGoal, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMonster, m_movementActivity, FIELD_INTEGER ), - - // int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. -// DEFINE_FIELD( CBaseMonster, m_afSoundTypes, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_vecLastPosition, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMonster, m_iHintNode, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_afMemory, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iMaxHealth, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseMonster, m_vecEnemyLKP, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMonster, m_cAmmoLoaded, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_afCapability, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseMonster, m_flNextAttack, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_bitsDamageType, FIELD_INTEGER ), - DEFINE_ARRAY( CBaseMonster, m_rgbTimeBasedDamage, FIELD_CHARACTER, CDMG_TIMEBASED ), - DEFINE_FIELD( CBaseMonster, m_bloodColor, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_failSchedule, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseMonster, m_flHungryTime, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_flDistTooFar, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flDistLook, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_iTriggerCondition, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iszTriggerTarget, FIELD_STRING ), - - DEFINE_FIELD( CBaseMonster, m_HackedGunPos, FIELD_VECTOR ), - - DEFINE_FIELD( CBaseMonster, m_scriptState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_pCine, FIELD_CLASSPTR ), -}; - -//IMPLEMENT_SAVERESTORE( CBaseMonster, CBaseToggle ); -int CBaseMonster::Save( CSave &save ) -{ - if ( !CBaseToggle::Save(save) ) - return 0; - return save.WriteFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); -} - -int CBaseMonster::Restore( CRestore &restore ) -{ - if ( !CBaseToggle::Restore(restore) ) - return 0; - int status = restore.ReadFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - - // We don't save/restore routes yet - RouteClear(); - - // We don't save/restore schedules yet - m_pSchedule = NULL; - m_iTaskStatus = TASKSTATUS_NEW; - - // Reset animation - m_Activity = ACT_RESET; - - // If we don't have an enemy, clear conditions like see enemy, etc. - if ( m_hEnemy == NULL ) - m_afConditions = 0; - - return status; -} - - -//========================================================= -// Eat - makes a monster full for a little while. -//========================================================= -void CBaseMonster :: Eat ( float flFullDuration ) -{ - m_flHungryTime = gpGlobals->time + flFullDuration; -} - -//========================================================= -// FShouldEat - returns true if a monster is hungry. -//========================================================= -BOOL CBaseMonster :: FShouldEat ( void ) -{ - if ( m_flHungryTime > gpGlobals->time ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// BarnacleVictimBitten - called -// by Barnacle victims when the barnacle pulls their head -// into its mouth -//========================================================= -void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) -{ - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( SCHED_BARNACLE_VICTIM_CHOMP ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } -} - -//========================================================= -// BarnacleVictimReleased - called by barnacle victims when -// the host barnacle is killed. -//========================================================= -void CBaseMonster :: BarnacleVictimReleased ( void ) -{ - m_IdealMonsterState = MONSTERSTATE_IDLE; - - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_STEP; -} - -//========================================================= -// Listen - monsters dig through the active sound list for -// any sounds that may interest them. (smells, too!) -//========================================================= -void CBaseMonster :: Listen ( void ) -{ - int iSound; - int iMySounds; - float hearingSensitivity; - CSound *pCurrentSound; - - m_iAudibleList = SOUNDLIST_EMPTY; - ClearConditions(bits_COND_HEAR_SOUND | bits_COND_SMELL | bits_COND_SMELL_FOOD); - m_afSoundTypes = 0; - - iMySounds = ISoundMask(); - - if ( m_pSchedule ) - { - //!!!WATCH THIS SPOT IF YOU ARE HAVING SOUND RELATED BUGS! - // Make sure your schedule AND personal sound masks agree! - iMySounds &= m_pSchedule->iSoundMask; - } - - iSound = CSoundEnt::ActiveList(); - - // UNDONE: Clear these here? - ClearConditions( bits_COND_HEAR_SOUND | bits_COND_SMELL_FOOD | bits_COND_SMELL ); - hearingSensitivity = HearingSensitivity( ); - - while ( iSound != SOUNDLIST_EMPTY ) - { - pCurrentSound = CSoundEnt::SoundPointerForIndex( iSound ); - - if ( pCurrentSound && - ( pCurrentSound->m_iType & iMySounds ) && - ( pCurrentSound->m_vecOrigin - EarPosition() ).Length() <= pCurrentSound->m_iVolume * hearingSensitivity ) - - //if ( ( g_pSoundEnt->m_SoundPool[ iSound ].m_iType & iMySounds ) && ( g_pSoundEnt->m_SoundPool[ iSound ].m_vecOrigin - EarPosition()).Length () <= g_pSoundEnt->m_SoundPool[ iSound ].m_iVolume * hearingSensitivity ) - { - // the monster cares about this sound, and it's close enough to hear. - //g_pSoundEnt->m_SoundPool[ iSound ].m_iNextAudible = m_iAudibleList; - pCurrentSound->m_iNextAudible = m_iAudibleList; - - if ( pCurrentSound->FIsSound() ) - { - // this is an audible sound. - SetConditions( bits_COND_HEAR_SOUND ); - } - else - { - // if not a sound, must be a smell - determine if it's just a scent, or if it's a food scent -// if ( g_pSoundEnt->m_SoundPool[ iSound ].m_iType & ( bits_SOUND_MEAT | bits_SOUND_CARCASS ) ) - if ( pCurrentSound->m_iType & ( bits_SOUND_MEAT | bits_SOUND_CARCASS ) ) - { - // the detected scent is a food item, so set both conditions. - // !!!BUGBUG - maybe a virtual function to determine whether or not the scent is food? - SetConditions( bits_COND_SMELL_FOOD ); - SetConditions( bits_COND_SMELL ); - } - else - { - // just a normal scent. - SetConditions( bits_COND_SMELL ); - } - } - -// m_afSoundTypes |= g_pSoundEnt->m_SoundPool[ iSound ].m_iType; - m_afSoundTypes |= pCurrentSound->m_iType; - - m_iAudibleList = iSound; - } - -// iSound = g_pSoundEnt->m_SoundPool[ iSound ].m_iNext; - iSound = pCurrentSound->m_iNext; - } -} - -//========================================================= -// FLSoundVolume - subtracts the volume of the given sound -// from the distance the sound source is from the caller, -// and returns that value, which is considered to be the 'local' -// volume of the sound. -//========================================================= -float CBaseMonster :: FLSoundVolume ( CSound *pSound ) -{ - return ( pSound->m_iVolume - ( ( pSound->m_vecOrigin - pev->origin ).Length() ) ); -} - -//========================================================= -// FValidateHintType - tells use whether or not the monster cares -// about the type of Hint Node given -//========================================================= -BOOL CBaseMonster :: FValidateHintType ( short sHint ) -{ - return FALSE; -} - -//========================================================= -// Look - Base class monster function to find enemies or -// food by sight. iDistance is distance ( in units ) that the -// monster can see. -// -// Sets the sight bits of the m_afConditions mask to indicate -// which types of entities were sighted. -// Function also sets the Looker's m_pLink -// to the head of a link list that contains all visible ents. -// (linked via each ent's m_pLink field) -// -//========================================================= -void CBaseMonster :: Look ( int iDistance ) -{ - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); - - m_pLink = NULL; - - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - - // See no evil if prisoner is set - if ( !FBitSet( pev->spawnflags, SF_MONSTER_PRISONER ) ) - { - CBaseEntity *pList[100]; - - Vector delta = Vector( iDistance, iDistance, iDistance ); - - // Find only monsters/clients in box, NOT limited to PVS - int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); - for ( int i = 0; i < count; i++ ) - { - pSightEnt = pList[i]; - // !!!temporarily only considering other monsters and clients, don't see prisoners - if ( pSightEnt != this && - !FBitSet( pSightEnt->pev->spawnflags, SF_MONSTER_PRISONER ) && - pSightEnt->pev->health > 0 ) - { - // the looker will want to consider this entity - // don't check anything else about an entity that can't be seen, or an entity that you don't care about. - if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) - { - if ( pSightEnt->IsPlayer() ) - { - if ( pev->spawnflags & SF_MONSTER_WAIT_TILL_SEEN ) - { - CBaseMonster *pClient; - - pClient = pSightEnt->MyMonsterPointer(); - // don't link this client in the list if the monster is wait till seen and the player isn't facing the monster - if ( pSightEnt && !pClient->FInViewCone( this ) ) - { - // we're not in the player's view cone. - continue; - } - else - { - // player sees us, become normal now. - pev->spawnflags &= ~SF_MONSTER_WAIT_TILL_SEEN; - } - } - - // if we see a client, remember that (mostly for scripted AI) - iSighted |= bits_COND_SEE_CLIENT; - } - - pSightEnt->m_pLink = m_pLink; - m_pLink = pSightEnt; - - if ( pSightEnt == m_hEnemy ) - { - // we know this ent is visible, so if it also happens to be our enemy, store that now. - iSighted |= bits_COND_SEE_ENEMY; - } - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch ( IRelationship ( pSightEnt ) ) - { - case R_NM: - iSighted |= bits_COND_SEE_NEMESIS; - break; - case R_HT: - iSighted |= bits_COND_SEE_HATE; - break; - case R_DL: - iSighted |= bits_COND_SEE_DISLIKE; - break; - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_AL: - break; - default: - ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - } - - SetConditions( iSighted ); -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CBaseMonster :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER; -} - -//========================================================= -// PBestSound - returns a pointer to the sound the monster -// should react to. Right now responds only to nearest sound. -//========================================================= -CSound* CBaseMonster :: PBestSound ( void ) -{ - int iThisSound; - int iBestSound = -1; - float flBestDist = 8192;// so first nearby sound will become best so far. - float flDist; - CSound *pSound; - - iThisSound = m_iAudibleList; - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_aiconsole, "ERROR! monster %s has no audible sounds!\n", STRING(pev->classname) ); -#if _DEBUG - ALERT( at_error, "NULL Return from PBestSound\n" ); -#endif - return NULL; - } - - while ( iThisSound != SOUNDLIST_EMPTY ) - { - pSound = CSoundEnt::SoundPointerForIndex( iThisSound ); - - if ( pSound && pSound->FIsSound() ) - { - flDist = ( pSound->m_vecOrigin - EarPosition()).Length(); - - if ( flDist < flBestDist ) - { - iBestSound = iThisSound; - flBestDist = flDist; - } - } - - iThisSound = pSound->m_iNextAudible; - } - if ( iBestSound >= 0 ) - { - pSound = CSoundEnt::SoundPointerForIndex( iBestSound ); - return pSound; - } -#if _DEBUG - ALERT( at_error, "NULL Return from PBestSound\n" ); -#endif - return NULL; -} - -//========================================================= -// PBestScent - returns a pointer to the scent the monster -// should react to. Right now responds only to nearest scent -//========================================================= -CSound* CBaseMonster :: PBestScent ( void ) -{ - int iThisScent; - int iBestScent = -1; - float flBestDist = 8192;// so first nearby smell will become best so far. - float flDist; - CSound *pSound; - - iThisScent = m_iAudibleList;// smells are in the sound list. - - if ( iThisScent == SOUNDLIST_EMPTY ) - { - ALERT ( at_aiconsole, "ERROR! PBestScent() has empty soundlist!\n" ); -#if _DEBUG - ALERT( at_error, "NULL Return from PBestSound\n" ); -#endif - return NULL; - } - - while ( iThisScent != SOUNDLIST_EMPTY ) - { - pSound = CSoundEnt::SoundPointerForIndex( iThisScent ); - - if ( pSound->FIsScent() ) - { - flDist = ( pSound->m_vecOrigin - pev->origin ).Length(); - - if ( flDist < flBestDist ) - { - iBestScent = iThisScent; - flBestDist = flDist; - } - } - - iThisScent = pSound->m_iNextAudible; - } - if ( iBestScent >= 0 ) - { - pSound = CSoundEnt::SoundPointerForIndex( iBestScent ); - - return pSound; - } -#if _DEBUG - ALERT( at_error, "NULL Return from PBestScent\n" ); -#endif - return NULL; -} - - - -//========================================================= -// Monster Think - calls out to core AI functions and handles this -// monster's specific animation events -//========================================================= -void CBaseMonster :: MonsterThink ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking. - - - RunAI(); - - float flInterval = StudioFrameAdvance( ); // animate -// start or end a fidget -// This needs a better home -- switching animations over time should be encapsulated on a per-activity basis -// perhaps MaintainActivity() or a ShiftAnimationOverTime() or something. - if ( m_MonsterState != MONSTERSTATE_SCRIPT && m_MonsterState != MONSTERSTATE_DEAD && m_Activity == ACT_IDLE && m_fSequenceFinished ) - { - int iSequence; - - if ( m_fSequenceLoops ) - { - // animation does loop, which means we're playing subtle idle. Might need to - // fidget. - iSequence = LookupActivity ( m_Activity ); - } - else - { - // animation that just ended doesn't loop! That means we just finished a fidget - // and should return to our heaviest weighted idle (the subtle one) - iSequence = LookupActivityHeaviest ( m_Activity ); - } - if ( iSequence != ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = iSequence; // Set to new anim (if it's there) - ResetSequenceInfo( ); - } - } - - DispatchAnimEvents( flInterval ); - - if ( !MovementIsComplete() ) - { - Move( flInterval ); - } -#if _DEBUG - else - { - if ( !TaskIsRunning() && !TaskIsComplete() ) - ALERT( at_error, "Schedule stalled!!\n" ); - } -#endif -} - -//========================================================= -// CBaseMonster - USE - will make a monster angry at whomever -// activated it. -//========================================================= -void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_IdealMonsterState = MONSTERSTATE_ALERT; -} - -//========================================================= -// Ignore conditions - before a set of conditions is allowed -// to interrupt a monster's schedule, this function removes -// conditions that we have flagged to interrupt the current -// schedule, but may not want to interrupt the schedule every -// time. (Pain, for instance) -//========================================================= -int CBaseMonster :: IgnoreConditions ( void ) -{ - int iIgnoreConditions = 0; - - if ( !FShouldEat() ) - { - // not hungry? Ignore food smell. - iIgnoreConditions |= bits_COND_SMELL_FOOD; - } - - if ( m_MonsterState == MONSTERSTATE_SCRIPT && m_pCine ) - iIgnoreConditions |= m_pCine->IgnoreConditions(); - - return iIgnoreConditions; -} - -//========================================================= -// RouteClear - zeroes out the monster's route array and goal -//========================================================= -void CBaseMonster :: RouteClear ( void ) -{ - RouteNew(); - m_movementGoal = MOVEGOAL_NONE; - m_movementActivity = ACT_IDLE; - Forget( bits_MEMORY_MOVE_FAILED ); -} - -//========================================================= -// Route New - clears out a route to be changed, but keeps -// goal intact. -//========================================================= -void CBaseMonster :: RouteNew ( void ) -{ - m_Route[ 0 ].iType = 0; - m_iRouteIndex = 0; -} - -//========================================================= -// FRouteClear - returns TRUE is the Route is cleared out -// ( invalid ) -//========================================================= -BOOL CBaseMonster :: FRouteClear ( void ) -{ - if ( m_Route[ m_iRouteIndex ].iType == 0 || m_movementGoal == MOVEGOAL_NONE ) - return TRUE; - - return FALSE; -} - -//========================================================= -// FRefreshRoute - after calculating a path to the monster's -// target, this function copies as many waypoints as possible -// from that path to the monster's Route array -//========================================================= -BOOL CBaseMonster :: FRefreshRoute ( void ) -{ - CBaseEntity *pPathCorner; - int i; - BOOL returnCode; - - RouteNew(); - - returnCode = FALSE; - - switch( m_movementGoal ) - { - case MOVEGOAL_PATHCORNER: - { - // monster is on a path_corner loop - pPathCorner = m_pGoalEnt; - i = 0; - - while ( pPathCorner && i < ROUTE_SIZE ) - { - m_Route[ i ].iType = bits_MF_TO_PATHCORNER; - m_Route[ i ].vecLocation = pPathCorner->pev->origin; - - pPathCorner = pPathCorner->GetNextTarget(); - - // Last path_corner in list? - if ( !pPathCorner ) - m_Route[i].iType |= bits_MF_IS_GOAL; - - i++; - } - } - returnCode = TRUE; - break; - - case MOVEGOAL_ENEMY: - returnCode = BuildRoute( m_vecEnemyLKP, bits_MF_TO_ENEMY, m_hEnemy ); - break; - - case MOVEGOAL_LOCATION: - returnCode = BuildRoute( m_vecMoveGoal, bits_MF_TO_LOCATION, NULL ); - break; - - case MOVEGOAL_TARGETENT: - if (m_hTargetEnt != NULL) - { - returnCode = BuildRoute( m_hTargetEnt->pev->origin, bits_MF_TO_TARGETENT, m_hTargetEnt ); - } - break; - - case MOVEGOAL_NODE: - returnCode = FGetNodeRoute( m_vecMoveGoal ); -// if ( returnCode ) -// RouteSimplify( NULL ); - break; - } - - return returnCode; -} - - -BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_ENEMY; - return FRefreshRoute(); -} - - -BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_LOCATION; - m_vecMoveGoal = goal; - return FRefreshRoute(); -} - - -BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_TARGETENT; - return FRefreshRoute(); -} - - -BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_NODE; - m_vecMoveGoal = goal; - return FRefreshRoute(); -} - - -#ifdef _DEBUG -void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ) -{ - int i; - - if ( m_Route[m_iRouteIndex].iType == 0 ) - { - ALERT( at_aiconsole, "Can't draw route!\n" ); - return; - } - -// UTIL_ParticleEffect ( m_Route[ m_iRouteIndex ].vecLocation, g_vecZero, 255, 25 ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.x ); - WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.y ); - WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.z ); - - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 1 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( r ); // r, g, b - WRITE_BYTE( g ); // r, g, b - WRITE_BYTE( b ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - for ( i = m_iRouteIndex ; i < ROUTE_SIZE - 1; i++ ) - { - if ( (m_Route[ i ].iType & bits_MF_IS_GOAL) || (m_Route[ i+1 ].iType == 0) ) - break; - - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS ); - WRITE_COORD( m_Route[ i ].vecLocation.x ); - WRITE_COORD( m_Route[ i ].vecLocation.y ); - WRITE_COORD( m_Route[ i ].vecLocation.z ); - WRITE_COORD( m_Route[ i + 1 ].vecLocation.x ); - WRITE_COORD( m_Route[ i + 1 ].vecLocation.y ); - WRITE_COORD( m_Route[ i + 1 ].vecLocation.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 1 ); // life - WRITE_BYTE( 8 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( r ); // r, g, b - WRITE_BYTE( g ); // r, g, b - WRITE_BYTE( b ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - -// UTIL_ParticleEffect ( m_Route[ i ].vecLocation, g_vecZero, 255, 25 ); - } -} -#endif - - -int ShouldSimplify( int routeType ) -{ - routeType &= ~bits_MF_IS_GOAL; - - if ( (routeType == bits_MF_TO_PATHCORNER) || (routeType & bits_MF_DONT_SIMPLIFY) ) - return FALSE; - return TRUE; -} - -//========================================================= -// RouteSimplify -// -// Attempts to make the route more direct by cutting out -// unnecessary nodes & cutting corners. -// -//========================================================= -void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) -{ - // BUGBUG: this doesn't work 100% yet - int i, count, outCount; - Vector vecStart; - WayPoint_t outRoute[ ROUTE_SIZE * 2 ]; // Any points except the ends can turn into 2 points in the simplified route - - count = 0; - - for ( i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) - { - if ( !m_Route[i].iType ) - break; - else - count++; - if ( m_Route[i].iType & bits_MF_IS_GOAL ) - break; - } - // Can't simplify a direct route! - if ( count < 2 ) - { -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); - return; - } - - outCount = 0; - vecStart = pev->origin; - for ( i = 0; i < count-1; i++ ) - { - // Don't eliminate path_corners - if ( !ShouldSimplify( m_Route[m_iRouteIndex+i].iType ) ) - { - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; - outCount++; - } - else if ( CheckLocalMove ( vecStart, m_Route[m_iRouteIndex+i+1].vecLocation, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - // Skip vert - continue; - } - else - { - Vector vecTest, vecSplit; - - // Halfway between this and next - vecTest = (m_Route[m_iRouteIndex+i+1].vecLocation + m_Route[m_iRouteIndex+i].vecLocation) * 0.5; - - // Halfway between this and previous - vecSplit = (m_Route[m_iRouteIndex+i].vecLocation + vecStart) * 0.5; - - int iType = (m_Route[m_iRouteIndex+i].iType | bits_MF_TO_DETOUR) & ~bits_MF_NOT_TO_MASK; - if ( CheckLocalMove ( vecStart, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - outRoute[outCount].iType = iType; - outRoute[outCount].vecLocation = vecTest; - } - else if ( CheckLocalMove ( vecSplit, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - outRoute[outCount].iType = iType; - outRoute[outCount].vecLocation = vecSplit; - outRoute[outCount+1].iType = iType; - outRoute[outCount+1].vecLocation = vecTest; - outCount++; // Adding an extra point - } - else - { - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; - } - } - // Get last point - vecStart = outRoute[ outCount ].vecLocation; - outCount++; - } - ASSERT( i < count ); - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; - outCount++; - - // Terminate - outRoute[outCount].iType = 0; - ASSERT( outCount < (ROUTE_SIZE*2) ); - -// Copy the simplified route, disable for testing - m_iRouteIndex = 0; - for ( i = 0; i < ROUTE_SIZE && i < outCount; i++ ) - { - m_Route[i] = outRoute[i]; - } - - // Terminate route - if ( i < ROUTE_SIZE ) - m_Route[i].iType = 0; - -// Debug, test movement code -#if 0 -// if ( CVAR_GET_FLOAT( "simplify" ) != 0 ) - DrawRoute( pev, outRoute, 0, 255, 0, 0 ); -// else - DrawRoute( pev, m_Route, m_iRouteIndex, 0, 255, 0 ); -#endif -} - -//========================================================= -// FBecomeProne - tries to send a monster into PRONE state. -// right now only used when a barnacle snatches someone, so -// may have some special case stuff for that. -//========================================================= -BOOL CBaseMonster :: FBecomeProne ( void ) -{ - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - pev->flags -= FL_ONGROUND; - } - - m_IdealMonsterState = MONSTERSTATE_PRONE; - return TRUE; -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 -//========================================================= -BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if ( flDist > 64 && flDist <= 512 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - // Decent fix to keep folks from kicking/punching hornets and snarks is to check the onground flag(sjb) - if ( flDist <= 64 && flDot >= 0.7 && m_hEnemy != NULL && FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack2 -//========================================================= -BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) -{ - if ( flDist <= 64 && flDot >= 0.7 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckAttacks - sets all of the bits for attacks that the -// monster is capable of carrying out on the passed entity. -//========================================================= -void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( pTarget->pev->origin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - // we know the enemy is in front now. We'll find which attacks the monster is capable of by - // checking for corresponding Activities in the model file, then do the simple checks to validate - // those attack types. - - // Clear all attack conditions - ClearConditions( bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK1 |bits_COND_CAN_MELEE_ATTACK2 ); - - if ( m_afCapability & bits_CAP_RANGE_ATTACK1 ) - { - if ( CheckRangeAttack1 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_RANGE_ATTACK1 ); - } - if ( m_afCapability & bits_CAP_RANGE_ATTACK2 ) - { - if ( CheckRangeAttack2 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_RANGE_ATTACK2 ); - } - if ( m_afCapability & bits_CAP_MELEE_ATTACK1 ) - { - if ( CheckMeleeAttack1 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); - } - if ( m_afCapability & bits_CAP_MELEE_ATTACK2 ) - { - if ( CheckMeleeAttack2 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_MELEE_ATTACK2 ); - } -} - -//========================================================= -// CanCheckAttacks - prequalifies a monster to do more fine -// checking of potential attacks. -//========================================================= -BOOL CBaseMonster :: FCanCheckAttacks ( void ) -{ - if ( HasConditions(bits_COND_SEE_ENEMY) && !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckEnemy - part of the Condition collection process, -// gets and stores data and conditions pertaining to a monster's -// enemy. Returns TRUE if Enemy LKP was updated. -//========================================================= -int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) -{ - float flDistToEnemy; - int iUpdatedLKP;// set this to TRUE if you update the EnemyLKP in this function. - - iUpdatedLKP = FALSE; - ClearConditions ( bits_COND_ENEMY_FACING_ME ); - - if ( !FVisible( pEnemy ) ) - { - ASSERT(!HasConditions(bits_COND_SEE_ENEMY)); - SetConditions( bits_COND_ENEMY_OCCLUDED ); - } - else - ClearConditions( bits_COND_ENEMY_OCCLUDED ); - - if ( !pEnemy->IsAlive() ) - { - SetConditions ( bits_COND_ENEMY_DEAD ); - ClearConditions( bits_COND_SEE_ENEMY | bits_COND_ENEMY_OCCLUDED ); - return FALSE; - } - - Vector vecEnemyPos = pEnemy->pev->origin; - // distance to enemy's origin - flDistToEnemy = ( vecEnemyPos - pev->origin ).Length(); - vecEnemyPos.z += pEnemy->pev->size.z * 0.5; - // distance to enemy's head - float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); - if (flDistToEnemy2 < flDistToEnemy) - flDistToEnemy = flDistToEnemy2; - else - { - // distance to enemy's feet - vecEnemyPos.z -= pEnemy->pev->size.z; - float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); - if (flDistToEnemy2 < flDistToEnemy) - flDistToEnemy = flDistToEnemy2; - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - { - CBaseMonster *pEnemyMonster; - - iUpdatedLKP = TRUE; - m_vecEnemyLKP = pEnemy->pev->origin; - - pEnemyMonster = pEnemy->MyMonsterPointer(); - - if ( pEnemyMonster ) - { - if ( pEnemyMonster->FInViewCone ( this ) ) - { - SetConditions ( bits_COND_ENEMY_FACING_ME ); - } - else - ClearConditions( bits_COND_ENEMY_FACING_ME ); - } - - if (pEnemy->pev->velocity != Vector( 0, 0, 0)) - { - // trail the enemy a bit - m_vecEnemyLKP = m_vecEnemyLKP - pEnemy->pev->velocity * RANDOM_FLOAT( -0.05, 0 ); - } - else - { - // UNDONE: use pev->oldorigin? - } - } - else if ( !HasConditions(bits_COND_ENEMY_OCCLUDED|bits_COND_SEE_ENEMY) && ( flDistToEnemy <= 256 ) ) - { - // if the enemy is not occluded, and unseen, that means it is behind or beside the monster. - // if the enemy is near enough the monster, we go ahead and let the monster know where the - // enemy is. - iUpdatedLKP = TRUE; - m_vecEnemyLKP = pEnemy->pev->origin; - } - - if ( flDistToEnemy >= m_flDistTooFar ) - { - // enemy is very far away from monster - SetConditions( bits_COND_ENEMY_TOOFAR ); - } - else - ClearConditions( bits_COND_ENEMY_TOOFAR ); - - if ( FCanCheckAttacks() ) - { - CheckAttacks ( m_hEnemy, flDistToEnemy ); - } - - if ( m_movementGoal == MOVEGOAL_ENEMY ) - { - for ( int i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) - { - if ( m_Route[ i ].iType == (bits_MF_IS_GOAL|bits_MF_TO_ENEMY) ) - { - // UNDONE: Should we allow monsters to override this distance (80?) - if ( (m_Route[ i ].vecLocation - m_vecEnemyLKP).Length() > 80 ) - { - // Refresh - FRefreshRoute(); - return iUpdatedLKP; - } - } - } - } - - return iUpdatedLKP; -} - -//========================================================= -// PushEnemy - remember the last few enemies, always remember the player -//========================================================= -void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) -{ - int i; - - if (pEnemy == NULL) - return; - - // UNDONE: blah, this is bad, we should use a stack but I'm too lazy to code one. - for (i = 0; i < MAX_OLD_ENEMIES; i++) - { - if (m_hOldEnemy[i] == pEnemy) - return; - if (m_hOldEnemy[i] == NULL) // someone died, reuse their slot - break; - } - if (i >= MAX_OLD_ENEMIES) - return; - - m_hOldEnemy[i] = pEnemy; - m_vecOldEnemy[i] = vecLastKnownPos; -} - -//========================================================= -// PopEnemy - try remembering the last few enemies -//========================================================= -BOOL CBaseMonster :: PopEnemy( ) -{ - // UNDONE: blah, this is bad, we should use a stack but I'm too lazy to code one. - for (int i = MAX_OLD_ENEMIES - 1; i >= 0; i--) - { - if (m_hOldEnemy[i] != NULL) - { - if (m_hOldEnemy[i]->IsAlive( )) // cheat and know when they die - { - m_hEnemy = m_hOldEnemy[i]; - m_vecEnemyLKP = m_vecOldEnemy[i]; - // ALERT( at_console, "remembering\n"); - return TRUE; - } - else - { - m_hOldEnemy[i] = NULL; - } - } - } - return FALSE; -} - -//========================================================= -// SetActivity -//========================================================= -void CBaseMonster :: SetActivity ( Activity NewActivity ) -{ - int iSequence; - - iSequence = LookupActivity ( NewActivity ); - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - // don't reset frame between walk and run - if ( !(m_Activity == ACT_WALK || m_Activity == ACT_RUN) || !(NewActivity == ACT_WALK || NewActivity == ACT_RUN)) - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_aiconsole, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // In case someone calls this with something other than the ideal activity - m_IdealActivity = m_Activity; - - -} - -//========================================================= -// SetSequenceByName -//========================================================= -void CBaseMonster :: SetSequenceByName ( char *szSequence ) -{ - int iSequence; - - iSequence = LookupSequence ( szSequence ); - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_aiconsole, "%s has no sequence named:%f\n", STRING(pev->classname), szSequence ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} - -//========================================================= -// CheckLocalMove - returns TRUE if the caller can walk a -// straight line from its current origin to the given -// location. If so, don't use the node graph! -// -// if a valid pointer to a int is passed, the function -// will fill that int with the distance that the check -// reached before hitting something. THIS ONLY HAPPENS -// IF THE LOCAL MOVE CHECK FAILS! -// -// !!!PERFORMANCE - should we try to load balance this? -// DON"T USE SETORIGIN! -//========================================================= -#define LOCAL_STEP_SIZE 16 -int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - Vector vecStartPos;// record monster's position before trying the move - float flYaw; - float flDist; - float flStep, stepSize; - int iReturn; - - vecStartPos = pev->origin; - - - flYaw = UTIL_VecToYaw ( vecEnd - vecStart );// build a yaw that points to the goal. - flDist = ( vecEnd - vecStart ).Length2D();// get the distance. - iReturn = LOCALMOVE_VALID;// assume everything will be ok. - - // move the monster to the start of the local move that's to be checked. - UTIL_SetOrigin( pev, vecStart );// !!!BUGBUG - won't this fire triggers? - nope, SetOrigin doesn't fire - - if ( !(pev->flags & (FL_FLY|FL_SWIM)) ) - { - DROP_TO_FLOOR( ENT( pev ) );//make sure monster is on the floor! - } - - //pev->origin.z = vecStartPos.z;//!!!HACKHACK - -// pev->origin = vecStart; - -/* - if ( flDist > 1024 ) - { - // !!!PERFORMANCE - this operation may be too CPU intensive to try checks this large. - // We don't lose much here, because a distance this great is very likely - // to have something in the way. - - // since we've actually moved the monster during the check, undo the move. - pev->origin = vecStartPos; - return FALSE; - } -*/ - // this loop takes single steps to the goal. - for ( flStep = 0 ; flStep < flDist ; flStep += LOCAL_STEP_SIZE ) - { - stepSize = LOCAL_STEP_SIZE; - - if ( (flStep + LOCAL_STEP_SIZE) >= (flDist-1) ) - stepSize = (flDist - flStep) - 1; - -// UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); - - if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, WALKMOVE_CHECKONLY ) ) - {// can't take the next step, fail! - - if ( pflDist != NULL ) - { - *pflDist = flStep; - } - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - { - // if this step hits target ent, the move is legal. - iReturn = LOCALMOVE_VALID; - break; - } - else - { - // If we're going toward an entity, and we're almost getting there, it's OK. -// if ( pTarget && fabs( flDist - iStep ) < LOCAL_STEP_SIZE ) -// fReturn = TRUE; -// else - iReturn = LOCALMOVE_INVALID; - break; - } - - } - } - - if ( iReturn == LOCALMOVE_VALID && !(pev->flags & (FL_FLY|FL_SWIM) ) && (!pTarget || (pTarget->pev->flags & FL_ONGROUND)) ) - { - // The monster can move to a spot UNDER the target, but not to it. Don't try to triangulate, go directly to the node graph. - // UNDONE: Magic # 64 -- this used to be pev->size.z but that won't work for small creatures like the headcrab - if ( fabs(vecEnd.z - pev->origin.z) > 64 ) - { - iReturn = LOCALMOVE_INVALID_DONT_TRIANGULATE; - } - } - /* - // uncommenting this block will draw a line representing the nearest legal move. - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); - WRITE_COORD(MSG_BROADCAST, pev->origin.x); - WRITE_COORD(MSG_BROADCAST, pev->origin.y); - WRITE_COORD(MSG_BROADCAST, pev->origin.z); - WRITE_COORD(MSG_BROADCAST, vecStart.x); - WRITE_COORD(MSG_BROADCAST, vecStart.y); - WRITE_COORD(MSG_BROADCAST, vecStart.z); - */ - - // since we've actually moved the monster during the check, undo the move. - UTIL_SetOrigin( pev, vecStartPos ); - - return iReturn; -} - - -float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) -{ - float flTravelTime = 0; - - //ALERT(at_aiconsole, "A door. "); - CBaseEntity *pcbeDoor = CBaseEntity::Instance(pevDoor); - if (pcbeDoor && !pcbeDoor->IsLockedByMaster()) - { - //ALERT(at_aiconsole, "unlocked! "); - pcbeDoor->Use(this, this, USE_ON, 0.0); - //ALERT(at_aiconsole, "pevDoor->nextthink = %d ms\n", (int)(1000*pevDoor->nextthink)); - //ALERT(at_aiconsole, "pevDoor->ltime = %d ms\n", (int)(1000*pevDoor->ltime)); - //ALERT(at_aiconsole, "pev-> nextthink = %d ms\n", (int)(1000*pev->nextthink)); - //ALERT(at_aiconsole, "pev->ltime = %d ms\n", (int)(1000*pev->ltime)); - flTravelTime = pevDoor->nextthink - pevDoor->ltime; - //ALERT(at_aiconsole, "Waiting %d ms\n", (int)(1000*flTravelTime)); - if ( pcbeDoor->pev->targetname ) - { - edict_t *pentTarget = NULL; - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pcbeDoor->pev->targetname)); - - if ( VARS( pentTarget ) != pcbeDoor->pev ) - { - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs ( pentTarget, STRING(pcbeDoor->pev->classname) ) ) - { - CBaseEntity *pDoor = Instance(pentTarget); - if ( pDoor ) - pDoor->Use(this, this, USE_ON, 0.0); - } - } - } - } - } - - return gpGlobals->time + flTravelTime; -} - - -//========================================================= -// AdvanceRoute - poorly named function that advances the -// m_iRouteIndex. If it goes beyond ROUTE_SIZE, the route -// is refreshed. -//========================================================= -void CBaseMonster :: AdvanceRoute ( float distance ) -{ - - if ( m_iRouteIndex == ROUTE_SIZE - 1 ) - { - // time to refresh the route. - if ( !FRefreshRoute() ) - { - ALERT ( at_aiconsole, "Can't Refresh Route!!\n" ); - } - } - else - { - if ( ! (m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL) ) - { - // If we've just passed a path_corner, advance m_pGoalEnt - if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_PATHCORNER ) - m_pGoalEnt = m_pGoalEnt->GetNextTarget(); - - // IF both waypoints are nodes, then check for a link for a door and operate it. - // - if ( (m_Route[m_iRouteIndex].iType & bits_MF_TO_NODE) == bits_MF_TO_NODE - && (m_Route[m_iRouteIndex+1].iType & bits_MF_TO_NODE) == bits_MF_TO_NODE) - { - //ALERT(at_aiconsole, "SVD: Two nodes. "); - - int iSrcNode = WorldGraph.FindNearestNode(m_Route[m_iRouteIndex].vecLocation, this ); - int iDestNode = WorldGraph.FindNearestNode(m_Route[m_iRouteIndex+1].vecLocation, this ); - - int iLink; - WorldGraph.HashSearch(iSrcNode, iDestNode, iLink); - - if ( iLink >= 0 && WorldGraph.m_pLinkPool[iLink].m_pLinkEnt != NULL ) - { - //ALERT(at_aiconsole, "A link. "); - if ( WorldGraph.HandleLinkEnt ( iSrcNode, WorldGraph.m_pLinkPool[iLink].m_pLinkEnt, m_afCapability, CGraph::NODEGRAPH_DYNAMIC ) ) - { - //ALERT(at_aiconsole, "usable."); - entvars_t *pevDoor = WorldGraph.m_pLinkPool[iLink].m_pLinkEnt; - if (pevDoor) - { - m_flMoveWaitFinished = OpenDoorAndWait( pevDoor ); -// ALERT( at_aiconsole, "Wating for door %.2f\n", m_flMoveWaitFinished-gpGlobals->time ); - } - } - } - //ALERT(at_aiconsole, "\n"); - } - m_iRouteIndex++; - } - else // At goal!!! - { - if ( distance < m_flGroundSpeed * 0.2 /* FIX */ ) - { - MovementComplete(); - } - } - } -} - - -int CBaseMonster :: RouteClassify( int iMoveFlag ) -{ - int movementGoal; - - movementGoal = MOVEGOAL_NONE; - - if ( iMoveFlag & bits_MF_TO_TARGETENT ) - movementGoal = MOVEGOAL_TARGETENT; - else if ( iMoveFlag & bits_MF_TO_ENEMY ) - movementGoal = MOVEGOAL_ENEMY; - else if ( iMoveFlag & bits_MF_TO_PATHCORNER ) - movementGoal = MOVEGOAL_PATHCORNER; - else if ( iMoveFlag & bits_MF_TO_NODE ) - movementGoal = MOVEGOAL_NODE; - else if ( iMoveFlag & bits_MF_TO_LOCATION ) - movementGoal = MOVEGOAL_LOCATION; - - return movementGoal; -} - -//========================================================= -// BuildRoute -//========================================================= -BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) -{ - float flDist; - Vector vecApex; - int iLocalMove; - - RouteNew(); - m_movementGoal = RouteClassify( iMoveFlag ); - -// so we don't end up with no moveflags - m_Route[ 0 ].vecLocation = vecGoal; - m_Route[ 0 ].iType = iMoveFlag | bits_MF_IS_GOAL; - -// check simple local move - iLocalMove = CheckLocalMove( pev->origin, vecGoal, pTarget, &flDist ); - - if ( iLocalMove == LOCALMOVE_VALID ) - { - // monster can walk straight there! - return TRUE; - } -// try to triangulate around any obstacles. - else if ( iLocalMove != LOCALMOVE_INVALID_DONT_TRIANGULATE && FTriangulate( pev->origin, vecGoal, flDist, pTarget, &vecApex ) ) - { - // there is a slightly more complicated path that allows the monster to reach vecGoal - m_Route[ 0 ].vecLocation = vecApex; - m_Route[ 0 ].iType = (iMoveFlag | bits_MF_TO_DETOUR); - - m_Route[ 1 ].vecLocation = vecGoal; - m_Route[ 1 ].iType = iMoveFlag | bits_MF_IS_GOAL; - - /* - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); - WRITE_COORD(MSG_BROADCAST, vecApex.x ); - WRITE_COORD(MSG_BROADCAST, vecApex.y ); - WRITE_COORD(MSG_BROADCAST, vecApex.z ); - WRITE_COORD(MSG_BROADCAST, vecApex.x ); - WRITE_COORD(MSG_BROADCAST, vecApex.y ); - WRITE_COORD(MSG_BROADCAST, vecApex.z + 128 ); - */ - - RouteSimplify( pTarget ); - return TRUE; - } - -// last ditch, try nodes - if ( FGetNodeRoute( vecGoal ) ) - { -// ALERT ( at_console, "Can get there on nodes\n" ); - m_vecMoveGoal = vecGoal; - RouteSimplify( pTarget ); - return TRUE; - } - - // b0rk - return FALSE; -} - - -//========================================================= -// InsertWaypoint - Rebuilds the existing route so that the -// supplied vector and moveflags are the first waypoint in -// the route, and fills the rest of the route with as much -// of the pre-existing route as possible -//========================================================= -void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) -{ - int i, type; - - - // we have to save some Index and Type information from the real - // path_corner or node waypoint that the monster was trying to reach. This makes sure that data necessary - // to refresh the original path exists even in the new waypoints that don't correspond directy to a path_corner - // or node. - type = afMoveFlags | (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK); - - for ( i = ROUTE_SIZE-1; i > 0; i-- ) - m_Route[i] = m_Route[i-1]; - - m_Route[ m_iRouteIndex ].vecLocation = vecLocation; - m_Route[ m_iRouteIndex ].iType = type; -} - -//========================================================= -// FTriangulate - tries to overcome local obstacles by -// triangulating a path around them. -// -// iApexDist is how far the obstruction that we are trying -// to triangulate around is from the monster. -//========================================================= -BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) -{ - Vector vecDir; - Vector vecForward; - Vector vecLeft;// the spot we'll try to triangulate to on the left - Vector vecRight;// the spot we'll try to triangulate to on the right - Vector vecTop;// the spot we'll try to triangulate to on the top - Vector vecBottom;// the spot we'll try to triangulate to on the bottom - Vector vecFarSide;// the spot that we'll move to after hitting the triangulated point, before moving on to our normal goal. - int i; - float sizeX, sizeZ; - - // If the hull width is less than 24, use 24 because CheckLocalMove uses a min of - // 24. - sizeX = pev->size.x; - if (sizeX < 24.0) - sizeX = 24.0; - else if (sizeX > 48.0) - sizeX = 48.0; - sizeZ = pev->size.z; - //if (sizeZ < 24.0) - // sizeZ = 24.0; - - vecForward = ( vecEnd - vecStart ).Normalize(); - - Vector vecDirUp(0,0,1); - vecDir = CrossProduct ( vecForward, vecDirUp); - - // start checking right about where the object is, picking two equidistant starting points, one on - // the left, one on the right. As we progress through the loop, we'll push these away from the obstacle, - // hoping to find a way around on either side. pev->size.x is added to the ApexDist in order to help select - // an apex point that insures that the monster is sufficiently past the obstacle before trying to turn back - // onto its original course. - - vecLeft = pev->origin + ( vecForward * ( flDist + sizeX ) ) - vecDir * ( sizeX * 3 ); - vecRight = pev->origin + ( vecForward * ( flDist + sizeX ) ) + vecDir * ( sizeX * 3 ); - if (pev->movetype == MOVETYPE_FLY) - { - vecTop = pev->origin + (vecForward * flDist) + (vecDirUp * sizeZ * 3); - vecBottom = pev->origin + (vecForward * flDist) - (vecDirUp * sizeZ * 3); - } - - vecFarSide = m_Route[ m_iRouteIndex ].vecLocation; - - vecDir = vecDir * sizeX * 2; - if (pev->movetype == MOVETYPE_FLY) - vecDirUp = vecDirUp * sizeZ * 2; - - for ( i = 0 ; i < 8; i++ ) - { -// Debug, Draw the triangulation -#if 0 - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecRight.x ); - WRITE_COORD( vecRight.y ); - WRITE_COORD( vecRight.z ); - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecLeft.x ); - WRITE_COORD( vecLeft.y ); - WRITE_COORD( vecLeft.z ); - MESSAGE_END(); -#endif - -#if 0 - if (pev->movetype == MOVETYPE_FLY) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecTop.x ); - WRITE_COORD( vecTop.y ); - WRITE_COORD( vecTop.z ); - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecBottom.x ); - WRITE_COORD( vecBottom.y ); - WRITE_COORD( vecBottom.z ); - MESSAGE_END(); - } -#endif - - if ( CheckLocalMove( pev->origin, vecRight, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( CheckLocalMove ( vecRight, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecRight; - } - - return TRUE; - } - } - if ( CheckLocalMove( pev->origin, vecLeft, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( CheckLocalMove ( vecLeft, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecLeft; - } - - return TRUE; - } - } - - if (pev->movetype == MOVETYPE_FLY) - { - if ( CheckLocalMove( pev->origin, vecTop, pTargetEnt, NULL ) == LOCALMOVE_VALID) - { - if ( CheckLocalMove ( vecTop, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecTop; - //ALERT(at_aiconsole, "triangulate over\n"); - } - - return TRUE; - } - } -#if 1 - if ( CheckLocalMove( pev->origin, vecBottom, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( CheckLocalMove ( vecBottom, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecBottom; - //ALERT(at_aiconsole, "triangulate under\n"); - } - - return TRUE; - } - } -#endif - } - - vecRight = vecRight + vecDir; - vecLeft = vecLeft - vecDir; - if (pev->movetype == MOVETYPE_FLY) - { - vecTop = vecTop + vecDirUp; - vecBottom = vecBottom - vecDirUp; - } - } - - return FALSE; -} - -//========================================================= -// Move - take a single step towards the next ROUTE location -//========================================================= -#define DIST_TO_CHECK 200 - -void CBaseMonster :: Move ( float flInterval ) -{ - float flWaypointDist; - float flCheckDist; - float flDist;// how far the lookahead check got before hitting an object. - Vector vecDir; - Vector vecApex; - CBaseEntity *pTargetEnt; - - // Don't move if no valid route - if ( FRouteClear() ) - { - // If we still have a movement goal, then this is probably a route truncated by SimplifyRoute() - // so refresh it. - if ( m_movementGoal == MOVEGOAL_NONE || !FRefreshRoute() ) - { - ALERT( at_aiconsole, "Tried to move with no route!\n" ); - TaskFail(); - return; - } - } - - if ( m_flMoveWaitFinished > gpGlobals->time ) - return; - -// Debug, test movement code -#if 0 -// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) - { - if ( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - return; - } -#else -// Debug, draw the route -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 200, 0 ); -#endif - - // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer - // to that entity for the CheckLocalMove and Triangulate functions. - pTargetEnt = NULL; - - // local move to waypoint. - vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); - - MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); - ChangeYaw ( pev->yaw_speed ); - - // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint - if ( flWaypointDist < DIST_TO_CHECK ) - { - flCheckDist = flWaypointDist; - } - else - { - flCheckDist = DIST_TO_CHECK; - } - - if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) - { - // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) - pTargetEnt = m_hEnemy; - } - else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) - { - pTargetEnt = m_hTargetEnt; - } - - // !!!BUGBUG - CheckDist should be derived from ground speed. - // If this fails, it should be because of some dynamic entity blocking this guy. - // We've already checked this path, so we should wait and time out if the entity doesn't move - flDist = 0; - if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) - { - CBaseEntity *pBlocker; - - // Can't move, stop - Stop(); - // Blocking entity is in global trace_ent - pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if (pBlocker) - { - DispatchBlocked( edict(), pBlocker->edict() ); - } - - if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) - { - // Can we still move toward our target? - if ( flDist < m_flGroundSpeed ) - { - // No, Wait for a second - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; - return; - } - // Ok, still enough room to take a step - } - else - { - // try to triangulate around whatever is in the way. - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); - RouteSimplify( pTargetEnt ); - } - else - { -// ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); - Stop(); - // Only do this once until your route is cleared - if ( m_moveWaitTime > 0 && !(m_afMemory & bits_MEMORY_MOVE_FAILED) ) - { - FRefreshRoute(); - if ( FRouteClear() ) - { - TaskFail(); - } - else - { - // Don't get stuck - if ( (gpGlobals->time - m_flMoveWaitFinished) < 0.2 ) - Remember( bits_MEMORY_MOVE_FAILED ); - - m_flMoveWaitFinished = gpGlobals->time + 0.1; - } - } - else - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to move (%d)!\n", STRING(pev->classname), HasMemory( bits_MEMORY_MOVE_FAILED ) ); - //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); - } - return; - } - } - } - - // close enough to the target, now advance to the next target. This is done before actually reaching - // the target so that we get a nice natural turn while moving. - if ( ShouldAdvanceRoute( flWaypointDist ) )///!!!BUGBUG- magic number - { - AdvanceRoute( flWaypointDist ); - } - - // Might be waiting for a door - if ( m_flMoveWaitFinished > gpGlobals->time ) - { - Stop(); - return; - } - - // UNDONE: this is a hack to quit moving farther than it has looked ahead. - if (flCheckDist < m_flGroundSpeed * flInterval) - { - flInterval = flCheckDist / m_flGroundSpeed; - // ALERT( at_console, "%.02f\n", flInterval ); - } - MoveExecute( pTargetEnt, vecDir, flInterval ); - - if ( MovementIsComplete() ) - { - Stop(); - RouteClear(); - } -} - - -BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) -{ - if ( flWaypointDist <= MONSTER_CUT_CORNER_DIST ) - { - // ALERT( at_console, "cut %f\n", flWaypointDist ); - return TRUE; - } - - return FALSE; -} - - -void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ -// float flYaw = UTIL_VecToYaw ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin );// build a yaw that points to the goal. -// WALK_MOVE( ENT(pev), flYaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); - if ( m_IdealActivity != m_movementActivity ) - m_IdealActivity = m_movementActivity; - - float flTotal = m_flGroundSpeed * pev->framerate * flInterval; - float flStep; - while (flTotal > 0.001) - { - // don't walk more than 16 units or stairs stop working - flStep = min( 16.0, flTotal ); - UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flStep, MOVE_NORMAL ); - flTotal -= flStep; - } - // ALERT( at_console, "dist %f\n", m_flGroundSpeed * pev->framerate * flInterval ); -} - - -//========================================================= -// MonsterInit - after a monster is spawned, it needs to -// be dropped into the world, checked for mobility problems, -// and put on the proper path, if any. This function does -// all of those things after the monster spawns. Any -// initialization that should take place for all monsters -// goes here. -//========================================================= -void CBaseMonster :: MonsterInit ( void ) -{ - if (!g_pGameRules->FAllowMonsters()) - { - pev->flags |= FL_KILLME; // Post this because some monster code modifies class data after calling this function -// REMOVE_ENTITY(ENT(pev)); - return; - } - - // Set fields common to all monsters - pev->effects = 0; - pev->takedamage = DAMAGE_AIM; - pev->ideal_yaw = pev->angles.y; - pev->max_health = pev->health; - pev->deadflag = DEAD_NO; - m_IdealMonsterState = MONSTERSTATE_IDLE;// Assume monster will be idle, until proven otherwise - - m_IdealActivity = ACT_IDLE; - - SetBits (pev->flags, FL_MONSTER); - if ( pev->spawnflags & SF_MONSTER_HITMONSTERCLIP ) - pev->flags |= FL_MONSTERCLIP; - - ClearSchedule(); - RouteClear(); - InitBoneControllers( ); // FIX: should be done in Spawn - - m_iHintNode = NO_NODE; - - m_afMemory = MEMORY_CLEAR; - - m_hEnemy = NULL; - - m_flDistTooFar = 1024.0; - m_flDistLook = 2048.0; - - // set eye position - SetEyePosition(); - - SetThink( &CBaseMonster::MonsterInitThink ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse ( &CBaseMonster::MonsterUse ); -} - -//========================================================= -// MonsterInitThink - Calls StartMonster. Startmonster is -// virtual, but this function cannot be -//========================================================= -void CBaseMonster :: MonsterInitThink ( void ) -{ - StartMonster(); -} - -//========================================================= -// StartMonster - final bit of initization before a monster -// is turned over to the AI. -//========================================================= -void CBaseMonster :: StartMonster ( void ) -{ - // update capabilities - if ( LookupActivity ( ACT_RANGE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_RANGE_ATTACK1; - } - if ( LookupActivity ( ACT_RANGE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_RANGE_ATTACK2; - } - if ( LookupActivity ( ACT_MELEE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_MELEE_ATTACK1; - } - if ( LookupActivity ( ACT_MELEE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_MELEE_ATTACK2; - } - - // Raise monster off the floor one unit, then drop to floor - if ( pev->movetype != MOVETYPE_FLY && !FBitSet( pev->spawnflags, SF_MONSTER_FALL_TO_GROUND ) ) - { - pev->origin.z += 1; - DROP_TO_FLOOR ( ENT(pev) ); - // Try to move the monster to make sure it's not stuck in a brush. - if (!WALK_MOVE ( ENT(pev), 0, 0, WALKMOVE_NORMAL ) ) - { - ALERT(at_error, "Monster %s stuck in wall--level design error", STRING(pev->classname)); - pev->effects = EF_BRIGHTFIELD; - } - } - else - { - pev->flags &= ~FL_ONGROUND; - } - - if ( !FStringNull(pev->target) )// this monster has a target - { - // Find the monster's initial target entity, stash it - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( pev->target ) ) ); - - if ( !m_pGoalEnt ) - { - ALERT(at_error, "ReadyMonster()--%s couldn't find target %s", STRING(pev->classname), STRING(pev->target)); - } - else - { - // Monster will start turning towards his destination - MakeIdealYaw ( m_pGoalEnt->pev->origin ); - - // JAY: How important is this error message? Big Momma doesn't obey this rule, so I took it out. -#if 0 - // At this point, we expect only a path_corner as initial goal - if (!FClassnameIs( m_pGoalEnt->pev, "path_corner")) - { - ALERT(at_warning, "ReadyMonster--monster's initial goal '%s' is not a path_corner", STRING(pev->target)); - } -#endif - - // set the monster up to walk a path corner path. - // !!!BUGBUG - this is a minor bit of a hack. - // JAYJAY - m_movementGoal = MOVEGOAL_PATHCORNER; - - if ( pev->movetype == MOVETYPE_FLY ) - m_movementActivity = ACT_FLY; - else - m_movementActivity = ACT_WALK; - - if ( !FRefreshRoute() ) - { - ALERT ( at_aiconsole, "Can't Create Route!\n" ); - } - SetState( MONSTERSTATE_IDLE ); - ChangeSchedule( GetScheduleOfType( SCHED_IDLE_WALK ) ); - } - } - - //SetState ( m_IdealMonsterState ); - //SetActivity ( m_IdealActivity ); - - // Delay drop to floor to make sure each door in the level has had its chance to spawn - // Spread think times so that they don't all happen at the same time (Carmack) - SetThink ( &CBaseMonster::CallMonsterThink ); - pev->nextthink += RANDOM_FLOAT(0.1, 0.4); // spread think times. - - if ( !FStringNull(pev->targetname) )// wait until triggered - { - SetState( MONSTERSTATE_IDLE ); - // UNDONE: Some scripted sequence monsters don't have an idle? - SetActivity( ACT_IDLE ); - ChangeSchedule( GetScheduleOfType( SCHED_WAIT_TRIGGER ) ); - } -} - - -void CBaseMonster :: MovementComplete( void ) -{ - switch( m_iTaskStatus ) - { - case TASKSTATUS_NEW: - case TASKSTATUS_RUNNING: - m_iTaskStatus = TASKSTATUS_RUNNING_TASK; - break; - - case TASKSTATUS_RUNNING_MOVEMENT: - TaskComplete(); - break; - - case TASKSTATUS_RUNNING_TASK: - ALERT( at_error, "Movement completed twice!\n" ); - break; - - case TASKSTATUS_COMPLETE: - break; - } - m_movementGoal = MOVEGOAL_NONE; -} - - -int CBaseMonster::TaskIsRunning( void ) -{ - if ( m_iTaskStatus != TASKSTATUS_COMPLETE && - m_iTaskStatus != TASKSTATUS_RUNNING_MOVEMENT ) - return 1; - - return 0; -} - -//========================================================= -// IRelationship - returns an integer that describes the -// relationship between two types of monster. -//========================================================= -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) -{ - static int iEnemy[14][14] = - { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN - /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, - /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, - /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, - /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, - /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, - /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, - /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, - /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, - /*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO } - }; - - return iEnemy[ Classify() ][ pTarget->Classify() ]; -} - -//========================================================= -// FindCover - tries to find a nearby node that will hide -// the caller from its enemy. -// -// If supplied, search will return a node at least as far -// away as MinDist, but no farther than MaxDist. -// if MaxDist isn't supplied, it defaults to a reasonable -// value -//========================================================= -// UNDONE: Should this find the nearest node? - -//float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) - -BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) -{ - int i; - int iMyHullIndex; - int iMyNode; - int iThreatNode; - float flDist; - Vector vecLookersOffset; - TraceResult tr; - - if ( !flMaxDist ) - { - // user didn't supply a MaxDist, so work up a crazy one. - flMaxDist = 784; - } - - if ( flMinDist > 0.5 * flMaxDist) - { -#if _DEBUG - ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); -#endif - flMinDist = 0.5 * flMaxDist; - } - - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - { - ALERT ( at_aiconsole, "Graph not ready for findcover!\n" ); - return FALSE; - } - - iMyNode = WorldGraph.FindNearestNode( pev->origin, this ); - iThreatNode = WorldGraph.FindNearestNode ( vecThreat, this ); - iMyHullIndex = WorldGraph.HullIndex( this ); - - if ( iMyNode == NO_NODE ) - { - ALERT ( at_aiconsole, "FindCover() - %s has no nearest node!\n", STRING(pev->classname)); - return FALSE; - } - if ( iThreatNode == NO_NODE ) - { - // ALERT ( at_aiconsole, "FindCover() - Threat has no nearest node!\n" ); - iThreatNode = iMyNode; - // return FALSE; - } - - vecLookersOffset = vecThreat + vecViewOffset;// calculate location of enemy's eyes - - // we'll do a rough sample to find nodes that are relatively nearby - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; - - CNode &node = WorldGraph.Node( nodeNumber ); - WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. - - // could use an optimization here!! - flDist = ( pev->origin - node.m_vecOrigin ).Length(); - - // DON'T do the trace check on a node that is farther away than a node that we've already found to - // provide cover! Also make sure the node is within the mins/maxs of the search. - if ( flDist >= flMinDist && flDist < flMaxDist ) - { - UTIL_TraceLine ( node.m_vecOrigin + vecViewOffset, vecLookersOffset, ignore_monsters, ignore_glass, ENT(pev), &tr ); - - // if this node will block the threat's line of sight to me... - if ( tr.flFraction != 1.0 ) - { - // ..and is also closer to me than the threat, or the same distance from myself and the threat the node is good. - if ( ( iMyNode == iThreatNode ) || WorldGraph.PathLength( iMyNode, nodeNumber, iMyHullIndex, m_afCapability ) <= WorldGraph.PathLength( iThreatNode, nodeNumber, iMyHullIndex, m_afCapability ) ) - { - if ( FValidateCover ( node.m_vecOrigin ) && MoveToLocation( ACT_RUN, 0, node.m_vecOrigin ) ) - { - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( node.m_vecOrigin.x ); - WRITE_COORD( node.m_vecOrigin.y ); - WRITE_COORD( node.m_vecOrigin.z ); - - WRITE_COORD( vecLookersOffset.x ); - WRITE_COORD( vecLookersOffset.y ); - WRITE_COORD( vecLookersOffset.z ); - MESSAGE_END(); - */ - - return TRUE; - } - } - } - } - } - return FALSE; -} - - -//========================================================= -// BuildNearestRoute - tries to build a route as close to the target -// as possible, even if there isn't a path to the final point. -// -// If supplied, search will return a node at least as far -// away as MinDist from vecThreat, but no farther than MaxDist. -// if MaxDist isn't supplied, it defaults to a reasonable -// value -//========================================================= -BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) -{ - int i; - int iMyHullIndex; - int iMyNode; - float flDist; - Vector vecLookersOffset; - TraceResult tr; - - if ( !flMaxDist ) - { - // user didn't supply a MaxDist, so work up a crazy one. - flMaxDist = 784; - } - - if ( flMinDist > 0.5 * flMaxDist) - { -#if _DEBUG - ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); -#endif - flMinDist = 0.5 * flMaxDist; - } - - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - { - ALERT ( at_aiconsole, "Graph not ready for BuildNearestRoute!\n" ); - return FALSE; - } - - iMyNode = WorldGraph.FindNearestNode( pev->origin, this ); - iMyHullIndex = WorldGraph.HullIndex( this ); - - if ( iMyNode == NO_NODE ) - { - ALERT ( at_aiconsole, "BuildNearestRoute() - %s has no nearest node!\n", STRING(pev->classname)); - return FALSE; - } - - vecLookersOffset = vecThreat + vecViewOffset;// calculate location of enemy's eyes - - // we'll do a rough sample to find nodes that are relatively nearby - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; - - CNode &node = WorldGraph.Node( nodeNumber ); - WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. - - // can I get there? - if (WorldGraph.NextNodeInRoute( iMyNode, nodeNumber, iMyHullIndex, 0 ) != iMyNode) - { - flDist = ( vecThreat - node.m_vecOrigin ).Length(); - - // is it close? - if ( flDist > flMinDist && flDist < flMaxDist) - { - // can I see where I want to be from there? - UTIL_TraceLine( node.m_vecOrigin + pev->view_ofs, vecLookersOffset, ignore_monsters, edict(), &tr ); - - if (tr.flFraction == 1.0) - { - // try to actually get there - if ( BuildRoute ( node.m_vecOrigin, bits_MF_TO_LOCATION, NULL ) ) - { - flMaxDist = flDist; - m_vecMoveGoal = node.m_vecOrigin; - return TRUE; // UNDONE: keep looking for something closer! - } - } - } - } - } - - return FALSE; -} - - - -//========================================================= -// BestVisibleEnemy - this functions searches the link -// list whose head is the caller's m_pLink field, and returns -// a pointer to the enemy entity in that list that is nearest the -// caller. -// -// !!!UNDONE - currently, this only returns the closest enemy. -// we'll want to consider distance, relationship, attack types, back turned, etc. -//========================================================= -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) -{ - CBaseEntity *pReturn; - CBaseEntity *pNextEnt; - int iNearest; - int iDist; - int iBestRelationship; - - iNearest = 8192;// so first visible entity will become the closest. - pNextEnt = m_pLink; - pReturn = NULL; - iBestRelationship = R_NO; - - while ( pNextEnt != NULL ) - { - if ( pNextEnt->IsAlive() ) - { - if ( IRelationship( pNextEnt) > iBestRelationship ) - { - // this entity is disliked MORE than the entity that we - // currently think is the best visible enemy. No need to do - // a distance check, just get mad at this one for now. - iBestRelationship = IRelationship ( pNextEnt ); - iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); - pReturn = pNextEnt; - } - else if ( IRelationship( pNextEnt) == iBestRelationship ) - { - // this entity is disliked just as much as the entity that - // we currently think is the best visible enemy, so we only - // get mad at it if it is closer. - iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); - - if ( iDist <= iNearest ) - { - iNearest = iDist; - iBestRelationship = IRelationship ( pNextEnt ); - pReturn = pNextEnt; - } - } - } - - pNextEnt = pNextEnt->m_pLink; - } - - return pReturn; -} - - -//========================================================= -// MakeIdealYaw - gets a yaw value for the caller that would -// face the supplied vector. Value is stuffed into the monster's -// ideal_yaw -//========================================================= -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) -{ - Vector vecProjection; - - // strafing monster needs to face 90 degrees away from its goal - if ( m_movementActivity == ACT_STRAFE_LEFT ) - { - vecProjection.x = -vecTarget.y; - vecProjection.y = vecTarget.x; - - pev->ideal_yaw = UTIL_VecToYaw( vecProjection - pev->origin ); - } - else if ( m_movementActivity == ACT_STRAFE_RIGHT ) - { - vecProjection.x = vecTarget.y; - vecProjection.y = vecTarget.x; - - pev->ideal_yaw = UTIL_VecToYaw( vecProjection - pev->origin ); - } - else - { - pev->ideal_yaw = UTIL_VecToYaw ( vecTarget - pev->origin ); - } -} - -//========================================================= -// FlYawDiff - returns the difference ( in degrees ) between -// monster's current yaw and ideal_yaw -// -// Positive result is left turn, negative is right turn -//========================================================= -float CBaseMonster::FlYawDiff ( void ) -{ - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - - if ( flCurrentYaw == pev->ideal_yaw ) - { - return 0; - } - - - return UTIL_AngleDiff( pev->ideal_yaw, flCurrentYaw ); -} - - -//========================================================= -// Changeyaw - turns a monster towards its ideal_yaw -//========================================================= -float CBaseMonster::ChangeYaw ( int yawSpeed ) -{ - float ideal, current, move, speed; - - current = UTIL_AngleMod( pev->angles.y ); - ideal = pev->ideal_yaw; - if (current != ideal) - { - speed = (float)yawSpeed * gpGlobals->frametime * 10; - move = ideal - current; - - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - - if (move > 0) - {// turning to the monster's left - if (move > speed) - move = speed; - } - else - {// turning to the monster's right - if (move < -speed) - move = -speed; - } - - pev->angles.y = UTIL_AngleMod (current + move); - - // turn head in desired direction only if they have a turnable head - if (m_afCapability & bits_CAP_TURN_HEAD) - { - float yaw = pev->ideal_yaw - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - // yaw *= 0.8; - SetBoneController( 0, yaw ); - } - } - else - move = 0; - - return move; -} - -//========================================================= -// VecToYaw - turns a directional vector into a yaw value -// that points down that vector. -//========================================================= -float CBaseMonster::VecToYaw ( Vector vecDir ) -{ - if (vecDir.x == 0 && vecDir.y == 0 && vecDir.z == 0) - return pev->angles.y; - - return UTIL_VecToYaw( vecDir ); -} - - -//========================================================= -// SetEyePosition -// -// queries the monster's model for $eyeposition and copies -// that vector to the monster's view_ofs -// -//========================================================= -void CBaseMonster :: SetEyePosition ( void ) -{ - Vector vecEyePosition; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - GetEyePosition( pmodel, vecEyePosition ); - - pev->view_ofs = vecEyePosition; - - if ( pev->view_ofs == g_vecZero ) - { - ALERT ( at_aiconsole, "%s has no view_ofs!\n", STRING ( pev->classname ) ); - } -} - -void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCRIPT_EVENT_DEAD: - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pev->deadflag = DEAD_DYING; - // Kill me now! (and fade out when CineCleanup() is called) -#if _DEBUG - ALERT( at_aiconsole, "Death event: %s\n", STRING(pev->classname) ); -#endif - pev->health = 0; - } -#if _DEBUG - else - ALERT( at_aiconsole, "INVALID death event:%s\n", STRING(pev->classname) ); -#endif - break; - case SCRIPT_EVENT_NOT_DEAD: - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pev->deadflag = DEAD_NO; - // This is for life/death sequences where the player can determine whether a character is dead or alive after the script - pev->health = pev->max_health; - } - break; - - case SCRIPT_EVENT_SOUND: // Play a named wave file - EMIT_SOUND( edict(), CHAN_BODY, pEvent->options, 1.0, ATTN_IDLE ); - break; - - case SCRIPT_EVENT_SOUND_VOICE: - EMIT_SOUND( edict(), CHAN_VOICE, pEvent->options, 1.0, ATTN_IDLE ); - break; - - case SCRIPT_EVENT_SENTENCE_RND1: // Play a named sentence group 33% of the time - if (RANDOM_LONG(0,2) == 0) - break; - // fall through... - case SCRIPT_EVENT_SENTENCE: // Play a named sentence group - SENTENCEG_PlayRndSz( edict(), pEvent->options, 1.0, ATTN_IDLE, 0, 100 ); - break; - - case SCRIPT_EVENT_FIREEVENT: // Fire a trigger - FireTargets( pEvent->options, this, this, USE_TOGGLE, 0 ); - break; - - case SCRIPT_EVENT_NOINTERRUPT: // Can't be interrupted from now on - if ( m_pCine ) - m_pCine->AllowInterrupt( FALSE ); - break; - - case SCRIPT_EVENT_CANINTERRUPT: // OK to interrupt now - if ( m_pCine ) - m_pCine->AllowInterrupt( TRUE ); - break; - -#if 0 - case SCRIPT_EVENT_INAIR: // Don't DROP_TO_FLOOR() - case SCRIPT_EVENT_ENDANIMATION: // Set ending animation sequence to - break; -#endif - - case MONSTER_EVENT_BODYDROP_HEAVY: - if ( pev->flags & FL_ONGROUND ) - { - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM, 0, 90 ); - } - else - { - EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop4.wav", 1, ATTN_NORM, 0, 90 ); - } - } - break; - - case MONSTER_EVENT_BODYDROP_LIGHT: - if ( pev->flags & FL_ONGROUND ) - { - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM ); - } - else - { - EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop4.wav", 1, ATTN_NORM ); - } - } - break; - - case MONSTER_EVENT_SWISHSOUND: - { - // NO MONSTER may use this anim event unless that monster's precache precaches this sound!!! - EMIT_SOUND( ENT(pev), CHAN_BODY, "zombie/claw_miss2.wav", 1, ATTN_NORM ); - break; - } - - default: - ALERT( at_aiconsole, "Unhandled animation event %d for %s\n", pEvent->event, STRING(pev->classname) ); - break; - - } -} - - -// Combat - -Vector CBaseMonster :: GetGunPosition( ) -{ - UTIL_MakeVectors(pev->angles); - - // Vector vecSrc = pev->origin + gpGlobals->v_forward * 10; - //vecSrc.z = pevShooter->absmin.z + pevShooter->size.z * 0.7; - //vecSrc.z = pev->origin.z + (pev->view_ofs.z - 4); - Vector vecSrc = pev->origin - + gpGlobals->v_forward * m_HackedGunPos.y - + gpGlobals->v_right * m_HackedGunPos.x - + gpGlobals->v_up * m_HackedGunPos.z; - - return vecSrc; -} - - - - - -//========================================================= -// NODE GRAPH -//========================================================= - - - - - -//========================================================= -// FGetNodeRoute - tries to build an entire node path from -// the callers origin to the passed vector. If this is -// possible, ROUTE_SIZE waypoints will be copied into the -// callers m_Route. TRUE is returned if the operation -// succeeds (path is valid) or FALSE if failed (no path -// exists ) -//========================================================= -BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) -{ - int iPath[ MAX_PATH_SIZE ]; - int iSrcNode, iDestNode; - int iResult; - int i; - int iNumToCopy; - - iSrcNode = WorldGraph.FindNearestNode ( pev->origin, this ); - iDestNode = WorldGraph.FindNearestNode ( vecDest, this ); - - if ( iSrcNode == -1 ) - { - // no node nearest self -// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near self!\n" ); - return FALSE; - } - else if ( iDestNode == -1 ) - { - // no node nearest target -// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near target!\n" ); - return FALSE; - } - - // valid src and dest nodes were found, so it's safe to proceed with - // find shortest path - int iNodeHull = WorldGraph.HullIndex( this ); // make this a monster virtual function - iResult = WorldGraph.FindShortestPath ( iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability ); - - if ( !iResult ) - { -#if 1 - ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); - return FALSE; -#else - BOOL bRoutingSave = WorldGraph.m_fRoutingComplete; - WorldGraph.m_fRoutingComplete = FALSE; - iResult = WorldGraph.FindShortestPath(iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability); - WorldGraph.m_fRoutingComplete = bRoutingSave; - if ( !iResult ) - { - ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); - return FALSE; - } - else - { - ALERT ( at_aiconsole, "Routing is inconsistent!" ); - } -#endif - } - - // there's a valid path within iPath now, so now we will fill the route array - // up with as many of the waypoints as it will hold. - - // don't copy ROUTE_SIZE entries if the path returned is shorter - // than ROUTE_SIZE!!! - if ( iResult < ROUTE_SIZE ) - { - iNumToCopy = iResult; - } - else - { - iNumToCopy = ROUTE_SIZE; - } - - for ( i = 0 ; i < iNumToCopy; i++ ) - { - m_Route[ i ].vecLocation = WorldGraph.m_pNodes[ iPath[ i ] ].m_vecOrigin; - m_Route[ i ].iType = bits_MF_TO_NODE; - } - - if ( iNumToCopy < ROUTE_SIZE ) - { - m_Route[ iNumToCopy ].vecLocation = vecDest; - m_Route[ iNumToCopy ].iType |= bits_MF_IS_GOAL; - } - - return TRUE; -} - -//========================================================= -// FindHintNode -//========================================================= -int CBaseMonster :: FindHintNode ( void ) -{ - int i; - TraceResult tr; - - if ( !WorldGraph.m_fGraphPresent ) - { - ALERT ( at_aiconsole, "find_hintnode: graph not ready!\n" ); - return NO_NODE; - } - - if ( WorldGraph.m_iLastActiveIdleSearch >= WorldGraph.m_cNodes ) - { - WorldGraph.m_iLastActiveIdleSearch = 0; - } - - for ( i = 0; i < WorldGraph.m_cNodes ; i++ ) - { - int nodeNumber = (i + WorldGraph.m_iLastActiveIdleSearch) % WorldGraph.m_cNodes; - CNode &node = WorldGraph.Node( nodeNumber ); - - if ( node.m_sHintType ) - { - // this node has a hint. Take it if it is visible, the monster likes it, and the monster has an animation to match the hint's activity. - if ( FValidateHintType ( node.m_sHintType ) ) - { - if ( !node.m_sHintActivity || LookupActivity ( node.m_sHintActivity ) != ACTIVITY_NOT_AVAILABLE ) - { - UTIL_TraceLine ( pev->origin + pev->view_ofs, node.m_vecOrigin + pev->view_ofs, ignore_monsters, ENT(pev), &tr ); - - if ( tr.flFraction == 1.0 ) - { - WorldGraph.m_iLastActiveIdleSearch = nodeNumber + 1; // next monster that searches for hint nodes will start where we left off. - return nodeNumber;// take it! - } - } - } - } - } - - WorldGraph.m_iLastActiveIdleSearch = 0;// start at the top of the list for the next search. - - return NO_NODE; -} - - -void CBaseMonster::ReportAIState( void ) -{ - ALERT_TYPE level = at_console; - - static const char *pStateNames[] = { "None", "Idle", "Combat", "Alert", "Hunt", "Prone", "Scripted", "Dead" }; - - ALERT( level, "%s: ", STRING(pev->classname) ); - if ( (int)m_MonsterState < ARRAYSIZE(pStateNames) ) - ALERT( level, "State: %s, ", pStateNames[m_MonsterState] ); - int i = 0; - while ( activity_map[i].type != 0 ) - { - if ( activity_map[i].type == (int)m_Activity ) - { - ALERT( level, "Activity %s, ", activity_map[i].name ); - break; - } - i++; - } - - if ( m_pSchedule ) - { - const char *pName = NULL; - pName = m_pSchedule->pName; - if ( !pName ) - pName = "Unknown"; - ALERT( level, "Schedule %s, ", pName ); - Task_t *pTask = GetTask(); - if ( pTask ) - ALERT( level, "Task %d (#%d), ", pTask->iTask, m_iScheduleIndex ); - } - else - ALERT( level, "No Schedule, " ); - - if ( m_hEnemy != NULL ) - ALERT( level, "\nEnemy is %s", STRING(m_hEnemy->pev->classname) ); - else - ALERT( level, "No enemy" ); - - if ( IsMoving() ) - { - ALERT( level, " Moving " ); - if ( m_flMoveWaitFinished > gpGlobals->time ) - ALERT( level, ": Stopped for %.2f. ", m_flMoveWaitFinished - gpGlobals->time ); - else if ( m_IdealActivity == GetStoppedActivity() ) - ALERT( level, ": In stopped anim. " ); - } - - CSquadMonster *pSquadMonster = MySquadMonsterPointer(); - - if ( pSquadMonster ) - { - if ( !pSquadMonster->InSquad() ) - { - ALERT ( level, "not " ); - } - - ALERT ( level, "In Squad, " ); - - if ( !pSquadMonster->IsLeader() ) - { - ALERT ( level, "not " ); - } - - ALERT ( level, "Leader." ); - } - - ALERT( level, "\n" ); - ALERT( level, "Yaw speed:%3.1f,Health: %3.1f\n", pev->yaw_speed, pev->health ); - if ( pev->spawnflags & SF_MONSTER_PRISONER ) - ALERT( level, " PRISONER! " ); - if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) - ALERT( level, " Pre-Disaster! " ); - ALERT( level, "\n" ); -} - -//========================================================= -// KeyValue -// -// !!! netname entvar field is used in squadmonster for groupname!!! -//========================================================= -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "TriggerTarget")) - { - m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TriggerCondition") ) - { - m_iTriggerCondition = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseToggle::KeyValue( pkvd ); - } -} - -//========================================================= -// FCheckAITrigger - checks the monster's AI Trigger Conditions, -// if there is a condition, then checks to see if condition is -// met. If yes, the monster's TriggerTarget is fired. -// -// Returns TRUE if the target is fired. -//========================================================= -BOOL CBaseMonster :: FCheckAITrigger ( void ) -{ - BOOL fFireTarget; - - if ( m_iTriggerCondition == AITRIGGER_NONE ) - { - // no conditions, so this trigger is never fired. - return FALSE; - } - - fFireTarget = FALSE; - - switch ( m_iTriggerCondition ) - { - case AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER: - if ( m_hEnemy != NULL && m_hEnemy->IsPlayer() && HasConditions ( bits_COND_SEE_ENEMY ) ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_SEEPLAYER_UNCONDITIONAL: - if ( HasConditions ( bits_COND_SEE_CLIENT ) ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_SEEPLAYER_NOT_IN_COMBAT: - if ( HasConditions ( bits_COND_SEE_CLIENT ) && - m_MonsterState != MONSTERSTATE_COMBAT && - m_MonsterState != MONSTERSTATE_PRONE && - m_MonsterState != MONSTERSTATE_SCRIPT) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_TAKEDAMAGE: - if ( m_afConditions & ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_DEATH: - if ( pev->deadflag != DEAD_NO ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_HALFHEALTH: - if ( IsAlive() && pev->health <= ( pev->max_health / 2 ) ) - { - fFireTarget = TRUE; - } - break; -/* - - // !!!UNDONE - no persistant game state that allows us to track these two. - - case AITRIGGER_SQUADMEMBERDIE: - break; - case AITRIGGER_SQUADLEADERDIE: - break; -*/ - case AITRIGGER_HEARWORLD: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_WORLD ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_HEARPLAYER: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_PLAYER ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_HEARCOMBAT: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_COMBAT ) - { - fFireTarget = TRUE; - } - break; - } - - if ( fFireTarget ) - { - // fire the target, then set the trigger conditions to NONE so we don't fire again - ALERT ( at_aiconsole, "AI Trigger Fire Target\n" ); - FireTargets( STRING( m_iszTriggerTarget ), this, this, USE_TOGGLE, 0 ); - m_iTriggerCondition = AITRIGGER_NONE; - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CanPlaySequence - determines whether or not the monster -// can play the scripted sequence or AI sequence that is -// trying to possess it. If DisregardState is set, the monster -// will be sucked into the script no matter what state it is -// in. ONLY Scripted AI ents should allow this. -//========================================================= -int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) -{ - if ( m_pCine || !IsAlive() || m_MonsterState == MONSTERSTATE_PRONE ) - { - // monster is already running a scripted sequence or dead! - return FALSE; - } - - if ( fDisregardMonsterState ) - { - // ok to go, no matter what the monster state. (scripted AI) - return TRUE; - } - - if ( m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE ) - { - // ok to go, but only in these states - return TRUE; - } - - if ( m_MonsterState == MONSTERSTATE_ALERT && interruptLevel >= SS_INTERRUPT_BY_NAME ) - return TRUE; - - // unknown situation - return FALSE; -} - - -//========================================================= -// FindLateralCover - attempts to locate a spot in the world -// directly to the left or right of the caller that will -// conceal them from view of pSightEnt -//========================================================= -#define COVER_CHECKS 5// how many checks are made -#define COVER_DELTA 48// distance between checks - -BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) -{ - TraceResult tr; - Vector vecBestOnLeft; - Vector vecBestOnRight; - Vector vecLeftTest; - Vector vecRightTest; - Vector vecStepRight; - int i; - - UTIL_MakeVectors ( pev->angles ); - vecStepRight = gpGlobals->v_right * COVER_DELTA; - vecStepRight.z = 0; - - vecLeftTest = vecRightTest = pev->origin; - - for ( i = 0 ; i < COVER_CHECKS ; i++ ) - { - vecLeftTest = vecLeftTest - vecStepRight; - vecRightTest = vecRightTest + vecStepRight; - - // it's faster to check the SightEnt's visibility to the potential spot than to check the local move, so we do that first. - UTIL_TraceLine( vecThreat + vecViewOffset, vecLeftTest + pev->view_ofs, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); - - if (tr.flFraction != 1.0) - { - if ( FValidateCover ( vecLeftTest ) && CheckLocalMove( pev->origin, vecLeftTest, NULL, NULL ) == LOCALMOVE_VALID ) - { - if ( MoveToLocation( ACT_RUN, 0, vecLeftTest ) ) - { - return TRUE; - } - } - } - - // it's faster to check the SightEnt's visibility to the potential spot than to check the local move, so we do that first. - UTIL_TraceLine(vecThreat + vecViewOffset, vecRightTest + pev->view_ofs, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); - - if ( tr.flFraction != 1.0 ) - { - if ( FValidateCover ( vecRightTest ) && CheckLocalMove( pev->origin, vecRightTest, NULL, NULL ) == LOCALMOVE_VALID ) - { - if ( MoveToLocation( ACT_RUN, 0, vecRightTest ) ) - { - return TRUE; - } - } - } - } - - return FALSE; -} - - -Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) -{ - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy ) - { - return ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP - shootOrigin ).Normalize(); - } - else - return gpGlobals->v_forward; -} - - - -//========================================================= -// FacingIdeal - tells us if a monster is facing its ideal -// yaw. Created this function because many spots in the -// code were checking the yawdiff against this magic -// number. Nicer to have it in one place if we're gonna -// be stuck with it. -//========================================================= -BOOL CBaseMonster :: FacingIdeal( void ) -{ - if ( fabs( FlYawDiff() ) <= 0.006 )//!!!BUGBUG - no magic numbers!!! - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// FCanActiveIdle -//========================================================= -BOOL CBaseMonster :: FCanActiveIdle ( void ) -{ - /* - if ( m_MonsterState == MONSTERSTATE_IDLE && m_IdealMonsterState == MONSTERSTATE_IDLE && !IsMoving() ) - { - return TRUE; - } - */ - return FALSE; -} - - -void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) -{ - if ( pszSentence && IsAlive() ) - { - if ( pszSentence[0] == '!' ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, PITCH_NORM ); - else - SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, PITCH_NORM ); - } -} - - -void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - PlaySentence( pszSentence, duration, volume, attenuation ); -} - - -void CBaseMonster::SentenceStop( void ) -{ - EMIT_SOUND( edict(), CHAN_VOICE, "common/null.wav", 1.0, ATTN_IDLE ); -} - - -void CBaseMonster::CorpseFallThink( void ) -{ - if ( pev->flags & FL_ONGROUND ) - { - SetThink ( NULL ); - - SetSequenceBox( ); - UTIL_SetOrigin( pev, pev->origin );// link into world. - } - else - pev->nextthink = gpGlobals->time + 0.1; -} - -// Call after animation/pose is set up -void CBaseMonster :: MonsterInitDead( void ) -{ - InitBoneControllers(); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground - - pev->frame = 0; - ResetSequenceInfo( ); - pev->framerate = 0; - - // Copy health - pev->max_health = pev->health; - pev->deadflag = DEAD_DEAD; - - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - UTIL_SetOrigin( pev, pev->origin ); - - // Setup health counters, etc. - BecomeDead(); - SetThink( &CBaseMonster::CorpseFallThink ); - pev->nextthink = gpGlobals->time + 0.5; -} - -//========================================================= -// BBoxIsFlat - check to see if the monster's bounding box -// is lying flat on a surface (traces from all four corners -// are same length.) -//========================================================= -BOOL CBaseMonster :: BBoxFlat ( void ) -{ - TraceResult tr; - Vector vecPoint; - float flXSize, flYSize; - float flLength; - float flLength2; - - flXSize = pev->size.x / 2; - flYSize = pev->size.y / 2; - - vecPoint.x = pev->origin.x + flXSize; - vecPoint.y = pev->origin.y + flYSize; - vecPoint.z = pev->origin.z; - - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength = (vecPoint - tr.vecEndPos).Length(); - - vecPoint.x = pev->origin.x - flXSize; - vecPoint.y = pev->origin.y - flYSize; - - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength2 = (vecPoint - tr.vecEndPos).Length(); - if ( flLength2 > flLength ) - { - return FALSE; - } - flLength = flLength2; - - vecPoint.x = pev->origin.x - flXSize; - vecPoint.y = pev->origin.y + flYSize; - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength2 = (vecPoint - tr.vecEndPos).Length(); - if ( flLength2 > flLength ) - { - return FALSE; - } - flLength = flLength2; - - vecPoint.x = pev->origin.x + flXSize; - vecPoint.y = pev->origin.y - flYSize; - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength2 = (vecPoint - tr.vecEndPos).Length(); - if ( flLength2 > flLength ) - { - return FALSE; - } - flLength = flLength2; - - return TRUE; -} - -//========================================================= -// Get Enemy - tries to find the best suitable enemy for the monster. -//========================================================= -BOOL CBaseMonster :: GetEnemy ( void ) -{ - CBaseEntity *pNewEnemy; - - if ( HasConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_NEMESIS) ) - { - pNewEnemy = BestVisibleEnemy(); - - if ( pNewEnemy != m_hEnemy && pNewEnemy != NULL) - { - // DO NOT mess with the monster's m_hEnemy pointer unless the schedule the monster is currently running will be interrupted - // by COND_NEW_ENEMY. This will eliminate the problem of monsters getting a new enemy while they are in a schedule that doesn't care, - // and then not realizing it by the time they get to a schedule that does. I don't feel this is a good permanent fix. - - if ( m_pSchedule ) - { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) - { - PushEnemy( m_hEnemy, m_vecEnemyLKP ); - SetConditions(bits_COND_NEW_ENEMY); - m_hEnemy = pNewEnemy; - m_vecEnemyLKP = m_hEnemy->pev->origin; - } - // if the new enemy has an owner, take that one as well - if (pNewEnemy->pev->owner != NULL) - { - CBaseEntity *pOwner = GetMonsterPointer( pNewEnemy->pev->owner ); - if ( pOwner && (pOwner->pev->flags & FL_MONSTER) && IRelationship( pOwner ) != R_NO ) - PushEnemy( pOwner, m_vecEnemyLKP ); - } - } - } - } - - // remember old enemies - if (m_hEnemy == NULL && PopEnemy( )) - { - if ( m_pSchedule ) - { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) - { - SetConditions(bits_COND_NEW_ENEMY); - } - } - } - - if ( m_hEnemy != NULL ) - { - // monster has an enemy. - return TRUE; - } - - return FALSE;// monster has no enemy -} - - -//========================================================= -// DropItem - dead monster drops named item -//========================================================= -CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) -{ - if ( !pszItemName ) - { - ALERT ( at_console, "DropItem() - No item name!\n" ); - return NULL; - } - - CBaseEntity *pItem = CBaseEntity::Create( pszItemName, vecPos, vecAng, edict() ); - - if ( pItem ) - { - // do we want this behavior to be default?! (sjb) - pItem->pev->velocity = pev->velocity; - pItem->pev->avelocity = Vector ( (float)0, (float)RANDOM_FLOAT( 0, 100 ), (float)0 ); - return pItem; - } - else - { - ALERT ( at_console, "DropItem() - Didn't create!\n" ); - return FALSE; - } - -} - - -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) -{ - // if flagged to fade out or I have an owner (I came from a monster spawner) - if ( (pev->spawnflags & SF_MONSTER_FADECORPSE) || !FNullEnt( pev->owner ) ) - return TRUE; - - return FALSE; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +/* + +===== monsters.cpp ======================================================== + + Monster-related utility code + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "nodes.h" +#include "monsters.h" +#include "animation.h" +#include "saverestore.h" +#include "weapons.h" +#include "scripted.h" +#include "squadmonster.h" +#include "decals.h" +#include "soundent.h" +#include "gamerules.h" + +#define MONSTER_CUT_CORNER_DIST 8 // 8 means the monster's bounding box is contained without the box of the node in WC + + +Vector VecBModelOrigin( entvars_t* pevBModel ); + +extern DLL_GLOBAL BOOL g_fDrawLines; +extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam +extern DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot + +extern CGraph WorldGraph;// the world node graph + + + +// Global Savedata for monster +// UNDONE: Save schedule data? Can this be done? We may +// lose our enemy pointer or other data (goal ent, target, etc) +// that make the current schedule invalid, perhaps it's best +// to just pick a new one when we start up again. +TYPEDESCRIPTION CBaseMonster::m_SaveData[] = +{ + DEFINE_FIELD( CBaseMonster, m_hEnemy, FIELD_EHANDLE ), + DEFINE_FIELD( CBaseMonster, m_hTargetEnt, FIELD_EHANDLE ), + DEFINE_ARRAY( CBaseMonster, m_hOldEnemy, FIELD_EHANDLE, MAX_OLD_ENEMIES ), + DEFINE_ARRAY( CBaseMonster, m_vecOldEnemy, FIELD_POSITION_VECTOR, MAX_OLD_ENEMIES ), + DEFINE_FIELD( CBaseMonster, m_flFieldOfView, FIELD_FLOAT ), + DEFINE_FIELD( CBaseMonster, m_flWaitFinished, FIELD_TIME ), + DEFINE_FIELD( CBaseMonster, m_flMoveWaitFinished, FIELD_TIME ), + + DEFINE_FIELD( CBaseMonster, m_Activity, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_IdealActivity, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_LastHitGroup, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_MonsterState, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_IdealMonsterState, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_iTaskStatus, FIELD_INTEGER ), + + //Schedule_t *m_pSchedule; + + DEFINE_FIELD( CBaseMonster, m_iScheduleIndex, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_afConditions, FIELD_INTEGER ), + //WayPoint_t m_Route[ ROUTE_SIZE ]; +// DEFINE_FIELD( CBaseMonster, m_movementGoal, FIELD_INTEGER ), +// DEFINE_FIELD( CBaseMonster, m_iRouteIndex, FIELD_INTEGER ), +// DEFINE_FIELD( CBaseMonster, m_moveWaitTime, FIELD_FLOAT ), + + DEFINE_FIELD( CBaseMonster, m_vecMoveGoal, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseMonster, m_movementActivity, FIELD_INTEGER ), + + // int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. +// DEFINE_FIELD( CBaseMonster, m_afSoundTypes, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_vecLastPosition, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseMonster, m_iHintNode, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_afMemory, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_iMaxHealth, FIELD_INTEGER ), + + DEFINE_FIELD( CBaseMonster, m_vecEnemyLKP, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseMonster, m_cAmmoLoaded, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_afCapability, FIELD_INTEGER ), + + DEFINE_FIELD( CBaseMonster, m_flNextAttack, FIELD_TIME ), + DEFINE_FIELD( CBaseMonster, m_bitsDamageType, FIELD_INTEGER ), + DEFINE_ARRAY( CBaseMonster, m_rgbTimeBasedDamage, FIELD_CHARACTER, CDMG_TIMEBASED ), + DEFINE_FIELD( CBaseMonster, m_bloodColor, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_failSchedule, FIELD_INTEGER ), + + DEFINE_FIELD( CBaseMonster, m_flHungryTime, FIELD_TIME ), + DEFINE_FIELD( CBaseMonster, m_flDistTooFar, FIELD_FLOAT ), + DEFINE_FIELD( CBaseMonster, m_flDistLook, FIELD_FLOAT ), + DEFINE_FIELD( CBaseMonster, m_iTriggerCondition, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_iszTriggerTarget, FIELD_STRING ), + + DEFINE_FIELD( CBaseMonster, m_HackedGunPos, FIELD_VECTOR ), + + DEFINE_FIELD( CBaseMonster, m_scriptState, FIELD_INTEGER ), + DEFINE_FIELD( CBaseMonster, m_pCine, FIELD_CLASSPTR ), +}; + +//IMPLEMENT_SAVERESTORE( CBaseMonster, CBaseToggle ); +int CBaseMonster::Save( CSave &save ) +{ + if ( !CBaseToggle::Save(save) ) + return 0; + return save.WriteFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); +} + +int CBaseMonster::Restore( CRestore &restore ) +{ + if ( !CBaseToggle::Restore(restore) ) + return 0; + int status = restore.ReadFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); + + // We don't save/restore routes yet + RouteClear(); + + // We don't save/restore schedules yet + m_pSchedule = NULL; + m_iTaskStatus = TASKSTATUS_NEW; + + // Reset animation + m_Activity = ACT_RESET; + + // If we don't have an enemy, clear conditions like see enemy, etc. + if ( m_hEnemy == NULL ) + m_afConditions = 0; + + return status; +} + + +//========================================================= +// Eat - makes a monster full for a little while. +//========================================================= +void CBaseMonster :: Eat ( float flFullDuration ) +{ + m_flHungryTime = gpGlobals->time + flFullDuration; +} + +//========================================================= +// FShouldEat - returns true if a monster is hungry. +//========================================================= +BOOL CBaseMonster :: FShouldEat ( void ) +{ + if ( m_flHungryTime > gpGlobals->time ) + { + return FALSE; + } + + return TRUE; +} + +//========================================================= +// BarnacleVictimBitten - called +// by Barnacle victims when the barnacle pulls their head +// into its mouth +//========================================================= +void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) +{ + Schedule_t *pNewSchedule; + + pNewSchedule = GetScheduleOfType( SCHED_BARNACLE_VICTIM_CHOMP ); + + if ( pNewSchedule ) + { + ChangeSchedule( pNewSchedule ); + } +} + +//========================================================= +// BarnacleVictimReleased - called by barnacle victims when +// the host barnacle is killed. +//========================================================= +void CBaseMonster :: BarnacleVictimReleased ( void ) +{ + m_IdealMonsterState = MONSTERSTATE_IDLE; + + pev->velocity = g_vecZero; + pev->movetype = MOVETYPE_STEP; +} + +//========================================================= +// Listen - monsters dig through the active sound list for +// any sounds that may interest them. (smells, too!) +//========================================================= +void CBaseMonster :: Listen ( void ) +{ + int iSound; + int iMySounds; + float hearingSensitivity; + CSound *pCurrentSound; + + m_iAudibleList = SOUNDLIST_EMPTY; + ClearConditions(bits_COND_HEAR_SOUND | bits_COND_SMELL | bits_COND_SMELL_FOOD); + m_afSoundTypes = 0; + + iMySounds = ISoundMask(); + + if ( m_pSchedule ) + { + //!!!WATCH THIS SPOT IF YOU ARE HAVING SOUND RELATED BUGS! + // Make sure your schedule AND personal sound masks agree! + iMySounds &= m_pSchedule->iSoundMask; + } + + iSound = CSoundEnt::ActiveList(); + + // UNDONE: Clear these here? + ClearConditions( bits_COND_HEAR_SOUND | bits_COND_SMELL_FOOD | bits_COND_SMELL ); + hearingSensitivity = HearingSensitivity( ); + + while ( iSound != SOUNDLIST_EMPTY ) + { + pCurrentSound = CSoundEnt::SoundPointerForIndex( iSound ); + + if ( pCurrentSound && + ( pCurrentSound->m_iType & iMySounds ) && + ( pCurrentSound->m_vecOrigin - EarPosition() ).Length() <= pCurrentSound->m_iVolume * hearingSensitivity ) + + //if ( ( g_pSoundEnt->m_SoundPool[ iSound ].m_iType & iMySounds ) && ( g_pSoundEnt->m_SoundPool[ iSound ].m_vecOrigin - EarPosition()).Length () <= g_pSoundEnt->m_SoundPool[ iSound ].m_iVolume * hearingSensitivity ) + { + // the monster cares about this sound, and it's close enough to hear. + //g_pSoundEnt->m_SoundPool[ iSound ].m_iNextAudible = m_iAudibleList; + pCurrentSound->m_iNextAudible = m_iAudibleList; + + if ( pCurrentSound->FIsSound() ) + { + // this is an audible sound. + SetConditions( bits_COND_HEAR_SOUND ); + } + else + { + // if not a sound, must be a smell - determine if it's just a scent, or if it's a food scent +// if ( g_pSoundEnt->m_SoundPool[ iSound ].m_iType & ( bits_SOUND_MEAT | bits_SOUND_CARCASS ) ) + if ( pCurrentSound->m_iType & ( bits_SOUND_MEAT | bits_SOUND_CARCASS ) ) + { + // the detected scent is a food item, so set both conditions. + // !!!BUGBUG - maybe a virtual function to determine whether or not the scent is food? + SetConditions( bits_COND_SMELL_FOOD ); + SetConditions( bits_COND_SMELL ); + } + else + { + // just a normal scent. + SetConditions( bits_COND_SMELL ); + } + } + +// m_afSoundTypes |= g_pSoundEnt->m_SoundPool[ iSound ].m_iType; + m_afSoundTypes |= pCurrentSound->m_iType; + + m_iAudibleList = iSound; + } + +// iSound = g_pSoundEnt->m_SoundPool[ iSound ].m_iNext; + iSound = pCurrentSound->m_iNext; + } +} + +//========================================================= +// FLSoundVolume - subtracts the volume of the given sound +// from the distance the sound source is from the caller, +// and returns that value, which is considered to be the 'local' +// volume of the sound. +//========================================================= +float CBaseMonster :: FLSoundVolume ( CSound *pSound ) +{ + return ( pSound->m_iVolume - ( ( pSound->m_vecOrigin - pev->origin ).Length() ) ); +} + +//========================================================= +// FValidateHintType - tells use whether or not the monster cares +// about the type of Hint Node given +//========================================================= +BOOL CBaseMonster :: FValidateHintType ( short sHint ) +{ + return FALSE; +} + +//========================================================= +// Look - Base class monster function to find enemies or +// food by sight. iDistance is distance ( in units ) that the +// monster can see. +// +// Sets the sight bits of the m_afConditions mask to indicate +// which types of entities were sighted. +// Function also sets the Looker's m_pLink +// to the head of a link list that contains all visible ents. +// (linked via each ent's m_pLink field) +// +//========================================================= +void CBaseMonster :: Look ( int iDistance ) +{ + int iSighted = 0; + + // DON'T let visibility information from last frame sit around! + ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); + + m_pLink = NULL; + + CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with + + // See no evil if prisoner is set + if ( !FBitSet( pev->spawnflags, SF_MONSTER_PRISONER ) ) + { + CBaseEntity *pList[100]; + + Vector delta = Vector( iDistance, iDistance, iDistance ); + + // Find only monsters/clients in box, NOT limited to PVS + int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); + for ( int i = 0; i < count; i++ ) + { + pSightEnt = pList[i]; + // !!!temporarily only considering other monsters and clients, don't see prisoners + if ( pSightEnt != this && + !FBitSet( pSightEnt->pev->spawnflags, SF_MONSTER_PRISONER ) && + pSightEnt->pev->health > 0 ) + { + // the looker will want to consider this entity + // don't check anything else about an entity that can't be seen, or an entity that you don't care about. + if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) + { + if ( pSightEnt->IsPlayer() ) + { + if ( pev->spawnflags & SF_MONSTER_WAIT_TILL_SEEN ) + { + CBaseMonster *pClient; + + pClient = pSightEnt->MyMonsterPointer(); + // don't link this client in the list if the monster is wait till seen and the player isn't facing the monster + if ( pSightEnt && !pClient->FInViewCone( this ) ) + { + // we're not in the player's view cone. + continue; + } + else + { + // player sees us, become normal now. + pev->spawnflags &= ~SF_MONSTER_WAIT_TILL_SEEN; + } + } + + // if we see a client, remember that (mostly for scripted AI) + iSighted |= bits_COND_SEE_CLIENT; + } + + pSightEnt->m_pLink = m_pLink; + m_pLink = pSightEnt; + + if ( pSightEnt == m_hEnemy ) + { + // we know this ent is visible, so if it also happens to be our enemy, store that now. + iSighted |= bits_COND_SEE_ENEMY; + } + + // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when + // we see monsters other than the Enemy. + switch ( IRelationship ( pSightEnt ) ) + { + case R_NM: + iSighted |= bits_COND_SEE_NEMESIS; + break; + case R_HT: + iSighted |= bits_COND_SEE_HATE; + break; + case R_DL: + iSighted |= bits_COND_SEE_DISLIKE; + break; + case R_FR: + iSighted |= bits_COND_SEE_FEAR; + break; + case R_AL: + break; + default: + ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); + break; + } + } + } + } + } + + SetConditions( iSighted ); +} + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. In the base class implementation, +// monsters care about all sounds, but no scents. +//========================================================= +int CBaseMonster :: ISoundMask ( void ) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER; +} + +//========================================================= +// PBestSound - returns a pointer to the sound the monster +// should react to. Right now responds only to nearest sound. +//========================================================= +CSound* CBaseMonster :: PBestSound ( void ) +{ + int iThisSound; + int iBestSound = -1; + float flBestDist = 8192;// so first nearby sound will become best so far. + float flDist; + CSound *pSound; + + iThisSound = m_iAudibleList; + + if ( iThisSound == SOUNDLIST_EMPTY ) + { + ALERT ( at_aiconsole, "ERROR! monster %s has no audible sounds!\n", STRING(pev->classname) ); +#if _DEBUG + ALERT( at_error, "NULL Return from PBestSound\n" ); +#endif + return NULL; + } + + while ( iThisSound != SOUNDLIST_EMPTY ) + { + pSound = CSoundEnt::SoundPointerForIndex( iThisSound ); + + if ( pSound && pSound->FIsSound() ) + { + flDist = ( pSound->m_vecOrigin - EarPosition()).Length(); + + if ( flDist < flBestDist ) + { + iBestSound = iThisSound; + flBestDist = flDist; + } + } + + iThisSound = pSound->m_iNextAudible; + } + if ( iBestSound >= 0 ) + { + pSound = CSoundEnt::SoundPointerForIndex( iBestSound ); + return pSound; + } +#if _DEBUG + ALERT( at_error, "NULL Return from PBestSound\n" ); +#endif + return NULL; +} + +//========================================================= +// PBestScent - returns a pointer to the scent the monster +// should react to. Right now responds only to nearest scent +//========================================================= +CSound* CBaseMonster :: PBestScent ( void ) +{ + int iThisScent; + int iBestScent = -1; + float flBestDist = 8192;// so first nearby smell will become best so far. + float flDist; + CSound *pSound; + + iThisScent = m_iAudibleList;// smells are in the sound list. + + if ( iThisScent == SOUNDLIST_EMPTY ) + { + ALERT ( at_aiconsole, "ERROR! PBestScent() has empty soundlist!\n" ); +#if _DEBUG + ALERT( at_error, "NULL Return from PBestSound\n" ); +#endif + return NULL; + } + + while ( iThisScent != SOUNDLIST_EMPTY ) + { + pSound = CSoundEnt::SoundPointerForIndex( iThisScent ); + + if ( pSound->FIsScent() ) + { + flDist = ( pSound->m_vecOrigin - pev->origin ).Length(); + + if ( flDist < flBestDist ) + { + iBestScent = iThisScent; + flBestDist = flDist; + } + } + + iThisScent = pSound->m_iNextAudible; + } + if ( iBestScent >= 0 ) + { + pSound = CSoundEnt::SoundPointerForIndex( iBestScent ); + + return pSound; + } +#if _DEBUG + ALERT( at_error, "NULL Return from PBestScent\n" ); +#endif + return NULL; +} + + + +//========================================================= +// Monster Think - calls out to core AI functions and handles this +// monster's specific animation events +//========================================================= +void CBaseMonster :: MonsterThink ( void ) +{ + pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking. + + + RunAI(); + + float flInterval = StudioFrameAdvance( ); // animate +// start or end a fidget +// This needs a better home -- switching animations over time should be encapsulated on a per-activity basis +// perhaps MaintainActivity() or a ShiftAnimationOverTime() or something. + if ( m_MonsterState != MONSTERSTATE_SCRIPT && m_MonsterState != MONSTERSTATE_DEAD && m_Activity == ACT_IDLE && m_fSequenceFinished ) + { + int iSequence; + + if ( m_fSequenceLoops ) + { + // animation does loop, which means we're playing subtle idle. Might need to + // fidget. + iSequence = LookupActivity ( m_Activity ); + } + else + { + // animation that just ended doesn't loop! That means we just finished a fidget + // and should return to our heaviest weighted idle (the subtle one) + iSequence = LookupActivityHeaviest ( m_Activity ); + } + if ( iSequence != ACTIVITY_NOT_AVAILABLE ) + { + pev->sequence = iSequence; // Set to new anim (if it's there) + ResetSequenceInfo( ); + } + } + + DispatchAnimEvents( flInterval ); + + if ( !MovementIsComplete() ) + { + Move( flInterval ); + } +#if _DEBUG + else + { + if ( !TaskIsRunning() && !TaskIsComplete() ) + ALERT( at_error, "Schedule stalled!!\n" ); + } +#endif +} + +//========================================================= +// CBaseMonster - USE - will make a monster angry at whomever +// activated it. +//========================================================= +void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + m_IdealMonsterState = MONSTERSTATE_ALERT; +} + +//========================================================= +// Ignore conditions - before a set of conditions is allowed +// to interrupt a monster's schedule, this function removes +// conditions that we have flagged to interrupt the current +// schedule, but may not want to interrupt the schedule every +// time. (Pain, for instance) +//========================================================= +int CBaseMonster :: IgnoreConditions ( void ) +{ + int iIgnoreConditions = 0; + + if ( !FShouldEat() ) + { + // not hungry? Ignore food smell. + iIgnoreConditions |= bits_COND_SMELL_FOOD; + } + + if ( m_MonsterState == MONSTERSTATE_SCRIPT && m_pCine ) + iIgnoreConditions |= m_pCine->IgnoreConditions(); + + return iIgnoreConditions; +} + +//========================================================= +// RouteClear - zeroes out the monster's route array and goal +//========================================================= +void CBaseMonster :: RouteClear ( void ) +{ + RouteNew(); + m_movementGoal = MOVEGOAL_NONE; + m_movementActivity = ACT_IDLE; + Forget( bits_MEMORY_MOVE_FAILED ); +} + +//========================================================= +// Route New - clears out a route to be changed, but keeps +// goal intact. +//========================================================= +void CBaseMonster :: RouteNew ( void ) +{ + m_Route[ 0 ].iType = 0; + m_iRouteIndex = 0; +} + +//========================================================= +// FRouteClear - returns TRUE is the Route is cleared out +// ( invalid ) +//========================================================= +BOOL CBaseMonster :: FRouteClear ( void ) +{ + if ( m_Route[ m_iRouteIndex ].iType == 0 || m_movementGoal == MOVEGOAL_NONE ) + return TRUE; + + return FALSE; +} + +//========================================================= +// FRefreshRoute - after calculating a path to the monster's +// target, this function copies as many waypoints as possible +// from that path to the monster's Route array +//========================================================= +BOOL CBaseMonster :: FRefreshRoute ( void ) +{ + CBaseEntity *pPathCorner; + int i; + BOOL returnCode; + + RouteNew(); + + returnCode = FALSE; + + switch( m_movementGoal ) + { + case MOVEGOAL_PATHCORNER: + { + // monster is on a path_corner loop + pPathCorner = m_pGoalEnt; + i = 0; + + while ( pPathCorner && i < ROUTE_SIZE ) + { + m_Route[ i ].iType = bits_MF_TO_PATHCORNER; + m_Route[ i ].vecLocation = pPathCorner->pev->origin; + + pPathCorner = pPathCorner->GetNextTarget(); + + // Last path_corner in list? + if ( !pPathCorner ) + m_Route[i].iType |= bits_MF_IS_GOAL; + + i++; + } + } + returnCode = TRUE; + break; + + case MOVEGOAL_ENEMY: + returnCode = BuildRoute( m_vecEnemyLKP, bits_MF_TO_ENEMY, m_hEnemy ); + break; + + case MOVEGOAL_LOCATION: + returnCode = BuildRoute( m_vecMoveGoal, bits_MF_TO_LOCATION, NULL ); + break; + + case MOVEGOAL_TARGETENT: + if (m_hTargetEnt != NULL) + { + returnCode = BuildRoute( m_hTargetEnt->pev->origin, bits_MF_TO_TARGETENT, m_hTargetEnt ); + } + break; + + case MOVEGOAL_NODE: + returnCode = FGetNodeRoute( m_vecMoveGoal ); +// if ( returnCode ) +// RouteSimplify( NULL ); + break; + } + + return returnCode; +} + + +BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) +{ + m_movementActivity = movementAct; + m_moveWaitTime = waitTime; + + m_movementGoal = MOVEGOAL_ENEMY; + return FRefreshRoute(); +} + + +BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) +{ + m_movementActivity = movementAct; + m_moveWaitTime = waitTime; + + m_movementGoal = MOVEGOAL_LOCATION; + m_vecMoveGoal = goal; + return FRefreshRoute(); +} + + +BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) +{ + m_movementActivity = movementAct; + m_moveWaitTime = waitTime; + + m_movementGoal = MOVEGOAL_TARGETENT; + return FRefreshRoute(); +} + + +BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) +{ + m_movementActivity = movementAct; + m_moveWaitTime = waitTime; + + m_movementGoal = MOVEGOAL_NODE; + m_vecMoveGoal = goal; + return FRefreshRoute(); +} + + +#ifdef _DEBUG +void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ) +{ + int i; + + if ( m_Route[m_iRouteIndex].iType == 0 ) + { + ALERT( at_aiconsole, "Can't draw route!\n" ); + return; + } + +// UTIL_ParticleEffect ( m_Route[ m_iRouteIndex ].vecLocation, g_vecZero, 255, 25 ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.x ); + WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.y ); + WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.z ); + + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 1 ); // life + WRITE_BYTE( 16 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( r ); // r, g, b + WRITE_BYTE( g ); // r, g, b + WRITE_BYTE( b ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); + + for ( i = m_iRouteIndex ; i < ROUTE_SIZE - 1; i++ ) + { + if ( (m_Route[ i ].iType & bits_MF_IS_GOAL) || (m_Route[ i+1 ].iType == 0) ) + break; + + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD( m_Route[ i ].vecLocation.x ); + WRITE_COORD( m_Route[ i ].vecLocation.y ); + WRITE_COORD( m_Route[ i ].vecLocation.z ); + WRITE_COORD( m_Route[ i + 1 ].vecLocation.x ); + WRITE_COORD( m_Route[ i + 1 ].vecLocation.y ); + WRITE_COORD( m_Route[ i + 1 ].vecLocation.z ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 1 ); // life + WRITE_BYTE( 8 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( r ); // r, g, b + WRITE_BYTE( g ); // r, g, b + WRITE_BYTE( b ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); + +// UTIL_ParticleEffect ( m_Route[ i ].vecLocation, g_vecZero, 255, 25 ); + } +} +#endif + + +int ShouldSimplify( int routeType ) +{ + routeType &= ~bits_MF_IS_GOAL; + + if ( (routeType == bits_MF_TO_PATHCORNER) || (routeType & bits_MF_DONT_SIMPLIFY) ) + return FALSE; + return TRUE; +} + +//========================================================= +// RouteSimplify +// +// Attempts to make the route more direct by cutting out +// unnecessary nodes & cutting corners. +// +//========================================================= +void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) +{ + // BUGBUG: this doesn't work 100% yet + int i, count, outCount; + Vector vecStart; + WayPoint_t outRoute[ ROUTE_SIZE * 2 ]; // Any points except the ends can turn into 2 points in the simplified route + + count = 0; + + for ( i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) + { + if ( !m_Route[i].iType ) + break; + else + count++; + if ( m_Route[i].iType & bits_MF_IS_GOAL ) + break; + } + // Can't simplify a direct route! + if ( count < 2 ) + { +// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); + return; + } + + outCount = 0; + vecStart = pev->origin; + for ( i = 0; i < count-1; i++ ) + { + // Don't eliminate path_corners + if ( !ShouldSimplify( m_Route[m_iRouteIndex+i].iType ) ) + { + outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; + outCount++; + } + else if ( CheckLocalMove ( vecStart, m_Route[m_iRouteIndex+i+1].vecLocation, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + // Skip vert + continue; + } + else + { + Vector vecTest, vecSplit; + + // Halfway between this and next + vecTest = (m_Route[m_iRouteIndex+i+1].vecLocation + m_Route[m_iRouteIndex+i].vecLocation) * 0.5; + + // Halfway between this and previous + vecSplit = (m_Route[m_iRouteIndex+i].vecLocation + vecStart) * 0.5; + + int iType = (m_Route[m_iRouteIndex+i].iType | bits_MF_TO_DETOUR) & ~bits_MF_NOT_TO_MASK; + if ( CheckLocalMove ( vecStart, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + outRoute[outCount].iType = iType; + outRoute[outCount].vecLocation = vecTest; + } + else if ( CheckLocalMove ( vecSplit, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + outRoute[outCount].iType = iType; + outRoute[outCount].vecLocation = vecSplit; + outRoute[outCount+1].iType = iType; + outRoute[outCount+1].vecLocation = vecTest; + outCount++; // Adding an extra point + } + else + { + outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; + } + } + // Get last point + vecStart = outRoute[ outCount ].vecLocation; + outCount++; + } + ASSERT( i < count ); + outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; + outCount++; + + // Terminate + outRoute[outCount].iType = 0; + ASSERT( outCount < (ROUTE_SIZE*2) ); + +// Copy the simplified route, disable for testing + m_iRouteIndex = 0; + for ( i = 0; i < ROUTE_SIZE && i < outCount; i++ ) + { + m_Route[i] = outRoute[i]; + } + + // Terminate route + if ( i < ROUTE_SIZE ) + m_Route[i].iType = 0; + +// Debug, test movement code +#if 0 +// if ( CVAR_GET_FLOAT( "simplify" ) != 0 ) + DrawRoute( pev, outRoute, 0, 255, 0, 0 ); +// else + DrawRoute( pev, m_Route, m_iRouteIndex, 0, 255, 0 ); +#endif +} + +//========================================================= +// FBecomeProne - tries to send a monster into PRONE state. +// right now only used when a barnacle snatches someone, so +// may have some special case stuff for that. +//========================================================= +BOOL CBaseMonster :: FBecomeProne ( void ) +{ + if ( FBitSet ( pev->flags, FL_ONGROUND ) ) + { + pev->flags -= FL_ONGROUND; + } + + m_IdealMonsterState = MONSTERSTATE_PRONE; + return TRUE; +} + +//========================================================= +// CheckRangeAttack1 +//========================================================= +BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) +{ + if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckRangeAttack2 +//========================================================= +BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) +{ + if ( flDist > 64 && flDist <= 512 && flDot >= 0.5 ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckMeleeAttack1 +//========================================================= +BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) +{ + // Decent fix to keep folks from kicking/punching hornets and snarks is to check the onground flag(sjb) + if ( flDist <= 64 && flDot >= 0.7 && m_hEnemy != NULL && FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckMeleeAttack2 +//========================================================= +BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) +{ + if ( flDist <= 64 && flDot >= 0.7 ) + { + return TRUE; + } + return FALSE; +} + +//========================================================= +// CheckAttacks - sets all of the bits for attacks that the +// monster is capable of carrying out on the passed entity. +//========================================================= +void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) +{ + Vector2D vec2LOS; + float flDot; + + UTIL_MakeVectors ( pev->angles ); + + vec2LOS = ( pTarget->pev->origin - pev->origin ).Make2D(); + vec2LOS = vec2LOS.Normalize(); + + flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + + // we know the enemy is in front now. We'll find which attacks the monster is capable of by + // checking for corresponding Activities in the model file, then do the simple checks to validate + // those attack types. + + // Clear all attack conditions + ClearConditions( bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK1 |bits_COND_CAN_MELEE_ATTACK2 ); + + if ( m_afCapability & bits_CAP_RANGE_ATTACK1 ) + { + if ( CheckRangeAttack1 ( flDot, flDist ) ) + SetConditions( bits_COND_CAN_RANGE_ATTACK1 ); + } + if ( m_afCapability & bits_CAP_RANGE_ATTACK2 ) + { + if ( CheckRangeAttack2 ( flDot, flDist ) ) + SetConditions( bits_COND_CAN_RANGE_ATTACK2 ); + } + if ( m_afCapability & bits_CAP_MELEE_ATTACK1 ) + { + if ( CheckMeleeAttack1 ( flDot, flDist ) ) + SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); + } + if ( m_afCapability & bits_CAP_MELEE_ATTACK2 ) + { + if ( CheckMeleeAttack2 ( flDot, flDist ) ) + SetConditions( bits_COND_CAN_MELEE_ATTACK2 ); + } +} + +//========================================================= +// CanCheckAttacks - prequalifies a monster to do more fine +// checking of potential attacks. +//========================================================= +BOOL CBaseMonster :: FCanCheckAttacks ( void ) +{ + if ( HasConditions(bits_COND_SEE_ENEMY) && !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// CheckEnemy - part of the Condition collection process, +// gets and stores data and conditions pertaining to a monster's +// enemy. Returns TRUE if Enemy LKP was updated. +//========================================================= +int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) +{ + float flDistToEnemy; + int iUpdatedLKP;// set this to TRUE if you update the EnemyLKP in this function. + + iUpdatedLKP = FALSE; + ClearConditions ( bits_COND_ENEMY_FACING_ME ); + + if ( !FVisible( pEnemy ) ) + { + ASSERT(!HasConditions(bits_COND_SEE_ENEMY)); + SetConditions( bits_COND_ENEMY_OCCLUDED ); + } + else + ClearConditions( bits_COND_ENEMY_OCCLUDED ); + + if ( !pEnemy->IsAlive() ) + { + SetConditions ( bits_COND_ENEMY_DEAD ); + ClearConditions( bits_COND_SEE_ENEMY | bits_COND_ENEMY_OCCLUDED ); + return FALSE; + } + + Vector vecEnemyPos = pEnemy->pev->origin; + // distance to enemy's origin + flDistToEnemy = ( vecEnemyPos - pev->origin ).Length(); + vecEnemyPos.z += pEnemy->pev->size.z * 0.5; + // distance to enemy's head + float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); + if (flDistToEnemy2 < flDistToEnemy) + flDistToEnemy = flDistToEnemy2; + else + { + // distance to enemy's feet + vecEnemyPos.z -= pEnemy->pev->size.z; + float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); + if (flDistToEnemy2 < flDistToEnemy) + flDistToEnemy = flDistToEnemy2; + } + + if ( HasConditions( bits_COND_SEE_ENEMY ) ) + { + CBaseMonster *pEnemyMonster; + + iUpdatedLKP = TRUE; + m_vecEnemyLKP = pEnemy->pev->origin; + + pEnemyMonster = pEnemy->MyMonsterPointer(); + + if ( pEnemyMonster ) + { + if ( pEnemyMonster->FInViewCone ( this ) ) + { + SetConditions ( bits_COND_ENEMY_FACING_ME ); + } + else + ClearConditions( bits_COND_ENEMY_FACING_ME ); + } + + if (pEnemy->pev->velocity != Vector( 0, 0, 0)) + { + // trail the enemy a bit + m_vecEnemyLKP = m_vecEnemyLKP - pEnemy->pev->velocity * RANDOM_FLOAT( -0.05, 0 ); + } + else + { + // UNDONE: use pev->oldorigin? + } + } + else if ( !HasConditions(bits_COND_ENEMY_OCCLUDED|bits_COND_SEE_ENEMY) && ( flDistToEnemy <= 256 ) ) + { + // if the enemy is not occluded, and unseen, that means it is behind or beside the monster. + // if the enemy is near enough the monster, we go ahead and let the monster know where the + // enemy is. + iUpdatedLKP = TRUE; + m_vecEnemyLKP = pEnemy->pev->origin; + } + + if ( flDistToEnemy >= m_flDistTooFar ) + { + // enemy is very far away from monster + SetConditions( bits_COND_ENEMY_TOOFAR ); + } + else + ClearConditions( bits_COND_ENEMY_TOOFAR ); + + if ( FCanCheckAttacks() ) + { + CheckAttacks ( m_hEnemy, flDistToEnemy ); + } + + if ( m_movementGoal == MOVEGOAL_ENEMY ) + { + for ( int i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) + { + if ( m_Route[ i ].iType == (bits_MF_IS_GOAL|bits_MF_TO_ENEMY) ) + { + // UNDONE: Should we allow monsters to override this distance (80?) + if ( (m_Route[ i ].vecLocation - m_vecEnemyLKP).Length() > 80 ) + { + // Refresh + FRefreshRoute(); + return iUpdatedLKP; + } + } + } + } + + return iUpdatedLKP; +} + +//========================================================= +// PushEnemy - remember the last few enemies, always remember the player +//========================================================= +void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) +{ + int i; + + if (pEnemy == NULL) + return; + + // UNDONE: blah, this is bad, we should use a stack but I'm too lazy to code one. + for (i = 0; i < MAX_OLD_ENEMIES; i++) + { + if (m_hOldEnemy[i] == pEnemy) + return; + if (m_hOldEnemy[i] == NULL) // someone died, reuse their slot + break; + } + if (i >= MAX_OLD_ENEMIES) + return; + + m_hOldEnemy[i] = pEnemy; + m_vecOldEnemy[i] = vecLastKnownPos; +} + +//========================================================= +// PopEnemy - try remembering the last few enemies +//========================================================= +BOOL CBaseMonster :: PopEnemy( ) +{ + // UNDONE: blah, this is bad, we should use a stack but I'm too lazy to code one. + for (int i = MAX_OLD_ENEMIES - 1; i >= 0; i--) + { + if (m_hOldEnemy[i] != NULL) + { + if (m_hOldEnemy[i]->IsAlive( )) // cheat and know when they die + { + m_hEnemy = m_hOldEnemy[i]; + m_vecEnemyLKP = m_vecOldEnemy[i]; + // ALERT( at_console, "remembering\n"); + return TRUE; + } + else + { + m_hOldEnemy[i] = NULL; + } + } + } + return FALSE; +} + +//========================================================= +// SetActivity +//========================================================= +void CBaseMonster :: SetActivity ( Activity NewActivity ) +{ + int iSequence; + + iSequence = LookupActivity ( NewActivity ); + + // Set to the desired anim, or default anim if the desired is not present + if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + { + if ( pev->sequence != iSequence || !m_fSequenceLoops ) + { + // don't reset frame between walk and run + if ( !(m_Activity == ACT_WALK || m_Activity == ACT_RUN) || !(NewActivity == ACT_WALK || NewActivity == ACT_RUN)) + pev->frame = 0; + } + + pev->sequence = iSequence; // Set to the reset anim (if it's there) + ResetSequenceInfo( ); + SetYawSpeed(); + } + else + { + // Not available try to get default anim + ALERT ( at_aiconsole, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); + pev->sequence = 0; // Set to the reset anim (if it's there) + } + + m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present + + // In case someone calls this with something other than the ideal activity + m_IdealActivity = m_Activity; + + +} + +//========================================================= +// SetSequenceByName +//========================================================= +void CBaseMonster :: SetSequenceByName ( char *szSequence ) +{ + int iSequence; + + iSequence = LookupSequence ( szSequence ); + + // Set to the desired anim, or default anim if the desired is not present + if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + { + if ( pev->sequence != iSequence || !m_fSequenceLoops ) + { + pev->frame = 0; + } + + pev->sequence = iSequence; // Set to the reset anim (if it's there) + ResetSequenceInfo( ); + SetYawSpeed(); + } + else + { + // Not available try to get default anim + ALERT ( at_aiconsole, "%s has no sequence named:%f\n", STRING(pev->classname), szSequence ); + pev->sequence = 0; // Set to the reset anim (if it's there) + } +} + +//========================================================= +// CheckLocalMove - returns TRUE if the caller can walk a +// straight line from its current origin to the given +// location. If so, don't use the node graph! +// +// if a valid pointer to a int is passed, the function +// will fill that int with the distance that the check +// reached before hitting something. THIS ONLY HAPPENS +// IF THE LOCAL MOVE CHECK FAILS! +// +// !!!PERFORMANCE - should we try to load balance this? +// DON"T USE SETORIGIN! +//========================================================= +#define LOCAL_STEP_SIZE 16 +int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) +{ + Vector vecStartPos;// record monster's position before trying the move + float flYaw; + float flDist; + float flStep, stepSize; + int iReturn; + + vecStartPos = pev->origin; + + + flYaw = UTIL_VecToYaw ( vecEnd - vecStart );// build a yaw that points to the goal. + flDist = ( vecEnd - vecStart ).Length2D();// get the distance. + iReturn = LOCALMOVE_VALID;// assume everything will be ok. + + // move the monster to the start of the local move that's to be checked. + UTIL_SetOrigin( pev, vecStart );// !!!BUGBUG - won't this fire triggers? - nope, SetOrigin doesn't fire + + if ( !(pev->flags & (FL_FLY|FL_SWIM)) ) + { + DROP_TO_FLOOR( ENT( pev ) );//make sure monster is on the floor! + } + + //pev->origin.z = vecStartPos.z;//!!!HACKHACK + +// pev->origin = vecStart; + +/* + if ( flDist > 1024 ) + { + // !!!PERFORMANCE - this operation may be too CPU intensive to try checks this large. + // We don't lose much here, because a distance this great is very likely + // to have something in the way. + + // since we've actually moved the monster during the check, undo the move. + pev->origin = vecStartPos; + return FALSE; + } +*/ + // this loop takes single steps to the goal. + for ( flStep = 0 ; flStep < flDist ; flStep += LOCAL_STEP_SIZE ) + { + stepSize = LOCAL_STEP_SIZE; + + if ( (flStep + LOCAL_STEP_SIZE) >= (flDist-1) ) + stepSize = (flDist - flStep) - 1; + +// UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); + + if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, WALKMOVE_CHECKONLY ) ) + {// can't take the next step, fail! + + if ( pflDist != NULL ) + { + *pflDist = flStep; + } + if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) + { + // if this step hits target ent, the move is legal. + iReturn = LOCALMOVE_VALID; + break; + } + else + { + // If we're going toward an entity, and we're almost getting there, it's OK. +// if ( pTarget && fabs( flDist - iStep ) < LOCAL_STEP_SIZE ) +// fReturn = TRUE; +// else + iReturn = LOCALMOVE_INVALID; + break; + } + + } + } + + if ( iReturn == LOCALMOVE_VALID && !(pev->flags & (FL_FLY|FL_SWIM) ) && (!pTarget || (pTarget->pev->flags & FL_ONGROUND)) ) + { + // The monster can move to a spot UNDER the target, but not to it. Don't try to triangulate, go directly to the node graph. + // UNDONE: Magic # 64 -- this used to be pev->size.z but that won't work for small creatures like the headcrab + if ( fabs(vecEnd.z - pev->origin.z) > 64 ) + { + iReturn = LOCALMOVE_INVALID_DONT_TRIANGULATE; + } + } + /* + // uncommenting this block will draw a line representing the nearest legal move. + WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); + WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); + WRITE_COORD(MSG_BROADCAST, pev->origin.x); + WRITE_COORD(MSG_BROADCAST, pev->origin.y); + WRITE_COORD(MSG_BROADCAST, pev->origin.z); + WRITE_COORD(MSG_BROADCAST, vecStart.x); + WRITE_COORD(MSG_BROADCAST, vecStart.y); + WRITE_COORD(MSG_BROADCAST, vecStart.z); + */ + + // since we've actually moved the monster during the check, undo the move. + UTIL_SetOrigin( pev, vecStartPos ); + + return iReturn; +} + + +float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) +{ + float flTravelTime = 0; + + //ALERT(at_aiconsole, "A door. "); + CBaseEntity *pcbeDoor = CBaseEntity::Instance(pevDoor); + if (pcbeDoor && !pcbeDoor->IsLockedByMaster()) + { + //ALERT(at_aiconsole, "unlocked! "); + pcbeDoor->Use(this, this, USE_ON, 0.0); + //ALERT(at_aiconsole, "pevDoor->nextthink = %d ms\n", (int)(1000*pevDoor->nextthink)); + //ALERT(at_aiconsole, "pevDoor->ltime = %d ms\n", (int)(1000*pevDoor->ltime)); + //ALERT(at_aiconsole, "pev-> nextthink = %d ms\n", (int)(1000*pev->nextthink)); + //ALERT(at_aiconsole, "pev->ltime = %d ms\n", (int)(1000*pev->ltime)); + flTravelTime = pevDoor->nextthink - pevDoor->ltime; + //ALERT(at_aiconsole, "Waiting %d ms\n", (int)(1000*flTravelTime)); + if ( pcbeDoor->pev->targetname ) + { + edict_t *pentTarget = NULL; + for (;;) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pcbeDoor->pev->targetname)); + + if ( VARS( pentTarget ) != pcbeDoor->pev ) + { + if (FNullEnt(pentTarget)) + break; + + if ( FClassnameIs ( pentTarget, STRING(pcbeDoor->pev->classname) ) ) + { + CBaseEntity *pDoor = Instance(pentTarget); + if ( pDoor ) + pDoor->Use(this, this, USE_ON, 0.0); + } + } + } + } + } + + return gpGlobals->time + flTravelTime; +} + + +//========================================================= +// AdvanceRoute - poorly named function that advances the +// m_iRouteIndex. If it goes beyond ROUTE_SIZE, the route +// is refreshed. +//========================================================= +void CBaseMonster :: AdvanceRoute ( float distance ) +{ + + if ( m_iRouteIndex == ROUTE_SIZE - 1 ) + { + // time to refresh the route. + if ( !FRefreshRoute() ) + { + ALERT ( at_aiconsole, "Can't Refresh Route!!\n" ); + } + } + else + { + if ( ! (m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL) ) + { + // If we've just passed a path_corner, advance m_pGoalEnt + if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_PATHCORNER ) + m_pGoalEnt = m_pGoalEnt->GetNextTarget(); + + // IF both waypoints are nodes, then check for a link for a door and operate it. + // + if ( (m_Route[m_iRouteIndex].iType & bits_MF_TO_NODE) == bits_MF_TO_NODE + && (m_Route[m_iRouteIndex+1].iType & bits_MF_TO_NODE) == bits_MF_TO_NODE) + { + //ALERT(at_aiconsole, "SVD: Two nodes. "); + + int iSrcNode = WorldGraph.FindNearestNode(m_Route[m_iRouteIndex].vecLocation, this ); + int iDestNode = WorldGraph.FindNearestNode(m_Route[m_iRouteIndex+1].vecLocation, this ); + + int iLink; + WorldGraph.HashSearch(iSrcNode, iDestNode, iLink); + + if ( iLink >= 0 && WorldGraph.m_pLinkPool[iLink].m_pLinkEnt != NULL ) + { + //ALERT(at_aiconsole, "A link. "); + if ( WorldGraph.HandleLinkEnt ( iSrcNode, WorldGraph.m_pLinkPool[iLink].m_pLinkEnt, m_afCapability, CGraph::NODEGRAPH_DYNAMIC ) ) + { + //ALERT(at_aiconsole, "usable."); + entvars_t *pevDoor = WorldGraph.m_pLinkPool[iLink].m_pLinkEnt; + if (pevDoor) + { + m_flMoveWaitFinished = OpenDoorAndWait( pevDoor ); +// ALERT( at_aiconsole, "Wating for door %.2f\n", m_flMoveWaitFinished-gpGlobals->time ); + } + } + } + //ALERT(at_aiconsole, "\n"); + } + m_iRouteIndex++; + } + else // At goal!!! + { + if ( distance < m_flGroundSpeed * 0.2 /* FIX */ ) + { + MovementComplete(); + } + } + } +} + + +int CBaseMonster :: RouteClassify( int iMoveFlag ) +{ + int movementGoal; + + movementGoal = MOVEGOAL_NONE; + + if ( iMoveFlag & bits_MF_TO_TARGETENT ) + movementGoal = MOVEGOAL_TARGETENT; + else if ( iMoveFlag & bits_MF_TO_ENEMY ) + movementGoal = MOVEGOAL_ENEMY; + else if ( iMoveFlag & bits_MF_TO_PATHCORNER ) + movementGoal = MOVEGOAL_PATHCORNER; + else if ( iMoveFlag & bits_MF_TO_NODE ) + movementGoal = MOVEGOAL_NODE; + else if ( iMoveFlag & bits_MF_TO_LOCATION ) + movementGoal = MOVEGOAL_LOCATION; + + return movementGoal; +} + +//========================================================= +// BuildRoute +//========================================================= +BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) +{ + float flDist; + Vector vecApex; + int iLocalMove; + + RouteNew(); + m_movementGoal = RouteClassify( iMoveFlag ); + +// so we don't end up with no moveflags + m_Route[ 0 ].vecLocation = vecGoal; + m_Route[ 0 ].iType = iMoveFlag | bits_MF_IS_GOAL; + +// check simple local move + iLocalMove = CheckLocalMove( pev->origin, vecGoal, pTarget, &flDist ); + + if ( iLocalMove == LOCALMOVE_VALID ) + { + // monster can walk straight there! + return TRUE; + } +// try to triangulate around any obstacles. + else if ( iLocalMove != LOCALMOVE_INVALID_DONT_TRIANGULATE && FTriangulate( pev->origin, vecGoal, flDist, pTarget, &vecApex ) ) + { + // there is a slightly more complicated path that allows the monster to reach vecGoal + m_Route[ 0 ].vecLocation = vecApex; + m_Route[ 0 ].iType = (iMoveFlag | bits_MF_TO_DETOUR); + + m_Route[ 1 ].vecLocation = vecGoal; + m_Route[ 1 ].iType = iMoveFlag | bits_MF_IS_GOAL; + + /* + WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); + WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); + WRITE_COORD(MSG_BROADCAST, vecApex.x ); + WRITE_COORD(MSG_BROADCAST, vecApex.y ); + WRITE_COORD(MSG_BROADCAST, vecApex.z ); + WRITE_COORD(MSG_BROADCAST, vecApex.x ); + WRITE_COORD(MSG_BROADCAST, vecApex.y ); + WRITE_COORD(MSG_BROADCAST, vecApex.z + 128 ); + */ + + RouteSimplify( pTarget ); + return TRUE; + } + +// last ditch, try nodes + if ( FGetNodeRoute( vecGoal ) ) + { +// ALERT ( at_console, "Can get there on nodes\n" ); + m_vecMoveGoal = vecGoal; + RouteSimplify( pTarget ); + return TRUE; + } + + // b0rk + return FALSE; +} + + +//========================================================= +// InsertWaypoint - Rebuilds the existing route so that the +// supplied vector and moveflags are the first waypoint in +// the route, and fills the rest of the route with as much +// of the pre-existing route as possible +//========================================================= +void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) +{ + int i, type; + + + // we have to save some Index and Type information from the real + // path_corner or node waypoint that the monster was trying to reach. This makes sure that data necessary + // to refresh the original path exists even in the new waypoints that don't correspond directy to a path_corner + // or node. + type = afMoveFlags | (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK); + + for ( i = ROUTE_SIZE-1; i > 0; i-- ) + m_Route[i] = m_Route[i-1]; + + m_Route[ m_iRouteIndex ].vecLocation = vecLocation; + m_Route[ m_iRouteIndex ].iType = type; +} + +//========================================================= +// FTriangulate - tries to overcome local obstacles by +// triangulating a path around them. +// +// iApexDist is how far the obstruction that we are trying +// to triangulate around is from the monster. +//========================================================= +BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) +{ + Vector vecDir; + Vector vecForward; + Vector vecLeft;// the spot we'll try to triangulate to on the left + Vector vecRight;// the spot we'll try to triangulate to on the right + Vector vecTop;// the spot we'll try to triangulate to on the top + Vector vecBottom;// the spot we'll try to triangulate to on the bottom + Vector vecFarSide;// the spot that we'll move to after hitting the triangulated point, before moving on to our normal goal. + int i; + float sizeX, sizeZ; + + // If the hull width is less than 24, use 24 because CheckLocalMove uses a min of + // 24. + sizeX = pev->size.x; + if (sizeX < 24.0) + sizeX = 24.0; + else if (sizeX > 48.0) + sizeX = 48.0; + sizeZ = pev->size.z; + //if (sizeZ < 24.0) + // sizeZ = 24.0; + + vecForward = ( vecEnd - vecStart ).Normalize(); + + Vector vecDirUp(0,0,1); + vecDir = CrossProduct ( vecForward, vecDirUp); + + // start checking right about where the object is, picking two equidistant starting points, one on + // the left, one on the right. As we progress through the loop, we'll push these away from the obstacle, + // hoping to find a way around on either side. pev->size.x is added to the ApexDist in order to help select + // an apex point that insures that the monster is sufficiently past the obstacle before trying to turn back + // onto its original course. + + vecLeft = pev->origin + ( vecForward * ( flDist + sizeX ) ) - vecDir * ( sizeX * 3 ); + vecRight = pev->origin + ( vecForward * ( flDist + sizeX ) ) + vecDir * ( sizeX * 3 ); + if (pev->movetype == MOVETYPE_FLY) + { + vecTop = pev->origin + (vecForward * flDist) + (vecDirUp * sizeZ * 3); + vecBottom = pev->origin + (vecForward * flDist) - (vecDirUp * sizeZ * 3); + } + + vecFarSide = m_Route[ m_iRouteIndex ].vecLocation; + + vecDir = vecDir * sizeX * 2; + if (pev->movetype == MOVETYPE_FLY) + vecDirUp = vecDirUp * sizeZ * 2; + + for ( i = 0 ; i < 8; i++ ) + { +// Debug, Draw the triangulation +#if 0 + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( vecRight.x ); + WRITE_COORD( vecRight.y ); + WRITE_COORD( vecRight.z ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( vecLeft.x ); + WRITE_COORD( vecLeft.y ); + WRITE_COORD( vecLeft.z ); + MESSAGE_END(); +#endif + +#if 0 + if (pev->movetype == MOVETYPE_FLY) + { + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( vecTop.x ); + WRITE_COORD( vecTop.y ); + WRITE_COORD( vecTop.z ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( vecBottom.x ); + WRITE_COORD( vecBottom.y ); + WRITE_COORD( vecBottom.z ); + MESSAGE_END(); + } +#endif + + if ( CheckLocalMove( pev->origin, vecRight, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( CheckLocalMove ( vecRight, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( pApex ) + { + *pApex = vecRight; + } + + return TRUE; + } + } + if ( CheckLocalMove( pev->origin, vecLeft, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( CheckLocalMove ( vecLeft, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( pApex ) + { + *pApex = vecLeft; + } + + return TRUE; + } + } + + if (pev->movetype == MOVETYPE_FLY) + { + if ( CheckLocalMove( pev->origin, vecTop, pTargetEnt, NULL ) == LOCALMOVE_VALID) + { + if ( CheckLocalMove ( vecTop, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( pApex ) + { + *pApex = vecTop; + //ALERT(at_aiconsole, "triangulate over\n"); + } + + return TRUE; + } + } +#if 1 + if ( CheckLocalMove( pev->origin, vecBottom, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( CheckLocalMove ( vecBottom, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + { + if ( pApex ) + { + *pApex = vecBottom; + //ALERT(at_aiconsole, "triangulate under\n"); + } + + return TRUE; + } + } +#endif + } + + vecRight = vecRight + vecDir; + vecLeft = vecLeft - vecDir; + if (pev->movetype == MOVETYPE_FLY) + { + vecTop = vecTop + vecDirUp; + vecBottom = vecBottom - vecDirUp; + } + } + + return FALSE; +} + +//========================================================= +// Move - take a single step towards the next ROUTE location +//========================================================= +#define DIST_TO_CHECK 200 + +void CBaseMonster :: Move ( float flInterval ) +{ + float flWaypointDist; + float flCheckDist; + float flDist;// how far the lookahead check got before hitting an object. + Vector vecDir; + Vector vecApex; + CBaseEntity *pTargetEnt; + + // Don't move if no valid route + if ( FRouteClear() ) + { + // If we still have a movement goal, then this is probably a route truncated by SimplifyRoute() + // so refresh it. + if ( m_movementGoal == MOVEGOAL_NONE || !FRefreshRoute() ) + { + ALERT( at_aiconsole, "Tried to move with no route!\n" ); + TaskFail(); + return; + } + } + + if ( m_flMoveWaitFinished > gpGlobals->time ) + return; + +// Debug, test movement code +#if 0 +// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) + { + if ( m_movementGoal == MOVEGOAL_ENEMY ) + RouteSimplify( m_hEnemy ); + else + RouteSimplify( m_hTargetEnt ); + FRefreshRoute(); + return; + } +#else +// Debug, draw the route +// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 200, 0 ); +#endif + + // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer + // to that entity for the CheckLocalMove and Triangulate functions. + pTargetEnt = NULL; + + // local move to waypoint. + vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); + flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); + + MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); + ChangeYaw ( pev->yaw_speed ); + + // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint + if ( flWaypointDist < DIST_TO_CHECK ) + { + flCheckDist = flWaypointDist; + } + else + { + flCheckDist = DIST_TO_CHECK; + } + + if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) + { + // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) + pTargetEnt = m_hEnemy; + } + else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) + { + pTargetEnt = m_hTargetEnt; + } + + // !!!BUGBUG - CheckDist should be derived from ground speed. + // If this fails, it should be because of some dynamic entity blocking this guy. + // We've already checked this path, so we should wait and time out if the entity doesn't move + flDist = 0; + if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) + { + CBaseEntity *pBlocker; + + // Can't move, stop + Stop(); + // Blocking entity is in global trace_ent + pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); + if (pBlocker) + { + DispatchBlocked( edict(), pBlocker->edict() ); + } + + if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) + { + // Can we still move toward our target? + if ( flDist < m_flGroundSpeed ) + { + // No, Wait for a second + m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; + return; + } + // Ok, still enough room to take a step + } + else + { + // try to triangulate around whatever is in the way. + if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) + { + InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); + RouteSimplify( pTargetEnt ); + } + else + { +// ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); + Stop(); + // Only do this once until your route is cleared + if ( m_moveWaitTime > 0 && !(m_afMemory & bits_MEMORY_MOVE_FAILED) ) + { + FRefreshRoute(); + if ( FRouteClear() ) + { + TaskFail(); + } + else + { + // Don't get stuck + if ( (gpGlobals->time - m_flMoveWaitFinished) < 0.2 ) + Remember( bits_MEMORY_MOVE_FAILED ); + + m_flMoveWaitFinished = gpGlobals->time + 0.1; + } + } + else + { + TaskFail(); + ALERT( at_aiconsole, "%s Failed to move (%d)!\n", STRING(pev->classname), HasMemory( bits_MEMORY_MOVE_FAILED ) ); + //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); + } + return; + } + } + } + + // close enough to the target, now advance to the next target. This is done before actually reaching + // the target so that we get a nice natural turn while moving. + if ( ShouldAdvanceRoute( flWaypointDist ) )///!!!BUGBUG- magic number + { + AdvanceRoute( flWaypointDist ); + } + + // Might be waiting for a door + if ( m_flMoveWaitFinished > gpGlobals->time ) + { + Stop(); + return; + } + + // UNDONE: this is a hack to quit moving farther than it has looked ahead. + if (flCheckDist < m_flGroundSpeed * flInterval) + { + flInterval = flCheckDist / m_flGroundSpeed; + // ALERT( at_console, "%.02f\n", flInterval ); + } + MoveExecute( pTargetEnt, vecDir, flInterval ); + + if ( MovementIsComplete() ) + { + Stop(); + RouteClear(); + } +} + + +BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) +{ + if ( flWaypointDist <= MONSTER_CUT_CORNER_DIST ) + { + // ALERT( at_console, "cut %f\n", flWaypointDist ); + return TRUE; + } + + return FALSE; +} + + +void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) +{ +// float flYaw = UTIL_VecToYaw ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin );// build a yaw that points to the goal. +// WALK_MOVE( ENT(pev), flYaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); + if ( m_IdealActivity != m_movementActivity ) + m_IdealActivity = m_movementActivity; + + float flTotal = m_flGroundSpeed * pev->framerate * flInterval; + float flStep; + while (flTotal > 0.001) + { + // don't walk more than 16 units or stairs stop working + flStep = min( 16.0, flTotal ); + UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flStep, MOVE_NORMAL ); + flTotal -= flStep; + } + // ALERT( at_console, "dist %f\n", m_flGroundSpeed * pev->framerate * flInterval ); +} + + +//========================================================= +// MonsterInit - after a monster is spawned, it needs to +// be dropped into the world, checked for mobility problems, +// and put on the proper path, if any. This function does +// all of those things after the monster spawns. Any +// initialization that should take place for all monsters +// goes here. +//========================================================= +void CBaseMonster :: MonsterInit ( void ) +{ + if (!g_pGameRules->FAllowMonsters()) + { + pev->flags |= FL_KILLME; // Post this because some monster code modifies class data after calling this function +// REMOVE_ENTITY(ENT(pev)); + return; + } + + // Set fields common to all monsters + pev->effects = 0; + pev->takedamage = DAMAGE_AIM; + pev->ideal_yaw = pev->angles.y; + pev->max_health = pev->health; + pev->deadflag = DEAD_NO; + m_IdealMonsterState = MONSTERSTATE_IDLE;// Assume monster will be idle, until proven otherwise + + m_IdealActivity = ACT_IDLE; + + SetBits (pev->flags, FL_MONSTER); + if ( pev->spawnflags & SF_MONSTER_HITMONSTERCLIP ) + pev->flags |= FL_MONSTERCLIP; + + ClearSchedule(); + RouteClear(); + InitBoneControllers( ); // FIX: should be done in Spawn + + m_iHintNode = NO_NODE; + + m_afMemory = MEMORY_CLEAR; + + m_hEnemy = NULL; + + m_flDistTooFar = 1024.0; + m_flDistLook = 2048.0; + + // set eye position + SetEyePosition(); + + SetThink( &CBaseMonster::MonsterInitThink ); + pev->nextthink = gpGlobals->time + 0.1; + SetUse ( &CBaseMonster::MonsterUse ); +} + +//========================================================= +// MonsterInitThink - Calls StartMonster. Startmonster is +// virtual, but this function cannot be +//========================================================= +void CBaseMonster :: MonsterInitThink ( void ) +{ + StartMonster(); +} + +//========================================================= +// StartMonster - final bit of initization before a monster +// is turned over to the AI. +//========================================================= +void CBaseMonster :: StartMonster ( void ) +{ + // update capabilities + if ( LookupActivity ( ACT_RANGE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) + { + m_afCapability |= bits_CAP_RANGE_ATTACK1; + } + if ( LookupActivity ( ACT_RANGE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) + { + m_afCapability |= bits_CAP_RANGE_ATTACK2; + } + if ( LookupActivity ( ACT_MELEE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) + { + m_afCapability |= bits_CAP_MELEE_ATTACK1; + } + if ( LookupActivity ( ACT_MELEE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) + { + m_afCapability |= bits_CAP_MELEE_ATTACK2; + } + + // Raise monster off the floor one unit, then drop to floor + if ( pev->movetype != MOVETYPE_FLY && !FBitSet( pev->spawnflags, SF_MONSTER_FALL_TO_GROUND ) ) + { + pev->origin.z += 1; + DROP_TO_FLOOR ( ENT(pev) ); + // Try to move the monster to make sure it's not stuck in a brush. + if (!WALK_MOVE ( ENT(pev), 0, 0, WALKMOVE_NORMAL ) ) + { + ALERT(at_error, "Monster %s stuck in wall--level design error", STRING(pev->classname)); + pev->effects = EF_BRIGHTFIELD; + } + } + else + { + pev->flags &= ~FL_ONGROUND; + } + + if ( !FStringNull(pev->target) )// this monster has a target + { + // Find the monster's initial target entity, stash it + m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( pev->target ) ) ); + + if ( !m_pGoalEnt ) + { + ALERT(at_error, "ReadyMonster()--%s couldn't find target %s", STRING(pev->classname), STRING(pev->target)); + } + else + { + // Monster will start turning towards his destination + MakeIdealYaw ( m_pGoalEnt->pev->origin ); + + // JAY: How important is this error message? Big Momma doesn't obey this rule, so I took it out. +#if 0 + // At this point, we expect only a path_corner as initial goal + if (!FClassnameIs( m_pGoalEnt->pev, "path_corner")) + { + ALERT(at_warning, "ReadyMonster--monster's initial goal '%s' is not a path_corner", STRING(pev->target)); + } +#endif + + // set the monster up to walk a path corner path. + // !!!BUGBUG - this is a minor bit of a hack. + // JAYJAY + m_movementGoal = MOVEGOAL_PATHCORNER; + + if ( pev->movetype == MOVETYPE_FLY ) + m_movementActivity = ACT_FLY; + else + m_movementActivity = ACT_WALK; + + if ( !FRefreshRoute() ) + { + ALERT ( at_aiconsole, "Can't Create Route!\n" ); + } + SetState( MONSTERSTATE_IDLE ); + ChangeSchedule( GetScheduleOfType( SCHED_IDLE_WALK ) ); + } + } + + //SetState ( m_IdealMonsterState ); + //SetActivity ( m_IdealActivity ); + + // Delay drop to floor to make sure each door in the level has had its chance to spawn + // Spread think times so that they don't all happen at the same time (Carmack) + SetThink ( &CBaseMonster::CallMonsterThink ); + pev->nextthink += RANDOM_FLOAT(0.1, 0.4); // spread think times. + + if ( !FStringNull(pev->targetname) )// wait until triggered + { + SetState( MONSTERSTATE_IDLE ); + // UNDONE: Some scripted sequence monsters don't have an idle? + SetActivity( ACT_IDLE ); + ChangeSchedule( GetScheduleOfType( SCHED_WAIT_TRIGGER ) ); + } +} + + +void CBaseMonster :: MovementComplete( void ) +{ + switch( m_iTaskStatus ) + { + case TASKSTATUS_NEW: + case TASKSTATUS_RUNNING: + m_iTaskStatus = TASKSTATUS_RUNNING_TASK; + break; + + case TASKSTATUS_RUNNING_MOVEMENT: + TaskComplete(); + break; + + case TASKSTATUS_RUNNING_TASK: + ALERT( at_error, "Movement completed twice!\n" ); + break; + + case TASKSTATUS_COMPLETE: + break; + } + m_movementGoal = MOVEGOAL_NONE; +} + + +int CBaseMonster::TaskIsRunning( void ) +{ + if ( m_iTaskStatus != TASKSTATUS_COMPLETE && + m_iTaskStatus != TASKSTATUS_RUNNING_MOVEMENT ) + return 1; + + return 0; +} + +//========================================================= +// IRelationship - returns an integer that describes the +// relationship between two types of monster. +//========================================================= +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) +{ + static int iEnemy[14][14] = + { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN + /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, + /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, + /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, + /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, + /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, + /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, + /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, + /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, + /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, + /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, + /*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO } + }; + + return iEnemy[ Classify() ][ pTarget->Classify() ]; +} + +//========================================================= +// FindCover - tries to find a nearby node that will hide +// the caller from its enemy. +// +// If supplied, search will return a node at least as far +// away as MinDist, but no farther than MaxDist. +// if MaxDist isn't supplied, it defaults to a reasonable +// value +//========================================================= +// UNDONE: Should this find the nearest node? + +//float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) + +BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) +{ + int i; + int iMyHullIndex; + int iMyNode; + int iThreatNode; + float flDist; + Vector vecLookersOffset; + TraceResult tr; + + if ( !flMaxDist ) + { + // user didn't supply a MaxDist, so work up a crazy one. + flMaxDist = 784; + } + + if ( flMinDist > 0.5 * flMaxDist) + { +#if _DEBUG + ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); +#endif + flMinDist = 0.5 * flMaxDist; + } + + if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) + { + ALERT ( at_aiconsole, "Graph not ready for findcover!\n" ); + return FALSE; + } + + iMyNode = WorldGraph.FindNearestNode( pev->origin, this ); + iThreatNode = WorldGraph.FindNearestNode ( vecThreat, this ); + iMyHullIndex = WorldGraph.HullIndex( this ); + + if ( iMyNode == NO_NODE ) + { + ALERT ( at_aiconsole, "FindCover() - %s has no nearest node!\n", STRING(pev->classname)); + return FALSE; + } + if ( iThreatNode == NO_NODE ) + { + // ALERT ( at_aiconsole, "FindCover() - Threat has no nearest node!\n" ); + iThreatNode = iMyNode; + // return FALSE; + } + + vecLookersOffset = vecThreat + vecViewOffset;// calculate location of enemy's eyes + + // we'll do a rough sample to find nodes that are relatively nearby + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + { + int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; + + CNode &node = WorldGraph.Node( nodeNumber ); + WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. + + // could use an optimization here!! + flDist = ( pev->origin - node.m_vecOrigin ).Length(); + + // DON'T do the trace check on a node that is farther away than a node that we've already found to + // provide cover! Also make sure the node is within the mins/maxs of the search. + if ( flDist >= flMinDist && flDist < flMaxDist ) + { + UTIL_TraceLine ( node.m_vecOrigin + vecViewOffset, vecLookersOffset, ignore_monsters, ignore_glass, ENT(pev), &tr ); + + // if this node will block the threat's line of sight to me... + if ( tr.flFraction != 1.0 ) + { + // ..and is also closer to me than the threat, or the same distance from myself and the threat the node is good. + if ( ( iMyNode == iThreatNode ) || WorldGraph.PathLength( iMyNode, nodeNumber, iMyHullIndex, m_afCapability ) <= WorldGraph.PathLength( iThreatNode, nodeNumber, iMyHullIndex, m_afCapability ) ) + { + if ( FValidateCover ( node.m_vecOrigin ) && MoveToLocation( ACT_RUN, 0, node.m_vecOrigin ) ) + { + /* + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + + WRITE_COORD( node.m_vecOrigin.x ); + WRITE_COORD( node.m_vecOrigin.y ); + WRITE_COORD( node.m_vecOrigin.z ); + + WRITE_COORD( vecLookersOffset.x ); + WRITE_COORD( vecLookersOffset.y ); + WRITE_COORD( vecLookersOffset.z ); + MESSAGE_END(); + */ + + return TRUE; + } + } + } + } + } + return FALSE; +} + + +//========================================================= +// BuildNearestRoute - tries to build a route as close to the target +// as possible, even if there isn't a path to the final point. +// +// If supplied, search will return a node at least as far +// away as MinDist from vecThreat, but no farther than MaxDist. +// if MaxDist isn't supplied, it defaults to a reasonable +// value +//========================================================= +BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) +{ + int i; + int iMyHullIndex; + int iMyNode; + float flDist; + Vector vecLookersOffset; + TraceResult tr; + + if ( !flMaxDist ) + { + // user didn't supply a MaxDist, so work up a crazy one. + flMaxDist = 784; + } + + if ( flMinDist > 0.5 * flMaxDist) + { +#if _DEBUG + ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); +#endif + flMinDist = 0.5 * flMaxDist; + } + + if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) + { + ALERT ( at_aiconsole, "Graph not ready for BuildNearestRoute!\n" ); + return FALSE; + } + + iMyNode = WorldGraph.FindNearestNode( pev->origin, this ); + iMyHullIndex = WorldGraph.HullIndex( this ); + + if ( iMyNode == NO_NODE ) + { + ALERT ( at_aiconsole, "BuildNearestRoute() - %s has no nearest node!\n", STRING(pev->classname)); + return FALSE; + } + + vecLookersOffset = vecThreat + vecViewOffset;// calculate location of enemy's eyes + + // we'll do a rough sample to find nodes that are relatively nearby + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + { + int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; + + CNode &node = WorldGraph.Node( nodeNumber ); + WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. + + // can I get there? + if (WorldGraph.NextNodeInRoute( iMyNode, nodeNumber, iMyHullIndex, 0 ) != iMyNode) + { + flDist = ( vecThreat - node.m_vecOrigin ).Length(); + + // is it close? + if ( flDist > flMinDist && flDist < flMaxDist) + { + // can I see where I want to be from there? + UTIL_TraceLine( node.m_vecOrigin + pev->view_ofs, vecLookersOffset, ignore_monsters, edict(), &tr ); + + if (tr.flFraction == 1.0) + { + // try to actually get there + if ( BuildRoute ( node.m_vecOrigin, bits_MF_TO_LOCATION, NULL ) ) + { + flMaxDist = flDist; + m_vecMoveGoal = node.m_vecOrigin; + return TRUE; // UNDONE: keep looking for something closer! + } + } + } + } + } + + return FALSE; +} + + + +//========================================================= +// BestVisibleEnemy - this functions searches the link +// list whose head is the caller's m_pLink field, and returns +// a pointer to the enemy entity in that list that is nearest the +// caller. +// +// !!!UNDONE - currently, this only returns the closest enemy. +// we'll want to consider distance, relationship, attack types, back turned, etc. +//========================================================= +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) +{ + CBaseEntity *pReturn; + CBaseEntity *pNextEnt; + int iNearest; + int iDist; + int iBestRelationship; + + iNearest = 8192;// so first visible entity will become the closest. + pNextEnt = m_pLink; + pReturn = NULL; + iBestRelationship = R_NO; + + while ( pNextEnt != NULL ) + { + if ( pNextEnt->IsAlive() ) + { + if ( IRelationship( pNextEnt) > iBestRelationship ) + { + // this entity is disliked MORE than the entity that we + // currently think is the best visible enemy. No need to do + // a distance check, just get mad at this one for now. + iBestRelationship = IRelationship ( pNextEnt ); + iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); + pReturn = pNextEnt; + } + else if ( IRelationship( pNextEnt) == iBestRelationship ) + { + // this entity is disliked just as much as the entity that + // we currently think is the best visible enemy, so we only + // get mad at it if it is closer. + iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); + + if ( iDist <= iNearest ) + { + iNearest = iDist; + iBestRelationship = IRelationship ( pNextEnt ); + pReturn = pNextEnt; + } + } + } + + pNextEnt = pNextEnt->m_pLink; + } + + return pReturn; +} + + +//========================================================= +// MakeIdealYaw - gets a yaw value for the caller that would +// face the supplied vector. Value is stuffed into the monster's +// ideal_yaw +//========================================================= +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) +{ + Vector vecProjection; + + // strafing monster needs to face 90 degrees away from its goal + if ( m_movementActivity == ACT_STRAFE_LEFT ) + { + vecProjection.x = -vecTarget.y; + vecProjection.y = vecTarget.x; + + pev->ideal_yaw = UTIL_VecToYaw( vecProjection - pev->origin ); + } + else if ( m_movementActivity == ACT_STRAFE_RIGHT ) + { + vecProjection.x = vecTarget.y; + vecProjection.y = vecTarget.x; + + pev->ideal_yaw = UTIL_VecToYaw( vecProjection - pev->origin ); + } + else + { + pev->ideal_yaw = UTIL_VecToYaw ( vecTarget - pev->origin ); + } +} + +//========================================================= +// FlYawDiff - returns the difference ( in degrees ) between +// monster's current yaw and ideal_yaw +// +// Positive result is left turn, negative is right turn +//========================================================= +float CBaseMonster::FlYawDiff ( void ) +{ + float flCurrentYaw; + + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); + + if ( flCurrentYaw == pev->ideal_yaw ) + { + return 0; + } + + + return UTIL_AngleDiff( pev->ideal_yaw, flCurrentYaw ); +} + + +//========================================================= +// Changeyaw - turns a monster towards its ideal_yaw +//========================================================= +float CBaseMonster::ChangeYaw ( int yawSpeed ) +{ + float ideal, current, move, speed; + + current = UTIL_AngleMod( pev->angles.y ); + ideal = pev->ideal_yaw; + if (current != ideal) + { + speed = (float)yawSpeed * gpGlobals->frametime * 10; + move = ideal - current; + + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + + if (move > 0) + {// turning to the monster's left + if (move > speed) + move = speed; + } + else + {// turning to the monster's right + if (move < -speed) + move = -speed; + } + + pev->angles.y = UTIL_AngleMod (current + move); + + // turn head in desired direction only if they have a turnable head + if (m_afCapability & bits_CAP_TURN_HEAD) + { + float yaw = pev->ideal_yaw - pev->angles.y; + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + // yaw *= 0.8; + SetBoneController( 0, yaw ); + } + } + else + move = 0; + + return move; +} + +//========================================================= +// VecToYaw - turns a directional vector into a yaw value +// that points down that vector. +//========================================================= +float CBaseMonster::VecToYaw ( Vector vecDir ) +{ + if (vecDir.x == 0 && vecDir.y == 0 && vecDir.z == 0) + return pev->angles.y; + + return UTIL_VecToYaw( vecDir ); +} + + +//========================================================= +// SetEyePosition +// +// queries the monster's model for $eyeposition and copies +// that vector to the monster's view_ofs +// +//========================================================= +void CBaseMonster :: SetEyePosition ( void ) +{ + Vector vecEyePosition; + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + GetEyePosition( pmodel, vecEyePosition ); + + pev->view_ofs = vecEyePosition; + + if ( pev->view_ofs == g_vecZero ) + { + ALERT ( at_aiconsole, "%s has no view_ofs!\n", STRING ( pev->classname ) ); + } +} + +void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case SCRIPT_EVENT_DEAD: + if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + { + pev->deadflag = DEAD_DYING; + // Kill me now! (and fade out when CineCleanup() is called) +#if _DEBUG + ALERT( at_aiconsole, "Death event: %s\n", STRING(pev->classname) ); +#endif + pev->health = 0; + } +#if _DEBUG + else + ALERT( at_aiconsole, "INVALID death event:%s\n", STRING(pev->classname) ); +#endif + break; + case SCRIPT_EVENT_NOT_DEAD: + if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + { + pev->deadflag = DEAD_NO; + // This is for life/death sequences where the player can determine whether a character is dead or alive after the script + pev->health = pev->max_health; + } + break; + + case SCRIPT_EVENT_SOUND: // Play a named wave file + EMIT_SOUND( edict(), CHAN_BODY, pEvent->options, 1.0, ATTN_IDLE ); + break; + + case SCRIPT_EVENT_SOUND_VOICE: + EMIT_SOUND( edict(), CHAN_VOICE, pEvent->options, 1.0, ATTN_IDLE ); + break; + + case SCRIPT_EVENT_SENTENCE_RND1: // Play a named sentence group 33% of the time + if (RANDOM_LONG(0,2) == 0) + break; + // fall through... + case SCRIPT_EVENT_SENTENCE: // Play a named sentence group + SENTENCEG_PlayRndSz( edict(), pEvent->options, 1.0, ATTN_IDLE, 0, 100 ); + break; + + case SCRIPT_EVENT_FIREEVENT: // Fire a trigger + FireTargets( pEvent->options, this, this, USE_TOGGLE, 0 ); + break; + + case SCRIPT_EVENT_NOINTERRUPT: // Can't be interrupted from now on + if ( m_pCine ) + m_pCine->AllowInterrupt( FALSE ); + break; + + case SCRIPT_EVENT_CANINTERRUPT: // OK to interrupt now + if ( m_pCine ) + m_pCine->AllowInterrupt( TRUE ); + break; + +#if 0 + case SCRIPT_EVENT_INAIR: // Don't DROP_TO_FLOOR() + case SCRIPT_EVENT_ENDANIMATION: // Set ending animation sequence to + break; +#endif + + case MONSTER_EVENT_BODYDROP_HEAVY: + if ( pev->flags & FL_ONGROUND ) + { + if ( RANDOM_LONG( 0, 1 ) == 0 ) + { + EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM, 0, 90 ); + } + else + { + EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop4.wav", 1, ATTN_NORM, 0, 90 ); + } + } + break; + + case MONSTER_EVENT_BODYDROP_LIGHT: + if ( pev->flags & FL_ONGROUND ) + { + if ( RANDOM_LONG( 0, 1 ) == 0 ) + { + EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM ); + } + else + { + EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop4.wav", 1, ATTN_NORM ); + } + } + break; + + case MONSTER_EVENT_SWISHSOUND: + { + // NO MONSTER may use this anim event unless that monster's precache precaches this sound!!! + EMIT_SOUND( ENT(pev), CHAN_BODY, "zombie/claw_miss2.wav", 1, ATTN_NORM ); + break; + } + + default: + ALERT( at_aiconsole, "Unhandled animation event %d for %s\n", pEvent->event, STRING(pev->classname) ); + break; + + } +} + + +// Combat + +Vector CBaseMonster :: GetGunPosition( ) +{ + UTIL_MakeVectors(pev->angles); + + // Vector vecSrc = pev->origin + gpGlobals->v_forward * 10; + //vecSrc.z = pevShooter->absmin.z + pevShooter->size.z * 0.7; + //vecSrc.z = pev->origin.z + (pev->view_ofs.z - 4); + Vector vecSrc = pev->origin + + gpGlobals->v_forward * m_HackedGunPos.y + + gpGlobals->v_right * m_HackedGunPos.x + + gpGlobals->v_up * m_HackedGunPos.z; + + return vecSrc; +} + + + + + +//========================================================= +// NODE GRAPH +//========================================================= + + + + + +//========================================================= +// FGetNodeRoute - tries to build an entire node path from +// the callers origin to the passed vector. If this is +// possible, ROUTE_SIZE waypoints will be copied into the +// callers m_Route. TRUE is returned if the operation +// succeeds (path is valid) or FALSE if failed (no path +// exists ) +//========================================================= +BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) +{ + int iPath[ MAX_PATH_SIZE ]; + int iSrcNode, iDestNode; + int iResult; + int i; + int iNumToCopy; + + iSrcNode = WorldGraph.FindNearestNode ( pev->origin, this ); + iDestNode = WorldGraph.FindNearestNode ( vecDest, this ); + + if ( iSrcNode == -1 ) + { + // no node nearest self +// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near self!\n" ); + return FALSE; + } + else if ( iDestNode == -1 ) + { + // no node nearest target +// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near target!\n" ); + return FALSE; + } + + // valid src and dest nodes were found, so it's safe to proceed with + // find shortest path + int iNodeHull = WorldGraph.HullIndex( this ); // make this a monster virtual function + iResult = WorldGraph.FindShortestPath ( iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability ); + + if ( !iResult ) + { +#if 1 + ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); + return FALSE; +#else + BOOL bRoutingSave = WorldGraph.m_fRoutingComplete; + WorldGraph.m_fRoutingComplete = FALSE; + iResult = WorldGraph.FindShortestPath(iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability); + WorldGraph.m_fRoutingComplete = bRoutingSave; + if ( !iResult ) + { + ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); + return FALSE; + } + else + { + ALERT ( at_aiconsole, "Routing is inconsistent!" ); + } +#endif + } + + // there's a valid path within iPath now, so now we will fill the route array + // up with as many of the waypoints as it will hold. + + // don't copy ROUTE_SIZE entries if the path returned is shorter + // than ROUTE_SIZE!!! + if ( iResult < ROUTE_SIZE ) + { + iNumToCopy = iResult; + } + else + { + iNumToCopy = ROUTE_SIZE; + } + + for ( i = 0 ; i < iNumToCopy; i++ ) + { + m_Route[ i ].vecLocation = WorldGraph.m_pNodes[ iPath[ i ] ].m_vecOrigin; + m_Route[ i ].iType = bits_MF_TO_NODE; + } + + if ( iNumToCopy < ROUTE_SIZE ) + { + m_Route[ iNumToCopy ].vecLocation = vecDest; + m_Route[ iNumToCopy ].iType |= bits_MF_IS_GOAL; + } + + return TRUE; +} + +//========================================================= +// FindHintNode +//========================================================= +int CBaseMonster :: FindHintNode ( void ) +{ + int i; + TraceResult tr; + + if ( !WorldGraph.m_fGraphPresent ) + { + ALERT ( at_aiconsole, "find_hintnode: graph not ready!\n" ); + return NO_NODE; + } + + if ( WorldGraph.m_iLastActiveIdleSearch >= WorldGraph.m_cNodes ) + { + WorldGraph.m_iLastActiveIdleSearch = 0; + } + + for ( i = 0; i < WorldGraph.m_cNodes ; i++ ) + { + int nodeNumber = (i + WorldGraph.m_iLastActiveIdleSearch) % WorldGraph.m_cNodes; + CNode &node = WorldGraph.Node( nodeNumber ); + + if ( node.m_sHintType ) + { + // this node has a hint. Take it if it is visible, the monster likes it, and the monster has an animation to match the hint's activity. + if ( FValidateHintType ( node.m_sHintType ) ) + { + if ( !node.m_sHintActivity || LookupActivity ( node.m_sHintActivity ) != ACTIVITY_NOT_AVAILABLE ) + { + UTIL_TraceLine ( pev->origin + pev->view_ofs, node.m_vecOrigin + pev->view_ofs, ignore_monsters, ENT(pev), &tr ); + + if ( tr.flFraction == 1.0 ) + { + WorldGraph.m_iLastActiveIdleSearch = nodeNumber + 1; // next monster that searches for hint nodes will start where we left off. + return nodeNumber;// take it! + } + } + } + } + } + + WorldGraph.m_iLastActiveIdleSearch = 0;// start at the top of the list for the next search. + + return NO_NODE; +} + + +void CBaseMonster::ReportAIState( void ) +{ + ALERT_TYPE level = at_console; + + static const char *pStateNames[] = { "None", "Idle", "Combat", "Alert", "Hunt", "Prone", "Scripted", "Dead" }; + + ALERT( level, "%s: ", STRING(pev->classname) ); + if ( (int)m_MonsterState < ARRAYSIZE(pStateNames) ) + ALERT( level, "State: %s, ", pStateNames[m_MonsterState] ); + int i = 0; + while ( activity_map[i].type != 0 ) + { + if ( activity_map[i].type == (int)m_Activity ) + { + ALERT( level, "Activity %s, ", activity_map[i].name ); + break; + } + i++; + } + + if ( m_pSchedule ) + { + const char *pName = NULL; + pName = m_pSchedule->pName; + if ( !pName ) + pName = "Unknown"; + ALERT( level, "Schedule %s, ", pName ); + Task_t *pTask = GetTask(); + if ( pTask ) + ALERT( level, "Task %d (#%d), ", pTask->iTask, m_iScheduleIndex ); + } + else + ALERT( level, "No Schedule, " ); + + if ( m_hEnemy != NULL ) + ALERT( level, "\nEnemy is %s", STRING(m_hEnemy->pev->classname) ); + else + ALERT( level, "No enemy" ); + + if ( IsMoving() ) + { + ALERT( level, " Moving " ); + if ( m_flMoveWaitFinished > gpGlobals->time ) + ALERT( level, ": Stopped for %.2f. ", m_flMoveWaitFinished - gpGlobals->time ); + else if ( m_IdealActivity == GetStoppedActivity() ) + ALERT( level, ": In stopped anim. " ); + } + + CSquadMonster *pSquadMonster = MySquadMonsterPointer(); + + if ( pSquadMonster ) + { + if ( !pSquadMonster->InSquad() ) + { + ALERT ( level, "not " ); + } + + ALERT ( level, "In Squad, " ); + + if ( !pSquadMonster->IsLeader() ) + { + ALERT ( level, "not " ); + } + + ALERT ( level, "Leader." ); + } + + ALERT( level, "\n" ); + ALERT( level, "Yaw speed:%3.1f,Health: %3.1f\n", pev->yaw_speed, pev->health ); + if ( pev->spawnflags & SF_MONSTER_PRISONER ) + ALERT( level, " PRISONER! " ); + if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) + ALERT( level, " Pre-Disaster! " ); + ALERT( level, "\n" ); +} + +//========================================================= +// KeyValue +// +// !!! netname entvar field is used in squadmonster for groupname!!! +//========================================================= +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "TriggerTarget")) + { + m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "TriggerCondition") ) + { + m_iTriggerCondition = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + { + CBaseToggle::KeyValue( pkvd ); + } +} + +//========================================================= +// FCheckAITrigger - checks the monster's AI Trigger Conditions, +// if there is a condition, then checks to see if condition is +// met. If yes, the monster's TriggerTarget is fired. +// +// Returns TRUE if the target is fired. +//========================================================= +BOOL CBaseMonster :: FCheckAITrigger ( void ) +{ + BOOL fFireTarget; + + if ( m_iTriggerCondition == AITRIGGER_NONE ) + { + // no conditions, so this trigger is never fired. + return FALSE; + } + + fFireTarget = FALSE; + + switch ( m_iTriggerCondition ) + { + case AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER: + if ( m_hEnemy != NULL && m_hEnemy->IsPlayer() && HasConditions ( bits_COND_SEE_ENEMY ) ) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_SEEPLAYER_UNCONDITIONAL: + if ( HasConditions ( bits_COND_SEE_CLIENT ) ) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_SEEPLAYER_NOT_IN_COMBAT: + if ( HasConditions ( bits_COND_SEE_CLIENT ) && + m_MonsterState != MONSTERSTATE_COMBAT && + m_MonsterState != MONSTERSTATE_PRONE && + m_MonsterState != MONSTERSTATE_SCRIPT) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_TAKEDAMAGE: + if ( m_afConditions & ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_DEATH: + if ( pev->deadflag != DEAD_NO ) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_HALFHEALTH: + if ( IsAlive() && pev->health <= ( pev->max_health / 2 ) ) + { + fFireTarget = TRUE; + } + break; +/* + + // !!!UNDONE - no persistant game state that allows us to track these two. + + case AITRIGGER_SQUADMEMBERDIE: + break; + case AITRIGGER_SQUADLEADERDIE: + break; +*/ + case AITRIGGER_HEARWORLD: + if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_WORLD ) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_HEARPLAYER: + if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_PLAYER ) + { + fFireTarget = TRUE; + } + break; + case AITRIGGER_HEARCOMBAT: + if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_COMBAT ) + { + fFireTarget = TRUE; + } + break; + } + + if ( fFireTarget ) + { + // fire the target, then set the trigger conditions to NONE so we don't fire again + ALERT ( at_aiconsole, "AI Trigger Fire Target\n" ); + FireTargets( STRING( m_iszTriggerTarget ), this, this, USE_TOGGLE, 0 ); + m_iTriggerCondition = AITRIGGER_NONE; + return TRUE; + } + + return FALSE; +} + +//========================================================= +// CanPlaySequence - determines whether or not the monster +// can play the scripted sequence or AI sequence that is +// trying to possess it. If DisregardState is set, the monster +// will be sucked into the script no matter what state it is +// in. ONLY Scripted AI ents should allow this. +//========================================================= +int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) +{ + if ( m_pCine || !IsAlive() || m_MonsterState == MONSTERSTATE_PRONE ) + { + // monster is already running a scripted sequence or dead! + return FALSE; + } + + if ( fDisregardMonsterState ) + { + // ok to go, no matter what the monster state. (scripted AI) + return TRUE; + } + + if ( m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE ) + { + // ok to go, but only in these states + return TRUE; + } + + if ( m_MonsterState == MONSTERSTATE_ALERT && interruptLevel >= SS_INTERRUPT_BY_NAME ) + return TRUE; + + // unknown situation + return FALSE; +} + + +//========================================================= +// FindLateralCover - attempts to locate a spot in the world +// directly to the left or right of the caller that will +// conceal them from view of pSightEnt +//========================================================= +#define COVER_CHECKS 5// how many checks are made +#define COVER_DELTA 48// distance between checks + +BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) +{ + TraceResult tr; + Vector vecBestOnLeft; + Vector vecBestOnRight; + Vector vecLeftTest; + Vector vecRightTest; + Vector vecStepRight; + int i; + + UTIL_MakeVectors ( pev->angles ); + vecStepRight = gpGlobals->v_right * COVER_DELTA; + vecStepRight.z = 0; + + vecLeftTest = vecRightTest = pev->origin; + + for ( i = 0 ; i < COVER_CHECKS ; i++ ) + { + vecLeftTest = vecLeftTest - vecStepRight; + vecRightTest = vecRightTest + vecStepRight; + + // it's faster to check the SightEnt's visibility to the potential spot than to check the local move, so we do that first. + UTIL_TraceLine( vecThreat + vecViewOffset, vecLeftTest + pev->view_ofs, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); + + if (tr.flFraction != 1.0) + { + if ( FValidateCover ( vecLeftTest ) && CheckLocalMove( pev->origin, vecLeftTest, NULL, NULL ) == LOCALMOVE_VALID ) + { + if ( MoveToLocation( ACT_RUN, 0, vecLeftTest ) ) + { + return TRUE; + } + } + } + + // it's faster to check the SightEnt's visibility to the potential spot than to check the local move, so we do that first. + UTIL_TraceLine(vecThreat + vecViewOffset, vecRightTest + pev->view_ofs, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); + + if ( tr.flFraction != 1.0 ) + { + if ( FValidateCover ( vecRightTest ) && CheckLocalMove( pev->origin, vecRightTest, NULL, NULL ) == LOCALMOVE_VALID ) + { + if ( MoveToLocation( ACT_RUN, 0, vecRightTest ) ) + { + return TRUE; + } + } + } + } + + return FALSE; +} + + +Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) +{ + CBaseEntity *pEnemy = m_hEnemy; + + if ( pEnemy ) + { + return ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP - shootOrigin ).Normalize(); + } + else + return gpGlobals->v_forward; +} + + + +//========================================================= +// FacingIdeal - tells us if a monster is facing its ideal +// yaw. Created this function because many spots in the +// code were checking the yawdiff against this magic +// number. Nicer to have it in one place if we're gonna +// be stuck with it. +//========================================================= +BOOL CBaseMonster :: FacingIdeal( void ) +{ + if ( fabs( FlYawDiff() ) <= 0.006 )//!!!BUGBUG - no magic numbers!!! + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// FCanActiveIdle +//========================================================= +BOOL CBaseMonster :: FCanActiveIdle ( void ) +{ + /* + if ( m_MonsterState == MONSTERSTATE_IDLE && m_IdealMonsterState == MONSTERSTATE_IDLE && !IsMoving() ) + { + return TRUE; + } + */ + return FALSE; +} + + +void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) +{ + if ( pszSentence && IsAlive() ) + { + if ( pszSentence[0] == '!' ) + EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, PITCH_NORM ); + else + SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, PITCH_NORM ); + } +} + + +void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) +{ + PlaySentence( pszSentence, duration, volume, attenuation ); +} + + +void CBaseMonster::SentenceStop( void ) +{ + EMIT_SOUND( edict(), CHAN_VOICE, "common/null.wav", 1.0, ATTN_IDLE ); +} + + +void CBaseMonster::CorpseFallThink( void ) +{ + if ( pev->flags & FL_ONGROUND ) + { + SetThink ( NULL ); + + SetSequenceBox( ); + UTIL_SetOrigin( pev, pev->origin );// link into world. + } + else + pev->nextthink = gpGlobals->time + 0.1; +} + +// Call after animation/pose is set up +void CBaseMonster :: MonsterInitDead( void ) +{ + InitBoneControllers(); + + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground + + pev->frame = 0; + ResetSequenceInfo( ); + pev->framerate = 0; + + // Copy health + pev->max_health = pev->health; + pev->deadflag = DEAD_DEAD; + + UTIL_SetSize(pev, g_vecZero, g_vecZero ); + UTIL_SetOrigin( pev, pev->origin ); + + // Setup health counters, etc. + BecomeDead(); + SetThink( &CBaseMonster::CorpseFallThink ); + pev->nextthink = gpGlobals->time + 0.5; +} + +//========================================================= +// BBoxIsFlat - check to see if the monster's bounding box +// is lying flat on a surface (traces from all four corners +// are same length.) +//========================================================= +BOOL CBaseMonster :: BBoxFlat ( void ) +{ + TraceResult tr; + Vector vecPoint; + float flXSize, flYSize; + float flLength; + float flLength2; + + flXSize = pev->size.x / 2; + flYSize = pev->size.y / 2; + + vecPoint.x = pev->origin.x + flXSize; + vecPoint.y = pev->origin.y + flYSize; + vecPoint.z = pev->origin.z; + + UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); + flLength = (vecPoint - tr.vecEndPos).Length(); + + vecPoint.x = pev->origin.x - flXSize; + vecPoint.y = pev->origin.y - flYSize; + + UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); + flLength2 = (vecPoint - tr.vecEndPos).Length(); + if ( flLength2 > flLength ) + { + return FALSE; + } + flLength = flLength2; + + vecPoint.x = pev->origin.x - flXSize; + vecPoint.y = pev->origin.y + flYSize; + UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); + flLength2 = (vecPoint - tr.vecEndPos).Length(); + if ( flLength2 > flLength ) + { + return FALSE; + } + flLength = flLength2; + + vecPoint.x = pev->origin.x + flXSize; + vecPoint.y = pev->origin.y - flYSize; + UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); + flLength2 = (vecPoint - tr.vecEndPos).Length(); + if ( flLength2 > flLength ) + { + return FALSE; + } + flLength = flLength2; + + return TRUE; +} + +//========================================================= +// Get Enemy - tries to find the best suitable enemy for the monster. +//========================================================= +BOOL CBaseMonster :: GetEnemy ( void ) +{ + CBaseEntity *pNewEnemy; + + if ( HasConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_NEMESIS) ) + { + pNewEnemy = BestVisibleEnemy(); + + if ( pNewEnemy != m_hEnemy && pNewEnemy != NULL) + { + // DO NOT mess with the monster's m_hEnemy pointer unless the schedule the monster is currently running will be interrupted + // by COND_NEW_ENEMY. This will eliminate the problem of monsters getting a new enemy while they are in a schedule that doesn't care, + // and then not realizing it by the time they get to a schedule that does. I don't feel this is a good permanent fix. + + if ( m_pSchedule ) + { + if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) + { + PushEnemy( m_hEnemy, m_vecEnemyLKP ); + SetConditions(bits_COND_NEW_ENEMY); + m_hEnemy = pNewEnemy; + m_vecEnemyLKP = m_hEnemy->pev->origin; + } + // if the new enemy has an owner, take that one as well + if (pNewEnemy->pev->owner != NULL) + { + CBaseEntity *pOwner = GetMonsterPointer( pNewEnemy->pev->owner ); + if ( pOwner && (pOwner->pev->flags & FL_MONSTER) && IRelationship( pOwner ) != R_NO ) + PushEnemy( pOwner, m_vecEnemyLKP ); + } + } + } + } + + // remember old enemies + if (m_hEnemy == NULL && PopEnemy( )) + { + if ( m_pSchedule ) + { + if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) + { + SetConditions(bits_COND_NEW_ENEMY); + } + } + } + + if ( m_hEnemy != NULL ) + { + // monster has an enemy. + return TRUE; + } + + return FALSE;// monster has no enemy +} + + +//========================================================= +// DropItem - dead monster drops named item +//========================================================= +CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) +{ + if ( !pszItemName ) + { + ALERT ( at_console, "DropItem() - No item name!\n" ); + return NULL; + } + + CBaseEntity *pItem = CBaseEntity::Create( pszItemName, vecPos, vecAng, edict() ); + + if ( pItem ) + { + // do we want this behavior to be default?! (sjb) + pItem->pev->velocity = pev->velocity; + pItem->pev->avelocity = Vector ( (float)0, (float)RANDOM_FLOAT( 0, 100 ), (float)0 ); + return pItem; + } + else + { + ALERT ( at_console, "DropItem() - Didn't create!\n" ); + return FALSE; + } + +} + + +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) +{ + // if flagged to fade out or I have an owner (I came from a monster spawner) + if ( (pev->spawnflags & SF_MONSTER_FADECORPSE) || !FNullEnt( pev->owner ) ) + return TRUE; + + return FALSE; +} diff --git a/main/source/dlls/monsters.h b/main/source/dlls/monsters.h index 5a219906..e0489078 100644 --- a/main/source/dlls/monsters.h +++ b/main/source/dlls/monsters.h @@ -1,88 +1,88 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef MONSTERS_H -#include "skill.h" -#define MONSTERS_H - -/* - -===== monsters.h ======================================================== - - Header file for monster-related utility code - -*/ - -// Hit Group standards -#define HITGROUP_GENERIC 0 -#define HITGROUP_HEAD 1 -#define HITGROUP_CHEST 2 -#define HITGROUP_STOMACH 3 -#define HITGROUP_LEFTARM 4 -#define HITGROUP_RIGHTARM 5 -#define HITGROUP_LEFTLEG 6 -#define HITGROUP_RIGHTLEG 7 - - -// spawn flags 256 and above are already taken by the engine -extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType ); - -Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 ); -Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL CONSTANT float g_flMeleeRange; -extern DLL_GLOBAL CONSTANT float g_flMediumRange; -extern DLL_GLOBAL CONSTANT float g_flLongRange; -extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ); -extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ); - -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget ); -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 ); - -// monster to monster relationship types -#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable. -#define R_FR -1// (FEAR)will run -#define R_NO 0// (NO RELATIONSHIP) disregard -#define R_DL 1// (DISLIKE) will attack -#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters -#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what - - -#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed() - -// -// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc. -// -class CGib : public CBaseEntity -{ -public: - void Spawn( const char *szGibModel ); - void EXPORT BounceGibTouch ( CBaseEntity *pOther ); - void EXPORT StickyGibTouch ( CBaseEntity *pOther ); - void EXPORT WaitTillLand( void ); - void LimitVelocity( void ); - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } - static void SpawnHeadGib( entvars_t *pevVictim ); - static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ); - static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ); - - int m_bloodColor; - int m_cBloodDecals; - int m_material; - float m_lifeTime; -}; - - -#endif //MONSTERS_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef MONSTERS_H +#include "skill.h" +#define MONSTERS_H + +/* + +===== monsters.h ======================================================== + + Header file for monster-related utility code + +*/ + +// Hit Group standards +#define HITGROUP_GENERIC 0 +#define HITGROUP_HEAD 1 +#define HITGROUP_CHEST 2 +#define HITGROUP_STOMACH 3 +#define HITGROUP_LEFTARM 4 +#define HITGROUP_RIGHTARM 5 +#define HITGROUP_LEFTLEG 6 +#define HITGROUP_RIGHTLEG 7 + + +// spawn flags 256 and above are already taken by the engine +extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType ); + +Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 ); +Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 ); +extern DLL_GLOBAL Vector g_vecAttackDir; +extern DLL_GLOBAL CONSTANT float g_flMeleeRange; +extern DLL_GLOBAL CONSTANT float g_flMediumRange; +extern DLL_GLOBAL CONSTANT float g_flLongRange; +extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ); +extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ); + +BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget ); +BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 ); + +// monster to monster relationship types +#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable. +#define R_FR -1// (FEAR)will run +#define R_NO 0// (NO RELATIONSHIP) disregard +#define R_DL 1// (DISLIKE) will attack +#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters +#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what + + +#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed() + +// +// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc. +// +class CGib : public CBaseEntity +{ +public: + void Spawn( const char *szGibModel ); + void EXPORT BounceGibTouch ( CBaseEntity *pOther ); + void EXPORT StickyGibTouch ( CBaseEntity *pOther ); + void EXPORT WaitTillLand( void ); + void LimitVelocity( void ); + + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } + static void SpawnHeadGib( entvars_t *pevVictim ); + static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ); + static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ); + + int m_bloodColor; + int m_cBloodDecals; + int m_material; + float m_lifeTime; +}; + + +#endif //MONSTERS_H diff --git a/main/source/dlls/monsterstate.cpp b/main/source/dlls/monsterstate.cpp index 775bcda0..125c080c 100644 --- a/main/source/dlls/monsterstate.cpp +++ b/main/source/dlls/monsterstate.cpp @@ -1,234 +1,234 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monsterstate.cpp - base class monster functions for -// controlling core AI. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "soundent.h" - -//========================================================= -// SetState -//========================================================= -void CBaseMonster :: SetState ( MONSTERSTATE State ) -{ -/* - if ( State != m_MonsterState ) - { - ALERT ( at_aiconsole, "State Changed to %d\n", State ); - } -*/ - - switch( State ) - { - - // Drop enemy pointers when going to idle - case MONSTERSTATE_IDLE: - - if ( m_hEnemy != NULL ) - { - m_hEnemy = NULL;// not allowed to have an enemy anymore. - ALERT ( at_aiconsole, "Stripped\n" ); - } - break; - } - - m_MonsterState = State; - m_IdealMonsterState = State; -} - -//========================================================= -// RunAI -//========================================================= -void CBaseMonster :: RunAI ( void ) -{ - // to test model's eye height - //UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 ); - - // IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state - // once we have sounds for that state. - if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) ) - { - IdleSound(); - } - - if ( m_MonsterState != MONSTERSTATE_NONE && - m_MonsterState != MONSTERSTATE_PRONE && - m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone. - { - // collect some sensory Condition information. - // don't let monsters outside of the player's PVS act up, or most of the interesting - // things will happen before the player gets there! - // UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave - // an area where monsters are fighting, and the fight will continue. - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) ) - { - Look( m_flDistLook ); - Listen();// check for audible sounds. - - // now filter conditions. - ClearConditions( IgnoreConditions() ); - - GetEnemy(); - } - - // do these calculations if monster has an enemy. - if ( m_hEnemy != NULL ) - { - CheckEnemy( m_hEnemy ); - } - - CheckAmmo(); - } - - FCheckAITrigger(); - - PrescheduleThink(); - - MaintainSchedule(); - - // if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger() - // we throw them out cause we don't want them sitting around through the lifespan of a schedule - // that doesn't use them. - m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); -} - -//========================================================= -// GetIdealState - surveys the Conditions information available -// and finds the best new state for a monster. -//========================================================= -MONSTERSTATE CBaseMonster :: GetIdealState ( void ) -{ - int iConditions; - - iConditions = IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - - /* - IDLE goes to ALERT upon hearing a sound - -IDLE goes to ALERT upon being injured - IDLE goes to ALERT upon seeing food - -IDLE goes to COMBAT upon sighting an enemy - IDLE goes to HUNT upon smelling food - */ - { - if ( iConditions & bits_COND_NEW_ENEMY ) - { - // new enemy! This means an idle monster has seen someone it dislikes, or - // that a monster in combat has found a more suitable target to attack - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } - else if ( iConditions & bits_COND_LIGHT_DAMAGE ) - { - MakeIdealYaw ( m_vecEnemyLKP ); - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - else if ( iConditions & bits_COND_HEAVY_DAMAGE ) - { - MakeIdealYaw ( m_vecEnemyLKP ); - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - else if ( iConditions & bits_COND_HEAR_SOUND ) - { - CSound *pSound; - - pSound = PBestSound(); - ASSERT( pSound != NULL ); - if ( pSound ) - { - MakeIdealYaw ( pSound->m_vecOrigin ); - if ( pSound->m_iType & (bits_SOUND_COMBAT|bits_SOUND_DANGER) ) - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - } - else if ( iConditions & (bits_COND_SMELL | bits_COND_SMELL_FOOD) ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - - break; - } - case MONSTERSTATE_ALERT: - /* - ALERT goes to IDLE upon becoming bored - -ALERT goes to COMBAT upon sighting an enemy - ALERT goes to HUNT upon hearing a noise - */ - { - if ( iConditions & (bits_COND_NEW_ENEMY|bits_COND_SEE_ENEMY) ) - { - // see an enemy we MUST attack - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } - else if ( iConditions & bits_COND_HEAR_SOUND ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - CSound *pSound = PBestSound(); - ASSERT( pSound != NULL ); - if ( pSound ) - MakeIdealYaw ( pSound->m_vecOrigin ); - } - break; - } - case MONSTERSTATE_COMBAT: - /* - COMBAT goes to HUNT upon losing sight of enemy - COMBAT goes to ALERT upon death of enemy - */ - { - if ( m_hEnemy == NULL ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - // pev->effects = EF_BRIGHTFIELD; - ALERT ( at_aiconsole, "***Combat state with no enemy!\n" ); - } - break; - } - case MONSTERSTATE_HUNT: - /* - HUNT goes to ALERT upon seeing food - HUNT goes to ALERT upon being injured - HUNT goes to IDLE if goal touched - HUNT goes to COMBAT upon seeing enemy - */ - { - break; - } - case MONSTERSTATE_SCRIPT: - if ( iConditions & (bits_COND_TASK_FAILED|bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) ) - { - ExitScriptedSequence(); // This will set the ideal state - } - break; - - case MONSTERSTATE_DEAD: - m_IdealMonsterState = MONSTERSTATE_DEAD; - break; - } - - return m_IdealMonsterState; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// monsterstate.cpp - base class monster functions for +// controlling core AI. +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "nodes.h" +#include "monsters.h" +#include "animation.h" +#include "saverestore.h" +#include "soundent.h" + +//========================================================= +// SetState +//========================================================= +void CBaseMonster :: SetState ( MONSTERSTATE State ) +{ +/* + if ( State != m_MonsterState ) + { + ALERT ( at_aiconsole, "State Changed to %d\n", State ); + } +*/ + + switch( State ) + { + + // Drop enemy pointers when going to idle + case MONSTERSTATE_IDLE: + + if ( m_hEnemy != NULL ) + { + m_hEnemy = NULL;// not allowed to have an enemy anymore. + ALERT ( at_aiconsole, "Stripped\n" ); + } + break; + } + + m_MonsterState = State; + m_IdealMonsterState = State; +} + +//========================================================= +// RunAI +//========================================================= +void CBaseMonster :: RunAI ( void ) +{ + // to test model's eye height + //UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 ); + + // IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state + // once we have sounds for that state. + if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) ) + { + IdleSound(); + } + + if ( m_MonsterState != MONSTERSTATE_NONE && + m_MonsterState != MONSTERSTATE_PRONE && + m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone. + { + // collect some sensory Condition information. + // don't let monsters outside of the player's PVS act up, or most of the interesting + // things will happen before the player gets there! + // UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave + // an area where monsters are fighting, and the fight will continue. + if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) ) + { + Look( m_flDistLook ); + Listen();// check for audible sounds. + + // now filter conditions. + ClearConditions( IgnoreConditions() ); + + GetEnemy(); + } + + // do these calculations if monster has an enemy. + if ( m_hEnemy != NULL ) + { + CheckEnemy( m_hEnemy ); + } + + CheckAmmo(); + } + + FCheckAITrigger(); + + PrescheduleThink(); + + MaintainSchedule(); + + // if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger() + // we throw them out cause we don't want them sitting around through the lifespan of a schedule + // that doesn't use them. + m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); +} + +//========================================================= +// GetIdealState - surveys the Conditions information available +// and finds the best new state for a monster. +//========================================================= +MONSTERSTATE CBaseMonster :: GetIdealState ( void ) +{ + int iConditions; + + iConditions = IScheduleFlags(); + + // If no schedule conditions, the new ideal state is probably the reason we're in here. + switch ( m_MonsterState ) + { + case MONSTERSTATE_IDLE: + + /* + IDLE goes to ALERT upon hearing a sound + -IDLE goes to ALERT upon being injured + IDLE goes to ALERT upon seeing food + -IDLE goes to COMBAT upon sighting an enemy + IDLE goes to HUNT upon smelling food + */ + { + if ( iConditions & bits_COND_NEW_ENEMY ) + { + // new enemy! This means an idle monster has seen someone it dislikes, or + // that a monster in combat has found a more suitable target to attack + m_IdealMonsterState = MONSTERSTATE_COMBAT; + } + else if ( iConditions & bits_COND_LIGHT_DAMAGE ) + { + MakeIdealYaw ( m_vecEnemyLKP ); + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + else if ( iConditions & bits_COND_HEAVY_DAMAGE ) + { + MakeIdealYaw ( m_vecEnemyLKP ); + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + else if ( iConditions & bits_COND_HEAR_SOUND ) + { + CSound *pSound; + + pSound = PBestSound(); + ASSERT( pSound != NULL ); + if ( pSound ) + { + MakeIdealYaw ( pSound->m_vecOrigin ); + if ( pSound->m_iType & (bits_SOUND_COMBAT|bits_SOUND_DANGER) ) + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + } + else if ( iConditions & (bits_COND_SMELL | bits_COND_SMELL_FOOD) ) + { + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + + break; + } + case MONSTERSTATE_ALERT: + /* + ALERT goes to IDLE upon becoming bored + -ALERT goes to COMBAT upon sighting an enemy + ALERT goes to HUNT upon hearing a noise + */ + { + if ( iConditions & (bits_COND_NEW_ENEMY|bits_COND_SEE_ENEMY) ) + { + // see an enemy we MUST attack + m_IdealMonsterState = MONSTERSTATE_COMBAT; + } + else if ( iConditions & bits_COND_HEAR_SOUND ) + { + m_IdealMonsterState = MONSTERSTATE_ALERT; + CSound *pSound = PBestSound(); + ASSERT( pSound != NULL ); + if ( pSound ) + MakeIdealYaw ( pSound->m_vecOrigin ); + } + break; + } + case MONSTERSTATE_COMBAT: + /* + COMBAT goes to HUNT upon losing sight of enemy + COMBAT goes to ALERT upon death of enemy + */ + { + if ( m_hEnemy == NULL ) + { + m_IdealMonsterState = MONSTERSTATE_ALERT; + // pev->effects = EF_BRIGHTFIELD; + ALERT ( at_aiconsole, "***Combat state with no enemy!\n" ); + } + break; + } + case MONSTERSTATE_HUNT: + /* + HUNT goes to ALERT upon seeing food + HUNT goes to ALERT upon being injured + HUNT goes to IDLE if goal touched + HUNT goes to COMBAT upon seeing enemy + */ + { + break; + } + case MONSTERSTATE_SCRIPT: + if ( iConditions & (bits_COND_TASK_FAILED|bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) ) + { + ExitScriptedSequence(); // This will set the ideal state + } + break; + + case MONSTERSTATE_DEAD: + m_IdealMonsterState = MONSTERSTATE_DEAD; + break; + } + + return m_IdealMonsterState; +} + diff --git a/main/source/dlls/mortar.cpp b/main/source/dlls/mortar.cpp index 60d61b2a..0b879955 100644 --- a/main/source/dlls/mortar.cpp +++ b/main/source/dlls/mortar.cpp @@ -1,323 +1,323 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== mortar.cpp ======================================================== - - the "LaBuznik" mortar device - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "weapons.h" -#include "decals.h" -#include "soundent.h" - -class CFuncMortarField : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - void EXPORT FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iszXController; - int m_iszYController; - float m_flSpread; - float m_flDelay; - int m_iCount; - int m_fControl; -}; - -LINK_ENTITY_TO_CLASS( func_mortar_field, CFuncMortarField ); - -TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = -{ - DEFINE_FIELD( CFuncMortarField, m_iszXController, FIELD_STRING ), - DEFINE_FIELD( CFuncMortarField, m_iszYController, FIELD_STRING ), - DEFINE_FIELD( CFuncMortarField, m_flSpread, FIELD_FLOAT ), - DEFINE_FIELD( CFuncMortarField, m_flDelay, FIELD_FLOAT ), - DEFINE_FIELD( CFuncMortarField, m_iCount, FIELD_INTEGER ), - DEFINE_FIELD( CFuncMortarField, m_fControl, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle ); - - -void CFuncMortarField :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszXController")) - { - m_iszXController = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszYController")) - { - m_iszYController = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flSpread")) - { - m_flSpread = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fControl")) - { - m_fControl = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iCount")) - { - m_iCount = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - - -// Drop bombs from above -void CFuncMortarField :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_NONE; - SetBits( pev->effects, EF_NODRAW ); - SetUse( &CFuncMortarField::FieldUse ); - Precache(); -} - - -void CFuncMortarField :: Precache( void ) -{ - PRECACHE_SOUND ("weapons/mortar.wav"); - PRECACHE_SOUND ("weapons/mortarhit.wav"); - PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - - -// If connected to a table, then use the table controllers, else hit where the trigger is. -void CFuncMortarField :: FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - Vector vecStart; - - vecStart.x = RANDOM_FLOAT( pev->mins.x, pev->maxs.x ); - vecStart.y = RANDOM_FLOAT( pev->mins.y, pev->maxs.y ); - vecStart.z = pev->maxs.z; - - switch( m_fControl ) - { - case 0: // random - break; - case 1: // Trigger Activator - if (pActivator != NULL) - { - vecStart.x = pActivator->pev->origin.x; - vecStart.y = pActivator->pev->origin.y; - } - break; - case 2: // table - { - CBaseEntity *pController; - - if (!FStringNull(m_iszXController)) - { - pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszXController)); - if (pController != NULL) - { - vecStart.x = pev->mins.x + pController->pev->ideal_yaw * (pev->size.x); - } - } - if (!FStringNull(m_iszYController)) - { - pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszYController)); - if (pController != NULL) - { - vecStart.y = pev->mins.y + pController->pev->ideal_yaw * (pev->size.y); - } - } - } - break; - } - - int pitch = RANDOM_LONG(95,124); - - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortar.wav", 1.0, ATTN_NONE, 0, pitch); - - float t = 2.5; - for (int i = 0; i < m_iCount; i++) - { - Vector vecSpot = vecStart; - vecSpot.x += RANDOM_FLOAT( -m_flSpread, m_flSpread ); - vecSpot.y += RANDOM_FLOAT( -m_flSpread, m_flSpread ); - - TraceResult tr; - UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pev), &tr ); - - edict_t *pentOwner = NULL; - if (pActivator) pentOwner = pActivator->edict(); - - CBaseEntity *pMortar = Create("monster_mortar", tr.vecEndPos, Vector( 0, 0, 0 ), pentOwner ); - pMortar->pev->nextthink = gpGlobals->time + t; - t += RANDOM_FLOAT( 0.2, 0.5 ); - - if (i == 0) - CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); - } -} - - -class CMortar : public CGrenade -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT MortarExplode( void ); - - int m_spriteTexture; -}; - -LINK_ENTITY_TO_CLASS( monster_mortar, CMortar ); - -void CMortar::Spawn( ) -{ - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - - pev->dmg = 200; - - SetThink( &CMortar::MortarExplode ); - pev->nextthink = 0; - - Precache( ); - - -} - - -void CMortar::Precache( ) -{ - m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - -void CMortar::MortarExplode( void ) -{ -#if 1 - // mortar beam - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS ); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z + 1024); - WRITE_SHORT(m_spriteTexture ); - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 1 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 160 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); -#endif - -#if 0 - // blast circle - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMTORUS); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z + 32); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z + 32 + pev->dmg * 2 / .2); // reach damage radius over .3 seconds - WRITE_SHORT(m_spriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 12 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 160 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); -#endif - - TraceResult tr; - UTIL_TraceLine( pev->origin + Vector( 0, 0, 1024 ), pev->origin - Vector( 0, 0, 1024 ), dont_ignore_monsters, ENT(pev), &tr ); - - Explode( &tr, DMG_BLAST | DMG_MORTAR ); - UTIL_ScreenShake( tr.vecEndPos, 25.0, 150.0, 1.0, 750 ); - -#if 0 - int pitch = RANDOM_LONG(95,124); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortarhit.wav", 1.0, 0.55, 0, pitch); - - // ForceSound( SNDRADIUS_MP5, bits_SOUND_COMBAT ); - - // ExplodeModel( pev->origin, 400, g_sModelIndexShrapnel, 30 ); - - RadiusDamage ( pev, VARS(pev->owner), pev->dmg, CLASS_NONE, DMG_BLAST ); - - /* - if ( RANDOM_FLOAT ( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); - } - */ - - SetThink( &CMortar::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -#endif - -} - - -#if 0 -void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time ) -{ - CMortar *pMortar = GetClassPtr( (CMortar *)NULL ); - pMortar->Spawn(); - - TraceResult tr; - UTIL_TraceLine( vecStart, vecStart + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pMortar->pev), &tr ); - - pMortar->pev->nextthink = gpGlobals->time + time; - - UTIL_SetOrigin( pMortar->pev, tr.vecEndPos ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== mortar.cpp ======================================================== + + the "LaBuznik" mortar device + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "weapons.h" +#include "decals.h" +#include "soundent.h" + +class CFuncMortarField : public CBaseToggle +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + + // Bmodels don't go across transitions + virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + void EXPORT FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + int m_iszXController; + int m_iszYController; + float m_flSpread; + float m_flDelay; + int m_iCount; + int m_fControl; +}; + +LINK_ENTITY_TO_CLASS( func_mortar_field, CFuncMortarField ); + +TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = +{ + DEFINE_FIELD( CFuncMortarField, m_iszXController, FIELD_STRING ), + DEFINE_FIELD( CFuncMortarField, m_iszYController, FIELD_STRING ), + DEFINE_FIELD( CFuncMortarField, m_flSpread, FIELD_FLOAT ), + DEFINE_FIELD( CFuncMortarField, m_flDelay, FIELD_FLOAT ), + DEFINE_FIELD( CFuncMortarField, m_iCount, FIELD_INTEGER ), + DEFINE_FIELD( CFuncMortarField, m_fControl, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle ); + + +void CFuncMortarField :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "m_iszXController")) + { + m_iszXController = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_iszYController")) + { + m_iszYController = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_flSpread")) + { + m_flSpread = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_fControl")) + { + m_fControl = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_iCount")) + { + m_iCount = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } +} + + +// Drop bombs from above +void CFuncMortarField :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + pev->movetype = MOVETYPE_NONE; + SetBits( pev->effects, EF_NODRAW ); + SetUse( &CFuncMortarField::FieldUse ); + Precache(); +} + + +void CFuncMortarField :: Precache( void ) +{ + PRECACHE_SOUND ("weapons/mortar.wav"); + PRECACHE_SOUND ("weapons/mortarhit.wav"); + PRECACHE_MODEL( "sprites/lgtning.spr" ); +} + + +// If connected to a table, then use the table controllers, else hit where the trigger is. +void CFuncMortarField :: FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + Vector vecStart; + + vecStart.x = RANDOM_FLOAT( pev->mins.x, pev->maxs.x ); + vecStart.y = RANDOM_FLOAT( pev->mins.y, pev->maxs.y ); + vecStart.z = pev->maxs.z; + + switch( m_fControl ) + { + case 0: // random + break; + case 1: // Trigger Activator + if (pActivator != NULL) + { + vecStart.x = pActivator->pev->origin.x; + vecStart.y = pActivator->pev->origin.y; + } + break; + case 2: // table + { + CBaseEntity *pController; + + if (!FStringNull(m_iszXController)) + { + pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszXController)); + if (pController != NULL) + { + vecStart.x = pev->mins.x + pController->pev->ideal_yaw * (pev->size.x); + } + } + if (!FStringNull(m_iszYController)) + { + pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszYController)); + if (pController != NULL) + { + vecStart.y = pev->mins.y + pController->pev->ideal_yaw * (pev->size.y); + } + } + } + break; + } + + int pitch = RANDOM_LONG(95,124); + + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortar.wav", 1.0, ATTN_NONE, 0, pitch); + + float t = 2.5; + for (int i = 0; i < m_iCount; i++) + { + Vector vecSpot = vecStart; + vecSpot.x += RANDOM_FLOAT( -m_flSpread, m_flSpread ); + vecSpot.y += RANDOM_FLOAT( -m_flSpread, m_flSpread ); + + TraceResult tr; + UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pev), &tr ); + + edict_t *pentOwner = NULL; + if (pActivator) pentOwner = pActivator->edict(); + + CBaseEntity *pMortar = Create("monster_mortar", tr.vecEndPos, Vector( 0, 0, 0 ), pentOwner ); + pMortar->pev->nextthink = gpGlobals->time + t; + t += RANDOM_FLOAT( 0.2, 0.5 ); + + if (i == 0) + CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); + } +} + + +class CMortar : public CGrenade +{ +public: + void Spawn( void ); + void Precache( void ); + + void EXPORT MortarExplode( void ); + + int m_spriteTexture; +}; + +LINK_ENTITY_TO_CLASS( monster_mortar, CMortar ); + +void CMortar::Spawn( ) +{ + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + + pev->dmg = 200; + + SetThink( &CMortar::MortarExplode ); + pev->nextthink = 0; + + Precache( ); + + +} + + +void CMortar::Precache( ) +{ + m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr" ); +} + +void CMortar::MortarExplode( void ) +{ +#if 1 + // mortar beam + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(pev->origin.x); + WRITE_COORD(pev->origin.y); + WRITE_COORD(pev->origin.z); + WRITE_COORD(pev->origin.x); + WRITE_COORD(pev->origin.y); + WRITE_COORD(pev->origin.z + 1024); + WRITE_SHORT(m_spriteTexture ); + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 1 ); // life + WRITE_BYTE( 40 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 160 ); // r, g, b + WRITE_BYTE( 100 ); // r, g, b + WRITE_BYTE( 128 ); // brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); +#endif + +#if 0 + // blast circle + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMTORUS); + WRITE_COORD(pev->origin.x); + WRITE_COORD(pev->origin.y); + WRITE_COORD(pev->origin.z + 32); + WRITE_COORD(pev->origin.x); + WRITE_COORD(pev->origin.y); + WRITE_COORD(pev->origin.z + 32 + pev->dmg * 2 / .2); // reach damage radius over .3 seconds + WRITE_SHORT(m_spriteTexture ); + WRITE_BYTE( 0 ); // startframe + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 2 ); // life + WRITE_BYTE( 12 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 160 ); // r, g, b + WRITE_BYTE( 100 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); +#endif + + TraceResult tr; + UTIL_TraceLine( pev->origin + Vector( 0, 0, 1024 ), pev->origin - Vector( 0, 0, 1024 ), dont_ignore_monsters, ENT(pev), &tr ); + + Explode( &tr, DMG_BLAST | DMG_MORTAR ); + UTIL_ScreenShake( tr.vecEndPos, 25.0, 150.0, 1.0, 750 ); + +#if 0 + int pitch = RANDOM_LONG(95,124); + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortarhit.wav", 1.0, 0.55, 0, pitch); + + // ForceSound( SNDRADIUS_MP5, bits_SOUND_COMBAT ); + + // ExplodeModel( pev->origin, 400, g_sModelIndexShrapnel, 30 ); + + RadiusDamage ( pev, VARS(pev->owner), pev->dmg, CLASS_NONE, DMG_BLAST ); + + /* + if ( RANDOM_FLOAT ( 0 , 1 ) < 0.5 ) + { + UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); + } + else + { + UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); + } + */ + + SetThink( &CMortar::SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; +#endif + +} + + +#if 0 +void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time ) +{ + CMortar *pMortar = GetClassPtr( (CMortar *)NULL ); + pMortar->Spawn(); + + TraceResult tr; + UTIL_TraceLine( vecStart, vecStart + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pMortar->pev), &tr ); + + pMortar->pev->nextthink = gpGlobals->time + time; + + UTIL_SetOrigin( pMortar->pev, tr.vecEndPos ); +} #endif \ No newline at end of file diff --git a/main/source/dlls/mp5.cpp b/main/source/dlls/mp5.cpp index 5626bc74..613603c4 100644 --- a/main/source/dlls/mp5.cpp +++ b/main/source/dlls/mp5.cpp @@ -1,385 +1,385 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" - -enum mp5_e -{ - MP5_LONGIDLE = 0, - MP5_IDLE1, - MP5_LAUNCH, - MP5_RELOAD, - MP5_DEPLOY, - MP5_FIRE1, - MP5_FIRE2, - MP5_FIRE3, -}; - - - -LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ); -LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); - - -//========================================================= -//========================================================= -int CMP5::SecondaryAmmoIndex( void ) -{ - return m_iSecondaryAmmoType; -} - -void CMP5::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmAR"); // hack to allow for old names - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmAR.mdl"); - m_iId = WEAPON_MP5; - - m_iDefaultAmmo = MP5_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CMP5::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmAR.mdl"); - PRECACHE_MODEL("models/w_9mmAR.mdl"); - PRECACHE_MODEL("models/p_9mmAR.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shellTE_MODEL - - PRECACHE_MODEL("models/grenade.mdl"); // grenade - - PRECACHE_MODEL("models/w_9mmARclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND("items/clipinsert1.wav"); - PRECACHE_SOUND("items/cliprelease1.wav"); - - PRECACHE_SOUND ("weapons/hks1.wav");// H to the K - PRECACHE_SOUND ("weapons/hks2.wav");// H to the K - PRECACHE_SOUND ("weapons/hks3.wav");// H to the K - - PRECACHE_SOUND( "weapons/glauncher.wav" ); - PRECACHE_SOUND( "weapons/glauncher2.wav" ); - - PRECACHE_SOUND ("weapons/357_cock1.wav"); - - m_usMP5 = PRECACHE_EVENT( 1, "events/mp5.sc" ); - m_usMP52 = PRECACHE_EVENT( 1, "events/mp52.sc" ); -} - -int CMP5::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = "ARgrenades"; - p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY; - p->iMaxClip = MP5_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_MP5; - p->iWeight = MP5_WEIGHT; - - return 1; -} - -int CMP5::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CMP5::Deploy( ) -{ - return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" ); -} - - -void CMP5::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if (m_iClip <= 0) - { - PlayEmptySound(); - m_flNextPrimaryAttack = 0.15; - return; - } - - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - Vector vecDir; - -#ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) -#else - if ( !g_pGameRules->IsMultiplayer() ) -#endif - { - // optimized multiplayer. Widened to make it easier to hit a moving player - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // single player spread - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usMP5, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - - if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - - -void CMP5::SecondaryAttack( void ) -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0) - { - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; - m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; - - m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - // we don't add in player velocity anymore. - CGrenade::ShootContact( m_pPlayer->pev, - m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, - gpGlobals->v_forward * 800 ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. - - if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); -} - -void CMP5::Reload( void ) -{ - if ( m_pPlayer->ammo_9mm <= 0 ) - return; - - DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); -} - - -void CMP5::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - iAnim = MP5_LONGIDLE; - break; - - default: - case 1: - iAnim = MP5_IDLE1; - break; - } - - SendWeaponAnim( iAnim ); - - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. -} - - - -class CMP5AmmoClip : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmARclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmARclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = (pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", _9MM_MAX_CARRY) != -1); - if (bResult) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return bResult; - } -}; -LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ); -LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ); - - - -class CMP5Chainammo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_chainammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = (pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "9mm", _9MM_MAX_CARRY) != -1); - if (bResult) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return bResult; - } -}; -LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo ); - - -class CMP5AmmoGrenade : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_ARgrenade.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_ARgrenade.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = (pOther->GiveAmmo( AMMO_M203BOX_GIVE, "ARgrenades", M203_GRENADE_MAX_CARRY ) != -1); - - if (bResult) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return bResult; - } -}; -LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade ); -LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade ); - - - - - - - - - - - - - - - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "soundent.h" +#include "gamerules.h" + +enum mp5_e +{ + MP5_LONGIDLE = 0, + MP5_IDLE1, + MP5_LAUNCH, + MP5_RELOAD, + MP5_DEPLOY, + MP5_FIRE1, + MP5_FIRE2, + MP5_FIRE3, +}; + + + +LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ); +LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); + + +//========================================================= +//========================================================= +int CMP5::SecondaryAmmoIndex( void ) +{ + return m_iSecondaryAmmoType; +} + +void CMP5::Spawn( ) +{ + pev->classname = MAKE_STRING("weapon_9mmAR"); // hack to allow for old names + Precache( ); + SET_MODEL(ENT(pev), "models/w_9mmAR.mdl"); + m_iId = WEAPON_MP5; + + m_iDefaultAmmo = MP5_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CMP5::Precache( void ) +{ + PRECACHE_MODEL("models/v_9mmAR.mdl"); + PRECACHE_MODEL("models/w_9mmAR.mdl"); + PRECACHE_MODEL("models/p_9mmAR.mdl"); + + m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shellTE_MODEL + + PRECACHE_MODEL("models/grenade.mdl"); // grenade + + PRECACHE_MODEL("models/w_9mmARclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + + PRECACHE_SOUND("items/clipinsert1.wav"); + PRECACHE_SOUND("items/cliprelease1.wav"); + + PRECACHE_SOUND ("weapons/hks1.wav");// H to the K + PRECACHE_SOUND ("weapons/hks2.wav");// H to the K + PRECACHE_SOUND ("weapons/hks3.wav");// H to the K + + PRECACHE_SOUND( "weapons/glauncher.wav" ); + PRECACHE_SOUND( "weapons/glauncher2.wav" ); + + PRECACHE_SOUND ("weapons/357_cock1.wav"); + + m_usMP5 = PRECACHE_EVENT( 1, "events/mp5.sc" ); + m_usMP52 = PRECACHE_EVENT( 1, "events/mp52.sc" ); +} + +int CMP5::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "9mm"; + p->iMaxAmmo1 = _9MM_MAX_CARRY; + p->pszAmmo2 = "ARgrenades"; + p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY; + p->iMaxClip = MP5_MAX_CLIP; + p->iSlot = 2; + p->iPosition = 0; + p->iFlags = 0; + p->iId = m_iId = WEAPON_MP5; + p->iWeight = MP5_WEIGHT; + + return 1; +} + +int CMP5::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); + WRITE_BYTE( m_iId ); + MESSAGE_END(); + return TRUE; + } + return FALSE; +} + +BOOL CMP5::Deploy( ) +{ + return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" ); +} + + +void CMP5::PrimaryAttack() +{ + // don't fire underwater + if (m_pPlayer->pev->waterlevel == 3) + { + PlayEmptySound( ); + m_flNextPrimaryAttack = 0.15; + return; + } + + if (m_iClip <= 0) + { + PlayEmptySound(); + m_flNextPrimaryAttack = 0.15; + return; + } + + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; + + m_iClip--; + + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + Vector vecDir; + +#ifdef CLIENT_DLL + if ( !bIsMultiplayer() ) +#else + if ( !g_pGameRules->IsMultiplayer() ) +#endif + { + // optimized multiplayer. Widened to make it easier to hit a moving player + vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + } + else + { + // single player spread + vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + } + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usMP5, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; + + if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +} + + + +void CMP5::SecondaryAttack( void ) +{ + // don't fire underwater + if (m_pPlayer->pev->waterlevel == 3) + { + PlayEmptySound( ); + m_flNextPrimaryAttack = 0.15; + return; + } + + if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0) + { + PlayEmptySound( ); + return; + } + + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; + + m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; + m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; + + m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + + // we don't add in player velocity anymore. + CGrenade::ShootContact( m_pPlayer->pev, + m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, + gpGlobals->v_forward * 800 ); + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. + + if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); +} + +void CMP5::Reload( void ) +{ + if ( m_pPlayer->ammo_9mm <= 0 ) + return; + + DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); +} + + +void CMP5::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + int iAnim; + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: + iAnim = MP5_LONGIDLE; + break; + + default: + case 1: + iAnim = MP5_IDLE1; + break; + } + + SendWeaponAnim( iAnim ); + + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. +} + + + +class CMP5AmmoClip : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_9mmARclip.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_9mmARclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + int bResult = (pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", _9MM_MAX_CARRY) != -1); + if (bResult) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + } + return bResult; + } +}; +LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ); +LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ); + + + +class CMP5Chainammo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_chainammo.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + int bResult = (pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "9mm", _9MM_MAX_CARRY) != -1); + if (bResult) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + } + return bResult; + } +}; +LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo ); + + +class CMP5AmmoGrenade : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_ARgrenade.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_ARgrenade.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + int bResult = (pOther->GiveAmmo( AMMO_M203BOX_GIVE, "ARgrenades", M203_GRENADE_MAX_CARRY ) != -1); + + if (bResult) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + } + return bResult; + } +}; +LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade ); +LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade ); + + + + + + + + + + + + + + + + + + diff --git a/main/source/dlls/mpstubb.cpp b/main/source/dlls/mpstubb.cpp index 153b25e9..83b5e7b2 100644 --- a/main/source/dlls/mpstubb.cpp +++ b/main/source/dlls/mpstubb.cpp @@ -1,264 +1,264 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" -#include "nodes.h" -#include "talkmonster.h" - - -float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once - -/*********************************************************/ - - -CGraph WorldGraph; -void CGraph :: InitGraph( void ) { } -int CGraph :: FLoadGraph ( char *szMapName ) { return FALSE; } -int CGraph :: AllocNodes ( void ) { return FALSE; } -int CGraph :: CheckNODFile ( char *szMapName ) { return FALSE; } -int CGraph :: FSetGraphPointers ( void ) { return 0; } -void CGraph :: ShowNodeConnections ( int iNode ) { } -int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) { return 0; } - - -/*********************************************************/ - - -void CBaseMonster :: ReportAIState( void ) { } -float CBaseMonster :: ChangeYaw ( int speed ) { return 0; } -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } - - -void CBaseMonster::CorpseFallThink( void ) -{ - if ( pev->flags & FL_ONGROUND ) - { - SetThink ( NULL ); - - SetSequenceBox( ); - UTIL_SetOrigin( pev, pev->origin );// link into world. - } - else - pev->nextthink = gpGlobals->time + 0.1; -} -// Call after animation/pose is set up -void CBaseMonster :: MonsterInitDead( void ) -{ - InitBoneControllers(); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground - - pev->frame = 0; - ResetSequenceInfo( ); - pev->framerate = 0; - - // Copy health - pev->max_health = pev->health; - pev->deadflag = DEAD_DEAD; - - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - UTIL_SetOrigin( pev, pev->origin ); - - // Setup health counters, etc. - BecomeDead(); - SetThink( &CBaseMonster::CorpseFallThink ); - pev->nextthink = gpGlobals->time + 0.5; -} - - -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) -{ - return FALSE; -} - -BOOL CBaseMonster :: FCheckAITrigger ( void ) -{ - return FALSE; -} - -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) -{ - CBaseToggle::KeyValue( pkvd ); -} - -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) -{ - static int iEnemy[14][14] = - { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN - /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, - /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, - /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, - /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, - /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, - /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, - /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, - /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, - /*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO } - }; - - return iEnemy[ Classify() ][ pTarget->Classify() ]; -} - - -//========================================================= -// Look - Base class monster function to find enemies or -// food by sight. iDistance is distance ( in units ) that the -// monster can see. -// -// Sets the sight bits of the m_afConditions mask to indicate -// which types of entities were sighted. -// Function also sets the Looker's m_pLink -// to the head of a link list that contains all visible ents. -// (linked via each ent's m_pLink field) -// -//========================================================= -void CBaseMonster :: Look ( int iDistance ) -{ - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); - - m_pLink = NULL; - - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - - CBaseEntity *pList[100]; - - Vector delta = Vector( iDistance, iDistance, iDistance ); - - // Find only monsters/clients in box, NOT limited to PVS - int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); - for ( int i = 0; i < count; i++ ) - { - pSightEnt = pList[i]; - if ( pSightEnt != this && pSightEnt->pev->health > 0 ) - { - // the looker will want to consider this entity - // don't check anything else about an entity that can't be seen, or an entity that you don't care about. - if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) - { - if ( pSightEnt->IsPlayer() ) - { - // if we see a client, remember that (mostly for scripted AI) - iSighted |= bits_COND_SEE_CLIENT; - } - - pSightEnt->m_pLink = m_pLink; - m_pLink = pSightEnt; - - if ( pSightEnt == m_hEnemy ) - { - // we know this ent is visible, so if it also happens to be our enemy, store that now. - iSighted |= bits_COND_SEE_ENEMY; - } - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch ( IRelationship ( pSightEnt ) ) - { - case R_NM: - iSighted |= bits_COND_SEE_NEMESIS; - break; - case R_HT: - iSighted |= bits_COND_SEE_HATE; - break; - case R_DL: - iSighted |= bits_COND_SEE_DISLIKE; - break; - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_AL: - break; - default: - ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - - SetConditions( iSighted ); -} - - -//========================================================= -// BestVisibleEnemy - this functions searches the link -// list whose head is the caller's m_pLink field, and returns -// a pointer to the enemy entity in that list that is nearest the -// caller. -// -// !!!UNDONE - currently, this only returns the closest enemy. -// we'll want to consider distance, relationship, attack types, back turned, etc. -//========================================================= -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) -{ - CBaseEntity *pReturn; - CBaseEntity *pNextEnt; - int iNearest; - int iDist; - int iBestRelationship; - - iNearest = 8192;// so first visible entity will become the closest. - pNextEnt = m_pLink; - pReturn = NULL; - iBestRelationship = R_NO; - - while ( pNextEnt != NULL ) - { - if ( pNextEnt->IsAlive() ) - { - if ( IRelationship( pNextEnt) > iBestRelationship ) - { - // this entity is disliked MORE than the entity that we - // currently think is the best visible enemy. No need to do - // a distance check, just get mad at this one for now. - iBestRelationship = IRelationship ( pNextEnt ); - iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); - pReturn = pNextEnt; - } - else if ( IRelationship( pNextEnt) == iBestRelationship ) - { - // this entity is disliked just as much as the entity that - // we currently think is the best visible enemy, so we only - // get mad at it if it is closer. - iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); - - if ( iDist <= iNearest ) - { - iNearest = iDist; - iBestRelationship = IRelationship ( pNextEnt ); - pReturn = pNextEnt; - } - } - } - - pNextEnt = pNextEnt->m_pLink; - } - - return pReturn; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "soundent.h" +#include "nodes.h" +#include "talkmonster.h" + + +float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once + +/*********************************************************/ + + +CGraph WorldGraph; +void CGraph :: InitGraph( void ) { } +int CGraph :: FLoadGraph ( char *szMapName ) { return FALSE; } +int CGraph :: AllocNodes ( void ) { return FALSE; } +int CGraph :: CheckNODFile ( char *szMapName ) { return FALSE; } +int CGraph :: FSetGraphPointers ( void ) { return 0; } +void CGraph :: ShowNodeConnections ( int iNode ) { } +int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) { return 0; } + + +/*********************************************************/ + + +void CBaseMonster :: ReportAIState( void ) { } +float CBaseMonster :: ChangeYaw ( int speed ) { return 0; } +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } + + +void CBaseMonster::CorpseFallThink( void ) +{ + if ( pev->flags & FL_ONGROUND ) + { + SetThink ( NULL ); + + SetSequenceBox( ); + UTIL_SetOrigin( pev, pev->origin );// link into world. + } + else + pev->nextthink = gpGlobals->time + 0.1; +} +// Call after animation/pose is set up +void CBaseMonster :: MonsterInitDead( void ) +{ + InitBoneControllers(); + + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground + + pev->frame = 0; + ResetSequenceInfo( ); + pev->framerate = 0; + + // Copy health + pev->max_health = pev->health; + pev->deadflag = DEAD_DEAD; + + UTIL_SetSize(pev, g_vecZero, g_vecZero ); + UTIL_SetOrigin( pev, pev->origin ); + + // Setup health counters, etc. + BecomeDead(); + SetThink( &CBaseMonster::CorpseFallThink ); + pev->nextthink = gpGlobals->time + 0.5; +} + + +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) +{ + return FALSE; +} + +BOOL CBaseMonster :: FCheckAITrigger ( void ) +{ + return FALSE; +} + +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) +{ + CBaseToggle::KeyValue( pkvd ); +} + +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) +{ + static int iEnemy[14][14] = + { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN + /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, + /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, + /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, + /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, + /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, + /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, + /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, + /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, + /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, + /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, + /*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO } + }; + + return iEnemy[ Classify() ][ pTarget->Classify() ]; +} + + +//========================================================= +// Look - Base class monster function to find enemies or +// food by sight. iDistance is distance ( in units ) that the +// monster can see. +// +// Sets the sight bits of the m_afConditions mask to indicate +// which types of entities were sighted. +// Function also sets the Looker's m_pLink +// to the head of a link list that contains all visible ents. +// (linked via each ent's m_pLink field) +// +//========================================================= +void CBaseMonster :: Look ( int iDistance ) +{ + int iSighted = 0; + + // DON'T let visibility information from last frame sit around! + ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); + + m_pLink = NULL; + + CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with + + CBaseEntity *pList[100]; + + Vector delta = Vector( iDistance, iDistance, iDistance ); + + // Find only monsters/clients in box, NOT limited to PVS + int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); + for ( int i = 0; i < count; i++ ) + { + pSightEnt = pList[i]; + if ( pSightEnt != this && pSightEnt->pev->health > 0 ) + { + // the looker will want to consider this entity + // don't check anything else about an entity that can't be seen, or an entity that you don't care about. + if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) + { + if ( pSightEnt->IsPlayer() ) + { + // if we see a client, remember that (mostly for scripted AI) + iSighted |= bits_COND_SEE_CLIENT; + } + + pSightEnt->m_pLink = m_pLink; + m_pLink = pSightEnt; + + if ( pSightEnt == m_hEnemy ) + { + // we know this ent is visible, so if it also happens to be our enemy, store that now. + iSighted |= bits_COND_SEE_ENEMY; + } + + // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when + // we see monsters other than the Enemy. + switch ( IRelationship ( pSightEnt ) ) + { + case R_NM: + iSighted |= bits_COND_SEE_NEMESIS; + break; + case R_HT: + iSighted |= bits_COND_SEE_HATE; + break; + case R_DL: + iSighted |= bits_COND_SEE_DISLIKE; + break; + case R_FR: + iSighted |= bits_COND_SEE_FEAR; + break; + case R_AL: + break; + default: + ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); + break; + } + } + } + } + + SetConditions( iSighted ); +} + + +//========================================================= +// BestVisibleEnemy - this functions searches the link +// list whose head is the caller's m_pLink field, and returns +// a pointer to the enemy entity in that list that is nearest the +// caller. +// +// !!!UNDONE - currently, this only returns the closest enemy. +// we'll want to consider distance, relationship, attack types, back turned, etc. +//========================================================= +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) +{ + CBaseEntity *pReturn; + CBaseEntity *pNextEnt; + int iNearest; + int iDist; + int iBestRelationship; + + iNearest = 8192;// so first visible entity will become the closest. + pNextEnt = m_pLink; + pReturn = NULL; + iBestRelationship = R_NO; + + while ( pNextEnt != NULL ) + { + if ( pNextEnt->IsAlive() ) + { + if ( IRelationship( pNextEnt) > iBestRelationship ) + { + // this entity is disliked MORE than the entity that we + // currently think is the best visible enemy. No need to do + // a distance check, just get mad at this one for now. + iBestRelationship = IRelationship ( pNextEnt ); + iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); + pReturn = pNextEnt; + } + else if ( IRelationship( pNextEnt) == iBestRelationship ) + { + // this entity is disliked just as much as the entity that + // we currently think is the best visible enemy, so we only + // get mad at it if it is closer. + iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); + + if ( iDist <= iNearest ) + { + iNearest = iDist; + iBestRelationship = IRelationship ( pNextEnt ); + pReturn = pNextEnt; + } + } + } + + pNextEnt = pNextEnt->m_pLink; + } + + return pReturn; +} diff --git a/main/source/dlls/multiplay_gamerules.cpp b/main/source/dlls/multiplay_gamerules.cpp index 3a26b518..aa38e682 100644 --- a/main/source/dlls/multiplay_gamerules.cpp +++ b/main/source/dlls/multiplay_gamerules.cpp @@ -1,1607 +1,1607 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" - -#include "skill.h" -#include "game.h" -#include "items.h" -#include "game_shared/voice_gamemgr.h" -#include "mod/AvHServerUtil.h" -#include "common/hltv.h" -#include "mod/AvHNetworkMessages.h" -#include "mod/AvHServerVariables.h" - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; - -extern int g_teamplay; - -std::string GetLogStringForPlayer( edict_t *pEntity ); //defined in client.cpp - -#define ITEM_RESPAWN_TIME 30 -#define WEAPON_RESPAWN_TIME 20 -#define AMMO_RESPAWN_TIME 20 - -// Allow assignment within conditional -#pragma warning (disable: 4706) - -float g_flIntermissionStartTime = 0; - -//CVoiceGameMgr g_VoiceGameMgr; - -class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper -{ -public: - virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) - { - if ( g_teamplay ) - { - if ( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) - { - return false; - } - } - - return true; - } -}; -static CMultiplayGameMgrHelper g_GameMgrHelper; - -//********************************************************* -// Rules for the half-life multiplayer game. -//********************************************************* - -CHalfLifeMultiplay :: CHalfLifeMultiplay() -{ - //g_VoiceGameMgr.Init(&g_GameMgrHelper, gpGlobals->maxClients); - - //RefreshSkillData(); - m_flIntermissionEndTime = 0; - g_flIntermissionStartTime = 0; - - // 11/8/98 - // Modified by YWB: Server .cfg file is now a cvar, so that - // server ops can run multiple game servers, with different server .cfg files, - // from a single installed directory. - // Mapcyclefile is already a cvar. - - // 3/31/99 - // Added lservercfg file cvar, since listen and dedicated servers should not - // share a single config file. (sjb) - if ( IS_DEDICATED_SERVER() ) - { - // dedicated server - char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); - - if ( servercfgfile && servercfgfile[0] ) - { - char szCommand[256]; - - ALERT( at_console, "Executing dedicated server config file\n" ); - sprintf( szCommand, "exec %s\n", servercfgfile ); - SERVER_COMMAND( szCommand ); - } - } - else - { - // listen server - char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); - - if ( lservercfgfile && lservercfgfile[0] ) - { - char szCommand[256]; - - ALERT( at_console, "Executing listen server config file\n" ); - sprintf( szCommand, "exec %s\n", lservercfgfile ); - SERVER_COMMAND( szCommand ); - } - } -} - -BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - //if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) - // return TRUE; - - return CGameRules::ClientCommand(pPlayer, pcmd); -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::RefreshSkillData( void ) -{ -// load all default values - //CGameRules::RefreshSkillData(); - -// override some values for multiplay. - - // suitcharger - gSkillData.suitchargerCapacity = 30; - - // Crowbar whack - gSkillData.plrDmgCrowbar = 25; - - // Glock Round - gSkillData.plrDmg9MM = 12; - - // 357 Round - gSkillData.plrDmg357 = 40; - - // MP5 Round - gSkillData.plrDmgMP5 = 12; - - // M203 grenade - gSkillData.plrDmgM203Grenade = 100; - - // Shotgun buckshot - gSkillData.plrDmgBuckshot = 20;// fewer pellets in deathmatch - - // Crossbow - gSkillData.plrDmgCrossbowClient = 20; - - // RPG - gSkillData.plrDmgRPG = 120; - - // Egon - gSkillData.plrDmgEgonWide = 20; - gSkillData.plrDmgEgonNarrow = 10; - - // Hand Grendade - gSkillData.plrDmgHandGrenade = 100; - - // Satchel Charge - gSkillData.plrDmgSatchel = 120; - - // Tripmine - gSkillData.plrDmgTripmine = 150; - - // hornet - gSkillData.plrDmgHornet = 10; -} - -// longest the intermission can last, in seconds -#define MAX_INTERMISSION_TIME 120 - -extern cvar_t timeleft, fragsleft; - -extern cvar_t mp_chattime; - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: Think ( void ) -{ - //g_VoiceGameMgr.Update(gpGlobals->frametime); - - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - if ( g_fGameOver ) // someone else quit the game already - { - // bounds check - int time = (int)ns_cvar_float( &mp_chattime ); - if ( time < 10 ) - CVAR_SET_STRING( "mp_chattime", "10" ); - else if ( time > MAX_INTERMISSION_TIME ) - CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); - - m_flIntermissionEndTime = g_flIntermissionStartTime + mp_chattime.value; - - // check to see if we should change levels now - if ( m_flIntermissionEndTime < gpGlobals->time ) - { - if ( m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over - || ( ( g_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals->time) ) - ChangeLevel(); // intermission is over - } - - return; - } - - float flTimeLimit = timelimit.value * 60; - float flFragLimit = fraglimit.value; - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) - { - GoToIntermission(); - return; - } - - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any player is over the frag limit - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && pPlayer->pev->frags >= flFragLimit ) - { - GoToIntermission(); - return; - } - - - if ( pPlayer ) - { - remain = flFragLimit - pPlayer->pev->frags; - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if ( frags_remaining != last_frags ) - { - g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); - } - - // Updates once per second - if ( timeleft.value != last_time ) - { - g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsMultiplayer( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsDeathmatch( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsCoOp( void ) -{ - return gpGlobals->coop; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) - { - // that weapon can't deploy anyway. - return FALSE; - } - - if ( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if ( !pPlayer->m_pActiveItem->CanHolster() ) - { - // can't put away the active item. - return FALSE; - } - - if ( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) - { - return TRUE; - } - - return FALSE; -} - -BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - - CBasePlayerItem *pCheck; - CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. - int iBestWeight; - int i; - - iBestWeight = -1;// no weapon lower than -1 can be autoswitched to - pBest = NULL; - - if ( pCurrentWeapon != NULL && !pCurrentWeapon->CanHolster() ) - { - // can't put this gun away right now, so can't switch. - return FALSE; - } - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pCheck = pPlayer->m_rgpPlayerItems[ i ]; - - while ( pCheck ) - { - if ( pCurrentWeapon != NULL && pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) - { - // this weapon is from the same category. - if ( pCheck->CanDeploy() && pCheck->IsUseable()) - { - if ( pPlayer->SwitchWeapon( pCheck ) ) - { - return TRUE; - } - } - } - else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of - { - //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); - // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight - // that the player was using. This will end up leaving the player with his heaviest-weighted - // weapon. - if ( pCheck->CanDeploy() && pCheck->IsUseable()) - { - // if this weapon is useable, flag it as the best - iBestWeight = pCheck->iWeight(); - pBest = pCheck; - } - } - - pCheck = pCheck->m_pNext; - } - } - - // if we make it here, we've checked all the weapons and found no useable - // weapon in the same catagory as the current weapon. - - // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always - // at least get the crowbar, but ya never know. - if ( !pBest ) - { - return FALSE; - } - - pPlayer->SwitchWeapon( pBest ); - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - //g_VoiceGameMgr.ClientConnected(pEntity); - return TRUE; -} - -void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) -{ - // notify other clients of player joining the game - UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", - ( pl->pev->netname && STRING(pl->pev->netname)[0] != 0 ) ? STRING(pl->pev->netname) : "unconnected" ) ); - - UTIL_LogPrintf( "%s entered the game\n", GetLogStringForPlayer( pl->edict() ).c_str() ); - - pl->EffectivePlayerClassChanged(); - - SendMOTDToClient( pl->edict() ); - - // loop through all active players and send their score info to the new client - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - // FIXME: Probably don't need to cast this just to read m_iDeaths - CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); - - if ( plr ) - { - plr->EffectivePlayerClassChanged(); - } - } - - if ( g_fGameOver ) - { - MESSAGE_BEGIN( MSG_ONE, SVC_INTERMISSION, NULL, pl->edict() ); - MESSAGE_END(); - } -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) -{ - if ( pClient ) - { - CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - - if ( pPlayer ) - { - FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); - - UTIL_LogPrintf( "%s disconnected\n", GetLogStringForPlayer( pPlayer->edict() ).c_str() ); - - pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items - } - } -} - - -//========================================================= -//========================================================= -float CHalfLifeMultiplay :: FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - int iFallDamage = (int)falldamage.value; - - switch ( iFallDamage ) - { - case 1://progressive - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; - break; - default: - case 0:// fixed - return 10; - break; - } -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: PlayerThink( CBasePlayer *pPlayer ) -{ - if ( g_fGameOver ) - { - // check for button presses - if ( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) - m_iEndIntermissionButtonHit = TRUE; - - pPlayer->ClearKeys(); - } -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) -{ - BOOL addDefault; - CBaseEntity *pWeaponEntity = NULL; - - pPlayer->pev->weapons |= (1<Touch( pPlayer ); - addDefault = FALSE; - } - - if ( addDefault ) - { - } -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) -{ - return ( aimcrosshair.value != 0 ); -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - DeathNotice( pVictim, pKiller, pInflictor ); - - pVictim->m_iDeaths += 1; - - - FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 ); - CBasePlayer *peKiller = NULL; - CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); - if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) ) - peKiller = (CBasePlayer*)ktmp; - - if ( pVictim->pev == pKiller ) - { - // Already increment deaths, don't need to lose frags also - // killed self - //pKiller->frags -= 1; - } - else if ( ktmp && ktmp->IsPlayer() ) - { - // if a player dies in a deathmatch game and the killer is a client, award the killer some points - pKiller->frags += IPointsForKill( peKiller, pVictim ); - - FireTargets( "game_playerkill", ktmp, ktmp, USE_TOGGLE, 0 ); - } - else - { // killed by the world - pKiller->frags -= 1; - } - - // update the scores - // killed scores - pVictim->EffectivePlayerClassChanged(); - - // killers score, if it's a player - CBaseEntity *ep = CBaseEntity::Instance( pKiller ); - if ( ep && ep->Classify() == CLASS_PLAYER ) - { - CBasePlayer *PK = (CBasePlayer*)ep; - - PK->EffectivePlayerClassChanged(); - - // let the killer paint another decal as soon as he'd like. - PK->m_flNextDecalTime = gpGlobals->time; - } - -// Game rules shouldn't know about specific weapons! Removed this because AvH doesn't have satchel charges. -//#ifndef HLDEMO_BUILD -// if ( pVictim->HasNamedPlayerItem("weapon_satchel") ) -// { -// DeactivateSatchels( pVictim ); -// } -//#endif -} - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - // Work out what killed the player, and send a message to all clients about it - CBaseEntity *Killer = CBaseEntity::Instance( pKiller ); - - const char *killer_weapon_name = "world"; // by default, the player is killed by the world - int killer_index = 0; - - // Hack to fix name change - char *tau = "tau_cannon"; - char *gluon = "gluon gun"; - - if ( pKiller->flags & FL_CLIENT ) - { - killer_index = ENTINDEX(ENT(pKiller)); - - if ( pevInflictor ) - { - if ( pevInflictor == pKiller ) - { - // If the inflictor is the killer, then it must be their current weapon doing the damage - CBasePlayer *pPlayer = (CBasePlayer*)CBaseEntity::Instance( pKiller ); - - if ( pPlayer->m_pActiveItem ) - { - killer_weapon_name = pPlayer->m_pActiveItem->pszName(); - } - } - else - { - killer_weapon_name = STRING( pevInflictor->classname ); // it's just that easy - } - } - } - else - { - killer_weapon_name = STRING( pevInflictor->classname ); - } - - // strip the monster_* or weapon_* from the inflictor's classname - if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) - killer_weapon_name += 7; - else if ( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) - killer_weapon_name += 8; - else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) - killer_weapon_name += 5; - string tmpstr(killer_weapon_name); - NetMsg_DeathMsg( killer_index, ENTINDEX( pVictim->edict() ), tmpstr); - - // replace the code names with the 'real' names - if ( !strcmp( killer_weapon_name, "egon" ) ) - killer_weapon_name = gluon; - else if ( !strcmp( killer_weapon_name, "gauss" ) ) - killer_weapon_name = tau; - - if ( pVictim->pev == pKiller ) //killed self - { - UTIL_LogPrintf( "%s committed suicide with \"%s\"\n", GetLogStringForPlayer( pVictim->edict() ).c_str(), killer_weapon_name); - } - else if ( pKiller->flags & FL_CLIENT ) //killed by client - { - UTIL_LogPrintf( "%s killed %s with \"%s\"\n", - GetLogStringForPlayer( ENT(pKiller) ).c_str(), - GetLogStringForPlayer( pVictim->edict() ).c_str(), - killer_weapon_name - ); - } - else //killed by world - { - UTIL_LogPrintf( "%s committed suicide with \"%s\" (world)\n", GetLogStringForPlayer( pVictim->edict() ).c_str(), killer_weapon_name); - } - - MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); - WRITE_BYTE(DIRECTOR_MESSAGE_SIZE); - WRITE_BYTE(DRC_CMD_EVENT); // player killed - WRITE_SHORT( ENTINDEX(pVictim->edict()) ); // index number of primary entity - if (pevInflictor) - WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity - else - WRITE_SHORT( ENTINDEX(ENT(pKiller)) ); // index number of secondary entity - WRITE_LONG( 7 | DRC_FLAG_DRAMATIC); // eventflags (priority and flags) - MESSAGE_END(); - -// Print a standard message - // TODO: make this go direct to console - return; // just remove for now -/* - char szText[ 128 ]; - - if ( pKiller->flags & FL_MONSTER ) - { - // killed by a monster - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was killed by a monster.\n" ); - return; - } - - if ( pKiller == pVictim->pev ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " commited suicide.\n" ); - } - else if ( pKiller->flags & FL_CLIENT ) - { - strcpy ( szText, STRING( pKiller->netname ) ); - - strcat( szText, " : " ); - strcat( szText, killer_weapon_name ); - strcat( szText, " : " ); - - strcat ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, "\n" ); - } - else if ( FClassnameIs ( pKiller, "worldspawn" ) ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " fell or drowned or something.\n" ); - } - else if ( pKiller->solid == SOLID_BSP ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was mooshed.\n" ); - } - else - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " died mysteriously.\n" ); - } - - UTIL_ClientPrintAll( szText ); -*/ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) -{ - if ( weaponstay.value > 0 ) - { - // make sure it's only certain weapons - if ( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) - { - return gpGlobals->time + 0; // weapon respawns almost instantly - } - } - - return gpGlobals->time + WEAPON_RESPAWN_TIME; -} - -// when we are within this close to running out of entities, items -// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn -#define ENTITY_INTOLERANCE 100 - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeMultiplay :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) -{ - if ( pWeapon && pWeapon->m_iId && (pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) - { - if ( NUMBER_OF_ENTITIES() < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) ) - return 0; - - // we're past the entity tolerance level, so delay the respawn - return FlWeaponRespawnTime( pWeapon ); - } - - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeMultiplay :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) -{ - if ( pWeapon->pev->spawnflags & SF_NORESPAWN ) - { - return GR_WEAPON_RESPAWN_NO; - } - - return GR_WEAPON_RESPAWN_YES; -} - -//========================================================= -// CanHaveWeapon - returns FALSE if the player is not allowed -// to pick up this weapon -//========================================================= -BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) -{ - if ( weaponstay.value > 0 ) - { - if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); - - // check if the player already has this weapon - for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - CBasePlayerItem *it = pPlayer->m_rgpPlayerItems[i]; - - while ( it != NULL ) - { - if ( it->m_iId == pItem->m_iId ) - { - return FALSE; - } - - it = it->m_pNext; - } - } - } - - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::ItemShouldRespawn( CItem *pItem ) -{ - if ( pItem->pev->spawnflags & SF_NORESPAWN ) - { - return GR_ITEM_RESPAWN_NO; - } - - return GR_ITEM_RESPAWN_YES; -} - - -//========================================================= -// At what time in the future may this Item respawn? -//========================================================= -float CHalfLifeMultiplay::FlItemRespawnTime( CItem *pItem ) -{ - return gpGlobals->time + ITEM_RESPAWN_TIME; -} - -//========================================================= -// Where should this item respawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeMultiplay::VecItemRespawnSpot( CItem *pItem ) -{ - return pItem->pev->origin; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ -// if ( pEntity->pev->flags & FL_MONSTER ) -// return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) -{ - if ( pAmmo->pev->spawnflags & SF_NORESPAWN ) - { - return GR_AMMO_RESPAWN_NO; - } - - return GR_AMMO_RESPAWN_YES; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) -{ - return gpGlobals->time + AMMO_RESPAWN_TIME; -} - -//========================================================= -//========================================================= -Vector CHalfLifeMultiplay::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) -{ - return pAmmo->pev->origin; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay::FlHealthChargerRechargeTime( void ) -{ - return 60; -} - - -float CHalfLifeMultiplay::FlHEVChargerRechargeTime( void ) -{ - return 30; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_ACTIVE; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_ACTIVE; -} - -edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ - edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); - if ( IsMultiplayer() && !FNullEnt(pentSpawnSpot) && (pentSpawnSpot->v.target)) - { - FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); - } - - return pentSpawnSpot; -} - - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life deathmatch has only enemies - return GR_NOTTEAMMATE; -} - -BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) -{ - if ( g_footsteps && g_footsteps->value == 0 ) - return FALSE; - - if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > pl->GetMaxWalkSpeed() ) - return TRUE; // only make step sounds in multiplayer if the player is moving fast enough - - return FALSE; -} - -BOOL CHalfLifeMultiplay :: FAllowFlashlight( void ) -{ - return flashlight.value != 0; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) -{ - return ( allowmonsters.value != 0 ); -} - -//========================================================= -//======== CHalfLifeMultiplay private functions =========== -#define INTERMISSION_TIME 6 - -void CHalfLifeMultiplay :: GoToIntermission( void ) -{ - if ( g_fGameOver ) - return; // intermission has already been triggered, so ignore. - - MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); - MESSAGE_END(); - - // bounds check - int time = (int)ns_cvar_float( &mp_chattime ); - if ( time < 10 ) - CVAR_SET_STRING( "mp_chattime", "10" ); - else if ( time > MAX_INTERMISSION_TIME ) - CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); - - m_flIntermissionEndTime = gpGlobals->time + ( (int)mp_chattime.value ); - g_flIntermissionStartTime = gpGlobals->time; - - g_fGameOver = TRUE; - m_iEndIntermissionButtonHit = FALSE; -} - -#define MAX_RULE_BUFFER 1024 - -typedef struct mapcycle_item_s -{ - struct mapcycle_item_s *next; - - char mapname[ 32 ]; - int minplayers, maxplayers; - char rulebuffer[ MAX_RULE_BUFFER ]; -} mapcycle_item_t; - -typedef struct mapcycle_s -{ - struct mapcycle_item_s *items; - struct mapcycle_item_s *next_item; -} mapcycle_t; - -/* -============== -DestroyMapCycle - -Clean up memory used by mapcycle when switching it -============== -*/ -void DestroyMapCycle( mapcycle_t *cycle ) -{ - mapcycle_item_t *p, *n, *start; - p = cycle->items; - if ( p ) - { - start = p; - p = p->next; - while ( p != start ) - { - n = p->next; - delete p; - p = n; - } - - delete cycle->items; - } - cycle->items = NULL; - cycle->next_item = NULL; -} - -static char com_token[ 1500 ]; - -/* -============== -COM_Parse - -Parse a token out of a string -============== -*/ -char *COM_Parse (char *data) -{ - int c; - int len; - - len = 0; - com_token[0] = 0; - - if (!data) - return NULL; - -// skip whitespace -skipwhite: - while ( (c = *data) <= ' ') - { - if (c == 0) - return NULL; // end of file; - data++; - } - -// skip // comments - if (c=='/' && data[1] == '/') - { - while (*data && *data != '\n') - data++; - goto skipwhite; - } - - -// handle quoted strings specially - if (c == '\"') - { - data++; - while (1) - { - c = *data++; - if (c=='\"' || !c) - { - com_token[len] = 0; - return data; - } - com_token[len] = c; - len++; - } - } - -// parse single characters - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) - { - com_token[len] = c; - len++; - com_token[len] = 0; - return data+1; - } - -// parse a regular word - do - { - com_token[len] = c; - data++; - len++; - c = *data; - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) - break; - } while (c>32); - - com_token[len] = 0; - return data; -} - -/* -============== -COM_TokenWaiting - -Returns 1 if additional data is waiting to be processed on this line -============== -*/ -int COM_TokenWaiting( char *buffer ) -{ - char *p; - - p = buffer; - while ( *p && *p!='\n') - { - if ( !isspace( *p ) || isalnum( *p ) ) - return 1; - - p++; - } - - return 0; -} - -void GetMapNamesFromMapCycle(StringList& outMapNameList) -{ - char* mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); - ASSERT( mapcfile != NULL ); - - char szBuffer[ MAX_RULE_BUFFER ]; - char szMap[ 32 ]; - int length; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( mapcfile, &length ); - int hasbuffer; - mapcycle_item_s *newlist = NULL; - - if ( pFileList && length ) - { - // the first map name in the file becomes the default - while ( 1 ) - { - hasbuffer = 0; - memset( szBuffer, 0, MAX_RULE_BUFFER ); - - pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) <= 0 ) - break; - - strcpy( szMap, com_token ); - - // Any more tokens on this line? - if ( COM_TokenWaiting( pFileList ) ) - { - pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) > 0 ) - { - hasbuffer = 1; - strcpy( szBuffer, com_token ); - } - } - - // Check map - if ( IS_MAP_VALID( szMap ) ) - { - outMapNameList.push_back( szMap ); - } - } - - FREE_FILE( aFileList ); - } -} - - -/* -============== -ReloadMapCycleFile - - -Parses mapcycle.txt file into mapcycle_t structure -============== -*/ -int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) -{ - char szBuffer[ MAX_RULE_BUFFER ]; - char szMap[ 32 ]; - int length; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); - int hasbuffer; - mapcycle_item_s *item, *newlist = NULL, *next; - - if ( pFileList && length ) - { - // the first map name in the file becomes the default - while ( 1 ) - { - hasbuffer = 0; - memset( szBuffer, 0, MAX_RULE_BUFFER ); - - pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) <= 0 ) - break; - - strcpy( szMap, com_token ); - - // Any more tokens on this line? - if ( COM_TokenWaiting( pFileList ) ) - { - pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) > 0 ) - { - hasbuffer = 1; - strcpy( szBuffer, com_token ); - } - } - - // Check map - if ( IS_MAP_VALID( szMap ) ) - { - // Create entry - char *s; - - item = new mapcycle_item_s; - - strcpy( item->mapname, szMap ); - - item->minplayers = 0; - item->maxplayers = 0; - - memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); - - if ( hasbuffer ) - { - s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); - if ( s && s[0] ) - { - item->minplayers = atoi( s ); - item->minplayers = max( item->minplayers, 0 ); - item->minplayers = min( item->minplayers, gpGlobals->maxClients ); - } - s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); - if ( s && s[0] ) - { - item->maxplayers = atoi( s ); - item->maxplayers = max( item->maxplayers, 0 ); - item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); - } - - // Remove keys - // - g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); - g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); - - strcpy( item->rulebuffer, szBuffer ); - } - - item->next = cycle->items; - cycle->items = item; - } - else - { - ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); - } - - } - - FREE_FILE( aFileList ); - } - - // Fixup circular list pointer - item = cycle->items; - - // Reverse it to get original order - while ( item ) - { - next = item->next; - item->next = newlist; - newlist = item; - item = next; - } - cycle->items = newlist; - item = cycle->items; - - // Didn't parse anything - if ( !item ) - { - return 0; - } - - while ( item->next ) - { - item = item->next; - } - item->next = cycle->items; - - cycle->next_item = item->next; - - return 1; -} - -/* -============== -CountPlayers - -Determine the current # of active players on the server for map cycling logic -============== -*/ -int CountPlayers( void ) -{ - int num = 0; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); - - if ( pEnt ) - { - num = num + 1; - } - } - - return num; -} - -/* -============== -ExtractCommandString - -Parse commands/key value pairs to issue right after map xxx command is issued on server - level transition -============== -*/ -void ExtractCommandString( char *s, char *szCommand ) -{ - // Now make rules happen - char pkey[512]; - char value[512]; // use two buffers so compares - // work without stomping on each other - char *o; - - if ( *s == '\\' ) - s++; - - while (1) - { - o = pkey; - while ( *s != '\\' ) - { - if ( !*s ) - return; - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - - while (*s != '\\' && *s) - { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - - strcat( szCommand, pkey ); - if ( strlen( value ) > 0 ) - { - strcat( szCommand, " " ); - strcat( szCommand, value ); - } - strcat( szCommand, "\n" ); - - if (!*s) - return; - s++; - } -} - -/* -============== -ChangeLevel - -Server is changing to a new level, check mapcycle.txt for map name and setup info -============== -*/ -void CHalfLifeMultiplay :: ChangeLevel( void ) -{ - static char szPreviousMapCycleFile[ 256 ]; - static mapcycle_t mapcycle; - - char szNextMap[32]; - char szFirstMapInList[32]; - char szCommands[ 1500 ]; - char szRules[ 1500 ]; - int minplayers = 0, maxplayers = 0; - strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 - - int curplayers; - BOOL do_cycle = TRUE; - - // find the map to change to - char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); - ASSERT( mapcfile != NULL ); - - szCommands[ 0 ] = '\0'; - szRules[ 0 ] = '\0'; - - curplayers = CountPlayers(); - - // Has the map cycle filename changed? - if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) - { - strcpy( szPreviousMapCycleFile, mapcfile ); - - DestroyMapCycle( &mapcycle ); - - if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) - { - ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); - do_cycle = FALSE; - } - } - - if ( do_cycle && mapcycle.items ) - { - BOOL keeplooking = FALSE; - BOOL found = FALSE; - mapcycle_item_s *item; - - // Assume current map - strcpy( szNextMap, STRING(gpGlobals->mapname) ); - strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); - - // Traverse list - for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) - { - keeplooking = FALSE; - - ASSERT( item != NULL ); - - if ( item->minplayers != 0 ) - { - if ( curplayers >= item->minplayers ) - { - found = TRUE; - minplayers = item->minplayers; - } - else - { - keeplooking = TRUE; - } - } - - if ( item->maxplayers != 0 ) - { - if ( curplayers <= item->maxplayers ) - { - found = TRUE; - maxplayers = item->maxplayers; - } - else - { - keeplooking = TRUE; - } - } - - if ( keeplooking ) - continue; - - found = TRUE; - break; - } - - if ( !found ) - { - item = mapcycle.next_item; - } - - // Increment next item pointer - mapcycle.next_item = item->next; - - // Perform logic on current item - strcpy( szNextMap, item->mapname ); - - ExtractCommandString( item->rulebuffer, szCommands ); - strcpy( szRules, item->rulebuffer ); - } - - if ( !IS_MAP_VALID(szNextMap) ) - { - strcpy( szNextMap, szFirstMapInList ); - } - - g_fGameOver = TRUE; - - ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); - if ( minplayers || maxplayers ) - { - ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); - } - if ( strlen( szRules ) > 0 ) - { - ALERT( at_console, "RULES: %s\n", szRules ); - } - - CHANGE_LEVEL( szNextMap, NULL ); - if ( strlen( szCommands ) > 0 ) - { - SERVER_COMMAND( szCommands ); - } -} - -#define MAX_MOTD_CHUNK 60 -#define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4) - -void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) -{ - // read from the MOTD.txt file - int length, char_count = 0; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( (char *)CVAR_GET_STRING( "motdfile" ), &length ); - - // send the server name - NetMsg_ServerName( &client->v, string( CVAR_GET_STRING( "hostname" ) ) ); - - // Send the message of the day - // read it chunk-by-chunk, and send it in parts - - while ( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) - { - char chunk[MAX_MOTD_CHUNK+1]; - - if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) - { - strcpy( chunk, pFileList ); - } - else - { - strncpy( chunk, pFileList, MAX_MOTD_CHUNK ); - chunk[MAX_MOTD_CHUNK] = 0; // strncpy doesn't always append the null terminator - } - - char_count += strlen( chunk ); - if ( char_count < MAX_MOTD_LENGTH ) - pFileList = aFileList + char_count; - else - *pFileList = 0; - - NetMsg_MOTD( &client->v, *pFileList ? false : true, string( chunk ) ); - } - - FREE_FILE( aFileList ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// teamplay_gamerules.cpp +// +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +#include "skill.h" +#include "game.h" +#include "items.h" +#include "game_shared/voice_gamemgr.h" +#include "mod/AvHServerUtil.h" +#include "common/hltv.h" +#include "mod/AvHNetworkMessages.h" +#include "mod/AvHServerVariables.h" + +extern DLL_GLOBAL CGameRules *g_pGameRules; +extern DLL_GLOBAL BOOL g_fGameOver; + +extern int g_teamplay; + +std::string GetLogStringForPlayer( edict_t *pEntity ); //defined in client.cpp + +#define ITEM_RESPAWN_TIME 30 +#define WEAPON_RESPAWN_TIME 20 +#define AMMO_RESPAWN_TIME 20 + +// Allow assignment within conditional +#pragma warning (disable: 4706) + +float g_flIntermissionStartTime = 0; + +//CVoiceGameMgr g_VoiceGameMgr; + +class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper +{ +public: + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) + { + if ( g_teamplay ) + { + if ( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) + { + return false; + } + } + + return true; + } +}; +static CMultiplayGameMgrHelper g_GameMgrHelper; + +//********************************************************* +// Rules for the half-life multiplayer game. +//********************************************************* + +CHalfLifeMultiplay :: CHalfLifeMultiplay() +{ + //g_VoiceGameMgr.Init(&g_GameMgrHelper, gpGlobals->maxClients); + + //RefreshSkillData(); + m_flIntermissionEndTime = 0; + g_flIntermissionStartTime = 0; + + // 11/8/98 + // Modified by YWB: Server .cfg file is now a cvar, so that + // server ops can run multiple game servers, with different server .cfg files, + // from a single installed directory. + // Mapcyclefile is already a cvar. + + // 3/31/99 + // Added lservercfg file cvar, since listen and dedicated servers should not + // share a single config file. (sjb) + if ( IS_DEDICATED_SERVER() ) + { + // dedicated server + char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + + if ( servercfgfile && servercfgfile[0] ) + { + char szCommand[256]; + + ALERT( at_console, "Executing dedicated server config file\n" ); + sprintf( szCommand, "exec %s\n", servercfgfile ); + SERVER_COMMAND( szCommand ); + } + } + else + { + // listen server + char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); + + if ( lservercfgfile && lservercfgfile[0] ) + { + char szCommand[256]; + + ALERT( at_console, "Executing listen server config file\n" ); + sprintf( szCommand, "exec %s\n", lservercfgfile ); + SERVER_COMMAND( szCommand ); + } + } +} + +BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) +{ + //if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + // return TRUE; + + return CGameRules::ClientCommand(pPlayer, pcmd); +} + +//========================================================= +//========================================================= +void CHalfLifeMultiplay::RefreshSkillData( void ) +{ +// load all default values + //CGameRules::RefreshSkillData(); + +// override some values for multiplay. + + // suitcharger + gSkillData.suitchargerCapacity = 30; + + // Crowbar whack + gSkillData.plrDmgCrowbar = 25; + + // Glock Round + gSkillData.plrDmg9MM = 12; + + // 357 Round + gSkillData.plrDmg357 = 40; + + // MP5 Round + gSkillData.plrDmgMP5 = 12; + + // M203 grenade + gSkillData.plrDmgM203Grenade = 100; + + // Shotgun buckshot + gSkillData.plrDmgBuckshot = 20;// fewer pellets in deathmatch + + // Crossbow + gSkillData.plrDmgCrossbowClient = 20; + + // RPG + gSkillData.plrDmgRPG = 120; + + // Egon + gSkillData.plrDmgEgonWide = 20; + gSkillData.plrDmgEgonNarrow = 10; + + // Hand Grendade + gSkillData.plrDmgHandGrenade = 100; + + // Satchel Charge + gSkillData.plrDmgSatchel = 120; + + // Tripmine + gSkillData.plrDmgTripmine = 150; + + // hornet + gSkillData.plrDmgHornet = 10; +} + +// longest the intermission can last, in seconds +#define MAX_INTERMISSION_TIME 120 + +extern cvar_t timeleft, fragsleft; + +extern cvar_t mp_chattime; + +//========================================================= +//========================================================= +void CHalfLifeMultiplay :: Think ( void ) +{ + //g_VoiceGameMgr.Update(gpGlobals->frametime); + + ///// Check game rules ///// + static int last_frags; + static int last_time; + + int frags_remaining = 0; + int time_remaining = 0; + + if ( g_fGameOver ) // someone else quit the game already + { + // bounds check + int time = (int)ns_cvar_float( &mp_chattime ); + if ( time < 10 ) + CVAR_SET_STRING( "mp_chattime", "10" ); + else if ( time > MAX_INTERMISSION_TIME ) + CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); + + m_flIntermissionEndTime = g_flIntermissionStartTime + mp_chattime.value; + + // check to see if we should change levels now + if ( m_flIntermissionEndTime < gpGlobals->time ) + { + if ( m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over + || ( ( g_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals->time) ) + ChangeLevel(); // intermission is over + } + + return; + } + + float flTimeLimit = timelimit.value * 60; + float flFragLimit = fraglimit.value; + + time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + + if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) + { + GoToIntermission(); + return; + } + + if ( flFragLimit ) + { + int bestfrags = 9999; + int remain; + + // check if any player is over the frag limit + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); + + if ( pPlayer && pPlayer->pev->frags >= flFragLimit ) + { + GoToIntermission(); + return; + } + + + if ( pPlayer ) + { + remain = flFragLimit - pPlayer->pev->frags; + if ( remain < bestfrags ) + { + bestfrags = remain; + } + } + + } + frags_remaining = bestfrags; + } + + // Updates when frags change + if ( frags_remaining != last_frags ) + { + g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); + } + + // Updates once per second + if ( timeleft.value != last_time ) + { + g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); + } + + last_frags = frags_remaining; + last_time = time_remaining; +} + + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::IsMultiplayer( void ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::IsDeathmatch( void ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::IsCoOp( void ) +{ + return gpGlobals->coop; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ + if ( !pWeapon->CanDeploy() ) + { + // that weapon can't deploy anyway. + return FALSE; + } + + if ( !pPlayer->m_pActiveItem ) + { + // player doesn't have an active item! + return TRUE; + } + + if ( !pPlayer->m_pActiveItem->CanHolster() ) + { + // can't put away the active item. + return FALSE; + } + + if ( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) + { + return TRUE; + } + + return FALSE; +} + +BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +{ + + CBasePlayerItem *pCheck; + CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. + int iBestWeight; + int i; + + iBestWeight = -1;// no weapon lower than -1 can be autoswitched to + pBest = NULL; + + if ( pCurrentWeapon != NULL && !pCurrentWeapon->CanHolster() ) + { + // can't put this gun away right now, so can't switch. + return FALSE; + } + + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + pCheck = pPlayer->m_rgpPlayerItems[ i ]; + + while ( pCheck ) + { + if ( pCurrentWeapon != NULL && pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) + { + // this weapon is from the same category. + if ( pCheck->CanDeploy() && pCheck->IsUseable()) + { + if ( pPlayer->SwitchWeapon( pCheck ) ) + { + return TRUE; + } + } + } + else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of + { + //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); + // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight + // that the player was using. This will end up leaving the player with his heaviest-weighted + // weapon. + if ( pCheck->CanDeploy() && pCheck->IsUseable()) + { + // if this weapon is useable, flag it as the best + iBestWeight = pCheck->iWeight(); + pBest = pCheck; + } + } + + pCheck = pCheck->m_pNext; + } + } + + // if we make it here, we've checked all the weapons and found no useable + // weapon in the same catagory as the current weapon. + + // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always + // at least get the crowbar, but ya never know. + if ( !pBest ) + { + return FALSE; + } + + pPlayer->SwitchWeapon( pBest ); + + return TRUE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +{ + //g_VoiceGameMgr.ClientConnected(pEntity); + return TRUE; +} + +void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) +{ + // notify other clients of player joining the game + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", + ( pl->pev->netname && STRING(pl->pev->netname)[0] != 0 ) ? STRING(pl->pev->netname) : "unconnected" ) ); + + UTIL_LogPrintf( "%s entered the game\n", GetLogStringForPlayer( pl->edict() ).c_str() ); + + pl->EffectivePlayerClassChanged(); + + SendMOTDToClient( pl->edict() ); + + // loop through all active players and send their score info to the new client + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + // FIXME: Probably don't need to cast this just to read m_iDeaths + CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); + + if ( plr ) + { + plr->EffectivePlayerClassChanged(); + } + } + + if ( g_fGameOver ) + { + MESSAGE_BEGIN( MSG_ONE, SVC_INTERMISSION, NULL, pl->edict() ); + MESSAGE_END(); + } +} + +//========================================================= +//========================================================= +void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) +{ + if ( pClient ) + { + CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); + + if ( pPlayer ) + { + FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); + + UTIL_LogPrintf( "%s disconnected\n", GetLogStringForPlayer( pPlayer->edict() ).c_str() ); + + pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items + } + } +} + + +//========================================================= +//========================================================= +float CHalfLifeMultiplay :: FlPlayerFallDamage( CBasePlayer *pPlayer ) +{ + int iFallDamage = (int)falldamage.value; + + switch ( iFallDamage ) + { + case 1://progressive + pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; + return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; + break; + default: + case 0:// fixed + return 10; + break; + } +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +void CHalfLifeMultiplay :: PlayerThink( CBasePlayer *pPlayer ) +{ + if ( g_fGameOver ) + { + // check for button presses + if ( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) + m_iEndIntermissionButtonHit = TRUE; + + pPlayer->ClearKeys(); + } +} + +//========================================================= +//========================================================= +void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) +{ + BOOL addDefault; + CBaseEntity *pWeaponEntity = NULL; + + pPlayer->pev->weapons |= (1<Touch( pPlayer ); + addDefault = FALSE; + } + + if ( addDefault ) + { + } +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay :: FPlayerCanRespawn( CBasePlayer *pPlayer ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +float CHalfLifeMultiplay :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) +{ + return gpGlobals->time;//now! +} + +BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) +{ + return ( aimcrosshair.value != 0 ); +} + +//========================================================= +// IPointsForKill - how many points awarded to anyone +// that kills this player? +//========================================================= +int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +{ + return 1; +} + + +//========================================================= +// PlayerKilled - someone/something killed this player +//========================================================= +void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +{ + DeathNotice( pVictim, pKiller, pInflictor ); + + pVictim->m_iDeaths += 1; + + + FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 ); + CBasePlayer *peKiller = NULL; + CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); + if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) ) + peKiller = (CBasePlayer*)ktmp; + + if ( pVictim->pev == pKiller ) + { + // Already increment deaths, don't need to lose frags also + // killed self + //pKiller->frags -= 1; + } + else if ( ktmp && ktmp->IsPlayer() ) + { + // if a player dies in a deathmatch game and the killer is a client, award the killer some points + pKiller->frags += IPointsForKill( peKiller, pVictim ); + + FireTargets( "game_playerkill", ktmp, ktmp, USE_TOGGLE, 0 ); + } + else + { // killed by the world + pKiller->frags -= 1; + } + + // update the scores + // killed scores + pVictim->EffectivePlayerClassChanged(); + + // killers score, if it's a player + CBaseEntity *ep = CBaseEntity::Instance( pKiller ); + if ( ep && ep->Classify() == CLASS_PLAYER ) + { + CBasePlayer *PK = (CBasePlayer*)ep; + + PK->EffectivePlayerClassChanged(); + + // let the killer paint another decal as soon as he'd like. + PK->m_flNextDecalTime = gpGlobals->time; + } + +// Game rules shouldn't know about specific weapons! Removed this because AvH doesn't have satchel charges. +//#ifndef HLDEMO_BUILD +// if ( pVictim->HasNamedPlayerItem("weapon_satchel") ) +// { +// DeactivateSatchels( pVictim ); +// } +//#endif +} + +//========================================================= +// Deathnotice. +//========================================================= +void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) +{ + // Work out what killed the player, and send a message to all clients about it + CBaseEntity *Killer = CBaseEntity::Instance( pKiller ); + + const char *killer_weapon_name = "world"; // by default, the player is killed by the world + int killer_index = 0; + + // Hack to fix name change + char *tau = "tau_cannon"; + char *gluon = "gluon gun"; + + if ( pKiller->flags & FL_CLIENT ) + { + killer_index = ENTINDEX(ENT(pKiller)); + + if ( pevInflictor ) + { + if ( pevInflictor == pKiller ) + { + // If the inflictor is the killer, then it must be their current weapon doing the damage + CBasePlayer *pPlayer = (CBasePlayer*)CBaseEntity::Instance( pKiller ); + + if ( pPlayer->m_pActiveItem ) + { + killer_weapon_name = pPlayer->m_pActiveItem->pszName(); + } + } + else + { + killer_weapon_name = STRING( pevInflictor->classname ); // it's just that easy + } + } + } + else + { + killer_weapon_name = STRING( pevInflictor->classname ); + } + + // strip the monster_* or weapon_* from the inflictor's classname + if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) + killer_weapon_name += 7; + else if ( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) + killer_weapon_name += 8; + else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) + killer_weapon_name += 5; + string tmpstr(killer_weapon_name); + NetMsg_DeathMsg( killer_index, ENTINDEX( pVictim->edict() ), tmpstr); + + // replace the code names with the 'real' names + if ( !strcmp( killer_weapon_name, "egon" ) ) + killer_weapon_name = gluon; + else if ( !strcmp( killer_weapon_name, "gauss" ) ) + killer_weapon_name = tau; + + if ( pVictim->pev == pKiller ) //killed self + { + UTIL_LogPrintf( "%s committed suicide with \"%s\"\n", GetLogStringForPlayer( pVictim->edict() ).c_str(), killer_weapon_name); + } + else if ( pKiller->flags & FL_CLIENT ) //killed by client + { + UTIL_LogPrintf( "%s killed %s with \"%s\"\n", + GetLogStringForPlayer( ENT(pKiller) ).c_str(), + GetLogStringForPlayer( pVictim->edict() ).c_str(), + killer_weapon_name + ); + } + else //killed by world + { + UTIL_LogPrintf( "%s committed suicide with \"%s\" (world)\n", GetLogStringForPlayer( pVictim->edict() ).c_str(), killer_weapon_name); + } + + MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); + WRITE_BYTE(DIRECTOR_MESSAGE_SIZE); + WRITE_BYTE(DRC_CMD_EVENT); // player killed + WRITE_SHORT( ENTINDEX(pVictim->edict()) ); // index number of primary entity + if (pevInflictor) + WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity + else + WRITE_SHORT( ENTINDEX(ENT(pKiller)) ); // index number of secondary entity + WRITE_LONG( 7 | DRC_FLAG_DRAMATIC); // eventflags (priority and flags) + MESSAGE_END(); + +// Print a standard message + // TODO: make this go direct to console + return; // just remove for now +/* + char szText[ 128 ]; + + if ( pKiller->flags & FL_MONSTER ) + { + // killed by a monster + strcpy ( szText, STRING( pVictim->pev->netname ) ); + strcat ( szText, " was killed by a monster.\n" ); + return; + } + + if ( pKiller == pVictim->pev ) + { + strcpy ( szText, STRING( pVictim->pev->netname ) ); + strcat ( szText, " commited suicide.\n" ); + } + else if ( pKiller->flags & FL_CLIENT ) + { + strcpy ( szText, STRING( pKiller->netname ) ); + + strcat( szText, " : " ); + strcat( szText, killer_weapon_name ); + strcat( szText, " : " ); + + strcat ( szText, STRING( pVictim->pev->netname ) ); + strcat ( szText, "\n" ); + } + else if ( FClassnameIs ( pKiller, "worldspawn" ) ) + { + strcpy ( szText, STRING( pVictim->pev->netname ) ); + strcat ( szText, " fell or drowned or something.\n" ); + } + else if ( pKiller->solid == SOLID_BSP ) + { + strcpy ( szText, STRING( pVictim->pev->netname ) ); + strcat ( szText, " was mooshed.\n" ); + } + else + { + strcpy ( szText, STRING( pVictim->pev->netname ) ); + strcat ( szText, " died mysteriously.\n" ); + } + + UTIL_ClientPrintAll( szText ); +*/ +} + +//========================================================= +// PlayerGotWeapon - player has grabbed a weapon that was +// sitting in the world +//========================================================= +void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ +} + +//========================================================= +// FlWeaponRespawnTime - what is the time in the future +// at which this weapon may spawn? +//========================================================= +float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) +{ + if ( weaponstay.value > 0 ) + { + // make sure it's only certain weapons + if ( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) + { + return gpGlobals->time + 0; // weapon respawns almost instantly + } + } + + return gpGlobals->time + WEAPON_RESPAWN_TIME; +} + +// when we are within this close to running out of entities, items +// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn +#define ENTITY_INTOLERANCE 100 + +//========================================================= +// FlWeaponRespawnTime - Returns 0 if the weapon can respawn +// now, otherwise it returns the time at which it can try +// to spawn again. +//========================================================= +float CHalfLifeMultiplay :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) +{ + if ( pWeapon && pWeapon->m_iId && (pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) + { + if ( NUMBER_OF_ENTITIES() < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) ) + return 0; + + // we're past the entity tolerance level, so delay the respawn + return FlWeaponRespawnTime( pWeapon ); + } + + return 0; +} + +//========================================================= +// VecWeaponRespawnSpot - where should this weapon spawn? +// Some game variations may choose to randomize spawn locations +//========================================================= +Vector CHalfLifeMultiplay :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) +{ + return pWeapon->pev->origin; +} + +//========================================================= +// WeaponShouldRespawn - any conditions inhibiting the +// respawning of this weapon? +//========================================================= +int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) +{ + if ( pWeapon->pev->spawnflags & SF_NORESPAWN ) + { + return GR_WEAPON_RESPAWN_NO; + } + + return GR_WEAPON_RESPAWN_YES; +} + +//========================================================= +// CanHaveWeapon - returns FALSE if the player is not allowed +// to pick up this weapon +//========================================================= +BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) +{ + if ( weaponstay.value > 0 ) + { + if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) + return CGameRules::CanHavePlayerItem( pPlayer, pItem ); + + // check if the player already has this weapon + for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + CBasePlayerItem *it = pPlayer->m_rgpPlayerItems[i]; + + while ( it != NULL ) + { + if ( it->m_iId == pItem->m_iId ) + { + return FALSE; + } + + it = it->m_pNext; + } + } + } + + return CGameRules::CanHavePlayerItem( pPlayer, pItem ); +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +void CHalfLifeMultiplay::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) +{ +} + +//========================================================= +//========================================================= +int CHalfLifeMultiplay::ItemShouldRespawn( CItem *pItem ) +{ + if ( pItem->pev->spawnflags & SF_NORESPAWN ) + { + return GR_ITEM_RESPAWN_NO; + } + + return GR_ITEM_RESPAWN_YES; +} + + +//========================================================= +// At what time in the future may this Item respawn? +//========================================================= +float CHalfLifeMultiplay::FlItemRespawnTime( CItem *pItem ) +{ + return gpGlobals->time + ITEM_RESPAWN_TIME; +} + +//========================================================= +// Where should this item respawn? +// Some game variations may choose to randomize spawn locations +//========================================================= +Vector CHalfLifeMultiplay::VecItemRespawnSpot( CItem *pItem ) +{ + return pItem->pev->origin; +} + +//========================================================= +//========================================================= +void CHalfLifeMultiplay::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) +{ +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) +{ +// if ( pEntity->pev->flags & FL_MONSTER ) +// return FALSE; + + return TRUE; +} + +//========================================================= +//========================================================= +int CHalfLifeMultiplay::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) +{ + if ( pAmmo->pev->spawnflags & SF_NORESPAWN ) + { + return GR_AMMO_RESPAWN_NO; + } + + return GR_AMMO_RESPAWN_YES; +} + +//========================================================= +//========================================================= +float CHalfLifeMultiplay::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) +{ + return gpGlobals->time + AMMO_RESPAWN_TIME; +} + +//========================================================= +//========================================================= +Vector CHalfLifeMultiplay::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) +{ + return pAmmo->pev->origin; +} + +//========================================================= +//========================================================= +float CHalfLifeMultiplay::FlHealthChargerRechargeTime( void ) +{ + return 60; +} + + +float CHalfLifeMultiplay::FlHEVChargerRechargeTime( void ) +{ + return 30; +} + +//========================================================= +//========================================================= +int CHalfLifeMultiplay::DeadPlayerWeapons( CBasePlayer *pPlayer ) +{ + return GR_PLR_DROP_GUN_ACTIVE; +} + +//========================================================= +//========================================================= +int CHalfLifeMultiplay::DeadPlayerAmmo( CBasePlayer *pPlayer ) +{ + return GR_PLR_DROP_AMMO_ACTIVE; +} + +edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) +{ + edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); + if ( IsMultiplayer() && !FNullEnt(pentSpawnSpot) && (pentSpawnSpot->v.target)) + { + FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); + } + + return pentSpawnSpot; +} + + +//========================================================= +//========================================================= +int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) +{ + // half life deathmatch has only enemies + return GR_NOTTEAMMATE; +} + +BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) +{ + if ( g_footsteps && g_footsteps->value == 0 ) + return FALSE; + + if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > pl->GetMaxWalkSpeed() ) + return TRUE; // only make step sounds in multiplayer if the player is moving fast enough + + return FALSE; +} + +BOOL CHalfLifeMultiplay :: FAllowFlashlight( void ) +{ + return flashlight.value != 0; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) +{ + return ( allowmonsters.value != 0 ); +} + +//========================================================= +//======== CHalfLifeMultiplay private functions =========== +#define INTERMISSION_TIME 6 + +void CHalfLifeMultiplay :: GoToIntermission( void ) +{ + if ( g_fGameOver ) + return; // intermission has already been triggered, so ignore. + + MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); + MESSAGE_END(); + + // bounds check + int time = (int)ns_cvar_float( &mp_chattime ); + if ( time < 10 ) + CVAR_SET_STRING( "mp_chattime", "10" ); + else if ( time > MAX_INTERMISSION_TIME ) + CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); + + m_flIntermissionEndTime = gpGlobals->time + ( (int)mp_chattime.value ); + g_flIntermissionStartTime = gpGlobals->time; + + g_fGameOver = TRUE; + m_iEndIntermissionButtonHit = FALSE; +} + +#define MAX_RULE_BUFFER 1024 + +typedef struct mapcycle_item_s +{ + struct mapcycle_item_s *next; + + char mapname[ 32 ]; + int minplayers, maxplayers; + char rulebuffer[ MAX_RULE_BUFFER ]; +} mapcycle_item_t; + +typedef struct mapcycle_s +{ + struct mapcycle_item_s *items; + struct mapcycle_item_s *next_item; +} mapcycle_t; + +/* +============== +DestroyMapCycle + +Clean up memory used by mapcycle when switching it +============== +*/ +void DestroyMapCycle( mapcycle_t *cycle ) +{ + mapcycle_item_t *p, *n, *start; + p = cycle->items; + if ( p ) + { + start = p; + p = p->next; + while ( p != start ) + { + n = p->next; + delete p; + p = n; + } + + delete cycle->items; + } + cycle->items = NULL; + cycle->next_item = NULL; +} + +static char com_token[ 1500 ]; + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c=='\"' || !c) + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +/* +============== +COM_TokenWaiting + +Returns 1 if additional data is waiting to be processed on this line +============== +*/ +int COM_TokenWaiting( char *buffer ) +{ + char *p; + + p = buffer; + while ( *p && *p!='\n') + { + if ( !isspace( *p ) || isalnum( *p ) ) + return 1; + + p++; + } + + return 0; +} + +void GetMapNamesFromMapCycle(StringList& outMapNameList) +{ + char* mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); + ASSERT( mapcfile != NULL ); + + char szBuffer[ MAX_RULE_BUFFER ]; + char szMap[ 32 ]; + int length; + char *pFileList; + char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( mapcfile, &length ); + int hasbuffer; + mapcycle_item_s *newlist = NULL; + + if ( pFileList && length ) + { + // the first map name in the file becomes the default + while ( 1 ) + { + hasbuffer = 0; + memset( szBuffer, 0, MAX_RULE_BUFFER ); + + pFileList = COM_Parse( pFileList ); + if ( strlen( com_token ) <= 0 ) + break; + + strcpy( szMap, com_token ); + + // Any more tokens on this line? + if ( COM_TokenWaiting( pFileList ) ) + { + pFileList = COM_Parse( pFileList ); + if ( strlen( com_token ) > 0 ) + { + hasbuffer = 1; + strcpy( szBuffer, com_token ); + } + } + + // Check map + if ( IS_MAP_VALID( szMap ) ) + { + outMapNameList.push_back( szMap ); + } + } + + FREE_FILE( aFileList ); + } +} + + +/* +============== +ReloadMapCycleFile + + +Parses mapcycle.txt file into mapcycle_t structure +============== +*/ +int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) +{ + char szBuffer[ MAX_RULE_BUFFER ]; + char szMap[ 32 ]; + int length; + char *pFileList; + char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); + int hasbuffer; + mapcycle_item_s *item, *newlist = NULL, *next; + + if ( pFileList && length ) + { + // the first map name in the file becomes the default + while ( 1 ) + { + hasbuffer = 0; + memset( szBuffer, 0, MAX_RULE_BUFFER ); + + pFileList = COM_Parse( pFileList ); + if ( strlen( com_token ) <= 0 ) + break; + + strcpy( szMap, com_token ); + + // Any more tokens on this line? + if ( COM_TokenWaiting( pFileList ) ) + { + pFileList = COM_Parse( pFileList ); + if ( strlen( com_token ) > 0 ) + { + hasbuffer = 1; + strcpy( szBuffer, com_token ); + } + } + + // Check map + if ( IS_MAP_VALID( szMap ) ) + { + // Create entry + char *s; + + item = new mapcycle_item_s; + + strcpy( item->mapname, szMap ); + + item->minplayers = 0; + item->maxplayers = 0; + + memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); + + if ( hasbuffer ) + { + s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); + if ( s && s[0] ) + { + item->minplayers = atoi( s ); + item->minplayers = max( item->minplayers, 0 ); + item->minplayers = min( item->minplayers, gpGlobals->maxClients ); + } + s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); + if ( s && s[0] ) + { + item->maxplayers = atoi( s ); + item->maxplayers = max( item->maxplayers, 0 ); + item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); + } + + // Remove keys + // + g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); + g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); + + strcpy( item->rulebuffer, szBuffer ); + } + + item->next = cycle->items; + cycle->items = item; + } + else + { + ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); + } + + } + + FREE_FILE( aFileList ); + } + + // Fixup circular list pointer + item = cycle->items; + + // Reverse it to get original order + while ( item ) + { + next = item->next; + item->next = newlist; + newlist = item; + item = next; + } + cycle->items = newlist; + item = cycle->items; + + // Didn't parse anything + if ( !item ) + { + return 0; + } + + while ( item->next ) + { + item = item->next; + } + item->next = cycle->items; + + cycle->next_item = item->next; + + return 1; +} + +/* +============== +CountPlayers + +Determine the current # of active players on the server for map cycling logic +============== +*/ +int CountPlayers( void ) +{ + int num = 0; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); + + if ( pEnt ) + { + num = num + 1; + } + } + + return num; +} + +/* +============== +ExtractCommandString + +Parse commands/key value pairs to issue right after map xxx command is issued on server + level transition +============== +*/ +void ExtractCommandString( char *s, char *szCommand ) +{ + // Now make rules happen + char pkey[512]; + char value[512]; // use two buffers so compares + // work without stomping on each other + char *o; + + if ( *s == '\\' ) + s++; + + while (1) + { + o = pkey; + while ( *s != '\\' ) + { + if ( !*s ) + return; + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + + while (*s != '\\' && *s) + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + + strcat( szCommand, pkey ); + if ( strlen( value ) > 0 ) + { + strcat( szCommand, " " ); + strcat( szCommand, value ); + } + strcat( szCommand, "\n" ); + + if (!*s) + return; + s++; + } +} + +/* +============== +ChangeLevel + +Server is changing to a new level, check mapcycle.txt for map name and setup info +============== +*/ +void CHalfLifeMultiplay :: ChangeLevel( void ) +{ + static char szPreviousMapCycleFile[ 256 ]; + static mapcycle_t mapcycle; + + char szNextMap[32]; + char szFirstMapInList[32]; + char szCommands[ 1500 ]; + char szRules[ 1500 ]; + int minplayers = 0, maxplayers = 0; + strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 + + int curplayers; + BOOL do_cycle = TRUE; + + // find the map to change to + char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); + ASSERT( mapcfile != NULL ); + + szCommands[ 0 ] = '\0'; + szRules[ 0 ] = '\0'; + + curplayers = CountPlayers(); + + // Has the map cycle filename changed? + if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) + { + strcpy( szPreviousMapCycleFile, mapcfile ); + + DestroyMapCycle( &mapcycle ); + + if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) + { + ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); + do_cycle = FALSE; + } + } + + if ( do_cycle && mapcycle.items ) + { + BOOL keeplooking = FALSE; + BOOL found = FALSE; + mapcycle_item_s *item; + + // Assume current map + strcpy( szNextMap, STRING(gpGlobals->mapname) ); + strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); + + // Traverse list + for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) + { + keeplooking = FALSE; + + ASSERT( item != NULL ); + + if ( item->minplayers != 0 ) + { + if ( curplayers >= item->minplayers ) + { + found = TRUE; + minplayers = item->minplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( item->maxplayers != 0 ) + { + if ( curplayers <= item->maxplayers ) + { + found = TRUE; + maxplayers = item->maxplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( keeplooking ) + continue; + + found = TRUE; + break; + } + + if ( !found ) + { + item = mapcycle.next_item; + } + + // Increment next item pointer + mapcycle.next_item = item->next; + + // Perform logic on current item + strcpy( szNextMap, item->mapname ); + + ExtractCommandString( item->rulebuffer, szCommands ); + strcpy( szRules, item->rulebuffer ); + } + + if ( !IS_MAP_VALID(szNextMap) ) + { + strcpy( szNextMap, szFirstMapInList ); + } + + g_fGameOver = TRUE; + + ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); + if ( minplayers || maxplayers ) + { + ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); + } + if ( strlen( szRules ) > 0 ) + { + ALERT( at_console, "RULES: %s\n", szRules ); + } + + CHANGE_LEVEL( szNextMap, NULL ); + if ( strlen( szCommands ) > 0 ) + { + SERVER_COMMAND( szCommands ); + } +} + +#define MAX_MOTD_CHUNK 60 +#define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4) + +void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) +{ + // read from the MOTD.txt file + int length, char_count = 0; + char *pFileList; + char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( (char *)CVAR_GET_STRING( "motdfile" ), &length ); + + // send the server name + NetMsg_ServerName( &client->v, string( CVAR_GET_STRING( "hostname" ) ) ); + + // Send the message of the day + // read it chunk-by-chunk, and send it in parts + + while ( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) + { + char chunk[MAX_MOTD_CHUNK+1]; + + if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) + { + strcpy( chunk, pFileList ); + } + else + { + strncpy( chunk, pFileList, MAX_MOTD_CHUNK ); + chunk[MAX_MOTD_CHUNK] = 0; // strncpy doesn't always append the null terminator + } + + char_count += strlen( chunk ); + if ( char_count < MAX_MOTD_LENGTH ) + pFileList = aFileList + char_count; + else + *pFileList = 0; + + NetMsg_MOTD( &client->v, *pFileList ? false : true, string( chunk ) ); + } + + FREE_FILE( aFileList ); +} + diff --git a/main/source/dlls/nihilanth.cpp b/main/source/dlls/nihilanth.cpp index 8116f902..2b7b9447 100644 --- a/main/source/dlls/nihilanth.cpp +++ b/main/source/dlls/nihilanth.cpp @@ -1,1836 +1,1836 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" - -#define N_SCALE 15 -#define N_SPHERES 20 - -class CNihilanth : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_ALIEN_MILITARY; }; - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -16 * N_SCALE, -16 * N_SCALE, -48 * N_SCALE ); - pev->absmax = pev->origin + Vector( 16 * N_SCALE, 16 * N_SCALE, 28 * N_SCALE ); - } - - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void EXPORT StartupThink( void ); - void EXPORT HuntThink( void ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT NullThink( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void FloatSequence( void ); - void NextActivity( void ); - - void Flight( void ); - - BOOL AbsorbSphere( void ); - BOOL EmitSphere( void ); - void TargetSphere( USE_TYPE useType, float value ); - CBaseEntity *RandomTargetname( const char *szName ); - void ShootBalls( void ); - void MakeFriend( Vector vecPos ); - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - void PainSound( void ); - void DeathSound( void ); - - static const char *pAttackSounds[]; // vocalization: play sometimes when he launches an attack - static const char *pBallSounds[]; // the sound of the lightening ball launch - static const char *pShootSounds[]; // grunting vocalization: play sometimes when he launches an attack - static const char *pRechargeSounds[]; // vocalization: play when he recharges - static const char *pLaughSounds[]; // vocalization: play sometimes when hit and still has lots of health - static const char *pPainSounds[]; // vocalization: play sometimes when hit and has much less health and no more chargers - static const char *pDeathSounds[]; // vocalization: play as he dies - - // x_teleattack1.wav the looping sound of the teleport attack ball. - - float m_flForce; - - float m_flNextPainSound; - - Vector m_velocity; - Vector m_avelocity; - - Vector m_vecTarget; - Vector m_posTarget; - - Vector m_vecDesired; - Vector m_posDesired; - - float m_flMinZ; - float m_flMaxZ; - - Vector m_vecGoal; - - float m_flLastSeen; - float m_flPrevSeen; - - int m_irritation; - - int m_iLevel; - int m_iTeleport; - - EHANDLE m_hRecharger; - - EHANDLE m_hSphere[N_SPHERES]; - int m_iActiveSpheres; - - float m_flAdj; - - CSprite *m_pBall; - - char m_szRechargerTarget[64]; - char m_szDrawUse[64]; - char m_szTeleportUse[64]; - char m_szTeleportTouch[64]; - char m_szDeadUse[64]; - char m_szDeadTouch[64]; - - float m_flShootEnd; - float m_flShootTime; - - EHANDLE m_hFriend[3]; -}; - -LINK_ENTITY_TO_CLASS( monster_nihilanth, CNihilanth ); - -TYPEDESCRIPTION CNihilanth::m_SaveData[] = -{ - DEFINE_FIELD( CNihilanth, m_flForce, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_flNextPainSound, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_velocity, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_avelocity, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_posTarget, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CNihilanth, m_vecDesired, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_posDesired, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CNihilanth, m_flMinZ, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_flMaxZ, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_vecGoal, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_flLastSeen, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_flPrevSeen, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_irritation, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_iLevel, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_iTeleport, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_hRecharger, FIELD_EHANDLE ), - DEFINE_ARRAY( CNihilanth, m_hSphere, FIELD_EHANDLE, N_SPHERES ), - DEFINE_FIELD( CNihilanth, m_iActiveSpheres, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_flAdj, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_pBall, FIELD_CLASSPTR ), - DEFINE_ARRAY( CNihilanth, m_szRechargerTarget, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDrawUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szTeleportUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szTeleportTouch, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDeadUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDeadTouch, FIELD_CHARACTER, 64 ), - DEFINE_FIELD( CNihilanth, m_flShootEnd, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_flShootTime, FIELD_TIME ), - DEFINE_ARRAY( CNihilanth, m_hFriend, FIELD_EHANDLE, 3 ), -}; - -IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ); - -class CNihilanthHVR : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - - void CircleInit( CBaseEntity *pTarget ); - void AbsorbInit( void ); - void TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ); - void GreenBallInit( void ); - void ZapInit( CBaseEntity *pEnemy ); - - void EXPORT HoverThink( void ); - BOOL CircleTarget( Vector vecTarget ); - void EXPORT DissipateThink( void ); - - void EXPORT ZapThink( void ); - void EXPORT TeleportThink( void ); - void EXPORT TeleportTouch( CBaseEntity *pOther ); - - void EXPORT RemoveTouch( CBaseEntity *pOther ); - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT ZapTouch( CBaseEntity *pOther ); - - CBaseEntity *RandomClassname( const char *szName ); - - // void EXPORT SphereUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void MovetoTarget( Vector vecTarget ); - virtual void Crawl( void ); - - void Zap( void ); - void Teleport( void ); - - float m_flIdealVel; - Vector m_vecIdeal; - CNihilanth *m_pNihilanth; - EHANDLE m_hTouch; - int m_nFrames; -}; - -LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR ); - - -TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = -{ - DEFINE_FIELD( CNihilanthHVR, m_flIdealVel, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanthHVR, m_vecIdeal, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanthHVR, m_pNihilanth, FIELD_CLASSPTR ), - DEFINE_FIELD( CNihilanthHVR, m_hTouch, FIELD_EHANDLE ), - DEFINE_FIELD( CNihilanthHVR, m_nFrames, FIELD_INTEGER ), -}; - - -IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ); - - -//========================================================= -// Nihilanth, final Boss monster -//========================================================= - -const char *CNihilanth::pAttackSounds[] = -{ - "X/x_attack1.wav", - "X/x_attack2.wav", - "X/x_attack3.wav", -}; - -const char *CNihilanth::pBallSounds[] = -{ - "X/x_ballattack1.wav", -}; - -const char *CNihilanth::pShootSounds[] = -{ - "X/x_shoot1.wav", -}; - -const char *CNihilanth::pRechargeSounds[] = -{ - "X/x_recharge1.wav", - "X/x_recharge2.wav", - "X/x_recharge3.wav", -}; - -const char *CNihilanth::pLaughSounds[] = -{ - "X/x_laugh1.wav", - "X/x_laugh2.wav", -}; - -const char *CNihilanth::pPainSounds[] = -{ - "X/x_pain1.wav", - "X/x_pain2.wav", -}; - -const char *CNihilanth::pDeathSounds[] = -{ - "X/x_die1.wav", -}; - - -void CNihilanth :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(edict(), "models/nihilanth.mdl"); - // UTIL_SetSize(pev, Vector( -300, -300, 0), Vector(300, 300, 512)); - UTIL_SetSize(pev, Vector( -32, -32, 0), Vector(32, 32, 64)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.nihilanthHealth; - pev->view_ofs = Vector( 0, 0, 300 ); - - m_flFieldOfView = -1; // 360 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - - InitBoneControllers(); - - SetThink( &CNihilanth::StartupThink ); - pev->nextthink = gpGlobals->time + 0.1; - - m_vecDesired = Vector( 1, 0, 0 ); - m_posDesired = Vector( pev->origin.x, pev->origin.y, 512 ); - - m_iLevel = 1; - m_iTeleport = 1; - - if (m_szRechargerTarget[0] == '\0') strcpy( m_szRechargerTarget, "n_recharger" ); - if (m_szDrawUse[0] == '\0') strcpy( m_szDrawUse, "n_draw" ); - if (m_szTeleportUse[0] == '\0') strcpy( m_szTeleportUse, "n_leaving" ); - if (m_szTeleportTouch[0] == '\0') strcpy( m_szTeleportTouch, "n_teleport" ); - if (m_szDeadUse[0] == '\0') strcpy( m_szDeadUse, "n_dead" ); - if (m_szDeadTouch[0] == '\0') strcpy( m_szDeadTouch, "n_ending" ); - - // near death - /* - m_iTeleport = 10; - m_iLevel = 10; - m_irritation = 2; - pev->health = 100; - */ -} - - -void CNihilanth::Precache( void ) -{ - PRECACHE_MODEL("models/nihilanth.mdl"); - PRECACHE_MODEL("sprites/lgtning.spr"); - UTIL_PrecacheOther( "nihilanth_energy_ball" ); - UTIL_PrecacheOther( "monster_alien_controller" ); - UTIL_PrecacheOther( "monster_alien_slave" ); - - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pBallSounds ); - PRECACHE_SOUND_ARRAY( pShootSounds ); - PRECACHE_SOUND_ARRAY( pRechargeSounds ); - PRECACHE_SOUND_ARRAY( pLaughSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND("debris/beamstart7.wav"); -} - - - -void CNihilanth :: PainSound( void ) -{ - if (m_flNextPainSound > gpGlobals->time) - return; - - m_flNextPainSound = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - - if (pev->health > gSkillData.nihilanthHealth / 2) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pLaughSounds ), 1.0, 0.2 ); - } - else if (m_irritation >= 2) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0, 0.2 ); - } -} - -void CNihilanth :: DeathSound( void ) -{ - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1.0, 0.1 ); -} - - -void CNihilanth::NullThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.5; -} - - -void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CNihilanth::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse( &CNihilanth::CommandUse ); -} - - -void CNihilanth::StartupThink( void ) -{ - m_irritation = 0; - m_flAdj = 512; - - CBaseEntity *pEntity; - - pEntity = UTIL_FindEntityByTargetname( NULL, "n_min"); - if (pEntity) - m_flMinZ = pEntity->pev->origin.z; - else - m_flMinZ = -4096; - - pEntity = UTIL_FindEntityByTargetname( NULL, "n_max"); - if (pEntity) - m_flMaxZ = pEntity->pev->origin.z; - else - m_flMaxZ = 4096; - - m_hRecharger = this; - for (int i = 0; i < N_SPHERES; i++) - { - EmitSphere( ); - } - m_hRecharger = NULL; - - SetThink( &CNihilanth::HuntThink); - SetUse( &CNihilanth::CommandUse ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CNihilanth :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); -} - -void CNihilanth :: DyingThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - if (pev->deadflag == DEAD_NO) - { - DeathSound( ); - pev->deadflag = DEAD_DYING; - - m_posDesired.z = m_flMaxZ; - } - - if (pev->deadflag == DEAD_DYING) - { - Flight( ); - - if (fabs( pev->origin.z - m_flMaxZ ) < 16) - { - pev->velocity = Vector( 0, 0, 0 ); - FireTargets( m_szDeadUse, this, this, USE_ON, 1.0 ); - pev->deadflag = DEAD_DEAD; - } - } - - if (m_fSequenceFinished) - { - pev->avelocity.y += RANDOM_FLOAT( -100, 100 ); - if (pev->avelocity.y < -100) - pev->avelocity.y = -100; - if (pev->avelocity.y > 100) - pev->avelocity.y = 100; - - pev->sequence = LookupSequence( "die1" ); - } - - if (m_pBall) - { - if (m_pBall->pev->renderamt > 0) - { - m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2); - } - else - { - UTIL_Remove( m_pBall ); - m_pBall = NULL; - } - } - - Vector vecDir, vecSrc, vecAngles; - - UTIL_MakeAimVectors( pev->angles ); - int iAttachment = RANDOM_LONG( 1, 4 ); - - do { - vecDir = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 )); - } while (DotProduct( vecDir, vecDir) > 1.0); - - switch( RANDOM_LONG( 1, 4 )) - { - case 1: // head - vecDir.z = fabs( vecDir.z ) * 0.5; - vecDir = vecDir + 2 * gpGlobals->v_up; - break; - case 2: // eyes - if (DotProduct( vecDir, gpGlobals->v_forward ) < 0) - vecDir = vecDir * -1; - - vecDir = vecDir + 2 * gpGlobals->v_forward; - break; - case 3: // left hand - if (DotProduct( vecDir, gpGlobals->v_right ) > 0) - vecDir = vecDir * -1; - vecDir = vecDir - 2 * gpGlobals->v_right; - break; - case 4: // right hand - if (DotProduct( vecDir, gpGlobals->v_right ) < 0) - vecDir = vecDir * -1; - vecDir = vecDir + 2 * gpGlobals->v_right; - break; - } - - GetAttachment( iAttachment - 1, vecSrc, vecAngles ); - - TraceResult tr; - - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 4096, ignore_monsters, ENT(pev), &tr ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() + 0x1000 * iAttachment ); - WRITE_COORD( tr.vecEndPos.x); - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 5 ); // life - WRITE_BYTE( 100 ); // width - WRITE_BYTE( 120 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; - pEntity->GreenBallInit( ); - - return; -} - - - -void CNihilanth::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - SetTouch( &CNihilanth::NULL ); - pev->nextthink = gpGlobals->time; - } -} - - - -void CNihilanth :: GibMonster( void ) -{ - // EMIT_SOUND_DYN(edict(), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - - - -void CNihilanth :: FloatSequence( void ) -{ - if (m_irritation >= 2) - { - pev->sequence = LookupSequence( "float_open" ); - } - else if (m_avelocity.y > 30) - { - pev->sequence = LookupSequence( "walk_r" ); - } - else if (m_avelocity.y < -30) - { - pev->sequence = LookupSequence( "walk_l" ); - } - else if (m_velocity.z > 30) - { - pev->sequence = LookupSequence( "walk_u" ); - } - else if (m_velocity.z < -30) - { - pev->sequence = LookupSequence( "walk_d" ); - } - else - { - pev->sequence = LookupSequence( "float" ); - } -} - - -void CNihilanth :: ShootBalls( void ) -{ - if (m_flShootEnd > gpGlobals->time) - { - Vector vecHand, vecAngle; - - while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) - { - if (m_hEnemy != NULL) - { - Vector vecSrc, vecDir; - CNihilanthHVR *pEntity; - - GetAttachment( 2, vecHand, vecAngle ); - vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); - // vecDir = (m_posTarget - vecSrc).Normalize( ); - vecDir = (m_posTarget - pev->origin).Normalize( ); - vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = vecDir * 200.0; - pEntity->ZapInit( m_hEnemy ); - - GetAttachment( 3, vecHand, vecAngle ); - vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); - // vecDir = (m_posTarget - vecSrc).Normalize( ); - vecDir = (m_posTarget - pev->origin).Normalize( ); - vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = vecDir * 200.0; - pEntity->ZapInit( m_hEnemy ); - } - m_flShootTime += 0.2; - } - } -} - - -void CNihilanth :: MakeFriend( Vector vecStart ) -{ - int i; - - for (i = 0; i < 3; i++) - { - if (m_hFriend[i] != NULL && !m_hFriend[i]->IsAlive()) - { - if (pev->rendermode == kRenderNormal) // don't do it if they are already fading - m_hFriend[i]->MyMonsterPointer()->FadeMonster( ); - m_hFriend[i] = NULL; - } - - if (m_hFriend[i] == NULL) - { - if (RANDOM_LONG(0, 1) == 0) - { - int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_AIR ); - if (iNode != NO_NODE) - { - CNode &node = WorldGraph.Node( iNode ); - TraceResult tr; - UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 32 ), node.m_vecOrigin + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, NULL, &tr ); - if (tr.fStartSolid == 0) - m_hFriend[i] = Create("monster_alien_controller", node.m_vecOrigin, pev->angles ); - } - } - else - { - int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_LAND | bits_NODE_WATER ); - if (iNode != NO_NODE) - { - CNode &node = WorldGraph.Node( iNode ); - TraceResult tr; - UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 36 ), node.m_vecOrigin + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, NULL, &tr ); - if (tr.fStartSolid == 0) - m_hFriend[i] = Create("monster_alien_slave", node.m_vecOrigin, pev->angles ); - } - } - if (m_hFriend[i] != NULL) - { - EMIT_SOUND( m_hFriend[i]->edict(), CHAN_WEAPON, "debris/beamstart7.wav", 1.0, ATTN_NORM ); - } - - return; - } - } -} - - -void CNihilanth :: NextActivity( ) -{ - UTIL_MakeAimVectors( pev->angles ); - - if (m_irritation >= 2) - { - if (m_pBall == NULL) - { - m_pBall = CSprite::SpriteCreate( "sprites/tele1.spr", pev->origin, TRUE ); - if (m_pBall) - { - m_pBall->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pBall->SetAttachment( edict(), 1 ); - m_pBall->SetScale( 4.0 ); - m_pBall->pev->framerate = 10.0; - m_pBall->TurnOn( ); - } - } - - if (m_pBall) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 200 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } - } - - if ((pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2) && m_hRecharger == NULL && m_iLevel <= 9) - { - char szName[64]; - - CBaseEntity *pEnt = NULL; - CBaseEntity *pRecharger = NULL; - float flDist = 8192; - - sprintf(szName, "%s%d", m_szRechargerTarget, m_iLevel ); - - while ((pEnt = UTIL_FindEntityByTargetname( pEnt, szName )) != NULL) - { - float flLocal = (pEnt->pev->origin - pev->origin).Length(); - if (flLocal < flDist) - { - flDist = flLocal; - pRecharger = pEnt; - } - } - - if (pRecharger) - { - m_hRecharger = pRecharger; - m_posDesired = Vector( pev->origin.x, pev->origin.y, pRecharger->pev->origin.z ); - m_vecDesired = (pRecharger->pev->origin - m_posDesired).Normalize( ); - m_vecDesired.z = 0; - m_vecDesired = m_vecDesired.Normalize(); - } - else - { - m_hRecharger = NULL; - ALERT( at_aiconsole, "nihilanth can't find %s\n", szName ); - m_iLevel++; - if (m_iLevel > 9) - m_irritation = 2; - } - } - - float flDist = (m_posDesired - pev->origin).Length(); - float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); - - if (m_hRecharger != NULL) - { - // at we at power up yet? - if (flDist < 128.0) - { - int iseq = LookupSequence( "recharge" ); - - if (iseq != pev->sequence) - { - char szText[64]; - - sprintf( szText, "%s%d", m_szDrawUse, m_iLevel ); - FireTargets( szText, this, this, USE_ON, 1.0 ); - - ALERT( at_console, "fireing %s\n", szText ); - } - pev->sequence = LookupSequence( "recharge" ); - } - else - { - FloatSequence( ); - } - return; - } - - if (m_hEnemy != NULL && !m_hEnemy->IsAlive()) - { - m_hEnemy = NULL; - } - - if (m_flLastSeen + 15 < gpGlobals->time) - { - m_hEnemy = NULL; - } - - if (m_hEnemy == NULL) - { - Look( 4096 ); - m_hEnemy = BestVisibleEnemy( ); - } - - if (m_hEnemy != NULL && m_irritation != 0) - { - if (m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0) - { - if (m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0) - { - pev->sequence = LookupSequence( "attack1_open" ); - } - else - { - if (RANDOM_LONG(0, 1 ) == 0) - { - pev->sequence = LookupSequence( "attack1" ); // zap - } - else - { - char szText[64]; - - sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); - - sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); - CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - - if (pTrigger != NULL || pTouch != NULL) - { - pev->sequence = LookupSequence( "attack2" ); // teleport - } - else - { - m_iTeleport++; - pev->sequence = LookupSequence( "attack1" ); // zap - } - } - } - return; - } - } - - FloatSequence( ); -} - -void CNihilanth :: HuntThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - ShootBalls( ); - - // if dead, force cancelation of current animation - if (pev->health <= 0) - { - SetThink( &CNihilanth::DyingThink ); - m_fSequenceFinished = TRUE; - return; - } - - // ALERT( at_console, "health %.0f\n", pev->health ); - - // if damaged, try to abosorb some spheres - if (pev->health < gSkillData.nihilanthHealth && AbsorbSphere( )) - { - pev->health += gSkillData.nihilanthHealth / N_SPHERES; - } - - // get new sequence - if (m_fSequenceFinished) - { - // if (!m_fSequenceLoops) - pev->frame = 0; - NextActivity( ); - ResetSequenceInfo( ); - pev->framerate = 2.0 - 1.0 * (pev->health / gSkillData.nihilanthHealth); - } - - // look for current enemy - if (m_hEnemy != NULL && m_hRecharger == NULL) - { - if (FVisible( m_hEnemy )) - { - if (m_flLastSeen < gpGlobals->time - 5) - m_flPrevSeen = gpGlobals->time; - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->pev->origin; - m_vecTarget = (m_posTarget - pev->origin).Normalize(); - m_vecDesired = m_vecTarget; - m_posDesired = Vector( pev->origin.x, pev->origin.y, m_posTarget.z + m_flAdj ); - } - else - { - m_flAdj = min( m_flAdj + 10, 1000 ); - } - } - - // don't go too high - if (m_posDesired.z > m_flMaxZ) - m_posDesired.z = m_flMaxZ; - - // don't go too low - if (m_posDesired.z < m_flMinZ) - m_posDesired.z = m_flMinZ; - - Flight( ); -} - - - -void CNihilanth :: Flight( void ) -{ - // estimate where I'll be facing in one seconds - UTIL_MakeAimVectors( pev->angles + m_avelocity ); - // Vector vecEst1 = pev->origin + m_velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); - // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); - - float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - - if (flSide < 0) - { - if (m_avelocity.y < 180) - { - m_avelocity.y += 6; // 9 * (3.0/2.0); - } - } - else - { - if (m_avelocity.y > -180) - { - m_avelocity.y -= 6; // 9 * (3.0/2.0); - } - } - m_avelocity.y *= 0.98; - - // estimate where I'll be in two seconds - Vector vecEst = pev->origin + m_velocity * 2.0 + gpGlobals->v_up * m_flForce * 20; - - // add immediate force - UTIL_MakeAimVectors( pev->angles ); - m_velocity.x += gpGlobals->v_up.x * m_flForce; - m_velocity.y += gpGlobals->v_up.y * m_flForce; - m_velocity.z += gpGlobals->v_up.z * m_flForce; - - - float flSpeed = m_velocity.Length(); - float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( m_velocity.x, m_velocity.y, 0 ) ); - if (flDir < 0) - flSpeed = -flSpeed; - - float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); - - // sideways drag - m_velocity.x = m_velocity.x * (1.0 - fabs( gpGlobals->v_right.x ) * 0.05); - m_velocity.y = m_velocity.y * (1.0 - fabs( gpGlobals->v_right.y ) * 0.05); - m_velocity.z = m_velocity.z * (1.0 - fabs( gpGlobals->v_right.z ) * 0.05); - - // general drag - m_velocity = m_velocity * 0.995; - - // apply power to stay correct height - if (m_flForce < 100 && vecEst.z < m_posDesired.z) - { - m_flForce += 10; - } - else if (m_flForce > -100 && vecEst.z > m_posDesired.z) - { - if (vecEst.z > m_posDesired.z) - m_flForce -= 10; - } - - UTIL_SetOrigin( pev, pev->origin + m_velocity * 0.1 ); - pev->angles = pev->angles + m_avelocity * 0.1; - - // ALERT( at_console, "%5.0f %5.0f : %4.0f : %3.0f : %2.0f\n", m_posDesired.z, pev->origin.z, m_velocity.z, m_avelocity.y, m_flForce ); -} - - -BOOL CNihilanth :: AbsorbSphere( void ) -{ - for (int i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != NULL) - { - CNihilanthHVR *pSphere = (CNihilanthHVR *)((CBaseEntity *)m_hSphere[i]); - pSphere->AbsorbInit( ); - m_hSphere[i] = NULL; - m_iActiveSpheres--; - return TRUE; - } - } - return FALSE; -} - - -BOOL CNihilanth :: EmitSphere( void ) -{ - m_iActiveSpheres = 0; - int empty = 0; - - for (int i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != NULL) - { - m_iActiveSpheres++; - } - else - { - empty = i; - } - } - - if (m_iActiveSpheres >= N_SPHERES) - return FALSE; - - Vector vecSrc = m_hRecharger->pev->origin; - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->CircleInit( this ); - - m_hSphere[empty] = pEntity; - return TRUE; -} - - -void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) -{ - CBaseMonster *pSphere; - for (int i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != NULL) - { - pSphere = m_hSphere[i]->MyMonsterPointer(); - if (pSphere->m_hEnemy == NULL) - break; - } - } - if (i == N_SPHERES) - { - return; - } - - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - UTIL_SetOrigin( pSphere->pev, vecSrc ); - pSphere->Use( this, this, useType, value ); - pSphere->pev->velocity = m_vecDesired * RANDOM_FLOAT( 50, 100 ) + Vector( RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ) ); -} - - - -void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 1: // shoot - break; - case 2: // zen - if (m_hEnemy != NULL) - { - if (RANDOM_LONG(0,4) == 0) - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); - - EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - m_flShootTime = gpGlobals->time; - m_flShootEnd = gpGlobals->time + 1.0; - } - break; - case 3: // prayer - if (m_hEnemy != NULL) - { - char szText[32]; - - sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); - - sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); - CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - - if (pTrigger != NULL || pTouch != NULL) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); - - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->TeleportInit( this, m_hEnemy, pTrigger, pTouch ); - } - else - { - m_iTeleport++; // unexpected failure - - EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); - - ALERT( at_aiconsole, "nihilanth can't target %s\n", szText ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - m_flShootTime = gpGlobals->time; - m_flShootEnd = gpGlobals->time + 1.0; - } - } - break; - case 4: // get a sphere - { - if (m_hRecharger != NULL) - { - if (!EmitSphere( )) - { - m_hRecharger = NULL; - } - } - } - break; - case 5: // start up sphere machine - { - EMIT_SOUND( edict(), CHAN_VOICE , RANDOM_SOUND_ARRAY( pRechargeSounds ), 1.0, 0.2 ); - } - break; - case 6: - if (m_hEnemy != NULL) - { - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->ZapInit( m_hEnemy ); - } - break; - case 7: - /* - Vector vecSrc, vecAngles; - GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; - pEntity->GreenBallInit( ); - */ - break; - } -} - - - -void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - switch (useType) - { - case USE_OFF: - { - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); - if ( pTouch && m_hEnemy != NULL ) - pTouch->Touch( m_hEnemy ); - } - break; - case USE_ON: - if (m_irritation == 0) - { - m_irritation = 1; - } - break; - case USE_SET: - break; - case USE_TOGGLE: - break; - } -} - - -int CNihilanth :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (pevInflictor->owner == edict()) - return 0; - - if (flDamage >= pev->health) - { - pev->health = 1; - if (m_irritation != 3) - return 0; - } - - PainSound( ); - - pev->health -= flDamage; - return 0; -} - - - -void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if (m_irritation == 3) - m_irritation = 2; - - if (m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2) - m_irritation = 3; - - if (m_irritation != 3) - { - Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( ); - - UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + (100 - 100 * (pev->health / gSkillData.nihilanthHealth))); - } - - // SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage * 5.0);// a little surface blood. - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - - - -CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - - - - - - - - - -//========================================================= -// Controller bouncy ball attack -//========================================================= - - - -void CNihilanthHVR :: Spawn( void ) -{ - Precache( ); - - pev->rendermode = kRenderTransAdd; - pev->renderamt = 255; - pev->scale = 3.0; -} - - -void CNihilanthHVR :: Precache( void ) -{ - PRECACHE_MODEL("sprites/flare6.spr"); - PRECACHE_MODEL("sprites/nhth1.spr"); - PRECACHE_MODEL("sprites/exit1.spr"); - PRECACHE_MODEL("sprites/tele1.spr"); - PRECACHE_MODEL("sprites/animglow01.spr"); - PRECACHE_MODEL("sprites/xspark4.spr"); - PRECACHE_MODEL("sprites/muzzleflash3.spr"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("x/x_teleattack1.wav"); -} - - - -void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) -{ - pev->movetype = MOVETYPE_NOCLIP; - pev->solid = SOLID_NOT; - - // SET_MODEL(edict(), "sprites/flare6.spr"); - // pev->scale = 3.0; - // SET_MODEL(edict(), "sprites/xspark4.spr"); - SET_MODEL(edict(), "sprites/muzzleflash3.spr"); - pev->rendercolor.x = 255; - pev->rendercolor.y = 224; - pev->rendercolor.z = 192; - pev->scale = 2.0; - m_nFrames = 1; - pev->renderamt = 255; - - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CNihilanth::HoverThink ); - SetTouch( &CNihilanthHVR::BounceTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - m_hTargetEnt = pTarget; -} - - -CBaseEntity *CNihilanthHVR::RandomClassname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByClassname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - -void CNihilanthHVR :: HoverThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (m_hTargetEnt != NULL) - { - CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 16 * N_SCALE ) ); - } - else - { - UTIL_Remove( this ); - } - - - if (RANDOM_LONG( 0, 99 ) < 5) - { -/* - CBaseEntity *pOther = RandomClassname( STRING(pev->classname) ); - - if (pOther && pOther != this) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( pOther->entindex() ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); - } -*/ -/* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); -*/ - } - - pev->frame = ((int)pev->frame + 1) % m_nFrames; -} - - - - -void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(edict(), "sprites/nhth1.spr"); - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->scale = 2.0; - - pev->velocity = (pEnemy->pev->origin - pev->origin).Normalize() * 200; - - m_hEnemy = pEnemy; - SetThink( &CNihilanthHVR::ZapThink ); - SetTouch( &CNihilanthHVR::ZapTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 ); -} - -void CNihilanthHVR :: ZapThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.05; - - // check world boundaries - if (m_hEnemy == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - if (pev->velocity.Length() < 2000) - { - pev->velocity = pev->velocity * 1.2; - } - - - // MovetoTarget( m_hEnemy->Center( ) ); - - if ((m_hEnemy->Center() - pev->origin).Length() < 256) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, edict(), &tr ); - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - if (pEntity != NULL && pEntity->pev->takedamage) - { - ClearMultiDamage( ); - pEntity->TraceAttack( pev, gSkillData.nihilanthZap, pev->velocity, &tr, DMG_SHOCK ); - ApplyMultiDamage( pev, pev ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 20 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 196 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - UTIL_EmitAmbientSound( edict(), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - - SetTouch( NULL ); - UTIL_Remove( this ); - pev->nextthink = gpGlobals->time + 0.2; - return; - } - - pev->frame = (int)(pev->frame + 1) % 11; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 128 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - // Crawl( ); -} - - -void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) -{ - UTIL_EmitAmbientSound( edict(), pev->origin, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, RANDOM_LONG( 90, 95 ) ); - - RadiusDamage( pev, pev, 50, CLASS_NONE, DMG_SHOCK ); - pev->velocity = pev->velocity * 0; - - /* - for (int i = 0; i < 10; i++) - { - Crawl( ); - } - */ - - SetTouch( NULL ); - UTIL_Remove( this ); - pev->nextthink = gpGlobals->time + 0.2; -} - - - -void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->velocity.z *= 0.2; - - SET_MODEL(edict(), "sprites/exit1.spr"); - - m_pNihilanth = pOwner; - m_hEnemy = pEnemy; - m_hTargetEnt = pTarget; - m_hTouch = pTouch; - - SetThink( &CNihilanthHVR::TeleportThink ); - SetTouch( &CNihilanthHVR::TeleportTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); -} - - -void CNihilanthHVR :: GreenBallInit( ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->scale = 1.0; - - SET_MODEL(edict(), "sprites/exit1.spr"); - - SetTouch( &CNihilanthHVR::RemoveTouch ); -} - - -void CNihilanthHVR :: TeleportThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - // check world boundaries - if (m_hEnemy == NULL || !m_hEnemy->IsAlive() || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); - return; - } - - if ((m_hEnemy->Center() - pev->origin).Length() < 128) - { - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); - - if (m_hTargetEnt != NULL) - m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - - if ( m_hTouch != NULL && m_hEnemy != NULL ) - m_hTouch->Touch( m_hEnemy ); - } - else - { - MovetoTarget( m_hEnemy->Center( ) ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 0 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 0 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 256 ); // decay - MESSAGE_END(); - - pev->frame = (int)(pev->frame + 1) % 20; -} - - -void CNihilanthHVR :: AbsorbInit( void ) -{ - SetThink( &CNihilanthHVR::DissipateThink ); - pev->renderamt = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 50 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); -} - -void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) -{ - CBaseEntity *pEnemy = m_hEnemy; - - if (pOther == pEnemy) - { - if (m_hTargetEnt != NULL) - m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); - - if (m_hTouch != NULL && pEnemy != NULL ) - m_hTouch->Touch( pEnemy ); - } - else - { - m_pNihilanth->MakeFriend( pev->origin ); - } - - SetTouch( NULL ); - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); -} - - -void CNihilanthHVR :: DissipateThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->scale > 5.0) - UTIL_Remove( this ); - - pev->renderamt -= 2; - pev->scale += 0.1; - - if (m_hTargetEnt != NULL) - { - CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 4096 ) ); - } - else - { - UTIL_Remove( this ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( pev->renderamt ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); -} - - -BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) -{ - BOOL fClose = FALSE; - - Vector vecDest = vecTarget; - Vector vecEst = pev->origin + pev->velocity * 0.5; - Vector vecSrc = pev->origin; - vecDest.z = 0; - vecEst.z = 0; - vecSrc.z = 0; - float d1 = (vecDest - vecSrc).Length() - 24 * N_SCALE; - float d2 = (vecDest - vecEst).Length() - 24 * N_SCALE; - - if (m_vecIdeal == Vector( 0, 0, 0 )) - { - m_vecIdeal = pev->velocity; - } - - if (d1 < 0 && d2 <= d1) - { - // ALERT( at_console, "too close\n"); - m_vecIdeal = m_vecIdeal - (vecDest - vecSrc).Normalize() * 50; - } - else if (d1 > 0 && d2 >= d1) - { - // ALERT( at_console, "too far\n"); - m_vecIdeal = m_vecIdeal + (vecDest - vecSrc).Normalize() * 50; - } - pev->avelocity.z = d1 * 20; - - if (d1 < 32) - { - fClose = TRUE; - } - - m_vecIdeal = m_vecIdeal + Vector( RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 )); - m_vecIdeal = Vector( m_vecIdeal.x, m_vecIdeal.y, 0 ).Normalize( ) * 200 - /* + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize( ) * 32 */ - + Vector( 0, 0, m_vecIdeal.z ); - // m_vecIdeal = m_vecIdeal + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize( ) * 2; - - // move up/down - d1 = vecTarget.z - pev->origin.z; - if (d1 > 0 && m_vecIdeal.z < 200) - m_vecIdeal.z += 20; - else if (d1 < 0 && m_vecIdeal.z > -200) - m_vecIdeal.z -= 20; - - pev->velocity = m_vecIdeal; - - // ALERT( at_console, "%.0f %.0f %.0f\n", m_vecIdeal.x, m_vecIdeal.y, m_vecIdeal.z ); - return fClose; -} - - -void CNihilanthHVR :: MovetoTarget( Vector vecTarget ) -{ - if (m_vecIdeal == Vector( 0, 0, 0 )) - { - m_vecIdeal = pev->velocity; - } - - // accelerate - float flSpeed = m_vecIdeal.Length(); - if (flSpeed > 300) - { - m_vecIdeal = m_vecIdeal.Normalize( ) * 300; - } - m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 300; - pev->velocity = m_vecIdeal; -} - - - - -void CNihilanthHVR :: Crawl( void ) -{ - - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); - Vector vecPnt = pev->origin + pev->velocity * 0.2 + vecAim * 128; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( vecPnt.x); - WRITE_COORD( vecPnt.y); - WRITE_COORD( vecPnt.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); -} - - -void CNihilanthHVR::RemoveTouch( CBaseEntity *pOther ) -{ - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); -} - -void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) -{ - Vector vecDir = m_vecIdeal.Normalize( ); - - TraceResult tr = UTIL_GetGlobalTrace( ); - - float n = -DotProduct(tr.vecPlaneNormal, vecDir); - - vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; - - m_vecIdeal = vecDir * m_vecIdeal.Length(); -} - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "effects.h" + +#define N_SCALE 15 +#define N_SPHERES 20 + +class CNihilanth : public CBaseMonster +{ +public: + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + int Classify( void ) { return CLASS_ALIEN_MILITARY; }; + int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } + void Killed( entvars_t *pevAttacker, int iGib ); + void GibMonster( void ); + + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -16 * N_SCALE, -16 * N_SCALE, -48 * N_SCALE ); + pev->absmax = pev->origin + Vector( 16 * N_SCALE, 16 * N_SCALE, 28 * N_SCALE ); + } + + void HandleAnimEvent( MonsterEvent_t *pEvent ); + + void EXPORT StartupThink( void ); + void EXPORT HuntThink( void ); + void EXPORT CrashTouch( CBaseEntity *pOther ); + void EXPORT DyingThink( void ); + void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT NullThink( void ); + void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + void FloatSequence( void ); + void NextActivity( void ); + + void Flight( void ); + + BOOL AbsorbSphere( void ); + BOOL EmitSphere( void ); + void TargetSphere( USE_TYPE useType, float value ); + CBaseEntity *RandomTargetname( const char *szName ); + void ShootBalls( void ); + void MakeFriend( Vector vecPos ); + + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + + void PainSound( void ); + void DeathSound( void ); + + static const char *pAttackSounds[]; // vocalization: play sometimes when he launches an attack + static const char *pBallSounds[]; // the sound of the lightening ball launch + static const char *pShootSounds[]; // grunting vocalization: play sometimes when he launches an attack + static const char *pRechargeSounds[]; // vocalization: play when he recharges + static const char *pLaughSounds[]; // vocalization: play sometimes when hit and still has lots of health + static const char *pPainSounds[]; // vocalization: play sometimes when hit and has much less health and no more chargers + static const char *pDeathSounds[]; // vocalization: play as he dies + + // x_teleattack1.wav the looping sound of the teleport attack ball. + + float m_flForce; + + float m_flNextPainSound; + + Vector m_velocity; + Vector m_avelocity; + + Vector m_vecTarget; + Vector m_posTarget; + + Vector m_vecDesired; + Vector m_posDesired; + + float m_flMinZ; + float m_flMaxZ; + + Vector m_vecGoal; + + float m_flLastSeen; + float m_flPrevSeen; + + int m_irritation; + + int m_iLevel; + int m_iTeleport; + + EHANDLE m_hRecharger; + + EHANDLE m_hSphere[N_SPHERES]; + int m_iActiveSpheres; + + float m_flAdj; + + CSprite *m_pBall; + + char m_szRechargerTarget[64]; + char m_szDrawUse[64]; + char m_szTeleportUse[64]; + char m_szTeleportTouch[64]; + char m_szDeadUse[64]; + char m_szDeadTouch[64]; + + float m_flShootEnd; + float m_flShootTime; + + EHANDLE m_hFriend[3]; +}; + +LINK_ENTITY_TO_CLASS( monster_nihilanth, CNihilanth ); + +TYPEDESCRIPTION CNihilanth::m_SaveData[] = +{ + DEFINE_FIELD( CNihilanth, m_flForce, FIELD_FLOAT ), + DEFINE_FIELD( CNihilanth, m_flNextPainSound, FIELD_TIME ), + DEFINE_FIELD( CNihilanth, m_velocity, FIELD_VECTOR ), + DEFINE_FIELD( CNihilanth, m_avelocity, FIELD_VECTOR ), + DEFINE_FIELD( CNihilanth, m_vecTarget, FIELD_VECTOR ), + DEFINE_FIELD( CNihilanth, m_posTarget, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CNihilanth, m_vecDesired, FIELD_VECTOR ), + DEFINE_FIELD( CNihilanth, m_posDesired, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CNihilanth, m_flMinZ, FIELD_FLOAT ), + DEFINE_FIELD( CNihilanth, m_flMaxZ, FIELD_FLOAT ), + DEFINE_FIELD( CNihilanth, m_vecGoal, FIELD_VECTOR ), + DEFINE_FIELD( CNihilanth, m_flLastSeen, FIELD_TIME ), + DEFINE_FIELD( CNihilanth, m_flPrevSeen, FIELD_TIME ), + DEFINE_FIELD( CNihilanth, m_irritation, FIELD_INTEGER ), + DEFINE_FIELD( CNihilanth, m_iLevel, FIELD_INTEGER ), + DEFINE_FIELD( CNihilanth, m_iTeleport, FIELD_INTEGER ), + DEFINE_FIELD( CNihilanth, m_hRecharger, FIELD_EHANDLE ), + DEFINE_ARRAY( CNihilanth, m_hSphere, FIELD_EHANDLE, N_SPHERES ), + DEFINE_FIELD( CNihilanth, m_iActiveSpheres, FIELD_INTEGER ), + DEFINE_FIELD( CNihilanth, m_flAdj, FIELD_FLOAT ), + DEFINE_FIELD( CNihilanth, m_pBall, FIELD_CLASSPTR ), + DEFINE_ARRAY( CNihilanth, m_szRechargerTarget, FIELD_CHARACTER, 64 ), + DEFINE_ARRAY( CNihilanth, m_szDrawUse, FIELD_CHARACTER, 64 ), + DEFINE_ARRAY( CNihilanth, m_szTeleportUse, FIELD_CHARACTER, 64 ), + DEFINE_ARRAY( CNihilanth, m_szTeleportTouch, FIELD_CHARACTER, 64 ), + DEFINE_ARRAY( CNihilanth, m_szDeadUse, FIELD_CHARACTER, 64 ), + DEFINE_ARRAY( CNihilanth, m_szDeadTouch, FIELD_CHARACTER, 64 ), + DEFINE_FIELD( CNihilanth, m_flShootEnd, FIELD_TIME ), + DEFINE_FIELD( CNihilanth, m_flShootTime, FIELD_TIME ), + DEFINE_ARRAY( CNihilanth, m_hFriend, FIELD_EHANDLE, 3 ), +}; + +IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ); + +class CNihilanthHVR : public CBaseMonster +{ +public: + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + + void CircleInit( CBaseEntity *pTarget ); + void AbsorbInit( void ); + void TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ); + void GreenBallInit( void ); + void ZapInit( CBaseEntity *pEnemy ); + + void EXPORT HoverThink( void ); + BOOL CircleTarget( Vector vecTarget ); + void EXPORT DissipateThink( void ); + + void EXPORT ZapThink( void ); + void EXPORT TeleportThink( void ); + void EXPORT TeleportTouch( CBaseEntity *pOther ); + + void EXPORT RemoveTouch( CBaseEntity *pOther ); + void EXPORT BounceTouch( CBaseEntity *pOther ); + void EXPORT ZapTouch( CBaseEntity *pOther ); + + CBaseEntity *RandomClassname( const char *szName ); + + // void EXPORT SphereUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + void MovetoTarget( Vector vecTarget ); + virtual void Crawl( void ); + + void Zap( void ); + void Teleport( void ); + + float m_flIdealVel; + Vector m_vecIdeal; + CNihilanth *m_pNihilanth; + EHANDLE m_hTouch; + int m_nFrames; +}; + +LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR ); + + +TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = +{ + DEFINE_FIELD( CNihilanthHVR, m_flIdealVel, FIELD_FLOAT ), + DEFINE_FIELD( CNihilanthHVR, m_vecIdeal, FIELD_VECTOR ), + DEFINE_FIELD( CNihilanthHVR, m_pNihilanth, FIELD_CLASSPTR ), + DEFINE_FIELD( CNihilanthHVR, m_hTouch, FIELD_EHANDLE ), + DEFINE_FIELD( CNihilanthHVR, m_nFrames, FIELD_INTEGER ), +}; + + +IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ); + + +//========================================================= +// Nihilanth, final Boss monster +//========================================================= + +const char *CNihilanth::pAttackSounds[] = +{ + "X/x_attack1.wav", + "X/x_attack2.wav", + "X/x_attack3.wav", +}; + +const char *CNihilanth::pBallSounds[] = +{ + "X/x_ballattack1.wav", +}; + +const char *CNihilanth::pShootSounds[] = +{ + "X/x_shoot1.wav", +}; + +const char *CNihilanth::pRechargeSounds[] = +{ + "X/x_recharge1.wav", + "X/x_recharge2.wav", + "X/x_recharge3.wav", +}; + +const char *CNihilanth::pLaughSounds[] = +{ + "X/x_laugh1.wav", + "X/x_laugh2.wav", +}; + +const char *CNihilanth::pPainSounds[] = +{ + "X/x_pain1.wav", + "X/x_pain2.wav", +}; + +const char *CNihilanth::pDeathSounds[] = +{ + "X/x_die1.wav", +}; + + +void CNihilanth :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(edict(), "models/nihilanth.mdl"); + // UTIL_SetSize(pev, Vector( -300, -300, 0), Vector(300, 300, 512)); + UTIL_SetSize(pev, Vector( -32, -32, 0), Vector(32, 32, 64)); + UTIL_SetOrigin( pev, pev->origin ); + + pev->flags |= FL_MONSTER; + pev->takedamage = DAMAGE_AIM; + pev->health = gSkillData.nihilanthHealth; + pev->view_ofs = Vector( 0, 0, 300 ); + + m_flFieldOfView = -1; // 360 degrees + + pev->sequence = 0; + ResetSequenceInfo( ); + + InitBoneControllers(); + + SetThink( &CNihilanth::StartupThink ); + pev->nextthink = gpGlobals->time + 0.1; + + m_vecDesired = Vector( 1, 0, 0 ); + m_posDesired = Vector( pev->origin.x, pev->origin.y, 512 ); + + m_iLevel = 1; + m_iTeleport = 1; + + if (m_szRechargerTarget[0] == '\0') strcpy( m_szRechargerTarget, "n_recharger" ); + if (m_szDrawUse[0] == '\0') strcpy( m_szDrawUse, "n_draw" ); + if (m_szTeleportUse[0] == '\0') strcpy( m_szTeleportUse, "n_leaving" ); + if (m_szTeleportTouch[0] == '\0') strcpy( m_szTeleportTouch, "n_teleport" ); + if (m_szDeadUse[0] == '\0') strcpy( m_szDeadUse, "n_dead" ); + if (m_szDeadTouch[0] == '\0') strcpy( m_szDeadTouch, "n_ending" ); + + // near death + /* + m_iTeleport = 10; + m_iLevel = 10; + m_irritation = 2; + pev->health = 100; + */ +} + + +void CNihilanth::Precache( void ) +{ + PRECACHE_MODEL("models/nihilanth.mdl"); + PRECACHE_MODEL("sprites/lgtning.spr"); + UTIL_PrecacheOther( "nihilanth_energy_ball" ); + UTIL_PrecacheOther( "monster_alien_controller" ); + UTIL_PrecacheOther( "monster_alien_slave" ); + + PRECACHE_SOUND_ARRAY( pAttackSounds ); + PRECACHE_SOUND_ARRAY( pBallSounds ); + PRECACHE_SOUND_ARRAY( pShootSounds ); + PRECACHE_SOUND_ARRAY( pRechargeSounds ); + PRECACHE_SOUND_ARRAY( pLaughSounds ); + PRECACHE_SOUND_ARRAY( pPainSounds ); + PRECACHE_SOUND_ARRAY( pDeathSounds ); + PRECACHE_SOUND("debris/beamstart7.wav"); +} + + + +void CNihilanth :: PainSound( void ) +{ + if (m_flNextPainSound > gpGlobals->time) + return; + + m_flNextPainSound = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); + + if (pev->health > gSkillData.nihilanthHealth / 2) + { + EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pLaughSounds ), 1.0, 0.2 ); + } + else if (m_irritation >= 2) + { + EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0, 0.2 ); + } +} + +void CNihilanth :: DeathSound( void ) +{ + EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1.0, 0.1 ); +} + + +void CNihilanth::NullThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.5; +} + + +void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( &CNihilanth::HuntThink ); + pev->nextthink = gpGlobals->time + 0.1; + SetUse( &CNihilanth::CommandUse ); +} + + +void CNihilanth::StartupThink( void ) +{ + m_irritation = 0; + m_flAdj = 512; + + CBaseEntity *pEntity; + + pEntity = UTIL_FindEntityByTargetname( NULL, "n_min"); + if (pEntity) + m_flMinZ = pEntity->pev->origin.z; + else + m_flMinZ = -4096; + + pEntity = UTIL_FindEntityByTargetname( NULL, "n_max"); + if (pEntity) + m_flMaxZ = pEntity->pev->origin.z; + else + m_flMaxZ = 4096; + + m_hRecharger = this; + for (int i = 0; i < N_SPHERES; i++) + { + EmitSphere( ); + } + m_hRecharger = NULL; + + SetThink( &CNihilanth::HuntThink); + SetUse( &CNihilanth::CommandUse ); + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CNihilanth :: Killed( entvars_t *pevAttacker, int iGib ) +{ + CBaseMonster::Killed( pevAttacker, iGib ); +} + +void CNihilanth :: DyingThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + DispatchAnimEvents( ); + StudioFrameAdvance( ); + + if (pev->deadflag == DEAD_NO) + { + DeathSound( ); + pev->deadflag = DEAD_DYING; + + m_posDesired.z = m_flMaxZ; + } + + if (pev->deadflag == DEAD_DYING) + { + Flight( ); + + if (fabs( pev->origin.z - m_flMaxZ ) < 16) + { + pev->velocity = Vector( 0, 0, 0 ); + FireTargets( m_szDeadUse, this, this, USE_ON, 1.0 ); + pev->deadflag = DEAD_DEAD; + } + } + + if (m_fSequenceFinished) + { + pev->avelocity.y += RANDOM_FLOAT( -100, 100 ); + if (pev->avelocity.y < -100) + pev->avelocity.y = -100; + if (pev->avelocity.y > 100) + pev->avelocity.y = 100; + + pev->sequence = LookupSequence( "die1" ); + } + + if (m_pBall) + { + if (m_pBall->pev->renderamt > 0) + { + m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2); + } + else + { + UTIL_Remove( m_pBall ); + m_pBall = NULL; + } + } + + Vector vecDir, vecSrc, vecAngles; + + UTIL_MakeAimVectors( pev->angles ); + int iAttachment = RANDOM_LONG( 1, 4 ); + + do { + vecDir = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 )); + } while (DotProduct( vecDir, vecDir) > 1.0); + + switch( RANDOM_LONG( 1, 4 )) + { + case 1: // head + vecDir.z = fabs( vecDir.z ) * 0.5; + vecDir = vecDir + 2 * gpGlobals->v_up; + break; + case 2: // eyes + if (DotProduct( vecDir, gpGlobals->v_forward ) < 0) + vecDir = vecDir * -1; + + vecDir = vecDir + 2 * gpGlobals->v_forward; + break; + case 3: // left hand + if (DotProduct( vecDir, gpGlobals->v_right ) > 0) + vecDir = vecDir * -1; + vecDir = vecDir - 2 * gpGlobals->v_right; + break; + case 4: // right hand + if (DotProduct( vecDir, gpGlobals->v_right ) < 0) + vecDir = vecDir * -1; + vecDir = vecDir + 2 * gpGlobals->v_right; + break; + } + + GetAttachment( iAttachment - 1, vecSrc, vecAngles ); + + TraceResult tr; + + UTIL_TraceLine( vecSrc, vecSrc + vecDir * 4096, ignore_monsters, ENT(pev), &tr ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTPOINT ); + WRITE_SHORT( entindex() + 0x1000 * iAttachment ); + WRITE_COORD( tr.vecEndPos.x); + WRITE_COORD( tr.vecEndPos.y); + WRITE_COORD( tr.vecEndPos.z); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 5 ); // life + WRITE_BYTE( 100 ); // width + WRITE_BYTE( 120 ); // noise + WRITE_BYTE( 64 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 255); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); + + GetAttachment( 0, vecSrc, vecAngles ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; + pEntity->GreenBallInit( ); + + return; +} + + + +void CNihilanth::CrashTouch( CBaseEntity *pOther ) +{ + // only crash if we hit something solid + if ( pOther->pev->solid == SOLID_BSP) + { + SetTouch( &CNihilanth::NULL ); + pev->nextthink = gpGlobals->time; + } +} + + + +void CNihilanth :: GibMonster( void ) +{ + // EMIT_SOUND_DYN(edict(), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); +} + + + +void CNihilanth :: FloatSequence( void ) +{ + if (m_irritation >= 2) + { + pev->sequence = LookupSequence( "float_open" ); + } + else if (m_avelocity.y > 30) + { + pev->sequence = LookupSequence( "walk_r" ); + } + else if (m_avelocity.y < -30) + { + pev->sequence = LookupSequence( "walk_l" ); + } + else if (m_velocity.z > 30) + { + pev->sequence = LookupSequence( "walk_u" ); + } + else if (m_velocity.z < -30) + { + pev->sequence = LookupSequence( "walk_d" ); + } + else + { + pev->sequence = LookupSequence( "float" ); + } +} + + +void CNihilanth :: ShootBalls( void ) +{ + if (m_flShootEnd > gpGlobals->time) + { + Vector vecHand, vecAngle; + + while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) + { + if (m_hEnemy != NULL) + { + Vector vecSrc, vecDir; + CNihilanthHVR *pEntity; + + GetAttachment( 2, vecHand, vecAngle ); + vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); + // vecDir = (m_posTarget - vecSrc).Normalize( ); + vecDir = (m_posTarget - pev->origin).Normalize( ); + vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); + pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = vecDir * 200.0; + pEntity->ZapInit( m_hEnemy ); + + GetAttachment( 3, vecHand, vecAngle ); + vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); + // vecDir = (m_posTarget - vecSrc).Normalize( ); + vecDir = (m_posTarget - pev->origin).Normalize( ); + vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); + pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = vecDir * 200.0; + pEntity->ZapInit( m_hEnemy ); + } + m_flShootTime += 0.2; + } + } +} + + +void CNihilanth :: MakeFriend( Vector vecStart ) +{ + int i; + + for (i = 0; i < 3; i++) + { + if (m_hFriend[i] != NULL && !m_hFriend[i]->IsAlive()) + { + if (pev->rendermode == kRenderNormal) // don't do it if they are already fading + m_hFriend[i]->MyMonsterPointer()->FadeMonster( ); + m_hFriend[i] = NULL; + } + + if (m_hFriend[i] == NULL) + { + if (RANDOM_LONG(0, 1) == 0) + { + int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_AIR ); + if (iNode != NO_NODE) + { + CNode &node = WorldGraph.Node( iNode ); + TraceResult tr; + UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 32 ), node.m_vecOrigin + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, NULL, &tr ); + if (tr.fStartSolid == 0) + m_hFriend[i] = Create("monster_alien_controller", node.m_vecOrigin, pev->angles ); + } + } + else + { + int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_LAND | bits_NODE_WATER ); + if (iNode != NO_NODE) + { + CNode &node = WorldGraph.Node( iNode ); + TraceResult tr; + UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 36 ), node.m_vecOrigin + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, NULL, &tr ); + if (tr.fStartSolid == 0) + m_hFriend[i] = Create("monster_alien_slave", node.m_vecOrigin, pev->angles ); + } + } + if (m_hFriend[i] != NULL) + { + EMIT_SOUND( m_hFriend[i]->edict(), CHAN_WEAPON, "debris/beamstart7.wav", 1.0, ATTN_NORM ); + } + + return; + } + } +} + + +void CNihilanth :: NextActivity( ) +{ + UTIL_MakeAimVectors( pev->angles ); + + if (m_irritation >= 2) + { + if (m_pBall == NULL) + { + m_pBall = CSprite::SpriteCreate( "sprites/tele1.spr", pev->origin, TRUE ); + if (m_pBall) + { + m_pBall->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); + m_pBall->SetAttachment( edict(), 1 ); + m_pBall->SetScale( 4.0 ); + m_pBall->pev->framerate = 10.0; + m_pBall->TurnOn( ); + } + } + + if (m_pBall) + { + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 256 ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 192 ); // G + WRITE_BYTE( 64 ); // B + WRITE_BYTE( 200 ); // life * 10 + WRITE_COORD( 0 ); // decay + MESSAGE_END(); + } + } + + if ((pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2) && m_hRecharger == NULL && m_iLevel <= 9) + { + char szName[64]; + + CBaseEntity *pEnt = NULL; + CBaseEntity *pRecharger = NULL; + float flDist = 8192; + + sprintf(szName, "%s%d", m_szRechargerTarget, m_iLevel ); + + while ((pEnt = UTIL_FindEntityByTargetname( pEnt, szName )) != NULL) + { + float flLocal = (pEnt->pev->origin - pev->origin).Length(); + if (flLocal < flDist) + { + flDist = flLocal; + pRecharger = pEnt; + } + } + + if (pRecharger) + { + m_hRecharger = pRecharger; + m_posDesired = Vector( pev->origin.x, pev->origin.y, pRecharger->pev->origin.z ); + m_vecDesired = (pRecharger->pev->origin - m_posDesired).Normalize( ); + m_vecDesired.z = 0; + m_vecDesired = m_vecDesired.Normalize(); + } + else + { + m_hRecharger = NULL; + ALERT( at_aiconsole, "nihilanth can't find %s\n", szName ); + m_iLevel++; + if (m_iLevel > 9) + m_irritation = 2; + } + } + + float flDist = (m_posDesired - pev->origin).Length(); + float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); + + if (m_hRecharger != NULL) + { + // at we at power up yet? + if (flDist < 128.0) + { + int iseq = LookupSequence( "recharge" ); + + if (iseq != pev->sequence) + { + char szText[64]; + + sprintf( szText, "%s%d", m_szDrawUse, m_iLevel ); + FireTargets( szText, this, this, USE_ON, 1.0 ); + + ALERT( at_console, "fireing %s\n", szText ); + } + pev->sequence = LookupSequence( "recharge" ); + } + else + { + FloatSequence( ); + } + return; + } + + if (m_hEnemy != NULL && !m_hEnemy->IsAlive()) + { + m_hEnemy = NULL; + } + + if (m_flLastSeen + 15 < gpGlobals->time) + { + m_hEnemy = NULL; + } + + if (m_hEnemy == NULL) + { + Look( 4096 ); + m_hEnemy = BestVisibleEnemy( ); + } + + if (m_hEnemy != NULL && m_irritation != 0) + { + if (m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0) + { + if (m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0) + { + pev->sequence = LookupSequence( "attack1_open" ); + } + else + { + if (RANDOM_LONG(0, 1 ) == 0) + { + pev->sequence = LookupSequence( "attack1" ); // zap + } + else + { + char szText[64]; + + sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); + CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); + + sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); + CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); + + if (pTrigger != NULL || pTouch != NULL) + { + pev->sequence = LookupSequence( "attack2" ); // teleport + } + else + { + m_iTeleport++; + pev->sequence = LookupSequence( "attack1" ); // zap + } + } + } + return; + } + } + + FloatSequence( ); +} + +void CNihilanth :: HuntThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + DispatchAnimEvents( ); + StudioFrameAdvance( ); + + ShootBalls( ); + + // if dead, force cancelation of current animation + if (pev->health <= 0) + { + SetThink( &CNihilanth::DyingThink ); + m_fSequenceFinished = TRUE; + return; + } + + // ALERT( at_console, "health %.0f\n", pev->health ); + + // if damaged, try to abosorb some spheres + if (pev->health < gSkillData.nihilanthHealth && AbsorbSphere( )) + { + pev->health += gSkillData.nihilanthHealth / N_SPHERES; + } + + // get new sequence + if (m_fSequenceFinished) + { + // if (!m_fSequenceLoops) + pev->frame = 0; + NextActivity( ); + ResetSequenceInfo( ); + pev->framerate = 2.0 - 1.0 * (pev->health / gSkillData.nihilanthHealth); + } + + // look for current enemy + if (m_hEnemy != NULL && m_hRecharger == NULL) + { + if (FVisible( m_hEnemy )) + { + if (m_flLastSeen < gpGlobals->time - 5) + m_flPrevSeen = gpGlobals->time; + m_flLastSeen = gpGlobals->time; + m_posTarget = m_hEnemy->pev->origin; + m_vecTarget = (m_posTarget - pev->origin).Normalize(); + m_vecDesired = m_vecTarget; + m_posDesired = Vector( pev->origin.x, pev->origin.y, m_posTarget.z + m_flAdj ); + } + else + { + m_flAdj = min( m_flAdj + 10, 1000 ); + } + } + + // don't go too high + if (m_posDesired.z > m_flMaxZ) + m_posDesired.z = m_flMaxZ; + + // don't go too low + if (m_posDesired.z < m_flMinZ) + m_posDesired.z = m_flMinZ; + + Flight( ); +} + + + +void CNihilanth :: Flight( void ) +{ + // estimate where I'll be facing in one seconds + UTIL_MakeAimVectors( pev->angles + m_avelocity ); + // Vector vecEst1 = pev->origin + m_velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); + // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); + + float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); + + if (flSide < 0) + { + if (m_avelocity.y < 180) + { + m_avelocity.y += 6; // 9 * (3.0/2.0); + } + } + else + { + if (m_avelocity.y > -180) + { + m_avelocity.y -= 6; // 9 * (3.0/2.0); + } + } + m_avelocity.y *= 0.98; + + // estimate where I'll be in two seconds + Vector vecEst = pev->origin + m_velocity * 2.0 + gpGlobals->v_up * m_flForce * 20; + + // add immediate force + UTIL_MakeAimVectors( pev->angles ); + m_velocity.x += gpGlobals->v_up.x * m_flForce; + m_velocity.y += gpGlobals->v_up.y * m_flForce; + m_velocity.z += gpGlobals->v_up.z * m_flForce; + + + float flSpeed = m_velocity.Length(); + float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( m_velocity.x, m_velocity.y, 0 ) ); + if (flDir < 0) + flSpeed = -flSpeed; + + float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); + + // sideways drag + m_velocity.x = m_velocity.x * (1.0 - fabs( gpGlobals->v_right.x ) * 0.05); + m_velocity.y = m_velocity.y * (1.0 - fabs( gpGlobals->v_right.y ) * 0.05); + m_velocity.z = m_velocity.z * (1.0 - fabs( gpGlobals->v_right.z ) * 0.05); + + // general drag + m_velocity = m_velocity * 0.995; + + // apply power to stay correct height + if (m_flForce < 100 && vecEst.z < m_posDesired.z) + { + m_flForce += 10; + } + else if (m_flForce > -100 && vecEst.z > m_posDesired.z) + { + if (vecEst.z > m_posDesired.z) + m_flForce -= 10; + } + + UTIL_SetOrigin( pev, pev->origin + m_velocity * 0.1 ); + pev->angles = pev->angles + m_avelocity * 0.1; + + // ALERT( at_console, "%5.0f %5.0f : %4.0f : %3.0f : %2.0f\n", m_posDesired.z, pev->origin.z, m_velocity.z, m_avelocity.y, m_flForce ); +} + + +BOOL CNihilanth :: AbsorbSphere( void ) +{ + for (int i = 0; i < N_SPHERES; i++) + { + if (m_hSphere[i] != NULL) + { + CNihilanthHVR *pSphere = (CNihilanthHVR *)((CBaseEntity *)m_hSphere[i]); + pSphere->AbsorbInit( ); + m_hSphere[i] = NULL; + m_iActiveSpheres--; + return TRUE; + } + } + return FALSE; +} + + +BOOL CNihilanth :: EmitSphere( void ) +{ + m_iActiveSpheres = 0; + int empty = 0; + + for (int i = 0; i < N_SPHERES; i++) + { + if (m_hSphere[i] != NULL) + { + m_iActiveSpheres++; + } + else + { + empty = i; + } + } + + if (m_iActiveSpheres >= N_SPHERES) + return FALSE; + + Vector vecSrc = m_hRecharger->pev->origin; + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = pev->origin - vecSrc; + pEntity->CircleInit( this ); + + m_hSphere[empty] = pEntity; + return TRUE; +} + + +void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) +{ + CBaseMonster *pSphere; + for (int i = 0; i < N_SPHERES; i++) + { + if (m_hSphere[i] != NULL) + { + pSphere = m_hSphere[i]->MyMonsterPointer(); + if (pSphere->m_hEnemy == NULL) + break; + } + } + if (i == N_SPHERES) + { + return; + } + + Vector vecSrc, vecAngles; + GetAttachment( 2, vecSrc, vecAngles ); + UTIL_SetOrigin( pSphere->pev, vecSrc ); + pSphere->Use( this, this, useType, value ); + pSphere->pev->velocity = m_vecDesired * RANDOM_FLOAT( 50, 100 ) + Vector( RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ) ); +} + + + +void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case 1: // shoot + break; + case 2: // zen + if (m_hEnemy != NULL) + { + if (RANDOM_LONG(0,4) == 0) + EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); + + EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 256 ); // radius + WRITE_BYTE( 128 ); // R + WRITE_BYTE( 128 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 128 ); // decay + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 256 ); // radius + WRITE_BYTE( 128 ); // R + WRITE_BYTE( 128 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 128 ); // decay + MESSAGE_END(); + + m_flShootTime = gpGlobals->time; + m_flShootEnd = gpGlobals->time + 1.0; + } + break; + case 3: // prayer + if (m_hEnemy != NULL) + { + char szText[32]; + + sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); + CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); + + sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); + CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); + + if (pTrigger != NULL || pTouch != NULL) + { + EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); + + Vector vecSrc, vecAngles; + GetAttachment( 2, vecSrc, vecAngles ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = pev->origin - vecSrc; + pEntity->TeleportInit( this, m_hEnemy, pTrigger, pTouch ); + } + else + { + m_iTeleport++; // unexpected failure + + EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); + + ALERT( at_aiconsole, "nihilanth can't target %s\n", szText ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 256 ); // radius + WRITE_BYTE( 128 ); // R + WRITE_BYTE( 128 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 128 ); // decay + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 256 ); // radius + WRITE_BYTE( 128 ); // R + WRITE_BYTE( 128 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 128 ); // decay + MESSAGE_END(); + + m_flShootTime = gpGlobals->time; + m_flShootEnd = gpGlobals->time + 1.0; + } + } + break; + case 4: // get a sphere + { + if (m_hRecharger != NULL) + { + if (!EmitSphere( )) + { + m_hRecharger = NULL; + } + } + } + break; + case 5: // start up sphere machine + { + EMIT_SOUND( edict(), CHAN_VOICE , RANDOM_SOUND_ARRAY( pRechargeSounds ), 1.0, 0.2 ); + } + break; + case 6: + if (m_hEnemy != NULL) + { + Vector vecSrc, vecAngles; + GetAttachment( 2, vecSrc, vecAngles ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = pev->origin - vecSrc; + pEntity->ZapInit( m_hEnemy ); + } + break; + case 7: + /* + Vector vecSrc, vecAngles; + GetAttachment( 0, vecSrc, vecAngles ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; + pEntity->GreenBallInit( ); + */ + break; + } +} + + + +void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + switch (useType) + { + case USE_OFF: + { + CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); + if ( pTouch && m_hEnemy != NULL ) + pTouch->Touch( m_hEnemy ); + } + break; + case USE_ON: + if (m_irritation == 0) + { + m_irritation = 1; + } + break; + case USE_SET: + break; + case USE_TOGGLE: + break; + } +} + + +int CNihilanth :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if (pevInflictor->owner == edict()) + return 0; + + if (flDamage >= pev->health) + { + pev->health = 1; + if (m_irritation != 3) + return 0; + } + + PainSound( ); + + pev->health -= flDamage; + return 0; +} + + + +void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if (m_irritation == 3) + m_irritation = 2; + + if (m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2) + m_irritation = 3; + + if (m_irritation != 3) + { + Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( ); + + UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + (100 - 100 * (pev->health / gSkillData.nihilanthHealth))); + } + + // SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage * 5.0);// a little surface blood. + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); +} + + + +CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) +{ + int total = 0; + + CBaseEntity *pEntity = NULL; + CBaseEntity *pNewEntity = NULL; + while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) + { + total++; + if (RANDOM_LONG(0,total-1) < 1) + pEntity = pNewEntity; + } + return pEntity; +} + + + + + + + + + +//========================================================= +// Controller bouncy ball attack +//========================================================= + + + +void CNihilanthHVR :: Spawn( void ) +{ + Precache( ); + + pev->rendermode = kRenderTransAdd; + pev->renderamt = 255; + pev->scale = 3.0; +} + + +void CNihilanthHVR :: Precache( void ) +{ + PRECACHE_MODEL("sprites/flare6.spr"); + PRECACHE_MODEL("sprites/nhth1.spr"); + PRECACHE_MODEL("sprites/exit1.spr"); + PRECACHE_MODEL("sprites/tele1.spr"); + PRECACHE_MODEL("sprites/animglow01.spr"); + PRECACHE_MODEL("sprites/xspark4.spr"); + PRECACHE_MODEL("sprites/muzzleflash3.spr"); + PRECACHE_SOUND("debris/zap4.wav"); + PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_SOUND("x/x_teleattack1.wav"); +} + + + +void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) +{ + pev->movetype = MOVETYPE_NOCLIP; + pev->solid = SOLID_NOT; + + // SET_MODEL(edict(), "sprites/flare6.spr"); + // pev->scale = 3.0; + // SET_MODEL(edict(), "sprites/xspark4.spr"); + SET_MODEL(edict(), "sprites/muzzleflash3.spr"); + pev->rendercolor.x = 255; + pev->rendercolor.y = 224; + pev->rendercolor.z = 192; + pev->scale = 2.0; + m_nFrames = 1; + pev->renderamt = 255; + + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetOrigin( pev, pev->origin ); + + SetThink( &CNihilanth::HoverThink ); + SetTouch( &CNihilanthHVR::BounceTouch ); + pev->nextthink = gpGlobals->time + 0.1; + + m_hTargetEnt = pTarget; +} + + +CBaseEntity *CNihilanthHVR::RandomClassname( const char *szName ) +{ + int total = 0; + + CBaseEntity *pEntity = NULL; + CBaseEntity *pNewEntity = NULL; + while ((pNewEntity = UTIL_FindEntityByClassname( pNewEntity, szName )) != NULL) + { + total++; + if (RANDOM_LONG(0,total-1) < 1) + pEntity = pNewEntity; + } + return pEntity; +} + +void CNihilanthHVR :: HoverThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if (m_hTargetEnt != NULL) + { + CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 16 * N_SCALE ) ); + } + else + { + UTIL_Remove( this ); + } + + + if (RANDOM_LONG( 0, 99 ) < 5) + { +/* + CBaseEntity *pOther = RandomClassname( STRING(pev->classname) ); + + if (pOther && pOther != this) + { + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTS ); + WRITE_SHORT( this->entindex() ); + WRITE_SHORT( pOther->entindex() ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // framestart + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 10 ); // life + WRITE_BYTE( 80 ); // width + WRITE_BYTE( 80 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 64 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 30 ); // speed + MESSAGE_END(); + } +*/ +/* + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTS ); + WRITE_SHORT( this->entindex() ); + WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // framestart + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 10 ); // life + WRITE_BYTE( 80 ); // width + WRITE_BYTE( 80 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 64 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 30 ); // speed + MESSAGE_END(); +*/ + } + + pev->frame = ((int)pev->frame + 1) % m_nFrames; +} + + + + +void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) +{ + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(edict(), "sprites/nhth1.spr"); + + pev->rendercolor.x = 255; + pev->rendercolor.y = 255; + pev->rendercolor.z = 255; + pev->scale = 2.0; + + pev->velocity = (pEnemy->pev->origin - pev->origin).Normalize() * 200; + + m_hEnemy = pEnemy; + SetThink( &CNihilanthHVR::ZapThink ); + SetTouch( &CNihilanthHVR::ZapTouch ); + pev->nextthink = gpGlobals->time + 0.1; + + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 ); +} + +void CNihilanthHVR :: ZapThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.05; + + // check world boundaries + if (m_hEnemy == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + { + SetTouch( NULL ); + UTIL_Remove( this ); + return; + } + + if (pev->velocity.Length() < 2000) + { + pev->velocity = pev->velocity * 1.2; + } + + + // MovetoTarget( m_hEnemy->Center( ) ); + + if ((m_hEnemy->Center() - pev->origin).Length() < 256) + { + TraceResult tr; + + UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, edict(), &tr ); + + CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + if (pEntity != NULL && pEntity->pev->takedamage) + { + ClearMultiDamage( ); + pEntity->TraceAttack( pev, gSkillData.nihilanthZap, pev->velocity, &tr, DMG_SHOCK ); + ApplyMultiDamage( pev, pev ); + } + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTPOINT ); + WRITE_SHORT( entindex() ); + WRITE_COORD( tr.vecEndPos.x ); + WRITE_COORD( tr.vecEndPos.y ); + WRITE_COORD( tr.vecEndPos.z ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 3 ); // life + WRITE_BYTE( 20 ); // width + WRITE_BYTE( 20 ); // noise + WRITE_BYTE( 64 ); // r, g, b + WRITE_BYTE( 196 ); // r, g, b + WRITE_BYTE( 255); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); + + UTIL_EmitAmbientSound( edict(), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); + + SetTouch( NULL ); + UTIL_Remove( this ); + pev->nextthink = gpGlobals->time + 0.2; + return; + } + + pev->frame = (int)(pev->frame + 1) % 11; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 128 ); // radius + WRITE_BYTE( 128 ); // R + WRITE_BYTE( 128 ); // G + WRITE_BYTE( 255 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 128 ); // decay + MESSAGE_END(); + + // Crawl( ); +} + + +void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) +{ + UTIL_EmitAmbientSound( edict(), pev->origin, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, RANDOM_LONG( 90, 95 ) ); + + RadiusDamage( pev, pev, 50, CLASS_NONE, DMG_SHOCK ); + pev->velocity = pev->velocity * 0; + + /* + for (int i = 0; i < 10; i++) + { + Crawl( ); + } + */ + + SetTouch( NULL ); + UTIL_Remove( this ); + pev->nextthink = gpGlobals->time + 0.2; +} + + + +void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) +{ + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + pev->rendercolor.x = 255; + pev->rendercolor.y = 255; + pev->rendercolor.z = 255; + pev->velocity.z *= 0.2; + + SET_MODEL(edict(), "sprites/exit1.spr"); + + m_pNihilanth = pOwner; + m_hEnemy = pEnemy; + m_hTargetEnt = pTarget; + m_hTouch = pTouch; + + SetThink( &CNihilanthHVR::TeleportThink ); + SetTouch( &CNihilanthHVR::TeleportTouch ); + pev->nextthink = gpGlobals->time + 0.1; + + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); +} + + +void CNihilanthHVR :: GreenBallInit( ) +{ + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + pev->rendercolor.x = 255; + pev->rendercolor.y = 255; + pev->rendercolor.z = 255; + pev->scale = 1.0; + + SET_MODEL(edict(), "sprites/exit1.spr"); + + SetTouch( &CNihilanthHVR::RemoveTouch ); +} + + +void CNihilanthHVR :: TeleportThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + // check world boundaries + if (m_hEnemy == NULL || !m_hEnemy->IsAlive() || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + { + STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); + UTIL_Remove( this ); + return; + } + + if ((m_hEnemy->Center() - pev->origin).Length() < 128) + { + STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); + UTIL_Remove( this ); + + if (m_hTargetEnt != NULL) + m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); + + if ( m_hTouch != NULL && m_hEnemy != NULL ) + m_hTouch->Touch( m_hEnemy ); + } + else + { + MovetoTarget( m_hEnemy->Center( ) ); + } + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( 256 ); // radius + WRITE_BYTE( 0 ); // R + WRITE_BYTE( 255 ); // G + WRITE_BYTE( 0 ); // B + WRITE_BYTE( 10 ); // life * 10 + WRITE_COORD( 256 ); // decay + MESSAGE_END(); + + pev->frame = (int)(pev->frame + 1) % 20; +} + + +void CNihilanthHVR :: AbsorbInit( void ) +{ + SetThink( &CNihilanthHVR::DissipateThink ); + pev->renderamt = 255; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTS ); + WRITE_SHORT( this->entindex() ); + WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // framestart + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 50 ); // life + WRITE_BYTE( 80 ); // width + WRITE_BYTE( 80 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 64 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 30 ); // speed + MESSAGE_END(); +} + +void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) +{ + CBaseEntity *pEnemy = m_hEnemy; + + if (pOther == pEnemy) + { + if (m_hTargetEnt != NULL) + m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); + + if (m_hTouch != NULL && pEnemy != NULL ) + m_hTouch->Touch( pEnemy ); + } + else + { + m_pNihilanth->MakeFriend( pev->origin ); + } + + SetTouch( NULL ); + STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); + UTIL_Remove( this ); +} + + +void CNihilanthHVR :: DissipateThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if (pev->scale > 5.0) + UTIL_Remove( this ); + + pev->renderamt -= 2; + pev->scale += 0.1; + + if (m_hTargetEnt != NULL) + { + CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 4096 ) ); + } + else + { + UTIL_Remove( this ); + } + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_COORD( pev->origin.x ); // origin + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_COORD( pev->renderamt ); // radius + WRITE_BYTE( 255 ); // R + WRITE_BYTE( 192 ); // G + WRITE_BYTE( 64 ); // B + WRITE_BYTE( 2 ); // life * 10 + WRITE_COORD( 0 ); // decay + MESSAGE_END(); +} + + +BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) +{ + BOOL fClose = FALSE; + + Vector vecDest = vecTarget; + Vector vecEst = pev->origin + pev->velocity * 0.5; + Vector vecSrc = pev->origin; + vecDest.z = 0; + vecEst.z = 0; + vecSrc.z = 0; + float d1 = (vecDest - vecSrc).Length() - 24 * N_SCALE; + float d2 = (vecDest - vecEst).Length() - 24 * N_SCALE; + + if (m_vecIdeal == Vector( 0, 0, 0 )) + { + m_vecIdeal = pev->velocity; + } + + if (d1 < 0 && d2 <= d1) + { + // ALERT( at_console, "too close\n"); + m_vecIdeal = m_vecIdeal - (vecDest - vecSrc).Normalize() * 50; + } + else if (d1 > 0 && d2 >= d1) + { + // ALERT( at_console, "too far\n"); + m_vecIdeal = m_vecIdeal + (vecDest - vecSrc).Normalize() * 50; + } + pev->avelocity.z = d1 * 20; + + if (d1 < 32) + { + fClose = TRUE; + } + + m_vecIdeal = m_vecIdeal + Vector( RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 )); + m_vecIdeal = Vector( m_vecIdeal.x, m_vecIdeal.y, 0 ).Normalize( ) * 200 + /* + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize( ) * 32 */ + + Vector( 0, 0, m_vecIdeal.z ); + // m_vecIdeal = m_vecIdeal + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize( ) * 2; + + // move up/down + d1 = vecTarget.z - pev->origin.z; + if (d1 > 0 && m_vecIdeal.z < 200) + m_vecIdeal.z += 20; + else if (d1 < 0 && m_vecIdeal.z > -200) + m_vecIdeal.z -= 20; + + pev->velocity = m_vecIdeal; + + // ALERT( at_console, "%.0f %.0f %.0f\n", m_vecIdeal.x, m_vecIdeal.y, m_vecIdeal.z ); + return fClose; +} + + +void CNihilanthHVR :: MovetoTarget( Vector vecTarget ) +{ + if (m_vecIdeal == Vector( 0, 0, 0 )) + { + m_vecIdeal = pev->velocity; + } + + // accelerate + float flSpeed = m_vecIdeal.Length(); + if (flSpeed > 300) + { + m_vecIdeal = m_vecIdeal.Normalize( ) * 300; + } + m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 300; + pev->velocity = m_vecIdeal; +} + + + + +void CNihilanthHVR :: Crawl( void ) +{ + + Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); + Vector vecPnt = pev->origin + pev->velocity * 0.2 + vecAim * 128; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMENTPOINT ); + WRITE_SHORT( entindex() ); + WRITE_COORD( vecPnt.x); + WRITE_COORD( vecPnt.y); + WRITE_COORD( vecPnt.z); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // frame start + WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 3 ); // life + WRITE_BYTE( 20 ); // width + WRITE_BYTE( 80 ); // noise + WRITE_BYTE( 64 ); // r, g, b + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 255); // r, g, b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 10 ); // speed + MESSAGE_END(); +} + + +void CNihilanthHVR::RemoveTouch( CBaseEntity *pOther ) +{ + STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); + UTIL_Remove( this ); +} + +void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) +{ + Vector vecDir = m_vecIdeal.Normalize( ); + + TraceResult tr = UTIL_GetGlobalTrace( ); + + float n = -DotProduct(tr.vecPlaneNormal, vecDir); + + vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; + + m_vecIdeal = vecDir * m_vecIdeal.Length(); +} + + + #endif \ No newline at end of file diff --git a/main/source/dlls/nodes.cpp b/main/source/dlls/nodes.cpp index 807a9c52..bd3c7a37 100644 --- a/main/source/dlls/nodes.cpp +++ b/main/source/dlls/nodes.cpp @@ -1,3642 +1,3642 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// nodes.cpp - AI node tree stuff. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "nodes.h" -#include "animation.h" -#include "doors.h" -#include "mod/AvHConstants.h" - -#define HULL_STEP_SIZE 16// how far the test hull moves on each step -#define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier) - -// to help eliminate node clutter by level designers, this is used to cap how many other nodes -// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()". -#define MAX_NODE_INITIAL_LINKS 128 -#define MAX_NODES 1024 - -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; - -Vector VecBModelOrigin( entvars_t* pevBModel ); - -CGraph WorldGraph; - -LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); -LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); -#ifdef __linux__ -#include -#include -#define CreateDirectory(p, n) mkdir(p, 0777) -#endif -//========================================================= -// CGraph - InitGraph - prepares the graph for use. Frees any -// memory currently in use by the world graph, NULLs -// all pointers, and zeros the node count. -//========================================================= -void CGraph :: InitGraph( void) -{ - - // Make the graph unavailable - // - m_fGraphPresent = FALSE; - m_fGraphPointersSet = FALSE; - m_fRoutingComplete = FALSE; - - // Free the link pool - // - if ( m_pLinkPool ) - { - free ( m_pLinkPool ); - m_pLinkPool = NULL; - } - - // Free the node info - // - if ( m_pNodes ) - { - free ( m_pNodes ); - m_pNodes = NULL; - } - - if ( m_di ) - { - free ( m_di ); - m_di = NULL; - } - - // Free the routing info. - // - if ( m_pRouteInfo ) - { - free ( m_pRouteInfo ); - m_pRouteInfo = NULL; - } - - if (m_pHashLinks) - { - free(m_pHashLinks); - m_pHashLinks = NULL; - } - - // Zero node and link counts - // - m_cNodes = 0; - m_cLinks = 0; - m_nRouteInfo = 0; - - m_iLastActiveIdleSearch = 0; - m_iLastCoverSearch = 0; -} - -//========================================================= -// CGraph - AllocNodes - temporary function that mallocs a -// reasonable number of nodes so we can build the path which -// will be saved to disk. -//========================================================= -int CGraph :: AllocNodes ( void ) -{ -// malloc all of the nodes - WorldGraph.m_pNodes = (CNode *)calloc ( sizeof ( CNode ), MAX_NODES ); - -// could not malloc space for all the nodes! - if ( !WorldGraph.m_pNodes ) - { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", WorldGraph.m_cNodes ); - return FALSE; - } - - return TRUE; -} - -//========================================================= -// CGraph - LinkEntForLink - sometimes the ent that blocks -// a path is a usable door, in which case the monster just -// needs to face the door and fire it. In other cases, the -// monster needs to operate a button or lever to get the -// door to open. This function will return a pointer to the -// button if the monster needs to hit a button to open the -// door, or returns a pointer to the door if the monster -// need only use the door. -// -// pNode is the node the monster will be standing on when it -// will need to stop and trigger the ent. -//========================================================= -entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) -{ - edict_t *pentSearch; - edict_t *pentTrigger; - entvars_t *pevTrigger; - entvars_t *pevLinkEnt; - TraceResult tr; - - pevLinkEnt = pLink->m_pLinkEnt; - if ( !pevLinkEnt ) - return NULL; - - pentSearch = NULL;// start search at the top of the ent list. - - if ( FClassnameIs ( pevLinkEnt, kesFuncDoor ) || FClassnameIs ( pevLinkEnt, "func_door_rotating" ) ) - { - - ///!!!UNDONE - check for TOGGLE or STAY open doors here. If a door is in the way, and is - // TOGGLE or STAY OPEN, even monsters that can't open doors can go that way. - - if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) - {// door is use only, so the door is all the monster has to worry about - return pevLinkEnt; - } - - while ( 1 ) - { - pentTrigger = FIND_ENTITY_BY_TARGET ( pentSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger - - if ( FNullEnt( pentTrigger ) ) - {// no trigger found - - // right now this is a problem among auto-open doors, or any door that opens through the use - // of a trigger brush. Trigger brushes have no models, and don't show up in searches. Just allow - // monsters to open these sorts of doors for now. - return pevLinkEnt; - } - - pentSearch = pentTrigger; - pevTrigger = VARS( pentTrigger ); - - if ( FClassnameIs(pevTrigger, "func_button") || FClassnameIs(pevTrigger, "func_rot_button" ) ) - {// only buttons are handled right now. - - // trace from the node to the trigger, make sure it's one we can see from the node. - // !!!HACKHACK Use bodyqueue here cause there are no ents we really wish to ignore! - UTIL_TraceLine ( pNode->m_vecOrigin, VecBModelOrigin( pevTrigger ), ignore_monsters, g_pBodyQueueHead, &tr ); - - - if ( VARS(tr.pHit) == pevTrigger ) - {// good to go! - return VARS( tr.pHit ); - } - } - } - } - else - { - ALERT ( at_aiconsole, "Unsupported PathEnt:\n'%s'\n", STRING ( pevLinkEnt->classname ) ); - return NULL; - } -} - -//========================================================= -// CGraph - HandleLinkEnt - a brush ent is between two -// nodes that would otherwise be able to see each other. -// Given the monster's capability, determine whether -// or not the monster can go this way. -//========================================================= -int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ) -{ - edict_t *pentWorld; - CBaseEntity *pDoor; - TraceResult tr; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return FALSE; - } - - if ( FNullEnt ( pevLinkEnt ) ) - { - ALERT ( at_aiconsole, "dead path ent!\n" ); - return TRUE; - } - pentWorld = NULL; - -// func_door - if ( FClassnameIs( pevLinkEnt, kesFuncDoor ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) - {// ent is a door. - - pDoor = ( CBaseEntity::Instance( pevLinkEnt ) ); - - if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) - {// door is use only. - - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) - {// let monster right through if he can open doors - return TRUE; - } - else - { - // monster should try for it if the door is open and looks as if it will stay that way - if ( pDoor->GetToggleState()== TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) - { - return TRUE; - } - - return FALSE; - } - } - else - {// door must be opened with a button or trigger field. - - // monster should try for it if the door is open and looks as if it will stay that way - if ( pDoor->GetToggleState() == TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) - { - return TRUE; - } - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) - { - if ( !( pevLinkEnt->spawnflags & SF_DOOR_NOMONSTERS ) || queryType == NODEGRAPH_STATIC ) - return TRUE; - } - - return FALSE; - } - } -// func_breakable - else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) - { - return TRUE; - } - else - { - ALERT ( at_aiconsole, "Unhandled Ent in Path %s\n", STRING( pevLinkEnt->classname ) ); - return FALSE; - } - - return FALSE; -} - -#if 0 -//========================================================= -// FindNearestLink - finds the connection (line) nearest -// the given point. Returns FALSE if fails, or TRUE if it -// has stuffed the index into the nearest link pool connection -// into the passed int pointer, and a BOOL telling whether or -// not the point is along the line into the passed BOOL pointer. -//========================================================= -int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine ) -{ - int i, j;// loops - - int iNearestLink;// index into the link pool, this is the nearest node at any time. - float flMinDist;// the distance of of the nearest case so far - float flDistToLine;// the distance of the current test case - - BOOL fCurrentAlongLine; - BOOL fSuccess; - - //float flConstant;// line constant - Vector vecSpot1, vecSpot2; - Vector2D vec2Spot1, vec2Spot2, vec2TestPoint; - Vector2D vec2Normal;// line normal - Vector2D vec2Line; - - TraceResult tr; - - iNearestLink = -1;// prepare for failure - fSuccess = FALSE; - - flMinDist = 9999;// anything will be closer than this - -// go through all of the nodes, and each node's connections - int cSkip = 0;// how many links proper pairing allowed us to skip - int cChecked = 0;// how many links were checked - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - vecSpot1 = m_pNodes[ i ].m_vecOrigin; - - if ( m_pNodes[ i ].m_cNumLinks <= 0 ) - {// this shouldn't happen! - ALERT ( at_aiconsole, "**Node %d has no links\n", i ); - continue; - } - - for ( j = 0 ; j < m_pNodes[ i ].m_cNumLinks ; j++ ) - { - /* - !!!This optimization only works when the node graph consists of properly linked pairs. - if ( INodeLink ( i, j ) <= i ) - { - // since we're going through the nodes in order, don't check - // any connections whose second node is lower in the list - // than the node we're currently working with. This eliminates - // redundant checks. - cSkip++; - continue; - } - */ - - vecSpot2 = PNodeLink ( i, j )->m_vecOrigin; - - // these values need a little attention now and then, or sometimes ramps cause trouble. - if ( fabs ( vecSpot1.z - vecTestPoint.z ) > 48 && fabs ( vecSpot2.z - vecTestPoint.z ) > 48 ) - { - // if both endpoints of the line are 32 units or more above or below the monster, - // the monster won't be able to get to them, so we do a bit of trivial rejection here. - // this may change if monsters are allowed to jump down. - // - // !!!LATER: some kind of clever X/Y hashing should be used here, too - continue; - } - -// now we have two endpoints for a line segment that we've not already checked. -// since all lines that make it this far are within -/+ 32 units of the test point's -// Z Plane, we can get away with doing the point->line check in 2d. - - cChecked++; - - vec2Spot1 = vecSpot1.Make2D(); - vec2Spot2 = vecSpot2.Make2D(); - vec2TestPoint = vecTestPoint.Make2D(); - - // get the line normal. - vec2Line = ( vec2Spot1 - vec2Spot2 ).Normalize(); - vec2Normal.x = -vec2Line.y; - vec2Normal.y = vec2Line.x; - - if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot1 ) ) > 0 ) - {// point outside of line - flDistToLine = ( vec2TestPoint - vec2Spot1 ).Length(); - fCurrentAlongLine = FALSE; - } - else if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot2 ) ) < 0 ) - {// point outside of line - flDistToLine = ( vec2TestPoint - vec2Spot2 ).Length(); - fCurrentAlongLine = FALSE; - } - else - {// point inside line - flDistToLine = fabs( DotProduct ( vec2TestPoint - vec2Spot2, vec2Normal ) ); - fCurrentAlongLine = TRUE; - } - - if ( flDistToLine < flMinDist ) - {// just found a line nearer than any other so far - - UTIL_TraceLine ( vecTestPoint, SourceNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); - - if ( tr.flFraction != 1.0 ) - {// crap. can't see the first node of this link, try to see the other - - UTIL_TraceLine ( vecTestPoint, DestNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); - if ( tr.flFraction != 1.0 ) - {// can't use this link, cause can't see either node! - continue; - } - - } - - fSuccess = TRUE;// we know there will be something to return. - flMinDist = flDistToLine; - iNearestLink = m_pNodes [ i ].m_iFirstLink + j; - *piNearestLink = m_pNodes[ i ].m_iFirstLink + j; - *pfAlongLine = fCurrentAlongLine; - } - } - } - -/* - if ( fSuccess ) - { - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); - - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.x ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.y ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.z + NODE_HEIGHT); - - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.x ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.y ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.z + NODE_HEIGHT); - } -*/ - - ALERT ( at_aiconsole, "%d Checked\n", cChecked ); - return fSuccess; -} - -#endif - -int CGraph::HullIndex( const CBaseEntity *pEntity ) -{ - if ( pEntity->pev->movetype == MOVETYPE_FLY) - return NODE_FLY_HULL; - - if ( pEntity->pev->mins == Vector( -12, -12, 0 ) ) - return NODE_SMALL_HULL; - else if ( pEntity->pev->mins == VEC_HUMAN_HULL_MIN ) - return NODE_HUMAN_HULL; - else if ( pEntity->pev->mins == Vector ( -32, -32, 0 ) ) - return NODE_LARGE_HULL; - -// ALERT ( at_aiconsole, "Unknown Hull Mins!\n" ); - return NODE_HUMAN_HULL; -} - - -int CGraph::NodeType( const CBaseEntity *pEntity ) -{ - if ( pEntity->pev->movetype == MOVETYPE_FLY) - { - if (pEntity->pev->waterlevel != 0) - { - return bits_NODE_WATER; - } - else - { - return bits_NODE_AIR; - } - } - return bits_NODE_LAND; -} - - -// Sum up graph weights on the path from iStart to iDest to determine path length -float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) -{ - float distance = 0; - int iNext; - - int iMaxLoop = m_cNodes; - - int iCurrentNode = iStart; - int iCap = CapIndex( afCapMask ); - - while (iCurrentNode != iDest) - { - if (iMaxLoop-- <= 0) - { - ALERT( at_console, "Route Failure\n" ); - return 0; - } - - iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); - if (iCurrentNode == iNext) - { - //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); - return 0; - } - - int iLink; - HashSearch(iCurrentNode, iNext, iLink); - if (iLink < 0) - { - ALERT(at_console, "HashLinks is broken from %d to %d.\n", iCurrentNode, iDest); - return 0; - } - CLink &link = Link(iLink); - distance += link.m_flWeight; - - iCurrentNode = iNext; - } - - return distance; -} - - -// Parse the routing table at iCurrentNode for the next node on the shortest path to iDest -int CGraph::NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ) -{ - int iNext = iCurrentNode; - int nCount = iDest+1; - char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; - - // Until we decode the next best node - // - while (nCount > 0) - { - char ch = *pRoute++; - //ALERT(at_aiconsole, "C(%d)", ch); - if (ch < 0) - { - // Sequence phrase - // - ch = -ch; - if (nCount <= ch) - { - iNext = iDest; - nCount = 0; - //ALERT(at_aiconsole, "SEQ: iNext/iDest=%d\n", iNext); - } - else - { - //ALERT(at_aiconsole, "SEQ: nCount + ch (%d + %d)\n", nCount, ch); - nCount = nCount - ch; - } - } - else - { - //ALERT(at_aiconsole, "C(%d)", *pRoute); - - // Repeat phrase - // - if (nCount <= ch+1) - { - iNext = iCurrentNode + *pRoute; - if (iNext >= m_cNodes) iNext -= m_cNodes; - else if (iNext < 0) iNext += m_cNodes; - nCount = 0; - //ALERT(at_aiconsole, "REP: iNext=%d\n", iNext); - } - else - { - //ALERT(at_aiconsole, "REP: nCount - ch+1 (%d - %d+1)\n", nCount, ch); - nCount = nCount - ch - 1; - } - pRoute++; - } - } - - return iNext; -} - - -//========================================================= -// CGraph - FindShortestPath -// -// accepts a capability mask (afCapMask), and will only -// find a path usable by a monster with those capabilities -// returns the number of nodes copied into supplied array -//========================================================= -int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask) -{ - int iVisitNode; - int iCurrentNode; - int iNumPathNodes; - int iHullMask; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return FALSE; - } - - if ( iStart < 0 || iStart > m_cNodes ) - {// The start node is bad? - ALERT ( at_aiconsole, "Can't build a path, iStart is %d!\n", iStart ); - return FALSE; - } - - if (iStart == iDest) - { - piPath[0] = iStart; - piPath[1] = iDest; - return 2; - } - - // Is routing information present. - // - if (m_fRoutingComplete) - { - int iCap = CapIndex( afCapMask ); - - iNumPathNodes = 0; - piPath[iNumPathNodes++] = iStart; - iCurrentNode = iStart; - int iNext; - - //ALERT(at_aiconsole, "GOAL: %d to %d\n", iStart, iDest); - - // Until we arrive at the destination - // - while (iCurrentNode != iDest) - { - iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); - if (iCurrentNode == iNext) - { - //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); - return 0; - break; - } - if (iNumPathNodes >= MAX_PATH_SIZE) - { - //ALERT(at_aiconsole, "SVD: Don't return the entire path.\n"); - break; - } - piPath[iNumPathNodes++] = iNext; - iCurrentNode = iNext; - } - //ALERT( at_aiconsole, "SVD: Path with %d nodes.\n", iNumPathNodes); - } - else - { - CQueuePriority queue; - - switch( iHull ) - { - case NODE_SMALL_HULL: - iHullMask = bits_LINK_SMALL_HULL; - break; - case NODE_HUMAN_HULL: - iHullMask = bits_LINK_HUMAN_HULL; - break; - case NODE_LARGE_HULL: - iHullMask = bits_LINK_LARGE_HULL; - break; - case NODE_FLY_HULL: - iHullMask = bits_LINK_FLY_HULL; - break; - } - - // Mark all the nodes as unvisited. - // - for ( int i = 0; i < m_cNodes; i++) - { - m_pNodes[ i ].m_flClosestSoFar = -1.0; - } - - m_pNodes[ iStart ].m_flClosestSoFar = 0.0; - m_pNodes[ iStart ].m_iPreviousNode = iStart;// tag this as the origin node - queue.Insert( iStart, 0.0 );// insert start node - - while ( !queue.Empty() ) - { - // now pull a node out of the queue - float flCurrentDistance; - iCurrentNode = queue.Remove(flCurrentDistance); - - // For straight-line weights, the following Shortcut works. For arbitrary weights, - // it doesn't. - // - if (iCurrentNode == iDest) break; - - CNode *pCurrentNode = &m_pNodes[ iCurrentNode ]; - - for ( i = 0 ; i < pCurrentNode->m_cNumLinks ; i++ ) - {// run through all of this node's neighbors - - iVisitNode = INodeLink ( iCurrentNode, i ); - if ( ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo & iHullMask ) != iHullMask ) - {// monster is too large to walk this connection - //ALERT ( at_aiconsole, "fat ass %d/%d\n",m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo, iMonsterHull ); - continue; - } - // check the connection from the current node to the node we're about to mark visited and push into the queue - if ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt != NULL ) - {// there's a brush ent in the way! Don't mark this node or put it into the queue unless the monster can negotiate it - - if ( !HandleLinkEnt ( iCurrentNode, m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt, afCapMask, NODEGRAPH_STATIC ) ) - {// monster should not try to go this way. - continue; - } - } - float flOurDistance = flCurrentDistance + m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i].m_flWeight; - if ( m_pNodes[ iVisitNode ].m_flClosestSoFar < -0.5 - || flOurDistance < m_pNodes[ iVisitNode ].m_flClosestSoFar - 0.001 ) - { - m_pNodes[iVisitNode].m_flClosestSoFar = flOurDistance; - m_pNodes[iVisitNode].m_iPreviousNode = iCurrentNode; - - queue.Insert ( iVisitNode, flOurDistance ); - } - } - } - if ( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) - {// Destination is unreachable, no path found. - return 0; - } - - // the queue is not empty - - // now we must walk backwards through the m_iPreviousNode field, and count how many connections there are in the path - iCurrentNode = iDest; - iNumPathNodes = 1;// count the dest - - while ( iCurrentNode != iStart ) - { - iNumPathNodes++; - iCurrentNode = m_pNodes[ iCurrentNode ].m_iPreviousNode; - } - - iCurrentNode = iDest; - for ( i = iNumPathNodes - 1 ; i >= 0 ; i-- ) - { - piPath[ i ] = iCurrentNode; - iCurrentNode = m_pNodes [ iCurrentNode ].m_iPreviousNode; - } - } - -#if 0 - - if (m_fRoutingComplete) - { - // This will draw the entire path that was generated for the monster. - - for ( int i = 0 ; i < iNumPathNodes - 1 ; i++ ) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.z + NODE_HEIGHT ); - MESSAGE_END(); - } - } - -#endif -#if 0 // MAZE map - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.z + NODE_HEIGHT ); - MESSAGE_END(); -#endif - - return iNumPathNodes; -} - -inline ULONG Hash(void *p, int len) -{ - CRC32_t ulCrc; - CRC32_INIT(&ulCrc); - CRC32_PROCESS_BUFFER(&ulCrc, p, len); - return CRC32_FINAL(ulCrc); -} - -void inline CalcBounds(int &Lower, int &Upper, int Goal, int Best) -{ - int Temp = 2*Goal - Best; - if (Best > Goal) - { - Lower = max(0, Temp); - Upper = Best; - } - else - { - Upper = min(255, Temp); - Lower = Best; - } -} - -// Convert from [-8192,8192] to [0, 255] -// -inline int CALC_RANGE(int x, int lower, int upper) -{ - return NUM_RANGES*(x-lower)/((upper-lower+1)); -} - - -void inline UpdateRange(int &minValue, int &maxValue, int Goal, int Best) -{ - int Lower, Upper; - CalcBounds(Lower, Upper, Goal, Best); - if (Upper < maxValue) maxValue = Upper; - if (minValue < Lower) minValue = Lower; -} - -void CGraph :: CheckNode(Vector vecOrigin, int iNode) -{ - // Have we already seen this point before?. - // - if (m_di[iNode].m_CheckedEvent == m_CheckedCounter) return; - m_di[iNode].m_CheckedEvent = m_CheckedCounter; - - float flDist = ( vecOrigin - m_pNodes[ iNode ].m_vecOriginPeek ).Length(); - - if ( flDist < m_flShortest ) - { - TraceResult tr; - - // make sure that vecOrigin can trace to this node! - UTIL_TraceLine ( vecOrigin, m_pNodes[ iNode ].m_vecOriginPeek, ignore_monsters, 0, &tr ); - - if ( tr.flFraction == 1.0 ) - { - m_iNearest = iNode; - m_flShortest = flDist; - - UpdateRange(m_minX, m_maxX, CALC_RANGE(vecOrigin.x, m_RegionMin[0], m_RegionMax[0]), m_pNodes[iNode].m_Region[0]); - UpdateRange(m_minY, m_maxY, CALC_RANGE(vecOrigin.y, m_RegionMin[1], m_RegionMax[1]), m_pNodes[iNode].m_Region[1]); - UpdateRange(m_minZ, m_maxZ, CALC_RANGE(vecOrigin.z, m_RegionMin[2], m_RegionMax[2]), m_pNodes[iNode].m_Region[2]); - - // From maxCircle, calculate maximum bounds box. All points must be - // simultaneously inside all bounds of the box. - // - m_minBoxX = CALC_RANGE(vecOrigin.x - flDist, m_RegionMin[0], m_RegionMax[0]); - m_maxBoxX = CALC_RANGE(vecOrigin.x + flDist, m_RegionMin[0], m_RegionMax[0]); - m_minBoxY = CALC_RANGE(vecOrigin.y - flDist, m_RegionMin[1], m_RegionMax[1]); - m_maxBoxY = CALC_RANGE(vecOrigin.y + flDist, m_RegionMin[1], m_RegionMax[1]); - m_minBoxZ = CALC_RANGE(vecOrigin.z - flDist, m_RegionMin[2], m_RegionMax[2]); - m_maxBoxZ = CALC_RANGE(vecOrigin.z + flDist, m_RegionMin[2], m_RegionMax[2]); - } - } -} - -//========================================================= -// CGraph - FindNearestNode - returns the index of the node nearest -// the given vector -1 is failure (couldn't find a valid -// near node ) -//========================================================= -int CGraph :: FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ) -{ - return FindNearestNode( vecOrigin, NodeType( pEntity ) ); -} - -int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) -{ - int i; - TraceResult tr; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return -1; - } - - // Check with the cache - // - ULONG iHash = (CACHE_SIZE-1) & Hash((void *)(const float *)vecOrigin, sizeof(vecOrigin)); - if (m_Cache[iHash].v == vecOrigin) - { - //ALERT(at_aiconsole, "Cache Hit.\n"); - return m_Cache[iHash].n; - } - else - { - //ALERT(at_aiconsole, "Cache Miss.\n"); - } - - // Mark all points as unchecked. - // - m_CheckedCounter++; - if (m_CheckedCounter == 0) - { - for (int i = 0; i < m_cNodes; i++) - { - m_di[i].m_CheckedEvent = 0; - } - m_CheckedCounter++; - } - - m_iNearest = -1; - m_flShortest = 999999.0; // just a big number. - - // If we can find a visible point, then let CalcBounds set the limits, but if - // we have no visible point at all to start with, then don't restrict the limits. - // -#if 1 - m_minX = 0; m_maxX = 255; - m_minY = 0; m_maxY = 255; - m_minZ = 0; m_maxZ = 255; - m_minBoxX = 0; m_maxBoxX = 255; - m_minBoxY = 0; m_maxBoxY = 255; - m_minBoxZ = 0; m_maxBoxZ = 255; -#else - m_minBoxX = CALC_RANGE(vecOrigin.x - flDist, m_RegionMin[0], m_RegionMax[0]); - m_maxBoxX = CALC_RANGE(vecOrigin.x + flDist, m_RegionMin[0], m_RegionMax[0]); - m_minBoxY = CALC_RANGE(vecOrigin.y - flDist, m_RegionMin[1], m_RegionMax[1]); - m_maxBoxY = CALC_RANGE(vecOrigin.y + flDist, m_RegionMin[1], m_RegionMax[1]); - m_minBoxZ = CALC_RANGE(vecOrigin.z - flDist, m_RegionMin[2], m_RegionMax[2]); - m_maxBoxZ = CALC_RANGE(vecOrigin.z + flDist, m_RegionMin[2], m_RegionMax[2]) - CalcBounds(m_minX, m_maxX, CALC_RANGE(vecOrigin.x, m_RegionMin[0], m_RegionMax[0]), m_pNodes[m_iNearest].m_Region[0]); - CalcBounds(m_minY, m_maxY, CALC_RANGE(vecOrigin.y, m_RegionMin[1], m_RegionMax[1]), m_pNodes[m_iNearest].m_Region[1]); - CalcBounds(m_minZ, m_maxZ, CALC_RANGE(vecOrigin.z, m_RegionMin[2], m_RegionMax[2]), m_pNodes[m_iNearest].m_Region[2]); -#endif - - int halfX = (m_minX+m_maxX)/2; - int halfY = (m_minY+m_maxY)/2; - int halfZ = (m_minZ+m_maxZ)/2; - - int j; - - for (i = halfX; i >= m_minX; i--) - { - for (j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes)) continue; - - int rgY = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[1]; - if (rgY > m_maxBoxY) break; - if (rgY < m_minBoxY) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[2]; - if (rgZ < m_minBoxZ) continue; - if (rgZ > m_maxBoxZ) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[0]); - } - } - - for (i = max(m_minY,halfY+1); i <= m_maxY; i++) - { - for (j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[1]].m_afNodeInfo & afNodeTypes)) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[2]; - if (rgZ > m_maxBoxZ) break; - if (rgZ < m_minBoxZ) continue; - int rgX = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[0]; - if (rgX < m_minBoxX) continue; - if (rgX > m_maxBoxX) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); - } - } - - for (i = min(m_maxZ,halfZ); i >= m_minZ; i--) - { - for (j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[2]].m_afNodeInfo & afNodeTypes)) continue; - - int rgX = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[0]; - if (rgX > m_maxBoxX) break; - if (rgX < m_minBoxX) continue; - int rgY = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[1]; - if (rgY < m_minBoxY) continue; - if (rgY > m_maxBoxY) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); - } - } - - for (i = max(m_minX,halfX+1); i <= m_maxX; i++) - { - for (j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes)) continue; - - int rgY = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[1]; - if (rgY > m_maxBoxY) break; - if (rgY < m_minBoxY) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[2]; - if (rgZ < m_minBoxZ) continue; - if (rgZ > m_maxBoxZ) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[0]); - } - } - - for (i = min(m_maxY,halfY); i >= m_minY; i--) - { - for (j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[1]].m_afNodeInfo & afNodeTypes)) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[2]; - if (rgZ > m_maxBoxZ) break; - if (rgZ < m_minBoxZ) continue; - int rgX = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[0]; - if (rgX < m_minBoxX) continue; - if (rgX > m_maxBoxX) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); - } - } - - for (i = max(m_minZ,halfZ+1); i <= m_maxZ; i++) - { - for (j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[2]].m_afNodeInfo & afNodeTypes)) continue; - - int rgX = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[0]; - if (rgX > m_maxBoxX) break; - if (rgX < m_minBoxX) continue; - int rgY = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[1]; - if (rgY < m_minBoxY) continue; - if (rgY > m_maxBoxY) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); - } - } - -#if 0 - // Verify our answers. - // - int iNearestCheck = -1; - m_flShortest = 8192;// find nodes within this radius - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - float flDist = ( vecOrigin - m_pNodes[ i ].m_vecOriginPeek ).Length(); - - if ( flDist < m_flShortest ) - { - // make sure that vecOrigin can trace to this node! - UTIL_TraceLine ( vecOrigin, m_pNodes[ i ].m_vecOriginPeek, ignore_monsters, 0, &tr ); - - if ( tr.flFraction == 1.0 ) - { - iNearestCheck = i; - m_flShortest = flDist; - } - } - } - - if (iNearestCheck != m_iNearest) - { - ALERT( at_aiconsole, "NOT closest %d(%f,%f,%f) %d(%f,%f,%f).\n", - iNearestCheck, - m_pNodes[iNearestCheck].m_vecOriginPeek.x, - m_pNodes[iNearestCheck].m_vecOriginPeek.y, - m_pNodes[iNearestCheck].m_vecOriginPeek.z, - m_iNearest, - (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.x), - (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.y), - (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.z)); - } - if (m_iNearest == -1) - { - ALERT(at_aiconsole, "All that work for nothing.\n"); - } -#endif - m_Cache[iHash].v = vecOrigin; - m_Cache[iHash].n = m_iNearest; - return m_iNearest; -} - -//========================================================= -// CGraph - ShowNodeConnections - draws a line from the given node -// to all connected nodes -//========================================================= -void CGraph :: ShowNodeConnections ( int iNode ) -{ - Vector vecSpot; - CNode *pNode; - CNode *pLinkNode; - int i; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return; - } - - if ( iNode < 0 ) - { - ALERT( at_aiconsole, "Can't show connections for node %d\n", iNode ); - return; - } - - pNode = &m_pNodes[ iNode ]; - - UTIL_ParticleEffect( pNode->m_vecOrigin, g_vecZero, 255, 20 );// show node position - - if ( pNode->m_cNumLinks <= 0 ) - {// no connections! - ALERT ( at_aiconsole, "**No Connections!\n" ); - } - - for ( i = 0 ; i < pNode->m_cNumLinks ; i++ ) - { - - pLinkNode = &Node( NodeLink( iNode, i).m_iDestNode ); - vecSpot = pLinkNode->m_vecOrigin; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + NODE_HEIGHT ); - MESSAGE_END(); - - } -} - -//========================================================= -// CGraph - LinkVisibleNodes - the first, most basic -// function of node graph creation, this connects every -// node to every other node that it can see. Expects a -// pointer to an empty connection pool and a file pointer -// to write progress to. Returns the total number of initial -// links. -// -// If there's a problem with this process, the index -// of the offending node will be written to piBadNode -//========================================================= -int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ) -{ - int i,j,z; - edict_t *pTraceEnt; - int cTotalLinks, cLinksThisNode, cMaxInitialLinks; - TraceResult tr; - - // !!!BUGBUG - this function returns 0 if there is a problem in the middle of connecting the graph - // it also returns 0 if none of the nodes in a level can see each other. piBadNode is ALWAYS read - // by BuildNodeGraph() if this function returns a 0, so make sure that it doesn't get some random - // number back. - *piBadNode = 0; - - - if ( m_cNodes <= 0 ) - { - ALERT ( at_aiconsole, "No Nodes!\n" ); - return FALSE; - } - - // if the file pointer is bad, don't blow up, just don't write the - // file. - if ( !file ) - { - ALERT ( at_aiconsole, "**LinkVisibleNodes:\ncan't write to file." ); - } - else - { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "LinkVisibleNodes - Initial Connections\n" ); - fprintf ( file, "----------------------------------------------------------------------------\n" ); - } - - cTotalLinks = 0;// start with no connections - - // to keep track of the maximum number of initial links any node had so far. - // this lets us keep an eye on MAX_NODE_INITIAL_LINKS to ensure that we are - // being generous enough. - cMaxInitialLinks = 0; - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - cLinksThisNode = 0;// reset this count for each node. - - if ( file ) - { - fprintf ( file, "Node #%4d:\n\n", i ); - } - - for ( z = 0 ; z < MAX_NODE_INITIAL_LINKS ; z++ ) - {// clear out the important fields in the link pool for this node - pLinkPool [ cTotalLinks + z ].m_iSrcNode = i;// so each link knows which node it originates from - pLinkPool [ cTotalLinks + z ].m_iDestNode = 0; - pLinkPool [ cTotalLinks + z ].m_pLinkEnt = NULL; - } - - m_pNodes [ i ].m_iFirstLink = cTotalLinks; - - // now build a list of every other node that this node can see - for ( j = 0 ; j < m_cNodes ; j++ ) - { - if ( j == i ) - {// don't connect to self! - continue; - } - -#if 0 - - if ( (m_pNodes[ i ].m_afNodeInfo & bits_NODE_WATER) != (m_pNodes[ j ].m_afNodeInfo & bits_NODE_WATER) ) - { - // don't connect water nodes to air nodes or land nodes. It just wouldn't be prudent at this juncture. - continue; - } -#else - if ( (m_pNodes[ i ].m_afNodeInfo & bits_NODE_GROUP_REALM) != (m_pNodes[ j ].m_afNodeInfo & bits_NODE_GROUP_REALM) ) - { - // don't connect air nodes to water nodes to land nodes. It just wouldn't be prudent at this juncture. - continue; - } -#endif - - tr.pHit = NULL;// clear every time so we don't get stuck with last trace's hit ent - pTraceEnt = 0; - - UTIL_TraceLine ( m_pNodes[ i ].m_vecOrigin, - m_pNodes[ j ].m_vecOrigin, - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - - if ( tr.fStartSolid ) - continue; - - if ( tr.flFraction != 1.0 ) - {// trace hit a brush ent, trace backwards to make sure that this ent is the only thing in the way. - - pTraceEnt = tr.pHit;// store the ent that the trace hit, for comparison - - UTIL_TraceLine ( m_pNodes[ j ].m_vecOrigin, - m_pNodes[ i ].m_vecOrigin, - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - -// there is a solid_bsp ent in the way of these two nodes, so we must record several things about in order to keep -// track of it in the pathfinding code, as well as through save and restore of the node graph. ANY data that is manipulated -// as part of the process of adding a LINKENT to a connection here must also be done in CGraph::SetGraphPointers, where reloaded -// graphs are prepared for use. - if ( tr.pHit == pTraceEnt && !FClassnameIs( tr.pHit, "worldspawn" ) ) - { - // get a pointer - pLinkPool [ cTotalLinks ].m_pLinkEnt = VARS( tr.pHit ); - - // record the modelname, so that we can save/load node trees - memcpy( pLinkPool [ cTotalLinks ].m_szLinkEntModelname, STRING( VARS(tr.pHit)->model ), 4 ); - - // set the flag for this ent that indicates that it is attached to the world graph - // if this ent is removed from the world, it must also be removed from the connections - // that it formerly blocked. - if ( !FBitSet( VARS( tr.pHit )->flags, FL_GRAPHED ) ) - { - VARS( tr.pHit )->flags += FL_GRAPHED; - } - } - else - {// even if the ent wasn't there, these nodes couldn't be connected. Skip. - continue; - } - } - - if ( file ) - { - fprintf ( file, "%4d", j ); - - if ( !FNullEnt( pLinkPool[ cTotalLinks ].m_pLinkEnt ) ) - {// record info about the ent in the way, if any. - fprintf ( file, " Entity on connection: %s, name: %s Model: %s", STRING( VARS( pTraceEnt )->classname ), STRING ( VARS( pTraceEnt )->targetname ), STRING ( VARS(tr.pHit)->model ) ); - } - - fprintf ( file, "\n", j ); - } - - pLinkPool [ cTotalLinks ].m_iDestNode = j; - cLinksThisNode++; - cTotalLinks++; - - // If we hit this, either a level designer is placing too many nodes in the same area, or - // we need to allow for a larger initial link pool. - if ( cLinksThisNode == MAX_NODE_INITIAL_LINKS ) - { - ALERT ( at_aiconsole, "**LinkVisibleNodes:\nNode %d has NodeLinks > MAX_NODE_INITIAL_LINKS", i ); - fprintf ( file, "** NODE %d HAS NodeLinks > MAX_NODE_INITIAL_LINKS **\n", i ); - *piBadNode = i; - return FALSE; - } - else if ( cTotalLinks > MAX_NODE_INITIAL_LINKS * m_cNodes ) - {// this is paranoia - ALERT ( at_aiconsole, "**LinkVisibleNodes:\nTotalLinks > MAX_NODE_INITIAL_LINKS * NUMNODES" ); - *piBadNode = i; - return FALSE; - } - - if ( cLinksThisNode == 0 ) - { - fprintf ( file, "**NO INITIAL LINKS**\n" ); - } - - // record the connection info in the link pool - WorldGraph.m_pNodes [ i ].m_cNumLinks = cLinksThisNode; - - // keep track of the most initial links ANY node had, so we can figure out - // if we have a large enough default link pool - if ( cLinksThisNode > cMaxInitialLinks ) - { - cMaxInitialLinks = cLinksThisNode; - } - } - - - if ( file ) - { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - } - } - - fprintf ( file, "\n%4d Total Initial Connections - %4d Maximum connections for a single node.\n", cTotalLinks, cMaxInitialLinks ); - fprintf ( file, "----------------------------------------------------------------------------\n\n\n" ); - - return cTotalLinks; -} - -//========================================================= -// CGraph - RejectInlineLinks - expects a pointer to a link -// pool, and a pointer to and already-open file ( if you -// want status reports written to disk ). RETURNS the number -// of connections that were rejected -//========================================================= -int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file ) -{ - int i,j,k; - - int cRejectedLinks; - - BOOL fRestartLoop;// have to restart the J loop if we eliminate a link. - - CNode *pSrcNode; - CNode *pCheckNode;// the node we are testing for (one of pSrcNode's connections) - CNode *pTestNode;// the node we are checking against ( also one of pSrcNode's connections) - - float flDistToTestNode, flDistToCheckNode; - - Vector2D vec2DirToTestNode, vec2DirToCheckNode; - - if ( file ) - { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "InLine Rejection:\n" ); - fprintf ( file, "----------------------------------------------------------------------------\n" ); - } - - cRejectedLinks = 0; - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - pSrcNode = &m_pNodes[ i ]; - - if ( file ) - { - fprintf ( file, "Node %3d:\n", i ); - } - - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) - { - pCheckNode = &m_pNodes[ pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; - - vec2DirToCheckNode = ( pCheckNode->m_vecOrigin - pSrcNode->m_vecOrigin ).Make2D(); - flDistToCheckNode = vec2DirToCheckNode.Length(); - vec2DirToCheckNode = vec2DirToCheckNode.Normalize(); - - pLinkPool[ pSrcNode->m_iFirstLink + j ].m_flWeight = flDistToCheckNode; - - fRestartLoop = FALSE; - for ( k = 0 ; k < pSrcNode->m_cNumLinks && !fRestartLoop ; k++ ) - { - if ( k == j ) - {// don't check against same node - continue; - } - - pTestNode = &m_pNodes [ pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode ]; - - vec2DirToTestNode = ( pTestNode->m_vecOrigin - pSrcNode->m_vecOrigin ).Make2D(); - - flDistToTestNode = vec2DirToTestNode.Length(); - vec2DirToTestNode = vec2DirToTestNode.Normalize(); - - if ( DotProduct ( vec2DirToCheckNode, vec2DirToTestNode ) >= 0.998 ) - { - // there's a chance that TestNode intersects the line to CheckNode. If so, we should disconnect the link to CheckNode. - if ( flDistToTestNode < flDistToCheckNode ) - { - if ( file ) - { - fprintf ( file, "REJECTED NODE %3d through Node %3d, Dot = %8f\n", pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode, pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode, DotProduct ( vec2DirToCheckNode, vec2DirToTestNode ) ); - } - - pLinkPool[ pSrcNode->m_iFirstLink + j ] = pLinkPool[ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; - pSrcNode->m_cNumLinks--; - j--; - - cRejectedLinks++;// keeping track of how many links are cut, so that we can return that value. - - fRestartLoop = TRUE; - } - } - } - } - - if ( file ) - { - fprintf ( file, "----------------------------------------------------------------------------\n\n" ); - } - } - - return cRejectedLinks; -} - -//========================================================= -// TestHull is a modelless clip hull that verifies reachable -// nodes by walking from every node to each of it's connections -//========================================================= -class CTestHull : public CBaseMonster -{ - -public: - void Spawn( entvars_t *pevMasterNode ); - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void EXPORT CallBuildNodeGraph ( void ); - void BuildNodeGraph ( void ); - void EXPORT ShowBadNode ( void ); - void EXPORT DropDelay ( void ); - void EXPORT PathFind ( void ); - - Vector vecBadNodeOrigin; -}; - -LINK_ENTITY_TO_CLASS( testhull, CTestHull ); - -//========================================================= -// CTestHull::Spawn -//========================================================= -void CTestHull :: Spawn( entvars_t *pevMasterNode ) -{ - SET_MODEL(ENT(pev), "models/player.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 50; - pev->yaw_speed = 8; - - if ( WorldGraph.m_fGraphPresent ) - {// graph loaded from disk, so we don't need the test hull - SetThink ( &CTestHull::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - else - { - SetThink ( &CTestHull::DropDelay ); - pev->nextthink = gpGlobals->time + 1; - } - - // Make this invisible - // UNDONE: Shouldn't we just use EF_NODRAW? This doesn't need to go to the client. - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; -} - -//========================================================= -// TestHull::DropDelay - spawns TestHull on top of -// the 0th node and drops it to the ground. -//========================================================= -void CTestHull::DropDelay ( void ) -{ - UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." ); - - UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); - - SetThink ( &CTestHull::CallBuildNodeGraph ); - - pev->nextthink = gpGlobals->time + 1; -} - -//========================================================= -// nodes start out as ents in the world. As they are spawned, -// the node info is recorded then the ents are discarded. -//========================================================= -void CNodeEnt :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "hinttype")) - { - m_sHintType = (short)atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - - if (FStrEq(pkvd->szKeyName, "activity")) - { - m_sHintActivity = (short)atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -//========================================================= -//========================================================= -void CNodeEnt :: Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT;// always solid_not - - if ( WorldGraph.m_fGraphPresent ) - {// graph loaded from disk, so discard all these node ents as soon as they spawn - REMOVE_ENTITY( edict() ); - return; - } - - if ( WorldGraph.m_cNodes == 0 ) - {// this is the first node to spawn, spawn the test hull entity that builds and walks the node tree - CTestHull *pHull = GetClassPtr((CTestHull *)NULL); - pHull->Spawn( pev ); - } - - if ( WorldGraph.m_cNodes >= MAX_NODES ) - { - ALERT ( at_aiconsole, "cNodes > MAX_NODES\n" ); - return; - } - - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_vecOriginPeek = - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_vecOrigin = pev->origin; - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_flHintYaw = pev->angles.y; - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_sHintType = m_sHintType; - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_sHintActivity = m_sHintActivity; - - if (FClassnameIs( pev, "info_node_air" )) - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = bits_NODE_AIR; - else - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = 0; - - WorldGraph.m_cNodes++; - - REMOVE_ENTITY( edict() ); -} - -//========================================================= -// CTestHull - ShowBadNode - makes a bad node fizzle. When -// there's a problem with node graph generation, the test -// hull will be placed up the bad node's location and will generate -// particles -//========================================================= -void CTestHull :: ShowBadNode( void ) -{ - pev->movetype = MOVETYPE_FLY; - pev->angles.y = pev->angles.y + 4; - - UTIL_MakeVectors ( pev->angles ); - - UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * 64, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin - gpGlobals->v_forward * 64, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin + gpGlobals->v_right * 64, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin - gpGlobals->v_right * 64, g_vecZero, 255, 25 ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -extern BOOL gTouchDisabled; -void CTestHull::CallBuildNodeGraph( void ) -{ - // TOUCH HACK -- Don't allow this entity to call anyone's "touch" function - gTouchDisabled = TRUE; - BuildNodeGraph(); - gTouchDisabled = FALSE; - // Undo TOUCH HACK -} - -//========================================================= -// BuildNodeGraph - think function called by the empty walk -// hull that is spawned by the first node to spawn. This -// function links all nodes that can see each other, then -// eliminates all inline links, then uses a monster-sized -// hull that walks between each node and each of its links -// to ensure that a monster can actually fit through the space -//========================================================= -void CTestHull :: BuildNodeGraph( void ) -{ - TraceResult tr; - FILE *file; - - char szNrpFilename [MAX_PATH];// text node report filename - - CLink *pTempPool; // temporary link pool - - CNode *pSrcNode;// node we're currently working with - CNode *pDestNode;// the other node in comparison operations - - BOOL fSkipRemainingHulls;//if smallest hull can't fit, don't check any others - BOOL fPairsValid;// are all links in the graph evenly paired? - - int i, j, hull; - - int iBadNode;// this is the node that caused graph generation to fail - - int cMaxInitialLinks = 0; - int cMaxValidLinks = 0; - - int iPoolIndex = 0; - int cPoolLinks;// number of links in the pool. - - Vector vecDirToCheckNode; - Vector vecDirToTestNode; - Vector vecStepCheckDir; - Vector vecTraceSpot; - Vector vecSpot; - - Vector2D vec2DirToCheckNode; - Vector2D vec2DirToTestNode; - Vector2D vec2StepCheckDir; - Vector2D vec2TraceSpot; - Vector2D vec2Spot; - - float flYaw;// use this stuff to walk the hull between nodes - float flDist; - int step; - - SetThink ( &CTestHull::SUB_Remove );// no matter what happens, the hull gets rid of itself. - pev->nextthink = gpGlobals->time; - -// malloc a swollen temporary connection pool that we trim down after we know exactly how many connections there are. - pTempPool = (CLink *)calloc ( sizeof ( CLink ) , ( WorldGraph.m_cNodes * MAX_NODE_INITIAL_LINKS ) ); - if ( !pTempPool ) - { - ALERT ( at_aiconsole, "**Could not malloc TempPool!\n" ); - return; - } - - - // make sure directories have been made - GET_GAME_DIR( szNrpFilename ); - strcat( szNrpFilename, "/maps" ); - CreateDirectory( szNrpFilename, NULL ); - strcat( szNrpFilename, "/graphs" ); - CreateDirectory( szNrpFilename, NULL ); - - strcat( szNrpFilename, "/" ); - strcat( szNrpFilename, STRING( gpGlobals->mapname ) ); - strcat( szNrpFilename, ".nrp" ); - - file = fopen ( szNrpFilename, "w+" ); - - if ( !file ) - {// file error - ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); - - if ( pTempPool ) - { - free ( pTempPool ); - } - - return; - } - - fprintf( file, "Node Graph Report for map: %s.bsp\n", STRING(gpGlobals->mapname) ); - fprintf ( file, "%d Total Nodes\n\n", WorldGraph.m_cNodes ); - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - {// print all node numbers and their locations to the file. - WorldGraph.m_pNodes[ i ].m_cNumLinks = 0; - WorldGraph.m_pNodes[ i ].m_iFirstLink = 0; - memset(WorldGraph.m_pNodes[ i ].m_pNextBestNode, 0, sizeof(WorldGraph.m_pNodes[ i ].m_pNextBestNode)); - - fprintf ( file, "Node# %4d\n", i ); - fprintf ( file, "Location %4d,%4d,%4d\n",(int)WorldGraph.m_pNodes[ i ].m_vecOrigin.x, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.y, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.z ); - fprintf ( file, "HintType: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintType ); - fprintf ( file, "HintActivity: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintActivity ); - fprintf ( file, "HintYaw: %4f\n", WorldGraph.m_pNodes[ i ].m_flHintYaw ); - fprintf ( file, "-------------------------------------------------------------------------------\n" ); - } - fprintf ( file, "\n\n" ); - - - // Automatically recognize WATER nodes and drop the LAND nodes to the floor. - // - for ( i = 0; i < WorldGraph.m_cNodes; i++) - { - if (WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_AIR) - { - // do nothing - } - else if (UTIL_PointContents(WorldGraph.m_pNodes[ i ].m_vecOrigin) == CONTENTS_WATER) - { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_WATER; - } - else - { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_LAND; - - // trace to the ground, then pop up 8 units and place node there to make it - // easier for them to connect (think stairs, chairs, and bumps in the floor). - // After the routing is done, push them back down. - // - TraceResult tr; - - UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, - WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - // This trace is ONLY used if we hit an entity flagged with FL_WORLDBRUSH - TraceResult trEnt; - UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, - WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), - dont_ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &trEnt ); - - - // Did we hit something closer than the floor? - if ( trEnt.flFraction < tr.flFraction ) - { - // If it was a world brush entity, copy the node location - if ( trEnt.pHit && (trEnt.pHit->v.flags & FL_WORLDBRUSH) ) - tr.vecEndPos = trEnt.vecEndPos; - } - - WorldGraph.m_pNodes[i].m_vecOriginPeek.z = - WorldGraph.m_pNodes[i].m_vecOrigin.z = tr.vecEndPos.z + NODE_HEIGHT; - } - } - - cPoolLinks = WorldGraph.LinkVisibleNodes( pTempPool, file, &iBadNode ); - - if ( !cPoolLinks ) - { - ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); - - SetThink ( &CTestHull::ShowBadNode );// send the hull off to show the offending node. - //pev->solid = SOLID_NOT; - pev->origin = WorldGraph.m_pNodes[ iBadNode ].m_vecOrigin; - - if ( pTempPool ) - { - free ( pTempPool ); - } - - if ( file ) - {// close the file - fclose ( file ); - } - - return; - } - -// send the walkhull to all of this node's connections now. We'll do this here since -// so much of it relies on being able to control the test hull. - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "Walk Rejection:\n"); - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - pSrcNode = &WorldGraph.m_pNodes[ i ]; - - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "Node %4d:\n\n", i ); - - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) - { - // assume that all hulls can walk this link, then eliminate the ones that can't. - pTempPool [ pSrcNode->m_iFirstLink + j ].m_afLinkInfo = bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL | bits_LINK_FLY_HULL; - - - // do a check for each hull size. - - // if we can't fit a tiny hull through a connection, no other hulls with fit either, so we - // should just fall out of the loop. Do so by setting the SkipRemainingHulls flag. - fSkipRemainingHulls = FALSE; - for ( hull = 0 ; hull < MAX_NODE_HULLS; hull++ ) - { - if (fSkipRemainingHulls && (hull == NODE_HUMAN_HULL || hull == NODE_LARGE_HULL)) // skip the remaining walk hulls - continue; - - switch ( hull ) - { - case NODE_SMALL_HULL: - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - break; - case NODE_HUMAN_HULL: - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - break; - case NODE_LARGE_HULL: - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - break; - case NODE_FLY_HULL: - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - // UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - break; - } - - UTIL_SetOrigin ( pev, pSrcNode->m_vecOrigin );// place the hull on the node - - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) - { - ALERT ( at_aiconsole, "OFFGROUND!\n" ); - } - - // now build a yaw that points to the dest node, and get the distance. - if ( j < 0 ) - { - ALERT ( at_aiconsole, "**** j = %d ****\n", j ); - if ( pTempPool ) - { - free ( pTempPool ); - } - - if ( file ) - {// close the file - fclose ( file ); - } - return; - } - - pDestNode = &WorldGraph.m_pNodes [ pTempPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; - - vecSpot = pDestNode->m_vecOrigin; - //vecSpot.z = pev->origin.z; - - if (hull < NODE_FLY_HULL) - { - int SaveFlags = pev->flags; - int MoveMode = WALKMOVE_WORLDONLY; - if (pSrcNode->m_afNodeInfo & bits_NODE_WATER) - { - pev->flags |= FL_SWIM; - MoveMode = WALKMOVE_NORMAL; - } - - flYaw = UTIL_VecToYaw ( pDestNode->m_vecOrigin - pev->origin ); - - flDist = ( vecSpot - pev->origin ).Length2D(); - - int fWalkFailed = FALSE; - - // in this loop we take tiny steps from the current node to the nodes that it links to, one at a time. - // pev->angles.y = flYaw; - for ( step = 0 ; step < flDist && !fWalkFailed ; step += HULL_STEP_SIZE ) - { - float stepSize = HULL_STEP_SIZE; - - if ( (step + stepSize) >= (flDist-1) ) - stepSize = (flDist - step) - 1; - - if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, MoveMode ) ) - {// can't take the next step - - fWalkFailed = TRUE; - break; - } - } - - if (!fWalkFailed && (pev->origin - vecSpot).Length() > 64) - { - // ALERT( at_console, "bogus walk\n"); - // we thought we - fWalkFailed = TRUE; - } - - if (fWalkFailed) - { - - //pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; - - // now me must eliminate the hull that couldn't walk this connection - switch ( hull ) - { - case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection - fprintf ( file, "NODE_SMALL_HULL step %f\n", step ); - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL); - fSkipRemainingHulls = TRUE;// don't bother checking larger hulls - break; - case NODE_HUMAN_HULL: - fprintf ( file, "NODE_HUMAN_HULL step %f\n", step ); - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL); - fSkipRemainingHulls = TRUE;// don't bother checking larger hulls - break; - case NODE_LARGE_HULL: - fprintf ( file, "NODE_LARGE_HULL step %f\n", step ); - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL; - break; - } - } - pev->flags = SaveFlags; - } - else - { - TraceResult tr; - - UTIL_TraceHull( pSrcNode->m_vecOrigin + Vector( 0, 0, 32 ), pDestNode->m_vecOriginPeek + Vector( 0, 0, 32 ), ignore_monsters, large_hull, ENT( pev ), &tr ); - if (tr.fStartSolid || tr.flFraction < 1.0) - { - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_FLY_HULL; - } - } - } - - if (pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo == 0) - { - fprintf ( file, "Rejected Node %3d - Unreachable by ", pTempPool [ pSrcNode->m_iFirstLink + j ].m_iDestNode ); - pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; - fprintf ( file, "Any Hull\n" ); - - pSrcNode->m_cNumLinks--; - cPoolLinks--;// we just removed a link, so decrement the total number of links in the pool. - j--; - } - - } - } - fprintf ( file, "-------------------------------------------------------------------------------\n\n\n"); - - cPoolLinks -= WorldGraph.RejectInlineLinks ( pTempPool, file ); - -// now malloc a pool just large enough to hold the links that are actually used - WorldGraph.m_pLinkPool = (CLink *) calloc ( sizeof ( CLink ), cPoolLinks ); - - if ( !WorldGraph.m_pLinkPool ) - {// couldn't make the link pool! - ALERT ( at_aiconsole, "Couldn't malloc LinkPool!\n" ); - if ( pTempPool ) - { - free ( pTempPool ); - } - if ( file ) - {// close the file - fclose ( file ); - } - - return; - } - WorldGraph.m_cLinks = cPoolLinks; - -//copy only the used portions of the TempPool into the graph's link pool - int iFinalPoolIndex = 0; - int iOldFirstLink; - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - iOldFirstLink = WorldGraph.m_pNodes[ i ].m_iFirstLink;// store this, because we have to re-assign it before entering the copy loop - - WorldGraph.m_pNodes[ i ].m_iFirstLink = iFinalPoolIndex; - - for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) - { - WorldGraph.m_pLinkPool[ iFinalPoolIndex++ ] = pTempPool[ iOldFirstLink + j ]; - } - } - - - // Node sorting numbers linked nodes close to each other - // - WorldGraph.SortNodes(); - - // This is used for HashSearch - // - WorldGraph.BuildLinkLookups(); - - fPairsValid = TRUE; // assume that the connection pairs are all valid to start - - fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); - fprintf ( file, "Link Pairings:\n"); - -// link integrity check. The idea here is that if Node A links to Node B, node B should -// link to node A. If not, we have a situation that prevents us from using a basic -// optimization in the FindNearestLink function. - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) - { - int iLink; - WorldGraph.HashSearch(WorldGraph.INodeLink(i,j), i, iLink); - if (iLink < 0) - { - fPairsValid = FALSE;// unmatched link pair. - fprintf ( file, "WARNING: Node %3d does not connect back to Node %3d\n", WorldGraph.INodeLink(i, j), i); - } - } - } - - // !!!LATER - if all connections are properly paired, when can enable an optimization in the pathfinding code - // (in the find nearest line function) - if ( fPairsValid ) - { - fprintf ( file, "\nAll Connections are Paired!\n"); - } - - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); - fprintf ( file, "Total Number of Connections in Pool: %d\n", cPoolLinks ); - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "Connection Pool: %d bytes\n", sizeof ( CLink ) * cPoolLinks ); - fprintf ( file, "-------------------------------------------------------------------------------\n"); - - - ALERT ( at_aiconsole, "%d Nodes, %d Connections\n", WorldGraph.m_cNodes, cPoolLinks ); - - // This is used for FindNearestNode - // - WorldGraph.BuildRegionTables(); - - - // Push all of the LAND nodes down to the ground now. Leave the water and air nodes alone. - // - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - if ((WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_LAND)) - { - WorldGraph.m_pNodes[ i ].m_vecOrigin.z -= NODE_HEIGHT; - } - } - - - if ( pTempPool ) - {// free the temp pool - free ( pTempPool ); - } - - if ( file ) - { - fclose ( file ); - } - - // We now have some graphing capabilities. - // - WorldGraph.m_fGraphPresent = TRUE;//graph is in memory. - WorldGraph.m_fGraphPointersSet = TRUE;// since the graph was generated, the pointers are ready - WorldGraph.m_fRoutingComplete = FALSE; // Optimal routes aren't computed, yet. - - // Compute and compress the routing information. - // - WorldGraph.ComputeStaticRoutingTables(); - -// save the node graph for this level - WorldGraph.FSaveGraph( (char *)STRING( gpGlobals->mapname ) ); - ALERT( at_console, "Done.\n"); -} - - -//========================================================= -// returns a hardcoded path. -//========================================================= -void CTestHull :: PathFind ( void ) -{ - int iPath[ 50 ]; - int iPathSize; - int i; - CNode *pNode, *pNextNode; - - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return; - } - - iPathSize = WorldGraph.FindShortestPath ( iPath, 0, 19, 0, 0 ); // UNDONE use hull constant - - if ( !iPathSize ) - { - ALERT ( at_aiconsole, "No Path!\n" ); - return; - } - - ALERT ( at_aiconsole, "%d\n", iPathSize ); - - pNode = &WorldGraph.m_pNodes[ iPath [ 0 ] ]; - - for ( i = 0 ; i < iPathSize - 1 ; i++ ) - { - - pNextNode = &WorldGraph.m_pNodes[ iPath [ i + 1 ] ]; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( pNode->m_vecOrigin.x ); - WRITE_COORD( pNode->m_vecOrigin.y ); - WRITE_COORD( pNode->m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( pNextNode->m_vecOrigin.x); - WRITE_COORD( pNextNode->m_vecOrigin.y); - WRITE_COORD( pNextNode->m_vecOrigin.z + NODE_HEIGHT); - MESSAGE_END(); - - pNode = pNextNode; - } - -} - - -//========================================================= -// CStack Constructor -//========================================================= -CStack :: CStack( void ) -{ - m_level = 0; -} - -//========================================================= -// pushes a value onto the stack -//========================================================= -void CStack :: Push( int value ) -{ - if ( m_level >= MAX_STACK_NODES ) - { - printf("Error!\n"); - return; - } - m_stack[m_level] = value; - m_level++; -} - -//========================================================= -// pops a value off of the stack -//========================================================= -int CStack :: Pop( void ) -{ - if ( m_level <= 0 ) - return -1; - - m_level--; - return m_stack[ m_level ]; -} - -//========================================================= -// returns the value on the top of the stack -//========================================================= -int CStack :: Top ( void ) -{ - return m_stack[ m_level - 1 ]; -} - -//========================================================= -// copies every element on the stack into an array LIFO -//========================================================= -void CStack :: CopyToArray ( int *piArray ) -{ - int i; - - for ( i = 0 ; i < m_level ; i++ ) - { - piArray[ i ] = m_stack[ i ]; - } -} - -//========================================================= -// CQueue constructor -//========================================================= -CQueue :: CQueue( void ) -{ - m_cSize = 0; - m_head = 0; - m_tail = -1; -} - -//========================================================= -// inserts a value into the queue -//========================================================= -void CQueue :: Insert ( int iValue, float fPriority ) -{ - - if ( Full() ) - { - printf ( "Queue is full!\n" ); - return; - } - - m_tail++; - - if ( m_tail == MAX_STACK_NODES ) - {//wrap around - m_tail = 0; - } - - m_queue[ m_tail ].Id = iValue; - m_queue[ m_tail ].Priority = fPriority; - m_cSize++; -} - -//========================================================= -// removes a value from the queue (FIFO) -//========================================================= -int CQueue :: Remove ( float &fPriority ) -{ - if ( m_head == MAX_STACK_NODES ) - {// wrap - m_head = 0; - } - - m_cSize--; - fPriority = m_queue[ m_head ].Priority; - return m_queue[ m_head++ ].Id; -} - -//========================================================= -// CQueue constructor -//========================================================= -CQueuePriority :: CQueuePriority( void ) -{ - m_cSize = 0; -} - -//========================================================= -// inserts a value into the priority queue -//========================================================= -void CQueuePriority :: Insert( int iValue, float fPriority ) -{ - - if ( Full() ) - { - printf ( "Queue is full!\n" ); - return; - } - - m_heap[ m_cSize ].Priority = fPriority; - m_heap[ m_cSize ].Id = iValue; - m_cSize++; - Heap_SiftUp(); -} - -//========================================================= -// removes the smallest item from the priority queue -// -//========================================================= -int CQueuePriority :: Remove( float &fPriority ) -{ - int iReturn = m_heap[ 0 ].Id; - fPriority = m_heap[ 0 ].Priority; - - m_cSize--; - - m_heap[ 0 ] = m_heap[ m_cSize ]; - - Heap_SiftDown(0); - return iReturn; -} - -#define HEAP_LEFT_CHILD(x) (2*(x)+1) -#define HEAP_RIGHT_CHILD(x) (2*(x)+2) -#define HEAP_PARENT(x) (((x)-1)/2) - -void CQueuePriority::Heap_SiftDown(int iSubRoot) -{ - int parent = iSubRoot; - int child = HEAP_LEFT_CHILD(parent); - - struct tag_HEAP_NODE Ref = m_heap[ parent ]; - - while (child < m_cSize) - { - int rightchild = HEAP_RIGHT_CHILD(parent); - if (rightchild < m_cSize) - { - if ( m_heap[ rightchild ].Priority < m_heap[ child ].Priority ) - { - child = rightchild; - } - } - if ( Ref.Priority <= m_heap[ child ].Priority ) - break; - - m_heap[ parent ] = m_heap[ child ]; - parent = child; - child = HEAP_LEFT_CHILD(parent); - } - m_heap[ parent ] = Ref; -} - -void CQueuePriority::Heap_SiftUp(void) -{ - int child = m_cSize-1; - while (child) - { - int parent = HEAP_PARENT(child); - if ( m_heap[ parent ].Priority <= m_heap[ child ].Priority ) - break; - - struct tag_HEAP_NODE Tmp; - Tmp = m_heap[ child ]; - m_heap[ child ] = m_heap[ parent ]; - m_heap[ parent ] = Tmp; - - child = parent; - } -} - -//========================================================= -// CGraph - FLoadGraph - attempts to load a node graph from disk. -// if the current level is maps/snar.bsp, maps/graphs/snar.nod -// will be loaded. If file cannot be loaded, the node tree -// will be created and saved to disk. -//========================================================= -int CGraph :: FLoadGraph ( char *szMapName ) -{ - char szFilename[MAX_PATH]; - int iVersion; - int length; - byte *aMemFile; - byte *pMemFile; - - // make sure the directories have been made - char szDirName[MAX_PATH]; - GET_GAME_DIR( szDirName ); - strcat( szDirName, "/maps" ); - CreateDirectory( szDirName, NULL ); - strcat( szDirName, "/graphs" ); - CreateDirectory( szDirName, NULL ); - - strcpy ( szFilename, "maps/graphs/" ); - strcat ( szFilename, szMapName ); - strcat( szFilename, ".nod" ); - - pMemFile = aMemFile = LOAD_FILE_FOR_ME(szFilename, &length); - - if ( !aMemFile ) - { - return FALSE; - } - else - { - // Read the graph version number - // - length -= sizeof(int); - if (length < 0) goto ShortFile; - memcpy(&iVersion, pMemFile, sizeof(int)); - pMemFile += sizeof(int); - - if ( iVersion != GRAPH_VERSION ) - { - // This file was written by a different build of the dll! - // - ALERT ( at_aiconsole, "**ERROR** Graph version is %d, expected %d\n",iVersion, GRAPH_VERSION ); - goto ShortFile; - } - - // Read the graph class - // - length -= sizeof(CGraph); - if (length < 0) goto ShortFile; - memcpy(this, pMemFile, sizeof(CGraph)); - pMemFile += sizeof(CGraph); - - // Set the pointers to zero, just in case we run out of memory. - // - m_pNodes = NULL; - m_pLinkPool = NULL; - m_di = NULL; - m_pRouteInfo = NULL; - m_pHashLinks = NULL; - - - // Malloc for the nodes - // - m_pNodes = ( CNode * )calloc ( sizeof ( CNode ), m_cNodes ); - - if ( !m_pNodes ) - { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", m_cNodes ); - goto NoMemory; - } - - // Read in all the nodes - // - length -= sizeof(CNode) * m_cNodes; - if (length < 0) goto ShortFile; - memcpy(m_pNodes, pMemFile, sizeof(CNode)*m_cNodes); - pMemFile += sizeof(CNode) * m_cNodes; - - - // Malloc for the link pool - // - m_pLinkPool = ( CLink * )calloc ( sizeof ( CLink ), m_cLinks ); - - if ( !m_pLinkPool ) - { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d link!\n", m_cLinks ); - goto NoMemory; - } - - // Read in all the links - // - length -= sizeof(CLink)*m_cLinks; - if (length < 0) goto ShortFile; - memcpy(m_pLinkPool, pMemFile, sizeof(CLink)*m_cLinks); - pMemFile += sizeof(CLink)*m_cLinks; - - // Malloc for the sorting info. - // - m_di = (DIST_INFO *)calloc( sizeof(DIST_INFO), m_cNodes ); - if ( !m_di ) - { - ALERT ( at_aiconsole, "***ERROR**\nCouldn't malloc %d entries sorting nodes!\n", m_cNodes ); - goto NoMemory; - } - - // Read it in. - // - length -= sizeof(DIST_INFO)*m_cNodes; - if (length < 0) goto ShortFile; - memcpy(m_di, pMemFile, sizeof(DIST_INFO)*m_cNodes); - pMemFile += sizeof(DIST_INFO)*m_cNodes; - - // Malloc for the routing info. - // - m_fRoutingComplete = FALSE; - m_pRouteInfo = (char *)calloc( sizeof(char), m_nRouteInfo ); - if ( !m_pRouteInfo ) - { - ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d route bytes!\n", m_nRouteInfo ); - goto NoMemory; - } - m_CheckedCounter = 0; - for (int i = 0; i < m_cNodes; i++) - { - m_di[i].m_CheckedEvent = 0; - } - - // Read in the route information. - // - length -= sizeof(char)*m_nRouteInfo; - if (length < 0) goto ShortFile; - memcpy(m_pRouteInfo, pMemFile, sizeof(char)*m_nRouteInfo); - pMemFile += sizeof(char)*m_nRouteInfo; - m_fRoutingComplete = TRUE;; - - // malloc for the hash links - // - m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); - if (!m_pHashLinks) - { - ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d hash link bytes!\n", m_nHashLinks ); - goto NoMemory; - } - - // Read in the hash link information - // - length -= sizeof(short)*m_nHashLinks; - if (length < 0) goto ShortFile; - memcpy(m_pHashLinks, pMemFile, sizeof(short)*m_nHashLinks); - pMemFile += sizeof(short)*m_nHashLinks; - - // Set the graph present flag, clear the pointers set flag - // - m_fGraphPresent = TRUE; - m_fGraphPointersSet = FALSE; - - FREE_FILE(aMemFile); - - if (length != 0) - { - ALERT ( at_aiconsole, "***WARNING***:Node graph was longer than expected by %d bytes.!\n", length); - } - - return TRUE; - } - -ShortFile: -NoMemory: - FREE_FILE(aMemFile); - return FALSE; -} - -//========================================================= -// CGraph - FSaveGraph - It's not rocket science. -// this WILL overwrite existing files. -//========================================================= -int CGraph :: FSaveGraph ( char *szMapName ) -{ - - int iVersion = GRAPH_VERSION; - char szFilename[MAX_PATH]; - FILE *file; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return FALSE; - } - - // make sure directories have been made - GET_GAME_DIR( szFilename ); - strcat( szFilename, "/maps" ); - CreateDirectory( szFilename, NULL ); - strcat( szFilename, "/graphs" ); - CreateDirectory( szFilename, NULL ); - - strcat( szFilename, "/" ); - strcat( szFilename, szMapName ); - strcat( szFilename, ".nod" ); - - file = fopen ( szFilename, "wb" ); - - ALERT ( at_aiconsole, "Created: %s\n", szFilename ); - - if ( !file ) - {// couldn't create - ALERT ( at_aiconsole, "Couldn't Create: %s\n", szFilename ); - return FALSE; - } - else - { - // write the version - fwrite ( &iVersion, sizeof ( int ), 1, file ); - - // write the CGraph class - fwrite ( this, sizeof ( CGraph ), 1, file ); - - // write the nodes - fwrite ( m_pNodes, sizeof ( CNode ), m_cNodes, file ); - - // write the links - fwrite ( m_pLinkPool, sizeof ( CLink ), m_cLinks, file ); - - fwrite ( m_di, sizeof(DIST_INFO), m_cNodes, file ); - - // Write the route info. - // - if ( m_pRouteInfo && m_nRouteInfo ) - { - fwrite ( m_pRouteInfo, sizeof( char ), m_nRouteInfo, file ); - } - - if (m_pHashLinks && m_nHashLinks) - { - fwrite(m_pHashLinks, sizeof(short), m_nHashLinks, file); - } - fclose ( file ); - return TRUE; - } -} - -//========================================================= -// CGraph - FSetGraphPointers - Takes the modelnames of -// all of the brush ents that block connections in the node -// graph and resolves them into pointers to those entities. -// this is done after loading the graph from disk, whereupon -// the pointers are not valid. -//========================================================= -int CGraph :: FSetGraphPointers ( void ) -{ - int i; - edict_t *pentLinkEnt; - - for ( i = 0 ; i < m_cLinks ; i++ ) - {// go through all of the links - - if ( m_pLinkPool[ i ].m_pLinkEnt != NULL ) - { - char name[5]; - // when graphs are saved, any valid pointers are will be non-zero, signifying that we should - // reset those pointers upon reloading. Any pointers that were NULL when the graph was saved - // will be NULL when reloaded, and will ignored by this function. - - // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) - memcpy( name, m_pLinkPool[ i ].m_szLinkEntModelname, 4 ); - name[4] = 0; - pentLinkEnt = FIND_ENTITY_BY_STRING( NULL, "model", name ); - - if ( FNullEnt ( pentLinkEnt ) ) - { - // the ent isn't around anymore? Either there is a major problem, or it was removed from the world - // ( like a func_breakable that's been destroyed or something ). Make sure that LinkEnt is null. - ALERT ( at_aiconsole, "**Could not find model %s\n", name ); - m_pLinkPool[ i ].m_pLinkEnt = NULL; - } - else - { - m_pLinkPool[ i ].m_pLinkEnt = VARS( pentLinkEnt ); - - if ( !FBitSet( m_pLinkPool[ i ].m_pLinkEnt->flags, FL_GRAPHED ) ) - { - m_pLinkPool[ i ].m_pLinkEnt->flags += FL_GRAPHED; - } - } - } - } - - // the pointers are now set. - m_fGraphPointersSet = TRUE; - return TRUE; -} - -//========================================================= -// CGraph - CheckNODFile - this function checks the date of -// the BSP file that was just loaded and the date of the a -// ssociated .NOD file. If the NOD file is not present, or -// is older than the BSP file, we rebuild it. -// -// returns FALSE if the .NOD file doesn't qualify and needs -// to be rebuilt. -// -// !!!BUGBUG - the file times we get back are 20 hours ahead! -// since this happens consistantly, we can still correctly -// determine which of the 2 files is newer. This needs fixed, -// though. ( I now suspect that we are getting GMT back from -// these functions and must compensate for local time ) (sjb) -//========================================================= -int CGraph :: CheckNODFile ( char *szMapName ) -{ - int retValue; - - char szBspFilename[MAX_PATH]; - char szGraphFilename[MAX_PATH]; - - - strcpy ( szBspFilename, "maps/" ); - strcat ( szBspFilename, szMapName ); - strcat ( szBspFilename, ".bsp" ); - - strcpy ( szGraphFilename, "maps/graphs/" ); - strcat ( szGraphFilename, szMapName ); - strcat ( szGraphFilename, ".nod" ); - - retValue = TRUE; - - int iCompare; - if (COMPARE_FILE_TIME(szBspFilename, szGraphFilename, &iCompare)) - { - if ( iCompare > 0 ) - {// BSP file is newer. - ALERT ( at_aiconsole, ".NOD File will be updated\n\n" ); - retValue = FALSE; - } - } - else - { - retValue = FALSE; - } - - return retValue; -} - -#define ENTRY_STATE_EMPTY -1 - -struct tagNodePair -{ - short iSrc; - short iDest; -}; - -void CGraph::HashInsert(int iSrcNode, int iDestNode, int iKey) -{ - struct tagNodePair np; - - np.iSrc = iSrcNode; - np.iDest = iDestNode; - CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(dwHash); - - int di = m_HashPrimes[dwHash&15]; - int i = (dwHash >> 4) % m_nHashLinks; - while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) - { - i += di; - if (i >= m_nHashLinks) i -= m_nHashLinks; - } - m_pHashLinks[i] = iKey; -} - -void CGraph::HashSearch(int iSrcNode, int iDestNode, int &iKey) -{ - struct tagNodePair np; - - np.iSrc = iSrcNode; - np.iDest = iDestNode; - CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(dwHash); - - int di = m_HashPrimes[dwHash&15]; - int i = (dwHash >> 4) % m_nHashLinks; - while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) - { - CLink &link = Link(m_pHashLinks[i]); - if (iSrcNode == link.m_iSrcNode && iDestNode == link.m_iDestNode) - { - break; - } - else - { - i += di; - if (i >= m_nHashLinks) i -= m_nHashLinks; - } - } - iKey = m_pHashLinks[i]; -} - -#define NUMBER_OF_PRIMES 177 - -int Primes[NUMBER_OF_PRIMES] = -{ 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, -71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, -157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, -241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, -347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, -439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, -547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, -643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, -751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, -859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, -977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 0 }; - -void CGraph::HashChoosePrimes(int TableSize) -{ - int LargestPrime = TableSize/2; - if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) - { - LargestPrime = Primes[NUMBER_OF_PRIMES-2]; - } - int Spacing = LargestPrime/16; - - // Pick a set primes that are evenly spaced from (0 to LargestPrime) - // We divide this interval into 16 equal sized zones. We want to find - // one prime number that best represents that zone. - // - for (int iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing) - { - // Search for a prime number that is less than the target zone - // number given by iZone. - // - int Lower = Primes[0]; - for (int jPrime = 0; Primes[jPrime] != 0; jPrime++) - { - if (jPrime != 0 && TableSize % Primes[jPrime] == 0) continue; - int Upper = Primes[jPrime]; - if (Lower <= iZone && iZone <= Upper) - { - // Choose the closest lower prime number. - // - if (iZone - Lower <= Upper - iZone) - { - m_HashPrimes[iPrime++] = Lower; - } - else - { - m_HashPrimes[iPrime++] = Upper; - } - break; - } - Lower = Upper; - } - } - - // Alternate negative and positive numbers - // - for (iPrime = 0; iPrime < 16; iPrime += 2) - { - m_HashPrimes[iPrime] = TableSize-m_HashPrimes[iPrime]; - } - - // Shuffle the set of primes to reduce correlation with bits in - // hash key. - // - for (iPrime = 0; iPrime < 16-1; iPrime++) - { - int Pick = RANDOM_LONG(0, 15-iPrime); - int Temp = m_HashPrimes[Pick]; - m_HashPrimes[Pick] = m_HashPrimes[15-iPrime]; - m_HashPrimes[15-iPrime] = Temp; - } -} - -// Renumber nodes so that nodes that link together are together. -// -#define UNNUMBERED_NODE -1 -void CGraph::SortNodes(void) -{ - // We are using m_iPreviousNode to be the new node number. - // After assigning new node numbers to everything, we move - // things and patchup the links. - // - int iNodeCnt = 0; - m_pNodes[0].m_iPreviousNode = iNodeCnt++; - for (int i = 1; i < m_cNodes; i++) - { - m_pNodes[i].m_iPreviousNode = UNNUMBERED_NODE; - } - - for (i = 0; i < m_cNodes; i++) - { - // Run through all of this node's neighbors - // - for (int j = 0 ; j < m_pNodes[i].m_cNumLinks; j++ ) - { - int iDestNode = INodeLink(i, j); - if (m_pNodes[iDestNode].m_iPreviousNode == UNNUMBERED_NODE) - { - m_pNodes[iDestNode].m_iPreviousNode = iNodeCnt++; - } - } - } - - // Assign remaining node numbers to unlinked nodes. - // - for (i = 0; i < m_cNodes; i++) - { - if (m_pNodes[i].m_iPreviousNode == UNNUMBERED_NODE) - { - m_pNodes[i].m_iPreviousNode = iNodeCnt++; - } - } - - // Alter links to reflect new node numbers. - // - for (i = 0; i < m_cLinks; i++) - { - m_pLinkPool[i].m_iSrcNode = m_pNodes[m_pLinkPool[i].m_iSrcNode].m_iPreviousNode; - m_pLinkPool[i].m_iDestNode = m_pNodes[m_pLinkPool[i].m_iDestNode].m_iPreviousNode; - } - - // Rearrange nodes to reflect new node numbering. - // - for (i = 0; i < m_cNodes; i++) - { - while (m_pNodes[i].m_iPreviousNode != i) - { - // Move current node off to where it should be, and bring - // that other node back into the current slot. - // - int iDestNode = m_pNodes[i].m_iPreviousNode; - CNode TempNode = m_pNodes[iDestNode]; - m_pNodes[iDestNode] = m_pNodes[i]; - m_pNodes[i] = TempNode; - } - } -} - -void CGraph::BuildLinkLookups(void) -{ - m_nHashLinks = 3*m_cLinks/2 + 3; - - HashChoosePrimes(m_nHashLinks); - m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); - if (!m_pHashLinks) - { - ALERT(at_aiconsole, "Couldn't allocated Link Lookup Table.\n"); - return; - } - for (int i = 0; i < m_nHashLinks; i++) - { - m_pHashLinks[i] = ENTRY_STATE_EMPTY; - } - - for (i = 0; i < m_cLinks; i++) - { - CLink &link = Link(i); - HashInsert(link.m_iSrcNode, link.m_iDestNode, i); - } -#if 0 - for (i = 0; i < m_cLinks; i++) - { - CLink &link = Link(i); - int iKey; - HashSearch(link.m_iSrcNode, link.m_iDestNode, iKey); - if (iKey != i) - { - ALERT(at_aiconsole, "HashLinks don't match (%d versus %d)\n", i, iKey); - } - } -#endif -} - -void CGraph::BuildRegionTables(void) -{ - if (m_di) free(m_di); - - // Go ahead and setup for range searching the nodes for FindNearestNodes - // - m_di = (DIST_INFO *)calloc(sizeof(DIST_INFO), m_cNodes); - if (!m_di) - { - ALERT(at_aiconsole, "Couldn't allocated node ordering array.\n"); - return; - } - - // Calculate regions for all the nodes. - // - // - for (int i = 0; i < 3; i++) - { - m_RegionMin[i] = 999999999.0; // just a big number out there; - m_RegionMax[i] = -999999999.0; // just a big number out there; - } - for (i = 0; i < m_cNodes; i++) - { - if (m_pNodes[i].m_vecOrigin.x < m_RegionMin[0]) - m_RegionMin[0] = m_pNodes[i].m_vecOrigin.x; - if (m_pNodes[i].m_vecOrigin.y < m_RegionMin[1]) - m_RegionMin[1] = m_pNodes[i].m_vecOrigin.y; - if (m_pNodes[i].m_vecOrigin.z < m_RegionMin[2]) - m_RegionMin[2] = m_pNodes[i].m_vecOrigin.z; - - if (m_pNodes[i].m_vecOrigin.x > m_RegionMax[0]) - m_RegionMax[0] = m_pNodes[i].m_vecOrigin.x; - if (m_pNodes[i].m_vecOrigin.y > m_RegionMax[1]) - m_RegionMax[1] = m_pNodes[i].m_vecOrigin.y; - if (m_pNodes[i].m_vecOrigin.z > m_RegionMax[2]) - m_RegionMax[2] = m_pNodes[i].m_vecOrigin.z; - } - for (i = 0; i < m_cNodes; i++) - { - m_pNodes[i].m_Region[0] = CALC_RANGE(m_pNodes[i].m_vecOrigin.x, m_RegionMin[0], m_RegionMax[0]); - m_pNodes[i].m_Region[1] = CALC_RANGE(m_pNodes[i].m_vecOrigin.y, m_RegionMin[1], m_RegionMax[1]); - m_pNodes[i].m_Region[2] = CALC_RANGE(m_pNodes[i].m_vecOrigin.z, m_RegionMin[2], m_RegionMax[2]); - } - - for (i = 0; i < 3; i++) - { - for (int j = 0; j < NUM_RANGES; j++) - { - m_RangeStart[i][j] = 255; - m_RangeEnd[i][j] = 0; - } - for (j = 0; j < m_cNodes; j++) - { - m_di[j].m_SortedBy[i] = j; - } - - for (j = 0; j < m_cNodes - 1; j++) - { - int jNode = m_di[j].m_SortedBy[i]; - int jCodeX = m_pNodes[jNode].m_Region[0]; - int jCodeY = m_pNodes[jNode].m_Region[1]; - int jCodeZ = m_pNodes[jNode].m_Region[2]; - int jCode; - switch (i) - { - case 0: - jCode = (jCodeX << 16) + (jCodeY << 8) + jCodeZ; - break; - case 1: - jCode = (jCodeY << 16) + (jCodeZ << 8) + jCodeX; - break; - case 2: - jCode = (jCodeZ << 16) + (jCodeX << 8) + jCodeY; - break; - } - - for (int k = j+1; k < m_cNodes; k++) - { - int kNode = m_di[k].m_SortedBy[i]; - int kCodeX = m_pNodes[kNode].m_Region[0]; - int kCodeY = m_pNodes[kNode].m_Region[1]; - int kCodeZ = m_pNodes[kNode].m_Region[2]; - int kCode; - switch (i) - { - case 0: - kCode = (kCodeX << 16) + (kCodeY << 8) + kCodeZ; - break; - case 1: - kCode = (kCodeY << 16) + (kCodeZ << 8) + kCodeX; - break; - case 2: - kCode = (kCodeZ << 16) + (kCodeX << 8) + kCodeY; - break; - } - - if (kCode < jCode) - { - // Swap j and k entries. - // - int Tmp = m_di[j].m_SortedBy[i]; - m_di[j].m_SortedBy[i] = m_di[k].m_SortedBy[i]; - m_di[k].m_SortedBy[i] = Tmp; - } - } - } - } - - // Generate lookup tables. - // - for (i = 0; i < m_cNodes; i++) - { - int CodeX = m_pNodes[m_di[i].m_SortedBy[0]].m_Region[0]; - int CodeY = m_pNodes[m_di[i].m_SortedBy[1]].m_Region[1]; - int CodeZ = m_pNodes[m_di[i].m_SortedBy[2]].m_Region[2]; - - if (i < m_RangeStart[0][CodeX]) - { - m_RangeStart[0][CodeX] = i; - } - if (i < m_RangeStart[1][CodeY]) - { - m_RangeStart[1][CodeY] = i; - } - if (i < m_RangeStart[2][CodeZ]) - { - m_RangeStart[2][CodeZ] = i; - } - if (m_RangeEnd[0][CodeX] < i) - { - m_RangeEnd[0][CodeX] = i; - } - if (m_RangeEnd[1][CodeY] < i) - { - m_RangeEnd[1][CodeY] = i; - } - if (m_RangeEnd[2][CodeZ] < i) - { - m_RangeEnd[2][CodeZ] = i; - } - } - - // Initialize the cache. - // - memset(m_Cache, 0, sizeof(m_Cache)); -} - -void CGraph :: ComputeStaticRoutingTables( void ) -{ - int nRoutes = m_cNodes*m_cNodes; -#define FROM_TO(x,y) ((x)*m_cNodes+(y)) - short *Routes = new short[nRoutes]; - - int *pMyPath = new int[m_cNodes]; - unsigned short *BestNextNodes = new unsigned short[m_cNodes]; - char *pRoute = new char[m_cNodes*2]; - - - if (Routes && pMyPath && BestNextNodes && pRoute) - { - int nTotalCompressedSize = 0; - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) - { - for (int iCap = 0; iCap < 2; iCap++) - { - int iCapMask; - switch (iCap) - { - case 0: - iCapMask = 0; - break; - - case 1: - iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - break; - } - - - // Initialize Routing table to uncalculated. - // - for (int iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - Routes[FROM_TO(iFrom, iTo)] = -1; - } - } - - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = m_cNodes-1; iTo >= 0; iTo--) - { - if (Routes[FROM_TO(iFrom, iTo)] != -1) continue; - - int cPathSize = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - - // Use the computed path to update the routing table. - // - if (cPathSize > 1) - { - for (int iNode = 0; iNode < cPathSize-1; iNode++) - { - int iStart = pMyPath[iNode]; - int iNext = pMyPath[iNode+1]; - for (int iNode1 = iNode+1; iNode1 < cPathSize; iNode1++) - { - int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; - } - } -#if 0 - // Well, at first glance, this should work, but actually it's safer - // to be told explictly that you can take a series of node in a - // particular direction. Some links don't appear to have links in - // the opposite direction. - // - for (iNode = cPathSize-1; iNode >= 1; iNode--) - { - int iStart = pMyPath[iNode]; - int iNext = pMyPath[iNode-1]; - for (int iNode1 = iNode-1; iNode1 >= 0; iNode1--) - { - int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; - } - } -#endif - } - else - { - Routes[FROM_TO(iFrom, iTo)] = iFrom; - Routes[FROM_TO(iTo, iFrom)] = iTo; - } - } - } - - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - BestNextNodes[iTo] = Routes[FROM_TO(iFrom, iTo)]; - } - - // Compress this node's routing table. - // - int iLastNode = 9999999; // just really big. - int cSequence = 0; - int cRepeats = 0; - int CompressedSize = 0; - char *p = pRoute; - for (int i = 0; i < m_cNodes; i++) - { - BOOL CanRepeat = ((BestNextNodes[i] == iLastNode) && cRepeats < 127); - BOOL CanSequence = (BestNextNodes[i] == i && cSequence < 128); - - if (cRepeats) - { - if (CanRepeat) - { - cRepeats++; - } - else - { - // Emit the repeat phrase. - // - CompressedSize += 2; // (count-1, iLastNode-i) - *p++ = cRepeats - 1; - int a = iLastNode - iFrom; - int b = iLastNode - iFrom + m_cNodes; - int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) - { - *p++ = a; - } - else if (-128 <= b && b <= 127) - { - *p++ = b; - } - else if (-128 <= c && c <= 127) - { - *p++ = c; - } - else - { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); - } - cRepeats = 0; - - if (CanSequence) - { - // Start a sequence. - // - cSequence++; - } - else - { - // Start another repeat. - // - cRepeats++; - } - } - } - else if (cSequence) - { - if (CanSequence) - { - cSequence++; - } - else - { - // It may be advantageous to combine - // a single-entry sequence phrase with the - // next repeat phrase. - // - if (cSequence == 1 && CanRepeat) - { - // Combine with repeat phrase. - // - cRepeats = 2; - cSequence = 0; - } - else - { - // Emit the sequence phrase. - // - CompressedSize += 1; // (-count) - *p++ = -cSequence; - cSequence = 0; - - // Start a repeat sequence. - // - cRepeats++; - } - } - } - else - { - if (CanSequence) - { - // Start a sequence phrase. - // - cSequence++; - } - else - { - // Start a repeat sequence. - // - cRepeats++; - } - } - iLastNode = BestNextNodes[i]; - } - if (cRepeats) - { - // Emit the repeat phrase. - // - CompressedSize += 2; - *p++ = cRepeats - 1; -#if 0 - iLastNode = iFrom + *pRoute; - if (iLastNode >= m_cNodes) iLastNode -= m_cNodes; - else if (iLastNode < 0) iLastNode += m_cNodes; -#endif - int a = iLastNode - iFrom; - int b = iLastNode - iFrom + m_cNodes; - int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) - { - *p++ = a; - } - else if (-128 <= b && b <= 127) - { - *p++ = b; - } - else if (-128 <= c && c <= 127) - { - *p++ = c; - } - else - { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); - } - } - if (cSequence) - { - // Emit the Sequence phrase. - // - CompressedSize += 1; - *p++ = -cSequence; - } - - // Go find a place to store this thing and point to it. - // - int nRoute = p - pRoute; - if (m_pRouteInfo) - { - for (int i = 0; i < m_nRouteInfo - nRoute; i++) - { - if (memcmp(m_pRouteInfo + i, pRoute, nRoute) == 0) - { - break; - } - } - if (i < m_nRouteInfo - nRoute) - { - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = i; - } - else - { - char *Tmp = (char *)calloc(sizeof(char), (m_nRouteInfo + nRoute)); - memcpy(Tmp, m_pRouteInfo, m_nRouteInfo); - free(m_pRouteInfo); - m_pRouteInfo = Tmp; - memcpy(m_pRouteInfo + m_nRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = m_nRouteInfo; - m_nRouteInfo += nRoute; - nTotalCompressedSize += CompressedSize; - } - } - else - { - m_nRouteInfo = nRoute; - m_pRouteInfo = (char *)calloc(sizeof(char), nRoute); - memcpy(m_pRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = 0; - nTotalCompressedSize += CompressedSize; - } - } - } - } - ALERT( at_aiconsole, "Size of Routes = %d\n", nTotalCompressedSize); - } - if (Routes) delete Routes; - if (BestNextNodes) delete BestNextNodes; - if (pRoute) delete pRoute; - if (pMyPath) delete pMyPath; - Routes = 0; - BestNextNodes = 0; - pRoute = 0; - pMyPath = 0; - -#if 0 - TestRoutingTables(); -#endif - m_fRoutingComplete = TRUE; -} - -// Test those routing tables. Doesn't really work, yet. -// -void CGraph :: TestRoutingTables( void ) -{ - int *pMyPath = new int[m_cNodes]; - int *pMyPath2 = new int[m_cNodes]; - if (pMyPath && pMyPath2) - { - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) - { - for (int iCap = 0; iCap < 2; iCap++) - { - int iCapMask; - switch (iCap) - { - case 0: - iCapMask = 0; - break; - - case 1: - iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - break; - } - - for (int iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - m_fRoutingComplete = FALSE; - int cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - m_fRoutingComplete = TRUE; - int cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); - - // Unless we can look at the entire path, we can verify that it's correct. - // - if (cPathSize2 == MAX_PATH_SIZE) continue; - - // Compare distances. - // -#if 1 - float flDistance1 = 0.0; - for (int i = 0; i < cPathSize1-1; i++) - { - // Find the link from pMyPath[i] to pMyPath[i+1] - // - if (pMyPath[i] == pMyPath[i+1]) continue; - int iVisitNode; - BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath[i]].m_cNumLinks; iLink++) - { - iVisitNode = INodeLink ( pMyPath[i], iLink ); - if (iVisitNode == pMyPath[i+1]) - { - flDistance1 += m_pLinkPool[ m_pNodes[ pMyPath[i] ].m_iFirstLink + iLink].m_flWeight; - bFound = TRUE; - break; - } - } - if (!bFound) - { - ALERT(at_aiconsole, "No link.\n"); - } - } - - float flDistance2 = 0.0; - for (i = 0; i < cPathSize2-1; i++) - { - // Find the link from pMyPath2[i] to pMyPath2[i+1] - // - if (pMyPath2[i] == pMyPath2[i+1]) continue; - int iVisitNode; - BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath2[i]].m_cNumLinks; iLink++) - { - iVisitNode = INodeLink ( pMyPath2[i], iLink ); - if (iVisitNode == pMyPath2[i+1]) - { - flDistance2 += m_pLinkPool[ m_pNodes[ pMyPath2[i] ].m_iFirstLink + iLink].m_flWeight; - bFound = TRUE; - break; - } - } - if (!bFound) - { - ALERT(at_aiconsole, "No link.\n"); - } - } - if (fabs(flDistance1 - flDistance2) > 0.10) - { -#else - if (cPathSize1 != cPathSize2 || memcmp(pMyPath, pMyPath2, sizeof(int)*cPathSize1) != 0) - { -#endif - ALERT(at_aiconsole, "Routing is inconsistent!!!\n"); - ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap); - for (int i = 0; i < cPathSize1; i++) - { - ALERT(at_aiconsole, "%d ", pMyPath[i]); - } - ALERT(at_aiconsole, "\n(%d to %d |%d/%d)2:", iFrom, iTo, iHull, iCap); - for (i = 0; i < cPathSize2; i++) - { - ALERT(at_aiconsole, "%d ", pMyPath2[i]); - } - ALERT(at_aiconsole, "\n"); - m_fRoutingComplete = FALSE; - cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - m_fRoutingComplete = TRUE; - cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); - goto EnoughSaid; - } - } - } - } - } - } - -EnoughSaid: - - if (pMyPath) delete pMyPath; - if (pMyPath2) delete pMyPath2; - pMyPath = 0; - pMyPath2 = 0; -} - - - - - - - - - -//========================================================= -// CNodeViewer - Draws a graph of the shorted path from all nodes -// to current location (typically the player). It then draws -// as many connects as it can per frame, trying not to overflow the buffer -//========================================================= -class CNodeViewer : public CBaseEntity -{ -public: - void Spawn( void ); - - int m_iBaseNode; - int m_iDraw; - int m_nVisited; - int m_aFrom[128]; - int m_aTo[128]; - int m_iHull; - int m_afNodeType; - Vector m_vecColor; - - void FindNodeConnections( int iNode ); - void AddNode( int iFrom, int iTo ); - void EXPORT DrawThink( void ); - -}; -LINK_ENTITY_TO_CLASS( node_viewer, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_human, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_fly, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_large, CNodeViewer ); - -void CNodeViewer::Spawn( ) -{ - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_console, "Graph not ready!\n" ); - UTIL_Remove( this ); - return; - } - - - if (FClassnameIs( pev, "node_viewer_fly")) - { - m_iHull = NODE_FLY_HULL; - m_afNodeType = bits_NODE_AIR; - m_vecColor = Vector( 160, 100, 255 ); - } - else if (FClassnameIs( pev, "node_viewer_large")) - { - m_iHull = NODE_LARGE_HULL; - m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; - m_vecColor = Vector( 100, 255, 160 ); - } - else - { - m_iHull = NODE_HUMAN_HULL; - m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; - m_vecColor = Vector( 255, 160, 100 ); - } - - - m_iBaseNode = WorldGraph.FindNearestNode ( pev->origin, m_afNodeType ); - - if ( m_iBaseNode < 0 ) - { - ALERT( at_console, "No nearby node\n" ); - return; - } - - m_nVisited = 0; - - ALERT( at_aiconsole, "basenode %d\n", m_iBaseNode ); - - if (WorldGraph.m_cNodes < 128) - { - for (int i = 0; i < WorldGraph.m_cNodes; i++) - { - AddNode( i, WorldGraph.NextNodeInRoute( i, m_iBaseNode, m_iHull, 0 )); - } - } - else - { - // do a depth traversal - FindNodeConnections( m_iBaseNode ); - - int start = 0; - int end; - do { - end = m_nVisited; - // ALERT( at_console, "%d :", m_nVisited ); - for (end = m_nVisited; start < end; start++) - { - FindNodeConnections( m_aFrom[start] ); - FindNodeConnections( m_aTo[start] ); - } - } while (end != m_nVisited); - } - - ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); - - m_iDraw = 0; - SetThink( &CNodeViewer::DrawThink ); - pev->nextthink = gpGlobals->time; -} - - -void CNodeViewer :: FindNodeConnections ( int iNode ) -{ - AddNode( iNode, WorldGraph.NextNodeInRoute( iNode, m_iBaseNode, m_iHull, 0 )); - for ( int i = 0 ; i < WorldGraph.m_pNodes[ iNode ].m_cNumLinks ; i++ ) - { - CLink *pToLink = &WorldGraph.NodeLink( iNode, i); - AddNode( pToLink->m_iDestNode, WorldGraph.NextNodeInRoute( pToLink->m_iDestNode, m_iBaseNode, m_iHull, 0 )); - } -} - -void CNodeViewer::AddNode( int iFrom, int iTo ) -{ - if (m_nVisited >= 128) - { - return; - } - else - { - if (iFrom == iTo) - return; - - for (int i = 0; i < m_nVisited; i++) - { - if (m_aFrom[i] == iFrom && m_aTo[i] == iTo) - return; - if (m_aFrom[i] == iTo && m_aTo[i] == iFrom) - return; - } - m_aFrom[m_nVisited] = iFrom; - m_aTo[m_nVisited] = iTo; - m_nVisited++; - } -} - - -void CNodeViewer :: DrawThink( void ) -{ - pev->nextthink = gpGlobals->time; - - for (int i = 0; i < 10; i++) - { - if (m_iDraw == m_nVisited) - { - UTIL_Remove( this ); - return; - } - - extern short g_sModelIndexLaser; - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.x ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.y ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.x ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.y ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.z + NODE_HEIGHT ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 250 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( m_vecColor.x ); // r, g, b - WRITE_BYTE( m_vecColor.y ); // r, g, b - WRITE_BYTE( m_vecColor.z ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - m_iDraw++; - } -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// nodes.cpp - AI node tree stuff. +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "nodes.h" +#include "animation.h" +#include "doors.h" +#include "mod/AvHConstants.h" + +#define HULL_STEP_SIZE 16// how far the test hull moves on each step +#define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier) + +// to help eliminate node clutter by level designers, this is used to cap how many other nodes +// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()". +#define MAX_NODE_INITIAL_LINKS 128 +#define MAX_NODES 1024 + +extern DLL_GLOBAL edict_t *g_pBodyQueueHead; + +Vector VecBModelOrigin( entvars_t* pevBModel ); + +CGraph WorldGraph; + +LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); +LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); +#ifdef __linux__ +#include +#include +#define CreateDirectory(p, n) mkdir(p, 0777) +#endif +//========================================================= +// CGraph - InitGraph - prepares the graph for use. Frees any +// memory currently in use by the world graph, NULLs +// all pointers, and zeros the node count. +//========================================================= +void CGraph :: InitGraph( void) +{ + + // Make the graph unavailable + // + m_fGraphPresent = FALSE; + m_fGraphPointersSet = FALSE; + m_fRoutingComplete = FALSE; + + // Free the link pool + // + if ( m_pLinkPool ) + { + free ( m_pLinkPool ); + m_pLinkPool = NULL; + } + + // Free the node info + // + if ( m_pNodes ) + { + free ( m_pNodes ); + m_pNodes = NULL; + } + + if ( m_di ) + { + free ( m_di ); + m_di = NULL; + } + + // Free the routing info. + // + if ( m_pRouteInfo ) + { + free ( m_pRouteInfo ); + m_pRouteInfo = NULL; + } + + if (m_pHashLinks) + { + free(m_pHashLinks); + m_pHashLinks = NULL; + } + + // Zero node and link counts + // + m_cNodes = 0; + m_cLinks = 0; + m_nRouteInfo = 0; + + m_iLastActiveIdleSearch = 0; + m_iLastCoverSearch = 0; +} + +//========================================================= +// CGraph - AllocNodes - temporary function that mallocs a +// reasonable number of nodes so we can build the path which +// will be saved to disk. +//========================================================= +int CGraph :: AllocNodes ( void ) +{ +// malloc all of the nodes + WorldGraph.m_pNodes = (CNode *)calloc ( sizeof ( CNode ), MAX_NODES ); + +// could not malloc space for all the nodes! + if ( !WorldGraph.m_pNodes ) + { + ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", WorldGraph.m_cNodes ); + return FALSE; + } + + return TRUE; +} + +//========================================================= +// CGraph - LinkEntForLink - sometimes the ent that blocks +// a path is a usable door, in which case the monster just +// needs to face the door and fire it. In other cases, the +// monster needs to operate a button or lever to get the +// door to open. This function will return a pointer to the +// button if the monster needs to hit a button to open the +// door, or returns a pointer to the door if the monster +// need only use the door. +// +// pNode is the node the monster will be standing on when it +// will need to stop and trigger the ent. +//========================================================= +entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) +{ + edict_t *pentSearch; + edict_t *pentTrigger; + entvars_t *pevTrigger; + entvars_t *pevLinkEnt; + TraceResult tr; + + pevLinkEnt = pLink->m_pLinkEnt; + if ( !pevLinkEnt ) + return NULL; + + pentSearch = NULL;// start search at the top of the ent list. + + if ( FClassnameIs ( pevLinkEnt, kesFuncDoor ) || FClassnameIs ( pevLinkEnt, "func_door_rotating" ) ) + { + + ///!!!UNDONE - check for TOGGLE or STAY open doors here. If a door is in the way, and is + // TOGGLE or STAY OPEN, even monsters that can't open doors can go that way. + + if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) + {// door is use only, so the door is all the monster has to worry about + return pevLinkEnt; + } + + while ( 1 ) + { + pentTrigger = FIND_ENTITY_BY_TARGET ( pentSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger + + if ( FNullEnt( pentTrigger ) ) + {// no trigger found + + // right now this is a problem among auto-open doors, or any door that opens through the use + // of a trigger brush. Trigger brushes have no models, and don't show up in searches. Just allow + // monsters to open these sorts of doors for now. + return pevLinkEnt; + } + + pentSearch = pentTrigger; + pevTrigger = VARS( pentTrigger ); + + if ( FClassnameIs(pevTrigger, "func_button") || FClassnameIs(pevTrigger, "func_rot_button" ) ) + {// only buttons are handled right now. + + // trace from the node to the trigger, make sure it's one we can see from the node. + // !!!HACKHACK Use bodyqueue here cause there are no ents we really wish to ignore! + UTIL_TraceLine ( pNode->m_vecOrigin, VecBModelOrigin( pevTrigger ), ignore_monsters, g_pBodyQueueHead, &tr ); + + + if ( VARS(tr.pHit) == pevTrigger ) + {// good to go! + return VARS( tr.pHit ); + } + } + } + } + else + { + ALERT ( at_aiconsole, "Unsupported PathEnt:\n'%s'\n", STRING ( pevLinkEnt->classname ) ); + return NULL; + } +} + +//========================================================= +// CGraph - HandleLinkEnt - a brush ent is between two +// nodes that would otherwise be able to see each other. +// Given the monster's capability, determine whether +// or not the monster can go this way. +//========================================================= +int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ) +{ + edict_t *pentWorld; + CBaseEntity *pDoor; + TraceResult tr; + + if ( !m_fGraphPresent || !m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available + ALERT ( at_aiconsole, "Graph not ready!\n" ); + return FALSE; + } + + if ( FNullEnt ( pevLinkEnt ) ) + { + ALERT ( at_aiconsole, "dead path ent!\n" ); + return TRUE; + } + pentWorld = NULL; + +// func_door + if ( FClassnameIs( pevLinkEnt, kesFuncDoor ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) + {// ent is a door. + + pDoor = ( CBaseEntity::Instance( pevLinkEnt ) ); + + if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) + {// door is use only. + + if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) + {// let monster right through if he can open doors + return TRUE; + } + else + { + // monster should try for it if the door is open and looks as if it will stay that way + if ( pDoor->GetToggleState()== TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) + { + return TRUE; + } + + return FALSE; + } + } + else + {// door must be opened with a button or trigger field. + + // monster should try for it if the door is open and looks as if it will stay that way + if ( pDoor->GetToggleState() == TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) + { + return TRUE; + } + if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) + { + if ( !( pevLinkEnt->spawnflags & SF_DOOR_NOMONSTERS ) || queryType == NODEGRAPH_STATIC ) + return TRUE; + } + + return FALSE; + } + } +// func_breakable + else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) + { + return TRUE; + } + else + { + ALERT ( at_aiconsole, "Unhandled Ent in Path %s\n", STRING( pevLinkEnt->classname ) ); + return FALSE; + } + + return FALSE; +} + +#if 0 +//========================================================= +// FindNearestLink - finds the connection (line) nearest +// the given point. Returns FALSE if fails, or TRUE if it +// has stuffed the index into the nearest link pool connection +// into the passed int pointer, and a BOOL telling whether or +// not the point is along the line into the passed BOOL pointer. +//========================================================= +int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine ) +{ + int i, j;// loops + + int iNearestLink;// index into the link pool, this is the nearest node at any time. + float flMinDist;// the distance of of the nearest case so far + float flDistToLine;// the distance of the current test case + + BOOL fCurrentAlongLine; + BOOL fSuccess; + + //float flConstant;// line constant + Vector vecSpot1, vecSpot2; + Vector2D vec2Spot1, vec2Spot2, vec2TestPoint; + Vector2D vec2Normal;// line normal + Vector2D vec2Line; + + TraceResult tr; + + iNearestLink = -1;// prepare for failure + fSuccess = FALSE; + + flMinDist = 9999;// anything will be closer than this + +// go through all of the nodes, and each node's connections + int cSkip = 0;// how many links proper pairing allowed us to skip + int cChecked = 0;// how many links were checked + + for ( i = 0 ; i < m_cNodes ; i++ ) + { + vecSpot1 = m_pNodes[ i ].m_vecOrigin; + + if ( m_pNodes[ i ].m_cNumLinks <= 0 ) + {// this shouldn't happen! + ALERT ( at_aiconsole, "**Node %d has no links\n", i ); + continue; + } + + for ( j = 0 ; j < m_pNodes[ i ].m_cNumLinks ; j++ ) + { + /* + !!!This optimization only works when the node graph consists of properly linked pairs. + if ( INodeLink ( i, j ) <= i ) + { + // since we're going through the nodes in order, don't check + // any connections whose second node is lower in the list + // than the node we're currently working with. This eliminates + // redundant checks. + cSkip++; + continue; + } + */ + + vecSpot2 = PNodeLink ( i, j )->m_vecOrigin; + + // these values need a little attention now and then, or sometimes ramps cause trouble. + if ( fabs ( vecSpot1.z - vecTestPoint.z ) > 48 && fabs ( vecSpot2.z - vecTestPoint.z ) > 48 ) + { + // if both endpoints of the line are 32 units or more above or below the monster, + // the monster won't be able to get to them, so we do a bit of trivial rejection here. + // this may change if monsters are allowed to jump down. + // + // !!!LATER: some kind of clever X/Y hashing should be used here, too + continue; + } + +// now we have two endpoints for a line segment that we've not already checked. +// since all lines that make it this far are within -/+ 32 units of the test point's +// Z Plane, we can get away with doing the point->line check in 2d. + + cChecked++; + + vec2Spot1 = vecSpot1.Make2D(); + vec2Spot2 = vecSpot2.Make2D(); + vec2TestPoint = vecTestPoint.Make2D(); + + // get the line normal. + vec2Line = ( vec2Spot1 - vec2Spot2 ).Normalize(); + vec2Normal.x = -vec2Line.y; + vec2Normal.y = vec2Line.x; + + if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot1 ) ) > 0 ) + {// point outside of line + flDistToLine = ( vec2TestPoint - vec2Spot1 ).Length(); + fCurrentAlongLine = FALSE; + } + else if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot2 ) ) < 0 ) + {// point outside of line + flDistToLine = ( vec2TestPoint - vec2Spot2 ).Length(); + fCurrentAlongLine = FALSE; + } + else + {// point inside line + flDistToLine = fabs( DotProduct ( vec2TestPoint - vec2Spot2, vec2Normal ) ); + fCurrentAlongLine = TRUE; + } + + if ( flDistToLine < flMinDist ) + {// just found a line nearer than any other so far + + UTIL_TraceLine ( vecTestPoint, SourceNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); + + if ( tr.flFraction != 1.0 ) + {// crap. can't see the first node of this link, try to see the other + + UTIL_TraceLine ( vecTestPoint, DestNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); + if ( tr.flFraction != 1.0 ) + {// can't use this link, cause can't see either node! + continue; + } + + } + + fSuccess = TRUE;// we know there will be something to return. + flMinDist = flDistToLine; + iNearestLink = m_pNodes [ i ].m_iFirstLink + j; + *piNearestLink = m_pNodes[ i ].m_iFirstLink + j; + *pfAlongLine = fCurrentAlongLine; + } + } + } + +/* + if ( fSuccess ) + { + WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); + WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); + + WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.x ); + WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.y ); + WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.z + NODE_HEIGHT); + + WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.x ); + WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.y ); + WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.z + NODE_HEIGHT); + } +*/ + + ALERT ( at_aiconsole, "%d Checked\n", cChecked ); + return fSuccess; +} + +#endif + +int CGraph::HullIndex( const CBaseEntity *pEntity ) +{ + if ( pEntity->pev->movetype == MOVETYPE_FLY) + return NODE_FLY_HULL; + + if ( pEntity->pev->mins == Vector( -12, -12, 0 ) ) + return NODE_SMALL_HULL; + else if ( pEntity->pev->mins == VEC_HUMAN_HULL_MIN ) + return NODE_HUMAN_HULL; + else if ( pEntity->pev->mins == Vector ( -32, -32, 0 ) ) + return NODE_LARGE_HULL; + +// ALERT ( at_aiconsole, "Unknown Hull Mins!\n" ); + return NODE_HUMAN_HULL; +} + + +int CGraph::NodeType( const CBaseEntity *pEntity ) +{ + if ( pEntity->pev->movetype == MOVETYPE_FLY) + { + if (pEntity->pev->waterlevel != 0) + { + return bits_NODE_WATER; + } + else + { + return bits_NODE_AIR; + } + } + return bits_NODE_LAND; +} + + +// Sum up graph weights on the path from iStart to iDest to determine path length +float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) +{ + float distance = 0; + int iNext; + + int iMaxLoop = m_cNodes; + + int iCurrentNode = iStart; + int iCap = CapIndex( afCapMask ); + + while (iCurrentNode != iDest) + { + if (iMaxLoop-- <= 0) + { + ALERT( at_console, "Route Failure\n" ); + return 0; + } + + iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); + if (iCurrentNode == iNext) + { + //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); + return 0; + } + + int iLink; + HashSearch(iCurrentNode, iNext, iLink); + if (iLink < 0) + { + ALERT(at_console, "HashLinks is broken from %d to %d.\n", iCurrentNode, iDest); + return 0; + } + CLink &link = Link(iLink); + distance += link.m_flWeight; + + iCurrentNode = iNext; + } + + return distance; +} + + +// Parse the routing table at iCurrentNode for the next node on the shortest path to iDest +int CGraph::NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ) +{ + int iNext = iCurrentNode; + int nCount = iDest+1; + char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; + + // Until we decode the next best node + // + while (nCount > 0) + { + char ch = *pRoute++; + //ALERT(at_aiconsole, "C(%d)", ch); + if (ch < 0) + { + // Sequence phrase + // + ch = -ch; + if (nCount <= ch) + { + iNext = iDest; + nCount = 0; + //ALERT(at_aiconsole, "SEQ: iNext/iDest=%d\n", iNext); + } + else + { + //ALERT(at_aiconsole, "SEQ: nCount + ch (%d + %d)\n", nCount, ch); + nCount = nCount - ch; + } + } + else + { + //ALERT(at_aiconsole, "C(%d)", *pRoute); + + // Repeat phrase + // + if (nCount <= ch+1) + { + iNext = iCurrentNode + *pRoute; + if (iNext >= m_cNodes) iNext -= m_cNodes; + else if (iNext < 0) iNext += m_cNodes; + nCount = 0; + //ALERT(at_aiconsole, "REP: iNext=%d\n", iNext); + } + else + { + //ALERT(at_aiconsole, "REP: nCount - ch+1 (%d - %d+1)\n", nCount, ch); + nCount = nCount - ch - 1; + } + pRoute++; + } + } + + return iNext; +} + + +//========================================================= +// CGraph - FindShortestPath +// +// accepts a capability mask (afCapMask), and will only +// find a path usable by a monster with those capabilities +// returns the number of nodes copied into supplied array +//========================================================= +int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask) +{ + int iVisitNode; + int iCurrentNode; + int iNumPathNodes; + int iHullMask; + + if ( !m_fGraphPresent || !m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available or built + ALERT ( at_aiconsole, "Graph not ready!\n" ); + return FALSE; + } + + if ( iStart < 0 || iStart > m_cNodes ) + {// The start node is bad? + ALERT ( at_aiconsole, "Can't build a path, iStart is %d!\n", iStart ); + return FALSE; + } + + if (iStart == iDest) + { + piPath[0] = iStart; + piPath[1] = iDest; + return 2; + } + + // Is routing information present. + // + if (m_fRoutingComplete) + { + int iCap = CapIndex( afCapMask ); + + iNumPathNodes = 0; + piPath[iNumPathNodes++] = iStart; + iCurrentNode = iStart; + int iNext; + + //ALERT(at_aiconsole, "GOAL: %d to %d\n", iStart, iDest); + + // Until we arrive at the destination + // + while (iCurrentNode != iDest) + { + iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); + if (iCurrentNode == iNext) + { + //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); + return 0; + break; + } + if (iNumPathNodes >= MAX_PATH_SIZE) + { + //ALERT(at_aiconsole, "SVD: Don't return the entire path.\n"); + break; + } + piPath[iNumPathNodes++] = iNext; + iCurrentNode = iNext; + } + //ALERT( at_aiconsole, "SVD: Path with %d nodes.\n", iNumPathNodes); + } + else + { + CQueuePriority queue; + + switch( iHull ) + { + case NODE_SMALL_HULL: + iHullMask = bits_LINK_SMALL_HULL; + break; + case NODE_HUMAN_HULL: + iHullMask = bits_LINK_HUMAN_HULL; + break; + case NODE_LARGE_HULL: + iHullMask = bits_LINK_LARGE_HULL; + break; + case NODE_FLY_HULL: + iHullMask = bits_LINK_FLY_HULL; + break; + } + + // Mark all the nodes as unvisited. + // + for ( int i = 0; i < m_cNodes; i++) + { + m_pNodes[ i ].m_flClosestSoFar = -1.0; + } + + m_pNodes[ iStart ].m_flClosestSoFar = 0.0; + m_pNodes[ iStart ].m_iPreviousNode = iStart;// tag this as the origin node + queue.Insert( iStart, 0.0 );// insert start node + + while ( !queue.Empty() ) + { + // now pull a node out of the queue + float flCurrentDistance; + iCurrentNode = queue.Remove(flCurrentDistance); + + // For straight-line weights, the following Shortcut works. For arbitrary weights, + // it doesn't. + // + if (iCurrentNode == iDest) break; + + CNode *pCurrentNode = &m_pNodes[ iCurrentNode ]; + + for ( i = 0 ; i < pCurrentNode->m_cNumLinks ; i++ ) + {// run through all of this node's neighbors + + iVisitNode = INodeLink ( iCurrentNode, i ); + if ( ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo & iHullMask ) != iHullMask ) + {// monster is too large to walk this connection + //ALERT ( at_aiconsole, "fat ass %d/%d\n",m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo, iMonsterHull ); + continue; + } + // check the connection from the current node to the node we're about to mark visited and push into the queue + if ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt != NULL ) + {// there's a brush ent in the way! Don't mark this node or put it into the queue unless the monster can negotiate it + + if ( !HandleLinkEnt ( iCurrentNode, m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt, afCapMask, NODEGRAPH_STATIC ) ) + {// monster should not try to go this way. + continue; + } + } + float flOurDistance = flCurrentDistance + m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i].m_flWeight; + if ( m_pNodes[ iVisitNode ].m_flClosestSoFar < -0.5 + || flOurDistance < m_pNodes[ iVisitNode ].m_flClosestSoFar - 0.001 ) + { + m_pNodes[iVisitNode].m_flClosestSoFar = flOurDistance; + m_pNodes[iVisitNode].m_iPreviousNode = iCurrentNode; + + queue.Insert ( iVisitNode, flOurDistance ); + } + } + } + if ( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) + {// Destination is unreachable, no path found. + return 0; + } + + // the queue is not empty + + // now we must walk backwards through the m_iPreviousNode field, and count how many connections there are in the path + iCurrentNode = iDest; + iNumPathNodes = 1;// count the dest + + while ( iCurrentNode != iStart ) + { + iNumPathNodes++; + iCurrentNode = m_pNodes[ iCurrentNode ].m_iPreviousNode; + } + + iCurrentNode = iDest; + for ( i = iNumPathNodes - 1 ; i >= 0 ; i-- ) + { + piPath[ i ] = iCurrentNode; + iCurrentNode = m_pNodes [ iCurrentNode ].m_iPreviousNode; + } + } + +#if 0 + + if (m_fRoutingComplete) + { + // This will draw the entire path that was generated for the monster. + + for ( int i = 0 ; i < iNumPathNodes - 1 ; i++ ) + { + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + + WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.x ); + WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.y ); + WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.z + NODE_HEIGHT ); + + WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.x ); + WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.y ); + WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.z + NODE_HEIGHT ); + MESSAGE_END(); + } + } + +#endif +#if 0 // MAZE map + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + + WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.x ); + WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.y ); + WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.z + NODE_HEIGHT ); + + WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.x ); + WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.y ); + WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.z + NODE_HEIGHT ); + MESSAGE_END(); +#endif + + return iNumPathNodes; +} + +inline ULONG Hash(void *p, int len) +{ + CRC32_t ulCrc; + CRC32_INIT(&ulCrc); + CRC32_PROCESS_BUFFER(&ulCrc, p, len); + return CRC32_FINAL(ulCrc); +} + +void inline CalcBounds(int &Lower, int &Upper, int Goal, int Best) +{ + int Temp = 2*Goal - Best; + if (Best > Goal) + { + Lower = max(0, Temp); + Upper = Best; + } + else + { + Upper = min(255, Temp); + Lower = Best; + } +} + +// Convert from [-8192,8192] to [0, 255] +// +inline int CALC_RANGE(int x, int lower, int upper) +{ + return NUM_RANGES*(x-lower)/((upper-lower+1)); +} + + +void inline UpdateRange(int &minValue, int &maxValue, int Goal, int Best) +{ + int Lower, Upper; + CalcBounds(Lower, Upper, Goal, Best); + if (Upper < maxValue) maxValue = Upper; + if (minValue < Lower) minValue = Lower; +} + +void CGraph :: CheckNode(Vector vecOrigin, int iNode) +{ + // Have we already seen this point before?. + // + if (m_di[iNode].m_CheckedEvent == m_CheckedCounter) return; + m_di[iNode].m_CheckedEvent = m_CheckedCounter; + + float flDist = ( vecOrigin - m_pNodes[ iNode ].m_vecOriginPeek ).Length(); + + if ( flDist < m_flShortest ) + { + TraceResult tr; + + // make sure that vecOrigin can trace to this node! + UTIL_TraceLine ( vecOrigin, m_pNodes[ iNode ].m_vecOriginPeek, ignore_monsters, 0, &tr ); + + if ( tr.flFraction == 1.0 ) + { + m_iNearest = iNode; + m_flShortest = flDist; + + UpdateRange(m_minX, m_maxX, CALC_RANGE(vecOrigin.x, m_RegionMin[0], m_RegionMax[0]), m_pNodes[iNode].m_Region[0]); + UpdateRange(m_minY, m_maxY, CALC_RANGE(vecOrigin.y, m_RegionMin[1], m_RegionMax[1]), m_pNodes[iNode].m_Region[1]); + UpdateRange(m_minZ, m_maxZ, CALC_RANGE(vecOrigin.z, m_RegionMin[2], m_RegionMax[2]), m_pNodes[iNode].m_Region[2]); + + // From maxCircle, calculate maximum bounds box. All points must be + // simultaneously inside all bounds of the box. + // + m_minBoxX = CALC_RANGE(vecOrigin.x - flDist, m_RegionMin[0], m_RegionMax[0]); + m_maxBoxX = CALC_RANGE(vecOrigin.x + flDist, m_RegionMin[0], m_RegionMax[0]); + m_minBoxY = CALC_RANGE(vecOrigin.y - flDist, m_RegionMin[1], m_RegionMax[1]); + m_maxBoxY = CALC_RANGE(vecOrigin.y + flDist, m_RegionMin[1], m_RegionMax[1]); + m_minBoxZ = CALC_RANGE(vecOrigin.z - flDist, m_RegionMin[2], m_RegionMax[2]); + m_maxBoxZ = CALC_RANGE(vecOrigin.z + flDist, m_RegionMin[2], m_RegionMax[2]); + } + } +} + +//========================================================= +// CGraph - FindNearestNode - returns the index of the node nearest +// the given vector -1 is failure (couldn't find a valid +// near node ) +//========================================================= +int CGraph :: FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ) +{ + return FindNearestNode( vecOrigin, NodeType( pEntity ) ); +} + +int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) +{ + int i; + TraceResult tr; + + if ( !m_fGraphPresent || !m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available + ALERT ( at_aiconsole, "Graph not ready!\n" ); + return -1; + } + + // Check with the cache + // + ULONG iHash = (CACHE_SIZE-1) & Hash((void *)(const float *)vecOrigin, sizeof(vecOrigin)); + if (m_Cache[iHash].v == vecOrigin) + { + //ALERT(at_aiconsole, "Cache Hit.\n"); + return m_Cache[iHash].n; + } + else + { + //ALERT(at_aiconsole, "Cache Miss.\n"); + } + + // Mark all points as unchecked. + // + m_CheckedCounter++; + if (m_CheckedCounter == 0) + { + for (int i = 0; i < m_cNodes; i++) + { + m_di[i].m_CheckedEvent = 0; + } + m_CheckedCounter++; + } + + m_iNearest = -1; + m_flShortest = 999999.0; // just a big number. + + // If we can find a visible point, then let CalcBounds set the limits, but if + // we have no visible point at all to start with, then don't restrict the limits. + // +#if 1 + m_minX = 0; m_maxX = 255; + m_minY = 0; m_maxY = 255; + m_minZ = 0; m_maxZ = 255; + m_minBoxX = 0; m_maxBoxX = 255; + m_minBoxY = 0; m_maxBoxY = 255; + m_minBoxZ = 0; m_maxBoxZ = 255; +#else + m_minBoxX = CALC_RANGE(vecOrigin.x - flDist, m_RegionMin[0], m_RegionMax[0]); + m_maxBoxX = CALC_RANGE(vecOrigin.x + flDist, m_RegionMin[0], m_RegionMax[0]); + m_minBoxY = CALC_RANGE(vecOrigin.y - flDist, m_RegionMin[1], m_RegionMax[1]); + m_maxBoxY = CALC_RANGE(vecOrigin.y + flDist, m_RegionMin[1], m_RegionMax[1]); + m_minBoxZ = CALC_RANGE(vecOrigin.z - flDist, m_RegionMin[2], m_RegionMax[2]); + m_maxBoxZ = CALC_RANGE(vecOrigin.z + flDist, m_RegionMin[2], m_RegionMax[2]) + CalcBounds(m_minX, m_maxX, CALC_RANGE(vecOrigin.x, m_RegionMin[0], m_RegionMax[0]), m_pNodes[m_iNearest].m_Region[0]); + CalcBounds(m_minY, m_maxY, CALC_RANGE(vecOrigin.y, m_RegionMin[1], m_RegionMax[1]), m_pNodes[m_iNearest].m_Region[1]); + CalcBounds(m_minZ, m_maxZ, CALC_RANGE(vecOrigin.z, m_RegionMin[2], m_RegionMax[2]), m_pNodes[m_iNearest].m_Region[2]); +#endif + + int halfX = (m_minX+m_maxX)/2; + int halfY = (m_minY+m_maxY)/2; + int halfZ = (m_minZ+m_maxZ)/2; + + int j; + + for (i = halfX; i >= m_minX; i--) + { + for (j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++) + { + if (!(m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes)) continue; + + int rgY = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[1]; + if (rgY > m_maxBoxY) break; + if (rgY < m_minBoxY) continue; + + int rgZ = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[2]; + if (rgZ < m_minBoxZ) continue; + if (rgZ > m_maxBoxZ) continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[0]); + } + } + + for (i = max(m_minY,halfY+1); i <= m_maxY; i++) + { + for (j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++) + { + if (!(m_pNodes[m_di[j].m_SortedBy[1]].m_afNodeInfo & afNodeTypes)) continue; + + int rgZ = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[2]; + if (rgZ > m_maxBoxZ) break; + if (rgZ < m_minBoxZ) continue; + int rgX = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[0]; + if (rgX < m_minBoxX) continue; + if (rgX > m_maxBoxX) continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); + } + } + + for (i = min(m_maxZ,halfZ); i >= m_minZ; i--) + { + for (j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++) + { + if (!(m_pNodes[m_di[j].m_SortedBy[2]].m_afNodeInfo & afNodeTypes)) continue; + + int rgX = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[0]; + if (rgX > m_maxBoxX) break; + if (rgX < m_minBoxX) continue; + int rgY = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[1]; + if (rgY < m_minBoxY) continue; + if (rgY > m_maxBoxY) continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); + } + } + + for (i = max(m_minX,halfX+1); i <= m_maxX; i++) + { + for (j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++) + { + if (!(m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes)) continue; + + int rgY = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[1]; + if (rgY > m_maxBoxY) break; + if (rgY < m_minBoxY) continue; + + int rgZ = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[2]; + if (rgZ < m_minBoxZ) continue; + if (rgZ > m_maxBoxZ) continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[0]); + } + } + + for (i = min(m_maxY,halfY); i >= m_minY; i--) + { + for (j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++) + { + if (!(m_pNodes[m_di[j].m_SortedBy[1]].m_afNodeInfo & afNodeTypes)) continue; + + int rgZ = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[2]; + if (rgZ > m_maxBoxZ) break; + if (rgZ < m_minBoxZ) continue; + int rgX = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[0]; + if (rgX < m_minBoxX) continue; + if (rgX > m_maxBoxX) continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); + } + } + + for (i = max(m_minZ,halfZ+1); i <= m_maxZ; i++) + { + for (j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++) + { + if (!(m_pNodes[m_di[j].m_SortedBy[2]].m_afNodeInfo & afNodeTypes)) continue; + + int rgX = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[0]; + if (rgX > m_maxBoxX) break; + if (rgX < m_minBoxX) continue; + int rgY = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[1]; + if (rgY < m_minBoxY) continue; + if (rgY > m_maxBoxY) continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); + } + } + +#if 0 + // Verify our answers. + // + int iNearestCheck = -1; + m_flShortest = 8192;// find nodes within this radius + + for ( i = 0 ; i < m_cNodes ; i++ ) + { + float flDist = ( vecOrigin - m_pNodes[ i ].m_vecOriginPeek ).Length(); + + if ( flDist < m_flShortest ) + { + // make sure that vecOrigin can trace to this node! + UTIL_TraceLine ( vecOrigin, m_pNodes[ i ].m_vecOriginPeek, ignore_monsters, 0, &tr ); + + if ( tr.flFraction == 1.0 ) + { + iNearestCheck = i; + m_flShortest = flDist; + } + } + } + + if (iNearestCheck != m_iNearest) + { + ALERT( at_aiconsole, "NOT closest %d(%f,%f,%f) %d(%f,%f,%f).\n", + iNearestCheck, + m_pNodes[iNearestCheck].m_vecOriginPeek.x, + m_pNodes[iNearestCheck].m_vecOriginPeek.y, + m_pNodes[iNearestCheck].m_vecOriginPeek.z, + m_iNearest, + (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.x), + (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.y), + (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.z)); + } + if (m_iNearest == -1) + { + ALERT(at_aiconsole, "All that work for nothing.\n"); + } +#endif + m_Cache[iHash].v = vecOrigin; + m_Cache[iHash].n = m_iNearest; + return m_iNearest; +} + +//========================================================= +// CGraph - ShowNodeConnections - draws a line from the given node +// to all connected nodes +//========================================================= +void CGraph :: ShowNodeConnections ( int iNode ) +{ + Vector vecSpot; + CNode *pNode; + CNode *pLinkNode; + int i; + + if ( !m_fGraphPresent || !m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available or built + ALERT ( at_aiconsole, "Graph not ready!\n" ); + return; + } + + if ( iNode < 0 ) + { + ALERT( at_aiconsole, "Can't show connections for node %d\n", iNode ); + return; + } + + pNode = &m_pNodes[ iNode ]; + + UTIL_ParticleEffect( pNode->m_vecOrigin, g_vecZero, 255, 20 );// show node position + + if ( pNode->m_cNumLinks <= 0 ) + {// no connections! + ALERT ( at_aiconsole, "**No Connections!\n" ); + } + + for ( i = 0 ; i < pNode->m_cNumLinks ; i++ ) + { + + pLinkNode = &Node( NodeLink( iNode, i).m_iDestNode ); + vecSpot = pLinkNode->m_vecOrigin; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + + WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.x ); + WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.y ); + WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.z + NODE_HEIGHT ); + + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + NODE_HEIGHT ); + MESSAGE_END(); + + } +} + +//========================================================= +// CGraph - LinkVisibleNodes - the first, most basic +// function of node graph creation, this connects every +// node to every other node that it can see. Expects a +// pointer to an empty connection pool and a file pointer +// to write progress to. Returns the total number of initial +// links. +// +// If there's a problem with this process, the index +// of the offending node will be written to piBadNode +//========================================================= +int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ) +{ + int i,j,z; + edict_t *pTraceEnt; + int cTotalLinks, cLinksThisNode, cMaxInitialLinks; + TraceResult tr; + + // !!!BUGBUG - this function returns 0 if there is a problem in the middle of connecting the graph + // it also returns 0 if none of the nodes in a level can see each other. piBadNode is ALWAYS read + // by BuildNodeGraph() if this function returns a 0, so make sure that it doesn't get some random + // number back. + *piBadNode = 0; + + + if ( m_cNodes <= 0 ) + { + ALERT ( at_aiconsole, "No Nodes!\n" ); + return FALSE; + } + + // if the file pointer is bad, don't blow up, just don't write the + // file. + if ( !file ) + { + ALERT ( at_aiconsole, "**LinkVisibleNodes:\ncan't write to file." ); + } + else + { + fprintf ( file, "----------------------------------------------------------------------------\n" ); + fprintf ( file, "LinkVisibleNodes - Initial Connections\n" ); + fprintf ( file, "----------------------------------------------------------------------------\n" ); + } + + cTotalLinks = 0;// start with no connections + + // to keep track of the maximum number of initial links any node had so far. + // this lets us keep an eye on MAX_NODE_INITIAL_LINKS to ensure that we are + // being generous enough. + cMaxInitialLinks = 0; + + for ( i = 0 ; i < m_cNodes ; i++ ) + { + cLinksThisNode = 0;// reset this count for each node. + + if ( file ) + { + fprintf ( file, "Node #%4d:\n\n", i ); + } + + for ( z = 0 ; z < MAX_NODE_INITIAL_LINKS ; z++ ) + {// clear out the important fields in the link pool for this node + pLinkPool [ cTotalLinks + z ].m_iSrcNode = i;// so each link knows which node it originates from + pLinkPool [ cTotalLinks + z ].m_iDestNode = 0; + pLinkPool [ cTotalLinks + z ].m_pLinkEnt = NULL; + } + + m_pNodes [ i ].m_iFirstLink = cTotalLinks; + + // now build a list of every other node that this node can see + for ( j = 0 ; j < m_cNodes ; j++ ) + { + if ( j == i ) + {// don't connect to self! + continue; + } + +#if 0 + + if ( (m_pNodes[ i ].m_afNodeInfo & bits_NODE_WATER) != (m_pNodes[ j ].m_afNodeInfo & bits_NODE_WATER) ) + { + // don't connect water nodes to air nodes or land nodes. It just wouldn't be prudent at this juncture. + continue; + } +#else + if ( (m_pNodes[ i ].m_afNodeInfo & bits_NODE_GROUP_REALM) != (m_pNodes[ j ].m_afNodeInfo & bits_NODE_GROUP_REALM) ) + { + // don't connect air nodes to water nodes to land nodes. It just wouldn't be prudent at this juncture. + continue; + } +#endif + + tr.pHit = NULL;// clear every time so we don't get stuck with last trace's hit ent + pTraceEnt = 0; + + UTIL_TraceLine ( m_pNodes[ i ].m_vecOrigin, + m_pNodes[ j ].m_vecOrigin, + ignore_monsters, + g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about + &tr ); + + + if ( tr.fStartSolid ) + continue; + + if ( tr.flFraction != 1.0 ) + {// trace hit a brush ent, trace backwards to make sure that this ent is the only thing in the way. + + pTraceEnt = tr.pHit;// store the ent that the trace hit, for comparison + + UTIL_TraceLine ( m_pNodes[ j ].m_vecOrigin, + m_pNodes[ i ].m_vecOrigin, + ignore_monsters, + g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about + &tr ); + + +// there is a solid_bsp ent in the way of these two nodes, so we must record several things about in order to keep +// track of it in the pathfinding code, as well as through save and restore of the node graph. ANY data that is manipulated +// as part of the process of adding a LINKENT to a connection here must also be done in CGraph::SetGraphPointers, where reloaded +// graphs are prepared for use. + if ( tr.pHit == pTraceEnt && !FClassnameIs( tr.pHit, "worldspawn" ) ) + { + // get a pointer + pLinkPool [ cTotalLinks ].m_pLinkEnt = VARS( tr.pHit ); + + // record the modelname, so that we can save/load node trees + memcpy( pLinkPool [ cTotalLinks ].m_szLinkEntModelname, STRING( VARS(tr.pHit)->model ), 4 ); + + // set the flag for this ent that indicates that it is attached to the world graph + // if this ent is removed from the world, it must also be removed from the connections + // that it formerly blocked. + if ( !FBitSet( VARS( tr.pHit )->flags, FL_GRAPHED ) ) + { + VARS( tr.pHit )->flags += FL_GRAPHED; + } + } + else + {// even if the ent wasn't there, these nodes couldn't be connected. Skip. + continue; + } + } + + if ( file ) + { + fprintf ( file, "%4d", j ); + + if ( !FNullEnt( pLinkPool[ cTotalLinks ].m_pLinkEnt ) ) + {// record info about the ent in the way, if any. + fprintf ( file, " Entity on connection: %s, name: %s Model: %s", STRING( VARS( pTraceEnt )->classname ), STRING ( VARS( pTraceEnt )->targetname ), STRING ( VARS(tr.pHit)->model ) ); + } + + fprintf ( file, "\n", j ); + } + + pLinkPool [ cTotalLinks ].m_iDestNode = j; + cLinksThisNode++; + cTotalLinks++; + + // If we hit this, either a level designer is placing too many nodes in the same area, or + // we need to allow for a larger initial link pool. + if ( cLinksThisNode == MAX_NODE_INITIAL_LINKS ) + { + ALERT ( at_aiconsole, "**LinkVisibleNodes:\nNode %d has NodeLinks > MAX_NODE_INITIAL_LINKS", i ); + fprintf ( file, "** NODE %d HAS NodeLinks > MAX_NODE_INITIAL_LINKS **\n", i ); + *piBadNode = i; + return FALSE; + } + else if ( cTotalLinks > MAX_NODE_INITIAL_LINKS * m_cNodes ) + {// this is paranoia + ALERT ( at_aiconsole, "**LinkVisibleNodes:\nTotalLinks > MAX_NODE_INITIAL_LINKS * NUMNODES" ); + *piBadNode = i; + return FALSE; + } + + if ( cLinksThisNode == 0 ) + { + fprintf ( file, "**NO INITIAL LINKS**\n" ); + } + + // record the connection info in the link pool + WorldGraph.m_pNodes [ i ].m_cNumLinks = cLinksThisNode; + + // keep track of the most initial links ANY node had, so we can figure out + // if we have a large enough default link pool + if ( cLinksThisNode > cMaxInitialLinks ) + { + cMaxInitialLinks = cLinksThisNode; + } + } + + + if ( file ) + { + fprintf ( file, "----------------------------------------------------------------------------\n" ); + } + } + + fprintf ( file, "\n%4d Total Initial Connections - %4d Maximum connections for a single node.\n", cTotalLinks, cMaxInitialLinks ); + fprintf ( file, "----------------------------------------------------------------------------\n\n\n" ); + + return cTotalLinks; +} + +//========================================================= +// CGraph - RejectInlineLinks - expects a pointer to a link +// pool, and a pointer to and already-open file ( if you +// want status reports written to disk ). RETURNS the number +// of connections that were rejected +//========================================================= +int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file ) +{ + int i,j,k; + + int cRejectedLinks; + + BOOL fRestartLoop;// have to restart the J loop if we eliminate a link. + + CNode *pSrcNode; + CNode *pCheckNode;// the node we are testing for (one of pSrcNode's connections) + CNode *pTestNode;// the node we are checking against ( also one of pSrcNode's connections) + + float flDistToTestNode, flDistToCheckNode; + + Vector2D vec2DirToTestNode, vec2DirToCheckNode; + + if ( file ) + { + fprintf ( file, "----------------------------------------------------------------------------\n" ); + fprintf ( file, "InLine Rejection:\n" ); + fprintf ( file, "----------------------------------------------------------------------------\n" ); + } + + cRejectedLinks = 0; + + for ( i = 0 ; i < m_cNodes ; i++ ) + { + pSrcNode = &m_pNodes[ i ]; + + if ( file ) + { + fprintf ( file, "Node %3d:\n", i ); + } + + for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) + { + pCheckNode = &m_pNodes[ pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; + + vec2DirToCheckNode = ( pCheckNode->m_vecOrigin - pSrcNode->m_vecOrigin ).Make2D(); + flDistToCheckNode = vec2DirToCheckNode.Length(); + vec2DirToCheckNode = vec2DirToCheckNode.Normalize(); + + pLinkPool[ pSrcNode->m_iFirstLink + j ].m_flWeight = flDistToCheckNode; + + fRestartLoop = FALSE; + for ( k = 0 ; k < pSrcNode->m_cNumLinks && !fRestartLoop ; k++ ) + { + if ( k == j ) + {// don't check against same node + continue; + } + + pTestNode = &m_pNodes [ pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode ]; + + vec2DirToTestNode = ( pTestNode->m_vecOrigin - pSrcNode->m_vecOrigin ).Make2D(); + + flDistToTestNode = vec2DirToTestNode.Length(); + vec2DirToTestNode = vec2DirToTestNode.Normalize(); + + if ( DotProduct ( vec2DirToCheckNode, vec2DirToTestNode ) >= 0.998 ) + { + // there's a chance that TestNode intersects the line to CheckNode. If so, we should disconnect the link to CheckNode. + if ( flDistToTestNode < flDistToCheckNode ) + { + if ( file ) + { + fprintf ( file, "REJECTED NODE %3d through Node %3d, Dot = %8f\n", pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode, pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode, DotProduct ( vec2DirToCheckNode, vec2DirToTestNode ) ); + } + + pLinkPool[ pSrcNode->m_iFirstLink + j ] = pLinkPool[ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; + pSrcNode->m_cNumLinks--; + j--; + + cRejectedLinks++;// keeping track of how many links are cut, so that we can return that value. + + fRestartLoop = TRUE; + } + } + } + } + + if ( file ) + { + fprintf ( file, "----------------------------------------------------------------------------\n\n" ); + } + } + + return cRejectedLinks; +} + +//========================================================= +// TestHull is a modelless clip hull that verifies reachable +// nodes by walking from every node to each of it's connections +//========================================================= +class CTestHull : public CBaseMonster +{ + +public: + void Spawn( entvars_t *pevMasterNode ); + virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + void EXPORT CallBuildNodeGraph ( void ); + void BuildNodeGraph ( void ); + void EXPORT ShowBadNode ( void ); + void EXPORT DropDelay ( void ); + void EXPORT PathFind ( void ); + + Vector vecBadNodeOrigin; +}; + +LINK_ENTITY_TO_CLASS( testhull, CTestHull ); + +//========================================================= +// CTestHull::Spawn +//========================================================= +void CTestHull :: Spawn( entvars_t *pevMasterNode ) +{ + SET_MODEL(ENT(pev), "models/player.mdl"); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + pev->effects = 0; + pev->health = 50; + pev->yaw_speed = 8; + + if ( WorldGraph.m_fGraphPresent ) + {// graph loaded from disk, so we don't need the test hull + SetThink ( &CTestHull::SUB_Remove ); + pev->nextthink = gpGlobals->time; + } + else + { + SetThink ( &CTestHull::DropDelay ); + pev->nextthink = gpGlobals->time + 1; + } + + // Make this invisible + // UNDONE: Shouldn't we just use EF_NODRAW? This doesn't need to go to the client. + pev->rendermode = kRenderTransTexture; + pev->renderamt = 0; +} + +//========================================================= +// TestHull::DropDelay - spawns TestHull on top of +// the 0th node and drops it to the ground. +//========================================================= +void CTestHull::DropDelay ( void ) +{ + UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." ); + + UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); + + SetThink ( &CTestHull::CallBuildNodeGraph ); + + pev->nextthink = gpGlobals->time + 1; +} + +//========================================================= +// nodes start out as ents in the world. As they are spawned, +// the node info is recorded then the ents are discarded. +//========================================================= +void CNodeEnt :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "hinttype")) + { + m_sHintType = (short)atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + + if (FStrEq(pkvd->szKeyName, "activity")) + { + m_sHintActivity = (short)atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +//========================================================= +//========================================================= +void CNodeEnt :: Spawn( void ) +{ + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT;// always solid_not + + if ( WorldGraph.m_fGraphPresent ) + {// graph loaded from disk, so discard all these node ents as soon as they spawn + REMOVE_ENTITY( edict() ); + return; + } + + if ( WorldGraph.m_cNodes == 0 ) + {// this is the first node to spawn, spawn the test hull entity that builds and walks the node tree + CTestHull *pHull = GetClassPtr((CTestHull *)NULL); + pHull->Spawn( pev ); + } + + if ( WorldGraph.m_cNodes >= MAX_NODES ) + { + ALERT ( at_aiconsole, "cNodes > MAX_NODES\n" ); + return; + } + + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_vecOriginPeek = + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_vecOrigin = pev->origin; + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_flHintYaw = pev->angles.y; + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_sHintType = m_sHintType; + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_sHintActivity = m_sHintActivity; + + if (FClassnameIs( pev, "info_node_air" )) + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = bits_NODE_AIR; + else + WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = 0; + + WorldGraph.m_cNodes++; + + REMOVE_ENTITY( edict() ); +} + +//========================================================= +// CTestHull - ShowBadNode - makes a bad node fizzle. When +// there's a problem with node graph generation, the test +// hull will be placed up the bad node's location and will generate +// particles +//========================================================= +void CTestHull :: ShowBadNode( void ) +{ + pev->movetype = MOVETYPE_FLY; + pev->angles.y = pev->angles.y + 4; + + UTIL_MakeVectors ( pev->angles ); + + UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); + UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * 64, g_vecZero, 255, 25 ); + UTIL_ParticleEffect ( pev->origin - gpGlobals->v_forward * 64, g_vecZero, 255, 25 ); + UTIL_ParticleEffect ( pev->origin + gpGlobals->v_right * 64, g_vecZero, 255, 25 ); + UTIL_ParticleEffect ( pev->origin - gpGlobals->v_right * 64, g_vecZero, 255, 25 ); + + pev->nextthink = gpGlobals->time + 0.1; +} + +extern BOOL gTouchDisabled; +void CTestHull::CallBuildNodeGraph( void ) +{ + // TOUCH HACK -- Don't allow this entity to call anyone's "touch" function + gTouchDisabled = TRUE; + BuildNodeGraph(); + gTouchDisabled = FALSE; + // Undo TOUCH HACK +} + +//========================================================= +// BuildNodeGraph - think function called by the empty walk +// hull that is spawned by the first node to spawn. This +// function links all nodes that can see each other, then +// eliminates all inline links, then uses a monster-sized +// hull that walks between each node and each of its links +// to ensure that a monster can actually fit through the space +//========================================================= +void CTestHull :: BuildNodeGraph( void ) +{ + TraceResult tr; + FILE *file; + + char szNrpFilename [MAX_PATH];// text node report filename + + CLink *pTempPool; // temporary link pool + + CNode *pSrcNode;// node we're currently working with + CNode *pDestNode;// the other node in comparison operations + + BOOL fSkipRemainingHulls;//if smallest hull can't fit, don't check any others + BOOL fPairsValid;// are all links in the graph evenly paired? + + int i, j, hull; + + int iBadNode;// this is the node that caused graph generation to fail + + int cMaxInitialLinks = 0; + int cMaxValidLinks = 0; + + int iPoolIndex = 0; + int cPoolLinks;// number of links in the pool. + + Vector vecDirToCheckNode; + Vector vecDirToTestNode; + Vector vecStepCheckDir; + Vector vecTraceSpot; + Vector vecSpot; + + Vector2D vec2DirToCheckNode; + Vector2D vec2DirToTestNode; + Vector2D vec2StepCheckDir; + Vector2D vec2TraceSpot; + Vector2D vec2Spot; + + float flYaw;// use this stuff to walk the hull between nodes + float flDist; + int step; + + SetThink ( &CTestHull::SUB_Remove );// no matter what happens, the hull gets rid of itself. + pev->nextthink = gpGlobals->time; + +// malloc a swollen temporary connection pool that we trim down after we know exactly how many connections there are. + pTempPool = (CLink *)calloc ( sizeof ( CLink ) , ( WorldGraph.m_cNodes * MAX_NODE_INITIAL_LINKS ) ); + if ( !pTempPool ) + { + ALERT ( at_aiconsole, "**Could not malloc TempPool!\n" ); + return; + } + + + // make sure directories have been made + GET_GAME_DIR( szNrpFilename ); + strcat( szNrpFilename, "/maps" ); + CreateDirectory( szNrpFilename, NULL ); + strcat( szNrpFilename, "/graphs" ); + CreateDirectory( szNrpFilename, NULL ); + + strcat( szNrpFilename, "/" ); + strcat( szNrpFilename, STRING( gpGlobals->mapname ) ); + strcat( szNrpFilename, ".nrp" ); + + file = fopen ( szNrpFilename, "w+" ); + + if ( !file ) + {// file error + ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); + + if ( pTempPool ) + { + free ( pTempPool ); + } + + return; + } + + fprintf( file, "Node Graph Report for map: %s.bsp\n", STRING(gpGlobals->mapname) ); + fprintf ( file, "%d Total Nodes\n\n", WorldGraph.m_cNodes ); + + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + {// print all node numbers and their locations to the file. + WorldGraph.m_pNodes[ i ].m_cNumLinks = 0; + WorldGraph.m_pNodes[ i ].m_iFirstLink = 0; + memset(WorldGraph.m_pNodes[ i ].m_pNextBestNode, 0, sizeof(WorldGraph.m_pNodes[ i ].m_pNextBestNode)); + + fprintf ( file, "Node# %4d\n", i ); + fprintf ( file, "Location %4d,%4d,%4d\n",(int)WorldGraph.m_pNodes[ i ].m_vecOrigin.x, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.y, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.z ); + fprintf ( file, "HintType: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintType ); + fprintf ( file, "HintActivity: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintActivity ); + fprintf ( file, "HintYaw: %4f\n", WorldGraph.m_pNodes[ i ].m_flHintYaw ); + fprintf ( file, "-------------------------------------------------------------------------------\n" ); + } + fprintf ( file, "\n\n" ); + + + // Automatically recognize WATER nodes and drop the LAND nodes to the floor. + // + for ( i = 0; i < WorldGraph.m_cNodes; i++) + { + if (WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_AIR) + { + // do nothing + } + else if (UTIL_PointContents(WorldGraph.m_pNodes[ i ].m_vecOrigin) == CONTENTS_WATER) + { + WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_WATER; + } + else + { + WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_LAND; + + // trace to the ground, then pop up 8 units and place node there to make it + // easier for them to connect (think stairs, chairs, and bumps in the floor). + // After the routing is done, push them back down. + // + TraceResult tr; + + UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, + WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), + ignore_monsters, + g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about + &tr ); + + // This trace is ONLY used if we hit an entity flagged with FL_WORLDBRUSH + TraceResult trEnt; + UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, + WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), + dont_ignore_monsters, + g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about + &trEnt ); + + + // Did we hit something closer than the floor? + if ( trEnt.flFraction < tr.flFraction ) + { + // If it was a world brush entity, copy the node location + if ( trEnt.pHit && (trEnt.pHit->v.flags & FL_WORLDBRUSH) ) + tr.vecEndPos = trEnt.vecEndPos; + } + + WorldGraph.m_pNodes[i].m_vecOriginPeek.z = + WorldGraph.m_pNodes[i].m_vecOrigin.z = tr.vecEndPos.z + NODE_HEIGHT; + } + } + + cPoolLinks = WorldGraph.LinkVisibleNodes( pTempPool, file, &iBadNode ); + + if ( !cPoolLinks ) + { + ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); + + SetThink ( &CTestHull::ShowBadNode );// send the hull off to show the offending node. + //pev->solid = SOLID_NOT; + pev->origin = WorldGraph.m_pNodes[ iBadNode ].m_vecOrigin; + + if ( pTempPool ) + { + free ( pTempPool ); + } + + if ( file ) + {// close the file + fclose ( file ); + } + + return; + } + +// send the walkhull to all of this node's connections now. We'll do this here since +// so much of it relies on being able to control the test hull. + fprintf ( file, "----------------------------------------------------------------------------\n" ); + fprintf ( file, "Walk Rejection:\n"); + + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + { + pSrcNode = &WorldGraph.m_pNodes[ i ]; + + fprintf ( file, "-------------------------------------------------------------------------------\n"); + fprintf ( file, "Node %4d:\n\n", i ); + + for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) + { + // assume that all hulls can walk this link, then eliminate the ones that can't. + pTempPool [ pSrcNode->m_iFirstLink + j ].m_afLinkInfo = bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL | bits_LINK_FLY_HULL; + + + // do a check for each hull size. + + // if we can't fit a tiny hull through a connection, no other hulls with fit either, so we + // should just fall out of the loop. Do so by setting the SkipRemainingHulls flag. + fSkipRemainingHulls = FALSE; + for ( hull = 0 ; hull < MAX_NODE_HULLS; hull++ ) + { + if (fSkipRemainingHulls && (hull == NODE_HUMAN_HULL || hull == NODE_LARGE_HULL)) // skip the remaining walk hulls + continue; + + switch ( hull ) + { + case NODE_SMALL_HULL: + UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); + break; + case NODE_HUMAN_HULL: + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); + break; + case NODE_LARGE_HULL: + UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + break; + case NODE_FLY_HULL: + UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + // UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); + break; + } + + UTIL_SetOrigin ( pev, pSrcNode->m_vecOrigin );// place the hull on the node + + if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) + { + ALERT ( at_aiconsole, "OFFGROUND!\n" ); + } + + // now build a yaw that points to the dest node, and get the distance. + if ( j < 0 ) + { + ALERT ( at_aiconsole, "**** j = %d ****\n", j ); + if ( pTempPool ) + { + free ( pTempPool ); + } + + if ( file ) + {// close the file + fclose ( file ); + } + return; + } + + pDestNode = &WorldGraph.m_pNodes [ pTempPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; + + vecSpot = pDestNode->m_vecOrigin; + //vecSpot.z = pev->origin.z; + + if (hull < NODE_FLY_HULL) + { + int SaveFlags = pev->flags; + int MoveMode = WALKMOVE_WORLDONLY; + if (pSrcNode->m_afNodeInfo & bits_NODE_WATER) + { + pev->flags |= FL_SWIM; + MoveMode = WALKMOVE_NORMAL; + } + + flYaw = UTIL_VecToYaw ( pDestNode->m_vecOrigin - pev->origin ); + + flDist = ( vecSpot - pev->origin ).Length2D(); + + int fWalkFailed = FALSE; + + // in this loop we take tiny steps from the current node to the nodes that it links to, one at a time. + // pev->angles.y = flYaw; + for ( step = 0 ; step < flDist && !fWalkFailed ; step += HULL_STEP_SIZE ) + { + float stepSize = HULL_STEP_SIZE; + + if ( (step + stepSize) >= (flDist-1) ) + stepSize = (flDist - step) - 1; + + if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, MoveMode ) ) + {// can't take the next step + + fWalkFailed = TRUE; + break; + } + } + + if (!fWalkFailed && (pev->origin - vecSpot).Length() > 64) + { + // ALERT( at_console, "bogus walk\n"); + // we thought we + fWalkFailed = TRUE; + } + + if (fWalkFailed) + { + + //pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; + + // now me must eliminate the hull that couldn't walk this connection + switch ( hull ) + { + case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection + fprintf ( file, "NODE_SMALL_HULL step %f\n", step ); + pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL); + fSkipRemainingHulls = TRUE;// don't bother checking larger hulls + break; + case NODE_HUMAN_HULL: + fprintf ( file, "NODE_HUMAN_HULL step %f\n", step ); + pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL); + fSkipRemainingHulls = TRUE;// don't bother checking larger hulls + break; + case NODE_LARGE_HULL: + fprintf ( file, "NODE_LARGE_HULL step %f\n", step ); + pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL; + break; + } + } + pev->flags = SaveFlags; + } + else + { + TraceResult tr; + + UTIL_TraceHull( pSrcNode->m_vecOrigin + Vector( 0, 0, 32 ), pDestNode->m_vecOriginPeek + Vector( 0, 0, 32 ), ignore_monsters, large_hull, ENT( pev ), &tr ); + if (tr.fStartSolid || tr.flFraction < 1.0) + { + pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_FLY_HULL; + } + } + } + + if (pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo == 0) + { + fprintf ( file, "Rejected Node %3d - Unreachable by ", pTempPool [ pSrcNode->m_iFirstLink + j ].m_iDestNode ); + pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; + fprintf ( file, "Any Hull\n" ); + + pSrcNode->m_cNumLinks--; + cPoolLinks--;// we just removed a link, so decrement the total number of links in the pool. + j--; + } + + } + } + fprintf ( file, "-------------------------------------------------------------------------------\n\n\n"); + + cPoolLinks -= WorldGraph.RejectInlineLinks ( pTempPool, file ); + +// now malloc a pool just large enough to hold the links that are actually used + WorldGraph.m_pLinkPool = (CLink *) calloc ( sizeof ( CLink ), cPoolLinks ); + + if ( !WorldGraph.m_pLinkPool ) + {// couldn't make the link pool! + ALERT ( at_aiconsole, "Couldn't malloc LinkPool!\n" ); + if ( pTempPool ) + { + free ( pTempPool ); + } + if ( file ) + {// close the file + fclose ( file ); + } + + return; + } + WorldGraph.m_cLinks = cPoolLinks; + +//copy only the used portions of the TempPool into the graph's link pool + int iFinalPoolIndex = 0; + int iOldFirstLink; + + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + { + iOldFirstLink = WorldGraph.m_pNodes[ i ].m_iFirstLink;// store this, because we have to re-assign it before entering the copy loop + + WorldGraph.m_pNodes[ i ].m_iFirstLink = iFinalPoolIndex; + + for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) + { + WorldGraph.m_pLinkPool[ iFinalPoolIndex++ ] = pTempPool[ iOldFirstLink + j ]; + } + } + + + // Node sorting numbers linked nodes close to each other + // + WorldGraph.SortNodes(); + + // This is used for HashSearch + // + WorldGraph.BuildLinkLookups(); + + fPairsValid = TRUE; // assume that the connection pairs are all valid to start + + fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); + fprintf ( file, "Link Pairings:\n"); + +// link integrity check. The idea here is that if Node A links to Node B, node B should +// link to node A. If not, we have a situation that prevents us from using a basic +// optimization in the FindNearestLink function. + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + { + for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) + { + int iLink; + WorldGraph.HashSearch(WorldGraph.INodeLink(i,j), i, iLink); + if (iLink < 0) + { + fPairsValid = FALSE;// unmatched link pair. + fprintf ( file, "WARNING: Node %3d does not connect back to Node %3d\n", WorldGraph.INodeLink(i, j), i); + } + } + } + + // !!!LATER - if all connections are properly paired, when can enable an optimization in the pathfinding code + // (in the find nearest line function) + if ( fPairsValid ) + { + fprintf ( file, "\nAll Connections are Paired!\n"); + } + + fprintf ( file, "-------------------------------------------------------------------------------\n"); + fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); + fprintf ( file, "Total Number of Connections in Pool: %d\n", cPoolLinks ); + fprintf ( file, "-------------------------------------------------------------------------------\n"); + fprintf ( file, "Connection Pool: %d bytes\n", sizeof ( CLink ) * cPoolLinks ); + fprintf ( file, "-------------------------------------------------------------------------------\n"); + + + ALERT ( at_aiconsole, "%d Nodes, %d Connections\n", WorldGraph.m_cNodes, cPoolLinks ); + + // This is used for FindNearestNode + // + WorldGraph.BuildRegionTables(); + + + // Push all of the LAND nodes down to the ground now. Leave the water and air nodes alone. + // + for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + { + if ((WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_LAND)) + { + WorldGraph.m_pNodes[ i ].m_vecOrigin.z -= NODE_HEIGHT; + } + } + + + if ( pTempPool ) + {// free the temp pool + free ( pTempPool ); + } + + if ( file ) + { + fclose ( file ); + } + + // We now have some graphing capabilities. + // + WorldGraph.m_fGraphPresent = TRUE;//graph is in memory. + WorldGraph.m_fGraphPointersSet = TRUE;// since the graph was generated, the pointers are ready + WorldGraph.m_fRoutingComplete = FALSE; // Optimal routes aren't computed, yet. + + // Compute and compress the routing information. + // + WorldGraph.ComputeStaticRoutingTables(); + +// save the node graph for this level + WorldGraph.FSaveGraph( (char *)STRING( gpGlobals->mapname ) ); + ALERT( at_console, "Done.\n"); +} + + +//========================================================= +// returns a hardcoded path. +//========================================================= +void CTestHull :: PathFind ( void ) +{ + int iPath[ 50 ]; + int iPathSize; + int i; + CNode *pNode, *pNextNode; + + if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available + ALERT ( at_aiconsole, "Graph not ready!\n" ); + return; + } + + iPathSize = WorldGraph.FindShortestPath ( iPath, 0, 19, 0, 0 ); // UNDONE use hull constant + + if ( !iPathSize ) + { + ALERT ( at_aiconsole, "No Path!\n" ); + return; + } + + ALERT ( at_aiconsole, "%d\n", iPathSize ); + + pNode = &WorldGraph.m_pNodes[ iPath [ 0 ] ]; + + for ( i = 0 ; i < iPathSize - 1 ; i++ ) + { + + pNextNode = &WorldGraph.m_pNodes[ iPath [ i + 1 ] ]; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SHOWLINE); + + WRITE_COORD( pNode->m_vecOrigin.x ); + WRITE_COORD( pNode->m_vecOrigin.y ); + WRITE_COORD( pNode->m_vecOrigin.z + NODE_HEIGHT ); + + WRITE_COORD( pNextNode->m_vecOrigin.x); + WRITE_COORD( pNextNode->m_vecOrigin.y); + WRITE_COORD( pNextNode->m_vecOrigin.z + NODE_HEIGHT); + MESSAGE_END(); + + pNode = pNextNode; + } + +} + + +//========================================================= +// CStack Constructor +//========================================================= +CStack :: CStack( void ) +{ + m_level = 0; +} + +//========================================================= +// pushes a value onto the stack +//========================================================= +void CStack :: Push( int value ) +{ + if ( m_level >= MAX_STACK_NODES ) + { + printf("Error!\n"); + return; + } + m_stack[m_level] = value; + m_level++; +} + +//========================================================= +// pops a value off of the stack +//========================================================= +int CStack :: Pop( void ) +{ + if ( m_level <= 0 ) + return -1; + + m_level--; + return m_stack[ m_level ]; +} + +//========================================================= +// returns the value on the top of the stack +//========================================================= +int CStack :: Top ( void ) +{ + return m_stack[ m_level - 1 ]; +} + +//========================================================= +// copies every element on the stack into an array LIFO +//========================================================= +void CStack :: CopyToArray ( int *piArray ) +{ + int i; + + for ( i = 0 ; i < m_level ; i++ ) + { + piArray[ i ] = m_stack[ i ]; + } +} + +//========================================================= +// CQueue constructor +//========================================================= +CQueue :: CQueue( void ) +{ + m_cSize = 0; + m_head = 0; + m_tail = -1; +} + +//========================================================= +// inserts a value into the queue +//========================================================= +void CQueue :: Insert ( int iValue, float fPriority ) +{ + + if ( Full() ) + { + printf ( "Queue is full!\n" ); + return; + } + + m_tail++; + + if ( m_tail == MAX_STACK_NODES ) + {//wrap around + m_tail = 0; + } + + m_queue[ m_tail ].Id = iValue; + m_queue[ m_tail ].Priority = fPriority; + m_cSize++; +} + +//========================================================= +// removes a value from the queue (FIFO) +//========================================================= +int CQueue :: Remove ( float &fPriority ) +{ + if ( m_head == MAX_STACK_NODES ) + {// wrap + m_head = 0; + } + + m_cSize--; + fPriority = m_queue[ m_head ].Priority; + return m_queue[ m_head++ ].Id; +} + +//========================================================= +// CQueue constructor +//========================================================= +CQueuePriority :: CQueuePriority( void ) +{ + m_cSize = 0; +} + +//========================================================= +// inserts a value into the priority queue +//========================================================= +void CQueuePriority :: Insert( int iValue, float fPriority ) +{ + + if ( Full() ) + { + printf ( "Queue is full!\n" ); + return; + } + + m_heap[ m_cSize ].Priority = fPriority; + m_heap[ m_cSize ].Id = iValue; + m_cSize++; + Heap_SiftUp(); +} + +//========================================================= +// removes the smallest item from the priority queue +// +//========================================================= +int CQueuePriority :: Remove( float &fPriority ) +{ + int iReturn = m_heap[ 0 ].Id; + fPriority = m_heap[ 0 ].Priority; + + m_cSize--; + + m_heap[ 0 ] = m_heap[ m_cSize ]; + + Heap_SiftDown(0); + return iReturn; +} + +#define HEAP_LEFT_CHILD(x) (2*(x)+1) +#define HEAP_RIGHT_CHILD(x) (2*(x)+2) +#define HEAP_PARENT(x) (((x)-1)/2) + +void CQueuePriority::Heap_SiftDown(int iSubRoot) +{ + int parent = iSubRoot; + int child = HEAP_LEFT_CHILD(parent); + + struct tag_HEAP_NODE Ref = m_heap[ parent ]; + + while (child < m_cSize) + { + int rightchild = HEAP_RIGHT_CHILD(parent); + if (rightchild < m_cSize) + { + if ( m_heap[ rightchild ].Priority < m_heap[ child ].Priority ) + { + child = rightchild; + } + } + if ( Ref.Priority <= m_heap[ child ].Priority ) + break; + + m_heap[ parent ] = m_heap[ child ]; + parent = child; + child = HEAP_LEFT_CHILD(parent); + } + m_heap[ parent ] = Ref; +} + +void CQueuePriority::Heap_SiftUp(void) +{ + int child = m_cSize-1; + while (child) + { + int parent = HEAP_PARENT(child); + if ( m_heap[ parent ].Priority <= m_heap[ child ].Priority ) + break; + + struct tag_HEAP_NODE Tmp; + Tmp = m_heap[ child ]; + m_heap[ child ] = m_heap[ parent ]; + m_heap[ parent ] = Tmp; + + child = parent; + } +} + +//========================================================= +// CGraph - FLoadGraph - attempts to load a node graph from disk. +// if the current level is maps/snar.bsp, maps/graphs/snar.nod +// will be loaded. If file cannot be loaded, the node tree +// will be created and saved to disk. +//========================================================= +int CGraph :: FLoadGraph ( char *szMapName ) +{ + char szFilename[MAX_PATH]; + int iVersion; + int length; + byte *aMemFile; + byte *pMemFile; + + // make sure the directories have been made + char szDirName[MAX_PATH]; + GET_GAME_DIR( szDirName ); + strcat( szDirName, "/maps" ); + CreateDirectory( szDirName, NULL ); + strcat( szDirName, "/graphs" ); + CreateDirectory( szDirName, NULL ); + + strcpy ( szFilename, "maps/graphs/" ); + strcat ( szFilename, szMapName ); + strcat( szFilename, ".nod" ); + + pMemFile = aMemFile = LOAD_FILE_FOR_ME(szFilename, &length); + + if ( !aMemFile ) + { + return FALSE; + } + else + { + // Read the graph version number + // + length -= sizeof(int); + if (length < 0) goto ShortFile; + memcpy(&iVersion, pMemFile, sizeof(int)); + pMemFile += sizeof(int); + + if ( iVersion != GRAPH_VERSION ) + { + // This file was written by a different build of the dll! + // + ALERT ( at_aiconsole, "**ERROR** Graph version is %d, expected %d\n",iVersion, GRAPH_VERSION ); + goto ShortFile; + } + + // Read the graph class + // + length -= sizeof(CGraph); + if (length < 0) goto ShortFile; + memcpy(this, pMemFile, sizeof(CGraph)); + pMemFile += sizeof(CGraph); + + // Set the pointers to zero, just in case we run out of memory. + // + m_pNodes = NULL; + m_pLinkPool = NULL; + m_di = NULL; + m_pRouteInfo = NULL; + m_pHashLinks = NULL; + + + // Malloc for the nodes + // + m_pNodes = ( CNode * )calloc ( sizeof ( CNode ), m_cNodes ); + + if ( !m_pNodes ) + { + ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", m_cNodes ); + goto NoMemory; + } + + // Read in all the nodes + // + length -= sizeof(CNode) * m_cNodes; + if (length < 0) goto ShortFile; + memcpy(m_pNodes, pMemFile, sizeof(CNode)*m_cNodes); + pMemFile += sizeof(CNode) * m_cNodes; + + + // Malloc for the link pool + // + m_pLinkPool = ( CLink * )calloc ( sizeof ( CLink ), m_cLinks ); + + if ( !m_pLinkPool ) + { + ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d link!\n", m_cLinks ); + goto NoMemory; + } + + // Read in all the links + // + length -= sizeof(CLink)*m_cLinks; + if (length < 0) goto ShortFile; + memcpy(m_pLinkPool, pMemFile, sizeof(CLink)*m_cLinks); + pMemFile += sizeof(CLink)*m_cLinks; + + // Malloc for the sorting info. + // + m_di = (DIST_INFO *)calloc( sizeof(DIST_INFO), m_cNodes ); + if ( !m_di ) + { + ALERT ( at_aiconsole, "***ERROR**\nCouldn't malloc %d entries sorting nodes!\n", m_cNodes ); + goto NoMemory; + } + + // Read it in. + // + length -= sizeof(DIST_INFO)*m_cNodes; + if (length < 0) goto ShortFile; + memcpy(m_di, pMemFile, sizeof(DIST_INFO)*m_cNodes); + pMemFile += sizeof(DIST_INFO)*m_cNodes; + + // Malloc for the routing info. + // + m_fRoutingComplete = FALSE; + m_pRouteInfo = (char *)calloc( sizeof(char), m_nRouteInfo ); + if ( !m_pRouteInfo ) + { + ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d route bytes!\n", m_nRouteInfo ); + goto NoMemory; + } + m_CheckedCounter = 0; + for (int i = 0; i < m_cNodes; i++) + { + m_di[i].m_CheckedEvent = 0; + } + + // Read in the route information. + // + length -= sizeof(char)*m_nRouteInfo; + if (length < 0) goto ShortFile; + memcpy(m_pRouteInfo, pMemFile, sizeof(char)*m_nRouteInfo); + pMemFile += sizeof(char)*m_nRouteInfo; + m_fRoutingComplete = TRUE;; + + // malloc for the hash links + // + m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); + if (!m_pHashLinks) + { + ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d hash link bytes!\n", m_nHashLinks ); + goto NoMemory; + } + + // Read in the hash link information + // + length -= sizeof(short)*m_nHashLinks; + if (length < 0) goto ShortFile; + memcpy(m_pHashLinks, pMemFile, sizeof(short)*m_nHashLinks); + pMemFile += sizeof(short)*m_nHashLinks; + + // Set the graph present flag, clear the pointers set flag + // + m_fGraphPresent = TRUE; + m_fGraphPointersSet = FALSE; + + FREE_FILE(aMemFile); + + if (length != 0) + { + ALERT ( at_aiconsole, "***WARNING***:Node graph was longer than expected by %d bytes.!\n", length); + } + + return TRUE; + } + +ShortFile: +NoMemory: + FREE_FILE(aMemFile); + return FALSE; +} + +//========================================================= +// CGraph - FSaveGraph - It's not rocket science. +// this WILL overwrite existing files. +//========================================================= +int CGraph :: FSaveGraph ( char *szMapName ) +{ + + int iVersion = GRAPH_VERSION; + char szFilename[MAX_PATH]; + FILE *file; + + if ( !m_fGraphPresent || !m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available or built + ALERT ( at_aiconsole, "Graph not ready!\n" ); + return FALSE; + } + + // make sure directories have been made + GET_GAME_DIR( szFilename ); + strcat( szFilename, "/maps" ); + CreateDirectory( szFilename, NULL ); + strcat( szFilename, "/graphs" ); + CreateDirectory( szFilename, NULL ); + + strcat( szFilename, "/" ); + strcat( szFilename, szMapName ); + strcat( szFilename, ".nod" ); + + file = fopen ( szFilename, "wb" ); + + ALERT ( at_aiconsole, "Created: %s\n", szFilename ); + + if ( !file ) + {// couldn't create + ALERT ( at_aiconsole, "Couldn't Create: %s\n", szFilename ); + return FALSE; + } + else + { + // write the version + fwrite ( &iVersion, sizeof ( int ), 1, file ); + + // write the CGraph class + fwrite ( this, sizeof ( CGraph ), 1, file ); + + // write the nodes + fwrite ( m_pNodes, sizeof ( CNode ), m_cNodes, file ); + + // write the links + fwrite ( m_pLinkPool, sizeof ( CLink ), m_cLinks, file ); + + fwrite ( m_di, sizeof(DIST_INFO), m_cNodes, file ); + + // Write the route info. + // + if ( m_pRouteInfo && m_nRouteInfo ) + { + fwrite ( m_pRouteInfo, sizeof( char ), m_nRouteInfo, file ); + } + + if (m_pHashLinks && m_nHashLinks) + { + fwrite(m_pHashLinks, sizeof(short), m_nHashLinks, file); + } + fclose ( file ); + return TRUE; + } +} + +//========================================================= +// CGraph - FSetGraphPointers - Takes the modelnames of +// all of the brush ents that block connections in the node +// graph and resolves them into pointers to those entities. +// this is done after loading the graph from disk, whereupon +// the pointers are not valid. +//========================================================= +int CGraph :: FSetGraphPointers ( void ) +{ + int i; + edict_t *pentLinkEnt; + + for ( i = 0 ; i < m_cLinks ; i++ ) + {// go through all of the links + + if ( m_pLinkPool[ i ].m_pLinkEnt != NULL ) + { + char name[5]; + // when graphs are saved, any valid pointers are will be non-zero, signifying that we should + // reset those pointers upon reloading. Any pointers that were NULL when the graph was saved + // will be NULL when reloaded, and will ignored by this function. + + // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) + memcpy( name, m_pLinkPool[ i ].m_szLinkEntModelname, 4 ); + name[4] = 0; + pentLinkEnt = FIND_ENTITY_BY_STRING( NULL, "model", name ); + + if ( FNullEnt ( pentLinkEnt ) ) + { + // the ent isn't around anymore? Either there is a major problem, or it was removed from the world + // ( like a func_breakable that's been destroyed or something ). Make sure that LinkEnt is null. + ALERT ( at_aiconsole, "**Could not find model %s\n", name ); + m_pLinkPool[ i ].m_pLinkEnt = NULL; + } + else + { + m_pLinkPool[ i ].m_pLinkEnt = VARS( pentLinkEnt ); + + if ( !FBitSet( m_pLinkPool[ i ].m_pLinkEnt->flags, FL_GRAPHED ) ) + { + m_pLinkPool[ i ].m_pLinkEnt->flags += FL_GRAPHED; + } + } + } + } + + // the pointers are now set. + m_fGraphPointersSet = TRUE; + return TRUE; +} + +//========================================================= +// CGraph - CheckNODFile - this function checks the date of +// the BSP file that was just loaded and the date of the a +// ssociated .NOD file. If the NOD file is not present, or +// is older than the BSP file, we rebuild it. +// +// returns FALSE if the .NOD file doesn't qualify and needs +// to be rebuilt. +// +// !!!BUGBUG - the file times we get back are 20 hours ahead! +// since this happens consistantly, we can still correctly +// determine which of the 2 files is newer. This needs fixed, +// though. ( I now suspect that we are getting GMT back from +// these functions and must compensate for local time ) (sjb) +//========================================================= +int CGraph :: CheckNODFile ( char *szMapName ) +{ + int retValue; + + char szBspFilename[MAX_PATH]; + char szGraphFilename[MAX_PATH]; + + + strcpy ( szBspFilename, "maps/" ); + strcat ( szBspFilename, szMapName ); + strcat ( szBspFilename, ".bsp" ); + + strcpy ( szGraphFilename, "maps/graphs/" ); + strcat ( szGraphFilename, szMapName ); + strcat ( szGraphFilename, ".nod" ); + + retValue = TRUE; + + int iCompare; + if (COMPARE_FILE_TIME(szBspFilename, szGraphFilename, &iCompare)) + { + if ( iCompare > 0 ) + {// BSP file is newer. + ALERT ( at_aiconsole, ".NOD File will be updated\n\n" ); + retValue = FALSE; + } + } + else + { + retValue = FALSE; + } + + return retValue; +} + +#define ENTRY_STATE_EMPTY -1 + +struct tagNodePair +{ + short iSrc; + short iDest; +}; + +void CGraph::HashInsert(int iSrcNode, int iDestNode, int iKey) +{ + struct tagNodePair np; + + np.iSrc = iSrcNode; + np.iDest = iDestNode; + CRC32_t dwHash; + CRC32_INIT(&dwHash); + CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); + dwHash = CRC32_FINAL(dwHash); + + int di = m_HashPrimes[dwHash&15]; + int i = (dwHash >> 4) % m_nHashLinks; + while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) + { + i += di; + if (i >= m_nHashLinks) i -= m_nHashLinks; + } + m_pHashLinks[i] = iKey; +} + +void CGraph::HashSearch(int iSrcNode, int iDestNode, int &iKey) +{ + struct tagNodePair np; + + np.iSrc = iSrcNode; + np.iDest = iDestNode; + CRC32_t dwHash; + CRC32_INIT(&dwHash); + CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); + dwHash = CRC32_FINAL(dwHash); + + int di = m_HashPrimes[dwHash&15]; + int i = (dwHash >> 4) % m_nHashLinks; + while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) + { + CLink &link = Link(m_pHashLinks[i]); + if (iSrcNode == link.m_iSrcNode && iDestNode == link.m_iDestNode) + { + break; + } + else + { + i += di; + if (i >= m_nHashLinks) i -= m_nHashLinks; + } + } + iKey = m_pHashLinks[i]; +} + +#define NUMBER_OF_PRIMES 177 + +int Primes[NUMBER_OF_PRIMES] = +{ 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, +71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, +157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, +241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, +347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, +439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, +547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, +643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, +751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, +859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, +977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 0 }; + +void CGraph::HashChoosePrimes(int TableSize) +{ + int LargestPrime = TableSize/2; + if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) + { + LargestPrime = Primes[NUMBER_OF_PRIMES-2]; + } + int Spacing = LargestPrime/16; + + // Pick a set primes that are evenly spaced from (0 to LargestPrime) + // We divide this interval into 16 equal sized zones. We want to find + // one prime number that best represents that zone. + // + for (int iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing) + { + // Search for a prime number that is less than the target zone + // number given by iZone. + // + int Lower = Primes[0]; + for (int jPrime = 0; Primes[jPrime] != 0; jPrime++) + { + if (jPrime != 0 && TableSize % Primes[jPrime] == 0) continue; + int Upper = Primes[jPrime]; + if (Lower <= iZone && iZone <= Upper) + { + // Choose the closest lower prime number. + // + if (iZone - Lower <= Upper - iZone) + { + m_HashPrimes[iPrime++] = Lower; + } + else + { + m_HashPrimes[iPrime++] = Upper; + } + break; + } + Lower = Upper; + } + } + + // Alternate negative and positive numbers + // + for (iPrime = 0; iPrime < 16; iPrime += 2) + { + m_HashPrimes[iPrime] = TableSize-m_HashPrimes[iPrime]; + } + + // Shuffle the set of primes to reduce correlation with bits in + // hash key. + // + for (iPrime = 0; iPrime < 16-1; iPrime++) + { + int Pick = RANDOM_LONG(0, 15-iPrime); + int Temp = m_HashPrimes[Pick]; + m_HashPrimes[Pick] = m_HashPrimes[15-iPrime]; + m_HashPrimes[15-iPrime] = Temp; + } +} + +// Renumber nodes so that nodes that link together are together. +// +#define UNNUMBERED_NODE -1 +void CGraph::SortNodes(void) +{ + // We are using m_iPreviousNode to be the new node number. + // After assigning new node numbers to everything, we move + // things and patchup the links. + // + int iNodeCnt = 0; + m_pNodes[0].m_iPreviousNode = iNodeCnt++; + for (int i = 1; i < m_cNodes; i++) + { + m_pNodes[i].m_iPreviousNode = UNNUMBERED_NODE; + } + + for (i = 0; i < m_cNodes; i++) + { + // Run through all of this node's neighbors + // + for (int j = 0 ; j < m_pNodes[i].m_cNumLinks; j++ ) + { + int iDestNode = INodeLink(i, j); + if (m_pNodes[iDestNode].m_iPreviousNode == UNNUMBERED_NODE) + { + m_pNodes[iDestNode].m_iPreviousNode = iNodeCnt++; + } + } + } + + // Assign remaining node numbers to unlinked nodes. + // + for (i = 0; i < m_cNodes; i++) + { + if (m_pNodes[i].m_iPreviousNode == UNNUMBERED_NODE) + { + m_pNodes[i].m_iPreviousNode = iNodeCnt++; + } + } + + // Alter links to reflect new node numbers. + // + for (i = 0; i < m_cLinks; i++) + { + m_pLinkPool[i].m_iSrcNode = m_pNodes[m_pLinkPool[i].m_iSrcNode].m_iPreviousNode; + m_pLinkPool[i].m_iDestNode = m_pNodes[m_pLinkPool[i].m_iDestNode].m_iPreviousNode; + } + + // Rearrange nodes to reflect new node numbering. + // + for (i = 0; i < m_cNodes; i++) + { + while (m_pNodes[i].m_iPreviousNode != i) + { + // Move current node off to where it should be, and bring + // that other node back into the current slot. + // + int iDestNode = m_pNodes[i].m_iPreviousNode; + CNode TempNode = m_pNodes[iDestNode]; + m_pNodes[iDestNode] = m_pNodes[i]; + m_pNodes[i] = TempNode; + } + } +} + +void CGraph::BuildLinkLookups(void) +{ + m_nHashLinks = 3*m_cLinks/2 + 3; + + HashChoosePrimes(m_nHashLinks); + m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); + if (!m_pHashLinks) + { + ALERT(at_aiconsole, "Couldn't allocated Link Lookup Table.\n"); + return; + } + for (int i = 0; i < m_nHashLinks; i++) + { + m_pHashLinks[i] = ENTRY_STATE_EMPTY; + } + + for (i = 0; i < m_cLinks; i++) + { + CLink &link = Link(i); + HashInsert(link.m_iSrcNode, link.m_iDestNode, i); + } +#if 0 + for (i = 0; i < m_cLinks; i++) + { + CLink &link = Link(i); + int iKey; + HashSearch(link.m_iSrcNode, link.m_iDestNode, iKey); + if (iKey != i) + { + ALERT(at_aiconsole, "HashLinks don't match (%d versus %d)\n", i, iKey); + } + } +#endif +} + +void CGraph::BuildRegionTables(void) +{ + if (m_di) free(m_di); + + // Go ahead and setup for range searching the nodes for FindNearestNodes + // + m_di = (DIST_INFO *)calloc(sizeof(DIST_INFO), m_cNodes); + if (!m_di) + { + ALERT(at_aiconsole, "Couldn't allocated node ordering array.\n"); + return; + } + + // Calculate regions for all the nodes. + // + // + for (int i = 0; i < 3; i++) + { + m_RegionMin[i] = 999999999.0; // just a big number out there; + m_RegionMax[i] = -999999999.0; // just a big number out there; + } + for (i = 0; i < m_cNodes; i++) + { + if (m_pNodes[i].m_vecOrigin.x < m_RegionMin[0]) + m_RegionMin[0] = m_pNodes[i].m_vecOrigin.x; + if (m_pNodes[i].m_vecOrigin.y < m_RegionMin[1]) + m_RegionMin[1] = m_pNodes[i].m_vecOrigin.y; + if (m_pNodes[i].m_vecOrigin.z < m_RegionMin[2]) + m_RegionMin[2] = m_pNodes[i].m_vecOrigin.z; + + if (m_pNodes[i].m_vecOrigin.x > m_RegionMax[0]) + m_RegionMax[0] = m_pNodes[i].m_vecOrigin.x; + if (m_pNodes[i].m_vecOrigin.y > m_RegionMax[1]) + m_RegionMax[1] = m_pNodes[i].m_vecOrigin.y; + if (m_pNodes[i].m_vecOrigin.z > m_RegionMax[2]) + m_RegionMax[2] = m_pNodes[i].m_vecOrigin.z; + } + for (i = 0; i < m_cNodes; i++) + { + m_pNodes[i].m_Region[0] = CALC_RANGE(m_pNodes[i].m_vecOrigin.x, m_RegionMin[0], m_RegionMax[0]); + m_pNodes[i].m_Region[1] = CALC_RANGE(m_pNodes[i].m_vecOrigin.y, m_RegionMin[1], m_RegionMax[1]); + m_pNodes[i].m_Region[2] = CALC_RANGE(m_pNodes[i].m_vecOrigin.z, m_RegionMin[2], m_RegionMax[2]); + } + + for (i = 0; i < 3; i++) + { + for (int j = 0; j < NUM_RANGES; j++) + { + m_RangeStart[i][j] = 255; + m_RangeEnd[i][j] = 0; + } + for (j = 0; j < m_cNodes; j++) + { + m_di[j].m_SortedBy[i] = j; + } + + for (j = 0; j < m_cNodes - 1; j++) + { + int jNode = m_di[j].m_SortedBy[i]; + int jCodeX = m_pNodes[jNode].m_Region[0]; + int jCodeY = m_pNodes[jNode].m_Region[1]; + int jCodeZ = m_pNodes[jNode].m_Region[2]; + int jCode; + switch (i) + { + case 0: + jCode = (jCodeX << 16) + (jCodeY << 8) + jCodeZ; + break; + case 1: + jCode = (jCodeY << 16) + (jCodeZ << 8) + jCodeX; + break; + case 2: + jCode = (jCodeZ << 16) + (jCodeX << 8) + jCodeY; + break; + } + + for (int k = j+1; k < m_cNodes; k++) + { + int kNode = m_di[k].m_SortedBy[i]; + int kCodeX = m_pNodes[kNode].m_Region[0]; + int kCodeY = m_pNodes[kNode].m_Region[1]; + int kCodeZ = m_pNodes[kNode].m_Region[2]; + int kCode; + switch (i) + { + case 0: + kCode = (kCodeX << 16) + (kCodeY << 8) + kCodeZ; + break; + case 1: + kCode = (kCodeY << 16) + (kCodeZ << 8) + kCodeX; + break; + case 2: + kCode = (kCodeZ << 16) + (kCodeX << 8) + kCodeY; + break; + } + + if (kCode < jCode) + { + // Swap j and k entries. + // + int Tmp = m_di[j].m_SortedBy[i]; + m_di[j].m_SortedBy[i] = m_di[k].m_SortedBy[i]; + m_di[k].m_SortedBy[i] = Tmp; + } + } + } + } + + // Generate lookup tables. + // + for (i = 0; i < m_cNodes; i++) + { + int CodeX = m_pNodes[m_di[i].m_SortedBy[0]].m_Region[0]; + int CodeY = m_pNodes[m_di[i].m_SortedBy[1]].m_Region[1]; + int CodeZ = m_pNodes[m_di[i].m_SortedBy[2]].m_Region[2]; + + if (i < m_RangeStart[0][CodeX]) + { + m_RangeStart[0][CodeX] = i; + } + if (i < m_RangeStart[1][CodeY]) + { + m_RangeStart[1][CodeY] = i; + } + if (i < m_RangeStart[2][CodeZ]) + { + m_RangeStart[2][CodeZ] = i; + } + if (m_RangeEnd[0][CodeX] < i) + { + m_RangeEnd[0][CodeX] = i; + } + if (m_RangeEnd[1][CodeY] < i) + { + m_RangeEnd[1][CodeY] = i; + } + if (m_RangeEnd[2][CodeZ] < i) + { + m_RangeEnd[2][CodeZ] = i; + } + } + + // Initialize the cache. + // + memset(m_Cache, 0, sizeof(m_Cache)); +} + +void CGraph :: ComputeStaticRoutingTables( void ) +{ + int nRoutes = m_cNodes*m_cNodes; +#define FROM_TO(x,y) ((x)*m_cNodes+(y)) + short *Routes = new short[nRoutes]; + + int *pMyPath = new int[m_cNodes]; + unsigned short *BestNextNodes = new unsigned short[m_cNodes]; + char *pRoute = new char[m_cNodes*2]; + + + if (Routes && pMyPath && BestNextNodes && pRoute) + { + int nTotalCompressedSize = 0; + for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) + { + for (int iCap = 0; iCap < 2; iCap++) + { + int iCapMask; + switch (iCap) + { + case 0: + iCapMask = 0; + break; + + case 1: + iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; + break; + } + + + // Initialize Routing table to uncalculated. + // + for (int iFrom = 0; iFrom < m_cNodes; iFrom++) + { + for (int iTo = 0; iTo < m_cNodes; iTo++) + { + Routes[FROM_TO(iFrom, iTo)] = -1; + } + } + + for (iFrom = 0; iFrom < m_cNodes; iFrom++) + { + for (int iTo = m_cNodes-1; iTo >= 0; iTo--) + { + if (Routes[FROM_TO(iFrom, iTo)] != -1) continue; + + int cPathSize = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); + + // Use the computed path to update the routing table. + // + if (cPathSize > 1) + { + for (int iNode = 0; iNode < cPathSize-1; iNode++) + { + int iStart = pMyPath[iNode]; + int iNext = pMyPath[iNode+1]; + for (int iNode1 = iNode+1; iNode1 < cPathSize; iNode1++) + { + int iEnd = pMyPath[iNode1]; + Routes[FROM_TO(iStart, iEnd)] = iNext; + } + } +#if 0 + // Well, at first glance, this should work, but actually it's safer + // to be told explictly that you can take a series of node in a + // particular direction. Some links don't appear to have links in + // the opposite direction. + // + for (iNode = cPathSize-1; iNode >= 1; iNode--) + { + int iStart = pMyPath[iNode]; + int iNext = pMyPath[iNode-1]; + for (int iNode1 = iNode-1; iNode1 >= 0; iNode1--) + { + int iEnd = pMyPath[iNode1]; + Routes[FROM_TO(iStart, iEnd)] = iNext; + } + } +#endif + } + else + { + Routes[FROM_TO(iFrom, iTo)] = iFrom; + Routes[FROM_TO(iTo, iFrom)] = iTo; + } + } + } + + for (iFrom = 0; iFrom < m_cNodes; iFrom++) + { + for (int iTo = 0; iTo < m_cNodes; iTo++) + { + BestNextNodes[iTo] = Routes[FROM_TO(iFrom, iTo)]; + } + + // Compress this node's routing table. + // + int iLastNode = 9999999; // just really big. + int cSequence = 0; + int cRepeats = 0; + int CompressedSize = 0; + char *p = pRoute; + for (int i = 0; i < m_cNodes; i++) + { + BOOL CanRepeat = ((BestNextNodes[i] == iLastNode) && cRepeats < 127); + BOOL CanSequence = (BestNextNodes[i] == i && cSequence < 128); + + if (cRepeats) + { + if (CanRepeat) + { + cRepeats++; + } + else + { + // Emit the repeat phrase. + // + CompressedSize += 2; // (count-1, iLastNode-i) + *p++ = cRepeats - 1; + int a = iLastNode - iFrom; + int b = iLastNode - iFrom + m_cNodes; + int c = iLastNode - iFrom - m_cNodes; + if (-128 <= a && a <= 127) + { + *p++ = a; + } + else if (-128 <= b && b <= 127) + { + *p++ = b; + } + else if (-128 <= c && c <= 127) + { + *p++ = c; + } + else + { + ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); + } + cRepeats = 0; + + if (CanSequence) + { + // Start a sequence. + // + cSequence++; + } + else + { + // Start another repeat. + // + cRepeats++; + } + } + } + else if (cSequence) + { + if (CanSequence) + { + cSequence++; + } + else + { + // It may be advantageous to combine + // a single-entry sequence phrase with the + // next repeat phrase. + // + if (cSequence == 1 && CanRepeat) + { + // Combine with repeat phrase. + // + cRepeats = 2; + cSequence = 0; + } + else + { + // Emit the sequence phrase. + // + CompressedSize += 1; // (-count) + *p++ = -cSequence; + cSequence = 0; + + // Start a repeat sequence. + // + cRepeats++; + } + } + } + else + { + if (CanSequence) + { + // Start a sequence phrase. + // + cSequence++; + } + else + { + // Start a repeat sequence. + // + cRepeats++; + } + } + iLastNode = BestNextNodes[i]; + } + if (cRepeats) + { + // Emit the repeat phrase. + // + CompressedSize += 2; + *p++ = cRepeats - 1; +#if 0 + iLastNode = iFrom + *pRoute; + if (iLastNode >= m_cNodes) iLastNode -= m_cNodes; + else if (iLastNode < 0) iLastNode += m_cNodes; +#endif + int a = iLastNode - iFrom; + int b = iLastNode - iFrom + m_cNodes; + int c = iLastNode - iFrom - m_cNodes; + if (-128 <= a && a <= 127) + { + *p++ = a; + } + else if (-128 <= b && b <= 127) + { + *p++ = b; + } + else if (-128 <= c && c <= 127) + { + *p++ = c; + } + else + { + ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); + } + } + if (cSequence) + { + // Emit the Sequence phrase. + // + CompressedSize += 1; + *p++ = -cSequence; + } + + // Go find a place to store this thing and point to it. + // + int nRoute = p - pRoute; + if (m_pRouteInfo) + { + for (int i = 0; i < m_nRouteInfo - nRoute; i++) + { + if (memcmp(m_pRouteInfo + i, pRoute, nRoute) == 0) + { + break; + } + } + if (i < m_nRouteInfo - nRoute) + { + m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = i; + } + else + { + char *Tmp = (char *)calloc(sizeof(char), (m_nRouteInfo + nRoute)); + memcpy(Tmp, m_pRouteInfo, m_nRouteInfo); + free(m_pRouteInfo); + m_pRouteInfo = Tmp; + memcpy(m_pRouteInfo + m_nRouteInfo, pRoute, nRoute); + m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = m_nRouteInfo; + m_nRouteInfo += nRoute; + nTotalCompressedSize += CompressedSize; + } + } + else + { + m_nRouteInfo = nRoute; + m_pRouteInfo = (char *)calloc(sizeof(char), nRoute); + memcpy(m_pRouteInfo, pRoute, nRoute); + m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = 0; + nTotalCompressedSize += CompressedSize; + } + } + } + } + ALERT( at_aiconsole, "Size of Routes = %d\n", nTotalCompressedSize); + } + if (Routes) delete Routes; + if (BestNextNodes) delete BestNextNodes; + if (pRoute) delete pRoute; + if (pMyPath) delete pMyPath; + Routes = 0; + BestNextNodes = 0; + pRoute = 0; + pMyPath = 0; + +#if 0 + TestRoutingTables(); +#endif + m_fRoutingComplete = TRUE; +} + +// Test those routing tables. Doesn't really work, yet. +// +void CGraph :: TestRoutingTables( void ) +{ + int *pMyPath = new int[m_cNodes]; + int *pMyPath2 = new int[m_cNodes]; + if (pMyPath && pMyPath2) + { + for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) + { + for (int iCap = 0; iCap < 2; iCap++) + { + int iCapMask; + switch (iCap) + { + case 0: + iCapMask = 0; + break; + + case 1: + iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; + break; + } + + for (int iFrom = 0; iFrom < m_cNodes; iFrom++) + { + for (int iTo = 0; iTo < m_cNodes; iTo++) + { + m_fRoutingComplete = FALSE; + int cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); + m_fRoutingComplete = TRUE; + int cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); + + // Unless we can look at the entire path, we can verify that it's correct. + // + if (cPathSize2 == MAX_PATH_SIZE) continue; + + // Compare distances. + // +#if 1 + float flDistance1 = 0.0; + for (int i = 0; i < cPathSize1-1; i++) + { + // Find the link from pMyPath[i] to pMyPath[i+1] + // + if (pMyPath[i] == pMyPath[i+1]) continue; + int iVisitNode; + BOOL bFound = FALSE; + for (int iLink = 0; iLink < m_pNodes[pMyPath[i]].m_cNumLinks; iLink++) + { + iVisitNode = INodeLink ( pMyPath[i], iLink ); + if (iVisitNode == pMyPath[i+1]) + { + flDistance1 += m_pLinkPool[ m_pNodes[ pMyPath[i] ].m_iFirstLink + iLink].m_flWeight; + bFound = TRUE; + break; + } + } + if (!bFound) + { + ALERT(at_aiconsole, "No link.\n"); + } + } + + float flDistance2 = 0.0; + for (i = 0; i < cPathSize2-1; i++) + { + // Find the link from pMyPath2[i] to pMyPath2[i+1] + // + if (pMyPath2[i] == pMyPath2[i+1]) continue; + int iVisitNode; + BOOL bFound = FALSE; + for (int iLink = 0; iLink < m_pNodes[pMyPath2[i]].m_cNumLinks; iLink++) + { + iVisitNode = INodeLink ( pMyPath2[i], iLink ); + if (iVisitNode == pMyPath2[i+1]) + { + flDistance2 += m_pLinkPool[ m_pNodes[ pMyPath2[i] ].m_iFirstLink + iLink].m_flWeight; + bFound = TRUE; + break; + } + } + if (!bFound) + { + ALERT(at_aiconsole, "No link.\n"); + } + } + if (fabs(flDistance1 - flDistance2) > 0.10) + { +#else + if (cPathSize1 != cPathSize2 || memcmp(pMyPath, pMyPath2, sizeof(int)*cPathSize1) != 0) + { +#endif + ALERT(at_aiconsole, "Routing is inconsistent!!!\n"); + ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap); + for (int i = 0; i < cPathSize1; i++) + { + ALERT(at_aiconsole, "%d ", pMyPath[i]); + } + ALERT(at_aiconsole, "\n(%d to %d |%d/%d)2:", iFrom, iTo, iHull, iCap); + for (i = 0; i < cPathSize2; i++) + { + ALERT(at_aiconsole, "%d ", pMyPath2[i]); + } + ALERT(at_aiconsole, "\n"); + m_fRoutingComplete = FALSE; + cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); + m_fRoutingComplete = TRUE; + cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); + goto EnoughSaid; + } + } + } + } + } + } + +EnoughSaid: + + if (pMyPath) delete pMyPath; + if (pMyPath2) delete pMyPath2; + pMyPath = 0; + pMyPath2 = 0; +} + + + + + + + + + +//========================================================= +// CNodeViewer - Draws a graph of the shorted path from all nodes +// to current location (typically the player). It then draws +// as many connects as it can per frame, trying not to overflow the buffer +//========================================================= +class CNodeViewer : public CBaseEntity +{ +public: + void Spawn( void ); + + int m_iBaseNode; + int m_iDraw; + int m_nVisited; + int m_aFrom[128]; + int m_aTo[128]; + int m_iHull; + int m_afNodeType; + Vector m_vecColor; + + void FindNodeConnections( int iNode ); + void AddNode( int iFrom, int iTo ); + void EXPORT DrawThink( void ); + +}; +LINK_ENTITY_TO_CLASS( node_viewer, CNodeViewer ); +LINK_ENTITY_TO_CLASS( node_viewer_human, CNodeViewer ); +LINK_ENTITY_TO_CLASS( node_viewer_fly, CNodeViewer ); +LINK_ENTITY_TO_CLASS( node_viewer_large, CNodeViewer ); + +void CNodeViewer::Spawn( ) +{ + if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) + {// protect us in the case that the node graph isn't available or built + ALERT ( at_console, "Graph not ready!\n" ); + UTIL_Remove( this ); + return; + } + + + if (FClassnameIs( pev, "node_viewer_fly")) + { + m_iHull = NODE_FLY_HULL; + m_afNodeType = bits_NODE_AIR; + m_vecColor = Vector( 160, 100, 255 ); + } + else if (FClassnameIs( pev, "node_viewer_large")) + { + m_iHull = NODE_LARGE_HULL; + m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; + m_vecColor = Vector( 100, 255, 160 ); + } + else + { + m_iHull = NODE_HUMAN_HULL; + m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; + m_vecColor = Vector( 255, 160, 100 ); + } + + + m_iBaseNode = WorldGraph.FindNearestNode ( pev->origin, m_afNodeType ); + + if ( m_iBaseNode < 0 ) + { + ALERT( at_console, "No nearby node\n" ); + return; + } + + m_nVisited = 0; + + ALERT( at_aiconsole, "basenode %d\n", m_iBaseNode ); + + if (WorldGraph.m_cNodes < 128) + { + for (int i = 0; i < WorldGraph.m_cNodes; i++) + { + AddNode( i, WorldGraph.NextNodeInRoute( i, m_iBaseNode, m_iHull, 0 )); + } + } + else + { + // do a depth traversal + FindNodeConnections( m_iBaseNode ); + + int start = 0; + int end; + do { + end = m_nVisited; + // ALERT( at_console, "%d :", m_nVisited ); + for (end = m_nVisited; start < end; start++) + { + FindNodeConnections( m_aFrom[start] ); + FindNodeConnections( m_aTo[start] ); + } + } while (end != m_nVisited); + } + + ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); + + m_iDraw = 0; + SetThink( &CNodeViewer::DrawThink ); + pev->nextthink = gpGlobals->time; +} + + +void CNodeViewer :: FindNodeConnections ( int iNode ) +{ + AddNode( iNode, WorldGraph.NextNodeInRoute( iNode, m_iBaseNode, m_iHull, 0 )); + for ( int i = 0 ; i < WorldGraph.m_pNodes[ iNode ].m_cNumLinks ; i++ ) + { + CLink *pToLink = &WorldGraph.NodeLink( iNode, i); + AddNode( pToLink->m_iDestNode, WorldGraph.NextNodeInRoute( pToLink->m_iDestNode, m_iBaseNode, m_iHull, 0 )); + } +} + +void CNodeViewer::AddNode( int iFrom, int iTo ) +{ + if (m_nVisited >= 128) + { + return; + } + else + { + if (iFrom == iTo) + return; + + for (int i = 0; i < m_nVisited; i++) + { + if (m_aFrom[i] == iFrom && m_aTo[i] == iTo) + return; + if (m_aFrom[i] == iTo && m_aTo[i] == iFrom) + return; + } + m_aFrom[m_nVisited] = iFrom; + m_aTo[m_nVisited] = iTo; + m_nVisited++; + } +} + + +void CNodeViewer :: DrawThink( void ) +{ + pev->nextthink = gpGlobals->time; + + for (int i = 0; i < 10; i++) + { + if (m_iDraw == m_nVisited) + { + UTIL_Remove( this ); + return; + } + + extern short g_sModelIndexLaser; + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.x ); + WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.y ); + WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.z + NODE_HEIGHT ); + + WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.x ); + WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.y ); + WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.z + NODE_HEIGHT ); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 250 ); // life + WRITE_BYTE( 40 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( m_vecColor.x ); // r, g, b + WRITE_BYTE( m_vecColor.y ); // r, g, b + WRITE_BYTE( m_vecColor.z ); // r, g, b + WRITE_BYTE( 128 ); // brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); + + m_iDraw++; + } +} + + diff --git a/main/source/dlls/nodes.h b/main/source/dlls/nodes.h index 824ceb20..b1a5d13f 100644 --- a/main/source/dlls/nodes.h +++ b/main/source/dlls/nodes.h @@ -1,54 +1,54 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// nodes.h -//========================================================= - -#ifndef NODES_H -#define NODES_H - -#define bits_NODE_GROUP_REALM 1 - -class CLink -{ -public: - entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc) -}; - - -class CGraph -{ -public: - BOOL m_fGraphPresent;// is the graph in memory? - BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set? - - int m_cLinks;// total number of links - CLink *m_pLinkPool;// big list of all node connections - - void InitGraph( void ); - int AllocNodes ( void ); - - int CheckNODFile(char *szMapName); - int FLoadGraph(char *szMapName); - int FSetGraphPointers(void); - void ShowNodeConnections ( int iNode ); - int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ); - int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ); - -}; - -extern CGraph WorldGraph; - +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// nodes.h +//========================================================= + +#ifndef NODES_H +#define NODES_H + +#define bits_NODE_GROUP_REALM 1 + +class CLink +{ +public: + entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc) +}; + + +class CGraph +{ +public: + BOOL m_fGraphPresent;// is the graph in memory? + BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set? + + int m_cLinks;// total number of links + CLink *m_pLinkPool;// big list of all node connections + + void InitGraph( void ); + int AllocNodes ( void ); + + int CheckNODFile(char *szMapName); + int FLoadGraph(char *szMapName); + int FSetGraphPointers(void); + void ShowNodeConnections ( int iNode ); + int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ); + int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ); + +}; + +extern CGraph WorldGraph; + #endif // NODES_H \ No newline at end of file diff --git a/main/source/dlls/observer.cpp b/main/source/dlls/observer.cpp index 95c03bf8..ec2e9082 100644 --- a/main/source/dlls/observer.cpp +++ b/main/source/dlls/observer.cpp @@ -1,315 +1,315 @@ -//=========== (C) Copyright 1996-2002, Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: Functionality for the observer chase camera -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//============================================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "pm_shared/pm_shared.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHGamerules.h" - -const float kNextTargetInterval = .2f; - -// Find the next client in the game for this player to spectate -bool CBasePlayer::Observer_FindNextPlayer(bool inReverse) -{ - // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching - // only a subset of the players. e.g. Make it check the target's team. - bool theSuccess = false; - int iStart; - if ( m_hObserverTarget ) - iStart = ENTINDEX( m_hObserverTarget->edict() ); - else - iStart = ENTINDEX( edict() ); - int iCurrent = iStart; - m_hObserverTarget = NULL; - - if(this->entindex() == 1) - { - int a = 0; - } - - int iDir = inReverse ? -1 : 1; - AvHPlayer* theThisAvHPlayer = dynamic_cast(this); - - do - { - iCurrent += iDir; - - // Loop through the clients - if (iCurrent > gpGlobals->maxClients) - iCurrent = 1; - if (iCurrent < 1) - iCurrent = gpGlobals->maxClients; - - CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); - if ( !pEnt ) - continue; - if ( pEnt == this ) - continue; - // Don't spec observers or invisible players - if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW)) - continue; - - // MOD AUTHORS: Add checks on target here. - AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); - if(theThisAvHPlayer && thePotentialTargetPlayer) - { - if(!thePotentialTargetPlayer->GetIsRelevant()) - { - continue; - } - - // Don't allow spectating of other team when we could come back in - if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) - { - continue; - } - - if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) - { - if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) - { - continue; - } - } - - // Don't allow spectating of players in top down mode - if(thePotentialTargetPlayer->GetIsInTopDownMode()) - { - continue; - } - - // Don't allow spectating opposite teams in tournament mode - //if(GetGameRules()->GetIsTournamentMode()) - //{ - //} - - m_hObserverTarget = pEnt; - } - break; - - } while ( iCurrent != iStart ); - - // Did we find a target? - if ( m_hObserverTarget ) - { - // Store the target in pev so the physics DLL can get to it - if (pev->iuser1 != OBS_ROAMING) - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); - // Move to the target - UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); - - //ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->classname ) ); - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - - theSuccess = true; - } - else - { - //ALERT( at_console, "No observer targets.\n" ); - } - return theSuccess; -} - -void CBasePlayer::Observer_SpectatePlayer(int index) -{ - - CBaseEntity* pEnt = UTIL_PlayerByIndex(index); - - AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); - AvHPlayer* theThisAvHPlayer = dynamic_cast(this); - - if (theThisAvHPlayer == NULL || thePotentialTargetPlayer == NULL) - { - return; - } - - if(!thePotentialTargetPlayer->GetIsRelevant()) - { - return; - } - - // Don't allow spectating of other team when we could come back in - if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) - { - return; - } - - if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) - { - if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) - { - return; - } - } - - // Don't allow spectating of players in top down mode - if(thePotentialTargetPlayer->GetIsInTopDownMode()) - { - return; - } - - m_hObserverTarget = pEnt; - pev->iuser2 = index; - -} - -// Handle buttons in observer mode -void CBasePlayer::Observer_HandleButtons() -{ - - // Removed by mmcguire. - // This is all handled through the client side UI. - - /* - // Slow down mouse clicks - if ( m_flNextObserverInput > gpGlobals->time ) - return; - - // Only do this if spectating - AvHPlayer* thePlayer = dynamic_cast(this); - ASSERT(thePlayer); - bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); - - // Jump changes from modes: Chase to Roaming - if ( m_afButtonPressed & IN_JUMP ) - { - if ( pev->iuser1 == OBS_CHASE_LOCKED ) - { - Observer_SetMode( OBS_CHASE_FREE ); - } - else if ( pev->iuser1 == OBS_CHASE_FREE ) - { - if(theIsObserving) - { - Observer_SetMode(OBS_ROAMING); - } - else - { - Observer_SetMode(OBS_IN_EYE); - } - } - else if ( pev->iuser1 == OBS_ROAMING ) - { - Observer_SetMode( OBS_IN_EYE ); - } - else if ( pev->iuser1 == OBS_IN_EYE ) - { - if(theIsObserving) - { - Observer_SetMode(OBS_MAP_FREE); - } - else - { - Observer_SetMode(OBS_CHASE_LOCKED); - } - } - else if ( pev->iuser1 == OBS_MAP_FREE ) - { - Observer_SetMode( OBS_MAP_CHASE ); - } - else - { - Observer_SetMode( OBS_CHASE_FREE ); // don't use OBS_CHASE_LOCKED anymore - } - - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - } - - // Attack moves to the next player - if ( (m_afButtonPressed & IN_ATTACK) || ((m_afButtonPressed & IN_MOVERIGHT) && (pev->iuser1 != OBS_ROAMING)) ) - { - if(Observer_FindNextPlayer( false )) - { - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - } - else - { - Observer_SetMode( OBS_CHASE_FREE ); - } - } - - // Attack2 moves to the prev player - if ( (m_afButtonPressed & IN_ATTACK2) || ((m_afButtonPressed & IN_MOVELEFT) && (pev->iuser1 != OBS_ROAMING)) ) - { - if(Observer_FindNextPlayer( true )) - { - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - } - else - { - Observer_SetMode( OBS_CHASE_FREE ); - } - } - */ - -} - -// Attempt to change the observer mode -void CBasePlayer::Observer_SetMode( int iMode ) -{ - // Limit some modes if we're not observing - AvHPlayer* thePlayer = dynamic_cast(this); - ASSERT(thePlayer); - - bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); - - if(!theIsObserving) - { - if((iMode == OBS_ROAMING) /*|| (iMode == OBS_MAP_FREE) || (iMode == OBS_MAP_CHASE)*/) - { - return; - } - } - - // Just abort if we're changing to the mode we're already in - if ( iMode == pev->iuser1 ) - return; - - // Removed by mmcguire. - - // is valid mode ? - if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_IN_EYE ) - iMode = OBS_IN_EYE; // now it is - - // if we are not roaming, we need a valid target to track - if ( (iMode != OBS_ROAMING) && (m_hObserverTarget == NULL) ) - { - Observer_FindNextPlayer(); - - // if we didn't find a valid target switch to roaming - if (m_hObserverTarget == NULL) - { - iMode = OBS_ROAMING; - } - } - - // set spectator mode - pev->iuser1 = iMode; - - // set target if not roaming - if (iMode == OBS_ROAMING) - pev->iuser2 = 0; - else - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); - - // Make sure our target is valid (go backward then forward) - Observer_FindNextPlayer(true); - Observer_FindNextPlayer(false); +//=========== (C) Copyright 1996-2002, Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Functionality for the observer chase camera +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "pm_shared/pm_shared.h" +#include "../mod/AvHPlayer.h" +#include "../mod/AvHGamerules.h" + +const float kNextTargetInterval = .2f; + +// Find the next client in the game for this player to spectate +bool CBasePlayer::Observer_FindNextPlayer(bool inReverse) +{ + // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching + // only a subset of the players. e.g. Make it check the target's team. + bool theSuccess = false; + int iStart; + if ( m_hObserverTarget ) + iStart = ENTINDEX( m_hObserverTarget->edict() ); + else + iStart = ENTINDEX( edict() ); + int iCurrent = iStart; + m_hObserverTarget = NULL; + + if(this->entindex() == 1) + { + int a = 0; + } + + int iDir = inReverse ? -1 : 1; + AvHPlayer* theThisAvHPlayer = dynamic_cast(this); + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > gpGlobals->maxClients) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = gpGlobals->maxClients; + + CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); + if ( !pEnt ) + continue; + if ( pEnt == this ) + continue; + // Don't spec observers or invisible players + if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW)) + continue; + + // MOD AUTHORS: Add checks on target here. + AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); + if(theThisAvHPlayer && thePotentialTargetPlayer) + { + if(!thePotentialTargetPlayer->GetIsRelevant()) + { + continue; + } + + // Don't allow spectating of other team when we could come back in + if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) + { + continue; + } + + if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) + { + if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) + { + continue; + } + } + + // Don't allow spectating of players in top down mode + if(thePotentialTargetPlayer->GetIsInTopDownMode()) + { + continue; + } + + // Don't allow spectating opposite teams in tournament mode + //if(GetGameRules()->GetIsTournamentMode()) + //{ + //} + + m_hObserverTarget = pEnt; + } + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( m_hObserverTarget ) + { + // Store the target in pev so the physics DLL can get to it + if (pev->iuser1 != OBS_ROAMING) + pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); + // Move to the target + UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); + + //ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->classname ) ); + m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; + + theSuccess = true; + } + else + { + //ALERT( at_console, "No observer targets.\n" ); + } + return theSuccess; +} + +void CBasePlayer::Observer_SpectatePlayer(int index) +{ + + CBaseEntity* pEnt = UTIL_PlayerByIndex(index); + + AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); + AvHPlayer* theThisAvHPlayer = dynamic_cast(this); + + if (theThisAvHPlayer == NULL || thePotentialTargetPlayer == NULL) + { + return; + } + + if(!thePotentialTargetPlayer->GetIsRelevant()) + { + return; + } + + // Don't allow spectating of other team when we could come back in + if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) + { + return; + } + + if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) + { + if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) + { + return; + } + } + + // Don't allow spectating of players in top down mode + if(thePotentialTargetPlayer->GetIsInTopDownMode()) + { + return; + } + + m_hObserverTarget = pEnt; + pev->iuser2 = index; + +} + +// Handle buttons in observer mode +void CBasePlayer::Observer_HandleButtons() +{ + + // Removed by mmcguire. + // This is all handled through the client side UI. + + /* + // Slow down mouse clicks + if ( m_flNextObserverInput > gpGlobals->time ) + return; + + // Only do this if spectating + AvHPlayer* thePlayer = dynamic_cast(this); + ASSERT(thePlayer); + bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); + + // Jump changes from modes: Chase to Roaming + if ( m_afButtonPressed & IN_JUMP ) + { + if ( pev->iuser1 == OBS_CHASE_LOCKED ) + { + Observer_SetMode( OBS_CHASE_FREE ); + } + else if ( pev->iuser1 == OBS_CHASE_FREE ) + { + if(theIsObserving) + { + Observer_SetMode(OBS_ROAMING); + } + else + { + Observer_SetMode(OBS_IN_EYE); + } + } + else if ( pev->iuser1 == OBS_ROAMING ) + { + Observer_SetMode( OBS_IN_EYE ); + } + else if ( pev->iuser1 == OBS_IN_EYE ) + { + if(theIsObserving) + { + Observer_SetMode(OBS_MAP_FREE); + } + else + { + Observer_SetMode(OBS_CHASE_LOCKED); + } + } + else if ( pev->iuser1 == OBS_MAP_FREE ) + { + Observer_SetMode( OBS_MAP_CHASE ); + } + else + { + Observer_SetMode( OBS_CHASE_FREE ); // don't use OBS_CHASE_LOCKED anymore + } + + m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; + } + + // Attack moves to the next player + if ( (m_afButtonPressed & IN_ATTACK) || ((m_afButtonPressed & IN_MOVERIGHT) && (pev->iuser1 != OBS_ROAMING)) ) + { + if(Observer_FindNextPlayer( false )) + { + m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; + } + else + { + Observer_SetMode( OBS_CHASE_FREE ); + } + } + + // Attack2 moves to the prev player + if ( (m_afButtonPressed & IN_ATTACK2) || ((m_afButtonPressed & IN_MOVELEFT) && (pev->iuser1 != OBS_ROAMING)) ) + { + if(Observer_FindNextPlayer( true )) + { + m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; + } + else + { + Observer_SetMode( OBS_CHASE_FREE ); + } + } + */ + +} + +// Attempt to change the observer mode +void CBasePlayer::Observer_SetMode( int iMode ) +{ + // Limit some modes if we're not observing + AvHPlayer* thePlayer = dynamic_cast(this); + ASSERT(thePlayer); + + bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); + + if(!theIsObserving) + { + if((iMode == OBS_ROAMING) /*|| (iMode == OBS_MAP_FREE) || (iMode == OBS_MAP_CHASE)*/) + { + return; + } + } + + // Just abort if we're changing to the mode we're already in + if ( iMode == pev->iuser1 ) + return; + + // Removed by mmcguire. + + // is valid mode ? + if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_IN_EYE ) + iMode = OBS_IN_EYE; // now it is + + // if we are not roaming, we need a valid target to track + if ( (iMode != OBS_ROAMING) && (m_hObserverTarget == NULL) ) + { + Observer_FindNextPlayer(); + + // if we didn't find a valid target switch to roaming + if (m_hObserverTarget == NULL) + { + iMode = OBS_ROAMING; + } + } + + // set spectator mode + pev->iuser1 = iMode; + + // set target if not roaming + if (iMode == OBS_ROAMING) + pev->iuser2 = 0; + else + pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); + + // Make sure our target is valid (go backward then forward) + Observer_FindNextPlayer(true); + Observer_FindNextPlayer(false); } \ No newline at end of file diff --git a/main/source/dlls/observer.cpp~ b/main/source/dlls/observer.cpp~ deleted file mode 100644 index 25643d48..00000000 --- a/main/source/dlls/observer.cpp~ +++ /dev/null @@ -1,315 +0,0 @@ -//=========== (C) Copyright 1996-2002, Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: Functionality for the observer chase camera -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//============================================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "pm_shared/pm_shared.h" -#include "..mod/AvHPlayer.h" -#include "..mod/AvHGamerules.h" - -const float kNextTargetInterval = .2f; - -// Find the next client in the game for this player to spectate -bool CBasePlayer::Observer_FindNextPlayer(bool inReverse) -{ - // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching - // only a subset of the players. e.g. Make it check the target's team. - bool theSuccess = false; - int iStart; - if ( m_hObserverTarget ) - iStart = ENTINDEX( m_hObserverTarget->edict() ); - else - iStart = ENTINDEX( edict() ); - int iCurrent = iStart; - m_hObserverTarget = NULL; - - if(this->entindex() == 1) - { - int a = 0; - } - - int iDir = inReverse ? -1 : 1; - AvHPlayer* theThisAvHPlayer = dynamic_cast(this); - - do - { - iCurrent += iDir; - - // Loop through the clients - if (iCurrent > gpGlobals->maxClients) - iCurrent = 1; - if (iCurrent < 1) - iCurrent = gpGlobals->maxClients; - - CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); - if ( !pEnt ) - continue; - if ( pEnt == this ) - continue; - // Don't spec observers or invisible players - if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW)) - continue; - - // MOD AUTHORS: Add checks on target here. - AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); - if(theThisAvHPlayer && thePotentialTargetPlayer) - { - if(!thePotentialTargetPlayer->GetIsRelevant()) - { - continue; - } - - // Don't allow spectating of other team when we could come back in - if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) - { - continue; - } - - if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) - { - if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) - { - continue; - } - } - - // Don't allow spectating of players in top down mode - if(thePotentialTargetPlayer->GetIsInTopDownMode()) - { - continue; - } - - // Don't allow spectating opposite teams in tournament mode - //if(GetGameRules()->GetIsTournamentMode()) - //{ - //} - - m_hObserverTarget = pEnt; - } - break; - - } while ( iCurrent != iStart ); - - // Did we find a target? - if ( m_hObserverTarget ) - { - // Store the target in pev so the physics DLL can get to it - if (pev->iuser1 != OBS_ROAMING) - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); - // Move to the target - UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); - - //ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->classname ) ); - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - - theSuccess = true; - } - else - { - //ALERT( at_console, "No observer targets.\n" ); - } - return theSuccess; -} - -void CBasePlayer::Observer_SpectatePlayer(int index) -{ - - CBaseEntity* pEnt = UTIL_PlayerByIndex(index); - - AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); - AvHPlayer* theThisAvHPlayer = dynamic_cast(this); - - if (theThisAvHPlayer == NULL || thePotentialTargetPlayer == NULL) - { - return; - } - - if(!thePotentialTargetPlayer->GetIsRelevant()) - { - return; - } - - // Don't allow spectating of other team when we could come back in - if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) - { - return; - } - - if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) - { - if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) - { - return; - } - } - - // Don't allow spectating of players in top down mode - if(thePotentialTargetPlayer->GetIsInTopDownMode()) - { - return; - } - - m_hObserverTarget = pEnt; - pev->iuser2 = index; - -} - -// Handle buttons in observer mode -void CBasePlayer::Observer_HandleButtons() -{ - - // Removed by mmcguire. - // This is all handled through the client side UI. - - /* - // Slow down mouse clicks - if ( m_flNextObserverInput > gpGlobals->time ) - return; - - // Only do this if spectating - AvHPlayer* thePlayer = dynamic_cast(this); - ASSERT(thePlayer); - bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); - - // Jump changes from modes: Chase to Roaming - if ( m_afButtonPressed & IN_JUMP ) - { - if ( pev->iuser1 == OBS_CHASE_LOCKED ) - { - Observer_SetMode( OBS_CHASE_FREE ); - } - else if ( pev->iuser1 == OBS_CHASE_FREE ) - { - if(theIsObserving) - { - Observer_SetMode(OBS_ROAMING); - } - else - { - Observer_SetMode(OBS_IN_EYE); - } - } - else if ( pev->iuser1 == OBS_ROAMING ) - { - Observer_SetMode( OBS_IN_EYE ); - } - else if ( pev->iuser1 == OBS_IN_EYE ) - { - if(theIsObserving) - { - Observer_SetMode(OBS_MAP_FREE); - } - else - { - Observer_SetMode(OBS_CHASE_LOCKED); - } - } - else if ( pev->iuser1 == OBS_MAP_FREE ) - { - Observer_SetMode( OBS_MAP_CHASE ); - } - else - { - Observer_SetMode( OBS_CHASE_FREE ); // don't use OBS_CHASE_LOCKED anymore - } - - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - } - - // Attack moves to the next player - if ( (m_afButtonPressed & IN_ATTACK) || ((m_afButtonPressed & IN_MOVERIGHT) && (pev->iuser1 != OBS_ROAMING)) ) - { - if(Observer_FindNextPlayer( false )) - { - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - } - else - { - Observer_SetMode( OBS_CHASE_FREE ); - } - } - - // Attack2 moves to the prev player - if ( (m_afButtonPressed & IN_ATTACK2) || ((m_afButtonPressed & IN_MOVELEFT) && (pev->iuser1 != OBS_ROAMING)) ) - { - if(Observer_FindNextPlayer( true )) - { - m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; - } - else - { - Observer_SetMode( OBS_CHASE_FREE ); - } - } - */ - -} - -// Attempt to change the observer mode -void CBasePlayer::Observer_SetMode( int iMode ) -{ - // Limit some modes if we're not observing - AvHPlayer* thePlayer = dynamic_cast(this); - ASSERT(thePlayer); - - bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); - - if(!theIsObserving) - { - if((iMode == OBS_ROAMING) /*|| (iMode == OBS_MAP_FREE) || (iMode == OBS_MAP_CHASE)*/) - { - return; - } - } - - // Just abort if we're changing to the mode we're already in - if ( iMode == pev->iuser1 ) - return; - - // Removed by mmcguire. - - // is valid mode ? - if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_IN_EYE ) - iMode = OBS_IN_EYE; // now it is - - // if we are not roaming, we need a valid target to track - if ( (iMode != OBS_ROAMING) && (m_hObserverTarget == NULL) ) - { - Observer_FindNextPlayer(); - - // if we didn't find a valid target switch to roaming - if (m_hObserverTarget == NULL) - { - iMode = OBS_ROAMING; - } - } - - // set spectator mode - pev->iuser1 = iMode; - - // set target if not roaming - if (iMode == OBS_ROAMING) - pev->iuser2 = 0; - else - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); - - // Make sure our target is valid (go backward then forward) - Observer_FindNextPlayer(true); - Observer_FindNextPlayer(false); -} \ No newline at end of file diff --git a/main/source/dlls/osprey.cpp b/main/source/dlls/osprey.cpp index 75503e79..e46253f9 100644 --- a/main/source/dlls/osprey.cpp +++ b/main/source/dlls/osprey.cpp @@ -1,805 +1,805 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "effects.h" -#include "customentity.h" - -typedef struct -{ - int isValid; - EHANDLE hGrunt; - Vector vecOrigin; - Vector vecAngles; -} t_ospreygrunt; - - - -#define SF_WAITFORTRIGGER 0x40 - - -#define MAX_CARRY 24 - -class COsprey : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_MACHINE; }; - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - - void UpdateGoal( void ); - BOOL HasDead( void ); - void EXPORT FlyThink( void ); - void EXPORT DeployThink( void ); - void Flight( void ); - void EXPORT HitTouch( CBaseEntity *pOther ); - void EXPORT FindAllThink( void ); - void EXPORT HoverThink( void ); - CBaseMonster *MakeGrunt( Vector vecSrc ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void ShowDamage( void ); - - CBaseEntity *m_pGoalEnt; - Vector m_vel1; - Vector m_vel2; - Vector m_pos1; - Vector m_pos2; - Vector m_ang1; - Vector m_ang2; - float m_startTime; - float m_dTime; - - Vector m_velocity; - - float m_flIdealtilt; - float m_flRotortilt; - - float m_flRightHealth; - float m_flLeftHealth; - - int m_iUnits; - EHANDLE m_hGrunt[MAX_CARRY]; - Vector m_vecOrigin[MAX_CARRY]; - EHANDLE m_hRepel[4]; - - int m_iSoundState; - int m_iSpriteTexture; - - int m_iPitch; - - int m_iExplode; - int m_iTailGibs; - int m_iBodyGibs; - int m_iEngineGibs; - - int m_iDoLeftSmokePuff; - int m_iDoRightSmokePuff; -}; - -LINK_ENTITY_TO_CLASS( monster_osprey, COsprey ); - -TYPEDESCRIPTION COsprey::m_SaveData[] = -{ - DEFINE_FIELD( COsprey, m_pGoalEnt, FIELD_CLASSPTR ), - DEFINE_FIELD( COsprey, m_vel1, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_vel2, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_pos1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( COsprey, m_pos2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( COsprey, m_ang1, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_ang2, FIELD_VECTOR ), - - DEFINE_FIELD( COsprey, m_startTime, FIELD_TIME ), - DEFINE_FIELD( COsprey, m_dTime, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_velocity, FIELD_VECTOR ), - - DEFINE_FIELD( COsprey, m_flIdealtilt, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_flRotortilt, FIELD_FLOAT ), - - DEFINE_FIELD( COsprey, m_flRightHealth, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_flLeftHealth, FIELD_FLOAT ), - - DEFINE_FIELD( COsprey, m_iUnits, FIELD_INTEGER ), - DEFINE_ARRAY( COsprey, m_hGrunt, FIELD_EHANDLE, MAX_CARRY ), - DEFINE_ARRAY( COsprey, m_vecOrigin, FIELD_POSITION_VECTOR, MAX_CARRY ), - DEFINE_ARRAY( COsprey, m_hRepel, FIELD_EHANDLE, 4 ), - - // DEFINE_FIELD( COsprey, m_iSoundState, FIELD_INTEGER ), - // DEFINE_FIELD( COsprey, m_iSpriteTexture, FIELD_INTEGER ), - // DEFINE_FIELD( COsprey, m_iPitch, FIELD_INTEGER ), - - DEFINE_FIELD( COsprey, m_iDoLeftSmokePuff, FIELD_INTEGER ), - DEFINE_FIELD( COsprey, m_iDoRightSmokePuff, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ); - - -void COsprey :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/osprey.mdl"); - UTIL_SetSize(pev, Vector( -400, -400, -100), Vector(400, 400, 32)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_YES; - m_flRightHealth = 200; - m_flLeftHealth = 200; - pev->health = 400; - - m_flFieldOfView = 0; // 180 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0,0xFF); - - InitBoneControllers(); - - SetThink( &COsprey::FindAllThink ); - SetUse( &COsprey::CommandUse ); - - if (!(pev->spawnflags & SF_WAITFORTRIGGER)) - { - pev->nextthink = gpGlobals->time + 1.0; - } - - m_pos2 = pev->origin; - m_ang2 = pev->angles; - m_vel2 = pev->velocity; -} - - -void COsprey::Precache( void ) -{ - UTIL_PrecacheOther( "monster_human_grunt" ); - - PRECACHE_MODEL("models/osprey.mdl"); - PRECACHE_MODEL("models/HVR.mdl"); - - PRECACHE_SOUND("apache/ap_rotor4.wav"); - PRECACHE_SOUND("weapons/mortarhit.wav"); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); - - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); - m_iTailGibs = PRECACHE_MODEL( "models/osprey_tailgibs.mdl" ); - m_iBodyGibs = PRECACHE_MODEL( "models/osprey_bodygibs.mdl" ); - m_iEngineGibs = PRECACHE_MODEL( "models/osprey_enginegibs.mdl" ); -} - -void COsprey::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->nextthink = gpGlobals->time + 0.1; -} - -void COsprey :: FindAllThink( void ) -{ - CBaseEntity *pEntity = NULL; - - m_iUnits = 0; - while (m_iUnits < MAX_CARRY && (pEntity = UTIL_FindEntityByClassname( pEntity, "monster_human_grunt" )) != NULL) - { - if (pEntity->IsAlive()) - { - m_hGrunt[m_iUnits] = pEntity; - m_vecOrigin[m_iUnits] = pEntity->pev->origin; - m_iUnits++; - } - } - - if (m_iUnits == 0) - { - ALERT( at_console, "osprey error: no grunts to resupply\n"); - UTIL_Remove( this ); - return; - } - SetThink( &COsprey::FlyThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_startTime = gpGlobals->time; -} - - -void COsprey :: DeployThink( void ) -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector vecForward = gpGlobals->v_forward; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - Vector vecSrc; - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0), ignore_monsters, ENT(pev), &tr); - CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * 100 + vecUp * -96; - m_hRepel[0] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * 100 + vecUp * -96; - m_hRepel[1] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * -100 + vecUp * -96; - m_hRepel[2] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; - m_hRepel[3] = MakeGrunt( vecSrc ); - - SetThink( &COsprey::HoverThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -BOOL COsprey :: HasDead( ) -{ - for (int i = 0; i < m_iUnits; i++) - { - if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) - { - return TRUE; - } - else - { - m_vecOrigin[i] = m_hGrunt[i]->pev->origin; // send them to where they died - } - } - return FALSE; -} - - -CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) -{ - CBaseEntity *pEntity; - CBaseMonster *pGrunt; - - TraceResult tr; - UTIL_TraceLine( vecSrc, vecSrc + Vector( 0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr); - if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) - return NULL; - - for (int i = 0; i < m_iUnits; i++) - { - if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) - { - if (m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal) - { - m_hGrunt[i]->SUB_StartFadeOut( ); - } - pEntity = Create( "monster_human_grunt", vecSrc, pev->angles ); - pGrunt = pEntity->MyMonsterPointer( ); - pGrunt->pev->movetype = MOVETYPE_FLY; - pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); - pGrunt->SetActivity( ACT_GLIDE ); - - CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); - pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt->entindex() ); - pBeam->SetFlags( BEAM_FSOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &COsprey::SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; - - // ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z ); - pGrunt->m_vecLastPosition = m_vecOrigin[i]; - m_hGrunt[i] = pGrunt; - return pGrunt; - } - } - // ALERT( at_console, "none dead\n"); - return NULL; -} - - -void COsprey :: HoverThink( void ) -{ - int i; - for (i = 0; i < 4; i++) - { - if (m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && !(m_hRepel[i]->pev->flags & FL_ONGROUND)) - { - break; - } - } - - if (i == 4) - { - m_startTime = gpGlobals->time; - SetThink( &COsprey::FlyThink ); - } - - pev->nextthink = gpGlobals->time + 0.1; - UTIL_MakeAimVectors( pev->angles ); - ShowDamage( ); -} - - -void COsprey::UpdateGoal( ) -{ - if (m_pGoalEnt) - { - m_pos1 = m_pos2; - m_ang1 = m_ang2; - m_vel1 = m_vel2; - m_pos2 = m_pGoalEnt->pev->origin; - m_ang2 = m_pGoalEnt->pev->angles; - UTIL_MakeAimVectors( Vector( 0, m_ang2.y, 0 ) ); - m_vel2 = gpGlobals->v_forward * m_pGoalEnt->pev->speed; - - m_startTime = m_startTime + m_dTime; - m_dTime = 2.0 * (m_pos1 - m_pos2).Length() / (m_vel1.Length() + m_pGoalEnt->pev->speed); - - if (m_ang1.y - m_ang2.y < -180) - { - m_ang1.y += 360; - } - else if (m_ang1.y - m_ang2.y > 180) - { - m_ang1.y -= 360; - } - - if (m_pGoalEnt->pev->speed < 400) - m_flIdealtilt = 0; - else - m_flIdealtilt = -90; - } - else - { - ALERT( at_console, "osprey missing target"); - } -} - - -void COsprey::FlyThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target - { - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( pev->target ) ) ); - UpdateGoal( ); - } - - if (gpGlobals->time > m_startTime + m_dTime) - { - if (m_pGoalEnt->pev->speed == 0) - { - SetThink( &COsprey::DeployThink ); - } - do { - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( m_pGoalEnt->pev->target ) ) ); - } while (m_pGoalEnt->pev->speed < 400 && !HasDead()); - UpdateGoal( ); - } - - Flight( ); - ShowDamage( ); -} - - -void COsprey::Flight( ) -{ - float t = (gpGlobals->time - m_startTime); - float scale = 1.0 / m_dTime; - - float f = UTIL_SplineFraction( t * scale, 1.0 ); - - Vector pos = (m_pos1 + m_vel1 * t) * (1.0 - f) + (m_pos2 - m_vel2 * (m_dTime - t)) * f; - Vector ang = (m_ang1) * (1.0 - f) + (m_ang2) * f; - m_velocity = m_vel1 * (1.0 - f) + m_vel2 * f; - - UTIL_SetOrigin( pev, pos ); - pev->angles = ang; - UTIL_MakeAimVectors( pev->angles ); - float flSpeed = DotProduct( gpGlobals->v_forward, m_velocity ); - - // float flSpeed = DotProduct( gpGlobals->v_forward, pev->velocity ); - - float m_flIdealtilt = (160 - flSpeed) / 10.0; - - // ALERT( at_console, "%f %f\n", flSpeed, flIdealtilt ); - if (m_flRotortilt < m_flIdealtilt) - { - m_flRotortilt += 0.5; - if (m_flRotortilt > 0) - m_flRotortilt = 0; - } - if (m_flRotortilt > m_flIdealtilt) - { - m_flRotortilt -= 0.5; - if (m_flRotortilt < -90) - m_flRotortilt = -90; - } - SetBoneController( 0, m_flRotortilt ); - - - if (m_iSoundState == 0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, 0, 110 ); - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - } - else - { - CBaseEntity *pPlayer = NULL; - - pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - // UNDONE: this needs to send different sounds to every player for multiplayer. - if (pPlayer) - { - float pitch = DotProduct( m_velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); - - pitch = (int)(100 + pitch / 75.0); - - if (pitch > 250) - pitch = 250; - if (pitch < 50) - pitch = 50; - - if (pitch == 100) - pitch = 101; - - if (pitch != m_iPitch) - { - m_iPitch = pitch; - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - // ALERT( at_console, "%.0f\n", pitch ); - } - } - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - } - -} - - -void COsprey::HitTouch( CBaseEntity *pOther ) -{ - pev->nextthink = gpGlobals->time + 2.0; -} - - -/* -int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if (m_flRotortilt <= -90) - { - m_flRotortilt = 0; - } - else - { - m_flRotortilt -= 45; - } - SetBoneController( 0, m_flRotortilt ); - return 0; -} -*/ - - - -void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - pev->velocity = m_velocity; - pev->avelocity = Vector( RANDOM_FLOAT( -20, 20 ), 0, RANDOM_FLOAT( -50, 50 ) ); - STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( &COsprey::DyingThink ); - SetTouch( &COsprey::CrashTouch ); - pev->nextthink = gpGlobals->time + 0.1; - pev->health = 0; - pev->takedamage = DAMAGE_NO; - - m_startTime = gpGlobals->time + 4.0; -} - -void COsprey::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - SetTouch( NULL ); - m_startTime = gpGlobals->time; - pev->nextthink = gpGlobals->time; - m_velocity = pev->velocity; - } -} - - -void COsprey :: DyingThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->avelocity = pev->avelocity * 1.02; - - // still falling? - if (m_startTime > gpGlobals->time ) - { - UTIL_MakeAimVectors( pev->angles ); - ShowDamage( ); - - Vector vecSpot = pev->origin + pev->velocity * 0.2; - - // random explosions - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 100 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( 800 ); - WRITE_COORD( 800 ); - WRITE_COORD( 132 ); - - // velocity - WRITE_COORD( pev->velocity.x ); - WRITE_COORD( pev->velocity.y ); - WRITE_COORD( pev->velocity.z ); - - // randomization - WRITE_BYTE( 50 ); - - // Model - WRITE_SHORT( m_iTailGibs ); //model id# - - // # of shards - WRITE_BYTE( 8 ); // let client decide - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - - - // don't stop it we touch a entity - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.2; - return; - } - else - { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - */ - - // gibs - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 255 ); // brightness - MESSAGE_END(); - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 300 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 6 ); // framerate - MESSAGE_END(); - */ - - // blast circle - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 4 ); // life - WRITE_BYTE( 32 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 192 ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); - - RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); - - // gibs - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 64); - - // size - WRITE_COORD( 800 ); - WRITE_COORD( 800 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( m_velocity.x ); - WRITE_COORD( m_velocity.y ); - WRITE_COORD( fabs( m_velocity.z ) * 0.25 ); - - // randomization - WRITE_BYTE( 40 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 128 ); - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - UTIL_Remove( this ); - } -} - - -void COsprey :: ShowDamage( void ) -{ - if (m_iDoLeftSmokePuff > 0 || RANDOM_LONG(0,99) > m_flLeftHealth) - { - Vector vecSrc = pev->origin + gpGlobals->v_right * -340; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - if (m_iDoLeftSmokePuff > 0) - m_iDoLeftSmokePuff--; - } - if (m_iDoRightSmokePuff > 0 || RANDOM_LONG(0,99) > m_flRightHealth) - { - Vector vecSrc = pev->origin + gpGlobals->v_right * 340; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - if (m_iDoRightSmokePuff > 0) - m_iDoRightSmokePuff--; - } -} - - -void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); - - // only so much per engine - if (ptr->iHitgroup == 3) - { - if (m_flRightHealth < 0) - return; - else - m_flRightHealth -= flDamage; - m_iDoLeftSmokePuff = 3 + (flDamage / 5.0); - } - - if (ptr->iHitgroup == 2) - { - if (m_flLeftHealth < 0) - return; - else - m_flLeftHealth -= flDamage; - m_iDoRightSmokePuff = 3 + (flDamage / 5.0); - } - - // hit hard, hits cockpit, hits engines - if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3) - { - // ALERT( at_console, "%.0f\n", flDamage ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } - else - { - UTIL_Sparks( ptr->vecEndPos ); - } -} - - - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "effects.h" +#include "customentity.h" + +typedef struct +{ + int isValid; + EHANDLE hGrunt; + Vector vecOrigin; + Vector vecAngles; +} t_ospreygrunt; + + + +#define SF_WAITFORTRIGGER 0x40 + + +#define MAX_CARRY 24 + +class COsprey : public CBaseMonster +{ +public: + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + void Spawn( void ); + void Precache( void ); + int Classify( void ) { return CLASS_MACHINE; }; + int BloodColor( void ) { return DONT_BLEED; } + void Killed( entvars_t *pevAttacker, int iGib ); + + void UpdateGoal( void ); + BOOL HasDead( void ); + void EXPORT FlyThink( void ); + void EXPORT DeployThink( void ); + void Flight( void ); + void EXPORT HitTouch( CBaseEntity *pOther ); + void EXPORT FindAllThink( void ); + void EXPORT HoverThink( void ); + CBaseMonster *MakeGrunt( Vector vecSrc ); + void EXPORT CrashTouch( CBaseEntity *pOther ); + void EXPORT DyingThink( void ); + void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + // int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + void ShowDamage( void ); + + CBaseEntity *m_pGoalEnt; + Vector m_vel1; + Vector m_vel2; + Vector m_pos1; + Vector m_pos2; + Vector m_ang1; + Vector m_ang2; + float m_startTime; + float m_dTime; + + Vector m_velocity; + + float m_flIdealtilt; + float m_flRotortilt; + + float m_flRightHealth; + float m_flLeftHealth; + + int m_iUnits; + EHANDLE m_hGrunt[MAX_CARRY]; + Vector m_vecOrigin[MAX_CARRY]; + EHANDLE m_hRepel[4]; + + int m_iSoundState; + int m_iSpriteTexture; + + int m_iPitch; + + int m_iExplode; + int m_iTailGibs; + int m_iBodyGibs; + int m_iEngineGibs; + + int m_iDoLeftSmokePuff; + int m_iDoRightSmokePuff; +}; + +LINK_ENTITY_TO_CLASS( monster_osprey, COsprey ); + +TYPEDESCRIPTION COsprey::m_SaveData[] = +{ + DEFINE_FIELD( COsprey, m_pGoalEnt, FIELD_CLASSPTR ), + DEFINE_FIELD( COsprey, m_vel1, FIELD_VECTOR ), + DEFINE_FIELD( COsprey, m_vel2, FIELD_VECTOR ), + DEFINE_FIELD( COsprey, m_pos1, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( COsprey, m_pos2, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( COsprey, m_ang1, FIELD_VECTOR ), + DEFINE_FIELD( COsprey, m_ang2, FIELD_VECTOR ), + + DEFINE_FIELD( COsprey, m_startTime, FIELD_TIME ), + DEFINE_FIELD( COsprey, m_dTime, FIELD_FLOAT ), + DEFINE_FIELD( COsprey, m_velocity, FIELD_VECTOR ), + + DEFINE_FIELD( COsprey, m_flIdealtilt, FIELD_FLOAT ), + DEFINE_FIELD( COsprey, m_flRotortilt, FIELD_FLOAT ), + + DEFINE_FIELD( COsprey, m_flRightHealth, FIELD_FLOAT ), + DEFINE_FIELD( COsprey, m_flLeftHealth, FIELD_FLOAT ), + + DEFINE_FIELD( COsprey, m_iUnits, FIELD_INTEGER ), + DEFINE_ARRAY( COsprey, m_hGrunt, FIELD_EHANDLE, MAX_CARRY ), + DEFINE_ARRAY( COsprey, m_vecOrigin, FIELD_POSITION_VECTOR, MAX_CARRY ), + DEFINE_ARRAY( COsprey, m_hRepel, FIELD_EHANDLE, 4 ), + + // DEFINE_FIELD( COsprey, m_iSoundState, FIELD_INTEGER ), + // DEFINE_FIELD( COsprey, m_iSpriteTexture, FIELD_INTEGER ), + // DEFINE_FIELD( COsprey, m_iPitch, FIELD_INTEGER ), + + DEFINE_FIELD( COsprey, m_iDoLeftSmokePuff, FIELD_INTEGER ), + DEFINE_FIELD( COsprey, m_iDoRightSmokePuff, FIELD_INTEGER ), +}; +IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ); + + +void COsprey :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/osprey.mdl"); + UTIL_SetSize(pev, Vector( -400, -400, -100), Vector(400, 400, 32)); + UTIL_SetOrigin( pev, pev->origin ); + + pev->flags |= FL_MONSTER; + pev->takedamage = DAMAGE_YES; + m_flRightHealth = 200; + m_flLeftHealth = 200; + pev->health = 400; + + m_flFieldOfView = 0; // 180 degrees + + pev->sequence = 0; + ResetSequenceInfo( ); + pev->frame = RANDOM_LONG(0,0xFF); + + InitBoneControllers(); + + SetThink( &COsprey::FindAllThink ); + SetUse( &COsprey::CommandUse ); + + if (!(pev->spawnflags & SF_WAITFORTRIGGER)) + { + pev->nextthink = gpGlobals->time + 1.0; + } + + m_pos2 = pev->origin; + m_ang2 = pev->angles; + m_vel2 = pev->velocity; +} + + +void COsprey::Precache( void ) +{ + UTIL_PrecacheOther( "monster_human_grunt" ); + + PRECACHE_MODEL("models/osprey.mdl"); + PRECACHE_MODEL("models/HVR.mdl"); + + PRECACHE_SOUND("apache/ap_rotor4.wav"); + PRECACHE_SOUND("weapons/mortarhit.wav"); + + m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); + + m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); + m_iTailGibs = PRECACHE_MODEL( "models/osprey_tailgibs.mdl" ); + m_iBodyGibs = PRECACHE_MODEL( "models/osprey_bodygibs.mdl" ); + m_iEngineGibs = PRECACHE_MODEL( "models/osprey_enginegibs.mdl" ); +} + +void COsprey::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + pev->nextthink = gpGlobals->time + 0.1; +} + +void COsprey :: FindAllThink( void ) +{ + CBaseEntity *pEntity = NULL; + + m_iUnits = 0; + while (m_iUnits < MAX_CARRY && (pEntity = UTIL_FindEntityByClassname( pEntity, "monster_human_grunt" )) != NULL) + { + if (pEntity->IsAlive()) + { + m_hGrunt[m_iUnits] = pEntity; + m_vecOrigin[m_iUnits] = pEntity->pev->origin; + m_iUnits++; + } + } + + if (m_iUnits == 0) + { + ALERT( at_console, "osprey error: no grunts to resupply\n"); + UTIL_Remove( this ); + return; + } + SetThink( &COsprey::FlyThink ); + pev->nextthink = gpGlobals->time + 0.1; + m_startTime = gpGlobals->time; +} + + +void COsprey :: DeployThink( void ) +{ + UTIL_MakeAimVectors( pev->angles ); + + Vector vecForward = gpGlobals->v_forward; + Vector vecRight = gpGlobals->v_right; + Vector vecUp = gpGlobals->v_up; + + Vector vecSrc; + + TraceResult tr; + UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0), ignore_monsters, ENT(pev), &tr); + CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); + + vecSrc = pev->origin + vecForward * 32 + vecRight * 100 + vecUp * -96; + m_hRepel[0] = MakeGrunt( vecSrc ); + + vecSrc = pev->origin + vecForward * -64 + vecRight * 100 + vecUp * -96; + m_hRepel[1] = MakeGrunt( vecSrc ); + + vecSrc = pev->origin + vecForward * 32 + vecRight * -100 + vecUp * -96; + m_hRepel[2] = MakeGrunt( vecSrc ); + + vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; + m_hRepel[3] = MakeGrunt( vecSrc ); + + SetThink( &COsprey::HoverThink ); + pev->nextthink = gpGlobals->time + 0.1; +} + + + +BOOL COsprey :: HasDead( ) +{ + for (int i = 0; i < m_iUnits; i++) + { + if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) + { + return TRUE; + } + else + { + m_vecOrigin[i] = m_hGrunt[i]->pev->origin; // send them to where they died + } + } + return FALSE; +} + + +CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) +{ + CBaseEntity *pEntity; + CBaseMonster *pGrunt; + + TraceResult tr; + UTIL_TraceLine( vecSrc, vecSrc + Vector( 0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr); + if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) + return NULL; + + for (int i = 0; i < m_iUnits; i++) + { + if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) + { + if (m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal) + { + m_hGrunt[i]->SUB_StartFadeOut( ); + } + pEntity = Create( "monster_human_grunt", vecSrc, pev->angles ); + pGrunt = pEntity->MyMonsterPointer( ); + pGrunt->pev->movetype = MOVETYPE_FLY; + pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); + pGrunt->SetActivity( ACT_GLIDE ); + + CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); + pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt->entindex() ); + pBeam->SetFlags( BEAM_FSOLID ); + pBeam->SetColor( 255, 255, 255 ); + pBeam->SetThink( &COsprey::SUB_Remove ); + pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; + + // ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z ); + pGrunt->m_vecLastPosition = m_vecOrigin[i]; + m_hGrunt[i] = pGrunt; + return pGrunt; + } + } + // ALERT( at_console, "none dead\n"); + return NULL; +} + + +void COsprey :: HoverThink( void ) +{ + int i; + for (i = 0; i < 4; i++) + { + if (m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && !(m_hRepel[i]->pev->flags & FL_ONGROUND)) + { + break; + } + } + + if (i == 4) + { + m_startTime = gpGlobals->time; + SetThink( &COsprey::FlyThink ); + } + + pev->nextthink = gpGlobals->time + 0.1; + UTIL_MakeAimVectors( pev->angles ); + ShowDamage( ); +} + + +void COsprey::UpdateGoal( ) +{ + if (m_pGoalEnt) + { + m_pos1 = m_pos2; + m_ang1 = m_ang2; + m_vel1 = m_vel2; + m_pos2 = m_pGoalEnt->pev->origin; + m_ang2 = m_pGoalEnt->pev->angles; + UTIL_MakeAimVectors( Vector( 0, m_ang2.y, 0 ) ); + m_vel2 = gpGlobals->v_forward * m_pGoalEnt->pev->speed; + + m_startTime = m_startTime + m_dTime; + m_dTime = 2.0 * (m_pos1 - m_pos2).Length() / (m_vel1.Length() + m_pGoalEnt->pev->speed); + + if (m_ang1.y - m_ang2.y < -180) + { + m_ang1.y += 360; + } + else if (m_ang1.y - m_ang2.y > 180) + { + m_ang1.y -= 360; + } + + if (m_pGoalEnt->pev->speed < 400) + m_flIdealtilt = 0; + else + m_flIdealtilt = -90; + } + else + { + ALERT( at_console, "osprey missing target"); + } +} + + +void COsprey::FlyThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target + { + m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( pev->target ) ) ); + UpdateGoal( ); + } + + if (gpGlobals->time > m_startTime + m_dTime) + { + if (m_pGoalEnt->pev->speed == 0) + { + SetThink( &COsprey::DeployThink ); + } + do { + m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( m_pGoalEnt->pev->target ) ) ); + } while (m_pGoalEnt->pev->speed < 400 && !HasDead()); + UpdateGoal( ); + } + + Flight( ); + ShowDamage( ); +} + + +void COsprey::Flight( ) +{ + float t = (gpGlobals->time - m_startTime); + float scale = 1.0 / m_dTime; + + float f = UTIL_SplineFraction( t * scale, 1.0 ); + + Vector pos = (m_pos1 + m_vel1 * t) * (1.0 - f) + (m_pos2 - m_vel2 * (m_dTime - t)) * f; + Vector ang = (m_ang1) * (1.0 - f) + (m_ang2) * f; + m_velocity = m_vel1 * (1.0 - f) + m_vel2 * f; + + UTIL_SetOrigin( pev, pos ); + pev->angles = ang; + UTIL_MakeAimVectors( pev->angles ); + float flSpeed = DotProduct( gpGlobals->v_forward, m_velocity ); + + // float flSpeed = DotProduct( gpGlobals->v_forward, pev->velocity ); + + float m_flIdealtilt = (160 - flSpeed) / 10.0; + + // ALERT( at_console, "%f %f\n", flSpeed, flIdealtilt ); + if (m_flRotortilt < m_flIdealtilt) + { + m_flRotortilt += 0.5; + if (m_flRotortilt > 0) + m_flRotortilt = 0; + } + if (m_flRotortilt > m_flIdealtilt) + { + m_flRotortilt -= 0.5; + if (m_flRotortilt < -90) + m_flRotortilt = -90; + } + SetBoneController( 0, m_flRotortilt ); + + + if (m_iSoundState == 0) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, 0, 110 ); + // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); + + m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions + } + else + { + CBaseEntity *pPlayer = NULL; + + pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); + // UNDONE: this needs to send different sounds to every player for multiplayer. + if (pPlayer) + { + float pitch = DotProduct( m_velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); + + pitch = (int)(100 + pitch / 75.0); + + if (pitch > 250) + pitch = 250; + if (pitch < 50) + pitch = 50; + + if (pitch == 100) + pitch = 101; + + if (pitch != m_iPitch) + { + m_iPitch = pitch; + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); + // ALERT( at_console, "%.0f\n", pitch ); + } + } + // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); + } + +} + + +void COsprey::HitTouch( CBaseEntity *pOther ) +{ + pev->nextthink = gpGlobals->time + 2.0; +} + + +/* +int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + if (m_flRotortilt <= -90) + { + m_flRotortilt = 0; + } + else + { + m_flRotortilt -= 45; + } + SetBoneController( 0, m_flRotortilt ); + return 0; +} +*/ + + + +void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->movetype = MOVETYPE_TOSS; + pev->gravity = 0.3; + pev->velocity = m_velocity; + pev->avelocity = Vector( RANDOM_FLOAT( -20, 20 ), 0, RANDOM_FLOAT( -50, 50 ) ); + STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" ); + + UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); + SetThink( &COsprey::DyingThink ); + SetTouch( &COsprey::CrashTouch ); + pev->nextthink = gpGlobals->time + 0.1; + pev->health = 0; + pev->takedamage = DAMAGE_NO; + + m_startTime = gpGlobals->time + 4.0; +} + +void COsprey::CrashTouch( CBaseEntity *pOther ) +{ + // only crash if we hit something solid + if ( pOther->pev->solid == SOLID_BSP) + { + SetTouch( NULL ); + m_startTime = gpGlobals->time; + pev->nextthink = gpGlobals->time; + m_velocity = pev->velocity; + } +} + + +void COsprey :: DyingThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + pev->avelocity = pev->avelocity * 1.02; + + // still falling? + if (m_startTime > gpGlobals->time ) + { + UTIL_MakeAimVectors( pev->angles ); + ShowDamage( ); + + Vector vecSpot = pev->origin + pev->velocity * 0.2; + + // random explosions + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now + WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 )); + WRITE_SHORT( g_sModelIndexFireball ); + WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + + // lots of smoke + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 )); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 100 ); // scale * 10 + WRITE_BYTE( 10 ); // framerate + MESSAGE_END(); + + + vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_BREAKMODEL); + + // position + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z ); + + // size + WRITE_COORD( 800 ); + WRITE_COORD( 800 ); + WRITE_COORD( 132 ); + + // velocity + WRITE_COORD( pev->velocity.x ); + WRITE_COORD( pev->velocity.y ); + WRITE_COORD( pev->velocity.z ); + + // randomization + WRITE_BYTE( 50 ); + + // Model + WRITE_SHORT( m_iTailGibs ); //model id# + + // # of shards + WRITE_BYTE( 8 ); // let client decide + + // duration + WRITE_BYTE( 200 );// 10.0 seconds + + // flags + + WRITE_BYTE( BREAK_METAL ); + MESSAGE_END(); + + + + // don't stop it we touch a entity + pev->flags &= ~FL_ONGROUND; + pev->nextthink = gpGlobals->time + 0.2; + return; + } + else + { + Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + + /* + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 512 ); + WRITE_SHORT( m_iExplode ); + WRITE_BYTE( 250 ); // scale * 10 + WRITE_BYTE( 10 ); // framerate + MESSAGE_END(); + */ + + // gibs + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_SPRITE ); + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 512 ); + WRITE_SHORT( m_iExplode ); + WRITE_BYTE( 250 ); // scale * 10 + WRITE_BYTE( 255 ); // brightness + MESSAGE_END(); + + /* + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 300 ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 250 ); // scale * 10 + WRITE_BYTE( 6 ); // framerate + MESSAGE_END(); + */ + + // blast circle + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_BEAMCYLINDER ); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z); + WRITE_COORD( pev->origin.x); + WRITE_COORD( pev->origin.y); + WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds + WRITE_SHORT( m_iSpriteTexture ); + WRITE_BYTE( 0 ); // startframe + WRITE_BYTE( 0 ); // framerate + WRITE_BYTE( 4 ); // life + WRITE_BYTE( 32 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 192 ); // r, g, b + WRITE_BYTE( 128 ); // brightness + WRITE_BYTE( 0 ); // speed + MESSAGE_END(); + + EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); + + RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); + + // gibs + vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecSpot ); + WRITE_BYTE( TE_BREAKMODEL); + + // position + WRITE_COORD( vecSpot.x ); + WRITE_COORD( vecSpot.y ); + WRITE_COORD( vecSpot.z + 64); + + // size + WRITE_COORD( 800 ); + WRITE_COORD( 800 ); + WRITE_COORD( 128 ); + + // velocity + WRITE_COORD( m_velocity.x ); + WRITE_COORD( m_velocity.y ); + WRITE_COORD( fabs( m_velocity.z ) * 0.25 ); + + // randomization + WRITE_BYTE( 40 ); + + // Model + WRITE_SHORT( m_iBodyGibs ); //model id# + + // # of shards + WRITE_BYTE( 128 ); + + // duration + WRITE_BYTE( 200 );// 10.0 seconds + + // flags + + WRITE_BYTE( BREAK_METAL ); + MESSAGE_END(); + + UTIL_Remove( this ); + } +} + + +void COsprey :: ShowDamage( void ) +{ + if (m_iDoLeftSmokePuff > 0 || RANDOM_LONG(0,99) > m_flLeftHealth) + { + Vector vecSrc = pev->origin + gpGlobals->v_right * -340; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSrc.x ); + WRITE_COORD( vecSrc.y ); + WRITE_COORD( vecSrc.z ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + MESSAGE_END(); + if (m_iDoLeftSmokePuff > 0) + m_iDoLeftSmokePuff--; + } + if (m_iDoRightSmokePuff > 0 || RANDOM_LONG(0,99) > m_flRightHealth) + { + Vector vecSrc = pev->origin + gpGlobals->v_right * 340; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSrc.x ); + WRITE_COORD( vecSrc.y ); + WRITE_COORD( vecSrc.z ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + MESSAGE_END(); + if (m_iDoRightSmokePuff > 0) + m_iDoRightSmokePuff--; + } +} + + +void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); + + // only so much per engine + if (ptr->iHitgroup == 3) + { + if (m_flRightHealth < 0) + return; + else + m_flRightHealth -= flDamage; + m_iDoLeftSmokePuff = 3 + (flDamage / 5.0); + } + + if (ptr->iHitgroup == 2) + { + if (m_flLeftHealth < 0) + return; + else + m_flLeftHealth -= flDamage; + m_iDoRightSmokePuff = 3 + (flDamage / 5.0); + } + + // hit hard, hits cockpit, hits engines + if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3) + { + // ALERT( at_console, "%.0f\n", flDamage ); + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + } + else + { + UTIL_Sparks( ptr->vecEndPos ); + } +} + + + + + diff --git a/main/source/dlls/pathcorner.cpp b/main/source/dlls/pathcorner.cpp index f8cc66b3..e8b67b59 100644 --- a/main/source/dlls/pathcorner.cpp +++ b/main/source/dlls/pathcorner.cpp @@ -1,428 +1,428 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// ========================== PATH_CORNER =========================== -// - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "trains.h" -#include "saverestore.h" - -class CPathCorner : public CPointEntity -{ -public: - void Spawn( ); - void KeyValue( KeyValueData* pkvd ); - float GetDelay( void ) { return m_flWait; } -// void Touch( CBaseEntity *pOther ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - float m_flWait; -}; - -LINK_ENTITY_TO_CLASS( path_corner, CPathCorner ); - -// Global Savedata for Delay -TYPEDESCRIPTION CPathCorner::m_SaveData[] = -{ - DEFINE_FIELD( CPathCorner, m_flWait, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity ); - -// -// Cache user-entity-field values until spawn is called. -// -void CPathCorner :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CPathCorner :: Spawn( ) -{ - ASSERTSZ(!FStringNull(pev->targetname), "path_corner without a targetname"); -} - -#if 0 -void CPathCorner :: Touch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - if ( FBitSet ( pevToucher->flags, FL_MONSTER ) ) - {// monsters don't navigate path corners based on touch anymore - return; - } - - // If OTHER isn't explicitly looking for this path_corner, bail out - if ( pOther->m_pGoalEnt != this ) - { - return; - } - - // If OTHER has an enemy, this touch is incidental, ignore - if ( !FNullEnt(pevToucher->enemy) ) - { - return; // fighting, not following a path - } - - // UNDONE: support non-zero flWait - /* - if (m_flWait != 0) - ALERT(at_warning, "Non-zero path-cornder waits NYI"); - */ - - // Find the next "stop" on the path, make it the goal of the "toucher". - if (FStringNull(pev->target)) - { - ALERT(at_warning, "PathCornerTouch: no next stop specified"); - } - - pOther->m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ) ); - - // If "next spot" was not found (does not exist - level design error) - if ( !pOther->m_pGoalEnt ) - { - ALERT(at_console, "PathCornerTouch--%s couldn't find next stop in path: %s", STRING(pev->classname), STRING(pev->target)); - return; - } - - // Turn towards the next stop in the path. - pevToucher->ideal_yaw = UTIL_VecToYaw ( pOther->m_pGoalEnt->pev->origin - pevToucher->origin ); -} -#endif - - - -TYPEDESCRIPTION CPathTrack::m_SaveData[] = -{ - DEFINE_FIELD( CPathTrack, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CPathTrack, m_pnext, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_paltpath, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_pprevious, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_altName, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity ); -LINK_ENTITY_TO_CLASS( path_track, CPathTrack ); - -// -// Cache user-entity-field values until spawn is called. -// -void CPathTrack :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "altpath")) - { - m_altName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int on; - - // Use toggles between two paths - if ( m_paltpath ) - { - on = !FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ); - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - SetBits( pev->spawnflags, SF_PATH_ALTERNATE ); - else - ClearBits( pev->spawnflags, SF_PATH_ALTERNATE ); - } - } - else // Use toggles between enabled/disabled - { - on = !FBitSet( pev->spawnflags, SF_PATH_DISABLED ); - - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - SetBits( pev->spawnflags, SF_PATH_DISABLED ); - else - ClearBits( pev->spawnflags, SF_PATH_DISABLED ); - } - } -} - - -void CPathTrack :: Link( void ) -{ - edict_t *pentTarget; - - if ( !FStringNull(pev->target) ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); - if ( !FNullEnt(pentTarget) ) - { - m_pnext = CPathTrack::Instance( pentTarget ); - - if ( m_pnext ) // If no next pointer, this is the end of a path - { - m_pnext->SetPrevious( this ); - } - } - else - ALERT( at_console, "Dead end link %s\n", STRING(pev->target) ); - } - - // Find "alternate" path - if ( m_altName ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_altName) ); - if ( !FNullEnt(pentTarget) ) - { - m_paltpath = CPathTrack::Instance( pentTarget ); - - if ( m_paltpath ) // If no next pointer, this is the end of a path - { - m_paltpath->SetPrevious( this ); - } - } - } -} - - -void CPathTrack :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - - m_pnext = NULL; - m_pprevious = NULL; -// DEBUGGING CODE -#if PATH_SPARKLE_DEBUG - SetThink( &CPathTrack::Sparkle ); - pev->nextthink = gpGlobals->time + 0.5; -#endif -} - - -void CPathTrack::Activate( void ) -{ - if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link - Link(); -} - -CPathTrack *CPathTrack :: ValidPath( CPathTrack *ppath, int testFlag ) -{ - if ( !ppath ) - return NULL; - - if ( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) ) - return NULL; - - return ppath; -} - - -void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ) -{ - if ( pstart && pend ) - { - Vector dir = (pend->pev->origin - pstart->pev->origin); - dir = dir.Normalize(); - *origin = pend->pev->origin + dir * dist; - } -} - -CPathTrack *CPathTrack::GetNext( void ) -{ - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) - return m_paltpath; - - return m_pnext; -} - - - -CPathTrack *CPathTrack::GetPrevious( void ) -{ - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) - return m_paltpath; - - return m_pprevious; -} - - - -void CPathTrack::SetPrevious( CPathTrack *pprev ) -{ - // Only set previous if this isn't my alternate path - if ( pprev && !FStrEq( STRING(pprev->pev->targetname), STRING(m_altName) ) ) - m_pprevious = pprev; -} - - -// Assumes this is ALWAYS enabled -CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) -{ - CPathTrack *pcurrent; - float originalDist = dist; - - pcurrent = this; - Vector currentPos = *origin; - - if ( dist < 0 ) // Travelling backwards through path - { - dist = -dist; - while ( dist > 0 ) - { - Vector dir = pcurrent->pev->origin - currentPos; - float length = dir.Length(); - if ( !length ) - { - if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. - { - if ( !move ) - Project( pcurrent->GetNext(), pcurrent, origin, dist ); - return NULL; - } - pcurrent = pcurrent->GetPrevious(); - } - else if ( length > dist ) // enough left in this path to move - { - *origin = currentPos + (dir * (dist / length)); - return pcurrent; - } - else - { - dist -= length; - currentPos = pcurrent->pev->origin; - *origin = currentPos; - if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. - return NULL; - - pcurrent = pcurrent->GetPrevious(); - } - } - *origin = currentPos; - return pcurrent; - } - else - { - while ( dist > 0 ) - { - if ( !ValidPath(pcurrent->GetNext(), move) ) // If there is no next node, or it's disabled, return now. - { - if ( !move ) - Project( pcurrent->GetPrevious(), pcurrent, origin, dist ); - return NULL; - } - Vector dir = pcurrent->GetNext()->pev->origin - currentPos; - float length = dir.Length(); - if ( !length && !ValidPath( pcurrent->GetNext()->GetNext(), move ) ) - { - if ( dist == originalDist ) // HACK -- up against a dead end - return NULL; - return pcurrent; - } - if ( length > dist ) // enough left in this path to move - { - *origin = currentPos + (dir * (dist / length)); - return pcurrent; - } - else - { - dist -= length; - currentPos = pcurrent->GetNext()->pev->origin; - pcurrent = pcurrent->GetNext(); - *origin = currentPos; - } - } - *origin = currentPos; - } - - return pcurrent; -} - - -// Assumes this is ALWAYS enabled -CPathTrack *CPathTrack :: Nearest( Vector origin ) -{ - int deadCount; - float minDist, dist; - Vector delta; - CPathTrack *ppath, *pnearest; - - - delta = origin - pev->origin; - delta.z = 0; - minDist = delta.Length(); - pnearest = this; - ppath = GetNext(); - - // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :) - deadCount = 0; - while ( ppath && ppath != this ) - { - deadCount++; - if ( deadCount > 9999 ) - { - ALERT( at_error, "Bad sequence of path_tracks from %s", STRING(pev->targetname) ); - return NULL; - } - delta = origin - ppath->pev->origin; - delta.z = 0; - dist = delta.Length(); - if ( dist < minDist ) - { - minDist = dist; - pnearest = ppath; - } - ppath = ppath->GetNext(); - } - return pnearest; -} - - -CPathTrack *CPathTrack::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "path_track" ) ) - return (CPathTrack *)GET_PRIVATE(pent); - return NULL; -} - - - // DEBUGGING CODE -#if PATH_SPARKLE_DEBUG -void CPathTrack :: Sparkle( void ) -{ - - pev->nextthink = gpGlobals->time + 0.2; - if ( FBitSet( pev->spawnflags, SF_PATH_DISABLED ) ) - UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 210, 10); - else - UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 84, 10); -} -#endif - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// ========================== PATH_CORNER =========================== +// + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "trains.h" +#include "saverestore.h" + +class CPathCorner : public CPointEntity +{ +public: + void Spawn( ); + void KeyValue( KeyValueData* pkvd ); + float GetDelay( void ) { return m_flWait; } +// void Touch( CBaseEntity *pOther ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + float m_flWait; +}; + +LINK_ENTITY_TO_CLASS( path_corner, CPathCorner ); + +// Global Savedata for Delay +TYPEDESCRIPTION CPathCorner::m_SaveData[] = +{ + DEFINE_FIELD( CPathCorner, m_flWait, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity ); + +// +// Cache user-entity-field values until spawn is called. +// +void CPathCorner :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "wait")) + { + m_flWait = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + + +void CPathCorner :: Spawn( ) +{ + ASSERTSZ(!FStringNull(pev->targetname), "path_corner without a targetname"); +} + +#if 0 +void CPathCorner :: Touch( CBaseEntity *pOther ) +{ + entvars_t* pevToucher = pOther->pev; + + if ( FBitSet ( pevToucher->flags, FL_MONSTER ) ) + {// monsters don't navigate path corners based on touch anymore + return; + } + + // If OTHER isn't explicitly looking for this path_corner, bail out + if ( pOther->m_pGoalEnt != this ) + { + return; + } + + // If OTHER has an enemy, this touch is incidental, ignore + if ( !FNullEnt(pevToucher->enemy) ) + { + return; // fighting, not following a path + } + + // UNDONE: support non-zero flWait + /* + if (m_flWait != 0) + ALERT(at_warning, "Non-zero path-cornder waits NYI"); + */ + + // Find the next "stop" on the path, make it the goal of the "toucher". + if (FStringNull(pev->target)) + { + ALERT(at_warning, "PathCornerTouch: no next stop specified"); + } + + pOther->m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ) ); + + // If "next spot" was not found (does not exist - level design error) + if ( !pOther->m_pGoalEnt ) + { + ALERT(at_console, "PathCornerTouch--%s couldn't find next stop in path: %s", STRING(pev->classname), STRING(pev->target)); + return; + } + + // Turn towards the next stop in the path. + pevToucher->ideal_yaw = UTIL_VecToYaw ( pOther->m_pGoalEnt->pev->origin - pevToucher->origin ); +} +#endif + + + +TYPEDESCRIPTION CPathTrack::m_SaveData[] = +{ + DEFINE_FIELD( CPathTrack, m_length, FIELD_FLOAT ), + DEFINE_FIELD( CPathTrack, m_pnext, FIELD_CLASSPTR ), + DEFINE_FIELD( CPathTrack, m_paltpath, FIELD_CLASSPTR ), + DEFINE_FIELD( CPathTrack, m_pprevious, FIELD_CLASSPTR ), + DEFINE_FIELD( CPathTrack, m_altName, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity ); +LINK_ENTITY_TO_CLASS( path_track, CPathTrack ); + +// +// Cache user-entity-field values until spawn is called. +// +void CPathTrack :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "altpath")) + { + m_altName = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int on; + + // Use toggles between two paths + if ( m_paltpath ) + { + on = !FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ); + if ( ShouldToggle( useType, on ) ) + { + if ( on ) + SetBits( pev->spawnflags, SF_PATH_ALTERNATE ); + else + ClearBits( pev->spawnflags, SF_PATH_ALTERNATE ); + } + } + else // Use toggles between enabled/disabled + { + on = !FBitSet( pev->spawnflags, SF_PATH_DISABLED ); + + if ( ShouldToggle( useType, on ) ) + { + if ( on ) + SetBits( pev->spawnflags, SF_PATH_DISABLED ); + else + ClearBits( pev->spawnflags, SF_PATH_DISABLED ); + } + } +} + + +void CPathTrack :: Link( void ) +{ + edict_t *pentTarget; + + if ( !FStringNull(pev->target) ) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); + if ( !FNullEnt(pentTarget) ) + { + m_pnext = CPathTrack::Instance( pentTarget ); + + if ( m_pnext ) // If no next pointer, this is the end of a path + { + m_pnext->SetPrevious( this ); + } + } + else + ALERT( at_console, "Dead end link %s\n", STRING(pev->target) ); + } + + // Find "alternate" path + if ( m_altName ) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_altName) ); + if ( !FNullEnt(pentTarget) ) + { + m_paltpath = CPathTrack::Instance( pentTarget ); + + if ( m_paltpath ) // If no next pointer, this is the end of a path + { + m_paltpath->SetPrevious( this ); + } + } + } +} + + +void CPathTrack :: Spawn( void ) +{ + pev->solid = SOLID_TRIGGER; + UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); + + m_pnext = NULL; + m_pprevious = NULL; +// DEBUGGING CODE +#if PATH_SPARKLE_DEBUG + SetThink( &CPathTrack::Sparkle ); + pev->nextthink = gpGlobals->time + 0.5; +#endif +} + + +void CPathTrack::Activate( void ) +{ + if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link + Link(); +} + +CPathTrack *CPathTrack :: ValidPath( CPathTrack *ppath, int testFlag ) +{ + if ( !ppath ) + return NULL; + + if ( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) ) + return NULL; + + return ppath; +} + + +void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ) +{ + if ( pstart && pend ) + { + Vector dir = (pend->pev->origin - pstart->pev->origin); + dir = dir.Normalize(); + *origin = pend->pev->origin + dir * dist; + } +} + +CPathTrack *CPathTrack::GetNext( void ) +{ + if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) + return m_paltpath; + + return m_pnext; +} + + + +CPathTrack *CPathTrack::GetPrevious( void ) +{ + if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) + return m_paltpath; + + return m_pprevious; +} + + + +void CPathTrack::SetPrevious( CPathTrack *pprev ) +{ + // Only set previous if this isn't my alternate path + if ( pprev && !FStrEq( STRING(pprev->pev->targetname), STRING(m_altName) ) ) + m_pprevious = pprev; +} + + +// Assumes this is ALWAYS enabled +CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) +{ + CPathTrack *pcurrent; + float originalDist = dist; + + pcurrent = this; + Vector currentPos = *origin; + + if ( dist < 0 ) // Travelling backwards through path + { + dist = -dist; + while ( dist > 0 ) + { + Vector dir = pcurrent->pev->origin - currentPos; + float length = dir.Length(); + if ( !length ) + { + if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. + { + if ( !move ) + Project( pcurrent->GetNext(), pcurrent, origin, dist ); + return NULL; + } + pcurrent = pcurrent->GetPrevious(); + } + else if ( length > dist ) // enough left in this path to move + { + *origin = currentPos + (dir * (dist / length)); + return pcurrent; + } + else + { + dist -= length; + currentPos = pcurrent->pev->origin; + *origin = currentPos; + if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. + return NULL; + + pcurrent = pcurrent->GetPrevious(); + } + } + *origin = currentPos; + return pcurrent; + } + else + { + while ( dist > 0 ) + { + if ( !ValidPath(pcurrent->GetNext(), move) ) // If there is no next node, or it's disabled, return now. + { + if ( !move ) + Project( pcurrent->GetPrevious(), pcurrent, origin, dist ); + return NULL; + } + Vector dir = pcurrent->GetNext()->pev->origin - currentPos; + float length = dir.Length(); + if ( !length && !ValidPath( pcurrent->GetNext()->GetNext(), move ) ) + { + if ( dist == originalDist ) // HACK -- up against a dead end + return NULL; + return pcurrent; + } + if ( length > dist ) // enough left in this path to move + { + *origin = currentPos + (dir * (dist / length)); + return pcurrent; + } + else + { + dist -= length; + currentPos = pcurrent->GetNext()->pev->origin; + pcurrent = pcurrent->GetNext(); + *origin = currentPos; + } + } + *origin = currentPos; + } + + return pcurrent; +} + + +// Assumes this is ALWAYS enabled +CPathTrack *CPathTrack :: Nearest( Vector origin ) +{ + int deadCount; + float minDist, dist; + Vector delta; + CPathTrack *ppath, *pnearest; + + + delta = origin - pev->origin; + delta.z = 0; + minDist = delta.Length(); + pnearest = this; + ppath = GetNext(); + + // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :) + deadCount = 0; + while ( ppath && ppath != this ) + { + deadCount++; + if ( deadCount > 9999 ) + { + ALERT( at_error, "Bad sequence of path_tracks from %s", STRING(pev->targetname) ); + return NULL; + } + delta = origin - ppath->pev->origin; + delta.z = 0; + dist = delta.Length(); + if ( dist < minDist ) + { + minDist = dist; + pnearest = ppath; + } + ppath = ppath->GetNext(); + } + return pnearest; +} + + +CPathTrack *CPathTrack::Instance( edict_t *pent ) +{ + if ( FClassnameIs( pent, "path_track" ) ) + return (CPathTrack *)GET_PRIVATE(pent); + return NULL; +} + + + // DEBUGGING CODE +#if PATH_SPARKLE_DEBUG +void CPathTrack :: Sparkle( void ) +{ + + pev->nextthink = gpGlobals->time + 0.2; + if ( FBitSet( pev->spawnflags, SF_PATH_DISABLED ) ) + UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 210, 10); + else + UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 84, 10); +} +#endif + diff --git a/main/source/dlls/plane.cpp b/main/source/dlls/plane.cpp index c96bf464..3c1b8755 100644 --- a/main/source/dlls/plane.cpp +++ b/main/source/dlls/plane.cpp @@ -1,60 +1,60 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "plane.h" - -//========================================================= -// Plane -//========================================================= -CPlane :: CPlane ( void ) -{ - m_fInitialized = FALSE; -} - -//========================================================= -// InitializePlane - Takes a normal for the plane and a -// point on the plane and -//========================================================= -void CPlane :: InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ) -{ - m_vecNormal = vecNormal; - m_flDist = DotProduct ( m_vecNormal, vecPoint ); - m_fInitialized = TRUE; -} - - -//========================================================= -// PointInFront - determines whether the given vector is -// in front of the plane. -//========================================================= -BOOL CPlane :: PointInFront ( const Vector &vecPoint ) -{ - float flFace; - - if ( !m_fInitialized ) - { - return FALSE; - } - - flFace = DotProduct ( m_vecNormal, vecPoint ) - m_flDist; - - if ( flFace >= 0 ) - { - return TRUE; - } - - return FALSE; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "plane.h" + +//========================================================= +// Plane +//========================================================= +CPlane :: CPlane ( void ) +{ + m_fInitialized = FALSE; +} + +//========================================================= +// InitializePlane - Takes a normal for the plane and a +// point on the plane and +//========================================================= +void CPlane :: InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ) +{ + m_vecNormal = vecNormal; + m_flDist = DotProduct ( m_vecNormal, vecPoint ); + m_fInitialized = TRUE; +} + + +//========================================================= +// PointInFront - determines whether the given vector is +// in front of the plane. +//========================================================= +BOOL CPlane :: PointInFront ( const Vector &vecPoint ) +{ + float flFace; + + if ( !m_fInitialized ) + { + return FALSE; + } + + flFace = DotProduct ( m_vecNormal, vecPoint ) - m_flDist; + + if ( flFace >= 0 ) + { + return TRUE; + } + + return FALSE; +} + diff --git a/main/source/dlls/plane.h b/main/source/dlls/plane.h index ea2aa336..91ea67ea 100644 --- a/main/source/dlls/plane.h +++ b/main/source/dlls/plane.h @@ -1,43 +1,43 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLANE_H -#define PLANE_H - -//========================================================= -// Plane -//========================================================= -class CPlane -{ -public: - CPlane ( void ); - - //========================================================= - // InitializePlane - Takes a normal for the plane and a - // point on the plane and - //========================================================= - void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ); - - //========================================================= - // PointInFront - determines whether the given vector is - // in front of the plane. - //========================================================= - BOOL PointInFront ( const Vector &vecPoint ); - - Vector m_vecNormal; - float m_flDist; - BOOL m_fInitialized; -}; - -#endif // PLANE_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PLANE_H +#define PLANE_H + +//========================================================= +// Plane +//========================================================= +class CPlane +{ +public: + CPlane ( void ); + + //========================================================= + // InitializePlane - Takes a normal for the plane and a + // point on the plane and + //========================================================= + void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ); + + //========================================================= + // PointInFront - determines whether the given vector is + // in front of the plane. + //========================================================= + BOOL PointInFront ( const Vector &vecPoint ); + + Vector m_vecNormal; + float m_flDist; + BOOL m_fInitialized; +}; + +#endif // PLANE_H diff --git a/main/source/dlls/plats.cpp b/main/source/dlls/plats.cpp index 6cb30ce3..9ff0ca82 100644 --- a/main/source/dlls/plats.cpp +++ b/main/source/dlls/plats.cpp @@ -1,2266 +1,2266 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== plats.cpp ======================================================== - - spawn, think, and touch functions for trains, etc - -*/ - -//#include "extdll.h" -//#include "util.h" -//#include "cbase.h" -//#include "trains.h" -//#include "saverestore.h" -#include -#include "plats.h" - -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform); - -TYPEDESCRIPTION CBasePlatTrain::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlatTrain, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBasePlatTrain, m_bStopSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBasePlatTrain, m_volume, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBasePlatTrain, CBaseToggle ); - -void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lip")) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_flHeight = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotation")) - { - m_vecFinalAngle.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - m_volume = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -#define noiseMoving noise -#define noiseArrived noise1 - -void CBasePlatTrain::Precache( void ) -{ -// set the plat's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = MAKE_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("plats/bigmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove1.wav"); - break; - case 2: - PRECACHE_SOUND ("plats/bigmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove2.wav"); - break; - case 3: - PRECACHE_SOUND ("plats/elevmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove1.wav"); - break; - case 4: - PRECACHE_SOUND ("plats/elevmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove2.wav"); - break; - case 5: - PRECACHE_SOUND ("plats/elevmove3.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove3.wav"); - break; - case 6: - PRECACHE_SOUND ("plats/freightmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/freightmove1.wav"); - break; - case 7: - PRECACHE_SOUND ("plats/freightmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/freightmove2.wav"); - break; - case 8: - PRECACHE_SOUND ("plats/heavymove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/heavymove1.wav"); - break; - case 9: - PRECACHE_SOUND ("plats/rackmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/rackmove1.wav"); - break; - case 10: - PRECACHE_SOUND ("plats/railmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/railmove1.wav"); - break; - case 11: - PRECACHE_SOUND ("plats/squeekmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/squeekmove1.wav"); - break; - case 12: - PRECACHE_SOUND ("plats/talkmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/talkmove1.wav"); - break; - case 13: - PRECACHE_SOUND ("plats/talkmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/talkmove2.wav"); - break; - default: - pev->noiseMoving = MAKE_STRING("common/null.wav"); - break; - } - -// set the plat's 'reached destination' stop sound - switch (m_bStopSnd) - { - case 0: - pev->noiseArrived = MAKE_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("plats/bigstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop1.wav"); - break; - case 2: - PRECACHE_SOUND ("plats/bigstop2.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop2.wav"); - break; - case 3: - PRECACHE_SOUND ("plats/freightstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/freightstop1.wav"); - break; - case 4: - PRECACHE_SOUND ("plats/heavystop2.wav"); - pev->noiseArrived = MAKE_STRING("plats/heavystop2.wav"); - break; - case 5: - PRECACHE_SOUND ("plats/rackstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/rackstop1.wav"); - break; - case 6: - PRECACHE_SOUND ("plats/railstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/railstop1.wav"); - break; - case 7: - PRECACHE_SOUND ("plats/squeekstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/squeekstop1.wav"); - break; - case 8: - PRECACHE_SOUND ("plats/talkstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/talkstop1.wav"); - break; - - default: - pev->noiseArrived = MAKE_STRING("common/null.wav"); - break; - } -} - -// -//====================== PLAT code ==================================================== -// - - -#define noiseMovement noise -#define noiseStopMoving noise1 - -class CFuncPlat : public CBasePlatTrain -{ -public: - void Spawn( void ); - void Precache( void ); - void Setup( void ); - - virtual void Blocked( CBaseEntity *pOther ); - - - void EXPORT PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void EXPORT CallGoDown( void ) { GoDown(); } - void EXPORT CallHitTop( void ) { HitTop(); } - void EXPORT CallHitBottom( void ) { HitBottom(); } - - virtual void GoUp( void ); - virtual void GoDown( void ); - virtual void HitTop( void ); - virtual void HitBottom( void ); -}; -LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ); - - -// UNDONE: Need to save this!!! It needs class & linkage -class CPlatTrigger : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } - void SpawnInsideTrigger( CFuncPlat *pPlatform ); - void Touch( CBaseEntity *pOther ); - CFuncPlat *m_pPlatform; -}; - - - -/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER -speed default 150 - -Plats are always drawn in the extended position, so they will light correctly. - -If the plat is the target of another trigger or button, it will start out disabled in -the extended position until it is trigger, when it will lower and become a normal plat. - -If the "height" key is set, that will determine the amount the plat moves, instead of -being implicitly determined by the model's height. - -Set "sounds" to one of the following: -1) base fast -2) chain slow -*/ - -void CFuncPlat :: Setup( void ) -{ - //pev->noiseMovement = MAKE_STRING("plats/platmove1.wav"); - //pev->noiseStopMoving = MAKE_STRING("plats/platstop1.wav"); - - if (m_flTLength == 0) - m_flTLength = 80; - if (m_flTWidth == 0) - m_flTWidth = 10; - - pev->angles = g_vecZero; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - // vecPosition1 is the top position, vecPosition2 is the bottom - m_vecPosition1 = pev->origin; - m_vecPosition2 = pev->origin; - if (m_flHeight != 0) - m_vecPosition2.z = pev->origin.z - m_flHeight; - else - m_vecPosition2.z = pev->origin.z - pev->size.z + 8; - if (pev->speed == 0) - pev->speed = 150; - - if ( m_volume == 0 ) - m_volume = 0.85; -} - - -void CFuncPlat :: Precache( ) -{ - CBasePlatTrain::Precache(); - //PRECACHE_SOUND("plats/platmove1.wav"); - //PRECACHE_SOUND("plats/platstop1.wav"); - if ( !IsTogglePlat() ) - PlatSpawnInsideTrigger( pev ); // the "start moving" trigger -} - - -void CFuncPlat :: Spawn( ) -{ - Setup(); - - Precache(); - - // If this platform is the target of some button, it starts at the TOP position, - // and is brought down by that button. Otherwise, it starts at BOTTOM. - if ( !FStringNull(pev->targetname) ) - { - UTIL_SetOrigin (pev, m_vecPosition1); - m_toggle_state = TS_AT_TOP; - SetUse( &CFuncPlat::PlatUse ); - } - else - { - UTIL_SetOrigin (pev, m_vecPosition2); - m_toggle_state = TS_AT_BOTTOM; - } -} - - - -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform) -{ - GetClassPtr( (CPlatTrigger *)NULL)->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); -} - - -// -// Create a trigger entity for a platform. -// -void CPlatTrigger :: SpawnInsideTrigger( CFuncPlat *pPlatform ) -{ - m_pPlatform = pPlatform; - // Create trigger entity, "point" it at the owning platform, give it a touch method - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->origin = pPlatform->pev->origin; - - // Establish the trigger field's size - Vector vecTMin = m_pPlatform->pev->mins + Vector ( 25 , 25 , 0 ); - Vector vecTMax = m_pPlatform->pev->maxs + Vector ( 25 , 25 , 8 ); - vecTMin.z = vecTMax.z - ( m_pPlatform->m_vecPosition1.z - m_pPlatform->m_vecPosition2.z + 8 ); - if (m_pPlatform->pev->size.x <= 50) - { - vecTMin.x = (m_pPlatform->pev->mins.x + m_pPlatform->pev->maxs.x) / 2; - vecTMax.x = vecTMin.x + 1; - } - if (m_pPlatform->pev->size.y <= 50) - { - vecTMin.y = (m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y) / 2; - vecTMax.y = vecTMin.y + 1; - } - UTIL_SetSize ( pev, vecTMin, vecTMax ); -} - - -// -// When the platform's trigger field is touched, the platform ??? -// -void CPlatTrigger :: Touch( CBaseEntity *pOther ) -{ - // Ignore touches by non-players - entvars_t* pevToucher = pOther->pev; - if ( !FClassnameIs (pevToucher, "player") ) - return; - - // Ignore touches by corpses - if (!pOther->IsAlive()) - return; - - // Make linked platform go up/down. - if (m_pPlatform->m_toggle_state == TS_AT_BOTTOM) - m_pPlatform->GoUp(); - else if (m_pPlatform->m_toggle_state == TS_AT_TOP) - m_pPlatform->pev->nextthink = m_pPlatform->pev->ltime + 1;// delay going down -} - - -// -// Used by SUB_UseTargets, when a platform is the target of a button. -// Start bringing platform down. -// -void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsTogglePlat() ) - { - // Top is off, bottom is on - BOOL on = (m_toggle_state == TS_AT_BOTTOM) ? TRUE : FALSE; - - if ( !ShouldToggle( useType, on ) ) - return; - - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else if ( m_toggle_state == TS_AT_BOTTOM ) - GoUp(); - } - else - { - SetUse( NULL ); - - if (m_toggle_state == TS_AT_TOP) - GoDown(); - } -} - - -// -// Platform is at top, now starts moving down. -// -void CFuncPlat :: GoDown( void ) -{ - if(pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_GOING_DOWN; - SetMoveDone(&CFuncPlat::CallHitBottom); - LinearMove(m_vecPosition2, pev->speed); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncPlat :: HitBottom( void ) -{ - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - if (pev->noiseStopMoving) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncPlat :: GoUp( void ) -{ - if (pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_GOING_UP; - SetMoveDone(&CFuncPlat::CallHitTop); - LinearMove(m_vecPosition1, pev->speed); -} - - -// -// Platform has hit top. Pauses, then starts back down again. -// -void CFuncPlat :: HitTop( void ) -{ - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - if (pev->noiseStopMoving) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_AT_TOP; - - if ( !IsTogglePlat() ) - { - // After a delay, the platform will automatically start going down again. - SetThink( &CFuncPlat::CallGoDown ); - pev->nextthink = pev->ltime + 3; - } -} - - -void CFuncPlat :: Blocked( CBaseEntity *pOther ) -{ - ALERT( at_aiconsole, "%s Blocked by %s\n", STRING(pev->classname), STRING(pOther->pev->classname) ); - // Hurt the blocker a little - pOther->TakeDamage(pev, pev, 1, DMG_CRUSH); - - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - // Send the platform back where it came from - ASSERT(m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN); - if (m_toggle_state == TS_GOING_UP) - GoDown(); - else if (m_toggle_state == TS_GOING_DOWN) - GoUp (); -} - - -class CFuncPlatRot : public CFuncPlat -{ -public: - void Spawn( void ); - void SetupRotation( void ); - - virtual void GoUp( void ); - virtual void GoDown( void ); - virtual void HitTop( void ); - virtual void HitBottom( void ); - - void RotMove( Vector &destAngle, float time ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - Vector m_end, m_start; -}; -LINK_ENTITY_TO_CLASS( func_platrot, CFuncPlatRot ); -TYPEDESCRIPTION CFuncPlatRot::m_SaveData[] = -{ - DEFINE_FIELD( CFuncPlatRot, m_end, FIELD_VECTOR ), - DEFINE_FIELD( CFuncPlatRot, m_start, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CFuncPlatRot, CFuncPlat ); - - -void CFuncPlatRot :: SetupRotation( void ) -{ - if ( m_vecFinalAngle.x != 0 ) // This plat rotates too! - { - CBaseToggle :: AxisDir( pev ); - m_start = pev->angles; - m_end = pev->angles + pev->movedir * m_vecFinalAngle.x; - } - else - { - m_start = g_vecZero; - m_end = g_vecZero; - } - if ( !FStringNull(pev->targetname) ) // Start at top - { - pev->angles = m_end; - } -} - - -void CFuncPlatRot :: Spawn( void ) -{ - CFuncPlat :: Spawn(); - SetupRotation(); -} - -void CFuncPlatRot :: GoDown( void ) -{ - CFuncPlat :: GoDown(); - RotMove( m_start, pev->nextthink - pev->ltime ); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncPlatRot :: HitBottom( void ) -{ - CFuncPlat :: HitBottom(); - pev->avelocity = g_vecZero; - pev->angles = m_start; -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncPlatRot :: GoUp( void ) -{ - CFuncPlat :: GoUp(); - RotMove( m_end, pev->nextthink - pev->ltime ); -} - - -// -// Platform has hit top. Pauses, then starts back down again. -// -void CFuncPlatRot :: HitTop( void ) -{ - CFuncPlat :: HitTop(); - pev->avelocity = g_vecZero; - pev->angles = m_end; -} - - -void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) -{ - // set destdelta to the vector needed to move - Vector vecDestDelta = destAngle - pev->angles; - - // Travel time is so short, we're practically there already; so make it so. - if ( time >= 0.1) - pev->avelocity = vecDestDelta / time; - else - { - pev->avelocity = vecDestDelta; - pev->nextthink = pev->ltime + 1; - } -} - - -// -//====================== TRAIN code ================================================== -// - -class CFuncTrain : public CBasePlatTrain -{ -public: - void Spawn( void ); - void Precache( void ); - void Activate( void ); - void OverrideReset( void ); - - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - - void EXPORT Wait( void ); - void EXPORT Next( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - entvars_t *m_pevCurrentTarget; - int m_sounds; - BOOL m_activated; -}; - -LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); -TYPEDESCRIPTION CFuncTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrain, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrain, m_pevCurrentTarget, FIELD_EVARS ), - DEFINE_FIELD( CFuncTrain, m_activated, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatTrain ); - - -void CFuncTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBasePlatTrain::KeyValue( pkvd ); -} - - -void CFuncTrain :: Blocked( CBaseEntity *pOther ) - -{ - if ( gpGlobals->time < m_flActivateFinished) - return; - - m_flActivateFinished = gpGlobals->time + 0.5; - - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); -} - - -void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) - { - // Move toward my target - pev->spawnflags &= ~SF_TRAIN_WAIT_RETRIGGER; - Next(); - } - else - { - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - // Pop back to last target if it's available - if ( pev->enemy ) - pev->target = pev->enemy->v.targetname; - pev->nextthink = 0; - pev->velocity = g_vecZero; - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - } -} - - -void CFuncTrain :: Wait( void ) -{ - // Fire the pass target if there is one - if ( m_pevCurrentTarget->message ) - { - FireTargets( STRING(m_pevCurrentTarget->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pevCurrentTarget->spawnflags, SF_CORNER_FIREONCE ) ) - m_pevCurrentTarget->message = 0; - } - - // need pointer to LAST target. - if ( FBitSet (m_pevCurrentTarget->spawnflags , SF_TRAIN_WAIT_RETRIGGER ) || ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) ) - { - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - // clear the sound channel. - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - pev->nextthink = 0; - return; - } - - // ALERT ( at_console, "%f\n", m_flWait ); - - if (m_flWait != 0) - {// -1 wait will wait forever! - pev->nextthink = pev->ltime + m_flWait; - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - SetThink( &CFuncTrain::Next ); - } - else - { - Next();// do it RIGHT now! - } -} - - -// -// Train next - path corner needs to change to next target -// -void CFuncTrain :: Next( void ) -{ - CBaseEntity *pTarg; - - - // now find our next target - pTarg = GetNextTarget(); - - if ( !pTarg ) - { - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - // Play stop sound - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - return; - } - - // Save last target in case we need to find it again - pev->message = pev->target; - - pev->target = pTarg->pev->target; - m_flWait = pTarg->GetDelay(); - - if ( m_pevCurrentTarget && m_pevCurrentTarget->speed != 0 ) - {// don't copy speed from target if it is 0 (uninitialized) - pev->speed = m_pevCurrentTarget->speed; - ALERT( at_aiconsole, "Train %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); - } - m_pevCurrentTarget = pTarg->pev;// keep track of this since path corners change our target for us. - - pev->enemy = pTarg->edict();//hack - - if(FBitSet(m_pevCurrentTarget->spawnflags, SF_CORNER_TELEPORT)) - { - // Path corner has indicated a teleport to the next corner. - SetBits(pev->effects, EF_NOINTERP); - UTIL_SetOrigin(pev, pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5); - Wait(); // Get on with doing the next path corner. - } - else - { - // Normal linear move. - - // CHANGED this from CHAN_VOICE to CHAN_STATIC around OEM beta time because trains should - // use CHAN_STATIC for their movement sounds to prevent sound field problems. - // this is not a hack or temporary fix, this is how things should be. (sjb). - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseMovement ) - EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - ClearBits(pev->effects, EF_NOINTERP); - SetMoveDone( &CFuncTrain::Wait ); - LinearMove (pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5, pev->speed); - } -} - - -void CFuncTrain :: Activate( void ) -{ - // Not yet active, so teleport to first target - if ( !m_activated ) - { - m_activated = TRUE; - entvars_t *pevTarg = VARS( FIND_ENTITY_BY_TARGETNAME (NULL, STRING(pev->target) ) ); - - pev->target = pevTarg->target; - m_pevCurrentTarget = pevTarg;// keep track of this since path corners change our target for us. - - UTIL_SetOrigin (pev, pevTarg->origin - (pev->mins + pev->maxs) * 0.5 ); - - if ( FStringNull(pev->targetname) ) - { // not triggered, so start immediately - pev->nextthink = pev->ltime + 0.1; - SetThink( &CFuncTrain::Next ); - } - else - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - } -} - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving platforms that players can ride. -The targets origin specifies the min point of the train at each corner. -The train spawns at the first target it is pointing at. -If the train is the target of a button or trigger, it will not begin moving until activated. -speed default 100 -dmg default 2 -sounds -1) ratchet metal -*/ - -void CFuncTrain :: Spawn( void ) -{ - Precache(); - if (pev->speed == 0) - pev->speed = 100; - - if ( FStringNull(pev->target) ) - ALERT(at_console, "FuncTrain with no target"); - - if (pev->dmg == 0) - pev->dmg = 2; - - pev->movetype = MOVETYPE_PUSH; - - if ( FBitSet (pev->spawnflags, SF_TRACKTRAIN_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - SET_MODEL( ENT(pev), STRING(pev->model) ); - UTIL_SetSize (pev, pev->mins, pev->maxs); - UTIL_SetOrigin(pev, pev->origin); - - m_activated = FALSE; - - if ( m_volume == 0 ) - m_volume = 0.85; -} - - -void CFuncTrain::Precache( void ) -{ - CBasePlatTrain::Precache(); - -#if 0 // obsolete - // otherwise use preset sound - switch (m_sounds) - { - case 0: - pev->noise = 0; - pev->noise1 = 0; - break; - - case 1: - PRECACHE_SOUND ("plats/train2.wav"); - PRECACHE_SOUND ("plats/train1.wav"); - pev->noise = MAKE_STRING("plats/train2.wav"); - pev->noise1 = MAKE_STRING("plats/train1.wav"); - break; - - case 2: - PRECACHE_SOUND ("plats/platmove1.wav"); - PRECACHE_SOUND ("plats/platstop1.wav"); - pev->noise = MAKE_STRING("plats/platstop1.wav"); - pev->noise1 = MAKE_STRING("plats/platmove1.wav"); - break; - } -#endif -} - - -void CFuncTrain::OverrideReset( void ) -{ - CBaseEntity *pTarg; - - // Are we moving? - if ( pev->velocity != g_vecZero && pev->nextthink != 0 ) - { - pev->target = pev->message; - // now find our next target - pTarg = GetNextTarget(); - if ( !pTarg ) - { - pev->nextthink = 0; - pev->velocity = g_vecZero; - } - else // Keep moving for 0.1 secs, then find path_corner again and restart - { - SetThink( &CFuncTrain::Next ); - pev->nextthink = pev->ltime + 0.1; - } - } -} - - - - -// --------------------------------------------------------------------- -// -// Track Train -// -// --------------------------------------------------------------------- - -TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrackTrain, m_ppath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrackTrain, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_speed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_dir, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_startSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMins, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMaxs, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackTrain, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_flBank, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ); -LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); - -void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wheels")) - { - m_length = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_height = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "startspeed")) - { - m_startSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - m_flVolume = (float) (atoi(pkvd->szValue)); - m_flVolume *= 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bank")) - { - m_flBank = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) -{ - if ( alwaysThink ) - pev->flags |= FL_ALWAYSTHINK; - else - pev->flags &= ~FL_ALWAYSTHINK; - - pev->nextthink = thinkTime; -} - - -void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // Blocker is on-ground on the train - if ( FBitSet( pevOther->flags, FL_ONGROUND ) && VARS(pevOther->groundentity) == pev ) - { - float deltaSpeed = fabs(pev->speed); - if ( deltaSpeed > 50 ) - deltaSpeed = 50; - if ( !pevOther->velocity.z ) - pevOther->velocity.z += deltaSpeed; - return; - } - else - pevOther->velocity = (pevOther->origin - pev->origin ).Normalize() * pev->dmg; - - ALERT( at_aiconsole, "TRAIN(%s): Blocked by %s (dmg:%.2f)\n", STRING(pev->targetname), STRING(pOther->pev->classname), pev->dmg ); - if ( pev->dmg <= 0 ) - return; - // we can't hurt this thing, so we're not concerned with it - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); -} - - -void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType != USE_SET ) - { - if ( !ShouldToggle( useType, (pev->speed != 0) ) ) - return; - - if ( pev->speed == 0 ) - { - pev->speed = m_speed * m_dir; - - Next(); - } - else - { - pev->speed = 0; - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - StopSound(); - SetThink( NULL ); - } - } - else - { - float delta = value; - - delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; - if ( delta > 1 ) - delta = 1; - else if ( delta < -1 ) - delta = -1; - if ( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) - { - if ( delta < 0 ) - delta = 0; - } - pev->speed = m_speed * delta; - Next(); - ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING(pev->targetname), pev->speed ); - } -} - - -static float Fix( float angle ) -{ - while ( angle < 0 ) - angle += 360; - while ( angle > 360 ) - angle -= 360; - - return angle; -} - - -static void FixupAngles( Vector &v ) -{ - v.x = Fix( v.x ); - v.y = Fix( v.y ); - v.z = Fix( v.z ); -} - -#define TRAIN_STARTPITCH 60 -#define TRAIN_MAXPITCH 200 -#define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation - -void CFuncTrackTrain :: StopSound( void ) -{ - // if sound playing, stop it - if (m_soundPlaying && pev->noise) - { - unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; - - us_encode = us_sound; - - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, - (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 ); - - /* - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - */ - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100); - } - - m_soundPlaying = 0; -} - -// update pitch based on speed, start sound if not playing -// NOTE: when train goes through transition, m_soundPlaying should go to 0, -// which will cause the looped sound to restart. - -void CFuncTrackTrain :: UpdateSound( void ) -{ - float flpitch; - - if (!pev->noise) - return; - - flpitch = TRAIN_STARTPITCH + (abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); - - if (!m_soundPlaying) - { - // play startup sound for train - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, (int) flpitch); - m_soundPlaying = 1; - } - else - { -/* - // update pitch - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int) flpitch); -*/ - // volume 0.0 - 1.0 - 6 bits - // m_sounds 3 bits - // flpitch = 6 bits - // 15 bits total - - unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; - unsigned short us_pitch = ( ( unsigned short )( flpitch / 10.0 ) & 0x003f ) << 6; - unsigned short us_volume = ( ( unsigned short )( m_flVolume * 40.0 ) & 0x003f ); - - us_encode = us_sound | us_pitch | us_volume; - - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, - (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 ); - } -} - - -void CFuncTrackTrain :: Next( void ) -{ - float time = 0.5; - - if ( !pev->speed ) - { - ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); - StopSound(); - return; - } - -// if ( !m_ppath ) -// m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) - { - ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - UpdateSound(); - - Vector nextPos = pev->origin; - - nextPos.z -= m_height; - CPathTrack *pnext = m_ppath->LookAhead( &nextPos, pev->speed * 0.1, 1 ); - nextPos.z += m_height; - - pev->velocity = (nextPos - pev->origin) * 10; - Vector nextFront = pev->origin; - - nextFront.z -= m_height; - if ( m_length > 0 ) - m_ppath->LookAhead( &nextFront, m_length, 0 ); - else - m_ppath->LookAhead( &nextFront, 100, 0 ); - nextFront.z += m_height; - - Vector delta = nextFront - pev->origin; - Vector angles = UTIL_VecToAngles( delta ); - // The train actually points west - angles.y += 180; - - // !!! All of this crap has to be done to make the angles not wrap around, revisit this. - FixupAngles( angles ); - FixupAngles( pev->angles ); - - if ( !pnext || (delta.x == 0 && delta.y == 0) ) - angles = pev->angles; - - float vy, vx; - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) - vx = UTIL_AngleDistance( angles.x, pev->angles.x ); - else - vx = 0; - vy = UTIL_AngleDistance( angles.y, pev->angles.y ); - - pev->avelocity.y = vy * 10; - pev->avelocity.x = vx * 10; - - if ( m_flBank != 0 ) - { - if ( pev->avelocity.y < -5 ) - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( -m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else if ( pev->avelocity.y > 5 ) - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank*4 ), pev->angles.z) * 4; - } - - if ( pnext ) - { - if ( pnext != m_ppath ) - { - CPathTrack *pFire; - if ( pev->speed >= 0 ) - pFire = pnext; - else - pFire = m_ppath; - - m_ppath = pnext; - // Fire the pass target if there is one - if ( pFire->pev->message ) - { - FireTargets( STRING(pFire->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) - pFire->pev->message = 0; - } - - if ( pFire->pev->spawnflags & SF_PATH_DISABLE_TRAIN ) - pev->spawnflags |= SF_TRACKTRAIN_NOCONTROL; - - // Don't override speed if under user control - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - { - if ( pFire->pev->speed != 0 ) - {// don't copy speed from target if it is 0 (uninitialized) - pev->speed = pFire->pev->speed; - ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); - } - } - - } - SetThink( &CFuncTrackTrain::Next ); - NextThink( pev->ltime + time, TRUE ); - } - else // end of path, stop - { - StopSound(); - pev->velocity = (nextPos - pev->origin); - pev->avelocity = g_vecZero; - float distance = pev->velocity.Length(); - m_oldSpeed = pev->speed; - - - pev->speed = 0; - - // Move to the dead end - - // Are we there yet? - if ( distance > 0 ) - { - // no, how long to get there? - time = distance / m_oldSpeed; - pev->velocity = pev->velocity * (m_oldSpeed / distance); - SetThink( &CFuncTrackTrain::DeadEnd ); - NextThink( pev->ltime + time, FALSE ); - } - else - { - DeadEnd(); - } - } -} - - -void CFuncTrackTrain::DeadEnd( void ) -{ - // Fire the dead-end target if there is one - CPathTrack *pTrack, *pNext; - - pTrack = m_ppath; - - ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); - // Find the dead end path node - // HACKHACK -- This is bugly, but the train can actually stop moving at a different node depending on it's speed - // so we have to traverse the list to it's end. - if ( pTrack ) - { - if ( m_oldSpeed < 0 ) - { - do - { - pNext = pTrack->ValidPath( pTrack->GetPrevious(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - else - { - do - { - pNext = pTrack->ValidPath( pTrack->GetNext(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - } - - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - if ( pTrack ) - { - ALERT( at_aiconsole, "at %s\n", STRING(pTrack->pev->targetname) ); - if ( pTrack->pev->netname ) - FireTargets( STRING(pTrack->pev->netname), this, this, USE_TOGGLE, 0 ); - } - else - ALERT( at_aiconsole, "\n" ); -} - - -void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) -{ - Vector offset = pevControls->origin - pev->oldorigin; - - m_controlMins = pevControls->mins + offset; - m_controlMaxs = pevControls->maxs + offset; -} - - -BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) -{ - Vector offset = pevTest->origin - pev->origin; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - return FALSE; - - // Transform offset into local coordinates - UTIL_MakeVectors( pev->angles ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = -DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - if ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z && - local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ) - return TRUE; - - return FALSE; -} - - -void CFuncTrackTrain :: Find( void ) -{ - m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) - return; - - entvars_t *pevTarget = m_ppath->pev; - if ( !FClassnameIs( pevTarget, "path_track" ) ) - { - ALERT( at_error, "func_track_train must be on a path of path_track\n" ); - m_ppath = NULL; - return; - } - - Vector nextPos = pevTarget->origin; - nextPos.z += m_height; - - Vector look = nextPos; - look.z -= m_height; - m_ppath->LookAhead( &look, m_length, 0 ); - look.z += m_height; - - pev->angles = UTIL_VecToAngles( look - nextPos ); - // The train actually points west - pev->angles.y += 180; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) - pev->angles.x = 0; - UTIL_SetOrigin( pev, nextPos ); - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Next ); - pev->speed = m_startSpeed; - - UpdateSound(); -} - - -void CFuncTrackTrain :: NearestPath( void ) -{ - CBaseEntity *pTrack = NULL; - CBaseEntity *pNearest = NULL; - float dist, closest; - - closest = 1024; - - while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) - { - // filter out non-tracks - if ( !(pTrack->pev->flags & (FL_CLIENT|FL_MONSTER)) && FClassnameIs( pTrack->pev, "path_track" ) ) - { - dist = (pev->origin - pTrack->pev->origin).Length(); - if ( dist < closest ) - { - closest = dist; - pNearest = pTrack; - } - } - } - - if ( !pNearest ) - { - ALERT( at_console, "Can't find a nearby track !!!\n" ); - SetThink(NULL); - return; - } - - ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING(pev->targetname), STRING(pNearest->pev->targetname) ); - // If I'm closer to the next path_track on this path, then it's my real path - pTrack = ((CPathTrack *)pNearest)->GetNext(); - if ( pTrack ) - { - if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) - pNearest = pTrack; - } - - m_ppath = (CPathTrack *)pNearest; - - if ( pev->speed != 0 ) - { - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Next ); - } -} - - -void CFuncTrackTrain::OverrideReset( void ) -{ - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::NearestPath ); -} - - -CFuncTrackTrain *CFuncTrackTrain::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "func_tracktrain" ) ) - return (CFuncTrackTrain *)GET_PRIVATE(pent); - return NULL; -} - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving platforms that players can ride. -The targets origin specifies the min point of the train at each corner. -The train spawns at the first target it is pointing at. -If the train is the target of a button or trigger, it will not begin moving until activated. -speed default 100 -dmg default 2 -sounds -1) ratchet metal -*/ - -void CFuncTrackTrain :: Spawn( void ) -{ - if ( pev->speed == 0 ) - m_speed = 100; - else - m_speed = pev->speed; - - pev->speed = 0; - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->impulse = m_speed; - - m_dir = 1; - - if ( FStringNull(pev->target) ) - ALERT( at_console, "FuncTrain with no target" ); - - if ( pev->spawnflags & SF_TRACKTRAIN_PASSABLE ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - // Cache off placed origin for train controls - pev->oldorigin = pev->origin; - - m_controlMins = pev->mins; - m_controlMaxs = pev->maxs; - m_controlMaxs.z += 72; -// start trains on the next frame, to make sure their targets have had -// a chance to spawn/activate - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Find ); - Precache(); -} - -void CFuncTrackTrain :: Precache( void ) -{ - if (m_flVolume == 0.0) - m_flVolume = 1.0; - - switch (m_sounds) - { - default: - // no sound - pev->noise = 0; - break; - case 1: PRECACHE_SOUND("plats/ttrain1.wav"); pev->noise = MAKE_STRING("plats/ttrain1.wav");break; - case 2: PRECACHE_SOUND("plats/ttrain2.wav"); pev->noise = MAKE_STRING("plats/ttrain2.wav");break; - case 3: PRECACHE_SOUND("plats/ttrain3.wav"); pev->noise = MAKE_STRING("plats/ttrain3.wav");break; - case 4: PRECACHE_SOUND("plats/ttrain4.wav"); pev->noise = MAKE_STRING("plats/ttrain4.wav");break; - case 5: PRECACHE_SOUND("plats/ttrain6.wav"); pev->noise = MAKE_STRING("plats/ttrain6.wav");break; - case 6: PRECACHE_SOUND("plats/ttrain7.wav"); pev->noise = MAKE_STRING("plats/ttrain7.wav");break; - } - - PRECACHE_SOUND("plats/ttrain_brake1.wav"); - PRECACHE_SOUND("plats/ttrain_start1.wav"); - - m_usAdjustPitch = PRECACHE_EVENT( 1, "events/train.sc" ); -} - -// This class defines the volume of space that the player must stand in to control the train -class CFuncTrainControls : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void Spawn( void ); - void EXPORT Find( void ); -}; -LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ); - - -void CFuncTrainControls :: Find( void ) -{ - edict_t *pTarget = NULL; - - do - { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && !FClassnameIs(pTarget, "func_tracktrain") ); - - if ( FNullEnt( pTarget ) ) - { - ALERT( at_console, "No train %s\n", STRING(pev->target) ); - return; - } - - CFuncTrackTrain *ptrain = CFuncTrackTrain::Instance(pTarget); - ptrain->SetControls( pev ); - UTIL_Remove( this ); -} - - -void CFuncTrainControls :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CFuncTrainControls::Find ); - pev->nextthink = gpGlobals->time; -} - - - -// ---------------------------------------------------------------------------- -// -// Track changer / Train elevator -// -// ---------------------------------------------------------------------------- - -#define SF_TRACK_ACTIVATETRAIN 0x00000001 -#define SF_TRACK_RELINK 0x00000002 -#define SF_TRACK_ROTMOVE 0x00000004 -#define SF_TRACK_STARTBOTTOM 0x00000008 -#define SF_TRACK_DONT_MOVE 0x00000010 - -// -// This entity is a rotating/moving platform that will carry a train to a new track. -// It must be larger in X-Y planar area than the train, since it must contain the -// train within these dimensions in order to operate when the train is near it. -// - -typedef enum { TRAIN_SAFE, TRAIN_BLOCKING, TRAIN_FOLLOWING } TRAIN_CODE; - -class CFuncTrackChange : public CFuncPlatRot -{ -public: - void Spawn( void ); - void Precache( void ); - -// virtual void Blocked( void ); - virtual void EXPORT GoUp( void ); - virtual void EXPORT GoDown( void ); - - void KeyValue( KeyValueData* pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Find( void ); - TRAIN_CODE EvaluateTrain( CPathTrack *pcurrent ); - void UpdateTrain( Vector &dest ); - virtual void HitBottom( void ); - virtual void HitTop( void ); - void Touch( CBaseEntity *pOther ); - virtual void UpdateAutoTargets( int toggleState ); - virtual BOOL IsTogglePlat( void ) { return TRUE; } - - void DisableUse( void ) { m_use = 0; } - void EnableUse( void ) { m_use = 1; } - int UseEnabled( void ) { return m_use; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual void OverrideReset( void ); - - - CPathTrack *m_trackTop; - CPathTrack *m_trackBottom; - - CFuncTrackTrain *m_train; - - int m_trackTopName; - int m_trackBottomName; - int m_trainName; - TRAIN_CODE m_code; - int m_targetState; - int m_use; -}; -LINK_ENTITY_TO_CLASS( func_trackchange, CFuncTrackChange ); - -TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = -{ - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTop, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottom, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_train, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTopName, FIELD_STRING ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottomName, FIELD_STRING ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trainName, FIELD_STRING ), - DEFINE_FIELD( CFuncTrackChange, m_code, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackChange, m_targetState, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackChange, m_use, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ); - -void CFuncTrackChange :: Spawn( void ) -{ - Setup(); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - m_vecPosition2.z = pev->origin.z; - - SetupRotation(); - - if ( FBitSet( pev->spawnflags, SF_TRACK_STARTBOTTOM ) ) - { - UTIL_SetOrigin (pev, m_vecPosition2); - m_toggle_state = TS_AT_BOTTOM; - pev->angles = m_start; - m_targetState = TS_AT_TOP; - } - else - { - UTIL_SetOrigin (pev, m_vecPosition1); - m_toggle_state = TS_AT_TOP; - pev->angles = m_end; - m_targetState = TS_AT_BOTTOM; - } - - EnableUse(); - pev->nextthink = pev->ltime + 2.0; - SetThink( &CFuncTrackChange::Find ); - Precache(); -} - -void CFuncTrackChange :: Precache( void ) -{ - // Can't trigger sound - PRECACHE_SOUND( "buttons/button11.wav" ); - - CFuncPlatRot::Precache(); -} - - -// UNDONE: Filter touches before re-evaluating the train. -void CFuncTrackChange :: Touch( CBaseEntity *pOther ) -{ -#if 0 - TRAIN_CODE code; - entvars_t *pevToucher = pOther->pev; -#endif -} - - - -void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "train") ) - { - m_trainName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "toptrack") ) - { - m_trackTopName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bottomtrack") ) - { - m_trackBottomName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CFuncPlatRot::KeyValue( pkvd ); // Pass up to base class - } -} - - -void CFuncTrackChange::OverrideReset( void ) -{ - pev->nextthink = pev->ltime + 1.0; - SetThink( &CFuncTrackChange::Find ); -} - -void CFuncTrackChange :: Find( void ) -{ - // Find track entities - edict_t *target; - - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackTopName) ); - if ( !FNullEnt(target) ) - { - m_trackTop = CPathTrack::Instance( target ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackBottomName) ); - if ( !FNullEnt(target) ) - { - m_trackBottom = CPathTrack::Instance( target ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); - if ( !FNullEnt(target) ) - { - m_train = CFuncTrackTrain::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ) ); - if ( !m_train ) - { - ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); - return; - } - Vector center = (pev->absmin + pev->absmax) * 0.5; - m_trackBottom = m_trackBottom->Nearest( center ); - m_trackTop = m_trackTop->Nearest( center ); - UpdateAutoTargets( m_toggle_state ); - SetThink( NULL ); - return; - } - else - { - ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); - } - } - else - ALERT( at_error, "Can't find bottom track for track change! %s\n", STRING(m_trackBottomName) ); - } - else - ALERT( at_error, "Can't find top track for track change! %s\n", STRING(m_trackTopName) ); -} - - - -TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) -{ - // Go ahead and work, we don't have anything to switch, so just be an elevator - if ( !pcurrent || !m_train ) - return TRAIN_SAFE; - - if ( m_train->m_ppath == pcurrent || (pcurrent->m_pprevious && m_train->m_ppath == pcurrent->m_pprevious) || - (pcurrent->m_pnext && m_train->m_ppath == pcurrent->m_pnext) ) - { - if ( m_train->pev->speed != 0 ) - return TRAIN_BLOCKING; - - Vector dist = pev->origin - m_train->pev->origin; - float length = dist.Length2D(); - if ( length < m_train->m_length ) // Empirically determined close distance - return TRAIN_FOLLOWING; - else if ( length > (150 + m_train->m_length) ) - return TRAIN_SAFE; - - return TRAIN_BLOCKING; - } - - return TRAIN_SAFE; -} - - -void CFuncTrackChange :: UpdateTrain( Vector &dest ) -{ - float time = (pev->nextthink - pev->ltime); - - m_train->pev->velocity = pev->velocity; - m_train->pev->avelocity = pev->avelocity; - m_train->NextThink( m_train->pev->ltime + time, FALSE ); - - // Attempt at getting the train to rotate properly around the origin of the trackchange - if ( time <= 0 ) - return; - - Vector offset = m_train->pev->origin - pev->origin; - Vector delta = dest - pev->angles; - // Transform offset into local coordinates - UTIL_MakeInvVectors( delta, gpGlobals ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - local = local - offset; - m_train->pev->velocity = pev->velocity + (local * (1.0/time)); -} - -void CFuncTrackChange :: GoDown( void ) -{ - if ( m_code == TRAIN_BLOCKING ) - return; - - // HitBottom may get called during CFuncPlat::GoDown(), so set up for that - // before you call GoDown() - - UpdateAutoTargets( TS_GOING_DOWN ); - // If ROTMOVE, move & rotate - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - { - SetMoveDone( &CFuncTrackChange::CallHitBottom ); - m_toggle_state = TS_GOING_DOWN; - AngularMove( m_start, pev->speed ); - } - else - { - CFuncPlat :: GoDown(); - SetMoveDone( &CFuncTrackChange::CallHitBottom ); - RotMove( m_start, pev->nextthink - pev->ltime ); - } - // Otherwise, rotate first, move second - - // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) - { - UpdateTrain( m_start ); - m_train->m_ppath = NULL; - } -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncTrackChange :: GoUp( void ) -{ - if ( m_code == TRAIN_BLOCKING ) - return; - - // HitTop may get called during CFuncPlat::GoUp(), so set up for that - // before you call GoUp(); - - UpdateAutoTargets( TS_GOING_UP ); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - { - m_toggle_state = TS_GOING_UP; - SetMoveDone( &CFuncTrackChange::CallHitTop ); - AngularMove( m_end, pev->speed ); - } - else - { - // If ROTMOVE, move & rotate - CFuncPlat :: GoUp(); - SetMoveDone( &CFuncTrackChange::CallHitTop ); - RotMove( m_end, pev->nextthink - pev->ltime ); - } - - // Otherwise, move first, rotate second - - // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) - { - UpdateTrain( m_end ); - m_train->m_ppath = NULL; - } -} - - -// Normal track change -void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) -{ - if ( !m_trackTop || !m_trackBottom ) - return; - - if ( toggleState == TS_AT_TOP ) - ClearBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); - else - SetBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); - - if ( toggleState == TS_AT_BOTTOM ) - ClearBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); - else - SetBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); -} - - -void CFuncTrackChange :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( m_toggle_state != TS_AT_TOP && m_toggle_state != TS_AT_BOTTOM ) - return; - - // If train is in "safe" area, but not on the elevator, play alarm sound - if ( m_toggle_state == TS_AT_TOP ) - m_code = EvaluateTrain( m_trackTop ); - else if ( m_toggle_state == TS_AT_BOTTOM ) - m_code = EvaluateTrain( m_trackBottom ); - else - m_code = TRAIN_BLOCKING; - if ( m_code == TRAIN_BLOCKING ) - { - // Play alarm and return - EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/button11.wav", 1, ATTN_NORM); - return; - } - - // Otherwise, it's safe to move - // If at top, go down - // at bottom, go up - - DisableUse(); - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else - GoUp(); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncTrackChange :: HitBottom( void ) -{ - CFuncPlatRot :: HitBottom(); - if ( m_code == TRAIN_FOLLOWING ) - { -// UpdateTrain(); - m_train->SetTrack( m_trackBottom ); - } - SetThink( NULL ); - pev->nextthink = -1; - - UpdateAutoTargets( m_toggle_state ); - - EnableUse(); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncTrackChange :: HitTop( void ) -{ - CFuncPlatRot :: HitTop(); - if ( m_code == TRAIN_FOLLOWING ) - { -// UpdateTrain(); - m_train->SetTrack( m_trackTop ); - } - - // Don't let the plat go back down - SetThink( NULL ); - pev->nextthink = -1; - UpdateAutoTargets( m_toggle_state ); - EnableUse(); -} - - - -class CFuncTrackAuto : public CFuncTrackChange -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void UpdateAutoTargets( int toggleState ); -}; - -LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ); - -// Auto track change -void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) -{ - CPathTrack *pTarget, *pNextTarget; - - if ( !m_trackTop || !m_trackBottom ) - return; - - if ( m_targetState == TS_AT_TOP ) - { - pTarget = m_trackTop->GetNext(); - pNextTarget = m_trackBottom->GetNext(); - } - else - { - pTarget = m_trackBottom->GetNext(); - pNextTarget = m_trackTop->GetNext(); - } - if ( pTarget ) - { - ClearBits( pTarget->pev->spawnflags, SF_PATH_DISABLED ); - if ( m_code == TRAIN_FOLLOWING && m_train && m_train->pev->speed == 0 ) - m_train->Use( this, this, USE_ON, 0 ); - } - - if ( pNextTarget ) - SetBits( pNextTarget->pev->spawnflags, SF_PATH_DISABLED ); - -} - - -void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CPathTrack *pTarget; - - if ( !UseEnabled() ) - return; - - if ( m_toggle_state == TS_AT_TOP ) - pTarget = m_trackTop; - else if ( m_toggle_state == TS_AT_BOTTOM ) - pTarget = m_trackBottom; - else - pTarget = NULL; - - if ( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) - { - m_code = EvaluateTrain( pTarget ); - // Safe to fire? - if ( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) - { - DisableUse(); - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else - GoUp(); - } - } - else - { - if ( pTarget ) - pTarget = pTarget->GetNext(); - if ( pTarget && m_train->m_ppath != pTarget && ShouldToggle( useType, m_targetState ) ) - { - if ( m_targetState == TS_AT_TOP ) - m_targetState = TS_AT_BOTTOM; - else - m_targetState = TS_AT_TOP; - } - - UpdateAutoTargets( m_targetState ); - } -} - - -// ---------------------------------------------------------- -// -// -// pev->speed is the travel speed -// pev->health is current health -// pev->max_health is the amount to reset to each time it starts - -#define FGUNTARGET_START_ON 0x0001 - -class CGunTarget : public CBaseMonster -{ -public: - void Spawn( void ); - void Activate( void ); - void EXPORT Next( void ); - void EXPORT Start( void ); - void EXPORT Wait( void ); - void Stop( void ); - - int BloodColor( void ) { return DONT_BLEED; } - int Classify( void ) { return CLASS_MACHINE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - Vector BodyTarget( const Vector &posSrc ) { return pev->origin; } - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - BOOL m_on; -}; - - -LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ); - -TYPEDESCRIPTION CGunTarget::m_SaveData[] = -{ - DEFINE_FIELD( CGunTarget, m_on, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ); - - -void CGunTarget::Spawn( void ) -{ - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if ( pev->speed == 0 ) - pev->speed = 100; - - // Don't take damage until "on" - pev->takedamage = DAMAGE_NO; - pev->flags |= FL_MONSTER; - - m_on = FALSE; - pev->max_health = pev->health; - - if ( pev->spawnflags & FGUNTARGET_START_ON ) - { - SetThink( &CGunTarget::Start ); - pev->nextthink = pev->ltime + 0.3; - } -} - - -void CGunTarget::Activate( void ) -{ - CBaseEntity *pTarg; - - // now find our next target - pTarg = GetNextTarget(); - if ( pTarg ) - { - m_hTargetEnt = pTarg; - UTIL_SetOrigin( pev, pTarg->pev->origin - (pev->mins + pev->maxs) * 0.5 ); - } -} - - -void CGunTarget::Start( void ) -{ - Use( this, this, USE_ON, 0 ); -} - - -void CGunTarget::Next( void ) -{ - SetThink( NULL ); - - m_hTargetEnt = GetNextTarget(); - CBaseEntity *pTarget = m_hTargetEnt; - - if ( !pTarget ) - { - Stop(); - return; - } - SetMoveDone( &CGunTarget::Wait ); - LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); -} - - -void CGunTarget::Wait( void ) -{ - CBaseEntity *pTarget = m_hTargetEnt; - - if ( !pTarget ) - { - Stop(); - return; - } - - // Fire the pass target if there is one - if ( pTarget->pev->message ) - { - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pTarget->pev->spawnflags, SF_CORNER_FIREONCE ) ) - pTarget->pev->message = 0; - } - - m_flWait = pTarget->GetDelay(); - - pev->target = pTarget->pev->target; - SetThink( &CGunTarget::Next ); - if (m_flWait != 0) - {// -1 wait will wait forever! - pev->nextthink = pev->ltime + m_flWait; - } - else - { - Next();// do it RIGHT now! - } -} - - -void CGunTarget::Stop( void ) -{ - pev->velocity = g_vecZero; - pev->nextthink = 0; - pev->takedamage = DAMAGE_NO; -} - - -int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( pev->health > 0 ) - { - pev->health -= flDamage; - if ( pev->health <= 0 ) - { - pev->health = 0; - Stop(); - if ( pev->message ) - FireTargets( STRING(pev->message), this, this, USE_TOGGLE, 0 ); - } - } - return 0; -} - - -void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_on ) ) - return; - - if ( m_on ) - { - Stop(); - } - else - { - pev->takedamage = DAMAGE_AIM; - m_hTargetEnt = GetNextTarget(); - if ( m_hTargetEnt == NULL ) - return; - pev->health = pev->max_health; - Next(); - } -} - - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== plats.cpp ======================================================== + + spawn, think, and touch functions for trains, etc + +*/ + +//#include "extdll.h" +//#include "util.h" +//#include "cbase.h" +//#include "trains.h" +//#include "saverestore.h" +#include +#include "plats.h" + +static void PlatSpawnInsideTrigger(entvars_t* pevPlatform); + +TYPEDESCRIPTION CBasePlatTrain::m_SaveData[] = +{ + DEFINE_FIELD( CBasePlatTrain, m_bMoveSnd, FIELD_CHARACTER ), + DEFINE_FIELD( CBasePlatTrain, m_bStopSnd, FIELD_CHARACTER ), + DEFINE_FIELD( CBasePlatTrain, m_volume, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CBasePlatTrain, CBaseToggle ); + +void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "lip")) + { + m_flLip = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "wait")) + { + m_flWait = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "height")) + { + m_flHeight = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "rotation")) + { + m_vecFinalAngle.x = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "stopsnd")) + { + m_bStopSnd = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "volume")) + { + m_volume = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +#define noiseMoving noise +#define noiseArrived noise1 + +void CBasePlatTrain::Precache( void ) +{ +// set the plat's "in-motion" sound + switch (m_bMoveSnd) + { + case 0: + pev->noiseMoving = MAKE_STRING("common/null.wav"); + break; + case 1: + PRECACHE_SOUND ("plats/bigmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/bigmove1.wav"); + break; + case 2: + PRECACHE_SOUND ("plats/bigmove2.wav"); + pev->noiseMoving = MAKE_STRING("plats/bigmove2.wav"); + break; + case 3: + PRECACHE_SOUND ("plats/elevmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/elevmove1.wav"); + break; + case 4: + PRECACHE_SOUND ("plats/elevmove2.wav"); + pev->noiseMoving = MAKE_STRING("plats/elevmove2.wav"); + break; + case 5: + PRECACHE_SOUND ("plats/elevmove3.wav"); + pev->noiseMoving = MAKE_STRING("plats/elevmove3.wav"); + break; + case 6: + PRECACHE_SOUND ("plats/freightmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/freightmove1.wav"); + break; + case 7: + PRECACHE_SOUND ("plats/freightmove2.wav"); + pev->noiseMoving = MAKE_STRING("plats/freightmove2.wav"); + break; + case 8: + PRECACHE_SOUND ("plats/heavymove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/heavymove1.wav"); + break; + case 9: + PRECACHE_SOUND ("plats/rackmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/rackmove1.wav"); + break; + case 10: + PRECACHE_SOUND ("plats/railmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/railmove1.wav"); + break; + case 11: + PRECACHE_SOUND ("plats/squeekmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/squeekmove1.wav"); + break; + case 12: + PRECACHE_SOUND ("plats/talkmove1.wav"); + pev->noiseMoving = MAKE_STRING("plats/talkmove1.wav"); + break; + case 13: + PRECACHE_SOUND ("plats/talkmove2.wav"); + pev->noiseMoving = MAKE_STRING("plats/talkmove2.wav"); + break; + default: + pev->noiseMoving = MAKE_STRING("common/null.wav"); + break; + } + +// set the plat's 'reached destination' stop sound + switch (m_bStopSnd) + { + case 0: + pev->noiseArrived = MAKE_STRING("common/null.wav"); + break; + case 1: + PRECACHE_SOUND ("plats/bigstop1.wav"); + pev->noiseArrived = MAKE_STRING("plats/bigstop1.wav"); + break; + case 2: + PRECACHE_SOUND ("plats/bigstop2.wav"); + pev->noiseArrived = MAKE_STRING("plats/bigstop2.wav"); + break; + case 3: + PRECACHE_SOUND ("plats/freightstop1.wav"); + pev->noiseArrived = MAKE_STRING("plats/freightstop1.wav"); + break; + case 4: + PRECACHE_SOUND ("plats/heavystop2.wav"); + pev->noiseArrived = MAKE_STRING("plats/heavystop2.wav"); + break; + case 5: + PRECACHE_SOUND ("plats/rackstop1.wav"); + pev->noiseArrived = MAKE_STRING("plats/rackstop1.wav"); + break; + case 6: + PRECACHE_SOUND ("plats/railstop1.wav"); + pev->noiseArrived = MAKE_STRING("plats/railstop1.wav"); + break; + case 7: + PRECACHE_SOUND ("plats/squeekstop1.wav"); + pev->noiseArrived = MAKE_STRING("plats/squeekstop1.wav"); + break; + case 8: + PRECACHE_SOUND ("plats/talkstop1.wav"); + pev->noiseArrived = MAKE_STRING("plats/talkstop1.wav"); + break; + + default: + pev->noiseArrived = MAKE_STRING("common/null.wav"); + break; + } +} + +// +//====================== PLAT code ==================================================== +// + + +#define noiseMovement noise +#define noiseStopMoving noise1 + +class CFuncPlat : public CBasePlatTrain +{ +public: + void Spawn( void ); + void Precache( void ); + void Setup( void ); + + virtual void Blocked( CBaseEntity *pOther ); + + + void EXPORT PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + void EXPORT CallGoDown( void ) { GoDown(); } + void EXPORT CallHitTop( void ) { HitTop(); } + void EXPORT CallHitBottom( void ) { HitBottom(); } + + virtual void GoUp( void ); + virtual void GoDown( void ); + virtual void HitTop( void ); + virtual void HitBottom( void ); +}; +LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ); + + +// UNDONE: Need to save this!!! It needs class & linkage +class CPlatTrigger : public CBaseEntity +{ +public: + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } + void SpawnInsideTrigger( CFuncPlat *pPlatform ); + void Touch( CBaseEntity *pOther ); + CFuncPlat *m_pPlatform; +}; + + + +/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER +speed default 150 + +Plats are always drawn in the extended position, so they will light correctly. + +If the plat is the target of another trigger or button, it will start out disabled in +the extended position until it is trigger, when it will lower and become a normal plat. + +If the "height" key is set, that will determine the amount the plat moves, instead of +being implicitly determined by the model's height. + +Set "sounds" to one of the following: +1) base fast +2) chain slow +*/ + +void CFuncPlat :: Setup( void ) +{ + //pev->noiseMovement = MAKE_STRING("plats/platmove1.wav"); + //pev->noiseStopMoving = MAKE_STRING("plats/platstop1.wav"); + + if (m_flTLength == 0) + m_flTLength = 80; + if (m_flTWidth == 0) + m_flTWidth = 10; + + pev->angles = g_vecZero; + + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + + UTIL_SetOrigin(pev, pev->origin); // set size and link into world + UTIL_SetSize(pev, pev->mins, pev->maxs); + SET_MODEL(ENT(pev), STRING(pev->model) ); + + // vecPosition1 is the top position, vecPosition2 is the bottom + m_vecPosition1 = pev->origin; + m_vecPosition2 = pev->origin; + if (m_flHeight != 0) + m_vecPosition2.z = pev->origin.z - m_flHeight; + else + m_vecPosition2.z = pev->origin.z - pev->size.z + 8; + if (pev->speed == 0) + pev->speed = 150; + + if ( m_volume == 0 ) + m_volume = 0.85; +} + + +void CFuncPlat :: Precache( ) +{ + CBasePlatTrain::Precache(); + //PRECACHE_SOUND("plats/platmove1.wav"); + //PRECACHE_SOUND("plats/platstop1.wav"); + if ( !IsTogglePlat() ) + PlatSpawnInsideTrigger( pev ); // the "start moving" trigger +} + + +void CFuncPlat :: Spawn( ) +{ + Setup(); + + Precache(); + + // If this platform is the target of some button, it starts at the TOP position, + // and is brought down by that button. Otherwise, it starts at BOTTOM. + if ( !FStringNull(pev->targetname) ) + { + UTIL_SetOrigin (pev, m_vecPosition1); + m_toggle_state = TS_AT_TOP; + SetUse( &CFuncPlat::PlatUse ); + } + else + { + UTIL_SetOrigin (pev, m_vecPosition2); + m_toggle_state = TS_AT_BOTTOM; + } +} + + + +static void PlatSpawnInsideTrigger(entvars_t* pevPlatform) +{ + GetClassPtr( (CPlatTrigger *)NULL)->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); +} + + +// +// Create a trigger entity for a platform. +// +void CPlatTrigger :: SpawnInsideTrigger( CFuncPlat *pPlatform ) +{ + m_pPlatform = pPlatform; + // Create trigger entity, "point" it at the owning platform, give it a touch method + pev->solid = SOLID_TRIGGER; + pev->movetype = MOVETYPE_NONE; + pev->origin = pPlatform->pev->origin; + + // Establish the trigger field's size + Vector vecTMin = m_pPlatform->pev->mins + Vector ( 25 , 25 , 0 ); + Vector vecTMax = m_pPlatform->pev->maxs + Vector ( 25 , 25 , 8 ); + vecTMin.z = vecTMax.z - ( m_pPlatform->m_vecPosition1.z - m_pPlatform->m_vecPosition2.z + 8 ); + if (m_pPlatform->pev->size.x <= 50) + { + vecTMin.x = (m_pPlatform->pev->mins.x + m_pPlatform->pev->maxs.x) / 2; + vecTMax.x = vecTMin.x + 1; + } + if (m_pPlatform->pev->size.y <= 50) + { + vecTMin.y = (m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y) / 2; + vecTMax.y = vecTMin.y + 1; + } + UTIL_SetSize ( pev, vecTMin, vecTMax ); +} + + +// +// When the platform's trigger field is touched, the platform ??? +// +void CPlatTrigger :: Touch( CBaseEntity *pOther ) +{ + // Ignore touches by non-players + entvars_t* pevToucher = pOther->pev; + if ( !FClassnameIs (pevToucher, "player") ) + return; + + // Ignore touches by corpses + if (!pOther->IsAlive()) + return; + + // Make linked platform go up/down. + if (m_pPlatform->m_toggle_state == TS_AT_BOTTOM) + m_pPlatform->GoUp(); + else if (m_pPlatform->m_toggle_state == TS_AT_TOP) + m_pPlatform->pev->nextthink = m_pPlatform->pev->ltime + 1;// delay going down +} + + +// +// Used by SUB_UseTargets, when a platform is the target of a button. +// Start bringing platform down. +// +void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( IsTogglePlat() ) + { + // Top is off, bottom is on + BOOL on = (m_toggle_state == TS_AT_BOTTOM) ? TRUE : FALSE; + + if ( !ShouldToggle( useType, on ) ) + return; + + if (m_toggle_state == TS_AT_TOP) + GoDown(); + else if ( m_toggle_state == TS_AT_BOTTOM ) + GoUp(); + } + else + { + SetUse( NULL ); + + if (m_toggle_state == TS_AT_TOP) + GoDown(); + } +} + + +// +// Platform is at top, now starts moving down. +// +void CFuncPlat :: GoDown( void ) +{ + if(pev->noiseMovement) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); + + ASSERT(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP); + m_toggle_state = TS_GOING_DOWN; + SetMoveDone(&CFuncPlat::CallHitBottom); + LinearMove(m_vecPosition2, pev->speed); +} + + +// +// Platform has hit bottom. Stops and waits forever. +// +void CFuncPlat :: HitBottom( void ) +{ + if(pev->noiseMovement) + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); + + if (pev->noiseStopMoving) + EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); + + ASSERT(m_toggle_state == TS_GOING_DOWN); + m_toggle_state = TS_AT_BOTTOM; +} + + +// +// Platform is at bottom, now starts moving up +// +void CFuncPlat :: GoUp( void ) +{ + if (pev->noiseMovement) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); + + ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); + m_toggle_state = TS_GOING_UP; + SetMoveDone(&CFuncPlat::CallHitTop); + LinearMove(m_vecPosition1, pev->speed); +} + + +// +// Platform has hit top. Pauses, then starts back down again. +// +void CFuncPlat :: HitTop( void ) +{ + if(pev->noiseMovement) + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); + + if (pev->noiseStopMoving) + EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); + + ASSERT(m_toggle_state == TS_GOING_UP); + m_toggle_state = TS_AT_TOP; + + if ( !IsTogglePlat() ) + { + // After a delay, the platform will automatically start going down again. + SetThink( &CFuncPlat::CallGoDown ); + pev->nextthink = pev->ltime + 3; + } +} + + +void CFuncPlat :: Blocked( CBaseEntity *pOther ) +{ + ALERT( at_aiconsole, "%s Blocked by %s\n", STRING(pev->classname), STRING(pOther->pev->classname) ); + // Hurt the blocker a little + pOther->TakeDamage(pev, pev, 1, DMG_CRUSH); + + if(pev->noiseMovement) + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); + + // Send the platform back where it came from + ASSERT(m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN); + if (m_toggle_state == TS_GOING_UP) + GoDown(); + else if (m_toggle_state == TS_GOING_DOWN) + GoUp (); +} + + +class CFuncPlatRot : public CFuncPlat +{ +public: + void Spawn( void ); + void SetupRotation( void ); + + virtual void GoUp( void ); + virtual void GoDown( void ); + virtual void HitTop( void ); + virtual void HitBottom( void ); + + void RotMove( Vector &destAngle, float time ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + Vector m_end, m_start; +}; +LINK_ENTITY_TO_CLASS( func_platrot, CFuncPlatRot ); +TYPEDESCRIPTION CFuncPlatRot::m_SaveData[] = +{ + DEFINE_FIELD( CFuncPlatRot, m_end, FIELD_VECTOR ), + DEFINE_FIELD( CFuncPlatRot, m_start, FIELD_VECTOR ), +}; + +IMPLEMENT_SAVERESTORE( CFuncPlatRot, CFuncPlat ); + + +void CFuncPlatRot :: SetupRotation( void ) +{ + if ( m_vecFinalAngle.x != 0 ) // This plat rotates too! + { + CBaseToggle :: AxisDir( pev ); + m_start = pev->angles; + m_end = pev->angles + pev->movedir * m_vecFinalAngle.x; + } + else + { + m_start = g_vecZero; + m_end = g_vecZero; + } + if ( !FStringNull(pev->targetname) ) // Start at top + { + pev->angles = m_end; + } +} + + +void CFuncPlatRot :: Spawn( void ) +{ + CFuncPlat :: Spawn(); + SetupRotation(); +} + +void CFuncPlatRot :: GoDown( void ) +{ + CFuncPlat :: GoDown(); + RotMove( m_start, pev->nextthink - pev->ltime ); +} + + +// +// Platform has hit bottom. Stops and waits forever. +// +void CFuncPlatRot :: HitBottom( void ) +{ + CFuncPlat :: HitBottom(); + pev->avelocity = g_vecZero; + pev->angles = m_start; +} + + +// +// Platform is at bottom, now starts moving up +// +void CFuncPlatRot :: GoUp( void ) +{ + CFuncPlat :: GoUp(); + RotMove( m_end, pev->nextthink - pev->ltime ); +} + + +// +// Platform has hit top. Pauses, then starts back down again. +// +void CFuncPlatRot :: HitTop( void ) +{ + CFuncPlat :: HitTop(); + pev->avelocity = g_vecZero; + pev->angles = m_end; +} + + +void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) +{ + // set destdelta to the vector needed to move + Vector vecDestDelta = destAngle - pev->angles; + + // Travel time is so short, we're practically there already; so make it so. + if ( time >= 0.1) + pev->avelocity = vecDestDelta / time; + else + { + pev->avelocity = vecDestDelta; + pev->nextthink = pev->ltime + 1; + } +} + + +// +//====================== TRAIN code ================================================== +// + +class CFuncTrain : public CBasePlatTrain +{ +public: + void Spawn( void ); + void Precache( void ); + void Activate( void ); + void OverrideReset( void ); + + void Blocked( CBaseEntity *pOther ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + + + void EXPORT Wait( void ); + void EXPORT Next( void ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + entvars_t *m_pevCurrentTarget; + int m_sounds; + BOOL m_activated; +}; + +LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); +TYPEDESCRIPTION CFuncTrain::m_SaveData[] = +{ + DEFINE_FIELD( CFuncTrain, m_sounds, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTrain, m_pevCurrentTarget, FIELD_EVARS ), + DEFINE_FIELD( CFuncTrain, m_activated, FIELD_BOOLEAN ), +}; + +IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatTrain ); + + +void CFuncTrain :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "sounds")) + { + m_sounds = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBasePlatTrain::KeyValue( pkvd ); +} + + +void CFuncTrain :: Blocked( CBaseEntity *pOther ) + +{ + if ( gpGlobals->time < m_flActivateFinished) + return; + + m_flActivateFinished = gpGlobals->time + 0.5; + + pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); +} + + +void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) + { + // Move toward my target + pev->spawnflags &= ~SF_TRAIN_WAIT_RETRIGGER; + Next(); + } + else + { + pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; + // Pop back to last target if it's available + if ( pev->enemy ) + pev->target = pev->enemy->v.targetname; + pev->nextthink = 0; + pev->velocity = g_vecZero; + if ( pev->noiseStopMoving ) + EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); + } +} + + +void CFuncTrain :: Wait( void ) +{ + // Fire the pass target if there is one + if ( m_pevCurrentTarget->message ) + { + FireTargets( STRING(m_pevCurrentTarget->message), this, this, USE_TOGGLE, 0 ); + if ( FBitSet( m_pevCurrentTarget->spawnflags, SF_CORNER_FIREONCE ) ) + m_pevCurrentTarget->message = 0; + } + + // need pointer to LAST target. + if ( FBitSet (m_pevCurrentTarget->spawnflags , SF_TRAIN_WAIT_RETRIGGER ) || ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) ) + { + pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; + // clear the sound channel. + if ( pev->noiseMovement ) + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); + if ( pev->noiseStopMoving ) + EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); + pev->nextthink = 0; + return; + } + + // ALERT ( at_console, "%f\n", m_flWait ); + + if (m_flWait != 0) + {// -1 wait will wait forever! + pev->nextthink = pev->ltime + m_flWait; + if ( pev->noiseMovement ) + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); + if ( pev->noiseStopMoving ) + EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); + SetThink( &CFuncTrain::Next ); + } + else + { + Next();// do it RIGHT now! + } +} + + +// +// Train next - path corner needs to change to next target +// +void CFuncTrain :: Next( void ) +{ + CBaseEntity *pTarg; + + + // now find our next target + pTarg = GetNextTarget(); + + if ( !pTarg ) + { + if ( pev->noiseMovement ) + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); + // Play stop sound + if ( pev->noiseStopMoving ) + EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); + return; + } + + // Save last target in case we need to find it again + pev->message = pev->target; + + pev->target = pTarg->pev->target; + m_flWait = pTarg->GetDelay(); + + if ( m_pevCurrentTarget && m_pevCurrentTarget->speed != 0 ) + {// don't copy speed from target if it is 0 (uninitialized) + pev->speed = m_pevCurrentTarget->speed; + ALERT( at_aiconsole, "Train %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); + } + m_pevCurrentTarget = pTarg->pev;// keep track of this since path corners change our target for us. + + pev->enemy = pTarg->edict();//hack + + if(FBitSet(m_pevCurrentTarget->spawnflags, SF_CORNER_TELEPORT)) + { + // Path corner has indicated a teleport to the next corner. + SetBits(pev->effects, EF_NOINTERP); + UTIL_SetOrigin(pev, pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5); + Wait(); // Get on with doing the next path corner. + } + else + { + // Normal linear move. + + // CHANGED this from CHAN_VOICE to CHAN_STATIC around OEM beta time because trains should + // use CHAN_STATIC for their movement sounds to prevent sound field problems. + // this is not a hack or temporary fix, this is how things should be. (sjb). + if ( pev->noiseMovement ) + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); + if ( pev->noiseMovement ) + EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); + ClearBits(pev->effects, EF_NOINTERP); + SetMoveDone( &CFuncTrain::Wait ); + LinearMove (pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5, pev->speed); + } +} + + +void CFuncTrain :: Activate( void ) +{ + // Not yet active, so teleport to first target + if ( !m_activated ) + { + m_activated = TRUE; + entvars_t *pevTarg = VARS( FIND_ENTITY_BY_TARGETNAME (NULL, STRING(pev->target) ) ); + + pev->target = pevTarg->target; + m_pevCurrentTarget = pevTarg;// keep track of this since path corners change our target for us. + + UTIL_SetOrigin (pev, pevTarg->origin - (pev->mins + pev->maxs) * 0.5 ); + + if ( FStringNull(pev->targetname) ) + { // not triggered, so start immediately + pev->nextthink = pev->ltime + 0.1; + SetThink( &CFuncTrain::Next ); + } + else + pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; + } +} + +/*QUAKED func_train (0 .5 .8) ? +Trains are moving platforms that players can ride. +The targets origin specifies the min point of the train at each corner. +The train spawns at the first target it is pointing at. +If the train is the target of a button or trigger, it will not begin moving until activated. +speed default 100 +dmg default 2 +sounds +1) ratchet metal +*/ + +void CFuncTrain :: Spawn( void ) +{ + Precache(); + if (pev->speed == 0) + pev->speed = 100; + + if ( FStringNull(pev->target) ) + ALERT(at_console, "FuncTrain with no target"); + + if (pev->dmg == 0) + pev->dmg = 2; + + pev->movetype = MOVETYPE_PUSH; + + if ( FBitSet (pev->spawnflags, SF_TRACKTRAIN_PASSABLE) ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + + SET_MODEL( ENT(pev), STRING(pev->model) ); + UTIL_SetSize (pev, pev->mins, pev->maxs); + UTIL_SetOrigin(pev, pev->origin); + + m_activated = FALSE; + + if ( m_volume == 0 ) + m_volume = 0.85; +} + + +void CFuncTrain::Precache( void ) +{ + CBasePlatTrain::Precache(); + +#if 0 // obsolete + // otherwise use preset sound + switch (m_sounds) + { + case 0: + pev->noise = 0; + pev->noise1 = 0; + break; + + case 1: + PRECACHE_SOUND ("plats/train2.wav"); + PRECACHE_SOUND ("plats/train1.wav"); + pev->noise = MAKE_STRING("plats/train2.wav"); + pev->noise1 = MAKE_STRING("plats/train1.wav"); + break; + + case 2: + PRECACHE_SOUND ("plats/platmove1.wav"); + PRECACHE_SOUND ("plats/platstop1.wav"); + pev->noise = MAKE_STRING("plats/platstop1.wav"); + pev->noise1 = MAKE_STRING("plats/platmove1.wav"); + break; + } +#endif +} + + +void CFuncTrain::OverrideReset( void ) +{ + CBaseEntity *pTarg; + + // Are we moving? + if ( pev->velocity != g_vecZero && pev->nextthink != 0 ) + { + pev->target = pev->message; + // now find our next target + pTarg = GetNextTarget(); + if ( !pTarg ) + { + pev->nextthink = 0; + pev->velocity = g_vecZero; + } + else // Keep moving for 0.1 secs, then find path_corner again and restart + { + SetThink( &CFuncTrain::Next ); + pev->nextthink = pev->ltime + 0.1; + } + } +} + + + + +// --------------------------------------------------------------------- +// +// Track Train +// +// --------------------------------------------------------------------- + +TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = +{ + DEFINE_FIELD( CFuncTrackTrain, m_ppath, FIELD_CLASSPTR ), + DEFINE_FIELD( CFuncTrackTrain, m_length, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_height, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_speed, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_dir, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_startSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_controlMins, FIELD_VECTOR ), + DEFINE_FIELD( CFuncTrackTrain, m_controlMaxs, FIELD_VECTOR ), + DEFINE_FIELD( CFuncTrackTrain, m_sounds, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTrackTrain, m_flVolume, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_flBank, FIELD_FLOAT ), + DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ); +LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); + +void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "wheels")) + { + m_length = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "height")) + { + m_height = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "startspeed")) + { + m_startSpeed = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "sounds")) + { + m_sounds = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "volume")) + { + m_flVolume = (float) (atoi(pkvd->szValue)); + m_flVolume *= 0.1; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "bank")) + { + m_flBank = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + + +void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) +{ + if ( alwaysThink ) + pev->flags |= FL_ALWAYSTHINK; + else + pev->flags &= ~FL_ALWAYSTHINK; + + pev->nextthink = thinkTime; +} + + +void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + // Blocker is on-ground on the train + if ( FBitSet( pevOther->flags, FL_ONGROUND ) && VARS(pevOther->groundentity) == pev ) + { + float deltaSpeed = fabs(pev->speed); + if ( deltaSpeed > 50 ) + deltaSpeed = 50; + if ( !pevOther->velocity.z ) + pevOther->velocity.z += deltaSpeed; + return; + } + else + pevOther->velocity = (pevOther->origin - pev->origin ).Normalize() * pev->dmg; + + ALERT( at_aiconsole, "TRAIN(%s): Blocked by %s (dmg:%.2f)\n", STRING(pev->targetname), STRING(pOther->pev->classname), pev->dmg ); + if ( pev->dmg <= 0 ) + return; + // we can't hurt this thing, so we're not concerned with it + pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); +} + + +void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( useType != USE_SET ) + { + if ( !ShouldToggle( useType, (pev->speed != 0) ) ) + return; + + if ( pev->speed == 0 ) + { + pev->speed = m_speed * m_dir; + + Next(); + } + else + { + pev->speed = 0; + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + StopSound(); + SetThink( NULL ); + } + } + else + { + float delta = value; + + delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; + if ( delta > 1 ) + delta = 1; + else if ( delta < -1 ) + delta = -1; + if ( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) + { + if ( delta < 0 ) + delta = 0; + } + pev->speed = m_speed * delta; + Next(); + ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING(pev->targetname), pev->speed ); + } +} + + +static float Fix( float angle ) +{ + while ( angle < 0 ) + angle += 360; + while ( angle > 360 ) + angle -= 360; + + return angle; +} + + +static void FixupAngles( Vector &v ) +{ + v.x = Fix( v.x ); + v.y = Fix( v.y ); + v.z = Fix( v.z ); +} + +#define TRAIN_STARTPITCH 60 +#define TRAIN_MAXPITCH 200 +#define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation + +void CFuncTrackTrain :: StopSound( void ) +{ + // if sound playing, stop it + if (m_soundPlaying && pev->noise) + { + unsigned short us_encode; + unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; + + us_encode = us_sound; + + PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, + (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 ); + + /* + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); + */ + EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100); + } + + m_soundPlaying = 0; +} + +// update pitch based on speed, start sound if not playing +// NOTE: when train goes through transition, m_soundPlaying should go to 0, +// which will cause the looped sound to restart. + +void CFuncTrackTrain :: UpdateSound( void ) +{ + float flpitch; + + if (!pev->noise) + return; + + flpitch = TRAIN_STARTPITCH + (abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); + + if (!m_soundPlaying) + { + // play startup sound for train + EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100); + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, (int) flpitch); + m_soundPlaying = 1; + } + else + { +/* + // update pitch + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int) flpitch); +*/ + // volume 0.0 - 1.0 - 6 bits + // m_sounds 3 bits + // flpitch = 6 bits + // 15 bits total + + unsigned short us_encode; + unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; + unsigned short us_pitch = ( ( unsigned short )( flpitch / 10.0 ) & 0x003f ) << 6; + unsigned short us_volume = ( ( unsigned short )( m_flVolume * 40.0 ) & 0x003f ); + + us_encode = us_sound | us_pitch | us_volume; + + PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, + (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 ); + } +} + + +void CFuncTrackTrain :: Next( void ) +{ + float time = 0.5; + + if ( !pev->speed ) + { + ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); + StopSound(); + return; + } + +// if ( !m_ppath ) +// m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); + if ( !m_ppath ) + { + ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING(pev->targetname) ); + StopSound(); + return; + } + + UpdateSound(); + + Vector nextPos = pev->origin; + + nextPos.z -= m_height; + CPathTrack *pnext = m_ppath->LookAhead( &nextPos, pev->speed * 0.1, 1 ); + nextPos.z += m_height; + + pev->velocity = (nextPos - pev->origin) * 10; + Vector nextFront = pev->origin; + + nextFront.z -= m_height; + if ( m_length > 0 ) + m_ppath->LookAhead( &nextFront, m_length, 0 ); + else + m_ppath->LookAhead( &nextFront, 100, 0 ); + nextFront.z += m_height; + + Vector delta = nextFront - pev->origin; + Vector angles = UTIL_VecToAngles( delta ); + // The train actually points west + angles.y += 180; + + // !!! All of this crap has to be done to make the angles not wrap around, revisit this. + FixupAngles( angles ); + FixupAngles( pev->angles ); + + if ( !pnext || (delta.x == 0 && delta.y == 0) ) + angles = pev->angles; + + float vy, vx; + if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) + vx = UTIL_AngleDistance( angles.x, pev->angles.x ); + else + vx = 0; + vy = UTIL_AngleDistance( angles.y, pev->angles.y ); + + pev->avelocity.y = vy * 10; + pev->avelocity.x = vx * 10; + + if ( m_flBank != 0 ) + { + if ( pev->avelocity.y < -5 ) + pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( -m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); + else if ( pev->avelocity.y > 5 ) + pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); + else + pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank*4 ), pev->angles.z) * 4; + } + + if ( pnext ) + { + if ( pnext != m_ppath ) + { + CPathTrack *pFire; + if ( pev->speed >= 0 ) + pFire = pnext; + else + pFire = m_ppath; + + m_ppath = pnext; + // Fire the pass target if there is one + if ( pFire->pev->message ) + { + FireTargets( STRING(pFire->pev->message), this, this, USE_TOGGLE, 0 ); + if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) + pFire->pev->message = 0; + } + + if ( pFire->pev->spawnflags & SF_PATH_DISABLE_TRAIN ) + pev->spawnflags |= SF_TRACKTRAIN_NOCONTROL; + + // Don't override speed if under user control + if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) + { + if ( pFire->pev->speed != 0 ) + {// don't copy speed from target if it is 0 (uninitialized) + pev->speed = pFire->pev->speed; + ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); + } + } + + } + SetThink( &CFuncTrackTrain::Next ); + NextThink( pev->ltime + time, TRUE ); + } + else // end of path, stop + { + StopSound(); + pev->velocity = (nextPos - pev->origin); + pev->avelocity = g_vecZero; + float distance = pev->velocity.Length(); + m_oldSpeed = pev->speed; + + + pev->speed = 0; + + // Move to the dead end + + // Are we there yet? + if ( distance > 0 ) + { + // no, how long to get there? + time = distance / m_oldSpeed; + pev->velocity = pev->velocity * (m_oldSpeed / distance); + SetThink( &CFuncTrackTrain::DeadEnd ); + NextThink( pev->ltime + time, FALSE ); + } + else + { + DeadEnd(); + } + } +} + + +void CFuncTrackTrain::DeadEnd( void ) +{ + // Fire the dead-end target if there is one + CPathTrack *pTrack, *pNext; + + pTrack = m_ppath; + + ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); + // Find the dead end path node + // HACKHACK -- This is bugly, but the train can actually stop moving at a different node depending on it's speed + // so we have to traverse the list to it's end. + if ( pTrack ) + { + if ( m_oldSpeed < 0 ) + { + do + { + pNext = pTrack->ValidPath( pTrack->GetPrevious(), TRUE ); + if ( pNext ) + pTrack = pNext; + } while ( pNext ); + } + else + { + do + { + pNext = pTrack->ValidPath( pTrack->GetNext(), TRUE ); + if ( pNext ) + pTrack = pNext; + } while ( pNext ); + } + } + + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + if ( pTrack ) + { + ALERT( at_aiconsole, "at %s\n", STRING(pTrack->pev->targetname) ); + if ( pTrack->pev->netname ) + FireTargets( STRING(pTrack->pev->netname), this, this, USE_TOGGLE, 0 ); + } + else + ALERT( at_aiconsole, "\n" ); +} + + +void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) +{ + Vector offset = pevControls->origin - pev->oldorigin; + + m_controlMins = pevControls->mins + offset; + m_controlMaxs = pevControls->maxs + offset; +} + + +BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) +{ + Vector offset = pevTest->origin - pev->origin; + + if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) + return FALSE; + + // Transform offset into local coordinates + UTIL_MakeVectors( pev->angles ); + Vector local; + local.x = DotProduct( offset, gpGlobals->v_forward ); + local.y = -DotProduct( offset, gpGlobals->v_right ); + local.z = DotProduct( offset, gpGlobals->v_up ); + + if ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z && + local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ) + return TRUE; + + return FALSE; +} + + +void CFuncTrackTrain :: Find( void ) +{ + m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); + if ( !m_ppath ) + return; + + entvars_t *pevTarget = m_ppath->pev; + if ( !FClassnameIs( pevTarget, "path_track" ) ) + { + ALERT( at_error, "func_track_train must be on a path of path_track\n" ); + m_ppath = NULL; + return; + } + + Vector nextPos = pevTarget->origin; + nextPos.z += m_height; + + Vector look = nextPos; + look.z -= m_height; + m_ppath->LookAhead( &look, m_length, 0 ); + look.z += m_height; + + pev->angles = UTIL_VecToAngles( look - nextPos ); + // The train actually points west + pev->angles.y += 180; + + if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) + pev->angles.x = 0; + UTIL_SetOrigin( pev, nextPos ); + NextThink( pev->ltime + 0.1, FALSE ); + SetThink( &CFuncTrackTrain::Next ); + pev->speed = m_startSpeed; + + UpdateSound(); +} + + +void CFuncTrackTrain :: NearestPath( void ) +{ + CBaseEntity *pTrack = NULL; + CBaseEntity *pNearest = NULL; + float dist, closest; + + closest = 1024; + + while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) + { + // filter out non-tracks + if ( !(pTrack->pev->flags & (FL_CLIENT|FL_MONSTER)) && FClassnameIs( pTrack->pev, "path_track" ) ) + { + dist = (pev->origin - pTrack->pev->origin).Length(); + if ( dist < closest ) + { + closest = dist; + pNearest = pTrack; + } + } + } + + if ( !pNearest ) + { + ALERT( at_console, "Can't find a nearby track !!!\n" ); + SetThink(NULL); + return; + } + + ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING(pev->targetname), STRING(pNearest->pev->targetname) ); + // If I'm closer to the next path_track on this path, then it's my real path + pTrack = ((CPathTrack *)pNearest)->GetNext(); + if ( pTrack ) + { + if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) + pNearest = pTrack; + } + + m_ppath = (CPathTrack *)pNearest; + + if ( pev->speed != 0 ) + { + NextThink( pev->ltime + 0.1, FALSE ); + SetThink( &CFuncTrackTrain::Next ); + } +} + + +void CFuncTrackTrain::OverrideReset( void ) +{ + NextThink( pev->ltime + 0.1, FALSE ); + SetThink( &CFuncTrackTrain::NearestPath ); +} + + +CFuncTrackTrain *CFuncTrackTrain::Instance( edict_t *pent ) +{ + if ( FClassnameIs( pent, "func_tracktrain" ) ) + return (CFuncTrackTrain *)GET_PRIVATE(pent); + return NULL; +} + +/*QUAKED func_train (0 .5 .8) ? +Trains are moving platforms that players can ride. +The targets origin specifies the min point of the train at each corner. +The train spawns at the first target it is pointing at. +If the train is the target of a button or trigger, it will not begin moving until activated. +speed default 100 +dmg default 2 +sounds +1) ratchet metal +*/ + +void CFuncTrackTrain :: Spawn( void ) +{ + if ( pev->speed == 0 ) + m_speed = 100; + else + m_speed = pev->speed; + + pev->speed = 0; + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + pev->impulse = m_speed; + + m_dir = 1; + + if ( FStringNull(pev->target) ) + ALERT( at_console, "FuncTrain with no target" ); + + if ( pev->spawnflags & SF_TRACKTRAIN_PASSABLE ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + + SET_MODEL( ENT(pev), STRING(pev->model) ); + + UTIL_SetSize( pev, pev->mins, pev->maxs ); + UTIL_SetOrigin( pev, pev->origin ); + + // Cache off placed origin for train controls + pev->oldorigin = pev->origin; + + m_controlMins = pev->mins; + m_controlMaxs = pev->maxs; + m_controlMaxs.z += 72; +// start trains on the next frame, to make sure their targets have had +// a chance to spawn/activate + NextThink( pev->ltime + 0.1, FALSE ); + SetThink( &CFuncTrackTrain::Find ); + Precache(); +} + +void CFuncTrackTrain :: Precache( void ) +{ + if (m_flVolume == 0.0) + m_flVolume = 1.0; + + switch (m_sounds) + { + default: + // no sound + pev->noise = 0; + break; + case 1: PRECACHE_SOUND("plats/ttrain1.wav"); pev->noise = MAKE_STRING("plats/ttrain1.wav");break; + case 2: PRECACHE_SOUND("plats/ttrain2.wav"); pev->noise = MAKE_STRING("plats/ttrain2.wav");break; + case 3: PRECACHE_SOUND("plats/ttrain3.wav"); pev->noise = MAKE_STRING("plats/ttrain3.wav");break; + case 4: PRECACHE_SOUND("plats/ttrain4.wav"); pev->noise = MAKE_STRING("plats/ttrain4.wav");break; + case 5: PRECACHE_SOUND("plats/ttrain6.wav"); pev->noise = MAKE_STRING("plats/ttrain6.wav");break; + case 6: PRECACHE_SOUND("plats/ttrain7.wav"); pev->noise = MAKE_STRING("plats/ttrain7.wav");break; + } + + PRECACHE_SOUND("plats/ttrain_brake1.wav"); + PRECACHE_SOUND("plats/ttrain_start1.wav"); + + m_usAdjustPitch = PRECACHE_EVENT( 1, "events/train.sc" ); +} + +// This class defines the volume of space that the player must stand in to control the train +class CFuncTrainControls : public CBaseEntity +{ +public: + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + void Spawn( void ); + void EXPORT Find( void ); +}; +LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ); + + +void CFuncTrainControls :: Find( void ) +{ + edict_t *pTarget = NULL; + + do + { + pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); + } while ( !FNullEnt(pTarget) && !FClassnameIs(pTarget, "func_tracktrain") ); + + if ( FNullEnt( pTarget ) ) + { + ALERT( at_console, "No train %s\n", STRING(pev->target) ); + return; + } + + CFuncTrackTrain *ptrain = CFuncTrackTrain::Instance(pTarget); + ptrain->SetControls( pev ); + UTIL_Remove( this ); +} + + +void CFuncTrainControls :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + SET_MODEL( ENT(pev), STRING(pev->model) ); + + UTIL_SetSize( pev, pev->mins, pev->maxs ); + UTIL_SetOrigin( pev, pev->origin ); + + SetThink( &CFuncTrainControls::Find ); + pev->nextthink = gpGlobals->time; +} + + + +// ---------------------------------------------------------------------------- +// +// Track changer / Train elevator +// +// ---------------------------------------------------------------------------- + +#define SF_TRACK_ACTIVATETRAIN 0x00000001 +#define SF_TRACK_RELINK 0x00000002 +#define SF_TRACK_ROTMOVE 0x00000004 +#define SF_TRACK_STARTBOTTOM 0x00000008 +#define SF_TRACK_DONT_MOVE 0x00000010 + +// +// This entity is a rotating/moving platform that will carry a train to a new track. +// It must be larger in X-Y planar area than the train, since it must contain the +// train within these dimensions in order to operate when the train is near it. +// + +typedef enum { TRAIN_SAFE, TRAIN_BLOCKING, TRAIN_FOLLOWING } TRAIN_CODE; + +class CFuncTrackChange : public CFuncPlatRot +{ +public: + void Spawn( void ); + void Precache( void ); + +// virtual void Blocked( void ); + virtual void EXPORT GoUp( void ); + virtual void EXPORT GoDown( void ); + + void KeyValue( KeyValueData* pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT Find( void ); + TRAIN_CODE EvaluateTrain( CPathTrack *pcurrent ); + void UpdateTrain( Vector &dest ); + virtual void HitBottom( void ); + virtual void HitTop( void ); + void Touch( CBaseEntity *pOther ); + virtual void UpdateAutoTargets( int toggleState ); + virtual BOOL IsTogglePlat( void ) { return TRUE; } + + void DisableUse( void ) { m_use = 0; } + void EnableUse( void ) { m_use = 1; } + int UseEnabled( void ) { return m_use; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + virtual void OverrideReset( void ); + + + CPathTrack *m_trackTop; + CPathTrack *m_trackBottom; + + CFuncTrackTrain *m_train; + + int m_trackTopName; + int m_trackBottomName; + int m_trainName; + TRAIN_CODE m_code; + int m_targetState; + int m_use; +}; +LINK_ENTITY_TO_CLASS( func_trackchange, CFuncTrackChange ); + +TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = +{ + DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTop, FIELD_CLASSPTR ), + DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottom, FIELD_CLASSPTR ), + DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_train, FIELD_CLASSPTR ), + DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTopName, FIELD_STRING ), + DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottomName, FIELD_STRING ), + DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trainName, FIELD_STRING ), + DEFINE_FIELD( CFuncTrackChange, m_code, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTrackChange, m_targetState, FIELD_INTEGER ), + DEFINE_FIELD( CFuncTrackChange, m_use, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ); + +void CFuncTrackChange :: Spawn( void ) +{ + Setup(); + if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) + m_vecPosition2.z = pev->origin.z; + + SetupRotation(); + + if ( FBitSet( pev->spawnflags, SF_TRACK_STARTBOTTOM ) ) + { + UTIL_SetOrigin (pev, m_vecPosition2); + m_toggle_state = TS_AT_BOTTOM; + pev->angles = m_start; + m_targetState = TS_AT_TOP; + } + else + { + UTIL_SetOrigin (pev, m_vecPosition1); + m_toggle_state = TS_AT_TOP; + pev->angles = m_end; + m_targetState = TS_AT_BOTTOM; + } + + EnableUse(); + pev->nextthink = pev->ltime + 2.0; + SetThink( &CFuncTrackChange::Find ); + Precache(); +} + +void CFuncTrackChange :: Precache( void ) +{ + // Can't trigger sound + PRECACHE_SOUND( "buttons/button11.wav" ); + + CFuncPlatRot::Precache(); +} + + +// UNDONE: Filter touches before re-evaluating the train. +void CFuncTrackChange :: Touch( CBaseEntity *pOther ) +{ +#if 0 + TRAIN_CODE code; + entvars_t *pevToucher = pOther->pev; +#endif +} + + + +void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) +{ + if ( FStrEq(pkvd->szKeyName, "train") ) + { + m_trainName = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "toptrack") ) + { + m_trackTopName = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "bottomtrack") ) + { + m_trackBottomName = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + { + CFuncPlatRot::KeyValue( pkvd ); // Pass up to base class + } +} + + +void CFuncTrackChange::OverrideReset( void ) +{ + pev->nextthink = pev->ltime + 1.0; + SetThink( &CFuncTrackChange::Find ); +} + +void CFuncTrackChange :: Find( void ) +{ + // Find track entities + edict_t *target; + + target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackTopName) ); + if ( !FNullEnt(target) ) + { + m_trackTop = CPathTrack::Instance( target ); + target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackBottomName) ); + if ( !FNullEnt(target) ) + { + m_trackBottom = CPathTrack::Instance( target ); + target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); + if ( !FNullEnt(target) ) + { + m_train = CFuncTrackTrain::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ) ); + if ( !m_train ) + { + ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); + return; + } + Vector center = (pev->absmin + pev->absmax) * 0.5; + m_trackBottom = m_trackBottom->Nearest( center ); + m_trackTop = m_trackTop->Nearest( center ); + UpdateAutoTargets( m_toggle_state ); + SetThink( NULL ); + return; + } + else + { + ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); + target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); + } + } + else + ALERT( at_error, "Can't find bottom track for track change! %s\n", STRING(m_trackBottomName) ); + } + else + ALERT( at_error, "Can't find top track for track change! %s\n", STRING(m_trackTopName) ); +} + + + +TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) +{ + // Go ahead and work, we don't have anything to switch, so just be an elevator + if ( !pcurrent || !m_train ) + return TRAIN_SAFE; + + if ( m_train->m_ppath == pcurrent || (pcurrent->m_pprevious && m_train->m_ppath == pcurrent->m_pprevious) || + (pcurrent->m_pnext && m_train->m_ppath == pcurrent->m_pnext) ) + { + if ( m_train->pev->speed != 0 ) + return TRAIN_BLOCKING; + + Vector dist = pev->origin - m_train->pev->origin; + float length = dist.Length2D(); + if ( length < m_train->m_length ) // Empirically determined close distance + return TRAIN_FOLLOWING; + else if ( length > (150 + m_train->m_length) ) + return TRAIN_SAFE; + + return TRAIN_BLOCKING; + } + + return TRAIN_SAFE; +} + + +void CFuncTrackChange :: UpdateTrain( Vector &dest ) +{ + float time = (pev->nextthink - pev->ltime); + + m_train->pev->velocity = pev->velocity; + m_train->pev->avelocity = pev->avelocity; + m_train->NextThink( m_train->pev->ltime + time, FALSE ); + + // Attempt at getting the train to rotate properly around the origin of the trackchange + if ( time <= 0 ) + return; + + Vector offset = m_train->pev->origin - pev->origin; + Vector delta = dest - pev->angles; + // Transform offset into local coordinates + UTIL_MakeInvVectors( delta, gpGlobals ); + Vector local; + local.x = DotProduct( offset, gpGlobals->v_forward ); + local.y = DotProduct( offset, gpGlobals->v_right ); + local.z = DotProduct( offset, gpGlobals->v_up ); + + local = local - offset; + m_train->pev->velocity = pev->velocity + (local * (1.0/time)); +} + +void CFuncTrackChange :: GoDown( void ) +{ + if ( m_code == TRAIN_BLOCKING ) + return; + + // HitBottom may get called during CFuncPlat::GoDown(), so set up for that + // before you call GoDown() + + UpdateAutoTargets( TS_GOING_DOWN ); + // If ROTMOVE, move & rotate + if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) + { + SetMoveDone( &CFuncTrackChange::CallHitBottom ); + m_toggle_state = TS_GOING_DOWN; + AngularMove( m_start, pev->speed ); + } + else + { + CFuncPlat :: GoDown(); + SetMoveDone( &CFuncTrackChange::CallHitBottom ); + RotMove( m_start, pev->nextthink - pev->ltime ); + } + // Otherwise, rotate first, move second + + // If the train is moving with the platform, update it + if ( m_code == TRAIN_FOLLOWING ) + { + UpdateTrain( m_start ); + m_train->m_ppath = NULL; + } +} + + +// +// Platform is at bottom, now starts moving up +// +void CFuncTrackChange :: GoUp( void ) +{ + if ( m_code == TRAIN_BLOCKING ) + return; + + // HitTop may get called during CFuncPlat::GoUp(), so set up for that + // before you call GoUp(); + + UpdateAutoTargets( TS_GOING_UP ); + if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) + { + m_toggle_state = TS_GOING_UP; + SetMoveDone( &CFuncTrackChange::CallHitTop ); + AngularMove( m_end, pev->speed ); + } + else + { + // If ROTMOVE, move & rotate + CFuncPlat :: GoUp(); + SetMoveDone( &CFuncTrackChange::CallHitTop ); + RotMove( m_end, pev->nextthink - pev->ltime ); + } + + // Otherwise, move first, rotate second + + // If the train is moving with the platform, update it + if ( m_code == TRAIN_FOLLOWING ) + { + UpdateTrain( m_end ); + m_train->m_ppath = NULL; + } +} + + +// Normal track change +void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) +{ + if ( !m_trackTop || !m_trackBottom ) + return; + + if ( toggleState == TS_AT_TOP ) + ClearBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); + else + SetBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); + + if ( toggleState == TS_AT_BOTTOM ) + ClearBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); + else + SetBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); +} + + +void CFuncTrackChange :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( m_toggle_state != TS_AT_TOP && m_toggle_state != TS_AT_BOTTOM ) + return; + + // If train is in "safe" area, but not on the elevator, play alarm sound + if ( m_toggle_state == TS_AT_TOP ) + m_code = EvaluateTrain( m_trackTop ); + else if ( m_toggle_state == TS_AT_BOTTOM ) + m_code = EvaluateTrain( m_trackBottom ); + else + m_code = TRAIN_BLOCKING; + if ( m_code == TRAIN_BLOCKING ) + { + // Play alarm and return + EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/button11.wav", 1, ATTN_NORM); + return; + } + + // Otherwise, it's safe to move + // If at top, go down + // at bottom, go up + + DisableUse(); + if (m_toggle_state == TS_AT_TOP) + GoDown(); + else + GoUp(); +} + + +// +// Platform has hit bottom. Stops and waits forever. +// +void CFuncTrackChange :: HitBottom( void ) +{ + CFuncPlatRot :: HitBottom(); + if ( m_code == TRAIN_FOLLOWING ) + { +// UpdateTrain(); + m_train->SetTrack( m_trackBottom ); + } + SetThink( NULL ); + pev->nextthink = -1; + + UpdateAutoTargets( m_toggle_state ); + + EnableUse(); +} + + +// +// Platform has hit bottom. Stops and waits forever. +// +void CFuncTrackChange :: HitTop( void ) +{ + CFuncPlatRot :: HitTop(); + if ( m_code == TRAIN_FOLLOWING ) + { +// UpdateTrain(); + m_train->SetTrack( m_trackTop ); + } + + // Don't let the plat go back down + SetThink( NULL ); + pev->nextthink = -1; + UpdateAutoTargets( m_toggle_state ); + EnableUse(); +} + + + +class CFuncTrackAuto : public CFuncTrackChange +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void UpdateAutoTargets( int toggleState ); +}; + +LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ); + +// Auto track change +void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) +{ + CPathTrack *pTarget, *pNextTarget; + + if ( !m_trackTop || !m_trackBottom ) + return; + + if ( m_targetState == TS_AT_TOP ) + { + pTarget = m_trackTop->GetNext(); + pNextTarget = m_trackBottom->GetNext(); + } + else + { + pTarget = m_trackBottom->GetNext(); + pNextTarget = m_trackTop->GetNext(); + } + if ( pTarget ) + { + ClearBits( pTarget->pev->spawnflags, SF_PATH_DISABLED ); + if ( m_code == TRAIN_FOLLOWING && m_train && m_train->pev->speed == 0 ) + m_train->Use( this, this, USE_ON, 0 ); + } + + if ( pNextTarget ) + SetBits( pNextTarget->pev->spawnflags, SF_PATH_DISABLED ); + +} + + +void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CPathTrack *pTarget; + + if ( !UseEnabled() ) + return; + + if ( m_toggle_state == TS_AT_TOP ) + pTarget = m_trackTop; + else if ( m_toggle_state == TS_AT_BOTTOM ) + pTarget = m_trackBottom; + else + pTarget = NULL; + + if ( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) + { + m_code = EvaluateTrain( pTarget ); + // Safe to fire? + if ( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) + { + DisableUse(); + if (m_toggle_state == TS_AT_TOP) + GoDown(); + else + GoUp(); + } + } + else + { + if ( pTarget ) + pTarget = pTarget->GetNext(); + if ( pTarget && m_train->m_ppath != pTarget && ShouldToggle( useType, m_targetState ) ) + { + if ( m_targetState == TS_AT_TOP ) + m_targetState = TS_AT_BOTTOM; + else + m_targetState = TS_AT_TOP; + } + + UpdateAutoTargets( m_targetState ); + } +} + + +// ---------------------------------------------------------- +// +// +// pev->speed is the travel speed +// pev->health is current health +// pev->max_health is the amount to reset to each time it starts + +#define FGUNTARGET_START_ON 0x0001 + +class CGunTarget : public CBaseMonster +{ +public: + void Spawn( void ); + void Activate( void ); + void EXPORT Next( void ); + void EXPORT Start( void ); + void EXPORT Wait( void ); + void Stop( void ); + + int BloodColor( void ) { return DONT_BLEED; } + int Classify( void ) { return CLASS_MACHINE; } + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + Vector BodyTarget( const Vector &posSrc ) { return pev->origin; } + + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + BOOL m_on; +}; + + +LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ); + +TYPEDESCRIPTION CGunTarget::m_SaveData[] = +{ + DEFINE_FIELD( CGunTarget, m_on, FIELD_BOOLEAN ), +}; + +IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ); + + +void CGunTarget::Spawn( void ) +{ + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + + UTIL_SetOrigin(pev, pev->origin); + SET_MODEL(ENT(pev), STRING(pev->model) ); + + if ( pev->speed == 0 ) + pev->speed = 100; + + // Don't take damage until "on" + pev->takedamage = DAMAGE_NO; + pev->flags |= FL_MONSTER; + + m_on = FALSE; + pev->max_health = pev->health; + + if ( pev->spawnflags & FGUNTARGET_START_ON ) + { + SetThink( &CGunTarget::Start ); + pev->nextthink = pev->ltime + 0.3; + } +} + + +void CGunTarget::Activate( void ) +{ + CBaseEntity *pTarg; + + // now find our next target + pTarg = GetNextTarget(); + if ( pTarg ) + { + m_hTargetEnt = pTarg; + UTIL_SetOrigin( pev, pTarg->pev->origin - (pev->mins + pev->maxs) * 0.5 ); + } +} + + +void CGunTarget::Start( void ) +{ + Use( this, this, USE_ON, 0 ); +} + + +void CGunTarget::Next( void ) +{ + SetThink( NULL ); + + m_hTargetEnt = GetNextTarget(); + CBaseEntity *pTarget = m_hTargetEnt; + + if ( !pTarget ) + { + Stop(); + return; + } + SetMoveDone( &CGunTarget::Wait ); + LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); +} + + +void CGunTarget::Wait( void ) +{ + CBaseEntity *pTarget = m_hTargetEnt; + + if ( !pTarget ) + { + Stop(); + return; + } + + // Fire the pass target if there is one + if ( pTarget->pev->message ) + { + FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); + if ( FBitSet( pTarget->pev->spawnflags, SF_CORNER_FIREONCE ) ) + pTarget->pev->message = 0; + } + + m_flWait = pTarget->GetDelay(); + + pev->target = pTarget->pev->target; + SetThink( &CGunTarget::Next ); + if (m_flWait != 0) + {// -1 wait will wait forever! + pev->nextthink = pev->ltime + m_flWait; + } + else + { + Next();// do it RIGHT now! + } +} + + +void CGunTarget::Stop( void ) +{ + pev->velocity = g_vecZero; + pev->nextthink = 0; + pev->takedamage = DAMAGE_NO; +} + + +int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + if ( pev->health > 0 ) + { + pev->health -= flDamage; + if ( pev->health <= 0 ) + { + pev->health = 0; + Stop(); + if ( pev->message ) + FireTargets( STRING(pev->message), this, this, USE_TOGGLE, 0 ); + } + } + return 0; +} + + +void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_on ) ) + return; + + if ( m_on ) + { + Stop(); + } + else + { + pev->takedamage = DAMAGE_AIM; + m_hTargetEnt = GetNextTarget(); + if ( m_hTargetEnt == NULL ) + return; + pev->health = pev->max_health; + Next(); + } +} + + + diff --git a/main/source/dlls/plats.cpp~ b/main/source/dlls/plats.cpp~ deleted file mode 100644 index 01c1199c..00000000 --- a/main/source/dlls/plats.cpp~ +++ /dev/null @@ -1,2266 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== plats.cpp ======================================================== - - spawn, think, and touch functions for trains, etc - -*/ - -//#include "extdll.h" -//#include "util.h" -//#include "cbase.h" -//#include "trains.h" -//#include "saverestore.h" -#include -#include "dlls/plats.h" - -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform); - -TYPEDESCRIPTION CBasePlatTrain::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlatTrain, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBasePlatTrain, m_bStopSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBasePlatTrain, m_volume, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBasePlatTrain, CBaseToggle ); - -void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lip")) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_flHeight = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotation")) - { - m_vecFinalAngle.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - m_volume = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -#define noiseMoving noise -#define noiseArrived noise1 - -void CBasePlatTrain::Precache( void ) -{ -// set the plat's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = MAKE_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("plats/bigmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove1.wav"); - break; - case 2: - PRECACHE_SOUND ("plats/bigmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove2.wav"); - break; - case 3: - PRECACHE_SOUND ("plats/elevmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove1.wav"); - break; - case 4: - PRECACHE_SOUND ("plats/elevmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove2.wav"); - break; - case 5: - PRECACHE_SOUND ("plats/elevmove3.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove3.wav"); - break; - case 6: - PRECACHE_SOUND ("plats/freightmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/freightmove1.wav"); - break; - case 7: - PRECACHE_SOUND ("plats/freightmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/freightmove2.wav"); - break; - case 8: - PRECACHE_SOUND ("plats/heavymove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/heavymove1.wav"); - break; - case 9: - PRECACHE_SOUND ("plats/rackmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/rackmove1.wav"); - break; - case 10: - PRECACHE_SOUND ("plats/railmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/railmove1.wav"); - break; - case 11: - PRECACHE_SOUND ("plats/squeekmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/squeekmove1.wav"); - break; - case 12: - PRECACHE_SOUND ("plats/talkmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/talkmove1.wav"); - break; - case 13: - PRECACHE_SOUND ("plats/talkmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/talkmove2.wav"); - break; - default: - pev->noiseMoving = MAKE_STRING("common/null.wav"); - break; - } - -// set the plat's 'reached destination' stop sound - switch (m_bStopSnd) - { - case 0: - pev->noiseArrived = MAKE_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("plats/bigstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop1.wav"); - break; - case 2: - PRECACHE_SOUND ("plats/bigstop2.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop2.wav"); - break; - case 3: - PRECACHE_SOUND ("plats/freightstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/freightstop1.wav"); - break; - case 4: - PRECACHE_SOUND ("plats/heavystop2.wav"); - pev->noiseArrived = MAKE_STRING("plats/heavystop2.wav"); - break; - case 5: - PRECACHE_SOUND ("plats/rackstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/rackstop1.wav"); - break; - case 6: - PRECACHE_SOUND ("plats/railstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/railstop1.wav"); - break; - case 7: - PRECACHE_SOUND ("plats/squeekstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/squeekstop1.wav"); - break; - case 8: - PRECACHE_SOUND ("plats/talkstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/talkstop1.wav"); - break; - - default: - pev->noiseArrived = MAKE_STRING("common/null.wav"); - break; - } -} - -// -//====================== PLAT code ==================================================== -// - - -#define noiseMovement noise -#define noiseStopMoving noise1 - -class CFuncPlat : public CBasePlatTrain -{ -public: - void Spawn( void ); - void Precache( void ); - void Setup( void ); - - virtual void Blocked( CBaseEntity *pOther ); - - - void EXPORT PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void EXPORT CallGoDown( void ) { GoDown(); } - void EXPORT CallHitTop( void ) { HitTop(); } - void EXPORT CallHitBottom( void ) { HitBottom(); } - - virtual void GoUp( void ); - virtual void GoDown( void ); - virtual void HitTop( void ); - virtual void HitBottom( void ); -}; -LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ); - - -// UNDONE: Need to save this!!! It needs class & linkage -class CPlatTrigger : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } - void SpawnInsideTrigger( CFuncPlat *pPlatform ); - void Touch( CBaseEntity *pOther ); - CFuncPlat *m_pPlatform; -}; - - - -/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER -speed default 150 - -Plats are always drawn in the extended position, so they will light correctly. - -If the plat is the target of another trigger or button, it will start out disabled in -the extended position until it is trigger, when it will lower and become a normal plat. - -If the "height" key is set, that will determine the amount the plat moves, instead of -being implicitly determined by the model's height. - -Set "sounds" to one of the following: -1) base fast -2) chain slow -*/ - -void CFuncPlat :: Setup( void ) -{ - //pev->noiseMovement = MAKE_STRING("plats/platmove1.wav"); - //pev->noiseStopMoving = MAKE_STRING("plats/platstop1.wav"); - - if (m_flTLength == 0) - m_flTLength = 80; - if (m_flTWidth == 0) - m_flTWidth = 10; - - pev->angles = g_vecZero; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - // vecPosition1 is the top position, vecPosition2 is the bottom - m_vecPosition1 = pev->origin; - m_vecPosition2 = pev->origin; - if (m_flHeight != 0) - m_vecPosition2.z = pev->origin.z - m_flHeight; - else - m_vecPosition2.z = pev->origin.z - pev->size.z + 8; - if (pev->speed == 0) - pev->speed = 150; - - if ( m_volume == 0 ) - m_volume = 0.85; -} - - -void CFuncPlat :: Precache( ) -{ - CBasePlatTrain::Precache(); - //PRECACHE_SOUND("plats/platmove1.wav"); - //PRECACHE_SOUND("plats/platstop1.wav"); - if ( !IsTogglePlat() ) - PlatSpawnInsideTrigger( pev ); // the "start moving" trigger -} - - -void CFuncPlat :: Spawn( ) -{ - Setup(); - - Precache(); - - // If this platform is the target of some button, it starts at the TOP position, - // and is brought down by that button. Otherwise, it starts at BOTTOM. - if ( !FStringNull(pev->targetname) ) - { - UTIL_SetOrigin (pev, m_vecPosition1); - m_toggle_state = TS_AT_TOP; - SetUse( &CFuncPlat::PlatUse ); - } - else - { - UTIL_SetOrigin (pev, m_vecPosition2); - m_toggle_state = TS_AT_BOTTOM; - } -} - - - -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform) -{ - GetClassPtr( (CPlatTrigger *)NULL)->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); -} - - -// -// Create a trigger entity for a platform. -// -void CPlatTrigger :: SpawnInsideTrigger( CFuncPlat *pPlatform ) -{ - m_pPlatform = pPlatform; - // Create trigger entity, "point" it at the owning platform, give it a touch method - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->origin = pPlatform->pev->origin; - - // Establish the trigger field's size - Vector vecTMin = m_pPlatform->pev->mins + Vector ( 25 , 25 , 0 ); - Vector vecTMax = m_pPlatform->pev->maxs + Vector ( 25 , 25 , 8 ); - vecTMin.z = vecTMax.z - ( m_pPlatform->m_vecPosition1.z - m_pPlatform->m_vecPosition2.z + 8 ); - if (m_pPlatform->pev->size.x <= 50) - { - vecTMin.x = (m_pPlatform->pev->mins.x + m_pPlatform->pev->maxs.x) / 2; - vecTMax.x = vecTMin.x + 1; - } - if (m_pPlatform->pev->size.y <= 50) - { - vecTMin.y = (m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y) / 2; - vecTMax.y = vecTMin.y + 1; - } - UTIL_SetSize ( pev, vecTMin, vecTMax ); -} - - -// -// When the platform's trigger field is touched, the platform ??? -// -void CPlatTrigger :: Touch( CBaseEntity *pOther ) -{ - // Ignore touches by non-players - entvars_t* pevToucher = pOther->pev; - if ( !FClassnameIs (pevToucher, "player") ) - return; - - // Ignore touches by corpses - if (!pOther->IsAlive()) - return; - - // Make linked platform go up/down. - if (m_pPlatform->m_toggle_state == TS_AT_BOTTOM) - m_pPlatform->GoUp(); - else if (m_pPlatform->m_toggle_state == TS_AT_TOP) - m_pPlatform->pev->nextthink = m_pPlatform->pev->ltime + 1;// delay going down -} - - -// -// Used by SUB_UseTargets, when a platform is the target of a button. -// Start bringing platform down. -// -void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsTogglePlat() ) - { - // Top is off, bottom is on - BOOL on = (m_toggle_state == TS_AT_BOTTOM) ? TRUE : FALSE; - - if ( !ShouldToggle( useType, on ) ) - return; - - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else if ( m_toggle_state == TS_AT_BOTTOM ) - GoUp(); - } - else - { - SetUse( NULL ); - - if (m_toggle_state == TS_AT_TOP) - GoDown(); - } -} - - -// -// Platform is at top, now starts moving down. -// -void CFuncPlat :: GoDown( void ) -{ - if(pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_GOING_DOWN; - SetMoveDone(&CFuncPlat::CallHitBottom); - LinearMove(m_vecPosition2, pev->speed); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncPlat :: HitBottom( void ) -{ - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - if (pev->noiseStopMoving) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncPlat :: GoUp( void ) -{ - if (pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_GOING_UP; - SetMoveDone(&CFuncPlat::CallHitTop); - LinearMove(m_vecPosition1, pev->speed); -} - - -// -// Platform has hit top. Pauses, then starts back down again. -// -void CFuncPlat :: HitTop( void ) -{ - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - if (pev->noiseStopMoving) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_AT_TOP; - - if ( !IsTogglePlat() ) - { - // After a delay, the platform will automatically start going down again. - SetThink( &CFuncPlat::CallGoDown ); - pev->nextthink = pev->ltime + 3; - } -} - - -void CFuncPlat :: Blocked( CBaseEntity *pOther ) -{ - ALERT( at_aiconsole, "%s Blocked by %s\n", STRING(pev->classname), STRING(pOther->pev->classname) ); - // Hurt the blocker a little - pOther->TakeDamage(pev, pev, 1, DMG_CRUSH); - - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - // Send the platform back where it came from - ASSERT(m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN); - if (m_toggle_state == TS_GOING_UP) - GoDown(); - else if (m_toggle_state == TS_GOING_DOWN) - GoUp (); -} - - -class CFuncPlatRot : public CFuncPlat -{ -public: - void Spawn( void ); - void SetupRotation( void ); - - virtual void GoUp( void ); - virtual void GoDown( void ); - virtual void HitTop( void ); - virtual void HitBottom( void ); - - void RotMove( Vector &destAngle, float time ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - Vector m_end, m_start; -}; -LINK_ENTITY_TO_CLASS( func_platrot, CFuncPlatRot ); -TYPEDESCRIPTION CFuncPlatRot::m_SaveData[] = -{ - DEFINE_FIELD( CFuncPlatRot, m_end, FIELD_VECTOR ), - DEFINE_FIELD( CFuncPlatRot, m_start, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CFuncPlatRot, CFuncPlat ); - - -void CFuncPlatRot :: SetupRotation( void ) -{ - if ( m_vecFinalAngle.x != 0 ) // This plat rotates too! - { - CBaseToggle :: AxisDir( pev ); - m_start = pev->angles; - m_end = pev->angles + pev->movedir * m_vecFinalAngle.x; - } - else - { - m_start = g_vecZero; - m_end = g_vecZero; - } - if ( !FStringNull(pev->targetname) ) // Start at top - { - pev->angles = m_end; - } -} - - -void CFuncPlatRot :: Spawn( void ) -{ - CFuncPlat :: Spawn(); - SetupRotation(); -} - -void CFuncPlatRot :: GoDown( void ) -{ - CFuncPlat :: GoDown(); - RotMove( m_start, pev->nextthink - pev->ltime ); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncPlatRot :: HitBottom( void ) -{ - CFuncPlat :: HitBottom(); - pev->avelocity = g_vecZero; - pev->angles = m_start; -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncPlatRot :: GoUp( void ) -{ - CFuncPlat :: GoUp(); - RotMove( m_end, pev->nextthink - pev->ltime ); -} - - -// -// Platform has hit top. Pauses, then starts back down again. -// -void CFuncPlatRot :: HitTop( void ) -{ - CFuncPlat :: HitTop(); - pev->avelocity = g_vecZero; - pev->angles = m_end; -} - - -void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) -{ - // set destdelta to the vector needed to move - Vector vecDestDelta = destAngle - pev->angles; - - // Travel time is so short, we're practically there already; so make it so. - if ( time >= 0.1) - pev->avelocity = vecDestDelta / time; - else - { - pev->avelocity = vecDestDelta; - pev->nextthink = pev->ltime + 1; - } -} - - -// -//====================== TRAIN code ================================================== -// - -class CFuncTrain : public CBasePlatTrain -{ -public: - void Spawn( void ); - void Precache( void ); - void Activate( void ); - void OverrideReset( void ); - - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - - void EXPORT Wait( void ); - void EXPORT Next( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - entvars_t *m_pevCurrentTarget; - int m_sounds; - BOOL m_activated; -}; - -LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); -TYPEDESCRIPTION CFuncTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrain, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrain, m_pevCurrentTarget, FIELD_EVARS ), - DEFINE_FIELD( CFuncTrain, m_activated, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatTrain ); - - -void CFuncTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBasePlatTrain::KeyValue( pkvd ); -} - - -void CFuncTrain :: Blocked( CBaseEntity *pOther ) - -{ - if ( gpGlobals->time < m_flActivateFinished) - return; - - m_flActivateFinished = gpGlobals->time + 0.5; - - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); -} - - -void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) - { - // Move toward my target - pev->spawnflags &= ~SF_TRAIN_WAIT_RETRIGGER; - Next(); - } - else - { - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - // Pop back to last target if it's available - if ( pev->enemy ) - pev->target = pev->enemy->v.targetname; - pev->nextthink = 0; - pev->velocity = g_vecZero; - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - } -} - - -void CFuncTrain :: Wait( void ) -{ - // Fire the pass target if there is one - if ( m_pevCurrentTarget->message ) - { - FireTargets( STRING(m_pevCurrentTarget->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pevCurrentTarget->spawnflags, SF_CORNER_FIREONCE ) ) - m_pevCurrentTarget->message = 0; - } - - // need pointer to LAST target. - if ( FBitSet (m_pevCurrentTarget->spawnflags , SF_TRAIN_WAIT_RETRIGGER ) || ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) ) - { - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - // clear the sound channel. - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - pev->nextthink = 0; - return; - } - - // ALERT ( at_console, "%f\n", m_flWait ); - - if (m_flWait != 0) - {// -1 wait will wait forever! - pev->nextthink = pev->ltime + m_flWait; - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - SetThink( &CFuncTrain::Next ); - } - else - { - Next();// do it RIGHT now! - } -} - - -// -// Train next - path corner needs to change to next target -// -void CFuncTrain :: Next( void ) -{ - CBaseEntity *pTarg; - - - // now find our next target - pTarg = GetNextTarget(); - - if ( !pTarg ) - { - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - // Play stop sound - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - return; - } - - // Save last target in case we need to find it again - pev->message = pev->target; - - pev->target = pTarg->pev->target; - m_flWait = pTarg->GetDelay(); - - if ( m_pevCurrentTarget && m_pevCurrentTarget->speed != 0 ) - {// don't copy speed from target if it is 0 (uninitialized) - pev->speed = m_pevCurrentTarget->speed; - ALERT( at_aiconsole, "Train %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); - } - m_pevCurrentTarget = pTarg->pev;// keep track of this since path corners change our target for us. - - pev->enemy = pTarg->edict();//hack - - if(FBitSet(m_pevCurrentTarget->spawnflags, SF_CORNER_TELEPORT)) - { - // Path corner has indicated a teleport to the next corner. - SetBits(pev->effects, EF_NOINTERP); - UTIL_SetOrigin(pev, pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5); - Wait(); // Get on with doing the next path corner. - } - else - { - // Normal linear move. - - // CHANGED this from CHAN_VOICE to CHAN_STATIC around OEM beta time because trains should - // use CHAN_STATIC for their movement sounds to prevent sound field problems. - // this is not a hack or temporary fix, this is how things should be. (sjb). - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseMovement ) - EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - ClearBits(pev->effects, EF_NOINTERP); - SetMoveDone( &CFuncTrain::Wait ); - LinearMove (pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5, pev->speed); - } -} - - -void CFuncTrain :: Activate( void ) -{ - // Not yet active, so teleport to first target - if ( !m_activated ) - { - m_activated = TRUE; - entvars_t *pevTarg = VARS( FIND_ENTITY_BY_TARGETNAME (NULL, STRING(pev->target) ) ); - - pev->target = pevTarg->target; - m_pevCurrentTarget = pevTarg;// keep track of this since path corners change our target for us. - - UTIL_SetOrigin (pev, pevTarg->origin - (pev->mins + pev->maxs) * 0.5 ); - - if ( FStringNull(pev->targetname) ) - { // not triggered, so start immediately - pev->nextthink = pev->ltime + 0.1; - SetThink( &CFuncTrain::Next ); - } - else - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - } -} - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving platforms that players can ride. -The targets origin specifies the min point of the train at each corner. -The train spawns at the first target it is pointing at. -If the train is the target of a button or trigger, it will not begin moving until activated. -speed default 100 -dmg default 2 -sounds -1) ratchet metal -*/ - -void CFuncTrain :: Spawn( void ) -{ - Precache(); - if (pev->speed == 0) - pev->speed = 100; - - if ( FStringNull(pev->target) ) - ALERT(at_console, "FuncTrain with no target"); - - if (pev->dmg == 0) - pev->dmg = 2; - - pev->movetype = MOVETYPE_PUSH; - - if ( FBitSet (pev->spawnflags, SF_TRACKTRAIN_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - SET_MODEL( ENT(pev), STRING(pev->model) ); - UTIL_SetSize (pev, pev->mins, pev->maxs); - UTIL_SetOrigin(pev, pev->origin); - - m_activated = FALSE; - - if ( m_volume == 0 ) - m_volume = 0.85; -} - - -void CFuncTrain::Precache( void ) -{ - CBasePlatTrain::Precache(); - -#if 0 // obsolete - // otherwise use preset sound - switch (m_sounds) - { - case 0: - pev->noise = 0; - pev->noise1 = 0; - break; - - case 1: - PRECACHE_SOUND ("plats/train2.wav"); - PRECACHE_SOUND ("plats/train1.wav"); - pev->noise = MAKE_STRING("plats/train2.wav"); - pev->noise1 = MAKE_STRING("plats/train1.wav"); - break; - - case 2: - PRECACHE_SOUND ("plats/platmove1.wav"); - PRECACHE_SOUND ("plats/platstop1.wav"); - pev->noise = MAKE_STRING("plats/platstop1.wav"); - pev->noise1 = MAKE_STRING("plats/platmove1.wav"); - break; - } -#endif -} - - -void CFuncTrain::OverrideReset( void ) -{ - CBaseEntity *pTarg; - - // Are we moving? - if ( pev->velocity != g_vecZero && pev->nextthink != 0 ) - { - pev->target = pev->message; - // now find our next target - pTarg = GetNextTarget(); - if ( !pTarg ) - { - pev->nextthink = 0; - pev->velocity = g_vecZero; - } - else // Keep moving for 0.1 secs, then find path_corner again and restart - { - SetThink( &CFuncTrain::Next ); - pev->nextthink = pev->ltime + 0.1; - } - } -} - - - - -// --------------------------------------------------------------------- -// -// Track Train -// -// --------------------------------------------------------------------- - -TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrackTrain, m_ppath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrackTrain, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_speed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_dir, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_startSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMins, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMaxs, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackTrain, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_flBank, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ); -LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); - -void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wheels")) - { - m_length = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_height = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "startspeed")) - { - m_startSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - m_flVolume = (float) (atoi(pkvd->szValue)); - m_flVolume *= 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bank")) - { - m_flBank = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) -{ - if ( alwaysThink ) - pev->flags |= FL_ALWAYSTHINK; - else - pev->flags &= ~FL_ALWAYSTHINK; - - pev->nextthink = thinkTime; -} - - -void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // Blocker is on-ground on the train - if ( FBitSet( pevOther->flags, FL_ONGROUND ) && VARS(pevOther->groundentity) == pev ) - { - float deltaSpeed = fabs(pev->speed); - if ( deltaSpeed > 50 ) - deltaSpeed = 50; - if ( !pevOther->velocity.z ) - pevOther->velocity.z += deltaSpeed; - return; - } - else - pevOther->velocity = (pevOther->origin - pev->origin ).Normalize() * pev->dmg; - - ALERT( at_aiconsole, "TRAIN(%s): Blocked by %s (dmg:%.2f)\n", STRING(pev->targetname), STRING(pOther->pev->classname), pev->dmg ); - if ( pev->dmg <= 0 ) - return; - // we can't hurt this thing, so we're not concerned with it - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); -} - - -void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType != USE_SET ) - { - if ( !ShouldToggle( useType, (pev->speed != 0) ) ) - return; - - if ( pev->speed == 0 ) - { - pev->speed = m_speed * m_dir; - - Next(); - } - else - { - pev->speed = 0; - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - StopSound(); - SetThink( NULL ); - } - } - else - { - float delta = value; - - delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; - if ( delta > 1 ) - delta = 1; - else if ( delta < -1 ) - delta = -1; - if ( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) - { - if ( delta < 0 ) - delta = 0; - } - pev->speed = m_speed * delta; - Next(); - ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING(pev->targetname), pev->speed ); - } -} - - -static float Fix( float angle ) -{ - while ( angle < 0 ) - angle += 360; - while ( angle > 360 ) - angle -= 360; - - return angle; -} - - -static void FixupAngles( Vector &v ) -{ - v.x = Fix( v.x ); - v.y = Fix( v.y ); - v.z = Fix( v.z ); -} - -#define TRAIN_STARTPITCH 60 -#define TRAIN_MAXPITCH 200 -#define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation - -void CFuncTrackTrain :: StopSound( void ) -{ - // if sound playing, stop it - if (m_soundPlaying && pev->noise) - { - unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; - - us_encode = us_sound; - - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, - (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 ); - - /* - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - */ - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100); - } - - m_soundPlaying = 0; -} - -// update pitch based on speed, start sound if not playing -// NOTE: when train goes through transition, m_soundPlaying should go to 0, -// which will cause the looped sound to restart. - -void CFuncTrackTrain :: UpdateSound( void ) -{ - float flpitch; - - if (!pev->noise) - return; - - flpitch = TRAIN_STARTPITCH + (abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); - - if (!m_soundPlaying) - { - // play startup sound for train - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, (int) flpitch); - m_soundPlaying = 1; - } - else - { -/* - // update pitch - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int) flpitch); -*/ - // volume 0.0 - 1.0 - 6 bits - // m_sounds 3 bits - // flpitch = 6 bits - // 15 bits total - - unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; - unsigned short us_pitch = ( ( unsigned short )( flpitch / 10.0 ) & 0x003f ) << 6; - unsigned short us_volume = ( ( unsigned short )( m_flVolume * 40.0 ) & 0x003f ); - - us_encode = us_sound | us_pitch | us_volume; - - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, - (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 ); - } -} - - -void CFuncTrackTrain :: Next( void ) -{ - float time = 0.5; - - if ( !pev->speed ) - { - ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); - StopSound(); - return; - } - -// if ( !m_ppath ) -// m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) - { - ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - UpdateSound(); - - Vector nextPos = pev->origin; - - nextPos.z -= m_height; - CPathTrack *pnext = m_ppath->LookAhead( &nextPos, pev->speed * 0.1, 1 ); - nextPos.z += m_height; - - pev->velocity = (nextPos - pev->origin) * 10; - Vector nextFront = pev->origin; - - nextFront.z -= m_height; - if ( m_length > 0 ) - m_ppath->LookAhead( &nextFront, m_length, 0 ); - else - m_ppath->LookAhead( &nextFront, 100, 0 ); - nextFront.z += m_height; - - Vector delta = nextFront - pev->origin; - Vector angles = UTIL_VecToAngles( delta ); - // The train actually points west - angles.y += 180; - - // !!! All of this crap has to be done to make the angles not wrap around, revisit this. - FixupAngles( angles ); - FixupAngles( pev->angles ); - - if ( !pnext || (delta.x == 0 && delta.y == 0) ) - angles = pev->angles; - - float vy, vx; - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) - vx = UTIL_AngleDistance( angles.x, pev->angles.x ); - else - vx = 0; - vy = UTIL_AngleDistance( angles.y, pev->angles.y ); - - pev->avelocity.y = vy * 10; - pev->avelocity.x = vx * 10; - - if ( m_flBank != 0 ) - { - if ( pev->avelocity.y < -5 ) - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( -m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else if ( pev->avelocity.y > 5 ) - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank*4 ), pev->angles.z) * 4; - } - - if ( pnext ) - { - if ( pnext != m_ppath ) - { - CPathTrack *pFire; - if ( pev->speed >= 0 ) - pFire = pnext; - else - pFire = m_ppath; - - m_ppath = pnext; - // Fire the pass target if there is one - if ( pFire->pev->message ) - { - FireTargets( STRING(pFire->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) - pFire->pev->message = 0; - } - - if ( pFire->pev->spawnflags & SF_PATH_DISABLE_TRAIN ) - pev->spawnflags |= SF_TRACKTRAIN_NOCONTROL; - - // Don't override speed if under user control - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - { - if ( pFire->pev->speed != 0 ) - {// don't copy speed from target if it is 0 (uninitialized) - pev->speed = pFire->pev->speed; - ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); - } - } - - } - SetThink( &CFuncTrackTrain::Next ); - NextThink( pev->ltime + time, TRUE ); - } - else // end of path, stop - { - StopSound(); - pev->velocity = (nextPos - pev->origin); - pev->avelocity = g_vecZero; - float distance = pev->velocity.Length(); - m_oldSpeed = pev->speed; - - - pev->speed = 0; - - // Move to the dead end - - // Are we there yet? - if ( distance > 0 ) - { - // no, how long to get there? - time = distance / m_oldSpeed; - pev->velocity = pev->velocity * (m_oldSpeed / distance); - SetThink( &CFuncTrackTrain::DeadEnd ); - NextThink( pev->ltime + time, FALSE ); - } - else - { - DeadEnd(); - } - } -} - - -void CFuncTrackTrain::DeadEnd( void ) -{ - // Fire the dead-end target if there is one - CPathTrack *pTrack, *pNext; - - pTrack = m_ppath; - - ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); - // Find the dead end path node - // HACKHACK -- This is bugly, but the train can actually stop moving at a different node depending on it's speed - // so we have to traverse the list to it's end. - if ( pTrack ) - { - if ( m_oldSpeed < 0 ) - { - do - { - pNext = pTrack->ValidPath( pTrack->GetPrevious(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - else - { - do - { - pNext = pTrack->ValidPath( pTrack->GetNext(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - } - - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - if ( pTrack ) - { - ALERT( at_aiconsole, "at %s\n", STRING(pTrack->pev->targetname) ); - if ( pTrack->pev->netname ) - FireTargets( STRING(pTrack->pev->netname), this, this, USE_TOGGLE, 0 ); - } - else - ALERT( at_aiconsole, "\n" ); -} - - -void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) -{ - Vector offset = pevControls->origin - pev->oldorigin; - - m_controlMins = pevControls->mins + offset; - m_controlMaxs = pevControls->maxs + offset; -} - - -BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) -{ - Vector offset = pevTest->origin - pev->origin; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - return FALSE; - - // Transform offset into local coordinates - UTIL_MakeVectors( pev->angles ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = -DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - if ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z && - local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ) - return TRUE; - - return FALSE; -} - - -void CFuncTrackTrain :: Find( void ) -{ - m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) - return; - - entvars_t *pevTarget = m_ppath->pev; - if ( !FClassnameIs( pevTarget, "path_track" ) ) - { - ALERT( at_error, "func_track_train must be on a path of path_track\n" ); - m_ppath = NULL; - return; - } - - Vector nextPos = pevTarget->origin; - nextPos.z += m_height; - - Vector look = nextPos; - look.z -= m_height; - m_ppath->LookAhead( &look, m_length, 0 ); - look.z += m_height; - - pev->angles = UTIL_VecToAngles( look - nextPos ); - // The train actually points west - pev->angles.y += 180; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) - pev->angles.x = 0; - UTIL_SetOrigin( pev, nextPos ); - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Next ); - pev->speed = m_startSpeed; - - UpdateSound(); -} - - -void CFuncTrackTrain :: NearestPath( void ) -{ - CBaseEntity *pTrack = NULL; - CBaseEntity *pNearest = NULL; - float dist, closest; - - closest = 1024; - - while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) - { - // filter out non-tracks - if ( !(pTrack->pev->flags & (FL_CLIENT|FL_MONSTER)) && FClassnameIs( pTrack->pev, "path_track" ) ) - { - dist = (pev->origin - pTrack->pev->origin).Length(); - if ( dist < closest ) - { - closest = dist; - pNearest = pTrack; - } - } - } - - if ( !pNearest ) - { - ALERT( at_console, "Can't find a nearby track !!!\n" ); - SetThink(NULL); - return; - } - - ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING(pev->targetname), STRING(pNearest->pev->targetname) ); - // If I'm closer to the next path_track on this path, then it's my real path - pTrack = ((CPathTrack *)pNearest)->GetNext(); - if ( pTrack ) - { - if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) - pNearest = pTrack; - } - - m_ppath = (CPathTrack *)pNearest; - - if ( pev->speed != 0 ) - { - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Next ); - } -} - - -void CFuncTrackTrain::OverrideReset( void ) -{ - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::NearestPath ); -} - - -CFuncTrackTrain *CFuncTrackTrain::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "func_tracktrain" ) ) - return (CFuncTrackTrain *)GET_PRIVATE(pent); - return NULL; -} - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving platforms that players can ride. -The targets origin specifies the min point of the train at each corner. -The train spawns at the first target it is pointing at. -If the train is the target of a button or trigger, it will not begin moving until activated. -speed default 100 -dmg default 2 -sounds -1) ratchet metal -*/ - -void CFuncTrackTrain :: Spawn( void ) -{ - if ( pev->speed == 0 ) - m_speed = 100; - else - m_speed = pev->speed; - - pev->speed = 0; - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->impulse = m_speed; - - m_dir = 1; - - if ( FStringNull(pev->target) ) - ALERT( at_console, "FuncTrain with no target" ); - - if ( pev->spawnflags & SF_TRACKTRAIN_PASSABLE ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - // Cache off placed origin for train controls - pev->oldorigin = pev->origin; - - m_controlMins = pev->mins; - m_controlMaxs = pev->maxs; - m_controlMaxs.z += 72; -// start trains on the next frame, to make sure their targets have had -// a chance to spawn/activate - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Find ); - Precache(); -} - -void CFuncTrackTrain :: Precache( void ) -{ - if (m_flVolume == 0.0) - m_flVolume = 1.0; - - switch (m_sounds) - { - default: - // no sound - pev->noise = 0; - break; - case 1: PRECACHE_SOUND("plats/ttrain1.wav"); pev->noise = MAKE_STRING("plats/ttrain1.wav");break; - case 2: PRECACHE_SOUND("plats/ttrain2.wav"); pev->noise = MAKE_STRING("plats/ttrain2.wav");break; - case 3: PRECACHE_SOUND("plats/ttrain3.wav"); pev->noise = MAKE_STRING("plats/ttrain3.wav");break; - case 4: PRECACHE_SOUND("plats/ttrain4.wav"); pev->noise = MAKE_STRING("plats/ttrain4.wav");break; - case 5: PRECACHE_SOUND("plats/ttrain6.wav"); pev->noise = MAKE_STRING("plats/ttrain6.wav");break; - case 6: PRECACHE_SOUND("plats/ttrain7.wav"); pev->noise = MAKE_STRING("plats/ttrain7.wav");break; - } - - PRECACHE_SOUND("plats/ttrain_brake1.wav"); - PRECACHE_SOUND("plats/ttrain_start1.wav"); - - m_usAdjustPitch = PRECACHE_EVENT( 1, "events/train.sc" ); -} - -// This class defines the volume of space that the player must stand in to control the train -class CFuncTrainControls : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void Spawn( void ); - void EXPORT Find( void ); -}; -LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ); - - -void CFuncTrainControls :: Find( void ) -{ - edict_t *pTarget = NULL; - - do - { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && !FClassnameIs(pTarget, "func_tracktrain") ); - - if ( FNullEnt( pTarget ) ) - { - ALERT( at_console, "No train %s\n", STRING(pev->target) ); - return; - } - - CFuncTrackTrain *ptrain = CFuncTrackTrain::Instance(pTarget); - ptrain->SetControls( pev ); - UTIL_Remove( this ); -} - - -void CFuncTrainControls :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CFuncTrainControls::Find ); - pev->nextthink = gpGlobals->time; -} - - - -// ---------------------------------------------------------------------------- -// -// Track changer / Train elevator -// -// ---------------------------------------------------------------------------- - -#define SF_TRACK_ACTIVATETRAIN 0x00000001 -#define SF_TRACK_RELINK 0x00000002 -#define SF_TRACK_ROTMOVE 0x00000004 -#define SF_TRACK_STARTBOTTOM 0x00000008 -#define SF_TRACK_DONT_MOVE 0x00000010 - -// -// This entity is a rotating/moving platform that will carry a train to a new track. -// It must be larger in X-Y planar area than the train, since it must contain the -// train within these dimensions in order to operate when the train is near it. -// - -typedef enum { TRAIN_SAFE, TRAIN_BLOCKING, TRAIN_FOLLOWING } TRAIN_CODE; - -class CFuncTrackChange : public CFuncPlatRot -{ -public: - void Spawn( void ); - void Precache( void ); - -// virtual void Blocked( void ); - virtual void EXPORT GoUp( void ); - virtual void EXPORT GoDown( void ); - - void KeyValue( KeyValueData* pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Find( void ); - TRAIN_CODE EvaluateTrain( CPathTrack *pcurrent ); - void UpdateTrain( Vector &dest ); - virtual void HitBottom( void ); - virtual void HitTop( void ); - void Touch( CBaseEntity *pOther ); - virtual void UpdateAutoTargets( int toggleState ); - virtual BOOL IsTogglePlat( void ) { return TRUE; } - - void DisableUse( void ) { m_use = 0; } - void EnableUse( void ) { m_use = 1; } - int UseEnabled( void ) { return m_use; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual void OverrideReset( void ); - - - CPathTrack *m_trackTop; - CPathTrack *m_trackBottom; - - CFuncTrackTrain *m_train; - - int m_trackTopName; - int m_trackBottomName; - int m_trainName; - TRAIN_CODE m_code; - int m_targetState; - int m_use; -}; -LINK_ENTITY_TO_CLASS( func_trackchange, CFuncTrackChange ); - -TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = -{ - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTop, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottom, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_train, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTopName, FIELD_STRING ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottomName, FIELD_STRING ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trainName, FIELD_STRING ), - DEFINE_FIELD( CFuncTrackChange, m_code, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackChange, m_targetState, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackChange, m_use, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ); - -void CFuncTrackChange :: Spawn( void ) -{ - Setup(); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - m_vecPosition2.z = pev->origin.z; - - SetupRotation(); - - if ( FBitSet( pev->spawnflags, SF_TRACK_STARTBOTTOM ) ) - { - UTIL_SetOrigin (pev, m_vecPosition2); - m_toggle_state = TS_AT_BOTTOM; - pev->angles = m_start; - m_targetState = TS_AT_TOP; - } - else - { - UTIL_SetOrigin (pev, m_vecPosition1); - m_toggle_state = TS_AT_TOP; - pev->angles = m_end; - m_targetState = TS_AT_BOTTOM; - } - - EnableUse(); - pev->nextthink = pev->ltime + 2.0; - SetThink( &CFuncTrackChange::Find ); - Precache(); -} - -void CFuncTrackChange :: Precache( void ) -{ - // Can't trigger sound - PRECACHE_SOUND( "buttons/button11.wav" ); - - CFuncPlatRot::Precache(); -} - - -// UNDONE: Filter touches before re-evaluating the train. -void CFuncTrackChange :: Touch( CBaseEntity *pOther ) -{ -#if 0 - TRAIN_CODE code; - entvars_t *pevToucher = pOther->pev; -#endif -} - - - -void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "train") ) - { - m_trainName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "toptrack") ) - { - m_trackTopName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bottomtrack") ) - { - m_trackBottomName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CFuncPlatRot::KeyValue( pkvd ); // Pass up to base class - } -} - - -void CFuncTrackChange::OverrideReset( void ) -{ - pev->nextthink = pev->ltime + 1.0; - SetThink( &CFuncTrackChange::Find ); -} - -void CFuncTrackChange :: Find( void ) -{ - // Find track entities - edict_t *target; - - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackTopName) ); - if ( !FNullEnt(target) ) - { - m_trackTop = CPathTrack::Instance( target ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackBottomName) ); - if ( !FNullEnt(target) ) - { - m_trackBottom = CPathTrack::Instance( target ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); - if ( !FNullEnt(target) ) - { - m_train = CFuncTrackTrain::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ) ); - if ( !m_train ) - { - ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); - return; - } - Vector center = (pev->absmin + pev->absmax) * 0.5; - m_trackBottom = m_trackBottom->Nearest( center ); - m_trackTop = m_trackTop->Nearest( center ); - UpdateAutoTargets( m_toggle_state ); - SetThink( NULL ); - return; - } - else - { - ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); - } - } - else - ALERT( at_error, "Can't find bottom track for track change! %s\n", STRING(m_trackBottomName) ); - } - else - ALERT( at_error, "Can't find top track for track change! %s\n", STRING(m_trackTopName) ); -} - - - -TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) -{ - // Go ahead and work, we don't have anything to switch, so just be an elevator - if ( !pcurrent || !m_train ) - return TRAIN_SAFE; - - if ( m_train->m_ppath == pcurrent || (pcurrent->m_pprevious && m_train->m_ppath == pcurrent->m_pprevious) || - (pcurrent->m_pnext && m_train->m_ppath == pcurrent->m_pnext) ) - { - if ( m_train->pev->speed != 0 ) - return TRAIN_BLOCKING; - - Vector dist = pev->origin - m_train->pev->origin; - float length = dist.Length2D(); - if ( length < m_train->m_length ) // Empirically determined close distance - return TRAIN_FOLLOWING; - else if ( length > (150 + m_train->m_length) ) - return TRAIN_SAFE; - - return TRAIN_BLOCKING; - } - - return TRAIN_SAFE; -} - - -void CFuncTrackChange :: UpdateTrain( Vector &dest ) -{ - float time = (pev->nextthink - pev->ltime); - - m_train->pev->velocity = pev->velocity; - m_train->pev->avelocity = pev->avelocity; - m_train->NextThink( m_train->pev->ltime + time, FALSE ); - - // Attempt at getting the train to rotate properly around the origin of the trackchange - if ( time <= 0 ) - return; - - Vector offset = m_train->pev->origin - pev->origin; - Vector delta = dest - pev->angles; - // Transform offset into local coordinates - UTIL_MakeInvVectors( delta, gpGlobals ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - local = local - offset; - m_train->pev->velocity = pev->velocity + (local * (1.0/time)); -} - -void CFuncTrackChange :: GoDown( void ) -{ - if ( m_code == TRAIN_BLOCKING ) - return; - - // HitBottom may get called during CFuncPlat::GoDown(), so set up for that - // before you call GoDown() - - UpdateAutoTargets( TS_GOING_DOWN ); - // If ROTMOVE, move & rotate - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - { - SetMoveDone( &CFuncTrackChange::CallHitBottom ); - m_toggle_state = TS_GOING_DOWN; - AngularMove( m_start, pev->speed ); - } - else - { - CFuncPlat :: GoDown(); - SetMoveDone( &CFuncTrackChange::CallHitBottom ); - RotMove( m_start, pev->nextthink - pev->ltime ); - } - // Otherwise, rotate first, move second - - // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) - { - UpdateTrain( m_start ); - m_train->m_ppath = NULL; - } -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncTrackChange :: GoUp( void ) -{ - if ( m_code == TRAIN_BLOCKING ) - return; - - // HitTop may get called during CFuncPlat::GoUp(), so set up for that - // before you call GoUp(); - - UpdateAutoTargets( TS_GOING_UP ); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - { - m_toggle_state = TS_GOING_UP; - SetMoveDone( &CFuncTrackChange::CallHitTop ); - AngularMove( m_end, pev->speed ); - } - else - { - // If ROTMOVE, move & rotate - CFuncPlat :: GoUp(); - SetMoveDone( &CFuncTrackChange::CallHitTop ); - RotMove( m_end, pev->nextthink - pev->ltime ); - } - - // Otherwise, move first, rotate second - - // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) - { - UpdateTrain( m_end ); - m_train->m_ppath = NULL; - } -} - - -// Normal track change -void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) -{ - if ( !m_trackTop || !m_trackBottom ) - return; - - if ( toggleState == TS_AT_TOP ) - ClearBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); - else - SetBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); - - if ( toggleState == TS_AT_BOTTOM ) - ClearBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); - else - SetBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); -} - - -void CFuncTrackChange :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( m_toggle_state != TS_AT_TOP && m_toggle_state != TS_AT_BOTTOM ) - return; - - // If train is in "safe" area, but not on the elevator, play alarm sound - if ( m_toggle_state == TS_AT_TOP ) - m_code = EvaluateTrain( m_trackTop ); - else if ( m_toggle_state == TS_AT_BOTTOM ) - m_code = EvaluateTrain( m_trackBottom ); - else - m_code = TRAIN_BLOCKING; - if ( m_code == TRAIN_BLOCKING ) - { - // Play alarm and return - EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/button11.wav", 1, ATTN_NORM); - return; - } - - // Otherwise, it's safe to move - // If at top, go down - // at bottom, go up - - DisableUse(); - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else - GoUp(); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncTrackChange :: HitBottom( void ) -{ - CFuncPlatRot :: HitBottom(); - if ( m_code == TRAIN_FOLLOWING ) - { -// UpdateTrain(); - m_train->SetTrack( m_trackBottom ); - } - SetThink( NULL ); - pev->nextthink = -1; - - UpdateAutoTargets( m_toggle_state ); - - EnableUse(); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncTrackChange :: HitTop( void ) -{ - CFuncPlatRot :: HitTop(); - if ( m_code == TRAIN_FOLLOWING ) - { -// UpdateTrain(); - m_train->SetTrack( m_trackTop ); - } - - // Don't let the plat go back down - SetThink( NULL ); - pev->nextthink = -1; - UpdateAutoTargets( m_toggle_state ); - EnableUse(); -} - - - -class CFuncTrackAuto : public CFuncTrackChange -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void UpdateAutoTargets( int toggleState ); -}; - -LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ); - -// Auto track change -void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) -{ - CPathTrack *pTarget, *pNextTarget; - - if ( !m_trackTop || !m_trackBottom ) - return; - - if ( m_targetState == TS_AT_TOP ) - { - pTarget = m_trackTop->GetNext(); - pNextTarget = m_trackBottom->GetNext(); - } - else - { - pTarget = m_trackBottom->GetNext(); - pNextTarget = m_trackTop->GetNext(); - } - if ( pTarget ) - { - ClearBits( pTarget->pev->spawnflags, SF_PATH_DISABLED ); - if ( m_code == TRAIN_FOLLOWING && m_train && m_train->pev->speed == 0 ) - m_train->Use( this, this, USE_ON, 0 ); - } - - if ( pNextTarget ) - SetBits( pNextTarget->pev->spawnflags, SF_PATH_DISABLED ); - -} - - -void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CPathTrack *pTarget; - - if ( !UseEnabled() ) - return; - - if ( m_toggle_state == TS_AT_TOP ) - pTarget = m_trackTop; - else if ( m_toggle_state == TS_AT_BOTTOM ) - pTarget = m_trackBottom; - else - pTarget = NULL; - - if ( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) - { - m_code = EvaluateTrain( pTarget ); - // Safe to fire? - if ( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) - { - DisableUse(); - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else - GoUp(); - } - } - else - { - if ( pTarget ) - pTarget = pTarget->GetNext(); - if ( pTarget && m_train->m_ppath != pTarget && ShouldToggle( useType, m_targetState ) ) - { - if ( m_targetState == TS_AT_TOP ) - m_targetState = TS_AT_BOTTOM; - else - m_targetState = TS_AT_TOP; - } - - UpdateAutoTargets( m_targetState ); - } -} - - -// ---------------------------------------------------------- -// -// -// pev->speed is the travel speed -// pev->health is current health -// pev->max_health is the amount to reset to each time it starts - -#define FGUNTARGET_START_ON 0x0001 - -class CGunTarget : public CBaseMonster -{ -public: - void Spawn( void ); - void Activate( void ); - void EXPORT Next( void ); - void EXPORT Start( void ); - void EXPORT Wait( void ); - void Stop( void ); - - int BloodColor( void ) { return DONT_BLEED; } - int Classify( void ) { return CLASS_MACHINE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - Vector BodyTarget( const Vector &posSrc ) { return pev->origin; } - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - BOOL m_on; -}; - - -LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ); - -TYPEDESCRIPTION CGunTarget::m_SaveData[] = -{ - DEFINE_FIELD( CGunTarget, m_on, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ); - - -void CGunTarget::Spawn( void ) -{ - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if ( pev->speed == 0 ) - pev->speed = 100; - - // Don't take damage until "on" - pev->takedamage = DAMAGE_NO; - pev->flags |= FL_MONSTER; - - m_on = FALSE; - pev->max_health = pev->health; - - if ( pev->spawnflags & FGUNTARGET_START_ON ) - { - SetThink( &CGunTarget::Start ); - pev->nextthink = pev->ltime + 0.3; - } -} - - -void CGunTarget::Activate( void ) -{ - CBaseEntity *pTarg; - - // now find our next target - pTarg = GetNextTarget(); - if ( pTarg ) - { - m_hTargetEnt = pTarg; - UTIL_SetOrigin( pev, pTarg->pev->origin - (pev->mins + pev->maxs) * 0.5 ); - } -} - - -void CGunTarget::Start( void ) -{ - Use( this, this, USE_ON, 0 ); -} - - -void CGunTarget::Next( void ) -{ - SetThink( NULL ); - - m_hTargetEnt = GetNextTarget(); - CBaseEntity *pTarget = m_hTargetEnt; - - if ( !pTarget ) - { - Stop(); - return; - } - SetMoveDone( &CGunTarget::Wait ); - LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); -} - - -void CGunTarget::Wait( void ) -{ - CBaseEntity *pTarget = m_hTargetEnt; - - if ( !pTarget ) - { - Stop(); - return; - } - - // Fire the pass target if there is one - if ( pTarget->pev->message ) - { - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pTarget->pev->spawnflags, SF_CORNER_FIREONCE ) ) - pTarget->pev->message = 0; - } - - m_flWait = pTarget->GetDelay(); - - pev->target = pTarget->pev->target; - SetThink( &CGunTarget::Next ); - if (m_flWait != 0) - {// -1 wait will wait forever! - pev->nextthink = pev->ltime + m_flWait; - } - else - { - Next();// do it RIGHT now! - } -} - - -void CGunTarget::Stop( void ) -{ - pev->velocity = g_vecZero; - pev->nextthink = 0; - pev->takedamage = DAMAGE_NO; -} - - -int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( pev->health > 0 ) - { - pev->health -= flDamage; - if ( pev->health <= 0 ) - { - pev->health = 0; - Stop(); - if ( pev->message ) - FireTargets( STRING(pev->message), this, this, USE_TOGGLE, 0 ); - } - } - return 0; -} - - -void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_on ) ) - return; - - if ( m_on ) - { - Stop(); - } - else - { - pev->takedamage = DAMAGE_AIM; - m_hTargetEnt = GetNextTarget(); - if ( m_hTargetEnt == NULL ) - return; - pev->health = pev->max_health; - Next(); - } -} - - - diff --git a/main/source/dlls/plats.h b/main/source/dlls/plats.h index 53fed78d..e1671c9c 100644 --- a/main/source/dlls/plats.h +++ b/main/source/dlls/plats.h @@ -1,31 +1,31 @@ -#ifndef CBASEPLATTRAIN_H -#define CBASEPLATTRAIN_H - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "trains.h" -#include "saverestore.h" - -#define SF_PLAT_TOGGLE 0x0001 - -class CBasePlatTrain : public CBaseToggle -{ -public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void KeyValue( KeyValueData* pkvd); - void Precache( void ); - - // This is done to fix spawn flag collisions between this class and a derived class - virtual BOOL IsTogglePlat( void ) { return (pev->spawnflags & SF_PLAT_TOGGLE) ? TRUE : FALSE; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BYTE m_bMoveSnd; // sound a plat makes while moving - BYTE m_bStopSnd; // sound a plat makes when it stops - float m_volume; // Sound volume -}; - +#ifndef CBASEPLATTRAIN_H +#define CBASEPLATTRAIN_H + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "trains.h" +#include "saverestore.h" + +#define SF_PLAT_TOGGLE 0x0001 + +class CBasePlatTrain : public CBaseToggle +{ +public: + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + void KeyValue( KeyValueData* pkvd); + void Precache( void ); + + // This is done to fix spawn flag collisions between this class and a derived class + virtual BOOL IsTogglePlat( void ) { return (pev->spawnflags & SF_PLAT_TOGGLE) ? TRUE : FALSE; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + BYTE m_bMoveSnd; // sound a plat makes while moving + BYTE m_bStopSnd; // sound a plat makes when it stops + float m_volume; // Sound volume +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/player.cpp b/main/source/dlls/player.cpp index 2b85dd78..e4d31498 100644 --- a/main/source/dlls/player.cpp +++ b/main/source/dlls/player.cpp @@ -1,5047 +1,5047 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// -//===== player.cpp ======================================================== -// -// functions dealing with the player -// -// -// $Workfile: player.cpp $ -// $Date: 2002/11/22 21:12:55 $ -// -//------------------------------------------------------------------------------- -// $Log: player.cpp,v $ -// Revision 1.39 2002/11/22 21:12:55 Flayra -// - Added DMG_IGNOREARMOR flag for players (used for ending game quickly) -// - NULL checks for when owner of turret is removed after owner leaves team -// - Send deploy weapon switch to player, when "lastinv" is executed -// -// Revision 1.38 2002/11/15 19:09:40 Flayra -// - Reworked network metering to be easily toggleable -// -// Revision 1.37 2002/11/12 02:18:41 Flayra -// - Beginning of HLTV changes -// -// Revision 1.36 2002/10/24 21:18:23 Flayra -// - Major networking optimizations, to prevent overlflows after 20+ players on game reset -// -// Revision 1.35 2002/10/18 22:15:13 Flayra -// - Fixed problem where level5 gets stuck with redemption -// -// Revision 1.34 2002/10/16 00:40:39 Flayra -// - Fixed bug where player couldn't switch to next player while observing -// - Propagate health as short for larger aliens -// - Propagate auth mask -// -// Revision 1.33 2002/10/03 18:26:03 Flayra -// - Removed HL "flatline" sound on death -// -// Revision 1.32 2002/09/23 22:03:50 Flayra -// - Fixed problem where anims weren't playing properly in ready room -// - Fixed problem where gestation model anims were playing before model was updated -// -// Revision 1.31 2002/08/31 18:01:18 Flayra -// - Work at VALVe -// -// Revision 1.30 2002/08/09 00:17:03 Flayra -// - Allow moveleft and moveright to change targets, allow players to have only one primary weapon -// -// Revision 1.29 2002/07/23 16:48:21 Flayra -// - Refactored duplicate spawn code -// -// Revision 1.28 2002/07/10 14:36:09 Flayra -// - Fixed bug that caused "Battery" message to be sent every tick (this never showed up in HL because they never had a float armor value?) -// -// Revision 1.27 2002/07/08 16:31:39 Flayra -// - Level 1 doesn't make falling splat sound, dead players shouldn't block spawn points, replaced impulse hard-codes with constants -// -//=============================================================================== -#include -#include "extdll.h" -#include "util.h" - -#include "cbase.h" -#include "player.h" -#include "trains.h" -#include "nodes.h" -#include "weapons.h" -#include "soundent.h" -#include "monsters.h" -#include "../engine/shake.h" -#include "decals.h" -#include "gamerules.h" -#include "../mod/AvHEntities.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHPlayerUpgrade.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHSharedUtil.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHHulls.h" -#include "../mod/AvHMovementUtil.h" -#include "game.h" -#include "../common/hltv.h" -#include "../mod/AvHNetworkMessages.h" -#include "../util/MathUtil.h" - -// #define DUCKFIX - -// Allow assignment within conditional -#pragma warning (disable: 4706) - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL BOOL g_fDrawLines; -int gEvilImpulse101; -extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; - - -BOOL gInitHUD = TRUE; - -extern void CopyToBodyQue(entvars_t* pev); -extern void respawn(entvars_t *pev, BOOL fCopyCorpse); -extern Vector VecBModelOrigin(entvars_t *pevBModel ); -//extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); - -// the world node graph -extern CGraph WorldGraph; - -#define TRAIN_ACTIVE 0x80 -#define TRAIN_NEW 0xc0 -#define TRAIN_OFF 0x00 -#define TRAIN_NEUTRAL 0x01 -#define TRAIN_SLOW 0x02 -#define TRAIN_MEDIUM 0x03 -#define TRAIN_FAST 0x04 -#define TRAIN_BACK 0x05 - -#define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes -#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) - -// Global Savedata for player -TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = -{ - DEFINE_FIELD( CBasePlayer, m_afButtonLast, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonPressed, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonReleased, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgItems, FIELD_INTEGER, MAX_ITEMS ), - DEFINE_FIELD( CBasePlayer, m_afPhysicsFlags, FIELD_INTEGER ), - - DEFINE_FIELD( CBasePlayer, m_flTimeStepSound, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flSwimTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flDuckTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flWallJumpTime, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_flSuitUpdate, FIELD_TIME ), - DEFINE_ARRAY( CBasePlayer, m_rgSuitPlayList, FIELD_INTEGER, CSUITPLAYLIST ), - DEFINE_FIELD( CBasePlayer, m_iSuitPlayNext, FIELD_INTEGER ), - DEFINE_ARRAY( CBasePlayer, m_rgiSuitNoRepeat, FIELD_INTEGER, CSUITNOREPEAT ), - DEFINE_ARRAY( CBasePlayer, m_rgflSuitNoRepeatTime, FIELD_TIME, CSUITNOREPEAT ), - DEFINE_FIELD( CBasePlayer, m_lastDamageAmount, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CBasePlayer, m_pActiveItem, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayer, m_pLastItem, FIELD_CLASSPTR ), - - DEFINE_ARRAY( CBasePlayer, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_FIELD( CBasePlayer, m_idrowndmg, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_idrownrestored, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_tSneaking, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_iTrain, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_bitsHUDDamage, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_flFallVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, m_iTargetVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iExtraSoundTypes, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponFlash, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_fLongJump, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_fInitHUD, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_tbdPrev, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ), - DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ), -}; - -void CBasePlayer :: Pain( void ) -{ - float flRndSound;//sound randomizer - - flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); -} - -/* - * - */ -Vector VecVelocityForDamage(float flDamage) -{ - Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - - if (flDamage > -50) - vec = vec * 0.7; - else if (flDamage > -200) - vec = vec * 2; - else - vec = vec * 10; - - return vec; -} - -#if 0 /* -static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) -{ - edict_t *pentNew = CREATE_ENTITY(); - entvars_t *pevNew = VARS(pentNew); - - pevNew->origin = pev->origin; - SET_MODEL(ENT(pevNew), szGibModel); - UTIL_SetSize(pevNew, g_vecZero, g_vecZero); - - pevNew->velocity = VecVelocityForDamage(flDamage); - pevNew->movetype = MOVETYPE_BOUNCE; - pevNew->solid = SOLID_NOT; - pevNew->avelocity.x = RANDOM_FLOAT(0,600); - pevNew->avelocity.y = RANDOM_FLOAT(0,600); - pevNew->avelocity.z = RANDOM_FLOAT(0,600); - CHANGE_METHOD(ENT(pevNew), em_think, SUB_Remove); - pevNew->ltime = gpGlobals->time; - pevNew->nextthink = gpGlobals->time + RANDOM_FLOAT(10,20); - pevNew->frame = 0; - pevNew->flags = 0; -} - - -static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) -{ - SET_MODEL(ENT(pev), szGibModel); - pev->frame = 0; - pev->nextthink = -1; - pev->movetype = MOVETYPE_BOUNCE; - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT; - pev->view_ofs = Vector(0,0,8); - UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,56)); - pev->velocity = VecVelocityForDamage(flDamage); - pev->avelocity = RANDOM_FLOAT(-1,1) * Vector(0,600,0); - pev->origin.z -= 24; - ClearBits(pev->flags, FL_ONGROUND); -} - - -*/ -#endif - -int TrainSpeed(int iSpeed, int iMax) -{ - float fSpeed, fMax; - int iRet = 0; - - fMax = (float)iMax; - fSpeed = iSpeed; - - fSpeed = fSpeed/fMax; - - if (iSpeed < 0) - iRet = TRAIN_BACK; - else if (iSpeed == 0) - iRet = TRAIN_NEUTRAL; - else if (fSpeed < 0.33) - iRet = TRAIN_SLOW; - else if (fSpeed < 0.66) - iRet = TRAIN_MEDIUM; - else - iRet = TRAIN_FAST; - - return iRet; -} - -void CBasePlayer :: DeathSound( void ) -{ - // water death sounds - /* - if (pev->waterlevel == 3) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); - return; - } - */ - - // temporarily using pain sounds for death sounds - switch (RANDOM_LONG(1,5)) - { - case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - break; - case 2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - break; - case 3: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); - break; - } - - // play one of the suit death alarms - //EMIT_GROUPNAME_SUIT(ENT(pev), "HEV_DEAD"); -} - -// override takehealth -// bitsDamageType indicates type of damage healed. - -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) -{ - return CBaseMonster :: TakeHealth (flHealth, bitsDamageType); - -} - -Vector CBasePlayer :: GetGunPosition( ) -{ -// UTIL_MakeVectors(pev->v_angle); -// m_HackedGunPos = pev->view_ofs; - Vector origin; - - origin = pev->origin + pev->view_ofs; - - return origin; -} - -//========================================================= -// TraceAttack -//========================================================= -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= gSkillData.plrHead; - break; - case HITGROUP_CHEST: - flDamage *= gSkillData.plrChest; - break; - case HITGROUP_STOMACH: - flDamage *= gSkillData.plrStomach; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= gSkillData.plrArm; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= gSkillData.plrLeg; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -void CBasePlayer::SpawnClientSideCorpse() -{ -// char *infobuffer = g_engfuncs.pfnGetInfoKeyBuffer( edict() ); -// char *pModel = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); -// -// MESSAGE_BEGIN( MSG_ALL, gmsgSendCorpse ); -// WRITE_STRING( pModel ); -// WRITE_LONG ( pev->origin.x * 128.0); -// WRITE_LONG ( pev->origin.y * 128.0); -// WRITE_LONG ( pev->origin.z * 128.0); -// WRITE_COORD ( pev->angles.x ); -// WRITE_COORD ( pev->angles.y ); -// WRITE_COORD ( pev->angles.z ); -// WRITE_LONG ( (pev->animtime - gpGlobals->time) * 100.0f ); -// WRITE_BYTE ( pev->sequence ); -// WRITE_BYTE ( pev->body ); -// MESSAGE_END(); -} - -/* - Take some damage. - NOTE: each call to TakeDamage with bitsDamageType set to a time-based damage - type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation - etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC. -*/ - -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // have suit diagnose the problem - ie: report damage type - int bitsDamage = bitsDamageType; - int ffound = TRUE; - int fmajor; - int fcritical; - int fTookDamage; - int ftrivial; - //float flRatio; - //float flBonus; - float flHealthPrev = pev->health; - - //flBonus = AvHPlayerUpgrade::GetArmorBonus(this->pev->iuser4); - //flRatio = AvHPlayerUpgrade::GetArmorRatio(this->pev->iuser4); - -// if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) -// { -// // blasts damage armor more. -// flBonus *= 2; -// } - - // Already dead - if ( !IsAlive() ) - return 0; - // go take the damage first - - - CBaseEntity *pAttacker = NULL; - - if(pevAttacker) - { - pAttacker = CBaseEntity::Instance(pevAttacker); - } - - if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) - { - // Refuse the damage - return 0; - } - - // keep track of amount of damage last sustained - m_lastDamageAmount = flDamage; - - if(!(bitsDamageType & DMG_IGNOREARMOR)) - { - flDamage = AvHPlayerUpgrade::CalculateDamageLessArmor((AvHUser3)this->pev->iuser3, this->pev->iuser4, flDamage, this->pev->armorvalue, bitsDamageType, GetGameRules()->GetNumActiveHives((AvHTeamNumber)this->pev->team)); - } - else - { - int a = 0; - } - - // Armor. -// if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage! -// { -// float flNew = flDamage * flRatio; -// -// float flArmor; -// -// flArmor = (flDamage - flNew) * flBonus; -// -// // Does this use more armor than we have? -// if (flArmor > pev->armorvalue) -// { -// flArmor = pev->armorvalue; -// flArmor *= (1/flBonus); -// flNew = flDamage - flArmor; -// pev->armorvalue = 0; -// } -// else -// pev->armorvalue -= flArmor; -// -// flDamage = flNew; -// } - - fTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); - - // reset damage time countdown for each type of time based damage player just sustained - - { - for (int i = 0; i < CDMG_TIMEBASED; i++) - if (bitsDamageType & (DMG_PARALYZE << i)) - m_rgbTimeBasedDamage[i] = 0; - } - - // tell director about it - MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); - WRITE_BYTE(DIRECTOR_MESSAGE_SIZE); - WRITE_BYTE ( DRC_CMD_EVENT ); // take damage event - WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity - WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity - WRITE_LONG( 5 ); // eventflags (priority and flags) - MESSAGE_END(); - - - // how bad is it, doc? - - ftrivial = (pev->health > 75 || m_lastDamageAmount < 5); - fmajor = (m_lastDamageAmount > 25); - fcritical = (pev->health < 30); - - // handle all bits set in this damage message, - // let the suit give player the diagnosis - - // UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash ) - - // UNDONE: still need to record damage and heal messages for the following types - - // DMG_BURN - // DMG_FREEZE - // DMG_BLAST - // DMG_SHOCK - - m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client - m_bitsHUDDamage = -1; // make sure the damage bits get resent - - while (fTookDamage && (!ftrivial || (bitsDamage & DMG_TIMEBASED)) && ffound && bitsDamage) - { - ffound = FALSE; - - if (bitsDamage & DMG_CLUB) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - bitsDamage &= ~DMG_CLUB; - ffound = TRUE; - } - if (bitsDamage & (DMG_FALL | DMG_CRUSH)) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC); // major fracture - else - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - - bitsDamage &= ~(DMG_FALL | DMG_CRUSH); - ffound = TRUE; - } - - if (bitsDamage & DMG_BULLET) - { - if (m_lastDamageAmount > 5) - SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC); // blood loss detected - //else - // SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_BULLET; - ffound = TRUE; - } - - if (bitsDamage & DMG_SLASH) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC); // major laceration - else - SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_SLASH; - ffound = TRUE; - } - - if (bitsDamage & DMG_SONIC) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN); // internal bleeding - bitsDamage &= ~DMG_SONIC; - ffound = TRUE; - } - - if (bitsDamage & (DMG_POISON | DMG_PARALYZE)) - { - SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN); // blood toxins detected - bitsDamage &= ~(DMG_POISON | DMG_PARALYZE); - ffound = TRUE; - } - - if (bitsDamage & DMG_ACID) - { - SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected - bitsDamage &= ~DMG_ACID; - ffound = TRUE; - } - - if (bitsDamage & DMG_NERVEGAS) - { - SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN); // biohazard detected - bitsDamage &= ~DMG_NERVEGAS; - ffound = TRUE; - } - - if (bitsDamage & DMG_RADIATION) - { - SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected - bitsDamage &= ~DMG_RADIATION; - ffound = TRUE; - } - if (bitsDamage & DMG_SHOCK) - { - bitsDamage &= ~DMG_SHOCK; - ffound = TRUE; - } - } - - pev->punchangle.x = -2; - - if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) - { - // first time we take major damage... - // turn automedic on if not on - SetSuitUpdate("!HEV_MED1", FALSE, SUIT_NEXT_IN_30MIN); // automedic on - - // give morphine shot if not given recently - SetSuitUpdate("!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN); // morphine shot - } - - if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75) - { - - // already took major damage, now it's critical... - if (pev->health < 6) - SetSuitUpdate("!HEV_HLTH3", FALSE, SUIT_NEXT_IN_10MIN); // near death - else if (pev->health < 20) - SetSuitUpdate("!HEV_HLTH2", FALSE, SUIT_NEXT_IN_10MIN); // health critical - - // give critical health warnings - if (!RANDOM_LONG(0,3) && flHealthPrev < 50) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - - // if we're taking time based damage, warn about its continuing effects - if (fTookDamage && (bitsDamageType & DMG_TIMEBASED) && flHealthPrev < 75) - { - if (flHealthPrev < 50) - { - if (!RANDOM_LONG(0,3)) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - else - SetSuitUpdate("!HEV_HLTH1", FALSE, SUIT_NEXT_IN_10MIN); // health dropping - } - - //return fTookDamage; - int theReturnValue = 0; - if(fTookDamage) - { - theReturnValue = flDamage; - } - return theReturnValue; -} - -//========================================================= -// PackDeadPlayerItems - call this when a player dies to -// pack up the appropriate weapons and ammo items, and to -// destroy anything that shouldn't be packed. -// -// This is pretty brute force :( -//========================================================= -void CBasePlayer::PackDeadPlayerItems( void ) -{ - int iWeaponRules; - int iAmmoRules; - int i; - CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have? - int iPackAmmo[ MAX_AMMO_SLOTS + 1]; - int iPW = 0;// index into packweapons array - int iPA = 0;// index into packammo array - - memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) ); - memset(iPackAmmo, -1, sizeof(iPackAmmo) ); - - // get the game rules - iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); - iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); - - if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) - { - // nothing to pack. Remove the weapons and return. Don't call create on the box! - RemoveAllItems( TRUE ); - return; - } - -// go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - switch( iWeaponRules ) - { - case GR_PLR_DROP_GUN_ACTIVE: - if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) - { - // this is the active item. Pack it. - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - } - break; - - case GR_PLR_DROP_GUN_ALL: - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - break; - - default: - break; - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - -// now go through ammo and make a list of which types to pack. - if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) - { - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( m_rgAmmo[ i ] > 0 ) - { - // player has some ammo of this type. - switch ( iAmmoRules ) - { - case GR_PLR_DROP_AMMO_ALL: - iPackAmmo[ iPA++ ] = i; - break; - - case GR_PLR_DROP_AMMO_ACTIVE: - if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) - { - // this is the primary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) - { - // this is the secondary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - break; - - default: - break; - } - } - } - } - -// create a box to pack the stuff into. - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, edict() ); - - pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. - pWeaponBox->pev->angles.z = 0; - - pWeaponBox->SetThink( &CWeaponBox::Kill ); - pWeaponBox->pev->nextthink = gpGlobals->time + 120; - -// back these two lists up to their first elements - iPA = 0; - iPW = 0; - -// pack the ammo - while ( iPackAmmo[ iPA ] != -1 ) - { - // Only pack items with ammo - const char* theAmmoName = CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName; - if(theAmmoName && theAmmoName != "") - pWeaponBox->PackAmmo( MAKE_STRING(theAmmoName), m_rgAmmo[ iPackAmmo[ iPA ] ] ); - - iPA++; - } - -// now pack all of the items in the lists - while ( rgpPackWeapons[ iPW ] ) - { - // weapon unhooked from the player. Pack it into der box. - pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); - - iPW++; - } - - pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. - - RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. -} - -void CBasePlayer::DestroyAllItems(BOOL removeSuit) -{ - if (m_pActiveItem) - { - ResetAutoaim( ); - m_pActiveItem->Holster( ); - m_pActiveItem = NULL; - } - - m_pLastItem = NULL; - - int i; - CBasePlayerItem *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) - { - pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->DestroyItem(); - m_pActiveItem = pPendingItem; - } - m_rgpPlayerItems[i] = NULL; - } - m_pActiveItem = NULL; - - pev->viewmodel = 0; - pev->weaponmodel = 0; - - if ( removeSuit ) - pev->weapons = 0; - else - pev->weapons &= ~WEAPON_ALLWEAPONS; - - for ( i = 0; i < MAX_AMMO_SLOTS;i++) - m_rgAmmo[i] = 0; - - // send Selected Weapon Message to our client - NetMsg_CurWeapon( pev, 0, 0, 0 ); -} - -void CBasePlayer::RemoveAllItems( BOOL removeSuit ) -{ - if (m_pActiveItem) - { - ResetAutoaim( ); - m_pActiveItem->Holster( ); - m_pActiveItem = NULL; - } - - m_pLastItem = NULL; - - int i; - CBasePlayerItem *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) - { - pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->Drop( ); - m_pActiveItem = pPendingItem; - } - m_rgpPlayerItems[i] = NULL; - } - m_pActiveItem = NULL; - - pev->viewmodel = 0; - pev->weaponmodel = 0; - - if ( removeSuit ) - pev->weapons = 0; - else - pev->weapons &= ~WEAPON_ALLWEAPONS; - - for ( i = 0; i < MAX_AMMO_SLOTS;i++) - m_rgAmmo[i] = 0; - -// UpdateClientData(); -// // send Selected Weapon Message to our client -// MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); -// WRITE_BYTE(0); -// WRITE_BYTE(0); -// WRITE_BYTE(0); -// MESSAGE_END(); -} - -/* - * GLOBALS ASSUMED SET: g_ulModelIndexPlayer - * - * ENTITY_METHOD(PlayerDie) - */ -entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage inflictor for death messages. - // Better solution: Add as parameter to all Killed() functions. - -void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) -{ - CSound *pSound; - - // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); - - GetGameRules()->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); - - if ( m_pTank != NULL ) - { - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - - // this client isn't going to be thinking for a while, so reset the sound until they respawn - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) ); - { - if ( pSound ) - { - pSound->Reset(); - } - } - - SetAnimation( PLAYER_DIE ); - - m_iRespawnFrames = 0; - - //pev->modelindex = g_ulModelIndexPlayer; // don't use eyes - - // Clear buttons held down on death, fixes bug where player can't switch observer targets - m_afButtonLast = 0; - - pev->deadflag = DEAD_DYING; - pev->movetype = MOVETYPE_TOSS; - ClearBits( pev->flags, FL_ONGROUND ); - if (pev->velocity.z < 10) - pev->velocity.z += RANDOM_FLOAT(0,300); - - // clear out the suit message cache so we don't keep chattering - SetSuitUpdate(NULL, FALSE, 0); - - // send "health" update message to zero - m_iClientHealth = 0; - NetMsg_Health( pev, m_iClientHealth ); - - // Tell Ammo Hud that the player is dead - NetMsg_CurWeapon( pev, 0, 0xFF, 0xFF ); - - // reset FOV - pev->fov = m_iFOV = m_iClientFOV = 0; - NetMsg_SetFOV( pev, 0 ); - - - // UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12 - // UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE ); - - if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) - { - pev->solid = SOLID_NOT; - GibMonster(); // This clears pev->model - pev->effects |= EF_NODRAW; - return; - } - - DeathSound(); - - pev->angles.x = 0; - pev->angles.z = 0; - - SetThink(&CBasePlayer::PlayerDeathThink); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CBasePlayer::Suicide(void) -{ - AvHPlayer* thePlayer = dynamic_cast(this); - - ASSERT(thePlayer); - - if(thePlayer && thePlayer->GetUsedKilled())//: prevent exploitation of "kill" command. - return; - - // have the player kill themself - float theKillDelay = ns_cvar_float(&avh_killdelay); - - #ifdef DEBUG - #ifndef AVH_EXTERNAL_BUILD - theKillDelay = 0; - #endif - #endif - - if(theKillDelay > 0.0f) - { - char theMessage[256]; - sprintf(theMessage, "Suiciding in %.1f seconds...\n", theKillDelay); - UTIL_SayText(theMessage, this, ENTINDEX(this->edict())); - } - - thePlayer->SetUsedKilled(true); - SetThink(&CBasePlayer::SuicideThink); - this->pev->nextthink = gpGlobals->time + theKillDelay; -} - -void CBasePlayer::SuicideThink(void) -{ - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && thePlayer->GetCanBeAffectedByEnemies()) - { - this->pev->health = 0; - this->Killed(this->pev, GIB_NEVER); - } -} - -// Set the activity based on an event or current state -void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) -{ - int animDesired; - int gaitDesired; - float speed; - char szAnim[64]; - bool theFoundAnim = true; - int theDebugAnimations = BALANCE_VAR(kDebugAnimations); - bool reloadAnim = false; - - // Make sure the model is set, as gestating models aren't set before the animation starts playing - AvHPlayer* theAvHPlayer = dynamic_cast(this); - ASSERT(theAvHPlayer); - theAvHPlayer->SetModelFromState(); - - speed = pev->velocity.Length2D(); - - if (pev->flags & FL_FROZEN) - { - speed = 0; - playerAnim = PLAYER_IDLE; - } - - switch (playerAnim) - { - case PLAYER_JUMP: - m_IdealActivity = ACT_HOP; - break; - - case PLAYER_SUPERJUMP: - m_IdealActivity = ACT_LEAP; - break; - - case PLAYER_DIE: - m_IdealActivity = ACT_DIESIMPLE; - m_IdealActivity = GetDeathActivity( ); - - //this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - //animDesired = LookupSequence( szAnim ); - //if (animDesired == -1) - //{ - // animDesired = 0; - //} - //this->pev->sequence = animDesired; - break; - - case PLAYER_ATTACK1: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - break; - - case PLAYER_PRIME: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RANGE_PRIME; - break; - } - break; - - case PLAYER_RELOAD: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD; - break; - } - break; - case PLAYER_RELOAD_START: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD_START; - break; - } - break; - case PLAYER_RELOAD_INSERT: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD_INSERT; - break; - } - break; - case PLAYER_RELOAD_END: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD_END; - break; - } - break; - case PLAYER_IDLE: - case PLAYER_WALK: - if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping - { - m_IdealActivity = m_Activity; - } - else if ( pev->waterlevel > 1 ) - { - if ( speed == 0 ) - m_IdealActivity = ACT_HOVER; - else - m_IdealActivity = ACT_SWIM; - } - else - { - if((playerAnim == PLAYER_IDLE) && !strcmp(this->m_szAnimExtention, "") && (theAvHPlayer->GetPlayMode() != PLAYMODE_READYROOM)) - { - m_IdealActivity = ACT_IDLE; - } - else - { - m_IdealActivity = ACT_WALK; - } - } - break; - } - - switch (m_IdealActivity) - { - - case ACT_DIESIMPLE: - case ACT_DIEBACKWARD: - case ACT_DIEFORWARD: - case ACT_DIEVIOLENT: - default: - if ( m_Activity == m_IdealActivity) - return; - m_Activity = m_IdealActivity; - - //animDesired = LookupActivity( m_Activity ); - this->GetAnimationForActivity(this->m_Activity, szAnim); - animDesired = LookupSequence( szAnim ); - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - #ifdef DEBUG - if(theDebugAnimations) - { - char theMessage[256]; - sprintf(theMessage, "Setting full-body animation (%s): %d (no gaitsequence)\n", szAnim, animDesired); - ALERT(at_console, theMessage); - } - #endif - - pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); - return; - - // create seperate case for these so that they don't interfere with a reload - Elven - case ACT_HOVER: - case ACT_LEAP: - case ACT_SWIM: - case ACT_HOP: - reloadAnim = (m_Activity == ACT_RELOAD) || (m_Activity == ACT_RELOAD_START) || (m_Activity == ACT_RELOAD_INSERT) || (m_Activity == ACT_RELOAD_END); - if ( m_Activity == m_IdealActivity || reloadAnim) - return; - m_Activity = m_IdealActivity; - - //animDesired = LookupActivity( m_Activity ); - this->GetAnimationForActivity(this->m_Activity, szAnim); - animDesired = LookupSequence( szAnim ); - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); - return; - - - case ACT_RANGE_ATTACK1: - case ACT_RANGE_PRIME: - this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - animDesired = LookupSequence( szAnim ); - - if (animDesired == -1) - { - animDesired = 0; - theFoundAnim = false; - } - - if ( pev->sequence != animDesired || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - if (!m_fSequenceLoops) - { - pev->effects |= EF_NOINTERP; - } - - m_Activity = m_IdealActivity; - - if(theFoundAnim) - { - #ifdef DEBUG - if(theDebugAnimations) - { - char theMessage[256]; - sprintf(theMessage, "%s%s\n", "Setting attack animation: ", szAnim); - ALERT(at_console, theMessage); - } - #endif - } - - pev->sequence = animDesired; - ResetSequenceInfo( ); - break; - - case ACT_RELOAD: - case ACT_RELOAD_START: - case ACT_RELOAD_INSERT: - case ACT_RELOAD_END: - this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - animDesired = LookupSequence( szAnim ); - - if ( pev->sequence != animDesired || !m_fSequenceLoops ) - { - pev->frame = 0; - } - m_Activity = m_IdealActivity; - break; - - - - case ACT_WALK: - reloadAnim = (m_Activity == ACT_RELOAD) || (m_Activity == ACT_RELOAD_START) || - (m_Activity == ACT_RELOAD_INSERT) || (m_Activity == ACT_RELOAD_END); - if ((m_Activity != ACT_RANGE_ATTACK1 && m_Activity != ACT_RANGE_PRIME && !reloadAnim/*m_Activity != ACT_RELOAD*/ ) || m_fSequenceFinished) - { - this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - animDesired = LookupSequence( szAnim ); - if (animDesired == -1) - { - animDesired = 0; - } - m_Activity = ACT_WALK; - } - else - { - animDesired = pev->sequence; - } - break; - } - - // Now handle gaitsequence - if(FBitSet(this->pev->flags, FL_DUCKING)) - { - if(speed == 0) - { - this->GetAnimationForActivity(ACT_CROUCHIDLE, szAnim, true); - } - else - { - this->GetAnimationForActivity(ACT_CROUCH, szAnim, true); - } - } - else if (speed > this->GetMaxWalkSpeed() ) - { - this->GetAnimationForActivity(ACT_RUN, szAnim, true); - } - else if (speed > 0) - { - this->GetAnimationForActivity(ACT_WALK, szAnim, true); - } - else - { - this->GetAnimationForActivity(ACT_IDLE, szAnim, true); - } - - // Set the gaitsequence - gaitDesired = LookupSequence(szAnim, 1); - if(gaitDesired == -1) - { - gaitDesired = 0; - } - -#ifdef DEBUG - if(theDebugAnimations) - { - if((this->pev->gaitsequence != gaitDesired) || (this->pev->sequence != animDesired)) - { - ALERT(at_console, "Anim desired (%s): %d, gaitsequence: %d gaitdesired: %d \n", szAnim, animDesired, pev->gaitsequence, gaitDesired); - } - } -#endif - - this->pev->gaitsequence = gaitDesired; - - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && (thePlayer->GetPlayMode() == PLAYMODE_READYROOM)) - { - // Play some animation on top and bottom when not holding any weapons - animDesired = gaitDesired; - } - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - // Reset to first frame of desired animation - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); -} - -/* -=========== -TabulateAmmo -This function is used to find and store -all the ammo we have into the ammo vars. -============ -*/ -void CBasePlayer::TabulateAmmo() -{ - ammo_9mm = AmmoInventory( GetAmmoIndex( "9mm" ) ); - ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) ); - ammo_argrens = AmmoInventory( GetAmmoIndex( "ARgrenades" ) ); - ammo_bolts = AmmoInventory( GetAmmoIndex( "bolts" ) ); - ammo_buckshot = AmmoInventory( GetAmmoIndex( "buckshot" ) ); - ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) ); - ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) ); - ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) ); -} - - -/* -=========== -WaterMove -============ -*/ -#define AIRTIME 12 // lung full of air lasts this many seconds - -void CBasePlayer::WaterMove() -{ - int air; - - if (pev->movetype == MOVETYPE_NOCLIP) - return; - - if (pev->health < 0) - return; - - // waterlevel 0 - not in water - // waterlevel 1 - feet in water - // waterlevel 2 - waist in water - // waterlevel 3 - head in water - - if (pev->waterlevel != 3) - { - // not underwater - - // play 'up for air' sound - if (pev->air_finished < gpGlobals->time) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", 1, ATTN_NORM); - else if (pev->air_finished < gpGlobals->time + 9) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", 1, ATTN_NORM); - - pev->air_finished = gpGlobals->time + AIRTIME; - pev->dmg = 2; - - // if we took drowning damage, give it back slowly - if (m_idrowndmg > m_idrownrestored) - { - // set drowning damage bit. hack - dmg_drownrecover actually - // makes the time based damage code 'give back' health over time. - // make sure counter is cleared so we start count correctly. - - // NOTE: this actually causes the count to continue restarting - // until all drowning damage is healed. - - m_bitsDamageType |= DMG_DROWNRECOVER; - m_bitsDamageType &= ~DMG_DROWN; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - } - - } - else - { // fully under water - // stop restoring damage while underwater - m_bitsDamageType &= ~DMG_DROWNRECOVER; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - - if (pev->air_finished < gpGlobals->time) // drown! - { - if (pev->pain_finished < gpGlobals->time) - { - // take drowning damage - pev->dmg += 1; - if (pev->dmg > 5) - pev->dmg = 5; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN); - pev->pain_finished = gpGlobals->time + 1; - - // track drowning damage, give it back when - // player finally takes a breath - - m_idrowndmg += pev->dmg; - } - } - else - { - m_bitsDamageType &= ~DMG_DROWN; - } - } - - if (!pev->waterlevel) - { - if (FBitSet(pev->flags, FL_INWATER)) - { - ClearBits(pev->flags, FL_INWATER); - } - return; - } - - // make bubbles - - air = (int)(pev->air_finished - gpGlobals->time); - if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim1.wav", 0.8, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 0.8, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim3.wav", 0.8, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim4.wav", 0.8, ATTN_NORM); break; - } - } - - if (pev->watertype == CONTENT_LAVA) // do damage - { - if (pev->dmgtime < gpGlobals->time) - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN); - } - else if (pev->watertype == CONTENT_SLIME) // do damage - { - pev->dmgtime = gpGlobals->time + 1; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID); - } - - if (!FBitSet(pev->flags, FL_INWATER)) - { - SetBits(pev->flags, FL_INWATER); - pev->dmgtime = 0; - } -} - -void CBasePlayer::InitPlayerFromSpawn(edict_t* inSpawn) -{ - if(!FNullEnt(inSpawn)) - { - int theOffset = AvHMUGetOriginOffsetForUser3(AvHUser3(this->pev->iuser3)); - this->pev->origin = VARS(inSpawn)->origin + Vector(0, 0, theOffset); - - this->pev->v_angle = VARS(inSpawn)->v_angle; - this->pev->velocity = g_vecZero; - this->pev->angles = VARS(inSpawn)->angles; - this->pev->punchangle = g_vecZero; - this->pev->fixangle = TRUE; - } -} - -// TRUE if the player is attached to a ladder -BOOL CBasePlayer::IsOnLadder( void ) -{ - return ( pev->movetype == MOVETYPE_FLY ); -} - -void CBasePlayer::PlayerDeathThink(void) -{ - float flForward; - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - flForward = pev->velocity.Length() - 20; - if (flForward <= 0) - pev->velocity = g_vecZero; - else - pev->velocity = flForward * pev->velocity.Normalize(); - } - - if ( HasWeapons() ) - { - // we drop the guns here because weapons that have an area effect and can kill their user - // will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the - // player class sometimes is freed. It's safer to manipulate the weapons once we know - // we aren't calling into any of their code anymore through the player pointer. - PackDeadPlayerItems(); - - // Assumes that all players have at least one weapon when they die - //SpawnClientSideCorpse(); - } - - if (pev->modelindex && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)) - { - StudioFrameAdvance( ); - - m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands - if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this - return; - } - - // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore - // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn - if ( pev->movetype != MOVETYPE_NONE && FBitSet(pev->flags, FL_ONGROUND) ) - pev->movetype = MOVETYPE_NONE; - - if (pev->deadflag == DEAD_DYING) - pev->deadflag = DEAD_DEAD; - - StopAnimation(); - - pev->effects |= EF_NOINTERP; - pev->framerate = 0.0; - - BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); - - // wait for all buttons released - if (pev->deadflag == DEAD_DEAD) - { - //if (fAnyButtonDown) - // return; - - //if ( g_pGameRules->FPlayerCanRespawn( this ) ) - //{ - m_fDeadTime = gpGlobals->time; - pev->deadflag = DEAD_RESPAWNABLE; - //} - - return; - } - -// if the player has been dead for one second longer than allowed by forcerespawn, -// forcerespawn isn't on. Send the player off to an intermission camera until they -// choose to respawn. - //if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) ) - //{ - // // go to dead camera. - // StartDeathCam(); - //} - - - // From Counter-strike - // if the player has been dead for one second longer than allowed by forcerespawn, - // forcerespawn isn't on. Send the player off to an intermission camera until they - // choose to respawn. -// if ( g_pGameRules->IsMultiplayer() && -// ( gpGlobals->time > (m_fDeadTime + 3) ) && -// !( m_afPhysicsFlags & PFLAG_OBSERVER) ) -// { -// //Send message to everybody to spawn a corpse. -// SpawnClientSideCorpse(); -// -// // go to dead camera. -// //StartDeathCam(); -// } - - const float kMinDeathTime = .5f; - -// wait for any button down, or mp_forcerespawn is set and the respawn time is up - if ((!fAnyButtonDown || ( gpGlobals->time < (m_fDeadTime + kMinDeathTime) )) - && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && (gpGlobals->time > (m_fDeadTime + kMinDeathTime))) ) - return; - - pev->button = 0; - m_iRespawnFrames = 0; - - // Player is done with the death cam, continue - AvHPlayer* thePlayer = dynamic_cast(this); - AvHGamerules* theGameRules = dynamic_cast(g_pGameRules); - - theGameRules->PlayerDeathEnd(thePlayer); -} - -//========================================================= -// StartDeathCam - find an intermission spot and send the -// player off into observer mode -//========================================================= -void CBasePlayer::StartDeathCam( void ) -{ - edict_t *pSpot, *pNewSpot; - int iRand; - - if ( pev->view_ofs == g_vecZero ) - { - // don't accept subsequent attempts to StartDeathCam() - return; - } - - pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission"); - - if ( !FNullEnt( pSpot ) ) - { - // at least one intermission spot in the world. - iRand = RANDOM_LONG( 0, 3 ); - - while ( iRand > 0 ) - { - pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission"); - - if ( pNewSpot ) - { - pSpot = pNewSpot; - } - - iRand--; - } - - CopyToBodyQue( pev ); - StartObserver( pSpot->v.origin, pSpot->v.v_angle ); - } - else - { - // no intermission spot. Push them up in the air, looking down at their corpse - TraceResult tr; - CopyToBodyQue( pev ); - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); - return; - } -} - -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) -{ -// m_afPhysicsFlags |= PFLAG_OBSERVER; -// -// pev->view_ofs = g_vecZero; -// pev->angles = pev->v_angle = vecViewAngle; -// pev->fixangle = TRUE; -// pev->solid = SOLID_NOT; -// pev->takedamage = DAMAGE_NO; -// pev->movetype = MOVETYPE_NONE; -// pev->modelindex = 0; -// UTIL_SetOrigin( pev, vecPosition ); - - m_iHideHUD |= (HIDEHUD_HEALTH | HIDEHUD_WEAPONS); - m_afPhysicsFlags |= PFLAG_OBSERVER; - - pev->effects = EF_NODRAW; - pev->view_ofs = g_vecZero; - pev->angles = pev->v_angle = vecViewAngle; - pev->fixangle = TRUE; - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - pev->movetype = MOVETYPE_NONE; - UTIL_SetOrigin( pev, vecPosition ); - - ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); - ClearBits( pev->flags, FL_DUCKING ); - // pev->flags = FL_CLIENT | FL_SPECTATOR; // Should we set Spectator flag? Or is it reserver for people connecting with spectator 1? - pev->deadflag = DEAD_RESPAWNABLE; - - // Tell the physics code that this player's now in observer mode - Observer_SetMode(this->GetDefaultSpectatingMode()); - Observer_SpectatePlayer(this->GetDefaultSpectatingTarget()); - m_flNextObserverInput = 0; -} - -void CBasePlayer::StopObserver() -{ - this->pev->solid = SOLID_SLIDEBOX; - this->pev->effects = 0; - this->pev->takedamage = DAMAGE_YES; - this->pev->movetype = MOVETYPE_WALK; - ClearBits(this->m_afPhysicsFlags, PFLAG_OBSERVER); - ClearBits(this->m_afPhysicsFlags, PFLAG_DUCKING ); - ClearBits(this->pev->flags, FL_DUCKING ); - this->pev->iuser1 = this->pev->iuser2 = 0; -} - -// -// PlayerUse - handles USE keypress -// -#define PLAYER_SEARCH_RADIUS (float)64 - -void CBasePlayer::ClearKeys() -{ - // clear attack/use commands from player - this->m_afButtonPressed = 0; - this->pev->button = 0; - this->m_afButtonReleased = 0; -} - -void CBasePlayer::PlayerUse ( void ) -{ - AvHPlayer* theAvHPlayer = dynamic_cast(this); - - // Was use pressed or released? - if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) - return; - - //: Dont do this on commanders to prevent phantom use sounds. - if(theAvHPlayer->GetIsInTopDownMode()) - return; - - // Hit Use on a train? - if ( m_afButtonPressed & IN_USE ) - { - if ( m_pTank != NULL ) - { - // Stop controlling the tank - // TODO: Send HUD Update - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - return; - } - else - { - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - else - { // Start controlling the train! - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - - if ( pTrain && !(pev->button & IN_JUMP) && FBitSet(pev->flags, FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(pev) ) - { - m_afPhysicsFlags |= PFLAG_ONTRAIN; - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); - m_iTrain |= TRAIN_NEW; - EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM); - return; - } - } - } - } - - CBaseEntity *pObject = NULL; - CBaseEntity *pClosest = NULL; - Vector vecLOS; - float flMaxDot = VIEW_FIELD_NARROW; - float flDot; - - UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing - - - while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL) - { - - if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE)) - { - // !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that - // this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS - // when player hits the use key. How many objects can be in that area, anyway? (sjb) - vecLOS = (VecBModelOrigin( pObject->pev ) - (pev->origin + pev->view_ofs)); - - // This essentially moves the origin of the target to the corner nearest the player to test to see - // if it's "hull" is in the view cone - vecLOS = UTIL_ClampVectorToBox( vecLOS, pObject->pev->size * 0.5 ); - - flDot = DotProduct (vecLOS , gpGlobals->v_forward); - if (flDot > flMaxDot ) - {// only if the item is in front of the user - pClosest = pObject; - flMaxDot = flDot; -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } - } - - pObject = pClosest; - - // Add los test for aliens looking at hives. - if ( pObject == NULL && AvHGetIsAlien(this->pev->iuser3) ) { - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = this->GetGunPosition( ) + vecAiming; - Vector vecEnd = vecSrc + vecAiming*800; - - TraceResult theTraceResult; - UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, this->edict(), &theTraceResult); - - edict_t* theEntityHit = theTraceResult.pHit; - AvHHive *theHive = dynamic_cast(CBaseEntity::Instance(theEntityHit)); - if ( theHive) { - - float the2DDistance = VectorDistance2D(this->pev->origin, theHive->pev->origin); - - // Enabled state is true - if(the2DDistance <= 150.0 && (this->pev->origin < theHive->pev->origin) ) - { - pObject=theHive; - } - } - } - - // Found an object - if (pObject ) - { - //!!!UNDONE: traceline here to prevent USEing buttons through walls - int caps = pObject->ObjectCaps(); - - if ( m_afButtonPressed & IN_USE ) - { - //EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM); - const char* theSound = AvHSHUGetCommonSoundName(theAvHPlayer->GetIsAlien(), WEAPON_SOUND_SELECT); - EMIT_SOUND( ENT(pev), CHAN_ITEM, theSound, 0.4, ATTN_NORM); - } - - if ( ( (pev->button & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || - ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) - { - if ( caps & FCAP_CONTINUOUS_USE ) - m_afPhysicsFlags |= PFLAG_USING; - - pObject->Use( this, this, USE_SET, 1 ); - } - // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away - else if ( (m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use - { - pObject->Use( this, this, USE_SET, 0 ); - } - } - else - { - if ( m_afButtonPressed & IN_USE ) - { - //EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM); - const char* theSound = AvHSHUGetCommonSoundName(theAvHPlayer->GetIsAlien(), WEAPON_SOUND_DENYSELECT); - EMIT_SOUND( ENT(pev), CHAN_ITEM, theSound, 0.4, ATTN_NORM); - } - } -} - - - -void CBasePlayer::Jump() -{ - Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping - Vector vecAdjustedVelocity; - Vector vecSpot; - TraceResult tr; - - if (FBitSet(pev->flags, FL_WATERJUMP)) - return; - - if (pev->waterlevel >= 2) - { - return; - } - - // jump velocity is sqrt( height * gravity * 2) - - // If this isn't the first frame pressing the jump button, break out. - if ( !FBitSet( m_afButtonPressed, IN_JUMP ) ) - return; // don't pogo stick - - if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity ) - { - return; - } - -// many features in this function use v_forward, so makevectors now. - UTIL_MakeVectors (pev->angles); - - // ClearBits(pev->flags, FL_ONGROUND); // don't stairwalk - - SetAnimation( PLAYER_JUMP ); - - if ( m_fLongJump && - (pev->button & IN_DUCK) && - ( pev->flDuckTime > 0 ) && - pev->velocity.Length() > 50 ) - { - SetAnimation( PLAYER_SUPERJUMP ); - } - - // If you're standing on a conveyor, add it's velocity to yours (for momentum) - entvars_t *pevGround = VARS(pev->groundentity); - if ( pevGround && (pevGround->flags & FL_CONVEYOR) ) - { - pev->velocity = pev->velocity + pev->basevelocity; - } -} - - - -// This is a glorious hack to find free space when you've crouched into some solid space -// Our crouching collisions do not work correctly for some reason and this is easier -// than fixing the problem :( -void FixPlayerCrouchStuck( edict_t *pPlayer ) -{ - TraceResult trace; - - // Move up as many as 18 pixels if the player is stuck. - for ( int i = 0; i < 18; i++ ) - { - UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace ); - if ( trace.fStartSolid ) - pPlayer->v.origin.z ++; - else - break; - } -} - -void CBasePlayer::Duck( ) -{ - if (pev->button & IN_DUCK) - { - if ( m_IdealActivity != ACT_LEAP ) - { - SetAnimation( PLAYER_WALK ); - } - } -} - -// -// ID's player as such. -// -int CBasePlayer::Classify ( void ) -{ - return CLASS_PLAYER; -} - - -void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) -{ - // Positive score always adds - if ( score < 0 ) - { - if ( !bAllowNegativeScore ) - { - if ( pev->frags < 0 ) // Can't go more negative - return; - - if ( -score > pev->frags ) // Will this go negative? - { - score = -pev->frags; // Sum will be 0 - } - } - } - - pev->frags += score; -} - -void CBasePlayer::EffectivePlayerClassChanged() -{ -} - -void CBasePlayer::NeedsTeamUpdate() -{ -} - -void CBasePlayer::SendTeamUpdate() -{ -} - -void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) -{ - int index = entindex(); - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && i != index ) - { - if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) - { - pPlayer->AddPoints( score, bAllowNegativeScore ); - } - } - } -} - -//Player ID -void CBasePlayer::InitStatusBar() -{ - m_flStatusBarDisappearDelay = 0; - m_SbarString1[0] = m_SbarString0[0] = 0; -} - -void CBasePlayer::UpdateStatusBar() -{ - int newSBarState[ SBAR_END ]; - char sbuf0[ SBAR_STRING_SIZE ]; - char sbuf1[ SBAR_STRING_SIZE ]; - - int i; - - for (i = 0; i < SBAR_END; ++i) - { - newSBarState[i] = -1; - } - - //memset( newSBarState, 0, sizeof(newSBarState) ); - - strcpy( sbuf0, m_SbarString0 ); - strcpy( sbuf1, m_SbarString1 ); - - // Find an ID Target - TraceResult tr; - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - Vector vecSrc = EyePosition(); - Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE); - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr); - - bool theIsCombatMode = GetGameRules()->GetIsCombatMode(); - int theMaxEnumToSend = SBAR_ID_TARGETARMOR; - if(theIsCombatMode) - { - theMaxEnumToSend = SBAR_ID_TARGETLEVEL; - } - - if (tr.flFraction != 1.0) - { - if ( !FNullEnt( tr.pHit ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if(!pEntity) - return; - - if (pEntity->Classify() == CLASS_PLAYER ) - { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); - - // Name Health: X% Armor: Y% - //strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" ); - - // (health: X armor: Y) - if(!theIsCombatMode) - { - strcpy( sbuf1, "2 (health: %i2%%\n3 armor: %i3%%)" ); - } - else - { - strcpy( sbuf1, "2 (health: %i2%%\n3 armor: %i3%%\n4 level: %i4)" ); - } - - // allies and medics get to see the targets health - if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) - { - int theLevel = 1; - AvHPlayer* thePlayer = dynamic_cast(pEntity); - if(thePlayer) - { - theLevel = thePlayer->GetExperienceLevel(); - } - - //newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); - //newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. - float theHealthPercent = pEntity->pev->health/AvHPlayerUpgrade::GetMaxHealth(pEntity->pev->iuser4, (AvHUser3)pEntity->pev->iuser3, theLevel); - float theArmorPercent = pEntity->pev->armorvalue/AvHPlayerUpgrade::GetMaxArmorLevel(pEntity->pev->iuser4, (AvHUser3)pEntity->pev->iuser3); - newSBarState[ SBAR_ID_TARGETHEALTH ] = max(theHealthPercent*100+0.5f, 0.0f); - newSBarState[ SBAR_ID_TARGETARMOR ] = max(theArmorPercent*100+0.5f, 0.0f); - newSBarState[ SBAR_ID_TARGETLEVEL ] = theLevel; - } - } - else - { - bool theSuccess = false; - - // Show hive health for friendlies - if(this->pev->team == pEntity->pev->team) - { - AvHUser3 theUser3 = (AvHUser3)pEntity->pev->iuser3; - switch(theUser3) - { - // Place user3s to draw here - case AVH_USER3_HIVE: - theSuccess = true; - break; - } - } - - if(theSuccess) - { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); - - strcpy( sbuf1, "2 (health: %i2%%)\n" ); - - float theHealthPercentage = pEntity->pev->health/pEntity->pev->max_health; - newSBarState[ SBAR_ID_TARGETHEALTH ] = max(theHealthPercentage*100+0.5f, 0.0f); - } - } - - m_flStatusBarDisappearDelay = gpGlobals->time + 1.0; - } - else if ( m_flStatusBarDisappearDelay > gpGlobals->time ) - { - // hold the values for a short amount of time after viewing the object - newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ]; - newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ]; - newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ]; - newSBarState[ SBAR_ID_TARGETLEVEL ] = m_izSBarState[ SBAR_ID_TARGETLEVEL ]; - } - } - - BOOL bForceResend = FALSE; - - if ( strcmp( sbuf0, m_SbarString0 ) ) - { - NetMsg_StatusText( pev, 0, string(sbuf0) ); - strcpy( m_SbarString0, sbuf0 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - if ( strcmp( sbuf1, m_SbarString1 ) ) - { - NetMsg_StatusText( pev, 1, string(sbuf1) ); - strcpy( m_SbarString1, sbuf1 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - // Check values and send if they don't match - for (i = 1; i <= theMaxEnumToSend; i++) - { - if ( newSBarState[i] != m_izSBarState[i] || bForceResend ) - { - NetMsg_StatusValue( pev, i, newSBarState[i] ); - m_izSBarState[i] = newSBarState[i]; - } - } -} - - - - - - - - - -#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing -#define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible -#define CLIMB_SPEED_DEC 15 // climbing deceleration rate -#define CLIMB_PUNCH_X -7 // how far to 'punch' client X axis when climbing -#define CLIMB_PUNCH_Z 7 // how far to 'punch' client Z axis when climbing - -void CBasePlayer::PreThink(void) -{ - int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame - - // Debounced button codes for pressed/released - // UNDONE: Do we need auto-repeat? - m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed" - m_afButtonReleased = buttonsChanged & (~pev->button); // The ones not down are "released" - - g_pGameRules->PlayerThink( this ); - - if ( g_fGameOver ) - return; // intermission or finale - - UTIL_MakeVectors(pev->v_angle); // is this still used? - - ItemPreFrame( ); - WaterMove(); - - if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) - m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; - else - m_iHideHUD |= HIDEHUD_FLASHLIGHT; - - - // JOHN: checks if new client data (for HUD and view control) needs to be sent to the client - UpdateClientData(); - - CheckTimeBasedDamage(); - - // Observer Button Handling - if (this->IsObserver() ) - { - Observer_HandleButtons(); - pev->impulse = 0; - return; - } - - CheckSuitUpdate(); - - if (pev->deadflag >= DEAD_DYING) - { - PlayerDeathThink(); - return; - } - - // So the correct flags get sent to client asap. - // - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - pev->flags |= FL_ONTRAIN; - else - pev->flags &= ~FL_ONTRAIN; - - // Train speed control - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - float vel; - - if ( !pTrain ) - { - TraceResult trainTrace; - // Maybe this is on the other side of a level transition - UTIL_TraceLine( pev->origin, pev->origin + Vector(0,0,-38), ignore_monsters, ENT(pev), &trainTrace ); - - // HACKHACK - Just look for the func_tracktrain classname - if ( trainTrace.flFraction != 1.0 && trainTrace.pHit ) - pTrain = CBaseEntity::Instance( trainTrace.pHit ); - - - if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) ) - { - //ALERT( at_error, "In train mode with no train!\n" ); - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - } - else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) ) - { - // Turn off the train if you jump, strafe, or the train controls go dead - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - - pev->velocity = g_vecZero; - vel = 0; - if ( m_afButtonPressed & IN_FORWARD ) - { - vel = 1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - else if ( m_afButtonPressed & IN_BACK ) - { - vel = -1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - - if (vel) - { - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); - m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; - } - - } else if (m_iTrain & TRAIN_ACTIVE) - m_iTrain = TRAIN_NEW; // turn off train - - if (pev->button & IN_JUMP) - { - // If on a ladder, jump off the ladder - // else Jump - Jump(); - } - - - // If trying to duck, already ducked, or in the process of ducking - if ((pev->button & IN_DUCK) || FBitSet(pev->flags,FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) { - if ( AvHMUGetCanDuck(this->pev->iuser3) ) - Duck(); - } - - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) - { - m_flFallVelocity = -pev->velocity.z; - } - - // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? - - // Clear out ladder pointer - m_hEnemy = NULL; - - if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) - { - pev->velocity = g_vecZero; - } -} -/* Time based Damage works as follows: - 1) There are several types of timebased damage: - - #define DMG_PARALYZE (1 << 14) // slows affected creature down - #define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad - #define DMG_POISON (1 << 16) // blood poisioning - #define DMG_RADIATION (1 << 17) // radiation exposure - #define DMG_DROWNRECOVER (1 << 18) // drown recovery - #define DMG_ACID (1 << 19) // toxic chemicals or acid burns - #define DMG_SLOWBURN (1 << 20) // in an oven - #define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer - - 2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter, - per damage type. The counter is decremented every second, so the maximum time - an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius - of a damaging effect like fire, nervegas, radiation will continually reset the counter to max. - - 3) Every second that a tbd counter is running, the player takes damage. The damage - is determined by the type of tdb. - Paralyze - 1/2 movement rate, 30 second duration. - Nervegas - 5 points per second, 16 second duration = 80 points max dose. - Poison - 2 points per second, 25 second duration = 50 points max dose. - Radiation - 1 point per second, 50 second duration = 50 points max dose. - Drown - 5 points per second, 2 second duration. - Acid/Chemical - 5 points per second, 10 second duration = 50 points max. - Burn - 10 points per second, 2 second duration. - Freeze - 3 points per second, 10 second duration = 30 points max. - - 4) Certain actions or countermeasures counteract the damaging effects of tbds: - - Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body - - recharged by suit recharger - Air In Lungs - drowning damage is done to air in lungs first, then to body - - recharged by poking head out of water - - 10 seconds if swiming fast - Air In SCUBA - drowning damage is done to air in tanks first, then to body - - 2 minutes in tanks. Need new tank once empty. - Radiation Syringe - Each syringe full provides protection vs one radiation dosage - Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison). - Health kit - Immediate stop to acid/chemical, fire or freeze damage. - Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage. - - -*/ - -// If player is taking time based damage, continue doing damage to player - -// this simulates the effect of being poisoned, gassed, dosed with radiation etc - -// anything that continues to do damage even after the initial contact stops. -// Update all time based damage counters, and shut off any that are done. - -// The m_bitsDamageType bit MUST be set if any damage is to be taken. -// This routine will detect the initial on value of the m_bitsDamageType -// and init the appropriate counter. Only processes damage every second. - -//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage -//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval - -//#define NERVEGAS_DURATION 16 -//#define NERVEGAS_DAMAGE 5.0 - -//#define POISON_DURATION 25 -//#define POISON_DAMAGE 2.0 - -//#define RADIATION_DURATION 50 -//#define RADIATION_DAMAGE 1.0 - -//#define ACID_DURATION 10 -//#define ACID_DAMAGE 5.0 - -//#define SLOWBURN_DURATION 2 -//#define SLOWBURN_DAMAGE 1.0 - -//#define SLOWFREEZE_DURATION 1.0 -//#define SLOWFREEZE_DAMAGE 3.0 - -/* */ - - -void CBasePlayer::CheckTimeBasedDamage() -{ - int i; - BYTE bDuration = 0; - - static float gtbdPrev = 0.0; - - if (!(m_bitsDamageType & DMG_TIMEBASED)) - return; - - // only check for time based damage approx. every 2 seconds - if (abs(gpGlobals->time - m_tbdPrev) < 2.0) - return; - - m_tbdPrev = gpGlobals->time; - - for (i = 0; i < CDMG_TIMEBASED; i++) - { - // make sure bit is set for damage type - if (m_bitsDamageType & (DMG_PARALYZE << i)) - { - switch (i) - { - case itbd_Paralyze: - // UNDONE - flag movement as half-speed - bDuration = PARALYZE_DURATION; - break; - case itbd_NerveGas: -// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); - bDuration = NERVEGAS_DURATION; - break; - case itbd_Poison: - TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC); - bDuration = POISON_DURATION; - break; - case itbd_Radiation: -// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); - bDuration = RADIATION_DURATION; - break; - case itbd_DrownRecover: - // NOTE: this hack is actually used to RESTORE health - // after the player has been drowning and finally takes a breath - if (m_idrowndmg > m_idrownrestored) - { - int idif = min(m_idrowndmg - m_idrownrestored, 10); - - TakeHealth(idif, DMG_GENERIC); - m_idrownrestored += idif; - } - bDuration = 4; // get up to 5*10 = 50 points back - break; - case itbd_Acid: -// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); - bDuration = ACID_DURATION; - break; - case itbd_SlowBurn: -// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); - bDuration = SLOWBURN_DURATION; - break; - case itbd_SlowFreeze: -// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); - bDuration = SLOWFREEZE_DURATION; - break; - default: - bDuration = 0; - } - - if (m_rgbTimeBasedDamage[i]) - { - // use up an antitoxin on poison or nervegas after a few seconds of damage - if (((i == itbd_NerveGas) && (m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION)) || - ((i == itbd_Poison) && (m_rgbTimeBasedDamage[i] < POISON_DURATION))) - { - if (m_rgItems[ITEM_ANTIDOTE]) - { - m_rgbTimeBasedDamage[i] = 0; - m_rgItems[ITEM_ANTIDOTE]--; - SetSuitUpdate("!HEV_HEAL4", FALSE, SUIT_REPEAT_OK); - } - } - - - // decrement damage duration, detect when done. - if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0) - { - m_rgbTimeBasedDamage[i] = 0; - // if we're done, clear damage bits - m_bitsDamageType &= ~(DMG_PARALYZE << i); - } - } - else - // first time taking this damage type - init damage duration - m_rgbTimeBasedDamage[i] = bDuration; - } - } -} - -/* -THE POWER SUIT - -The Suit provides 3 main functions: Protection, Notification and Augmentation. -Some functions are automatic, some require power. -The player gets the suit shortly after getting off the train in C1A0 and it stays -with him for the entire game. - -Protection - - Heat/Cold - When the player enters a hot/cold area, the heating/cooling indicator on the suit - will come on and the battery will drain while the player stays in the area. - After the battery is dead, the player starts to take damage. - This feature is built into the suit and is automatically engaged. - Radiation Syringe - This will cause the player to be immune from the effects of radiation for N seconds. Single use item. - Anti-Toxin Syringe - This will cure the player from being poisoned. Single use item. - Health - Small (1st aid kits, food, etc.) - Large (boxes on walls) - Armor - The armor works using energy to create a protective field that deflects a - percentage of damage projectile and explosive attacks. After the armor has been deployed, - it will attempt to recharge itself to full capacity with the energy reserves from the battery. - It takes the armor N seconds to fully charge. - -Notification (via the HUD) - -x Health -x Ammo -x Automatic Health Care - Notifies the player when automatic healing has been engaged. -x Geiger counter - Classic Geiger counter sound and status bar at top of HUD - alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal. -x Poison - Armor - Displays the current level of armor. - -Augmentation - - Reanimation (w/adrenaline) - Causes the player to come back to life after he has been dead for 3 seconds. - Will not work if player was gibbed. Single use. - Long Jump - Used by hitting the ??? key(s). Caused the player to further than normal. - SCUBA - Used automatically after picked up and after player enters the water. - Works for N seconds. Single use. - -Things powered by the battery - - Armor - Uses N watts for every M units of damage. - Heat/Cool - Uses N watts for every second in hot/cold area. - Long Jump - Uses N watts for every jump. - Alien Cloak - Uses N watts for each use. Each use lasts M seconds. - Alien Shield - Augments armor. Reduces Armor drain by one half - -*/ - -// if in range of radiation source, ping geiger counter - -#define GEIGERDELAY 0.25 - -void CBasePlayer :: UpdateGeigerCounter( void ) -{ - BYTE range; - - // delay per update ie: don't flood net with these msgs - if (gpGlobals->time < m_flgeigerDelay) - return; - - m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; - - // send range to radition source to client - - range = (BYTE) (m_flgeigerRange / 4); - - if (range != m_igeigerRangePrev) - { - m_igeigerRangePrev = range; - NetMsg_GeigerRange( pev, range ); - } - - // reset counter and semaphore - if (!RANDOM_LONG(0,3)) - m_flgeigerRange = 1000; - -} - -/* -================ -CheckSuitUpdate - -Play suit update if it's time -================ -*/ - -#define SUITUPDATETIME 3.5 -#define SUITFIRSTUPDATETIME 0.1 - -void CBasePlayer::CheckSuitUpdate() -{ - int i; - int isentence = 0; - int isearch = m_iSuitPlayNext; - - // Ignore suit updates if no suit - if ( !(pev->weapons & (1<IsMultiplayer() ) - { - // don't bother updating HEV voice in multiplayer. - return; - } - - if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0) - { - // play a sentence off of the end of the queue - for (i = 0; i < CSUITPLAYLIST; i++) - { - if (isentence = m_rgSuitPlayList[isearch]) - break; - - if (++isearch == CSUITPLAYLIST) - isearch = 0; - } - - if (isentence) - { - m_rgSuitPlayList[isearch] = 0; - if (isentence > 0) - { - // play sentence number - - char sentence[CBSENTENCENAME_MAX+1]; - strcpy(sentence, "!"); - strcat(sentence, gszallsentencenames[isentence]); - EMIT_SOUND_SUIT(ENT(pev), sentence); - } - else - { - // play sentence group - EMIT_GROUPID_SUIT(ENT(pev), -isentence); - } - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - else - // queue is empty, don't check - m_flSuitUpdate = 0; - } -} - -// add sentence to suit playlist queue. if fgroup is true, then -// name is a sentence group (HEV_AA), otherwise name is a specific -// sentence name ie: !HEV_AA0. If iNoRepeat is specified in -// seconds, then we won't repeat playback of this word or sentence -// for at least that number of seconds. - -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) -{ - int i; - int isentence; - int iempty = -1; - - - // Ignore suit updates if no suit - if ( !(pev->weapons & (1<IsMultiplayer() ) - { - // due to static channel design, etc. We don't play HEV sounds in multiplayer right now. - return; - } - - // if name == NULL, then clear out the queue - - if (!name) - { - for (i = 0; i < CSUITPLAYLIST; i++) - m_rgSuitPlayList[i] = 0; - return; - } - // get sentence or group number - if (!fgroup) - { - isentence = SENTENCEG_Lookup(name, NULL); - if (isentence < 0) - return; - } - else - // mark group number as negative - isentence = -SENTENCEG_GetIndex(name); - - // check norepeat list - this list lets us cancel - // the playback of words or sentences that have already - // been played within a certain time. - - for (i = 0; i < CSUITNOREPEAT; i++) - { - if (isentence == m_rgiSuitNoRepeat[i]) - { - // this sentence or group is already in - // the norepeat list - - if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time) - { - // norepeat time has expired, clear it out - m_rgiSuitNoRepeat[i] = 0; - m_rgflSuitNoRepeatTime[i] = 0.0; - iempty = i; - break; - } - else - { - // don't play, still marked as norepeat - return; - } - } - // keep track of empty slot - if (!m_rgiSuitNoRepeat[i]) - iempty = i; - } - - // sentence is not in norepeat list, save if norepeat time was given - - if (iNoRepeatTime) - { - if (iempty < 0) - iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over - m_rgiSuitNoRepeat[iempty] = isentence; - m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time; - } - - // find empty spot in queue, or overwrite last spot - - m_rgSuitPlayList[m_iSuitPlayNext++] = isentence; - if (m_iSuitPlayNext == CSUITPLAYLIST) - m_iSuitPlayNext = 0; - - if (m_flSuitUpdate <= gpGlobals->time) - { - if (m_flSuitUpdate == 0) - // play queue is empty, don't delay too long before playback - m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME; - else - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - -} - -/* -================ -CheckPowerups - -Check for turning off powerups - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -================ -*/ - static void -CheckPowerups(entvars_t *pev) -{ - if (pev->health <= 0) - return; - - //pev->modelindex = g_ulModelIndexPlayer; // don't use eyes -} - - -//========================================================= -// UpdatePlayerSound - updates the position of the player's -// reserved sound slot in the sound list. -//========================================================= -void CBasePlayer :: UpdatePlayerSound ( void ) -{ - int iBodyVolume; - int iVolume; - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) ); - - if ( !pSound ) - { - ALERT ( at_console, "Client lost reserved sound!\n" ); - return; - } - - pSound->m_iType = bits_SOUND_NONE; - - // now calculate the best target volume for the sound. If the player's weapon - // is louder than his body/movement, use the weapon volume, else, use the body volume. - - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - iBodyVolume = pev->velocity.Length(); - - // clamp the noise that can be made by the body, in case a push trigger, - // weapon recoil, or anything shoves the player abnormally fast. - if ( iBodyVolume > 512 ) - { - iBodyVolume = 512; - } - } - else - { - iBodyVolume = 0; - } - - if ( pev->button & IN_JUMP ) - { - iBodyVolume += 100; - } - -// convert player move speed and actions into sound audible by monsters. - if ( m_iWeaponVolume > iBodyVolume ) - { - m_iTargetVolume = m_iWeaponVolume; - - // OR in the bits for COMBAT sound if the weapon is being louder than the player. - pSound->m_iType |= bits_SOUND_COMBAT; - } - else - { - m_iTargetVolume = iBodyVolume; - } - - // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while - m_iWeaponVolume -= 250 * gpGlobals->frametime; - if ( m_iWeaponVolume < 0 ) - { - iVolume = 0; - } - - - // if target volume is greater than the player sound's current volume, we paste the new volume in - // immediately. If target is less than the current volume, current volume is not set immediately to the - // lower volume, rather works itself towards target volume over time. This gives monsters a much better chance - // to hear a sound, especially if they don't listen every frame. - iVolume = pSound->m_iVolume; - - if ( m_iTargetVolume > iVolume ) - { - iVolume = m_iTargetVolume; - } - else if ( iVolume > m_iTargetVolume ) - { - iVolume -= 250 * gpGlobals->frametime; - - if ( iVolume < m_iTargetVolume ) - { - iVolume = 0; - } - } - - if ( m_fNoPlayerSound ) - { - // debugging flag, lets players move around and shoot without monsters hearing. - iVolume = 0; - } - - if ( gpGlobals->time > m_flStopExtraSoundTime ) - { - // since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two - // after actual emission to make sure it gets heard. - m_iExtraSoundTypes = 0; - } - - if ( pSound ) - { - pSound->m_vecOrigin = pev->origin; - pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes ); - pSound->m_iVolume = iVolume; - } - - // keep track of virtual muzzle flash - m_iWeaponFlash -= 256 * gpGlobals->frametime; - if (m_iWeaponFlash < 0) - m_iWeaponFlash = 0; - - //UTIL_MakeVectors ( pev->angles ); - //gpGlobals->v_forward.z = 0; - - // Below are a couple of useful little bits that make it easier to determine just how much noise the - // player is making. - // UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 ); - //ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume ); -} - - -void CBasePlayer::PostThink() -{ - if ( g_fGameOver ) - goto pt_end; // intermission or finale - - if (!IsAlive()) - goto pt_end; - - // Handle Tank controlling - if ( m_pTank != NULL ) - { // if they've moved too far from the gun, or selected a weapon, unuse the gun - if ( m_pTank->OnControls( pev ) && !pev->weaponmodel ) - { - m_pTank->Use( this, this, USE_SET, 2 ); // try fire the gun - } - else - { // they've moved off the platform - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - } - -// do weapon stuff - ItemPostFrame( ); - -// check to see if player landed hard enough to make a sound -// falling farther than half of the maximum safe distance, but not as far a max safe distance will -// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half -// of maximum safe distance will make no sound. Falling farther than max safe distance will play a -// fallpain sound, and damage will be inflicted based on how far the player fell - - if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) - { - // ALERT ( at_console, "%f\n", m_flFallVelocity ); - - if (pev->watertype == CONTENT_WATER) - { - // Did he hit the world or a non-moving entity? - // BUG - this happens all the time in water, especially when - // BUG - water has current force - // if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 ) - // EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); - } - // skulks, lerks, fades and jetpackers don't take falling damage - else if ((m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER1) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER3) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER4) && (this->pev->iuser3 != AVH_USER3_ALIEN_EMBRYO) && (!GetHasUpgrade(this->pev->iuser4, MASK_UPGRADE_7) || !(this->pev->iuser3 == AVH_USER3_MARINE_PLAYER)) ) - {// after this point, we start doing damage - - float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); - - if ( flFallDamage > pev->health ) - {//splat - // note: play on item channel because we play footstep landing on body channel - // : 243 don't play gib sound if being digested - if ( AvHGetIsAlien(this->pev->iuser3) || !GetHasUpgrade(this->pev->iuser4, MASK_DIGESTING) ) - EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM); - } - - if ( flFallDamage > 0 ) - { - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); - pev->punchangle.x = 0; - } - } - - if ( IsAlive() ) - { - SetAnimation( PLAYER_WALK ); - } - } - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer()) - { - CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 ); - // ALERT( at_console, "fall %f\n", m_flFallVelocity ); - } - m_flFallVelocity = 0; - } - - // select the proper animation for the player character - if ( IsAlive() ) - { - if (!pev->velocity.x && !pev->velocity.y) - SetAnimation( PLAYER_IDLE ); - else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) - SetAnimation( PLAYER_WALK ); - else if (pev->waterlevel > 1) - SetAnimation( PLAYER_WALK ); - } - - StudioFrameAdvance( ); - CheckPowerups(pev); - - UpdatePlayerSound(); - - // Track button info so we can detect 'pressed' and 'released' buttons next frame - m_afButtonLast = pev->button; - -pt_end: - // Decay timers on weapons - // go through all of the weapons and make a list of the ones to pack - for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - CBasePlayerWeapon *gun; - - gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - - if ( gun && gun->UseDecrement() ) - { - gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0f ); - gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001f ); - - if ( gun->m_flTimeWeaponIdle != 1000 ) - { - gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001f ); - } - - if ( gun->pev->fuser1 != 1000 ) - { - gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001f ); - } - - // Only decrement if not flagged as NO_DECREMENT -// if ( gun->m_flPumpTime != 1000 ) - // { - // gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001f ); - // } - - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - - m_flNextAttack -= gpGlobals->frametime; - if ( m_flNextAttack < -0.001 ) - m_flNextAttack = -0.001; - - if ( m_flNextAmmoBurn != 1000 ) - { - m_flNextAmmoBurn -= gpGlobals->frametime; - - if ( m_flNextAmmoBurn < -0.001 ) - m_flNextAmmoBurn = -0.001; - } - - if ( m_flAmmoStartCharge != 1000 ) - { - m_flAmmoStartCharge -= gpGlobals->frametime; - - if ( m_flAmmoStartCharge < -0.001 ) - m_flAmmoStartCharge = -0.001; - } -} - - -// checks if the spot is clear of players -BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) -{ - CBaseEntity *ent = NULL; - - if ( !pSpot->IsTriggered( pPlayer ) ) - { - return FALSE; - } - - AvHPlayer* thePlayer = dynamic_cast(pPlayer); - ASSERT(thePlayer); - - Vector theMinSize; - Vector theMaxSize; - thePlayer->GetSize(theMinSize, theMaxSize); - - int theOffset = AvHMUGetOriginOffsetForUser3(AvHUser3(thePlayer->pev->iuser3)); - Vector theOriginToSpawn = pSpot->pev->origin; - theOriginToSpawn.z += theOffset; - - if(!AvHSUGetIsEnoughRoomForHull(theOriginToSpawn, AvHMUGetHull(false, thePlayer->pev->iuser3), thePlayer->edict())) - return FALSE; - - //while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) - - // Assumes UTIL_FindEntityInSphere doesn't take size of other object into account. Players should be 2*HULL0_MAXX from each other, add another for safety - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 3*HULL0_MAXX)) != NULL ) - { - // if ent is a client, don't spawn on 'em (but dead players don't block) - if ( ent->IsPlayer() && (ent != pPlayer) && ent->IsAlive() ) - return FALSE; - - } - - return TRUE; -} - -BOOL CBasePlayer::IsAlive() const -{ - // Take into account spectators - return (pev->deadflag == DEAD_NO) && pev->health > 0; -} - -BOOL CBasePlayer::IsAlive(bool inIncludeSpectating) const -{ - // Take into account spectators - BOOL theIsAlive = this->IsAlive(); - if(inIncludeSpectating) - { - CBaseEntity* theSpectatingEntity = this->GetSpectatingEntity(); - if(theSpectatingEntity) - { - theIsAlive = theSpectatingEntity->IsAlive(); - } - } - - return theIsAlive; -} - -CBaseEntity* CBasePlayer::GetSpectatingEntity() const -{ - CBaseEntity* theSpectatingEntity = NULL; - - if(this->pev && this->pev->iuser1 && this->pev->iuser2) - { - int theEntityIndex = this->pev->iuser2; - theSpectatingEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theEntityIndex)); - } - - return theSpectatingEntity; -} - -void CBasePlayer::Spawn( void ) -{ - pev->classname = MAKE_STRING("player"); -// pev->health = 100; -// pev->armorvalue = 0; -// pev->max_health = pev->health; - pev->takedamage = DAMAGE_AIM; - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_WALK; - pev->flags &= FL_PROXY; // keep proxy flag sey by engine - pev->flags |= FL_CLIENT; - pev->air_finished = gpGlobals->time + 12; - pev->dmg = 2; // initial water damage - pev->effects = 0; - pev->deadflag = DEAD_NO; - pev->dmg_take = 0; - pev->dmg_save = 0; - pev->friction = 1.0; - pev->gravity = 1.0; - m_bitsHUDDamage = -1; - m_bitsDamageType = 0; - m_afPhysicsFlags = 0; - m_fLongJump = FALSE;// no longjump module. - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - pev->fov = m_iFOV = 0;// init field of view. - m_iClientFOV = -1; // make sure fov reset is sent - - m_flNextDecalTime = 0;// let this player decal as soon as he spawns. - - m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations - // are recieved by all clients - - m_flTimeStepSound = 0; - m_iStepLeft = 0; - m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. - - m_bloodColor = BLOOD_COLOR_RED; - m_flNextAttack = UTIL_WeaponTimeBase(); - StartSneaking(); - -// m_iFlashBattery = 99; -// m_flFlashLightTime = 1; // force first message - -// dont let uninitialized value here hurt the player - m_flFallVelocity = 0; - - GetGameRules()->SetDefaultPlayerTeam( this ); - edict_t* theSpawnPoint = GetGameRules()->SelectSpawnPoint( this ); - ASSERT(theSpawnPoint); - this->InitPlayerFromSpawn(theSpawnPoint); - - //AvHPlayer* thePlayer = dynamic_cast(this); - //char* thePlayerModel = thePlayer->GetPlayerModel(); - //SET_MODEL(ENT(pev), thePlayerModel); - SET_MODEL(ENT(pev), "models/player.mdl"); - - g_ulModelIndexPlayer = pev->modelindex; - //pev->sequence = LookupActivity( ACT_IDLE ); - pev->sequence = LookupSequence("idle1"); - - if ( FBitSet(pev->flags, FL_DUCKING) ) - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - - pev->view_ofs = VEC_VIEW; - Precache(); - m_HackedGunPos = Vector( 0, 32, 0 ); - - if ( m_iPlayerSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Couldn't alloc player sound slot!\n" ); - } - - m_fNoPlayerSound = FALSE;// normal sound behavior. - - m_pLastItem = NULL; - m_pLastItemName = 0; // Added by mmcguire. - - m_fInitHUD = TRUE; - m_iClientHideHUD = -1; // force this to be recalculated - m_fWeapon = FALSE; - m_pClientActiveItem = NULL; - m_iClientBattery = -1; - - // reset all ammo values to 0 - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - m_rgAmmo[i] = 0; - m_rgAmmoLast[i] = 0; // client ammo values also have to be reset (the death hud clear messages does on the client side) - } - - m_lastx = m_lasty = 0; - - m_flNextChatTime = gpGlobals->time; - - g_pGameRules->PlayerSpawn( this ); -} - - -void CBasePlayer :: Precache( void ) -{ - // in the event that the player JUST spawned, and the level node graph - // was loaded, fix all of the node graph pointers before the game starts. - - // !!!BUGBUG - now that we have multiplayer, this needs to be moved! - if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet ) - { - if ( !WorldGraph.FSetGraphPointers() ) - { - ALERT ( at_console, "**Graph pointers were not set!\n"); - } - else - { - ALERT ( at_console, "**Graph Pointers Set!\n" ); - } - } - - // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific) - // because they need to precache before any clients have connected - - Net_InitializeMessages(); - - // init geiger counter vars during spawn and each time - // we cross a level transition - - m_flgeigerRange = 1000; - m_igeigerRangePrev = 1000; - - m_bitsDamageType = 0; - m_bitsHUDDamage = -1; - - m_iClientBattery = -1; - - m_iTrain = TRAIN_NEW; - - m_iUpdateTime = 5; // won't update for 1/2 a second - - if ( gInitHUD ) - m_fInitHUD = TRUE; -} - - -int CBasePlayer::Save( CSave &save ) -{ - if ( !CBaseMonster::Save(save) ) - return 0; - - return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); -} - - -// -// Marks everything as new so the player will resend this to the hud. -// -void CBasePlayer::RenewItems(void) -{ - -} - -int CBasePlayer::Restore( CRestore &restore ) -{ - if ( !CBaseMonster::Restore(restore) ) - return 0; - - int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); - - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - // landmark isn't present. - if ( !pSaveData->fUseLandmark ) - { - ALERT( at_console, "No Landmark:%s\n", pSaveData->szLandmarkName ); - - // default to normal spawn - //edict_t* pentSpawnSpot = EntSelectSpawnPoint( this ); - ASSERT(FALSE); - //pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); - //pev->angles = VARS(pentSpawnSpot)->angles; - } - pev->v_angle.z = 0; // Clear out roll - pev->angles = pev->v_angle; - - pev->fixangle = TRUE; // turn this way immediately - -// Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; - - g_ulModelIndexPlayer = pev->modelindex; - - if ( FBitSet(pev->flags, FL_DUCKING) ) - { - // Use the crouch HACK - //FixPlayerCrouchStuck( edict() ); - // Don't need to do this with new player prediction code. - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - } - else - { - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - } - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - if ( m_fLongJump ) - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" ); - } - else - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - } - - RenewItems(); - - // HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it - // as just a counter. Ideally, this needs its own variable that's saved as a plain float. - // Barring that, we clear it out here instead of using the incorrect restored time value. - m_flNextAttack = UTIL_WeaponTimeBase(); - - return status; -} - - - -void CBasePlayer::SelectNextItem( int iItem ) -{ - CBasePlayerItem *pItem; - - pItem = m_rgpPlayerItems[ iItem ]; - - if (!pItem) - return; - - if (pItem == m_pActiveItem) - { - // select the next one in the chain - pItem = m_pActiveItem->m_pNext; - if (! pItem) - { - return; - } - - CBasePlayerItem *pLast; - pLast = pItem; - while (pLast->m_pNext) - pLast = pLast->m_pNext; - - // relink chain - pLast->m_pNext = m_pActiveItem; - m_pActiveItem->m_pNext = NULL; - m_rgpPlayerItems[ iItem ] = pItem; - } - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - { - m_pActiveItem->Holster( ); - } - - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); - } -} - -void CBasePlayer::SelectItem(const char *pstr) -{ - if (!pstr) - return; - - CBasePlayerItem *pItem = NULL; - - for (int i = 0; i < MAX_ITEM_TYPES; i++) - { - if (m_rgpPlayerItems[i]) - { - pItem = m_rgpPlayerItems[i]; - - while (pItem) - { - if (FClassnameIs(pItem->pev, pstr)) - break; - pItem = pItem->m_pNext; - } - } - - if (pItem) - break; - } - - if (!pItem) - return; - - - if ((pItem == m_pActiveItem) || (m_pActiveItem != NULL && !m_pActiveItem->CanHolster())) - return; - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - m_pLastItem = m_pActiveItem; - - if (m_pLastItem) - { - m_pLastItemName = m_pLastItem->pev->classname; - } - else - { - m_pLastItemName = 0; - } - - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); - } -} - -//note this should no longer be called, and asserts if used -void CBasePlayer::SelectLastItem(void) -{ - if (!m_pLastItem) - { - - // Try the last item name. - - if (m_pLastItemName != 0) - { - for (int i = 0; i < MAX_ITEM_TYPES; i++) - { - CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; - while (theCurrentItem) - { - if(FClassnameIs(theCurrentItem->pev, STRING(m_pLastItemName))) - { - m_pLastItem = theCurrentItem; - break; - } - theCurrentItem = theCurrentItem->m_pNext; - } - } - } - - } - - if (!m_pLastItem) - { - return; - } - - this->SelectItem(STRING(m_pLastItem->pev->classname)); //replaced copy-and-paste from SelectItem with actual SelectItem call -} - -BOOL CBasePlayer::HasItem(CBasePlayerItem* inWeapon) -{ - // Return true if we have a weapon of this type - bool theHasWeapon = false; - - for(int i = 0; (i < MAX_ITEM_TYPES) && !theHasWeapon; i++) - { - CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; - while(theCurrentItem && !theHasWeapon) - { - if(FClassnameIs(theCurrentItem->pev, STRING(inWeapon->pev->classname))) - { - theHasWeapon = true; - } - theCurrentItem = theCurrentItem->m_pNext; - } - } - - return theHasWeapon; -} - -BOOL CBasePlayer::HasItemWithFlag(int inFlag, CBasePlayerItem*& outItem) -{ - // Return true if we have a weapon of this type - bool theHasWeaponWithFlag = false; - - for(int i = 0; (i < MAX_ITEM_TYPES) && !theHasWeaponWithFlag; i++) - { - CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; - while(theCurrentItem && !theHasWeaponWithFlag) - { - ItemInfo theItemInfo; - theCurrentItem->GetItemInfo(&theItemInfo); - - int theFlags = theItemInfo.iFlags; - if(theFlags & inFlag) - { - theHasWeaponWithFlag = true; - outItem = theCurrentItem; - } - theCurrentItem = theCurrentItem->m_pNext; - } - } - - return theHasWeaponWithFlag; -} - -//============================================== -// HasWeapons - do I have any weapons at all? -//============================================== -BOOL CBasePlayer::HasWeapons( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return TRUE; - } - } - - return FALSE; -} - -void CBasePlayer::SelectPrevItem( int iItem ) -{ -} - - -char *CBasePlayer::TeamID( void ) -{ - if ( pev == NULL ) // Not fully connected yet - return ""; - - // return their team name - return m_szTeamName; -} - -void CBasePlayer::SetTeamID(const char* inTeamID) -{ - strncpy(this->m_szTeamName, inTeamID, TEAM_NAME_LENGTH); -} - -//============================================== -// !!!UNDONE:ultra temporary SprayCan entity to apply -// decal frame at a time. For PreAlpha CD -//============================================== -class CSprayCan : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Think( void ); - - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -void CSprayCan::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - pev->frame = 0; - - pev->nextthink = gpGlobals->time + 0.1; - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM); -} - -void CSprayCan::Think( void ) -{ - TraceResult tr; - int playernum; - int nFrames; - CBasePlayer *pPlayer; - - pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner); - - if (pPlayer) - nFrames = pPlayer->GetCustomDecalFrames(); - else - nFrames = -1; - - playernum = ENTINDEX(pev->owner); - - // ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames); - - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - // No customization present. - if (nFrames == -1) - { - UTIL_DecalTrace( &tr, DECAL_LAMBDA6 ); - UTIL_Remove( this ); - } - else - { - UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE ); - // Just painted last custom frame. - if ( pev->frame++ >= (nFrames - 1)) - UTIL_Remove( this ); - } - - pev->nextthink = gpGlobals->time + 0.1; -} - -class CBloodSplat : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Spray ( void ); -}; - -void CBloodSplat::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - - SetThink ( &CBloodSplat::Spray ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CBloodSplat::Spray ( void ) -{ - TraceResult tr; - - if ( g_Language != LANGUAGE_GERMAN ) - { - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - } - SetThink ( &CBloodSplat::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -} - -//============================================== - - - -void CBasePlayer::GiveNamedItem( const char *pszName, bool inSendMessage ) -{ - edict_t *pent; - - int istr = MAKE_STRING(pszName); - - pent = CREATE_NAMED_ENTITY(istr); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in GiveNamedItem!\n" ); - return; - } - VARS( pent )->origin = pev->origin; - pent->v.spawnflags |= SF_NORESPAWN; - - DispatchSpawn( pent ); - DispatchTouch( pent, ENT( pev ) ); - - if(inSendMessage) - { - CBaseEntity* theEntity = CBaseEntity::Instance(ENT(pent)); - ASSERT(theEntity); - CBasePlayerWeapon* theWeapon = dynamic_cast(theEntity); - //ASSERT(theWeapon); - if(theWeapon) - { - int theWeaponID = theWeapon->m_iId; - NetMsg_WeapPickup( pev, theWeaponID ); - } - } -} - - - -CBaseEntity *FindEntityForward( CBaseEntity *pMe ) -{ - TraceResult tr; - - UTIL_MakeVectors(pMe->pev->v_angle); - UTIL_TraceLine(pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 8192,dont_ignore_monsters, pMe->edict(), &tr ); - if ( tr.flFraction != 1.0 && !FNullEnt( tr.pHit) ) - { - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - return pHit; - } - return NULL; -} - - -BOOL CBasePlayer :: FlashlightIsOn( void ) -{ - return FBitSet(pev->effects, EF_DIMLIGHT); -} - -const float kFlashlightVolume = .3f; - -void CBasePlayer :: FlashlightTurnOn( void ) -{ - if ( !g_pGameRules->FAllowFlashlight() ) - { - return; - } - - if ( (pev->weapons & (1<effects, EF_DIMLIGHT); - - /*MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(1); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time;*/ - - } -} - - -void CBasePlayer :: FlashlightTurnOff( void ) -{ - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, kFlashlightVolume, ATTN_NORM, 0, PITCH_NORM ); - ClearBits(pev->effects, EF_DIMLIGHT); - - /*MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time;*/ - -} - -/* -=============== -ForceClientDllUpdate - -When recording a demo, we need to have the server tell us the entire client state -so that the client side .dll can behave correctly. -Reset stuff so that the state is transmitted. -=============== -*/ -void CBasePlayer :: ForceClientDllUpdate( void ) -{ - m_iClientHealth = -1; - m_iClientBattery = -1; - m_iTrain |= TRAIN_NEW; // Force new train message. - m_fWeapon = FALSE; // Force weapon send - m_fKnownItem = FALSE; // Force weaponinit messages. - m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message - - // Now force all the necessary messages - // to be sent. - UpdateClientData(); - // m_fWeapon = TRUE; // Force weapon send -} - -/* -============ -ImpulseCommands -============ -*/ -extern float g_flWeaponCheat; - -void CBasePlayer::ImpulseCommands( ) -{ - TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs - - int iImpulse = (int)pev->impulse; - switch (iImpulse) - { - case IMPULSE_FLASHLIGHT: - // temporary flashlight for level designers - if ( FlashlightIsOn() ) - { - FlashlightTurnOff(); - } - else - { - FlashlightTurnOn(); - } - break; - - case IMPULSE_SPRAYPAINT:// paint decal - - if ( gpGlobals->time < m_flNextDecalTime ) - { - // too early! - break; - } - - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr); - - if ( tr.flFraction != 1.0 ) - {// line hit something, so paint a decal - m_flNextDecalTime = gpGlobals->time + decalfrequency.value; - CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); - pCan->Spawn( pev ); - } - - break; -// HLDSDK 2.3 update -// case IMPULSE_DEMORECORD: // Demo recording, update client dll specific data again. -// ForceClientDllUpdate(); -// break; - default: - // check all of the cheat impulse commands now - CheatImpulseCommands( iImpulse ); - break; - } - - pev->impulse = 0; -} - -//========================================================= -//========================================================= -void CBasePlayer::CheatImpulseCommands( int iImpulse ) -{ -} - -// -// Add a weapon to the player (Item == Weapon == Selectable Object) -// -int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) -{ - CBasePlayerItem *pInsert; - - pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; - ItemInfo ii; - pItem->GetItemInfo(&ii); - - if ( pItem->iItemSlot() == 1 || ii.iId == AVH_WEAPON_MINE || ii.iId == AVH_WEAPON_WELDER) { - this->EffectivePlayerClassChanged(); - } - while (pInsert) - { - if (FClassnameIs( pInsert->pev, STRING( pItem->pev->classname) )) - { - if (pItem->AddDuplicate( pInsert )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - // ugly hack to update clip w/o an update clip message - pInsert->UpdateItemInfo( ); - if (m_pActiveItem) - m_pActiveItem->UpdateItemInfo( ); - - pItem->Kill( ); - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); - } - return FALSE; - } - pInsert = pInsert->m_pNext; - } - - if (pItem->AddToPlayer( this )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()]; - m_rgpPlayerItems[pItem->iItemSlot()] = pItem; - - // should we switch to this item? - if ( g_pGameRules->FShouldSwitchWeapon( this, pItem ) ) - { - SwitchWeapon( pItem ); - } - - return TRUE; - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); - } - return FALSE; -} - - - -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) -{ - - if (m_pActiveItem == pItem) - { - - ResetAutoaim( ); - pItem->Holster( ); - pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. - pItem->SetThink( NULL ); - m_pActiveItem = NULL; - pev->viewmodel = 0; - pev->weaponmodel = 0; - - } - else if ( m_pLastItem == pItem ) - m_pLastItem = NULL; - - AvHBasePlayerWeapon* theWeapon = dynamic_cast(pItem); - if(theWeapon) - { - ItemInfo theInfo; - theWeapon->GetItemInfo(&theInfo); - int theID = theInfo.iId; - this->pev->weapons &= ~(1<iItemSlot()]; - - if (pPrev == pItem) - { - m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext; - return TRUE; - } - else - { - while (pPrev && pPrev->m_pNext != pItem) - { - pPrev = pPrev->m_pNext; - } - if (pPrev) - { - pPrev->m_pNext = pItem->m_pNext; - return TRUE; - } - } - return FALSE; -} - - -// -// Returns the unique ID for the ammo, or -1 if error -// -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) -{ - if ( !szName ) - { - // no ammo. - return -1; - } - - if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) - { - // game rules say I can't have any more of this ammo type. - return -1; - } - - int i = 0; - - i = GetAmmoIndex( szName ); - - if ( i < 0 || i >= MAX_AMMO_SLOTS ) - return -1; - - int iAdd = min( iCount, iMax - m_rgAmmo[i] ); - if ( iAdd < 1 ) - return i; - - m_rgAmmo[ i ] += iAdd; - - - // Send the message that ammo has been picked up - NetMsg_AmmoPickup( pev, GetAmmoIndex(szName), iAdd ); - - TabulateAmmo(); - - return i; -} - - -/* -============ -ItemPreFrame - -Called every frame by the player PreThink -============ -*/ -void CBasePlayer::ItemPreFrame() -{ - if ( m_flNextAttack > 0 ) - { - return; - } - - if (!m_pActiveItem) - return; - - m_pActiveItem->ItemPreFrame( ); -} - - -/* -============ -ItemPostFrame - -Called every frame by the player PostThink -============ -*/ -void CBasePlayer::ItemPostFrame() -{ - static int fInSelect = FALSE; - - // check if the player is using a tank - if ( m_pTank != NULL ) - return; - - ImpulseCommands(); - - if ( m_flNextAttack > 0 ) - { - return; - } - - if (!m_pActiveItem) - return; - - // Only update weapon once game has started (no firing before then) - //if(GetGameRules()->GetGameStarted()) - //{ - this->m_pActiveItem->ItemPostFrame( ); - //} -} - -int CBasePlayer::AmmoInventory( int iAmmoIndex ) -{ - if (iAmmoIndex == -1) - { - return -1; - } - - return m_rgAmmo[ iAmmoIndex ]; -} - -int CBasePlayer::GetAmmoIndex(const char *psz) -{ - int i; - - if (!psz) - return -1; - - for (i = 1; i < MAX_AMMO_SLOTS; i++) - { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName ) - continue; - - if (stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0) - return i; - } - - return -1; -} - -int CBasePlayer::GetMaxWalkSpeed(void) const -{ - return 220; -} - -// Called from UpdateClientData -// makes sure the client has all the necessary ammo info, if values have changed -void CBasePlayer::SendAmmoUpdate(void) -{ - int theAmmoToSend[MAX_AMMO_SLOTS]; - memcpy(&theAmmoToSend, &this->m_rgAmmo, MAX_AMMO_SLOTS*sizeof(int)); - -// if(this->pev->iuser1 == OBS_IN_EYE) -// { -// CBasePlayer* theEntity = NULL; -// if(AvHSUGetEntityFromIndex(this->pev->iuser2, theEntity)) -// { -// memcpy(&theAmmoToSend, &theEntity->m_rgAmmo, MAX_AMMO_SLOTS*sizeof(int)); -// } -// } - - for (int i=0; i < MAX_AMMO_SLOTS;i++) - { - if (theAmmoToSend[i] != m_rgAmmoLast[i]) - { - m_rgAmmoLast[i] = theAmmoToSend[i]; - - // TODO: Fix me! - //ASSERT( m_rgAmmo[i] >= 0 ); - //ASSERT( m_rgAmmo[i] < 255 ); - if((theAmmoToSend[i] >= 0) && (theAmmoToSend[i] < 255)) - { - // send "Ammo" update message - NetMsg_AmmoX( pev, i, max( min( theAmmoToSend[i], 254 ), 0 ) ); - } - } - } -} - -/* -========================================================= - UpdateClientData - -resends any changed player HUD info to the client. -Called every frame by PlayerPreThink -Also called at start of demo recording and playback by -ForceClientDllUpdate to ensure the demo gets messages -reflecting all of the HUD state info. -========================================================= -*/ -void CBasePlayer :: UpdateClientData( void ) -{ - CBasePlayer* thePlayerToUseForWeaponUpdates = this; -// if(this->pev->iuser1 == OBS_IN_EYE) -// { -// CBasePlayer* theSpectatingPlayer = NULL; -// if(AvHSUGetEntityFromIndex(this->pev->iuser2, theSpectatingPlayer)) -// { -// thePlayerToUseForWeaponUpdates = theSpectatingPlayer; -// } -// } - - if (m_fInitHUD) - { - m_fInitHUD = FALSE; - gInitHUD = FALSE; - - NetMsg_ResetHUD( pev ); - - if ( !m_fGameHUDInitialized ) - { - NetMsg_InitHUD( pev ); - - g_pGameRules->InitHUD( this ); - m_fGameHUDInitialized = TRUE; - if ( g_pGameRules->IsMultiplayer() ) - { - FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); - } - } - FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); - - InitStatusBar(); - } - - if ( m_iHideHUD != m_iClientHideHUD ) - { - NetMsg_HideWeapon( pev, m_iHideHUD ); - m_iClientHideHUD = m_iHideHUD; - } - - if ( m_iFOV != m_iClientFOV ) - { - NetMsg_SetFOV( pev, m_iFOV ); - // cache FOV change at end of function, so weapon updates can see that FOV has changed - } - - // HACKHACK -- send the message to display the game title - if (gDisplayTitle) - { - NetMsg_ShowGameTitle( pev ); - gDisplayTitle = 0; - } - - if ((int)pev->health != m_iClientHealth) //: this cast to int is important, otherwise we spam the message, this is just a quick and easy fix. - { - NetMsg_Health( pev, max( pev->health, 0.0f ) ); - m_iClientHealth = (int)pev->health; - } - - if ((int)pev->armorvalue != m_iClientBattery) - { - NetMsg_Battery( pev, (int)pev->armorvalue ); - m_iClientBattery = (int)pev->armorvalue; - } - - if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType) - { - // Comes from inside me if not set - Vector damageOrigin = pev->origin; - // send "damage" message - // causes screen to flash, and pain compass to show direction of damage - edict_t *other = pev->dmg_inflictor; - if ( other ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(other); - if ( pEntity ) - damageOrigin = pEntity->Center(); - } - - // only send down damage type that have hud art - int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; - - float origin[] = { damageOrigin.x, damageOrigin.y, damageOrigin.z }; - NetMsg_Damage( pev, pev->dmg_save, pev->dmg_take, 0, origin ); - - pev->dmg_take = 0; - pev->dmg_save = 0; - m_bitsHUDDamage = m_bitsDamageType; - - // Clear off non-time-based damage indicators - m_bitsDamageType &= DMG_TIMEBASED; - } - - if (m_iTrain & TRAIN_NEW) - { - // send "health" update message - NetMsg_Train( pev, m_iTrain & 0xF ); - m_iTrain &= ~TRAIN_NEW; - } - - // - // New Weapon? - // - - bool forceCurWeaponUpdate = false; - - if (!m_fKnownItem) - { - - m_fKnownItem = TRUE; - - // WeaponInit Message - // byte = # of weapons - // - // for each weapon: - // byte name str length (not including null) - // bytes... name - // byte Ammo Type - // byte Ammo2 Type - // byte bucket - // byte bucket pos - // byte flags - // ???? Icons - - // Send ALL the weapon info now - this->SendWeaponUpdate(); - - // : HACK force an full curweapon update after each bunch of weaponlists sent - forceCurWeaponUpdate = true; - // : - } - - - SendAmmoUpdate(); - - // Update all the items - for ( int i = 0; i < MAX_ITEM_TYPES; i++ ) - { - if (forceCurWeaponUpdate == true) - m_fWeapon = FALSE; - if ( thePlayerToUseForWeaponUpdates->m_rgpPlayerItems[i] ) // each item updates it's successors - thePlayerToUseForWeaponUpdates->m_rgpPlayerItems[i]->UpdateClientData( thePlayerToUseForWeaponUpdates ); - } - if (forceCurWeaponUpdate == true) - m_fWeapon = TRUE; - - // Cache and client weapon change - m_pClientActiveItem = thePlayerToUseForWeaponUpdates->m_pActiveItem; - m_iClientFOV = thePlayerToUseForWeaponUpdates->m_iFOV; - - // Update Status Bar if we're playing - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && (thePlayer->GetPlayMode() == PLAYMODE_PLAYING)) - { - if ( m_flNextSBarUpdateTime < gpGlobals->time ) - { - UpdateStatusBar(); - m_flNextSBarUpdateTime = gpGlobals->time + 0.2; - } - } -} - -void CBasePlayer::SendWeaponUpdate() -{ - int i; - - for (i = 0; i < MAX_WEAPONS; i++) - { - ItemInfo& II = CBasePlayerItem::ItemInfoArray[i]; - - if ( !II.iId ) - continue; - - const char *pszName; - if (!II.pszName) - pszName = "Empty"; - else - pszName = II.pszName; - - WeaponList weapon; - weapon.weapon_name = pszName; - weapon.ammo1_type = GetAmmoIndex(II.pszAmmo1); - weapon.ammo2_type = GetAmmoIndex(II.pszAmmo2); - weapon.ammo1_max_amnt = II.iMaxAmmo1; - weapon.ammo2_max_amnt = II.iMaxAmmo2; - weapon.bucket = II.iSlot; - weapon.bucket_pos = II.iPosition; - weapon.bit_index = II.iId; - weapon.flags = II.iFlags; - - NetMsg_WeaponList( pev, weapon ); - } - -} - -//========================================================= -// FBecomeProne - Overridden for the player to set the proper -// physics flags when a barnacle grabs player. -//========================================================= -BOOL CBasePlayer :: FBecomeProne ( void ) -{ - m_afPhysicsFlags |= PFLAG_ONBARNACLE; - return TRUE; -} - -//========================================================= -// BarnacleVictimBitten - bad name for a function that is called -// by Barnacle victims when the barnacle pulls their head -// into its mouth. For the player, just die. -//========================================================= -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) -{ - TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); -} - -//========================================================= -// BarnacleVictimReleased - overridden for player who has -// physics flags concerns. -//========================================================= -void CBasePlayer :: BarnacleVictimReleased ( void ) -{ - m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; -} - - -//========================================================= -// Illumination -// return player light level plus virtual muzzle flash -//========================================================= -int CBasePlayer :: Illumination( void ) -{ - int iIllum = CBaseEntity::Illumination( ); - - iIllum += m_iWeaponFlash; - if (iIllum > 255) - return 255; - return iIllum; -} - - -void CBasePlayer :: EnableControl(BOOL fControl) -{ - if (!fControl) - pev->flags |= FL_FROZEN; - else - pev->flags &= ~FL_FROZEN; - -} - - -#define DOT_1DEGREE 0.9998476951564 -#define DOT_2DEGREE 0.9993908270191 -#define DOT_3DEGREE 0.9986295347546 -#define DOT_4DEGREE 0.9975640502598 -#define DOT_5DEGREE 0.9961946980917 -#define DOT_6DEGREE 0.9945218953683 -#define DOT_7DEGREE 0.9925461516413 -#define DOT_8DEGREE 0.9902680687416 -#define DOT_9DEGREE 0.9876883405951 -#define DOT_10DEGREE 0.9848077530122 -#define DOT_15DEGREE 0.9659258262891 -#define DOT_20DEGREE 0.9396926207859 -#define DOT_25DEGREE 0.9063077870367 - -//========================================================= -// Autoaim -// set crosshair position to point to enemey -//========================================================= -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) -{ - if (g_iSkillLevel == SKILL_HARD) - { - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - return gpGlobals->v_forward; - } - - Vector vecSrc = GetGunPosition( ); - float flDist = 8192; - - // always use non-sticky autoaim - // UNDONE: use sever variable to chose! - if (1 || g_iSkillLevel == SKILL_MEDIUM) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - // flDelta *= 0.5; - } - - BOOL m_fOldTargeting = m_fOnTarget; - Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta ); - - // update ontarget if changed - if ( !g_pGameRules->AllowAutoTargetCrosshair() ) - m_fOnTarget = 0; - else if (m_fOldTargeting != m_fOnTarget) - { - m_pActiveItem->UpdateItemInfo( ); - } - - if (angles.x > 180) - angles.x -= 360; - if (angles.x < -180) - angles.x += 360; - if (angles.y > 180) - angles.y -= 360; - if (angles.y < -180) - angles.y += 360; - - if (angles.x > 25) - angles.x = 25; - if (angles.x < -25) - angles.x = -25; - if (angles.y > 12) - angles.y = 12; - if (angles.y < -12) - angles.y = -12; - - - // always use non-sticky autoaim - // UNDONE: use sever variable to chose! - if (0 || g_iSkillLevel == SKILL_EASY) - { - m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33; - } - else - { - m_vecAutoAim = angles * 0.9; - } - - // m_vecAutoAim = m_vecAutoAim * 0.99; - - // Don't send across network if sv_aim is 0 - if ( g_psv_aim->value != 0 ) - { - if ( m_vecAutoAim.x != m_lastx || - m_vecAutoAim.y != m_lasty ) - { - SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); - - m_lastx = m_vecAutoAim.x; - m_lasty = m_vecAutoAim.y; - } - } - - // ALERT( at_console, "%f %f\n", angles.x, angles.y ); - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - return gpGlobals->v_forward; -} - - -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - float bestdot; - Vector bestdir; - edict_t *bestent; - TraceResult tr; - - if ( g_psv_aim->value == 0 ) - { - m_fOnTarget = FALSE; - return g_vecZero; - } - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - - // try all possible entities - bestdir = gpGlobals->v_forward; - bestdot = flDelta; // +- 10 degrees - bestent = NULL; - - m_fOnTarget = FALSE; - - UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr ); - - - if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO) - { - // don't look through water - if (!((pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3) - || (pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0))) - { - if (tr.pHit->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return m_vecAutoAim; - } - } - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - Vector center; - Vector dir; - float dot; - - if ( pEdict->free ) // Not in use - continue; - - if (pEdict->v.takedamage != DAMAGE_AIM) - continue; - if (pEdict == edict()) - continue; -// if (pev->team > 0 && pEdict->v.team == pev->team) -// continue; // don't aim at teammate - if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) - continue; - - pEntity = Instance( pEdict ); - if (pEntity == NULL) - continue; - - if (!pEntity->IsAlive()) - continue; - - // don't look through water - if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - continue; - - center = pEntity->BodyTarget( vecSrc ); - - dir = (center - vecSrc).Normalize( ); - - // make sure it's in front of the player - if (DotProduct (dir, gpGlobals->v_forward ) < 0) - continue; - - dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) - + fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5; - - // tweek for distance - dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist); - - if (dot > bestdot) - continue; // to far to turn - - UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr ); - if (tr.flFraction != 1.0 && tr.pHit != pEdict) - { - // ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) ); - continue; - } - - // don't shoot at friends - if (IRelationship( pEntity ) < 0) - { - if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch()) - // ALERT( at_console, "friend\n"); - continue; - } - - // can shoot at this one - bestdot = dot; - bestent = pEdict; - bestdir = dir; - } - - if (bestent) - { - bestdir = UTIL_VecToAngles (bestdir); - bestdir.x = -bestdir.x; - bestdir = bestdir - pev->v_angle - pev->punchangle; - - if (bestent->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return bestdir; - } - - return Vector( 0, 0, 0 ); -} - - -void CBasePlayer :: ResetAutoaim( ) -{ - if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - SET_CROSSHAIRANGLE( edict(), 0, 0 ); - } - m_fOnTarget = FALSE; -} - -/* -============= -SetCustomDecalFrames - - UNDONE: Determine real frame limit, 8 is a placeholder. - Note: -1 means no custom frames present. -============= -*/ -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) -{ - if (nFrames > 0 && - nFrames < 8) - m_nCustomSprayFrames = nFrames; - else - m_nCustomSprayFrames = -1; -} - -/* -============= -GetCustomDecalFrames - - Returns the # of custom frames this player's custom clan logo contains. -============= -*/ -int CBasePlayer :: GetCustomDecalFrames( void ) -{ - return m_nCustomSprayFrames; -} - - -//========================================================= -// DropPlayerItem - drop the named item, or if no name, -// the active item. -//========================================================= -void CBasePlayer::DropPlayerItem ( char *pszItemName ) -{ - if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) ) - { - // no dropping in single player. - return; - } - - if ( !strlen( pszItemName ) ) - { - // if this string has no length, the client didn't type a name! - // assume player wants to drop the active item. - // make the string null to make future operations in this function easier - pszItemName = NULL; - } - - CBasePlayerItem *pWeapon; - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - if ( pszItemName ) - { - // try to match by name. - const char* theWeaponClassName = STRING( pWeapon->pev->classname ); - if ( !strcmp( pszItemName, theWeaponClassName) ) - { - // match! - break; - } - } - else - { - // trying to drop active item - if ( pWeapon == m_pActiveItem ) - { - // active item! - break; - } - } - - pWeapon = pWeapon->m_pNext; - } - - - // if we land here with a valid pWeapon pointer, that's because we found the - // item we want to drop and hit a BREAK; pWeapon is the item. - if ( pWeapon ) - { - g_pGameRules->GetNextBestWeapon( this, pWeapon ); - - UTIL_MakeVectors ( pev->angles ); - - pev->weapons &= ~(1<m_iId);// take item off hud - - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() ); - pWeaponBox->pev->angles.x = 0; - pWeaponBox->pev->angles.z = 0; - pWeaponBox->PackWeapon( pWeapon ); - pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; - - // drop half of the ammo for this weapon. - int iAmmoIndex; - - iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ??? - - if ( iAmmoIndex != -1 ) - { - // this weapon weapon uses ammo, so pack an appropriate amount. - if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE ) - { - // pack up all the ammo, this weapon is its own ammo type - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] ); - m_rgAmmo[ iAmmoIndex ] = 0; - - } - else - { - // pack half of the ammo - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] / 2 ); - m_rgAmmo[ iAmmoIndex ] /= 2; - } - - } - - return;// we're done, so stop searching with the FOR loop. - } - } -} - -//========================================================= -// HasPlayerItem Does the player already have this item? -//========================================================= -BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) -{ - CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// HasNamedPlayerItem Does the player already have this item? -//========================================================= -CBasePlayerItem* CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) -{ - CBasePlayerItem *pReturn = NULL; - CBasePlayerItem *pItem = NULL; - int i; - - for ( i = 0 ; (i < MAX_ITEM_TYPES) && !pReturn ; i++ ) - { - pItem = m_rgpPlayerItems[ i ]; - - while (pItem && !pReturn) - { - if ( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) ) - { - pReturn = pItem; - } - pItem = pItem->m_pNext; - } - } - - return pReturn; -} - -//========================================================= -// -//========================================================= -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) - { - return FALSE; - } - - ResetAutoaim( ); - - if (m_pActiveItem) - { - m_pActiveItem->Holster( ); - } - - m_pActiveItem = pWeapon; - pWeapon->Deploy( ); - - return TRUE; -} - -//========================================================= -// Dead HEV suit prop -//========================================================= -class CDeadHEV : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[4]; -}; - -char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" }; - -void CDeadHEV::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ); - -//========================================================= -// ********** DeadHEV SPAWN ********** -//========================================================= -void CDeadHEV :: Spawn( void ) -{ - PRECACHE_MODEL("models/player.mdl"); - SET_MODEL(ENT(pev), "models/player.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - pev->body = 1; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead hevsuit with bad pose\n" ); - pev->sequence = 0; - pev->effects = EF_BRIGHTFIELD; - } - - // Corpses have less health - pev->health = 8; - - MonsterInitDead(); -} - - -class CStripWeapons : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: -}; - -LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ); - -void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pActivator; - } - else if ( !g_pGameRules->IsDeathmatch() ) - { - pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - } - - if ( pPlayer ) - pPlayer->RemoveAllItems( FALSE ); -} - - -class CRevertSaved : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MessageThink( void ); - void EXPORT LoadThink( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - inline float MessageTime( void ) { return m_messageTime; } - inline float LoadTime( void ) { return m_loadTime; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } - inline void SetMessageTime( float time ) { m_messageTime = time; } - inline void SetLoadTime( float time ) { m_loadTime = time; } - -private: - float m_messageTime; - float m_loadTime; -}; - -LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ); - -TYPEDESCRIPTION CRevertSaved::m_SaveData[] = -{ - DEFINE_FIELD( CRevertSaved, m_messageTime, FIELD_FLOAT ), // These are not actual times, but durations, so save as floats - DEFINE_FIELD( CRevertSaved, m_loadTime, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ); - -void CRevertSaved :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagetime")) - { - SetMessageTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "loadtime")) - { - SetLoadTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); - pev->nextthink = gpGlobals->time + MessageTime(); - SetThink( &CRevertSaved::MessageThink ); -} - - -void CRevertSaved :: MessageThink( void ) -{ - UTIL_ShowMessageAll( STRING(pev->message) ); - float nextThink = LoadTime() - MessageTime(); - if ( nextThink > 0 ) - { - pev->nextthink = gpGlobals->time + nextThink; - SetThink( &CRevertSaved::LoadThink ); - } - else - LoadThink(); -} - - -void CRevertSaved :: LoadThink( void ) -{ - if ( !gpGlobals->deathmatch ) - { - SERVER_COMMAND("reload\n"); - } -} - - -//========================================================= -// Multiplayer intermission spots. -//========================================================= -class CInfoIntermission:public CPointEntity -{ - void Spawn( void ); - void Think( void ); -}; - -void CInfoIntermission::Spawn( void ) -{ - UTIL_SetOrigin( pev, pev->origin ); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - pev->v_angle = g_vecZero; - - pev->nextthink = gpGlobals->time + 2;// let targets spawn! - -} - -void CInfoIntermission::Think ( void ) -{ - edict_t *pTarget; - - // find my target - pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); - - if ( !FNullEnt(pTarget) ) - { - pev->v_angle = UTIL_VecToAngles( (pTarget->v.origin - pev->origin).Normalize() ); - pev->v_angle.x = -pev->v_angle.x; - } -} - -LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ); - +// +// Copyright (c) 1999, Valve LLC. All rights reserved. +// +// This product contains software technology licensed from Id +// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +// All Rights Reserved. +// +// Use, distribution, and modification of this source code and/or resulting +// object code is restricted to non-commercial enhancements to products from +// Valve LLC. All other use, distribution, or modification is prohibited +// without written permission from Valve LLC. +// +// +//===== player.cpp ======================================================== +// +// functions dealing with the player +// +// +// $Workfile: player.cpp $ +// $Date: 2002/11/22 21:12:55 $ +// +//------------------------------------------------------------------------------- +// $Log: player.cpp,v $ +// Revision 1.39 2002/11/22 21:12:55 Flayra +// - Added DMG_IGNOREARMOR flag for players (used for ending game quickly) +// - NULL checks for when owner of turret is removed after owner leaves team +// - Send deploy weapon switch to player, when "lastinv" is executed +// +// Revision 1.38 2002/11/15 19:09:40 Flayra +// - Reworked network metering to be easily toggleable +// +// Revision 1.37 2002/11/12 02:18:41 Flayra +// - Beginning of HLTV changes +// +// Revision 1.36 2002/10/24 21:18:23 Flayra +// - Major networking optimizations, to prevent overlflows after 20+ players on game reset +// +// Revision 1.35 2002/10/18 22:15:13 Flayra +// - Fixed problem where level5 gets stuck with redemption +// +// Revision 1.34 2002/10/16 00:40:39 Flayra +// - Fixed bug where player couldn't switch to next player while observing +// - Propagate health as short for larger aliens +// - Propagate auth mask +// +// Revision 1.33 2002/10/03 18:26:03 Flayra +// - Removed HL "flatline" sound on death +// +// Revision 1.32 2002/09/23 22:03:50 Flayra +// - Fixed problem where anims weren't playing properly in ready room +// - Fixed problem where gestation model anims were playing before model was updated +// +// Revision 1.31 2002/08/31 18:01:18 Flayra +// - Work at VALVe +// +// Revision 1.30 2002/08/09 00:17:03 Flayra +// - Allow moveleft and moveright to change targets, allow players to have only one primary weapon +// +// Revision 1.29 2002/07/23 16:48:21 Flayra +// - Refactored duplicate spawn code +// +// Revision 1.28 2002/07/10 14:36:09 Flayra +// - Fixed bug that caused "Battery" message to be sent every tick (this never showed up in HL because they never had a float armor value?) +// +// Revision 1.27 2002/07/08 16:31:39 Flayra +// - Level 1 doesn't make falling splat sound, dead players shouldn't block spawn points, replaced impulse hard-codes with constants +// +//=============================================================================== +#include +#include "extdll.h" +#include "util.h" + +#include "cbase.h" +#include "player.h" +#include "trains.h" +#include "nodes.h" +#include "weapons.h" +#include "soundent.h" +#include "monsters.h" +#include "../engine/shake.h" +#include "decals.h" +#include "gamerules.h" +#include "../mod/AvHEntities.h" +#include "../mod/AvHPlayer.h" +#include "../mod/AvHGamerules.h" +#include "../mod/AvHPlayerUpgrade.h" +#include "../mod/AvHServerUtil.h" +#include "../mod/AvHSharedUtil.h" +#include "../mod/AvHServerVariables.h" +#include "../mod/AvHHulls.h" +#include "../mod/AvHMovementUtil.h" +#include "game.h" +#include "../common/hltv.h" +#include "../mod/AvHNetworkMessages.h" +#include "../util/MathUtil.h" + +// #define DUCKFIX + +// Allow assignment within conditional +#pragma warning (disable: 4706) + +extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; +extern DLL_GLOBAL BOOL g_fGameOver; +extern DLL_GLOBAL BOOL g_fDrawLines; +int gEvilImpulse101; +extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; + + +BOOL gInitHUD = TRUE; + +extern void CopyToBodyQue(entvars_t* pev); +extern void respawn(entvars_t *pev, BOOL fCopyCorpse); +extern Vector VecBModelOrigin(entvars_t *pevBModel ); +//extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); + +// the world node graph +extern CGraph WorldGraph; + +#define TRAIN_ACTIVE 0x80 +#define TRAIN_NEW 0xc0 +#define TRAIN_OFF 0x00 +#define TRAIN_NEUTRAL 0x01 +#define TRAIN_SLOW 0x02 +#define TRAIN_MEDIUM 0x03 +#define TRAIN_FAST 0x04 +#define TRAIN_BACK 0x05 + +#define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes +#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) + +// Global Savedata for player +TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = +{ + DEFINE_FIELD( CBasePlayer, m_afButtonLast, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_afButtonPressed, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_afButtonReleased, FIELD_INTEGER ), + + DEFINE_ARRAY( CBasePlayer, m_rgItems, FIELD_INTEGER, MAX_ITEMS ), + DEFINE_FIELD( CBasePlayer, m_afPhysicsFlags, FIELD_INTEGER ), + + DEFINE_FIELD( CBasePlayer, m_flTimeStepSound, FIELD_TIME ), + DEFINE_FIELD( CBasePlayer, m_flTimeWeaponIdle, FIELD_TIME ), + DEFINE_FIELD( CBasePlayer, m_flSwimTime, FIELD_TIME ), + DEFINE_FIELD( CBasePlayer, m_flDuckTime, FIELD_TIME ), + DEFINE_FIELD( CBasePlayer, m_flWallJumpTime, FIELD_TIME ), + + DEFINE_FIELD( CBasePlayer, m_flSuitUpdate, FIELD_TIME ), + DEFINE_ARRAY( CBasePlayer, m_rgSuitPlayList, FIELD_INTEGER, CSUITPLAYLIST ), + DEFINE_FIELD( CBasePlayer, m_iSuitPlayNext, FIELD_INTEGER ), + DEFINE_ARRAY( CBasePlayer, m_rgiSuitNoRepeat, FIELD_INTEGER, CSUITNOREPEAT ), + DEFINE_ARRAY( CBasePlayer, m_rgflSuitNoRepeatTime, FIELD_TIME, CSUITNOREPEAT ), + DEFINE_FIELD( CBasePlayer, m_lastDamageAmount, FIELD_INTEGER ), + + DEFINE_ARRAY( CBasePlayer, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), + DEFINE_FIELD( CBasePlayer, m_pActiveItem, FIELD_CLASSPTR ), + DEFINE_FIELD( CBasePlayer, m_pLastItem, FIELD_CLASSPTR ), + + DEFINE_ARRAY( CBasePlayer, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), + DEFINE_FIELD( CBasePlayer, m_idrowndmg, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_idrownrestored, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_tSneaking, FIELD_TIME ), + + DEFINE_FIELD( CBasePlayer, m_iTrain, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_bitsHUDDamage, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_flFallVelocity, FIELD_FLOAT ), + DEFINE_FIELD( CBasePlayer, m_iTargetVolume, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_iWeaponVolume, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_iExtraSoundTypes, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_iWeaponFlash, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_fLongJump, FIELD_BOOLEAN ), + DEFINE_FIELD( CBasePlayer, m_fInitHUD, FIELD_BOOLEAN ), + DEFINE_FIELD( CBasePlayer, m_tbdPrev, FIELD_TIME ), + + DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ), + DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ), +}; + +void CBasePlayer :: Pain( void ) +{ + float flRndSound;//sound randomizer + + flRndSound = RANDOM_FLOAT ( 0 , 1 ); + + if ( flRndSound <= 0.33 ) + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); + else if ( flRndSound <= 0.66 ) + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); + else + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); +} + +/* + * + */ +Vector VecVelocityForDamage(float flDamage) +{ + Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); + + if (flDamage > -50) + vec = vec * 0.7; + else if (flDamage > -200) + vec = vec * 2; + else + vec = vec * 10; + + return vec; +} + +#if 0 /* +static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) +{ + edict_t *pentNew = CREATE_ENTITY(); + entvars_t *pevNew = VARS(pentNew); + + pevNew->origin = pev->origin; + SET_MODEL(ENT(pevNew), szGibModel); + UTIL_SetSize(pevNew, g_vecZero, g_vecZero); + + pevNew->velocity = VecVelocityForDamage(flDamage); + pevNew->movetype = MOVETYPE_BOUNCE; + pevNew->solid = SOLID_NOT; + pevNew->avelocity.x = RANDOM_FLOAT(0,600); + pevNew->avelocity.y = RANDOM_FLOAT(0,600); + pevNew->avelocity.z = RANDOM_FLOAT(0,600); + CHANGE_METHOD(ENT(pevNew), em_think, SUB_Remove); + pevNew->ltime = gpGlobals->time; + pevNew->nextthink = gpGlobals->time + RANDOM_FLOAT(10,20); + pevNew->frame = 0; + pevNew->flags = 0; +} + + +static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) +{ + SET_MODEL(ENT(pev), szGibModel); + pev->frame = 0; + pev->nextthink = -1; + pev->movetype = MOVETYPE_BOUNCE; + pev->takedamage = DAMAGE_NO; + pev->solid = SOLID_NOT; + pev->view_ofs = Vector(0,0,8); + UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,56)); + pev->velocity = VecVelocityForDamage(flDamage); + pev->avelocity = RANDOM_FLOAT(-1,1) * Vector(0,600,0); + pev->origin.z -= 24; + ClearBits(pev->flags, FL_ONGROUND); +} + + +*/ +#endif + +int TrainSpeed(int iSpeed, int iMax) +{ + float fSpeed, fMax; + int iRet = 0; + + fMax = (float)iMax; + fSpeed = iSpeed; + + fSpeed = fSpeed/fMax; + + if (iSpeed < 0) + iRet = TRAIN_BACK; + else if (iSpeed == 0) + iRet = TRAIN_NEUTRAL; + else if (fSpeed < 0.33) + iRet = TRAIN_SLOW; + else if (fSpeed < 0.66) + iRet = TRAIN_MEDIUM; + else + iRet = TRAIN_FAST; + + return iRet; +} + +void CBasePlayer :: DeathSound( void ) +{ + // water death sounds + /* + if (pev->waterlevel == 3) + { + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); + return; + } + */ + + // temporarily using pain sounds for death sounds + switch (RANDOM_LONG(1,5)) + { + case 1: + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); + break; + case 2: + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); + break; + case 3: + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); + break; + } + + // play one of the suit death alarms + //EMIT_GROUPNAME_SUIT(ENT(pev), "HEV_DEAD"); +} + +// override takehealth +// bitsDamageType indicates type of damage healed. + +int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) +{ + return CBaseMonster :: TakeHealth (flHealth, bitsDamageType); + +} + +Vector CBasePlayer :: GetGunPosition( ) +{ +// UTIL_MakeVectors(pev->v_angle); +// m_HackedGunPos = pev->view_ofs; + Vector origin; + + origin = pev->origin + pev->view_ofs; + + return origin; +} + +//========================================================= +// TraceAttack +//========================================================= +void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if ( pev->takedamage ) + { + m_LastHitGroup = ptr->iHitgroup; + + switch ( ptr->iHitgroup ) + { + case HITGROUP_GENERIC: + break; + case HITGROUP_HEAD: + flDamage *= gSkillData.plrHead; + break; + case HITGROUP_CHEST: + flDamage *= gSkillData.plrChest; + break; + case HITGROUP_STOMACH: + flDamage *= gSkillData.plrStomach; + break; + case HITGROUP_LEFTARM: + case HITGROUP_RIGHTARM: + flDamage *= gSkillData.plrArm; + break; + case HITGROUP_LEFTLEG: + case HITGROUP_RIGHTLEG: + flDamage *= gSkillData.plrLeg; + break; + default: + break; + } + + SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. + TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); + } +} + +void CBasePlayer::SpawnClientSideCorpse() +{ +// char *infobuffer = g_engfuncs.pfnGetInfoKeyBuffer( edict() ); +// char *pModel = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); +// +// MESSAGE_BEGIN( MSG_ALL, gmsgSendCorpse ); +// WRITE_STRING( pModel ); +// WRITE_LONG ( pev->origin.x * 128.0); +// WRITE_LONG ( pev->origin.y * 128.0); +// WRITE_LONG ( pev->origin.z * 128.0); +// WRITE_COORD ( pev->angles.x ); +// WRITE_COORD ( pev->angles.y ); +// WRITE_COORD ( pev->angles.z ); +// WRITE_LONG ( (pev->animtime - gpGlobals->time) * 100.0f ); +// WRITE_BYTE ( pev->sequence ); +// WRITE_BYTE ( pev->body ); +// MESSAGE_END(); +} + +/* + Take some damage. + NOTE: each call to TakeDamage with bitsDamageType set to a time-based damage + type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation + etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC. +*/ + +int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + // have suit diagnose the problem - ie: report damage type + int bitsDamage = bitsDamageType; + int ffound = TRUE; + int fmajor; + int fcritical; + int fTookDamage; + int ftrivial; + //float flRatio; + //float flBonus; + float flHealthPrev = pev->health; + + //flBonus = AvHPlayerUpgrade::GetArmorBonus(this->pev->iuser4); + //flRatio = AvHPlayerUpgrade::GetArmorRatio(this->pev->iuser4); + +// if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) +// { +// // blasts damage armor more. +// flBonus *= 2; +// } + + // Already dead + if ( !IsAlive() ) + return 0; + // go take the damage first + + + CBaseEntity *pAttacker = NULL; + + if(pevAttacker) + { + pAttacker = CBaseEntity::Instance(pevAttacker); + } + + if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) + { + // Refuse the damage + return 0; + } + + // keep track of amount of damage last sustained + m_lastDamageAmount = flDamage; + + if(!(bitsDamageType & DMG_IGNOREARMOR)) + { + flDamage = AvHPlayerUpgrade::CalculateDamageLessArmor((AvHUser3)this->pev->iuser3, this->pev->iuser4, flDamage, this->pev->armorvalue, bitsDamageType, GetGameRules()->GetNumActiveHives((AvHTeamNumber)this->pev->team)); + } + else + { + int a = 0; + } + + // Armor. +// if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage! +// { +// float flNew = flDamage * flRatio; +// +// float flArmor; +// +// flArmor = (flDamage - flNew) * flBonus; +// +// // Does this use more armor than we have? +// if (flArmor > pev->armorvalue) +// { +// flArmor = pev->armorvalue; +// flArmor *= (1/flBonus); +// flNew = flDamage - flArmor; +// pev->armorvalue = 0; +// } +// else +// pev->armorvalue -= flArmor; +// +// flDamage = flNew; +// } + + fTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); + + // reset damage time countdown for each type of time based damage player just sustained + + { + for (int i = 0; i < CDMG_TIMEBASED; i++) + if (bitsDamageType & (DMG_PARALYZE << i)) + m_rgbTimeBasedDamage[i] = 0; + } + + // tell director about it + MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); + WRITE_BYTE(DIRECTOR_MESSAGE_SIZE); + WRITE_BYTE ( DRC_CMD_EVENT ); // take damage event + WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity + WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity + WRITE_LONG( 5 ); // eventflags (priority and flags) + MESSAGE_END(); + + + // how bad is it, doc? + + ftrivial = (pev->health > 75 || m_lastDamageAmount < 5); + fmajor = (m_lastDamageAmount > 25); + fcritical = (pev->health < 30); + + // handle all bits set in this damage message, + // let the suit give player the diagnosis + + // UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash ) + + // UNDONE: still need to record damage and heal messages for the following types + + // DMG_BURN + // DMG_FREEZE + // DMG_BLAST + // DMG_SHOCK + + m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client + m_bitsHUDDamage = -1; // make sure the damage bits get resent + + while (fTookDamage && (!ftrivial || (bitsDamage & DMG_TIMEBASED)) && ffound && bitsDamage) + { + ffound = FALSE; + + if (bitsDamage & DMG_CLUB) + { + if (fmajor) + SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture + bitsDamage &= ~DMG_CLUB; + ffound = TRUE; + } + if (bitsDamage & (DMG_FALL | DMG_CRUSH)) + { + if (fmajor) + SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC); // major fracture + else + SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture + + bitsDamage &= ~(DMG_FALL | DMG_CRUSH); + ffound = TRUE; + } + + if (bitsDamage & DMG_BULLET) + { + if (m_lastDamageAmount > 5) + SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC); // blood loss detected + //else + // SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration + + bitsDamage &= ~DMG_BULLET; + ffound = TRUE; + } + + if (bitsDamage & DMG_SLASH) + { + if (fmajor) + SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC); // major laceration + else + SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration + + bitsDamage &= ~DMG_SLASH; + ffound = TRUE; + } + + if (bitsDamage & DMG_SONIC) + { + if (fmajor) + SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN); // internal bleeding + bitsDamage &= ~DMG_SONIC; + ffound = TRUE; + } + + if (bitsDamage & (DMG_POISON | DMG_PARALYZE)) + { + SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN); // blood toxins detected + bitsDamage &= ~(DMG_POISON | DMG_PARALYZE); + ffound = TRUE; + } + + if (bitsDamage & DMG_ACID) + { + SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected + bitsDamage &= ~DMG_ACID; + ffound = TRUE; + } + + if (bitsDamage & DMG_NERVEGAS) + { + SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN); // biohazard detected + bitsDamage &= ~DMG_NERVEGAS; + ffound = TRUE; + } + + if (bitsDamage & DMG_RADIATION) + { + SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected + bitsDamage &= ~DMG_RADIATION; + ffound = TRUE; + } + if (bitsDamage & DMG_SHOCK) + { + bitsDamage &= ~DMG_SHOCK; + ffound = TRUE; + } + } + + pev->punchangle.x = -2; + + if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) + { + // first time we take major damage... + // turn automedic on if not on + SetSuitUpdate("!HEV_MED1", FALSE, SUIT_NEXT_IN_30MIN); // automedic on + + // give morphine shot if not given recently + SetSuitUpdate("!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN); // morphine shot + } + + if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75) + { + + // already took major damage, now it's critical... + if (pev->health < 6) + SetSuitUpdate("!HEV_HLTH3", FALSE, SUIT_NEXT_IN_10MIN); // near death + else if (pev->health < 20) + SetSuitUpdate("!HEV_HLTH2", FALSE, SUIT_NEXT_IN_10MIN); // health critical + + // give critical health warnings + if (!RANDOM_LONG(0,3) && flHealthPrev < 50) + SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention + } + + // if we're taking time based damage, warn about its continuing effects + if (fTookDamage && (bitsDamageType & DMG_TIMEBASED) && flHealthPrev < 75) + { + if (flHealthPrev < 50) + { + if (!RANDOM_LONG(0,3)) + SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention + } + else + SetSuitUpdate("!HEV_HLTH1", FALSE, SUIT_NEXT_IN_10MIN); // health dropping + } + + //return fTookDamage; + int theReturnValue = 0; + if(fTookDamage) + { + theReturnValue = flDamage; + } + return theReturnValue; +} + +//========================================================= +// PackDeadPlayerItems - call this when a player dies to +// pack up the appropriate weapons and ammo items, and to +// destroy anything that shouldn't be packed. +// +// This is pretty brute force :( +//========================================================= +void CBasePlayer::PackDeadPlayerItems( void ) +{ + int iWeaponRules; + int iAmmoRules; + int i; + CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have? + int iPackAmmo[ MAX_AMMO_SLOTS + 1]; + int iPW = 0;// index into packweapons array + int iPA = 0;// index into packammo array + + memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) ); + memset(iPackAmmo, -1, sizeof(iPackAmmo) ); + + // get the game rules + iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); + iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); + + if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) + { + // nothing to pack. Remove the weapons and return. Don't call create on the box! + RemoveAllItems( TRUE ); + return; + } + +// go through all of the weapons and make a list of the ones to pack + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + // there's a weapon here. Should I pack it? + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; + + while ( pPlayerItem ) + { + switch( iWeaponRules ) + { + case GR_PLR_DROP_GUN_ACTIVE: + if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) + { + // this is the active item. Pack it. + rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; + } + break; + + case GR_PLR_DROP_GUN_ALL: + rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; + break; + + default: + break; + } + + pPlayerItem = pPlayerItem->m_pNext; + } + } + } + +// now go through ammo and make a list of which types to pack. + if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) + { + for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + { + if ( m_rgAmmo[ i ] > 0 ) + { + // player has some ammo of this type. + switch ( iAmmoRules ) + { + case GR_PLR_DROP_AMMO_ALL: + iPackAmmo[ iPA++ ] = i; + break; + + case GR_PLR_DROP_AMMO_ACTIVE: + if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) + { + // this is the primary ammo type for the active weapon + iPackAmmo[ iPA++ ] = i; + } + else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) + { + // this is the secondary ammo type for the active weapon + iPackAmmo[ iPA++ ] = i; + } + break; + + default: + break; + } + } + } + } + +// create a box to pack the stuff into. + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, edict() ); + + pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. + pWeaponBox->pev->angles.z = 0; + + pWeaponBox->SetThink( &CWeaponBox::Kill ); + pWeaponBox->pev->nextthink = gpGlobals->time + 120; + +// back these two lists up to their first elements + iPA = 0; + iPW = 0; + +// pack the ammo + while ( iPackAmmo[ iPA ] != -1 ) + { + // Only pack items with ammo + const char* theAmmoName = CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName; + if(theAmmoName && theAmmoName != "") + pWeaponBox->PackAmmo( MAKE_STRING(theAmmoName), m_rgAmmo[ iPackAmmo[ iPA ] ] ); + + iPA++; + } + +// now pack all of the items in the lists + while ( rgpPackWeapons[ iPW ] ) + { + // weapon unhooked from the player. Pack it into der box. + pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); + + iPW++; + } + + pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. + + RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. +} + +void CBasePlayer::DestroyAllItems(BOOL removeSuit) +{ + if (m_pActiveItem) + { + ResetAutoaim( ); + m_pActiveItem->Holster( ); + m_pActiveItem = NULL; + } + + m_pLastItem = NULL; + + int i; + CBasePlayerItem *pPendingItem; + for (i = 0; i < MAX_ITEM_TYPES; i++) + { + m_pActiveItem = m_rgpPlayerItems[i]; + while (m_pActiveItem) + { + pPendingItem = m_pActiveItem->m_pNext; + m_pActiveItem->DestroyItem(); + m_pActiveItem = pPendingItem; + } + m_rgpPlayerItems[i] = NULL; + } + m_pActiveItem = NULL; + + pev->viewmodel = 0; + pev->weaponmodel = 0; + + if ( removeSuit ) + pev->weapons = 0; + else + pev->weapons &= ~WEAPON_ALLWEAPONS; + + for ( i = 0; i < MAX_AMMO_SLOTS;i++) + m_rgAmmo[i] = 0; + + // send Selected Weapon Message to our client + NetMsg_CurWeapon( pev, 0, 0, 0 ); +} + +void CBasePlayer::RemoveAllItems( BOOL removeSuit ) +{ + if (m_pActiveItem) + { + ResetAutoaim( ); + m_pActiveItem->Holster( ); + m_pActiveItem = NULL; + } + + m_pLastItem = NULL; + + int i; + CBasePlayerItem *pPendingItem; + for (i = 0; i < MAX_ITEM_TYPES; i++) + { + m_pActiveItem = m_rgpPlayerItems[i]; + while (m_pActiveItem) + { + pPendingItem = m_pActiveItem->m_pNext; + m_pActiveItem->Drop( ); + m_pActiveItem = pPendingItem; + } + m_rgpPlayerItems[i] = NULL; + } + m_pActiveItem = NULL; + + pev->viewmodel = 0; + pev->weaponmodel = 0; + + if ( removeSuit ) + pev->weapons = 0; + else + pev->weapons &= ~WEAPON_ALLWEAPONS; + + for ( i = 0; i < MAX_AMMO_SLOTS;i++) + m_rgAmmo[i] = 0; + +// UpdateClientData(); +// // send Selected Weapon Message to our client +// MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); +// WRITE_BYTE(0); +// WRITE_BYTE(0); +// WRITE_BYTE(0); +// MESSAGE_END(); +} + +/* + * GLOBALS ASSUMED SET: g_ulModelIndexPlayer + * + * ENTITY_METHOD(PlayerDie) + */ +entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage inflictor for death messages. + // Better solution: Add as parameter to all Killed() functions. + +void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) +{ + CSound *pSound; + + // Holster weapon immediately, to allow it to cleanup + if ( m_pActiveItem ) + m_pActiveItem->Holster( ); + + GetGameRules()->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); + + if ( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + + // this client isn't going to be thinking for a while, so reset the sound until they respawn + pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) ); + { + if ( pSound ) + { + pSound->Reset(); + } + } + + SetAnimation( PLAYER_DIE ); + + m_iRespawnFrames = 0; + + //pev->modelindex = g_ulModelIndexPlayer; // don't use eyes + + // Clear buttons held down on death, fixes bug where player can't switch observer targets + m_afButtonLast = 0; + + pev->deadflag = DEAD_DYING; + pev->movetype = MOVETYPE_TOSS; + ClearBits( pev->flags, FL_ONGROUND ); + if (pev->velocity.z < 10) + pev->velocity.z += RANDOM_FLOAT(0,300); + + // clear out the suit message cache so we don't keep chattering + SetSuitUpdate(NULL, FALSE, 0); + + // send "health" update message to zero + m_iClientHealth = 0; + NetMsg_Health( pev, m_iClientHealth ); + + // Tell Ammo Hud that the player is dead + NetMsg_CurWeapon( pev, 0, 0xFF, 0xFF ); + + // reset FOV + pev->fov = m_iFOV = m_iClientFOV = 0; + NetMsg_SetFOV( pev, 0 ); + + + // UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12 + // UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE ); + + if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) + { + pev->solid = SOLID_NOT; + GibMonster(); // This clears pev->model + pev->effects |= EF_NODRAW; + return; + } + + DeathSound(); + + pev->angles.x = 0; + pev->angles.z = 0; + + SetThink(&CBasePlayer::PlayerDeathThink); + pev->nextthink = gpGlobals->time + 0.1; +} + +void CBasePlayer::Suicide(void) +{ + AvHPlayer* thePlayer = dynamic_cast(this); + + ASSERT(thePlayer); + + if(thePlayer && thePlayer->GetUsedKilled())//: prevent exploitation of "kill" command. + return; + + // have the player kill themself + float theKillDelay = ns_cvar_float(&avh_killdelay); + + #ifdef DEBUG + #ifndef AVH_EXTERNAL_BUILD + theKillDelay = 0; + #endif + #endif + + if(theKillDelay > 0.0f) + { + char theMessage[256]; + sprintf(theMessage, "Suiciding in %.1f seconds...\n", theKillDelay); + UTIL_SayText(theMessage, this, ENTINDEX(this->edict())); + } + + thePlayer->SetUsedKilled(true); + SetThink(&CBasePlayer::SuicideThink); + this->pev->nextthink = gpGlobals->time + theKillDelay; +} + +void CBasePlayer::SuicideThink(void) +{ + AvHPlayer* thePlayer = dynamic_cast(this); + if(thePlayer && thePlayer->GetCanBeAffectedByEnemies()) + { + this->pev->health = 0; + this->Killed(this->pev, GIB_NEVER); + } +} + +// Set the activity based on an event or current state +void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) +{ + int animDesired; + int gaitDesired; + float speed; + char szAnim[64]; + bool theFoundAnim = true; + int theDebugAnimations = BALANCE_VAR(kDebugAnimations); + bool reloadAnim = false; + + // Make sure the model is set, as gestating models aren't set before the animation starts playing + AvHPlayer* theAvHPlayer = dynamic_cast(this); + ASSERT(theAvHPlayer); + theAvHPlayer->SetModelFromState(); + + speed = pev->velocity.Length2D(); + + if (pev->flags & FL_FROZEN) + { + speed = 0; + playerAnim = PLAYER_IDLE; + } + + switch (playerAnim) + { + case PLAYER_JUMP: + m_IdealActivity = ACT_HOP; + break; + + case PLAYER_SUPERJUMP: + m_IdealActivity = ACT_LEAP; + break; + + case PLAYER_DIE: + m_IdealActivity = ACT_DIESIMPLE; + m_IdealActivity = GetDeathActivity( ); + + //this->GetAnimationForActivity(this->m_IdealActivity, szAnim); + //animDesired = LookupSequence( szAnim ); + //if (animDesired == -1) + //{ + // animDesired = 0; + //} + //this->pev->sequence = animDesired; + break; + + case PLAYER_ATTACK1: + switch( m_Activity ) + { + case ACT_HOVER: + case ACT_SWIM: + case ACT_HOP: + case ACT_LEAP: + case ACT_DIESIMPLE: + m_IdealActivity = m_Activity; + break; + default: + m_IdealActivity = ACT_RANGE_ATTACK1; + break; + } + break; + + case PLAYER_PRIME: + switch( m_Activity ) + { + case ACT_HOVER: + case ACT_SWIM: + case ACT_HOP: + case ACT_LEAP: + case ACT_DIESIMPLE: + m_IdealActivity = m_Activity; + break; + default: + m_IdealActivity = ACT_RANGE_PRIME; + break; + } + break; + + case PLAYER_RELOAD: + switch( m_Activity ) + { + case ACT_HOVER: + case ACT_SWIM: + case ACT_HOP: + case ACT_LEAP: + case ACT_DIESIMPLE: + m_IdealActivity = m_Activity; + break; + default: + m_IdealActivity = ACT_RELOAD; + break; + } + break; + case PLAYER_RELOAD_START: + switch( m_Activity ) + { + case ACT_HOVER: + case ACT_SWIM: + case ACT_HOP: + case ACT_LEAP: + case ACT_DIESIMPLE: + m_IdealActivity = m_Activity; + break; + default: + m_IdealActivity = ACT_RELOAD_START; + break; + } + break; + case PLAYER_RELOAD_INSERT: + switch( m_Activity ) + { + case ACT_HOVER: + case ACT_SWIM: + case ACT_HOP: + case ACT_LEAP: + case ACT_DIESIMPLE: + m_IdealActivity = m_Activity; + break; + default: + m_IdealActivity = ACT_RELOAD_INSERT; + break; + } + break; + case PLAYER_RELOAD_END: + switch( m_Activity ) + { + case ACT_HOVER: + case ACT_SWIM: + case ACT_HOP: + case ACT_LEAP: + case ACT_DIESIMPLE: + m_IdealActivity = m_Activity; + break; + default: + m_IdealActivity = ACT_RELOAD_END; + break; + } + break; + case PLAYER_IDLE: + case PLAYER_WALK: + if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping + { + m_IdealActivity = m_Activity; + } + else if ( pev->waterlevel > 1 ) + { + if ( speed == 0 ) + m_IdealActivity = ACT_HOVER; + else + m_IdealActivity = ACT_SWIM; + } + else + { + if((playerAnim == PLAYER_IDLE) && !strcmp(this->m_szAnimExtention, "") && (theAvHPlayer->GetPlayMode() != PLAYMODE_READYROOM)) + { + m_IdealActivity = ACT_IDLE; + } + else + { + m_IdealActivity = ACT_WALK; + } + } + break; + } + + switch (m_IdealActivity) + { + + case ACT_DIESIMPLE: + case ACT_DIEBACKWARD: + case ACT_DIEFORWARD: + case ACT_DIEVIOLENT: + default: + if ( m_Activity == m_IdealActivity) + return; + m_Activity = m_IdealActivity; + + //animDesired = LookupActivity( m_Activity ); + this->GetAnimationForActivity(this->m_Activity, szAnim); + animDesired = LookupSequence( szAnim ); + + // Already using the desired animation? + if (pev->sequence == animDesired) + return; + + #ifdef DEBUG + if(theDebugAnimations) + { + char theMessage[256]; + sprintf(theMessage, "Setting full-body animation (%s): %d (no gaitsequence)\n", szAnim, animDesired); + ALERT(at_console, theMessage); + } + #endif + + pev->gaitsequence = 0; + pev->sequence = animDesired; + pev->frame = 0; + ResetSequenceInfo( ); + return; + + // create seperate case for these so that they don't interfere with a reload - Elven + case ACT_HOVER: + case ACT_LEAP: + case ACT_SWIM: + case ACT_HOP: + reloadAnim = (m_Activity == ACT_RELOAD) || (m_Activity == ACT_RELOAD_START) || (m_Activity == ACT_RELOAD_INSERT) || (m_Activity == ACT_RELOAD_END); + if ( m_Activity == m_IdealActivity || reloadAnim) + return; + m_Activity = m_IdealActivity; + + //animDesired = LookupActivity( m_Activity ); + this->GetAnimationForActivity(this->m_Activity, szAnim); + animDesired = LookupSequence( szAnim ); + + // Already using the desired animation? + if (pev->sequence == animDesired) + return; + pev->gaitsequence = 0; + pev->sequence = animDesired; + pev->frame = 0; + ResetSequenceInfo( ); + return; + + + case ACT_RANGE_ATTACK1: + case ACT_RANGE_PRIME: + this->GetAnimationForActivity(this->m_IdealActivity, szAnim); + animDesired = LookupSequence( szAnim ); + + if (animDesired == -1) + { + animDesired = 0; + theFoundAnim = false; + } + + if ( pev->sequence != animDesired || !m_fSequenceLoops ) + { + pev->frame = 0; + } + + if (!m_fSequenceLoops) + { + pev->effects |= EF_NOINTERP; + } + + m_Activity = m_IdealActivity; + + if(theFoundAnim) + { + #ifdef DEBUG + if(theDebugAnimations) + { + char theMessage[256]; + sprintf(theMessage, "%s%s\n", "Setting attack animation: ", szAnim); + ALERT(at_console, theMessage); + } + #endif + } + + pev->sequence = animDesired; + ResetSequenceInfo( ); + break; + + case ACT_RELOAD: + case ACT_RELOAD_START: + case ACT_RELOAD_INSERT: + case ACT_RELOAD_END: + this->GetAnimationForActivity(this->m_IdealActivity, szAnim); + animDesired = LookupSequence( szAnim ); + + if ( pev->sequence != animDesired || !m_fSequenceLoops ) + { + pev->frame = 0; + } + m_Activity = m_IdealActivity; + break; + + + + case ACT_WALK: + reloadAnim = (m_Activity == ACT_RELOAD) || (m_Activity == ACT_RELOAD_START) || + (m_Activity == ACT_RELOAD_INSERT) || (m_Activity == ACT_RELOAD_END); + if ((m_Activity != ACT_RANGE_ATTACK1 && m_Activity != ACT_RANGE_PRIME && !reloadAnim/*m_Activity != ACT_RELOAD*/ ) || m_fSequenceFinished) + { + this->GetAnimationForActivity(this->m_IdealActivity, szAnim); + animDesired = LookupSequence( szAnim ); + if (animDesired == -1) + { + animDesired = 0; + } + m_Activity = ACT_WALK; + } + else + { + animDesired = pev->sequence; + } + break; + } + + // Now handle gaitsequence + if(FBitSet(this->pev->flags, FL_DUCKING)) + { + if(speed == 0) + { + this->GetAnimationForActivity(ACT_CROUCHIDLE, szAnim, true); + } + else + { + this->GetAnimationForActivity(ACT_CROUCH, szAnim, true); + } + } + else if (speed > this->GetMaxWalkSpeed() ) + { + this->GetAnimationForActivity(ACT_RUN, szAnim, true); + } + else if (speed > 0) + { + this->GetAnimationForActivity(ACT_WALK, szAnim, true); + } + else + { + this->GetAnimationForActivity(ACT_IDLE, szAnim, true); + } + + // Set the gaitsequence + gaitDesired = LookupSequence(szAnim, 1); + if(gaitDesired == -1) + { + gaitDesired = 0; + } + +#ifdef DEBUG + if(theDebugAnimations) + { + if((this->pev->gaitsequence != gaitDesired) || (this->pev->sequence != animDesired)) + { + ALERT(at_console, "Anim desired (%s): %d, gaitsequence: %d gaitdesired: %d \n", szAnim, animDesired, pev->gaitsequence, gaitDesired); + } + } +#endif + + this->pev->gaitsequence = gaitDesired; + + AvHPlayer* thePlayer = dynamic_cast(this); + if(thePlayer && (thePlayer->GetPlayMode() == PLAYMODE_READYROOM)) + { + // Play some animation on top and bottom when not holding any weapons + animDesired = gaitDesired; + } + + // Already using the desired animation? + if (pev->sequence == animDesired) + return; + + // Reset to first frame of desired animation + pev->sequence = animDesired; + pev->frame = 0; + ResetSequenceInfo( ); +} + +/* +=========== +TabulateAmmo +This function is used to find and store +all the ammo we have into the ammo vars. +============ +*/ +void CBasePlayer::TabulateAmmo() +{ + ammo_9mm = AmmoInventory( GetAmmoIndex( "9mm" ) ); + ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) ); + ammo_argrens = AmmoInventory( GetAmmoIndex( "ARgrenades" ) ); + ammo_bolts = AmmoInventory( GetAmmoIndex( "bolts" ) ); + ammo_buckshot = AmmoInventory( GetAmmoIndex( "buckshot" ) ); + ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) ); + ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) ); + ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) ); +} + + +/* +=========== +WaterMove +============ +*/ +#define AIRTIME 12 // lung full of air lasts this many seconds + +void CBasePlayer::WaterMove() +{ + int air; + + if (pev->movetype == MOVETYPE_NOCLIP) + return; + + if (pev->health < 0) + return; + + // waterlevel 0 - not in water + // waterlevel 1 - feet in water + // waterlevel 2 - waist in water + // waterlevel 3 - head in water + + if (pev->waterlevel != 3) + { + // not underwater + + // play 'up for air' sound + if (pev->air_finished < gpGlobals->time) + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", 1, ATTN_NORM); + else if (pev->air_finished < gpGlobals->time + 9) + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", 1, ATTN_NORM); + + pev->air_finished = gpGlobals->time + AIRTIME; + pev->dmg = 2; + + // if we took drowning damage, give it back slowly + if (m_idrowndmg > m_idrownrestored) + { + // set drowning damage bit. hack - dmg_drownrecover actually + // makes the time based damage code 'give back' health over time. + // make sure counter is cleared so we start count correctly. + + // NOTE: this actually causes the count to continue restarting + // until all drowning damage is healed. + + m_bitsDamageType |= DMG_DROWNRECOVER; + m_bitsDamageType &= ~DMG_DROWN; + m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; + } + + } + else + { // fully under water + // stop restoring damage while underwater + m_bitsDamageType &= ~DMG_DROWNRECOVER; + m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; + + if (pev->air_finished < gpGlobals->time) // drown! + { + if (pev->pain_finished < gpGlobals->time) + { + // take drowning damage + pev->dmg += 1; + if (pev->dmg > 5) + pev->dmg = 5; + TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN); + pev->pain_finished = gpGlobals->time + 1; + + // track drowning damage, give it back when + // player finally takes a breath + + m_idrowndmg += pev->dmg; + } + } + else + { + m_bitsDamageType &= ~DMG_DROWN; + } + } + + if (!pev->waterlevel) + { + if (FBitSet(pev->flags, FL_INWATER)) + { + ClearBits(pev->flags, FL_INWATER); + } + return; + } + + // make bubbles + + air = (int)(pev->air_finished - gpGlobals->time); + if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air) + { + switch (RANDOM_LONG(0,3)) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim1.wav", 0.8, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 0.8, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim3.wav", 0.8, ATTN_NORM); break; + case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim4.wav", 0.8, ATTN_NORM); break; + } + } + + if (pev->watertype == CONTENT_LAVA) // do damage + { + if (pev->dmgtime < gpGlobals->time) + TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN); + } + else if (pev->watertype == CONTENT_SLIME) // do damage + { + pev->dmgtime = gpGlobals->time + 1; + TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID); + } + + if (!FBitSet(pev->flags, FL_INWATER)) + { + SetBits(pev->flags, FL_INWATER); + pev->dmgtime = 0; + } +} + +void CBasePlayer::InitPlayerFromSpawn(edict_t* inSpawn) +{ + if(!FNullEnt(inSpawn)) + { + int theOffset = AvHMUGetOriginOffsetForUser3(AvHUser3(this->pev->iuser3)); + this->pev->origin = VARS(inSpawn)->origin + Vector(0, 0, theOffset); + + this->pev->v_angle = VARS(inSpawn)->v_angle; + this->pev->velocity = g_vecZero; + this->pev->angles = VARS(inSpawn)->angles; + this->pev->punchangle = g_vecZero; + this->pev->fixangle = TRUE; + } +} + +// TRUE if the player is attached to a ladder +BOOL CBasePlayer::IsOnLadder( void ) +{ + return ( pev->movetype == MOVETYPE_FLY ); +} + +void CBasePlayer::PlayerDeathThink(void) +{ + float flForward; + + if (FBitSet(pev->flags, FL_ONGROUND)) + { + flForward = pev->velocity.Length() - 20; + if (flForward <= 0) + pev->velocity = g_vecZero; + else + pev->velocity = flForward * pev->velocity.Normalize(); + } + + if ( HasWeapons() ) + { + // we drop the guns here because weapons that have an area effect and can kill their user + // will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the + // player class sometimes is freed. It's safer to manipulate the weapons once we know + // we aren't calling into any of their code anymore through the player pointer. + PackDeadPlayerItems(); + + // Assumes that all players have at least one weapon when they die + //SpawnClientSideCorpse(); + } + + if (pev->modelindex && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)) + { + StudioFrameAdvance( ); + + m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands + if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this + return; + } + + // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore + // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn + if ( pev->movetype != MOVETYPE_NONE && FBitSet(pev->flags, FL_ONGROUND) ) + pev->movetype = MOVETYPE_NONE; + + if (pev->deadflag == DEAD_DYING) + pev->deadflag = DEAD_DEAD; + + StopAnimation(); + + pev->effects |= EF_NOINTERP; + pev->framerate = 0.0; + + BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); + + // wait for all buttons released + if (pev->deadflag == DEAD_DEAD) + { + //if (fAnyButtonDown) + // return; + + //if ( g_pGameRules->FPlayerCanRespawn( this ) ) + //{ + m_fDeadTime = gpGlobals->time; + pev->deadflag = DEAD_RESPAWNABLE; + //} + + return; + } + +// if the player has been dead for one second longer than allowed by forcerespawn, +// forcerespawn isn't on. Send the player off to an intermission camera until they +// choose to respawn. + //if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) ) + //{ + // // go to dead camera. + // StartDeathCam(); + //} + + + // From Counter-strike + // if the player has been dead for one second longer than allowed by forcerespawn, + // forcerespawn isn't on. Send the player off to an intermission camera until they + // choose to respawn. +// if ( g_pGameRules->IsMultiplayer() && +// ( gpGlobals->time > (m_fDeadTime + 3) ) && +// !( m_afPhysicsFlags & PFLAG_OBSERVER) ) +// { +// //Send message to everybody to spawn a corpse. +// SpawnClientSideCorpse(); +// +// // go to dead camera. +// //StartDeathCam(); +// } + + const float kMinDeathTime = .5f; + +// wait for any button down, or mp_forcerespawn is set and the respawn time is up + if ((!fAnyButtonDown || ( gpGlobals->time < (m_fDeadTime + kMinDeathTime) )) + && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && (gpGlobals->time > (m_fDeadTime + kMinDeathTime))) ) + return; + + pev->button = 0; + m_iRespawnFrames = 0; + + // Player is done with the death cam, continue + AvHPlayer* thePlayer = dynamic_cast(this); + AvHGamerules* theGameRules = dynamic_cast(g_pGameRules); + + theGameRules->PlayerDeathEnd(thePlayer); +} + +//========================================================= +// StartDeathCam - find an intermission spot and send the +// player off into observer mode +//========================================================= +void CBasePlayer::StartDeathCam( void ) +{ + edict_t *pSpot, *pNewSpot; + int iRand; + + if ( pev->view_ofs == g_vecZero ) + { + // don't accept subsequent attempts to StartDeathCam() + return; + } + + pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission"); + + if ( !FNullEnt( pSpot ) ) + { + // at least one intermission spot in the world. + iRand = RANDOM_LONG( 0, 3 ); + + while ( iRand > 0 ) + { + pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission"); + + if ( pNewSpot ) + { + pSpot = pNewSpot; + } + + iRand--; + } + + CopyToBodyQue( pev ); + StartObserver( pSpot->v.origin, pSpot->v.v_angle ); + } + else + { + // no intermission spot. Push them up in the air, looking down at their corpse + TraceResult tr; + CopyToBodyQue( pev ); + UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); + StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); + return; + } +} + +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) +{ +// m_afPhysicsFlags |= PFLAG_OBSERVER; +// +// pev->view_ofs = g_vecZero; +// pev->angles = pev->v_angle = vecViewAngle; +// pev->fixangle = TRUE; +// pev->solid = SOLID_NOT; +// pev->takedamage = DAMAGE_NO; +// pev->movetype = MOVETYPE_NONE; +// pev->modelindex = 0; +// UTIL_SetOrigin( pev, vecPosition ); + + m_iHideHUD |= (HIDEHUD_HEALTH | HIDEHUD_WEAPONS); + m_afPhysicsFlags |= PFLAG_OBSERVER; + + pev->effects = EF_NODRAW; + pev->view_ofs = g_vecZero; + pev->angles = pev->v_angle = vecViewAngle; + pev->fixangle = TRUE; + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + pev->movetype = MOVETYPE_NONE; + UTIL_SetOrigin( pev, vecPosition ); + + ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); + ClearBits( pev->flags, FL_DUCKING ); + // pev->flags = FL_CLIENT | FL_SPECTATOR; // Should we set Spectator flag? Or is it reserver for people connecting with spectator 1? + pev->deadflag = DEAD_RESPAWNABLE; + + // Tell the physics code that this player's now in observer mode + Observer_SetMode(this->GetDefaultSpectatingMode()); + Observer_SpectatePlayer(this->GetDefaultSpectatingTarget()); + m_flNextObserverInput = 0; +} + +void CBasePlayer::StopObserver() +{ + this->pev->solid = SOLID_SLIDEBOX; + this->pev->effects = 0; + this->pev->takedamage = DAMAGE_YES; + this->pev->movetype = MOVETYPE_WALK; + ClearBits(this->m_afPhysicsFlags, PFLAG_OBSERVER); + ClearBits(this->m_afPhysicsFlags, PFLAG_DUCKING ); + ClearBits(this->pev->flags, FL_DUCKING ); + this->pev->iuser1 = this->pev->iuser2 = 0; +} + +// +// PlayerUse - handles USE keypress +// +#define PLAYER_SEARCH_RADIUS (float)64 + +void CBasePlayer::ClearKeys() +{ + // clear attack/use commands from player + this->m_afButtonPressed = 0; + this->pev->button = 0; + this->m_afButtonReleased = 0; +} + +void CBasePlayer::PlayerUse ( void ) +{ + AvHPlayer* theAvHPlayer = dynamic_cast(this); + + // Was use pressed or released? + if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) + return; + + //: Dont do this on commanders to prevent phantom use sounds. + if(theAvHPlayer->GetIsInTopDownMode()) + return; + + // Hit Use on a train? + if ( m_afButtonPressed & IN_USE ) + { + if ( m_pTank != NULL ) + { + // Stop controlling the tank + // TODO: Send HUD Update + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + return; + } + else + { + if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) + { + m_afPhysicsFlags &= ~PFLAG_ONTRAIN; + m_iTrain = TRAIN_NEW|TRAIN_OFF; + return; + } + else + { // Start controlling the train! + CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); + + if ( pTrain && !(pev->button & IN_JUMP) && FBitSet(pev->flags, FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(pev) ) + { + m_afPhysicsFlags |= PFLAG_ONTRAIN; + m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); + m_iTrain |= TRAIN_NEW; + EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM); + return; + } + } + } + } + + CBaseEntity *pObject = NULL; + CBaseEntity *pClosest = NULL; + Vector vecLOS; + float flMaxDot = VIEW_FIELD_NARROW; + float flDot; + + UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing + + + while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL) + { + + if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE)) + { + // !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that + // this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS + // when player hits the use key. How many objects can be in that area, anyway? (sjb) + vecLOS = (VecBModelOrigin( pObject->pev ) - (pev->origin + pev->view_ofs)); + + // This essentially moves the origin of the target to the corner nearest the player to test to see + // if it's "hull" is in the view cone + vecLOS = UTIL_ClampVectorToBox( vecLOS, pObject->pev->size * 0.5 ); + + flDot = DotProduct (vecLOS , gpGlobals->v_forward); + if (flDot > flMaxDot ) + {// only if the item is in front of the user + pClosest = pObject; + flMaxDot = flDot; +// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); + } +// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); + } + } + + pObject = pClosest; + + // Add los test for aliens looking at hives. + if ( pObject == NULL && AvHGetIsAlien(this->pev->iuser3) ) { + Vector vecAiming = gpGlobals->v_forward; + Vector vecSrc = this->GetGunPosition( ) + vecAiming; + Vector vecEnd = vecSrc + vecAiming*800; + + TraceResult theTraceResult; + UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, this->edict(), &theTraceResult); + + edict_t* theEntityHit = theTraceResult.pHit; + AvHHive *theHive = dynamic_cast(CBaseEntity::Instance(theEntityHit)); + if ( theHive) { + + float the2DDistance = VectorDistance2D(this->pev->origin, theHive->pev->origin); + + // Enabled state is true + if(the2DDistance <= 150.0 && (this->pev->origin < theHive->pev->origin) ) + { + pObject=theHive; + } + } + } + + // Found an object + if (pObject ) + { + //!!!UNDONE: traceline here to prevent USEing buttons through walls + int caps = pObject->ObjectCaps(); + + if ( m_afButtonPressed & IN_USE ) + { + //EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM); + const char* theSound = AvHSHUGetCommonSoundName(theAvHPlayer->GetIsAlien(), WEAPON_SOUND_SELECT); + EMIT_SOUND( ENT(pev), CHAN_ITEM, theSound, 0.4, ATTN_NORM); + } + + if ( ( (pev->button & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || + ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) + { + if ( caps & FCAP_CONTINUOUS_USE ) + m_afPhysicsFlags |= PFLAG_USING; + + pObject->Use( this, this, USE_SET, 1 ); + } + // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away + else if ( (m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use + { + pObject->Use( this, this, USE_SET, 0 ); + } + } + else + { + if ( m_afButtonPressed & IN_USE ) + { + //EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM); + const char* theSound = AvHSHUGetCommonSoundName(theAvHPlayer->GetIsAlien(), WEAPON_SOUND_DENYSELECT); + EMIT_SOUND( ENT(pev), CHAN_ITEM, theSound, 0.4, ATTN_NORM); + } + } +} + + + +void CBasePlayer::Jump() +{ + Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping + Vector vecAdjustedVelocity; + Vector vecSpot; + TraceResult tr; + + if (FBitSet(pev->flags, FL_WATERJUMP)) + return; + + if (pev->waterlevel >= 2) + { + return; + } + + // jump velocity is sqrt( height * gravity * 2) + + // If this isn't the first frame pressing the jump button, break out. + if ( !FBitSet( m_afButtonPressed, IN_JUMP ) ) + return; // don't pogo stick + + if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity ) + { + return; + } + +// many features in this function use v_forward, so makevectors now. + UTIL_MakeVectors (pev->angles); + + // ClearBits(pev->flags, FL_ONGROUND); // don't stairwalk + + SetAnimation( PLAYER_JUMP ); + + if ( m_fLongJump && + (pev->button & IN_DUCK) && + ( pev->flDuckTime > 0 ) && + pev->velocity.Length() > 50 ) + { + SetAnimation( PLAYER_SUPERJUMP ); + } + + // If you're standing on a conveyor, add it's velocity to yours (for momentum) + entvars_t *pevGround = VARS(pev->groundentity); + if ( pevGround && (pevGround->flags & FL_CONVEYOR) ) + { + pev->velocity = pev->velocity + pev->basevelocity; + } +} + + + +// This is a glorious hack to find free space when you've crouched into some solid space +// Our crouching collisions do not work correctly for some reason and this is easier +// than fixing the problem :( +void FixPlayerCrouchStuck( edict_t *pPlayer ) +{ + TraceResult trace; + + // Move up as many as 18 pixels if the player is stuck. + for ( int i = 0; i < 18; i++ ) + { + UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace ); + if ( trace.fStartSolid ) + pPlayer->v.origin.z ++; + else + break; + } +} + +void CBasePlayer::Duck( ) +{ + if (pev->button & IN_DUCK) + { + if ( m_IdealActivity != ACT_LEAP ) + { + SetAnimation( PLAYER_WALK ); + } + } +} + +// +// ID's player as such. +// +int CBasePlayer::Classify ( void ) +{ + return CLASS_PLAYER; +} + + +void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) +{ + // Positive score always adds + if ( score < 0 ) + { + if ( !bAllowNegativeScore ) + { + if ( pev->frags < 0 ) // Can't go more negative + return; + + if ( -score > pev->frags ) // Will this go negative? + { + score = -pev->frags; // Sum will be 0 + } + } + } + + pev->frags += score; +} + +void CBasePlayer::EffectivePlayerClassChanged() +{ +} + +void CBasePlayer::NeedsTeamUpdate() +{ +} + +void CBasePlayer::SendTeamUpdate() +{ +} + +void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) +{ + int index = entindex(); + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); + + if ( pPlayer && i != index ) + { + if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) + { + pPlayer->AddPoints( score, bAllowNegativeScore ); + } + } + } +} + +//Player ID +void CBasePlayer::InitStatusBar() +{ + m_flStatusBarDisappearDelay = 0; + m_SbarString1[0] = m_SbarString0[0] = 0; +} + +void CBasePlayer::UpdateStatusBar() +{ + int newSBarState[ SBAR_END ]; + char sbuf0[ SBAR_STRING_SIZE ]; + char sbuf1[ SBAR_STRING_SIZE ]; + + int i; + + for (i = 0; i < SBAR_END; ++i) + { + newSBarState[i] = -1; + } + + //memset( newSBarState, 0, sizeof(newSBarState) ); + + strcpy( sbuf0, m_SbarString0 ); + strcpy( sbuf1, m_SbarString1 ); + + // Find an ID Target + TraceResult tr; + UTIL_MakeVectors( pev->v_angle + pev->punchangle ); + Vector vecSrc = EyePosition(); + Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE); + UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr); + + bool theIsCombatMode = GetGameRules()->GetIsCombatMode(); + int theMaxEnumToSend = SBAR_ID_TARGETARMOR; + if(theIsCombatMode) + { + theMaxEnumToSend = SBAR_ID_TARGETLEVEL; + } + + if (tr.flFraction != 1.0) + { + if ( !FNullEnt( tr.pHit ) ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + + if(!pEntity) + return; + + if (pEntity->Classify() == CLASS_PLAYER ) + { + newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); + + // Name Health: X% Armor: Y% + //strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" ); + + // (health: X armor: Y) + if(!theIsCombatMode) + { + strcpy( sbuf1, "2 (health: %i2%%\n3 armor: %i3%%)" ); + } + else + { + strcpy( sbuf1, "2 (health: %i2%%\n3 armor: %i3%%\n4 level: %i4)" ); + } + + // allies and medics get to see the targets health + if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) + { + int theLevel = 1; + AvHPlayer* thePlayer = dynamic_cast(pEntity); + if(thePlayer) + { + theLevel = thePlayer->GetExperienceLevel(); + } + + //newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); + //newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. + float theHealthPercent = pEntity->pev->health/AvHPlayerUpgrade::GetMaxHealth(pEntity->pev->iuser4, (AvHUser3)pEntity->pev->iuser3, theLevel); + float theArmorPercent = pEntity->pev->armorvalue/AvHPlayerUpgrade::GetMaxArmorLevel(pEntity->pev->iuser4, (AvHUser3)pEntity->pev->iuser3); + newSBarState[ SBAR_ID_TARGETHEALTH ] = max(theHealthPercent*100+0.5f, 0.0f); + newSBarState[ SBAR_ID_TARGETARMOR ] = max(theArmorPercent*100+0.5f, 0.0f); + newSBarState[ SBAR_ID_TARGETLEVEL ] = theLevel; + } + } + else + { + bool theSuccess = false; + + // Show hive health for friendlies + if(this->pev->team == pEntity->pev->team) + { + AvHUser3 theUser3 = (AvHUser3)pEntity->pev->iuser3; + switch(theUser3) + { + // Place user3s to draw here + case AVH_USER3_HIVE: + theSuccess = true; + break; + } + } + + if(theSuccess) + { + newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); + + strcpy( sbuf1, "2 (health: %i2%%)\n" ); + + float theHealthPercentage = pEntity->pev->health/pEntity->pev->max_health; + newSBarState[ SBAR_ID_TARGETHEALTH ] = max(theHealthPercentage*100+0.5f, 0.0f); + } + } + + m_flStatusBarDisappearDelay = gpGlobals->time + 1.0; + } + else if ( m_flStatusBarDisappearDelay > gpGlobals->time ) + { + // hold the values for a short amount of time after viewing the object + newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ]; + newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ]; + newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ]; + newSBarState[ SBAR_ID_TARGETLEVEL ] = m_izSBarState[ SBAR_ID_TARGETLEVEL ]; + } + } + + BOOL bForceResend = FALSE; + + if ( strcmp( sbuf0, m_SbarString0 ) ) + { + NetMsg_StatusText( pev, 0, string(sbuf0) ); + strcpy( m_SbarString0, sbuf0 ); + + // make sure everything's resent + bForceResend = TRUE; + } + + if ( strcmp( sbuf1, m_SbarString1 ) ) + { + NetMsg_StatusText( pev, 1, string(sbuf1) ); + strcpy( m_SbarString1, sbuf1 ); + + // make sure everything's resent + bForceResend = TRUE; + } + + // Check values and send if they don't match + for (i = 1; i <= theMaxEnumToSend; i++) + { + if ( newSBarState[i] != m_izSBarState[i] || bForceResend ) + { + NetMsg_StatusValue( pev, i, newSBarState[i] ); + m_izSBarState[i] = newSBarState[i]; + } + } +} + + + + + + + + + +#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing +#define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible +#define CLIMB_SPEED_DEC 15 // climbing deceleration rate +#define CLIMB_PUNCH_X -7 // how far to 'punch' client X axis when climbing +#define CLIMB_PUNCH_Z 7 // how far to 'punch' client Z axis when climbing + +void CBasePlayer::PreThink(void) +{ + int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame + + // Debounced button codes for pressed/released + // UNDONE: Do we need auto-repeat? + m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed" + m_afButtonReleased = buttonsChanged & (~pev->button); // The ones not down are "released" + + g_pGameRules->PlayerThink( this ); + + if ( g_fGameOver ) + return; // intermission or finale + + UTIL_MakeVectors(pev->v_angle); // is this still used? + + ItemPreFrame( ); + WaterMove(); + + if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) + m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; + else + m_iHideHUD |= HIDEHUD_FLASHLIGHT; + + + // JOHN: checks if new client data (for HUD and view control) needs to be sent to the client + UpdateClientData(); + + CheckTimeBasedDamage(); + + // Observer Button Handling + if (this->IsObserver() ) + { + Observer_HandleButtons(); + pev->impulse = 0; + return; + } + + CheckSuitUpdate(); + + if (pev->deadflag >= DEAD_DYING) + { + PlayerDeathThink(); + return; + } + + // So the correct flags get sent to client asap. + // + if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) + pev->flags |= FL_ONTRAIN; + else + pev->flags &= ~FL_ONTRAIN; + + // Train speed control + if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) + { + CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); + float vel; + + if ( !pTrain ) + { + TraceResult trainTrace; + // Maybe this is on the other side of a level transition + UTIL_TraceLine( pev->origin, pev->origin + Vector(0,0,-38), ignore_monsters, ENT(pev), &trainTrace ); + + // HACKHACK - Just look for the func_tracktrain classname + if ( trainTrace.flFraction != 1.0 && trainTrace.pHit ) + pTrain = CBaseEntity::Instance( trainTrace.pHit ); + + + if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) ) + { + //ALERT( at_error, "In train mode with no train!\n" ); + m_afPhysicsFlags &= ~PFLAG_ONTRAIN; + m_iTrain = TRAIN_NEW|TRAIN_OFF; + return; + } + } + else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) ) + { + // Turn off the train if you jump, strafe, or the train controls go dead + m_afPhysicsFlags &= ~PFLAG_ONTRAIN; + m_iTrain = TRAIN_NEW|TRAIN_OFF; + return; + } + + pev->velocity = g_vecZero; + vel = 0; + if ( m_afButtonPressed & IN_FORWARD ) + { + vel = 1; + pTrain->Use( this, this, USE_SET, (float)vel ); + } + else if ( m_afButtonPressed & IN_BACK ) + { + vel = -1; + pTrain->Use( this, this, USE_SET, (float)vel ); + } + + if (vel) + { + m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); + m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; + } + + } else if (m_iTrain & TRAIN_ACTIVE) + m_iTrain = TRAIN_NEW; // turn off train + + if (pev->button & IN_JUMP) + { + // If on a ladder, jump off the ladder + // else Jump + Jump(); + } + + + // If trying to duck, already ducked, or in the process of ducking + if ((pev->button & IN_DUCK) || FBitSet(pev->flags,FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) { + if ( AvHMUGetCanDuck(this->pev->iuser3) ) + Duck(); + } + + if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) + { + m_flFallVelocity = -pev->velocity.z; + } + + // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? + + // Clear out ladder pointer + m_hEnemy = NULL; + + if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) + { + pev->velocity = g_vecZero; + } +} +/* Time based Damage works as follows: + 1) There are several types of timebased damage: + + #define DMG_PARALYZE (1 << 14) // slows affected creature down + #define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad + #define DMG_POISON (1 << 16) // blood poisioning + #define DMG_RADIATION (1 << 17) // radiation exposure + #define DMG_DROWNRECOVER (1 << 18) // drown recovery + #define DMG_ACID (1 << 19) // toxic chemicals or acid burns + #define DMG_SLOWBURN (1 << 20) // in an oven + #define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer + + 2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter, + per damage type. The counter is decremented every second, so the maximum time + an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius + of a damaging effect like fire, nervegas, radiation will continually reset the counter to max. + + 3) Every second that a tbd counter is running, the player takes damage. The damage + is determined by the type of tdb. + Paralyze - 1/2 movement rate, 30 second duration. + Nervegas - 5 points per second, 16 second duration = 80 points max dose. + Poison - 2 points per second, 25 second duration = 50 points max dose. + Radiation - 1 point per second, 50 second duration = 50 points max dose. + Drown - 5 points per second, 2 second duration. + Acid/Chemical - 5 points per second, 10 second duration = 50 points max. + Burn - 10 points per second, 2 second duration. + Freeze - 3 points per second, 10 second duration = 30 points max. + + 4) Certain actions or countermeasures counteract the damaging effects of tbds: + + Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body + - recharged by suit recharger + Air In Lungs - drowning damage is done to air in lungs first, then to body + - recharged by poking head out of water + - 10 seconds if swiming fast + Air In SCUBA - drowning damage is done to air in tanks first, then to body + - 2 minutes in tanks. Need new tank once empty. + Radiation Syringe - Each syringe full provides protection vs one radiation dosage + Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison). + Health kit - Immediate stop to acid/chemical, fire or freeze damage. + Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage. + + +*/ + +// If player is taking time based damage, continue doing damage to player - +// this simulates the effect of being poisoned, gassed, dosed with radiation etc - +// anything that continues to do damage even after the initial contact stops. +// Update all time based damage counters, and shut off any that are done. + +// The m_bitsDamageType bit MUST be set if any damage is to be taken. +// This routine will detect the initial on value of the m_bitsDamageType +// and init the appropriate counter. Only processes damage every second. + +//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage +//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval + +//#define NERVEGAS_DURATION 16 +//#define NERVEGAS_DAMAGE 5.0 + +//#define POISON_DURATION 25 +//#define POISON_DAMAGE 2.0 + +//#define RADIATION_DURATION 50 +//#define RADIATION_DAMAGE 1.0 + +//#define ACID_DURATION 10 +//#define ACID_DAMAGE 5.0 + +//#define SLOWBURN_DURATION 2 +//#define SLOWBURN_DAMAGE 1.0 + +//#define SLOWFREEZE_DURATION 1.0 +//#define SLOWFREEZE_DAMAGE 3.0 + +/* */ + + +void CBasePlayer::CheckTimeBasedDamage() +{ + int i; + BYTE bDuration = 0; + + static float gtbdPrev = 0.0; + + if (!(m_bitsDamageType & DMG_TIMEBASED)) + return; + + // only check for time based damage approx. every 2 seconds + if (abs(gpGlobals->time - m_tbdPrev) < 2.0) + return; + + m_tbdPrev = gpGlobals->time; + + for (i = 0; i < CDMG_TIMEBASED; i++) + { + // make sure bit is set for damage type + if (m_bitsDamageType & (DMG_PARALYZE << i)) + { + switch (i) + { + case itbd_Paralyze: + // UNDONE - flag movement as half-speed + bDuration = PARALYZE_DURATION; + break; + case itbd_NerveGas: +// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); + bDuration = NERVEGAS_DURATION; + break; + case itbd_Poison: + TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC); + bDuration = POISON_DURATION; + break; + case itbd_Radiation: +// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); + bDuration = RADIATION_DURATION; + break; + case itbd_DrownRecover: + // NOTE: this hack is actually used to RESTORE health + // after the player has been drowning and finally takes a breath + if (m_idrowndmg > m_idrownrestored) + { + int idif = min(m_idrowndmg - m_idrownrestored, 10); + + TakeHealth(idif, DMG_GENERIC); + m_idrownrestored += idif; + } + bDuration = 4; // get up to 5*10 = 50 points back + break; + case itbd_Acid: +// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); + bDuration = ACID_DURATION; + break; + case itbd_SlowBurn: +// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); + bDuration = SLOWBURN_DURATION; + break; + case itbd_SlowFreeze: +// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); + bDuration = SLOWFREEZE_DURATION; + break; + default: + bDuration = 0; + } + + if (m_rgbTimeBasedDamage[i]) + { + // use up an antitoxin on poison or nervegas after a few seconds of damage + if (((i == itbd_NerveGas) && (m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION)) || + ((i == itbd_Poison) && (m_rgbTimeBasedDamage[i] < POISON_DURATION))) + { + if (m_rgItems[ITEM_ANTIDOTE]) + { + m_rgbTimeBasedDamage[i] = 0; + m_rgItems[ITEM_ANTIDOTE]--; + SetSuitUpdate("!HEV_HEAL4", FALSE, SUIT_REPEAT_OK); + } + } + + + // decrement damage duration, detect when done. + if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0) + { + m_rgbTimeBasedDamage[i] = 0; + // if we're done, clear damage bits + m_bitsDamageType &= ~(DMG_PARALYZE << i); + } + } + else + // first time taking this damage type - init damage duration + m_rgbTimeBasedDamage[i] = bDuration; + } + } +} + +/* +THE POWER SUIT + +The Suit provides 3 main functions: Protection, Notification and Augmentation. +Some functions are automatic, some require power. +The player gets the suit shortly after getting off the train in C1A0 and it stays +with him for the entire game. + +Protection + + Heat/Cold + When the player enters a hot/cold area, the heating/cooling indicator on the suit + will come on and the battery will drain while the player stays in the area. + After the battery is dead, the player starts to take damage. + This feature is built into the suit and is automatically engaged. + Radiation Syringe + This will cause the player to be immune from the effects of radiation for N seconds. Single use item. + Anti-Toxin Syringe + This will cure the player from being poisoned. Single use item. + Health + Small (1st aid kits, food, etc.) + Large (boxes on walls) + Armor + The armor works using energy to create a protective field that deflects a + percentage of damage projectile and explosive attacks. After the armor has been deployed, + it will attempt to recharge itself to full capacity with the energy reserves from the battery. + It takes the armor N seconds to fully charge. + +Notification (via the HUD) + +x Health +x Ammo +x Automatic Health Care + Notifies the player when automatic healing has been engaged. +x Geiger counter + Classic Geiger counter sound and status bar at top of HUD + alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal. +x Poison + Armor + Displays the current level of armor. + +Augmentation + + Reanimation (w/adrenaline) + Causes the player to come back to life after he has been dead for 3 seconds. + Will not work if player was gibbed. Single use. + Long Jump + Used by hitting the ??? key(s). Caused the player to further than normal. + SCUBA + Used automatically after picked up and after player enters the water. + Works for N seconds. Single use. + +Things powered by the battery + + Armor + Uses N watts for every M units of damage. + Heat/Cool + Uses N watts for every second in hot/cold area. + Long Jump + Uses N watts for every jump. + Alien Cloak + Uses N watts for each use. Each use lasts M seconds. + Alien Shield + Augments armor. Reduces Armor drain by one half + +*/ + +// if in range of radiation source, ping geiger counter + +#define GEIGERDELAY 0.25 + +void CBasePlayer :: UpdateGeigerCounter( void ) +{ + BYTE range; + + // delay per update ie: don't flood net with these msgs + if (gpGlobals->time < m_flgeigerDelay) + return; + + m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; + + // send range to radition source to client + + range = (BYTE) (m_flgeigerRange / 4); + + if (range != m_igeigerRangePrev) + { + m_igeigerRangePrev = range; + NetMsg_GeigerRange( pev, range ); + } + + // reset counter and semaphore + if (!RANDOM_LONG(0,3)) + m_flgeigerRange = 1000; + +} + +/* +================ +CheckSuitUpdate + +Play suit update if it's time +================ +*/ + +#define SUITUPDATETIME 3.5 +#define SUITFIRSTUPDATETIME 0.1 + +void CBasePlayer::CheckSuitUpdate() +{ + int i; + int isentence = 0; + int isearch = m_iSuitPlayNext; + + // Ignore suit updates if no suit + if ( !(pev->weapons & (1<IsMultiplayer() ) + { + // don't bother updating HEV voice in multiplayer. + return; + } + + if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0) + { + // play a sentence off of the end of the queue + for (i = 0; i < CSUITPLAYLIST; i++) + { + if (isentence = m_rgSuitPlayList[isearch]) + break; + + if (++isearch == CSUITPLAYLIST) + isearch = 0; + } + + if (isentence) + { + m_rgSuitPlayList[isearch] = 0; + if (isentence > 0) + { + // play sentence number + + char sentence[CBSENTENCENAME_MAX+1]; + strcpy(sentence, "!"); + strcat(sentence, gszallsentencenames[isentence]); + EMIT_SOUND_SUIT(ENT(pev), sentence); + } + else + { + // play sentence group + EMIT_GROUPID_SUIT(ENT(pev), -isentence); + } + m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; + } + else + // queue is empty, don't check + m_flSuitUpdate = 0; + } +} + +// add sentence to suit playlist queue. if fgroup is true, then +// name is a sentence group (HEV_AA), otherwise name is a specific +// sentence name ie: !HEV_AA0. If iNoRepeat is specified in +// seconds, then we won't repeat playback of this word or sentence +// for at least that number of seconds. + +void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) +{ + int i; + int isentence; + int iempty = -1; + + + // Ignore suit updates if no suit + if ( !(pev->weapons & (1<IsMultiplayer() ) + { + // due to static channel design, etc. We don't play HEV sounds in multiplayer right now. + return; + } + + // if name == NULL, then clear out the queue + + if (!name) + { + for (i = 0; i < CSUITPLAYLIST; i++) + m_rgSuitPlayList[i] = 0; + return; + } + // get sentence or group number + if (!fgroup) + { + isentence = SENTENCEG_Lookup(name, NULL); + if (isentence < 0) + return; + } + else + // mark group number as negative + isentence = -SENTENCEG_GetIndex(name); + + // check norepeat list - this list lets us cancel + // the playback of words or sentences that have already + // been played within a certain time. + + for (i = 0; i < CSUITNOREPEAT; i++) + { + if (isentence == m_rgiSuitNoRepeat[i]) + { + // this sentence or group is already in + // the norepeat list + + if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time) + { + // norepeat time has expired, clear it out + m_rgiSuitNoRepeat[i] = 0; + m_rgflSuitNoRepeatTime[i] = 0.0; + iempty = i; + break; + } + else + { + // don't play, still marked as norepeat + return; + } + } + // keep track of empty slot + if (!m_rgiSuitNoRepeat[i]) + iempty = i; + } + + // sentence is not in norepeat list, save if norepeat time was given + + if (iNoRepeatTime) + { + if (iempty < 0) + iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over + m_rgiSuitNoRepeat[iempty] = isentence; + m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time; + } + + // find empty spot in queue, or overwrite last spot + + m_rgSuitPlayList[m_iSuitPlayNext++] = isentence; + if (m_iSuitPlayNext == CSUITPLAYLIST) + m_iSuitPlayNext = 0; + + if (m_flSuitUpdate <= gpGlobals->time) + { + if (m_flSuitUpdate == 0) + // play queue is empty, don't delay too long before playback + m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME; + else + m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; + } + +} + +/* +================ +CheckPowerups + +Check for turning off powerups + +GLOBALS ASSUMED SET: g_ulModelIndexPlayer +================ +*/ + static void +CheckPowerups(entvars_t *pev) +{ + if (pev->health <= 0) + return; + + //pev->modelindex = g_ulModelIndexPlayer; // don't use eyes +} + + +//========================================================= +// UpdatePlayerSound - updates the position of the player's +// reserved sound slot in the sound list. +//========================================================= +void CBasePlayer :: UpdatePlayerSound ( void ) +{ + int iBodyVolume; + int iVolume; + CSound *pSound; + + pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) ); + + if ( !pSound ) + { + ALERT ( at_console, "Client lost reserved sound!\n" ); + return; + } + + pSound->m_iType = bits_SOUND_NONE; + + // now calculate the best target volume for the sound. If the player's weapon + // is louder than his body/movement, use the weapon volume, else, use the body volume. + + if ( FBitSet ( pev->flags, FL_ONGROUND ) ) + { + iBodyVolume = pev->velocity.Length(); + + // clamp the noise that can be made by the body, in case a push trigger, + // weapon recoil, or anything shoves the player abnormally fast. + if ( iBodyVolume > 512 ) + { + iBodyVolume = 512; + } + } + else + { + iBodyVolume = 0; + } + + if ( pev->button & IN_JUMP ) + { + iBodyVolume += 100; + } + +// convert player move speed and actions into sound audible by monsters. + if ( m_iWeaponVolume > iBodyVolume ) + { + m_iTargetVolume = m_iWeaponVolume; + + // OR in the bits for COMBAT sound if the weapon is being louder than the player. + pSound->m_iType |= bits_SOUND_COMBAT; + } + else + { + m_iTargetVolume = iBodyVolume; + } + + // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while + m_iWeaponVolume -= 250 * gpGlobals->frametime; + if ( m_iWeaponVolume < 0 ) + { + iVolume = 0; + } + + + // if target volume is greater than the player sound's current volume, we paste the new volume in + // immediately. If target is less than the current volume, current volume is not set immediately to the + // lower volume, rather works itself towards target volume over time. This gives monsters a much better chance + // to hear a sound, especially if they don't listen every frame. + iVolume = pSound->m_iVolume; + + if ( m_iTargetVolume > iVolume ) + { + iVolume = m_iTargetVolume; + } + else if ( iVolume > m_iTargetVolume ) + { + iVolume -= 250 * gpGlobals->frametime; + + if ( iVolume < m_iTargetVolume ) + { + iVolume = 0; + } + } + + if ( m_fNoPlayerSound ) + { + // debugging flag, lets players move around and shoot without monsters hearing. + iVolume = 0; + } + + if ( gpGlobals->time > m_flStopExtraSoundTime ) + { + // since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two + // after actual emission to make sure it gets heard. + m_iExtraSoundTypes = 0; + } + + if ( pSound ) + { + pSound->m_vecOrigin = pev->origin; + pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes ); + pSound->m_iVolume = iVolume; + } + + // keep track of virtual muzzle flash + m_iWeaponFlash -= 256 * gpGlobals->frametime; + if (m_iWeaponFlash < 0) + m_iWeaponFlash = 0; + + //UTIL_MakeVectors ( pev->angles ); + //gpGlobals->v_forward.z = 0; + + // Below are a couple of useful little bits that make it easier to determine just how much noise the + // player is making. + // UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 ); + //ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume ); +} + + +void CBasePlayer::PostThink() +{ + if ( g_fGameOver ) + goto pt_end; // intermission or finale + + if (!IsAlive()) + goto pt_end; + + // Handle Tank controlling + if ( m_pTank != NULL ) + { // if they've moved too far from the gun, or selected a weapon, unuse the gun + if ( m_pTank->OnControls( pev ) && !pev->weaponmodel ) + { + m_pTank->Use( this, this, USE_SET, 2 ); // try fire the gun + } + else + { // they've moved off the platform + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + } + +// do weapon stuff + ItemPostFrame( ); + +// check to see if player landed hard enough to make a sound +// falling farther than half of the maximum safe distance, but not as far a max safe distance will +// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half +// of maximum safe distance will make no sound. Falling farther than max safe distance will play a +// fallpain sound, and damage will be inflicted based on how far the player fell + + if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) + { + // ALERT ( at_console, "%f\n", m_flFallVelocity ); + + if (pev->watertype == CONTENT_WATER) + { + // Did he hit the world or a non-moving entity? + // BUG - this happens all the time in water, especially when + // BUG - water has current force + // if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 ) + // EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); + } + // skulks, lerks, fades and jetpackers don't take falling damage + else if ((m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER1) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER3) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER4) && (this->pev->iuser3 != AVH_USER3_ALIEN_EMBRYO) && (!GetHasUpgrade(this->pev->iuser4, MASK_UPGRADE_7) || !(this->pev->iuser3 == AVH_USER3_MARINE_PLAYER)) ) + {// after this point, we start doing damage + + float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); + + if ( flFallDamage > pev->health ) + {//splat + // note: play on item channel because we play footstep landing on body channel + // : 243 don't play gib sound if being digested + if ( AvHGetIsAlien(this->pev->iuser3) || !GetHasUpgrade(this->pev->iuser4, MASK_DIGESTING) ) + EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM); + } + + if ( flFallDamage > 0 ) + { + TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); + pev->punchangle.x = 0; + } + } + + if ( IsAlive() ) + { + SetAnimation( PLAYER_WALK ); + } + } + + if (FBitSet(pev->flags, FL_ONGROUND)) + { + if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer()) + { + CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 ); + // ALERT( at_console, "fall %f\n", m_flFallVelocity ); + } + m_flFallVelocity = 0; + } + + // select the proper animation for the player character + if ( IsAlive() ) + { + if (!pev->velocity.x && !pev->velocity.y) + SetAnimation( PLAYER_IDLE ); + else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) + SetAnimation( PLAYER_WALK ); + else if (pev->waterlevel > 1) + SetAnimation( PLAYER_WALK ); + } + + StudioFrameAdvance( ); + CheckPowerups(pev); + + UpdatePlayerSound(); + + // Track button info so we can detect 'pressed' and 'released' buttons next frame + m_afButtonLast = pev->button; + +pt_end: + // Decay timers on weapons + // go through all of the weapons and make a list of the ones to pack + for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; + + while ( pPlayerItem ) + { + CBasePlayerWeapon *gun; + + gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); + + if ( gun && gun->UseDecrement() ) + { + gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0f ); + gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001f ); + + if ( gun->m_flTimeWeaponIdle != 1000 ) + { + gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001f ); + } + + if ( gun->pev->fuser1 != 1000 ) + { + gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001f ); + } + + // Only decrement if not flagged as NO_DECREMENT +// if ( gun->m_flPumpTime != 1000 ) + // { + // gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001f ); + // } + + } + + pPlayerItem = pPlayerItem->m_pNext; + } + } + } + + m_flNextAttack -= gpGlobals->frametime; + if ( m_flNextAttack < -0.001 ) + m_flNextAttack = -0.001; + + if ( m_flNextAmmoBurn != 1000 ) + { + m_flNextAmmoBurn -= gpGlobals->frametime; + + if ( m_flNextAmmoBurn < -0.001 ) + m_flNextAmmoBurn = -0.001; + } + + if ( m_flAmmoStartCharge != 1000 ) + { + m_flAmmoStartCharge -= gpGlobals->frametime; + + if ( m_flAmmoStartCharge < -0.001 ) + m_flAmmoStartCharge = -0.001; + } +} + + +// checks if the spot is clear of players +BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) +{ + CBaseEntity *ent = NULL; + + if ( !pSpot->IsTriggered( pPlayer ) ) + { + return FALSE; + } + + AvHPlayer* thePlayer = dynamic_cast(pPlayer); + ASSERT(thePlayer); + + Vector theMinSize; + Vector theMaxSize; + thePlayer->GetSize(theMinSize, theMaxSize); + + int theOffset = AvHMUGetOriginOffsetForUser3(AvHUser3(thePlayer->pev->iuser3)); + Vector theOriginToSpawn = pSpot->pev->origin; + theOriginToSpawn.z += theOffset; + + if(!AvHSUGetIsEnoughRoomForHull(theOriginToSpawn, AvHMUGetHull(false, thePlayer->pev->iuser3), thePlayer->edict())) + return FALSE; + + //while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) + + // Assumes UTIL_FindEntityInSphere doesn't take size of other object into account. Players should be 2*HULL0_MAXX from each other, add another for safety + while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 3*HULL0_MAXX)) != NULL ) + { + // if ent is a client, don't spawn on 'em (but dead players don't block) + if ( ent->IsPlayer() && (ent != pPlayer) && ent->IsAlive() ) + return FALSE; + + } + + return TRUE; +} + +BOOL CBasePlayer::IsAlive() const +{ + // Take into account spectators + return (pev->deadflag == DEAD_NO) && pev->health > 0; +} + +BOOL CBasePlayer::IsAlive(bool inIncludeSpectating) const +{ + // Take into account spectators + BOOL theIsAlive = this->IsAlive(); + if(inIncludeSpectating) + { + CBaseEntity* theSpectatingEntity = this->GetSpectatingEntity(); + if(theSpectatingEntity) + { + theIsAlive = theSpectatingEntity->IsAlive(); + } + } + + return theIsAlive; +} + +CBaseEntity* CBasePlayer::GetSpectatingEntity() const +{ + CBaseEntity* theSpectatingEntity = NULL; + + if(this->pev && this->pev->iuser1 && this->pev->iuser2) + { + int theEntityIndex = this->pev->iuser2; + theSpectatingEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theEntityIndex)); + } + + return theSpectatingEntity; +} + +void CBasePlayer::Spawn( void ) +{ + pev->classname = MAKE_STRING("player"); +// pev->health = 100; +// pev->armorvalue = 0; +// pev->max_health = pev->health; + pev->takedamage = DAMAGE_AIM; + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_WALK; + pev->flags &= FL_PROXY; // keep proxy flag sey by engine + pev->flags |= FL_CLIENT; + pev->air_finished = gpGlobals->time + 12; + pev->dmg = 2; // initial water damage + pev->effects = 0; + pev->deadflag = DEAD_NO; + pev->dmg_take = 0; + pev->dmg_save = 0; + pev->friction = 1.0; + pev->gravity = 1.0; + m_bitsHUDDamage = -1; + m_bitsDamageType = 0; + m_afPhysicsFlags = 0; + m_fLongJump = FALSE;// no longjump module. + + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); + + pev->fov = m_iFOV = 0;// init field of view. + m_iClientFOV = -1; // make sure fov reset is sent + + m_flNextDecalTime = 0;// let this player decal as soon as he spawns. + + m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations + // are recieved by all clients + + m_flTimeStepSound = 0; + m_iStepLeft = 0; + m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. + + m_bloodColor = BLOOD_COLOR_RED; + m_flNextAttack = UTIL_WeaponTimeBase(); + StartSneaking(); + +// m_iFlashBattery = 99; +// m_flFlashLightTime = 1; // force first message + +// dont let uninitialized value here hurt the player + m_flFallVelocity = 0; + + GetGameRules()->SetDefaultPlayerTeam( this ); + edict_t* theSpawnPoint = GetGameRules()->SelectSpawnPoint( this ); + ASSERT(theSpawnPoint); + this->InitPlayerFromSpawn(theSpawnPoint); + + //AvHPlayer* thePlayer = dynamic_cast(this); + //char* thePlayerModel = thePlayer->GetPlayerModel(); + //SET_MODEL(ENT(pev), thePlayerModel); + SET_MODEL(ENT(pev), "models/player.mdl"); + + g_ulModelIndexPlayer = pev->modelindex; + //pev->sequence = LookupActivity( ACT_IDLE ); + pev->sequence = LookupSequence("idle1"); + + if ( FBitSet(pev->flags, FL_DUCKING) ) + UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); + else + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + + pev->view_ofs = VEC_VIEW; + Precache(); + m_HackedGunPos = Vector( 0, 32, 0 ); + + if ( m_iPlayerSound == SOUNDLIST_EMPTY ) + { + ALERT ( at_console, "Couldn't alloc player sound slot!\n" ); + } + + m_fNoPlayerSound = FALSE;// normal sound behavior. + + m_pLastItem = NULL; + m_pLastItemName = 0; // Added by mmcguire. + + m_fInitHUD = TRUE; + m_iClientHideHUD = -1; // force this to be recalculated + m_fWeapon = FALSE; + m_pClientActiveItem = NULL; + m_iClientBattery = -1; + + // reset all ammo values to 0 + for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) + { + m_rgAmmo[i] = 0; + m_rgAmmoLast[i] = 0; // client ammo values also have to be reset (the death hud clear messages does on the client side) + } + + m_lastx = m_lasty = 0; + + m_flNextChatTime = gpGlobals->time; + + g_pGameRules->PlayerSpawn( this ); +} + + +void CBasePlayer :: Precache( void ) +{ + // in the event that the player JUST spawned, and the level node graph + // was loaded, fix all of the node graph pointers before the game starts. + + // !!!BUGBUG - now that we have multiplayer, this needs to be moved! + if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet ) + { + if ( !WorldGraph.FSetGraphPointers() ) + { + ALERT ( at_console, "**Graph pointers were not set!\n"); + } + else + { + ALERT ( at_console, "**Graph Pointers Set!\n" ); + } + } + + // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific) + // because they need to precache before any clients have connected + + Net_InitializeMessages(); + + // init geiger counter vars during spawn and each time + // we cross a level transition + + m_flgeigerRange = 1000; + m_igeigerRangePrev = 1000; + + m_bitsDamageType = 0; + m_bitsHUDDamage = -1; + + m_iClientBattery = -1; + + m_iTrain = TRAIN_NEW; + + m_iUpdateTime = 5; // won't update for 1/2 a second + + if ( gInitHUD ) + m_fInitHUD = TRUE; +} + + +int CBasePlayer::Save( CSave &save ) +{ + if ( !CBaseMonster::Save(save) ) + return 0; + + return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); +} + + +// +// Marks everything as new so the player will resend this to the hud. +// +void CBasePlayer::RenewItems(void) +{ + +} + +int CBasePlayer::Restore( CRestore &restore ) +{ + if ( !CBaseMonster::Restore(restore) ) + return 0; + + int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); + + SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; + // landmark isn't present. + if ( !pSaveData->fUseLandmark ) + { + ALERT( at_console, "No Landmark:%s\n", pSaveData->szLandmarkName ); + + // default to normal spawn + //edict_t* pentSpawnSpot = EntSelectSpawnPoint( this ); + ASSERT(FALSE); + //pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); + //pev->angles = VARS(pentSpawnSpot)->angles; + } + pev->v_angle.z = 0; // Clear out roll + pev->angles = pev->v_angle; + + pev->fixangle = TRUE; // turn this way immediately + +// Copied from spawn() for now + m_bloodColor = BLOOD_COLOR_RED; + + g_ulModelIndexPlayer = pev->modelindex; + + if ( FBitSet(pev->flags, FL_DUCKING) ) + { + // Use the crouch HACK + //FixPlayerCrouchStuck( edict() ); + // Don't need to do this with new player prediction code. + UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); + } + else + { + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + } + + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); + + if ( m_fLongJump ) + { + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" ); + } + else + { + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); + } + + RenewItems(); + + // HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it + // as just a counter. Ideally, this needs its own variable that's saved as a plain float. + // Barring that, we clear it out here instead of using the incorrect restored time value. + m_flNextAttack = UTIL_WeaponTimeBase(); + + return status; +} + + + +void CBasePlayer::SelectNextItem( int iItem ) +{ + CBasePlayerItem *pItem; + + pItem = m_rgpPlayerItems[ iItem ]; + + if (!pItem) + return; + + if (pItem == m_pActiveItem) + { + // select the next one in the chain + pItem = m_pActiveItem->m_pNext; + if (! pItem) + { + return; + } + + CBasePlayerItem *pLast; + pLast = pItem; + while (pLast->m_pNext) + pLast = pLast->m_pNext; + + // relink chain + pLast->m_pNext = m_pActiveItem; + m_pActiveItem->m_pNext = NULL; + m_rgpPlayerItems[ iItem ] = pItem; + } + + ResetAutoaim( ); + + // FIX, this needs to queue them up and delay + if (m_pActiveItem) + { + m_pActiveItem->Holster( ); + } + + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + m_pActiveItem->UpdateItemInfo( ); + } +} + +void CBasePlayer::SelectItem(const char *pstr) +{ + if (!pstr) + return; + + CBasePlayerItem *pItem = NULL; + + for (int i = 0; i < MAX_ITEM_TYPES; i++) + { + if (m_rgpPlayerItems[i]) + { + pItem = m_rgpPlayerItems[i]; + + while (pItem) + { + if (FClassnameIs(pItem->pev, pstr)) + break; + pItem = pItem->m_pNext; + } + } + + if (pItem) + break; + } + + if (!pItem) + return; + + + if ((pItem == m_pActiveItem) || (m_pActiveItem != NULL && !m_pActiveItem->CanHolster())) + return; + + ResetAutoaim( ); + + // FIX, this needs to queue them up and delay + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + m_pLastItem = m_pActiveItem; + + if (m_pLastItem) + { + m_pLastItemName = m_pLastItem->pev->classname; + } + else + { + m_pLastItemName = 0; + } + + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + m_pActiveItem->UpdateItemInfo( ); + } +} + +//note this should no longer be called, and asserts if used +void CBasePlayer::SelectLastItem(void) +{ + if (!m_pLastItem) + { + + // Try the last item name. + + if (m_pLastItemName != 0) + { + for (int i = 0; i < MAX_ITEM_TYPES; i++) + { + CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; + while (theCurrentItem) + { + if(FClassnameIs(theCurrentItem->pev, STRING(m_pLastItemName))) + { + m_pLastItem = theCurrentItem; + break; + } + theCurrentItem = theCurrentItem->m_pNext; + } + } + } + + } + + if (!m_pLastItem) + { + return; + } + + this->SelectItem(STRING(m_pLastItem->pev->classname)); //replaced copy-and-paste from SelectItem with actual SelectItem call +} + +BOOL CBasePlayer::HasItem(CBasePlayerItem* inWeapon) +{ + // Return true if we have a weapon of this type + bool theHasWeapon = false; + + for(int i = 0; (i < MAX_ITEM_TYPES) && !theHasWeapon; i++) + { + CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; + while(theCurrentItem && !theHasWeapon) + { + if(FClassnameIs(theCurrentItem->pev, STRING(inWeapon->pev->classname))) + { + theHasWeapon = true; + } + theCurrentItem = theCurrentItem->m_pNext; + } + } + + return theHasWeapon; +} + +BOOL CBasePlayer::HasItemWithFlag(int inFlag, CBasePlayerItem*& outItem) +{ + // Return true if we have a weapon of this type + bool theHasWeaponWithFlag = false; + + for(int i = 0; (i < MAX_ITEM_TYPES) && !theHasWeaponWithFlag; i++) + { + CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; + while(theCurrentItem && !theHasWeaponWithFlag) + { + ItemInfo theItemInfo; + theCurrentItem->GetItemInfo(&theItemInfo); + + int theFlags = theItemInfo.iFlags; + if(theFlags & inFlag) + { + theHasWeaponWithFlag = true; + outItem = theCurrentItem; + } + theCurrentItem = theCurrentItem->m_pNext; + } + } + + return theHasWeaponWithFlag; +} + +//============================================== +// HasWeapons - do I have any weapons at all? +//============================================== +BOOL CBasePlayer::HasWeapons( void ) +{ + int i; + + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + return TRUE; + } + } + + return FALSE; +} + +void CBasePlayer::SelectPrevItem( int iItem ) +{ +} + + +char *CBasePlayer::TeamID( void ) +{ + if ( pev == NULL ) // Not fully connected yet + return ""; + + // return their team name + return m_szTeamName; +} + +void CBasePlayer::SetTeamID(const char* inTeamID) +{ + strncpy(this->m_szTeamName, inTeamID, TEAM_NAME_LENGTH); +} + +//============================================== +// !!!UNDONE:ultra temporary SprayCan entity to apply +// decal frame at a time. For PreAlpha CD +//============================================== +class CSprayCan : public CBaseEntity +{ +public: + void Spawn ( entvars_t *pevOwner ); + void Think( void ); + + virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } +}; + +void CSprayCan::Spawn ( entvars_t *pevOwner ) +{ + pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); + pev->angles = pevOwner->v_angle; + pev->owner = ENT(pevOwner); + pev->frame = 0; + + pev->nextthink = gpGlobals->time + 0.1; + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM); +} + +void CSprayCan::Think( void ) +{ + TraceResult tr; + int playernum; + int nFrames; + CBasePlayer *pPlayer; + + pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner); + + if (pPlayer) + nFrames = pPlayer->GetCustomDecalFrames(); + else + nFrames = -1; + + playernum = ENTINDEX(pev->owner); + + // ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames); + + UTIL_MakeVectors(pev->angles); + UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); + + // No customization present. + if (nFrames == -1) + { + UTIL_DecalTrace( &tr, DECAL_LAMBDA6 ); + UTIL_Remove( this ); + } + else + { + UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE ); + // Just painted last custom frame. + if ( pev->frame++ >= (nFrames - 1)) + UTIL_Remove( this ); + } + + pev->nextthink = gpGlobals->time + 0.1; +} + +class CBloodSplat : public CBaseEntity +{ +public: + void Spawn ( entvars_t *pevOwner ); + void Spray ( void ); +}; + +void CBloodSplat::Spawn ( entvars_t *pevOwner ) +{ + pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); + pev->angles = pevOwner->v_angle; + pev->owner = ENT(pevOwner); + + SetThink ( &CBloodSplat::Spray ); + pev->nextthink = gpGlobals->time + 0.1; +} + +void CBloodSplat::Spray ( void ) +{ + TraceResult tr; + + if ( g_Language != LANGUAGE_GERMAN ) + { + UTIL_MakeVectors(pev->angles); + UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); + + UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); + } + SetThink ( &CBloodSplat::SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; +} + +//============================================== + + + +void CBasePlayer::GiveNamedItem( const char *pszName, bool inSendMessage ) +{ + edict_t *pent; + + int istr = MAKE_STRING(pszName); + + pent = CREATE_NAMED_ENTITY(istr); + if ( FNullEnt( pent ) ) + { + ALERT ( at_console, "NULL Ent in GiveNamedItem!\n" ); + return; + } + VARS( pent )->origin = pev->origin; + pent->v.spawnflags |= SF_NORESPAWN; + + DispatchSpawn( pent ); + DispatchTouch( pent, ENT( pev ) ); + + if(inSendMessage) + { + CBaseEntity* theEntity = CBaseEntity::Instance(ENT(pent)); + ASSERT(theEntity); + CBasePlayerWeapon* theWeapon = dynamic_cast(theEntity); + //ASSERT(theWeapon); + if(theWeapon) + { + int theWeaponID = theWeapon->m_iId; + NetMsg_WeapPickup( pev, theWeaponID ); + } + } +} + + + +CBaseEntity *FindEntityForward( CBaseEntity *pMe ) +{ + TraceResult tr; + + UTIL_MakeVectors(pMe->pev->v_angle); + UTIL_TraceLine(pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 8192,dont_ignore_monsters, pMe->edict(), &tr ); + if ( tr.flFraction != 1.0 && !FNullEnt( tr.pHit) ) + { + CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); + return pHit; + } + return NULL; +} + + +BOOL CBasePlayer :: FlashlightIsOn( void ) +{ + return FBitSet(pev->effects, EF_DIMLIGHT); +} + +const float kFlashlightVolume = .3f; + +void CBasePlayer :: FlashlightTurnOn( void ) +{ + if ( !g_pGameRules->FAllowFlashlight() ) + { + return; + } + + if ( (pev->weapons & (1<effects, EF_DIMLIGHT); + + /*MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); + WRITE_BYTE(1); + WRITE_BYTE(m_iFlashBattery); + MESSAGE_END(); + + m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time;*/ + + } +} + + +void CBasePlayer :: FlashlightTurnOff( void ) +{ + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, kFlashlightVolume, ATTN_NORM, 0, PITCH_NORM ); + ClearBits(pev->effects, EF_DIMLIGHT); + + /*MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); + WRITE_BYTE(0); + WRITE_BYTE(m_iFlashBattery); + MESSAGE_END(); + + m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time;*/ + +} + +/* +=============== +ForceClientDllUpdate + +When recording a demo, we need to have the server tell us the entire client state +so that the client side .dll can behave correctly. +Reset stuff so that the state is transmitted. +=============== +*/ +void CBasePlayer :: ForceClientDllUpdate( void ) +{ + m_iClientHealth = -1; + m_iClientBattery = -1; + m_iTrain |= TRAIN_NEW; // Force new train message. + m_fWeapon = FALSE; // Force weapon send + m_fKnownItem = FALSE; // Force weaponinit messages. + m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message + + // Now force all the necessary messages + // to be sent. + UpdateClientData(); + // m_fWeapon = TRUE; // Force weapon send +} + +/* +============ +ImpulseCommands +============ +*/ +extern float g_flWeaponCheat; + +void CBasePlayer::ImpulseCommands( ) +{ + TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs + + int iImpulse = (int)pev->impulse; + switch (iImpulse) + { + case IMPULSE_FLASHLIGHT: + // temporary flashlight for level designers + if ( FlashlightIsOn() ) + { + FlashlightTurnOff(); + } + else + { + FlashlightTurnOn(); + } + break; + + case IMPULSE_SPRAYPAINT:// paint decal + + if ( gpGlobals->time < m_flNextDecalTime ) + { + // too early! + break; + } + + UTIL_MakeVectors(pev->v_angle); + UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr); + + if ( tr.flFraction != 1.0 ) + {// line hit something, so paint a decal + m_flNextDecalTime = gpGlobals->time + decalfrequency.value; + CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); + pCan->Spawn( pev ); + } + + break; +// HLDSDK 2.3 update +// case IMPULSE_DEMORECORD: // Demo recording, update client dll specific data again. +// ForceClientDllUpdate(); +// break; + default: + // check all of the cheat impulse commands now + CheatImpulseCommands( iImpulse ); + break; + } + + pev->impulse = 0; +} + +//========================================================= +//========================================================= +void CBasePlayer::CheatImpulseCommands( int iImpulse ) +{ +} + +// +// Add a weapon to the player (Item == Weapon == Selectable Object) +// +int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) +{ + CBasePlayerItem *pInsert; + + pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; + ItemInfo ii; + pItem->GetItemInfo(&ii); + + if ( pItem->iItemSlot() == 1 || ii.iId == AVH_WEAPON_MINE || ii.iId == AVH_WEAPON_WELDER) { + this->EffectivePlayerClassChanged(); + } + while (pInsert) + { + if (FClassnameIs( pInsert->pev, STRING( pItem->pev->classname) )) + { + if (pItem->AddDuplicate( pInsert )) + { + g_pGameRules->PlayerGotWeapon ( this, pItem ); + pItem->CheckRespawn(); + + // ugly hack to update clip w/o an update clip message + pInsert->UpdateItemInfo( ); + if (m_pActiveItem) + m_pActiveItem->UpdateItemInfo( ); + + pItem->Kill( ); + } + else if (gEvilImpulse101) + { + // FIXME: remove anyway for deathmatch testing + pItem->Kill( ); + } + return FALSE; + } + pInsert = pInsert->m_pNext; + } + + if (pItem->AddToPlayer( this )) + { + g_pGameRules->PlayerGotWeapon ( this, pItem ); + pItem->CheckRespawn(); + + pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()]; + m_rgpPlayerItems[pItem->iItemSlot()] = pItem; + + // should we switch to this item? + if ( g_pGameRules->FShouldSwitchWeapon( this, pItem ) ) + { + SwitchWeapon( pItem ); + } + + return TRUE; + } + else if (gEvilImpulse101) + { + // FIXME: remove anyway for deathmatch testing + pItem->Kill( ); + } + return FALSE; +} + + + +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) +{ + + if (m_pActiveItem == pItem) + { + + ResetAutoaim( ); + pItem->Holster( ); + pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. + pItem->SetThink( NULL ); + m_pActiveItem = NULL; + pev->viewmodel = 0; + pev->weaponmodel = 0; + + } + else if ( m_pLastItem == pItem ) + m_pLastItem = NULL; + + AvHBasePlayerWeapon* theWeapon = dynamic_cast(pItem); + if(theWeapon) + { + ItemInfo theInfo; + theWeapon->GetItemInfo(&theInfo); + int theID = theInfo.iId; + this->pev->weapons &= ~(1<iItemSlot()]; + + if (pPrev == pItem) + { + m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext; + return TRUE; + } + else + { + while (pPrev && pPrev->m_pNext != pItem) + { + pPrev = pPrev->m_pNext; + } + if (pPrev) + { + pPrev->m_pNext = pItem->m_pNext; + return TRUE; + } + } + return FALSE; +} + + +// +// Returns the unique ID for the ammo, or -1 if error +// +int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) +{ + if ( !szName ) + { + // no ammo. + return -1; + } + + if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) + { + // game rules say I can't have any more of this ammo type. + return -1; + } + + int i = 0; + + i = GetAmmoIndex( szName ); + + if ( i < 0 || i >= MAX_AMMO_SLOTS ) + return -1; + + int iAdd = min( iCount, iMax - m_rgAmmo[i] ); + if ( iAdd < 1 ) + return i; + + m_rgAmmo[ i ] += iAdd; + + + // Send the message that ammo has been picked up + NetMsg_AmmoPickup( pev, GetAmmoIndex(szName), iAdd ); + + TabulateAmmo(); + + return i; +} + + +/* +============ +ItemPreFrame + +Called every frame by the player PreThink +============ +*/ +void CBasePlayer::ItemPreFrame() +{ + if ( m_flNextAttack > 0 ) + { + return; + } + + if (!m_pActiveItem) + return; + + m_pActiveItem->ItemPreFrame( ); +} + + +/* +============ +ItemPostFrame + +Called every frame by the player PostThink +============ +*/ +void CBasePlayer::ItemPostFrame() +{ + static int fInSelect = FALSE; + + // check if the player is using a tank + if ( m_pTank != NULL ) + return; + + ImpulseCommands(); + + if ( m_flNextAttack > 0 ) + { + return; + } + + if (!m_pActiveItem) + return; + + // Only update weapon once game has started (no firing before then) + //if(GetGameRules()->GetGameStarted()) + //{ + this->m_pActiveItem->ItemPostFrame( ); + //} +} + +int CBasePlayer::AmmoInventory( int iAmmoIndex ) +{ + if (iAmmoIndex == -1) + { + return -1; + } + + return m_rgAmmo[ iAmmoIndex ]; +} + +int CBasePlayer::GetAmmoIndex(const char *psz) +{ + int i; + + if (!psz) + return -1; + + for (i = 1; i < MAX_AMMO_SLOTS; i++) + { + if ( !CBasePlayerItem::AmmoInfoArray[i].pszName ) + continue; + + if (stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0) + return i; + } + + return -1; +} + +int CBasePlayer::GetMaxWalkSpeed(void) const +{ + return 220; +} + +// Called from UpdateClientData +// makes sure the client has all the necessary ammo info, if values have changed +void CBasePlayer::SendAmmoUpdate(void) +{ + int theAmmoToSend[MAX_AMMO_SLOTS]; + memcpy(&theAmmoToSend, &this->m_rgAmmo, MAX_AMMO_SLOTS*sizeof(int)); + +// if(this->pev->iuser1 == OBS_IN_EYE) +// { +// CBasePlayer* theEntity = NULL; +// if(AvHSUGetEntityFromIndex(this->pev->iuser2, theEntity)) +// { +// memcpy(&theAmmoToSend, &theEntity->m_rgAmmo, MAX_AMMO_SLOTS*sizeof(int)); +// } +// } + + for (int i=0; i < MAX_AMMO_SLOTS;i++) + { + if (theAmmoToSend[i] != m_rgAmmoLast[i]) + { + m_rgAmmoLast[i] = theAmmoToSend[i]; + + // TODO: Fix me! + //ASSERT( m_rgAmmo[i] >= 0 ); + //ASSERT( m_rgAmmo[i] < 255 ); + if((theAmmoToSend[i] >= 0) && (theAmmoToSend[i] < 255)) + { + // send "Ammo" update message + NetMsg_AmmoX( pev, i, max( min( theAmmoToSend[i], 254 ), 0 ) ); + } + } + } +} + +/* +========================================================= + UpdateClientData + +resends any changed player HUD info to the client. +Called every frame by PlayerPreThink +Also called at start of demo recording and playback by +ForceClientDllUpdate to ensure the demo gets messages +reflecting all of the HUD state info. +========================================================= +*/ +void CBasePlayer :: UpdateClientData( void ) +{ + CBasePlayer* thePlayerToUseForWeaponUpdates = this; +// if(this->pev->iuser1 == OBS_IN_EYE) +// { +// CBasePlayer* theSpectatingPlayer = NULL; +// if(AvHSUGetEntityFromIndex(this->pev->iuser2, theSpectatingPlayer)) +// { +// thePlayerToUseForWeaponUpdates = theSpectatingPlayer; +// } +// } + + if (m_fInitHUD) + { + m_fInitHUD = FALSE; + gInitHUD = FALSE; + + NetMsg_ResetHUD( pev ); + + if ( !m_fGameHUDInitialized ) + { + NetMsg_InitHUD( pev ); + + g_pGameRules->InitHUD( this ); + m_fGameHUDInitialized = TRUE; + if ( g_pGameRules->IsMultiplayer() ) + { + FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); + } + } + FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); + + InitStatusBar(); + } + + if ( m_iHideHUD != m_iClientHideHUD ) + { + NetMsg_HideWeapon( pev, m_iHideHUD ); + m_iClientHideHUD = m_iHideHUD; + } + + if ( m_iFOV != m_iClientFOV ) + { + NetMsg_SetFOV( pev, m_iFOV ); + // cache FOV change at end of function, so weapon updates can see that FOV has changed + } + + // HACKHACK -- send the message to display the game title + if (gDisplayTitle) + { + NetMsg_ShowGameTitle( pev ); + gDisplayTitle = 0; + } + + if ((int)pev->health != m_iClientHealth) //: this cast to int is important, otherwise we spam the message, this is just a quick and easy fix. + { + NetMsg_Health( pev, max( pev->health, 0.0f ) ); + m_iClientHealth = (int)pev->health; + } + + if ((int)pev->armorvalue != m_iClientBattery) + { + NetMsg_Battery( pev, (int)pev->armorvalue ); + m_iClientBattery = (int)pev->armorvalue; + } + + if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType) + { + // Comes from inside me if not set + Vector damageOrigin = pev->origin; + // send "damage" message + // causes screen to flash, and pain compass to show direction of damage + edict_t *other = pev->dmg_inflictor; + if ( other ) + { + CBaseEntity *pEntity = CBaseEntity::Instance(other); + if ( pEntity ) + damageOrigin = pEntity->Center(); + } + + // only send down damage type that have hud art + int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; + + float origin[] = { damageOrigin.x, damageOrigin.y, damageOrigin.z }; + NetMsg_Damage( pev, pev->dmg_save, pev->dmg_take, 0, origin ); + + pev->dmg_take = 0; + pev->dmg_save = 0; + m_bitsHUDDamage = m_bitsDamageType; + + // Clear off non-time-based damage indicators + m_bitsDamageType &= DMG_TIMEBASED; + } + + if (m_iTrain & TRAIN_NEW) + { + // send "health" update message + NetMsg_Train( pev, m_iTrain & 0xF ); + m_iTrain &= ~TRAIN_NEW; + } + + // + // New Weapon? + // + + bool forceCurWeaponUpdate = false; + + if (!m_fKnownItem) + { + + m_fKnownItem = TRUE; + + // WeaponInit Message + // byte = # of weapons + // + // for each weapon: + // byte name str length (not including null) + // bytes... name + // byte Ammo Type + // byte Ammo2 Type + // byte bucket + // byte bucket pos + // byte flags + // ???? Icons + + // Send ALL the weapon info now + this->SendWeaponUpdate(); + + // : HACK force an full curweapon update after each bunch of weaponlists sent + forceCurWeaponUpdate = true; + // : + } + + + SendAmmoUpdate(); + + // Update all the items + for ( int i = 0; i < MAX_ITEM_TYPES; i++ ) + { + if (forceCurWeaponUpdate == true) + m_fWeapon = FALSE; + if ( thePlayerToUseForWeaponUpdates->m_rgpPlayerItems[i] ) // each item updates it's successors + thePlayerToUseForWeaponUpdates->m_rgpPlayerItems[i]->UpdateClientData( thePlayerToUseForWeaponUpdates ); + } + if (forceCurWeaponUpdate == true) + m_fWeapon = TRUE; + + // Cache and client weapon change + m_pClientActiveItem = thePlayerToUseForWeaponUpdates->m_pActiveItem; + m_iClientFOV = thePlayerToUseForWeaponUpdates->m_iFOV; + + // Update Status Bar if we're playing + AvHPlayer* thePlayer = dynamic_cast(this); + if(thePlayer && (thePlayer->GetPlayMode() == PLAYMODE_PLAYING)) + { + if ( m_flNextSBarUpdateTime < gpGlobals->time ) + { + UpdateStatusBar(); + m_flNextSBarUpdateTime = gpGlobals->time + 0.2; + } + } +} + +void CBasePlayer::SendWeaponUpdate() +{ + int i; + + for (i = 0; i < MAX_WEAPONS; i++) + { + ItemInfo& II = CBasePlayerItem::ItemInfoArray[i]; + + if ( !II.iId ) + continue; + + const char *pszName; + if (!II.pszName) + pszName = "Empty"; + else + pszName = II.pszName; + + WeaponList weapon; + weapon.weapon_name = pszName; + weapon.ammo1_type = GetAmmoIndex(II.pszAmmo1); + weapon.ammo2_type = GetAmmoIndex(II.pszAmmo2); + weapon.ammo1_max_amnt = II.iMaxAmmo1; + weapon.ammo2_max_amnt = II.iMaxAmmo2; + weapon.bucket = II.iSlot; + weapon.bucket_pos = II.iPosition; + weapon.bit_index = II.iId; + weapon.flags = II.iFlags; + + NetMsg_WeaponList( pev, weapon ); + } + +} + +//========================================================= +// FBecomeProne - Overridden for the player to set the proper +// physics flags when a barnacle grabs player. +//========================================================= +BOOL CBasePlayer :: FBecomeProne ( void ) +{ + m_afPhysicsFlags |= PFLAG_ONBARNACLE; + return TRUE; +} + +//========================================================= +// BarnacleVictimBitten - bad name for a function that is called +// by Barnacle victims when the barnacle pulls their head +// into its mouth. For the player, just die. +//========================================================= +void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) +{ + TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); +} + +//========================================================= +// BarnacleVictimReleased - overridden for player who has +// physics flags concerns. +//========================================================= +void CBasePlayer :: BarnacleVictimReleased ( void ) +{ + m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; +} + + +//========================================================= +// Illumination +// return player light level plus virtual muzzle flash +//========================================================= +int CBasePlayer :: Illumination( void ) +{ + int iIllum = CBaseEntity::Illumination( ); + + iIllum += m_iWeaponFlash; + if (iIllum > 255) + return 255; + return iIllum; +} + + +void CBasePlayer :: EnableControl(BOOL fControl) +{ + if (!fControl) + pev->flags |= FL_FROZEN; + else + pev->flags &= ~FL_FROZEN; + +} + + +#define DOT_1DEGREE 0.9998476951564 +#define DOT_2DEGREE 0.9993908270191 +#define DOT_3DEGREE 0.9986295347546 +#define DOT_4DEGREE 0.9975640502598 +#define DOT_5DEGREE 0.9961946980917 +#define DOT_6DEGREE 0.9945218953683 +#define DOT_7DEGREE 0.9925461516413 +#define DOT_8DEGREE 0.9902680687416 +#define DOT_9DEGREE 0.9876883405951 +#define DOT_10DEGREE 0.9848077530122 +#define DOT_15DEGREE 0.9659258262891 +#define DOT_20DEGREE 0.9396926207859 +#define DOT_25DEGREE 0.9063077870367 + +//========================================================= +// Autoaim +// set crosshair position to point to enemey +//========================================================= +Vector CBasePlayer :: GetAutoaimVector( float flDelta ) +{ + if (g_iSkillLevel == SKILL_HARD) + { + UTIL_MakeVectors( pev->v_angle + pev->punchangle ); + return gpGlobals->v_forward; + } + + Vector vecSrc = GetGunPosition( ); + float flDist = 8192; + + // always use non-sticky autoaim + // UNDONE: use sever variable to chose! + if (1 || g_iSkillLevel == SKILL_MEDIUM) + { + m_vecAutoAim = Vector( 0, 0, 0 ); + // flDelta *= 0.5; + } + + BOOL m_fOldTargeting = m_fOnTarget; + Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta ); + + // update ontarget if changed + if ( !g_pGameRules->AllowAutoTargetCrosshair() ) + m_fOnTarget = 0; + else if (m_fOldTargeting != m_fOnTarget) + { + m_pActiveItem->UpdateItemInfo( ); + } + + if (angles.x > 180) + angles.x -= 360; + if (angles.x < -180) + angles.x += 360; + if (angles.y > 180) + angles.y -= 360; + if (angles.y < -180) + angles.y += 360; + + if (angles.x > 25) + angles.x = 25; + if (angles.x < -25) + angles.x = -25; + if (angles.y > 12) + angles.y = 12; + if (angles.y < -12) + angles.y = -12; + + + // always use non-sticky autoaim + // UNDONE: use sever variable to chose! + if (0 || g_iSkillLevel == SKILL_EASY) + { + m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33; + } + else + { + m_vecAutoAim = angles * 0.9; + } + + // m_vecAutoAim = m_vecAutoAim * 0.99; + + // Don't send across network if sv_aim is 0 + if ( g_psv_aim->value != 0 ) + { + if ( m_vecAutoAim.x != m_lastx || + m_vecAutoAim.y != m_lasty ) + { + SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); + + m_lastx = m_vecAutoAim.x; + m_lasty = m_vecAutoAim.y; + } + } + + // ALERT( at_console, "%f %f\n", angles.x, angles.y ); + + UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); + return gpGlobals->v_forward; +} + + +Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) +{ + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + CBaseEntity *pEntity; + float bestdot; + Vector bestdir; + edict_t *bestent; + TraceResult tr; + + if ( g_psv_aim->value == 0 ) + { + m_fOnTarget = FALSE; + return g_vecZero; + } + + UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); + + // try all possible entities + bestdir = gpGlobals->v_forward; + bestdot = flDelta; // +- 10 degrees + bestent = NULL; + + m_fOnTarget = FALSE; + + UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr ); + + + if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO) + { + // don't look through water + if (!((pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3) + || (pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0))) + { + if (tr.pHit->v.takedamage == DAMAGE_AIM) + m_fOnTarget = TRUE; + + return m_vecAutoAim; + } + } + + for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + { + Vector center; + Vector dir; + float dot; + + if ( pEdict->free ) // Not in use + continue; + + if (pEdict->v.takedamage != DAMAGE_AIM) + continue; + if (pEdict == edict()) + continue; +// if (pev->team > 0 && pEdict->v.team == pev->team) +// continue; // don't aim at teammate + if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) + continue; + + pEntity = Instance( pEdict ); + if (pEntity == NULL) + continue; + + if (!pEntity->IsAlive()) + continue; + + // don't look through water + if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) + || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) + continue; + + center = pEntity->BodyTarget( vecSrc ); + + dir = (center - vecSrc).Normalize( ); + + // make sure it's in front of the player + if (DotProduct (dir, gpGlobals->v_forward ) < 0) + continue; + + dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) + + fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5; + + // tweek for distance + dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist); + + if (dot > bestdot) + continue; // to far to turn + + UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr ); + if (tr.flFraction != 1.0 && tr.pHit != pEdict) + { + // ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) ); + continue; + } + + // don't shoot at friends + if (IRelationship( pEntity ) < 0) + { + if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch()) + // ALERT( at_console, "friend\n"); + continue; + } + + // can shoot at this one + bestdot = dot; + bestent = pEdict; + bestdir = dir; + } + + if (bestent) + { + bestdir = UTIL_VecToAngles (bestdir); + bestdir.x = -bestdir.x; + bestdir = bestdir - pev->v_angle - pev->punchangle; + + if (bestent->v.takedamage == DAMAGE_AIM) + m_fOnTarget = TRUE; + + return bestdir; + } + + return Vector( 0, 0, 0 ); +} + + +void CBasePlayer :: ResetAutoaim( ) +{ + if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) + { + m_vecAutoAim = Vector( 0, 0, 0 ); + SET_CROSSHAIRANGLE( edict(), 0, 0 ); + } + m_fOnTarget = FALSE; +} + +/* +============= +SetCustomDecalFrames + + UNDONE: Determine real frame limit, 8 is a placeholder. + Note: -1 means no custom frames present. +============= +*/ +void CBasePlayer :: SetCustomDecalFrames( int nFrames ) +{ + if (nFrames > 0 && + nFrames < 8) + m_nCustomSprayFrames = nFrames; + else + m_nCustomSprayFrames = -1; +} + +/* +============= +GetCustomDecalFrames + + Returns the # of custom frames this player's custom clan logo contains. +============= +*/ +int CBasePlayer :: GetCustomDecalFrames( void ) +{ + return m_nCustomSprayFrames; +} + + +//========================================================= +// DropPlayerItem - drop the named item, or if no name, +// the active item. +//========================================================= +void CBasePlayer::DropPlayerItem ( char *pszItemName ) +{ + if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) ) + { + // no dropping in single player. + return; + } + + if ( !strlen( pszItemName ) ) + { + // if this string has no length, the client didn't type a name! + // assume player wants to drop the active item. + // make the string null to make future operations in this function easier + pszItemName = NULL; + } + + CBasePlayerItem *pWeapon; + int i; + + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + pWeapon = m_rgpPlayerItems[ i ]; + + while ( pWeapon ) + { + if ( pszItemName ) + { + // try to match by name. + const char* theWeaponClassName = STRING( pWeapon->pev->classname ); + if ( !strcmp( pszItemName, theWeaponClassName) ) + { + // match! + break; + } + } + else + { + // trying to drop active item + if ( pWeapon == m_pActiveItem ) + { + // active item! + break; + } + } + + pWeapon = pWeapon->m_pNext; + } + + + // if we land here with a valid pWeapon pointer, that's because we found the + // item we want to drop and hit a BREAK; pWeapon is the item. + if ( pWeapon ) + { + g_pGameRules->GetNextBestWeapon( this, pWeapon ); + + UTIL_MakeVectors ( pev->angles ); + + pev->weapons &= ~(1<m_iId);// take item off hud + + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() ); + pWeaponBox->pev->angles.x = 0; + pWeaponBox->pev->angles.z = 0; + pWeaponBox->PackWeapon( pWeapon ); + pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; + + // drop half of the ammo for this weapon. + int iAmmoIndex; + + iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ??? + + if ( iAmmoIndex != -1 ) + { + // this weapon weapon uses ammo, so pack an appropriate amount. + if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE ) + { + // pack up all the ammo, this weapon is its own ammo type + pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] ); + m_rgAmmo[ iAmmoIndex ] = 0; + + } + else + { + // pack half of the ammo + pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] / 2 ); + m_rgAmmo[ iAmmoIndex ] /= 2; + } + + } + + return;// we're done, so stop searching with the FOR loop. + } + } +} + +//========================================================= +// HasPlayerItem Does the player already have this item? +//========================================================= +BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) +{ + CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; + + while (pItem) + { + if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) + { + return TRUE; + } + pItem = pItem->m_pNext; + } + + return FALSE; +} + +//========================================================= +// HasNamedPlayerItem Does the player already have this item? +//========================================================= +CBasePlayerItem* CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) +{ + CBasePlayerItem *pReturn = NULL; + CBasePlayerItem *pItem = NULL; + int i; + + for ( i = 0 ; (i < MAX_ITEM_TYPES) && !pReturn ; i++ ) + { + pItem = m_rgpPlayerItems[ i ]; + + while (pItem && !pReturn) + { + if ( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) ) + { + pReturn = pItem; + } + pItem = pItem->m_pNext; + } + } + + return pReturn; +} + +//========================================================= +// +//========================================================= +BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) +{ + if ( !pWeapon->CanDeploy() ) + { + return FALSE; + } + + ResetAutoaim( ); + + if (m_pActiveItem) + { + m_pActiveItem->Holster( ); + } + + m_pActiveItem = pWeapon; + pWeapon->Deploy( ); + + return TRUE; +} + +//========================================================= +// Dead HEV suit prop +//========================================================= +class CDeadHEV : public CBaseMonster +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_HUMAN_MILITARY; } + + void KeyValue( KeyValueData *pkvd ); + + int m_iPose;// which sequence to display -- temporary, don't need to save + static char *m_szPoses[4]; +}; + +char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" }; + +void CDeadHEV::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "pose")) + { + m_iPose = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseMonster::KeyValue( pkvd ); +} + +LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ); + +//========================================================= +// ********** DeadHEV SPAWN ********** +//========================================================= +void CDeadHEV :: Spawn( void ) +{ + PRECACHE_MODEL("models/player.mdl"); + SET_MODEL(ENT(pev), "models/player.mdl"); + + pev->effects = 0; + pev->yaw_speed = 8; + pev->sequence = 0; + pev->body = 1; + m_bloodColor = BLOOD_COLOR_RED; + + pev->sequence = LookupSequence( m_szPoses[m_iPose] ); + + if (pev->sequence == -1) + { + ALERT ( at_console, "Dead hevsuit with bad pose\n" ); + pev->sequence = 0; + pev->effects = EF_BRIGHTFIELD; + } + + // Corpses have less health + pev->health = 8; + + MonsterInitDead(); +} + + +class CStripWeapons : public CPointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +private: +}; + +LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ); + +void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CBasePlayer *pPlayer = NULL; + + if ( pActivator && pActivator->IsPlayer() ) + { + pPlayer = (CBasePlayer *)pActivator; + } + else if ( !g_pGameRules->IsDeathmatch() ) + { + pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); + } + + if ( pPlayer ) + pPlayer->RemoveAllItems( FALSE ); +} + + +class CRevertSaved : public CPointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT MessageThink( void ); + void EXPORT LoadThink( void ); + void KeyValue( KeyValueData *pkvd ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + inline float Duration( void ) { return pev->dmg_take; } + inline float HoldTime( void ) { return pev->dmg_save; } + inline float MessageTime( void ) { return m_messageTime; } + inline float LoadTime( void ) { return m_loadTime; } + + inline void SetDuration( float duration ) { pev->dmg_take = duration; } + inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } + inline void SetMessageTime( float time ) { m_messageTime = time; } + inline void SetLoadTime( float time ) { m_loadTime = time; } + +private: + float m_messageTime; + float m_loadTime; +}; + +LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ); + +TYPEDESCRIPTION CRevertSaved::m_SaveData[] = +{ + DEFINE_FIELD( CRevertSaved, m_messageTime, FIELD_FLOAT ), // These are not actual times, but durations, so save as floats + DEFINE_FIELD( CRevertSaved, m_loadTime, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ); + +void CRevertSaved :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "duration")) + { + SetDuration( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "holdtime")) + { + SetHoldTime( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "messagetime")) + { + SetMessageTime( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "loadtime")) + { + SetLoadTime( atof(pkvd->szValue) ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); + pev->nextthink = gpGlobals->time + MessageTime(); + SetThink( &CRevertSaved::MessageThink ); +} + + +void CRevertSaved :: MessageThink( void ) +{ + UTIL_ShowMessageAll( STRING(pev->message) ); + float nextThink = LoadTime() - MessageTime(); + if ( nextThink > 0 ) + { + pev->nextthink = gpGlobals->time + nextThink; + SetThink( &CRevertSaved::LoadThink ); + } + else + LoadThink(); +} + + +void CRevertSaved :: LoadThink( void ) +{ + if ( !gpGlobals->deathmatch ) + { + SERVER_COMMAND("reload\n"); + } +} + + +//========================================================= +// Multiplayer intermission spots. +//========================================================= +class CInfoIntermission:public CPointEntity +{ + void Spawn( void ); + void Think( void ); +}; + +void CInfoIntermission::Spawn( void ) +{ + UTIL_SetOrigin( pev, pev->origin ); + pev->solid = SOLID_NOT; + pev->effects = EF_NODRAW; + pev->v_angle = g_vecZero; + + pev->nextthink = gpGlobals->time + 2;// let targets spawn! + +} + +void CInfoIntermission::Think ( void ) +{ + edict_t *pTarget; + + // find my target + pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); + + if ( !FNullEnt(pTarget) ) + { + pev->v_angle = UTIL_VecToAngles( (pTarget->v.origin - pev->origin).Normalize() ); + pev->v_angle.x = -pev->v_angle.x; + } +} + +LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ); + diff --git a/main/source/dlls/player.cpp~ b/main/source/dlls/player.cpp~ deleted file mode 100644 index df46e6b1..00000000 --- a/main/source/dlls/player.cpp~ +++ /dev/null @@ -1,5047 +0,0 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// -//===== player.cpp ======================================================== -// -// functions dealing with the player -// -// -// $Workfile: player.cpp $ -// $Date: 2002/11/22 21:12:55 $ -// -//------------------------------------------------------------------------------- -// $Log: player.cpp,v $ -// Revision 1.39 2002/11/22 21:12:55 Flayra -// - Added DMG_IGNOREARMOR flag for players (used for ending game quickly) -// - NULL checks for when owner of turret is removed after owner leaves team -// - Send deploy weapon switch to player, when "lastinv" is executed -// -// Revision 1.38 2002/11/15 19:09:40 Flayra -// - Reworked network metering to be easily toggleable -// -// Revision 1.37 2002/11/12 02:18:41 Flayra -// - Beginning of HLTV changes -// -// Revision 1.36 2002/10/24 21:18:23 Flayra -// - Major networking optimizations, to prevent overlflows after 20+ players on game reset -// -// Revision 1.35 2002/10/18 22:15:13 Flayra -// - Fixed problem where level5 gets stuck with redemption -// -// Revision 1.34 2002/10/16 00:40:39 Flayra -// - Fixed bug where player couldn't switch to next player while observing -// - Propagate health as short for larger aliens -// - Propagate auth mask -// -// Revision 1.33 2002/10/03 18:26:03 Flayra -// - Removed HL "flatline" sound on death -// -// Revision 1.32 2002/09/23 22:03:50 Flayra -// - Fixed problem where anims weren't playing properly in ready room -// - Fixed problem where gestation model anims were playing before model was updated -// -// Revision 1.31 2002/08/31 18:01:18 Flayra -// - Work at VALVe -// -// Revision 1.30 2002/08/09 00:17:03 Flayra -// - Allow moveleft and moveright to change targets, allow players to have only one primary weapon -// -// Revision 1.29 2002/07/23 16:48:21 Flayra -// - Refactored duplicate spawn code -// -// Revision 1.28 2002/07/10 14:36:09 Flayra -// - Fixed bug that caused "Battery" message to be sent every tick (this never showed up in HL because they never had a float armor value?) -// -// Revision 1.27 2002/07/08 16:31:39 Flayra -// - Level 1 doesn't make falling splat sound, dead players shouldn't block spawn points, replaced impulse hard-codes with constants -// -//=============================================================================== -#include -#include "extdll.h" -#include "util.h" - -#include "cbase.h" -#include "player.h" -#include "trains.h" -#include "nodes.h" -#include "weapons.h" -#include "soundent.h" -#include "monsters.h" -#include "../engine/shake.h" -#include "decals.h" -#include "gamerules.h" -#include "../mod/AvHEntities.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHPlayerUpgrade.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHSharedUtil.h" -#include "../mod/AvHServerVariables.h" -#include "../mod/AvHHulls.h" -#include "../mod/AvHMovementUtil.h" -#include "game.h" -#include "../common/hltv.h" -#include "../mod/AvHNetworkMessages.h" -#include "util/MathUtil.h" - -// #define DUCKFIX - -// Allow assignment within conditional -#pragma warning (disable: 4706) - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL BOOL g_fDrawLines; -int gEvilImpulse101; -extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; - - -BOOL gInitHUD = TRUE; - -extern void CopyToBodyQue(entvars_t* pev); -extern void respawn(entvars_t *pev, BOOL fCopyCorpse); -extern Vector VecBModelOrigin(entvars_t *pevBModel ); -//extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); - -// the world node graph -extern CGraph WorldGraph; - -#define TRAIN_ACTIVE 0x80 -#define TRAIN_NEW 0xc0 -#define TRAIN_OFF 0x00 -#define TRAIN_NEUTRAL 0x01 -#define TRAIN_SLOW 0x02 -#define TRAIN_MEDIUM 0x03 -#define TRAIN_FAST 0x04 -#define TRAIN_BACK 0x05 - -#define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes -#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) - -// Global Savedata for player -TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = -{ - DEFINE_FIELD( CBasePlayer, m_afButtonLast, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonPressed, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonReleased, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgItems, FIELD_INTEGER, MAX_ITEMS ), - DEFINE_FIELD( CBasePlayer, m_afPhysicsFlags, FIELD_INTEGER ), - - DEFINE_FIELD( CBasePlayer, m_flTimeStepSound, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flSwimTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flDuckTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flWallJumpTime, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_flSuitUpdate, FIELD_TIME ), - DEFINE_ARRAY( CBasePlayer, m_rgSuitPlayList, FIELD_INTEGER, CSUITPLAYLIST ), - DEFINE_FIELD( CBasePlayer, m_iSuitPlayNext, FIELD_INTEGER ), - DEFINE_ARRAY( CBasePlayer, m_rgiSuitNoRepeat, FIELD_INTEGER, CSUITNOREPEAT ), - DEFINE_ARRAY( CBasePlayer, m_rgflSuitNoRepeatTime, FIELD_TIME, CSUITNOREPEAT ), - DEFINE_FIELD( CBasePlayer, m_lastDamageAmount, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CBasePlayer, m_pActiveItem, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayer, m_pLastItem, FIELD_CLASSPTR ), - - DEFINE_ARRAY( CBasePlayer, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_FIELD( CBasePlayer, m_idrowndmg, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_idrownrestored, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_tSneaking, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_iTrain, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_bitsHUDDamage, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_flFallVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, m_iTargetVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iExtraSoundTypes, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponFlash, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_fLongJump, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_fInitHUD, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_tbdPrev, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ), - DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ), -}; - -void CBasePlayer :: Pain( void ) -{ - float flRndSound;//sound randomizer - - flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); -} - -/* - * - */ -Vector VecVelocityForDamage(float flDamage) -{ - Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - - if (flDamage > -50) - vec = vec * 0.7; - else if (flDamage > -200) - vec = vec * 2; - else - vec = vec * 10; - - return vec; -} - -#if 0 /* -static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) -{ - edict_t *pentNew = CREATE_ENTITY(); - entvars_t *pevNew = VARS(pentNew); - - pevNew->origin = pev->origin; - SET_MODEL(ENT(pevNew), szGibModel); - UTIL_SetSize(pevNew, g_vecZero, g_vecZero); - - pevNew->velocity = VecVelocityForDamage(flDamage); - pevNew->movetype = MOVETYPE_BOUNCE; - pevNew->solid = SOLID_NOT; - pevNew->avelocity.x = RANDOM_FLOAT(0,600); - pevNew->avelocity.y = RANDOM_FLOAT(0,600); - pevNew->avelocity.z = RANDOM_FLOAT(0,600); - CHANGE_METHOD(ENT(pevNew), em_think, SUB_Remove); - pevNew->ltime = gpGlobals->time; - pevNew->nextthink = gpGlobals->time + RANDOM_FLOAT(10,20); - pevNew->frame = 0; - pevNew->flags = 0; -} - - -static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) -{ - SET_MODEL(ENT(pev), szGibModel); - pev->frame = 0; - pev->nextthink = -1; - pev->movetype = MOVETYPE_BOUNCE; - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT; - pev->view_ofs = Vector(0,0,8); - UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,56)); - pev->velocity = VecVelocityForDamage(flDamage); - pev->avelocity = RANDOM_FLOAT(-1,1) * Vector(0,600,0); - pev->origin.z -= 24; - ClearBits(pev->flags, FL_ONGROUND); -} - - -*/ -#endif - -int TrainSpeed(int iSpeed, int iMax) -{ - float fSpeed, fMax; - int iRet = 0; - - fMax = (float)iMax; - fSpeed = iSpeed; - - fSpeed = fSpeed/fMax; - - if (iSpeed < 0) - iRet = TRAIN_BACK; - else if (iSpeed == 0) - iRet = TRAIN_NEUTRAL; - else if (fSpeed < 0.33) - iRet = TRAIN_SLOW; - else if (fSpeed < 0.66) - iRet = TRAIN_MEDIUM; - else - iRet = TRAIN_FAST; - - return iRet; -} - -void CBasePlayer :: DeathSound( void ) -{ - // water death sounds - /* - if (pev->waterlevel == 3) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); - return; - } - */ - - // temporarily using pain sounds for death sounds - switch (RANDOM_LONG(1,5)) - { - case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - break; - case 2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - break; - case 3: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); - break; - } - - // play one of the suit death alarms - //EMIT_GROUPNAME_SUIT(ENT(pev), "HEV_DEAD"); -} - -// override takehealth -// bitsDamageType indicates type of damage healed. - -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) -{ - return CBaseMonster :: TakeHealth (flHealth, bitsDamageType); - -} - -Vector CBasePlayer :: GetGunPosition( ) -{ -// UTIL_MakeVectors(pev->v_angle); -// m_HackedGunPos = pev->view_ofs; - Vector origin; - - origin = pev->origin + pev->view_ofs; - - return origin; -} - -//========================================================= -// TraceAttack -//========================================================= -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= gSkillData.plrHead; - break; - case HITGROUP_CHEST: - flDamage *= gSkillData.plrChest; - break; - case HITGROUP_STOMACH: - flDamage *= gSkillData.plrStomach; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= gSkillData.plrArm; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= gSkillData.plrLeg; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -void CBasePlayer::SpawnClientSideCorpse() -{ -// char *infobuffer = g_engfuncs.pfnGetInfoKeyBuffer( edict() ); -// char *pModel = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); -// -// MESSAGE_BEGIN( MSG_ALL, gmsgSendCorpse ); -// WRITE_STRING( pModel ); -// WRITE_LONG ( pev->origin.x * 128.0); -// WRITE_LONG ( pev->origin.y * 128.0); -// WRITE_LONG ( pev->origin.z * 128.0); -// WRITE_COORD ( pev->angles.x ); -// WRITE_COORD ( pev->angles.y ); -// WRITE_COORD ( pev->angles.z ); -// WRITE_LONG ( (pev->animtime - gpGlobals->time) * 100.0f ); -// WRITE_BYTE ( pev->sequence ); -// WRITE_BYTE ( pev->body ); -// MESSAGE_END(); -} - -/* - Take some damage. - NOTE: each call to TakeDamage with bitsDamageType set to a time-based damage - type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation - etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC. -*/ - -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // have suit diagnose the problem - ie: report damage type - int bitsDamage = bitsDamageType; - int ffound = TRUE; - int fmajor; - int fcritical; - int fTookDamage; - int ftrivial; - //float flRatio; - //float flBonus; - float flHealthPrev = pev->health; - - //flBonus = AvHPlayerUpgrade::GetArmorBonus(this->pev->iuser4); - //flRatio = AvHPlayerUpgrade::GetArmorRatio(this->pev->iuser4); - -// if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) -// { -// // blasts damage armor more. -// flBonus *= 2; -// } - - // Already dead - if ( !IsAlive() ) - return 0; - // go take the damage first - - - CBaseEntity *pAttacker = NULL; - - if(pevAttacker) - { - pAttacker = CBaseEntity::Instance(pevAttacker); - } - - if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) - { - // Refuse the damage - return 0; - } - - // keep track of amount of damage last sustained - m_lastDamageAmount = flDamage; - - if(!(bitsDamageType & DMG_IGNOREARMOR)) - { - flDamage = AvHPlayerUpgrade::CalculateDamageLessArmor((AvHUser3)this->pev->iuser3, this->pev->iuser4, flDamage, this->pev->armorvalue, bitsDamageType, GetGameRules()->GetNumActiveHives((AvHTeamNumber)this->pev->team)); - } - else - { - int a = 0; - } - - // Armor. -// if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage! -// { -// float flNew = flDamage * flRatio; -// -// float flArmor; -// -// flArmor = (flDamage - flNew) * flBonus; -// -// // Does this use more armor than we have? -// if (flArmor > pev->armorvalue) -// { -// flArmor = pev->armorvalue; -// flArmor *= (1/flBonus); -// flNew = flDamage - flArmor; -// pev->armorvalue = 0; -// } -// else -// pev->armorvalue -= flArmor; -// -// flDamage = flNew; -// } - - fTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); - - // reset damage time countdown for each type of time based damage player just sustained - - { - for (int i = 0; i < CDMG_TIMEBASED; i++) - if (bitsDamageType & (DMG_PARALYZE << i)) - m_rgbTimeBasedDamage[i] = 0; - } - - // tell director about it - MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); - WRITE_BYTE(DIRECTOR_MESSAGE_SIZE); - WRITE_BYTE ( DRC_CMD_EVENT ); // take damage event - WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity - WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity - WRITE_LONG( 5 ); // eventflags (priority and flags) - MESSAGE_END(); - - - // how bad is it, doc? - - ftrivial = (pev->health > 75 || m_lastDamageAmount < 5); - fmajor = (m_lastDamageAmount > 25); - fcritical = (pev->health < 30); - - // handle all bits set in this damage message, - // let the suit give player the diagnosis - - // UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash ) - - // UNDONE: still need to record damage and heal messages for the following types - - // DMG_BURN - // DMG_FREEZE - // DMG_BLAST - // DMG_SHOCK - - m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client - m_bitsHUDDamage = -1; // make sure the damage bits get resent - - while (fTookDamage && (!ftrivial || (bitsDamage & DMG_TIMEBASED)) && ffound && bitsDamage) - { - ffound = FALSE; - - if (bitsDamage & DMG_CLUB) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - bitsDamage &= ~DMG_CLUB; - ffound = TRUE; - } - if (bitsDamage & (DMG_FALL | DMG_CRUSH)) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC); // major fracture - else - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - - bitsDamage &= ~(DMG_FALL | DMG_CRUSH); - ffound = TRUE; - } - - if (bitsDamage & DMG_BULLET) - { - if (m_lastDamageAmount > 5) - SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC); // blood loss detected - //else - // SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_BULLET; - ffound = TRUE; - } - - if (bitsDamage & DMG_SLASH) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC); // major laceration - else - SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_SLASH; - ffound = TRUE; - } - - if (bitsDamage & DMG_SONIC) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN); // internal bleeding - bitsDamage &= ~DMG_SONIC; - ffound = TRUE; - } - - if (bitsDamage & (DMG_POISON | DMG_PARALYZE)) - { - SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN); // blood toxins detected - bitsDamage &= ~(DMG_POISON | DMG_PARALYZE); - ffound = TRUE; - } - - if (bitsDamage & DMG_ACID) - { - SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected - bitsDamage &= ~DMG_ACID; - ffound = TRUE; - } - - if (bitsDamage & DMG_NERVEGAS) - { - SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN); // biohazard detected - bitsDamage &= ~DMG_NERVEGAS; - ffound = TRUE; - } - - if (bitsDamage & DMG_RADIATION) - { - SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected - bitsDamage &= ~DMG_RADIATION; - ffound = TRUE; - } - if (bitsDamage & DMG_SHOCK) - { - bitsDamage &= ~DMG_SHOCK; - ffound = TRUE; - } - } - - pev->punchangle.x = -2; - - if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) - { - // first time we take major damage... - // turn automedic on if not on - SetSuitUpdate("!HEV_MED1", FALSE, SUIT_NEXT_IN_30MIN); // automedic on - - // give morphine shot if not given recently - SetSuitUpdate("!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN); // morphine shot - } - - if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75) - { - - // already took major damage, now it's critical... - if (pev->health < 6) - SetSuitUpdate("!HEV_HLTH3", FALSE, SUIT_NEXT_IN_10MIN); // near death - else if (pev->health < 20) - SetSuitUpdate("!HEV_HLTH2", FALSE, SUIT_NEXT_IN_10MIN); // health critical - - // give critical health warnings - if (!RANDOM_LONG(0,3) && flHealthPrev < 50) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - - // if we're taking time based damage, warn about its continuing effects - if (fTookDamage && (bitsDamageType & DMG_TIMEBASED) && flHealthPrev < 75) - { - if (flHealthPrev < 50) - { - if (!RANDOM_LONG(0,3)) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - else - SetSuitUpdate("!HEV_HLTH1", FALSE, SUIT_NEXT_IN_10MIN); // health dropping - } - - //return fTookDamage; - int theReturnValue = 0; - if(fTookDamage) - { - theReturnValue = flDamage; - } - return theReturnValue; -} - -//========================================================= -// PackDeadPlayerItems - call this when a player dies to -// pack up the appropriate weapons and ammo items, and to -// destroy anything that shouldn't be packed. -// -// This is pretty brute force :( -//========================================================= -void CBasePlayer::PackDeadPlayerItems( void ) -{ - int iWeaponRules; - int iAmmoRules; - int i; - CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have? - int iPackAmmo[ MAX_AMMO_SLOTS + 1]; - int iPW = 0;// index into packweapons array - int iPA = 0;// index into packammo array - - memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) ); - memset(iPackAmmo, -1, sizeof(iPackAmmo) ); - - // get the game rules - iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); - iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); - - if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) - { - // nothing to pack. Remove the weapons and return. Don't call create on the box! - RemoveAllItems( TRUE ); - return; - } - -// go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - switch( iWeaponRules ) - { - case GR_PLR_DROP_GUN_ACTIVE: - if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) - { - // this is the active item. Pack it. - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - } - break; - - case GR_PLR_DROP_GUN_ALL: - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - break; - - default: - break; - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - -// now go through ammo and make a list of which types to pack. - if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) - { - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( m_rgAmmo[ i ] > 0 ) - { - // player has some ammo of this type. - switch ( iAmmoRules ) - { - case GR_PLR_DROP_AMMO_ALL: - iPackAmmo[ iPA++ ] = i; - break; - - case GR_PLR_DROP_AMMO_ACTIVE: - if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) - { - // this is the primary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) - { - // this is the secondary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - break; - - default: - break; - } - } - } - } - -// create a box to pack the stuff into. - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, edict() ); - - pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. - pWeaponBox->pev->angles.z = 0; - - pWeaponBox->SetThink( &CWeaponBox::Kill ); - pWeaponBox->pev->nextthink = gpGlobals->time + 120; - -// back these two lists up to their first elements - iPA = 0; - iPW = 0; - -// pack the ammo - while ( iPackAmmo[ iPA ] != -1 ) - { - // Only pack items with ammo - const char* theAmmoName = CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName; - if(theAmmoName && theAmmoName != "") - pWeaponBox->PackAmmo( MAKE_STRING(theAmmoName), m_rgAmmo[ iPackAmmo[ iPA ] ] ); - - iPA++; - } - -// now pack all of the items in the lists - while ( rgpPackWeapons[ iPW ] ) - { - // weapon unhooked from the player. Pack it into der box. - pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); - - iPW++; - } - - pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. - - RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. -} - -void CBasePlayer::DestroyAllItems(BOOL removeSuit) -{ - if (m_pActiveItem) - { - ResetAutoaim( ); - m_pActiveItem->Holster( ); - m_pActiveItem = NULL; - } - - m_pLastItem = NULL; - - int i; - CBasePlayerItem *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) - { - pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->DestroyItem(); - m_pActiveItem = pPendingItem; - } - m_rgpPlayerItems[i] = NULL; - } - m_pActiveItem = NULL; - - pev->viewmodel = 0; - pev->weaponmodel = 0; - - if ( removeSuit ) - pev->weapons = 0; - else - pev->weapons &= ~WEAPON_ALLWEAPONS; - - for ( i = 0; i < MAX_AMMO_SLOTS;i++) - m_rgAmmo[i] = 0; - - // send Selected Weapon Message to our client - NetMsg_CurWeapon( pev, 0, 0, 0 ); -} - -void CBasePlayer::RemoveAllItems( BOOL removeSuit ) -{ - if (m_pActiveItem) - { - ResetAutoaim( ); - m_pActiveItem->Holster( ); - m_pActiveItem = NULL; - } - - m_pLastItem = NULL; - - int i; - CBasePlayerItem *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) - { - pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->Drop( ); - m_pActiveItem = pPendingItem; - } - m_rgpPlayerItems[i] = NULL; - } - m_pActiveItem = NULL; - - pev->viewmodel = 0; - pev->weaponmodel = 0; - - if ( removeSuit ) - pev->weapons = 0; - else - pev->weapons &= ~WEAPON_ALLWEAPONS; - - for ( i = 0; i < MAX_AMMO_SLOTS;i++) - m_rgAmmo[i] = 0; - -// UpdateClientData(); -// // send Selected Weapon Message to our client -// MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); -// WRITE_BYTE(0); -// WRITE_BYTE(0); -// WRITE_BYTE(0); -// MESSAGE_END(); -} - -/* - * GLOBALS ASSUMED SET: g_ulModelIndexPlayer - * - * ENTITY_METHOD(PlayerDie) - */ -entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage inflictor for death messages. - // Better solution: Add as parameter to all Killed() functions. - -void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) -{ - CSound *pSound; - - // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); - - GetGameRules()->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); - - if ( m_pTank != NULL ) - { - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - - // this client isn't going to be thinking for a while, so reset the sound until they respawn - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) ); - { - if ( pSound ) - { - pSound->Reset(); - } - } - - SetAnimation( PLAYER_DIE ); - - m_iRespawnFrames = 0; - - //pev->modelindex = g_ulModelIndexPlayer; // don't use eyes - - // Clear buttons held down on death, fixes bug where player can't switch observer targets - m_afButtonLast = 0; - - pev->deadflag = DEAD_DYING; - pev->movetype = MOVETYPE_TOSS; - ClearBits( pev->flags, FL_ONGROUND ); - if (pev->velocity.z < 10) - pev->velocity.z += RANDOM_FLOAT(0,300); - - // clear out the suit message cache so we don't keep chattering - SetSuitUpdate(NULL, FALSE, 0); - - // send "health" update message to zero - m_iClientHealth = 0; - NetMsg_Health( pev, m_iClientHealth ); - - // Tell Ammo Hud that the player is dead - NetMsg_CurWeapon( pev, 0, 0xFF, 0xFF ); - - // reset FOV - pev->fov = m_iFOV = m_iClientFOV = 0; - NetMsg_SetFOV( pev, 0 ); - - - // UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12 - // UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE ); - - if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) - { - pev->solid = SOLID_NOT; - GibMonster(); // This clears pev->model - pev->effects |= EF_NODRAW; - return; - } - - DeathSound(); - - pev->angles.x = 0; - pev->angles.z = 0; - - SetThink(&CBasePlayer::PlayerDeathThink); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CBasePlayer::Suicide(void) -{ - AvHPlayer* thePlayer = dynamic_cast(this); - - ASSERT(thePlayer); - - if(thePlayer && thePlayer->GetUsedKilled())//: prevent exploitation of "kill" command. - return; - - // have the player kill themself - float theKillDelay = ns_cvar_float(&avh_killdelay); - - #ifdef DEBUG - #ifndef AVH_EXTERNAL_BUILD - theKillDelay = 0; - #endif - #endif - - if(theKillDelay > 0.0f) - { - char theMessage[256]; - sprintf(theMessage, "Suiciding in %.1f seconds...\n", theKillDelay); - UTIL_SayText(theMessage, this, ENTINDEX(this->edict())); - } - - thePlayer->SetUsedKilled(true); - SetThink(&CBasePlayer::SuicideThink); - this->pev->nextthink = gpGlobals->time + theKillDelay; -} - -void CBasePlayer::SuicideThink(void) -{ - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && thePlayer->GetCanBeAffectedByEnemies()) - { - this->pev->health = 0; - this->Killed(this->pev, GIB_NEVER); - } -} - -// Set the activity based on an event or current state -void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) -{ - int animDesired; - int gaitDesired; - float speed; - char szAnim[64]; - bool theFoundAnim = true; - int theDebugAnimations = BALANCE_VAR(kDebugAnimations); - bool reloadAnim = false; - - // Make sure the model is set, as gestating models aren't set before the animation starts playing - AvHPlayer* theAvHPlayer = dynamic_cast(this); - ASSERT(theAvHPlayer); - theAvHPlayer->SetModelFromState(); - - speed = pev->velocity.Length2D(); - - if (pev->flags & FL_FROZEN) - { - speed = 0; - playerAnim = PLAYER_IDLE; - } - - switch (playerAnim) - { - case PLAYER_JUMP: - m_IdealActivity = ACT_HOP; - break; - - case PLAYER_SUPERJUMP: - m_IdealActivity = ACT_LEAP; - break; - - case PLAYER_DIE: - m_IdealActivity = ACT_DIESIMPLE; - m_IdealActivity = GetDeathActivity( ); - - //this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - //animDesired = LookupSequence( szAnim ); - //if (animDesired == -1) - //{ - // animDesired = 0; - //} - //this->pev->sequence = animDesired; - break; - - case PLAYER_ATTACK1: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - break; - - case PLAYER_PRIME: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RANGE_PRIME; - break; - } - break; - - case PLAYER_RELOAD: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD; - break; - } - break; - case PLAYER_RELOAD_START: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD_START; - break; - } - break; - case PLAYER_RELOAD_INSERT: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD_INSERT; - break; - } - break; - case PLAYER_RELOAD_END: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RELOAD_END; - break; - } - break; - case PLAYER_IDLE: - case PLAYER_WALK: - if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping - { - m_IdealActivity = m_Activity; - } - else if ( pev->waterlevel > 1 ) - { - if ( speed == 0 ) - m_IdealActivity = ACT_HOVER; - else - m_IdealActivity = ACT_SWIM; - } - else - { - if((playerAnim == PLAYER_IDLE) && !strcmp(this->m_szAnimExtention, "") && (theAvHPlayer->GetPlayMode() != PLAYMODE_READYROOM)) - { - m_IdealActivity = ACT_IDLE; - } - else - { - m_IdealActivity = ACT_WALK; - } - } - break; - } - - switch (m_IdealActivity) - { - - case ACT_DIESIMPLE: - case ACT_DIEBACKWARD: - case ACT_DIEFORWARD: - case ACT_DIEVIOLENT: - default: - if ( m_Activity == m_IdealActivity) - return; - m_Activity = m_IdealActivity; - - //animDesired = LookupActivity( m_Activity ); - this->GetAnimationForActivity(this->m_Activity, szAnim); - animDesired = LookupSequence( szAnim ); - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - #ifdef DEBUG - if(theDebugAnimations) - { - char theMessage[256]; - sprintf(theMessage, "Setting full-body animation (%s): %d (no gaitsequence)\n", szAnim, animDesired); - ALERT(at_console, theMessage); - } - #endif - - pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); - return; - - // create seperate case for these so that they don't interfere with a reload - Elven - case ACT_HOVER: - case ACT_LEAP: - case ACT_SWIM: - case ACT_HOP: - reloadAnim = (m_Activity == ACT_RELOAD) || (m_Activity == ACT_RELOAD_START) || (m_Activity == ACT_RELOAD_INSERT) || (m_Activity == ACT_RELOAD_END); - if ( m_Activity == m_IdealActivity || reloadAnim) - return; - m_Activity = m_IdealActivity; - - //animDesired = LookupActivity( m_Activity ); - this->GetAnimationForActivity(this->m_Activity, szAnim); - animDesired = LookupSequence( szAnim ); - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); - return; - - - case ACT_RANGE_ATTACK1: - case ACT_RANGE_PRIME: - this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - animDesired = LookupSequence( szAnim ); - - if (animDesired == -1) - { - animDesired = 0; - theFoundAnim = false; - } - - if ( pev->sequence != animDesired || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - if (!m_fSequenceLoops) - { - pev->effects |= EF_NOINTERP; - } - - m_Activity = m_IdealActivity; - - if(theFoundAnim) - { - #ifdef DEBUG - if(theDebugAnimations) - { - char theMessage[256]; - sprintf(theMessage, "%s%s\n", "Setting attack animation: ", szAnim); - ALERT(at_console, theMessage); - } - #endif - } - - pev->sequence = animDesired; - ResetSequenceInfo( ); - break; - - case ACT_RELOAD: - case ACT_RELOAD_START: - case ACT_RELOAD_INSERT: - case ACT_RELOAD_END: - this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - animDesired = LookupSequence( szAnim ); - - if ( pev->sequence != animDesired || !m_fSequenceLoops ) - { - pev->frame = 0; - } - m_Activity = m_IdealActivity; - break; - - - - case ACT_WALK: - reloadAnim = (m_Activity == ACT_RELOAD) || (m_Activity == ACT_RELOAD_START) || - (m_Activity == ACT_RELOAD_INSERT) || (m_Activity == ACT_RELOAD_END); - if ((m_Activity != ACT_RANGE_ATTACK1 && m_Activity != ACT_RANGE_PRIME && !reloadAnim/*m_Activity != ACT_RELOAD*/ ) || m_fSequenceFinished) - { - this->GetAnimationForActivity(this->m_IdealActivity, szAnim); - animDesired = LookupSequence( szAnim ); - if (animDesired == -1) - { - animDesired = 0; - } - m_Activity = ACT_WALK; - } - else - { - animDesired = pev->sequence; - } - break; - } - - // Now handle gaitsequence - if(FBitSet(this->pev->flags, FL_DUCKING)) - { - if(speed == 0) - { - this->GetAnimationForActivity(ACT_CROUCHIDLE, szAnim, true); - } - else - { - this->GetAnimationForActivity(ACT_CROUCH, szAnim, true); - } - } - else if (speed > this->GetMaxWalkSpeed() ) - { - this->GetAnimationForActivity(ACT_RUN, szAnim, true); - } - else if (speed > 0) - { - this->GetAnimationForActivity(ACT_WALK, szAnim, true); - } - else - { - this->GetAnimationForActivity(ACT_IDLE, szAnim, true); - } - - // Set the gaitsequence - gaitDesired = LookupSequence(szAnim, 1); - if(gaitDesired == -1) - { - gaitDesired = 0; - } - -#ifdef DEBUG - if(theDebugAnimations) - { - if((this->pev->gaitsequence != gaitDesired) || (this->pev->sequence != animDesired)) - { - ALERT(at_console, "Anim desired (%s): %d, gaitsequence: %d gaitdesired: %d \n", szAnim, animDesired, pev->gaitsequence, gaitDesired); - } - } -#endif - - this->pev->gaitsequence = gaitDesired; - - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && (thePlayer->GetPlayMode() == PLAYMODE_READYROOM)) - { - // Play some animation on top and bottom when not holding any weapons - animDesired = gaitDesired; - } - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - // Reset to first frame of desired animation - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); -} - -/* -=========== -TabulateAmmo -This function is used to find and store -all the ammo we have into the ammo vars. -============ -*/ -void CBasePlayer::TabulateAmmo() -{ - ammo_9mm = AmmoInventory( GetAmmoIndex( "9mm" ) ); - ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) ); - ammo_argrens = AmmoInventory( GetAmmoIndex( "ARgrenades" ) ); - ammo_bolts = AmmoInventory( GetAmmoIndex( "bolts" ) ); - ammo_buckshot = AmmoInventory( GetAmmoIndex( "buckshot" ) ); - ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) ); - ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) ); - ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) ); -} - - -/* -=========== -WaterMove -============ -*/ -#define AIRTIME 12 // lung full of air lasts this many seconds - -void CBasePlayer::WaterMove() -{ - int air; - - if (pev->movetype == MOVETYPE_NOCLIP) - return; - - if (pev->health < 0) - return; - - // waterlevel 0 - not in water - // waterlevel 1 - feet in water - // waterlevel 2 - waist in water - // waterlevel 3 - head in water - - if (pev->waterlevel != 3) - { - // not underwater - - // play 'up for air' sound - if (pev->air_finished < gpGlobals->time) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", 1, ATTN_NORM); - else if (pev->air_finished < gpGlobals->time + 9) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", 1, ATTN_NORM); - - pev->air_finished = gpGlobals->time + AIRTIME; - pev->dmg = 2; - - // if we took drowning damage, give it back slowly - if (m_idrowndmg > m_idrownrestored) - { - // set drowning damage bit. hack - dmg_drownrecover actually - // makes the time based damage code 'give back' health over time. - // make sure counter is cleared so we start count correctly. - - // NOTE: this actually causes the count to continue restarting - // until all drowning damage is healed. - - m_bitsDamageType |= DMG_DROWNRECOVER; - m_bitsDamageType &= ~DMG_DROWN; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - } - - } - else - { // fully under water - // stop restoring damage while underwater - m_bitsDamageType &= ~DMG_DROWNRECOVER; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - - if (pev->air_finished < gpGlobals->time) // drown! - { - if (pev->pain_finished < gpGlobals->time) - { - // take drowning damage - pev->dmg += 1; - if (pev->dmg > 5) - pev->dmg = 5; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN); - pev->pain_finished = gpGlobals->time + 1; - - // track drowning damage, give it back when - // player finally takes a breath - - m_idrowndmg += pev->dmg; - } - } - else - { - m_bitsDamageType &= ~DMG_DROWN; - } - } - - if (!pev->waterlevel) - { - if (FBitSet(pev->flags, FL_INWATER)) - { - ClearBits(pev->flags, FL_INWATER); - } - return; - } - - // make bubbles - - air = (int)(pev->air_finished - gpGlobals->time); - if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim1.wav", 0.8, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 0.8, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim3.wav", 0.8, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim4.wav", 0.8, ATTN_NORM); break; - } - } - - if (pev->watertype == CONTENT_LAVA) // do damage - { - if (pev->dmgtime < gpGlobals->time) - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN); - } - else if (pev->watertype == CONTENT_SLIME) // do damage - { - pev->dmgtime = gpGlobals->time + 1; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID); - } - - if (!FBitSet(pev->flags, FL_INWATER)) - { - SetBits(pev->flags, FL_INWATER); - pev->dmgtime = 0; - } -} - -void CBasePlayer::InitPlayerFromSpawn(edict_t* inSpawn) -{ - if(!FNullEnt(inSpawn)) - { - int theOffset = AvHMUGetOriginOffsetForUser3(AvHUser3(this->pev->iuser3)); - this->pev->origin = VARS(inSpawn)->origin + Vector(0, 0, theOffset); - - this->pev->v_angle = VARS(inSpawn)->v_angle; - this->pev->velocity = g_vecZero; - this->pev->angles = VARS(inSpawn)->angles; - this->pev->punchangle = g_vecZero; - this->pev->fixangle = TRUE; - } -} - -// TRUE if the player is attached to a ladder -BOOL CBasePlayer::IsOnLadder( void ) -{ - return ( pev->movetype == MOVETYPE_FLY ); -} - -void CBasePlayer::PlayerDeathThink(void) -{ - float flForward; - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - flForward = pev->velocity.Length() - 20; - if (flForward <= 0) - pev->velocity = g_vecZero; - else - pev->velocity = flForward * pev->velocity.Normalize(); - } - - if ( HasWeapons() ) - { - // we drop the guns here because weapons that have an area effect and can kill their user - // will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the - // player class sometimes is freed. It's safer to manipulate the weapons once we know - // we aren't calling into any of their code anymore through the player pointer. - PackDeadPlayerItems(); - - // Assumes that all players have at least one weapon when they die - //SpawnClientSideCorpse(); - } - - if (pev->modelindex && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)) - { - StudioFrameAdvance( ); - - m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands - if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this - return; - } - - // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore - // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn - if ( pev->movetype != MOVETYPE_NONE && FBitSet(pev->flags, FL_ONGROUND) ) - pev->movetype = MOVETYPE_NONE; - - if (pev->deadflag == DEAD_DYING) - pev->deadflag = DEAD_DEAD; - - StopAnimation(); - - pev->effects |= EF_NOINTERP; - pev->framerate = 0.0; - - BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); - - // wait for all buttons released - if (pev->deadflag == DEAD_DEAD) - { - //if (fAnyButtonDown) - // return; - - //if ( g_pGameRules->FPlayerCanRespawn( this ) ) - //{ - m_fDeadTime = gpGlobals->time; - pev->deadflag = DEAD_RESPAWNABLE; - //} - - return; - } - -// if the player has been dead for one second longer than allowed by forcerespawn, -// forcerespawn isn't on. Send the player off to an intermission camera until they -// choose to respawn. - //if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) ) - //{ - // // go to dead camera. - // StartDeathCam(); - //} - - - // From Counter-strike - // if the player has been dead for one second longer than allowed by forcerespawn, - // forcerespawn isn't on. Send the player off to an intermission camera until they - // choose to respawn. -// if ( g_pGameRules->IsMultiplayer() && -// ( gpGlobals->time > (m_fDeadTime + 3) ) && -// !( m_afPhysicsFlags & PFLAG_OBSERVER) ) -// { -// //Send message to everybody to spawn a corpse. -// SpawnClientSideCorpse(); -// -// // go to dead camera. -// //StartDeathCam(); -// } - - const float kMinDeathTime = .5f; - -// wait for any button down, or mp_forcerespawn is set and the respawn time is up - if ((!fAnyButtonDown || ( gpGlobals->time < (m_fDeadTime + kMinDeathTime) )) - && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && (gpGlobals->time > (m_fDeadTime + kMinDeathTime))) ) - return; - - pev->button = 0; - m_iRespawnFrames = 0; - - // Player is done with the death cam, continue - AvHPlayer* thePlayer = dynamic_cast(this); - AvHGamerules* theGameRules = dynamic_cast(g_pGameRules); - - theGameRules->PlayerDeathEnd(thePlayer); -} - -//========================================================= -// StartDeathCam - find an intermission spot and send the -// player off into observer mode -//========================================================= -void CBasePlayer::StartDeathCam( void ) -{ - edict_t *pSpot, *pNewSpot; - int iRand; - - if ( pev->view_ofs == g_vecZero ) - { - // don't accept subsequent attempts to StartDeathCam() - return; - } - - pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission"); - - if ( !FNullEnt( pSpot ) ) - { - // at least one intermission spot in the world. - iRand = RANDOM_LONG( 0, 3 ); - - while ( iRand > 0 ) - { - pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission"); - - if ( pNewSpot ) - { - pSpot = pNewSpot; - } - - iRand--; - } - - CopyToBodyQue( pev ); - StartObserver( pSpot->v.origin, pSpot->v.v_angle ); - } - else - { - // no intermission spot. Push them up in the air, looking down at their corpse - TraceResult tr; - CopyToBodyQue( pev ); - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); - return; - } -} - -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) -{ -// m_afPhysicsFlags |= PFLAG_OBSERVER; -// -// pev->view_ofs = g_vecZero; -// pev->angles = pev->v_angle = vecViewAngle; -// pev->fixangle = TRUE; -// pev->solid = SOLID_NOT; -// pev->takedamage = DAMAGE_NO; -// pev->movetype = MOVETYPE_NONE; -// pev->modelindex = 0; -// UTIL_SetOrigin( pev, vecPosition ); - - m_iHideHUD |= (HIDEHUD_HEALTH | HIDEHUD_WEAPONS); - m_afPhysicsFlags |= PFLAG_OBSERVER; - - pev->effects = EF_NODRAW; - pev->view_ofs = g_vecZero; - pev->angles = pev->v_angle = vecViewAngle; - pev->fixangle = TRUE; - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - pev->movetype = MOVETYPE_NONE; - UTIL_SetOrigin( pev, vecPosition ); - - ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); - ClearBits( pev->flags, FL_DUCKING ); - // pev->flags = FL_CLIENT | FL_SPECTATOR; // Should we set Spectator flag? Or is it reserver for people connecting with spectator 1? - pev->deadflag = DEAD_RESPAWNABLE; - - // Tell the physics code that this player's now in observer mode - Observer_SetMode(this->GetDefaultSpectatingMode()); - Observer_SpectatePlayer(this->GetDefaultSpectatingTarget()); - m_flNextObserverInput = 0; -} - -void CBasePlayer::StopObserver() -{ - this->pev->solid = SOLID_SLIDEBOX; - this->pev->effects = 0; - this->pev->takedamage = DAMAGE_YES; - this->pev->movetype = MOVETYPE_WALK; - ClearBits(this->m_afPhysicsFlags, PFLAG_OBSERVER); - ClearBits(this->m_afPhysicsFlags, PFLAG_DUCKING ); - ClearBits(this->pev->flags, FL_DUCKING ); - this->pev->iuser1 = this->pev->iuser2 = 0; -} - -// -// PlayerUse - handles USE keypress -// -#define PLAYER_SEARCH_RADIUS (float)64 - -void CBasePlayer::ClearKeys() -{ - // clear attack/use commands from player - this->m_afButtonPressed = 0; - this->pev->button = 0; - this->m_afButtonReleased = 0; -} - -void CBasePlayer::PlayerUse ( void ) -{ - AvHPlayer* theAvHPlayer = dynamic_cast(this); - - // Was use pressed or released? - if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) - return; - - //: Dont do this on commanders to prevent phantom use sounds. - if(theAvHPlayer->GetIsInTopDownMode()) - return; - - // Hit Use on a train? - if ( m_afButtonPressed & IN_USE ) - { - if ( m_pTank != NULL ) - { - // Stop controlling the tank - // TODO: Send HUD Update - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - return; - } - else - { - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - else - { // Start controlling the train! - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - - if ( pTrain && !(pev->button & IN_JUMP) && FBitSet(pev->flags, FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(pev) ) - { - m_afPhysicsFlags |= PFLAG_ONTRAIN; - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); - m_iTrain |= TRAIN_NEW; - EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM); - return; - } - } - } - } - - CBaseEntity *pObject = NULL; - CBaseEntity *pClosest = NULL; - Vector vecLOS; - float flMaxDot = VIEW_FIELD_NARROW; - float flDot; - - UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing - - - while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL) - { - - if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE)) - { - // !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that - // this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS - // when player hits the use key. How many objects can be in that area, anyway? (sjb) - vecLOS = (VecBModelOrigin( pObject->pev ) - (pev->origin + pev->view_ofs)); - - // This essentially moves the origin of the target to the corner nearest the player to test to see - // if it's "hull" is in the view cone - vecLOS = UTIL_ClampVectorToBox( vecLOS, pObject->pev->size * 0.5 ); - - flDot = DotProduct (vecLOS , gpGlobals->v_forward); - if (flDot > flMaxDot ) - {// only if the item is in front of the user - pClosest = pObject; - flMaxDot = flDot; -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } - } - - pObject = pClosest; - - // Add los test for aliens looking at hives. - if ( pObject == NULL && AvHGetIsAlien(this->pev->iuser3) ) { - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = this->GetGunPosition( ) + vecAiming; - Vector vecEnd = vecSrc + vecAiming*800; - - TraceResult theTraceResult; - UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, this->edict(), &theTraceResult); - - edict_t* theEntityHit = theTraceResult.pHit; - AvHHive *theHive = dynamic_cast(CBaseEntity::Instance(theEntityHit)); - if ( theHive) { - - float the2DDistance = VectorDistance2D(this->pev->origin, theHive->pev->origin); - - // Enabled state is true - if(the2DDistance <= 150.0 && (this->pev->origin < theHive->pev->origin) ) - { - pObject=theHive; - } - } - } - - // Found an object - if (pObject ) - { - //!!!UNDONE: traceline here to prevent USEing buttons through walls - int caps = pObject->ObjectCaps(); - - if ( m_afButtonPressed & IN_USE ) - { - //EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM); - const char* theSound = AvHSHUGetCommonSoundName(theAvHPlayer->GetIsAlien(), WEAPON_SOUND_SELECT); - EMIT_SOUND( ENT(pev), CHAN_ITEM, theSound, 0.4, ATTN_NORM); - } - - if ( ( (pev->button & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || - ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) - { - if ( caps & FCAP_CONTINUOUS_USE ) - m_afPhysicsFlags |= PFLAG_USING; - - pObject->Use( this, this, USE_SET, 1 ); - } - // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away - else if ( (m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use - { - pObject->Use( this, this, USE_SET, 0 ); - } - } - else - { - if ( m_afButtonPressed & IN_USE ) - { - //EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM); - const char* theSound = AvHSHUGetCommonSoundName(theAvHPlayer->GetIsAlien(), WEAPON_SOUND_DENYSELECT); - EMIT_SOUND( ENT(pev), CHAN_ITEM, theSound, 0.4, ATTN_NORM); - } - } -} - - - -void CBasePlayer::Jump() -{ - Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping - Vector vecAdjustedVelocity; - Vector vecSpot; - TraceResult tr; - - if (FBitSet(pev->flags, FL_WATERJUMP)) - return; - - if (pev->waterlevel >= 2) - { - return; - } - - // jump velocity is sqrt( height * gravity * 2) - - // If this isn't the first frame pressing the jump button, break out. - if ( !FBitSet( m_afButtonPressed, IN_JUMP ) ) - return; // don't pogo stick - - if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity ) - { - return; - } - -// many features in this function use v_forward, so makevectors now. - UTIL_MakeVectors (pev->angles); - - // ClearBits(pev->flags, FL_ONGROUND); // don't stairwalk - - SetAnimation( PLAYER_JUMP ); - - if ( m_fLongJump && - (pev->button & IN_DUCK) && - ( pev->flDuckTime > 0 ) && - pev->velocity.Length() > 50 ) - { - SetAnimation( PLAYER_SUPERJUMP ); - } - - // If you're standing on a conveyor, add it's velocity to yours (for momentum) - entvars_t *pevGround = VARS(pev->groundentity); - if ( pevGround && (pevGround->flags & FL_CONVEYOR) ) - { - pev->velocity = pev->velocity + pev->basevelocity; - } -} - - - -// This is a glorious hack to find free space when you've crouched into some solid space -// Our crouching collisions do not work correctly for some reason and this is easier -// than fixing the problem :( -void FixPlayerCrouchStuck( edict_t *pPlayer ) -{ - TraceResult trace; - - // Move up as many as 18 pixels if the player is stuck. - for ( int i = 0; i < 18; i++ ) - { - UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace ); - if ( trace.fStartSolid ) - pPlayer->v.origin.z ++; - else - break; - } -} - -void CBasePlayer::Duck( ) -{ - if (pev->button & IN_DUCK) - { - if ( m_IdealActivity != ACT_LEAP ) - { - SetAnimation( PLAYER_WALK ); - } - } -} - -// -// ID's player as such. -// -int CBasePlayer::Classify ( void ) -{ - return CLASS_PLAYER; -} - - -void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) -{ - // Positive score always adds - if ( score < 0 ) - { - if ( !bAllowNegativeScore ) - { - if ( pev->frags < 0 ) // Can't go more negative - return; - - if ( -score > pev->frags ) // Will this go negative? - { - score = -pev->frags; // Sum will be 0 - } - } - } - - pev->frags += score; -} - -void CBasePlayer::EffectivePlayerClassChanged() -{ -} - -void CBasePlayer::NeedsTeamUpdate() -{ -} - -void CBasePlayer::SendTeamUpdate() -{ -} - -void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) -{ - int index = entindex(); - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && i != index ) - { - if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) - { - pPlayer->AddPoints( score, bAllowNegativeScore ); - } - } - } -} - -//Player ID -void CBasePlayer::InitStatusBar() -{ - m_flStatusBarDisappearDelay = 0; - m_SbarString1[0] = m_SbarString0[0] = 0; -} - -void CBasePlayer::UpdateStatusBar() -{ - int newSBarState[ SBAR_END ]; - char sbuf0[ SBAR_STRING_SIZE ]; - char sbuf1[ SBAR_STRING_SIZE ]; - - int i; - - for (i = 0; i < SBAR_END; ++i) - { - newSBarState[i] = -1; - } - - //memset( newSBarState, 0, sizeof(newSBarState) ); - - strcpy( sbuf0, m_SbarString0 ); - strcpy( sbuf1, m_SbarString1 ); - - // Find an ID Target - TraceResult tr; - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - Vector vecSrc = EyePosition(); - Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE); - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr); - - bool theIsCombatMode = GetGameRules()->GetIsCombatMode(); - int theMaxEnumToSend = SBAR_ID_TARGETARMOR; - if(theIsCombatMode) - { - theMaxEnumToSend = SBAR_ID_TARGETLEVEL; - } - - if (tr.flFraction != 1.0) - { - if ( !FNullEnt( tr.pHit ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if(!pEntity) - return; - - if (pEntity->Classify() == CLASS_PLAYER ) - { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); - - // Name Health: X% Armor: Y% - //strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" ); - - // (health: X armor: Y) - if(!theIsCombatMode) - { - strcpy( sbuf1, "2 (health: %i2%%\n3 armor: %i3%%)" ); - } - else - { - strcpy( sbuf1, "2 (health: %i2%%\n3 armor: %i3%%\n4 level: %i4)" ); - } - - // allies and medics get to see the targets health - if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) - { - int theLevel = 1; - AvHPlayer* thePlayer = dynamic_cast(pEntity); - if(thePlayer) - { - theLevel = thePlayer->GetExperienceLevel(); - } - - //newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); - //newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. - float theHealthPercent = pEntity->pev->health/AvHPlayerUpgrade::GetMaxHealth(pEntity->pev->iuser4, (AvHUser3)pEntity->pev->iuser3, theLevel); - float theArmorPercent = pEntity->pev->armorvalue/AvHPlayerUpgrade::GetMaxArmorLevel(pEntity->pev->iuser4, (AvHUser3)pEntity->pev->iuser3); - newSBarState[ SBAR_ID_TARGETHEALTH ] = max(theHealthPercent*100+0.5f, 0.0f); - newSBarState[ SBAR_ID_TARGETARMOR ] = max(theArmorPercent*100+0.5f, 0.0f); - newSBarState[ SBAR_ID_TARGETLEVEL ] = theLevel; - } - } - else - { - bool theSuccess = false; - - // Show hive health for friendlies - if(this->pev->team == pEntity->pev->team) - { - AvHUser3 theUser3 = (AvHUser3)pEntity->pev->iuser3; - switch(theUser3) - { - // Place user3s to draw here - case AVH_USER3_HIVE: - theSuccess = true; - break; - } - } - - if(theSuccess) - { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); - - strcpy( sbuf1, "2 (health: %i2%%)\n" ); - - float theHealthPercentage = pEntity->pev->health/pEntity->pev->max_health; - newSBarState[ SBAR_ID_TARGETHEALTH ] = max(theHealthPercentage*100+0.5f, 0.0f); - } - } - - m_flStatusBarDisappearDelay = gpGlobals->time + 1.0; - } - else if ( m_flStatusBarDisappearDelay > gpGlobals->time ) - { - // hold the values for a short amount of time after viewing the object - newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ]; - newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ]; - newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ]; - newSBarState[ SBAR_ID_TARGETLEVEL ] = m_izSBarState[ SBAR_ID_TARGETLEVEL ]; - } - } - - BOOL bForceResend = FALSE; - - if ( strcmp( sbuf0, m_SbarString0 ) ) - { - NetMsg_StatusText( pev, 0, string(sbuf0) ); - strcpy( m_SbarString0, sbuf0 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - if ( strcmp( sbuf1, m_SbarString1 ) ) - { - NetMsg_StatusText( pev, 1, string(sbuf1) ); - strcpy( m_SbarString1, sbuf1 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - // Check values and send if they don't match - for (i = 1; i <= theMaxEnumToSend; i++) - { - if ( newSBarState[i] != m_izSBarState[i] || bForceResend ) - { - NetMsg_StatusValue( pev, i, newSBarState[i] ); - m_izSBarState[i] = newSBarState[i]; - } - } -} - - - - - - - - - -#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing -#define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible -#define CLIMB_SPEED_DEC 15 // climbing deceleration rate -#define CLIMB_PUNCH_X -7 // how far to 'punch' client X axis when climbing -#define CLIMB_PUNCH_Z 7 // how far to 'punch' client Z axis when climbing - -void CBasePlayer::PreThink(void) -{ - int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame - - // Debounced button codes for pressed/released - // UNDONE: Do we need auto-repeat? - m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed" - m_afButtonReleased = buttonsChanged & (~pev->button); // The ones not down are "released" - - g_pGameRules->PlayerThink( this ); - - if ( g_fGameOver ) - return; // intermission or finale - - UTIL_MakeVectors(pev->v_angle); // is this still used? - - ItemPreFrame( ); - WaterMove(); - - if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) - m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; - else - m_iHideHUD |= HIDEHUD_FLASHLIGHT; - - - // JOHN: checks if new client data (for HUD and view control) needs to be sent to the client - UpdateClientData(); - - CheckTimeBasedDamage(); - - // Observer Button Handling - if (this->IsObserver() ) - { - Observer_HandleButtons(); - pev->impulse = 0; - return; - } - - CheckSuitUpdate(); - - if (pev->deadflag >= DEAD_DYING) - { - PlayerDeathThink(); - return; - } - - // So the correct flags get sent to client asap. - // - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - pev->flags |= FL_ONTRAIN; - else - pev->flags &= ~FL_ONTRAIN; - - // Train speed control - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - float vel; - - if ( !pTrain ) - { - TraceResult trainTrace; - // Maybe this is on the other side of a level transition - UTIL_TraceLine( pev->origin, pev->origin + Vector(0,0,-38), ignore_monsters, ENT(pev), &trainTrace ); - - // HACKHACK - Just look for the func_tracktrain classname - if ( trainTrace.flFraction != 1.0 && trainTrace.pHit ) - pTrain = CBaseEntity::Instance( trainTrace.pHit ); - - - if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) ) - { - //ALERT( at_error, "In train mode with no train!\n" ); - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - } - else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) ) - { - // Turn off the train if you jump, strafe, or the train controls go dead - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - - pev->velocity = g_vecZero; - vel = 0; - if ( m_afButtonPressed & IN_FORWARD ) - { - vel = 1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - else if ( m_afButtonPressed & IN_BACK ) - { - vel = -1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - - if (vel) - { - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); - m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; - } - - } else if (m_iTrain & TRAIN_ACTIVE) - m_iTrain = TRAIN_NEW; // turn off train - - if (pev->button & IN_JUMP) - { - // If on a ladder, jump off the ladder - // else Jump - Jump(); - } - - - // If trying to duck, already ducked, or in the process of ducking - if ((pev->button & IN_DUCK) || FBitSet(pev->flags,FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) { - if ( AvHMUGetCanDuck(this->pev->iuser3) ) - Duck(); - } - - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) - { - m_flFallVelocity = -pev->velocity.z; - } - - // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? - - // Clear out ladder pointer - m_hEnemy = NULL; - - if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) - { - pev->velocity = g_vecZero; - } -} -/* Time based Damage works as follows: - 1) There are several types of timebased damage: - - #define DMG_PARALYZE (1 << 14) // slows affected creature down - #define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad - #define DMG_POISON (1 << 16) // blood poisioning - #define DMG_RADIATION (1 << 17) // radiation exposure - #define DMG_DROWNRECOVER (1 << 18) // drown recovery - #define DMG_ACID (1 << 19) // toxic chemicals or acid burns - #define DMG_SLOWBURN (1 << 20) // in an oven - #define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer - - 2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter, - per damage type. The counter is decremented every second, so the maximum time - an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius - of a damaging effect like fire, nervegas, radiation will continually reset the counter to max. - - 3) Every second that a tbd counter is running, the player takes damage. The damage - is determined by the type of tdb. - Paralyze - 1/2 movement rate, 30 second duration. - Nervegas - 5 points per second, 16 second duration = 80 points max dose. - Poison - 2 points per second, 25 second duration = 50 points max dose. - Radiation - 1 point per second, 50 second duration = 50 points max dose. - Drown - 5 points per second, 2 second duration. - Acid/Chemical - 5 points per second, 10 second duration = 50 points max. - Burn - 10 points per second, 2 second duration. - Freeze - 3 points per second, 10 second duration = 30 points max. - - 4) Certain actions or countermeasures counteract the damaging effects of tbds: - - Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body - - recharged by suit recharger - Air In Lungs - drowning damage is done to air in lungs first, then to body - - recharged by poking head out of water - - 10 seconds if swiming fast - Air In SCUBA - drowning damage is done to air in tanks first, then to body - - 2 minutes in tanks. Need new tank once empty. - Radiation Syringe - Each syringe full provides protection vs one radiation dosage - Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison). - Health kit - Immediate stop to acid/chemical, fire or freeze damage. - Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage. - - -*/ - -// If player is taking time based damage, continue doing damage to player - -// this simulates the effect of being poisoned, gassed, dosed with radiation etc - -// anything that continues to do damage even after the initial contact stops. -// Update all time based damage counters, and shut off any that are done. - -// The m_bitsDamageType bit MUST be set if any damage is to be taken. -// This routine will detect the initial on value of the m_bitsDamageType -// and init the appropriate counter. Only processes damage every second. - -//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage -//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval - -//#define NERVEGAS_DURATION 16 -//#define NERVEGAS_DAMAGE 5.0 - -//#define POISON_DURATION 25 -//#define POISON_DAMAGE 2.0 - -//#define RADIATION_DURATION 50 -//#define RADIATION_DAMAGE 1.0 - -//#define ACID_DURATION 10 -//#define ACID_DAMAGE 5.0 - -//#define SLOWBURN_DURATION 2 -//#define SLOWBURN_DAMAGE 1.0 - -//#define SLOWFREEZE_DURATION 1.0 -//#define SLOWFREEZE_DAMAGE 3.0 - -/* */ - - -void CBasePlayer::CheckTimeBasedDamage() -{ - int i; - BYTE bDuration = 0; - - static float gtbdPrev = 0.0; - - if (!(m_bitsDamageType & DMG_TIMEBASED)) - return; - - // only check for time based damage approx. every 2 seconds - if (abs(gpGlobals->time - m_tbdPrev) < 2.0) - return; - - m_tbdPrev = gpGlobals->time; - - for (i = 0; i < CDMG_TIMEBASED; i++) - { - // make sure bit is set for damage type - if (m_bitsDamageType & (DMG_PARALYZE << i)) - { - switch (i) - { - case itbd_Paralyze: - // UNDONE - flag movement as half-speed - bDuration = PARALYZE_DURATION; - break; - case itbd_NerveGas: -// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); - bDuration = NERVEGAS_DURATION; - break; - case itbd_Poison: - TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC); - bDuration = POISON_DURATION; - break; - case itbd_Radiation: -// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); - bDuration = RADIATION_DURATION; - break; - case itbd_DrownRecover: - // NOTE: this hack is actually used to RESTORE health - // after the player has been drowning and finally takes a breath - if (m_idrowndmg > m_idrownrestored) - { - int idif = min(m_idrowndmg - m_idrownrestored, 10); - - TakeHealth(idif, DMG_GENERIC); - m_idrownrestored += idif; - } - bDuration = 4; // get up to 5*10 = 50 points back - break; - case itbd_Acid: -// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); - bDuration = ACID_DURATION; - break; - case itbd_SlowBurn: -// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); - bDuration = SLOWBURN_DURATION; - break; - case itbd_SlowFreeze: -// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); - bDuration = SLOWFREEZE_DURATION; - break; - default: - bDuration = 0; - } - - if (m_rgbTimeBasedDamage[i]) - { - // use up an antitoxin on poison or nervegas after a few seconds of damage - if (((i == itbd_NerveGas) && (m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION)) || - ((i == itbd_Poison) && (m_rgbTimeBasedDamage[i] < POISON_DURATION))) - { - if (m_rgItems[ITEM_ANTIDOTE]) - { - m_rgbTimeBasedDamage[i] = 0; - m_rgItems[ITEM_ANTIDOTE]--; - SetSuitUpdate("!HEV_HEAL4", FALSE, SUIT_REPEAT_OK); - } - } - - - // decrement damage duration, detect when done. - if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0) - { - m_rgbTimeBasedDamage[i] = 0; - // if we're done, clear damage bits - m_bitsDamageType &= ~(DMG_PARALYZE << i); - } - } - else - // first time taking this damage type - init damage duration - m_rgbTimeBasedDamage[i] = bDuration; - } - } -} - -/* -THE POWER SUIT - -The Suit provides 3 main functions: Protection, Notification and Augmentation. -Some functions are automatic, some require power. -The player gets the suit shortly after getting off the train in C1A0 and it stays -with him for the entire game. - -Protection - - Heat/Cold - When the player enters a hot/cold area, the heating/cooling indicator on the suit - will come on and the battery will drain while the player stays in the area. - After the battery is dead, the player starts to take damage. - This feature is built into the suit and is automatically engaged. - Radiation Syringe - This will cause the player to be immune from the effects of radiation for N seconds. Single use item. - Anti-Toxin Syringe - This will cure the player from being poisoned. Single use item. - Health - Small (1st aid kits, food, etc.) - Large (boxes on walls) - Armor - The armor works using energy to create a protective field that deflects a - percentage of damage projectile and explosive attacks. After the armor has been deployed, - it will attempt to recharge itself to full capacity with the energy reserves from the battery. - It takes the armor N seconds to fully charge. - -Notification (via the HUD) - -x Health -x Ammo -x Automatic Health Care - Notifies the player when automatic healing has been engaged. -x Geiger counter - Classic Geiger counter sound and status bar at top of HUD - alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal. -x Poison - Armor - Displays the current level of armor. - -Augmentation - - Reanimation (w/adrenaline) - Causes the player to come back to life after he has been dead for 3 seconds. - Will not work if player was gibbed. Single use. - Long Jump - Used by hitting the ??? key(s). Caused the player to further than normal. - SCUBA - Used automatically after picked up and after player enters the water. - Works for N seconds. Single use. - -Things powered by the battery - - Armor - Uses N watts for every M units of damage. - Heat/Cool - Uses N watts for every second in hot/cold area. - Long Jump - Uses N watts for every jump. - Alien Cloak - Uses N watts for each use. Each use lasts M seconds. - Alien Shield - Augments armor. Reduces Armor drain by one half - -*/ - -// if in range of radiation source, ping geiger counter - -#define GEIGERDELAY 0.25 - -void CBasePlayer :: UpdateGeigerCounter( void ) -{ - BYTE range; - - // delay per update ie: don't flood net with these msgs - if (gpGlobals->time < m_flgeigerDelay) - return; - - m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; - - // send range to radition source to client - - range = (BYTE) (m_flgeigerRange / 4); - - if (range != m_igeigerRangePrev) - { - m_igeigerRangePrev = range; - NetMsg_GeigerRange( pev, range ); - } - - // reset counter and semaphore - if (!RANDOM_LONG(0,3)) - m_flgeigerRange = 1000; - -} - -/* -================ -CheckSuitUpdate - -Play suit update if it's time -================ -*/ - -#define SUITUPDATETIME 3.5 -#define SUITFIRSTUPDATETIME 0.1 - -void CBasePlayer::CheckSuitUpdate() -{ - int i; - int isentence = 0; - int isearch = m_iSuitPlayNext; - - // Ignore suit updates if no suit - if ( !(pev->weapons & (1<IsMultiplayer() ) - { - // don't bother updating HEV voice in multiplayer. - return; - } - - if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0) - { - // play a sentence off of the end of the queue - for (i = 0; i < CSUITPLAYLIST; i++) - { - if (isentence = m_rgSuitPlayList[isearch]) - break; - - if (++isearch == CSUITPLAYLIST) - isearch = 0; - } - - if (isentence) - { - m_rgSuitPlayList[isearch] = 0; - if (isentence > 0) - { - // play sentence number - - char sentence[CBSENTENCENAME_MAX+1]; - strcpy(sentence, "!"); - strcat(sentence, gszallsentencenames[isentence]); - EMIT_SOUND_SUIT(ENT(pev), sentence); - } - else - { - // play sentence group - EMIT_GROUPID_SUIT(ENT(pev), -isentence); - } - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - else - // queue is empty, don't check - m_flSuitUpdate = 0; - } -} - -// add sentence to suit playlist queue. if fgroup is true, then -// name is a sentence group (HEV_AA), otherwise name is a specific -// sentence name ie: !HEV_AA0. If iNoRepeat is specified in -// seconds, then we won't repeat playback of this word or sentence -// for at least that number of seconds. - -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) -{ - int i; - int isentence; - int iempty = -1; - - - // Ignore suit updates if no suit - if ( !(pev->weapons & (1<IsMultiplayer() ) - { - // due to static channel design, etc. We don't play HEV sounds in multiplayer right now. - return; - } - - // if name == NULL, then clear out the queue - - if (!name) - { - for (i = 0; i < CSUITPLAYLIST; i++) - m_rgSuitPlayList[i] = 0; - return; - } - // get sentence or group number - if (!fgroup) - { - isentence = SENTENCEG_Lookup(name, NULL); - if (isentence < 0) - return; - } - else - // mark group number as negative - isentence = -SENTENCEG_GetIndex(name); - - // check norepeat list - this list lets us cancel - // the playback of words or sentences that have already - // been played within a certain time. - - for (i = 0; i < CSUITNOREPEAT; i++) - { - if (isentence == m_rgiSuitNoRepeat[i]) - { - // this sentence or group is already in - // the norepeat list - - if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time) - { - // norepeat time has expired, clear it out - m_rgiSuitNoRepeat[i] = 0; - m_rgflSuitNoRepeatTime[i] = 0.0; - iempty = i; - break; - } - else - { - // don't play, still marked as norepeat - return; - } - } - // keep track of empty slot - if (!m_rgiSuitNoRepeat[i]) - iempty = i; - } - - // sentence is not in norepeat list, save if norepeat time was given - - if (iNoRepeatTime) - { - if (iempty < 0) - iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over - m_rgiSuitNoRepeat[iempty] = isentence; - m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time; - } - - // find empty spot in queue, or overwrite last spot - - m_rgSuitPlayList[m_iSuitPlayNext++] = isentence; - if (m_iSuitPlayNext == CSUITPLAYLIST) - m_iSuitPlayNext = 0; - - if (m_flSuitUpdate <= gpGlobals->time) - { - if (m_flSuitUpdate == 0) - // play queue is empty, don't delay too long before playback - m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME; - else - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - -} - -/* -================ -CheckPowerups - -Check for turning off powerups - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -================ -*/ - static void -CheckPowerups(entvars_t *pev) -{ - if (pev->health <= 0) - return; - - //pev->modelindex = g_ulModelIndexPlayer; // don't use eyes -} - - -//========================================================= -// UpdatePlayerSound - updates the position of the player's -// reserved sound slot in the sound list. -//========================================================= -void CBasePlayer :: UpdatePlayerSound ( void ) -{ - int iBodyVolume; - int iVolume; - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) ); - - if ( !pSound ) - { - ALERT ( at_console, "Client lost reserved sound!\n" ); - return; - } - - pSound->m_iType = bits_SOUND_NONE; - - // now calculate the best target volume for the sound. If the player's weapon - // is louder than his body/movement, use the weapon volume, else, use the body volume. - - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - iBodyVolume = pev->velocity.Length(); - - // clamp the noise that can be made by the body, in case a push trigger, - // weapon recoil, or anything shoves the player abnormally fast. - if ( iBodyVolume > 512 ) - { - iBodyVolume = 512; - } - } - else - { - iBodyVolume = 0; - } - - if ( pev->button & IN_JUMP ) - { - iBodyVolume += 100; - } - -// convert player move speed and actions into sound audible by monsters. - if ( m_iWeaponVolume > iBodyVolume ) - { - m_iTargetVolume = m_iWeaponVolume; - - // OR in the bits for COMBAT sound if the weapon is being louder than the player. - pSound->m_iType |= bits_SOUND_COMBAT; - } - else - { - m_iTargetVolume = iBodyVolume; - } - - // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while - m_iWeaponVolume -= 250 * gpGlobals->frametime; - if ( m_iWeaponVolume < 0 ) - { - iVolume = 0; - } - - - // if target volume is greater than the player sound's current volume, we paste the new volume in - // immediately. If target is less than the current volume, current volume is not set immediately to the - // lower volume, rather works itself towards target volume over time. This gives monsters a much better chance - // to hear a sound, especially if they don't listen every frame. - iVolume = pSound->m_iVolume; - - if ( m_iTargetVolume > iVolume ) - { - iVolume = m_iTargetVolume; - } - else if ( iVolume > m_iTargetVolume ) - { - iVolume -= 250 * gpGlobals->frametime; - - if ( iVolume < m_iTargetVolume ) - { - iVolume = 0; - } - } - - if ( m_fNoPlayerSound ) - { - // debugging flag, lets players move around and shoot without monsters hearing. - iVolume = 0; - } - - if ( gpGlobals->time > m_flStopExtraSoundTime ) - { - // since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two - // after actual emission to make sure it gets heard. - m_iExtraSoundTypes = 0; - } - - if ( pSound ) - { - pSound->m_vecOrigin = pev->origin; - pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes ); - pSound->m_iVolume = iVolume; - } - - // keep track of virtual muzzle flash - m_iWeaponFlash -= 256 * gpGlobals->frametime; - if (m_iWeaponFlash < 0) - m_iWeaponFlash = 0; - - //UTIL_MakeVectors ( pev->angles ); - //gpGlobals->v_forward.z = 0; - - // Below are a couple of useful little bits that make it easier to determine just how much noise the - // player is making. - // UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 ); - //ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume ); -} - - -void CBasePlayer::PostThink() -{ - if ( g_fGameOver ) - goto pt_end; // intermission or finale - - if (!IsAlive()) - goto pt_end; - - // Handle Tank controlling - if ( m_pTank != NULL ) - { // if they've moved too far from the gun, or selected a weapon, unuse the gun - if ( m_pTank->OnControls( pev ) && !pev->weaponmodel ) - { - m_pTank->Use( this, this, USE_SET, 2 ); // try fire the gun - } - else - { // they've moved off the platform - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - } - -// do weapon stuff - ItemPostFrame( ); - -// check to see if player landed hard enough to make a sound -// falling farther than half of the maximum safe distance, but not as far a max safe distance will -// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half -// of maximum safe distance will make no sound. Falling farther than max safe distance will play a -// fallpain sound, and damage will be inflicted based on how far the player fell - - if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) - { - // ALERT ( at_console, "%f\n", m_flFallVelocity ); - - if (pev->watertype == CONTENT_WATER) - { - // Did he hit the world or a non-moving entity? - // BUG - this happens all the time in water, especially when - // BUG - water has current force - // if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 ) - // EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); - } - // skulks, lerks, fades and jetpackers don't take falling damage - else if ((m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER1) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER3) && (this->pev->iuser3 != AVH_USER3_ALIEN_PLAYER4) && (this->pev->iuser3 != AVH_USER3_ALIEN_EMBRYO) && (!GetHasUpgrade(this->pev->iuser4, MASK_UPGRADE_7) || !(this->pev->iuser3 == AVH_USER3_MARINE_PLAYER)) ) - {// after this point, we start doing damage - - float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); - - if ( flFallDamage > pev->health ) - {//splat - // note: play on item channel because we play footstep landing on body channel - // : 243 don't play gib sound if being digested - if ( AvHGetIsAlien(this->pev->iuser3) || !GetHasUpgrade(this->pev->iuser4, MASK_DIGESTING) ) - EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM); - } - - if ( flFallDamage > 0 ) - { - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); - pev->punchangle.x = 0; - } - } - - if ( IsAlive() ) - { - SetAnimation( PLAYER_WALK ); - } - } - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer()) - { - CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 ); - // ALERT( at_console, "fall %f\n", m_flFallVelocity ); - } - m_flFallVelocity = 0; - } - - // select the proper animation for the player character - if ( IsAlive() ) - { - if (!pev->velocity.x && !pev->velocity.y) - SetAnimation( PLAYER_IDLE ); - else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) - SetAnimation( PLAYER_WALK ); - else if (pev->waterlevel > 1) - SetAnimation( PLAYER_WALK ); - } - - StudioFrameAdvance( ); - CheckPowerups(pev); - - UpdatePlayerSound(); - - // Track button info so we can detect 'pressed' and 'released' buttons next frame - m_afButtonLast = pev->button; - -pt_end: - // Decay timers on weapons - // go through all of the weapons and make a list of the ones to pack - for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - CBasePlayerWeapon *gun; - - gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - - if ( gun && gun->UseDecrement() ) - { - gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0f ); - gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001f ); - - if ( gun->m_flTimeWeaponIdle != 1000 ) - { - gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001f ); - } - - if ( gun->pev->fuser1 != 1000 ) - { - gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001f ); - } - - // Only decrement if not flagged as NO_DECREMENT -// if ( gun->m_flPumpTime != 1000 ) - // { - // gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001f ); - // } - - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - - m_flNextAttack -= gpGlobals->frametime; - if ( m_flNextAttack < -0.001 ) - m_flNextAttack = -0.001; - - if ( m_flNextAmmoBurn != 1000 ) - { - m_flNextAmmoBurn -= gpGlobals->frametime; - - if ( m_flNextAmmoBurn < -0.001 ) - m_flNextAmmoBurn = -0.001; - } - - if ( m_flAmmoStartCharge != 1000 ) - { - m_flAmmoStartCharge -= gpGlobals->frametime; - - if ( m_flAmmoStartCharge < -0.001 ) - m_flAmmoStartCharge = -0.001; - } -} - - -// checks if the spot is clear of players -BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) -{ - CBaseEntity *ent = NULL; - - if ( !pSpot->IsTriggered( pPlayer ) ) - { - return FALSE; - } - - AvHPlayer* thePlayer = dynamic_cast(pPlayer); - ASSERT(thePlayer); - - Vector theMinSize; - Vector theMaxSize; - thePlayer->GetSize(theMinSize, theMaxSize); - - int theOffset = AvHMUGetOriginOffsetForUser3(AvHUser3(thePlayer->pev->iuser3)); - Vector theOriginToSpawn = pSpot->pev->origin; - theOriginToSpawn.z += theOffset; - - if(!AvHSUGetIsEnoughRoomForHull(theOriginToSpawn, AvHMUGetHull(false, thePlayer->pev->iuser3), thePlayer->edict())) - return FALSE; - - //while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) - - // Assumes UTIL_FindEntityInSphere doesn't take size of other object into account. Players should be 2*HULL0_MAXX from each other, add another for safety - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 3*HULL0_MAXX)) != NULL ) - { - // if ent is a client, don't spawn on 'em (but dead players don't block) - if ( ent->IsPlayer() && (ent != pPlayer) && ent->IsAlive() ) - return FALSE; - - } - - return TRUE; -} - -BOOL CBasePlayer::IsAlive() const -{ - // Take into account spectators - return (pev->deadflag == DEAD_NO) && pev->health > 0; -} - -BOOL CBasePlayer::IsAlive(bool inIncludeSpectating) const -{ - // Take into account spectators - BOOL theIsAlive = this->IsAlive(); - if(inIncludeSpectating) - { - CBaseEntity* theSpectatingEntity = this->GetSpectatingEntity(); - if(theSpectatingEntity) - { - theIsAlive = theSpectatingEntity->IsAlive(); - } - } - - return theIsAlive; -} - -CBaseEntity* CBasePlayer::GetSpectatingEntity() const -{ - CBaseEntity* theSpectatingEntity = NULL; - - if(this->pev && this->pev->iuser1 && this->pev->iuser2) - { - int theEntityIndex = this->pev->iuser2; - theSpectatingEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theEntityIndex)); - } - - return theSpectatingEntity; -} - -void CBasePlayer::Spawn( void ) -{ - pev->classname = MAKE_STRING("player"); -// pev->health = 100; -// pev->armorvalue = 0; -// pev->max_health = pev->health; - pev->takedamage = DAMAGE_AIM; - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_WALK; - pev->flags &= FL_PROXY; // keep proxy flag sey by engine - pev->flags |= FL_CLIENT; - pev->air_finished = gpGlobals->time + 12; - pev->dmg = 2; // initial water damage - pev->effects = 0; - pev->deadflag = DEAD_NO; - pev->dmg_take = 0; - pev->dmg_save = 0; - pev->friction = 1.0; - pev->gravity = 1.0; - m_bitsHUDDamage = -1; - m_bitsDamageType = 0; - m_afPhysicsFlags = 0; - m_fLongJump = FALSE;// no longjump module. - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - pev->fov = m_iFOV = 0;// init field of view. - m_iClientFOV = -1; // make sure fov reset is sent - - m_flNextDecalTime = 0;// let this player decal as soon as he spawns. - - m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations - // are recieved by all clients - - m_flTimeStepSound = 0; - m_iStepLeft = 0; - m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. - - m_bloodColor = BLOOD_COLOR_RED; - m_flNextAttack = UTIL_WeaponTimeBase(); - StartSneaking(); - -// m_iFlashBattery = 99; -// m_flFlashLightTime = 1; // force first message - -// dont let uninitialized value here hurt the player - m_flFallVelocity = 0; - - GetGameRules()->SetDefaultPlayerTeam( this ); - edict_t* theSpawnPoint = GetGameRules()->SelectSpawnPoint( this ); - ASSERT(theSpawnPoint); - this->InitPlayerFromSpawn(theSpawnPoint); - - //AvHPlayer* thePlayer = dynamic_cast(this); - //char* thePlayerModel = thePlayer->GetPlayerModel(); - //SET_MODEL(ENT(pev), thePlayerModel); - SET_MODEL(ENT(pev), "models/player.mdl"); - - g_ulModelIndexPlayer = pev->modelindex; - //pev->sequence = LookupActivity( ACT_IDLE ); - pev->sequence = LookupSequence("idle1"); - - if ( FBitSet(pev->flags, FL_DUCKING) ) - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - - pev->view_ofs = VEC_VIEW; - Precache(); - m_HackedGunPos = Vector( 0, 32, 0 ); - - if ( m_iPlayerSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Couldn't alloc player sound slot!\n" ); - } - - m_fNoPlayerSound = FALSE;// normal sound behavior. - - m_pLastItem = NULL; - m_pLastItemName = 0; // Added by mmcguire. - - m_fInitHUD = TRUE; - m_iClientHideHUD = -1; // force this to be recalculated - m_fWeapon = FALSE; - m_pClientActiveItem = NULL; - m_iClientBattery = -1; - - // reset all ammo values to 0 - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - m_rgAmmo[i] = 0; - m_rgAmmoLast[i] = 0; // client ammo values also have to be reset (the death hud clear messages does on the client side) - } - - m_lastx = m_lasty = 0; - - m_flNextChatTime = gpGlobals->time; - - g_pGameRules->PlayerSpawn( this ); -} - - -void CBasePlayer :: Precache( void ) -{ - // in the event that the player JUST spawned, and the level node graph - // was loaded, fix all of the node graph pointers before the game starts. - - // !!!BUGBUG - now that we have multiplayer, this needs to be moved! - if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet ) - { - if ( !WorldGraph.FSetGraphPointers() ) - { - ALERT ( at_console, "**Graph pointers were not set!\n"); - } - else - { - ALERT ( at_console, "**Graph Pointers Set!\n" ); - } - } - - // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific) - // because they need to precache before any clients have connected - - Net_InitializeMessages(); - - // init geiger counter vars during spawn and each time - // we cross a level transition - - m_flgeigerRange = 1000; - m_igeigerRangePrev = 1000; - - m_bitsDamageType = 0; - m_bitsHUDDamage = -1; - - m_iClientBattery = -1; - - m_iTrain = TRAIN_NEW; - - m_iUpdateTime = 5; // won't update for 1/2 a second - - if ( gInitHUD ) - m_fInitHUD = TRUE; -} - - -int CBasePlayer::Save( CSave &save ) -{ - if ( !CBaseMonster::Save(save) ) - return 0; - - return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); -} - - -// -// Marks everything as new so the player will resend this to the hud. -// -void CBasePlayer::RenewItems(void) -{ - -} - -int CBasePlayer::Restore( CRestore &restore ) -{ - if ( !CBaseMonster::Restore(restore) ) - return 0; - - int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); - - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - // landmark isn't present. - if ( !pSaveData->fUseLandmark ) - { - ALERT( at_console, "No Landmark:%s\n", pSaveData->szLandmarkName ); - - // default to normal spawn - //edict_t* pentSpawnSpot = EntSelectSpawnPoint( this ); - ASSERT(FALSE); - //pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); - //pev->angles = VARS(pentSpawnSpot)->angles; - } - pev->v_angle.z = 0; // Clear out roll - pev->angles = pev->v_angle; - - pev->fixangle = TRUE; // turn this way immediately - -// Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; - - g_ulModelIndexPlayer = pev->modelindex; - - if ( FBitSet(pev->flags, FL_DUCKING) ) - { - // Use the crouch HACK - //FixPlayerCrouchStuck( edict() ); - // Don't need to do this with new player prediction code. - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - } - else - { - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - } - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - if ( m_fLongJump ) - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" ); - } - else - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - } - - RenewItems(); - - // HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it - // as just a counter. Ideally, this needs its own variable that's saved as a plain float. - // Barring that, we clear it out here instead of using the incorrect restored time value. - m_flNextAttack = UTIL_WeaponTimeBase(); - - return status; -} - - - -void CBasePlayer::SelectNextItem( int iItem ) -{ - CBasePlayerItem *pItem; - - pItem = m_rgpPlayerItems[ iItem ]; - - if (!pItem) - return; - - if (pItem == m_pActiveItem) - { - // select the next one in the chain - pItem = m_pActiveItem->m_pNext; - if (! pItem) - { - return; - } - - CBasePlayerItem *pLast; - pLast = pItem; - while (pLast->m_pNext) - pLast = pLast->m_pNext; - - // relink chain - pLast->m_pNext = m_pActiveItem; - m_pActiveItem->m_pNext = NULL; - m_rgpPlayerItems[ iItem ] = pItem; - } - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - { - m_pActiveItem->Holster( ); - } - - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); - } -} - -void CBasePlayer::SelectItem(const char *pstr) -{ - if (!pstr) - return; - - CBasePlayerItem *pItem = NULL; - - for (int i = 0; i < MAX_ITEM_TYPES; i++) - { - if (m_rgpPlayerItems[i]) - { - pItem = m_rgpPlayerItems[i]; - - while (pItem) - { - if (FClassnameIs(pItem->pev, pstr)) - break; - pItem = pItem->m_pNext; - } - } - - if (pItem) - break; - } - - if (!pItem) - return; - - - if ((pItem == m_pActiveItem) || (m_pActiveItem != NULL && !m_pActiveItem->CanHolster())) - return; - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - m_pLastItem = m_pActiveItem; - - if (m_pLastItem) - { - m_pLastItemName = m_pLastItem->pev->classname; - } - else - { - m_pLastItemName = 0; - } - - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); - } -} - -//note this should no longer be called, and asserts if used -void CBasePlayer::SelectLastItem(void) -{ - if (!m_pLastItem) - { - - // Try the last item name. - - if (m_pLastItemName != 0) - { - for (int i = 0; i < MAX_ITEM_TYPES; i++) - { - CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; - while (theCurrentItem) - { - if(FClassnameIs(theCurrentItem->pev, STRING(m_pLastItemName))) - { - m_pLastItem = theCurrentItem; - break; - } - theCurrentItem = theCurrentItem->m_pNext; - } - } - } - - } - - if (!m_pLastItem) - { - return; - } - - this->SelectItem(STRING(m_pLastItem->pev->classname)); //replaced copy-and-paste from SelectItem with actual SelectItem call -} - -BOOL CBasePlayer::HasItem(CBasePlayerItem* inWeapon) -{ - // Return true if we have a weapon of this type - bool theHasWeapon = false; - - for(int i = 0; (i < MAX_ITEM_TYPES) && !theHasWeapon; i++) - { - CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; - while(theCurrentItem && !theHasWeapon) - { - if(FClassnameIs(theCurrentItem->pev, STRING(inWeapon->pev->classname))) - { - theHasWeapon = true; - } - theCurrentItem = theCurrentItem->m_pNext; - } - } - - return theHasWeapon; -} - -BOOL CBasePlayer::HasItemWithFlag(int inFlag, CBasePlayerItem*& outItem) -{ - // Return true if we have a weapon of this type - bool theHasWeaponWithFlag = false; - - for(int i = 0; (i < MAX_ITEM_TYPES) && !theHasWeaponWithFlag; i++) - { - CBasePlayerItem* theCurrentItem = this->m_rgpPlayerItems[i]; - while(theCurrentItem && !theHasWeaponWithFlag) - { - ItemInfo theItemInfo; - theCurrentItem->GetItemInfo(&theItemInfo); - - int theFlags = theItemInfo.iFlags; - if(theFlags & inFlag) - { - theHasWeaponWithFlag = true; - outItem = theCurrentItem; - } - theCurrentItem = theCurrentItem->m_pNext; - } - } - - return theHasWeaponWithFlag; -} - -//============================================== -// HasWeapons - do I have any weapons at all? -//============================================== -BOOL CBasePlayer::HasWeapons( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return TRUE; - } - } - - return FALSE; -} - -void CBasePlayer::SelectPrevItem( int iItem ) -{ -} - - -char *CBasePlayer::TeamID( void ) -{ - if ( pev == NULL ) // Not fully connected yet - return ""; - - // return their team name - return m_szTeamName; -} - -void CBasePlayer::SetTeamID(const char* inTeamID) -{ - strncpy(this->m_szTeamName, inTeamID, TEAM_NAME_LENGTH); -} - -//============================================== -// !!!UNDONE:ultra temporary SprayCan entity to apply -// decal frame at a time. For PreAlpha CD -//============================================== -class CSprayCan : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Think( void ); - - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -void CSprayCan::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - pev->frame = 0; - - pev->nextthink = gpGlobals->time + 0.1; - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM); -} - -void CSprayCan::Think( void ) -{ - TraceResult tr; - int playernum; - int nFrames; - CBasePlayer *pPlayer; - - pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner); - - if (pPlayer) - nFrames = pPlayer->GetCustomDecalFrames(); - else - nFrames = -1; - - playernum = ENTINDEX(pev->owner); - - // ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames); - - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - // No customization present. - if (nFrames == -1) - { - UTIL_DecalTrace( &tr, DECAL_LAMBDA6 ); - UTIL_Remove( this ); - } - else - { - UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE ); - // Just painted last custom frame. - if ( pev->frame++ >= (nFrames - 1)) - UTIL_Remove( this ); - } - - pev->nextthink = gpGlobals->time + 0.1; -} - -class CBloodSplat : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Spray ( void ); -}; - -void CBloodSplat::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - - SetThink ( &CBloodSplat::Spray ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CBloodSplat::Spray ( void ) -{ - TraceResult tr; - - if ( g_Language != LANGUAGE_GERMAN ) - { - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - } - SetThink ( &CBloodSplat::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -} - -//============================================== - - - -void CBasePlayer::GiveNamedItem( const char *pszName, bool inSendMessage ) -{ - edict_t *pent; - - int istr = MAKE_STRING(pszName); - - pent = CREATE_NAMED_ENTITY(istr); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in GiveNamedItem!\n" ); - return; - } - VARS( pent )->origin = pev->origin; - pent->v.spawnflags |= SF_NORESPAWN; - - DispatchSpawn( pent ); - DispatchTouch( pent, ENT( pev ) ); - - if(inSendMessage) - { - CBaseEntity* theEntity = CBaseEntity::Instance(ENT(pent)); - ASSERT(theEntity); - CBasePlayerWeapon* theWeapon = dynamic_cast(theEntity); - //ASSERT(theWeapon); - if(theWeapon) - { - int theWeaponID = theWeapon->m_iId; - NetMsg_WeapPickup( pev, theWeaponID ); - } - } -} - - - -CBaseEntity *FindEntityForward( CBaseEntity *pMe ) -{ - TraceResult tr; - - UTIL_MakeVectors(pMe->pev->v_angle); - UTIL_TraceLine(pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 8192,dont_ignore_monsters, pMe->edict(), &tr ); - if ( tr.flFraction != 1.0 && !FNullEnt( tr.pHit) ) - { - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - return pHit; - } - return NULL; -} - - -BOOL CBasePlayer :: FlashlightIsOn( void ) -{ - return FBitSet(pev->effects, EF_DIMLIGHT); -} - -const float kFlashlightVolume = .3f; - -void CBasePlayer :: FlashlightTurnOn( void ) -{ - if ( !g_pGameRules->FAllowFlashlight() ) - { - return; - } - - if ( (pev->weapons & (1<effects, EF_DIMLIGHT); - - /*MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(1); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time;*/ - - } -} - - -void CBasePlayer :: FlashlightTurnOff( void ) -{ - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, kFlashlightVolume, ATTN_NORM, 0, PITCH_NORM ); - ClearBits(pev->effects, EF_DIMLIGHT); - - /*MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time;*/ - -} - -/* -=============== -ForceClientDllUpdate - -When recording a demo, we need to have the server tell us the entire client state -so that the client side .dll can behave correctly. -Reset stuff so that the state is transmitted. -=============== -*/ -void CBasePlayer :: ForceClientDllUpdate( void ) -{ - m_iClientHealth = -1; - m_iClientBattery = -1; - m_iTrain |= TRAIN_NEW; // Force new train message. - m_fWeapon = FALSE; // Force weapon send - m_fKnownItem = FALSE; // Force weaponinit messages. - m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message - - // Now force all the necessary messages - // to be sent. - UpdateClientData(); - // m_fWeapon = TRUE; // Force weapon send -} - -/* -============ -ImpulseCommands -============ -*/ -extern float g_flWeaponCheat; - -void CBasePlayer::ImpulseCommands( ) -{ - TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs - - int iImpulse = (int)pev->impulse; - switch (iImpulse) - { - case IMPULSE_FLASHLIGHT: - // temporary flashlight for level designers - if ( FlashlightIsOn() ) - { - FlashlightTurnOff(); - } - else - { - FlashlightTurnOn(); - } - break; - - case IMPULSE_SPRAYPAINT:// paint decal - - if ( gpGlobals->time < m_flNextDecalTime ) - { - // too early! - break; - } - - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr); - - if ( tr.flFraction != 1.0 ) - {// line hit something, so paint a decal - m_flNextDecalTime = gpGlobals->time + decalfrequency.value; - CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); - pCan->Spawn( pev ); - } - - break; -// HLDSDK 2.3 update -// case IMPULSE_DEMORECORD: // Demo recording, update client dll specific data again. -// ForceClientDllUpdate(); -// break; - default: - // check all of the cheat impulse commands now - CheatImpulseCommands( iImpulse ); - break; - } - - pev->impulse = 0; -} - -//========================================================= -//========================================================= -void CBasePlayer::CheatImpulseCommands( int iImpulse ) -{ -} - -// -// Add a weapon to the player (Item == Weapon == Selectable Object) -// -int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) -{ - CBasePlayerItem *pInsert; - - pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; - ItemInfo ii; - pItem->GetItemInfo(&ii); - - if ( pItem->iItemSlot() == 1 || ii.iId == AVH_WEAPON_MINE || ii.iId == AVH_WEAPON_WELDER) { - this->EffectivePlayerClassChanged(); - } - while (pInsert) - { - if (FClassnameIs( pInsert->pev, STRING( pItem->pev->classname) )) - { - if (pItem->AddDuplicate( pInsert )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - // ugly hack to update clip w/o an update clip message - pInsert->UpdateItemInfo( ); - if (m_pActiveItem) - m_pActiveItem->UpdateItemInfo( ); - - pItem->Kill( ); - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); - } - return FALSE; - } - pInsert = pInsert->m_pNext; - } - - if (pItem->AddToPlayer( this )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()]; - m_rgpPlayerItems[pItem->iItemSlot()] = pItem; - - // should we switch to this item? - if ( g_pGameRules->FShouldSwitchWeapon( this, pItem ) ) - { - SwitchWeapon( pItem ); - } - - return TRUE; - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); - } - return FALSE; -} - - - -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) -{ - - if (m_pActiveItem == pItem) - { - - ResetAutoaim( ); - pItem->Holster( ); - pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. - pItem->SetThink( NULL ); - m_pActiveItem = NULL; - pev->viewmodel = 0; - pev->weaponmodel = 0; - - } - else if ( m_pLastItem == pItem ) - m_pLastItem = NULL; - - AvHBasePlayerWeapon* theWeapon = dynamic_cast(pItem); - if(theWeapon) - { - ItemInfo theInfo; - theWeapon->GetItemInfo(&theInfo); - int theID = theInfo.iId; - this->pev->weapons &= ~(1<iItemSlot()]; - - if (pPrev == pItem) - { - m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext; - return TRUE; - } - else - { - while (pPrev && pPrev->m_pNext != pItem) - { - pPrev = pPrev->m_pNext; - } - if (pPrev) - { - pPrev->m_pNext = pItem->m_pNext; - return TRUE; - } - } - return FALSE; -} - - -// -// Returns the unique ID for the ammo, or -1 if error -// -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) -{ - if ( !szName ) - { - // no ammo. - return -1; - } - - if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) - { - // game rules say I can't have any more of this ammo type. - return -1; - } - - int i = 0; - - i = GetAmmoIndex( szName ); - - if ( i < 0 || i >= MAX_AMMO_SLOTS ) - return -1; - - int iAdd = min( iCount, iMax - m_rgAmmo[i] ); - if ( iAdd < 1 ) - return i; - - m_rgAmmo[ i ] += iAdd; - - - // Send the message that ammo has been picked up - NetMsg_AmmoPickup( pev, GetAmmoIndex(szName), iAdd ); - - TabulateAmmo(); - - return i; -} - - -/* -============ -ItemPreFrame - -Called every frame by the player PreThink -============ -*/ -void CBasePlayer::ItemPreFrame() -{ - if ( m_flNextAttack > 0 ) - { - return; - } - - if (!m_pActiveItem) - return; - - m_pActiveItem->ItemPreFrame( ); -} - - -/* -============ -ItemPostFrame - -Called every frame by the player PostThink -============ -*/ -void CBasePlayer::ItemPostFrame() -{ - static int fInSelect = FALSE; - - // check if the player is using a tank - if ( m_pTank != NULL ) - return; - - ImpulseCommands(); - - if ( m_flNextAttack > 0 ) - { - return; - } - - if (!m_pActiveItem) - return; - - // Only update weapon once game has started (no firing before then) - //if(GetGameRules()->GetGameStarted()) - //{ - this->m_pActiveItem->ItemPostFrame( ); - //} -} - -int CBasePlayer::AmmoInventory( int iAmmoIndex ) -{ - if (iAmmoIndex == -1) - { - return -1; - } - - return m_rgAmmo[ iAmmoIndex ]; -} - -int CBasePlayer::GetAmmoIndex(const char *psz) -{ - int i; - - if (!psz) - return -1; - - for (i = 1; i < MAX_AMMO_SLOTS; i++) - { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName ) - continue; - - if (stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0) - return i; - } - - return -1; -} - -int CBasePlayer::GetMaxWalkSpeed(void) const -{ - return 220; -} - -// Called from UpdateClientData -// makes sure the client has all the necessary ammo info, if values have changed -void CBasePlayer::SendAmmoUpdate(void) -{ - int theAmmoToSend[MAX_AMMO_SLOTS]; - memcpy(&theAmmoToSend, &this->m_rgAmmo, MAX_AMMO_SLOTS*sizeof(int)); - -// if(this->pev->iuser1 == OBS_IN_EYE) -// { -// CBasePlayer* theEntity = NULL; -// if(AvHSUGetEntityFromIndex(this->pev->iuser2, theEntity)) -// { -// memcpy(&theAmmoToSend, &theEntity->m_rgAmmo, MAX_AMMO_SLOTS*sizeof(int)); -// } -// } - - for (int i=0; i < MAX_AMMO_SLOTS;i++) - { - if (theAmmoToSend[i] != m_rgAmmoLast[i]) - { - m_rgAmmoLast[i] = theAmmoToSend[i]; - - // TODO: Fix me! - //ASSERT( m_rgAmmo[i] >= 0 ); - //ASSERT( m_rgAmmo[i] < 255 ); - if((theAmmoToSend[i] >= 0) && (theAmmoToSend[i] < 255)) - { - // send "Ammo" update message - NetMsg_AmmoX( pev, i, max( min( theAmmoToSend[i], 254 ), 0 ) ); - } - } - } -} - -/* -========================================================= - UpdateClientData - -resends any changed player HUD info to the client. -Called every frame by PlayerPreThink -Also called at start of demo recording and playback by -ForceClientDllUpdate to ensure the demo gets messages -reflecting all of the HUD state info. -========================================================= -*/ -void CBasePlayer :: UpdateClientData( void ) -{ - CBasePlayer* thePlayerToUseForWeaponUpdates = this; -// if(this->pev->iuser1 == OBS_IN_EYE) -// { -// CBasePlayer* theSpectatingPlayer = NULL; -// if(AvHSUGetEntityFromIndex(this->pev->iuser2, theSpectatingPlayer)) -// { -// thePlayerToUseForWeaponUpdates = theSpectatingPlayer; -// } -// } - - if (m_fInitHUD) - { - m_fInitHUD = FALSE; - gInitHUD = FALSE; - - NetMsg_ResetHUD( pev ); - - if ( !m_fGameHUDInitialized ) - { - NetMsg_InitHUD( pev ); - - g_pGameRules->InitHUD( this ); - m_fGameHUDInitialized = TRUE; - if ( g_pGameRules->IsMultiplayer() ) - { - FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); - } - } - FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); - - InitStatusBar(); - } - - if ( m_iHideHUD != m_iClientHideHUD ) - { - NetMsg_HideWeapon( pev, m_iHideHUD ); - m_iClientHideHUD = m_iHideHUD; - } - - if ( m_iFOV != m_iClientFOV ) - { - NetMsg_SetFOV( pev, m_iFOV ); - // cache FOV change at end of function, so weapon updates can see that FOV has changed - } - - // HACKHACK -- send the message to display the game title - if (gDisplayTitle) - { - NetMsg_ShowGameTitle( pev ); - gDisplayTitle = 0; - } - - if ((int)pev->health != m_iClientHealth) //: this cast to int is important, otherwise we spam the message, this is just a quick and easy fix. - { - NetMsg_Health( pev, max( pev->health, 0.0f ) ); - m_iClientHealth = (int)pev->health; - } - - if ((int)pev->armorvalue != m_iClientBattery) - { - NetMsg_Battery( pev, (int)pev->armorvalue ); - m_iClientBattery = (int)pev->armorvalue; - } - - if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType) - { - // Comes from inside me if not set - Vector damageOrigin = pev->origin; - // send "damage" message - // causes screen to flash, and pain compass to show direction of damage - edict_t *other = pev->dmg_inflictor; - if ( other ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(other); - if ( pEntity ) - damageOrigin = pEntity->Center(); - } - - // only send down damage type that have hud art - int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; - - float origin[] = { damageOrigin.x, damageOrigin.y, damageOrigin.z }; - NetMsg_Damage( pev, pev->dmg_save, pev->dmg_take, 0, origin ); - - pev->dmg_take = 0; - pev->dmg_save = 0; - m_bitsHUDDamage = m_bitsDamageType; - - // Clear off non-time-based damage indicators - m_bitsDamageType &= DMG_TIMEBASED; - } - - if (m_iTrain & TRAIN_NEW) - { - // send "health" update message - NetMsg_Train( pev, m_iTrain & 0xF ); - m_iTrain &= ~TRAIN_NEW; - } - - // - // New Weapon? - // - - bool forceCurWeaponUpdate = false; - - if (!m_fKnownItem) - { - - m_fKnownItem = TRUE; - - // WeaponInit Message - // byte = # of weapons - // - // for each weapon: - // byte name str length (not including null) - // bytes... name - // byte Ammo Type - // byte Ammo2 Type - // byte bucket - // byte bucket pos - // byte flags - // ???? Icons - - // Send ALL the weapon info now - this->SendWeaponUpdate(); - - // : HACK force an full curweapon update after each bunch of weaponlists sent - forceCurWeaponUpdate = true; - // : - } - - - SendAmmoUpdate(); - - // Update all the items - for ( int i = 0; i < MAX_ITEM_TYPES; i++ ) - { - if (forceCurWeaponUpdate == true) - m_fWeapon = FALSE; - if ( thePlayerToUseForWeaponUpdates->m_rgpPlayerItems[i] ) // each item updates it's successors - thePlayerToUseForWeaponUpdates->m_rgpPlayerItems[i]->UpdateClientData( thePlayerToUseForWeaponUpdates ); - } - if (forceCurWeaponUpdate == true) - m_fWeapon = TRUE; - - // Cache and client weapon change - m_pClientActiveItem = thePlayerToUseForWeaponUpdates->m_pActiveItem; - m_iClientFOV = thePlayerToUseForWeaponUpdates->m_iFOV; - - // Update Status Bar if we're playing - AvHPlayer* thePlayer = dynamic_cast(this); - if(thePlayer && (thePlayer->GetPlayMode() == PLAYMODE_PLAYING)) - { - if ( m_flNextSBarUpdateTime < gpGlobals->time ) - { - UpdateStatusBar(); - m_flNextSBarUpdateTime = gpGlobals->time + 0.2; - } - } -} - -void CBasePlayer::SendWeaponUpdate() -{ - int i; - - for (i = 0; i < MAX_WEAPONS; i++) - { - ItemInfo& II = CBasePlayerItem::ItemInfoArray[i]; - - if ( !II.iId ) - continue; - - const char *pszName; - if (!II.pszName) - pszName = "Empty"; - else - pszName = II.pszName; - - WeaponList weapon; - weapon.weapon_name = pszName; - weapon.ammo1_type = GetAmmoIndex(II.pszAmmo1); - weapon.ammo2_type = GetAmmoIndex(II.pszAmmo2); - weapon.ammo1_max_amnt = II.iMaxAmmo1; - weapon.ammo2_max_amnt = II.iMaxAmmo2; - weapon.bucket = II.iSlot; - weapon.bucket_pos = II.iPosition; - weapon.bit_index = II.iId; - weapon.flags = II.iFlags; - - NetMsg_WeaponList( pev, weapon ); - } - -} - -//========================================================= -// FBecomeProne - Overridden for the player to set the proper -// physics flags when a barnacle grabs player. -//========================================================= -BOOL CBasePlayer :: FBecomeProne ( void ) -{ - m_afPhysicsFlags |= PFLAG_ONBARNACLE; - return TRUE; -} - -//========================================================= -// BarnacleVictimBitten - bad name for a function that is called -// by Barnacle victims when the barnacle pulls their head -// into its mouth. For the player, just die. -//========================================================= -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) -{ - TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); -} - -//========================================================= -// BarnacleVictimReleased - overridden for player who has -// physics flags concerns. -//========================================================= -void CBasePlayer :: BarnacleVictimReleased ( void ) -{ - m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; -} - - -//========================================================= -// Illumination -// return player light level plus virtual muzzle flash -//========================================================= -int CBasePlayer :: Illumination( void ) -{ - int iIllum = CBaseEntity::Illumination( ); - - iIllum += m_iWeaponFlash; - if (iIllum > 255) - return 255; - return iIllum; -} - - -void CBasePlayer :: EnableControl(BOOL fControl) -{ - if (!fControl) - pev->flags |= FL_FROZEN; - else - pev->flags &= ~FL_FROZEN; - -} - - -#define DOT_1DEGREE 0.9998476951564 -#define DOT_2DEGREE 0.9993908270191 -#define DOT_3DEGREE 0.9986295347546 -#define DOT_4DEGREE 0.9975640502598 -#define DOT_5DEGREE 0.9961946980917 -#define DOT_6DEGREE 0.9945218953683 -#define DOT_7DEGREE 0.9925461516413 -#define DOT_8DEGREE 0.9902680687416 -#define DOT_9DEGREE 0.9876883405951 -#define DOT_10DEGREE 0.9848077530122 -#define DOT_15DEGREE 0.9659258262891 -#define DOT_20DEGREE 0.9396926207859 -#define DOT_25DEGREE 0.9063077870367 - -//========================================================= -// Autoaim -// set crosshair position to point to enemey -//========================================================= -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) -{ - if (g_iSkillLevel == SKILL_HARD) - { - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - return gpGlobals->v_forward; - } - - Vector vecSrc = GetGunPosition( ); - float flDist = 8192; - - // always use non-sticky autoaim - // UNDONE: use sever variable to chose! - if (1 || g_iSkillLevel == SKILL_MEDIUM) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - // flDelta *= 0.5; - } - - BOOL m_fOldTargeting = m_fOnTarget; - Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta ); - - // update ontarget if changed - if ( !g_pGameRules->AllowAutoTargetCrosshair() ) - m_fOnTarget = 0; - else if (m_fOldTargeting != m_fOnTarget) - { - m_pActiveItem->UpdateItemInfo( ); - } - - if (angles.x > 180) - angles.x -= 360; - if (angles.x < -180) - angles.x += 360; - if (angles.y > 180) - angles.y -= 360; - if (angles.y < -180) - angles.y += 360; - - if (angles.x > 25) - angles.x = 25; - if (angles.x < -25) - angles.x = -25; - if (angles.y > 12) - angles.y = 12; - if (angles.y < -12) - angles.y = -12; - - - // always use non-sticky autoaim - // UNDONE: use sever variable to chose! - if (0 || g_iSkillLevel == SKILL_EASY) - { - m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33; - } - else - { - m_vecAutoAim = angles * 0.9; - } - - // m_vecAutoAim = m_vecAutoAim * 0.99; - - // Don't send across network if sv_aim is 0 - if ( g_psv_aim->value != 0 ) - { - if ( m_vecAutoAim.x != m_lastx || - m_vecAutoAim.y != m_lasty ) - { - SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); - - m_lastx = m_vecAutoAim.x; - m_lasty = m_vecAutoAim.y; - } - } - - // ALERT( at_console, "%f %f\n", angles.x, angles.y ); - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - return gpGlobals->v_forward; -} - - -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - float bestdot; - Vector bestdir; - edict_t *bestent; - TraceResult tr; - - if ( g_psv_aim->value == 0 ) - { - m_fOnTarget = FALSE; - return g_vecZero; - } - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - - // try all possible entities - bestdir = gpGlobals->v_forward; - bestdot = flDelta; // +- 10 degrees - bestent = NULL; - - m_fOnTarget = FALSE; - - UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr ); - - - if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO) - { - // don't look through water - if (!((pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3) - || (pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0))) - { - if (tr.pHit->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return m_vecAutoAim; - } - } - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - Vector center; - Vector dir; - float dot; - - if ( pEdict->free ) // Not in use - continue; - - if (pEdict->v.takedamage != DAMAGE_AIM) - continue; - if (pEdict == edict()) - continue; -// if (pev->team > 0 && pEdict->v.team == pev->team) -// continue; // don't aim at teammate - if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) - continue; - - pEntity = Instance( pEdict ); - if (pEntity == NULL) - continue; - - if (!pEntity->IsAlive()) - continue; - - // don't look through water - if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - continue; - - center = pEntity->BodyTarget( vecSrc ); - - dir = (center - vecSrc).Normalize( ); - - // make sure it's in front of the player - if (DotProduct (dir, gpGlobals->v_forward ) < 0) - continue; - - dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) - + fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5; - - // tweek for distance - dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist); - - if (dot > bestdot) - continue; // to far to turn - - UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr ); - if (tr.flFraction != 1.0 && tr.pHit != pEdict) - { - // ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) ); - continue; - } - - // don't shoot at friends - if (IRelationship( pEntity ) < 0) - { - if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch()) - // ALERT( at_console, "friend\n"); - continue; - } - - // can shoot at this one - bestdot = dot; - bestent = pEdict; - bestdir = dir; - } - - if (bestent) - { - bestdir = UTIL_VecToAngles (bestdir); - bestdir.x = -bestdir.x; - bestdir = bestdir - pev->v_angle - pev->punchangle; - - if (bestent->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return bestdir; - } - - return Vector( 0, 0, 0 ); -} - - -void CBasePlayer :: ResetAutoaim( ) -{ - if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - SET_CROSSHAIRANGLE( edict(), 0, 0 ); - } - m_fOnTarget = FALSE; -} - -/* -============= -SetCustomDecalFrames - - UNDONE: Determine real frame limit, 8 is a placeholder. - Note: -1 means no custom frames present. -============= -*/ -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) -{ - if (nFrames > 0 && - nFrames < 8) - m_nCustomSprayFrames = nFrames; - else - m_nCustomSprayFrames = -1; -} - -/* -============= -GetCustomDecalFrames - - Returns the # of custom frames this player's custom clan logo contains. -============= -*/ -int CBasePlayer :: GetCustomDecalFrames( void ) -{ - return m_nCustomSprayFrames; -} - - -//========================================================= -// DropPlayerItem - drop the named item, or if no name, -// the active item. -//========================================================= -void CBasePlayer::DropPlayerItem ( char *pszItemName ) -{ - if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) ) - { - // no dropping in single player. - return; - } - - if ( !strlen( pszItemName ) ) - { - // if this string has no length, the client didn't type a name! - // assume player wants to drop the active item. - // make the string null to make future operations in this function easier - pszItemName = NULL; - } - - CBasePlayerItem *pWeapon; - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - if ( pszItemName ) - { - // try to match by name. - const char* theWeaponClassName = STRING( pWeapon->pev->classname ); - if ( !strcmp( pszItemName, theWeaponClassName) ) - { - // match! - break; - } - } - else - { - // trying to drop active item - if ( pWeapon == m_pActiveItem ) - { - // active item! - break; - } - } - - pWeapon = pWeapon->m_pNext; - } - - - // if we land here with a valid pWeapon pointer, that's because we found the - // item we want to drop and hit a BREAK; pWeapon is the item. - if ( pWeapon ) - { - g_pGameRules->GetNextBestWeapon( this, pWeapon ); - - UTIL_MakeVectors ( pev->angles ); - - pev->weapons &= ~(1<m_iId);// take item off hud - - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() ); - pWeaponBox->pev->angles.x = 0; - pWeaponBox->pev->angles.z = 0; - pWeaponBox->PackWeapon( pWeapon ); - pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; - - // drop half of the ammo for this weapon. - int iAmmoIndex; - - iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ??? - - if ( iAmmoIndex != -1 ) - { - // this weapon weapon uses ammo, so pack an appropriate amount. - if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE ) - { - // pack up all the ammo, this weapon is its own ammo type - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] ); - m_rgAmmo[ iAmmoIndex ] = 0; - - } - else - { - // pack half of the ammo - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] / 2 ); - m_rgAmmo[ iAmmoIndex ] /= 2; - } - - } - - return;// we're done, so stop searching with the FOR loop. - } - } -} - -//========================================================= -// HasPlayerItem Does the player already have this item? -//========================================================= -BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) -{ - CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// HasNamedPlayerItem Does the player already have this item? -//========================================================= -CBasePlayerItem* CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) -{ - CBasePlayerItem *pReturn = NULL; - CBasePlayerItem *pItem = NULL; - int i; - - for ( i = 0 ; (i < MAX_ITEM_TYPES) && !pReturn ; i++ ) - { - pItem = m_rgpPlayerItems[ i ]; - - while (pItem && !pReturn) - { - if ( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) ) - { - pReturn = pItem; - } - pItem = pItem->m_pNext; - } - } - - return pReturn; -} - -//========================================================= -// -//========================================================= -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) - { - return FALSE; - } - - ResetAutoaim( ); - - if (m_pActiveItem) - { - m_pActiveItem->Holster( ); - } - - m_pActiveItem = pWeapon; - pWeapon->Deploy( ); - - return TRUE; -} - -//========================================================= -// Dead HEV suit prop -//========================================================= -class CDeadHEV : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[4]; -}; - -char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" }; - -void CDeadHEV::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ); - -//========================================================= -// ********** DeadHEV SPAWN ********** -//========================================================= -void CDeadHEV :: Spawn( void ) -{ - PRECACHE_MODEL("models/player.mdl"); - SET_MODEL(ENT(pev), "models/player.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - pev->body = 1; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead hevsuit with bad pose\n" ); - pev->sequence = 0; - pev->effects = EF_BRIGHTFIELD; - } - - // Corpses have less health - pev->health = 8; - - MonsterInitDead(); -} - - -class CStripWeapons : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: -}; - -LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ); - -void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pActivator; - } - else if ( !g_pGameRules->IsDeathmatch() ) - { - pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - } - - if ( pPlayer ) - pPlayer->RemoveAllItems( FALSE ); -} - - -class CRevertSaved : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MessageThink( void ); - void EXPORT LoadThink( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - inline float MessageTime( void ) { return m_messageTime; } - inline float LoadTime( void ) { return m_loadTime; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } - inline void SetMessageTime( float time ) { m_messageTime = time; } - inline void SetLoadTime( float time ) { m_loadTime = time; } - -private: - float m_messageTime; - float m_loadTime; -}; - -LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ); - -TYPEDESCRIPTION CRevertSaved::m_SaveData[] = -{ - DEFINE_FIELD( CRevertSaved, m_messageTime, FIELD_FLOAT ), // These are not actual times, but durations, so save as floats - DEFINE_FIELD( CRevertSaved, m_loadTime, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ); - -void CRevertSaved :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagetime")) - { - SetMessageTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "loadtime")) - { - SetLoadTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); - pev->nextthink = gpGlobals->time + MessageTime(); - SetThink( &CRevertSaved::MessageThink ); -} - - -void CRevertSaved :: MessageThink( void ) -{ - UTIL_ShowMessageAll( STRING(pev->message) ); - float nextThink = LoadTime() - MessageTime(); - if ( nextThink > 0 ) - { - pev->nextthink = gpGlobals->time + nextThink; - SetThink( &CRevertSaved::LoadThink ); - } - else - LoadThink(); -} - - -void CRevertSaved :: LoadThink( void ) -{ - if ( !gpGlobals->deathmatch ) - { - SERVER_COMMAND("reload\n"); - } -} - - -//========================================================= -// Multiplayer intermission spots. -//========================================================= -class CInfoIntermission:public CPointEntity -{ - void Spawn( void ); - void Think( void ); -}; - -void CInfoIntermission::Spawn( void ) -{ - UTIL_SetOrigin( pev, pev->origin ); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - pev->v_angle = g_vecZero; - - pev->nextthink = gpGlobals->time + 2;// let targets spawn! - -} - -void CInfoIntermission::Think ( void ) -{ - edict_t *pTarget; - - // find my target - pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); - - if ( !FNullEnt(pTarget) ) - { - pev->v_angle = UTIL_VecToAngles( (pTarget->v.origin - pev->origin).Normalize() ); - pev->v_angle.x = -pev->v_angle.x; - } -} - -LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ); - diff --git a/main/source/dlls/player.h b/main/source/dlls/player.h index 49456762..c1689439 100644 --- a/main/source/dlls/player.h +++ b/main/source/dlls/player.h @@ -1,381 +1,381 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLAYER_H -#define PLAYER_H - - -#include "../pm_shared/pm_materials.h" - - -#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet -#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet -#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. -#define PLAYER_MIN_BOUNCE_SPEED 200 -#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. - -// -// Player PHYSICS FLAGS bits -// -#define PFLAG_ONLADDER ( 1<<0 ) -#define PFLAG_ONSWING ( 1<<0 ) -#define PFLAG_ONTRAIN ( 1<<1 ) -#define PFLAG_ONBARNACLE ( 1<<2 ) -#define PFLAG_DUCKING ( 1<<3 ) // In the process of ducking, but totally squatted yet -#define PFLAG_USING ( 1<<4 ) // Using a continuous entity -#define PFLAG_OBSERVER ( 1<<5 ) // player is locked in stationary cam mode. Spectators can move, observers can't. - -// -// generic player -// -//----------------------------------------------------- -//This is Half-Life player entity -//----------------------------------------------------- -#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time - -#define SUIT_GROUP TRUE -#define SUIT_SENTENCE FALSE - -#define SUIT_REPEAT_OK 0 -#define SUIT_NEXT_IN_30SEC 30 -#define SUIT_NEXT_IN_1MIN 60 -#define SUIT_NEXT_IN_5MIN 300 -#define SUIT_NEXT_IN_10MIN 600 -#define SUIT_NEXT_IN_30MIN 1800 -#define SUIT_NEXT_IN_1HOUR 3600 - -#define CSUITNOREPEAT 32 - -#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" -#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" - -#define TEAM_NAME_LENGTH 16 - -typedef enum -{ - PLAYER_IDLE, - PLAYER_WALK, - PLAYER_JUMP, - PLAYER_SUPERJUMP, - PLAYER_DIE, - PLAYER_ATTACK1, - PLAYER_RELOAD, - PLAYER_PRIME, - PLAYER_RELOAD_START, - PLAYER_RELOAD_INSERT, - PLAYER_RELOAD_END -} PLAYER_ANIM; - -#define MAX_ID_RANGE 2048 -#define SBAR_STRING_SIZE 128 - -enum sbar_data -{ - SBAR_ID_TARGETNAME = 1, - SBAR_ID_TARGETHEALTH, - SBAR_ID_TARGETARMOR, - SBAR_ID_TARGETLEVEL, - SBAR_END, -}; - -#define CHAT_INTERVAL 1.0f -class CBasePlayer : public CBaseMonster -{ -public: - int random_seed; // See that is shared between client & server for shared weapons code - - int m_iPlayerSound;// the index of the sound list slot reserved for this player - int m_iTargetVolume;// ideal sound volume. - int m_iWeaponVolume;// how loud the player's weapon is right now. - int m_iExtraSoundTypes;// additional classification for this weapon's sound - int m_iWeaponFlash;// brightness of the weapon flash - float m_flStopExtraSoundTime; - -// float m_flFlashLightTime; // Time until next battery draw/Recharge -// int m_iFlashBattery; // Flashlight Battery Draw - - int m_afButtonLast; - int m_afButtonPressed; - int m_afButtonReleased; - - edict_t *m_pentSndLast; // last sound entity to modify player room type - float m_flSndRoomtype; // last roomtype set by sound entity - float m_flSndRange; // dist from player to sound entity - - float m_flFallVelocity; - - int m_rgItems[MAX_ITEMS]; - int m_fKnownItem; // True when a new item needs to be added - int m_fNewAmmo; // True when a new item has been added - - unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden - float m_fNextSuicideTime; // the time after which the player can next use the suicide command - - -// these are time-sensitive things that we keep track of - float m_flTimeStepSound; // when the last stepping sound was made - float m_flTimeWeaponIdle; // when to play another weapon idle animation. - float m_flSwimTime; // how long player has been underwater - float m_flDuckTime; // how long we've been ducking - float m_flWallJumpTime; // how long until next walljump - - float m_flSuitUpdate; // when to play next suit update - int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update - int m_iSuitPlayNext; // next sentence slot for queue storage; - int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list - float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat - int m_lastDamageAmount; // Last damage taken - float m_tbdPrev; // Time-based damage timer - - float m_flgeigerRange; // range to nearest radiation source - float m_flgeigerDelay; // delay per update of range msg to client - int m_igeigerRangePrev; - int m_iStepLeft; // alternate left/right foot stepping sound - char m_szTextureName[CBTEXTURENAMEMAX]; // current texture name we're standing on - char m_chTextureType; // current texture type - - int m_idrowndmg; // track drowning damage taken - int m_idrownrestored; // track drowning damage restored - - int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to - // the hude via the DAMAGE message - BOOL m_fInitHUD; // True when deferred HUD restart msg needs to be sent - BOOL m_fGameHUDInitialized; - int m_iTrain; // Train control position - BOOL m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info - - EHANDLE m_pTank; // the tank which the player is currently controlling, NULL if no tank - float m_fDeadTime; // the time at which the player died (used in PlayerDeathThink()) - - BOOL m_fNoPlayerSound; // a debugging feature. Player makes no sound if this is true. - BOOL m_fLongJump; // does this player have the longjump module? - - float m_tSneaking; - int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages - int m_iClientHealth; // the health currently known by the client. If this changes, send a new - int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new - int m_iHideHUD; // the players hud weapon info is to be hidden - int m_iClientHideHUD; - int m_iFOV; // field of view - int m_iClientFOV; // client's known FOV - // usable player items - CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; - CBasePlayerItem *m_pActiveItem; - CBasePlayerItem *m_pClientActiveItem; // client version of the active item - CBasePlayerItem *m_pLastItem; - // Added by mmcguire. - string_t m_pLastItemName; - - - // shared ammo slots - int m_rgAmmo[MAX_AMMO_SLOTS]; - int m_rgAmmoLast[MAX_AMMO_SLOTS]; - - Vector m_vecAutoAim; - BOOL m_fOnTarget; - int m_iDeaths; - float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn - - int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE - - int m_nCustomSprayFrames;// Custom clan logo frames for this player - float m_flNextDecalTime;// next time this player can spray a decal - - char m_szTeamName[TEAM_NAME_LENGTH]; - - virtual void Spawn( void ); - void Pain( void ); - -// virtual void Think( void ); - virtual void Jump( void ); - virtual void Duck( void ); - virtual void PreThink( void ); - virtual void PostThink( void ); - virtual Vector GetGunPosition( void ); - virtual int GetMaxWalkSpeed(void) const; - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) + pev->view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); }; // position to shoot at - virtual void StartSneaking( void ) { m_tSneaking = gpGlobals->time - 1; } - virtual void StopSneaking( void ) { m_tSneaking = gpGlobals->time + 30; } - virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } - virtual BOOL IsAlive() const; - virtual BOOL IsAlive(bool inIncludeSpectating) const; - virtual BOOL ShouldFadeOnDeath( void ) { return FALSE; } - void SpawnClientSideCorpse(); - virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned - - virtual BOOL IsNetClient( void ) { return !(pev->flags & FL_FAKECLIENT); } // Bots should return FALSE for this, they can't receive NET messages - // Spectators should return TRUE for this - virtual char *TeamID(void); - virtual void SetTeamID(const char* inTeamID); - virtual int GetEffectivePlayerClass() { return 0; } - virtual int GetAuthenticationMask() { return 0; } - virtual void EffectivePlayerClassChanged(); - virtual void NeedsTeamUpdate(); - virtual void SendTeamUpdate(); - virtual void SendWeaponUpdate(); - - virtual void InitPlayerFromSpawn(edict_t* inSpawn); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void RenewItems(void); - virtual void PackDeadPlayerItems( void ); - void DestroyAllItems( BOOL removeSuit ); - void RemoveAllItems( BOOL removeSuit ); - BOOL SwitchWeapon( CBasePlayerItem *pWeapon ); - - // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) - virtual void UpdateClientData( void ); - - static TYPEDESCRIPTION m_playerSaveData[]; - - // Player is moved across the transition by other means - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual void Precache( void ); - BOOL IsOnLadder( void ); - BOOL FlashlightIsOn( void ); - void FlashlightTurnOn( void ); - void FlashlightTurnOff( void ); - - void UpdatePlayerSound ( void ); - void DeathSound ( void ); - - int Classify ( void ); - virtual void GetAnimationForActivity(int inActivity, char outAnimation[64], bool inGaitSequence = false) { strcpy(outAnimation, ""); }; - void SetAnimation( PLAYER_ANIM playerAnim ); - void SetWeaponAnimType( const char *szExtention ); - char m_szAnimExtention[32]; - - // custom player functions - virtual void ImpulseCommands( void ); - void CheatImpulseCommands( int iImpulse ); - - void StartDeathCam( void ); - virtual void StartObserver( Vector vecPosition, Vector vecViewAngle ); - virtual void StopObserver(); - - // Observer camera - bool Observer_FindNextPlayer(bool inReverse = false); - void Observer_HandleButtons(); - void Observer_SetMode( int iMode ); - void Observer_SpectatePlayer( int idx); - - EHANDLE m_hObserverTarget; - float m_flNextObserverInput; - int IsObserver() const { return pev->iuser1; }; - - virtual float GetAdrenalineFactor() const { return 0.0f; } - - virtual void AddPoints( int score, BOOL bAllowNegativeScore ); - virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); - BOOL AddPlayerItem( CBasePlayerItem *pItem ); - BOOL RemovePlayerItem( CBasePlayerItem *pItem ); - void DropPlayerItem ( char *pszItemName ); - BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); - CBasePlayerItem* HasNamedPlayerItem( const char *pszItemName ); - BOOL HasItem(CBasePlayerItem* inWeapon); - BOOL HasItemWithFlag(int inFlag, CBasePlayerItem*& outItem); - BOOL HasWeapons( void );// do I have ANY weapons? - void SelectPrevItem( int iItem ); - void SelectNextItem( int iItem ); - void SelectLastItem(void); - void SelectItem(const char *pstr); - void ItemPreFrame( void ); - virtual void ItemPostFrame( void ); - - virtual void GiveNamedItem( const char *szName, bool inSendMessage = false); - void EnableControl(BOOL fControl); - - virtual int GiveAmmo( int iAmount, char *szName, int iMax ); - void SendAmmoUpdate(void); - - void WaterMove( void ); - virtual void Suicide(); - void EXPORT PlayerDeathThink( void ); - void EXPORT SuicideThink(void); - void PlayerUse( void ); - void ClearKeys( void); - - void CheckSuitUpdate(); - void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); - void UpdateGeigerCounter( void ); - void CheckTimeBasedDamage( void ); - - BOOL FBecomeProne ( void ); - void BarnacleVictimBitten ( entvars_t *pevBarnacle ); - void BarnacleVictimReleased ( void ); - static int GetAmmoIndex(const char *psz); - int AmmoInventory( int iAmmoIndex ); - int Illumination( void ); - - void ResetAutoaim( void ); - Vector GetAutoaimVector( float flDelta ); - Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ); - - void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. - - void DeathMessage( entvars_t *pevKiller ); - - void SetCustomDecalFrames( int nFrames ); - int GetCustomDecalFrames( void ); - - void CBasePlayer::TabulateAmmo( void ); - - float m_flStartCharge; - float m_flAmmoStartCharge; - float m_flPlayAftershock; - float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo? - //Player ID - void InitStatusBar( void ); - void UpdateStatusBar( void ); - int m_izSBarState[ SBAR_END ]; - float m_flNextSBarUpdateTime; - float m_flStatusBarDisappearDelay; - char m_SbarString0[ SBAR_STRING_SIZE ]; - char m_SbarString1[ SBAR_STRING_SIZE ]; - - float m_flNextChatTime; - int m_DefaultSpectatingMode; - int m_DefaultSpectatingTarget; - - CBaseEntity* GetSpectatingEntity() const; - int GetDefaultSpectatingMode() const { return this->m_DefaultSpectatingMode; } - int GetDefaultSpectatingTarget() const { return this->m_DefaultSpectatingTarget; } - void SetDefaultSpectatingSettings(int inSpectatingMode, int inDefaultSpectatingTarget = -1) { this->m_DefaultSpectatingMode = inSpectatingMode; this->m_DefaultSpectatingTarget = inDefaultSpectatingTarget; } - - // Added by mmcguire. - virtual bool GetCanUseWeapon() const { return true; } - -}; - -#define AUTOAIM_2DEGREES 0.0348994967025 -#define AUTOAIM_5DEGREES 0.08715574274766 -#define AUTOAIM_8DEGREES 0.1391731009601 -#define AUTOAIM_10DEGREES 0.1736481776669 - - -extern int gmsgHudText; -extern BOOL gInitHUD; - -// HLSDK 2.3 update -//// Observer Movement modes (stored in pev->iuser1, so the physics code can get at them) -//#define OBS_CHASE_LOCKED 1 -//#define OBS_CHASE_FREE 2 -//#define OBS_ROAMING 3 - -#endif // PLAYER_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PLAYER_H +#define PLAYER_H + + +#include "../pm_shared/pm_materials.h" + + +#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet +#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet +#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. +#define PLAYER_MIN_BOUNCE_SPEED 200 +#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. + +// +// Player PHYSICS FLAGS bits +// +#define PFLAG_ONLADDER ( 1<<0 ) +#define PFLAG_ONSWING ( 1<<0 ) +#define PFLAG_ONTRAIN ( 1<<1 ) +#define PFLAG_ONBARNACLE ( 1<<2 ) +#define PFLAG_DUCKING ( 1<<3 ) // In the process of ducking, but totally squatted yet +#define PFLAG_USING ( 1<<4 ) // Using a continuous entity +#define PFLAG_OBSERVER ( 1<<5 ) // player is locked in stationary cam mode. Spectators can move, observers can't. + +// +// generic player +// +//----------------------------------------------------- +//This is Half-Life player entity +//----------------------------------------------------- +#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time + +#define SUIT_GROUP TRUE +#define SUIT_SENTENCE FALSE + +#define SUIT_REPEAT_OK 0 +#define SUIT_NEXT_IN_30SEC 30 +#define SUIT_NEXT_IN_1MIN 60 +#define SUIT_NEXT_IN_5MIN 300 +#define SUIT_NEXT_IN_10MIN 600 +#define SUIT_NEXT_IN_30MIN 1800 +#define SUIT_NEXT_IN_1HOUR 3600 + +#define CSUITNOREPEAT 32 + +#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" +#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" + +#define TEAM_NAME_LENGTH 16 + +typedef enum +{ + PLAYER_IDLE, + PLAYER_WALK, + PLAYER_JUMP, + PLAYER_SUPERJUMP, + PLAYER_DIE, + PLAYER_ATTACK1, + PLAYER_RELOAD, + PLAYER_PRIME, + PLAYER_RELOAD_START, + PLAYER_RELOAD_INSERT, + PLAYER_RELOAD_END +} PLAYER_ANIM; + +#define MAX_ID_RANGE 2048 +#define SBAR_STRING_SIZE 128 + +enum sbar_data +{ + SBAR_ID_TARGETNAME = 1, + SBAR_ID_TARGETHEALTH, + SBAR_ID_TARGETARMOR, + SBAR_ID_TARGETLEVEL, + SBAR_END, +}; + +#define CHAT_INTERVAL 1.0f +class CBasePlayer : public CBaseMonster +{ +public: + int random_seed; // See that is shared between client & server for shared weapons code + + int m_iPlayerSound;// the index of the sound list slot reserved for this player + int m_iTargetVolume;// ideal sound volume. + int m_iWeaponVolume;// how loud the player's weapon is right now. + int m_iExtraSoundTypes;// additional classification for this weapon's sound + int m_iWeaponFlash;// brightness of the weapon flash + float m_flStopExtraSoundTime; + +// float m_flFlashLightTime; // Time until next battery draw/Recharge +// int m_iFlashBattery; // Flashlight Battery Draw + + int m_afButtonLast; + int m_afButtonPressed; + int m_afButtonReleased; + + edict_t *m_pentSndLast; // last sound entity to modify player room type + float m_flSndRoomtype; // last roomtype set by sound entity + float m_flSndRange; // dist from player to sound entity + + float m_flFallVelocity; + + int m_rgItems[MAX_ITEMS]; + int m_fKnownItem; // True when a new item needs to be added + int m_fNewAmmo; // True when a new item has been added + + unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden + float m_fNextSuicideTime; // the time after which the player can next use the suicide command + + +// these are time-sensitive things that we keep track of + float m_flTimeStepSound; // when the last stepping sound was made + float m_flTimeWeaponIdle; // when to play another weapon idle animation. + float m_flSwimTime; // how long player has been underwater + float m_flDuckTime; // how long we've been ducking + float m_flWallJumpTime; // how long until next walljump + + float m_flSuitUpdate; // when to play next suit update + int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update + int m_iSuitPlayNext; // next sentence slot for queue storage; + int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list + float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat + int m_lastDamageAmount; // Last damage taken + float m_tbdPrev; // Time-based damage timer + + float m_flgeigerRange; // range to nearest radiation source + float m_flgeigerDelay; // delay per update of range msg to client + int m_igeigerRangePrev; + int m_iStepLeft; // alternate left/right foot stepping sound + char m_szTextureName[CBTEXTURENAMEMAX]; // current texture name we're standing on + char m_chTextureType; // current texture type + + int m_idrowndmg; // track drowning damage taken + int m_idrownrestored; // track drowning damage restored + + int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to + // the hude via the DAMAGE message + BOOL m_fInitHUD; // True when deferred HUD restart msg needs to be sent + BOOL m_fGameHUDInitialized; + int m_iTrain; // Train control position + BOOL m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info + + EHANDLE m_pTank; // the tank which the player is currently controlling, NULL if no tank + float m_fDeadTime; // the time at which the player died (used in PlayerDeathThink()) + + BOOL m_fNoPlayerSound; // a debugging feature. Player makes no sound if this is true. + BOOL m_fLongJump; // does this player have the longjump module? + + float m_tSneaking; + int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages + int m_iClientHealth; // the health currently known by the client. If this changes, send a new + int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new + int m_iHideHUD; // the players hud weapon info is to be hidden + int m_iClientHideHUD; + int m_iFOV; // field of view + int m_iClientFOV; // client's known FOV + // usable player items + CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; + CBasePlayerItem *m_pActiveItem; + CBasePlayerItem *m_pClientActiveItem; // client version of the active item + CBasePlayerItem *m_pLastItem; + // Added by mmcguire. + string_t m_pLastItemName; + + + // shared ammo slots + int m_rgAmmo[MAX_AMMO_SLOTS]; + int m_rgAmmoLast[MAX_AMMO_SLOTS]; + + Vector m_vecAutoAim; + BOOL m_fOnTarget; + int m_iDeaths; + float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn + + int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE + + int m_nCustomSprayFrames;// Custom clan logo frames for this player + float m_flNextDecalTime;// next time this player can spray a decal + + char m_szTeamName[TEAM_NAME_LENGTH]; + + virtual void Spawn( void ); + void Pain( void ); + +// virtual void Think( void ); + virtual void Jump( void ); + virtual void Duck( void ); + virtual void PreThink( void ); + virtual void PostThink( void ); + virtual Vector GetGunPosition( void ); + virtual int GetMaxWalkSpeed(void) const; + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) + pev->view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); }; // position to shoot at + virtual void StartSneaking( void ) { m_tSneaking = gpGlobals->time - 1; } + virtual void StopSneaking( void ) { m_tSneaking = gpGlobals->time + 30; } + virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } + virtual BOOL IsAlive() const; + virtual BOOL IsAlive(bool inIncludeSpectating) const; + virtual BOOL ShouldFadeOnDeath( void ) { return FALSE; } + void SpawnClientSideCorpse(); + virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned + + virtual BOOL IsNetClient( void ) { return !(pev->flags & FL_FAKECLIENT); } // Bots should return FALSE for this, they can't receive NET messages + // Spectators should return TRUE for this + virtual char *TeamID(void); + virtual void SetTeamID(const char* inTeamID); + virtual int GetEffectivePlayerClass() { return 0; } + virtual int GetAuthenticationMask() { return 0; } + virtual void EffectivePlayerClassChanged(); + virtual void NeedsTeamUpdate(); + virtual void SendTeamUpdate(); + virtual void SendWeaponUpdate(); + + virtual void InitPlayerFromSpawn(edict_t* inSpawn); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + void RenewItems(void); + virtual void PackDeadPlayerItems( void ); + void DestroyAllItems( BOOL removeSuit ); + void RemoveAllItems( BOOL removeSuit ); + BOOL SwitchWeapon( CBasePlayerItem *pWeapon ); + + // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) + virtual void UpdateClientData( void ); + + static TYPEDESCRIPTION m_playerSaveData[]; + + // Player is moved across the transition by other means + virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual void Precache( void ); + BOOL IsOnLadder( void ); + BOOL FlashlightIsOn( void ); + void FlashlightTurnOn( void ); + void FlashlightTurnOff( void ); + + void UpdatePlayerSound ( void ); + void DeathSound ( void ); + + int Classify ( void ); + virtual void GetAnimationForActivity(int inActivity, char outAnimation[64], bool inGaitSequence = false) { strcpy(outAnimation, ""); }; + void SetAnimation( PLAYER_ANIM playerAnim ); + void SetWeaponAnimType( const char *szExtention ); + char m_szAnimExtention[32]; + + // custom player functions + virtual void ImpulseCommands( void ); + void CheatImpulseCommands( int iImpulse ); + + void StartDeathCam( void ); + virtual void StartObserver( Vector vecPosition, Vector vecViewAngle ); + virtual void StopObserver(); + + // Observer camera + bool Observer_FindNextPlayer(bool inReverse = false); + void Observer_HandleButtons(); + void Observer_SetMode( int iMode ); + void Observer_SpectatePlayer( int idx); + + EHANDLE m_hObserverTarget; + float m_flNextObserverInput; + int IsObserver() const { return pev->iuser1; }; + + virtual float GetAdrenalineFactor() const { return 0.0f; } + + virtual void AddPoints( int score, BOOL bAllowNegativeScore ); + virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); + BOOL AddPlayerItem( CBasePlayerItem *pItem ); + BOOL RemovePlayerItem( CBasePlayerItem *pItem ); + void DropPlayerItem ( char *pszItemName ); + BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); + CBasePlayerItem* HasNamedPlayerItem( const char *pszItemName ); + BOOL HasItem(CBasePlayerItem* inWeapon); + BOOL HasItemWithFlag(int inFlag, CBasePlayerItem*& outItem); + BOOL HasWeapons( void );// do I have ANY weapons? + void SelectPrevItem( int iItem ); + void SelectNextItem( int iItem ); + void SelectLastItem(void); + void SelectItem(const char *pstr); + void ItemPreFrame( void ); + virtual void ItemPostFrame( void ); + + virtual void GiveNamedItem( const char *szName, bool inSendMessage = false); + void EnableControl(BOOL fControl); + + virtual int GiveAmmo( int iAmount, char *szName, int iMax ); + void SendAmmoUpdate(void); + + void WaterMove( void ); + virtual void Suicide(); + void EXPORT PlayerDeathThink( void ); + void EXPORT SuicideThink(void); + void PlayerUse( void ); + void ClearKeys( void); + + void CheckSuitUpdate(); + void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); + void UpdateGeigerCounter( void ); + void CheckTimeBasedDamage( void ); + + BOOL FBecomeProne ( void ); + void BarnacleVictimBitten ( entvars_t *pevBarnacle ); + void BarnacleVictimReleased ( void ); + static int GetAmmoIndex(const char *psz); + int AmmoInventory( int iAmmoIndex ); + int Illumination( void ); + + void ResetAutoaim( void ); + Vector GetAutoaimVector( float flDelta ); + Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ); + + void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. + + void DeathMessage( entvars_t *pevKiller ); + + void SetCustomDecalFrames( int nFrames ); + int GetCustomDecalFrames( void ); + + void CBasePlayer::TabulateAmmo( void ); + + float m_flStartCharge; + float m_flAmmoStartCharge; + float m_flPlayAftershock; + float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo? + //Player ID + void InitStatusBar( void ); + void UpdateStatusBar( void ); + int m_izSBarState[ SBAR_END ]; + float m_flNextSBarUpdateTime; + float m_flStatusBarDisappearDelay; + char m_SbarString0[ SBAR_STRING_SIZE ]; + char m_SbarString1[ SBAR_STRING_SIZE ]; + + float m_flNextChatTime; + int m_DefaultSpectatingMode; + int m_DefaultSpectatingTarget; + + CBaseEntity* GetSpectatingEntity() const; + int GetDefaultSpectatingMode() const { return this->m_DefaultSpectatingMode; } + int GetDefaultSpectatingTarget() const { return this->m_DefaultSpectatingTarget; } + void SetDefaultSpectatingSettings(int inSpectatingMode, int inDefaultSpectatingTarget = -1) { this->m_DefaultSpectatingMode = inSpectatingMode; this->m_DefaultSpectatingTarget = inDefaultSpectatingTarget; } + + // Added by mmcguire. + virtual bool GetCanUseWeapon() const { return true; } + +}; + +#define AUTOAIM_2DEGREES 0.0348994967025 +#define AUTOAIM_5DEGREES 0.08715574274766 +#define AUTOAIM_8DEGREES 0.1391731009601 +#define AUTOAIM_10DEGREES 0.1736481776669 + + +extern int gmsgHudText; +extern BOOL gInitHUD; + +// HLSDK 2.3 update +//// Observer Movement modes (stored in pev->iuser1, so the physics code can get at them) +//#define OBS_CHASE_LOCKED 1 +//#define OBS_CHASE_FREE 2 +//#define OBS_ROAMING 3 + +#endif // PLAYER_H diff --git a/main/source/dlls/player.h~ b/main/source/dlls/player.h~ deleted file mode 100644 index 14ecd54b..00000000 --- a/main/source/dlls/player.h~ +++ /dev/null @@ -1,381 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLAYER_H -#define PLAYER_H - - -#include "pm_materials.h" - - -#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet -#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet -#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. -#define PLAYER_MIN_BOUNCE_SPEED 200 -#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. - -// -// Player PHYSICS FLAGS bits -// -#define PFLAG_ONLADDER ( 1<<0 ) -#define PFLAG_ONSWING ( 1<<0 ) -#define PFLAG_ONTRAIN ( 1<<1 ) -#define PFLAG_ONBARNACLE ( 1<<2 ) -#define PFLAG_DUCKING ( 1<<3 ) // In the process of ducking, but totally squatted yet -#define PFLAG_USING ( 1<<4 ) // Using a continuous entity -#define PFLAG_OBSERVER ( 1<<5 ) // player is locked in stationary cam mode. Spectators can move, observers can't. - -// -// generic player -// -//----------------------------------------------------- -//This is Half-Life player entity -//----------------------------------------------------- -#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time - -#define SUIT_GROUP TRUE -#define SUIT_SENTENCE FALSE - -#define SUIT_REPEAT_OK 0 -#define SUIT_NEXT_IN_30SEC 30 -#define SUIT_NEXT_IN_1MIN 60 -#define SUIT_NEXT_IN_5MIN 300 -#define SUIT_NEXT_IN_10MIN 600 -#define SUIT_NEXT_IN_30MIN 1800 -#define SUIT_NEXT_IN_1HOUR 3600 - -#define CSUITNOREPEAT 32 - -#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" -#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" - -#define TEAM_NAME_LENGTH 16 - -typedef enum -{ - PLAYER_IDLE, - PLAYER_WALK, - PLAYER_JUMP, - PLAYER_SUPERJUMP, - PLAYER_DIE, - PLAYER_ATTACK1, - PLAYER_RELOAD, - PLAYER_PRIME, - PLAYER_RELOAD_START, - PLAYER_RELOAD_INSERT, - PLAYER_RELOAD_END -} PLAYER_ANIM; - -#define MAX_ID_RANGE 2048 -#define SBAR_STRING_SIZE 128 - -enum sbar_data -{ - SBAR_ID_TARGETNAME = 1, - SBAR_ID_TARGETHEALTH, - SBAR_ID_TARGETARMOR, - SBAR_ID_TARGETLEVEL, - SBAR_END, -}; - -#define CHAT_INTERVAL 1.0f -class CBasePlayer : public CBaseMonster -{ -public: - int random_seed; // See that is shared between client & server for shared weapons code - - int m_iPlayerSound;// the index of the sound list slot reserved for this player - int m_iTargetVolume;// ideal sound volume. - int m_iWeaponVolume;// how loud the player's weapon is right now. - int m_iExtraSoundTypes;// additional classification for this weapon's sound - int m_iWeaponFlash;// brightness of the weapon flash - float m_flStopExtraSoundTime; - -// float m_flFlashLightTime; // Time until next battery draw/Recharge -// int m_iFlashBattery; // Flashlight Battery Draw - - int m_afButtonLast; - int m_afButtonPressed; - int m_afButtonReleased; - - edict_t *m_pentSndLast; // last sound entity to modify player room type - float m_flSndRoomtype; // last roomtype set by sound entity - float m_flSndRange; // dist from player to sound entity - - float m_flFallVelocity; - - int m_rgItems[MAX_ITEMS]; - int m_fKnownItem; // True when a new item needs to be added - int m_fNewAmmo; // True when a new item has been added - - unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden - float m_fNextSuicideTime; // the time after which the player can next use the suicide command - - -// these are time-sensitive things that we keep track of - float m_flTimeStepSound; // when the last stepping sound was made - float m_flTimeWeaponIdle; // when to play another weapon idle animation. - float m_flSwimTime; // how long player has been underwater - float m_flDuckTime; // how long we've been ducking - float m_flWallJumpTime; // how long until next walljump - - float m_flSuitUpdate; // when to play next suit update - int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update - int m_iSuitPlayNext; // next sentence slot for queue storage; - int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list - float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat - int m_lastDamageAmount; // Last damage taken - float m_tbdPrev; // Time-based damage timer - - float m_flgeigerRange; // range to nearest radiation source - float m_flgeigerDelay; // delay per update of range msg to client - int m_igeigerRangePrev; - int m_iStepLeft; // alternate left/right foot stepping sound - char m_szTextureName[CBTEXTURENAMEMAX]; // current texture name we're standing on - char m_chTextureType; // current texture type - - int m_idrowndmg; // track drowning damage taken - int m_idrownrestored; // track drowning damage restored - - int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to - // the hude via the DAMAGE message - BOOL m_fInitHUD; // True when deferred HUD restart msg needs to be sent - BOOL m_fGameHUDInitialized; - int m_iTrain; // Train control position - BOOL m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info - - EHANDLE m_pTank; // the tank which the player is currently controlling, NULL if no tank - float m_fDeadTime; // the time at which the player died (used in PlayerDeathThink()) - - BOOL m_fNoPlayerSound; // a debugging feature. Player makes no sound if this is true. - BOOL m_fLongJump; // does this player have the longjump module? - - float m_tSneaking; - int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages - int m_iClientHealth; // the health currently known by the client. If this changes, send a new - int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new - int m_iHideHUD; // the players hud weapon info is to be hidden - int m_iClientHideHUD; - int m_iFOV; // field of view - int m_iClientFOV; // client's known FOV - // usable player items - CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; - CBasePlayerItem *m_pActiveItem; - CBasePlayerItem *m_pClientActiveItem; // client version of the active item - CBasePlayerItem *m_pLastItem; - // Added by mmcguire. - string_t m_pLastItemName; - - - // shared ammo slots - int m_rgAmmo[MAX_AMMO_SLOTS]; - int m_rgAmmoLast[MAX_AMMO_SLOTS]; - - Vector m_vecAutoAim; - BOOL m_fOnTarget; - int m_iDeaths; - float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn - - int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE - - int m_nCustomSprayFrames;// Custom clan logo frames for this player - float m_flNextDecalTime;// next time this player can spray a decal - - char m_szTeamName[TEAM_NAME_LENGTH]; - - virtual void Spawn( void ); - void Pain( void ); - -// virtual void Think( void ); - virtual void Jump( void ); - virtual void Duck( void ); - virtual void PreThink( void ); - virtual void PostThink( void ); - virtual Vector GetGunPosition( void ); - virtual int GetMaxWalkSpeed(void) const; - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) + pev->view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); }; // position to shoot at - virtual void StartSneaking( void ) { m_tSneaking = gpGlobals->time - 1; } - virtual void StopSneaking( void ) { m_tSneaking = gpGlobals->time + 30; } - virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } - virtual BOOL IsAlive() const; - virtual BOOL IsAlive(bool inIncludeSpectating) const; - virtual BOOL ShouldFadeOnDeath( void ) { return FALSE; } - void SpawnClientSideCorpse(); - virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned - - virtual BOOL IsNetClient( void ) { return !(pev->flags & FL_FAKECLIENT); } // Bots should return FALSE for this, they can't receive NET messages - // Spectators should return TRUE for this - virtual char *TeamID(void); - virtual void SetTeamID(const char* inTeamID); - virtual int GetEffectivePlayerClass() { return 0; } - virtual int GetAuthenticationMask() { return 0; } - virtual void EffectivePlayerClassChanged(); - virtual void NeedsTeamUpdate(); - virtual void SendTeamUpdate(); - virtual void SendWeaponUpdate(); - - virtual void InitPlayerFromSpawn(edict_t* inSpawn); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void RenewItems(void); - virtual void PackDeadPlayerItems( void ); - void DestroyAllItems( BOOL removeSuit ); - void RemoveAllItems( BOOL removeSuit ); - BOOL SwitchWeapon( CBasePlayerItem *pWeapon ); - - // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) - virtual void UpdateClientData( void ); - - static TYPEDESCRIPTION m_playerSaveData[]; - - // Player is moved across the transition by other means - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual void Precache( void ); - BOOL IsOnLadder( void ); - BOOL FlashlightIsOn( void ); - void FlashlightTurnOn( void ); - void FlashlightTurnOff( void ); - - void UpdatePlayerSound ( void ); - void DeathSound ( void ); - - int Classify ( void ); - virtual void GetAnimationForActivity(int inActivity, char outAnimation[64], bool inGaitSequence = false) { strcpy(outAnimation, ""); }; - void SetAnimation( PLAYER_ANIM playerAnim ); - void SetWeaponAnimType( const char *szExtention ); - char m_szAnimExtention[32]; - - // custom player functions - virtual void ImpulseCommands( void ); - void CheatImpulseCommands( int iImpulse ); - - void StartDeathCam( void ); - virtual void StartObserver( Vector vecPosition, Vector vecViewAngle ); - virtual void StopObserver(); - - // Observer camera - bool Observer_FindNextPlayer(bool inReverse = false); - void Observer_HandleButtons(); - void Observer_SetMode( int iMode ); - void Observer_SpectatePlayer( int idx); - - EHANDLE m_hObserverTarget; - float m_flNextObserverInput; - int IsObserver() const { return pev->iuser1; }; - - virtual float GetAdrenalineFactor() const { return 0.0f; } - - virtual void AddPoints( int score, BOOL bAllowNegativeScore ); - virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); - BOOL AddPlayerItem( CBasePlayerItem *pItem ); - BOOL RemovePlayerItem( CBasePlayerItem *pItem ); - void DropPlayerItem ( char *pszItemName ); - BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); - CBasePlayerItem* HasNamedPlayerItem( const char *pszItemName ); - BOOL HasItem(CBasePlayerItem* inWeapon); - BOOL HasItemWithFlag(int inFlag, CBasePlayerItem*& outItem); - BOOL HasWeapons( void );// do I have ANY weapons? - void SelectPrevItem( int iItem ); - void SelectNextItem( int iItem ); - void SelectLastItem(void); - void SelectItem(const char *pstr); - void ItemPreFrame( void ); - virtual void ItemPostFrame( void ); - - virtual void GiveNamedItem( const char *szName, bool inSendMessage = false); - void EnableControl(BOOL fControl); - - virtual int GiveAmmo( int iAmount, char *szName, int iMax ); - void SendAmmoUpdate(void); - - void WaterMove( void ); - virtual void Suicide(); - void EXPORT PlayerDeathThink( void ); - void EXPORT SuicideThink(void); - void PlayerUse( void ); - void ClearKeys( void); - - void CheckSuitUpdate(); - void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); - void UpdateGeigerCounter( void ); - void CheckTimeBasedDamage( void ); - - BOOL FBecomeProne ( void ); - void BarnacleVictimBitten ( entvars_t *pevBarnacle ); - void BarnacleVictimReleased ( void ); - static int GetAmmoIndex(const char *psz); - int AmmoInventory( int iAmmoIndex ); - int Illumination( void ); - - void ResetAutoaim( void ); - Vector GetAutoaimVector( float flDelta ); - Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ); - - void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. - - void DeathMessage( entvars_t *pevKiller ); - - void SetCustomDecalFrames( int nFrames ); - int GetCustomDecalFrames( void ); - - void CBasePlayer::TabulateAmmo( void ); - - float m_flStartCharge; - float m_flAmmoStartCharge; - float m_flPlayAftershock; - float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo? - //Player ID - void InitStatusBar( void ); - void UpdateStatusBar( void ); - int m_izSBarState[ SBAR_END ]; - float m_flNextSBarUpdateTime; - float m_flStatusBarDisappearDelay; - char m_SbarString0[ SBAR_STRING_SIZE ]; - char m_SbarString1[ SBAR_STRING_SIZE ]; - - float m_flNextChatTime; - int m_DefaultSpectatingMode; - int m_DefaultSpectatingTarget; - - CBaseEntity* GetSpectatingEntity() const; - int GetDefaultSpectatingMode() const { return this->m_DefaultSpectatingMode; } - int GetDefaultSpectatingTarget() const { return this->m_DefaultSpectatingTarget; } - void SetDefaultSpectatingSettings(int inSpectatingMode, int inDefaultSpectatingTarget = -1) { this->m_DefaultSpectatingMode = inSpectatingMode; this->m_DefaultSpectatingTarget = inDefaultSpectatingTarget; } - - // Added by mmcguire. - virtual bool GetCanUseWeapon() const { return true; } - -}; - -#define AUTOAIM_2DEGREES 0.0348994967025 -#define AUTOAIM_5DEGREES 0.08715574274766 -#define AUTOAIM_8DEGREES 0.1391731009601 -#define AUTOAIM_10DEGREES 0.1736481776669 - - -extern int gmsgHudText; -extern BOOL gInitHUD; - -// HLSDK 2.3 update -//// Observer Movement modes (stored in pev->iuser1, so the physics code can get at them) -//#define OBS_CHASE_LOCKED 1 -//#define OBS_CHASE_FREE 2 -//#define OBS_ROAMING 3 - -#endif // PLAYER_H diff --git a/main/source/dlls/playermonster.cpp b/main/source/dlls/playermonster.cpp index ce1781a1..584a10c4 100644 --- a/main/source/dlls/playermonster.cpp +++ b/main/source/dlls/playermonster.cpp @@ -1,115 +1,115 @@ -//========================================================= -// playermonster - for scripted sequence use. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -// For holograms, make them not solid so the player can walk through them -#define SF_MONSTERPLAYER_NOTSOLID 4 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CPlayerMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); -}; -LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CPlayerMonster :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CPlayerMonster :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CPlayerMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - player monster can't hear. -//========================================================= -int CPlayerMonster :: ISoundMask ( void ) -{ - return NULL; -} - -//========================================================= -// Spawn -//========================================================= -void CPlayerMonster :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/player.mdl"); - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - - MonsterInit(); - if ( pev->spawnflags & SF_MONSTERPLAYER_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CPlayerMonster :: Precache() -{ - PRECACHE_MODEL("models/player.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= +//========================================================= +// playermonster - for scripted sequence use. +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + +// For holograms, make them not solid so the player can walk through them +#define SF_MONSTERPLAYER_NOTSOLID 4 + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= + +class CPlayerMonster : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + int ISoundMask ( void ); +}; +LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CPlayerMonster :: Classify ( void ) +{ + return CLASS_PLAYER_ALLY; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CPlayerMonster :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + default: + ys = 90; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CPlayerMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case 0: + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// ISoundMask - player monster can't hear. +//========================================================= +int CPlayerMonster :: ISoundMask ( void ) +{ + return NULL; +} + +//========================================================= +// Spawn +//========================================================= +void CPlayerMonster :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/player.mdl"); + UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->health = 8; + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + + MonsterInit(); + if ( pev->spawnflags & SF_MONSTERPLAYER_NOTSOLID ) + { + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + } +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CPlayerMonster :: Precache() +{ + PRECACHE_MODEL("models/player.mdl"); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= diff --git a/main/source/dlls/python.cpp b/main/source/dlls/python.cpp index 9e7a645a..b560f049 100644 --- a/main/source/dlls/python.cpp +++ b/main/source/dlls/python.cpp @@ -1,319 +1,319 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "monsters.h" -#include "player.h" -#include "gamerules.h" - - -enum python_e { - PYTHON_IDLE1 = 0, - PYTHON_FIDGET, - PYTHON_FIRE1, - PYTHON_RELOAD, - PYTHON_HOLSTER, - PYTHON_DRAW, - PYTHON_IDLE2, - PYTHON_IDLE3 -}; - -LINK_ENTITY_TO_CLASS( weapon_python, CPython ); -LINK_ENTITY_TO_CLASS( weapon_357, CPython ); - -int CPython::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "357"; - p->iMaxAmmo1 = _357_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = PYTHON_MAX_CLIP; - p->iFlags = 0; - p->iSlot = 1; - p->iPosition = 1; - p->iId = m_iId = WEAPON_PYTHON; - p->iWeight = PYTHON_WEIGHT; - - return 1; -} - -int CPython::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CPython::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_357"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_PYTHON; - SET_MODEL(ENT(pev), "models/w_357.mdl"); - - m_iDefaultAmmo = PYTHON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CPython::Precache( void ) -{ - PRECACHE_MODEL("models/v_357.mdl"); - PRECACHE_MODEL("models/w_357.mdl"); - PRECACHE_MODEL("models/p_357.mdl"); - - PRECACHE_MODEL("models/w_357ammobox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND ("weapons/357_reload1.wav"); - PRECACHE_SOUND ("weapons/357_cock1.wav"); - PRECACHE_SOUND ("weapons/357_shot1.wav"); - PRECACHE_SOUND ("weapons/357_shot2.wav"); - - m_usFirePython = PRECACHE_EVENT( 1, "events/python.sc" ); -} - -BOOL CPython::Deploy( ) -{ -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // enable laser sight geometry. - pev->body = 1; - } - else - { - pev->body = 0; - } - - return DefaultDeploy( "models/v_357.mdl", "models/p_357.mdl", PYTHON_DRAW, "python", UseDecrement(), pev->body ); -} - - -void CPython::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - if ( m_fInZoom ) - { - SecondaryAttack(); - } - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - SendWeaponAnim( PYTHON_HOLSTER ); -} - -void CPython::SecondaryAttack( void ) -{ -#ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) -#else - if ( !g_pGameRules->IsMultiplayer() ) -#endif - { - return; - } - - if ( m_pPlayer->pev->fov != 0 ) - { - m_fInZoom = FALSE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - } - else if ( m_pPlayer->pev->fov != 40 ) - { - m_fInZoom = TRUE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; - } - - m_flNextSecondaryAttack = 0.5; -} - -void CPython::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if (m_iClip <= 0) - { - if (!m_fFireOnEmpty) - Reload( ); - else - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_flNextPrimaryAttack = 0.15; - } - - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - Vector vecDir; - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFirePython, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flNextPrimaryAttack = 0.75; - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CPython::Reload( void ) -{ - if ( m_pPlayer->ammo_357 <= 0 ) - return; - - if ( m_pPlayer->pev->fov != 0 ) - { - m_fInZoom = FALSE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - } - - int bUseScope = FALSE; -#ifdef CLIENT_DLL - bUseScope = bIsMultiplayer(); -#else - bUseScope = g_pGameRules->IsMultiplayer(); -#endif - if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) - { - m_flSoundDelay = 1.5; - } -} - - -void CPython::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); - if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); - m_flSoundDelay = 0; - } - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - if (flRand <= 0.5) - { - iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = (70.0/30.0); - } - else if (flRand <= 0.7) - { - iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = (60.0/30.0); - } - else if (flRand <= 0.9) - { - iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = (88.0/30.0); - } - else - { - iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = (170.0/30.0); - } - - int bUseScope = FALSE; -#ifdef CLIENT_DLL - bUseScope = bIsMultiplayer(); -#else - bUseScope = g_pGameRules->IsMultiplayer(); -#endif - - SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); -} - - - -class CPythonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_357ammobox.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_357ammobox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", _357_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ); - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "weapons.h" +#include "monsters.h" +#include "player.h" +#include "gamerules.h" + + +enum python_e { + PYTHON_IDLE1 = 0, + PYTHON_FIDGET, + PYTHON_FIRE1, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_DRAW, + PYTHON_IDLE2, + PYTHON_IDLE3 +}; + +LINK_ENTITY_TO_CLASS( weapon_python, CPython ); +LINK_ENTITY_TO_CLASS( weapon_357, CPython ); + +int CPython::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "357"; + p->iMaxAmmo1 = _357_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = PYTHON_MAX_CLIP; + p->iFlags = 0; + p->iSlot = 1; + p->iPosition = 1; + p->iId = m_iId = WEAPON_PYTHON; + p->iWeight = PYTHON_WEIGHT; + + return 1; +} + +int CPython::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); + WRITE_BYTE( m_iId ); + MESSAGE_END(); + return TRUE; + } + return FALSE; +} + +void CPython::Spawn( ) +{ + pev->classname = MAKE_STRING("weapon_357"); // hack to allow for old names + Precache( ); + m_iId = WEAPON_PYTHON; + SET_MODEL(ENT(pev), "models/w_357.mdl"); + + m_iDefaultAmmo = PYTHON_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CPython::Precache( void ) +{ + PRECACHE_MODEL("models/v_357.mdl"); + PRECACHE_MODEL("models/w_357.mdl"); + PRECACHE_MODEL("models/p_357.mdl"); + + PRECACHE_MODEL("models/w_357ammobox.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + + PRECACHE_SOUND ("weapons/357_reload1.wav"); + PRECACHE_SOUND ("weapons/357_cock1.wav"); + PRECACHE_SOUND ("weapons/357_shot1.wav"); + PRECACHE_SOUND ("weapons/357_shot2.wav"); + + m_usFirePython = PRECACHE_EVENT( 1, "events/python.sc" ); +} + +BOOL CPython::Deploy( ) +{ +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + // enable laser sight geometry. + pev->body = 1; + } + else + { + pev->body = 0; + } + + return DefaultDeploy( "models/v_357.mdl", "models/p_357.mdl", PYTHON_DRAW, "python", UseDecrement(), pev->body ); +} + + +void CPython::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE;// cancel any reload in progress. + + if ( m_fInZoom ) + { + SecondaryAttack(); + } + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + SendWeaponAnim( PYTHON_HOLSTER ); +} + +void CPython::SecondaryAttack( void ) +{ +#ifdef CLIENT_DLL + if ( !bIsMultiplayer() ) +#else + if ( !g_pGameRules->IsMultiplayer() ) +#endif + { + return; + } + + if ( m_pPlayer->pev->fov != 0 ) + { + m_fInZoom = FALSE; + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov + } + else if ( m_pPlayer->pev->fov != 40 ) + { + m_fInZoom = TRUE; + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; + } + + m_flNextSecondaryAttack = 0.5; +} + +void CPython::PrimaryAttack() +{ + // don't fire underwater + if (m_pPlayer->pev->waterlevel == 3) + { + PlayEmptySound( ); + m_flNextPrimaryAttack = 0.15; + return; + } + + if (m_iClip <= 0) + { + if (!m_fFireOnEmpty) + Reload( ); + else + { + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); + m_flNextPrimaryAttack = 0.15; + } + + return; + } + + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; + + m_iClip--; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + Vector vecDir; + vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFirePython, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flNextPrimaryAttack = 0.75; + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +} + + +void CPython::Reload( void ) +{ + if ( m_pPlayer->ammo_357 <= 0 ) + return; + + if ( m_pPlayer->pev->fov != 0 ) + { + m_fInZoom = FALSE; + m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov + } + + int bUseScope = FALSE; +#ifdef CLIENT_DLL + bUseScope = bIsMultiplayer(); +#else + bUseScope = g_pGameRules->IsMultiplayer(); +#endif + if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) + { + m_flSoundDelay = 1.5; + } +} + + +void CPython::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); + if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) + { + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); + m_flSoundDelay = 0; + } + + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + if (flRand <= 0.5) + { + iAnim = PYTHON_IDLE1; + m_flTimeWeaponIdle = (70.0/30.0); + } + else if (flRand <= 0.7) + { + iAnim = PYTHON_IDLE2; + m_flTimeWeaponIdle = (60.0/30.0); + } + else if (flRand <= 0.9) + { + iAnim = PYTHON_IDLE3; + m_flTimeWeaponIdle = (88.0/30.0); + } + else + { + iAnim = PYTHON_FIDGET; + m_flTimeWeaponIdle = (170.0/30.0); + } + + int bUseScope = FALSE; +#ifdef CLIENT_DLL + bUseScope = bIsMultiplayer(); +#else + bUseScope = g_pGameRules->IsMultiplayer(); +#endif + + SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); +} + + + +class CPythonAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_357ammobox.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_357ammobox.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", _357_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ); + + #endif \ No newline at end of file diff --git a/main/source/dlls/rat.cpp b/main/source/dlls/rat.cpp index 58827451..7f19c248 100644 --- a/main/source/dlls/rat.cpp +++ b/main/source/dlls/rat.cpp @@ -1,98 +1,98 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// rat - environmental monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CRat : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); -}; -LINK_ENTITY_TO_CLASS( monster_rat, CRat ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CRat :: Classify ( void ) -{ - return CLASS_INSECT; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CRat :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 45; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CRat :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/bigrat.mdl"); - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - pev->view_ofs = Vector ( 0, 0, 6 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CRat :: Precache() -{ - PRECACHE_MODEL("models/bigrat.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// rat - environmental monster +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= + +class CRat : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); +}; +LINK_ENTITY_TO_CLASS( monster_rat, CRat ); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CRat :: Classify ( void ) +{ + return CLASS_INSECT; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CRat :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + default: + ys = 45; + break; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// Spawn +//========================================================= +void CRat :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/bigrat.mdl"); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->health = 8; + pev->view_ofs = Vector ( 0, 0, 6 );// position of the eyes relative to monster's origin. + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CRat :: Precache() +{ + PRECACHE_MODEL("models/bigrat.mdl"); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= diff --git a/main/source/dlls/roach.cpp b/main/source/dlls/roach.cpp index c64d6069..f1e86175 100644 --- a/main/source/dlls/roach.cpp +++ b/main/source/dlls/roach.cpp @@ -1,436 +1,436 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// cockroach -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "soundent.h" -#include "decals.h" -#include "roach.h" - -#define ROACH_IDLE 0 -#define ROACH_BORED 1 -#define ROACH_SCARED_BY_ENT 2 -#define ROACH_SCARED_BY_LIGHT 3 -#define ROACH_SMELL_FOOD 4 -#define ROACH_EAT 5 - -LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ); - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CRoach :: ISoundMask ( void ) -{ - return bits_SOUND_CARCASS | bits_SOUND_MEAT; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CRoach :: Classify ( void ) -{ - return CLASS_INSECT; -} - -//========================================================= -// Touch -//========================================================= -void CRoach :: Touch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - if ( pOther->pev->velocity == g_vecZero || !pOther->IsPlayer() ) - { - return; - } - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); - - // This isn't really blood. So you don't have to screen it out based on violence levels (UTIL_ShouldShowBlood()) - UTIL_DecalTrace( &tr, DECAL_YBLOOD1 +RANDOM_LONG(0,5) ); - - TakeDamage( pOther->pev, pOther->pev, pev->health, DMG_CRUSH ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CRoach :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CRoach :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/roach.mdl"); - UTIL_SetSize( pev, Vector( -1, -1, 0 ), Vector( 1, 1, 2 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_YELLOW; - pev->effects = 0; - pev->health = 1; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - this->pev->classname = ALLOC_STRING(kRoachClassName); - - MonsterInit(); - SetActivity ( ACT_IDLE ); - - pev->view_ofs = Vector ( 0, 0, 1 );// position of the eyes relative to monster's origin. - pev->takedamage = DAMAGE_YES; - m_fLightHacked = FALSE; - m_flLastLightLevel = -1; - m_iMode = ROACH_IDLE; - m_flNextSmellTime = gpGlobals->time; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CRoach :: Precache() -{ - PRECACHE_MODEL("models/roach.mdl"); - - PRECACHE_SOUND("roach/rch_die.wav"); - PRECACHE_SOUND("roach/rch_walk.wav"); - PRECACHE_SOUND("roach/rch_smash.wav"); -} - - -//========================================================= -// Killed. -//========================================================= -void CRoach :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->solid = SOLID_NOT; - - //random sound - if ( RANDOM_LONG(0,4) == 1 ) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "roach/rch_die.wav", 0.8, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "roach/rch_smash.wav", 0.7, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); - } - - CSoundEnt::InsertSound ( bits_SOUND_WORLD, pev->origin, 128, 1 ); - - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) - { - pOwner->DeathNotice( pev ); - } - UTIL_Remove( this ); -} - -//========================================================= -// MonsterThink, overridden for roaches. -//========================================================= -void CRoach :: MonsterThink( void ) -{ - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); - else - pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking - - float flInterval = StudioFrameAdvance( ); // animate - - if ( !m_fLightHacked ) - { - // if light value hasn't been collection for the first time yet, - // suspend the creature for a second so the world finishes spawning, then we'll collect the light level. - pev->nextthink = gpGlobals->time + 1; - m_fLightHacked = TRUE; - return; - } - else if ( m_flLastLightLevel < 0 ) - { - // collect light level for the first time, now that all of the lightmaps in the roach's area have been calculated. - m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) ); - } - - switch ( m_iMode ) - { - case ROACH_IDLE: - case ROACH_EAT: - { - // if not moving, sample environment to see if anything scary is around. Do a radius search 'look' at random. - if ( RANDOM_LONG(0,3) == 1 ) - { - Look( 150 ); - if (HasConditions(bits_COND_SEE_FEAR)) - { - // if see something scary - //ALERT ( at_aiconsole, "Scared\n" ); - Eat( 30 + ( RANDOM_LONG(0,14) ) );// roach will ignore food for 30 to 45 seconds - PickNewDest( ROACH_SCARED_BY_ENT ); - SetActivity ( ACT_WALK ); - } - else if ( RANDOM_LONG(0,149) == 1 ) - { - // if roach doesn't see anything, there's still a chance that it will move. (boredom) - //ALERT ( at_aiconsole, "Bored\n" ); - PickNewDest( ROACH_BORED ); - SetActivity ( ACT_WALK ); - - if ( m_iMode == ROACH_EAT ) - { - // roach will ignore food for 30 to 45 seconds if it got bored while eating. - Eat( 30 + ( RANDOM_LONG(0,14) ) ); - } - } - } - - // don't do this stuff if eating! - if ( m_iMode == ROACH_IDLE ) - { - if ( FShouldEat() ) - { - Listen(); - } - - if ( GETENTITYILLUM( ENT(pev) ) > m_flLastLightLevel ) - { - // someone turned on lights! - //ALERT ( at_console, "Lights!\n" ); - PickNewDest( ROACH_SCARED_BY_LIGHT ); - SetActivity ( ACT_WALK ); - } - else if ( HasConditions(bits_COND_SMELL_FOOD) ) - { - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - - // roach smells food and is just standing around. Go to food unless food isn't on same z-plane. - if ( pSound && abs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3 ) - { - PickNewDest( ROACH_SMELL_FOOD ); - SetActivity ( ACT_WALK ); - } - } - } - - break; - } - case ROACH_SCARED_BY_LIGHT: - { - // if roach was scared by light, then stop if we're over a spot at least as dark as where we started! - if ( GETENTITYILLUM( ENT( pev ) ) <= m_flLastLightLevel ) - { - SetActivity ( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// make this our new light level. - } - break; - } - } - - if ( m_flGroundSpeed != 0 ) - { - Move( flInterval ); - } -} - -//========================================================= -// Picks a new spot for roach to run to.( -//========================================================= -void CRoach :: PickNewDest ( int iCondition ) -{ - Vector vecNewDir; - Vector vecDest; - float flDist; - - m_iMode = iCondition; - - if ( m_iMode == ROACH_SMELL_FOOD ) - { - // find the food and go there. - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - - if ( pSound ) - { - m_Route[ 0 ].vecLocation.x = pSound->m_vecOrigin.x + ( 3 - RANDOM_LONG(0,5) ); - m_Route[ 0 ].vecLocation.y = pSound->m_vecOrigin.y + ( 3 - RANDOM_LONG(0,5) ); - m_Route[ 0 ].vecLocation.z = pSound->m_vecOrigin.z; - m_Route[ 0 ].iType = bits_MF_TO_LOCATION; - m_movementGoal = RouteClassify( m_Route[ 0 ].iType ); - return; - } - } - - do - { - // picks a random spot, requiring that it be at least 128 units away - // else, the roach will pick a spot too close to itself and run in - // circles. this is a hack but buys me time to work on the real monsters. - vecNewDir.x = RANDOM_FLOAT( -1, 1 ); - vecNewDir.y = RANDOM_FLOAT( -1, 1 ); - flDist = 256 + ( RANDOM_LONG(0,255) ); - vecDest = pev->origin + vecNewDir * flDist; - - } while ( ( vecDest - pev->origin ).Length2D() < 128 ); - - m_Route[ 0 ].vecLocation.x = vecDest.x; - m_Route[ 0 ].vecLocation.y = vecDest.y; - m_Route[ 0 ].vecLocation.z = pev->origin.z; - m_Route[ 0 ].iType = bits_MF_TO_LOCATION; - m_movementGoal = RouteClassify( m_Route[ 0 ].iType ); - - if ( RANDOM_LONG(0,9) == 1 ) - { - // every once in a while, a roach will play a skitter sound when they decide to run - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "roach/rch_walk.wav", 1, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); - } -} - -//========================================================= -// roach's move function -//========================================================= -void CRoach :: Move ( float flInterval ) -{ - float flWaypointDist; - Vector vecApex; - - // local move to waypoint. - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); - MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); - - ChangeYaw ( pev->yaw_speed ); - UTIL_MakeVectors( pev->angles ); - - if ( RANDOM_LONG(0,7) == 1 ) - { - // randomly check for blocked path.(more random load balancing) - if ( !WALK_MOVE( ENT(pev), pev->ideal_yaw, 4, WALKMOVE_NORMAL ) ) - { - // stuck, so just pick a new spot to run off to - PickNewDest( m_iMode ); - } - } - - WALK_MOVE( ENT(pev), pev->ideal_yaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); - - // if the waypoint is closer than step size, then stop after next step (ok for roach to overshoot) - if ( flWaypointDist <= m_flGroundSpeed * flInterval ) - { - // take truncated step and stop - - SetActivity ( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// this is roach's new comfortable light level - - if ( m_iMode == ROACH_SMELL_FOOD ) - { - m_iMode = ROACH_EAT; - } - else - { - m_iMode = ROACH_IDLE; - } - } - - if ( RANDOM_LONG(0,149) == 1 && m_iMode != ROACH_SCARED_BY_LIGHT && m_iMode != ROACH_SMELL_FOOD ) - { - // random skitter while moving as long as not on a b-line to get out of light or going to food - PickNewDest( FALSE ); - } -} - -//========================================================= -// Look - overriden for the roach, which can virtually see -// 360 degrees. -//========================================================= -void CRoach :: Look ( int iDistance ) -{ - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - CBaseEntity *pPreviousEnt;// the last entity added to the link list - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions( bits_COND_SEE_HATE |bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR ); - - // don't let monsters outside of the player's PVS act up, or most of the interesting - // things will happen before the player gets there! - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - return; - } - - m_pLink = NULL; - pPreviousEnt = this; - - // Does sphere also limit itself to PVS? - // Examine all entities within a reasonable radius - // !!!PERFORMANCE - let's trivially reject the ent list before radius searching! - while ((pSightEnt = UTIL_FindEntityInSphere( pSightEnt, pev->origin, iDistance )) != NULL) - { - // only consider ents that can be damaged. !!!temporarily only considering other monsters and clients - if ( pSightEnt->IsPlayer() || FBitSet ( pSightEnt->pev->flags, FL_MONSTER ) ) - { - if ( /*FVisible( pSightEnt ) &&*/ !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && pSightEnt->pev->health > 0 ) - { - // NULL the Link pointer for each ent added to the link list. If other ents follow, the will overwrite - // this value. If this ent happens to be the last, the list will be properly terminated. - pPreviousEnt->m_pLink = pSightEnt; - pSightEnt->m_pLink = NULL; - pPreviousEnt = pSightEnt; - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch ( IRelationship ( pSightEnt ) ) - { - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_NO: - break; - default: - ALERT ( at_console, "%s can't asses %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - SetConditions( iSighted ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// cockroach +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "soundent.h" +#include "decals.h" +#include "roach.h" + +#define ROACH_IDLE 0 +#define ROACH_BORED 1 +#define ROACH_SCARED_BY_ENT 2 +#define ROACH_SCARED_BY_LIGHT 3 +#define ROACH_SMELL_FOOD 4 +#define ROACH_EAT 5 + +LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ); + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. In the base class implementation, +// monsters care about all sounds, but no scents. +//========================================================= +int CRoach :: ISoundMask ( void ) +{ + return bits_SOUND_CARCASS | bits_SOUND_MEAT; +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CRoach :: Classify ( void ) +{ + return CLASS_INSECT; +} + +//========================================================= +// Touch +//========================================================= +void CRoach :: Touch ( CBaseEntity *pOther ) +{ + Vector vecSpot; + TraceResult tr; + + if ( pOther->pev->velocity == g_vecZero || !pOther->IsPlayer() ) + { + return; + } + + vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. + UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); + + // This isn't really blood. So you don't have to screen it out based on violence levels (UTIL_ShouldShowBlood()) + UTIL_DecalTrace( &tr, DECAL_YBLOOD1 +RANDOM_LONG(0,5) ); + + TakeDamage( pOther->pev, pOther->pev, pev->health, DMG_CRUSH ); +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CRoach :: SetYawSpeed ( void ) +{ + int ys; + + ys = 120; + + pev->yaw_speed = ys; +} + +//========================================================= +// Spawn +//========================================================= +void CRoach :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/roach.mdl"); + UTIL_SetSize( pev, Vector( -1, -1, 0 ), Vector( 1, 1, 2 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_YELLOW; + pev->effects = 0; + pev->health = 1; + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + this->pev->classname = ALLOC_STRING(kRoachClassName); + + MonsterInit(); + SetActivity ( ACT_IDLE ); + + pev->view_ofs = Vector ( 0, 0, 1 );// position of the eyes relative to monster's origin. + pev->takedamage = DAMAGE_YES; + m_fLightHacked = FALSE; + m_flLastLightLevel = -1; + m_iMode = ROACH_IDLE; + m_flNextSmellTime = gpGlobals->time; +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CRoach :: Precache() +{ + PRECACHE_MODEL("models/roach.mdl"); + + PRECACHE_SOUND("roach/rch_die.wav"); + PRECACHE_SOUND("roach/rch_walk.wav"); + PRECACHE_SOUND("roach/rch_smash.wav"); +} + + +//========================================================= +// Killed. +//========================================================= +void CRoach :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->solid = SOLID_NOT; + + //random sound + if ( RANDOM_LONG(0,4) == 1 ) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "roach/rch_die.wav", 0.8, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); + } + else + { + EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "roach/rch_smash.wav", 0.7, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); + } + + CSoundEnt::InsertSound ( bits_SOUND_WORLD, pev->origin, 128, 1 ); + + CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); + if ( pOwner ) + { + pOwner->DeathNotice( pev ); + } + UTIL_Remove( this ); +} + +//========================================================= +// MonsterThink, overridden for roaches. +//========================================================= +void CRoach :: MonsterThink( void ) +{ + if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); + else + pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking + + float flInterval = StudioFrameAdvance( ); // animate + + if ( !m_fLightHacked ) + { + // if light value hasn't been collection for the first time yet, + // suspend the creature for a second so the world finishes spawning, then we'll collect the light level. + pev->nextthink = gpGlobals->time + 1; + m_fLightHacked = TRUE; + return; + } + else if ( m_flLastLightLevel < 0 ) + { + // collect light level for the first time, now that all of the lightmaps in the roach's area have been calculated. + m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) ); + } + + switch ( m_iMode ) + { + case ROACH_IDLE: + case ROACH_EAT: + { + // if not moving, sample environment to see if anything scary is around. Do a radius search 'look' at random. + if ( RANDOM_LONG(0,3) == 1 ) + { + Look( 150 ); + if (HasConditions(bits_COND_SEE_FEAR)) + { + // if see something scary + //ALERT ( at_aiconsole, "Scared\n" ); + Eat( 30 + ( RANDOM_LONG(0,14) ) );// roach will ignore food for 30 to 45 seconds + PickNewDest( ROACH_SCARED_BY_ENT ); + SetActivity ( ACT_WALK ); + } + else if ( RANDOM_LONG(0,149) == 1 ) + { + // if roach doesn't see anything, there's still a chance that it will move. (boredom) + //ALERT ( at_aiconsole, "Bored\n" ); + PickNewDest( ROACH_BORED ); + SetActivity ( ACT_WALK ); + + if ( m_iMode == ROACH_EAT ) + { + // roach will ignore food for 30 to 45 seconds if it got bored while eating. + Eat( 30 + ( RANDOM_LONG(0,14) ) ); + } + } + } + + // don't do this stuff if eating! + if ( m_iMode == ROACH_IDLE ) + { + if ( FShouldEat() ) + { + Listen(); + } + + if ( GETENTITYILLUM( ENT(pev) ) > m_flLastLightLevel ) + { + // someone turned on lights! + //ALERT ( at_console, "Lights!\n" ); + PickNewDest( ROACH_SCARED_BY_LIGHT ); + SetActivity ( ACT_WALK ); + } + else if ( HasConditions(bits_COND_SMELL_FOOD) ) + { + CSound *pSound; + + pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); + + // roach smells food and is just standing around. Go to food unless food isn't on same z-plane. + if ( pSound && abs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3 ) + { + PickNewDest( ROACH_SMELL_FOOD ); + SetActivity ( ACT_WALK ); + } + } + } + + break; + } + case ROACH_SCARED_BY_LIGHT: + { + // if roach was scared by light, then stop if we're over a spot at least as dark as where we started! + if ( GETENTITYILLUM( ENT( pev ) ) <= m_flLastLightLevel ) + { + SetActivity ( ACT_IDLE ); + m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// make this our new light level. + } + break; + } + } + + if ( m_flGroundSpeed != 0 ) + { + Move( flInterval ); + } +} + +//========================================================= +// Picks a new spot for roach to run to.( +//========================================================= +void CRoach :: PickNewDest ( int iCondition ) +{ + Vector vecNewDir; + Vector vecDest; + float flDist; + + m_iMode = iCondition; + + if ( m_iMode == ROACH_SMELL_FOOD ) + { + // find the food and go there. + CSound *pSound; + + pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); + + if ( pSound ) + { + m_Route[ 0 ].vecLocation.x = pSound->m_vecOrigin.x + ( 3 - RANDOM_LONG(0,5) ); + m_Route[ 0 ].vecLocation.y = pSound->m_vecOrigin.y + ( 3 - RANDOM_LONG(0,5) ); + m_Route[ 0 ].vecLocation.z = pSound->m_vecOrigin.z; + m_Route[ 0 ].iType = bits_MF_TO_LOCATION; + m_movementGoal = RouteClassify( m_Route[ 0 ].iType ); + return; + } + } + + do + { + // picks a random spot, requiring that it be at least 128 units away + // else, the roach will pick a spot too close to itself and run in + // circles. this is a hack but buys me time to work on the real monsters. + vecNewDir.x = RANDOM_FLOAT( -1, 1 ); + vecNewDir.y = RANDOM_FLOAT( -1, 1 ); + flDist = 256 + ( RANDOM_LONG(0,255) ); + vecDest = pev->origin + vecNewDir * flDist; + + } while ( ( vecDest - pev->origin ).Length2D() < 128 ); + + m_Route[ 0 ].vecLocation.x = vecDest.x; + m_Route[ 0 ].vecLocation.y = vecDest.y; + m_Route[ 0 ].vecLocation.z = pev->origin.z; + m_Route[ 0 ].iType = bits_MF_TO_LOCATION; + m_movementGoal = RouteClassify( m_Route[ 0 ].iType ); + + if ( RANDOM_LONG(0,9) == 1 ) + { + // every once in a while, a roach will play a skitter sound when they decide to run + EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "roach/rch_walk.wav", 1, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); + } +} + +//========================================================= +// roach's move function +//========================================================= +void CRoach :: Move ( float flInterval ) +{ + float flWaypointDist; + Vector vecApex; + + // local move to waypoint. + flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); + MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); + + ChangeYaw ( pev->yaw_speed ); + UTIL_MakeVectors( pev->angles ); + + if ( RANDOM_LONG(0,7) == 1 ) + { + // randomly check for blocked path.(more random load balancing) + if ( !WALK_MOVE( ENT(pev), pev->ideal_yaw, 4, WALKMOVE_NORMAL ) ) + { + // stuck, so just pick a new spot to run off to + PickNewDest( m_iMode ); + } + } + + WALK_MOVE( ENT(pev), pev->ideal_yaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); + + // if the waypoint is closer than step size, then stop after next step (ok for roach to overshoot) + if ( flWaypointDist <= m_flGroundSpeed * flInterval ) + { + // take truncated step and stop + + SetActivity ( ACT_IDLE ); + m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// this is roach's new comfortable light level + + if ( m_iMode == ROACH_SMELL_FOOD ) + { + m_iMode = ROACH_EAT; + } + else + { + m_iMode = ROACH_IDLE; + } + } + + if ( RANDOM_LONG(0,149) == 1 && m_iMode != ROACH_SCARED_BY_LIGHT && m_iMode != ROACH_SMELL_FOOD ) + { + // random skitter while moving as long as not on a b-line to get out of light or going to food + PickNewDest( FALSE ); + } +} + +//========================================================= +// Look - overriden for the roach, which can virtually see +// 360 degrees. +//========================================================= +void CRoach :: Look ( int iDistance ) +{ + CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with + CBaseEntity *pPreviousEnt;// the last entity added to the link list + int iSighted = 0; + + // DON'T let visibility information from last frame sit around! + ClearConditions( bits_COND_SEE_HATE |bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR ); + + // don't let monsters outside of the player's PVS act up, or most of the interesting + // things will happen before the player gets there! + if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + { + return; + } + + m_pLink = NULL; + pPreviousEnt = this; + + // Does sphere also limit itself to PVS? + // Examine all entities within a reasonable radius + // !!!PERFORMANCE - let's trivially reject the ent list before radius searching! + while ((pSightEnt = UTIL_FindEntityInSphere( pSightEnt, pev->origin, iDistance )) != NULL) + { + // only consider ents that can be damaged. !!!temporarily only considering other monsters and clients + if ( pSightEnt->IsPlayer() || FBitSet ( pSightEnt->pev->flags, FL_MONSTER ) ) + { + if ( /*FVisible( pSightEnt ) &&*/ !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && pSightEnt->pev->health > 0 ) + { + // NULL the Link pointer for each ent added to the link list. If other ents follow, the will overwrite + // this value. If this ent happens to be the last, the list will be properly terminated. + pPreviousEnt->m_pLink = pSightEnt; + pSightEnt->m_pLink = NULL; + pPreviousEnt = pSightEnt; + + // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when + // we see monsters other than the Enemy. + switch ( IRelationship ( pSightEnt ) ) + { + case R_FR: + iSighted |= bits_COND_SEE_FEAR; + break; + case R_NO: + break; + default: + ALERT ( at_console, "%s can't asses %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); + break; + } + } + } + } + SetConditions( iSighted ); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + diff --git a/main/source/dlls/roach.h b/main/source/dlls/roach.h index dea76767..b7d67272 100644 --- a/main/source/dlls/roach.h +++ b/main/source/dlls/roach.h @@ -1,35 +1,35 @@ -#ifndef ROACH_H -#define ROACH_H - -#include "cbase.h" - -#define kRoachClassName "Roach" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -class CRoach : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - void EXPORT MonsterThink ( void ); - void Move ( float flInterval ); - void PickNewDest ( int iCondition ); - void EXPORT Touch ( CBaseEntity *pOther ); - void Killed( entvars_t *pevAttacker, int iGib ); - - float m_flLastLightLevel; - float m_flNextSmellTime; - int Classify ( void ); - void Look ( int iDistance ); - int ISoundMask ( void ); - - // UNDONE: These don't necessarily need to be save/restored, but if we add more data, it may - BOOL m_fLightHacked; - int m_iMode; - // ----------------------------- -}; - +#ifndef ROACH_H +#define ROACH_H + +#include "cbase.h" + +#define kRoachClassName "Roach" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +class CRoach : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + void EXPORT MonsterThink ( void ); + void Move ( float flInterval ); + void PickNewDest ( int iCondition ); + void EXPORT Touch ( CBaseEntity *pOther ); + void Killed( entvars_t *pevAttacker, int iGib ); + + float m_flLastLightLevel; + float m_flNextSmellTime; + int Classify ( void ); + void Look ( int iDistance ); + int ISoundMask ( void ); + + // UNDONE: These don't necessarily need to be save/restored, but if we add more data, it may + BOOL m_fLightHacked; + int m_iMode; + // ----------------------------- +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/rpg.cpp b/main/source/dlls/rpg.cpp index 76e32079..504be549 100644 --- a/main/source/dlls/rpg.cpp +++ b/main/source/dlls/rpg.cpp @@ -1,619 +1,619 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" -#include "../mod/AvHNetworkMessages.h" - - - - -enum rpg_e { - RPG_IDLE = 0, - RPG_FIDGET, - RPG_RELOAD, // to reload - RPG_FIRE2, // to empty - RPG_HOLSTER1, // loaded - RPG_DRAW1, // loaded - RPG_HOLSTER2, // unloaded - RPG_DRAW_UL, // unloaded - RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget -}; - -LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ); - -#ifndef CLIENT_DLL - -LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); - -//========================================================= -//========================================================= -CLaserSpot *CLaserSpot::CreateSpot( void ) -{ - CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); - pSpot->Spawn(); - - pSpot->pev->classname = MAKE_STRING("laser_spot"); - - return pSpot; -} - -//========================================================= -//========================================================= -void CLaserSpot::Spawn( void ) -{ - Precache( ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - - pev->rendermode = kRenderGlow; - pev->renderfx = kRenderFxNoDissipation; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/laserdot.spr"); - UTIL_SetOrigin( pev, pev->origin ); -}; - -//========================================================= -// Suspend- make the laser sight invisible. -//========================================================= -void CLaserSpot::Suspend( float flSuspendTime ) -{ - pev->effects |= EF_NODRAW; - - SetThink( &CLaserSpot::Revive ); - pev->nextthink = gpGlobals->time + flSuspendTime; -} - -//========================================================= -// Revive - bring a suspended laser sight back. -//========================================================= -void CLaserSpot::Revive( void ) -{ - pev->effects &= ~EF_NODRAW; - - SetThink( NULL ); -} - -void CLaserSpot::Precache( void ) -{ - PRECACHE_MODEL("sprites/laserdot.spr"); -}; - -LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); - -//========================================================= -//========================================================= -CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ) -{ - CRpgRocket *pRocket = GetClassPtr( (CRpgRocket *)NULL ); - - UTIL_SetOrigin( pRocket->pev, vecOrigin ); - pRocket->pev->angles = vecAngles; - pRocket->Spawn(); - pRocket->SetTouch( &CRpgRocket::RocketTouch ); - pRocket->m_pLauncher = pLauncher;// remember what RPG fired me. - pRocket->m_pLauncher->m_cActiveRockets++;// register this missile as active for the launcher - pRocket->pev->owner = pOwner->edict(); - - return pRocket; -} - -//========================================================= -//========================================================= -void CRpgRocket :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/rpgrocket.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->classname = MAKE_STRING("rpg_rocket"); - - SetThink( &CRpgRocket::IgniteThink ); - SetTouch( &CRpgRocket::ExplodeTouch ); - - pev->angles.x -= 30; - UTIL_MakeVectors( pev->angles ); - pev->angles.x = -(pev->angles.x + 30); - - pev->velocity = gpGlobals->v_forward * 250; - pev->gravity = 0.5; - - pev->nextthink = gpGlobals->time + 0.4; - - pev->dmg = gSkillData.plrDmgRPG; -} - -//========================================================= -//========================================================= -void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) -{ - if ( m_pLauncher ) - { - // my launcher is still around, tell it I'm dead. - m_pLauncher->m_cActiveRockets--; - } - - STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); - ExplodeTouch( pOther ); -} - -//========================================================= -//========================================================= -void CRpgRocket :: Precache( void ) -{ - PRECACHE_MODEL("models/rpgrocket.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); -} - - -void CRpgRocket :: IgniteThink( void ) -{ - // pev->movetype = MOVETYPE_TOSS; - - pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); - - // rocket trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT(entindex()); // entity - WRITE_SHORT(m_iTrail ); // model - WRITE_BYTE( 40 ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - - MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - m_flIgniteTime = gpGlobals->time; - - // set to follow laser spot - SetThink( &CRpgRocket::FollowThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CRpgRocket :: FollowThink( void ) -{ - CBaseEntity *pOther = NULL; - Vector vecTarget; - Vector vecDir; - float flDist, flMax, flDot; - TraceResult tr; - - UTIL_MakeAimVectors( pev->angles ); - - vecTarget = gpGlobals->v_forward; - flMax = 4096; - - // Examine all entities within a reasonable radius - while ((pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" )) != NULL) - { - UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr ); - // ALERT( at_console, "%f\n", tr.flFraction ); - if (tr.flFraction >= 0.90) - { - vecDir = pOther->pev->origin - pev->origin; - flDist = vecDir.Length( ); - vecDir = vecDir.Normalize( ); - flDot = DotProduct( gpGlobals->v_forward, vecDir ); - if ((flDot > 0) && (flDist * (1 - flDot) < flMax)) - { - flMax = flDist * (1 - flDot); - vecTarget = vecDir; - } - } - } - - pev->angles = UTIL_VecToAngles( vecTarget ); - - // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it. - float flSpeed = pev->velocity.Length(); - if (gpGlobals->time - m_flIgniteTime < 1.0) - { - pev->velocity = pev->velocity * 0.2 + vecTarget * (flSpeed * 0.8 + 400); - if (pev->waterlevel == 3) - { - // go slow underwater - if (pev->velocity.Length() > 300) - { - pev->velocity = pev->velocity.Normalize() * 300; - } - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 4 ); - } - else - { - if (pev->velocity.Length() > 2000) - { - pev->velocity = pev->velocity.Normalize() * 2000; - } - } - } - else - { - if (pev->effects & EF_LIGHT) - { - pev->effects = 0; - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav" ); - } - pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; - if (pev->waterlevel == 0 && pev->velocity.Length() < 1500) - { - Detonate( ); - } - } - // ALERT( at_console, "%.0f\n", flSpeed ); - - pev->nextthink = gpGlobals->time + 0.1; -} -#endif - - - -void CRpg::Reload( void ) -{ - int iResult; - - if ( m_iClip == 1 ) - { - // don't bother with any of this if don't need to reload. - return; - } - - if ( m_pPlayer->ammo_rockets <= 0 ) - return; - - // because the RPG waits to autoreload when no missiles are active while the LTD is on, the - // weapons code is constantly calling into this function, but is often denied because - // a) missiles are in flight, but the LTD is on - // or - // b) player is totally out of ammo and has nothing to switch to, and should be allowed to - // shine the designator around - // - // Set the next attack time into the future so that WeaponIdle will get called more often - // than reload, allowing the RPG LTD to be updated - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_cActiveRockets && m_fSpotActive ) - { - // no reloading when there are active missiles tracking the designator. - // ward off future autoreload attempts by setting next attack time into the future for a bit. - return; - } - -#ifndef CLIENT_DLL - if ( m_pSpot && m_fSpotActive ) - { - m_pSpot->Suspend( 2.1 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.1; - } -#endif - - if ( m_iClip == 0 ) - iResult = DefaultReload( RPG_MAX_CLIP, RPG_RELOAD, 2 ); - - if ( iResult ) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - -} - -void CRpg::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_RPG; - - SET_MODEL(ENT(pev), "models/w_rpg.mdl"); - m_fSpotActive = 1; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // more default ammo in multiplay. - m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2; - } - else - { - m_iDefaultAmmo = RPG_DEFAULT_GIVE; - } - - FallInit();// get ready to fall down. -} - - -void CRpg::Precache( void ) -{ - PRECACHE_MODEL("models/w_rpg.mdl"); - PRECACHE_MODEL("models/v_rpg.mdl"); - PRECACHE_MODEL("models/p_rpg.mdl"); - - PRECACHE_SOUND("items/9mmclip1.wav"); - - UTIL_PrecacheOther( "laser_spot" ); - UTIL_PrecacheOther( "rpg_rocket" ); - - PRECACHE_SOUND("weapons/rocketfire1.wav"); - PRECACHE_SOUND("weapons/glauncher.wav"); // alternative fire sound - - m_usRpg = PRECACHE_EVENT ( 1, "events/rpg.sc" ); -} - - -int CRpg::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "rockets"; - p->iMaxAmmo1 = ROCKET_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = RPG_MAX_CLIP; - p->iSlot = 3; - p->iPosition = 0; - p->iId = m_iId = WEAPON_RPG; - p->iFlags = 0; - p->iWeight = RPG_WEIGHT; - - return 1; -} - -int CRpg::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pev, m_iId ); - //MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - // WRITE_BYTE( m_iId ); - //MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CRpg::Deploy( ) -{ - if ( m_iClip == 0 ) - { - return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW_UL, "rpg" ); - } - - return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW1, "rpg" ); -} - - -BOOL CRpg::CanHolster( void ) -{ - if ( m_fSpotActive && m_cActiveRockets ) - { - // can't put away while guiding a missile. - return FALSE; - } - - return TRUE; -} - -void CRpg::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( RPG_HOLSTER1 ); - -#ifndef CLIENT_DLL - if (m_pSpot) - { - m_pSpot->Killed( NULL, GIB_NEVER ); - m_pSpot = NULL; - } -#endif - -} - - - -void CRpg::PrimaryAttack() -{ - if ( m_iClip ) - { - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - -#ifndef CLIENT_DLL - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -8; - - CRpgRocket *pRocket = CRpgRocket::CreateRpgRocket( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake. - pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); -#endif - - // firing RPG no longer turns on the designator. ALT fire is a toggle switch for the LTD. - // Ken signed up for this as a global change (sjb) - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); - - m_iClip--; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - else - { - PlayEmptySound( ); - } - UpdateSpot( ); -} - - -void CRpg::SecondaryAttack() -{ - m_fSpotActive = ! m_fSpotActive; - -#ifndef CLIENT_DLL - if (!m_fSpotActive && m_pSpot) - { - m_pSpot->Killed( NULL, GIB_NORMAL ); - m_pSpot = NULL; - } -#endif - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; -} - - -void CRpg::WeaponIdle( void ) -{ - UpdateSpot( ); - - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75 || m_fSpotActive) - { - if ( m_iClip == 0 ) - iAnim = RPG_IDLE_UL; - else - iAnim = RPG_IDLE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 15.0; - } - else - { - if ( m_iClip == 0 ) - iAnim = RPG_FIDGET_UL; - else - iAnim = RPG_FIDGET; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0; - } - - SendWeaponAnim( iAnim ); - } - else - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1; - } -} - - - -void CRpg::UpdateSpot( void ) -{ - -#ifndef CLIENT_DLL - if (m_fSpotActive) - { - if (!m_pSpot) - { - m_pSpot = CLaserSpot::CreateSpot(); - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( );; - Vector vecAiming = gpGlobals->v_forward; - - TraceResult tr; - UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr ); - - UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); - } -#endif - -} - - -class CRpgAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_rpgammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_rpgammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int iGive; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // hand out more ammo per rocket in multiplayer. - iGive = AMMO_RPGCLIP_GIVE * 2; - } - else - { - iGive = AMMO_RPGCLIP_GIVE; - } - - if (pOther->GiveAmmo( iGive, "rockets", ROCKET_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" +#include "../mod/AvHNetworkMessages.h" + + + + +enum rpg_e { + RPG_IDLE = 0, + RPG_FIDGET, + RPG_RELOAD, // to reload + RPG_FIRE2, // to empty + RPG_HOLSTER1, // loaded + RPG_DRAW1, // loaded + RPG_HOLSTER2, // unloaded + RPG_DRAW_UL, // unloaded + RPG_IDLE_UL, // unloaded idle + RPG_FIDGET_UL, // unloaded fidget +}; + +LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ); + +#ifndef CLIENT_DLL + +LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); + +//========================================================= +//========================================================= +CLaserSpot *CLaserSpot::CreateSpot( void ) +{ + CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); + pSpot->Spawn(); + + pSpot->pev->classname = MAKE_STRING("laser_spot"); + + return pSpot; +} + +//========================================================= +//========================================================= +void CLaserSpot::Spawn( void ) +{ + Precache( ); + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + + pev->rendermode = kRenderGlow; + pev->renderfx = kRenderFxNoDissipation; + pev->renderamt = 255; + + SET_MODEL(ENT(pev), "sprites/laserdot.spr"); + UTIL_SetOrigin( pev, pev->origin ); +}; + +//========================================================= +// Suspend- make the laser sight invisible. +//========================================================= +void CLaserSpot::Suspend( float flSuspendTime ) +{ + pev->effects |= EF_NODRAW; + + SetThink( &CLaserSpot::Revive ); + pev->nextthink = gpGlobals->time + flSuspendTime; +} + +//========================================================= +// Revive - bring a suspended laser sight back. +//========================================================= +void CLaserSpot::Revive( void ) +{ + pev->effects &= ~EF_NODRAW; + + SetThink( NULL ); +} + +void CLaserSpot::Precache( void ) +{ + PRECACHE_MODEL("sprites/laserdot.spr"); +}; + +LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); + +//========================================================= +//========================================================= +CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ) +{ + CRpgRocket *pRocket = GetClassPtr( (CRpgRocket *)NULL ); + + UTIL_SetOrigin( pRocket->pev, vecOrigin ); + pRocket->pev->angles = vecAngles; + pRocket->Spawn(); + pRocket->SetTouch( &CRpgRocket::RocketTouch ); + pRocket->m_pLauncher = pLauncher;// remember what RPG fired me. + pRocket->m_pLauncher->m_cActiveRockets++;// register this missile as active for the launcher + pRocket->pev->owner = pOwner->edict(); + + return pRocket; +} + +//========================================================= +//========================================================= +void CRpgRocket :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/rpgrocket.mdl"); + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetOrigin( pev, pev->origin ); + + pev->classname = MAKE_STRING("rpg_rocket"); + + SetThink( &CRpgRocket::IgniteThink ); + SetTouch( &CRpgRocket::ExplodeTouch ); + + pev->angles.x -= 30; + UTIL_MakeVectors( pev->angles ); + pev->angles.x = -(pev->angles.x + 30); + + pev->velocity = gpGlobals->v_forward * 250; + pev->gravity = 0.5; + + pev->nextthink = gpGlobals->time + 0.4; + + pev->dmg = gSkillData.plrDmgRPG; +} + +//========================================================= +//========================================================= +void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) +{ + if ( m_pLauncher ) + { + // my launcher is still around, tell it I'm dead. + m_pLauncher->m_cActiveRockets--; + } + + STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); + ExplodeTouch( pOther ); +} + +//========================================================= +//========================================================= +void CRpgRocket :: Precache( void ) +{ + PRECACHE_MODEL("models/rpgrocket.mdl"); + m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); + PRECACHE_SOUND ("weapons/rocket1.wav"); +} + + +void CRpgRocket :: IgniteThink( void ) +{ + // pev->movetype = MOVETYPE_TOSS; + + pev->movetype = MOVETYPE_FLY; + pev->effects |= EF_LIGHT; + + // make rocket sound + EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); + + // rocket trail + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + + WRITE_BYTE( TE_BEAMFOLLOW ); + WRITE_SHORT(entindex()); // entity + WRITE_SHORT(m_iTrail ); // model + WRITE_BYTE( 40 ); // life + WRITE_BYTE( 5 ); // width + WRITE_BYTE( 224 ); // r, g, b + WRITE_BYTE( 224 ); // r, g, b + WRITE_BYTE( 255 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + + MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) + + m_flIgniteTime = gpGlobals->time; + + // set to follow laser spot + SetThink( &CRpgRocket::FollowThink ); + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CRpgRocket :: FollowThink( void ) +{ + CBaseEntity *pOther = NULL; + Vector vecTarget; + Vector vecDir; + float flDist, flMax, flDot; + TraceResult tr; + + UTIL_MakeAimVectors( pev->angles ); + + vecTarget = gpGlobals->v_forward; + flMax = 4096; + + // Examine all entities within a reasonable radius + while ((pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" )) != NULL) + { + UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr ); + // ALERT( at_console, "%f\n", tr.flFraction ); + if (tr.flFraction >= 0.90) + { + vecDir = pOther->pev->origin - pev->origin; + flDist = vecDir.Length( ); + vecDir = vecDir.Normalize( ); + flDot = DotProduct( gpGlobals->v_forward, vecDir ); + if ((flDot > 0) && (flDist * (1 - flDot) < flMax)) + { + flMax = flDist * (1 - flDot); + vecTarget = vecDir; + } + } + } + + pev->angles = UTIL_VecToAngles( vecTarget ); + + // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it. + float flSpeed = pev->velocity.Length(); + if (gpGlobals->time - m_flIgniteTime < 1.0) + { + pev->velocity = pev->velocity * 0.2 + vecTarget * (flSpeed * 0.8 + 400); + if (pev->waterlevel == 3) + { + // go slow underwater + if (pev->velocity.Length() > 300) + { + pev->velocity = pev->velocity.Normalize() * 300; + } + UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 4 ); + } + else + { + if (pev->velocity.Length() > 2000) + { + pev->velocity = pev->velocity.Normalize() * 2000; + } + } + } + else + { + if (pev->effects & EF_LIGHT) + { + pev->effects = 0; + STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav" ); + } + pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; + if (pev->waterlevel == 0 && pev->velocity.Length() < 1500) + { + Detonate( ); + } + } + // ALERT( at_console, "%.0f\n", flSpeed ); + + pev->nextthink = gpGlobals->time + 0.1; +} +#endif + + + +void CRpg::Reload( void ) +{ + int iResult; + + if ( m_iClip == 1 ) + { + // don't bother with any of this if don't need to reload. + return; + } + + if ( m_pPlayer->ammo_rockets <= 0 ) + return; + + // because the RPG waits to autoreload when no missiles are active while the LTD is on, the + // weapons code is constantly calling into this function, but is often denied because + // a) missiles are in flight, but the LTD is on + // or + // b) player is totally out of ammo and has nothing to switch to, and should be allowed to + // shine the designator around + // + // Set the next attack time into the future so that WeaponIdle will get called more often + // than reload, allowing the RPG LTD to be updated + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + + if ( m_cActiveRockets && m_fSpotActive ) + { + // no reloading when there are active missiles tracking the designator. + // ward off future autoreload attempts by setting next attack time into the future for a bit. + return; + } + +#ifndef CLIENT_DLL + if ( m_pSpot && m_fSpotActive ) + { + m_pSpot->Suspend( 2.1 ); + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.1; + } +#endif + + if ( m_iClip == 0 ) + iResult = DefaultReload( RPG_MAX_CLIP, RPG_RELOAD, 2 ); + + if ( iResult ) + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + +} + +void CRpg::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_RPG; + + SET_MODEL(ENT(pev), "models/w_rpg.mdl"); + m_fSpotActive = 1; + +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + // more default ammo in multiplay. + m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2; + } + else + { + m_iDefaultAmmo = RPG_DEFAULT_GIVE; + } + + FallInit();// get ready to fall down. +} + + +void CRpg::Precache( void ) +{ + PRECACHE_MODEL("models/w_rpg.mdl"); + PRECACHE_MODEL("models/v_rpg.mdl"); + PRECACHE_MODEL("models/p_rpg.mdl"); + + PRECACHE_SOUND("items/9mmclip1.wav"); + + UTIL_PrecacheOther( "laser_spot" ); + UTIL_PrecacheOther( "rpg_rocket" ); + + PRECACHE_SOUND("weapons/rocketfire1.wav"); + PRECACHE_SOUND("weapons/glauncher.wav"); // alternative fire sound + + m_usRpg = PRECACHE_EVENT ( 1, "events/rpg.sc" ); +} + + +int CRpg::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "rockets"; + p->iMaxAmmo1 = ROCKET_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = RPG_MAX_CLIP; + p->iSlot = 3; + p->iPosition = 0; + p->iId = m_iId = WEAPON_RPG; + p->iFlags = 0; + p->iWeight = RPG_WEIGHT; + + return 1; +} + +int CRpg::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + NetMsg_WeapPickup( pev, m_iId ); + //MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); + // WRITE_BYTE( m_iId ); + //MESSAGE_END(); + return TRUE; + } + return FALSE; +} + +BOOL CRpg::Deploy( ) +{ + if ( m_iClip == 0 ) + { + return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW_UL, "rpg" ); + } + + return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW1, "rpg" ); +} + + +BOOL CRpg::CanHolster( void ) +{ + if ( m_fSpotActive && m_cActiveRockets ) + { + // can't put away while guiding a missile. + return FALSE; + } + + return TRUE; +} + +void CRpg::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE;// cancel any reload in progress. + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + + SendWeaponAnim( RPG_HOLSTER1 ); + +#ifndef CLIENT_DLL + if (m_pSpot) + { + m_pSpot->Killed( NULL, GIB_NEVER ); + m_pSpot = NULL; + } +#endif + +} + + + +void CRpg::PrimaryAttack() +{ + if ( m_iClip ) + { + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; + +#ifndef CLIENT_DLL + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + UTIL_MakeVectors( m_pPlayer->pev->v_angle ); + Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -8; + + CRpgRocket *pRocket = CRpgRocket::CreateRpgRocket( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this ); + + UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake. + pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); +#endif + + // firing RPG no longer turns on the designator. ALT fire is a toggle switch for the LTD. + // Ken signed up for this as a global change (sjb) + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); + + m_iClip--; + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; + } + else + { + PlayEmptySound( ); + } + UpdateSpot( ); +} + + +void CRpg::SecondaryAttack() +{ + m_fSpotActive = ! m_fSpotActive; + +#ifndef CLIENT_DLL + if (!m_fSpotActive && m_pSpot) + { + m_pSpot->Killed( NULL, GIB_NORMAL ); + m_pSpot = NULL; + } +#endif + + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; +} + + +void CRpg::WeaponIdle( void ) +{ + UpdateSpot( ); + + ResetEmptySound( ); + + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + { + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if (flRand <= 0.75 || m_fSpotActive) + { + if ( m_iClip == 0 ) + iAnim = RPG_IDLE_UL; + else + iAnim = RPG_IDLE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 15.0; + } + else + { + if ( m_iClip == 0 ) + iAnim = RPG_FIDGET_UL; + else + iAnim = RPG_FIDGET; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0; + } + + SendWeaponAnim( iAnim ); + } + else + { + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1; + } +} + + + +void CRpg::UpdateSpot( void ) +{ + +#ifndef CLIENT_DLL + if (m_fSpotActive) + { + if (!m_pSpot) + { + m_pSpot = CLaserSpot::CreateSpot(); + } + + UTIL_MakeVectors( m_pPlayer->pev->v_angle ); + Vector vecSrc = m_pPlayer->GetGunPosition( );; + Vector vecAiming = gpGlobals->v_forward; + + TraceResult tr; + UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr ); + + UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); + } +#endif + +} + + +class CRpgAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_rpgammo.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_rpgammo.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + int iGive; + +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + // hand out more ammo per rocket in multiplayer. + iGive = AMMO_RPGCLIP_GIVE * 2; + } + else + { + iGive = AMMO_RPGCLIP_GIVE; + } + + if (pOther->GiveAmmo( iGive, "rockets", ROCKET_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); + +#endif diff --git a/main/source/dlls/rpg.cpp~ b/main/source/dlls/rpg.cpp~ deleted file mode 100644 index 4ae3d120..00000000 --- a/main/source/dlls/rpg.cpp~ +++ /dev/null @@ -1,619 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" -#include "..mod/AvHNetworkMessages.h" - - - - -enum rpg_e { - RPG_IDLE = 0, - RPG_FIDGET, - RPG_RELOAD, // to reload - RPG_FIRE2, // to empty - RPG_HOLSTER1, // loaded - RPG_DRAW1, // loaded - RPG_HOLSTER2, // unloaded - RPG_DRAW_UL, // unloaded - RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget -}; - -LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ); - -#ifndef CLIENT_DLL - -LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); - -//========================================================= -//========================================================= -CLaserSpot *CLaserSpot::CreateSpot( void ) -{ - CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); - pSpot->Spawn(); - - pSpot->pev->classname = MAKE_STRING("laser_spot"); - - return pSpot; -} - -//========================================================= -//========================================================= -void CLaserSpot::Spawn( void ) -{ - Precache( ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - - pev->rendermode = kRenderGlow; - pev->renderfx = kRenderFxNoDissipation; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/laserdot.spr"); - UTIL_SetOrigin( pev, pev->origin ); -}; - -//========================================================= -// Suspend- make the laser sight invisible. -//========================================================= -void CLaserSpot::Suspend( float flSuspendTime ) -{ - pev->effects |= EF_NODRAW; - - SetThink( &CLaserSpot::Revive ); - pev->nextthink = gpGlobals->time + flSuspendTime; -} - -//========================================================= -// Revive - bring a suspended laser sight back. -//========================================================= -void CLaserSpot::Revive( void ) -{ - pev->effects &= ~EF_NODRAW; - - SetThink( NULL ); -} - -void CLaserSpot::Precache( void ) -{ - PRECACHE_MODEL("sprites/laserdot.spr"); -}; - -LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); - -//========================================================= -//========================================================= -CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ) -{ - CRpgRocket *pRocket = GetClassPtr( (CRpgRocket *)NULL ); - - UTIL_SetOrigin( pRocket->pev, vecOrigin ); - pRocket->pev->angles = vecAngles; - pRocket->Spawn(); - pRocket->SetTouch( &CRpgRocket::RocketTouch ); - pRocket->m_pLauncher = pLauncher;// remember what RPG fired me. - pRocket->m_pLauncher->m_cActiveRockets++;// register this missile as active for the launcher - pRocket->pev->owner = pOwner->edict(); - - return pRocket; -} - -//========================================================= -//========================================================= -void CRpgRocket :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/rpgrocket.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->classname = MAKE_STRING("rpg_rocket"); - - SetThink( &CRpgRocket::IgniteThink ); - SetTouch( &CRpgRocket::ExplodeTouch ); - - pev->angles.x -= 30; - UTIL_MakeVectors( pev->angles ); - pev->angles.x = -(pev->angles.x + 30); - - pev->velocity = gpGlobals->v_forward * 250; - pev->gravity = 0.5; - - pev->nextthink = gpGlobals->time + 0.4; - - pev->dmg = gSkillData.plrDmgRPG; -} - -//========================================================= -//========================================================= -void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) -{ - if ( m_pLauncher ) - { - // my launcher is still around, tell it I'm dead. - m_pLauncher->m_cActiveRockets--; - } - - STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); - ExplodeTouch( pOther ); -} - -//========================================================= -//========================================================= -void CRpgRocket :: Precache( void ) -{ - PRECACHE_MODEL("models/rpgrocket.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); -} - - -void CRpgRocket :: IgniteThink( void ) -{ - // pev->movetype = MOVETYPE_TOSS; - - pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); - - // rocket trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT(entindex()); // entity - WRITE_SHORT(m_iTrail ); // model - WRITE_BYTE( 40 ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - - MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - m_flIgniteTime = gpGlobals->time; - - // set to follow laser spot - SetThink( &CRpgRocket::FollowThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CRpgRocket :: FollowThink( void ) -{ - CBaseEntity *pOther = NULL; - Vector vecTarget; - Vector vecDir; - float flDist, flMax, flDot; - TraceResult tr; - - UTIL_MakeAimVectors( pev->angles ); - - vecTarget = gpGlobals->v_forward; - flMax = 4096; - - // Examine all entities within a reasonable radius - while ((pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" )) != NULL) - { - UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr ); - // ALERT( at_console, "%f\n", tr.flFraction ); - if (tr.flFraction >= 0.90) - { - vecDir = pOther->pev->origin - pev->origin; - flDist = vecDir.Length( ); - vecDir = vecDir.Normalize( ); - flDot = DotProduct( gpGlobals->v_forward, vecDir ); - if ((flDot > 0) && (flDist * (1 - flDot) < flMax)) - { - flMax = flDist * (1 - flDot); - vecTarget = vecDir; - } - } - } - - pev->angles = UTIL_VecToAngles( vecTarget ); - - // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it. - float flSpeed = pev->velocity.Length(); - if (gpGlobals->time - m_flIgniteTime < 1.0) - { - pev->velocity = pev->velocity * 0.2 + vecTarget * (flSpeed * 0.8 + 400); - if (pev->waterlevel == 3) - { - // go slow underwater - if (pev->velocity.Length() > 300) - { - pev->velocity = pev->velocity.Normalize() * 300; - } - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 4 ); - } - else - { - if (pev->velocity.Length() > 2000) - { - pev->velocity = pev->velocity.Normalize() * 2000; - } - } - } - else - { - if (pev->effects & EF_LIGHT) - { - pev->effects = 0; - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav" ); - } - pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; - if (pev->waterlevel == 0 && pev->velocity.Length() < 1500) - { - Detonate( ); - } - } - // ALERT( at_console, "%.0f\n", flSpeed ); - - pev->nextthink = gpGlobals->time + 0.1; -} -#endif - - - -void CRpg::Reload( void ) -{ - int iResult; - - if ( m_iClip == 1 ) - { - // don't bother with any of this if don't need to reload. - return; - } - - if ( m_pPlayer->ammo_rockets <= 0 ) - return; - - // because the RPG waits to autoreload when no missiles are active while the LTD is on, the - // weapons code is constantly calling into this function, but is often denied because - // a) missiles are in flight, but the LTD is on - // or - // b) player is totally out of ammo and has nothing to switch to, and should be allowed to - // shine the designator around - // - // Set the next attack time into the future so that WeaponIdle will get called more often - // than reload, allowing the RPG LTD to be updated - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_cActiveRockets && m_fSpotActive ) - { - // no reloading when there are active missiles tracking the designator. - // ward off future autoreload attempts by setting next attack time into the future for a bit. - return; - } - -#ifndef CLIENT_DLL - if ( m_pSpot && m_fSpotActive ) - { - m_pSpot->Suspend( 2.1 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.1; - } -#endif - - if ( m_iClip == 0 ) - iResult = DefaultReload( RPG_MAX_CLIP, RPG_RELOAD, 2 ); - - if ( iResult ) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - -} - -void CRpg::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_RPG; - - SET_MODEL(ENT(pev), "models/w_rpg.mdl"); - m_fSpotActive = 1; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // more default ammo in multiplay. - m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2; - } - else - { - m_iDefaultAmmo = RPG_DEFAULT_GIVE; - } - - FallInit();// get ready to fall down. -} - - -void CRpg::Precache( void ) -{ - PRECACHE_MODEL("models/w_rpg.mdl"); - PRECACHE_MODEL("models/v_rpg.mdl"); - PRECACHE_MODEL("models/p_rpg.mdl"); - - PRECACHE_SOUND("items/9mmclip1.wav"); - - UTIL_PrecacheOther( "laser_spot" ); - UTIL_PrecacheOther( "rpg_rocket" ); - - PRECACHE_SOUND("weapons/rocketfire1.wav"); - PRECACHE_SOUND("weapons/glauncher.wav"); // alternative fire sound - - m_usRpg = PRECACHE_EVENT ( 1, "events/rpg.sc" ); -} - - -int CRpg::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "rockets"; - p->iMaxAmmo1 = ROCKET_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = RPG_MAX_CLIP; - p->iSlot = 3; - p->iPosition = 0; - p->iId = m_iId = WEAPON_RPG; - p->iFlags = 0; - p->iWeight = RPG_WEIGHT; - - return 1; -} - -int CRpg::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pev, m_iId ); - //MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - // WRITE_BYTE( m_iId ); - //MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CRpg::Deploy( ) -{ - if ( m_iClip == 0 ) - { - return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW_UL, "rpg" ); - } - - return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW1, "rpg" ); -} - - -BOOL CRpg::CanHolster( void ) -{ - if ( m_fSpotActive && m_cActiveRockets ) - { - // can't put away while guiding a missile. - return FALSE; - } - - return TRUE; -} - -void CRpg::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( RPG_HOLSTER1 ); - -#ifndef CLIENT_DLL - if (m_pSpot) - { - m_pSpot->Killed( NULL, GIB_NEVER ); - m_pSpot = NULL; - } -#endif - -} - - - -void CRpg::PrimaryAttack() -{ - if ( m_iClip ) - { - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - -#ifndef CLIENT_DLL - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -8; - - CRpgRocket *pRocket = CRpgRocket::CreateRpgRocket( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake. - pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); -#endif - - // firing RPG no longer turns on the designator. ALT fire is a toggle switch for the LTD. - // Ken signed up for this as a global change (sjb) - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); - - m_iClip--; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - else - { - PlayEmptySound( ); - } - UpdateSpot( ); -} - - -void CRpg::SecondaryAttack() -{ - m_fSpotActive = ! m_fSpotActive; - -#ifndef CLIENT_DLL - if (!m_fSpotActive && m_pSpot) - { - m_pSpot->Killed( NULL, GIB_NORMAL ); - m_pSpot = NULL; - } -#endif - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; -} - - -void CRpg::WeaponIdle( void ) -{ - UpdateSpot( ); - - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75 || m_fSpotActive) - { - if ( m_iClip == 0 ) - iAnim = RPG_IDLE_UL; - else - iAnim = RPG_IDLE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 15.0; - } - else - { - if ( m_iClip == 0 ) - iAnim = RPG_FIDGET_UL; - else - iAnim = RPG_FIDGET; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0; - } - - SendWeaponAnim( iAnim ); - } - else - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1; - } -} - - - -void CRpg::UpdateSpot( void ) -{ - -#ifndef CLIENT_DLL - if (m_fSpotActive) - { - if (!m_pSpot) - { - m_pSpot = CLaserSpot::CreateSpot(); - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( );; - Vector vecAiming = gpGlobals->v_forward; - - TraceResult tr; - UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr ); - - UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); - } -#endif - -} - - -class CRpgAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_rpgammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_rpgammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int iGive; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // hand out more ammo per rocket in multiplayer. - iGive = AMMO_RPGCLIP_GIVE * 2; - } - else - { - iGive = AMMO_RPGCLIP_GIVE; - } - - if (pOther->GiveAmmo( iGive, "rockets", ROCKET_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); - -#endif diff --git a/main/source/dlls/satchel.cpp b/main/source/dlls/satchel.cpp index ea2025b0..b4862121 100644 --- a/main/source/dlls/satchel.cpp +++ b/main/source/dlls/satchel.cpp @@ -1,494 +1,494 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -enum satchel_e { - SATCHEL_IDLE1 = 0, - SATCHEL_FIDGET1, - SATCHEL_DRAW, - SATCHEL_DROP -}; - -enum satchel_radio_e { - SATCHEL_RADIO_IDLE1 = 0, - SATCHEL_RADIO_FIDGET1, - SATCHEL_RADIO_DRAW, - SATCHEL_RADIO_FIRE, - SATCHEL_RADIO_HOLSTER -}; - - - -class CSatchelCharge : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void BounceSound( void ); - - void EXPORT SatchelSlide( CBaseEntity *pOther ); - void EXPORT SatchelThink( void ); - -public: - void Deactivate( void ); -}; -LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ); - -//========================================================= -// Deactivate - do whatever it is we do to an orphaned -// satchel when we don't want it in the world anymore. -//========================================================= -void CSatchelCharge::Deactivate( void ) -{ - pev->solid = SOLID_NOT; - UTIL_Remove( this ); -} - - -void CSatchelCharge :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_satchel.mdl"); - //UTIL_SetSize(pev, Vector( -16, -16, -4), Vector(16, 16, 32)); // Old box -- size of headcrab monsters/players get blocked by this - UTIL_SetSize(pev, Vector( -4, -4, -4), Vector(4, 4, 4)); // Uses point-sized, and can be stepped over - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CSatchelCharge::SatchelSlide ); - SetUse( &CSatchelCharge::DetonateUse ); - SetThink( &CSatchelCharge::SatchelThink ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->gravity = 0.5; - pev->friction = 0.8; - - pev->dmg = gSkillData.plrDmgSatchel; - // ResetSequenceInfo( ); - pev->sequence = 1; -} - - -void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector (300, 300, 300); - pev->gravity = 1;// normal gravity now - - // HACKHACK - On ground isn't always set, so look for ground underneath - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,10), ignore_monsters, edict(), &tr ); - - if ( tr.flFraction < 1.0 ) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - pev->avelocity = pev->avelocity * 0.9; - // play sliding sound, volume based on velocity - } - if ( !(pev->flags & FL_ONGROUND) && pev->velocity.Length2D() > 10 ) - { - BounceSound(); - } - StudioFrameAdvance( ); -} - - -void CSatchelCharge :: SatchelThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - if (pev->waterlevel == 3) - { - pev->movetype = MOVETYPE_FLY; - pev->velocity = pev->velocity * 0.8; - pev->avelocity = pev->avelocity * 0.9; - pev->velocity.z += 8; - } - else if (pev->waterlevel == 0) - { - pev->movetype = MOVETYPE_BOUNCE; - } - else - { - pev->velocity.z -= 8; - } -} - -void CSatchelCharge :: Precache( void ) -{ - PRECACHE_MODEL("models/grenade.mdl"); - PRECACHE_SOUND("weapons/g_bounce1.wav"); - PRECACHE_SOUND("weapons/g_bounce2.wav"); - PRECACHE_SOUND("weapons/g_bounce3.wav"); -} - -void CSatchelCharge :: BounceSound( void ) -{ - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce3.wav", 1, ATTN_NORM); break; - } -} - - -LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ); - - -//========================================================= -// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal -//========================================================= -int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) -{ - CSatchel *pSatchel; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - pSatchel = (CSatchel *)pOriginal; - - if ( pSatchel->m_chargeReady != 0 ) - { - // player has some satchels deployed. Refuse to add more. - return FALSE; - } - } - - return CBasePlayerWeapon::AddDuplicate ( pOriginal ); -} - -//========================================================= -//========================================================= -int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) -{ - int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - - pPlayer->pev->weapons |= (1<pszName = STRING(pev->classname); - p->pszAmmo1 = "Satchel Charge"; - p->iMaxAmmo1 = SATCHEL_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 1; - p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - p->iId = m_iId = WEAPON_SATCHEL; - p->iWeight = SATCHEL_WEIGHT; - - return 1; -} - -//========================================================= -//========================================================= -BOOL CSatchel::IsUseable( void ) -{ - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) - { - // player is carrying some satchels - return TRUE; - } - - if ( m_chargeReady != 0 ) - { - // player isn't carrying any satchels, but has some out - return TRUE; - } - - return FALSE; -} - -BOOL CSatchel::CanDeploy( void ) -{ - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) - { - // player is carrying some satchels - return TRUE; - } - - if ( m_chargeReady != 0 ) - { - // player isn't carrying any satchels, but has some out - return TRUE; - } - - return FALSE; -} - -BOOL CSatchel::Deploy( ) -{ - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - - if ( m_chargeReady ) - return DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" ); - else - return DefaultDeploy( "models/v_satchel.mdl", "models/p_satchel.mdl", SATCHEL_DRAW, "trip" ); - - - return TRUE; -} - - -void CSatchel::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_chargeReady ) - { - SendWeaponAnim( SATCHEL_RADIO_HOLSTER ); - } - else - { - SendWeaponAnim( SATCHEL_DROP ); - } - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); - - if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) - { - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - } -} - - - -void CSatchel::PrimaryAttack() -{ - switch (m_chargeReady) - { - case 0: - { - Throw( ); - } - break; - case 1: - { - SendWeaponAnim( SATCHEL_RADIO_FIRE ); - - edict_t *pPlayer = m_pPlayer->edict( ); - - CBaseEntity *pSatchel = NULL; - - while ((pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 )) != NULL) - { - if (FClassnameIs( pSatchel->pev, "monster_satchel")) - { - if (pSatchel->pev->owner == pPlayer) - { - pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); - m_chargeReady = 2; - } - } - } - - m_chargeReady = 2; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - break; - } - - case 2: - // we're reloading, don't allow fire - { - } - break; - } -} - - -void CSatchel::SecondaryAttack( void ) -{ - if ( m_chargeReady != 2 ) - { - Throw( ); - } -} - - -void CSatchel::Throw( void ) -{ - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - Vector vecSrc = m_pPlayer->pev->origin; - - Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; - -#ifndef CLIENT_DLL - CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0), m_pPlayer->edict() ); - pSatchel->pev->velocity = vecThrow; - pSatchel->pev->avelocity.y = 400; - - m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel_radio.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel_radio.mdl"); -#else - LoadVModel ( "models/v_satchel_radio.mdl", m_pPlayer ); -#endif - - SendWeaponAnim( SATCHEL_RADIO_DRAW ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_chargeReady = 1; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - } -} - - -void CSatchel::WeaponIdle( void ) -{ - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - switch( m_chargeReady ) - { - case 0: - SendWeaponAnim( SATCHEL_FIDGET1 ); - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - break; - case 1: - SendWeaponAnim( SATCHEL_RADIO_FIDGET1 ); - // use hivehand animations - strcpy( m_pPlayer->m_szAnimExtention, "hive" ); - break; - case 2: - if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - m_chargeReady = 0; - RetireWeapon(); - return; - } - -#ifndef CLIENT_DLL - m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel.mdl"); -#else - LoadVModel ( "models/v_satchel.mdl", m_pPlayer ); -#endif - - SendWeaponAnim( SATCHEL_DRAW ); - - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_chargeReady = 0; - break; - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. -} - -//========================================================= -// DeactivateSatchels - removes all satchels owned by -// the provided player. Should only be used upon death. -// -// Made this global on purpose. -//========================================================= -void DeactivateSatchels( CBasePlayer *pOwner ) -{ - edict_t *pFind; - - pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_satchel" ); - - while ( !FNullEnt( pFind ) ) - { - CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); - CSatchelCharge *pSatchel = (CSatchelCharge *)pEnt; - - if ( pSatchel ) - { - if ( pSatchel->pev->owner == pOwner->edict() ) - { - pSatchel->Deactivate(); - } - } - - pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_satchel" ); - } -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" + +enum satchel_e { + SATCHEL_IDLE1 = 0, + SATCHEL_FIDGET1, + SATCHEL_DRAW, + SATCHEL_DROP +}; + +enum satchel_radio_e { + SATCHEL_RADIO_IDLE1 = 0, + SATCHEL_RADIO_FIDGET1, + SATCHEL_RADIO_DRAW, + SATCHEL_RADIO_FIRE, + SATCHEL_RADIO_HOLSTER +}; + + + +class CSatchelCharge : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + void BounceSound( void ); + + void EXPORT SatchelSlide( CBaseEntity *pOther ); + void EXPORT SatchelThink( void ); + +public: + void Deactivate( void ); +}; +LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ); + +//========================================================= +// Deactivate - do whatever it is we do to an orphaned +// satchel when we don't want it in the world anymore. +//========================================================= +void CSatchelCharge::Deactivate( void ) +{ + pev->solid = SOLID_NOT; + UTIL_Remove( this ); +} + + +void CSatchelCharge :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/w_satchel.mdl"); + //UTIL_SetSize(pev, Vector( -16, -16, -4), Vector(16, 16, 32)); // Old box -- size of headcrab monsters/players get blocked by this + UTIL_SetSize(pev, Vector( -4, -4, -4), Vector(4, 4, 4)); // Uses point-sized, and can be stepped over + UTIL_SetOrigin( pev, pev->origin ); + + SetTouch( &CSatchelCharge::SatchelSlide ); + SetUse( &CSatchelCharge::DetonateUse ); + SetThink( &CSatchelCharge::SatchelThink ); + pev->nextthink = gpGlobals->time + 0.1; + + pev->gravity = 0.5; + pev->friction = 0.8; + + pev->dmg = gSkillData.plrDmgSatchel; + // ResetSequenceInfo( ); + pev->sequence = 1; +} + + +void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + // don't hit the guy that launched this grenade + if ( pOther->edict() == pev->owner ) + return; + + // pev->avelocity = Vector (300, 300, 300); + pev->gravity = 1;// normal gravity now + + // HACKHACK - On ground isn't always set, so look for ground underneath + TraceResult tr; + UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,10), ignore_monsters, edict(), &tr ); + + if ( tr.flFraction < 1.0 ) + { + // add a bit of static friction + pev->velocity = pev->velocity * 0.95; + pev->avelocity = pev->avelocity * 0.9; + // play sliding sound, volume based on velocity + } + if ( !(pev->flags & FL_ONGROUND) && pev->velocity.Length2D() > 10 ) + { + BounceSound(); + } + StudioFrameAdvance( ); +} + + +void CSatchelCharge :: SatchelThink( void ) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + if (!IsInWorld()) + { + UTIL_Remove( this ); + return; + } + + if (pev->waterlevel == 3) + { + pev->movetype = MOVETYPE_FLY; + pev->velocity = pev->velocity * 0.8; + pev->avelocity = pev->avelocity * 0.9; + pev->velocity.z += 8; + } + else if (pev->waterlevel == 0) + { + pev->movetype = MOVETYPE_BOUNCE; + } + else + { + pev->velocity.z -= 8; + } +} + +void CSatchelCharge :: Precache( void ) +{ + PRECACHE_MODEL("models/grenade.mdl"); + PRECACHE_SOUND("weapons/g_bounce1.wav"); + PRECACHE_SOUND("weapons/g_bounce2.wav"); + PRECACHE_SOUND("weapons/g_bounce3.wav"); +} + +void CSatchelCharge :: BounceSound( void ) +{ + switch ( RANDOM_LONG( 0, 2 ) ) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce1.wav", 1, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce2.wav", 1, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce3.wav", 1, ATTN_NORM); break; + } +} + + +LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ); + + +//========================================================= +// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal +//========================================================= +int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) +{ + CSatchel *pSatchel; + +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + pSatchel = (CSatchel *)pOriginal; + + if ( pSatchel->m_chargeReady != 0 ) + { + // player has some satchels deployed. Refuse to add more. + return FALSE; + } + } + + return CBasePlayerWeapon::AddDuplicate ( pOriginal ); +} + +//========================================================= +//========================================================= +int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) +{ + int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); + + pPlayer->pev->weapons |= (1<pszName = STRING(pev->classname); + p->pszAmmo1 = "Satchel Charge"; + p->iMaxAmmo1 = SATCHEL_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 4; + p->iPosition = 1; + p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; + p->iId = m_iId = WEAPON_SATCHEL; + p->iWeight = SATCHEL_WEIGHT; + + return 1; +} + +//========================================================= +//========================================================= +BOOL CSatchel::IsUseable( void ) +{ + if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) + { + // player is carrying some satchels + return TRUE; + } + + if ( m_chargeReady != 0 ) + { + // player isn't carrying any satchels, but has some out + return TRUE; + } + + return FALSE; +} + +BOOL CSatchel::CanDeploy( void ) +{ + if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) + { + // player is carrying some satchels + return TRUE; + } + + if ( m_chargeReady != 0 ) + { + // player isn't carrying any satchels, but has some out + return TRUE; + } + + return FALSE; +} + +BOOL CSatchel::Deploy( ) +{ + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + + if ( m_chargeReady ) + return DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" ); + else + return DefaultDeploy( "models/v_satchel.mdl", "models/p_satchel.mdl", SATCHEL_DRAW, "trip" ); + + + return TRUE; +} + + +void CSatchel::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + + if ( m_chargeReady ) + { + SendWeaponAnim( SATCHEL_RADIO_HOLSTER ); + } + else + { + SendWeaponAnim( SATCHEL_DROP ); + } + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); + + if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) + { + m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; + } +} + + + +void CSatchel::PrimaryAttack() +{ + switch (m_chargeReady) + { + case 0: + { + Throw( ); + } + break; + case 1: + { + SendWeaponAnim( SATCHEL_RADIO_FIRE ); + + edict_t *pPlayer = m_pPlayer->edict( ); + + CBaseEntity *pSatchel = NULL; + + while ((pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 )) != NULL) + { + if (FClassnameIs( pSatchel->pev, "monster_satchel")) + { + if (pSatchel->pev->owner == pPlayer) + { + pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); + m_chargeReady = 2; + } + } + } + + m_chargeReady = 2; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + break; + } + + case 2: + // we're reloading, don't allow fire + { + } + break; + } +} + + +void CSatchel::SecondaryAttack( void ) +{ + if ( m_chargeReady != 2 ) + { + Throw( ); + } +} + + +void CSatchel::Throw( void ) +{ + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + { + Vector vecSrc = m_pPlayer->pev->origin; + + Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; + +#ifndef CLIENT_DLL + CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0), m_pPlayer->edict() ); + pSatchel->pev->velocity = vecThrow; + pSatchel->pev->avelocity.y = 400; + + m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel_radio.mdl"); + m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel_radio.mdl"); +#else + LoadVModel ( "models/v_satchel_radio.mdl", m_pPlayer ); +#endif + + SendWeaponAnim( SATCHEL_RADIO_DRAW ); + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_chargeReady = 1; + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + } +} + + +void CSatchel::WeaponIdle( void ) +{ + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + switch( m_chargeReady ) + { + case 0: + SendWeaponAnim( SATCHEL_FIDGET1 ); + // use tripmine animations + strcpy( m_pPlayer->m_szAnimExtention, "trip" ); + break; + case 1: + SendWeaponAnim( SATCHEL_RADIO_FIDGET1 ); + // use hivehand animations + strcpy( m_pPlayer->m_szAnimExtention, "hive" ); + break; + case 2: + if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + { + m_chargeReady = 0; + RetireWeapon(); + return; + } + +#ifndef CLIENT_DLL + m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel.mdl"); + m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel.mdl"); +#else + LoadVModel ( "models/v_satchel.mdl", m_pPlayer ); +#endif + + SendWeaponAnim( SATCHEL_DRAW ); + + // use tripmine animations + strcpy( m_pPlayer->m_szAnimExtention, "trip" ); + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_chargeReady = 0; + break; + } + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. +} + +//========================================================= +// DeactivateSatchels - removes all satchels owned by +// the provided player. Should only be used upon death. +// +// Made this global on purpose. +//========================================================= +void DeactivateSatchels( CBasePlayer *pOwner ) +{ + edict_t *pFind; + + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_satchel" ); + + while ( !FNullEnt( pFind ) ) + { + CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); + CSatchelCharge *pSatchel = (CSatchelCharge *)pEnt; + + if ( pSatchel ) + { + if ( pSatchel->pev->owner == pOwner->edict() ) + { + pSatchel->Deactivate(); + } + } + + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_satchel" ); + } +} + #endif \ No newline at end of file diff --git a/main/source/dlls/saverestore.h b/main/source/dlls/saverestore.h index c07a66c1..c2964eec 100644 --- a/main/source/dlls/saverestore.h +++ b/main/source/dlls/saverestore.h @@ -1,171 +1,171 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Implementation in UTIL.CPP -#ifndef SAVERESTORE_H -#define SAVERESTORE_H - -class CBaseEntity; - -class CSaveRestoreBuffer -{ -public: - CSaveRestoreBuffer( void ); - CSaveRestoreBuffer( SAVERESTOREDATA *pdata ); - ~CSaveRestoreBuffer( void ); - - int EntityIndex( entvars_t *pevLookup ); - int EntityIndex( edict_t *pentLookup ); - int EntityIndex( EOFFSET eoLookup ); - int EntityIndex( CBaseEntity *pEntity ); - - int EntityFlags( int entityIndex, int flags ) { return EntityFlagsSet( entityIndex, 0 ); } - int EntityFlagsSet( int entityIndex, int flags ); - - edict_t *EntityFromIndex( int entityIndex ); - - unsigned short TokenHash( const char *pszToken ); - -protected: - SAVERESTOREDATA *m_pdata; - void BufferRewind( int size ); - unsigned int HashString( const char *pszToken ); -}; - - -class CSave : public CSaveRestoreBuffer -{ -public: - CSave( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) {}; - - void WriteShort( const char *pname, const short *value, int count ); - void WriteInt( const char *pname, const int *value, int count ); // Save an int - void WriteFloat( const char *pname, const float *value, int count ); // Save a float - void WriteTime( const char *pname, const float *value, int count ); // Save a float (timevalue) - void WriteData( const char *pname, int size, const char *pdata ); // Save a binary data block - void WriteString( const char *pname, const char *pstring ); // Save a null-terminated string - void WriteString( const char *pname, const int *stringId, int count ); // Save a null-terminated string (engine string) - void WriteVector( const char *pname, const Vector &value ); // Save a vector - void WriteVector( const char *pname, const float *value, int count ); // Save a vector - void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary - void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors - void WriteFunction( const char *pname, const int *value, int count ); // Save a function pointer - int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) - int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - -private: - int DataEmpty( const char *pdata, int size ); - void BufferField( const char *pname, int size, const char *pdata ); - void BufferString( char *pdata, int len ); - void BufferData( const char *pdata, int size ); - void BufferHeader( const char *pname, int size ); -}; - -typedef struct -{ - unsigned short size; - unsigned short token; - char *pData; -} HEADER; - -class CRestore : public CSaveRestoreBuffer -{ -public: - CRestore( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) { m_global = 0; m_precache = TRUE; } - int ReadEntVars( const char *pname, entvars_t *pev ); // entvars_t - int ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - int ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ); - int ReadInt( void ); - short ReadShort( void ); - int ReadNamedInt( const char *pName ); - char *ReadNamedString( const char *pName ); - int Empty( void ) { return (m_pdata == NULL) || ((m_pdata->pCurrentData-m_pdata->pBaseData)>=m_pdata->bufferSize); } - inline void SetGlobalMode( int global ) { m_global = global; } - void PrecacheMode( BOOL mode ) { m_precache = mode; } - -private: - char *BufferPointer( void ); - void BufferReadBytes( char *pOutput, int size ); - void BufferSkipBytes( int bytes ); - int BufferSkipZString( void ); - int BufferCheckZString( const char *string ); - - void BufferReadHeader( HEADER *pheader ); - - int m_global; // Restoring a global entity? - BOOL m_precache; -}; - -#define MAX_ENTITYARRAY 64 - -//#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) - -#define IMPLEMENT_SAVERESTORE(derivedClass,baseClass) \ - int derivedClass::Save( CSave &save )\ - {\ - if ( !baseClass::Save(save) )\ - return 0;\ - return save.WriteFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - }\ - int derivedClass::Restore( CRestore &restore )\ - {\ - if ( !baseClass::Restore(restore) )\ - return 0;\ - return restore.ReadFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - } - - -typedef enum { GLOBAL_OFF = 0, GLOBAL_ON = 1, GLOBAL_DEAD = 2 } GLOBALESTATE; - -typedef struct globalentity_s globalentity_t; - -struct globalentity_s -{ - char name[64]; - char levelName[32]; - GLOBALESTATE state; - globalentity_t *pNext; -}; - -class CGlobalState -{ -public: - CGlobalState(); - void Reset( void ); - void ClearStates( void ); - void EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ); - void EntitySetState( string_t globalname, GLOBALESTATE state ); - void EntityUpdate( string_t globalname, string_t mapname ); - const globalentity_t *EntityFromTable( string_t globalname ); - GLOBALESTATE EntityGetState( string_t globalname ); - int EntityInTable( string_t globalname ) { return (Find( globalname ) != NULL) ? 1 : 0; } - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - const char* GetLevelName(); - -//#ifdef _DEBUG - void DumpGlobals( void ); -//#endif - -private: - globalentity_t *Find( string_t globalname ); - globalentity_t *m_pList; - int m_listCount; -}; - -extern CGlobalState gGlobalState; - -#endif //SAVERESTORE_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Implementation in UTIL.CPP +#ifndef SAVERESTORE_H +#define SAVERESTORE_H + +class CBaseEntity; + +class CSaveRestoreBuffer +{ +public: + CSaveRestoreBuffer( void ); + CSaveRestoreBuffer( SAVERESTOREDATA *pdata ); + ~CSaveRestoreBuffer( void ); + + int EntityIndex( entvars_t *pevLookup ); + int EntityIndex( edict_t *pentLookup ); + int EntityIndex( EOFFSET eoLookup ); + int EntityIndex( CBaseEntity *pEntity ); + + int EntityFlags( int entityIndex, int flags ) { return EntityFlagsSet( entityIndex, 0 ); } + int EntityFlagsSet( int entityIndex, int flags ); + + edict_t *EntityFromIndex( int entityIndex ); + + unsigned short TokenHash( const char *pszToken ); + +protected: + SAVERESTOREDATA *m_pdata; + void BufferRewind( int size ); + unsigned int HashString( const char *pszToken ); +}; + + +class CSave : public CSaveRestoreBuffer +{ +public: + CSave( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) {}; + + void WriteShort( const char *pname, const short *value, int count ); + void WriteInt( const char *pname, const int *value, int count ); // Save an int + void WriteFloat( const char *pname, const float *value, int count ); // Save a float + void WriteTime( const char *pname, const float *value, int count ); // Save a float (timevalue) + void WriteData( const char *pname, int size, const char *pdata ); // Save a binary data block + void WriteString( const char *pname, const char *pstring ); // Save a null-terminated string + void WriteString( const char *pname, const int *stringId, int count ); // Save a null-terminated string (engine string) + void WriteVector( const char *pname, const Vector &value ); // Save a vector + void WriteVector( const char *pname, const float *value, int count ); // Save a vector + void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary + void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors + void WriteFunction( const char *pname, const int *value, int count ); // Save a function pointer + int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) + int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); + +private: + int DataEmpty( const char *pdata, int size ); + void BufferField( const char *pname, int size, const char *pdata ); + void BufferString( char *pdata, int len ); + void BufferData( const char *pdata, int size ); + void BufferHeader( const char *pname, int size ); +}; + +typedef struct +{ + unsigned short size; + unsigned short token; + char *pData; +} HEADER; + +class CRestore : public CSaveRestoreBuffer +{ +public: + CRestore( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) { m_global = 0; m_precache = TRUE; } + int ReadEntVars( const char *pname, entvars_t *pev ); // entvars_t + int ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); + int ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ); + int ReadInt( void ); + short ReadShort( void ); + int ReadNamedInt( const char *pName ); + char *ReadNamedString( const char *pName ); + int Empty( void ) { return (m_pdata == NULL) || ((m_pdata->pCurrentData-m_pdata->pBaseData)>=m_pdata->bufferSize); } + inline void SetGlobalMode( int global ) { m_global = global; } + void PrecacheMode( BOOL mode ) { m_precache = mode; } + +private: + char *BufferPointer( void ); + void BufferReadBytes( char *pOutput, int size ); + void BufferSkipBytes( int bytes ); + int BufferSkipZString( void ); + int BufferCheckZString( const char *string ); + + void BufferReadHeader( HEADER *pheader ); + + int m_global; // Restoring a global entity? + BOOL m_precache; +}; + +#define MAX_ENTITYARRAY 64 + +//#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +#define IMPLEMENT_SAVERESTORE(derivedClass,baseClass) \ + int derivedClass::Save( CSave &save )\ + {\ + if ( !baseClass::Save(save) )\ + return 0;\ + return save.WriteFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ + }\ + int derivedClass::Restore( CRestore &restore )\ + {\ + if ( !baseClass::Restore(restore) )\ + return 0;\ + return restore.ReadFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ + } + + +typedef enum { GLOBAL_OFF = 0, GLOBAL_ON = 1, GLOBAL_DEAD = 2 } GLOBALESTATE; + +typedef struct globalentity_s globalentity_t; + +struct globalentity_s +{ + char name[64]; + char levelName[32]; + GLOBALESTATE state; + globalentity_t *pNext; +}; + +class CGlobalState +{ +public: + CGlobalState(); + void Reset( void ); + void ClearStates( void ); + void EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ); + void EntitySetState( string_t globalname, GLOBALESTATE state ); + void EntityUpdate( string_t globalname, string_t mapname ); + const globalentity_t *EntityFromTable( string_t globalname ); + GLOBALESTATE EntityGetState( string_t globalname ); + int EntityInTable( string_t globalname ) { return (Find( globalname ) != NULL) ? 1 : 0; } + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + const char* GetLevelName(); + +//#ifdef _DEBUG + void DumpGlobals( void ); +//#endif + +private: + globalentity_t *Find( string_t globalname ); + globalentity_t *m_pList; + int m_listCount; +}; + +extern CGlobalState gGlobalState; + +#endif //SAVERESTORE_H diff --git a/main/source/dlls/schedule.cpp b/main/source/dlls/schedule.cpp index 2b6058e4..f9ff6db4 100644 --- a/main/source/dlls/schedule.cpp +++ b/main/source/dlls/schedule.cpp @@ -1,1514 +1,1514 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// schedule.cpp - functions and data pertaining to the -// monsters' AI scheduling system. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "scripted.h" -#include "nodes.h" -#include "defaultai.h" -#include "soundent.h" - -extern CGraph WorldGraph; - -//========================================================= -// FHaveSchedule - Returns TRUE if monster's m_pSchedule -// is anything other than NULL. -//========================================================= -BOOL CBaseMonster :: FHaveSchedule( void ) -{ - if ( m_pSchedule == NULL ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// ClearSchedule - blanks out the caller's schedule pointer -// and index. -//========================================================= -void CBaseMonster :: ClearSchedule( void ) -{ - m_iTaskStatus = TASKSTATUS_NEW; - m_pSchedule = NULL; - m_iScheduleIndex = 0; -} - -//========================================================= -// FScheduleDone - Returns TRUE if the caller is on the -// last task in the schedule -//========================================================= -BOOL CBaseMonster :: FScheduleDone ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - if ( m_iScheduleIndex == m_pSchedule->cTasks ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// ChangeSchedule - replaces the monster's schedule pointer -// with the passed pointer, and sets the ScheduleIndex back -// to 0 -//========================================================= -void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) -{ - ASSERT( pNewSchedule != NULL ); - - m_pSchedule = pNewSchedule; - m_iScheduleIndex = 0; - m_iTaskStatus = TASKSTATUS_NEW; - m_afConditions = 0;// clear all of the conditions - m_failSchedule = SCHED_NONE; - - if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) - { - ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); - } - else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) - { - ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); - } - -#if _DEBUG - if ( !ScheduleFromName( pNewSchedule->pName ) ) - { - ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); - } -#endif - -// this is very useful code if you can isolate a test case in a level with a single monster. It will notify -// you of every schedule selection the monster makes. -#if 0 - if ( FClassnameIs( pev, "monster_human_grunt" ) ) - { - Task_t *pTask = GetTask(); - - if ( pTask ) - { - const char *pName = NULL; - - if ( m_pSchedule ) - { - pName = m_pSchedule->pName; - } - else - { - pName = "No Schedule"; - } - - if ( !pName ) - { - pName = "Unknown"; - } - - ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); - } - } -#endif// 0 - -} - -//========================================================= -// NextScheduledTask - increments the ScheduleIndex -//========================================================= -void CBaseMonster :: NextScheduledTask ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - m_iTaskStatus = TASKSTATUS_NEW; - m_iScheduleIndex++; - - if ( FScheduleDone() ) - { - // just completed last task in schedule, so make it invalid by clearing it. - SetConditions( bits_COND_SCHEDULE_DONE ); - //ClearSchedule(); - } -} - -//========================================================= -// IScheduleFlags - returns an integer with all Conditions -// bits that are currently set and also set in the current -// schedule's Interrupt mask. -//========================================================= -int CBaseMonster :: IScheduleFlags ( void ) -{ - if( !m_pSchedule ) - { - return 0; - } - - // strip off all bits excepts the ones capable of breaking this schedule. - return m_afConditions & m_pSchedule->iInterruptMask; -} - -//========================================================= -// FScheduleValid - returns TRUE as long as the current -// schedule is still the proper schedule to be executing, -// taking into account all conditions -//========================================================= -BOOL CBaseMonster :: FScheduleValid ( void ) -{ - if ( m_pSchedule == NULL ) - { - // schedule is empty, and therefore not valid. - return FALSE; - } - - if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) - { -#ifdef DEBUG - if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) - { - // fail! Send a visual indicator. - ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); - - Vector tmp = pev->origin; - tmp.z = pev->absmax.z + 16; - UTIL_Sparks( tmp ); - } -#endif // DEBUG - - // some condition has interrupted the schedule, or the schedule is done - return FALSE; - } - - return TRUE; -} - -//========================================================= -// MaintainSchedule - does all the per-think schedule maintenance. -// ensures that the monster leaves this function with a valid -// schedule! -//========================================================= -void CBaseMonster :: MaintainSchedule ( void ) -{ - Schedule_t *pNewSchedule; - int i; - - // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible - for ( i = 0; i < 10; i++ ) - { - if ( m_pSchedule != NULL && TaskIsComplete() ) - { - NextScheduledTask(); - } - - // validate existing schedule - if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) - { - // if we come into this block of code, the schedule is going to have to be changed. - // if the previous schedule was interrupted by a condition, GetIdealState will be - // called. Else, a schedule finished normally. - - // Notify the monster that his schedule is changing - ScheduleChange(); - - // Call GetIdealState if we're not dead and one or more of the following... - // - in COMBAT state with no enemy (it died?) - // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, - // - schedule is done but schedule indicates it wants GetIdealState called - // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) - // DEAD & SCRIPT are not suggestions, they are commands! - if ( m_IdealMonsterState != MONSTERSTATE_DEAD && - (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) - { - if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || - (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || - ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == NULL)) ) - { - GetIdealState(); - } - } - if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) - { - if ( m_failSchedule != SCHED_NONE ) - pNewSchedule = GetScheduleOfType( m_failSchedule ); - else - pNewSchedule = GetScheduleOfType( SCHED_FAIL ); - // schedule was invalid because the current task failed to start or complete - ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); - ChangeSchedule( pNewSchedule ); - } - else - { - SetState( m_IdealMonsterState ); - if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) - pNewSchedule = CBaseMonster::GetSchedule(); - else - pNewSchedule = GetSchedule(); - ChangeSchedule( pNewSchedule ); - } - } - - if ( m_iTaskStatus == TASKSTATUS_NEW ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - TaskBegin(); - StartTask( pTask ); - } - - // UNDONE: Twice?!!! - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - - if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) - break; - } - - if ( TaskIsRunning() ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - RunTask( pTask ); - } - - // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation - // RunTask() will always change animations at the end of a script! - // Don't do this twice - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } -} - -//========================================================= -// RunTask -//========================================================= -void CBaseMonster :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - case TASK_TURN_LEFT: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - { - CBaseEntity *pTarget; - - if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) - pTarget = m_hTargetEnt; - else - pTarget = m_hEnemy; - if ( pTarget ) - { - pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - if ( m_fSequenceFinished ) - TaskComplete(); - } - break; - - case TASK_PLAY_SEQUENCE: - case TASK_PLAY_ACTIVE_IDLE: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - - - case TASK_FACE_ENEMY: - { - MakeIdealYaw( m_vecEnemyLKP ); - - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_FACE_HINTNODE: - case TASK_FACE_LASTPOSITION: - case TASK_FACE_TARGET: - case TASK_FACE_IDEAL: - case TASK_FACE_ROUTE: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_PVS: - { - if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_RANDOM: - { - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - float distance; - - if ( m_hTargetEnt == NULL ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK ) - m_movementActivity = ACT_WALK; - else if ( distance >= 270 && m_movementActivity != ACT_RUN ) - m_movementActivity = ACT_RUN; - } - - break; - } - case TASK_WAIT_FOR_MOVEMENT: - { - if (MovementIsComplete()) - { - TaskComplete(); - RouteClear(); // Stop moving - } - break; - } - case TASK_DIE: - { - if ( m_fSequenceFinished && pev->frame >= 255 ) - { - pev->deadflag = DEAD_DEAD; - - SetThink ( NULL ); - StopAnimation(); - - if ( !BBoxFlat() ) - { - // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will - // block the player on a slope or stairs, the corpse is made nonsolid. -// pev->solid = SOLID_NOT; - UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); - } - else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem - UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); - - if ( ShouldFadeOnDeath() ) - { - // this monster was created by a monstermaker... fade the corpse out. - SUB_StartFadeOut(); - } - else - { - // body is gonna be around for a while, so have it stink for a bit. - CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); - } - } - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RELOAD_NOTURN: - { - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_RANGE_ATTACK1: - case TASK_MELEE_ATTACK1: - case TASK_MELEE_ATTACK2: - case TASK_RANGE_ATTACK2: - case TASK_SPECIAL_ATTACK1: - case TASK_SPECIAL_ATTACK2: - case TASK_RELOAD: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_SMALL_FLINCH: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - } - break; - case TASK_WAIT_FOR_SCRIPT: - { - if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) - { - TaskComplete(); - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); - if ( m_fSequenceFinished ) - ClearSchedule(); - pev->framerate = 1.0; - //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - } - break; - } - case TASK_PLAY_SCRIPT: - { - if (m_fSequenceFinished) - { - m_pCine->SequenceDone( this ); - } - break; - } - } -} - -//========================================================= -// SetTurnActivity - measures the difference between the way -// the monster is facing and determines whether or not to -// select one of the 180 turn animations. -//========================================================= -void CBaseMonster :: SetTurnActivity ( void ) -{ - float flYD; - flYD = FlYawDiff(); - - if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) - {// big right turn - m_IdealActivity = ACT_TURN_RIGHT; - } - else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) - {// big left turn - m_IdealActivity = ACT_TURN_LEFT; - } -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CBaseMonster :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_TURN_LEFT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_REMEMBER: - { - Remember ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FORGET: - { - Forget ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FIND_HINTNODE: - { - m_iHintNode = FindHintNode(); - - if ( m_iHintNode != NO_NODE ) - { - TaskComplete(); - } - else - { - TaskFail(); - } - break; - } - case TASK_STORE_LASTPOSITION: - { - m_vecLastPosition = pev->origin; - TaskComplete(); - break; - } - case TASK_CLEAR_LASTPOSITION: - { - m_vecLastPosition = g_vecZero; - TaskComplete(); - break; - } - case TASK_CLEAR_HINTNODE: - { - m_iHintNode = NO_NODE; - TaskComplete(); - break; - } - case TASK_STOP_MOVING: - { - if ( m_IdealActivity == m_movementActivity ) - { - m_IdealActivity = GetStoppedActivity(); - } - - RouteClear(); - TaskComplete(); - break; - } - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - case TASK_PLAY_SEQUENCE: - { - m_IdealActivity = ( Activity )( int )pTask->flData; - break; - } - case TASK_PLAY_ACTIVE_IDLE: - { - // monsters verify that they have a sequence for the node's activity BEFORE - // moving towards the node, so it's ok to just set the activity without checking here. - m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; - break; - } - case TASK_SET_SCHEDULE: - { - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( (int)pTask->flData ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } - else - { - TaskFail(); - } - - break; - } - case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ENEMY: - { - entvars_t *pevCover; - - if ( m_hEnemy == NULL ) - { - // Find cover from self if no enemy available - pevCover = pev; -// TaskFail(); -// return; - } - else - pevCover = m_hEnemy->pev; - - if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ORIGIN: - { - if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no cover! - TaskFail(); - } - } - break; - case TASK_FIND_COVER_FROM_BEST_SOUND: - { - CSound *pBestSound; - - pBestSound = PBestSound(); - - ASSERT( pBestSound != NULL ); - /* - if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - */ - - if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. or no sound in list - TaskFail(); - } - break; - } - case TASK_FACE_HINTNODE: - { - pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; - SetTurnActivity(); - break; - } - - case TASK_FACE_LASTPOSITION: - MakeIdealYaw ( m_vecLastPosition ); - SetTurnActivity(); - break; - - case TASK_FACE_TARGET: - if ( m_hTargetEnt != NULL ) - { - MakeIdealYaw ( m_hTargetEnt->pev->origin ); - SetTurnActivity(); - } - else - TaskFail(); - break; - case TASK_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - SetTurnActivity(); - break; - } - case TASK_FACE_IDEAL: - { - SetTurnActivity(); - break; - } - case TASK_FACE_ROUTE: - { - if (FRouteClear()) - { - ALERT(at_aiconsole, "No route to face!\n"); - TaskFail(); - } - else - { - MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); - SetTurnActivity(); - } - break; - } - case TASK_WAIT_PVS: - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - } - case TASK_WAIT_RANDOM: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK, 2 ) ) - TaskFail(); - } - break; - } - case TASK_RUN_TO_TARGET: - case TASK_WALK_TO_TARGET: - { - Activity newActivity; - - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - if ( pTask->iTask == TASK_WALK_TO_TARGET ) - newActivity = ACT_WALK; - else - newActivity = ACT_RUN; - // This monster can't do this! - if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) - TaskComplete(); - else - { - if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); - RouteClear(); - } - } - } - TaskComplete(); - break; - } - case TASK_CLEAR_MOVE_WAIT: - { - m_flMoveWaitFinished = gpGlobals->time; - TaskComplete(); - break; - } - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1: - { - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - } - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_MELEE_ATTACK2: - { - m_IdealActivity = ACT_MELEE_ATTACK2; - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2: - { - m_IdealActivity = ACT_RANGE_ATTACK2; - break; - } - case TASK_RELOAD_NOTURN: - case TASK_RELOAD: - { - m_IdealActivity = ACT_RELOAD; - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_SPECIAL_ATTACK2: - { - m_IdealActivity = ACT_SPECIAL_ATTACK2; - break; - } - case TASK_SET_ACTIVITY: - { - m_IdealActivity = (Activity)(int)pTask->flData; - TaskComplete(); - break; - } - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - case TASK_GET_PATH_TO_SPOT: - { - CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); - if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - - case TASK_GET_PATH_TO_TARGET: - { - RouteClear(); - if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_HINTNODE:// for active idles! - { - if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_LASTPOSITION: - { - m_vecMoveGoal = m_vecLastPosition; - - if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_BESTSOUND: - { - CSound *pSound; - - pSound = PBestSound(); - - if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); - TaskFail(); - } - break; - } -case TASK_GET_PATH_TO_BESTSCENT: - { - CSound *pScent; - - pScent = PBestScent(); - - if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); - - TaskFail(); - } - break; - } - case TASK_RUN_PATH: - { - // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? - if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_RUN; - } - else - { - m_movementActivity = ACT_WALK; - } - TaskComplete(); - break; - } - case TASK_WALK_PATH: - { - if ( pev->movetype == MOVETYPE_FLY ) - { - m_movementActivity = ACT_FLY; - } - if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_WALK; - } - else - { - m_movementActivity = ACT_RUN; - } - TaskComplete(); - break; - } - case TASK_STRAFE_PATH: - { - Vector2D vec2DirToPoint; - Vector2D vec2RightSide; - - // to start strafing, we have to first figure out if the target is on the left side or right side - UTIL_MakeVectors ( pev->angles ); - - vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); - vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); - - if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) - { - // strafe right - m_movementActivity = ACT_STRAFE_RIGHT; - } - else - { - // strafe left - m_movementActivity = ACT_STRAFE_LEFT; - } - TaskComplete(); - break; - } - - - case TASK_WAIT_FOR_MOVEMENT: - { - if (FRouteClear()) - { - TaskComplete(); - } - break; - } - - case TASK_EAT: - { - Eat( pTask->flData ); - TaskComplete(); - break; - } - case TASK_SMALL_FLINCH: - { - m_IdealActivity = GetSmallFlinchActivity(); - break; - } - case TASK_DIE: - { - RouteClear(); - - m_IdealActivity = GetDeathActivity(); - - pev->deadflag = DEAD_DYING; - break; - } - case TASK_SOUND_WAKE: - { - AlertSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DIE: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_IDLE: - { - IdleSound(); - TaskComplete(); - break; - } - case TASK_SOUND_PAIN: - { - PainSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DEATH: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_ANGRY: - { - // sounds are complete as soon as we get here, cause we've already played them. - ALERT ( at_aiconsole, "SOUND\n" ); - TaskComplete(); - break; - } - case TASK_WAIT_FOR_SCRIPT: - { - if (m_pCine->m_iszIdle) - { - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); - if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) - { - pev->framerate = 0; - } - } - else - m_IdealActivity = ACT_IDLE; - - break; - } - case TASK_PLAY_SCRIPT: - { - pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); - m_scriptState = SCRIPT_PLAYING; - break; - } - case TASK_ENABLE_SCRIPT: - { - m_pCine->DelayStart( 0 ); - TaskComplete(); - break; - } - case TASK_PLANT_ON_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->origin = m_hTargetEnt->pev->origin; // Plant on target - } - - TaskComplete(); - break; - } - case TASK_FACE_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); - } - - TaskComplete(); - m_IdealActivity = ACT_IDLE; - RouteClear(); - break; - } - - case TASK_SUGGEST_STATE: - { - m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; - TaskComplete(); - break; - } - - case TASK_SET_FAIL_SCHEDULE: - m_failSchedule = (int)pTask->flData; - TaskComplete(); - break; - - case TASK_CLEAR_FAIL_SCHEDULE: - m_failSchedule = SCHED_NONE; - TaskComplete(); - break; - - default: - { - ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); - break; - } - } -} - -//========================================================= -// GetTask - returns a pointer to the current -// scheduled task. NULL if there's a problem. -//========================================================= -Task_t *CBaseMonster :: GetTask ( void ) -{ - if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) - { - // m_iScheduleIndex is not within valid range for the monster's current schedule. - return NULL; - } - else - { - return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CBaseMonster :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_PRONE: - { - return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); - break; - } - case MONSTERSTATE_NONE: - { - ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); - break; - } - case MONSTERSTATE_IDLE: - { - if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else if ( FRouteClear() ) - { - // no valid route! - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - else - { - // valid route. Get moving - return GetScheduleOfType( SCHED_IDLE_WALK ); - } - break; - } - case MONSTERSTATE_ALERT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) - { - return GetScheduleOfType ( SCHED_VICTORY_DANCE ); - } - - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) - { - if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); - } - } - - else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_STAND ); - } - break; - } - case MONSTERSTATE_COMBAT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // clear the current (dead) enemy and try to find another. - m_hEnemy = NULL; - - if ( GetEnemy() ) - { - ClearConditions( bits_COND_ENEMY_DEAD ); - return GetSchedule(); - } - else - { - SetState( MONSTERSTATE_ALERT ); - return GetSchedule(); - } - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); - } - else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - else if ( !HasConditions(bits_COND_SEE_ENEMY) ) - { - // we can't see the enemy - if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) - { - // enemy is unseen, but not occluded! - // turn to face enemy - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - // chase! - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - } - else - { - // we can see the enemy - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); - } - if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) - { - // if we can see enemy but can't use either attack type, we must need to get closer to enemy - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - else if ( !FacingIdeal() ) - { - //turn - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); - } - } - break; - } - case MONSTERSTATE_DEAD: - { - return GetScheduleOfType( SCHED_DIE ); - break; - } - case MONSTERSTATE_SCRIPT: - { - ASSERT( m_pCine != NULL ); - if ( !m_pCine ) - { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - - return GetScheduleOfType( SCHED_AISCRIPT ); - } - default: - { - ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); - break; - } - } - - return &slError[ 0 ]; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// schedule.cpp - functions and data pertaining to the +// monsters' AI scheduling system. +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "animation.h" +#include "scripted.h" +#include "nodes.h" +#include "defaultai.h" +#include "soundent.h" + +extern CGraph WorldGraph; + +//========================================================= +// FHaveSchedule - Returns TRUE if monster's m_pSchedule +// is anything other than NULL. +//========================================================= +BOOL CBaseMonster :: FHaveSchedule( void ) +{ + if ( m_pSchedule == NULL ) + { + return FALSE; + } + + return TRUE; +} + +//========================================================= +// ClearSchedule - blanks out the caller's schedule pointer +// and index. +//========================================================= +void CBaseMonster :: ClearSchedule( void ) +{ + m_iTaskStatus = TASKSTATUS_NEW; + m_pSchedule = NULL; + m_iScheduleIndex = 0; +} + +//========================================================= +// FScheduleDone - Returns TRUE if the caller is on the +// last task in the schedule +//========================================================= +BOOL CBaseMonster :: FScheduleDone ( void ) +{ + ASSERT( m_pSchedule != NULL ); + + if ( m_iScheduleIndex == m_pSchedule->cTasks ) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// ChangeSchedule - replaces the monster's schedule pointer +// with the passed pointer, and sets the ScheduleIndex back +// to 0 +//========================================================= +void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) +{ + ASSERT( pNewSchedule != NULL ); + + m_pSchedule = pNewSchedule; + m_iScheduleIndex = 0; + m_iTaskStatus = TASKSTATUS_NEW; + m_afConditions = 0;// clear all of the conditions + m_failSchedule = SCHED_NONE; + + if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) + { + ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); + } + else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) + { + ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); + } + +#if _DEBUG + if ( !ScheduleFromName( pNewSchedule->pName ) ) + { + ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); + } +#endif + +// this is very useful code if you can isolate a test case in a level with a single monster. It will notify +// you of every schedule selection the monster makes. +#if 0 + if ( FClassnameIs( pev, "monster_human_grunt" ) ) + { + Task_t *pTask = GetTask(); + + if ( pTask ) + { + const char *pName = NULL; + + if ( m_pSchedule ) + { + pName = m_pSchedule->pName; + } + else + { + pName = "No Schedule"; + } + + if ( !pName ) + { + pName = "Unknown"; + } + + ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); + } + } +#endif// 0 + +} + +//========================================================= +// NextScheduledTask - increments the ScheduleIndex +//========================================================= +void CBaseMonster :: NextScheduledTask ( void ) +{ + ASSERT( m_pSchedule != NULL ); + + m_iTaskStatus = TASKSTATUS_NEW; + m_iScheduleIndex++; + + if ( FScheduleDone() ) + { + // just completed last task in schedule, so make it invalid by clearing it. + SetConditions( bits_COND_SCHEDULE_DONE ); + //ClearSchedule(); + } +} + +//========================================================= +// IScheduleFlags - returns an integer with all Conditions +// bits that are currently set and also set in the current +// schedule's Interrupt mask. +//========================================================= +int CBaseMonster :: IScheduleFlags ( void ) +{ + if( !m_pSchedule ) + { + return 0; + } + + // strip off all bits excepts the ones capable of breaking this schedule. + return m_afConditions & m_pSchedule->iInterruptMask; +} + +//========================================================= +// FScheduleValid - returns TRUE as long as the current +// schedule is still the proper schedule to be executing, +// taking into account all conditions +//========================================================= +BOOL CBaseMonster :: FScheduleValid ( void ) +{ + if ( m_pSchedule == NULL ) + { + // schedule is empty, and therefore not valid. + return FALSE; + } + + if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) + { +#ifdef DEBUG + if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) + { + // fail! Send a visual indicator. + ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); + + Vector tmp = pev->origin; + tmp.z = pev->absmax.z + 16; + UTIL_Sparks( tmp ); + } +#endif // DEBUG + + // some condition has interrupted the schedule, or the schedule is done + return FALSE; + } + + return TRUE; +} + +//========================================================= +// MaintainSchedule - does all the per-think schedule maintenance. +// ensures that the monster leaves this function with a valid +// schedule! +//========================================================= +void CBaseMonster :: MaintainSchedule ( void ) +{ + Schedule_t *pNewSchedule; + int i; + + // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible + for ( i = 0; i < 10; i++ ) + { + if ( m_pSchedule != NULL && TaskIsComplete() ) + { + NextScheduledTask(); + } + + // validate existing schedule + if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) + { + // if we come into this block of code, the schedule is going to have to be changed. + // if the previous schedule was interrupted by a condition, GetIdealState will be + // called. Else, a schedule finished normally. + + // Notify the monster that his schedule is changing + ScheduleChange(); + + // Call GetIdealState if we're not dead and one or more of the following... + // - in COMBAT state with no enemy (it died?) + // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, + // - schedule is done but schedule indicates it wants GetIdealState called + // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) + // DEAD & SCRIPT are not suggestions, they are commands! + if ( m_IdealMonsterState != MONSTERSTATE_DEAD && + (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) + { + if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || + (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || + ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == NULL)) ) + { + GetIdealState(); + } + } + if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) + { + if ( m_failSchedule != SCHED_NONE ) + pNewSchedule = GetScheduleOfType( m_failSchedule ); + else + pNewSchedule = GetScheduleOfType( SCHED_FAIL ); + // schedule was invalid because the current task failed to start or complete + ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); + ChangeSchedule( pNewSchedule ); + } + else + { + SetState( m_IdealMonsterState ); + if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) + pNewSchedule = CBaseMonster::GetSchedule(); + else + pNewSchedule = GetSchedule(); + ChangeSchedule( pNewSchedule ); + } + } + + if ( m_iTaskStatus == TASKSTATUS_NEW ) + { + Task_t *pTask = GetTask(); + ASSERT( pTask != NULL ); + TaskBegin(); + StartTask( pTask ); + } + + // UNDONE: Twice?!!! + if ( m_Activity != m_IdealActivity ) + { + SetActivity ( m_IdealActivity ); + } + + if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) + break; + } + + if ( TaskIsRunning() ) + { + Task_t *pTask = GetTask(); + ASSERT( pTask != NULL ); + RunTask( pTask ); + } + + // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation + // RunTask() will always change animations at the end of a script! + // Don't do this twice + if ( m_Activity != m_IdealActivity ) + { + SetActivity ( m_IdealActivity ); + } +} + +//========================================================= +// RunTask +//========================================================= +void CBaseMonster :: RunTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_TURN_RIGHT: + case TASK_TURN_LEFT: + { + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + TaskComplete(); + } + break; + } + + case TASK_PLAY_SEQUENCE_FACE_ENEMY: + case TASK_PLAY_SEQUENCE_FACE_TARGET: + { + CBaseEntity *pTarget; + + if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) + pTarget = m_hTargetEnt; + else + pTarget = m_hEnemy; + if ( pTarget ) + { + pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); + ChangeYaw( pev->yaw_speed ); + } + if ( m_fSequenceFinished ) + TaskComplete(); + } + break; + + case TASK_PLAY_SEQUENCE: + case TASK_PLAY_ACTIVE_IDLE: + { + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + break; + } + + + case TASK_FACE_ENEMY: + { + MakeIdealYaw( m_vecEnemyLKP ); + + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + TaskComplete(); + } + break; + } + case TASK_FACE_HINTNODE: + case TASK_FACE_LASTPOSITION: + case TASK_FACE_TARGET: + case TASK_FACE_IDEAL: + case TASK_FACE_ROUTE: + { + ChangeYaw( pev->yaw_speed ); + + if ( FacingIdeal() ) + { + TaskComplete(); + } + break; + } + case TASK_WAIT_PVS: + { + if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) + { + TaskComplete(); + } + break; + } + case TASK_WAIT_INDEFINITE: + { + // don't do anything. + break; + } + case TASK_WAIT: + case TASK_WAIT_RANDOM: + { + if ( gpGlobals->time >= m_flWaitFinished ) + { + TaskComplete(); + } + break; + } + case TASK_WAIT_FACE_ENEMY: + { + MakeIdealYaw ( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); + + if ( gpGlobals->time >= m_flWaitFinished ) + { + TaskComplete(); + } + break; + } + case TASK_MOVE_TO_TARGET_RANGE: + { + float distance; + + if ( m_hTargetEnt == NULL ) + TaskFail(); + else + { + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + // Re-evaluate when you think your finished, or the target has moved too far + if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) + { + m_vecMoveGoal = m_hTargetEnt->pev->origin; + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + FRefreshRoute(); + } + + // Set the appropriate activity based on an overlapping range + // overlap the range to prevent oscillation + if ( distance < pTask->flData ) + { + TaskComplete(); + RouteClear(); // Stop moving + } + else if ( distance < 190 && m_movementActivity != ACT_WALK ) + m_movementActivity = ACT_WALK; + else if ( distance >= 270 && m_movementActivity != ACT_RUN ) + m_movementActivity = ACT_RUN; + } + + break; + } + case TASK_WAIT_FOR_MOVEMENT: + { + if (MovementIsComplete()) + { + TaskComplete(); + RouteClear(); // Stop moving + } + break; + } + case TASK_DIE: + { + if ( m_fSequenceFinished && pev->frame >= 255 ) + { + pev->deadflag = DEAD_DEAD; + + SetThink ( NULL ); + StopAnimation(); + + if ( !BBoxFlat() ) + { + // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will + // block the player on a slope or stairs, the corpse is made nonsolid. +// pev->solid = SOLID_NOT; + UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); + } + else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem + UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); + + if ( ShouldFadeOnDeath() ) + { + // this monster was created by a monstermaker... fade the corpse out. + SUB_StartFadeOut(); + } + else + { + // body is gonna be around for a while, so have it stink for a bit. + CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); + } + } + break; + } + case TASK_RANGE_ATTACK1_NOTURN: + case TASK_MELEE_ATTACK1_NOTURN: + case TASK_MELEE_ATTACK2_NOTURN: + case TASK_RANGE_ATTACK2_NOTURN: + case TASK_RELOAD_NOTURN: + { + if ( m_fSequenceFinished ) + { + m_Activity = ACT_RESET; + TaskComplete(); + } + break; + } + case TASK_RANGE_ATTACK1: + case TASK_MELEE_ATTACK1: + case TASK_MELEE_ATTACK2: + case TASK_RANGE_ATTACK2: + case TASK_SPECIAL_ATTACK1: + case TASK_SPECIAL_ATTACK2: + case TASK_RELOAD: + { + MakeIdealYaw ( m_vecEnemyLKP ); + ChangeYaw ( pev->yaw_speed ); + + if ( m_fSequenceFinished ) + { + m_Activity = ACT_RESET; + TaskComplete(); + } + break; + } + case TASK_SMALL_FLINCH: + { + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + } + break; + case TASK_WAIT_FOR_SCRIPT: + { + if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) + { + TaskComplete(); + m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); + if ( m_fSequenceFinished ) + ClearSchedule(); + pev->framerate = 1.0; + //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); + } + break; + } + case TASK_PLAY_SCRIPT: + { + if (m_fSequenceFinished) + { + m_pCine->SequenceDone( this ); + } + break; + } + } +} + +//========================================================= +// SetTurnActivity - measures the difference between the way +// the monster is facing and determines whether or not to +// select one of the 180 turn animations. +//========================================================= +void CBaseMonster :: SetTurnActivity ( void ) +{ + float flYD; + flYD = FlYawDiff(); + + if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) + {// big right turn + m_IdealActivity = ACT_TURN_RIGHT; + } + else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) + {// big left turn + m_IdealActivity = ACT_TURN_LEFT; + } +} + +//========================================================= +// Start task - selects the correct activity and performs +// any necessary calculations to start the next task on the +// schedule. +//========================================================= +void CBaseMonster :: StartTask ( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_TURN_RIGHT: + { + float flCurrentYaw; + + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); + pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); + SetTurnActivity(); + break; + } + case TASK_TURN_LEFT: + { + float flCurrentYaw; + + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); + pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); + SetTurnActivity(); + break; + } + case TASK_REMEMBER: + { + Remember ( (int)pTask->flData ); + TaskComplete(); + break; + } + case TASK_FORGET: + { + Forget ( (int)pTask->flData ); + TaskComplete(); + break; + } + case TASK_FIND_HINTNODE: + { + m_iHintNode = FindHintNode(); + + if ( m_iHintNode != NO_NODE ) + { + TaskComplete(); + } + else + { + TaskFail(); + } + break; + } + case TASK_STORE_LASTPOSITION: + { + m_vecLastPosition = pev->origin; + TaskComplete(); + break; + } + case TASK_CLEAR_LASTPOSITION: + { + m_vecLastPosition = g_vecZero; + TaskComplete(); + break; + } + case TASK_CLEAR_HINTNODE: + { + m_iHintNode = NO_NODE; + TaskComplete(); + break; + } + case TASK_STOP_MOVING: + { + if ( m_IdealActivity == m_movementActivity ) + { + m_IdealActivity = GetStoppedActivity(); + } + + RouteClear(); + TaskComplete(); + break; + } + case TASK_PLAY_SEQUENCE_FACE_ENEMY: + case TASK_PLAY_SEQUENCE_FACE_TARGET: + case TASK_PLAY_SEQUENCE: + { + m_IdealActivity = ( Activity )( int )pTask->flData; + break; + } + case TASK_PLAY_ACTIVE_IDLE: + { + // monsters verify that they have a sequence for the node's activity BEFORE + // moving towards the node, so it's ok to just set the activity without checking here. + m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; + break; + } + case TASK_SET_SCHEDULE: + { + Schedule_t *pNewSchedule; + + pNewSchedule = GetScheduleOfType( (int)pTask->flData ); + + if ( pNewSchedule ) + { + ChangeSchedule( pNewSchedule ); + } + else + { + TaskFail(); + } + + break; + } + case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: + { + if ( m_hEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) + { + // try for cover farther than the FLData from the schedule. + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: + { + if ( m_hEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) + { + // try for cover farther than the FLData from the schedule. + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_NODE_COVER_FROM_ENEMY: + { + if ( m_hEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) + { + // try for cover farther than the FLData from the schedule. + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_COVER_FROM_ENEMY: + { + entvars_t *pevCover; + + if ( m_hEnemy == NULL ) + { + // Find cover from self if no enemy available + pevCover = pev; +// TaskFail(); +// return; + } + else + pevCover = m_hEnemy->pev; + + if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) + { + // try lateral first + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else + { + // no coverwhatsoever. + TaskFail(); + } + break; + } + case TASK_FIND_COVER_FROM_ORIGIN: + { + if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else + { + // no cover! + TaskFail(); + } + } + break; + case TASK_FIND_COVER_FROM_BEST_SOUND: + { + CSound *pBestSound; + + pBestSound = PBestSound(); + + ASSERT( pBestSound != NULL ); + /* + if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) + { + // try lateral first + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + */ + + if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else + { + // no coverwhatsoever. or no sound in list + TaskFail(); + } + break; + } + case TASK_FACE_HINTNODE: + { + pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; + SetTurnActivity(); + break; + } + + case TASK_FACE_LASTPOSITION: + MakeIdealYaw ( m_vecLastPosition ); + SetTurnActivity(); + break; + + case TASK_FACE_TARGET: + if ( m_hTargetEnt != NULL ) + { + MakeIdealYaw ( m_hTargetEnt->pev->origin ); + SetTurnActivity(); + } + else + TaskFail(); + break; + case TASK_FACE_ENEMY: + { + MakeIdealYaw ( m_vecEnemyLKP ); + SetTurnActivity(); + break; + } + case TASK_FACE_IDEAL: + { + SetTurnActivity(); + break; + } + case TASK_FACE_ROUTE: + { + if (FRouteClear()) + { + ALERT(at_aiconsole, "No route to face!\n"); + TaskFail(); + } + else + { + MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); + SetTurnActivity(); + } + break; + } + case TASK_WAIT_PVS: + case TASK_WAIT_INDEFINITE: + { + // don't do anything. + break; + } + case TASK_WAIT: + case TASK_WAIT_FACE_ENEMY: + {// set a future time that tells us when the wait is over. + m_flWaitFinished = gpGlobals->time + pTask->flData; + break; + } + case TASK_WAIT_RANDOM: + {// set a future time that tells us when the wait is over. + m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); + break; + } + case TASK_MOVE_TO_TARGET_RANGE: + { + if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + TaskComplete(); + else + { + m_vecMoveGoal = m_hTargetEnt->pev->origin; + if ( !MoveToTarget( ACT_WALK, 2 ) ) + TaskFail(); + } + break; + } + case TASK_RUN_TO_TARGET: + case TASK_WALK_TO_TARGET: + { + Activity newActivity; + + if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + TaskComplete(); + else + { + if ( pTask->iTask == TASK_WALK_TO_TARGET ) + newActivity = ACT_WALK; + else + newActivity = ACT_RUN; + // This monster can't do this! + if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) + TaskComplete(); + else + { + if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) + { + TaskFail(); + ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); + RouteClear(); + } + } + } + TaskComplete(); + break; + } + case TASK_CLEAR_MOVE_WAIT: + { + m_flMoveWaitFinished = gpGlobals->time; + TaskComplete(); + break; + } + case TASK_MELEE_ATTACK1_NOTURN: + case TASK_MELEE_ATTACK1: + { + m_IdealActivity = ACT_MELEE_ATTACK1; + break; + } + case TASK_MELEE_ATTACK2_NOTURN: + case TASK_MELEE_ATTACK2: + { + m_IdealActivity = ACT_MELEE_ATTACK2; + break; + } + case TASK_RANGE_ATTACK1_NOTURN: + case TASK_RANGE_ATTACK1: + { + m_IdealActivity = ACT_RANGE_ATTACK1; + break; + } + case TASK_RANGE_ATTACK2_NOTURN: + case TASK_RANGE_ATTACK2: + { + m_IdealActivity = ACT_RANGE_ATTACK2; + break; + } + case TASK_RELOAD_NOTURN: + case TASK_RELOAD: + { + m_IdealActivity = ACT_RELOAD; + break; + } + case TASK_SPECIAL_ATTACK1: + { + m_IdealActivity = ACT_SPECIAL_ATTACK1; + break; + } + case TASK_SPECIAL_ATTACK2: + { + m_IdealActivity = ACT_SPECIAL_ATTACK2; + break; + } + case TASK_SET_ACTIVITY: + { + m_IdealActivity = (Activity)(int)pTask->flData; + TaskComplete(); + break; + } + case TASK_GET_PATH_TO_ENEMY_LKP: + { + if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) + { + TaskComplete(); + } + else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_ENEMY: + { + CBaseEntity *pEnemy = m_hEnemy; + + if ( pEnemy == NULL ) + { + TaskFail(); + return; + } + + if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) + { + TaskComplete(); + } + else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_ENEMY_CORPSE: + { + UTIL_MakeVectors( pev->angles ); + if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) + { + TaskComplete(); + } + else + { + ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); + TaskFail(); + } + } + break; + case TASK_GET_PATH_TO_SPOT: + { + CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); + if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); + TaskFail(); + } + break; + } + + case TASK_GET_PATH_TO_TARGET: + { + RouteClear(); + if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_HINTNODE:// for active idles! + { + if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_LASTPOSITION: + { + m_vecMoveGoal = m_vecLastPosition; + + if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); + TaskFail(); + } + break; + } + case TASK_GET_PATH_TO_BESTSOUND: + { + CSound *pSound; + + pSound = PBestSound(); + + if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); + TaskFail(); + } + break; + } +case TASK_GET_PATH_TO_BESTSCENT: + { + CSound *pScent; + + pScent = PBestScent(); + + if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) + { + TaskComplete(); + } + else + { + // no way to get there =( + ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); + + TaskFail(); + } + break; + } + case TASK_RUN_PATH: + { + // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? + if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) + { + m_movementActivity = ACT_RUN; + } + else + { + m_movementActivity = ACT_WALK; + } + TaskComplete(); + break; + } + case TASK_WALK_PATH: + { + if ( pev->movetype == MOVETYPE_FLY ) + { + m_movementActivity = ACT_FLY; + } + if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) + { + m_movementActivity = ACT_WALK; + } + else + { + m_movementActivity = ACT_RUN; + } + TaskComplete(); + break; + } + case TASK_STRAFE_PATH: + { + Vector2D vec2DirToPoint; + Vector2D vec2RightSide; + + // to start strafing, we have to first figure out if the target is on the left side or right side + UTIL_MakeVectors ( pev->angles ); + + vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); + vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); + + if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) + { + // strafe right + m_movementActivity = ACT_STRAFE_RIGHT; + } + else + { + // strafe left + m_movementActivity = ACT_STRAFE_LEFT; + } + TaskComplete(); + break; + } + + + case TASK_WAIT_FOR_MOVEMENT: + { + if (FRouteClear()) + { + TaskComplete(); + } + break; + } + + case TASK_EAT: + { + Eat( pTask->flData ); + TaskComplete(); + break; + } + case TASK_SMALL_FLINCH: + { + m_IdealActivity = GetSmallFlinchActivity(); + break; + } + case TASK_DIE: + { + RouteClear(); + + m_IdealActivity = GetDeathActivity(); + + pev->deadflag = DEAD_DYING; + break; + } + case TASK_SOUND_WAKE: + { + AlertSound(); + TaskComplete(); + break; + } + case TASK_SOUND_DIE: + { + DeathSound(); + TaskComplete(); + break; + } + case TASK_SOUND_IDLE: + { + IdleSound(); + TaskComplete(); + break; + } + case TASK_SOUND_PAIN: + { + PainSound(); + TaskComplete(); + break; + } + case TASK_SOUND_DEATH: + { + DeathSound(); + TaskComplete(); + break; + } + case TASK_SOUND_ANGRY: + { + // sounds are complete as soon as we get here, cause we've already played them. + ALERT ( at_aiconsole, "SOUND\n" ); + TaskComplete(); + break; + } + case TASK_WAIT_FOR_SCRIPT: + { + if (m_pCine->m_iszIdle) + { + m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); + if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) + { + pev->framerate = 0; + } + } + else + m_IdealActivity = ACT_IDLE; + + break; + } + case TASK_PLAY_SCRIPT: + { + pev->movetype = MOVETYPE_FLY; + ClearBits(pev->flags, FL_ONGROUND); + m_scriptState = SCRIPT_PLAYING; + break; + } + case TASK_ENABLE_SCRIPT: + { + m_pCine->DelayStart( 0 ); + TaskComplete(); + break; + } + case TASK_PLANT_ON_SCRIPT: + { + if ( m_hTargetEnt != NULL ) + { + pev->origin = m_hTargetEnt->pev->origin; // Plant on target + } + + TaskComplete(); + break; + } + case TASK_FACE_SCRIPT: + { + if ( m_hTargetEnt != NULL ) + { + pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); + } + + TaskComplete(); + m_IdealActivity = ACT_IDLE; + RouteClear(); + break; + } + + case TASK_SUGGEST_STATE: + { + m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; + TaskComplete(); + break; + } + + case TASK_SET_FAIL_SCHEDULE: + m_failSchedule = (int)pTask->flData; + TaskComplete(); + break; + + case TASK_CLEAR_FAIL_SCHEDULE: + m_failSchedule = SCHED_NONE; + TaskComplete(); + break; + + default: + { + ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); + break; + } + } +} + +//========================================================= +// GetTask - returns a pointer to the current +// scheduled task. NULL if there's a problem. +//========================================================= +Task_t *CBaseMonster :: GetTask ( void ) +{ + if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) + { + // m_iScheduleIndex is not within valid range for the monster's current schedule. + return NULL; + } + else + { + return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; + } +} + +//========================================================= +// GetSchedule - Decides which type of schedule best suits +// the monster's current state and conditions. Then calls +// monster's member function to get a pointer to a schedule +// of the proper type. +//========================================================= +Schedule_t *CBaseMonster :: GetSchedule ( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_PRONE: + { + return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); + break; + } + case MONSTERSTATE_NONE: + { + ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); + break; + } + case MONSTERSTATE_IDLE: + { + if ( HasConditions ( bits_COND_HEAR_SOUND ) ) + { + return GetScheduleOfType( SCHED_ALERT_FACE ); + } + else if ( FRouteClear() ) + { + // no valid route! + return GetScheduleOfType( SCHED_IDLE_STAND ); + } + else + { + // valid route. Get moving + return GetScheduleOfType( SCHED_IDLE_WALK ); + } + break; + } + case MONSTERSTATE_ALERT: + { + if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) + { + return GetScheduleOfType ( SCHED_VICTORY_DANCE ); + } + + if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) + { + if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction + { + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); + } + else + { + return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); + } + } + + else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) + { + return GetScheduleOfType( SCHED_ALERT_FACE ); + } + else + { + return GetScheduleOfType( SCHED_ALERT_STAND ); + } + break; + } + case MONSTERSTATE_COMBAT: + { + if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + { + // clear the current (dead) enemy and try to find another. + m_hEnemy = NULL; + + if ( GetEnemy() ) + { + ClearConditions( bits_COND_ENEMY_DEAD ); + return GetSchedule(); + } + else + { + SetState( MONSTERSTATE_ALERT ); + return GetSchedule(); + } + } + + if ( HasConditions(bits_COND_NEW_ENEMY) ) + { + return GetScheduleOfType ( SCHED_WAKE_ANGRY ); + } + else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) + { + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + else if ( !HasConditions(bits_COND_SEE_ENEMY) ) + { + // we can't see the enemy + if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) + { + // enemy is unseen, but not occluded! + // turn to face enemy + return GetScheduleOfType( SCHED_COMBAT_FACE ); + } + else + { + // chase! + return GetScheduleOfType( SCHED_CHASE_ENEMY ); + } + } + else + { + // we can see the enemy + if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) + { + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); + } + if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) + { + return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); + } + if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) + { + return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); + } + if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) + { + return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); + } + if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) + { + // if we can see enemy but can't use either attack type, we must need to get closer to enemy + return GetScheduleOfType( SCHED_CHASE_ENEMY ); + } + else if ( !FacingIdeal() ) + { + //turn + return GetScheduleOfType( SCHED_COMBAT_FACE ); + } + else + { + ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); + } + } + break; + } + case MONSTERSTATE_DEAD: + { + return GetScheduleOfType( SCHED_DIE ); + break; + } + case MONSTERSTATE_SCRIPT: + { + ASSERT( m_pCine != NULL ); + if ( !m_pCine ) + { + ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); + CineCleanup(); + return GetScheduleOfType( SCHED_IDLE_STAND ); + } + + return GetScheduleOfType( SCHED_AISCRIPT ); + } + default: + { + ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); + break; + } + } + + return &slError[ 0 ]; +} diff --git a/main/source/dlls/schedule.h b/main/source/dlls/schedule.h index 7d341588..52ea0442 100644 --- a/main/source/dlls/schedule.h +++ b/main/source/dlls/schedule.h @@ -1,31 +1,31 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Scheduling -//========================================================= -#ifndef SCHEDULE_H -#define SCHEDULE_H - -#define bits_COND_SEE_HATE ( 1 << 1 ) // see something that you hate -#define bits_COND_SEE_FEAR ( 1 << 2 ) // see something that you are afraid of -#define bits_COND_SEE_DISLIKE ( 1 << 3 ) // see something that you dislike -#define bits_COND_SEE_ENEMY ( 1 << 4 ) // target entity is in full view. -#define bits_COND_LIGHT_DAMAGE ( 1 << 8 ) // hurt a little -#define bits_COND_HEAVY_DAMAGE ( 1 << 9 ) // hurt a lot -#define bits_COND_SEE_CLIENT ( 1 << 21) // see a client -#define bits_COND_SEE_NEMESIS ( 1 << 22) // see my nemesis - - -#endif // SCHEDULE_H +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Scheduling +//========================================================= +#ifndef SCHEDULE_H +#define SCHEDULE_H + +#define bits_COND_SEE_HATE ( 1 << 1 ) // see something that you hate +#define bits_COND_SEE_FEAR ( 1 << 2 ) // see something that you are afraid of +#define bits_COND_SEE_DISLIKE ( 1 << 3 ) // see something that you dislike +#define bits_COND_SEE_ENEMY ( 1 << 4 ) // target entity is in full view. +#define bits_COND_LIGHT_DAMAGE ( 1 << 8 ) // hurt a little +#define bits_COND_HEAVY_DAMAGE ( 1 << 9 ) // hurt a lot +#define bits_COND_SEE_CLIENT ( 1 << 21) // see a client +#define bits_COND_SEE_NEMESIS ( 1 << 22) // see my nemesis + + +#endif // SCHEDULE_H diff --git a/main/source/dlls/scientist.cpp b/main/source/dlls/scientist.cpp index 98050950..3ab8f7c2 100644 --- a/main/source/dlls/scientist.cpp +++ b/main/source/dlls/scientist.cpp @@ -1,1428 +1,1428 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// human scientist (passive lab worker) -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "animation.h" -#include "soundent.h" - - -#define NUM_SCIENTIST_HEADS 4 // four heads available for scientist model -enum { HEAD_GLASSES = 0, HEAD_EINSTEIN = 1, HEAD_LUTHER = 2, HEAD_SLICK = 3 }; - -enum -{ - SCHED_HIDE = LAST_TALKMONSTER_SCHEDULE + 1, - SCHED_FEAR, - SCHED_PANIC, - SCHED_STARTLE, - SCHED_TARGET_CHASE_SCARED, - SCHED_TARGET_FACE_SCARED, -}; - -enum -{ - TASK_SAY_HEAL = LAST_TALKMONSTER_TASK + 1, - TASK_HEAL, - TASK_SAY_FEAR, - TASK_RUN_PATH_SCARED, - TASK_SCREAM, - TASK_RANDOM_SCREAM, - TASK_MOVE_TO_TARGET_RANGE_SCARED, -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define SCIENTIST_AE_HEAL ( 1 ) -#define SCIENTIST_AE_NEEDLEON ( 2 ) -#define SCIENTIST_AE_NEEDLEOFF ( 3 ) - -//======================================================= -// Scientist -//======================================================= - -class CScientist : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual int FriendNumber( int arrayNumber ); - void SetActivity ( Activity newActivity ); - Activity GetStoppedActivity( void ); - int ISoundMask( void ); - void DeclineFollowing( void ); - - float CoverRadius( void ) { return 1200; } // Need more room for cover because scientists want to get far away! - BOOL DisregardEnemy( CBaseEntity *pEnemy ) { return !pEnemy->IsAlive() || (gpGlobals->time - m_fearTime) > 15; } - - BOOL CanHeal( void ); - void Heal( void ); - void Scream( void ); - - // Override these to set behavior - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule ( void ); - MONSTERSTATE GetIdealState ( void ); - - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CUSTOM_SCHEDULES; - -private: - float m_painTime; - float m_healTime; - float m_fearTime; -}; - -LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ); - -TYPEDESCRIPTION CScientist::m_SaveData[] = -{ - DEFINE_FIELD( CScientist, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CScientist, m_healTime, FIELD_TIME ), - DEFINE_FIELD( CScientist, m_fearTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CScientist, CTalkMonster ); - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlFollow[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CANT_FOLLOW }, // If you fail, bail out of follow - { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) -// { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slFollow[] = -{ - { - tlFollow, - ARRAYSIZE ( tlFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_COMBAT | - bits_SOUND_DANGER, - "Follow" - }, -}; - -Task_t tlFollowScared[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE },// If you fail, follow normally - { TASK_MOVE_TO_TARGET_RANGE_SCARED,(float)128 }, // Move within 128 of target ent (client) -// { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE_SCARED }, -}; - -Schedule_t slFollowScared[] = -{ - { - tlFollowScared, - ARRAYSIZE ( tlFollowScared ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - bits_SOUND_DANGER, - "FollowScared" - }, -}; - -Task_t tlFaceTargetScared[] = -{ - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE_SCARED }, -}; - -Schedule_t slFaceTargetScared[] = -{ - { - tlFaceTargetScared, - ARRAYSIZE ( tlFaceTargetScared ), - bits_COND_HEAR_SOUND | - bits_COND_NEW_ENEMY, - bits_SOUND_DANGER, - "FaceTargetScared" - }, -}; - -Task_t tlStopFollowing[] = -{ - { TASK_CANT_FOLLOW, (float)0 }, -}; - -Schedule_t slStopFollowing[] = -{ - { - tlStopFollowing, - ARRAYSIZE ( tlStopFollowing ), - 0, - 0, - "StopFollowing" - }, -}; - - -Task_t tlHeal[] = -{ - { TASK_MOVE_TO_TARGET_RANGE,(float)50 }, // Move within 60 of target ent (client) - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE }, // If you fail, catch up with that guy! (change this to put syringe away and then chase) - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SAY_HEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_ARM }, // Whip out the needle - { TASK_HEAL, (float)0 }, // Put it in the player - { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_DISARM }, // Put away the needle -}; - -Schedule_t slHeal[] = -{ - { - tlHeal, - ARRAYSIZE ( tlHeal ), - 0, // Don't interrupt or he'll end up running around with a needle all the time - 0, - "Heal" - }, -}; - - -Task_t tlFaceTarget[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, -}; - -Schedule_t slFaceTarget[] = -{ - { - tlFaceTarget, - ARRAYSIZE ( tlFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_COMBAT | - bits_SOUND_DANGER, - "FaceTarget" - }, -}; - - -Task_t tlSciPanic[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SCREAM, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_EXCITED }, // This is really fear-stricken excitement - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slSciPanic[] = -{ - { - tlSciPanic, - ARRAYSIZE ( tlSciPanic ), - 0, - 0, - "SciPanic" - }, -}; - - -Task_t tlIdleSciStand[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. - { TASK_TLK_HEADRESET, (float)0 }, // reset head position -}; - -Schedule_t slIdleSciStand[] = -{ - { - tlIdleSciStand, - ARRAYSIZE ( tlIdleSciStand ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleSciStand" - - }, -}; - - -Task_t tlScientistCover[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH_SCARED, (float)0 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_SET_SCHEDULE, (float)SCHED_HIDE }, -}; - -Schedule_t slScientistCover[] = -{ - { - tlScientistCover, - ARRAYSIZE ( tlScientistCover ), - bits_COND_NEW_ENEMY, - 0, - "ScientistCover" - }, -}; - - - -Task_t tlScientistHide[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, // FIXME: This looks lame - { TASK_WAIT_RANDOM, (float)10.0 }, -}; - -Schedule_t slScientistHide[] = -{ - { - tlScientistHide, - ARRAYSIZE ( tlScientistHide ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_SEE_ENEMY | - bits_COND_SEE_HATE | - bits_COND_SEE_FEAR | - bits_COND_SEE_DISLIKE, - bits_SOUND_DANGER, - "ScientistHide" - }, -}; - - -Task_t tlScientistStartle[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_RANDOM_SCREAM, (float)0.3 }, // Scream 30% of the time - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_RANDOM_SCREAM, (float)0.1 }, // Scream again 10% of the time - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCHIDLE }, - { TASK_WAIT_RANDOM, (float)1.0 }, -}; - -Schedule_t slScientistStartle[] = -{ - { - tlScientistStartle, - ARRAYSIZE ( tlScientistStartle ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_HATE | - bits_COND_SEE_FEAR | - bits_COND_SEE_DISLIKE, - 0, - "ScientistStartle" - }, -}; - - - -Task_t tlFear[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SAY_FEAR, (float)0 }, -// { TASK_PLAY_SEQUENCE, (float)ACT_FEAR_DISPLAY }, -}; - -Schedule_t slFear[] = -{ - { - tlFear, - ARRAYSIZE ( tlFear ), - bits_COND_NEW_ENEMY, - 0, - "Fear" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CScientist ) -{ - slFollow, - slFaceTarget, - slIdleSciStand, - slFear, - slScientistCover, - slScientistHide, - slScientistStartle, - slHeal, - slStopFollowing, - slSciPanic, - slFollowScared, - slFaceTargetScared, -}; - - -IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster ); - - -void CScientist::DeclineFollowing( void ) -{ - Talk( 10 ); - m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); -} - - -void CScientist :: Scream( void ) -{ - if ( FOkToSpeak() ) - { - Talk( 10 ); - m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); - } -} - - -Activity CScientist::GetStoppedActivity( void ) -{ - if ( m_hEnemy != NULL ) - return ACT_EXCITED; - return CTalkMonster::GetStoppedActivity(); -} - - -void CScientist :: StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_SAY_HEAL: -// if ( FOkToSpeak() ) - Talk( 2 ); - m_hTalkTarget = m_hTargetEnt; - PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); - - TaskComplete(); - break; - - case TASK_SCREAM: - Scream(); - TaskComplete(); - break; - - case TASK_RANDOM_SCREAM: - if ( RANDOM_FLOAT( 0, 1 ) < pTask->flData ) - Scream(); - TaskComplete(); - break; - - case TASK_SAY_FEAR: - if ( FOkToSpeak() ) - { - Talk( 2 ); - m_hTalkTarget = m_hEnemy; - if ( m_hEnemy->IsPlayer() ) - PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); - else - PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); - } - TaskComplete(); - break; - - case TASK_HEAL: - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - - case TASK_RUN_PATH_SCARED: - m_movementActivity = ACT_RUN_SCARED; - break; - - case TASK_MOVE_TO_TARGET_RANGE_SCARED: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) ) - TaskFail(); - } - } - break; - - default: - CTalkMonster::StartTask( pTask ); - break; - } -} - -void CScientist :: RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RUN_PATH_SCARED: - if ( MovementIsComplete() ) - TaskComplete(); - if ( RANDOM_LONG(0,31) < 8 ) - Scream(); - break; - - case TASK_MOVE_TO_TARGET_RANGE_SCARED: - { - if ( RANDOM_LONG(0,63)< 8 ) - Scream(); - - if ( m_hEnemy == NULL ) - { - TaskFail(); - } - else - { - float distance; - - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK_SCARED ) - m_movementActivity = ACT_WALK_SCARED; - else if ( distance >= 270 && m_movementActivity != ACT_RUN_SCARED ) - m_movementActivity = ACT_RUN_SCARED; - } - } - break; - - case TASK_HEAL: - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - else - { - if ( TargetDistance() > 90 ) - TaskComplete(); - pev->ideal_yaw = UTIL_VecToYaw( m_hTargetEnt->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - break; - default: - CTalkMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CScientist :: Classify ( void ) -{ - return CLASS_HUMAN_PASSIVE; -} - - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CScientist :: SetYawSpeed ( void ) -{ - int ys; - - ys = 90; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 120; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 120; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCIENTIST_AE_HEAL: // Heal my target (if within range) - Heal(); - break; - case SCIENTIST_AE_NEEDLEON: - { - int oldBody = pev->body; - pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 1; - } - break; - case SCIENTIST_AE_NEEDLEOFF: - { - int oldBody = pev->body; - pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 0; - } - break; - - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CScientist :: Spawn( void ) -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/scientist.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.scientistHealth; - pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - -// m_flDistTooFar = 256.0; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - - // White hands - pev->skin = 0; - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - MonsterInit(); - SetUse( FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CScientist :: Precache( void ) -{ - PRECACHE_MODEL("models/scientist.mdl"); - PRECACHE_SOUND("scientist/sci_pain1.wav"); - PRECACHE_SOUND("scientist/sci_pain2.wav"); - PRECACHE_SOUND("scientist/sci_pain3.wav"); - PRECACHE_SOUND("scientist/sci_pain4.wav"); - PRECACHE_SOUND("scientist/sci_pain5.wav"); - - // every new scientist must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - - CTalkMonster::Precache(); -} - -// Init talk data -void CScientist :: TalkInit() -{ - - CTalkMonster::TalkInit(); - - // scientist will try to talk to friends in this order: - - m_szFriends[0] = "monster_scientist"; - m_szFriends[1] = "monster_sitting_scientist"; - m_szFriends[2] = "monster_barney"; - - // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "SC_ANSWER"; - m_szGrp[TLK_QUESTION] = "SC_QUESTION"; - m_szGrp[TLK_IDLE] = "SC_IDLE"; - m_szGrp[TLK_STARE] = "SC_STARE"; - m_szGrp[TLK_USE] = "SC_OK"; - m_szGrp[TLK_UNUSE] = "SC_WAIT"; - m_szGrp[TLK_STOP] = "SC_STOP"; - m_szGrp[TLK_NOSHOOT] = "SC_SCARED"; - m_szGrp[TLK_HELLO] = "SC_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!SC_CUREA"; - m_szGrp[TLK_PLHURT2] = "!SC_CUREB"; - m_szGrp[TLK_PLHURT3] = "!SC_CUREC"; - - m_szGrp[TLK_PHELLO] = "SC_PHELLO"; - m_szGrp[TLK_PIDLE] = "SC_PIDLE"; - m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; - m_szGrp[TLK_SMELL] = "SC_SMELL"; - - m_szGrp[TLK_WOUND] = "SC_WOUND"; - m_szGrp[TLK_MORTAL] = "SC_MORTAL"; - - // get voice for head - switch (pev->body % 3) - { - default: - case HEAD_GLASSES: m_voicePitch = 105; break; //glasses - case HEAD_EINSTEIN: m_voicePitch = 100; break; //einstein - case HEAD_LUTHER: m_voicePitch = 95; break; //luther - case HEAD_SLICK: m_voicePitch = 100; break;//slick - } -} - -int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - - if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) - { - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - - // make sure friends talk about it if player hurts scientist... - return CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CScientist :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// PainSound -//========================================================= -void CScientist :: PainSound ( void ) -{ - if (gpGlobals->time < m_painTime ) - return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - - switch (RANDOM_LONG(0,4)) - { - case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 3: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain4.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 4: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain5.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CScientist :: DeathSound ( void ) -{ - PainSound(); -} - - -void CScientist::Killed( entvars_t *pevAttacker, int iGib ) -{ - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); -} - - -void CScientist :: SetActivity ( Activity newActivity ) -{ - int iSequence; - - iSequence = LookupActivity ( newActivity ); - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence == ACTIVITY_NOT_AVAILABLE ) - newActivity = ACT_IDLE; - CTalkMonster::SetActivity( newActivity ); -} - - -Schedule_t* CScientist :: GetScheduleOfType ( int Type ) -{ - Schedule_t *psched; - - switch( Type ) - { - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that scientist will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slFaceTarget; // override this for different target face behavior - else - return psched; - - case SCHED_TARGET_CHASE: - return slFollow; - - case SCHED_CANT_FOLLOW: - return slStopFollowing; - - case SCHED_PANIC: - return slSciPanic; - - case SCHED_TARGET_CHASE_SCARED: - return slFollowScared; - - case SCHED_TARGET_FACE_SCARED: - return slFaceTargetScared; - - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slIdleSciStand; - else - return psched; - - case SCHED_HIDE: - return slScientistHide; - - case SCHED_STARTLE: - return slScientistStartle; - - case SCHED_FEAR: - return slFear; - } - - return CTalkMonster::GetScheduleOfType( Type ); -} - -Schedule_t *CScientist :: GetSchedule ( void ) -{ - // so we don't keep calling through the EHANDLE stuff - CBaseEntity *pEnemy = m_hEnemy; - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if ( pEnemy ) - { - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - m_fearTime = gpGlobals->time; - else if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert - { - m_hEnemy = NULL; - pEnemy = NULL; - } - } - - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) - { - // flinch if hurt - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - // Cower when you hear something scary - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound ) - { - if ( pSound->m_iType & (bits_SOUND_DANGER | bits_SOUND_COMBAT) ) - { - if ( gpGlobals->time - m_fearTime > 3 ) // Only cower every 3 seconds or so - { - m_fearTime = gpGlobals->time; // Update last fear - return GetScheduleOfType( SCHED_STARTLE ); // This will just duck for a second - } - } - } - } - - // Behavior for following the player - if ( IsFollowing() ) - { - if ( !m_hTargetEnt->IsAlive() ) - { - // UNDONE: Comment about the recently dead player here? - StopFollowing( FALSE ); - break; - } - - int relationship = R_NO; - - // Nothing scary, just me and the player - if ( pEnemy != NULL ) - relationship = IRelationship( pEnemy ); - - // UNDONE: Model fear properly, fix R_FR and add multiple levels of fear - if ( relationship != R_DL && relationship != R_HT ) - { - // If I'm already close enough to my target - if ( TargetDistance() <= 128 ) - { - if ( CanHeal() ) // Heal opportunistically - return slHeal; - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move - return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); - } - return GetScheduleOfType( SCHED_TARGET_FACE ); // Just face and follow. - } - else // UNDONE: When afraid, scientist won't move out of your way. Keep This? If not, write move away scared - { - if ( HasConditions( bits_COND_NEW_ENEMY ) ) // I just saw something new and scary, react - return GetScheduleOfType( SCHED_FEAR ); // React to something scary - return GetScheduleOfType( SCHED_TARGET_FACE_SCARED ); // face and follow, but I'm scared! - } - } - - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move - return GetScheduleOfType( SCHED_MOVE_AWAY ); - - // try to say something about smells - TrySmellTalk(); - break; - case MONSTERSTATE_COMBAT: - if ( HasConditions( bits_COND_NEW_ENEMY ) ) - return slFear; // Point and scream! - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - return slScientistCover; // Take Cover - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - return slTakeCoverFromBestSound; // Cower and panic from the scary sound! - - return slScientistCover; // Run & Cower - break; - } - - return CTalkMonster::GetSchedule(); -} - -MONSTERSTATE CScientist :: GetIdealState ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if ( HasConditions( bits_COND_NEW_ENEMY ) ) - { - if ( IsFollowing() ) - { - int relationship = IRelationship( m_hEnemy ); - if ( relationship != R_FR || relationship != R_HT && !HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - // Don't go to combat if you're following the player - m_IdealMonsterState = MONSTERSTATE_ALERT; - return m_IdealMonsterState; - } - StopFollowing( TRUE ); - } - } - else if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - // Stop following if you take damage - if ( IsFollowing() ) - StopFollowing( TRUE ); - } - break; - - case MONSTERSTATE_COMBAT: - { - CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy != NULL ) - { - if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert - { - // Strip enemy when going to alert - m_IdealMonsterState = MONSTERSTATE_ALERT; - m_hEnemy = NULL; - return m_IdealMonsterState; - } - // Follow if only scared a little - if ( m_hTargetEnt != NULL ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - return m_IdealMonsterState; - } - - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - m_fearTime = gpGlobals->time; - m_IdealMonsterState = MONSTERSTATE_COMBAT; - return m_IdealMonsterState; - } - - } - } - break; - } - - return CTalkMonster::GetIdealState(); -} - - -BOOL CScientist::CanHeal( void ) -{ - if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (m_hTargetEnt->pev->health > (m_hTargetEnt->pev->max_health * 0.5)) ) - return FALSE; - - return TRUE; -} - -void CScientist::Heal( void ) -{ - if ( !CanHeal() ) - return; - - Vector target = m_hTargetEnt->pev->origin - pev->origin; - if ( target.Length() > 100 ) - return; - - m_hTargetEnt->TakeHealth( gSkillData.scientistHeal, DMG_GENERIC ); - // Don't heal again for 1 minute - m_healTime = gpGlobals->time + 60; -} - -int CScientist::FriendNumber( int arrayNumber ) -{ - static int array[3] = { 1, 2, 0 }; - if ( arrayNumber < 3 ) - return array[ arrayNumber ]; - return arrayNumber; -} - - -//========================================================= -// Dead Scientist PROP -//========================================================= -class CDeadScientist : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_PASSIVE; } - - void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display - static char *m_szPoses[7]; -}; -char *CDeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", "dead_sitting", "dead_hang", "dead_table1", "dead_table2", "dead_table3" }; - -void CDeadScientist::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} -LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ); - -// -// ********** DeadScientist SPAWN ********** -// -void CDeadScientist :: Spawn( ) -{ - PRECACHE_MODEL("models/scientist.mdl"); - SET_MODEL(ENT(pev), "models/scientist.mdl"); - - pev->effects = 0; - pev->sequence = 0; - // Corpses have less health - pev->health = 8;//gSkillData.scientistHealth; - - m_bloodColor = BLOOD_COLOR_RED; - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - else - pev->skin = 0; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead scientist with bad pose\n" ); - } - - // pev->skin += 2; // use bloody skin -- UNDONE: Turn this back on when we have a bloody skin again! - MonsterInitDead(); -} - - -//========================================================= -// Sitting Scientist PROP -//========================================================= - -class CSittingScientist : public CScientist // kdb: changed from public CBaseMonster so he can speak -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SittingThink( void ); - int Classify ( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual void SetAnswerQuestion( CTalkMonster *pSpeaker ); - int FriendNumber( int arrayNumber ); - - int FIdleSpeak ( void ); - int m_baseSequence; - int m_headTurn; - float m_flResponseDelay; -}; - -LINK_ENTITY_TO_CLASS( monster_sitting_scientist, CSittingScientist ); -TYPEDESCRIPTION CSittingScientist::m_SaveData[] = -{ - // Don't need to save/restore m_baseSequence (recalced) - DEFINE_FIELD( CSittingScientist, m_headTurn, FIELD_INTEGER ), - DEFINE_FIELD( CSittingScientist, m_flResponseDelay, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CSittingScientist, CScientist ); - -// animation sequence aliases -typedef enum -{ -SITTING_ANIM_sitlookleft, -SITTING_ANIM_sitlookright, -SITTING_ANIM_sitscared, -SITTING_ANIM_sitting2, -SITTING_ANIM_sitting3 -} SITTING_ANIM; - - -// -// ********** Scientist SPAWN ********** -// -void CSittingScientist :: Spawn( ) -{ - PRECACHE_MODEL("models/scientist.mdl"); - SET_MODEL(ENT(pev), "models/scientist.mdl"); - Precache(); - InitBoneControllers(); - - UTIL_SetSize(pev, Vector(-14, -14, 0), Vector(14, 14, 36)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 50; - - m_bloodColor = BLOOD_COLOR_RED; - m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD; - - SetBits(pev->spawnflags, SF_MONSTER_PREDISASTER); // predisaster only! - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - m_baseSequence = LookupSequence( "sitlookleft" ); - pev->sequence = m_baseSequence + RANDOM_LONG(0,4); - ResetSequenceInfo( ); - - SetThink (SittingThink); - pev->nextthink = gpGlobals->time + 0.1; - - DROP_TO_FLOOR ( ENT(pev) ); -} - -void CSittingScientist :: Precache( void ) -{ - m_baseSequence = LookupSequence( "sitlookleft" ); - TalkInit(); -} - -//========================================================= -// ID as a passive human -//========================================================= -int CSittingScientist :: Classify ( void ) -{ - return CLASS_HUMAN_PASSIVE; -} - - -int CSittingScientist::FriendNumber( int arrayNumber ) -{ - static int array[3] = { 2, 1, 0 }; - if ( arrayNumber < 3 ) - return array[ arrayNumber ]; - return arrayNumber; -} - - - -//========================================================= -// sit, do stuff -//========================================================= -void CSittingScientist :: SittingThink( void ) -{ - CBaseEntity *pent; - - StudioFrameAdvance( ); - - // try to greet player - if (FIdleHello()) - { - pent = FindNearestFriend(TRUE); - if (pent) - { - float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw > 0) - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; - else - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; - - ResetSequenceInfo( ); - pev->frame = 0; - SetBoneController( 0, 0 ); - } - } - else if (m_fSequenceFinished) - { - int i = RANDOM_LONG(0,99); - m_headTurn = 0; - - if (m_flResponseDelay && gpGlobals->time > m_flResponseDelay) - { - // respond to question - IdleRespond(); - pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; - m_flResponseDelay = 0; - } - else if (i < 30) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - - // turn towards player or nearest friend and speak - - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) - pent = FindNearestFriend(TRUE); - else - pent = FindNearestFriend(FALSE); - - if (!FIdleSpeak() || !pent) - { - m_headTurn = RANDOM_LONG(0,8) * 10 - 40; - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - } - else - { - // only turn head if we spoke - float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw > 0) - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; - else - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; - - //ALERT(at_console, "sitting speak\n"); - } - } - else if (i < 60) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - m_headTurn = RANDOM_LONG(0,8) * 10 - 40; - if (RANDOM_LONG(0,99) < 5) - { - //ALERT(at_console, "sitting speak2\n"); - FIdleSpeak(); - } - } - else if (i < 80) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting2; - } - else if (i < 100) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; - } - - ResetSequenceInfo( ); - pev->frame = 0; - SetBoneController( 0, m_headTurn ); - } - pev->nextthink = gpGlobals->time + 0.1; -} - -// prepare sitting scientist to answer a question -void CSittingScientist :: SetAnswerQuestion( CTalkMonster *pSpeaker ) -{ - m_flResponseDelay = gpGlobals->time + RANDOM_FLOAT(3, 4); - m_hTalkTarget = (CBaseMonster *)pSpeaker; -} - - -//========================================================= -// FIdleSpeak -// ask question of nearby friend, or make statement -//========================================================= -int CSittingScientist :: FIdleSpeak ( void ) -{ - // try to start a conversation, or make statement - int pitch; - - if (!FOkToSpeak()) - return FALSE; - - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); - - pitch = GetVoicePitch(); - - // if there is a friend nearby to speak to, play sentence, set friend's response time, return - - // try to talk to any standing or sitting scientists nearby - CBaseEntity *pentFriend = FindNearestFriend(FALSE); - - if (pentFriend && RANDOM_LONG(0,1)) - { - CTalkMonster *pTalkMonster = GetClassPtr((CTalkMonster *)pentFriend->pev); - pTalkMonster->SetAnswerQuestion( this ); - - IdleHeadTurn(pentFriend->pev->origin); - SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PQUESTION], 1.0, ATTN_IDLE, 0, pitch ); - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); - return TRUE; - } - - // otherwise, play an idle statement - if (RANDOM_LONG(0,1)) - { - SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PIDLE], 1.0, ATTN_IDLE, 0, pitch ); - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); - return TRUE; - } - - // never spoke - CTalkMonster::g_talkWaitTime = 0; - return FALSE; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// human scientist (passive lab worker) +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "talkmonster.h" +#include "schedule.h" +#include "defaultai.h" +#include "scripted.h" +#include "animation.h" +#include "soundent.h" + + +#define NUM_SCIENTIST_HEADS 4 // four heads available for scientist model +enum { HEAD_GLASSES = 0, HEAD_EINSTEIN = 1, HEAD_LUTHER = 2, HEAD_SLICK = 3 }; + +enum +{ + SCHED_HIDE = LAST_TALKMONSTER_SCHEDULE + 1, + SCHED_FEAR, + SCHED_PANIC, + SCHED_STARTLE, + SCHED_TARGET_CHASE_SCARED, + SCHED_TARGET_FACE_SCARED, +}; + +enum +{ + TASK_SAY_HEAL = LAST_TALKMONSTER_TASK + 1, + TASK_HEAL, + TASK_SAY_FEAR, + TASK_RUN_PATH_SCARED, + TASK_SCREAM, + TASK_RANDOM_SCREAM, + TASK_MOVE_TO_TARGET_RANGE_SCARED, +}; + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define SCIENTIST_AE_HEAL ( 1 ) +#define SCIENTIST_AE_NEEDLEON ( 2 ) +#define SCIENTIST_AE_NEEDLEOFF ( 3 ) + +//======================================================= +// Scientist +//======================================================= + +class CScientist : public CTalkMonster +{ +public: + void Spawn( void ); + void Precache( void ); + + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void RunTask( Task_t *pTask ); + void StartTask( Task_t *pTask ); + int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + virtual int FriendNumber( int arrayNumber ); + void SetActivity ( Activity newActivity ); + Activity GetStoppedActivity( void ); + int ISoundMask( void ); + void DeclineFollowing( void ); + + float CoverRadius( void ) { return 1200; } // Need more room for cover because scientists want to get far away! + BOOL DisregardEnemy( CBaseEntity *pEnemy ) { return !pEnemy->IsAlive() || (gpGlobals->time - m_fearTime) > 15; } + + BOOL CanHeal( void ); + void Heal( void ); + void Scream( void ); + + // Override these to set behavior + Schedule_t *GetScheduleOfType ( int Type ); + Schedule_t *GetSchedule ( void ); + MONSTERSTATE GetIdealState ( void ); + + void DeathSound( void ); + void PainSound( void ); + + void TalkInit( void ); + + void Killed( entvars_t *pevAttacker, int iGib ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + CUSTOM_SCHEDULES; + +private: + float m_painTime; + float m_healTime; + float m_fearTime; +}; + +LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ); + +TYPEDESCRIPTION CScientist::m_SaveData[] = +{ + DEFINE_FIELD( CScientist, m_painTime, FIELD_TIME ), + DEFINE_FIELD( CScientist, m_healTime, FIELD_TIME ), + DEFINE_FIELD( CScientist, m_fearTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CScientist, CTalkMonster ); + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= +Task_t tlFollow[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CANT_FOLLOW }, // If you fail, bail out of follow + { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) +// { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, +}; + +Schedule_t slFollow[] = +{ + { + tlFollow, + ARRAYSIZE ( tlFollow ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + bits_SOUND_COMBAT | + bits_SOUND_DANGER, + "Follow" + }, +}; + +Task_t tlFollowScared[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE },// If you fail, follow normally + { TASK_MOVE_TO_TARGET_RANGE_SCARED,(float)128 }, // Move within 128 of target ent (client) +// { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE_SCARED }, +}; + +Schedule_t slFollowScared[] = +{ + { + tlFollowScared, + ARRAYSIZE ( tlFollowScared ), + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + bits_SOUND_DANGER, + "FollowScared" + }, +}; + +Task_t tlFaceTargetScared[] = +{ + { TASK_FACE_TARGET, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE_SCARED }, +}; + +Schedule_t slFaceTargetScared[] = +{ + { + tlFaceTargetScared, + ARRAYSIZE ( tlFaceTargetScared ), + bits_COND_HEAR_SOUND | + bits_COND_NEW_ENEMY, + bits_SOUND_DANGER, + "FaceTargetScared" + }, +}; + +Task_t tlStopFollowing[] = +{ + { TASK_CANT_FOLLOW, (float)0 }, +}; + +Schedule_t slStopFollowing[] = +{ + { + tlStopFollowing, + ARRAYSIZE ( tlStopFollowing ), + 0, + 0, + "StopFollowing" + }, +}; + + +Task_t tlHeal[] = +{ + { TASK_MOVE_TO_TARGET_RANGE,(float)50 }, // Move within 60 of target ent (client) + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE }, // If you fail, catch up with that guy! (change this to put syringe away and then chase) + { TASK_FACE_IDEAL, (float)0 }, + { TASK_SAY_HEAL, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_ARM }, // Whip out the needle + { TASK_HEAL, (float)0 }, // Put it in the player + { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_DISARM }, // Put away the needle +}; + +Schedule_t slHeal[] = +{ + { + tlHeal, + ARRAYSIZE ( tlHeal ), + 0, // Don't interrupt or he'll end up running around with a needle all the time + 0, + "Heal" + }, +}; + + +Task_t tlFaceTarget[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_TARGET, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, +}; + +Schedule_t slFaceTarget[] = +{ + { + tlFaceTarget, + ARRAYSIZE ( tlFaceTarget ), + bits_COND_CLIENT_PUSH | + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND, + bits_SOUND_COMBAT | + bits_SOUND_DANGER, + "FaceTarget" + }, +}; + + +Task_t tlSciPanic[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SCREAM, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_EXCITED }, // This is really fear-stricken excitement + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, +}; + +Schedule_t slSciPanic[] = +{ + { + tlSciPanic, + ARRAYSIZE ( tlSciPanic ), + 0, + 0, + "SciPanic" + }, +}; + + +Task_t tlIdleSciStand[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. + { TASK_TLK_HEADRESET, (float)0 }, // reset head position +}; + +Schedule_t slIdleSciStand[] = +{ + { + tlIdleSciStand, + ARRAYSIZE ( tlIdleSciStand ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_SMELL | + bits_COND_CLIENT_PUSH | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT |// sound flags + //bits_SOUND_PLAYER | + //bits_SOUND_WORLD | + bits_SOUND_DANGER | + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "IdleSciStand" + + }, +}; + + +Task_t tlScientistCover[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! + { TASK_STOP_MOVING, (float)0 }, + { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, + { TASK_RUN_PATH_SCARED, (float)0 }, + { TASK_TURN_LEFT, (float)179 }, + { TASK_SET_SCHEDULE, (float)SCHED_HIDE }, +}; + +Schedule_t slScientistCover[] = +{ + { + tlScientistCover, + ARRAYSIZE ( tlScientistCover ), + bits_COND_NEW_ENEMY, + 0, + "ScientistCover" + }, +}; + + + +Task_t tlScientistHide[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, + { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, // FIXME: This looks lame + { TASK_WAIT_RANDOM, (float)10.0 }, +}; + +Schedule_t slScientistHide[] = +{ + { + tlScientistHide, + ARRAYSIZE ( tlScientistHide ), + bits_COND_NEW_ENEMY | + bits_COND_HEAR_SOUND | + bits_COND_SEE_ENEMY | + bits_COND_SEE_HATE | + bits_COND_SEE_FEAR | + bits_COND_SEE_DISLIKE, + bits_SOUND_DANGER, + "ScientistHide" + }, +}; + + +Task_t tlScientistStartle[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! + { TASK_RANDOM_SCREAM, (float)0.3 }, // Scream 30% of the time + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, + { TASK_RANDOM_SCREAM, (float)0.1 }, // Scream again 10% of the time + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCHIDLE }, + { TASK_WAIT_RANDOM, (float)1.0 }, +}; + +Schedule_t slScientistStartle[] = +{ + { + tlScientistStartle, + ARRAYSIZE ( tlScientistStartle ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_ENEMY | + bits_COND_SEE_HATE | + bits_COND_SEE_FEAR | + bits_COND_SEE_DISLIKE, + 0, + "ScientistStartle" + }, +}; + + + +Task_t tlFear[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SAY_FEAR, (float)0 }, +// { TASK_PLAY_SEQUENCE, (float)ACT_FEAR_DISPLAY }, +}; + +Schedule_t slFear[] = +{ + { + tlFear, + ARRAYSIZE ( tlFear ), + bits_COND_NEW_ENEMY, + 0, + "Fear" + }, +}; + + +DEFINE_CUSTOM_SCHEDULES( CScientist ) +{ + slFollow, + slFaceTarget, + slIdleSciStand, + slFear, + slScientistCover, + slScientistHide, + slScientistStartle, + slHeal, + slStopFollowing, + slSciPanic, + slFollowScared, + slFaceTargetScared, +}; + + +IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster ); + + +void CScientist::DeclineFollowing( void ) +{ + Talk( 10 ); + m_hTalkTarget = m_hEnemy; + PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); +} + + +void CScientist :: Scream( void ) +{ + if ( FOkToSpeak() ) + { + Talk( 10 ); + m_hTalkTarget = m_hEnemy; + PlaySentence( "SC_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); + } +} + + +Activity CScientist::GetStoppedActivity( void ) +{ + if ( m_hEnemy != NULL ) + return ACT_EXCITED; + return CTalkMonster::GetStoppedActivity(); +} + + +void CScientist :: StartTask( Task_t *pTask ) +{ + switch( pTask->iTask ) + { + case TASK_SAY_HEAL: +// if ( FOkToSpeak() ) + Talk( 2 ); + m_hTalkTarget = m_hTargetEnt; + PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); + + TaskComplete(); + break; + + case TASK_SCREAM: + Scream(); + TaskComplete(); + break; + + case TASK_RANDOM_SCREAM: + if ( RANDOM_FLOAT( 0, 1 ) < pTask->flData ) + Scream(); + TaskComplete(); + break; + + case TASK_SAY_FEAR: + if ( FOkToSpeak() ) + { + Talk( 2 ); + m_hTalkTarget = m_hEnemy; + if ( m_hEnemy->IsPlayer() ) + PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); + else + PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); + } + TaskComplete(); + break; + + case TASK_HEAL: + m_IdealActivity = ACT_MELEE_ATTACK1; + break; + + case TASK_RUN_PATH_SCARED: + m_movementActivity = ACT_RUN_SCARED; + break; + + case TASK_MOVE_TO_TARGET_RANGE_SCARED: + { + if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + TaskComplete(); + else + { + m_vecMoveGoal = m_hTargetEnt->pev->origin; + if ( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) ) + TaskFail(); + } + } + break; + + default: + CTalkMonster::StartTask( pTask ); + break; + } +} + +void CScientist :: RunTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_RUN_PATH_SCARED: + if ( MovementIsComplete() ) + TaskComplete(); + if ( RANDOM_LONG(0,31) < 8 ) + Scream(); + break; + + case TASK_MOVE_TO_TARGET_RANGE_SCARED: + { + if ( RANDOM_LONG(0,63)< 8 ) + Scream(); + + if ( m_hEnemy == NULL ) + { + TaskFail(); + } + else + { + float distance; + + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + // Re-evaluate when you think your finished, or the target has moved too far + if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) + { + m_vecMoveGoal = m_hTargetEnt->pev->origin; + distance = ( m_vecMoveGoal - pev->origin ).Length2D(); + FRefreshRoute(); + } + + // Set the appropriate activity based on an overlapping range + // overlap the range to prevent oscillation + if ( distance < pTask->flData ) + { + TaskComplete(); + RouteClear(); // Stop moving + } + else if ( distance < 190 && m_movementActivity != ACT_WALK_SCARED ) + m_movementActivity = ACT_WALK_SCARED; + else if ( distance >= 270 && m_movementActivity != ACT_RUN_SCARED ) + m_movementActivity = ACT_RUN_SCARED; + } + } + break; + + case TASK_HEAL: + if ( m_fSequenceFinished ) + { + TaskComplete(); + } + else + { + if ( TargetDistance() > 90 ) + TaskComplete(); + pev->ideal_yaw = UTIL_VecToYaw( m_hTargetEnt->pev->origin - pev->origin ); + ChangeYaw( pev->yaw_speed ); + } + break; + default: + CTalkMonster::RunTask( pTask ); + break; + } +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CScientist :: Classify ( void ) +{ + return CLASS_HUMAN_PASSIVE; +} + + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CScientist :: SetYawSpeed ( void ) +{ + int ys; + + ys = 90; + + switch ( m_Activity ) + { + case ACT_IDLE: + ys = 120; + break; + case ACT_WALK: + ys = 180; + break; + case ACT_RUN: + ys = 150; + break; + case ACT_TURN_LEFT: + case ACT_TURN_RIGHT: + ys = 120; + break; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case SCIENTIST_AE_HEAL: // Heal my target (if within range) + Heal(); + break; + case SCIENTIST_AE_NEEDLEON: + { + int oldBody = pev->body; + pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 1; + } + break; + case SCIENTIST_AE_NEEDLEOFF: + { + int oldBody = pev->body; + pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 0; + } + break; + + default: + CTalkMonster::HandleAnimEvent( pEvent ); + } +} + +//========================================================= +// Spawn +//========================================================= +void CScientist :: Spawn( void ) +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/scientist.mdl"); + UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_RED; + pev->health = gSkillData.scientistHealth; + pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. + m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello + m_MonsterState = MONSTERSTATE_NONE; + +// m_flDistTooFar = 256.0; + + m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; + + // White hands + pev->skin = 0; + + if ( pev->body == -1 ) + {// -1 chooses a random head + pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head + } + + // Luther is black, make his hands black + if ( pev->body == HEAD_LUTHER ) + pev->skin = 1; + + MonsterInit(); + SetUse( FollowerUse ); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CScientist :: Precache( void ) +{ + PRECACHE_MODEL("models/scientist.mdl"); + PRECACHE_SOUND("scientist/sci_pain1.wav"); + PRECACHE_SOUND("scientist/sci_pain2.wav"); + PRECACHE_SOUND("scientist/sci_pain3.wav"); + PRECACHE_SOUND("scientist/sci_pain4.wav"); + PRECACHE_SOUND("scientist/sci_pain5.wav"); + + // every new scientist must call this, otherwise + // when a level is loaded, nobody will talk (time is reset to 0) + TalkInit(); + + CTalkMonster::Precache(); +} + +// Init talk data +void CScientist :: TalkInit() +{ + + CTalkMonster::TalkInit(); + + // scientist will try to talk to friends in this order: + + m_szFriends[0] = "monster_scientist"; + m_szFriends[1] = "monster_sitting_scientist"; + m_szFriends[2] = "monster_barney"; + + // scientists speach group names (group names are in sentences.txt) + + m_szGrp[TLK_ANSWER] = "SC_ANSWER"; + m_szGrp[TLK_QUESTION] = "SC_QUESTION"; + m_szGrp[TLK_IDLE] = "SC_IDLE"; + m_szGrp[TLK_STARE] = "SC_STARE"; + m_szGrp[TLK_USE] = "SC_OK"; + m_szGrp[TLK_UNUSE] = "SC_WAIT"; + m_szGrp[TLK_STOP] = "SC_STOP"; + m_szGrp[TLK_NOSHOOT] = "SC_SCARED"; + m_szGrp[TLK_HELLO] = "SC_HELLO"; + + m_szGrp[TLK_PLHURT1] = "!SC_CUREA"; + m_szGrp[TLK_PLHURT2] = "!SC_CUREB"; + m_szGrp[TLK_PLHURT3] = "!SC_CUREC"; + + m_szGrp[TLK_PHELLO] = "SC_PHELLO"; + m_szGrp[TLK_PIDLE] = "SC_PIDLE"; + m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; + m_szGrp[TLK_SMELL] = "SC_SMELL"; + + m_szGrp[TLK_WOUND] = "SC_WOUND"; + m_szGrp[TLK_MORTAL] = "SC_MORTAL"; + + // get voice for head + switch (pev->body % 3) + { + default: + case HEAD_GLASSES: m_voicePitch = 105; break; //glasses + case HEAD_EINSTEIN: m_voicePitch = 100; break; //einstein + case HEAD_LUTHER: m_voicePitch = 95; break; //luther + case HEAD_SLICK: m_voicePitch = 100; break;//slick + } +} + +int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) +{ + + if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) + { + Remember( bits_MEMORY_PROVOKED ); + StopFollowing( TRUE ); + } + + // make sure friends talk about it if player hurts scientist... + return CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); +} + + +//========================================================= +// ISoundMask - returns a bit mask indicating which types +// of sounds this monster regards. In the base class implementation, +// monsters care about all sounds, but no scents. +//========================================================= +int CScientist :: ISoundMask ( void ) +{ + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_DANGER | + bits_SOUND_PLAYER; +} + +//========================================================= +// PainSound +//========================================================= +void CScientist :: PainSound ( void ) +{ + if (gpGlobals->time < m_painTime ) + return; + + m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); + + switch (RANDOM_LONG(0,4)) + { + case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 3: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain4.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + case 4: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain5.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; + } +} + +//========================================================= +// DeathSound +//========================================================= +void CScientist :: DeathSound ( void ) +{ + PainSound(); +} + + +void CScientist::Killed( entvars_t *pevAttacker, int iGib ) +{ + SetUse( NULL ); + CTalkMonster::Killed( pevAttacker, iGib ); +} + + +void CScientist :: SetActivity ( Activity newActivity ) +{ + int iSequence; + + iSequence = LookupActivity ( newActivity ); + + // Set to the desired anim, or default anim if the desired is not present + if ( iSequence == ACTIVITY_NOT_AVAILABLE ) + newActivity = ACT_IDLE; + CTalkMonster::SetActivity( newActivity ); +} + + +Schedule_t* CScientist :: GetScheduleOfType ( int Type ) +{ + Schedule_t *psched; + + switch( Type ) + { + // Hook these to make a looping schedule + case SCHED_TARGET_FACE: + // call base class default so that scientist will talk + // when 'used' + psched = CTalkMonster::GetScheduleOfType(Type); + + if (psched == slIdleStand) + return slFaceTarget; // override this for different target face behavior + else + return psched; + + case SCHED_TARGET_CHASE: + return slFollow; + + case SCHED_CANT_FOLLOW: + return slStopFollowing; + + case SCHED_PANIC: + return slSciPanic; + + case SCHED_TARGET_CHASE_SCARED: + return slFollowScared; + + case SCHED_TARGET_FACE_SCARED: + return slFaceTargetScared; + + case SCHED_IDLE_STAND: + // call base class default so that scientist will talk + // when standing during idle + psched = CTalkMonster::GetScheduleOfType(Type); + + if (psched == slIdleStand) + return slIdleSciStand; + else + return psched; + + case SCHED_HIDE: + return slScientistHide; + + case SCHED_STARTLE: + return slScientistStartle; + + case SCHED_FEAR: + return slFear; + } + + return CTalkMonster::GetScheduleOfType( Type ); +} + +Schedule_t *CScientist :: GetSchedule ( void ) +{ + // so we don't keep calling through the EHANDLE stuff + CBaseEntity *pEnemy = m_hEnemy; + + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); + } + + switch( m_MonsterState ) + { + case MONSTERSTATE_ALERT: + case MONSTERSTATE_IDLE: + if ( pEnemy ) + { + if ( HasConditions( bits_COND_SEE_ENEMY ) ) + m_fearTime = gpGlobals->time; + else if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert + { + m_hEnemy = NULL; + pEnemy = NULL; + } + } + + if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) + { + // flinch if hurt + return GetScheduleOfType( SCHED_SMALL_FLINCH ); + } + + // Cower when you hear something scary + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + { + CSound *pSound; + pSound = PBestSound(); + + ASSERT( pSound != NULL ); + if ( pSound ) + { + if ( pSound->m_iType & (bits_SOUND_DANGER | bits_SOUND_COMBAT) ) + { + if ( gpGlobals->time - m_fearTime > 3 ) // Only cower every 3 seconds or so + { + m_fearTime = gpGlobals->time; // Update last fear + return GetScheduleOfType( SCHED_STARTLE ); // This will just duck for a second + } + } + } + } + + // Behavior for following the player + if ( IsFollowing() ) + { + if ( !m_hTargetEnt->IsAlive() ) + { + // UNDONE: Comment about the recently dead player here? + StopFollowing( FALSE ); + break; + } + + int relationship = R_NO; + + // Nothing scary, just me and the player + if ( pEnemy != NULL ) + relationship = IRelationship( pEnemy ); + + // UNDONE: Model fear properly, fix R_FR and add multiple levels of fear + if ( relationship != R_DL && relationship != R_HT ) + { + // If I'm already close enough to my target + if ( TargetDistance() <= 128 ) + { + if ( CanHeal() ) // Heal opportunistically + return slHeal; + if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move + return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); + } + return GetScheduleOfType( SCHED_TARGET_FACE ); // Just face and follow. + } + else // UNDONE: When afraid, scientist won't move out of your way. Keep This? If not, write move away scared + { + if ( HasConditions( bits_COND_NEW_ENEMY ) ) // I just saw something new and scary, react + return GetScheduleOfType( SCHED_FEAR ); // React to something scary + return GetScheduleOfType( SCHED_TARGET_FACE_SCARED ); // face and follow, but I'm scared! + } + } + + if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move + return GetScheduleOfType( SCHED_MOVE_AWAY ); + + // try to say something about smells + TrySmellTalk(); + break; + case MONSTERSTATE_COMBAT: + if ( HasConditions( bits_COND_NEW_ENEMY ) ) + return slFear; // Point and scream! + if ( HasConditions( bits_COND_SEE_ENEMY ) ) + return slScientistCover; // Take Cover + + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + return slTakeCoverFromBestSound; // Cower and panic from the scary sound! + + return slScientistCover; // Run & Cower + break; + } + + return CTalkMonster::GetSchedule(); +} + +MONSTERSTATE CScientist :: GetIdealState ( void ) +{ + switch ( m_MonsterState ) + { + case MONSTERSTATE_ALERT: + case MONSTERSTATE_IDLE: + if ( HasConditions( bits_COND_NEW_ENEMY ) ) + { + if ( IsFollowing() ) + { + int relationship = IRelationship( m_hEnemy ); + if ( relationship != R_FR || relationship != R_HT && !HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + { + // Don't go to combat if you're following the player + m_IdealMonsterState = MONSTERSTATE_ALERT; + return m_IdealMonsterState; + } + StopFollowing( TRUE ); + } + } + else if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + { + // Stop following if you take damage + if ( IsFollowing() ) + StopFollowing( TRUE ); + } + break; + + case MONSTERSTATE_COMBAT: + { + CBaseEntity *pEnemy = m_hEnemy; + if ( pEnemy != NULL ) + { + if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert + { + // Strip enemy when going to alert + m_IdealMonsterState = MONSTERSTATE_ALERT; + m_hEnemy = NULL; + return m_IdealMonsterState; + } + // Follow if only scared a little + if ( m_hTargetEnt != NULL ) + { + m_IdealMonsterState = MONSTERSTATE_ALERT; + return m_IdealMonsterState; + } + + if ( HasConditions ( bits_COND_SEE_ENEMY ) ) + { + m_fearTime = gpGlobals->time; + m_IdealMonsterState = MONSTERSTATE_COMBAT; + return m_IdealMonsterState; + } + + } + } + break; + } + + return CTalkMonster::GetIdealState(); +} + + +BOOL CScientist::CanHeal( void ) +{ + if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (m_hTargetEnt->pev->health > (m_hTargetEnt->pev->max_health * 0.5)) ) + return FALSE; + + return TRUE; +} + +void CScientist::Heal( void ) +{ + if ( !CanHeal() ) + return; + + Vector target = m_hTargetEnt->pev->origin - pev->origin; + if ( target.Length() > 100 ) + return; + + m_hTargetEnt->TakeHealth( gSkillData.scientistHeal, DMG_GENERIC ); + // Don't heal again for 1 minute + m_healTime = gpGlobals->time + 60; +} + +int CScientist::FriendNumber( int arrayNumber ) +{ + static int array[3] = { 1, 2, 0 }; + if ( arrayNumber < 3 ) + return array[ arrayNumber ]; + return arrayNumber; +} + + +//========================================================= +// Dead Scientist PROP +//========================================================= +class CDeadScientist : public CBaseMonster +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_HUMAN_PASSIVE; } + + void KeyValue( KeyValueData *pkvd ); + int m_iPose;// which sequence to display + static char *m_szPoses[7]; +}; +char *CDeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", "dead_sitting", "dead_hang", "dead_table1", "dead_table2", "dead_table3" }; + +void CDeadScientist::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "pose")) + { + m_iPose = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseMonster::KeyValue( pkvd ); +} +LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ); + +// +// ********** DeadScientist SPAWN ********** +// +void CDeadScientist :: Spawn( ) +{ + PRECACHE_MODEL("models/scientist.mdl"); + SET_MODEL(ENT(pev), "models/scientist.mdl"); + + pev->effects = 0; + pev->sequence = 0; + // Corpses have less health + pev->health = 8;//gSkillData.scientistHealth; + + m_bloodColor = BLOOD_COLOR_RED; + + if ( pev->body == -1 ) + {// -1 chooses a random head + pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head + } + // Luther is black, make his hands black + if ( pev->body == HEAD_LUTHER ) + pev->skin = 1; + else + pev->skin = 0; + + pev->sequence = LookupSequence( m_szPoses[m_iPose] ); + if (pev->sequence == -1) + { + ALERT ( at_console, "Dead scientist with bad pose\n" ); + } + + // pev->skin += 2; // use bloody skin -- UNDONE: Turn this back on when we have a bloody skin again! + MonsterInitDead(); +} + + +//========================================================= +// Sitting Scientist PROP +//========================================================= + +class CSittingScientist : public CScientist // kdb: changed from public CBaseMonster so he can speak +{ +public: + void Spawn( void ); + void Precache( void ); + + void EXPORT SittingThink( void ); + int Classify ( void ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + virtual void SetAnswerQuestion( CTalkMonster *pSpeaker ); + int FriendNumber( int arrayNumber ); + + int FIdleSpeak ( void ); + int m_baseSequence; + int m_headTurn; + float m_flResponseDelay; +}; + +LINK_ENTITY_TO_CLASS( monster_sitting_scientist, CSittingScientist ); +TYPEDESCRIPTION CSittingScientist::m_SaveData[] = +{ + // Don't need to save/restore m_baseSequence (recalced) + DEFINE_FIELD( CSittingScientist, m_headTurn, FIELD_INTEGER ), + DEFINE_FIELD( CSittingScientist, m_flResponseDelay, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CSittingScientist, CScientist ); + +// animation sequence aliases +typedef enum +{ +SITTING_ANIM_sitlookleft, +SITTING_ANIM_sitlookright, +SITTING_ANIM_sitscared, +SITTING_ANIM_sitting2, +SITTING_ANIM_sitting3 +} SITTING_ANIM; + + +// +// ********** Scientist SPAWN ********** +// +void CSittingScientist :: Spawn( ) +{ + PRECACHE_MODEL("models/scientist.mdl"); + SET_MODEL(ENT(pev), "models/scientist.mdl"); + Precache(); + InitBoneControllers(); + + UTIL_SetSize(pev, Vector(-14, -14, 0), Vector(14, 14, 36)); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + pev->effects = 0; + pev->health = 50; + + m_bloodColor = BLOOD_COLOR_RED; + m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) + + m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD; + + SetBits(pev->spawnflags, SF_MONSTER_PREDISASTER); // predisaster only! + + if ( pev->body == -1 ) + {// -1 chooses a random head + pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head + } + // Luther is black, make his hands black + if ( pev->body == HEAD_LUTHER ) + pev->skin = 1; + + m_baseSequence = LookupSequence( "sitlookleft" ); + pev->sequence = m_baseSequence + RANDOM_LONG(0,4); + ResetSequenceInfo( ); + + SetThink (SittingThink); + pev->nextthink = gpGlobals->time + 0.1; + + DROP_TO_FLOOR ( ENT(pev) ); +} + +void CSittingScientist :: Precache( void ) +{ + m_baseSequence = LookupSequence( "sitlookleft" ); + TalkInit(); +} + +//========================================================= +// ID as a passive human +//========================================================= +int CSittingScientist :: Classify ( void ) +{ + return CLASS_HUMAN_PASSIVE; +} + + +int CSittingScientist::FriendNumber( int arrayNumber ) +{ + static int array[3] = { 2, 1, 0 }; + if ( arrayNumber < 3 ) + return array[ arrayNumber ]; + return arrayNumber; +} + + + +//========================================================= +// sit, do stuff +//========================================================= +void CSittingScientist :: SittingThink( void ) +{ + CBaseEntity *pent; + + StudioFrameAdvance( ); + + // try to greet player + if (FIdleHello()) + { + pent = FindNearestFriend(TRUE); + if (pent) + { + float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; + + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + + if (yaw > 0) + pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; + else + pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; + + ResetSequenceInfo( ); + pev->frame = 0; + SetBoneController( 0, 0 ); + } + } + else if (m_fSequenceFinished) + { + int i = RANDOM_LONG(0,99); + m_headTurn = 0; + + if (m_flResponseDelay && gpGlobals->time > m_flResponseDelay) + { + // respond to question + IdleRespond(); + pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; + m_flResponseDelay = 0; + } + else if (i < 30) + { + pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; + + // turn towards player or nearest friend and speak + + if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) + pent = FindNearestFriend(TRUE); + else + pent = FindNearestFriend(FALSE); + + if (!FIdleSpeak() || !pent) + { + m_headTurn = RANDOM_LONG(0,8) * 10 - 40; + pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; + } + else + { + // only turn head if we spoke + float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; + + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + + if (yaw > 0) + pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; + else + pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; + + //ALERT(at_console, "sitting speak\n"); + } + } + else if (i < 60) + { + pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; + m_headTurn = RANDOM_LONG(0,8) * 10 - 40; + if (RANDOM_LONG(0,99) < 5) + { + //ALERT(at_console, "sitting speak2\n"); + FIdleSpeak(); + } + } + else if (i < 80) + { + pev->sequence = m_baseSequence + SITTING_ANIM_sitting2; + } + else if (i < 100) + { + pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; + } + + ResetSequenceInfo( ); + pev->frame = 0; + SetBoneController( 0, m_headTurn ); + } + pev->nextthink = gpGlobals->time + 0.1; +} + +// prepare sitting scientist to answer a question +void CSittingScientist :: SetAnswerQuestion( CTalkMonster *pSpeaker ) +{ + m_flResponseDelay = gpGlobals->time + RANDOM_FLOAT(3, 4); + m_hTalkTarget = (CBaseMonster *)pSpeaker; +} + + +//========================================================= +// FIdleSpeak +// ask question of nearby friend, or make statement +//========================================================= +int CSittingScientist :: FIdleSpeak ( void ) +{ + // try to start a conversation, or make statement + int pitch; + + if (!FOkToSpeak()) + return FALSE; + + // set global min delay for next conversation + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); + + pitch = GetVoicePitch(); + + // if there is a friend nearby to speak to, play sentence, set friend's response time, return + + // try to talk to any standing or sitting scientists nearby + CBaseEntity *pentFriend = FindNearestFriend(FALSE); + + if (pentFriend && RANDOM_LONG(0,1)) + { + CTalkMonster *pTalkMonster = GetClassPtr((CTalkMonster *)pentFriend->pev); + pTalkMonster->SetAnswerQuestion( this ); + + IdleHeadTurn(pentFriend->pev->origin); + SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PQUESTION], 1.0, ATTN_IDLE, 0, pitch ); + // set global min delay for next conversation + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); + return TRUE; + } + + // otherwise, play an idle statement + if (RANDOM_LONG(0,1)) + { + SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PIDLE], 1.0, ATTN_IDLE, 0, pitch ); + // set global min delay for next conversation + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); + return TRUE; + } + + // never spoke + CTalkMonster::g_talkWaitTime = 0; + return FALSE; +} diff --git a/main/source/dlls/scripted.cpp b/main/source/dlls/scripted.cpp index bf0261fd..e1c4e0c8 100644 --- a/main/source/dlls/scripted.cpp +++ b/main/source/dlls/scripted.cpp @@ -1,1249 +1,1249 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - - -===== scripted.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" - -#ifndef ANIMATION_H -#include "animation.h" -#endif - -#ifndef SAVERESTORE_H -#include "saverestore.h" -#endif - -#include "schedule.h" -#include "scripted.h" -#include "defaultai.h" - - - -/* -classname "scripted_sequence" -targetname "me" - there can be more than one with the same name, and they act in concert -target "the_entity_I_want_to_start_playing" or "class entity_classname" will pick the closest inactive scientist -play "name_of_sequence" -idle "name of idle sequence to play before starting" -donetrigger "whatever" - can be any other triggerable entity such as another sequence, train, door, or a special case like "die" or "remove" -moveto - if set the monster first moves to this nodes position -range # - only search this far to find the target -spawnflags - (stop if blocked, stop if player seen) -*/ - - -// -// Cache user-entity-field values until spawn is called. -// - -void CCineMonster :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszIdle")) - { - m_iszIdle = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszPlay")) - { - m_iszPlay = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszEntity")) - { - m_iszEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fMoveTo")) - { - m_fMoveTo = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flRepeat")) - { - m_flRepeat = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flRadius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iFinishSchedule")) - { - m_iFinishSchedule = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseMonster::KeyValue( pkvd ); - } -} - -TYPEDESCRIPTION CCineMonster::m_SaveData[] = -{ - DEFINE_FIELD( CCineMonster, m_iszIdle, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_iszPlay, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_iszEntity, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_fMoveTo, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_flRepeat, FIELD_FLOAT ), - DEFINE_FIELD( CCineMonster, m_flRadius, FIELD_FLOAT ), - - DEFINE_FIELD( CCineMonster, m_iDelay, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_startTime, FIELD_TIME ), - - DEFINE_FIELD( CCineMonster, m_saved_movetype, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_saved_solid, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_saved_effects, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_iFinishSchedule, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_interruptable, FIELD_BOOLEAN ), -}; - - -IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ); - -LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ); -#define CLASSNAME "scripted_sequence" - -LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ); - - -void CCineMonster :: Spawn( void ) -{ - // pev->solid = SOLID_TRIGGER; - // UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - pev->solid = SOLID_NOT; - - - // REMOVE: The old side-effect -#if 0 - if ( m_iszIdle ) - m_fMoveTo = 4; -#endif - - // if no targetname, start now - if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) - { - SetThink( &CCineMonster::CineThink ); - pev->nextthink = gpGlobals->time + 1.0; - // Wait to be used? - if ( pev->targetname ) - m_startTime = gpGlobals->time + 1E6; - } - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - m_interruptable = FALSE; - else - m_interruptable = TRUE; -} - -//========================================================= -// FCanOverrideState - returns FALSE, scripted sequences -// cannot possess entities regardless of state. -//========================================================= -BOOL CCineMonster :: FCanOverrideState( void ) -{ - if ( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) - return TRUE; - return FALSE; -} - -//========================================================= -// FCanOverrideState - returns true because scripted AI can -// possess entities regardless of their state. -//========================================================= -BOOL CCineAI :: FCanOverrideState( void ) -{ - return TRUE; -} - - -// -// CineStart -// -void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // do I already know who I should use - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - // am I already playing the script? - if ( pTarget->m_scriptState == SCRIPT_PLAYING ) - return; - - m_startTime = gpGlobals->time + 0.05; - } - else - { - // if not, try finding them - SetThink( &CCineMonster::CineThink ); - pev->nextthink = gpGlobals->time; - } -} - - -// This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events -void CCineMonster :: Blocked( CBaseEntity *pOther ) -{ - -} - -void CCineMonster :: Touch( CBaseEntity *pOther ) -{ -/* - ALERT( at_aiconsole, "Cine Touch\n" ); - if (m_pentTarget && OFFSET(pOther->pev) == OFFSET(m_pentTarget)) - { - CBaseMonster *pTarget = GetClassPtr((CBaseMonster *)VARS(m_pentTarget)); - pTarget->m_monsterState == MONSTERSTATE_SCRIPT; - } -*/ -} - - -/* - entvars_t *pevOther = VARS( gpGlobals->other ); - - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-monster. - return; - } - - pevOther->origin.z += 1; - - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) - {// clear the onground so physics don't bitch - pevOther->flags -= FL_ONGROUND; - } - - // toss the monster! - pevOther->velocity = pev->movedir * pev->speed; - pevOther->velocity.z += m_flHeight; - - - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE -} -*/ - - -// -// ********** Cinematic DIE ********** -// -void CCineMonster :: Die( void ) -{ - SetThink( &CCineMonster::SUB_Remove ); -} - -// -// ********** Cinematic PAIN ********** -// -void CCineMonster :: Pain( void ) -{ - -} - -// -// ********** Cinematic Think ********** -// - -// find a viable entity -int CCineMonster :: FindEntity( void ) -{ - edict_t *pentTarget; - - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - m_hTargetEnt = NULL; - CBaseMonster *pTarget = NULL; - - while (!FNullEnt(pentTarget)) - { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) - { - pTarget = GetMonsterPointer( pentTarget ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_BY_NAME ) ) - { - m_hTargetEnt = pTarget; - return TRUE; - } - ALERT( at_console, "Found %s, but can't play!\n", STRING(m_iszEntity) ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - pTarget = NULL; - } - - if ( !pTarget ) - { - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pTarget = pEntity->MyMonsterPointer( ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_IDLE ) ) - { - m_hTargetEnt = pTarget; - return TRUE; - } - } - } - } - } - pTarget = NULL; - m_hTargetEnt = NULL; - return FALSE; -} - -// make the entity enter a scripted sequence -void CCineMonster :: PossessEntity( void ) -{ - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - - // FindEntity() just checked this! -#if 0 - if ( !pTarget->CanPlaySequence( FCanOverrideState() ) ) - { - ALERT( at_aiconsole, "Can't possess entity %s\n", STRING(pTarget->pev->classname) ); - return; - } -#endif - - pTarget->m_pGoalEnt = this; - pTarget->m_pCine = this; - pTarget->m_hTargetEnt = this; - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - - switch (m_fMoveTo) - { - case 0: - pTarget->m_scriptState = SCRIPT_WAIT; - break; - - case 1: - pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; - DelayStart( 1 ); - break; - - case 2: - pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; - DelayStart( 1 ); - break; - - case 4: - UTIL_SetOrigin( pTarget->pev, pev->origin ); - pTarget->pev->ideal_yaw = pev->angles.y; - pTarget->pev->avelocity = Vector( 0, 0, 0 ); - pTarget->pev->velocity = Vector( 0, 0, 0 ); - pTarget->pev->effects |= EF_NOINTERP; - pTarget->pev->angles.y = pev->angles.y; - pTarget->m_scriptState = SCRIPT_WAIT; - m_startTime = gpGlobals->time + 1E6; - // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters - // pTarget->pev->flags &= ~FL_ONGROUND; - break; - } -// ALERT( at_aiconsole, "\"%s\" found and used (INT: %s)\n", STRING( pTarget->pev->targetname ), FBitSet(pev->spawnflags, SF_SCRIPT_NOINTERRUPT)?"No":"Yes" ); - - pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; - if (m_iszIdle) - { - StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) - { - pTarget->pev->framerate = 0; - } - } - } -} - -// make the entity carry out the scripted sequence instructions, but without -// destroying the monster's state. -void CCineAI :: PossessEntity( void ) -{ - Schedule_t *pNewSchedule; - - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - if ( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) - { - ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", STRING(pTarget->pev->classname) ); - return; - } - - pTarget->m_pGoalEnt = this; - pTarget->m_pCine = this; - pTarget->m_hTargetEnt = this; - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - - switch (m_fMoveTo) - { - case 0: - case 5: - pTarget->m_scriptState = SCRIPT_WAIT; - break; - - case 1: - pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; - break; - - case 2: - pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; - break; - - case 4: - // zap the monster instantly to the site of the script entity. - UTIL_SetOrigin( pTarget->pev, pev->origin ); - pTarget->pev->ideal_yaw = pev->angles.y; - pTarget->pev->avelocity = Vector( 0, 0, 0 ); - pTarget->pev->velocity = Vector( 0, 0, 0 ); - pTarget->pev->effects |= EF_NOINTERP; - pTarget->pev->angles.y = pev->angles.y; - pTarget->m_scriptState = SCRIPT_WAIT; - m_startTime = gpGlobals->time + 1E6; - // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters - pTarget->pev->flags &= ~FL_ONGROUND; - break; - default: - ALERT ( at_aiconsole, "aiscript: invalid Move To Position value!" ); - break; - } - - ALERT( at_aiconsole, "\"%s\" found and used\n", STRING( pTarget->pev->targetname ) ); - - pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; - -/* - if (m_iszIdle) - { - StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) - { - pTarget->pev->framerate = 0; - } - } -*/ - // Already in a scripted state? - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pNewSchedule = pTarget->GetScheduleOfType( SCHED_AISCRIPT ); - pTarget->ChangeSchedule( pNewSchedule ); - } - } -} - -void CCineMonster :: CineThink( void ) -{ - if (FindEntity()) - { - PossessEntity( ); - ALERT( at_aiconsole, "script \"%s\" using monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - } - else - { - CancelScript( ); - ALERT( at_aiconsole, "script \"%s\" can't find monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - pev->nextthink = gpGlobals->time + 1.0; - } -} - - -// lookup a sequence name and setup the target monster to play it -BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ - if ( !iszSeq && completeOnEmpty ) - { - SequenceDone( pTarget ); - return FALSE; - } - - pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - if (pTarget->pev->sequence == -1) - { - ALERT( at_error, "%s: unknown scripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); - pTarget->pev->sequence = 0; - // return FALSE; - } - -#if 0 - char *s; - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - s = "No"; - else - s = "Yes"; - - ALERT( at_console, "%s (%s): started \"%s\":INT:%s\n", STRING( pTarget->pev->targetname ), STRING( pTarget->pev->classname ), STRING( iszSeq), s ); -#endif - - pTarget->pev->frame = 0; - pTarget->ResetSequenceInfo( ); - return TRUE; -} - -// lookup a sequence name and setup the target monster to play it -// overridden for CCineAI because it's ok for them to not have an animation sequence -// for the monster to play. For a regular Scripted Sequence, that situation is an error. -BOOL CCineAI :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ - if ( iszSeq == 0 && completeOnEmpty ) - { - // no sequence was provided. Just let the monster proceed, however, we still have to fire any Sequence target - // and remove any non-repeatable CineAI entities here ( because there is code elsewhere that handles those tasks, but - // not until the animation sequence is finished. We have to manually take care of these things where there is no sequence. - - SequenceDone ( pTarget ); - - return TRUE; - } - - pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - - if (pTarget->pev->sequence == -1) - { - ALERT( at_error, "%s: unknown aiscripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); - pTarget->pev->sequence = 0; - // return FALSE; - } - - pTarget->pev->frame = 0; - pTarget->ResetSequenceInfo( ); - return TRUE; -} - -//========================================================= -// SequenceDone - called when a scripted sequence animation -// sequence is done playing ( or when an AI Scripted Sequence -// doesn't supply an animation sequence to play ). Expects -// the CBaseMonster pointer to the monster that the sequence -// possesses. -//========================================================= -void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) -{ - //ALERT( at_aiconsole, "Sequence %s finished\n", STRING( m_pCine->m_iszPlay ) ); - - if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) - { - SetThink( &CCineMonster::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - } - - // This is done so that another sequence can take over the monster when triggered by the first - - pMonster->CineCleanup(); - - FixScriptMonsterSchedule( pMonster ); - - // This may cause a sequence to attempt to grab this guy NOW, so we have to clear him out - // of the existing sequence - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); -} - -//========================================================= -// When a monster finishes a scripted sequence, we have to -// fix up its state and schedule for it to return to a -// normal AI monster. -// -// Scripted sequences just dirty the Schedule and drop the -// monster in Idle State. -//========================================================= -void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - if ( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) - pMonster->m_IdealMonsterState = MONSTERSTATE_IDLE; - pMonster->ClearSchedule(); -} - -//========================================================= -// When a monster finishes a scripted sequence, we have to -// fix up its state and schedule for it to return to a -// normal AI monster. -// -// AI Scripted sequences will, depending on what the level -// designer selects: -// -// -Dirty the monster's schedule and drop out of the -// sequence in their current state. -// -// -Select a specific AMBUSH schedule, regardless of state. -//========================================================= -void CCineAI :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - switch ( m_iFinishSchedule ) - { - case SCRIPT_FINISHSCHED_DEFAULT: - pMonster->ClearSchedule(); - break; - case SCRIPT_FINISHSCHED_AMBUSH: - pMonster->ChangeSchedule( pMonster->GetScheduleOfType( SCHED_AMBUSH ) ); - break; - default: - ALERT ( at_aiconsole, "FixScriptMonsterSchedule - no case!\n" ); - pMonster->ClearSchedule(); - break; - } -} - -BOOL CBaseMonster :: ExitScriptedSequence( ) -{ - if ( pev->deadflag == DEAD_DYING ) - { - // is this legal? - // BUGBUG -- This doesn't call Killed() - m_IdealMonsterState = MONSTERSTATE_DEAD; - return FALSE; - } - - if (m_pCine) - { - m_pCine->CancelScript( ); - } - - return TRUE; -} - - -void CCineMonster::AllowInterrupt( BOOL fAllow ) -{ - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - return; - m_interruptable = fAllow; -} - - -BOOL CCineMonster::CanInterrupt( void ) -{ - if ( !m_interruptable ) - return FALSE; - - CBaseEntity *pTarget = m_hTargetEnt; - - if ( pTarget != NULL && pTarget->pev->deadflag == DEAD_NO ) - return TRUE; - - return FALSE; -} - - -int CCineMonster::IgnoreConditions( void ) -{ - if ( CanInterrupt() ) - return 0; - return SCRIPT_BREAK_CONDITIONS; -} - - -void ScriptEntityCancel( edict_t *pentCine ) -{ - // make sure they are a scripted_sequence - if (FClassnameIs( pentCine, CLASSNAME )) - { - CCineMonster *pCineTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - // make sure they have a monster in mind for the script - CBaseEntity *pEntity = pCineTarget->m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if (pTarget) - { - // make sure their monster is actually playing a script - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) - { - // tell them do die - pTarget->m_scriptState = CCineMonster::SCRIPT_CLEANUP; - // do it now - pTarget->CineCleanup( ); - } - } - } -} - - -// find all the cinematic entities with my targetname and stop them from playing -void CCineMonster :: CancelScript( void ) -{ - ALERT( at_aiconsole, "Cancelling script: %s\n", STRING(m_iszPlay) ); - - if ( !pev->targetname ) - { - ScriptEntityCancel( edict() ); - return; - } - - edict_t *pentCineTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); - - while (!FNullEnt(pentCineTarget)) - { - ScriptEntityCancel( pentCineTarget ); - pentCineTarget = FIND_ENTITY_BY_TARGETNAME(pentCineTarget, STRING(pev->targetname)); - } -} - - -// find all the cinematic entities with my targetname and tell them to wait before starting -void CCineMonster :: DelayStart( int state ) -{ - edict_t *pentCine = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); - - while (!FNullEnt(pentCine)) - { - if (FClassnameIs( pentCine, "scripted_sequence" )) - { - CCineMonster *pTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - if (state) - { - pTarget->m_iDelay++; - } - else - { - pTarget->m_iDelay--; - if (pTarget->m_iDelay <= 0) - pTarget->m_startTime = gpGlobals->time + 0.05; - } - } - pentCine = FIND_ENTITY_BY_TARGETNAME(pentCine, STRING(pev->targetname)); - } -} - - - -// Find an entity that I'm interested in and precache the sounds he'll need in the sequence. -void CCineMonster :: Activate( void ) -{ - edict_t *pentTarget; - CBaseMonster *pTarget; - - // The entity name could be a target name or a classname - // Check the targetname - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - pTarget = NULL; - - while (!pTarget && !FNullEnt(pentTarget)) - { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) - { - pTarget = GetMonsterPointer( pentTarget ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - - // If no entity with that targetname, check the classname - if ( !pTarget ) - { - pentTarget = FIND_ENTITY_BY_CLASSNAME(NULL, STRING(m_iszEntity)); - while (!pTarget && !FNullEnt(pentTarget)) - { - pTarget = GetMonsterPointer( pentTarget ); - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - } - // Found a compatible entity - if ( pTarget ) - { - void *pmodel; - pmodel = GET_MODEL_PTR( pTarget->edict() ); - if ( pmodel ) - { - // Look through the event list for stuff to precache - SequencePrecache( pmodel, STRING( m_iszIdle ) ); - SequencePrecache( pmodel, STRING( m_iszPlay ) ); - } - } -} - - -BOOL CBaseMonster :: CineCleanup( ) -{ - CCineMonster *pOldCine = m_pCine; - - // am I linked to a cinematic? - if (m_pCine) - { - // okay, reset me to what it thought I was before - m_pCine->m_hTargetEnt = NULL; - pev->movetype = m_pCine->m_saved_movetype; - pev->solid = m_pCine->m_saved_solid; - pev->effects = m_pCine->m_saved_effects; - } - else - { - // arg, punt - pev->movetype = MOVETYPE_STEP;// this is evil - pev->solid = SOLID_SLIDEBOX; - } - m_pCine = NULL; - m_hTargetEnt = NULL; - m_pGoalEnt = NULL; - if (pev->deadflag == DEAD_DYING) - { - // last frame of death animation? - pev->health = 0; - pev->framerate = 0.0; - pev->solid = SOLID_NOT; - SetState( MONSTERSTATE_DEAD ); - pev->deadflag = DEAD_DEAD; - UTIL_SetSize( pev, pev->mins, Vector(pev->maxs.x, pev->maxs.y, pev->mins.z + 2) ); - - if ( pOldCine && FBitSet( pOldCine->pev->spawnflags, SF_SCRIPT_LEAVECORPSE ) ) - { - SetUse( NULL ); // BUGBUG -- This doesn't call Killed() - SetThink( NULL ); // This will probably break some stuff - SetTouch( NULL ); - } - else - SUB_StartFadeOut(); // SetThink( SUB_DoNothing ); - // This turns off animation & physics in case their origin ends up stuck in the world or something - StopAnimation(); - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NOINTERP; // Don't interpolate either, assume the corpse is positioned in its final resting place - return FALSE; - } - - // If we actually played a sequence - if ( pOldCine && pOldCine->m_iszPlay ) - { - if ( !(pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT) ) - { - // reset position - Vector new_origin, new_angle; - GetBonePosition( 0, new_origin, new_angle ); - - // Figure out how far they have moved - // We can't really solve this problem because we can't query the movement of the origin relative - // to the sequence. We can get the root bone's position as we do here, but there are - // cases where the root bone is in a different relative position to the entity's origin - // before/after the sequence plays. So we are stuck doing this: - - // !!!HACKHACK: Float the origin up and drop to floor because some sequences have - // irregular motion that can't be properly accounted for. - - // UNDONE: THIS SHOULD ONLY HAPPEN IF WE ACTUALLY PLAYED THE SEQUENCE. - Vector oldOrigin = pev->origin; - - // UNDONE: ugly hack. Don't move monster if they don't "seem" to move - // this really needs to be done with the AX,AY,etc. flags, but that aren't consistantly - // being set, so animations that really do move won't be caught. - if ((oldOrigin - new_origin).Length2D() < 8.0) - new_origin = oldOrigin; - - pev->origin.x = new_origin.x; - pev->origin.y = new_origin.y; - pev->origin.z += 1; - - pev->flags |= FL_ONGROUND; - int drop = DROP_TO_FLOOR( ENT(pev) ); - - // Origin in solid? Set to org at the end of the sequence - if ( drop < 0 ) - pev->origin = oldOrigin; - else if ( drop == 0 ) // Hanging in air? - { - pev->origin.z = new_origin.z; - pev->flags &= ~FL_ONGROUND; - } - // else entity hit floor, leave there - - // pEntity->pev->origin.z = new_origin.z + 5.0; // damn, got to fix this - - UTIL_SetOrigin( pev, pev->origin ); - pev->effects |= EF_NOINTERP; - } - - // We should have some animation to put these guys in, but for now it's idle. - // Due to NOINTERP above, there won't be any blending between this anim & the sequence - m_Activity = ACT_RESET; - } - // set them back into a normal state - pev->enemy = NULL; - if ( pev->health > 0 ) - m_IdealMonsterState = MONSTERSTATE_IDLE; // m_previousState; - else - { - // Dropping out because he got killed - // Can't call killed() no attacker and weirdness (late gibbing) may result - m_IdealMonsterState = MONSTERSTATE_DEAD; - SetConditions( bits_COND_LIGHT_DAMAGE ); - pev->deadflag = DEAD_DYING; - FCheckAITrigger(); - pev->deadflag = DEAD_NO; - } - - - // SetAnimation( m_MonsterState ); - ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); - - return TRUE; -} - - - - -class CScriptedSentence : public CBaseToggle -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT FindThink( void ); - void EXPORT DelayThink( void ); - int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - CBaseMonster *FindEntity( void ); - BOOL AcceptableSpeaker( CBaseMonster *pMonster ); - BOOL StartSentence( CBaseMonster *pTarget ); - - -private: - int m_iszSentence; // string index for idle animation - int m_iszEntity; // entity that is wanted for this sentence - float m_flRadius; // range to search - float m_flDuration; // How long the sentence lasts - float m_flRepeat; // repeat rate - float m_flAttenuation; - float m_flVolume; - BOOL m_active; - int m_iszListener; // name of entity to look at while talking -}; - -#define SF_SENTENCE_ONCE 0x0001 -#define SF_SENTENCE_FOLLOWERS 0x0002 // only say if following player -#define SF_SENTENCE_INTERRUPT 0x0004 // force talking except when dead -#define SF_SENTENCE_CONCURRENT 0x0008 // allow other people to keep talking - -TYPEDESCRIPTION CScriptedSentence::m_SaveData[] = -{ - DEFINE_FIELD( CScriptedSentence, m_iszSentence, FIELD_STRING ), - DEFINE_FIELD( CScriptedSentence, m_iszEntity, FIELD_STRING ), - DEFINE_FIELD( CScriptedSentence, m_flRadius, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flDuration, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flRepeat, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_active, FIELD_BOOLEAN ), - DEFINE_FIELD( CScriptedSentence, m_iszListener, FIELD_STRING ), -}; - - -IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ); - -LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ); - -void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sentence")) - { - m_iszSentence = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "entity")) - { - m_iszEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - m_flDuration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "refire")) - { - m_flRepeat = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if(FStrEq(pkvd->szKeyName, "attenuation")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if(FStrEq(pkvd->szKeyName, "volume")) - { - m_flVolume = atof( pkvd->szValue ) * 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "listener")) - { - m_iszListener = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - - -void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !m_active ) - return; -// ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); - SetThink( &CScriptedSentence::FindThink ); - pev->nextthink = gpGlobals->time; -} - - -void CScriptedSentence :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - - m_active = TRUE; - // if no targetname, start now - if ( !pev->targetname ) - { - SetThink( &CScriptedSentence::FindThink ); - pev->nextthink = gpGlobals->time + 1.0; - } - - switch( pev->impulse ) - { - case 1: // Medium radius - m_flAttenuation = ATTN_STATIC; - break; - - case 2: // Large radius - m_flAttenuation = ATTN_NORM; - break; - - case 3: //EVERYWHERE - m_flAttenuation = ATTN_NONE; - break; - - default: - case 0: // Small radius - m_flAttenuation = ATTN_IDLE; - break; - } - pev->impulse = 0; - - // No volume, use normal - if ( m_flVolume <= 0 ) - m_flVolume = 1.0; -} - - -void CScriptedSentence :: FindThink( void ) -{ - CBaseMonster *pMonster = FindEntity(); - if ( pMonster ) - { - StartSentence( pMonster ); - if ( pev->spawnflags & SF_SENTENCE_ONCE ) - UTIL_Remove( this ); - SetThink( &CScriptedSentence::DelayThink ); - pev->nextthink = gpGlobals->time + m_flDuration + m_flRepeat; - m_active = FALSE; -// ALERT( at_console, "%s: found monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); - } - else - { -// ALERT( at_console, "%s: can't find monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); - pev->nextthink = gpGlobals->time + m_flRepeat + 0.5; - } -} - - -void CScriptedSentence :: DelayThink( void ) -{ - m_active = TRUE; - if ( !pev->targetname ) - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CScriptedSentence::FindThink ); -} - - -BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) -{ - if ( pMonster ) - { - if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) - { - if ( pMonster->m_hTargetEnt == NULL || !FClassnameIs(pMonster->m_hTargetEnt->pev, "player") ) - return FALSE; - } - BOOL override; - if ( pev->spawnflags & SF_SENTENCE_INTERRUPT ) - override = TRUE; - else - override = FALSE; - if ( pMonster->CanPlaySentence( override ) ) - return TRUE; - } - return FALSE; -} - - -CBaseMonster *CScriptedSentence :: FindEntity( void ) -{ - edict_t *pentTarget; - CBaseMonster *pMonster; - - - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - pMonster = NULL; - - while (!FNullEnt(pentTarget)) - { - pMonster = GetMonsterPointer( pentTarget ); - if ( pMonster != NULL ) - { - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; -// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pMonster = pEntity->MyMonsterPointer( ); - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; - } - } - } - - return NULL; -} - - -BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) -{ - if ( !pTarget ) - { - ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING(m_iszSentence) ); - return NULL; - } - - BOOL bConcurrent = FALSE; - if ( !(pev->spawnflags & SF_SENTENCE_CONCURRENT) ) - bConcurrent = TRUE; - - CBaseEntity *pListener = NULL; - if (!FStringNull(m_iszListener)) - { - float radius = m_flRadius; - - if ( FStrEq( STRING(m_iszListener ), "player" ) ) - radius = 4096; // Always find the player - - pListener = UTIL_FindEntityGeneric( STRING( m_iszListener ), pTarget->pev->origin, radius ); - } - - pTarget->PlayScriptedSentence( STRING(m_iszSentence), m_flDuration, m_flVolume, m_flAttenuation, bConcurrent, pListener ); - ALERT( at_aiconsole, "Playing sentence %s (%.1f)\n", STRING(m_iszSentence), m_flDuration ); - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - return TRUE; -} - - - - - -/* - -*/ - - -#include "furniture.h" - -LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); - - -//========================================================= -// Furniture is killed -//========================================================= -void CFurniture :: Die ( void ) -{ - SetThink ( &CFurniture::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// This used to have something to do with bees flying, but -// now it only initializes moving furniture in scripted sequences -//========================================================= -void CFurniture :: Spawn( ) -{ - PRECACHE_MODEL((char *)STRING(pev->model)); - SET_MODEL(ENT(pev), STRING(pev->model)); - - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - pev->health = 80000; - pev->takedamage = DAMAGE_AIM; - pev->effects = 0; - pev->yaw_speed = 0; - pev->sequence = 0; - pev->frame = 0; - -// pev->nextthink += 1.0; -// SetThink (WalkMonsterDelay); - - ResetSequenceInfo( ); - pev->frame = 0; - MonsterInit(); -} - -//========================================================= -// ID's Furniture as neutral (noone will attack it) -//========================================================= -int CFurniture::Classify ( void ) -{ - return CLASS_NONE; -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +/* + + +===== scripted.cpp ======================================================== + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" + +#ifndef ANIMATION_H +#include "animation.h" +#endif + +#ifndef SAVERESTORE_H +#include "saverestore.h" +#endif + +#include "schedule.h" +#include "scripted.h" +#include "defaultai.h" + + + +/* +classname "scripted_sequence" +targetname "me" - there can be more than one with the same name, and they act in concert +target "the_entity_I_want_to_start_playing" or "class entity_classname" will pick the closest inactive scientist +play "name_of_sequence" +idle "name of idle sequence to play before starting" +donetrigger "whatever" - can be any other triggerable entity such as another sequence, train, door, or a special case like "die" or "remove" +moveto - if set the monster first moves to this nodes position +range # - only search this far to find the target +spawnflags - (stop if blocked, stop if player seen) +*/ + + +// +// Cache user-entity-field values until spawn is called. +// + +void CCineMonster :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "m_iszIdle")) + { + m_iszIdle = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_iszPlay")) + { + m_iszPlay = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_iszEntity")) + { + m_iszEntity = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_fMoveTo")) + { + m_fMoveTo = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_flRepeat")) + { + m_flRepeat = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_flRadius")) + { + m_flRadius = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_iFinishSchedule")) + { + m_iFinishSchedule = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + { + CBaseMonster::KeyValue( pkvd ); + } +} + +TYPEDESCRIPTION CCineMonster::m_SaveData[] = +{ + DEFINE_FIELD( CCineMonster, m_iszIdle, FIELD_STRING ), + DEFINE_FIELD( CCineMonster, m_iszPlay, FIELD_STRING ), + DEFINE_FIELD( CCineMonster, m_iszEntity, FIELD_STRING ), + DEFINE_FIELD( CCineMonster, m_fMoveTo, FIELD_INTEGER ), + DEFINE_FIELD( CCineMonster, m_flRepeat, FIELD_FLOAT ), + DEFINE_FIELD( CCineMonster, m_flRadius, FIELD_FLOAT ), + + DEFINE_FIELD( CCineMonster, m_iDelay, FIELD_INTEGER ), + DEFINE_FIELD( CCineMonster, m_startTime, FIELD_TIME ), + + DEFINE_FIELD( CCineMonster, m_saved_movetype, FIELD_INTEGER ), + DEFINE_FIELD( CCineMonster, m_saved_solid, FIELD_INTEGER ), + DEFINE_FIELD( CCineMonster, m_saved_effects, FIELD_INTEGER ), + DEFINE_FIELD( CCineMonster, m_iFinishSchedule, FIELD_INTEGER ), + DEFINE_FIELD( CCineMonster, m_interruptable, FIELD_BOOLEAN ), +}; + + +IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ); + +LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ); +#define CLASSNAME "scripted_sequence" + +LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ); + + +void CCineMonster :: Spawn( void ) +{ + // pev->solid = SOLID_TRIGGER; + // UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); + pev->solid = SOLID_NOT; + + + // REMOVE: The old side-effect +#if 0 + if ( m_iszIdle ) + m_fMoveTo = 4; +#endif + + // if no targetname, start now + if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) + { + SetThink( &CCineMonster::CineThink ); + pev->nextthink = gpGlobals->time + 1.0; + // Wait to be used? + if ( pev->targetname ) + m_startTime = gpGlobals->time + 1E6; + } + if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) + m_interruptable = FALSE; + else + m_interruptable = TRUE; +} + +//========================================================= +// FCanOverrideState - returns FALSE, scripted sequences +// cannot possess entities regardless of state. +//========================================================= +BOOL CCineMonster :: FCanOverrideState( void ) +{ + if ( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) + return TRUE; + return FALSE; +} + +//========================================================= +// FCanOverrideState - returns true because scripted AI can +// possess entities regardless of their state. +//========================================================= +BOOL CCineAI :: FCanOverrideState( void ) +{ + return TRUE; +} + + +// +// CineStart +// +void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // do I already know who I should use + CBaseEntity *pEntity = m_hTargetEnt; + CBaseMonster *pTarget = NULL; + + if ( pEntity ) + pTarget = pEntity->MyMonsterPointer(); + + if ( pTarget ) + { + // am I already playing the script? + if ( pTarget->m_scriptState == SCRIPT_PLAYING ) + return; + + m_startTime = gpGlobals->time + 0.05; + } + else + { + // if not, try finding them + SetThink( &CCineMonster::CineThink ); + pev->nextthink = gpGlobals->time; + } +} + + +// This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events +void CCineMonster :: Blocked( CBaseEntity *pOther ) +{ + +} + +void CCineMonster :: Touch( CBaseEntity *pOther ) +{ +/* + ALERT( at_aiconsole, "Cine Touch\n" ); + if (m_pentTarget && OFFSET(pOther->pev) == OFFSET(m_pentTarget)) + { + CBaseMonster *pTarget = GetClassPtr((CBaseMonster *)VARS(m_pentTarget)); + pTarget->m_monsterState == MONSTERSTATE_SCRIPT; + } +*/ +} + + +/* + entvars_t *pevOther = VARS( gpGlobals->other ); + + if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) + {// touched by a non-monster. + return; + } + + pevOther->origin.z += 1; + + if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) + {// clear the onground so physics don't bitch + pevOther->flags -= FL_ONGROUND; + } + + // toss the monster! + pevOther->velocity = pev->movedir * pev->speed; + pevOther->velocity.z += m_flHeight; + + + pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE +} +*/ + + +// +// ********** Cinematic DIE ********** +// +void CCineMonster :: Die( void ) +{ + SetThink( &CCineMonster::SUB_Remove ); +} + +// +// ********** Cinematic PAIN ********** +// +void CCineMonster :: Pain( void ) +{ + +} + +// +// ********** Cinematic Think ********** +// + +// find a viable entity +int CCineMonster :: FindEntity( void ) +{ + edict_t *pentTarget; + + pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); + m_hTargetEnt = NULL; + CBaseMonster *pTarget = NULL; + + while (!FNullEnt(pentTarget)) + { + if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) + { + pTarget = GetMonsterPointer( pentTarget ); + if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_BY_NAME ) ) + { + m_hTargetEnt = pTarget; + return TRUE; + } + ALERT( at_console, "Found %s, but can't play!\n", STRING(m_iszEntity) ); + } + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); + pTarget = NULL; + } + + if ( !pTarget ) + { + CBaseEntity *pEntity = NULL; + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) + { + if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) + { + if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) + { + pTarget = pEntity->MyMonsterPointer( ); + if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_IDLE ) ) + { + m_hTargetEnt = pTarget; + return TRUE; + } + } + } + } + } + pTarget = NULL; + m_hTargetEnt = NULL; + return FALSE; +} + +// make the entity enter a scripted sequence +void CCineMonster :: PossessEntity( void ) +{ + CBaseEntity *pEntity = m_hTargetEnt; + CBaseMonster *pTarget = NULL; + if ( pEntity ) + pTarget = pEntity->MyMonsterPointer(); + + if ( pTarget ) + { + + // FindEntity() just checked this! +#if 0 + if ( !pTarget->CanPlaySequence( FCanOverrideState() ) ) + { + ALERT( at_aiconsole, "Can't possess entity %s\n", STRING(pTarget->pev->classname) ); + return; + } +#endif + + pTarget->m_pGoalEnt = this; + pTarget->m_pCine = this; + pTarget->m_hTargetEnt = this; + + m_saved_movetype = pTarget->pev->movetype; + m_saved_solid = pTarget->pev->solid; + m_saved_effects = pTarget->pev->effects; + pTarget->pev->effects |= pev->effects; + + switch (m_fMoveTo) + { + case 0: + pTarget->m_scriptState = SCRIPT_WAIT; + break; + + case 1: + pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; + DelayStart( 1 ); + break; + + case 2: + pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; + DelayStart( 1 ); + break; + + case 4: + UTIL_SetOrigin( pTarget->pev, pev->origin ); + pTarget->pev->ideal_yaw = pev->angles.y; + pTarget->pev->avelocity = Vector( 0, 0, 0 ); + pTarget->pev->velocity = Vector( 0, 0, 0 ); + pTarget->pev->effects |= EF_NOINTERP; + pTarget->pev->angles.y = pev->angles.y; + pTarget->m_scriptState = SCRIPT_WAIT; + m_startTime = gpGlobals->time + 1E6; + // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters + // pTarget->pev->flags &= ~FL_ONGROUND; + break; + } +// ALERT( at_aiconsole, "\"%s\" found and used (INT: %s)\n", STRING( pTarget->pev->targetname ), FBitSet(pev->spawnflags, SF_SCRIPT_NOINTERRUPT)?"No":"Yes" ); + + pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; + if (m_iszIdle) + { + StartSequence( pTarget, m_iszIdle, FALSE ); + if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) + { + pTarget->pev->framerate = 0; + } + } + } +} + +// make the entity carry out the scripted sequence instructions, but without +// destroying the monster's state. +void CCineAI :: PossessEntity( void ) +{ + Schedule_t *pNewSchedule; + + CBaseEntity *pEntity = m_hTargetEnt; + CBaseMonster *pTarget = NULL; + if ( pEntity ) + pTarget = pEntity->MyMonsterPointer(); + + if ( pTarget ) + { + if ( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) + { + ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", STRING(pTarget->pev->classname) ); + return; + } + + pTarget->m_pGoalEnt = this; + pTarget->m_pCine = this; + pTarget->m_hTargetEnt = this; + + m_saved_movetype = pTarget->pev->movetype; + m_saved_solid = pTarget->pev->solid; + m_saved_effects = pTarget->pev->effects; + pTarget->pev->effects |= pev->effects; + + switch (m_fMoveTo) + { + case 0: + case 5: + pTarget->m_scriptState = SCRIPT_WAIT; + break; + + case 1: + pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; + break; + + case 2: + pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; + break; + + case 4: + // zap the monster instantly to the site of the script entity. + UTIL_SetOrigin( pTarget->pev, pev->origin ); + pTarget->pev->ideal_yaw = pev->angles.y; + pTarget->pev->avelocity = Vector( 0, 0, 0 ); + pTarget->pev->velocity = Vector( 0, 0, 0 ); + pTarget->pev->effects |= EF_NOINTERP; + pTarget->pev->angles.y = pev->angles.y; + pTarget->m_scriptState = SCRIPT_WAIT; + m_startTime = gpGlobals->time + 1E6; + // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters + pTarget->pev->flags &= ~FL_ONGROUND; + break; + default: + ALERT ( at_aiconsole, "aiscript: invalid Move To Position value!" ); + break; + } + + ALERT( at_aiconsole, "\"%s\" found and used\n", STRING( pTarget->pev->targetname ) ); + + pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; + +/* + if (m_iszIdle) + { + StartSequence( pTarget, m_iszIdle, FALSE ); + if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) + { + pTarget->pev->framerate = 0; + } + } +*/ + // Already in a scripted state? + if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) + { + pNewSchedule = pTarget->GetScheduleOfType( SCHED_AISCRIPT ); + pTarget->ChangeSchedule( pNewSchedule ); + } + } +} + +void CCineMonster :: CineThink( void ) +{ + if (FindEntity()) + { + PossessEntity( ); + ALERT( at_aiconsole, "script \"%s\" using monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); + } + else + { + CancelScript( ); + ALERT( at_aiconsole, "script \"%s\" can't find monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); + pev->nextthink = gpGlobals->time + 1.0; + } +} + + +// lookup a sequence name and setup the target monster to play it +BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) +{ + if ( !iszSeq && completeOnEmpty ) + { + SequenceDone( pTarget ); + return FALSE; + } + + pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); + if (pTarget->pev->sequence == -1) + { + ALERT( at_error, "%s: unknown scripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); + pTarget->pev->sequence = 0; + // return FALSE; + } + +#if 0 + char *s; + if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) + s = "No"; + else + s = "Yes"; + + ALERT( at_console, "%s (%s): started \"%s\":INT:%s\n", STRING( pTarget->pev->targetname ), STRING( pTarget->pev->classname ), STRING( iszSeq), s ); +#endif + + pTarget->pev->frame = 0; + pTarget->ResetSequenceInfo( ); + return TRUE; +} + +// lookup a sequence name and setup the target monster to play it +// overridden for CCineAI because it's ok for them to not have an animation sequence +// for the monster to play. For a regular Scripted Sequence, that situation is an error. +BOOL CCineAI :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) +{ + if ( iszSeq == 0 && completeOnEmpty ) + { + // no sequence was provided. Just let the monster proceed, however, we still have to fire any Sequence target + // and remove any non-repeatable CineAI entities here ( because there is code elsewhere that handles those tasks, but + // not until the animation sequence is finished. We have to manually take care of these things where there is no sequence. + + SequenceDone ( pTarget ); + + return TRUE; + } + + pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); + + if (pTarget->pev->sequence == -1) + { + ALERT( at_error, "%s: unknown aiscripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); + pTarget->pev->sequence = 0; + // return FALSE; + } + + pTarget->pev->frame = 0; + pTarget->ResetSequenceInfo( ); + return TRUE; +} + +//========================================================= +// SequenceDone - called when a scripted sequence animation +// sequence is done playing ( or when an AI Scripted Sequence +// doesn't supply an animation sequence to play ). Expects +// the CBaseMonster pointer to the monster that the sequence +// possesses. +//========================================================= +void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) +{ + //ALERT( at_aiconsole, "Sequence %s finished\n", STRING( m_pCine->m_iszPlay ) ); + + if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) + { + SetThink( &CCineMonster::SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + } + + // This is done so that another sequence can take over the monster when triggered by the first + + pMonster->CineCleanup(); + + FixScriptMonsterSchedule( pMonster ); + + // This may cause a sequence to attempt to grab this guy NOW, so we have to clear him out + // of the existing sequence + SUB_UseTargets( NULL, USE_TOGGLE, 0 ); +} + +//========================================================= +// When a monster finishes a scripted sequence, we have to +// fix up its state and schedule for it to return to a +// normal AI monster. +// +// Scripted sequences just dirty the Schedule and drop the +// monster in Idle State. +//========================================================= +void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) +{ + if ( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) + pMonster->m_IdealMonsterState = MONSTERSTATE_IDLE; + pMonster->ClearSchedule(); +} + +//========================================================= +// When a monster finishes a scripted sequence, we have to +// fix up its state and schedule for it to return to a +// normal AI monster. +// +// AI Scripted sequences will, depending on what the level +// designer selects: +// +// -Dirty the monster's schedule and drop out of the +// sequence in their current state. +// +// -Select a specific AMBUSH schedule, regardless of state. +//========================================================= +void CCineAI :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) +{ + switch ( m_iFinishSchedule ) + { + case SCRIPT_FINISHSCHED_DEFAULT: + pMonster->ClearSchedule(); + break; + case SCRIPT_FINISHSCHED_AMBUSH: + pMonster->ChangeSchedule( pMonster->GetScheduleOfType( SCHED_AMBUSH ) ); + break; + default: + ALERT ( at_aiconsole, "FixScriptMonsterSchedule - no case!\n" ); + pMonster->ClearSchedule(); + break; + } +} + +BOOL CBaseMonster :: ExitScriptedSequence( ) +{ + if ( pev->deadflag == DEAD_DYING ) + { + // is this legal? + // BUGBUG -- This doesn't call Killed() + m_IdealMonsterState = MONSTERSTATE_DEAD; + return FALSE; + } + + if (m_pCine) + { + m_pCine->CancelScript( ); + } + + return TRUE; +} + + +void CCineMonster::AllowInterrupt( BOOL fAllow ) +{ + if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) + return; + m_interruptable = fAllow; +} + + +BOOL CCineMonster::CanInterrupt( void ) +{ + if ( !m_interruptable ) + return FALSE; + + CBaseEntity *pTarget = m_hTargetEnt; + + if ( pTarget != NULL && pTarget->pev->deadflag == DEAD_NO ) + return TRUE; + + return FALSE; +} + + +int CCineMonster::IgnoreConditions( void ) +{ + if ( CanInterrupt() ) + return 0; + return SCRIPT_BREAK_CONDITIONS; +} + + +void ScriptEntityCancel( edict_t *pentCine ) +{ + // make sure they are a scripted_sequence + if (FClassnameIs( pentCine, CLASSNAME )) + { + CCineMonster *pCineTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); + // make sure they have a monster in mind for the script + CBaseEntity *pEntity = pCineTarget->m_hTargetEnt; + CBaseMonster *pTarget = NULL; + if ( pEntity ) + pTarget = pEntity->MyMonsterPointer(); + + if (pTarget) + { + // make sure their monster is actually playing a script + if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) + { + // tell them do die + pTarget->m_scriptState = CCineMonster::SCRIPT_CLEANUP; + // do it now + pTarget->CineCleanup( ); + } + } + } +} + + +// find all the cinematic entities with my targetname and stop them from playing +void CCineMonster :: CancelScript( void ) +{ + ALERT( at_aiconsole, "Cancelling script: %s\n", STRING(m_iszPlay) ); + + if ( !pev->targetname ) + { + ScriptEntityCancel( edict() ); + return; + } + + edict_t *pentCineTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); + + while (!FNullEnt(pentCineTarget)) + { + ScriptEntityCancel( pentCineTarget ); + pentCineTarget = FIND_ENTITY_BY_TARGETNAME(pentCineTarget, STRING(pev->targetname)); + } +} + + +// find all the cinematic entities with my targetname and tell them to wait before starting +void CCineMonster :: DelayStart( int state ) +{ + edict_t *pentCine = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); + + while (!FNullEnt(pentCine)) + { + if (FClassnameIs( pentCine, "scripted_sequence" )) + { + CCineMonster *pTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); + if (state) + { + pTarget->m_iDelay++; + } + else + { + pTarget->m_iDelay--; + if (pTarget->m_iDelay <= 0) + pTarget->m_startTime = gpGlobals->time + 0.05; + } + } + pentCine = FIND_ENTITY_BY_TARGETNAME(pentCine, STRING(pev->targetname)); + } +} + + + +// Find an entity that I'm interested in and precache the sounds he'll need in the sequence. +void CCineMonster :: Activate( void ) +{ + edict_t *pentTarget; + CBaseMonster *pTarget; + + // The entity name could be a target name or a classname + // Check the targetname + pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); + pTarget = NULL; + + while (!pTarget && !FNullEnt(pentTarget)) + { + if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) + { + pTarget = GetMonsterPointer( pentTarget ); + } + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); + } + + // If no entity with that targetname, check the classname + if ( !pTarget ) + { + pentTarget = FIND_ENTITY_BY_CLASSNAME(NULL, STRING(m_iszEntity)); + while (!pTarget && !FNullEnt(pentTarget)) + { + pTarget = GetMonsterPointer( pentTarget ); + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); + } + } + // Found a compatible entity + if ( pTarget ) + { + void *pmodel; + pmodel = GET_MODEL_PTR( pTarget->edict() ); + if ( pmodel ) + { + // Look through the event list for stuff to precache + SequencePrecache( pmodel, STRING( m_iszIdle ) ); + SequencePrecache( pmodel, STRING( m_iszPlay ) ); + } + } +} + + +BOOL CBaseMonster :: CineCleanup( ) +{ + CCineMonster *pOldCine = m_pCine; + + // am I linked to a cinematic? + if (m_pCine) + { + // okay, reset me to what it thought I was before + m_pCine->m_hTargetEnt = NULL; + pev->movetype = m_pCine->m_saved_movetype; + pev->solid = m_pCine->m_saved_solid; + pev->effects = m_pCine->m_saved_effects; + } + else + { + // arg, punt + pev->movetype = MOVETYPE_STEP;// this is evil + pev->solid = SOLID_SLIDEBOX; + } + m_pCine = NULL; + m_hTargetEnt = NULL; + m_pGoalEnt = NULL; + if (pev->deadflag == DEAD_DYING) + { + // last frame of death animation? + pev->health = 0; + pev->framerate = 0.0; + pev->solid = SOLID_NOT; + SetState( MONSTERSTATE_DEAD ); + pev->deadflag = DEAD_DEAD; + UTIL_SetSize( pev, pev->mins, Vector(pev->maxs.x, pev->maxs.y, pev->mins.z + 2) ); + + if ( pOldCine && FBitSet( pOldCine->pev->spawnflags, SF_SCRIPT_LEAVECORPSE ) ) + { + SetUse( NULL ); // BUGBUG -- This doesn't call Killed() + SetThink( NULL ); // This will probably break some stuff + SetTouch( NULL ); + } + else + SUB_StartFadeOut(); // SetThink( SUB_DoNothing ); + // This turns off animation & physics in case their origin ends up stuck in the world or something + StopAnimation(); + pev->movetype = MOVETYPE_NONE; + pev->effects |= EF_NOINTERP; // Don't interpolate either, assume the corpse is positioned in its final resting place + return FALSE; + } + + // If we actually played a sequence + if ( pOldCine && pOldCine->m_iszPlay ) + { + if ( !(pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT) ) + { + // reset position + Vector new_origin, new_angle; + GetBonePosition( 0, new_origin, new_angle ); + + // Figure out how far they have moved + // We can't really solve this problem because we can't query the movement of the origin relative + // to the sequence. We can get the root bone's position as we do here, but there are + // cases where the root bone is in a different relative position to the entity's origin + // before/after the sequence plays. So we are stuck doing this: + + // !!!HACKHACK: Float the origin up and drop to floor because some sequences have + // irregular motion that can't be properly accounted for. + + // UNDONE: THIS SHOULD ONLY HAPPEN IF WE ACTUALLY PLAYED THE SEQUENCE. + Vector oldOrigin = pev->origin; + + // UNDONE: ugly hack. Don't move monster if they don't "seem" to move + // this really needs to be done with the AX,AY,etc. flags, but that aren't consistantly + // being set, so animations that really do move won't be caught. + if ((oldOrigin - new_origin).Length2D() < 8.0) + new_origin = oldOrigin; + + pev->origin.x = new_origin.x; + pev->origin.y = new_origin.y; + pev->origin.z += 1; + + pev->flags |= FL_ONGROUND; + int drop = DROP_TO_FLOOR( ENT(pev) ); + + // Origin in solid? Set to org at the end of the sequence + if ( drop < 0 ) + pev->origin = oldOrigin; + else if ( drop == 0 ) // Hanging in air? + { + pev->origin.z = new_origin.z; + pev->flags &= ~FL_ONGROUND; + } + // else entity hit floor, leave there + + // pEntity->pev->origin.z = new_origin.z + 5.0; // damn, got to fix this + + UTIL_SetOrigin( pev, pev->origin ); + pev->effects |= EF_NOINTERP; + } + + // We should have some animation to put these guys in, but for now it's idle. + // Due to NOINTERP above, there won't be any blending between this anim & the sequence + m_Activity = ACT_RESET; + } + // set them back into a normal state + pev->enemy = NULL; + if ( pev->health > 0 ) + m_IdealMonsterState = MONSTERSTATE_IDLE; // m_previousState; + else + { + // Dropping out because he got killed + // Can't call killed() no attacker and weirdness (late gibbing) may result + m_IdealMonsterState = MONSTERSTATE_DEAD; + SetConditions( bits_COND_LIGHT_DAMAGE ); + pev->deadflag = DEAD_DYING; + FCheckAITrigger(); + pev->deadflag = DEAD_NO; + } + + + // SetAnimation( m_MonsterState ); + ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); + + return TRUE; +} + + + + +class CScriptedSentence : public CBaseToggle +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT FindThink( void ); + void EXPORT DelayThink( void ); + int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + CBaseMonster *FindEntity( void ); + BOOL AcceptableSpeaker( CBaseMonster *pMonster ); + BOOL StartSentence( CBaseMonster *pTarget ); + + +private: + int m_iszSentence; // string index for idle animation + int m_iszEntity; // entity that is wanted for this sentence + float m_flRadius; // range to search + float m_flDuration; // How long the sentence lasts + float m_flRepeat; // repeat rate + float m_flAttenuation; + float m_flVolume; + BOOL m_active; + int m_iszListener; // name of entity to look at while talking +}; + +#define SF_SENTENCE_ONCE 0x0001 +#define SF_SENTENCE_FOLLOWERS 0x0002 // only say if following player +#define SF_SENTENCE_INTERRUPT 0x0004 // force talking except when dead +#define SF_SENTENCE_CONCURRENT 0x0008 // allow other people to keep talking + +TYPEDESCRIPTION CScriptedSentence::m_SaveData[] = +{ + DEFINE_FIELD( CScriptedSentence, m_iszSentence, FIELD_STRING ), + DEFINE_FIELD( CScriptedSentence, m_iszEntity, FIELD_STRING ), + DEFINE_FIELD( CScriptedSentence, m_flRadius, FIELD_FLOAT ), + DEFINE_FIELD( CScriptedSentence, m_flDuration, FIELD_FLOAT ), + DEFINE_FIELD( CScriptedSentence, m_flRepeat, FIELD_FLOAT ), + DEFINE_FIELD( CScriptedSentence, m_flAttenuation, FIELD_FLOAT ), + DEFINE_FIELD( CScriptedSentence, m_flVolume, FIELD_FLOAT ), + DEFINE_FIELD( CScriptedSentence, m_active, FIELD_BOOLEAN ), + DEFINE_FIELD( CScriptedSentence, m_iszListener, FIELD_STRING ), +}; + + +IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ); + +LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ); + +void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "sentence")) + { + m_iszSentence = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "entity")) + { + m_iszEntity = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "duration")) + { + m_flDuration = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "radius")) + { + m_flRadius = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "refire")) + { + m_flRepeat = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if(FStrEq(pkvd->szKeyName, "attenuation")) + { + pev->impulse = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if(FStrEq(pkvd->szKeyName, "volume")) + { + m_flVolume = atof( pkvd->szValue ) * 0.1; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "listener")) + { + m_iszListener = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + + +void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !m_active ) + return; +// ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); + SetThink( &CScriptedSentence::FindThink ); + pev->nextthink = gpGlobals->time; +} + + +void CScriptedSentence :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + + m_active = TRUE; + // if no targetname, start now + if ( !pev->targetname ) + { + SetThink( &CScriptedSentence::FindThink ); + pev->nextthink = gpGlobals->time + 1.0; + } + + switch( pev->impulse ) + { + case 1: // Medium radius + m_flAttenuation = ATTN_STATIC; + break; + + case 2: // Large radius + m_flAttenuation = ATTN_NORM; + break; + + case 3: //EVERYWHERE + m_flAttenuation = ATTN_NONE; + break; + + default: + case 0: // Small radius + m_flAttenuation = ATTN_IDLE; + break; + } + pev->impulse = 0; + + // No volume, use normal + if ( m_flVolume <= 0 ) + m_flVolume = 1.0; +} + + +void CScriptedSentence :: FindThink( void ) +{ + CBaseMonster *pMonster = FindEntity(); + if ( pMonster ) + { + StartSentence( pMonster ); + if ( pev->spawnflags & SF_SENTENCE_ONCE ) + UTIL_Remove( this ); + SetThink( &CScriptedSentence::DelayThink ); + pev->nextthink = gpGlobals->time + m_flDuration + m_flRepeat; + m_active = FALSE; +// ALERT( at_console, "%s: found monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); + } + else + { +// ALERT( at_console, "%s: can't find monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); + pev->nextthink = gpGlobals->time + m_flRepeat + 0.5; + } +} + + +void CScriptedSentence :: DelayThink( void ) +{ + m_active = TRUE; + if ( !pev->targetname ) + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CScriptedSentence::FindThink ); +} + + +BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) +{ + if ( pMonster ) + { + if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) + { + if ( pMonster->m_hTargetEnt == NULL || !FClassnameIs(pMonster->m_hTargetEnt->pev, "player") ) + return FALSE; + } + BOOL override; + if ( pev->spawnflags & SF_SENTENCE_INTERRUPT ) + override = TRUE; + else + override = FALSE; + if ( pMonster->CanPlaySentence( override ) ) + return TRUE; + } + return FALSE; +} + + +CBaseMonster *CScriptedSentence :: FindEntity( void ) +{ + edict_t *pentTarget; + CBaseMonster *pMonster; + + + pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); + pMonster = NULL; + + while (!FNullEnt(pentTarget)) + { + pMonster = GetMonsterPointer( pentTarget ); + if ( pMonster != NULL ) + { + if ( AcceptableSpeaker( pMonster ) ) + return pMonster; +// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); + } + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); + } + + CBaseEntity *pEntity = NULL; + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) + { + if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) + { + if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) + { + pMonster = pEntity->MyMonsterPointer( ); + if ( AcceptableSpeaker( pMonster ) ) + return pMonster; + } + } + } + + return NULL; +} + + +BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) +{ + if ( !pTarget ) + { + ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING(m_iszSentence) ); + return NULL; + } + + BOOL bConcurrent = FALSE; + if ( !(pev->spawnflags & SF_SENTENCE_CONCURRENT) ) + bConcurrent = TRUE; + + CBaseEntity *pListener = NULL; + if (!FStringNull(m_iszListener)) + { + float radius = m_flRadius; + + if ( FStrEq( STRING(m_iszListener ), "player" ) ) + radius = 4096; // Always find the player + + pListener = UTIL_FindEntityGeneric( STRING( m_iszListener ), pTarget->pev->origin, radius ); + } + + pTarget->PlayScriptedSentence( STRING(m_iszSentence), m_flDuration, m_flVolume, m_flAttenuation, bConcurrent, pListener ); + ALERT( at_aiconsole, "Playing sentence %s (%.1f)\n", STRING(m_iszSentence), m_flDuration ); + SUB_UseTargets( NULL, USE_TOGGLE, 0 ); + return TRUE; +} + + + + + +/* + +*/ + + +#include "furniture.h" + +LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); + + +//========================================================= +// Furniture is killed +//========================================================= +void CFurniture :: Die ( void ) +{ + SetThink ( &CFurniture::SUB_Remove ); + pev->nextthink = gpGlobals->time; +} + +//========================================================= +// This used to have something to do with bees flying, but +// now it only initializes moving furniture in scripted sequences +//========================================================= +void CFurniture :: Spawn( ) +{ + PRECACHE_MODEL((char *)STRING(pev->model)); + SET_MODEL(ENT(pev), STRING(pev->model)); + + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_BBOX; + pev->health = 80000; + pev->takedamage = DAMAGE_AIM; + pev->effects = 0; + pev->yaw_speed = 0; + pev->sequence = 0; + pev->frame = 0; + +// pev->nextthink += 1.0; +// SetThink (WalkMonsterDelay); + + ResetSequenceInfo( ); + pev->frame = 0; + MonsterInit(); +} + +//========================================================= +// ID's Furniture as neutral (noone will attack it) +//========================================================= +int CFurniture::Classify ( void ) +{ + return CLASS_NONE; +} + + diff --git a/main/source/dlls/scripted.cpp~ b/main/source/dlls/scripted.cpp~ deleted file mode 100644 index 9ce2db02..00000000 --- a/main/source/dlls/scripted.cpp~ +++ /dev/null @@ -1,1249 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - - -===== scripted.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" - -#ifndef ANIMATION_H -#include "animation.h" -#endif - -#ifndef SAVERESTORE_H -#include "saverestore.h" -#endif - -#include "schedule.h" -#include "scripted.h" -#include "defaultai.h" - - - -/* -classname "scripted_sequence" -targetname "me" - there can be more than one with the same name, and they act in concert -target "the_entity_I_want_to_start_playing" or "class entity_classname" will pick the closest inactive scientist -play "name_of_sequence" -idle "name of idle sequence to play before starting" -donetrigger "whatever" - can be any other triggerable entity such as another sequence, train, door, or a special case like "die" or "remove" -moveto - if set the monster first moves to this nodes position -range # - only search this far to find the target -spawnflags - (stop if blocked, stop if player seen) -*/ - - -// -// Cache user-entity-field values until spawn is called. -// - -void CCineMonster :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszIdle")) - { - m_iszIdle = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszPlay")) - { - m_iszPlay = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszEntity")) - { - m_iszEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fMoveTo")) - { - m_fMoveTo = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flRepeat")) - { - m_flRepeat = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flRadius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iFinishSchedule")) - { - m_iFinishSchedule = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseMonster::KeyValue( pkvd ); - } -} - -TYPEDESCRIPTION CCineMonster::m_SaveData[] = -{ - DEFINE_FIELD( CCineMonster, m_iszIdle, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_iszPlay, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_iszEntity, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_fMoveTo, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_flRepeat, FIELD_FLOAT ), - DEFINE_FIELD( CCineMonster, m_flRadius, FIELD_FLOAT ), - - DEFINE_FIELD( CCineMonster, m_iDelay, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_startTime, FIELD_TIME ), - - DEFINE_FIELD( CCineMonster, m_saved_movetype, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_saved_solid, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_saved_effects, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_iFinishSchedule, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_interruptable, FIELD_BOOLEAN ), -}; - - -IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ); - -LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ); -#define CLASSNAME "scripted_sequence" - -LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ); - - -void CCineMonster :: Spawn( void ) -{ - // pev->solid = SOLID_TRIGGER; - // UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - pev->solid = SOLID_NOT; - - - // REMOVE: The old side-effect -#if 0 - if ( m_iszIdle ) - m_fMoveTo = 4; -#endif - - // if no targetname, start now - if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) - { - SetThink( &CCineMonster::CineThink ); - pev->nextthink = gpGlobals->time + 1.0; - // Wait to be used? - if ( pev->targetname ) - m_startTime = gpGlobals->time + 1E6; - } - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - m_interruptable = FALSE; - else - m_interruptable = TRUE; -} - -//========================================================= -// FCanOverrideState - returns FALSE, scripted sequences -// cannot possess entities regardless of state. -//========================================================= -BOOL CCineMonster :: FCanOverrideState( void ) -{ - if ( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) - return TRUE; - return FALSE; -} - -//========================================================= -// FCanOverrideState - returns true because scripted AI can -// possess entities regardless of their state. -//========================================================= -BOOL CCineAI :: FCanOverrideState( void ) -{ - return TRUE; -} - - -// -// CineStart -// -void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // do I already know who I should use - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - // am I already playing the script? - if ( pTarget->m_scriptState == SCRIPT_PLAYING ) - return; - - m_startTime = gpGlobals->time + 0.05; - } - else - { - // if not, try finding them - SetThink( &CCineMonster::CineThink ); - pev->nextthink = gpGlobals->time; - } -} - - -// This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events -void CCineMonster :: Blocked( CBaseEntity *pOther ) -{ - -} - -void CCineMonster :: Touch( CBaseEntity *pOther ) -{ -/* - ALERT( at_aiconsole, "Cine Touch\n" ); - if (m_pentTarget && OFFSET(pOther->pev) == OFFSET(m_pentTarget)) - { - CBaseMonster *pTarget = GetClassPtr((CBaseMonster *)VARS(m_pentTarget)); - pTarget->m_monsterState == MONSTERSTATE_SCRIPT; - } -*/ -} - - -/* - entvars_t *pevOther = VARS( gpGlobals->other ); - - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-monster. - return; - } - - pevOther->origin.z += 1; - - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) - {// clear the onground so physics don't bitch - pevOther->flags -= FL_ONGROUND; - } - - // toss the monster! - pevOther->velocity = pev->movedir * pev->speed; - pevOther->velocity.z += m_flHeight; - - - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE -} -*/ - - -// -// ********** Cinematic DIE ********** -// -void CCineMonster :: Die( void ) -{ - SetThink( &CCineMonster::SUB_Remove ); -} - -// -// ********** Cinematic PAIN ********** -// -void CCineMonster :: Pain( void ) -{ - -} - -// -// ********** Cinematic Think ********** -// - -// find a viable entity -int CCineMonster :: FindEntity( void ) -{ - edict_t *pentTarget; - - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - m_hTargetEnt = NULL; - CBaseMonster *pTarget = NULL; - - while (!FNullEnt(pentTarget)) - { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) - { - pTarget = GetMonsterPointer( pentTarget ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_BY_NAME ) ) - { - m_hTargetEnt = pTarget; - return TRUE; - } - ALERT( at_console, "Found %s, but can't play!\n", STRING(m_iszEntity) ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - pTarget = NULL; - } - - if ( !pTarget ) - { - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pTarget = pEntity->MyMonsterPointer( ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_IDLE ) ) - { - m_hTargetEnt = pTarget; - return TRUE; - } - } - } - } - } - pTarget = NULL; - m_hTargetEnt = NULL; - return FALSE; -} - -// make the entity enter a scripted sequence -void CCineMonster :: PossessEntity( void ) -{ - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - - // FindEntity() just checked this! -#if 0 - if ( !pTarget->CanPlaySequence( FCanOverrideState() ) ) - { - ALERT( at_aiconsole, "Can't possess entity %s\n", STRING(pTarget->pev->classname) ); - return; - } -#endif - - pTarget->m_pGoalEnt = this; - pTarget->m_pCine = this; - pTarget->m_hTargetEnt = this; - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - - switch (m_fMoveTo) - { - case 0: - pTarget->m_scriptState = SCRIPT_WAIT; - break; - - case 1: - pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; - DelayStart( 1 ); - break; - - case 2: - pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; - DelayStart( 1 ); - break; - - case 4: - UTIL_SetOrigin( pTarget->pev, pev->origin ); - pTarget->pev->ideal_yaw = pev->angles.y; - pTarget->pev->avelocity = Vector( 0, 0, 0 ); - pTarget->pev->velocity = Vector( 0, 0, 0 ); - pTarget->pev->effects |= EF_NOINTERP; - pTarget->pev->angles.y = pev->angles.y; - pTarget->m_scriptState = SCRIPT_WAIT; - m_startTime = gpGlobals->time + 1E6; - // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters - // pTarget->pev->flags &= ~FL_ONGROUND; - break; - } -// ALERT( at_aiconsole, "\"%s\" found and used (INT: %s)\n", STRING( pTarget->pev->targetname ), FBitSet(pev->spawnflags, SF_SCRIPT_NOINTERRUPT)?"No":"Yes" ); - - pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; - if (m_iszIdle) - { - StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) - { - pTarget->pev->framerate = 0; - } - } - } -} - -// make the entity carry out the scripted sequence instructions, but without -// destroying the monster's state. -void CCineAI :: PossessEntity( void ) -{ - Schedule_t *pNewSchedule; - - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - if ( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) - { - ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", STRING(pTarget->pev->classname) ); - return; - } - - pTarget->m_pGoalEnt = this; - pTarget->m_pCine = this; - pTarget->m_hTargetEnt = this; - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - - switch (m_fMoveTo) - { - case 0: - case 5: - pTarget->m_scriptState = SCRIPT_WAIT; - break; - - case 1: - pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; - break; - - case 2: - pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; - break; - - case 4: - // zap the monster instantly to the site of the script entity. - UTIL_SetOrigin( pTarget->pev, pev->origin ); - pTarget->pev->ideal_yaw = pev->angles.y; - pTarget->pev->avelocity = Vector( 0, 0, 0 ); - pTarget->pev->velocity = Vector( 0, 0, 0 ); - pTarget->pev->effects |= EF_NOINTERP; - pTarget->pev->angles.y = pev->angles.y; - pTarget->m_scriptState = SCRIPT_WAIT; - m_startTime = gpGlobals->time + 1E6; - // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters - pTarget->pev->flags &= ~FL_ONGROUND; - break; - default: - ALERT ( at_aiconsole, "aiscript: invalid Move To Position value!" ); - break; - } - - ALERT( at_aiconsole, "\"%s\" found and used\n", STRING( pTarget->pev->targetname ) ); - - pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; - -/* - if (m_iszIdle) - { - StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) - { - pTarget->pev->framerate = 0; - } - } -*/ - // Already in a scripted state? - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pNewSchedule = pTarget->GetScheduleOfType( SCHED_AISCRIPT ); - pTarget->ChangeSchedule( pNewSchedule ); - } - } -} - -void CCineMonster :: CineThink( void ) -{ - if (FindEntity()) - { - PossessEntity( ); - ALERT( at_aiconsole, "script \"%s\" using monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - } - else - { - CancelScript( ); - ALERT( at_aiconsole, "script \"%s\" can't find monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - pev->nextthink = gpGlobals->time + 1.0; - } -} - - -// lookup a sequence name and setup the target monster to play it -BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ - if ( !iszSeq && completeOnEmpty ) - { - SequenceDone( pTarget ); - return FALSE; - } - - pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - if (pTarget->pev->sequence == -1) - { - ALERT( at_error, "%s: unknown scripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); - pTarget->pev->sequence = 0; - // return FALSE; - } - -#if 0 - char *s; - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - s = "No"; - else - s = "Yes"; - - ALERT( at_console, "%s (%s): started \"%s\":INT:%s\n", STRING( pTarget->pev->targetname ), STRING( pTarget->pev->classname ), STRING( iszSeq), s ); -#endif - - pTarget->pev->frame = 0; - pTarget->ResetSequenceInfo( ); - return TRUE; -} - -// lookup a sequence name and setup the target monster to play it -// overridden for CCineAI because it's ok for them to not have an animation sequence -// for the monster to play. For a regular Scripted Sequence, that situation is an error. -BOOL CCineAI :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ - if ( iszSeq == 0 && completeOnEmpty ) - { - // no sequence was provided. Just let the monster proceed, however, we still have to fire any Sequence target - // and remove any non-repeatable CineAI entities here ( because there is code elsewhere that handles those tasks, but - // not until the animation sequence is finished. We have to manually take care of these things where there is no sequence. - - SequenceDone ( pTarget ); - - return TRUE; - } - - pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - - if (pTarget->pev->sequence == -1) - { - ALERT( at_error, "%s: unknown aiscripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); - pTarget->pev->sequence = 0; - // return FALSE; - } - - pTarget->pev->frame = 0; - pTarget->ResetSequenceInfo( ); - return TRUE; -} - -//========================================================= -// SequenceDone - called when a scripted sequence animation -// sequence is done playing ( or when an AI Scripted Sequence -// doesn't supply an animation sequence to play ). Expects -// the CBaseMonster pointer to the monster that the sequence -// possesses. -//========================================================= -void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) -{ - //ALERT( at_aiconsole, "Sequence %s finished\n", STRING( m_pCine->m_iszPlay ) ); - - if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) - { - SetThink( &CCineMonster::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - } - - // This is done so that another sequence can take over the monster when triggered by the first - - pMonster->CineCleanup(); - - FixScriptMonsterSchedule( pMonster ); - - // This may cause a sequence to attempt to grab this guy NOW, so we have to clear him out - // of the existing sequence - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); -} - -//========================================================= -// When a monster finishes a scripted sequence, we have to -// fix up its state and schedule for it to return to a -// normal AI monster. -// -// Scripted sequences just dirty the Schedule and drop the -// monster in Idle State. -//========================================================= -void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - if ( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) - pMonster->m_IdealMonsterState = MONSTERSTATE_IDLE; - pMonster->ClearSchedule(); -} - -//========================================================= -// When a monster finishes a scripted sequence, we have to -// fix up its state and schedule for it to return to a -// normal AI monster. -// -// AI Scripted sequences will, depending on what the level -// designer selects: -// -// -Dirty the monster's schedule and drop out of the -// sequence in their current state. -// -// -Select a specific AMBUSH schedule, regardless of state. -//========================================================= -void CCineAI :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - switch ( m_iFinishSchedule ) - { - case SCRIPT_FINISHSCHED_DEFAULT: - pMonster->ClearSchedule(); - break; - case SCRIPT_FINISHSCHED_AMBUSH: - pMonster->ChangeSchedule( pMonster->GetScheduleOfType( SCHED_AMBUSH ) ); - break; - default: - ALERT ( at_aiconsole, "FixScriptMonsterSchedule - no case!\n" ); - pMonster->ClearSchedule(); - break; - } -} - -BOOL CBaseMonster :: ExitScriptedSequence( ) -{ - if ( pev->deadflag == DEAD_DYING ) - { - // is this legal? - // BUGBUG -- This doesn't call Killed() - m_IdealMonsterState = MONSTERSTATE_DEAD; - return FALSE; - } - - if (m_pCine) - { - m_pCine->CancelScript( ); - } - - return TRUE; -} - - -void CCineMonster::AllowInterrupt( BOOL fAllow ) -{ - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - return; - m_interruptable = fAllow; -} - - -BOOL CCineMonster::CanInterrupt( void ) -{ - if ( !m_interruptable ) - return FALSE; - - CBaseEntity *pTarget = m_hTargetEnt; - - if ( pTarget != NULL && pTarget->pev->deadflag == DEAD_NO ) - return TRUE; - - return FALSE; -} - - -int CCineMonster::IgnoreConditions( void ) -{ - if ( CanInterrupt() ) - return 0; - return SCRIPT_BREAK_CONDITIONS; -} - - -void ScriptEntityCancel( edict_t *pentCine ) -{ - // make sure they are a scripted_sequence - if (FClassnameIs( pentCine, CLASSNAME )) - { - CCineMonster *pCineTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - // make sure they have a monster in mind for the script - CBaseEntity *pEntity = pCineTarget->m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if (pTarget) - { - // make sure their monster is actually playing a script - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) - { - // tell them do die - pTarget->m_scriptState = CCineMonster::SCRIPT_CLEANUP; - // do it now - pTarget->CineCleanup( ); - } - } - } -} - - -// find all the cinematic entities with my targetname and stop them from playing -void CCineMonster :: CancelScript( void ) -{ - ALERT( at_aiconsole, "Cancelling script: %s\n", STRING(m_iszPlay) ); - - if ( !pev->targetname ) - { - ScriptEntityCancel( edict() ); - return; - } - - edict_t *pentCineTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); - - while (!FNullEnt(pentCineTarget)) - { - ScriptEntityCancel( pentCineTarget ); - pentCineTarget = FIND_ENTITY_BY_TARGETNAME(pentCineTarget, STRING(pev->targetname)); - } -} - - -// find all the cinematic entities with my targetname and tell them to wait before starting -void CCineMonster :: DelayStart( int state ) -{ - edict_t *pentCine = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); - - while (!FNullEnt(pentCine)) - { - if (FClassnameIs( pentCine, "scripted_sequence" )) - { - CCineMonster *pTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - if (state) - { - pTarget->m_iDelay++; - } - else - { - pTarget->m_iDelay--; - if (pTarget->m_iDelay <= 0) - pTarget->m_startTime = gpGlobals->time + 0.05; - } - } - pentCine = FIND_ENTITY_BY_TARGETNAME(pentCine, STRING(pev->targetname)); - } -} - - - -// Find an entity that I'm interested in and precache the sounds he'll need in the sequence. -void CCineMonster :: Activate( void ) -{ - edict_t *pentTarget; - CBaseMonster *pTarget; - - // The entity name could be a target name or a classname - // Check the targetname - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - pTarget = NULL; - - while (!pTarget && !FNullEnt(pentTarget)) - { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) - { - pTarget = GetMonsterPointer( pentTarget ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - - // If no entity with that targetname, check the classname - if ( !pTarget ) - { - pentTarget = FIND_ENTITY_BY_CLASSNAME(NULL, STRING(m_iszEntity)); - while (!pTarget && !FNullEnt(pentTarget)) - { - pTarget = GetMonsterPointer( pentTarget ); - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - } - // Found a compatible entity - if ( pTarget ) - { - void *pmodel; - pmodel = GET_MODEL_PTR( pTarget->edict() ); - if ( pmodel ) - { - // Look through the event list for stuff to precache - SequencePrecache( pmodel, STRING( m_iszIdle ) ); - SequencePrecache( pmodel, STRING( m_iszPlay ) ); - } - } -} - - -BOOL CBaseMonster :: CineCleanup( ) -{ - CCineMonster *pOldCine = m_pCine; - - // am I linked to a cinematic? - if (m_pCine) - { - // okay, reset me to what it thought I was before - m_pCine->m_hTargetEnt = NULL; - pev->movetype = m_pCine->m_saved_movetype; - pev->solid = m_pCine->m_saved_solid; - pev->effects = m_pCine->m_saved_effects; - } - else - { - // arg, punt - pev->movetype = MOVETYPE_STEP;// this is evil - pev->solid = SOLID_SLIDEBOX; - } - m_pCine = NULL; - m_hTargetEnt = NULL; - m_pGoalEnt = NULL; - if (pev->deadflag == DEAD_DYING) - { - // last frame of death animation? - pev->health = 0; - pev->framerate = 0.0; - pev->solid = SOLID_NOT; - SetState( MONSTERSTATE_DEAD ); - pev->deadflag = DEAD_DEAD; - UTIL_SetSize( pev, pev->mins, Vector(pev->maxs.x, pev->maxs.y, pev->mins.z + 2) ); - - if ( pOldCine && FBitSet( pOldCine->pev->spawnflags, SF_SCRIPT_LEAVECORPSE ) ) - { - SetUse( NULL ); // BUGBUG -- This doesn't call Killed() - SetThink( NULL ); // This will probably break some stuff - SetTouch( NULL ); - } - else - SUB_StartFadeOut(); // SetThink( SUB_DoNothing ); - // This turns off animation & physics in case their origin ends up stuck in the world or something - StopAnimation(); - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NOINTERP; // Don't interpolate either, assume the corpse is positioned in its final resting place - return FALSE; - } - - // If we actually played a sequence - if ( pOldCine && pOldCine->m_iszPlay ) - { - if ( !(pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT) ) - { - // reset position - Vector new_origin, new_angle; - GetBonePosition( 0, new_origin, new_angle ); - - // Figure out how far they have moved - // We can't really solve this problem because we can't query the movement of the origin relative - // to the sequence. We can get the root bone's position as we do here, but there are - // cases where the root bone is in a different relative position to the entity's origin - // before/after the sequence plays. So we are stuck doing this: - - // !!!HACKHACK: Float the origin up and drop to floor because some sequences have - // irregular motion that can't be properly accounted for. - - // UNDONE: THIS SHOULD ONLY HAPPEN IF WE ACTUALLY PLAYED THE SEQUENCE. - Vector oldOrigin = pev->origin; - - // UNDONE: ugly hack. Don't move monster if they don't "seem" to move - // this really needs to be done with the AX,AY,etc. flags, but that aren't consistantly - // being set, so animations that really do move won't be caught. - if ((oldOrigin - new_origin).Length2D() < 8.0) - new_origin = oldOrigin; - - pev->origin.x = new_origin.x; - pev->origin.y = new_origin.y; - pev->origin.z += 1; - - pev->flags |= FL_ONGROUND; - int drop = DROP_TO_FLOOR( ENT(pev) ); - - // Origin in solid? Set to org at the end of the sequence - if ( drop < 0 ) - pev->origin = oldOrigin; - else if ( drop == 0 ) // Hanging in air? - { - pev->origin.z = new_origin.z; - pev->flags &= ~FL_ONGROUND; - } - // else entity hit floor, leave there - - // pEntity->pev->origin.z = new_origin.z + 5.0; // damn, got to fix this - - UTIL_SetOrigin( pev, pev->origin ); - pev->effects |= EF_NOINTERP; - } - - // We should have some animation to put these guys in, but for now it's idle. - // Due to NOINTERP above, there won't be any blending between this anim & the sequence - m_Activity = ACT_RESET; - } - // set them back into a normal state - pev->enemy = NULL; - if ( pev->health > 0 ) - m_IdealMonsterState = MONSTERSTATE_IDLE; // m_previousState; - else - { - // Dropping out because he got killed - // Can't call killed() no attacker and weirdness (late gibbing) may result - m_IdealMonsterState = MONSTERSTATE_DEAD; - SetConditions( bits_COND_LIGHT_DAMAGE ); - pev->deadflag = DEAD_DYING; - FCheckAITrigger(); - pev->deadflag = DEAD_NO; - } - - - // SetAnimation( m_MonsterState ); - ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); - - return TRUE; -} - - - - -class CScriptedSentence : public CBaseToggle -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT FindThink( void ); - void EXPORT DelayThink( void ); - int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - CBaseMonster *FindEntity( void ); - BOOL AcceptableSpeaker( CBaseMonster *pMonster ); - BOOL StartSentence( CBaseMonster *pTarget ); - - -private: - int m_iszSentence; // string index for idle animation - int m_iszEntity; // entity that is wanted for this sentence - float m_flRadius; // range to search - float m_flDuration; // How long the sentence lasts - float m_flRepeat; // repeat rate - float m_flAttenuation; - float m_flVolume; - BOOL m_active; - int m_iszListener; // name of entity to look at while talking -}; - -#define SF_SENTENCE_ONCE 0x0001 -#define SF_SENTENCE_FOLLOWERS 0x0002 // only say if following player -#define SF_SENTENCE_INTERRUPT 0x0004 // force talking except when dead -#define SF_SENTENCE_CONCURRENT 0x0008 // allow other people to keep talking - -TYPEDESCRIPTION CScriptedSentence::m_SaveData[] = -{ - DEFINE_FIELD( CScriptedSentence, m_iszSentence, FIELD_STRING ), - DEFINE_FIELD( CScriptedSentence, m_iszEntity, FIELD_STRING ), - DEFINE_FIELD( CScriptedSentence, m_flRadius, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flDuration, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flRepeat, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_active, FIELD_BOOLEAN ), - DEFINE_FIELD( CScriptedSentence, m_iszListener, FIELD_STRING ), -}; - - -IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ); - -LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ); - -void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sentence")) - { - m_iszSentence = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "entity")) - { - m_iszEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - m_flDuration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "refire")) - { - m_flRepeat = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if(FStrEq(pkvd->szKeyName, "attenuation")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if(FStrEq(pkvd->szKeyName, "volume")) - { - m_flVolume = atof( pkvd->szValue ) * 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "listener")) - { - m_iszListener = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - - -void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !m_active ) - return; -// ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); - SetThink( &CScriptedSentence::FindThink ); - pev->nextthink = gpGlobals->time; -} - - -void CScriptedSentence :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - - m_active = TRUE; - // if no targetname, start now - if ( !pev->targetname ) - { - SetThink( &CScriptedSentence::FindThink ); - pev->nextthink = gpGlobals->time + 1.0; - } - - switch( pev->impulse ) - { - case 1: // Medium radius - m_flAttenuation = ATTN_STATIC; - break; - - case 2: // Large radius - m_flAttenuation = ATTN_NORM; - break; - - case 3: //EVERYWHERE - m_flAttenuation = ATTN_NONE; - break; - - default: - case 0: // Small radius - m_flAttenuation = ATTN_IDLE; - break; - } - pev->impulse = 0; - - // No volume, use normal - if ( m_flVolume <= 0 ) - m_flVolume = 1.0; -} - - -void CScriptedSentence :: FindThink( void ) -{ - CBaseMonster *pMonster = FindEntity(); - if ( pMonster ) - { - StartSentence( pMonster ); - if ( pev->spawnflags & SF_SENTENCE_ONCE ) - UTIL_Remove( this ); - SetThink( &CScriptedSentence::DelayThink ); - pev->nextthink = gpGlobals->time + m_flDuration + m_flRepeat; - m_active = FALSE; -// ALERT( at_console, "%s: found monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); - } - else - { -// ALERT( at_console, "%s: can't find monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); - pev->nextthink = gpGlobals->time + m_flRepeat + 0.5; - } -} - - -void CScriptedSentence :: DelayThink( void ) -{ - m_active = TRUE; - if ( !pev->targetname ) - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CScriptedSentence::FindThink ); -} - - -BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) -{ - if ( pMonster ) - { - if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) - { - if ( pMonster->m_hTargetEnt == NULL || !FClassnameIs(pMonster->m_hTargetEnt->pev, "player") ) - return FALSE; - } - BOOL override; - if ( pev->spawnflags & SF_SENTENCE_INTERRUPT ) - override = TRUE; - else - override = FALSE; - if ( pMonster->CanPlaySentence( override ) ) - return TRUE; - } - return FALSE; -} - - -CBaseMonster *CScriptedSentence :: FindEntity( void ) -{ - edict_t *pentTarget; - CBaseMonster *pMonster; - - - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - pMonster = NULL; - - while (!FNullEnt(pentTarget)) - { - pMonster = GetMonsterPointer( pentTarget ); - if ( pMonster != NULL ) - { - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; -// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pMonster = pEntity->MyMonsterPointer( ); - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; - } - } - } - - return NULL; -} - - -BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) -{ - if ( !pTarget ) - { - ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING(m_iszSentence) ); - return NULL; - } - - BOOL bConcurrent = FALSE; - if ( !(pev->spawnflags & SF_SENTENCE_CONCURRENT) ) - bConcurrent = TRUE; - - CBaseEntity *pListener = NULL; - if (!FStringNull(m_iszListener)) - { - float radius = m_flRadius; - - if ( FStrEq( STRING(m_iszListener ), "player" ) ) - radius = 4096; // Always find the player - - pListener = UTIL_FindEntityGeneric( STRING( m_iszListener ), pTarget->pev->origin, radius ); - } - - pTarget->PlayScriptedSentence( STRING(m_iszSentence), m_flDuration, m_flVolume, m_flAttenuation, bConcurrent, pListener ); - ALERT( at_aiconsole, "Playing sentence %s (%.1f)\n", STRING(m_iszSentence), m_flDuration ); - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - return TRUE; -} - - - - - -/* - -*/ - - -#include "dlls/furniture.h" - -LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); - - -//========================================================= -// Furniture is killed -//========================================================= -void CFurniture :: Die ( void ) -{ - SetThink ( &CFurniture::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// This used to have something to do with bees flying, but -// now it only initializes moving furniture in scripted sequences -//========================================================= -void CFurniture :: Spawn( ) -{ - PRECACHE_MODEL((char *)STRING(pev->model)); - SET_MODEL(ENT(pev), STRING(pev->model)); - - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - pev->health = 80000; - pev->takedamage = DAMAGE_AIM; - pev->effects = 0; - pev->yaw_speed = 0; - pev->sequence = 0; - pev->frame = 0; - -// pev->nextthink += 1.0; -// SetThink (WalkMonsterDelay); - - ResetSequenceInfo( ); - pev->frame = 0; - MonsterInit(); -} - -//========================================================= -// ID's Furniture as neutral (noone will attack it) -//========================================================= -int CFurniture::Classify ( void ) -{ - return CLASS_NONE; -} - - diff --git a/main/source/dlls/scripted.h b/main/source/dlls/scripted.h index d83614ad..bd08972f 100644 --- a/main/source/dlls/scripted.h +++ b/main/source/dlls/scripted.h @@ -1,107 +1,107 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef SCRIPTED_H -#define SCRIPTED_H - -#ifndef SCRIPTEVENT_H -#include "scriptevent.h" -#endif - -#define SF_SCRIPT_WAITTILLSEEN 1 -#define SF_SCRIPT_EXITAGITATED 2 -#define SF_SCRIPT_REPEATABLE 4 -#define SF_SCRIPT_LEAVECORPSE 8 -//#define SF_SCRIPT_INTERPOLATE 16 // don't use, old bug -#define SF_SCRIPT_NOINTERRUPT 32 -#define SF_SCRIPT_OVERRIDESTATE 64 -#define SF_SCRIPT_NOSCRIPTMOVEMENT 128 - -#define SCRIPT_BREAK_CONDITIONS (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) - -enum SS_INTERRUPT -{ - SS_INTERRUPT_IDLE = 0, - SS_INTERRUPT_BY_NAME, - SS_INTERRUPT_AI, -}; - -// when a monster finishes an AI scripted sequence, we can choose -// a schedule to place them in. These defines are the aliases to -// resolve worldcraft input to real schedules (sjb) -#define SCRIPT_FINISHSCHED_DEFAULT 0 -#define SCRIPT_FINISHSCHED_AMBUSH 1 - -class CCineMonster : public CBaseMonster -{ -public: - void Spawn( void ); - virtual void KeyValue( KeyValueData *pkvd ); - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void Blocked( CBaseEntity *pOther ); - virtual void Touch( CBaseEntity *pOther ); - virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - virtual void Activate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // void EXPORT CineSpawnThink( void ); - void EXPORT CineThink( void ); - void Pain( void ); - void Die( void ); - void DelayStart( int state ); - BOOL FindEntity( void ); - virtual void PossessEntity( void ); - - void ReleaseEntity( CBaseMonster *pEntity ); - void CancelScript( void ); - virtual BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); - virtual BOOL FCanOverrideState ( void ); - void SequenceDone ( CBaseMonster *pMonster ); - virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); - BOOL CanInterrupt( void ); - void AllowInterrupt( BOOL fAllow ); - int IgnoreConditions( void ); - - int m_iszIdle; // string index for idle animation - int m_iszPlay; // string index for scripted animation - int m_iszEntity; // entity that is wanted for this script - int m_fMoveTo; - int m_iFinishSchedule; - float m_flRadius; // range to search - float m_flRepeat; // repeat rate - - int m_iDelay; - float m_startTime; - - int m_saved_movetype; - int m_saved_solid; - int m_saved_effects; -// Vector m_vecOrigOrigin; - BOOL m_interruptable; -}; - -class CCineAI : public CCineMonster -{ - BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); - void PossessEntity( void ); - BOOL FCanOverrideState ( void ); - virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); -}; - - -#endif //SCRIPTED_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef SCRIPTED_H +#define SCRIPTED_H + +#ifndef SCRIPTEVENT_H +#include "scriptevent.h" +#endif + +#define SF_SCRIPT_WAITTILLSEEN 1 +#define SF_SCRIPT_EXITAGITATED 2 +#define SF_SCRIPT_REPEATABLE 4 +#define SF_SCRIPT_LEAVECORPSE 8 +//#define SF_SCRIPT_INTERPOLATE 16 // don't use, old bug +#define SF_SCRIPT_NOINTERRUPT 32 +#define SF_SCRIPT_OVERRIDESTATE 64 +#define SF_SCRIPT_NOSCRIPTMOVEMENT 128 + +#define SCRIPT_BREAK_CONDITIONS (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) + +enum SS_INTERRUPT +{ + SS_INTERRUPT_IDLE = 0, + SS_INTERRUPT_BY_NAME, + SS_INTERRUPT_AI, +}; + +// when a monster finishes an AI scripted sequence, we can choose +// a schedule to place them in. These defines are the aliases to +// resolve worldcraft input to real schedules (sjb) +#define SCRIPT_FINISHSCHED_DEFAULT 0 +#define SCRIPT_FINISHSCHED_AMBUSH 1 + +class CCineMonster : public CBaseMonster +{ +public: + void Spawn( void ); + virtual void KeyValue( KeyValueData *pkvd ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void Blocked( CBaseEntity *pOther ); + virtual void Touch( CBaseEntity *pOther ); + virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + virtual void Activate( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + // void EXPORT CineSpawnThink( void ); + void EXPORT CineThink( void ); + void Pain( void ); + void Die( void ); + void DelayStart( int state ); + BOOL FindEntity( void ); + virtual void PossessEntity( void ); + + void ReleaseEntity( CBaseMonster *pEntity ); + void CancelScript( void ); + virtual BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); + virtual BOOL FCanOverrideState ( void ); + void SequenceDone ( CBaseMonster *pMonster ); + virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); + BOOL CanInterrupt( void ); + void AllowInterrupt( BOOL fAllow ); + int IgnoreConditions( void ); + + int m_iszIdle; // string index for idle animation + int m_iszPlay; // string index for scripted animation + int m_iszEntity; // entity that is wanted for this script + int m_fMoveTo; + int m_iFinishSchedule; + float m_flRadius; // range to search + float m_flRepeat; // repeat rate + + int m_iDelay; + float m_startTime; + + int m_saved_movetype; + int m_saved_solid; + int m_saved_effects; +// Vector m_vecOrigOrigin; + BOOL m_interruptable; +}; + +class CCineAI : public CCineMonster +{ + BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); + void PossessEntity( void ); + BOOL FCanOverrideState ( void ); + virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); +}; + + +#endif //SCRIPTED_H diff --git a/main/source/dlls/scriptevent.h b/main/source/dlls/scriptevent.h index d660e4ba..be9c8852 100644 --- a/main/source/dlls/scriptevent.h +++ b/main/source/dlls/scriptevent.h @@ -1,29 +1,29 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef SCRIPTEVENT_H -#define SCRIPTEVENT_H - -#define SCRIPT_EVENT_DEAD 1000 // character is now dead -#define SCRIPT_EVENT_NOINTERRUPT 1001 // does not allow interrupt -#define SCRIPT_EVENT_CANINTERRUPT 1002 // will allow interrupt -#define SCRIPT_EVENT_FIREEVENT 1003 // event now fires -#define SCRIPT_EVENT_SOUND 1004 // Play named wave file (on CHAN_BODY) -#define SCRIPT_EVENT_SENTENCE 1005 // Play named sentence -#define SCRIPT_EVENT_INAIR 1006 // Leave the character in air at the end of the sequence (don't find the floor) -#define SCRIPT_EVENT_ENDANIMATION 1007 // Set the animation by name after the sequence completes -#define SCRIPT_EVENT_SOUND_VOICE 1008 // Play named wave file (on CHAN_VOICE) -#define SCRIPT_EVENT_SENTENCE_RND1 1009 // Play sentence group 25% of the time -#define SCRIPT_EVENT_NOT_DEAD 1010 // Bring back to life (for life/death sequences) -#endif //SCRIPTEVENT_H +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef SCRIPTEVENT_H +#define SCRIPTEVENT_H + +#define SCRIPT_EVENT_DEAD 1000 // character is now dead +#define SCRIPT_EVENT_NOINTERRUPT 1001 // does not allow interrupt +#define SCRIPT_EVENT_CANINTERRUPT 1002 // will allow interrupt +#define SCRIPT_EVENT_FIREEVENT 1003 // event now fires +#define SCRIPT_EVENT_SOUND 1004 // Play named wave file (on CHAN_BODY) +#define SCRIPT_EVENT_SENTENCE 1005 // Play named sentence +#define SCRIPT_EVENT_INAIR 1006 // Leave the character in air at the end of the sequence (don't find the floor) +#define SCRIPT_EVENT_ENDANIMATION 1007 // Set the animation by name after the sequence completes +#define SCRIPT_EVENT_SOUND_VOICE 1008 // Play named wave file (on CHAN_VOICE) +#define SCRIPT_EVENT_SENTENCE_RND1 1009 // Play sentence group 25% of the time +#define SCRIPT_EVENT_NOT_DEAD 1010 // Bring back to life (for life/death sequences) +#endif //SCRIPTEVENT_H diff --git a/main/source/dlls/shotgun.cpp b/main/source/dlls/shotgun.cpp index 4748a094..f30ce978 100644 --- a/main/source/dlls/shotgun.cpp +++ b/main/source/dlls/shotgun.cpp @@ -1,389 +1,389 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" -#include "../mod/AvHNetworkMessages.h" - -// special deathmatch shotgun spreads -#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees -#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees - -enum shotgun_e { - SHOTGUN_IDLE = 0, - SHOTGUN_FIRE, - SHOTGUN_FIRE2, - SHOTGUN_RELOAD, - SHOTGUN_PUMP, - SHOTGUN_START_RELOAD, - SHOTGUN_DRAW, - SHOTGUN_HOLSTER, - SHOTGUN_IDLE4, - SHOTGUN_IDLE_DEEP -}; - -//LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); - -void CShotgun::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_SHOTGUN; - SET_MODEL(ENT(pev), "models/w_shotgun.mdl"); - - m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE; - - FallInit();// get ready to fall -} - - -void CShotgun::Precache( void ) -{ - PRECACHE_MODEL("models/v_shotgun.mdl"); - PRECACHE_MODEL("models/w_shotgun.mdl"); - PRECACHE_MODEL("models/p_shotgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shotgunshell.mdl");// shotgun shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND ("weapons/dbarrel1.wav");//shotgun - PRECACHE_SOUND ("weapons/sbarrel1.wav");//shotgun - - PRECACHE_SOUND ("weapons/reload1.wav"); // shotgun reload - PRECACHE_SOUND ("weapons/reload3.wav"); // shotgun reload - -// PRECACHE_SOUND ("weapons/sshell1.wav"); // shotgun reload - played on client -// PRECACHE_SOUND ("weapons/sshell3.wav"); // shotgun reload - played on client - - PRECACHE_SOUND ("weapons/357_cock1.wav"); // gun empty sound - PRECACHE_SOUND ("weapons/scock1.wav"); // cock gun - - m_usSingleFire = PRECACHE_EVENT( 1, "events/shotgun1.sc" ); - m_usDoubleFire = PRECACHE_EVENT( 1, "events/shotgun2.sc" ); -} - -int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pPlayer->pev, m_iId ); - return TRUE; - } - return FALSE; -} - - -int CShotgun::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "buckshot"; - p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = SHOTGUN_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 1; - p->iFlags = 0; - p->iId = m_iId = WEAPON_SHOTGUN; - p->iWeight = SHOTGUN_WEIGHT; - - return 1; -} - - - -BOOL CShotgun::Deploy( ) -{ - return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); -} - -void CShotgun::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; - return; - } - - if (m_iClip <= 0) - { - Reload( ); - if (m_iClip == 0) - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - int flags = FEV_NOTHOST; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // regular old, untouched spread. - vecDir = m_pPlayer->FireBulletsPlayer( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSingleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - if (m_iClip != 0) - m_flPumpTime = gpGlobals->time + 0.5; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; - m_fInSpecialReload = 0; -} - - -void CShotgun::SecondaryAttack( void ) -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; - return; - } - - if (m_iClip <= 1) - { - Reload( ); - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip -= 2; - - - int flags = FEV_NOTHOST; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // tuned for deathmatch - vecDir = m_pPlayer->FireBulletsPlayer( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // untouched default single player - vecDir = m_pPlayer->FireBulletsPlayer( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usDoubleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - if (m_iClip != 0) - m_flPumpTime = gpGlobals->time + 0.95; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; - else - m_flTimeWeaponIdle = 1.5; - - m_fInSpecialReload = 0; - -} - - -void CShotgun::Reload( void ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) - return; - - // don't reload until recoil is done - if (m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) - return; - - // check to see if we're ready to reload - if (m_fInSpecialReload == 0) - { - SendWeaponAnim( SHOTGUN_START_RELOAD ); - m_fInSpecialReload = 1; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - return; - } - else if (m_fInSpecialReload == 1) - { - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - // was waiting for gun to move to side - m_fInSpecialReload = 2; - - if (RANDOM_LONG(0,1)) - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload1.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - else - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - - SendWeaponAnim( SHOTGUN_RELOAD ); - - m_flNextReload = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - } - else - { - // Add them to the clip - m_iClip += 1; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1; - m_fInSpecialReload = 1; - } -} - - -void CShotgun::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if ( m_flPumpTime && m_flPumpTime < gpGlobals->time ) - { - // play pumping sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); - m_flPumpTime = 0; - } - - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - Reload( ); - } - else if (m_fInSpecialReload != 0) - { - if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - Reload( ); - } - else - { - // reload debounce has timed out - SendWeaponAnim( SHOTGUN_PUMP ); - - // play cocking sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); - m_fInSpecialReload = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - } - else - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.8) - { - iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); - } - else if (flRand <= 0.95) - { - iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); - } - else - { - iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); - } - SendWeaponAnim( iAnim ); - } - } -} - - - -class CShotgunAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_shotbox.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_shotbox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ); - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" +#include "../mod/AvHNetworkMessages.h" + +// special deathmatch shotgun spreads +#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees +#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees + +enum shotgun_e { + SHOTGUN_IDLE = 0, + SHOTGUN_FIRE, + SHOTGUN_FIRE2, + SHOTGUN_RELOAD, + SHOTGUN_PUMP, + SHOTGUN_START_RELOAD, + SHOTGUN_DRAW, + SHOTGUN_HOLSTER, + SHOTGUN_IDLE4, + SHOTGUN_IDLE_DEEP +}; + +//LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); + +void CShotgun::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_SHOTGUN; + SET_MODEL(ENT(pev), "models/w_shotgun.mdl"); + + m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE; + + FallInit();// get ready to fall +} + + +void CShotgun::Precache( void ) +{ + PRECACHE_MODEL("models/v_shotgun.mdl"); + PRECACHE_MODEL("models/w_shotgun.mdl"); + PRECACHE_MODEL("models/p_shotgun.mdl"); + + m_iShell = PRECACHE_MODEL ("models/shotgunshell.mdl");// shotgun shell + + PRECACHE_SOUND("items/9mmclip1.wav"); + + PRECACHE_SOUND ("weapons/dbarrel1.wav");//shotgun + PRECACHE_SOUND ("weapons/sbarrel1.wav");//shotgun + + PRECACHE_SOUND ("weapons/reload1.wav"); // shotgun reload + PRECACHE_SOUND ("weapons/reload3.wav"); // shotgun reload + +// PRECACHE_SOUND ("weapons/sshell1.wav"); // shotgun reload - played on client +// PRECACHE_SOUND ("weapons/sshell3.wav"); // shotgun reload - played on client + + PRECACHE_SOUND ("weapons/357_cock1.wav"); // gun empty sound + PRECACHE_SOUND ("weapons/scock1.wav"); // cock gun + + m_usSingleFire = PRECACHE_EVENT( 1, "events/shotgun1.sc" ); + m_usDoubleFire = PRECACHE_EVENT( 1, "events/shotgun2.sc" ); +} + +int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + NetMsg_WeapPickup( pPlayer->pev, m_iId ); + return TRUE; + } + return FALSE; +} + + +int CShotgun::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "buckshot"; + p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = SHOTGUN_MAX_CLIP; + p->iSlot = 2; + p->iPosition = 1; + p->iFlags = 0; + p->iId = m_iId = WEAPON_SHOTGUN; + p->iWeight = SHOTGUN_WEIGHT; + + return 1; +} + + + +BOOL CShotgun::Deploy( ) +{ + return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); +} + +void CShotgun::PrimaryAttack() +{ + // don't fire underwater + if (m_pPlayer->pev->waterlevel == 3) + { + PlayEmptySound( ); + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + return; + } + + if (m_iClip <= 0) + { + Reload( ); + if (m_iClip == 0) + PlayEmptySound( ); + return; + } + + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; + + m_iClip--; + + int flags = FEV_NOTHOST; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + Vector vecDir; + +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + } + else + { + // regular old, untouched spread. + vecDir = m_pPlayer->FireBulletsPlayer( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + } + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSingleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); + + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + if (m_iClip != 0) + m_flPumpTime = gpGlobals->time + 0.5; + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; + if (m_iClip != 0) + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; + else + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; + m_fInSpecialReload = 0; +} + + +void CShotgun::SecondaryAttack( void ) +{ + // don't fire underwater + if (m_pPlayer->pev->waterlevel == 3) + { + PlayEmptySound( ); + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + return; + } + + if (m_iClip <= 1) + { + Reload( ); + PlayEmptySound( ); + return; + } + + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; + + m_iClip -= 2; + + + int flags = FEV_NOTHOST; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + Vector vecDir; + +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif + { + // tuned for deathmatch + vecDir = m_pPlayer->FireBulletsPlayer( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + } + else + { + // untouched default single player + vecDir = m_pPlayer->FireBulletsPlayer( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + } + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usDoubleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + if (m_iClip != 0) + m_flPumpTime = gpGlobals->time + 0.95; + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; + if (m_iClip != 0) + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; + else + m_flTimeWeaponIdle = 1.5; + + m_fInSpecialReload = 0; + +} + + +void CShotgun::Reload( void ) +{ + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) + return; + + // don't reload until recoil is done + if (m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) + return; + + // check to see if we're ready to reload + if (m_fInSpecialReload == 0) + { + SendWeaponAnim( SHOTGUN_START_RELOAD ); + m_fInSpecialReload = 1; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; + return; + } + else if (m_fInSpecialReload == 1) + { + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + return; + // was waiting for gun to move to side + m_fInSpecialReload = 2; + + if (RANDOM_LONG(0,1)) + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload1.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); + else + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); + + SendWeaponAnim( SHOTGUN_RELOAD ); + + m_flNextReload = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + } + else + { + // Add them to the clip + m_iClip += 1; + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1; + m_fInSpecialReload = 1; + } +} + + +void CShotgun::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + if ( m_flPumpTime && m_flPumpTime < gpGlobals->time ) + { + // play pumping sound + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); + m_flPumpTime = 0; + } + + if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) + { + if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + { + Reload( ); + } + else if (m_fInSpecialReload != 0) + { + if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + { + Reload( ); + } + else + { + // reload debounce has timed out + SendWeaponAnim( SHOTGUN_PUMP ); + + // play cocking sound + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); + m_fInSpecialReload = 0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; + } + } + else + { + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if (flRand <= 0.8) + { + iAnim = SHOTGUN_IDLE_DEEP; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); + } + else if (flRand <= 0.95) + { + iAnim = SHOTGUN_IDLE; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); + } + else + { + iAnim = SHOTGUN_IDLE4; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); + } + SendWeaponAnim( iAnim ); + } + } +} + + + +class CShotgunAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_shotbox.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_shotbox.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ); + + diff --git a/main/source/dlls/shotgun.cpp~ b/main/source/dlls/shotgun.cpp~ deleted file mode 100644 index d5860836..00000000 --- a/main/source/dlls/shotgun.cpp~ +++ /dev/null @@ -1,389 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" -#include "..mod/AvHNetworkMessages.h" - -// special deathmatch shotgun spreads -#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees -#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees - -enum shotgun_e { - SHOTGUN_IDLE = 0, - SHOTGUN_FIRE, - SHOTGUN_FIRE2, - SHOTGUN_RELOAD, - SHOTGUN_PUMP, - SHOTGUN_START_RELOAD, - SHOTGUN_DRAW, - SHOTGUN_HOLSTER, - SHOTGUN_IDLE4, - SHOTGUN_IDLE_DEEP -}; - -//LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); - -void CShotgun::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_SHOTGUN; - SET_MODEL(ENT(pev), "models/w_shotgun.mdl"); - - m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE; - - FallInit();// get ready to fall -} - - -void CShotgun::Precache( void ) -{ - PRECACHE_MODEL("models/v_shotgun.mdl"); - PRECACHE_MODEL("models/w_shotgun.mdl"); - PRECACHE_MODEL("models/p_shotgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shotgunshell.mdl");// shotgun shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND ("weapons/dbarrel1.wav");//shotgun - PRECACHE_SOUND ("weapons/sbarrel1.wav");//shotgun - - PRECACHE_SOUND ("weapons/reload1.wav"); // shotgun reload - PRECACHE_SOUND ("weapons/reload3.wav"); // shotgun reload - -// PRECACHE_SOUND ("weapons/sshell1.wav"); // shotgun reload - played on client -// PRECACHE_SOUND ("weapons/sshell3.wav"); // shotgun reload - played on client - - PRECACHE_SOUND ("weapons/357_cock1.wav"); // gun empty sound - PRECACHE_SOUND ("weapons/scock1.wav"); // cock gun - - m_usSingleFire = PRECACHE_EVENT( 1, "events/shotgun1.sc" ); - m_usDoubleFire = PRECACHE_EVENT( 1, "events/shotgun2.sc" ); -} - -int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - NetMsg_WeapPickup( pPlayer->pev, m_iId ); - return TRUE; - } - return FALSE; -} - - -int CShotgun::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "buckshot"; - p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = SHOTGUN_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 1; - p->iFlags = 0; - p->iId = m_iId = WEAPON_SHOTGUN; - p->iWeight = SHOTGUN_WEIGHT; - - return 1; -} - - - -BOOL CShotgun::Deploy( ) -{ - return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); -} - -void CShotgun::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; - return; - } - - if (m_iClip <= 0) - { - Reload( ); - if (m_iClip == 0) - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - int flags = FEV_NOTHOST; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // regular old, untouched spread. - vecDir = m_pPlayer->FireBulletsPlayer( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSingleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - if (m_iClip != 0) - m_flPumpTime = gpGlobals->time + 0.5; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; - m_fInSpecialReload = 0; -} - - -void CShotgun::SecondaryAttack( void ) -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; - return; - } - - if (m_iClip <= 1) - { - Reload( ); - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip -= 2; - - - int flags = FEV_NOTHOST; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // tuned for deathmatch - vecDir = m_pPlayer->FireBulletsPlayer( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // untouched default single player - vecDir = m_pPlayer->FireBulletsPlayer( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usDoubleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - if (m_iClip != 0) - m_flPumpTime = gpGlobals->time + 0.95; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; - else - m_flTimeWeaponIdle = 1.5; - - m_fInSpecialReload = 0; - -} - - -void CShotgun::Reload( void ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) - return; - - // don't reload until recoil is done - if (m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) - return; - - // check to see if we're ready to reload - if (m_fInSpecialReload == 0) - { - SendWeaponAnim( SHOTGUN_START_RELOAD ); - m_fInSpecialReload = 1; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - return; - } - else if (m_fInSpecialReload == 1) - { - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - // was waiting for gun to move to side - m_fInSpecialReload = 2; - - if (RANDOM_LONG(0,1)) - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload1.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - else - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - - SendWeaponAnim( SHOTGUN_RELOAD ); - - m_flNextReload = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - } - else - { - // Add them to the clip - m_iClip += 1; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1; - m_fInSpecialReload = 1; - } -} - - -void CShotgun::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if ( m_flPumpTime && m_flPumpTime < gpGlobals->time ) - { - // play pumping sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); - m_flPumpTime = 0; - } - - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - Reload( ); - } - else if (m_fInSpecialReload != 0) - { - if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - Reload( ); - } - else - { - // reload debounce has timed out - SendWeaponAnim( SHOTGUN_PUMP ); - - // play cocking sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); - m_fInSpecialReload = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - } - else - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.8) - { - iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); - } - else if (flRand <= 0.95) - { - iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); - } - else - { - iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); - } - SendWeaponAnim( iAnim ); - } - } -} - - - -class CShotgunAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_shotbox.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_shotbox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ); - - diff --git a/main/source/dlls/singleplay_gamerules.cpp b/main/source/dlls/singleplay_gamerules.cpp index 28db7512..2e316d50 100644 --- a/main/source/dlls/singleplay_gamerules.cpp +++ b/main/source/dlls/singleplay_gamerules.cpp @@ -1,328 +1,328 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "skill.h" -#include "items.h" - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; -extern int gmsgDeathMsg; // client dll messages -extern int gmsgScoreInfo; -extern int gmsgMOTD; - -//========================================================= -//========================================================= -CHalfLifeRules::CHalfLifeRules( void ) -{ - //RefreshSkillData(); -} - -//========================================================= -//========================================================= -void CHalfLifeRules::Think ( void ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsMultiplayer( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsDeathmatch ( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsCoOp( void ) -{ - return FALSE; -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - if ( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if ( !pPlayer->m_pActiveItem->CanHolster() ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - return TRUE; -} - -void CHalfLifeRules :: InitHUD( CBasePlayer *pl ) -{ -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: ClientDisconnected( edict_t *pClient ) -{ -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - // subtract off the speed at which a player is allowed to fall without being hurt, - // so damage will be based on speed beyond that, not the entire fall - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: PlayerSpawn( CBasePlayer *pPlayer ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: AllowAutoTargetCrosshair( void ) -{ - return ( g_iSkillLevel == SKILL_EASY ); -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: PlayerThink( CBasePlayer *pPlayer ) -{ -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeRules :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeRules :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeRules :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// Deathnotice -//========================================================= -void CHalfLifeRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeRules :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeRules :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) -{ - return -1; -} - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeRules :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) -{ - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeRules :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) -{ - return GR_WEAPON_RESPAWN_NO; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeRules::ItemShouldRespawn( CItem *pItem ) -{ - return GR_ITEM_RESPAWN_NO; -} - - -//========================================================= -// At what time in the future may this Item respawn? -//========================================================= -float CHalfLifeRules::FlItemRespawnTime( CItem *pItem ) -{ - return -1; -} - -//========================================================= -// Where should this item respawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules::VecItemRespawnSpot( CItem *pItem ) -{ - return pItem->pev->origin; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeRules::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) -{ - return GR_AMMO_RESPAWN_NO; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) -{ - return -1; -} - -//========================================================= -//========================================================= -Vector CHalfLifeRules::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) -{ - return pAmmo->pev->origin; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlHealthChargerRechargeTime( void ) -{ - return 0;// don't recharge -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // why would a single player in half life need this? - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: FAllowMonsters( void ) -{ - return TRUE; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// teamplay_gamerules.cpp +// +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "skill.h" +#include "items.h" + +extern DLL_GLOBAL CGameRules *g_pGameRules; +extern DLL_GLOBAL BOOL g_fGameOver; +extern int gmsgDeathMsg; // client dll messages +extern int gmsgScoreInfo; +extern int gmsgMOTD; + +//========================================================= +//========================================================= +CHalfLifeRules::CHalfLifeRules( void ) +{ + //RefreshSkillData(); +} + +//========================================================= +//========================================================= +void CHalfLifeRules::Think ( void ) +{ +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules::IsMultiplayer( void ) +{ + return FALSE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules::IsDeathmatch ( void ) +{ + return FALSE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules::IsCoOp( void ) +{ + return FALSE; +} + + +//========================================================= +//========================================================= +BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ + if ( !pPlayer->m_pActiveItem ) + { + // player doesn't have an active item! + return TRUE; + } + + if ( !pPlayer->m_pActiveItem->CanHolster() ) + { + return FALSE; + } + + return TRUE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +{ + return FALSE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +{ + return TRUE; +} + +void CHalfLifeRules :: InitHUD( CBasePlayer *pl ) +{ +} + +//========================================================= +//========================================================= +void CHalfLifeRules :: ClientDisconnected( edict_t *pClient ) +{ +} + +//========================================================= +//========================================================= +float CHalfLifeRules::FlPlayerFallDamage( CBasePlayer *pPlayer ) +{ + // subtract off the speed at which a player is allowed to fall without being hurt, + // so damage will be based on speed beyond that, not the entire fall + pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; + return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; +} + +//========================================================= +//========================================================= +void CHalfLifeRules :: PlayerSpawn( CBasePlayer *pPlayer ) +{ +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules :: AllowAutoTargetCrosshair( void ) +{ + return ( g_iSkillLevel == SKILL_EASY ); +} + +//========================================================= +//========================================================= +void CHalfLifeRules :: PlayerThink( CBasePlayer *pPlayer ) +{ +} + + +//========================================================= +//========================================================= +BOOL CHalfLifeRules :: FPlayerCanRespawn( CBasePlayer *pPlayer ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +float CHalfLifeRules :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) +{ + return gpGlobals->time;//now! +} + +//========================================================= +// IPointsForKill - how many points awarded to anyone +// that kills this player? +//========================================================= +int CHalfLifeRules :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +{ + return 1; +} + +//========================================================= +// PlayerKilled - someone/something killed this player +//========================================================= +void CHalfLifeRules :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +{ +} + +//========================================================= +// Deathnotice +//========================================================= +void CHalfLifeRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +{ +} + +//========================================================= +// PlayerGotWeapon - player has grabbed a weapon that was +// sitting in the world +//========================================================= +void CHalfLifeRules :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ +} + +//========================================================= +// FlWeaponRespawnTime - what is the time in the future +// at which this weapon may spawn? +//========================================================= +float CHalfLifeRules :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) +{ + return -1; +} + +//========================================================= +// FlWeaponRespawnTime - Returns 0 if the weapon can respawn +// now, otherwise it returns the time at which it can try +// to spawn again. +//========================================================= +float CHalfLifeRules :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) +{ + return 0; +} + +//========================================================= +// VecWeaponRespawnSpot - where should this weapon spawn? +// Some game variations may choose to randomize spawn locations +//========================================================= +Vector CHalfLifeRules :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) +{ + return pWeapon->pev->origin; +} + +//========================================================= +// WeaponShouldRespawn - any conditions inhibiting the +// respawning of this weapon? +//========================================================= +int CHalfLifeRules :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) +{ + return GR_WEAPON_RESPAWN_NO; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +void CHalfLifeRules::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) +{ +} + +//========================================================= +//========================================================= +int CHalfLifeRules::ItemShouldRespawn( CItem *pItem ) +{ + return GR_ITEM_RESPAWN_NO; +} + + +//========================================================= +// At what time in the future may this Item respawn? +//========================================================= +float CHalfLifeRules::FlItemRespawnTime( CItem *pItem ) +{ + return -1; +} + +//========================================================= +// Where should this item respawn? +// Some game variations may choose to randomize spawn locations +//========================================================= +Vector CHalfLifeRules::VecItemRespawnSpot( CItem *pItem ) +{ + return pItem->pev->origin; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules::IsAllowedToSpawn( CBaseEntity *pEntity ) +{ + return TRUE; +} + +//========================================================= +//========================================================= +void CHalfLifeRules::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) +{ +} + +//========================================================= +//========================================================= +int CHalfLifeRules::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) +{ + return GR_AMMO_RESPAWN_NO; +} + +//========================================================= +//========================================================= +float CHalfLifeRules::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) +{ + return -1; +} + +//========================================================= +//========================================================= +Vector CHalfLifeRules::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) +{ + return pAmmo->pev->origin; +} + +//========================================================= +//========================================================= +float CHalfLifeRules::FlHealthChargerRechargeTime( void ) +{ + return 0;// don't recharge +} + +//========================================================= +//========================================================= +int CHalfLifeRules::DeadPlayerWeapons( CBasePlayer *pPlayer ) +{ + return GR_PLR_DROP_GUN_NO; +} + +//========================================================= +//========================================================= +int CHalfLifeRules::DeadPlayerAmmo( CBasePlayer *pPlayer ) +{ + return GR_PLR_DROP_AMMO_NO; +} + +//========================================================= +//========================================================= +int CHalfLifeRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) +{ + // why would a single player in half life need this? + return GR_NOTTEAMMATE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeRules :: FAllowMonsters( void ) +{ + return TRUE; +} diff --git a/main/source/dlls/skill.cpp b/main/source/dlls/skill.cpp index 6718db58..a0bfae25 100644 --- a/main/source/dlls/skill.cpp +++ b/main/source/dlls/skill.cpp @@ -1,47 +1,47 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// skill.cpp - code for skill level concerns -//========================================================= -#include "extdll.h" -#include "util.h" -#include "skill.h" - - -skilldata_t gSkillData; - - -//========================================================= -// take the name of a cvar, tack a digit for the skill level -// on, and return the value.of that Cvar -//========================================================= -float GetSkillCvar( char *pName ) -{ - int iCount; - float flValue; - char szBuffer[ 64 ]; - - iCount = sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); - - flValue = CVAR_GET_FLOAT ( szBuffer ); - - if ( flValue <= 0 ) - { - ALERT ( at_console, "\n\n** GetSkillCVar Got a zero for %s **\n\n", szBuffer ); - } - - return flValue; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// skill.cpp - code for skill level concerns +//========================================================= +#include "extdll.h" +#include "util.h" +#include "skill.h" + + +skilldata_t gSkillData; + + +//========================================================= +// take the name of a cvar, tack a digit for the skill level +// on, and return the value.of that Cvar +//========================================================= +float GetSkillCvar( char *pName ) +{ + int iCount; + float flValue; + char szBuffer[ 64 ]; + + iCount = sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); + + flValue = CVAR_GET_FLOAT ( szBuffer ); + + if ( flValue <= 0 ) + { + ALERT ( at_console, "\n\n** GetSkillCVar Got a zero for %s **\n\n", szBuffer ); + } + + return flValue; +} + diff --git a/main/source/dlls/skill.h b/main/source/dlls/skill.h index d695b0a7..7770aca9 100644 --- a/main/source/dlls/skill.h +++ b/main/source/dlls/skill.h @@ -1,151 +1,151 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// skill.h - skill level concerns -//========================================================= -#ifndef SKILL_H -#define SKILL_H - -struct skilldata_t -{ - - int iSkillLevel; // game skill level - -// Monster Health & Damage - float agruntHealth; - float agruntDmgPunch; - - float apacheHealth; - - float barneyHealth; - - float bigmommaHealthFactor; // Multiply each node's health by this - float bigmommaDmgSlash; // melee attack damage - float bigmommaDmgBlast; // mortar attack damage - float bigmommaRadiusBlast; // mortar attack radius - - float bullsquidHealth; - float bullsquidDmgBite; - float bullsquidDmgWhip; - float bullsquidDmgSpit; - - float gargantuaHealth; - float gargantuaDmgSlash; - float gargantuaDmgFire; - float gargantuaDmgStomp; - - float hassassinHealth; - - float headcrabHealth; - float headcrabDmgBite; - - float hgruntHealth; - float hgruntDmgKick; - float hgruntShotgunPellets; - float hgruntGrenadeSpeed; - - float houndeyeHealth; - float houndeyeDmgBlast; - - float slaveHealth; - float slaveDmgClaw; - float slaveDmgClawrake; - float slaveDmgZap; - - float ichthyosaurHealth; - float ichthyosaurDmgShake; - - float leechHealth; - float leechDmgBite; - - float controllerHealth; - float controllerDmgZap; - float controllerSpeedBall; - float controllerDmgBall; - - float nihilanthHealth; - float nihilanthZap; - - float scientistHealth; - - float snarkHealth; - float snarkDmgBite; - float snarkDmgPop; - - float zombieHealth; - float zombieDmgOneSlash; - float zombieDmgBothSlash; - - float turretHealth; - float miniturretHealth; - float sentryHealth; - - -// Player Weapons - float plrDmgCrowbar; - float plrDmg9MM; - float plrDmg357; - float plrDmgMP5; - float plrDmgM203Grenade; - float plrDmgBuckshot; - float plrDmgCrossbowClient; - float plrDmgCrossbowMonster; - float plrDmgRPG; - float plrDmgGauss; - float plrDmgEgonNarrow; - float plrDmgEgonWide; - float plrDmgHornet; - float plrDmgHandGrenade; - float plrDmgSatchel; - float plrDmgTripmine; - -// weapons shared by monsters - float monDmg9MM; - float monDmgMP5; - float monDmg12MM; - float monDmgHornet; - -// health/suit charge - float suitchargerCapacity; - float batteryCapacity; - float healthchargerCapacity; - float healthkitCapacity; - float scientistHeal; - -// monster damage adj - float monHead; - float monChest; - float monStomach; - float monLeg; - float monArm; - -// player damage adj - float plrHead; - float plrChest; - float plrStomach; - float plrLeg; - float plrArm; -}; - -extern DLL_GLOBAL skilldata_t gSkillData; -float GetSkillCvar( char *pName ); - -extern DLL_GLOBAL int g_iSkillLevel; - -#define SKILL_EASY 1 -#define SKILL_MEDIUM 2 -#define SKILL_HARD 3 - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// skill.h - skill level concerns +//========================================================= +#ifndef SKILL_H +#define SKILL_H + +struct skilldata_t +{ + + int iSkillLevel; // game skill level + +// Monster Health & Damage + float agruntHealth; + float agruntDmgPunch; + + float apacheHealth; + + float barneyHealth; + + float bigmommaHealthFactor; // Multiply each node's health by this + float bigmommaDmgSlash; // melee attack damage + float bigmommaDmgBlast; // mortar attack damage + float bigmommaRadiusBlast; // mortar attack radius + + float bullsquidHealth; + float bullsquidDmgBite; + float bullsquidDmgWhip; + float bullsquidDmgSpit; + + float gargantuaHealth; + float gargantuaDmgSlash; + float gargantuaDmgFire; + float gargantuaDmgStomp; + + float hassassinHealth; + + float headcrabHealth; + float headcrabDmgBite; + + float hgruntHealth; + float hgruntDmgKick; + float hgruntShotgunPellets; + float hgruntGrenadeSpeed; + + float houndeyeHealth; + float houndeyeDmgBlast; + + float slaveHealth; + float slaveDmgClaw; + float slaveDmgClawrake; + float slaveDmgZap; + + float ichthyosaurHealth; + float ichthyosaurDmgShake; + + float leechHealth; + float leechDmgBite; + + float controllerHealth; + float controllerDmgZap; + float controllerSpeedBall; + float controllerDmgBall; + + float nihilanthHealth; + float nihilanthZap; + + float scientistHealth; + + float snarkHealth; + float snarkDmgBite; + float snarkDmgPop; + + float zombieHealth; + float zombieDmgOneSlash; + float zombieDmgBothSlash; + + float turretHealth; + float miniturretHealth; + float sentryHealth; + + +// Player Weapons + float plrDmgCrowbar; + float plrDmg9MM; + float plrDmg357; + float plrDmgMP5; + float plrDmgM203Grenade; + float plrDmgBuckshot; + float plrDmgCrossbowClient; + float plrDmgCrossbowMonster; + float plrDmgRPG; + float plrDmgGauss; + float plrDmgEgonNarrow; + float plrDmgEgonWide; + float plrDmgHornet; + float plrDmgHandGrenade; + float plrDmgSatchel; + float plrDmgTripmine; + +// weapons shared by monsters + float monDmg9MM; + float monDmgMP5; + float monDmg12MM; + float monDmgHornet; + +// health/suit charge + float suitchargerCapacity; + float batteryCapacity; + float healthchargerCapacity; + float healthkitCapacity; + float scientistHeal; + +// monster damage adj + float monHead; + float monChest; + float monStomach; + float monLeg; + float monArm; + +// player damage adj + float plrHead; + float plrChest; + float plrStomach; + float plrLeg; + float plrArm; +}; + +extern DLL_GLOBAL skilldata_t gSkillData; +float GetSkillCvar( char *pName ); + +extern DLL_GLOBAL int g_iSkillLevel; + +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 + #endif \ No newline at end of file diff --git a/main/source/dlls/sound.cpp b/main/source/dlls/sound.cpp index caddfac4..9645b765 100644 --- a/main/source/dlls/sound.cpp +++ b/main/source/dlls/sound.cpp @@ -1,1990 +1,1990 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// sound.cpp -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "player.h" -#include "talkmonster.h" -#include "gamerules.h" -#include "../mod/AvHSpecials.h" - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); - - -// ==================== GENERIC AMBIENT SOUND ====================================== - -// runtime pitch shift and volume fadein/out structure - -// NOTE: IF YOU CHANGE THIS STRUCT YOU MUST CHANGE THE SAVE/RESTORE VERSION NUMBER -// SEE BELOW (in the typedescription for the class) -typedef struct dynpitchvol -{ - // NOTE: do not change the order of these parameters - // NOTE: unless you also change order of rgdpvpreset array elements! - int preset; - - int pitchrun; // pitch shift % when sound is running 0 - 255 - int pitchstart; // pitch shift % when sound stops or starts 0 - 255 - int spinup; // spinup time 0 - 100 - int spindown; // spindown time 0 - 100 - - int volrun; // volume change % when sound is running 0 - 10 - int volstart; // volume change % when sound stops or starts 0 - 10 - int fadein; // volume fade in time 0 - 100 - int fadeout; // volume fade out time 0 - 100 - - // Low Frequency Oscillator - int lfotype; // 0) off 1) square 2) triangle 3) random - int lforate; // 0 - 1000, how fast lfo osciallates - - int lfomodpitch; // 0-100 mod of current pitch. 0 is off. - int lfomodvol; // 0-100 mod of current volume. 0 is off. - - int cspinup; // each trigger hit increments counter and spinup pitch - - - int cspincount; - - int pitch; - int spinupsav; - int spindownsav; - int pitchfrac; - - int vol; - int fadeinsav; - int fadeoutsav; - int volfrac; - - int lfofrac; - int lfomult; - - -} dynpitchvol_t; - -#define CDPVPRESETMAX 27 - -// presets for runtime pitch and vol modulation of ambient sounds - -dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = -{ -// pitch pstart spinup spindwn volrun volstrt fadein fadeout lfotype lforate modptch modvol cspnup -{1, 255, 75, 95, 95, 10, 1, 50, 95, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{2, 255, 85, 70, 88, 10, 1, 20, 88, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{3, 255, 100, 50, 75, 10, 1, 10, 75, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{4, 100, 100, 0, 0, 10, 1, 90, 90, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{5, 100, 100, 0, 0, 10, 1, 80, 80, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{6, 100, 100, 0, 0, 10, 1, 50, 70, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{7, 100, 100, 0, 0, 5, 1, 40, 50, 1, 50, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{8, 100, 100, 0, 0, 5, 1, 40, 50, 1, 150, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{9, 100, 100, 0, 0, 5, 1, 40, 50, 1, 750, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{10,128, 100, 50, 75, 10, 1, 30, 40, 2, 8, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{11,128, 100, 50, 75, 10, 1, 30, 40, 2, 25, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{12,128, 100, 50, 75, 10, 1, 30, 40, 2, 70, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{13,50, 50, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{14,70, 70, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{15,90, 90, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{16,120, 120, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{17,180, 180, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{18,255, 255, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{19,200, 75, 90, 90, 10, 1, 50, 90, 2, 100, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{20,255, 75, 97, 90, 10, 1, 50, 90, 1, 40, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{21,100, 100, 0, 0, 10, 1, 30, 50, 3, 15, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{22,160, 160, 0, 0, 10, 1, 50, 50, 3, 500, 25, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{23,255, 75, 88, 0, 10, 1, 40, 0, 0, 0, 0, 0, 5, 0,0,0,0,0,0,0,0,0,0}, -{24,200, 20, 95, 70, 10, 1, 70, 70, 3, 20, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{25,180, 100, 50, 60, 10, 1, 40, 60, 2, 90, 100, 100, 0, 0,0,0,0,0,0,0,0,0,0}, -{26,60, 60, 0, 0, 10, 1, 40, 70, 3, 80, 20, 50, 0, 0,0,0,0,0,0,0,0,0,0}, -{27,128, 90, 10, 10, 10, 1, 20, 40, 1, 5, 10, 20, 0, 0,0,0,0,0,0,0,0,0,0} -}; - -class CAmbientGeneric : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT RampThink( void ); - void InitModulationParms(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - float m_flAttenuation; // attenuation value - dynpitchvol_t m_dpv; - - BOOL m_fActive; // only TRUE when the entity is playing a looping sound - BOOL m_fLooping; // TRUE when the sound played will loop -}; - -LINK_ENTITY_TO_CLASS( ambient_generic, CAmbientGeneric ); -TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = -{ - DEFINE_FIELD( CAmbientGeneric, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CAmbientGeneric, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CAmbientGeneric, m_fLooping, FIELD_BOOLEAN ), - - // HACKHACK - This is not really in the spirit of the save/restore design, but save this - // out as a binary data block. If the dynpitchvol_t is changed, old saved games will NOT - // load these correctly, so bump the save/restore version if you change the size of the struct - // The right way to do this is to split the input parms (read in keyvalue) into members and re-init this - // struct in Precache(), but it's unlikely that the struct will change, so it's not worth the time right now. - DEFINE_ARRAY( CAmbientGeneric, m_dpv, FIELD_CHARACTER, sizeof(dynpitchvol_t) ), -}; - -IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CAmbientGeneric :: Spawn( void ) -{ -/* - -1 : "Default" - 0 : "Everywhere" - 200 : "Small Radius" - 125 : "Medium Radius" - 80 : "Large Radius" -*/ - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) - { - m_flAttenuation = ATTN_NONE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - else - {// if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_STATIC; - } - - char* szSoundFile = (char*) STRING(pev->message); - - if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) - { - ALERT( at_error, "EMPTY AMBIENT AT: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CAmbientGeneric::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - // Set up think function for dynamic modification - // of ambient sound's pitch or volume. Don't - // start thinking yet. - - SetThink(&CAmbientGeneric::RampThink); - pev->nextthink = 0; - - // allow on/off switching via 'use' function. - - SetUse ( &CAmbientGeneric::ToggleUse ); - - m_fActive = FALSE; - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) - m_fLooping = FALSE; - else - m_fLooping = TRUE; - Precache( ); -} - - -void CAmbientGeneric :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) - { - if (*szSoundFile != '!') - PRECACHE_SOUND(szSoundFile); - } - // init all dynamic modulation parms - InitModulationParms(); - - if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) - { - // start the sound ASAP - if (m_fLooping) - m_fActive = TRUE; - } - if ( m_fActive ) - { - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); - - pev->nextthink = gpGlobals->time + 0.1; - } -} - -// RampThink - Think at 5hz if we are dynamically modifying -// pitch or volume of the playing sound. This function will -// ramp pitch and/or volume up or down, modify pitch/volume -// with lfo if active. - -void CAmbientGeneric :: RampThink( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - int pitch = m_dpv.pitch; - int vol = m_dpv.vol; - int flags = 0; - int fChanged = 0; // FALSE if pitch and vol remain unchanged this round - int prev; - - if (!m_dpv.spinup && !m_dpv.spindown && !m_dpv.fadein && !m_dpv.fadeout && !m_dpv.lfotype) - return; // no ramps or lfo, stop thinking - - // ============== - // pitch envelope - // ============== - if (m_dpv.spinup || m_dpv.spindown) - { - prev = m_dpv.pitchfrac >> 8; - - if (m_dpv.spinup > 0) - m_dpv.pitchfrac += m_dpv.spinup; - else if (m_dpv.spindown > 0) - m_dpv.pitchfrac -= m_dpv.spindown; - - pitch = m_dpv.pitchfrac >> 8; - - if (pitch > m_dpv.pitchrun) - { - pitch = m_dpv.pitchrun; - m_dpv.spinup = 0; // done with ramp up - } - - if (pitch < m_dpv.pitchstart) - { - pitch = m_dpv.pitchstart; - m_dpv.spindown = 0; // done with ramp down - - // shut sound off - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // return without setting nextthink - return; - } - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - m_dpv.pitch = pitch; - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - // ================== - // amplitude envelope - // ================== - if (m_dpv.fadein || m_dpv.fadeout) - { - prev = m_dpv.volfrac >> 8; - - if (m_dpv.fadein > 0) - m_dpv.volfrac += m_dpv.fadein; - else if (m_dpv.fadeout > 0) - m_dpv.volfrac -= m_dpv.fadeout; - - vol = m_dpv.volfrac >> 8; - - if (vol > m_dpv.volrun) - { - vol = m_dpv.volrun; - m_dpv.fadein = 0; // done with ramp up - } - - if (vol < m_dpv.volstart) - { - vol = m_dpv.volstart; - m_dpv.fadeout = 0; // done with ramp down - - // shut sound off - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // return without setting nextthink - return; - } - - if (vol > 100) vol = 100; - if (vol < 1) vol = 1; - - m_dpv.vol = vol; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - // =================== - // pitch/amplitude LFO - // =================== - if (m_dpv.lfotype) - { - int pos; - - if (m_dpv.lfofrac > 0x6fffffff) - m_dpv.lfofrac = 0; - - // update lfo, lfofrac/255 makes a triangle wave 0-255 - m_dpv.lfofrac += m_dpv.lforate; - pos = m_dpv.lfofrac >> 8; - - if (m_dpv.lfofrac < 0) - { - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - pos = 0; - } - else if (pos > 255) - { - pos = 255; - m_dpv.lfofrac = (255 << 8); - m_dpv.lforate = -abs(m_dpv.lforate); - } - - switch(m_dpv.lfotype) - { - case LFO_SQUARE: - if (pos < 128) - m_dpv.lfomult = 255; - else - m_dpv.lfomult = 0; - - break; - case LFO_RANDOM: - if (pos == 255) - m_dpv.lfomult = RANDOM_LONG(0, 255); - break; - case LFO_TRIANGLE: - default: - m_dpv.lfomult = pos; - break; - } - - if (m_dpv.lfomodpitch) - { - prev = pitch; - - // pitch 0-255 - pitch += ((m_dpv.lfomult - 128) * m_dpv.lfomodpitch) / 100; - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - if (m_dpv.lfomodvol) - { - // vol 0-100 - prev = vol; - - vol += ((m_dpv.lfomult - 128) * m_dpv.lfomodvol) / 100; - - if (vol > 100) vol = 100; - if (vol < 0) vol = 0; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - } - - // Send update to playing sound only if we actually changed - // pitch or volume in this routine. - - if (flags && fChanged) - { - if (pitch == PITCH_NORM) - pitch = PITCH_NORM + 1; // don't send 'no pitch' ! - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (vol * 0.01), m_flAttenuation, flags, pitch); - } - - // update ramps at 5hz - pev->nextthink = gpGlobals->time + 0.2; - return; -} - -// Init all ramp params in preparation to -// play a new sound - -void CAmbientGeneric :: InitModulationParms(void) -{ - int pitchinc; - - m_dpv.volrun = pev->health * 10; // 0 - 100 - if (m_dpv.volrun > 100) m_dpv.volrun = 100; - if (m_dpv.volrun < 0) m_dpv.volrun = 0; - - // get presets - if (m_dpv.preset != 0 && m_dpv.preset <= CDPVPRESETMAX) - { - // load preset values - m_dpv = rgdpvpreset[m_dpv.preset - 1]; - - // fixup preset values, just like - // fixups in KeyValue routine. - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - - m_dpv.volstart *= 10; - m_dpv.volrun *= 10; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - - m_dpv.lforate *= 256; - - m_dpv.fadeinsav = m_dpv.fadein; - m_dpv.fadeoutsav = m_dpv.fadeout; - m_dpv.spinupsav = m_dpv.spinup; - m_dpv.spindownsav = m_dpv.spindown; - } - - m_dpv.fadein = m_dpv.fadeinsav; - m_dpv.fadeout = 0; - - if (m_dpv.fadein) - m_dpv.vol = m_dpv.volstart; - else - m_dpv.vol = m_dpv.volrun; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - if (m_dpv.spinup) - m_dpv.pitch = m_dpv.pitchstart; - else - m_dpv.pitch = m_dpv.pitchrun; - - if (m_dpv.pitch == 0) - m_dpv.pitch = PITCH_NORM; - - m_dpv.pitchfrac = m_dpv.pitch << 8; - m_dpv.volfrac = m_dpv.vol << 8; - - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - - m_dpv.cspincount = 1; - - if (m_dpv.cspinup) - { - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - } - - if ((m_dpv.spinupsav || m_dpv.spindownsav || (m_dpv.lfotype && m_dpv.lfomodpitch)) - && (m_dpv.pitch == PITCH_NORM)) - m_dpv.pitch = PITCH_NORM + 1; // must never send 'no pitch' as first pitch - // if we intend to pitch shift later! -} - -// -// ToggleUse - turns an ambient sound on or off. If the -// ambient is a looping sound, mark sound as active (m_fActive) -// if it's playing, innactive if not. If the sound is not -// a looping sound, never mark it as active. -// -void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - char* szSoundFile = (char*) STRING(pev->message); - float fraction; - - if ( useType != USE_TOGGLE ) - { - if ( (m_fActive && useType == USE_ON) || (!m_fActive && useType == USE_OFF) ) - return; - } - // Directly change pitch if arg passed. Only works if sound is already playing. - - if (useType == USE_SET && m_fActive) // Momentary buttons will pass down a float in here - { - - fraction = value; - - if ( fraction > 1.0 ) - fraction = 1.0; - if (fraction < 0.0) - fraction = 0.01; - - m_dpv.pitch = fraction * 255; - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); - - return; - } - - // Toggle - - // m_fActive is TRUE only if a looping sound is playing. - - if ( m_fActive ) - {// turn sound off - - if (m_dpv.cspinup) - { - // Don't actually shut off. Each toggle causes - // incremental spinup to max pitch - - if (m_dpv.cspincount <= m_dpv.cspinup) - { - int pitchinc; - - // start a new spinup - m_dpv.cspincount++; - - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc * m_dpv.cspincount; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - - pev->nextthink = gpGlobals->time + 0.1; - } - - } - else - { - m_fActive = FALSE; - - // HACKHACK - this makes the code in Precache() work properly after a save/restore - pev->spawnflags |= AMBIENT_SOUND_START_SILENT; - - if (m_dpv.spindownsav || m_dpv.fadeoutsav) - { - // spin it down (or fade it) before shutoff if spindown is set - m_dpv.spindown = m_dpv.spindownsav; - m_dpv.spinup = 0; - - m_dpv.fadeout = m_dpv.fadeoutsav; - m_dpv.fadein = 0; - pev->nextthink = gpGlobals->time + 0.1; - } - else - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - } - else - {// turn sound on - - // only toggle if this is a looping sound. If not looping, each - // trigger will cause the sound to play. If the sound is still - // playing from a previous trigger press, it will be shut off - // and then restarted. - - if (m_fLooping) - m_fActive = TRUE; - else - // shut sound off now - may be interrupting a long non-looping sound - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // init all ramp params for startup - - InitModulationParms(); - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, 0, m_dpv.pitch); - - pev->nextthink = gpGlobals->time + 0.1; - - } -} -// KeyValue - load keyvalue pairs into member data of the -// ambient generic. NOTE: called BEFORE spawn! - -void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) -{ - // NOTE: changing any of the modifiers in this code - // NOTE: also requires changing InitModulationParms code. - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_dpv.preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - - // pitchrun - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - m_dpv.pitchrun = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - if (m_dpv.pitchrun < 0) m_dpv.pitchrun = 0; - } - - // pitchstart - else if (FStrEq(pkvd->szKeyName, "pitchstart")) - { - m_dpv.pitchstart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchstart > 255) m_dpv.pitchstart = 255; - if (m_dpv.pitchstart < 0) m_dpv.pitchstart = 0; - } - - // spinup - else if (FStrEq(pkvd->szKeyName, "spinup")) - { - m_dpv.spinup = atoi(pkvd->szValue); - - if (m_dpv.spinup > 100) m_dpv.spinup = 100; - if (m_dpv.spinup < 0) m_dpv.spinup = 0; - - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - m_dpv.spinupsav = m_dpv.spinup; - pkvd->fHandled = TRUE; - } - - // spindown - else if (FStrEq(pkvd->szKeyName, "spindown")) - { - m_dpv.spindown = atoi(pkvd->szValue); - - if (m_dpv.spindown > 100) m_dpv.spindown = 100; - if (m_dpv.spindown < 0) m_dpv.spindown = 0; - - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - m_dpv.spindownsav = m_dpv.spindown; - pkvd->fHandled = TRUE; - } - - // volstart - else if (FStrEq(pkvd->szKeyName, "volstart")) - { - m_dpv.volstart = atoi(pkvd->szValue); - - if (m_dpv.volstart > 10) m_dpv.volstart = 10; - if (m_dpv.volstart < 0) m_dpv.volstart = 0; - - m_dpv.volstart *= 10; // 0 - 100 - - pkvd->fHandled = TRUE; - } - - // fadein - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_dpv.fadein = atoi(pkvd->szValue); - - if (m_dpv.fadein > 100) m_dpv.fadein = 100; - if (m_dpv.fadein < 0) m_dpv.fadein = 0; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - m_dpv.fadeinsav = m_dpv.fadein; - pkvd->fHandled = TRUE; - } - - // fadeout - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_dpv.fadeout = atoi(pkvd->szValue); - - if (m_dpv.fadeout > 100) m_dpv.fadeout = 100; - if (m_dpv.fadeout < 0) m_dpv.fadeout = 0; - - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - m_dpv.fadeoutsav = m_dpv.fadeout; - pkvd->fHandled = TRUE; - } - - // lfotype - else if (FStrEq(pkvd->szKeyName, "lfotype")) - { - m_dpv.lfotype = atoi(pkvd->szValue); - if (m_dpv.lfotype > 4) m_dpv.lfotype = LFO_TRIANGLE; - pkvd->fHandled = TRUE; - } - - // lforate - else if (FStrEq(pkvd->szKeyName, "lforate")) - { - m_dpv.lforate = atoi(pkvd->szValue); - - if (m_dpv.lforate > 1000) m_dpv.lforate = 1000; - if (m_dpv.lforate < 0) m_dpv.lforate = 0; - - m_dpv.lforate *= 256; - - pkvd->fHandled = TRUE; - } - // lfomodpitch - else if (FStrEq(pkvd->szKeyName, "lfomodpitch")) - { - m_dpv.lfomodpitch = atoi(pkvd->szValue); - if (m_dpv.lfomodpitch > 100) m_dpv.lfomodpitch = 100; - if (m_dpv.lfomodpitch < 0) m_dpv.lfomodpitch = 0; - - - pkvd->fHandled = TRUE; - } - - // lfomodvol - else if (FStrEq(pkvd->szKeyName, "lfomodvol")) - { - m_dpv.lfomodvol = atoi(pkvd->szValue); - if (m_dpv.lfomodvol > 100) m_dpv.lfomodvol = 100; - if (m_dpv.lfomodvol < 0) m_dpv.lfomodvol = 0; - - pkvd->fHandled = TRUE; - } - - // cspinup - else if (FStrEq(pkvd->szKeyName, "cspinup")) - { - m_dpv.cspinup = atoi(pkvd->szValue); - if (m_dpv.cspinup > 100) m_dpv.cspinup = 100; - if (m_dpv.cspinup < 0) m_dpv.cspinup = 0; - - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// =================== ROOM SOUND FX ========================================== - -class CEnvSound : public CPointEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flRadius; - float m_flRoomtype; -}; - -LINK_ENTITY_TO_CLASS( env_sound, CEnvSound ); -TYPEDESCRIPTION CEnvSound::m_SaveData[] = -{ - DEFINE_FIELD( CEnvSound, m_flRadius, FIELD_FLOAT ), - DEFINE_FIELD( CEnvSound, m_flRoomtype, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CEnvSound, CBaseEntity ); - - -void CEnvSound :: KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "roomtype")) - { - m_flRoomtype = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - -// returns TRUE if the given sound entity (pev) is in range -// and can see the given player entity (pevTarget) - -BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) -{ - CEnvSound *pSound = GetClassPtr( (CEnvSound *)pev ); - Vector vecSpot1 = pev->origin + pev->view_ofs; - Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; - Vector vecRange; - float flRange; - TraceResult tr; - - UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); - - // check if line of sight crosses water boundary, or is blocked - - if ((tr.fInOpen && tr.fInWater) || tr.flFraction != 1) - return FALSE; - - // calc range from sound entity to player - - vecRange = tr.vecEndPos - vecSpot1; - flRange = vecRange.Length(); - - if (pSound->m_flRadius < flRange) - return FALSE; - - if (pflRange) - *pflRange = flRange; - - return TRUE; -} - -// -// A client that is visible and in range of a sound entity will -// have its room_type set by that sound entity. If two or more -// sound entities are contending for a client, then the nearest -// sound entity to the client will set the client's room_type. -// A client's room_type will remain set to its prior value until -// a new in-range, visible sound entity resets a new room_type. -// - -// CONSIDER: if player in water state, autoset roomtype to 14,15 or 16. - -void CEnvSound :: Think( void ) -{ - // get pointer to client if visible; FIND_CLIENT_IN_PVS will - // cycle through visible clients on consecutive calls. - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS(edict()); - CBasePlayer *pPlayer = NULL; - - if (FNullEnt(pentPlayer)) - goto env_sound_Think_slow; // no player in pvs of sound entity, slow it down - - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - float flRange; - - // Don't change sound types for players that are being digested - if(!GetHasUpgrade(pPlayer->pev->iuser4, MASK_DIGESTING)) - { - // check to see if this is the sound entity that is - // currently affecting this player - - if(!FNullEnt(pPlayer->m_pentSndLast) && (pPlayer->m_pentSndLast == ENT(pev))) { - - // this is the entity currently affecting player, check - // for validity - - if (pPlayer->m_flSndRoomtype != 0 && pPlayer->m_flSndRange != 0) { - - // we're looking at a valid sound entity affecting - // player, make sure it's still valid, update range - - if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) { - pPlayer->m_flSndRange = flRange; - goto env_sound_Think_fast; - } else { - - // current sound entity affecting player is no longer valid, - // flag this state by clearing room_type and range. - // NOTE: we do not actually change the player's room_type - // NOTE: until we have a new valid room_type to change it to. - - pPlayer->m_flSndRange = 0; - pPlayer->m_flSndRoomtype = 0; - goto env_sound_Think_slow; - } - } else { - // entity is affecting player but is out of range, - // wait passively for another entity to usurp it... - goto env_sound_Think_slow; - } - } - - // if we got this far, we're looking at an entity that is contending - // for current player sound. the closest entity to player wins. - - if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) - { - if (flRange < pPlayer->m_flSndRange || pPlayer->m_flSndRange == 0) - { - // new entity is closer to player, so it wins. - pPlayer->m_pentSndLast = ENT(pev); - pPlayer->m_flSndRoomtype = m_flRoomtype; - pPlayer->m_flSndRange = flRange; - - // send room_type command to player's server. - // this should be a rare event - once per change of room_type - // only! - - //CLIENT_COMMAND(pentPlayer, "room_type %f", m_flRoomtype); - - MESSAGE_BEGIN( MSG_ONE, SVC_ROOMTYPE, NULL, pentPlayer ); // use the magic #1 for "one client" - WRITE_SHORT( (short)m_flRoomtype ); // sequence number - MESSAGE_END(); - - // crank up nextthink rate for new active sound entity - // by falling through to think_fast... - } - // player is not closer to the contending sound entity, - // just fall through to think_fast. this effectively - // cranks up the think_rate of entities near the player. - } - } - else - { - int a = 0; - } - - // player is in pvs of sound entity, but either not visible or - // not in range. do nothing, fall through to think_fast... - -env_sound_Think_fast: - pev->nextthink = gpGlobals->time + 0.25; - return; - -env_sound_Think_slow: - pev->nextthink = gpGlobals->time + 0.75; - return; -} - -// -// env_sound - spawn a sound entity that will set player roomtype -// when player moves in range and sight. -// -// -void CEnvSound :: Spawn( ) -{ - // spread think times - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); -} - -// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== - -#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group - -// group of related sentences - -typedef struct sentenceg -{ - char szgroupname[CBSENTENCENAME_MAX]; - int count; - unsigned char rgblru[CSENTENCE_LRU_MAX]; - -} SENTENCEG; - -#define CSENTENCEG_MAX 200 // max number of sentence groups -// globals - -SENTENCEG rgsentenceg[CSENTENCEG_MAX]; -int fSentencesInit = FALSE; - -char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -int gcallsentences = 0; - -// randomize list of sentence name indices - -void USENTENCEG_InitLRU(unsigned char *plru, int count) -{ - int i, j, k; - unsigned char temp; - - if (!fSentencesInit) - return; - - if (count > CSENTENCE_LRU_MAX) - count = CSENTENCE_LRU_MAX; - - for (i = 0; i < count; i++) - plru[i] = (unsigned char) i; - - // randomize array - for (i = 0; i < (count * 4); i++) - { - j = RANDOM_LONG(0,count-1); - k = RANDOM_LONG(0,count-1); - temp = plru[j]; - plru[j] = plru[k]; - plru[k] = temp; - } -} - -// ignore lru. pick next sentence from sentence group. Go in order until we hit the last sentence, -// then repeat list if freset is true. If freset is false, then repeat last sentence. -// ipick is passed in as the requested sentence ordinal. -// ipick 'next' is returned. -// return of -1 indicates an error. - -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) -{ - char *szgroupname; - unsigned char count; - char sznum[8]; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - - if (count == 0) - return -1; - - if (ipick >= count) - ipick = count-1; - - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - - if (ipick >= count) - { - if (freset) - // reset at end of list - return 0; - else - return count; - } - - return ipick + 1; -} - - - -// pick a random sentence from rootname0 to rootnameX. -// picks from the rgsentenceg[isentenceg] least -// recently used, modifies lru array. returns the sentencename. -// note, lru must be seeded with 0-n randomized sentence numbers, with the -// rest of the lru filled with -1. The first integer in the lru is -// actually the size of the list. Returns ipick, the ordinal -// of the picked sentence within the group. - -int USENTENCEG_Pick(int isentenceg, char *szfound) -{ - char *szgroupname; - unsigned char *plru; - unsigned char i; - unsigned char count; - char sznum[8]; - unsigned char ipick; - int ffound = FALSE; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - plru = rgsentenceg[isentenceg].rgblru; - - while (!ffound) - { - for (i = 0; i < count; i++) - if (plru[i] != 0xFF) - { - ipick = plru[i]; - plru[i] = 0xFF; - ffound = TRUE; - break; - } - - if (!ffound) - USENTENCEG_InitLRU(plru, count); - else - { - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - return ipick; - } - } - return -1; -} - -// ===================== SENTENCE GROUPS, MAIN ROUTINES ======================== - -// Given sentence group rootname (name without number suffix), -// get sentence group index (isentenceg). Returns -1 if no such name. - -int SENTENCEG_GetIndex(const char *szgroupname) -{ - int i; - - if (!fSentencesInit || !szgroupname) - return -1; - - // search rgsentenceg for match on szgroupname - - i = 0; - while (rgsentenceg[i].count) - { - if (!strcmp(szgroupname, rgsentenceg[i].szgroupname)) - return i; - i++; - } - - return -1; -} - -// given sentence group index, play random sentence for given entity. -// returns ipick - which sentence was picked to -// play from the group. Ipick is only needed if you plan on stopping -// the sound before playback is done (see SENTENCEG_Stop). - -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick > 0 && name) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipick; -} - -// same as above, but takes sentence group name instead of index - -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - { - ALERT( at_console, "No such sentence group %s\n", szgroupname ); - return -1; - } - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - - return ipick; -} - -// play sentences in sequential order from sentence group. Reset after last sentence. - -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch, int ipick, int freset) -{ - char name[64]; - int ipicknext; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - return -1; - - ipicknext = USENTENCEG_PickSequential(isentenceg, name, ipick, freset); - if (ipicknext >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipicknext; -} - - -// for this entity, for the given sentence within the sentence group, stop -// the sentence. - -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) -{ - char buffer[64]; - char sznum[8]; - - if (!fSentencesInit) - return; - - if (isentenceg < 0 || ipick < 0) - return; - - strcpy(buffer, "!"); - strcat(buffer, rgsentenceg[isentenceg].szgroupname); - sprintf(sznum, "%d", ipick); - strcat(buffer, sznum); - - STOP_SOUND(entity, CHAN_VOICE, buffer); -} - -// open sentences.txt, scan for groups, build rgsentenceg -// Should be called from world spawn, only works on the -// first call and is ignored subsequently. - -void SENTENCEG_Init() -{ - char buffer[512]; - char szgroup[64]; - int i, j; - int isentencegs; - - if (fSentencesInit) - return; - - memset(gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX); - gcallsentences = 0; - - memset(rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG)); - memset(buffer, 0, 512); - memset(szgroup, 0, 64); - isentencegs = -1; - - - int filePos = 0, fileSize; - byte *pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/sentences.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while ( memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL ) - { - // skip whitespace - i = 0; - while(buffer[i] && buffer[i] == ' ') - i++; - - if (!buffer[i]) - continue; - - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get sentence name - j = i; - while (buffer[j] && buffer[j] != ' ') - j++; - - if (!buffer[j]) - continue; - - if (gcallsentences > CVOXFILESENTENCEMAX) - { - ALERT (at_error, "Too many sentences in sentences.txt!\n"); - break; - } - - // null-terminate name and save in sentences array - buffer[j] = 0; - const char *pString = buffer + i; - - if ( strlen( pString ) >= CBSENTENCENAME_MAX ) - ALERT( at_warning, "Sentence %s longer than %d letters\n", pString, CBSENTENCENAME_MAX-1 ); - - strcpy( gszallsentencenames[gcallsentences++], pString ); - - j--; - if (j <= i) - continue; - if (!isdigit(buffer[j])) - continue; - - // cut out suffix numbers - while (j > i && isdigit(buffer[j])) - j--; - - if (j <= i) - continue; - - buffer[j+1] = 0; - - // if new name doesn't match previous group name, - // make a new group. - - if (strcmp(szgroup, &(buffer[i]))) - { - // name doesn't match with prev name, - // copy name into group, init count to 1 - isentencegs++; - if (isentencegs >= CSENTENCEG_MAX) - { - ALERT (at_error, "Too many sentence groups in sentences.txt!\n"); - break; - } - - strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); - rgsentenceg[isentencegs].count = 1; - - strcpy(szgroup, &(buffer[i])); - - continue; - } - else - { - //name matches with previous, increment group count - if (isentencegs >= 0) - rgsentenceg[isentencegs].count++; - } - } - - g_engfuncs.pfnFreeFile( pMemFile ); - - fSentencesInit = TRUE; - - // init lru lists - - i = 0; - - while (rgsentenceg[i].count && i < CSENTENCEG_MAX) - { - USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); - i++; - } - -} - -// convert sentence (sample) name to !sentencenum, return !sentencenum - -int SENTENCEG_Lookup(const char *sample, char *sentencenum) -{ - char sznum[8]; - -//#ifdef GERMANY -// return -1; // no constructed sentences in international versions -//#endif // GERMANY - - int i; - // this is a sentence name; lookup sentence number - // and give to engine as string. - for (i = 0; i < gcallsentences; i++) - if (!stricmp(gszallsentencenames[i], sample+1)) - { - if (sentencenum) - { - strcpy(sentencenum, "!"); - sprintf(sznum, "%d", i); - strcat(sentencenum, sznum); - } - return i; - } - // sentence name not found! - return -1; -} - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch) -{ - if (sample && *sample == '!') - { - char name[32]; - if (SENTENCEG_Lookup(sample, name) >= 0) - EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); - else - ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); - } - else - EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch); -} - -// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - EMIT_SOUND_DYN(entity, CHAN_STATIC, sample, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in group id, over the HEV suit speaker - -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndI(entity, isentenceg, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in groupname - -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndSz(entity, groupname, fvol, ATTN_NORM, 0, pitch); -} - -// ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ======================== -// -// Used to detect the texture the player is standing on, map the -// texture name to a material type. Play footstep sound based -// on material type. - -int fTextureTypeInit = FALSE; - -#define CTEXTURESMAX 512 // max number of textures loaded - -int gcTextures = 0; -char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; // texture names -char grgchTextureType[CTEXTURESMAX]; // parallel array of texture types - -// open materials.txt, get size, alloc space, -// save in array. Only works first time called, -// ignored on subsequent calls. - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ) -{ - // Bullet-proofing - if ( !pMemFile || !pBuffer ) - return NULL; - - if ( filePos >= fileSize ) - return NULL; - - int i = filePos; - int last = fileSize; - - // fgets always NULL terminates, so only read bufferSize-1 characters - if ( last - filePos > (bufferSize-1) ) - last = filePos + (bufferSize-1); - - int stop = 0; - - // Stop at the next newline (inclusive) or end of buffer - while ( i < last && !stop ) - { - if ( pMemFile[i] == '\n' ) - stop = 1; - i++; - } - - - // If we actually advanced the pointer, copy it over - if ( i != filePos ) - { - // We read in size bytes - int size = i - filePos; - // copy it out - memcpy( pBuffer, pMemFile + filePos, sizeof(byte)*size ); - - // If the buffer isn't full, terminate (this is always true) - if ( size < bufferSize ) - pBuffer[size] = 0; - - // Update file pointer - filePos = i; - return pBuffer; - } - - // No data read, bail - return NULL; -} - - -void TEXTURETYPE_Init() -{ - char buffer[512]; - int i, j; - byte *pMemFile; - int fileSize, filePos; - - if (fTextureTypeInit) - return; - - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); - - gcTextures = 0; - memset(buffer, 0, 512); - - pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/materials.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while (memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL && (gcTextures < CTEXTURESMAX)) - { - // skip whitespace - i = 0; - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); - - // skip whitespace - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // get sentence name - j = i; - while (buffer[j] && !isspace(buffer[j])) - j++; - - if (!buffer[j]) - continue; - - // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); - buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); - } - - g_engfuncs.pfnFreeFile( pMemFile ); - - fTextureTypeInit = TRUE; -} - -// given texture name, find texture type -// if not found, return type 'concrete' - -// NOTE: this routine should ONLY be called if the -// current texture under the player changes! - -char TEXTURETYPE_Find(char *name) -{ - // CONSIDER: pre-sort texture names and perform faster binary search here - - for (int i = 0; i < gcTextures; i++) - { - if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) - return (grgchTextureType[i]); - } - - return CHAR_TEX_CONCRETE; -} - -// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the -// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. -// returns volume of strike instrument (crowbar) to play - -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType) -{ -// hit the world, try to play sound based on texture material type - - char chTextureType; - float fvol; - float fvolbar; - char szbuffer[64]; - const char *pTextureName; - float rgfl1[3]; - float rgfl2[3]; - char *rgsz[4]; - int cnt; - float fattn = ATTN_NORM; - - if ( !g_pGameRules->PlayTextureSounds() ) - return 0.0; - - CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); - - chTextureType = 0; - - if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) - // hit body - chTextureType = CHAR_TEX_FLESH; - else - { - // hit world - - // find texture under strike, get material type - - // copy trace vector into array for trace_texture - - vecSrc.CopyToArray(rgfl1); - vecEnd.CopyToArray(rgfl2); - - // get texture from entity or world (world is ent(0)) - if (pEntity) - pTextureName = TRACE_TEXTURE( ENT(pEntity->pev), rgfl1, rgfl2 ); - else - pTextureName = TRACE_TEXTURE( ENT(0), rgfl1, rgfl2 ); - - if ( pTextureName ) - { - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - pTextureName += 2; - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - pTextureName++; - // '}}' - strcpy(szbuffer, pTextureName); - szbuffer[CBTEXTURENAMEMAX - 1] = 0; - - // ALERT ( at_console, "texture hit: %s\n", szbuffer); - - // get texture type - chTextureType = TEXTURETYPE_Find(szbuffer); - } - } - - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; - rgsz[0] = "player/pl_step1.wav"; - rgsz[1] = "player/pl_step2.wav"; - cnt = 2; - break; - case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3; - rgsz[0] = "player/pl_metal1.wav"; - rgsz[1] = "player/pl_metal2.wav"; - cnt = 2; - break; - case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; - rgsz[0] = "player/pl_dirt1.wav"; - rgsz[1] = "player/pl_dirt2.wav"; - rgsz[2] = "player/pl_dirt3.wav"; - cnt = 3; - break; - case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; - rgsz[0] = "player/pl_duct1.wav"; - rgsz[1] = "player/pl_duct1.wav"; - cnt = 2; - break; - case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; - rgsz[0] = "player/pl_grate1.wav"; - rgsz[1] = "player/pl_grate4.wav"; - cnt = 2; - break; - case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "player/pl_tile1.wav"; - rgsz[1] = "player/pl_tile3.wav"; - rgsz[2] = "player/pl_tile2.wav"; - rgsz[3] = "player/pl_tile4.wav"; - cnt = 4; - break; - case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; - rgsz[0] = "player/pl_slosh1.wav"; - rgsz[1] = "player/pl_slosh3.wav"; - rgsz[2] = "player/pl_slosh2.wav"; - rgsz[3] = "player/pl_slosh4.wav"; - cnt = 4; - break; - case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; - rgsz[0] = "debris/wood1.wav"; - rgsz[1] = "debris/wood2.wav"; - rgsz[2] = "debris/wood3.wav"; - cnt = 3; - break; - case CHAR_TEX_GLASS: - case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "debris/glass1.wav"; - rgsz[1] = "debris/glass2.wav"; - rgsz[2] = "debris/glass3.wav"; - cnt = 3; - break; - case CHAR_TEX_FLESH: - //if (iBulletType == BULLET_PLAYER_CROWBAR) - // return 0.0; // crowbar already makes this sound - fvol = 1.0; fvolbar = 0.2; - rgsz[0] = "weapons/bullet_hit1.wav"; - rgsz[1] = "weapons/bullet_hit2.wav"; - fattn = 1.0; - cnt = 2; - break; - } - - // did we hit a breakable? - - if (pEntity && FClassnameIs(pEntity->pev, "func_breakable")) - { - // drop volumes, the object will already play a damaged sound - fvol /= 1.5; - fvolbar /= 2.0; - } - else if (chTextureType == CHAR_TEX_COMPUTER) - { - // play random spark if computer - - if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark5.wav", flVolume, ATTN_NORM, 0, 100); break; - case 1: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark6.wav", flVolume, ATTN_NORM, 0, 100); break; - // case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - // case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } - } - } - - // play material hit sound - UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, rgsz[RANDOM_LONG(0,cnt-1)], fvol, fattn, 0, 96 + RANDOM_LONG(0,0xf)); - //EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, rgsz[RANDOM_LONG(0,cnt-1)], fvol, ATTN_NORM, 0, 96 + RANDOM_LONG(0,0xf)); - - return fvolbar; -} - -// =================================================================================== -// -// Speaker class. Used for announcements per level, for door lock/unlock spoken voice. -// - -class CSpeaker : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT SpeakerThink( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - int m_preset; // preset number -}; - -LINK_ENTITY_TO_CLASS( speaker, CSpeaker ); -TYPEDESCRIPTION CSpeaker::m_SaveData[] = -{ - DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CSpeaker :: Spawn( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !m_preset && (FStringNull( pev->message ) || strlen( szSoundFile ) < 1 )) - { - ALERT( at_error, "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CSpeaker::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - - SetThink(&CSpeaker::SpeakerThink); - pev->nextthink = 0.0; - - // allow on/off switching via 'use' function. - - SetUse ( &CSpeaker::ToggleUse ); - - Precache( ); -} - -#define ANNOUNCE_MINUTES_MIN 0.25 -#define ANNOUNCE_MINUTES_MAX 2.25 - -void CSpeaker :: Precache( void ) -{ - if ( !FBitSet (pev->spawnflags, SPEAKER_START_SILENT ) ) - // set first announcement time for random n second - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(5.0, 15.0); -} -void CSpeaker :: SpeakerThink( void ) -{ - char* szSoundFile; - float flvolume = pev->health * 0.1; - float flattenuation = 0.3; - int flags = 0; - int pitch = 100; - - - // Wait for the talkmonster to finish first. - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - { - pev->nextthink = CTalkMonster::g_talkWaitTime + RANDOM_FLOAT( 5, 10 ); - return; - } - - if (m_preset) - { - // go lookup preset text, assign szSoundFile - switch (m_preset) - { - case 1: szSoundFile = "C1A0_"; break; - case 2: szSoundFile = "C1A1_"; break; - case 3: szSoundFile = "C1A2_"; break; - case 4: szSoundFile = "C1A3_"; break; - case 5: szSoundFile = "C1A4_"; break; - case 6: szSoundFile = "C2A1_"; break; - case 7: szSoundFile = "C2A2_"; break; - case 8: szSoundFile = "C2A3_"; break; - case 9: szSoundFile = "C2A4_"; break; - case 10: szSoundFile = "C2A5_"; break; - case 11: szSoundFile = "C3A1_"; break; - case 12: szSoundFile = "C3A2_"; break; - } - } else - szSoundFile = (char*) STRING(pev->message); - - if (szSoundFile[0] == '!') - { - // play single sentence, one shot - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - flvolume, flattenuation, flags, pitch); - - // shut off and reset - pev->nextthink = 0.0; - } - else - { - // make random announcement from sentence group - - if (SENTENCEG_PlayRndSz(ENT(pev), szSoundFile, flvolume, flattenuation, flags, pitch) < 0) - ALERT(at_console, "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile); - - // set next announcement time for random 5 to 10 minute delay - pev->nextthink = gpGlobals->time + - RANDOM_FLOAT(ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0); - - CTalkMonster::g_talkWaitTime = gpGlobals->time + 5; // time delay until it's ok to speak: used so that two NPCs don't talk at once - } - - return; -} - - -// -// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one. -// -void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fActive = (pev->nextthink > 0.0); - - // fActive is TRUE only if an announcement is pending - - if ( useType != USE_TOGGLE ) - { - // ignore if we're just turning something on that's already on, or - // turning something off that's already off. - if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) ) - return; - } - - if ( useType == USE_ON ) - { - // turn on announcements - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - if ( useType == USE_OFF ) - { - // turn off announcements - pev->nextthink = 0.0; - return; - - } - - // Toggle announcements - - - if ( fActive ) - { - // turn off announcements - pev->nextthink = 0.0; - } - else - { - // turn on announcements - pev->nextthink = gpGlobals->time + 0.1; - } -} - -// KeyValue - load keyvalue pairs into member data -// NOTE: called BEFORE spawn! - -void CSpeaker :: KeyValue( KeyValueData *pkvd ) -{ - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// sound.cpp +//========================================================= + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "weapons.h" +#include "player.h" +#include "talkmonster.h" +#include "gamerules.h" +#include "../mod/AvHSpecials.h" + +static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); + + +// ==================== GENERIC AMBIENT SOUND ====================================== + +// runtime pitch shift and volume fadein/out structure + +// NOTE: IF YOU CHANGE THIS STRUCT YOU MUST CHANGE THE SAVE/RESTORE VERSION NUMBER +// SEE BELOW (in the typedescription for the class) +typedef struct dynpitchvol +{ + // NOTE: do not change the order of these parameters + // NOTE: unless you also change order of rgdpvpreset array elements! + int preset; + + int pitchrun; // pitch shift % when sound is running 0 - 255 + int pitchstart; // pitch shift % when sound stops or starts 0 - 255 + int spinup; // spinup time 0 - 100 + int spindown; // spindown time 0 - 100 + + int volrun; // volume change % when sound is running 0 - 10 + int volstart; // volume change % when sound stops or starts 0 - 10 + int fadein; // volume fade in time 0 - 100 + int fadeout; // volume fade out time 0 - 100 + + // Low Frequency Oscillator + int lfotype; // 0) off 1) square 2) triangle 3) random + int lforate; // 0 - 1000, how fast lfo osciallates + + int lfomodpitch; // 0-100 mod of current pitch. 0 is off. + int lfomodvol; // 0-100 mod of current volume. 0 is off. + + int cspinup; // each trigger hit increments counter and spinup pitch + + + int cspincount; + + int pitch; + int spinupsav; + int spindownsav; + int pitchfrac; + + int vol; + int fadeinsav; + int fadeoutsav; + int volfrac; + + int lfofrac; + int lfomult; + + +} dynpitchvol_t; + +#define CDPVPRESETMAX 27 + +// presets for runtime pitch and vol modulation of ambient sounds + +dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = +{ +// pitch pstart spinup spindwn volrun volstrt fadein fadeout lfotype lforate modptch modvol cspnup +{1, 255, 75, 95, 95, 10, 1, 50, 95, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{2, 255, 85, 70, 88, 10, 1, 20, 88, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{3, 255, 100, 50, 75, 10, 1, 10, 75, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{4, 100, 100, 0, 0, 10, 1, 90, 90, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{5, 100, 100, 0, 0, 10, 1, 80, 80, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{6, 100, 100, 0, 0, 10, 1, 50, 70, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{7, 100, 100, 0, 0, 5, 1, 40, 50, 1, 50, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, +{8, 100, 100, 0, 0, 5, 1, 40, 50, 1, 150, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, +{9, 100, 100, 0, 0, 5, 1, 40, 50, 1, 750, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, +{10,128, 100, 50, 75, 10, 1, 30, 40, 2, 8, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{11,128, 100, 50, 75, 10, 1, 30, 40, 2, 25, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{12,128, 100, 50, 75, 10, 1, 30, 40, 2, 70, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{13,50, 50, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{14,70, 70, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{15,90, 90, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{16,120, 120, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{17,180, 180, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{18,255, 255, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{19,200, 75, 90, 90, 10, 1, 50, 90, 2, 100, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{20,255, 75, 97, 90, 10, 1, 50, 90, 1, 40, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{21,100, 100, 0, 0, 10, 1, 30, 50, 3, 15, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{22,160, 160, 0, 0, 10, 1, 50, 50, 3, 500, 25, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{23,255, 75, 88, 0, 10, 1, 40, 0, 0, 0, 0, 0, 5, 0,0,0,0,0,0,0,0,0,0}, +{24,200, 20, 95, 70, 10, 1, 70, 70, 3, 20, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, +{25,180, 100, 50, 60, 10, 1, 40, 60, 2, 90, 100, 100, 0, 0,0,0,0,0,0,0,0,0,0}, +{26,60, 60, 0, 0, 10, 1, 40, 70, 3, 80, 20, 50, 0, 0,0,0,0,0,0,0,0,0,0}, +{27,128, 90, 10, 10, 10, 1, 20, 40, 1, 5, 10, 20, 0, 0,0,0,0,0,0,0,0,0,0} +}; + +class CAmbientGeneric : public CBaseEntity +{ +public: + void KeyValue( KeyValueData* pkvd); + void Spawn( void ); + void Precache( void ); + void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT RampThink( void ); + void InitModulationParms(void); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + + float m_flAttenuation; // attenuation value + dynpitchvol_t m_dpv; + + BOOL m_fActive; // only TRUE when the entity is playing a looping sound + BOOL m_fLooping; // TRUE when the sound played will loop +}; + +LINK_ENTITY_TO_CLASS( ambient_generic, CAmbientGeneric ); +TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = +{ + DEFINE_FIELD( CAmbientGeneric, m_flAttenuation, FIELD_FLOAT ), + DEFINE_FIELD( CAmbientGeneric, m_fActive, FIELD_BOOLEAN ), + DEFINE_FIELD( CAmbientGeneric, m_fLooping, FIELD_BOOLEAN ), + + // HACKHACK - This is not really in the spirit of the save/restore design, but save this + // out as a binary data block. If the dynpitchvol_t is changed, old saved games will NOT + // load these correctly, so bump the save/restore version if you change the size of the struct + // The right way to do this is to split the input parms (read in keyvalue) into members and re-init this + // struct in Precache(), but it's unlikely that the struct will change, so it's not worth the time right now. + DEFINE_ARRAY( CAmbientGeneric, m_dpv, FIELD_CHARACTER, sizeof(dynpitchvol_t) ), +}; + +IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ); + +// +// ambient_generic - general-purpose user-defined static sound +// +void CAmbientGeneric :: Spawn( void ) +{ +/* + -1 : "Default" + 0 : "Everywhere" + 200 : "Small Radius" + 125 : "Medium Radius" + 80 : "Large Radius" +*/ + + if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) + { + m_flAttenuation = ATTN_NONE; + } + else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) + { + m_flAttenuation = ATTN_IDLE; + } + else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) + { + m_flAttenuation = ATTN_STATIC; + } + else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) + { + m_flAttenuation = ATTN_NORM; + } + else + {// if the designer didn't set a sound attenuation, default to one. + m_flAttenuation = ATTN_STATIC; + } + + char* szSoundFile = (char*) STRING(pev->message); + + if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) + { + ALERT( at_error, "EMPTY AMBIENT AT: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CAmbientGeneric::SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + + // Set up think function for dynamic modification + // of ambient sound's pitch or volume. Don't + // start thinking yet. + + SetThink(&CAmbientGeneric::RampThink); + pev->nextthink = 0; + + // allow on/off switching via 'use' function. + + SetUse ( &CAmbientGeneric::ToggleUse ); + + m_fActive = FALSE; + + if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) + m_fLooping = FALSE; + else + m_fLooping = TRUE; + Precache( ); +} + + +void CAmbientGeneric :: Precache( void ) +{ + char* szSoundFile = (char*) STRING(pev->message); + + if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) + { + if (*szSoundFile != '!') + PRECACHE_SOUND(szSoundFile); + } + // init all dynamic modulation parms + InitModulationParms(); + + if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) + { + // start the sound ASAP + if (m_fLooping) + m_fActive = TRUE; + } + if ( m_fActive ) + { + UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, + (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); + + pev->nextthink = gpGlobals->time + 0.1; + } +} + +// RampThink - Think at 5hz if we are dynamically modifying +// pitch or volume of the playing sound. This function will +// ramp pitch and/or volume up or down, modify pitch/volume +// with lfo if active. + +void CAmbientGeneric :: RampThink( void ) +{ + char* szSoundFile = (char*) STRING(pev->message); + int pitch = m_dpv.pitch; + int vol = m_dpv.vol; + int flags = 0; + int fChanged = 0; // FALSE if pitch and vol remain unchanged this round + int prev; + + if (!m_dpv.spinup && !m_dpv.spindown && !m_dpv.fadein && !m_dpv.fadeout && !m_dpv.lfotype) + return; // no ramps or lfo, stop thinking + + // ============== + // pitch envelope + // ============== + if (m_dpv.spinup || m_dpv.spindown) + { + prev = m_dpv.pitchfrac >> 8; + + if (m_dpv.spinup > 0) + m_dpv.pitchfrac += m_dpv.spinup; + else if (m_dpv.spindown > 0) + m_dpv.pitchfrac -= m_dpv.spindown; + + pitch = m_dpv.pitchfrac >> 8; + + if (pitch > m_dpv.pitchrun) + { + pitch = m_dpv.pitchrun; + m_dpv.spinup = 0; // done with ramp up + } + + if (pitch < m_dpv.pitchstart) + { + pitch = m_dpv.pitchstart; + m_dpv.spindown = 0; // done with ramp down + + // shut sound off + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + 0, 0, SND_STOP, 0); + + // return without setting nextthink + return; + } + + if (pitch > 255) pitch = 255; + if (pitch < 1) pitch = 1; + + m_dpv.pitch = pitch; + + fChanged |= (prev != pitch); + flags |= SND_CHANGE_PITCH; + } + + // ================== + // amplitude envelope + // ================== + if (m_dpv.fadein || m_dpv.fadeout) + { + prev = m_dpv.volfrac >> 8; + + if (m_dpv.fadein > 0) + m_dpv.volfrac += m_dpv.fadein; + else if (m_dpv.fadeout > 0) + m_dpv.volfrac -= m_dpv.fadeout; + + vol = m_dpv.volfrac >> 8; + + if (vol > m_dpv.volrun) + { + vol = m_dpv.volrun; + m_dpv.fadein = 0; // done with ramp up + } + + if (vol < m_dpv.volstart) + { + vol = m_dpv.volstart; + m_dpv.fadeout = 0; // done with ramp down + + // shut sound off + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + 0, 0, SND_STOP, 0); + + // return without setting nextthink + return; + } + + if (vol > 100) vol = 100; + if (vol < 1) vol = 1; + + m_dpv.vol = vol; + + fChanged |= (prev != vol); + flags |= SND_CHANGE_VOL; + } + + // =================== + // pitch/amplitude LFO + // =================== + if (m_dpv.lfotype) + { + int pos; + + if (m_dpv.lfofrac > 0x6fffffff) + m_dpv.lfofrac = 0; + + // update lfo, lfofrac/255 makes a triangle wave 0-255 + m_dpv.lfofrac += m_dpv.lforate; + pos = m_dpv.lfofrac >> 8; + + if (m_dpv.lfofrac < 0) + { + m_dpv.lfofrac = 0; + m_dpv.lforate = abs(m_dpv.lforate); + pos = 0; + } + else if (pos > 255) + { + pos = 255; + m_dpv.lfofrac = (255 << 8); + m_dpv.lforate = -abs(m_dpv.lforate); + } + + switch(m_dpv.lfotype) + { + case LFO_SQUARE: + if (pos < 128) + m_dpv.lfomult = 255; + else + m_dpv.lfomult = 0; + + break; + case LFO_RANDOM: + if (pos == 255) + m_dpv.lfomult = RANDOM_LONG(0, 255); + break; + case LFO_TRIANGLE: + default: + m_dpv.lfomult = pos; + break; + } + + if (m_dpv.lfomodpitch) + { + prev = pitch; + + // pitch 0-255 + pitch += ((m_dpv.lfomult - 128) * m_dpv.lfomodpitch) / 100; + + if (pitch > 255) pitch = 255; + if (pitch < 1) pitch = 1; + + + fChanged |= (prev != pitch); + flags |= SND_CHANGE_PITCH; + } + + if (m_dpv.lfomodvol) + { + // vol 0-100 + prev = vol; + + vol += ((m_dpv.lfomult - 128) * m_dpv.lfomodvol) / 100; + + if (vol > 100) vol = 100; + if (vol < 0) vol = 0; + + fChanged |= (prev != vol); + flags |= SND_CHANGE_VOL; + } + + } + + // Send update to playing sound only if we actually changed + // pitch or volume in this routine. + + if (flags && fChanged) + { + if (pitch == PITCH_NORM) + pitch = PITCH_NORM + 1; // don't send 'no pitch' ! + + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + (vol * 0.01), m_flAttenuation, flags, pitch); + } + + // update ramps at 5hz + pev->nextthink = gpGlobals->time + 0.2; + return; +} + +// Init all ramp params in preparation to +// play a new sound + +void CAmbientGeneric :: InitModulationParms(void) +{ + int pitchinc; + + m_dpv.volrun = pev->health * 10; // 0 - 100 + if (m_dpv.volrun > 100) m_dpv.volrun = 100; + if (m_dpv.volrun < 0) m_dpv.volrun = 0; + + // get presets + if (m_dpv.preset != 0 && m_dpv.preset <= CDPVPRESETMAX) + { + // load preset values + m_dpv = rgdpvpreset[m_dpv.preset - 1]; + + // fixup preset values, just like + // fixups in KeyValue routine. + if (m_dpv.spindown > 0) + m_dpv.spindown = (101 - m_dpv.spindown) * 64; + if (m_dpv.spinup > 0) + m_dpv.spinup = (101 - m_dpv.spinup) * 64; + + m_dpv.volstart *= 10; + m_dpv.volrun *= 10; + + if (m_dpv.fadein > 0) + m_dpv.fadein = (101 - m_dpv.fadein) * 64; + if (m_dpv.fadeout > 0) + m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; + + m_dpv.lforate *= 256; + + m_dpv.fadeinsav = m_dpv.fadein; + m_dpv.fadeoutsav = m_dpv.fadeout; + m_dpv.spinupsav = m_dpv.spinup; + m_dpv.spindownsav = m_dpv.spindown; + } + + m_dpv.fadein = m_dpv.fadeinsav; + m_dpv.fadeout = 0; + + if (m_dpv.fadein) + m_dpv.vol = m_dpv.volstart; + else + m_dpv.vol = m_dpv.volrun; + + m_dpv.spinup = m_dpv.spinupsav; + m_dpv.spindown = 0; + + if (m_dpv.spinup) + m_dpv.pitch = m_dpv.pitchstart; + else + m_dpv.pitch = m_dpv.pitchrun; + + if (m_dpv.pitch == 0) + m_dpv.pitch = PITCH_NORM; + + m_dpv.pitchfrac = m_dpv.pitch << 8; + m_dpv.volfrac = m_dpv.vol << 8; + + m_dpv.lfofrac = 0; + m_dpv.lforate = abs(m_dpv.lforate); + + m_dpv.cspincount = 1; + + if (m_dpv.cspinup) + { + pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; + + m_dpv.pitchrun = m_dpv.pitchstart + pitchinc; + if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; + } + + if ((m_dpv.spinupsav || m_dpv.spindownsav || (m_dpv.lfotype && m_dpv.lfomodpitch)) + && (m_dpv.pitch == PITCH_NORM)) + m_dpv.pitch = PITCH_NORM + 1; // must never send 'no pitch' as first pitch + // if we intend to pitch shift later! +} + +// +// ToggleUse - turns an ambient sound on or off. If the +// ambient is a looping sound, mark sound as active (m_fActive) +// if it's playing, innactive if not. If the sound is not +// a looping sound, never mark it as active. +// +void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + char* szSoundFile = (char*) STRING(pev->message); + float fraction; + + if ( useType != USE_TOGGLE ) + { + if ( (m_fActive && useType == USE_ON) || (!m_fActive && useType == USE_OFF) ) + return; + } + // Directly change pitch if arg passed. Only works if sound is already playing. + + if (useType == USE_SET && m_fActive) // Momentary buttons will pass down a float in here + { + + fraction = value; + + if ( fraction > 1.0 ) + fraction = 1.0; + if (fraction < 0.0) + fraction = 0.01; + + m_dpv.pitch = fraction * 255; + + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); + + return; + } + + // Toggle + + // m_fActive is TRUE only if a looping sound is playing. + + if ( m_fActive ) + {// turn sound off + + if (m_dpv.cspinup) + { + // Don't actually shut off. Each toggle causes + // incremental spinup to max pitch + + if (m_dpv.cspincount <= m_dpv.cspinup) + { + int pitchinc; + + // start a new spinup + m_dpv.cspincount++; + + pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; + + m_dpv.spinup = m_dpv.spinupsav; + m_dpv.spindown = 0; + + m_dpv.pitchrun = m_dpv.pitchstart + pitchinc * m_dpv.cspincount; + if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; + + pev->nextthink = gpGlobals->time + 0.1; + } + + } + else + { + m_fActive = FALSE; + + // HACKHACK - this makes the code in Precache() work properly after a save/restore + pev->spawnflags |= AMBIENT_SOUND_START_SILENT; + + if (m_dpv.spindownsav || m_dpv.fadeoutsav) + { + // spin it down (or fade it) before shutoff if spindown is set + m_dpv.spindown = m_dpv.spindownsav; + m_dpv.spinup = 0; + + m_dpv.fadeout = m_dpv.fadeoutsav; + m_dpv.fadein = 0; + pev->nextthink = gpGlobals->time + 0.1; + } + else + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + 0, 0, SND_STOP, 0); + } + } + else + {// turn sound on + + // only toggle if this is a looping sound. If not looping, each + // trigger will cause the sound to play. If the sound is still + // playing from a previous trigger press, it will be shut off + // and then restarted. + + if (m_fLooping) + m_fActive = TRUE; + else + // shut sound off now - may be interrupting a long non-looping sound + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + 0, 0, SND_STOP, 0); + + // init all ramp params for startup + + InitModulationParms(); + + UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, + (m_dpv.vol * 0.01), m_flAttenuation, 0, m_dpv.pitch); + + pev->nextthink = gpGlobals->time + 0.1; + + } +} +// KeyValue - load keyvalue pairs into member data of the +// ambient generic. NOTE: called BEFORE spawn! + +void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) +{ + // NOTE: changing any of the modifiers in this code + // NOTE: also requires changing InitModulationParms code. + + // preset + if (FStrEq(pkvd->szKeyName, "preset")) + { + m_dpv.preset = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + + // pitchrun + else if (FStrEq(pkvd->szKeyName, "pitch")) + { + m_dpv.pitchrun = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + + if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; + if (m_dpv.pitchrun < 0) m_dpv.pitchrun = 0; + } + + // pitchstart + else if (FStrEq(pkvd->szKeyName, "pitchstart")) + { + m_dpv.pitchstart = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + + if (m_dpv.pitchstart > 255) m_dpv.pitchstart = 255; + if (m_dpv.pitchstart < 0) m_dpv.pitchstart = 0; + } + + // spinup + else if (FStrEq(pkvd->szKeyName, "spinup")) + { + m_dpv.spinup = atoi(pkvd->szValue); + + if (m_dpv.spinup > 100) m_dpv.spinup = 100; + if (m_dpv.spinup < 0) m_dpv.spinup = 0; + + if (m_dpv.spinup > 0) + m_dpv.spinup = (101 - m_dpv.spinup) * 64; + m_dpv.spinupsav = m_dpv.spinup; + pkvd->fHandled = TRUE; + } + + // spindown + else if (FStrEq(pkvd->szKeyName, "spindown")) + { + m_dpv.spindown = atoi(pkvd->szValue); + + if (m_dpv.spindown > 100) m_dpv.spindown = 100; + if (m_dpv.spindown < 0) m_dpv.spindown = 0; + + if (m_dpv.spindown > 0) + m_dpv.spindown = (101 - m_dpv.spindown) * 64; + m_dpv.spindownsav = m_dpv.spindown; + pkvd->fHandled = TRUE; + } + + // volstart + else if (FStrEq(pkvd->szKeyName, "volstart")) + { + m_dpv.volstart = atoi(pkvd->szValue); + + if (m_dpv.volstart > 10) m_dpv.volstart = 10; + if (m_dpv.volstart < 0) m_dpv.volstart = 0; + + m_dpv.volstart *= 10; // 0 - 100 + + pkvd->fHandled = TRUE; + } + + // fadein + else if (FStrEq(pkvd->szKeyName, "fadein")) + { + m_dpv.fadein = atoi(pkvd->szValue); + + if (m_dpv.fadein > 100) m_dpv.fadein = 100; + if (m_dpv.fadein < 0) m_dpv.fadein = 0; + + if (m_dpv.fadein > 0) + m_dpv.fadein = (101 - m_dpv.fadein) * 64; + m_dpv.fadeinsav = m_dpv.fadein; + pkvd->fHandled = TRUE; + } + + // fadeout + else if (FStrEq(pkvd->szKeyName, "fadeout")) + { + m_dpv.fadeout = atoi(pkvd->szValue); + + if (m_dpv.fadeout > 100) m_dpv.fadeout = 100; + if (m_dpv.fadeout < 0) m_dpv.fadeout = 0; + + if (m_dpv.fadeout > 0) + m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; + m_dpv.fadeoutsav = m_dpv.fadeout; + pkvd->fHandled = TRUE; + } + + // lfotype + else if (FStrEq(pkvd->szKeyName, "lfotype")) + { + m_dpv.lfotype = atoi(pkvd->szValue); + if (m_dpv.lfotype > 4) m_dpv.lfotype = LFO_TRIANGLE; + pkvd->fHandled = TRUE; + } + + // lforate + else if (FStrEq(pkvd->szKeyName, "lforate")) + { + m_dpv.lforate = atoi(pkvd->szValue); + + if (m_dpv.lforate > 1000) m_dpv.lforate = 1000; + if (m_dpv.lforate < 0) m_dpv.lforate = 0; + + m_dpv.lforate *= 256; + + pkvd->fHandled = TRUE; + } + // lfomodpitch + else if (FStrEq(pkvd->szKeyName, "lfomodpitch")) + { + m_dpv.lfomodpitch = atoi(pkvd->szValue); + if (m_dpv.lfomodpitch > 100) m_dpv.lfomodpitch = 100; + if (m_dpv.lfomodpitch < 0) m_dpv.lfomodpitch = 0; + + + pkvd->fHandled = TRUE; + } + + // lfomodvol + else if (FStrEq(pkvd->szKeyName, "lfomodvol")) + { + m_dpv.lfomodvol = atoi(pkvd->szValue); + if (m_dpv.lfomodvol > 100) m_dpv.lfomodvol = 100; + if (m_dpv.lfomodvol < 0) m_dpv.lfomodvol = 0; + + pkvd->fHandled = TRUE; + } + + // cspinup + else if (FStrEq(pkvd->szKeyName, "cspinup")) + { + m_dpv.cspinup = atoi(pkvd->szValue); + if (m_dpv.cspinup > 100) m_dpv.cspinup = 100; + if (m_dpv.cspinup < 0) m_dpv.cspinup = 0; + + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + + +// =================== ROOM SOUND FX ========================================== + +class CEnvSound : public CPointEntity +{ +public: + void KeyValue( KeyValueData* pkvd); + void Spawn( void ); + + void Think( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + float m_flRadius; + float m_flRoomtype; +}; + +LINK_ENTITY_TO_CLASS( env_sound, CEnvSound ); +TYPEDESCRIPTION CEnvSound::m_SaveData[] = +{ + DEFINE_FIELD( CEnvSound, m_flRadius, FIELD_FLOAT ), + DEFINE_FIELD( CEnvSound, m_flRoomtype, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CEnvSound, CBaseEntity ); + + +void CEnvSound :: KeyValue( KeyValueData *pkvd ) +{ + + if (FStrEq(pkvd->szKeyName, "radius")) + { + m_flRadius = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + if (FStrEq(pkvd->szKeyName, "roomtype")) + { + m_flRoomtype = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } +} + +// returns TRUE if the given sound entity (pev) is in range +// and can see the given player entity (pevTarget) + +BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) +{ + CEnvSound *pSound = GetClassPtr( (CEnvSound *)pev ); + Vector vecSpot1 = pev->origin + pev->view_ofs; + Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; + Vector vecRange; + float flRange; + TraceResult tr; + + UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); + + // check if line of sight crosses water boundary, or is blocked + + if ((tr.fInOpen && tr.fInWater) || tr.flFraction != 1) + return FALSE; + + // calc range from sound entity to player + + vecRange = tr.vecEndPos - vecSpot1; + flRange = vecRange.Length(); + + if (pSound->m_flRadius < flRange) + return FALSE; + + if (pflRange) + *pflRange = flRange; + + return TRUE; +} + +// +// A client that is visible and in range of a sound entity will +// have its room_type set by that sound entity. If two or more +// sound entities are contending for a client, then the nearest +// sound entity to the client will set the client's room_type. +// A client's room_type will remain set to its prior value until +// a new in-range, visible sound entity resets a new room_type. +// + +// CONSIDER: if player in water state, autoset roomtype to 14,15 or 16. + +void CEnvSound :: Think( void ) +{ + // get pointer to client if visible; FIND_CLIENT_IN_PVS will + // cycle through visible clients on consecutive calls. + + edict_t *pentPlayer = FIND_CLIENT_IN_PVS(edict()); + CBasePlayer *pPlayer = NULL; + + if (FNullEnt(pentPlayer)) + goto env_sound_Think_slow; // no player in pvs of sound entity, slow it down + + pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); + float flRange; + + // Don't change sound types for players that are being digested + if(!GetHasUpgrade(pPlayer->pev->iuser4, MASK_DIGESTING)) + { + // check to see if this is the sound entity that is + // currently affecting this player + + if(!FNullEnt(pPlayer->m_pentSndLast) && (pPlayer->m_pentSndLast == ENT(pev))) { + + // this is the entity currently affecting player, check + // for validity + + if (pPlayer->m_flSndRoomtype != 0 && pPlayer->m_flSndRange != 0) { + + // we're looking at a valid sound entity affecting + // player, make sure it's still valid, update range + + if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) { + pPlayer->m_flSndRange = flRange; + goto env_sound_Think_fast; + } else { + + // current sound entity affecting player is no longer valid, + // flag this state by clearing room_type and range. + // NOTE: we do not actually change the player's room_type + // NOTE: until we have a new valid room_type to change it to. + + pPlayer->m_flSndRange = 0; + pPlayer->m_flSndRoomtype = 0; + goto env_sound_Think_slow; + } + } else { + // entity is affecting player but is out of range, + // wait passively for another entity to usurp it... + goto env_sound_Think_slow; + } + } + + // if we got this far, we're looking at an entity that is contending + // for current player sound. the closest entity to player wins. + + if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) + { + if (flRange < pPlayer->m_flSndRange || pPlayer->m_flSndRange == 0) + { + // new entity is closer to player, so it wins. + pPlayer->m_pentSndLast = ENT(pev); + pPlayer->m_flSndRoomtype = m_flRoomtype; + pPlayer->m_flSndRange = flRange; + + // send room_type command to player's server. + // this should be a rare event - once per change of room_type + // only! + + //CLIENT_COMMAND(pentPlayer, "room_type %f", m_flRoomtype); + + MESSAGE_BEGIN( MSG_ONE, SVC_ROOMTYPE, NULL, pentPlayer ); // use the magic #1 for "one client" + WRITE_SHORT( (short)m_flRoomtype ); // sequence number + MESSAGE_END(); + + // crank up nextthink rate for new active sound entity + // by falling through to think_fast... + } + // player is not closer to the contending sound entity, + // just fall through to think_fast. this effectively + // cranks up the think_rate of entities near the player. + } + } + else + { + int a = 0; + } + + // player is in pvs of sound entity, but either not visible or + // not in range. do nothing, fall through to think_fast... + +env_sound_Think_fast: + pev->nextthink = gpGlobals->time + 0.25; + return; + +env_sound_Think_slow: + pev->nextthink = gpGlobals->time + 0.75; + return; +} + +// +// env_sound - spawn a sound entity that will set player roomtype +// when player moves in range and sight. +// +// +void CEnvSound :: Spawn( ) +{ + // spread think times + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); +} + +// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== + +#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group + +// group of related sentences + +typedef struct sentenceg +{ + char szgroupname[CBSENTENCENAME_MAX]; + int count; + unsigned char rgblru[CSENTENCE_LRU_MAX]; + +} SENTENCEG; + +#define CSENTENCEG_MAX 200 // max number of sentence groups +// globals + +SENTENCEG rgsentenceg[CSENTENCEG_MAX]; +int fSentencesInit = FALSE; + +char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; +int gcallsentences = 0; + +// randomize list of sentence name indices + +void USENTENCEG_InitLRU(unsigned char *plru, int count) +{ + int i, j, k; + unsigned char temp; + + if (!fSentencesInit) + return; + + if (count > CSENTENCE_LRU_MAX) + count = CSENTENCE_LRU_MAX; + + for (i = 0; i < count; i++) + plru[i] = (unsigned char) i; + + // randomize array + for (i = 0; i < (count * 4); i++) + { + j = RANDOM_LONG(0,count-1); + k = RANDOM_LONG(0,count-1); + temp = plru[j]; + plru[j] = plru[k]; + plru[k] = temp; + } +} + +// ignore lru. pick next sentence from sentence group. Go in order until we hit the last sentence, +// then repeat list if freset is true. If freset is false, then repeat last sentence. +// ipick is passed in as the requested sentence ordinal. +// ipick 'next' is returned. +// return of -1 indicates an error. + +int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) +{ + char *szgroupname; + unsigned char count; + char sznum[8]; + + if (!fSentencesInit) + return -1; + + if (isentenceg < 0) + return -1; + + szgroupname = rgsentenceg[isentenceg].szgroupname; + count = rgsentenceg[isentenceg].count; + + if (count == 0) + return -1; + + if (ipick >= count) + ipick = count-1; + + strcpy(szfound, "!"); + strcat(szfound, szgroupname); + sprintf(sznum, "%d", ipick); + strcat(szfound, sznum); + + if (ipick >= count) + { + if (freset) + // reset at end of list + return 0; + else + return count; + } + + return ipick + 1; +} + + + +// pick a random sentence from rootname0 to rootnameX. +// picks from the rgsentenceg[isentenceg] least +// recently used, modifies lru array. returns the sentencename. +// note, lru must be seeded with 0-n randomized sentence numbers, with the +// rest of the lru filled with -1. The first integer in the lru is +// actually the size of the list. Returns ipick, the ordinal +// of the picked sentence within the group. + +int USENTENCEG_Pick(int isentenceg, char *szfound) +{ + char *szgroupname; + unsigned char *plru; + unsigned char i; + unsigned char count; + char sznum[8]; + unsigned char ipick; + int ffound = FALSE; + + if (!fSentencesInit) + return -1; + + if (isentenceg < 0) + return -1; + + szgroupname = rgsentenceg[isentenceg].szgroupname; + count = rgsentenceg[isentenceg].count; + plru = rgsentenceg[isentenceg].rgblru; + + while (!ffound) + { + for (i = 0; i < count; i++) + if (plru[i] != 0xFF) + { + ipick = plru[i]; + plru[i] = 0xFF; + ffound = TRUE; + break; + } + + if (!ffound) + USENTENCEG_InitLRU(plru, count); + else + { + strcpy(szfound, "!"); + strcat(szfound, szgroupname); + sprintf(sznum, "%d", ipick); + strcat(szfound, sznum); + return ipick; + } + } + return -1; +} + +// ===================== SENTENCE GROUPS, MAIN ROUTINES ======================== + +// Given sentence group rootname (name without number suffix), +// get sentence group index (isentenceg). Returns -1 if no such name. + +int SENTENCEG_GetIndex(const char *szgroupname) +{ + int i; + + if (!fSentencesInit || !szgroupname) + return -1; + + // search rgsentenceg for match on szgroupname + + i = 0; + while (rgsentenceg[i].count) + { + if (!strcmp(szgroupname, rgsentenceg[i].szgroupname)) + return i; + i++; + } + + return -1; +} + +// given sentence group index, play random sentence for given entity. +// returns ipick - which sentence was picked to +// play from the group. Ipick is only needed if you plan on stopping +// the sound before playback is done (see SENTENCEG_Stop). + +int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, + float volume, float attenuation, int flags, int pitch) +{ + char name[64]; + int ipick; + + if (!fSentencesInit) + return -1; + + name[0] = 0; + + ipick = USENTENCEG_Pick(isentenceg, name); + if (ipick > 0 && name) + EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); + return ipick; +} + +// same as above, but takes sentence group name instead of index + +int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, + float volume, float attenuation, int flags, int pitch) +{ + char name[64]; + int ipick; + int isentenceg; + + if (!fSentencesInit) + return -1; + + name[0] = 0; + + isentenceg = SENTENCEG_GetIndex(szgroupname); + if (isentenceg < 0) + { + ALERT( at_console, "No such sentence group %s\n", szgroupname ); + return -1; + } + + ipick = USENTENCEG_Pick(isentenceg, name); + if (ipick >= 0 && name[0]) + EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); + + return ipick; +} + +// play sentences in sequential order from sentence group. Reset after last sentence. + +int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, + float volume, float attenuation, int flags, int pitch, int ipick, int freset) +{ + char name[64]; + int ipicknext; + int isentenceg; + + if (!fSentencesInit) + return -1; + + name[0] = 0; + + isentenceg = SENTENCEG_GetIndex(szgroupname); + if (isentenceg < 0) + return -1; + + ipicknext = USENTENCEG_PickSequential(isentenceg, name, ipick, freset); + if (ipicknext >= 0 && name[0]) + EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); + return ipicknext; +} + + +// for this entity, for the given sentence within the sentence group, stop +// the sentence. + +void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) +{ + char buffer[64]; + char sznum[8]; + + if (!fSentencesInit) + return; + + if (isentenceg < 0 || ipick < 0) + return; + + strcpy(buffer, "!"); + strcat(buffer, rgsentenceg[isentenceg].szgroupname); + sprintf(sznum, "%d", ipick); + strcat(buffer, sznum); + + STOP_SOUND(entity, CHAN_VOICE, buffer); +} + +// open sentences.txt, scan for groups, build rgsentenceg +// Should be called from world spawn, only works on the +// first call and is ignored subsequently. + +void SENTENCEG_Init() +{ + char buffer[512]; + char szgroup[64]; + int i, j; + int isentencegs; + + if (fSentencesInit) + return; + + memset(gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX); + gcallsentences = 0; + + memset(rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG)); + memset(buffer, 0, 512); + memset(szgroup, 0, 64); + isentencegs = -1; + + + int filePos = 0, fileSize; + byte *pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/sentences.txt", &fileSize ); + if ( !pMemFile ) + return; + + // for each line in the file... + while ( memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL ) + { + // skip whitespace + i = 0; + while(buffer[i] && buffer[i] == ' ') + i++; + + if (!buffer[i]) + continue; + + if (buffer[i] == '/' || !isalpha(buffer[i])) + continue; + + // get sentence name + j = i; + while (buffer[j] && buffer[j] != ' ') + j++; + + if (!buffer[j]) + continue; + + if (gcallsentences > CVOXFILESENTENCEMAX) + { + ALERT (at_error, "Too many sentences in sentences.txt!\n"); + break; + } + + // null-terminate name and save in sentences array + buffer[j] = 0; + const char *pString = buffer + i; + + if ( strlen( pString ) >= CBSENTENCENAME_MAX ) + ALERT( at_warning, "Sentence %s longer than %d letters\n", pString, CBSENTENCENAME_MAX-1 ); + + strcpy( gszallsentencenames[gcallsentences++], pString ); + + j--; + if (j <= i) + continue; + if (!isdigit(buffer[j])) + continue; + + // cut out suffix numbers + while (j > i && isdigit(buffer[j])) + j--; + + if (j <= i) + continue; + + buffer[j+1] = 0; + + // if new name doesn't match previous group name, + // make a new group. + + if (strcmp(szgroup, &(buffer[i]))) + { + // name doesn't match with prev name, + // copy name into group, init count to 1 + isentencegs++; + if (isentencegs >= CSENTENCEG_MAX) + { + ALERT (at_error, "Too many sentence groups in sentences.txt!\n"); + break; + } + + strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); + rgsentenceg[isentencegs].count = 1; + + strcpy(szgroup, &(buffer[i])); + + continue; + } + else + { + //name matches with previous, increment group count + if (isentencegs >= 0) + rgsentenceg[isentencegs].count++; + } + } + + g_engfuncs.pfnFreeFile( pMemFile ); + + fSentencesInit = TRUE; + + // init lru lists + + i = 0; + + while (rgsentenceg[i].count && i < CSENTENCEG_MAX) + { + USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); + i++; + } + +} + +// convert sentence (sample) name to !sentencenum, return !sentencenum + +int SENTENCEG_Lookup(const char *sample, char *sentencenum) +{ + char sznum[8]; + +//#ifdef GERMANY +// return -1; // no constructed sentences in international versions +//#endif // GERMANY + + int i; + // this is a sentence name; lookup sentence number + // and give to engine as string. + for (i = 0; i < gcallsentences; i++) + if (!stricmp(gszallsentencenames[i], sample+1)) + { + if (sentencenum) + { + strcpy(sentencenum, "!"); + sprintf(sznum, "%d", i); + strcat(sentencenum, sznum); + } + return i; + } + // sentence name not found! + return -1; +} + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, + int flags, int pitch) +{ + if (sample && *sample == '!') + { + char name[32]; + if (SENTENCEG_Lookup(sample, name) >= 0) + EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); + else + ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); + } + else + EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch); +} + +// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename + +void EMIT_SOUND_SUIT(edict_t *entity, const char *sample) +{ + float fvol; + int pitch = PITCH_NORM; + + fvol = CVAR_GET_FLOAT("suitvolume"); + if (RANDOM_LONG(0,1)) + pitch = RANDOM_LONG(0,6) + 98; + + if (fvol > 0.05) + EMIT_SOUND_DYN(entity, CHAN_STATIC, sample, fvol, ATTN_NORM, 0, pitch); +} + +// play a sentence, randomly selected from the passed in group id, over the HEV suit speaker + +void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg) +{ + float fvol; + int pitch = PITCH_NORM; + + fvol = CVAR_GET_FLOAT("suitvolume"); + if (RANDOM_LONG(0,1)) + pitch = RANDOM_LONG(0,6) + 98; + + if (fvol > 0.05) + SENTENCEG_PlayRndI(entity, isentenceg, fvol, ATTN_NORM, 0, pitch); +} + +// play a sentence, randomly selected from the passed in groupname + +void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname) +{ + float fvol; + int pitch = PITCH_NORM; + + fvol = CVAR_GET_FLOAT("suitvolume"); + if (RANDOM_LONG(0,1)) + pitch = RANDOM_LONG(0,6) + 98; + + if (fvol > 0.05) + SENTENCEG_PlayRndSz(entity, groupname, fvol, ATTN_NORM, 0, pitch); +} + +// ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ======================== +// +// Used to detect the texture the player is standing on, map the +// texture name to a material type. Play footstep sound based +// on material type. + +int fTextureTypeInit = FALSE; + +#define CTEXTURESMAX 512 // max number of textures loaded + +int gcTextures = 0; +char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; // texture names +char grgchTextureType[CTEXTURESMAX]; // parallel array of texture types + +// open materials.txt, get size, alloc space, +// save in array. Only works first time called, +// ignored on subsequent calls. + +static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ) +{ + // Bullet-proofing + if ( !pMemFile || !pBuffer ) + return NULL; + + if ( filePos >= fileSize ) + return NULL; + + int i = filePos; + int last = fileSize; + + // fgets always NULL terminates, so only read bufferSize-1 characters + if ( last - filePos > (bufferSize-1) ) + last = filePos + (bufferSize-1); + + int stop = 0; + + // Stop at the next newline (inclusive) or end of buffer + while ( i < last && !stop ) + { + if ( pMemFile[i] == '\n' ) + stop = 1; + i++; + } + + + // If we actually advanced the pointer, copy it over + if ( i != filePos ) + { + // We read in size bytes + int size = i - filePos; + // copy it out + memcpy( pBuffer, pMemFile + filePos, sizeof(byte)*size ); + + // If the buffer isn't full, terminate (this is always true) + if ( size < bufferSize ) + pBuffer[size] = 0; + + // Update file pointer + filePos = i; + return pBuffer; + } + + // No data read, bail + return NULL; +} + + +void TEXTURETYPE_Init() +{ + char buffer[512]; + int i, j; + byte *pMemFile; + int fileSize = 0, filePos = 0; + + if (fTextureTypeInit) + return; + + memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); + memset(grgchTextureType, 0, CTEXTURESMAX); + + gcTextures = 0; + memset(buffer, 0, 512); + + pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/materials.txt", &fileSize ); + if ( !pMemFile ) + return; + + // for each line in the file... + while (memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL && (gcTextures < CTEXTURESMAX)) + { + // skip whitespace + i = 0; + while(buffer[i] && isspace(buffer[i])) + i++; + + if (!buffer[i]) + continue; + + // skip comment lines + if (buffer[i] == '/' || !isalpha(buffer[i])) + continue; + + // get texture type + grgchTextureType[gcTextures] = toupper(buffer[i++]); + + // skip whitespace + while(buffer[i] && isspace(buffer[i])) + i++; + + if (!buffer[i]) + continue; + + // get sentence name + j = i; + while (buffer[j] && !isspace(buffer[j])) + j++; + + if (!buffer[j]) + continue; + + // null-terminate name and save in sentences array + j = min (j, CBTEXTURENAMEMAX-1+i); + buffer[j] = 0; + strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); + } + + g_engfuncs.pfnFreeFile( pMemFile ); + + fTextureTypeInit = TRUE; +} + +// given texture name, find texture type +// if not found, return type 'concrete' + +// NOTE: this routine should ONLY be called if the +// current texture under the player changes! + +char TEXTURETYPE_Find(char *name) +{ + // CONSIDER: pre-sort texture names and perform faster binary search here + + for (int i = 0; i < gcTextures; i++) + { + if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) + return (grgchTextureType[i]); + } + + return CHAR_TEX_CONCRETE; +} + +// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the +// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. +// returns volume of strike instrument (crowbar) to play + +float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType) +{ +// hit the world, try to play sound based on texture material type + + char chTextureType; + float fvol; + float fvolbar; + char szbuffer[64]; + const char *pTextureName; + float rgfl1[3]; + float rgfl2[3]; + char *rgsz[4]; + int cnt; + float fattn = ATTN_NORM; + + if ( !g_pGameRules->PlayTextureSounds() ) + return 0.0; + + CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); + + chTextureType = 0; + + if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) + // hit body + chTextureType = CHAR_TEX_FLESH; + else + { + // hit world + + // find texture under strike, get material type + + // copy trace vector into array for trace_texture + + vecSrc.CopyToArray(rgfl1); + vecEnd.CopyToArray(rgfl2); + + // get texture from entity or world (world is ent(0)) + if (pEntity) + pTextureName = TRACE_TEXTURE( ENT(pEntity->pev), rgfl1, rgfl2 ); + else + pTextureName = TRACE_TEXTURE( ENT(0), rgfl1, rgfl2 ); + + if ( pTextureName ) + { + // strip leading '-0' or '+0~' or '{' or '!' + if (*pTextureName == '-' || *pTextureName == '+') + pTextureName += 2; + + if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + pTextureName++; + // '}}' + strcpy(szbuffer, pTextureName); + szbuffer[CBTEXTURENAMEMAX - 1] = 0; + + // ALERT ( at_console, "texture hit: %s\n", szbuffer); + + // get texture type + chTextureType = TEXTURETYPE_Find(szbuffer); + } + } + + switch (chTextureType) + { + default: + case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; + rgsz[0] = "player/pl_step1.wav"; + rgsz[1] = "player/pl_step2.wav"; + cnt = 2; + break; + case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3; + rgsz[0] = "player/pl_metal1.wav"; + rgsz[1] = "player/pl_metal2.wav"; + cnt = 2; + break; + case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; + rgsz[0] = "player/pl_dirt1.wav"; + rgsz[1] = "player/pl_dirt2.wav"; + rgsz[2] = "player/pl_dirt3.wav"; + cnt = 3; + break; + case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; + rgsz[0] = "player/pl_duct1.wav"; + rgsz[1] = "player/pl_duct1.wav"; + cnt = 2; + break; + case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; + rgsz[0] = "player/pl_grate1.wav"; + rgsz[1] = "player/pl_grate4.wav"; + cnt = 2; + break; + case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; + rgsz[0] = "player/pl_tile1.wav"; + rgsz[1] = "player/pl_tile3.wav"; + rgsz[2] = "player/pl_tile2.wav"; + rgsz[3] = "player/pl_tile4.wav"; + cnt = 4; + break; + case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; + rgsz[0] = "player/pl_slosh1.wav"; + rgsz[1] = "player/pl_slosh3.wav"; + rgsz[2] = "player/pl_slosh2.wav"; + rgsz[3] = "player/pl_slosh4.wav"; + cnt = 4; + break; + case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; + rgsz[0] = "debris/wood1.wav"; + rgsz[1] = "debris/wood2.wav"; + rgsz[2] = "debris/wood3.wav"; + cnt = 3; + break; + case CHAR_TEX_GLASS: + case CHAR_TEX_COMPUTER: + fvol = 0.8; fvolbar = 0.2; + rgsz[0] = "debris/glass1.wav"; + rgsz[1] = "debris/glass2.wav"; + rgsz[2] = "debris/glass3.wav"; + cnt = 3; + break; + case CHAR_TEX_FLESH: + //if (iBulletType == BULLET_PLAYER_CROWBAR) + // return 0.0; // crowbar already makes this sound + fvol = 1.0; fvolbar = 0.2; + rgsz[0] = "weapons/bullet_hit1.wav"; + rgsz[1] = "weapons/bullet_hit2.wav"; + fattn = 1.0; + cnt = 2; + break; + } + + // did we hit a breakable? + + if (pEntity && FClassnameIs(pEntity->pev, "func_breakable")) + { + // drop volumes, the object will already play a damaged sound + fvol /= 1.5; + fvolbar /= 2.0; + } + else if (chTextureType == CHAR_TEX_COMPUTER) + { + // play random spark if computer + + if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) + { + UTIL_Sparks( ptr->vecEndPos ); + + float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range + switch ( RANDOM_LONG(0,1) ) + { + case 0: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark5.wav", flVolume, ATTN_NORM, 0, 100); break; + case 1: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark6.wav", flVolume, ATTN_NORM, 0, 100); break; + // case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; + // case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; + } + } + } + + // play material hit sound + UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, rgsz[RANDOM_LONG(0,cnt-1)], fvol, fattn, 0, 96 + RANDOM_LONG(0,0xf)); + //EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, rgsz[RANDOM_LONG(0,cnt-1)], fvol, ATTN_NORM, 0, 96 + RANDOM_LONG(0,0xf)); + + return fvolbar; +} + +// =================================================================================== +// +// Speaker class. Used for announcements per level, for door lock/unlock spoken voice. +// + +class CSpeaker : public CBaseEntity +{ +public: + void KeyValue( KeyValueData* pkvd); + void Spawn( void ); + void Precache( void ); + void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT SpeakerThink( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + + int m_preset; // preset number +}; + +LINK_ENTITY_TO_CLASS( speaker, CSpeaker ); +TYPEDESCRIPTION CSpeaker::m_SaveData[] = +{ + DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ); + +// +// ambient_generic - general-purpose user-defined static sound +// +void CSpeaker :: Spawn( void ) +{ + char* szSoundFile = (char*) STRING(pev->message); + + if ( !m_preset && (FStringNull( pev->message ) || strlen( szSoundFile ) < 1 )) + { + ALERT( at_error, "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CSpeaker::SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + + + SetThink(&CSpeaker::SpeakerThink); + pev->nextthink = 0.0; + + // allow on/off switching via 'use' function. + + SetUse ( &CSpeaker::ToggleUse ); + + Precache( ); +} + +#define ANNOUNCE_MINUTES_MIN 0.25 +#define ANNOUNCE_MINUTES_MAX 2.25 + +void CSpeaker :: Precache( void ) +{ + if ( !FBitSet (pev->spawnflags, SPEAKER_START_SILENT ) ) + // set first announcement time for random n second + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(5.0, 15.0); +} +void CSpeaker :: SpeakerThink( void ) +{ + char* szSoundFile; + float flvolume = pev->health * 0.1; + float flattenuation = 0.3; + int flags = 0; + int pitch = 100; + + + // Wait for the talkmonster to finish first. + if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) + { + pev->nextthink = CTalkMonster::g_talkWaitTime + RANDOM_FLOAT( 5, 10 ); + return; + } + + if (m_preset) + { + // go lookup preset text, assign szSoundFile + switch (m_preset) + { + case 1: szSoundFile = "C1A0_"; break; + case 2: szSoundFile = "C1A1_"; break; + case 3: szSoundFile = "C1A2_"; break; + case 4: szSoundFile = "C1A3_"; break; + case 5: szSoundFile = "C1A4_"; break; + case 6: szSoundFile = "C2A1_"; break; + case 7: szSoundFile = "C2A2_"; break; + case 8: szSoundFile = "C2A3_"; break; + case 9: szSoundFile = "C2A4_"; break; + case 10: szSoundFile = "C2A5_"; break; + case 11: szSoundFile = "C3A1_"; break; + case 12: szSoundFile = "C3A2_"; break; + } + } else + szSoundFile = (char*) STRING(pev->message); + + if (szSoundFile[0] == '!') + { + // play single sentence, one shot + UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, + flvolume, flattenuation, flags, pitch); + + // shut off and reset + pev->nextthink = 0.0; + } + else + { + // make random announcement from sentence group + + if (SENTENCEG_PlayRndSz(ENT(pev), szSoundFile, flvolume, flattenuation, flags, pitch) < 0) + ALERT(at_console, "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile); + + // set next announcement time for random 5 to 10 minute delay + pev->nextthink = gpGlobals->time + + RANDOM_FLOAT(ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0); + + CTalkMonster::g_talkWaitTime = gpGlobals->time + 5; // time delay until it's ok to speak: used so that two NPCs don't talk at once + } + + return; +} + + +// +// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one. +// +void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + int fActive = (pev->nextthink > 0.0); + + // fActive is TRUE only if an announcement is pending + + if ( useType != USE_TOGGLE ) + { + // ignore if we're just turning something on that's already on, or + // turning something off that's already off. + if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) ) + return; + } + + if ( useType == USE_ON ) + { + // turn on announcements + pev->nextthink = gpGlobals->time + 0.1; + return; + } + + if ( useType == USE_OFF ) + { + // turn off announcements + pev->nextthink = 0.0; + return; + + } + + // Toggle announcements + + + if ( fActive ) + { + // turn off announcements + pev->nextthink = 0.0; + } + else + { + // turn on announcements + pev->nextthink = gpGlobals->time + 0.1; + } +} + +// KeyValue - load keyvalue pairs into member data +// NOTE: called BEFORE spawn! + +void CSpeaker :: KeyValue( KeyValueData *pkvd ) +{ + + // preset + if (FStrEq(pkvd->szKeyName, "preset")) + { + m_preset = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); } \ No newline at end of file diff --git a/main/source/dlls/sound.cpp~ b/main/source/dlls/sound.cpp~ deleted file mode 100644 index 4013e5b7..00000000 --- a/main/source/dlls/sound.cpp~ +++ /dev/null @@ -1,1990 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// sound.cpp -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "player.h" -#include "talkmonster.h" -#include "gamerules.h" -#include "..mod/AvHSpecials.h" - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); - - -// ==================== GENERIC AMBIENT SOUND ====================================== - -// runtime pitch shift and volume fadein/out structure - -// NOTE: IF YOU CHANGE THIS STRUCT YOU MUST CHANGE THE SAVE/RESTORE VERSION NUMBER -// SEE BELOW (in the typedescription for the class) -typedef struct dynpitchvol -{ - // NOTE: do not change the order of these parameters - // NOTE: unless you also change order of rgdpvpreset array elements! - int preset; - - int pitchrun; // pitch shift % when sound is running 0 - 255 - int pitchstart; // pitch shift % when sound stops or starts 0 - 255 - int spinup; // spinup time 0 - 100 - int spindown; // spindown time 0 - 100 - - int volrun; // volume change % when sound is running 0 - 10 - int volstart; // volume change % when sound stops or starts 0 - 10 - int fadein; // volume fade in time 0 - 100 - int fadeout; // volume fade out time 0 - 100 - - // Low Frequency Oscillator - int lfotype; // 0) off 1) square 2) triangle 3) random - int lforate; // 0 - 1000, how fast lfo osciallates - - int lfomodpitch; // 0-100 mod of current pitch. 0 is off. - int lfomodvol; // 0-100 mod of current volume. 0 is off. - - int cspinup; // each trigger hit increments counter and spinup pitch - - - int cspincount; - - int pitch; - int spinupsav; - int spindownsav; - int pitchfrac; - - int vol; - int fadeinsav; - int fadeoutsav; - int volfrac; - - int lfofrac; - int lfomult; - - -} dynpitchvol_t; - -#define CDPVPRESETMAX 27 - -// presets for runtime pitch and vol modulation of ambient sounds - -dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = -{ -// pitch pstart spinup spindwn volrun volstrt fadein fadeout lfotype lforate modptch modvol cspnup -{1, 255, 75, 95, 95, 10, 1, 50, 95, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{2, 255, 85, 70, 88, 10, 1, 20, 88, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{3, 255, 100, 50, 75, 10, 1, 10, 75, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{4, 100, 100, 0, 0, 10, 1, 90, 90, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{5, 100, 100, 0, 0, 10, 1, 80, 80, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{6, 100, 100, 0, 0, 10, 1, 50, 70, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{7, 100, 100, 0, 0, 5, 1, 40, 50, 1, 50, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{8, 100, 100, 0, 0, 5, 1, 40, 50, 1, 150, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{9, 100, 100, 0, 0, 5, 1, 40, 50, 1, 750, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{10,128, 100, 50, 75, 10, 1, 30, 40, 2, 8, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{11,128, 100, 50, 75, 10, 1, 30, 40, 2, 25, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{12,128, 100, 50, 75, 10, 1, 30, 40, 2, 70, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{13,50, 50, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{14,70, 70, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{15,90, 90, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{16,120, 120, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{17,180, 180, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{18,255, 255, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{19,200, 75, 90, 90, 10, 1, 50, 90, 2, 100, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{20,255, 75, 97, 90, 10, 1, 50, 90, 1, 40, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{21,100, 100, 0, 0, 10, 1, 30, 50, 3, 15, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{22,160, 160, 0, 0, 10, 1, 50, 50, 3, 500, 25, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{23,255, 75, 88, 0, 10, 1, 40, 0, 0, 0, 0, 0, 5, 0,0,0,0,0,0,0,0,0,0}, -{24,200, 20, 95, 70, 10, 1, 70, 70, 3, 20, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{25,180, 100, 50, 60, 10, 1, 40, 60, 2, 90, 100, 100, 0, 0,0,0,0,0,0,0,0,0,0}, -{26,60, 60, 0, 0, 10, 1, 40, 70, 3, 80, 20, 50, 0, 0,0,0,0,0,0,0,0,0,0}, -{27,128, 90, 10, 10, 10, 1, 20, 40, 1, 5, 10, 20, 0, 0,0,0,0,0,0,0,0,0,0} -}; - -class CAmbientGeneric : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT RampThink( void ); - void InitModulationParms(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - float m_flAttenuation; // attenuation value - dynpitchvol_t m_dpv; - - BOOL m_fActive; // only TRUE when the entity is playing a looping sound - BOOL m_fLooping; // TRUE when the sound played will loop -}; - -LINK_ENTITY_TO_CLASS( ambient_generic, CAmbientGeneric ); -TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = -{ - DEFINE_FIELD( CAmbientGeneric, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CAmbientGeneric, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CAmbientGeneric, m_fLooping, FIELD_BOOLEAN ), - - // HACKHACK - This is not really in the spirit of the save/restore design, but save this - // out as a binary data block. If the dynpitchvol_t is changed, old saved games will NOT - // load these correctly, so bump the save/restore version if you change the size of the struct - // The right way to do this is to split the input parms (read in keyvalue) into members and re-init this - // struct in Precache(), but it's unlikely that the struct will change, so it's not worth the time right now. - DEFINE_ARRAY( CAmbientGeneric, m_dpv, FIELD_CHARACTER, sizeof(dynpitchvol_t) ), -}; - -IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CAmbientGeneric :: Spawn( void ) -{ -/* - -1 : "Default" - 0 : "Everywhere" - 200 : "Small Radius" - 125 : "Medium Radius" - 80 : "Large Radius" -*/ - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) - { - m_flAttenuation = ATTN_NONE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - else - {// if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_STATIC; - } - - char* szSoundFile = (char*) STRING(pev->message); - - if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) - { - ALERT( at_error, "EMPTY AMBIENT AT: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CAmbientGeneric::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - // Set up think function for dynamic modification - // of ambient sound's pitch or volume. Don't - // start thinking yet. - - SetThink(&CAmbientGeneric::RampThink); - pev->nextthink = 0; - - // allow on/off switching via 'use' function. - - SetUse ( &CAmbientGeneric::ToggleUse ); - - m_fActive = FALSE; - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) - m_fLooping = FALSE; - else - m_fLooping = TRUE; - Precache( ); -} - - -void CAmbientGeneric :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) - { - if (*szSoundFile != '!') - PRECACHE_SOUND(szSoundFile); - } - // init all dynamic modulation parms - InitModulationParms(); - - if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) - { - // start the sound ASAP - if (m_fLooping) - m_fActive = TRUE; - } - if ( m_fActive ) - { - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); - - pev->nextthink = gpGlobals->time + 0.1; - } -} - -// RampThink - Think at 5hz if we are dynamically modifying -// pitch or volume of the playing sound. This function will -// ramp pitch and/or volume up or down, modify pitch/volume -// with lfo if active. - -void CAmbientGeneric :: RampThink( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - int pitch = m_dpv.pitch; - int vol = m_dpv.vol; - int flags = 0; - int fChanged = 0; // FALSE if pitch and vol remain unchanged this round - int prev; - - if (!m_dpv.spinup && !m_dpv.spindown && !m_dpv.fadein && !m_dpv.fadeout && !m_dpv.lfotype) - return; // no ramps or lfo, stop thinking - - // ============== - // pitch envelope - // ============== - if (m_dpv.spinup || m_dpv.spindown) - { - prev = m_dpv.pitchfrac >> 8; - - if (m_dpv.spinup > 0) - m_dpv.pitchfrac += m_dpv.spinup; - else if (m_dpv.spindown > 0) - m_dpv.pitchfrac -= m_dpv.spindown; - - pitch = m_dpv.pitchfrac >> 8; - - if (pitch > m_dpv.pitchrun) - { - pitch = m_dpv.pitchrun; - m_dpv.spinup = 0; // done with ramp up - } - - if (pitch < m_dpv.pitchstart) - { - pitch = m_dpv.pitchstart; - m_dpv.spindown = 0; // done with ramp down - - // shut sound off - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // return without setting nextthink - return; - } - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - m_dpv.pitch = pitch; - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - // ================== - // amplitude envelope - // ================== - if (m_dpv.fadein || m_dpv.fadeout) - { - prev = m_dpv.volfrac >> 8; - - if (m_dpv.fadein > 0) - m_dpv.volfrac += m_dpv.fadein; - else if (m_dpv.fadeout > 0) - m_dpv.volfrac -= m_dpv.fadeout; - - vol = m_dpv.volfrac >> 8; - - if (vol > m_dpv.volrun) - { - vol = m_dpv.volrun; - m_dpv.fadein = 0; // done with ramp up - } - - if (vol < m_dpv.volstart) - { - vol = m_dpv.volstart; - m_dpv.fadeout = 0; // done with ramp down - - // shut sound off - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // return without setting nextthink - return; - } - - if (vol > 100) vol = 100; - if (vol < 1) vol = 1; - - m_dpv.vol = vol; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - // =================== - // pitch/amplitude LFO - // =================== - if (m_dpv.lfotype) - { - int pos; - - if (m_dpv.lfofrac > 0x6fffffff) - m_dpv.lfofrac = 0; - - // update lfo, lfofrac/255 makes a triangle wave 0-255 - m_dpv.lfofrac += m_dpv.lforate; - pos = m_dpv.lfofrac >> 8; - - if (m_dpv.lfofrac < 0) - { - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - pos = 0; - } - else if (pos > 255) - { - pos = 255; - m_dpv.lfofrac = (255 << 8); - m_dpv.lforate = -abs(m_dpv.lforate); - } - - switch(m_dpv.lfotype) - { - case LFO_SQUARE: - if (pos < 128) - m_dpv.lfomult = 255; - else - m_dpv.lfomult = 0; - - break; - case LFO_RANDOM: - if (pos == 255) - m_dpv.lfomult = RANDOM_LONG(0, 255); - break; - case LFO_TRIANGLE: - default: - m_dpv.lfomult = pos; - break; - } - - if (m_dpv.lfomodpitch) - { - prev = pitch; - - // pitch 0-255 - pitch += ((m_dpv.lfomult - 128) * m_dpv.lfomodpitch) / 100; - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - if (m_dpv.lfomodvol) - { - // vol 0-100 - prev = vol; - - vol += ((m_dpv.lfomult - 128) * m_dpv.lfomodvol) / 100; - - if (vol > 100) vol = 100; - if (vol < 0) vol = 0; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - } - - // Send update to playing sound only if we actually changed - // pitch or volume in this routine. - - if (flags && fChanged) - { - if (pitch == PITCH_NORM) - pitch = PITCH_NORM + 1; // don't send 'no pitch' ! - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (vol * 0.01), m_flAttenuation, flags, pitch); - } - - // update ramps at 5hz - pev->nextthink = gpGlobals->time + 0.2; - return; -} - -// Init all ramp params in preparation to -// play a new sound - -void CAmbientGeneric :: InitModulationParms(void) -{ - int pitchinc; - - m_dpv.volrun = pev->health * 10; // 0 - 100 - if (m_dpv.volrun > 100) m_dpv.volrun = 100; - if (m_dpv.volrun < 0) m_dpv.volrun = 0; - - // get presets - if (m_dpv.preset != 0 && m_dpv.preset <= CDPVPRESETMAX) - { - // load preset values - m_dpv = rgdpvpreset[m_dpv.preset - 1]; - - // fixup preset values, just like - // fixups in KeyValue routine. - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - - m_dpv.volstart *= 10; - m_dpv.volrun *= 10; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - - m_dpv.lforate *= 256; - - m_dpv.fadeinsav = m_dpv.fadein; - m_dpv.fadeoutsav = m_dpv.fadeout; - m_dpv.spinupsav = m_dpv.spinup; - m_dpv.spindownsav = m_dpv.spindown; - } - - m_dpv.fadein = m_dpv.fadeinsav; - m_dpv.fadeout = 0; - - if (m_dpv.fadein) - m_dpv.vol = m_dpv.volstart; - else - m_dpv.vol = m_dpv.volrun; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - if (m_dpv.spinup) - m_dpv.pitch = m_dpv.pitchstart; - else - m_dpv.pitch = m_dpv.pitchrun; - - if (m_dpv.pitch == 0) - m_dpv.pitch = PITCH_NORM; - - m_dpv.pitchfrac = m_dpv.pitch << 8; - m_dpv.volfrac = m_dpv.vol << 8; - - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - - m_dpv.cspincount = 1; - - if (m_dpv.cspinup) - { - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - } - - if ((m_dpv.spinupsav || m_dpv.spindownsav || (m_dpv.lfotype && m_dpv.lfomodpitch)) - && (m_dpv.pitch == PITCH_NORM)) - m_dpv.pitch = PITCH_NORM + 1; // must never send 'no pitch' as first pitch - // if we intend to pitch shift later! -} - -// -// ToggleUse - turns an ambient sound on or off. If the -// ambient is a looping sound, mark sound as active (m_fActive) -// if it's playing, innactive if not. If the sound is not -// a looping sound, never mark it as active. -// -void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - char* szSoundFile = (char*) STRING(pev->message); - float fraction; - - if ( useType != USE_TOGGLE ) - { - if ( (m_fActive && useType == USE_ON) || (!m_fActive && useType == USE_OFF) ) - return; - } - // Directly change pitch if arg passed. Only works if sound is already playing. - - if (useType == USE_SET && m_fActive) // Momentary buttons will pass down a float in here - { - - fraction = value; - - if ( fraction > 1.0 ) - fraction = 1.0; - if (fraction < 0.0) - fraction = 0.01; - - m_dpv.pitch = fraction * 255; - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); - - return; - } - - // Toggle - - // m_fActive is TRUE only if a looping sound is playing. - - if ( m_fActive ) - {// turn sound off - - if (m_dpv.cspinup) - { - // Don't actually shut off. Each toggle causes - // incremental spinup to max pitch - - if (m_dpv.cspincount <= m_dpv.cspinup) - { - int pitchinc; - - // start a new spinup - m_dpv.cspincount++; - - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc * m_dpv.cspincount; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - - pev->nextthink = gpGlobals->time + 0.1; - } - - } - else - { - m_fActive = FALSE; - - // HACKHACK - this makes the code in Precache() work properly after a save/restore - pev->spawnflags |= AMBIENT_SOUND_START_SILENT; - - if (m_dpv.spindownsav || m_dpv.fadeoutsav) - { - // spin it down (or fade it) before shutoff if spindown is set - m_dpv.spindown = m_dpv.spindownsav; - m_dpv.spinup = 0; - - m_dpv.fadeout = m_dpv.fadeoutsav; - m_dpv.fadein = 0; - pev->nextthink = gpGlobals->time + 0.1; - } - else - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - } - else - {// turn sound on - - // only toggle if this is a looping sound. If not looping, each - // trigger will cause the sound to play. If the sound is still - // playing from a previous trigger press, it will be shut off - // and then restarted. - - if (m_fLooping) - m_fActive = TRUE; - else - // shut sound off now - may be interrupting a long non-looping sound - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // init all ramp params for startup - - InitModulationParms(); - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, 0, m_dpv.pitch); - - pev->nextthink = gpGlobals->time + 0.1; - - } -} -// KeyValue - load keyvalue pairs into member data of the -// ambient generic. NOTE: called BEFORE spawn! - -void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) -{ - // NOTE: changing any of the modifiers in this code - // NOTE: also requires changing InitModulationParms code. - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_dpv.preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - - // pitchrun - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - m_dpv.pitchrun = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - if (m_dpv.pitchrun < 0) m_dpv.pitchrun = 0; - } - - // pitchstart - else if (FStrEq(pkvd->szKeyName, "pitchstart")) - { - m_dpv.pitchstart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchstart > 255) m_dpv.pitchstart = 255; - if (m_dpv.pitchstart < 0) m_dpv.pitchstart = 0; - } - - // spinup - else if (FStrEq(pkvd->szKeyName, "spinup")) - { - m_dpv.spinup = atoi(pkvd->szValue); - - if (m_dpv.spinup > 100) m_dpv.spinup = 100; - if (m_dpv.spinup < 0) m_dpv.spinup = 0; - - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - m_dpv.spinupsav = m_dpv.spinup; - pkvd->fHandled = TRUE; - } - - // spindown - else if (FStrEq(pkvd->szKeyName, "spindown")) - { - m_dpv.spindown = atoi(pkvd->szValue); - - if (m_dpv.spindown > 100) m_dpv.spindown = 100; - if (m_dpv.spindown < 0) m_dpv.spindown = 0; - - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - m_dpv.spindownsav = m_dpv.spindown; - pkvd->fHandled = TRUE; - } - - // volstart - else if (FStrEq(pkvd->szKeyName, "volstart")) - { - m_dpv.volstart = atoi(pkvd->szValue); - - if (m_dpv.volstart > 10) m_dpv.volstart = 10; - if (m_dpv.volstart < 0) m_dpv.volstart = 0; - - m_dpv.volstart *= 10; // 0 - 100 - - pkvd->fHandled = TRUE; - } - - // fadein - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_dpv.fadein = atoi(pkvd->szValue); - - if (m_dpv.fadein > 100) m_dpv.fadein = 100; - if (m_dpv.fadein < 0) m_dpv.fadein = 0; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - m_dpv.fadeinsav = m_dpv.fadein; - pkvd->fHandled = TRUE; - } - - // fadeout - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_dpv.fadeout = atoi(pkvd->szValue); - - if (m_dpv.fadeout > 100) m_dpv.fadeout = 100; - if (m_dpv.fadeout < 0) m_dpv.fadeout = 0; - - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - m_dpv.fadeoutsav = m_dpv.fadeout; - pkvd->fHandled = TRUE; - } - - // lfotype - else if (FStrEq(pkvd->szKeyName, "lfotype")) - { - m_dpv.lfotype = atoi(pkvd->szValue); - if (m_dpv.lfotype > 4) m_dpv.lfotype = LFO_TRIANGLE; - pkvd->fHandled = TRUE; - } - - // lforate - else if (FStrEq(pkvd->szKeyName, "lforate")) - { - m_dpv.lforate = atoi(pkvd->szValue); - - if (m_dpv.lforate > 1000) m_dpv.lforate = 1000; - if (m_dpv.lforate < 0) m_dpv.lforate = 0; - - m_dpv.lforate *= 256; - - pkvd->fHandled = TRUE; - } - // lfomodpitch - else if (FStrEq(pkvd->szKeyName, "lfomodpitch")) - { - m_dpv.lfomodpitch = atoi(pkvd->szValue); - if (m_dpv.lfomodpitch > 100) m_dpv.lfomodpitch = 100; - if (m_dpv.lfomodpitch < 0) m_dpv.lfomodpitch = 0; - - - pkvd->fHandled = TRUE; - } - - // lfomodvol - else if (FStrEq(pkvd->szKeyName, "lfomodvol")) - { - m_dpv.lfomodvol = atoi(pkvd->szValue); - if (m_dpv.lfomodvol > 100) m_dpv.lfomodvol = 100; - if (m_dpv.lfomodvol < 0) m_dpv.lfomodvol = 0; - - pkvd->fHandled = TRUE; - } - - // cspinup - else if (FStrEq(pkvd->szKeyName, "cspinup")) - { - m_dpv.cspinup = atoi(pkvd->szValue); - if (m_dpv.cspinup > 100) m_dpv.cspinup = 100; - if (m_dpv.cspinup < 0) m_dpv.cspinup = 0; - - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// =================== ROOM SOUND FX ========================================== - -class CEnvSound : public CPointEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flRadius; - float m_flRoomtype; -}; - -LINK_ENTITY_TO_CLASS( env_sound, CEnvSound ); -TYPEDESCRIPTION CEnvSound::m_SaveData[] = -{ - DEFINE_FIELD( CEnvSound, m_flRadius, FIELD_FLOAT ), - DEFINE_FIELD( CEnvSound, m_flRoomtype, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CEnvSound, CBaseEntity ); - - -void CEnvSound :: KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "roomtype")) - { - m_flRoomtype = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - -// returns TRUE if the given sound entity (pev) is in range -// and can see the given player entity (pevTarget) - -BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) -{ - CEnvSound *pSound = GetClassPtr( (CEnvSound *)pev ); - Vector vecSpot1 = pev->origin + pev->view_ofs; - Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; - Vector vecRange; - float flRange; - TraceResult tr; - - UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); - - // check if line of sight crosses water boundary, or is blocked - - if ((tr.fInOpen && tr.fInWater) || tr.flFraction != 1) - return FALSE; - - // calc range from sound entity to player - - vecRange = tr.vecEndPos - vecSpot1; - flRange = vecRange.Length(); - - if (pSound->m_flRadius < flRange) - return FALSE; - - if (pflRange) - *pflRange = flRange; - - return TRUE; -} - -// -// A client that is visible and in range of a sound entity will -// have its room_type set by that sound entity. If two or more -// sound entities are contending for a client, then the nearest -// sound entity to the client will set the client's room_type. -// A client's room_type will remain set to its prior value until -// a new in-range, visible sound entity resets a new room_type. -// - -// CONSIDER: if player in water state, autoset roomtype to 14,15 or 16. - -void CEnvSound :: Think( void ) -{ - // get pointer to client if visible; FIND_CLIENT_IN_PVS will - // cycle through visible clients on consecutive calls. - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS(edict()); - CBasePlayer *pPlayer = NULL; - - if (FNullEnt(pentPlayer)) - goto env_sound_Think_slow; // no player in pvs of sound entity, slow it down - - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - float flRange; - - // Don't change sound types for players that are being digested - if(!GetHasUpgrade(pPlayer->pev->iuser4, MASK_DIGESTING)) - { - // check to see if this is the sound entity that is - // currently affecting this player - - if(!FNullEnt(pPlayer->m_pentSndLast) && (pPlayer->m_pentSndLast == ENT(pev))) { - - // this is the entity currently affecting player, check - // for validity - - if (pPlayer->m_flSndRoomtype != 0 && pPlayer->m_flSndRange != 0) { - - // we're looking at a valid sound entity affecting - // player, make sure it's still valid, update range - - if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) { - pPlayer->m_flSndRange = flRange; - goto env_sound_Think_fast; - } else { - - // current sound entity affecting player is no longer valid, - // flag this state by clearing room_type and range. - // NOTE: we do not actually change the player's room_type - // NOTE: until we have a new valid room_type to change it to. - - pPlayer->m_flSndRange = 0; - pPlayer->m_flSndRoomtype = 0; - goto env_sound_Think_slow; - } - } else { - // entity is affecting player but is out of range, - // wait passively for another entity to usurp it... - goto env_sound_Think_slow; - } - } - - // if we got this far, we're looking at an entity that is contending - // for current player sound. the closest entity to player wins. - - if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) - { - if (flRange < pPlayer->m_flSndRange || pPlayer->m_flSndRange == 0) - { - // new entity is closer to player, so it wins. - pPlayer->m_pentSndLast = ENT(pev); - pPlayer->m_flSndRoomtype = m_flRoomtype; - pPlayer->m_flSndRange = flRange; - - // send room_type command to player's server. - // this should be a rare event - once per change of room_type - // only! - - //CLIENT_COMMAND(pentPlayer, "room_type %f", m_flRoomtype); - - MESSAGE_BEGIN( MSG_ONE, SVC_ROOMTYPE, NULL, pentPlayer ); // use the magic #1 for "one client" - WRITE_SHORT( (short)m_flRoomtype ); // sequence number - MESSAGE_END(); - - // crank up nextthink rate for new active sound entity - // by falling through to think_fast... - } - // player is not closer to the contending sound entity, - // just fall through to think_fast. this effectively - // cranks up the think_rate of entities near the player. - } - } - else - { - int a = 0; - } - - // player is in pvs of sound entity, but either not visible or - // not in range. do nothing, fall through to think_fast... - -env_sound_Think_fast: - pev->nextthink = gpGlobals->time + 0.25; - return; - -env_sound_Think_slow: - pev->nextthink = gpGlobals->time + 0.75; - return; -} - -// -// env_sound - spawn a sound entity that will set player roomtype -// when player moves in range and sight. -// -// -void CEnvSound :: Spawn( ) -{ - // spread think times - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); -} - -// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== - -#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group - -// group of related sentences - -typedef struct sentenceg -{ - char szgroupname[CBSENTENCENAME_MAX]; - int count; - unsigned char rgblru[CSENTENCE_LRU_MAX]; - -} SENTENCEG; - -#define CSENTENCEG_MAX 200 // max number of sentence groups -// globals - -SENTENCEG rgsentenceg[CSENTENCEG_MAX]; -int fSentencesInit = FALSE; - -char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -int gcallsentences = 0; - -// randomize list of sentence name indices - -void USENTENCEG_InitLRU(unsigned char *plru, int count) -{ - int i, j, k; - unsigned char temp; - - if (!fSentencesInit) - return; - - if (count > CSENTENCE_LRU_MAX) - count = CSENTENCE_LRU_MAX; - - for (i = 0; i < count; i++) - plru[i] = (unsigned char) i; - - // randomize array - for (i = 0; i < (count * 4); i++) - { - j = RANDOM_LONG(0,count-1); - k = RANDOM_LONG(0,count-1); - temp = plru[j]; - plru[j] = plru[k]; - plru[k] = temp; - } -} - -// ignore lru. pick next sentence from sentence group. Go in order until we hit the last sentence, -// then repeat list if freset is true. If freset is false, then repeat last sentence. -// ipick is passed in as the requested sentence ordinal. -// ipick 'next' is returned. -// return of -1 indicates an error. - -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) -{ - char *szgroupname; - unsigned char count; - char sznum[8]; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - - if (count == 0) - return -1; - - if (ipick >= count) - ipick = count-1; - - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - - if (ipick >= count) - { - if (freset) - // reset at end of list - return 0; - else - return count; - } - - return ipick + 1; -} - - - -// pick a random sentence from rootname0 to rootnameX. -// picks from the rgsentenceg[isentenceg] least -// recently used, modifies lru array. returns the sentencename. -// note, lru must be seeded with 0-n randomized sentence numbers, with the -// rest of the lru filled with -1. The first integer in the lru is -// actually the size of the list. Returns ipick, the ordinal -// of the picked sentence within the group. - -int USENTENCEG_Pick(int isentenceg, char *szfound) -{ - char *szgroupname; - unsigned char *plru; - unsigned char i; - unsigned char count; - char sznum[8]; - unsigned char ipick; - int ffound = FALSE; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - plru = rgsentenceg[isentenceg].rgblru; - - while (!ffound) - { - for (i = 0; i < count; i++) - if (plru[i] != 0xFF) - { - ipick = plru[i]; - plru[i] = 0xFF; - ffound = TRUE; - break; - } - - if (!ffound) - USENTENCEG_InitLRU(plru, count); - else - { - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - return ipick; - } - } - return -1; -} - -// ===================== SENTENCE GROUPS, MAIN ROUTINES ======================== - -// Given sentence group rootname (name without number suffix), -// get sentence group index (isentenceg). Returns -1 if no such name. - -int SENTENCEG_GetIndex(const char *szgroupname) -{ - int i; - - if (!fSentencesInit || !szgroupname) - return -1; - - // search rgsentenceg for match on szgroupname - - i = 0; - while (rgsentenceg[i].count) - { - if (!strcmp(szgroupname, rgsentenceg[i].szgroupname)) - return i; - i++; - } - - return -1; -} - -// given sentence group index, play random sentence for given entity. -// returns ipick - which sentence was picked to -// play from the group. Ipick is only needed if you plan on stopping -// the sound before playback is done (see SENTENCEG_Stop). - -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick > 0 && name) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipick; -} - -// same as above, but takes sentence group name instead of index - -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - { - ALERT( at_console, "No such sentence group %s\n", szgroupname ); - return -1; - } - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - - return ipick; -} - -// play sentences in sequential order from sentence group. Reset after last sentence. - -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch, int ipick, int freset) -{ - char name[64]; - int ipicknext; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - return -1; - - ipicknext = USENTENCEG_PickSequential(isentenceg, name, ipick, freset); - if (ipicknext >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipicknext; -} - - -// for this entity, for the given sentence within the sentence group, stop -// the sentence. - -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) -{ - char buffer[64]; - char sznum[8]; - - if (!fSentencesInit) - return; - - if (isentenceg < 0 || ipick < 0) - return; - - strcpy(buffer, "!"); - strcat(buffer, rgsentenceg[isentenceg].szgroupname); - sprintf(sznum, "%d", ipick); - strcat(buffer, sznum); - - STOP_SOUND(entity, CHAN_VOICE, buffer); -} - -// open sentences.txt, scan for groups, build rgsentenceg -// Should be called from world spawn, only works on the -// first call and is ignored subsequently. - -void SENTENCEG_Init() -{ - char buffer[512]; - char szgroup[64]; - int i, j; - int isentencegs; - - if (fSentencesInit) - return; - - memset(gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX); - gcallsentences = 0; - - memset(rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG)); - memset(buffer, 0, 512); - memset(szgroup, 0, 64); - isentencegs = -1; - - - int filePos = 0, fileSize; - byte *pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/sentences.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while ( memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL ) - { - // skip whitespace - i = 0; - while(buffer[i] && buffer[i] == ' ') - i++; - - if (!buffer[i]) - continue; - - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get sentence name - j = i; - while (buffer[j] && buffer[j] != ' ') - j++; - - if (!buffer[j]) - continue; - - if (gcallsentences > CVOXFILESENTENCEMAX) - { - ALERT (at_error, "Too many sentences in sentences.txt!\n"); - break; - } - - // null-terminate name and save in sentences array - buffer[j] = 0; - const char *pString = buffer + i; - - if ( strlen( pString ) >= CBSENTENCENAME_MAX ) - ALERT( at_warning, "Sentence %s longer than %d letters\n", pString, CBSENTENCENAME_MAX-1 ); - - strcpy( gszallsentencenames[gcallsentences++], pString ); - - j--; - if (j <= i) - continue; - if (!isdigit(buffer[j])) - continue; - - // cut out suffix numbers - while (j > i && isdigit(buffer[j])) - j--; - - if (j <= i) - continue; - - buffer[j+1] = 0; - - // if new name doesn't match previous group name, - // make a new group. - - if (strcmp(szgroup, &(buffer[i]))) - { - // name doesn't match with prev name, - // copy name into group, init count to 1 - isentencegs++; - if (isentencegs >= CSENTENCEG_MAX) - { - ALERT (at_error, "Too many sentence groups in sentences.txt!\n"); - break; - } - - strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); - rgsentenceg[isentencegs].count = 1; - - strcpy(szgroup, &(buffer[i])); - - continue; - } - else - { - //name matches with previous, increment group count - if (isentencegs >= 0) - rgsentenceg[isentencegs].count++; - } - } - - g_engfuncs.pfnFreeFile( pMemFile ); - - fSentencesInit = TRUE; - - // init lru lists - - i = 0; - - while (rgsentenceg[i].count && i < CSENTENCEG_MAX) - { - USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); - i++; - } - -} - -// convert sentence (sample) name to !sentencenum, return !sentencenum - -int SENTENCEG_Lookup(const char *sample, char *sentencenum) -{ - char sznum[8]; - -//#ifdef GERMANY -// return -1; // no constructed sentences in international versions -//#endif // GERMANY - - int i; - // this is a sentence name; lookup sentence number - // and give to engine as string. - for (i = 0; i < gcallsentences; i++) - if (!stricmp(gszallsentencenames[i], sample+1)) - { - if (sentencenum) - { - strcpy(sentencenum, "!"); - sprintf(sznum, "%d", i); - strcat(sentencenum, sznum); - } - return i; - } - // sentence name not found! - return -1; -} - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch) -{ - if (sample && *sample == '!') - { - char name[32]; - if (SENTENCEG_Lookup(sample, name) >= 0) - EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); - else - ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); - } - else - EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch); -} - -// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - EMIT_SOUND_DYN(entity, CHAN_STATIC, sample, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in group id, over the HEV suit speaker - -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndI(entity, isentenceg, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in groupname - -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndSz(entity, groupname, fvol, ATTN_NORM, 0, pitch); -} - -// ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ======================== -// -// Used to detect the texture the player is standing on, map the -// texture name to a material type. Play footstep sound based -// on material type. - -int fTextureTypeInit = FALSE; - -#define CTEXTURESMAX 512 // max number of textures loaded - -int gcTextures = 0; -char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; // texture names -char grgchTextureType[CTEXTURESMAX]; // parallel array of texture types - -// open materials.txt, get size, alloc space, -// save in array. Only works first time called, -// ignored on subsequent calls. - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ) -{ - // Bullet-proofing - if ( !pMemFile || !pBuffer ) - return NULL; - - if ( filePos >= fileSize ) - return NULL; - - int i = filePos; - int last = fileSize; - - // fgets always NULL terminates, so only read bufferSize-1 characters - if ( last - filePos > (bufferSize-1) ) - last = filePos + (bufferSize-1); - - int stop = 0; - - // Stop at the next newline (inclusive) or end of buffer - while ( i < last && !stop ) - { - if ( pMemFile[i] == '\n' ) - stop = 1; - i++; - } - - - // If we actually advanced the pointer, copy it over - if ( i != filePos ) - { - // We read in size bytes - int size = i - filePos; - // copy it out - memcpy( pBuffer, pMemFile + filePos, sizeof(byte)*size ); - - // If the buffer isn't full, terminate (this is always true) - if ( size < bufferSize ) - pBuffer[size] = 0; - - // Update file pointer - filePos = i; - return pBuffer; - } - - // No data read, bail - return NULL; -} - - -void TEXTURETYPE_Init() -{ - char buffer[512]; - int i, j; - byte *pMemFile; - int fileSize, filePos; - - if (fTextureTypeInit) - return; - - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); - - gcTextures = 0; - memset(buffer, 0, 512); - - pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/materials.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while (memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL && (gcTextures < CTEXTURESMAX)) - { - // skip whitespace - i = 0; - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); - - // skip whitespace - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // get sentence name - j = i; - while (buffer[j] && !isspace(buffer[j])) - j++; - - if (!buffer[j]) - continue; - - // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); - buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); - } - - g_engfuncs.pfnFreeFile( pMemFile ); - - fTextureTypeInit = TRUE; -} - -// given texture name, find texture type -// if not found, return type 'concrete' - -// NOTE: this routine should ONLY be called if the -// current texture under the player changes! - -char TEXTURETYPE_Find(char *name) -{ - // CONSIDER: pre-sort texture names and perform faster binary search here - - for (int i = 0; i < gcTextures; i++) - { - if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) - return (grgchTextureType[i]); - } - - return CHAR_TEX_CONCRETE; -} - -// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the -// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. -// returns volume of strike instrument (crowbar) to play - -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType) -{ -// hit the world, try to play sound based on texture material type - - char chTextureType; - float fvol; - float fvolbar; - char szbuffer[64]; - const char *pTextureName; - float rgfl1[3]; - float rgfl2[3]; - char *rgsz[4]; - int cnt; - float fattn = ATTN_NORM; - - if ( !g_pGameRules->PlayTextureSounds() ) - return 0.0; - - CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); - - chTextureType = 0; - - if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) - // hit body - chTextureType = CHAR_TEX_FLESH; - else - { - // hit world - - // find texture under strike, get material type - - // copy trace vector into array for trace_texture - - vecSrc.CopyToArray(rgfl1); - vecEnd.CopyToArray(rgfl2); - - // get texture from entity or world (world is ent(0)) - if (pEntity) - pTextureName = TRACE_TEXTURE( ENT(pEntity->pev), rgfl1, rgfl2 ); - else - pTextureName = TRACE_TEXTURE( ENT(0), rgfl1, rgfl2 ); - - if ( pTextureName ) - { - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - pTextureName += 2; - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - pTextureName++; - // '}}' - strcpy(szbuffer, pTextureName); - szbuffer[CBTEXTURENAMEMAX - 1] = 0; - - // ALERT ( at_console, "texture hit: %s\n", szbuffer); - - // get texture type - chTextureType = TEXTURETYPE_Find(szbuffer); - } - } - - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; - rgsz[0] = "player/pl_step1.wav"; - rgsz[1] = "player/pl_step2.wav"; - cnt = 2; - break; - case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3; - rgsz[0] = "player/pl_metal1.wav"; - rgsz[1] = "player/pl_metal2.wav"; - cnt = 2; - break; - case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; - rgsz[0] = "player/pl_dirt1.wav"; - rgsz[1] = "player/pl_dirt2.wav"; - rgsz[2] = "player/pl_dirt3.wav"; - cnt = 3; - break; - case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; - rgsz[0] = "player/pl_duct1.wav"; - rgsz[1] = "player/pl_duct1.wav"; - cnt = 2; - break; - case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; - rgsz[0] = "player/pl_grate1.wav"; - rgsz[1] = "player/pl_grate4.wav"; - cnt = 2; - break; - case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "player/pl_tile1.wav"; - rgsz[1] = "player/pl_tile3.wav"; - rgsz[2] = "player/pl_tile2.wav"; - rgsz[3] = "player/pl_tile4.wav"; - cnt = 4; - break; - case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; - rgsz[0] = "player/pl_slosh1.wav"; - rgsz[1] = "player/pl_slosh3.wav"; - rgsz[2] = "player/pl_slosh2.wav"; - rgsz[3] = "player/pl_slosh4.wav"; - cnt = 4; - break; - case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; - rgsz[0] = "debris/wood1.wav"; - rgsz[1] = "debris/wood2.wav"; - rgsz[2] = "debris/wood3.wav"; - cnt = 3; - break; - case CHAR_TEX_GLASS: - case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "debris/glass1.wav"; - rgsz[1] = "debris/glass2.wav"; - rgsz[2] = "debris/glass3.wav"; - cnt = 3; - break; - case CHAR_TEX_FLESH: - //if (iBulletType == BULLET_PLAYER_CROWBAR) - // return 0.0; // crowbar already makes this sound - fvol = 1.0; fvolbar = 0.2; - rgsz[0] = "weapons/bullet_hit1.wav"; - rgsz[1] = "weapons/bullet_hit2.wav"; - fattn = 1.0; - cnt = 2; - break; - } - - // did we hit a breakable? - - if (pEntity && FClassnameIs(pEntity->pev, "func_breakable")) - { - // drop volumes, the object will already play a damaged sound - fvol /= 1.5; - fvolbar /= 2.0; - } - else if (chTextureType == CHAR_TEX_COMPUTER) - { - // play random spark if computer - - if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark5.wav", flVolume, ATTN_NORM, 0, 100); break; - case 1: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark6.wav", flVolume, ATTN_NORM, 0, 100); break; - // case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - // case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } - } - } - - // play material hit sound - UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, rgsz[RANDOM_LONG(0,cnt-1)], fvol, fattn, 0, 96 + RANDOM_LONG(0,0xf)); - //EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, rgsz[RANDOM_LONG(0,cnt-1)], fvol, ATTN_NORM, 0, 96 + RANDOM_LONG(0,0xf)); - - return fvolbar; -} - -// =================================================================================== -// -// Speaker class. Used for announcements per level, for door lock/unlock spoken voice. -// - -class CSpeaker : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT SpeakerThink( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - int m_preset; // preset number -}; - -LINK_ENTITY_TO_CLASS( speaker, CSpeaker ); -TYPEDESCRIPTION CSpeaker::m_SaveData[] = -{ - DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CSpeaker :: Spawn( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !m_preset && (FStringNull( pev->message ) || strlen( szSoundFile ) < 1 )) - { - ALERT( at_error, "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CSpeaker::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - - SetThink(&CSpeaker::SpeakerThink); - pev->nextthink = 0.0; - - // allow on/off switching via 'use' function. - - SetUse ( &CSpeaker::ToggleUse ); - - Precache( ); -} - -#define ANNOUNCE_MINUTES_MIN 0.25 -#define ANNOUNCE_MINUTES_MAX 2.25 - -void CSpeaker :: Precache( void ) -{ - if ( !FBitSet (pev->spawnflags, SPEAKER_START_SILENT ) ) - // set first announcement time for random n second - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(5.0, 15.0); -} -void CSpeaker :: SpeakerThink( void ) -{ - char* szSoundFile; - float flvolume = pev->health * 0.1; - float flattenuation = 0.3; - int flags = 0; - int pitch = 100; - - - // Wait for the talkmonster to finish first. - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - { - pev->nextthink = CTalkMonster::g_talkWaitTime + RANDOM_FLOAT( 5, 10 ); - return; - } - - if (m_preset) - { - // go lookup preset text, assign szSoundFile - switch (m_preset) - { - case 1: szSoundFile = "C1A0_"; break; - case 2: szSoundFile = "C1A1_"; break; - case 3: szSoundFile = "C1A2_"; break; - case 4: szSoundFile = "C1A3_"; break; - case 5: szSoundFile = "C1A4_"; break; - case 6: szSoundFile = "C2A1_"; break; - case 7: szSoundFile = "C2A2_"; break; - case 8: szSoundFile = "C2A3_"; break; - case 9: szSoundFile = "C2A4_"; break; - case 10: szSoundFile = "C2A5_"; break; - case 11: szSoundFile = "C3A1_"; break; - case 12: szSoundFile = "C3A2_"; break; - } - } else - szSoundFile = (char*) STRING(pev->message); - - if (szSoundFile[0] == '!') - { - // play single sentence, one shot - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - flvolume, flattenuation, flags, pitch); - - // shut off and reset - pev->nextthink = 0.0; - } - else - { - // make random announcement from sentence group - - if (SENTENCEG_PlayRndSz(ENT(pev), szSoundFile, flvolume, flattenuation, flags, pitch) < 0) - ALERT(at_console, "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile); - - // set next announcement time for random 5 to 10 minute delay - pev->nextthink = gpGlobals->time + - RANDOM_FLOAT(ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0); - - CTalkMonster::g_talkWaitTime = gpGlobals->time + 5; // time delay until it's ok to speak: used so that two NPCs don't talk at once - } - - return; -} - - -// -// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one. -// -void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fActive = (pev->nextthink > 0.0); - - // fActive is TRUE only if an announcement is pending - - if ( useType != USE_TOGGLE ) - { - // ignore if we're just turning something on that's already on, or - // turning something off that's already off. - if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) ) - return; - } - - if ( useType == USE_ON ) - { - // turn on announcements - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - if ( useType == USE_OFF ) - { - // turn off announcements - pev->nextthink = 0.0; - return; - - } - - // Toggle announcements - - - if ( fActive ) - { - // turn off announcements - pev->nextthink = 0.0; - } - else - { - // turn on announcements - pev->nextthink = gpGlobals->time + 0.1; - } -} - -// KeyValue - load keyvalue pairs into member data -// NOTE: called BEFORE spawn! - -void CSpeaker :: KeyValue( KeyValueData *pkvd ) -{ - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} \ No newline at end of file diff --git a/main/source/dlls/soundent.cpp b/main/source/dlls/soundent.cpp index ff16d49e..b9b4f663 100644 --- a/main/source/dlls/soundent.cpp +++ b/main/source/dlls/soundent.cpp @@ -1,379 +1,379 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" - - -LINK_ENTITY_TO_CLASS( soundent, CSoundEnt ); - -CSoundEnt *pSoundEnt; - -//========================================================= -// CSound - Clear - zeros all fields for a sound -//========================================================= -void CSound :: Clear ( void ) -{ - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_flExpireTime = 0; - m_iNext = SOUNDLIST_EMPTY; - m_iNextAudible = 0; -} - -//========================================================= -// Reset - clears the volume, origin, and type for a sound, -// but doesn't expire or unlink it. -//========================================================= -void CSound :: Reset ( void ) -{ - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_iNext = SOUNDLIST_EMPTY; -} - -//========================================================= -// FIsSound - returns TRUE if the sound is an Audible sound -//========================================================= -BOOL CSound :: FIsSound ( void ) -{ - if ( m_iType & ( bits_SOUND_COMBAT | bits_SOUND_WORLD | bits_SOUND_PLAYER | bits_SOUND_DANGER ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// FIsScent - returns TRUE if the sound is actually a scent -//========================================================= -BOOL CSound :: FIsScent ( void ) -{ - if ( m_iType & ( bits_SOUND_CARCASS | bits_SOUND_MEAT | bits_SOUND_GARBAGE ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// Spawn -//========================================================= -void CSoundEnt :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - Initialize(); - - pev->nextthink = gpGlobals->time + 1; -} - -//========================================================= -// Think - at interval, the entire active sound list is checked -// for sounds that have ExpireTimes less than or equal -// to the current world time, and these sounds are deallocated. -//========================================================= -void CSoundEnt :: Think ( void ) -{ - int iSound; - int iPreviousSound; - - pev->nextthink = gpGlobals->time + 0.3;// how often to check the sound list. - - iPreviousSound = SOUNDLIST_EMPTY; - iSound = m_iActiveSound; - - while ( iSound != SOUNDLIST_EMPTY ) - { - if ( m_SoundPool[ iSound ].m_flExpireTime <= gpGlobals->time && m_SoundPool[ iSound ].m_flExpireTime != SOUND_NEVER_EXPIRE ) - { - int iNext = m_SoundPool[ iSound ].m_iNext; - - // move this sound back into the free list - FreeSound( iSound, iPreviousSound ); - - iSound = iNext; - } - else - { - iPreviousSound = iSound; - iSound = m_SoundPool[ iSound ].m_iNext; - } - } - - if ( m_fShowReport ) - { - ALERT ( at_aiconsole, "Soundlist: %d / %d (%d)\n", ISoundsInList( SOUNDLISTTYPE_ACTIVE ),ISoundsInList( SOUNDLISTTYPE_FREE ), ISoundsInList( SOUNDLISTTYPE_ACTIVE ) - m_cLastActiveSounds ); - m_cLastActiveSounds = ISoundsInList ( SOUNDLISTTYPE_ACTIVE ); - } - -} - -//========================================================= -// Precache - dummy function -//========================================================= -void CSoundEnt :: Precache ( void ) -{ -} - -//========================================================= -// FreeSound - clears the passed active sound and moves it -// to the top of the free list. TAKE CARE to only call this -// function for sounds in the Active list!! -//========================================================= -void CSoundEnt :: FreeSound ( int iSound, int iPrevious ) -{ - if ( !pSoundEnt ) - { - // no sound ent! - return; - } - - if ( iPrevious != SOUNDLIST_EMPTY ) - { - // iSound is not the head of the active list, so - // must fix the index for the Previous sound -// pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = m_SoundPool[ iSound ].m_iNext; - pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = pSoundEnt->m_SoundPool[ iSound ].m_iNext; - } - else - { - // the sound we're freeing IS the head of the active list. - pSoundEnt->m_iActiveSound = pSoundEnt->m_SoundPool [ iSound ].m_iNext; - } - - // make iSound the head of the Free list. - pSoundEnt->m_SoundPool[ iSound ].m_iNext = pSoundEnt->m_iFreeSound; - pSoundEnt->m_iFreeSound = iSound; -} - -//========================================================= -// IAllocSound - moves a sound from the Free list to the -// Active list returns the index of the alloc'd sound -//========================================================= -int CSoundEnt :: IAllocSound( void ) -{ - int iNewSound; - - if ( m_iFreeSound == SOUNDLIST_EMPTY ) - { - // no free sound! - ALERT ( at_console, "Free Sound List is full!\n" ); - return SOUNDLIST_EMPTY; - } - - // there is at least one sound available, so move it to the - // Active sound list, and return its SoundPool index. - - iNewSound = m_iFreeSound;// copy the index of the next free sound - - m_iFreeSound = m_SoundPool[ m_iFreeSound ].m_iNext;// move the index down into the free list. - - m_SoundPool[ iNewSound ].m_iNext = m_iActiveSound;// point the new sound at the top of the active list. - - m_iActiveSound = iNewSound;// now make the new sound the top of the active list. You're done. - - return iNewSound; -} - -//========================================================= -// InsertSound - Allocates a free sound and fills it with -// sound info. -//========================================================= -void CSoundEnt :: InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) -{ - int iThisSound; - - if ( !pSoundEnt ) - { - // no sound ent! - return; - } - - iThisSound = pSoundEnt->IAllocSound(); - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Could not AllocSound() for InsertSound() (DLL)\n" ); - return; - } - - pSoundEnt->m_SoundPool[ iThisSound ].m_vecOrigin = vecOrigin; - pSoundEnt->m_SoundPool[ iThisSound ].m_iType = iType; - pSoundEnt->m_SoundPool[ iThisSound ].m_iVolume = iVolume; - pSoundEnt->m_SoundPool[ iThisSound ].m_flExpireTime = gpGlobals->time + flDuration; -} - -//========================================================= -// Initialize - clears all sounds and moves them into the -// free sound list. -//========================================================= -void CSoundEnt :: Initialize ( void ) -{ - int i; - int iSound; - - m_cLastActiveSounds; - m_iFreeSound = 0; - m_iActiveSound = SOUNDLIST_EMPTY; - - for ( i = 0 ; i < MAX_WORLD_SOUNDS ; i++ ) - {// clear all sounds, and link them into the free sound list. - m_SoundPool[ i ].Clear(); - m_SoundPool[ i ].m_iNext = i + 1; - } - - m_SoundPool[ i - 1 ].m_iNext = SOUNDLIST_EMPTY;// terminate the list here. - - - // now reserve enough sounds for each client - for ( i = 0 ; i < gpGlobals->maxClients ; i++ ) - { - iSound = pSoundEnt->IAllocSound(); - - if ( iSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Could not AllocSound() for Client Reserve! (DLL)\n" ); - return; - } - - pSoundEnt->m_SoundPool[ iSound ].m_flExpireTime = SOUND_NEVER_EXPIRE; - } - - if ( CVAR_GET_FLOAT("displaysoundlist") == 1 ) - { - m_fShowReport = TRUE; - } - else - { - m_fShowReport = FALSE; - } -} - -//========================================================= -// ISoundsInList - returns the number of sounds in the desired -// sound list. -//========================================================= -int CSoundEnt :: ISoundsInList ( int iListType ) -{ - int i; - int iThisSound; - - if ( iListType == SOUNDLISTTYPE_FREE ) - { - iThisSound = m_iFreeSound; - } - else if ( iListType == SOUNDLISTTYPE_ACTIVE ) - { - iThisSound = m_iActiveSound; - } - else - { - ALERT ( at_console, "Unknown Sound List Type!\n" ); - } - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - return 0; - } - - i = 0; - - while ( iThisSound != SOUNDLIST_EMPTY ) - { - i++; - - iThisSound = m_SoundPool[ iThisSound ].m_iNext; - } - - return i; -} - -//========================================================= -// ActiveList - returns the head of the active sound list -//========================================================= -int CSoundEnt :: ActiveList ( void ) -{ - if ( !pSoundEnt ) - { - return SOUNDLIST_EMPTY; - } - - return pSoundEnt->m_iActiveSound; -} - -//========================================================= -// FreeList - returns the head of the free sound list -//========================================================= -int CSoundEnt :: FreeList ( void ) -{ - if ( !pSoundEnt ) - { - return SOUNDLIST_EMPTY; - } - - return pSoundEnt->m_iFreeSound; -} - -//========================================================= -// SoundPointerForIndex - returns a pointer to the instance -// of CSound at index's position in the sound pool. -//========================================================= -CSound* CSoundEnt :: SoundPointerForIndex( int iIndex ) -{ - if ( !pSoundEnt ) - { - return NULL; - } - - if ( iIndex > ( MAX_WORLD_SOUNDS - 1 ) ) - { - ALERT ( at_console, "SoundPointerForIndex() - Index too large!\n" ); - return NULL; - } - - if ( iIndex < 0 ) - { - ALERT ( at_console, "SoundPointerForIndex() - Index < 0!\n" ); - return NULL; - } - - return &pSoundEnt->m_SoundPool[ iIndex ]; -} - -//========================================================= -// Clients are numbered from 1 to MAXCLIENTS, but the client -// reserved sounds in the soundlist are from 0 to MAXCLIENTS - 1, -// so this function ensures that a client gets the proper index -// to his reserved sound in the soundlist. -//========================================================= -int CSoundEnt :: ClientSoundIndex ( edict_t *pClient ) -{ - int iReturn = ENTINDEX( pClient ) - 1; - -#ifdef _DEBUG - if ( iReturn < 0 || iReturn > gpGlobals->maxClients ) - { - ALERT ( at_console, "** ClientSoundIndex returning a bogus value! **\n" ); - } -#endif // _DEBUG - - return iReturn; +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "soundent.h" + + +LINK_ENTITY_TO_CLASS( soundent, CSoundEnt ); + +CSoundEnt *pSoundEnt; + +//========================================================= +// CSound - Clear - zeros all fields for a sound +//========================================================= +void CSound :: Clear ( void ) +{ + m_vecOrigin = g_vecZero; + m_iType = 0; + m_iVolume = 0; + m_flExpireTime = 0; + m_iNext = SOUNDLIST_EMPTY; + m_iNextAudible = 0; +} + +//========================================================= +// Reset - clears the volume, origin, and type for a sound, +// but doesn't expire or unlink it. +//========================================================= +void CSound :: Reset ( void ) +{ + m_vecOrigin = g_vecZero; + m_iType = 0; + m_iVolume = 0; + m_iNext = SOUNDLIST_EMPTY; +} + +//========================================================= +// FIsSound - returns TRUE if the sound is an Audible sound +//========================================================= +BOOL CSound :: FIsSound ( void ) +{ + if ( m_iType & ( bits_SOUND_COMBAT | bits_SOUND_WORLD | bits_SOUND_PLAYER | bits_SOUND_DANGER ) ) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// FIsScent - returns TRUE if the sound is actually a scent +//========================================================= +BOOL CSound :: FIsScent ( void ) +{ + if ( m_iType & ( bits_SOUND_CARCASS | bits_SOUND_MEAT | bits_SOUND_GARBAGE ) ) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// Spawn +//========================================================= +void CSoundEnt :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + Initialize(); + + pev->nextthink = gpGlobals->time + 1; +} + +//========================================================= +// Think - at interval, the entire active sound list is checked +// for sounds that have ExpireTimes less than or equal +// to the current world time, and these sounds are deallocated. +//========================================================= +void CSoundEnt :: Think ( void ) +{ + int iSound; + int iPreviousSound; + + pev->nextthink = gpGlobals->time + 0.3;// how often to check the sound list. + + iPreviousSound = SOUNDLIST_EMPTY; + iSound = m_iActiveSound; + + while ( iSound != SOUNDLIST_EMPTY ) + { + if ( m_SoundPool[ iSound ].m_flExpireTime <= gpGlobals->time && m_SoundPool[ iSound ].m_flExpireTime != SOUND_NEVER_EXPIRE ) + { + int iNext = m_SoundPool[ iSound ].m_iNext; + + // move this sound back into the free list + FreeSound( iSound, iPreviousSound ); + + iSound = iNext; + } + else + { + iPreviousSound = iSound; + iSound = m_SoundPool[ iSound ].m_iNext; + } + } + + if ( m_fShowReport ) + { + ALERT ( at_aiconsole, "Soundlist: %d / %d (%d)\n", ISoundsInList( SOUNDLISTTYPE_ACTIVE ),ISoundsInList( SOUNDLISTTYPE_FREE ), ISoundsInList( SOUNDLISTTYPE_ACTIVE ) - m_cLastActiveSounds ); + m_cLastActiveSounds = ISoundsInList ( SOUNDLISTTYPE_ACTIVE ); + } + +} + +//========================================================= +// Precache - dummy function +//========================================================= +void CSoundEnt :: Precache ( void ) +{ +} + +//========================================================= +// FreeSound - clears the passed active sound and moves it +// to the top of the free list. TAKE CARE to only call this +// function for sounds in the Active list!! +//========================================================= +void CSoundEnt :: FreeSound ( int iSound, int iPrevious ) +{ + if ( !pSoundEnt ) + { + // no sound ent! + return; + } + + if ( iPrevious != SOUNDLIST_EMPTY ) + { + // iSound is not the head of the active list, so + // must fix the index for the Previous sound +// pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = m_SoundPool[ iSound ].m_iNext; + pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = pSoundEnt->m_SoundPool[ iSound ].m_iNext; + } + else + { + // the sound we're freeing IS the head of the active list. + pSoundEnt->m_iActiveSound = pSoundEnt->m_SoundPool [ iSound ].m_iNext; + } + + // make iSound the head of the Free list. + pSoundEnt->m_SoundPool[ iSound ].m_iNext = pSoundEnt->m_iFreeSound; + pSoundEnt->m_iFreeSound = iSound; +} + +//========================================================= +// IAllocSound - moves a sound from the Free list to the +// Active list returns the index of the alloc'd sound +//========================================================= +int CSoundEnt :: IAllocSound( void ) +{ + int iNewSound; + + if ( m_iFreeSound == SOUNDLIST_EMPTY ) + { + // no free sound! + ALERT ( at_console, "Free Sound List is full!\n" ); + return SOUNDLIST_EMPTY; + } + + // there is at least one sound available, so move it to the + // Active sound list, and return its SoundPool index. + + iNewSound = m_iFreeSound;// copy the index of the next free sound + + m_iFreeSound = m_SoundPool[ m_iFreeSound ].m_iNext;// move the index down into the free list. + + m_SoundPool[ iNewSound ].m_iNext = m_iActiveSound;// point the new sound at the top of the active list. + + m_iActiveSound = iNewSound;// now make the new sound the top of the active list. You're done. + + return iNewSound; +} + +//========================================================= +// InsertSound - Allocates a free sound and fills it with +// sound info. +//========================================================= +void CSoundEnt :: InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) +{ + int iThisSound; + + if ( !pSoundEnt ) + { + // no sound ent! + return; + } + + iThisSound = pSoundEnt->IAllocSound(); + + if ( iThisSound == SOUNDLIST_EMPTY ) + { + ALERT ( at_console, "Could not AllocSound() for InsertSound() (DLL)\n" ); + return; + } + + pSoundEnt->m_SoundPool[ iThisSound ].m_vecOrigin = vecOrigin; + pSoundEnt->m_SoundPool[ iThisSound ].m_iType = iType; + pSoundEnt->m_SoundPool[ iThisSound ].m_iVolume = iVolume; + pSoundEnt->m_SoundPool[ iThisSound ].m_flExpireTime = gpGlobals->time + flDuration; +} + +//========================================================= +// Initialize - clears all sounds and moves them into the +// free sound list. +//========================================================= +void CSoundEnt :: Initialize ( void ) +{ + int i; + int iSound; + + m_cLastActiveSounds; + m_iFreeSound = 0; + m_iActiveSound = SOUNDLIST_EMPTY; + + for ( i = 0 ; i < MAX_WORLD_SOUNDS ; i++ ) + {// clear all sounds, and link them into the free sound list. + m_SoundPool[ i ].Clear(); + m_SoundPool[ i ].m_iNext = i + 1; + } + + m_SoundPool[ i - 1 ].m_iNext = SOUNDLIST_EMPTY;// terminate the list here. + + + // now reserve enough sounds for each client + for ( i = 0 ; i < gpGlobals->maxClients ; i++ ) + { + iSound = pSoundEnt->IAllocSound(); + + if ( iSound == SOUNDLIST_EMPTY ) + { + ALERT ( at_console, "Could not AllocSound() for Client Reserve! (DLL)\n" ); + return; + } + + pSoundEnt->m_SoundPool[ iSound ].m_flExpireTime = SOUND_NEVER_EXPIRE; + } + + if ( CVAR_GET_FLOAT("displaysoundlist") == 1 ) + { + m_fShowReport = TRUE; + } + else + { + m_fShowReport = FALSE; + } +} + +//========================================================= +// ISoundsInList - returns the number of sounds in the desired +// sound list. +//========================================================= +int CSoundEnt :: ISoundsInList ( int iListType ) +{ + int i; + int iThisSound; + + if ( iListType == SOUNDLISTTYPE_FREE ) + { + iThisSound = m_iFreeSound; + } + else if ( iListType == SOUNDLISTTYPE_ACTIVE ) + { + iThisSound = m_iActiveSound; + } + else + { + ALERT ( at_console, "Unknown Sound List Type!\n" ); + } + + if ( iThisSound == SOUNDLIST_EMPTY ) + { + return 0; + } + + i = 0; + + while ( iThisSound != SOUNDLIST_EMPTY ) + { + i++; + + iThisSound = m_SoundPool[ iThisSound ].m_iNext; + } + + return i; +} + +//========================================================= +// ActiveList - returns the head of the active sound list +//========================================================= +int CSoundEnt :: ActiveList ( void ) +{ + if ( !pSoundEnt ) + { + return SOUNDLIST_EMPTY; + } + + return pSoundEnt->m_iActiveSound; +} + +//========================================================= +// FreeList - returns the head of the free sound list +//========================================================= +int CSoundEnt :: FreeList ( void ) +{ + if ( !pSoundEnt ) + { + return SOUNDLIST_EMPTY; + } + + return pSoundEnt->m_iFreeSound; +} + +//========================================================= +// SoundPointerForIndex - returns a pointer to the instance +// of CSound at index's position in the sound pool. +//========================================================= +CSound* CSoundEnt :: SoundPointerForIndex( int iIndex ) +{ + if ( !pSoundEnt ) + { + return NULL; + } + + if ( iIndex > ( MAX_WORLD_SOUNDS - 1 ) ) + { + ALERT ( at_console, "SoundPointerForIndex() - Index too large!\n" ); + return NULL; + } + + if ( iIndex < 0 ) + { + ALERT ( at_console, "SoundPointerForIndex() - Index < 0!\n" ); + return NULL; + } + + return &pSoundEnt->m_SoundPool[ iIndex ]; +} + +//========================================================= +// Clients are numbered from 1 to MAXCLIENTS, but the client +// reserved sounds in the soundlist are from 0 to MAXCLIENTS - 1, +// so this function ensures that a client gets the proper index +// to his reserved sound in the soundlist. +//========================================================= +int CSoundEnt :: ClientSoundIndex ( edict_t *pClient ) +{ + int iReturn = ENTINDEX( pClient ) - 1; + +#ifdef _DEBUG + if ( iReturn < 0 || iReturn > gpGlobals->maxClients ) + { + ALERT ( at_console, "** ClientSoundIndex returning a bogus value! **\n" ); + } +#endif // _DEBUG + + return iReturn; } \ No newline at end of file diff --git a/main/source/dlls/soundent.h b/main/source/dlls/soundent.h index 3d1c5cb7..bbb2981c 100644 --- a/main/source/dlls/soundent.h +++ b/main/source/dlls/soundent.h @@ -1,99 +1,99 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Soundent.h - the entity that spawns when the world -// spawns, and handles the world's active and free sound -// lists. -//========================================================= -#ifndef SOUNDENT_H -#define SOUNDENT_H - -#define MAX_WORLD_SOUNDS 64 // maximum number of sounds handled by the world at one time. - -#define bits_SOUND_NONE 0 -#define bits_SOUND_COMBAT ( 1 << 0 )// gunshots, explosions -#define bits_SOUND_WORLD ( 1 << 1 )// door opening/closing, glass breaking -#define bits_SOUND_PLAYER ( 1 << 2 )// all noises generated by player. walking, shooting, falling, splashing -#define bits_SOUND_CARCASS ( 1 << 3 )// dead body -#define bits_SOUND_MEAT ( 1 << 4 )// gib or pork chop -#define bits_SOUND_DANGER ( 1 << 5 )// pending danger. Grenade that is about to explode, explosive barrel that is damaged, falling crate -#define bits_SOUND_GARBAGE ( 1 << 6 )// trash cans, banana peels, old fast food bags. - -#define bits_ALL_SOUNDS 0xFFFFFFFF - -#define SOUNDLIST_EMPTY -1 - -#define SOUNDLISTTYPE_FREE 1// identifiers passed to functions that can operate on either list, to indicate which list to operate on. -#define SOUNDLISTTYPE_ACTIVE 2 - -#define SOUND_NEVER_EXPIRE -1 // with this set as a sound's ExpireTime, the sound will never expire. - -//========================================================= -// CSound - an instance of a sound in the world. -//========================================================= -class CSound -{ -public: - - void Clear ( void ); - void Reset ( void ); - - Vector m_vecOrigin; // sound's location in space - int m_iType; // what type of sound this is - int m_iVolume; // how loud the sound is - float m_flExpireTime; // when the sound should be purged from the list - int m_iNext; // index of next sound in this list ( Active or Free ) - int m_iNextAudible; // temporary link that monsters use to build a list of audible sounds - - BOOL FIsSound( void ); - BOOL FIsScent( void ); -}; - -//========================================================= -// CSoundEnt - a single instance of this entity spawns when -// the world spawns. The SoundEnt's job is to update the -// world's Free and Active sound lists. -//========================================================= -class CSoundEnt : public CBaseEntity -{ -public: - - void Precache ( void ); - void Spawn( void ); - void Think( void ); - void Initialize ( void ); - - static void InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ); - static void FreeSound ( int iSound, int iPrevious ); - static int ActiveList( void );// return the head of the active list - static int FreeList( void );// return the head of the free list - static CSound* SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list - static int ClientSoundIndex ( edict_t *pClient ); - - BOOL IsEmpty( void ) { return m_iActiveSound == SOUNDLIST_EMPTY; } - int ISoundsInList ( int iListType ); - int IAllocSound ( void ); - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - - int m_iFreeSound; // index of the first sound in the free sound list - int m_iActiveSound; // indes of the first sound in the active sound list - int m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work) - BOOL m_fShowReport; // if true, dump information about free/active sounds. - -private: - CSound m_SoundPool[ MAX_WORLD_SOUNDS ]; -}; - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Soundent.h - the entity that spawns when the world +// spawns, and handles the world's active and free sound +// lists. +//========================================================= +#ifndef SOUNDENT_H +#define SOUNDENT_H + +#define MAX_WORLD_SOUNDS 64 // maximum number of sounds handled by the world at one time. + +#define bits_SOUND_NONE 0 +#define bits_SOUND_COMBAT ( 1 << 0 )// gunshots, explosions +#define bits_SOUND_WORLD ( 1 << 1 )// door opening/closing, glass breaking +#define bits_SOUND_PLAYER ( 1 << 2 )// all noises generated by player. walking, shooting, falling, splashing +#define bits_SOUND_CARCASS ( 1 << 3 )// dead body +#define bits_SOUND_MEAT ( 1 << 4 )// gib or pork chop +#define bits_SOUND_DANGER ( 1 << 5 )// pending danger. Grenade that is about to explode, explosive barrel that is damaged, falling crate +#define bits_SOUND_GARBAGE ( 1 << 6 )// trash cans, banana peels, old fast food bags. + +#define bits_ALL_SOUNDS 0xFFFFFFFF + +#define SOUNDLIST_EMPTY -1 + +#define SOUNDLISTTYPE_FREE 1// identifiers passed to functions that can operate on either list, to indicate which list to operate on. +#define SOUNDLISTTYPE_ACTIVE 2 + +#define SOUND_NEVER_EXPIRE -1 // with this set as a sound's ExpireTime, the sound will never expire. + +//========================================================= +// CSound - an instance of a sound in the world. +//========================================================= +class CSound +{ +public: + + void Clear ( void ); + void Reset ( void ); + + Vector m_vecOrigin; // sound's location in space + int m_iType; // what type of sound this is + int m_iVolume; // how loud the sound is + float m_flExpireTime; // when the sound should be purged from the list + int m_iNext; // index of next sound in this list ( Active or Free ) + int m_iNextAudible; // temporary link that monsters use to build a list of audible sounds + + BOOL FIsSound( void ); + BOOL FIsScent( void ); +}; + +//========================================================= +// CSoundEnt - a single instance of this entity spawns when +// the world spawns. The SoundEnt's job is to update the +// world's Free and Active sound lists. +//========================================================= +class CSoundEnt : public CBaseEntity +{ +public: + + void Precache ( void ); + void Spawn( void ); + void Think( void ); + void Initialize ( void ); + + static void InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ); + static void FreeSound ( int iSound, int iPrevious ); + static int ActiveList( void );// return the head of the active list + static int FreeList( void );// return the head of the free list + static CSound* SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list + static int ClientSoundIndex ( edict_t *pClient ); + + BOOL IsEmpty( void ) { return m_iActiveSound == SOUNDLIST_EMPTY; } + int ISoundsInList ( int iListType ); + int IAllocSound ( void ); + virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + + int m_iFreeSound; // index of the first sound in the free sound list + int m_iActiveSound; // indes of the first sound in the active sound list + int m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work) + BOOL m_fShowReport; // if true, dump information about free/active sounds. + +private: + CSound m_SoundPool[ MAX_WORLD_SOUNDS ]; +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/spectator.cpp b/main/source/dlls/spectator.cpp index 28002eb6..4e307b6c 100644 --- a/main/source/dlls/spectator.cpp +++ b/main/source/dlls/spectator.cpp @@ -1,149 +1,149 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// CBaseSpectator - -// YWB: UNDONE - -// Spectator functions -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "spectator.h" - -/* -=========== -SpectatorConnect - -called when a spectator connects to a server -============ -*/ -void CBaseSpectator::SpectatorConnect(void) -{ - pev->flags = FL_SPECTATOR; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_pGoalEnt = NULL; -} - -/* -=========== -SpectatorDisconnect - -called when a spectator disconnects from a server -============ -*/ -void CBaseSpectator::SpectatorDisconnect(void) -{ -} - -/* -================ -SpectatorImpulseCommand - -Called by SpectatorThink if the spectator entered an impulse -================ -*/ -void CBaseSpectator::SpectatorImpulseCommand(void) -{ - static edict_t *pGoal = NULL; - edict_t *pPreviousGoal; - edict_t *pCurrentGoal; - BOOL bFound; - - switch (pev->impulse) - { - case 1: - // teleport the spectator to the next spawn point - // note that if the spectator is tracking, this doesn't do - // much - pPreviousGoal = pGoal; - pCurrentGoal = pGoal; - // Start at the current goal, skip the world, and stop if we looped - // back around - - bFound = FALSE; - while (1) - { - pCurrentGoal = FIND_ENTITY_BY_CLASSNAME(pCurrentGoal, "info_player_deathmatch"); - // Looped around, failure - if (pCurrentGoal == pPreviousGoal) - { - ALERT(at_console, "Could not find a spawn spot.\n"); - break; - } - // Found a non-world entity, set success, otherwise, look for the next one. - if (!FNullEnt(pCurrentGoal)) - { - bFound = TRUE; - break; - } - } - - if (!bFound) // Didn't find a good spot. - break; - - pGoal = pCurrentGoal; - UTIL_SetOrigin( pev, pGoal->v.origin ); - pev->angles = pGoal->v.angles; - pev->fixangle = FALSE; - break; - default: - ALERT(at_console, "Unknown spectator impulse\n"); - break; - } - - pev->impulse = 0; -} - -/* -================ -SpectatorThink - -Called every frame after physics are run -================ -*/ -void CBaseSpectator::SpectatorThink(void) -{ - if (!(pev->flags & FL_SPECTATOR)) - { - pev->flags = FL_SPECTATOR; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - if (pev->impulse) - SpectatorImpulseCommand(); -} - -/* -=========== -Spawn - - Called when spectator is initialized: - UNDONE: Is this actually being called because spectators are not allocated in normal fashion? -============ -*/ -void CBaseSpectator::Spawn() -{ - pev->flags = FL_SPECTATOR; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_pGoalEnt = NULL; -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// CBaseSpectator + +// YWB: UNDONE + +// Spectator functions +// +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "spectator.h" + +/* +=========== +SpectatorConnect + +called when a spectator connects to a server +============ +*/ +void CBaseSpectator::SpectatorConnect(void) +{ + pev->flags = FL_SPECTATOR; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NOCLIP; + + m_pGoalEnt = NULL; +} + +/* +=========== +SpectatorDisconnect + +called when a spectator disconnects from a server +============ +*/ +void CBaseSpectator::SpectatorDisconnect(void) +{ +} + +/* +================ +SpectatorImpulseCommand + +Called by SpectatorThink if the spectator entered an impulse +================ +*/ +void CBaseSpectator::SpectatorImpulseCommand(void) +{ + static edict_t *pGoal = NULL; + edict_t *pPreviousGoal; + edict_t *pCurrentGoal; + BOOL bFound; + + switch (pev->impulse) + { + case 1: + // teleport the spectator to the next spawn point + // note that if the spectator is tracking, this doesn't do + // much + pPreviousGoal = pGoal; + pCurrentGoal = pGoal; + // Start at the current goal, skip the world, and stop if we looped + // back around + + bFound = FALSE; + while (1) + { + pCurrentGoal = FIND_ENTITY_BY_CLASSNAME(pCurrentGoal, "info_player_deathmatch"); + // Looped around, failure + if (pCurrentGoal == pPreviousGoal) + { + ALERT(at_console, "Could not find a spawn spot.\n"); + break; + } + // Found a non-world entity, set success, otherwise, look for the next one. + if (!FNullEnt(pCurrentGoal)) + { + bFound = TRUE; + break; + } + } + + if (!bFound) // Didn't find a good spot. + break; + + pGoal = pCurrentGoal; + UTIL_SetOrigin( pev, pGoal->v.origin ); + pev->angles = pGoal->v.angles; + pev->fixangle = FALSE; + break; + default: + ALERT(at_console, "Unknown spectator impulse\n"); + break; + } + + pev->impulse = 0; +} + +/* +================ +SpectatorThink + +Called every frame after physics are run +================ +*/ +void CBaseSpectator::SpectatorThink(void) +{ + if (!(pev->flags & FL_SPECTATOR)) + { + pev->flags = FL_SPECTATOR; + } + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NOCLIP; + + if (pev->impulse) + SpectatorImpulseCommand(); +} + +/* +=========== +Spawn + + Called when spectator is initialized: + UNDONE: Is this actually being called because spectators are not allocated in normal fashion? +============ +*/ +void CBaseSpectator::Spawn() +{ + pev->flags = FL_SPECTATOR; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NOCLIP; + + m_pGoalEnt = NULL; +} diff --git a/main/source/dlls/spectator.h b/main/source/dlls/spectator.h index f4c4ef37..0a90d97d 100644 --- a/main/source/dlls/spectator.h +++ b/main/source/dlls/spectator.h @@ -1,27 +1,27 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Spectator.h - -class CBaseSpectator : public CBaseEntity -{ -public: - void Spawn(); - void SpectatorConnect(void); - void SpectatorDisconnect(void); - void SpectatorThink(void); - -private: - void SpectatorImpulseCommand(void); +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Spectator.h + +class CBaseSpectator : public CBaseEntity +{ +public: + void Spawn(); + void SpectatorConnect(void); + void SpectatorDisconnect(void); + void SpectatorThink(void); + +private: + void SpectatorImpulseCommand(void); }; \ No newline at end of file diff --git a/main/source/dlls/squad.h b/main/source/dlls/squad.h index abf3194f..0d0f7330 100644 --- a/main/source/dlls/squad.h +++ b/main/source/dlls/squad.h @@ -1,13 +1,13 @@ -//========================================================= -// squad.h -//========================================================= - -// these are special group roles that are assigned to members when the group is formed. -// the reason these are explicitly assigned and tasks like throwing grenades to flush out -// enemies is that it's bad to have two members trying to flank left at the same time, but -// ok to have two throwing grenades at the same time. When a squad member cannot attack the -// enemy, it will choose to execute its special role. -#define bits_SQUAD_FLANK_LEFT ( 1 << 0 ) -#define bits_SQUAD_FLANK_RIGHT ( 1 << 1 ) -#define bits_SQUAD_ADVANCE ( 1 << 2 ) +//========================================================= +// squad.h +//========================================================= + +// these are special group roles that are assigned to members when the group is formed. +// the reason these are explicitly assigned and tasks like throwing grenades to flush out +// enemies is that it's bad to have two members trying to flank left at the same time, but +// ok to have two throwing grenades at the same time. When a squad member cannot attack the +// enemy, it will choose to execute its special role. +#define bits_SQUAD_FLANK_LEFT ( 1 << 0 ) +#define bits_SQUAD_FLANK_RIGHT ( 1 << 1 ) +#define bits_SQUAD_ADVANCE ( 1 << 2 ) #define bits_SQUAD_FLUSH_ATTACK ( 1 << 3 ) \ No newline at end of file diff --git a/main/source/dlls/squadmonster.cpp b/main/source/dlls/squadmonster.cpp index 35d52ca1..ab6aabd5 100644 --- a/main/source/dlls/squadmonster.cpp +++ b/main/source/dlls/squadmonster.cpp @@ -1,623 +1,623 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Squadmonster functions -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "squadmonster.h" -#include "plane.h" - -//========================================================= -// Save/Restore -//========================================================= -TYPEDESCRIPTION CSquadMonster::m_SaveData[] = -{ - DEFINE_FIELD( CSquadMonster, m_hSquadLeader, FIELD_EHANDLE ), - DEFINE_ARRAY( CSquadMonster, m_hSquadMember, FIELD_EHANDLE, MAX_SQUAD_MEMBERS - 1 ), - - // DEFINE_FIELD( CSquadMonster, m_afSquadSlots, FIELD_INTEGER ), // these need to be reset after transitions! - DEFINE_FIELD( CSquadMonster, m_fEnemyEluded, FIELD_BOOLEAN ), - DEFINE_FIELD( CSquadMonster, m_flLastEnemySightTime, FIELD_TIME ), - - DEFINE_FIELD( CSquadMonster, m_iMySlot, FIELD_INTEGER ), - - -}; - -IMPLEMENT_SAVERESTORE( CSquadMonster, CBaseMonster ); - - -//========================================================= -// OccupySlot - if any slots of the passed slots are -// available, the monster will be assigned to one. -//========================================================= -BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) -{ - int i; - int iMask; - int iSquadSlots; - - if ( !InSquad() ) - { - return TRUE; - } - - if ( SquadEnemySplit() ) - { - // if the squad members aren't all fighting the same enemy, slots are disabled - // so that a squad member doesn't get stranded unable to engage his enemy because - // all of the attack slots are taken by squad members fighting other enemies. - m_iMySlot = bits_SLOT_SQUAD_SPLIT; - return TRUE; - } - - CSquadMonster *pSquadLeader = MySquadLeader(); - - if ( !( iDesiredSlots ^ pSquadLeader->m_afSquadSlots ) ) - { - // none of the desired slots are available. - return FALSE; - } - - iSquadSlots = pSquadLeader->m_afSquadSlots; - - for ( i = 0; i < NUM_SLOTS; i++ ) - { - iMask = 1<m_afSquadSlots |= iMask; - m_iMySlot = iMask; -// ALERT ( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots ); - return TRUE; - } - } - } - - return FALSE; -} - -//========================================================= -// VacateSlot -//========================================================= -void CSquadMonster :: VacateSlot() -{ - if ( m_iMySlot != bits_NO_SLOT && InSquad() ) - { -// ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); - MySquadLeader()->m_afSquadSlots &= ~m_iMySlot; - m_iMySlot = bits_NO_SLOT; - } -} - -//========================================================= -// ScheduleChange -//========================================================= -void CSquadMonster :: ScheduleChange ( void ) -{ - VacateSlot(); -} - -//========================================================= -// Killed -//========================================================= -void CSquadMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - VacateSlot(); - - if ( InSquad() ) - { - MySquadLeader()->SquadRemove( this ); - } - - CBaseMonster :: Killed ( pevAttacker, iGib ); -} - -// These functions are still awaiting conversion to CSquadMonster - - -//========================================================= -// -// SquadRemove(), remove pRemove from my squad. -// If I am pRemove, promote m_pSquadNext to leader -// -//========================================================= -void CSquadMonster :: SquadRemove( CSquadMonster *pRemove ) -{ - ASSERT( pRemove!=NULL ); - ASSERT( this->IsLeader() ); - ASSERT( pRemove->m_hSquadLeader == this ); - - // If I'm the leader, get rid of my squad - if (pRemove == MySquadLeader()) - { - for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) - { - CSquadMonster *pMember = MySquadMember(i); - if (pMember) - { - pMember->m_hSquadLeader = NULL; - m_hSquadMember[i] = NULL; - } - } - } - else - { - CSquadMonster *pSquadLeader = MySquadLeader(); - if (pSquadLeader) - { - for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) - { - if (pSquadLeader->m_hSquadMember[i] == this) - { - pSquadLeader->m_hSquadMember[i] = NULL; - break; - } - } - } - } - - pRemove->m_hSquadLeader = NULL; -} - -//========================================================= -// -// SquadAdd(), add pAdd to my squad -// -//========================================================= -BOOL CSquadMonster :: SquadAdd( CSquadMonster *pAdd ) -{ - ASSERT( pAdd!=NULL ); - ASSERT( !pAdd->InSquad() ); - ASSERT( this->IsLeader() ); - - for (int i = 0; i < MAX_SQUAD_MEMBERS-1; i++) - { - if (m_hSquadMember[i] == NULL) - { - m_hSquadMember[i] = pAdd; - pAdd->m_hSquadLeader = this; - return TRUE; - } - } - return FALSE; - // should complain here -} - - -//========================================================= -// -// SquadPasteEnemyInfo - called by squad members that have -// current info on the enemy so that it can be stored for -// members who don't have current info. -// -//========================================================= -void CSquadMonster :: SquadPasteEnemyInfo ( void ) -{ - CSquadMonster *pSquadLeader = MySquadLeader( ); - if (pSquadLeader) - pSquadLeader->m_vecEnemyLKP = m_vecEnemyLKP; -} - -//========================================================= -// -// SquadCopyEnemyInfo - called by squad members who don't -// have current info on the enemy. Reads from the same fields -// in the leader's data that other squad members write to, -// so the most recent data is always available here. -// -//========================================================= -void CSquadMonster :: SquadCopyEnemyInfo ( void ) -{ - CSquadMonster *pSquadLeader = MySquadLeader( ); - if (pSquadLeader) - m_vecEnemyLKP = pSquadLeader->m_vecEnemyLKP; -} - -//========================================================= -// -// SquadMakeEnemy - makes everyone in the squad angry at -// the same entity. -// -//========================================================= -void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) -{ - if (!InSquad()) - return; - - if ( !pEnemy ) - { - ALERT ( at_console, "ERROR: SquadMakeEnemy() - pEnemy is NULL!\n" ); - return; - } - - CSquadMonster *pSquadLeader = MySquadLeader( ); - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember) - { - // reset members who aren't activly engaged in fighting - if (pMember->m_hEnemy != pEnemy && !pMember->HasConditions( bits_COND_SEE_ENEMY)) - { - if ( pMember->m_hEnemy != NULL) - { - // remember their current enemy - pMember->PushEnemy( pMember->m_hEnemy, pMember->m_vecEnemyLKP ); - } - // give them a new enemy - pMember->m_hEnemy = pEnemy; - pMember->m_vecEnemyLKP = pEnemy->pev->origin; - pMember->SetConditions ( bits_COND_NEW_ENEMY ); - } - } - } -} - - -//========================================================= -// -// SquadCount(), return the number of members of this squad -// callable from leaders & followers -// -//========================================================= -int CSquadMonster :: SquadCount( void ) -{ - if (!InSquad()) - return 0; - - CSquadMonster *pSquadLeader = MySquadLeader(); - int squadCount = 0; - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - if (pSquadLeader->MySquadMember(i) != NULL) - squadCount++; - } - - return squadCount; -} - - -//========================================================= -// -// SquadRecruit(), get some monsters of my classification and -// link them as a group. returns the group size -// -//========================================================= -int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) -{ - int squadCount; - int iMyClass = Classify();// cache this monster's class - - - // Don't recruit if I'm already in a group - if ( InSquad() ) - return 0; - - if ( maxMembers < 2 ) - return 0; - - // I am my own leader - m_hSquadLeader = this; - squadCount = 1; - - CBaseEntity *pEntity = NULL; - - if ( !FStringNull( pev->netname ) ) - { - // I have a netname, so unconditionally recruit everyone else with that name. - pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); - while ( pEntity ) - { - CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer(); - - if ( pRecruit ) - { - if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this ) - { - // minimum protection here against user error.in worldcraft. - if (!SquadAdd( pRecruit )) - break; - squadCount++; - } - } - - pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); - } - } - else - { - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, searchRadius )) != NULL) - { - CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer( ); - - if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) - { - // Can we recruit this guy? - if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && - ( (iMyClass != CLASS_ALIEN_MONSTER) || FStrEq(STRING(pev->classname), STRING(pRecruit->pev->classname))) && - FStringNull( pRecruit->pev->netname ) ) - { - TraceResult tr; - UTIL_TraceLine( pev->origin + pev->view_ofs, pRecruit->pev->origin + pev->view_ofs, ignore_monsters, pRecruit->edict(), &tr );// try to hit recruit with a traceline. - if ( tr.flFraction == 1.0 ) - { - if (!SquadAdd( pRecruit )) - break; - - squadCount++; - } - } - } - } - } - - // no single member squads - if (squadCount == 1) - { - m_hSquadLeader = NULL; - } - - return squadCount; -} - -//========================================================= -// CheckEnemy -//========================================================= -int CSquadMonster :: CheckEnemy ( CBaseEntity *pEnemy ) -{ - int iUpdatedLKP; - - iUpdatedLKP = CBaseMonster :: CheckEnemy ( m_hEnemy ); - - // communicate with squad members about the enemy IF this individual has the same enemy as the squad leader. - if ( InSquad() && (CBaseEntity *)m_hEnemy == MySquadLeader()->m_hEnemy ) - { - if ( iUpdatedLKP ) - { - // have new enemy information, so paste to the squad. - SquadPasteEnemyInfo(); - } - else - { - // enemy unseen, copy from the squad knowledge. - SquadCopyEnemyInfo(); - } - } - - return iUpdatedLKP; -} - -//========================================================= -// StartMonster -//========================================================= -void CSquadMonster :: StartMonster( void ) -{ - CBaseMonster :: StartMonster(); - - if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) - { - if ( !FStringNull( pev->netname ) ) - { - // if I have a groupname, I can only recruit if I'm flagged as leader - if ( !( pev->spawnflags & SF_SQUADMONSTER_LEADER ) ) - { - return; - } - } - - // try to form squads now. - int iSquadSize = SquadRecruit( 1024, 4 ); - - if ( iSquadSize ) - { - ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); - } - - if ( IsLeader() && FClassnameIs ( pev, "monster_human_grunt" ) ) - { - SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack - pev->skin = 0; - } - - } -} - -//========================================================= -// NoFriendlyFire - checks for possibility of friendly fire -// -// Builds a large box in front of the grunt and checks to see -// if any squad members are in that box. -//========================================================= -BOOL CSquadMonster :: NoFriendlyFire( void ) -{ - if ( !InSquad() ) - { - return TRUE; - } - - CPlane backPlane; - CPlane leftPlane; - CPlane rightPlane; - - Vector vecLeftSide; - Vector vecRightSide; - Vector v_left; - - //!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!! - - if ( m_hEnemy != NULL ) - { - UTIL_MakeVectors ( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); - } - else - { - // if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot. - return FALSE; - } - - //UTIL_MakeVectors ( pev->angles ); - - vecLeftSide = pev->origin - ( gpGlobals->v_right * ( pev->size.x * 1.5 ) ); - vecRightSide = pev->origin + ( gpGlobals->v_right * ( pev->size.x * 1.5 ) ); - v_left = gpGlobals->v_right * -1; - - leftPlane.InitializePlane ( gpGlobals->v_right, vecLeftSide ); - rightPlane.InitializePlane ( v_left, vecRightSide ); - backPlane.InitializePlane ( gpGlobals->v_forward, pev->origin ); - -/* - ALERT ( at_console, "LeftPlane: %f %f %f : %f\n", leftPlane.m_vecNormal.x, leftPlane.m_vecNormal.y, leftPlane.m_vecNormal.z, leftPlane.m_flDist ); - ALERT ( at_console, "RightPlane: %f %f %f : %f\n", rightPlane.m_vecNormal.x, rightPlane.m_vecNormal.y, rightPlane.m_vecNormal.z, rightPlane.m_flDist ); - ALERT ( at_console, "BackPlane: %f %f %f : %f\n", backPlane.m_vecNormal.x, backPlane.m_vecNormal.y, backPlane.m_vecNormal.z, backPlane.m_flDist ); -*/ - - CSquadMonster *pSquadLeader = MySquadLeader(); - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember && pMember != this) - { - - if ( backPlane.PointInFront ( pMember->pev->origin ) && - leftPlane.PointInFront ( pMember->pev->origin ) && - rightPlane.PointInFront ( pMember->pev->origin) ) - { - // this guy is in the check volume! Don't shoot! - return FALSE; - } - } - } - - return TRUE; -} - -//========================================================= -// GetIdealState - surveys the Conditions information available -// and finds the best new state for a monster. -//========================================================= -MONSTERSTATE CSquadMonster :: GetIdealState ( void ) -{ - int iConditions; - - iConditions = IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - case MONSTERSTATE_ALERT: - if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) - { - SquadMakeEnemy ( m_hEnemy ); - } - break; - } - - return CBaseMonster :: GetIdealState(); -} - -//========================================================= -// FValidateCover - determines whether or not the chosen -// cover location is a good one to move to. (currently based -// on proximity to others in the squad) -//========================================================= -BOOL CSquadMonster :: FValidateCover ( const Vector &vecCoverLocation ) -{ - if ( !InSquad() ) - { - return TRUE; - } - - if (SquadMemberInRange( vecCoverLocation, 128 )) - { - // another squad member is too close to this piece of cover. - return FALSE; - } - - return TRUE; -} - -//========================================================= -// SquadEnemySplit- returns TRUE if not all squad members -// are fighting the same enemy. -//========================================================= -BOOL CSquadMonster :: SquadEnemySplit ( void ) -{ - if (!InSquad()) - return FALSE; - - CSquadMonster *pSquadLeader = MySquadLeader(); - CBaseEntity *pEnemy = pSquadLeader->m_hEnemy; - - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy) - { - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// FValidateCover - determines whether or not the chosen -// cover location is a good one to move to. (currently based -// on proximity to others in the squad) -//========================================================= -BOOL CSquadMonster :: SquadMemberInRange ( const Vector &vecLocation, float flDist ) -{ - if (!InSquad()) - return FALSE; - - CSquadMonster *pSquadLeader = MySquadLeader(); - - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pSquadMember = pSquadLeader->MySquadMember(i); - if (pSquadMember && (vecLocation - pSquadMember->pev->origin ).Length2D() <= flDist) - return TRUE; - } - return FALSE; -} - - -extern Schedule_t slChaseEnemyFailed[]; - -Schedule_t *CSquadMonster::GetScheduleOfType( int iType ) -{ - switch ( iType ) - { - - case SCHED_CHASE_ENEMY_FAILED: - { - return &slChaseEnemyFailed[ 0 ]; - } - - default: - return CBaseMonster::GetScheduleOfType( iType ); - } -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Squadmonster functions +//========================================================= +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "nodes.h" +#include "monsters.h" +#include "animation.h" +#include "saverestore.h" +#include "squadmonster.h" +#include "plane.h" + +//========================================================= +// Save/Restore +//========================================================= +TYPEDESCRIPTION CSquadMonster::m_SaveData[] = +{ + DEFINE_FIELD( CSquadMonster, m_hSquadLeader, FIELD_EHANDLE ), + DEFINE_ARRAY( CSquadMonster, m_hSquadMember, FIELD_EHANDLE, MAX_SQUAD_MEMBERS - 1 ), + + // DEFINE_FIELD( CSquadMonster, m_afSquadSlots, FIELD_INTEGER ), // these need to be reset after transitions! + DEFINE_FIELD( CSquadMonster, m_fEnemyEluded, FIELD_BOOLEAN ), + DEFINE_FIELD( CSquadMonster, m_flLastEnemySightTime, FIELD_TIME ), + + DEFINE_FIELD( CSquadMonster, m_iMySlot, FIELD_INTEGER ), + + +}; + +IMPLEMENT_SAVERESTORE( CSquadMonster, CBaseMonster ); + + +//========================================================= +// OccupySlot - if any slots of the passed slots are +// available, the monster will be assigned to one. +//========================================================= +BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) +{ + int i; + int iMask; + int iSquadSlots; + + if ( !InSquad() ) + { + return TRUE; + } + + if ( SquadEnemySplit() ) + { + // if the squad members aren't all fighting the same enemy, slots are disabled + // so that a squad member doesn't get stranded unable to engage his enemy because + // all of the attack slots are taken by squad members fighting other enemies. + m_iMySlot = bits_SLOT_SQUAD_SPLIT; + return TRUE; + } + + CSquadMonster *pSquadLeader = MySquadLeader(); + + if ( !( iDesiredSlots ^ pSquadLeader->m_afSquadSlots ) ) + { + // none of the desired slots are available. + return FALSE; + } + + iSquadSlots = pSquadLeader->m_afSquadSlots; + + for ( i = 0; i < NUM_SLOTS; i++ ) + { + iMask = 1<m_afSquadSlots |= iMask; + m_iMySlot = iMask; +// ALERT ( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots ); + return TRUE; + } + } + } + + return FALSE; +} + +//========================================================= +// VacateSlot +//========================================================= +void CSquadMonster :: VacateSlot() +{ + if ( m_iMySlot != bits_NO_SLOT && InSquad() ) + { +// ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); + MySquadLeader()->m_afSquadSlots &= ~m_iMySlot; + m_iMySlot = bits_NO_SLOT; + } +} + +//========================================================= +// ScheduleChange +//========================================================= +void CSquadMonster :: ScheduleChange ( void ) +{ + VacateSlot(); +} + +//========================================================= +// Killed +//========================================================= +void CSquadMonster :: Killed( entvars_t *pevAttacker, int iGib ) +{ + VacateSlot(); + + if ( InSquad() ) + { + MySquadLeader()->SquadRemove( this ); + } + + CBaseMonster :: Killed ( pevAttacker, iGib ); +} + +// These functions are still awaiting conversion to CSquadMonster + + +//========================================================= +// +// SquadRemove(), remove pRemove from my squad. +// If I am pRemove, promote m_pSquadNext to leader +// +//========================================================= +void CSquadMonster :: SquadRemove( CSquadMonster *pRemove ) +{ + ASSERT( pRemove!=NULL ); + ASSERT( this->IsLeader() ); + ASSERT( pRemove->m_hSquadLeader == this ); + + // If I'm the leader, get rid of my squad + if (pRemove == MySquadLeader()) + { + for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) + { + CSquadMonster *pMember = MySquadMember(i); + if (pMember) + { + pMember->m_hSquadLeader = NULL; + m_hSquadMember[i] = NULL; + } + } + } + else + { + CSquadMonster *pSquadLeader = MySquadLeader(); + if (pSquadLeader) + { + for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) + { + if (pSquadLeader->m_hSquadMember[i] == this) + { + pSquadLeader->m_hSquadMember[i] = NULL; + break; + } + } + } + } + + pRemove->m_hSquadLeader = NULL; +} + +//========================================================= +// +// SquadAdd(), add pAdd to my squad +// +//========================================================= +BOOL CSquadMonster :: SquadAdd( CSquadMonster *pAdd ) +{ + ASSERT( pAdd!=NULL ); + ASSERT( !pAdd->InSquad() ); + ASSERT( this->IsLeader() ); + + for (int i = 0; i < MAX_SQUAD_MEMBERS-1; i++) + { + if (m_hSquadMember[i] == NULL) + { + m_hSquadMember[i] = pAdd; + pAdd->m_hSquadLeader = this; + return TRUE; + } + } + return FALSE; + // should complain here +} + + +//========================================================= +// +// SquadPasteEnemyInfo - called by squad members that have +// current info on the enemy so that it can be stored for +// members who don't have current info. +// +//========================================================= +void CSquadMonster :: SquadPasteEnemyInfo ( void ) +{ + CSquadMonster *pSquadLeader = MySquadLeader( ); + if (pSquadLeader) + pSquadLeader->m_vecEnemyLKP = m_vecEnemyLKP; +} + +//========================================================= +// +// SquadCopyEnemyInfo - called by squad members who don't +// have current info on the enemy. Reads from the same fields +// in the leader's data that other squad members write to, +// so the most recent data is always available here. +// +//========================================================= +void CSquadMonster :: SquadCopyEnemyInfo ( void ) +{ + CSquadMonster *pSquadLeader = MySquadLeader( ); + if (pSquadLeader) + m_vecEnemyLKP = pSquadLeader->m_vecEnemyLKP; +} + +//========================================================= +// +// SquadMakeEnemy - makes everyone in the squad angry at +// the same entity. +// +//========================================================= +void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) +{ + if (!InSquad()) + return; + + if ( !pEnemy ) + { + ALERT ( at_console, "ERROR: SquadMakeEnemy() - pEnemy is NULL!\n" ); + return; + } + + CSquadMonster *pSquadLeader = MySquadLeader( ); + for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + { + CSquadMonster *pMember = pSquadLeader->MySquadMember(i); + if (pMember) + { + // reset members who aren't activly engaged in fighting + if (pMember->m_hEnemy != pEnemy && !pMember->HasConditions( bits_COND_SEE_ENEMY)) + { + if ( pMember->m_hEnemy != NULL) + { + // remember their current enemy + pMember->PushEnemy( pMember->m_hEnemy, pMember->m_vecEnemyLKP ); + } + // give them a new enemy + pMember->m_hEnemy = pEnemy; + pMember->m_vecEnemyLKP = pEnemy->pev->origin; + pMember->SetConditions ( bits_COND_NEW_ENEMY ); + } + } + } +} + + +//========================================================= +// +// SquadCount(), return the number of members of this squad +// callable from leaders & followers +// +//========================================================= +int CSquadMonster :: SquadCount( void ) +{ + if (!InSquad()) + return 0; + + CSquadMonster *pSquadLeader = MySquadLeader(); + int squadCount = 0; + for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + { + if (pSquadLeader->MySquadMember(i) != NULL) + squadCount++; + } + + return squadCount; +} + + +//========================================================= +// +// SquadRecruit(), get some monsters of my classification and +// link them as a group. returns the group size +// +//========================================================= +int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) +{ + int squadCount; + int iMyClass = Classify();// cache this monster's class + + + // Don't recruit if I'm already in a group + if ( InSquad() ) + return 0; + + if ( maxMembers < 2 ) + return 0; + + // I am my own leader + m_hSquadLeader = this; + squadCount = 1; + + CBaseEntity *pEntity = NULL; + + if ( !FStringNull( pev->netname ) ) + { + // I have a netname, so unconditionally recruit everyone else with that name. + pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); + while ( pEntity ) + { + CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer(); + + if ( pRecruit ) + { + if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this ) + { + // minimum protection here against user error.in worldcraft. + if (!SquadAdd( pRecruit )) + break; + squadCount++; + } + } + + pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); + } + } + else + { + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, searchRadius )) != NULL) + { + CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer( ); + + if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) + { + // Can we recruit this guy? + if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && + ( (iMyClass != CLASS_ALIEN_MONSTER) || FStrEq(STRING(pev->classname), STRING(pRecruit->pev->classname))) && + FStringNull( pRecruit->pev->netname ) ) + { + TraceResult tr; + UTIL_TraceLine( pev->origin + pev->view_ofs, pRecruit->pev->origin + pev->view_ofs, ignore_monsters, pRecruit->edict(), &tr );// try to hit recruit with a traceline. + if ( tr.flFraction == 1.0 ) + { + if (!SquadAdd( pRecruit )) + break; + + squadCount++; + } + } + } + } + } + + // no single member squads + if (squadCount == 1) + { + m_hSquadLeader = NULL; + } + + return squadCount; +} + +//========================================================= +// CheckEnemy +//========================================================= +int CSquadMonster :: CheckEnemy ( CBaseEntity *pEnemy ) +{ + int iUpdatedLKP; + + iUpdatedLKP = CBaseMonster :: CheckEnemy ( m_hEnemy ); + + // communicate with squad members about the enemy IF this individual has the same enemy as the squad leader. + if ( InSquad() && (CBaseEntity *)m_hEnemy == MySquadLeader()->m_hEnemy ) + { + if ( iUpdatedLKP ) + { + // have new enemy information, so paste to the squad. + SquadPasteEnemyInfo(); + } + else + { + // enemy unseen, copy from the squad knowledge. + SquadCopyEnemyInfo(); + } + } + + return iUpdatedLKP; +} + +//========================================================= +// StartMonster +//========================================================= +void CSquadMonster :: StartMonster( void ) +{ + CBaseMonster :: StartMonster(); + + if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) + { + if ( !FStringNull( pev->netname ) ) + { + // if I have a groupname, I can only recruit if I'm flagged as leader + if ( !( pev->spawnflags & SF_SQUADMONSTER_LEADER ) ) + { + return; + } + } + + // try to form squads now. + int iSquadSize = SquadRecruit( 1024, 4 ); + + if ( iSquadSize ) + { + ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); + } + + if ( IsLeader() && FClassnameIs ( pev, "monster_human_grunt" ) ) + { + SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack + pev->skin = 0; + } + + } +} + +//========================================================= +// NoFriendlyFire - checks for possibility of friendly fire +// +// Builds a large box in front of the grunt and checks to see +// if any squad members are in that box. +//========================================================= +BOOL CSquadMonster :: NoFriendlyFire( void ) +{ + if ( !InSquad() ) + { + return TRUE; + } + + CPlane backPlane; + CPlane leftPlane; + CPlane rightPlane; + + Vector vecLeftSide; + Vector vecRightSide; + Vector v_left; + + //!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!! + + if ( m_hEnemy != NULL ) + { + UTIL_MakeVectors ( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); + } + else + { + // if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot. + return FALSE; + } + + //UTIL_MakeVectors ( pev->angles ); + + vecLeftSide = pev->origin - ( gpGlobals->v_right * ( pev->size.x * 1.5 ) ); + vecRightSide = pev->origin + ( gpGlobals->v_right * ( pev->size.x * 1.5 ) ); + v_left = gpGlobals->v_right * -1; + + leftPlane.InitializePlane ( gpGlobals->v_right, vecLeftSide ); + rightPlane.InitializePlane ( v_left, vecRightSide ); + backPlane.InitializePlane ( gpGlobals->v_forward, pev->origin ); + +/* + ALERT ( at_console, "LeftPlane: %f %f %f : %f\n", leftPlane.m_vecNormal.x, leftPlane.m_vecNormal.y, leftPlane.m_vecNormal.z, leftPlane.m_flDist ); + ALERT ( at_console, "RightPlane: %f %f %f : %f\n", rightPlane.m_vecNormal.x, rightPlane.m_vecNormal.y, rightPlane.m_vecNormal.z, rightPlane.m_flDist ); + ALERT ( at_console, "BackPlane: %f %f %f : %f\n", backPlane.m_vecNormal.x, backPlane.m_vecNormal.y, backPlane.m_vecNormal.z, backPlane.m_flDist ); +*/ + + CSquadMonster *pSquadLeader = MySquadLeader(); + for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + { + CSquadMonster *pMember = pSquadLeader->MySquadMember(i); + if (pMember && pMember != this) + { + + if ( backPlane.PointInFront ( pMember->pev->origin ) && + leftPlane.PointInFront ( pMember->pev->origin ) && + rightPlane.PointInFront ( pMember->pev->origin) ) + { + // this guy is in the check volume! Don't shoot! + return FALSE; + } + } + } + + return TRUE; +} + +//========================================================= +// GetIdealState - surveys the Conditions information available +// and finds the best new state for a monster. +//========================================================= +MONSTERSTATE CSquadMonster :: GetIdealState ( void ) +{ + int iConditions; + + iConditions = IScheduleFlags(); + + // If no schedule conditions, the new ideal state is probably the reason we're in here. + switch ( m_MonsterState ) + { + case MONSTERSTATE_IDLE: + case MONSTERSTATE_ALERT: + if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) + { + SquadMakeEnemy ( m_hEnemy ); + } + break; + } + + return CBaseMonster :: GetIdealState(); +} + +//========================================================= +// FValidateCover - determines whether or not the chosen +// cover location is a good one to move to. (currently based +// on proximity to others in the squad) +//========================================================= +BOOL CSquadMonster :: FValidateCover ( const Vector &vecCoverLocation ) +{ + if ( !InSquad() ) + { + return TRUE; + } + + if (SquadMemberInRange( vecCoverLocation, 128 )) + { + // another squad member is too close to this piece of cover. + return FALSE; + } + + return TRUE; +} + +//========================================================= +// SquadEnemySplit- returns TRUE if not all squad members +// are fighting the same enemy. +//========================================================= +BOOL CSquadMonster :: SquadEnemySplit ( void ) +{ + if (!InSquad()) + return FALSE; + + CSquadMonster *pSquadLeader = MySquadLeader(); + CBaseEntity *pEnemy = pSquadLeader->m_hEnemy; + + for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + { + CSquadMonster *pMember = pSquadLeader->MySquadMember(i); + if (pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy) + { + return TRUE; + } + } + return FALSE; +} + +//========================================================= +// FValidateCover - determines whether or not the chosen +// cover location is a good one to move to. (currently based +// on proximity to others in the squad) +//========================================================= +BOOL CSquadMonster :: SquadMemberInRange ( const Vector &vecLocation, float flDist ) +{ + if (!InSquad()) + return FALSE; + + CSquadMonster *pSquadLeader = MySquadLeader(); + + for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + { + CSquadMonster *pSquadMember = pSquadLeader->MySquadMember(i); + if (pSquadMember && (vecLocation - pSquadMember->pev->origin ).Length2D() <= flDist) + return TRUE; + } + return FALSE; +} + + +extern Schedule_t slChaseEnemyFailed[]; + +Schedule_t *CSquadMonster::GetScheduleOfType( int iType ) +{ + switch ( iType ) + { + + case SCHED_CHASE_ENEMY_FAILED: + { + return &slChaseEnemyFailed[ 0 ]; + } + + default: + return CBaseMonster::GetScheduleOfType( iType ); + } +} + diff --git a/main/source/dlls/squadmonster.h b/main/source/dlls/squadmonster.h index b1517348..b1f23e4b 100644 --- a/main/source/dlls/squadmonster.h +++ b/main/source/dlls/squadmonster.h @@ -1,120 +1,120 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// CSquadMonster - all the extra data for monsters that -// form squads. -//========================================================= - -#define SF_SQUADMONSTER_LEADER 32 - - -#define bits_NO_SLOT 0 - -// HUMAN GRUNT SLOTS -#define bits_SLOT_HGRUNT_ENGAGE1 ( 1 << 0 ) -#define bits_SLOT_HGRUNT_ENGAGE2 ( 1 << 1 ) -#define bits_SLOTS_HGRUNT_ENGAGE ( bits_SLOT_HGRUNT_ENGAGE1 | bits_SLOT_HGRUNT_ENGAGE2 ) - -#define bits_SLOT_HGRUNT_GRENADE1 ( 1 << 2 ) -#define bits_SLOT_HGRUNT_GRENADE2 ( 1 << 3 ) -#define bits_SLOTS_HGRUNT_GRENADE ( bits_SLOT_HGRUNT_GRENADE1 | bits_SLOT_HGRUNT_GRENADE2 ) - -// ALIEN GRUNT SLOTS -#define bits_SLOT_AGRUNT_HORNET1 ( 1 << 4 ) -#define bits_SLOT_AGRUNT_HORNET2 ( 1 << 5 ) -#define bits_SLOT_AGRUNT_CHASE ( 1 << 6 ) -#define bits_SLOTS_AGRUNT_HORNET ( bits_SLOT_AGRUNT_HORNET1 | bits_SLOT_AGRUNT_HORNET2 ) - -// HOUNDEYE SLOTS -#define bits_SLOT_HOUND_ATTACK1 ( 1 << 7 ) -#define bits_SLOT_HOUND_ATTACK2 ( 1 << 8 ) -#define bits_SLOT_HOUND_ATTACK3 ( 1 << 9 ) -#define bits_SLOTS_HOUND_ATTACK ( bits_SLOT_HOUND_ATTACK1 | bits_SLOT_HOUND_ATTACK2 | bits_SLOT_HOUND_ATTACK3 ) - -// global slots -#define bits_SLOT_SQUAD_SPLIT ( 1 << 10 )// squad members don't all have the same enemy - -#define NUM_SLOTS 11// update this every time you add/remove a slot. - -#define MAX_SQUAD_MEMBERS 5 - -//========================================================= -// CSquadMonster - for any monster that forms squads. -//========================================================= -class CSquadMonster : public CBaseMonster -{ -public: - // squad leader info - EHANDLE m_hSquadLeader; // who is my leader - EHANDLE m_hSquadMember[MAX_SQUAD_MEMBERS-1]; // valid only for leader - int m_afSquadSlots; - float m_flLastEnemySightTime; // last time anyone in the squad saw the enemy - BOOL m_fEnemyEluded; - - // squad member info - int m_iMySlot;// this is the behaviour slot that the monster currently holds in the squad. - - int CheckEnemy ( CBaseEntity *pEnemy ); - void StartMonster ( void ); - void VacateSlot( void ); - void ScheduleChange( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - BOOL OccupySlot( int iDesiredSlot ); - BOOL NoFriendlyFire( void ); - - // squad functions still left in base class - CSquadMonster *MySquadLeader( ) - { - CSquadMonster *pSquadLeader = (CSquadMonster *)((CBaseEntity *)m_hSquadLeader); - if (pSquadLeader != NULL) - return pSquadLeader; - return this; - } - CSquadMonster *MySquadMember( int i ) - { - if (i >= MAX_SQUAD_MEMBERS-1) - return this; - else - return (CSquadMonster *)((CBaseEntity *)m_hSquadMember[i]); - } - int InSquad ( void ) { return m_hSquadLeader != NULL; } - int IsLeader ( void ) { return m_hSquadLeader == this; } - int SquadJoin ( int searchRadius ); - int SquadRecruit ( int searchRadius, int maxMembers ); - int SquadCount( void ); - void SquadRemove( CSquadMonster *pRemove ); - void SquadUnlink( void ); - BOOL SquadAdd( CSquadMonster *pAdd ); - void SquadDisband( void ); - void SquadAddConditions ( int iConditions ); - void SquadMakeEnemy ( CBaseEntity *pEnemy ); - void SquadPasteEnemyInfo ( void ); - void SquadCopyEnemyInfo ( void ); - BOOL SquadEnemySplit ( void ); - BOOL SquadMemberInRange( const Vector &vecLocation, float flDist ); - - virtual CSquadMonster *MySquadMonsterPointer( void ) { return this; } - - static TYPEDESCRIPTION m_SaveData[]; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - BOOL FValidateCover ( const Vector &vecCoverLocation ); - - MONSTERSTATE GetIdealState ( void ); - Schedule_t *GetScheduleOfType ( int iType ); -}; - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// CSquadMonster - all the extra data for monsters that +// form squads. +//========================================================= + +#define SF_SQUADMONSTER_LEADER 32 + + +#define bits_NO_SLOT 0 + +// HUMAN GRUNT SLOTS +#define bits_SLOT_HGRUNT_ENGAGE1 ( 1 << 0 ) +#define bits_SLOT_HGRUNT_ENGAGE2 ( 1 << 1 ) +#define bits_SLOTS_HGRUNT_ENGAGE ( bits_SLOT_HGRUNT_ENGAGE1 | bits_SLOT_HGRUNT_ENGAGE2 ) + +#define bits_SLOT_HGRUNT_GRENADE1 ( 1 << 2 ) +#define bits_SLOT_HGRUNT_GRENADE2 ( 1 << 3 ) +#define bits_SLOTS_HGRUNT_GRENADE ( bits_SLOT_HGRUNT_GRENADE1 | bits_SLOT_HGRUNT_GRENADE2 ) + +// ALIEN GRUNT SLOTS +#define bits_SLOT_AGRUNT_HORNET1 ( 1 << 4 ) +#define bits_SLOT_AGRUNT_HORNET2 ( 1 << 5 ) +#define bits_SLOT_AGRUNT_CHASE ( 1 << 6 ) +#define bits_SLOTS_AGRUNT_HORNET ( bits_SLOT_AGRUNT_HORNET1 | bits_SLOT_AGRUNT_HORNET2 ) + +// HOUNDEYE SLOTS +#define bits_SLOT_HOUND_ATTACK1 ( 1 << 7 ) +#define bits_SLOT_HOUND_ATTACK2 ( 1 << 8 ) +#define bits_SLOT_HOUND_ATTACK3 ( 1 << 9 ) +#define bits_SLOTS_HOUND_ATTACK ( bits_SLOT_HOUND_ATTACK1 | bits_SLOT_HOUND_ATTACK2 | bits_SLOT_HOUND_ATTACK3 ) + +// global slots +#define bits_SLOT_SQUAD_SPLIT ( 1 << 10 )// squad members don't all have the same enemy + +#define NUM_SLOTS 11// update this every time you add/remove a slot. + +#define MAX_SQUAD_MEMBERS 5 + +//========================================================= +// CSquadMonster - for any monster that forms squads. +//========================================================= +class CSquadMonster : public CBaseMonster +{ +public: + // squad leader info + EHANDLE m_hSquadLeader; // who is my leader + EHANDLE m_hSquadMember[MAX_SQUAD_MEMBERS-1]; // valid only for leader + int m_afSquadSlots; + float m_flLastEnemySightTime; // last time anyone in the squad saw the enemy + BOOL m_fEnemyEluded; + + // squad member info + int m_iMySlot;// this is the behaviour slot that the monster currently holds in the squad. + + int CheckEnemy ( CBaseEntity *pEnemy ); + void StartMonster ( void ); + void VacateSlot( void ); + void ScheduleChange( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + BOOL OccupySlot( int iDesiredSlot ); + BOOL NoFriendlyFire( void ); + + // squad functions still left in base class + CSquadMonster *MySquadLeader( ) + { + CSquadMonster *pSquadLeader = (CSquadMonster *)((CBaseEntity *)m_hSquadLeader); + if (pSquadLeader != NULL) + return pSquadLeader; + return this; + } + CSquadMonster *MySquadMember( int i ) + { + if (i >= MAX_SQUAD_MEMBERS-1) + return this; + else + return (CSquadMonster *)((CBaseEntity *)m_hSquadMember[i]); + } + int InSquad ( void ) { return m_hSquadLeader != NULL; } + int IsLeader ( void ) { return m_hSquadLeader == this; } + int SquadJoin ( int searchRadius ); + int SquadRecruit ( int searchRadius, int maxMembers ); + int SquadCount( void ); + void SquadRemove( CSquadMonster *pRemove ); + void SquadUnlink( void ); + BOOL SquadAdd( CSquadMonster *pAdd ); + void SquadDisband( void ); + void SquadAddConditions ( int iConditions ); + void SquadMakeEnemy ( CBaseEntity *pEnemy ); + void SquadPasteEnemyInfo ( void ); + void SquadCopyEnemyInfo ( void ); + BOOL SquadEnemySplit ( void ); + BOOL SquadMemberInRange( const Vector &vecLocation, float flDist ); + + virtual CSquadMonster *MySquadMonsterPointer( void ) { return this; } + + static TYPEDESCRIPTION m_SaveData[]; + + int Save( CSave &save ); + int Restore( CRestore &restore ); + + BOOL FValidateCover ( const Vector &vecCoverLocation ); + + MONSTERSTATE GetIdealState ( void ); + Schedule_t *GetScheduleOfType ( int iType ); +}; + diff --git a/main/source/dlls/squeakgrenade.cpp b/main/source/dlls/squeakgrenade.cpp index cd461b8e..ec4cb7a3 100644 --- a/main/source/dlls/squeakgrenade.cpp +++ b/main/source/dlls/squeakgrenade.cpp @@ -1,599 +1,599 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" - -// Allow assignment within conditional -#pragma warning (disable: 4706) - -enum w_squeak_e { - WSQUEAK_IDLE1 = 0, - WSQUEAK_FIDGET, - WSQUEAK_JUMP, - WSQUEAK_RUN, -}; - -enum squeak_e { - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -#ifndef CLIENT_DLL - -class CSqueakGrenade : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - int Classify( void ); - void EXPORT SuperBounceTouch( CBaseEntity *pOther ); - void EXPORT HuntThink( void ); - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - static float m_flNextBounceSoundTime; - - // CBaseEntity *m_pTarget; - float m_flDie; - Vector m_vecTarget; - float m_flNextHunt; - float m_flNextHit; - Vector m_posPrev; - EHANDLE m_hOwner; - int m_iMyClass; -}; - -float CSqueakGrenade::m_flNextBounceSoundTime = 0; - -LINK_ENTITY_TO_CLASS( monster_snark, CSqueakGrenade ); -TYPEDESCRIPTION CSqueakGrenade::m_SaveData[] = -{ - DEFINE_FIELD( CSqueakGrenade, m_flDie, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CSqueakGrenade, m_flNextHunt, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_flNextHit, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_posPrev, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CSqueakGrenade, m_hOwner, FIELD_EHANDLE ), -}; - -IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ); - -#define SQUEEK_DETONATE_DELAY 15.0 - -int CSqueakGrenade :: Classify ( void ) -{ - if (m_iMyClass != 0) - return m_iMyClass; // protect against recursion - - if (m_hEnemy != NULL) - { - m_iMyClass = CLASS_INSECT; // no one cares about it - switch( m_hEnemy->Classify( ) ) - { - case CLASS_PLAYER: - case CLASS_HUMAN_PASSIVE: - case CLASS_HUMAN_MILITARY: - m_iMyClass = 0; - return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it - } - m_iMyClass = 0; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -void CSqueakGrenade :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_squeak.mdl"); - UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CSqueakGrenade::SuperBounceTouch ); - SetThink( &CSqueakGrenade::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time + 1E6; - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.snarkHealth; - pev->gravity = 0.5; - pev->friction = 0.5; - - pev->dmg = gSkillData.snarkDmgPop; - - m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY; - - m_flFieldOfView = 0; // 180 degrees - - if ( pev->owner ) - m_hOwner = Instance( pev->owner ); - - m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. - - pev->sequence = WSQUEAK_RUN; - ResetSequenceInfo( ); -} - -void CSqueakGrenade::Precache( void ) -{ - PRECACHE_MODEL("models/w_squeak.mdl"); - PRECACHE_SOUND("squeek/sqk_blast1.wav"); - PRECACHE_SOUND("common/bodysplat.wav"); - PRECACHE_SOUND("squeek/sqk_die1.wav"); - PRECACHE_SOUND("squeek/sqk_hunt1.wav"); - PRECACHE_SOUND("squeek/sqk_hunt2.wav"); - PRECACHE_SOUND("squeek/sqk_hunt3.wav"); - PRECACHE_SOUND("squeek/sqk_deploy1.wav"); -} - - -void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->model = iStringNull;// make invisible - SetThink( &CSqueakGrenade::SUB_Remove ); - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - - // since squeak grenades never leave a body behind, clear out their takedamage now. - // Squeaks do a bit of radius damage when they pop, and that radius damage will - // continue to call this function unless we acknowledge the Squeak's death now. (sjb) - pev->takedamage = DAMAGE_NO; - - // play squeek blast - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); - - UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); - - if (m_hOwner != NULL) - RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - else - RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - - // reset owner so death message happens - if (m_hOwner != NULL) - pev->owner = m_hOwner->edict(); - - CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); -} - -void CSqueakGrenade :: GibMonster( void ) -{ - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - - - -void CSqueakGrenade::HuntThink( void ) -{ - // ALERT( at_console, "think\n" ); - - if (!IsInWorld()) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - // explode when ready - if (gpGlobals->time >= m_flDie) - { - g_vecAttackDir = pev->velocity.Normalize( ); - pev->health = -1; - Killed( pev, 0 ); - return; - } - - // float - if (pev->waterlevel != 0) - { - if (pev->movetype == MOVETYPE_BOUNCE) - { - pev->movetype = MOVETYPE_FLY; - } - pev->velocity = pev->velocity * 0.9; - pev->velocity.z += 8.0; - } - else if (pev->movetype = MOVETYPE_FLY) - { - pev->movetype = MOVETYPE_BOUNCE; - } - - // return if not time to hunt - if (m_flNextHunt > gpGlobals->time) - return; - - m_flNextHunt = gpGlobals->time + 2.0; - - CBaseEntity *pOther = NULL; - Vector vecDir; - TraceResult tr; - - Vector vecFlat = pev->velocity; - vecFlat.z = 0; - vecFlat = vecFlat.Normalize( ); - - UTIL_MakeVectors( pev->angles ); - - if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) - { - // find target, bounce a bit towards it. - Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); - } - - // squeek if it's about time blow up - if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F)); - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); - } - - // higher pitch as squeeker gets closer to detonation time - float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - if (flpitch < 80) - flpitch = 80; - - if (m_hEnemy != NULL) - { - if (FVisible( m_hEnemy )) - { - vecDir = m_hEnemy->EyePosition() - pev->origin; - m_vecTarget = vecDir.Normalize( ); - } - - float flVel = pev->velocity.Length(); - float flAdj = 50.0 / (flVel + 10.0); - - if (flAdj > 1.2) - flAdj = 1.2; - - // ALERT( at_console, "think : enemy\n"); - - // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); - - pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; - } - - if (pev->flags & FL_ONGROUND) - { - pev->avelocity = Vector( 0, 0, 0 ); - } - else - { - if (pev->avelocity == Vector( 0, 0, 0)) - { - pev->avelocity.x = RANDOM_FLOAT( -100, 100 ); - pev->avelocity.z = RANDOM_FLOAT( -100, 100 ); - } - } - - if ((pev->origin - m_posPrev).Length() < 1.0) - { - pev->velocity.x = RANDOM_FLOAT( -100, 100 ); - pev->velocity.y = RANDOM_FLOAT( -100, 100 ); - } - m_posPrev = pev->origin; - - pev->angles = UTIL_VecToAngles( pev->velocity ); - pev->angles.z = 0; - pev->angles.x = 0; -} - - -void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) -{ - float flpitch; - - TraceResult tr = UTIL_GetGlobalTrace( ); - - // don't hit the guy that launched this grenade - if ( pev->owner && pOther->edict() == pev->owner ) - return; - - // at least until we've bounced once - pev->owner = NULL; - - pev->angles.x = 0; - pev->angles.z = 0; - - // avoid bouncing too much - if (m_flNextHit > gpGlobals->time) - return; - - // higher pitch as squeeker gets closer to detonation time - flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - - if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) - { - // attack! - - // make sure it's me who has touched them - if (tr.pHit == pOther->edict()) - { - // and it's not another squeakgrenade - if (tr.pHit->v.modelindex != pev->modelindex) - { - // ALERT( at_console, "hit enemy\n"); - ClearMultiDamage( ); - pOther->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); - if (m_hOwner != NULL) - ApplyMultiDamage( pev, m_hOwner->pev ); - else - ApplyMultiDamage( pev, pev ); - - pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage - // m_flDie += 2.0; // add more life - - // make bite sound - EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch); - m_flNextAttack = gpGlobals->time + 0.5; - } - } - else - { - // ALERT( at_console, "been hit\n"); - } - } - - m_flNextHit = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time; - - if ( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. - if ( gpGlobals->time < m_flNextBounceSoundTime ) - { - // too soon! - return; - } - } - - if (!(pev->flags & FL_ONGROUND)) - { - // play bounce sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch); - else if (flRndSound <= 0.66) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch); - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); - } - else - { - // skittering sound - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 100, 0.1 ); - } - - m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. -} - -#endif - -LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ); - - -void CSqueak::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_SNARK; - SET_MODEL(ENT(pev), "models/w_sqknest.mdl"); - - FallInit();//get ready to fall down. - - m_iDefaultAmmo = SNARK_DEFAULT_GIVE; - - pev->sequence = 1; - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; -} - - -void CSqueak::Precache( void ) -{ - PRECACHE_MODEL("models/w_sqknest.mdl"); - PRECACHE_MODEL("models/v_squeak.mdl"); - PRECACHE_MODEL("models/p_squeak.mdl"); - PRECACHE_SOUND("squeek/sqk_hunt2.wav"); - PRECACHE_SOUND("squeek/sqk_hunt3.wav"); - UTIL_PrecacheOther("monster_snark"); - - m_usSnarkFire = PRECACHE_EVENT ( 1, "events/snarkfire.sc" ); -} - - -int CSqueak::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Snarks"; - p->iMaxAmmo1 = SNARK_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 3; - p->iId = m_iId = WEAPON_SNARK; - p->iWeight = SNARK_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - - - -BOOL CSqueak::Deploy( ) -{ - // play hunt sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.5 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100); - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - return DefaultDeploy( "models/v_squeak.mdl", "models/p_squeak.mdl", SQUEAK_UP, "squeak" ); -} - - -void CSqueak::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - return; - } - - SendWeaponAnim( SQUEAK_DOWN ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); -} - - -void CSqueak::PrimaryAttack() -{ - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - TraceResult tr; - Vector trace_origin; - - // HACK HACK: Ugly hacks to handle change in origin based on new physics code for players - // Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 ) - trace_origin = m_pPlayer->pev->origin; - if ( m_pPlayer->pev->flags & FL_DUCKING ) - { - trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - // find place to toss monster - UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); - - int flags = FEV_NOTHOST; - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - if ( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 ) - { - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#ifndef CLIENT_DLL - CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pSqueak->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity; -#endif - - // play hunt sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.5 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 105); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 105); - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_fJustThrown = 1; - - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - } - } -} - - -void CSqueak::SecondaryAttack( void ) -{ - -} - - -void CSqueak::WeaponIdle( void ) -{ - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if (m_fJustThrown) - { - m_fJustThrown = 0; - - if ( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) - { - RetireWeapon(); - return; - } - - SendWeaponAnim( SQUEAK_UP ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - return; - } - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - iAnim = SQUEAK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); - } - else if (flRand <= 0.875) - { - iAnim = SQUEAK_FIDGETFIT; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; - } - else - { - iAnim = SQUEAK_FIDGETNIP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0; - } - SendWeaponAnim( iAnim ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "soundent.h" +#include "gamerules.h" + +// Allow assignment within conditional +#pragma warning (disable: 4706) + +enum w_squeak_e { + WSQUEAK_IDLE1 = 0, + WSQUEAK_FIDGET, + WSQUEAK_JUMP, + WSQUEAK_RUN, +}; + +enum squeak_e { + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; + +#ifndef CLIENT_DLL + +class CSqueakGrenade : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + int Classify( void ); + void EXPORT SuperBounceTouch( CBaseEntity *pOther ); + void EXPORT HuntThink( void ); + int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } + void Killed( entvars_t *pevAttacker, int iGib ); + void GibMonster( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + static float m_flNextBounceSoundTime; + + // CBaseEntity *m_pTarget; + float m_flDie; + Vector m_vecTarget; + float m_flNextHunt; + float m_flNextHit; + Vector m_posPrev; + EHANDLE m_hOwner; + int m_iMyClass; +}; + +float CSqueakGrenade::m_flNextBounceSoundTime = 0; + +LINK_ENTITY_TO_CLASS( monster_snark, CSqueakGrenade ); +TYPEDESCRIPTION CSqueakGrenade::m_SaveData[] = +{ + DEFINE_FIELD( CSqueakGrenade, m_flDie, FIELD_TIME ), + DEFINE_FIELD( CSqueakGrenade, m_vecTarget, FIELD_VECTOR ), + DEFINE_FIELD( CSqueakGrenade, m_flNextHunt, FIELD_TIME ), + DEFINE_FIELD( CSqueakGrenade, m_flNextHit, FIELD_TIME ), + DEFINE_FIELD( CSqueakGrenade, m_posPrev, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CSqueakGrenade, m_hOwner, FIELD_EHANDLE ), +}; + +IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ); + +#define SQUEEK_DETONATE_DELAY 15.0 + +int CSqueakGrenade :: Classify ( void ) +{ + if (m_iMyClass != 0) + return m_iMyClass; // protect against recursion + + if (m_hEnemy != NULL) + { + m_iMyClass = CLASS_INSECT; // no one cares about it + switch( m_hEnemy->Classify( ) ) + { + case CLASS_PLAYER: + case CLASS_HUMAN_PASSIVE: + case CLASS_HUMAN_MILITARY: + m_iMyClass = 0; + return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it + } + m_iMyClass = 0; + } + + return CLASS_ALIEN_BIOWEAPON; +} + +void CSqueakGrenade :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/w_squeak.mdl"); + UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8)); + UTIL_SetOrigin( pev, pev->origin ); + + SetTouch( &CSqueakGrenade::SuperBounceTouch ); + SetThink( &CSqueakGrenade::HuntThink ); + pev->nextthink = gpGlobals->time + 0.1; + m_flNextHunt = gpGlobals->time + 1E6; + + pev->flags |= FL_MONSTER; + pev->takedamage = DAMAGE_AIM; + pev->health = gSkillData.snarkHealth; + pev->gravity = 0.5; + pev->friction = 0.5; + + pev->dmg = gSkillData.snarkDmgPop; + + m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY; + + m_flFieldOfView = 0; // 180 degrees + + if ( pev->owner ) + m_hOwner = Instance( pev->owner ); + + m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. + + pev->sequence = WSQUEAK_RUN; + ResetSequenceInfo( ); +} + +void CSqueakGrenade::Precache( void ) +{ + PRECACHE_MODEL("models/w_squeak.mdl"); + PRECACHE_SOUND("squeek/sqk_blast1.wav"); + PRECACHE_SOUND("common/bodysplat.wav"); + PRECACHE_SOUND("squeek/sqk_die1.wav"); + PRECACHE_SOUND("squeek/sqk_hunt1.wav"); + PRECACHE_SOUND("squeek/sqk_hunt2.wav"); + PRECACHE_SOUND("squeek/sqk_hunt3.wav"); + PRECACHE_SOUND("squeek/sqk_deploy1.wav"); +} + + +void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->model = iStringNull;// make invisible + SetThink( &CSqueakGrenade::SUB_Remove ); + SetTouch( NULL ); + pev->nextthink = gpGlobals->time + 0.1; + + // since squeak grenades never leave a body behind, clear out their takedamage now. + // Squeaks do a bit of radius damage when they pop, and that radius damage will + // continue to call this function unless we acknowledge the Squeak's death now. (sjb) + pev->takedamage = DAMAGE_NO; + + // play squeek blast + EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); + + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); + + UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); + + if (m_hOwner != NULL) + RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); + else + RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); + + // reset owner so death message happens + if (m_hOwner != NULL) + pev->owner = m_hOwner->edict(); + + CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); +} + +void CSqueakGrenade :: GibMonster( void ) +{ + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); +} + + + +void CSqueakGrenade::HuntThink( void ) +{ + // ALERT( at_console, "think\n" ); + + if (!IsInWorld()) + { + SetTouch( NULL ); + UTIL_Remove( this ); + return; + } + + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + // explode when ready + if (gpGlobals->time >= m_flDie) + { + g_vecAttackDir = pev->velocity.Normalize( ); + pev->health = -1; + Killed( pev, 0 ); + return; + } + + // float + if (pev->waterlevel != 0) + { + if (pev->movetype == MOVETYPE_BOUNCE) + { + pev->movetype = MOVETYPE_FLY; + } + pev->velocity = pev->velocity * 0.9; + pev->velocity.z += 8.0; + } + else if (pev->movetype = MOVETYPE_FLY) + { + pev->movetype = MOVETYPE_BOUNCE; + } + + // return if not time to hunt + if (m_flNextHunt > gpGlobals->time) + return; + + m_flNextHunt = gpGlobals->time + 2.0; + + CBaseEntity *pOther = NULL; + Vector vecDir; + TraceResult tr; + + Vector vecFlat = pev->velocity; + vecFlat.z = 0; + vecFlat = vecFlat.Normalize( ); + + UTIL_MakeVectors( pev->angles ); + + if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) + { + // find target, bounce a bit towards it. + Look( 512 ); + m_hEnemy = BestVisibleEnemy( ); + } + + // squeek if it's about time blow up + if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F)); + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); + } + + // higher pitch as squeeker gets closer to detonation time + float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); + if (flpitch < 80) + flpitch = 80; + + if (m_hEnemy != NULL) + { + if (FVisible( m_hEnemy )) + { + vecDir = m_hEnemy->EyePosition() - pev->origin; + m_vecTarget = vecDir.Normalize( ); + } + + float flVel = pev->velocity.Length(); + float flAdj = 50.0 / (flVel + 10.0); + + if (flAdj > 1.2) + flAdj = 1.2; + + // ALERT( at_console, "think : enemy\n"); + + // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); + + pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; + } + + if (pev->flags & FL_ONGROUND) + { + pev->avelocity = Vector( 0, 0, 0 ); + } + else + { + if (pev->avelocity == Vector( 0, 0, 0)) + { + pev->avelocity.x = RANDOM_FLOAT( -100, 100 ); + pev->avelocity.z = RANDOM_FLOAT( -100, 100 ); + } + } + + if ((pev->origin - m_posPrev).Length() < 1.0) + { + pev->velocity.x = RANDOM_FLOAT( -100, 100 ); + pev->velocity.y = RANDOM_FLOAT( -100, 100 ); + } + m_posPrev = pev->origin; + + pev->angles = UTIL_VecToAngles( pev->velocity ); + pev->angles.z = 0; + pev->angles.x = 0; +} + + +void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) +{ + float flpitch; + + TraceResult tr = UTIL_GetGlobalTrace( ); + + // don't hit the guy that launched this grenade + if ( pev->owner && pOther->edict() == pev->owner ) + return; + + // at least until we've bounced once + pev->owner = NULL; + + pev->angles.x = 0; + pev->angles.z = 0; + + // avoid bouncing too much + if (m_flNextHit > gpGlobals->time) + return; + + // higher pitch as squeeker gets closer to detonation time + flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); + + if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) + { + // attack! + + // make sure it's me who has touched them + if (tr.pHit == pOther->edict()) + { + // and it's not another squeakgrenade + if (tr.pHit->v.modelindex != pev->modelindex) + { + // ALERT( at_console, "hit enemy\n"); + ClearMultiDamage( ); + pOther->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); + if (m_hOwner != NULL) + ApplyMultiDamage( pev, m_hOwner->pev ); + else + ApplyMultiDamage( pev, pev ); + + pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage + // m_flDie += 2.0; // add more life + + // make bite sound + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch); + m_flNextAttack = gpGlobals->time + 0.5; + } + } + else + { + // ALERT( at_console, "been hit\n"); + } + } + + m_flNextHit = gpGlobals->time + 0.1; + m_flNextHunt = gpGlobals->time; + + if ( g_pGameRules->IsMultiplayer() ) + { + // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. + if ( gpGlobals->time < m_flNextBounceSoundTime ) + { + // too soon! + return; + } + } + + if (!(pev->flags & FL_ONGROUND)) + { + // play bounce sound + float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + + if ( flRndSound <= 0.33 ) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch); + else if (flRndSound <= 0.66) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch); + else + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch); + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); + } + else + { + // skittering sound + CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 100, 0.1 ); + } + + m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. +} + +#endif + +LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ); + + +void CSqueak::Spawn( ) +{ + Precache( ); + m_iId = WEAPON_SNARK; + SET_MODEL(ENT(pev), "models/w_sqknest.mdl"); + + FallInit();//get ready to fall down. + + m_iDefaultAmmo = SNARK_DEFAULT_GIVE; + + pev->sequence = 1; + pev->animtime = gpGlobals->time; + pev->framerate = 1.0; +} + + +void CSqueak::Precache( void ) +{ + PRECACHE_MODEL("models/w_sqknest.mdl"); + PRECACHE_MODEL("models/v_squeak.mdl"); + PRECACHE_MODEL("models/p_squeak.mdl"); + PRECACHE_SOUND("squeek/sqk_hunt2.wav"); + PRECACHE_SOUND("squeek/sqk_hunt3.wav"); + UTIL_PrecacheOther("monster_snark"); + + m_usSnarkFire = PRECACHE_EVENT ( 1, "events/snarkfire.sc" ); +} + + +int CSqueak::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "Snarks"; + p->iMaxAmmo1 = SNARK_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 4; + p->iPosition = 3; + p->iId = m_iId = WEAPON_SNARK; + p->iWeight = SNARK_WEIGHT; + p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; + + return 1; +} + + + +BOOL CSqueak::Deploy( ) +{ + // play hunt sound + float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + + if ( flRndSound <= 0.5 ) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100); + else + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100); + + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + + return DefaultDeploy( "models/v_squeak.mdl", "models/p_squeak.mdl", SQUEAK_UP, "squeak" ); +} + + +void CSqueak::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + + if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + { + m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; + return; + } + + SendWeaponAnim( SQUEAK_DOWN ); + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); +} + + +void CSqueak::PrimaryAttack() +{ + if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + { + UTIL_MakeVectors( m_pPlayer->pev->v_angle ); + TraceResult tr; + Vector trace_origin; + + // HACK HACK: Ugly hacks to handle change in origin based on new physics code for players + // Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 ) + trace_origin = m_pPlayer->pev->origin; + if ( m_pPlayer->pev->flags & FL_DUCKING ) + { + trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + } + + // find place to toss monster + UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); + + int flags = FEV_NOTHOST; + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); + + if ( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 ) + { + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + +#ifndef CLIENT_DLL + CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); + pSqueak->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity; +#endif + + // play hunt sound + float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + + if ( flRndSound <= 0.5 ) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 105); + else + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 105); + + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + + m_fJustThrown = 1; + + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + } + } +} + + +void CSqueak::SecondaryAttack( void ) +{ + +} + + +void CSqueak::WeaponIdle( void ) +{ + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + if (m_fJustThrown) + { + m_fJustThrown = 0; + + if ( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) + { + RetireWeapon(); + return; + } + + SendWeaponAnim( SQUEAK_UP ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + return; + } + + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if (flRand <= 0.75) + { + iAnim = SQUEAK_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); + } + else if (flRand <= 0.875) + { + iAnim = SQUEAK_FIDGETFIT; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; + } + else + { + iAnim = SQUEAK_FIDGETNIP; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0; + } + SendWeaponAnim( iAnim ); +} + #endif \ No newline at end of file diff --git a/main/source/dlls/stats.cpp b/main/source/dlls/stats.cpp index 54ea2839..5d1d2d3e 100644 --- a/main/source/dlls/stats.cpp +++ b/main/source/dlls/stats.cpp @@ -1,149 +1,149 @@ -#include "extdll.h" -#include "util.h" - -#include "cbase.h" -#include "player.h" -#include "trains.h" -#include "nodes.h" -#include "weapons.h" -#include "soundent.h" -#include "monsters.h" -#include "..\engine\shake.h" -#include "decals.h" -#include "gamerules.h" - - -float AmmoDamage( const char *pName ) -{ - if ( !pName ) - return 0; - - if ( !strcmp( pName, "9mm" ) ) - return gSkillData.plrDmg9MM; - if ( !strcmp( pName, "357" ) ) - return gSkillData.plrDmg357; - if ( !strcmp( pName, "ARgrenades" ) ) - return gSkillData.plrDmgM203Grenade; - if ( !strcmp( pName, "buckshot" ) ) - return gSkillData.plrDmgBuckshot; - if ( !strcmp( pName, "bolts") ) - return gSkillData.plrDmgCrossbowMonster; - if ( !strcmp( pName, "rockets") ) - return gSkillData.plrDmgRPG; - if ( !strcmp( pName, "uranium") ) - return gSkillData.plrDmgGauss; - if ( !strcmp( pName, "Hand Grenade") ) - return gSkillData.plrDmgHandGrenade; - if ( !strcmp( pName, "Satchel Charge") ) - return gSkillData.plrDmgSatchel; - if ( !strcmp( pName, "Trip Mine") ) - return gSkillData.plrDmgTripmine; - - return 0; -} - - -void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, int skillLevel ) -{ - FILE *fp; - - fp = fopen( "stats.txt", "a" ); - if ( !fp ) - return; - fprintf( fp, "%6.2f, %6.2f, %6.2f, %s, %2d\n", dataTime, health, ammo, pMapname, skillLevel ); - fclose( fp ); -} - - -#define AMMO_THRESHOLD 10 // This much ammo goes by before it is "interesting" -#define HEALTH_THRESHOLD 10 // Same for health -#define OUTPUT_LATENCY 3 // This many seconds for ammo/health to settle - -typedef struct -{ - int lastAmmo; - float lastHealth; - float lastOutputTime; // NOTE: These times are in "game" time -- a running total of elapsed time since the game started - float nextOutputTime; - float dataTime; - float gameTime; - float lastGameTime; -} TESTSTATS; - -TESTSTATS gStats = {0,0,0,0,0,0,0}; - -void UpdateStats( CBasePlayer *pPlayer ) -{ - int i; - - int ammoCount[ MAX_AMMO_SLOTS ]; - memcpy( ammoCount, pPlayer->m_rgAmmo, MAX_AMMO_SLOTS * sizeof(int) ); - - // Keep a running time, so the graph doesn't overlap - - if ( gpGlobals->time < gStats.lastGameTime ) // Changed level or died, don't b0rk - { - gStats.lastGameTime = gpGlobals->time; - gStats.dataTime = gStats.gameTime; - } - - gStats.gameTime += gpGlobals->time - gStats.lastGameTime; - gStats.lastGameTime = gpGlobals->time; - - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - CBasePlayerItem *p = pPlayer->m_rgpPlayerItems[i]; - while (p) - { - ItemInfo II; - - memset(&II, 0, sizeof(II)); - p->GetItemInfo(&II); - - int index = pPlayer->GetAmmoIndex(II.pszAmmo1); - if ( index >= 0 ) - ammoCount[ index ] += ((CBasePlayerWeapon *)p)->m_iClip; - - p = p->m_pNext; - } - } - - float ammo = 0; - for (i = 1; i < MAX_AMMO_SLOTS; i++) - { - ammo += ammoCount[i] * AmmoDamage( CBasePlayerItem::AmmoInfoArray[i].pszName ); - } - - float health = pPlayer->pev->health + pPlayer->pev->armorvalue * 2; // Armor is 2X health - float ammoDelta = fabs( ammo - gStats.lastAmmo ); - float healthDelta = fabs( health - gStats.lastHealth ); - int forceWrite = 0; - if ( health <= 0 && gStats.lastHealth > 0 ) - forceWrite = 1; - - if ( (ammoDelta > AMMO_THRESHOLD || healthDelta > HEALTH_THRESHOLD) && !forceWrite ) - { - if ( gStats.nextOutputTime == 0 ) - gStats.dataTime = gStats.gameTime; - - gStats.lastAmmo = ammo; - gStats.lastHealth = health; - - gStats.nextOutputTime = gStats.gameTime + OUTPUT_LATENCY; - } - else if ( (gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime) || forceWrite ) - { - UpdateStatsFile( gStats.dataTime, (char *)STRING(gpGlobals->mapname), health, ammo, (int)CVAR_GET_FLOAT("skill") ); - - gStats.lastAmmo = ammo; - gStats.lastHealth = health; - gStats.lastOutputTime = gStats.gameTime; - gStats.nextOutputTime = 0; - } -} - -void InitStats( CBasePlayer *pPlayer ) -{ - gStats.lastGameTime = gpGlobals->time; // Fixup stats time -} - +#include "extdll.h" +#include "util.h" + +#include "cbase.h" +#include "player.h" +#include "trains.h" +#include "nodes.h" +#include "weapons.h" +#include "soundent.h" +#include "monsters.h" +#include "..\engine\shake.h" +#include "decals.h" +#include "gamerules.h" + + +float AmmoDamage( const char *pName ) +{ + if ( !pName ) + return 0; + + if ( !strcmp( pName, "9mm" ) ) + return gSkillData.plrDmg9MM; + if ( !strcmp( pName, "357" ) ) + return gSkillData.plrDmg357; + if ( !strcmp( pName, "ARgrenades" ) ) + return gSkillData.plrDmgM203Grenade; + if ( !strcmp( pName, "buckshot" ) ) + return gSkillData.plrDmgBuckshot; + if ( !strcmp( pName, "bolts") ) + return gSkillData.plrDmgCrossbowMonster; + if ( !strcmp( pName, "rockets") ) + return gSkillData.plrDmgRPG; + if ( !strcmp( pName, "uranium") ) + return gSkillData.plrDmgGauss; + if ( !strcmp( pName, "Hand Grenade") ) + return gSkillData.plrDmgHandGrenade; + if ( !strcmp( pName, "Satchel Charge") ) + return gSkillData.plrDmgSatchel; + if ( !strcmp( pName, "Trip Mine") ) + return gSkillData.plrDmgTripmine; + + return 0; +} + + +void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, int skillLevel ) +{ + FILE *fp; + + fp = fopen( "stats.txt", "a" ); + if ( !fp ) + return; + fprintf( fp, "%6.2f, %6.2f, %6.2f, %s, %2d\n", dataTime, health, ammo, pMapname, skillLevel ); + fclose( fp ); +} + + +#define AMMO_THRESHOLD 10 // This much ammo goes by before it is "interesting" +#define HEALTH_THRESHOLD 10 // Same for health +#define OUTPUT_LATENCY 3 // This many seconds for ammo/health to settle + +typedef struct +{ + int lastAmmo; + float lastHealth; + float lastOutputTime; // NOTE: These times are in "game" time -- a running total of elapsed time since the game started + float nextOutputTime; + float dataTime; + float gameTime; + float lastGameTime; +} TESTSTATS; + +TESTSTATS gStats = {0,0,0,0,0,0,0}; + +void UpdateStats( CBasePlayer *pPlayer ) +{ + int i; + + int ammoCount[ MAX_AMMO_SLOTS ]; + memcpy( ammoCount, pPlayer->m_rgAmmo, MAX_AMMO_SLOTS * sizeof(int) ); + + // Keep a running time, so the graph doesn't overlap + + if ( gpGlobals->time < gStats.lastGameTime ) // Changed level or died, don't b0rk + { + gStats.lastGameTime = gpGlobals->time; + gStats.dataTime = gStats.gameTime; + } + + gStats.gameTime += gpGlobals->time - gStats.lastGameTime; + gStats.lastGameTime = gpGlobals->time; + + for (i = 0; i < MAX_ITEM_TYPES; i++) + { + CBasePlayerItem *p = pPlayer->m_rgpPlayerItems[i]; + while (p) + { + ItemInfo II; + + memset(&II, 0, sizeof(II)); + p->GetItemInfo(&II); + + int index = pPlayer->GetAmmoIndex(II.pszAmmo1); + if ( index >= 0 ) + ammoCount[ index ] += ((CBasePlayerWeapon *)p)->m_iClip; + + p = p->m_pNext; + } + } + + float ammo = 0; + for (i = 1; i < MAX_AMMO_SLOTS; i++) + { + ammo += ammoCount[i] * AmmoDamage( CBasePlayerItem::AmmoInfoArray[i].pszName ); + } + + float health = pPlayer->pev->health + pPlayer->pev->armorvalue * 2; // Armor is 2X health + float ammoDelta = fabs( ammo - gStats.lastAmmo ); + float healthDelta = fabs( health - gStats.lastHealth ); + int forceWrite = 0; + if ( health <= 0 && gStats.lastHealth > 0 ) + forceWrite = 1; + + if ( (ammoDelta > AMMO_THRESHOLD || healthDelta > HEALTH_THRESHOLD) && !forceWrite ) + { + if ( gStats.nextOutputTime == 0 ) + gStats.dataTime = gStats.gameTime; + + gStats.lastAmmo = ammo; + gStats.lastHealth = health; + + gStats.nextOutputTime = gStats.gameTime + OUTPUT_LATENCY; + } + else if ( (gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime) || forceWrite ) + { + UpdateStatsFile( gStats.dataTime, (char *)STRING(gpGlobals->mapname), health, ammo, (int)CVAR_GET_FLOAT("skill") ); + + gStats.lastAmmo = ammo; + gStats.lastHealth = health; + gStats.lastOutputTime = gStats.gameTime; + gStats.nextOutputTime = 0; + } +} + +void InitStats( CBasePlayer *pPlayer ) +{ + gStats.lastGameTime = gpGlobals->time; // Fixup stats time +} + diff --git a/main/source/dlls/subs.cpp b/main/source/dlls/subs.cpp index b249b2b9..3dd35292 100644 --- a/main/source/dlls/subs.cpp +++ b/main/source/dlls/subs.cpp @@ -1,568 +1,568 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== subs.cpp ======================================================== - - frequently used global functions - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "nodes.h" -#include "doors.h" - -extern CGraph WorldGraph; - -extern BOOL FEntIsVisible(entvars_t* pev, entvars_t* pevTarget); - -extern DLL_GLOBAL int g_iSkillLevel; - - -// Landmark class -void CPointEntity :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - -// UTIL_SetSize(pev, g_vecZero, g_vecZero); -} - - -class CNullEntity : public CBaseEntity -{ -public: - void Spawn( void ); -}; - - -// Null Entity, remove on startup -void CNullEntity :: Spawn( void ) -{ - REMOVE_ENTITY(ENT(pev)); -} -LINK_ENTITY_TO_CLASS(info_null,CNullEntity); - -class CBaseDMStart : public CPointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - BOOL IsTriggered( CBaseEntity *pEntity ); - -private: -}; - -// These are the new entry points to entities. -LINK_ENTITY_TO_CLASS(info_player_deathmatch,CBaseDMStart); -LINK_ENTITY_TO_CLASS(info_player_start,CPointEntity); -LINK_ENTITY_TO_CLASS(info_landmark,CPointEntity); - -void CBaseDMStart::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -BOOL CBaseDMStart::IsTriggered( CBaseEntity *pEntity ) -{ - BOOL master = UTIL_IsMasterTriggered( pev->netname, pEntity ); - - return master; -} - -// This updates global tables that need to know about entities being removed -void CBaseEntity::UpdateOnRemove( void ) -{ - int i; - - if ( FBitSet( pev->flags, FL_GRAPHED ) ) - { - // this entity was a LinkEnt in the world node graph, so we must remove it from - // the graph since we are removing it from the world. - for ( i = 0 ; i < WorldGraph.m_cLinks ; i++ ) - { - if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev ) - { - // if this link has a link ent which is the same ent that is removing itself, remove it! - WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL; - } - } - } - if ( pev->globalname ) - gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD ); -} - -// Convenient way to delay removing oneself -void CBaseEntity :: SUB_Remove( void ) -{ - UpdateOnRemove(); - if (pev->health > 0) - { - // this situation can screw up monsters who can't tell their entity pointers are invalid. - pev->health = 0; - ALERT( at_aiconsole, "SUB_Remove called on entity with health > 0\n"); - } - - REMOVE_ENTITY(ENT(pev)); -} - - -// Convenient way to explicitly do nothing (passed to functions that require a method) -void CBaseEntity :: SUB_DoNothing( void ) -{ -} - - -// Global Savedata for Delay -TYPEDESCRIPTION CBaseDelay::m_SaveData[] = -{ - DEFINE_FIELD( CBaseDelay, m_flDelay, FIELD_FLOAT ), - DEFINE_FIELD( CBaseDelay, m_iszKillTarget, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CBaseDelay, CBaseEntity ); - -void CBaseDelay :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "delay")) - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "killtarget")) - { - m_iszKillTarget = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - { - CBaseEntity::KeyValue( pkvd ); - } -} - - -/* -============================== -SUB_UseTargets - -If self.delay is set, a DelayedUse entity will be created that will actually -do the SUB_UseTargets after that many seconds have passed. - -Removes all entities with a targetname that match self.killtarget, -and removes them, so some events can remove other triggers. - -Search for (string)targetname in all entities that -match (string)self.target and call their .use function (if they have one) - -============================== -*/ -void CBaseEntity :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) -{ - // - // fire targets - // - if (!FStringNull(pev->target)) - { - FireTargets( STRING(pev->target), pActivator, this, useType, value ); - } -} - - -void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - edict_t *pentTarget = NULL; - if ( !targetName ) - return; - - ALERT( at_aiconsole, "Firing: (%s)\n", targetName ); - - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, targetName); - if (FNullEnt(pentTarget)) - break; - - CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); - if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents - { - ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName ); - pTarget->Use( pActivator, pCaller, useType, value ); - } - } -} - -LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay ); - - -void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) -{ - // - // exit immediatly if we don't have a target or kill target - // - if (FStringNull(pev->target) && !m_iszKillTarget) - return; - - // - // check for a delay - // - if (m_flDelay != 0) - { - // create a temp object to fire at a later time - CBaseDelay *pTemp = GetClassPtr( (CBaseDelay *)NULL); - pTemp->pev->classname = MAKE_STRING("DelayedUse"); - - pTemp->pev->nextthink = gpGlobals->time + m_flDelay; - - pTemp->SetThink( &CBaseDelay::DelayThink ); - - // Save the useType - pTemp->pev->button = (int)useType; - pTemp->m_iszKillTarget = m_iszKillTarget; - pTemp->m_flDelay = 0; // prevent "recursion" - pTemp->pev->target = pev->target; - - // HACKHACK - // This wasn't in the release build of Half-Life. We should have moved m_hActivator into this class - // but changing member variable hierarchy would break save/restore without some ugly code. - // This code is not as ugly as that code - if ( pActivator && pActivator->IsPlayer() ) // If a player activates, then save it - { - pTemp->pev->owner = pActivator->edict(); - } - else - { - pTemp->pev->owner = NULL; - } - - return; - } - - // - // kill the killtargets - // - - if ( m_iszKillTarget ) - { - edict_t *pentKillTarget = NULL; - - ALERT( at_aiconsole, "KillTarget: %s\n", STRING(m_iszKillTarget) ); - pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) ); - while ( !FNullEnt(pentKillTarget) ) - { - UTIL_Remove( CBaseEntity::Instance(pentKillTarget) ); - - ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) ); - pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) ); - } - } - - // - // fire targets - // - if (!FStringNull(pev->target)) - { - FireTargets( STRING(pev->target), pActivator, this, useType, value ); - } -} - - -/* -void CBaseDelay :: SUB_UseTargetsEntMethod( void ) -{ - SUB_UseTargets(pev); -} -*/ - -/* -QuakeEd only writes a single float for angles (bad idea), so up and down are -just constant angles. -*/ -void SetMovedir( entvars_t *pev ) -{ - if (pev->angles == Vector(0, -1, 0)) - { - pev->movedir = Vector(0, 0, 1); - } - else if (pev->angles == Vector(0, -2, 0)) - { - pev->movedir = Vector(0, 0, -1); - } - else - { - UTIL_MakeVectors(pev->angles); - pev->movedir = gpGlobals->v_forward; - } - - pev->angles = g_vecZero; -} - - - - -void CBaseDelay::DelayThink( void ) -{ - CBaseEntity *pActivator = NULL; - - if ( pev->owner != NULL ) // A player activated this on delay - { - pActivator = CBaseEntity::Instance( pev->owner ); - } - // The use type is cached (and stashed) in pev->button - SUB_UseTargets( pActivator, (USE_TYPE)pev->button, 0 ); - REMOVE_ENTITY(ENT(pev)); -} - - -// Global Savedata for Toggle -TYPEDESCRIPTION CBaseToggle::m_SaveData[] = -{ - DEFINE_FIELD( CBaseToggle, m_toggle_state, FIELD_INTEGER ), - DEFINE_FIELD( CBaseToggle, m_flActivateFinished, FIELD_TIME ), - DEFINE_FIELD( CBaseToggle, m_flMoveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flLip, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flTWidth, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flTLength, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_vecPosition1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_vecPosition2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_vecAngle1, FIELD_VECTOR ), // UNDONE: Position could go through transition, but also angle? - DEFINE_FIELD( CBaseToggle, m_vecAngle2, FIELD_VECTOR ), // UNDONE: Position could go through transition, but also angle? - DEFINE_FIELD( CBaseToggle, m_cTriggersLeft, FIELD_INTEGER ), - DEFINE_FIELD( CBaseToggle, m_flHeight, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_hActivator, FIELD_EHANDLE ), - DEFINE_FIELD( CBaseToggle, m_pfnCallWhenMoveDone, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseToggle, m_vecFinalDest, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_vecFinalAngle, FIELD_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_sMaster, FIELD_STRING), - DEFINE_FIELD( CBaseToggle, m_bitsDamageInflict, FIELD_INTEGER ), // damage type inflicted -}; -IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating ); - - -void CBaseToggle::SaveDataForReset() -{ -} - -void CBaseToggle::ResetEntity() -{ -} - -void CBaseToggle::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lip")) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_sMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "distance")) - { - m_flMoveDistance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - -/* -============= -LinearMove - -calculate pev->velocity and pev->nextthink to reach vecDest from -pev->origin traveling at flSpeed -=============== -*/ -void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!"); -// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "LinearMove: no post-move function defined"); - - m_vecFinalDest = vecDest; - - // Already there? - if (vecDest == pev->origin) - { - LinearMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDest - pev->origin; - - // divide vector length by speed to get time to reach dest - float flTravelTime = vecDestDelta.Length() / flSpeed; - - // set nextthink to trigger a call to LinearMoveDone when dest is reached - pev->nextthink = pev->ltime + flTravelTime; - SetThink( &CBaseToggle::LinearMoveDone ); - - // scale the destdelta vector by the time spent traveling to get velocity - pev->velocity = vecDestDelta / flTravelTime; -} - - -/* -============ -After moving, set origin to exact final destination, call "move done" function -============ -*/ -void CBaseToggle :: LinearMoveDone( void ) -{ - UTIL_SetOrigin(pev, m_vecFinalDest); - pev->velocity = g_vecZero; - pev->nextthink = -1; - if ( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); -} - -BOOL CBaseToggle :: IsLockedByMaster( void ) -{ - if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return TRUE; - else - return FALSE; -} - -/* -============= -AngularMove - -calculate pev->velocity and pev->nextthink to reach vecDest from -pev->origin traveling at flSpeed -Just like LinearMove, but rotational. -=============== -*/ -void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!"); -// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "AngularMove: no post-move function defined"); - - m_vecFinalAngle = vecDestAngle; - - // Already there? - if (vecDestAngle == pev->angles) - { - AngularMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDestAngle - pev->angles; - - // divide by speed to get time to reach dest - float flTravelTime = vecDestDelta.Length() / flSpeed; - - // set nextthink to trigger a call to AngularMoveDone when dest is reached - pev->nextthink = pev->ltime + flTravelTime; - SetThink( &CBaseToggle::AngularMoveDone ); - - // scale the destdelta vector by the time spent traveling to get velocity - pev->avelocity = vecDestDelta / flTravelTime; -} - - -/* -============ -After rotating, set angle to exact final angle, call "move done" function -============ -*/ -void CBaseToggle :: AngularMoveDone( void ) -{ - pev->angles = m_vecFinalAngle; - pev->avelocity = g_vecZero; - pev->nextthink = -1; - if ( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); -} - - -float CBaseToggle :: AxisValue( int flags, const Vector &angles ) -{ - if ( FBitSet(flags, SF_DOOR_ROTATE_Z) ) - return angles.z; - if ( FBitSet(flags, SF_DOOR_ROTATE_X) ) - return angles.x; - - return angles.y; -} - - -void CBaseToggle :: AxisDir( entvars_t *pev ) -{ - if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_Z) ) - pev->movedir = Vector ( 0, 0, 1 ); // around z-axis - else if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_X) ) - pev->movedir = Vector ( 1, 0, 0 ); // around x-axis - else - pev->movedir = Vector ( 0, 1, 0 ); // around y-axis -} - - -float CBaseToggle :: AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ) -{ - if ( FBitSet (flags, SF_DOOR_ROTATE_Z) ) - return angle1.z - angle2.z; - - if ( FBitSet (flags, SF_DOOR_ROTATE_X) ) - return angle1.x - angle2.x; - - return angle1.y - angle2.y; -} - - -/* -============= -FEntIsVisible - -returns TRUE if the passed entity is visible to caller, even if not infront () -============= -*/ - BOOL -FEntIsVisible( - entvars_t* pev, - entvars_t* pevTarget) - { - Vector vecSpot1 = pev->origin + pev->view_ofs; - Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; - TraceResult tr; - - UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); - - if (tr.fInOpen && tr.fInWater) - return FALSE; // sight line crossed contents - - if (tr.flFraction == 1) - return TRUE; - - return FALSE; - } - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== subs.cpp ======================================================== + + frequently used global functions + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include "nodes.h" +#include "doors.h" + +extern CGraph WorldGraph; + +extern BOOL FEntIsVisible(entvars_t* pev, entvars_t* pevTarget); + +extern DLL_GLOBAL int g_iSkillLevel; + + +// Landmark class +void CPointEntity :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + +// UTIL_SetSize(pev, g_vecZero, g_vecZero); +} + + +class CNullEntity : public CBaseEntity +{ +public: + void Spawn( void ); +}; + + +// Null Entity, remove on startup +void CNullEntity :: Spawn( void ) +{ + REMOVE_ENTITY(ENT(pev)); +} +LINK_ENTITY_TO_CLASS(info_null,CNullEntity); + +class CBaseDMStart : public CPointEntity +{ +public: + void KeyValue( KeyValueData *pkvd ); + BOOL IsTriggered( CBaseEntity *pEntity ); + +private: +}; + +// These are the new entry points to entities. +LINK_ENTITY_TO_CLASS(info_player_deathmatch,CBaseDMStart); +LINK_ENTITY_TO_CLASS(info_player_start,CPointEntity); +LINK_ENTITY_TO_CLASS(info_landmark,CPointEntity); + +void CBaseDMStart::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "master")) + { + pev->netname = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +BOOL CBaseDMStart::IsTriggered( CBaseEntity *pEntity ) +{ + BOOL master = UTIL_IsMasterTriggered( pev->netname, pEntity ); + + return master; +} + +// This updates global tables that need to know about entities being removed +void CBaseEntity::UpdateOnRemove( void ) +{ + int i; + + if ( FBitSet( pev->flags, FL_GRAPHED ) ) + { + // this entity was a LinkEnt in the world node graph, so we must remove it from + // the graph since we are removing it from the world. + for ( i = 0 ; i < WorldGraph.m_cLinks ; i++ ) + { + if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev ) + { + // if this link has a link ent which is the same ent that is removing itself, remove it! + WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL; + } + } + } + if ( pev->globalname ) + gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD ); +} + +// Convenient way to delay removing oneself +void CBaseEntity :: SUB_Remove( void ) +{ + UpdateOnRemove(); + if (pev->health > 0) + { + // this situation can screw up monsters who can't tell their entity pointers are invalid. + pev->health = 0; + ALERT( at_aiconsole, "SUB_Remove called on entity with health > 0\n"); + } + + REMOVE_ENTITY(ENT(pev)); +} + + +// Convenient way to explicitly do nothing (passed to functions that require a method) +void CBaseEntity :: SUB_DoNothing( void ) +{ +} + + +// Global Savedata for Delay +TYPEDESCRIPTION CBaseDelay::m_SaveData[] = +{ + DEFINE_FIELD( CBaseDelay, m_flDelay, FIELD_FLOAT ), + DEFINE_FIELD( CBaseDelay, m_iszKillTarget, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE( CBaseDelay, CBaseEntity ); + +void CBaseDelay :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "delay")) + { + m_flDelay = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "killtarget")) + { + m_iszKillTarget = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + { + CBaseEntity::KeyValue( pkvd ); + } +} + + +/* +============================== +SUB_UseTargets + +If self.delay is set, a DelayedUse entity will be created that will actually +do the SUB_UseTargets after that many seconds have passed. + +Removes all entities with a targetname that match self.killtarget, +and removes them, so some events can remove other triggers. + +Search for (string)targetname in all entities that +match (string)self.target and call their .use function (if they have one) + +============================== +*/ +void CBaseEntity :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) +{ + // + // fire targets + // + if (!FStringNull(pev->target)) + { + FireTargets( STRING(pev->target), pActivator, this, useType, value ); + } +} + + +void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + edict_t *pentTarget = NULL; + if ( !targetName ) + return; + + ALERT( at_aiconsole, "Firing: (%s)\n", targetName ); + + for (;;) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, targetName); + if (FNullEnt(pentTarget)) + break; + + CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); + if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents + { + ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName ); + pTarget->Use( pActivator, pCaller, useType, value ); + } + } +} + +LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay ); + + +void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) +{ + // + // exit immediatly if we don't have a target or kill target + // + if (FStringNull(pev->target) && !m_iszKillTarget) + return; + + // + // check for a delay + // + if (m_flDelay != 0) + { + // create a temp object to fire at a later time + CBaseDelay *pTemp = GetClassPtr( (CBaseDelay *)NULL); + pTemp->pev->classname = MAKE_STRING("DelayedUse"); + + pTemp->pev->nextthink = gpGlobals->time + m_flDelay; + + pTemp->SetThink( &CBaseDelay::DelayThink ); + + // Save the useType + pTemp->pev->button = (int)useType; + pTemp->m_iszKillTarget = m_iszKillTarget; + pTemp->m_flDelay = 0; // prevent "recursion" + pTemp->pev->target = pev->target; + + // HACKHACK + // This wasn't in the release build of Half-Life. We should have moved m_hActivator into this class + // but changing member variable hierarchy would break save/restore without some ugly code. + // This code is not as ugly as that code + if ( pActivator && pActivator->IsPlayer() ) // If a player activates, then save it + { + pTemp->pev->owner = pActivator->edict(); + } + else + { + pTemp->pev->owner = NULL; + } + + return; + } + + // + // kill the killtargets + // + + if ( m_iszKillTarget ) + { + edict_t *pentKillTarget = NULL; + + ALERT( at_aiconsole, "KillTarget: %s\n", STRING(m_iszKillTarget) ); + pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) ); + while ( !FNullEnt(pentKillTarget) ) + { + UTIL_Remove( CBaseEntity::Instance(pentKillTarget) ); + + ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) ); + pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) ); + } + } + + // + // fire targets + // + if (!FStringNull(pev->target)) + { + FireTargets( STRING(pev->target), pActivator, this, useType, value ); + } +} + + +/* +void CBaseDelay :: SUB_UseTargetsEntMethod( void ) +{ + SUB_UseTargets(pev); +} +*/ + +/* +QuakeEd only writes a single float for angles (bad idea), so up and down are +just constant angles. +*/ +void SetMovedir( entvars_t *pev ) +{ + if (pev->angles == Vector(0, -1, 0)) + { + pev->movedir = Vector(0, 0, 1); + } + else if (pev->angles == Vector(0, -2, 0)) + { + pev->movedir = Vector(0, 0, -1); + } + else + { + UTIL_MakeVectors(pev->angles); + pev->movedir = gpGlobals->v_forward; + } + + pev->angles = g_vecZero; +} + + + + +void CBaseDelay::DelayThink( void ) +{ + CBaseEntity *pActivator = NULL; + + if ( pev->owner != NULL ) // A player activated this on delay + { + pActivator = CBaseEntity::Instance( pev->owner ); + } + // The use type is cached (and stashed) in pev->button + SUB_UseTargets( pActivator, (USE_TYPE)pev->button, 0 ); + REMOVE_ENTITY(ENT(pev)); +} + + +// Global Savedata for Toggle +TYPEDESCRIPTION CBaseToggle::m_SaveData[] = +{ + DEFINE_FIELD( CBaseToggle, m_toggle_state, FIELD_INTEGER ), + DEFINE_FIELD( CBaseToggle, m_flActivateFinished, FIELD_TIME ), + DEFINE_FIELD( CBaseToggle, m_flMoveDistance, FIELD_FLOAT ), + DEFINE_FIELD( CBaseToggle, m_flWait, FIELD_FLOAT ), + DEFINE_FIELD( CBaseToggle, m_flLip, FIELD_FLOAT ), + DEFINE_FIELD( CBaseToggle, m_flTWidth, FIELD_FLOAT ), + DEFINE_FIELD( CBaseToggle, m_flTLength, FIELD_FLOAT ), + DEFINE_FIELD( CBaseToggle, m_vecPosition1, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseToggle, m_vecPosition2, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseToggle, m_vecAngle1, FIELD_VECTOR ), // UNDONE: Position could go through transition, but also angle? + DEFINE_FIELD( CBaseToggle, m_vecAngle2, FIELD_VECTOR ), // UNDONE: Position could go through transition, but also angle? + DEFINE_FIELD( CBaseToggle, m_cTriggersLeft, FIELD_INTEGER ), + DEFINE_FIELD( CBaseToggle, m_flHeight, FIELD_FLOAT ), + DEFINE_FIELD( CBaseToggle, m_hActivator, FIELD_EHANDLE ), + DEFINE_FIELD( CBaseToggle, m_pfnCallWhenMoveDone, FIELD_FUNCTION ), + DEFINE_FIELD( CBaseToggle, m_vecFinalDest, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseToggle, m_vecFinalAngle, FIELD_VECTOR ), + DEFINE_FIELD( CBaseToggle, m_sMaster, FIELD_STRING), + DEFINE_FIELD( CBaseToggle, m_bitsDamageInflict, FIELD_INTEGER ), // damage type inflicted +}; +IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating ); + + +void CBaseToggle::SaveDataForReset() +{ +} + +void CBaseToggle::ResetEntity() +{ +} + +void CBaseToggle::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "lip")) + { + m_flLip = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "wait")) + { + m_flWait = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "master")) + { + m_sMaster = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "distance")) + { + m_flMoveDistance = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseDelay::KeyValue( pkvd ); +} + +/* +============= +LinearMove + +calculate pev->velocity and pev->nextthink to reach vecDest from +pev->origin traveling at flSpeed +=============== +*/ +void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) +{ + ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!"); +// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "LinearMove: no post-move function defined"); + + m_vecFinalDest = vecDest; + + // Already there? + if (vecDest == pev->origin) + { + LinearMoveDone(); + return; + } + + // set destdelta to the vector needed to move + Vector vecDestDelta = vecDest - pev->origin; + + // divide vector length by speed to get time to reach dest + float flTravelTime = vecDestDelta.Length() / flSpeed; + + // set nextthink to trigger a call to LinearMoveDone when dest is reached + pev->nextthink = pev->ltime + flTravelTime; + SetThink( &CBaseToggle::LinearMoveDone ); + + // scale the destdelta vector by the time spent traveling to get velocity + pev->velocity = vecDestDelta / flTravelTime; +} + + +/* +============ +After moving, set origin to exact final destination, call "move done" function +============ +*/ +void CBaseToggle :: LinearMoveDone( void ) +{ + UTIL_SetOrigin(pev, m_vecFinalDest); + pev->velocity = g_vecZero; + pev->nextthink = -1; + if ( m_pfnCallWhenMoveDone ) + (this->*m_pfnCallWhenMoveDone)(); +} + +BOOL CBaseToggle :: IsLockedByMaster( void ) +{ + if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + return TRUE; + else + return FALSE; +} + +/* +============= +AngularMove + +calculate pev->velocity and pev->nextthink to reach vecDest from +pev->origin traveling at flSpeed +Just like LinearMove, but rotational. +=============== +*/ +void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) +{ + ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!"); +// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "AngularMove: no post-move function defined"); + + m_vecFinalAngle = vecDestAngle; + + // Already there? + if (vecDestAngle == pev->angles) + { + AngularMoveDone(); + return; + } + + // set destdelta to the vector needed to move + Vector vecDestDelta = vecDestAngle - pev->angles; + + // divide by speed to get time to reach dest + float flTravelTime = vecDestDelta.Length() / flSpeed; + + // set nextthink to trigger a call to AngularMoveDone when dest is reached + pev->nextthink = pev->ltime + flTravelTime; + SetThink( &CBaseToggle::AngularMoveDone ); + + // scale the destdelta vector by the time spent traveling to get velocity + pev->avelocity = vecDestDelta / flTravelTime; +} + + +/* +============ +After rotating, set angle to exact final angle, call "move done" function +============ +*/ +void CBaseToggle :: AngularMoveDone( void ) +{ + pev->angles = m_vecFinalAngle; + pev->avelocity = g_vecZero; + pev->nextthink = -1; + if ( m_pfnCallWhenMoveDone ) + (this->*m_pfnCallWhenMoveDone)(); +} + + +float CBaseToggle :: AxisValue( int flags, const Vector &angles ) +{ + if ( FBitSet(flags, SF_DOOR_ROTATE_Z) ) + return angles.z; + if ( FBitSet(flags, SF_DOOR_ROTATE_X) ) + return angles.x; + + return angles.y; +} + + +void CBaseToggle :: AxisDir( entvars_t *pev ) +{ + if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_Z) ) + pev->movedir = Vector ( 0, 0, 1 ); // around z-axis + else if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_X) ) + pev->movedir = Vector ( 1, 0, 0 ); // around x-axis + else + pev->movedir = Vector ( 0, 1, 0 ); // around y-axis +} + + +float CBaseToggle :: AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ) +{ + if ( FBitSet (flags, SF_DOOR_ROTATE_Z) ) + return angle1.z - angle2.z; + + if ( FBitSet (flags, SF_DOOR_ROTATE_X) ) + return angle1.x - angle2.x; + + return angle1.y - angle2.y; +} + + +/* +============= +FEntIsVisible + +returns TRUE if the passed entity is visible to caller, even if not infront () +============= +*/ + BOOL +FEntIsVisible( + entvars_t* pev, + entvars_t* pevTarget) + { + Vector vecSpot1 = pev->origin + pev->view_ofs; + Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; + TraceResult tr; + + UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); + + if (tr.fInOpen && tr.fInWater) + return FALSE; // sight line crossed contents + + if (tr.flFraction == 1) + return TRUE; + + return FALSE; + } + + diff --git a/main/source/dlls/talkmonster.cpp b/main/source/dlls/talkmonster.cpp index 8e283fa0..27b92765 100644 --- a/main/source/dlls/talkmonster.cpp +++ b/main/source/dlls/talkmonster.cpp @@ -1,1475 +1,1475 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "talkmonster.h" -#include "defaultai.h" -#include "scripted.h" -#include "soundent.h" -#include "animation.h" - -//========================================================= -// Talking monster base class -// Used for scientists and barneys -//========================================================= -float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once - -// Allow assignment within conditional -#pragma warning (disable: 4706) - -// NOTE: m_voicePitch & m_szGrp should be fixed up by precache each save/restore - -TYPEDESCRIPTION CTalkMonster::m_SaveData[] = -{ - DEFINE_FIELD( CTalkMonster, m_bitsSaid, FIELD_INTEGER ), - DEFINE_FIELD( CTalkMonster, m_nSpeak, FIELD_INTEGER ), - - // Recalc'ed in Precache() - // DEFINE_FIELD( CTalkMonster, m_voicePitch, FIELD_INTEGER ), - // DEFINE_FIELD( CTalkMonster, m_szGrp, FIELD_??? ), - DEFINE_FIELD( CTalkMonster, m_useTime, FIELD_TIME ), - DEFINE_FIELD( CTalkMonster, m_iszUse, FIELD_STRING ), - DEFINE_FIELD( CTalkMonster, m_iszUnUse, FIELD_STRING ), - DEFINE_FIELD( CTalkMonster, m_flLastSaidSmelled, FIELD_TIME ), - DEFINE_FIELD( CTalkMonster, m_flStopTalkTime, FIELD_TIME ), - DEFINE_FIELD( CTalkMonster, m_hTalkTarget, FIELD_EHANDLE ), -}; - -IMPLEMENT_SAVERESTORE( CTalkMonster, CBaseMonster ); - -// array of friend names -char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = -{ - "monster_barney", - "monster_scientist", - "monster_sitting_scientist", -}; - - -//========================================================= -// AI Schedules Specific to talking monsters -//========================================================= - -Task_t tlIdleResponse[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_IDLE },// Stop and listen - { TASK_WAIT, (float)0.5 },// Wait until sure it's me they are talking to - { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done - { TASK_TLK_RESPOND, (float)0 },// Wait and then say my response - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done -}; - -Schedule_t slIdleResponse[] = -{ - { - tlIdleResponse, - ARRAYSIZE ( tlIdleResponse ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Response" - - }, -}; - -Task_t tlIdleSpeak[] = -{ - { TASK_TLK_SPEAK, (float)0 },// question or remark - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT_RANDOM, (float)0.5 }, -}; - -Schedule_t slIdleSpeak[] = -{ - { - tlIdleSpeak, - ARRAYSIZE ( tlIdleSpeak ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Speak" - }, -}; - -Task_t tlIdleSpeakWait[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 },// Stop and talk - { TASK_TLK_SPEAK, (float)0 },// question or remark - { TASK_TLK_EYECONTACT, (float)0 },// - { TASK_WAIT, (float)2 },// wait - used when sci is in 'use' mode to keep head turned -}; - -Schedule_t slIdleSpeakWait[] = -{ - { - tlIdleSpeakWait, - ARRAYSIZE ( tlIdleSpeakWait ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Speak Wait" - }, -}; - -Task_t tlIdleHello[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 },// Stop and talk - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - -}; - -Schedule_t slIdleHello[] = -{ - { - tlIdleHello, - ARRAYSIZE ( tlIdleHello ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT, - "Idle Hello" - }, -}; - -Task_t tlIdleStopShooting[] = -{ - { TASK_TLK_STOPSHOOTING, (float)0 },// tell player to stop shooting friend - // { TASK_TLK_EYECONTACT, (float)0 },// look at the player -}; - -Schedule_t slIdleStopShooting[] = -{ - { - tlIdleStopShooting, - ARRAYSIZE ( tlIdleStopShooting ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - 0, - "Idle Stop Shooting" - }, -}; - -Task_t tlMoveAway[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MOVE_AWAY_FAIL }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_MOVE_AWAY_PATH, (float)100 }, - { TASK_WALK_PATH_FOR_UNITS, (float)100 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_PLAYER, (float)0.5 }, -}; - -Schedule_t slMoveAway[] = -{ - { - tlMoveAway, - ARRAYSIZE ( tlMoveAway ), - 0, - 0, - "MoveAway" - }, -}; - - -Task_t tlMoveAwayFail[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_PLAYER, (float)0.5 }, -}; - -Schedule_t slMoveAwayFail[] = -{ - { - tlMoveAwayFail, - ARRAYSIZE ( tlMoveAwayFail ), - 0, - 0, - "MoveAwayFail" - }, -}; - - - -Task_t tlMoveAwayFollow[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_FACE }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_MOVE_AWAY_PATH, (float)100 }, - { TASK_WALK_PATH_FOR_UNITS, (float)100 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slMoveAwayFollow[] = -{ - { - tlMoveAwayFollow, - ARRAYSIZE ( tlMoveAwayFollow ), - 0, - 0, - "MoveAwayFollow" - }, -}; - -Task_t tlTlkIdleWatchClient[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_TLK_LOOK_AT_CLIENT, (float)6 }, -}; - -Task_t tlTlkIdleWatchClientStare[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_TLK_CLIENT_STARE, (float)6 }, - { TASK_TLK_STARE, (float)0 }, - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 }, -}; - -Schedule_t slTlkIdleWatchClient[] = -{ - { - tlTlkIdleWatchClient, - ARRAYSIZE ( tlTlkIdleWatchClient ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_CLIENT_UNSEEN | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "TlkIdleWatchClient" - }, - - { - tlTlkIdleWatchClientStare, - ARRAYSIZE ( tlTlkIdleWatchClientStare ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_CLIENT_UNSEEN | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "TlkIdleWatchClientStare" - }, -}; - - -Task_t tlTlkIdleEyecontact[] = -{ - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done -}; - -Schedule_t slTlkIdleEyecontact[] = -{ - { - tlTlkIdleEyecontact, - ARRAYSIZE ( tlTlkIdleEyecontact ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "TlkIdleEyecontact" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CTalkMonster ) -{ - slIdleResponse, - slIdleSpeak, - slIdleHello, - slIdleSpeakWait, - slIdleStopShooting, - slMoveAway, - slMoveAwayFollow, - slMoveAwayFail, - slTlkIdleWatchClient, - &slTlkIdleWatchClient[ 1 ], - slTlkIdleEyecontact, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CTalkMonster, CBaseMonster ); - - -void CTalkMonster :: SetActivity ( Activity newActivity ) -{ - if (newActivity == ACT_IDLE && IsTalking() ) - newActivity = ACT_SIGNAL3; - - if ( newActivity == ACT_SIGNAL3 && (LookupActivity ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE)) - newActivity = ACT_IDLE; - - CBaseMonster::SetActivity( newActivity ); -} - - -void CTalkMonster :: StartTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TLK_SPEAK: - // ask question or make statement - FIdleSpeak(); - TaskComplete(); - break; - - case TASK_TLK_RESPOND: - // respond to question - IdleRespond(); - TaskComplete(); - break; - - case TASK_TLK_HELLO: - // greet player - FIdleHello(); - TaskComplete(); - break; - - - case TASK_TLK_STARE: - // let the player know I know he's staring at me. - FIdleStare(); - TaskComplete(); - break; - - case TASK_FACE_PLAYER: - case TASK_TLK_LOOK_AT_CLIENT: - case TASK_TLK_CLIENT_STARE: - // track head to the client for a while. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - - case TASK_TLK_EYECONTACT: - break; - - case TASK_TLK_IDEALYAW: - if (m_hTalkTarget != NULL) - { - pev->yaw_speed = 60; - float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw < 0) - { - pev->ideal_yaw = min( yaw + 45, 0 ) + pev->angles.y; - } - else - { - pev->ideal_yaw = max( yaw - 45, 0 ) + pev->angles.y; - } - } - TaskComplete(); - break; - - case TASK_TLK_HEADRESET: - // reset head position after looking at something - m_hTalkTarget = NULL; - TaskComplete(); - break; - - case TASK_TLK_STOPSHOOTING: - // tell player to stop shooting - PlaySentence( m_szGrp[TLK_NOSHOOT], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_NORM ); - TaskComplete(); - break; - - case TASK_CANT_FOLLOW: - StopFollowing( FALSE ); - PlaySentence( m_szGrp[TLK_STOP], RANDOM_FLOAT(2, 2.5), VOL_NORM, ATTN_NORM ); - TaskComplete(); - break; - - case TASK_WALK_PATH_FOR_UNITS: - m_movementActivity = ACT_WALK; - break; - - case TASK_MOVE_AWAY_PATH: - { - Vector dir = pev->angles; - dir.y = pev->ideal_yaw + 180; - Vector move; - - UTIL_MakeVectorsPrivate( dir, move, NULL, NULL ); - dir = pev->origin + move * pTask->flData; - if ( MoveToLocation( ACT_WALK, 2, dir ) ) - { - TaskComplete(); - } - else if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + 2; - TaskComplete(); - } - else - { - // nowhere to go? - TaskFail(); - } - } - break; - - case TASK_PLAY_SCRIPT: - m_hTalkTarget = NULL; - CBaseMonster::StartTask( pTask ); - break; - - default: - CBaseMonster::StartTask( pTask ); - } -} - - -void CTalkMonster :: RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_TLK_CLIENT_STARE: - case TASK_TLK_LOOK_AT_CLIENT: - - edict_t *pPlayer; - - // track head to the client for a while. - if ( m_MonsterState == MONSTERSTATE_IDLE && - !IsMoving() && - !IsTalking() ) - { - // Get edict for one player - pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - if ( pPlayer ) - { - IdleHeadTurn( pPlayer->v.origin ); - } - } - else - { - // started moving or talking - TaskFail(); - return; - } - - if ( pTask->iTask == TASK_TLK_CLIENT_STARE ) - { - // fail out if the player looks away or moves away. - if ( ( pPlayer->v.origin - pev->origin ).Length2D() > TLK_STARE_DIST ) - { - // player moved away. - TaskFail(); - } - - UTIL_MakeVectors( pPlayer->v.angles ); - if ( UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) < m_flFieldOfView ) - { - // player looked away - TaskFail(); - } - } - - if ( gpGlobals->time > m_flWaitFinished ) - { - TaskComplete(); - } - break; - - case TASK_FACE_PLAYER: - { - // Get edict for one player - edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - if ( pPlayer ) - { - MakeIdealYaw ( pPlayer->v.origin ); - ChangeYaw ( pev->yaw_speed ); - IdleHeadTurn( pPlayer->v.origin ); - if ( gpGlobals->time > m_flWaitFinished && FlYawDiff() < 10 ) - { - TaskComplete(); - } - } - else - { - TaskFail(); - } - } - break; - - case TASK_TLK_EYECONTACT: - if (!IsMoving() && IsTalking() && m_hTalkTarget != NULL) - { - // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); - IdleHeadTurn( m_hTalkTarget->pev->origin ); - } - else - { - TaskComplete(); - } - break; - - case TASK_WALK_PATH_FOR_UNITS: - { - float distance; - - distance = (m_vecLastPosition - pev->origin).Length2D(); - - // Walk path until far enough away - if ( distance > pTask->flData || MovementIsComplete() ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - } - break; - case TASK_WAIT_FOR_MOVEMENT: - if (IsTalking() && m_hTalkTarget != NULL) - { - // ALERT(at_console, "walking, talking\n"); - IdleHeadTurn( m_hTalkTarget->pev->origin ); - } - else - { - IdleHeadTurn( pev->origin ); - // override so that during walk, a scientist may talk and greet player - FIdleHello(); - if (RANDOM_LONG(0,m_nSpeak * 20) == 0) - { - FIdleSpeak(); - } - } - - CBaseMonster::RunTask( pTask ); - if (TaskIsComplete()) - IdleHeadTurn( pev->origin ); - break; - - default: - if (IsTalking() && m_hTalkTarget != NULL) - { - IdleHeadTurn( m_hTalkTarget->pev->origin ); - } - else - { - SetBoneController( 0, 0 ); - } - CBaseMonster::RunTask( pTask ); - } -} - - -void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - // If a client killed me (unless I was already Barnacle'd), make everyone else mad/afraid of him - if ( (pevAttacker->flags & FL_CLIENT) && m_MonsterState != MONSTERSTATE_PRONE ) - { - AlertFriends(); - LimitFollowers( CBaseEntity::Instance(pevAttacker), 0 ); - } - - m_hTargetEnt = NULL; - // Don't finish that sentence - StopTalking(); - SetUse( NULL ); - CBaseMonster::Killed( pevAttacker, iGib ); -} - - - -CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) -{ - CBaseEntity *pFriend = pPrevious; - char *pszFriend; - TraceResult tr; - Vector vecCheck; - - pszFriend = m_szFriends[ FriendNumber(listNumber) ]; - while (pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend )) - { - if (pFriend == this || !pFriend->IsAlive()) - // don't talk to self or dead people - continue; - if ( bTrace ) - { - vecCheck = pFriend->pev->origin; - vecCheck.z = pFriend->pev->absmax.z; - - UTIL_TraceLine( pev->origin, vecCheck, ignore_monsters, ENT(pev), &tr); - } - else - tr.flFraction = 1.0; - - if (tr.flFraction == 1.0) - { - return pFriend; - } - } - - return NULL; -} - - -void CTalkMonster::AlertFriends( void ) -{ - CBaseEntity *pFriend = NULL; - int i; - - // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) - { - while (pFriend = EnumFriends( pFriend, i, TRUE )) - { - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster->IsAlive() ) - { - // don't provoke a friend that's playing a death animation. They're a goner - pMonster->m_afMemory |= bits_MEMORY_PROVOKED; - } - } - } -} - - - -void CTalkMonster::ShutUpFriends( void ) -{ - CBaseEntity *pFriend = NULL; - int i; - - // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) - { - while (pFriend = EnumFriends( pFriend, i, TRUE )) - { - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster ) - { - pMonster->SentenceStop(); - } - } - } -} - - -// UNDONE: Keep a follow time in each follower, make a list of followers in this function and do LRU -// UNDONE: Check this in Restore to keep restored monsters from joining a full list of followers -void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) -{ - CBaseEntity *pFriend = NULL; - int i, count; - - count = 0; - // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) - { - while (pFriend = EnumFriends( pFriend, i, FALSE )) - { - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster ) - { - if ( pMonster->m_hTargetEnt == pPlayer ) - { - count++; - if ( count > maxFollowers ) - pMonster->StopFollowing( TRUE ); - } - } - } - } -} - - -float CTalkMonster::TargetDistance( void ) -{ - // If we lose the player, or he dies, return a really large distance - if ( m_hTargetEnt == NULL || !m_hTargetEnt->IsAlive() ) - return 1e6; - - return (m_hTargetEnt->pev->origin - pev->origin).Length(); -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CTalkMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCRIPT_EVENT_SENTENCE_RND1: // Play a named sentence group 25% of the time - if (RANDOM_LONG(0,99) < 75) - break; - // fall through... - case SCRIPT_EVENT_SENTENCE: // Play a named sentence group - ShutUpFriends(); - PlaySentence( pEvent->options, RANDOM_FLOAT(2.8, 3.4), VOL_NORM, ATTN_IDLE ); - //ALERT(at_console, "script event speak\n"); - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -// monsters derived from ctalkmonster should call this in precache() - -void CTalkMonster :: TalkInit( void ) -{ - // every new talking monster must reset this global, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - - CTalkMonster::g_talkWaitTime = 0; - - m_voicePitch = 100; -} -//========================================================= -// FindNearestFriend -// Scan for nearest, visible friend. If fPlayer is true, look for -// nearest player -//========================================================= -CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) -{ - CBaseEntity *pFriend = NULL; - CBaseEntity *pNearest = NULL; - float range = 10000000.0; - TraceResult tr; - Vector vecStart = pev->origin; - Vector vecCheck; - int i; - char *pszFriend; - int cfriends; - - vecStart.z = pev->absmax.z; - - if (fPlayer) - cfriends = 1; - else - cfriends = TLK_CFRIENDS; - - // for each type of friend... - - for (i = cfriends-1; i > -1; i--) - { - if (fPlayer) - pszFriend = "player"; - else - pszFriend = m_szFriends[FriendNumber(i)]; - - if (!pszFriend) - continue; - - // for each friend in this bsp... - while (pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend )) - { - if (pFriend == this || !pFriend->IsAlive()) - // don't talk to self or dead people - continue; - - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - - // If not a monster for some reason, or in a script, or prone - if ( !pMonster || pMonster->m_MonsterState == MONSTERSTATE_SCRIPT || pMonster->m_MonsterState == MONSTERSTATE_PRONE ) - continue; - - vecCheck = pFriend->pev->origin; - vecCheck.z = pFriend->pev->absmax.z; - - // if closer than previous friend, and in range, see if he's visible - - if (range > (vecStart - vecCheck).Length()) - { - UTIL_TraceLine(vecStart, vecCheck, ignore_monsters, ENT(pev), &tr); - - if (tr.flFraction == 1.0) - { - // visible and in range, this is the new nearest scientist - if ((vecStart - vecCheck).Length() < TALKRANGE_MIN) - { - pNearest = pFriend; - range = (vecStart - vecCheck).Length(); - } - } - } - } - } - return pNearest; -} - -int CTalkMonster :: GetVoicePitch( void ) -{ - return m_voicePitch + RANDOM_LONG(0,3); -} - - -void CTalkMonster :: Touch( CBaseEntity *pOther ) -{ - // Did the player touch me? - if ( pOther->IsPlayer() ) - { - // Ignore if pissed at player - if ( m_afMemory & bits_MEMORY_PROVOKED ) - return; - - // Stay put during speech - if ( IsTalking() ) - return; - - // Heuristic for determining if the player is pushing me away - float speed = fabs(pOther->pev->velocity.x) + fabs(pOther->pev->velocity.y); - if ( speed > 50 ) - { - SetConditions( bits_COND_CLIENT_PUSH ); - MakeIdealYaw( pOther->pev->origin ); - } - } -} - - - -//========================================================= -// IdleRespond -// Respond to a previous question -//========================================================= -void CTalkMonster :: IdleRespond( void ) -{ - int pitch = GetVoicePitch(); - - // play response - PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); -} - -int CTalkMonster :: FOkToSpeak( void ) -{ - // if in the grip of a barnacle, don't speak - if ( m_MonsterState == MONSTERSTATE_PRONE || m_IdealMonsterState == MONSTERSTATE_PRONE ) - { - return FALSE; - } - - // if not alive, certainly don't speak - if ( pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - // if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - return FALSE; - - if ( pev->spawnflags & SF_MONSTER_GAG ) - return FALSE; - - if ( m_MonsterState == MONSTERSTATE_PRONE ) - return FALSE; - - // if player is not in pvs, don't speak - if (!IsAlive() || FNullEnt(FIND_CLIENT_IN_PVS(edict()))) - return FALSE; - - // don't talk if you're in combat - if (m_hEnemy != NULL && FVisible( m_hEnemy )) - return FALSE; - - return TRUE; -} - - -int CTalkMonster::CanPlaySentence( BOOL fDisregardState ) -{ - if ( fDisregardState ) - return CBaseMonster::CanPlaySentence( fDisregardState ); - return FOkToSpeak(); -} - -//========================================================= -// FIdleStare -//========================================================= -int CTalkMonster :: FIdleStare( void ) -{ - if (!FOkToSpeak()) - return FALSE; - - PlaySentence( m_szGrp[TLK_STARE], RANDOM_FLOAT(5, 7.5), VOL_NORM, ATTN_IDLE ); - - m_hTalkTarget = FindNearestFriend( TRUE ); - return TRUE; -} - -//========================================================= -// IdleHello -// Try to greet player first time he's seen -//========================================================= -int CTalkMonster :: FIdleHello( void ) -{ - if (!FOkToSpeak()) - return FALSE; - - // if this is first time scientist has seen player, greet him - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) - { - // get a player - CBaseEntity *pPlayer = FindNearestFriend(TRUE); - - if (pPlayer) - { - if (FInViewCone(pPlayer) && FVisible(pPlayer)) - { - m_hTalkTarget = pPlayer; - - if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) - PlaySentence( m_szGrp[TLK_PHELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); - else - PlaySentence( m_szGrp[TLK_HELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); - - SetBits(m_bitsSaid, bit_saidHelloPlayer); - - return TRUE; - } - } - } - return FALSE; -} - - -// turn head towards supplied origin -void CTalkMonster :: IdleHeadTurn( Vector &vecFriend ) -{ - // turn head in desired direction only if ent has a turnable head - if (m_afCapability & bits_CAP_TURN_HEAD) - { - float yaw = VecToYaw(vecFriend - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } -} - -//========================================================= -// FIdleSpeak -// ask question of nearby friend, or make statement -//========================================================= -int CTalkMonster :: FIdleSpeak ( void ) -{ - // try to start a conversation, or make statement - int pitch; - const char *szIdleGroup; - const char *szQuestionGroup; - float duration; - - if (!FOkToSpeak()) - return FALSE; - - // set idle groups based on pre/post disaster - if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) - { - szIdleGroup = m_szGrp[TLK_PIDLE]; - szQuestionGroup = m_szGrp[TLK_PQUESTION]; - // set global min delay for next conversation - duration = RANDOM_FLOAT(4.8, 5.2); - } - else - { - szIdleGroup = m_szGrp[TLK_IDLE]; - szQuestionGroup = m_szGrp[TLK_QUESTION]; - // set global min delay for next conversation - duration = RANDOM_FLOAT(2.8, 3.2); - - } - - pitch = GetVoicePitch(); - - // player using this entity is alive and wounded? - CBaseEntity *pTarget = m_hTargetEnt; - - if ( pTarget != NULL ) - { - if ( pTarget->IsPlayer() ) - { - if ( pTarget->IsAlive() ) - { - m_hTalkTarget = m_hTargetEnt; - if (!FBitSet(m_bitsSaid, bit_saidDamageHeavy) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 8)) - { - //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT3], 1.0, ATTN_IDLE, 0, pitch); - PlaySentence( m_szGrp[TLK_PLHURT3], duration, VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidDamageHeavy); - return TRUE; - } - else if (!FBitSet(m_bitsSaid, bit_saidDamageMedium) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 4)) - { - //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT2], 1.0, ATTN_IDLE, 0, pitch); - PlaySentence( m_szGrp[TLK_PLHURT2], duration, VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidDamageMedium); - return TRUE; - } - else if (!FBitSet(m_bitsSaid, bit_saidDamageLight) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 2)) - { - //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT1], 1.0, ATTN_IDLE, 0, pitch); - PlaySentence( m_szGrp[TLK_PLHURT1], duration, VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidDamageLight); - return TRUE; - } - } - else - { - //!!!KELLY - here's a cool spot to have the talkmonster talk about the dead player if we want. - // "Oh dear, Gordon Freeman is dead!" -Scientist - // "Damn, I can't do this without you." -Barney - } - } - } - - // if there is a friend nearby to speak to, play sentence, set friend's response time, return - CBaseEntity *pFriend = FindNearestFriend(FALSE); - - if (pFriend && !(pFriend->IsMoving()) && (RANDOM_LONG(0,99) < 75)) - { - PlaySentence( szQuestionGroup, duration, VOL_NORM, ATTN_IDLE ); - //SENTENCEG_PlayRndSz( ENT(pev), szQuestionGroup, 1.0, ATTN_IDLE, 0, pitch ); - - // force friend to answer - CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; - m_hTalkTarget = pFriend; - pTalkMonster->SetAnswerQuestion( this ); // UNDONE: This is EVIL!!! - pTalkMonster->m_flStopTalkTime = m_flStopTalkTime; - - m_nSpeak++; - return TRUE; - } - - // otherwise, play an idle statement, try to face client when making a statement. - if ( RANDOM_LONG(0,1) ) - { - //SENTENCEG_PlayRndSz( ENT(pev), szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); - CBaseEntity *pFriend = FindNearestFriend(TRUE); - - if ( pFriend ) - { - m_hTalkTarget = pFriend; - PlaySentence( szIdleGroup, duration, VOL_NORM, ATTN_IDLE ); - m_nSpeak++; - return TRUE; - } - } - - // didn't speak - Talk( 0 ); - CTalkMonster::g_talkWaitTime = 0; - return FALSE; -} - -void CTalkMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - if ( !bConcurrent ) - ShutUpFriends(); - - ClearConditions( bits_COND_CLIENT_PUSH ); // Forget about moving! I've got something to say! - m_useTime = gpGlobals->time + duration; - PlaySentence( pszSentence, duration, volume, attenuation ); - - m_hTalkTarget = pListener; -} - -void CTalkMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) -{ - if ( !pszSentence ) - return; - - Talk ( duration ); - - CTalkMonster::g_talkWaitTime = gpGlobals->time + duration + 2.0; - if ( pszSentence[0] == '!' ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, GetVoicePitch()); - else - SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, GetVoicePitch() ); - - // If you say anything, don't greet the player - you may have already spoken to them - SetBits(m_bitsSaid, bit_saidHelloPlayer); -} - -//========================================================= -// Talk - set a timer that tells us when the monster is done -// talking. -//========================================================= -void CTalkMonster :: Talk( float flDuration ) -{ - if ( flDuration <= 0 ) - { - // no duration :( - m_flStopTalkTime = gpGlobals->time + 3; - } - else - { - m_flStopTalkTime = gpGlobals->time + flDuration; - } -} - -// Prepare this talking monster to answer question -void CTalkMonster :: SetAnswerQuestion( CTalkMonster *pSpeaker ) -{ - if ( !m_pCine ) - ChangeSchedule( slIdleResponse ); - m_hTalkTarget = (CBaseMonster *)pSpeaker; -} - -int CTalkMonster :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) -{ - if ( IsAlive() ) - { - // if player damaged this entity, have other friends talk about it - if (pevAttacker && m_MonsterState != MONSTERSTATE_PRONE && FBitSet(pevAttacker->flags, FL_CLIENT)) - { - CBaseEntity *pFriend = FindNearestFriend(FALSE); - - if (pFriend && pFriend->IsAlive()) - { - // only if not dead or dying! - CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; - pTalkMonster->ChangeSchedule( slIdleStopShooting ); - } - } - } - return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) -{ - switch( Type ) - { - case SCHED_MOVE_AWAY: - return slMoveAway; - - case SCHED_MOVE_AWAY_FOLLOW: - return slMoveAwayFollow; - - case SCHED_MOVE_AWAY_FAIL: - return slMoveAwayFail; - - case SCHED_TARGET_FACE: - // speak during 'use' - if (RANDOM_LONG(0,99) < 2) - //ALERT ( at_console, "target chase speak\n" ); - return slIdleSpeakWait; - else - return slIdleStand; - - case SCHED_IDLE_STAND: - { - // if never seen player, try to greet him - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) - { - return slIdleHello; - } - - // sustained light wounds? - if (!FBitSet(m_bitsSaid, bit_saidWoundLight) && (pev->health <= (pev->max_health * 0.75))) - { - //SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_WOUND], 1.0, ATTN_IDLE, 0, GetVoicePitch() ); - //CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(2.8, 3.2); - PlaySentence( m_szGrp[TLK_WOUND], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidWoundLight); - return slIdleStand; - } - // sustained heavy wounds? - else if (!FBitSet(m_bitsSaid, bit_saidWoundHeavy) && (pev->health <= (pev->max_health * 0.5))) - { - //SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_MORTAL], 1.0, ATTN_IDLE, 0, GetVoicePitch() ); - //CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(2.8, 3.2); - PlaySentence( m_szGrp[TLK_MORTAL], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidWoundHeavy); - return slIdleStand; - } - - // talk about world - if (FOkToSpeak() && RANDOM_LONG(0,m_nSpeak * 2) == 0) - { - //ALERT ( at_console, "standing idle speak\n" ); - return slIdleSpeak; - } - - if ( !IsTalking() && HasConditions ( bits_COND_SEE_CLIENT ) && RANDOM_LONG( 0, 6 ) == 0 ) - { - edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - if ( pPlayer ) - { - // watch the client. - UTIL_MakeVectors ( pPlayer->v.angles ); - if ( ( pPlayer->v.origin - pev->origin ).Length2D() < TLK_STARE_DIST && - UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) >= m_flFieldOfView ) - { - // go into the special STARE schedule if the player is close, and looking at me too. - return &slTlkIdleWatchClient[ 1 ]; - } - - return slTlkIdleWatchClient; - } - } - else - { - if (IsTalking()) - // look at who we're talking to - return slTlkIdleEyecontact; - else - // regular standing idle - return slIdleStand; - } - - - // NOTE - caller must first CTalkMonster::GetScheduleOfType, - // then check result and decide what to return ie: if sci gets back - // slIdleStand, return slIdleSciStand - } - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// IsTalking - am I saying a sentence right now? -//========================================================= -BOOL CTalkMonster :: IsTalking( void ) -{ - if ( m_flStopTalkTime > gpGlobals->time ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// If there's a player around, watch him. -//========================================================= -void CTalkMonster :: PrescheduleThink ( void ) -{ - if ( !HasConditions ( bits_COND_SEE_CLIENT ) ) - { - SetConditions ( bits_COND_CLIENT_UNSEEN ); - } -} - -// try to smell something -void CTalkMonster :: TrySmellTalk( void ) -{ - if ( !FOkToSpeak() ) - return; - - // clear smell bits periodically - if ( gpGlobals->time > m_flLastSaidSmelled ) - { -// ALERT ( at_aiconsole, "Clear smell bits\n" ); - ClearBits(m_bitsSaid, bit_saidSmelled); - } - // smelled something? - if (!FBitSet(m_bitsSaid, bit_saidSmelled) && HasConditions ( bits_COND_SMELL )) - { - PlaySentence( m_szGrp[TLK_SMELL], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - m_flLastSaidSmelled = gpGlobals->time + 60;// don't talk about the stinky for a while. - SetBits(m_bitsSaid, bit_saidSmelled); - } -} - - - -int CTalkMonster::IRelationship( CBaseEntity *pTarget ) -{ - if ( pTarget->IsPlayer() ) - if ( m_afMemory & bits_MEMORY_PROVOKED ) - return R_HT; - return CBaseMonster::IRelationship( pTarget ); -} - - -void CTalkMonster::StopFollowing( BOOL clearSchedule ) -{ - if ( IsFollowing() ) - { - if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) - { - PlaySentence( m_szGrp[TLK_UNUSE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - m_hTalkTarget = m_hTargetEnt; - } - - if ( m_movementGoal == MOVEGOAL_TARGETENT ) - RouteClear(); // Stop him from walking toward the player - m_hTargetEnt = NULL; - if ( clearSchedule ) - ClearSchedule(); - if ( m_hEnemy != NULL ) - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } -} - - -void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) -{ - if ( m_pCine ) - m_pCine->CancelScript(); - - if ( m_hEnemy != NULL ) - m_IdealMonsterState = MONSTERSTATE_ALERT; - - m_hTargetEnt = pLeader; - PlaySentence( m_szGrp[TLK_USE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - m_hTalkTarget = m_hTargetEnt; - ClearConditions( bits_COND_CLIENT_PUSH ); - ClearSchedule(); -} - - -BOOL CTalkMonster::CanFollow( void ) -{ - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - if ( !m_pCine->CanInterrupt() ) - return FALSE; - } - - if ( !IsAlive() ) - return FALSE; - - return !IsFollowing(); -} - - -void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Don't allow use during a scripted_sentence - if ( m_useTime > gpGlobals->time ) - return; - - if ( pCaller != NULL && pCaller->IsPlayer() ) - { - // Pre-disaster followers can't be used - if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) - { - DeclineFollowing(); - } - else if ( CanFollow() ) - { - LimitFollowers( pCaller , 1 ); - - if ( m_afMemory & bits_MEMORY_PROVOKED ) - ALERT( at_console, "I'm not following you, you evil person!\n" ); - else - { - StartFollowing( pCaller ); - SetBits(m_bitsSaid, bit_saidHelloPlayer); // Don't say hi after you've started following - } - } - else - { - StopFollowing( TRUE ); - } - } -} - -void CTalkMonster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "UseSentence")) - { - m_iszUse = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "UnUseSentence")) - { - m_iszUnUse = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CTalkMonster::Precache( void ) -{ - if ( m_iszUse ) - m_szGrp[TLK_USE] = STRING( m_iszUse ); - if ( m_iszUnUse ) - m_szGrp[TLK_UNUSE] = STRING( m_iszUnUse ); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" +#include "talkmonster.h" +#include "defaultai.h" +#include "scripted.h" +#include "soundent.h" +#include "animation.h" + +//========================================================= +// Talking monster base class +// Used for scientists and barneys +//========================================================= +float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once + +// Allow assignment within conditional +#pragma warning (disable: 4706) + +// NOTE: m_voicePitch & m_szGrp should be fixed up by precache each save/restore + +TYPEDESCRIPTION CTalkMonster::m_SaveData[] = +{ + DEFINE_FIELD( CTalkMonster, m_bitsSaid, FIELD_INTEGER ), + DEFINE_FIELD( CTalkMonster, m_nSpeak, FIELD_INTEGER ), + + // Recalc'ed in Precache() + // DEFINE_FIELD( CTalkMonster, m_voicePitch, FIELD_INTEGER ), + // DEFINE_FIELD( CTalkMonster, m_szGrp, FIELD_??? ), + DEFINE_FIELD( CTalkMonster, m_useTime, FIELD_TIME ), + DEFINE_FIELD( CTalkMonster, m_iszUse, FIELD_STRING ), + DEFINE_FIELD( CTalkMonster, m_iszUnUse, FIELD_STRING ), + DEFINE_FIELD( CTalkMonster, m_flLastSaidSmelled, FIELD_TIME ), + DEFINE_FIELD( CTalkMonster, m_flStopTalkTime, FIELD_TIME ), + DEFINE_FIELD( CTalkMonster, m_hTalkTarget, FIELD_EHANDLE ), +}; + +IMPLEMENT_SAVERESTORE( CTalkMonster, CBaseMonster ); + +// array of friend names +char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = +{ + "monster_barney", + "monster_scientist", + "monster_sitting_scientist", +}; + + +//========================================================= +// AI Schedules Specific to talking monsters +//========================================================= + +Task_t tlIdleResponse[] = +{ + { TASK_SET_ACTIVITY, (float)ACT_IDLE },// Stop and listen + { TASK_WAIT, (float)0.5 },// Wait until sure it's me they are talking to + { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done + { TASK_TLK_RESPOND, (float)0 },// Wait and then say my response + { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to + { TASK_FACE_IDEAL, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, + { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done +}; + +Schedule_t slIdleResponse[] = +{ + { + tlIdleResponse, + ARRAYSIZE ( tlIdleResponse ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "Idle Response" + + }, +}; + +Task_t tlIdleSpeak[] = +{ + { TASK_TLK_SPEAK, (float)0 },// question or remark + { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to + { TASK_FACE_IDEAL, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, + { TASK_TLK_EYECONTACT, (float)0 }, + { TASK_WAIT_RANDOM, (float)0.5 }, +}; + +Schedule_t slIdleSpeak[] = +{ + { + tlIdleSpeak, + ARRAYSIZE ( tlIdleSpeak ), + bits_COND_NEW_ENEMY | + bits_COND_CLIENT_PUSH | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "Idle Speak" + }, +}; + +Task_t tlIdleSpeakWait[] = +{ + { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 },// Stop and talk + { TASK_TLK_SPEAK, (float)0 },// question or remark + { TASK_TLK_EYECONTACT, (float)0 },// + { TASK_WAIT, (float)2 },// wait - used when sci is in 'use' mode to keep head turned +}; + +Schedule_t slIdleSpeakWait[] = +{ + { + tlIdleSpeakWait, + ARRAYSIZE ( tlIdleSpeakWait ), + bits_COND_NEW_ENEMY | + bits_COND_CLIENT_PUSH | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "Idle Speak Wait" + }, +}; + +Task_t tlIdleHello[] = +{ + { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 },// Stop and talk + { TASK_TLK_HELLO, (float)0 },// Try to say hello to player + { TASK_TLK_EYECONTACT, (float)0 }, + { TASK_WAIT, (float)0.5 },// wait a bit + { TASK_TLK_HELLO, (float)0 },// Try to say hello to player + { TASK_TLK_EYECONTACT, (float)0 }, + { TASK_WAIT, (float)0.5 },// wait a bit + { TASK_TLK_HELLO, (float)0 },// Try to say hello to player + { TASK_TLK_EYECONTACT, (float)0 }, + { TASK_WAIT, (float)0.5 },// wait a bit + { TASK_TLK_HELLO, (float)0 },// Try to say hello to player + { TASK_TLK_EYECONTACT, (float)0 }, + { TASK_WAIT, (float)0.5 },// wait a bit + +}; + +Schedule_t slIdleHello[] = +{ + { + tlIdleHello, + ARRAYSIZE ( tlIdleHello ), + bits_COND_NEW_ENEMY | + bits_COND_CLIENT_PUSH | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT, + "Idle Hello" + }, +}; + +Task_t tlIdleStopShooting[] = +{ + { TASK_TLK_STOPSHOOTING, (float)0 },// tell player to stop shooting friend + // { TASK_TLK_EYECONTACT, (float)0 },// look at the player +}; + +Schedule_t slIdleStopShooting[] = +{ + { + tlIdleStopShooting, + ARRAYSIZE ( tlIdleStopShooting ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND, + 0, + "Idle Stop Shooting" + }, +}; + +Task_t tlMoveAway[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MOVE_AWAY_FAIL }, + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_MOVE_AWAY_PATH, (float)100 }, + { TASK_WALK_PATH_FOR_UNITS, (float)100 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_PLAYER, (float)0.5 }, +}; + +Schedule_t slMoveAway[] = +{ + { + tlMoveAway, + ARRAYSIZE ( tlMoveAway ), + 0, + 0, + "MoveAway" + }, +}; + + +Task_t tlMoveAwayFail[] = +{ + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_PLAYER, (float)0.5 }, +}; + +Schedule_t slMoveAwayFail[] = +{ + { + tlMoveAwayFail, + ARRAYSIZE ( tlMoveAwayFail ), + 0, + 0, + "MoveAwayFail" + }, +}; + + + +Task_t tlMoveAwayFollow[] = +{ + { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_FACE }, + { TASK_STORE_LASTPOSITION, (float)0 }, + { TASK_MOVE_AWAY_PATH, (float)100 }, + { TASK_WALK_PATH_FOR_UNITS, (float)100 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, +}; + +Schedule_t slMoveAwayFollow[] = +{ + { + tlMoveAwayFollow, + ARRAYSIZE ( tlMoveAwayFollow ), + 0, + 0, + "MoveAwayFollow" + }, +}; + +Task_t tlTlkIdleWatchClient[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_TLK_LOOK_AT_CLIENT, (float)6 }, +}; + +Task_t tlTlkIdleWatchClientStare[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_TLK_CLIENT_STARE, (float)6 }, + { TASK_TLK_STARE, (float)0 }, + { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to + { TASK_FACE_IDEAL, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, + { TASK_TLK_EYECONTACT, (float)0 }, +}; + +Schedule_t slTlkIdleWatchClient[] = +{ + { + tlTlkIdleWatchClient, + ARRAYSIZE ( tlTlkIdleWatchClient ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_SMELL | + bits_COND_CLIENT_PUSH | + bits_COND_CLIENT_UNSEEN | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. + //bits_SOUND_PLAYER | + //bits_SOUND_WORLD | + + bits_SOUND_DANGER | + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "TlkIdleWatchClient" + }, + + { + tlTlkIdleWatchClientStare, + ARRAYSIZE ( tlTlkIdleWatchClientStare ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_HEAR_SOUND | + bits_COND_SMELL | + bits_COND_CLIENT_PUSH | + bits_COND_CLIENT_UNSEEN | + bits_COND_PROVOKED, + + bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. + //bits_SOUND_PLAYER | + //bits_SOUND_WORLD | + + bits_SOUND_DANGER | + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | + bits_SOUND_GARBAGE, + "TlkIdleWatchClientStare" + }, +}; + + +Task_t tlTlkIdleEyecontact[] = +{ + { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to + { TASK_FACE_IDEAL, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, + { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done +}; + +Schedule_t slTlkIdleEyecontact[] = +{ + { + tlTlkIdleEyecontact, + ARRAYSIZE ( tlTlkIdleEyecontact ), + bits_COND_NEW_ENEMY | + bits_COND_CLIENT_PUSH | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE, + 0, + "TlkIdleEyecontact" + }, +}; + + +DEFINE_CUSTOM_SCHEDULES( CTalkMonster ) +{ + slIdleResponse, + slIdleSpeak, + slIdleHello, + slIdleSpeakWait, + slIdleStopShooting, + slMoveAway, + slMoveAwayFollow, + slMoveAwayFail, + slTlkIdleWatchClient, + &slTlkIdleWatchClient[ 1 ], + slTlkIdleEyecontact, +}; + +IMPLEMENT_CUSTOM_SCHEDULES( CTalkMonster, CBaseMonster ); + + +void CTalkMonster :: SetActivity ( Activity newActivity ) +{ + if (newActivity == ACT_IDLE && IsTalking() ) + newActivity = ACT_SIGNAL3; + + if ( newActivity == ACT_SIGNAL3 && (LookupActivity ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE)) + newActivity = ACT_IDLE; + + CBaseMonster::SetActivity( newActivity ); +} + + +void CTalkMonster :: StartTask( Task_t *pTask ) +{ + switch ( pTask->iTask ) + { + case TASK_TLK_SPEAK: + // ask question or make statement + FIdleSpeak(); + TaskComplete(); + break; + + case TASK_TLK_RESPOND: + // respond to question + IdleRespond(); + TaskComplete(); + break; + + case TASK_TLK_HELLO: + // greet player + FIdleHello(); + TaskComplete(); + break; + + + case TASK_TLK_STARE: + // let the player know I know he's staring at me. + FIdleStare(); + TaskComplete(); + break; + + case TASK_FACE_PLAYER: + case TASK_TLK_LOOK_AT_CLIENT: + case TASK_TLK_CLIENT_STARE: + // track head to the client for a while. + m_flWaitFinished = gpGlobals->time + pTask->flData; + break; + + case TASK_TLK_EYECONTACT: + break; + + case TASK_TLK_IDEALYAW: + if (m_hTalkTarget != NULL) + { + pev->yaw_speed = 60; + float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; + + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + + if (yaw < 0) + { + pev->ideal_yaw = min( yaw + 45, 0 ) + pev->angles.y; + } + else + { + pev->ideal_yaw = max( yaw - 45, 0 ) + pev->angles.y; + } + } + TaskComplete(); + break; + + case TASK_TLK_HEADRESET: + // reset head position after looking at something + m_hTalkTarget = NULL; + TaskComplete(); + break; + + case TASK_TLK_STOPSHOOTING: + // tell player to stop shooting + PlaySentence( m_szGrp[TLK_NOSHOOT], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_NORM ); + TaskComplete(); + break; + + case TASK_CANT_FOLLOW: + StopFollowing( FALSE ); + PlaySentence( m_szGrp[TLK_STOP], RANDOM_FLOAT(2, 2.5), VOL_NORM, ATTN_NORM ); + TaskComplete(); + break; + + case TASK_WALK_PATH_FOR_UNITS: + m_movementActivity = ACT_WALK; + break; + + case TASK_MOVE_AWAY_PATH: + { + Vector dir = pev->angles; + dir.y = pev->ideal_yaw + 180; + Vector move; + + UTIL_MakeVectorsPrivate( dir, move, NULL, NULL ); + dir = pev->origin + move * pTask->flData; + if ( MoveToLocation( ACT_WALK, 2, dir ) ) + { + TaskComplete(); + } + else if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + 2; + TaskComplete(); + } + else + { + // nowhere to go? + TaskFail(); + } + } + break; + + case TASK_PLAY_SCRIPT: + m_hTalkTarget = NULL; + CBaseMonster::StartTask( pTask ); + break; + + default: + CBaseMonster::StartTask( pTask ); + } +} + + +void CTalkMonster :: RunTask( Task_t *pTask ) +{ + switch( pTask->iTask ) + { + case TASK_TLK_CLIENT_STARE: + case TASK_TLK_LOOK_AT_CLIENT: + + edict_t *pPlayer; + + // track head to the client for a while. + if ( m_MonsterState == MONSTERSTATE_IDLE && + !IsMoving() && + !IsTalking() ) + { + // Get edict for one player + pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + + if ( pPlayer ) + { + IdleHeadTurn( pPlayer->v.origin ); + } + } + else + { + // started moving or talking + TaskFail(); + return; + } + + if ( pTask->iTask == TASK_TLK_CLIENT_STARE ) + { + // fail out if the player looks away or moves away. + if ( ( pPlayer->v.origin - pev->origin ).Length2D() > TLK_STARE_DIST ) + { + // player moved away. + TaskFail(); + } + + UTIL_MakeVectors( pPlayer->v.angles ); + if ( UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) < m_flFieldOfView ) + { + // player looked away + TaskFail(); + } + } + + if ( gpGlobals->time > m_flWaitFinished ) + { + TaskComplete(); + } + break; + + case TASK_FACE_PLAYER: + { + // Get edict for one player + edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + + if ( pPlayer ) + { + MakeIdealYaw ( pPlayer->v.origin ); + ChangeYaw ( pev->yaw_speed ); + IdleHeadTurn( pPlayer->v.origin ); + if ( gpGlobals->time > m_flWaitFinished && FlYawDiff() < 10 ) + { + TaskComplete(); + } + } + else + { + TaskFail(); + } + } + break; + + case TASK_TLK_EYECONTACT: + if (!IsMoving() && IsTalking() && m_hTalkTarget != NULL) + { + // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); + IdleHeadTurn( m_hTalkTarget->pev->origin ); + } + else + { + TaskComplete(); + } + break; + + case TASK_WALK_PATH_FOR_UNITS: + { + float distance; + + distance = (m_vecLastPosition - pev->origin).Length2D(); + + // Walk path until far enough away + if ( distance > pTask->flData || MovementIsComplete() ) + { + TaskComplete(); + RouteClear(); // Stop moving + } + } + break; + case TASK_WAIT_FOR_MOVEMENT: + if (IsTalking() && m_hTalkTarget != NULL) + { + // ALERT(at_console, "walking, talking\n"); + IdleHeadTurn( m_hTalkTarget->pev->origin ); + } + else + { + IdleHeadTurn( pev->origin ); + // override so that during walk, a scientist may talk and greet player + FIdleHello(); + if (RANDOM_LONG(0,m_nSpeak * 20) == 0) + { + FIdleSpeak(); + } + } + + CBaseMonster::RunTask( pTask ); + if (TaskIsComplete()) + IdleHeadTurn( pev->origin ); + break; + + default: + if (IsTalking() && m_hTalkTarget != NULL) + { + IdleHeadTurn( m_hTalkTarget->pev->origin ); + } + else + { + SetBoneController( 0, 0 ); + } + CBaseMonster::RunTask( pTask ); + } +} + + +void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) +{ + // If a client killed me (unless I was already Barnacle'd), make everyone else mad/afraid of him + if ( (pevAttacker->flags & FL_CLIENT) && m_MonsterState != MONSTERSTATE_PRONE ) + { + AlertFriends(); + LimitFollowers( CBaseEntity::Instance(pevAttacker), 0 ); + } + + m_hTargetEnt = NULL; + // Don't finish that sentence + StopTalking(); + SetUse( NULL ); + CBaseMonster::Killed( pevAttacker, iGib ); +} + + + +CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) +{ + CBaseEntity *pFriend = pPrevious; + char *pszFriend; + TraceResult tr; + Vector vecCheck; + + pszFriend = m_szFriends[ FriendNumber(listNumber) ]; + while (pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend )) + { + if (pFriend == this || !pFriend->IsAlive()) + // don't talk to self or dead people + continue; + if ( bTrace ) + { + vecCheck = pFriend->pev->origin; + vecCheck.z = pFriend->pev->absmax.z; + + UTIL_TraceLine( pev->origin, vecCheck, ignore_monsters, ENT(pev), &tr); + } + else + tr.flFraction = 1.0; + + if (tr.flFraction == 1.0) + { + return pFriend; + } + } + + return NULL; +} + + +void CTalkMonster::AlertFriends( void ) +{ + CBaseEntity *pFriend = NULL; + int i; + + // for each friend in this bsp... + for ( i = 0; i < TLK_CFRIENDS; i++ ) + { + while (pFriend = EnumFriends( pFriend, i, TRUE )) + { + CBaseMonster *pMonster = pFriend->MyMonsterPointer(); + if ( pMonster->IsAlive() ) + { + // don't provoke a friend that's playing a death animation. They're a goner + pMonster->m_afMemory |= bits_MEMORY_PROVOKED; + } + } + } +} + + + +void CTalkMonster::ShutUpFriends( void ) +{ + CBaseEntity *pFriend = NULL; + int i; + + // for each friend in this bsp... + for ( i = 0; i < TLK_CFRIENDS; i++ ) + { + while (pFriend = EnumFriends( pFriend, i, TRUE )) + { + CBaseMonster *pMonster = pFriend->MyMonsterPointer(); + if ( pMonster ) + { + pMonster->SentenceStop(); + } + } + } +} + + +// UNDONE: Keep a follow time in each follower, make a list of followers in this function and do LRU +// UNDONE: Check this in Restore to keep restored monsters from joining a full list of followers +void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) +{ + CBaseEntity *pFriend = NULL; + int i, count; + + count = 0; + // for each friend in this bsp... + for ( i = 0; i < TLK_CFRIENDS; i++ ) + { + while (pFriend = EnumFriends( pFriend, i, FALSE )) + { + CBaseMonster *pMonster = pFriend->MyMonsterPointer(); + if ( pMonster ) + { + if ( pMonster->m_hTargetEnt == pPlayer ) + { + count++; + if ( count > maxFollowers ) + pMonster->StopFollowing( TRUE ); + } + } + } + } +} + + +float CTalkMonster::TargetDistance( void ) +{ + // If we lose the player, or he dies, return a really large distance + if ( m_hTargetEnt == NULL || !m_hTargetEnt->IsAlive() ) + return 1e6; + + return (m_hTargetEnt->pev->origin - pev->origin).Length(); +} + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CTalkMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case SCRIPT_EVENT_SENTENCE_RND1: // Play a named sentence group 25% of the time + if (RANDOM_LONG(0,99) < 75) + break; + // fall through... + case SCRIPT_EVENT_SENTENCE: // Play a named sentence group + ShutUpFriends(); + PlaySentence( pEvent->options, RANDOM_FLOAT(2.8, 3.4), VOL_NORM, ATTN_IDLE ); + //ALERT(at_console, "script event speak\n"); + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +// monsters derived from ctalkmonster should call this in precache() + +void CTalkMonster :: TalkInit( void ) +{ + // every new talking monster must reset this global, otherwise + // when a level is loaded, nobody will talk (time is reset to 0) + + CTalkMonster::g_talkWaitTime = 0; + + m_voicePitch = 100; +} +//========================================================= +// FindNearestFriend +// Scan for nearest, visible friend. If fPlayer is true, look for +// nearest player +//========================================================= +CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) +{ + CBaseEntity *pFriend = NULL; + CBaseEntity *pNearest = NULL; + float range = 10000000.0; + TraceResult tr; + Vector vecStart = pev->origin; + Vector vecCheck; + int i; + char *pszFriend; + int cfriends; + + vecStart.z = pev->absmax.z; + + if (fPlayer) + cfriends = 1; + else + cfriends = TLK_CFRIENDS; + + // for each type of friend... + + for (i = cfriends-1; i > -1; i--) + { + if (fPlayer) + pszFriend = "player"; + else + pszFriend = m_szFriends[FriendNumber(i)]; + + if (!pszFriend) + continue; + + // for each friend in this bsp... + while (pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend )) + { + if (pFriend == this || !pFriend->IsAlive()) + // don't talk to self or dead people + continue; + + CBaseMonster *pMonster = pFriend->MyMonsterPointer(); + + // If not a monster for some reason, or in a script, or prone + if ( !pMonster || pMonster->m_MonsterState == MONSTERSTATE_SCRIPT || pMonster->m_MonsterState == MONSTERSTATE_PRONE ) + continue; + + vecCheck = pFriend->pev->origin; + vecCheck.z = pFriend->pev->absmax.z; + + // if closer than previous friend, and in range, see if he's visible + + if (range > (vecStart - vecCheck).Length()) + { + UTIL_TraceLine(vecStart, vecCheck, ignore_monsters, ENT(pev), &tr); + + if (tr.flFraction == 1.0) + { + // visible and in range, this is the new nearest scientist + if ((vecStart - vecCheck).Length() < TALKRANGE_MIN) + { + pNearest = pFriend; + range = (vecStart - vecCheck).Length(); + } + } + } + } + } + return pNearest; +} + +int CTalkMonster :: GetVoicePitch( void ) +{ + return m_voicePitch + RANDOM_LONG(0,3); +} + + +void CTalkMonster :: Touch( CBaseEntity *pOther ) +{ + // Did the player touch me? + if ( pOther->IsPlayer() ) + { + // Ignore if pissed at player + if ( m_afMemory & bits_MEMORY_PROVOKED ) + return; + + // Stay put during speech + if ( IsTalking() ) + return; + + // Heuristic for determining if the player is pushing me away + float speed = fabs(pOther->pev->velocity.x) + fabs(pOther->pev->velocity.y); + if ( speed > 50 ) + { + SetConditions( bits_COND_CLIENT_PUSH ); + MakeIdealYaw( pOther->pev->origin ); + } + } +} + + + +//========================================================= +// IdleRespond +// Respond to a previous question +//========================================================= +void CTalkMonster :: IdleRespond( void ) +{ + int pitch = GetVoicePitch(); + + // play response + PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); +} + +int CTalkMonster :: FOkToSpeak( void ) +{ + // if in the grip of a barnacle, don't speak + if ( m_MonsterState == MONSTERSTATE_PRONE || m_IdealMonsterState == MONSTERSTATE_PRONE ) + { + return FALSE; + } + + // if not alive, certainly don't speak + if ( pev->deadflag != DEAD_NO ) + { + return FALSE; + } + + // if someone else is talking, don't speak + if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) + return FALSE; + + if ( pev->spawnflags & SF_MONSTER_GAG ) + return FALSE; + + if ( m_MonsterState == MONSTERSTATE_PRONE ) + return FALSE; + + // if player is not in pvs, don't speak + if (!IsAlive() || FNullEnt(FIND_CLIENT_IN_PVS(edict()))) + return FALSE; + + // don't talk if you're in combat + if (m_hEnemy != NULL && FVisible( m_hEnemy )) + return FALSE; + + return TRUE; +} + + +int CTalkMonster::CanPlaySentence( BOOL fDisregardState ) +{ + if ( fDisregardState ) + return CBaseMonster::CanPlaySentence( fDisregardState ); + return FOkToSpeak(); +} + +//========================================================= +// FIdleStare +//========================================================= +int CTalkMonster :: FIdleStare( void ) +{ + if (!FOkToSpeak()) + return FALSE; + + PlaySentence( m_szGrp[TLK_STARE], RANDOM_FLOAT(5, 7.5), VOL_NORM, ATTN_IDLE ); + + m_hTalkTarget = FindNearestFriend( TRUE ); + return TRUE; +} + +//========================================================= +// IdleHello +// Try to greet player first time he's seen +//========================================================= +int CTalkMonster :: FIdleHello( void ) +{ + if (!FOkToSpeak()) + return FALSE; + + // if this is first time scientist has seen player, greet him + if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) + { + // get a player + CBaseEntity *pPlayer = FindNearestFriend(TRUE); + + if (pPlayer) + { + if (FInViewCone(pPlayer) && FVisible(pPlayer)) + { + m_hTalkTarget = pPlayer; + + if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) + PlaySentence( m_szGrp[TLK_PHELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); + else + PlaySentence( m_szGrp[TLK_HELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); + + SetBits(m_bitsSaid, bit_saidHelloPlayer); + + return TRUE; + } + } + } + return FALSE; +} + + +// turn head towards supplied origin +void CTalkMonster :: IdleHeadTurn( Vector &vecFriend ) +{ + // turn head in desired direction only if ent has a turnable head + if (m_afCapability & bits_CAP_TURN_HEAD) + { + float yaw = VecToYaw(vecFriend - pev->origin) - pev->angles.y; + + if (yaw > 180) yaw -= 360; + if (yaw < -180) yaw += 360; + + // turn towards vector + SetBoneController( 0, yaw ); + } +} + +//========================================================= +// FIdleSpeak +// ask question of nearby friend, or make statement +//========================================================= +int CTalkMonster :: FIdleSpeak ( void ) +{ + // try to start a conversation, or make statement + int pitch; + const char *szIdleGroup; + const char *szQuestionGroup; + float duration; + + if (!FOkToSpeak()) + return FALSE; + + // set idle groups based on pre/post disaster + if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) + { + szIdleGroup = m_szGrp[TLK_PIDLE]; + szQuestionGroup = m_szGrp[TLK_PQUESTION]; + // set global min delay for next conversation + duration = RANDOM_FLOAT(4.8, 5.2); + } + else + { + szIdleGroup = m_szGrp[TLK_IDLE]; + szQuestionGroup = m_szGrp[TLK_QUESTION]; + // set global min delay for next conversation + duration = RANDOM_FLOAT(2.8, 3.2); + + } + + pitch = GetVoicePitch(); + + // player using this entity is alive and wounded? + CBaseEntity *pTarget = m_hTargetEnt; + + if ( pTarget != NULL ) + { + if ( pTarget->IsPlayer() ) + { + if ( pTarget->IsAlive() ) + { + m_hTalkTarget = m_hTargetEnt; + if (!FBitSet(m_bitsSaid, bit_saidDamageHeavy) && + (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 8)) + { + //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT3], 1.0, ATTN_IDLE, 0, pitch); + PlaySentence( m_szGrp[TLK_PLHURT3], duration, VOL_NORM, ATTN_IDLE ); + SetBits(m_bitsSaid, bit_saidDamageHeavy); + return TRUE; + } + else if (!FBitSet(m_bitsSaid, bit_saidDamageMedium) && + (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 4)) + { + //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT2], 1.0, ATTN_IDLE, 0, pitch); + PlaySentence( m_szGrp[TLK_PLHURT2], duration, VOL_NORM, ATTN_IDLE ); + SetBits(m_bitsSaid, bit_saidDamageMedium); + return TRUE; + } + else if (!FBitSet(m_bitsSaid, bit_saidDamageLight) && + (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 2)) + { + //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT1], 1.0, ATTN_IDLE, 0, pitch); + PlaySentence( m_szGrp[TLK_PLHURT1], duration, VOL_NORM, ATTN_IDLE ); + SetBits(m_bitsSaid, bit_saidDamageLight); + return TRUE; + } + } + else + { + //!!!KELLY - here's a cool spot to have the talkmonster talk about the dead player if we want. + // "Oh dear, Gordon Freeman is dead!" -Scientist + // "Damn, I can't do this without you." -Barney + } + } + } + + // if there is a friend nearby to speak to, play sentence, set friend's response time, return + CBaseEntity *pFriend = FindNearestFriend(FALSE); + + if (pFriend && !(pFriend->IsMoving()) && (RANDOM_LONG(0,99) < 75)) + { + PlaySentence( szQuestionGroup, duration, VOL_NORM, ATTN_IDLE ); + //SENTENCEG_PlayRndSz( ENT(pev), szQuestionGroup, 1.0, ATTN_IDLE, 0, pitch ); + + // force friend to answer + CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; + m_hTalkTarget = pFriend; + pTalkMonster->SetAnswerQuestion( this ); // UNDONE: This is EVIL!!! + pTalkMonster->m_flStopTalkTime = m_flStopTalkTime; + + m_nSpeak++; + return TRUE; + } + + // otherwise, play an idle statement, try to face client when making a statement. + if ( RANDOM_LONG(0,1) ) + { + //SENTENCEG_PlayRndSz( ENT(pev), szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); + CBaseEntity *pFriend = FindNearestFriend(TRUE); + + if ( pFriend ) + { + m_hTalkTarget = pFriend; + PlaySentence( szIdleGroup, duration, VOL_NORM, ATTN_IDLE ); + m_nSpeak++; + return TRUE; + } + } + + // didn't speak + Talk( 0 ); + CTalkMonster::g_talkWaitTime = 0; + return FALSE; +} + +void CTalkMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) +{ + if ( !bConcurrent ) + ShutUpFriends(); + + ClearConditions( bits_COND_CLIENT_PUSH ); // Forget about moving! I've got something to say! + m_useTime = gpGlobals->time + duration; + PlaySentence( pszSentence, duration, volume, attenuation ); + + m_hTalkTarget = pListener; +} + +void CTalkMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) +{ + if ( !pszSentence ) + return; + + Talk ( duration ); + + CTalkMonster::g_talkWaitTime = gpGlobals->time + duration + 2.0; + if ( pszSentence[0] == '!' ) + EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, GetVoicePitch()); + else + SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, GetVoicePitch() ); + + // If you say anything, don't greet the player - you may have already spoken to them + SetBits(m_bitsSaid, bit_saidHelloPlayer); +} + +//========================================================= +// Talk - set a timer that tells us when the monster is done +// talking. +//========================================================= +void CTalkMonster :: Talk( float flDuration ) +{ + if ( flDuration <= 0 ) + { + // no duration :( + m_flStopTalkTime = gpGlobals->time + 3; + } + else + { + m_flStopTalkTime = gpGlobals->time + flDuration; + } +} + +// Prepare this talking monster to answer question +void CTalkMonster :: SetAnswerQuestion( CTalkMonster *pSpeaker ) +{ + if ( !m_pCine ) + ChangeSchedule( slIdleResponse ); + m_hTalkTarget = (CBaseMonster *)pSpeaker; +} + +int CTalkMonster :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +{ + if ( IsAlive() ) + { + // if player damaged this entity, have other friends talk about it + if (pevAttacker && m_MonsterState != MONSTERSTATE_PRONE && FBitSet(pevAttacker->flags, FL_CLIENT)) + { + CBaseEntity *pFriend = FindNearestFriend(FALSE); + + if (pFriend && pFriend->IsAlive()) + { + // only if not dead or dying! + CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; + pTalkMonster->ChangeSchedule( slIdleStopShooting ); + } + } + } + return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); +} + + +Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) +{ + switch( Type ) + { + case SCHED_MOVE_AWAY: + return slMoveAway; + + case SCHED_MOVE_AWAY_FOLLOW: + return slMoveAwayFollow; + + case SCHED_MOVE_AWAY_FAIL: + return slMoveAwayFail; + + case SCHED_TARGET_FACE: + // speak during 'use' + if (RANDOM_LONG(0,99) < 2) + //ALERT ( at_console, "target chase speak\n" ); + return slIdleSpeakWait; + else + return slIdleStand; + + case SCHED_IDLE_STAND: + { + // if never seen player, try to greet him + if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) + { + return slIdleHello; + } + + // sustained light wounds? + if (!FBitSet(m_bitsSaid, bit_saidWoundLight) && (pev->health <= (pev->max_health * 0.75))) + { + //SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_WOUND], 1.0, ATTN_IDLE, 0, GetVoicePitch() ); + //CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(2.8, 3.2); + PlaySentence( m_szGrp[TLK_WOUND], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + SetBits(m_bitsSaid, bit_saidWoundLight); + return slIdleStand; + } + // sustained heavy wounds? + else if (!FBitSet(m_bitsSaid, bit_saidWoundHeavy) && (pev->health <= (pev->max_health * 0.5))) + { + //SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_MORTAL], 1.0, ATTN_IDLE, 0, GetVoicePitch() ); + //CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(2.8, 3.2); + PlaySentence( m_szGrp[TLK_MORTAL], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + SetBits(m_bitsSaid, bit_saidWoundHeavy); + return slIdleStand; + } + + // talk about world + if (FOkToSpeak() && RANDOM_LONG(0,m_nSpeak * 2) == 0) + { + //ALERT ( at_console, "standing idle speak\n" ); + return slIdleSpeak; + } + + if ( !IsTalking() && HasConditions ( bits_COND_SEE_CLIENT ) && RANDOM_LONG( 0, 6 ) == 0 ) + { + edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + + if ( pPlayer ) + { + // watch the client. + UTIL_MakeVectors ( pPlayer->v.angles ); + if ( ( pPlayer->v.origin - pev->origin ).Length2D() < TLK_STARE_DIST && + UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) >= m_flFieldOfView ) + { + // go into the special STARE schedule if the player is close, and looking at me too. + return &slTlkIdleWatchClient[ 1 ]; + } + + return slTlkIdleWatchClient; + } + } + else + { + if (IsTalking()) + // look at who we're talking to + return slTlkIdleEyecontact; + else + // regular standing idle + return slIdleStand; + } + + + // NOTE - caller must first CTalkMonster::GetScheduleOfType, + // then check result and decide what to return ie: if sci gets back + // slIdleStand, return slIdleSciStand + } + break; + } + + return CBaseMonster::GetScheduleOfType( Type ); +} + +//========================================================= +// IsTalking - am I saying a sentence right now? +//========================================================= +BOOL CTalkMonster :: IsTalking( void ) +{ + if ( m_flStopTalkTime > gpGlobals->time ) + { + return TRUE; + } + + return FALSE; +} + +//========================================================= +// If there's a player around, watch him. +//========================================================= +void CTalkMonster :: PrescheduleThink ( void ) +{ + if ( !HasConditions ( bits_COND_SEE_CLIENT ) ) + { + SetConditions ( bits_COND_CLIENT_UNSEEN ); + } +} + +// try to smell something +void CTalkMonster :: TrySmellTalk( void ) +{ + if ( !FOkToSpeak() ) + return; + + // clear smell bits periodically + if ( gpGlobals->time > m_flLastSaidSmelled ) + { +// ALERT ( at_aiconsole, "Clear smell bits\n" ); + ClearBits(m_bitsSaid, bit_saidSmelled); + } + // smelled something? + if (!FBitSet(m_bitsSaid, bit_saidSmelled) && HasConditions ( bits_COND_SMELL )) + { + PlaySentence( m_szGrp[TLK_SMELL], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + m_flLastSaidSmelled = gpGlobals->time + 60;// don't talk about the stinky for a while. + SetBits(m_bitsSaid, bit_saidSmelled); + } +} + + + +int CTalkMonster::IRelationship( CBaseEntity *pTarget ) +{ + if ( pTarget->IsPlayer() ) + if ( m_afMemory & bits_MEMORY_PROVOKED ) + return R_HT; + return CBaseMonster::IRelationship( pTarget ); +} + + +void CTalkMonster::StopFollowing( BOOL clearSchedule ) +{ + if ( IsFollowing() ) + { + if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) + { + PlaySentence( m_szGrp[TLK_UNUSE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + m_hTalkTarget = m_hTargetEnt; + } + + if ( m_movementGoal == MOVEGOAL_TARGETENT ) + RouteClear(); // Stop him from walking toward the player + m_hTargetEnt = NULL; + if ( clearSchedule ) + ClearSchedule(); + if ( m_hEnemy != NULL ) + m_IdealMonsterState = MONSTERSTATE_COMBAT; + } +} + + +void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) +{ + if ( m_pCine ) + m_pCine->CancelScript(); + + if ( m_hEnemy != NULL ) + m_IdealMonsterState = MONSTERSTATE_ALERT; + + m_hTargetEnt = pLeader; + PlaySentence( m_szGrp[TLK_USE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + m_hTalkTarget = m_hTargetEnt; + ClearConditions( bits_COND_CLIENT_PUSH ); + ClearSchedule(); +} + + +BOOL CTalkMonster::CanFollow( void ) +{ + if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + { + if ( !m_pCine->CanInterrupt() ) + return FALSE; + } + + if ( !IsAlive() ) + return FALSE; + + return !IsFollowing(); +} + + +void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // Don't allow use during a scripted_sentence + if ( m_useTime > gpGlobals->time ) + return; + + if ( pCaller != NULL && pCaller->IsPlayer() ) + { + // Pre-disaster followers can't be used + if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) + { + DeclineFollowing(); + } + else if ( CanFollow() ) + { + LimitFollowers( pCaller , 1 ); + + if ( m_afMemory & bits_MEMORY_PROVOKED ) + ALERT( at_console, "I'm not following you, you evil person!\n" ); + else + { + StartFollowing( pCaller ); + SetBits(m_bitsSaid, bit_saidHelloPlayer); // Don't say hi after you've started following + } + } + else + { + StopFollowing( TRUE ); + } + } +} + +void CTalkMonster::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "UseSentence")) + { + m_iszUse = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "UnUseSentence")) + { + m_iszUnUse = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseMonster::KeyValue( pkvd ); +} + + +void CTalkMonster::Precache( void ) +{ + if ( m_iszUse ) + m_szGrp[TLK_USE] = STRING( m_iszUse ); + if ( m_iszUnUse ) + m_szGrp[TLK_UNUSE] = STRING( m_iszUnUse ); +} + diff --git a/main/source/dlls/talkmonster.h b/main/source/dlls/talkmonster.h index 34fc40ee..25c1fc6d 100644 --- a/main/source/dlls/talkmonster.h +++ b/main/source/dlls/talkmonster.h @@ -1,26 +1,26 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef TALKMONSTER_H -#define TALKMONSTER_H - -class CTalkMonster : public CBaseMonster -{ -public: - static float g_talkWaitTime; - -}; - -#endif //TALKMONSTER_H +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef TALKMONSTER_H +#define TALKMONSTER_H + +class CTalkMonster : public CBaseMonster +{ +public: + static float g_talkWaitTime; + +}; + +#endif //TALKMONSTER_H diff --git a/main/source/dlls/teamplay_gamerules.cpp b/main/source/dlls/teamplay_gamerules.cpp index 031f0d01..875523d9 100644 --- a/main/source/dlls/teamplay_gamerules.cpp +++ b/main/source/dlls/teamplay_gamerules.cpp @@ -1,566 +1,566 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "game.h" -#include "mod/AvHConstants.h" -#include "mod/AvHServerVariables.h" -#include "mod/AvHServerUtil.h" -#include "mod/AvHNetworkMessages.h" - -static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; -static int team_scores[MAX_TEAMS]; -static int num_teams = 0; - -extern DLL_GLOBAL BOOL g_fGameOver; - -std::string GetLogStringForPlayer( edict_t *pEntity ); //defined in client.cpp - -CHalfLifeTeamplay :: CHalfLifeTeamplay() -{ - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - - memset( team_names, 0, sizeof(team_names) ); - memset( team_scores, 0, sizeof(team_scores) ); - num_teams = 0; - - // Copy over the team from the server config - m_szTeamList[0] = 0; - - // Cache this because the team code doesn't want to deal with changing this in the middle of a game - //strncpy( m_szTeamList, teamlist.string, TEAMPLAY_TEAMLISTLENGTH ); - strcpy(this->m_szTeamList, kTeamString); - - edict_t *pWorld = INDEXENT(0); - if ( pWorld && pWorld->v.team ) - { - if ( teamoverride.value ) - { - const char *pTeamList = STRING(pWorld->v.team); - if ( pTeamList && strlen(pTeamList) ) - { - strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH ); - } - } - } - // Has the server set teams - if ( strlen( m_szTeamList ) ) - m_teamLimit = TRUE; - else - m_teamLimit = FALSE; - - RecountTeams(); -} - -extern cvar_t timeleft, fragsleft; - -#include "../game_shared/voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - -void CHalfLifeTeamplay :: Think ( void ) -{ - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - g_VoiceGameMgr.Update(gpGlobals->frametime); - - if ( g_fGameOver ) // someone else quit the game already - { - CHalfLifeMultiplay::Think(); - return; - } - - float flTimeLimit = ns_cvar_float(&timelimit) * 60; - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - // Don't map switch in tourny mode, it signals the end of the match instead - bool theIsTournyMode = (ns_cvar_int(&avh_tournamentmode) > 0); - if ( flTimeLimit != 0 && (gpGlobals->time >= flTimeLimit) && !theIsTournyMode) - { - GoToIntermission(); - return; - } - - float flFragLimit = fraglimit.value; - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any team is over the frag limit - for ( int i = 0; i < num_teams; i++ ) - { - if ( team_scores[i] >= flFragLimit ) - { - GoToIntermission(); - return; - } - - remain = flFragLimit - team_scores[i]; - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if ( frags_remaining != last_frags ) - { - g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); - } - - // Updates once per second - if ( timeleft.value != last_time ) - { - g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - -//========================================================= -// ClientCommand -// the user has typed a command which is unrecognized by everything else; -// this check to see if the gamerules knows anything about the command -//========================================================= -BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) - return TRUE; - - if ( FStrEq( pcmd, "menuselect" ) ) - { - if ( CMD_ARGC() < 2 ) - return TRUE; - - int slot = atoi( CMD_ARGV(1) ); - - // select the item from the current menu - - return TRUE; - } - - return FALSE; -} - -const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) -{ - // copy out the team name from the model - char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); - pPlayer->SetTeamID(mdls); - - RecountTeams(); - - // update the current player of the team he is joining - const char* theTeamName = pPlayer->TeamID(); - - if ( theTeamName == '\0' || !IsValidTeam( theTeamName ) || defaultteam.value ) - { - const char *pTeamName = NULL; - - if ( defaultteam.value ) - { - pTeamName = team_names[0]; - } - else - { - pTeamName = TeamWithFewestPlayers(); - } - pPlayer->SetTeamID(pTeamName); - } - - return pPlayer->TeamID(); -} - - -//========================================================= -// InitHUD -//========================================================= -void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) -{ - SetDefaultPlayerTeam( pPlayer ); - CHalfLifeMultiplay::InitHUD( pPlayer ); - - StringList team_name_list; - for( int counter = 0; counter < num_teams; counter++ ) - { team_name_list.push_back( string("#") + string(team_names[counter]) ); } - - NetMsg_TeamNames( pPlayer->pev, team_name_list ); - - RecountTeams(); - - ChangePlayerTeam( pPlayer, pPlayer->TeamID(), FALSE, FALSE ); - int clientIndex = pPlayer->entindex(); - RecountTeams(); - - pPlayer->NeedsTeamUpdate(); -} - - -void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) -{ - int damageFlags = DMG_GENERIC; - int clientIndex = pPlayer->entindex(); - - if ( !bGib ) - { - damageFlags |= DMG_NEVERGIB; - } - else - { - damageFlags |= DMG_ALWAYSGIB; - } - - if ( bKill ) - { - // kill the player, remove a death, and let them start on the new team - m_DisableDeathMessages = TRUE; - m_DisableDeathPenalty = TRUE; - - entvars_t *pevWorld = VARS( INDEXENT(0) ); - pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); - - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - } - - pPlayer->SetTeamID(pTeamName); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->TeamID()); - - // notify everyone's HUD of the team change - pPlayer->SendTeamUpdate(); - - pPlayer->EffectivePlayerClassChanged(); -} - - -//========================================================= -// ClientUserInfoChanged -//========================================================= -void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) -{ - char text[1024]; - - // prevent skin/color/model changes - char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); - - if ( !_stricmp( mdls, pPlayer->TeamID() ) ) - return; - - if ( defaultteam.value ) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->TeamID() ); - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->TeamID() ); - sprintf( text, "* Not allowed to change teams in this game!\n" ); - UTIL_SayText( text, pPlayer ); - return; - } - - if ( defaultteam.value || !IsValidTeam( mdls ) ) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->TeamID() ); - sprintf( text, "* Can't change team to \'%s\'\n", mdls ); - UTIL_SayText( text, pPlayer ); - sprintf( text, "* Server limits teams to \'%s\'\n", m_szTeamList ); - UTIL_SayText( text, pPlayer ); - return; - } - // notify everyone of the team change - sprintf( text, "* %s has changed to team \'%s\'\n", STRING(pPlayer->pev->netname), mdls ); - UTIL_SayTextAll( text, pPlayer ); - - UTIL_LogPrintf( "%s joined team \"%s\"\n", GetLogStringForPlayer( pPlayer->edict() ).c_str(), mdls ); - - ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); - // recound stuff - RecountTeams(); -} - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - if ( m_DisableDeathMessages ) - return; - - if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) - { - CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); - - if ( pk ) - { - if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) - { - string tmpstr("teammate"); - NetMsg_DeathMsg( ENTINDEX(ENT(pKiller)), ENTINDEX(pVictim->edict()), tmpstr); - return; - } - } - } - - CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); -} - -//========================================================= -//========================================================= -void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - if ( !m_DisableDeathPenalty ) - { - CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); - RecountTeams(); - } -} - - -//========================================================= -// IsTeamplay -//========================================================= -BOOL CHalfLifeTeamplay::IsTeamplay( void ) -{ - return TRUE; -} - -BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) - { - // my teammate hit me. - if ( (friendlyfire.value == 0) && (pAttacker != pPlayer) ) - { - // friendly fire is off, and this hit came from someone other than myself, then don't get hurt - return FALSE; - } - } - - return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life multiplay has a simple concept of Player Relationships. - // you are either on another player's team, or you are not. - if ( !pPlayer || !pTarget || !pTarget->IsPlayer() ) - return GR_NOTTEAMMATE; - - if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !_stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) - { - return GR_TEAMMATE; - } - - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) -{ - // always autoaim, unless target is a teammate - CBaseEntity *pTgt = CBaseEntity::Instance( target ); - if ( pTgt && pTgt->IsPlayer() ) - { - if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) - return FALSE; // don't autoaim at teammates - } - - return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - if ( !pKilled ) - return 0; - - if ( !pAttacker ) - return 1; - - if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) - return -1; - - return 1; -} - -//========================================================= -//========================================================= -const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL || pEntity->pev == NULL ) - return ""; - - // return their team name - return pEntity->TeamID(); -} - - -int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) -{ - if ( pTeamName && *pTeamName != 0 ) - { - // try to find existing team - for ( int tm = 0; tm < num_teams; tm++ ) - { - if ( !_stricmp( team_names[tm], pTeamName ) ) - return tm; - } - } - - return -1; // No match -} - - -const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) -{ - if ( teamIndex < 0 || teamIndex >= num_teams ) - return ""; - - return team_names[ teamIndex ]; -} - - -BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) -{ - if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set - return TRUE; - - return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; -} - -const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) -{ - int i; - int minPlayers = MAX_TEAMS; - int teamCount[ MAX_TEAMS ]; - char *pTeamName = NULL; - - memset( teamCount, 0, MAX_TEAMS * sizeof(int) ); - - // loop through all clients, count number of players on each team - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - int team = GetTeamIndex( plr->TeamID() ); - if ( team >= 0 ) - teamCount[team] ++; - } - } - - // Find team with least players - for ( i = 0; i < num_teams; i++ ) - { - if ( teamCount[i] < minPlayers ) - { - minPlayers = teamCount[i]; - pTeamName = team_names[i]; - } - } - - return pTeamName; -} - - -//========================================================= -//========================================================= -void CHalfLifeTeamplay::RecountTeams( void ) -{ - char *pName; - char teamlist[TEAMPLAY_TEAMLISTLENGTH]; - - // loop through all teams, recounting everything - num_teams = 0; - - // Copy all of the teams from the teamlist - // make a copy because strtok is destructive - strcpy( teamlist, m_szTeamList ); - pName = teamlist; - pName = strtok( pName, ";" ); - while ( pName != NULL && *pName ) - { - if ( GetTeamIndex( pName ) < 0 ) - { - strcpy( team_names[num_teams], pName ); - num_teams++; - } - pName = strtok( NULL, ";" ); - } - - if ( num_teams < 2 ) - { - num_teams = 0; - m_teamLimit = FALSE; - } - - // Sanity check - memset( team_scores, 0, sizeof(team_scores) ); - - // loop through all clients - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - const char *pTeamName = plr->TeamID(); - // try add to existing team - int tm = GetTeamIndex( pTeamName ); - - if ( tm < 0 ) // no team match found - { - if ( !m_teamLimit ) - { - // add to new team - tm = num_teams; - num_teams++; - team_scores[tm] = 0; - strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); - } - } - - if ( tm >= 0 ) - { - team_scores[tm] += plr->pev->frags; - } - } - } -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// teamplay_gamerules.cpp +// +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "teamplay_gamerules.h" +#include "game.h" +#include "mod/AvHConstants.h" +#include "mod/AvHServerVariables.h" +#include "mod/AvHServerUtil.h" +#include "mod/AvHNetworkMessages.h" + +static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; +static int team_scores[MAX_TEAMS]; +static int num_teams = 0; + +extern DLL_GLOBAL BOOL g_fGameOver; + +std::string GetLogStringForPlayer( edict_t *pEntity ); //defined in client.cpp + +CHalfLifeTeamplay :: CHalfLifeTeamplay() +{ + m_DisableDeathMessages = FALSE; + m_DisableDeathPenalty = FALSE; + + memset( team_names, 0, sizeof(team_names) ); + memset( team_scores, 0, sizeof(team_scores) ); + num_teams = 0; + + // Copy over the team from the server config + m_szTeamList[0] = 0; + + // Cache this because the team code doesn't want to deal with changing this in the middle of a game + //strncpy( m_szTeamList, teamlist.string, TEAMPLAY_TEAMLISTLENGTH ); + strcpy(this->m_szTeamList, kTeamString); + + edict_t *pWorld = INDEXENT(0); + if ( pWorld && pWorld->v.team ) + { + if ( teamoverride.value ) + { + const char *pTeamList = STRING(pWorld->v.team); + if ( pTeamList && strlen(pTeamList) ) + { + strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH ); + } + } + } + // Has the server set teams + if ( strlen( m_szTeamList ) ) + m_teamLimit = TRUE; + else + m_teamLimit = FALSE; + + RecountTeams(); +} + +extern cvar_t timeleft, fragsleft; + +#include "../game_shared/voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + +void CHalfLifeTeamplay :: Think ( void ) +{ + ///// Check game rules ///// + static int last_frags; + static int last_time; + + int frags_remaining = 0; + int time_remaining = 0; + + g_VoiceGameMgr.Update(gpGlobals->frametime); + + if ( g_fGameOver ) // someone else quit the game already + { + CHalfLifeMultiplay::Think(); + return; + } + + float flTimeLimit = ns_cvar_float(&timelimit) * 60; + + time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + + // Don't map switch in tourny mode, it signals the end of the match instead + bool theIsTournyMode = (ns_cvar_int(&avh_tournamentmode) > 0); + if ( flTimeLimit != 0 && (gpGlobals->time >= flTimeLimit) && !theIsTournyMode) + { + GoToIntermission(); + return; + } + + float flFragLimit = fraglimit.value; + if ( flFragLimit ) + { + int bestfrags = 9999; + int remain; + + // check if any team is over the frag limit + for ( int i = 0; i < num_teams; i++ ) + { + if ( team_scores[i] >= flFragLimit ) + { + GoToIntermission(); + return; + } + + remain = flFragLimit - team_scores[i]; + if ( remain < bestfrags ) + { + bestfrags = remain; + } + } + frags_remaining = bestfrags; + } + + // Updates when frags change + if ( frags_remaining != last_frags ) + { + g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); + } + + // Updates once per second + if ( timeleft.value != last_time ) + { + g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); + } + + last_frags = frags_remaining; + last_time = time_remaining; +} + +//========================================================= +// ClientCommand +// the user has typed a command which is unrecognized by everything else; +// this check to see if the gamerules knows anything about the command +//========================================================= +BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) +{ + if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + return TRUE; + + if ( FStrEq( pcmd, "menuselect" ) ) + { + if ( CMD_ARGC() < 2 ) + return TRUE; + + int slot = atoi( CMD_ARGV(1) ); + + // select the item from the current menu + + return TRUE; + } + + return FALSE; +} + +const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) +{ + // copy out the team name from the model + char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); + pPlayer->SetTeamID(mdls); + + RecountTeams(); + + // update the current player of the team he is joining + const char* theTeamName = pPlayer->TeamID(); + + if ( theTeamName == '\0' || !IsValidTeam( theTeamName ) || defaultteam.value ) + { + const char *pTeamName = NULL; + + if ( defaultteam.value ) + { + pTeamName = team_names[0]; + } + else + { + pTeamName = TeamWithFewestPlayers(); + } + pPlayer->SetTeamID(pTeamName); + } + + return pPlayer->TeamID(); +} + + +//========================================================= +// InitHUD +//========================================================= +void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) +{ + SetDefaultPlayerTeam( pPlayer ); + CHalfLifeMultiplay::InitHUD( pPlayer ); + + StringList team_name_list; + for( int counter = 0; counter < num_teams; counter++ ) + { team_name_list.push_back( string("#") + string(team_names[counter]) ); } + + NetMsg_TeamNames( pPlayer->pev, team_name_list ); + + RecountTeams(); + + ChangePlayerTeam( pPlayer, pPlayer->TeamID(), FALSE, FALSE ); + int clientIndex = pPlayer->entindex(); + RecountTeams(); + + pPlayer->NeedsTeamUpdate(); +} + + +void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) +{ + int damageFlags = DMG_GENERIC; + int clientIndex = pPlayer->entindex(); + + if ( !bGib ) + { + damageFlags |= DMG_NEVERGIB; + } + else + { + damageFlags |= DMG_ALWAYSGIB; + } + + if ( bKill ) + { + // kill the player, remove a death, and let them start on the new team + m_DisableDeathMessages = TRUE; + m_DisableDeathPenalty = TRUE; + + entvars_t *pevWorld = VARS( INDEXENT(0) ); + pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); + + m_DisableDeathMessages = FALSE; + m_DisableDeathPenalty = FALSE; + } + + pPlayer->SetTeamID(pTeamName); + + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->TeamID()); + + // notify everyone's HUD of the team change + pPlayer->SendTeamUpdate(); + + pPlayer->EffectivePlayerClassChanged(); +} + + +//========================================================= +// ClientUserInfoChanged +//========================================================= +void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) +{ + char text[1024]; + + // prevent skin/color/model changes + char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); + + if ( !_stricmp( mdls, pPlayer->TeamID() ) ) + return; + + if ( defaultteam.value ) + { + int clientIndex = pPlayer->entindex(); + + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->TeamID() ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->TeamID() ); + sprintf( text, "* Not allowed to change teams in this game!\n" ); + UTIL_SayText( text, pPlayer ); + return; + } + + if ( defaultteam.value || !IsValidTeam( mdls ) ) + { + int clientIndex = pPlayer->entindex(); + + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->TeamID() ); + sprintf( text, "* Can't change team to \'%s\'\n", mdls ); + UTIL_SayText( text, pPlayer ); + sprintf( text, "* Server limits teams to \'%s\'\n", m_szTeamList ); + UTIL_SayText( text, pPlayer ); + return; + } + // notify everyone of the team change + sprintf( text, "* %s has changed to team \'%s\'\n", STRING(pPlayer->pev->netname), mdls ); + UTIL_SayTextAll( text, pPlayer ); + + UTIL_LogPrintf( "%s joined team \"%s\"\n", GetLogStringForPlayer( pPlayer->edict() ).c_str(), mdls ); + + ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); + // recound stuff + RecountTeams(); +} + +//========================================================= +// Deathnotice. +//========================================================= +void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) +{ + if ( m_DisableDeathMessages ) + return; + + if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) + { + CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); + + if ( pk ) + { + if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) + { + string tmpstr("teammate"); + NetMsg_DeathMsg( ENTINDEX(ENT(pKiller)), ENTINDEX(pVictim->edict()), tmpstr); + return; + } + } + } + + CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); +} + +//========================================================= +//========================================================= +void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +{ + if ( !m_DisableDeathPenalty ) + { + CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); + RecountTeams(); + } +} + + +//========================================================= +// IsTeamplay +//========================================================= +BOOL CHalfLifeTeamplay::IsTeamplay( void ) +{ + return TRUE; +} + +BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) +{ + if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) + { + // my teammate hit me. + if ( (friendlyfire.value == 0) && (pAttacker != pPlayer) ) + { + // friendly fire is off, and this hit came from someone other than myself, then don't get hurt + return FALSE; + } + } + + return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker ); +} + +//========================================================= +//========================================================= +int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) +{ + // half life multiplay has a simple concept of Player Relationships. + // you are either on another player's team, or you are not. + if ( !pPlayer || !pTarget || !pTarget->IsPlayer() ) + return GR_NOTTEAMMATE; + + if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !_stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) + { + return GR_TEAMMATE; + } + + return GR_NOTTEAMMATE; +} + +//========================================================= +//========================================================= +BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) +{ + // always autoaim, unless target is a teammate + CBaseEntity *pTgt = CBaseEntity::Instance( target ); + if ( pTgt && pTgt->IsPlayer() ) + { + if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) + return FALSE; // don't autoaim at teammates + } + + return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target ); +} + +//========================================================= +//========================================================= +int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +{ + if ( !pKilled ) + return 0; + + if ( !pAttacker ) + return 1; + + if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) + return -1; + + return 1; +} + +//========================================================= +//========================================================= +const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) +{ + if ( pEntity == NULL || pEntity->pev == NULL ) + return ""; + + // return their team name + return pEntity->TeamID(); +} + + +int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) +{ + if ( pTeamName && *pTeamName != 0 ) + { + // try to find existing team + for ( int tm = 0; tm < num_teams; tm++ ) + { + if ( !_stricmp( team_names[tm], pTeamName ) ) + return tm; + } + } + + return -1; // No match +} + + +const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) +{ + if ( teamIndex < 0 || teamIndex >= num_teams ) + return ""; + + return team_names[ teamIndex ]; +} + + +BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) +{ + if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set + return TRUE; + + return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; +} + +const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) +{ + int i; + int minPlayers = MAX_TEAMS; + int teamCount[ MAX_TEAMS ]; + char *pTeamName = NULL; + + memset( teamCount, 0, MAX_TEAMS * sizeof(int) ); + + // loop through all clients, count number of players on each team + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + + if ( plr ) + { + int team = GetTeamIndex( plr->TeamID() ); + if ( team >= 0 ) + teamCount[team] ++; + } + } + + // Find team with least players + for ( i = 0; i < num_teams; i++ ) + { + if ( teamCount[i] < minPlayers ) + { + minPlayers = teamCount[i]; + pTeamName = team_names[i]; + } + } + + return pTeamName; +} + + +//========================================================= +//========================================================= +void CHalfLifeTeamplay::RecountTeams( void ) +{ + char *pName; + char teamlist[TEAMPLAY_TEAMLISTLENGTH]; + + // loop through all teams, recounting everything + num_teams = 0; + + // Copy all of the teams from the teamlist + // make a copy because strtok is destructive + strcpy( teamlist, m_szTeamList ); + pName = teamlist; + pName = strtok( pName, ";" ); + while ( pName != NULL && *pName ) + { + if ( GetTeamIndex( pName ) < 0 ) + { + strcpy( team_names[num_teams], pName ); + num_teams++; + } + pName = strtok( NULL, ";" ); + } + + if ( num_teams < 2 ) + { + num_teams = 0; + m_teamLimit = FALSE; + } + + // Sanity check + memset( team_scores, 0, sizeof(team_scores) ); + + // loop through all clients + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + + if ( plr ) + { + const char *pTeamName = plr->TeamID(); + // try add to existing team + int tm = GetTeamIndex( pTeamName ); + + if ( tm < 0 ) // no team match found + { + if ( !m_teamLimit ) + { + // add to new team + tm = num_teams; + num_teams++; + team_scores[tm] = 0; + strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); + } + } + + if ( tm >= 0 ) + { + team_scores[tm] += plr->pev->frags; + } + } + } +} diff --git a/main/source/dlls/teamplay_gamerules.cpp~ b/main/source/dlls/teamplay_gamerules.cpp~ deleted file mode 100644 index cbad936a..00000000 --- a/main/source/dlls/teamplay_gamerules.cpp~ +++ /dev/null @@ -1,566 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "game.h" -#include "mod/AvHConstants.h" -#include "mod/AvHServerVariables.h" -#include "mod/AvHServerUtil.h" -#include "mod/AvHNetworkMessages.h" - -static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; -static int team_scores[MAX_TEAMS]; -static int num_teams = 0; - -extern DLL_GLOBAL BOOL g_fGameOver; - -std::string GetLogStringForPlayer( edict_t *pEntity ); //defined in client.cpp - -CHalfLifeTeamplay :: CHalfLifeTeamplay() -{ - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - - memset( team_names, 0, sizeof(team_names) ); - memset( team_scores, 0, sizeof(team_scores) ); - num_teams = 0; - - // Copy over the team from the server config - m_szTeamList[0] = 0; - - // Cache this because the team code doesn't want to deal with changing this in the middle of a game - //strncpy( m_szTeamList, teamlist.string, TEAMPLAY_TEAMLISTLENGTH ); - strcpy(this->m_szTeamList, kTeamString); - - edict_t *pWorld = INDEXENT(0); - if ( pWorld && pWorld->v.team ) - { - if ( teamoverride.value ) - { - const char *pTeamList = STRING(pWorld->v.team); - if ( pTeamList && strlen(pTeamList) ) - { - strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH ); - } - } - } - // Has the server set teams - if ( strlen( m_szTeamList ) ) - m_teamLimit = TRUE; - else - m_teamLimit = FALSE; - - RecountTeams(); -} - -extern cvar_t timeleft, fragsleft; - -#include "game_shared/voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - -void CHalfLifeTeamplay :: Think ( void ) -{ - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - g_VoiceGameMgr.Update(gpGlobals->frametime); - - if ( g_fGameOver ) // someone else quit the game already - { - CHalfLifeMultiplay::Think(); - return; - } - - float flTimeLimit = ns_cvar_float(&timelimit) * 60; - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - // Don't map switch in tourny mode, it signals the end of the match instead - bool theIsTournyMode = (ns_cvar_int(&avh_tournamentmode) > 0); - if ( flTimeLimit != 0 && (gpGlobals->time >= flTimeLimit) && !theIsTournyMode) - { - GoToIntermission(); - return; - } - - float flFragLimit = fraglimit.value; - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any team is over the frag limit - for ( int i = 0; i < num_teams; i++ ) - { - if ( team_scores[i] >= flFragLimit ) - { - GoToIntermission(); - return; - } - - remain = flFragLimit - team_scores[i]; - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if ( frags_remaining != last_frags ) - { - g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); - } - - // Updates once per second - if ( timeleft.value != last_time ) - { - g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - -//========================================================= -// ClientCommand -// the user has typed a command which is unrecognized by everything else; -// this check to see if the gamerules knows anything about the command -//========================================================= -BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) - return TRUE; - - if ( FStrEq( pcmd, "menuselect" ) ) - { - if ( CMD_ARGC() < 2 ) - return TRUE; - - int slot = atoi( CMD_ARGV(1) ); - - // select the item from the current menu - - return TRUE; - } - - return FALSE; -} - -const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) -{ - // copy out the team name from the model - char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); - pPlayer->SetTeamID(mdls); - - RecountTeams(); - - // update the current player of the team he is joining - const char* theTeamName = pPlayer->TeamID(); - - if ( theTeamName == '\0' || !IsValidTeam( theTeamName ) || defaultteam.value ) - { - const char *pTeamName = NULL; - - if ( defaultteam.value ) - { - pTeamName = team_names[0]; - } - else - { - pTeamName = TeamWithFewestPlayers(); - } - pPlayer->SetTeamID(pTeamName); - } - - return pPlayer->TeamID(); -} - - -//========================================================= -// InitHUD -//========================================================= -void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) -{ - SetDefaultPlayerTeam( pPlayer ); - CHalfLifeMultiplay::InitHUD( pPlayer ); - - StringList team_name_list; - for( int counter = 0; counter < num_teams; counter++ ) - { team_name_list.push_back( string("#") + string(team_names[counter]) ); } - - NetMsg_TeamNames( pPlayer->pev, team_name_list ); - - RecountTeams(); - - ChangePlayerTeam( pPlayer, pPlayer->TeamID(), FALSE, FALSE ); - int clientIndex = pPlayer->entindex(); - RecountTeams(); - - pPlayer->NeedsTeamUpdate(); -} - - -void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) -{ - int damageFlags = DMG_GENERIC; - int clientIndex = pPlayer->entindex(); - - if ( !bGib ) - { - damageFlags |= DMG_NEVERGIB; - } - else - { - damageFlags |= DMG_ALWAYSGIB; - } - - if ( bKill ) - { - // kill the player, remove a death, and let them start on the new team - m_DisableDeathMessages = TRUE; - m_DisableDeathPenalty = TRUE; - - entvars_t *pevWorld = VARS( INDEXENT(0) ); - pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); - - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - } - - pPlayer->SetTeamID(pTeamName); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->TeamID()); - - // notify everyone's HUD of the team change - pPlayer->SendTeamUpdate(); - - pPlayer->EffectivePlayerClassChanged(); -} - - -//========================================================= -// ClientUserInfoChanged -//========================================================= -void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) -{ - char text[1024]; - - // prevent skin/color/model changes - char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); - - if ( !_stricmp( mdls, pPlayer->TeamID() ) ) - return; - - if ( defaultteam.value ) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->TeamID() ); - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->TeamID() ); - sprintf( text, "* Not allowed to change teams in this game!\n" ); - UTIL_SayText( text, pPlayer ); - return; - } - - if ( defaultteam.value || !IsValidTeam( mdls ) ) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->TeamID() ); - sprintf( text, "* Can't change team to \'%s\'\n", mdls ); - UTIL_SayText( text, pPlayer ); - sprintf( text, "* Server limits teams to \'%s\'\n", m_szTeamList ); - UTIL_SayText( text, pPlayer ); - return; - } - // notify everyone of the team change - sprintf( text, "* %s has changed to team \'%s\'\n", STRING(pPlayer->pev->netname), mdls ); - UTIL_SayTextAll( text, pPlayer ); - - UTIL_LogPrintf( "%s joined team \"%s\"\n", GetLogStringForPlayer( pPlayer->edict() ).c_str(), mdls ); - - ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); - // recound stuff - RecountTeams(); -} - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - if ( m_DisableDeathMessages ) - return; - - if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) - { - CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); - - if ( pk ) - { - if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) - { - string tmpstr("teammate"); - NetMsg_DeathMsg( ENTINDEX(ENT(pKiller)), ENTINDEX(pVictim->edict()), tmpstr); - return; - } - } - } - - CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); -} - -//========================================================= -//========================================================= -void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - if ( !m_DisableDeathPenalty ) - { - CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); - RecountTeams(); - } -} - - -//========================================================= -// IsTeamplay -//========================================================= -BOOL CHalfLifeTeamplay::IsTeamplay( void ) -{ - return TRUE; -} - -BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) - { - // my teammate hit me. - if ( (friendlyfire.value == 0) && (pAttacker != pPlayer) ) - { - // friendly fire is off, and this hit came from someone other than myself, then don't get hurt - return FALSE; - } - } - - return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life multiplay has a simple concept of Player Relationships. - // you are either on another player's team, or you are not. - if ( !pPlayer || !pTarget || !pTarget->IsPlayer() ) - return GR_NOTTEAMMATE; - - if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !_stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) - { - return GR_TEAMMATE; - } - - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) -{ - // always autoaim, unless target is a teammate - CBaseEntity *pTgt = CBaseEntity::Instance( target ); - if ( pTgt && pTgt->IsPlayer() ) - { - if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) - return FALSE; // don't autoaim at teammates - } - - return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - if ( !pKilled ) - return 0; - - if ( !pAttacker ) - return 1; - - if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) - return -1; - - return 1; -} - -//========================================================= -//========================================================= -const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL || pEntity->pev == NULL ) - return ""; - - // return their team name - return pEntity->TeamID(); -} - - -int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) -{ - if ( pTeamName && *pTeamName != 0 ) - { - // try to find existing team - for ( int tm = 0; tm < num_teams; tm++ ) - { - if ( !_stricmp( team_names[tm], pTeamName ) ) - return tm; - } - } - - return -1; // No match -} - - -const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) -{ - if ( teamIndex < 0 || teamIndex >= num_teams ) - return ""; - - return team_names[ teamIndex ]; -} - - -BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) -{ - if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set - return TRUE; - - return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; -} - -const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) -{ - int i; - int minPlayers = MAX_TEAMS; - int teamCount[ MAX_TEAMS ]; - char *pTeamName = NULL; - - memset( teamCount, 0, MAX_TEAMS * sizeof(int) ); - - // loop through all clients, count number of players on each team - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - int team = GetTeamIndex( plr->TeamID() ); - if ( team >= 0 ) - teamCount[team] ++; - } - } - - // Find team with least players - for ( i = 0; i < num_teams; i++ ) - { - if ( teamCount[i] < minPlayers ) - { - minPlayers = teamCount[i]; - pTeamName = team_names[i]; - } - } - - return pTeamName; -} - - -//========================================================= -//========================================================= -void CHalfLifeTeamplay::RecountTeams( void ) -{ - char *pName; - char teamlist[TEAMPLAY_TEAMLISTLENGTH]; - - // loop through all teams, recounting everything - num_teams = 0; - - // Copy all of the teams from the teamlist - // make a copy because strtok is destructive - strcpy( teamlist, m_szTeamList ); - pName = teamlist; - pName = strtok( pName, ";" ); - while ( pName != NULL && *pName ) - { - if ( GetTeamIndex( pName ) < 0 ) - { - strcpy( team_names[num_teams], pName ); - num_teams++; - } - pName = strtok( NULL, ";" ); - } - - if ( num_teams < 2 ) - { - num_teams = 0; - m_teamLimit = FALSE; - } - - // Sanity check - memset( team_scores, 0, sizeof(team_scores) ); - - // loop through all clients - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - const char *pTeamName = plr->TeamID(); - // try add to existing team - int tm = GetTeamIndex( pTeamName ); - - if ( tm < 0 ) // no team match found - { - if ( !m_teamLimit ) - { - // add to new team - tm = num_teams; - num_teams++; - team_scores[tm] = 0; - strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); - } - } - - if ( tm >= 0 ) - { - team_scores[tm] += plr->pev->frags; - } - } - } -} diff --git a/main/source/dlls/teamplay_gamerules.h b/main/source/dlls/teamplay_gamerules.h index fe53e9ee..4d0b8fb6 100644 --- a/main/source/dlls/teamplay_gamerules.h +++ b/main/source/dlls/teamplay_gamerules.h @@ -1,57 +1,57 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.h -// -#ifndef CHALFLIFETEAMPLAY_H -#define CHALFLIFETEAMPLAY_H - -#include "../game_shared/teamconst.h" - -class CHalfLifeTeamplay : public CHalfLifeMultiplay -{ -public: - CHalfLifeTeamplay(); - - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); - virtual BOOL IsTeamplay( void ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - virtual const char *GetTeamID( CBaseEntity *pEntity ); - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void InitHUD( CBasePlayer *pl ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); - virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void Think ( void ); - virtual int GetTeamIndex( const char *pTeamName ); - virtual const char *GetIndexedTeamName( int teamIndex ); - virtual BOOL IsValidTeam( const char *pTeamName ); - const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); - -private: - void RecountTeams( void ); - const char *TeamWithFewestPlayers( void ); - - BOOL m_DisableDeathMessages; - BOOL m_DisableDeathPenalty; - BOOL m_teamLimit; // This means the server set only some teams as valid - char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; -}; - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// teamplay_gamerules.h +// +#ifndef CHALFLIFETEAMPLAY_H +#define CHALFLIFETEAMPLAY_H + +#include "../game_shared/teamconst.h" + +class CHalfLifeTeamplay : public CHalfLifeMultiplay +{ +public: + CHalfLifeTeamplay(); + + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); + virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); + virtual BOOL IsTeamplay( void ); + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual const char *GetTeamID( CBaseEntity *pEntity ); + virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void InitHUD( CBasePlayer *pl ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); + virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void Think ( void ); + virtual int GetTeamIndex( const char *pTeamName ); + virtual const char *GetIndexedTeamName( int teamIndex ); + virtual BOOL IsValidTeam( const char *pTeamName ); + const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); + +private: + void RecountTeams( void ); + const char *TeamWithFewestPlayers( void ); + + BOOL m_DisableDeathMessages; + BOOL m_DisableDeathPenalty; + BOOL m_teamLimit; // This means the server set only some teams as valid + char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; +}; + #endif \ No newline at end of file diff --git a/main/source/dlls/teamplay_gamerules.h~ b/main/source/dlls/teamplay_gamerules.h~ deleted file mode 100644 index d3b56a7e..00000000 --- a/main/source/dlls/teamplay_gamerules.h~ +++ /dev/null @@ -1,57 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.h -// -#ifndef CHALFLIFETEAMPLAY_H -#define CHALFLIFETEAMPLAY_H - -#include "game_shared/teamconst.h" - -class CHalfLifeTeamplay : public CHalfLifeMultiplay -{ -public: - CHalfLifeTeamplay(); - - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); - virtual BOOL IsTeamplay( void ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - virtual const char *GetTeamID( CBaseEntity *pEntity ); - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void InitHUD( CBasePlayer *pl ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); - virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void Think ( void ); - virtual int GetTeamIndex( const char *pTeamName ); - virtual const char *GetIndexedTeamName( int teamIndex ); - virtual BOOL IsValidTeam( const char *pTeamName ); - const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); - -private: - void RecountTeams( void ); - const char *TeamWithFewestPlayers( void ); - - BOOL m_DisableDeathMessages; - BOOL m_DisableDeathPenalty; - BOOL m_teamLimit; // This means the server set only some teams as valid - char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; -}; - -#endif \ No newline at end of file diff --git a/main/source/dlls/tempmonster.cpp b/main/source/dlls/tempmonster.cpp index 8dfeef8b..43f1f18f 100644 --- a/main/source/dlls/tempmonster.cpp +++ b/main/source/dlls/tempmonster.cpp @@ -1,117 +1,117 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monster template -//========================================================= -#if 0 - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CMyMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); -}; -LINK_ENTITY_TO_CLASS( my_monster, CMyMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CMyMonster :: Classify ( void ) -{ - return CLASS_MY_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CMyMonster :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CMyMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CMyMonster :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/mymodel.mdl"); - UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 8; - pev->view_ofs = Vector ( 0, 0, 0 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CMyMonster :: Precache() -{ - PRECACHE_SOUND("mysound.wav"); - - PRECACHE_MODEL("models/mymodel.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -#endif 0 +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// monster template +//========================================================= +#if 0 + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= + +class CMyMonster : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); +}; +LINK_ENTITY_TO_CLASS( my_monster, CMyMonster ); + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CMyMonster :: Classify ( void ) +{ + return CLASS_MY_MONSTER; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CMyMonster :: SetYawSpeed ( void ) +{ + int ys; + + switch ( m_Activity ) + { + case ACT_IDLE: + default: + ys = 90; + } + + pev->yaw_speed = ys; +} + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CMyMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case 0: + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CMyMonster :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/mymodel.mdl"); + UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = 8; + pev->view_ofs = Vector ( 0, 0, 0 );// position of the eyes relative to monster's origin. + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CMyMonster :: Precache() +{ + PRECACHE_SOUND("mysound.wav"); + + PRECACHE_MODEL("models/mymodel.mdl"); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= +#endif 0 diff --git a/main/source/dlls/tentacle.cpp b/main/source/dlls/tentacle.cpp index 2cc5c176..835cbc68 100644 --- a/main/source/dlls/tentacle.cpp +++ b/main/source/dlls/tentacle.cpp @@ -1,1044 +1,1044 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -/* - - h_tentacle.cpp - silo of death tentacle monster (half life) - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "soundent.h" - - -#define ACT_T_IDLE 1010 -#define ACT_T_TAP 1020 -#define ACT_T_STRIKE 1030 -#define ACT_T_REARIDLE 1040 - -class CTentacle : public CBaseMonster -{ -public: - CTentacle( void ); - - void Spawn( ); - void Precache( ); - void KeyValue( KeyValueData *pkvd ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - // Don't allow the tentacle to go across transitions!!! - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector(-400, -400, 0); - pev->absmax = pev->origin + Vector(400, 400, 850); - } - - void EXPORT Cycle( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Start( void ); - void EXPORT DieThink( void ); - - void EXPORT Test( void ); - - void EXPORT HitTouch( CBaseEntity *pOther ); - - float HearingSensitivity( void ) { return 2.0; }; - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Killed( entvars_t *pevAttacker, int iGib ); - - MONSTERSTATE GetIdealState ( void ) { return MONSTERSTATE_IDLE; }; - int CanPlaySequence( BOOL fDisregardState ) { return TRUE; }; - - int Classify( void ); - - int Level( float dz ); - int MyLevel( void ); - float MyHeight( void ); - - float m_flInitialYaw; - int m_iGoalAnim; - int m_iLevel; - int m_iDir; - float m_flFramerateAdj; - float m_flSoundYaw; - int m_iSoundLevel; - float m_flSoundTime; - float m_flSoundRadius; - int m_iHitDmg; - float m_flHitTime; - - float m_flTapRadius; - - float m_flNextSong; - static int g_fFlySound; - static int g_fSquirmSound; - - float m_flMaxYaw; - int m_iTapSound; - - Vector m_vecPrevSound; - float m_flPrevSoundTime; - - static const char *pHitSilo[]; - static const char *pHitDirt[]; - static const char *pHitWater[]; -}; - - - -int CTentacle :: g_fFlySound; -int CTentacle :: g_fSquirmSound; - -LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ); - -// stike sounds -#define TE_NONE -1 -#define TE_SILO 0 -#define TE_DIRT 1 -#define TE_WATER 2 - -const char *CTentacle::pHitSilo[] = -{ - "tentacle/te_strike1.wav", - "tentacle/te_strike2.wav", -}; - -const char *CTentacle::pHitDirt[] = -{ - "player/pl_dirt1.wav", - "player/pl_dirt2.wav", - "player/pl_dirt3.wav", - "player/pl_dirt4.wav", -}; - -const char *CTentacle::pHitWater[] = -{ - "player/pl_slosh1.wav", - "player/pl_slosh2.wav", - "player/pl_slosh3.wav", - "player/pl_slosh4.wav", -}; - - -TYPEDESCRIPTION CTentacle::m_SaveData[] = -{ - DEFINE_FIELD( CTentacle, m_flInitialYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iGoalAnim, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_iLevel, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_iDir, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flFramerateAdj, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_flSoundYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iSoundLevel, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flSoundTime, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_flSoundRadius, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iHitDmg, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flHitTime, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_flTapRadius, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_flNextSong, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_iTapSound, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flMaxYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTentacle, m_flPrevSoundTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ); - - -// animation sequence aliases -typedef enum -{ - TENTACLE_ANIM_Pit_Idle, - - TENTACLE_ANIM_rise_to_Temp1, - TENTACLE_ANIM_Temp1_to_Floor, - TENTACLE_ANIM_Floor_Idle, - TENTACLE_ANIM_Floor_Fidget_Pissed, - TENTACLE_ANIM_Floor_Fidget_SmallRise, - TENTACLE_ANIM_Floor_Fidget_Wave, - TENTACLE_ANIM_Floor_Strike, - TENTACLE_ANIM_Floor_Tap, - TENTACLE_ANIM_Floor_Rotate, - TENTACLE_ANIM_Floor_Rear, - TENTACLE_ANIM_Floor_Rear_Idle, - TENTACLE_ANIM_Floor_to_Lev1, - - TENTACLE_ANIM_Lev1_Idle, - TENTACLE_ANIM_Lev1_Fidget_Claw, - TENTACLE_ANIM_Lev1_Fidget_Shake, - TENTACLE_ANIM_Lev1_Fidget_Snap, - TENTACLE_ANIM_Lev1_Strike, - TENTACLE_ANIM_Lev1_Tap, - TENTACLE_ANIM_Lev1_Rotate, - TENTACLE_ANIM_Lev1_Rear, - TENTACLE_ANIM_Lev1_Rear_Idle, - TENTACLE_ANIM_Lev1_to_Lev2, - - TENTACLE_ANIM_Lev2_Idle, - TENTACLE_ANIM_Lev2_Fidget_Shake, - TENTACLE_ANIM_Lev2_Fidget_Swing, - TENTACLE_ANIM_Lev2_Fidget_Tut, - TENTACLE_ANIM_Lev2_Strike, - TENTACLE_ANIM_Lev2_Tap, - TENTACLE_ANIM_Lev2_Rotate, - TENTACLE_ANIM_Lev2_Rear, - TENTACLE_ANIM_Lev2_Rear_Idle, - TENTACLE_ANIM_Lev2_to_Lev3, - - TENTACLE_ANIM_Lev3_Idle, - TENTACLE_ANIM_Lev3_Fidget_Shake, - TENTACLE_ANIM_Lev3_Fidget_Side, - TENTACLE_ANIM_Lev3_Fidget_Swipe, - TENTACLE_ANIM_Lev3_Strike, - TENTACLE_ANIM_Lev3_Tap, - TENTACLE_ANIM_Lev3_Rotate, - TENTACLE_ANIM_Lev3_Rear, - TENTACLE_ANIM_Lev3_Rear_Idle, - - TENTACLE_ANIM_Lev1_Door_reach, - - TENTACLE_ANIM_Lev3_to_Engine, - TENTACLE_ANIM_Engine_Idle, - TENTACLE_ANIM_Engine_Sway, - TENTACLE_ANIM_Engine_Swat, - TENTACLE_ANIM_Engine_Bob, - TENTACLE_ANIM_Engine_Death1, - TENTACLE_ANIM_Engine_Death2, - TENTACLE_ANIM_Engine_Death3, - - TENTACLE_ANIM_none -} TENTACLE_ANIM; - - - - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CTentacle :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -// -// Tentacle Spawn -// -void CTentacle :: Spawn( ) -{ - Precache( ); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - pev->effects = 0; - pev->health = 75; - pev->sequence = 0; - - SET_MODEL(ENT(pev), "models/tentacle2.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->takedamage = DAMAGE_AIM; - pev->flags |= FL_MONSTER; - - m_bloodColor = BLOOD_COLOR_GREEN; - - SetThink( &CTentacle::Start ); - SetTouch( &CTentacle::HitTouch ); - SetUse( &CTentacle::CommandUse ); - - pev->nextthink = gpGlobals->time + 0.2; - - ResetSequenceInfo( ); - m_iDir = 1; - - pev->yaw_speed = 18; - m_flInitialYaw = pev->angles.y; - pev->ideal_yaw = m_flInitialYaw; - - g_fFlySound = FALSE; - g_fSquirmSound = FALSE; - - m_iHitDmg = 20; - - if (m_flMaxYaw <= 0) - m_flMaxYaw = 65; - - m_MonsterState = MONSTERSTATE_IDLE; - - // SetThink( Test ); - UTIL_SetOrigin( pev, pev->origin ); -} - -void CTentacle :: Precache( ) -{ - PRECACHE_MODEL("models/tentacle2.mdl"); - - PRECACHE_SOUND("ambience/flies.wav"); - PRECACHE_SOUND("ambience/squirm2.wav"); - - PRECACHE_SOUND("tentacle/te_alert1.wav"); - PRECACHE_SOUND("tentacle/te_alert2.wav"); - PRECACHE_SOUND("tentacle/te_flies1.wav"); - PRECACHE_SOUND("tentacle/te_move1.wav"); - PRECACHE_SOUND("tentacle/te_move2.wav"); - PRECACHE_SOUND("tentacle/te_roar1.wav"); - PRECACHE_SOUND("tentacle/te_roar2.wav"); - PRECACHE_SOUND("tentacle/te_search1.wav"); - PRECACHE_SOUND("tentacle/te_search2.wav"); - PRECACHE_SOUND("tentacle/te_sing1.wav"); - PRECACHE_SOUND("tentacle/te_sing2.wav"); - PRECACHE_SOUND("tentacle/te_squirm2.wav"); - PRECACHE_SOUND("tentacle/te_strike1.wav"); - PRECACHE_SOUND("tentacle/te_strike2.wav"); - PRECACHE_SOUND("tentacle/te_swing1.wav"); - PRECACHE_SOUND("tentacle/te_swing2.wav"); - - PRECACHE_SOUND_ARRAY( pHitSilo ); - PRECACHE_SOUND_ARRAY( pHitDirt ); - PRECACHE_SOUND_ARRAY( pHitWater ); -} - - -CTentacle::CTentacle( ) -{ - m_flMaxYaw = 65; - m_iTapSound = 0; -} - -void CTentacle::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sweeparc")) - { - m_flMaxYaw = atof(pkvd->szValue) / 2.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sound")) - { - m_iTapSound = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else - CBaseMonster::KeyValue( pkvd ); -} - - - -int CTentacle :: Level( float dz ) -{ - if (dz < 216) - return 0; - if (dz < 408) - return 1; - if (dz < 600) - return 2; - return 3; -} - - -float CTentacle :: MyHeight( ) -{ - switch ( MyLevel( ) ) - { - case 1: - return 256; - case 2: - return 448; - case 3: - return 640; - } - return 0; -} - - -int CTentacle :: MyLevel( ) -{ - switch( pev->sequence ) - { - case TENTACLE_ANIM_Pit_Idle: - return -1; - - case TENTACLE_ANIM_rise_to_Temp1: - case TENTACLE_ANIM_Temp1_to_Floor: - case TENTACLE_ANIM_Floor_to_Lev1: - return 0; - - case TENTACLE_ANIM_Floor_Idle: - case TENTACLE_ANIM_Floor_Fidget_Pissed: - case TENTACLE_ANIM_Floor_Fidget_SmallRise: - case TENTACLE_ANIM_Floor_Fidget_Wave: - case TENTACLE_ANIM_Floor_Strike: - case TENTACLE_ANIM_Floor_Tap: - case TENTACLE_ANIM_Floor_Rotate: - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - return 0; - - case TENTACLE_ANIM_Lev1_Idle: - case TENTACLE_ANIM_Lev1_Fidget_Claw: - case TENTACLE_ANIM_Lev1_Fidget_Shake: - case TENTACLE_ANIM_Lev1_Fidget_Snap: - case TENTACLE_ANIM_Lev1_Strike: - case TENTACLE_ANIM_Lev1_Tap: - case TENTACLE_ANIM_Lev1_Rotate: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - return 1; - - case TENTACLE_ANIM_Lev1_to_Lev2: - return 1; - - case TENTACLE_ANIM_Lev2_Idle: - case TENTACLE_ANIM_Lev2_Fidget_Shake: - case TENTACLE_ANIM_Lev2_Fidget_Swing: - case TENTACLE_ANIM_Lev2_Fidget_Tut: - case TENTACLE_ANIM_Lev2_Strike: - case TENTACLE_ANIM_Lev2_Tap: - case TENTACLE_ANIM_Lev2_Rotate: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - return 2; - - case TENTACLE_ANIM_Lev2_to_Lev3: - return 2; - - case TENTACLE_ANIM_Lev3_Idle: - case TENTACLE_ANIM_Lev3_Fidget_Shake: - case TENTACLE_ANIM_Lev3_Fidget_Side: - case TENTACLE_ANIM_Lev3_Fidget_Swipe: - case TENTACLE_ANIM_Lev3_Strike: - case TENTACLE_ANIM_Lev3_Tap: - case TENTACLE_ANIM_Lev3_Rotate: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - return 3; - - case TENTACLE_ANIM_Lev1_Door_reach: - return -1; - } - return -1; -} - - -void CTentacle :: Test( void ) -{ - pev->sequence = TENTACLE_ANIM_Floor_Strike; - pev->framerate = 0; - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -// -// TentacleThink -// -void CTentacle :: Cycle( void ) -{ - // ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState ); - pev->nextthink = gpGlobals-> time + 0.1; - - // ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health ); - - if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT) - { - pev->angles.y = m_flInitialYaw; - pev->ideal_yaw = m_flInitialYaw; - ClearConditions( IgnoreConditions() ); - MonsterThink( ); - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - return; - } - - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - ChangeYaw( pev->yaw_speed ); - - CSound *pSound; - - Listen( ); - - // Listen will set this if there's something in my sound list - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - pSound = PBestSound(); - else - pSound = NULL; - - if ( pSound ) - { - Vector vecDir; - if (gpGlobals->time - m_flPrevSoundTime < 0.5) - { - float dt = gpGlobals->time - m_flPrevSoundTime; - vecDir = pSound->m_vecOrigin + (pSound->m_vecOrigin - m_vecPrevSound) / dt - pev->origin; - } - else - { - vecDir = pSound->m_vecOrigin - pev->origin; - } - m_flPrevSoundTime = gpGlobals->time; - m_vecPrevSound = pSound->m_vecOrigin; - - m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw; - m_iSoundLevel = Level( vecDir.z ); - - if (m_flSoundYaw < -180) - m_flSoundYaw += 360; - if (m_flSoundYaw > 180) - m_flSoundYaw -= 360; - - // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); - if (m_flSoundTime < gpGlobals->time) - { - // play "I hear new something" sound - char *sound; - - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_alert1.wav"; break; - case 1: sound = "tentacle/te_alert2.wav"; break; - } - - // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - } - m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); - } - - // clip ideal_yaw - float dy = m_flSoundYaw; - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - if (dy < 0 && dy > -m_flMaxYaw) - dy = -m_flMaxYaw; - if (dy > 0 && dy < m_flMaxYaw) - dy = m_flMaxYaw; - break; - default: - if (dy < -m_flMaxYaw) - dy = -m_flMaxYaw; - if (dy > m_flMaxYaw) - dy = m_flMaxYaw; - } - pev->ideal_yaw = m_flInitialYaw + dy; - - if (m_fSequenceFinished) - { - // ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); - if (pev->health <= 1) - { - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - if (pev->sequence == TENTACLE_ANIM_Pit_Idle) - { - pev->health = 75; - } - } - else if ( m_flSoundTime > gpGlobals->time ) - { - if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30)) - { - // strike - m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); - } - else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); - } - else - { - // go into rear idle - m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); - } - } - else if (pev->sequence == TENTACLE_ANIM_Pit_Idle) - { - // stay in pit until hear noise - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - } - else if (pev->sequence == m_iGoalAnim) - { - if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime) - { - if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time) - { - // continue stike - m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); - } - else - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); - } - } - else if (MyLevel( ) < 0) - { - m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); - } - else - { - if (m_flNextSong < gpGlobals->time) - { - // play "I hear new something" sound - char *sound; - - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_sing1.wav"; break; - case 1: sound = "tentacle/te_sing2.wav"; break; - } - - EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, 1.0, ATTN_NORM); - - m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 ); - } - - if (RANDOM_LONG(0,15) == 0) - { - // idle on new level - m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) ); - } - else if (RANDOM_LONG(0,3) == 0) - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) ); - } - else - { - // idle - m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) ); - } - } - if (m_flSoundYaw < 0) - m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); - else - m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); - } - - pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - - if (m_iDir > 0) - { - pev->frame = 0; - } - else - { - m_iDir = -1; // just to safe - pev->frame = 255; - } - ResetSequenceInfo( ); - - m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); - pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; - - switch( pev->sequence) - { - case TENTACLE_ANIM_Floor_Tap: - case TENTACLE_ANIM_Lev1_Tap: - case TENTACLE_ANIM_Lev2_Tap: - case TENTACLE_ANIM_Lev3_Tap: - { - Vector vecSrc; - UTIL_MakeVectors( pev->angles ); - - TraceResult tr1, tr2; - - vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4); - UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 ); - - vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8); - UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 ); - - // ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 ); - - m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) ); - } - break; - default: - m_flTapRadius = 336; // 400 - 64 - break; - } - pev->view_ofs.z = MyHeight( ); - // ALERT( at_console, "seq %d\n", pev->sequence ); - } - - if (m_flPrevSoundTime + 2.0 > gpGlobals->time) - { - // 1.5 normal speed if hears sounds - pev->framerate = m_iDir * 1.5 + m_flFramerateAdj; - } - else if (m_flPrevSoundTime + 5.0 > gpGlobals->time) - { - // slowdown to normal - pev->framerate = m_iDir + m_iDir * (5 - (gpGlobals->time - m_flPrevSoundTime)) / 2 + m_flFramerateAdj; - } -} - - - -void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // ALERT( at_console, "%s triggered %d\n", STRING( pev->targetname ), useType ); - switch( useType ) - { - case USE_OFF: - pev->takedamage = DAMAGE_NO; - SetThink( &CTentacle::DieThink ); - m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; - break; - case USE_ON: - if (pActivator) - { - // ALERT( at_console, "insert sound\n"); - CSoundEnt::InsertSound ( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); - } - break; - case USE_SET: - break; - case USE_TOGGLE: - pev->takedamage = DAMAGE_NO; - SetThink( &CTentacle::DieThink ); - m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; - break; - } - -} - - - -void CTentacle :: DieThink( void ) -{ - pev->nextthink = gpGlobals-> time + 0.1; - - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - ChangeYaw( 24 ); - - if (m_fSequenceFinished) - { - if (pev->sequence == m_iGoalAnim) - { - switch( m_iGoalAnim ) - { - case TENTACLE_ANIM_Engine_Idle: - case TENTACLE_ANIM_Engine_Sway: - case TENTACLE_ANIM_Engine_Swat: - case TENTACLE_ANIM_Engine_Bob: - m_iGoalAnim = TENTACLE_ANIM_Engine_Sway + RANDOM_LONG( 0, 2 ); - break; - case TENTACLE_ANIM_Engine_Death1: - case TENTACLE_ANIM_Engine_Death2: - case TENTACLE_ANIM_Engine_Death3: - UTIL_Remove( this ); - return; - } - } - - // ALERT( at_console, "%d : %d => ", pev->sequence, m_iGoalAnim ); - pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - // ALERT( at_console, "%d\n", pev->sequence ); - - if (m_iDir > 0) - { - pev->frame = 0; - } - else - { - pev->frame = 255; - } - ResetSequenceInfo( ); - - float dy; - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - case TENTACLE_ANIM_Engine_Idle: - case TENTACLE_ANIM_Engine_Sway: - case TENTACLE_ANIM_Engine_Swat: - case TENTACLE_ANIM_Engine_Bob: - case TENTACLE_ANIM_Engine_Death1: - case TENTACLE_ANIM_Engine_Death2: - case TENTACLE_ANIM_Engine_Death3: - pev->framerate = RANDOM_FLOAT( m_iDir - 0.2, m_iDir + 0.2 ); - dy = 180; - break; - default: - pev->framerate = 1.5; - dy = 0; - break; - } - pev->ideal_yaw = m_flInitialYaw + dy; - } -} - - -void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - char *sound; - - switch( pEvent->event ) - { - case 1: // bang - { - Vector vecSrc, vecAngles; - GetAttachment( 0, vecSrc, vecAngles ); - - // Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (3.14192653 / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); - - // vecSrc.z += MyHeight( ); - - switch( m_iTapSound ) - { - case TE_SILO: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, ATTN_NORM, 0, 100); - break; - case TE_NONE: - break; - case TE_DIRT: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), 1.0, ATTN_NORM, 0, 100); - break; - case TE_WATER: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, ATTN_NORM, 0, 100); - break; - } - gpGlobals->force_retouch++; - } - break; - - case 3: // start killing swing - m_iHitDmg = 200; - // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing1.wav", 1.0, ATTN_NORM, 0, 100); - break; - - case 4: // end killing swing - m_iHitDmg = 25; - break; - - case 5: // just "whoosh" sound - // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing2.wav", 1.0, ATTN_NORM, 0, 100); - break; - - case 2: // tap scrape - case 6: // light tap - { - Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (M_PI / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); - - vecSrc.z += MyHeight( ); - - float flVol = RANDOM_FLOAT( 0.3, 0.5 ); - - switch( m_iTapSound ) - { - case TE_SILO: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), flVol, ATTN_NORM, 0, 100); - break; - case TE_NONE: - break; - case TE_DIRT: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), flVol, ATTN_NORM, 0, 100); - break; - case TE_WATER: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), flVol, ATTN_NORM, 0, 100); - break; - } - } - break; - - - case 7: // roar - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_roar1.wav"; break; - case 1: sound = "tentacle/te_roar2.wav"; break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - - case 8: // search - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_search1.wav"; break; - case 1: sound = "tentacle/te_search2.wav"; break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - - case 9: // swing - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_move1.wav"; break; - case 1: sound = "tentacle/te_move2.wav"; break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - - -// -// TentacleStart -// -// void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -void CTentacle :: Start( void ) -{ - SetThink( &CTentacle::Cycle ); - - if ( !g_fFlySound ) - { - EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); - g_fFlySound = TRUE; -// pev->nextthink = gpGlobals-> time + 0.1; - } - else if ( !g_fSquirmSound ) - { - EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM ); - g_fSquirmSound = TRUE; - } - - pev->nextthink = gpGlobals->time + 0.1; -} - - - - -void CTentacle :: HitTouch( CBaseEntity *pOther ) -{ - TraceResult tr = UTIL_GetGlobalTrace( ); - - if (pOther->pev->modelindex == pev->modelindex) - return; - - if (m_flHitTime > gpGlobals->time) - return; - - // only look at the ones where the player hit me - if (tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex) - return; - - if (tr.iHitgroup >= 3) - { - pOther->TakeDamage( pev, pev, m_iHitDmg, DMG_CRUSH ); - // ALERT( at_console, "wack %3d : ", m_iHitDmg ); - } - else if (tr.iHitgroup != 0) - { - pOther->TakeDamage( pev, pev, 20, DMG_CRUSH ); - // ALERT( at_console, "tap %3d : ", 20 ); - } - else - { - return; // Huh? - } - - m_flHitTime = gpGlobals->time + 0.5; - - // ALERT( at_console, "%s : ", STRING( tr.pHit->v.classname ) ); - - // ALERT( at_console, "%.0f : %s : %d\n", pev->angles.y, STRING( pOther->pev->classname ), tr.iHitgroup ); -} - - -int CTentacle::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (flDamage > pev->health) - { - pev->health = 1; - } - else - { - pev->health -= flDamage; - } - return 1; -} - - - - -void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) -{ - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - return; -} - - - -class CTentacleMaw : public CBaseMonster -{ -public: - void Spawn( ); - void Precache( ); -}; - -LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ); - -// -// Tentacle Spawn -// -void CTentacleMaw :: Spawn( ) -{ - Precache( ); - SET_MODEL(ENT(pev), "models/maw.mdl"); - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 75; - pev->yaw_speed = 8; - pev->sequence = 0; - - pev->angles.x = 90; - // ResetSequenceInfo( ); -} - -void CTentacleMaw :: Precache( ) -{ - PRECACHE_MODEL("models/maw.mdl"); -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +/* + + h_tentacle.cpp - silo of death tentacle monster (half life) + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "soundent.h" + + +#define ACT_T_IDLE 1010 +#define ACT_T_TAP 1020 +#define ACT_T_STRIKE 1030 +#define ACT_T_REARIDLE 1040 + +class CTentacle : public CBaseMonster +{ +public: + CTentacle( void ); + + void Spawn( ); + void Precache( ); + void KeyValue( KeyValueData *pkvd ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + // Don't allow the tentacle to go across transitions!!! + virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector(-400, -400, 0); + pev->absmax = pev->origin + Vector(400, 400, 850); + } + + void EXPORT Cycle( void ); + void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT Start( void ); + void EXPORT DieThink( void ); + + void EXPORT Test( void ); + + void EXPORT HitTouch( CBaseEntity *pOther ); + + float HearingSensitivity( void ) { return 2.0; }; + + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void Killed( entvars_t *pevAttacker, int iGib ); + + MONSTERSTATE GetIdealState ( void ) { return MONSTERSTATE_IDLE; }; + int CanPlaySequence( BOOL fDisregardState ) { return TRUE; }; + + int Classify( void ); + + int Level( float dz ); + int MyLevel( void ); + float MyHeight( void ); + + float m_flInitialYaw; + int m_iGoalAnim; + int m_iLevel; + int m_iDir; + float m_flFramerateAdj; + float m_flSoundYaw; + int m_iSoundLevel; + float m_flSoundTime; + float m_flSoundRadius; + int m_iHitDmg; + float m_flHitTime; + + float m_flTapRadius; + + float m_flNextSong; + static int g_fFlySound; + static int g_fSquirmSound; + + float m_flMaxYaw; + int m_iTapSound; + + Vector m_vecPrevSound; + float m_flPrevSoundTime; + + static const char *pHitSilo[]; + static const char *pHitDirt[]; + static const char *pHitWater[]; +}; + + + +int CTentacle :: g_fFlySound; +int CTentacle :: g_fSquirmSound; + +LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ); + +// stike sounds +#define TE_NONE -1 +#define TE_SILO 0 +#define TE_DIRT 1 +#define TE_WATER 2 + +const char *CTentacle::pHitSilo[] = +{ + "tentacle/te_strike1.wav", + "tentacle/te_strike2.wav", +}; + +const char *CTentacle::pHitDirt[] = +{ + "player/pl_dirt1.wav", + "player/pl_dirt2.wav", + "player/pl_dirt3.wav", + "player/pl_dirt4.wav", +}; + +const char *CTentacle::pHitWater[] = +{ + "player/pl_slosh1.wav", + "player/pl_slosh2.wav", + "player/pl_slosh3.wav", + "player/pl_slosh4.wav", +}; + + +TYPEDESCRIPTION CTentacle::m_SaveData[] = +{ + DEFINE_FIELD( CTentacle, m_flInitialYaw, FIELD_FLOAT ), + DEFINE_FIELD( CTentacle, m_iGoalAnim, FIELD_INTEGER ), + DEFINE_FIELD( CTentacle, m_iLevel, FIELD_INTEGER ), + DEFINE_FIELD( CTentacle, m_iDir, FIELD_INTEGER ), + DEFINE_FIELD( CTentacle, m_flFramerateAdj, FIELD_FLOAT ), + DEFINE_FIELD( CTentacle, m_flSoundYaw, FIELD_FLOAT ), + DEFINE_FIELD( CTentacle, m_iSoundLevel, FIELD_INTEGER ), + DEFINE_FIELD( CTentacle, m_flSoundTime, FIELD_TIME ), + DEFINE_FIELD( CTentacle, m_flSoundRadius, FIELD_FLOAT ), + DEFINE_FIELD( CTentacle, m_iHitDmg, FIELD_INTEGER ), + DEFINE_FIELD( CTentacle, m_flHitTime, FIELD_TIME ), + DEFINE_FIELD( CTentacle, m_flTapRadius, FIELD_FLOAT ), + DEFINE_FIELD( CTentacle, m_flNextSong, FIELD_TIME ), + DEFINE_FIELD( CTentacle, m_iTapSound, FIELD_INTEGER ), + DEFINE_FIELD( CTentacle, m_flMaxYaw, FIELD_FLOAT ), + DEFINE_FIELD( CTentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CTentacle, m_flPrevSoundTime, FIELD_TIME ), +}; +IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ); + + +// animation sequence aliases +typedef enum +{ + TENTACLE_ANIM_Pit_Idle, + + TENTACLE_ANIM_rise_to_Temp1, + TENTACLE_ANIM_Temp1_to_Floor, + TENTACLE_ANIM_Floor_Idle, + TENTACLE_ANIM_Floor_Fidget_Pissed, + TENTACLE_ANIM_Floor_Fidget_SmallRise, + TENTACLE_ANIM_Floor_Fidget_Wave, + TENTACLE_ANIM_Floor_Strike, + TENTACLE_ANIM_Floor_Tap, + TENTACLE_ANIM_Floor_Rotate, + TENTACLE_ANIM_Floor_Rear, + TENTACLE_ANIM_Floor_Rear_Idle, + TENTACLE_ANIM_Floor_to_Lev1, + + TENTACLE_ANIM_Lev1_Idle, + TENTACLE_ANIM_Lev1_Fidget_Claw, + TENTACLE_ANIM_Lev1_Fidget_Shake, + TENTACLE_ANIM_Lev1_Fidget_Snap, + TENTACLE_ANIM_Lev1_Strike, + TENTACLE_ANIM_Lev1_Tap, + TENTACLE_ANIM_Lev1_Rotate, + TENTACLE_ANIM_Lev1_Rear, + TENTACLE_ANIM_Lev1_Rear_Idle, + TENTACLE_ANIM_Lev1_to_Lev2, + + TENTACLE_ANIM_Lev2_Idle, + TENTACLE_ANIM_Lev2_Fidget_Shake, + TENTACLE_ANIM_Lev2_Fidget_Swing, + TENTACLE_ANIM_Lev2_Fidget_Tut, + TENTACLE_ANIM_Lev2_Strike, + TENTACLE_ANIM_Lev2_Tap, + TENTACLE_ANIM_Lev2_Rotate, + TENTACLE_ANIM_Lev2_Rear, + TENTACLE_ANIM_Lev2_Rear_Idle, + TENTACLE_ANIM_Lev2_to_Lev3, + + TENTACLE_ANIM_Lev3_Idle, + TENTACLE_ANIM_Lev3_Fidget_Shake, + TENTACLE_ANIM_Lev3_Fidget_Side, + TENTACLE_ANIM_Lev3_Fidget_Swipe, + TENTACLE_ANIM_Lev3_Strike, + TENTACLE_ANIM_Lev3_Tap, + TENTACLE_ANIM_Lev3_Rotate, + TENTACLE_ANIM_Lev3_Rear, + TENTACLE_ANIM_Lev3_Rear_Idle, + + TENTACLE_ANIM_Lev1_Door_reach, + + TENTACLE_ANIM_Lev3_to_Engine, + TENTACLE_ANIM_Engine_Idle, + TENTACLE_ANIM_Engine_Sway, + TENTACLE_ANIM_Engine_Swat, + TENTACLE_ANIM_Engine_Bob, + TENTACLE_ANIM_Engine_Death1, + TENTACLE_ANIM_Engine_Death2, + TENTACLE_ANIM_Engine_Death3, + + TENTACLE_ANIM_none +} TENTACLE_ANIM; + + + + + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CTentacle :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +// +// Tentacle Spawn +// +void CTentacle :: Spawn( ) +{ + Precache( ); + + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_FLY; + pev->effects = 0; + pev->health = 75; + pev->sequence = 0; + + SET_MODEL(ENT(pev), "models/tentacle2.mdl"); + UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); + + pev->takedamage = DAMAGE_AIM; + pev->flags |= FL_MONSTER; + + m_bloodColor = BLOOD_COLOR_GREEN; + + SetThink( &CTentacle::Start ); + SetTouch( &CTentacle::HitTouch ); + SetUse( &CTentacle::CommandUse ); + + pev->nextthink = gpGlobals->time + 0.2; + + ResetSequenceInfo( ); + m_iDir = 1; + + pev->yaw_speed = 18; + m_flInitialYaw = pev->angles.y; + pev->ideal_yaw = m_flInitialYaw; + + g_fFlySound = FALSE; + g_fSquirmSound = FALSE; + + m_iHitDmg = 20; + + if (m_flMaxYaw <= 0) + m_flMaxYaw = 65; + + m_MonsterState = MONSTERSTATE_IDLE; + + // SetThink( Test ); + UTIL_SetOrigin( pev, pev->origin ); +} + +void CTentacle :: Precache( ) +{ + PRECACHE_MODEL("models/tentacle2.mdl"); + + PRECACHE_SOUND("ambience/flies.wav"); + PRECACHE_SOUND("ambience/squirm2.wav"); + + PRECACHE_SOUND("tentacle/te_alert1.wav"); + PRECACHE_SOUND("tentacle/te_alert2.wav"); + PRECACHE_SOUND("tentacle/te_flies1.wav"); + PRECACHE_SOUND("tentacle/te_move1.wav"); + PRECACHE_SOUND("tentacle/te_move2.wav"); + PRECACHE_SOUND("tentacle/te_roar1.wav"); + PRECACHE_SOUND("tentacle/te_roar2.wav"); + PRECACHE_SOUND("tentacle/te_search1.wav"); + PRECACHE_SOUND("tentacle/te_search2.wav"); + PRECACHE_SOUND("tentacle/te_sing1.wav"); + PRECACHE_SOUND("tentacle/te_sing2.wav"); + PRECACHE_SOUND("tentacle/te_squirm2.wav"); + PRECACHE_SOUND("tentacle/te_strike1.wav"); + PRECACHE_SOUND("tentacle/te_strike2.wav"); + PRECACHE_SOUND("tentacle/te_swing1.wav"); + PRECACHE_SOUND("tentacle/te_swing2.wav"); + + PRECACHE_SOUND_ARRAY( pHitSilo ); + PRECACHE_SOUND_ARRAY( pHitDirt ); + PRECACHE_SOUND_ARRAY( pHitWater ); +} + + +CTentacle::CTentacle( ) +{ + m_flMaxYaw = 65; + m_iTapSound = 0; +} + +void CTentacle::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "sweeparc")) + { + m_flMaxYaw = atof(pkvd->szValue) / 2.0; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "sound")) + { + m_iTapSound = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + + } + else + CBaseMonster::KeyValue( pkvd ); +} + + + +int CTentacle :: Level( float dz ) +{ + if (dz < 216) + return 0; + if (dz < 408) + return 1; + if (dz < 600) + return 2; + return 3; +} + + +float CTentacle :: MyHeight( ) +{ + switch ( MyLevel( ) ) + { + case 1: + return 256; + case 2: + return 448; + case 3: + return 640; + } + return 0; +} + + +int CTentacle :: MyLevel( ) +{ + switch( pev->sequence ) + { + case TENTACLE_ANIM_Pit_Idle: + return -1; + + case TENTACLE_ANIM_rise_to_Temp1: + case TENTACLE_ANIM_Temp1_to_Floor: + case TENTACLE_ANIM_Floor_to_Lev1: + return 0; + + case TENTACLE_ANIM_Floor_Idle: + case TENTACLE_ANIM_Floor_Fidget_Pissed: + case TENTACLE_ANIM_Floor_Fidget_SmallRise: + case TENTACLE_ANIM_Floor_Fidget_Wave: + case TENTACLE_ANIM_Floor_Strike: + case TENTACLE_ANIM_Floor_Tap: + case TENTACLE_ANIM_Floor_Rotate: + case TENTACLE_ANIM_Floor_Rear: + case TENTACLE_ANIM_Floor_Rear_Idle: + return 0; + + case TENTACLE_ANIM_Lev1_Idle: + case TENTACLE_ANIM_Lev1_Fidget_Claw: + case TENTACLE_ANIM_Lev1_Fidget_Shake: + case TENTACLE_ANIM_Lev1_Fidget_Snap: + case TENTACLE_ANIM_Lev1_Strike: + case TENTACLE_ANIM_Lev1_Tap: + case TENTACLE_ANIM_Lev1_Rotate: + case TENTACLE_ANIM_Lev1_Rear: + case TENTACLE_ANIM_Lev1_Rear_Idle: + return 1; + + case TENTACLE_ANIM_Lev1_to_Lev2: + return 1; + + case TENTACLE_ANIM_Lev2_Idle: + case TENTACLE_ANIM_Lev2_Fidget_Shake: + case TENTACLE_ANIM_Lev2_Fidget_Swing: + case TENTACLE_ANIM_Lev2_Fidget_Tut: + case TENTACLE_ANIM_Lev2_Strike: + case TENTACLE_ANIM_Lev2_Tap: + case TENTACLE_ANIM_Lev2_Rotate: + case TENTACLE_ANIM_Lev2_Rear: + case TENTACLE_ANIM_Lev2_Rear_Idle: + return 2; + + case TENTACLE_ANIM_Lev2_to_Lev3: + return 2; + + case TENTACLE_ANIM_Lev3_Idle: + case TENTACLE_ANIM_Lev3_Fidget_Shake: + case TENTACLE_ANIM_Lev3_Fidget_Side: + case TENTACLE_ANIM_Lev3_Fidget_Swipe: + case TENTACLE_ANIM_Lev3_Strike: + case TENTACLE_ANIM_Lev3_Tap: + case TENTACLE_ANIM_Lev3_Rotate: + case TENTACLE_ANIM_Lev3_Rear: + case TENTACLE_ANIM_Lev3_Rear_Idle: + return 3; + + case TENTACLE_ANIM_Lev1_Door_reach: + return -1; + } + return -1; +} + + +void CTentacle :: Test( void ) +{ + pev->sequence = TENTACLE_ANIM_Floor_Strike; + pev->framerate = 0; + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; +} + + + +// +// TentacleThink +// +void CTentacle :: Cycle( void ) +{ + // ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState ); + pev->nextthink = gpGlobals-> time + 0.1; + + // ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health ); + + if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT) + { + pev->angles.y = m_flInitialYaw; + pev->ideal_yaw = m_flInitialYaw; + ClearConditions( IgnoreConditions() ); + MonsterThink( ); + m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; + return; + } + + DispatchAnimEvents( ); + StudioFrameAdvance( ); + + ChangeYaw( pev->yaw_speed ); + + CSound *pSound; + + Listen( ); + + // Listen will set this if there's something in my sound list + if ( HasConditions( bits_COND_HEAR_SOUND ) ) + pSound = PBestSound(); + else + pSound = NULL; + + if ( pSound ) + { + Vector vecDir; + if (gpGlobals->time - m_flPrevSoundTime < 0.5) + { + float dt = gpGlobals->time - m_flPrevSoundTime; + vecDir = pSound->m_vecOrigin + (pSound->m_vecOrigin - m_vecPrevSound) / dt - pev->origin; + } + else + { + vecDir = pSound->m_vecOrigin - pev->origin; + } + m_flPrevSoundTime = gpGlobals->time; + m_vecPrevSound = pSound->m_vecOrigin; + + m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw; + m_iSoundLevel = Level( vecDir.z ); + + if (m_flSoundYaw < -180) + m_flSoundYaw += 360; + if (m_flSoundYaw > 180) + m_flSoundYaw -= 360; + + // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); + if (m_flSoundTime < gpGlobals->time) + { + // play "I hear new something" sound + char *sound; + + switch( RANDOM_LONG(0,1) ) + { + case 0: sound = "tentacle/te_alert1.wav"; break; + case 1: sound = "tentacle/te_alert2.wav"; break; + } + + // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); + } + m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); + } + + // clip ideal_yaw + float dy = m_flSoundYaw; + switch( pev->sequence ) + { + case TENTACLE_ANIM_Floor_Rear: + case TENTACLE_ANIM_Floor_Rear_Idle: + case TENTACLE_ANIM_Lev1_Rear: + case TENTACLE_ANIM_Lev1_Rear_Idle: + case TENTACLE_ANIM_Lev2_Rear: + case TENTACLE_ANIM_Lev2_Rear_Idle: + case TENTACLE_ANIM_Lev3_Rear: + case TENTACLE_ANIM_Lev3_Rear_Idle: + if (dy < 0 && dy > -m_flMaxYaw) + dy = -m_flMaxYaw; + if (dy > 0 && dy < m_flMaxYaw) + dy = m_flMaxYaw; + break; + default: + if (dy < -m_flMaxYaw) + dy = -m_flMaxYaw; + if (dy > m_flMaxYaw) + dy = m_flMaxYaw; + } + pev->ideal_yaw = m_flInitialYaw + dy; + + if (m_fSequenceFinished) + { + // ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); + if (pev->health <= 1) + { + m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; + if (pev->sequence == TENTACLE_ANIM_Pit_Idle) + { + pev->health = 75; + } + } + else if ( m_flSoundTime > gpGlobals->time ) + { + if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30)) + { + // strike + m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); + } + else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) + { + // tap + m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); + } + else + { + // go into rear idle + m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); + } + } + else if (pev->sequence == TENTACLE_ANIM_Pit_Idle) + { + // stay in pit until hear noise + m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; + } + else if (pev->sequence == m_iGoalAnim) + { + if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime) + { + if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time) + { + // continue stike + m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); + } + else + { + // tap + m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); + } + } + else if (MyLevel( ) < 0) + { + m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); + } + else + { + if (m_flNextSong < gpGlobals->time) + { + // play "I hear new something" sound + char *sound; + + switch( RANDOM_LONG(0,1) ) + { + case 0: sound = "tentacle/te_sing1.wav"; break; + case 1: sound = "tentacle/te_sing2.wav"; break; + } + + EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, 1.0, ATTN_NORM); + + m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 ); + } + + if (RANDOM_LONG(0,15) == 0) + { + // idle on new level + m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) ); + } + else if (RANDOM_LONG(0,3) == 0) + { + // tap + m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) ); + } + else + { + // idle + m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) ); + } + } + if (m_flSoundYaw < 0) + m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); + else + m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); + } + + pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); + + if (m_iDir > 0) + { + pev->frame = 0; + } + else + { + m_iDir = -1; // just to safe + pev->frame = 255; + } + ResetSequenceInfo( ); + + m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); + pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; + + switch( pev->sequence) + { + case TENTACLE_ANIM_Floor_Tap: + case TENTACLE_ANIM_Lev1_Tap: + case TENTACLE_ANIM_Lev2_Tap: + case TENTACLE_ANIM_Lev3_Tap: + { + Vector vecSrc; + UTIL_MakeVectors( pev->angles ); + + TraceResult tr1, tr2; + + vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4); + UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 ); + + vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8); + UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 ); + + // ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 ); + + m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) ); + } + break; + default: + m_flTapRadius = 336; // 400 - 64 + break; + } + pev->view_ofs.z = MyHeight( ); + // ALERT( at_console, "seq %d\n", pev->sequence ); + } + + if (m_flPrevSoundTime + 2.0 > gpGlobals->time) + { + // 1.5 normal speed if hears sounds + pev->framerate = m_iDir * 1.5 + m_flFramerateAdj; + } + else if (m_flPrevSoundTime + 5.0 > gpGlobals->time) + { + // slowdown to normal + pev->framerate = m_iDir + m_iDir * (5 - (gpGlobals->time - m_flPrevSoundTime)) / 2 + m_flFramerateAdj; + } +} + + + +void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // ALERT( at_console, "%s triggered %d\n", STRING( pev->targetname ), useType ); + switch( useType ) + { + case USE_OFF: + pev->takedamage = DAMAGE_NO; + SetThink( &CTentacle::DieThink ); + m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; + break; + case USE_ON: + if (pActivator) + { + // ALERT( at_console, "insert sound\n"); + CSoundEnt::InsertSound ( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); + } + break; + case USE_SET: + break; + case USE_TOGGLE: + pev->takedamage = DAMAGE_NO; + SetThink( &CTentacle::DieThink ); + m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; + break; + } + +} + + + +void CTentacle :: DieThink( void ) +{ + pev->nextthink = gpGlobals-> time + 0.1; + + DispatchAnimEvents( ); + StudioFrameAdvance( ); + + ChangeYaw( 24 ); + + if (m_fSequenceFinished) + { + if (pev->sequence == m_iGoalAnim) + { + switch( m_iGoalAnim ) + { + case TENTACLE_ANIM_Engine_Idle: + case TENTACLE_ANIM_Engine_Sway: + case TENTACLE_ANIM_Engine_Swat: + case TENTACLE_ANIM_Engine_Bob: + m_iGoalAnim = TENTACLE_ANIM_Engine_Sway + RANDOM_LONG( 0, 2 ); + break; + case TENTACLE_ANIM_Engine_Death1: + case TENTACLE_ANIM_Engine_Death2: + case TENTACLE_ANIM_Engine_Death3: + UTIL_Remove( this ); + return; + } + } + + // ALERT( at_console, "%d : %d => ", pev->sequence, m_iGoalAnim ); + pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); + // ALERT( at_console, "%d\n", pev->sequence ); + + if (m_iDir > 0) + { + pev->frame = 0; + } + else + { + pev->frame = 255; + } + ResetSequenceInfo( ); + + float dy; + switch( pev->sequence ) + { + case TENTACLE_ANIM_Floor_Rear: + case TENTACLE_ANIM_Floor_Rear_Idle: + case TENTACLE_ANIM_Lev1_Rear: + case TENTACLE_ANIM_Lev1_Rear_Idle: + case TENTACLE_ANIM_Lev2_Rear: + case TENTACLE_ANIM_Lev2_Rear_Idle: + case TENTACLE_ANIM_Lev3_Rear: + case TENTACLE_ANIM_Lev3_Rear_Idle: + case TENTACLE_ANIM_Engine_Idle: + case TENTACLE_ANIM_Engine_Sway: + case TENTACLE_ANIM_Engine_Swat: + case TENTACLE_ANIM_Engine_Bob: + case TENTACLE_ANIM_Engine_Death1: + case TENTACLE_ANIM_Engine_Death2: + case TENTACLE_ANIM_Engine_Death3: + pev->framerate = RANDOM_FLOAT( m_iDir - 0.2, m_iDir + 0.2 ); + dy = 180; + break; + default: + pev->framerate = 1.5; + dy = 0; + break; + } + pev->ideal_yaw = m_flInitialYaw + dy; + } +} + + +void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + char *sound; + + switch( pEvent->event ) + { + case 1: // bang + { + Vector vecSrc, vecAngles; + GetAttachment( 0, vecSrc, vecAngles ); + + // Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (3.14192653 / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); + + // vecSrc.z += MyHeight( ); + + switch( m_iTapSound ) + { + case TE_SILO: + UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, ATTN_NORM, 0, 100); + break; + case TE_NONE: + break; + case TE_DIRT: + UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), 1.0, ATTN_NORM, 0, 100); + break; + case TE_WATER: + UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, ATTN_NORM, 0, 100); + break; + } + gpGlobals->force_retouch++; + } + break; + + case 3: // start killing swing + m_iHitDmg = 200; + // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing1.wav", 1.0, ATTN_NORM, 0, 100); + break; + + case 4: // end killing swing + m_iHitDmg = 25; + break; + + case 5: // just "whoosh" sound + // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing2.wav", 1.0, ATTN_NORM, 0, 100); + break; + + case 2: // tap scrape + case 6: // light tap + { + Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (M_PI / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); + + vecSrc.z += MyHeight( ); + + float flVol = RANDOM_FLOAT( 0.3, 0.5 ); + + switch( m_iTapSound ) + { + case TE_SILO: + UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), flVol, ATTN_NORM, 0, 100); + break; + case TE_NONE: + break; + case TE_DIRT: + UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), flVol, ATTN_NORM, 0, 100); + break; + case TE_WATER: + UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), flVol, ATTN_NORM, 0, 100); + break; + } + } + break; + + + case 7: // roar + switch( RANDOM_LONG(0,1) ) + { + case 0: sound = "tentacle/te_roar1.wav"; break; + case 1: sound = "tentacle/te_roar2.wav"; break; + } + + UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); + break; + + case 8: // search + switch( RANDOM_LONG(0,1) ) + { + case 0: sound = "tentacle/te_search1.wav"; break; + case 1: sound = "tentacle/te_search2.wav"; break; + } + + UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); + break; + + case 9: // swing + switch( RANDOM_LONG(0,1) ) + { + case 0: sound = "tentacle/te_move1.wav"; break; + case 1: sound = "tentacle/te_move2.wav"; break; + } + + UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + } +} + + +// +// TentacleStart +// +// void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CTentacle :: Start( void ) +{ + SetThink( &CTentacle::Cycle ); + + if ( !g_fFlySound ) + { + EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); + g_fFlySound = TRUE; +// pev->nextthink = gpGlobals-> time + 0.1; + } + else if ( !g_fSquirmSound ) + { + EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM ); + g_fSquirmSound = TRUE; + } + + pev->nextthink = gpGlobals->time + 0.1; +} + + + + +void CTentacle :: HitTouch( CBaseEntity *pOther ) +{ + TraceResult tr = UTIL_GetGlobalTrace( ); + + if (pOther->pev->modelindex == pev->modelindex) + return; + + if (m_flHitTime > gpGlobals->time) + return; + + // only look at the ones where the player hit me + if (tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex) + return; + + if (tr.iHitgroup >= 3) + { + pOther->TakeDamage( pev, pev, m_iHitDmg, DMG_CRUSH ); + // ALERT( at_console, "wack %3d : ", m_iHitDmg ); + } + else if (tr.iHitgroup != 0) + { + pOther->TakeDamage( pev, pev, 20, DMG_CRUSH ); + // ALERT( at_console, "tap %3d : ", 20 ); + } + else + { + return; // Huh? + } + + m_flHitTime = gpGlobals->time + 0.5; + + // ALERT( at_console, "%s : ", STRING( tr.pHit->v.classname ) ); + + // ALERT( at_console, "%.0f : %s : %d\n", pev->angles.y, STRING( pOther->pev->classname ), tr.iHitgroup ); +} + + +int CTentacle::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if (flDamage > pev->health) + { + pev->health = 1; + } + else + { + pev->health -= flDamage; + } + return 1; +} + + + + +void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) +{ + m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; + return; +} + + + +class CTentacleMaw : public CBaseMonster +{ +public: + void Spawn( ); + void Precache( ); +}; + +LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ); + +// +// Tentacle Spawn +// +void CTentacleMaw :: Spawn( ) +{ + Precache( ); + SET_MODEL(ENT(pev), "models/maw.mdl"); + UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_STEP; + pev->effects = 0; + pev->health = 75; + pev->yaw_speed = 8; + pev->sequence = 0; + + pev->angles.x = 90; + // ResetSequenceInfo( ); +} + +void CTentacleMaw :: Precache( ) +{ + PRECACHE_MODEL("models/maw.mdl"); +} + #endif \ No newline at end of file diff --git a/main/source/dlls/trains.h b/main/source/dlls/trains.h index 15aa38ca..4608f64d 100644 --- a/main/source/dlls/trains.h +++ b/main/source/dlls/trains.h @@ -1,127 +1,127 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef TRAINS_H -#define TRAINS_H - -// Tracktrain spawn flags -#define SF_TRACKTRAIN_NOPITCH 0x0001 -#define SF_TRACKTRAIN_NOCONTROL 0x0002 -#define SF_TRACKTRAIN_FORWARDONLY 0x0004 -#define SF_TRACKTRAIN_PASSABLE 0x0008 - -// Spawnflag for CPathTrack -#define SF_PATH_DISABLED 0x00000001 -#define SF_PATH_FIREONCE 0x00000002 -#define SF_PATH_ALTREVERSE 0x00000004 -#define SF_PATH_DISABLE_TRAIN 0x00000008 -#define SF_PATH_ALTERNATE 0x00008000 - -// Spawnflags of CPathCorner -#define SF_CORNER_WAITFORTRIG 0x001 -#define SF_CORNER_TELEPORT 0x002 -#define SF_CORNER_FIREONCE 0x004 - -//#define PATH_SPARKLE_DEBUG 1 // This makes a particle effect around path_track entities for debugging -class CPathTrack : public CPointEntity -{ -public: - void Spawn( void ); - void Activate( void ); - void KeyValue( KeyValueData* pkvd); - - void SetPrevious( CPathTrack *pprevious ); - void Link( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - CPathTrack *ValidPath( CPathTrack *ppath, int testFlag ); // Returns ppath if enabled, NULL otherwise - void Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ); - - static CPathTrack *Instance( edict_t *pent ); - - CPathTrack *LookAhead( Vector *origin, float dist, int move ); - CPathTrack *Nearest( Vector origin ); - - CPathTrack *GetNext( void ); - CPathTrack *GetPrevious( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; -#if PATH_SPARKLE_DEBUG - void EXPORT Sparkle(void); -#endif - - float m_length; - string_t m_altName; - CPathTrack *m_pnext; - CPathTrack *m_pprevious; - CPathTrack *m_paltpath; -}; - - -class CFuncTrackTrain : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData* pkvd ); - - void EXPORT Next( void ); - void EXPORT Find( void ); - void EXPORT NearestPath( void ); - void EXPORT DeadEnd( void ); - - void NextThink( float thinkTime, BOOL alwaysThink ); - - void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest(pev->origin); } - void SetControls( entvars_t *pevControls ); - BOOL OnControls( entvars_t *pev ); - - void StopSound ( void ); - void UpdateSound ( void ); - - static CFuncTrackTrain *Instance( edict_t *pent ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DIRECTIONAL_USE; } - - virtual void OverrideReset( void ); - - CPathTrack *m_ppath; - float m_length; - float m_height; - float m_speed; - float m_dir; - float m_startSpeed; - Vector m_controlMins; - Vector m_controlMaxs; - int m_soundPlaying; - int m_sounds; - float m_flVolume; - float m_flBank; - float m_oldSpeed; - -private: - unsigned short m_usAdjustPitch; -}; - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef TRAINS_H +#define TRAINS_H + +// Tracktrain spawn flags +#define SF_TRACKTRAIN_NOPITCH 0x0001 +#define SF_TRACKTRAIN_NOCONTROL 0x0002 +#define SF_TRACKTRAIN_FORWARDONLY 0x0004 +#define SF_TRACKTRAIN_PASSABLE 0x0008 + +// Spawnflag for CPathTrack +#define SF_PATH_DISABLED 0x00000001 +#define SF_PATH_FIREONCE 0x00000002 +#define SF_PATH_ALTREVERSE 0x00000004 +#define SF_PATH_DISABLE_TRAIN 0x00000008 +#define SF_PATH_ALTERNATE 0x00008000 + +// Spawnflags of CPathCorner +#define SF_CORNER_WAITFORTRIG 0x001 +#define SF_CORNER_TELEPORT 0x002 +#define SF_CORNER_FIREONCE 0x004 + +//#define PATH_SPARKLE_DEBUG 1 // This makes a particle effect around path_track entities for debugging +class CPathTrack : public CPointEntity +{ +public: + void Spawn( void ); + void Activate( void ); + void KeyValue( KeyValueData* pkvd); + + void SetPrevious( CPathTrack *pprevious ); + void Link( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + CPathTrack *ValidPath( CPathTrack *ppath, int testFlag ); // Returns ppath if enabled, NULL otherwise + void Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ); + + static CPathTrack *Instance( edict_t *pent ); + + CPathTrack *LookAhead( Vector *origin, float dist, int move ); + CPathTrack *Nearest( Vector origin ); + + CPathTrack *GetNext( void ); + CPathTrack *GetPrevious( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; +#if PATH_SPARKLE_DEBUG + void EXPORT Sparkle(void); +#endif + + float m_length; + string_t m_altName; + CPathTrack *m_pnext; + CPathTrack *m_pprevious; + CPathTrack *m_paltpath; +}; + + +class CFuncTrackTrain : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + + void Blocked( CBaseEntity *pOther ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData* pkvd ); + + void EXPORT Next( void ); + void EXPORT Find( void ); + void EXPORT NearestPath( void ); + void EXPORT DeadEnd( void ); + + void NextThink( float thinkTime, BOOL alwaysThink ); + + void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest(pev->origin); } + void SetControls( entvars_t *pevControls ); + BOOL OnControls( entvars_t *pev ); + + void StopSound ( void ); + void UpdateSound ( void ); + + static CFuncTrackTrain *Instance( edict_t *pent ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DIRECTIONAL_USE; } + + virtual void OverrideReset( void ); + + CPathTrack *m_ppath; + float m_length; + float m_height; + float m_speed; + float m_dir; + float m_startSpeed; + Vector m_controlMins; + Vector m_controlMaxs; + int m_soundPlaying; + int m_sounds; + float m_flVolume; + float m_flBank; + float m_oldSpeed; + +private: + unsigned short m_usAdjustPitch; +}; + +#endif diff --git a/main/source/dlls/triggers.cpp b/main/source/dlls/triggers.cpp index 9805ca1c..f75e368a 100644 --- a/main/source/dlls/triggers.cpp +++ b/main/source/dlls/triggers.cpp @@ -1,2405 +1,2405 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== triggers.cpp ======================================================== - - spawn and use functions for editor-placed triggers - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "saverestore.h" -#include "trains.h" // trigger_camera has train functionality -#include "gamerules.h" -#include "triggers.h" -#include "../mod/AvHServerVariables.h" - -#define SF_TRIGGER_PUSH_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_TARGETONCE 1// Only fire hurt target once -#define SF_TRIGGER_HURT_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_NO_CLIENTS 8//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16// trigger hurt will only fire its target if it is hurting a client -#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32// only clients may touch this trigger. - -extern DLL_GLOBAL BOOL g_fGameOver; - -extern void SetMovedir(entvars_t* pev); -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -class CFrictionModifier : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT ChangeFriction( CBaseEntity *pOther ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - static TYPEDESCRIPTION m_SaveData[]; - - float m_frictionFraction; // Sorry, couldn't resist this name :) -}; - -LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ); - -// Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = -{ - DEFINE_FIELD( CFrictionModifier, m_frictionFraction, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE(CFrictionModifier,CBaseEntity); - - -// Modify an entity's friction -void CFrictionModifier :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_NONE; - SetTouch( &CFrictionModifier::ChangeFriction ); -} - - -// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) -void CFrictionModifier :: ChangeFriction( CBaseEntity *pOther ) -{ - if ( pOther->pev->movetype != MOVETYPE_BOUNCEMISSILE && pOther->pev->movetype != MOVETYPE_BOUNCE ) - pOther->pev->friction = m_frictionFraction; -} - - - -// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) -void CFrictionModifier :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "modifier")) - { - m_frictionFraction = atof(pkvd->szValue) / 100.0; - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// This trigger will fire when the level spawns (or respawns if not fire once) -// It will check a global state before firing. It supports delay and killtargets - -#define SF_AUTO_FIREONCE 0x0001 - -class CAutoTrigger : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Precache( void ); - void Think( void ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_globalstate; - USE_TYPE triggerType; -}; -LINK_ENTITY_TO_CLASS( trigger_auto, CAutoTrigger ); - -TYPEDESCRIPTION CAutoTrigger::m_SaveData[] = -{ - DEFINE_FIELD( CAutoTrigger, m_globalstate, FIELD_STRING ), - DEFINE_FIELD( CAutoTrigger, triggerType, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CAutoTrigger,CBaseDelay); - -void CAutoTrigger::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "globalstate")) - { - m_globalstate = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - -void CAutoTrigger::Spawn( void ) -{ - Precache(); -} - - -void CAutoTrigger::Precache( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CAutoTrigger::Think( void ) -{ - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) - { - SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_AUTO_FIREONCE ) - UTIL_Remove( this ); - } -} - - - -#define SF_RELAY_FIREONCE 0x0001 - -class CTriggerRelay : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - USE_TYPE triggerType; -}; -LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ); - -TYPEDESCRIPTION CTriggerRelay::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerRelay, triggerType, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerRelay,CBaseDelay); - -void CTriggerRelay::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - -void CTriggerRelay::Spawn( void ) -{ -} - - - - -void CTriggerRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_RELAY_FIREONCE ) - UTIL_Remove( this ); -} - - -//********************************************************** -// The Multimanager Entity - when fired, will fire up to 16 targets -// at specified times. -// FLAG: THREAD (create clones when triggered) -// FLAG: CLONE (this is a clone for a threaded execution) - -#define SF_MULTIMAN_CLONE 0x80000000 -#define SF_MULTIMAN_THREAD 0x00000001 - -class CMultiManager : public CBaseToggle -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn ( void ); - void EXPORT ManagerThink ( void ); - void EXPORT ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -#if _DEBUG - void EXPORT ManagerReport( void ); -#endif - - BOOL HasTarget( string_t targetname ); - - int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_cTargets; // the total number of targets in this manager's fire list. - int m_index; // Current target - float m_startTime;// Time we started firing - int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array - float m_flTargetDelay [ MAX_MULTI_TARGETS ];// delay (in seconds) from time of manager fire to target fire -private: - inline BOOL IsClone( void ) { return (pev->spawnflags & SF_MULTIMAN_CLONE) ? TRUE : FALSE; } - inline BOOL ShouldClone( void ) - { - if ( IsClone() ) - return FALSE; - - return (pev->spawnflags & SF_MULTIMAN_THREAD) ? TRUE : FALSE; - } - - CMultiManager *Clone( void ); -}; -LINK_ENTITY_TO_CLASS( multi_manager, CMultiManager ); - -// Global Savedata for multi_manager -TYPEDESCRIPTION CMultiManager::m_SaveData[] = -{ - DEFINE_FIELD( CMultiManager, m_cTargets, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_index, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_startTime, FIELD_TIME ), - DEFINE_ARRAY( CMultiManager, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), -}; - -IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle); - -void CMultiManager :: KeyValue( KeyValueData *pkvd ) -{ - // UNDONE: Maybe this should do something like this: - //CBaseToggle::KeyValue( pkvd ); - // if ( !pkvd->fHandled ) - // ... etc. - - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else // add this field to the target list - { - // this assumes that additional fields are targetnames and their values are delay values. - if ( m_cTargets < MAX_MULTI_TARGETS ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp ); - m_flTargetDelay [ m_cTargets ] = atof (pkvd->szValue); - m_cTargets++; - pkvd->fHandled = TRUE; - } - } -} - - -void CMultiManager :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - SetUse ( &CMultiManager::ManagerUse ); - SetThink (&CMultiManager::ManagerThink); - - // Sort targets - // Quick and dirty bubble sort - int swapped = 1; - - while ( swapped ) - { - swapped = 0; - for ( int i = 1; i < m_cTargets; i++ ) - { - if ( m_flTargetDelay[i] < m_flTargetDelay[i-1] ) - { - // Swap out of order elements - int name = m_iTargetName[i]; - float delay = m_flTargetDelay[i]; - m_iTargetName[i] = m_iTargetName[i-1]; - m_flTargetDelay[i] = m_flTargetDelay[i-1]; - m_iTargetName[i-1] = name; - m_flTargetDelay[i-1] = delay; - swapped = 1; - } - } - } -} - - -BOOL CMultiManager::HasTarget( string_t targetname ) -{ - for ( int i = 0; i < m_cTargets; i++ ) - if ( FStrEq(STRING(targetname), STRING(m_iTargetName[i])) ) - return TRUE; - - return FALSE; -} - - -// Designers were using this to fire targets that may or may not exist -- -// so I changed it to use the standard target fire code, made it a little simpler. -void CMultiManager :: ManagerThink ( void ) -{ - float time; - - time = gpGlobals->time - m_startTime; - while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time ) - { - FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 ); - m_index++; - } - - if ( m_index >= m_cTargets )// have we fired all targets? - { - SetThink( NULL ); - if ( IsClone() ) - { - UTIL_Remove( this ); - return; - } - SetUse ( &CMultiManager::ManagerUse );// allow manager re-use - } - else - pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; -} - -CMultiManager *CMultiManager::Clone( void ) -{ - CMultiManager *pMulti = GetClassPtr( (CMultiManager *)NULL ); - - edict_t *pEdict = pMulti->pev->pContainingEntity; - memcpy( pMulti->pev, pev, sizeof(*pev) ); - pMulti->pev->pContainingEntity = pEdict; - - pMulti->pev->spawnflags |= SF_MULTIMAN_CLONE; - pMulti->m_cTargets = m_cTargets; - memcpy( pMulti->m_iTargetName, m_iTargetName, sizeof( m_iTargetName ) ); - memcpy( pMulti->m_flTargetDelay, m_flTargetDelay, sizeof( m_flTargetDelay ) ); - - return pMulti; -} - - -// The USE function builds the time table and starts the entity thinking. -void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // In multiplayer games, clone the MM and execute in the clone (like a thread) - // to allow multiple players to trigger the same multimanager - if ( ShouldClone() ) - { - CMultiManager *pClone = Clone(); - pClone->ManagerUse( pActivator, pCaller, useType, value ); - return; - } - - m_hActivator = pActivator; - m_index = 0; - m_startTime = gpGlobals->time; - - SetUse( NULL );// disable use until all targets have fired - - SetThink ( &CMultiManager::ManagerThink ); - pev->nextthink = gpGlobals->time; -} - -#if _DEBUG -void CMultiManager :: ManagerReport ( void ) -{ - int cIndex; - - for ( cIndex = 0 ; cIndex < m_cTargets ; cIndex++ ) - { - ALERT ( at_console, "%s %f\n", STRING(m_iTargetName[cIndex]), m_flTargetDelay[cIndex] ); - } -} -#endif - -//*********************************************************** - - -// -// Render parameters trigger -// -// This entity will copy its render parameters (renderfx, rendermode, rendercolor, renderamt) -// to its targets when triggered. -// - - -// Flags to indicate masking off various render parameters that are normally copied to the targets -#define SF_RENDER_MASKFX (1<<0) -#define SF_RENDER_MASKAMT (1<<1) -#define SF_RENDER_MASKMODE (1<<2) -#define SF_RENDER_MASKCOLOR (1<<3) - -class CRenderFxManager : public CBaseEntity -{ -public: - void Spawn( void ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ); - - -void CRenderFxManager :: Spawn ( void ) -{ - pev->solid = SOLID_NOT; -} - -void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - while ( 1 ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - - entvars_t *pevTarget = VARS( pentTarget ); - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) ) - pevTarget->renderfx = pev->renderfx; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) - pevTarget->renderamt = pev->renderamt; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) - pevTarget->rendermode = pev->rendermode; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) - pevTarget->rendercolor = pev->rendercolor; - } - } -} - - - -LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ); - -/* -================ -InitTrigger -================ -*/ -void CBaseTrigger::InitTrigger( ) -{ - // trigger angles are used for one-way touches. An angle of 0 is assumed - // to mean no restrictions, so use a yaw of 360 instead. - if (pev->angles != g_vecZero) - SetMovedir(pev); - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - if ( ns_cvar_float(showtriggers) == 0 ) - SetBits( pev->effects, EF_NODRAW ); -} - - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseTrigger :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "count")) - { - m_cTriggersLeft = (int) atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damagetype")) - { - m_bitsDamageInflict = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -class CTriggerHurt : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT RadiationThink( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ); - -// -// trigger_monsterjump -// -class CTriggerMonsterJump : public CBaseTrigger -{ -public: - void Spawn( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ); - - -void CTriggerMonsterJump :: Spawn ( void ) -{ - SetMovedir ( pev ); - - InitTrigger (); - - pev->nextthink = 0; - pev->speed = 200; - m_flHeight = 150; - - if ( !FStringNull ( pev->targetname ) ) - {// if targetted, spawn turned off - pev->solid = SOLID_NOT; - UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetUse( &CTriggerMonsterJump::ToggleUse ); - } -} - - -void CTriggerMonsterJump :: Think( void ) -{ - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE - UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetThink( NULL ); -} - -void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-monster. - return; - } - - pevOther->origin.z += 1; - - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) - {// clear the onground so physics don't bitch - pevOther->flags &= ~FL_ONGROUND; - } - - // toss the monster! - pevOther->velocity = pev->movedir * pev->speed; - pevOther->velocity.z += m_flHeight; - pev->nextthink = gpGlobals->time; -} - - -//===================================== -// -// trigger_cdaudio - starts/stops cd audio tracks -// -class CTriggerCDAudio : public CBaseTrigger -{ -public: - void Spawn( void ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void PlayTrack( void ); - void Touch ( CBaseEntity *pOther ); -}; - -LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ); - -// -// Changes tracks or stops CD when player touches -// -// !!!HACK - overloaded HEALTH to avoid adding new field -void CTriggerCDAudio :: Touch ( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - {// only clients may trigger these events - return; - } - - PlayTrack(); -} - -void CTriggerCDAudio :: Spawn( void ) -{ - InitTrigger(); -} - -void CTriggerCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - PlayTrack(); -} - -void PlayCDTrack( int iTrack ) -{ - edict_t *pClient; - - // manually find the single player. - pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - // Can't play if the client is not connected! - if ( !pClient ) - return; - - if ( iTrack < -1 || iTrack > 30 ) - { - ALERT ( at_console, "TriggerCDAudio - Track %d out of range\n" ); - return; - } - - if ( iTrack == -1 ) - { - CLIENT_COMMAND ( pClient, "cd pause\n"); - } - else - { - char string [ 64 ]; - - sprintf( string, "cd play %3d\n", iTrack ); - CLIENT_COMMAND ( pClient, string); - } -} - - -// only plays for ONE client, so only use in single play! -void CTriggerCDAudio :: PlayTrack( void ) -{ - PlayCDTrack( (int)pev->health ); - - SetTouch( NULL ); - UTIL_Remove( this ); -} - - -// This plays a CD track when fired or when the player enters it's radius -class CTargetCDAudio : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void Play( void ); -}; - -LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudio ); - -void CTargetCDAudio :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->scale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CTargetCDAudio :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - if ( pev->scale > 0 ) - pev->nextthink = gpGlobals->time + 1.0; -} - -void CTargetCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - Play(); -} - -// only plays for ONE client, so only use in single play! -void CTargetCDAudio::Think( void ) -{ - edict_t *pClient; - - // manually find the single player. - pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - // Can't play if the client is not connected! - if ( !pClient ) - return; - - pev->nextthink = gpGlobals->time + 0.5; - - if ( (pClient->v.origin - pev->origin).Length() <= pev->scale ) - Play(); - -} - -void CTargetCDAudio::Play( void ) -{ - PlayCDTrack( (int)pev->health ); - UTIL_Remove(this); -} - -//===================================== - -// -// trigger_hurt - hurts anything that touches it. if the trigger has a targetname, firing it will toggle state -// -//int gfToggleState = 0; // used to determine when all radiation trigger hurts have called 'RadiationThink' - -void CTriggerHurt :: Spawn( void ) -{ - InitTrigger(); - SetTouch ( &CTriggerHurt::HurtTouch ); - - if ( !FStringNull ( pev->targetname ) ) - { - SetUse ( &CTriggerHurt::ToggleUse ); - } - else - { - SetUse ( NULL ); - } - - if (m_bitsDamageInflict & DMG_RADIATION) - { - SetThink ( &CTriggerHurt::RadiationThink ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); - } - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_HURT_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - UTIL_SetOrigin( pev, pev->origin ); // Link into the list -} - -// trigger hurt that causes radiation will do a radius -// check and set the player's geiger counter level -// according to distance from center of trigger - -void CTriggerHurt :: RadiationThink( void ) -{ - - edict_t *pentPlayer; - CBasePlayer *pPlayer = NULL; - float flRange; - entvars_t *pevTarget; - Vector vecSpot1; - Vector vecSpot2; - Vector vecRange; - Vector origin; - Vector view_ofs; - - // check to see if a player is in pvs - // if not, continue - - // set origin to center of trigger so that this check works - origin = pev->origin; - view_ofs = pev->view_ofs; - - pev->origin = (pev->absmin + pev->absmax) * 0.5; - pev->view_ofs = pev->view_ofs * 0.0; - - pentPlayer = FIND_CLIENT_IN_PVS(edict()); - - pev->origin = origin; - pev->view_ofs = view_ofs; - - // reset origin - - if (!FNullEnt(pentPlayer)) - { - - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - - pevTarget = VARS(pentPlayer); - - // get range to player; - - vecSpot1 = (pev->absmin + pev->absmax) * 0.5; - vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5; - - vecRange = vecSpot1 - vecSpot2; - flRange = vecRange.Length(); - - // if player's current geiger counter range is larger - // than range to this trigger hurt, reset player's - // geiger counter range - - if (pPlayer->m_flgeigerRange >= flRange) - pPlayer->m_flgeigerRange = flRange; - } - - pev->nextthink = gpGlobals->time + 0.25; -} - -// -// ToggleUse - If this is the USE function for a trigger, its state will toggle every time it's fired -// -void CBaseTrigger :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (pev->solid == SOLID_NOT) - {// if the trigger is off, turn it on - pev->solid = SOLID_TRIGGER; - - // Force retouch - gpGlobals->force_retouch++; - } - else - {// turn the trigger off - pev->solid = SOLID_NOT; - } - UTIL_SetOrigin( pev, pev->origin ); -} - -// When touched, a hurt trigger does DMG points of damage each half-second -void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) -{ - float fldmg; - - if ( !pOther->pev->takedamage ) - return; - - if ( (pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH) && !pOther->IsPlayer() ) - { - // this trigger is only allowed to touch clients, and this ain't a client. - return; - } - - if ( (pev->spawnflags & SF_TRIGGER_HURT_NO_CLIENTS) && pOther->IsPlayer() ) - return; - - // HACKHACK -- In multiplayer, players touch this based on packet receipt. - // So the players who send packets later aren't always hurt. Keep track of - // how much time has passed and whether or not you've touched that player - if ( g_pGameRules->IsMultiplayer() ) - { - if ( pev->dmgtime > gpGlobals->time ) - { - if ( gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - - // If I've already touched this player (this time), then bail out - if ( pev->impulse & playerMask ) - return; - - // Mark this player as touched - // BUGBUG - There can be only 32 players! - pev->impulse |= playerMask; - } - else - { - return; - } - } - } - else - { - // New clock, "un-touch" all players - pev->impulse = 0; - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - - // Mark this player as touched - // BUGBUG - There can be only 32 players! - pev->impulse |= playerMask; - } - } - } - else // Original code -- single player - { - if ( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity - return; - } - } - - - - // If this is time_based damage (poison, radiation), override the pev->dmg with a - // default for the given damage type. Monsters only take time-based damage - // while touching the trigger. Player continues taking damage for a while after - // leaving the trigger - - fldmg = pev->dmg * 0.5; // 0.5 seconds worth of damage, pev->dmg is damage/second - - - // JAY: Cut this because it wasn't fully realized. Damage is simpler now. -#if 0 - switch (m_bitsDamageInflict) - { - default: break; - case DMG_POISON: fldmg = POISON_DAMAGE/4; break; - case DMG_NERVEGAS: fldmg = NERVEGAS_DAMAGE/4; break; - case DMG_RADIATION: fldmg = RADIATION_DAMAGE/4; break; - case DMG_PARALYZE: fldmg = PARALYZE_DAMAGE/4; break; // UNDONE: cut this? should slow movement to 50% - case DMG_ACID: fldmg = ACID_DAMAGE/4; break; - case DMG_SLOWBURN: fldmg = SLOWBURN_DAMAGE/4; break; - case DMG_SLOWFREEZE: fldmg = SLOWFREEZE_DAMAGE/4; break; - } -#endif - - if ( fldmg < 0 ) - pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); - else - pOther->TakeDamage( pev, pev, fldmg, m_bitsDamageInflict ); - - // Store pain time so we can get all of the other entities on this frame - pev->pain_finished = gpGlobals->time; - - // Apply damage every half second - pev->dmgtime = gpGlobals->time + 0.5;// half second delay until this trigger can hurt toucher again - - - - if ( pev->target ) - { - // trigger has a target it wants to fire. - if ( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE ) - { - // if the toucher isn't a client, don't fire the target! - if ( !pOther->IsPlayer() ) - { - return; - } - } - - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - if ( pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE ) - pev->target = 0; - } -} - - -/*QUAKED trigger_multiple (.5 .5 .5) ? notouch -Variable sized repeatable trigger. Must be targeted at one or more entities. -If "health" is set, the trigger must be killed to activate each time. -If "delay" is set, the trigger waits some time after activating before firing. -"wait" : Seconds between triggerings. (.2 default) -If notouch is set, the trigger is only fired by other entities, not by touching. -NOTOUCH has been obsoleted by trigger_relay! -sounds -1) secret -2) beep beep -3) large switch -4) -NEW -if a trigger has a NETNAME, that NETNAME will become the TARGET of the triggered object. -*/ -class CTriggerMultiple : public CBaseTrigger -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ); - - -void CTriggerMultiple :: Spawn( void ) -{ - if (m_flWait == 0) - m_flWait = 0.2; - - InitTrigger(); - - ASSERTSZ(pev->health == 0, "trigger_multiple with health"); -// UTIL_SetOrigin(pev, pev->origin); -// SET_MODEL( ENT(pev), STRING(pev->model) ); -// if (pev->health > 0) -// { -// if (FBitSet(pev->spawnflags, SPAWNFLAG_NOTOUCH)) -// ALERT(at_error, "trigger_multiple spawn: health and notouch don't make sense"); -// pev->max_health = pev->health; -//UNDONE: where to get pfnDie from? -// pev->pfnDie = multi_killed; -// pev->takedamage = DAMAGE_YES; -// pev->solid = SOLID_BBOX; -// UTIL_SetOrigin(pev, pev->origin); // make sure it links into the world -// } -// else - { - SetTouch( &CTriggerMultiple::MultiTouch ); - } - } - - -/*QUAKED trigger_once (.5 .5 .5) ? notouch -Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching -"targetname". If "health" is set, the trigger must be killed to activate. -If notouch is set, the trigger is only fired by other entities, not by touching. -if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. -if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. -sounds -1) secret -2) beep beep -3) large switch -4) -*/ -class CTriggerOnce : public CTriggerMultiple -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ); -void CTriggerOnce::Spawn( void ) -{ - m_flWait = -1; - - CTriggerMultiple :: Spawn(); -} - - - -void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) -{ - entvars_t *pevToucher; - - pevToucher = pOther->pev; - - // Only touch clients, monsters, or pushables (depending on flags) - if ( ((pevToucher->flags & FL_CLIENT) && !(pev->spawnflags & SF_TRIGGER_NOCLIENTS)) || - ((pevToucher->flags & FL_MONSTER) && (pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS)) || - (pev->spawnflags & SF_TRIGGER_PUSHABLES) && FClassnameIs(pevToucher,"func_pushable") ) - { - -#if 0 - // if the trigger has an angles field, check player's facing direction - if (pev->movedir != g_vecZero) - { - UTIL_MakeVectors( pevToucher->angles ); - if ( DotProduct( gpGlobals->v_forward, pev->movedir ) < 0 ) - return; // not facing the right way - } -#endif - - ActivateMultiTrigger( pOther ); - } -} - - -// -// the trigger was just touched/killed/used -// self.enemy should be set to the activator so it can be held through a delay -// so wait for the delay time before firing -// -void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) -{ - if (pev->nextthink > gpGlobals->time) - return; // still waiting for reset time - - if (!UTIL_IsMasterTriggered(m_sMaster,pActivator)) - return; - - if (FClassnameIs(pev, "trigger_secret")) - { - if ( pev->enemy == NULL || !FClassnameIs(pev->enemy, "player")) - return; - gpGlobals->found_secrets++; - } - - if (!FStringNull(pev->noise)) - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - -// don't trigger again until reset -// pev->takedamage = DAMAGE_NO; - - m_hActivator = pActivator; - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - - if ( pev->message && pActivator->IsPlayer() ) - { - UTIL_ShowMessage( STRING(pev->message), pActivator ); -// CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); - } - - if (m_flWait > 0) - { - SetThink( &CBaseTrigger::MultiWaitOver ); - pev->nextthink = gpGlobals->time + m_flWait; - } - else - { - // we can't just remove (self) here, because this is a touch function - // called while C code is looping through area links... - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CBaseTrigger::SUB_Remove ); - } -} - - -// the wait time has passed, so set back up for another activation -void CBaseTrigger :: MultiWaitOver( void ) -{ -// if (pev->max_health) -// { -// pev->health = pev->max_health; -// pev->takedamage = DAMAGE_YES; -// pev->solid = SOLID_BBOX; -// } - SetThink( NULL ); -} - - -// ========================= COUNTING TRIGGER ===================================== - -// -// GLOBALS ASSUMED SET: g_eoActivator -// -void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_cTriggersLeft--; - m_hActivator = pActivator; - - if (m_cTriggersLeft < 0) - return; - - BOOL fTellActivator = - (m_hActivator != 0) && - (FClassnameIs(m_hActivator->pev, "player") && - !FBitSet(pev->spawnflags, SPAWNFLAG_NOMESSAGE)); - if (m_cTriggersLeft != 0) - { - if (fTellActivator) - { - // UNDONE: I don't think we want these Quakesque messages - switch (m_cTriggersLeft) - { - case 1: ALERT(at_console, "Only 1 more to go..."); break; - case 2: ALERT(at_console, "Only 2 more to go..."); break; - case 3: ALERT(at_console, "Only 3 more to go..."); break; - default: ALERT(at_console, "There are more to go..."); break; - } - } - return; - } - - // !!!UNDONE: I don't think we want these Quakesque messages - if (fTellActivator) - ALERT(at_console, "Sequence completed!"); - - ActivateMultiTrigger( m_hActivator ); -} - - -/*QUAKED trigger_counter (.5 .5 .5) ? nomessage -Acts as an intermediary for an action that takes multiple inputs. -If nomessage is not set, it will print "1 more.. " etc when triggered and -"sequence complete" when finished. After the counter has been triggered "cTriggersLeft" -times (default 2), it will fire all of it's targets and remove itself. -*/ -class CTriggerCounter : public CBaseTrigger -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ); - -void CTriggerCounter :: Spawn( void ) -{ - // By making the flWait be -1, this counter-trigger will disappear after it's activated - // (but of course it needs cTriggersLeft "uses" before that happens). - m_flWait = -1; - - if (m_cTriggersLeft == 0) - m_cTriggersLeft = 2; - SetUse( &CTriggerCounter::CounterUse ); -} - -// ====================== TRIGGER_CHANGELEVEL ================================ - -class CTriggerVolume : public CPointEntity // Derive from point entity so this doesn't move across levels -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ); - -// Define space that travels across a level transition -void CTriggerVolume :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->model = NULL; - pev->modelindex = 0; -} - - -// Fires a target after level transition and then dies -class CFireAndDie : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Think( void ); - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() | FCAP_FORCE_TRANSITION; } // Always go across transitions -}; -LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ); - -void CFireAndDie::Spawn( void ) -{ - pev->classname = MAKE_STRING("fireanddie"); - // Don't call Precache() - it should be called on restore -} - - -void CFireAndDie::Precache( void ) -{ - // This gets called on restore - pev->nextthink = gpGlobals->time + m_flDelay; -} - - -void CFireAndDie::Think( void ) -{ - SUB_UseTargets( this, USE_TOGGLE, 0 ); - UTIL_Remove( this ); -} - - -#define SF_CHANGELEVEL_USEONLY 0x0002 -class CChangeLevel : public CBaseTrigger -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TriggerChangeLevel( void ); - void EXPORT ExecuteChangeLevel( void ); - void EXPORT TouchChangeLevel( CBaseEntity *pOther ); - void ChangeLevelNow( CBaseEntity *pActivator ); - - static edict_t *FindLandmark( const char *pLandmarkName ); - static int ChangeList( LEVELLIST *pLevelList, int maxList ); - static int AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ); - static int InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - char m_szMapName[cchMapNameMost]; // trigger_changelevel only: next map - char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map - int m_changeTarget; - float m_changeTargetDelay; -}; -LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ); - -// Global Savedata for changelevel trigger -TYPEDESCRIPTION CChangeLevel::m_SaveData[] = -{ - DEFINE_ARRAY( CChangeLevel, m_szMapName, FIELD_CHARACTER, cchMapNameMost ), - DEFINE_ARRAY( CChangeLevel, m_szLandmarkName, FIELD_CHARACTER, cchMapNameMost ), - DEFINE_FIELD( CChangeLevel, m_changeTarget, FIELD_STRING ), - DEFINE_FIELD( CChangeLevel, m_changeTargetDelay, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger); - -// -// Cache user-entity-field values until spawn is called. -// - -void CChangeLevel :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "map")) - { - if (strlen(pkvd->szValue) >= cchMapNameMost) - ALERT( at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szMapName, pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "landmark")) - { - if (strlen(pkvd->szValue) >= cchMapNameMost) - ALERT( at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szLandmarkName, pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changetarget")) - { - m_changeTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changedelay")) - { - m_changeTargetDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseTrigger::KeyValue( pkvd ); -} - - -/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION -When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. -*/ - -void CChangeLevel :: Spawn( void ) -{ - if ( FStrEq( m_szMapName, "" ) ) - ALERT( at_console, "a trigger_changelevel doesn't have a map" ); - - if ( FStrEq( m_szLandmarkName, "" ) ) - ALERT( at_console, "trigger_changelevel to %s doesn't have a landmark", m_szMapName ); - - if (!FStringNull ( pev->targetname ) ) - { - SetUse ( &CChangeLevel::UseChangeLevel ); - } - InitTrigger(); - if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) - SetTouch( &CChangeLevel::TouchChangeLevel ); -// ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); -} - - -void CChangeLevel :: ExecuteChangeLevel( void ) -{ - MESSAGE_BEGIN( MSG_ALL, SVC_CDTRACK ); - WRITE_BYTE( 3 ); - WRITE_BYTE( 3 ); - MESSAGE_END(); - - MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); - MESSAGE_END(); -} - - -FILE_GLOBAL char st_szNextMap[cchMapNameMost]; -FILE_GLOBAL char st_szNextSpot[cchMapNameMost]; - -edict_t *CChangeLevel :: FindLandmark( const char *pLandmarkName ) -{ - edict_t *pentLandmark; - - pentLandmark = FIND_ENTITY_BY_STRING( NULL, "targetname", pLandmarkName ); - while ( !FNullEnt( pentLandmark ) ) - { - // Found the landmark - if ( FClassnameIs( pentLandmark, "info_landmark" ) ) - return pentLandmark; - else - pentLandmark = FIND_ENTITY_BY_STRING( pentLandmark, "targetname", pLandmarkName ); - } - ALERT( at_error, "Can't find landmark %s\n", pLandmarkName ); - return NULL; -} - - -//========================================================= -// CChangeLevel :: Use - allows level transitions to be -// triggered by buttons, etc. -// -//========================================================= -void CChangeLevel :: UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - ChangeLevelNow( pActivator ); -} - -void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) -{ - edict_t *pentLandmark; - LEVELLIST levels[16]; - - ASSERT(!FStrEq(m_szMapName, "")); - - // Don't work in deathmatch - if ( g_pGameRules->IsDeathmatch() ) - return; - - // Some people are firing these multiple times in a frame, disable - if ( gpGlobals->time == pev->dmgtime ) - return; - - pev->dmgtime = gpGlobals->time; - - - CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) ) - { - ALERT( at_aiconsole, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName ); - return; - } - - // Create an entity to fire the changetarget - if ( m_changeTarget ) - { - CFireAndDie *pFireAndDie = GetClassPtr( (CFireAndDie *)NULL ); - if ( pFireAndDie ) - { - // Set target and delay - pFireAndDie->pev->target = m_changeTarget; - pFireAndDie->m_flDelay = m_changeTargetDelay; - pFireAndDie->pev->origin = pPlayer->pev->origin; - // Call spawn - DispatchSpawn( pFireAndDie->edict() ); - } - } - // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - strcpy(st_szNextMap, m_szMapName); - - m_hActivator = pActivator; - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - st_szNextSpot[0] = 0; // Init landmark to NULL - - // look for a landmark entity - pentLandmark = FindLandmark( m_szLandmarkName ); - if ( !FNullEnt( pentLandmark ) ) - { - strcpy(st_szNextSpot, m_szLandmarkName); - gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; - } -// ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); - ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); - CHANGE_LEVEL( st_szNextMap, st_szNextSpot ); -} - -// -// GLOBALS ASSUMED SET: st_szNextMap -// -void CChangeLevel :: TouchChangeLevel( CBaseEntity *pOther ) -{ - if (!FClassnameIs(pOther->pev, "player")) - return; - - ChangeLevelNow( pOther ); -} - - -// Add a transition to the list, but ignore duplicates -// (a designer may have placed multiple trigger_changelevels with the same landmark) -int CChangeLevel::AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ) -{ - int i; - - if ( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) - return 0; - - for ( i = 0; i < listCount; i++ ) - { - if ( pLevelList[i].pentLandmark == pentLandmark && strcmp( pLevelList[i].mapName, pMapName ) == 0 ) - return 0; - } - strcpy( pLevelList[listCount].mapName, pMapName ); - strcpy( pLevelList[listCount].landmarkName, pLandmarkName ); - pLevelList[listCount].pentLandmark = pentLandmark; - pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin; - - return 1; -} - -int BuildChangeList( LEVELLIST *pLevelList, int maxList ) -{ - return CChangeLevel::ChangeList( pLevelList, maxList ); -} - - -int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) -{ - edict_t *pentVolume; - - - if ( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) - return 1; - - // If you're following another entity, follow it through the transition (weapons follow the player) - if ( pEntity->pev->movetype == MOVETYPE_FOLLOW ) - { - if ( pEntity->pev->aiment != NULL ) - pEntity = CBaseEntity::Instance( pEntity->pev->aiment ); - } - - int inVolume = 1; // Unless we find a trigger_transition, everything is in the volume - - pentVolume = FIND_ENTITY_BY_TARGETNAME( NULL, pVolumeName ); - while ( !FNullEnt( pentVolume ) ) - { - CBaseEntity *pVolume = CBaseEntity::Instance( pentVolume ); - - if ( pVolume && FClassnameIs( pVolume->pev, "trigger_transition" ) ) - { - if ( pVolume->Intersects( pEntity ) ) // It touches one, it's in the volume - return 1; - else - inVolume = 0; // Found a trigger_transition, but I don't intersect it -- if I don't find another, don't go! - } - pentVolume = FIND_ENTITY_BY_TARGETNAME( pentVolume, pVolumeName ); - } - - return inVolume; -} - - -// We can only ever move 512 entities across a transition -#define MAX_ENTITY 512 - -// This has grown into a complicated beast -// Can we make this more elegant? -// This builds the list of all transitions on this level and which entities are in their PVS's and can / should -// be moved across. -int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) -{ - edict_t *pentChangelevel, *pentLandmark; - int i, count; - - count = 0; - - // Find all of the possible level changes on this BSP - pentChangelevel = FIND_ENTITY_BY_STRING( NULL, "classname", "trigger_changelevel" ); - if ( FNullEnt( pentChangelevel ) ) - return 0; - while ( !FNullEnt( pentChangelevel ) ) - { - CChangeLevel *pTrigger; - - pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel)); - if ( pTrigger ) - { - // Find the corresponding landmark - pentLandmark = FindLandmark( pTrigger->m_szLandmarkName ); - if ( pentLandmark ) - { - // Build a list of unique transitions - if ( AddTransitionToList( pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark ) ) - { - count++; - if ( count >= maxList ) // FULL!! - break; - } - } - } - pentChangelevel = FIND_ENTITY_BY_STRING( pentChangelevel, "classname", "trigger_changelevel" ); - } - - if ( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) - { - CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); - - for ( i = 0; i < count; i++ ) - { - int j, entityCount = 0; - CBaseEntity *pEntList[ MAX_ENTITY ]; - int entityFlags[ MAX_ENTITY ]; - - // Follow the linked list of entities in the PVS of the transition landmark - edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); - - // Build a list of valid entities in this linked list (we're going to use pent->v.chain again) - while ( !FNullEnt( pent ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(pent); - if ( pEntity ) - { -// ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); - int caps = pEntity->ObjectCaps(); - if ( !(caps & FCAP_DONT_SAVE) ) - { - int flags = 0; - - // If this entity can be moved or is global, mark it - if ( caps & FCAP_ACROSS_TRANSITION ) - flags |= FENTTABLE_MOVEABLE; - if ( pEntity->pev->globalname && !pEntity->IsDormant() ) - flags |= FENTTABLE_GLOBAL; - if ( flags ) - { - pEntList[ entityCount ] = pEntity; - entityFlags[ entityCount ] = flags; - entityCount++; - if ( entityCount > MAX_ENTITY ) - ALERT( at_error, "Too many entities across a transition!" ); - } -// else -// ALERT( at_console, "Failed %s\n", STRING(pEntity->pev->classname) ); - } -// else -// ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); - } - pent = pent->v.chain; - } - - for ( j = 0; j < entityCount; j++ ) - { - // Check to make sure the entity isn't screened out by a trigger_transition - if ( entityFlags[j] && InTransitionVolume( pEntList[j], pLevelList[i].landmarkName ) ) - { - // Mark entity table with 1<pev->classname) ); - - } - } - } - - return count; -} - -/* -go to the next level for deathmatch -only called if a time or frag limit has expired -*/ -void NextLevel( void ) -{ - edict_t* pent; - CChangeLevel *pChange; - - // find a trigger_changelevel - pent = FIND_ENTITY_BY_CLASSNAME(NULL, "trigger_changelevel"); - - // go back to start if no trigger_changelevel - if (FNullEnt(pent)) - { - gpGlobals->mapname = ALLOC_STRING("start"); - pChange = GetClassPtr( (CChangeLevel *)NULL ); - strcpy(pChange->m_szMapName, "start"); - } - else - pChange = GetClassPtr( (CChangeLevel *)VARS(pent)); - - strcpy(st_szNextMap, pChange->m_szMapName); - g_fGameOver = TRUE; - - if (pChange->pev->nextthink < gpGlobals->time) - { - pChange->SetThink( &CChangeLevel::ExecuteChangeLevel ); - pChange->pev->nextthink = gpGlobals->time + 0.1; - } -} - -LINK_ENTITY_TO_CLASS( func_ladder, CLadder ); - - -void CLadder :: KeyValue( KeyValueData *pkvd ) -{ - CBaseTrigger::KeyValue( pkvd ); -} - - -//========================================================= -// func_ladder - makes an area vertically negotiable -//========================================================= -void CLadder :: Precache( void ) -{ - // Do all of this in here because we need to 'convert' old saved games - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_LADDER; - if ( ns_cvar_float(showtriggers) == 0 ) - { - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; - } - pev->effects &= ~EF_NODRAW; -} - - -void CLadder :: Spawn( void ) -{ - Precache(); - - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_PUSH; -} - - -// ========================== A TRIGGER THAT PUSHES YOU =============================== - -class CTriggerPush : public CBaseTrigger -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ); - - -void CTriggerPush :: KeyValue( KeyValueData *pkvd ) -{ - CBaseTrigger::KeyValue( pkvd ); -} - - -/*QUAKED trigger_push (.5 .5 .5) ? TRIG_PUSH_ONCE -Pushes the player -*/ - -void CTriggerPush :: Spawn( ) -{ - if ( pev->angles == g_vecZero ) - pev->angles.y = 360; - InitTrigger(); - - if (pev->speed == 0) - pev->speed = 100; - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - SetUse(&CTriggerPush::ToggleUse ); - - UTIL_SetOrigin( pev, pev->origin ); // Link into the list -} - - -void CTriggerPush :: Touch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - // UNDONE: Is there a better way than health to detect things that have physics? (clients/monsters) - switch( pevToucher->movetype ) - { - case MOVETYPE_NONE: - case MOVETYPE_PUSH: - case MOVETYPE_NOCLIP: - case MOVETYPE_FOLLOW: - return; - } - - if ( pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP ) - { - // Instant trigger, just transfer velocity and remove - if (FBitSet(pev->spawnflags, SF_TRIG_PUSH_ONCE)) - { - pevToucher->velocity = pevToucher->velocity + (pev->speed * pev->movedir); - if ( pevToucher->velocity.z > 0 ) - pevToucher->flags &= ~FL_ONGROUND; - UTIL_Remove( this ); - } - else - { // Push field, transfer to base velocity - Vector vecPush = (pev->speed * pev->movedir); - if ( pevToucher->flags & FL_BASEVELOCITY ) - vecPush = vecPush + pevToucher->basevelocity; - - pevToucher->basevelocity = vecPush; - - pevToucher->flags |= FL_BASEVELOCITY; -// ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); - } - } -} - - -//====================================== -// teleport trigger -// -// - -void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - edict_t *pentTarget = NULL; - - // Only teleport monsters or clients - if ( !FBitSet( pevToucher->flags, FL_CLIENT|FL_MONSTER ) ) - return; - - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) - return; - - if ( !( pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) - {// no monsters allowed! - if ( FBitSet( pevToucher->flags, FL_MONSTER ) ) - { - return; - } - } - - if ( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) - {// no clients allowed - if ( pOther->IsPlayer() ) - { - return; - } - } - - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pev->target) ); - if (FNullEnt(pentTarget)) - return; - - Vector tmp = VARS( pentTarget )->origin; - - if ( pOther->IsPlayer() ) - { - tmp.z -= pOther->pev->mins.z;// make origin adjustments in case the teleportee is a player. (origin in center, not at feet) - } - - tmp.z++; - - pevToucher->flags &= ~FL_ONGROUND; - - UTIL_SetOrigin( pevToucher, tmp ); - - pevToucher->angles = pentTarget->v.angles; - - if ( pOther->IsPlayer() ) - { - pevToucher->v_angle = pentTarget->v.angles; - } - - pevToucher->fixangle = TRUE; - pevToucher->velocity = pevToucher->basevelocity = g_vecZero; -} - - -class CTriggerTeleport : public CBaseTrigger -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ); - -void CTriggerTeleport :: Spawn( void ) -{ - InitTrigger(); - - SetTouch( &CTriggerTeleport::TeleportTouch ); -} - - -LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ); - - - -class CTriggerSave : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT SaveTouch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); - -void CTriggerSave::Spawn( void ) -{ - if ( g_pGameRules->IsDeathmatch() ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - - InitTrigger(); - SetTouch( &CTriggerSave::SaveTouch ); -} - -void CTriggerSave::SaveTouch( CBaseEntity *pOther ) -{ - if ( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) - return; - - // Only save on clients - if ( !pOther->IsPlayer() ) - return; - - SetTouch( NULL ); - UTIL_Remove( this ); - SERVER_COMMAND( "autosave\n" ); -} - -#define SF_ENDSECTION_USEONLY 0x0001 - -class CTriggerEndSection : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT EndSectionTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection ); - - -void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Only save on clients - if ( pActivator && !pActivator->IsNetClient() ) - return; - - SetUse( NULL ); - - if ( pev->message ) - { - g_engfuncs.pfnEndSection(STRING(pev->message)); - } - UTIL_Remove( this ); -} - -void CTriggerEndSection::Spawn( void ) -{ - if ( g_pGameRules->IsDeathmatch() ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - - InitTrigger(); - - SetUse ( &CTriggerEndSection::EndSectionUse ); - // If it is a "use only" trigger, then don't set the touch function. - if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) - SetTouch( &CTriggerEndSection::EndSectionTouch ); -} - -void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) -{ - // Only save on clients - if ( !pOther->IsNetClient() ) - return; - - SetTouch( NULL ); - - if (pev->message) - { - g_engfuncs.pfnEndSection(STRING(pev->message)); - } - UTIL_Remove( this ); -} - -void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "section")) - { -// m_iszSectionName = ALLOC_STRING( pkvd->szValue ); - // Store this in message so we don't have to write save/restore for this ent - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseTrigger::KeyValue( pkvd ); -} - - -class CTriggerGravity : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT GravityTouch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); - -void CTriggerGravity::Spawn( void ) -{ - InitTrigger(); - SetTouch( &CTriggerGravity::GravityTouch ); -} - -void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) -{ - // Only save on clients - if ( !pOther->IsPlayer() ) - return; - - pOther->pev->gravity = pev->gravity; -} - - - - - - - -// this is a really bad idea. -class CTriggerChangeTarget : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_iszNewTarget; -}; -LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ); - -TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay); - -void CTriggerChangeTarget::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszNewTarget")) - { - m_iszNewTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - -void CTriggerChangeTarget::Spawn( void ) -{ -} - - -void CTriggerChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pTarget = UTIL_FindEntityByString( NULL, "targetname", STRING( pev->target ) ); - - if (pTarget) - { - pTarget->pev->target = m_iszNewTarget; - CBaseMonster *pMonster = pTarget->MyMonsterPointer( ); - if (pMonster) - { - pMonster->m_pGoalEnt = NULL; - } - } -} - - - - -#define SF_CAMERA_PLAYER_POSITION 1 -#define SF_CAMERA_PLAYER_TARGET 2 -#define SF_CAMERA_PLAYER_TAKECONTROL 4 - -class CTriggerCamera : public CBaseDelay -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT FollowTarget( void ); - void Move(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; - - EHANDLE m_hPlayer; - EHANDLE m_hTarget; - CBaseEntity *m_pentPath; - int m_sPath; - float m_flWait; - float m_flReturnTime; - float m_flStopTime; - float m_moveDistance; - float m_targetSpeed; - float m_initialSpeed; - float m_acceleration; - float m_deceleration; - int m_state; - -}; -LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ); - -// Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerCamera, m_hPlayer, FIELD_EHANDLE ), - DEFINE_FIELD( CTriggerCamera, m_hTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CTriggerCamera, m_pentPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CTriggerCamera, m_sPath, FIELD_STRING ), - DEFINE_FIELD( CTriggerCamera, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_flReturnTime, FIELD_TIME ), - DEFINE_FIELD( CTriggerCamera, m_flStopTime, FIELD_TIME ), - DEFINE_FIELD( CTriggerCamera, m_moveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_targetSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_initialSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_acceleration, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_deceleration, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay); - -void CTriggerCamera::Spawn( void ) -{ - pev->movetype = MOVETYPE_NOCLIP; - pev->solid = SOLID_NOT; // Remove model & collisions - pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on - pev->rendermode = kRenderTransTexture; - - m_initialSpeed = pev->speed; - if ( m_acceleration == 0 ) - m_acceleration = 500; - if ( m_deceleration == 0 ) - m_deceleration = 500; -} - - -void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "moveto")) - { - m_sPath = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "acceleration")) - { - m_acceleration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "deceleration")) - { - m_deceleration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - - -void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_state ) ) - return; - - // Toggle state - m_state = !m_state; - if (m_state == 0) - { - m_flReturnTime = gpGlobals->time; - return; - } - if ( !pActivator || !pActivator->IsPlayer() ) - { - pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex( 1 )); - } - - m_hPlayer = pActivator; - - m_flReturnTime = gpGlobals->time + m_flWait; - pev->speed = m_initialSpeed; - m_targetSpeed = m_initialSpeed; - - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TARGET ) ) - { - m_hTarget = m_hPlayer; - } - else - { - m_hTarget = GetNextTarget(); - } - - // Nothing to look at! - if ( m_hTarget == NULL ) - { - return; - } - - - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) - { - ((CBasePlayer *)pActivator)->EnableControl(FALSE); - } - - if ( m_sPath ) - { - m_pentPath = Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_sPath)) ); - } - else - { - m_pentPath = NULL; - } - - m_flStopTime = gpGlobals->time; - if ( m_pentPath ) - { - if ( m_pentPath->pev->speed != 0 ) - m_targetSpeed = m_pentPath->pev->speed; - - m_flStopTime += m_pentPath->GetDelay(); - } - - // copy over player information - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_POSITION ) ) - { - UTIL_SetOrigin( pev, pActivator->pev->origin + pActivator->pev->view_ofs ); - pev->angles.x = -pActivator->pev->angles.x; - pev->angles.y = pActivator->pev->angles.y; - pev->angles.z = 0; - pev->velocity = pActivator->pev->velocity; - } - else - { - pev->velocity = Vector( 0, 0, 0 ); - } - - SET_VIEW( pActivator->edict(), edict() ); - - SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); - - // follow the player down - SetThink( &CTriggerCamera::FollowTarget ); - pev->nextthink = gpGlobals->time; - - m_moveDistance = 0; - Move(); -} - - -void CTriggerCamera::FollowTarget( ) -{ - if (m_hPlayer == NULL) - return; - - if (m_hTarget == NULL || m_flReturnTime < gpGlobals->time) - { - if (m_hPlayer->IsAlive( )) - { - SET_VIEW( m_hPlayer->edict(), m_hPlayer->edict() ); - ((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE); - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); - pev->avelocity = Vector( 0, 0, 0 ); - m_state = 0; - return; - } - - Vector vecGoal = UTIL_VecToAngles( m_hTarget->pev->origin - pev->origin ); - vecGoal.x = -vecGoal.x; - - if (pev->angles.y > 360) - pev->angles.y -= 360; - - if (pev->angles.y < 0) - pev->angles.y += 360; - - float dx = vecGoal.x - pev->angles.x; - float dy = vecGoal.y - pev->angles.y; - - if (dx < -180) - dx += 360; - if (dx > 180) - dx = dx - 360; - - if (dy < -180) - dy += 360; - if (dy > 180) - dy = dy - 360; - - pev->avelocity.x = dx * 40 * gpGlobals->frametime; - pev->avelocity.y = dy * 40 * gpGlobals->frametime; - - - if (!(FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL))) - { - pev->velocity = pev->velocity * 0.8; - if (pev->velocity.Length( ) < 10.0) - pev->velocity = g_vecZero; - } - - pev->nextthink = gpGlobals->time; - - Move(); -} - -void CTriggerCamera::Move() -{ - // Not moving on a path, return - if (!m_pentPath) - return; - - // Subtract movement from the previous frame - m_moveDistance -= pev->speed * gpGlobals->frametime; - - // Have we moved enough to reach the target? - if ( m_moveDistance <= 0 ) - { - // Fire the passtarget if there is one - if ( m_pentPath->pev->message ) - { - FireTargets( STRING(m_pentPath->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pentPath->pev->spawnflags, SF_CORNER_FIREONCE ) ) - m_pentPath->pev->message = 0; - } - // Time to go to the next target - m_pentPath = m_pentPath->GetNextTarget(); - - // Set up next corner - if ( !m_pentPath ) - { - pev->velocity = g_vecZero; - } - else - { - if ( m_pentPath->pev->speed != 0 ) - m_targetSpeed = m_pentPath->pev->speed; - - Vector delta = m_pentPath->pev->origin - pev->origin; - m_moveDistance = delta.Length(); - pev->movedir = delta.Normalize(); - m_flStopTime = gpGlobals->time + m_pentPath->GetDelay(); - } - } - - if ( m_flStopTime > gpGlobals->time ) - pev->speed = UTIL_Approach( 0, pev->speed, m_deceleration * gpGlobals->frametime ); - else - pev->speed = UTIL_Approach( m_targetSpeed, pev->speed, m_acceleration * gpGlobals->frametime ); - - float fraction = 2 * gpGlobals->frametime; - pev->velocity = ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1-fraction)); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== triggers.cpp ======================================================== + + spawn and use functions for editor-placed triggers + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "saverestore.h" +#include "trains.h" // trigger_camera has train functionality +#include "gamerules.h" +#include "triggers.h" +#include "../mod/AvHServerVariables.h" + +#define SF_TRIGGER_PUSH_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF +#define SF_TRIGGER_HURT_TARGETONCE 1// Only fire hurt target once +#define SF_TRIGGER_HURT_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF +#define SF_TRIGGER_HURT_NO_CLIENTS 8//spawnflag that makes trigger_push spawn turned OFF +#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16// trigger hurt will only fire its target if it is hurting a client +#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32// only clients may touch this trigger. + +extern DLL_GLOBAL BOOL g_fGameOver; + +extern void SetMovedir(entvars_t* pev); +extern Vector VecBModelOrigin( entvars_t* pevBModel ); + +class CFrictionModifier : public CBaseEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT ChangeFriction( CBaseEntity *pOther ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + static TYPEDESCRIPTION m_SaveData[]; + + float m_frictionFraction; // Sorry, couldn't resist this name :) +}; + +LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ); + +// Global Savedata for changelevel friction modifier +TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = +{ + DEFINE_FIELD( CFrictionModifier, m_frictionFraction, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE(CFrictionModifier,CBaseEntity); + + +// Modify an entity's friction +void CFrictionModifier :: Spawn( void ) +{ + pev->solid = SOLID_TRIGGER; + SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + pev->movetype = MOVETYPE_NONE; + SetTouch( &CFrictionModifier::ChangeFriction ); +} + + +// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) +void CFrictionModifier :: ChangeFriction( CBaseEntity *pOther ) +{ + if ( pOther->pev->movetype != MOVETYPE_BOUNCEMISSILE && pOther->pev->movetype != MOVETYPE_BOUNCE ) + pOther->pev->friction = m_frictionFraction; +} + + + +// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) +void CFrictionModifier :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "modifier")) + { + m_frictionFraction = atof(pkvd->szValue) / 100.0; + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + + +// This trigger will fire when the level spawns (or respawns if not fire once) +// It will check a global state before firing. It supports delay and killtargets + +#define SF_AUTO_FIREONCE 0x0001 + +class CAutoTrigger : public CBaseDelay +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Spawn( void ); + void Precache( void ); + void Think( void ); + + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + int m_globalstate; + USE_TYPE triggerType; +}; +LINK_ENTITY_TO_CLASS( trigger_auto, CAutoTrigger ); + +TYPEDESCRIPTION CAutoTrigger::m_SaveData[] = +{ + DEFINE_FIELD( CAutoTrigger, m_globalstate, FIELD_STRING ), + DEFINE_FIELD( CAutoTrigger, triggerType, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE(CAutoTrigger,CBaseDelay); + +void CAutoTrigger::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "globalstate")) + { + m_globalstate = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "triggerstate")) + { + int type = atoi( pkvd->szValue ); + switch( type ) + { + case 0: + triggerType = USE_OFF; + break; + case 2: + triggerType = USE_TOGGLE; + break; + default: + triggerType = USE_ON; + break; + } + pkvd->fHandled = TRUE; + } + else + CBaseDelay::KeyValue( pkvd ); +} + + +void CAutoTrigger::Spawn( void ) +{ + Precache(); +} + + +void CAutoTrigger::Precache( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CAutoTrigger::Think( void ) +{ + if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) + { + SUB_UseTargets( this, triggerType, 0 ); + if ( pev->spawnflags & SF_AUTO_FIREONCE ) + UTIL_Remove( this ); + } +} + + + +#define SF_RELAY_FIREONCE 0x0001 + +class CTriggerRelay : public CBaseDelay +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + USE_TYPE triggerType; +}; +LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ); + +TYPEDESCRIPTION CTriggerRelay::m_SaveData[] = +{ + DEFINE_FIELD( CTriggerRelay, triggerType, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE(CTriggerRelay,CBaseDelay); + +void CTriggerRelay::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "triggerstate")) + { + int type = atoi( pkvd->szValue ); + switch( type ) + { + case 0: + triggerType = USE_OFF; + break; + case 2: + triggerType = USE_TOGGLE; + break; + default: + triggerType = USE_ON; + break; + } + pkvd->fHandled = TRUE; + } + else + CBaseDelay::KeyValue( pkvd ); +} + + +void CTriggerRelay::Spawn( void ) +{ +} + + + + +void CTriggerRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SUB_UseTargets( this, triggerType, 0 ); + if ( pev->spawnflags & SF_RELAY_FIREONCE ) + UTIL_Remove( this ); +} + + +//********************************************************** +// The Multimanager Entity - when fired, will fire up to 16 targets +// at specified times. +// FLAG: THREAD (create clones when triggered) +// FLAG: CLONE (this is a clone for a threaded execution) + +#define SF_MULTIMAN_CLONE 0x80000000 +#define SF_MULTIMAN_THREAD 0x00000001 + +class CMultiManager : public CBaseToggle +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Spawn ( void ); + void EXPORT ManagerThink ( void ); + void EXPORT ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +#if _DEBUG + void EXPORT ManagerReport( void ); +#endif + + BOOL HasTarget( string_t targetname ); + + int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + int m_cTargets; // the total number of targets in this manager's fire list. + int m_index; // Current target + float m_startTime;// Time we started firing + int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array + float m_flTargetDelay [ MAX_MULTI_TARGETS ];// delay (in seconds) from time of manager fire to target fire +private: + inline BOOL IsClone( void ) { return (pev->spawnflags & SF_MULTIMAN_CLONE) ? TRUE : FALSE; } + inline BOOL ShouldClone( void ) + { + if ( IsClone() ) + return FALSE; + + return (pev->spawnflags & SF_MULTIMAN_THREAD) ? TRUE : FALSE; + } + + CMultiManager *Clone( void ); +}; +LINK_ENTITY_TO_CLASS( multi_manager, CMultiManager ); + +// Global Savedata for multi_manager +TYPEDESCRIPTION CMultiManager::m_SaveData[] = +{ + DEFINE_FIELD( CMultiManager, m_cTargets, FIELD_INTEGER ), + DEFINE_FIELD( CMultiManager, m_index, FIELD_INTEGER ), + DEFINE_FIELD( CMultiManager, m_startTime, FIELD_TIME ), + DEFINE_ARRAY( CMultiManager, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), + DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), +}; + +IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle); + +void CMultiManager :: KeyValue( KeyValueData *pkvd ) +{ + // UNDONE: Maybe this should do something like this: + //CBaseToggle::KeyValue( pkvd ); + // if ( !pkvd->fHandled ) + // ... etc. + + if (FStrEq(pkvd->szKeyName, "wait")) + { + m_flWait = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else // add this field to the target list + { + // this assumes that additional fields are targetnames and their values are delay values. + if ( m_cTargets < MAX_MULTI_TARGETS ) + { + char tmp[128]; + + UTIL_StripToken( pkvd->szKeyName, tmp ); + m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp ); + m_flTargetDelay [ m_cTargets ] = atof (pkvd->szValue); + m_cTargets++; + pkvd->fHandled = TRUE; + } + } +} + + +void CMultiManager :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + SetUse ( &CMultiManager::ManagerUse ); + SetThink (&CMultiManager::ManagerThink); + + // Sort targets + // Quick and dirty bubble sort + int swapped = 1; + + while ( swapped ) + { + swapped = 0; + for ( int i = 1; i < m_cTargets; i++ ) + { + if ( m_flTargetDelay[i] < m_flTargetDelay[i-1] ) + { + // Swap out of order elements + int name = m_iTargetName[i]; + float delay = m_flTargetDelay[i]; + m_iTargetName[i] = m_iTargetName[i-1]; + m_flTargetDelay[i] = m_flTargetDelay[i-1]; + m_iTargetName[i-1] = name; + m_flTargetDelay[i-1] = delay; + swapped = 1; + } + } + } +} + + +BOOL CMultiManager::HasTarget( string_t targetname ) +{ + for ( int i = 0; i < m_cTargets; i++ ) + if ( FStrEq(STRING(targetname), STRING(m_iTargetName[i])) ) + return TRUE; + + return FALSE; +} + + +// Designers were using this to fire targets that may or may not exist -- +// so I changed it to use the standard target fire code, made it a little simpler. +void CMultiManager :: ManagerThink ( void ) +{ + float time; + + time = gpGlobals->time - m_startTime; + while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time ) + { + FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 ); + m_index++; + } + + if ( m_index >= m_cTargets )// have we fired all targets? + { + SetThink( NULL ); + if ( IsClone() ) + { + UTIL_Remove( this ); + return; + } + SetUse ( &CMultiManager::ManagerUse );// allow manager re-use + } + else + pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; +} + +CMultiManager *CMultiManager::Clone( void ) +{ + CMultiManager *pMulti = GetClassPtr( (CMultiManager *)NULL ); + + edict_t *pEdict = pMulti->pev->pContainingEntity; + memcpy( pMulti->pev, pev, sizeof(*pev) ); + pMulti->pev->pContainingEntity = pEdict; + + pMulti->pev->spawnflags |= SF_MULTIMAN_CLONE; + pMulti->m_cTargets = m_cTargets; + memcpy( pMulti->m_iTargetName, m_iTargetName, sizeof( m_iTargetName ) ); + memcpy( pMulti->m_flTargetDelay, m_flTargetDelay, sizeof( m_flTargetDelay ) ); + + return pMulti; +} + + +// The USE function builds the time table and starts the entity thinking. +void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // In multiplayer games, clone the MM and execute in the clone (like a thread) + // to allow multiple players to trigger the same multimanager + if ( ShouldClone() ) + { + CMultiManager *pClone = Clone(); + pClone->ManagerUse( pActivator, pCaller, useType, value ); + return; + } + + m_hActivator = pActivator; + m_index = 0; + m_startTime = gpGlobals->time; + + SetUse( NULL );// disable use until all targets have fired + + SetThink ( &CMultiManager::ManagerThink ); + pev->nextthink = gpGlobals->time; +} + +#if _DEBUG +void CMultiManager :: ManagerReport ( void ) +{ + int cIndex; + + for ( cIndex = 0 ; cIndex < m_cTargets ; cIndex++ ) + { + ALERT ( at_console, "%s %f\n", STRING(m_iTargetName[cIndex]), m_flTargetDelay[cIndex] ); + } +} +#endif + +//*********************************************************** + + +// +// Render parameters trigger +// +// This entity will copy its render parameters (renderfx, rendermode, rendercolor, renderamt) +// to its targets when triggered. +// + + +// Flags to indicate masking off various render parameters that are normally copied to the targets +#define SF_RENDER_MASKFX (1<<0) +#define SF_RENDER_MASKAMT (1<<1) +#define SF_RENDER_MASKMODE (1<<2) +#define SF_RENDER_MASKCOLOR (1<<3) + +class CRenderFxManager : public CBaseEntity +{ +public: + void Spawn( void ); + void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ); + + +void CRenderFxManager :: Spawn ( void ) +{ + pev->solid = SOLID_NOT; +} + +void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if (!FStringNull(pev->target)) + { + edict_t* pentTarget = NULL; + while ( 1 ) + { + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); + if (FNullEnt(pentTarget)) + break; + + entvars_t *pevTarget = VARS( pentTarget ); + if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) ) + pevTarget->renderfx = pev->renderfx; + if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) + pevTarget->renderamt = pev->renderamt; + if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) + pevTarget->rendermode = pev->rendermode; + if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) + pevTarget->rendercolor = pev->rendercolor; + } + } +} + + + +LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ); + +/* +================ +InitTrigger +================ +*/ +void CBaseTrigger::InitTrigger( ) +{ + // trigger angles are used for one-way touches. An angle of 0 is assumed + // to mean no restrictions, so use a yaw of 360 instead. + if (pev->angles != g_vecZero) + SetMovedir(pev); + pev->solid = SOLID_TRIGGER; + pev->movetype = MOVETYPE_NONE; + SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + if ( ns_cvar_float(showtriggers) == 0 ) + SetBits( pev->effects, EF_NODRAW ); +} + + +// +// Cache user-entity-field values until spawn is called. +// + +void CBaseTrigger :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "damage")) + { + pev->dmg = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "count")) + { + m_cTriggersLeft = (int) atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "damagetype")) + { + m_bitsDamageInflict = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseToggle::KeyValue( pkvd ); +} + +class CTriggerHurt : public CBaseTrigger +{ +public: + void Spawn( void ); + void EXPORT RadiationThink( void ); +}; + +LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ); + +// +// trigger_monsterjump +// +class CTriggerMonsterJump : public CBaseTrigger +{ +public: + void Spawn( void ); + void Touch( CBaseEntity *pOther ); + void Think( void ); +}; + +LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ); + + +void CTriggerMonsterJump :: Spawn ( void ) +{ + SetMovedir ( pev ); + + InitTrigger (); + + pev->nextthink = 0; + pev->speed = 200; + m_flHeight = 150; + + if ( !FStringNull ( pev->targetname ) ) + {// if targetted, spawn turned off + pev->solid = SOLID_NOT; + UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list + SetUse( &CTriggerMonsterJump::ToggleUse ); + } +} + + +void CTriggerMonsterJump :: Think( void ) +{ + pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE + UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list + SetThink( NULL ); +} + +void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) + {// touched by a non-monster. + return; + } + + pevOther->origin.z += 1; + + if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) + {// clear the onground so physics don't bitch + pevOther->flags &= ~FL_ONGROUND; + } + + // toss the monster! + pevOther->velocity = pev->movedir * pev->speed; + pevOther->velocity.z += m_flHeight; + pev->nextthink = gpGlobals->time; +} + + +//===================================== +// +// trigger_cdaudio - starts/stops cd audio tracks +// +class CTriggerCDAudio : public CBaseTrigger +{ +public: + void Spawn( void ); + + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void PlayTrack( void ); + void Touch ( CBaseEntity *pOther ); +}; + +LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ); + +// +// Changes tracks or stops CD when player touches +// +// !!!HACK - overloaded HEALTH to avoid adding new field +void CTriggerCDAudio :: Touch ( CBaseEntity *pOther ) +{ + if ( !pOther->IsPlayer() ) + {// only clients may trigger these events + return; + } + + PlayTrack(); +} + +void CTriggerCDAudio :: Spawn( void ) +{ + InitTrigger(); +} + +void CTriggerCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + PlayTrack(); +} + +void PlayCDTrack( int iTrack ) +{ + edict_t *pClient; + + // manually find the single player. + pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + + // Can't play if the client is not connected! + if ( !pClient ) + return; + + if ( iTrack < -1 || iTrack > 30 ) + { + ALERT ( at_console, "TriggerCDAudio - Track %d out of range\n" ); + return; + } + + if ( iTrack == -1 ) + { + CLIENT_COMMAND ( pClient, "cd pause\n"); + } + else + { + char string [ 64 ]; + + sprintf( string, "cd play %3d\n", iTrack ); + CLIENT_COMMAND ( pClient, string); + } +} + + +// only plays for ONE client, so only use in single play! +void CTriggerCDAudio :: PlayTrack( void ) +{ + PlayCDTrack( (int)pev->health ); + + SetTouch( NULL ); + UTIL_Remove( this ); +} + + +// This plays a CD track when fired or when the player enters it's radius +class CTargetCDAudio : public CPointEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Think( void ); + void Play( void ); +}; + +LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudio ); + +void CTargetCDAudio :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "radius")) + { + pev->scale = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +void CTargetCDAudio :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + + if ( pev->scale > 0 ) + pev->nextthink = gpGlobals->time + 1.0; +} + +void CTargetCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + Play(); +} + +// only plays for ONE client, so only use in single play! +void CTargetCDAudio::Think( void ) +{ + edict_t *pClient; + + // manually find the single player. + pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + + // Can't play if the client is not connected! + if ( !pClient ) + return; + + pev->nextthink = gpGlobals->time + 0.5; + + if ( (pClient->v.origin - pev->origin).Length() <= pev->scale ) + Play(); + +} + +void CTargetCDAudio::Play( void ) +{ + PlayCDTrack( (int)pev->health ); + UTIL_Remove(this); +} + +//===================================== + +// +// trigger_hurt - hurts anything that touches it. if the trigger has a targetname, firing it will toggle state +// +//int gfToggleState = 0; // used to determine when all radiation trigger hurts have called 'RadiationThink' + +void CTriggerHurt :: Spawn( void ) +{ + InitTrigger(); + SetTouch ( &CTriggerHurt::HurtTouch ); + + if ( !FStringNull ( pev->targetname ) ) + { + SetUse ( &CTriggerHurt::ToggleUse ); + } + else + { + SetUse ( NULL ); + } + + if (m_bitsDamageInflict & DMG_RADIATION) + { + SetThink ( &CTriggerHurt::RadiationThink ); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); + } + + if ( FBitSet (pev->spawnflags, SF_TRIGGER_HURT_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. + pev->solid = SOLID_NOT; + + UTIL_SetOrigin( pev, pev->origin ); // Link into the list +} + +// trigger hurt that causes radiation will do a radius +// check and set the player's geiger counter level +// according to distance from center of trigger + +void CTriggerHurt :: RadiationThink( void ) +{ + + edict_t *pentPlayer; + CBasePlayer *pPlayer = NULL; + float flRange; + entvars_t *pevTarget; + Vector vecSpot1; + Vector vecSpot2; + Vector vecRange; + Vector origin; + Vector view_ofs; + + // check to see if a player is in pvs + // if not, continue + + // set origin to center of trigger so that this check works + origin = pev->origin; + view_ofs = pev->view_ofs; + + pev->origin = (pev->absmin + pev->absmax) * 0.5; + pev->view_ofs = pev->view_ofs * 0.0; + + pentPlayer = FIND_CLIENT_IN_PVS(edict()); + + pev->origin = origin; + pev->view_ofs = view_ofs; + + // reset origin + + if (!FNullEnt(pentPlayer)) + { + + pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); + + pevTarget = VARS(pentPlayer); + + // get range to player; + + vecSpot1 = (pev->absmin + pev->absmax) * 0.5; + vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5; + + vecRange = vecSpot1 - vecSpot2; + flRange = vecRange.Length(); + + // if player's current geiger counter range is larger + // than range to this trigger hurt, reset player's + // geiger counter range + + if (pPlayer->m_flgeigerRange >= flRange) + pPlayer->m_flgeigerRange = flRange; + } + + pev->nextthink = gpGlobals->time + 0.25; +} + +// +// ToggleUse - If this is the USE function for a trigger, its state will toggle every time it's fired +// +void CBaseTrigger :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if (pev->solid == SOLID_NOT) + {// if the trigger is off, turn it on + pev->solid = SOLID_TRIGGER; + + // Force retouch + gpGlobals->force_retouch++; + } + else + {// turn the trigger off + pev->solid = SOLID_NOT; + } + UTIL_SetOrigin( pev, pev->origin ); +} + +// When touched, a hurt trigger does DMG points of damage each half-second +void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) +{ + float fldmg; + + if ( !pOther->pev->takedamage ) + return; + + if ( (pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH) && !pOther->IsPlayer() ) + { + // this trigger is only allowed to touch clients, and this ain't a client. + return; + } + + if ( (pev->spawnflags & SF_TRIGGER_HURT_NO_CLIENTS) && pOther->IsPlayer() ) + return; + + // HACKHACK -- In multiplayer, players touch this based on packet receipt. + // So the players who send packets later aren't always hurt. Keep track of + // how much time has passed and whether or not you've touched that player + if ( g_pGameRules->IsMultiplayer() ) + { + if ( pev->dmgtime > gpGlobals->time ) + { + if ( gpGlobals->time != pev->pain_finished ) + {// too early to hurt again, and not same frame with a different entity + if ( pOther->IsPlayer() ) + { + int playerMask = 1 << (pOther->entindex() - 1); + + // If I've already touched this player (this time), then bail out + if ( pev->impulse & playerMask ) + return; + + // Mark this player as touched + // BUGBUG - There can be only 32 players! + pev->impulse |= playerMask; + } + else + { + return; + } + } + } + else + { + // New clock, "un-touch" all players + pev->impulse = 0; + if ( pOther->IsPlayer() ) + { + int playerMask = 1 << (pOther->entindex() - 1); + + // Mark this player as touched + // BUGBUG - There can be only 32 players! + pev->impulse |= playerMask; + } + } + } + else // Original code -- single player + { + if ( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) + {// too early to hurt again, and not same frame with a different entity + return; + } + } + + + + // If this is time_based damage (poison, radiation), override the pev->dmg with a + // default for the given damage type. Monsters only take time-based damage + // while touching the trigger. Player continues taking damage for a while after + // leaving the trigger + + fldmg = pev->dmg * 0.5; // 0.5 seconds worth of damage, pev->dmg is damage/second + + + // JAY: Cut this because it wasn't fully realized. Damage is simpler now. +#if 0 + switch (m_bitsDamageInflict) + { + default: break; + case DMG_POISON: fldmg = POISON_DAMAGE/4; break; + case DMG_NERVEGAS: fldmg = NERVEGAS_DAMAGE/4; break; + case DMG_RADIATION: fldmg = RADIATION_DAMAGE/4; break; + case DMG_PARALYZE: fldmg = PARALYZE_DAMAGE/4; break; // UNDONE: cut this? should slow movement to 50% + case DMG_ACID: fldmg = ACID_DAMAGE/4; break; + case DMG_SLOWBURN: fldmg = SLOWBURN_DAMAGE/4; break; + case DMG_SLOWFREEZE: fldmg = SLOWFREEZE_DAMAGE/4; break; + } +#endif + + if ( fldmg < 0 ) + pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); + else + pOther->TakeDamage( pev, pev, fldmg, m_bitsDamageInflict ); + + // Store pain time so we can get all of the other entities on this frame + pev->pain_finished = gpGlobals->time; + + // Apply damage every half second + pev->dmgtime = gpGlobals->time + 0.5;// half second delay until this trigger can hurt toucher again + + + + if ( pev->target ) + { + // trigger has a target it wants to fire. + if ( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE ) + { + // if the toucher isn't a client, don't fire the target! + if ( !pOther->IsPlayer() ) + { + return; + } + } + + SUB_UseTargets( pOther, USE_TOGGLE, 0 ); + if ( pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE ) + pev->target = 0; + } +} + + +/*QUAKED trigger_multiple (.5 .5 .5) ? notouch +Variable sized repeatable trigger. Must be targeted at one or more entities. +If "health" is set, the trigger must be killed to activate each time. +If "delay" is set, the trigger waits some time after activating before firing. +"wait" : Seconds between triggerings. (.2 default) +If notouch is set, the trigger is only fired by other entities, not by touching. +NOTOUCH has been obsoleted by trigger_relay! +sounds +1) secret +2) beep beep +3) large switch +4) +NEW +if a trigger has a NETNAME, that NETNAME will become the TARGET of the triggered object. +*/ +class CTriggerMultiple : public CBaseTrigger +{ +public: + void Spawn( void ); +}; + +LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ); + + +void CTriggerMultiple :: Spawn( void ) +{ + if (m_flWait == 0) + m_flWait = 0.2; + + InitTrigger(); + + ASSERTSZ(pev->health == 0, "trigger_multiple with health"); +// UTIL_SetOrigin(pev, pev->origin); +// SET_MODEL( ENT(pev), STRING(pev->model) ); +// if (pev->health > 0) +// { +// if (FBitSet(pev->spawnflags, SPAWNFLAG_NOTOUCH)) +// ALERT(at_error, "trigger_multiple spawn: health and notouch don't make sense"); +// pev->max_health = pev->health; +//UNDONE: where to get pfnDie from? +// pev->pfnDie = multi_killed; +// pev->takedamage = DAMAGE_YES; +// pev->solid = SOLID_BBOX; +// UTIL_SetOrigin(pev, pev->origin); // make sure it links into the world +// } +// else + { + SetTouch( &CTriggerMultiple::MultiTouch ); + } + } + + +/*QUAKED trigger_once (.5 .5 .5) ? notouch +Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching +"targetname". If "health" is set, the trigger must be killed to activate. +If notouch is set, the trigger is only fired by other entities, not by touching. +if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. +if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. +sounds +1) secret +2) beep beep +3) large switch +4) +*/ +class CTriggerOnce : public CTriggerMultiple +{ +public: + void Spawn( void ); +}; + +LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ); +void CTriggerOnce::Spawn( void ) +{ + m_flWait = -1; + + CTriggerMultiple :: Spawn(); +} + + + +void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) +{ + entvars_t *pevToucher; + + pevToucher = pOther->pev; + + // Only touch clients, monsters, or pushables (depending on flags) + if ( ((pevToucher->flags & FL_CLIENT) && !(pev->spawnflags & SF_TRIGGER_NOCLIENTS)) || + ((pevToucher->flags & FL_MONSTER) && (pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS)) || + (pev->spawnflags & SF_TRIGGER_PUSHABLES) && FClassnameIs(pevToucher,"func_pushable") ) + { + +#if 0 + // if the trigger has an angles field, check player's facing direction + if (pev->movedir != g_vecZero) + { + UTIL_MakeVectors( pevToucher->angles ); + if ( DotProduct( gpGlobals->v_forward, pev->movedir ) < 0 ) + return; // not facing the right way + } +#endif + + ActivateMultiTrigger( pOther ); + } +} + + +// +// the trigger was just touched/killed/used +// self.enemy should be set to the activator so it can be held through a delay +// so wait for the delay time before firing +// +void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) +{ + if (pev->nextthink > gpGlobals->time) + return; // still waiting for reset time + + if (!UTIL_IsMasterTriggered(m_sMaster,pActivator)) + return; + + if (FClassnameIs(pev, "trigger_secret")) + { + if ( pev->enemy == NULL || !FClassnameIs(pev->enemy, "player")) + return; + gpGlobals->found_secrets++; + } + + if (!FStringNull(pev->noise)) + EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + +// don't trigger again until reset +// pev->takedamage = DAMAGE_NO; + + m_hActivator = pActivator; + SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); + + if ( pev->message && pActivator->IsPlayer() ) + { + UTIL_ShowMessage( STRING(pev->message), pActivator ); +// CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); + } + + if (m_flWait > 0) + { + SetThink( &CBaseTrigger::MultiWaitOver ); + pev->nextthink = gpGlobals->time + m_flWait; + } + else + { + // we can't just remove (self) here, because this is a touch function + // called while C code is looping through area links... + SetTouch( NULL ); + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CBaseTrigger::SUB_Remove ); + } +} + + +// the wait time has passed, so set back up for another activation +void CBaseTrigger :: MultiWaitOver( void ) +{ +// if (pev->max_health) +// { +// pev->health = pev->max_health; +// pev->takedamage = DAMAGE_YES; +// pev->solid = SOLID_BBOX; +// } + SetThink( NULL ); +} + + +// ========================= COUNTING TRIGGER ===================================== + +// +// GLOBALS ASSUMED SET: g_eoActivator +// +void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + m_cTriggersLeft--; + m_hActivator = pActivator; + + if (m_cTriggersLeft < 0) + return; + + BOOL fTellActivator = + (m_hActivator != 0) && + (FClassnameIs(m_hActivator->pev, "player") && + !FBitSet(pev->spawnflags, SPAWNFLAG_NOMESSAGE)); + if (m_cTriggersLeft != 0) + { + if (fTellActivator) + { + // UNDONE: I don't think we want these Quakesque messages + switch (m_cTriggersLeft) + { + case 1: ALERT(at_console, "Only 1 more to go..."); break; + case 2: ALERT(at_console, "Only 2 more to go..."); break; + case 3: ALERT(at_console, "Only 3 more to go..."); break; + default: ALERT(at_console, "There are more to go..."); break; + } + } + return; + } + + // !!!UNDONE: I don't think we want these Quakesque messages + if (fTellActivator) + ALERT(at_console, "Sequence completed!"); + + ActivateMultiTrigger( m_hActivator ); +} + + +/*QUAKED trigger_counter (.5 .5 .5) ? nomessage +Acts as an intermediary for an action that takes multiple inputs. +If nomessage is not set, it will print "1 more.. " etc when triggered and +"sequence complete" when finished. After the counter has been triggered "cTriggersLeft" +times (default 2), it will fire all of it's targets and remove itself. +*/ +class CTriggerCounter : public CBaseTrigger +{ +public: + void Spawn( void ); +}; +LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ); + +void CTriggerCounter :: Spawn( void ) +{ + // By making the flWait be -1, this counter-trigger will disappear after it's activated + // (but of course it needs cTriggersLeft "uses" before that happens). + m_flWait = -1; + + if (m_cTriggersLeft == 0) + m_cTriggersLeft = 2; + SetUse( &CTriggerCounter::CounterUse ); +} + +// ====================== TRIGGER_CHANGELEVEL ================================ + +class CTriggerVolume : public CPointEntity // Derive from point entity so this doesn't move across levels +{ +public: + void Spawn( void ); +}; + +LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ); + +// Define space that travels across a level transition +void CTriggerVolume :: Spawn( void ) +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + pev->model = NULL; + pev->modelindex = 0; +} + + +// Fires a target after level transition and then dies +class CFireAndDie : public CBaseDelay +{ +public: + void Spawn( void ); + void Precache( void ); + void Think( void ); + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() | FCAP_FORCE_TRANSITION; } // Always go across transitions +}; +LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ); + +void CFireAndDie::Spawn( void ) +{ + pev->classname = MAKE_STRING("fireanddie"); + // Don't call Precache() - it should be called on restore +} + + +void CFireAndDie::Precache( void ) +{ + // This gets called on restore + pev->nextthink = gpGlobals->time + m_flDelay; +} + + +void CFireAndDie::Think( void ) +{ + SUB_UseTargets( this, USE_TOGGLE, 0 ); + UTIL_Remove( this ); +} + + +#define SF_CHANGELEVEL_USEONLY 0x0002 +class CChangeLevel : public CBaseTrigger +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT TriggerChangeLevel( void ); + void EXPORT ExecuteChangeLevel( void ); + void EXPORT TouchChangeLevel( CBaseEntity *pOther ); + void ChangeLevelNow( CBaseEntity *pActivator ); + + static edict_t *FindLandmark( const char *pLandmarkName ); + static int ChangeList( LEVELLIST *pLevelList, int maxList ); + static int AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ); + static int InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + char m_szMapName[cchMapNameMost]; // trigger_changelevel only: next map + char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map + int m_changeTarget; + float m_changeTargetDelay; +}; +LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ); + +// Global Savedata for changelevel trigger +TYPEDESCRIPTION CChangeLevel::m_SaveData[] = +{ + DEFINE_ARRAY( CChangeLevel, m_szMapName, FIELD_CHARACTER, cchMapNameMost ), + DEFINE_ARRAY( CChangeLevel, m_szLandmarkName, FIELD_CHARACTER, cchMapNameMost ), + DEFINE_FIELD( CChangeLevel, m_changeTarget, FIELD_STRING ), + DEFINE_FIELD( CChangeLevel, m_changeTargetDelay, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger); + +// +// Cache user-entity-field values until spawn is called. +// + +void CChangeLevel :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "map")) + { + if (strlen(pkvd->szValue) >= cchMapNameMost) + ALERT( at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue ); + strcpy(m_szMapName, pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "landmark")) + { + if (strlen(pkvd->szValue) >= cchMapNameMost) + ALERT( at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue ); + strcpy(m_szLandmarkName, pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "changetarget")) + { + m_changeTarget = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "changedelay")) + { + m_changeTargetDelay = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseTrigger::KeyValue( pkvd ); +} + + +/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION +When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. +*/ + +void CChangeLevel :: Spawn( void ) +{ + if ( FStrEq( m_szMapName, "" ) ) + ALERT( at_console, "a trigger_changelevel doesn't have a map" ); + + if ( FStrEq( m_szLandmarkName, "" ) ) + ALERT( at_console, "trigger_changelevel to %s doesn't have a landmark", m_szMapName ); + + if (!FStringNull ( pev->targetname ) ) + { + SetUse ( &CChangeLevel::UseChangeLevel ); + } + InitTrigger(); + if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) + SetTouch( &CChangeLevel::TouchChangeLevel ); +// ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); +} + + +void CChangeLevel :: ExecuteChangeLevel( void ) +{ + MESSAGE_BEGIN( MSG_ALL, SVC_CDTRACK ); + WRITE_BYTE( 3 ); + WRITE_BYTE( 3 ); + MESSAGE_END(); + + MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); + MESSAGE_END(); +} + + +FILE_GLOBAL char st_szNextMap[cchMapNameMost]; +FILE_GLOBAL char st_szNextSpot[cchMapNameMost]; + +edict_t *CChangeLevel :: FindLandmark( const char *pLandmarkName ) +{ + edict_t *pentLandmark; + + pentLandmark = FIND_ENTITY_BY_STRING( NULL, "targetname", pLandmarkName ); + while ( !FNullEnt( pentLandmark ) ) + { + // Found the landmark + if ( FClassnameIs( pentLandmark, "info_landmark" ) ) + return pentLandmark; + else + pentLandmark = FIND_ENTITY_BY_STRING( pentLandmark, "targetname", pLandmarkName ); + } + ALERT( at_error, "Can't find landmark %s\n", pLandmarkName ); + return NULL; +} + + +//========================================================= +// CChangeLevel :: Use - allows level transitions to be +// triggered by buttons, etc. +// +//========================================================= +void CChangeLevel :: UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + ChangeLevelNow( pActivator ); +} + +void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) +{ + edict_t *pentLandmark; + LEVELLIST levels[16]; + + ASSERT(!FStrEq(m_szMapName, "")); + + // Don't work in deathmatch + if ( g_pGameRules->IsDeathmatch() ) + return; + + // Some people are firing these multiple times in a frame, disable + if ( gpGlobals->time == pev->dmgtime ) + return; + + pev->dmgtime = gpGlobals->time; + + + CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); + if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) ) + { + ALERT( at_aiconsole, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName ); + return; + } + + // Create an entity to fire the changetarget + if ( m_changeTarget ) + { + CFireAndDie *pFireAndDie = GetClassPtr( (CFireAndDie *)NULL ); + if ( pFireAndDie ) + { + // Set target and delay + pFireAndDie->pev->target = m_changeTarget; + pFireAndDie->m_flDelay = m_changeTargetDelay; + pFireAndDie->pev->origin = pPlayer->pev->origin; + // Call spawn + DispatchSpawn( pFireAndDie->edict() ); + } + } + // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory + strcpy(st_szNextMap, m_szMapName); + + m_hActivator = pActivator; + SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); + st_szNextSpot[0] = 0; // Init landmark to NULL + + // look for a landmark entity + pentLandmark = FindLandmark( m_szLandmarkName ); + if ( !FNullEnt( pentLandmark ) ) + { + strcpy(st_szNextSpot, m_szLandmarkName); + gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; + } +// ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); + ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); + CHANGE_LEVEL( st_szNextMap, st_szNextSpot ); +} + +// +// GLOBALS ASSUMED SET: st_szNextMap +// +void CChangeLevel :: TouchChangeLevel( CBaseEntity *pOther ) +{ + if (!FClassnameIs(pOther->pev, "player")) + return; + + ChangeLevelNow( pOther ); +} + + +// Add a transition to the list, but ignore duplicates +// (a designer may have placed multiple trigger_changelevels with the same landmark) +int CChangeLevel::AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ) +{ + int i; + + if ( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) + return 0; + + for ( i = 0; i < listCount; i++ ) + { + if ( pLevelList[i].pentLandmark == pentLandmark && strcmp( pLevelList[i].mapName, pMapName ) == 0 ) + return 0; + } + strcpy( pLevelList[listCount].mapName, pMapName ); + strcpy( pLevelList[listCount].landmarkName, pLandmarkName ); + pLevelList[listCount].pentLandmark = pentLandmark; + pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin; + + return 1; +} + +int BuildChangeList( LEVELLIST *pLevelList, int maxList ) +{ + return CChangeLevel::ChangeList( pLevelList, maxList ); +} + + +int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) +{ + edict_t *pentVolume; + + + if ( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) + return 1; + + // If you're following another entity, follow it through the transition (weapons follow the player) + if ( pEntity->pev->movetype == MOVETYPE_FOLLOW ) + { + if ( pEntity->pev->aiment != NULL ) + pEntity = CBaseEntity::Instance( pEntity->pev->aiment ); + } + + int inVolume = 1; // Unless we find a trigger_transition, everything is in the volume + + pentVolume = FIND_ENTITY_BY_TARGETNAME( NULL, pVolumeName ); + while ( !FNullEnt( pentVolume ) ) + { + CBaseEntity *pVolume = CBaseEntity::Instance( pentVolume ); + + if ( pVolume && FClassnameIs( pVolume->pev, "trigger_transition" ) ) + { + if ( pVolume->Intersects( pEntity ) ) // It touches one, it's in the volume + return 1; + else + inVolume = 0; // Found a trigger_transition, but I don't intersect it -- if I don't find another, don't go! + } + pentVolume = FIND_ENTITY_BY_TARGETNAME( pentVolume, pVolumeName ); + } + + return inVolume; +} + + +// We can only ever move 512 entities across a transition +#define MAX_ENTITY 512 + +// This has grown into a complicated beast +// Can we make this more elegant? +// This builds the list of all transitions on this level and which entities are in their PVS's and can / should +// be moved across. +int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) +{ + edict_t *pentChangelevel, *pentLandmark; + int i, count; + + count = 0; + + // Find all of the possible level changes on this BSP + pentChangelevel = FIND_ENTITY_BY_STRING( NULL, "classname", "trigger_changelevel" ); + if ( FNullEnt( pentChangelevel ) ) + return 0; + while ( !FNullEnt( pentChangelevel ) ) + { + CChangeLevel *pTrigger; + + pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel)); + if ( pTrigger ) + { + // Find the corresponding landmark + pentLandmark = FindLandmark( pTrigger->m_szLandmarkName ); + if ( pentLandmark ) + { + // Build a list of unique transitions + if ( AddTransitionToList( pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark ) ) + { + count++; + if ( count >= maxList ) // FULL!! + break; + } + } + } + pentChangelevel = FIND_ENTITY_BY_STRING( pentChangelevel, "classname", "trigger_changelevel" ); + } + + if ( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) + { + CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); + + for ( i = 0; i < count; i++ ) + { + int j, entityCount = 0; + CBaseEntity *pEntList[ MAX_ENTITY ]; + int entityFlags[ MAX_ENTITY ]; + + // Follow the linked list of entities in the PVS of the transition landmark + edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); + + // Build a list of valid entities in this linked list (we're going to use pent->v.chain again) + while ( !FNullEnt( pent ) ) + { + CBaseEntity *pEntity = CBaseEntity::Instance(pent); + if ( pEntity ) + { +// ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); + int caps = pEntity->ObjectCaps(); + if ( !(caps & FCAP_DONT_SAVE) ) + { + int flags = 0; + + // If this entity can be moved or is global, mark it + if ( caps & FCAP_ACROSS_TRANSITION ) + flags |= FENTTABLE_MOVEABLE; + if ( pEntity->pev->globalname && !pEntity->IsDormant() ) + flags |= FENTTABLE_GLOBAL; + if ( flags ) + { + pEntList[ entityCount ] = pEntity; + entityFlags[ entityCount ] = flags; + entityCount++; + if ( entityCount > MAX_ENTITY ) + ALERT( at_error, "Too many entities across a transition!" ); + } +// else +// ALERT( at_console, "Failed %s\n", STRING(pEntity->pev->classname) ); + } +// else +// ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); + } + pent = pent->v.chain; + } + + for ( j = 0; j < entityCount; j++ ) + { + // Check to make sure the entity isn't screened out by a trigger_transition + if ( entityFlags[j] && InTransitionVolume( pEntList[j], pLevelList[i].landmarkName ) ) + { + // Mark entity table with 1<pev->classname) ); + + } + } + } + + return count; +} + +/* +go to the next level for deathmatch +only called if a time or frag limit has expired +*/ +void NextLevel( void ) +{ + edict_t* pent; + CChangeLevel *pChange; + + // find a trigger_changelevel + pent = FIND_ENTITY_BY_CLASSNAME(NULL, "trigger_changelevel"); + + // go back to start if no trigger_changelevel + if (FNullEnt(pent)) + { + gpGlobals->mapname = ALLOC_STRING("start"); + pChange = GetClassPtr( (CChangeLevel *)NULL ); + strcpy(pChange->m_szMapName, "start"); + } + else + pChange = GetClassPtr( (CChangeLevel *)VARS(pent)); + + strcpy(st_szNextMap, pChange->m_szMapName); + g_fGameOver = TRUE; + + if (pChange->pev->nextthink < gpGlobals->time) + { + pChange->SetThink( &CChangeLevel::ExecuteChangeLevel ); + pChange->pev->nextthink = gpGlobals->time + 0.1; + } +} + +LINK_ENTITY_TO_CLASS( func_ladder, CLadder ); + + +void CLadder :: KeyValue( KeyValueData *pkvd ) +{ + CBaseTrigger::KeyValue( pkvd ); +} + + +//========================================================= +// func_ladder - makes an area vertically negotiable +//========================================================= +void CLadder :: Precache( void ) +{ + // Do all of this in here because we need to 'convert' old saved games + pev->solid = SOLID_NOT; + pev->skin = CONTENTS_LADDER; + if ( ns_cvar_float(showtriggers) == 0 ) + { + pev->rendermode = kRenderTransTexture; + pev->renderamt = 0; + } + pev->effects &= ~EF_NODRAW; +} + + +void CLadder :: Spawn( void ) +{ + Precache(); + + SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + pev->movetype = MOVETYPE_PUSH; +} + + +// ========================== A TRIGGER THAT PUSHES YOU =============================== + +class CTriggerPush : public CBaseTrigger +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void Touch( CBaseEntity *pOther ); +}; +LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ); + + +void CTriggerPush :: KeyValue( KeyValueData *pkvd ) +{ + CBaseTrigger::KeyValue( pkvd ); +} + + +/*QUAKED trigger_push (.5 .5 .5) ? TRIG_PUSH_ONCE +Pushes the player +*/ + +void CTriggerPush :: Spawn( ) +{ + if ( pev->angles == g_vecZero ) + pev->angles.y = 360; + InitTrigger(); + + if (pev->speed == 0) + pev->speed = 100; + + if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. + pev->solid = SOLID_NOT; + + SetUse(&CTriggerPush::ToggleUse ); + + UTIL_SetOrigin( pev, pev->origin ); // Link into the list +} + + +void CTriggerPush :: Touch( CBaseEntity *pOther ) +{ + entvars_t* pevToucher = pOther->pev; + + // UNDONE: Is there a better way than health to detect things that have physics? (clients/monsters) + switch( pevToucher->movetype ) + { + case MOVETYPE_NONE: + case MOVETYPE_PUSH: + case MOVETYPE_NOCLIP: + case MOVETYPE_FOLLOW: + return; + } + + if ( pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP ) + { + // Instant trigger, just transfer velocity and remove + if (FBitSet(pev->spawnflags, SF_TRIG_PUSH_ONCE)) + { + pevToucher->velocity = pevToucher->velocity + (pev->speed * pev->movedir); + if ( pevToucher->velocity.z > 0 ) + pevToucher->flags &= ~FL_ONGROUND; + UTIL_Remove( this ); + } + else + { // Push field, transfer to base velocity + Vector vecPush = (pev->speed * pev->movedir); + if ( pevToucher->flags & FL_BASEVELOCITY ) + vecPush = vecPush + pevToucher->basevelocity; + + pevToucher->basevelocity = vecPush; + + pevToucher->flags |= FL_BASEVELOCITY; +// ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); + } + } +} + + +//====================================== +// teleport trigger +// +// + +void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) +{ + entvars_t* pevToucher = pOther->pev; + edict_t *pentTarget = NULL; + + // Only teleport monsters or clients + if ( !FBitSet( pevToucher->flags, FL_CLIENT|FL_MONSTER ) ) + return; + + if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) + return; + + if ( !( pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) + {// no monsters allowed! + if ( FBitSet( pevToucher->flags, FL_MONSTER ) ) + { + return; + } + } + + if ( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) + {// no clients allowed + if ( pOther->IsPlayer() ) + { + return; + } + } + + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pev->target) ); + if (FNullEnt(pentTarget)) + return; + + Vector tmp = VARS( pentTarget )->origin; + + if ( pOther->IsPlayer() ) + { + tmp.z -= pOther->pev->mins.z;// make origin adjustments in case the teleportee is a player. (origin in center, not at feet) + } + + tmp.z++; + + pevToucher->flags &= ~FL_ONGROUND; + + UTIL_SetOrigin( pevToucher, tmp ); + + pevToucher->angles = pentTarget->v.angles; + + if ( pOther->IsPlayer() ) + { + pevToucher->v_angle = pentTarget->v.angles; + } + + pevToucher->fixangle = TRUE; + pevToucher->velocity = pevToucher->basevelocity = g_vecZero; +} + + +class CTriggerTeleport : public CBaseTrigger +{ +public: + void Spawn( void ); +}; +LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ); + +void CTriggerTeleport :: Spawn( void ) +{ + InitTrigger(); + + SetTouch( &CTriggerTeleport::TeleportTouch ); +} + + +LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ); + + + +class CTriggerSave : public CBaseTrigger +{ +public: + void Spawn( void ); + void EXPORT SaveTouch( CBaseEntity *pOther ); +}; +LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); + +void CTriggerSave::Spawn( void ) +{ + if ( g_pGameRules->IsDeathmatch() ) + { + REMOVE_ENTITY( ENT(pev) ); + return; + } + + InitTrigger(); + SetTouch( &CTriggerSave::SaveTouch ); +} + +void CTriggerSave::SaveTouch( CBaseEntity *pOther ) +{ + if ( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) + return; + + // Only save on clients + if ( !pOther->IsPlayer() ) + return; + + SetTouch( NULL ); + UTIL_Remove( this ); + SERVER_COMMAND( "autosave\n" ); +} + +#define SF_ENDSECTION_USEONLY 0x0001 + +class CTriggerEndSection : public CBaseTrigger +{ +public: + void Spawn( void ); + void EXPORT EndSectionTouch( CBaseEntity *pOther ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; +LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection ); + + +void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // Only save on clients + if ( pActivator && !pActivator->IsNetClient() ) + return; + + SetUse( NULL ); + + if ( pev->message ) + { + g_engfuncs.pfnEndSection(STRING(pev->message)); + } + UTIL_Remove( this ); +} + +void CTriggerEndSection::Spawn( void ) +{ + if ( g_pGameRules->IsDeathmatch() ) + { + REMOVE_ENTITY( ENT(pev) ); + return; + } + + InitTrigger(); + + SetUse ( &CTriggerEndSection::EndSectionUse ); + // If it is a "use only" trigger, then don't set the touch function. + if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) + SetTouch( &CTriggerEndSection::EndSectionTouch ); +} + +void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) +{ + // Only save on clients + if ( !pOther->IsNetClient() ) + return; + + SetTouch( NULL ); + + if (pev->message) + { + g_engfuncs.pfnEndSection(STRING(pev->message)); + } + UTIL_Remove( this ); +} + +void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "section")) + { +// m_iszSectionName = ALLOC_STRING( pkvd->szValue ); + // Store this in message so we don't have to write save/restore for this ent + pev->message = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseTrigger::KeyValue( pkvd ); +} + + +class CTriggerGravity : public CBaseTrigger +{ +public: + void Spawn( void ); + void EXPORT GravityTouch( CBaseEntity *pOther ); +}; +LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); + +void CTriggerGravity::Spawn( void ) +{ + InitTrigger(); + SetTouch( &CTriggerGravity::GravityTouch ); +} + +void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) +{ + // Only save on clients + if ( !pOther->IsPlayer() ) + return; + + pOther->pev->gravity = pev->gravity; +} + + + + + + + +// this is a really bad idea. +class CTriggerChangeTarget : public CBaseDelay +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + int m_iszNewTarget; +}; +LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ); + +TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = +{ + DEFINE_FIELD( CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING ), +}; + +IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay); + +void CTriggerChangeTarget::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "m_iszNewTarget")) + { + m_iszNewTarget = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseDelay::KeyValue( pkvd ); +} + +void CTriggerChangeTarget::Spawn( void ) +{ +} + + +void CTriggerChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CBaseEntity *pTarget = UTIL_FindEntityByString( NULL, "targetname", STRING( pev->target ) ); + + if (pTarget) + { + pTarget->pev->target = m_iszNewTarget; + CBaseMonster *pMonster = pTarget->MyMonsterPointer( ); + if (pMonster) + { + pMonster->m_pGoalEnt = NULL; + } + } +} + + + + +#define SF_CAMERA_PLAYER_POSITION 1 +#define SF_CAMERA_PLAYER_TARGET 2 +#define SF_CAMERA_PLAYER_TAKECONTROL 4 + +class CTriggerCamera : public CBaseDelay +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT FollowTarget( void ); + void Move(void); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + static TYPEDESCRIPTION m_SaveData[]; + + EHANDLE m_hPlayer; + EHANDLE m_hTarget; + CBaseEntity *m_pentPath; + int m_sPath; + float m_flWait; + float m_flReturnTime; + float m_flStopTime; + float m_moveDistance; + float m_targetSpeed; + float m_initialSpeed; + float m_acceleration; + float m_deceleration; + int m_state; + +}; +LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ); + +// Global Savedata for changelevel friction modifier +TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = +{ + DEFINE_FIELD( CTriggerCamera, m_hPlayer, FIELD_EHANDLE ), + DEFINE_FIELD( CTriggerCamera, m_hTarget, FIELD_EHANDLE ), + DEFINE_FIELD( CTriggerCamera, m_pentPath, FIELD_CLASSPTR ), + DEFINE_FIELD( CTriggerCamera, m_sPath, FIELD_STRING ), + DEFINE_FIELD( CTriggerCamera, m_flWait, FIELD_FLOAT ), + DEFINE_FIELD( CTriggerCamera, m_flReturnTime, FIELD_TIME ), + DEFINE_FIELD( CTriggerCamera, m_flStopTime, FIELD_TIME ), + DEFINE_FIELD( CTriggerCamera, m_moveDistance, FIELD_FLOAT ), + DEFINE_FIELD( CTriggerCamera, m_targetSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CTriggerCamera, m_initialSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CTriggerCamera, m_acceleration, FIELD_FLOAT ), + DEFINE_FIELD( CTriggerCamera, m_deceleration, FIELD_FLOAT ), + DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay); + +void CTriggerCamera::Spawn( void ) +{ + pev->movetype = MOVETYPE_NOCLIP; + pev->solid = SOLID_NOT; // Remove model & collisions + pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on + pev->rendermode = kRenderTransTexture; + + m_initialSpeed = pev->speed; + if ( m_acceleration == 0 ) + m_acceleration = 500; + if ( m_deceleration == 0 ) + m_deceleration = 500; +} + + +void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "wait")) + { + m_flWait = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "moveto")) + { + m_sPath = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "acceleration")) + { + m_acceleration = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "deceleration")) + { + m_deceleration = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseDelay::KeyValue( pkvd ); +} + + + +void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_state ) ) + return; + + // Toggle state + m_state = !m_state; + if (m_state == 0) + { + m_flReturnTime = gpGlobals->time; + return; + } + if ( !pActivator || !pActivator->IsPlayer() ) + { + pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex( 1 )); + } + + m_hPlayer = pActivator; + + m_flReturnTime = gpGlobals->time + m_flWait; + pev->speed = m_initialSpeed; + m_targetSpeed = m_initialSpeed; + + if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TARGET ) ) + { + m_hTarget = m_hPlayer; + } + else + { + m_hTarget = GetNextTarget(); + } + + // Nothing to look at! + if ( m_hTarget == NULL ) + { + return; + } + + + if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) + { + ((CBasePlayer *)pActivator)->EnableControl(FALSE); + } + + if ( m_sPath ) + { + m_pentPath = Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_sPath)) ); + } + else + { + m_pentPath = NULL; + } + + m_flStopTime = gpGlobals->time; + if ( m_pentPath ) + { + if ( m_pentPath->pev->speed != 0 ) + m_targetSpeed = m_pentPath->pev->speed; + + m_flStopTime += m_pentPath->GetDelay(); + } + + // copy over player information + if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_POSITION ) ) + { + UTIL_SetOrigin( pev, pActivator->pev->origin + pActivator->pev->view_ofs ); + pev->angles.x = -pActivator->pev->angles.x; + pev->angles.y = pActivator->pev->angles.y; + pev->angles.z = 0; + pev->velocity = pActivator->pev->velocity; + } + else + { + pev->velocity = Vector( 0, 0, 0 ); + } + + SET_VIEW( pActivator->edict(), edict() ); + + SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); + + // follow the player down + SetThink( &CTriggerCamera::FollowTarget ); + pev->nextthink = gpGlobals->time; + + m_moveDistance = 0; + Move(); +} + + +void CTriggerCamera::FollowTarget( ) +{ + if (m_hPlayer == NULL) + return; + + if (m_hTarget == NULL || m_flReturnTime < gpGlobals->time) + { + if (m_hPlayer->IsAlive( )) + { + SET_VIEW( m_hPlayer->edict(), m_hPlayer->edict() ); + ((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE); + } + SUB_UseTargets( this, USE_TOGGLE, 0 ); + pev->avelocity = Vector( 0, 0, 0 ); + m_state = 0; + return; + } + + Vector vecGoal = UTIL_VecToAngles( m_hTarget->pev->origin - pev->origin ); + vecGoal.x = -vecGoal.x; + + if (pev->angles.y > 360) + pev->angles.y -= 360; + + if (pev->angles.y < 0) + pev->angles.y += 360; + + float dx = vecGoal.x - pev->angles.x; + float dy = vecGoal.y - pev->angles.y; + + if (dx < -180) + dx += 360; + if (dx > 180) + dx = dx - 360; + + if (dy < -180) + dy += 360; + if (dy > 180) + dy = dy - 360; + + pev->avelocity.x = dx * 40 * gpGlobals->frametime; + pev->avelocity.y = dy * 40 * gpGlobals->frametime; + + + if (!(FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL))) + { + pev->velocity = pev->velocity * 0.8; + if (pev->velocity.Length( ) < 10.0) + pev->velocity = g_vecZero; + } + + pev->nextthink = gpGlobals->time; + + Move(); +} + +void CTriggerCamera::Move() +{ + // Not moving on a path, return + if (!m_pentPath) + return; + + // Subtract movement from the previous frame + m_moveDistance -= pev->speed * gpGlobals->frametime; + + // Have we moved enough to reach the target? + if ( m_moveDistance <= 0 ) + { + // Fire the passtarget if there is one + if ( m_pentPath->pev->message ) + { + FireTargets( STRING(m_pentPath->pev->message), this, this, USE_TOGGLE, 0 ); + if ( FBitSet( m_pentPath->pev->spawnflags, SF_CORNER_FIREONCE ) ) + m_pentPath->pev->message = 0; + } + // Time to go to the next target + m_pentPath = m_pentPath->GetNextTarget(); + + // Set up next corner + if ( !m_pentPath ) + { + pev->velocity = g_vecZero; + } + else + { + if ( m_pentPath->pev->speed != 0 ) + m_targetSpeed = m_pentPath->pev->speed; + + Vector delta = m_pentPath->pev->origin - pev->origin; + m_moveDistance = delta.Length(); + pev->movedir = delta.Normalize(); + m_flStopTime = gpGlobals->time + m_pentPath->GetDelay(); + } + } + + if ( m_flStopTime > gpGlobals->time ) + pev->speed = UTIL_Approach( 0, pev->speed, m_deceleration * gpGlobals->frametime ); + else + pev->speed = UTIL_Approach( m_targetSpeed, pev->speed, m_acceleration * gpGlobals->frametime ); + + float fraction = 2 * gpGlobals->frametime; + pev->velocity = ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1-fraction)); +} diff --git a/main/source/dlls/triggers.cpp~ b/main/source/dlls/triggers.cpp~ deleted file mode 100644 index 92550084..00000000 --- a/main/source/dlls/triggers.cpp~ +++ /dev/null @@ -1,2405 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== triggers.cpp ======================================================== - - spawn and use functions for editor-placed triggers - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "saverestore.h" -#include "trains.h" // trigger_camera has train functionality -#include "gamerules.h" -#include "dlls/triggers.h" -#include "../mod/AvHServerVariables.h" - -#define SF_TRIGGER_PUSH_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_TARGETONCE 1// Only fire hurt target once -#define SF_TRIGGER_HURT_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_NO_CLIENTS 8//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16// trigger hurt will only fire its target if it is hurting a client -#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32// only clients may touch this trigger. - -extern DLL_GLOBAL BOOL g_fGameOver; - -extern void SetMovedir(entvars_t* pev); -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -class CFrictionModifier : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT ChangeFriction( CBaseEntity *pOther ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - static TYPEDESCRIPTION m_SaveData[]; - - float m_frictionFraction; // Sorry, couldn't resist this name :) -}; - -LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ); - -// Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = -{ - DEFINE_FIELD( CFrictionModifier, m_frictionFraction, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE(CFrictionModifier,CBaseEntity); - - -// Modify an entity's friction -void CFrictionModifier :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_NONE; - SetTouch( &CFrictionModifier::ChangeFriction ); -} - - -// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) -void CFrictionModifier :: ChangeFriction( CBaseEntity *pOther ) -{ - if ( pOther->pev->movetype != MOVETYPE_BOUNCEMISSILE && pOther->pev->movetype != MOVETYPE_BOUNCE ) - pOther->pev->friction = m_frictionFraction; -} - - - -// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) -void CFrictionModifier :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "modifier")) - { - m_frictionFraction = atof(pkvd->szValue) / 100.0; - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// This trigger will fire when the level spawns (or respawns if not fire once) -// It will check a global state before firing. It supports delay and killtargets - -#define SF_AUTO_FIREONCE 0x0001 - -class CAutoTrigger : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Precache( void ); - void Think( void ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_globalstate; - USE_TYPE triggerType; -}; -LINK_ENTITY_TO_CLASS( trigger_auto, CAutoTrigger ); - -TYPEDESCRIPTION CAutoTrigger::m_SaveData[] = -{ - DEFINE_FIELD( CAutoTrigger, m_globalstate, FIELD_STRING ), - DEFINE_FIELD( CAutoTrigger, triggerType, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CAutoTrigger,CBaseDelay); - -void CAutoTrigger::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "globalstate")) - { - m_globalstate = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - -void CAutoTrigger::Spawn( void ) -{ - Precache(); -} - - -void CAutoTrigger::Precache( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CAutoTrigger::Think( void ) -{ - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) - { - SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_AUTO_FIREONCE ) - UTIL_Remove( this ); - } -} - - - -#define SF_RELAY_FIREONCE 0x0001 - -class CTriggerRelay : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - USE_TYPE triggerType; -}; -LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ); - -TYPEDESCRIPTION CTriggerRelay::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerRelay, triggerType, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerRelay,CBaseDelay); - -void CTriggerRelay::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - -void CTriggerRelay::Spawn( void ) -{ -} - - - - -void CTriggerRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_RELAY_FIREONCE ) - UTIL_Remove( this ); -} - - -//********************************************************** -// The Multimanager Entity - when fired, will fire up to 16 targets -// at specified times. -// FLAG: THREAD (create clones when triggered) -// FLAG: CLONE (this is a clone for a threaded execution) - -#define SF_MULTIMAN_CLONE 0x80000000 -#define SF_MULTIMAN_THREAD 0x00000001 - -class CMultiManager : public CBaseToggle -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn ( void ); - void EXPORT ManagerThink ( void ); - void EXPORT ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -#if _DEBUG - void EXPORT ManagerReport( void ); -#endif - - BOOL HasTarget( string_t targetname ); - - int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_cTargets; // the total number of targets in this manager's fire list. - int m_index; // Current target - float m_startTime;// Time we started firing - int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array - float m_flTargetDelay [ MAX_MULTI_TARGETS ];// delay (in seconds) from time of manager fire to target fire -private: - inline BOOL IsClone( void ) { return (pev->spawnflags & SF_MULTIMAN_CLONE) ? TRUE : FALSE; } - inline BOOL ShouldClone( void ) - { - if ( IsClone() ) - return FALSE; - - return (pev->spawnflags & SF_MULTIMAN_THREAD) ? TRUE : FALSE; - } - - CMultiManager *Clone( void ); -}; -LINK_ENTITY_TO_CLASS( multi_manager, CMultiManager ); - -// Global Savedata for multi_manager -TYPEDESCRIPTION CMultiManager::m_SaveData[] = -{ - DEFINE_FIELD( CMultiManager, m_cTargets, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_index, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_startTime, FIELD_TIME ), - DEFINE_ARRAY( CMultiManager, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), -}; - -IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle); - -void CMultiManager :: KeyValue( KeyValueData *pkvd ) -{ - // UNDONE: Maybe this should do something like this: - //CBaseToggle::KeyValue( pkvd ); - // if ( !pkvd->fHandled ) - // ... etc. - - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else // add this field to the target list - { - // this assumes that additional fields are targetnames and their values are delay values. - if ( m_cTargets < MAX_MULTI_TARGETS ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp ); - m_flTargetDelay [ m_cTargets ] = atof (pkvd->szValue); - m_cTargets++; - pkvd->fHandled = TRUE; - } - } -} - - -void CMultiManager :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - SetUse ( &CMultiManager::ManagerUse ); - SetThink (&CMultiManager::ManagerThink); - - // Sort targets - // Quick and dirty bubble sort - int swapped = 1; - - while ( swapped ) - { - swapped = 0; - for ( int i = 1; i < m_cTargets; i++ ) - { - if ( m_flTargetDelay[i] < m_flTargetDelay[i-1] ) - { - // Swap out of order elements - int name = m_iTargetName[i]; - float delay = m_flTargetDelay[i]; - m_iTargetName[i] = m_iTargetName[i-1]; - m_flTargetDelay[i] = m_flTargetDelay[i-1]; - m_iTargetName[i-1] = name; - m_flTargetDelay[i-1] = delay; - swapped = 1; - } - } - } -} - - -BOOL CMultiManager::HasTarget( string_t targetname ) -{ - for ( int i = 0; i < m_cTargets; i++ ) - if ( FStrEq(STRING(targetname), STRING(m_iTargetName[i])) ) - return TRUE; - - return FALSE; -} - - -// Designers were using this to fire targets that may or may not exist -- -// so I changed it to use the standard target fire code, made it a little simpler. -void CMultiManager :: ManagerThink ( void ) -{ - float time; - - time = gpGlobals->time - m_startTime; - while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time ) - { - FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 ); - m_index++; - } - - if ( m_index >= m_cTargets )// have we fired all targets? - { - SetThink( NULL ); - if ( IsClone() ) - { - UTIL_Remove( this ); - return; - } - SetUse ( &CMultiManager::ManagerUse );// allow manager re-use - } - else - pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; -} - -CMultiManager *CMultiManager::Clone( void ) -{ - CMultiManager *pMulti = GetClassPtr( (CMultiManager *)NULL ); - - edict_t *pEdict = pMulti->pev->pContainingEntity; - memcpy( pMulti->pev, pev, sizeof(*pev) ); - pMulti->pev->pContainingEntity = pEdict; - - pMulti->pev->spawnflags |= SF_MULTIMAN_CLONE; - pMulti->m_cTargets = m_cTargets; - memcpy( pMulti->m_iTargetName, m_iTargetName, sizeof( m_iTargetName ) ); - memcpy( pMulti->m_flTargetDelay, m_flTargetDelay, sizeof( m_flTargetDelay ) ); - - return pMulti; -} - - -// The USE function builds the time table and starts the entity thinking. -void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // In multiplayer games, clone the MM and execute in the clone (like a thread) - // to allow multiple players to trigger the same multimanager - if ( ShouldClone() ) - { - CMultiManager *pClone = Clone(); - pClone->ManagerUse( pActivator, pCaller, useType, value ); - return; - } - - m_hActivator = pActivator; - m_index = 0; - m_startTime = gpGlobals->time; - - SetUse( NULL );// disable use until all targets have fired - - SetThink ( &CMultiManager::ManagerThink ); - pev->nextthink = gpGlobals->time; -} - -#if _DEBUG -void CMultiManager :: ManagerReport ( void ) -{ - int cIndex; - - for ( cIndex = 0 ; cIndex < m_cTargets ; cIndex++ ) - { - ALERT ( at_console, "%s %f\n", STRING(m_iTargetName[cIndex]), m_flTargetDelay[cIndex] ); - } -} -#endif - -//*********************************************************** - - -// -// Render parameters trigger -// -// This entity will copy its render parameters (renderfx, rendermode, rendercolor, renderamt) -// to its targets when triggered. -// - - -// Flags to indicate masking off various render parameters that are normally copied to the targets -#define SF_RENDER_MASKFX (1<<0) -#define SF_RENDER_MASKAMT (1<<1) -#define SF_RENDER_MASKMODE (1<<2) -#define SF_RENDER_MASKCOLOR (1<<3) - -class CRenderFxManager : public CBaseEntity -{ -public: - void Spawn( void ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ); - - -void CRenderFxManager :: Spawn ( void ) -{ - pev->solid = SOLID_NOT; -} - -void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - while ( 1 ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - - entvars_t *pevTarget = VARS( pentTarget ); - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) ) - pevTarget->renderfx = pev->renderfx; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) - pevTarget->renderamt = pev->renderamt; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) - pevTarget->rendermode = pev->rendermode; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) - pevTarget->rendercolor = pev->rendercolor; - } - } -} - - - -LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ); - -/* -================ -InitTrigger -================ -*/ -void CBaseTrigger::InitTrigger( ) -{ - // trigger angles are used for one-way touches. An angle of 0 is assumed - // to mean no restrictions, so use a yaw of 360 instead. - if (pev->angles != g_vecZero) - SetMovedir(pev); - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - if ( ns_cvar_float(showtriggers) == 0 ) - SetBits( pev->effects, EF_NODRAW ); -} - - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseTrigger :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "count")) - { - m_cTriggersLeft = (int) atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damagetype")) - { - m_bitsDamageInflict = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -class CTriggerHurt : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT RadiationThink( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ); - -// -// trigger_monsterjump -// -class CTriggerMonsterJump : public CBaseTrigger -{ -public: - void Spawn( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ); - - -void CTriggerMonsterJump :: Spawn ( void ) -{ - SetMovedir ( pev ); - - InitTrigger (); - - pev->nextthink = 0; - pev->speed = 200; - m_flHeight = 150; - - if ( !FStringNull ( pev->targetname ) ) - {// if targetted, spawn turned off - pev->solid = SOLID_NOT; - UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetUse( &CTriggerMonsterJump::ToggleUse ); - } -} - - -void CTriggerMonsterJump :: Think( void ) -{ - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE - UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetThink( NULL ); -} - -void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-monster. - return; - } - - pevOther->origin.z += 1; - - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) - {// clear the onground so physics don't bitch - pevOther->flags &= ~FL_ONGROUND; - } - - // toss the monster! - pevOther->velocity = pev->movedir * pev->speed; - pevOther->velocity.z += m_flHeight; - pev->nextthink = gpGlobals->time; -} - - -//===================================== -// -// trigger_cdaudio - starts/stops cd audio tracks -// -class CTriggerCDAudio : public CBaseTrigger -{ -public: - void Spawn( void ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void PlayTrack( void ); - void Touch ( CBaseEntity *pOther ); -}; - -LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ); - -// -// Changes tracks or stops CD when player touches -// -// !!!HACK - overloaded HEALTH to avoid adding new field -void CTriggerCDAudio :: Touch ( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - {// only clients may trigger these events - return; - } - - PlayTrack(); -} - -void CTriggerCDAudio :: Spawn( void ) -{ - InitTrigger(); -} - -void CTriggerCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - PlayTrack(); -} - -void PlayCDTrack( int iTrack ) -{ - edict_t *pClient; - - // manually find the single player. - pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - // Can't play if the client is not connected! - if ( !pClient ) - return; - - if ( iTrack < -1 || iTrack > 30 ) - { - ALERT ( at_console, "TriggerCDAudio - Track %d out of range\n" ); - return; - } - - if ( iTrack == -1 ) - { - CLIENT_COMMAND ( pClient, "cd pause\n"); - } - else - { - char string [ 64 ]; - - sprintf( string, "cd play %3d\n", iTrack ); - CLIENT_COMMAND ( pClient, string); - } -} - - -// only plays for ONE client, so only use in single play! -void CTriggerCDAudio :: PlayTrack( void ) -{ - PlayCDTrack( (int)pev->health ); - - SetTouch( NULL ); - UTIL_Remove( this ); -} - - -// This plays a CD track when fired or when the player enters it's radius -class CTargetCDAudio : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void Play( void ); -}; - -LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudio ); - -void CTargetCDAudio :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->scale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CTargetCDAudio :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - if ( pev->scale > 0 ) - pev->nextthink = gpGlobals->time + 1.0; -} - -void CTargetCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - Play(); -} - -// only plays for ONE client, so only use in single play! -void CTargetCDAudio::Think( void ) -{ - edict_t *pClient; - - // manually find the single player. - pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - // Can't play if the client is not connected! - if ( !pClient ) - return; - - pev->nextthink = gpGlobals->time + 0.5; - - if ( (pClient->v.origin - pev->origin).Length() <= pev->scale ) - Play(); - -} - -void CTargetCDAudio::Play( void ) -{ - PlayCDTrack( (int)pev->health ); - UTIL_Remove(this); -} - -//===================================== - -// -// trigger_hurt - hurts anything that touches it. if the trigger has a targetname, firing it will toggle state -// -//int gfToggleState = 0; // used to determine when all radiation trigger hurts have called 'RadiationThink' - -void CTriggerHurt :: Spawn( void ) -{ - InitTrigger(); - SetTouch ( &CTriggerHurt::HurtTouch ); - - if ( !FStringNull ( pev->targetname ) ) - { - SetUse ( &CTriggerHurt::ToggleUse ); - } - else - { - SetUse ( NULL ); - } - - if (m_bitsDamageInflict & DMG_RADIATION) - { - SetThink ( &CTriggerHurt::RadiationThink ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); - } - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_HURT_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - UTIL_SetOrigin( pev, pev->origin ); // Link into the list -} - -// trigger hurt that causes radiation will do a radius -// check and set the player's geiger counter level -// according to distance from center of trigger - -void CTriggerHurt :: RadiationThink( void ) -{ - - edict_t *pentPlayer; - CBasePlayer *pPlayer = NULL; - float flRange; - entvars_t *pevTarget; - Vector vecSpot1; - Vector vecSpot2; - Vector vecRange; - Vector origin; - Vector view_ofs; - - // check to see if a player is in pvs - // if not, continue - - // set origin to center of trigger so that this check works - origin = pev->origin; - view_ofs = pev->view_ofs; - - pev->origin = (pev->absmin + pev->absmax) * 0.5; - pev->view_ofs = pev->view_ofs * 0.0; - - pentPlayer = FIND_CLIENT_IN_PVS(edict()); - - pev->origin = origin; - pev->view_ofs = view_ofs; - - // reset origin - - if (!FNullEnt(pentPlayer)) - { - - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - - pevTarget = VARS(pentPlayer); - - // get range to player; - - vecSpot1 = (pev->absmin + pev->absmax) * 0.5; - vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5; - - vecRange = vecSpot1 - vecSpot2; - flRange = vecRange.Length(); - - // if player's current geiger counter range is larger - // than range to this trigger hurt, reset player's - // geiger counter range - - if (pPlayer->m_flgeigerRange >= flRange) - pPlayer->m_flgeigerRange = flRange; - } - - pev->nextthink = gpGlobals->time + 0.25; -} - -// -// ToggleUse - If this is the USE function for a trigger, its state will toggle every time it's fired -// -void CBaseTrigger :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (pev->solid == SOLID_NOT) - {// if the trigger is off, turn it on - pev->solid = SOLID_TRIGGER; - - // Force retouch - gpGlobals->force_retouch++; - } - else - {// turn the trigger off - pev->solid = SOLID_NOT; - } - UTIL_SetOrigin( pev, pev->origin ); -} - -// When touched, a hurt trigger does DMG points of damage each half-second -void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) -{ - float fldmg; - - if ( !pOther->pev->takedamage ) - return; - - if ( (pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH) && !pOther->IsPlayer() ) - { - // this trigger is only allowed to touch clients, and this ain't a client. - return; - } - - if ( (pev->spawnflags & SF_TRIGGER_HURT_NO_CLIENTS) && pOther->IsPlayer() ) - return; - - // HACKHACK -- In multiplayer, players touch this based on packet receipt. - // So the players who send packets later aren't always hurt. Keep track of - // how much time has passed and whether or not you've touched that player - if ( g_pGameRules->IsMultiplayer() ) - { - if ( pev->dmgtime > gpGlobals->time ) - { - if ( gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - - // If I've already touched this player (this time), then bail out - if ( pev->impulse & playerMask ) - return; - - // Mark this player as touched - // BUGBUG - There can be only 32 players! - pev->impulse |= playerMask; - } - else - { - return; - } - } - } - else - { - // New clock, "un-touch" all players - pev->impulse = 0; - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - - // Mark this player as touched - // BUGBUG - There can be only 32 players! - pev->impulse |= playerMask; - } - } - } - else // Original code -- single player - { - if ( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity - return; - } - } - - - - // If this is time_based damage (poison, radiation), override the pev->dmg with a - // default for the given damage type. Monsters only take time-based damage - // while touching the trigger. Player continues taking damage for a while after - // leaving the trigger - - fldmg = pev->dmg * 0.5; // 0.5 seconds worth of damage, pev->dmg is damage/second - - - // JAY: Cut this because it wasn't fully realized. Damage is simpler now. -#if 0 - switch (m_bitsDamageInflict) - { - default: break; - case DMG_POISON: fldmg = POISON_DAMAGE/4; break; - case DMG_NERVEGAS: fldmg = NERVEGAS_DAMAGE/4; break; - case DMG_RADIATION: fldmg = RADIATION_DAMAGE/4; break; - case DMG_PARALYZE: fldmg = PARALYZE_DAMAGE/4; break; // UNDONE: cut this? should slow movement to 50% - case DMG_ACID: fldmg = ACID_DAMAGE/4; break; - case DMG_SLOWBURN: fldmg = SLOWBURN_DAMAGE/4; break; - case DMG_SLOWFREEZE: fldmg = SLOWFREEZE_DAMAGE/4; break; - } -#endif - - if ( fldmg < 0 ) - pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); - else - pOther->TakeDamage( pev, pev, fldmg, m_bitsDamageInflict ); - - // Store pain time so we can get all of the other entities on this frame - pev->pain_finished = gpGlobals->time; - - // Apply damage every half second - pev->dmgtime = gpGlobals->time + 0.5;// half second delay until this trigger can hurt toucher again - - - - if ( pev->target ) - { - // trigger has a target it wants to fire. - if ( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE ) - { - // if the toucher isn't a client, don't fire the target! - if ( !pOther->IsPlayer() ) - { - return; - } - } - - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - if ( pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE ) - pev->target = 0; - } -} - - -/*QUAKED trigger_multiple (.5 .5 .5) ? notouch -Variable sized repeatable trigger. Must be targeted at one or more entities. -If "health" is set, the trigger must be killed to activate each time. -If "delay" is set, the trigger waits some time after activating before firing. -"wait" : Seconds between triggerings. (.2 default) -If notouch is set, the trigger is only fired by other entities, not by touching. -NOTOUCH has been obsoleted by trigger_relay! -sounds -1) secret -2) beep beep -3) large switch -4) -NEW -if a trigger has a NETNAME, that NETNAME will become the TARGET of the triggered object. -*/ -class CTriggerMultiple : public CBaseTrigger -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ); - - -void CTriggerMultiple :: Spawn( void ) -{ - if (m_flWait == 0) - m_flWait = 0.2; - - InitTrigger(); - - ASSERTSZ(pev->health == 0, "trigger_multiple with health"); -// UTIL_SetOrigin(pev, pev->origin); -// SET_MODEL( ENT(pev), STRING(pev->model) ); -// if (pev->health > 0) -// { -// if (FBitSet(pev->spawnflags, SPAWNFLAG_NOTOUCH)) -// ALERT(at_error, "trigger_multiple spawn: health and notouch don't make sense"); -// pev->max_health = pev->health; -//UNDONE: where to get pfnDie from? -// pev->pfnDie = multi_killed; -// pev->takedamage = DAMAGE_YES; -// pev->solid = SOLID_BBOX; -// UTIL_SetOrigin(pev, pev->origin); // make sure it links into the world -// } -// else - { - SetTouch( &CTriggerMultiple::MultiTouch ); - } - } - - -/*QUAKED trigger_once (.5 .5 .5) ? notouch -Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching -"targetname". If "health" is set, the trigger must be killed to activate. -If notouch is set, the trigger is only fired by other entities, not by touching. -if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. -if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. -sounds -1) secret -2) beep beep -3) large switch -4) -*/ -class CTriggerOnce : public CTriggerMultiple -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ); -void CTriggerOnce::Spawn( void ) -{ - m_flWait = -1; - - CTriggerMultiple :: Spawn(); -} - - - -void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) -{ - entvars_t *pevToucher; - - pevToucher = pOther->pev; - - // Only touch clients, monsters, or pushables (depending on flags) - if ( ((pevToucher->flags & FL_CLIENT) && !(pev->spawnflags & SF_TRIGGER_NOCLIENTS)) || - ((pevToucher->flags & FL_MONSTER) && (pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS)) || - (pev->spawnflags & SF_TRIGGER_PUSHABLES) && FClassnameIs(pevToucher,"func_pushable") ) - { - -#if 0 - // if the trigger has an angles field, check player's facing direction - if (pev->movedir != g_vecZero) - { - UTIL_MakeVectors( pevToucher->angles ); - if ( DotProduct( gpGlobals->v_forward, pev->movedir ) < 0 ) - return; // not facing the right way - } -#endif - - ActivateMultiTrigger( pOther ); - } -} - - -// -// the trigger was just touched/killed/used -// self.enemy should be set to the activator so it can be held through a delay -// so wait for the delay time before firing -// -void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) -{ - if (pev->nextthink > gpGlobals->time) - return; // still waiting for reset time - - if (!UTIL_IsMasterTriggered(m_sMaster,pActivator)) - return; - - if (FClassnameIs(pev, "trigger_secret")) - { - if ( pev->enemy == NULL || !FClassnameIs(pev->enemy, "player")) - return; - gpGlobals->found_secrets++; - } - - if (!FStringNull(pev->noise)) - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - -// don't trigger again until reset -// pev->takedamage = DAMAGE_NO; - - m_hActivator = pActivator; - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - - if ( pev->message && pActivator->IsPlayer() ) - { - UTIL_ShowMessage( STRING(pev->message), pActivator ); -// CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); - } - - if (m_flWait > 0) - { - SetThink( &CBaseTrigger::MultiWaitOver ); - pev->nextthink = gpGlobals->time + m_flWait; - } - else - { - // we can't just remove (self) here, because this is a touch function - // called while C code is looping through area links... - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CBaseTrigger::SUB_Remove ); - } -} - - -// the wait time has passed, so set back up for another activation -void CBaseTrigger :: MultiWaitOver( void ) -{ -// if (pev->max_health) -// { -// pev->health = pev->max_health; -// pev->takedamage = DAMAGE_YES; -// pev->solid = SOLID_BBOX; -// } - SetThink( NULL ); -} - - -// ========================= COUNTING TRIGGER ===================================== - -// -// GLOBALS ASSUMED SET: g_eoActivator -// -void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_cTriggersLeft--; - m_hActivator = pActivator; - - if (m_cTriggersLeft < 0) - return; - - BOOL fTellActivator = - (m_hActivator != 0) && - (FClassnameIs(m_hActivator->pev, "player") && - !FBitSet(pev->spawnflags, SPAWNFLAG_NOMESSAGE)); - if (m_cTriggersLeft != 0) - { - if (fTellActivator) - { - // UNDONE: I don't think we want these Quakesque messages - switch (m_cTriggersLeft) - { - case 1: ALERT(at_console, "Only 1 more to go..."); break; - case 2: ALERT(at_console, "Only 2 more to go..."); break; - case 3: ALERT(at_console, "Only 3 more to go..."); break; - default: ALERT(at_console, "There are more to go..."); break; - } - } - return; - } - - // !!!UNDONE: I don't think we want these Quakesque messages - if (fTellActivator) - ALERT(at_console, "Sequence completed!"); - - ActivateMultiTrigger( m_hActivator ); -} - - -/*QUAKED trigger_counter (.5 .5 .5) ? nomessage -Acts as an intermediary for an action that takes multiple inputs. -If nomessage is not set, it will print "1 more.. " etc when triggered and -"sequence complete" when finished. After the counter has been triggered "cTriggersLeft" -times (default 2), it will fire all of it's targets and remove itself. -*/ -class CTriggerCounter : public CBaseTrigger -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ); - -void CTriggerCounter :: Spawn( void ) -{ - // By making the flWait be -1, this counter-trigger will disappear after it's activated - // (but of course it needs cTriggersLeft "uses" before that happens). - m_flWait = -1; - - if (m_cTriggersLeft == 0) - m_cTriggersLeft = 2; - SetUse( &CTriggerCounter::CounterUse ); -} - -// ====================== TRIGGER_CHANGELEVEL ================================ - -class CTriggerVolume : public CPointEntity // Derive from point entity so this doesn't move across levels -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ); - -// Define space that travels across a level transition -void CTriggerVolume :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->model = NULL; - pev->modelindex = 0; -} - - -// Fires a target after level transition and then dies -class CFireAndDie : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Think( void ); - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() | FCAP_FORCE_TRANSITION; } // Always go across transitions -}; -LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ); - -void CFireAndDie::Spawn( void ) -{ - pev->classname = MAKE_STRING("fireanddie"); - // Don't call Precache() - it should be called on restore -} - - -void CFireAndDie::Precache( void ) -{ - // This gets called on restore - pev->nextthink = gpGlobals->time + m_flDelay; -} - - -void CFireAndDie::Think( void ) -{ - SUB_UseTargets( this, USE_TOGGLE, 0 ); - UTIL_Remove( this ); -} - - -#define SF_CHANGELEVEL_USEONLY 0x0002 -class CChangeLevel : public CBaseTrigger -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TriggerChangeLevel( void ); - void EXPORT ExecuteChangeLevel( void ); - void EXPORT TouchChangeLevel( CBaseEntity *pOther ); - void ChangeLevelNow( CBaseEntity *pActivator ); - - static edict_t *FindLandmark( const char *pLandmarkName ); - static int ChangeList( LEVELLIST *pLevelList, int maxList ); - static int AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ); - static int InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - char m_szMapName[cchMapNameMost]; // trigger_changelevel only: next map - char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map - int m_changeTarget; - float m_changeTargetDelay; -}; -LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ); - -// Global Savedata for changelevel trigger -TYPEDESCRIPTION CChangeLevel::m_SaveData[] = -{ - DEFINE_ARRAY( CChangeLevel, m_szMapName, FIELD_CHARACTER, cchMapNameMost ), - DEFINE_ARRAY( CChangeLevel, m_szLandmarkName, FIELD_CHARACTER, cchMapNameMost ), - DEFINE_FIELD( CChangeLevel, m_changeTarget, FIELD_STRING ), - DEFINE_FIELD( CChangeLevel, m_changeTargetDelay, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger); - -// -// Cache user-entity-field values until spawn is called. -// - -void CChangeLevel :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "map")) - { - if (strlen(pkvd->szValue) >= cchMapNameMost) - ALERT( at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szMapName, pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "landmark")) - { - if (strlen(pkvd->szValue) >= cchMapNameMost) - ALERT( at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szLandmarkName, pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changetarget")) - { - m_changeTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changedelay")) - { - m_changeTargetDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseTrigger::KeyValue( pkvd ); -} - - -/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION -When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. -*/ - -void CChangeLevel :: Spawn( void ) -{ - if ( FStrEq( m_szMapName, "" ) ) - ALERT( at_console, "a trigger_changelevel doesn't have a map" ); - - if ( FStrEq( m_szLandmarkName, "" ) ) - ALERT( at_console, "trigger_changelevel to %s doesn't have a landmark", m_szMapName ); - - if (!FStringNull ( pev->targetname ) ) - { - SetUse ( &CChangeLevel::UseChangeLevel ); - } - InitTrigger(); - if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) - SetTouch( &CChangeLevel::TouchChangeLevel ); -// ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); -} - - -void CChangeLevel :: ExecuteChangeLevel( void ) -{ - MESSAGE_BEGIN( MSG_ALL, SVC_CDTRACK ); - WRITE_BYTE( 3 ); - WRITE_BYTE( 3 ); - MESSAGE_END(); - - MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); - MESSAGE_END(); -} - - -FILE_GLOBAL char st_szNextMap[cchMapNameMost]; -FILE_GLOBAL char st_szNextSpot[cchMapNameMost]; - -edict_t *CChangeLevel :: FindLandmark( const char *pLandmarkName ) -{ - edict_t *pentLandmark; - - pentLandmark = FIND_ENTITY_BY_STRING( NULL, "targetname", pLandmarkName ); - while ( !FNullEnt( pentLandmark ) ) - { - // Found the landmark - if ( FClassnameIs( pentLandmark, "info_landmark" ) ) - return pentLandmark; - else - pentLandmark = FIND_ENTITY_BY_STRING( pentLandmark, "targetname", pLandmarkName ); - } - ALERT( at_error, "Can't find landmark %s\n", pLandmarkName ); - return NULL; -} - - -//========================================================= -// CChangeLevel :: Use - allows level transitions to be -// triggered by buttons, etc. -// -//========================================================= -void CChangeLevel :: UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - ChangeLevelNow( pActivator ); -} - -void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) -{ - edict_t *pentLandmark; - LEVELLIST levels[16]; - - ASSERT(!FStrEq(m_szMapName, "")); - - // Don't work in deathmatch - if ( g_pGameRules->IsDeathmatch() ) - return; - - // Some people are firing these multiple times in a frame, disable - if ( gpGlobals->time == pev->dmgtime ) - return; - - pev->dmgtime = gpGlobals->time; - - - CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) ) - { - ALERT( at_aiconsole, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName ); - return; - } - - // Create an entity to fire the changetarget - if ( m_changeTarget ) - { - CFireAndDie *pFireAndDie = GetClassPtr( (CFireAndDie *)NULL ); - if ( pFireAndDie ) - { - // Set target and delay - pFireAndDie->pev->target = m_changeTarget; - pFireAndDie->m_flDelay = m_changeTargetDelay; - pFireAndDie->pev->origin = pPlayer->pev->origin; - // Call spawn - DispatchSpawn( pFireAndDie->edict() ); - } - } - // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - strcpy(st_szNextMap, m_szMapName); - - m_hActivator = pActivator; - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - st_szNextSpot[0] = 0; // Init landmark to NULL - - // look for a landmark entity - pentLandmark = FindLandmark( m_szLandmarkName ); - if ( !FNullEnt( pentLandmark ) ) - { - strcpy(st_szNextSpot, m_szLandmarkName); - gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; - } -// ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); - ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); - CHANGE_LEVEL( st_szNextMap, st_szNextSpot ); -} - -// -// GLOBALS ASSUMED SET: st_szNextMap -// -void CChangeLevel :: TouchChangeLevel( CBaseEntity *pOther ) -{ - if (!FClassnameIs(pOther->pev, "player")) - return; - - ChangeLevelNow( pOther ); -} - - -// Add a transition to the list, but ignore duplicates -// (a designer may have placed multiple trigger_changelevels with the same landmark) -int CChangeLevel::AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ) -{ - int i; - - if ( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) - return 0; - - for ( i = 0; i < listCount; i++ ) - { - if ( pLevelList[i].pentLandmark == pentLandmark && strcmp( pLevelList[i].mapName, pMapName ) == 0 ) - return 0; - } - strcpy( pLevelList[listCount].mapName, pMapName ); - strcpy( pLevelList[listCount].landmarkName, pLandmarkName ); - pLevelList[listCount].pentLandmark = pentLandmark; - pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin; - - return 1; -} - -int BuildChangeList( LEVELLIST *pLevelList, int maxList ) -{ - return CChangeLevel::ChangeList( pLevelList, maxList ); -} - - -int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) -{ - edict_t *pentVolume; - - - if ( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) - return 1; - - // If you're following another entity, follow it through the transition (weapons follow the player) - if ( pEntity->pev->movetype == MOVETYPE_FOLLOW ) - { - if ( pEntity->pev->aiment != NULL ) - pEntity = CBaseEntity::Instance( pEntity->pev->aiment ); - } - - int inVolume = 1; // Unless we find a trigger_transition, everything is in the volume - - pentVolume = FIND_ENTITY_BY_TARGETNAME( NULL, pVolumeName ); - while ( !FNullEnt( pentVolume ) ) - { - CBaseEntity *pVolume = CBaseEntity::Instance( pentVolume ); - - if ( pVolume && FClassnameIs( pVolume->pev, "trigger_transition" ) ) - { - if ( pVolume->Intersects( pEntity ) ) // It touches one, it's in the volume - return 1; - else - inVolume = 0; // Found a trigger_transition, but I don't intersect it -- if I don't find another, don't go! - } - pentVolume = FIND_ENTITY_BY_TARGETNAME( pentVolume, pVolumeName ); - } - - return inVolume; -} - - -// We can only ever move 512 entities across a transition -#define MAX_ENTITY 512 - -// This has grown into a complicated beast -// Can we make this more elegant? -// This builds the list of all transitions on this level and which entities are in their PVS's and can / should -// be moved across. -int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) -{ - edict_t *pentChangelevel, *pentLandmark; - int i, count; - - count = 0; - - // Find all of the possible level changes on this BSP - pentChangelevel = FIND_ENTITY_BY_STRING( NULL, "classname", "trigger_changelevel" ); - if ( FNullEnt( pentChangelevel ) ) - return 0; - while ( !FNullEnt( pentChangelevel ) ) - { - CChangeLevel *pTrigger; - - pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel)); - if ( pTrigger ) - { - // Find the corresponding landmark - pentLandmark = FindLandmark( pTrigger->m_szLandmarkName ); - if ( pentLandmark ) - { - // Build a list of unique transitions - if ( AddTransitionToList( pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark ) ) - { - count++; - if ( count >= maxList ) // FULL!! - break; - } - } - } - pentChangelevel = FIND_ENTITY_BY_STRING( pentChangelevel, "classname", "trigger_changelevel" ); - } - - if ( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) - { - CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); - - for ( i = 0; i < count; i++ ) - { - int j, entityCount = 0; - CBaseEntity *pEntList[ MAX_ENTITY ]; - int entityFlags[ MAX_ENTITY ]; - - // Follow the linked list of entities in the PVS of the transition landmark - edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); - - // Build a list of valid entities in this linked list (we're going to use pent->v.chain again) - while ( !FNullEnt( pent ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(pent); - if ( pEntity ) - { -// ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); - int caps = pEntity->ObjectCaps(); - if ( !(caps & FCAP_DONT_SAVE) ) - { - int flags = 0; - - // If this entity can be moved or is global, mark it - if ( caps & FCAP_ACROSS_TRANSITION ) - flags |= FENTTABLE_MOVEABLE; - if ( pEntity->pev->globalname && !pEntity->IsDormant() ) - flags |= FENTTABLE_GLOBAL; - if ( flags ) - { - pEntList[ entityCount ] = pEntity; - entityFlags[ entityCount ] = flags; - entityCount++; - if ( entityCount > MAX_ENTITY ) - ALERT( at_error, "Too many entities across a transition!" ); - } -// else -// ALERT( at_console, "Failed %s\n", STRING(pEntity->pev->classname) ); - } -// else -// ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); - } - pent = pent->v.chain; - } - - for ( j = 0; j < entityCount; j++ ) - { - // Check to make sure the entity isn't screened out by a trigger_transition - if ( entityFlags[j] && InTransitionVolume( pEntList[j], pLevelList[i].landmarkName ) ) - { - // Mark entity table with 1<pev->classname) ); - - } - } - } - - return count; -} - -/* -go to the next level for deathmatch -only called if a time or frag limit has expired -*/ -void NextLevel( void ) -{ - edict_t* pent; - CChangeLevel *pChange; - - // find a trigger_changelevel - pent = FIND_ENTITY_BY_CLASSNAME(NULL, "trigger_changelevel"); - - // go back to start if no trigger_changelevel - if (FNullEnt(pent)) - { - gpGlobals->mapname = ALLOC_STRING("start"); - pChange = GetClassPtr( (CChangeLevel *)NULL ); - strcpy(pChange->m_szMapName, "start"); - } - else - pChange = GetClassPtr( (CChangeLevel *)VARS(pent)); - - strcpy(st_szNextMap, pChange->m_szMapName); - g_fGameOver = TRUE; - - if (pChange->pev->nextthink < gpGlobals->time) - { - pChange->SetThink( &CChangeLevel::ExecuteChangeLevel ); - pChange->pev->nextthink = gpGlobals->time + 0.1; - } -} - -LINK_ENTITY_TO_CLASS( func_ladder, CLadder ); - - -void CLadder :: KeyValue( KeyValueData *pkvd ) -{ - CBaseTrigger::KeyValue( pkvd ); -} - - -//========================================================= -// func_ladder - makes an area vertically negotiable -//========================================================= -void CLadder :: Precache( void ) -{ - // Do all of this in here because we need to 'convert' old saved games - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_LADDER; - if ( ns_cvar_float(showtriggers) == 0 ) - { - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; - } - pev->effects &= ~EF_NODRAW; -} - - -void CLadder :: Spawn( void ) -{ - Precache(); - - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_PUSH; -} - - -// ========================== A TRIGGER THAT PUSHES YOU =============================== - -class CTriggerPush : public CBaseTrigger -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ); - - -void CTriggerPush :: KeyValue( KeyValueData *pkvd ) -{ - CBaseTrigger::KeyValue( pkvd ); -} - - -/*QUAKED trigger_push (.5 .5 .5) ? TRIG_PUSH_ONCE -Pushes the player -*/ - -void CTriggerPush :: Spawn( ) -{ - if ( pev->angles == g_vecZero ) - pev->angles.y = 360; - InitTrigger(); - - if (pev->speed == 0) - pev->speed = 100; - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - SetUse(&CTriggerPush::ToggleUse ); - - UTIL_SetOrigin( pev, pev->origin ); // Link into the list -} - - -void CTriggerPush :: Touch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - // UNDONE: Is there a better way than health to detect things that have physics? (clients/monsters) - switch( pevToucher->movetype ) - { - case MOVETYPE_NONE: - case MOVETYPE_PUSH: - case MOVETYPE_NOCLIP: - case MOVETYPE_FOLLOW: - return; - } - - if ( pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP ) - { - // Instant trigger, just transfer velocity and remove - if (FBitSet(pev->spawnflags, SF_TRIG_PUSH_ONCE)) - { - pevToucher->velocity = pevToucher->velocity + (pev->speed * pev->movedir); - if ( pevToucher->velocity.z > 0 ) - pevToucher->flags &= ~FL_ONGROUND; - UTIL_Remove( this ); - } - else - { // Push field, transfer to base velocity - Vector vecPush = (pev->speed * pev->movedir); - if ( pevToucher->flags & FL_BASEVELOCITY ) - vecPush = vecPush + pevToucher->basevelocity; - - pevToucher->basevelocity = vecPush; - - pevToucher->flags |= FL_BASEVELOCITY; -// ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); - } - } -} - - -//====================================== -// teleport trigger -// -// - -void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - edict_t *pentTarget = NULL; - - // Only teleport monsters or clients - if ( !FBitSet( pevToucher->flags, FL_CLIENT|FL_MONSTER ) ) - return; - - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) - return; - - if ( !( pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) - {// no monsters allowed! - if ( FBitSet( pevToucher->flags, FL_MONSTER ) ) - { - return; - } - } - - if ( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) - {// no clients allowed - if ( pOther->IsPlayer() ) - { - return; - } - } - - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pev->target) ); - if (FNullEnt(pentTarget)) - return; - - Vector tmp = VARS( pentTarget )->origin; - - if ( pOther->IsPlayer() ) - { - tmp.z -= pOther->pev->mins.z;// make origin adjustments in case the teleportee is a player. (origin in center, not at feet) - } - - tmp.z++; - - pevToucher->flags &= ~FL_ONGROUND; - - UTIL_SetOrigin( pevToucher, tmp ); - - pevToucher->angles = pentTarget->v.angles; - - if ( pOther->IsPlayer() ) - { - pevToucher->v_angle = pentTarget->v.angles; - } - - pevToucher->fixangle = TRUE; - pevToucher->velocity = pevToucher->basevelocity = g_vecZero; -} - - -class CTriggerTeleport : public CBaseTrigger -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ); - -void CTriggerTeleport :: Spawn( void ) -{ - InitTrigger(); - - SetTouch( &CTriggerTeleport::TeleportTouch ); -} - - -LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ); - - - -class CTriggerSave : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT SaveTouch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); - -void CTriggerSave::Spawn( void ) -{ - if ( g_pGameRules->IsDeathmatch() ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - - InitTrigger(); - SetTouch( &CTriggerSave::SaveTouch ); -} - -void CTriggerSave::SaveTouch( CBaseEntity *pOther ) -{ - if ( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) - return; - - // Only save on clients - if ( !pOther->IsPlayer() ) - return; - - SetTouch( NULL ); - UTIL_Remove( this ); - SERVER_COMMAND( "autosave\n" ); -} - -#define SF_ENDSECTION_USEONLY 0x0001 - -class CTriggerEndSection : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT EndSectionTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection ); - - -void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Only save on clients - if ( pActivator && !pActivator->IsNetClient() ) - return; - - SetUse( NULL ); - - if ( pev->message ) - { - g_engfuncs.pfnEndSection(STRING(pev->message)); - } - UTIL_Remove( this ); -} - -void CTriggerEndSection::Spawn( void ) -{ - if ( g_pGameRules->IsDeathmatch() ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - - InitTrigger(); - - SetUse ( &CTriggerEndSection::EndSectionUse ); - // If it is a "use only" trigger, then don't set the touch function. - if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) - SetTouch( &CTriggerEndSection::EndSectionTouch ); -} - -void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) -{ - // Only save on clients - if ( !pOther->IsNetClient() ) - return; - - SetTouch( NULL ); - - if (pev->message) - { - g_engfuncs.pfnEndSection(STRING(pev->message)); - } - UTIL_Remove( this ); -} - -void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "section")) - { -// m_iszSectionName = ALLOC_STRING( pkvd->szValue ); - // Store this in message so we don't have to write save/restore for this ent - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseTrigger::KeyValue( pkvd ); -} - - -class CTriggerGravity : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT GravityTouch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); - -void CTriggerGravity::Spawn( void ) -{ - InitTrigger(); - SetTouch( &CTriggerGravity::GravityTouch ); -} - -void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) -{ - // Only save on clients - if ( !pOther->IsPlayer() ) - return; - - pOther->pev->gravity = pev->gravity; -} - - - - - - - -// this is a really bad idea. -class CTriggerChangeTarget : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_iszNewTarget; -}; -LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ); - -TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay); - -void CTriggerChangeTarget::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszNewTarget")) - { - m_iszNewTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - -void CTriggerChangeTarget::Spawn( void ) -{ -} - - -void CTriggerChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pTarget = UTIL_FindEntityByString( NULL, "targetname", STRING( pev->target ) ); - - if (pTarget) - { - pTarget->pev->target = m_iszNewTarget; - CBaseMonster *pMonster = pTarget->MyMonsterPointer( ); - if (pMonster) - { - pMonster->m_pGoalEnt = NULL; - } - } -} - - - - -#define SF_CAMERA_PLAYER_POSITION 1 -#define SF_CAMERA_PLAYER_TARGET 2 -#define SF_CAMERA_PLAYER_TAKECONTROL 4 - -class CTriggerCamera : public CBaseDelay -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT FollowTarget( void ); - void Move(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; - - EHANDLE m_hPlayer; - EHANDLE m_hTarget; - CBaseEntity *m_pentPath; - int m_sPath; - float m_flWait; - float m_flReturnTime; - float m_flStopTime; - float m_moveDistance; - float m_targetSpeed; - float m_initialSpeed; - float m_acceleration; - float m_deceleration; - int m_state; - -}; -LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ); - -// Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerCamera, m_hPlayer, FIELD_EHANDLE ), - DEFINE_FIELD( CTriggerCamera, m_hTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CTriggerCamera, m_pentPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CTriggerCamera, m_sPath, FIELD_STRING ), - DEFINE_FIELD( CTriggerCamera, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_flReturnTime, FIELD_TIME ), - DEFINE_FIELD( CTriggerCamera, m_flStopTime, FIELD_TIME ), - DEFINE_FIELD( CTriggerCamera, m_moveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_targetSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_initialSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_acceleration, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_deceleration, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay); - -void CTriggerCamera::Spawn( void ) -{ - pev->movetype = MOVETYPE_NOCLIP; - pev->solid = SOLID_NOT; // Remove model & collisions - pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on - pev->rendermode = kRenderTransTexture; - - m_initialSpeed = pev->speed; - if ( m_acceleration == 0 ) - m_acceleration = 500; - if ( m_deceleration == 0 ) - m_deceleration = 500; -} - - -void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "moveto")) - { - m_sPath = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "acceleration")) - { - m_acceleration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "deceleration")) - { - m_deceleration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - - -void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_state ) ) - return; - - // Toggle state - m_state = !m_state; - if (m_state == 0) - { - m_flReturnTime = gpGlobals->time; - return; - } - if ( !pActivator || !pActivator->IsPlayer() ) - { - pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex( 1 )); - } - - m_hPlayer = pActivator; - - m_flReturnTime = gpGlobals->time + m_flWait; - pev->speed = m_initialSpeed; - m_targetSpeed = m_initialSpeed; - - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TARGET ) ) - { - m_hTarget = m_hPlayer; - } - else - { - m_hTarget = GetNextTarget(); - } - - // Nothing to look at! - if ( m_hTarget == NULL ) - { - return; - } - - - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) - { - ((CBasePlayer *)pActivator)->EnableControl(FALSE); - } - - if ( m_sPath ) - { - m_pentPath = Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_sPath)) ); - } - else - { - m_pentPath = NULL; - } - - m_flStopTime = gpGlobals->time; - if ( m_pentPath ) - { - if ( m_pentPath->pev->speed != 0 ) - m_targetSpeed = m_pentPath->pev->speed; - - m_flStopTime += m_pentPath->GetDelay(); - } - - // copy over player information - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_POSITION ) ) - { - UTIL_SetOrigin( pev, pActivator->pev->origin + pActivator->pev->view_ofs ); - pev->angles.x = -pActivator->pev->angles.x; - pev->angles.y = pActivator->pev->angles.y; - pev->angles.z = 0; - pev->velocity = pActivator->pev->velocity; - } - else - { - pev->velocity = Vector( 0, 0, 0 ); - } - - SET_VIEW( pActivator->edict(), edict() ); - - SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); - - // follow the player down - SetThink( &CTriggerCamera::FollowTarget ); - pev->nextthink = gpGlobals->time; - - m_moveDistance = 0; - Move(); -} - - -void CTriggerCamera::FollowTarget( ) -{ - if (m_hPlayer == NULL) - return; - - if (m_hTarget == NULL || m_flReturnTime < gpGlobals->time) - { - if (m_hPlayer->IsAlive( )) - { - SET_VIEW( m_hPlayer->edict(), m_hPlayer->edict() ); - ((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE); - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); - pev->avelocity = Vector( 0, 0, 0 ); - m_state = 0; - return; - } - - Vector vecGoal = UTIL_VecToAngles( m_hTarget->pev->origin - pev->origin ); - vecGoal.x = -vecGoal.x; - - if (pev->angles.y > 360) - pev->angles.y -= 360; - - if (pev->angles.y < 0) - pev->angles.y += 360; - - float dx = vecGoal.x - pev->angles.x; - float dy = vecGoal.y - pev->angles.y; - - if (dx < -180) - dx += 360; - if (dx > 180) - dx = dx - 360; - - if (dy < -180) - dy += 360; - if (dy > 180) - dy = dy - 360; - - pev->avelocity.x = dx * 40 * gpGlobals->frametime; - pev->avelocity.y = dy * 40 * gpGlobals->frametime; - - - if (!(FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL))) - { - pev->velocity = pev->velocity * 0.8; - if (pev->velocity.Length( ) < 10.0) - pev->velocity = g_vecZero; - } - - pev->nextthink = gpGlobals->time; - - Move(); -} - -void CTriggerCamera::Move() -{ - // Not moving on a path, return - if (!m_pentPath) - return; - - // Subtract movement from the previous frame - m_moveDistance -= pev->speed * gpGlobals->frametime; - - // Have we moved enough to reach the target? - if ( m_moveDistance <= 0 ) - { - // Fire the passtarget if there is one - if ( m_pentPath->pev->message ) - { - FireTargets( STRING(m_pentPath->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pentPath->pev->spawnflags, SF_CORNER_FIREONCE ) ) - m_pentPath->pev->message = 0; - } - // Time to go to the next target - m_pentPath = m_pentPath->GetNextTarget(); - - // Set up next corner - if ( !m_pentPath ) - { - pev->velocity = g_vecZero; - } - else - { - if ( m_pentPath->pev->speed != 0 ) - m_targetSpeed = m_pentPath->pev->speed; - - Vector delta = m_pentPath->pev->origin - pev->origin; - m_moveDistance = delta.Length(); - pev->movedir = delta.Normalize(); - m_flStopTime = gpGlobals->time + m_pentPath->GetDelay(); - } - } - - if ( m_flStopTime > gpGlobals->time ) - pev->speed = UTIL_Approach( 0, pev->speed, m_deceleration * gpGlobals->frametime ); - else - pev->speed = UTIL_Approach( m_targetSpeed, pev->speed, m_acceleration * gpGlobals->frametime ); - - float fraction = 2 * gpGlobals->frametime; - pev->velocity = ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1-fraction)); -} diff --git a/main/source/dlls/triggers.h b/main/source/dlls/triggers.h index 4eabd7fe..0ab4a417 100644 --- a/main/source/dlls/triggers.h +++ b/main/source/dlls/triggers.h @@ -1,27 +1,27 @@ -// ============================== LADDER ======================================= - -class CBaseTrigger : public CBaseToggle -{ -public: - void EXPORT TeleportTouch ( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT MultiTouch( CBaseEntity *pOther ); - void EXPORT HurtTouch ( CBaseEntity *pOther ); - void EXPORT CDAudioTouch ( CBaseEntity *pOther ); - void ActivateMultiTrigger( CBaseEntity *pActivator ); - void EXPORT MultiWaitOver( void ); - void EXPORT CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void InitTrigger( void ); - - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - - -class CLadder : public CBaseTrigger -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Precache( void ); -}; +// ============================== LADDER ======================================= + +class CBaseTrigger : public CBaseToggle +{ +public: + void EXPORT TeleportTouch ( CBaseEntity *pOther ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT MultiTouch( CBaseEntity *pOther ); + void EXPORT HurtTouch ( CBaseEntity *pOther ); + void EXPORT CDAudioTouch ( CBaseEntity *pOther ); + void ActivateMultiTrigger( CBaseEntity *pActivator ); + void EXPORT MultiWaitOver( void ); + void EXPORT CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void InitTrigger( void ); + + virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +}; + + +class CLadder : public CBaseTrigger +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Spawn( void ); + void Precache( void ); +}; diff --git a/main/source/dlls/turret.cpp b/main/source/dlls/turret.cpp index 3c05f12a..b8aa2fa5 100644 --- a/main/source/dlls/turret.cpp +++ b/main/source/dlls/turret.cpp @@ -1,1210 +1,1210 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== turret.cpp ======================================================== - -*/ - -// -// TODO: -// Take advantage of new monster fields like m_hEnemy and get rid of that OFFSET() stuff -// Revisit enemy validation stuff, maybe it's not necessary with the newest monster code -// - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "effects.h" -#include "turret.h" -#include "../mod/AvHMarineEquipmentConstants.h" -#include "../mod/AvHSpecials.h" - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - - -TYPEDESCRIPTION CBaseTurret::m_SaveData[] = -{ - DEFINE_FIELD( CBaseTurret, m_flMaxSpin, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iSpin, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_pEyeGlow, FIELD_CLASSPTR ), - DEFINE_FIELD( CBaseTurret, m_eyeBrightness, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iDeployHeight, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iRetractHeight, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iMinPitch, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_iBaseTurnRate, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_fTurnRate, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iOrientation, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iOn, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_fBeserk, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iAutoStart, FIELD_INTEGER ), - - - DEFINE_FIELD( CBaseTurret, m_vecLastSight, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseTurret, m_flLastSight, FIELD_TIME ), - DEFINE_FIELD( CBaseTurret, m_flMaxWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iSearchSpeed, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_flStartYaw, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_vecCurAngles, FIELD_VECTOR ), - DEFINE_FIELD( CBaseTurret, m_vecGoalAngles, FIELD_VECTOR ), - - DEFINE_FIELD( CBaseTurret, m_flPingTime, FIELD_TIME ), - DEFINE_FIELD( CBaseTurret, m_flSpinUpTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ); - -TYPEDESCRIPTION CTurret::m_SaveData[] = -{ - DEFINE_FIELD( CTurret, m_iStartSpin, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ); - - - -LINK_ENTITY_TO_CLASS( monster_turret, CTurret ); -LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ); - -const float kPingInterval = 3.0f; -const float kPingVolume = .7f; - -void CBaseTurret::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "maxsleep")) - { - m_flMaxWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "orientation")) - { - m_iOrientation = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else if (FStrEq(pkvd->szKeyName, "searchspeed")) - { - m_iSearchSpeed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else if (FStrEq(pkvd->szKeyName, "turnrate")) - { - m_iBaseTurnRate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CBaseTurret::Spawn() -{ - Precache( ); - pev->nextthink = gpGlobals->time + 1; - pev->movetype = MOVETYPE_FLY; - pev->sequence = 0; - pev->frame = 0; - pev->solid = SOLID_SLIDEBOX; - pev->takedamage = DAMAGE_AIM; - - SetBits (pev->flags, FL_MONSTER); - SetUse(&CBaseTurret::TurretUse ); - - if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) - { - m_iAutoStart = TRUE; - } - - ResetSequenceInfo( ); - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - m_flFieldOfView = VIEW_FIELD_FULL; - // m_flSightRange = this->GetRange(); -} - -char* CBaseTurret::GetPingSound() const -{ - return "turret/tu_ping.wav"; -} - -char* CBaseTurret::GetActiveSound() const -{ - return "turret/tu_active2.wav"; -} - -char* CBaseTurret::GetAlertSound() const -{ - return "turret/tu_alert.wav"; -} - -char* CBaseTurret::GetDeploySound() const -{ - return "turret/tu_deploy.wav"; -} - -void CBaseTurret::Precache( ) -{ - PRECACHE_SOUND ("turret/tu_fire1.wav"); - PRECACHE_SOUND (this->GetPingSound()); - PRECACHE_SOUND (this->GetActiveSound()); - PRECACHE_SOUND ("turret/tu_die.wav"); - PRECACHE_SOUND ("turret/tu_die2.wav"); - PRECACHE_SOUND ("turret/tu_die3.wav"); - PRECACHE_SOUND ("turret/tu_active2.wav"); - // PRECACHE_SOUND ("turret/tu_retract.wav"); // just use deploy sound to save memory - PRECACHE_SOUND (this->GetDeploySound()); - PRECACHE_SOUND ("turret/tu_spinup.wav"); - PRECACHE_SOUND ("turret/tu_spindown.wav"); - PRECACHE_SOUND (this->GetAlertSound()); -} - -#define TURRET_GLOW_SPRITE "sprites/flare3.spr" - -void CTurret::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/turret.mdl"); - pev->health = gSkillData.turretHealth; - m_HackedGunPos = Vector( (float)0, (float)0, (float)12.75 ); - m_flMaxSpin = TURRET_MAXSPIN; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - - SetThink(&CTurret::Initialize); - - m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetAttachment( edict(), 2 ); - m_eyeBrightness = 0; - - pev->nextthink = gpGlobals->time + 0.3; -} - -void CTurret::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/turret.mdl"); - PRECACHE_MODEL (TURRET_GLOW_SPRITE); -} - -void CMiniTurret::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/miniturret.mdl"); - pev->health = gSkillData.miniturretHealth; - m_HackedGunPos = Vector( (float)0, (float)0, (float)12.75 ); - m_flMaxSpin = 0; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetThink(&CMiniTurret::Initialize); - pev->nextthink = gpGlobals->time + 0.3; -} - - -void CMiniTurret::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/miniturret.mdl"); - PRECACHE_SOUND("weapons/hks1.wav"); - PRECACHE_SOUND("weapons/hks2.wav"); - PRECACHE_SOUND("weapons/hks3.wav"); -} - -void CBaseTurret::Initialize(void) -{ - m_iOn = 0; - m_fBeserk = 0; - m_iSpin = 0; - - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - - if (m_iBaseTurnRate == 0) - { - m_iBaseTurnRate = TURRET_TURNRATE; - } - if (m_flMaxWait == 0) - { - m_flMaxWait = TURRET_MAXWAIT; - } - - m_flStartYaw = pev->angles.y; - if (m_iOrientation == 1) - { - pev->idealpitch = 180; - pev->angles.x = 180; - pev->view_ofs.z = -pev->view_ofs.z; - pev->effects |= EF_INVLIGHT; - pev->angles.y = pev->angles.y + 180; - if (pev->angles.y > 360) - pev->angles.y = pev->angles.y - 360; - } - - m_vecGoalAngles.x = 0; - - if (m_iAutoStart) - { - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::AutoSearchThink); - pev->nextthink = gpGlobals->time + .1; - } - else - SetThink(&CBaseTurret::SUB_DoNothing); - - int a = 0; -} - -void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_iOn ) ) - return; - - if (m_iOn) - { - m_hEnemy = NULL; - pev->nextthink = gpGlobals->time + 0.1; - m_iAutoStart = FALSE;// switching off a turret disables autostart - //!!!! this should spin down first!!BUGBUG - SetThink(&CBaseTurret::Retire); - } - else - { - pev->nextthink = gpGlobals->time + 0.1; // turn on delay - - // if the turret is flagged as an autoactivate turret, re-enable it's ability open self. - if ( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - { - m_iAutoStart = TRUE; - } - - SetThink(&CBaseTurret::Deploy); - } -} - - -void CBaseTurret::Ping( void ) -{ - // make the pinging noise every second while searching - if (m_flPingTime == 0) - m_flPingTime = gpGlobals->time + kPingInterval; - else if (m_flPingTime <= gpGlobals->time) - { - m_flPingTime = gpGlobals->time + kPingInterval; - EMIT_SOUND(ENT(pev), CHAN_ITEM, this->GetPingSound(), kPingVolume, ATTN_STATIC); - EyeOn( ); - } - else if (m_eyeBrightness > 0) - { - EyeOff( ); - } -} - - -void CBaseTurret::EyeOn( ) -{ - if (m_pEyeGlow) - { - if (m_eyeBrightness != 255) - { - m_eyeBrightness = 255; - } - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } -} - - -void CBaseTurret::EyeOff( ) -{ - if (m_pEyeGlow) - { - if (m_eyeBrightness > 0) - { - m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } - } -} - -bool CBaseTurret::NeedsLineOfSight() const -{ - return true; -} - -void CBaseTurret::ActiveThink(void) -{ - int fAttack = 0; - Vector vecDirToEnemy; - - pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); - - if ((!m_iOn) || FNullEnt(m_hEnemy)) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - - // if it's dead, look for something new - if ( !m_hEnemy->IsAlive() ) - { - if (!m_flLastSight) - { - m_flLastSight = gpGlobals->time + 0.5; // continue-shooting timeout - } - else - { - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - } - - Vector vecMid = pev->origin + pev->view_ofs; - Vector vecMidEnemy = m_hEnemy->BodyTarget( vecMid ); - - // Look for our current enemy - bool theEnemyHasCloaking = false;//GetHasUpgrade(m_hEnemy->pev->iuser4, MASK_ALIEN_UPGRADE_10); - if(theEnemyHasCloaking) - { - int a = 0; - } - - int fEnemyVisible = FBoxVisible(pev, m_hEnemy->pev, vecMidEnemy) || !this->NeedsLineOfSight(); - - vecDirToEnemy = vecMidEnemy - vecMid; // calculate dir and dist to enemy - float flDistToEnemy = vecDirToEnemy.Length(); - - Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid); - - // Current enemy is not visible. - if (!fEnemyVisible || (flDistToEnemy > this->GetRange()) || theEnemyHasCloaking) - { - if (!m_flLastSight) - m_flLastSight = gpGlobals->time + 0.5; - else - { - // Should we look for a new target? - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - fEnemyVisible = 0; - } - else - { - m_vecLastSight = vecMidEnemy; - } - - UTIL_MakeAimVectors(m_vecCurAngles); - - /* - ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n", - m_vecCurAngles.x, m_vecCurAngles.y, - gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_forward.z ); - */ - - Vector vecLOS = vecDirToEnemy; //vecMid - m_vecLastSight; - vecLOS = vecLOS.Normalize(); - - // Is the Gun looking at the target - if (DotProduct(vecLOS, gpGlobals->v_forward) <= 0.866) // 30 degree slop - fAttack = FALSE; - else - fAttack = TRUE; - - // fire the gun - if (m_iSpin && ((fAttack) || (m_fBeserk))) - { - Vector vecSrc, vecAng; - GetAttachment( 0, vecSrc, vecAng ); - SetTurretAnim(TURRET_ANIM_FIRE); - Shoot(vecSrc, gpGlobals->v_forward ); - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - this->StopShooting(); - } - - //move the gun - if (m_fBeserk) - { - if (RANDOM_LONG(0,9) == 0) - { - m_vecGoalAngles.y = RANDOM_FLOAT(0,360); - m_vecGoalAngles.x = RANDOM_FLOAT(0,90) - 90 * m_iOrientation; - TakeDamage(pev,pev,1, DMG_GENERIC); // don't beserk forever - return; - } - } - else if (fEnemyVisible) - { - if (vec.y > 360) - vec.y -= 360; - - if (vec.y < 0) - vec.y += 360; - - //ALERT(at_console, "[%.2f]", vec.x); - - if (vec.x < -180) - vec.x += 360; - - if (vec.x > 180) - vec.x -= 360; - - // now all numbers should be in [1...360] - // pin to turret limitations to [-90...15] - - if (m_iOrientation == 0) - { - if (vec.x > 90) - vec.x = 90; - else if (vec.x < m_iMinPitch) - vec.x = m_iMinPitch; - } - else - { - if (vec.x < -90) - vec.x = -90; - else if (vec.x > -m_iMinPitch) - vec.x = -m_iMinPitch; - } - - // ALERT(at_console, "->[%.2f]\n", vec.x); - - m_vecGoalAngles.y = vec.y; - m_vecGoalAngles.x = vec.x; - - } - - SpinUpCall(); - MoveTurret(); -} - - -void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_12MM, 1 ); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6); - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - - -void CMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_9MM, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - - -void CBaseTurret::Deploy(void) -{ - pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); - - if (pev->sequence != TURRET_ANIM_DEPLOY) - { - m_iOn = 1; - SetTurretAnim(TURRET_ANIM_DEPLOY); - EMIT_SOUND(ENT(pev), CHAN_BODY, this->GetDeploySound(), TURRET_MACHINE_VOLUME, ATTN_NORM); - SUB_UseTargets( this, USE_ON, 0 ); - } - - if (m_fSequenceFinished) - { - pev->maxs.z = m_iDeployHeight; - pev->mins.z = -m_iDeployHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - - m_vecCurAngles.x = 0; - - if (m_iOrientation == 1) - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); - } - else - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); - } - - SetTurretAnim(TURRET_ANIM_SPIN); - pev->framerate = 0; - SetThink(&CBaseTurret::SearchThink); - } - - m_flLastSight = gpGlobals->time + m_flMaxWait; -} - -void CBaseTurret::Retire(void) -{ - // make the turret level - m_vecGoalAngles.x = 0; - m_vecGoalAngles.y = m_flStartYaw; - - pev->nextthink = gpGlobals->time + 0.1; - - StudioFrameAdvance( ); - - EyeOff( ); - - if (!MoveTurret()) - { - if (m_iSpin) - { - SpinDownCall(); - } - else if (pev->sequence != TURRET_ANIM_RETIRE) - { - SetTurretAnim(TURRET_ANIM_RETIRE); - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, this->GetDeploySound(), TURRET_MACHINE_VOLUME, ATTN_NORM, 0, 120); - SUB_UseTargets( this, USE_OFF, 0 ); - } - else if (m_fSequenceFinished) - { - m_iOn = 0; - m_flLastSight = 0; - SetTurretAnim(TURRET_ANIM_NONE); - pev->maxs.z = m_iRetractHeight; - pev->mins.z = -m_iRetractHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - if (m_iAutoStart) - { - SetThink(&CBaseTurret::AutoSearchThink); - pev->nextthink = gpGlobals->time + .1; - } - else - SetThink(&CBaseTurret::SUB_DoNothing); - } - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - } -} - - -void CTurret::SpinUpCall(void) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - // Are we already spun up? If not start the two stage process. - if (!m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - // for the first pass, spin up the the barrel - if (!m_iStartSpin) - { - pev->nextthink = gpGlobals->time + 1.0; // spinup delay - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_spinup.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - m_iStartSpin = 1; - pev->framerate = 0.1; - } - // after the barrel is spun up, turn on the hum - else if (pev->framerate >= 1.0) - { - pev->nextthink = gpGlobals->time + 0.1; // retarget delay - EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SetThink(&CTurret::ActiveThink); - m_iStartSpin = 0; - m_iSpin = 1; - } - else - { - pev->framerate += 0.075; - } - } - - if (m_iSpin) - { - SetThink(&CTurret::ActiveThink); - } -} - - -void CTurret::SpinDownCall(void) -{ - if (m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - if (pev->framerate == 1.0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - EMIT_SOUND(ENT(pev), CHAN_ITEM, "turret/tu_spindown.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } - pev->framerate -= 0.02; - if (pev->framerate <= 0) - { - pev->framerate = 0; - m_iSpin = 0; - } - } -} - - -void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) -{ - if (pev->sequence != anim) - { - switch(anim) - { - case TURRET_ANIM_FIRE: - case TURRET_ANIM_SPIN: - if (pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN) - { - pev->frame = 0; - } - break; - default: - pev->frame = 0; - break; - } - - pev->sequence = anim; - ResetSequenceInfo( ); - - switch(anim) - { - case TURRET_ANIM_RETIRE: - pev->frame = 255; - pev->framerate = -1.0; - break; - case TURRET_ANIM_DIE: - pev->framerate = 1.0; - break; - } - //ALERT(at_console, "Turret anim #%d\n", anim); - } -} - - -// -// This search function will sit with the turret deployed and look for a new target. -// After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will -// retact. -// -void CBaseTurret::SearchThink(void) -{ - // ensure rethink - SetTurretAnim(TURRET_ANIM_SPIN); - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (m_flSpinUpTime == 0 && m_flMaxSpin) - m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; - - Ping( ); - - // If we have a target and we're still healthy - if (m_hEnemy != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - - // Acquire Target - if (m_hEnemy == NULL) - { - Look(this->GetRange()); - m_hEnemy = BestVisibleEnemy(); - } - - // If we've found a target, spin up the barrel and start to attack - if (m_hEnemy != NULL) - { - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::ActiveThink); - } - else - { - // Are we out of time, do we need to retract? - if (gpGlobals->time > m_flLastSight) - { - //Before we retrace, make sure that we are spun down. - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::Retire); - } - // should we stop the spin? - else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) - { - SpinDownCall(); - } - - // generic hunt for new victims - m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate); - if (m_vecGoalAngles.y >= 360) - m_vecGoalAngles.y -= 360; - MoveTurret(); - } -} - -int CBaseTurret::GetRange() const -{ - return TURRET_RANGE; -} - -// -// This think function will deploy the turret when something comes into range. This is for -// automatically activated turrets. -// -void CBaseTurret::AutoSearchThink(void) -{ - // ensure rethink - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.3; - - // If we have a target and we're still healthy - - if (m_hEnemy != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - // Acquire Target - - if (m_hEnemy == NULL) - { - Look( this->GetRange() ); - m_hEnemy = BestVisibleEnemy(); - } - - if (m_hEnemy != NULL) - { - SetThink(&CBaseTurret::Deploy); - EMIT_SOUND(ENT(pev), CHAN_BODY, this->GetAlertSound(), TURRET_MACHINE_VOLUME, ATTN_NORM); - } -} - - -void CBaseTurret :: TurretDeath( void ) -{ - BOOL iActive = FALSE; - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->deadflag != DEAD_DEAD) - { - pev->deadflag = DEAD_DEAD; - - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - - if (m_iOrientation == 0) - m_vecGoalAngles.x = -15; - else - m_vecGoalAngles.x = -90; - - SetTurretAnim(TURRET_ANIM_DIE); - - EyeOn( ); - } - - EyeOff( ); - - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) - { - // lots of smoke - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ) ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ) ); - WRITE_COORD( pev->origin.z - m_iOrientation * 64 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 25 ); // scale * 10 - WRITE_BYTE( 10 - m_iOrientation * 5); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 5 ) > gpGlobals->time) - { - Vector vecSrc = Vector( (float)RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ), (float)RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ), (float)0 ); - if (m_iOrientation == 0) - vecSrc = vecSrc + Vector( (float)0, (float)0, (float)RANDOM_FLOAT( pev->origin.z, pev->absmax.z ) ); - else - vecSrc = vecSrc + Vector( (float)0, (float)0, (float)RANDOM_FLOAT( pev->absmin.z, pev->origin.z ) ); - - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - - - -void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( ptr->iHitgroup == 10 ) - { - // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - - if ( !pev->takedamage ) - return; - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -// take damage. bitsDamageType indicates type of damage sustained, ie: DMG_BULLET - -int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - - if (!m_iOn) - flDamage /= 10.0; - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CBaseTurret::TurretDeath); - SUB_UseTargets( this, USE_ON, 0 ); // wake up others - pev->nextthink = gpGlobals->time + 0.1; - - return 0; - } - - if (pev->health <= 10) - { - if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) - { - m_fBeserk = 1; - SetThink(&CBaseTurret::SearchThink); - } - } - - return 1; -} - -int CBaseTurret::MoveTurret(void) -{ - ASSERT(this->m_iBaseTurnRate > 0); - ASSERT(this->m_fTurnRate > 0); - - int state = 0; - // any x movement? - - if (m_vecCurAngles.x != m_vecGoalAngles.x) - { - float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; - - m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir; - - // if we started below the goal, and now we're past, peg to goal - if (flDir == 1) - { - if (m_vecCurAngles.x > m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - else - { - if (m_vecCurAngles.x < m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - - if (m_iOrientation == 0) - SetBoneController(1, -m_vecCurAngles.x); - else - SetBoneController(1, m_vecCurAngles.x); - state = 1; - } - - if (m_vecCurAngles.y != m_vecGoalAngles.y) - { - float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; - float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); - - if (flDist > 180) - { - flDist = 360 - flDist; - flDir = -flDir; - } - if (flDist > 30) - { - if (m_fTurnRate < m_iBaseTurnRate * 10) - { - m_fTurnRate += m_iBaseTurnRate; - } - } - else if (m_fTurnRate > 45) - { - m_fTurnRate -= m_iBaseTurnRate; - } - else - { - m_fTurnRate += m_iBaseTurnRate; - } - - m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; - - if (m_vecCurAngles.y < 0) - m_vecCurAngles.y += 360; - else if (m_vecCurAngles.y >= 360) - m_vecCurAngles.y -= 360; - - if (flDist < (0.05 * m_iBaseTurnRate)) - m_vecCurAngles.y = m_vecGoalAngles.y; - - //ALERT(at_console, "%.2f -> %.2f\n", m_vecCurAngles.y, y); - if (m_iOrientation == 0) - SetBoneController(0, m_vecCurAngles.y - pev->angles.y ); - else - SetBoneController(0, pev->angles.y - 180 - m_vecCurAngles.y ); - state = 1; - } - - if (!state) - m_fTurnRate = m_iBaseTurnRate; - - //ALERT(at_console, "(%.2f, %.2f)->(%.2f, %.2f)\n", m_vecCurAngles.x, - // m_vecCurAngles.y, m_vecGoalAngles.x, m_vecGoalAngles.y); - return state; -} - -// -// ID as a machine -// -int CBaseTurret::Classify ( void ) -{ - if (m_iOn || m_iAutoStart) - return CLASS_MACHINE; - return CLASS_NONE; -} - - - - -LINK_ENTITY_TO_CLASS( monster_sentry, CSentry ); - -void CSentry::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL (kDeployedTurretModel); -} - -void CSentry::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), kDeployedTurretModel); - pev->health = gSkillData.sentryHealth; - m_HackedGunPos = Vector( 0, 0, 48 ); - pev->view_ofs.z = 48; - m_flMaxWait = TURRET_MAXWAIT; - m_flMaxSpin = TURRET_MAXSPIN; - - CBaseTurret::Spawn(); - m_iRetractHeight = 64; - m_iDeployHeight = 64; - m_iMinPitch = -60; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetTouch(&CSentry::SentryTouch); - SetThink(&CSentry::Initialize); - pev->nextthink = gpGlobals->time + 0.3; -} - -void CSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_MP5, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - -int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - -// if (!m_iOn) -// { -// SetThink( Deploy ); -// SetUse( NULL ); -// pev->nextthink = gpGlobals->time + 0.1; -// } - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CSentry::SentryDeath); - SUB_UseTargets( this, USE_ON, 0 ); // wake up others - pev->nextthink = gpGlobals->time + 0.1; - - return 0; - } - - return 1; -} - - -void CSentry::SentryTouch( CBaseEntity *pOther ) -{ - if ( pOther && (pOther->IsPlayer() || (pOther->pev->flags & FL_MONSTER)) ) - { - TakeDamage(pOther->pev, pOther->pev, 0, 0 ); - } -} - - -void CSentry :: SentryDeath( void ) -{ - BOOL iActive = FALSE; - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->deadflag != DEAD_DEAD) - { - pev->deadflag = DEAD_DEAD; - - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - - SetTurretAnim(TURRET_ANIM_DIE); - - pev->solid = SOLID_NOT; - pev->angles.y = UTIL_AngleMod( pev->angles.y + RANDOM_LONG( 0, 2 ) * 120 ); - - EyeOn( ); - } - - EyeOff( ); - - Vector vecSrc, vecAng; - GetAttachment( 1, vecSrc, vecAng ); - - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) - { - // lots of smoke - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x + RANDOM_FLOAT( -16, 16 ) ); - WRITE_COORD( vecSrc.y + RANDOM_FLOAT( -16, 16 ) ); - WRITE_COORD( vecSrc.z - 32 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 15 ); // scale * 10 - WRITE_BYTE( 8 ); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) - { - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +/* + +===== turret.cpp ======================================================== + +*/ + +// +// TODO: +// Take advantage of new monster fields like m_hEnemy and get rid of that OFFSET() stuff +// Revisit enemy validation stuff, maybe it's not necessary with the newest monster code +// + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "effects.h" +#include "turret.h" +#include "../mod/AvHMarineEquipmentConstants.h" +#include "../mod/AvHSpecials.h" + +extern Vector VecBModelOrigin( entvars_t* pevBModel ); + + +TYPEDESCRIPTION CBaseTurret::m_SaveData[] = +{ + DEFINE_FIELD( CBaseTurret, m_flMaxSpin, FIELD_FLOAT ), + DEFINE_FIELD( CBaseTurret, m_iSpin, FIELD_INTEGER ), + + DEFINE_FIELD( CBaseTurret, m_pEyeGlow, FIELD_CLASSPTR ), + DEFINE_FIELD( CBaseTurret, m_eyeBrightness, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_iDeployHeight, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_iRetractHeight, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_iMinPitch, FIELD_INTEGER ), + + DEFINE_FIELD( CBaseTurret, m_iBaseTurnRate, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_fTurnRate, FIELD_FLOAT ), + DEFINE_FIELD( CBaseTurret, m_iOrientation, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_iOn, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_fBeserk, FIELD_INTEGER ), + DEFINE_FIELD( CBaseTurret, m_iAutoStart, FIELD_INTEGER ), + + + DEFINE_FIELD( CBaseTurret, m_vecLastSight, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CBaseTurret, m_flLastSight, FIELD_TIME ), + DEFINE_FIELD( CBaseTurret, m_flMaxWait, FIELD_FLOAT ), + DEFINE_FIELD( CBaseTurret, m_iSearchSpeed, FIELD_INTEGER ), + + DEFINE_FIELD( CBaseTurret, m_flStartYaw, FIELD_FLOAT ), + DEFINE_FIELD( CBaseTurret, m_vecCurAngles, FIELD_VECTOR ), + DEFINE_FIELD( CBaseTurret, m_vecGoalAngles, FIELD_VECTOR ), + + DEFINE_FIELD( CBaseTurret, m_flPingTime, FIELD_TIME ), + DEFINE_FIELD( CBaseTurret, m_flSpinUpTime, FIELD_TIME ), +}; + +IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ); + +TYPEDESCRIPTION CTurret::m_SaveData[] = +{ + DEFINE_FIELD( CTurret, m_iStartSpin, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ); + + + +LINK_ENTITY_TO_CLASS( monster_turret, CTurret ); +LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ); + +const float kPingInterval = 3.0f; +const float kPingVolume = .7f; + +void CBaseTurret::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "maxsleep")) + { + m_flMaxWait = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "orientation")) + { + m_iOrientation = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + + } + else if (FStrEq(pkvd->szKeyName, "searchspeed")) + { + m_iSearchSpeed = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + + } + else if (FStrEq(pkvd->szKeyName, "turnrate")) + { + m_iBaseTurnRate = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "style") || + FStrEq(pkvd->szKeyName, "height") || + FStrEq(pkvd->szKeyName, "value1") || + FStrEq(pkvd->szKeyName, "value2") || + FStrEq(pkvd->szKeyName, "value3")) + pkvd->fHandled = TRUE; + else + CBaseMonster::KeyValue( pkvd ); +} + + +void CBaseTurret::Spawn() +{ + Precache( ); + pev->nextthink = gpGlobals->time + 1; + pev->movetype = MOVETYPE_FLY; + pev->sequence = 0; + pev->frame = 0; + pev->solid = SOLID_SLIDEBOX; + pev->takedamage = DAMAGE_AIM; + + SetBits (pev->flags, FL_MONSTER); + SetUse(&CBaseTurret::TurretUse ); + + if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) + && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) + { + m_iAutoStart = TRUE; + } + + ResetSequenceInfo( ); + SetBoneController( 0, 0 ); + SetBoneController( 1, 0 ); + m_flFieldOfView = VIEW_FIELD_FULL; + // m_flSightRange = this->GetRange(); +} + +char* CBaseTurret::GetPingSound() const +{ + return "turret/tu_ping.wav"; +} + +char* CBaseTurret::GetActiveSound() const +{ + return "turret/tu_active2.wav"; +} + +char* CBaseTurret::GetAlertSound() const +{ + return "turret/tu_alert.wav"; +} + +char* CBaseTurret::GetDeploySound() const +{ + return "turret/tu_deploy.wav"; +} + +void CBaseTurret::Precache( ) +{ + PRECACHE_SOUND ("turret/tu_fire1.wav"); + PRECACHE_SOUND (this->GetPingSound()); + PRECACHE_SOUND (this->GetActiveSound()); + PRECACHE_SOUND ("turret/tu_die.wav"); + PRECACHE_SOUND ("turret/tu_die2.wav"); + PRECACHE_SOUND ("turret/tu_die3.wav"); + PRECACHE_SOUND ("turret/tu_active2.wav"); + // PRECACHE_SOUND ("turret/tu_retract.wav"); // just use deploy sound to save memory + PRECACHE_SOUND (this->GetDeploySound()); + PRECACHE_SOUND ("turret/tu_spinup.wav"); + PRECACHE_SOUND ("turret/tu_spindown.wav"); + PRECACHE_SOUND (this->GetAlertSound()); +} + +#define TURRET_GLOW_SPRITE "sprites/flare3.spr" + +void CTurret::Spawn() +{ + Precache( ); + SET_MODEL(ENT(pev), "models/turret.mdl"); + pev->health = gSkillData.turretHealth; + m_HackedGunPos = Vector( (float)0, (float)0, (float)12.75 ); + m_flMaxSpin = TURRET_MAXSPIN; + pev->view_ofs.z = 12.75; + + CBaseTurret::Spawn( ); + + m_iRetractHeight = 16; + m_iDeployHeight = 32; + m_iMinPitch = -15; + UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); + + SetThink(&CTurret::Initialize); + + m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); + m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); + m_pEyeGlow->SetAttachment( edict(), 2 ); + m_eyeBrightness = 0; + + pev->nextthink = gpGlobals->time + 0.3; +} + +void CTurret::Precache() +{ + CBaseTurret::Precache( ); + PRECACHE_MODEL ("models/turret.mdl"); + PRECACHE_MODEL (TURRET_GLOW_SPRITE); +} + +void CMiniTurret::Spawn() +{ + Precache( ); + SET_MODEL(ENT(pev), "models/miniturret.mdl"); + pev->health = gSkillData.miniturretHealth; + m_HackedGunPos = Vector( (float)0, (float)0, (float)12.75 ); + m_flMaxSpin = 0; + pev->view_ofs.z = 12.75; + + CBaseTurret::Spawn( ); + m_iRetractHeight = 16; + m_iDeployHeight = 32; + m_iMinPitch = -15; + UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); + + SetThink(&CMiniTurret::Initialize); + pev->nextthink = gpGlobals->time + 0.3; +} + + +void CMiniTurret::Precache() +{ + CBaseTurret::Precache( ); + PRECACHE_MODEL ("models/miniturret.mdl"); + PRECACHE_SOUND("weapons/hks1.wav"); + PRECACHE_SOUND("weapons/hks2.wav"); + PRECACHE_SOUND("weapons/hks3.wav"); +} + +void CBaseTurret::Initialize(void) +{ + m_iOn = 0; + m_fBeserk = 0; + m_iSpin = 0; + + SetBoneController( 0, 0 ); + SetBoneController( 1, 0 ); + + if (m_iBaseTurnRate == 0) + { + m_iBaseTurnRate = TURRET_TURNRATE; + } + if (m_flMaxWait == 0) + { + m_flMaxWait = TURRET_MAXWAIT; + } + + m_flStartYaw = pev->angles.y; + if (m_iOrientation == 1) + { + pev->idealpitch = 180; + pev->angles.x = 180; + pev->view_ofs.z = -pev->view_ofs.z; + pev->effects |= EF_INVLIGHT; + pev->angles.y = pev->angles.y + 180; + if (pev->angles.y > 360) + pev->angles.y = pev->angles.y - 360; + } + + m_vecGoalAngles.x = 0; + + if (m_iAutoStart) + { + m_flLastSight = gpGlobals->time + m_flMaxWait; + SetThink(&CBaseTurret::AutoSearchThink); + pev->nextthink = gpGlobals->time + .1; + } + else + SetThink(&CBaseTurret::SUB_DoNothing); + + int a = 0; +} + +void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !ShouldToggle( useType, m_iOn ) ) + return; + + if (m_iOn) + { + m_hEnemy = NULL; + pev->nextthink = gpGlobals->time + 0.1; + m_iAutoStart = FALSE;// switching off a turret disables autostart + //!!!! this should spin down first!!BUGBUG + SetThink(&CBaseTurret::Retire); + } + else + { + pev->nextthink = gpGlobals->time + 0.1; // turn on delay + + // if the turret is flagged as an autoactivate turret, re-enable it's ability open self. + if ( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) + { + m_iAutoStart = TRUE; + } + + SetThink(&CBaseTurret::Deploy); + } +} + + +void CBaseTurret::Ping( void ) +{ + // make the pinging noise every second while searching + if (m_flPingTime == 0) + m_flPingTime = gpGlobals->time + kPingInterval; + else if (m_flPingTime <= gpGlobals->time) + { + m_flPingTime = gpGlobals->time + kPingInterval; + EMIT_SOUND(ENT(pev), CHAN_ITEM, this->GetPingSound(), kPingVolume, ATTN_STATIC); + EyeOn( ); + } + else if (m_eyeBrightness > 0) + { + EyeOff( ); + } +} + + +void CBaseTurret::EyeOn( ) +{ + if (m_pEyeGlow) + { + if (m_eyeBrightness != 255) + { + m_eyeBrightness = 255; + } + m_pEyeGlow->SetBrightness( m_eyeBrightness ); + } +} + + +void CBaseTurret::EyeOff( ) +{ + if (m_pEyeGlow) + { + if (m_eyeBrightness > 0) + { + m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); + m_pEyeGlow->SetBrightness( m_eyeBrightness ); + } + } +} + +bool CBaseTurret::NeedsLineOfSight() const +{ + return true; +} + +void CBaseTurret::ActiveThink(void) +{ + int fAttack = 0; + Vector vecDirToEnemy; + + pev->nextthink = gpGlobals->time + 0.1; + StudioFrameAdvance( ); + + if ((!m_iOn) || FNullEnt(m_hEnemy)) + { + m_hEnemy = NULL; + m_flLastSight = gpGlobals->time + m_flMaxWait; + SetThink(&CBaseTurret::SearchThink); + return; + } + + // if it's dead, look for something new + if ( !m_hEnemy->IsAlive() ) + { + if (!m_flLastSight) + { + m_flLastSight = gpGlobals->time + 0.5; // continue-shooting timeout + } + else + { + if (gpGlobals->time > m_flLastSight) + { + m_hEnemy = NULL; + m_flLastSight = gpGlobals->time + m_flMaxWait; + SetThink(&CBaseTurret::SearchThink); + return; + } + } + } + + Vector vecMid = pev->origin + pev->view_ofs; + Vector vecMidEnemy = m_hEnemy->BodyTarget( vecMid ); + + // Look for our current enemy + bool theEnemyHasCloaking = false;//GetHasUpgrade(m_hEnemy->pev->iuser4, MASK_ALIEN_UPGRADE_10); + if(theEnemyHasCloaking) + { + int a = 0; + } + + int fEnemyVisible = FBoxVisible(pev, m_hEnemy->pev, vecMidEnemy) || !this->NeedsLineOfSight(); + + vecDirToEnemy = vecMidEnemy - vecMid; // calculate dir and dist to enemy + float flDistToEnemy = vecDirToEnemy.Length(); + + Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid); + + // Current enemy is not visible. + if (!fEnemyVisible || (flDistToEnemy > this->GetRange()) || theEnemyHasCloaking) + { + if (!m_flLastSight) + m_flLastSight = gpGlobals->time + 0.5; + else + { + // Should we look for a new target? + if (gpGlobals->time > m_flLastSight) + { + m_hEnemy = NULL; + m_flLastSight = gpGlobals->time + m_flMaxWait; + SetThink(&CBaseTurret::SearchThink); + return; + } + } + fEnemyVisible = 0; + } + else + { + m_vecLastSight = vecMidEnemy; + } + + UTIL_MakeAimVectors(m_vecCurAngles); + + /* + ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n", + m_vecCurAngles.x, m_vecCurAngles.y, + gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_forward.z ); + */ + + Vector vecLOS = vecDirToEnemy; //vecMid - m_vecLastSight; + vecLOS = vecLOS.Normalize(); + + // Is the Gun looking at the target + if (DotProduct(vecLOS, gpGlobals->v_forward) <= 0.866) // 30 degree slop + fAttack = FALSE; + else + fAttack = TRUE; + + // fire the gun + if (m_iSpin && ((fAttack) || (m_fBeserk))) + { + Vector vecSrc, vecAng; + GetAttachment( 0, vecSrc, vecAng ); + SetTurretAnim(TURRET_ANIM_FIRE); + Shoot(vecSrc, gpGlobals->v_forward ); + } + else + { + SetTurretAnim(TURRET_ANIM_SPIN); + this->StopShooting(); + } + + //move the gun + if (m_fBeserk) + { + if (RANDOM_LONG(0,9) == 0) + { + m_vecGoalAngles.y = RANDOM_FLOAT(0,360); + m_vecGoalAngles.x = RANDOM_FLOAT(0,90) - 90 * m_iOrientation; + TakeDamage(pev,pev,1, DMG_GENERIC); // don't beserk forever + return; + } + } + else if (fEnemyVisible) + { + if (vec.y > 360) + vec.y -= 360; + + if (vec.y < 0) + vec.y += 360; + + //ALERT(at_console, "[%.2f]", vec.x); + + if (vec.x < -180) + vec.x += 360; + + if (vec.x > 180) + vec.x -= 360; + + // now all numbers should be in [1...360] + // pin to turret limitations to [-90...15] + + if (m_iOrientation == 0) + { + if (vec.x > 90) + vec.x = 90; + else if (vec.x < m_iMinPitch) + vec.x = m_iMinPitch; + } + else + { + if (vec.x < -90) + vec.x = -90; + else if (vec.x > -m_iMinPitch) + vec.x = -m_iMinPitch; + } + + // ALERT(at_console, "->[%.2f]\n", vec.x); + + m_vecGoalAngles.y = vec.y; + m_vecGoalAngles.x = vec.x; + + } + + SpinUpCall(); + MoveTurret(); +} + + +void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) +{ + FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_12MM, 1 ); + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6); + pev->effects = pev->effects | EF_MUZZLEFLASH; +} + + +void CMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) +{ + FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_9MM, 1 ); + + switch(RANDOM_LONG(0,2)) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; + } + pev->effects = pev->effects | EF_MUZZLEFLASH; +} + + +void CBaseTurret::Deploy(void) +{ + pev->nextthink = gpGlobals->time + 0.1; + StudioFrameAdvance( ); + + if (pev->sequence != TURRET_ANIM_DEPLOY) + { + m_iOn = 1; + SetTurretAnim(TURRET_ANIM_DEPLOY); + EMIT_SOUND(ENT(pev), CHAN_BODY, this->GetDeploySound(), TURRET_MACHINE_VOLUME, ATTN_NORM); + SUB_UseTargets( this, USE_ON, 0 ); + } + + if (m_fSequenceFinished) + { + pev->maxs.z = m_iDeployHeight; + pev->mins.z = -m_iDeployHeight; + UTIL_SetSize(pev, pev->mins, pev->maxs); + + m_vecCurAngles.x = 0; + + if (m_iOrientation == 1) + { + m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); + } + else + { + m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); + } + + SetTurretAnim(TURRET_ANIM_SPIN); + pev->framerate = 0; + SetThink(&CBaseTurret::SearchThink); + } + + m_flLastSight = gpGlobals->time + m_flMaxWait; +} + +void CBaseTurret::Retire(void) +{ + // make the turret level + m_vecGoalAngles.x = 0; + m_vecGoalAngles.y = m_flStartYaw; + + pev->nextthink = gpGlobals->time + 0.1; + + StudioFrameAdvance( ); + + EyeOff( ); + + if (!MoveTurret()) + { + if (m_iSpin) + { + SpinDownCall(); + } + else if (pev->sequence != TURRET_ANIM_RETIRE) + { + SetTurretAnim(TURRET_ANIM_RETIRE); + EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, this->GetDeploySound(), TURRET_MACHINE_VOLUME, ATTN_NORM, 0, 120); + SUB_UseTargets( this, USE_OFF, 0 ); + } + else if (m_fSequenceFinished) + { + m_iOn = 0; + m_flLastSight = 0; + SetTurretAnim(TURRET_ANIM_NONE); + pev->maxs.z = m_iRetractHeight; + pev->mins.z = -m_iRetractHeight; + UTIL_SetSize(pev, pev->mins, pev->maxs); + if (m_iAutoStart) + { + SetThink(&CBaseTurret::AutoSearchThink); + pev->nextthink = gpGlobals->time + .1; + } + else + SetThink(&CBaseTurret::SUB_DoNothing); + } + } + else + { + SetTurretAnim(TURRET_ANIM_SPIN); + } +} + + +void CTurret::SpinUpCall(void) +{ + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + // Are we already spun up? If not start the two stage process. + if (!m_iSpin) + { + SetTurretAnim( TURRET_ANIM_SPIN ); + // for the first pass, spin up the the barrel + if (!m_iStartSpin) + { + pev->nextthink = gpGlobals->time + 1.0; // spinup delay + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_spinup.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); + m_iStartSpin = 1; + pev->framerate = 0.1; + } + // after the barrel is spun up, turn on the hum + else if (pev->framerate >= 1.0) + { + pev->nextthink = gpGlobals->time + 0.1; // retarget delay + EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); + SetThink(&CTurret::ActiveThink); + m_iStartSpin = 0; + m_iSpin = 1; + } + else + { + pev->framerate += 0.075; + } + } + + if (m_iSpin) + { + SetThink(&CTurret::ActiveThink); + } +} + + +void CTurret::SpinDownCall(void) +{ + if (m_iSpin) + { + SetTurretAnim( TURRET_ANIM_SPIN ); + if (pev->framerate == 1.0) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); + EMIT_SOUND(ENT(pev), CHAN_ITEM, "turret/tu_spindown.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); + } + pev->framerate -= 0.02; + if (pev->framerate <= 0) + { + pev->framerate = 0; + m_iSpin = 0; + } + } +} + + +void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) +{ + if (pev->sequence != anim) + { + switch(anim) + { + case TURRET_ANIM_FIRE: + case TURRET_ANIM_SPIN: + if (pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN) + { + pev->frame = 0; + } + break; + default: + pev->frame = 0; + break; + } + + pev->sequence = anim; + ResetSequenceInfo( ); + + switch(anim) + { + case TURRET_ANIM_RETIRE: + pev->frame = 255; + pev->framerate = -1.0; + break; + case TURRET_ANIM_DIE: + pev->framerate = 1.0; + break; + } + //ALERT(at_console, "Turret anim #%d\n", anim); + } +} + + +// +// This search function will sit with the turret deployed and look for a new target. +// After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will +// retact. +// +void CBaseTurret::SearchThink(void) +{ + // ensure rethink + SetTurretAnim(TURRET_ANIM_SPIN); + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + if (m_flSpinUpTime == 0 && m_flMaxSpin) + m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; + + Ping( ); + + // If we have a target and we're still healthy + if (m_hEnemy != NULL) + { + if (!m_hEnemy->IsAlive() ) + m_hEnemy = NULL;// Dead enemy forces a search for new one + } + + + // Acquire Target + if (m_hEnemy == NULL) + { + Look(this->GetRange()); + m_hEnemy = BestVisibleEnemy(); + } + + // If we've found a target, spin up the barrel and start to attack + if (m_hEnemy != NULL) + { + m_flLastSight = 0; + m_flSpinUpTime = 0; + SetThink(&CBaseTurret::ActiveThink); + } + else + { + // Are we out of time, do we need to retract? + if (gpGlobals->time > m_flLastSight) + { + //Before we retrace, make sure that we are spun down. + m_flLastSight = 0; + m_flSpinUpTime = 0; + SetThink(&CBaseTurret::Retire); + } + // should we stop the spin? + else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) + { + SpinDownCall(); + } + + // generic hunt for new victims + m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate); + if (m_vecGoalAngles.y >= 360) + m_vecGoalAngles.y -= 360; + MoveTurret(); + } +} + +int CBaseTurret::GetRange() const +{ + return TURRET_RANGE; +} + +// +// This think function will deploy the turret when something comes into range. This is for +// automatically activated turrets. +// +void CBaseTurret::AutoSearchThink(void) +{ + // ensure rethink + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.3; + + // If we have a target and we're still healthy + + if (m_hEnemy != NULL) + { + if (!m_hEnemy->IsAlive() ) + m_hEnemy = NULL;// Dead enemy forces a search for new one + } + + // Acquire Target + + if (m_hEnemy == NULL) + { + Look( this->GetRange() ); + m_hEnemy = BestVisibleEnemy(); + } + + if (m_hEnemy != NULL) + { + SetThink(&CBaseTurret::Deploy); + EMIT_SOUND(ENT(pev), CHAN_BODY, this->GetAlertSound(), TURRET_MACHINE_VOLUME, ATTN_NORM); + } +} + + +void CBaseTurret :: TurretDeath( void ) +{ + BOOL iActive = FALSE; + + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + if (pev->deadflag != DEAD_DEAD) + { + pev->deadflag = DEAD_DEAD; + + float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + + if ( flRndSound <= 0.33 ) + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); + else if ( flRndSound <= 0.66 ) + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); + else + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); + + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); + + if (m_iOrientation == 0) + m_vecGoalAngles.x = -15; + else + m_vecGoalAngles.x = -90; + + SetTurretAnim(TURRET_ANIM_DIE); + + EyeOn( ); + } + + EyeOff( ); + + if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) + { + // lots of smoke + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ) ); + WRITE_COORD( RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ) ); + WRITE_COORD( pev->origin.z - m_iOrientation * 64 ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 25 ); // scale * 10 + WRITE_BYTE( 10 - m_iOrientation * 5); // framerate + MESSAGE_END(); + } + + if (pev->dmgtime + RANDOM_FLOAT( 0, 5 ) > gpGlobals->time) + { + Vector vecSrc = Vector( (float)RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ), (float)RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ), (float)0 ); + if (m_iOrientation == 0) + vecSrc = vecSrc + Vector( (float)0, (float)0, (float)RANDOM_FLOAT( pev->origin.z, pev->absmax.z ) ); + else + vecSrc = vecSrc + Vector( (float)0, (float)0, (float)RANDOM_FLOAT( pev->absmin.z, pev->origin.z ) ); + + UTIL_Sparks( vecSrc ); + } + + if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) + { + pev->framerate = 0; + SetThink( NULL ); + } +} + + + +void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +{ + if ( ptr->iHitgroup == 10 ) + { + // hit armor + if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + { + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); + pev->dmgtime = gpGlobals->time; + } + + flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated + } + + if ( !pev->takedamage ) + return; + + AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); +} + +// take damage. bitsDamageType indicates type of damage sustained, ie: DMG_BULLET + +int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) +{ + if ( !pev->takedamage ) + return 0; + + if (!m_iOn) + flDamage /= 10.0; + + pev->health -= flDamage; + if (pev->health <= 0) + { + pev->health = 0; + pev->takedamage = DAMAGE_NO; + pev->dmgtime = gpGlobals->time; + + ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? + + SetUse(NULL); + SetThink(&CBaseTurret::TurretDeath); + SUB_UseTargets( this, USE_ON, 0 ); // wake up others + pev->nextthink = gpGlobals->time + 0.1; + + return 0; + } + + if (pev->health <= 10) + { + if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) + { + m_fBeserk = 1; + SetThink(&CBaseTurret::SearchThink); + } + } + + return 1; +} + +int CBaseTurret::MoveTurret(void) +{ + ASSERT(this->m_iBaseTurnRate > 0); + ASSERT(this->m_fTurnRate > 0); + + int state = 0; + // any x movement? + + if (m_vecCurAngles.x != m_vecGoalAngles.x) + { + float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; + + m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir; + + // if we started below the goal, and now we're past, peg to goal + if (flDir == 1) + { + if (m_vecCurAngles.x > m_vecGoalAngles.x) + m_vecCurAngles.x = m_vecGoalAngles.x; + } + else + { + if (m_vecCurAngles.x < m_vecGoalAngles.x) + m_vecCurAngles.x = m_vecGoalAngles.x; + } + + if (m_iOrientation == 0) + SetBoneController(1, -m_vecCurAngles.x); + else + SetBoneController(1, m_vecCurAngles.x); + state = 1; + } + + if (m_vecCurAngles.y != m_vecGoalAngles.y) + { + float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; + float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); + + if (flDist > 180) + { + flDist = 360 - flDist; + flDir = -flDir; + } + if (flDist > 30) + { + if (m_fTurnRate < m_iBaseTurnRate * 10) + { + m_fTurnRate += m_iBaseTurnRate; + } + } + else if (m_fTurnRate > 45) + { + m_fTurnRate -= m_iBaseTurnRate; + } + else + { + m_fTurnRate += m_iBaseTurnRate; + } + + m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; + + if (m_vecCurAngles.y < 0) + m_vecCurAngles.y += 360; + else if (m_vecCurAngles.y >= 360) + m_vecCurAngles.y -= 360; + + if (flDist < (0.05 * m_iBaseTurnRate)) + m_vecCurAngles.y = m_vecGoalAngles.y; + + //ALERT(at_console, "%.2f -> %.2f\n", m_vecCurAngles.y, y); + if (m_iOrientation == 0) + SetBoneController(0, m_vecCurAngles.y - pev->angles.y ); + else + SetBoneController(0, pev->angles.y - 180 - m_vecCurAngles.y ); + state = 1; + } + + if (!state) + m_fTurnRate = m_iBaseTurnRate; + + //ALERT(at_console, "(%.2f, %.2f)->(%.2f, %.2f)\n", m_vecCurAngles.x, + // m_vecCurAngles.y, m_vecGoalAngles.x, m_vecGoalAngles.y); + return state; +} + +// +// ID as a machine +// +int CBaseTurret::Classify ( void ) +{ + if (m_iOn || m_iAutoStart) + return CLASS_MACHINE; + return CLASS_NONE; +} + + + + +LINK_ENTITY_TO_CLASS( monster_sentry, CSentry ); + +void CSentry::Precache() +{ + CBaseTurret::Precache( ); + PRECACHE_MODEL (kDeployedTurretModel); +} + +void CSentry::Spawn() +{ + Precache( ); + SET_MODEL(ENT(pev), kDeployedTurretModel); + pev->health = gSkillData.sentryHealth; + m_HackedGunPos = Vector( 0, 0, 48 ); + pev->view_ofs.z = 48; + m_flMaxWait = TURRET_MAXWAIT; + m_flMaxSpin = TURRET_MAXSPIN; + + CBaseTurret::Spawn(); + m_iRetractHeight = 64; + m_iDeployHeight = 64; + m_iMinPitch = -60; + UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); + + SetTouch(&CSentry::SentryTouch); + SetThink(&CSentry::Initialize); + pev->nextthink = gpGlobals->time + 0.3; +} + +void CSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) +{ + FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_MP5, 1 ); + + switch(RANDOM_LONG(0,2)) + { + case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; + } + pev->effects = pev->effects | EF_MUZZLEFLASH; +} + +int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) +{ + if ( !pev->takedamage ) + return 0; + +// if (!m_iOn) +// { +// SetThink( Deploy ); +// SetUse( NULL ); +// pev->nextthink = gpGlobals->time + 0.1; +// } + + pev->health -= flDamage; + if (pev->health <= 0) + { + pev->health = 0; + pev->takedamage = DAMAGE_NO; + pev->dmgtime = gpGlobals->time; + + ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? + + SetUse(NULL); + SetThink(&CSentry::SentryDeath); + SUB_UseTargets( this, USE_ON, 0 ); // wake up others + pev->nextthink = gpGlobals->time + 0.1; + + return 0; + } + + return 1; +} + + +void CSentry::SentryTouch( CBaseEntity *pOther ) +{ + if ( pOther && (pOther->IsPlayer() || (pOther->pev->flags & FL_MONSTER)) ) + { + TakeDamage(pOther->pev, pOther->pev, 0, 0 ); + } +} + + +void CSentry :: SentryDeath( void ) +{ + BOOL iActive = FALSE; + + StudioFrameAdvance( ); + pev->nextthink = gpGlobals->time + 0.1; + + if (pev->deadflag != DEAD_DEAD) + { + pev->deadflag = DEAD_DEAD; + + float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + + if ( flRndSound <= 0.33 ) + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); + else if ( flRndSound <= 0.66 ) + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); + else + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); + + EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); + + SetBoneController( 0, 0 ); + SetBoneController( 1, 0 ); + + SetTurretAnim(TURRET_ANIM_DIE); + + pev->solid = SOLID_NOT; + pev->angles.y = UTIL_AngleMod( pev->angles.y + RANDOM_LONG( 0, 2 ) * 120 ); + + EyeOn( ); + } + + EyeOff( ); + + Vector vecSrc, vecAng; + GetAttachment( 1, vecSrc, vecAng ); + + if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) + { + // lots of smoke + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( vecSrc.x + RANDOM_FLOAT( -16, 16 ) ); + WRITE_COORD( vecSrc.y + RANDOM_FLOAT( -16, 16 ) ); + WRITE_COORD( vecSrc.z - 32 ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 15 ); // scale * 10 + WRITE_BYTE( 8 ); // framerate + MESSAGE_END(); + } + + if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) + { + UTIL_Sparks( vecSrc ); + } + + if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) + { + pev->framerate = 0; + SetThink( NULL ); + } +} + diff --git a/main/source/dlls/turret.cpp~ b/main/source/dlls/turret.cpp~ deleted file mode 100644 index 6b29e0cd..00000000 --- a/main/source/dlls/turret.cpp~ +++ /dev/null @@ -1,1210 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== turret.cpp ======================================================== - -*/ - -// -// TODO: -// Take advantage of new monster fields like m_hEnemy and get rid of that OFFSET() stuff -// Revisit enemy validation stuff, maybe it's not necessary with the newest monster code -// - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "effects.h" -#include "dlls/turret.h" -#include "../mod/AvHMarineEquipmentConstants.h" -#include "../mod/AvHSpecials.h" - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - - -TYPEDESCRIPTION CBaseTurret::m_SaveData[] = -{ - DEFINE_FIELD( CBaseTurret, m_flMaxSpin, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iSpin, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_pEyeGlow, FIELD_CLASSPTR ), - DEFINE_FIELD( CBaseTurret, m_eyeBrightness, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iDeployHeight, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iRetractHeight, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iMinPitch, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_iBaseTurnRate, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_fTurnRate, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iOrientation, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iOn, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_fBeserk, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iAutoStart, FIELD_INTEGER ), - - - DEFINE_FIELD( CBaseTurret, m_vecLastSight, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseTurret, m_flLastSight, FIELD_TIME ), - DEFINE_FIELD( CBaseTurret, m_flMaxWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iSearchSpeed, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_flStartYaw, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_vecCurAngles, FIELD_VECTOR ), - DEFINE_FIELD( CBaseTurret, m_vecGoalAngles, FIELD_VECTOR ), - - DEFINE_FIELD( CBaseTurret, m_flPingTime, FIELD_TIME ), - DEFINE_FIELD( CBaseTurret, m_flSpinUpTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ); - -TYPEDESCRIPTION CTurret::m_SaveData[] = -{ - DEFINE_FIELD( CTurret, m_iStartSpin, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ); - - - -LINK_ENTITY_TO_CLASS( monster_turret, CTurret ); -LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ); - -const float kPingInterval = 3.0f; -const float kPingVolume = .7f; - -void CBaseTurret::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "maxsleep")) - { - m_flMaxWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "orientation")) - { - m_iOrientation = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else if (FStrEq(pkvd->szKeyName, "searchspeed")) - { - m_iSearchSpeed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else if (FStrEq(pkvd->szKeyName, "turnrate")) - { - m_iBaseTurnRate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CBaseTurret::Spawn() -{ - Precache( ); - pev->nextthink = gpGlobals->time + 1; - pev->movetype = MOVETYPE_FLY; - pev->sequence = 0; - pev->frame = 0; - pev->solid = SOLID_SLIDEBOX; - pev->takedamage = DAMAGE_AIM; - - SetBits (pev->flags, FL_MONSTER); - SetUse(&CBaseTurret::TurretUse ); - - if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) - { - m_iAutoStart = TRUE; - } - - ResetSequenceInfo( ); - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - m_flFieldOfView = VIEW_FIELD_FULL; - // m_flSightRange = this->GetRange(); -} - -char* CBaseTurret::GetPingSound() const -{ - return "turret/tu_ping.wav"; -} - -char* CBaseTurret::GetActiveSound() const -{ - return "turret/tu_active2.wav"; -} - -char* CBaseTurret::GetAlertSound() const -{ - return "turret/tu_alert.wav"; -} - -char* CBaseTurret::GetDeploySound() const -{ - return "turret/tu_deploy.wav"; -} - -void CBaseTurret::Precache( ) -{ - PRECACHE_SOUND ("turret/tu_fire1.wav"); - PRECACHE_SOUND (this->GetPingSound()); - PRECACHE_SOUND (this->GetActiveSound()); - PRECACHE_SOUND ("turret/tu_die.wav"); - PRECACHE_SOUND ("turret/tu_die2.wav"); - PRECACHE_SOUND ("turret/tu_die3.wav"); - PRECACHE_SOUND ("turret/tu_active2.wav"); - // PRECACHE_SOUND ("turret/tu_retract.wav"); // just use deploy sound to save memory - PRECACHE_SOUND (this->GetDeploySound()); - PRECACHE_SOUND ("turret/tu_spinup.wav"); - PRECACHE_SOUND ("turret/tu_spindown.wav"); - PRECACHE_SOUND (this->GetAlertSound()); -} - -#define TURRET_GLOW_SPRITE "sprites/flare3.spr" - -void CTurret::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/turret.mdl"); - pev->health = gSkillData.turretHealth; - m_HackedGunPos = Vector( (float)0, (float)0, (float)12.75 ); - m_flMaxSpin = TURRET_MAXSPIN; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - - SetThink(&CTurret::Initialize); - - m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetAttachment( edict(), 2 ); - m_eyeBrightness = 0; - - pev->nextthink = gpGlobals->time + 0.3; -} - -void CTurret::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/turret.mdl"); - PRECACHE_MODEL (TURRET_GLOW_SPRITE); -} - -void CMiniTurret::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/miniturret.mdl"); - pev->health = gSkillData.miniturretHealth; - m_HackedGunPos = Vector( (float)0, (float)0, (float)12.75 ); - m_flMaxSpin = 0; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetThink(&CMiniTurret::Initialize); - pev->nextthink = gpGlobals->time + 0.3; -} - - -void CMiniTurret::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/miniturret.mdl"); - PRECACHE_SOUND("weapons/hks1.wav"); - PRECACHE_SOUND("weapons/hks2.wav"); - PRECACHE_SOUND("weapons/hks3.wav"); -} - -void CBaseTurret::Initialize(void) -{ - m_iOn = 0; - m_fBeserk = 0; - m_iSpin = 0; - - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - - if (m_iBaseTurnRate == 0) - { - m_iBaseTurnRate = TURRET_TURNRATE; - } - if (m_flMaxWait == 0) - { - m_flMaxWait = TURRET_MAXWAIT; - } - - m_flStartYaw = pev->angles.y; - if (m_iOrientation == 1) - { - pev->idealpitch = 180; - pev->angles.x = 180; - pev->view_ofs.z = -pev->view_ofs.z; - pev->effects |= EF_INVLIGHT; - pev->angles.y = pev->angles.y + 180; - if (pev->angles.y > 360) - pev->angles.y = pev->angles.y - 360; - } - - m_vecGoalAngles.x = 0; - - if (m_iAutoStart) - { - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::AutoSearchThink); - pev->nextthink = gpGlobals->time + .1; - } - else - SetThink(&CBaseTurret::SUB_DoNothing); - - int a = 0; -} - -void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_iOn ) ) - return; - - if (m_iOn) - { - m_hEnemy = NULL; - pev->nextthink = gpGlobals->time + 0.1; - m_iAutoStart = FALSE;// switching off a turret disables autostart - //!!!! this should spin down first!!BUGBUG - SetThink(&CBaseTurret::Retire); - } - else - { - pev->nextthink = gpGlobals->time + 0.1; // turn on delay - - // if the turret is flagged as an autoactivate turret, re-enable it's ability open self. - if ( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - { - m_iAutoStart = TRUE; - } - - SetThink(&CBaseTurret::Deploy); - } -} - - -void CBaseTurret::Ping( void ) -{ - // make the pinging noise every second while searching - if (m_flPingTime == 0) - m_flPingTime = gpGlobals->time + kPingInterval; - else if (m_flPingTime <= gpGlobals->time) - { - m_flPingTime = gpGlobals->time + kPingInterval; - EMIT_SOUND(ENT(pev), CHAN_ITEM, this->GetPingSound(), kPingVolume, ATTN_STATIC); - EyeOn( ); - } - else if (m_eyeBrightness > 0) - { - EyeOff( ); - } -} - - -void CBaseTurret::EyeOn( ) -{ - if (m_pEyeGlow) - { - if (m_eyeBrightness != 255) - { - m_eyeBrightness = 255; - } - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } -} - - -void CBaseTurret::EyeOff( ) -{ - if (m_pEyeGlow) - { - if (m_eyeBrightness > 0) - { - m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } - } -} - -bool CBaseTurret::NeedsLineOfSight() const -{ - return true; -} - -void CBaseTurret::ActiveThink(void) -{ - int fAttack = 0; - Vector vecDirToEnemy; - - pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); - - if ((!m_iOn) || FNullEnt(m_hEnemy)) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - - // if it's dead, look for something new - if ( !m_hEnemy->IsAlive() ) - { - if (!m_flLastSight) - { - m_flLastSight = gpGlobals->time + 0.5; // continue-shooting timeout - } - else - { - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - } - - Vector vecMid = pev->origin + pev->view_ofs; - Vector vecMidEnemy = m_hEnemy->BodyTarget( vecMid ); - - // Look for our current enemy - bool theEnemyHasCloaking = false;//GetHasUpgrade(m_hEnemy->pev->iuser4, MASK_ALIEN_UPGRADE_10); - if(theEnemyHasCloaking) - { - int a = 0; - } - - int fEnemyVisible = FBoxVisible(pev, m_hEnemy->pev, vecMidEnemy) || !this->NeedsLineOfSight(); - - vecDirToEnemy = vecMidEnemy - vecMid; // calculate dir and dist to enemy - float flDistToEnemy = vecDirToEnemy.Length(); - - Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid); - - // Current enemy is not visible. - if (!fEnemyVisible || (flDistToEnemy > this->GetRange()) || theEnemyHasCloaking) - { - if (!m_flLastSight) - m_flLastSight = gpGlobals->time + 0.5; - else - { - // Should we look for a new target? - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - fEnemyVisible = 0; - } - else - { - m_vecLastSight = vecMidEnemy; - } - - UTIL_MakeAimVectors(m_vecCurAngles); - - /* - ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n", - m_vecCurAngles.x, m_vecCurAngles.y, - gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_forward.z ); - */ - - Vector vecLOS = vecDirToEnemy; //vecMid - m_vecLastSight; - vecLOS = vecLOS.Normalize(); - - // Is the Gun looking at the target - if (DotProduct(vecLOS, gpGlobals->v_forward) <= 0.866) // 30 degree slop - fAttack = FALSE; - else - fAttack = TRUE; - - // fire the gun - if (m_iSpin && ((fAttack) || (m_fBeserk))) - { - Vector vecSrc, vecAng; - GetAttachment( 0, vecSrc, vecAng ); - SetTurretAnim(TURRET_ANIM_FIRE); - Shoot(vecSrc, gpGlobals->v_forward ); - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - this->StopShooting(); - } - - //move the gun - if (m_fBeserk) - { - if (RANDOM_LONG(0,9) == 0) - { - m_vecGoalAngles.y = RANDOM_FLOAT(0,360); - m_vecGoalAngles.x = RANDOM_FLOAT(0,90) - 90 * m_iOrientation; - TakeDamage(pev,pev,1, DMG_GENERIC); // don't beserk forever - return; - } - } - else if (fEnemyVisible) - { - if (vec.y > 360) - vec.y -= 360; - - if (vec.y < 0) - vec.y += 360; - - //ALERT(at_console, "[%.2f]", vec.x); - - if (vec.x < -180) - vec.x += 360; - - if (vec.x > 180) - vec.x -= 360; - - // now all numbers should be in [1...360] - // pin to turret limitations to [-90...15] - - if (m_iOrientation == 0) - { - if (vec.x > 90) - vec.x = 90; - else if (vec.x < m_iMinPitch) - vec.x = m_iMinPitch; - } - else - { - if (vec.x < -90) - vec.x = -90; - else if (vec.x > -m_iMinPitch) - vec.x = -m_iMinPitch; - } - - // ALERT(at_console, "->[%.2f]\n", vec.x); - - m_vecGoalAngles.y = vec.y; - m_vecGoalAngles.x = vec.x; - - } - - SpinUpCall(); - MoveTurret(); -} - - -void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_12MM, 1 ); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6); - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - - -void CMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_9MM, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - - -void CBaseTurret::Deploy(void) -{ - pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); - - if (pev->sequence != TURRET_ANIM_DEPLOY) - { - m_iOn = 1; - SetTurretAnim(TURRET_ANIM_DEPLOY); - EMIT_SOUND(ENT(pev), CHAN_BODY, this->GetDeploySound(), TURRET_MACHINE_VOLUME, ATTN_NORM); - SUB_UseTargets( this, USE_ON, 0 ); - } - - if (m_fSequenceFinished) - { - pev->maxs.z = m_iDeployHeight; - pev->mins.z = -m_iDeployHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - - m_vecCurAngles.x = 0; - - if (m_iOrientation == 1) - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); - } - else - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); - } - - SetTurretAnim(TURRET_ANIM_SPIN); - pev->framerate = 0; - SetThink(&CBaseTurret::SearchThink); - } - - m_flLastSight = gpGlobals->time + m_flMaxWait; -} - -void CBaseTurret::Retire(void) -{ - // make the turret level - m_vecGoalAngles.x = 0; - m_vecGoalAngles.y = m_flStartYaw; - - pev->nextthink = gpGlobals->time + 0.1; - - StudioFrameAdvance( ); - - EyeOff( ); - - if (!MoveTurret()) - { - if (m_iSpin) - { - SpinDownCall(); - } - else if (pev->sequence != TURRET_ANIM_RETIRE) - { - SetTurretAnim(TURRET_ANIM_RETIRE); - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, this->GetDeploySound(), TURRET_MACHINE_VOLUME, ATTN_NORM, 0, 120); - SUB_UseTargets( this, USE_OFF, 0 ); - } - else if (m_fSequenceFinished) - { - m_iOn = 0; - m_flLastSight = 0; - SetTurretAnim(TURRET_ANIM_NONE); - pev->maxs.z = m_iRetractHeight; - pev->mins.z = -m_iRetractHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - if (m_iAutoStart) - { - SetThink(&CBaseTurret::AutoSearchThink); - pev->nextthink = gpGlobals->time + .1; - } - else - SetThink(&CBaseTurret::SUB_DoNothing); - } - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - } -} - - -void CTurret::SpinUpCall(void) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - // Are we already spun up? If not start the two stage process. - if (!m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - // for the first pass, spin up the the barrel - if (!m_iStartSpin) - { - pev->nextthink = gpGlobals->time + 1.0; // spinup delay - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_spinup.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - m_iStartSpin = 1; - pev->framerate = 0.1; - } - // after the barrel is spun up, turn on the hum - else if (pev->framerate >= 1.0) - { - pev->nextthink = gpGlobals->time + 0.1; // retarget delay - EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SetThink(&CTurret::ActiveThink); - m_iStartSpin = 0; - m_iSpin = 1; - } - else - { - pev->framerate += 0.075; - } - } - - if (m_iSpin) - { - SetThink(&CTurret::ActiveThink); - } -} - - -void CTurret::SpinDownCall(void) -{ - if (m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - if (pev->framerate == 1.0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - EMIT_SOUND(ENT(pev), CHAN_ITEM, "turret/tu_spindown.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } - pev->framerate -= 0.02; - if (pev->framerate <= 0) - { - pev->framerate = 0; - m_iSpin = 0; - } - } -} - - -void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) -{ - if (pev->sequence != anim) - { - switch(anim) - { - case TURRET_ANIM_FIRE: - case TURRET_ANIM_SPIN: - if (pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN) - { - pev->frame = 0; - } - break; - default: - pev->frame = 0; - break; - } - - pev->sequence = anim; - ResetSequenceInfo( ); - - switch(anim) - { - case TURRET_ANIM_RETIRE: - pev->frame = 255; - pev->framerate = -1.0; - break; - case TURRET_ANIM_DIE: - pev->framerate = 1.0; - break; - } - //ALERT(at_console, "Turret anim #%d\n", anim); - } -} - - -// -// This search function will sit with the turret deployed and look for a new target. -// After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will -// retact. -// -void CBaseTurret::SearchThink(void) -{ - // ensure rethink - SetTurretAnim(TURRET_ANIM_SPIN); - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (m_flSpinUpTime == 0 && m_flMaxSpin) - m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; - - Ping( ); - - // If we have a target and we're still healthy - if (m_hEnemy != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - - // Acquire Target - if (m_hEnemy == NULL) - { - Look(this->GetRange()); - m_hEnemy = BestVisibleEnemy(); - } - - // If we've found a target, spin up the barrel and start to attack - if (m_hEnemy != NULL) - { - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::ActiveThink); - } - else - { - // Are we out of time, do we need to retract? - if (gpGlobals->time > m_flLastSight) - { - //Before we retrace, make sure that we are spun down. - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::Retire); - } - // should we stop the spin? - else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) - { - SpinDownCall(); - } - - // generic hunt for new victims - m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate); - if (m_vecGoalAngles.y >= 360) - m_vecGoalAngles.y -= 360; - MoveTurret(); - } -} - -int CBaseTurret::GetRange() const -{ - return TURRET_RANGE; -} - -// -// This think function will deploy the turret when something comes into range. This is for -// automatically activated turrets. -// -void CBaseTurret::AutoSearchThink(void) -{ - // ensure rethink - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.3; - - // If we have a target and we're still healthy - - if (m_hEnemy != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - // Acquire Target - - if (m_hEnemy == NULL) - { - Look( this->GetRange() ); - m_hEnemy = BestVisibleEnemy(); - } - - if (m_hEnemy != NULL) - { - SetThink(&CBaseTurret::Deploy); - EMIT_SOUND(ENT(pev), CHAN_BODY, this->GetAlertSound(), TURRET_MACHINE_VOLUME, ATTN_NORM); - } -} - - -void CBaseTurret :: TurretDeath( void ) -{ - BOOL iActive = FALSE; - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->deadflag != DEAD_DEAD) - { - pev->deadflag = DEAD_DEAD; - - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - - if (m_iOrientation == 0) - m_vecGoalAngles.x = -15; - else - m_vecGoalAngles.x = -90; - - SetTurretAnim(TURRET_ANIM_DIE); - - EyeOn( ); - } - - EyeOff( ); - - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) - { - // lots of smoke - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ) ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ) ); - WRITE_COORD( pev->origin.z - m_iOrientation * 64 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 25 ); // scale * 10 - WRITE_BYTE( 10 - m_iOrientation * 5); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 5 ) > gpGlobals->time) - { - Vector vecSrc = Vector( (float)RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ), (float)RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ), (float)0 ); - if (m_iOrientation == 0) - vecSrc = vecSrc + Vector( (float)0, (float)0, (float)RANDOM_FLOAT( pev->origin.z, pev->absmax.z ) ); - else - vecSrc = vecSrc + Vector( (float)0, (float)0, (float)RANDOM_FLOAT( pev->absmin.z, pev->origin.z ) ); - - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - - - -void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( ptr->iHitgroup == 10 ) - { - // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - - if ( !pev->takedamage ) - return; - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -// take damage. bitsDamageType indicates type of damage sustained, ie: DMG_BULLET - -int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - - if (!m_iOn) - flDamage /= 10.0; - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CBaseTurret::TurretDeath); - SUB_UseTargets( this, USE_ON, 0 ); // wake up others - pev->nextthink = gpGlobals->time + 0.1; - - return 0; - } - - if (pev->health <= 10) - { - if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) - { - m_fBeserk = 1; - SetThink(&CBaseTurret::SearchThink); - } - } - - return 1; -} - -int CBaseTurret::MoveTurret(void) -{ - ASSERT(this->m_iBaseTurnRate > 0); - ASSERT(this->m_fTurnRate > 0); - - int state = 0; - // any x movement? - - if (m_vecCurAngles.x != m_vecGoalAngles.x) - { - float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; - - m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir; - - // if we started below the goal, and now we're past, peg to goal - if (flDir == 1) - { - if (m_vecCurAngles.x > m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - else - { - if (m_vecCurAngles.x < m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - - if (m_iOrientation == 0) - SetBoneController(1, -m_vecCurAngles.x); - else - SetBoneController(1, m_vecCurAngles.x); - state = 1; - } - - if (m_vecCurAngles.y != m_vecGoalAngles.y) - { - float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; - float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); - - if (flDist > 180) - { - flDist = 360 - flDist; - flDir = -flDir; - } - if (flDist > 30) - { - if (m_fTurnRate < m_iBaseTurnRate * 10) - { - m_fTurnRate += m_iBaseTurnRate; - } - } - else if (m_fTurnRate > 45) - { - m_fTurnRate -= m_iBaseTurnRate; - } - else - { - m_fTurnRate += m_iBaseTurnRate; - } - - m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; - - if (m_vecCurAngles.y < 0) - m_vecCurAngles.y += 360; - else if (m_vecCurAngles.y >= 360) - m_vecCurAngles.y -= 360; - - if (flDist < (0.05 * m_iBaseTurnRate)) - m_vecCurAngles.y = m_vecGoalAngles.y; - - //ALERT(at_console, "%.2f -> %.2f\n", m_vecCurAngles.y, y); - if (m_iOrientation == 0) - SetBoneController(0, m_vecCurAngles.y - pev->angles.y ); - else - SetBoneController(0, pev->angles.y - 180 - m_vecCurAngles.y ); - state = 1; - } - - if (!state) - m_fTurnRate = m_iBaseTurnRate; - - //ALERT(at_console, "(%.2f, %.2f)->(%.2f, %.2f)\n", m_vecCurAngles.x, - // m_vecCurAngles.y, m_vecGoalAngles.x, m_vecGoalAngles.y); - return state; -} - -// -// ID as a machine -// -int CBaseTurret::Classify ( void ) -{ - if (m_iOn || m_iAutoStart) - return CLASS_MACHINE; - return CLASS_NONE; -} - - - - -LINK_ENTITY_TO_CLASS( monster_sentry, CSentry ); - -void CSentry::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL (kDeployedTurretModel); -} - -void CSentry::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), kDeployedTurretModel); - pev->health = gSkillData.sentryHealth; - m_HackedGunPos = Vector( 0, 0, 48 ); - pev->view_ofs.z = 48; - m_flMaxWait = TURRET_MAXWAIT; - m_flMaxSpin = TURRET_MAXSPIN; - - CBaseTurret::Spawn(); - m_iRetractHeight = 64; - m_iDeployHeight = 64; - m_iMinPitch = -60; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetTouch(&CSentry::SentryTouch); - SetThink(&CSentry::Initialize); - pev->nextthink = gpGlobals->time + 0.3; -} - -void CSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, this->GetRange(), BULLET_MONSTER_MP5, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - -int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - -// if (!m_iOn) -// { -// SetThink( Deploy ); -// SetUse( NULL ); -// pev->nextthink = gpGlobals->time + 0.1; -// } - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CSentry::SentryDeath); - SUB_UseTargets( this, USE_ON, 0 ); // wake up others - pev->nextthink = gpGlobals->time + 0.1; - - return 0; - } - - return 1; -} - - -void CSentry::SentryTouch( CBaseEntity *pOther ) -{ - if ( pOther && (pOther->IsPlayer() || (pOther->pev->flags & FL_MONSTER)) ) - { - TakeDamage(pOther->pev, pOther->pev, 0, 0 ); - } -} - - -void CSentry :: SentryDeath( void ) -{ - BOOL iActive = FALSE; - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->deadflag != DEAD_DEAD) - { - pev->deadflag = DEAD_DEAD; - - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - - SetTurretAnim(TURRET_ANIM_DIE); - - pev->solid = SOLID_NOT; - pev->angles.y = UTIL_AngleMod( pev->angles.y + RANDOM_LONG( 0, 2 ) * 120 ); - - EyeOn( ); - } - - EyeOff( ); - - Vector vecSrc, vecAng; - GetAttachment( 1, vecSrc, vecAng ); - - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) - { - // lots of smoke - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x + RANDOM_FLOAT( -16, 16 ) ); - WRITE_COORD( vecSrc.y + RANDOM_FLOAT( -16, 16 ) ); - WRITE_COORD( vecSrc.z - 32 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 15 ); // scale * 10 - WRITE_BYTE( 8 ); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) - { - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - diff --git a/main/source/dlls/turret.h b/main/source/dlls/turret.h index 205aa102..43b82ebe 100644 --- a/main/source/dlls/turret.h +++ b/main/source/dlls/turret.h @@ -1,149 +1,149 @@ -#ifndef TURRET_H -#define TURRET_H - -#include "effects.h" -#include "turretconst.h" - -class CBaseTurret : public CBaseMonster -{ -public: - void Spawn(void); - virtual void Precache(void); - void KeyValue( KeyValueData *pkvd ); - void EXPORT TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int Classify(void); - virtual int GetRange() const; - - virtual char* GetPingSound() const; - virtual char* GetActiveSound() const; - virtual char* GetAlertSound() const; - virtual char* GetDeploySound() const; - - int BloodColor( void ) { return DONT_BLEED; } - void GibMonster( void ) {} // UNDONE: Throw turret gibs? - virtual void StopShooting() {}; - virtual bool NeedsLineOfSight() const; - - // Think functions - - void EXPORT ActiveThink(void); - void EXPORT SearchThink(void); - void EXPORT AutoSearchThink(void); - void EXPORT TurretDeath(void); - - virtual void EXPORT SpinDownCall(void) { m_iSpin = 0; } - virtual void EXPORT SpinUpCall(void) { m_iSpin = 1; } - - // void SpinDown(void); - // float EXPORT SpinDownCall( void ) { return SpinDown(); } - - // virtual float SpinDown(void) { return 0;} - // virtual float Retire(void) { return 0;} - - void EXPORT Deploy(void); - void EXPORT Retire(void); - - void EXPORT Initialize(void); - - virtual void Ping(void); - virtual void EyeOn(void); - virtual void EyeOff(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // other functions - void SetTurretAnim(TURRET_ANIM anim); - int MoveTurret(void); - virtual void Shoot(Vector &vecSrc, Vector &vecDirToEnemy) { }; - - float m_flMaxSpin; // Max time to spin the barrel w/o a target - int m_iSpin; - - CSprite *m_pEyeGlow; - int m_eyeBrightness; - - int m_iDeployHeight; - int m_iRetractHeight; - int m_iMinPitch; - - int m_iBaseTurnRate; // angles per second - float m_fTurnRate; // actual turn rate - int m_iOrientation; // 0 = floor, 1 = Ceiling - int m_iOn; - int m_fBeserk; // Sometimes this bitch will just freak out - int m_iAutoStart; // true if the turret auto deploys when a target - // enters its range - - Vector m_vecLastSight; - float m_flLastSight; // Last time we saw a target - float m_flMaxWait; // Max time to seach w/o a target - int m_iSearchSpeed; // Not Used! - - // movement - float m_flStartYaw; - Vector m_vecCurAngles; - Vector m_vecGoalAngles; - - - float m_flPingTime; // Time until the next ping, used when searching - float m_flSpinUpTime; // Amount of time until the barrel should spin down when searching -}; - -class CTurret : public CBaseTurret -{ -public: - void Spawn(void); - void Precache(void); - // Think functions - void SpinUpCall(void); - void SpinDownCall(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); - -private: - int m_iStartSpin; - -}; - - -class CMiniTurret : public CBaseTurret -{ -public: - void Spawn( ); - void Precache(void); - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); -}; - - -//========================================================= -// Sentry gun - smallest turret, placed near grunt entrenchments -//========================================================= -class CSentry : public CBaseTurret -{ -public: - void Spawn( ); - void Precache(void); - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); - int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - void EXPORT SentryTouch( CBaseEntity *pOther ); - void EXPORT SentryDeath( void ); - -}; - - - +#ifndef TURRET_H +#define TURRET_H + +#include "effects.h" +#include "turretconst.h" + +class CBaseTurret : public CBaseMonster +{ +public: + void Spawn(void); + virtual void Precache(void); + void KeyValue( KeyValueData *pkvd ); + void EXPORT TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + virtual int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + virtual int Classify(void); + virtual int GetRange() const; + + virtual char* GetPingSound() const; + virtual char* GetActiveSound() const; + virtual char* GetAlertSound() const; + virtual char* GetDeploySound() const; + + int BloodColor( void ) { return DONT_BLEED; } + void GibMonster( void ) {} // UNDONE: Throw turret gibs? + virtual void StopShooting() {}; + virtual bool NeedsLineOfSight() const; + + // Think functions + + void EXPORT ActiveThink(void); + void EXPORT SearchThink(void); + void EXPORT AutoSearchThink(void); + void EXPORT TurretDeath(void); + + virtual void EXPORT SpinDownCall(void) { m_iSpin = 0; } + virtual void EXPORT SpinUpCall(void) { m_iSpin = 1; } + + // void SpinDown(void); + // float EXPORT SpinDownCall( void ) { return SpinDown(); } + + // virtual float SpinDown(void) { return 0;} + // virtual float Retire(void) { return 0;} + + void EXPORT Deploy(void); + void EXPORT Retire(void); + + void EXPORT Initialize(void); + + virtual void Ping(void); + virtual void EyeOn(void); + virtual void EyeOff(void); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + // other functions + void SetTurretAnim(TURRET_ANIM anim); + int MoveTurret(void); + virtual void Shoot(Vector &vecSrc, Vector &vecDirToEnemy) { }; + + float m_flMaxSpin; // Max time to spin the barrel w/o a target + int m_iSpin; + + CSprite *m_pEyeGlow; + int m_eyeBrightness; + + int m_iDeployHeight; + int m_iRetractHeight; + int m_iMinPitch; + + int m_iBaseTurnRate; // angles per second + float m_fTurnRate; // actual turn rate + int m_iOrientation; // 0 = floor, 1 = Ceiling + int m_iOn; + int m_fBeserk; // Sometimes this bitch will just freak out + int m_iAutoStart; // true if the turret auto deploys when a target + // enters its range + + Vector m_vecLastSight; + float m_flLastSight; // Last time we saw a target + float m_flMaxWait; // Max time to seach w/o a target + int m_iSearchSpeed; // Not Used! + + // movement + float m_flStartYaw; + Vector m_vecCurAngles; + Vector m_vecGoalAngles; + + + float m_flPingTime; // Time until the next ping, used when searching + float m_flSpinUpTime; // Amount of time until the barrel should spin down when searching +}; + +class CTurret : public CBaseTurret +{ +public: + void Spawn(void); + void Precache(void); + // Think functions + void SpinUpCall(void); + void SpinDownCall(void); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + // other functions + void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); + +private: + int m_iStartSpin; + +}; + + +class CMiniTurret : public CBaseTurret +{ +public: + void Spawn( ); + void Precache(void); + // other functions + void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); +}; + + +//========================================================= +// Sentry gun - smallest turret, placed near grunt entrenchments +//========================================================= +class CSentry : public CBaseTurret +{ +public: + void Spawn( ); + void Precache(void); + // other functions + void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); + int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); + void EXPORT SentryTouch( CBaseEntity *pOther ); + void EXPORT SentryDeath( void ); + +}; + + + #endif \ No newline at end of file diff --git a/main/source/dlls/turret.h~ b/main/source/dlls/turret.h~ deleted file mode 100644 index 9ee8195d..00000000 --- a/main/source/dlls/turret.h~ +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef TURRET_H -#define TURRET_H - -#include "effects.h" -#include "dlls/turretconst.h" - -class CBaseTurret : public CBaseMonster -{ -public: - void Spawn(void); - virtual void Precache(void); - void KeyValue( KeyValueData *pkvd ); - void EXPORT TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int Classify(void); - virtual int GetRange() const; - - virtual char* GetPingSound() const; - virtual char* GetActiveSound() const; - virtual char* GetAlertSound() const; - virtual char* GetDeploySound() const; - - int BloodColor( void ) { return DONT_BLEED; } - void GibMonster( void ) {} // UNDONE: Throw turret gibs? - virtual void StopShooting() {}; - virtual bool NeedsLineOfSight() const; - - // Think functions - - void EXPORT ActiveThink(void); - void EXPORT SearchThink(void); - void EXPORT AutoSearchThink(void); - void EXPORT TurretDeath(void); - - virtual void EXPORT SpinDownCall(void) { m_iSpin = 0; } - virtual void EXPORT SpinUpCall(void) { m_iSpin = 1; } - - // void SpinDown(void); - // float EXPORT SpinDownCall( void ) { return SpinDown(); } - - // virtual float SpinDown(void) { return 0;} - // virtual float Retire(void) { return 0;} - - void EXPORT Deploy(void); - void EXPORT Retire(void); - - void EXPORT Initialize(void); - - virtual void Ping(void); - virtual void EyeOn(void); - virtual void EyeOff(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // other functions - void SetTurretAnim(TURRET_ANIM anim); - int MoveTurret(void); - virtual void Shoot(Vector &vecSrc, Vector &vecDirToEnemy) { }; - - float m_flMaxSpin; // Max time to spin the barrel w/o a target - int m_iSpin; - - CSprite *m_pEyeGlow; - int m_eyeBrightness; - - int m_iDeployHeight; - int m_iRetractHeight; - int m_iMinPitch; - - int m_iBaseTurnRate; // angles per second - float m_fTurnRate; // actual turn rate - int m_iOrientation; // 0 = floor, 1 = Ceiling - int m_iOn; - int m_fBeserk; // Sometimes this bitch will just freak out - int m_iAutoStart; // true if the turret auto deploys when a target - // enters its range - - Vector m_vecLastSight; - float m_flLastSight; // Last time we saw a target - float m_flMaxWait; // Max time to seach w/o a target - int m_iSearchSpeed; // Not Used! - - // movement - float m_flStartYaw; - Vector m_vecCurAngles; - Vector m_vecGoalAngles; - - - float m_flPingTime; // Time until the next ping, used when searching - float m_flSpinUpTime; // Amount of time until the barrel should spin down when searching -}; - -class CTurret : public CBaseTurret -{ -public: - void Spawn(void); - void Precache(void); - // Think functions - void SpinUpCall(void); - void SpinDownCall(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); - -private: - int m_iStartSpin; - -}; - - -class CMiniTurret : public CBaseTurret -{ -public: - void Spawn( ); - void Precache(void); - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); -}; - - -//========================================================= -// Sentry gun - smallest turret, placed near grunt entrenchments -//========================================================= -class CSentry : public CBaseTurret -{ -public: - void Spawn( ); - void Precache(void); - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); - int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - void EXPORT SentryTouch( CBaseEntity *pOther ); - void EXPORT SentryDeath( void ); - -}; - - - -#endif \ No newline at end of file diff --git a/main/source/dlls/turretconst.h b/main/source/dlls/turretconst.h index 204c05d8..8596ba67 100644 --- a/main/source/dlls/turretconst.h +++ b/main/source/dlls/turretconst.h @@ -1,25 +1,25 @@ -#ifndef TURRET_CONST_H -#define TURRET_CONST_H - -#define TURRET_SHOTS 2 -#define TURRET_RANGE (100 * 12) -#define TURRET_SPREAD Vector( 0, 0, 0 ) -#define TURRET_TURNRATE 30 //angles per 0.1 second -#define TURRET_MAXWAIT 15 // seconds turret will stay active w/o a target -#define TURRET_MAXSPIN 5 // seconds turret barrel will spin w/o a target -#define TURRET_MACHINE_VOLUME 0.5 - -typedef enum -{ - TURRET_ANIM_NONE = 0, - TURRET_ANIM_FIRE, - TURRET_ANIM_SPIN, - TURRET_ANIM_DEPLOY, - TURRET_ANIM_RETIRE, - TURRET_ANIM_DIE, -} TURRET_ANIM; - -#define SF_MONSTER_TURRET_AUTOACTIVATE 32 -#define SF_MONSTER_TURRET_STARTINACTIVE 64 - +#ifndef TURRET_CONST_H +#define TURRET_CONST_H + +#define TURRET_SHOTS 2 +#define TURRET_RANGE (100 * 12) +#define TURRET_SPREAD Vector( 0, 0, 0 ) +#define TURRET_TURNRATE 30 //angles per 0.1 second +#define TURRET_MAXWAIT 15 // seconds turret will stay active w/o a target +#define TURRET_MAXSPIN 5 // seconds turret barrel will spin w/o a target +#define TURRET_MACHINE_VOLUME 0.5 + +typedef enum +{ + TURRET_ANIM_NONE = 0, + TURRET_ANIM_FIRE, + TURRET_ANIM_SPIN, + TURRET_ANIM_DEPLOY, + TURRET_ANIM_RETIRE, + TURRET_ANIM_DIE, +} TURRET_ANIM; + +#define SF_MONSTER_TURRET_AUTOACTIVATE 32 +#define SF_MONSTER_TURRET_STARTINACTIVE 64 + #endif \ No newline at end of file diff --git a/main/source/dlls/util.cpp b/main/source/dlls/util.cpp index 00726bf6..5ba9977e 100644 --- a/main/source/dlls/util.cpp +++ b/main/source/dlls/util.cpp @@ -1,2617 +1,2617 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== util.cpp ======================================================== - - Utility code. Really not optional after all. - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include -#include "../engine/shake.h" -#include "decals.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "../mod/AvHServerUtil.h" -#include "../mod/AvHNetworkMessages.h" -#include "../mod/AvHServerVariables.h" -//#include "../mod/AvHSharedUtil.h" -//#include "../mod/AvHGamerules.h" - -float UTIL_WeaponTimeBase( void ) -{ - return 0.0; -} - -static unsigned int glSeed = 0; - -unsigned int seed_table[ 256 ] = -{ - 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, - 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, - 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, - 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, - 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, - 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, - 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, - 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, - 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, - 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, - 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, - 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, - 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, - 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, - 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, - 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 -}; - -unsigned int U_Random( void ) -{ - glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - - return ( ++glSeed & 0x0fffffff ); -} - -void U_Srand( unsigned int seed ) -{ - glSeed = seed_table[ seed & 0xff ]; -} - -/* -===================== -UTIL_SharedRandomLong -===================== -*/ -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) -{ - unsigned int range; - - U_Srand( (int)seed + low + high ); - - range = high - low + 1; - if ( !(range - 1) ) - { - return low; - } - else - { - int offset; - int rnum; - - rnum = U_Random(); - - offset = rnum % range; - - return (low + offset); - } -} - -/* -===================== -UTIL_SharedRandomFloat -===================== -*/ -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) -{ - U_Srand( (int)seed + *(int *)&low + *(int *)&high ); - - U_Random(); - U_Random(); - - float range = high - low; - if ( !range ) - { - return low; - } - else - { - int tensixrand; - float offset; - - tensixrand = U_Random() & 65535; - - offset = (float)tensixrand / 65536.0; - - return (low + offset * range ); - } -} - -void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner ) -{ - pev->startpos = vecOrigin; - // Trace out line to end pos - TraceResult tr; - UTIL_MakeVectors( vecAngles ); - UTIL_TraceLine( pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr); - pev->endpos = tr.vecEndPos; - - // Now compute how long it will take based on current velocity - Vector vecTravel = pev->endpos - pev->startpos; - float travelTime = 0.0; - if ( pev->velocity.Length() > 0 ) - { - travelTime = vecTravel.Length() / pev->velocity.Length(); - } - pev->starttime = gpGlobals->time; - pev->impacttime = gpGlobals->time + travelTime; -} - -int g_groupmask = 0; -int g_groupop = 0; - -// Normal overrides -void UTIL_SetGroupTrace( int groupmask, int op ) -{ - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -void UTIL_UnsetGroupTrace( void ) -{ - g_groupmask = 0; - g_groupop = 0; - - ENGINE_SETGROUPMASK( 0, 0 ); -} - -// Smart version, it'll clean itself up when it pops off stack -UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op ) -{ - m_oldgroupmask = g_groupmask; - m_oldgroupop = g_groupop; - - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -UTIL_GroupTrace::~UTIL_GroupTrace( void ) -{ - g_groupmask = m_oldgroupmask; - g_groupop = m_oldgroupop; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -TYPEDESCRIPTION gEntvarsDescription[] = -{ - DEFINE_ENTITY_FIELD( classname, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), - DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ), - - DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ), - DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ), - - // Having these fields be local to the individual levels makes it easier to test those levels individually. - DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( netname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( message, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ), -}; - -#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0])) - - -#ifdef DEBUG -edict_t *DBG_EntOfVars( const entvars_t *pev ) -{ - if (pev->pContainingEntity != NULL) - return pev->pContainingEntity; - ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); - edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); - if (pent == NULL) - ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); - ((entvars_t *)pev)->pContainingEntity = pent; - return pent; -} -#endif //DEBUG - - -//#ifdef DEBUG -// void -//DBG_AssertFunction( -// BOOL fExpr, -// const char* szExpr, -// const char* szFile, -// int szLine, -// const char* szMessage) -// { -// if (fExpr) -// return; -// char szOut[512]; -// if (szMessage != NULL) -// sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage); -// else -// sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine); -// ALERT(at_console, szOut); -// } -//#endif // DEBUG - -BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon ); -} - -// ripped this out of the engine -float UTIL_AngleMod(float a) -{ - if (a < 0) - { - a = a + 360 * ((int)(a / 360) + 1); - } - else if (a >= 360) - { - a = a - 360 * ((int)(a / 360)); - } - // a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); - return a; -} - -float UTIL_AngleDiff( float destAngle, float srcAngle ) -{ - float delta; - - delta = destAngle - srcAngle; - if ( destAngle > srcAngle ) - { - if ( delta >= 180 ) - delta -= 360; - } - else - { - if ( delta <= -180 ) - delta += 360; - } - return delta; -} - -Vector UTIL_VecToAngles( const Vector &vec ) -{ - float rgflVecOut[3]; - VEC_TO_ANGLES(vec, rgflVecOut); - return Vector(rgflVecOut); -} - -// float UTIL_MoveToOrigin( edict_t *pent, const Vector vecGoal, float flDist, int iMoveType ) -void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType ) -{ - float rgfl[3]; - vecGoal.CopyToArray(rgfl); -// return MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); - MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); -} - - -int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - - count = 0; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? - continue; - - if ( mins.x > pEdict->v.absmax.x || - mins.y > pEdict->v.absmax.y || - mins.z > pEdict->v.absmax.z || - maxs.x < pEdict->v.absmin.x || - maxs.y < pEdict->v.absmin.y || - maxs.z < pEdict->v.absmin.z ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - return count; -} - - -int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - float distance, delta; - - count = 0; - float radiusSquared = radius * radius; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? - continue; - - // Use origin for X & Y since they are centered for all monsters - // Now X - delta = center.x - pEdict->v.origin.x;//(pEdict->v.absmin.x + pEdict->v.absmax.x)*0.5; - delta *= delta; - - if ( delta > radiusSquared ) - continue; - distance = delta; - - // Now Y - delta = center.y - pEdict->v.origin.y;//(pEdict->v.absmin.y + pEdict->v.absmax.y)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - // Now Z - delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - - return count; -} - - -CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -int UTIL_CountEntitiesInSphere(const Vector& inVecCenter, float inRadius, const char* inClassName) -{ - int theNumEntities = 0; - - CBaseEntity* theEntity = NULL; - while((theEntity = UTIL_FindEntityInSphere(theEntity, inVecCenter, inRadius)) != NULL) - { - if(!strcmp(STRING(theEntity->pev->classname), inClassName)) - { - theNumEntities++; - } - } - - return theNumEntities; -} - - -CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue ); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -CBaseEntity *UTIL_FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "classname", szName ); -} - -CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "targetname", szName ); -} - - -CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius ) -{ - CBaseEntity *pEntity = NULL; - - pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever ); - if (pEntity) - return pEntity; - - CBaseEntity *pSearch = NULL; - float flMaxDist2 = flRadius * flRadius; - while ((pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever )) != NULL) - { - float flDist2 = (pSearch->pev->origin - vecSrc).Length(); - flDist2 = flDist2 * flDist2; - if (flMaxDist2 > flDist2) - { - pEntity = pSearch; - flMaxDist2 = flDist2; - } - } - return pEntity; -} - - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) -{ - CBaseEntity *pPlayer = NULL; - - if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) - { - edict_t *pPlayerEdict = INDEXENT( playerIndex ); - if ( pPlayerEdict && !pPlayerEdict->free ) - { - pPlayer = CBaseEntity::Instance( pPlayerEdict ); - } - } - - return pPlayer; -} - - -void UTIL_MakeVectors( const Vector &vecAngles ) -{ - MAKE_VECTORS( vecAngles ); -} - - -void UTIL_MakeAimVectors( const Vector &vecAngles ) -{ - float rgflVec[3]; - vecAngles.CopyToArray(rgflVec); - rgflVec[0] = -rgflVec[0]; - MAKE_VECTORS(rgflVec); -} - - -#define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) - -void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) -{ - MAKE_VECTORS(vec); - - float tmp; - pgv->v_right = pgv->v_right * -1; - - SWAP(pgv->v_forward.y, pgv->v_right.x, tmp); - SWAP(pgv->v_forward.z, pgv->v_up.x, tmp); - SWAP(pgv->v_right.z, pgv->v_up.y, tmp); -} - - -void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ) -{ - float rgfl[3]; - vecOrigin.CopyToArray(rgfl); - - if (samp && *samp == '!') - { - char name[32]; - if (SENTENCEG_Lookup(samp, name) >= 0) - EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); - } - else - EMIT_AMBIENT_SOUND(entity, rgfl, samp, vol, attenuation, fFlags, pitch); -} - -static unsigned short FixedUnsigned16( float value, float scale ) -{ - int output; - - output = value * scale; - if ( output < 0 ) - output = 0; - if ( output > 0xFFFF ) - output = 0xFFFF; - - return (unsigned short)output; -} - -static short FixedSigned16( float value, float scale ) -{ - int output; - - output = value * scale; - - if ( output > 32767 ) - output = 32767; - - if ( output < -32768 ) - output = -32768; - - return (short)output; -} - -// Shake the screen of all clients within radius -// radius == 0, shake all clients -// UNDONE: Allow caller to shake clients not ONGROUND? -// UNDONE: Fix falloff model (disabled)? -// UNDONE: Affect user controls? -void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ) -{ - int i; - float localAmplitude; - ScreenShake shake; - - shake.duration = FixedUnsigned16( duration, 1<<12 ); // 4.12 fixed - shake.frequency = FixedUnsigned16( frequency, 1<<8 ); // 8.8 fixed - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( !pPlayer /*|| !(pPlayer->pev->flags & FL_ONGROUND)*/ ) // Don't shake if not onground - continue; - - localAmplitude = 0; - - if ( radius <= 0 ) - localAmplitude = amplitude; - else - { - Vector delta = center - pPlayer->pev->origin; - float distance = delta.Length(); - - // Had to get rid of this falloff - it didn't work well - if ( distance < radius ) - localAmplitude = amplitude;//radius - distance; - } - if ( localAmplitude ) - { - shake.amplitude = FixedUnsigned16( localAmplitude, 1<<12 ); // 4.12 fixed - - NetMsg_Shake( pPlayer->pev, shake ); - } - } -} - - - -void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency, float duration ) -{ - UTIL_ScreenShake( center, amplitude, frequency, duration, 0 ); -} - - -void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - fade.duration = FixedUnsigned16( fadeTime, 1<<12 ); // 4.12 fixed - fade.holdTime = FixedUnsigned16( fadeHold, 1<<12 ); // 4.12 fixed - fade.r = (int)color.x; - fade.g = (int)color.y; - fade.b = (int)color.z; - fade.a = alpha; - fade.fadeFlags = flags; -} - - -void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - NetMsg_Fade( pEntity->pev, fade ); -} - - -void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - int i; - ScreenFade fade; - - - UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - UTIL_ScreenFadeWrite( fade, pPlayer ); - } -} - - -void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - ScreenFade fade; - - UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - UTIL_ScreenFadeWrite( fade, pEntity ); -} - - -void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pEntity->edict() ); - WRITE_BYTE( TE_TEXTMESSAGE ); - WRITE_BYTE( textparms.channel & 0xFF ); - - WRITE_SHORT( FixedSigned16( textparms.x, 1<<13 ) ); - WRITE_SHORT( FixedSigned16( textparms.y, 1<<13 ) ); - WRITE_BYTE( textparms.effect ); - - WRITE_BYTE( textparms.r1 ); - WRITE_BYTE( textparms.g1 ); - WRITE_BYTE( textparms.b1 ); - WRITE_BYTE( textparms.a1 ); - - WRITE_BYTE( textparms.r2 ); - WRITE_BYTE( textparms.g2 ); - WRITE_BYTE( textparms.b2 ); - WRITE_BYTE( textparms.a2 ); - - WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1<<8 ) ); - - if ( textparms.effect == 2 ) - WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1<<8 ) ); - - if ( strlen( pMessage ) < 512 ) - { - WRITE_STRING( pMessage ); - } - else - { - char tmp[512]; - strncpy( tmp, pMessage, 511 ); - tmp[511] = 0; - WRITE_STRING( tmp ); - } - MESSAGE_END(); -} - -void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) -{ - int i; - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_HudMessage( pPlayer, textparms, pMessage ); - } -} - - -void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - vector message; - message.push_back( msg_name ); - if( param1 ) message.push_back( param1 ); - if( param2 ) message.push_back( param2 ); - if( param3 ) message.push_back( param3 ); - if( param4 ) message.push_back( param4 ); - NetMsg_TextMsg( msg_dest, message ); -} - -void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - vector message; - message.push_back( msg_name ); - if( param1 ) message.push_back( param1 ); - if( param2 ) message.push_back( param2 ); - if( param3 ) message.push_back( param3 ); - if( param4 ) message.push_back( param4 ); - NetMsg_TextMsg( client, msg_dest, message ); -} - -void UTIL_SayText( const char *pText, CBaseEntity *pEntity, int inEntIndex) -{ - if ( !pEntity->IsNetClient() ) - return; - - string theLocation(" "); - - if(inEntIndex == -1) - { - inEntIndex = pEntity->entindex(); - } - else - { - CBaseEntity* theSpeakingPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(inEntIndex)); - if(theSpeakingPlayer) - { - theLocation = AvHSUGetLocationText(theSpeakingPlayer); - } - } - - NetMsg_SayText( pEntity->pev, inEntIndex, string( pText ), theLocation ); -} - -void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity, int inEntIndex) -{ - string theLocation(" "); - - if(inEntIndex == -1) - { - inEntIndex = pEntity->entindex(); - } - else - { - CBaseEntity* theSpeakingPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(inEntIndex)); - if(theSpeakingPlayer) - { - theLocation = AvHSUGetLocationText(theSpeakingPlayer); - } - } - - NetMsg_SayText( inEntIndex, string( pText ), theLocation ); -} - -void UTIL_Tutorial( CBaseEntity *pEntity, const char *pMessage ) -{ - // TODO: Be able to turn these off as a preference - hudtextparms_t theTextParms; - - // Init text parms - theTextParms.x = -1; - theTextParms.y = .8; - theTextParms.effect = 0; - theTextParms.r1 = 240; - theTextParms.g1 = 240; - theTextParms.b1 = 240; - theTextParms.a1 = 128; - theTextParms.r2 = 240; - theTextParms.g2 = 240; - theTextParms.b2 = 240; - theTextParms.a2 = 128; - theTextParms.fadeinTime = .3f; - theTextParms.fadeoutTime = .3f; - theTextParms.holdTime = 6.0f; - theTextParms.fxTime = .25f; - theTextParms.channel = 1; - - UTIL_HudMessage( pEntity, theTextParms, pMessage); -} - -void UTIL_Error( CBaseEntity *pEntity, const char *pMessage ) -{ - hudtextparms_t theTextParms; - - // Init text parms - theTextParms.x = -1; - theTextParms.y = .8; - theTextParms.effect = 0; - theTextParms.r1 = 240; - theTextParms.g1 = 100; - theTextParms.b1 = 100; - theTextParms.a1 = 128; - theTextParms.r2 = 240; - theTextParms.g2 = 100; - theTextParms.b2 = 100; - theTextParms.a2 = 128; - theTextParms.fadeinTime = .3f; - theTextParms.fadeoutTime = .3f; - theTextParms.holdTime = 2.0f; - theTextParms.fxTime = .25f; - theTextParms.channel = 1; - - UTIL_HudMessage( pEntity, theTextParms, pMessage); -} - -char *UTIL_dtos1( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos2( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos3( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos4( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - NetMsg_HudText( pEntity->pev, string( pString ) ); -} - -void UTIL_ShowMessage2( const char *pString, CBaseEntity *pEntity, SHOWMESSAGE_TYPE type) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - NetMsg_HudText2( pEntity->pev, string( pString ), type ); -} - - -void UTIL_ShowMessageAll( const char *pString ) -{ - int i; - - // loop through all players - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_ShowMessage( pString, pPlayer ); - } -} - -// Overloaded to add IGNORE_GLASS -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); -} - - -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); -} - - -void UTIL_TraceHull( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_HULL( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), hullNumber, pentIgnore, ptr ); -} - -void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr ) -{ - g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr ); -} - - -TraceResult UTIL_GetGlobalTrace( ) -{ - TraceResult tr; - - tr.fAllSolid = gpGlobals->trace_allsolid; - tr.fStartSolid = gpGlobals->trace_startsolid; - tr.fInOpen = gpGlobals->trace_inopen; - tr.fInWater = gpGlobals->trace_inwater; - tr.flFraction = gpGlobals->trace_fraction; - tr.flPlaneDist = gpGlobals->trace_plane_dist; - tr.pHit = gpGlobals->trace_ent; - tr.vecEndPos = gpGlobals->trace_endpos; - tr.vecPlaneNormal = gpGlobals->trace_plane_normal; - tr.iHitgroup = gpGlobals->trace_hitgroup; - return tr; -} - - -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) -{ - SET_SIZE( ENT(pev), vecMin, vecMax ); -} - - -float UTIL_VecToYaw( const Vector &vec ) -{ - return VEC_TO_YAW(vec); -} - - -void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) -{ - SET_ORIGIN(ENT(pev), vecOrigin ); -} - -void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ) -{ - PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount ); -} - - -float UTIL_Approach( float target, float value, float speed ) -{ - float delta = target - value; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_ApproachAngle( float target, float value, float speed ) -{ - target = UTIL_AngleMod( target ); - value = UTIL_AngleMod( target ); - - float delta = target - value; - - // Speed is assumed to be positive - if ( speed < 0 ) - speed = -speed; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_AngleDistance( float next, float cur ) -{ - float delta = next - cur; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - return delta; -} - - -float UTIL_SplineFraction( float value, float scale ) -{ - value = scale * value; - float valueSquared = value * value; - - // Nice little ease-in, ease-out spline-like curve - return 3 * valueSquared - 2 * valueSquared * value; -} - - -char* UTIL_VarArgs( char *format, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, format); -#ifdef WIN32 - //overflow protection in MS version of function... - _vsnprintf_s( string, 1023, format, argptr ); -#else - vsprintf (string, format,argptr); -#endif - va_end (argptr); - - return string; -} - -Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) -{ - Vector tmp; - GET_AIM_VECTOR(pent, flSpeed, tmp); - return tmp; -} - -int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) -{ - if (sMaster) - { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(sMaster)); - - if ( !FNullEnt(pentTarget) ) - { - CBaseEntity *pMaster = CBaseEntity::Instance(pentTarget); - if ( pMaster && (pMaster->ObjectCaps() & FCAP_MASTER) ) - return pMaster->IsTriggered( pActivator ); - } - - ALERT(at_console, "Master was null or not a master!\n"); - } - - // if this isn't a master entity, just say yes. - return 1; -} - -BOOL UTIL_ShouldShowBlood( int color ) -{ - if ( color != DONT_BLEED ) - { - if ( color == BLOOD_COLOR_RED ) - { - if ( ns_cvar_float(violence_hblood) != 0 ) - return TRUE; - } - else - { - if ( ns_cvar_float(violence_ablood) != 0 ) - return TRUE; - } - } - return FALSE; -} - -int UTIL_PointContents( const Vector &vec ) -{ - int thePointContents = POINT_CONTENTS(vec); - return thePointContents; -} - -void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_BLOODSTREAM ); - WRITE_COORD( origin.x ); - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); - WRITE_BYTE( min( amount, 255 ) ); - MESSAGE_END(); -} - -void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( color == DONT_BLEED || amount == 0 ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - if ( g_pGameRules->IsMultiplayer() ) - { - // scale up blood effect in multiplayer for better visibility - amount *= 2; - } - - if ( amount > 255 ) - amount = 255; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_BLOODSPRITE ); - WRITE_COORD( origin.x); // pos - WRITE_COORD( origin.y); - WRITE_COORD( origin.z); - WRITE_SHORT( g_sModelIndexBloodSpray ); // initial sprite model - WRITE_SHORT( g_sModelIndexBloodDrop ); // droplet sprite models - WRITE_BYTE( color ); // color index into host_basepal - WRITE_BYTE( min( max( 3, amount / 10 ), 16 ) ); // size - MESSAGE_END(); -} - -Vector UTIL_RandomBloodVector( void ) -{ - Vector direction; - - direction.x = RANDOM_FLOAT ( -1, 1 ); - direction.y = RANDOM_FLOAT ( -1, 1 ); - direction.z = RANDOM_FLOAT ( 0, 1 ); - - return direction; -} - - -void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) -{ - if ( UTIL_ShouldShowBlood( bloodColor ) ) - { - if ( bloodColor == BLOOD_COLOR_RED ) - UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG(0,5) ); - else - UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0,5) ); - } -} - - -void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) -{ - short entityIndex; - int index; - int message; - - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - // Only decal BSP models - if ( pTrace->pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit ); - if ( pEntity && !pEntity->IsBSPModel() ) - return; - entityIndex = ENTINDEX( pTrace->pHit ); - } - else - entityIndex = 0; - - message = TE_DECAL; - if ( entityIndex != 0 ) - { - if ( index > 255 ) - { - message = TE_DECALHIGH; - index -= 256; - } - } - else - { - message = TE_WORLDDECAL; - if ( index > 255 ) - { - message = TE_WORLDDECALHIGH; - index -= 256; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( message ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_BYTE( index ); - if ( entityIndex ) - WRITE_SHORT( entityIndex ); - MESSAGE_END(); -} - -/* -============== -UTIL_PlayerDecalTrace - -A player is trying to apply his custom decal for the spray can. -Tell connected clients to display it, or use the default spray can decal -if the custom can't be loaded. -============== -*/ -void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ) -{ - int index; - - if (!bIsCustom) - { - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - } - else - index = decalNumber; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_PLAYERDECAL ); - WRITE_BYTE ( playernum ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - -void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) -{ - if ( decalNumber < 0 ) - return; - - int index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos ); - WRITE_BYTE( TE_GUNSHOTDECAL ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - - -void UTIL_Sparks( const Vector &position ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_SPARKS ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - MESSAGE_END(); -} - - -void UTIL_Ricochet( const Vector &position, float scale ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_ARMOR_RICOCHET ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - WRITE_BYTE( (int)(scale*10) ); - MESSAGE_END(); -} - - -BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) -{ - // Everyone matches unless it's teamplay - if ( !g_pGameRules->IsTeamplay() ) - return TRUE; - - // Both on a team? - if ( *pTeamName1 != 0 && *pTeamName2 != 0 ) - { - if ( !_stricmp( pTeamName1, pTeamName2 ) ) // Same Team? - return TRUE; - } - - return FALSE; -} - - -void UTIL_StringToVector( float *pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - if (j < 2) - { - /* - ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n", - pkvd->szClassName, pkvd->szKeyName, pkvd->szValue ); - */ - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - - -void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < count; j++ ) // lifted from pr_edict.c - { - pVector[j] = atoi( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - for ( j++; j < count; j++ ) - { - pVector[j] = 0; - } -} - -Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) -{ - Vector sourceVector = input; - - if ( sourceVector.x > clampSize.x ) - sourceVector.x -= clampSize.x; - else if ( sourceVector.x < -clampSize.x ) - sourceVector.x += clampSize.x; - else - sourceVector.x = 0; - - if ( sourceVector.y > clampSize.y ) - sourceVector.y -= clampSize.y; - else if ( sourceVector.y < -clampSize.y ) - sourceVector.y += clampSize.y; - else - sourceVector.y = 0; - - if ( sourceVector.z > clampSize.z ) - sourceVector.z -= clampSize.z; - else if ( sourceVector.z < -clampSize.z ) - sourceVector.z += clampSize.z; - else - sourceVector.z = 0; - - return sourceVector.Normalize(); -} - - -float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) -{ - Vector midUp = position; - midUp.z = minz; - - if (UTIL_PointContents(midUp) != CONTENTS_WATER) - return minz; - - midUp.z = maxz; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) - return maxz; - - float diff = maxz - minz; - while (diff > 1.0) - { - midUp.z = minz + diff/2.0; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) - { - minz = midUp.z; - } - else - { - maxz = midUp.z; - } - diff = maxz - minz; - } - - return midUp.z; -} - - -extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model - -void UTIL_Bubbles( Vector mins, Vector maxs, int count ) -{ - Vector mid = (mins + maxs) * 0.5; - - float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); - flHeight = flHeight - mins.z; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, mid ); - WRITE_BYTE( TE_BUBBLES ); - WRITE_COORD( mins.x ); // mins - WRITE_COORD( mins.y ); - WRITE_COORD( mins.z ); - WRITE_COORD( maxs.x ); // maxz - WRITE_COORD( maxs.y ); - WRITE_COORD( maxs.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - -void UTIL_BubbleTrail( Vector from, Vector to, int count ) -{ - float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); - flHeight = flHeight - from.z; - - if (flHeight < 8) - { - flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); - flHeight = flHeight - to.z; - if (flHeight < 8) - return; - - // UNDONE: do a ploink sound - flHeight = flHeight + to.z - from.z; - } - - if (count > 255) - count = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BUBBLETRAIL ); - WRITE_COORD( from.x ); // mins - WRITE_COORD( from.y ); - WRITE_COORD( from.z ); - WRITE_COORD( to.x ); // maxz - WRITE_COORD( to.y ); - WRITE_COORD( to.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - - -void UTIL_Remove( CBaseEntity *pEntity ) -{ - if ( !pEntity ) - return; - - pEntity->UpdateOnRemove(); - pEntity->pev->flags |= FL_KILLME; - pEntity->pev->targetname = 0; -} - - -BOOL UTIL_IsValidEntity( edict_t *pent ) -{ - if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) - return FALSE; - return TRUE; -} - - -void UTIL_PrecacheOther( const char *szClassname ) -{ - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOther\n" ); - return; - } - - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - if (pEntity) - pEntity->Precache( ); - REMOVE_ENTITY(pent); -} - -//========================================================= -// UTIL_LogPrintf - Prints a logged message to console. -// Preceded by LOG: ( timestamp ) < message > -//========================================================= -void UTIL_LogPrintf( char *fmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start ( argptr, fmt ); -#ifdef WIN32 - //overflow protection in MS version of function... - _vsnprintf( string, 1023, fmt, argptr ); -#else - vsprintf ( string, fmt, argptr ); -#endif - va_end ( argptr ); - - // Print to server console - ALERT( at_logged, "%s", string ); -} - -//========================================================= -// UTIL_DotPoints - returns the dot product of a line from -// src to check and vecdir. -//========================================================= -float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ) -{ - Vector2D vec2LOS; - - vec2LOS = ( vecCheck - vecSrc ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); -} - - -//========================================================= -// UTIL_StripToken - for redundant keynames -//========================================================= -void UTIL_StripToken( const char *pKey, char *pDest ) -{ - int i = 0; - - while ( pKey[i] && pKey[i] != '#' ) - { - pDest[i] = pKey[i]; - i++; - } - pDest[i] = 0; -} - - -// -------------------------------------------------------------- -// -// CSave -// -// -------------------------------------------------------------- -static int gSizes[FIELD_TYPECOUNT] = -{ - sizeof(float), // FIELD_FLOAT - sizeof(int), // FIELD_STRING - sizeof(int), // FIELD_ENTITY - sizeof(int), // FIELD_CLASSPTR - sizeof(int), // FIELD_EHANDLE - sizeof(int), // FIELD_entvars_t - sizeof(int), // FIELD_EDICT - sizeof(float)*3, // FIELD_VECTOR - sizeof(float)*3, // FIELD_POSITION_VECTOR - sizeof(int *), // FIELD_POINTER - sizeof(int), // FIELD_INTEGER - sizeof(int *), // FIELD_FUNCTION - sizeof(int), // FIELD_BOOLEAN - sizeof(short), // FIELD_SHORT - sizeof(char), // FIELD_CHARACTER - sizeof(float), // FIELD_TIME - sizeof(int), // FIELD_MODELNAME - sizeof(int), // FIELD_SOUNDNAME -}; - - -// Base class includes common SAVERESTOREDATA pointer, and manages the entity table -CSaveRestoreBuffer :: CSaveRestoreBuffer( void ) -{ - m_pdata = NULL; -} - - -CSaveRestoreBuffer :: CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) -{ - m_pdata = pdata; -} - - -CSaveRestoreBuffer :: ~CSaveRestoreBuffer( void ) -{ -} - -int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL ) - return -1; - return EntityIndex( pEntity->pev ); -} - - -int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) -{ - if ( pevLookup == NULL ) - return -1; - return EntityIndex( ENT( pevLookup ) ); -} - -int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) -{ - return EntityIndex( ENT( eoLookup ) ); -} - - -int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) -{ - if ( !m_pdata || pentLookup == NULL ) - return -1; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->pent == pentLookup ) - return i; - } - return -1; -} - - -edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) -{ - if ( !m_pdata || entityIndex < 0 ) - return NULL; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->id == entityIndex ) - return pTable->pent; - } - return NULL; -} - - -int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) -{ - if ( !m_pdata || entityIndex < 0 ) - return 0; - if ( entityIndex > m_pdata->tableCount ) - return 0; - - m_pdata->pTable[ entityIndex ].flags |= flags; - - return m_pdata->pTable[ entityIndex ].flags; -} - - -void CSaveRestoreBuffer :: BufferRewind( int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size < size ) - size = m_pdata->size; - - m_pdata->pCurrentData -= size; - m_pdata->size -= size; -} - -#ifndef _WIN32 -extern "C" { -unsigned _rotr ( unsigned val, int shift) -{ - register unsigned lobit; /* non-zero means lo bit set */ - register unsigned num = val; /* number to rotate */ - - shift &= 0x1f; /* modulo 32 -- this will also make - negative shifts work */ - - while (shift--) { - lobit = num & 1; /* get high bit */ - num >>= 1; /* shift right one bit */ - if (lobit) - num |= 0x80000000; /* set hi bit if lo bit was set */ - } - - return num; -} -} -#endif - -unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) -{ - unsigned int hash = 0; - - while ( *pszToken ) - hash = _rotr( hash, 4 ) ^ *pszToken++; - - return hash; -} - -unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) -{ - unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)m_pdata->tokenCount ); - -#if _DEBUG - static int tokensparsed = 0; - tokensparsed++; - if ( !m_pdata->tokenCount || !m_pdata->pTokens ) - ALERT( at_error, "No token table array in TokenHash()!" ); -#endif - - for ( int i=0; itokenCount; i++ ) - { -#if _DEBUG - static qboolean beentheredonethat = FALSE; - if ( i > 50 && !beentheredonethat ) - { - beentheredonethat = TRUE; - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" ); - } -#endif - - int index = hash + i; - if ( index >= m_pdata->tokenCount ) - index -= m_pdata->tokenCount; - - if ( !m_pdata->pTokens[index] || strcmp( pszToken, m_pdata->pTokens[index] ) == 0 ) - { - m_pdata->pTokens[index] = (char *)pszToken; - return index; - } - } - - // Token hash table full!!! - // [Consider doing overflow table(s) after the main table & limiting linear hash table search] - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!" ); - return 0; -} - -void CSave :: WriteData( const char *pname, int size, const char *pdata ) -{ - BufferField( pname, size, pdata ); -} - - -void CSave :: WriteShort( const char *pname, const short *data, int count ) -{ - BufferField( pname, sizeof(short) * count, (const char *)data ); -} - - -void CSave :: WriteInt( const char *pname, const int *data, int count ) -{ - BufferField( pname, sizeof(int) * count, (const char *)data ); -} - - -void CSave :: WriteFloat( const char *pname, const float *data, int count ) -{ - BufferField( pname, sizeof(float) * count, (const char *)data ); -} - - -void CSave :: WriteTime( const char *pname, const float *data, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * count ); - for ( i = 0; i < count; i++ ) - { - float tmp = data[0]; - - // Always encode time as a delta from the current time so it can be re-based if loaded in a new level - // Times of 0 are never written to the file, so they will be restored as 0, not a relative time - if ( m_pdata ) - tmp -= m_pdata->time; - - BufferData( (const char *)&tmp, sizeof(float) ); - data ++; - } -} - - -void CSave :: WriteString( const char *pname, const char *pdata ) -{ -#ifdef TOKENIZE - short token = (short)TokenHash( pdata ); - WriteShort( pname, &token, 1 ); -#else - BufferField( pname, strlen(pdata) + 1, pdata ); -#endif -} - - -void CSave :: WriteString( const char *pname, const int *stringId, int count ) -{ - int i, size; - -#ifdef TOKENIZE - short token = (short)TokenHash( STRING( *stringId ) ); - WriteShort( pname, &token, 1 ); -#else -#if 0 - if ( count != 1 ) - ALERT( at_error, "No string arrays!\n" ); - WriteString( pname, (char *)STRING(*stringId) ); -#endif - - size = 0; - for ( i = 0; i < count; i++ ) - size += strlen( STRING( stringId[i] ) ) + 1; - - BufferHeader( pname, size ); - for ( i = 0; i < count; i++ ) - { - const char *pString = STRING(stringId[i]); - BufferData( pString, strlen(pString)+1 ); - } -#endif -} - - -void CSave :: WriteVector( const char *pname, const Vector &value ) -{ - WriteVector( pname, &value.x, 1 ); -} - - -void CSave :: WriteVector( const char *pname, const float *value, int count ) -{ - BufferHeader( pname, sizeof(float) * 3 * count ); - BufferData( (const char *)value, sizeof(float) * 3 * count ); -} - - - -void CSave :: WritePositionVector( const char *pname, const Vector &value ) -{ - - if ( m_pdata && m_pdata->fUseLandmark ) - { - Vector tmp = value - m_pdata->vecLandmarkOffset; - WriteVector( pname, tmp ); - } - - WriteVector( pname, value ); -} - - -void CSave :: WritePositionVector( const char *pname, const float *value, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * 3 * count ); - for ( i = 0; i < count; i++ ) - { - Vector tmp( value[0], value[1], value[2] ); - - if ( m_pdata && m_pdata->fUseLandmark ) - tmp = tmp - m_pdata->vecLandmarkOffset; - - BufferData( (const char *)&tmp.x, sizeof(float) * 3 ); - value += 3; - } -} - - -void CSave :: WriteFunction( const char *pname, const int *data, int count ) -{ - const char *functionName; - - functionName = NAME_FOR_FUNCTION( *data ); - if ( functionName ) - BufferField( pname, strlen(functionName) + 1, functionName ); - else - ALERT( at_error, "Invalid function pointer in entity!" ); -} - - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) -{ - int i; - TYPEDESCRIPTION *pField; - - for ( i = 0; i < ENTVARS_COUNT; i++ ) - { - pField = &gEntvarsDescription[i]; - - if ( !stricmp( pField->fieldName, pkvd->szKeyName ) ) - { - switch( pField->fieldType ) - { - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - (*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue ); - break; - - case FIELD_TIME: - case FIELD_FLOAT: - (*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); - break; - - case FIELD_INTEGER: - (*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue ); - break; - - case FIELD_POSITION_VECTOR: - case FIELD_VECTOR: - UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue ); - break; - - default: - case FIELD_EVARS: - case FIELD_CLASSPTR: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_POINTER: - ALERT( at_error, "Bad field in entity!!\n" ); - break; - } - pkvd->fHandled = TRUE; - return; - } - } -} - - - -int CSave :: WriteEntVars( const char *pname, entvars_t *pev ) -{ - return WriteFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - - - -int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - int i, j, actualCount, emptyCount; - TYPEDESCRIPTION *pTest; - int entityArray[MAX_ENTITYARRAY]; - - // Precalculate the number of empty fields - emptyCount = 0; - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pOutputData = ((char *)pBaseData + pFields[i].fieldOffset ); - if ( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) ) - emptyCount++; - } - - // Empty fields will not be written, write out the actual number of fields to be written - actualCount = fieldCount - emptyCount; - WriteInt( pname, &actualCount, 1 ); - - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pTest = &pFields[ i ]; - pOutputData = ((char *)pBaseData + pTest->fieldOffset ); - - // UNDONE: Must we do this twice? - if ( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) ) - continue; - - switch( pTest->fieldType ) - { - case FIELD_FLOAT: - WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_TIME: - WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - case FIELD_CLASSPTR: - case FIELD_EVARS: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_EHANDLE: - if ( pTest->fieldSize > MAX_ENTITYARRAY ) - ALERT( at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY ); - for ( j = 0; j < pTest->fieldSize; j++ ) - { - switch( pTest->fieldType ) - { - case FIELD_EVARS: - entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); - break; - case FIELD_CLASSPTR: - entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); - break; - case FIELD_EDICT: - entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); - break; - case FIELD_ENTITY: - entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); - break; - case FIELD_EHANDLE: - entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); - break; - } - } - WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); - break; - case FIELD_POSITION_VECTOR: - WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_VECTOR: - WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_BOOLEAN: - case FIELD_INTEGER: - WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_SHORT: - WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); - break; - - case FIELD_CHARACTER: - WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); - break; - - // For now, just write the address out, we're not going to change memory while doing this yet! - case FIELD_POINTER: - WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - default: - ALERT( at_error, "Bad field type\n" ); - } - } - - return 1; -} - - -void CSave :: BufferString( char *pdata, int len ) -{ - char c = 0; - - BufferData( pdata, len ); // Write the string - BufferData( &c, 1 ); // Write a null terminator -} - - -int CSave :: DataEmpty( const char *pdata, int size ) -{ - for ( int i = 0; i < size; i++ ) - { - if ( pdata[i] ) - return 0; - } - return 1; -} - - -void CSave :: BufferField( const char *pname, int size, const char *pdata ) -{ - BufferHeader( pname, size ); - BufferData( pdata, size ); -} - - -void CSave :: BufferHeader( const char *pname, int size ) -{ - short hashvalue = TokenHash( pname ); - if ( size > 1<<(sizeof(short)*8) ) - ALERT( at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!" ); - BufferData( (const char *)&size, sizeof(short) ); - BufferData( (const char *)&hashvalue, sizeof(short) ); -} - - -void CSave :: BufferData( const char *pdata, int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size + size > m_pdata->bufferSize ) - { - ALERT( at_error, "Save/Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - memcpy( m_pdata->pCurrentData, pdata, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - - -// -------------------------------------------------------------- -// -// CRestore -// -// -------------------------------------------------------------- - -int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ) -{ - int i, j, stringCount, fieldNumber, entityIndex; - TYPEDESCRIPTION *pTest; - float time, timeData; - Vector position; - edict_t *pent; - char *pString; - - time = 0; - position = Vector(0,0,0); - - if ( m_pdata ) - { - time = m_pdata->time; - if ( m_pdata->fUseLandmark ) - position = m_pdata->vecLandmarkOffset; - } - - for ( i = 0; i < fieldCount; i++ ) - { - fieldNumber = (i+startField)%fieldCount; - pTest = &pFields[ fieldNumber ]; - if ( !stricmp( pTest->fieldName, pName ) ) - { - if ( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL) ) - { - for ( j = 0; j < pTest->fieldSize; j++ ) - { - void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j*gSizes[pTest->fieldType]) ); - void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; - - switch( pTest->fieldType ) - { - case FIELD_TIME: - timeData = *(float *)pInputData; - // Re-base time variables - timeData += time; - *((float *)pOutputData) = timeData; - break; - case FIELD_FLOAT: - *((float *)pOutputData) = *(float *)pInputData; - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - // Skip over j strings - pString = (char *)pData; - for ( stringCount = 0; stringCount < j; stringCount++ ) - { - while (*pString) - pString++; - pString++; - } - pInputData = pString; - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - { - int string; - - string = ALLOC_STRING( (char *)pInputData ); - - *((int *)pOutputData) = string; - - if ( !FStringNull( string ) && m_precache ) - { - if ( pTest->fieldType == FIELD_MODELNAME ) - PRECACHE_MODEL( (char *)STRING( string ) ); - else if ( pTest->fieldType == FIELD_SOUNDNAME ) - PRECACHE_SOUND( (char *)STRING( string ) ); - } - } - break; - case FIELD_EVARS: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((entvars_t **)pOutputData) = VARS(pent); - else - *((entvars_t **)pOutputData) = NULL; - break; - case FIELD_CLASSPTR: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); - else - *((CBaseEntity **)pOutputData) = NULL; - break; - case FIELD_EDICT: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - *((edict_t **)pOutputData) = pent; - break; - case FIELD_EHANDLE: - // Input and Output sizes are different! - pOutputData = (char *)pOutputData + j*(sizeof(EHANDLE) - gSizes[pTest->fieldType]); - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); - else - *((EHANDLE *)pOutputData) = NULL; - break; - case FIELD_ENTITY: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EOFFSET *)pOutputData) = OFFSET(pent); - else - *((EOFFSET *)pOutputData) = 0; - break; - case FIELD_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0]; - ((float *)pOutputData)[1] = ((float *)pInputData)[1]; - ((float *)pOutputData)[2] = ((float *)pInputData)[2]; - break; - case FIELD_POSITION_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; - ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; - ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; - break; - - case FIELD_BOOLEAN: - case FIELD_INTEGER: - *((int *)pOutputData) = *( int *)pInputData; - break; - - case FIELD_SHORT: - *((short *)pOutputData) = *( short *)pInputData; - break; - - case FIELD_CHARACTER: - *((char *)pOutputData) = *( char *)pInputData; - break; - - case FIELD_POINTER: - *((int *)pOutputData) = *( int *)pInputData; - break; - case FIELD_FUNCTION: - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - *((int *)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); - break; - - default: - ALERT( at_error, "Bad field type\n" ); - } - } - } -#if 0 - else - { - ALERT( at_console, "Skipping global field %s\n", pName ); - } -#endif - return fieldNumber; - } - } - - return -1; -} - - -int CRestore::ReadEntVars( const char *pname, entvars_t *pev ) -{ - return ReadFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - - -int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - unsigned short i, token; - int lastField, fileCount; - HEADER header; - - i = ReadShort(); - ASSERT( i == sizeof(int) ); // First entry should be an int - - token = ReadShort(); - - // Check the struct name - if ( token != TokenHash(pname) ) // Field Set marker - { -// ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); - BufferRewind( 2*sizeof(short) ); - return 0; - } - - // Skip over the struct name - fileCount = ReadInt(); // Read field count - - lastField = 0; // Make searches faster, most data is read/written in the same order - - // Clear out base data - for ( i = 0; i < fieldCount; i++ ) - { - // Don't clear global fields - if ( !m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL) ) - memset( ((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ); - } - - for ( i = 0; i < fileCount; i++ ) - { - BufferReadHeader( &header ); - lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData ); - lastField++; - } - - return 1; -} - - -void CRestore::BufferReadHeader( HEADER *pheader ) -{ - ASSERT( pheader!=NULL ); - pheader->size = ReadShort(); // Read field size - pheader->token = ReadShort(); // Read field name token - pheader->pData = BufferPointer(); // Field Data is next - BufferSkipBytes( pheader->size ); // Advance to next field -} - - -short CRestore::ReadShort( void ) -{ - short tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(short) ); - - return tmp; -} - -int CRestore::ReadInt( void ) -{ - int tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(int) ); - - return tmp; -} - -int CRestore::ReadNamedInt( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); - return ((int *)header.pData)[0]; -} - -char *CRestore::ReadNamedString( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); -#ifdef TOKENIZE - return (char *)(m_pdata->pTokens[*(short *)header.pData]); -#else - return (char *)header.pData; -#endif -} - - -char *CRestore::BufferPointer( void ) -{ - if ( !m_pdata ) - return NULL; - - return m_pdata->pCurrentData; -} - -void CRestore::BufferReadBytes( char *pOutput, int size ) -{ - ASSERT( m_pdata !=NULL ); - - if ( !m_pdata || Empty() ) - return; - - if ( (m_pdata->size + size) > m_pdata->bufferSize ) - { - ALERT( at_error, "Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - if ( pOutput ) - memcpy( pOutput, m_pdata->pCurrentData, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - -void CRestore::BufferSkipBytes( int bytes ) -{ - BufferReadBytes( NULL, bytes ); -} - -int CRestore::BufferSkipZString( void ) -{ - char *pszSearch; - int len; - - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - - len = 0; - pszSearch = m_pdata->pCurrentData; - while ( *pszSearch++ && len < maxLen ) - len++; - - len++; - - BufferSkipBytes( len ); - - return len; -} - -int CRestore::BufferCheckZString( const char *string ) -{ - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - int len = strlen( string ); - if ( len <= maxLen ) - { - if ( !strncmp( string, m_pdata->pCurrentData, len ) ) - return 1; - } - return 0; -} - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== util.cpp ======================================================== + + Utility code. Really not optional after all. + +*/ + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include +#include "../engine/shake.h" +#include "decals.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "../mod/AvHServerUtil.h" +#include "../mod/AvHNetworkMessages.h" +#include "../mod/AvHServerVariables.h" +//#include "../mod/AvHSharedUtil.h" +//#include "../mod/AvHGamerules.h" + +float UTIL_WeaponTimeBase( void ) +{ + return 0.0; +} + +static unsigned int glSeed = 0; + +unsigned int seed_table[ 256 ] = +{ + 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, + 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, + 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, + 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, + 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, + 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, + 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, + 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, + 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, + 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, + 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, + 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, + 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, + 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, + 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, + 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 +}; + +unsigned int U_Random( void ) +{ + glSeed *= 69069; + glSeed += seed_table[ glSeed & 0xff ]; + + return ( ++glSeed & 0x0fffffff ); +} + +void U_Srand( unsigned int seed ) +{ + glSeed = seed_table[ seed & 0xff ]; +} + +/* +===================== +UTIL_SharedRandomLong +===================== +*/ +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) +{ + unsigned int range; + + U_Srand( (int)seed + low + high ); + + range = high - low + 1; + if ( !(range - 1) ) + { + return low; + } + else + { + int offset; + int rnum; + + rnum = U_Random(); + + offset = rnum % range; + + return (low + offset); + } +} + +/* +===================== +UTIL_SharedRandomFloat +===================== +*/ +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) +{ + U_Srand( (int)seed + *(int *)&low + *(int *)&high ); + + U_Random(); + U_Random(); + + float range = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner ) +{ + pev->startpos = vecOrigin; + // Trace out line to end pos + TraceResult tr; + UTIL_MakeVectors( vecAngles ); + UTIL_TraceLine( pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr); + pev->endpos = tr.vecEndPos; + + // Now compute how long it will take based on current velocity + Vector vecTravel = pev->endpos - pev->startpos; + float travelTime = 0.0; + if ( pev->velocity.Length() > 0 ) + { + travelTime = vecTravel.Length() / pev->velocity.Length(); + } + pev->starttime = gpGlobals->time; + pev->impacttime = gpGlobals->time + travelTime; +} + +int g_groupmask = 0; +int g_groupop = 0; + +// Normal overrides +void UTIL_SetGroupTrace( int groupmask, int op ) +{ + g_groupmask = groupmask; + g_groupop = op; + + ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); +} + +void UTIL_UnsetGroupTrace( void ) +{ + g_groupmask = 0; + g_groupop = 0; + + ENGINE_SETGROUPMASK( 0, 0 ); +} + +// Smart version, it'll clean itself up when it pops off stack +UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op ) +{ + m_oldgroupmask = g_groupmask; + m_oldgroupop = g_groupop; + + g_groupmask = groupmask; + g_groupop = op; + + ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); +} + +UTIL_GroupTrace::~UTIL_GroupTrace( void ) +{ + g_groupmask = m_oldgroupmask; + g_groupop = m_oldgroupop; + + ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); +} + +TYPEDESCRIPTION gEntvarsDescription[] = +{ + DEFINE_ENTITY_FIELD( classname, FIELD_STRING ), + DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ), + + DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ), + DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ), + DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ), + + DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ), + + DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), + DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), + + DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), + DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), + + DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ), + DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ), + DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ), + DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ), + DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ), + + DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ), + DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ), + + DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ), + + DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ), + + DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ), + + DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ), + DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ), + + DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ), + + DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ), + + DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ), + DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ), + + DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ), + DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ), + DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ), + DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ), + DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ), + DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ), + + DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ), + + DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ), + + DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ), + DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ), + DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ), + + // Having these fields be local to the individual levels makes it easier to test those levels individually. + DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ), + DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ), + DEFINE_ENTITY_FIELD( netname, FIELD_STRING ), + DEFINE_ENTITY_FIELD( message, FIELD_STRING ), + + DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ), + + DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ), + DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ), + DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ), + DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ), + DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ), + DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ), + DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ), + DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ), +}; + +#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0])) + + +#ifdef DEBUG +edict_t *DBG_EntOfVars( const entvars_t *pev ) +{ + if (pev->pContainingEntity != NULL) + return pev->pContainingEntity; + ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); + edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); + if (pent == NULL) + ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); + ((entvars_t *)pev)->pContainingEntity = pent; + return pent; +} +#endif //DEBUG + + +//#ifdef DEBUG +// void +//DBG_AssertFunction( +// BOOL fExpr, +// const char* szExpr, +// const char* szFile, +// int szLine, +// const char* szMessage) +// { +// if (fExpr) +// return; +// char szOut[512]; +// if (szMessage != NULL) +// sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage); +// else +// sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine); +// ALERT(at_console, szOut); +// } +//#endif // DEBUG + +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +{ + return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon ); +} + +// ripped this out of the engine +float UTIL_AngleMod(float a) +{ + if (a < 0) + { + a = a + 360 * ((int)(a / 360) + 1); + } + else if (a >= 360) + { + a = a - 360 * ((int)(a / 360)); + } + // a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); + return a; +} + +float UTIL_AngleDiff( float destAngle, float srcAngle ) +{ + float delta; + + delta = destAngle - srcAngle; + if ( destAngle > srcAngle ) + { + if ( delta >= 180 ) + delta -= 360; + } + else + { + if ( delta <= -180 ) + delta += 360; + } + return delta; +} + +Vector UTIL_VecToAngles( const Vector &vec ) +{ + float rgflVecOut[3]; + VEC_TO_ANGLES(vec, rgflVecOut); + return Vector(rgflVecOut); +} + +// float UTIL_MoveToOrigin( edict_t *pent, const Vector vecGoal, float flDist, int iMoveType ) +void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType ) +{ + float rgfl[3]; + vecGoal.CopyToArray(rgfl); +// return MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); + MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); +} + + +int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ) +{ + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + CBaseEntity *pEntity; + int count; + + count = 0; + + if ( !pEdict ) + return count; + + for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + { + if ( pEdict->free ) // Not in use + continue; + + if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? + continue; + + if ( mins.x > pEdict->v.absmax.x || + mins.y > pEdict->v.absmax.y || + mins.z > pEdict->v.absmax.z || + maxs.x < pEdict->v.absmin.x || + maxs.y < pEdict->v.absmin.y || + maxs.z < pEdict->v.absmin.z ) + continue; + + pEntity = CBaseEntity::Instance(pEdict); + if ( !pEntity ) + continue; + + pList[ count ] = pEntity; + count++; + + if ( count >= listMax ) + return count; + } + + return count; +} + + +int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) +{ + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + CBaseEntity *pEntity; + int count; + float distance, delta; + + count = 0; + float radiusSquared = radius * radius; + + if ( !pEdict ) + return count; + + for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + { + if ( pEdict->free ) // Not in use + continue; + + if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? + continue; + + // Use origin for X & Y since they are centered for all monsters + // Now X + delta = center.x - pEdict->v.origin.x;//(pEdict->v.absmin.x + pEdict->v.absmax.x)*0.5; + delta *= delta; + + if ( delta > radiusSquared ) + continue; + distance = delta; + + // Now Y + delta = center.y - pEdict->v.origin.y;//(pEdict->v.absmin.y + pEdict->v.absmax.y)*0.5; + delta *= delta; + + distance += delta; + if ( distance > radiusSquared ) + continue; + + // Now Z + delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z)*0.5; + delta *= delta; + + distance += delta; + if ( distance > radiusSquared ) + continue; + + pEntity = CBaseEntity::Instance(pEdict); + if ( !pEntity ) + continue; + + pList[ count ] = pEntity; + count++; + + if ( count >= listMax ) + return count; + } + + + return count; +} + + +CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) +{ + edict_t *pentEntity; + + if (pStartEntity) + pentEntity = pStartEntity->edict(); + else + pentEntity = NULL; + + pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); + + if (!FNullEnt(pentEntity)) + return CBaseEntity::Instance(pentEntity); + return NULL; +} + +int UTIL_CountEntitiesInSphere(const Vector& inVecCenter, float inRadius, const char* inClassName) +{ + int theNumEntities = 0; + + CBaseEntity* theEntity = NULL; + while((theEntity = UTIL_FindEntityInSphere(theEntity, inVecCenter, inRadius)) != NULL) + { + if(!strcmp(STRING(theEntity->pev->classname), inClassName)) + { + theNumEntities++; + } + } + + return theNumEntities; +} + + +CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ) +{ + edict_t *pentEntity; + + if (pStartEntity) + pentEntity = pStartEntity->edict(); + else + pentEntity = NULL; + + pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue ); + + if (!FNullEnt(pentEntity)) + return CBaseEntity::Instance(pentEntity); + return NULL; +} + +CBaseEntity *UTIL_FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ) +{ + return UTIL_FindEntityByString( pStartEntity, "classname", szName ); +} + +CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName ) +{ + return UTIL_FindEntityByString( pStartEntity, "targetname", szName ); +} + + +CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius ) +{ + CBaseEntity *pEntity = NULL; + + pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever ); + if (pEntity) + return pEntity; + + CBaseEntity *pSearch = NULL; + float flMaxDist2 = flRadius * flRadius; + while ((pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever )) != NULL) + { + float flDist2 = (pSearch->pev->origin - vecSrc).Length(); + flDist2 = flDist2 * flDist2; + if (flMaxDist2 > flDist2) + { + pEntity = pSearch; + flMaxDist2 = flDist2; + } + } + return pEntity; +} + + +// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected +// otherwise returns NULL +// Index is 1 based +CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) +{ + CBaseEntity *pPlayer = NULL; + + if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) + { + edict_t *pPlayerEdict = INDEXENT( playerIndex ); + if ( pPlayerEdict && !pPlayerEdict->free ) + { + pPlayer = CBaseEntity::Instance( pPlayerEdict ); + } + } + + return pPlayer; +} + + +void UTIL_MakeVectors( const Vector &vecAngles ) +{ + MAKE_VECTORS( vecAngles ); +} + + +void UTIL_MakeAimVectors( const Vector &vecAngles ) +{ + float rgflVec[3]; + vecAngles.CopyToArray(rgflVec); + rgflVec[0] = -rgflVec[0]; + MAKE_VECTORS(rgflVec); +} + + +#define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) + +void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) +{ + MAKE_VECTORS(vec); + + float tmp; + pgv->v_right = pgv->v_right * -1; + + SWAP(pgv->v_forward.y, pgv->v_right.x, tmp); + SWAP(pgv->v_forward.z, pgv->v_up.x, tmp); + SWAP(pgv->v_right.z, pgv->v_up.y, tmp); +} + + +void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ) +{ + float rgfl[3]; + vecOrigin.CopyToArray(rgfl); + + if (samp && *samp == '!') + { + char name[32]; + if (SENTENCEG_Lookup(samp, name) >= 0) + EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); + } + else + EMIT_AMBIENT_SOUND(entity, rgfl, samp, vol, attenuation, fFlags, pitch); +} + +static unsigned short FixedUnsigned16( float value, float scale ) +{ + int output; + + output = value * scale; + if ( output < 0 ) + output = 0; + if ( output > 0xFFFF ) + output = 0xFFFF; + + return (unsigned short)output; +} + +static short FixedSigned16( float value, float scale ) +{ + int output; + + output = value * scale; + + if ( output > 32767 ) + output = 32767; + + if ( output < -32768 ) + output = -32768; + + return (short)output; +} + +// Shake the screen of all clients within radius +// radius == 0, shake all clients +// UNDONE: Allow caller to shake clients not ONGROUND? +// UNDONE: Fix falloff model (disabled)? +// UNDONE: Affect user controls? +void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ) +{ + int i; + float localAmplitude; + ScreenShake shake; + + shake.duration = FixedUnsigned16( duration, 1<<12 ); // 4.12 fixed + shake.frequency = FixedUnsigned16( frequency, 1<<8 ); // 8.8 fixed + + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); + + if ( !pPlayer /*|| !(pPlayer->pev->flags & FL_ONGROUND)*/ ) // Don't shake if not onground + continue; + + localAmplitude = 0; + + if ( radius <= 0 ) + localAmplitude = amplitude; + else + { + Vector delta = center - pPlayer->pev->origin; + float distance = delta.Length(); + + // Had to get rid of this falloff - it didn't work well + if ( distance < radius ) + localAmplitude = amplitude;//radius - distance; + } + if ( localAmplitude ) + { + shake.amplitude = FixedUnsigned16( localAmplitude, 1<<12 ); // 4.12 fixed + + NetMsg_Shake( pPlayer->pev, shake ); + } + } +} + + + +void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency, float duration ) +{ + UTIL_ScreenShake( center, amplitude, frequency, duration, 0 ); +} + + +void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) +{ + fade.duration = FixedUnsigned16( fadeTime, 1<<12 ); // 4.12 fixed + fade.holdTime = FixedUnsigned16( fadeHold, 1<<12 ); // 4.12 fixed + fade.r = (int)color.x; + fade.g = (int)color.y; + fade.b = (int)color.z; + fade.a = alpha; + fade.fadeFlags = flags; +} + + +void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsNetClient() ) + return; + + NetMsg_Fade( pEntity->pev, fade ); +} + + +void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) +{ + int i; + ScreenFade fade; + + + UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); + + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); + + UTIL_ScreenFadeWrite( fade, pPlayer ); + } +} + + +void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) +{ + ScreenFade fade; + + UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); + UTIL_ScreenFadeWrite( fade, pEntity ); +} + + +void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) +{ + if ( !pEntity || !pEntity->IsNetClient() ) + return; + + MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pEntity->edict() ); + WRITE_BYTE( TE_TEXTMESSAGE ); + WRITE_BYTE( textparms.channel & 0xFF ); + + WRITE_SHORT( FixedSigned16( textparms.x, 1<<13 ) ); + WRITE_SHORT( FixedSigned16( textparms.y, 1<<13 ) ); + WRITE_BYTE( textparms.effect ); + + WRITE_BYTE( textparms.r1 ); + WRITE_BYTE( textparms.g1 ); + WRITE_BYTE( textparms.b1 ); + WRITE_BYTE( textparms.a1 ); + + WRITE_BYTE( textparms.r2 ); + WRITE_BYTE( textparms.g2 ); + WRITE_BYTE( textparms.b2 ); + WRITE_BYTE( textparms.a2 ); + + WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1<<8 ) ); + WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1<<8 ) ); + WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1<<8 ) ); + + if ( textparms.effect == 2 ) + WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1<<8 ) ); + + if ( strlen( pMessage ) < 512 ) + { + WRITE_STRING( pMessage ); + } + else + { + char tmp[512]; + strncpy( tmp, pMessage, 511 ); + tmp[511] = 0; + WRITE_STRING( tmp ); + } + MESSAGE_END(); +} + +void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) +{ + int i; + + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); + if ( pPlayer ) + UTIL_HudMessage( pPlayer, textparms, pMessage ); + } +} + + +void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) +{ + vector message; + message.push_back( msg_name ); + if( param1 ) message.push_back( param1 ); + if( param2 ) message.push_back( param2 ); + if( param3 ) message.push_back( param3 ); + if( param4 ) message.push_back( param4 ); + NetMsg_TextMsg( msg_dest, message ); +} + +void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) +{ + vector message; + message.push_back( msg_name ); + if( param1 ) message.push_back( param1 ); + if( param2 ) message.push_back( param2 ); + if( param3 ) message.push_back( param3 ); + if( param4 ) message.push_back( param4 ); + NetMsg_TextMsg( client, msg_dest, message ); +} + +void UTIL_SayText( const char *pText, CBaseEntity *pEntity, int inEntIndex) +{ + if ( !pEntity->IsNetClient() ) + return; + + string theLocation(" "); + + if(inEntIndex == -1) + { + inEntIndex = pEntity->entindex(); + } + else + { + CBaseEntity* theSpeakingPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(inEntIndex)); + if(theSpeakingPlayer) + { + theLocation = AvHSUGetLocationText(theSpeakingPlayer); + } + } + + NetMsg_SayText( pEntity->pev, inEntIndex, string( pText ), theLocation ); +} + +void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity, int inEntIndex) +{ + string theLocation(" "); + + if(inEntIndex == -1) + { + inEntIndex = pEntity->entindex(); + } + else + { + CBaseEntity* theSpeakingPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(inEntIndex)); + if(theSpeakingPlayer) + { + theLocation = AvHSUGetLocationText(theSpeakingPlayer); + } + } + + NetMsg_SayText( inEntIndex, string( pText ), theLocation ); +} + +void UTIL_Tutorial( CBaseEntity *pEntity, const char *pMessage ) +{ + // TODO: Be able to turn these off as a preference + hudtextparms_t theTextParms; + + // Init text parms + theTextParms.x = -1; + theTextParms.y = .8; + theTextParms.effect = 0; + theTextParms.r1 = 240; + theTextParms.g1 = 240; + theTextParms.b1 = 240; + theTextParms.a1 = 128; + theTextParms.r2 = 240; + theTextParms.g2 = 240; + theTextParms.b2 = 240; + theTextParms.a2 = 128; + theTextParms.fadeinTime = .3f; + theTextParms.fadeoutTime = .3f; + theTextParms.holdTime = 6.0f; + theTextParms.fxTime = .25f; + theTextParms.channel = 1; + + UTIL_HudMessage( pEntity, theTextParms, pMessage); +} + +void UTIL_Error( CBaseEntity *pEntity, const char *pMessage ) +{ + hudtextparms_t theTextParms; + + // Init text parms + theTextParms.x = -1; + theTextParms.y = .8; + theTextParms.effect = 0; + theTextParms.r1 = 240; + theTextParms.g1 = 100; + theTextParms.b1 = 100; + theTextParms.a1 = 128; + theTextParms.r2 = 240; + theTextParms.g2 = 100; + theTextParms.b2 = 100; + theTextParms.a2 = 128; + theTextParms.fadeinTime = .3f; + theTextParms.fadeoutTime = .3f; + theTextParms.holdTime = 2.0f; + theTextParms.fxTime = .25f; + theTextParms.channel = 1; + + UTIL_HudMessage( pEntity, theTextParms, pMessage); +} + +char *UTIL_dtos1( int d ) +{ + static char buf[8]; + sprintf( buf, "%d", d ); + return buf; +} + +char *UTIL_dtos2( int d ) +{ + static char buf[8]; + sprintf( buf, "%d", d ); + return buf; +} + +char *UTIL_dtos3( int d ) +{ + static char buf[8]; + sprintf( buf, "%d", d ); + return buf; +} + +char *UTIL_dtos4( int d ) +{ + static char buf[8]; + sprintf( buf, "%d", d ); + return buf; +} + +void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity) +{ + if ( !pEntity || !pEntity->IsNetClient() ) + return; + + NetMsg_HudText( pEntity->pev, string( pString ) ); +} + +void UTIL_ShowMessage2( const char *pString, CBaseEntity *pEntity, SHOWMESSAGE_TYPE type) +{ + if ( !pEntity || !pEntity->IsNetClient() ) + return; + + NetMsg_HudText2( pEntity->pev, string( pString ), type ); +} + + +void UTIL_ShowMessageAll( const char *pString ) +{ + int i; + + // loop through all players + + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); + if ( pPlayer ) + UTIL_ShowMessage( pString, pPlayer ); + } +} + +// Overloaded to add IGNORE_GLASS +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) +{ + TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); +} + + +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); +} + + +void UTIL_TraceHull( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr ) +{ + TRACE_HULL( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), hullNumber, pentIgnore, ptr ); +} + +void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr ) +{ + g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr ); +} + + +TraceResult UTIL_GetGlobalTrace( ) +{ + TraceResult tr; + + tr.fAllSolid = gpGlobals->trace_allsolid; + tr.fStartSolid = gpGlobals->trace_startsolid; + tr.fInOpen = gpGlobals->trace_inopen; + tr.fInWater = gpGlobals->trace_inwater; + tr.flFraction = gpGlobals->trace_fraction; + tr.flPlaneDist = gpGlobals->trace_plane_dist; + tr.pHit = gpGlobals->trace_ent; + tr.vecEndPos = gpGlobals->trace_endpos; + tr.vecPlaneNormal = gpGlobals->trace_plane_normal; + tr.iHitgroup = gpGlobals->trace_hitgroup; + return tr; +} + + +void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) +{ + SET_SIZE( ENT(pev), vecMin, vecMax ); +} + + +float UTIL_VecToYaw( const Vector &vec ) +{ + return VEC_TO_YAW(vec); +} + + +void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) +{ + SET_ORIGIN(ENT(pev), vecOrigin ); +} + +void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ) +{ + PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount ); +} + + +float UTIL_Approach( float target, float value, float speed ) +{ + float delta = target - value; + + if ( delta > speed ) + value += speed; + else if ( delta < -speed ) + value -= speed; + else + value = target; + + return value; +} + + +float UTIL_ApproachAngle( float target, float value, float speed ) +{ + target = UTIL_AngleMod( target ); + value = UTIL_AngleMod( target ); + + float delta = target - value; + + // Speed is assumed to be positive + if ( speed < 0 ) + speed = -speed; + + if ( delta < -180 ) + delta += 360; + else if ( delta > 180 ) + delta -= 360; + + if ( delta > speed ) + value += speed; + else if ( delta < -speed ) + value -= speed; + else + value = target; + + return value; +} + + +float UTIL_AngleDistance( float next, float cur ) +{ + float delta = next - cur; + + if ( delta < -180 ) + delta += 360; + else if ( delta > 180 ) + delta -= 360; + + return delta; +} + + +float UTIL_SplineFraction( float value, float scale ) +{ + value = scale * value; + float valueSquared = value * value; + + // Nice little ease-in, ease-out spline-like curve + return 3 * valueSquared - 2 * valueSquared * value; +} + + +char* UTIL_VarArgs( char *format, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, format); +#ifdef WIN32 + //overflow protection in MS version of function... + _vsnprintf_s( string, 1023, format, argptr ); +#else + vsprintf (string, format,argptr); +#endif + va_end (argptr); + + return string; +} + +Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) +{ + Vector tmp; + GET_AIM_VECTOR(pent, flSpeed, tmp); + return tmp; +} + +int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) +{ + if (sMaster) + { + edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(sMaster)); + + if ( !FNullEnt(pentTarget) ) + { + CBaseEntity *pMaster = CBaseEntity::Instance(pentTarget); + if ( pMaster && (pMaster->ObjectCaps() & FCAP_MASTER) ) + return pMaster->IsTriggered( pActivator ); + } + + ALERT(at_console, "Master was null or not a master!\n"); + } + + // if this isn't a master entity, just say yes. + return 1; +} + +BOOL UTIL_ShouldShowBlood( int color ) +{ + if ( color != DONT_BLEED ) + { + if ( color == BLOOD_COLOR_RED ) + { + if ( ns_cvar_float(violence_hblood) != 0 ) + return TRUE; + } + else + { + if ( ns_cvar_float(violence_ablood) != 0 ) + return TRUE; + } + } + return FALSE; +} + +int UTIL_PointContents( const Vector &vec ) +{ + int thePointContents = POINT_CONTENTS(vec); + return thePointContents; +} + +void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ) +{ + if ( !UTIL_ShouldShowBlood( color ) ) + return; + + if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) + color = 0; + + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); + WRITE_BYTE( TE_BLOODSTREAM ); + WRITE_COORD( origin.x ); + WRITE_COORD( origin.y ); + WRITE_COORD( origin.z ); + WRITE_COORD( direction.x ); + WRITE_COORD( direction.y ); + WRITE_COORD( direction.z ); + WRITE_BYTE( color ); + WRITE_BYTE( min( amount, 255 ) ); + MESSAGE_END(); +} + +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) +{ + if ( !UTIL_ShouldShowBlood( color ) ) + return; + + if ( color == DONT_BLEED || amount == 0 ) + return; + + if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) + color = 0; + + if ( g_pGameRules->IsMultiplayer() ) + { + // scale up blood effect in multiplayer for better visibility + amount *= 2; + } + + if ( amount > 255 ) + amount = 255; + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); + WRITE_BYTE( TE_BLOODSPRITE ); + WRITE_COORD( origin.x); // pos + WRITE_COORD( origin.y); + WRITE_COORD( origin.z); + WRITE_SHORT( g_sModelIndexBloodSpray ); // initial sprite model + WRITE_SHORT( g_sModelIndexBloodDrop ); // droplet sprite models + WRITE_BYTE( color ); // color index into host_basepal + WRITE_BYTE( min( max( 3, amount / 10 ), 16 ) ); // size + MESSAGE_END(); +} + +Vector UTIL_RandomBloodVector( void ) +{ + Vector direction; + + direction.x = RANDOM_FLOAT ( -1, 1 ); + direction.y = RANDOM_FLOAT ( -1, 1 ); + direction.z = RANDOM_FLOAT ( 0, 1 ); + + return direction; +} + + +void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) +{ + if ( UTIL_ShouldShowBlood( bloodColor ) ) + { + if ( bloodColor == BLOOD_COLOR_RED ) + UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG(0,5) ); + else + UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0,5) ); + } +} + + +void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) +{ + short entityIndex; + int index; + int message; + + if ( decalNumber < 0 ) + return; + + index = gDecals[ decalNumber ].index; + + if ( index < 0 ) + return; + + if (pTrace->flFraction == 1.0) + return; + + // Only decal BSP models + if ( pTrace->pHit ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit ); + if ( pEntity && !pEntity->IsBSPModel() ) + return; + entityIndex = ENTINDEX( pTrace->pHit ); + } + else + entityIndex = 0; + + message = TE_DECAL; + if ( entityIndex != 0 ) + { + if ( index > 255 ) + { + message = TE_DECALHIGH; + index -= 256; + } + } + else + { + message = TE_WORLDDECAL; + if ( index > 255 ) + { + message = TE_WORLDDECALHIGH; + index -= 256; + } + } + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( message ); + WRITE_COORD( pTrace->vecEndPos.x ); + WRITE_COORD( pTrace->vecEndPos.y ); + WRITE_COORD( pTrace->vecEndPos.z ); + WRITE_BYTE( index ); + if ( entityIndex ) + WRITE_SHORT( entityIndex ); + MESSAGE_END(); +} + +/* +============== +UTIL_PlayerDecalTrace + +A player is trying to apply his custom decal for the spray can. +Tell connected clients to display it, or use the default spray can decal +if the custom can't be loaded. +============== +*/ +void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ) +{ + int index; + + if (!bIsCustom) + { + if ( decalNumber < 0 ) + return; + + index = gDecals[ decalNumber ].index; + if ( index < 0 ) + return; + } + else + index = decalNumber; + + if (pTrace->flFraction == 1.0) + return; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_PLAYERDECAL ); + WRITE_BYTE ( playernum ); + WRITE_COORD( pTrace->vecEndPos.x ); + WRITE_COORD( pTrace->vecEndPos.y ); + WRITE_COORD( pTrace->vecEndPos.z ); + WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); + WRITE_BYTE( index ); + MESSAGE_END(); +} + +void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) +{ + if ( decalNumber < 0 ) + return; + + int index = gDecals[ decalNumber ].index; + if ( index < 0 ) + return; + + if (pTrace->flFraction == 1.0) + return; + + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos ); + WRITE_BYTE( TE_GUNSHOTDECAL ); + WRITE_COORD( pTrace->vecEndPos.x ); + WRITE_COORD( pTrace->vecEndPos.y ); + WRITE_COORD( pTrace->vecEndPos.z ); + WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); + WRITE_BYTE( index ); + MESSAGE_END(); +} + + +void UTIL_Sparks( const Vector &position ) +{ + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); + WRITE_BYTE( TE_SPARKS ); + WRITE_COORD( position.x ); + WRITE_COORD( position.y ); + WRITE_COORD( position.z ); + MESSAGE_END(); +} + + +void UTIL_Ricochet( const Vector &position, float scale ) +{ + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); + WRITE_BYTE( TE_ARMOR_RICOCHET ); + WRITE_COORD( position.x ); + WRITE_COORD( position.y ); + WRITE_COORD( position.z ); + WRITE_BYTE( (int)(scale*10) ); + MESSAGE_END(); +} + + +BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) +{ + // Everyone matches unless it's teamplay + if ( !g_pGameRules->IsTeamplay() ) + return TRUE; + + // Both on a team? + if ( *pTeamName1 != 0 && *pTeamName2 != 0 ) + { + if ( !_stricmp( pTeamName1, pTeamName2 ) ) // Same Team? + return TRUE; + } + + return FALSE; +} + + +void UTIL_StringToVector( float *pVector, const char *pString ) +{ + char *pstr, *pfront, tempString[128]; + int j; + + strcpy( tempString, pString ); + pstr = pfront = tempString; + + for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c + { + pVector[j] = atof( pfront ); + + while ( *pstr && *pstr != ' ' ) + pstr++; + if (!*pstr) + break; + pstr++; + pfront = pstr; + } + if (j < 2) + { + /* + ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n", + pkvd->szClassName, pkvd->szKeyName, pkvd->szValue ); + */ + for (j = j+1;j < 3; j++) + pVector[j] = 0; + } +} + + +void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) +{ + char *pstr, *pfront, tempString[128]; + int j; + + strcpy( tempString, pString ); + pstr = pfront = tempString; + + for ( j = 0; j < count; j++ ) // lifted from pr_edict.c + { + pVector[j] = atoi( pfront ); + + while ( *pstr && *pstr != ' ' ) + pstr++; + if (!*pstr) + break; + pstr++; + pfront = pstr; + } + + for ( j++; j < count; j++ ) + { + pVector[j] = 0; + } +} + +Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) +{ + Vector sourceVector = input; + + if ( sourceVector.x > clampSize.x ) + sourceVector.x -= clampSize.x; + else if ( sourceVector.x < -clampSize.x ) + sourceVector.x += clampSize.x; + else + sourceVector.x = 0; + + if ( sourceVector.y > clampSize.y ) + sourceVector.y -= clampSize.y; + else if ( sourceVector.y < -clampSize.y ) + sourceVector.y += clampSize.y; + else + sourceVector.y = 0; + + if ( sourceVector.z > clampSize.z ) + sourceVector.z -= clampSize.z; + else if ( sourceVector.z < -clampSize.z ) + sourceVector.z += clampSize.z; + else + sourceVector.z = 0; + + return sourceVector.Normalize(); +} + + +float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) +{ + Vector midUp = position; + midUp.z = minz; + + if (UTIL_PointContents(midUp) != CONTENTS_WATER) + return minz; + + midUp.z = maxz; + if (UTIL_PointContents(midUp) == CONTENTS_WATER) + return maxz; + + float diff = maxz - minz; + while (diff > 1.0) + { + midUp.z = minz + diff/2.0; + if (UTIL_PointContents(midUp) == CONTENTS_WATER) + { + minz = midUp.z; + } + else + { + maxz = midUp.z; + } + diff = maxz - minz; + } + + return midUp.z; +} + + +extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model + +void UTIL_Bubbles( Vector mins, Vector maxs, int count ) +{ + Vector mid = (mins + maxs) * 0.5; + + float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); + flHeight = flHeight - mins.z; + + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, mid ); + WRITE_BYTE( TE_BUBBLES ); + WRITE_COORD( mins.x ); // mins + WRITE_COORD( mins.y ); + WRITE_COORD( mins.z ); + WRITE_COORD( maxs.x ); // maxz + WRITE_COORD( maxs.y ); + WRITE_COORD( maxs.z ); + WRITE_COORD( flHeight ); // height + WRITE_SHORT( g_sModelIndexBubbles ); + WRITE_BYTE( count ); // count + WRITE_COORD( 8 ); // speed + MESSAGE_END(); +} + +void UTIL_BubbleTrail( Vector from, Vector to, int count ) +{ + float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); + flHeight = flHeight - from.z; + + if (flHeight < 8) + { + flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); + flHeight = flHeight - to.z; + if (flHeight < 8) + return; + + // UNDONE: do a ploink sound + flHeight = flHeight + to.z - from.z; + } + + if (count > 255) + count = 255; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BUBBLETRAIL ); + WRITE_COORD( from.x ); // mins + WRITE_COORD( from.y ); + WRITE_COORD( from.z ); + WRITE_COORD( to.x ); // maxz + WRITE_COORD( to.y ); + WRITE_COORD( to.z ); + WRITE_COORD( flHeight ); // height + WRITE_SHORT( g_sModelIndexBubbles ); + WRITE_BYTE( count ); // count + WRITE_COORD( 8 ); // speed + MESSAGE_END(); +} + + +void UTIL_Remove( CBaseEntity *pEntity ) +{ + if ( !pEntity ) + return; + + pEntity->UpdateOnRemove(); + pEntity->pev->flags |= FL_KILLME; + pEntity->pev->targetname = 0; +} + + +BOOL UTIL_IsValidEntity( edict_t *pent ) +{ + if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) + return FALSE; + return TRUE; +} + + +void UTIL_PrecacheOther( const char *szClassname ) +{ + edict_t *pent; + + pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); + if ( FNullEnt( pent ) ) + { + ALERT ( at_console, "NULL Ent in UTIL_PrecacheOther\n" ); + return; + } + + CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); + if (pEntity) + pEntity->Precache( ); + REMOVE_ENTITY(pent); +} + +//========================================================= +// UTIL_LogPrintf - Prints a logged message to console. +// Preceded by LOG: ( timestamp ) < message > +//========================================================= +void UTIL_LogPrintf( char *fmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start ( argptr, fmt ); +#ifdef WIN32 + //overflow protection in MS version of function... + _vsnprintf( string, 1023, fmt, argptr ); +#else + vsprintf ( string, fmt, argptr ); +#endif + va_end ( argptr ); + + // Print to server console + ALERT( at_logged, "%s", string ); +} + +//========================================================= +// UTIL_DotPoints - returns the dot product of a line from +// src to check and vecdir. +//========================================================= +float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ) +{ + Vector2D vec2LOS; + + vec2LOS = ( vecCheck - vecSrc ).Make2D(); + vec2LOS = vec2LOS.Normalize(); + + return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); +} + + +//========================================================= +// UTIL_StripToken - for redundant keynames +//========================================================= +void UTIL_StripToken( const char *pKey, char *pDest ) +{ + int i = 0; + + while ( pKey[i] && pKey[i] != '#' ) + { + pDest[i] = pKey[i]; + i++; + } + pDest[i] = 0; +} + + +// -------------------------------------------------------------- +// +// CSave +// +// -------------------------------------------------------------- +static int gSizes[FIELD_TYPECOUNT] = +{ + sizeof(float), // FIELD_FLOAT + sizeof(int), // FIELD_STRING + sizeof(int), // FIELD_ENTITY + sizeof(int), // FIELD_CLASSPTR + sizeof(int), // FIELD_EHANDLE + sizeof(int), // FIELD_entvars_t + sizeof(int), // FIELD_EDICT + sizeof(float)*3, // FIELD_VECTOR + sizeof(float)*3, // FIELD_POSITION_VECTOR + sizeof(int *), // FIELD_POINTER + sizeof(int), // FIELD_INTEGER + sizeof(int *), // FIELD_FUNCTION + sizeof(int), // FIELD_BOOLEAN + sizeof(short), // FIELD_SHORT + sizeof(char), // FIELD_CHARACTER + sizeof(float), // FIELD_TIME + sizeof(int), // FIELD_MODELNAME + sizeof(int), // FIELD_SOUNDNAME +}; + + +// Base class includes common SAVERESTOREDATA pointer, and manages the entity table +CSaveRestoreBuffer :: CSaveRestoreBuffer( void ) +{ + m_pdata = NULL; +} + + +CSaveRestoreBuffer :: CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) +{ + m_pdata = pdata; +} + + +CSaveRestoreBuffer :: ~CSaveRestoreBuffer( void ) +{ +} + +int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) +{ + if ( pEntity == NULL ) + return -1; + return EntityIndex( pEntity->pev ); +} + + +int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) +{ + if ( pevLookup == NULL ) + return -1; + return EntityIndex( ENT( pevLookup ) ); +} + +int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) +{ + return EntityIndex( ENT( eoLookup ) ); +} + + +int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) +{ + if ( !m_pdata || pentLookup == NULL ) + return -1; + + int i; + ENTITYTABLE *pTable; + + for ( i = 0; i < m_pdata->tableCount; i++ ) + { + pTable = m_pdata->pTable + i; + if ( pTable->pent == pentLookup ) + return i; + } + return -1; +} + + +edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) +{ + if ( !m_pdata || entityIndex < 0 ) + return NULL; + + int i; + ENTITYTABLE *pTable; + + for ( i = 0; i < m_pdata->tableCount; i++ ) + { + pTable = m_pdata->pTable + i; + if ( pTable->id == entityIndex ) + return pTable->pent; + } + return NULL; +} + + +int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) +{ + if ( !m_pdata || entityIndex < 0 ) + return 0; + if ( entityIndex > m_pdata->tableCount ) + return 0; + + m_pdata->pTable[ entityIndex ].flags |= flags; + + return m_pdata->pTable[ entityIndex ].flags; +} + + +void CSaveRestoreBuffer :: BufferRewind( int size ) +{ + if ( !m_pdata ) + return; + + if ( m_pdata->size < size ) + size = m_pdata->size; + + m_pdata->pCurrentData -= size; + m_pdata->size -= size; +} + +#ifndef _WIN32 +extern "C" { +unsigned _rotr ( unsigned val, int shift) +{ + register unsigned lobit; /* non-zero means lo bit set */ + register unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while (shift--) { + lobit = num & 1; /* get high bit */ + num >>= 1; /* shift right one bit */ + if (lobit) + num |= 0x80000000; /* set hi bit if lo bit was set */ + } + + return num; +} +} +#endif + +unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) +{ + unsigned int hash = 0; + + while ( *pszToken ) + hash = _rotr( hash, 4 ) ^ *pszToken++; + + return hash; +} + +unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) +{ + unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)m_pdata->tokenCount ); + +#if _DEBUG + static int tokensparsed = 0; + tokensparsed++; + if ( !m_pdata->tokenCount || !m_pdata->pTokens ) + ALERT( at_error, "No token table array in TokenHash()!" ); +#endif + + for ( int i=0; itokenCount; i++ ) + { +#if _DEBUG + static qboolean beentheredonethat = FALSE; + if ( i > 50 && !beentheredonethat ) + { + beentheredonethat = TRUE; + ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" ); + } +#endif + + int index = hash + i; + if ( index >= m_pdata->tokenCount ) + index -= m_pdata->tokenCount; + + if ( !m_pdata->pTokens[index] || strcmp( pszToken, m_pdata->pTokens[index] ) == 0 ) + { + m_pdata->pTokens[index] = (char *)pszToken; + return index; + } + } + + // Token hash table full!!! + // [Consider doing overflow table(s) after the main table & limiting linear hash table search] + ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!" ); + return 0; +} + +void CSave :: WriteData( const char *pname, int size, const char *pdata ) +{ + BufferField( pname, size, pdata ); +} + + +void CSave :: WriteShort( const char *pname, const short *data, int count ) +{ + BufferField( pname, sizeof(short) * count, (const char *)data ); +} + + +void CSave :: WriteInt( const char *pname, const int *data, int count ) +{ + BufferField( pname, sizeof(int) * count, (const char *)data ); +} + + +void CSave :: WriteFloat( const char *pname, const float *data, int count ) +{ + BufferField( pname, sizeof(float) * count, (const char *)data ); +} + + +void CSave :: WriteTime( const char *pname, const float *data, int count ) +{ + int i; + Vector tmp, input; + + BufferHeader( pname, sizeof(float) * count ); + for ( i = 0; i < count; i++ ) + { + float tmp = data[0]; + + // Always encode time as a delta from the current time so it can be re-based if loaded in a new level + // Times of 0 are never written to the file, so they will be restored as 0, not a relative time + if ( m_pdata ) + tmp -= m_pdata->time; + + BufferData( (const char *)&tmp, sizeof(float) ); + data ++; + } +} + + +void CSave :: WriteString( const char *pname, const char *pdata ) +{ +#ifdef TOKENIZE + short token = (short)TokenHash( pdata ); + WriteShort( pname, &token, 1 ); +#else + BufferField( pname, strlen(pdata) + 1, pdata ); +#endif +} + + +void CSave :: WriteString( const char *pname, const int *stringId, int count ) +{ + int i, size; + +#ifdef TOKENIZE + short token = (short)TokenHash( STRING( *stringId ) ); + WriteShort( pname, &token, 1 ); +#else +#if 0 + if ( count != 1 ) + ALERT( at_error, "No string arrays!\n" ); + WriteString( pname, (char *)STRING(*stringId) ); +#endif + + size = 0; + for ( i = 0; i < count; i++ ) + size += strlen( STRING( stringId[i] ) ) + 1; + + BufferHeader( pname, size ); + for ( i = 0; i < count; i++ ) + { + const char *pString = STRING(stringId[i]); + BufferData( pString, strlen(pString)+1 ); + } +#endif +} + + +void CSave :: WriteVector( const char *pname, const Vector &value ) +{ + WriteVector( pname, &value.x, 1 ); +} + + +void CSave :: WriteVector( const char *pname, const float *value, int count ) +{ + BufferHeader( pname, sizeof(float) * 3 * count ); + BufferData( (const char *)value, sizeof(float) * 3 * count ); +} + + + +void CSave :: WritePositionVector( const char *pname, const Vector &value ) +{ + + if ( m_pdata && m_pdata->fUseLandmark ) + { + Vector tmp = value - m_pdata->vecLandmarkOffset; + WriteVector( pname, tmp ); + } + + WriteVector( pname, value ); +} + + +void CSave :: WritePositionVector( const char *pname, const float *value, int count ) +{ + int i; + Vector tmp, input; + + BufferHeader( pname, sizeof(float) * 3 * count ); + for ( i = 0; i < count; i++ ) + { + Vector tmp( value[0], value[1], value[2] ); + + if ( m_pdata && m_pdata->fUseLandmark ) + tmp = tmp - m_pdata->vecLandmarkOffset; + + BufferData( (const char *)&tmp.x, sizeof(float) * 3 ); + value += 3; + } +} + + +void CSave :: WriteFunction( const char *pname, const int *data, int count ) +{ + const char *functionName; + + functionName = NAME_FOR_FUNCTION( *data ); + if ( functionName ) + BufferField( pname, strlen(functionName) + 1, functionName ); + else + ALERT( at_error, "Invalid function pointer in entity!" ); +} + + +void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) +{ + int i; + TYPEDESCRIPTION *pField; + + for ( i = 0; i < ENTVARS_COUNT; i++ ) + { + pField = &gEntvarsDescription[i]; + + if ( !stricmp( pField->fieldName, pkvd->szKeyName ) ) + { + switch( pField->fieldType ) + { + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + case FIELD_STRING: + (*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue ); + break; + + case FIELD_TIME: + case FIELD_FLOAT: + (*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); + break; + + case FIELD_INTEGER: + (*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue ); + break; + + case FIELD_POSITION_VECTOR: + case FIELD_VECTOR: + UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue ); + break; + + default: + case FIELD_EVARS: + case FIELD_CLASSPTR: + case FIELD_EDICT: + case FIELD_ENTITY: + case FIELD_POINTER: + ALERT( at_error, "Bad field in entity!!\n" ); + break; + } + pkvd->fHandled = TRUE; + return; + } + } +} + + + +int CSave :: WriteEntVars( const char *pname, entvars_t *pev ) +{ + return WriteFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); +} + + + +int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + int i, j, actualCount, emptyCount; + TYPEDESCRIPTION *pTest; + int entityArray[MAX_ENTITYARRAY]; + + // Precalculate the number of empty fields + emptyCount = 0; + for ( i = 0; i < fieldCount; i++ ) + { + void *pOutputData; + pOutputData = ((char *)pBaseData + pFields[i].fieldOffset ); + if ( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) ) + emptyCount++; + } + + // Empty fields will not be written, write out the actual number of fields to be written + actualCount = fieldCount - emptyCount; + WriteInt( pname, &actualCount, 1 ); + + for ( i = 0; i < fieldCount; i++ ) + { + void *pOutputData; + pTest = &pFields[ i ]; + pOutputData = ((char *)pBaseData + pTest->fieldOffset ); + + // UNDONE: Must we do this twice? + if ( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) ) + continue; + + switch( pTest->fieldType ) + { + case FIELD_FLOAT: + WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); + break; + case FIELD_TIME: + WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); + break; + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + case FIELD_STRING: + WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); + break; + case FIELD_CLASSPTR: + case FIELD_EVARS: + case FIELD_EDICT: + case FIELD_ENTITY: + case FIELD_EHANDLE: + if ( pTest->fieldSize > MAX_ENTITYARRAY ) + ALERT( at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY ); + for ( j = 0; j < pTest->fieldSize; j++ ) + { + switch( pTest->fieldType ) + { + case FIELD_EVARS: + entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); + break; + case FIELD_CLASSPTR: + entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); + break; + case FIELD_EDICT: + entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); + break; + case FIELD_ENTITY: + entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); + break; + case FIELD_EHANDLE: + entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); + break; + } + } + WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); + break; + case FIELD_POSITION_VECTOR: + WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); + break; + case FIELD_VECTOR: + WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); + break; + + case FIELD_BOOLEAN: + case FIELD_INTEGER: + WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); + break; + + case FIELD_SHORT: + WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); + break; + + case FIELD_CHARACTER: + WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); + break; + + // For now, just write the address out, we're not going to change memory while doing this yet! + case FIELD_POINTER: + WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); + break; + + case FIELD_FUNCTION: + WriteFunction( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); + break; + default: + ALERT( at_error, "Bad field type\n" ); + } + } + + return 1; +} + + +void CSave :: BufferString( char *pdata, int len ) +{ + char c = 0; + + BufferData( pdata, len ); // Write the string + BufferData( &c, 1 ); // Write a null terminator +} + + +int CSave :: DataEmpty( const char *pdata, int size ) +{ + for ( int i = 0; i < size; i++ ) + { + if ( pdata[i] ) + return 0; + } + return 1; +} + + +void CSave :: BufferField( const char *pname, int size, const char *pdata ) +{ + BufferHeader( pname, size ); + BufferData( pdata, size ); +} + + +void CSave :: BufferHeader( const char *pname, int size ) +{ + short hashvalue = TokenHash( pname ); + if ( size > 1<<(sizeof(short)*8) ) + ALERT( at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!" ); + BufferData( (const char *)&size, sizeof(short) ); + BufferData( (const char *)&hashvalue, sizeof(short) ); +} + + +void CSave :: BufferData( const char *pdata, int size ) +{ + if ( !m_pdata ) + return; + + if ( m_pdata->size + size > m_pdata->bufferSize ) + { + ALERT( at_error, "Save/Restore overflow!" ); + m_pdata->size = m_pdata->bufferSize; + return; + } + + memcpy( m_pdata->pCurrentData, pdata, size ); + m_pdata->pCurrentData += size; + m_pdata->size += size; +} + + + +// -------------------------------------------------------------- +// +// CRestore +// +// -------------------------------------------------------------- + +int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ) +{ + int i, j, stringCount, fieldNumber, entityIndex; + TYPEDESCRIPTION *pTest; + float time, timeData; + Vector position; + edict_t *pent; + char *pString; + + time = 0; + position = Vector(0,0,0); + + if ( m_pdata ) + { + time = m_pdata->time; + if ( m_pdata->fUseLandmark ) + position = m_pdata->vecLandmarkOffset; + } + + for ( i = 0; i < fieldCount; i++ ) + { + fieldNumber = (i+startField)%fieldCount; + pTest = &pFields[ fieldNumber ]; + if ( !stricmp( pTest->fieldName, pName ) ) + { + if ( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL) ) + { + for ( j = 0; j < pTest->fieldSize; j++ ) + { + void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j*gSizes[pTest->fieldType]) ); + void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; + + switch( pTest->fieldType ) + { + case FIELD_TIME: + timeData = *(float *)pInputData; + // Re-base time variables + timeData += time; + *((float *)pOutputData) = timeData; + break; + case FIELD_FLOAT: + *((float *)pOutputData) = *(float *)pInputData; + break; + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + case FIELD_STRING: + // Skip over j strings + pString = (char *)pData; + for ( stringCount = 0; stringCount < j; stringCount++ ) + { + while (*pString) + pString++; + pString++; + } + pInputData = pString; + if ( strlen( (char *)pInputData ) == 0 ) + *((int *)pOutputData) = 0; + else + { + int string; + + string = ALLOC_STRING( (char *)pInputData ); + + *((int *)pOutputData) = string; + + if ( !FStringNull( string ) && m_precache ) + { + if ( pTest->fieldType == FIELD_MODELNAME ) + PRECACHE_MODEL( (char *)STRING( string ) ); + else if ( pTest->fieldType == FIELD_SOUNDNAME ) + PRECACHE_SOUND( (char *)STRING( string ) ); + } + } + break; + case FIELD_EVARS: + entityIndex = *( int *)pInputData; + pent = EntityFromIndex( entityIndex ); + if ( pent ) + *((entvars_t **)pOutputData) = VARS(pent); + else + *((entvars_t **)pOutputData) = NULL; + break; + case FIELD_CLASSPTR: + entityIndex = *( int *)pInputData; + pent = EntityFromIndex( entityIndex ); + if ( pent ) + *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); + else + *((CBaseEntity **)pOutputData) = NULL; + break; + case FIELD_EDICT: + entityIndex = *( int *)pInputData; + pent = EntityFromIndex( entityIndex ); + *((edict_t **)pOutputData) = pent; + break; + case FIELD_EHANDLE: + // Input and Output sizes are different! + pOutputData = (char *)pOutputData + j*(sizeof(EHANDLE) - gSizes[pTest->fieldType]); + entityIndex = *( int *)pInputData; + pent = EntityFromIndex( entityIndex ); + if ( pent ) + *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); + else + *((EHANDLE *)pOutputData) = NULL; + break; + case FIELD_ENTITY: + entityIndex = *( int *)pInputData; + pent = EntityFromIndex( entityIndex ); + if ( pent ) + *((EOFFSET *)pOutputData) = OFFSET(pent); + else + *((EOFFSET *)pOutputData) = 0; + break; + case FIELD_VECTOR: + ((float *)pOutputData)[0] = ((float *)pInputData)[0]; + ((float *)pOutputData)[1] = ((float *)pInputData)[1]; + ((float *)pOutputData)[2] = ((float *)pInputData)[2]; + break; + case FIELD_POSITION_VECTOR: + ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; + ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; + ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; + break; + + case FIELD_BOOLEAN: + case FIELD_INTEGER: + *((int *)pOutputData) = *( int *)pInputData; + break; + + case FIELD_SHORT: + *((short *)pOutputData) = *( short *)pInputData; + break; + + case FIELD_CHARACTER: + *((char *)pOutputData) = *( char *)pInputData; + break; + + case FIELD_POINTER: + *((int *)pOutputData) = *( int *)pInputData; + break; + case FIELD_FUNCTION: + if ( strlen( (char *)pInputData ) == 0 ) + *((int *)pOutputData) = 0; + else + *((int *)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); + break; + + default: + ALERT( at_error, "Bad field type\n" ); + } + } + } +#if 0 + else + { + ALERT( at_console, "Skipping global field %s\n", pName ); + } +#endif + return fieldNumber; + } + } + + return -1; +} + + +int CRestore::ReadEntVars( const char *pname, entvars_t *pev ) +{ + return ReadFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); +} + + +int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) +{ + unsigned short i, token; + int lastField, fileCount; + HEADER header; + + i = ReadShort(); + ASSERT( i == sizeof(int) ); // First entry should be an int + + token = ReadShort(); + + // Check the struct name + if ( token != TokenHash(pname) ) // Field Set marker + { +// ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); + BufferRewind( 2*sizeof(short) ); + return 0; + } + + // Skip over the struct name + fileCount = ReadInt(); // Read field count + + lastField = 0; // Make searches faster, most data is read/written in the same order + + // Clear out base data + for ( i = 0; i < fieldCount; i++ ) + { + // Don't clear global fields + if ( !m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL) ) + memset( ((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ); + } + + for ( i = 0; i < fileCount; i++ ) + { + BufferReadHeader( &header ); + lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData ); + lastField++; + } + + return 1; +} + + +void CRestore::BufferReadHeader( HEADER *pheader ) +{ + ASSERT( pheader!=NULL ); + pheader->size = ReadShort(); // Read field size + pheader->token = ReadShort(); // Read field name token + pheader->pData = BufferPointer(); // Field Data is next + BufferSkipBytes( pheader->size ); // Advance to next field +} + + +short CRestore::ReadShort( void ) +{ + short tmp = 0; + + BufferReadBytes( (char *)&tmp, sizeof(short) ); + + return tmp; +} + +int CRestore::ReadInt( void ) +{ + int tmp = 0; + + BufferReadBytes( (char *)&tmp, sizeof(int) ); + + return tmp; +} + +int CRestore::ReadNamedInt( const char *pName ) +{ + HEADER header; + + BufferReadHeader( &header ); + return ((int *)header.pData)[0]; +} + +char *CRestore::ReadNamedString( const char *pName ) +{ + HEADER header; + + BufferReadHeader( &header ); +#ifdef TOKENIZE + return (char *)(m_pdata->pTokens[*(short *)header.pData]); +#else + return (char *)header.pData; +#endif +} + + +char *CRestore::BufferPointer( void ) +{ + if ( !m_pdata ) + return NULL; + + return m_pdata->pCurrentData; +} + +void CRestore::BufferReadBytes( char *pOutput, int size ) +{ + ASSERT( m_pdata !=NULL ); + + if ( !m_pdata || Empty() ) + return; + + if ( (m_pdata->size + size) > m_pdata->bufferSize ) + { + ALERT( at_error, "Restore overflow!" ); + m_pdata->size = m_pdata->bufferSize; + return; + } + + if ( pOutput ) + memcpy( pOutput, m_pdata->pCurrentData, size ); + m_pdata->pCurrentData += size; + m_pdata->size += size; +} + + +void CRestore::BufferSkipBytes( int bytes ) +{ + BufferReadBytes( NULL, bytes ); +} + +int CRestore::BufferSkipZString( void ) +{ + char *pszSearch; + int len; + + if ( !m_pdata ) + return 0; + + int maxLen = m_pdata->bufferSize - m_pdata->size; + + len = 0; + pszSearch = m_pdata->pCurrentData; + while ( *pszSearch++ && len < maxLen ) + len++; + + len++; + + BufferSkipBytes( len ); + + return len; +} + +int CRestore::BufferCheckZString( const char *string ) +{ + if ( !m_pdata ) + return 0; + + int maxLen = m_pdata->bufferSize - m_pdata->size; + int len = strlen( string ); + if ( len <= maxLen ) + { + if ( !strncmp( string, m_pdata->pCurrentData, len ) ) + return 1; + } + return 0; +} + diff --git a/main/source/dlls/util.cpp~ b/main/source/dlls/util.cpp~ deleted file mode 100644 index 5a5633ce..00000000 --- a/main/source/dlls/util.cpp~ +++ /dev/null @@ -1,2617 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== util.cpp ======================================================== - - Utility code. Really not optional after all. - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include -#include "../engine/shake.h" -#include "decals.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "..mod/AvHServerUtil.h" -#include "..mod/AvHNetworkMessages.h" -#include "..mod/AvHServerVariables.h" -//#include "..mod/AvHSharedUtil.h" -//#include "..mod/AvHGamerules.h" - -float UTIL_WeaponTimeBase( void ) -{ - return 0.0; -} - -static unsigned int glSeed = 0; - -unsigned int seed_table[ 256 ] = -{ - 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, - 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, - 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, - 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, - 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, - 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, - 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, - 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, - 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, - 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, - 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, - 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, - 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, - 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, - 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, - 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 -}; - -unsigned int U_Random( void ) -{ - glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - - return ( ++glSeed & 0x0fffffff ); -} - -void U_Srand( unsigned int seed ) -{ - glSeed = seed_table[ seed & 0xff ]; -} - -/* -===================== -UTIL_SharedRandomLong -===================== -*/ -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) -{ - unsigned int range; - - U_Srand( (int)seed + low + high ); - - range = high - low + 1; - if ( !(range - 1) ) - { - return low; - } - else - { - int offset; - int rnum; - - rnum = U_Random(); - - offset = rnum % range; - - return (low + offset); - } -} - -/* -===================== -UTIL_SharedRandomFloat -===================== -*/ -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) -{ - U_Srand( (int)seed + *(int *)&low + *(int *)&high ); - - U_Random(); - U_Random(); - - float range = high - low; - if ( !range ) - { - return low; - } - else - { - int tensixrand; - float offset; - - tensixrand = U_Random() & 65535; - - offset = (float)tensixrand / 65536.0; - - return (low + offset * range ); - } -} - -void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner ) -{ - pev->startpos = vecOrigin; - // Trace out line to end pos - TraceResult tr; - UTIL_MakeVectors( vecAngles ); - UTIL_TraceLine( pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr); - pev->endpos = tr.vecEndPos; - - // Now compute how long it will take based on current velocity - Vector vecTravel = pev->endpos - pev->startpos; - float travelTime = 0.0; - if ( pev->velocity.Length() > 0 ) - { - travelTime = vecTravel.Length() / pev->velocity.Length(); - } - pev->starttime = gpGlobals->time; - pev->impacttime = gpGlobals->time + travelTime; -} - -int g_groupmask = 0; -int g_groupop = 0; - -// Normal overrides -void UTIL_SetGroupTrace( int groupmask, int op ) -{ - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -void UTIL_UnsetGroupTrace( void ) -{ - g_groupmask = 0; - g_groupop = 0; - - ENGINE_SETGROUPMASK( 0, 0 ); -} - -// Smart version, it'll clean itself up when it pops off stack -UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op ) -{ - m_oldgroupmask = g_groupmask; - m_oldgroupop = g_groupop; - - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -UTIL_GroupTrace::~UTIL_GroupTrace( void ) -{ - g_groupmask = m_oldgroupmask; - g_groupop = m_oldgroupop; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -TYPEDESCRIPTION gEntvarsDescription[] = -{ - DEFINE_ENTITY_FIELD( classname, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), - DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ), - - DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ), - DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ), - - // Having these fields be local to the individual levels makes it easier to test those levels individually. - DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( netname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( message, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ), -}; - -#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0])) - - -#ifdef DEBUG -edict_t *DBG_EntOfVars( const entvars_t *pev ) -{ - if (pev->pContainingEntity != NULL) - return pev->pContainingEntity; - ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); - edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); - if (pent == NULL) - ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); - ((entvars_t *)pev)->pContainingEntity = pent; - return pent; -} -#endif //DEBUG - - -//#ifdef DEBUG -// void -//DBG_AssertFunction( -// BOOL fExpr, -// const char* szExpr, -// const char* szFile, -// int szLine, -// const char* szMessage) -// { -// if (fExpr) -// return; -// char szOut[512]; -// if (szMessage != NULL) -// sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage); -// else -// sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine); -// ALERT(at_console, szOut); -// } -//#endif // DEBUG - -BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon ); -} - -// ripped this out of the engine -float UTIL_AngleMod(float a) -{ - if (a < 0) - { - a = a + 360 * ((int)(a / 360) + 1); - } - else if (a >= 360) - { - a = a - 360 * ((int)(a / 360)); - } - // a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); - return a; -} - -float UTIL_AngleDiff( float destAngle, float srcAngle ) -{ - float delta; - - delta = destAngle - srcAngle; - if ( destAngle > srcAngle ) - { - if ( delta >= 180 ) - delta -= 360; - } - else - { - if ( delta <= -180 ) - delta += 360; - } - return delta; -} - -Vector UTIL_VecToAngles( const Vector &vec ) -{ - float rgflVecOut[3]; - VEC_TO_ANGLES(vec, rgflVecOut); - return Vector(rgflVecOut); -} - -// float UTIL_MoveToOrigin( edict_t *pent, const Vector vecGoal, float flDist, int iMoveType ) -void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType ) -{ - float rgfl[3]; - vecGoal.CopyToArray(rgfl); -// return MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); - MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); -} - - -int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - - count = 0; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? - continue; - - if ( mins.x > pEdict->v.absmax.x || - mins.y > pEdict->v.absmax.y || - mins.z > pEdict->v.absmax.z || - maxs.x < pEdict->v.absmin.x || - maxs.y < pEdict->v.absmin.y || - maxs.z < pEdict->v.absmin.z ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - return count; -} - - -int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - float distance, delta; - - count = 0; - float radiusSquared = radius * radius; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? - continue; - - // Use origin for X & Y since they are centered for all monsters - // Now X - delta = center.x - pEdict->v.origin.x;//(pEdict->v.absmin.x + pEdict->v.absmax.x)*0.5; - delta *= delta; - - if ( delta > radiusSquared ) - continue; - distance = delta; - - // Now Y - delta = center.y - pEdict->v.origin.y;//(pEdict->v.absmin.y + pEdict->v.absmax.y)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - // Now Z - delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - - return count; -} - - -CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -int UTIL_CountEntitiesInSphere(const Vector& inVecCenter, float inRadius, const char* inClassName) -{ - int theNumEntities = 0; - - CBaseEntity* theEntity = NULL; - while((theEntity = UTIL_FindEntityInSphere(theEntity, inVecCenter, inRadius)) != NULL) - { - if(!strcmp(STRING(theEntity->pev->classname), inClassName)) - { - theNumEntities++; - } - } - - return theNumEntities; -} - - -CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue ); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -CBaseEntity *UTIL_FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "classname", szName ); -} - -CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "targetname", szName ); -} - - -CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius ) -{ - CBaseEntity *pEntity = NULL; - - pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever ); - if (pEntity) - return pEntity; - - CBaseEntity *pSearch = NULL; - float flMaxDist2 = flRadius * flRadius; - while ((pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever )) != NULL) - { - float flDist2 = (pSearch->pev->origin - vecSrc).Length(); - flDist2 = flDist2 * flDist2; - if (flMaxDist2 > flDist2) - { - pEntity = pSearch; - flMaxDist2 = flDist2; - } - } - return pEntity; -} - - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) -{ - CBaseEntity *pPlayer = NULL; - - if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) - { - edict_t *pPlayerEdict = INDEXENT( playerIndex ); - if ( pPlayerEdict && !pPlayerEdict->free ) - { - pPlayer = CBaseEntity::Instance( pPlayerEdict ); - } - } - - return pPlayer; -} - - -void UTIL_MakeVectors( const Vector &vecAngles ) -{ - MAKE_VECTORS( vecAngles ); -} - - -void UTIL_MakeAimVectors( const Vector &vecAngles ) -{ - float rgflVec[3]; - vecAngles.CopyToArray(rgflVec); - rgflVec[0] = -rgflVec[0]; - MAKE_VECTORS(rgflVec); -} - - -#define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) - -void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) -{ - MAKE_VECTORS(vec); - - float tmp; - pgv->v_right = pgv->v_right * -1; - - SWAP(pgv->v_forward.y, pgv->v_right.x, tmp); - SWAP(pgv->v_forward.z, pgv->v_up.x, tmp); - SWAP(pgv->v_right.z, pgv->v_up.y, tmp); -} - - -void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ) -{ - float rgfl[3]; - vecOrigin.CopyToArray(rgfl); - - if (samp && *samp == '!') - { - char name[32]; - if (SENTENCEG_Lookup(samp, name) >= 0) - EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); - } - else - EMIT_AMBIENT_SOUND(entity, rgfl, samp, vol, attenuation, fFlags, pitch); -} - -static unsigned short FixedUnsigned16( float value, float scale ) -{ - int output; - - output = value * scale; - if ( output < 0 ) - output = 0; - if ( output > 0xFFFF ) - output = 0xFFFF; - - return (unsigned short)output; -} - -static short FixedSigned16( float value, float scale ) -{ - int output; - - output = value * scale; - - if ( output > 32767 ) - output = 32767; - - if ( output < -32768 ) - output = -32768; - - return (short)output; -} - -// Shake the screen of all clients within radius -// radius == 0, shake all clients -// UNDONE: Allow caller to shake clients not ONGROUND? -// UNDONE: Fix falloff model (disabled)? -// UNDONE: Affect user controls? -void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ) -{ - int i; - float localAmplitude; - ScreenShake shake; - - shake.duration = FixedUnsigned16( duration, 1<<12 ); // 4.12 fixed - shake.frequency = FixedUnsigned16( frequency, 1<<8 ); // 8.8 fixed - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( !pPlayer /*|| !(pPlayer->pev->flags & FL_ONGROUND)*/ ) // Don't shake if not onground - continue; - - localAmplitude = 0; - - if ( radius <= 0 ) - localAmplitude = amplitude; - else - { - Vector delta = center - pPlayer->pev->origin; - float distance = delta.Length(); - - // Had to get rid of this falloff - it didn't work well - if ( distance < radius ) - localAmplitude = amplitude;//radius - distance; - } - if ( localAmplitude ) - { - shake.amplitude = FixedUnsigned16( localAmplitude, 1<<12 ); // 4.12 fixed - - NetMsg_Shake( pPlayer->pev, shake ); - } - } -} - - - -void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency, float duration ) -{ - UTIL_ScreenShake( center, amplitude, frequency, duration, 0 ); -} - - -void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - fade.duration = FixedUnsigned16( fadeTime, 1<<12 ); // 4.12 fixed - fade.holdTime = FixedUnsigned16( fadeHold, 1<<12 ); // 4.12 fixed - fade.r = (int)color.x; - fade.g = (int)color.y; - fade.b = (int)color.z; - fade.a = alpha; - fade.fadeFlags = flags; -} - - -void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - NetMsg_Fade( pEntity->pev, fade ); -} - - -void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - int i; - ScreenFade fade; - - - UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - UTIL_ScreenFadeWrite( fade, pPlayer ); - } -} - - -void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - ScreenFade fade; - - UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - UTIL_ScreenFadeWrite( fade, pEntity ); -} - - -void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pEntity->edict() ); - WRITE_BYTE( TE_TEXTMESSAGE ); - WRITE_BYTE( textparms.channel & 0xFF ); - - WRITE_SHORT( FixedSigned16( textparms.x, 1<<13 ) ); - WRITE_SHORT( FixedSigned16( textparms.y, 1<<13 ) ); - WRITE_BYTE( textparms.effect ); - - WRITE_BYTE( textparms.r1 ); - WRITE_BYTE( textparms.g1 ); - WRITE_BYTE( textparms.b1 ); - WRITE_BYTE( textparms.a1 ); - - WRITE_BYTE( textparms.r2 ); - WRITE_BYTE( textparms.g2 ); - WRITE_BYTE( textparms.b2 ); - WRITE_BYTE( textparms.a2 ); - - WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1<<8 ) ); - - if ( textparms.effect == 2 ) - WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1<<8 ) ); - - if ( strlen( pMessage ) < 512 ) - { - WRITE_STRING( pMessage ); - } - else - { - char tmp[512]; - strncpy( tmp, pMessage, 511 ); - tmp[511] = 0; - WRITE_STRING( tmp ); - } - MESSAGE_END(); -} - -void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) -{ - int i; - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_HudMessage( pPlayer, textparms, pMessage ); - } -} - - -void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - vector message; - message.push_back( msg_name ); - if( param1 ) message.push_back( param1 ); - if( param2 ) message.push_back( param2 ); - if( param3 ) message.push_back( param3 ); - if( param4 ) message.push_back( param4 ); - NetMsg_TextMsg( msg_dest, message ); -} - -void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - vector message; - message.push_back( msg_name ); - if( param1 ) message.push_back( param1 ); - if( param2 ) message.push_back( param2 ); - if( param3 ) message.push_back( param3 ); - if( param4 ) message.push_back( param4 ); - NetMsg_TextMsg( client, msg_dest, message ); -} - -void UTIL_SayText( const char *pText, CBaseEntity *pEntity, int inEntIndex) -{ - if ( !pEntity->IsNetClient() ) - return; - - string theLocation(" "); - - if(inEntIndex == -1) - { - inEntIndex = pEntity->entindex(); - } - else - { - CBaseEntity* theSpeakingPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(inEntIndex)); - if(theSpeakingPlayer) - { - theLocation = AvHSUGetLocationText(theSpeakingPlayer); - } - } - - NetMsg_SayText( pEntity->pev, inEntIndex, string( pText ), theLocation ); -} - -void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity, int inEntIndex) -{ - string theLocation(" "); - - if(inEntIndex == -1) - { - inEntIndex = pEntity->entindex(); - } - else - { - CBaseEntity* theSpeakingPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(inEntIndex)); - if(theSpeakingPlayer) - { - theLocation = AvHSUGetLocationText(theSpeakingPlayer); - } - } - - NetMsg_SayText( inEntIndex, string( pText ), theLocation ); -} - -void UTIL_Tutorial( CBaseEntity *pEntity, const char *pMessage ) -{ - // TODO: Be able to turn these off as a preference - hudtextparms_t theTextParms; - - // Init text parms - theTextParms.x = -1; - theTextParms.y = .8; - theTextParms.effect = 0; - theTextParms.r1 = 240; - theTextParms.g1 = 240; - theTextParms.b1 = 240; - theTextParms.a1 = 128; - theTextParms.r2 = 240; - theTextParms.g2 = 240; - theTextParms.b2 = 240; - theTextParms.a2 = 128; - theTextParms.fadeinTime = .3f; - theTextParms.fadeoutTime = .3f; - theTextParms.holdTime = 6.0f; - theTextParms.fxTime = .25f; - theTextParms.channel = 1; - - UTIL_HudMessage( pEntity, theTextParms, pMessage); -} - -void UTIL_Error( CBaseEntity *pEntity, const char *pMessage ) -{ - hudtextparms_t theTextParms; - - // Init text parms - theTextParms.x = -1; - theTextParms.y = .8; - theTextParms.effect = 0; - theTextParms.r1 = 240; - theTextParms.g1 = 100; - theTextParms.b1 = 100; - theTextParms.a1 = 128; - theTextParms.r2 = 240; - theTextParms.g2 = 100; - theTextParms.b2 = 100; - theTextParms.a2 = 128; - theTextParms.fadeinTime = .3f; - theTextParms.fadeoutTime = .3f; - theTextParms.holdTime = 2.0f; - theTextParms.fxTime = .25f; - theTextParms.channel = 1; - - UTIL_HudMessage( pEntity, theTextParms, pMessage); -} - -char *UTIL_dtos1( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos2( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos3( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos4( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - NetMsg_HudText( pEntity->pev, string( pString ) ); -} - -void UTIL_ShowMessage2( const char *pString, CBaseEntity *pEntity, SHOWMESSAGE_TYPE type) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - NetMsg_HudText2( pEntity->pev, string( pString ), type ); -} - - -void UTIL_ShowMessageAll( const char *pString ) -{ - int i; - - // loop through all players - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_ShowMessage( pString, pPlayer ); - } -} - -// Overloaded to add IGNORE_GLASS -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); -} - - -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); -} - - -void UTIL_TraceHull( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_HULL( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), hullNumber, pentIgnore, ptr ); -} - -void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr ) -{ - g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr ); -} - - -TraceResult UTIL_GetGlobalTrace( ) -{ - TraceResult tr; - - tr.fAllSolid = gpGlobals->trace_allsolid; - tr.fStartSolid = gpGlobals->trace_startsolid; - tr.fInOpen = gpGlobals->trace_inopen; - tr.fInWater = gpGlobals->trace_inwater; - tr.flFraction = gpGlobals->trace_fraction; - tr.flPlaneDist = gpGlobals->trace_plane_dist; - tr.pHit = gpGlobals->trace_ent; - tr.vecEndPos = gpGlobals->trace_endpos; - tr.vecPlaneNormal = gpGlobals->trace_plane_normal; - tr.iHitgroup = gpGlobals->trace_hitgroup; - return tr; -} - - -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) -{ - SET_SIZE( ENT(pev), vecMin, vecMax ); -} - - -float UTIL_VecToYaw( const Vector &vec ) -{ - return VEC_TO_YAW(vec); -} - - -void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) -{ - SET_ORIGIN(ENT(pev), vecOrigin ); -} - -void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ) -{ - PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount ); -} - - -float UTIL_Approach( float target, float value, float speed ) -{ - float delta = target - value; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_ApproachAngle( float target, float value, float speed ) -{ - target = UTIL_AngleMod( target ); - value = UTIL_AngleMod( target ); - - float delta = target - value; - - // Speed is assumed to be positive - if ( speed < 0 ) - speed = -speed; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_AngleDistance( float next, float cur ) -{ - float delta = next - cur; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - return delta; -} - - -float UTIL_SplineFraction( float value, float scale ) -{ - value = scale * value; - float valueSquared = value * value; - - // Nice little ease-in, ease-out spline-like curve - return 3 * valueSquared - 2 * valueSquared * value; -} - - -char* UTIL_VarArgs( char *format, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, format); -#ifdef WIN32 - //overflow protection in MS version of function... - _vsnprintf_s( string, 1023, format, argptr ); -#else - vsprintf (string, format,argptr); -#endif - va_end (argptr); - - return string; -} - -Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) -{ - Vector tmp; - GET_AIM_VECTOR(pent, flSpeed, tmp); - return tmp; -} - -int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) -{ - if (sMaster) - { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(sMaster)); - - if ( !FNullEnt(pentTarget) ) - { - CBaseEntity *pMaster = CBaseEntity::Instance(pentTarget); - if ( pMaster && (pMaster->ObjectCaps() & FCAP_MASTER) ) - return pMaster->IsTriggered( pActivator ); - } - - ALERT(at_console, "Master was null or not a master!\n"); - } - - // if this isn't a master entity, just say yes. - return 1; -} - -BOOL UTIL_ShouldShowBlood( int color ) -{ - if ( color != DONT_BLEED ) - { - if ( color == BLOOD_COLOR_RED ) - { - if ( ns_cvar_float(violence_hblood) != 0 ) - return TRUE; - } - else - { - if ( ns_cvar_float(violence_ablood) != 0 ) - return TRUE; - } - } - return FALSE; -} - -int UTIL_PointContents( const Vector &vec ) -{ - int thePointContents = POINT_CONTENTS(vec); - return thePointContents; -} - -void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_BLOODSTREAM ); - WRITE_COORD( origin.x ); - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); - WRITE_BYTE( min( amount, 255 ) ); - MESSAGE_END(); -} - -void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( color == DONT_BLEED || amount == 0 ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - if ( g_pGameRules->IsMultiplayer() ) - { - // scale up blood effect in multiplayer for better visibility - amount *= 2; - } - - if ( amount > 255 ) - amount = 255; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_BLOODSPRITE ); - WRITE_COORD( origin.x); // pos - WRITE_COORD( origin.y); - WRITE_COORD( origin.z); - WRITE_SHORT( g_sModelIndexBloodSpray ); // initial sprite model - WRITE_SHORT( g_sModelIndexBloodDrop ); // droplet sprite models - WRITE_BYTE( color ); // color index into host_basepal - WRITE_BYTE( min( max( 3, amount / 10 ), 16 ) ); // size - MESSAGE_END(); -} - -Vector UTIL_RandomBloodVector( void ) -{ - Vector direction; - - direction.x = RANDOM_FLOAT ( -1, 1 ); - direction.y = RANDOM_FLOAT ( -1, 1 ); - direction.z = RANDOM_FLOAT ( 0, 1 ); - - return direction; -} - - -void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) -{ - if ( UTIL_ShouldShowBlood( bloodColor ) ) - { - if ( bloodColor == BLOOD_COLOR_RED ) - UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG(0,5) ); - else - UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0,5) ); - } -} - - -void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) -{ - short entityIndex; - int index; - int message; - - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - // Only decal BSP models - if ( pTrace->pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit ); - if ( pEntity && !pEntity->IsBSPModel() ) - return; - entityIndex = ENTINDEX( pTrace->pHit ); - } - else - entityIndex = 0; - - message = TE_DECAL; - if ( entityIndex != 0 ) - { - if ( index > 255 ) - { - message = TE_DECALHIGH; - index -= 256; - } - } - else - { - message = TE_WORLDDECAL; - if ( index > 255 ) - { - message = TE_WORLDDECALHIGH; - index -= 256; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( message ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_BYTE( index ); - if ( entityIndex ) - WRITE_SHORT( entityIndex ); - MESSAGE_END(); -} - -/* -============== -UTIL_PlayerDecalTrace - -A player is trying to apply his custom decal for the spray can. -Tell connected clients to display it, or use the default spray can decal -if the custom can't be loaded. -============== -*/ -void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ) -{ - int index; - - if (!bIsCustom) - { - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - } - else - index = decalNumber; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_PLAYERDECAL ); - WRITE_BYTE ( playernum ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - -void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) -{ - if ( decalNumber < 0 ) - return; - - int index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos ); - WRITE_BYTE( TE_GUNSHOTDECAL ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - - -void UTIL_Sparks( const Vector &position ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_SPARKS ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - MESSAGE_END(); -} - - -void UTIL_Ricochet( const Vector &position, float scale ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_ARMOR_RICOCHET ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - WRITE_BYTE( (int)(scale*10) ); - MESSAGE_END(); -} - - -BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) -{ - // Everyone matches unless it's teamplay - if ( !g_pGameRules->IsTeamplay() ) - return TRUE; - - // Both on a team? - if ( *pTeamName1 != 0 && *pTeamName2 != 0 ) - { - if ( !_stricmp( pTeamName1, pTeamName2 ) ) // Same Team? - return TRUE; - } - - return FALSE; -} - - -void UTIL_StringToVector( float *pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - if (j < 2) - { - /* - ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n", - pkvd->szClassName, pkvd->szKeyName, pkvd->szValue ); - */ - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - - -void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < count; j++ ) // lifted from pr_edict.c - { - pVector[j] = atoi( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - for ( j++; j < count; j++ ) - { - pVector[j] = 0; - } -} - -Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) -{ - Vector sourceVector = input; - - if ( sourceVector.x > clampSize.x ) - sourceVector.x -= clampSize.x; - else if ( sourceVector.x < -clampSize.x ) - sourceVector.x += clampSize.x; - else - sourceVector.x = 0; - - if ( sourceVector.y > clampSize.y ) - sourceVector.y -= clampSize.y; - else if ( sourceVector.y < -clampSize.y ) - sourceVector.y += clampSize.y; - else - sourceVector.y = 0; - - if ( sourceVector.z > clampSize.z ) - sourceVector.z -= clampSize.z; - else if ( sourceVector.z < -clampSize.z ) - sourceVector.z += clampSize.z; - else - sourceVector.z = 0; - - return sourceVector.Normalize(); -} - - -float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) -{ - Vector midUp = position; - midUp.z = minz; - - if (UTIL_PointContents(midUp) != CONTENTS_WATER) - return minz; - - midUp.z = maxz; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) - return maxz; - - float diff = maxz - minz; - while (diff > 1.0) - { - midUp.z = minz + diff/2.0; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) - { - minz = midUp.z; - } - else - { - maxz = midUp.z; - } - diff = maxz - minz; - } - - return midUp.z; -} - - -extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model - -void UTIL_Bubbles( Vector mins, Vector maxs, int count ) -{ - Vector mid = (mins + maxs) * 0.5; - - float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); - flHeight = flHeight - mins.z; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, mid ); - WRITE_BYTE( TE_BUBBLES ); - WRITE_COORD( mins.x ); // mins - WRITE_COORD( mins.y ); - WRITE_COORD( mins.z ); - WRITE_COORD( maxs.x ); // maxz - WRITE_COORD( maxs.y ); - WRITE_COORD( maxs.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - -void UTIL_BubbleTrail( Vector from, Vector to, int count ) -{ - float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); - flHeight = flHeight - from.z; - - if (flHeight < 8) - { - flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); - flHeight = flHeight - to.z; - if (flHeight < 8) - return; - - // UNDONE: do a ploink sound - flHeight = flHeight + to.z - from.z; - } - - if (count > 255) - count = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BUBBLETRAIL ); - WRITE_COORD( from.x ); // mins - WRITE_COORD( from.y ); - WRITE_COORD( from.z ); - WRITE_COORD( to.x ); // maxz - WRITE_COORD( to.y ); - WRITE_COORD( to.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - - -void UTIL_Remove( CBaseEntity *pEntity ) -{ - if ( !pEntity ) - return; - - pEntity->UpdateOnRemove(); - pEntity->pev->flags |= FL_KILLME; - pEntity->pev->targetname = 0; -} - - -BOOL UTIL_IsValidEntity( edict_t *pent ) -{ - if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) - return FALSE; - return TRUE; -} - - -void UTIL_PrecacheOther( const char *szClassname ) -{ - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOther\n" ); - return; - } - - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - if (pEntity) - pEntity->Precache( ); - REMOVE_ENTITY(pent); -} - -//========================================================= -// UTIL_LogPrintf - Prints a logged message to console. -// Preceded by LOG: ( timestamp ) < message > -//========================================================= -void UTIL_LogPrintf( char *fmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start ( argptr, fmt ); -#ifdef WIN32 - //overflow protection in MS version of function... - _vsnprintf( string, 1023, fmt, argptr ); -#else - vsprintf ( string, fmt, argptr ); -#endif - va_end ( argptr ); - - // Print to server console - ALERT( at_logged, "%s", string ); -} - -//========================================================= -// UTIL_DotPoints - returns the dot product of a line from -// src to check and vecdir. -//========================================================= -float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ) -{ - Vector2D vec2LOS; - - vec2LOS = ( vecCheck - vecSrc ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); -} - - -//========================================================= -// UTIL_StripToken - for redundant keynames -//========================================================= -void UTIL_StripToken( const char *pKey, char *pDest ) -{ - int i = 0; - - while ( pKey[i] && pKey[i] != '#' ) - { - pDest[i] = pKey[i]; - i++; - } - pDest[i] = 0; -} - - -// -------------------------------------------------------------- -// -// CSave -// -// -------------------------------------------------------------- -static int gSizes[FIELD_TYPECOUNT] = -{ - sizeof(float), // FIELD_FLOAT - sizeof(int), // FIELD_STRING - sizeof(int), // FIELD_ENTITY - sizeof(int), // FIELD_CLASSPTR - sizeof(int), // FIELD_EHANDLE - sizeof(int), // FIELD_entvars_t - sizeof(int), // FIELD_EDICT - sizeof(float)*3, // FIELD_VECTOR - sizeof(float)*3, // FIELD_POSITION_VECTOR - sizeof(int *), // FIELD_POINTER - sizeof(int), // FIELD_INTEGER - sizeof(int *), // FIELD_FUNCTION - sizeof(int), // FIELD_BOOLEAN - sizeof(short), // FIELD_SHORT - sizeof(char), // FIELD_CHARACTER - sizeof(float), // FIELD_TIME - sizeof(int), // FIELD_MODELNAME - sizeof(int), // FIELD_SOUNDNAME -}; - - -// Base class includes common SAVERESTOREDATA pointer, and manages the entity table -CSaveRestoreBuffer :: CSaveRestoreBuffer( void ) -{ - m_pdata = NULL; -} - - -CSaveRestoreBuffer :: CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) -{ - m_pdata = pdata; -} - - -CSaveRestoreBuffer :: ~CSaveRestoreBuffer( void ) -{ -} - -int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL ) - return -1; - return EntityIndex( pEntity->pev ); -} - - -int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) -{ - if ( pevLookup == NULL ) - return -1; - return EntityIndex( ENT( pevLookup ) ); -} - -int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) -{ - return EntityIndex( ENT( eoLookup ) ); -} - - -int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) -{ - if ( !m_pdata || pentLookup == NULL ) - return -1; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->pent == pentLookup ) - return i; - } - return -1; -} - - -edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) -{ - if ( !m_pdata || entityIndex < 0 ) - return NULL; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->id == entityIndex ) - return pTable->pent; - } - return NULL; -} - - -int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) -{ - if ( !m_pdata || entityIndex < 0 ) - return 0; - if ( entityIndex > m_pdata->tableCount ) - return 0; - - m_pdata->pTable[ entityIndex ].flags |= flags; - - return m_pdata->pTable[ entityIndex ].flags; -} - - -void CSaveRestoreBuffer :: BufferRewind( int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size < size ) - size = m_pdata->size; - - m_pdata->pCurrentData -= size; - m_pdata->size -= size; -} - -#ifndef _WIN32 -extern "C" { -unsigned _rotr ( unsigned val, int shift) -{ - register unsigned lobit; /* non-zero means lo bit set */ - register unsigned num = val; /* number to rotate */ - - shift &= 0x1f; /* modulo 32 -- this will also make - negative shifts work */ - - while (shift--) { - lobit = num & 1; /* get high bit */ - num >>= 1; /* shift right one bit */ - if (lobit) - num |= 0x80000000; /* set hi bit if lo bit was set */ - } - - return num; -} -} -#endif - -unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) -{ - unsigned int hash = 0; - - while ( *pszToken ) - hash = _rotr( hash, 4 ) ^ *pszToken++; - - return hash; -} - -unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) -{ - unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)m_pdata->tokenCount ); - -#if _DEBUG - static int tokensparsed = 0; - tokensparsed++; - if ( !m_pdata->tokenCount || !m_pdata->pTokens ) - ALERT( at_error, "No token table array in TokenHash()!" ); -#endif - - for ( int i=0; itokenCount; i++ ) - { -#if _DEBUG - static qboolean beentheredonethat = FALSE; - if ( i > 50 && !beentheredonethat ) - { - beentheredonethat = TRUE; - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" ); - } -#endif - - int index = hash + i; - if ( index >= m_pdata->tokenCount ) - index -= m_pdata->tokenCount; - - if ( !m_pdata->pTokens[index] || strcmp( pszToken, m_pdata->pTokens[index] ) == 0 ) - { - m_pdata->pTokens[index] = (char *)pszToken; - return index; - } - } - - // Token hash table full!!! - // [Consider doing overflow table(s) after the main table & limiting linear hash table search] - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!" ); - return 0; -} - -void CSave :: WriteData( const char *pname, int size, const char *pdata ) -{ - BufferField( pname, size, pdata ); -} - - -void CSave :: WriteShort( const char *pname, const short *data, int count ) -{ - BufferField( pname, sizeof(short) * count, (const char *)data ); -} - - -void CSave :: WriteInt( const char *pname, const int *data, int count ) -{ - BufferField( pname, sizeof(int) * count, (const char *)data ); -} - - -void CSave :: WriteFloat( const char *pname, const float *data, int count ) -{ - BufferField( pname, sizeof(float) * count, (const char *)data ); -} - - -void CSave :: WriteTime( const char *pname, const float *data, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * count ); - for ( i = 0; i < count; i++ ) - { - float tmp = data[0]; - - // Always encode time as a delta from the current time so it can be re-based if loaded in a new level - // Times of 0 are never written to the file, so they will be restored as 0, not a relative time - if ( m_pdata ) - tmp -= m_pdata->time; - - BufferData( (const char *)&tmp, sizeof(float) ); - data ++; - } -} - - -void CSave :: WriteString( const char *pname, const char *pdata ) -{ -#ifdef TOKENIZE - short token = (short)TokenHash( pdata ); - WriteShort( pname, &token, 1 ); -#else - BufferField( pname, strlen(pdata) + 1, pdata ); -#endif -} - - -void CSave :: WriteString( const char *pname, const int *stringId, int count ) -{ - int i, size; - -#ifdef TOKENIZE - short token = (short)TokenHash( STRING( *stringId ) ); - WriteShort( pname, &token, 1 ); -#else -#if 0 - if ( count != 1 ) - ALERT( at_error, "No string arrays!\n" ); - WriteString( pname, (char *)STRING(*stringId) ); -#endif - - size = 0; - for ( i = 0; i < count; i++ ) - size += strlen( STRING( stringId[i] ) ) + 1; - - BufferHeader( pname, size ); - for ( i = 0; i < count; i++ ) - { - const char *pString = STRING(stringId[i]); - BufferData( pString, strlen(pString)+1 ); - } -#endif -} - - -void CSave :: WriteVector( const char *pname, const Vector &value ) -{ - WriteVector( pname, &value.x, 1 ); -} - - -void CSave :: WriteVector( const char *pname, const float *value, int count ) -{ - BufferHeader( pname, sizeof(float) * 3 * count ); - BufferData( (const char *)value, sizeof(float) * 3 * count ); -} - - - -void CSave :: WritePositionVector( const char *pname, const Vector &value ) -{ - - if ( m_pdata && m_pdata->fUseLandmark ) - { - Vector tmp = value - m_pdata->vecLandmarkOffset; - WriteVector( pname, tmp ); - } - - WriteVector( pname, value ); -} - - -void CSave :: WritePositionVector( const char *pname, const float *value, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * 3 * count ); - for ( i = 0; i < count; i++ ) - { - Vector tmp( value[0], value[1], value[2] ); - - if ( m_pdata && m_pdata->fUseLandmark ) - tmp = tmp - m_pdata->vecLandmarkOffset; - - BufferData( (const char *)&tmp.x, sizeof(float) * 3 ); - value += 3; - } -} - - -void CSave :: WriteFunction( const char *pname, const int *data, int count ) -{ - const char *functionName; - - functionName = NAME_FOR_FUNCTION( *data ); - if ( functionName ) - BufferField( pname, strlen(functionName) + 1, functionName ); - else - ALERT( at_error, "Invalid function pointer in entity!" ); -} - - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) -{ - int i; - TYPEDESCRIPTION *pField; - - for ( i = 0; i < ENTVARS_COUNT; i++ ) - { - pField = &gEntvarsDescription[i]; - - if ( !stricmp( pField->fieldName, pkvd->szKeyName ) ) - { - switch( pField->fieldType ) - { - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - (*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue ); - break; - - case FIELD_TIME: - case FIELD_FLOAT: - (*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); - break; - - case FIELD_INTEGER: - (*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue ); - break; - - case FIELD_POSITION_VECTOR: - case FIELD_VECTOR: - UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue ); - break; - - default: - case FIELD_EVARS: - case FIELD_CLASSPTR: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_POINTER: - ALERT( at_error, "Bad field in entity!!\n" ); - break; - } - pkvd->fHandled = TRUE; - return; - } - } -} - - - -int CSave :: WriteEntVars( const char *pname, entvars_t *pev ) -{ - return WriteFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - - - -int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - int i, j, actualCount, emptyCount; - TYPEDESCRIPTION *pTest; - int entityArray[MAX_ENTITYARRAY]; - - // Precalculate the number of empty fields - emptyCount = 0; - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pOutputData = ((char *)pBaseData + pFields[i].fieldOffset ); - if ( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) ) - emptyCount++; - } - - // Empty fields will not be written, write out the actual number of fields to be written - actualCount = fieldCount - emptyCount; - WriteInt( pname, &actualCount, 1 ); - - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pTest = &pFields[ i ]; - pOutputData = ((char *)pBaseData + pTest->fieldOffset ); - - // UNDONE: Must we do this twice? - if ( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) ) - continue; - - switch( pTest->fieldType ) - { - case FIELD_FLOAT: - WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_TIME: - WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - case FIELD_CLASSPTR: - case FIELD_EVARS: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_EHANDLE: - if ( pTest->fieldSize > MAX_ENTITYARRAY ) - ALERT( at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY ); - for ( j = 0; j < pTest->fieldSize; j++ ) - { - switch( pTest->fieldType ) - { - case FIELD_EVARS: - entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); - break; - case FIELD_CLASSPTR: - entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); - break; - case FIELD_EDICT: - entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); - break; - case FIELD_ENTITY: - entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); - break; - case FIELD_EHANDLE: - entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); - break; - } - } - WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); - break; - case FIELD_POSITION_VECTOR: - WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_VECTOR: - WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_BOOLEAN: - case FIELD_INTEGER: - WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_SHORT: - WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); - break; - - case FIELD_CHARACTER: - WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); - break; - - // For now, just write the address out, we're not going to change memory while doing this yet! - case FIELD_POINTER: - WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - default: - ALERT( at_error, "Bad field type\n" ); - } - } - - return 1; -} - - -void CSave :: BufferString( char *pdata, int len ) -{ - char c = 0; - - BufferData( pdata, len ); // Write the string - BufferData( &c, 1 ); // Write a null terminator -} - - -int CSave :: DataEmpty( const char *pdata, int size ) -{ - for ( int i = 0; i < size; i++ ) - { - if ( pdata[i] ) - return 0; - } - return 1; -} - - -void CSave :: BufferField( const char *pname, int size, const char *pdata ) -{ - BufferHeader( pname, size ); - BufferData( pdata, size ); -} - - -void CSave :: BufferHeader( const char *pname, int size ) -{ - short hashvalue = TokenHash( pname ); - if ( size > 1<<(sizeof(short)*8) ) - ALERT( at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!" ); - BufferData( (const char *)&size, sizeof(short) ); - BufferData( (const char *)&hashvalue, sizeof(short) ); -} - - -void CSave :: BufferData( const char *pdata, int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size + size > m_pdata->bufferSize ) - { - ALERT( at_error, "Save/Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - memcpy( m_pdata->pCurrentData, pdata, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - - -// -------------------------------------------------------------- -// -// CRestore -// -// -------------------------------------------------------------- - -int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ) -{ - int i, j, stringCount, fieldNumber, entityIndex; - TYPEDESCRIPTION *pTest; - float time, timeData; - Vector position; - edict_t *pent; - char *pString; - - time = 0; - position = Vector(0,0,0); - - if ( m_pdata ) - { - time = m_pdata->time; - if ( m_pdata->fUseLandmark ) - position = m_pdata->vecLandmarkOffset; - } - - for ( i = 0; i < fieldCount; i++ ) - { - fieldNumber = (i+startField)%fieldCount; - pTest = &pFields[ fieldNumber ]; - if ( !stricmp( pTest->fieldName, pName ) ) - { - if ( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL) ) - { - for ( j = 0; j < pTest->fieldSize; j++ ) - { - void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j*gSizes[pTest->fieldType]) ); - void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; - - switch( pTest->fieldType ) - { - case FIELD_TIME: - timeData = *(float *)pInputData; - // Re-base time variables - timeData += time; - *((float *)pOutputData) = timeData; - break; - case FIELD_FLOAT: - *((float *)pOutputData) = *(float *)pInputData; - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - // Skip over j strings - pString = (char *)pData; - for ( stringCount = 0; stringCount < j; stringCount++ ) - { - while (*pString) - pString++; - pString++; - } - pInputData = pString; - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - { - int string; - - string = ALLOC_STRING( (char *)pInputData ); - - *((int *)pOutputData) = string; - - if ( !FStringNull( string ) && m_precache ) - { - if ( pTest->fieldType == FIELD_MODELNAME ) - PRECACHE_MODEL( (char *)STRING( string ) ); - else if ( pTest->fieldType == FIELD_SOUNDNAME ) - PRECACHE_SOUND( (char *)STRING( string ) ); - } - } - break; - case FIELD_EVARS: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((entvars_t **)pOutputData) = VARS(pent); - else - *((entvars_t **)pOutputData) = NULL; - break; - case FIELD_CLASSPTR: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); - else - *((CBaseEntity **)pOutputData) = NULL; - break; - case FIELD_EDICT: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - *((edict_t **)pOutputData) = pent; - break; - case FIELD_EHANDLE: - // Input and Output sizes are different! - pOutputData = (char *)pOutputData + j*(sizeof(EHANDLE) - gSizes[pTest->fieldType]); - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); - else - *((EHANDLE *)pOutputData) = NULL; - break; - case FIELD_ENTITY: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EOFFSET *)pOutputData) = OFFSET(pent); - else - *((EOFFSET *)pOutputData) = 0; - break; - case FIELD_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0]; - ((float *)pOutputData)[1] = ((float *)pInputData)[1]; - ((float *)pOutputData)[2] = ((float *)pInputData)[2]; - break; - case FIELD_POSITION_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; - ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; - ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; - break; - - case FIELD_BOOLEAN: - case FIELD_INTEGER: - *((int *)pOutputData) = *( int *)pInputData; - break; - - case FIELD_SHORT: - *((short *)pOutputData) = *( short *)pInputData; - break; - - case FIELD_CHARACTER: - *((char *)pOutputData) = *( char *)pInputData; - break; - - case FIELD_POINTER: - *((int *)pOutputData) = *( int *)pInputData; - break; - case FIELD_FUNCTION: - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - *((int *)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); - break; - - default: - ALERT( at_error, "Bad field type\n" ); - } - } - } -#if 0 - else - { - ALERT( at_console, "Skipping global field %s\n", pName ); - } -#endif - return fieldNumber; - } - } - - return -1; -} - - -int CRestore::ReadEntVars( const char *pname, entvars_t *pev ) -{ - return ReadFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - - -int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - unsigned short i, token; - int lastField, fileCount; - HEADER header; - - i = ReadShort(); - ASSERT( i == sizeof(int) ); // First entry should be an int - - token = ReadShort(); - - // Check the struct name - if ( token != TokenHash(pname) ) // Field Set marker - { -// ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); - BufferRewind( 2*sizeof(short) ); - return 0; - } - - // Skip over the struct name - fileCount = ReadInt(); // Read field count - - lastField = 0; // Make searches faster, most data is read/written in the same order - - // Clear out base data - for ( i = 0; i < fieldCount; i++ ) - { - // Don't clear global fields - if ( !m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL) ) - memset( ((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ); - } - - for ( i = 0; i < fileCount; i++ ) - { - BufferReadHeader( &header ); - lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData ); - lastField++; - } - - return 1; -} - - -void CRestore::BufferReadHeader( HEADER *pheader ) -{ - ASSERT( pheader!=NULL ); - pheader->size = ReadShort(); // Read field size - pheader->token = ReadShort(); // Read field name token - pheader->pData = BufferPointer(); // Field Data is next - BufferSkipBytes( pheader->size ); // Advance to next field -} - - -short CRestore::ReadShort( void ) -{ - short tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(short) ); - - return tmp; -} - -int CRestore::ReadInt( void ) -{ - int tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(int) ); - - return tmp; -} - -int CRestore::ReadNamedInt( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); - return ((int *)header.pData)[0]; -} - -char *CRestore::ReadNamedString( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); -#ifdef TOKENIZE - return (char *)(m_pdata->pTokens[*(short *)header.pData]); -#else - return (char *)header.pData; -#endif -} - - -char *CRestore::BufferPointer( void ) -{ - if ( !m_pdata ) - return NULL; - - return m_pdata->pCurrentData; -} - -void CRestore::BufferReadBytes( char *pOutput, int size ) -{ - ASSERT( m_pdata !=NULL ); - - if ( !m_pdata || Empty() ) - return; - - if ( (m_pdata->size + size) > m_pdata->bufferSize ) - { - ALERT( at_error, "Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - if ( pOutput ) - memcpy( pOutput, m_pdata->pCurrentData, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - -void CRestore::BufferSkipBytes( int bytes ) -{ - BufferReadBytes( NULL, bytes ); -} - -int CRestore::BufferSkipZString( void ) -{ - char *pszSearch; - int len; - - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - - len = 0; - pszSearch = m_pdata->pCurrentData; - while ( *pszSearch++ && len < maxLen ) - len++; - - len++; - - BufferSkipBytes( len ); - - return len; -} - -int CRestore::BufferCheckZString( const char *string ) -{ - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - int len = strlen( string ); - if ( len <= maxLen ) - { - if ( !strncmp( string, m_pdata->pCurrentData, len ) ) - return 1; - } - return 0; -} - diff --git a/main/source/dlls/util.h b/main/source/dlls/util.h index 6ab015a0..69e62199 100644 --- a/main/source/dlls/util.h +++ b/main/source/dlls/util.h @@ -1,592 +1,592 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "archtypes.h" // DAL -// -// Misc utility code -// -#ifndef UTIL_H -#define UTIL_H - - - #undef min - #undef max - -#include - -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif - -#include "../game_shared/directorconst.h" - -//inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file - -extern globalvars_t *gpGlobals; - -// Use this instead of ALLOC_STRING on constant strings -#define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) -// #define MAKE_STRING(str) ((int)str - (int)STRING(0)) - -#pragma warning(push) -#pragma warning(disable: 311) -inline string_t MAKE_STRING(const char* offset) -{ - return ((string_t)offset - (string_t)STRING(0)); -} -#pragma warning(pop) - -inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); -} - -inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName); -} - -// for doing a reverse lookup. Say you have a door, and want to find its button. -inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "target", pszName); -} - -// Keeps clutter down a bit, when writing key-value pairs -#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue) -#define WRITEKEY_FLOAT(pf, szKeyName, flKeyValue) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%f\"\n", szKeyName, flKeyValue) -#define WRITEKEY_STRING(pf, szKeyName, szKeyValue) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%s\"\n", szKeyName, szKeyValue) -#define WRITEKEY_VECTOR(pf, szKeyName, flX, flY, flZ) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%f %f %f\"\n", szKeyName, flX, flY, flZ) - -// Keeps clutter down a bit, when using a float as a bit-vector -#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) -#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) -#define FBitSet(flBitVector, bit) ((int)(flBitVector) & (bit)) - -// Makes these more explicit, and easier to find -#define FILE_GLOBAL static -#define DLL_GLOBAL - -// Until we figure out why "const" gives the compiler problems, we'll just have to use -// this bogus "empty" define to mark things as constant. -#define CONSTANT - -// More explicit than "int" -typedef int EOFFSET; - -// In case it's not alread defined -typedef int BOOL; - -// In case this ever changes -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -// Keeps clutter down a bit, when declaring external entity/global method prototypes -#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName( void ) -#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) -#ifndef UTIL_DLLEXPORT -#ifdef _WIN32 -#define UTIL_DLLEXPORT _declspec( dllexport ) -#else -#define UTIL_DLLEXPORT __attribute__ ((visibility("default"))) -#endif -#endif - -// This is the glue that hooks .MAP entity class names to our CPP classes -// The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress() -// The function is used to intialize / allocate the object for the entity -#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ - extern "C" UTIL_DLLEXPORT void mapClassName( entvars_t *pev ); \ - void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } - -// -// Conversion among the three types of "entity", including identity-conversions. -// -#ifdef DEBUG - extern edict_t *DBG_EntOfVars(const entvars_t *pev); - inline edict_t *ENT(const entvars_t *pev) { return DBG_EntOfVars(pev); } -#else - inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; } -#endif -inline edict_t *ENT(edict_t *pent) { return pent; } -inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); } -inline EOFFSET OFFSET(EOFFSET eoffset) { return eoffset; } -inline EOFFSET OFFSET(const edict_t *pent) -{ -#if _DEBUG - if ( !pent ) - ALERT( at_error, "Bad ent in OFFSET()\n" ); -#endif - return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); -} -inline EOFFSET OFFSET(entvars_t *pev) -{ -#if _DEBUG - if ( !pev ) - ALERT( at_error, "Bad pev in OFFSET()\n" ); -#endif - return OFFSET(ENT(pev)); -} -inline entvars_t *VARS(entvars_t *pev) { return pev; } - -inline entvars_t *VARS(edict_t *pent) -{ - if ( !pent ) - return NULL; - - return &pent->v; -} - -inline entvars_t* VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } -inline int ENTINDEX(const edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } -inline edict_t* INDEXENT( int iEdictNum ) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } - -extern void NetworkMeterMessageBegin(int msg_dest, int msg_type, const float* pOrigin, edict_t* ed); - -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) -{ - NetworkMeterMessageBegin(msg_dest, msg_type, pOrigin, ENT(ent)); -} -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t* ed = NULL) -{ - NetworkMeterMessageBegin(msg_dest, msg_type, pOrigin, ed); -} - -// Testing the three types of "entity" for nullity -#define eoNullEntity 0 -inline BOOL FNullEnt(EOFFSET eoffset) { return eoffset == 0; } -inline BOOL FNullEnt(const edict_t* pent) { return pent == NULL || FNullEnt(OFFSET(pent)); } -inline BOOL FNullEnt(entvars_t* pev) { return pev == NULL || FNullEnt(OFFSET(pev)); } - -// Testing strings for nullity -#define iStringNull 0 -inline BOOL FStringNull(int iString) { return iString == iStringNull; } - -#define cchMapNameMost 32 - -// Dot products for view cone checking -#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees -#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks -#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks -#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks - -// All monsters need this data -#define DONT_BLEED -1 -#define BLOOD_COLOR_RED (BYTE)247 -#define BLOOD_COLOR_YELLOW (BYTE)195 -#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW - -typedef enum -{ - - MONSTERSTATE_NONE = 0, - MONSTERSTATE_IDLE, - MONSTERSTATE_COMBAT, - MONSTERSTATE_ALERT, - MONSTERSTATE_HUNT, - MONSTERSTATE_PRONE, - MONSTERSTATE_SCRIPT, - MONSTERSTATE_PLAYDEAD, - MONSTERSTATE_DEAD - -} MONSTERSTATE; - - - -// Things that toggle (buttons/triggers/doors) need this -typedef enum - { - TS_AT_TOP, - TS_AT_BOTTOM, - TS_GOING_UP, - TS_GOING_DOWN - } TOGGLE_STATE; - -// Misc useful -inline BOOL FStrEq(const char*sz1, const char*sz2) - { return (strcmp(sz1, sz2) == 0); } -inline BOOL FClassnameIs(edict_t* pent, const char* szClassname) - { return FStrEq(STRING(VARS(pent)->classname), szClassname); } -inline BOOL FClassnameIs(entvars_t* pev, const char* szClassname) - { return FStrEq(STRING(pev->classname), szClassname); } - -class CBaseEntity; - -// Misc. Prototypes -extern void UTIL_SetSize (entvars_t* pev, const Vector &vecMin, const Vector &vecMax); -extern float UTIL_VecToYaw (const Vector &vec); -extern Vector UTIL_VecToAngles (const Vector &vec); -extern float UTIL_AngleMod (float a); -extern float UTIL_AngleDiff ( float destAngle, float srcAngle ); - -extern CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius); -extern CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ); -extern CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius ); -int UTIL_CountEntitiesInSphere(const Vector& inVecCenter, float inRadius, const char* inClassName); - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -extern CBaseEntity *UTIL_PlayerByIndex( int playerIndex ); - -#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent) -extern void UTIL_MakeVectors (const Vector &vecAngles); - -// Pass in an array of pointers and an array size, it fills the array and returns the number inserted -extern int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ); -extern int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ); - -inline void UTIL_MakeVectorsPrivate( const Vector &vecAngles, float *p_vForward, float *p_vRight, float *p_vUp ) -{ - g_engfuncs.pfnAngleVectors( vecAngles, p_vForward, p_vRight, p_vUp ); -} - -extern void UTIL_MakeAimVectors ( const Vector &vecAngles ); // like MakeVectors, but assumes pitch isn't inverted -extern void UTIL_MakeInvVectors ( const Vector &vec, globalvars_t *pgv ); - -extern void UTIL_Error ( CBaseEntity *pEntity, const char *pMessage ); -extern void UTIL_SetOrigin ( entvars_t* pev, const Vector &vecOrigin ); -extern void UTIL_EmitAmbientSound ( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ); -extern void UTIL_ParticleEffect ( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ); -extern void UTIL_ScreenShake ( const Vector ¢er, float amplitude, float frequency, float duration, float radius ); -extern void UTIL_ScreenShakeAll ( const Vector ¢er, float amplitude, float frequency, float duration ); -extern void UTIL_ShowMessage ( const char *pString, CBaseEntity *pPlayer); -typedef enum { NORMAL = 0, TOOLTIP = 1, CENTER = 2} SHOWMESSAGE_TYPE; -extern void UTIL_ShowMessage2 ( const char *pString, CBaseEntity *pPlayer, SHOWMESSAGE_TYPE type = NORMAL); -extern void UTIL_ShowMessageAll ( const char *pString ); -extern void UTIL_ScreenFadeAll ( const Vector &color, float fadeTime, float holdTime, int alpha, int flags ); -extern void UTIL_ScreenFade ( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ); - -typedef enum { ignore_monsters=1, dont_ignore_monsters=0, missile=2 } IGNORE_MONSTERS; -typedef enum { ignore_glass=1, dont_ignore_glass=0 } IGNORE_GLASS; -extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr); -extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr); -typedef enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 }; -extern void UTIL_TraceHull (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr); -extern TraceResult UTIL_GetGlobalTrace (void); -extern void UTIL_TraceModel (const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr); -extern Vector UTIL_GetAimVector (edict_t* pent, float flSpeed); -extern int UTIL_PointContents (const Vector &vec); - -extern int UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator); -extern void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ); -extern void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ); -extern Vector UTIL_RandomBloodVector( void ); -extern BOOL UTIL_ShouldShowBlood( int bloodColor ); -extern void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ); -extern void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ); -extern void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ); -extern void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ); -extern void UTIL_Sparks( const Vector &position ); -extern void UTIL_Ricochet( const Vector &position, float scale ); -extern void UTIL_StringToVector( float *pVector, const char *pString ); -extern void UTIL_StringToIntArray( int *pVector, int count, const char *pString ); -extern Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ); -extern float UTIL_Approach( float target, float value, float speed ); -extern float UTIL_ApproachAngle( float target, float value, float speed ); -extern float UTIL_AngleDistance( float next, float cur ); - -extern char *UTIL_VarArgs( char *format, ... ); -extern void UTIL_Remove( CBaseEntity *pEntity ); -extern BOOL UTIL_IsValidEntity( edict_t *pent ); -extern BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ); - -// Use for ease-in, ease-out style interpolation (accel/decel) -extern float UTIL_SplineFraction( float value, float scale ); - -// Search for water transition along a vertical line -extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); -extern void UTIL_Bubbles( Vector mins, Vector maxs, int count ); -extern void UTIL_BubbleTrail( Vector from, Vector to, int count ); - -// allows precacheing of other entities -extern void UTIL_PrecacheOther( const char *szClassname ); - -// prints a message to each client -extern void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); -inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ) -{ - UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); -} - -class CBasePlayerItem; -class CBasePlayer; -extern BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - -// prints messages through the HUD -extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); - -typedef struct hudtextparms_s -{ - float x; - float y; - int effect; - byte r1, g1, b1, a1; - byte r2, g2, b2, a2; - float fadeinTime; - float fadeoutTime; - float holdTime; - float fxTime; - int channel; -} hudtextparms_t; - -// prints as transparent 'title' to the HUD -extern void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ); -extern void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ); - -// for handy use with ClientPrint params -extern char *UTIL_dtos1( int d ); -extern char *UTIL_dtos2( int d ); -extern char *UTIL_dtos3( int d ); -extern char *UTIL_dtos4( int d ); - -// Writes message to console with timestamp and FragLog header. -extern void UTIL_LogPrintf( char *fmt, ... ); - -// Sorta like FInViewCone, but for nonmonsters. -extern float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); - -extern void UTIL_StripToken( const char *pKey, char *pDest );// for redundant keynames - -// Misc functions -extern void SetMovedir(entvars_t* pev); -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern int BuildChangeList( LEVELLIST *pLevelList, int maxList ); - -// -// How did I ever live without ASSERT? -// -#include "../localassert.h" -//#ifdef DEBUG -//void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage); -//#define ASSERT(f) DBG_AssertFunction(f, #f, __FILE__, __LINE__, NULL) -//#define ASSERTSZ(f, sz) DBG_AssertFunction(f, #f, __FILE__, __LINE__, sz) -//#else // !DEBUG -//#define ASSERT(f) -//#define ASSERTSZ(f, sz) -//#endif // !DEBUG - -extern DLL_GLOBAL const Vector g_vecZero; - -// -// Constants that were used only by QC (maybe not used at all now) -// -// Un-comment only as needed -// -#define LANGUAGE_ENGLISH 0 -#define LANGUAGE_GERMAN 1 -#define LANGUAGE_FRENCH 2 -#define LANGUAGE_BRITISH 3 - -extern DLL_GLOBAL int g_Language; - -#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation -#define AMBIENT_SOUND_EVERYWHERE 1 -#define AMBIENT_SOUND_SMALLRADIUS 2 -#define AMBIENT_SOUND_MEDIUMRADIUS 4 -#define AMBIENT_SOUND_LARGERADIUS 8 -#define AMBIENT_SOUND_START_SILENT 16 -#define AMBIENT_SOUND_NOT_LOOPING 32 - -#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements - -#define SND_SPAWNING (1<<8) // duplicated in protocol.h we're spawing, used in some cases for ambients -#define SND_STOP (1<<5) // duplicated in protocol.h stop sound -#define SND_CHANGE_VOL (1<<6) // duplicated in protocol.h change sound vol -#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch - -#define LFO_SQUARE 1 -#define LFO_TRIANGLE 2 -#define LFO_RANDOM 3 - -// func_rotating -#define SF_BRUSH_ROTATE_Y_AXIS 0 -#define SF_BRUSH_ROTATE_INSTANT 1 -#define SF_BRUSH_ROTATE_BACKWARDS 2 -#define SF_BRUSH_ROTATE_Z_AXIS 4 -#define SF_BRUSH_ROTATE_X_AXIS 8 -#define SF_PENDULUM_AUTO_RETURN 16 -#define SF_PENDULUM_PASSABLE 32 - - -#define SF_BRUSH_ROTATE_SMALLRADIUS 128 -#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 -#define SF_BRUSH_ROTATE_LARGERADIUS 512 - -#define PUSH_BLOCK_ONLY_X 1 -#define PUSH_BLOCK_ONLY_Y 2 - -#define VEC_HULL_MIN Vector(-16, -16, -36) -#define VEC_HULL_MAX Vector( 16, 16, 36) -#define VEC_HUMAN_HULL_MIN Vector( -16, -16, 0 ) -#define VEC_HUMAN_HULL_MAX Vector( 16, 16, 72 ) -#define VEC_HUMAN_HULL_DUCK Vector( 16, 16, 36 ) - -#define VEC_VIEW Vector( 0, 0, 28 ) - -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) -#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18) -//#define VEC_DUCK_VIEW Vector( 0, 0, 12 ) - -#define SVC_TEMPENTITY 23 -#define SVC_INTERMISSION 30 -#define SVC_CDTRACK 32 -#define SVC_WEAPONANIM 35 -#define SVC_ROOMTYPE 37 - -// triggers -#define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger -#define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger -#define SF_TRIGGER_PUSHABLES 4// only pushables can fire this trigger - -// func breakable -#define SF_BREAK_TRIGGER_ONLY 1// may only be broken by trigger -#define SF_BREAK_TOUCH 2// can be 'crashed through' by running player (plate glass) -#define SF_BREAK_PRESSURE 4// can be broken by a player standing on it -#define SF_BREAK_CROWBAR 256// instant break if hit with crowbar - -// func_pushable (it's also func_breakable, so don't collide with those flags) -#define SF_PUSH_BREAKABLE 128 - -#define SF_LIGHT_START_OFF 1 - -#define SPAWNFLAG_NOMESSAGE 1 -#define SPAWNFLAG_NOTOUCH 1 -#define SPAWNFLAG_DROIDONLY 4 - -#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons) - -#define TELE_PLAYER_ONLY 1 -#define TELE_SILENT 2 - -#define SF_TRIG_PUSH_ONCE 1 - - -// Sound Utilities - -// sentence groups -#define CBSENTENCENAME_MAX 16 -#define CVOXFILESENTENCEMAX 1536 // max number of sentences in game. NOTE: this must match - // CVOXFILESENTENCEMAX in engine\sound.h!!! - -extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -extern int gcallsentences; - -int USENTENCEG_Pick(int isentenceg, char *szfound); -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset); -void USENTENCEG_InitLRU(unsigned char *plru, int count); - -void SENTENCEG_Init(); -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch); -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch); -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch, int ipick, int freset); -int SENTENCEG_GetIndex(const char *szrootname); -int SENTENCEG_Lookup(const char *sample, char *sentencenum); - -void TEXTURETYPE_Init(); -char TEXTURETYPE_Find(char *name); -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); - -// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100 -// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 -// down to 1 is a lower pitch. 150 to 70 is the realistic range. -// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as -// fast as EMIT_SOUND (the pitchshift mixer is not native coded). - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch); - - -inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation) -{ - EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM); -} - -inline void STOP_SOUND(edict_t *entity, int channel, const char *sample) -{ - EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM); -} - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample); -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg); -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); - -#define PRECACHE_SOUND_ARRAY( a ) \ - { for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); } - -#define EMIT_SOUND_ARRAY_DYN( chan, array ) \ - EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) ); - -#define RANDOM_SOUND_ARRAY( array ) (array) [ RANDOM_LONG(0,ARRAYSIZE( (array) )-1) ] - -#define PLAYBACK_EVENT( flags, who, index ) PLAYBACK_EVENT_FULL( flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); -#define PLAYBACK_EVENT_DELAY( flags, who, index, delay ) PLAYBACK_EVENT_FULL( flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - -#define GROUP_OP_AND 0 -#define GROUP_OP_NAND 1 - -extern int g_groupmask; -extern int g_groupop; - -class UTIL_GroupTrace -{ -public: - UTIL_GroupTrace( int groupmask, int op ); - ~UTIL_GroupTrace( void ); - -private: - int m_oldgroupmask, m_oldgroupop; -}; - -void UTIL_SetGroupTrace( int groupmask, int op ); -void UTIL_UnsetGroupTrace( void ); - -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); - -float UTIL_WeaponTimeBase( void ); - -// Leave last parameter to make the same as pEntity -void UTIL_SayText( const char *pText, CBaseEntity *pEntity, int inEntIndex = -1); -void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity, int inEntIndex = -1); - -//: hope you dont mind me adding this, I use this in NSAdmin -// Statements like: -// #pragma message(Reminder "Fix this problem!") -// Which will cause messages like: -// C:\Source\Project\main.cpp(47): Reminder: Fix this problem! -// to show up during compiles. Note that you can NOT use the -// words "error" or "warning" in your reminders, since it will -// make the IDE think it should abort execution. You can double -// click on these messages and jump to the line in question. -#define Stringize( L ) #L -#define MakeString( M, L ) M(L) -#define $Line \ - MakeString( Stringize, __LINE__ ) -#define Reminder \ - __FILE__ "(" $Line ") : Reminder: " - - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "archtypes.h" // DAL +// +// Misc utility code +// +#ifndef UTIL_H +#define UTIL_H + + + #undef min + #undef max + +#include + +#ifndef ACTIVITY_H +#include "activity.h" +#endif + +#ifndef ENGINECALLBACK_H +#include "enginecallback.h" +#endif + +#include "../game_shared/directorconst.h" + +//inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file + +extern globalvars_t *gpGlobals; + +// Use this instead of ALLOC_STRING on constant strings +#define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) +// #define MAKE_STRING(str) ((int)str - (int)STRING(0)) + +#pragma warning(push) +#pragma warning(disable: 311) +inline string_t MAKE_STRING(const char* offset) +{ + return ((string_t)offset - (string_t)STRING(0)); +} +#pragma warning(pop) + +inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); +} + +inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName); +} + +// for doing a reverse lookup. Say you have a door, and want to find its button. +inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "target", pszName); +} + +// Keeps clutter down a bit, when writing key-value pairs +#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue) +#define WRITEKEY_FLOAT(pf, szKeyName, flKeyValue) \ + ENGINE_FPRINTF(pf, "\"%s\" \"%f\"\n", szKeyName, flKeyValue) +#define WRITEKEY_STRING(pf, szKeyName, szKeyValue) \ + ENGINE_FPRINTF(pf, "\"%s\" \"%s\"\n", szKeyName, szKeyValue) +#define WRITEKEY_VECTOR(pf, szKeyName, flX, flY, flZ) \ + ENGINE_FPRINTF(pf, "\"%s\" \"%f %f %f\"\n", szKeyName, flX, flY, flZ) + +// Keeps clutter down a bit, when using a float as a bit-vector +#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) +#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) +#define FBitSet(flBitVector, bit) ((int)(flBitVector) & (bit)) + +// Makes these more explicit, and easier to find +#define FILE_GLOBAL static +#define DLL_GLOBAL + +// Until we figure out why "const" gives the compiler problems, we'll just have to use +// this bogus "empty" define to mark things as constant. +#define CONSTANT + +// More explicit than "int" +typedef int EOFFSET; + +// In case it's not alread defined +typedef int BOOL; + +// In case this ever changes +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +// Keeps clutter down a bit, when declaring external entity/global method prototypes +#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName( void ) +#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) +#ifndef UTIL_DLLEXPORT +#ifdef _WIN32 +#define UTIL_DLLEXPORT _declspec( dllexport ) +#else +#define UTIL_DLLEXPORT __attribute__ ((visibility("default"))) +#endif +#endif + +// This is the glue that hooks .MAP entity class names to our CPP classes +// The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress() +// The function is used to intialize / allocate the object for the entity +#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ + extern "C" UTIL_DLLEXPORT void mapClassName( entvars_t *pev ); \ + void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } + +// +// Conversion among the three types of "entity", including identity-conversions. +// +#ifdef DEBUG + extern edict_t *DBG_EntOfVars(const entvars_t *pev); + inline edict_t *ENT(const entvars_t *pev) { return DBG_EntOfVars(pev); } +#else + inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; } +#endif +inline edict_t *ENT(edict_t *pent) { return pent; } +inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); } +inline EOFFSET OFFSET(EOFFSET eoffset) { return eoffset; } +inline EOFFSET OFFSET(const edict_t *pent) +{ +#if _DEBUG + if ( !pent ) + ALERT( at_error, "Bad ent in OFFSET()\n" ); +#endif + return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); +} +inline EOFFSET OFFSET(entvars_t *pev) +{ +#if _DEBUG + if ( !pev ) + ALERT( at_error, "Bad pev in OFFSET()\n" ); +#endif + return OFFSET(ENT(pev)); +} +inline entvars_t *VARS(entvars_t *pev) { return pev; } + +inline entvars_t *VARS(edict_t *pent) +{ + if ( !pent ) + return NULL; + + return &pent->v; +} + +inline entvars_t* VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } +inline int ENTINDEX(const edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } +inline edict_t* INDEXENT( int iEdictNum ) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } + +extern void NetworkMeterMessageBegin(int msg_dest, int msg_type, const float* pOrigin, edict_t* ed); + +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) +{ + NetworkMeterMessageBegin(msg_dest, msg_type, pOrigin, ENT(ent)); +} +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t* ed = NULL) +{ + NetworkMeterMessageBegin(msg_dest, msg_type, pOrigin, ed); +} + +// Testing the three types of "entity" for nullity +#define eoNullEntity 0 +inline BOOL FNullEnt(EOFFSET eoffset) { return eoffset == 0; } +inline BOOL FNullEnt(const edict_t* pent) { return pent == NULL || FNullEnt(OFFSET(pent)); } +inline BOOL FNullEnt(entvars_t* pev) { return pev == NULL || FNullEnt(OFFSET(pev)); } + +// Testing strings for nullity +#define iStringNull 0 +inline BOOL FStringNull(int iString) { return iString == iStringNull; } + +#define cchMapNameMost 32 + +// Dot products for view cone checking +#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees +#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks +#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks +#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks + +// All monsters need this data +#define DONT_BLEED -1 +#define BLOOD_COLOR_RED (BYTE)247 +#define BLOOD_COLOR_YELLOW (BYTE)195 +#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW + +typedef enum +{ + + MONSTERSTATE_NONE = 0, + MONSTERSTATE_IDLE, + MONSTERSTATE_COMBAT, + MONSTERSTATE_ALERT, + MONSTERSTATE_HUNT, + MONSTERSTATE_PRONE, + MONSTERSTATE_SCRIPT, + MONSTERSTATE_PLAYDEAD, + MONSTERSTATE_DEAD + +} MONSTERSTATE; + + + +// Things that toggle (buttons/triggers/doors) need this +typedef enum + { + TS_AT_TOP, + TS_AT_BOTTOM, + TS_GOING_UP, + TS_GOING_DOWN + } TOGGLE_STATE; + +// Misc useful +inline BOOL FStrEq(const char*sz1, const char*sz2) + { return (strcmp(sz1, sz2) == 0); } +inline BOOL FClassnameIs(edict_t* pent, const char* szClassname) + { return FStrEq(STRING(VARS(pent)->classname), szClassname); } +inline BOOL FClassnameIs(entvars_t* pev, const char* szClassname) + { return FStrEq(STRING(pev->classname), szClassname); } + +class CBaseEntity; + +// Misc. Prototypes +extern void UTIL_SetSize (entvars_t* pev, const Vector &vecMin, const Vector &vecMax); +extern float UTIL_VecToYaw (const Vector &vec); +extern Vector UTIL_VecToAngles (const Vector &vec); +extern float UTIL_AngleMod (float a); +extern float UTIL_AngleDiff ( float destAngle, float srcAngle ); + +extern CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius); +extern CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ); +extern CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName ); +extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName ); +extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius ); +int UTIL_CountEntitiesInSphere(const Vector& inVecCenter, float inRadius, const char* inClassName); + +// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected +// otherwise returns NULL +// Index is 1 based +extern CBaseEntity *UTIL_PlayerByIndex( int playerIndex ); + +#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent) +extern void UTIL_MakeVectors (const Vector &vecAngles); + +// Pass in an array of pointers and an array size, it fills the array and returns the number inserted +extern int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ); +extern int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ); + +inline void UTIL_MakeVectorsPrivate( const Vector &vecAngles, float *p_vForward, float *p_vRight, float *p_vUp ) +{ + g_engfuncs.pfnAngleVectors( vecAngles, p_vForward, p_vRight, p_vUp ); +} + +extern void UTIL_MakeAimVectors ( const Vector &vecAngles ); // like MakeVectors, but assumes pitch isn't inverted +extern void UTIL_MakeInvVectors ( const Vector &vec, globalvars_t *pgv ); + +extern void UTIL_Error ( CBaseEntity *pEntity, const char *pMessage ); +extern void UTIL_SetOrigin ( entvars_t* pev, const Vector &vecOrigin ); +extern void UTIL_EmitAmbientSound ( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ); +extern void UTIL_ParticleEffect ( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ); +extern void UTIL_ScreenShake ( const Vector ¢er, float amplitude, float frequency, float duration, float radius ); +extern void UTIL_ScreenShakeAll ( const Vector ¢er, float amplitude, float frequency, float duration ); +extern void UTIL_ShowMessage ( const char *pString, CBaseEntity *pPlayer); +typedef enum { NORMAL = 0, TOOLTIP = 1, CENTER = 2} SHOWMESSAGE_TYPE; +extern void UTIL_ShowMessage2 ( const char *pString, CBaseEntity *pPlayer, SHOWMESSAGE_TYPE type = NORMAL); +extern void UTIL_ShowMessageAll ( const char *pString ); +extern void UTIL_ScreenFadeAll ( const Vector &color, float fadeTime, float holdTime, int alpha, int flags ); +extern void UTIL_ScreenFade ( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ); + +typedef enum { ignore_monsters=1, dont_ignore_monsters=0, missile=2 } IGNORE_MONSTERS; +typedef enum { ignore_glass=1, dont_ignore_glass=0 } IGNORE_GLASS; +extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr); +extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr); +typedef enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 }; +extern void UTIL_TraceHull (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr); +extern TraceResult UTIL_GetGlobalTrace (void); +extern void UTIL_TraceModel (const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr); +extern Vector UTIL_GetAimVector (edict_t* pent, float flSpeed); +extern int UTIL_PointContents (const Vector &vec); + +extern int UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator); +extern void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ); +extern void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ); +extern Vector UTIL_RandomBloodVector( void ); +extern BOOL UTIL_ShouldShowBlood( int bloodColor ); +extern void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ); +extern void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ); +extern void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ); +extern void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ); +extern void UTIL_Sparks( const Vector &position ); +extern void UTIL_Ricochet( const Vector &position, float scale ); +extern void UTIL_StringToVector( float *pVector, const char *pString ); +extern void UTIL_StringToIntArray( int *pVector, int count, const char *pString ); +extern Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ); +extern float UTIL_Approach( float target, float value, float speed ); +extern float UTIL_ApproachAngle( float target, float value, float speed ); +extern float UTIL_AngleDistance( float next, float cur ); + +extern char *UTIL_VarArgs( char *format, ... ); +extern void UTIL_Remove( CBaseEntity *pEntity ); +extern BOOL UTIL_IsValidEntity( edict_t *pent ); +extern BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ); + +// Use for ease-in, ease-out style interpolation (accel/decel) +extern float UTIL_SplineFraction( float value, float scale ); + +// Search for water transition along a vertical line +extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); +extern void UTIL_Bubbles( Vector mins, Vector maxs, int count ); +extern void UTIL_BubbleTrail( Vector from, Vector to, int count ); + +// allows precacheing of other entities +extern void UTIL_PrecacheOther( const char *szClassname ); + +// prints a message to each client +extern void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); +inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ) +{ + UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); +} + +class CBasePlayerItem; +class CBasePlayer; +extern BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// prints messages through the HUD +extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); + +typedef struct hudtextparms_s +{ + float x; + float y; + int effect; + byte r1, g1, b1, a1; + byte r2, g2, b2, a2; + float fadeinTime; + float fadeoutTime; + float holdTime; + float fxTime; + int channel; +} hudtextparms_t; + +// prints as transparent 'title' to the HUD +extern void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ); +extern void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ); + +// for handy use with ClientPrint params +extern char *UTIL_dtos1( int d ); +extern char *UTIL_dtos2( int d ); +extern char *UTIL_dtos3( int d ); +extern char *UTIL_dtos4( int d ); + +// Writes message to console with timestamp and FragLog header. +extern void UTIL_LogPrintf( char *fmt, ... ); + +// Sorta like FInViewCone, but for nonmonsters. +extern float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); + +extern void UTIL_StripToken( const char *pKey, char *pDest );// for redundant keynames + +// Misc functions +extern void SetMovedir(entvars_t* pev); +extern Vector VecBModelOrigin( entvars_t* pevBModel ); +extern int BuildChangeList( LEVELLIST *pLevelList, int maxList ); + +// +// How did I ever live without ASSERT? +// +#include "../localassert.h" +//#ifdef DEBUG +//void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage); +//#define ASSERT(f) DBG_AssertFunction(f, #f, __FILE__, __LINE__, NULL) +//#define ASSERTSZ(f, sz) DBG_AssertFunction(f, #f, __FILE__, __LINE__, sz) +//#else // !DEBUG +//#define ASSERT(f) +//#define ASSERTSZ(f, sz) +//#endif // !DEBUG + +extern DLL_GLOBAL const Vector g_vecZero; + +// +// Constants that were used only by QC (maybe not used at all now) +// +// Un-comment only as needed +// +#define LANGUAGE_ENGLISH 0 +#define LANGUAGE_GERMAN 1 +#define LANGUAGE_FRENCH 2 +#define LANGUAGE_BRITISH 3 + +extern DLL_GLOBAL int g_Language; + +#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation +#define AMBIENT_SOUND_EVERYWHERE 1 +#define AMBIENT_SOUND_SMALLRADIUS 2 +#define AMBIENT_SOUND_MEDIUMRADIUS 4 +#define AMBIENT_SOUND_LARGERADIUS 8 +#define AMBIENT_SOUND_START_SILENT 16 +#define AMBIENT_SOUND_NOT_LOOPING 32 + +#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements + +#define SND_SPAWNING (1<<8) // duplicated in protocol.h we're spawing, used in some cases for ambients +#define SND_STOP (1<<5) // duplicated in protocol.h stop sound +#define SND_CHANGE_VOL (1<<6) // duplicated in protocol.h change sound vol +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +#define LFO_SQUARE 1 +#define LFO_TRIANGLE 2 +#define LFO_RANDOM 3 + +// func_rotating +#define SF_BRUSH_ROTATE_Y_AXIS 0 +#define SF_BRUSH_ROTATE_INSTANT 1 +#define SF_BRUSH_ROTATE_BACKWARDS 2 +#define SF_BRUSH_ROTATE_Z_AXIS 4 +#define SF_BRUSH_ROTATE_X_AXIS 8 +#define SF_PENDULUM_AUTO_RETURN 16 +#define SF_PENDULUM_PASSABLE 32 + + +#define SF_BRUSH_ROTATE_SMALLRADIUS 128 +#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 +#define SF_BRUSH_ROTATE_LARGERADIUS 512 + +#define PUSH_BLOCK_ONLY_X 1 +#define PUSH_BLOCK_ONLY_Y 2 + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_HULL_MAX Vector( 16, 16, 36) +#define VEC_HUMAN_HULL_MIN Vector( -16, -16, 0 ) +#define VEC_HUMAN_HULL_MAX Vector( 16, 16, 72 ) +#define VEC_HUMAN_HULL_DUCK Vector( 16, 16, 36 ) + +#define VEC_VIEW Vector( 0, 0, 28 ) + +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) +#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18) +//#define VEC_DUCK_VIEW Vector( 0, 0, 12 ) + +#define SVC_TEMPENTITY 23 +#define SVC_INTERMISSION 30 +#define SVC_CDTRACK 32 +#define SVC_WEAPONANIM 35 +#define SVC_ROOMTYPE 37 + +// triggers +#define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger +#define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger +#define SF_TRIGGER_PUSHABLES 4// only pushables can fire this trigger + +// func breakable +#define SF_BREAK_TRIGGER_ONLY 1// may only be broken by trigger +#define SF_BREAK_TOUCH 2// can be 'crashed through' by running player (plate glass) +#define SF_BREAK_PRESSURE 4// can be broken by a player standing on it +#define SF_BREAK_CROWBAR 256// instant break if hit with crowbar + +// func_pushable (it's also func_breakable, so don't collide with those flags) +#define SF_PUSH_BREAKABLE 128 + +#define SF_LIGHT_START_OFF 1 + +#define SPAWNFLAG_NOMESSAGE 1 +#define SPAWNFLAG_NOTOUCH 1 +#define SPAWNFLAG_DROIDONLY 4 + +#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons) + +#define TELE_PLAYER_ONLY 1 +#define TELE_SILENT 2 + +#define SF_TRIG_PUSH_ONCE 1 + + +// Sound Utilities + +// sentence groups +#define CBSENTENCENAME_MAX 16 +#define CVOXFILESENTENCEMAX 1536 // max number of sentences in game. NOTE: this must match + // CVOXFILESENTENCEMAX in engine\sound.h!!! + +extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; +extern int gcallsentences; + +int USENTENCEG_Pick(int isentenceg, char *szfound); +int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset); +void USENTENCEG_InitLRU(unsigned char *plru, int count); + +void SENTENCEG_Init(); +void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); +int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch); +int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch); +int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch, int ipick, int freset); +int SENTENCEG_GetIndex(const char *szrootname); +int SENTENCEG_Lookup(const char *sample, char *sentencenum); + +void TEXTURETYPE_Init(); +char TEXTURETYPE_Find(char *name); +float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); + +// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100 +// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 +// down to 1 is a lower pitch. 150 to 70 is the realistic range. +// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as +// fast as EMIT_SOUND (the pitchshift mixer is not native coded). + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, + int flags, int pitch); + + +inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation) +{ + EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM); +} + +inline void STOP_SOUND(edict_t *entity, int channel, const char *sample) +{ + EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM); +} + +void EMIT_SOUND_SUIT(edict_t *entity, const char *sample); +void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg); +void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); + +#define PRECACHE_SOUND_ARRAY( a ) \ + { for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); } + +#define EMIT_SOUND_ARRAY_DYN( chan, array ) \ + EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) ); + +#define RANDOM_SOUND_ARRAY( array ) (array) [ RANDOM_LONG(0,ARRAYSIZE( (array) )-1) ] + +#define PLAYBACK_EVENT( flags, who, index ) PLAYBACK_EVENT_FULL( flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); +#define PLAYBACK_EVENT_DELAY( flags, who, index, delay ) PLAYBACK_EVENT_FULL( flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); + +#define GROUP_OP_AND 0 +#define GROUP_OP_NAND 1 + +extern int g_groupmask; +extern int g_groupop; + +class UTIL_GroupTrace +{ +public: + UTIL_GroupTrace( int groupmask, int op ); + ~UTIL_GroupTrace( void ); + +private: + int m_oldgroupmask, m_oldgroupop; +}; + +void UTIL_SetGroupTrace( int groupmask, int op ); +void UTIL_UnsetGroupTrace( void ); + +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); + +float UTIL_WeaponTimeBase( void ); + +// Leave last parameter to make the same as pEntity +void UTIL_SayText( const char *pText, CBaseEntity *pEntity, int inEntIndex = -1); +void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity, int inEntIndex = -1); + +//: hope you dont mind me adding this, I use this in NSAdmin +// Statements like: +// #pragma message(Reminder "Fix this problem!") +// Which will cause messages like: +// C:\Source\Project\main.cpp(47): Reminder: Fix this problem! +// to show up during compiles. Note that you can NOT use the +// words "error" or "warning" in your reminders, since it will +// make the IDE think it should abort execution. You can double +// click on these messages and jump to the line in question. +#define Stringize( L ) #L +#define MakeString( M, L ) M(L) +#define $Line \ + MakeString( Stringize, __LINE__ ) +#define Reminder \ + __FILE__ "(" $Line ") : Reminder: " + + +#endif diff --git a/main/source/dlls/vector.h b/main/source/dlls/vector.h index f58820a3..66c53617 100644 --- a/main/source/dlls/vector.h +++ b/main/source/dlls/vector.h @@ -1,20 +1,20 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef VECTOR2D_H -#define VECTOR2D_H - -#include "../common/vectorclasses.h" - -#endif +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#include "../common/vectorclasses.h" + +#endif diff --git a/main/source/dlls/weapons.cpp b/main/source/dlls/weapons.cpp index c216b9fc..fd463cf9 100644 --- a/main/source/dlls/weapons.cpp +++ b/main/source/dlls/weapons.cpp @@ -1,1926 +1,1926 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// ===== weapons.cpp ======================================================== -// -// functions governing the selection/use of weapons for players -// -// $Workfile: weapons.cpp $ -// $Date: 2002/11/22 21:13:52 $ -// -//------------------------------------------------------------------------------- -// $Log: weapons.cpp,v $ -// Revision 1.49 2002/11/22 21:13:52 Flayra -// - mp_consistency changes -// -// Revision 1.48 2002/11/12 02:19:43 Flayra -// - Fixed problem where friendly bulletfire was doing damage -// -// Revision 1.47 2002/10/24 21:19:11 Flayra -// - Reworked jetpack effects -// - Added a few extra sounds -// -// Revision 1.46 2002/10/16 00:41:15 Flayra -// - Removed unneeds sounds and events -// - Added distress beacon event -// - Added general purpose particle event -// -// Revision 1.45 2002/09/25 20:40:09 Flayra -// - Play different sound for aliens when they get weapons -// -// Revision 1.44 2002/09/23 22:04:00 Flayra -// - Regular update -// -// Revision 1.43 2002/08/31 18:01:18 Flayra -// - Work at VALVe -// -// Revision 1.42 2002/07/26 23:01:05 Flayra -// - Precache numerical feedback event -// -// Revision 1.41 2002/07/23 16:48:37 Flayra -// - Added distress beacon -// -// Revision 1.40 2002/07/08 16:35:17 Flayra -// - Added document header, updates for cheat protection, added constants -// -//=============================================================================== -#include "../util/nowarnings.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "decals.h" -#include "gamerules.h" -#include "../mod/AvHConstants.h" -#include "../mod/AvHMarineEquipmentConstants.h" -#include "../mod/AvHAlienWeaponConstants.h" -#include "../mod/AvHAlienEquipmentConstants.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHNetworkMessages.h" - -extern CGraph WorldGraph; -extern int gEvilImpulse101; - -int gJetpackEventID; -int gStartOverwatchEventID; -int gEndOverwatchEventID; -int gTeleportEventID; -int gBlinkEffectSuccessEventID; -int gPhaseInEventID; -int gSiegeHitEventID; -int gSiegeViewHitEventID; -int gCommanderPointsAwardedEventID; -int gAlienSightOnEventID; -int gAlienSightOffEventID; -//int gParalysisStartEventID; -int gRegenerationEventID; -int gStartCloakEventID; -int gEndCloakEventID; -int gSporeCloudEventID; -int gUmbraCloudEventID; -int gStopScreamEventID; - -int gWelderEventID; -int gWelderConstEventID; -//int gWallJumpEventID; -//int gFlightEventID; -int gEmptySoundEventID; -int gNumericalInfoEventID; -int gInvalidActionEventID; -int gParticleEventID; -int gDistressBeaconEventID; -int gWeaponAnimationEventID; -int gLevelUpEventID; -int gMetabolizeSuccessEventID; - -#define NOT_USED 255 - -DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam -DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr"; -DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot -DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball -DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud -DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion -DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model -DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood -DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood - -ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; -AmmoInfo CBasePlayerItem::AmmoInfoArray[MAX_AMMO_SLOTS]; - -MULTIDAMAGE gMultiDamage; - -#define TRACER_FREQ 4 // Tracers fire every fourth bullet - -extern bool gCanMove[]; - -//========================================================= -// MaxAmmoCarry - pass in a name and this function will tell -// you the maximum amount of that type of ammunition that a -// player can carry. -//========================================================= -int MaxAmmoCarry( int iszName ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo1 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo1 ) ) - return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo1; - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo2 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo2 ) ) - return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo2; - } - - ALERT( at_console, "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName ) ); - return -1; -} - - -/* -============================================================================== - -MULTI-DAMAGE - -Collects multiple small damages into a single damage - -============================================================================== -*/ - -// -// ClearMultiDamage - resets the global multi damage accumulator -// -void ClearMultiDamage(void) -{ - gMultiDamage.pEntity = NULL; - gMultiDamage.amount = 0; - gMultiDamage.type = 0; -} - -// -// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity -// -// GLOBALS USED: -// gMultiDamage - -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) -{ - Vector vecSpot1;//where blood comes from - Vector vecDir;//direction blood should go - TraceResult tr; - - if ( !gMultiDamage.pEntity ) - return; - - float theDamage = gMultiDamage.amount; - gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, theDamage, gMultiDamage.type ); -} - - -// GLOBALS USED: -// gMultiDamage - -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) -{ - if ( !pEntity ) - return; - - gMultiDamage.type |= bitsDamageType; - - if ( pEntity != gMultiDamage.pEntity ) - { - ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker! - gMultiDamage.pEntity = pEntity; - gMultiDamage.amount = 0; - } - - gMultiDamage.amount += flDamage; -} - -/* -================ -SpawnBlood -================ -*/ -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) -{ - if(flDamage >= 0.0f) - { - if(bloodColor == DONT_BLEED) - { - UTIL_Sparks(vecSpot); - } - else - { - UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); - } - } -} - - -int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) -{ - if ( !pEntity ) - return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); - - return pEntity->DamageDecal( bitsDamageType ); -} - -void DecalGunshot( TraceResult *pTrace, int iBulletType ) -{ - // Is the entity valid - if ( !UTIL_IsValidEntity( pTrace->pHit ) ) - return; - - if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP ) - { - CBaseEntity *pEntity = NULL; - // Decal the wall with a gunshot - if ( !FNullEnt(pTrace->pHit) ) - pEntity = CBaseEntity::Instance(pTrace->pHit); - -// switch( iBulletType ) -// { -// case BULLET_PLAYER_9MM: -// case BULLET_MONSTER_9MM: -// case BULLET_PLAYER_MP5: -// case BULLET_MONSTER_MP5: -// case BULLET_PLAYER_BUCKSHOT: -// case BULLET_PLAYER_357: -// default: - // smoke and decal - UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); -// break; -// case BULLET_MONSTER_12MM: -// // smoke and decal -// UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); -// break; -// case BULLET_PLAYER_CROWBAR: -// // wall decal -// UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); -// break; -// } - } -} - - - -// -// EjectBrass - tosses a brass shell from passed origin at passed velocity -// -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) -{ - // FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see. - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE( TE_MODEL); - WRITE_COORD( vecOrigin.x); - WRITE_COORD( vecOrigin.y); - WRITE_COORD( vecOrigin.z); - WRITE_COORD( vecVelocity.x); - WRITE_COORD( vecVelocity.y); - WRITE_COORD( vecVelocity.z); - WRITE_ANGLE( rotation ); - WRITE_SHORT( model ); - WRITE_BYTE ( soundtype); - WRITE_BYTE ( 25 );// 2.5 seconds - MESSAGE_END(); -} - - -#if 0 -// UNDONE: This is no longer used? -void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE ( TE_EXPLODEMODEL ); - WRITE_COORD( vecOrigin.x ); - WRITE_COORD( vecOrigin.y ); - WRITE_COORD( vecOrigin.z ); - WRITE_COORD( speed ); - WRITE_SHORT( model ); - WRITE_SHORT( count ); - WRITE_BYTE ( 15 );// 1.5 seconds - MESSAGE_END(); -} -#endif - - -int giAmmoIndex = 0; - -// Precaches the ammo and queues the ammo info for sending to clients -void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) -{ - // make sure it's not already in the registry - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName) - continue; - - if ( stricmp( CBasePlayerItem::AmmoInfoArray[i].pszName, szAmmoname ) == 0 ) - return; // ammo already in registry, just quite - } - - - giAmmoIndex++; - ASSERT( giAmmoIndex < MAX_AMMO_SLOTS ); - if ( giAmmoIndex >= MAX_AMMO_SLOTS ) - giAmmoIndex = 0; - - CBasePlayerItem::AmmoInfoArray[giAmmoIndex].pszName = szAmmoname; - CBasePlayerItem::AmmoInfoArray[giAmmoIndex].iId = giAmmoIndex; // yes, this info is redundant -} - - -// Precaches the weapon and queues the weapon info for sending to clients -void UTIL_PrecacheOtherWeapon( const char *szClassname ) -{ - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOtherWeapon\n" ); - return; - } - - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - - if (pEntity) - { - ItemInfo II; - pEntity->Precache( ); - memset( &II, 0, sizeof II ); - if ( ((CBasePlayerItem*)pEntity)->GetItemInfo( &II ) ) - { - CBasePlayerItem::ItemInfoArray[II.iId] = II; - - if ( II.pszAmmo1 && *II.pszAmmo1 ) - { - AddAmmoNameToAmmoRegistry( II.pszAmmo1 ); - } - - if ( II.pszAmmo2 && *II.pszAmmo2 ) - { - AddAmmoNameToAmmoRegistry( II.pszAmmo2 ); - } - - memset( &II, 0, sizeof II ); - } - } - - REMOVE_ENTITY(pent); -} - -// called by worldspawn -void W_Precache(void) -{ - memset( CBasePlayerItem::ItemInfoArray, 0, sizeof(CBasePlayerItem::ItemInfoArray) ); - memset( CBasePlayerItem::AmmoInfoArray, 0, sizeof(CBasePlayerItem::AmmoInfoArray) ); - giAmmoIndex = 0; - - // Marine weapons - //UTIL_PrecacheOtherWeapon("weapon_9mmhandgun"); - //UTIL_PrecacheOtherWeapon("weapon_glock"); - //UTIL_PrecacheOther("ammo_9mmclip"); - - // Player assets - PRECACHE_UNMODIFIED_MODEL(kReadyRoomModel); - PRECACHE_UNMODIFIED_MODEL(kMarineSoldierModel); - PRECACHE_UNMODIFIED_MODEL(kHeavySoldierModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelOneModel); - PRECACHE_UNMODIFIED_SOUND(kDistressBeaconSound); - PRECACHE_UNMODIFIED_SOUND(kLevelUpMarineSound); - PRECACHE_UNMODIFIED_SOUND(kLevelUpAlienSound); - PRECACHE_UNMODIFIED_SOUND(kAlienBuildingSound1); - PRECACHE_UNMODIFIED_SOUND(kAlienBuildingSound2); - PRECACHE_SOUND(kMyHiveEasterEgg); - - //PRECACHE_UNMODIFIED_SOUND(kAlienAbilitiesGrantedSound); - //PRECACHE_UNMODIFIED_SOUND(kAlienAbilitiesLostSound); - - PRECACHE_UNMODIFIED_MODEL(kAlienLevelTwoModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelThreeModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFourModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFiveModel); - - PRECACHE_UNMODIFIED_MODEL(kMarineCommanderModel); - PRECACHE_UNMODIFIED_MODEL(kAlienGestateModel); - // : 1072 - // Added some client side consistency checks. - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash1.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash3.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/digesting.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/membrane.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/hera_fog.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/webstrand.spr"); - - UTIL_PrecacheOtherWeapon(kwsMine); - UTIL_PrecacheOtherWeapon(kwsKnife); - UTIL_PrecacheOtherWeapon(kwsMachineGun); - UTIL_PrecacheOtherWeapon(kwsPistol); - UTIL_PrecacheOtherWeapon(kwsShotGun); - UTIL_PrecacheOtherWeapon(kwsHeavyMachineGun); - UTIL_PrecacheOtherWeapon(kwsGrenadeGun); - UTIL_PrecacheOtherWeapon(kwsGrenade); - - // Alien weapons - UTIL_PrecacheOtherWeapon(kwsSpitGun); - UTIL_PrecacheOther(kwsSpitProjectile); - UTIL_PrecacheOther(kwsWebProjectile); - UTIL_PrecacheOtherWeapon(kwsClaws); - UTIL_PrecacheOtherWeapon(kwsSwipe); - UTIL_PrecacheOtherWeapon(kwsSporeGun); - UTIL_PrecacheOther(kwsSporeProjectile); -// UTIL_PrecacheOtherWeapon(kwsParalysisGun); - UTIL_PrecacheOtherWeapon(kwsSpikeGun); - UTIL_PrecacheOtherWeapon(kwsBiteGun); - UTIL_PrecacheOtherWeapon(kwsBite2Gun); - UTIL_PrecacheOtherWeapon(kwsHealingSpray); - UTIL_PrecacheOtherWeapon(kwsWebSpinner); -// UTIL_PrecacheOtherWeapon(kwsBabblerGun); - UTIL_PrecacheOtherWeapon(kwsPrimalScream); - UTIL_PrecacheOtherWeapon(kwsParasiteGun); - UTIL_PrecacheOtherWeapon(kwsMetabolize); - UTIL_PrecacheOtherWeapon(kwsUmbraGun); - UTIL_PrecacheOtherWeapon(kwsBlinkGun); - UTIL_PrecacheOtherWeapon(kwsDivineWind); - UTIL_PrecacheOtherWeapon(kwsBileBombGun); - UTIL_PrecacheOtherWeapon(kwsAcidRocketGun); - UTIL_PrecacheOtherWeapon(kwsStomp); - UTIL_PrecacheOtherWeapon(kwsDevour); -// UTIL_PrecacheOtherWeapon(kwsAmplify); - UTIL_PrecacheOther(kwsBileBomb); - - // Alien abilities - UTIL_PrecacheOtherWeapon(kwsLeap); - UTIL_PrecacheOtherWeapon(kwsCharge); - - // Alien buildings - UTIL_PrecacheOther(kwsAlienResourceTower); - UTIL_PrecacheOther(kwsOffenseChamber); - UTIL_PrecacheOther(kwsDefenseChamber); - UTIL_PrecacheOther(kwsSensoryChamber); - UTIL_PrecacheOther(kwsMovementChamber); - UTIL_PrecacheOther(kesTeamWebStrand); - - // Equipment - //UTIL_PrecacheOtherWeapon("weapon_tripmine"); - UTIL_PrecacheOther(kwsScan); - UTIL_PrecacheOther(kwsPhaseGate); - //UTIL_PrecacheOther(kwsNuke); - - // Marine buildings - UTIL_PrecacheOther(kwsTeamCommand); - UTIL_PrecacheOther(kwsResourceTower); - UTIL_PrecacheOther(kwsInfantryPortal); - UTIL_PrecacheOther(kwsTurretFactory); - UTIL_PrecacheOther(kwsArmory); - UTIL_PrecacheOther(kwsAdvancedArmory); - UTIL_PrecacheOther(kwsArmsLab); - UTIL_PrecacheOther(kwsPrototypeLab); - UTIL_PrecacheOther(kwsObservatory); - //UTIL_PrecacheOther(kwsChemlab); - //UTIL_PrecacheOther(kwsMedlab); - //UTIL_PrecacheOther(kwsNukePlant); - UTIL_PrecacheOther(kwsDeployedTurret); - UTIL_PrecacheOther(kwsSiegeTurret); - - // container for dropped deathmatch weapons - UTIL_PrecacheOther("weaponbox"); - - UTIL_PrecacheOtherWeapon(kwsWelder); - UTIL_PrecacheOther(kwsDeployedMine); - UTIL_PrecacheOther(kwsHealth); - UTIL_PrecacheOther(kwsCatalyst); - UTIL_PrecacheOther(kwsGenericAmmo); - UTIL_PrecacheOther(kwsHeavyArmor); - UTIL_PrecacheOther(kwsJetpack); - UTIL_PrecacheOther(kwsAmmoPack); - - UTIL_PrecacheOther(kwsDebugEntity); - - // Precache other events - gJetpackEventID = PRECACHE_EVENT(1, kJetpackEvent); - //gStartOverwatchEventID = PRECACHE_EVENT(1, kStartOverwatchEvent); - //gEndOverwatchEventID = PRECACHE_EVENT(1, kEndOverwatchEvent); - - // Alien upgrade events - gRegenerationEventID = PRECACHE_EVENT(1, kRegenerationEvent); - gStartCloakEventID = PRECACHE_EVENT(1, kStartCloakEvent); - gEndCloakEventID = PRECACHE_EVENT(1, kEndCloakEvent); - - // Extra alien weapon events - //gEnsnareHitEventID = PRECACHE_EVENT(1, kEnsnareHitEventName); - gSporeCloudEventID = PRECACHE_EVENT(1, kSporeCloudEventName); - gUmbraCloudEventID = PRECACHE_EVENT(1, kUmbraCloudEventName); - gStopScreamEventID = PRECACHE_EVENT(1, kStopPrimalScreamSoundEvent); - - // Extra marine events - gTeleportEventID = PRECACHE_EVENT(1, kTeleportEvent); - gBlinkEffectSuccessEventID = PRECACHE_EVENT(1, kBlinkEffectSuccessEventName); - gPhaseInEventID = PRECACHE_EVENT(1, kPhaseInEvent); - gSiegeHitEventID = PRECACHE_EVENT(1, kSiegeHitEvent); - gSiegeViewHitEventID = PRECACHE_EVENT(1, kSiegeViewHitEvent); - gCommanderPointsAwardedEventID = PRECACHE_EVENT(1, kCommanderPointsAwardedEvent); - gAlienSightOnEventID = PRECACHE_EVENT(1, kAlienSightOnEvent); - gAlienSightOffEventID = PRECACHE_EVENT(1, kAlienSightOffEvent); -// gParalysisStartEventID = PRECACHE_EVENT(1, kParalysisStartEventName); - - //gWallJumpEventID = PRECACHE_EVENT(1, kWallJumpEvent); - //gFlightEventID = PRECACHE_EVENT(1, kFlightEvent); - PRECACHE_UNMODIFIED_SOUND(kConnectSound); - //PRECACHE_UNMODIFIED_SOUND(kDisconnectSound); - PRECACHE_UNMODIFIED_MODEL(kNullModel); - - UTIL_PrecacheOther("monster_sentry"); - - // Allow welder events in mapper build - gWelderEventID = PRECACHE_EVENT(1, kWelderEventName); - gWelderConstEventID = PRECACHE_EVENT(1, kWelderConstEventName); - PRECACHE_EVENT(1, kWelderStartEventName); - PRECACHE_EVENT(1, kWelderEndEventName); - - gEmptySoundEventID = PRECACHE_EVENT(1, kEmptySoundEvent); - gNumericalInfoEventID = PRECACHE_EVENT(1, kNumericalInfoEvent); - gInvalidActionEventID = PRECACHE_EVENT(1, kInvalidActionEvent); - gParticleEventID = PRECACHE_EVENT(1, kParticleEvent); - gDistressBeaconEventID = PRECACHE_EVENT(1, kDistressBeaconEvent); - gWeaponAnimationEventID= PRECACHE_EVENT(1, kWeaponAnimationEvent); - gLevelUpEventID = PRECACHE_EVENT(1, kLevelUpEvent); - gMetabolizeSuccessEventID = PRECACHE_EVENT(1, kMetabolizeSuccessEventName); - - PRECACHE_UNMODIFIED_SOUND(kPhaseInSound); - - // Precache reload sound that is hardcoded deep in HL - PRECACHE_UNMODIFIED_SOUND(kEmptySound); - PRECACHE_UNMODIFIED_SOUND(kInvalidSound); - - // Not sure who's using these, but I keep getting errors that they're not precached. Buttons? - PRECACHE_UNMODIFIED_SOUND("buttons/spark1.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark2.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark3.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark4.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark5.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark6.wav"); - - // For grunts. Careful, this uses the same weapon id that the grenade gun uses - //UTIL_PrecacheOtherWeapon("weapon_9mmAR"); - - // common world objects -// UTIL_PrecacheOther( "item_suit" ); -// UTIL_PrecacheOther( "item_battery" ); -// UTIL_PrecacheOther( "item_antidote" ); -// UTIL_PrecacheOther( "item_security" ); -// UTIL_PrecacheOther( "item_longjump" ); - - // shotgun -// UTIL_PrecacheOtherWeapon( "weapon_shotgun" ); -// UTIL_PrecacheOther( "ammo_buckshot" ); -// -// // crowbar -// UTIL_PrecacheOtherWeapon( "weapon_rowbar" ); -// -// // glock -// UTIL_PrecacheOtherWeapon( "weapon_9mmhandgun" ); -// UTIL_PrecacheOther( "ammo_9mmclip" ); -// -// // mp5 -// UTIL_PrecacheOtherWeapon( "weapon_9mmAR" ); -// UTIL_PrecacheOther( "ammo_9mmAR" ); -// UTIL_PrecacheOther( "ammo_ARgrenades" ); - -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // python -// UTIL_PrecacheOtherWeapon( "weapon_357" ); -// UTIL_PrecacheOther( "ammo_357" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // gauss -// UTIL_PrecacheOtherWeapon( "weapon_gauss" ); -// UTIL_PrecacheOther( "ammo_gaussclip" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // rpg -// UTIL_PrecacheOtherWeapon( "weapon_rpg" ); -// UTIL_PrecacheOther( "ammo_rpgclip" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // crossbow -// UTIL_PrecacheOtherWeapon( "weapon_crossbow" ); -// UTIL_PrecacheOther( "ammo_crossbow" ); -// UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // egon -// UTIL_PrecacheOtherWeapon( "weapon_egon" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // satchel charge -// UTIL_PrecacheOtherWeapon( "weapon_satchel" ); -//#endif -// -// // hand grenade -// UTIL_PrecacheOtherWeapon("weapon_handgrenade"); -// -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // squeak grenade -// UTIL_PrecacheOtherWeapon( "weapon_snark" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // hornetgun -// UTIL_PrecacheOtherWeapon( "weapon_hornetgun" ); -//#endif - - -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// if ( g_pGameRules->IsDeathmatch() ) -// { -// UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons -// } -//#endif - - g_sModelIndexFireball = PRECACHE_UNMODIFIED_MODEL ("sprites/zerogxplode.spr");// fireball - g_sModelIndexWExplosion = PRECACHE_UNMODIFIED_MODEL ("sprites/WXplo1.spr");// underwater fireball - g_sModelIndexSmoke = PRECACHE_UNMODIFIED_MODEL ("sprites/steam1.spr");// smoke - g_sModelIndexBubbles = PRECACHE_UNMODIFIED_MODEL ("sprites/bubble2.spr");//bubbles - g_sModelIndexBloodSpray = PRECACHE_UNMODIFIED_MODEL ("sprites/bloodspray.spr"); // initial blood - g_sModelIndexBloodDrop = PRECACHE_UNMODIFIED_MODEL ("sprites/blood.spr"); // splattered blood - - g_sModelIndexLaser = PRECACHE_UNMODIFIED_MODEL( (char *)g_pModelNameLaser ); - g_sModelIndexLaserDot = PRECACHE_UNMODIFIED_MODEL("sprites/laserdot.spr"); - - - // used by explosions - PRECACHE_UNMODIFIED_MODEL ("models/grenade.mdl"); - PRECACHE_UNMODIFIED_MODEL ("sprites/explode1.spr"); - - PRECACHE_SOUND ("weapons/debris1.wav");// explosion aftermaths - PRECACHE_SOUND ("weapons/debris2.wav");// explosion aftermaths - PRECACHE_SOUND ("weapons/debris3.wav");// explosion aftermaths - - PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound1); - PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound2); - PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound3); - PRECACHE_UNMODIFIED_SOUND (kGRHitSound); - - PRECACHE_UNMODIFIED_SOUND ("weapons/bullet_hit1.wav"); // hit by bullet - PRECACHE_UNMODIFIED_SOUND ("weapons/bullet_hit2.wav"); // hit by bullet - - PRECACHE_UNMODIFIED_SOUND ("items/weapondrop1.wav");// weapon falls to the ground - -} - - - - -TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlayerItem, m_pPlayer, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerItem, m_pNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerItem, m_iId, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ); - - -TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_iPrimaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iSecondaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iClip, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ); - - -void CBasePlayerItem :: SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-24, -24, 0); - pev->absmax = pev->origin + Vector(24, 24, 16); -} - -BOOL -CBasePlayerItem::CanDeploy( void ) -{ - return TRUE; -} - -// can this weapon be put away right now? -BOOL CBasePlayerItem::CanHolster( void ) -{ - return TRUE; -}; - -// returns is deploy was successful -BOOL CBasePlayerItem::Deploy( ) -{ - return TRUE; -} - -BOOL -CBasePlayerItem::IsUseable( void ) -{ - return TRUE; -} - - -//========================================================= -// Sets up movetype, size, solidtype for a new weapon. -//========================================================= -void CBasePlayerItem :: FallInit( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_BBOX; - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) );//pointsize until it lands on the ground. - - SetTouch(&CBasePlayerItem::DefaultTouch ); - SetThink(&CBasePlayerItem::FallThink ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -//========================================================= -// FallThink - Items that have just spawned run this think -// to catch them when they hit the ground. Once we're sure -// that the object is grounded, we change its solid type -// to trigger and set it in a large box that helps the -// player get it. -//========================================================= -void CBasePlayerItem::FallThink ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( pev->flags & FL_ONGROUND ) - { - // clatter if we have an owner (i.e., dropped by someone) - // don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!) - if ( !FNullEnt( pev->owner ) ) - { - int pitch = 95 + RANDOM_LONG(0,29); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "items/weapondrop1.wav", 1, ATTN_NORM, 0, pitch); - } - - // lie flat - pev->angles.x = 0; - pev->angles.z = 0; - - Materialize(); - } -} - -//========================================================= -// Materialize - make a CBasePlayerItem visible and tangible -//========================================================= -void CBasePlayerItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - pev->solid = SOLID_TRIGGER; - - UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch (&CBasePlayerItem::DefaultTouch); - SetThink (NULL); - - this->VirtualMaterialize(); -} - -//========================================================= -// AttemptToMaterialize - the item is trying to rematerialize, -// should it do so now or wait longer? -//========================================================= -void CBasePlayerItem::AttemptToMaterialize( void ) -{ - float time = g_pGameRules->FlWeaponTryRespawn( this ); - - if ( time == 0 ) - { - Materialize(); - return; - } - - pev->nextthink = gpGlobals->time + time; -} - -//========================================================= -// CheckRespawn - a player is taking this weapon, should -// it respawn? -//========================================================= -void CBasePlayerItem :: CheckRespawn ( void ) -{ - switch ( g_pGameRules->WeaponShouldRespawn( this ) ) - { - case GR_WEAPON_RESPAWN_YES: - Respawn(); - break; - case GR_WEAPON_RESPAWN_NO: - return; - break; - } -} - -//========================================================= -// Respawn- this item is already in the world, but it is -// invisible and intangible. Make it visible and tangible. -//========================================================= -CBaseEntity* CBasePlayerItem::Respawn( void ) -{ - // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code - // will decide when to make the weapon visible and touchable. - CBaseEntity *pNewWeapon = CBaseEntity::Create( (char *)STRING( pev->classname ), g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); - - if ( pNewWeapon ) - { - pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now - pNewWeapon->SetTouch( NULL );// no touch - pNewWeapon->SetThink(&CBasePlayerItem::AttemptToMaterialize ); - - DROP_TO_FLOOR ( ENT(pev) ); - - // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement, - // but when it should respawn is based on conditions belonging to the weapon that was taken. - pNewWeapon->pev->nextthink = g_pGameRules->FlWeaponRespawnTime( this ); - } - else - { - ALERT ( at_console, "Respawn failed to create %s!\n", STRING( pev->classname ) ); - } - - return pNewWeapon; -} - -void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) - return; - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // can I have this? - if ( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) - { - if ( gEvilImpulse101 ) - { - UTIL_Remove( this ); - } - return; - } - - if (pOther->AddPlayerItem( this )) - { - AttachToPlayer( pPlayer ); - - AvHPlayer* thePlayer = dynamic_cast(pPlayer); - if(thePlayer && thePlayer->GetIsAlien()) - { - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2-a.wav", 1, ATTN_NORM); - } - else - { - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); - } - } - - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? -} - -BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) -{ - if ( !isPredicted ) - { - return ( attack_time <= curtime ) ? TRUE : FALSE; - } - else - { - return ( attack_time <= 0.0 ) ? TRUE : FALSE; - } -} - - -void CBasePlayerWeapon::ItemPostFrame( void ) -{ - bool theAttackPressed = (m_pPlayer->pev->button & IN_ATTACK) && !(m_pPlayer->pev->button & IN_ATTACK2); - - bool theWeaponPrimes = (this->GetWeaponPrimeTime() > 0.0f); - bool theWeaponIsPriming = this->GetIsWeaponPriming(); - bool theWeaponIsPrimed = this->GetIsWeaponPrimed(); - - if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) - { - // complete the reload. - int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - // Add them to the clip - m_iClip += j; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; - - m_pPlayer->TabulateAmmo(); - - m_fInReload = FALSE; - } - -/* // +movement: Removed case for +attack2 since it's used for movement abilities - if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - - if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) - { - m_fFireOnEmpty = TRUE; - } - - m_pPlayer->TabulateAmmo(); - SecondaryAttack(); - m_pPlayer->pev->button &= ~IN_ATTACK2; - } - } - else -*/ - if ( theAttackPressed && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) - { - m_fFireOnEmpty = TRUE; - } - - m_pPlayer->TabulateAmmo(); - PrimaryAttack(); - } - } - else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - // reload when reload is pressed, or if no buttons are down and weapon is empty. - Reload(); - } - } - // +movement: Removed case for +attack2 - else if ( !(m_pPlayer->pev->button & (IN_ATTACK /* |IN_ATTACK2 */) ) ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - - // no fire buttons down - - m_fFireOnEmpty = FALSE; - - if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) - { - // weapon isn't useable, switch. - if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) - { - m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; - return; - } - } - else - { - // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) - { - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) - { - Reload(); - return; - } - } - } - - WeaponIdle( ); - } - return; - } - - // catch all - if ( ShouldWeaponIdle() ) - { - WeaponIdle(); - } -} - -void CBasePlayerItem::DestroyItem( void ) -{ - //KGP: this is a virtual function call for a reason... - // it had been replaced with the contents of - // CBasePlayerItem::VirtualDestroyItem, ignoring - // AvHBasePlayerWeapon::VirtualDestroyItem in 3.01 - this->VirtualDestroyItem(); -} - -void CBasePlayerItem::VirtualDestroyItem( void ) -{ - if ( m_pPlayer ) - { - // if attached to a player, remove. - m_pPlayer->RemovePlayerItem( this ); - } - - Kill( ); -} - -int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) -{ - m_pPlayer = pPlayer; - pPlayer->m_iHideHUD &= ~HIDEHUD_WEAPONS; - return TRUE; -} - -void CBasePlayerItem::Drop( void ) -{ - SetTouch( NULL ); - SetThink(&CBasePlayerItem::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Kill( void ) -{ - SetTouch( NULL ); - SetThink(&CBasePlayerItem::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->pev->viewmodel = 0; - m_pPlayer->pev->weaponmodel = 0; -} - -void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) -{ - pev->movetype = MOVETYPE_FOLLOW; - pev->solid = SOLID_NOT; - pev->aiment = pPlayer->edict(); - pev->effects = EF_NODRAW; // ?? - pev->modelindex = 0;// server won't send down to clients if modelindex == 0 - pev->model = iStringNull; - pev->owner = pPlayer->edict(); - pev->nextthink = gpGlobals->time + .1; - SetTouch( NULL ); -} - -void CBasePlayerItem::Spawn() -{ - CBaseAnimating::Spawn(); -} - -// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal -int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) -{ - if ( m_iDefaultAmmo ) - { - return ExtractAmmo( (CBasePlayerWeapon *)pOriginal ); - } - else - { - // a dead player dropped this. - return ExtractClipAmmo( (CBasePlayerWeapon *)pOriginal ); - } -} - - -int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) -{ - int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - - pPlayer->pev->weapons |= (1<GetAmmoIndex( pszAmmo1() ); - m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); - } - - - if (bResult) - return AddWeapon( ); - return FALSE; -} - -int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) -{ - BOOL bSend = FALSE; - int state = 0; - - // KGP: folded m_iEnabled into the state value and converted it to a proper bitfield. - if( pPlayer->m_pActiveItem == this ) - { state |= WEAPON_IS_CURRENT; } - if( pPlayer->m_fOnTarget ) - { state |= WEAPON_ON_TARGET; } - if( m_iEnabled ) - { state |= WEAPON_IS_ENABLED; } - - // Forcing send of all data! - if ( !pPlayer->m_fWeapon ) - { - bSend = TRUE; - } - - // This is the current or last weapon, so the state will need to be updated - if ( this == pPlayer->m_pActiveItem || - this == pPlayer->m_pClientActiveItem ) - { - if ( pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem ) - { - bSend = TRUE; - } - } - - // If the ammo, state, or fov has changed, update the weapon - if ( m_iClip != m_iClientClip || - state != m_iClientWeaponState || - pPlayer->m_iFOV != pPlayer->m_iClientFOV ) - { - bSend = TRUE; - } - - if (m_iId == 22 || m_iId == 11 || m_iId == 21) - gCanMove[pPlayer->entindex() - 1] = m_iEnabled; - - if ( bSend ) - { - NetMsg_CurWeapon( pPlayer->pev, state, m_iId, m_iClip ); - m_iClientClip = m_iClip; - m_iClientWeaponState = state; - pPlayer->m_fWeapon = TRUE; - } - - if ( m_pNext ) - m_pNext->UpdateClientData( pPlayer ); - - return 1; -} - -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) -{ - if(iAnim >= 0) - { - if ( UseDecrement() ) - skiplocal = 1; - else - skiplocal = 0; - - m_pPlayer->pev->weaponanim = iAnim; - - if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) - return; - - MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); - WRITE_BYTE( iAnim ); // sequence number - WRITE_BYTE( pev->body ); // weaponmodel bodygroup. - MESSAGE_END(); - } -} - -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) -{ - int iIdAmmo; - - if (iMaxClip < 1) - { - m_iClip = -1; - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - else if (m_iClip == 0) - { - int i; - i = min( m_iClip + iCount, iMaxClip ) - m_iClip; - m_iClip += i; - iIdAmmo = m_pPlayer->GiveAmmo( iCount - i, szName, iMaxCarry ); - } - else - { - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - - // m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing - - if (iIdAmmo > 0) - { - m_iPrimaryAmmoType = iIdAmmo; - if (m_pPlayer->HasPlayerItem( this ) ) - { - // play the "got ammo" sound only if we gave some ammo to a player that already had this gun. - // if the player is just getting this gun for the first time, DefaultTouch will play the "picked up gun" sound for us. - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - } - - return iIdAmmo > 0 ? TRUE : FALSE; -} - - -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) -{ - int iIdAmmo; - - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMax ); - - //m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = iMax; // hack for testing - - if (iIdAmmo > 0) - { - m_iSecondaryAmmoType = iIdAmmo; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return iIdAmmo > 0 ? TRUE : FALSE; -} - -//========================================================= -// IsUseable - this function determines whether or not a -// weapon is useable by the player in its current state. -// (does it have ammo loaded? do I have any ammo for the -// weapon?, etc) -//========================================================= -BOOL CBasePlayerWeapon :: IsUseable( void ) -{ - if ( m_iClip <= 0 ) - { - // This looks like a nasty bug Valve didn't notice - ASSERT(PrimaryAmmoIndex() >= 0); - - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 ) - { - // clip is empty (or nonexistant) and the player has no more ammo of this type. - return FALSE; - } - } - - return TRUE; -} - -BOOL CBasePlayerWeapon :: CanDeploy( void ) -{ - BOOL bHasAmmo = 0; - - // All weapons can always deploy. Once fire is hit, it checks if it's out of ammo. If so, the weapon switches. - // This is needed so ammo packs function correctly, and it also feels more responsive. - -// if ( !pszAmmo1() ) -// { -// // this weapon doesn't use ammo, can always deploy. -// return TRUE; -// } -// -// if ( pszAmmo1() ) -// { -// bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); -// } -// if ( pszAmmo2() ) -// { -// bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); -// } -// if (m_iClip > 0) -// { -// bHasAmmo |= 1; -// } -// if (!bHasAmmo) -// { -// return FALSE; -// } - - return TRUE; -} - -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body) -{ - if (!CanDeploy( )) - return FALSE; - - m_pPlayer->TabulateAmmo(); - m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); - m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); - strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); - SendWeaponAnim( iAnim, skiplocal, body ); - - // Set the player animation as well - //this->m_pPlayer->SetAnimation(PLAYER_ANIM(iAnim)); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + this->GetDeployTime(); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + this->GetDeployTime() + kDeployIdleInterval; - - return TRUE; -} - - -BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - return FALSE; - - int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - if (j == 0) - return FALSE; - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; - - //!!UNDONE -- reload sound goes here !!! - //SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); - - m_fInReload = TRUE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kDeployIdleInterval; - - return TRUE; -} - -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) -{ - if (m_iPlayEmptySound) - { -// EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - - int flags = FEV_NOTHOST; - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), gEmptySoundEventID, 0.0, (float *)&(m_pPlayer->pev->origin), (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - m_iPlayEmptySound = 0; - return 0; - } - return 0; -} - -void CBasePlayerWeapon :: ResetEmptySound( void ) -{ - m_iPlayEmptySound = 1; -} - -//========================================================= -//========================================================= -int CBasePlayerWeapon::PrimaryAmmoIndex( void ) -{ - return m_iPrimaryAmmoType; -} - -//========================================================= -//========================================================= -int CBasePlayerWeapon::SecondaryAmmoIndex( void ) -{ - return -1; -} - -void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE; // cancel any reload in progress. - m_pPlayer->pev->viewmodel = 0; - m_pPlayer->pev->weaponmodel = 0; -} - -void CBasePlayerAmmo::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch(&CBasePlayerAmmo::DefaultTouch ); -} - -CBaseEntity* CBasePlayerAmmo::Respawn( void ) -{ - pev->effects |= EF_NODRAW; - SetTouch( NULL ); - - UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. - - SetThink(&CBasePlayerAmmo::Materialize ); - pev->nextthink = g_pGameRules->FlAmmoRespawnTime( this ); - - return this; -} - -void CBasePlayerAmmo::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - SetTouch(&CBasePlayerAmmo::DefaultTouch ); -} - -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - { - return; - } - - if (AddAmmo( pOther )) - { - if ( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) - { - Respawn(); - } - else - { - SetTouch( NULL ); - SetThink(&CBasePlayerAmmo::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } - } - else if (gEvilImpulse101) - { - // evil impulse 101 hack, kill always - SetTouch( NULL ); - SetThink(&CBasePlayerAmmo::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } -} - -//========================================================= -// called by the new item with the existing item as parameter -// -// if we call ExtractAmmo(), it's because the player is picking up this type of weapon for -// the first time. If it is spawned by the world, m_iDefaultAmmo will have a default ammo amount in it. -// if this is a weapon dropped by a dying player, has 0 m_iDefaultAmmo, which means only the ammo in -// the weapon clip comes along. -//========================================================= -int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iReturn; - - if ( pszAmmo1() != NULL ) - { - // blindly call with m_iDefaultAmmo. It's either going to be a value or zero. If it is zero, - // we only get the ammo in the weapon's clip, which is what we want. - iReturn = pWeapon->AddPrimaryAmmo( m_iDefaultAmmo, (char *)pszAmmo1(), iMaxClip(), iMaxAmmo1() ); - m_iDefaultAmmo = 0; - } - - if ( pszAmmo2() != NULL ) - { - iReturn = pWeapon->AddSecondaryAmmo( 0, (char *)pszAmmo2(), iMaxAmmo2() ); - } - - return iReturn; -} - -//========================================================= -// called by the new item's class with the existing item as parameter -//========================================================= -int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iAmmo; - - if ( m_iClip == WEAPON_NOCLIP ) - { - iAmmo = 0;// guns with no clips always come empty if they are second-hand - } - else - { - iAmmo = m_iClip; - } - - return pWeapon->m_pPlayer->GiveAmmo( iAmmo, (char *)pszAmmo1(), iMaxAmmo1() ); // , &m_iPrimaryAmmoType -} - -//========================================================= -// RetireWeapon - no more ammo for this gun, put it away. -//========================================================= -void CBasePlayerWeapon::RetireWeapon( void ) -{ - // first, no viewmodel at all. - m_pPlayer->pev->viewmodel = iStringNull; - m_pPlayer->pev->weaponmodel = iStringNull; - //m_pPlayer->pev->viewmodelindex = NULL; - - g_pGameRules->GetNextBestWeapon( m_pPlayer, this ); -} - -//********************************************************* -// weaponbox code: -//********************************************************* - -LINK_ENTITY_TO_CLASS( weaponbox, CWeaponBox ); - -TYPEDESCRIPTION CWeaponBox::m_SaveData[] = -{ - DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ); - -//========================================================= -// -//========================================================= -void CWeaponBox::Precache( void ) -{ - PRECACHE_UNMODIFIED_MODEL("models/w_weaponbox.mdl"); -} - -//========================================================= -//========================================================= -void CWeaponBox :: KeyValue( KeyValueData *pkvd ) -{ - if ( m_cAmmoTypes < MAX_AMMO_SLOTS ) - { - PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) ); - m_cAmmoTypes++;// count this new ammo type. - - pkvd->fHandled = TRUE; - } - else - { - ALERT ( at_console, "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS ); - } -} - -//========================================================= -// CWeaponBox - Spawn -//========================================================= -void CWeaponBox::Spawn( void ) -{ - Precache( ); - - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - - SET_MODEL( ENT(pev), "models/w_weaponbox.mdl"); -} - -//========================================================= -// CWeaponBox - Kill - the think function that removes the -// box from the world. -//========================================================= -void CWeaponBox::Kill( void ) -{ - CBasePlayerItem *pWeapon; - int i; - - // destroy the weapons - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - pWeapon->SetThink(&CWeaponBox::SUB_Remove); - pWeapon->pev->nextthink = gpGlobals->time + 0.1; - pWeapon = pWeapon->m_pNext; - } - } - - // remove the box - UTIL_Remove( this ); -} - -//========================================================= -// CWeaponBox - Touch: try to add my contents to the toucher -// if the toucher is a player. -//========================================================= -void CWeaponBox::Touch( CBaseEntity *pOther ) -{ - if ( !(pev->flags & FL_ONGROUND ) ) - { - return; - } - - if ( !pOther->IsPlayer() ) - { - // only players may touch a weaponbox. - return; - } - - if ( !pOther->IsAlive() ) - { - // no dead guys. - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - int i; - -// dole out ammo - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // there's some ammo of this type. - pPlayer->GiveAmmo( m_rgAmmo[ i ], (char *)STRING( m_rgiszAmmo[ i ] ), MaxAmmoCarry( m_rgiszAmmo[ i ] ) ); - - //ALERT ( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING(m_rgiszAmmo[i]) ); - - // now empty the ammo from the weaponbox since we just gave it to the player - m_rgiszAmmo[ i ] = iStringNull; - m_rgAmmo[ i ] = 0; - } - } - -// go through my weapons and try to give the usable ones to the player. -// it's important the the player be given ammo first, so the weapons code doesn't refuse -// to deploy a better weapon that the player may pick up because he has no ammo for it. - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerItem *pItem; - - // have at least one weapon in this slot - while ( m_rgpPlayerItems[ i ] ) - { - //ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) ); - - pItem = m_rgpPlayerItems[ i ]; - m_rgpPlayerItems[ i ] = m_rgpPlayerItems[ i ]->m_pNext;// unlink this weapon from the box - - if ( pPlayer->AddPlayerItem( pItem ) ) - { - pItem->AttachToPlayer( pPlayer ); - } - } - } - } - - EMIT_SOUND( pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - SetTouch(NULL); - UTIL_Remove(this); -} - -//========================================================= -// CWeaponBox - PackWeapon: Add this weapon to the box -//========================================================= -BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) -{ - // is one of these weapons already packed in this box? - if ( HasWeapon( pWeapon ) ) - { - return FALSE;// box can only hold one of each weapon type - } - - if ( pWeapon->m_pPlayer ) - { - if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) - { - // failed to unhook the weapon from the player! - return FALSE; - } - } - - int iWeaponSlot = pWeapon->iItemSlot(); - - if ( m_rgpPlayerItems[ iWeaponSlot ] ) - { - // there's already one weapon in this slot, so link this into the slot's column - pWeapon->m_pNext = m_rgpPlayerItems[ iWeaponSlot ]; - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - } - else - { - // first weapon we have for this slot - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - pWeapon->m_pNext = NULL; - } - - pWeapon->pev->spawnflags |= SF_NORESPAWN;// never respawn - pWeapon->pev->movetype = MOVETYPE_NONE; - pWeapon->pev->solid = SOLID_NOT; - pWeapon->pev->effects = EF_NODRAW; - pWeapon->pev->modelindex = 0; - pWeapon->pev->model = iStringNull; - pWeapon->pev->owner = edict(); - pWeapon->SetThink( NULL );// crowbar may be trying to swing again, etc. - pWeapon->SetTouch( NULL ); - pWeapon->m_pPlayer = NULL; - - //ALERT ( at_console, "packed %s\n", STRING(pWeapon->pev->classname) ); - - return TRUE; -} - -//========================================================= -// CWeaponBox - PackAmmo -//========================================================= -BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) -{ - int iMaxCarry; - - if ( FStringNull( iszName ) ) - { - // error here - ALERT ( at_console, "NULL String in PackAmmo!\n" ); - return FALSE; - } - - iMaxCarry = MaxAmmoCarry( iszName ); - - if ( iMaxCarry != -1 && iCount > 0 ) - { - //ALERT ( at_console, "Packed %d rounds of %s\n", iCount, STRING(iszName) ); - GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CWeaponBox - GiveAmmo -//========================================================= -int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NULL*/ ) -{ - int i; - - for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++) - { - if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0) - { - if (pIndex) - *pIndex = i; - - int iAdd = min( iCount, iMax - m_rgAmmo[i]); - if (iCount == 0 || iAdd > 0) - { - m_rgAmmo[i] += iAdd; - - return i; - } - return -1; - } - } - if (i < MAX_AMMO_SLOTS) - { - if (pIndex) - *pIndex = i; - - m_rgiszAmmo[i] = MAKE_STRING( szName ); - m_rgAmmo[i] = iCount; - - return i; - } - ALERT( at_console, "out of named ammo slots\n"); - return i; -} - -//========================================================= -// CWeaponBox::HasWeapon - is a weapon of this type already -// packed in this box? -//========================================================= -BOOL CWeaponBox::HasWeapon( CBasePlayerItem *pCheckItem ) -{ - CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// CWeaponBox::IsEmpty - is there anything in this box? -//========================================================= -BOOL CWeaponBox::IsEmpty( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return FALSE; - } - } - - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // still have a bit of this type of ammo - return FALSE; - } - } - - return TRUE; -} - -//========================================================= -//========================================================= -void CWeaponBox::SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-16, -16, 0); - pev->absmax = pev->origin + Vector(16, 16, 16); -} - - -void CBasePlayerWeapon::PrintState( void ) -{ - ALERT( at_console, "primary: %f\n", m_flNextPrimaryAttack ); - ALERT( at_console, "idle : %f\n", m_flTimeWeaponIdle ); - -// ALERT( at_console, "nextrl : %f\n", m_flNextReload ); -// ALERT( at_console, "nextpum: %f\n", m_flPumpTime ); - -// ALERT( at_console, "m_frt : %f\n", m_fReloadTime ); - ALERT( at_console, "m_finre: %i\n", m_fInReload ); -// ALERT( at_console, "m_finsr: %i\n", m_fInSpecialReload ); - - ALERT( at_console, "m_iclip: %i\n", m_iClip ); -} - - -TYPEDESCRIPTION CRpg::m_SaveData[] = -{ - DEFINE_FIELD( CRpg, m_fSpotActive, FIELD_INTEGER ), - DEFINE_FIELD( CRpg, m_cActiveRockets, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon ); - -TYPEDESCRIPTION CRpgRocket::m_SaveData[] = -{ - DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), - DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ); - -TYPEDESCRIPTION CShotgun::m_SaveData[] = -{ - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - DEFINE_FIELD( CShotgun, m_fInSpecialReload, FIELD_INTEGER ), - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - // DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ), - DEFINE_FIELD( CShotgun, m_flPumpTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CShotgun, CBasePlayerWeapon ); - -TYPEDESCRIPTION CGauss::m_SaveData[] = -{ - DEFINE_FIELD( CGauss, m_fInAttack, FIELD_INTEGER ), -// DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ), -// DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ), -// DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ), - DEFINE_FIELD( CGauss, m_fPrimaryFire, FIELD_BOOLEAN ), -}; -IMPLEMENT_SAVERESTORE( CGauss, CBasePlayerWeapon ); - -TYPEDESCRIPTION CEgon::m_SaveData[] = -{ -// DEFINE_FIELD( CEgon, m_pBeam, FIELD_CLASSPTR ), -// DEFINE_FIELD( CEgon, m_pNoise, FIELD_CLASSPTR ), -// DEFINE_FIELD( CEgon, m_pSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CEgon, m_shootTime, FIELD_TIME ), - DEFINE_FIELD( CEgon, m_fireState, FIELD_INTEGER ), - DEFINE_FIELD( CEgon, m_fireMode, FIELD_INTEGER ), - DEFINE_FIELD( CEgon, m_shakeTime, FIELD_TIME ), - DEFINE_FIELD( CEgon, m_flAmmoUseTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ); - -TYPEDESCRIPTION CSatchel::m_SaveData[] = -{ - DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ); - +// +// Copyright (c) 1999, Valve LLC. All rights reserved. +// +// This product contains software technology licensed from Id +// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +// All Rights Reserved. +// +// Use, distribution, and modification of this source code and/or resulting +// object code is restricted to non-commercial enhancements to products from +// Valve LLC. All other use, distribution, or modification is prohibited +// without written permission from Valve LLC. +// +// ===== weapons.cpp ======================================================== +// +// functions governing the selection/use of weapons for players +// +// $Workfile: weapons.cpp $ +// $Date: 2002/11/22 21:13:52 $ +// +//------------------------------------------------------------------------------- +// $Log: weapons.cpp,v $ +// Revision 1.49 2002/11/22 21:13:52 Flayra +// - mp_consistency changes +// +// Revision 1.48 2002/11/12 02:19:43 Flayra +// - Fixed problem where friendly bulletfire was doing damage +// +// Revision 1.47 2002/10/24 21:19:11 Flayra +// - Reworked jetpack effects +// - Added a few extra sounds +// +// Revision 1.46 2002/10/16 00:41:15 Flayra +// - Removed unneeds sounds and events +// - Added distress beacon event +// - Added general purpose particle event +// +// Revision 1.45 2002/09/25 20:40:09 Flayra +// - Play different sound for aliens when they get weapons +// +// Revision 1.44 2002/09/23 22:04:00 Flayra +// - Regular update +// +// Revision 1.43 2002/08/31 18:01:18 Flayra +// - Work at VALVe +// +// Revision 1.42 2002/07/26 23:01:05 Flayra +// - Precache numerical feedback event +// +// Revision 1.41 2002/07/23 16:48:37 Flayra +// - Added distress beacon +// +// Revision 1.40 2002/07/08 16:35:17 Flayra +// - Added document header, updates for cheat protection, added constants +// +//=============================================================================== +#include "../util/nowarnings.h" +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "decals.h" +#include "gamerules.h" +#include "../mod/AvHConstants.h" +#include "../mod/AvHMarineEquipmentConstants.h" +#include "../mod/AvHAlienWeaponConstants.h" +#include "../mod/AvHAlienEquipmentConstants.h" +#include "../mod/AvHPlayer.h" +#include "../mod/AvHGamerules.h" +#include "../mod/AvHNetworkMessages.h" + +extern CGraph WorldGraph; +extern int gEvilImpulse101; + +int gJetpackEventID; +int gStartOverwatchEventID; +int gEndOverwatchEventID; +int gTeleportEventID; +int gBlinkEffectSuccessEventID; +int gPhaseInEventID; +int gSiegeHitEventID; +int gSiegeViewHitEventID; +int gCommanderPointsAwardedEventID; +int gAlienSightOnEventID; +int gAlienSightOffEventID; +//int gParalysisStartEventID; +int gRegenerationEventID; +int gStartCloakEventID; +int gEndCloakEventID; +int gSporeCloudEventID; +int gUmbraCloudEventID; +int gStopScreamEventID; + +int gWelderEventID; +int gWelderConstEventID; +//int gWallJumpEventID; +//int gFlightEventID; +int gEmptySoundEventID; +int gNumericalInfoEventID; +int gInvalidActionEventID; +int gParticleEventID; +int gDistressBeaconEventID; +int gWeaponAnimationEventID; +int gLevelUpEventID; +int gMetabolizeSuccessEventID; + +#define NOT_USED 255 + +DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam +DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr"; +DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot +DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball +DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud +DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion +DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model +DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood +DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood + +ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; +AmmoInfo CBasePlayerItem::AmmoInfoArray[MAX_AMMO_SLOTS]; + +MULTIDAMAGE gMultiDamage; + +#define TRACER_FREQ 4 // Tracers fire every fourth bullet + +extern bool gCanMove[]; + +//========================================================= +// MaxAmmoCarry - pass in a name and this function will tell +// you the maximum amount of that type of ammunition that a +// player can carry. +//========================================================= +int MaxAmmoCarry( int iszName ) +{ + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo1 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo1 ) ) + return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo1; + if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo2 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo2 ) ) + return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo2; + } + + ALERT( at_console, "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName ) ); + return -1; +} + + +/* +============================================================================== + +MULTI-DAMAGE + +Collects multiple small damages into a single damage + +============================================================================== +*/ + +// +// ClearMultiDamage - resets the global multi damage accumulator +// +void ClearMultiDamage(void) +{ + gMultiDamage.pEntity = NULL; + gMultiDamage.amount = 0; + gMultiDamage.type = 0; +} + +// +// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity +// +// GLOBALS USED: +// gMultiDamage + +void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) +{ + Vector vecSpot1;//where blood comes from + Vector vecDir;//direction blood should go + TraceResult tr; + + if ( !gMultiDamage.pEntity ) + return; + + float theDamage = gMultiDamage.amount; + gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, theDamage, gMultiDamage.type ); +} + + +// GLOBALS USED: +// gMultiDamage + +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) +{ + if ( !pEntity ) + return; + + gMultiDamage.type |= bitsDamageType; + + if ( pEntity != gMultiDamage.pEntity ) + { + ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker! + gMultiDamage.pEntity = pEntity; + gMultiDamage.amount = 0; + } + + gMultiDamage.amount += flDamage; +} + +/* +================ +SpawnBlood +================ +*/ +void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) +{ + if(flDamage >= 0.0f) + { + if(bloodColor == DONT_BLEED) + { + UTIL_Sparks(vecSpot); + } + else + { + UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); + } + } +} + + +int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) +{ + if ( !pEntity ) + return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); + + return pEntity->DamageDecal( bitsDamageType ); +} + +void DecalGunshot( TraceResult *pTrace, int iBulletType ) +{ + // Is the entity valid + if ( !UTIL_IsValidEntity( pTrace->pHit ) ) + return; + + if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP ) + { + CBaseEntity *pEntity = NULL; + // Decal the wall with a gunshot + if ( !FNullEnt(pTrace->pHit) ) + pEntity = CBaseEntity::Instance(pTrace->pHit); + +// switch( iBulletType ) +// { +// case BULLET_PLAYER_9MM: +// case BULLET_MONSTER_9MM: +// case BULLET_PLAYER_MP5: +// case BULLET_MONSTER_MP5: +// case BULLET_PLAYER_BUCKSHOT: +// case BULLET_PLAYER_357: +// default: + // smoke and decal + UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); +// break; +// case BULLET_MONSTER_12MM: +// // smoke and decal +// UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); +// break; +// case BULLET_PLAYER_CROWBAR: +// // wall decal +// UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); +// break; +// } + } +} + + + +// +// EjectBrass - tosses a brass shell from passed origin at passed velocity +// +void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) +{ + // FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see. + + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); + WRITE_BYTE( TE_MODEL); + WRITE_COORD( vecOrigin.x); + WRITE_COORD( vecOrigin.y); + WRITE_COORD( vecOrigin.z); + WRITE_COORD( vecVelocity.x); + WRITE_COORD( vecVelocity.y); + WRITE_COORD( vecVelocity.z); + WRITE_ANGLE( rotation ); + WRITE_SHORT( model ); + WRITE_BYTE ( soundtype); + WRITE_BYTE ( 25 );// 2.5 seconds + MESSAGE_END(); +} + + +#if 0 +// UNDONE: This is no longer used? +void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) +{ + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); + WRITE_BYTE ( TE_EXPLODEMODEL ); + WRITE_COORD( vecOrigin.x ); + WRITE_COORD( vecOrigin.y ); + WRITE_COORD( vecOrigin.z ); + WRITE_COORD( speed ); + WRITE_SHORT( model ); + WRITE_SHORT( count ); + WRITE_BYTE ( 15 );// 1.5 seconds + MESSAGE_END(); +} +#endif + + +int giAmmoIndex = 0; + +// Precaches the ammo and queues the ammo info for sending to clients +void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) +{ + // make sure it's not already in the registry + for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) + { + if ( !CBasePlayerItem::AmmoInfoArray[i].pszName) + continue; + + if ( stricmp( CBasePlayerItem::AmmoInfoArray[i].pszName, szAmmoname ) == 0 ) + return; // ammo already in registry, just quite + } + + + giAmmoIndex++; + ASSERT( giAmmoIndex < MAX_AMMO_SLOTS ); + if ( giAmmoIndex >= MAX_AMMO_SLOTS ) + giAmmoIndex = 0; + + CBasePlayerItem::AmmoInfoArray[giAmmoIndex].pszName = szAmmoname; + CBasePlayerItem::AmmoInfoArray[giAmmoIndex].iId = giAmmoIndex; // yes, this info is redundant +} + + +// Precaches the weapon and queues the weapon info for sending to clients +void UTIL_PrecacheOtherWeapon( const char *szClassname ) +{ + edict_t *pent; + + pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); + if ( FNullEnt( pent ) ) + { + ALERT ( at_console, "NULL Ent in UTIL_PrecacheOtherWeapon\n" ); + return; + } + + CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); + + if (pEntity) + { + ItemInfo II; + pEntity->Precache( ); + memset( &II, 0, sizeof II ); + if ( ((CBasePlayerItem*)pEntity)->GetItemInfo( &II ) ) + { + CBasePlayerItem::ItemInfoArray[II.iId] = II; + + if ( II.pszAmmo1 && *II.pszAmmo1 ) + { + AddAmmoNameToAmmoRegistry( II.pszAmmo1 ); + } + + if ( II.pszAmmo2 && *II.pszAmmo2 ) + { + AddAmmoNameToAmmoRegistry( II.pszAmmo2 ); + } + + memset( &II, 0, sizeof II ); + } + } + + REMOVE_ENTITY(pent); +} + +// called by worldspawn +void W_Precache(void) +{ + memset( CBasePlayerItem::ItemInfoArray, 0, sizeof(CBasePlayerItem::ItemInfoArray) ); + memset( CBasePlayerItem::AmmoInfoArray, 0, sizeof(CBasePlayerItem::AmmoInfoArray) ); + giAmmoIndex = 0; + + // Marine weapons + //UTIL_PrecacheOtherWeapon("weapon_9mmhandgun"); + //UTIL_PrecacheOtherWeapon("weapon_glock"); + //UTIL_PrecacheOther("ammo_9mmclip"); + + // Player assets + PRECACHE_UNMODIFIED_MODEL(kReadyRoomModel); + PRECACHE_UNMODIFIED_MODEL(kMarineSoldierModel); + PRECACHE_UNMODIFIED_MODEL(kHeavySoldierModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelOneModel); + PRECACHE_UNMODIFIED_SOUND(kDistressBeaconSound); + PRECACHE_UNMODIFIED_SOUND(kLevelUpMarineSound); + PRECACHE_UNMODIFIED_SOUND(kLevelUpAlienSound); + PRECACHE_UNMODIFIED_SOUND(kAlienBuildingSound1); + PRECACHE_UNMODIFIED_SOUND(kAlienBuildingSound2); + PRECACHE_SOUND(kMyHiveEasterEgg); + + //PRECACHE_UNMODIFIED_SOUND(kAlienAbilitiesGrantedSound); + //PRECACHE_UNMODIFIED_SOUND(kAlienAbilitiesLostSound); + + PRECACHE_UNMODIFIED_MODEL(kAlienLevelTwoModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelThreeModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelFourModel); + PRECACHE_UNMODIFIED_MODEL(kAlienLevelFiveModel); + + PRECACHE_UNMODIFIED_MODEL(kMarineCommanderModel); + PRECACHE_UNMODIFIED_MODEL(kAlienGestateModel); + // : 1072 + // Added some client side consistency checks. + PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash1.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash2.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash3.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/digesting.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/membrane.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/hera_fog.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/spore.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/spore2.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/umbra.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/umbra2.spr"); + PRECACHE_UNMODIFIED_MODEL("sprites/webstrand.spr"); + + UTIL_PrecacheOtherWeapon(kwsMine); + UTIL_PrecacheOtherWeapon(kwsKnife); + UTIL_PrecacheOtherWeapon(kwsMachineGun); + UTIL_PrecacheOtherWeapon(kwsPistol); + UTIL_PrecacheOtherWeapon(kwsShotGun); + UTIL_PrecacheOtherWeapon(kwsHeavyMachineGun); + UTIL_PrecacheOtherWeapon(kwsGrenadeGun); + UTIL_PrecacheOtherWeapon(kwsGrenade); + + // Alien weapons + UTIL_PrecacheOtherWeapon(kwsSpitGun); + UTIL_PrecacheOther(kwsSpitProjectile); + UTIL_PrecacheOther(kwsWebProjectile); + UTIL_PrecacheOtherWeapon(kwsClaws); + UTIL_PrecacheOtherWeapon(kwsSwipe); + UTIL_PrecacheOtherWeapon(kwsSporeGun); + UTIL_PrecacheOther(kwsSporeProjectile); +// UTIL_PrecacheOtherWeapon(kwsParalysisGun); + UTIL_PrecacheOtherWeapon(kwsSpikeGun); + UTIL_PrecacheOtherWeapon(kwsBiteGun); + UTIL_PrecacheOtherWeapon(kwsBite2Gun); + UTIL_PrecacheOtherWeapon(kwsHealingSpray); + UTIL_PrecacheOtherWeapon(kwsWebSpinner); +// UTIL_PrecacheOtherWeapon(kwsBabblerGun); + UTIL_PrecacheOtherWeapon(kwsPrimalScream); + UTIL_PrecacheOtherWeapon(kwsParasiteGun); + UTIL_PrecacheOtherWeapon(kwsMetabolize); + UTIL_PrecacheOtherWeapon(kwsUmbraGun); + UTIL_PrecacheOtherWeapon(kwsBlinkGun); + UTIL_PrecacheOtherWeapon(kwsDivineWind); + UTIL_PrecacheOtherWeapon(kwsBileBombGun); + UTIL_PrecacheOtherWeapon(kwsAcidRocketGun); + UTIL_PrecacheOtherWeapon(kwsStomp); + UTIL_PrecacheOtherWeapon(kwsDevour); +// UTIL_PrecacheOtherWeapon(kwsAmplify); + UTIL_PrecacheOther(kwsBileBomb); + + // Alien abilities + UTIL_PrecacheOtherWeapon(kwsLeap); + UTIL_PrecacheOtherWeapon(kwsCharge); + + // Alien buildings + UTIL_PrecacheOther(kwsAlienResourceTower); + UTIL_PrecacheOther(kwsOffenseChamber); + UTIL_PrecacheOther(kwsDefenseChamber); + UTIL_PrecacheOther(kwsSensoryChamber); + UTIL_PrecacheOther(kwsMovementChamber); + UTIL_PrecacheOther(kesTeamWebStrand); + + // Equipment + //UTIL_PrecacheOtherWeapon("weapon_tripmine"); + UTIL_PrecacheOther(kwsScan); + UTIL_PrecacheOther(kwsPhaseGate); + //UTIL_PrecacheOther(kwsNuke); + + // Marine buildings + UTIL_PrecacheOther(kwsTeamCommand); + UTIL_PrecacheOther(kwsResourceTower); + UTIL_PrecacheOther(kwsInfantryPortal); + UTIL_PrecacheOther(kwsTurretFactory); + UTIL_PrecacheOther(kwsArmory); + UTIL_PrecacheOther(kwsAdvancedArmory); + UTIL_PrecacheOther(kwsArmsLab); + UTIL_PrecacheOther(kwsPrototypeLab); + UTIL_PrecacheOther(kwsObservatory); + //UTIL_PrecacheOther(kwsChemlab); + //UTIL_PrecacheOther(kwsMedlab); + //UTIL_PrecacheOther(kwsNukePlant); + UTIL_PrecacheOther(kwsDeployedTurret); + UTIL_PrecacheOther(kwsSiegeTurret); + + // container for dropped deathmatch weapons + UTIL_PrecacheOther("weaponbox"); + + UTIL_PrecacheOtherWeapon(kwsWelder); + UTIL_PrecacheOther(kwsDeployedMine); + UTIL_PrecacheOther(kwsHealth); + UTIL_PrecacheOther(kwsCatalyst); + UTIL_PrecacheOther(kwsGenericAmmo); + UTIL_PrecacheOther(kwsHeavyArmor); + UTIL_PrecacheOther(kwsJetpack); + UTIL_PrecacheOther(kwsAmmoPack); + + UTIL_PrecacheOther(kwsDebugEntity); + + // Precache other events + gJetpackEventID = PRECACHE_EVENT(1, kJetpackEvent); + //gStartOverwatchEventID = PRECACHE_EVENT(1, kStartOverwatchEvent); + //gEndOverwatchEventID = PRECACHE_EVENT(1, kEndOverwatchEvent); + + // Alien upgrade events + gRegenerationEventID = PRECACHE_EVENT(1, kRegenerationEvent); + gStartCloakEventID = PRECACHE_EVENT(1, kStartCloakEvent); + gEndCloakEventID = PRECACHE_EVENT(1, kEndCloakEvent); + + // Extra alien weapon events + //gEnsnareHitEventID = PRECACHE_EVENT(1, kEnsnareHitEventName); + gSporeCloudEventID = PRECACHE_EVENT(1, kSporeCloudEventName); + gUmbraCloudEventID = PRECACHE_EVENT(1, kUmbraCloudEventName); + gStopScreamEventID = PRECACHE_EVENT(1, kStopPrimalScreamSoundEvent); + + // Extra marine events + gTeleportEventID = PRECACHE_EVENT(1, kTeleportEvent); + gBlinkEffectSuccessEventID = PRECACHE_EVENT(1, kBlinkEffectSuccessEventName); + gPhaseInEventID = PRECACHE_EVENT(1, kPhaseInEvent); + gSiegeHitEventID = PRECACHE_EVENT(1, kSiegeHitEvent); + gSiegeViewHitEventID = PRECACHE_EVENT(1, kSiegeViewHitEvent); + gCommanderPointsAwardedEventID = PRECACHE_EVENT(1, kCommanderPointsAwardedEvent); + gAlienSightOnEventID = PRECACHE_EVENT(1, kAlienSightOnEvent); + gAlienSightOffEventID = PRECACHE_EVENT(1, kAlienSightOffEvent); +// gParalysisStartEventID = PRECACHE_EVENT(1, kParalysisStartEventName); + + //gWallJumpEventID = PRECACHE_EVENT(1, kWallJumpEvent); + //gFlightEventID = PRECACHE_EVENT(1, kFlightEvent); + PRECACHE_UNMODIFIED_SOUND(kConnectSound); + //PRECACHE_UNMODIFIED_SOUND(kDisconnectSound); + PRECACHE_UNMODIFIED_MODEL(kNullModel); + + UTIL_PrecacheOther("monster_sentry"); + + // Allow welder events in mapper build + gWelderEventID = PRECACHE_EVENT(1, kWelderEventName); + gWelderConstEventID = PRECACHE_EVENT(1, kWelderConstEventName); + PRECACHE_EVENT(1, kWelderStartEventName); + PRECACHE_EVENT(1, kWelderEndEventName); + + gEmptySoundEventID = PRECACHE_EVENT(1, kEmptySoundEvent); + gNumericalInfoEventID = PRECACHE_EVENT(1, kNumericalInfoEvent); + gInvalidActionEventID = PRECACHE_EVENT(1, kInvalidActionEvent); + gParticleEventID = PRECACHE_EVENT(1, kParticleEvent); + gDistressBeaconEventID = PRECACHE_EVENT(1, kDistressBeaconEvent); + gWeaponAnimationEventID= PRECACHE_EVENT(1, kWeaponAnimationEvent); + gLevelUpEventID = PRECACHE_EVENT(1, kLevelUpEvent); + gMetabolizeSuccessEventID = PRECACHE_EVENT(1, kMetabolizeSuccessEventName); + + PRECACHE_UNMODIFIED_SOUND(kPhaseInSound); + + // Precache reload sound that is hardcoded deep in HL + PRECACHE_UNMODIFIED_SOUND(kEmptySound); + PRECACHE_UNMODIFIED_SOUND(kInvalidSound); + + // Not sure who's using these, but I keep getting errors that they're not precached. Buttons? + PRECACHE_UNMODIFIED_SOUND("buttons/spark1.wav"); + PRECACHE_UNMODIFIED_SOUND("buttons/spark2.wav"); + PRECACHE_UNMODIFIED_SOUND("buttons/spark3.wav"); + PRECACHE_UNMODIFIED_SOUND("buttons/spark4.wav"); + PRECACHE_UNMODIFIED_SOUND("buttons/spark5.wav"); + PRECACHE_UNMODIFIED_SOUND("buttons/spark6.wav"); + + // For grunts. Careful, this uses the same weapon id that the grenade gun uses + //UTIL_PrecacheOtherWeapon("weapon_9mmAR"); + + // common world objects +// UTIL_PrecacheOther( "item_suit" ); +// UTIL_PrecacheOther( "item_battery" ); +// UTIL_PrecacheOther( "item_antidote" ); +// UTIL_PrecacheOther( "item_security" ); +// UTIL_PrecacheOther( "item_longjump" ); + + // shotgun +// UTIL_PrecacheOtherWeapon( "weapon_shotgun" ); +// UTIL_PrecacheOther( "ammo_buckshot" ); +// +// // crowbar +// UTIL_PrecacheOtherWeapon( "weapon_rowbar" ); +// +// // glock +// UTIL_PrecacheOtherWeapon( "weapon_9mmhandgun" ); +// UTIL_PrecacheOther( "ammo_9mmclip" ); +// +// // mp5 +// UTIL_PrecacheOtherWeapon( "weapon_9mmAR" ); +// UTIL_PrecacheOther( "ammo_9mmAR" ); +// UTIL_PrecacheOther( "ammo_ARgrenades" ); + +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // python +// UTIL_PrecacheOtherWeapon( "weapon_357" ); +// UTIL_PrecacheOther( "ammo_357" ); +//#endif +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // gauss +// UTIL_PrecacheOtherWeapon( "weapon_gauss" ); +// UTIL_PrecacheOther( "ammo_gaussclip" ); +//#endif +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // rpg +// UTIL_PrecacheOtherWeapon( "weapon_rpg" ); +// UTIL_PrecacheOther( "ammo_rpgclip" ); +//#endif +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // crossbow +// UTIL_PrecacheOtherWeapon( "weapon_crossbow" ); +// UTIL_PrecacheOther( "ammo_crossbow" ); +// UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons +//#endif +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // egon +// UTIL_PrecacheOtherWeapon( "weapon_egon" ); +//#endif +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // satchel charge +// UTIL_PrecacheOtherWeapon( "weapon_satchel" ); +//#endif +// +// // hand grenade +// UTIL_PrecacheOtherWeapon("weapon_handgrenade"); +// +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // squeak grenade +// UTIL_PrecacheOtherWeapon( "weapon_snark" ); +//#endif +// +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// // hornetgun +// UTIL_PrecacheOtherWeapon( "weapon_hornetgun" ); +//#endif + + +//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) +// if ( g_pGameRules->IsDeathmatch() ) +// { +// UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons +// } +//#endif + + g_sModelIndexFireball = PRECACHE_UNMODIFIED_MODEL ("sprites/zerogxplode.spr");// fireball + g_sModelIndexWExplosion = PRECACHE_UNMODIFIED_MODEL ("sprites/WXplo1.spr");// underwater fireball + g_sModelIndexSmoke = PRECACHE_UNMODIFIED_MODEL ("sprites/steam1.spr");// smoke + g_sModelIndexBubbles = PRECACHE_UNMODIFIED_MODEL ("sprites/bubble2.spr");//bubbles + g_sModelIndexBloodSpray = PRECACHE_UNMODIFIED_MODEL ("sprites/bloodspray.spr"); // initial blood + g_sModelIndexBloodDrop = PRECACHE_UNMODIFIED_MODEL ("sprites/blood.spr"); // splattered blood + + g_sModelIndexLaser = PRECACHE_UNMODIFIED_MODEL( (char *)g_pModelNameLaser ); + g_sModelIndexLaserDot = PRECACHE_UNMODIFIED_MODEL("sprites/laserdot.spr"); + + + // used by explosions + PRECACHE_UNMODIFIED_MODEL ("models/grenade.mdl"); + PRECACHE_UNMODIFIED_MODEL ("sprites/explode1.spr"); + + PRECACHE_SOUND ("weapons/debris1.wav");// explosion aftermaths + PRECACHE_SOUND ("weapons/debris2.wav");// explosion aftermaths + PRECACHE_SOUND ("weapons/debris3.wav");// explosion aftermaths + + PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound1); + PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound2); + PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound3); + PRECACHE_UNMODIFIED_SOUND (kGRHitSound); + + PRECACHE_UNMODIFIED_SOUND ("weapons/bullet_hit1.wav"); // hit by bullet + PRECACHE_UNMODIFIED_SOUND ("weapons/bullet_hit2.wav"); // hit by bullet + + PRECACHE_UNMODIFIED_SOUND ("items/weapondrop1.wav");// weapon falls to the ground + +} + + + + +TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = +{ + DEFINE_FIELD( CBasePlayerItem, m_pPlayer, FIELD_CLASSPTR ), + DEFINE_FIELD( CBasePlayerItem, m_pNext, FIELD_CLASSPTR ), + DEFINE_FIELD( CBasePlayerItem, m_iId, FIELD_INTEGER ), +}; +IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ); + + +TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = +{ + DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_TIME ), + DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_TIME ), + DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_TIME ), + DEFINE_FIELD( CBasePlayerWeapon, m_iPrimaryAmmoType, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayerWeapon, m_iSecondaryAmmoType, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayerWeapon, m_iClip, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ); + + +void CBasePlayerItem :: SetObjectCollisionBox( void ) +{ + pev->absmin = pev->origin + Vector(-24, -24, 0); + pev->absmax = pev->origin + Vector(24, 24, 16); +} + +BOOL +CBasePlayerItem::CanDeploy( void ) +{ + return TRUE; +} + +// can this weapon be put away right now? +BOOL CBasePlayerItem::CanHolster( void ) +{ + return TRUE; +}; + +// returns is deploy was successful +BOOL CBasePlayerItem::Deploy( ) +{ + return TRUE; +} + +BOOL +CBasePlayerItem::IsUseable( void ) +{ + return TRUE; +} + + +//========================================================= +// Sets up movetype, size, solidtype for a new weapon. +//========================================================= +void CBasePlayerItem :: FallInit( void ) +{ + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_BBOX; + + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) );//pointsize until it lands on the ground. + + SetTouch(&CBasePlayerItem::DefaultTouch ); + SetThink(&CBasePlayerItem::FallThink ); + + pev->nextthink = gpGlobals->time + 0.1; +} + +//========================================================= +// FallThink - Items that have just spawned run this think +// to catch them when they hit the ground. Once we're sure +// that the object is grounded, we change its solid type +// to trigger and set it in a large box that helps the +// player get it. +//========================================================= +void CBasePlayerItem::FallThink ( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if ( pev->flags & FL_ONGROUND ) + { + // clatter if we have an owner (i.e., dropped by someone) + // don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!) + if ( !FNullEnt( pev->owner ) ) + { + int pitch = 95 + RANDOM_LONG(0,29); + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "items/weapondrop1.wav", 1, ATTN_NORM, 0, pitch); + } + + // lie flat + pev->angles.x = 0; + pev->angles.z = 0; + + Materialize(); + } +} + +//========================================================= +// Materialize - make a CBasePlayerItem visible and tangible +//========================================================= +void CBasePlayerItem::Materialize( void ) +{ + if ( pev->effects & EF_NODRAW ) + { + // changing from invisible state to visible. + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); + pev->effects &= ~EF_NODRAW; + pev->effects |= EF_MUZZLEFLASH; + } + + pev->solid = SOLID_TRIGGER; + + UTIL_SetOrigin( pev, pev->origin );// link into world. + SetTouch (&CBasePlayerItem::DefaultTouch); + SetThink (NULL); + + this->VirtualMaterialize(); +} + +//========================================================= +// AttemptToMaterialize - the item is trying to rematerialize, +// should it do so now or wait longer? +//========================================================= +void CBasePlayerItem::AttemptToMaterialize( void ) +{ + float time = g_pGameRules->FlWeaponTryRespawn( this ); + + if ( time == 0 ) + { + Materialize(); + return; + } + + pev->nextthink = gpGlobals->time + time; +} + +//========================================================= +// CheckRespawn - a player is taking this weapon, should +// it respawn? +//========================================================= +void CBasePlayerItem :: CheckRespawn ( void ) +{ + switch ( g_pGameRules->WeaponShouldRespawn( this ) ) + { + case GR_WEAPON_RESPAWN_YES: + Respawn(); + break; + case GR_WEAPON_RESPAWN_NO: + return; + break; + } +} + +//========================================================= +// Respawn- this item is already in the world, but it is +// invisible and intangible. Make it visible and tangible. +//========================================================= +CBaseEntity* CBasePlayerItem::Respawn( void ) +{ + // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code + // will decide when to make the weapon visible and touchable. + CBaseEntity *pNewWeapon = CBaseEntity::Create( (char *)STRING( pev->classname ), g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); + + if ( pNewWeapon ) + { + pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now + pNewWeapon->SetTouch( NULL );// no touch + pNewWeapon->SetThink(&CBasePlayerItem::AttemptToMaterialize ); + + DROP_TO_FLOOR ( ENT(pev) ); + + // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement, + // but when it should respawn is based on conditions belonging to the weapon that was taken. + pNewWeapon->pev->nextthink = g_pGameRules->FlWeaponRespawnTime( this ); + } + else + { + ALERT ( at_console, "Respawn failed to create %s!\n", STRING( pev->classname ) ); + } + + return pNewWeapon; +} + +void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) +{ + // if it's not a player, ignore + if ( !pOther->IsPlayer() ) + return; + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + + // can I have this? + if ( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) + { + if ( gEvilImpulse101 ) + { + UTIL_Remove( this ); + } + return; + } + + if (pOther->AddPlayerItem( this )) + { + AttachToPlayer( pPlayer ); + + AvHPlayer* thePlayer = dynamic_cast(pPlayer); + if(thePlayer && thePlayer->GetIsAlien()) + { + EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2-a.wav", 1, ATTN_NORM); + } + else + { + EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); + } + } + + SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? +} + +BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) +{ + if ( !isPredicted ) + { + return ( attack_time <= curtime ) ? TRUE : FALSE; + } + else + { + return ( attack_time <= 0.0 ) ? TRUE : FALSE; + } +} + + +void CBasePlayerWeapon::ItemPostFrame( void ) +{ + bool theAttackPressed = (m_pPlayer->pev->button & IN_ATTACK) && !(m_pPlayer->pev->button & IN_ATTACK2); + + bool theWeaponPrimes = (this->GetWeaponPrimeTime() > 0.0f); + bool theWeaponIsPriming = this->GetIsWeaponPriming(); + bool theWeaponIsPrimed = this->GetIsWeaponPrimed(); + + if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) + { + // complete the reload. + int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + // Add them to the clip + m_iClip += j; + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; + + m_pPlayer->TabulateAmmo(); + + m_fInReload = FALSE; + } + +/* // +movement: Removed case for +attack2 since it's used for movement abilities + if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) + { + if (m_pPlayer->GetCanUseWeapon()) + { + + if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + { + m_fFireOnEmpty = TRUE; + } + + m_pPlayer->TabulateAmmo(); + SecondaryAttack(); + m_pPlayer->pev->button &= ~IN_ATTACK2; + } + } + else +*/ + if ( theAttackPressed && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) + { + if (m_pPlayer->GetCanUseWeapon()) + { + if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + { + m_fFireOnEmpty = TRUE; + } + + m_pPlayer->TabulateAmmo(); + PrimaryAttack(); + } + } + else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) + { + if (m_pPlayer->GetCanUseWeapon()) + { + // reload when reload is pressed, or if no buttons are down and weapon is empty. + Reload(); + } + } + // +movement: Removed case for +attack2 + else if ( !(m_pPlayer->pev->button & (IN_ATTACK /* |IN_ATTACK2 */) ) ) + { + if (m_pPlayer->GetCanUseWeapon()) + { + + // no fire buttons down + + m_fFireOnEmpty = FALSE; + + if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) + { + // weapon isn't useable, switch. + if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) + { + m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; + return; + } + } + else + { + // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) + { + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) + { + Reload(); + return; + } + } + } + + WeaponIdle( ); + } + return; + } + + // catch all + if ( ShouldWeaponIdle() ) + { + WeaponIdle(); + } +} + +void CBasePlayerItem::DestroyItem( void ) +{ + //KGP: this is a virtual function call for a reason... + // it had been replaced with the contents of + // CBasePlayerItem::VirtualDestroyItem, ignoring + // AvHBasePlayerWeapon::VirtualDestroyItem in 3.01 + this->VirtualDestroyItem(); +} + +void CBasePlayerItem::VirtualDestroyItem( void ) +{ + if ( m_pPlayer ) + { + // if attached to a player, remove. + m_pPlayer->RemovePlayerItem( this ); + } + + Kill( ); +} + +int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) +{ + m_pPlayer = pPlayer; + pPlayer->m_iHideHUD &= ~HIDEHUD_WEAPONS; + return TRUE; +} + +void CBasePlayerItem::Drop( void ) +{ + SetTouch( NULL ); + SetThink(&CBasePlayerItem::SUB_Remove); + pev->nextthink = gpGlobals->time + .1; +} + +void CBasePlayerItem::Kill( void ) +{ + SetTouch( NULL ); + SetThink(&CBasePlayerItem::SUB_Remove); + pev->nextthink = gpGlobals->time + .1; +} + +void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->pev->viewmodel = 0; + m_pPlayer->pev->weaponmodel = 0; +} + +void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) +{ + pev->movetype = MOVETYPE_FOLLOW; + pev->solid = SOLID_NOT; + pev->aiment = pPlayer->edict(); + pev->effects = EF_NODRAW; // ?? + pev->modelindex = 0;// server won't send down to clients if modelindex == 0 + pev->model = iStringNull; + pev->owner = pPlayer->edict(); + pev->nextthink = gpGlobals->time + .1; + SetTouch( NULL ); +} + +void CBasePlayerItem::Spawn() +{ + CBaseAnimating::Spawn(); +} + +// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal +int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) +{ + if ( m_iDefaultAmmo ) + { + return ExtractAmmo( (CBasePlayerWeapon *)pOriginal ); + } + else + { + // a dead player dropped this. + return ExtractClipAmmo( (CBasePlayerWeapon *)pOriginal ); + } +} + + +int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) +{ + int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); + + pPlayer->pev->weapons |= (1<GetAmmoIndex( pszAmmo1() ); + m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); + } + + + if (bResult) + return AddWeapon( ); + return FALSE; +} + +int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) +{ + BOOL bSend = FALSE; + int state = 0; + + // KGP: folded m_iEnabled into the state value and converted it to a proper bitfield. + if( pPlayer->m_pActiveItem == this ) + { state |= WEAPON_IS_CURRENT; } + if( pPlayer->m_fOnTarget ) + { state |= WEAPON_ON_TARGET; } + if( m_iEnabled ) + { state |= WEAPON_IS_ENABLED; } + + // Forcing send of all data! + if ( !pPlayer->m_fWeapon ) + { + bSend = TRUE; + } + + // This is the current or last weapon, so the state will need to be updated + if ( this == pPlayer->m_pActiveItem || + this == pPlayer->m_pClientActiveItem ) + { + if ( pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem ) + { + bSend = TRUE; + } + } + + // If the ammo, state, or fov has changed, update the weapon + if ( m_iClip != m_iClientClip || + state != m_iClientWeaponState || + pPlayer->m_iFOV != pPlayer->m_iClientFOV ) + { + bSend = TRUE; + } + + if (m_iId == 22 || m_iId == 11 || m_iId == 21) + gCanMove[pPlayer->entindex() - 1] = m_iEnabled; + + if ( bSend ) + { + NetMsg_CurWeapon( pPlayer->pev, state, m_iId, m_iClip ); + m_iClientClip = m_iClip; + m_iClientWeaponState = state; + pPlayer->m_fWeapon = TRUE; + } + + if ( m_pNext ) + m_pNext->UpdateClientData( pPlayer ); + + return 1; +} + +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) +{ + if(iAnim >= 0) + { + if ( UseDecrement() ) + skiplocal = 1; + else + skiplocal = 0; + + m_pPlayer->pev->weaponanim = iAnim; + + if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) + return; + + MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); + WRITE_BYTE( iAnim ); // sequence number + WRITE_BYTE( pev->body ); // weaponmodel bodygroup. + MESSAGE_END(); + } +} + +BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) +{ + int iIdAmmo; + + if (iMaxClip < 1) + { + m_iClip = -1; + iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); + } + else if (m_iClip == 0) + { + int i; + i = min( m_iClip + iCount, iMaxClip ) - m_iClip; + m_iClip += i; + iIdAmmo = m_pPlayer->GiveAmmo( iCount - i, szName, iMaxCarry ); + } + else + { + iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); + } + + // m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing + + if (iIdAmmo > 0) + { + m_iPrimaryAmmoType = iIdAmmo; + if (m_pPlayer->HasPlayerItem( this ) ) + { + // play the "got ammo" sound only if we gave some ammo to a player that already had this gun. + // if the player is just getting this gun for the first time, DefaultTouch will play the "picked up gun" sound for us. + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + } + } + + return iIdAmmo > 0 ? TRUE : FALSE; +} + + +BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) +{ + int iIdAmmo; + + iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMax ); + + //m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = iMax; // hack for testing + + if (iIdAmmo > 0) + { + m_iSecondaryAmmoType = iIdAmmo; + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + } + return iIdAmmo > 0 ? TRUE : FALSE; +} + +//========================================================= +// IsUseable - this function determines whether or not a +// weapon is useable by the player in its current state. +// (does it have ammo loaded? do I have any ammo for the +// weapon?, etc) +//========================================================= +BOOL CBasePlayerWeapon :: IsUseable( void ) +{ + if ( m_iClip <= 0 ) + { + // This looks like a nasty bug Valve didn't notice + ASSERT(PrimaryAmmoIndex() >= 0); + + if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 ) + { + // clip is empty (or nonexistant) and the player has no more ammo of this type. + return FALSE; + } + } + + return TRUE; +} + +BOOL CBasePlayerWeapon :: CanDeploy( void ) +{ + BOOL bHasAmmo = 0; + + // All weapons can always deploy. Once fire is hit, it checks if it's out of ammo. If so, the weapon switches. + // This is needed so ammo packs function correctly, and it also feels more responsive. + +// if ( !pszAmmo1() ) +// { +// // this weapon doesn't use ammo, can always deploy. +// return TRUE; +// } +// +// if ( pszAmmo1() ) +// { +// bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); +// } +// if ( pszAmmo2() ) +// { +// bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); +// } +// if (m_iClip > 0) +// { +// bHasAmmo |= 1; +// } +// if (!bHasAmmo) +// { +// return FALSE; +// } + + return TRUE; +} + +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body) +{ + if (!CanDeploy( )) + return FALSE; + + m_pPlayer->TabulateAmmo(); + m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); + m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); + strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); + SendWeaponAnim( iAnim, skiplocal, body ); + + // Set the player animation as well + //this->m_pPlayer->SetAnimation(PLAYER_ANIM(iAnim)); + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + this->GetDeployTime(); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + this->GetDeployTime() + kDeployIdleInterval; + + return TRUE; +} + + +BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body) +{ + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + return FALSE; + + int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + if (j == 0) + return FALSE; + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; + + //!!UNDONE -- reload sound goes here !!! + //SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); + + m_fInReload = TRUE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kDeployIdleInterval; + + return TRUE; +} + +BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +{ + if (m_iPlayEmptySound) + { +// EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); + + int flags = FEV_NOTHOST; + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), gEmptySoundEventID, 0.0, (float *)&(m_pPlayer->pev->origin), (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); + + m_iPlayEmptySound = 0; + return 0; + } + return 0; +} + +void CBasePlayerWeapon :: ResetEmptySound( void ) +{ + m_iPlayEmptySound = 1; +} + +//========================================================= +//========================================================= +int CBasePlayerWeapon::PrimaryAmmoIndex( void ) +{ + return m_iPrimaryAmmoType; +} + +//========================================================= +//========================================================= +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) +{ + return -1; +} + +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE; // cancel any reload in progress. + m_pPlayer->pev->viewmodel = 0; + m_pPlayer->pev->weaponmodel = 0; +} + +void CBasePlayerAmmo::Spawn( void ) +{ + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + UTIL_SetOrigin( pev, pev->origin ); + + SetTouch(&CBasePlayerAmmo::DefaultTouch ); +} + +CBaseEntity* CBasePlayerAmmo::Respawn( void ) +{ + pev->effects |= EF_NODRAW; + SetTouch( NULL ); + + UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. + + SetThink(&CBasePlayerAmmo::Materialize ); + pev->nextthink = g_pGameRules->FlAmmoRespawnTime( this ); + + return this; +} + +void CBasePlayerAmmo::Materialize( void ) +{ + if ( pev->effects & EF_NODRAW ) + { + // changing from invisible state to visible. + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); + pev->effects &= ~EF_NODRAW; + pev->effects |= EF_MUZZLEFLASH; + } + + SetTouch(&CBasePlayerAmmo::DefaultTouch ); +} + +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) +{ + if ( !pOther->IsPlayer() ) + { + return; + } + + if (AddAmmo( pOther )) + { + if ( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) + { + Respawn(); + } + else + { + SetTouch( NULL ); + SetThink(&CBasePlayerAmmo::SUB_Remove); + pev->nextthink = gpGlobals->time + .1; + } + } + else if (gEvilImpulse101) + { + // evil impulse 101 hack, kill always + SetTouch( NULL ); + SetThink(&CBasePlayerAmmo::SUB_Remove); + pev->nextthink = gpGlobals->time + .1; + } +} + +//========================================================= +// called by the new item with the existing item as parameter +// +// if we call ExtractAmmo(), it's because the player is picking up this type of weapon for +// the first time. If it is spawned by the world, m_iDefaultAmmo will have a default ammo amount in it. +// if this is a weapon dropped by a dying player, has 0 m_iDefaultAmmo, which means only the ammo in +// the weapon clip comes along. +//========================================================= +int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) +{ + int iReturn; + + if ( pszAmmo1() != NULL ) + { + // blindly call with m_iDefaultAmmo. It's either going to be a value or zero. If it is zero, + // we only get the ammo in the weapon's clip, which is what we want. + iReturn = pWeapon->AddPrimaryAmmo( m_iDefaultAmmo, (char *)pszAmmo1(), iMaxClip(), iMaxAmmo1() ); + m_iDefaultAmmo = 0; + } + + if ( pszAmmo2() != NULL ) + { + iReturn = pWeapon->AddSecondaryAmmo( 0, (char *)pszAmmo2(), iMaxAmmo2() ); + } + + return iReturn; +} + +//========================================================= +// called by the new item's class with the existing item as parameter +//========================================================= +int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) +{ + int iAmmo; + + if ( m_iClip == WEAPON_NOCLIP ) + { + iAmmo = 0;// guns with no clips always come empty if they are second-hand + } + else + { + iAmmo = m_iClip; + } + + return pWeapon->m_pPlayer->GiveAmmo( iAmmo, (char *)pszAmmo1(), iMaxAmmo1() ); // , &m_iPrimaryAmmoType +} + +//========================================================= +// RetireWeapon - no more ammo for this gun, put it away. +//========================================================= +void CBasePlayerWeapon::RetireWeapon( void ) +{ + // first, no viewmodel at all. + m_pPlayer->pev->viewmodel = iStringNull; + m_pPlayer->pev->weaponmodel = iStringNull; + //m_pPlayer->pev->viewmodelindex = NULL; + + g_pGameRules->GetNextBestWeapon( m_pPlayer, this ); +} + +//********************************************************* +// weaponbox code: +//********************************************************* + +LINK_ENTITY_TO_CLASS( weaponbox, CWeaponBox ); + +TYPEDESCRIPTION CWeaponBox::m_SaveData[] = +{ + DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), + DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ), + DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), + DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ); + +//========================================================= +// +//========================================================= +void CWeaponBox::Precache( void ) +{ + PRECACHE_UNMODIFIED_MODEL("models/w_weaponbox.mdl"); +} + +//========================================================= +//========================================================= +void CWeaponBox :: KeyValue( KeyValueData *pkvd ) +{ + if ( m_cAmmoTypes < MAX_AMMO_SLOTS ) + { + PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) ); + m_cAmmoTypes++;// count this new ammo type. + + pkvd->fHandled = TRUE; + } + else + { + ALERT ( at_console, "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS ); + } +} + +//========================================================= +// CWeaponBox - Spawn +//========================================================= +void CWeaponBox::Spawn( void ) +{ + Precache( ); + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + + UTIL_SetSize( pev, g_vecZero, g_vecZero ); + + SET_MODEL( ENT(pev), "models/w_weaponbox.mdl"); +} + +//========================================================= +// CWeaponBox - Kill - the think function that removes the +// box from the world. +//========================================================= +void CWeaponBox::Kill( void ) +{ + CBasePlayerItem *pWeapon; + int i; + + // destroy the weapons + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + pWeapon = m_rgpPlayerItems[ i ]; + + while ( pWeapon ) + { + pWeapon->SetThink(&CWeaponBox::SUB_Remove); + pWeapon->pev->nextthink = gpGlobals->time + 0.1; + pWeapon = pWeapon->m_pNext; + } + } + + // remove the box + UTIL_Remove( this ); +} + +//========================================================= +// CWeaponBox - Touch: try to add my contents to the toucher +// if the toucher is a player. +//========================================================= +void CWeaponBox::Touch( CBaseEntity *pOther ) +{ + if ( !(pev->flags & FL_ONGROUND ) ) + { + return; + } + + if ( !pOther->IsPlayer() ) + { + // only players may touch a weaponbox. + return; + } + + if ( !pOther->IsAlive() ) + { + // no dead guys. + return; + } + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + int i; + +// dole out ammo + for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + { + if ( !FStringNull( m_rgiszAmmo[ i ] ) ) + { + // there's some ammo of this type. + pPlayer->GiveAmmo( m_rgAmmo[ i ], (char *)STRING( m_rgiszAmmo[ i ] ), MaxAmmoCarry( m_rgiszAmmo[ i ] ) ); + + //ALERT ( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING(m_rgiszAmmo[i]) ); + + // now empty the ammo from the weaponbox since we just gave it to the player + m_rgiszAmmo[ i ] = iStringNull; + m_rgAmmo[ i ] = 0; + } + } + +// go through my weapons and try to give the usable ones to the player. +// it's important the the player be given ammo first, so the weapons code doesn't refuse +// to deploy a better weapon that the player may pick up because he has no ammo for it. + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + CBasePlayerItem *pItem; + + // have at least one weapon in this slot + while ( m_rgpPlayerItems[ i ] ) + { + //ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) ); + + pItem = m_rgpPlayerItems[ i ]; + m_rgpPlayerItems[ i ] = m_rgpPlayerItems[ i ]->m_pNext;// unlink this weapon from the box + + if ( pPlayer->AddPlayerItem( pItem ) ) + { + pItem->AttachToPlayer( pPlayer ); + } + } + } + } + + EMIT_SOUND( pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + SetTouch(NULL); + UTIL_Remove(this); +} + +//========================================================= +// CWeaponBox - PackWeapon: Add this weapon to the box +//========================================================= +BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) +{ + // is one of these weapons already packed in this box? + if ( HasWeapon( pWeapon ) ) + { + return FALSE;// box can only hold one of each weapon type + } + + if ( pWeapon->m_pPlayer ) + { + if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) + { + // failed to unhook the weapon from the player! + return FALSE; + } + } + + int iWeaponSlot = pWeapon->iItemSlot(); + + if ( m_rgpPlayerItems[ iWeaponSlot ] ) + { + // there's already one weapon in this slot, so link this into the slot's column + pWeapon->m_pNext = m_rgpPlayerItems[ iWeaponSlot ]; + m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; + } + else + { + // first weapon we have for this slot + m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; + pWeapon->m_pNext = NULL; + } + + pWeapon->pev->spawnflags |= SF_NORESPAWN;// never respawn + pWeapon->pev->movetype = MOVETYPE_NONE; + pWeapon->pev->solid = SOLID_NOT; + pWeapon->pev->effects = EF_NODRAW; + pWeapon->pev->modelindex = 0; + pWeapon->pev->model = iStringNull; + pWeapon->pev->owner = edict(); + pWeapon->SetThink( NULL );// crowbar may be trying to swing again, etc. + pWeapon->SetTouch( NULL ); + pWeapon->m_pPlayer = NULL; + + //ALERT ( at_console, "packed %s\n", STRING(pWeapon->pev->classname) ); + + return TRUE; +} + +//========================================================= +// CWeaponBox - PackAmmo +//========================================================= +BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) +{ + int iMaxCarry; + + if ( FStringNull( iszName ) ) + { + // error here + ALERT ( at_console, "NULL String in PackAmmo!\n" ); + return FALSE; + } + + iMaxCarry = MaxAmmoCarry( iszName ); + + if ( iMaxCarry != -1 && iCount > 0 ) + { + //ALERT ( at_console, "Packed %d rounds of %s\n", iCount, STRING(iszName) ); + GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); + return TRUE; + } + + return FALSE; +} + +//========================================================= +// CWeaponBox - GiveAmmo +//========================================================= +int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NULL*/ ) +{ + int i; + + for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++) + { + if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0) + { + if (pIndex) + *pIndex = i; + + int iAdd = min( iCount, iMax - m_rgAmmo[i]); + if (iCount == 0 || iAdd > 0) + { + m_rgAmmo[i] += iAdd; + + return i; + } + return -1; + } + } + if (i < MAX_AMMO_SLOTS) + { + if (pIndex) + *pIndex = i; + + m_rgiszAmmo[i] = MAKE_STRING( szName ); + m_rgAmmo[i] = iCount; + + return i; + } + ALERT( at_console, "out of named ammo slots\n"); + return i; +} + +//========================================================= +// CWeaponBox::HasWeapon - is a weapon of this type already +// packed in this box? +//========================================================= +BOOL CWeaponBox::HasWeapon( CBasePlayerItem *pCheckItem ) +{ + CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; + + while (pItem) + { + if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) + { + return TRUE; + } + pItem = pItem->m_pNext; + } + + return FALSE; +} + +//========================================================= +// CWeaponBox::IsEmpty - is there anything in this box? +//========================================================= +BOOL CWeaponBox::IsEmpty( void ) +{ + int i; + + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + return FALSE; + } + } + + for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + { + if ( !FStringNull( m_rgiszAmmo[ i ] ) ) + { + // still have a bit of this type of ammo + return FALSE; + } + } + + return TRUE; +} + +//========================================================= +//========================================================= +void CWeaponBox::SetObjectCollisionBox( void ) +{ + pev->absmin = pev->origin + Vector(-16, -16, 0); + pev->absmax = pev->origin + Vector(16, 16, 16); +} + + +void CBasePlayerWeapon::PrintState( void ) +{ + ALERT( at_console, "primary: %f\n", m_flNextPrimaryAttack ); + ALERT( at_console, "idle : %f\n", m_flTimeWeaponIdle ); + +// ALERT( at_console, "nextrl : %f\n", m_flNextReload ); +// ALERT( at_console, "nextpum: %f\n", m_flPumpTime ); + +// ALERT( at_console, "m_frt : %f\n", m_fReloadTime ); + ALERT( at_console, "m_finre: %i\n", m_fInReload ); +// ALERT( at_console, "m_finsr: %i\n", m_fInSpecialReload ); + + ALERT( at_console, "m_iclip: %i\n", m_iClip ); +} + + +TYPEDESCRIPTION CRpg::m_SaveData[] = +{ + DEFINE_FIELD( CRpg, m_fSpotActive, FIELD_INTEGER ), + DEFINE_FIELD( CRpg, m_cActiveRockets, FIELD_INTEGER ), +}; +IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon ); + +TYPEDESCRIPTION CRpgRocket::m_SaveData[] = +{ + DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), + DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), +}; +IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ); + +TYPEDESCRIPTION CShotgun::m_SaveData[] = +{ + DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), + DEFINE_FIELD( CShotgun, m_fInSpecialReload, FIELD_INTEGER ), + DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), + // DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ), + DEFINE_FIELD( CShotgun, m_flPumpTime, FIELD_TIME ), +}; +IMPLEMENT_SAVERESTORE( CShotgun, CBasePlayerWeapon ); + +TYPEDESCRIPTION CGauss::m_SaveData[] = +{ + DEFINE_FIELD( CGauss, m_fInAttack, FIELD_INTEGER ), +// DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ), +// DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ), +// DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ), + DEFINE_FIELD( CGauss, m_fPrimaryFire, FIELD_BOOLEAN ), +}; +IMPLEMENT_SAVERESTORE( CGauss, CBasePlayerWeapon ); + +TYPEDESCRIPTION CEgon::m_SaveData[] = +{ +// DEFINE_FIELD( CEgon, m_pBeam, FIELD_CLASSPTR ), +// DEFINE_FIELD( CEgon, m_pNoise, FIELD_CLASSPTR ), +// DEFINE_FIELD( CEgon, m_pSprite, FIELD_CLASSPTR ), + DEFINE_FIELD( CEgon, m_shootTime, FIELD_TIME ), + DEFINE_FIELD( CEgon, m_fireState, FIELD_INTEGER ), + DEFINE_FIELD( CEgon, m_fireMode, FIELD_INTEGER ), + DEFINE_FIELD( CEgon, m_shakeTime, FIELD_TIME ), + DEFINE_FIELD( CEgon, m_flAmmoUseTime, FIELD_TIME ), +}; +IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ); + +TYPEDESCRIPTION CSatchel::m_SaveData[] = +{ + DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), +}; +IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ); + diff --git a/main/source/dlls/weapons.cpp~ b/main/source/dlls/weapons.cpp~ deleted file mode 100644 index 7a6469e4..00000000 --- a/main/source/dlls/weapons.cpp~ +++ /dev/null @@ -1,1926 +0,0 @@ -// -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// ===== weapons.cpp ======================================================== -// -// functions governing the selection/use of weapons for players -// -// $Workfile: weapons.cpp $ -// $Date: 2002/11/22 21:13:52 $ -// -//------------------------------------------------------------------------------- -// $Log: weapons.cpp,v $ -// Revision 1.49 2002/11/22 21:13:52 Flayra -// - mp_consistency changes -// -// Revision 1.48 2002/11/12 02:19:43 Flayra -// - Fixed problem where friendly bulletfire was doing damage -// -// Revision 1.47 2002/10/24 21:19:11 Flayra -// - Reworked jetpack effects -// - Added a few extra sounds -// -// Revision 1.46 2002/10/16 00:41:15 Flayra -// - Removed unneeds sounds and events -// - Added distress beacon event -// - Added general purpose particle event -// -// Revision 1.45 2002/09/25 20:40:09 Flayra -// - Play different sound for aliens when they get weapons -// -// Revision 1.44 2002/09/23 22:04:00 Flayra -// - Regular update -// -// Revision 1.43 2002/08/31 18:01:18 Flayra -// - Work at VALVe -// -// Revision 1.42 2002/07/26 23:01:05 Flayra -// - Precache numerical feedback event -// -// Revision 1.41 2002/07/23 16:48:37 Flayra -// - Added distress beacon -// -// Revision 1.40 2002/07/08 16:35:17 Flayra -// - Added document header, updates for cheat protection, added constants -// -//=============================================================================== -#include "util/nowarnings.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "decals.h" -#include "gamerules.h" -#include "../mod/AvHConstants.h" -#include "../mod/AvHMarineEquipmentConstants.h" -#include "../mod/AvHAlienWeaponConstants.h" -#include "../mod/AvHAlienEquipmentConstants.h" -#include "../mod/AvHPlayer.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHNetworkMessages.h" - -extern CGraph WorldGraph; -extern int gEvilImpulse101; - -int gJetpackEventID; -int gStartOverwatchEventID; -int gEndOverwatchEventID; -int gTeleportEventID; -int gBlinkEffectSuccessEventID; -int gPhaseInEventID; -int gSiegeHitEventID; -int gSiegeViewHitEventID; -int gCommanderPointsAwardedEventID; -int gAlienSightOnEventID; -int gAlienSightOffEventID; -//int gParalysisStartEventID; -int gRegenerationEventID; -int gStartCloakEventID; -int gEndCloakEventID; -int gSporeCloudEventID; -int gUmbraCloudEventID; -int gStopScreamEventID; - -int gWelderEventID; -int gWelderConstEventID; -//int gWallJumpEventID; -//int gFlightEventID; -int gEmptySoundEventID; -int gNumericalInfoEventID; -int gInvalidActionEventID; -int gParticleEventID; -int gDistressBeaconEventID; -int gWeaponAnimationEventID; -int gLevelUpEventID; -int gMetabolizeSuccessEventID; - -#define NOT_USED 255 - -DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam -DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr"; -DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot -DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball -DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud -DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion -DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model -DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood -DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood - -ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; -AmmoInfo CBasePlayerItem::AmmoInfoArray[MAX_AMMO_SLOTS]; - -MULTIDAMAGE gMultiDamage; - -#define TRACER_FREQ 4 // Tracers fire every fourth bullet - -extern bool gCanMove[]; - -//========================================================= -// MaxAmmoCarry - pass in a name and this function will tell -// you the maximum amount of that type of ammunition that a -// player can carry. -//========================================================= -int MaxAmmoCarry( int iszName ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo1 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo1 ) ) - return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo1; - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo2 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo2 ) ) - return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo2; - } - - ALERT( at_console, "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName ) ); - return -1; -} - - -/* -============================================================================== - -MULTI-DAMAGE - -Collects multiple small damages into a single damage - -============================================================================== -*/ - -// -// ClearMultiDamage - resets the global multi damage accumulator -// -void ClearMultiDamage(void) -{ - gMultiDamage.pEntity = NULL; - gMultiDamage.amount = 0; - gMultiDamage.type = 0; -} - -// -// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity -// -// GLOBALS USED: -// gMultiDamage - -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) -{ - Vector vecSpot1;//where blood comes from - Vector vecDir;//direction blood should go - TraceResult tr; - - if ( !gMultiDamage.pEntity ) - return; - - float theDamage = gMultiDamage.amount; - gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, theDamage, gMultiDamage.type ); -} - - -// GLOBALS USED: -// gMultiDamage - -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) -{ - if ( !pEntity ) - return; - - gMultiDamage.type |= bitsDamageType; - - if ( pEntity != gMultiDamage.pEntity ) - { - ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker! - gMultiDamage.pEntity = pEntity; - gMultiDamage.amount = 0; - } - - gMultiDamage.amount += flDamage; -} - -/* -================ -SpawnBlood -================ -*/ -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) -{ - if(flDamage >= 0.0f) - { - if(bloodColor == DONT_BLEED) - { - UTIL_Sparks(vecSpot); - } - else - { - UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); - } - } -} - - -int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) -{ - if ( !pEntity ) - return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); - - return pEntity->DamageDecal( bitsDamageType ); -} - -void DecalGunshot( TraceResult *pTrace, int iBulletType ) -{ - // Is the entity valid - if ( !UTIL_IsValidEntity( pTrace->pHit ) ) - return; - - if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP ) - { - CBaseEntity *pEntity = NULL; - // Decal the wall with a gunshot - if ( !FNullEnt(pTrace->pHit) ) - pEntity = CBaseEntity::Instance(pTrace->pHit); - -// switch( iBulletType ) -// { -// case BULLET_PLAYER_9MM: -// case BULLET_MONSTER_9MM: -// case BULLET_PLAYER_MP5: -// case BULLET_MONSTER_MP5: -// case BULLET_PLAYER_BUCKSHOT: -// case BULLET_PLAYER_357: -// default: - // smoke and decal - UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); -// break; -// case BULLET_MONSTER_12MM: -// // smoke and decal -// UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); -// break; -// case BULLET_PLAYER_CROWBAR: -// // wall decal -// UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); -// break; -// } - } -} - - - -// -// EjectBrass - tosses a brass shell from passed origin at passed velocity -// -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) -{ - // FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see. - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE( TE_MODEL); - WRITE_COORD( vecOrigin.x); - WRITE_COORD( vecOrigin.y); - WRITE_COORD( vecOrigin.z); - WRITE_COORD( vecVelocity.x); - WRITE_COORD( vecVelocity.y); - WRITE_COORD( vecVelocity.z); - WRITE_ANGLE( rotation ); - WRITE_SHORT( model ); - WRITE_BYTE ( soundtype); - WRITE_BYTE ( 25 );// 2.5 seconds - MESSAGE_END(); -} - - -#if 0 -// UNDONE: This is no longer used? -void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE ( TE_EXPLODEMODEL ); - WRITE_COORD( vecOrigin.x ); - WRITE_COORD( vecOrigin.y ); - WRITE_COORD( vecOrigin.z ); - WRITE_COORD( speed ); - WRITE_SHORT( model ); - WRITE_SHORT( count ); - WRITE_BYTE ( 15 );// 1.5 seconds - MESSAGE_END(); -} -#endif - - -int giAmmoIndex = 0; - -// Precaches the ammo and queues the ammo info for sending to clients -void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) -{ - // make sure it's not already in the registry - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName) - continue; - - if ( stricmp( CBasePlayerItem::AmmoInfoArray[i].pszName, szAmmoname ) == 0 ) - return; // ammo already in registry, just quite - } - - - giAmmoIndex++; - ASSERT( giAmmoIndex < MAX_AMMO_SLOTS ); - if ( giAmmoIndex >= MAX_AMMO_SLOTS ) - giAmmoIndex = 0; - - CBasePlayerItem::AmmoInfoArray[giAmmoIndex].pszName = szAmmoname; - CBasePlayerItem::AmmoInfoArray[giAmmoIndex].iId = giAmmoIndex; // yes, this info is redundant -} - - -// Precaches the weapon and queues the weapon info for sending to clients -void UTIL_PrecacheOtherWeapon( const char *szClassname ) -{ - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOtherWeapon\n" ); - return; - } - - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - - if (pEntity) - { - ItemInfo II; - pEntity->Precache( ); - memset( &II, 0, sizeof II ); - if ( ((CBasePlayerItem*)pEntity)->GetItemInfo( &II ) ) - { - CBasePlayerItem::ItemInfoArray[II.iId] = II; - - if ( II.pszAmmo1 && *II.pszAmmo1 ) - { - AddAmmoNameToAmmoRegistry( II.pszAmmo1 ); - } - - if ( II.pszAmmo2 && *II.pszAmmo2 ) - { - AddAmmoNameToAmmoRegistry( II.pszAmmo2 ); - } - - memset( &II, 0, sizeof II ); - } - } - - REMOVE_ENTITY(pent); -} - -// called by worldspawn -void W_Precache(void) -{ - memset( CBasePlayerItem::ItemInfoArray, 0, sizeof(CBasePlayerItem::ItemInfoArray) ); - memset( CBasePlayerItem::AmmoInfoArray, 0, sizeof(CBasePlayerItem::AmmoInfoArray) ); - giAmmoIndex = 0; - - // Marine weapons - //UTIL_PrecacheOtherWeapon("weapon_9mmhandgun"); - //UTIL_PrecacheOtherWeapon("weapon_glock"); - //UTIL_PrecacheOther("ammo_9mmclip"); - - // Player assets - PRECACHE_UNMODIFIED_MODEL(kReadyRoomModel); - PRECACHE_UNMODIFIED_MODEL(kMarineSoldierModel); - PRECACHE_UNMODIFIED_MODEL(kHeavySoldierModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelOneModel); - PRECACHE_UNMODIFIED_SOUND(kDistressBeaconSound); - PRECACHE_UNMODIFIED_SOUND(kLevelUpMarineSound); - PRECACHE_UNMODIFIED_SOUND(kLevelUpAlienSound); - PRECACHE_UNMODIFIED_SOUND(kAlienBuildingSound1); - PRECACHE_UNMODIFIED_SOUND(kAlienBuildingSound2); - PRECACHE_SOUND(kMyHiveEasterEgg); - - //PRECACHE_UNMODIFIED_SOUND(kAlienAbilitiesGrantedSound); - //PRECACHE_UNMODIFIED_SOUND(kAlienAbilitiesLostSound); - - PRECACHE_UNMODIFIED_MODEL(kAlienLevelTwoModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelThreeModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFourModel); - PRECACHE_UNMODIFIED_MODEL(kAlienLevelFiveModel); - - PRECACHE_UNMODIFIED_MODEL(kMarineCommanderModel); - PRECACHE_UNMODIFIED_MODEL(kAlienGestateModel); - // : 1072 - // Added some client side consistency checks. - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash1.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/muzzleflash3.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/digesting.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/membrane.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/hera_fog.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/spore2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/umbra2.spr"); - PRECACHE_UNMODIFIED_MODEL("sprites/webstrand.spr"); - - UTIL_PrecacheOtherWeapon(kwsMine); - UTIL_PrecacheOtherWeapon(kwsKnife); - UTIL_PrecacheOtherWeapon(kwsMachineGun); - UTIL_PrecacheOtherWeapon(kwsPistol); - UTIL_PrecacheOtherWeapon(kwsShotGun); - UTIL_PrecacheOtherWeapon(kwsHeavyMachineGun); - UTIL_PrecacheOtherWeapon(kwsGrenadeGun); - UTIL_PrecacheOtherWeapon(kwsGrenade); - - // Alien weapons - UTIL_PrecacheOtherWeapon(kwsSpitGun); - UTIL_PrecacheOther(kwsSpitProjectile); - UTIL_PrecacheOther(kwsWebProjectile); - UTIL_PrecacheOtherWeapon(kwsClaws); - UTIL_PrecacheOtherWeapon(kwsSwipe); - UTIL_PrecacheOtherWeapon(kwsSporeGun); - UTIL_PrecacheOther(kwsSporeProjectile); -// UTIL_PrecacheOtherWeapon(kwsParalysisGun); - UTIL_PrecacheOtherWeapon(kwsSpikeGun); - UTIL_PrecacheOtherWeapon(kwsBiteGun); - UTIL_PrecacheOtherWeapon(kwsBite2Gun); - UTIL_PrecacheOtherWeapon(kwsHealingSpray); - UTIL_PrecacheOtherWeapon(kwsWebSpinner); -// UTIL_PrecacheOtherWeapon(kwsBabblerGun); - UTIL_PrecacheOtherWeapon(kwsPrimalScream); - UTIL_PrecacheOtherWeapon(kwsParasiteGun); - UTIL_PrecacheOtherWeapon(kwsMetabolize); - UTIL_PrecacheOtherWeapon(kwsUmbraGun); - UTIL_PrecacheOtherWeapon(kwsBlinkGun); - UTIL_PrecacheOtherWeapon(kwsDivineWind); - UTIL_PrecacheOtherWeapon(kwsBileBombGun); - UTIL_PrecacheOtherWeapon(kwsAcidRocketGun); - UTIL_PrecacheOtherWeapon(kwsStomp); - UTIL_PrecacheOtherWeapon(kwsDevour); -// UTIL_PrecacheOtherWeapon(kwsAmplify); - UTIL_PrecacheOther(kwsBileBomb); - - // Alien abilities - UTIL_PrecacheOtherWeapon(kwsLeap); - UTIL_PrecacheOtherWeapon(kwsCharge); - - // Alien buildings - UTIL_PrecacheOther(kwsAlienResourceTower); - UTIL_PrecacheOther(kwsOffenseChamber); - UTIL_PrecacheOther(kwsDefenseChamber); - UTIL_PrecacheOther(kwsSensoryChamber); - UTIL_PrecacheOther(kwsMovementChamber); - UTIL_PrecacheOther(kesTeamWebStrand); - - // Equipment - //UTIL_PrecacheOtherWeapon("weapon_tripmine"); - UTIL_PrecacheOther(kwsScan); - UTIL_PrecacheOther(kwsPhaseGate); - //UTIL_PrecacheOther(kwsNuke); - - // Marine buildings - UTIL_PrecacheOther(kwsTeamCommand); - UTIL_PrecacheOther(kwsResourceTower); - UTIL_PrecacheOther(kwsInfantryPortal); - UTIL_PrecacheOther(kwsTurretFactory); - UTIL_PrecacheOther(kwsArmory); - UTIL_PrecacheOther(kwsAdvancedArmory); - UTIL_PrecacheOther(kwsArmsLab); - UTIL_PrecacheOther(kwsPrototypeLab); - UTIL_PrecacheOther(kwsObservatory); - //UTIL_PrecacheOther(kwsChemlab); - //UTIL_PrecacheOther(kwsMedlab); - //UTIL_PrecacheOther(kwsNukePlant); - UTIL_PrecacheOther(kwsDeployedTurret); - UTIL_PrecacheOther(kwsSiegeTurret); - - // container for dropped deathmatch weapons - UTIL_PrecacheOther("weaponbox"); - - UTIL_PrecacheOtherWeapon(kwsWelder); - UTIL_PrecacheOther(kwsDeployedMine); - UTIL_PrecacheOther(kwsHealth); - UTIL_PrecacheOther(kwsCatalyst); - UTIL_PrecacheOther(kwsGenericAmmo); - UTIL_PrecacheOther(kwsHeavyArmor); - UTIL_PrecacheOther(kwsJetpack); - UTIL_PrecacheOther(kwsAmmoPack); - - UTIL_PrecacheOther(kwsDebugEntity); - - // Precache other events - gJetpackEventID = PRECACHE_EVENT(1, kJetpackEvent); - //gStartOverwatchEventID = PRECACHE_EVENT(1, kStartOverwatchEvent); - //gEndOverwatchEventID = PRECACHE_EVENT(1, kEndOverwatchEvent); - - // Alien upgrade events - gRegenerationEventID = PRECACHE_EVENT(1, kRegenerationEvent); - gStartCloakEventID = PRECACHE_EVENT(1, kStartCloakEvent); - gEndCloakEventID = PRECACHE_EVENT(1, kEndCloakEvent); - - // Extra alien weapon events - //gEnsnareHitEventID = PRECACHE_EVENT(1, kEnsnareHitEventName); - gSporeCloudEventID = PRECACHE_EVENT(1, kSporeCloudEventName); - gUmbraCloudEventID = PRECACHE_EVENT(1, kUmbraCloudEventName); - gStopScreamEventID = PRECACHE_EVENT(1, kStopPrimalScreamSoundEvent); - - // Extra marine events - gTeleportEventID = PRECACHE_EVENT(1, kTeleportEvent); - gBlinkEffectSuccessEventID = PRECACHE_EVENT(1, kBlinkEffectSuccessEventName); - gPhaseInEventID = PRECACHE_EVENT(1, kPhaseInEvent); - gSiegeHitEventID = PRECACHE_EVENT(1, kSiegeHitEvent); - gSiegeViewHitEventID = PRECACHE_EVENT(1, kSiegeViewHitEvent); - gCommanderPointsAwardedEventID = PRECACHE_EVENT(1, kCommanderPointsAwardedEvent); - gAlienSightOnEventID = PRECACHE_EVENT(1, kAlienSightOnEvent); - gAlienSightOffEventID = PRECACHE_EVENT(1, kAlienSightOffEvent); -// gParalysisStartEventID = PRECACHE_EVENT(1, kParalysisStartEventName); - - //gWallJumpEventID = PRECACHE_EVENT(1, kWallJumpEvent); - //gFlightEventID = PRECACHE_EVENT(1, kFlightEvent); - PRECACHE_UNMODIFIED_SOUND(kConnectSound); - //PRECACHE_UNMODIFIED_SOUND(kDisconnectSound); - PRECACHE_UNMODIFIED_MODEL(kNullModel); - - UTIL_PrecacheOther("monster_sentry"); - - // Allow welder events in mapper build - gWelderEventID = PRECACHE_EVENT(1, kWelderEventName); - gWelderConstEventID = PRECACHE_EVENT(1, kWelderConstEventName); - PRECACHE_EVENT(1, kWelderStartEventName); - PRECACHE_EVENT(1, kWelderEndEventName); - - gEmptySoundEventID = PRECACHE_EVENT(1, kEmptySoundEvent); - gNumericalInfoEventID = PRECACHE_EVENT(1, kNumericalInfoEvent); - gInvalidActionEventID = PRECACHE_EVENT(1, kInvalidActionEvent); - gParticleEventID = PRECACHE_EVENT(1, kParticleEvent); - gDistressBeaconEventID = PRECACHE_EVENT(1, kDistressBeaconEvent); - gWeaponAnimationEventID= PRECACHE_EVENT(1, kWeaponAnimationEvent); - gLevelUpEventID = PRECACHE_EVENT(1, kLevelUpEvent); - gMetabolizeSuccessEventID = PRECACHE_EVENT(1, kMetabolizeSuccessEventName); - - PRECACHE_UNMODIFIED_SOUND(kPhaseInSound); - - // Precache reload sound that is hardcoded deep in HL - PRECACHE_UNMODIFIED_SOUND(kEmptySound); - PRECACHE_UNMODIFIED_SOUND(kInvalidSound); - - // Not sure who's using these, but I keep getting errors that they're not precached. Buttons? - PRECACHE_UNMODIFIED_SOUND("buttons/spark1.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark2.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark3.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark4.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark5.wav"); - PRECACHE_UNMODIFIED_SOUND("buttons/spark6.wav"); - - // For grunts. Careful, this uses the same weapon id that the grenade gun uses - //UTIL_PrecacheOtherWeapon("weapon_9mmAR"); - - // common world objects -// UTIL_PrecacheOther( "item_suit" ); -// UTIL_PrecacheOther( "item_battery" ); -// UTIL_PrecacheOther( "item_antidote" ); -// UTIL_PrecacheOther( "item_security" ); -// UTIL_PrecacheOther( "item_longjump" ); - - // shotgun -// UTIL_PrecacheOtherWeapon( "weapon_shotgun" ); -// UTIL_PrecacheOther( "ammo_buckshot" ); -// -// // crowbar -// UTIL_PrecacheOtherWeapon( "weapon_rowbar" ); -// -// // glock -// UTIL_PrecacheOtherWeapon( "weapon_9mmhandgun" ); -// UTIL_PrecacheOther( "ammo_9mmclip" ); -// -// // mp5 -// UTIL_PrecacheOtherWeapon( "weapon_9mmAR" ); -// UTIL_PrecacheOther( "ammo_9mmAR" ); -// UTIL_PrecacheOther( "ammo_ARgrenades" ); - -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // python -// UTIL_PrecacheOtherWeapon( "weapon_357" ); -// UTIL_PrecacheOther( "ammo_357" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // gauss -// UTIL_PrecacheOtherWeapon( "weapon_gauss" ); -// UTIL_PrecacheOther( "ammo_gaussclip" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // rpg -// UTIL_PrecacheOtherWeapon( "weapon_rpg" ); -// UTIL_PrecacheOther( "ammo_rpgclip" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // crossbow -// UTIL_PrecacheOtherWeapon( "weapon_crossbow" ); -// UTIL_PrecacheOther( "ammo_crossbow" ); -// UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // egon -// UTIL_PrecacheOtherWeapon( "weapon_egon" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // satchel charge -// UTIL_PrecacheOtherWeapon( "weapon_satchel" ); -//#endif -// -// // hand grenade -// UTIL_PrecacheOtherWeapon("weapon_handgrenade"); -// -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // squeak grenade -// UTIL_PrecacheOtherWeapon( "weapon_snark" ); -//#endif -// -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// // hornetgun -// UTIL_PrecacheOtherWeapon( "weapon_hornetgun" ); -//#endif - - -//#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) -// if ( g_pGameRules->IsDeathmatch() ) -// { -// UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons -// } -//#endif - - g_sModelIndexFireball = PRECACHE_UNMODIFIED_MODEL ("sprites/zerogxplode.spr");// fireball - g_sModelIndexWExplosion = PRECACHE_UNMODIFIED_MODEL ("sprites/WXplo1.spr");// underwater fireball - g_sModelIndexSmoke = PRECACHE_UNMODIFIED_MODEL ("sprites/steam1.spr");// smoke - g_sModelIndexBubbles = PRECACHE_UNMODIFIED_MODEL ("sprites/bubble2.spr");//bubbles - g_sModelIndexBloodSpray = PRECACHE_UNMODIFIED_MODEL ("sprites/bloodspray.spr"); // initial blood - g_sModelIndexBloodDrop = PRECACHE_UNMODIFIED_MODEL ("sprites/blood.spr"); // splattered blood - - g_sModelIndexLaser = PRECACHE_UNMODIFIED_MODEL( (char *)g_pModelNameLaser ); - g_sModelIndexLaserDot = PRECACHE_UNMODIFIED_MODEL("sprites/laserdot.spr"); - - - // used by explosions - PRECACHE_UNMODIFIED_MODEL ("models/grenade.mdl"); - PRECACHE_UNMODIFIED_MODEL ("sprites/explode1.spr"); - - PRECACHE_SOUND ("weapons/debris1.wav");// explosion aftermaths - PRECACHE_SOUND ("weapons/debris2.wav");// explosion aftermaths - PRECACHE_SOUND ("weapons/debris3.wav");// explosion aftermaths - - PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound1); - PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound2); - PRECACHE_UNMODIFIED_SOUND (kGrenadeBounceSound3); - PRECACHE_UNMODIFIED_SOUND (kGRHitSound); - - PRECACHE_UNMODIFIED_SOUND ("weapons/bullet_hit1.wav"); // hit by bullet - PRECACHE_UNMODIFIED_SOUND ("weapons/bullet_hit2.wav"); // hit by bullet - - PRECACHE_UNMODIFIED_SOUND ("items/weapondrop1.wav");// weapon falls to the ground - -} - - - - -TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlayerItem, m_pPlayer, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerItem, m_pNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerItem, m_iId, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ); - - -TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_iPrimaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iSecondaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iClip, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ); - - -void CBasePlayerItem :: SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-24, -24, 0); - pev->absmax = pev->origin + Vector(24, 24, 16); -} - -BOOL -CBasePlayerItem::CanDeploy( void ) -{ - return TRUE; -} - -// can this weapon be put away right now? -BOOL CBasePlayerItem::CanHolster( void ) -{ - return TRUE; -}; - -// returns is deploy was successful -BOOL CBasePlayerItem::Deploy( ) -{ - return TRUE; -} - -BOOL -CBasePlayerItem::IsUseable( void ) -{ - return TRUE; -} - - -//========================================================= -// Sets up movetype, size, solidtype for a new weapon. -//========================================================= -void CBasePlayerItem :: FallInit( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_BBOX; - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) );//pointsize until it lands on the ground. - - SetTouch(&CBasePlayerItem::DefaultTouch ); - SetThink(&CBasePlayerItem::FallThink ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -//========================================================= -// FallThink - Items that have just spawned run this think -// to catch them when they hit the ground. Once we're sure -// that the object is grounded, we change its solid type -// to trigger and set it in a large box that helps the -// player get it. -//========================================================= -void CBasePlayerItem::FallThink ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( pev->flags & FL_ONGROUND ) - { - // clatter if we have an owner (i.e., dropped by someone) - // don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!) - if ( !FNullEnt( pev->owner ) ) - { - int pitch = 95 + RANDOM_LONG(0,29); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "items/weapondrop1.wav", 1, ATTN_NORM, 0, pitch); - } - - // lie flat - pev->angles.x = 0; - pev->angles.z = 0; - - Materialize(); - } -} - -//========================================================= -// Materialize - make a CBasePlayerItem visible and tangible -//========================================================= -void CBasePlayerItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - pev->solid = SOLID_TRIGGER; - - UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch (&CBasePlayerItem::DefaultTouch); - SetThink (NULL); - - this->VirtualMaterialize(); -} - -//========================================================= -// AttemptToMaterialize - the item is trying to rematerialize, -// should it do so now or wait longer? -//========================================================= -void CBasePlayerItem::AttemptToMaterialize( void ) -{ - float time = g_pGameRules->FlWeaponTryRespawn( this ); - - if ( time == 0 ) - { - Materialize(); - return; - } - - pev->nextthink = gpGlobals->time + time; -} - -//========================================================= -// CheckRespawn - a player is taking this weapon, should -// it respawn? -//========================================================= -void CBasePlayerItem :: CheckRespawn ( void ) -{ - switch ( g_pGameRules->WeaponShouldRespawn( this ) ) - { - case GR_WEAPON_RESPAWN_YES: - Respawn(); - break; - case GR_WEAPON_RESPAWN_NO: - return; - break; - } -} - -//========================================================= -// Respawn- this item is already in the world, but it is -// invisible and intangible. Make it visible and tangible. -//========================================================= -CBaseEntity* CBasePlayerItem::Respawn( void ) -{ - // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code - // will decide when to make the weapon visible and touchable. - CBaseEntity *pNewWeapon = CBaseEntity::Create( (char *)STRING( pev->classname ), g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); - - if ( pNewWeapon ) - { - pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now - pNewWeapon->SetTouch( NULL );// no touch - pNewWeapon->SetThink(&CBasePlayerItem::AttemptToMaterialize ); - - DROP_TO_FLOOR ( ENT(pev) ); - - // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement, - // but when it should respawn is based on conditions belonging to the weapon that was taken. - pNewWeapon->pev->nextthink = g_pGameRules->FlWeaponRespawnTime( this ); - } - else - { - ALERT ( at_console, "Respawn failed to create %s!\n", STRING( pev->classname ) ); - } - - return pNewWeapon; -} - -void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) - return; - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // can I have this? - if ( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) - { - if ( gEvilImpulse101 ) - { - UTIL_Remove( this ); - } - return; - } - - if (pOther->AddPlayerItem( this )) - { - AttachToPlayer( pPlayer ); - - AvHPlayer* thePlayer = dynamic_cast(pPlayer); - if(thePlayer && thePlayer->GetIsAlien()) - { - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2-a.wav", 1, ATTN_NORM); - } - else - { - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); - } - } - - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? -} - -BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) -{ - if ( !isPredicted ) - { - return ( attack_time <= curtime ) ? TRUE : FALSE; - } - else - { - return ( attack_time <= 0.0 ) ? TRUE : FALSE; - } -} - - -void CBasePlayerWeapon::ItemPostFrame( void ) -{ - bool theAttackPressed = (m_pPlayer->pev->button & IN_ATTACK) && !(m_pPlayer->pev->button & IN_ATTACK2); - - bool theWeaponPrimes = (this->GetWeaponPrimeTime() > 0.0f); - bool theWeaponIsPriming = this->GetIsWeaponPriming(); - bool theWeaponIsPrimed = this->GetIsWeaponPrimed(); - - if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) - { - // complete the reload. - int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - // Add them to the clip - m_iClip += j; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; - - m_pPlayer->TabulateAmmo(); - - m_fInReload = FALSE; - } - -/* // +movement: Removed case for +attack2 since it's used for movement abilities - if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - - if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) - { - m_fFireOnEmpty = TRUE; - } - - m_pPlayer->TabulateAmmo(); - SecondaryAttack(); - m_pPlayer->pev->button &= ~IN_ATTACK2; - } - } - else -*/ - if ( theAttackPressed && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) - { - m_fFireOnEmpty = TRUE; - } - - m_pPlayer->TabulateAmmo(); - PrimaryAttack(); - } - } - else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - // reload when reload is pressed, or if no buttons are down and weapon is empty. - Reload(); - } - } - // +movement: Removed case for +attack2 - else if ( !(m_pPlayer->pev->button & (IN_ATTACK /* |IN_ATTACK2 */) ) ) - { - if (m_pPlayer->GetCanUseWeapon()) - { - - // no fire buttons down - - m_fFireOnEmpty = FALSE; - - if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) - { - // weapon isn't useable, switch. - if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) - { - m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; - return; - } - } - else - { - // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) - { - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) - { - Reload(); - return; - } - } - } - - WeaponIdle( ); - } - return; - } - - // catch all - if ( ShouldWeaponIdle() ) - { - WeaponIdle(); - } -} - -void CBasePlayerItem::DestroyItem( void ) -{ - //KGP: this is a virtual function call for a reason... - // it had been replaced with the contents of - // CBasePlayerItem::VirtualDestroyItem, ignoring - // AvHBasePlayerWeapon::VirtualDestroyItem in 3.01 - this->VirtualDestroyItem(); -} - -void CBasePlayerItem::VirtualDestroyItem( void ) -{ - if ( m_pPlayer ) - { - // if attached to a player, remove. - m_pPlayer->RemovePlayerItem( this ); - } - - Kill( ); -} - -int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) -{ - m_pPlayer = pPlayer; - pPlayer->m_iHideHUD &= ~HIDEHUD_WEAPONS; - return TRUE; -} - -void CBasePlayerItem::Drop( void ) -{ - SetTouch( NULL ); - SetThink(&CBasePlayerItem::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Kill( void ) -{ - SetTouch( NULL ); - SetThink(&CBasePlayerItem::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->pev->viewmodel = 0; - m_pPlayer->pev->weaponmodel = 0; -} - -void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) -{ - pev->movetype = MOVETYPE_FOLLOW; - pev->solid = SOLID_NOT; - pev->aiment = pPlayer->edict(); - pev->effects = EF_NODRAW; // ?? - pev->modelindex = 0;// server won't send down to clients if modelindex == 0 - pev->model = iStringNull; - pev->owner = pPlayer->edict(); - pev->nextthink = gpGlobals->time + .1; - SetTouch( NULL ); -} - -void CBasePlayerItem::Spawn() -{ - CBaseAnimating::Spawn(); -} - -// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal -int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) -{ - if ( m_iDefaultAmmo ) - { - return ExtractAmmo( (CBasePlayerWeapon *)pOriginal ); - } - else - { - // a dead player dropped this. - return ExtractClipAmmo( (CBasePlayerWeapon *)pOriginal ); - } -} - - -int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) -{ - int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - - pPlayer->pev->weapons |= (1<GetAmmoIndex( pszAmmo1() ); - m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); - } - - - if (bResult) - return AddWeapon( ); - return FALSE; -} - -int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) -{ - BOOL bSend = FALSE; - int state = 0; - - // KGP: folded m_iEnabled into the state value and converted it to a proper bitfield. - if( pPlayer->m_pActiveItem == this ) - { state |= WEAPON_IS_CURRENT; } - if( pPlayer->m_fOnTarget ) - { state |= WEAPON_ON_TARGET; } - if( m_iEnabled ) - { state |= WEAPON_IS_ENABLED; } - - // Forcing send of all data! - if ( !pPlayer->m_fWeapon ) - { - bSend = TRUE; - } - - // This is the current or last weapon, so the state will need to be updated - if ( this == pPlayer->m_pActiveItem || - this == pPlayer->m_pClientActiveItem ) - { - if ( pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem ) - { - bSend = TRUE; - } - } - - // If the ammo, state, or fov has changed, update the weapon - if ( m_iClip != m_iClientClip || - state != m_iClientWeaponState || - pPlayer->m_iFOV != pPlayer->m_iClientFOV ) - { - bSend = TRUE; - } - - if (m_iId == 22 || m_iId == 11 || m_iId == 21) - gCanMove[pPlayer->entindex() - 1] = m_iEnabled; - - if ( bSend ) - { - NetMsg_CurWeapon( pPlayer->pev, state, m_iId, m_iClip ); - m_iClientClip = m_iClip; - m_iClientWeaponState = state; - pPlayer->m_fWeapon = TRUE; - } - - if ( m_pNext ) - m_pNext->UpdateClientData( pPlayer ); - - return 1; -} - -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) -{ - if(iAnim >= 0) - { - if ( UseDecrement() ) - skiplocal = 1; - else - skiplocal = 0; - - m_pPlayer->pev->weaponanim = iAnim; - - if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) - return; - - MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); - WRITE_BYTE( iAnim ); // sequence number - WRITE_BYTE( pev->body ); // weaponmodel bodygroup. - MESSAGE_END(); - } -} - -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) -{ - int iIdAmmo; - - if (iMaxClip < 1) - { - m_iClip = -1; - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - else if (m_iClip == 0) - { - int i; - i = min( m_iClip + iCount, iMaxClip ) - m_iClip; - m_iClip += i; - iIdAmmo = m_pPlayer->GiveAmmo( iCount - i, szName, iMaxCarry ); - } - else - { - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - - // m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing - - if (iIdAmmo > 0) - { - m_iPrimaryAmmoType = iIdAmmo; - if (m_pPlayer->HasPlayerItem( this ) ) - { - // play the "got ammo" sound only if we gave some ammo to a player that already had this gun. - // if the player is just getting this gun for the first time, DefaultTouch will play the "picked up gun" sound for us. - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - } - - return iIdAmmo > 0 ? TRUE : FALSE; -} - - -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) -{ - int iIdAmmo; - - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMax ); - - //m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = iMax; // hack for testing - - if (iIdAmmo > 0) - { - m_iSecondaryAmmoType = iIdAmmo; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return iIdAmmo > 0 ? TRUE : FALSE; -} - -//========================================================= -// IsUseable - this function determines whether or not a -// weapon is useable by the player in its current state. -// (does it have ammo loaded? do I have any ammo for the -// weapon?, etc) -//========================================================= -BOOL CBasePlayerWeapon :: IsUseable( void ) -{ - if ( m_iClip <= 0 ) - { - // This looks like a nasty bug Valve didn't notice - ASSERT(PrimaryAmmoIndex() >= 0); - - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 ) - { - // clip is empty (or nonexistant) and the player has no more ammo of this type. - return FALSE; - } - } - - return TRUE; -} - -BOOL CBasePlayerWeapon :: CanDeploy( void ) -{ - BOOL bHasAmmo = 0; - - // All weapons can always deploy. Once fire is hit, it checks if it's out of ammo. If so, the weapon switches. - // This is needed so ammo packs function correctly, and it also feels more responsive. - -// if ( !pszAmmo1() ) -// { -// // this weapon doesn't use ammo, can always deploy. -// return TRUE; -// } -// -// if ( pszAmmo1() ) -// { -// bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); -// } -// if ( pszAmmo2() ) -// { -// bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); -// } -// if (m_iClip > 0) -// { -// bHasAmmo |= 1; -// } -// if (!bHasAmmo) -// { -// return FALSE; -// } - - return TRUE; -} - -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body) -{ - if (!CanDeploy( )) - return FALSE; - - m_pPlayer->TabulateAmmo(); - m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); - m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); - strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); - SendWeaponAnim( iAnim, skiplocal, body ); - - // Set the player animation as well - //this->m_pPlayer->SetAnimation(PLAYER_ANIM(iAnim)); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + this->GetDeployTime(); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + this->GetDeployTime() + kDeployIdleInterval; - - return TRUE; -} - - -BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - return FALSE; - - int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - if (j == 0) - return FALSE; - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; - - //!!UNDONE -- reload sound goes here !!! - //SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); - - m_fInReload = TRUE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kDeployIdleInterval; - - return TRUE; -} - -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) -{ - if (m_iPlayEmptySound) - { -// EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - - int flags = FEV_NOTHOST; - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), gEmptySoundEventID, 0.0, (float *)&(m_pPlayer->pev->origin), (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - m_iPlayEmptySound = 0; - return 0; - } - return 0; -} - -void CBasePlayerWeapon :: ResetEmptySound( void ) -{ - m_iPlayEmptySound = 1; -} - -//========================================================= -//========================================================= -int CBasePlayerWeapon::PrimaryAmmoIndex( void ) -{ - return m_iPrimaryAmmoType; -} - -//========================================================= -//========================================================= -int CBasePlayerWeapon::SecondaryAmmoIndex( void ) -{ - return -1; -} - -void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE; // cancel any reload in progress. - m_pPlayer->pev->viewmodel = 0; - m_pPlayer->pev->weaponmodel = 0; -} - -void CBasePlayerAmmo::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch(&CBasePlayerAmmo::DefaultTouch ); -} - -CBaseEntity* CBasePlayerAmmo::Respawn( void ) -{ - pev->effects |= EF_NODRAW; - SetTouch( NULL ); - - UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. - - SetThink(&CBasePlayerAmmo::Materialize ); - pev->nextthink = g_pGameRules->FlAmmoRespawnTime( this ); - - return this; -} - -void CBasePlayerAmmo::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - SetTouch(&CBasePlayerAmmo::DefaultTouch ); -} - -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - { - return; - } - - if (AddAmmo( pOther )) - { - if ( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) - { - Respawn(); - } - else - { - SetTouch( NULL ); - SetThink(&CBasePlayerAmmo::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } - } - else if (gEvilImpulse101) - { - // evil impulse 101 hack, kill always - SetTouch( NULL ); - SetThink(&CBasePlayerAmmo::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } -} - -//========================================================= -// called by the new item with the existing item as parameter -// -// if we call ExtractAmmo(), it's because the player is picking up this type of weapon for -// the first time. If it is spawned by the world, m_iDefaultAmmo will have a default ammo amount in it. -// if this is a weapon dropped by a dying player, has 0 m_iDefaultAmmo, which means only the ammo in -// the weapon clip comes along. -//========================================================= -int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iReturn; - - if ( pszAmmo1() != NULL ) - { - // blindly call with m_iDefaultAmmo. It's either going to be a value or zero. If it is zero, - // we only get the ammo in the weapon's clip, which is what we want. - iReturn = pWeapon->AddPrimaryAmmo( m_iDefaultAmmo, (char *)pszAmmo1(), iMaxClip(), iMaxAmmo1() ); - m_iDefaultAmmo = 0; - } - - if ( pszAmmo2() != NULL ) - { - iReturn = pWeapon->AddSecondaryAmmo( 0, (char *)pszAmmo2(), iMaxAmmo2() ); - } - - return iReturn; -} - -//========================================================= -// called by the new item's class with the existing item as parameter -//========================================================= -int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iAmmo; - - if ( m_iClip == WEAPON_NOCLIP ) - { - iAmmo = 0;// guns with no clips always come empty if they are second-hand - } - else - { - iAmmo = m_iClip; - } - - return pWeapon->m_pPlayer->GiveAmmo( iAmmo, (char *)pszAmmo1(), iMaxAmmo1() ); // , &m_iPrimaryAmmoType -} - -//========================================================= -// RetireWeapon - no more ammo for this gun, put it away. -//========================================================= -void CBasePlayerWeapon::RetireWeapon( void ) -{ - // first, no viewmodel at all. - m_pPlayer->pev->viewmodel = iStringNull; - m_pPlayer->pev->weaponmodel = iStringNull; - //m_pPlayer->pev->viewmodelindex = NULL; - - g_pGameRules->GetNextBestWeapon( m_pPlayer, this ); -} - -//********************************************************* -// weaponbox code: -//********************************************************* - -LINK_ENTITY_TO_CLASS( weaponbox, CWeaponBox ); - -TYPEDESCRIPTION CWeaponBox::m_SaveData[] = -{ - DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ); - -//========================================================= -// -//========================================================= -void CWeaponBox::Precache( void ) -{ - PRECACHE_UNMODIFIED_MODEL("models/w_weaponbox.mdl"); -} - -//========================================================= -//========================================================= -void CWeaponBox :: KeyValue( KeyValueData *pkvd ) -{ - if ( m_cAmmoTypes < MAX_AMMO_SLOTS ) - { - PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) ); - m_cAmmoTypes++;// count this new ammo type. - - pkvd->fHandled = TRUE; - } - else - { - ALERT ( at_console, "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS ); - } -} - -//========================================================= -// CWeaponBox - Spawn -//========================================================= -void CWeaponBox::Spawn( void ) -{ - Precache( ); - - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - - SET_MODEL( ENT(pev), "models/w_weaponbox.mdl"); -} - -//========================================================= -// CWeaponBox - Kill - the think function that removes the -// box from the world. -//========================================================= -void CWeaponBox::Kill( void ) -{ - CBasePlayerItem *pWeapon; - int i; - - // destroy the weapons - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - pWeapon->SetThink(&CWeaponBox::SUB_Remove); - pWeapon->pev->nextthink = gpGlobals->time + 0.1; - pWeapon = pWeapon->m_pNext; - } - } - - // remove the box - UTIL_Remove( this ); -} - -//========================================================= -// CWeaponBox - Touch: try to add my contents to the toucher -// if the toucher is a player. -//========================================================= -void CWeaponBox::Touch( CBaseEntity *pOther ) -{ - if ( !(pev->flags & FL_ONGROUND ) ) - { - return; - } - - if ( !pOther->IsPlayer() ) - { - // only players may touch a weaponbox. - return; - } - - if ( !pOther->IsAlive() ) - { - // no dead guys. - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - int i; - -// dole out ammo - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // there's some ammo of this type. - pPlayer->GiveAmmo( m_rgAmmo[ i ], (char *)STRING( m_rgiszAmmo[ i ] ), MaxAmmoCarry( m_rgiszAmmo[ i ] ) ); - - //ALERT ( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING(m_rgiszAmmo[i]) ); - - // now empty the ammo from the weaponbox since we just gave it to the player - m_rgiszAmmo[ i ] = iStringNull; - m_rgAmmo[ i ] = 0; - } - } - -// go through my weapons and try to give the usable ones to the player. -// it's important the the player be given ammo first, so the weapons code doesn't refuse -// to deploy a better weapon that the player may pick up because he has no ammo for it. - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerItem *pItem; - - // have at least one weapon in this slot - while ( m_rgpPlayerItems[ i ] ) - { - //ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) ); - - pItem = m_rgpPlayerItems[ i ]; - m_rgpPlayerItems[ i ] = m_rgpPlayerItems[ i ]->m_pNext;// unlink this weapon from the box - - if ( pPlayer->AddPlayerItem( pItem ) ) - { - pItem->AttachToPlayer( pPlayer ); - } - } - } - } - - EMIT_SOUND( pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - SetTouch(NULL); - UTIL_Remove(this); -} - -//========================================================= -// CWeaponBox - PackWeapon: Add this weapon to the box -//========================================================= -BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) -{ - // is one of these weapons already packed in this box? - if ( HasWeapon( pWeapon ) ) - { - return FALSE;// box can only hold one of each weapon type - } - - if ( pWeapon->m_pPlayer ) - { - if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) - { - // failed to unhook the weapon from the player! - return FALSE; - } - } - - int iWeaponSlot = pWeapon->iItemSlot(); - - if ( m_rgpPlayerItems[ iWeaponSlot ] ) - { - // there's already one weapon in this slot, so link this into the slot's column - pWeapon->m_pNext = m_rgpPlayerItems[ iWeaponSlot ]; - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - } - else - { - // first weapon we have for this slot - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - pWeapon->m_pNext = NULL; - } - - pWeapon->pev->spawnflags |= SF_NORESPAWN;// never respawn - pWeapon->pev->movetype = MOVETYPE_NONE; - pWeapon->pev->solid = SOLID_NOT; - pWeapon->pev->effects = EF_NODRAW; - pWeapon->pev->modelindex = 0; - pWeapon->pev->model = iStringNull; - pWeapon->pev->owner = edict(); - pWeapon->SetThink( NULL );// crowbar may be trying to swing again, etc. - pWeapon->SetTouch( NULL ); - pWeapon->m_pPlayer = NULL; - - //ALERT ( at_console, "packed %s\n", STRING(pWeapon->pev->classname) ); - - return TRUE; -} - -//========================================================= -// CWeaponBox - PackAmmo -//========================================================= -BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) -{ - int iMaxCarry; - - if ( FStringNull( iszName ) ) - { - // error here - ALERT ( at_console, "NULL String in PackAmmo!\n" ); - return FALSE; - } - - iMaxCarry = MaxAmmoCarry( iszName ); - - if ( iMaxCarry != -1 && iCount > 0 ) - { - //ALERT ( at_console, "Packed %d rounds of %s\n", iCount, STRING(iszName) ); - GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CWeaponBox - GiveAmmo -//========================================================= -int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NULL*/ ) -{ - int i; - - for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++) - { - if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0) - { - if (pIndex) - *pIndex = i; - - int iAdd = min( iCount, iMax - m_rgAmmo[i]); - if (iCount == 0 || iAdd > 0) - { - m_rgAmmo[i] += iAdd; - - return i; - } - return -1; - } - } - if (i < MAX_AMMO_SLOTS) - { - if (pIndex) - *pIndex = i; - - m_rgiszAmmo[i] = MAKE_STRING( szName ); - m_rgAmmo[i] = iCount; - - return i; - } - ALERT( at_console, "out of named ammo slots\n"); - return i; -} - -//========================================================= -// CWeaponBox::HasWeapon - is a weapon of this type already -// packed in this box? -//========================================================= -BOOL CWeaponBox::HasWeapon( CBasePlayerItem *pCheckItem ) -{ - CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// CWeaponBox::IsEmpty - is there anything in this box? -//========================================================= -BOOL CWeaponBox::IsEmpty( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return FALSE; - } - } - - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // still have a bit of this type of ammo - return FALSE; - } - } - - return TRUE; -} - -//========================================================= -//========================================================= -void CWeaponBox::SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-16, -16, 0); - pev->absmax = pev->origin + Vector(16, 16, 16); -} - - -void CBasePlayerWeapon::PrintState( void ) -{ - ALERT( at_console, "primary: %f\n", m_flNextPrimaryAttack ); - ALERT( at_console, "idle : %f\n", m_flTimeWeaponIdle ); - -// ALERT( at_console, "nextrl : %f\n", m_flNextReload ); -// ALERT( at_console, "nextpum: %f\n", m_flPumpTime ); - -// ALERT( at_console, "m_frt : %f\n", m_fReloadTime ); - ALERT( at_console, "m_finre: %i\n", m_fInReload ); -// ALERT( at_console, "m_finsr: %i\n", m_fInSpecialReload ); - - ALERT( at_console, "m_iclip: %i\n", m_iClip ); -} - - -TYPEDESCRIPTION CRpg::m_SaveData[] = -{ - DEFINE_FIELD( CRpg, m_fSpotActive, FIELD_INTEGER ), - DEFINE_FIELD( CRpg, m_cActiveRockets, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon ); - -TYPEDESCRIPTION CRpgRocket::m_SaveData[] = -{ - DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), - DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ); - -TYPEDESCRIPTION CShotgun::m_SaveData[] = -{ - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - DEFINE_FIELD( CShotgun, m_fInSpecialReload, FIELD_INTEGER ), - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - // DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ), - DEFINE_FIELD( CShotgun, m_flPumpTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CShotgun, CBasePlayerWeapon ); - -TYPEDESCRIPTION CGauss::m_SaveData[] = -{ - DEFINE_FIELD( CGauss, m_fInAttack, FIELD_INTEGER ), -// DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ), -// DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ), -// DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ), - DEFINE_FIELD( CGauss, m_fPrimaryFire, FIELD_BOOLEAN ), -}; -IMPLEMENT_SAVERESTORE( CGauss, CBasePlayerWeapon ); - -TYPEDESCRIPTION CEgon::m_SaveData[] = -{ -// DEFINE_FIELD( CEgon, m_pBeam, FIELD_CLASSPTR ), -// DEFINE_FIELD( CEgon, m_pNoise, FIELD_CLASSPTR ), -// DEFINE_FIELD( CEgon, m_pSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CEgon, m_shootTime, FIELD_TIME ), - DEFINE_FIELD( CEgon, m_fireState, FIELD_INTEGER ), - DEFINE_FIELD( CEgon, m_fireMode, FIELD_INTEGER ), - DEFINE_FIELD( CEgon, m_shakeTime, FIELD_TIME ), - DEFINE_FIELD( CEgon, m_flAmmoUseTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ); - -TYPEDESCRIPTION CSatchel::m_SaveData[] = -{ - DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ); - diff --git a/main/source/dlls/weapons.h b/main/source/dlls/weapons.h index 7963e955..8dd64dcb 100644 --- a/main/source/dlls/weapons.h +++ b/main/source/dlls/weapons.h @@ -1,996 +1,996 @@ -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// $Workfile: weapons.h $ -// $Date: 2002/10/24 21:18:58 $ -// -//------------------------------------------------------------------------------- -// $Log: weapons.h,v $ -// Revision 1.17 2002/10/24 21:18:58 Flayra -// - Made virtual so child weapons could customize reload -// -// Revision 1.16 2002/10/16 00:41:15 Flayra -// - Removed unneeds sounds and events -// - Added distress beacon event -// - Added general purpose particle event -// -// Revision 1.15 2002/08/31 18:01:18 Flayra -// - Work at VALVe -// -// Revision 1.14 2002/08/09 00:17:35 Flayra -// - Added PRIMARY_WEAPON flag (allow marines to hold only one) -// -// Revision 1.13 2002/07/08 16:36:35 Flayra -// - Added 0-degree constant, added document header -// -//=============================================================================== -#ifndef WEAPONS_H -#define WEAPONS_H - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "effects.h" -//#include "dlls/weapons.h" - -class CBasePlayer; - -void DeactivateSatchels( CBasePlayer *pOwner ); - -// Contact Grenade / Timed grenade / Satchel Charge -class CGrenade : public CBaseMonster -{ -public: - void Spawn( void ); - - typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE; - - static CGrenade *ShootExplosiveTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, int inDamageType ); - static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time); - static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); - - void Explode( Vector vecSrc, Vector vecAim ); - void Explode( TraceResult *pTrace, int bitsDamageType ); - void EXPORT Smoke( void ); - - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT SlideTouch( CBaseEntity *pOther ); - void EXPORT ExplosiveBounceTouch( CBaseEntity *pOther ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - void EXPORT DangerSoundThink( void ); - void EXPORT PreDetonate( void ); - void EXPORT Detonate( void ); - void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TumbleThink( void ); - - virtual void BounceSound( void ); - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void SetDamageType(int inDamageType); - - BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. -private: - int m_damageType; -}; - - -// constant items -#define ITEM_HEALTHKIT 1 -#define ITEM_ANTIDOTE 2 -#define ITEM_SECURITY 3 -#define ITEM_BATTERY 4 - -#define WEAPON_NONE 0 -#define WEAPON_CROWBAR 1 -#define WEAPON_GLOCK 2 -#define WEAPON_PYTHON 3 -#define WEAPON_MP5 4 -#define WEAPON_CHAINGUN 5 -#define WEAPON_CROSSBOW 6 -#define WEAPON_SHOTGUN 7 -#define WEAPON_RPG 8 -#define WEAPON_GAUSS 9 -#define WEAPON_EGON 10 -#define WEAPON_HORNETGUN 11 -#define WEAPON_HANDGRENADE 12 -#define WEAPON_TRIPMINE 13 -#define WEAPON_SATCHEL 14 -#define WEAPON_SNARK 15 - -#define WEAPON_ALLWEAPONS (~(1<absmin = pev->origin + Vector(-16, -16, -5); -// pev->absmax = pev->origin + Vector(16, 16, 28); -// } -// -// void PrimaryAttack( void ); -// BOOL Deploy( void ); -// void Holster( int skiplocal = 0 ); -// void WeaponIdle( void ); -// -// virtual BOOL UseDecrement( void ) -// { -// return TRUE; -// } -// -//private: -// unsigned short m_usTripFire; -// -//}; - -class CSqueak : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - void WeaponIdle( void ); - int m_fJustThrown; - - virtual BOOL UseDecrement( void ) - { - return TRUE; - } - -private: - unsigned short m_usSnarkFire; -}; - - -#endif // WEAPONS_H +// Copyright (c) 1999, Valve LLC. All rights reserved. +// +// This product contains software technology licensed from Id +// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +// All Rights Reserved. +// +// Use, distribution, and modification of this source code and/or resulting +// object code is restricted to non-commercial enhancements to products from +// Valve LLC. All other use, distribution, or modification is prohibited +// without written permission from Valve LLC. +// +// $Workfile: weapons.h $ +// $Date: 2002/10/24 21:18:58 $ +// +//------------------------------------------------------------------------------- +// $Log: weapons.h,v $ +// Revision 1.17 2002/10/24 21:18:58 Flayra +// - Made virtual so child weapons could customize reload +// +// Revision 1.16 2002/10/16 00:41:15 Flayra +// - Removed unneeds sounds and events +// - Added distress beacon event +// - Added general purpose particle event +// +// Revision 1.15 2002/08/31 18:01:18 Flayra +// - Work at VALVe +// +// Revision 1.14 2002/08/09 00:17:35 Flayra +// - Added PRIMARY_WEAPON flag (allow marines to hold only one) +// +// Revision 1.13 2002/07/08 16:36:35 Flayra +// - Added 0-degree constant, added document header +// +//=============================================================================== +#ifndef WEAPONS_H +#define WEAPONS_H + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "effects.h" +//#include "dlls/weapons.h" + +class CBasePlayer; + +void DeactivateSatchels( CBasePlayer *pOwner ); + +// Contact Grenade / Timed grenade / Satchel Charge +class CGrenade : public CBaseMonster +{ +public: + void Spawn( void ); + + typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE; + + static CGrenade *ShootExplosiveTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, int inDamageType ); + static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time); + static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); + + void Explode( Vector vecSrc, Vector vecAim ); + void Explode( TraceResult *pTrace, int bitsDamageType ); + void EXPORT Smoke( void ); + + void EXPORT BounceTouch( CBaseEntity *pOther ); + void EXPORT SlideTouch( CBaseEntity *pOther ); + void EXPORT ExplosiveBounceTouch( CBaseEntity *pOther ); + void EXPORT ExplodeTouch( CBaseEntity *pOther ); + void EXPORT DangerSoundThink( void ); + void EXPORT PreDetonate( void ); + void EXPORT Detonate( void ); + void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT TumbleThink( void ); + + virtual void BounceSound( void ); + virtual int BloodColor( void ) { return DONT_BLEED; } + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual void SetDamageType(int inDamageType); + + BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. +private: + int m_damageType; +}; + + +// constant items +#define ITEM_HEALTHKIT 1 +#define ITEM_ANTIDOTE 2 +#define ITEM_SECURITY 3 +#define ITEM_BATTERY 4 + +#define WEAPON_NONE 0 +#define WEAPON_CROWBAR 1 +#define WEAPON_GLOCK 2 +#define WEAPON_PYTHON 3 +#define WEAPON_MP5 4 +#define WEAPON_CHAINGUN 5 +#define WEAPON_CROSSBOW 6 +#define WEAPON_SHOTGUN 7 +#define WEAPON_RPG 8 +#define WEAPON_GAUSS 9 +#define WEAPON_EGON 10 +#define WEAPON_HORNETGUN 11 +#define WEAPON_HANDGRENADE 12 +#define WEAPON_TRIPMINE 13 +#define WEAPON_SATCHEL 14 +#define WEAPON_SNARK 15 + +#define WEAPON_ALLWEAPONS (~(1<absmin = pev->origin + Vector(-16, -16, -5); +// pev->absmax = pev->origin + Vector(16, 16, 28); +// } +// +// void PrimaryAttack( void ); +// BOOL Deploy( void ); +// void Holster( int skiplocal = 0 ); +// void WeaponIdle( void ); +// +// virtual BOOL UseDecrement( void ) +// { +// return TRUE; +// } +// +//private: +// unsigned short m_usTripFire; +// +//}; + +class CSqueak : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 5; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + void WeaponIdle( void ); + int m_fJustThrown; + + virtual BOOL UseDecrement( void ) + { + return TRUE; + } + +private: + unsigned short m_usSnarkFire; +}; + + +#endif // WEAPONS_H diff --git a/main/source/dlls/weapons.h~ b/main/source/dlls/weapons.h~ deleted file mode 100644 index b2f92ba4..00000000 --- a/main/source/dlls/weapons.h~ +++ /dev/null @@ -1,996 +0,0 @@ -// Copyright (c) 1999, Valve LLC. All rights reserved. -// -// This product contains software technology licensed from Id -// Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -// All Rights Reserved. -// -// Use, distribution, and modification of this source code and/or resulting -// object code is restricted to non-commercial enhancements to products from -// Valve LLC. All other use, distribution, or modification is prohibited -// without written permission from Valve LLC. -// -// $Workfile: weapons.h $ -// $Date: 2002/10/24 21:18:58 $ -// -//------------------------------------------------------------------------------- -// $Log: weapons.h,v $ -// Revision 1.17 2002/10/24 21:18:58 Flayra -// - Made virtual so child weapons could customize reload -// -// Revision 1.16 2002/10/16 00:41:15 Flayra -// - Removed unneeds sounds and events -// - Added distress beacon event -// - Added general purpose particle event -// -// Revision 1.15 2002/08/31 18:01:18 Flayra -// - Work at VALVe -// -// Revision 1.14 2002/08/09 00:17:35 Flayra -// - Added PRIMARY_WEAPON flag (allow marines to hold only one) -// -// Revision 1.13 2002/07/08 16:36:35 Flayra -// - Added 0-degree constant, added document header -// -//=============================================================================== -#ifndef WEAPONS_H -#define WEAPONS_H - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "effects.h" -//#include "dlls/weapons.h" - -class CBasePlayer; - -void DeactivateSatchels( CBasePlayer *pOwner ); - -// Contact Grenade / Timed grenade / Satchel Charge -class CGrenade : public CBaseMonster -{ -public: - void Spawn( void ); - - typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE; - - static CGrenade *ShootExplosiveTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, int inDamageType ); - static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time); - static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); - - void Explode( Vector vecSrc, Vector vecAim ); - void Explode( TraceResult *pTrace, int bitsDamageType ); - void EXPORT Smoke( void ); - - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT SlideTouch( CBaseEntity *pOther ); - void EXPORT ExplosiveBounceTouch( CBaseEntity *pOther ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - void EXPORT DangerSoundThink( void ); - void EXPORT PreDetonate( void ); - void EXPORT Detonate( void ); - void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TumbleThink( void ); - - virtual void BounceSound( void ); - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void SetDamageType(int inDamageType); - - BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. -private: - int m_damageType; -}; - - -// constant items -#define ITEM_HEALTHKIT 1 -#define ITEM_ANTIDOTE 2 -#define ITEM_SECURITY 3 -#define ITEM_BATTERY 4 - -#define WEAPON_NONE 0 -#define WEAPON_CROWBAR 1 -#define WEAPON_GLOCK 2 -#define WEAPON_PYTHON 3 -#define WEAPON_MP5 4 -#define WEAPON_CHAINGUN 5 -#define WEAPON_CROSSBOW 6 -#define WEAPON_SHOTGUN 7 -#define WEAPON_RPG 8 -#define WEAPON_GAUSS 9 -#define WEAPON_EGON 10 -#define WEAPON_HORNETGUN 11 -#define WEAPON_HANDGRENADE 12 -#define WEAPON_TRIPMINE 13 -#define WEAPON_SATCHEL 14 -#define WEAPON_SNARK 15 - -#define WEAPON_ALLWEAPONS (~(1<absmin = pev->origin + Vector(-16, -16, -5); -// pev->absmax = pev->origin + Vector(16, 16, 28); -// } -// -// void PrimaryAttack( void ); -// BOOL Deploy( void ); -// void Holster( int skiplocal = 0 ); -// void WeaponIdle( void ); -// -// virtual BOOL UseDecrement( void ) -// { -// return TRUE; -// } -// -//private: -// unsigned short m_usTripFire; -// -//}; - -class CSqueak : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - void WeaponIdle( void ); - int m_fJustThrown; - - virtual BOOL UseDecrement( void ) - { - return TRUE; - } - -private: - unsigned short m_usSnarkFire; -}; - - -#endif // WEAPONS_H diff --git a/main/source/dlls/world.cpp b/main/source/dlls/world.cpp index d62a14b7..a7d3ddce 100644 --- a/main/source/dlls/world.cpp +++ b/main/source/dlls/world.cpp @@ -1,784 +1,784 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== world.cpp ======================================================== - - precaches and defs for entities and other data that must always be available. - -*/ - -#include "../util/nowarnings.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "soundent.h" -#include "client.h" -#include "decals.h" -#include "skill.h" -#include "effects.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHServerVariables.h" -#include "pm_shared/pm_defs.h" - -extern CGraph WorldGraph; -extern CSoundEnt *pSoundEnt; - -DLL_GLOBAL edict_t *g_pBodyQueueHead; -CGlobalState gGlobalState; -extern DLL_GLOBAL int gDisplayTitle; -extern playermove_t* pmove; - -extern void W_Precache(void); - -// -// This must match the list in util.h -// -DLL_DECALLIST gDecals[] = { - { "{shot1", 0 }, // DECAL_GUNSHOT1 - { "{shot2", 0 }, // DECAL_GUNSHOT2 - { "{shot3",0 }, // DECAL_GUNSHOT3 - { "{shot4", 0 }, // DECAL_GUNSHOT4 - { "{shot5", 0 }, // DECAL_GUNSHOT5 - { "{lambda01", 0 }, // DECAL_LAMBDA1 - { "{lambda02", 0 }, // DECAL_LAMBDA2 - { "{lambda03", 0 }, // DECAL_LAMBDA3 - { "{lambda04", 0 }, // DECAL_LAMBDA4 - { "{lambda05", 0 }, // DECAL_LAMBDA5 - { "{lambda06", 0 }, // DECAL_LAMBDA6 - { "{scorch1", 0 }, // DECAL_SCORCH1 - { "{scorch2", 0 }, // DECAL_SCORCH2 - { "{blood1", 0 }, // DECAL_BLOOD1 - { "{blood2", 0 }, // DECAL_BLOOD2 - { "{blood3", 0 }, // DECAL_BLOOD3 - { "{blood4", 0 }, // DECAL_BLOOD4 - { "{blood5", 0 }, // DECAL_BLOOD5 - { "{blood6", 0 }, // DECAL_BLOOD6 - { "{yblood1", 0 }, // DECAL_YBLOOD1 - { "{yblood2", 0 }, // DECAL_YBLOOD2 - { "{yblood3", 0 }, // DECAL_YBLOOD3 - { "{yblood4", 0 }, // DECAL_YBLOOD4 - { "{yblood5", 0 }, // DECAL_YBLOOD5 - { "{yblood6", 0 }, // DECAL_YBLOOD6 - { "{break1", 0 }, // DECAL_GLASSBREAK1 - { "{break2", 0 }, // DECAL_GLASSBREAK2 - { "{break3", 0 }, // DECAL_GLASSBREAK3 - { "{bigshot1", 0 }, // DECAL_BIGSHOT1 - { "{bigshot2", 0 }, // DECAL_BIGSHOT2 - { "{bigshot3", 0 }, // DECAL_BIGSHOT3 - { "{bigshot4", 0 }, // DECAL_BIGSHOT4 - { "{bigshot5", 0 }, // DECAL_BIGSHOT5 - { "{spit1", 0 }, // DECAL_SPIT1 - { "{spit2", 0 }, // DECAL_SPIT2 - { "{bproof1", 0 }, // DECAL_BPROOF1 - { "{gargstomp", 0 }, // DECAL_GARGSTOMP1, // Gargantua stomp crack - { "{smscorch1", 0 }, // DECAL_SMALLSCORCH1, // Small scorch mark - { "{smscorch2", 0 }, // DECAL_SMALLSCORCH2, // Small scorch mark - { "{smscorch3", 0 }, // DECAL_SMALLSCORCH3, // Small scorch mark - { "{mommablob", 0 }, // DECAL_MOMMABIRTH // BM Birth spray - { "{mommablob", 0 }, // DECAL_MOMMASPLAT // BM Mortar spray?? need decal -}; - -/* -============================================================================== - -BODY QUE - -============================================================================== -*/ - -#define SF_DECAL_NOTINDEATHMATCH 2048 - -class CDecal : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT StaticDecal( void ); - void EXPORT TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( infodecal, CDecal ); - -// UNDONE: These won't get sent to joining players in multi-player -void CDecal :: Spawn( void ) -{ - if ( pev->skin < 0 || (gpGlobals->deathmatch && FBitSet( pev->spawnflags, SF_DECAL_NOTINDEATHMATCH )) ) - { - REMOVE_ENTITY(ENT(pev)); - return; - } - - if ( FStringNull ( pev->targetname ) ) - { - SetThink(&CDecal::StaticDecal ); - // if there's no targetname, the decal will spray itself on as soon as the world is done spawning. - pev->nextthink = gpGlobals->time; - } - else - { - // if there IS a targetname, the decal sprays itself on when it is triggered. - SetThink (&CDecal::SUB_DoNothing ); - SetUse(&CDecal::TriggerDecal); - } -} - -void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // this is set up as a USE function for infodecals that have targetnames, so that the - // decal doesn't get applied until it is fired. (usually by a scripted sequence) - TraceResult trace; - int entityIndex; - - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE( TE_BSPDECAL ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( (int)pev->skin ); - entityIndex = (short)ENTINDEX(trace.pHit); - WRITE_SHORT( entityIndex ); - if ( entityIndex ) - WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); - MESSAGE_END(); - - SetThink(&CDecal::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CDecal :: StaticDecal( void ) -{ - TraceResult trace; - int entityIndex, modelIndex; - - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - - entityIndex = (short)ENTINDEX(trace.pHit); - if ( entityIndex ) - modelIndex = (int)VARS(trace.pHit)->modelindex; - else - modelIndex = 0; - - g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); - - SUB_Remove(); -} - - -void CDecal :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->skin = DECAL_INDEX( pkvd->szValue ); - - // Found - if ( pev->skin >= 0 ) - return; - ALERT( at_console, "Can't find decal %s\n", pkvd->szValue ); - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// Body queue class here.... It's really just CBaseEntity -class CCorpse : public CBaseEntity -{ - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -LINK_ENTITY_TO_CLASS( bodyque, CCorpse ); - -static void InitBodyQue(void) -{ - string_t istrClassname = MAKE_STRING("bodyque"); - - g_pBodyQueueHead = CREATE_NAMED_ENTITY( istrClassname ); - entvars_t *pev = VARS(g_pBodyQueueHead); - - // Reserve 3 more slots for dead bodies - for ( int i = 0; i < 3; i++ ) - { - pev->owner = CREATE_NAMED_ENTITY( istrClassname ); - pev = VARS(pev->owner); - } - - pev->owner = g_pBodyQueueHead; -} - - -// -// make a body que entry for the given ent so the ent can be respawned elsewhere -// -// GLOBALS ASSUMED SET: g_eoBodyQueueHead -// -void CopyToBodyQue(entvars_t *pev) -{ - if (pev->effects & EF_NODRAW) - return; - - entvars_t *pevHead = VARS(g_pBodyQueueHead); - - pevHead->angles = pev->angles; - pevHead->model = pev->model; - pevHead->modelindex = pev->modelindex; - pevHead->frame = pev->frame; - pevHead->colormap = pev->colormap; - pevHead->movetype = MOVETYPE_TOSS; - pevHead->velocity = pev->velocity; - pevHead->flags = 0; - pevHead->deadflag = pev->deadflag; - pevHead->renderfx = kRenderFxDeadPlayer; - pevHead->renderamt = ENTINDEX( ENT( pev ) ); - - pevHead->effects = pev->effects | EF_NOINTERP; - //pevHead->goalstarttime = pev->goalstarttime; - //pevHead->goalframe = pev->goalframe; - //pevHead->goalendtime = pev->goalendtime ; - - pevHead->sequence = pev->sequence; - pevHead->animtime = pev->animtime; - - UTIL_SetOrigin(pevHead, pev->origin); - UTIL_SetSize(pevHead, pev->mins, pev->maxs); - g_pBodyQueueHead = pevHead->owner; -} - - -CGlobalState::CGlobalState( void ) -{ - Reset(); -} - -void CGlobalState::Reset( void ) -{ - m_pList = NULL; - m_listCount = 0; -} - -globalentity_t *CGlobalState :: Find( string_t globalname ) -{ - if ( !globalname ) - return NULL; - - globalentity_t *pTest; - const char *pEntityName = STRING(globalname); - - - pTest = m_pList; - while ( pTest ) - { - if ( FStrEq( pEntityName, pTest->name ) ) - break; - - pTest = pTest->pNext; - } - - return pTest; -} - - -// This is available all the time now on impulse 104, remove later -//#ifdef _DEBUG -void CGlobalState :: DumpGlobals( void ) -{ - static char *estates[] = { "Off", "On", "Dead" }; - globalentity_t *pTest; - - ALERT( at_console, "-- Globals --\n" ); - pTest = m_pList; - while ( pTest ) - { - ALERT( at_console, "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state] ); - pTest = pTest->pNext; - } -} -//#endif - - -void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) -{ - ASSERT( !Find(globalname) ); - - globalentity_t *pNewEntity = (globalentity_t *)calloc( sizeof( globalentity_t ), 1 ); - ASSERT( pNewEntity != NULL ); - pNewEntity->pNext = m_pList; - m_pList = pNewEntity; - strcpy( pNewEntity->name, STRING( globalname ) ); - strcpy( pNewEntity->levelName, STRING(mapName) ); - pNewEntity->state = state; - m_listCount++; -} - - -void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) -{ - globalentity_t *pEnt = Find( globalname ); - - if ( pEnt ) - pEnt->state = state; -} - - -const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - - return pEnt; -} - - -GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) - return pEnt->state; - - return GLOBAL_OFF; -} - - -// Global Savedata for Delay -TYPEDESCRIPTION CGlobalState::m_SaveData[] = -{ - DEFINE_FIELD( CGlobalState, m_listCount, FIELD_INTEGER ), -}; - -// Global Savedata for Delay -TYPEDESCRIPTION gGlobalEntitySaveData[] = -{ - DEFINE_ARRAY( globalentity_t, name, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( globalentity_t, levelName, FIELD_CHARACTER, 32 ), - DEFINE_FIELD( globalentity_t, state, FIELD_INTEGER ), -}; - -const char* CGlobalState::GetLevelName() -{ - return STRING(this->m_pList->levelName); -} - -int CGlobalState::Save( CSave &save ) -{ - int i; - globalentity_t *pEntity; - - if ( !save.WriteFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - pEntity = m_pList; - for ( i = 0; i < m_listCount && pEntity; i++ ) - { - if ( !save.WriteFields( "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - - pEntity = pEntity->pNext; - } - - return 1; -} - -int CGlobalState::Restore( CRestore &restore ) -{ - int i, listCount; - globalentity_t tmpEntity; - - - ClearStates(); - if ( !restore.ReadFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - listCount = m_listCount; // Get new list count - m_listCount = 0; // Clear loaded data - - for ( i = 0; i < listCount; i++ ) - { - if ( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - EntityAdd( MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state ); - } - return 1; -} - -void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) -{ - globalentity_t *pEnt = Find( globalname ); - - if ( pEnt ) - strcpy( pEnt->levelName, STRING(mapname) ); -} - - -void CGlobalState::ClearStates( void ) -{ - globalentity_t *pFree = m_pList; - while ( pFree ) - { - globalentity_t *pNext = pFree->pNext; - free( pFree ); - pFree = pNext; - } - Reset(); -} - - -void SaveGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CSave saveHelper( pSaveData ); - gGlobalState.Save( saveHelper ); -} - - -void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CRestore restoreHelper( pSaveData ); - gGlobalState.Restore( restoreHelper ); -} - - -void ResetGlobalState( void ) -{ - gGlobalState.ClearStates(); - gInitHUD = TRUE; // Init the HUD on a new game / load game -} - -// moved CWorld class definition to cbase.h -//======================= -// CWorld -// -// This spawns first when each level begins. -//======================= - -LINK_ENTITY_TO_CLASS( worldspawn, CWorld ); - -#define SF_WORLD_DARK 0x0001 // Fade from black at startup -#define SF_WORLD_TITLE 0x0002 // Display game title at startup -#define SF_WORLD_FORCETEAM 0x0004 // Force teams - -extern DLL_GLOBAL BOOL g_fGameOver; -float g_flWeaponCheat; - -void CWorld :: Spawn( void ) -{ - g_fGameOver = FALSE; - Precache( ); - g_flWeaponCheat = ns_cvar_float(avh_cheats ); // Is the impulse 101 command allowed? -} - -void CWorld :: Precache( void ) -{ -#if 1 - CVAR_SET_STRING("sv_gravity", "800"); // 67ft/sec - CVAR_SET_STRING("sv_stepsize", "18"); -#else - CVAR_SET_STRING("sv_gravity", "384"); // 32ft/sec - CVAR_SET_STRING("sv_stepsize", "24"); -#endif - - CVAR_SET_STRING("room_type", "0");// clear DSP - - // Set up game rules - if (g_pGameRules) - { - delete g_pGameRules; - - // This is needed because pmove is used by AvHSUGetIsEnoughRoomForHull, and if it isn't set to null, pmove->physents[0].worldmodel is the old map on a changelevel, and invalid - pmove = NULL; - } - - InstallGameRules( ); - GetGameRules()->PreWorldPrecacheReset(); - - //AvHGamerules* theGameRules = dynamic_cast(g_pGameRules); - - //static const char* sCurrentLevelName = NULL; - //const char* theLevelName = STRING(gpGlobals->mapname); - //bool theNewMap = false; - //if(!sCurrentLevelName || strcmp(theLevelName, sCurrentLevelName)) - //{ - // theNewMap = true; - //} - - // Reset game, but don't send need to send particles if same map (remove this distinction?) - //theGameRules->ResetGame(theNewMap); - //sCurrentLevelName = theLevelName; -// static bool theFirstTime = true; -// if(!theFirstTime) -// { -// theGameRules->ResetGame(true); -// } -// theFirstTime = false; - - //!!!UNDONE why is there so much Spawn code in the Precache function? I'll just keep it here - - ///!!!LATER - do we want a sound ent in deathmatch? (sjb) - //pSoundEnt = CBaseEntity::Create( "soundent", g_vecZero, g_vecZero, edict() ); - pSoundEnt = GetClassPtr( ( CSoundEnt *)NULL ); - pSoundEnt->Spawn(); - - if ( !pSoundEnt ) - { - ALERT ( at_console, "**COULD NOT CREATE SOUNDENT**\n" ); - } - - InitBodyQue(); - -// init sentence group playback stuff from sentences.txt. -// ok to call this multiple times, calls after first are ignored. - - SENTENCEG_Init(); - -// init texture type array from materials.txt - - TEXTURETYPE_Init(); - - -// the area based ambient sounds MUST be the first precache_sounds - -// player precaches - W_Precache (); // get weapon precaches - - ClientPrecache(); - -// sounds used from C physics code - PRECACHE_SOUND("common/null.wav"); // clears sound channels - - PRECACHE_SOUND( "items/suitchargeok1.wav" );//!!! temporary sound for respawning weapons. - PRECACHE_UNMODIFIED_SOUND( "items/gunpickup2.wav" ); // player picks up a gun. - PRECACHE_UNMODIFIED_SOUND( "items/gunpickup2-a.wav" ); // alien is equipped - - PRECACHE_SOUND( "common/bodydrop3.wav" );// dead bodies hitting the ground (animation events) - PRECACHE_SOUND( "common/bodydrop4.wav" ); - - g_Language = (int)CVAR_GET_FLOAT( "sv_language" ); - if ( g_Language == LANGUAGE_GERMAN ) - { - PRECACHE_UNMODIFIED_MODEL( "models/germangibs.mdl" ); - } - else - { - PRECACHE_UNMODIFIED_MODEL( "models/hgibs.mdl" ); - PRECACHE_UNMODIFIED_MODEL( "models/agibs.mdl" ); - } - - PRECACHE_UNMODIFIED_SOUND ("weapons/ric1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric2.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric3.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric4.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric5.wav"); - - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_conc-1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_conc-2.wav"); - - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_metal-1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_metal-2.wav"); - - // Precache alien ricochet sounds - PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric2.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric3.wav"); -// -// Setup light animation tables. 'a' is total darkness, 'z' is maxbright. -// - - // 0 normal - LIGHT_STYLE(0, "m"); - - // 1 FLICKER (first variety) - LIGHT_STYLE(1, "mmnmmommommnonmmonqnmmo"); - - // 2 SLOW STRONG PULSE - LIGHT_STYLE(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); - - // 3 CANDLE (first variety) - LIGHT_STYLE(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); - - // 4 FAST STROBE - LIGHT_STYLE(4, "mamamamamama"); - - // 5 GENTLE PULSE 1 - LIGHT_STYLE(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); - - // 6 FLICKER (second variety) - LIGHT_STYLE(6, "nmonqnmomnmomomno"); - - // 7 CANDLE (second variety) - LIGHT_STYLE(7, "mmmaaaabcdefgmmmmaaaammmaamm"); - - // 8 CANDLE (third variety) - LIGHT_STYLE(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); - - // 9 SLOW STROBE (fourth variety) - LIGHT_STYLE(9, "aaaaaaaazzzzzzzz"); - - // 10 FLUORESCENT FLICKER - LIGHT_STYLE(10, "mmamammmmammamamaaamammma"); - - // 11 SLOW PULSE NOT FADE TO BLACK - LIGHT_STYLE(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); - - // 12 UNDERWATER LIGHT MUTATION - // this light only distorts the lightmap - no contribution - // is made to the brightness of affected surfaces - LIGHT_STYLE(12, "mmnnmmnnnmmnn"); - - // styles 32-62 are assigned by the light program for switchable lights - - // 63 testing - LIGHT_STYLE(63, "a"); - - for ( int i = 0; i < ARRAYSIZE(gDecals); i++ ) - gDecals[i].index = DECAL_INDEX( gDecals[i].name ); - -// init the WorldGraph. - WorldGraph.InitGraph(); - -// make sure the .NOD file is newer than the .BSP file. - if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) ) - {// NOD file is not present, or is older than the BSP file. - WorldGraph.AllocNodes (); - } - else - {// Load the node graph for this level - if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) ) - {// couldn't load, so alloc and prepare to build a graph. - ALERT ( at_console, "*Error opening .NOD file\n" ); - WorldGraph.AllocNodes (); - } - else - { - ALERT ( at_console, "\n*Graph Loaded!\n" ); - } - } - - if ( pev->speed > 0 ) - CVAR_SET_FLOAT( "sv_zmax", pev->speed ); - else - CVAR_SET_FLOAT( "sv_zmax", 4096 ); - - if ( pev->netname ) - { - ALERT( at_aiconsole, "Chapter title: %s\n", STRING(pev->netname) ); - CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); - if ( pEntity ) - { - pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); - pEntity->pev->message = pev->netname; - pev->netname = 0; - pEntity->pev->nextthink = gpGlobals->time + 0.3; - pEntity->pev->spawnflags = SF_MESSAGE_ONCE; - } - } - - if ( pev->spawnflags & SF_WORLD_DARK ) - CVAR_SET_FLOAT( "v_dark", 1.0 ); - else - CVAR_SET_FLOAT( "v_dark", 0.0 ); - - if ( pev->spawnflags & SF_WORLD_TITLE ) - gDisplayTitle = TRUE; // display the game title if this key is set - else - gDisplayTitle = FALSE; - - if ( pev->spawnflags & SF_WORLD_FORCETEAM ) - { - CVAR_SET_FLOAT( "mp_defaultteam", 1 ); - } - else - { - CVAR_SET_FLOAT( "mp_defaultteam", 0 ); - } -} - - -// -// Just to ignore the "wad" field. -// -void CWorld :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "skyname") ) - { - // Sent over net now. - CVAR_SET_STRING( "sv_skyname", pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "sounds") ) - { - gpGlobals->cdAudioTrack = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "WaveHeight") ) - { - // Sent over net now. - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); - } - else if ( FStrEq(pkvd->szKeyName, "MaxRange") ) - { - pev->speed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "chaptertitle") ) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "startdark") ) - { - // UNDONE: This is a gross hack!!! The CVAR is NOT sent over the client/sever link - // but it will work for single player - int flag = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - if ( flag ) - pev->spawnflags |= SF_WORLD_DARK; - } - else if ( FStrEq(pkvd->szKeyName, "newunit") ) - { - // Single player only. Clear save directory if set - if ( atoi(pkvd->szValue) ) - CVAR_SET_FLOAT( "sv_newunit", 1 ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "gametitle") ) - { - if ( atoi(pkvd->szValue) ) - pev->spawnflags |= SF_WORLD_TITLE; - - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "mapteams") ) - { - pev->team = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "defaultteam") ) - { - if ( atoi(pkvd->szValue) ) - { - pev->spawnflags |= SF_WORLD_FORCETEAM; - } - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +===== world.cpp ======================================================== + + precaches and defs for entities and other data that must always be available. + +*/ + +#include "../util/nowarnings.h" +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "nodes.h" +#include "soundent.h" +#include "client.h" +#include "decals.h" +#include "skill.h" +#include "effects.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "teamplay_gamerules.h" +#include "../mod/AvHGamerules.h" +#include "../mod/AvHServerVariables.h" +#include "pm_shared/pm_defs.h" + +extern CGraph WorldGraph; +extern CSoundEnt *pSoundEnt; + +DLL_GLOBAL edict_t *g_pBodyQueueHead; +CGlobalState gGlobalState; +extern DLL_GLOBAL int gDisplayTitle; +extern playermove_t* pmove; + +extern void W_Precache(void); + +// +// This must match the list in util.h +// +DLL_DECALLIST gDecals[] = { + { "{shot1", 0 }, // DECAL_GUNSHOT1 + { "{shot2", 0 }, // DECAL_GUNSHOT2 + { "{shot3",0 }, // DECAL_GUNSHOT3 + { "{shot4", 0 }, // DECAL_GUNSHOT4 + { "{shot5", 0 }, // DECAL_GUNSHOT5 + { "{lambda01", 0 }, // DECAL_LAMBDA1 + { "{lambda02", 0 }, // DECAL_LAMBDA2 + { "{lambda03", 0 }, // DECAL_LAMBDA3 + { "{lambda04", 0 }, // DECAL_LAMBDA4 + { "{lambda05", 0 }, // DECAL_LAMBDA5 + { "{lambda06", 0 }, // DECAL_LAMBDA6 + { "{scorch1", 0 }, // DECAL_SCORCH1 + { "{scorch2", 0 }, // DECAL_SCORCH2 + { "{blood1", 0 }, // DECAL_BLOOD1 + { "{blood2", 0 }, // DECAL_BLOOD2 + { "{blood3", 0 }, // DECAL_BLOOD3 + { "{blood4", 0 }, // DECAL_BLOOD4 + { "{blood5", 0 }, // DECAL_BLOOD5 + { "{blood6", 0 }, // DECAL_BLOOD6 + { "{yblood1", 0 }, // DECAL_YBLOOD1 + { "{yblood2", 0 }, // DECAL_YBLOOD2 + { "{yblood3", 0 }, // DECAL_YBLOOD3 + { "{yblood4", 0 }, // DECAL_YBLOOD4 + { "{yblood5", 0 }, // DECAL_YBLOOD5 + { "{yblood6", 0 }, // DECAL_YBLOOD6 + { "{break1", 0 }, // DECAL_GLASSBREAK1 + { "{break2", 0 }, // DECAL_GLASSBREAK2 + { "{break3", 0 }, // DECAL_GLASSBREAK3 + { "{bigshot1", 0 }, // DECAL_BIGSHOT1 + { "{bigshot2", 0 }, // DECAL_BIGSHOT2 + { "{bigshot3", 0 }, // DECAL_BIGSHOT3 + { "{bigshot4", 0 }, // DECAL_BIGSHOT4 + { "{bigshot5", 0 }, // DECAL_BIGSHOT5 + { "{spit1", 0 }, // DECAL_SPIT1 + { "{spit2", 0 }, // DECAL_SPIT2 + { "{bproof1", 0 }, // DECAL_BPROOF1 + { "{gargstomp", 0 }, // DECAL_GARGSTOMP1, // Gargantua stomp crack + { "{smscorch1", 0 }, // DECAL_SMALLSCORCH1, // Small scorch mark + { "{smscorch2", 0 }, // DECAL_SMALLSCORCH2, // Small scorch mark + { "{smscorch3", 0 }, // DECAL_SMALLSCORCH3, // Small scorch mark + { "{mommablob", 0 }, // DECAL_MOMMABIRTH // BM Birth spray + { "{mommablob", 0 }, // DECAL_MOMMASPLAT // BM Mortar spray?? need decal +}; + +/* +============================================================================== + +BODY QUE + +============================================================================== +*/ + +#define SF_DECAL_NOTINDEATHMATCH 2048 + +class CDecal : public CBaseEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void EXPORT StaticDecal( void ); + void EXPORT TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +LINK_ENTITY_TO_CLASS( infodecal, CDecal ); + +// UNDONE: These won't get sent to joining players in multi-player +void CDecal :: Spawn( void ) +{ + if ( pev->skin < 0 || (gpGlobals->deathmatch && FBitSet( pev->spawnflags, SF_DECAL_NOTINDEATHMATCH )) ) + { + REMOVE_ENTITY(ENT(pev)); + return; + } + + if ( FStringNull ( pev->targetname ) ) + { + SetThink(&CDecal::StaticDecal ); + // if there's no targetname, the decal will spray itself on as soon as the world is done spawning. + pev->nextthink = gpGlobals->time; + } + else + { + // if there IS a targetname, the decal sprays itself on when it is triggered. + SetThink (&CDecal::SUB_DoNothing ); + SetUse(&CDecal::TriggerDecal); + } +} + +void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // this is set up as a USE function for infodecals that have targetnames, so that the + // decal doesn't get applied until it is fired. (usually by a scripted sequence) + TraceResult trace; + int entityIndex; + + UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY); + WRITE_BYTE( TE_BSPDECAL ); + WRITE_COORD( pev->origin.x ); + WRITE_COORD( pev->origin.y ); + WRITE_COORD( pev->origin.z ); + WRITE_SHORT( (int)pev->skin ); + entityIndex = (short)ENTINDEX(trace.pHit); + WRITE_SHORT( entityIndex ); + if ( entityIndex ) + WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); + MESSAGE_END(); + + SetThink(&CDecal::SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CDecal :: StaticDecal( void ) +{ + TraceResult trace; + int entityIndex, modelIndex; + + UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); + + entityIndex = (short)ENTINDEX(trace.pHit); + if ( entityIndex ) + modelIndex = (int)VARS(trace.pHit)->modelindex; + else + modelIndex = 0; + + g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); + + SUB_Remove(); +} + + +void CDecal :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "texture")) + { + pev->skin = DECAL_INDEX( pkvd->szValue ); + + // Found + if ( pev->skin >= 0 ) + return; + ALERT( at_console, "Can't find decal %s\n", pkvd->szValue ); + } + else + CBaseEntity::KeyValue( pkvd ); +} + + +// Body queue class here.... It's really just CBaseEntity +class CCorpse : public CBaseEntity +{ + virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } +}; + +LINK_ENTITY_TO_CLASS( bodyque, CCorpse ); + +static void InitBodyQue(void) +{ + string_t istrClassname = MAKE_STRING("bodyque"); + + g_pBodyQueueHead = CREATE_NAMED_ENTITY( istrClassname ); + entvars_t *pev = VARS(g_pBodyQueueHead); + + // Reserve 3 more slots for dead bodies + for ( int i = 0; i < 3; i++ ) + { + pev->owner = CREATE_NAMED_ENTITY( istrClassname ); + pev = VARS(pev->owner); + } + + pev->owner = g_pBodyQueueHead; +} + + +// +// make a body que entry for the given ent so the ent can be respawned elsewhere +// +// GLOBALS ASSUMED SET: g_eoBodyQueueHead +// +void CopyToBodyQue(entvars_t *pev) +{ + if (pev->effects & EF_NODRAW) + return; + + entvars_t *pevHead = VARS(g_pBodyQueueHead); + + pevHead->angles = pev->angles; + pevHead->model = pev->model; + pevHead->modelindex = pev->modelindex; + pevHead->frame = pev->frame; + pevHead->colormap = pev->colormap; + pevHead->movetype = MOVETYPE_TOSS; + pevHead->velocity = pev->velocity; + pevHead->flags = 0; + pevHead->deadflag = pev->deadflag; + pevHead->renderfx = kRenderFxDeadPlayer; + pevHead->renderamt = ENTINDEX( ENT( pev ) ); + + pevHead->effects = pev->effects | EF_NOINTERP; + //pevHead->goalstarttime = pev->goalstarttime; + //pevHead->goalframe = pev->goalframe; + //pevHead->goalendtime = pev->goalendtime ; + + pevHead->sequence = pev->sequence; + pevHead->animtime = pev->animtime; + + UTIL_SetOrigin(pevHead, pev->origin); + UTIL_SetSize(pevHead, pev->mins, pev->maxs); + g_pBodyQueueHead = pevHead->owner; +} + + +CGlobalState::CGlobalState( void ) +{ + Reset(); +} + +void CGlobalState::Reset( void ) +{ + m_pList = NULL; + m_listCount = 0; +} + +globalentity_t *CGlobalState :: Find( string_t globalname ) +{ + if ( !globalname ) + return NULL; + + globalentity_t *pTest; + const char *pEntityName = STRING(globalname); + + + pTest = m_pList; + while ( pTest ) + { + if ( FStrEq( pEntityName, pTest->name ) ) + break; + + pTest = pTest->pNext; + } + + return pTest; +} + + +// This is available all the time now on impulse 104, remove later +//#ifdef _DEBUG +void CGlobalState :: DumpGlobals( void ) +{ + static char *estates[] = { "Off", "On", "Dead" }; + globalentity_t *pTest; + + ALERT( at_console, "-- Globals --\n" ); + pTest = m_pList; + while ( pTest ) + { + ALERT( at_console, "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state] ); + pTest = pTest->pNext; + } +} +//#endif + + +void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) +{ + ASSERT( !Find(globalname) ); + + globalentity_t *pNewEntity = (globalentity_t *)calloc( sizeof( globalentity_t ), 1 ); + ASSERT( pNewEntity != NULL ); + pNewEntity->pNext = m_pList; + m_pList = pNewEntity; + strcpy( pNewEntity->name, STRING( globalname ) ); + strcpy( pNewEntity->levelName, STRING(mapName) ); + pNewEntity->state = state; + m_listCount++; +} + + +void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) +{ + globalentity_t *pEnt = Find( globalname ); + + if ( pEnt ) + pEnt->state = state; +} + + +const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) +{ + globalentity_t *pEnt = Find( globalname ); + + return pEnt; +} + + +GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) +{ + globalentity_t *pEnt = Find( globalname ); + if ( pEnt ) + return pEnt->state; + + return GLOBAL_OFF; +} + + +// Global Savedata for Delay +TYPEDESCRIPTION CGlobalState::m_SaveData[] = +{ + DEFINE_FIELD( CGlobalState, m_listCount, FIELD_INTEGER ), +}; + +// Global Savedata for Delay +TYPEDESCRIPTION gGlobalEntitySaveData[] = +{ + DEFINE_ARRAY( globalentity_t, name, FIELD_CHARACTER, 64 ), + DEFINE_ARRAY( globalentity_t, levelName, FIELD_CHARACTER, 32 ), + DEFINE_FIELD( globalentity_t, state, FIELD_INTEGER ), +}; + +const char* CGlobalState::GetLevelName() +{ + return STRING(this->m_pList->levelName); +} + +int CGlobalState::Save( CSave &save ) +{ + int i; + globalentity_t *pEntity; + + if ( !save.WriteFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) + return 0; + + pEntity = m_pList; + for ( i = 0; i < m_listCount && pEntity; i++ ) + { + if ( !save.WriteFields( "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) + return 0; + + pEntity = pEntity->pNext; + } + + return 1; +} + +int CGlobalState::Restore( CRestore &restore ) +{ + int i, listCount; + globalentity_t tmpEntity; + + + ClearStates(); + if ( !restore.ReadFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) + return 0; + + listCount = m_listCount; // Get new list count + m_listCount = 0; // Clear loaded data + + for ( i = 0; i < listCount; i++ ) + { + if ( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) + return 0; + EntityAdd( MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state ); + } + return 1; +} + +void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) +{ + globalentity_t *pEnt = Find( globalname ); + + if ( pEnt ) + strcpy( pEnt->levelName, STRING(mapname) ); +} + + +void CGlobalState::ClearStates( void ) +{ + globalentity_t *pFree = m_pList; + while ( pFree ) + { + globalentity_t *pNext = pFree->pNext; + free( pFree ); + pFree = pNext; + } + Reset(); +} + + +void SaveGlobalState( SAVERESTOREDATA *pSaveData ) +{ + CSave saveHelper( pSaveData ); + gGlobalState.Save( saveHelper ); +} + + +void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) +{ + CRestore restoreHelper( pSaveData ); + gGlobalState.Restore( restoreHelper ); +} + + +void ResetGlobalState( void ) +{ + gGlobalState.ClearStates(); + gInitHUD = TRUE; // Init the HUD on a new game / load game +} + +// moved CWorld class definition to cbase.h +//======================= +// CWorld +// +// This spawns first when each level begins. +//======================= + +LINK_ENTITY_TO_CLASS( worldspawn, CWorld ); + +#define SF_WORLD_DARK 0x0001 // Fade from black at startup +#define SF_WORLD_TITLE 0x0002 // Display game title at startup +#define SF_WORLD_FORCETEAM 0x0004 // Force teams + +extern DLL_GLOBAL BOOL g_fGameOver; +float g_flWeaponCheat; + +void CWorld :: Spawn( void ) +{ + g_fGameOver = FALSE; + Precache( ); + g_flWeaponCheat = ns_cvar_float(avh_cheats ); // Is the impulse 101 command allowed? +} + +void CWorld :: Precache( void ) +{ +#if 1 + CVAR_SET_STRING("sv_gravity", "800"); // 67ft/sec + CVAR_SET_STRING("sv_stepsize", "18"); +#else + CVAR_SET_STRING("sv_gravity", "384"); // 32ft/sec + CVAR_SET_STRING("sv_stepsize", "24"); +#endif + + CVAR_SET_STRING("room_type", "0");// clear DSP + + // Set up game rules + if (g_pGameRules) + { + delete g_pGameRules; + + // This is needed because pmove is used by AvHSUGetIsEnoughRoomForHull, and if it isn't set to null, pmove->physents[0].worldmodel is the old map on a changelevel, and invalid + pmove = NULL; + } + + InstallGameRules( ); + GetGameRules()->PreWorldPrecacheReset(); + + //AvHGamerules* theGameRules = dynamic_cast(g_pGameRules); + + //static const char* sCurrentLevelName = NULL; + //const char* theLevelName = STRING(gpGlobals->mapname); + //bool theNewMap = false; + //if(!sCurrentLevelName || strcmp(theLevelName, sCurrentLevelName)) + //{ + // theNewMap = true; + //} + + // Reset game, but don't send need to send particles if same map (remove this distinction?) + //theGameRules->ResetGame(theNewMap); + //sCurrentLevelName = theLevelName; +// static bool theFirstTime = true; +// if(!theFirstTime) +// { +// theGameRules->ResetGame(true); +// } +// theFirstTime = false; + + //!!!UNDONE why is there so much Spawn code in the Precache function? I'll just keep it here + + ///!!!LATER - do we want a sound ent in deathmatch? (sjb) + //pSoundEnt = CBaseEntity::Create( "soundent", g_vecZero, g_vecZero, edict() ); + pSoundEnt = GetClassPtr( ( CSoundEnt *)NULL ); + pSoundEnt->Spawn(); + + if ( !pSoundEnt ) + { + ALERT ( at_console, "**COULD NOT CREATE SOUNDENT**\n" ); + } + + InitBodyQue(); + +// init sentence group playback stuff from sentences.txt. +// ok to call this multiple times, calls after first are ignored. + + SENTENCEG_Init(); + +// init texture type array from materials.txt + + TEXTURETYPE_Init(); + + +// the area based ambient sounds MUST be the first precache_sounds + +// player precaches + W_Precache (); // get weapon precaches + + ClientPrecache(); + +// sounds used from C physics code + PRECACHE_SOUND("common/null.wav"); // clears sound channels + + PRECACHE_SOUND( "items/suitchargeok1.wav" );//!!! temporary sound for respawning weapons. + PRECACHE_UNMODIFIED_SOUND( "items/gunpickup2.wav" ); // player picks up a gun. + PRECACHE_UNMODIFIED_SOUND( "items/gunpickup2-a.wav" ); // alien is equipped + + PRECACHE_SOUND( "common/bodydrop3.wav" );// dead bodies hitting the ground (animation events) + PRECACHE_SOUND( "common/bodydrop4.wav" ); + + g_Language = (int)CVAR_GET_FLOAT( "sv_language" ); + if ( g_Language == LANGUAGE_GERMAN ) + { + PRECACHE_UNMODIFIED_MODEL( "models/germangibs.mdl" ); + } + else + { + PRECACHE_UNMODIFIED_MODEL( "models/hgibs.mdl" ); + PRECACHE_UNMODIFIED_MODEL( "models/agibs.mdl" ); + } + + PRECACHE_UNMODIFIED_SOUND ("weapons/ric1.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/ric2.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/ric3.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/ric4.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/ric5.wav"); + + PRECACHE_UNMODIFIED_SOUND ("weapons/ric_conc-1.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/ric_conc-2.wav"); + + PRECACHE_UNMODIFIED_SOUND ("weapons/ric_metal-1.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/ric_metal-2.wav"); + + // Precache alien ricochet sounds + PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric1.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric2.wav"); + PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric3.wav"); +// +// Setup light animation tables. 'a' is total darkness, 'z' is maxbright. +// + + // 0 normal + LIGHT_STYLE(0, "m"); + + // 1 FLICKER (first variety) + LIGHT_STYLE(1, "mmnmmommommnonmmonqnmmo"); + + // 2 SLOW STRONG PULSE + LIGHT_STYLE(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); + + // 3 CANDLE (first variety) + LIGHT_STYLE(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); + + // 4 FAST STROBE + LIGHT_STYLE(4, "mamamamamama"); + + // 5 GENTLE PULSE 1 + LIGHT_STYLE(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); + + // 6 FLICKER (second variety) + LIGHT_STYLE(6, "nmonqnmomnmomomno"); + + // 7 CANDLE (second variety) + LIGHT_STYLE(7, "mmmaaaabcdefgmmmmaaaammmaamm"); + + // 8 CANDLE (third variety) + LIGHT_STYLE(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); + + // 9 SLOW STROBE (fourth variety) + LIGHT_STYLE(9, "aaaaaaaazzzzzzzz"); + + // 10 FLUORESCENT FLICKER + LIGHT_STYLE(10, "mmamammmmammamamaaamammma"); + + // 11 SLOW PULSE NOT FADE TO BLACK + LIGHT_STYLE(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); + + // 12 UNDERWATER LIGHT MUTATION + // this light only distorts the lightmap - no contribution + // is made to the brightness of affected surfaces + LIGHT_STYLE(12, "mmnnmmnnnmmnn"); + + // styles 32-62 are assigned by the light program for switchable lights + + // 63 testing + LIGHT_STYLE(63, "a"); + + for ( int i = 0; i < ARRAYSIZE(gDecals); i++ ) + gDecals[i].index = DECAL_INDEX( gDecals[i].name ); + +// init the WorldGraph. + WorldGraph.InitGraph(); + +// make sure the .NOD file is newer than the .BSP file. + if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) ) + {// NOD file is not present, or is older than the BSP file. + WorldGraph.AllocNodes (); + } + else + {// Load the node graph for this level + if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) ) + {// couldn't load, so alloc and prepare to build a graph. + ALERT ( at_console, "*Error opening .NOD file\n" ); + WorldGraph.AllocNodes (); + } + else + { + ALERT ( at_console, "\n*Graph Loaded!\n" ); + } + } + + if ( pev->speed > 0 ) + CVAR_SET_FLOAT( "sv_zmax", pev->speed ); + else + CVAR_SET_FLOAT( "sv_zmax", 4096 ); + + if ( pev->netname ) + { + ALERT( at_aiconsole, "Chapter title: %s\n", STRING(pev->netname) ); + CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); + if ( pEntity ) + { + pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); + pEntity->pev->message = pev->netname; + pev->netname = 0; + pEntity->pev->nextthink = gpGlobals->time + 0.3; + pEntity->pev->spawnflags = SF_MESSAGE_ONCE; + } + } + + if ( pev->spawnflags & SF_WORLD_DARK ) + CVAR_SET_FLOAT( "v_dark", 1.0 ); + else + CVAR_SET_FLOAT( "v_dark", 0.0 ); + + if ( pev->spawnflags & SF_WORLD_TITLE ) + gDisplayTitle = TRUE; // display the game title if this key is set + else + gDisplayTitle = FALSE; + + if ( pev->spawnflags & SF_WORLD_FORCETEAM ) + { + CVAR_SET_FLOAT( "mp_defaultteam", 1 ); + } + else + { + CVAR_SET_FLOAT( "mp_defaultteam", 0 ); + } +} + + +// +// Just to ignore the "wad" field. +// +void CWorld :: KeyValue( KeyValueData *pkvd ) +{ + if ( FStrEq(pkvd->szKeyName, "skyname") ) + { + // Sent over net now. + CVAR_SET_STRING( "sv_skyname", pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "sounds") ) + { + gpGlobals->cdAudioTrack = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "WaveHeight") ) + { + // Sent over net now. + pev->scale = atof(pkvd->szValue) * (1.0/8.0); + pkvd->fHandled = TRUE; + CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); + } + else if ( FStrEq(pkvd->szKeyName, "MaxRange") ) + { + pev->speed = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "chaptertitle") ) + { + pev->netname = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "startdark") ) + { + // UNDONE: This is a gross hack!!! The CVAR is NOT sent over the client/sever link + // but it will work for single player + int flag = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + if ( flag ) + pev->spawnflags |= SF_WORLD_DARK; + } + else if ( FStrEq(pkvd->szKeyName, "newunit") ) + { + // Single player only. Clear save directory if set + if ( atoi(pkvd->szValue) ) + CVAR_SET_FLOAT( "sv_newunit", 1 ); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "gametitle") ) + { + if ( atoi(pkvd->szValue) ) + pev->spawnflags |= SF_WORLD_TITLE; + + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "mapteams") ) + { + pev->team = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if ( FStrEq(pkvd->szKeyName, "defaultteam") ) + { + if ( atoi(pkvd->szValue) ) + { + pev->spawnflags |= SF_WORLD_FORCETEAM; + } + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} diff --git a/main/source/dlls/world.cpp~ b/main/source/dlls/world.cpp~ deleted file mode 100644 index 7de743fb..00000000 --- a/main/source/dlls/world.cpp~ +++ /dev/null @@ -1,784 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== world.cpp ======================================================== - - precaches and defs for entities and other data that must always be available. - -*/ - -#include "util/nowarnings.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "soundent.h" -#include "client.h" -#include "decals.h" -#include "skill.h" -#include "effects.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "../mod/AvHGamerules.h" -#include "../mod/AvHServerVariables.h" -#include "pm_shared/pm_defs.h" - -extern CGraph WorldGraph; -extern CSoundEnt *pSoundEnt; - -DLL_GLOBAL edict_t *g_pBodyQueueHead; -CGlobalState gGlobalState; -extern DLL_GLOBAL int gDisplayTitle; -extern playermove_t* pmove; - -extern void W_Precache(void); - -// -// This must match the list in util.h -// -DLL_DECALLIST gDecals[] = { - { "{shot1", 0 }, // DECAL_GUNSHOT1 - { "{shot2", 0 }, // DECAL_GUNSHOT2 - { "{shot3",0 }, // DECAL_GUNSHOT3 - { "{shot4", 0 }, // DECAL_GUNSHOT4 - { "{shot5", 0 }, // DECAL_GUNSHOT5 - { "{lambda01", 0 }, // DECAL_LAMBDA1 - { "{lambda02", 0 }, // DECAL_LAMBDA2 - { "{lambda03", 0 }, // DECAL_LAMBDA3 - { "{lambda04", 0 }, // DECAL_LAMBDA4 - { "{lambda05", 0 }, // DECAL_LAMBDA5 - { "{lambda06", 0 }, // DECAL_LAMBDA6 - { "{scorch1", 0 }, // DECAL_SCORCH1 - { "{scorch2", 0 }, // DECAL_SCORCH2 - { "{blood1", 0 }, // DECAL_BLOOD1 - { "{blood2", 0 }, // DECAL_BLOOD2 - { "{blood3", 0 }, // DECAL_BLOOD3 - { "{blood4", 0 }, // DECAL_BLOOD4 - { "{blood5", 0 }, // DECAL_BLOOD5 - { "{blood6", 0 }, // DECAL_BLOOD6 - { "{yblood1", 0 }, // DECAL_YBLOOD1 - { "{yblood2", 0 }, // DECAL_YBLOOD2 - { "{yblood3", 0 }, // DECAL_YBLOOD3 - { "{yblood4", 0 }, // DECAL_YBLOOD4 - { "{yblood5", 0 }, // DECAL_YBLOOD5 - { "{yblood6", 0 }, // DECAL_YBLOOD6 - { "{break1", 0 }, // DECAL_GLASSBREAK1 - { "{break2", 0 }, // DECAL_GLASSBREAK2 - { "{break3", 0 }, // DECAL_GLASSBREAK3 - { "{bigshot1", 0 }, // DECAL_BIGSHOT1 - { "{bigshot2", 0 }, // DECAL_BIGSHOT2 - { "{bigshot3", 0 }, // DECAL_BIGSHOT3 - { "{bigshot4", 0 }, // DECAL_BIGSHOT4 - { "{bigshot5", 0 }, // DECAL_BIGSHOT5 - { "{spit1", 0 }, // DECAL_SPIT1 - { "{spit2", 0 }, // DECAL_SPIT2 - { "{bproof1", 0 }, // DECAL_BPROOF1 - { "{gargstomp", 0 }, // DECAL_GARGSTOMP1, // Gargantua stomp crack - { "{smscorch1", 0 }, // DECAL_SMALLSCORCH1, // Small scorch mark - { "{smscorch2", 0 }, // DECAL_SMALLSCORCH2, // Small scorch mark - { "{smscorch3", 0 }, // DECAL_SMALLSCORCH3, // Small scorch mark - { "{mommablob", 0 }, // DECAL_MOMMABIRTH // BM Birth spray - { "{mommablob", 0 }, // DECAL_MOMMASPLAT // BM Mortar spray?? need decal -}; - -/* -============================================================================== - -BODY QUE - -============================================================================== -*/ - -#define SF_DECAL_NOTINDEATHMATCH 2048 - -class CDecal : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT StaticDecal( void ); - void EXPORT TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( infodecal, CDecal ); - -// UNDONE: These won't get sent to joining players in multi-player -void CDecal :: Spawn( void ) -{ - if ( pev->skin < 0 || (gpGlobals->deathmatch && FBitSet( pev->spawnflags, SF_DECAL_NOTINDEATHMATCH )) ) - { - REMOVE_ENTITY(ENT(pev)); - return; - } - - if ( FStringNull ( pev->targetname ) ) - { - SetThink(&CDecal::StaticDecal ); - // if there's no targetname, the decal will spray itself on as soon as the world is done spawning. - pev->nextthink = gpGlobals->time; - } - else - { - // if there IS a targetname, the decal sprays itself on when it is triggered. - SetThink (&CDecal::SUB_DoNothing ); - SetUse(&CDecal::TriggerDecal); - } -} - -void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // this is set up as a USE function for infodecals that have targetnames, so that the - // decal doesn't get applied until it is fired. (usually by a scripted sequence) - TraceResult trace; - int entityIndex; - - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE( TE_BSPDECAL ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( (int)pev->skin ); - entityIndex = (short)ENTINDEX(trace.pHit); - WRITE_SHORT( entityIndex ); - if ( entityIndex ) - WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); - MESSAGE_END(); - - SetThink(&CDecal::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CDecal :: StaticDecal( void ) -{ - TraceResult trace; - int entityIndex, modelIndex; - - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - - entityIndex = (short)ENTINDEX(trace.pHit); - if ( entityIndex ) - modelIndex = (int)VARS(trace.pHit)->modelindex; - else - modelIndex = 0; - - g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); - - SUB_Remove(); -} - - -void CDecal :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->skin = DECAL_INDEX( pkvd->szValue ); - - // Found - if ( pev->skin >= 0 ) - return; - ALERT( at_console, "Can't find decal %s\n", pkvd->szValue ); - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// Body queue class here.... It's really just CBaseEntity -class CCorpse : public CBaseEntity -{ - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -LINK_ENTITY_TO_CLASS( bodyque, CCorpse ); - -static void InitBodyQue(void) -{ - string_t istrClassname = MAKE_STRING("bodyque"); - - g_pBodyQueueHead = CREATE_NAMED_ENTITY( istrClassname ); - entvars_t *pev = VARS(g_pBodyQueueHead); - - // Reserve 3 more slots for dead bodies - for ( int i = 0; i < 3; i++ ) - { - pev->owner = CREATE_NAMED_ENTITY( istrClassname ); - pev = VARS(pev->owner); - } - - pev->owner = g_pBodyQueueHead; -} - - -// -// make a body que entry for the given ent so the ent can be respawned elsewhere -// -// GLOBALS ASSUMED SET: g_eoBodyQueueHead -// -void CopyToBodyQue(entvars_t *pev) -{ - if (pev->effects & EF_NODRAW) - return; - - entvars_t *pevHead = VARS(g_pBodyQueueHead); - - pevHead->angles = pev->angles; - pevHead->model = pev->model; - pevHead->modelindex = pev->modelindex; - pevHead->frame = pev->frame; - pevHead->colormap = pev->colormap; - pevHead->movetype = MOVETYPE_TOSS; - pevHead->velocity = pev->velocity; - pevHead->flags = 0; - pevHead->deadflag = pev->deadflag; - pevHead->renderfx = kRenderFxDeadPlayer; - pevHead->renderamt = ENTINDEX( ENT( pev ) ); - - pevHead->effects = pev->effects | EF_NOINTERP; - //pevHead->goalstarttime = pev->goalstarttime; - //pevHead->goalframe = pev->goalframe; - //pevHead->goalendtime = pev->goalendtime ; - - pevHead->sequence = pev->sequence; - pevHead->animtime = pev->animtime; - - UTIL_SetOrigin(pevHead, pev->origin); - UTIL_SetSize(pevHead, pev->mins, pev->maxs); - g_pBodyQueueHead = pevHead->owner; -} - - -CGlobalState::CGlobalState( void ) -{ - Reset(); -} - -void CGlobalState::Reset( void ) -{ - m_pList = NULL; - m_listCount = 0; -} - -globalentity_t *CGlobalState :: Find( string_t globalname ) -{ - if ( !globalname ) - return NULL; - - globalentity_t *pTest; - const char *pEntityName = STRING(globalname); - - - pTest = m_pList; - while ( pTest ) - { - if ( FStrEq( pEntityName, pTest->name ) ) - break; - - pTest = pTest->pNext; - } - - return pTest; -} - - -// This is available all the time now on impulse 104, remove later -//#ifdef _DEBUG -void CGlobalState :: DumpGlobals( void ) -{ - static char *estates[] = { "Off", "On", "Dead" }; - globalentity_t *pTest; - - ALERT( at_console, "-- Globals --\n" ); - pTest = m_pList; - while ( pTest ) - { - ALERT( at_console, "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state] ); - pTest = pTest->pNext; - } -} -//#endif - - -void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) -{ - ASSERT( !Find(globalname) ); - - globalentity_t *pNewEntity = (globalentity_t *)calloc( sizeof( globalentity_t ), 1 ); - ASSERT( pNewEntity != NULL ); - pNewEntity->pNext = m_pList; - m_pList = pNewEntity; - strcpy( pNewEntity->name, STRING( globalname ) ); - strcpy( pNewEntity->levelName, STRING(mapName) ); - pNewEntity->state = state; - m_listCount++; -} - - -void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) -{ - globalentity_t *pEnt = Find( globalname ); - - if ( pEnt ) - pEnt->state = state; -} - - -const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - - return pEnt; -} - - -GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) - return pEnt->state; - - return GLOBAL_OFF; -} - - -// Global Savedata for Delay -TYPEDESCRIPTION CGlobalState::m_SaveData[] = -{ - DEFINE_FIELD( CGlobalState, m_listCount, FIELD_INTEGER ), -}; - -// Global Savedata for Delay -TYPEDESCRIPTION gGlobalEntitySaveData[] = -{ - DEFINE_ARRAY( globalentity_t, name, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( globalentity_t, levelName, FIELD_CHARACTER, 32 ), - DEFINE_FIELD( globalentity_t, state, FIELD_INTEGER ), -}; - -const char* CGlobalState::GetLevelName() -{ - return STRING(this->m_pList->levelName); -} - -int CGlobalState::Save( CSave &save ) -{ - int i; - globalentity_t *pEntity; - - if ( !save.WriteFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - pEntity = m_pList; - for ( i = 0; i < m_listCount && pEntity; i++ ) - { - if ( !save.WriteFields( "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - - pEntity = pEntity->pNext; - } - - return 1; -} - -int CGlobalState::Restore( CRestore &restore ) -{ - int i, listCount; - globalentity_t tmpEntity; - - - ClearStates(); - if ( !restore.ReadFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - listCount = m_listCount; // Get new list count - m_listCount = 0; // Clear loaded data - - for ( i = 0; i < listCount; i++ ) - { - if ( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - EntityAdd( MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state ); - } - return 1; -} - -void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) -{ - globalentity_t *pEnt = Find( globalname ); - - if ( pEnt ) - strcpy( pEnt->levelName, STRING(mapname) ); -} - - -void CGlobalState::ClearStates( void ) -{ - globalentity_t *pFree = m_pList; - while ( pFree ) - { - globalentity_t *pNext = pFree->pNext; - free( pFree ); - pFree = pNext; - } - Reset(); -} - - -void SaveGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CSave saveHelper( pSaveData ); - gGlobalState.Save( saveHelper ); -} - - -void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CRestore restoreHelper( pSaveData ); - gGlobalState.Restore( restoreHelper ); -} - - -void ResetGlobalState( void ) -{ - gGlobalState.ClearStates(); - gInitHUD = TRUE; // Init the HUD on a new game / load game -} - -// moved CWorld class definition to cbase.h -//======================= -// CWorld -// -// This spawns first when each level begins. -//======================= - -LINK_ENTITY_TO_CLASS( worldspawn, CWorld ); - -#define SF_WORLD_DARK 0x0001 // Fade from black at startup -#define SF_WORLD_TITLE 0x0002 // Display game title at startup -#define SF_WORLD_FORCETEAM 0x0004 // Force teams - -extern DLL_GLOBAL BOOL g_fGameOver; -float g_flWeaponCheat; - -void CWorld :: Spawn( void ) -{ - g_fGameOver = FALSE; - Precache( ); - g_flWeaponCheat = ns_cvar_float(avh_cheats ); // Is the impulse 101 command allowed? -} - -void CWorld :: Precache( void ) -{ -#if 1 - CVAR_SET_STRING("sv_gravity", "800"); // 67ft/sec - CVAR_SET_STRING("sv_stepsize", "18"); -#else - CVAR_SET_STRING("sv_gravity", "384"); // 32ft/sec - CVAR_SET_STRING("sv_stepsize", "24"); -#endif - - CVAR_SET_STRING("room_type", "0");// clear DSP - - // Set up game rules - if (g_pGameRules) - { - delete g_pGameRules; - - // This is needed because pmove is used by AvHSUGetIsEnoughRoomForHull, and if it isn't set to null, pmove->physents[0].worldmodel is the old map on a changelevel, and invalid - pmove = NULL; - } - - InstallGameRules( ); - GetGameRules()->PreWorldPrecacheReset(); - - //AvHGamerules* theGameRules = dynamic_cast(g_pGameRules); - - //static const char* sCurrentLevelName = NULL; - //const char* theLevelName = STRING(gpGlobals->mapname); - //bool theNewMap = false; - //if(!sCurrentLevelName || strcmp(theLevelName, sCurrentLevelName)) - //{ - // theNewMap = true; - //} - - // Reset game, but don't send need to send particles if same map (remove this distinction?) - //theGameRules->ResetGame(theNewMap); - //sCurrentLevelName = theLevelName; -// static bool theFirstTime = true; -// if(!theFirstTime) -// { -// theGameRules->ResetGame(true); -// } -// theFirstTime = false; - - //!!!UNDONE why is there so much Spawn code in the Precache function? I'll just keep it here - - ///!!!LATER - do we want a sound ent in deathmatch? (sjb) - //pSoundEnt = CBaseEntity::Create( "soundent", g_vecZero, g_vecZero, edict() ); - pSoundEnt = GetClassPtr( ( CSoundEnt *)NULL ); - pSoundEnt->Spawn(); - - if ( !pSoundEnt ) - { - ALERT ( at_console, "**COULD NOT CREATE SOUNDENT**\n" ); - } - - InitBodyQue(); - -// init sentence group playback stuff from sentences.txt. -// ok to call this multiple times, calls after first are ignored. - - SENTENCEG_Init(); - -// init texture type array from materials.txt - - TEXTURETYPE_Init(); - - -// the area based ambient sounds MUST be the first precache_sounds - -// player precaches - W_Precache (); // get weapon precaches - - ClientPrecache(); - -// sounds used from C physics code - PRECACHE_SOUND("common/null.wav"); // clears sound channels - - PRECACHE_SOUND( "items/suitchargeok1.wav" );//!!! temporary sound for respawning weapons. - PRECACHE_UNMODIFIED_SOUND( "items/gunpickup2.wav" ); // player picks up a gun. - PRECACHE_UNMODIFIED_SOUND( "items/gunpickup2-a.wav" ); // alien is equipped - - PRECACHE_SOUND( "common/bodydrop3.wav" );// dead bodies hitting the ground (animation events) - PRECACHE_SOUND( "common/bodydrop4.wav" ); - - g_Language = (int)CVAR_GET_FLOAT( "sv_language" ); - if ( g_Language == LANGUAGE_GERMAN ) - { - PRECACHE_UNMODIFIED_MODEL( "models/germangibs.mdl" ); - } - else - { - PRECACHE_UNMODIFIED_MODEL( "models/hgibs.mdl" ); - PRECACHE_UNMODIFIED_MODEL( "models/agibs.mdl" ); - } - - PRECACHE_UNMODIFIED_SOUND ("weapons/ric1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric2.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric3.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric4.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric5.wav"); - - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_conc-1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_conc-2.wav"); - - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_metal-1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/ric_metal-2.wav"); - - // Precache alien ricochet sounds - PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric1.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric2.wav"); - PRECACHE_UNMODIFIED_SOUND ("weapons/a_ric3.wav"); -// -// Setup light animation tables. 'a' is total darkness, 'z' is maxbright. -// - - // 0 normal - LIGHT_STYLE(0, "m"); - - // 1 FLICKER (first variety) - LIGHT_STYLE(1, "mmnmmommommnonmmonqnmmo"); - - // 2 SLOW STRONG PULSE - LIGHT_STYLE(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); - - // 3 CANDLE (first variety) - LIGHT_STYLE(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); - - // 4 FAST STROBE - LIGHT_STYLE(4, "mamamamamama"); - - // 5 GENTLE PULSE 1 - LIGHT_STYLE(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); - - // 6 FLICKER (second variety) - LIGHT_STYLE(6, "nmonqnmomnmomomno"); - - // 7 CANDLE (second variety) - LIGHT_STYLE(7, "mmmaaaabcdefgmmmmaaaammmaamm"); - - // 8 CANDLE (third variety) - LIGHT_STYLE(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); - - // 9 SLOW STROBE (fourth variety) - LIGHT_STYLE(9, "aaaaaaaazzzzzzzz"); - - // 10 FLUORESCENT FLICKER - LIGHT_STYLE(10, "mmamammmmammamamaaamammma"); - - // 11 SLOW PULSE NOT FADE TO BLACK - LIGHT_STYLE(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); - - // 12 UNDERWATER LIGHT MUTATION - // this light only distorts the lightmap - no contribution - // is made to the brightness of affected surfaces - LIGHT_STYLE(12, "mmnnmmnnnmmnn"); - - // styles 32-62 are assigned by the light program for switchable lights - - // 63 testing - LIGHT_STYLE(63, "a"); - - for ( int i = 0; i < ARRAYSIZE(gDecals); i++ ) - gDecals[i].index = DECAL_INDEX( gDecals[i].name ); - -// init the WorldGraph. - WorldGraph.InitGraph(); - -// make sure the .NOD file is newer than the .BSP file. - if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) ) - {// NOD file is not present, or is older than the BSP file. - WorldGraph.AllocNodes (); - } - else - {// Load the node graph for this level - if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) ) - {// couldn't load, so alloc and prepare to build a graph. - ALERT ( at_console, "*Error opening .NOD file\n" ); - WorldGraph.AllocNodes (); - } - else - { - ALERT ( at_console, "\n*Graph Loaded!\n" ); - } - } - - if ( pev->speed > 0 ) - CVAR_SET_FLOAT( "sv_zmax", pev->speed ); - else - CVAR_SET_FLOAT( "sv_zmax", 4096 ); - - if ( pev->netname ) - { - ALERT( at_aiconsole, "Chapter title: %s\n", STRING(pev->netname) ); - CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); - if ( pEntity ) - { - pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); - pEntity->pev->message = pev->netname; - pev->netname = 0; - pEntity->pev->nextthink = gpGlobals->time + 0.3; - pEntity->pev->spawnflags = SF_MESSAGE_ONCE; - } - } - - if ( pev->spawnflags & SF_WORLD_DARK ) - CVAR_SET_FLOAT( "v_dark", 1.0 ); - else - CVAR_SET_FLOAT( "v_dark", 0.0 ); - - if ( pev->spawnflags & SF_WORLD_TITLE ) - gDisplayTitle = TRUE; // display the game title if this key is set - else - gDisplayTitle = FALSE; - - if ( pev->spawnflags & SF_WORLD_FORCETEAM ) - { - CVAR_SET_FLOAT( "mp_defaultteam", 1 ); - } - else - { - CVAR_SET_FLOAT( "mp_defaultteam", 0 ); - } -} - - -// -// Just to ignore the "wad" field. -// -void CWorld :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "skyname") ) - { - // Sent over net now. - CVAR_SET_STRING( "sv_skyname", pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "sounds") ) - { - gpGlobals->cdAudioTrack = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "WaveHeight") ) - { - // Sent over net now. - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); - } - else if ( FStrEq(pkvd->szKeyName, "MaxRange") ) - { - pev->speed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "chaptertitle") ) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "startdark") ) - { - // UNDONE: This is a gross hack!!! The CVAR is NOT sent over the client/sever link - // but it will work for single player - int flag = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - if ( flag ) - pev->spawnflags |= SF_WORLD_DARK; - } - else if ( FStrEq(pkvd->szKeyName, "newunit") ) - { - // Single player only. Clear save directory if set - if ( atoi(pkvd->szValue) ) - CVAR_SET_FLOAT( "sv_newunit", 1 ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "gametitle") ) - { - if ( atoi(pkvd->szValue) ) - pev->spawnflags |= SF_WORLD_TITLE; - - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "mapteams") ) - { - pev->team = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "defaultteam") ) - { - if ( atoi(pkvd->szValue) ) - { - pev->spawnflags |= SF_WORLD_FORCETEAM; - } - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} diff --git a/main/source/dlls/wxdebug.h b/main/source/dlls/wxdebug.h index 321b1bcd..026039ae 100644 --- a/main/source/dlls/wxdebug.h +++ b/main/source/dlls/wxdebug.h @@ -1,137 +1,137 @@ -#ifndef __WXDEBUG__ -#define __WXDEBUG__ - -// This library provides fairly straight forward debugging functionality, this -// is split into two main sections. The first is assertion handling, there are -// three types of assertions provided here. The most commonly used one is the -// ASSERT(condition) macro which will pop up a message box including the file -// and line number if the condition evaluates to FALSE. Then there is the -// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will -// still be executed in NON debug builds. The final type of assertion is the -// KASSERT macro which is more suitable for pure (perhaps kernel) filters as -// the condition is printed onto the debugger rather than in a message box. -// -// The other part of the debug module facilties is general purpose logging. -// This is accessed by calling DbgLog(). The function takes a type and level -// field which define the type of informational string you are presenting and -// it's relative importance. The type field can be a combination (one or more) -// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level -// is a DWORD value where zero defines highest important. Use of zero as the -// debug logging level is to be encouraged ONLY for major errors or events as -// they will ALWAYS be displayed on the debugger. Other debug output has it's -// level matched against the current debug output level stored in the registry -// for this module and if less than the current setting it will be displayed. -// -// Each module or executable has it's own debug output level for each of the -// five types. These are read in when the DbgInitialise function is called -// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL -// is loaded, executables must call it explicitely with the module instance -// handle given to them through the WINMAIN entry point. An executable must -// also call DbgTerminate when they have finished to clean up the resources -// the debug library uses, once again this is done automatically for DLLs - -// These are the five different categories of logging information - -#ifdef _DEBUG - - -enum -{ - LOG_TRACE = 0x00000001, // General tracing - LOG_ENTRY = 0x00000002, // Function entry logging - LOG_EXIT = 0x00000004, // Function exit logging - LOG_MEMORY = 0x00000008, // Memory alloc/free debugging - LOG_ERROR = 0x00000010, // Error notification - LOG_UNUSED0 = 0x00000020, // reserved - LOG_UNUSED1 = 0x00000040, // reserved - LOG_UNUSED2 = 0x00000080, // reserved - LOG_CHUM = 0x00000100, // Chumtoad debugging - LOG_LEECH = 0x00000200, // Leech debugging - LOG_ICHTHYOSAUR = 0x00000400, // Ichthyosaur debugging -}; - - -// These are public but should be called only by the DLLMain function -void WINAPI DbgInitialise(HINSTANCE hInst); -void WINAPI DbgTerminate(); -// These are public but should be called by macro only -void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); -void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); -void WINAPI DbgOutString(LPCTSTR psz); - - -// These are the macros that should be used in code. - -#define DBGASSERT(_x_) \ - if (!(_x_)) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - -#define DBGBREAK(_x_) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - -#define DBGASSERTEXECUTE(_x_) DBGASSERT(_x_) - -#define DBGLOG(_x_) DbgLogInfo _x_ - -#define DBGOUT(_x_) DbgOutString(_x_) - -#define ValidateReadPtr(p,cb) \ - {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ - DBGBREAK("Invalid read pointer");} - -#define ValidateWritePtr(p,cb) \ - {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ - DBGBREAK("Invalid write pointer");} - -#define ValidateReadWritePtr(p,cb) \ - {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} - -#define ValidateStringPtr(p) \ - {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid string pointer");} - -#define ValidateStringPtrA(p) \ - {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid ANSII string pointer");} - -#define ValidateStringPtrW(p) \ - {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid UNICODE string pointer");} - -#else // !_DEBUG - -// Retail builds make public debug functions inert - WARNING the source -// files do not define or build any of the entry points in debug builds -// (public entry points compile to nothing) so if you go trying to call -// any of the private entry points in your source they won't compile - -#define DBGASSERT(_x_) -#define DBGBREAK(_x_) -#define DBGASSERTEXECUTE(_x_) _x_ -#define DBGLOG(_x_) -#define DBGOUT(_x_) -#define ValidateReadPtr(p,cb) -#define ValidateWritePtr(p,cb) -#define ValidateReadWritePtr(p,cb) -#define ValidateStringPtr(p) -#define ValidateStringPtrA(p) -#define ValidateStringPtrW(p) - -#endif // !_DEBUG - - -#ifndef REMIND - // REMIND macro - generates warning as reminder to complete coding - // (eg) usage: - // - // #pragma message (REMIND("Add automation support")) - - - #define REMINDQUOTE(x) #x - #define REMINDQQUOTE(y) REMINDQUOTE(y) - #define REMIND(str) __FILE__ "(" REMINDQQUOTE(__LINE__) ") : " str -#endif - -#endif // __WXDEBUG__ - - +#ifndef __WXDEBUG__ +#define __WXDEBUG__ + +// This library provides fairly straight forward debugging functionality, this +// is split into two main sections. The first is assertion handling, there are +// three types of assertions provided here. The most commonly used one is the +// ASSERT(condition) macro which will pop up a message box including the file +// and line number if the condition evaluates to FALSE. Then there is the +// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will +// still be executed in NON debug builds. The final type of assertion is the +// KASSERT macro which is more suitable for pure (perhaps kernel) filters as +// the condition is printed onto the debugger rather than in a message box. +// +// The other part of the debug module facilties is general purpose logging. +// This is accessed by calling DbgLog(). The function takes a type and level +// field which define the type of informational string you are presenting and +// it's relative importance. The type field can be a combination (one or more) +// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level +// is a DWORD value where zero defines highest important. Use of zero as the +// debug logging level is to be encouraged ONLY for major errors or events as +// they will ALWAYS be displayed on the debugger. Other debug output has it's +// level matched against the current debug output level stored in the registry +// for this module and if less than the current setting it will be displayed. +// +// Each module or executable has it's own debug output level for each of the +// five types. These are read in when the DbgInitialise function is called +// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL +// is loaded, executables must call it explicitely with the module instance +// handle given to them through the WINMAIN entry point. An executable must +// also call DbgTerminate when they have finished to clean up the resources +// the debug library uses, once again this is done automatically for DLLs + +// These are the five different categories of logging information + +#ifdef _DEBUG + + +enum +{ + LOG_TRACE = 0x00000001, // General tracing + LOG_ENTRY = 0x00000002, // Function entry logging + LOG_EXIT = 0x00000004, // Function exit logging + LOG_MEMORY = 0x00000008, // Memory alloc/free debugging + LOG_ERROR = 0x00000010, // Error notification + LOG_UNUSED0 = 0x00000020, // reserved + LOG_UNUSED1 = 0x00000040, // reserved + LOG_UNUSED2 = 0x00000080, // reserved + LOG_CHUM = 0x00000100, // Chumtoad debugging + LOG_LEECH = 0x00000200, // Leech debugging + LOG_ICHTHYOSAUR = 0x00000400, // Ichthyosaur debugging +}; + + +// These are public but should be called only by the DLLMain function +void WINAPI DbgInitialise(HINSTANCE hInst); +void WINAPI DbgTerminate(); +// These are public but should be called by macro only +void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); +void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); +void WINAPI DbgOutString(LPCTSTR psz); + + +// These are the macros that should be used in code. + +#define DBGASSERT(_x_) \ + if (!(_x_)) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + +#define DBGBREAK(_x_) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + +#define DBGASSERTEXECUTE(_x_) DBGASSERT(_x_) + +#define DBGLOG(_x_) DbgLogInfo _x_ + +#define DBGOUT(_x_) DbgOutString(_x_) + +#define ValidateReadPtr(p,cb) \ + {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ + DBGBREAK("Invalid read pointer");} + +#define ValidateWritePtr(p,cb) \ + {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ + DBGBREAK("Invalid write pointer");} + +#define ValidateReadWritePtr(p,cb) \ + {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} + +#define ValidateStringPtr(p) \ + {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ + DBGBREAK("Invalid string pointer");} + +#define ValidateStringPtrA(p) \ + {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ + DBGBREAK("Invalid ANSII string pointer");} + +#define ValidateStringPtrW(p) \ + {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ + DBGBREAK("Invalid UNICODE string pointer");} + +#else // !_DEBUG + +// Retail builds make public debug functions inert - WARNING the source +// files do not define or build any of the entry points in debug builds +// (public entry points compile to nothing) so if you go trying to call +// any of the private entry points in your source they won't compile + +#define DBGASSERT(_x_) +#define DBGBREAK(_x_) +#define DBGASSERTEXECUTE(_x_) _x_ +#define DBGLOG(_x_) +#define DBGOUT(_x_) +#define ValidateReadPtr(p,cb) +#define ValidateWritePtr(p,cb) +#define ValidateReadWritePtr(p,cb) +#define ValidateStringPtr(p) +#define ValidateStringPtrA(p) +#define ValidateStringPtrW(p) + +#endif // !_DEBUG + + +#ifndef REMIND + // REMIND macro - generates warning as reminder to complete coding + // (eg) usage: + // + // #pragma message (REMIND("Add automation support")) + + + #define REMINDQUOTE(x) #x + #define REMINDQQUOTE(y) REMINDQUOTE(y) + #define REMIND(str) __FILE__ "(" REMINDQQUOTE(__LINE__) ") : " str +#endif + +#endif // __WXDEBUG__ + + diff --git a/main/source/dlls/xen.cpp b/main/source/dlls/xen.cpp index 606b6489..89b743d2 100644 --- a/main/source/dlls/xen.cpp +++ b/main/source/dlls/xen.cpp @@ -1,584 +1,584 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "animation.h" -#include "effects.h" - - -#define XEN_PLANT_GLOW_SPRITE "sprites/flare3.spr" -#define XEN_PLANT_HIDE_TIME 5 - - -class CActAnimating : public CBaseAnimating -{ -public: - void SetActivity( Activity act ); - inline Activity GetActivity( void ) { return m_Activity; } - - virtual int ObjectCaps( void ) { return CBaseAnimating :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - Activity m_Activity; -}; - -TYPEDESCRIPTION CActAnimating::m_SaveData[] = -{ - DEFINE_FIELD( CActAnimating, m_Activity, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CActAnimating, CBaseAnimating ); - -void CActAnimating :: SetActivity( Activity act ) -{ - int sequence = LookupActivity( act ); - if ( sequence != ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = sequence; - m_Activity = act; - pev->frame = 0; - ResetSequenceInfo( ); - } -} - - - - -class CXenPLight : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); - - void LightOn( void ); - void LightOff( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - CSprite *m_pGlow; -}; - -LINK_ENTITY_TO_CLASS( xen_plantlight, CXenPLight ); - -TYPEDESCRIPTION CXenPLight::m_SaveData[] = -{ - DEFINE_FIELD( CXenPLight, m_pGlow, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CXenPLight, CActAnimating ); - -void CXenPLight :: Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT(pev), "models/light.mdl" ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_TRIGGER; - - UTIL_SetSize( pev, Vector(-80,-80,0), Vector(80,80,32)); - SetActivity( ACT_IDLE ); - pev->nextthink = gpGlobals->time + 0.1; - pev->frame = RANDOM_FLOAT(0,255); - - m_pGlow = CSprite::SpriteCreate( XEN_PLANT_GLOW_SPRITE, pev->origin + Vector((float)0, (float)0, (float)((pev->mins.z+pev->maxs.z)*0.5)), FALSE ); - m_pGlow->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); - m_pGlow->SetAttachment( edict(), 1 ); -} - - -void CXenPLight :: Precache( void ) -{ - PRECACHE_MODEL( "models/light.mdl" ); - PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); -} - - -void CXenPLight :: Think( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - switch( GetActivity() ) - { - case ACT_CROUCH: - if ( m_fSequenceFinished ) - { - SetActivity( ACT_CROUCHIDLE ); - LightOff(); - } - break; - - case ACT_CROUCHIDLE: - if ( gpGlobals->time > pev->dmgtime ) - { - SetActivity( ACT_STAND ); - LightOn(); - } - break; - - case ACT_STAND: - if ( m_fSequenceFinished ) - SetActivity( ACT_IDLE ); - break; - - case ACT_IDLE: - default: - break; - } -} - - -void CXenPLight :: Touch( CBaseEntity *pOther ) -{ - if ( pOther->IsPlayer() ) - { - pev->dmgtime = gpGlobals->time + XEN_PLANT_HIDE_TIME; - if ( GetActivity() == ACT_IDLE || GetActivity() == ACT_STAND ) - { - SetActivity( ACT_CROUCH ); - } - } -} - - -void CXenPLight :: LightOn( void ) -{ - SUB_UseTargets( this, USE_ON, 0 ); - if ( m_pGlow ) - m_pGlow->pev->effects &= ~EF_NODRAW; -} - - -void CXenPLight :: LightOff( void ) -{ - SUB_UseTargets( this, USE_OFF, 0 ); - if ( m_pGlow ) - m_pGlow->pev->effects |= EF_NODRAW; -} - - - -class CXenHair : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( xen_hair, CXenHair ); - -#define SF_HAIR_SYNC 0x0001 - -void CXenHair::Spawn( void ) -{ - Precache(); - SET_MODEL( edict(), "models/hair.mdl" ); - UTIL_SetSize( pev, Vector(-4,-4,0), Vector(4,4,32)); - pev->sequence = 0; - - if ( !(pev->spawnflags & SF_HAIR_SYNC) ) - { - pev->frame = RANDOM_FLOAT(0,255); - pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - } - ResetSequenceInfo( ); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit -} - - -void CXenHair::Think( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.5; -} - - -void CXenHair::Precache( void ) -{ - PRECACHE_MODEL( "models/hair.mdl" ); -} - - -class CXenTreeTrigger : public CBaseEntity -{ -public: - void Touch( CBaseEntity *pOther ); - static CXenTreeTrigger *TriggerCreate( edict_t *pOwner, const Vector &position ); -}; -LINK_ENTITY_TO_CLASS( xen_ttrigger, CXenTreeTrigger ); - -CXenTreeTrigger *CXenTreeTrigger :: TriggerCreate( edict_t *pOwner, const Vector &position ) -{ - CXenTreeTrigger *pTrigger = GetClassPtr( (CXenTreeTrigger *)NULL ); - pTrigger->pev->origin = position; - pTrigger->pev->classname = MAKE_STRING("xen_ttrigger"); - pTrigger->pev->solid = SOLID_TRIGGER; - pTrigger->pev->movetype = MOVETYPE_NONE; - pTrigger->pev->owner = pOwner; - - return pTrigger; -} - - -void CXenTreeTrigger::Touch( CBaseEntity *pOther ) -{ - if ( pev->owner ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(pev->owner); - pEntity->Touch( pOther ); - } -} - - -#define TREE_AE_ATTACK 1 - -class CXenTree : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Attack(); return 0; } - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Attack( void ); - int Classify( void ) { return CLASS_BARNACLE; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - -private: - CXenTreeTrigger *m_pTrigger; -}; - -LINK_ENTITY_TO_CLASS( xen_tree, CXenTree ); - -TYPEDESCRIPTION CXenTree::m_SaveData[] = -{ - DEFINE_FIELD( CXenTree, m_pTrigger, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CXenTree, CActAnimating ); - -void CXenTree :: Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT(pev), "models/tree.mdl" ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - - pev->takedamage = DAMAGE_YES; - - UTIL_SetSize( pev, Vector(-30,-30,0), Vector(30,30,188)); - SetActivity( ACT_IDLE ); - pev->nextthink = gpGlobals->time + 0.1; - pev->frame = RANDOM_FLOAT(0,255); - pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - - Vector triggerPosition; - UTIL_MakeVectorsPrivate( pev->angles, triggerPosition, NULL, NULL ); - triggerPosition = pev->origin + (triggerPosition * 64); - // Create the trigger - m_pTrigger = CXenTreeTrigger::TriggerCreate( edict(), triggerPosition ); - UTIL_SetSize( m_pTrigger->pev, Vector( -24, -24, 0 ), Vector( 24, 24, 128 ) ); -} - -const char *CXenTree::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CXenTree::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -void CXenTree :: Precache( void ) -{ - PRECACHE_MODEL( "models/tree.mdl" ); - PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); - PRECACHE_SOUND_ARRAY( pAttackHitSounds ); - PRECACHE_SOUND_ARRAY( pAttackMissSounds ); -} - - -void CXenTree :: Touch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() && FClassnameIs( pOther->pev, "monster_bigmomma" ) ) - return; - - Attack(); -} - - -void CXenTree :: Attack( void ) -{ - if ( GetActivity() == ACT_IDLE ) - { - SetActivity( ACT_MELEE_ATTACK1 ); - pev->framerate = RANDOM_FLOAT( 1.0, 1.4 ); - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackMissSounds ); - } -} - - -void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case TREE_AE_ATTACK: - { - CBaseEntity *pList[8]; - BOOL sound = FALSE; - int count = UTIL_EntitiesInBox( pList, 8, m_pTrigger->pev->absmin, m_pTrigger->pev->absmax, FL_MONSTER|FL_CLIENT ); - Vector forward; - - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - for ( int i = 0; i < count; i++ ) - { - if ( pList[i] != this ) - { - if ( pList[i]->pev->owner != edict() ) - { - sound = TRUE; - pList[i]->TakeDamage( pev, pev, 25, DMG_CRUSH | DMG_SLASH ); - pList[i]->pev->punchangle.x = 15; - pList[i]->pev->velocity = pList[i]->pev->velocity + forward * 100; - } - } - } - - if ( sound ) - { - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds ); - } - } - return; - } - - CActAnimating::HandleAnimEvent( pEvent ); -} - -void CXenTree :: Think( void ) -{ - float flInterval = StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( flInterval ); - - switch( GetActivity() ) - { - case ACT_MELEE_ATTACK1: - if ( m_fSequenceFinished ) - { - SetActivity( ACT_IDLE ); - pev->framerate = RANDOM_FLOAT( 0.6, 1.4 ); - } - break; - - default: - case ACT_IDLE: - break; - - } -} - - -// UNDONE: These need to smoke somehow when they take damage -// Touch behavior? -// Cause damage in smoke area - -// -// Spores -// -class CXenSpore : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Attack(); return 0; } -// void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Attack( void ) {} - - static const char *pModelNames[]; -}; - -class CXenSporeSmall : public CXenSpore -{ - void Spawn( void ); -}; - -class CXenSporeMed : public CXenSpore -{ - void Spawn( void ); -}; - -class CXenSporeLarge : public CXenSpore -{ - void Spawn( void ); - - static const Vector m_hullSizes[]; -}; - -// Fake collision box for big spores -class CXenHull : public CPointEntity -{ -public: - static CXenHull *CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ); - int Classify( void ) { return CLASS_BARNACLE; } -}; - -CXenHull *CXenHull :: CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ) -{ - CXenHull *pHull = GetClassPtr( (CXenHull *)NULL ); - - UTIL_SetOrigin( pHull->pev, source->pev->origin + offset ); - SET_MODEL( pHull->edict(), STRING(source->pev->model) ); - pHull->pev->solid = SOLID_BBOX; - pHull->pev->classname = MAKE_STRING("xen_hull"); - pHull->pev->movetype = MOVETYPE_NONE; - pHull->pev->owner = source->edict(); - UTIL_SetSize( pHull->pev, mins, maxs ); - pHull->pev->renderamt = 0; - pHull->pev->rendermode = kRenderTransTexture; - // pHull->pev->effects = EF_NODRAW; - - return pHull; -} - - -LINK_ENTITY_TO_CLASS( xen_spore_small, CXenSporeSmall ); -LINK_ENTITY_TO_CLASS( xen_spore_medium, CXenSporeMed ); -LINK_ENTITY_TO_CLASS( xen_spore_large, CXenSporeLarge ); -LINK_ENTITY_TO_CLASS( xen_hull, CXenHull ); - -void CXenSporeSmall::Spawn( void ) -{ - pev->skin = 0; - CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-16,-16,0), Vector(16,16,64)); -} -void CXenSporeMed::Spawn( void ) -{ - pev->skin = 1; - CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-40,-40,0), Vector(40,40,120)); -} - - -// I just eyeballed these -- fill in hulls for the legs -const Vector CXenSporeLarge::m_hullSizes[] = -{ - Vector( 90, -25, 0 ), - Vector( 25, 75, 0 ), - Vector( -15, -100, 0 ), - Vector( -90, -35, 0 ), - Vector( -90, 60, 0 ), -}; - -void CXenSporeLarge::Spawn( void ) -{ - pev->skin = 2; - CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-48,-48,110), Vector(48,48,240)); - - Vector forward, right; - - UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); - - // Rotate the leg hulls into position - for ( int i = 0; i < ARRAYSIZE(m_hullSizes); i++ ) - CXenHull :: CreateHull( this, Vector(-12, -12, 0 ), Vector( 12, 12, 120 ), (m_hullSizes[i].x * forward) + (m_hullSizes[i].y * right) ); -} - -void CXenSpore :: Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT(pev), pModelNames[pev->skin] ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - pev->takedamage = DAMAGE_YES; - -// SetActivity( ACT_IDLE ); - pev->sequence = 0; - pev->frame = RANDOM_FLOAT(0,255); - pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - ResetSequenceInfo( ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit -} - -const char *CXenSpore::pModelNames[] = -{ - "models/fungus(small).mdl", - "models/fungus.mdl", - "models/fungus(large).mdl", -}; - - -void CXenSpore :: Precache( void ) -{ - PRECACHE_MODEL( (char *)pModelNames[pev->skin] ); -} - - -void CXenSpore :: Touch( CBaseEntity *pOther ) -{ -} - - -void CXenSpore :: Think( void ) -{ - float flInterval = StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - -#if 0 - DispatchAnimEvents( flInterval ); - - switch( GetActivity() ) - { - default: - case ACT_IDLE: - break; - - } -#endif -} - - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "animation.h" +#include "effects.h" + + +#define XEN_PLANT_GLOW_SPRITE "sprites/flare3.spr" +#define XEN_PLANT_HIDE_TIME 5 + + +class CActAnimating : public CBaseAnimating +{ +public: + void SetActivity( Activity act ); + inline Activity GetActivity( void ) { return m_Activity; } + + virtual int ObjectCaps( void ) { return CBaseAnimating :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + +private: + Activity m_Activity; +}; + +TYPEDESCRIPTION CActAnimating::m_SaveData[] = +{ + DEFINE_FIELD( CActAnimating, m_Activity, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE( CActAnimating, CBaseAnimating ); + +void CActAnimating :: SetActivity( Activity act ) +{ + int sequence = LookupActivity( act ); + if ( sequence != ACTIVITY_NOT_AVAILABLE ) + { + pev->sequence = sequence; + m_Activity = act; + pev->frame = 0; + ResetSequenceInfo( ); + } +} + + + + +class CXenPLight : public CActAnimating +{ +public: + void Spawn( void ); + void Precache( void ); + void Touch( CBaseEntity *pOther ); + void Think( void ); + + void LightOn( void ); + void LightOff( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + +private: + CSprite *m_pGlow; +}; + +LINK_ENTITY_TO_CLASS( xen_plantlight, CXenPLight ); + +TYPEDESCRIPTION CXenPLight::m_SaveData[] = +{ + DEFINE_FIELD( CXenPLight, m_pGlow, FIELD_CLASSPTR ), +}; + +IMPLEMENT_SAVERESTORE( CXenPLight, CActAnimating ); + +void CXenPLight :: Spawn( void ) +{ + Precache(); + + SET_MODEL( ENT(pev), "models/light.mdl" ); + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_TRIGGER; + + UTIL_SetSize( pev, Vector(-80,-80,0), Vector(80,80,32)); + SetActivity( ACT_IDLE ); + pev->nextthink = gpGlobals->time + 0.1; + pev->frame = RANDOM_FLOAT(0,255); + + m_pGlow = CSprite::SpriteCreate( XEN_PLANT_GLOW_SPRITE, pev->origin + Vector((float)0, (float)0, (float)((pev->mins.z+pev->maxs.z)*0.5)), FALSE ); + m_pGlow->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); + m_pGlow->SetAttachment( edict(), 1 ); +} + + +void CXenPLight :: Precache( void ) +{ + PRECACHE_MODEL( "models/light.mdl" ); + PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); +} + + +void CXenPLight :: Think( void ) +{ + StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + + switch( GetActivity() ) + { + case ACT_CROUCH: + if ( m_fSequenceFinished ) + { + SetActivity( ACT_CROUCHIDLE ); + LightOff(); + } + break; + + case ACT_CROUCHIDLE: + if ( gpGlobals->time > pev->dmgtime ) + { + SetActivity( ACT_STAND ); + LightOn(); + } + break; + + case ACT_STAND: + if ( m_fSequenceFinished ) + SetActivity( ACT_IDLE ); + break; + + case ACT_IDLE: + default: + break; + } +} + + +void CXenPLight :: Touch( CBaseEntity *pOther ) +{ + if ( pOther->IsPlayer() ) + { + pev->dmgtime = gpGlobals->time + XEN_PLANT_HIDE_TIME; + if ( GetActivity() == ACT_IDLE || GetActivity() == ACT_STAND ) + { + SetActivity( ACT_CROUCH ); + } + } +} + + +void CXenPLight :: LightOn( void ) +{ + SUB_UseTargets( this, USE_ON, 0 ); + if ( m_pGlow ) + m_pGlow->pev->effects &= ~EF_NODRAW; +} + + +void CXenPLight :: LightOff( void ) +{ + SUB_UseTargets( this, USE_OFF, 0 ); + if ( m_pGlow ) + m_pGlow->pev->effects |= EF_NODRAW; +} + + + +class CXenHair : public CActAnimating +{ +public: + void Spawn( void ); + void Precache( void ); + void Think( void ); +}; + +LINK_ENTITY_TO_CLASS( xen_hair, CXenHair ); + +#define SF_HAIR_SYNC 0x0001 + +void CXenHair::Spawn( void ) +{ + Precache(); + SET_MODEL( edict(), "models/hair.mdl" ); + UTIL_SetSize( pev, Vector(-4,-4,0), Vector(4,4,32)); + pev->sequence = 0; + + if ( !(pev->spawnflags & SF_HAIR_SYNC) ) + { + pev->frame = RANDOM_FLOAT(0,255); + pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); + } + ResetSequenceInfo( ); + + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit +} + + +void CXenHair::Think( void ) +{ + StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.5; +} + + +void CXenHair::Precache( void ) +{ + PRECACHE_MODEL( "models/hair.mdl" ); +} + + +class CXenTreeTrigger : public CBaseEntity +{ +public: + void Touch( CBaseEntity *pOther ); + static CXenTreeTrigger *TriggerCreate( edict_t *pOwner, const Vector &position ); +}; +LINK_ENTITY_TO_CLASS( xen_ttrigger, CXenTreeTrigger ); + +CXenTreeTrigger *CXenTreeTrigger :: TriggerCreate( edict_t *pOwner, const Vector &position ) +{ + CXenTreeTrigger *pTrigger = GetClassPtr( (CXenTreeTrigger *)NULL ); + pTrigger->pev->origin = position; + pTrigger->pev->classname = MAKE_STRING("xen_ttrigger"); + pTrigger->pev->solid = SOLID_TRIGGER; + pTrigger->pev->movetype = MOVETYPE_NONE; + pTrigger->pev->owner = pOwner; + + return pTrigger; +} + + +void CXenTreeTrigger::Touch( CBaseEntity *pOther ) +{ + if ( pev->owner ) + { + CBaseEntity *pEntity = CBaseEntity::Instance(pev->owner); + pEntity->Touch( pOther ); + } +} + + +#define TREE_AE_ATTACK 1 + +class CXenTree : public CActAnimating +{ +public: + void Spawn( void ); + void Precache( void ); + void Touch( CBaseEntity *pOther ); + void Think( void ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Attack(); return 0; } + void HandleAnimEvent( MonsterEvent_t *pEvent ); + void Attack( void ); + int Classify( void ) { return CLASS_BARNACLE; } + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + static const char *pAttackHitSounds[]; + static const char *pAttackMissSounds[]; + +private: + CXenTreeTrigger *m_pTrigger; +}; + +LINK_ENTITY_TO_CLASS( xen_tree, CXenTree ); + +TYPEDESCRIPTION CXenTree::m_SaveData[] = +{ + DEFINE_FIELD( CXenTree, m_pTrigger, FIELD_CLASSPTR ), +}; + +IMPLEMENT_SAVERESTORE( CXenTree, CActAnimating ); + +void CXenTree :: Spawn( void ) +{ + Precache(); + + SET_MODEL( ENT(pev), "models/tree.mdl" ); + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_BBOX; + + pev->takedamage = DAMAGE_YES; + + UTIL_SetSize( pev, Vector(-30,-30,0), Vector(30,30,188)); + SetActivity( ACT_IDLE ); + pev->nextthink = gpGlobals->time + 0.1; + pev->frame = RANDOM_FLOAT(0,255); + pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); + + Vector triggerPosition; + UTIL_MakeVectorsPrivate( pev->angles, triggerPosition, NULL, NULL ); + triggerPosition = pev->origin + (triggerPosition * 64); + // Create the trigger + m_pTrigger = CXenTreeTrigger::TriggerCreate( edict(), triggerPosition ); + UTIL_SetSize( m_pTrigger->pev, Vector( -24, -24, 0 ), Vector( 24, 24, 128 ) ); +} + +const char *CXenTree::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CXenTree::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + +void CXenTree :: Precache( void ) +{ + PRECACHE_MODEL( "models/tree.mdl" ); + PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); + PRECACHE_SOUND_ARRAY( pAttackHitSounds ); + PRECACHE_SOUND_ARRAY( pAttackMissSounds ); +} + + +void CXenTree :: Touch( CBaseEntity *pOther ) +{ + if ( !pOther->IsPlayer() && FClassnameIs( pOther->pev, "monster_bigmomma" ) ) + return; + + Attack(); +} + + +void CXenTree :: Attack( void ) +{ + if ( GetActivity() == ACT_IDLE ) + { + SetActivity( ACT_MELEE_ATTACK1 ); + pev->framerate = RANDOM_FLOAT( 1.0, 1.4 ); + EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackMissSounds ); + } +} + + +void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case TREE_AE_ATTACK: + { + CBaseEntity *pList[8]; + BOOL sound = FALSE; + int count = UTIL_EntitiesInBox( pList, 8, m_pTrigger->pev->absmin, m_pTrigger->pev->absmax, FL_MONSTER|FL_CLIENT ); + Vector forward; + + UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); + + for ( int i = 0; i < count; i++ ) + { + if ( pList[i] != this ) + { + if ( pList[i]->pev->owner != edict() ) + { + sound = TRUE; + pList[i]->TakeDamage( pev, pev, 25, DMG_CRUSH | DMG_SLASH ); + pList[i]->pev->punchangle.x = 15; + pList[i]->pev->velocity = pList[i]->pev->velocity + forward * 100; + } + } + } + + if ( sound ) + { + EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds ); + } + } + return; + } + + CActAnimating::HandleAnimEvent( pEvent ); +} + +void CXenTree :: Think( void ) +{ + float flInterval = StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + DispatchAnimEvents( flInterval ); + + switch( GetActivity() ) + { + case ACT_MELEE_ATTACK1: + if ( m_fSequenceFinished ) + { + SetActivity( ACT_IDLE ); + pev->framerate = RANDOM_FLOAT( 0.6, 1.4 ); + } + break; + + default: + case ACT_IDLE: + break; + + } +} + + +// UNDONE: These need to smoke somehow when they take damage +// Touch behavior? +// Cause damage in smoke area + +// +// Spores +// +class CXenSpore : public CActAnimating +{ +public: + void Spawn( void ); + void Precache( void ); + void Touch( CBaseEntity *pOther ); + void Think( void ); + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Attack(); return 0; } +// void HandleAnimEvent( MonsterEvent_t *pEvent ); + void Attack( void ) {} + + static const char *pModelNames[]; +}; + +class CXenSporeSmall : public CXenSpore +{ + void Spawn( void ); +}; + +class CXenSporeMed : public CXenSpore +{ + void Spawn( void ); +}; + +class CXenSporeLarge : public CXenSpore +{ + void Spawn( void ); + + static const Vector m_hullSizes[]; +}; + +// Fake collision box for big spores +class CXenHull : public CPointEntity +{ +public: + static CXenHull *CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ); + int Classify( void ) { return CLASS_BARNACLE; } +}; + +CXenHull *CXenHull :: CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ) +{ + CXenHull *pHull = GetClassPtr( (CXenHull *)NULL ); + + UTIL_SetOrigin( pHull->pev, source->pev->origin + offset ); + SET_MODEL( pHull->edict(), STRING(source->pev->model) ); + pHull->pev->solid = SOLID_BBOX; + pHull->pev->classname = MAKE_STRING("xen_hull"); + pHull->pev->movetype = MOVETYPE_NONE; + pHull->pev->owner = source->edict(); + UTIL_SetSize( pHull->pev, mins, maxs ); + pHull->pev->renderamt = 0; + pHull->pev->rendermode = kRenderTransTexture; + // pHull->pev->effects = EF_NODRAW; + + return pHull; +} + + +LINK_ENTITY_TO_CLASS( xen_spore_small, CXenSporeSmall ); +LINK_ENTITY_TO_CLASS( xen_spore_medium, CXenSporeMed ); +LINK_ENTITY_TO_CLASS( xen_spore_large, CXenSporeLarge ); +LINK_ENTITY_TO_CLASS( xen_hull, CXenHull ); + +void CXenSporeSmall::Spawn( void ) +{ + pev->skin = 0; + CXenSpore::Spawn(); + UTIL_SetSize( pev, Vector(-16,-16,0), Vector(16,16,64)); +} +void CXenSporeMed::Spawn( void ) +{ + pev->skin = 1; + CXenSpore::Spawn(); + UTIL_SetSize( pev, Vector(-40,-40,0), Vector(40,40,120)); +} + + +// I just eyeballed these -- fill in hulls for the legs +const Vector CXenSporeLarge::m_hullSizes[] = +{ + Vector( 90, -25, 0 ), + Vector( 25, 75, 0 ), + Vector( -15, -100, 0 ), + Vector( -90, -35, 0 ), + Vector( -90, 60, 0 ), +}; + +void CXenSporeLarge::Spawn( void ) +{ + pev->skin = 2; + CXenSpore::Spawn(); + UTIL_SetSize( pev, Vector(-48,-48,110), Vector(48,48,240)); + + Vector forward, right; + + UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); + + // Rotate the leg hulls into position + for ( int i = 0; i < ARRAYSIZE(m_hullSizes); i++ ) + CXenHull :: CreateHull( this, Vector(-12, -12, 0 ), Vector( 12, 12, 120 ), (m_hullSizes[i].x * forward) + (m_hullSizes[i].y * right) ); +} + +void CXenSpore :: Spawn( void ) +{ + Precache(); + + SET_MODEL( ENT(pev), pModelNames[pev->skin] ); + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_BBOX; + pev->takedamage = DAMAGE_YES; + +// SetActivity( ACT_IDLE ); + pev->sequence = 0; + pev->frame = RANDOM_FLOAT(0,255); + pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); + ResetSequenceInfo( ); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit +} + +const char *CXenSpore::pModelNames[] = +{ + "models/fungus(small).mdl", + "models/fungus.mdl", + "models/fungus(large).mdl", +}; + + +void CXenSpore :: Precache( void ) +{ + PRECACHE_MODEL( (char *)pModelNames[pev->skin] ); +} + + +void CXenSpore :: Touch( CBaseEntity *pOther ) +{ +} + + +void CXenSpore :: Think( void ) +{ + float flInterval = StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + +#if 0 + DispatchAnimEvents( flInterval ); + + switch( GetActivity() ) + { + default: + case ACT_IDLE: + break; + + } +#endif +} + + diff --git a/main/source/dlls/zombie.cpp b/main/source/dlls/zombie.cpp index 127cb261..b1c4975c 100644 --- a/main/source/dlls/zombie.cpp +++ b/main/source/dlls/zombie.cpp @@ -1,346 +1,346 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Zombie -//========================================================= - -// UNDONE: Don't flinch every time you get hit - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ZOMBIE_AE_ATTACK_RIGHT 0x01 -#define ZOMBIE_AE_ATTACK_LEFT 0x02 -#define ZOMBIE_AE_ATTACK_BOTH 0x03 - -#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs - -class CZombie : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int IgnoreConditions ( void ); - - float m_flNextFlinch; - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSound( void ); - - static const char *pAttackSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - - // No range attacks - BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); -}; - -LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ); - -const char *CZombie::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CZombie::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CZombie::pAttackSounds[] = -{ - "zombie/zo_attack1.wav", - "zombie/zo_attack2.wav", -}; - -const char *CZombie::pIdleSounds[] = -{ - "zombie/zo_idle1.wav", - "zombie/zo_idle2.wav", - "zombie/zo_idle3.wav", - "zombie/zo_idle4.wav", -}; - -const char *CZombie::pAlertSounds[] = -{ - "zombie/zo_alert10.wav", - "zombie/zo_alert20.wav", - "zombie/zo_alert30.wav", -}; - -const char *CZombie::pPainSounds[] = -{ - "zombie/zo_pain1.wav", - "zombie/zo_pain2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CZombie :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CZombie :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - -#if 0 - switch ( m_Activity ) - { - } -#endif - - pev->yaw_speed = ys; -} - -int CZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Take 30% damage from bullets - if ( bitsDamageType == DMG_BULLET ) - { - Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; - vecDir = vecDir.Normalize(); - float flForce = DamageForce( flDamage ); - pev->velocity = pev->velocity + vecDir * flForce; - flDamage *= 0.3; - } - - // HACK HACK -- until we fix this. - if ( IsAlive() ) - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CZombie :: PainSound( void ) -{ - int pitch = 95 + RANDOM_LONG(0,9); - - if (RANDOM_LONG(0,5) < 2) - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie :: AlertSound( void ) -{ - int pitch = 95 + RANDOM_LONG(0,9); - - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie :: IdleSound( void ) -{ - int pitch = 95 + RANDOM_LONG(0,9); - - // Play a random idle sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pIdleSounds[ RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); -} - -void CZombie :: AttackSound( void ) -{ - // Play a random attack sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case ZOMBIE_AE_ATTACK_RIGHT: - { - // do stuff for this event. - // ALERT( at_console, "Slash right!\n" ); - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; - } - // Play a random attack hit sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - else // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - if (RANDOM_LONG(0,1)) - AttackSound(); - } - break; - - case ZOMBIE_AE_ATTACK_LEFT: - { - // do stuff for this event. - // ALERT( at_console, "Slash left!\n" ); - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = 18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; - } - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - else - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - if (RANDOM_LONG(0,1)) - AttackSound(); - } - break; - - case ZOMBIE_AE_ATTACK_BOTH: - { - // do stuff for this event. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgBothSlash, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; - } - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - else - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - if (RANDOM_LONG(0,1)) - AttackSound(); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CZombie :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/zombie.mdl"); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.zombieHealth; - pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_DOORS_GROUP; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CZombie :: Precache() -{ - int i; - - PRECACHE_MODEL("models/zombie.mdl"); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - - -int CZombie::IgnoreConditions ( void ) -{ - int iIgnore = CBaseMonster::IgnoreConditions(); - - if ((m_Activity == ACT_MELEE_ATTACK1) || (m_Activity == ACT_MELEE_ATTACK1)) - { -#if 0 - if (pev->health < 20) - iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE); - else -#endif - if (m_flNextFlinch >= gpGlobals->time) - iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE); - } - - if ((m_Activity == ACT_SMALL_FLINCH) || (m_Activity == ACT_BIG_FLINCH)) - { - if (m_flNextFlinch < gpGlobals->time) - m_flNextFlinch = gpGlobals->time + ZOMBIE_FLINCH_DELAY; - } - - return iIgnore; - +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Zombie +//========================================================= + +// UNDONE: Don't flinch every time you get hit + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "schedule.h" + + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define ZOMBIE_AE_ATTACK_RIGHT 0x01 +#define ZOMBIE_AE_ATTACK_LEFT 0x02 +#define ZOMBIE_AE_ATTACK_BOTH 0x03 + +#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs + +class CZombie : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify ( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); + int IgnoreConditions ( void ); + + float m_flNextFlinch; + + void PainSound( void ); + void AlertSound( void ); + void IdleSound( void ); + void AttackSound( void ); + + static const char *pAttackSounds[]; + static const char *pIdleSounds[]; + static const char *pAlertSounds[]; + static const char *pPainSounds[]; + static const char *pAttackHitSounds[]; + static const char *pAttackMissSounds[]; + + // No range attacks + BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } + BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); +}; + +LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ); + +const char *CZombie::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char *CZombie::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + +const char *CZombie::pAttackSounds[] = +{ + "zombie/zo_attack1.wav", + "zombie/zo_attack2.wav", +}; + +const char *CZombie::pIdleSounds[] = +{ + "zombie/zo_idle1.wav", + "zombie/zo_idle2.wav", + "zombie/zo_idle3.wav", + "zombie/zo_idle4.wav", +}; + +const char *CZombie::pAlertSounds[] = +{ + "zombie/zo_alert10.wav", + "zombie/zo_alert20.wav", + "zombie/zo_alert30.wav", +}; + +const char *CZombie::pPainSounds[] = +{ + "zombie/zo_pain1.wav", + "zombie/zo_pain2.wav", +}; + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CZombie :: Classify ( void ) +{ + return CLASS_ALIEN_MONSTER; +} + +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CZombie :: SetYawSpeed ( void ) +{ + int ys; + + ys = 120; + +#if 0 + switch ( m_Activity ) + { + } +#endif + + pev->yaw_speed = ys; +} + +int CZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + // Take 30% damage from bullets + if ( bitsDamageType == DMG_BULLET ) + { + Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; + vecDir = vecDir.Normalize(); + float flForce = DamageForce( flDamage ); + pev->velocity = pev->velocity + vecDir * flForce; + flDamage *= 0.3; + } + + // HACK HACK -- until we fix this. + if ( IsAlive() ) + PainSound(); + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +void CZombie :: PainSound( void ) +{ + int pitch = 95 + RANDOM_LONG(0,9); + + if (RANDOM_LONG(0,5) < 2) + EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, pitch ); +} + +void CZombie :: AlertSound( void ) +{ + int pitch = 95 + RANDOM_LONG(0,9); + + EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM, 0, pitch ); +} + +void CZombie :: IdleSound( void ) +{ + int pitch = 95 + RANDOM_LONG(0,9); + + // Play a random idle sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pIdleSounds[ RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); +} + +void CZombie :: AttackSound( void ) +{ + // Play a random attack sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); +} + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) +{ + switch( pEvent->event ) + { + case ZOMBIE_AE_ATTACK_RIGHT: + { + // do stuff for this event. + // ALERT( at_console, "Slash right!\n" ); + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); + if ( pHurt ) + { + if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + { + pHurt->pev->punchangle.z = -18; + pHurt->pev->punchangle.x = 5; + pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; + } + // Play a random attack hit sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + else // Play a random attack miss sound + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + if (RANDOM_LONG(0,1)) + AttackSound(); + } + break; + + case ZOMBIE_AE_ATTACK_LEFT: + { + // do stuff for this event. + // ALERT( at_console, "Slash left!\n" ); + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); + if ( pHurt ) + { + if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + { + pHurt->pev->punchangle.z = 18; + pHurt->pev->punchangle.x = 5; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; + } + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + else + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + if (RANDOM_LONG(0,1)) + AttackSound(); + } + break; + + case ZOMBIE_AE_ATTACK_BOTH: + { + // do stuff for this event. + CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgBothSlash, DMG_SLASH ); + if ( pHurt ) + { + if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + { + pHurt->pev->punchangle.x = 5; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; + } + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + } + else + EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); + + if (RANDOM_LONG(0,1)) + AttackSound(); + } + break; + + default: + CBaseMonster::HandleAnimEvent( pEvent ); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CZombie :: Spawn() +{ + Precache( ); + + SET_MODEL(ENT(pev), "models/zombie.mdl"); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); + + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_STEP; + m_bloodColor = BLOOD_COLOR_GREEN; + pev->health = gSkillData.zombieHealth; + pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. + m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_afCapability = bits_CAP_DOORS_GROUP; + + MonsterInit(); +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CZombie :: Precache() +{ + int i; + + PRECACHE_MODEL("models/zombie.mdl"); + + for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackHitSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackMissSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) + PRECACHE_SOUND((char *)pAttackSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) + PRECACHE_SOUND((char *)pIdleSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) + PRECACHE_SOUND((char *)pAlertSounds[i]); + + for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) + PRECACHE_SOUND((char *)pPainSounds[i]); +} + +//========================================================= +// AI Schedules Specific to this monster +//========================================================= + + + +int CZombie::IgnoreConditions ( void ) +{ + int iIgnore = CBaseMonster::IgnoreConditions(); + + if ((m_Activity == ACT_MELEE_ATTACK1) || (m_Activity == ACT_MELEE_ATTACK1)) + { +#if 0 + if (pev->health < 20) + iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE); + else +#endif + if (m_flNextFlinch >= gpGlobals->time) + iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE); + } + + if ((m_Activity == ACT_SMALL_FLINCH) || (m_Activity == ACT_BIG_FLINCH)) + { + if (m_flNextFlinch < gpGlobals->time) + m_flNextFlinch = gpGlobals->time + ZOMBIE_FLINCH_DELAY; + } + + return iIgnore; + } \ No newline at end of file diff --git a/main/source/doc/SteamApp.cfg b/main/source/doc/SteamApp.cfg index 6521ec07..1cfbc59a 100644 --- a/main/source/doc/SteamApp.cfg +++ b/main/source/doc/SteamApp.cfg @@ -1,44 +1,44 @@ -############################################################################## -# SteamApp.cfg -# -# Steam Client App configuration-override file -# -# This file is read by the Steam code in the Client -# Application, and controls configurable parameters that -# affect only that App. -# -# To be effective it must be placed in the App directory -# (for example, c:\Steam\SteamApps\me@web.com\Half-Life\). -# -############################################################################## -# -# Debug-launch settings -# -# Use these settings when you are running your application directly -# from your debugger (ie, not launching the App from the Steam UI) -# In such cases, you need to tell Steam which application -# you are running and the version you want to use. Each application has -# an ID number and each version of your application has a version ID number. -# You also need to indicate the username you are running Steam under. -# -# SteamInstallPath should point to the directory where the corresponding Steam.exe -# resides -# -# To do a debug launch: -# -# - do at least one launch from the UI first to ensure the Minimum Footprint files -# are present -# - leave the Steam UI running -# - copy this file into the App directory -# - fill out the following config parameters -# - copy Steam.dll into the App directory -# - run the app directly or through the debugger, with "-steam" on the command line -# -# You may leave it setup and still do normal launches through the -# Steam UI. However, if you comment out the SteamInstallPath parameter, -# you must also REMOVE Steam.dll from the App directory, or else the -# launch will fail with "The local Steam service is not running". -SteamAppId=70 -SteamAppVersionId=0 -SteamInstallPath=D:\Games\Steam +############################################################################## +# SteamApp.cfg +# +# Steam Client App configuration-override file +# +# This file is read by the Steam code in the Client +# Application, and controls configurable parameters that +# affect only that App. +# +# To be effective it must be placed in the App directory +# (for example, c:\Steam\SteamApps\me@web.com\Half-Life\). +# +############################################################################## +# +# Debug-launch settings +# +# Use these settings when you are running your application directly +# from your debugger (ie, not launching the App from the Steam UI) +# In such cases, you need to tell Steam which application +# you are running and the version you want to use. Each application has +# an ID number and each version of your application has a version ID number. +# You also need to indicate the username you are running Steam under. +# +# SteamInstallPath should point to the directory where the corresponding Steam.exe +# resides +# +# To do a debug launch: +# +# - do at least one launch from the UI first to ensure the Minimum Footprint files +# are present +# - leave the Steam UI running +# - copy this file into the App directory +# - fill out the following config parameters +# - copy Steam.dll into the App directory +# - run the app directly or through the debugger, with "-steam" on the command line +# +# You may leave it setup and still do normal launches through the +# Steam UI. However, if you comment out the SteamInstallPath parameter, +# you must also REMOVE Steam.dll from the App directory, or else the +# launch will fail with "The local Steam service is not running". +SteamAppId=70 +SteamAppVersionId=0 +SteamInstallPath=D:\Games\Steam SteamAppUser=steam@overmind.org \ No newline at end of file diff --git a/main/source/doc/metamod-NS.txt b/main/source/doc/metamod-NS.txt index 77f9e556..c1a2605e 100644 --- a/main/source/doc/metamod-NS.txt +++ b/main/source/doc/metamod-NS.txt @@ -1,142 +1,142 @@ -// vim: set ft=cpp : - -// -// Metamod info file -// -// Natural Selection, v3.0 -// -// Game name: Natural Selection -// Homepage URL: http://www.natural-selection.org (sister site: http://www.readyroom.org) -// Game version: v3.0 -// Game directory: ns -// Win32 DLL name: ns.dll -// Linux SO name: ns_i386.so -// Last updated: January 29th, 2004 -// contact: flayra@overmind.org -// - -// -// Start: NS v3.0 -// -// Note, this should also include entities in previous versions of NS as well. -// - -// General entities -info_team_start -info_spectate -info_join_team -info_leave_game -info_join_autoassign -info_mapinfo -info_gameplay - -env_fog -env_gamma -env_particles -env_particles_custom - -func_weldable -func_seethrough -func_seethroughdoor -func_nobuild -func_resource - -info_location -target_mp3audio -trigger_presence -trigger_random -trigger_script - -// Used for dropped weapons -weaponbox - -// Marine structures -resourcetower -team_command -team_infportal -team_turretfactory -team_advturretfactory -team_armory -team_advarmory -team_armslab -team_prototypelab -team_observatory - -// Marine weapons -item_mine -item_catalyst -weapon_grenade -weapon_grenadegun -weapon_heavymachinegun -weapon_knife -weapon_machinegun -weapon_mine -weapon_pistol -weapon_shotgun -weapon_welder - -// Marine equipment -item_genericammo -item_health -item_heavyarmor -item_jetpack -phasegate -scan -siegeturret -turret - -// Alien structures -alienresourcetower -defensechamber -movementchamber -offensechamber -sensorychamber -team_hive -team_webstrand - -// Alien abilities/weapons (along with their projectiles) -weapon_acidrocket -weapon_acidrocketgun -weapon_bilebomb -weapon_bilebombgun -weapon_bitegun -weapon_bite2gun -weapon_blink -weapon_charge -weapon_claws -weapon_devour -weapon_divinewind -weapon_healingspray -weapon_leap -weapon_metabolize -weapon_parasite -weapon_primalscream -weapon_spit -weapon_spore -weapon_stomp -weapon_swipe -weapon_umbra -weapon_webspinner - -// Alien projectiles -spitgunprojectile -sporegunprojectile -umbracloud -webgunprojectile - -// Old/unused entities for backwards compatibility -gren_projectile -nuke -team_chemlab -team_medlab -team_nukeplant -weapon_babblergun -weapon_babblerprojectile -weapon_flamegun -weapon_nukegun -weapon_paralysis -weapon_spikegun - -// -// End: NS v3.0 +// vim: set ft=cpp : + +// +// Metamod info file +// +// Natural Selection, v3.0 +// +// Game name: Natural Selection +// Homepage URL: http://www.natural-selection.org (sister site: http://www.readyroom.org) +// Game version: v3.0 +// Game directory: ns +// Win32 DLL name: ns.dll +// Linux SO name: ns_i386.so +// Last updated: January 29th, 2004 +// contact: flayra@overmind.org +// + +// +// Start: NS v3.0 +// +// Note, this should also include entities in previous versions of NS as well. +// + +// General entities +info_team_start +info_spectate +info_join_team +info_leave_game +info_join_autoassign +info_mapinfo +info_gameplay + +env_fog +env_gamma +env_particles +env_particles_custom + +func_weldable +func_seethrough +func_seethroughdoor +func_nobuild +func_resource + +info_location +target_mp3audio +trigger_presence +trigger_random +trigger_script + +// Used for dropped weapons +weaponbox + +// Marine structures +resourcetower +team_command +team_infportal +team_turretfactory +team_advturretfactory +team_armory +team_advarmory +team_armslab +team_prototypelab +team_observatory + +// Marine weapons +item_mine +item_catalyst +weapon_grenade +weapon_grenadegun +weapon_heavymachinegun +weapon_knife +weapon_machinegun +weapon_mine +weapon_pistol +weapon_shotgun +weapon_welder + +// Marine equipment +item_genericammo +item_health +item_heavyarmor +item_jetpack +phasegate +scan +siegeturret +turret + +// Alien structures +alienresourcetower +defensechamber +movementchamber +offensechamber +sensorychamber +team_hive +team_webstrand + +// Alien abilities/weapons (along with their projectiles) +weapon_acidrocket +weapon_acidrocketgun +weapon_bilebomb +weapon_bilebombgun +weapon_bitegun +weapon_bite2gun +weapon_blink +weapon_charge +weapon_claws +weapon_devour +weapon_divinewind +weapon_healingspray +weapon_leap +weapon_metabolize +weapon_parasite +weapon_primalscream +weapon_spit +weapon_spore +weapon_stomp +weapon_swipe +weapon_umbra +weapon_webspinner + +// Alien projectiles +spitgunprojectile +sporegunprojectile +umbracloud +webgunprojectile + +// Old/unused entities for backwards compatibility +gren_projectile +nuke +team_chemlab +team_medlab +team_nukeplant +weapon_babblergun +weapon_babblerprojectile +weapon_flamegun +weapon_nukegun +weapon_paralysis +weapon_spikegun + +// +// End: NS v3.0 // \ No newline at end of file diff --git a/main/source/engine/cdll_int.h b/main/source/engine/cdll_int.h index e6053a69..f7e373e3 100644 --- a/main/source/engine/cdll_int.h +++ b/main/source/engine/cdll_int.h @@ -86,8 +86,8 @@ typedef struct hud_player_info_s char *model; short topcolor; short bottomcolor; - char padding[8]; - uint64 m_nSteamID; + char padding[8]; + uint64 m_nSteamID; } hud_player_info_t; diff --git a/main/source/engine/keydefs.h b/main/source/engine/keydefs.h index aca2c09b..45eb0691 100644 --- a/main/source/engine/keydefs.h +++ b/main/source/engine/keydefs.h @@ -1,129 +1,129 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// keydefs.h -#ifndef KEYDEFS_H -#define KEYDEFS_H -#ifdef _WIN32 -#pragma once -#endif - -// -// these are the key numbers that should be passed to Key_Event -// -#define K_TAB 9 -#define K_ENTER 13 -#define K_ESCAPE 27 -#define K_SPACE 32 - -// normal keys should be passed as lowercased ascii - -#define K_BACKSPACE 127 -#define K_UPARROW 128 -#define K_DOWNARROW 129 -#define K_LEFTARROW 130 -#define K_RIGHTARROW 131 - -#define K_ALT 132 -#define K_CTRL 133 -#define K_SHIFT 134 -#define K_F1 135 -#define K_F2 136 -#define K_F3 137 -#define K_F4 138 -#define K_F5 139 -#define K_F6 140 -#define K_F7 141 -#define K_F8 142 -#define K_F9 143 -#define K_F10 144 -#define K_F11 145 -#define K_F12 146 -#define K_INS 147 -#define K_DEL 148 -#define K_PGDN 149 -#define K_PGUP 150 -#define K_HOME 151 -#define K_END 152 - -#define K_KP_HOME 160 -#define K_KP_UPARROW 161 -#define K_KP_PGUP 162 -#define K_KP_LEFTARROW 163 -#define K_KP_5 164 -#define K_KP_RIGHTARROW 165 -#define K_KP_END 166 -#define K_KP_DOWNARROW 167 -#define K_KP_PGDN 168 -#define K_KP_ENTER 169 -#define K_KP_INS 170 -#define K_KP_DEL 171 -#define K_KP_SLASH 172 -#define K_KP_MINUS 173 -#define K_KP_PLUS 174 -#define K_CAPSLOCK 175 - - -// -// joystick buttons -// -#define K_JOY1 203 -#define K_JOY2 204 -#define K_JOY3 205 -#define K_JOY4 206 - -// -// aux keys are for multi-buttoned joysticks to generate so they can use -// the normal binding process -// -#define K_AUX1 207 -#define K_AUX2 208 -#define K_AUX3 209 -#define K_AUX4 210 -#define K_AUX5 211 -#define K_AUX6 212 -#define K_AUX7 213 -#define K_AUX8 214 -#define K_AUX9 215 -#define K_AUX10 216 -#define K_AUX11 217 -#define K_AUX12 218 -#define K_AUX13 219 -#define K_AUX14 220 -#define K_AUX15 221 -#define K_AUX16 222 -#define K_AUX17 223 -#define K_AUX18 224 -#define K_AUX19 225 -#define K_AUX20 226 -#define K_AUX21 227 -#define K_AUX22 228 -#define K_AUX23 229 -#define K_AUX24 230 -#define K_AUX25 231 -#define K_AUX26 232 -#define K_AUX27 233 -#define K_AUX28 234 -#define K_AUX29 235 -#define K_AUX30 236 -#define K_AUX31 237 -#define K_AUX32 238 -#define K_MWHEELDOWN 239 -#define K_MWHEELUP 240 - -#define K_PAUSE 255 - -// -// mouse buttons generate virtual keys -// -#define K_MOUSE1 241 -#define K_MOUSE2 242 -#define K_MOUSE3 243 -#define K_MOUSE4 244 -#define K_MOUSE5 245 - -#endif // KEYDEFS_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// keydefs.h +#ifndef KEYDEFS_H +#define KEYDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +#define K_KP_HOME 160 +#define K_KP_UPARROW 161 +#define K_KP_PGUP 162 +#define K_KP_LEFTARROW 163 +#define K_KP_5 164 +#define K_KP_RIGHTARROW 165 +#define K_KP_END 166 +#define K_KP_DOWNARROW 167 +#define K_KP_PGDN 168 +#define K_KP_ENTER 169 +#define K_KP_INS 170 +#define K_KP_DEL 171 +#define K_KP_SLASH 172 +#define K_KP_MINUS 173 +#define K_KP_PLUS 174 +#define K_CAPSLOCK 175 + + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 +#define K_MWHEELDOWN 239 +#define K_MWHEELUP 240 + +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 241 +#define K_MOUSE2 242 +#define K_MOUSE3 243 +#define K_MOUSE4 244 +#define K_MOUSE5 245 + +#endif // KEYDEFS_H diff --git a/main/source/game_shared/bitvec.h b/main/source/game_shared/bitvec.h index 3198b8a4..17c27e92 100644 --- a/main/source/game_shared/bitvec.h +++ b/main/source/game_shared/bitvec.h @@ -1,181 +1,181 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef BITVEC_H -#define BITVEC_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "archtypes.h" // DAL -#include -#include - - -class CBitVecAccessor -{ -public: - CBitVecAccessor(unsigned long *pDWords, int iBit); - - void operator=(int val); - operator unsigned long(); - -private: - unsigned long *m_pDWords; - int m_iBit; -}; - - -// CBitVec allows you to store a list of bits and do operations on them like they were -// an atomic type. -template -class CBitVec -{ -public: - - CBitVec(); - - // Set all values to the specified value (0 or 1..) - void Init(int val = 0); - - // Access the bits like an array. - CBitVecAccessor operator[](int i); - - // Operations on other bit vectors. - CBitVec& operator=(CBitVec const &other); - bool operator==(CBitVec const &other); - bool operator!=(CBitVec const &other); - - // Get underlying dword representations of the bits. - int GetNumDWords(); - unsigned long GetDWord(int i); - void SetDWord(int i, unsigned long val); - - int GetNumBits(); - -private: - - enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; - unsigned long m_DWords[NUM_DWORDS]; -}; - - - -// ------------------------------------------------------------------------ // -// CBitVecAccessor inlines. -// ------------------------------------------------------------------------ // - -inline CBitVecAccessor::CBitVecAccessor(unsigned long *pDWords, int iBit) -{ - m_pDWords = pDWords; - m_iBit = iBit; -} - - -inline void CBitVecAccessor::operator=(int val) -{ - if(val) - m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); - else - m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); -} - -inline CBitVecAccessor::operator unsigned long() -{ - return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); -} - - - -// ------------------------------------------------------------------------ // -// CBitVec inlines. -// ------------------------------------------------------------------------ // - -template -inline int CBitVec::GetNumBits() -{ - return NUM_BITS; -} - - -template -inline CBitVec::CBitVec() -{ - for(int i=0; i < NUM_DWORDS; i++) - m_DWords[i] = 0; -} - - -template -inline void CBitVec::Init(int val) -{ - for(int i=0; i < GetNumBits(); i++) - { - (*this)[i] = val; - } -} - - -template -inline CBitVec& CBitVec::operator=(CBitVec const &other) -{ - memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); - return *this; -} - - -template -inline CBitVecAccessor CBitVec::operator[](int i) -{ - assert(i >= 0 && i < GetNumBits()); - return CBitVecAccessor(m_DWords, i); -} - - -template -inline bool CBitVec::operator==(CBitVec const &other) -{ - for(int i=0; i < NUM_DWORDS; i++) - if(m_DWords[i] != other.m_DWords[i]) - return false; - - return true; -} - - -template -inline bool CBitVec::operator!=(CBitVec const &other) -{ - return !(*this == other); -} - - -template -inline int CBitVec::GetNumDWords() -{ - return NUM_DWORDS; -} - -template -inline unsigned long CBitVec::GetDWord(int i) -{ - assert(i >= 0 && i < NUM_DWORDS); - return m_DWords[i]; -} - - -template -inline void CBitVec::SetDWord(int i, unsigned long val) -{ - assert(i >= 0 && i < NUM_DWORDS); - m_DWords[i] = val; -} - - -#endif // BITVEC_H - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "archtypes.h" // DAL +#include +#include + + +class CBitVecAccessor +{ +public: + CBitVecAccessor(unsigned long *pDWords, int iBit); + + void operator=(int val); + operator unsigned long(); + +private: + unsigned long *m_pDWords; + int m_iBit; +}; + + +// CBitVec allows you to store a list of bits and do operations on them like they were +// an atomic type. +template +class CBitVec +{ +public: + + CBitVec(); + + // Set all values to the specified value (0 or 1..) + void Init(int val = 0); + + // Access the bits like an array. + CBitVecAccessor operator[](int i); + + // Operations on other bit vectors. + CBitVec& operator=(CBitVec const &other); + bool operator==(CBitVec const &other); + bool operator!=(CBitVec const &other); + + // Get underlying dword representations of the bits. + int GetNumDWords(); + unsigned long GetDWord(int i); + void SetDWord(int i, unsigned long val); + + int GetNumBits(); + +private: + + enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; + unsigned long m_DWords[NUM_DWORDS]; +}; + + + +// ------------------------------------------------------------------------ // +// CBitVecAccessor inlines. +// ------------------------------------------------------------------------ // + +inline CBitVecAccessor::CBitVecAccessor(unsigned long *pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + + +inline void CBitVecAccessor::operator=(int val) +{ + if(val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator unsigned long() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + + +// ------------------------------------------------------------------------ // +// CBitVec inlines. +// ------------------------------------------------------------------------ // + +template +inline int CBitVec::GetNumBits() +{ + return NUM_BITS; +} + + +template +inline CBitVec::CBitVec() +{ + for(int i=0; i < NUM_DWORDS; i++) + m_DWords[i] = 0; +} + + +template +inline void CBitVec::Init(int val) +{ + for(int i=0; i < GetNumBits(); i++) + { + (*this)[i] = val; + } +} + + +template +inline CBitVec& CBitVec::operator=(CBitVec const &other) +{ + memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); + return *this; +} + + +template +inline CBitVecAccessor CBitVec::operator[](int i) +{ + assert(i >= 0 && i < GetNumBits()); + return CBitVecAccessor(m_DWords, i); +} + + +template +inline bool CBitVec::operator==(CBitVec const &other) +{ + for(int i=0; i < NUM_DWORDS; i++) + if(m_DWords[i] != other.m_DWords[i]) + return false; + + return true; +} + + +template +inline bool CBitVec::operator!=(CBitVec const &other) +{ + return !(*this == other); +} + + +template +inline int CBitVec::GetNumDWords() +{ + return NUM_DWORDS; +} + +template +inline unsigned long CBitVec::GetDWord(int i) +{ + assert(i >= 0 && i < NUM_DWORDS); + return m_DWords[i]; +} + + +template +inline void CBitVec::SetDWord(int i, unsigned long val) +{ + assert(i >= 0 && i < NUM_DWORDS); + m_DWords[i] = val; +} + + +#endif // BITVEC_H + diff --git a/main/source/game_shared/directorconst.h b/main/source/game_shared/directorconst.h index 9c915f02..da1fcb52 100644 --- a/main/source/game_shared/directorconst.h +++ b/main/source/game_shared/directorconst.h @@ -1,45 +1,45 @@ -#ifndef DIRECTOR_CONST_H -#define DIRECTOR_CONST_H - -// not needed anymore -//#define SVC_HLTV 50 - -#define SVC_DIRECTOR 51 // messsage for director module in proxy - -// sub commands of svc_director: -#define DRC_CMD_NONE 0 // NULL director command -#define DRC_CMD_START 1 // start director mode -#define DRC_CMD_EVENT 2 // informs about director event -#define DRC_CMD_MODE 3 // switches camera modes -#define DRC_CMD_CAMERA 4 // sets camera registers -#define DRC_CMD_TIMESCALE 5 // sets time scale -#define DRC_CMD_MESSAGE 6 // send HUD centerprint -#define DRC_CMD_SOUND 7 // plays a particular sound -#define DRC_CMD_STATUS 8 // status info about broadcast -#define DRC_CMD_BANNER 9 // banner file name for HLTV gui -#define DRC_CMD_FADE 10 // send screen fade command -#define DRC_CMD_SHAKE 11 // send screen shake command -#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command -#define DRC_CMD_LAST 12 - - -// HLTV_EVENT event flags -#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) -#define DRC_FLAG_SIDE (1<<4) // -#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene -#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo -#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) -#define DRC_FLAG_INTRO (1<<8) // is a introduction scene -#define DRC_FLAG_FINAL (1<<9) // is a final scene -#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data - -// Size of message (command length in bytes = (1+2+2+4)) -#define DIRECTOR_MESSAGE_SIZE 9 - -// prxoy director stuff -//#define DRC_EVENT 3 // informs the dircetor about ann important game event - -#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) -#define DRC_FLAG_DRAMATIC (1<<5) - +#ifndef DIRECTOR_CONST_H +#define DIRECTOR_CONST_H + +// not needed anymore +//#define SVC_HLTV 50 + +#define SVC_DIRECTOR 51 // messsage for director module in proxy + +// sub commands of svc_director: +#define DRC_CMD_NONE 0 // NULL director command +#define DRC_CMD_START 1 // start director mode +#define DRC_CMD_EVENT 2 // informs about director event +#define DRC_CMD_MODE 3 // switches camera modes +#define DRC_CMD_CAMERA 4 // sets camera registers +#define DRC_CMD_TIMESCALE 5 // sets time scale +#define DRC_CMD_MESSAGE 6 // send HUD centerprint +#define DRC_CMD_SOUND 7 // plays a particular sound +#define DRC_CMD_STATUS 8 // status info about broadcast +#define DRC_CMD_BANNER 9 // banner file name for HLTV gui +#define DRC_CMD_FADE 10 // send screen fade command +#define DRC_CMD_SHAKE 11 // send screen shake command +#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command +#define DRC_CMD_LAST 12 + + +// HLTV_EVENT event flags +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene +#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo +#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) +#define DRC_FLAG_INTRO (1<<8) // is a introduction scene +#define DRC_FLAG_FINAL (1<<9) // is a final scene +#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data + +// Size of message (command length in bytes = (1+2+2+4)) +#define DIRECTOR_MESSAGE_SIZE 9 + +// prxoy director stuff +//#define DRC_EVENT 3 // informs the dircetor about ann important game event + +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_DRAMATIC (1<<5) + #endif \ No newline at end of file diff --git a/main/source/game_shared/teamconst.h b/main/source/game_shared/teamconst.h index da0d7509..2ed0c3d3 100644 --- a/main/source/game_shared/teamconst.h +++ b/main/source/game_shared/teamconst.h @@ -1,35 +1,35 @@ -//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= -// -// The copyright to the contents herein is the property of Charles G. Cleveland. -// The contents may be used and/or copied only with the written permission of -// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: -// -// $Workfile: teamconst.h $ -// $Date: 2002/07/23 16:49:42 $ -// -//------------------------------------------------------------------------------- -// $Log: teamconst.h,v $ -// Revision 1.2 2002/07/23 16:49:42 Flayra -// - Added document header, new player constant -// -//=============================================================================== -#ifndef TEAM_CONST_H -#define TEAM_CONST_H - -#define MAX_PLAYERS 32//: Why was this 64?! - -#define MAX_PLAYERS_PER_TEAM 16 - -//#define MAX_TEAMS 64 -#define MAX_TEAMS 6 - -#define MAX_TEAM_NAME 16 - -#define MAX_TEAMNAME_LENGTH 16 - -#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH - +//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= +// +// The copyright to the contents herein is the property of Charles G. Cleveland. +// The contents may be used and/or copied only with the written permission of +// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: teamconst.h $ +// $Date: 2002/07/23 16:49:42 $ +// +//------------------------------------------------------------------------------- +// $Log: teamconst.h,v $ +// Revision 1.2 2002/07/23 16:49:42 Flayra +// - Added document header, new player constant +// +//=============================================================================== +#ifndef TEAM_CONST_H +#define TEAM_CONST_H + +#define MAX_PLAYERS 32//: Why was this 64?! + +#define MAX_PLAYERS_PER_TEAM 16 + +//#define MAX_TEAMS 64 +#define MAX_TEAMS 6 + +#define MAX_TEAM_NAME 16 + +#define MAX_TEAMNAME_LENGTH 16 + +#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH + #endif \ No newline at end of file diff --git a/main/source/game_shared/vgui_checkbutton2.cpp b/main/source/game_shared/vgui_checkbutton2.cpp index b83090a2..3386a117 100644 --- a/main/source/game_shared/vgui_checkbutton2.cpp +++ b/main/source/game_shared/vgui_checkbutton2.cpp @@ -1,202 +1,202 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include -#include "vgui_checkbutton2.h" -#include "vgui_loadtga.h" - - -#define EXTRA_X 5 - - -using namespace vgui; - - - -CCheckButton2::CCheckButton2() : - m_Label(""), - m_pChecked(NULL), - m_pUnchecked(NULL), - m_pHandler(NULL), - m_CheckboxPanel(NULL) -{ - m_bOwnImages = false; - m_bChecked = false; - m_pChecked = m_pUnchecked = NULL; - m_bCheckboxLeft = true; - - m_Label.setParent(this); - m_Label.setFgColor(255,255,255,0); - m_Label.setBgColor(0,0,0,255); // background is not drawn and foreground is white - m_Label.addInputSignal(this); - - m_CheckboxPanel.setParent(this); - m_CheckboxPanel.addInputSignal(this); - - setPaintBackgroundEnabled(false); -} - - -CCheckButton2::~CCheckButton2() -{ - DeleteImages(); -} - - -void CCheckButton2::SetImages(char const *pChecked, char const *pUnchecked) -{ - DeleteImages(); - - m_pChecked = vgui_LoadTGA(pChecked); - m_pUnchecked = vgui_LoadTGA(pUnchecked); - m_bOwnImages = true; - - SetupControls(); -} - - -void CCheckButton2::SetImages(Image *pChecked, Image *pUnchecked) -{ - DeleteImages(); - - m_pChecked = pChecked; - m_pUnchecked = pUnchecked; - m_bOwnImages = false; - - SetupControls(); -} - - -void CCheckButton2::DeleteImages() -{ - if(m_bOwnImages) - { - delete m_pChecked; - delete m_pUnchecked; - } - - m_pChecked = NULL; - m_pUnchecked = NULL; - m_bOwnImages = false; - - SetupControls(); -} - - -void CCheckButton2::SetCheckboxLeft(bool bLeftAlign) -{ - m_bCheckboxLeft = bLeftAlign; - SetupControls(); -} - - -bool CCheckButton2::GetCheckboxLeft() -{ - return m_bCheckboxLeft; -} - - -void CCheckButton2::SetText(char const *pText, ...) -{ - char str[512]; - - va_list marker; - va_start(marker, pText); - _vsnprintf(str, sizeof(str), pText, marker); - va_end(marker); - - m_Label.setText(str); - SetupControls(); -} - - -void CCheckButton2::setFont(Font* font) -{ - m_Label.setFont(font); -} - -void CCheckButton2::SetTextColor(int r, int g, int b, int a) -{ - m_Label.setFgColor(r, g, b, a); - repaint(); -} - - -void CCheckButton2::SetHandler(ICheckButton2Handler *pHandler) -{ - m_pHandler = pHandler; -} - - -bool CCheckButton2::IsChecked() -{ - return m_bChecked; -} - - -void CCheckButton2::SetChecked(bool bChecked) -{ - m_bChecked = bChecked; - SetupControls(); -} - - -void CCheckButton2::internalMousePressed(MouseCode code) -{ - m_bChecked = !m_bChecked; - - if(m_pHandler) - m_pHandler->StateChanged(this); - - SetupControls(); -} - - -void CCheckButton2::SetupControls() -{ - // Initialize the checkbutton bitmap. - Image *pBitmap = m_bChecked ? m_pChecked : m_pUnchecked; - - Panel *controls[2] = {&m_CheckboxPanel, &m_Label}; - int controlSizes[2][2]; - - controlSizes[0][0] = controlSizes[0][1] = 0; - if(pBitmap) - pBitmap->getSize(controlSizes[0][0], controlSizes[0][1]); - - m_CheckboxPanel.setImage(pBitmap); - m_CheckboxPanel.setSize(controlSizes[0][0], controlSizes[0][1]); - - - // Get the label's size. - m_Label.getSize(controlSizes[1][0], controlSizes[1][1]); - m_Label.setContentAlignment(Label::a_west); - - - // Position the controls. - int iLeftControl = !m_bCheckboxLeft; - int iBiggestY = controlSizes[0][1] > controlSizes[1][0] ? 0 : 1; - controls[iLeftControl]->setPos(0, (controlSizes[iBiggestY][1] - controlSizes[iLeftControl][1]) / 2); - controls[!iLeftControl]->setPos(controlSizes[iLeftControl][0] + EXTRA_X, (controlSizes[iBiggestY][1] - controlSizes[!iLeftControl][1]) / 2); - - - // Fit this control to the sizes of the subcontrols. - setSize(controlSizes[0][0] + controlSizes[1][0] + EXTRA_X, (controlSizes[0][1] > controlSizes[1][1]) ? controlSizes[0][1] : controlSizes[1][1]); - repaint(); -} - - -void CCheckButton2::mousePressed(MouseCode code, Panel *panel) -{ - internalMousePressed(code); -} - - - - - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "vgui_checkbutton2.h" +#include "vgui_loadtga.h" + + +#define EXTRA_X 5 + + +using namespace vgui; + + + +CCheckButton2::CCheckButton2() : + m_Label(""), + m_pChecked(NULL), + m_pUnchecked(NULL), + m_pHandler(NULL), + m_CheckboxPanel(NULL) +{ + m_bOwnImages = false; + m_bChecked = false; + m_pChecked = m_pUnchecked = NULL; + m_bCheckboxLeft = true; + + m_Label.setParent(this); + m_Label.setFgColor(255,255,255,0); + m_Label.setBgColor(0,0,0,255); // background is not drawn and foreground is white + m_Label.addInputSignal(this); + + m_CheckboxPanel.setParent(this); + m_CheckboxPanel.addInputSignal(this); + + setPaintBackgroundEnabled(false); +} + + +CCheckButton2::~CCheckButton2() +{ + DeleteImages(); +} + + +void CCheckButton2::SetImages(char const *pChecked, char const *pUnchecked) +{ + DeleteImages(); + + m_pChecked = vgui_LoadTGA(pChecked); + m_pUnchecked = vgui_LoadTGA(pUnchecked); + m_bOwnImages = true; + + SetupControls(); +} + + +void CCheckButton2::SetImages(Image *pChecked, Image *pUnchecked) +{ + DeleteImages(); + + m_pChecked = pChecked; + m_pUnchecked = pUnchecked; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::DeleteImages() +{ + if(m_bOwnImages) + { + delete m_pChecked; + delete m_pUnchecked; + } + + m_pChecked = NULL; + m_pUnchecked = NULL; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::SetCheckboxLeft(bool bLeftAlign) +{ + m_bCheckboxLeft = bLeftAlign; + SetupControls(); +} + + +bool CCheckButton2::GetCheckboxLeft() +{ + return m_bCheckboxLeft; +} + + +void CCheckButton2::SetText(char const *pText, ...) +{ + char str[512]; + + va_list marker; + va_start(marker, pText); + _vsnprintf(str, sizeof(str), pText, marker); + va_end(marker); + + m_Label.setText(str); + SetupControls(); +} + + +void CCheckButton2::setFont(Font* font) +{ + m_Label.setFont(font); +} + +void CCheckButton2::SetTextColor(int r, int g, int b, int a) +{ + m_Label.setFgColor(r, g, b, a); + repaint(); +} + + +void CCheckButton2::SetHandler(ICheckButton2Handler *pHandler) +{ + m_pHandler = pHandler; +} + + +bool CCheckButton2::IsChecked() +{ + return m_bChecked; +} + + +void CCheckButton2::SetChecked(bool bChecked) +{ + m_bChecked = bChecked; + SetupControls(); +} + + +void CCheckButton2::internalMousePressed(MouseCode code) +{ + m_bChecked = !m_bChecked; + + if(m_pHandler) + m_pHandler->StateChanged(this); + + SetupControls(); +} + + +void CCheckButton2::SetupControls() +{ + // Initialize the checkbutton bitmap. + Image *pBitmap = m_bChecked ? m_pChecked : m_pUnchecked; + + Panel *controls[2] = {&m_CheckboxPanel, &m_Label}; + int controlSizes[2][2]; + + controlSizes[0][0] = controlSizes[0][1] = 0; + if(pBitmap) + pBitmap->getSize(controlSizes[0][0], controlSizes[0][1]); + + m_CheckboxPanel.setImage(pBitmap); + m_CheckboxPanel.setSize(controlSizes[0][0], controlSizes[0][1]); + + + // Get the label's size. + m_Label.getSize(controlSizes[1][0], controlSizes[1][1]); + m_Label.setContentAlignment(Label::a_west); + + + // Position the controls. + int iLeftControl = !m_bCheckboxLeft; + int iBiggestY = controlSizes[0][1] > controlSizes[1][0] ? 0 : 1; + controls[iLeftControl]->setPos(0, (controlSizes[iBiggestY][1] - controlSizes[iLeftControl][1]) / 2); + controls[!iLeftControl]->setPos(controlSizes[iLeftControl][0] + EXTRA_X, (controlSizes[iBiggestY][1] - controlSizes[!iLeftControl][1]) / 2); + + + // Fit this control to the sizes of the subcontrols. + setSize(controlSizes[0][0] + controlSizes[1][0] + EXTRA_X, (controlSizes[0][1] > controlSizes[1][1]) ? controlSizes[0][1] : controlSizes[1][1]); + repaint(); +} + + +void CCheckButton2::mousePressed(MouseCode code, Panel *panel) +{ + internalMousePressed(code); +} + + + + + diff --git a/main/source/game_shared/vgui_checkbutton2.h b/main/source/game_shared/vgui_checkbutton2.h index d23e614f..fc5eca00 100644 --- a/main/source/game_shared/vgui_checkbutton2.h +++ b/main/source/game_shared/vgui_checkbutton2.h @@ -1,100 +1,100 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_CHECKBUTTON2_H -#define VGUI_CHECKBUTTON2_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "VGUI_Label.h" -#include "VGUI_ImagePanel.h" -#include "vgui_defaultinputsignal.h" - - -namespace vgui -{ - - -class CCheckButton2; - - -class ICheckButton2Handler -{ -public: - virtual void StateChanged(CCheckButton2 *pButton) = 0; -}; - - -// VGUI checkbox class. -// - Provides access to the checkbox images. -// - Provides an easy callback mechanism for state changes. -// - Default background is invisible, and default text color is white. -class CCheckButton2 : public Panel, public CDefaultInputSignal -{ -public: - - CCheckButton2(); - ~CCheckButton2(); - - // Initialize the button with these. - void SetImages(char const *pChecked, char const *pUnchecked); - void SetImages(Image *pChecked, Image *pUnchecked); // If you use this, the button will never delete the images. - void DeleteImages(); - - // The checkbox can be to the left or the right of the text (default is left). - void SetCheckboxLeft(bool bLeftAlign); - bool GetCheckboxLeft(); - - // Set the label text. - void SetText(char const *pText, ...); - void SetTextColor(int r, int g, int b, int a); - void setFont(Font* font); - - // You can register for change notification here. - void SetHandler(ICheckButton2Handler *pHandler); - - // Get/set the check state. - bool IsChecked(); - void SetChecked(bool bChecked); - -// Panel overrides. -public: - - virtual void internalMousePressed(MouseCode code); - - -protected: - - void SetupControls(); - - -// InputSignal overrides. -protected: - virtual void mousePressed(MouseCode code,Panel* panel); - - -public: - ICheckButton2Handler *m_pHandler; - - bool m_bCheckboxLeft; - Label m_Label; - ImagePanel m_CheckboxPanel; - - Image *m_pChecked; - Image *m_pUnchecked; - bool m_bOwnImages; - - bool m_bChecked; -}; - - -} - - -#endif // VGUI_CHECKBUTTON2_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_CHECKBUTTON2_H +#define VGUI_CHECKBUTTON2_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Label.h" +#include "VGUI_ImagePanel.h" +#include "vgui_defaultinputsignal.h" + + +namespace vgui +{ + + +class CCheckButton2; + + +class ICheckButton2Handler +{ +public: + virtual void StateChanged(CCheckButton2 *pButton) = 0; +}; + + +// VGUI checkbox class. +// - Provides access to the checkbox images. +// - Provides an easy callback mechanism for state changes. +// - Default background is invisible, and default text color is white. +class CCheckButton2 : public Panel, public CDefaultInputSignal +{ +public: + + CCheckButton2(); + ~CCheckButton2(); + + // Initialize the button with these. + void SetImages(char const *pChecked, char const *pUnchecked); + void SetImages(Image *pChecked, Image *pUnchecked); // If you use this, the button will never delete the images. + void DeleteImages(); + + // The checkbox can be to the left or the right of the text (default is left). + void SetCheckboxLeft(bool bLeftAlign); + bool GetCheckboxLeft(); + + // Set the label text. + void SetText(char const *pText, ...); + void SetTextColor(int r, int g, int b, int a); + void setFont(Font* font); + + // You can register for change notification here. + void SetHandler(ICheckButton2Handler *pHandler); + + // Get/set the check state. + bool IsChecked(); + void SetChecked(bool bChecked); + +// Panel overrides. +public: + + virtual void internalMousePressed(MouseCode code); + + +protected: + + void SetupControls(); + + +// InputSignal overrides. +protected: + virtual void mousePressed(MouseCode code,Panel* panel); + + +public: + ICheckButton2Handler *m_pHandler; + + bool m_bCheckboxLeft; + Label m_Label; + ImagePanel m_CheckboxPanel; + + Image *m_pChecked; + Image *m_pUnchecked; + bool m_bOwnImages; + + bool m_bChecked; +}; + + +} + + +#endif // VGUI_CHECKBUTTON2_H diff --git a/main/source/game_shared/vgui_defaultinputsignal.h b/main/source/game_shared/vgui_defaultinputsignal.h index 281fbfa8..95ab0a4a 100644 --- a/main/source/game_shared/vgui_defaultinputsignal.h +++ b/main/source/game_shared/vgui_defaultinputsignal.h @@ -1,39 +1,39 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_DEFAULTINPUTSIGNAL_H -#define VGUI_DEFAULTINPUTSIGNAL_H -#ifdef _WIN32 -#pragma once -#endif - - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_DEFAULTINPUTSIGNAL_H +#define VGUI_DEFAULTINPUTSIGNAL_H +#ifdef _WIN32 +#pragma once +#endif + + #include "VGUI_InputSignal.h" - - -namespace vgui -{ - // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. - class CDefaultInputSignal : public vgui::InputSignal - { - public: - virtual void cursorMoved(int x,int y,Panel* panel) {} - virtual void cursorEntered(Panel* panel) {} - virtual void cursorExited(Panel* panel) {} - virtual void mousePressed(MouseCode code,Panel* panel) {} - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} - virtual void mouseReleased(MouseCode code,Panel* panel) {} - virtual void mouseWheeled(int delta,Panel* panel) {} - virtual void keyPressed(KeyCode code,Panel* panel) {} - virtual void keyTyped(KeyCode code,Panel* panel) {} - virtual void keyReleased(KeyCode code,Panel* panel) {} - virtual void keyFocusTicked(Panel* panel) {} - }; -} - - -#endif // VGUI_DEFAULTINPUTSIGNAL_H + + +namespace vgui +{ + // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. + class CDefaultInputSignal : public vgui::InputSignal + { + public: + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) {} + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseReleased(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} + }; +} + + +#endif // VGUI_DEFAULTINPUTSIGNAL_H diff --git a/main/source/game_shared/vgui_grid.cpp b/main/source/game_shared/vgui_grid.cpp index 2fc8cbad..66b23300 100644 --- a/main/source/game_shared/vgui_grid.cpp +++ b/main/source/game_shared/vgui_grid.cpp @@ -1,398 +1,398 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include "vgui_grid.h" - - -using namespace vgui; - - -#define AssertCheck(expr, msg) \ - if(!(expr))\ - {\ - assert(!msg);\ - return 0;\ - } - - - -// ------------------------------------------------------------------------------ // -// CGrid::CGridEntry. -// ------------------------------------------------------------------------------ // - -CGrid::CGridEntry::CGridEntry() -{ - m_pPanel = NULL; - m_bUnderline = false; -} - -CGrid::CGridEntry::~CGridEntry() -{ -} - - -// ------------------------------------------------------------------------------ // -// CGrid. -// ------------------------------------------------------------------------------ // - -CGrid::CGrid() -{ - Clear(); -} - - -CGrid::~CGrid() -{ - Term(); -} - - -bool CGrid::SetDimensions(int xCols, int yRows) -{ - Term(); - - m_GridEntries = new CGridEntry[xCols * yRows]; - m_Widths = new int[xCols*2 + yRows*2]; - m_Heights = m_Widths + xCols; - m_ColOffsets = m_Heights + yRows; - m_RowOffsets = m_ColOffsets + xCols; - - if(!m_GridEntries || !m_Widths) - { - Term(); - return false; - } - - memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2)); - - m_xCols = xCols; - m_yRows = yRows; - return true; -} - - -void CGrid::Term() -{ - delete [] m_GridEntries; - delete [] m_Widths; - Clear(); -} - - -Panel* CGrid::GetEntry(int x, int y) -{ - return GridEntry(x, y)->m_pPanel; -} - - -bool CGrid::SetEntry(int x, int y, Panel *pPanel) -{ - CGridEntry *pEntry = GridEntry(x, y); - if(!pEntry) - return false; - - if(pEntry->m_pPanel) - pEntry->m_pPanel->setParent(NULL); - - pEntry->m_pPanel = pPanel; - if(pPanel) - pPanel->setParent(this); - - m_bDirty = true; - return true; -} - - -int CGrid::GetXSpacing() -{ - return m_xSpacing; -} - - -int CGrid::GetYSpacing() -{ - return m_ySpacing; -} - - -void CGrid::SetSpacing(int xSpacing, int ySpacing) -{ - if(xSpacing != m_xSpacing) - { - m_xSpacing = xSpacing; - CalcColOffsets(0); - m_bDirty = true; - } - - if(ySpacing != m_ySpacing) - { - m_ySpacing = ySpacing; - CalcRowOffsets(0); - m_bDirty = true; - } -} - - -bool CGrid::SetColumnWidth(int iColumn, int width) -{ - AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified"); - m_Widths[iColumn] = width; - CalcColOffsets(iColumn+1); - m_bDirty = true; - return true; -} - - -bool CGrid::SetRowHeight(int iRow, int height) -{ - AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified"); - m_Heights[iRow] = height; - CalcRowOffsets(iRow+1); - m_bDirty = true; - return true; -} - - -int CGrid::GetColumnWidth(int iColumn) -{ - AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified"); - return m_Widths[iColumn]; -} - - -int CGrid::GetRowHeight(int iRow) -{ - AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified"); - return m_Heights[iRow]; -} - - -int CGrid::CalcFitColumnWidth(int iColumn) -{ - AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified"); - - int maxSize = 0; - for(int i=0; i < m_yRows; i++) - { - Panel *pPanel = GridEntry(iColumn, i)->m_pPanel; - if(!pPanel) - continue; - - int w, h; - pPanel->getSize(w,h); - if(w > maxSize) - maxSize = w; - } - - return maxSize; -} - - -int CGrid::CalcFitRowHeight(int iRow) -{ - AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified"); - - int maxSize = 0; - for(int i=0; i < m_xCols; i++) - { - Panel *pPanel = GridEntry(i, iRow)->m_pPanel; - if(!pPanel) - continue; - - int w, h; - pPanel->getSize(w,h); - if(h > maxSize) - maxSize = h; - } - - return maxSize; -} - - -void CGrid::AutoSetRowHeights() -{ - for(int i=0; i < m_yRows; i++) - SetRowHeight(i, CalcFitRowHeight(i)); -} - - -bool CGrid::GetEntryBox( - int col, int row, int &x, int &y, int &w, int &h) -{ - AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified"); - - x = m_ColOffsets[col]; - w = m_Widths[col]; - - y = m_RowOffsets[row]; - h = m_Heights[row]; - return true; -} - - -bool CGrid::CopyColumnWidths(CGrid *pOther) -{ - if(!pOther || pOther->m_xCols != m_xCols) - return false; - - for(int i=0; i < m_xCols; i++) - m_Widths[i] = pOther->m_Widths[i]; - - CalcColOffsets(0); - m_bDirty = true; - return true; -} - - -void CGrid::RepositionContents() -{ - for(int x=0; x < m_xCols; x++) - { - for(int y=0; y < m_yRows; y++) - { - Panel *pPanel = GridEntry(x,y)->m_pPanel; - if(!pPanel) - continue; - - pPanel->setBounds( - m_ColOffsets[x], - m_RowOffsets[y], - m_Widths[x], - m_Heights[y]); - } - } - - m_bDirty = false; -} - - -int CGrid::CalcDrawHeight() -{ - if(m_yRows > 0) - { - return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing; - } - else - { - return 0; - } -} - - -void CGrid::paint() -{ - if(m_bDirty) - RepositionContents(); - - Panel::paint(); - - // walk the grid looking for underlined rows - int x = 0, y = 0; - for (int row = 0; row < m_yRows; row++) - { - CGridEntry *cell = GridEntry(0, row); - - y += cell->m_pPanel->getTall() + m_ySpacing; - if (cell->m_bUnderline) - { - drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]); - drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset); - } - } -} - -void CGrid::paintBackground() -{ - Panel::paintBackground(); -} - -//----------------------------------------------------------------------------- -// Purpose: sets underline color for a particular row -//----------------------------------------------------------------------------- -void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a) -{ - CGridEntry *cell = GridEntry(0, row); - cell->m_bUnderline = enabled; - if (enabled) - { - cell->m_iUnderlineOffset = offset; - cell->m_UnderlineColor[0] = r; - cell->m_UnderlineColor[1] = g; - cell->m_UnderlineColor[2] = b; - cell->m_UnderlineColor[3] = a; - } -} - -void CGrid::Clear() -{ - m_xCols = m_yRows = 0; - m_Widths = NULL; - m_GridEntries = NULL; - m_xSpacing = m_ySpacing = 0; - m_bDirty = false; -} - - -CGrid::CGridEntry* CGrid::GridEntry(int x, int y) -{ - AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified"); - return &m_GridEntries[y*m_xCols + x]; -} - - -void CGrid::CalcColOffsets(int iStart) -{ - int cur = m_xSpacing; - if(iStart != 0) - cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1]; - - for(int i=iStart; i < m_xCols; i++) - { - m_ColOffsets[i] = cur; - cur += m_Widths[i] + m_xSpacing; - } -} - - -void CGrid::CalcRowOffsets(int iStart) -{ - int cur = m_ySpacing; - if(iStart != 0) - cur += m_RowOffsets[iStart-1]; - - for(int i=iStart; i < m_yRows; i++) - { - m_RowOffsets[i] = cur; - cur += m_Heights[i] + m_ySpacing; - } -} - -bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col) -{ - row = -1; col = -1; - for(int x=0; x < m_xCols; x++) - { - for(int y=0; y < m_yRows; y++) - { - Panel *pPanel = GridEntry(x,y)->m_pPanel; - if (!pPanel) - continue; - - if (pPanel->isWithin(worldX, worldY)) - { - col = x; - row = y; - return true; - } - } - } - - return false; -} - - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "vgui_grid.h" + + +using namespace vgui; + + +#define AssertCheck(expr, msg) \ + if(!(expr))\ + {\ + assert(!msg);\ + return 0;\ + } + + + +// ------------------------------------------------------------------------------ // +// CGrid::CGridEntry. +// ------------------------------------------------------------------------------ // + +CGrid::CGridEntry::CGridEntry() +{ + m_pPanel = NULL; + m_bUnderline = false; +} + +CGrid::CGridEntry::~CGridEntry() +{ +} + + +// ------------------------------------------------------------------------------ // +// CGrid. +// ------------------------------------------------------------------------------ // + +CGrid::CGrid() +{ + Clear(); +} + + +CGrid::~CGrid() +{ + Term(); +} + + +bool CGrid::SetDimensions(int xCols, int yRows) +{ + Term(); + + m_GridEntries = new CGridEntry[xCols * yRows]; + m_Widths = new int[xCols*2 + yRows*2]; + m_Heights = m_Widths + xCols; + m_ColOffsets = m_Heights + yRows; + m_RowOffsets = m_ColOffsets + xCols; + + if(!m_GridEntries || !m_Widths) + { + Term(); + return false; + } + + memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2)); + + m_xCols = xCols; + m_yRows = yRows; + return true; +} + + +void CGrid::Term() +{ + delete [] m_GridEntries; + delete [] m_Widths; + Clear(); +} + + +Panel* CGrid::GetEntry(int x, int y) +{ + return GridEntry(x, y)->m_pPanel; +} + + +bool CGrid::SetEntry(int x, int y, Panel *pPanel) +{ + CGridEntry *pEntry = GridEntry(x, y); + if(!pEntry) + return false; + + if(pEntry->m_pPanel) + pEntry->m_pPanel->setParent(NULL); + + pEntry->m_pPanel = pPanel; + if(pPanel) + pPanel->setParent(this); + + m_bDirty = true; + return true; +} + + +int CGrid::GetXSpacing() +{ + return m_xSpacing; +} + + +int CGrid::GetYSpacing() +{ + return m_ySpacing; +} + + +void CGrid::SetSpacing(int xSpacing, int ySpacing) +{ + if(xSpacing != m_xSpacing) + { + m_xSpacing = xSpacing; + CalcColOffsets(0); + m_bDirty = true; + } + + if(ySpacing != m_ySpacing) + { + m_ySpacing = ySpacing; + CalcRowOffsets(0); + m_bDirty = true; + } +} + + +bool CGrid::SetColumnWidth(int iColumn, int width) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified"); + m_Widths[iColumn] = width; + CalcColOffsets(iColumn+1); + m_bDirty = true; + return true; +} + + +bool CGrid::SetRowHeight(int iRow, int height) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified"); + m_Heights[iRow] = height; + CalcRowOffsets(iRow+1); + m_bDirty = true; + return true; +} + + +int CGrid::GetColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified"); + return m_Widths[iColumn]; +} + + +int CGrid::GetRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified"); + return m_Heights[iRow]; +} + + +int CGrid::CalcFitColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_yRows; i++) + { + Panel *pPanel = GridEntry(iColumn, i)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(w > maxSize) + maxSize = w; + } + + return maxSize; +} + + +int CGrid::CalcFitRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_xCols; i++) + { + Panel *pPanel = GridEntry(i, iRow)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(h > maxSize) + maxSize = h; + } + + return maxSize; +} + + +void CGrid::AutoSetRowHeights() +{ + for(int i=0; i < m_yRows; i++) + SetRowHeight(i, CalcFitRowHeight(i)); +} + + +bool CGrid::GetEntryBox( + int col, int row, int &x, int &y, int &w, int &h) +{ + AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified"); + + x = m_ColOffsets[col]; + w = m_Widths[col]; + + y = m_RowOffsets[row]; + h = m_Heights[row]; + return true; +} + + +bool CGrid::CopyColumnWidths(CGrid *pOther) +{ + if(!pOther || pOther->m_xCols != m_xCols) + return false; + + for(int i=0; i < m_xCols; i++) + m_Widths[i] = pOther->m_Widths[i]; + + CalcColOffsets(0); + m_bDirty = true; + return true; +} + + +void CGrid::RepositionContents() +{ + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if(!pPanel) + continue; + + pPanel->setBounds( + m_ColOffsets[x], + m_RowOffsets[y], + m_Widths[x], + m_Heights[y]); + } + } + + m_bDirty = false; +} + + +int CGrid::CalcDrawHeight() +{ + if(m_yRows > 0) + { + return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing; + } + else + { + return 0; + } +} + + +void CGrid::paint() +{ + if(m_bDirty) + RepositionContents(); + + Panel::paint(); + + // walk the grid looking for underlined rows + int x = 0, y = 0; + for (int row = 0; row < m_yRows; row++) + { + CGridEntry *cell = GridEntry(0, row); + + y += cell->m_pPanel->getTall() + m_ySpacing; + if (cell->m_bUnderline) + { + drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]); + drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset); + } + } +} + +void CGrid::paintBackground() +{ + Panel::paintBackground(); +} + +//----------------------------------------------------------------------------- +// Purpose: sets underline color for a particular row +//----------------------------------------------------------------------------- +void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a) +{ + CGridEntry *cell = GridEntry(0, row); + cell->m_bUnderline = enabled; + if (enabled) + { + cell->m_iUnderlineOffset = offset; + cell->m_UnderlineColor[0] = r; + cell->m_UnderlineColor[1] = g; + cell->m_UnderlineColor[2] = b; + cell->m_UnderlineColor[3] = a; + } +} + +void CGrid::Clear() +{ + m_xCols = m_yRows = 0; + m_Widths = NULL; + m_GridEntries = NULL; + m_xSpacing = m_ySpacing = 0; + m_bDirty = false; +} + + +CGrid::CGridEntry* CGrid::GridEntry(int x, int y) +{ + AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified"); + return &m_GridEntries[y*m_xCols + x]; +} + + +void CGrid::CalcColOffsets(int iStart) +{ + int cur = m_xSpacing; + if(iStart != 0) + cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1]; + + for(int i=iStart; i < m_xCols; i++) + { + m_ColOffsets[i] = cur; + cur += m_Widths[i] + m_xSpacing; + } +} + + +void CGrid::CalcRowOffsets(int iStart) +{ + int cur = m_ySpacing; + if(iStart != 0) + cur += m_RowOffsets[iStart-1]; + + for(int i=iStart; i < m_yRows; i++) + { + m_RowOffsets[i] = cur; + cur += m_Heights[i] + m_ySpacing; + } +} + +bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col) +{ + row = -1; col = -1; + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if (!pPanel) + continue; + + if (pPanel->isWithin(worldX, worldY)) + { + col = x; + row = y; + return true; + } + } + } + + return false; +} + + diff --git a/main/source/game_shared/vgui_grid.h b/main/source/game_shared/vgui_grid.h index 0718e39f..4cf43a7e 100644 --- a/main/source/game_shared/vgui_grid.h +++ b/main/source/game_shared/vgui_grid.h @@ -1,122 +1,122 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_GRID_H -#define VGUI_GRID_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "VGUI_Panel.h" - - -namespace vgui -{ - -// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and -// configure and fill the panels however you want. -// To use this control, call SetDimensions, SetSpacing and fill the controls. -class CGrid : public Panel -{ -public: - CGrid(); - virtual ~CGrid(); - - bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. - void Term(); - - Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. - bool SetEntry(int x, int y, Panel *pPanel); - - int GetXSpacing(); - int GetYSpacing(); - void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. - - bool SetColumnWidth(int iColumn, int width); // Set a column's width. - bool SetRowHeight(int iRow, int height); // Set a row's height. - - int GetColumnWidth(int iColumn); - int GetRowHeight(int iRow); - - int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. - int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. - - int CalcDrawHeight(); // Returns how many pixels high the grid control should be - // for all of its contents to be visible (based on its row heights - // and y spacing). - - void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. - - bool GetEntryBox( // Returns the bounding box for the specified entry. - int col, int row, int &x, int &y, int &w, int &h); - - bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the - // column count is different. - - void RepositionContents(); // Sets the size and position of all the grid entries based - // on current spacings and row/column widths. - // You usually only want to call this while setting up the control - // if you want to get the position or dimensions of the child - // controls. This will set them. - - void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row - - // returns the true if found, false otherwise - bool getCellAtPoint(int worldX, int worldY, int &row, int &col); - -// Panel overrides. -public: - - virtual void paint(); - virtual void paintBackground(); - -protected: - - class CGridEntry - { - public: - CGridEntry(); - ~CGridEntry(); - - Panel *m_pPanel; - - bool m_bUnderline; - short m_UnderlineColor[4]; - int m_iUnderlineOffset; - }; - - void Clear(); - CGridEntry* GridEntry(int x, int y); - - void CalcColOffsets(int iStart); - void CalcRowOffsets(int iStart); - - -protected: - - bool m_bDirty; // Set when controls will need to be repositioned. - - int m_xCols; - int m_yRows; - - int m_xSpacing; - int m_ySpacing; - - int *m_Widths; - int *m_Heights; - int *m_ColOffsets; - int *m_RowOffsets; - - CGridEntry *m_GridEntries; - -}; - -}; - - -#endif // VGUI_GRID_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_GRID_H +#define VGUI_GRID_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Panel.h" + + +namespace vgui +{ + +// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and +// configure and fill the panels however you want. +// To use this control, call SetDimensions, SetSpacing and fill the controls. +class CGrid : public Panel +{ +public: + CGrid(); + virtual ~CGrid(); + + bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. + void Term(); + + Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. + bool SetEntry(int x, int y, Panel *pPanel); + + int GetXSpacing(); + int GetYSpacing(); + void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. + + bool SetColumnWidth(int iColumn, int width); // Set a column's width. + bool SetRowHeight(int iRow, int height); // Set a row's height. + + int GetColumnWidth(int iColumn); + int GetRowHeight(int iRow); + + int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. + int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. + + int CalcDrawHeight(); // Returns how many pixels high the grid control should be + // for all of its contents to be visible (based on its row heights + // and y spacing). + + void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. + + bool GetEntryBox( // Returns the bounding box for the specified entry. + int col, int row, int &x, int &y, int &w, int &h); + + bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the + // column count is different. + + void RepositionContents(); // Sets the size and position of all the grid entries based + // on current spacings and row/column widths. + // You usually only want to call this while setting up the control + // if you want to get the position or dimensions of the child + // controls. This will set them. + + void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row + + // returns the true if found, false otherwise + bool getCellAtPoint(int worldX, int worldY, int &row, int &col); + +// Panel overrides. +public: + + virtual void paint(); + virtual void paintBackground(); + +protected: + + class CGridEntry + { + public: + CGridEntry(); + ~CGridEntry(); + + Panel *m_pPanel; + + bool m_bUnderline; + short m_UnderlineColor[4]; + int m_iUnderlineOffset; + }; + + void Clear(); + CGridEntry* GridEntry(int x, int y); + + void CalcColOffsets(int iStart); + void CalcRowOffsets(int iStart); + + +protected: + + bool m_bDirty; // Set when controls will need to be repositioned. + + int m_xCols; + int m_yRows; + + int m_xSpacing; + int m_ySpacing; + + int *m_Widths; + int *m_Heights; + int *m_ColOffsets; + int *m_RowOffsets; + + CGridEntry *m_GridEntries; + +}; + +}; + + +#endif // VGUI_GRID_H diff --git a/main/source/game_shared/vgui_helpers.cpp b/main/source/game_shared/vgui_helpers.cpp index c84ea107..f12a48c7 100644 --- a/main/source/game_shared/vgui_helpers.cpp +++ b/main/source/game_shared/vgui_helpers.cpp @@ -1,45 +1,45 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "vgui_helpers.h" - - -using namespace vgui; - - -void AlignPanel(Panel *pChild, Panel *pParent, int alignment) -{ - int w, h, cw, ch; - pParent->getSize(w, h); - pChild->getSize(cw, ch); - - int xCenter = (w - cw) / 2; - int yCenter = (h - ch) / 2; - - if(alignment == Label::a_west) - pChild->setPos(0, yCenter); - else if(alignment == Label::a_northwest) - pChild->setPos(0,0); - else if(alignment == Label::a_north) - pChild->setPos(xCenter, 0); - else if(alignment == Label::a_northeast) - pChild->setPos(w - cw, 0); - else if(alignment == Label::a_east) - pChild->setPos(w - cw, yCenter); - else if(alignment == Label::a_southeast) - pChild->setPos(w - cw, h - ch); - else if(alignment == Label::a_south) - pChild->setPos(xCenter, h - ch); - else if(alignment == Label::a_southwest) - pChild->setPos(0, h - ch); - else if(alignment == Label::a_center) - pChild->setPos(xCenter, yCenter); -} - - - - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_helpers.h" + + +using namespace vgui; + + +void AlignPanel(Panel *pChild, Panel *pParent, int alignment) +{ + int w, h, cw, ch; + pParent->getSize(w, h); + pChild->getSize(cw, ch); + + int xCenter = (w - cw) / 2; + int yCenter = (h - ch) / 2; + + if(alignment == Label::a_west) + pChild->setPos(0, yCenter); + else if(alignment == Label::a_northwest) + pChild->setPos(0,0); + else if(alignment == Label::a_north) + pChild->setPos(xCenter, 0); + else if(alignment == Label::a_northeast) + pChild->setPos(w - cw, 0); + else if(alignment == Label::a_east) + pChild->setPos(w - cw, yCenter); + else if(alignment == Label::a_southeast) + pChild->setPos(w - cw, h - ch); + else if(alignment == Label::a_south) + pChild->setPos(xCenter, h - ch); + else if(alignment == Label::a_southwest) + pChild->setPos(0, h - ch); + else if(alignment == Label::a_center) + pChild->setPos(xCenter, yCenter); +} + + + + diff --git a/main/source/game_shared/vgui_helpers.h b/main/source/game_shared/vgui_helpers.h index 5d553243..aab3d63d 100644 --- a/main/source/game_shared/vgui_helpers.h +++ b/main/source/game_shared/vgui_helpers.h @@ -1,31 +1,31 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_HELPERS_H -#define VGUI_HELPERS_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "VGUI_Panel.h" -#include "VGUI_Label.h" - - -inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y;} -inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x;} -inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x+w;} -inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y+h;} -inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return w;} -inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return h;} - -// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. -void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); - - -#endif // VGUI_HELPERS_H - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_HELPERS_H +#define VGUI_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Panel.h" +#include "VGUI_Label.h" + + +inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y;} +inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x;} +inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x+w;} +inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y+h;} +inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return w;} +inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return h;} + +// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. +void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); + + +#endif // VGUI_HELPERS_H + diff --git a/main/source/game_shared/vgui_listbox.cpp b/main/source/game_shared/vgui_listbox.cpp index 760a7f50..1f9386d8 100644 --- a/main/source/game_shared/vgui_listbox.cpp +++ b/main/source/game_shared/vgui_listbox.cpp @@ -1,201 +1,201 @@ - -#include "vgui_listbox.h" - - - -using namespace vgui; - - -CListBox::CListBox() : Panel(0, 0, 0, 0), - m_ItemsPanel(0,0,0,0), - m_ScrollBar(0, 0, 0, 0, true), - m_Slider(0, 0, 10, 40, true) -{ - m_Signal.m_pListBox = this; - - m_ItemsPanel.setParent(this); - m_ItemsPanel.setBgColor(0,0,0,255); - - m_Slider.setRangeWindow(50); - m_Slider.setRangeWindowEnabled(true); - - m_ScrollBar.setParent(this); - m_ScrollBar.addIntChangeSignal(&m_Signal); - m_ScrollBar.setSlider(&m_Slider); - m_ScrollBar.setButtonPressedScrollValue(1); - - m_Items.m_pNext = m_Items.m_pPrev = &m_Items; - m_ItemOffset = 0; - m_iScrollMax = -1; -} - -CListBox::~CListBox() -{ - Term(); -} - -void CListBox::Init() -{ - Term(); -} - -void CListBox::Term() -{ - m_ItemOffset = 0; - - // Free the LBItems. - LBItem *pNext; - for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pNext) - { - pItem->m_pPanel->setParent(NULL); // detach the panel from us - pNext = pItem->m_pNext; - delete pItem; - } - m_Items.m_pPrev = m_Items.m_pNext = &m_Items; -} - -void CListBox::AddItem(Panel* panel) -{ - // Add the item. - LBItem *pItem = new LBItem; - if(!pItem) - return; - - pItem->m_pPanel = panel; - pItem->m_pPanel->setParent(&m_ItemsPanel); - - pItem->m_pPrev = m_Items.m_pPrev; - pItem->m_pNext = &m_Items; - pItem->m_pNext->m_pPrev = pItem->m_pPrev->m_pNext = pItem; - - m_ScrollBar.setRange(0, GetScrollMax()); - m_Slider.setRangeWindow(50); - m_Slider.setRangeWindowEnabled(true); - - InternalLayout(); -} - -int CListBox::GetNumItems() -{ - int count=0; - for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) - ++count; - - return count; -} - -int CListBox::GetItemWidth() -{ - int wide, tall; - m_ItemsPanel.getSize(wide, tall); - return wide; -} - -int CListBox::GetScrollPos() -{ - return m_ItemOffset; -} - -void CListBox::SetScrollPos(int pos) -{ - int maxItems = GetScrollMax(); - if(maxItems < 0) - return; - - m_ItemOffset = (pos < 0) ? 0 : ((pos > maxItems) ? maxItems : pos); - InternalLayout(); -} - -void CListBox::setPos(int x, int y) -{ - Panel::setPos(x, y); - InternalLayout(); -} - -void CListBox::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - InternalLayout(); -} - -void CListBox::setPixelScroll(int value) -{ - m_ItemOffset = m_ScrollBar.getValue(); - InternalLayout(); -} - -void CListBox::InternalLayout() -{ - int x, y, wide, tall; - getBounds(x, y, wide, tall); - - // Reposition the main panel and the scrollbar. - m_ItemsPanel.setBounds(0, 0, wide-15, tall); - m_ScrollBar.setBounds(wide-15, 0, 15, tall); - - bool bNeedScrollbar = false; - - // Reposition the items. - int curItem = 0; - int curY = 0; - int maxItem = GetScrollMax(); - for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) - { - if(curItem < m_ItemOffset) - { - pItem->m_pPanel->setVisible(false); - bNeedScrollbar = true; - } - else if (curItem >= maxItem) - { - // item is past the end of the items we care about - pItem->m_pPanel->setVisible(false); - } - else - { - pItem->m_pPanel->setVisible(true); - - int itemWidth, itemHeight; - pItem->m_pPanel->getSize(itemWidth, itemHeight); - - // Don't change the item's height but change its width to fit the listbox. - pItem->m_pPanel->setBounds(0, curY, wide, itemHeight); - - curY += itemHeight; - - if (curY > tall) - { - bNeedScrollbar = true; - } - } - - ++curItem; - } - - m_ScrollBar.setVisible(bNeedScrollbar); - - repaint(); -} - -void CListBox::paintBackground() -{ -} - -void CListBox::SetScrollRange(int maxScroll) -{ - m_iScrollMax = maxScroll; - m_ScrollBar.setRange(0, maxScroll); - InternalLayout(); -} - -int CListBox::GetScrollMax() -{ - if (m_iScrollMax < 0) - { - return GetNumItems() - 1; - } - - return m_iScrollMax; -} - - + +#include "vgui_listbox.h" + + + +using namespace vgui; + + +CListBox::CListBox() : Panel(0, 0, 0, 0), + m_ItemsPanel(0,0,0,0), + m_ScrollBar(0, 0, 0, 0, true), + m_Slider(0, 0, 10, 40, true) +{ + m_Signal.m_pListBox = this; + + m_ItemsPanel.setParent(this); + m_ItemsPanel.setBgColor(0,0,0,255); + + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + m_ScrollBar.setParent(this); + m_ScrollBar.addIntChangeSignal(&m_Signal); + m_ScrollBar.setSlider(&m_Slider); + m_ScrollBar.setButtonPressedScrollValue(1); + + m_Items.m_pNext = m_Items.m_pPrev = &m_Items; + m_ItemOffset = 0; + m_iScrollMax = -1; +} + +CListBox::~CListBox() +{ + Term(); +} + +void CListBox::Init() +{ + Term(); +} + +void CListBox::Term() +{ + m_ItemOffset = 0; + + // Free the LBItems. + LBItem *pNext; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pNext) + { + pItem->m_pPanel->setParent(NULL); // detach the panel from us + pNext = pItem->m_pNext; + delete pItem; + } + m_Items.m_pPrev = m_Items.m_pNext = &m_Items; +} + +void CListBox::AddItem(Panel* panel) +{ + // Add the item. + LBItem *pItem = new LBItem; + if(!pItem) + return; + + pItem->m_pPanel = panel; + pItem->m_pPanel->setParent(&m_ItemsPanel); + + pItem->m_pPrev = m_Items.m_pPrev; + pItem->m_pNext = &m_Items; + pItem->m_pNext->m_pPrev = pItem->m_pPrev->m_pNext = pItem; + + m_ScrollBar.setRange(0, GetScrollMax()); + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + InternalLayout(); +} + +int CListBox::GetNumItems() +{ + int count=0; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + ++count; + + return count; +} + +int CListBox::GetItemWidth() +{ + int wide, tall; + m_ItemsPanel.getSize(wide, tall); + return wide; +} + +int CListBox::GetScrollPos() +{ + return m_ItemOffset; +} + +void CListBox::SetScrollPos(int pos) +{ + int maxItems = GetScrollMax(); + if(maxItems < 0) + return; + + m_ItemOffset = (pos < 0) ? 0 : ((pos > maxItems) ? maxItems : pos); + InternalLayout(); +} + +void CListBox::setPos(int x, int y) +{ + Panel::setPos(x, y); + InternalLayout(); +} + +void CListBox::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + InternalLayout(); +} + +void CListBox::setPixelScroll(int value) +{ + m_ItemOffset = m_ScrollBar.getValue(); + InternalLayout(); +} + +void CListBox::InternalLayout() +{ + int x, y, wide, tall; + getBounds(x, y, wide, tall); + + // Reposition the main panel and the scrollbar. + m_ItemsPanel.setBounds(0, 0, wide-15, tall); + m_ScrollBar.setBounds(wide-15, 0, 15, tall); + + bool bNeedScrollbar = false; + + // Reposition the items. + int curItem = 0; + int curY = 0; + int maxItem = GetScrollMax(); + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + { + if(curItem < m_ItemOffset) + { + pItem->m_pPanel->setVisible(false); + bNeedScrollbar = true; + } + else if (curItem >= maxItem) + { + // item is past the end of the items we care about + pItem->m_pPanel->setVisible(false); + } + else + { + pItem->m_pPanel->setVisible(true); + + int itemWidth, itemHeight; + pItem->m_pPanel->getSize(itemWidth, itemHeight); + + // Don't change the item's height but change its width to fit the listbox. + pItem->m_pPanel->setBounds(0, curY, wide, itemHeight); + + curY += itemHeight; + + if (curY > tall) + { + bNeedScrollbar = true; + } + } + + ++curItem; + } + + m_ScrollBar.setVisible(bNeedScrollbar); + + repaint(); +} + +void CListBox::paintBackground() +{ +} + +void CListBox::SetScrollRange(int maxScroll) +{ + m_iScrollMax = maxScroll; + m_ScrollBar.setRange(0, maxScroll); + InternalLayout(); +} + +int CListBox::GetScrollMax() +{ + if (m_iScrollMax < 0) + { + return GetNumItems() - 1; + } + + return m_iScrollMax; +} + + diff --git a/main/source/game_shared/vgui_listbox.h b/main/source/game_shared/vgui_listbox.h index 0b224a29..1d014fa2 100644 --- a/main/source/game_shared/vgui_listbox.h +++ b/main/source/game_shared/vgui_listbox.h @@ -1,115 +1,115 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_LISTBOX_H -#define VOICE_LISTBOX_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "VGUI_Panel.h" -#include "VGUI_IntChangeSignal.h" - -#include "vgui_slider2.h" -#include "vgui_scrollbar2.h" - - -namespace vgui -{ - -// Listbox class used by voice code. Based off of vgui's list panel but with some modifications: -// - This listbox clips its child items to its rectangle. -// - You can access things like the scrollbar and find out the item width. -// - The scrollbar scrolls one element at a time and the range is correct. - -// Note: this listbox does not provide notification when items are -class CListBox : public Panel -{ -public: - - CListBox(); - ~CListBox(); - - void Init(); - void Term(); - - // Add an item to the listbox. This automatically sets the item's parent to the listbox - // and resizes the item's width to fit within the listbox. - void AddItem(Panel *pPanel); - - // Get the number of items currently in the listbox. - int GetNumItems(); - - // Get the width that listbox items will be set to (this changes if you resize the listbox). - int GetItemWidth(); - - // Get/set the scrollbar position (position says which element is at the top of the listbox). - int GetScrollPos(); - void SetScrollPos(int pos); - - // sets the last item the listbox should scroll to - // scroll to GetNumItems() if not set - void SetScrollRange(int maxScroll); - - // returns the maximum value the scrollbar can scroll to - int GetScrollMax(); - -// vgui overrides. -public: - - virtual void setPos(int x, int y); - virtual void setSize(int wide,int tall); - virtual void setPixelScroll(int value); - virtual void paintBackground(); - - -protected: - - class LBItem - { - public: - Panel *m_pPanel; - LBItem *m_pPrev, *m_pNext; - }; - - class ListBoxSignal : public IntChangeSignal - { - public: - void intChanged(int value,Panel* panel) - { - m_pListBox->setPixelScroll(-value); - } - - vgui::CListBox *m_pListBox; - }; - - -protected: - - void InternalLayout(); - - -protected: - - // All the items.. - LBItem m_Items; - - Panel m_ItemsPanel; - - int m_ItemOffset; // where we're scrolled to - Slider2 m_Slider; - ScrollBar2 m_ScrollBar; - ListBoxSignal m_Signal; - - int m_iScrollMax; -}; - -} - - -#endif // VOICE_LISTBOX_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_LISTBOX_H +#define VOICE_LISTBOX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Panel.h" +#include "VGUI_IntChangeSignal.h" + +#include "vgui_slider2.h" +#include "vgui_scrollbar2.h" + + +namespace vgui +{ + +// Listbox class used by voice code. Based off of vgui's list panel but with some modifications: +// - This listbox clips its child items to its rectangle. +// - You can access things like the scrollbar and find out the item width. +// - The scrollbar scrolls one element at a time and the range is correct. + +// Note: this listbox does not provide notification when items are +class CListBox : public Panel +{ +public: + + CListBox(); + ~CListBox(); + + void Init(); + void Term(); + + // Add an item to the listbox. This automatically sets the item's parent to the listbox + // and resizes the item's width to fit within the listbox. + void AddItem(Panel *pPanel); + + // Get the number of items currently in the listbox. + int GetNumItems(); + + // Get the width that listbox items will be set to (this changes if you resize the listbox). + int GetItemWidth(); + + // Get/set the scrollbar position (position says which element is at the top of the listbox). + int GetScrollPos(); + void SetScrollPos(int pos); + + // sets the last item the listbox should scroll to + // scroll to GetNumItems() if not set + void SetScrollRange(int maxScroll); + + // returns the maximum value the scrollbar can scroll to + int GetScrollMax(); + +// vgui overrides. +public: + + virtual void setPos(int x, int y); + virtual void setSize(int wide,int tall); + virtual void setPixelScroll(int value); + virtual void paintBackground(); + + +protected: + + class LBItem + { + public: + Panel *m_pPanel; + LBItem *m_pPrev, *m_pNext; + }; + + class ListBoxSignal : public IntChangeSignal + { + public: + void intChanged(int value,Panel* panel) + { + m_pListBox->setPixelScroll(-value); + } + + vgui::CListBox *m_pListBox; + }; + + +protected: + + void InternalLayout(); + + +protected: + + // All the items.. + LBItem m_Items; + + Panel m_ItemsPanel; + + int m_ItemOffset; // where we're scrolled to + Slider2 m_Slider; + ScrollBar2 m_ScrollBar; + ListBoxSignal m_Signal; + + int m_iScrollMax; +}; + +} + + +#endif // VOICE_LISTBOX_H diff --git a/main/source/game_shared/vgui_loadtga.cpp b/main/source/game_shared/vgui_loadtga.cpp index 087a5c17..863a885a 100644 --- a/main/source/game_shared/vgui_loadtga.cpp +++ b/main/source/game_shared/vgui_loadtga.cpp @@ -1,100 +1,100 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "../cl_dll/wrect.h" -#include "../cl_dll/cl_dll.h" -#include "VGUI.h" -#include "vgui_loadtga.h" -#include "VGUI_InputStream.h" - - -//#include "ui/MemoryInputStream.h" - -// : HACK -// Implemented old MemoryInputStream to work around bugs(?) in the other implementation or in -// the vgui's handling of the other one -class MemoryInputStream2 : public vgui::InputStream -{ -public: - MemoryInputStream2() - { - m_pData = NULL; - m_DataLen = m_ReadPos = 0; - } - - virtual void seekStart(bool& success) {m_ReadPos=0; success=true;} - virtual void seekRelative(int count,bool& success) {m_ReadPos+=count; success=true;} - virtual void seekEnd(bool& success) {m_ReadPos=m_DataLen; success=true;} - virtual int getAvailable(bool& success) {success=false; return 0;} // This is what vgui does for files... - - virtual uchar readUChar(bool& success) - { - if(m_ReadPos>=0 && m_ReadPos=0 && m_ReadPos - -vgui::BitmapTGA* vgui_LoadTGA(char const *pFilename, bool bInvertAlpha = true); -vgui::BitmapTGA* vgui_LoadTGANoInvertAlpha(char const *pFilename); - -#endif // VGUI_LOADTGA_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_LOADTGA_H +#define VGUI_LOADTGA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include + +vgui::BitmapTGA* vgui_LoadTGA(char const *pFilename, bool bInvertAlpha = true); +vgui::BitmapTGA* vgui_LoadTGANoInvertAlpha(char const *pFilename); + +#endif // VGUI_LOADTGA_H diff --git a/main/source/game_shared/vgui_scrollbar2.cpp b/main/source/game_shared/vgui_scrollbar2.cpp index 8df2c620..c43a8c8a 100644 --- a/main/source/game_shared/vgui_scrollbar2.cpp +++ b/main/source/game_shared/vgui_scrollbar2.cpp @@ -1,310 +1,310 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - - -#include "vgui_scrollbar2.h" -#include "vgui_slider2.h" -#include "vgui_loadtga.h" - -#include -#include -#include -#include - -using namespace vgui; - - -namespace -{ -class FooDefaultScrollBarIntChangeSignal : public IntChangeSignal -{ -public: - FooDefaultScrollBarIntChangeSignal(ScrollBar2* scrollBar) - { - _scrollBar=scrollBar; - } - virtual void intChanged(int value,Panel* panel) - { - _scrollBar->fireIntChangeSignal(); - } -protected: - ScrollBar2* _scrollBar; -}; - -class FooDefaultButtonSignal : public ActionSignal -{ -public: - ScrollBar2* _scrollBar; - int _buttonIndex; -public: - FooDefaultButtonSignal(ScrollBar2* scrollBar,int buttonIndex) - { - _scrollBar=scrollBar; - _buttonIndex=buttonIndex; - } -public: - virtual void actionPerformed(Panel* panel) - { - _scrollBar->doButtonPressed(_buttonIndex); - } -}; - -} - -//----------------------------------------------------------------------------- -// Purpose: Default scrollbar button -// Draws in new scoreboard style -//----------------------------------------------------------------------------- -class ScrollBarButton : public Button -{ -private: - LineBorder m_Border; - -public: - ScrollBarButton(const char *filename, int x, int y, int wide, int tall) : m_Border(Color(60, 60, 60, 0)), Button("", x, y, wide, tall) - { - Image *image = vgui_LoadTGA(filename); - if (image) - { - image->setColor(Color(140, 140, 140, 0)); - setImage(image); - } - - setBorder(&m_Border); - } - - virtual void paintBackground() - { - int wide,tall; - getPaintSize(wide,tall); - - // fill the background - drawSetColor(0, 0, 0, 0); - drawFilledRect(0, 0, wide, tall); - } -}; - - - - -//----------------------------------------------------------------------------- -// Purpose: Constructor -// Input : x - -// y - -// wide - -// tall - -// vertical - -//----------------------------------------------------------------------------- -ScrollBar2::ScrollBar2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) -{ - _slider=null; - _button[0]=null; - _button[1]=null; - - if(vertical) - { - setSlider(new Slider2(0,wide-1,wide,(tall-(wide*2))+2,true)); - setButton(new ScrollBarButton("gfx/vgui/arrowup.tga",0,0,wide,wide),0); - setButton(new ScrollBarButton("gfx/vgui/arrowdown.tga",0,tall-wide,wide,wide),1); - } - else - { - // untested code - setSlider(new Slider2(tall,0,wide-(tall*2),tall,false)); - setButton(new ScrollBarButton("gfx/vgui/320_arrowlt.tga",0,0,tall+1,tall+1),0); - setButton(new ScrollBarButton("gfx/vgui/320_arrowrt.tga",wide-tall,0,tall+1,tall+1),1); - } - - setPaintBorderEnabled(true); - setPaintBackgroundEnabled(true); - setPaintEnabled(true); - setButtonPressedScrollValue(15); - - validate(); - } - -void ScrollBar2::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - - if(_slider==null) - { - return; - } - - if(_button[0]==null) - { - return; - } - - if(_button[1]==null) - { - return; - } - - getPaintSize(wide,tall); - - if(_slider->isVertical()) - { - _slider->setBounds(0,wide,wide,tall-(wide*2)); - //_slider->setBounds(0,0,wide,tall); - _button[0]->setBounds(0,0,wide,wide); - _button[1]->setBounds(0,tall-wide,wide,wide); - } - else - { - _slider->setBounds(tall,0,wide-(tall*2),tall); - //_slider->setBounds(0,0,wide,tall); - _button[0]->setBounds(0,0,tall,tall); - _button[1]->setBounds((wide-tall),0,tall,tall); - } -} - -void ScrollBar2::performLayout() -{ -} - -void ScrollBar2::setValue(int value) -{ - _slider->setValue(value); -} - -int ScrollBar2::getValue() -{ - return _slider->getValue(); -} - -void ScrollBar2::addIntChangeSignal(IntChangeSignal* s) -{ - _intChangeSignalDar.putElement(s); - _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); -} - -void ScrollBar2::setRange(int min,int max) -{ - _slider->setRange(min,max); -} - -void ScrollBar2::fireIntChangeSignal() -{ - for(int i=0;i<_intChangeSignalDar.getCount();i++) - { - _intChangeSignalDar[i]->intChanged(_slider->getValue(),this); - } -} - -bool ScrollBar2::isVertical() -{ - return _slider->isVertical(); -} - -bool ScrollBar2::hasFullRange() -{ - return _slider->hasFullRange(); -} - -//LEAK: new and old slider will leak -void ScrollBar2::setButton(Button* button,int index) -{ - if(_button[index]!=null) - { - removeChild(_button[index]); - } - _button[index]=button; - addChild(_button[index]); - - _button[index]->addActionSignal(new FooDefaultButtonSignal(this,index)); - - validate(); - - //_button[index]->setVisible(false); -} - -Button* ScrollBar2::getButton(int index) -{ - return _button[index]; -} - -//LEAK: new and old slider will leak -void ScrollBar2::setSlider(Slider2 *slider) -{ - if(_slider!=null) - { - removeChild(_slider); - } - _slider=slider; - addChild(_slider); - - _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); - - validate(); -} - -Slider2 *ScrollBar2::getSlider() -{ - return _slider; -} - -void ScrollBar2::doButtonPressed(int buttonIndex) -{ - if(buttonIndex==0) - { - _slider->setValue(_slider->getValue()-_buttonPressedScrollValue); - } - else - { - _slider->setValue(_slider->getValue()+_buttonPressedScrollValue); - } - -} - -void ScrollBar2::setButtonPressedScrollValue(int value) -{ - _buttonPressedScrollValue=value; -} - -void ScrollBar2::setRangeWindow(int rangeWindow) -{ - _slider->setRangeWindow(rangeWindow); -} - -void ScrollBar2::setRangeWindowEnabled(bool state) -{ - _slider->setRangeWindowEnabled(state); -} - -void ScrollBar2::validate() -{ - if(_slider!=null) - { - int buttonOffset=0; - - for(int i=0;i<2;i++) - { - if(_button[i]!=null) - { - if(_button[i]->isVisible()) - { - if(_slider->isVertical()) - { - buttonOffset+=_button[i]->getTall(); - } - else - { - buttonOffset+=_button[i]->getWide(); - } - } - } - } - - _slider->setButtonOffset(buttonOffset); - } - - int wide,tall; - getSize(wide,tall); - setSize(wide,tall); -} +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + + +#include "vgui_scrollbar2.h" +#include "vgui_slider2.h" +#include "vgui_loadtga.h" + +#include +#include +#include +#include + +using namespace vgui; + + +namespace +{ +class FooDefaultScrollBarIntChangeSignal : public IntChangeSignal +{ +public: + FooDefaultScrollBarIntChangeSignal(ScrollBar2* scrollBar) + { + _scrollBar=scrollBar; + } + virtual void intChanged(int value,Panel* panel) + { + _scrollBar->fireIntChangeSignal(); + } +protected: + ScrollBar2* _scrollBar; +}; + +class FooDefaultButtonSignal : public ActionSignal +{ +public: + ScrollBar2* _scrollBar; + int _buttonIndex; +public: + FooDefaultButtonSignal(ScrollBar2* scrollBar,int buttonIndex) + { + _scrollBar=scrollBar; + _buttonIndex=buttonIndex; + } +public: + virtual void actionPerformed(Panel* panel) + { + _scrollBar->doButtonPressed(_buttonIndex); + } +}; + +} + +//----------------------------------------------------------------------------- +// Purpose: Default scrollbar button +// Draws in new scoreboard style +//----------------------------------------------------------------------------- +class ScrollBarButton : public Button +{ +private: + LineBorder m_Border; + +public: + ScrollBarButton(const char *filename, int x, int y, int wide, int tall) : m_Border(Color(60, 60, 60, 0)), Button("", x, y, wide, tall) + { + Image *image = vgui_LoadTGA(filename); + if (image) + { + image->setColor(Color(140, 140, 140, 0)); + setImage(image); + } + + setBorder(&m_Border); + } + + virtual void paintBackground() + { + int wide,tall; + getPaintSize(wide,tall); + + // fill the background + drawSetColor(0, 0, 0, 0); + drawFilledRect(0, 0, wide, tall); + } +}; + + + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : x - +// y - +// wide - +// tall - +// vertical - +//----------------------------------------------------------------------------- +ScrollBar2::ScrollBar2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _slider=null; + _button[0]=null; + _button[1]=null; + + if(vertical) + { + setSlider(new Slider2(0,wide-1,wide,(tall-(wide*2))+2,true)); + setButton(new ScrollBarButton("gfx/vgui/arrowup.tga",0,0,wide,wide),0); + setButton(new ScrollBarButton("gfx/vgui/arrowdown.tga",0,tall-wide,wide,wide),1); + } + else + { + // untested code + setSlider(new Slider2(tall,0,wide-(tall*2),tall,false)); + setButton(new ScrollBarButton("gfx/vgui/320_arrowlt.tga",0,0,tall+1,tall+1),0); + setButton(new ScrollBarButton("gfx/vgui/320_arrowrt.tga",wide-tall,0,tall+1,tall+1),1); + } + + setPaintBorderEnabled(true); + setPaintBackgroundEnabled(true); + setPaintEnabled(true); + setButtonPressedScrollValue(15); + + validate(); + } + +void ScrollBar2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + if(_slider==null) + { + return; + } + + if(_button[0]==null) + { + return; + } + + if(_button[1]==null) + { + return; + } + + getPaintSize(wide,tall); + + if(_slider->isVertical()) + { + _slider->setBounds(0,wide,wide,tall-(wide*2)); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,wide,wide); + _button[1]->setBounds(0,tall-wide,wide,wide); + } + else + { + _slider->setBounds(tall,0,wide-(tall*2),tall); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,tall,tall); + _button[1]->setBounds((wide-tall),0,tall,tall); + } +} + +void ScrollBar2::performLayout() +{ +} + +void ScrollBar2::setValue(int value) +{ + _slider->setValue(value); +} + +int ScrollBar2::getValue() +{ + return _slider->getValue(); +} + +void ScrollBar2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); +} + +void ScrollBar2::setRange(int min,int max) +{ + _slider->setRange(min,max); +} + +void ScrollBar2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(_slider->getValue(),this); + } +} + +bool ScrollBar2::isVertical() +{ + return _slider->isVertical(); +} + +bool ScrollBar2::hasFullRange() +{ + return _slider->hasFullRange(); +} + +//LEAK: new and old slider will leak +void ScrollBar2::setButton(Button* button,int index) +{ + if(_button[index]!=null) + { + removeChild(_button[index]); + } + _button[index]=button; + addChild(_button[index]); + + _button[index]->addActionSignal(new FooDefaultButtonSignal(this,index)); + + validate(); + + //_button[index]->setVisible(false); +} + +Button* ScrollBar2::getButton(int index) +{ + return _button[index]; +} + +//LEAK: new and old slider will leak +void ScrollBar2::setSlider(Slider2 *slider) +{ + if(_slider!=null) + { + removeChild(_slider); + } + _slider=slider; + addChild(_slider); + + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); + + validate(); +} + +Slider2 *ScrollBar2::getSlider() +{ + return _slider; +} + +void ScrollBar2::doButtonPressed(int buttonIndex) +{ + if(buttonIndex==0) + { + _slider->setValue(_slider->getValue()-_buttonPressedScrollValue); + } + else + { + _slider->setValue(_slider->getValue()+_buttonPressedScrollValue); + } + +} + +void ScrollBar2::setButtonPressedScrollValue(int value) +{ + _buttonPressedScrollValue=value; +} + +void ScrollBar2::setRangeWindow(int rangeWindow) +{ + _slider->setRangeWindow(rangeWindow); +} + +void ScrollBar2::setRangeWindowEnabled(bool state) +{ + _slider->setRangeWindowEnabled(state); +} + +void ScrollBar2::validate() +{ + if(_slider!=null) + { + int buttonOffset=0; + + for(int i=0;i<2;i++) + { + if(_button[i]!=null) + { + if(_button[i]->isVisible()) + { + if(_slider->isVertical()) + { + buttonOffset+=_button[i]->getTall(); + } + else + { + buttonOffset+=_button[i]->getWide(); + } + } + } + } + + _slider->setButtonOffset(buttonOffset); + } + + int wide,tall; + getSize(wide,tall); + setSize(wide,tall); +} diff --git a/main/source/game_shared/vgui_scrollbar2.h b/main/source/game_shared/vgui_scrollbar2.h index ba85bb65..f83956cf 100644 --- a/main/source/game_shared/vgui_scrollbar2.h +++ b/main/source/game_shared/vgui_scrollbar2.h @@ -1,62 +1,62 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_SCROLLBAR2_H -#define VGUI_SCROLLBAR2_H -#ifdef _WIN32 -#pragma once -#endif - -#include -#include -#include - -namespace vgui -{ - -class IntChangeSignal; -class Button; -class Slider2; - -//----------------------------------------------------------------------------- -// Purpose: Hacked up version of the vgui scrollbar -//----------------------------------------------------------------------------- -class VGUIAPI ScrollBar2 : public Panel -{ -public: - ScrollBar2(int x,int y,int wide,int tall,bool vertical); -public: - virtual void setValue(int value); - virtual int getValue(); - virtual void addIntChangeSignal(IntChangeSignal* s); - virtual void setRange(int min,int max); - virtual void setRangeWindow(int rangeWindow); - virtual void setRangeWindowEnabled(bool state); - virtual void setSize(int wide,int tall); - virtual bool isVertical(); - virtual bool hasFullRange(); - virtual void setButton(Button *button,int index); - virtual Button* getButton(int index); - virtual void setSlider(Slider2 *slider); - virtual Slider2 *getSlider(); - virtual void doButtonPressed(int buttonIndex); - virtual void setButtonPressedScrollValue(int value); - virtual void validate(); -public: //bullshit public - virtual void fireIntChangeSignal(); -protected: - virtual void performLayout(); -protected: - Button* _button[2]; - Slider2 *_slider; - Dar _intChangeSignalDar; - int _buttonPressedScrollValue; -}; - -} - -#endif // VGUI_SCROLLBAR2_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SCROLLBAR2_H +#define VGUI_SCROLLBAR2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class IntChangeSignal; +class Button; +class Slider2; + +//----------------------------------------------------------------------------- +// Purpose: Hacked up version of the vgui scrollbar +//----------------------------------------------------------------------------- +class VGUIAPI ScrollBar2 : public Panel +{ +public: + ScrollBar2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual bool isVertical(); + virtual bool hasFullRange(); + virtual void setButton(Button *button,int index); + virtual Button* getButton(int index); + virtual void setSlider(Slider2 *slider); + virtual Slider2 *getSlider(); + virtual void doButtonPressed(int buttonIndex); + virtual void setButtonPressedScrollValue(int value); + virtual void validate(); +public: //bullshit public + virtual void fireIntChangeSignal(); +protected: + virtual void performLayout(); +protected: + Button* _button[2]; + Slider2 *_slider; + Dar _intChangeSignalDar; + int _buttonPressedScrollValue; +}; + +} + +#endif // VGUI_SCROLLBAR2_H diff --git a/main/source/game_shared/vgui_slider2.cpp b/main/source/game_shared/vgui_slider2.cpp index db3dc3de..966a2f8e 100644 --- a/main/source/game_shared/vgui_slider2.cpp +++ b/main/source/game_shared/vgui_slider2.cpp @@ -1,436 +1,436 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -#include "vgui_slider2.h" - -#include -#include -#include -#include - -using namespace vgui; - -namespace -{ -class FooDefaultSliderSignal : public InputSignal -{ -private: - Slider2* _slider; -public: - FooDefaultSliderSignal(Slider2* slider) - { - _slider=slider; - } -public: - void cursorMoved(int x,int y,Panel* panel) - { - _slider->privateCursorMoved(x,y,panel); - } - void cursorEntered(Panel* panel){} - void cursorExited(Panel* panel){} - void mouseDoublePressed(MouseCode code,Panel* panel){} - void mousePressed(MouseCode code,Panel* panel) - { - _slider->privateMousePressed(code,panel); - } - void mouseReleased(MouseCode code,Panel* panel) - { - _slider->privateMouseReleased(code,panel); - } - void mouseWheeled(int delta,Panel* panel){} - void keyPressed(KeyCode code,Panel* panel){} - void keyTyped(KeyCode code,Panel* panel){} - void keyReleased(KeyCode code,Panel* panel){} - void keyFocusTicked(Panel* panel){} -}; -} - -Slider2::Slider2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) -{ - _vertical=vertical; - _dragging=false; - _value=0; - _range[0]=0; - _range[1]=299; - _rangeWindow=0; - _rangeWindowEnabled=false; - _buttonOffset=0; - recomputeNobPosFromValue(); - addInputSignal(new FooDefaultSliderSignal(this)); -} - -void Slider2::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - recomputeNobPosFromValue(); -} - -bool Slider2::isVertical() -{ - return _vertical; -} - -void Slider2::setValue(int value) -{ - int oldValue=_value; - - if(value<_range[0]) - { - value=_range[0]; - } - - if(value>_range[1]) - { - value=_range[1]; - } - - _value=value; - recomputeNobPosFromValue(); - - if(_value!=oldValue) - { - fireIntChangeSignal(); - } -} - -int Slider2::getValue() -{ - return _value; -} - -void Slider2::recomputeNobPosFromValue() -{ - int wide,tall; - - getPaintSize(wide,tall); - - float fwide=(float)wide; - float ftall=(float)tall; - float frange=(float)(_range[1]-_range[0]); - float fvalue=(float)(_value-_range[0]); - float fper=fvalue/frange; - float frangewindow=(float)(_rangeWindow); - - if(frangewindow<0) - { - frangewindow=0; - } - - if(!_rangeWindowEnabled) - { - frangewindow=frange; - } - - if ( frangewindow > 0 ) - { - if(_vertical) - { - float fnobsize=frangewindow; - float freepixels = ftall - fnobsize; - - float firstpixel = freepixels * fper; - - _nobPos[0]=(int)( firstpixel ); - _nobPos[1]=(int)( firstpixel + fnobsize ); - - if(_nobPos[1]>tall) - { - _nobPos[0]=tall-((int)fnobsize); - _nobPos[1]=tall; - } - } - else - { - float fnobsize=frangewindow; - float freepixels = fwide - fnobsize; - - float firstpixel = freepixels * fper; - - _nobPos[0]=(int)( firstpixel ); - _nobPos[1]=(int)( firstpixel + fnobsize ); - - if(_nobPos[1]>wide) - { - _nobPos[0]=wide-((int)fnobsize); - _nobPos[1]=wide; - } - } - } - - repaint(); -} - -void Slider2::recomputeValueFromNobPos() -{ - int wide,tall; - getPaintSize(wide,tall); - - float fwide=(float)wide; - float ftall=(float)tall; - float frange=(float)(_range[1]-_range[0]); - float fvalue=(float)(_value-_range[0]); - float fnob=(float)_nobPos[0]; - float frangewindow=(float)(_rangeWindow); - - if(frangewindow<0) - { - frangewindow=0; - } - - if(!_rangeWindowEnabled) - { - frangewindow=frange; - } - - if ( frangewindow > 0 ) - { - if(_vertical) - { - float fnobsize=frangewindow; - fvalue=frange*(fnob/(ftall-fnobsize)); - } - else - { - float fnobsize=frangewindow; - fvalue=frange*(fnob/(fwide-fnobsize)); - } - } - // Take care of rounding issues. - _value=(int)(fvalue+_range[0]+0.5); - - // Clamp final result - _value = ( _value < _range[1] ) ? _value : _range[1]; -} - -bool Slider2::hasFullRange() -{ - int wide,tall; - getPaintSize(wide,tall); - - float fwide=(float)wide; - float ftall=(float)tall; - float frange=(float)(_range[1]-_range[0]); - float frangewindow=(float)(_rangeWindow); - - if(frangewindow<0) - { - frangewindow=0; - } - - if(!_rangeWindowEnabled) - { - frangewindow=frange; - } - - if ( frangewindow > 0 ) - { - if(_vertical) - { - if( frangewindow <= ( ftall + _buttonOffset ) ) - { - return true; - } - } - else - { - if( frangewindow <= ( fwide + _buttonOffset ) ) - { - return true; - } - } - } - - return false; -} - -void Slider2::addIntChangeSignal(IntChangeSignal* s) -{ - _intChangeSignalDar.putElement(s); -} - -void Slider2::fireIntChangeSignal() -{ - for(int i=0;i<_intChangeSignalDar.getCount();i++) - { - _intChangeSignalDar[i]->intChanged(getValue(),this); - } -} - -void Slider2::paintBackground() -{ - int wide,tall; - getPaintSize(wide,tall); - - if (_vertical) - { - // background behind slider - drawSetColor(40, 40, 40, 0); - drawFilledRect(0, 0, wide, tall); - - // slider front - drawSetColor(0, 0, 0, 0); - drawFilledRect(0,_nobPos[0],wide,_nobPos[1]); - - // slider border - drawSetColor(60, 60, 60, 0); - drawFilledRect(0,_nobPos[0],wide,_nobPos[0]+1); // top - drawFilledRect(0,_nobPos[1],wide,_nobPos[1]+1); // bottom - drawFilledRect(0,_nobPos[0]+1,1,_nobPos[1]); // left - drawFilledRect(wide-1,_nobPos[0]+1,wide,_nobPos[1]); // right - } - else - { - //!! doesn't work - - drawSetColor(Scheme::sc_secondary3); - drawFilledRect(0,0,wide,tall); - - drawSetColor(Scheme::sc_black); - drawOutlinedRect(0,0,wide,tall); - - drawSetColor(Scheme::sc_primary2); - drawFilledRect(_nobPos[0],0,_nobPos[1],tall); - - drawSetColor(Scheme::sc_black); - drawOutlinedRect(_nobPos[0],0,_nobPos[1],tall); - } -} - -void Slider2::setRange(int min,int max) -{ - if(maxmax) - { - min=max; - } - - _range[0]=min; - _range[1]=max; -} - -void Slider2::getRange(int& min,int& max) -{ - min=_range[0]; - max=_range[1]; -} - -void Slider2::privateCursorMoved(int x,int y,Panel* panel) -{ - if(!_dragging) - { - return; - } - - getApp()->getCursorPos(x,y); - screenToLocal(x,y); - - int wide,tall; - getPaintSize(wide,tall); - - if(_vertical) - { - _nobPos[0]=_nobDragStartPos[0]+(y-_dragStartPos[1]); - _nobPos[1]=_nobDragStartPos[1]+(y-_dragStartPos[1]); - - if(_nobPos[1]>tall) - { - _nobPos[0]=tall-(_nobPos[1]-_nobPos[0]); - _nobPos[1]=tall; - } - - if(_nobPos[0]<0) - { - _nobPos[1]=_nobPos[1]-_nobPos[0]; - _nobPos[0]=0; - } - } - else - { - _nobPos[0]=_nobDragStartPos[0]+(x-_dragStartPos[0]); - _nobPos[1]=_nobDragStartPos[1]+(x-_dragStartPos[0]); - - if(_nobPos[1]>wide) - { - _nobPos[0]=wide-(_nobPos[1]-_nobPos[0]); - _nobPos[1]=wide; - } - - if(_nobPos[0]<0) - { - _nobPos[1]=_nobPos[1]-_nobPos[0]; - _nobPos[0]=0; - } - } - - recomputeValueFromNobPos(); - repaint(); - fireIntChangeSignal(); -} - -void Slider2::privateMousePressed(MouseCode code,Panel* panel) -{ - int x,y; - getApp()->getCursorPos(x,y); - screenToLocal(x,y); - - if(_vertical) - { - if((y>=_nobPos[0])&&(y<_nobPos[1])) - { - _dragging=true; - getApp()->setMouseCapture(this); - _nobDragStartPos[0]=_nobPos[0]; - _nobDragStartPos[1]=_nobPos[1]; - _dragStartPos[0]=x; - _dragStartPos[1]=y; - } - } - else - { - if((x>=_nobPos[0])&&(x<_nobPos[1])) - { - _dragging=true; - getApp()->setMouseCapture(this); - _nobDragStartPos[0]=_nobPos[0]; - _nobDragStartPos[1]=_nobPos[1]; - _dragStartPos[0]=x; - _dragStartPos[1]=y; - } - } - -} - -void Slider2::privateMouseReleased(MouseCode code,Panel* panel) -{ - _dragging=false; - getApp()->setMouseCapture(null); -} - -void Slider2::getNobPos(int& min, int& max) -{ - min=_nobPos[0]; - max=_nobPos[1]; -} - -void Slider2::setRangeWindow(int rangeWindow) -{ - _rangeWindow=rangeWindow; -} - -void Slider2::setRangeWindowEnabled(bool state) -{ - _rangeWindowEnabled=state; -} - -void Slider2::setButtonOffset(int buttonOffset) -{ - _buttonOffset=buttonOffset; -} +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: New version of the slider bar +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_slider2.h" + +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooDefaultSliderSignal : public InputSignal +{ +private: + Slider2* _slider; +public: + FooDefaultSliderSignal(Slider2* slider) + { + _slider=slider; + } +public: + void cursorMoved(int x,int y,Panel* panel) + { + _slider->privateCursorMoved(x,y,panel); + } + void cursorEntered(Panel* panel){} + void cursorExited(Panel* panel){} + void mouseDoublePressed(MouseCode code,Panel* panel){} + void mousePressed(MouseCode code,Panel* panel) + { + _slider->privateMousePressed(code,panel); + } + void mouseReleased(MouseCode code,Panel* panel) + { + _slider->privateMouseReleased(code,panel); + } + void mouseWheeled(int delta,Panel* panel){} + void keyPressed(KeyCode code,Panel* panel){} + void keyTyped(KeyCode code,Panel* panel){} + void keyReleased(KeyCode code,Panel* panel){} + void keyFocusTicked(Panel* panel){} +}; +} + +Slider2::Slider2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _vertical=vertical; + _dragging=false; + _value=0; + _range[0]=0; + _range[1]=299; + _rangeWindow=0; + _rangeWindowEnabled=false; + _buttonOffset=0; + recomputeNobPosFromValue(); + addInputSignal(new FooDefaultSliderSignal(this)); +} + +void Slider2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + recomputeNobPosFromValue(); +} + +bool Slider2::isVertical() +{ + return _vertical; +} + +void Slider2::setValue(int value) +{ + int oldValue=_value; + + if(value<_range[0]) + { + value=_range[0]; + } + + if(value>_range[1]) + { + value=_range[1]; + } + + _value=value; + recomputeNobPosFromValue(); + + if(_value!=oldValue) + { + fireIntChangeSignal(); + } +} + +int Slider2::getValue() +{ + return _value; +} + +void Slider2::recomputeNobPosFromValue() +{ + int wide,tall; + + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fper=fvalue/frange; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + float freepixels = ftall - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-((int)fnobsize); + _nobPos[1]=tall; + } + } + else + { + float fnobsize=frangewindow; + float freepixels = fwide - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-((int)fnobsize); + _nobPos[1]=wide; + } + } + } + + repaint(); +} + +void Slider2::recomputeValueFromNobPos() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fnob=(float)_nobPos[0]; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(ftall-fnobsize)); + } + else + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(fwide-fnobsize)); + } + } + // Take care of rounding issues. + _value=(int)(fvalue+_range[0]+0.5); + + // Clamp final result + _value = ( _value < _range[1] ) ? _value : _range[1]; +} + +bool Slider2::hasFullRange() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + if( frangewindow <= ( ftall + _buttonOffset ) ) + { + return true; + } + } + else + { + if( frangewindow <= ( fwide + _buttonOffset ) ) + { + return true; + } + } + } + + return false; +} + +void Slider2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); +} + +void Slider2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(getValue(),this); + } +} + +void Slider2::paintBackground() +{ + int wide,tall; + getPaintSize(wide,tall); + + if (_vertical) + { + // background behind slider + drawSetColor(40, 40, 40, 0); + drawFilledRect(0, 0, wide, tall); + + // slider front + drawSetColor(0, 0, 0, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[1]); + + // slider border + drawSetColor(60, 60, 60, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[0]+1); // top + drawFilledRect(0,_nobPos[1],wide,_nobPos[1]+1); // bottom + drawFilledRect(0,_nobPos[0]+1,1,_nobPos[1]); // left + drawFilledRect(wide-1,_nobPos[0]+1,wide,_nobPos[1]); // right + } + else + { + //!! doesn't work + + drawSetColor(Scheme::sc_secondary3); + drawFilledRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_primary2); + drawFilledRect(_nobPos[0],0,_nobPos[1],tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(_nobPos[0],0,_nobPos[1],tall); + } +} + +void Slider2::setRange(int min,int max) +{ + if(maxmax) + { + min=max; + } + + _range[0]=min; + _range[1]=max; +} + +void Slider2::getRange(int& min,int& max) +{ + min=_range[0]; + max=_range[1]; +} + +void Slider2::privateCursorMoved(int x,int y,Panel* panel) +{ + if(!_dragging) + { + return; + } + + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + int wide,tall; + getPaintSize(wide,tall); + + if(_vertical) + { + _nobPos[0]=_nobDragStartPos[0]+(y-_dragStartPos[1]); + _nobPos[1]=_nobDragStartPos[1]+(y-_dragStartPos[1]); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=tall; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + else + { + _nobPos[0]=_nobDragStartPos[0]+(x-_dragStartPos[0]); + _nobPos[1]=_nobDragStartPos[1]+(x-_dragStartPos[0]); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=wide; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + + recomputeValueFromNobPos(); + repaint(); + fireIntChangeSignal(); +} + +void Slider2::privateMousePressed(MouseCode code,Panel* panel) +{ + int x,y; + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + if(_vertical) + { + if((y>=_nobPos[0])&&(y<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + else + { + if((x>=_nobPos[0])&&(x<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + +} + +void Slider2::privateMouseReleased(MouseCode code,Panel* panel) +{ + _dragging=false; + getApp()->setMouseCapture(null); +} + +void Slider2::getNobPos(int& min, int& max) +{ + min=_nobPos[0]; + max=_nobPos[1]; +} + +void Slider2::setRangeWindow(int rangeWindow) +{ + _rangeWindow=rangeWindow; +} + +void Slider2::setRangeWindowEnabled(bool state) +{ + _rangeWindowEnabled=state; +} + +void Slider2::setButtonOffset(int buttonOffset) +{ + _buttonOffset=buttonOffset; +} diff --git a/main/source/game_shared/vgui_slider2.h b/main/source/game_shared/vgui_slider2.h index 4f1d3f8c..90648a75 100644 --- a/main/source/game_shared/vgui_slider2.h +++ b/main/source/game_shared/vgui_slider2.h @@ -1,67 +1,67 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_SLIDER2_H -#define VGUI_SLIDER2_H -#ifdef _WIN32 -#pragma once -#endif - -#include -#include -#include - -namespace vgui -{ - -enum MouseCode; -class IntChangeSignal; - -class VGUIAPI Slider2 : public Panel -{ -private: - bool _vertical; - bool _dragging; - int _nobPos[2]; - int _nobDragStartPos[2]; - int _dragStartPos[2]; - Dar _intChangeSignalDar; - int _range[2]; - int _value; - int _rangeWindow; - bool _rangeWindowEnabled; - int _buttonOffset; -public: - Slider2(int x,int y,int wide,int tall,bool vertical); -public: - virtual void setValue(int value); - virtual int getValue(); - virtual bool isVertical(); - virtual void addIntChangeSignal(IntChangeSignal* s); - virtual void setRange(int min,int max); - virtual void getRange(int& min,int& max); - virtual void setRangeWindow(int rangeWindow); - virtual void setRangeWindowEnabled(bool state); - virtual void setSize(int wide,int tall); - virtual void getNobPos(int& min, int& max); - virtual bool hasFullRange(); - virtual void setButtonOffset(int buttonOffset); -private: - virtual void recomputeNobPosFromValue(); - virtual void recomputeValueFromNobPos(); -public: //bullshit public - virtual void privateCursorMoved(int x,int y,Panel* panel); - virtual void privateMousePressed(MouseCode code,Panel* panel); - virtual void privateMouseReleased(MouseCode code,Panel* panel); -protected: - virtual void fireIntChangeSignal(); - virtual void paintBackground(); -}; - -} - -#endif // VGUI_SLIDER2_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SLIDER2_H +#define VGUI_SLIDER2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class IntChangeSignal; + +class VGUIAPI Slider2 : public Panel +{ +private: + bool _vertical; + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + Dar _intChangeSignalDar; + int _range[2]; + int _value; + int _rangeWindow; + bool _rangeWindowEnabled; + int _buttonOffset; +public: + Slider2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual bool isVertical(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void getRange(int& min,int& max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual void getNobPos(int& min, int& max); + virtual bool hasFullRange(); + virtual void setButtonOffset(int buttonOffset); +private: + virtual void recomputeNobPosFromValue(); + virtual void recomputeValueFromNobPos(); +public: //bullshit public + virtual void privateCursorMoved(int x,int y,Panel* panel); + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseReleased(MouseCode code,Panel* panel); +protected: + virtual void fireIntChangeSignal(); + virtual void paintBackground(); +}; + +} + +#endif // VGUI_SLIDER2_H diff --git a/main/source/game_shared/voice_banmgr.cpp b/main/source/game_shared/voice_banmgr.cpp index 09b6ec0f..14e773cd 100644 --- a/main/source/game_shared/voice_banmgr.cpp +++ b/main/source/game_shared/voice_banmgr.cpp @@ -1,197 +1,197 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include -#include "voice_banmgr.h" -#include "../dlls/extdll.h" -#include "../localassert.h" -#define BANMGR_FILEVERSION 1 -char const *g_pBanMgrFilename = "voice_ban.dt"; - - - -// Hash a player ID to a byte. -unsigned char HashPlayerID(char const playerID[16]) -{ - char curHash = 0; - - for(int i=0; i < 16; i++) - curHash += (char)(playerID[i]); - - return (unsigned char)curHash; -} - - - -CVoiceBanMgr::CVoiceBanMgr() -{ - Clear(); -} - - -CVoiceBanMgr::~CVoiceBanMgr() -{ - Term(); -} - - -bool CVoiceBanMgr::Init(char const *pGameDir) -{ - Term(); - - char filename[512]; - _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); - - // Load in the squelch file. - FILE *fp = fopen(filename, "rb"); - if(fp) - { - int version; - fread(&version, 1, sizeof(version), fp); - if(version == BANMGR_FILEVERSION) - { - fseek(fp, 0, SEEK_END); - int nIDs = (ftell(fp) - sizeof(version)) / 16; - fseek(fp, sizeof(version), SEEK_SET); - - for(int i=0; i < nIDs; i++) - { - char playerID[16]; - fread(playerID, 1, 16, fp); - AddBannedPlayer(playerID); - } - } - - fclose(fp); - } - - return true; -} - - -void CVoiceBanMgr::Term() -{ - // Free all the player structures. - for(int i=0; i < 256; i++) - { - BannedPlayer *pListHead = &m_PlayerHash[i]; - BannedPlayer *pNext; - for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pNext) - { - pNext = pCur->m_pNext; - delete pCur; - } - } - - Clear(); -} - - -void CVoiceBanMgr::SaveState(char const *pGameDir) -{ - // Save the file out. - char filename[512]; - _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); - - FILE *fp = fopen(filename, "wb"); - if(fp) - { - int version = BANMGR_FILEVERSION; - fwrite(&version, 1, sizeof(version), fp); - - for(int i=0; i < 256; i++) - { - BannedPlayer *pListHead = &m_PlayerHash[i]; - for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) - { - fwrite(pCur->m_PlayerID, 1, 16, fp); - } - } - - fclose(fp); - } -} - - -bool CVoiceBanMgr::GetPlayerBan(char const playerID[16]) -{ - return !!InternalFindPlayerSquelch(playerID); -} - - -void CVoiceBanMgr::SetPlayerBan(char const playerID[16], bool bSquelch) -{ - if(bSquelch) - { - // Is this guy already squelched? - if(GetPlayerBan(playerID)) - return; - - AddBannedPlayer(playerID); - } - else - { - BannedPlayer *pPlayer = InternalFindPlayerSquelch(playerID); - if(pPlayer) - { - pPlayer->m_pPrev->m_pNext = pPlayer->m_pNext; - pPlayer->m_pNext->m_pPrev = pPlayer->m_pPrev; - delete pPlayer; - } - } -} - - -void CVoiceBanMgr::ForEachBannedPlayer(void (*callback)(char id[16])) -{ - for(int i=0; i < 256; i++) - { - for(BannedPlayer *pCur=m_PlayerHash[i].m_pNext; pCur != &m_PlayerHash[i]; pCur=pCur->m_pNext) - { - callback(pCur->m_PlayerID); - } - } -} - - -void CVoiceBanMgr::Clear() -{ - // Tie off the hash table entries. - for(int i=0; i < 256; i++) - m_PlayerHash[i].m_pNext = m_PlayerHash[i].m_pPrev = &m_PlayerHash[i]; -} - - -CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::InternalFindPlayerSquelch(char const playerID[16]) -{ - int index = (int)HashPlayerID(playerID) & 0xFF; - BannedPlayer *pListHead = &m_PlayerHash[index]; - for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) - { - if(memcmp(playerID, pCur->m_PlayerID, 16) == 0) - return pCur; - } - - return NULL; -} - - -CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::AddBannedPlayer(char const playerID[16]) -{ - BannedPlayer *pNew = new BannedPlayer; - if(!pNew) - return NULL; - - int index = HashPlayerID(playerID); - memcpy(pNew->m_PlayerID, playerID, 16); - pNew->m_pNext = &m_PlayerHash[index]; - pNew->m_pPrev = m_PlayerHash[index].m_pPrev; - pNew->m_pPrev->m_pNext = pNew->m_pNext->m_pPrev = pNew; - return pNew; -} - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "voice_banmgr.h" +#include "../dlls/extdll.h" +#include "../localassert.h" +#define BANMGR_FILEVERSION 1 +char const *g_pBanMgrFilename = "voice_ban.dt"; + + + +// Hash a player ID to a byte. +unsigned char HashPlayerID(char const playerID[16]) +{ + char curHash = 0; + + for(int i=0; i < 16; i++) + curHash += (char)(playerID[i]); + + return (unsigned char)curHash; +} + + + +CVoiceBanMgr::CVoiceBanMgr() +{ + Clear(); +} + + +CVoiceBanMgr::~CVoiceBanMgr() +{ + Term(); +} + + +bool CVoiceBanMgr::Init(char const *pGameDir) +{ + Term(); + + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + // Load in the squelch file. + FILE *fp = fopen(filename, "rb"); + if(fp) + { + int version; + fread(&version, 1, sizeof(version), fp); + if(version == BANMGR_FILEVERSION) + { + fseek(fp, 0, SEEK_END); + int nIDs = (ftell(fp) - sizeof(version)) / 16; + fseek(fp, sizeof(version), SEEK_SET); + + for(int i=0; i < nIDs; i++) + { + char playerID[16]; + fread(playerID, 1, 16, fp); + AddBannedPlayer(playerID); + } + } + + fclose(fp); + } + + return true; +} + + +void CVoiceBanMgr::Term() +{ + // Free all the player structures. + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + BannedPlayer *pNext; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pNext) + { + pNext = pCur->m_pNext; + delete pCur; + } + } + + Clear(); +} + + +void CVoiceBanMgr::SaveState(char const *pGameDir) +{ + // Save the file out. + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + FILE *fp = fopen(filename, "wb"); + if(fp) + { + int version = BANMGR_FILEVERSION; + fwrite(&version, 1, sizeof(version), fp); + + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + fwrite(pCur->m_PlayerID, 1, 16, fp); + } + } + + fclose(fp); + } +} + + +bool CVoiceBanMgr::GetPlayerBan(char const playerID[16]) +{ + return !!InternalFindPlayerSquelch(playerID); +} + + +void CVoiceBanMgr::SetPlayerBan(char const playerID[16], bool bSquelch) +{ + if(bSquelch) + { + // Is this guy already squelched? + if(GetPlayerBan(playerID)) + return; + + AddBannedPlayer(playerID); + } + else + { + BannedPlayer *pPlayer = InternalFindPlayerSquelch(playerID); + if(pPlayer) + { + pPlayer->m_pPrev->m_pNext = pPlayer->m_pNext; + pPlayer->m_pNext->m_pPrev = pPlayer->m_pPrev; + delete pPlayer; + } + } +} + + +void CVoiceBanMgr::ForEachBannedPlayer(void (*callback)(char id[16])) +{ + for(int i=0; i < 256; i++) + { + for(BannedPlayer *pCur=m_PlayerHash[i].m_pNext; pCur != &m_PlayerHash[i]; pCur=pCur->m_pNext) + { + callback(pCur->m_PlayerID); + } + } +} + + +void CVoiceBanMgr::Clear() +{ + // Tie off the hash table entries. + for(int i=0; i < 256; i++) + m_PlayerHash[i].m_pNext = m_PlayerHash[i].m_pPrev = &m_PlayerHash[i]; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::InternalFindPlayerSquelch(char const playerID[16]) +{ + int index = (int)HashPlayerID(playerID) & 0xFF; + BannedPlayer *pListHead = &m_PlayerHash[index]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + if(memcmp(playerID, pCur->m_PlayerID, 16) == 0) + return pCur; + } + + return NULL; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::AddBannedPlayer(char const playerID[16]) +{ + BannedPlayer *pNew = new BannedPlayer; + if(!pNew) + return NULL; + + int index = HashPlayerID(playerID); + memcpy(pNew->m_PlayerID, playerID, 16); + pNew->m_pNext = &m_PlayerHash[index]; + pNew->m_pPrev = m_PlayerHash[index].m_pPrev; + pNew->m_pPrev->m_pNext = pNew->m_pNext->m_pPrev = pNew; + return pNew; +} + diff --git a/main/source/game_shared/voice_banmgr.h b/main/source/game_shared/voice_banmgr.h index 3db37b91..78aa89ae 100644 --- a/main/source/game_shared/voice_banmgr.h +++ b/main/source/game_shared/voice_banmgr.h @@ -1,57 +1,57 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_BANMGR_H -#define VOICE_BANMGR_H -#ifdef _WIN32 -#pragma once -#endif - - -// This class manages the (persistent) list of squelched players. -class CVoiceBanMgr -{ -public: - - CVoiceBanMgr(); - ~CVoiceBanMgr(); - - // Init loads the list of squelched players from disk. - bool Init(char const *pGameDir); - void Term(); - - // Saves the state into voice_squelch.dt. - void SaveState(char const *pGameDir); - - bool GetPlayerBan(char const playerID[16]); - void SetPlayerBan(char const playerID[16], bool bSquelch); - - // Call your callback for each banned player. - void ForEachBannedPlayer(void (*callback)(char id[16])); - - -protected: - - class BannedPlayer - { - public: - char m_PlayerID[16]; - BannedPlayer *m_pPrev, *m_pNext; - }; - - void Clear(); - BannedPlayer* InternalFindPlayerSquelch(char const playerID[16]); - BannedPlayer* AddBannedPlayer(char const playerID[16]); - - -protected: - - BannedPlayer m_PlayerHash[256]; -}; - - -#endif // VOICE_BANMGR_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_BANMGR_H +#define VOICE_BANMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class manages the (persistent) list of squelched players. +class CVoiceBanMgr +{ +public: + + CVoiceBanMgr(); + ~CVoiceBanMgr(); + + // Init loads the list of squelched players from disk. + bool Init(char const *pGameDir); + void Term(); + + // Saves the state into voice_squelch.dt. + void SaveState(char const *pGameDir); + + bool GetPlayerBan(char const playerID[16]); + void SetPlayerBan(char const playerID[16], bool bSquelch); + + // Call your callback for each banned player. + void ForEachBannedPlayer(void (*callback)(char id[16])); + + +protected: + + class BannedPlayer + { + public: + char m_PlayerID[16]; + BannedPlayer *m_pPrev, *m_pNext; + }; + + void Clear(); + BannedPlayer* InternalFindPlayerSquelch(char const playerID[16]); + BannedPlayer* AddBannedPlayer(char const playerID[16]); + + +protected: + + BannedPlayer m_PlayerHash[256]; +}; + + +#endif // VOICE_BANMGR_H diff --git a/main/source/game_shared/voice_common.h b/main/source/game_shared/voice_common.h index abd49ef2..4d04ec99 100644 --- a/main/source/game_shared/voice_common.h +++ b/main/source/game_shared/voice_common.h @@ -1,24 +1,24 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_COMMON_H -#define VOICE_COMMON_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "bitvec.h" - - -#define VOICE_MAX_PLAYERS 32 // (todo: this should just be set to MAX_CLIENTS). -#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) - -typedef CBitVec CPlayerBitVec; - - -#endif // VOICE_COMMON_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_COMMON_H +#define VOICE_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "bitvec.h" + + +#define VOICE_MAX_PLAYERS 32 // (todo: this should just be set to MAX_CLIENTS). +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec CPlayerBitVec; + + +#endif // VOICE_COMMON_H diff --git a/main/source/game_shared/voice_gamemgr.cpp b/main/source/game_shared/voice_gamemgr.cpp index c62230ba..04e6cfc5 100644 --- a/main/source/game_shared/voice_gamemgr.cpp +++ b/main/source/game_shared/voice_gamemgr.cpp @@ -1,276 +1,276 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "voice_gamemgr.h" -#include -#include -#include "../dlls/extdll.h" -#include "../dlls/util.h" -#include "../dlls/cbase.h" -#include "../dlls/player.h" -#include "../mod/AvHServerVariables.h" - - -#define UPDATE_INTERVAL 0.3 - - -// These are stored off as CVoiceGameMgr is created and deleted. -CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. - // (If it's zero, then the server reports that the game rules are saying the - // player can't hear anyone). - -CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other. - // These are indexed as clients and each bit represents a client - // (so player entity is bit+1). - -CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if -CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them. -CPlayerBitVec g_bWantModEnable; - -cvar_t voice_serverdebug = {"voice_serverdebug", "0"}; - -// Set game rules to allow all clients to talk to each other. -// Muted players still can't talk to each other. -cvar_t sv_alltalk = {"sv_alltalk", "0"}; - -// ------------------------------------------------------------------------ // -// Static helpers. -// ------------------------------------------------------------------------ // - -// Find a player with a case-insensitive name search. -static CBasePlayer* FindPlayerByName(const char *pTestName) -{ - for(int i=1; i <= gpGlobals->maxClients; i++) - { - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); - if(pEdict) - { - CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); - if(pEnt && pEnt->IsPlayer()) - { - const char *pNetName = STRING(pEnt->pev->netname); - if(stricmp(pNetName, pTestName) == 0) - { - return (CBasePlayer*)pEnt; - } - } - } - } - - return NULL; -} - -static void VoiceServerDebug( char const *pFmt, ... ) -{ - char msg[4096]; - va_list marker; - - if( !voice_serverdebug.value ) - return; - - va_start( marker, pFmt ); - vsnprintf( msg, sizeof(msg), pFmt, marker ); - va_end( marker ); - - ALERT( at_console, "%s", msg ); -} - - - -// ------------------------------------------------------------------------ // -// CVoiceGameMgr. -// ------------------------------------------------------------------------ // - -CVoiceGameMgr::CVoiceGameMgr() -{ - m_UpdateInterval = 0; - m_nMaxPlayers = 0; -} - - -CVoiceGameMgr::~CVoiceGameMgr() -{ -} - - -bool CVoiceGameMgr::Init( - IVoiceGameMgrHelper *pHelper, - int maxClients) -{ - m_pHelper = pHelper; - m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; - g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); - - m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); - m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); - - // register voice_serverdebug if it hasn't been registered already - if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) - CVAR_REGISTER( &voice_serverdebug ); - - if( !CVAR_GET_POINTER( "sv_alltalk" ) ) - CVAR_REGISTER( &sv_alltalk ); - - return true; -} - - -void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) -{ - m_pHelper = pHelper; -} - - -void CVoiceGameMgr::Update(double frametime) -{ - // Only update periodically. - m_UpdateInterval += frametime; - if(m_UpdateInterval < UPDATE_INTERVAL) - return; - - UpdateMasks(); -} - - -void CVoiceGameMgr::ClientConnected(edict_t *pEdict) -{ - int index = ENTINDEX(pEdict) - 1; - - // Clear out everything we use for deltas on this guy. - g_bWantModEnable[index] = true; - g_SentGameRulesMasks[index].Init(0); - g_SentBanMasks[index].Init(0); -} - -// Called to determine if the Receiver has muted (blocked) the Sender -// Returns true if the receiver has blocked the sender -bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) -{ - int iReceiverIndex, iSenderIndex; - - if ( !pReceiver || !pSender ) - return false; - - iReceiverIndex = pReceiver->entindex() - 1; - iSenderIndex = pSender->entindex() - 1; - - if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) - return false; - - return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); -} - -bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) -{ - int playerClientIndex = pPlayer->entindex() - 1; - if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); - return true; - } - - bool bBan = stricmp(cmd, "vban") == 0; - if(bBan && CMD_ARGC() >= 2) - { - for(int i=1; i < CMD_ARGC(); i++) - { - unsigned long mask = 0; - sscanf(CMD_ARGV(i), "%x", &mask); - - if(i <= VOICE_MAX_PLAYERS_DW) - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); - g_BanMasks[playerClientIndex].SetDWord(i-1, mask); - } - else - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i ); - } - } - - // Commented out UpdateMasks() because Mugsy said it was causing overflows in DOD 4/22 - // Force it to update the masks now. - //UpdateMasks(); - return true; - } - else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); - g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); - g_bWantModEnable[playerClientIndex] = false; - // Commented out UpdateMasks() because Mugsy said it was causing overflows in DOD 4/22 - //UpdateMasks(); - return true; - } - else - { - return false; - } -} - - -void CVoiceGameMgr::UpdateMasks() -{ - m_UpdateInterval = 0; - - bool bAllTalk = !!ns_cvar_float(&sv_alltalk); - - for(int iClient=0; iClient < m_nMaxPlayers; iClient++) - { - CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); - if(!pEnt || !pEnt->IsPlayer()) - continue; - - // Request the state of their "VModEnable" cvar. - if(g_bWantModEnable[iClient]) - { - MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); - MESSAGE_END(); - } - - CBasePlayer *pPlayer = (CBasePlayer*)pEnt; - - CPlayerBitVec gameRulesMask; - if(g_PlayerModEnable[iClient]) - { - // Build a mask of who they can hear based on the game rules. - for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) - { - CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1); - if(pEnt && pEnt->IsPlayer() && - (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) - { - gameRulesMask[iOtherClient] = true; - } - } - } - - // If this is different from what the client has, send an update. - if(gameRulesMask != g_SentGameRulesMasks[iClient] || - g_BanMasks[iClient] != g_SentBanMasks[iClient]) - { - g_SentGameRulesMasks[iClient] = gameRulesMask; - g_SentBanMasks[iClient] = g_BanMasks[iClient]; - - MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); - int dw; - for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) - { - WRITE_LONG(gameRulesMask.GetDWord(dw)); - WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); - } - MESSAGE_END(); - } - - // Tell the engine. - for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) - { - bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; - g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); - } - } -} +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "voice_gamemgr.h" +#include +#include +#include "../dlls/extdll.h" +#include "../dlls/util.h" +#include "../dlls/cbase.h" +#include "../dlls/player.h" +#include "../mod/AvHServerVariables.h" + + +#define UPDATE_INTERVAL 0.3 + + +// These are stored off as CVoiceGameMgr is created and deleted. +CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. + // (If it's zero, then the server reports that the game rules are saying the + // player can't hear anyone). + +CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other. + // These are indexed as clients and each bit represents a client + // (so player entity is bit+1). + +CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if +CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them. +CPlayerBitVec g_bWantModEnable; + +cvar_t voice_serverdebug = {"voice_serverdebug", "0"}; + +// Set game rules to allow all clients to talk to each other. +// Muted players still can't talk to each other. +cvar_t sv_alltalk = {"sv_alltalk", "0"}; + +// ------------------------------------------------------------------------ // +// Static helpers. +// ------------------------------------------------------------------------ // + +// Find a player with a case-insensitive name search. +static CBasePlayer* FindPlayerByName(const char *pTestName) +{ + for(int i=1; i <= gpGlobals->maxClients; i++) + { + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); + if(pEdict) + { + CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); + if(pEnt && pEnt->IsPlayer()) + { + const char *pNetName = STRING(pEnt->pev->netname); + if(stricmp(pNetName, pTestName) == 0) + { + return (CBasePlayer*)pEnt; + } + } + } + } + + return NULL; +} + +static void VoiceServerDebug( char const *pFmt, ... ) +{ + char msg[4096]; + va_list marker; + + if( !voice_serverdebug.value ) + return; + + va_start( marker, pFmt ); + vsnprintf( msg, sizeof(msg), pFmt, marker ); + va_end( marker ); + + ALERT( at_console, "%s", msg ); +} + + + +// ------------------------------------------------------------------------ // +// CVoiceGameMgr. +// ------------------------------------------------------------------------ // + +CVoiceGameMgr::CVoiceGameMgr() +{ + m_UpdateInterval = 0; + m_nMaxPlayers = 0; +} + + +CVoiceGameMgr::~CVoiceGameMgr() +{ +} + + +bool CVoiceGameMgr::Init( + IVoiceGameMgrHelper *pHelper, + int maxClients) +{ + m_pHelper = pHelper; + m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; + g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); + + m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); + m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); + + // register voice_serverdebug if it hasn't been registered already + if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) + CVAR_REGISTER( &voice_serverdebug ); + + if( !CVAR_GET_POINTER( "sv_alltalk" ) ) + CVAR_REGISTER( &sv_alltalk ); + + return true; +} + + +void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) +{ + m_pHelper = pHelper; +} + + +void CVoiceGameMgr::Update(double frametime) +{ + // Only update periodically. + m_UpdateInterval += frametime; + if(m_UpdateInterval < UPDATE_INTERVAL) + return; + + UpdateMasks(); +} + + +void CVoiceGameMgr::ClientConnected(edict_t *pEdict) +{ + int index = ENTINDEX(pEdict) - 1; + + // Clear out everything we use for deltas on this guy. + g_bWantModEnable[index] = true; + g_SentGameRulesMasks[index].Init(0); + g_SentBanMasks[index].Init(0); +} + +// Called to determine if the Receiver has muted (blocked) the Sender +// Returns true if the receiver has blocked the sender +bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) +{ + int iReceiverIndex, iSenderIndex; + + if ( !pReceiver || !pSender ) + return false; + + iReceiverIndex = pReceiver->entindex() - 1; + iSenderIndex = pSender->entindex() - 1; + + if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) + return false; + + return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); +} + +bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) +{ + int playerClientIndex = pPlayer->entindex() - 1; + if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); + return true; + } + + bool bBan = stricmp(cmd, "vban") == 0; + if(bBan && CMD_ARGC() >= 2) + { + for(int i=1; i < CMD_ARGC(); i++) + { + unsigned long mask = 0; + sscanf(CMD_ARGV(i), "%x", &mask); + + if(i <= VOICE_MAX_PLAYERS_DW) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); + g_BanMasks[playerClientIndex].SetDWord(i-1, mask); + } + else + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i ); + } + } + + // Commented out UpdateMasks() because Mugsy said it was causing overflows in DOD 4/22 + // Force it to update the masks now. + //UpdateMasks(); + return true; + } + else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); + g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); + g_bWantModEnable[playerClientIndex] = false; + // Commented out UpdateMasks() because Mugsy said it was causing overflows in DOD 4/22 + //UpdateMasks(); + return true; + } + else + { + return false; + } +} + + +void CVoiceGameMgr::UpdateMasks() +{ + m_UpdateInterval = 0; + + bool bAllTalk = !!ns_cvar_float(&sv_alltalk); + + for(int iClient=0; iClient < m_nMaxPlayers; iClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); + if(!pEnt || !pEnt->IsPlayer()) + continue; + + // Request the state of their "VModEnable" cvar. + if(g_bWantModEnable[iClient]) + { + MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); + MESSAGE_END(); + } + + CBasePlayer *pPlayer = (CBasePlayer*)pEnt; + + CPlayerBitVec gameRulesMask; + if(g_PlayerModEnable[iClient]) + { + // Build a mask of who they can hear based on the game rules. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1); + if(pEnt && pEnt->IsPlayer() && + (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) + { + gameRulesMask[iOtherClient] = true; + } + } + } + + // If this is different from what the client has, send an update. + if(gameRulesMask != g_SentGameRulesMasks[iClient] || + g_BanMasks[iClient] != g_SentBanMasks[iClient]) + { + g_SentGameRulesMasks[iClient] = gameRulesMask; + g_SentBanMasks[iClient] = g_BanMasks[iClient]; + + MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); + int dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + WRITE_LONG(gameRulesMask.GetDWord(dw)); + WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); + } + MESSAGE_END(); + } + + // Tell the engine. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; + g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); + } + } +} diff --git a/main/source/game_shared/voice_gamemgr.h b/main/source/game_shared/voice_gamemgr.h index adfca6f6..b0d55c8e 100644 --- a/main/source/game_shared/voice_gamemgr.h +++ b/main/source/game_shared/voice_gamemgr.h @@ -1,79 +1,79 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_GAMEMGR_H -#define VOICE_GAMEMGR_H -#pragma once - - -#include "voice_common.h" - - -class CGameRules; -class CBasePlayer; - - -class IVoiceGameMgrHelper -{ -public: - virtual ~IVoiceGameMgrHelper() {} - - // Called each frame to determine which players are allowed to hear each other. This overrides - // whatever squelch settings players have. - virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) = 0; -}; - - -// CVoiceGameMgr manages which clients can hear which other clients. -class CVoiceGameMgr -{ -public: - CVoiceGameMgr(); - virtual ~CVoiceGameMgr(); - - bool Init( - IVoiceGameMgrHelper *m_pHelper, - int maxClients - ); - - void SetHelper(IVoiceGameMgrHelper *pHelper); - - // Updates which players can hear which other players. - // If gameplay mode is DM, then only players within the PVS can hear each other. - // If gameplay mode is teamplay, then only players on the same team can hear each other. - // Player masks are always applied. - void Update(double frametime); - - // Called when a new client connects (unsquelches its entity for everyone). - void ClientConnected(struct edict_s *pEdict); - - // Called on ClientCommand. Checks for the squelch and unsquelch commands. - // Returns true if it handled the command. - bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); - - // Called to determine if the Receiver has muted (blocked) the Sender - // Returns true if the receiver has blocked the sender - bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); - - -private: - - // Force it to update the client masks. - void UpdateMasks(); - - -private: - int m_msgPlayerVoiceMask; - int m_msgRequestState; - - IVoiceGameMgrHelper *m_pHelper; - int m_nMaxPlayers; - double m_UpdateInterval; // How long since the last update. -}; - - -#endif // VOICE_GAMEMGR_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_GAMEMGR_H +#define VOICE_GAMEMGR_H +#pragma once + + +#include "voice_common.h" + + +class CGameRules; +class CBasePlayer; + + +class IVoiceGameMgrHelper +{ +public: + virtual ~IVoiceGameMgrHelper() {} + + // Called each frame to determine which players are allowed to hear each other. This overrides + // whatever squelch settings players have. + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) = 0; +}; + + +// CVoiceGameMgr manages which clients can hear which other clients. +class CVoiceGameMgr +{ +public: + CVoiceGameMgr(); + virtual ~CVoiceGameMgr(); + + bool Init( + IVoiceGameMgrHelper *m_pHelper, + int maxClients + ); + + void SetHelper(IVoiceGameMgrHelper *pHelper); + + // Updates which players can hear which other players. + // If gameplay mode is DM, then only players within the PVS can hear each other. + // If gameplay mode is teamplay, then only players on the same team can hear each other. + // Player masks are always applied. + void Update(double frametime); + + // Called when a new client connects (unsquelches its entity for everyone). + void ClientConnected(struct edict_s *pEdict); + + // Called on ClientCommand. Checks for the squelch and unsquelch commands. + // Returns true if it handled the command. + bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); + + // Called to determine if the Receiver has muted (blocked) the Sender + // Returns true if the receiver has blocked the sender + bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); + + +private: + + // Force it to update the client masks. + void UpdateMasks(); + + +private: + int m_msgPlayerVoiceMask; + int m_msgRequestState; + + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. +}; + + +#endif // VOICE_GAMEMGR_H diff --git a/main/source/game_shared/voice_status.cpp b/main/source/game_shared/voice_status.cpp index 52234a10..9b89e308 100644 --- a/main/source/game_shared/voice_status.cpp +++ b/main/source/game_shared/voice_status.cpp @@ -1,883 +1,883 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// There are hud.h's coming out of the woodwork so this ensures that we get the right one. -#include "../cl_dll/hud.h" - -#include "../cl_dll/cl_util.h" -#include -#include -#include -#include -#include "../cl_dll/hud_servers.h" -#include "../cl_dll/demo.h" -#include "common/demo_api.h" -#include "voice_status.h" -#include "common/r_efx.h" -#include "common/entity_types.h" -#include "VGUI_ActionSignal.h" -#include "VGUI_Scheme.h" -#include "VGUI_TextImage.h" -#include "vgui_loadtga.h" -#include "vgui_helpers.h" -#include "VGUI_MouseCode.h" -#include "dlls/extdll.h" -#include "mod/AvHClientUtil.h" -#include "mod/AvHHudConstants.h" - -using namespace vgui; - - -extern int cam_thirdperson; - - -#define VOICE_MODEL_INTERVAL 0.3 -#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. -#define SQUELCHOSCILLATE_PER_SECOND 2.0f - - -extern BitmapTGA *LoadTGA( const char* pImageName ); - -// Allow assignment within conditional -#pragma warning (disable: 4706) - -// ---------------------------------------------------------------------- // -// The voice manager for the client. -// ---------------------------------------------------------------------- // -CVoiceStatus g_VoiceStatus; - -CVoiceStatus* GetClientVoiceMgr() -{ - return &g_VoiceStatus; -} - - - -// ---------------------------------------------------------------------- // -// CVoiceStatus. -// ---------------------------------------------------------------------- // - -static CVoiceStatus *g_pInternalVoiceStatus = NULL; - -int __MsgFunc_VoiceMask(const char *pszName, int iSize, void *pbuf) -{ - if(g_pInternalVoiceStatus) - g_pInternalVoiceStatus->HandleVoiceMaskMsg(iSize, pbuf); - - return 1; -} - -int __MsgFunc_ReqState(const char *pszName, int iSize, void *pbuf) -{ - if(g_pInternalVoiceStatus) - g_pInternalVoiceStatus->HandleReqStateMsg(iSize, pbuf); - - return 1; -} - - -int g_BannedPlayerPrintCount; -void ForEachBannedPlayer(char id[16]) -{ - char str[256]; - sprintf(str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", - g_BannedPlayerPrintCount++, - id[0], id[1], id[2], id[3], - id[4], id[5], id[6], id[7], - id[8], id[9], id[10], id[11], - id[12], id[13], id[14], id[15] - ); -#ifdef _WIN32 - strupr(str); -#endif - gEngfuncs.pfnConsolePrint(str); -} - - -void ShowBannedCallback() -{ - if(g_pInternalVoiceStatus) - { - g_BannedPlayerPrintCount = 0; - gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); - g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer(ForEachBannedPlayer); - gEngfuncs.pfnConsolePrint("------------------------------\n"); - } -} - - -// ---------------------------------------------------------------------- // -// CVoiceStatus. -// ---------------------------------------------------------------------- // - -CVoiceStatus::CVoiceStatus() -{ - m_bBanMgrInitialized = false; - m_LastUpdateServerState = 0; - - m_pSpeakerLabelIcon = NULL; - m_pScoreboardNeverSpoken = NULL; - m_pScoreboardNotSpeaking = NULL; - m_pScoreboardSpeaking = NULL; - m_pScoreboardSpeaking2 = NULL; - m_pScoreboardSquelch = NULL; - m_pScoreboardBanned = NULL; - - m_pLocalBitmap = NULL; - m_pAckBitmap = NULL; - - m_bTalking = m_bServerAcked = false; - - memset(m_pBanButtons, 0, sizeof(m_pBanButtons)); - - m_bServerModEnable = -1; -} - - -CVoiceStatus::~CVoiceStatus() -{ - g_pInternalVoiceStatus = NULL; - - for(int i=0; i < MAX_VOICE_SPEAKERS; i++) - { - delete m_Labels[i].m_pLabel; - m_Labels[i].m_pLabel = NULL; - - delete m_Labels[i].m_pIcon; - m_Labels[i].m_pIcon = NULL; - - delete m_Labels[i].m_pBackground; - m_Labels[i].m_pBackground = NULL; - } - - delete m_pLocalLabel; - m_pLocalLabel = NULL; - - FreeBitmaps(); - - if(m_pchGameDir) - { - if(m_bBanMgrInitialized) - { - m_BanMgr.SaveState(m_pchGameDir); - } - - free(m_pchGameDir); - } -} - - -int CVoiceStatus::Init( - IVoiceStatusHelper *pHelper, - Panel **pParentPanel) -{ - // Setup the voice_modenable cvar. - gEngfuncs.pfnRegisterVariable("voice_modenable", "1", FCVAR_ARCHIVE); - - gEngfuncs.pfnRegisterVariable("voice_clientdebug", "0", 0); - - gEngfuncs.pfnAddCommand("voice_showbanned", ShowBannedCallback); - - if(gEngfuncs.pfnGetGameDirectory()) - { - m_BanMgr.Init(gEngfuncs.pfnGetGameDirectory()); - m_bBanMgrInitialized = true; - } - - assert(!g_pInternalVoiceStatus); - g_pInternalVoiceStatus = this; - - m_BlinkTimer = 0; - m_VoiceHeadModel = NULL; - memset(m_Labels, 0, sizeof(m_Labels)); - - for(int i=0; i < MAX_VOICE_SPEAKERS; i++) - { - CVoiceLabel *pLabel = &m_Labels[i]; - - pLabel->m_pBackground = new Label(""); - - if(pLabel->m_pLabel = new Label("")) - { - pLabel->m_pLabel->setVisible( true ); - pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); - pLabel->m_pLabel->setTextAlignment( Label::a_east ); - pLabel->m_pLabel->setContentAlignment( Label::a_east ); - pLabel->m_pLabel->setParent( pLabel->m_pBackground ); - } - - if( pLabel->m_pIcon = new ImagePanel( NULL ) ) - { - pLabel->m_pIcon->setVisible( true ); - pLabel->m_pIcon->setParent( pLabel->m_pBackground ); - } - - pLabel->m_clientindex = -1; - } - - m_pLocalLabel = new ImagePanel(NULL); - - m_bInSquelchMode = false; - - m_pHelper = pHelper; - m_pParentPanel = pParentPanel; - gHUD.AddHudElem(this); - m_iFlags = HUD_ACTIVE; - HOOK_MESSAGE(VoiceMask); - HOOK_MESSAGE(ReqState); - - // Cache the game directory for use when we shut down - const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); - m_pchGameDir = (char *)malloc(strlen(pchGameDirT) + 1); - strcpy(m_pchGameDir, pchGameDirT); - - return 1; -} - - -int CVoiceStatus::VidInit() -{ - FreeBitmaps(); - - - if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) - { - m_pLocalBitmap->setColor(Color(255,255,255,135)); - } - - if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) - { - m_pAckBitmap->setColor(Color(255,255,255,135)); // Give just a tiny bit of translucency so software draws correctly. - } - - m_pLocalLabel->setImage( m_pLocalBitmap ); - m_pLocalLabel->setVisible( false ); - - - if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/speaker4.tga" ) ) - m_pSpeakerLabelIcon->setColor( Color(255,255,255,1) ); // Give just a tiny bit of translucency so software draws correctly. - - if (m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker1.tga")) - m_pScoreboardNeverSpoken->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker2.tga")) - m_pScoreboardNotSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker3.tga")) - m_pScoreboardSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker4.tga")) - m_pScoreboardSpeaking2->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardSquelch = vgui_LoadTGA("gfx/vgui/icntlk_squelch.tga")) - m_pScoreboardSquelch->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardBanned = vgui_LoadTGA("gfx/vgui/640_voiceblocked.tga")) - m_pScoreboardBanned->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - // Figure out the voice head model height. - m_VoiceHeadModelHeight = 45; - char *pFile = (char *)gEngfuncs.COM_LoadFile("scripts/voicemodel.txt", 5, NULL); - if(pFile) - { - char token[4096]; - gEngfuncs.COM_ParseFile(pFile, token); - if(token[0] >= '0' && token[0] <= '9') - { - m_VoiceHeadModelHeight = (float)atof(token); - } - - gEngfuncs.COM_FreeFile(pFile); - } - - m_VoiceHeadModel = gEngfuncs.pfnSPR_Load("sprites/voiceicon.spr"); - return TRUE; -} - - -void CVoiceStatus::Frame(double frametime) -{ - // check server banned players once per second - if(gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1) - { - UpdateServerState(false); - } - - m_BlinkTimer += frametime; - - // Update speaker labels. - if( m_pHelper->CanShowSpeakerLabels() ) - { - for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) - m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); - } - else - { - for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) - m_Labels[i].m_pBackground->setVisible( false ); - } - - for(int i=0; i < VOICE_MAX_PLAYERS; i++) - UpdateBanButton(i); -} - - -void CVoiceStatus::CreateEntities() -{ - if(!m_VoiceHeadModel) - return; - - cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); - - int iOutModel = 0; - for(int i=0; i < VOICE_MAX_PLAYERS; i++) - { - if(!m_VoicePlayers[i]) - continue; - - cl_entity_s *pClient = gEngfuncs.GetEntityByIndex(i+1); - - // Don't show an icon if the player is not in our PVS. - if(!pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum) - continue; - - // Don't show an icon for dead or spectating players (ie: invisible entities). - if(pClient->curstate.effects & EF_NODRAW) - continue; - - // Don't show an icon for the local player unless we're in thirdperson mode. - if(pClient == localPlayer && !cam_thirdperson) - continue; - - cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; - ++iOutModel; - - memset(pEnt, 0, sizeof(*pEnt)); - - pEnt->curstate.rendermode = kRenderTransAdd; - pEnt->curstate.renderamt = 255; - pEnt->baseline.renderamt = 255; - pEnt->curstate.renderfx = kRenderFxNoDissipation; - pEnt->curstate.framerate = 1; - // : different sprite for each team - if (pClient->curstate.team <= SPR_Frames(m_VoiceHeadModel)) - pEnt->curstate.frame = pClient->curstate.team; - else - pEnt->curstate.frame = 0; - //pEnt->curstate.frame = 0; - // : - pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer(m_VoiceHeadModel); - pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; - pEnt->curstate.scale = 0.5f; - - pEnt->origin[0] = pEnt->origin[1] = 0; - pEnt->origin[2] = AvHCUGetIconHeightForPlayer((AvHUser3)pClient->curstate.iuser3); - - VectorAdd(pEnt->origin, pClient->origin, pEnt->origin); - - // Tell the engine. - gEngfuncs.CL_CreateVisibleEntity(ET_NORMAL, pEnt); - } -} - - -void CVoiceStatus::UpdateSpeakerStatus(int entindex, qboolean bTalking) -{ - if(!*m_pParentPanel) - return; - - if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) - { - char msg[256]; - _snprintf( msg, sizeof(msg), "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); - gEngfuncs.pfnConsolePrint( msg ); - } - - // Is it the local player talking? - if( entindex == -1 ) - { - m_bTalking = !!bTalking; - if( bTalking ) - { - // Enable voice for them automatically if they try to talk. - gEngfuncs.pfnClientCmd( "voice_modenable 1" ); - } - } - else if( entindex == -2 ) - { - m_bServerAcked = !!bTalking; - } - else if(entindex >= 0 && entindex <= VOICE_MAX_PLAYERS) - { - int iClient = entindex - 1; - if(iClient < 0) - return; - - CVoiceLabel *pLabel = FindVoiceLabel(iClient); - if(bTalking) - { - m_VoicePlayers[iClient] = true; - m_VoiceEnabledPlayers[iClient] = true; - - // If we don't have a label for this guy yet, then create one. - if(!pLabel) - { - if(pLabel = GetFreeVoiceLabel()) - { - // Get the name from the engine. - hud_player_info_t info; - memset(&info, 0, sizeof(info)); - GetPlayerInfo(entindex, &info); - - char paddedName[512]; - _snprintf(paddedName, sizeof(paddedName), "%s ", info.name); - - int color[3]; - m_pHelper->GetPlayerTextColor( entindex, color ); - - if( pLabel->m_pBackground ) - { - pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); - pLabel->m_pBackground->setParent( *m_pParentPanel ); - pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); - } - - if( pLabel->m_pLabel ) - { - pLabel->m_pLabel->setFgColor( 0, 0, 0, 0 ); - pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); - pLabel->m_pLabel->setText( paddedName ); - } - - pLabel->m_clientindex = iClient; - } - } - } - else - { - m_VoicePlayers[iClient] = false; - - // If we have a label for this guy, kill it. - if(pLabel) - { - pLabel->m_pBackground->setVisible(false); - pLabel->m_clientindex = -1; - } - } - } - - RepositionLabels(); -} - - -void CVoiceStatus::UpdateServerState(bool bForce) -{ - // Can't do anything when we're not in a level. - char const *pLevelName = gEngfuncs.pfnGetLevelName(); - if( pLevelName[0] == 0 ) - { - if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); - } - - return; - } - - int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat("voice_modenable"); - if(bForce || m_bServerModEnable != bCVarModEnable) - { - m_bServerModEnable = bCVarModEnable; - - char str[256]; - _snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable); - ServerCmd(str); - - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char msg[256]; - sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); - gEngfuncs.pfnConsolePrint(msg); - } - } - - char str[2048]; - sprintf(str, "vban"); - bool bChange = false; - - for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) - { - unsigned long serverBanMask = 0; - unsigned long banMask = 0; - for(unsigned long i=0; i < 32; i++) - { - char playerID[16]; - if(!gEngfuncs.GetPlayerUniqueID(i+1, playerID)) - continue; - - if(m_BanMgr.GetPlayerBan(playerID)) - banMask |= 1 << i; - - if(m_ServerBannedPlayers[dw*32 + i]) - serverBanMask |= 1 << i; - } - - if(serverBanMask != banMask) - bChange = true; - - // Ok, the server needs to be updated. - char numStr[512]; - sprintf(numStr, " %x", banMask); - strcat(str, numStr); - } - - if(bChange || bForce) - { - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char msg[256]; - sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); - gEngfuncs.pfnConsolePrint(msg); - } - - gEngfuncs.pfnServerCmdUnreliable(str); // Tell the server.. - } - else - { - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); - } - } - - m_LastUpdateServerState = gEngfuncs.GetClientTime(); -} - -void CVoiceStatus::UpdateSpeakerImage(Label *pLabel, int iPlayer) -{ - m_pBanButtons[iPlayer-1] = pLabel; - UpdateBanButton(iPlayer-1); -} - -void CVoiceStatus::UpdateBanButton(int iClient) -{ - Label *pPanel = m_pBanButtons[iClient]; - - if (!pPanel) - return; - - char playerID[16]; - extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); - if(!HACK_GetPlayerUniqueID(iClient+1, playerID)) - return; - - // Figure out if it's blinking or not. - bool bBlink = fmod(m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY*2) < SCOREBOARD_BLINK_FREQUENCY; - bool bTalking = !!m_VoicePlayers[iClient]; - bool bBanned = m_BanMgr.GetPlayerBan(playerID); - bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; - - // Get the appropriate image to display on the panel. - if (bBanned) - { - pPanel->setImage(m_pScoreboardBanned); - } - else if (bTalking) - { - if (bBlink) - { - pPanel->setImage(m_pScoreboardSpeaking2); - } - else - { - pPanel->setImage(m_pScoreboardSpeaking); - } - pPanel->setFgColor(255, 170, 0, 1); - } - else if (bNeverSpoken) - { - pPanel->setImage(m_pScoreboardNeverSpoken); - pPanel->setFgColor(100, 100, 100, 1); - } - else - { - pPanel->setImage(m_pScoreboardNotSpeaking); - } -} - -#include "cl_dll/parsemsg.h" -void CVoiceStatus::HandleVoiceMaskMsg(int iSize, void *pbuf) -{ - BEGIN_READ( pbuf, iSize ); - - unsigned long dw; - for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) - { - m_AudiblePlayers.SetDWord(dw, (unsigned long)READ_LONG()); - m_ServerBannedPlayers.SetDWord(dw, (unsigned long)READ_LONG()); - - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char str[256]; - gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleVoiceMaskMsg\n"); - - sprintf(str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw)); - gEngfuncs.pfnConsolePrint(str); - - sprintf(str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw)); - gEngfuncs.pfnConsolePrint(str); - } - } - - m_bServerModEnable = READ_BYTE(); -} - -void CVoiceStatus::HandleReqStateMsg(int iSize, void *pbuf) -{ - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleReqStateMsg\n"); - } - - UpdateServerState(true); -} - -void CVoiceStatus::StartSquelchMode() -{ - if(m_bInSquelchMode) - return; - - m_bInSquelchMode = true; - m_pHelper->UpdateCursorState(); -} - -void CVoiceStatus::StopSquelchMode() -{ - m_bInSquelchMode = false; - m_pHelper->UpdateCursorState(); -} - -bool CVoiceStatus::IsInSquelchMode() -{ - return m_bInSquelchMode; -} - -CVoiceLabel* CVoiceStatus::FindVoiceLabel(int clientindex) -{ - for(int i=0; i < MAX_VOICE_SPEAKERS; i++) - { - if(m_Labels[i].m_clientindex == clientindex) - return &m_Labels[i]; - } - - return NULL; -} - - -CVoiceLabel* CVoiceStatus::GetFreeVoiceLabel() -{ - return FindVoiceLabel(-1); -} - - -void CVoiceStatus::RepositionLabels() -{ - // find starting position to draw from, along right-hand side of screen - int y = ScreenHeight() / 2; - - int iconWide = 8, iconTall = 8; - if( m_pSpeakerLabelIcon ) - { - m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); - } - - // Reposition active labels. - for(int i = 0; i < MAX_VOICE_SPEAKERS; i++) - { - CVoiceLabel *pLabel = &m_Labels[i]; - - if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) - { - if( pLabel->m_pBackground ) - pLabel->m_pBackground->setVisible( false ); - - continue; - } - - int textWide, textTall; - pLabel->m_pLabel->getContentSize( textWide, textTall ); - - // Don't let it stretch too far across their screen. - if( textWide > (ScreenWidth()*2)/3 ) - textWide = (ScreenWidth()*2)/3; - - // Setup the background label to fit everything in. - int border = 2; - int bgWide = textWide + iconWide + border*3; - int bgTall = max( textTall, iconTall ) + border*2; - pLabel->m_pBackground->setBounds( ScreenWidth() - bgWide - 8, y, bgWide, bgTall ); - - // Put the text at the left. - pLabel->m_pLabel->setBounds( border, (bgTall - textTall) / 2, textWide, textTall ); - - // Put the icon at the right. - int iconLeft = border + textWide + border; - int iconTop = (bgTall - iconTall) / 2; - if( pLabel->m_pIcon ) - { - pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); - pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); - } - - y += bgTall + 2; - } - - if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && (m_bTalking || m_bServerAcked) ) - { - m_pLocalLabel->setParent(*m_pParentPanel); - m_pLocalLabel->setVisible( true ); - - if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) - m_pLocalLabel->setImage( m_pAckBitmap ); - else - m_pLocalLabel->setImage( m_pLocalBitmap ); - - int sizeX, sizeY; - m_pLocalBitmap->getSize(sizeX, sizeY); - - int local_xPos = ScreenWidth() - sizeX - 10; - int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; - - // Move bar depending on role - switch(gHUD.GetHUDUser3()) - { - case AVH_USER3_ALIEN_PLAYER1: - case AVH_USER3_ALIEN_PLAYER2: - case AVH_USER3_ALIEN_PLAYER3: - case AVH_USER3_ALIEN_PLAYER4: - case AVH_USER3_ALIEN_PLAYER5: - local_xPos -= kResourceEnergyBarWidth*ScreenWidth(); - break; - - case AVH_USER3_COMMANDER_PLAYER: - local_xPos -= kVoiceStatusCommanderRightEdgeInset*ScreenWidth(); - local_yPos -= (1.0f - kVoiceStatusCommanderTopEdgeInset)*ScreenHeight(); - break; - - case AVH_USER3_MARINE_PLAYER: - local_xPos -= kVoiceStatusMarineRightEdgeInset*ScreenWidth(); - break; - } - - m_pLocalLabel->setPos( local_xPos, local_yPos ); - } - else - { - m_pLocalLabel->setVisible( false ); - } -} - - -void CVoiceStatus::FreeBitmaps() -{ - // Delete all the images we have loaded. - delete m_pLocalBitmap; - m_pLocalBitmap = NULL; - - delete m_pAckBitmap; - m_pAckBitmap = NULL; - - delete m_pSpeakerLabelIcon; - m_pSpeakerLabelIcon = NULL; - - delete m_pScoreboardNeverSpoken; - m_pScoreboardNeverSpoken = NULL; - - delete m_pScoreboardNotSpeaking; - m_pScoreboardNotSpeaking = NULL; - - delete m_pScoreboardSpeaking; - m_pScoreboardSpeaking = NULL; - - delete m_pScoreboardSpeaking2; - m_pScoreboardSpeaking2 = NULL; - - delete m_pScoreboardSquelch; - m_pScoreboardSquelch = NULL; - - delete m_pScoreboardBanned; - m_pScoreboardBanned = NULL; - - // Clear references to the images in panels. - for(int i=0; i < VOICE_MAX_PLAYERS; i++) - { - if (m_pBanButtons[i]) - { - m_pBanButtons[i]->setImage(NULL); - } - } - - if(m_pLocalLabel) - m_pLocalLabel->setImage(NULL); -} - -//----------------------------------------------------------------------------- -// Purpose: returns true if the target client has been banned -// Input : playerID - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CVoiceStatus::IsPlayerBlocked(int iPlayer) -{ - char playerID[16]; - if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) - return false; - - return m_BanMgr.GetPlayerBan(playerID); -} - -//----------------------------------------------------------------------------- -// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) -// Input : playerID - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CVoiceStatus::IsPlayerAudible(int iPlayer) -{ - return !!m_AudiblePlayers[iPlayer-1]; -} - -//----------------------------------------------------------------------------- -// Purpose: blocks/unblocks the target client from being heard -// Input : playerID - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked) -{ - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); - } - - char playerID[16]; - if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) - return; - - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); - } - - // Squelch or (try to) unsquelch this player. - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char str[256]; - sprintf(str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(playerID)); - gEngfuncs.pfnConsolePrint(str); - } - - m_BanMgr.SetPlayerBan( playerID, blocked ); - UpdateServerState(false); -} +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// There are hud.h's coming out of the woodwork so this ensures that we get the right one. +#include "../cl_dll/hud.h" + +#include "../cl_dll/cl_util.h" +#include +#include +#include +#include +#include "../cl_dll/hud_servers.h" +#include "../cl_dll/demo.h" +#include "common/demo_api.h" +#include "voice_status.h" +#include "common/r_efx.h" +#include "common/entity_types.h" +#include "VGUI_ActionSignal.h" +#include "VGUI_Scheme.h" +#include "VGUI_TextImage.h" +#include "vgui_loadtga.h" +#include "vgui_helpers.h" +#include "VGUI_MouseCode.h" +#include "dlls/extdll.h" +#include "mod/AvHClientUtil.h" +#include "mod/AvHHudConstants.h" + +using namespace vgui; + + +extern int cam_thirdperson; + + +#define VOICE_MODEL_INTERVAL 0.3 +#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. +#define SQUELCHOSCILLATE_PER_SECOND 2.0f + + +extern BitmapTGA *LoadTGA( const char* pImageName ); + +// Allow assignment within conditional +#pragma warning (disable: 4706) + +// ---------------------------------------------------------------------- // +// The voice manager for the client. +// ---------------------------------------------------------------------- // +CVoiceStatus g_VoiceStatus; + +CVoiceStatus* GetClientVoiceMgr() +{ + return &g_VoiceStatus; +} + + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +static CVoiceStatus *g_pInternalVoiceStatus = NULL; + +int __MsgFunc_VoiceMask(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleVoiceMaskMsg(iSize, pbuf); + + return 1; +} + +int __MsgFunc_ReqState(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleReqStateMsg(iSize, pbuf); + + return 1; +} + + +int g_BannedPlayerPrintCount; +void ForEachBannedPlayer(char id[16]) +{ + char str[256]; + sprintf(str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", + g_BannedPlayerPrintCount++, + id[0], id[1], id[2], id[3], + id[4], id[5], id[6], id[7], + id[8], id[9], id[10], id[11], + id[12], id[13], id[14], id[15] + ); +#ifdef _WIN32 + strupr(str); +#endif + gEngfuncs.pfnConsolePrint(str); +} + + +void ShowBannedCallback() +{ + if(g_pInternalVoiceStatus) + { + g_BannedPlayerPrintCount = 0; + gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); + g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer(ForEachBannedPlayer); + gEngfuncs.pfnConsolePrint("------------------------------\n"); + } +} + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +CVoiceStatus::CVoiceStatus() +{ + m_bBanMgrInitialized = false; + m_LastUpdateServerState = 0; + + m_pSpeakerLabelIcon = NULL; + m_pScoreboardNeverSpoken = NULL; + m_pScoreboardNotSpeaking = NULL; + m_pScoreboardSpeaking = NULL; + m_pScoreboardSpeaking2 = NULL; + m_pScoreboardSquelch = NULL; + m_pScoreboardBanned = NULL; + + m_pLocalBitmap = NULL; + m_pAckBitmap = NULL; + + m_bTalking = m_bServerAcked = false; + + memset(m_pBanButtons, 0, sizeof(m_pBanButtons)); + + m_bServerModEnable = -1; +} + + +CVoiceStatus::~CVoiceStatus() +{ + g_pInternalVoiceStatus = NULL; + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + delete m_Labels[i].m_pLabel; + m_Labels[i].m_pLabel = NULL; + + delete m_Labels[i].m_pIcon; + m_Labels[i].m_pIcon = NULL; + + delete m_Labels[i].m_pBackground; + m_Labels[i].m_pBackground = NULL; + } + + delete m_pLocalLabel; + m_pLocalLabel = NULL; + + FreeBitmaps(); + + if(m_pchGameDir) + { + if(m_bBanMgrInitialized) + { + m_BanMgr.SaveState(m_pchGameDir); + } + + free(m_pchGameDir); + } +} + + +int CVoiceStatus::Init( + IVoiceStatusHelper *pHelper, + Panel **pParentPanel) +{ + // Setup the voice_modenable cvar. + gEngfuncs.pfnRegisterVariable("voice_modenable", "1", FCVAR_ARCHIVE); + + gEngfuncs.pfnRegisterVariable("voice_clientdebug", "0", 0); + + gEngfuncs.pfnAddCommand("voice_showbanned", ShowBannedCallback); + + if(gEngfuncs.pfnGetGameDirectory()) + { + m_BanMgr.Init(gEngfuncs.pfnGetGameDirectory()); + m_bBanMgrInitialized = true; + } + + assert(!g_pInternalVoiceStatus); + g_pInternalVoiceStatus = this; + + m_BlinkTimer = 0; + m_VoiceHeadModel = NULL; + memset(m_Labels, 0, sizeof(m_Labels)); + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + pLabel->m_pBackground = new Label(""); + + if(pLabel->m_pLabel = new Label("")) + { + pLabel->m_pLabel->setVisible( true ); + pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); + pLabel->m_pLabel->setTextAlignment( Label::a_east ); + pLabel->m_pLabel->setContentAlignment( Label::a_east ); + pLabel->m_pLabel->setParent( pLabel->m_pBackground ); + } + + if( pLabel->m_pIcon = new ImagePanel( NULL ) ) + { + pLabel->m_pIcon->setVisible( true ); + pLabel->m_pIcon->setParent( pLabel->m_pBackground ); + } + + pLabel->m_clientindex = -1; + } + + m_pLocalLabel = new ImagePanel(NULL); + + m_bInSquelchMode = false; + + m_pHelper = pHelper; + m_pParentPanel = pParentPanel; + gHUD.AddHudElem(this); + m_iFlags = HUD_ACTIVE; + HOOK_MESSAGE(VoiceMask); + HOOK_MESSAGE(ReqState); + + // Cache the game directory for use when we shut down + const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); + m_pchGameDir = (char *)malloc(strlen(pchGameDirT) + 1); + strcpy(m_pchGameDir, pchGameDirT); + + return 1; +} + + +int CVoiceStatus::VidInit() +{ + FreeBitmaps(); + + + if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) + { + m_pLocalBitmap->setColor(Color(255,255,255,135)); + } + + if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) + { + m_pAckBitmap->setColor(Color(255,255,255,135)); // Give just a tiny bit of translucency so software draws correctly. + } + + m_pLocalLabel->setImage( m_pLocalBitmap ); + m_pLocalLabel->setVisible( false ); + + + if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/speaker4.tga" ) ) + m_pSpeakerLabelIcon->setColor( Color(255,255,255,1) ); // Give just a tiny bit of translucency so software draws correctly. + + if (m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker1.tga")) + m_pScoreboardNeverSpoken->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker2.tga")) + m_pScoreboardNotSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker3.tga")) + m_pScoreboardSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker4.tga")) + m_pScoreboardSpeaking2->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSquelch = vgui_LoadTGA("gfx/vgui/icntlk_squelch.tga")) + m_pScoreboardSquelch->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardBanned = vgui_LoadTGA("gfx/vgui/640_voiceblocked.tga")) + m_pScoreboardBanned->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + // Figure out the voice head model height. + m_VoiceHeadModelHeight = 45; + char *pFile = (char *)gEngfuncs.COM_LoadFile("scripts/voicemodel.txt", 5, NULL); + if(pFile) + { + char token[4096]; + gEngfuncs.COM_ParseFile(pFile, token); + if(token[0] >= '0' && token[0] <= '9') + { + m_VoiceHeadModelHeight = (float)atof(token); + } + + gEngfuncs.COM_FreeFile(pFile); + } + + m_VoiceHeadModel = gEngfuncs.pfnSPR_Load("sprites/voiceicon.spr"); + return TRUE; +} + + +void CVoiceStatus::Frame(double frametime) +{ + // check server banned players once per second + if(gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1) + { + UpdateServerState(false); + } + + m_BlinkTimer += frametime; + + // Update speaker labels. + if( m_pHelper->CanShowSpeakerLabels() ) + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); + } + else + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( false ); + } + + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + UpdateBanButton(i); +} + + +void CVoiceStatus::CreateEntities() +{ + if(!m_VoiceHeadModel) + return; + + cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); + + int iOutModel = 0; + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if(!m_VoicePlayers[i]) + continue; + + cl_entity_s *pClient = gEngfuncs.GetEntityByIndex(i+1); + + // Don't show an icon if the player is not in our PVS. + if(!pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum) + continue; + + // Don't show an icon for dead or spectating players (ie: invisible entities). + if(pClient->curstate.effects & EF_NODRAW) + continue; + + // Don't show an icon for the local player unless we're in thirdperson mode. + if(pClient == localPlayer && !cam_thirdperson) + continue; + + cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; + ++iOutModel; + + memset(pEnt, 0, sizeof(*pEnt)); + + pEnt->curstate.rendermode = kRenderTransAdd; + pEnt->curstate.renderamt = 255; + pEnt->baseline.renderamt = 255; + pEnt->curstate.renderfx = kRenderFxNoDissipation; + pEnt->curstate.framerate = 1; + // : different sprite for each team + if (pClient->curstate.team <= SPR_Frames(m_VoiceHeadModel)) + pEnt->curstate.frame = pClient->curstate.team; + else + pEnt->curstate.frame = 0; + //pEnt->curstate.frame = 0; + // : + pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer(m_VoiceHeadModel); + pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; + pEnt->curstate.scale = 0.5f; + + pEnt->origin[0] = pEnt->origin[1] = 0; + pEnt->origin[2] = AvHCUGetIconHeightForPlayer((AvHUser3)pClient->curstate.iuser3); + + VectorAdd(pEnt->origin, pClient->origin, pEnt->origin); + + // Tell the engine. + gEngfuncs.CL_CreateVisibleEntity(ET_NORMAL, pEnt); + } +} + + +void CVoiceStatus::UpdateSpeakerStatus(int entindex, qboolean bTalking) +{ + if(!*m_pParentPanel) + return; + + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + char msg[256]; + _snprintf( msg, sizeof(msg), "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); + gEngfuncs.pfnConsolePrint( msg ); + } + + // Is it the local player talking? + if( entindex == -1 ) + { + m_bTalking = !!bTalking; + if( bTalking ) + { + // Enable voice for them automatically if they try to talk. + gEngfuncs.pfnClientCmd( "voice_modenable 1" ); + } + } + else if( entindex == -2 ) + { + m_bServerAcked = !!bTalking; + } + else if(entindex >= 0 && entindex <= VOICE_MAX_PLAYERS) + { + int iClient = entindex - 1; + if(iClient < 0) + return; + + CVoiceLabel *pLabel = FindVoiceLabel(iClient); + if(bTalking) + { + m_VoicePlayers[iClient] = true; + m_VoiceEnabledPlayers[iClient] = true; + + // If we don't have a label for this guy yet, then create one. + if(!pLabel) + { + if(pLabel = GetFreeVoiceLabel()) + { + // Get the name from the engine. + hud_player_info_t info; + memset(&info, 0, sizeof(info)); + GetPlayerInfo(entindex, &info); + + char paddedName[512]; + _snprintf(paddedName, sizeof(paddedName), "%s ", info.name); + + int color[3]; + m_pHelper->GetPlayerTextColor( entindex, color ); + + if( pLabel->m_pBackground ) + { + pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); + pLabel->m_pBackground->setParent( *m_pParentPanel ); + pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); + } + + if( pLabel->m_pLabel ) + { + pLabel->m_pLabel->setFgColor( 0, 0, 0, 0 ); + pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); + pLabel->m_pLabel->setText( paddedName ); + } + + pLabel->m_clientindex = iClient; + } + } + } + else + { + m_VoicePlayers[iClient] = false; + + // If we have a label for this guy, kill it. + if(pLabel) + { + pLabel->m_pBackground->setVisible(false); + pLabel->m_clientindex = -1; + } + } + } + + RepositionLabels(); +} + + +void CVoiceStatus::UpdateServerState(bool bForce) +{ + // Can't do anything when we're not in a level. + char const *pLevelName = gEngfuncs.pfnGetLevelName(); + if( pLevelName[0] == 0 ) + { + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); + } + + return; + } + + int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat("voice_modenable"); + if(bForce || m_bServerModEnable != bCVarModEnable) + { + m_bServerModEnable = bCVarModEnable; + + char str[256]; + _snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable); + ServerCmd(str); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + } + + char str[2048]; + sprintf(str, "vban"); + bool bChange = false; + + for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + unsigned long serverBanMask = 0; + unsigned long banMask = 0; + for(unsigned long i=0; i < 32; i++) + { + char playerID[16]; + if(!gEngfuncs.GetPlayerUniqueID(i+1, playerID)) + continue; + + if(m_BanMgr.GetPlayerBan(playerID)) + banMask |= 1 << i; + + if(m_ServerBannedPlayers[dw*32 + i]) + serverBanMask |= 1 << i; + } + + if(serverBanMask != banMask) + bChange = true; + + // Ok, the server needs to be updated. + char numStr[512]; + sprintf(numStr, " %x", banMask); + strcat(str, numStr); + } + + if(bChange || bForce) + { + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + + gEngfuncs.pfnServerCmdUnreliable(str); // Tell the server.. + } + else + { + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); + } + } + + m_LastUpdateServerState = gEngfuncs.GetClientTime(); +} + +void CVoiceStatus::UpdateSpeakerImage(Label *pLabel, int iPlayer) +{ + m_pBanButtons[iPlayer-1] = pLabel; + UpdateBanButton(iPlayer-1); +} + +void CVoiceStatus::UpdateBanButton(int iClient) +{ + Label *pPanel = m_pBanButtons[iClient]; + + if (!pPanel) + return; + + char playerID[16]; + extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); + if(!HACK_GetPlayerUniqueID(iClient+1, playerID)) + return; + + // Figure out if it's blinking or not. + bool bBlink = fmod(m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY*2) < SCOREBOARD_BLINK_FREQUENCY; + bool bTalking = !!m_VoicePlayers[iClient]; + bool bBanned = m_BanMgr.GetPlayerBan(playerID); + bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; + + // Get the appropriate image to display on the panel. + if (bBanned) + { + pPanel->setImage(m_pScoreboardBanned); + } + else if (bTalking) + { + if (bBlink) + { + pPanel->setImage(m_pScoreboardSpeaking2); + } + else + { + pPanel->setImage(m_pScoreboardSpeaking); + } + pPanel->setFgColor(255, 170, 0, 1); + } + else if (bNeverSpoken) + { + pPanel->setImage(m_pScoreboardNeverSpoken); + pPanel->setFgColor(100, 100, 100, 1); + } + else + { + pPanel->setImage(m_pScoreboardNotSpeaking); + } +} + +#include "cl_dll/parsemsg.h" +void CVoiceStatus::HandleVoiceMaskMsg(int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + unsigned long dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + m_AudiblePlayers.SetDWord(dw, (unsigned long)READ_LONG()); + m_ServerBannedPlayers.SetDWord(dw, (unsigned long)READ_LONG()); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleVoiceMaskMsg\n"); + + sprintf(str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + + sprintf(str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + } + } + + m_bServerModEnable = READ_BYTE(); +} + +void CVoiceStatus::HandleReqStateMsg(int iSize, void *pbuf) +{ + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleReqStateMsg\n"); + } + + UpdateServerState(true); +} + +void CVoiceStatus::StartSquelchMode() +{ + if(m_bInSquelchMode) + return; + + m_bInSquelchMode = true; + m_pHelper->UpdateCursorState(); +} + +void CVoiceStatus::StopSquelchMode() +{ + m_bInSquelchMode = false; + m_pHelper->UpdateCursorState(); +} + +bool CVoiceStatus::IsInSquelchMode() +{ + return m_bInSquelchMode; +} + +CVoiceLabel* CVoiceStatus::FindVoiceLabel(int clientindex) +{ + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + if(m_Labels[i].m_clientindex == clientindex) + return &m_Labels[i]; + } + + return NULL; +} + + +CVoiceLabel* CVoiceStatus::GetFreeVoiceLabel() +{ + return FindVoiceLabel(-1); +} + + +void CVoiceStatus::RepositionLabels() +{ + // find starting position to draw from, along right-hand side of screen + int y = ScreenHeight() / 2; + + int iconWide = 8, iconTall = 8; + if( m_pSpeakerLabelIcon ) + { + m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); + } + + // Reposition active labels. + for(int i = 0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) + { + if( pLabel->m_pBackground ) + pLabel->m_pBackground->setVisible( false ); + + continue; + } + + int textWide, textTall; + pLabel->m_pLabel->getContentSize( textWide, textTall ); + + // Don't let it stretch too far across their screen. + if( textWide > (ScreenWidth()*2)/3 ) + textWide = (ScreenWidth()*2)/3; + + // Setup the background label to fit everything in. + int border = 2; + int bgWide = textWide + iconWide + border*3; + int bgTall = max( textTall, iconTall ) + border*2; + pLabel->m_pBackground->setBounds( ScreenWidth() - bgWide - 8, y, bgWide, bgTall ); + + // Put the text at the left. + pLabel->m_pLabel->setBounds( border, (bgTall - textTall) / 2, textWide, textTall ); + + // Put the icon at the right. + int iconLeft = border + textWide + border; + int iconTop = (bgTall - iconTall) / 2; + if( pLabel->m_pIcon ) + { + pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); + pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); + } + + y += bgTall + 2; + } + + if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && (m_bTalking || m_bServerAcked) ) + { + m_pLocalLabel->setParent(*m_pParentPanel); + m_pLocalLabel->setVisible( true ); + + if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + m_pLocalLabel->setImage( m_pAckBitmap ); + else + m_pLocalLabel->setImage( m_pLocalBitmap ); + + int sizeX, sizeY; + m_pLocalBitmap->getSize(sizeX, sizeY); + + int local_xPos = ScreenWidth() - sizeX - 10; + int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; + + // Move bar depending on role + switch(gHUD.GetHUDUser3()) + { + case AVH_USER3_ALIEN_PLAYER1: + case AVH_USER3_ALIEN_PLAYER2: + case AVH_USER3_ALIEN_PLAYER3: + case AVH_USER3_ALIEN_PLAYER4: + case AVH_USER3_ALIEN_PLAYER5: + local_xPos -= kResourceEnergyBarWidth*ScreenWidth(); + break; + + case AVH_USER3_COMMANDER_PLAYER: + local_xPos -= kVoiceStatusCommanderRightEdgeInset*ScreenWidth(); + local_yPos -= (1.0f - kVoiceStatusCommanderTopEdgeInset)*ScreenHeight(); + break; + + case AVH_USER3_MARINE_PLAYER: + local_xPos -= kVoiceStatusMarineRightEdgeInset*ScreenWidth(); + break; + } + + m_pLocalLabel->setPos( local_xPos, local_yPos ); + } + else + { + m_pLocalLabel->setVisible( false ); + } +} + + +void CVoiceStatus::FreeBitmaps() +{ + // Delete all the images we have loaded. + delete m_pLocalBitmap; + m_pLocalBitmap = NULL; + + delete m_pAckBitmap; + m_pAckBitmap = NULL; + + delete m_pSpeakerLabelIcon; + m_pSpeakerLabelIcon = NULL; + + delete m_pScoreboardNeverSpoken; + m_pScoreboardNeverSpoken = NULL; + + delete m_pScoreboardNotSpeaking; + m_pScoreboardNotSpeaking = NULL; + + delete m_pScoreboardSpeaking; + m_pScoreboardSpeaking = NULL; + + delete m_pScoreboardSpeaking2; + m_pScoreboardSpeaking2 = NULL; + + delete m_pScoreboardSquelch; + m_pScoreboardSquelch = NULL; + + delete m_pScoreboardBanned; + m_pScoreboardBanned = NULL; + + // Clear references to the images in panels. + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if (m_pBanButtons[i]) + { + m_pBanButtons[i]->setImage(NULL); + } + } + + if(m_pLocalLabel) + m_pLocalLabel->setImage(NULL); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the target client has been banned +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerBlocked(int iPlayer) +{ + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return false; + + return m_BanMgr.GetPlayerBan(playerID); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerAudible(int iPlayer) +{ + return !!m_AudiblePlayers[iPlayer-1]; +} + +//----------------------------------------------------------------------------- +// Purpose: blocks/unblocks the target client from being heard +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked) +{ + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); + } + + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return; + + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); + } + + // Squelch or (try to) unsquelch this player. + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + sprintf(str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(playerID)); + gEngfuncs.pfnConsolePrint(str); + } + + m_BanMgr.SetPlayerBan( playerID, blocked ); + UpdateServerState(false); +} diff --git a/main/source/game_shared/voice_status.h b/main/source/game_shared/voice_status.h index d4ad2ee6..8edf58c7 100644 --- a/main/source/game_shared/voice_status.h +++ b/main/source/game_shared/voice_status.h @@ -1,228 +1,228 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_STATUS_H -#define VOICE_STATUS_H -#pragma once - - -#include "VGUI_Label.h" -#include "VGUI_LineBorder.h" -#include "VGUI_ImagePanel.h" -#include "VGUI_BitmapTGA.h" -#include "VGUI_InputSignal.h" -#include "VGUI_Button.h" -#include "voice_common.h" -#include "cl_entity.h" -#include "voice_banmgr.h" -#include "vgui_checkbutton2.h" -#include "vgui_defaultinputsignal.h" - - -class CVoiceStatus; - - -class CVoiceLabel -{ -public: - vgui::Label *m_pLabel; - vgui::Label *m_pBackground; - vgui::ImagePanel *m_pIcon; // Voice icon next to player name. - int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. -}; - - -// This is provided by each mod to access data that may not be the same across mods. -class IVoiceStatusHelper -{ -public: - virtual ~IVoiceStatusHelper() {} - - // Get RGB color for voice status text about this player. - virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; - - // Force it to update the cursor state. - virtual void UpdateCursorState() = 0; - - // Return the height above the bottom that the voice ack icons should be drawn at. - virtual int GetAckIconHeight() = 0; - - // Return true if the voice manager is allowed to show speaker labels - // (mods usually return false when the scoreboard is up). - virtual bool CanShowSpeakerLabels() = 0; -}; - -//----------------------------------------------------------------------------- -// Purpose: Holds a color for the shared image -//----------------------------------------------------------------------------- -class VoiceImagePanel : public vgui::ImagePanel -{ - virtual void paintBackground() - { - if (_image!=null) - { - vgui::Color col; - getFgColor(col); - _image->setColor(col); - _image->doPaint(this); - } - } -}; - - -class CVoiceStatus : public CHudBase, public vgui::CDefaultInputSignal -{ -public: - CVoiceStatus(); - virtual ~CVoiceStatus(); - -// CHudBase overrides. -public: - - // Initialize the cl_dll's voice manager. - virtual int Init( - IVoiceStatusHelper *m_pHelper, - vgui::Panel **pParentPanel); - - // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. - virtual int VidInit(); - - -public: - - // Call from HUD_Frame each frame. - void Frame(double frametime); - - // Called when a player starts or stops talking. - // entindex is -1 to represent the local client talking (before the data comes back from the server). - // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). - // entindex is -2 to represent the local client's voice being acked by the server. - void UpdateSpeakerStatus(int entindex, qboolean bTalking); - - // sets the correct image in the label for the player - void UpdateSpeakerImage(vgui::Label *pLabel, int iPlayer); - - // Call from the HUD_CreateEntities function so it can add sprites above player heads. - void CreateEntities(); - - // Called when the server registers a change to who this client can hear. - void HandleVoiceMaskMsg(int iSize, void *pbuf); - - // The server sends this message initially to tell the client to send their state. - void HandleReqStateMsg(int iSize, void *pbuf); - - -// Squelch mode functions. -public: - - // When you enter squelch mode, pass in - void StartSquelchMode(); - void StopSquelchMode(); - bool IsInSquelchMode(); - - // returns true if the target client has been banned - // playerIndex is of range 1..maxplayers - bool IsPlayerBlocked(int iPlayerIndex); - - // returns false if the player can't hear the other client due to game rules (eg. the other team) - bool IsPlayerAudible(int iPlayerIndex); - - // blocks the target client from being heard - void SetPlayerBlockedState(int iPlayerIndex, bool blocked); - -public: - - CVoiceLabel* FindVoiceLabel(int clientindex); // Find a CVoiceLabel representing the specified speaker. - // Returns NULL if none. - // entindex can be -1 if you want a currently-unused voice label. - CVoiceLabel* GetFreeVoiceLabel(); // Get an unused voice label. Returns NULL if none. - - void RepositionLabels(); - - void FreeBitmaps(); - - void UpdateServerState(bool bForce); - - // Update the button artwork to reflect the client's current state. - void UpdateBanButton(int iClient); - - -public: - - enum {MAX_VOICE_SPEAKERS=7}; - - float m_LastUpdateServerState; // Last time we called this function. - int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. - - vgui::Panel **m_pParentPanel; - CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. - - // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on - // and is totally separate from the ban list. Indexed by client index. - CPlayerBitVec m_AudiblePlayers; - - // Players who have spoken at least once in the game so far - CPlayerBitVec m_VoiceEnabledPlayers; - - // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). - // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. - CPlayerBitVec m_ServerBannedPlayers; - - cl_entity_s m_VoiceHeadModels[VOICE_MAX_PLAYERS]; // These aren't necessarily in the order of players. They are just - // a place for it to put data in during CreateEntities. - - IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. - - - // Scoreboard icons. - double m_BlinkTimer; // Blink scoreboard icons.. - vgui::BitmapTGA *m_pScoreboardNeverSpoken; - vgui::BitmapTGA *m_pScoreboardNotSpeaking; - vgui::BitmapTGA *m_pScoreboardSpeaking; - vgui::BitmapTGA *m_pScoreboardSpeaking2; - vgui::BitmapTGA *m_pScoreboardSquelch; - vgui::BitmapTGA *m_pScoreboardBanned; - - vgui::Label *m_pBanButtons[VOICE_MAX_PLAYERS]; // scoreboard buttons. - - // Squelch mode stuff. - bool m_bInSquelchMode; - - HSPRITE m_VoiceHeadModel; // Voice head model (goes above players who are speaking). - float m_VoiceHeadModelHeight; // Height above their head to place the model. - - vgui::Image *m_pSpeakerLabelIcon; // Icon next to speaker labels. - - // Lower-right icons telling when the local player is talking.. - vgui::BitmapTGA *m_pLocalBitmap; // Represents the local client talking. - vgui::BitmapTGA *m_pAckBitmap; // Represents the server ack'ing the client talking. - vgui::ImagePanel *m_pLocalLabel; // Represents the local client talking. - - bool m_bTalking; // Set to true when the client thinks it's talking. - bool m_bServerAcked; // Set to true when the server knows the client is talking. - -public: - - CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. - -public: - - bool m_bBanMgrInitialized; - - // Labels telling who is speaking. - CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; - - // Cache the game directory for use when we shut down - char * m_pchGameDir; -}; - - -// Get the (global) voice manager. -CVoiceStatus* GetClientVoiceMgr(); - - -#endif // VOICE_STATUS_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_STATUS_H +#define VOICE_STATUS_H +#pragma once + + +#include "VGUI_Label.h" +#include "VGUI_LineBorder.h" +#include "VGUI_ImagePanel.h" +#include "VGUI_BitmapTGA.h" +#include "VGUI_InputSignal.h" +#include "VGUI_Button.h" +#include "voice_common.h" +#include "cl_entity.h" +#include "voice_banmgr.h" +#include "vgui_checkbutton2.h" +#include "vgui_defaultinputsignal.h" + + +class CVoiceStatus; + + +class CVoiceLabel +{ +public: + vgui::Label *m_pLabel; + vgui::Label *m_pBackground; + vgui::ImagePanel *m_pIcon; // Voice icon next to player name. + int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. +}; + + +// This is provided by each mod to access data that may not be the same across mods. +class IVoiceStatusHelper +{ +public: + virtual ~IVoiceStatusHelper() {} + + // Get RGB color for voice status text about this player. + virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; + + // Force it to update the cursor state. + virtual void UpdateCursorState() = 0; + + // Return the height above the bottom that the voice ack icons should be drawn at. + virtual int GetAckIconHeight() = 0; + + // Return true if the voice manager is allowed to show speaker labels + // (mods usually return false when the scoreboard is up). + virtual bool CanShowSpeakerLabels() = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Holds a color for the shared image +//----------------------------------------------------------------------------- +class VoiceImagePanel : public vgui::ImagePanel +{ + virtual void paintBackground() + { + if (_image!=null) + { + vgui::Color col; + getFgColor(col); + _image->setColor(col); + _image->doPaint(this); + } + } +}; + + +class CVoiceStatus : public CHudBase, public vgui::CDefaultInputSignal +{ +public: + CVoiceStatus(); + virtual ~CVoiceStatus(); + +// CHudBase overrides. +public: + + // Initialize the cl_dll's voice manager. + virtual int Init( + IVoiceStatusHelper *m_pHelper, + vgui::Panel **pParentPanel); + + // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. + virtual int VidInit(); + + +public: + + // Call from HUD_Frame each frame. + void Frame(double frametime); + + // Called when a player starts or stops talking. + // entindex is -1 to represent the local client talking (before the data comes back from the server). + // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). + // entindex is -2 to represent the local client's voice being acked by the server. + void UpdateSpeakerStatus(int entindex, qboolean bTalking); + + // sets the correct image in the label for the player + void UpdateSpeakerImage(vgui::Label *pLabel, int iPlayer); + + // Call from the HUD_CreateEntities function so it can add sprites above player heads. + void CreateEntities(); + + // Called when the server registers a change to who this client can hear. + void HandleVoiceMaskMsg(int iSize, void *pbuf); + + // The server sends this message initially to tell the client to send their state. + void HandleReqStateMsg(int iSize, void *pbuf); + + +// Squelch mode functions. +public: + + // When you enter squelch mode, pass in + void StartSquelchMode(); + void StopSquelchMode(); + bool IsInSquelchMode(); + + // returns true if the target client has been banned + // playerIndex is of range 1..maxplayers + bool IsPlayerBlocked(int iPlayerIndex); + + // returns false if the player can't hear the other client due to game rules (eg. the other team) + bool IsPlayerAudible(int iPlayerIndex); + + // blocks the target client from being heard + void SetPlayerBlockedState(int iPlayerIndex, bool blocked); + +public: + + CVoiceLabel* FindVoiceLabel(int clientindex); // Find a CVoiceLabel representing the specified speaker. + // Returns NULL if none. + // entindex can be -1 if you want a currently-unused voice label. + CVoiceLabel* GetFreeVoiceLabel(); // Get an unused voice label. Returns NULL if none. + + void RepositionLabels(); + + void FreeBitmaps(); + + void UpdateServerState(bool bForce); + + // Update the button artwork to reflect the client's current state. + void UpdateBanButton(int iClient); + + +public: + + enum {MAX_VOICE_SPEAKERS=7}; + + float m_LastUpdateServerState; // Last time we called this function. + int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. + + vgui::Panel **m_pParentPanel; + CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. + + // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on + // and is totally separate from the ban list. Indexed by client index. + CPlayerBitVec m_AudiblePlayers; + + // Players who have spoken at least once in the game so far + CPlayerBitVec m_VoiceEnabledPlayers; + + // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). + // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. + CPlayerBitVec m_ServerBannedPlayers; + + cl_entity_s m_VoiceHeadModels[VOICE_MAX_PLAYERS]; // These aren't necessarily in the order of players. They are just + // a place for it to put data in during CreateEntities. + + IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. + + + // Scoreboard icons. + double m_BlinkTimer; // Blink scoreboard icons.. + vgui::BitmapTGA *m_pScoreboardNeverSpoken; + vgui::BitmapTGA *m_pScoreboardNotSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking2; + vgui::BitmapTGA *m_pScoreboardSquelch; + vgui::BitmapTGA *m_pScoreboardBanned; + + vgui::Label *m_pBanButtons[VOICE_MAX_PLAYERS]; // scoreboard buttons. + + // Squelch mode stuff. + bool m_bInSquelchMode; + + HSPRITE m_VoiceHeadModel; // Voice head model (goes above players who are speaking). + float m_VoiceHeadModelHeight; // Height above their head to place the model. + + vgui::Image *m_pSpeakerLabelIcon; // Icon next to speaker labels. + + // Lower-right icons telling when the local player is talking.. + vgui::BitmapTGA *m_pLocalBitmap; // Represents the local client talking. + vgui::BitmapTGA *m_pAckBitmap; // Represents the server ack'ing the client talking. + vgui::ImagePanel *m_pLocalLabel; // Represents the local client talking. + + bool m_bTalking; // Set to true when the client thinks it's talking. + bool m_bServerAcked; // Set to true when the server knows the client is talking. + +public: + + CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. + +public: + + bool m_bBanMgrInitialized; + + // Labels telling who is speaking. + CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; + + // Cache the game directory for use when we shut down + char * m_pchGameDir; +}; + + +// Get the (global) voice manager. +CVoiceStatus* GetClientVoiceMgr(); + + +#endif // VOICE_STATUS_H diff --git a/main/source/game_shared/voice_vgui_tweakdlg.cpp b/main/source/game_shared/voice_vgui_tweakdlg.cpp index 4a29e375..dc7ba43a 100644 --- a/main/source/game_shared/voice_vgui_tweakdlg.cpp +++ b/main/source/game_shared/voice_vgui_tweakdlg.cpp @@ -1,289 +1,289 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "../cl_dll/hud.h" -#include "../cl_dll/cl_util.h" -#include "../cl_dll/vgui_TeamFortressViewport.h" - - -#include "VGUI_ActionSignal.h" -#include "voice_vgui_tweakdlg.h" -#include "voice_vgui_tweakdlg.h" -#include "VGUI_Panel.h" -#include "VGUI_ScrollBar.h" -#include "VGUI_Slider.h" -#include "common/ivoicetweak.h" -#include "VGUI_Button.h" -#include "vgui_checkbutton2.h" -#include "vgui_helpers.h" - - -#define ITEM_BORDER 40 // Border between text and scrollbars on left and right. -#define VOICETWEAK_TRANSPARENCY 150 - - -class TweakScroller -{ -public: - TweakScroller(); - void Init(Panel *pParent, char *pText, int yPos); - - // Get/set value. Values are 0-1. - float GetValue(); - void SetValue(float val); - -public: - Label m_Label; - ScrollBar m_Scroll; - Slider m_Slider; -}; - - -class CVoiceVGUITweakDlg : public CMenuPanel, public ICheckButton2Handler -{ -typedef CMenuPanel BaseClass; - -public: - CVoiceVGUITweakDlg(); - ~CVoiceVGUITweakDlg(); - -// CMenuPanel overrides. -public: - virtual void Open(); - virtual void Close(); - - -// ICheckButton2Handler overrides. -public: - - virtual void StateChanged(CCheckButton2 *pButton); - - - -// Panel overrides. -public: - virtual void paintBackground(); - - -private: - - int m_DlgWidth; - int m_DlgHeight; - - Label m_Label; - - IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API. - - TweakScroller m_MicVolume; - TweakScroller m_SpeakerVolume; - - CCheckButton2 m_VoiceModEnable; - - Button m_Button_OK; -}; - - - -bool g_bTweakDlgOpen = false; - -bool IsTweakDlgOpen() -{ - return g_bTweakDlgOpen; -} - - - -// ------------------------------------------------------------------------ // -// Global functions. -// ------------------------------------------------------------------------ // - -static CVoiceVGUITweakDlg g_VoiceTweakDlg; -CMenuPanel* GetVoiceTweakDlg() -{ - return &g_VoiceTweakDlg; -} - - -class CVoiceTweakOKButton : public ActionSignal -{ -public: - virtual void actionPerformed(Panel *pPanel) - { - gViewPort->HideVGUIMenu(); - } -}; -CVoiceTweakOKButton g_OKButtonSignal; - - - -// ------------------------------------------------------------------------ // -// TweakScroller -// ------------------------------------------------------------------------ // - -TweakScroller::TweakScroller() : - m_Label(""), - m_Scroll(0,0,0,0,false), - m_Slider(0,0,10,10,false) -{ -} - - -void TweakScroller::Init(Panel *pParent, char *pText, int yPos) -{ - int parentWidth, parentHeight; - pParent->getSize(parentWidth, parentHeight); - - // Setup the volume scroll bar. - m_Label.setParent(pParent); - m_Label.setFont(Scheme::sf_primary1); - m_Label.setContentAlignment(vgui::Label::a_northwest); - m_Label.setBgColor(0, 0, 0, 255); - m_Label.setFgColor(255,255,255,0); - m_Label.setPos(ITEM_BORDER, yPos); - m_Label.setSize(parentWidth/2-ITEM_BORDER, 20); - m_Label.setText(pText); - m_Label.setVisible(true); - - m_Slider.setRangeWindow(10); - m_Slider.setRangeWindowEnabled(true); - - m_Scroll.setPos(parentWidth/2+ITEM_BORDER, yPos); - m_Scroll.setSize(parentWidth/2-ITEM_BORDER*2, 20); - m_Scroll.setSlider(&m_Slider); - m_Scroll.setParent(pParent); - m_Scroll.setRange(0, 100); - m_Scroll.setFgColor(255,255,255,0); - m_Scroll.setBgColor(255,255,255,0); -} - - -float TweakScroller::GetValue() -{ - return m_Scroll.getValue() / 100.0f; -} - - -void TweakScroller::SetValue(float val) -{ - m_Scroll.setValue((int)(val * 100.0f)); -} - - -// ------------------------------------------------------------------------ // -// CVoiceVGUITweakDlg implementation. -// ------------------------------------------------------------------------ // - -CVoiceVGUITweakDlg::CVoiceVGUITweakDlg() - : CMenuPanel(VOICETWEAK_TRANSPARENCY, false, 0, 0, 0, 0), - m_Button_OK("",0,0), - m_Label("") -{ - m_pVoiceTweak = NULL; - m_Button_OK.addActionSignal(&g_OKButtonSignal); - m_Label.setBgColor(255,255,255,200); -} - - -CVoiceVGUITweakDlg::~CVoiceVGUITweakDlg() -{ -} - - -void CVoiceVGUITweakDlg::Open() -{ - if(g_bTweakDlgOpen) - return; - - g_bTweakDlgOpen = true; - - m_DlgWidth = ScreenWidth(); - m_DlgHeight = ScreenHeight(); - - m_pVoiceTweak = gEngfuncs.pVoiceTweak; - - // Tell the engine to start voice tweak mode (pipe voice output right to speakers). - m_pVoiceTweak->StartVoiceTweakMode(); - - // Set our size. - setPos((ScreenWidth() - m_DlgWidth) / 2, (ScreenHeight() - m_DlgHeight) / 2); - setSize(m_DlgWidth, m_DlgHeight); - - int curY = ITEM_BORDER; - m_MicVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Mic_Volume"), curY); - m_MicVolume.SetValue(m_pVoiceTweak->GetControlFloat(MicrophoneVolume)); - curY = PanelBottom(&m_MicVolume.m_Label); - - m_SpeakerVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Speaker_Volume"), curY); - m_SpeakerVolume.SetValue(m_pVoiceTweak->GetControlFloat(OtherSpeakerScale)); - curY = PanelBottom(&m_SpeakerVolume.m_Label); - - m_VoiceModEnable.setParent(this); - m_VoiceModEnable.SetImages("gfx/vgui/checked.tga", "gfx/vgui/unchecked.tga"); - m_VoiceModEnable.SetText("Enable Voice In This Mod"); - m_VoiceModEnable.setPos(ITEM_BORDER, curY); - m_VoiceModEnable.SetCheckboxLeft(false); - m_VoiceModEnable.SetChecked(!!gEngfuncs.pfnGetCvarFloat("voice_modenable")); - m_VoiceModEnable.SetHandler(this); - - // Setup the OK button. - int buttonWidth, buttonHeight; - m_Button_OK.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Menu_OK")); - m_Button_OK.getSize(buttonWidth, buttonHeight); - m_Button_OK.setPos((m_DlgWidth - buttonWidth) / 2, m_DlgHeight - buttonHeight - 3); - m_Button_OK.setParent(this); - - // Put the label on the top. - m_Label.setBgColor(0, 0, 0, 255); - m_Label.setFgColor(255,255,255,0); - m_Label.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Voice_Properties")); - int labelWidth, labelHeight; - m_Label.getSize(labelWidth, labelHeight); - m_Label.setPos((m_DlgWidth - labelWidth) / 2, 5); - m_Label.setParent(this); - - BaseClass::Open(); -} - - -void CVoiceVGUITweakDlg::Close() -{ - m_pVoiceTweak->EndVoiceTweakMode(); - g_bTweakDlgOpen = false; - - BaseClass::Close(); -} - - -void CVoiceVGUITweakDlg::paintBackground() -{ - BaseClass::paintBackground(); - - // Draw our border. - int w,h; - getSize(w,h); - - drawSetColor(128,128,128,1); - drawOutlinedRect(0, 0, w, h); - - float volume = m_MicVolume.GetValue(); - m_pVoiceTweak->SetControlFloat(MicrophoneVolume, volume); - - m_pVoiceTweak->SetControlFloat(OtherSpeakerScale, m_SpeakerVolume.GetValue()); -} - - -void CVoiceVGUITweakDlg::StateChanged(CCheckButton2 *pButton) -{ - if(pButton == &m_VoiceModEnable) - { - if(pButton->IsChecked()) - gEngfuncs.pfnClientCmd("voice_modenable 1"); - else - gEngfuncs.pfnClientCmd("voice_modenable 0"); - } -} - +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "../cl_dll/hud.h" +#include "../cl_dll/cl_util.h" +#include "../cl_dll/vgui_TeamFortressViewport.h" + + +#include "VGUI_ActionSignal.h" +#include "voice_vgui_tweakdlg.h" +#include "voice_vgui_tweakdlg.h" +#include "VGUI_Panel.h" +#include "VGUI_ScrollBar.h" +#include "VGUI_Slider.h" +#include "common/ivoicetweak.h" +#include "VGUI_Button.h" +#include "vgui_checkbutton2.h" +#include "vgui_helpers.h" + + +#define ITEM_BORDER 40 // Border between text and scrollbars on left and right. +#define VOICETWEAK_TRANSPARENCY 150 + + +class TweakScroller +{ +public: + TweakScroller(); + void Init(Panel *pParent, char *pText, int yPos); + + // Get/set value. Values are 0-1. + float GetValue(); + void SetValue(float val); + +public: + Label m_Label; + ScrollBar m_Scroll; + Slider m_Slider; +}; + + +class CVoiceVGUITweakDlg : public CMenuPanel, public ICheckButton2Handler +{ +typedef CMenuPanel BaseClass; + +public: + CVoiceVGUITweakDlg(); + ~CVoiceVGUITweakDlg(); + +// CMenuPanel overrides. +public: + virtual void Open(); + virtual void Close(); + + +// ICheckButton2Handler overrides. +public: + + virtual void StateChanged(CCheckButton2 *pButton); + + + +// Panel overrides. +public: + virtual void paintBackground(); + + +private: + + int m_DlgWidth; + int m_DlgHeight; + + Label m_Label; + + IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API. + + TweakScroller m_MicVolume; + TweakScroller m_SpeakerVolume; + + CCheckButton2 m_VoiceModEnable; + + Button m_Button_OK; +}; + + + +bool g_bTweakDlgOpen = false; + +bool IsTweakDlgOpen() +{ + return g_bTweakDlgOpen; +} + + + +// ------------------------------------------------------------------------ // +// Global functions. +// ------------------------------------------------------------------------ // + +static CVoiceVGUITweakDlg g_VoiceTweakDlg; +CMenuPanel* GetVoiceTweakDlg() +{ + return &g_VoiceTweakDlg; +} + + +class CVoiceTweakOKButton : public ActionSignal +{ +public: + virtual void actionPerformed(Panel *pPanel) + { + gViewPort->HideVGUIMenu(); + } +}; +CVoiceTweakOKButton g_OKButtonSignal; + + + +// ------------------------------------------------------------------------ // +// TweakScroller +// ------------------------------------------------------------------------ // + +TweakScroller::TweakScroller() : + m_Label(""), + m_Scroll(0,0,0,0,false), + m_Slider(0,0,10,10,false) +{ +} + + +void TweakScroller::Init(Panel *pParent, char *pText, int yPos) +{ + int parentWidth, parentHeight; + pParent->getSize(parentWidth, parentHeight); + + // Setup the volume scroll bar. + m_Label.setParent(pParent); + m_Label.setFont(Scheme::sf_primary1); + m_Label.setContentAlignment(vgui::Label::a_northwest); + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setPos(ITEM_BORDER, yPos); + m_Label.setSize(parentWidth/2-ITEM_BORDER, 20); + m_Label.setText(pText); + m_Label.setVisible(true); + + m_Slider.setRangeWindow(10); + m_Slider.setRangeWindowEnabled(true); + + m_Scroll.setPos(parentWidth/2+ITEM_BORDER, yPos); + m_Scroll.setSize(parentWidth/2-ITEM_BORDER*2, 20); + m_Scroll.setSlider(&m_Slider); + m_Scroll.setParent(pParent); + m_Scroll.setRange(0, 100); + m_Scroll.setFgColor(255,255,255,0); + m_Scroll.setBgColor(255,255,255,0); +} + + +float TweakScroller::GetValue() +{ + return m_Scroll.getValue() / 100.0f; +} + + +void TweakScroller::SetValue(float val) +{ + m_Scroll.setValue((int)(val * 100.0f)); +} + + +// ------------------------------------------------------------------------ // +// CVoiceVGUITweakDlg implementation. +// ------------------------------------------------------------------------ // + +CVoiceVGUITweakDlg::CVoiceVGUITweakDlg() + : CMenuPanel(VOICETWEAK_TRANSPARENCY, false, 0, 0, 0, 0), + m_Button_OK("",0,0), + m_Label("") +{ + m_pVoiceTweak = NULL; + m_Button_OK.addActionSignal(&g_OKButtonSignal); + m_Label.setBgColor(255,255,255,200); +} + + +CVoiceVGUITweakDlg::~CVoiceVGUITweakDlg() +{ +} + + +void CVoiceVGUITweakDlg::Open() +{ + if(g_bTweakDlgOpen) + return; + + g_bTweakDlgOpen = true; + + m_DlgWidth = ScreenWidth(); + m_DlgHeight = ScreenHeight(); + + m_pVoiceTweak = gEngfuncs.pVoiceTweak; + + // Tell the engine to start voice tweak mode (pipe voice output right to speakers). + m_pVoiceTweak->StartVoiceTweakMode(); + + // Set our size. + setPos((ScreenWidth() - m_DlgWidth) / 2, (ScreenHeight() - m_DlgHeight) / 2); + setSize(m_DlgWidth, m_DlgHeight); + + int curY = ITEM_BORDER; + m_MicVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Mic_Volume"), curY); + m_MicVolume.SetValue(m_pVoiceTweak->GetControlFloat(MicrophoneVolume)); + curY = PanelBottom(&m_MicVolume.m_Label); + + m_SpeakerVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Speaker_Volume"), curY); + m_SpeakerVolume.SetValue(m_pVoiceTweak->GetControlFloat(OtherSpeakerScale)); + curY = PanelBottom(&m_SpeakerVolume.m_Label); + + m_VoiceModEnable.setParent(this); + m_VoiceModEnable.SetImages("gfx/vgui/checked.tga", "gfx/vgui/unchecked.tga"); + m_VoiceModEnable.SetText("Enable Voice In This Mod"); + m_VoiceModEnable.setPos(ITEM_BORDER, curY); + m_VoiceModEnable.SetCheckboxLeft(false); + m_VoiceModEnable.SetChecked(!!gEngfuncs.pfnGetCvarFloat("voice_modenable")); + m_VoiceModEnable.SetHandler(this); + + // Setup the OK button. + int buttonWidth, buttonHeight; + m_Button_OK.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Menu_OK")); + m_Button_OK.getSize(buttonWidth, buttonHeight); + m_Button_OK.setPos((m_DlgWidth - buttonWidth) / 2, m_DlgHeight - buttonHeight - 3); + m_Button_OK.setParent(this); + + // Put the label on the top. + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Voice_Properties")); + int labelWidth, labelHeight; + m_Label.getSize(labelWidth, labelHeight); + m_Label.setPos((m_DlgWidth - labelWidth) / 2, 5); + m_Label.setParent(this); + + BaseClass::Open(); +} + + +void CVoiceVGUITweakDlg::Close() +{ + m_pVoiceTweak->EndVoiceTweakMode(); + g_bTweakDlgOpen = false; + + BaseClass::Close(); +} + + +void CVoiceVGUITweakDlg::paintBackground() +{ + BaseClass::paintBackground(); + + // Draw our border. + int w,h; + getSize(w,h); + + drawSetColor(128,128,128,1); + drawOutlinedRect(0, 0, w, h); + + float volume = m_MicVolume.GetValue(); + m_pVoiceTweak->SetControlFloat(MicrophoneVolume, volume); + + m_pVoiceTweak->SetControlFloat(OtherSpeakerScale, m_SpeakerVolume.GetValue()); +} + + +void CVoiceVGUITweakDlg::StateChanged(CCheckButton2 *pButton) +{ + if(pButton == &m_VoiceModEnable) + { + if(pButton->IsChecked()) + gEngfuncs.pfnClientCmd("voice_modenable 1"); + else + gEngfuncs.pfnClientCmd("voice_modenable 0"); + } +} + diff --git a/main/source/game_shared/voice_vgui_tweakdlg.h b/main/source/game_shared/voice_vgui_tweakdlg.h index 94e55908..35b07d8b 100644 --- a/main/source/game_shared/voice_vgui_tweakdlg.h +++ b/main/source/game_shared/voice_vgui_tweakdlg.h @@ -1,25 +1,25 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_VGUI_TWEAKDLG_H -#define VOICE_VGUI_TWEAKDLG_H -#ifdef _WIN32 -#pragma once -#endif - - -class CMenuPanel; - - -// Returns true if the tweak dialog is currently up. -bool IsTweakDlgOpen(); - -// Returns a global instance of the tweak dialog. -CMenuPanel* GetVoiceTweakDlg(); - - -#endif // VOICE_VGUI_TWEAKDLG_H +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_VGUI_TWEAKDLG_H +#define VOICE_VGUI_TWEAKDLG_H +#ifdef _WIN32 +#pragma once +#endif + + +class CMenuPanel; + + +// Returns true if the tweak dialog is currently up. +bool IsTweakDlgOpen(); + +// Returns a global instance of the tweak dialog. +CMenuPanel* GetVoiceTweakDlg(); + + +#endif // VOICE_VGUI_TWEAKDLG_H diff --git a/main/source/includes/fmod/inc/fmod.h b/main/source/includes/fmod/inc/fmod.h index 4164a98b..32207228 100644 --- a/main/source/includes/fmod/inc/fmod.h +++ b/main/source/includes/fmod/inc/fmod.h @@ -1,1183 +1,1183 @@ -/* ========================================================================================== */ -/* FMOD Main header file. Copyright (c), Firelight Technologies Pty, Ltd 1999-2003. */ -/* ========================================================================================== */ - -#ifndef _FMOD_H_ -#define _FMOD_H_ - -/* ========================================================================================== */ -/* DEFINITIONS */ -/* ========================================================================================== */ - -#if (!defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(_WIN32_WCE) && !defined(_XBOX)) || (defined(__GNUC__) && defined(WIN32)) - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __stdcall - #define __stdcall - #endif -#endif - -#if defined(_WIN32_WCE) - #define F_API _cdecl - #define F_CALLBACKAPI _cdecl -#else - #define F_API __stdcall - #define F_CALLBACKAPI __stdcall -#endif - -#ifdef DLL_EXPORTS - #define DLL_API __declspec(dllexport) -#else - #if defined(__LCC__) || defined(__MINGW32__) || defined(__CYGWIN32__) - #define DLL_API F_API - #else - #define DLL_API - #endif /* __LCC__ || __MINGW32__ || __CYGWIN32__ */ -#endif /* DLL_EXPORTS */ - -#define FMOD_VERSION 3.71f - -/* - FMOD defined types -*/ -typedef struct FSOUND_SAMPLE FSOUND_SAMPLE; -typedef struct FSOUND_STREAM FSOUND_STREAM; -typedef struct FSOUND_DSPUNIT FSOUND_DSPUNIT; -typedef struct FSOUND_SYNCPOINT FSOUND_SYNCPOINT; -typedef struct FMUSIC_MODULE FMUSIC_MODULE; - -/* - Callback types -*/ -typedef void * (F_CALLBACKAPI *FSOUND_DSPCALLBACK) (void *originalbuffer, void *newbuffer, int length, int param); -typedef signed char (F_CALLBACKAPI *FSOUND_STREAMCALLBACK) (FSOUND_STREAM *stream, void *buff, int len, int param); -typedef void (F_CALLBACKAPI *FMUSIC_CALLBACK) (FMUSIC_MODULE *mod, unsigned char param); - -typedef unsigned int(F_CALLBACKAPI *FSOUND_OPENCALLBACK) (const char *name); -typedef void (F_CALLBACKAPI *FSOUND_CLOSECALLBACK) (unsigned int handle); -typedef int (F_CALLBACKAPI *FSOUND_READCALLBACK) (void *buffer, int size, unsigned int handle); -typedef int (F_CALLBACKAPI *FSOUND_SEEKCALLBACK) (unsigned int handle, int pos, signed char mode); -typedef int (F_CALLBACKAPI *FSOUND_TELLCALLBACK) (unsigned int handle); - -typedef void * (F_CALLBACKAPI *FSOUND_ALLOCCALLBACK) (unsigned int size); -typedef void * (F_CALLBACKAPI *FSOUND_REALLOCCALLBACK) (void *ptr, unsigned int size); -typedef void (F_CALLBACKAPI *FSOUND_FREECALLBACK) (void *ptr); - -typedef signed char (F_CALLBACKAPI *FSOUND_METADATACALLBACK)(char *name, char *value, int userdata); - - -/* -[ENUM] -[ - [DESCRIPTION] - On failure of commands in FMOD, use FSOUND_GetError to attain what happened. - - [SEE_ALSO] - FSOUND_GetError -] -*/ -enum FMOD_ERRORS -{ - FMOD_ERR_NONE, /* No errors */ - FMOD_ERR_BUSY, /* Cannot call this command after FSOUND_Init. Call FSOUND_Close first. */ - FMOD_ERR_UNINITIALIZED, /* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */ - FMOD_ERR_INIT, /* Error initializing output device. */ - FMOD_ERR_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ - FMOD_ERR_PLAY, /* Playing the sound failed. */ - FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */ - FMOD_ERR_COOPERATIVELEVEL, /* Error setting cooperative level for hardware. */ - FMOD_ERR_CREATEBUFFER, /* Error creating hardware sound buffer. */ - FMOD_ERR_FILE_NOTFOUND, /* File not found */ - FMOD_ERR_FILE_FORMAT, /* Unknown file format */ - FMOD_ERR_FILE_BAD, /* Error loading file */ - FMOD_ERR_MEMORY, /* Not enough memory or resources */ - FMOD_ERR_VERSION, /* The version number of this file format is not supported */ - FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function */ - FMOD_ERR_NO_EAX, /* Tried to use an EAX command on a non EAX enabled channel or output. */ - FMOD_ERR_CHANNEL_ALLOC, /* Failed to allocate a new channel */ - FMOD_ERR_RECORD, /* Recording is not supported on this machine */ - FMOD_ERR_MEDIAPLAYER, /* Windows Media Player not installed so cannot play wma or use internet streaming. */ - FMOD_ERR_CDDEVICE /* An error occured trying to open the specified CD device */ -}; - - -/* -[ENUM] -[ - [DESCRIPTION] - These output types are used with FSOUND_SetOutput, to choose which output driver to use. - - FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver - does not support DirectX 6 Voice Manager Extensions. - - FSOUND_OUTPUT_WINMM is recommended for NT and CE. - - [SEE_ALSO] - FSOUND_SetOutput - FSOUND_GetOutput -] -*/ -enum FSOUND_OUTPUTTYPES -{ - FSOUND_OUTPUT_NOSOUND, /* NoSound driver, all calls to this succeed but do nothing. */ - FSOUND_OUTPUT_WINMM, /* Windows Multimedia driver. */ - FSOUND_OUTPUT_DSOUND, /* DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. */ - FSOUND_OUTPUT_A3D, /* A3D driver. */ - - FSOUND_OUTPUT_OSS, /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */ - FSOUND_OUTPUT_ESD, /* Linux/Unix ESD (Enlightment Sound Daemon) driver. */ - FSOUND_OUTPUT_ALSA, /* Linux Alsa driver. */ - - FSOUND_OUTPUT_ASIO, /* Low latency ASIO driver */ - FSOUND_OUTPUT_XBOX, /* Xbox driver */ - FSOUND_OUTPUT_PS2, /* PlayStation 2 driver */ - FSOUND_OUTPUT_MAC, /* Mac SoundManager driver */ - FSOUND_OUTPUT_GC, /* Gamecube driver */ - - FSOUND_OUTPUT_NOSOUND_NONREALTIME /* This is the same as nosound, but the sound generation is driven by FSOUND_Update */ -}; - - -/* -[ENUM] -[ - [DESCRIPTION] - These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act - upon for other reasons using FSOUND_GetMixer. - It is not nescessary to set the mixer. FMOD will autodetect the best mixer for you. - - [SEE_ALSO] - FSOUND_SetMixer - FSOUND_GetMixer -] -*/ -enum FSOUND_MIXERTYPES -{ - FSOUND_MIXER_AUTODETECT, /* CE/PS2/GC Only - Non interpolating/low quality mixer. */ - FSOUND_MIXER_BLENDMODE, /* Removed / obsolete. */ - FSOUND_MIXER_MMXP5, /* Removed / obsolete. */ - FSOUND_MIXER_MMXP6, /* Removed / obsolete. */ - - FSOUND_MIXER_QUALITY_AUTODETECT,/* All platforms - Autodetect the fastest quality mixer based on your cpu. */ - FSOUND_MIXER_QUALITY_FPU, /* Win32/Linux only - Interpolating/volume ramping FPU mixer. */ - FSOUND_MIXER_QUALITY_MMXP5, /* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. */ - FSOUND_MIXER_QUALITY_MMXP6, /* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */ - - FSOUND_MIXER_MONO, /* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/ - FSOUND_MIXER_QUALITY_MONO, /* CE/PS2/GC only - MONO Interpolating mixer. For speed */ - - FSOUND_MIXER_MAX -}; - - -/* -[ENUM] -[ - [DESCRIPTION] - These definitions describe the type of song being played. - - [SEE_ALSO] - FMUSIC_GetType -] -*/ -enum FMUSIC_TYPES -{ - FMUSIC_TYPE_NONE, - FMUSIC_TYPE_MOD, /* Protracker / Fasttracker */ - FMUSIC_TYPE_S3M, /* ScreamTracker 3 */ - FMUSIC_TYPE_XM, /* FastTracker 2 */ - FMUSIC_TYPE_IT, /* Impulse Tracker. */ - FMUSIC_TYPE_MIDI, /* MIDI file */ - FMUSIC_TYPE_FSB /* FMOD Sample Bank file */ -}; - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_DSP_PRIORITIES - - [DESCRIPTION] - These default priorities are used by FMOD internal system DSP units. They describe the - position of the DSP chain, and the order of how audio processing is executed. - You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP - unit), disable or even change the priority of a DSP unit. - - [SEE_ALSO] - FSOUND_DSP_Create - FSOUND_DSP_SetPriority - FSOUND_DSP_GetSpectrum -] -*/ -#define FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT 0 /* DSP CLEAR unit - done first */ -#define FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT 100 /* DSP SFX unit - done second */ -#define FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT 200 /* DSP MUSIC unit - done third */ -#define FSOUND_DSP_DEFAULTPRIORITY_USER 300 /* User priority, use this as reference for your own DSP units */ -#define FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT 900 /* This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units */ -#define FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT 1000 /* DSP CLIP AND COPY unit - last */ -/* [DEFINE_END] */ - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_CAPS - - [DESCRIPTION] - Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated - has the settings you are after. The enumerated driver depends on the output mode, see - FSOUND_OUTPUTTYPES - - [SEE_ALSO] - FSOUND_GetDriverCaps - FSOUND_OUTPUTTYPES -] -*/ -#define FSOUND_CAPS_HARDWARE 0x1 /* This driver supports hardware accelerated 3d sound. */ -#define FSOUND_CAPS_EAX2 0x2 /* This driver supports EAX 2 reverb */ -#define FSOUND_CAPS_EAX3 0x10 /* This driver supports EAX 3 reverb */ -/* [DEFINE_END] */ - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_MODES - - [DESCRIPTION] - Sample description bitfields, OR them together for loading and describing samples. - NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then - trying to override the pre-defined format with a new set of format flags will not work. For - example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just - ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags - you can specify that will really alter the behaviour of how it is loaded, are the following. - --------- - Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI - Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D - Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO - Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX - PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP - --------- - See flag descriptions for what these do. -] -*/ -#define FSOUND_LOOP_OFF 0x00000001 /* For non looping samples. */ -#define FSOUND_LOOP_NORMAL 0x00000002 /* For forward looping samples. */ -#define FSOUND_LOOP_BIDI 0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */ -#define FSOUND_8BITS 0x00000008 /* For 8 bit samples. */ -#define FSOUND_16BITS 0x00000010 /* For 16 bit samples. */ -#define FSOUND_MONO 0x00000020 /* For mono samples. */ -#define FSOUND_STEREO 0x00000040 /* For stereo samples. */ -#define FSOUND_UNSIGNED 0x00000080 /* For user created source data containing unsigned samples. */ -#define FSOUND_SIGNED 0x00000100 /* For user created source data containing signed data. */ -#define FSOUND_DELTA 0x00000200 /* For user created source data stored as delta values. */ -#define FSOUND_IT214 0x00000400 /* For user created source data stored using IT214 compression. */ -#define FSOUND_IT215 0x00000800 /* For user created source data stored using IT215 compression. */ -#define FSOUND_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */ -#define FSOUND_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */ -#define FSOUND_STREAMABLE 0x00004000 /* For a streamimg sound where you feed the data to it. */ -#define FSOUND_LOADMEMORY 0x00008000 /* "name" will be interpreted as a pointer to data for streaming and samples. */ -#define FSOUND_LOADRAW 0x00010000 /* Will ignore file format and treat as raw pcm. */ -#define FSOUND_MPEGACCURATE 0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */ -#define FSOUND_FORCEMONO 0x00040000 /* For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams */ -#define FSOUND_HW2D 0x00080000 /* 2D hardware sounds. allows hardware specific effects */ -#define FSOUND_ENABLEFX 0x00100000 /* Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency */ -#define FSOUND_MPEGHALFRATE 0x00200000 /* For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution */ -#define FSOUND_IMAADPCM 0x00400000 /* Contents are stored compressed as IMA ADPCM */ -#define FSOUND_VAG 0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */ -#define FSOUND_NONBLOCKING 0x01000000 /* For FSOUND_Stream_Open/FMUSIC_LoadSong - Causes stream or music to open in the background and not block the foreground app. See FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState to determine when it IS ready. */ -#define FSOUND_GCADPCM 0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */ -#define FSOUND_MULTICHANNEL 0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */ -#define FSOUND_USECORE0 0x08000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 00-23 */ -#define FSOUND_USECORE1 0x10000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 24-47 */ -#define FSOUND_LOADMEMORYIOP 0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */ -#define FSOUND_STREAM_NET 0x80000000 /* Specifies an internet stream */ - -#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO) -/* [DEFINE_END] */ - - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_CDPLAYMODES - - [DESCRIPTION] - Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode - - [SEE_ALSO] - FSOUND_CD_SetPlayMode - FSOUND_CD_Play -] -*/ -#define FSOUND_CD_PLAYCONTINUOUS 0 /* Starts from the current track and plays to end of CD. */ -#define FSOUND_CD_PLAYONCE 1 /* Plays the specified track then stops. */ -#define FSOUND_CD_PLAYLOOPED 2 /* Plays the specified track looped, forever until stopped manually. */ -#define FSOUND_CD_PLAYRANDOM 3 /* Plays tracks in random order */ -/* [DEFINE_END] */ - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_MISC_VALUES - - [DESCRIPTION] - Miscellaneous values for FMOD functions. - - [SEE_ALSO] - FSOUND_PlaySound - FSOUND_PlaySoundEx - FSOUND_Sample_Alloc - FSOUND_Sample_Load - FSOUND_SetPan -] -*/ -#define FSOUND_FREE -1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */ -#define FSOUND_UNMANAGED -2 /* value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. */ -#define FSOUND_ALL -3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */ -#define FSOUND_STEREOPAN -1 /* value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. */ -#define FSOUND_SYSTEMCHANNEL -1000 /* special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output channel */ -#define FSOUND_SYSTEMSAMPLE -1000 /* special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample */ - -/* [DEFINE_END] */ - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure defining a reverb environment. - For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3 - documentation at http://developer.creative.com/ under the 'downloads' section. - If they do not have the EAX3 documentation, then most information can be attained from - the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of EAX2. - Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. - Note that integer values that typically range from -10,000 to 1000 are represented in decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. - PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). - Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then the reverb should product a similar effect on either platform. - - The numerical values listed below are the maximum, minimum and default values for each variable respectively. - - [SEE_ALSO] - FSOUND_Reverb_SetProperties - FSOUND_Reverb_GetProperties - FSOUND_REVERB_PRESETS - FSOUND_REVERB_FLAGS -] -*/ -typedef struct _FSOUND_REVERB_PROPERTIES /* MIN MAX DEFAULT DESCRIPTION */ -{ - unsigned int Environment; /* 0 , 25 , 0 , sets all listener properties (WIN32/PS2 only) */ - float EnvSize; /* 1.0 , 100.0 , 7.5 , environment size in meters (WIN32 only) */ - float EnvDiffusion; /* 0.0 , 1.0 , 1.0 , environment diffusion (WIN32/XBOX) */ - int Room; /* -10000, 0 , -1000 , room effect level (at mid frequencies) (WIN32/XBOX/PS2) */ - int RoomHF; /* -10000, 0 , -100 , relative room effect level at high frequencies (WIN32/XBOX) */ - int RoomLF; /* -10000, 0 , 0 , relative room effect level at low frequencies (WIN32 only) */ - float DecayTime; /* 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (WIN32/XBOX) */ - float DecayHFRatio; /* 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (WIN32/XBOX) */ - float DecayLFRatio; /* 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (WIN32 only) */ - int Reflections; /* -10000, 1000 , -2602 , early reflections level relative to room effect (WIN32/XBOX) */ - float ReflectionsDelay; /* 0.0 , 0.3 , 0.007 , initial reflection delay time (WIN32/XBOX) */ - float ReflectionsPan[3]; /* , , [0,0,0], early reflections panning vector (WIN32 only) */ - int Reverb; /* -10000, 2000 , 200 , late reverberation level relative to room effect (WIN32/XBOX) */ - float ReverbDelay; /* 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (WIN32/XBOX) */ - float ReverbPan[3]; /* , , [0,0,0], late reverberation panning vector (WIN32 only) */ - float EchoTime; /* .075 , 0.25 , 0.25 , echo time (WIN32/PS2 only. PS2 = Delay time for ECHO/DELAY modes only) */ - float EchoDepth; /* 0.0 , 1.0 , 0.0 , echo depth (WIN32/PS2 only. PS2 = Feedback level for ECHO mode only) */ - float ModulationTime; /* 0.04 , 4.0 , 0.25 , modulation time (WIN32 only) */ - float ModulationDepth; /* 0.0 , 1.0 , 0.0 , modulation depth (WIN32 only) */ - float AirAbsorptionHF; /* -100 , 0.0 , -5.0 , change in level per meter at high frequencies (WIN32 only) */ - float HFReference; /* 1000.0, 20000 , 5000.0 , reference high frequency (hz) (WIN32/XBOX) */ - float LFReference; /* 20.0 , 1000.0, 250.0 , reference low frequency (hz) (WIN32 only) */ - float RoomRolloffFactor; /* 0.0 , 10.0 , 0.0 , like FSOUND_3D_SetRolloffFactor but for room effect (WIN32/XBOX) */ - float Diffusion; /* 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (XBOX only) */ - float Density; /* 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (XBOX only) */ - unsigned int Flags; /* FSOUND_REVERB_FLAGS - modifies the behavior of above properties (WIN32/PS2 only) */ -} FSOUND_REVERB_PROPERTIES; - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_REVERB_FLAGS - - [DESCRIPTION] - Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure. - - [SEE_ALSO] - FSOUND_REVERB_PROPERTIES -] -*/ -#define FSOUND_REVERB_FLAGS_DECAYTIMESCALE 0x00000001 /* 'EnvSize' affects reverberation decay time */ -#define FSOUND_REVERB_FLAGS_REFLECTIONSSCALE 0x00000002 /* 'EnvSize' affects reflection level */ -#define FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 /* 'EnvSize' affects initial reflection delay time */ -#define FSOUND_REVERB_FLAGS_REVERBSCALE 0x00000008 /* 'EnvSize' affects reflections level */ -#define FSOUND_REVERB_FLAGS_REVERBDELAYSCALE 0x00000010 /* 'EnvSize' affects late reverberation delay time */ -#define FSOUND_REVERB_FLAGS_DECAYHFLIMIT 0x00000020 /* AirAbsorptionHF affects DecayHFRatio */ -#define FSOUND_REVERB_FLAGS_ECHOTIMESCALE 0x00000040 /* 'EnvSize' affects echo time */ -#define FSOUND_REVERB_FLAGS_MODULATIONTIMESCALE 0x00000080 /* 'EnvSize' affects modulation time */ -#define FSOUND_REVERB_FLAGS_CORE0 0x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */ -#define FSOUND_REVERB_FLAGS_CORE1 0x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */ -#define FSOUND_REVERB_FLAGS_DEFAULT (FSOUND_REVERB_FLAGS_DECAYTIMESCALE | \ - FSOUND_REVERB_FLAGS_REFLECTIONSSCALE | \ - FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE | \ - FSOUND_REVERB_FLAGS_REVERBSCALE | \ - FSOUND_REVERB_FLAGS_REVERBDELAYSCALE | \ - FSOUND_REVERB_FLAGS_DECAYHFLIMIT | \ - FSOUND_REVERB_FLAGS_CORE0 | \ - FSOUND_REVERB_FLAGS_CORE1 ) -/* [DEFINE_END] */ - - - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_REVERB_PRESETS - - [DESCRIPTION] - A set of predefined environment PARAMETERS, created by Creative Labs - These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically. - ie - FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC; - - [SEE_ALSO] - FSOUND_Reverb_SetProperties -] -*/ -/* Env Size Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel RefPan Revb RevDel ReverbPan EchoTm EchDp ModTm ModDp AirAbs HFRef LFRef RRlOff Diffus Densty FLAGS */ -#define FSOUND_PRESET_OFF {0, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x33f } -#define FSOUND_PRESET_GENERIC {0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_PADDEDCELL {1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, { 0.0f,0.0f,0.0f }, 207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_ROOM {2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, { 0.0f,0.0f,0.0f }, 53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_BATHROOM {3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, { 0.0f,0.0f,0.0f }, 1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f } -#define FSOUND_PRESET_LIVINGROOM {4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_STONEROOM {5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, { 0.0f,0.0f,0.0f }, 83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_AUDITORIUM {6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, { 0.0f,0.0f,0.0f }, -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_CONCERTHALL {7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, { 0.0f,0.0f,0.0f }, -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_CAVE {8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, { 0.0f,0.0f,0.0f }, -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -#define FSOUND_PRESET_ARENA {9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, { 0.0f,0.0f,0.0f }, 16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_HANGAR {10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, { 0.0f,0.0f,0.0f }, 198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_CARPETTEDHALLWAY {11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_HALLWAY {12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, { 0.0f,0.0f,0.0f }, 441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_STONECORRIDOR {13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, { 0.0f,0.0f,0.0f }, 395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_ALLEY {14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, { 0.0f,0.0f,0.0f }, -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_FOREST {15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, { 0.0f,0.0f,0.0f }, -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_CITY {16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_MOUNTAINS {17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f } -#define FSOUND_PRESET_QUARRY {18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f }, 500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_PLAIN {19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f } -#define FSOUND_PRESET_PARKINGLOT {20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -#define FSOUND_PRESET_SEWERPIPE {21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, { 0.0f,0.0f,0.0f }, 1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f } -#define FSOUND_PRESET_UNDERWATER {22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, { 0.0f,0.0f,0.0f }, 1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } - -/* Non I3DL2 presets */ - -#define FSOUND_PRESET_DRUGGED {23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, { 0.0f,0.0f,0.0f }, 985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -#define FSOUND_PRESET_DIZZY {24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, { 0.0f,0.0f,0.0f }, -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -#define FSOUND_PRESET_PSYCHOTIC {25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, { 0.0f,0.0f,0.0f }, 774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } - -/* PlayStation 2 Only presets */ - -#define FSOUND_PRESET_PS2_ROOM {1, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_STUDIO_A {2, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_STUDIO_B {3, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_STUDIO_C {4, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_HALL {5, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_SPACE {6, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_ECHO {7, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_DELAY {8, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FSOUND_PRESET_PS2_PIPE {9, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } - -/* [DEFINE_END] */ - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure defining the properties for a reverb source, related to a FSOUND channel. - For more indepth descriptions of the reverb properties under win32, please see the EAX3 - documentation at http://developer.creative.com/ under the 'downloads' section. - If they do not have the EAX3 documentation, then most information can be attained from - the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of - EAX2. - - Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. - Note that integer values that typically range from -10,000 to 1000 are represented in - decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. - PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). - Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then - the reverb should product a similar effect on either platform. - Linux and FMODCE do not support the reverb api. - - The numerical values listed below are the maximum, minimum and default values for each variable respectively. - - [SEE_ALSO] - FSOUND_Reverb_SetChannelProperties - FSOUND_Reverb_GetChannelProperties - FSOUND_REVERB_CHANNELFLAGS -] -*/ -typedef struct _FSOUND_REVERB_CHANNELPROPERTIES /* MIN MAX DEFAULT */ -{ - int Direct; /* -10000, 1000, 0, direct path level (at low and mid frequencies) (WIN32/XBOX) */ - int DirectHF; /* -10000, 0, 0, relative direct path level at high frequencies (WIN32/XBOX) */ - int Room; /* -10000, 1000, 0, room effect level (at low and mid frequencies) (WIN32/XBOX/PS2) */ - int RoomHF; /* -10000, 0, 0, relative room effect level at high frequencies (WIN32/XBOX) */ - int Obstruction; /* -10000, 0, 0, main obstruction control (attenuation at high frequencies) (WIN32/XBOX) */ - float ObstructionLFRatio; /* 0.0, 1.0, 0.0, obstruction low-frequency level re. main control (WIN32/XBOX) */ - int Occlusion; /* -10000, 0, 0, main occlusion control (attenuation at high frequencies) (WIN32/XBOX) */ - float OcclusionLFRatio; /* 0.0, 1.0, 0.25, occlusion low-frequency level re. main control (WIN32/XBOX) */ - float OcclusionRoomRatio; /* 0.0, 10.0, 1.5, relative occlusion control for room effect (WIN32) */ - float OcclusionDirectRatio; /* 0.0, 10.0, 1.0, relative occlusion control for direct path (WIN32) */ - int Exclusion; /* -10000, 0, 0, main exlusion control (attenuation at high frequencies) (WIN32) */ - float ExclusionLFRatio; /* 0.0, 1.0, 1.0, exclusion low-frequency level re. main control (WIN32) */ - int OutsideVolumeHF; /* -10000, 0, 0, outside sound cone level at high frequencies (WIN32) */ - float DopplerFactor; /* 0.0, 10.0, 0.0, like DS3D flDopplerFactor but per source (WIN32) */ - float RolloffFactor; /* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but per source (WIN32) */ - float RoomRolloffFactor; /* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but for room effect (WIN32/XBOX) */ - float AirAbsorptionFactor; /* 0.0, 10.0, 1.0, multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (WIN32) */ - int Flags; /* FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (WIN32) */ -} FSOUND_REVERB_CHANNELPROPERTIES; - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_REVERB_CHANNELFLAGS - - [DESCRIPTION] - Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure. - - [SEE_ALSO] - FSOUND_REVERB_CHANNELPROPERTIES -] -*/ -#define FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO 0x00000001 /* Automatic setting of 'Direct' due to distance from listener */ -#define FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO 0x00000002 /* Automatic setting of 'Room' due to distance from listener */ -#define FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO 0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */ -#define FSOUND_REVERB_CHANNELFLAGS_DEFAULT (FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO | \ - FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO| \ - FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO) -/* [DEFINE_END] */ - - -/* -[ENUM] -[ - [DESCRIPTION] - These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel. - - [SEE_ALSO] - FSOUND_FX_Enable - FSOUND_FX_Disable - FSOUND_FX_SetChorus - FSOUND_FX_SetCompressor - FSOUND_FX_SetDistortion - FSOUND_FX_SetEcho - FSOUND_FX_SetFlanger - FSOUND_FX_SetGargle - FSOUND_FX_SetI3DL2Reverb - FSOUND_FX_SetParamEQ - FSOUND_FX_SetWavesReverb -] -*/ -enum FSOUND_FX_MODES -{ - FSOUND_FX_CHORUS, - FSOUND_FX_COMPRESSOR, - FSOUND_FX_DISTORTION, - FSOUND_FX_ECHO, - FSOUND_FX_FLANGER, - FSOUND_FX_GARGLE, - FSOUND_FX_I3DL2REVERB, - FSOUND_FX_PARAMEQ, - FSOUND_FX_WAVES_REVERB, - - FSOUND_FX_MAX -}; - -/* -[ENUM] -[ - [DESCRIPTION] - These are speaker types defined for use with the FSOUND_SetSpeakerMode command. - Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only - interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo. - - Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure. - - [SEE_ALSO] - FSOUND_SetSpeakerMode - -] -*/ -enum FSOUND_SPEAKERMODES -{ - FSOUND_SPEAKERMODE_DOLBYDIGITAL, /* Dolby Digital Output (XBOX or PC only). */ - FSOUND_SPEAKERMODE_HEADPHONES, /* The speakers are headphones. */ - FSOUND_SPEAKERMODE_MONO, /* The speakers are monaural. */ - FSOUND_SPEAKERMODE_QUAD, /* The speakers are quadraphonic. */ - FSOUND_SPEAKERMODE_STEREO, /* The speakers are stereo (default value). */ - FSOUND_SPEAKERMODE_SURROUND, /* The speakers are surround sound. */ - FSOUND_SPEAKERMODE_DTS, /* DTS output (XBOX only). */ - FSOUND_SPEAKERMODE_PROLOGIC2, /* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 doesnt support interior panning, but supports 48 voices simultaneously. */ - FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR /* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 does support interior panning, but only supports 24 voices simultaneously. */ -}; - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_INIT_FLAGS - - [DESCRIPTION] - Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour. - - FSOUND_INIT_ENABLEOUTPUTFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects. - Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small. - This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works. - When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters. - - [SEE_ALSO] - FSOUND_Init -] -*/ -#define FSOUND_INIT_USEDEFAULTMIDISYNTH 0x0001 /* Causes MIDI playback to force software decoding. */ -#define FSOUND_INIT_GLOBALFOCUS 0x0002 /* For DirectSound output - sound is not muted when window is out of focus. */ -#define FSOUND_INIT_ENABLEOUTPUTFX 0x0004 /* For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! */ -#define FSOUND_INIT_ACCURATEVULEVELS 0x0008 /* This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit */ -#define FSOUND_INIT_PS2_DISABLECORE0REVERB 0x0010 /* PS2 only - Disable reverb on CORE 0 to regain SRAM */ -#define FSOUND_INIT_PS2_DISABLECORE1REVERB 0x0020 /* PS2 only - Disable reverb on CORE 1 to regain SRAM */ -#define FSOUND_INIT_PS2_SWAPDMACORES 0x0040 /* PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around */ -#define FSOUND_INIT_DONTLATENCYADJUST 0x0080 /* Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate */ -#define FSOUND_INIT_GC_INITLIBS 0x0100 /* Gamecube only - Initializes GC audio libraries */ -#define FSOUND_INIT_STREAM_FROM_MAIN_THREAD 0x0200 /* Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user */ -#define FSOUND_INIT_PS2_USEVOLUMERAMPING 0x0400 /* PS2 only - Turns on volume ramping system to remove hardware clicks. */ -/* [DEFINE_END] */ - - -/* -[ENUM] -[ - [DESCRIPTION] - Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream. - - [SEE_ALSO] - FSOUND_Stream_Net_GetStatus -] -*/ -enum FSOUND_STREAM_NET_STATUS -{ - FSOUND_STREAM_NET_NOTCONNECTED = 0, /* Stream hasn't connected yet */ - FSOUND_STREAM_NET_CONNECTING, /* Stream is connecting to remote host */ - FSOUND_STREAM_NET_BUFFERING, /* Stream is buffering data */ - FSOUND_STREAM_NET_READY, /* Stream is ready to play */ - FSOUND_STREAM_NET_ERROR /* Stream has suffered a fatal error */ -}; - - -/* -[ENUM] -[ - [DESCRIPTION] - Describes the type of a particular tag field. - - [SEE_ALSO] - FSOUND_Stream_GetNumTagFields - FSOUND_Stream_GetTagField - FSOUND_Stream_FindTagField -] -*/ -enum FSOUND_TAGFIELD_TYPE -{ - FSOUND_TAGFIELD_VORBISCOMMENT = 0, /* A vorbis comment */ - FSOUND_TAGFIELD_ID3V1, /* Part of an ID3v1 tag */ - FSOUND_TAGFIELD_ID3V2, /* An ID3v2 frame */ - FSOUND_TAGFIELD_SHOUTCAST, /* A SHOUTcast header line */ - FSOUND_TAGFIELD_ICECAST, /* An Icecast header line */ - FSOUND_TAGFIELD_ASF /* An Advanced Streaming Format header line */ -}; - - -/* -[DEFINE_START] -[ - [NAME] - FSOUND_STATUS_FLAGS - - [DESCRIPTION] - These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream. - - [SEE_ALSO] - FSOUND_Stream_Net_GetStatus -] -*/ -#define FSOUND_PROTOCOL_SHOUTCAST 0x00000001 -#define FSOUND_PROTOCOL_ICECAST 0x00000002 -#define FSOUND_PROTOCOL_HTTP 0x00000004 -#define FSOUND_FORMAT_MPEG 0x00010000 -#define FSOUND_FORMAT_OGGVORBIS 0x00020000 -/* [DEFINE_END] */ - - -/* ========================================================================================== */ -/* FUNCTION PROTOTYPES */ -/* ========================================================================================== */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* ================================== */ -/* Initialization / Global functions. */ -/* ================================== */ - -/* - PRE - FSOUND_Init functions. These can't be called after FSOUND_Init is - called (they will fail). They set up FMOD system functionality. -*/ - -DLL_API signed char F_API FSOUND_SetOutput(int outputtype); -DLL_API signed char F_API FSOUND_SetDriver(int driver); -DLL_API signed char F_API FSOUND_SetMixer(int mixer); -DLL_API signed char F_API FSOUND_SetBufferSize(int len_ms); -DLL_API signed char F_API FSOUND_SetHWND(void *hwnd); -DLL_API signed char F_API FSOUND_SetMinHardwareChannels(int min); -DLL_API signed char F_API FSOUND_SetMaxHardwareChannels(int max); -DLL_API signed char F_API FSOUND_SetMemorySystem(void *pool, - int poollen, - FSOUND_ALLOCCALLBACK useralloc, - FSOUND_REALLOCCALLBACK userrealloc, - FSOUND_FREECALLBACK userfree); -/* - Main initialization / closedown functions. - Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override - with MIDI playback. - : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible no matter - which window is in focus. (FSOUND_OUTPUT_DSOUND only) -*/ - -DLL_API signed char F_API FSOUND_Init(int mixrate, int maxsoftwarechannels, unsigned int flags); -DLL_API void F_API FSOUND_Close(); - -/* - Runtime system level functions -*/ - -DLL_API void F_API FSOUND_Update(); /* This is called to update 3d sound / non-realtime output */ - -DLL_API void F_API FSOUND_SetSpeakerMode(unsigned int speakermode); -DLL_API void F_API FSOUND_SetSFXMasterVolume(int volume); -DLL_API void F_API FSOUND_SetPanSeperation(float pansep); -DLL_API void F_API FSOUND_File_SetCallbacks(FSOUND_OPENCALLBACK useropen, - FSOUND_CLOSECALLBACK userclose, - FSOUND_READCALLBACK userread, - FSOUND_SEEKCALLBACK userseek, - FSOUND_TELLCALLBACK usertell); - -/* - System information functions. -*/ - -DLL_API int F_API FSOUND_GetError(); -DLL_API float F_API FSOUND_GetVersion(); -DLL_API int F_API FSOUND_GetOutput(); -DLL_API void * F_API FSOUND_GetOutputHandle(); -DLL_API int F_API FSOUND_GetDriver(); -DLL_API int F_API FSOUND_GetMixer(); -DLL_API int F_API FSOUND_GetNumDrivers(); -DLL_API const char * F_API FSOUND_GetDriverName(int id); -DLL_API signed char F_API FSOUND_GetDriverCaps(int id, unsigned int *caps); -DLL_API int F_API FSOUND_GetOutputRate(); -DLL_API int F_API FSOUND_GetMaxChannels(); -DLL_API int F_API FSOUND_GetMaxSamples(); -DLL_API int F_API FSOUND_GetSFXMasterVolume(); -DLL_API int F_API FSOUND_GetNumHardwareChannels(); -DLL_API int F_API FSOUND_GetChannelsPlaying(); -DLL_API float F_API FSOUND_GetCPUUsage(); -DLL_API void F_API FSOUND_GetMemoryStats(unsigned int *currentalloced, unsigned int *maxalloced); - -/* =================================== */ -/* Sample management / load functions. */ -/* =================================== */ - -/* - Sample creation and management functions - Note : Use FSOUND_LOADMEMORY flag with FSOUND_Sample_Load to load from memory. - Use FSOUND_LOADRAW flag with FSOUND_Sample_Load to treat as as raw pcm data. -*/ - -DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length); -DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Alloc(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); -DLL_API void F_API FSOUND_Sample_Free(FSOUND_SAMPLE *sptr); -DLL_API signed char F_API FSOUND_Sample_Upload(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); -DLL_API signed char F_API FSOUND_Sample_Lock(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); -DLL_API signed char F_API FSOUND_Sample_Unlock(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); - -/* - Sample control functions -*/ - -DLL_API signed char F_API FSOUND_Sample_SetMode(FSOUND_SAMPLE *sptr, unsigned int mode); -DLL_API signed char F_API FSOUND_Sample_SetLoopPoints(FSOUND_SAMPLE *sptr, int loopstart, int loopend); -DLL_API signed char F_API FSOUND_Sample_SetDefaults(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); -DLL_API signed char F_API FSOUND_Sample_SetMinMaxDistance(FSOUND_SAMPLE *sptr, float min, float max); -DLL_API signed char F_API FSOUND_Sample_SetMaxPlaybacks(FSOUND_SAMPLE *sptr, int max); - -/* - Sample information functions -*/ - -DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Get(int sampno); -DLL_API const char * F_API FSOUND_Sample_GetName(FSOUND_SAMPLE *sptr); -DLL_API unsigned int F_API FSOUND_Sample_GetLength(FSOUND_SAMPLE *sptr); -DLL_API signed char F_API FSOUND_Sample_GetLoopPoints(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); -DLL_API signed char F_API FSOUND_Sample_GetDefaults(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); -DLL_API unsigned int F_API FSOUND_Sample_GetMode(FSOUND_SAMPLE *sptr); - -/* ============================ */ -/* Channel control functions. */ -/* ============================ */ - -/* - Playing and stopping sounds. - Note : Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. - Use FSOUND_ALL as the 'channel' variable to control ALL channels with one function call! -*/ - -DLL_API int F_API FSOUND_PlaySound(int channel, FSOUND_SAMPLE *sptr); -DLL_API int F_API FSOUND_PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); -DLL_API signed char F_API FSOUND_StopSound(int channel); - -/* - Functions to control playback of a channel. - Note : FSOUND_ALL can be used on most of these functions as a channel value. -*/ - -DLL_API signed char F_API FSOUND_SetFrequency(int channel, int freq); -DLL_API signed char F_API FSOUND_SetVolume(int channel, int vol); -DLL_API signed char F_API FSOUND_SetVolumeAbsolute(int channel, int vol); -DLL_API signed char F_API FSOUND_SetPan(int channel, int pan); -DLL_API signed char F_API FSOUND_SetSurround(int channel, signed char surround); -DLL_API signed char F_API FSOUND_SetMute(int channel, signed char mute); -DLL_API signed char F_API FSOUND_SetPriority(int channel, int priority); -DLL_API signed char F_API FSOUND_SetReserved(int channel, signed char reserved); -DLL_API signed char F_API FSOUND_SetPaused(int channel, signed char paused); -DLL_API signed char F_API FSOUND_SetLoopMode(int channel, unsigned int loopmode); -DLL_API signed char F_API FSOUND_SetCurrentPosition(int channel, unsigned int offset); - -/* - Channel information functions. -*/ - -DLL_API signed char F_API FSOUND_IsPlaying(int channel); -DLL_API int F_API FSOUND_GetFrequency(int channel); -DLL_API int F_API FSOUND_GetVolume(int channel); -DLL_API int F_API FSOUND_GetPan(int channel); -DLL_API signed char F_API FSOUND_GetSurround(int channel); -DLL_API signed char F_API FSOUND_GetMute(int channel); -DLL_API int F_API FSOUND_GetPriority(int channel); -DLL_API signed char F_API FSOUND_GetReserved(int channel); -DLL_API signed char F_API FSOUND_GetPaused(int channel); -DLL_API unsigned int F_API FSOUND_GetLoopMode(int channel); -DLL_API unsigned int F_API FSOUND_GetCurrentPosition(int channel); -DLL_API FSOUND_SAMPLE * F_API FSOUND_GetCurrentSample(int channel); -DLL_API signed char F_API FSOUND_GetCurrentLevels(int channel, float *l, float *r); -DLL_API int F_API FSOUND_GetNumSubChannels(int channel); -DLL_API int F_API FSOUND_GetSubChannel(int channel, int subchannel); - - -/* =================== */ -/* FX functions. */ -/* =================== */ - -/* - Functions to control DX8 only effects processing. - - - FX enabled samples can only be played once at a time, not multiple times at once. - - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work. - - FSOUND_INIT_ENABLEOUTPUTFX can be used to apply hardware effect processing to the - global mixed output of FMOD's software channels. - - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters. - - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type, - it will return a unique handle for each FX. - - FSOUND_FX_Enable cannot be called if the sound is playing or locked. - - FSOUND_FX_Disable must be called to reset/clear the FX from a channel. -*/ - -DLL_API int F_API FSOUND_FX_Enable(int channel, unsigned int fx); /* See FSOUND_FX_MODES */ -DLL_API signed char F_API FSOUND_FX_Disable(int channel); - -DLL_API signed char F_API FSOUND_FX_SetChorus(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); -DLL_API signed char F_API FSOUND_FX_SetCompressor(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); -DLL_API signed char F_API FSOUND_FX_SetDistortion(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); -DLL_API signed char F_API FSOUND_FX_SetEcho(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); -DLL_API signed char F_API FSOUND_FX_SetFlanger(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); -DLL_API signed char F_API FSOUND_FX_SetGargle(int fxid, int RateHz, int WaveShape); -DLL_API signed char F_API FSOUND_FX_SetI3DL2Reverb(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); -DLL_API signed char F_API FSOUND_FX_SetParamEQ(int fxid, float Center, float Bandwidth, float Gain); -DLL_API signed char F_API FSOUND_FX_SetWavesReverb(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); - -/* =================== */ -/* 3D sound functions. */ -/* =================== */ - -DLL_API void F_API FSOUND_3D_SetDopplerFactor(float scale); -DLL_API void F_API FSOUND_3D_SetDistanceFactor(float scale); -DLL_API void F_API FSOUND_3D_SetRolloffFactor(float scale); -DLL_API signed char F_API FSOUND_3D_SetAttributes(int channel, const float *pos, const float *vel); -DLL_API signed char F_API FSOUND_3D_GetAttributes(int channel, float *pos, float *vel); - -DLL_API void F_API FSOUND_3D_Listener_SetCurrent(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ -DLL_API void F_API FSOUND_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz); -DLL_API void F_API FSOUND_3D_Listener_GetAttributes(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); - -/* ========================= */ -/* File Streaming functions. */ -/* ========================= */ - -/* - Note : Use FSOUND_LOADMEMORY flag with FSOUND_Stream_Open to stream from memory. - Use FSOUND_LOADRAW flag with FSOUND_Stream_Open to treat stream as raw pcm data. - Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms. - Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. -*/ - -DLL_API signed char F_API FSOUND_Stream_SetBufferSize(int ms); /* call this before opening streams, not after */ - -DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Open(const char *name_or_data, unsigned int mode, int offset, int length); -DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Create(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, int userdata); -DLL_API signed char F_API FSOUND_Stream_Close(FSOUND_STREAM *stream); - -DLL_API int F_API FSOUND_Stream_Play(int channel, FSOUND_STREAM *stream); -DLL_API int F_API FSOUND_Stream_PlayEx(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); -DLL_API signed char F_API FSOUND_Stream_Stop(FSOUND_STREAM *stream); - -DLL_API signed char F_API FSOUND_Stream_SetPosition(FSOUND_STREAM *stream, unsigned int position); -DLL_API unsigned int F_API FSOUND_Stream_GetPosition(FSOUND_STREAM *stream); -DLL_API signed char F_API FSOUND_Stream_SetTime(FSOUND_STREAM *stream, int ms); -DLL_API int F_API FSOUND_Stream_GetTime(FSOUND_STREAM *stream); -DLL_API int F_API FSOUND_Stream_GetLength(FSOUND_STREAM *stream); -DLL_API int F_API FSOUND_Stream_GetLengthMs(FSOUND_STREAM *stream); - -DLL_API signed char F_API FSOUND_Stream_SetMode(FSOUND_STREAM *stream, unsigned int mode); -DLL_API unsigned int F_API FSOUND_Stream_GetMode(FSOUND_STREAM *stream); -DLL_API signed char F_API FSOUND_Stream_SetLoopPoints(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); -DLL_API signed char F_API FSOUND_Stream_SetLoopCount(FSOUND_STREAM *stream, int count); -DLL_API int F_API FSOUND_Stream_GetOpenState(FSOUND_STREAM *stream); /* use with FSOUND_NONBLOCKING opened streams */ -DLL_API FSOUND_SAMPLE * F_API FSOUND_Stream_GetSample(FSOUND_STREAM *stream); -DLL_API FSOUND_DSPUNIT * F_API FSOUND_Stream_CreateDSP(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, int param); - -DLL_API signed char F_API FSOUND_Stream_SetEndCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); -DLL_API signed char F_API FSOUND_Stream_SetSyncCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); - -DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_AddSyncPoint(FSOUND_STREAM *stream, unsigned int pcmoffset, const char *name); -DLL_API signed char F_API FSOUND_Stream_DeleteSyncPoint(FSOUND_SYNCPOINT *point); -DLL_API int F_API FSOUND_Stream_GetNumSyncPoints(FSOUND_STREAM *stream); -DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_GetSyncPoint(FSOUND_STREAM *stream, int index); -DLL_API char * F_API FSOUND_Stream_GetSyncPointInfo(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); - -DLL_API signed char F_API FSOUND_Stream_SetSubStream(FSOUND_STREAM *stream, int index); /* For FMOD .FSB bank files. */ -DLL_API int F_API FSOUND_Stream_GetNumSubStreams(FSOUND_STREAM *stream); /* For FMOD .FSB bank files. */ -DLL_API signed char F_API FSOUND_Stream_SetSubStreamSentence(FSOUND_STREAM *stream, const int *sentencelist, int numitems); - -DLL_API signed char F_API FSOUND_Stream_GetNumTagFields(FSOUND_STREAM *stream, int *num); -DLL_API signed char F_API FSOUND_Stream_GetTagField(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); -DLL_API signed char F_API FSOUND_Stream_FindTagField(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); - -/* - Internet streaming functions -*/ - -DLL_API signed char F_API FSOUND_Stream_Net_SetProxy(const char *proxy); -DLL_API char * F_API FSOUND_Stream_Net_GetLastServerStatus(); -DLL_API signed char F_API FSOUND_Stream_Net_SetBufferProperties(int buffersize, int prebuffer_percent, int rebuffer_percent); -DLL_API signed char F_API FSOUND_Stream_Net_GetBufferProperties(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); -DLL_API signed char F_API FSOUND_Stream_Net_SetMetadataCallback(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, int userdata); -DLL_API signed char F_API FSOUND_Stream_Net_GetStatus(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); - -/* =================== */ -/* CD audio functions. */ -/* =================== */ - -/* - Note : 0 = default cdrom. Otherwise specify the drive letter, for example. 'D'. -*/ - -DLL_API signed char F_API FSOUND_CD_Play(char drive, int track); -DLL_API void F_API FSOUND_CD_SetPlayMode(char drive, signed char mode); -DLL_API signed char F_API FSOUND_CD_Stop(char drive); -DLL_API signed char F_API FSOUND_CD_SetPaused(char drive, signed char paused); -DLL_API signed char F_API FSOUND_CD_SetVolume(char drive, int volume); -DLL_API signed char F_API FSOUND_CD_SetTrackTime(char drive, unsigned int ms); -DLL_API signed char F_API FSOUND_CD_Eject(char drive); - -DLL_API signed char F_API FSOUND_CD_GetPaused(char drive); -DLL_API int F_API FSOUND_CD_GetTrack(char drive); -DLL_API int F_API FSOUND_CD_GetNumTracks(char drive); -DLL_API int F_API FSOUND_CD_GetVolume(char drive); -DLL_API int F_API FSOUND_CD_GetTrackLength(char drive, int track); -DLL_API int F_API FSOUND_CD_GetTrackTime(char drive); - -/* ============== */ -/* DSP functions. */ -/* ============== */ - -/* - DSP Unit control and information functions. - These functions allow you access to the mixed stream that FMOD uses to play back sound on. -*/ - -DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_Create(FSOUND_DSPCALLBACK callback, int priority, int param); -DLL_API void F_API FSOUND_DSP_Free(FSOUND_DSPUNIT *unit); -DLL_API void F_API FSOUND_DSP_SetPriority(FSOUND_DSPUNIT *unit, int priority); -DLL_API int F_API FSOUND_DSP_GetPriority(FSOUND_DSPUNIT *unit); -DLL_API void F_API FSOUND_DSP_SetActive(FSOUND_DSPUNIT *unit, signed char active); -DLL_API signed char F_API FSOUND_DSP_GetActive(FSOUND_DSPUNIT *unit); - -/* - Functions to get hold of FSOUND 'system DSP unit' handles. -*/ - -DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClearUnit(); -DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetSFXUnit(); -DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetMusicUnit(); -DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetFFTUnit(); -DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClipAndCopyUnit(); - -/* - Miscellaneous DSP functions - Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with - the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); - It is off by default to save cpu usage. -*/ - -DLL_API signed char F_API FSOUND_DSP_MixBuffers(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); -DLL_API void F_API FSOUND_DSP_ClearMixBuffer(); -DLL_API int F_API FSOUND_DSP_GetBufferLength(); /* Length of each DSP update */ -DLL_API int F_API FSOUND_DSP_GetBufferLengthTotal(); /* Total buffer length due to FSOUND_SetBufferSize */ -DLL_API float * F_API FSOUND_DSP_GetSpectrum(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ - -/* =================================================================================== */ -/* Reverb functions. (eax2/eax3 reverb) (ONLY SUPPORTED ON WIN32 W/ FSOUND_HW3D FLAG) */ -/* =================================================================================== */ - -/* - See top of file for definitions and information on the reverb parameters. -*/ - -DLL_API signed char F_API FSOUND_Reverb_SetProperties(const FSOUND_REVERB_PROPERTIES *prop); -DLL_API signed char F_API FSOUND_Reverb_GetProperties(FSOUND_REVERB_PROPERTIES *prop); -DLL_API signed char F_API FSOUND_Reverb_SetChannelProperties(int channel, const FSOUND_REVERB_CHANNELPROPERTIES *prop); -DLL_API signed char F_API FSOUND_Reverb_GetChannelProperties(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); - -/* ===================================================== */ -/* Recording functions (ONLY SUPPORTED IN WIN32, WINCE) */ -/* ===================================================== */ - -/* - Recording initialization functions -*/ - -DLL_API signed char F_API FSOUND_Record_SetDriver(int outputtype); -DLL_API int F_API FSOUND_Record_GetNumDrivers(); -DLL_API const char * F_API FSOUND_Record_GetDriverName(int id); -DLL_API int F_API FSOUND_Record_GetDriver(); - -/* - Recording functionality. Only one recording session will work at a time. -*/ - -DLL_API signed char F_API FSOUND_Record_StartSample(FSOUND_SAMPLE *sptr, signed char loop); -DLL_API signed char F_API FSOUND_Record_Stop(); -DLL_API int F_API FSOUND_Record_GetPosition(); - -/* ========================================================================================== */ -/* FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK) */ -/* ========================================================================================== */ - -/* - Song management / playback functions. -*/ - -DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSong(const char *name); -DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSongEx(const char *name_or_data, int offset, int length, unsigned int mode, const int *samplelist, int samplelistnum); -DLL_API int F_API FMUSIC_GetOpenState(FMUSIC_MODULE *mod); -DLL_API signed char F_API FMUSIC_FreeSong(FMUSIC_MODULE *mod); -DLL_API signed char F_API FMUSIC_PlaySong(FMUSIC_MODULE *mod); -DLL_API signed char F_API FMUSIC_StopSong(FMUSIC_MODULE *mod); -DLL_API void F_API FMUSIC_StopAllSongs(); - -DLL_API signed char F_API FMUSIC_SetZxxCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); -DLL_API signed char F_API FMUSIC_SetRowCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); -DLL_API signed char F_API FMUSIC_SetOrderCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); -DLL_API signed char F_API FMUSIC_SetInstCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); - -DLL_API signed char F_API FMUSIC_SetSample(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); -DLL_API signed char F_API FMUSIC_SetUserData(FMUSIC_MODULE *mod, unsigned int userdata); -DLL_API signed char F_API FMUSIC_OptimizeChannels(FMUSIC_MODULE *mod, int maxchannels, int minvolume); - -/* - Runtime song functions. -*/ - -DLL_API signed char F_API FMUSIC_SetReverb(signed char reverb); /* MIDI only */ -DLL_API signed char F_API FMUSIC_SetLooping(FMUSIC_MODULE *mod, signed char looping); -DLL_API signed char F_API FMUSIC_SetOrder(FMUSIC_MODULE *mod, int order); -DLL_API signed char F_API FMUSIC_SetPaused(FMUSIC_MODULE *mod, signed char pause); -DLL_API signed char F_API FMUSIC_SetMasterVolume(FMUSIC_MODULE *mod, int volume); -DLL_API signed char F_API FMUSIC_SetMasterSpeed(FMUSIC_MODULE *mode, float speed); -DLL_API signed char F_API FMUSIC_SetPanSeperation(FMUSIC_MODULE *mod, float pansep); - -/* - Static song information functions. -*/ - -DLL_API const char * F_API FMUSIC_GetName(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetType(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetNumOrders(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetNumPatterns(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetNumInstruments(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetNumSamples(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetNumChannels(FMUSIC_MODULE *mod); -DLL_API FSOUND_SAMPLE * F_API FMUSIC_GetSample(FMUSIC_MODULE *mod, int sampno); -DLL_API int F_API FMUSIC_GetPatternLength(FMUSIC_MODULE *mod, int orderno); - -/* - Runtime song information. -*/ - -DLL_API signed char F_API FMUSIC_IsFinished(FMUSIC_MODULE *mod); -DLL_API signed char F_API FMUSIC_IsPlaying(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetMasterVolume(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetGlobalVolume(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetOrder(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetPattern(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetSpeed(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetBPM(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetRow(FMUSIC_MODULE *mod); -DLL_API signed char F_API FMUSIC_GetPaused(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetTime(FMUSIC_MODULE *mod); -DLL_API int F_API FMUSIC_GetRealChannel(FMUSIC_MODULE *mod, int modchannel); -DLL_API unsigned int F_API FMUSIC_GetUserData(FMUSIC_MODULE *mod); - -#ifdef __cplusplus -} -#endif - -#endif +/* ========================================================================================== */ +/* FMOD Main header file. Copyright (c), Firelight Technologies Pty, Ltd 1999-2003. */ +/* ========================================================================================== */ + +#ifndef _FMOD_H_ +#define _FMOD_H_ + +/* ========================================================================================== */ +/* DEFINITIONS */ +/* ========================================================================================== */ + +#if (!defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(_WIN32_WCE) && !defined(_XBOX)) || (defined(__GNUC__) && defined(WIN32)) + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __stdcall + #define __stdcall + #endif +#endif + +#if defined(_WIN32_WCE) + #define F_API _cdecl + #define F_CALLBACKAPI _cdecl +#else + #define F_API __stdcall + #define F_CALLBACKAPI __stdcall +#endif + +#ifdef DLL_EXPORTS + #define DLL_API __declspec(dllexport) +#else + #if defined(__LCC__) || defined(__MINGW32__) || defined(__CYGWIN32__) + #define DLL_API F_API + #else + #define DLL_API + #endif /* __LCC__ || __MINGW32__ || __CYGWIN32__ */ +#endif /* DLL_EXPORTS */ + +#define FMOD_VERSION 3.71f + +/* + FMOD defined types +*/ +typedef struct FSOUND_SAMPLE FSOUND_SAMPLE; +typedef struct FSOUND_STREAM FSOUND_STREAM; +typedef struct FSOUND_DSPUNIT FSOUND_DSPUNIT; +typedef struct FSOUND_SYNCPOINT FSOUND_SYNCPOINT; +typedef struct FMUSIC_MODULE FMUSIC_MODULE; + +/* + Callback types +*/ +typedef void * (F_CALLBACKAPI *FSOUND_DSPCALLBACK) (void *originalbuffer, void *newbuffer, int length, int param); +typedef signed char (F_CALLBACKAPI *FSOUND_STREAMCALLBACK) (FSOUND_STREAM *stream, void *buff, int len, int param); +typedef void (F_CALLBACKAPI *FMUSIC_CALLBACK) (FMUSIC_MODULE *mod, unsigned char param); + +typedef unsigned int(F_CALLBACKAPI *FSOUND_OPENCALLBACK) (const char *name); +typedef void (F_CALLBACKAPI *FSOUND_CLOSECALLBACK) (unsigned int handle); +typedef int (F_CALLBACKAPI *FSOUND_READCALLBACK) (void *buffer, int size, unsigned int handle); +typedef int (F_CALLBACKAPI *FSOUND_SEEKCALLBACK) (unsigned int handle, int pos, signed char mode); +typedef int (F_CALLBACKAPI *FSOUND_TELLCALLBACK) (unsigned int handle); + +typedef void * (F_CALLBACKAPI *FSOUND_ALLOCCALLBACK) (unsigned int size); +typedef void * (F_CALLBACKAPI *FSOUND_REALLOCCALLBACK) (void *ptr, unsigned int size); +typedef void (F_CALLBACKAPI *FSOUND_FREECALLBACK) (void *ptr); + +typedef signed char (F_CALLBACKAPI *FSOUND_METADATACALLBACK)(char *name, char *value, int userdata); + + +/* +[ENUM] +[ + [DESCRIPTION] + On failure of commands in FMOD, use FSOUND_GetError to attain what happened. + + [SEE_ALSO] + FSOUND_GetError +] +*/ +enum FMOD_ERRORS +{ + FMOD_ERR_NONE, /* No errors */ + FMOD_ERR_BUSY, /* Cannot call this command after FSOUND_Init. Call FSOUND_Close first. */ + FMOD_ERR_UNINITIALIZED, /* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */ + FMOD_ERR_INIT, /* Error initializing output device. */ + FMOD_ERR_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ + FMOD_ERR_PLAY, /* Playing the sound failed. */ + FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */ + FMOD_ERR_COOPERATIVELEVEL, /* Error setting cooperative level for hardware. */ + FMOD_ERR_CREATEBUFFER, /* Error creating hardware sound buffer. */ + FMOD_ERR_FILE_NOTFOUND, /* File not found */ + FMOD_ERR_FILE_FORMAT, /* Unknown file format */ + FMOD_ERR_FILE_BAD, /* Error loading file */ + FMOD_ERR_MEMORY, /* Not enough memory or resources */ + FMOD_ERR_VERSION, /* The version number of this file format is not supported */ + FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function */ + FMOD_ERR_NO_EAX, /* Tried to use an EAX command on a non EAX enabled channel or output. */ + FMOD_ERR_CHANNEL_ALLOC, /* Failed to allocate a new channel */ + FMOD_ERR_RECORD, /* Recording is not supported on this machine */ + FMOD_ERR_MEDIAPLAYER, /* Windows Media Player not installed so cannot play wma or use internet streaming. */ + FMOD_ERR_CDDEVICE /* An error occured trying to open the specified CD device */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These output types are used with FSOUND_SetOutput, to choose which output driver to use. + + FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver + does not support DirectX 6 Voice Manager Extensions. + + FSOUND_OUTPUT_WINMM is recommended for NT and CE. + + [SEE_ALSO] + FSOUND_SetOutput + FSOUND_GetOutput +] +*/ +enum FSOUND_OUTPUTTYPES +{ + FSOUND_OUTPUT_NOSOUND, /* NoSound driver, all calls to this succeed but do nothing. */ + FSOUND_OUTPUT_WINMM, /* Windows Multimedia driver. */ + FSOUND_OUTPUT_DSOUND, /* DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. */ + FSOUND_OUTPUT_A3D, /* A3D driver. */ + + FSOUND_OUTPUT_OSS, /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */ + FSOUND_OUTPUT_ESD, /* Linux/Unix ESD (Enlightment Sound Daemon) driver. */ + FSOUND_OUTPUT_ALSA, /* Linux Alsa driver. */ + + FSOUND_OUTPUT_ASIO, /* Low latency ASIO driver */ + FSOUND_OUTPUT_XBOX, /* Xbox driver */ + FSOUND_OUTPUT_PS2, /* PlayStation 2 driver */ + FSOUND_OUTPUT_MAC, /* Mac SoundManager driver */ + FSOUND_OUTPUT_GC, /* Gamecube driver */ + + FSOUND_OUTPUT_NOSOUND_NONREALTIME /* This is the same as nosound, but the sound generation is driven by FSOUND_Update */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act + upon for other reasons using FSOUND_GetMixer. + It is not nescessary to set the mixer. FMOD will autodetect the best mixer for you. + + [SEE_ALSO] + FSOUND_SetMixer + FSOUND_GetMixer +] +*/ +enum FSOUND_MIXERTYPES +{ + FSOUND_MIXER_AUTODETECT, /* CE/PS2/GC Only - Non interpolating/low quality mixer. */ + FSOUND_MIXER_BLENDMODE, /* Removed / obsolete. */ + FSOUND_MIXER_MMXP5, /* Removed / obsolete. */ + FSOUND_MIXER_MMXP6, /* Removed / obsolete. */ + + FSOUND_MIXER_QUALITY_AUTODETECT,/* All platforms - Autodetect the fastest quality mixer based on your cpu. */ + FSOUND_MIXER_QUALITY_FPU, /* Win32/Linux only - Interpolating/volume ramping FPU mixer. */ + FSOUND_MIXER_QUALITY_MMXP5, /* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. */ + FSOUND_MIXER_QUALITY_MMXP6, /* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */ + + FSOUND_MIXER_MONO, /* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/ + FSOUND_MIXER_QUALITY_MONO, /* CE/PS2/GC only - MONO Interpolating mixer. For speed */ + + FSOUND_MIXER_MAX +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the type of song being played. + + [SEE_ALSO] + FMUSIC_GetType +] +*/ +enum FMUSIC_TYPES +{ + FMUSIC_TYPE_NONE, + FMUSIC_TYPE_MOD, /* Protracker / Fasttracker */ + FMUSIC_TYPE_S3M, /* ScreamTracker 3 */ + FMUSIC_TYPE_XM, /* FastTracker 2 */ + FMUSIC_TYPE_IT, /* Impulse Tracker. */ + FMUSIC_TYPE_MIDI, /* MIDI file */ + FMUSIC_TYPE_FSB /* FMOD Sample Bank file */ +}; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_DSP_PRIORITIES + + [DESCRIPTION] + These default priorities are used by FMOD internal system DSP units. They describe the + position of the DSP chain, and the order of how audio processing is executed. + You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP + unit), disable or even change the priority of a DSP unit. + + [SEE_ALSO] + FSOUND_DSP_Create + FSOUND_DSP_SetPriority + FSOUND_DSP_GetSpectrum +] +*/ +#define FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT 0 /* DSP CLEAR unit - done first */ +#define FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT 100 /* DSP SFX unit - done second */ +#define FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT 200 /* DSP MUSIC unit - done third */ +#define FSOUND_DSP_DEFAULTPRIORITY_USER 300 /* User priority, use this as reference for your own DSP units */ +#define FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT 900 /* This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units */ +#define FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT 1000 /* DSP CLIP AND COPY unit - last */ +/* [DEFINE_END] */ + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_CAPS + + [DESCRIPTION] + Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated + has the settings you are after. The enumerated driver depends on the output mode, see + FSOUND_OUTPUTTYPES + + [SEE_ALSO] + FSOUND_GetDriverCaps + FSOUND_OUTPUTTYPES +] +*/ +#define FSOUND_CAPS_HARDWARE 0x1 /* This driver supports hardware accelerated 3d sound. */ +#define FSOUND_CAPS_EAX2 0x2 /* This driver supports EAX 2 reverb */ +#define FSOUND_CAPS_EAX3 0x10 /* This driver supports EAX 3 reverb */ +/* [DEFINE_END] */ + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_MODES + + [DESCRIPTION] + Sample description bitfields, OR them together for loading and describing samples. + NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then + trying to override the pre-defined format with a new set of format flags will not work. For + example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just + ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags + you can specify that will really alter the behaviour of how it is loaded, are the following. + --------- + Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI + Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D + Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO + Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX + PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP + --------- + See flag descriptions for what these do. +] +*/ +#define FSOUND_LOOP_OFF 0x00000001 /* For non looping samples. */ +#define FSOUND_LOOP_NORMAL 0x00000002 /* For forward looping samples. */ +#define FSOUND_LOOP_BIDI 0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */ +#define FSOUND_8BITS 0x00000008 /* For 8 bit samples. */ +#define FSOUND_16BITS 0x00000010 /* For 16 bit samples. */ +#define FSOUND_MONO 0x00000020 /* For mono samples. */ +#define FSOUND_STEREO 0x00000040 /* For stereo samples. */ +#define FSOUND_UNSIGNED 0x00000080 /* For user created source data containing unsigned samples. */ +#define FSOUND_SIGNED 0x00000100 /* For user created source data containing signed data. */ +#define FSOUND_DELTA 0x00000200 /* For user created source data stored as delta values. */ +#define FSOUND_IT214 0x00000400 /* For user created source data stored using IT214 compression. */ +#define FSOUND_IT215 0x00000800 /* For user created source data stored using IT215 compression. */ +#define FSOUND_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */ +#define FSOUND_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */ +#define FSOUND_STREAMABLE 0x00004000 /* For a streamimg sound where you feed the data to it. */ +#define FSOUND_LOADMEMORY 0x00008000 /* "name" will be interpreted as a pointer to data for streaming and samples. */ +#define FSOUND_LOADRAW 0x00010000 /* Will ignore file format and treat as raw pcm. */ +#define FSOUND_MPEGACCURATE 0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */ +#define FSOUND_FORCEMONO 0x00040000 /* For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams */ +#define FSOUND_HW2D 0x00080000 /* 2D hardware sounds. allows hardware specific effects */ +#define FSOUND_ENABLEFX 0x00100000 /* Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency */ +#define FSOUND_MPEGHALFRATE 0x00200000 /* For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution */ +#define FSOUND_IMAADPCM 0x00400000 /* Contents are stored compressed as IMA ADPCM */ +#define FSOUND_VAG 0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */ +#define FSOUND_NONBLOCKING 0x01000000 /* For FSOUND_Stream_Open/FMUSIC_LoadSong - Causes stream or music to open in the background and not block the foreground app. See FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState to determine when it IS ready. */ +#define FSOUND_GCADPCM 0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */ +#define FSOUND_MULTICHANNEL 0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */ +#define FSOUND_USECORE0 0x08000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 00-23 */ +#define FSOUND_USECORE1 0x10000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 24-47 */ +#define FSOUND_LOADMEMORYIOP 0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */ +#define FSOUND_STREAM_NET 0x80000000 /* Specifies an internet stream */ + +#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO) +/* [DEFINE_END] */ + + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_CDPLAYMODES + + [DESCRIPTION] + Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode + + [SEE_ALSO] + FSOUND_CD_SetPlayMode + FSOUND_CD_Play +] +*/ +#define FSOUND_CD_PLAYCONTINUOUS 0 /* Starts from the current track and plays to end of CD. */ +#define FSOUND_CD_PLAYONCE 1 /* Plays the specified track then stops. */ +#define FSOUND_CD_PLAYLOOPED 2 /* Plays the specified track looped, forever until stopped manually. */ +#define FSOUND_CD_PLAYRANDOM 3 /* Plays tracks in random order */ +/* [DEFINE_END] */ + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_MISC_VALUES + + [DESCRIPTION] + Miscellaneous values for FMOD functions. + + [SEE_ALSO] + FSOUND_PlaySound + FSOUND_PlaySoundEx + FSOUND_Sample_Alloc + FSOUND_Sample_Load + FSOUND_SetPan +] +*/ +#define FSOUND_FREE -1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */ +#define FSOUND_UNMANAGED -2 /* value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. */ +#define FSOUND_ALL -3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */ +#define FSOUND_STEREOPAN -1 /* value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. */ +#define FSOUND_SYSTEMCHANNEL -1000 /* special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output channel */ +#define FSOUND_SYSTEMSAMPLE -1000 /* special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample */ + +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a reverb environment. + For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of EAX2. + Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then the reverb should product a similar effect on either platform. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [SEE_ALSO] + FSOUND_Reverb_SetProperties + FSOUND_Reverb_GetProperties + FSOUND_REVERB_PRESETS + FSOUND_REVERB_FLAGS +] +*/ +typedef struct _FSOUND_REVERB_PROPERTIES /* MIN MAX DEFAULT DESCRIPTION */ +{ + unsigned int Environment; /* 0 , 25 , 0 , sets all listener properties (WIN32/PS2 only) */ + float EnvSize; /* 1.0 , 100.0 , 7.5 , environment size in meters (WIN32 only) */ + float EnvDiffusion; /* 0.0 , 1.0 , 1.0 , environment diffusion (WIN32/XBOX) */ + int Room; /* -10000, 0 , -1000 , room effect level (at mid frequencies) (WIN32/XBOX/PS2) */ + int RoomHF; /* -10000, 0 , -100 , relative room effect level at high frequencies (WIN32/XBOX) */ + int RoomLF; /* -10000, 0 , 0 , relative room effect level at low frequencies (WIN32 only) */ + float DecayTime; /* 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (WIN32/XBOX) */ + float DecayHFRatio; /* 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (WIN32/XBOX) */ + float DecayLFRatio; /* 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (WIN32 only) */ + int Reflections; /* -10000, 1000 , -2602 , early reflections level relative to room effect (WIN32/XBOX) */ + float ReflectionsDelay; /* 0.0 , 0.3 , 0.007 , initial reflection delay time (WIN32/XBOX) */ + float ReflectionsPan[3]; /* , , [0,0,0], early reflections panning vector (WIN32 only) */ + int Reverb; /* -10000, 2000 , 200 , late reverberation level relative to room effect (WIN32/XBOX) */ + float ReverbDelay; /* 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (WIN32/XBOX) */ + float ReverbPan[3]; /* , , [0,0,0], late reverberation panning vector (WIN32 only) */ + float EchoTime; /* .075 , 0.25 , 0.25 , echo time (WIN32/PS2 only. PS2 = Delay time for ECHO/DELAY modes only) */ + float EchoDepth; /* 0.0 , 1.0 , 0.0 , echo depth (WIN32/PS2 only. PS2 = Feedback level for ECHO mode only) */ + float ModulationTime; /* 0.04 , 4.0 , 0.25 , modulation time (WIN32 only) */ + float ModulationDepth; /* 0.0 , 1.0 , 0.0 , modulation depth (WIN32 only) */ + float AirAbsorptionHF; /* -100 , 0.0 , -5.0 , change in level per meter at high frequencies (WIN32 only) */ + float HFReference; /* 1000.0, 20000 , 5000.0 , reference high frequency (hz) (WIN32/XBOX) */ + float LFReference; /* 20.0 , 1000.0, 250.0 , reference low frequency (hz) (WIN32 only) */ + float RoomRolloffFactor; /* 0.0 , 10.0 , 0.0 , like FSOUND_3D_SetRolloffFactor but for room effect (WIN32/XBOX) */ + float Diffusion; /* 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (XBOX only) */ + float Density; /* 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (XBOX only) */ + unsigned int Flags; /* FSOUND_REVERB_FLAGS - modifies the behavior of above properties (WIN32/PS2 only) */ +} FSOUND_REVERB_PROPERTIES; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure. + + [SEE_ALSO] + FSOUND_REVERB_PROPERTIES +] +*/ +#define FSOUND_REVERB_FLAGS_DECAYTIMESCALE 0x00000001 /* 'EnvSize' affects reverberation decay time */ +#define FSOUND_REVERB_FLAGS_REFLECTIONSSCALE 0x00000002 /* 'EnvSize' affects reflection level */ +#define FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 /* 'EnvSize' affects initial reflection delay time */ +#define FSOUND_REVERB_FLAGS_REVERBSCALE 0x00000008 /* 'EnvSize' affects reflections level */ +#define FSOUND_REVERB_FLAGS_REVERBDELAYSCALE 0x00000010 /* 'EnvSize' affects late reverberation delay time */ +#define FSOUND_REVERB_FLAGS_DECAYHFLIMIT 0x00000020 /* AirAbsorptionHF affects DecayHFRatio */ +#define FSOUND_REVERB_FLAGS_ECHOTIMESCALE 0x00000040 /* 'EnvSize' affects echo time */ +#define FSOUND_REVERB_FLAGS_MODULATIONTIMESCALE 0x00000080 /* 'EnvSize' affects modulation time */ +#define FSOUND_REVERB_FLAGS_CORE0 0x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */ +#define FSOUND_REVERB_FLAGS_CORE1 0x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */ +#define FSOUND_REVERB_FLAGS_DEFAULT (FSOUND_REVERB_FLAGS_DECAYTIMESCALE | \ + FSOUND_REVERB_FLAGS_REFLECTIONSSCALE | \ + FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE | \ + FSOUND_REVERB_FLAGS_REVERBSCALE | \ + FSOUND_REVERB_FLAGS_REVERBDELAYSCALE | \ + FSOUND_REVERB_FLAGS_DECAYHFLIMIT | \ + FSOUND_REVERB_FLAGS_CORE0 | \ + FSOUND_REVERB_FLAGS_CORE1 ) +/* [DEFINE_END] */ + + + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS, created by Creative Labs + These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically. + ie + FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC; + + [SEE_ALSO] + FSOUND_Reverb_SetProperties +] +*/ +/* Env Size Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel RefPan Revb RevDel ReverbPan EchoTm EchDp ModTm ModDp AirAbs HFRef LFRef RRlOff Diffus Densty FLAGS */ +#define FSOUND_PRESET_OFF {0, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x33f } +#define FSOUND_PRESET_GENERIC {0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_PADDEDCELL {1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, { 0.0f,0.0f,0.0f }, 207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_ROOM {2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, { 0.0f,0.0f,0.0f }, 53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_BATHROOM {3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, { 0.0f,0.0f,0.0f }, 1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f } +#define FSOUND_PRESET_LIVINGROOM {4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_STONEROOM {5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, { 0.0f,0.0f,0.0f }, 83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_AUDITORIUM {6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, { 0.0f,0.0f,0.0f }, -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CONCERTHALL {7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, { 0.0f,0.0f,0.0f }, -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CAVE {8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, { 0.0f,0.0f,0.0f }, -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_ARENA {9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, { 0.0f,0.0f,0.0f }, 16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_HANGAR {10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, { 0.0f,0.0f,0.0f }, 198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CARPETTEDHALLWAY {11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_HALLWAY {12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, { 0.0f,0.0f,0.0f }, 441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_STONECORRIDOR {13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, { 0.0f,0.0f,0.0f }, 395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_ALLEY {14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, { 0.0f,0.0f,0.0f }, -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_FOREST {15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, { 0.0f,0.0f,0.0f }, -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CITY {16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_MOUNTAINS {17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_QUARRY {18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f }, 500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_PLAIN {19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_PARKINGLOT {20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_SEWERPIPE {21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, { 0.0f,0.0f,0.0f }, 1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f } +#define FSOUND_PRESET_UNDERWATER {22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, { 0.0f,0.0f,0.0f }, 1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } + +/* Non I3DL2 presets */ + +#define FSOUND_PRESET_DRUGGED {23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, { 0.0f,0.0f,0.0f }, 985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_DIZZY {24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, { 0.0f,0.0f,0.0f }, -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_PSYCHOTIC {25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, { 0.0f,0.0f,0.0f }, 774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } + +/* PlayStation 2 Only presets */ + +#define FSOUND_PRESET_PS2_ROOM {1, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_STUDIO_A {2, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_STUDIO_B {3, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_STUDIO_C {4, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_HALL {5, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_SPACE {6, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_ECHO {7, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_DELAY {8, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_PIPE {9, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } + +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FSOUND channel. + For more indepth descriptions of the reverb properties under win32, please see the EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then + the reverb should product a similar effect on either platform. + Linux and FMODCE do not support the reverb api. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [SEE_ALSO] + FSOUND_Reverb_SetChannelProperties + FSOUND_Reverb_GetChannelProperties + FSOUND_REVERB_CHANNELFLAGS +] +*/ +typedef struct _FSOUND_REVERB_CHANNELPROPERTIES /* MIN MAX DEFAULT */ +{ + int Direct; /* -10000, 1000, 0, direct path level (at low and mid frequencies) (WIN32/XBOX) */ + int DirectHF; /* -10000, 0, 0, relative direct path level at high frequencies (WIN32/XBOX) */ + int Room; /* -10000, 1000, 0, room effect level (at low and mid frequencies) (WIN32/XBOX/PS2) */ + int RoomHF; /* -10000, 0, 0, relative room effect level at high frequencies (WIN32/XBOX) */ + int Obstruction; /* -10000, 0, 0, main obstruction control (attenuation at high frequencies) (WIN32/XBOX) */ + float ObstructionLFRatio; /* 0.0, 1.0, 0.0, obstruction low-frequency level re. main control (WIN32/XBOX) */ + int Occlusion; /* -10000, 0, 0, main occlusion control (attenuation at high frequencies) (WIN32/XBOX) */ + float OcclusionLFRatio; /* 0.0, 1.0, 0.25, occlusion low-frequency level re. main control (WIN32/XBOX) */ + float OcclusionRoomRatio; /* 0.0, 10.0, 1.5, relative occlusion control for room effect (WIN32) */ + float OcclusionDirectRatio; /* 0.0, 10.0, 1.0, relative occlusion control for direct path (WIN32) */ + int Exclusion; /* -10000, 0, 0, main exlusion control (attenuation at high frequencies) (WIN32) */ + float ExclusionLFRatio; /* 0.0, 1.0, 1.0, exclusion low-frequency level re. main control (WIN32) */ + int OutsideVolumeHF; /* -10000, 0, 0, outside sound cone level at high frequencies (WIN32) */ + float DopplerFactor; /* 0.0, 10.0, 0.0, like DS3D flDopplerFactor but per source (WIN32) */ + float RolloffFactor; /* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but per source (WIN32) */ + float RoomRolloffFactor; /* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but for room effect (WIN32/XBOX) */ + float AirAbsorptionFactor; /* 0.0, 10.0, 1.0, multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (WIN32) */ + int Flags; /* FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (WIN32) */ +} FSOUND_REVERB_CHANNELPROPERTIES; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure. + + [SEE_ALSO] + FSOUND_REVERB_CHANNELPROPERTIES +] +*/ +#define FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO 0x00000001 /* Automatic setting of 'Direct' due to distance from listener */ +#define FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO 0x00000002 /* Automatic setting of 'Room' due to distance from listener */ +#define FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO 0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */ +#define FSOUND_REVERB_CHANNELFLAGS_DEFAULT (FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO | \ + FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO| \ + FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO) +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel. + + [SEE_ALSO] + FSOUND_FX_Enable + FSOUND_FX_Disable + FSOUND_FX_SetChorus + FSOUND_FX_SetCompressor + FSOUND_FX_SetDistortion + FSOUND_FX_SetEcho + FSOUND_FX_SetFlanger + FSOUND_FX_SetGargle + FSOUND_FX_SetI3DL2Reverb + FSOUND_FX_SetParamEQ + FSOUND_FX_SetWavesReverb +] +*/ +enum FSOUND_FX_MODES +{ + FSOUND_FX_CHORUS, + FSOUND_FX_COMPRESSOR, + FSOUND_FX_DISTORTION, + FSOUND_FX_ECHO, + FSOUND_FX_FLANGER, + FSOUND_FX_GARGLE, + FSOUND_FX_I3DL2REVERB, + FSOUND_FX_PARAMEQ, + FSOUND_FX_WAVES_REVERB, + + FSOUND_FX_MAX +}; + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the FSOUND_SetSpeakerMode command. + Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only + interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo. + + Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure. + + [SEE_ALSO] + FSOUND_SetSpeakerMode + +] +*/ +enum FSOUND_SPEAKERMODES +{ + FSOUND_SPEAKERMODE_DOLBYDIGITAL, /* Dolby Digital Output (XBOX or PC only). */ + FSOUND_SPEAKERMODE_HEADPHONES, /* The speakers are headphones. */ + FSOUND_SPEAKERMODE_MONO, /* The speakers are monaural. */ + FSOUND_SPEAKERMODE_QUAD, /* The speakers are quadraphonic. */ + FSOUND_SPEAKERMODE_STEREO, /* The speakers are stereo (default value). */ + FSOUND_SPEAKERMODE_SURROUND, /* The speakers are surround sound. */ + FSOUND_SPEAKERMODE_DTS, /* DTS output (XBOX only). */ + FSOUND_SPEAKERMODE_PROLOGIC2, /* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 doesnt support interior panning, but supports 48 voices simultaneously. */ + FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR /* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 does support interior panning, but only supports 24 voices simultaneously. */ +}; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_INIT_FLAGS + + [DESCRIPTION] + Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour. + + FSOUND_INIT_ENABLEOUTPUTFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects. + Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small. + This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works. + When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters. + + [SEE_ALSO] + FSOUND_Init +] +*/ +#define FSOUND_INIT_USEDEFAULTMIDISYNTH 0x0001 /* Causes MIDI playback to force software decoding. */ +#define FSOUND_INIT_GLOBALFOCUS 0x0002 /* For DirectSound output - sound is not muted when window is out of focus. */ +#define FSOUND_INIT_ENABLEOUTPUTFX 0x0004 /* For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! */ +#define FSOUND_INIT_ACCURATEVULEVELS 0x0008 /* This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit */ +#define FSOUND_INIT_PS2_DISABLECORE0REVERB 0x0010 /* PS2 only - Disable reverb on CORE 0 to regain SRAM */ +#define FSOUND_INIT_PS2_DISABLECORE1REVERB 0x0020 /* PS2 only - Disable reverb on CORE 1 to regain SRAM */ +#define FSOUND_INIT_PS2_SWAPDMACORES 0x0040 /* PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around */ +#define FSOUND_INIT_DONTLATENCYADJUST 0x0080 /* Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate */ +#define FSOUND_INIT_GC_INITLIBS 0x0100 /* Gamecube only - Initializes GC audio libraries */ +#define FSOUND_INIT_STREAM_FROM_MAIN_THREAD 0x0200 /* Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user */ +#define FSOUND_INIT_PS2_USEVOLUMERAMPING 0x0400 /* PS2 only - Turns on volume ramping system to remove hardware clicks. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream. + + [SEE_ALSO] + FSOUND_Stream_Net_GetStatus +] +*/ +enum FSOUND_STREAM_NET_STATUS +{ + FSOUND_STREAM_NET_NOTCONNECTED = 0, /* Stream hasn't connected yet */ + FSOUND_STREAM_NET_CONNECTING, /* Stream is connecting to remote host */ + FSOUND_STREAM_NET_BUFFERING, /* Stream is buffering data */ + FSOUND_STREAM_NET_READY, /* Stream is ready to play */ + FSOUND_STREAM_NET_ERROR /* Stream has suffered a fatal error */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + Describes the type of a particular tag field. + + [SEE_ALSO] + FSOUND_Stream_GetNumTagFields + FSOUND_Stream_GetTagField + FSOUND_Stream_FindTagField +] +*/ +enum FSOUND_TAGFIELD_TYPE +{ + FSOUND_TAGFIELD_VORBISCOMMENT = 0, /* A vorbis comment */ + FSOUND_TAGFIELD_ID3V1, /* Part of an ID3v1 tag */ + FSOUND_TAGFIELD_ID3V2, /* An ID3v2 frame */ + FSOUND_TAGFIELD_SHOUTCAST, /* A SHOUTcast header line */ + FSOUND_TAGFIELD_ICECAST, /* An Icecast header line */ + FSOUND_TAGFIELD_ASF /* An Advanced Streaming Format header line */ +}; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_STATUS_FLAGS + + [DESCRIPTION] + These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream. + + [SEE_ALSO] + FSOUND_Stream_Net_GetStatus +] +*/ +#define FSOUND_PROTOCOL_SHOUTCAST 0x00000001 +#define FSOUND_PROTOCOL_ICECAST 0x00000002 +#define FSOUND_PROTOCOL_HTTP 0x00000004 +#define FSOUND_FORMAT_MPEG 0x00010000 +#define FSOUND_FORMAT_OGGVORBIS 0x00020000 +/* [DEFINE_END] */ + + +/* ========================================================================================== */ +/* FUNCTION PROTOTYPES */ +/* ========================================================================================== */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================================== */ +/* Initialization / Global functions. */ +/* ================================== */ + +/* + PRE - FSOUND_Init functions. These can't be called after FSOUND_Init is + called (they will fail). They set up FMOD system functionality. +*/ + +DLL_API signed char F_API FSOUND_SetOutput(int outputtype); +DLL_API signed char F_API FSOUND_SetDriver(int driver); +DLL_API signed char F_API FSOUND_SetMixer(int mixer); +DLL_API signed char F_API FSOUND_SetBufferSize(int len_ms); +DLL_API signed char F_API FSOUND_SetHWND(void *hwnd); +DLL_API signed char F_API FSOUND_SetMinHardwareChannels(int min); +DLL_API signed char F_API FSOUND_SetMaxHardwareChannels(int max); +DLL_API signed char F_API FSOUND_SetMemorySystem(void *pool, + int poollen, + FSOUND_ALLOCCALLBACK useralloc, + FSOUND_REALLOCCALLBACK userrealloc, + FSOUND_FREECALLBACK userfree); +/* + Main initialization / closedown functions. + Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override + with MIDI playback. + : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible no matter + which window is in focus. (FSOUND_OUTPUT_DSOUND only) +*/ + +DLL_API signed char F_API FSOUND_Init(int mixrate, int maxsoftwarechannels, unsigned int flags); +DLL_API void F_API FSOUND_Close(); + +/* + Runtime system level functions +*/ + +DLL_API void F_API FSOUND_Update(); /* This is called to update 3d sound / non-realtime output */ + +DLL_API void F_API FSOUND_SetSpeakerMode(unsigned int speakermode); +DLL_API void F_API FSOUND_SetSFXMasterVolume(int volume); +DLL_API void F_API FSOUND_SetPanSeperation(float pansep); +DLL_API void F_API FSOUND_File_SetCallbacks(FSOUND_OPENCALLBACK useropen, + FSOUND_CLOSECALLBACK userclose, + FSOUND_READCALLBACK userread, + FSOUND_SEEKCALLBACK userseek, + FSOUND_TELLCALLBACK usertell); + +/* + System information functions. +*/ + +DLL_API int F_API FSOUND_GetError(); +DLL_API float F_API FSOUND_GetVersion(); +DLL_API int F_API FSOUND_GetOutput(); +DLL_API void * F_API FSOUND_GetOutputHandle(); +DLL_API int F_API FSOUND_GetDriver(); +DLL_API int F_API FSOUND_GetMixer(); +DLL_API int F_API FSOUND_GetNumDrivers(); +DLL_API const char * F_API FSOUND_GetDriverName(int id); +DLL_API signed char F_API FSOUND_GetDriverCaps(int id, unsigned int *caps); +DLL_API int F_API FSOUND_GetOutputRate(); +DLL_API int F_API FSOUND_GetMaxChannels(); +DLL_API int F_API FSOUND_GetMaxSamples(); +DLL_API int F_API FSOUND_GetSFXMasterVolume(); +DLL_API int F_API FSOUND_GetNumHardwareChannels(); +DLL_API int F_API FSOUND_GetChannelsPlaying(); +DLL_API float F_API FSOUND_GetCPUUsage(); +DLL_API void F_API FSOUND_GetMemoryStats(unsigned int *currentalloced, unsigned int *maxalloced); + +/* =================================== */ +/* Sample management / load functions. */ +/* =================================== */ + +/* + Sample creation and management functions + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Sample_Load to load from memory. + Use FSOUND_LOADRAW flag with FSOUND_Sample_Load to treat as as raw pcm data. +*/ + +DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length); +DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Alloc(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); +DLL_API void F_API FSOUND_Sample_Free(FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FSOUND_Sample_Upload(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); +DLL_API signed char F_API FSOUND_Sample_Lock(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +DLL_API signed char F_API FSOUND_Sample_Unlock(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + +/* + Sample control functions +*/ + +DLL_API signed char F_API FSOUND_Sample_SetMode(FSOUND_SAMPLE *sptr, unsigned int mode); +DLL_API signed char F_API FSOUND_Sample_SetLoopPoints(FSOUND_SAMPLE *sptr, int loopstart, int loopend); +DLL_API signed char F_API FSOUND_Sample_SetDefaults(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); +DLL_API signed char F_API FSOUND_Sample_SetMinMaxDistance(FSOUND_SAMPLE *sptr, float min, float max); +DLL_API signed char F_API FSOUND_Sample_SetMaxPlaybacks(FSOUND_SAMPLE *sptr, int max); + +/* + Sample information functions +*/ + +DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Get(int sampno); +DLL_API const char * F_API FSOUND_Sample_GetName(FSOUND_SAMPLE *sptr); +DLL_API unsigned int F_API FSOUND_Sample_GetLength(FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FSOUND_Sample_GetLoopPoints(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); +DLL_API signed char F_API FSOUND_Sample_GetDefaults(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); +DLL_API unsigned int F_API FSOUND_Sample_GetMode(FSOUND_SAMPLE *sptr); + +/* ============================ */ +/* Channel control functions. */ +/* ============================ */ + +/* + Playing and stopping sounds. + Note : Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. + Use FSOUND_ALL as the 'channel' variable to control ALL channels with one function call! +*/ + +DLL_API int F_API FSOUND_PlaySound(int channel, FSOUND_SAMPLE *sptr); +DLL_API int F_API FSOUND_PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); +DLL_API signed char F_API FSOUND_StopSound(int channel); + +/* + Functions to control playback of a channel. + Note : FSOUND_ALL can be used on most of these functions as a channel value. +*/ + +DLL_API signed char F_API FSOUND_SetFrequency(int channel, int freq); +DLL_API signed char F_API FSOUND_SetVolume(int channel, int vol); +DLL_API signed char F_API FSOUND_SetVolumeAbsolute(int channel, int vol); +DLL_API signed char F_API FSOUND_SetPan(int channel, int pan); +DLL_API signed char F_API FSOUND_SetSurround(int channel, signed char surround); +DLL_API signed char F_API FSOUND_SetMute(int channel, signed char mute); +DLL_API signed char F_API FSOUND_SetPriority(int channel, int priority); +DLL_API signed char F_API FSOUND_SetReserved(int channel, signed char reserved); +DLL_API signed char F_API FSOUND_SetPaused(int channel, signed char paused); +DLL_API signed char F_API FSOUND_SetLoopMode(int channel, unsigned int loopmode); +DLL_API signed char F_API FSOUND_SetCurrentPosition(int channel, unsigned int offset); + +/* + Channel information functions. +*/ + +DLL_API signed char F_API FSOUND_IsPlaying(int channel); +DLL_API int F_API FSOUND_GetFrequency(int channel); +DLL_API int F_API FSOUND_GetVolume(int channel); +DLL_API int F_API FSOUND_GetPan(int channel); +DLL_API signed char F_API FSOUND_GetSurround(int channel); +DLL_API signed char F_API FSOUND_GetMute(int channel); +DLL_API int F_API FSOUND_GetPriority(int channel); +DLL_API signed char F_API FSOUND_GetReserved(int channel); +DLL_API signed char F_API FSOUND_GetPaused(int channel); +DLL_API unsigned int F_API FSOUND_GetLoopMode(int channel); +DLL_API unsigned int F_API FSOUND_GetCurrentPosition(int channel); +DLL_API FSOUND_SAMPLE * F_API FSOUND_GetCurrentSample(int channel); +DLL_API signed char F_API FSOUND_GetCurrentLevels(int channel, float *l, float *r); +DLL_API int F_API FSOUND_GetNumSubChannels(int channel); +DLL_API int F_API FSOUND_GetSubChannel(int channel, int subchannel); + + +/* =================== */ +/* FX functions. */ +/* =================== */ + +/* + Functions to control DX8 only effects processing. + + - FX enabled samples can only be played once at a time, not multiple times at once. + - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work. + - FSOUND_INIT_ENABLEOUTPUTFX can be used to apply hardware effect processing to the + global mixed output of FMOD's software channels. + - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters. + - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type, + it will return a unique handle for each FX. + - FSOUND_FX_Enable cannot be called if the sound is playing or locked. + - FSOUND_FX_Disable must be called to reset/clear the FX from a channel. +*/ + +DLL_API int F_API FSOUND_FX_Enable(int channel, unsigned int fx); /* See FSOUND_FX_MODES */ +DLL_API signed char F_API FSOUND_FX_Disable(int channel); + +DLL_API signed char F_API FSOUND_FX_SetChorus(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); +DLL_API signed char F_API FSOUND_FX_SetCompressor(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); +DLL_API signed char F_API FSOUND_FX_SetDistortion(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); +DLL_API signed char F_API FSOUND_FX_SetEcho(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); +DLL_API signed char F_API FSOUND_FX_SetFlanger(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); +DLL_API signed char F_API FSOUND_FX_SetGargle(int fxid, int RateHz, int WaveShape); +DLL_API signed char F_API FSOUND_FX_SetI3DL2Reverb(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); +DLL_API signed char F_API FSOUND_FX_SetParamEQ(int fxid, float Center, float Bandwidth, float Gain); +DLL_API signed char F_API FSOUND_FX_SetWavesReverb(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); + +/* =================== */ +/* 3D sound functions. */ +/* =================== */ + +DLL_API void F_API FSOUND_3D_SetDopplerFactor(float scale); +DLL_API void F_API FSOUND_3D_SetDistanceFactor(float scale); +DLL_API void F_API FSOUND_3D_SetRolloffFactor(float scale); +DLL_API signed char F_API FSOUND_3D_SetAttributes(int channel, const float *pos, const float *vel); +DLL_API signed char F_API FSOUND_3D_GetAttributes(int channel, float *pos, float *vel); + +DLL_API void F_API FSOUND_3D_Listener_SetCurrent(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ +DLL_API void F_API FSOUND_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz); +DLL_API void F_API FSOUND_3D_Listener_GetAttributes(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); + +/* ========================= */ +/* File Streaming functions. */ +/* ========================= */ + +/* + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Stream_Open to stream from memory. + Use FSOUND_LOADRAW flag with FSOUND_Stream_Open to treat stream as raw pcm data. + Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms. + Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. +*/ + +DLL_API signed char F_API FSOUND_Stream_SetBufferSize(int ms); /* call this before opening streams, not after */ + +DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Open(const char *name_or_data, unsigned int mode, int offset, int length); +DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Create(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, int userdata); +DLL_API signed char F_API FSOUND_Stream_Close(FSOUND_STREAM *stream); + +DLL_API int F_API FSOUND_Stream_Play(int channel, FSOUND_STREAM *stream); +DLL_API int F_API FSOUND_Stream_PlayEx(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); +DLL_API signed char F_API FSOUND_Stream_Stop(FSOUND_STREAM *stream); + +DLL_API signed char F_API FSOUND_Stream_SetPosition(FSOUND_STREAM *stream, unsigned int position); +DLL_API unsigned int F_API FSOUND_Stream_GetPosition(FSOUND_STREAM *stream); +DLL_API signed char F_API FSOUND_Stream_SetTime(FSOUND_STREAM *stream, int ms); +DLL_API int F_API FSOUND_Stream_GetTime(FSOUND_STREAM *stream); +DLL_API int F_API FSOUND_Stream_GetLength(FSOUND_STREAM *stream); +DLL_API int F_API FSOUND_Stream_GetLengthMs(FSOUND_STREAM *stream); + +DLL_API signed char F_API FSOUND_Stream_SetMode(FSOUND_STREAM *stream, unsigned int mode); +DLL_API unsigned int F_API FSOUND_Stream_GetMode(FSOUND_STREAM *stream); +DLL_API signed char F_API FSOUND_Stream_SetLoopPoints(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); +DLL_API signed char F_API FSOUND_Stream_SetLoopCount(FSOUND_STREAM *stream, int count); +DLL_API int F_API FSOUND_Stream_GetOpenState(FSOUND_STREAM *stream); /* use with FSOUND_NONBLOCKING opened streams */ +DLL_API FSOUND_SAMPLE * F_API FSOUND_Stream_GetSample(FSOUND_STREAM *stream); +DLL_API FSOUND_DSPUNIT * F_API FSOUND_Stream_CreateDSP(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, int param); + +DLL_API signed char F_API FSOUND_Stream_SetEndCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); +DLL_API signed char F_API FSOUND_Stream_SetSyncCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); + +DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_AddSyncPoint(FSOUND_STREAM *stream, unsigned int pcmoffset, const char *name); +DLL_API signed char F_API FSOUND_Stream_DeleteSyncPoint(FSOUND_SYNCPOINT *point); +DLL_API int F_API FSOUND_Stream_GetNumSyncPoints(FSOUND_STREAM *stream); +DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_GetSyncPoint(FSOUND_STREAM *stream, int index); +DLL_API char * F_API FSOUND_Stream_GetSyncPointInfo(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); + +DLL_API signed char F_API FSOUND_Stream_SetSubStream(FSOUND_STREAM *stream, int index); /* For FMOD .FSB bank files. */ +DLL_API int F_API FSOUND_Stream_GetNumSubStreams(FSOUND_STREAM *stream); /* For FMOD .FSB bank files. */ +DLL_API signed char F_API FSOUND_Stream_SetSubStreamSentence(FSOUND_STREAM *stream, const int *sentencelist, int numitems); + +DLL_API signed char F_API FSOUND_Stream_GetNumTagFields(FSOUND_STREAM *stream, int *num); +DLL_API signed char F_API FSOUND_Stream_GetTagField(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); +DLL_API signed char F_API FSOUND_Stream_FindTagField(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); + +/* + Internet streaming functions +*/ + +DLL_API signed char F_API FSOUND_Stream_Net_SetProxy(const char *proxy); +DLL_API char * F_API FSOUND_Stream_Net_GetLastServerStatus(); +DLL_API signed char F_API FSOUND_Stream_Net_SetBufferProperties(int buffersize, int prebuffer_percent, int rebuffer_percent); +DLL_API signed char F_API FSOUND_Stream_Net_GetBufferProperties(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); +DLL_API signed char F_API FSOUND_Stream_Net_SetMetadataCallback(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, int userdata); +DLL_API signed char F_API FSOUND_Stream_Net_GetStatus(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); + +/* =================== */ +/* CD audio functions. */ +/* =================== */ + +/* + Note : 0 = default cdrom. Otherwise specify the drive letter, for example. 'D'. +*/ + +DLL_API signed char F_API FSOUND_CD_Play(char drive, int track); +DLL_API void F_API FSOUND_CD_SetPlayMode(char drive, signed char mode); +DLL_API signed char F_API FSOUND_CD_Stop(char drive); +DLL_API signed char F_API FSOUND_CD_SetPaused(char drive, signed char paused); +DLL_API signed char F_API FSOUND_CD_SetVolume(char drive, int volume); +DLL_API signed char F_API FSOUND_CD_SetTrackTime(char drive, unsigned int ms); +DLL_API signed char F_API FSOUND_CD_Eject(char drive); + +DLL_API signed char F_API FSOUND_CD_GetPaused(char drive); +DLL_API int F_API FSOUND_CD_GetTrack(char drive); +DLL_API int F_API FSOUND_CD_GetNumTracks(char drive); +DLL_API int F_API FSOUND_CD_GetVolume(char drive); +DLL_API int F_API FSOUND_CD_GetTrackLength(char drive, int track); +DLL_API int F_API FSOUND_CD_GetTrackTime(char drive); + +/* ============== */ +/* DSP functions. */ +/* ============== */ + +/* + DSP Unit control and information functions. + These functions allow you access to the mixed stream that FMOD uses to play back sound on. +*/ + +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_Create(FSOUND_DSPCALLBACK callback, int priority, int param); +DLL_API void F_API FSOUND_DSP_Free(FSOUND_DSPUNIT *unit); +DLL_API void F_API FSOUND_DSP_SetPriority(FSOUND_DSPUNIT *unit, int priority); +DLL_API int F_API FSOUND_DSP_GetPriority(FSOUND_DSPUNIT *unit); +DLL_API void F_API FSOUND_DSP_SetActive(FSOUND_DSPUNIT *unit, signed char active); +DLL_API signed char F_API FSOUND_DSP_GetActive(FSOUND_DSPUNIT *unit); + +/* + Functions to get hold of FSOUND 'system DSP unit' handles. +*/ + +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClearUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetSFXUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetMusicUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetFFTUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClipAndCopyUnit(); + +/* + Miscellaneous DSP functions + Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with + the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); + It is off by default to save cpu usage. +*/ + +DLL_API signed char F_API FSOUND_DSP_MixBuffers(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); +DLL_API void F_API FSOUND_DSP_ClearMixBuffer(); +DLL_API int F_API FSOUND_DSP_GetBufferLength(); /* Length of each DSP update */ +DLL_API int F_API FSOUND_DSP_GetBufferLengthTotal(); /* Total buffer length due to FSOUND_SetBufferSize */ +DLL_API float * F_API FSOUND_DSP_GetSpectrum(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ + +/* =================================================================================== */ +/* Reverb functions. (eax2/eax3 reverb) (ONLY SUPPORTED ON WIN32 W/ FSOUND_HW3D FLAG) */ +/* =================================================================================== */ + +/* + See top of file for definitions and information on the reverb parameters. +*/ + +DLL_API signed char F_API FSOUND_Reverb_SetProperties(const FSOUND_REVERB_PROPERTIES *prop); +DLL_API signed char F_API FSOUND_Reverb_GetProperties(FSOUND_REVERB_PROPERTIES *prop); +DLL_API signed char F_API FSOUND_Reverb_SetChannelProperties(int channel, const FSOUND_REVERB_CHANNELPROPERTIES *prop); +DLL_API signed char F_API FSOUND_Reverb_GetChannelProperties(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); + +/* ===================================================== */ +/* Recording functions (ONLY SUPPORTED IN WIN32, WINCE) */ +/* ===================================================== */ + +/* + Recording initialization functions +*/ + +DLL_API signed char F_API FSOUND_Record_SetDriver(int outputtype); +DLL_API int F_API FSOUND_Record_GetNumDrivers(); +DLL_API const char * F_API FSOUND_Record_GetDriverName(int id); +DLL_API int F_API FSOUND_Record_GetDriver(); + +/* + Recording functionality. Only one recording session will work at a time. +*/ + +DLL_API signed char F_API FSOUND_Record_StartSample(FSOUND_SAMPLE *sptr, signed char loop); +DLL_API signed char F_API FSOUND_Record_Stop(); +DLL_API int F_API FSOUND_Record_GetPosition(); + +/* ========================================================================================== */ +/* FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK) */ +/* ========================================================================================== */ + +/* + Song management / playback functions. +*/ + +DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSong(const char *name); +DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSongEx(const char *name_or_data, int offset, int length, unsigned int mode, const int *samplelist, int samplelistnum); +DLL_API int F_API FMUSIC_GetOpenState(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_FreeSong(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_PlaySong(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_StopSong(FMUSIC_MODULE *mod); +DLL_API void F_API FMUSIC_StopAllSongs(); + +DLL_API signed char F_API FMUSIC_SetZxxCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); +DLL_API signed char F_API FMUSIC_SetRowCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); +DLL_API signed char F_API FMUSIC_SetOrderCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); +DLL_API signed char F_API FMUSIC_SetInstCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); + +DLL_API signed char F_API FMUSIC_SetSample(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FMUSIC_SetUserData(FMUSIC_MODULE *mod, unsigned int userdata); +DLL_API signed char F_API FMUSIC_OptimizeChannels(FMUSIC_MODULE *mod, int maxchannels, int minvolume); + +/* + Runtime song functions. +*/ + +DLL_API signed char F_API FMUSIC_SetReverb(signed char reverb); /* MIDI only */ +DLL_API signed char F_API FMUSIC_SetLooping(FMUSIC_MODULE *mod, signed char looping); +DLL_API signed char F_API FMUSIC_SetOrder(FMUSIC_MODULE *mod, int order); +DLL_API signed char F_API FMUSIC_SetPaused(FMUSIC_MODULE *mod, signed char pause); +DLL_API signed char F_API FMUSIC_SetMasterVolume(FMUSIC_MODULE *mod, int volume); +DLL_API signed char F_API FMUSIC_SetMasterSpeed(FMUSIC_MODULE *mode, float speed); +DLL_API signed char F_API FMUSIC_SetPanSeperation(FMUSIC_MODULE *mod, float pansep); + +/* + Static song information functions. +*/ + +DLL_API const char * F_API FMUSIC_GetName(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetType(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumOrders(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumPatterns(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumInstruments(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumSamples(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumChannels(FMUSIC_MODULE *mod); +DLL_API FSOUND_SAMPLE * F_API FMUSIC_GetSample(FMUSIC_MODULE *mod, int sampno); +DLL_API int F_API FMUSIC_GetPatternLength(FMUSIC_MODULE *mod, int orderno); + +/* + Runtime song information. +*/ + +DLL_API signed char F_API FMUSIC_IsFinished(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_IsPlaying(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetMasterVolume(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetGlobalVolume(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetOrder(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetPattern(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetSpeed(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetBPM(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetRow(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_GetPaused(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetTime(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetRealChannel(FMUSIC_MODULE *mod, int modchannel); +DLL_API unsigned int F_API FMUSIC_GetUserData(FMUSIC_MODULE *mod); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/main/source/includes/fmod/inc/fmod_errors.h b/main/source/includes/fmod/inc/fmod_errors.h index b28b9c4f..9004ec16 100644 --- a/main/source/includes/fmod/inc/fmod_errors.h +++ b/main/source/includes/fmod/inc/fmod_errors.h @@ -1,32 +1,32 @@ -#ifndef _FMOD_ERRORS_H -#define _FMOD_ERRORS_H - -static char *FMOD_ErrorString(int errcode) -{ - switch (errcode) - { - case FMOD_ERR_NONE: return "No errors"; - case FMOD_ERR_BUSY: return "Cannot call this command after FSOUND_Init. Call FSOUND_Close first."; - case FMOD_ERR_UNINITIALIZED: return "This command failed because FSOUND_Init was not called"; - case FMOD_ERR_PLAY: return "Playing the sound failed."; - case FMOD_ERR_INIT: return "Error initializing output device."; - case FMOD_ERR_ALLOCATED: return "The output device is already in use and cannot be reused."; - case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the features needed for this soundsystem (16bit stereo output)"; - case FMOD_ERR_COOPERATIVELEVEL: return "Error setting cooperative level for hardware."; - case FMOD_ERR_CREATEBUFFER: return "Error creating hardware sound buffer."; - case FMOD_ERR_FILE_NOTFOUND: return "File not found"; - case FMOD_ERR_FILE_FORMAT: return "Unknown file format"; - case FMOD_ERR_FILE_BAD: return "Error loading file"; - case FMOD_ERR_MEMORY: return "Not enough memory "; - case FMOD_ERR_VERSION: return "The version number of this file format is not supported"; - case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function"; - case FMOD_ERR_NO_EAX: return "Tried to use an EAX command on a non EAX enabled channel or output."; - case FMOD_ERR_CHANNEL_ALLOC: return "Failed to allocate a new channel"; - case FMOD_ERR_RECORD: return "Recording not supported on this device"; - case FMOD_ERR_MEDIAPLAYER: return "Required Mediaplayer codec is not installed"; - - default : return "Unknown error"; - }; -} - -#endif +#ifndef _FMOD_ERRORS_H +#define _FMOD_ERRORS_H + +static char *FMOD_ErrorString(int errcode) +{ + switch (errcode) + { + case FMOD_ERR_NONE: return "No errors"; + case FMOD_ERR_BUSY: return "Cannot call this command after FSOUND_Init. Call FSOUND_Close first."; + case FMOD_ERR_UNINITIALIZED: return "This command failed because FSOUND_Init was not called"; + case FMOD_ERR_PLAY: return "Playing the sound failed."; + case FMOD_ERR_INIT: return "Error initializing output device."; + case FMOD_ERR_ALLOCATED: return "The output device is already in use and cannot be reused."; + case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the features needed for this soundsystem (16bit stereo output)"; + case FMOD_ERR_COOPERATIVELEVEL: return "Error setting cooperative level for hardware."; + case FMOD_ERR_CREATEBUFFER: return "Error creating hardware sound buffer."; + case FMOD_ERR_FILE_NOTFOUND: return "File not found"; + case FMOD_ERR_FILE_FORMAT: return "Unknown file format"; + case FMOD_ERR_FILE_BAD: return "Error loading file"; + case FMOD_ERR_MEMORY: return "Not enough memory "; + case FMOD_ERR_VERSION: return "The version number of this file format is not supported"; + case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function"; + case FMOD_ERR_NO_EAX: return "Tried to use an EAX command on a non EAX enabled channel or output."; + case FMOD_ERR_CHANNEL_ALLOC: return "Failed to allocate a new channel"; + case FMOD_ERR_RECORD: return "Recording not supported on this device"; + case FMOD_ERR_MEDIAPLAYER: return "Required Mediaplayer codec is not installed"; + + default : return "Unknown error"; + }; +} + +#endif diff --git a/main/source/includes/fmod/inc/fmoddyn.h b/main/source/includes/fmod/inc/fmoddyn.h index 0ce5f68d..b2be93dc 100644 --- a/main/source/includes/fmod/inc/fmoddyn.h +++ b/main/source/includes/fmod/inc/fmoddyn.h @@ -1,527 +1,527 @@ -/* ========================================================================================== */ -/* FMOD Dynamic DLL loading header. Copyright (c), Firelight Technologies Pty, Ltd 1999-2003. */ -/* ========================================================================================== */ - -#ifndef _FMODDYN_H_ -#define _FMODDYN_H_ - -#ifdef WIN32 - #include -#else - #include - #include -#endif -#include - -#include "fmod.h" - -typedef struct -{ - void *module; - - signed char (F_API *FSOUND_SetOutput)(int outputtype); - signed char (F_API *FSOUND_SetDriver)(int driver); - signed char (F_API *FSOUND_SetMixer)(int mixer); - signed char (F_API *FSOUND_SetBufferSize)(int len_ms); - signed char (F_API *FSOUND_SetHWND)(void *hwnd); - signed char (F_API *FSOUND_SetMinHardwareChannels)(int min); - signed char (F_API *FSOUND_SetMaxHardwareChannels)(int max); - signed char (F_API *FSOUND_SetMemorySystem)(void *pool, int poollen, FSOUND_ALLOCCALLBACK useralloc, FSOUND_REALLOCCALLBACK userrealloc, FSOUND_FREECALLBACK userfree); - signed char (F_API *FSOUND_Init)(int mixrate, int maxsoftwarechannels, unsigned int flags); - void (F_API *FSOUND_Close)(); - void (F_API *FSOUND_SetSpeakerMode)(unsigned int speakermode); - void (F_API *FSOUND_SetSFXMasterVolume)(int volume); - void (F_API *FSOUND_SetPanSeperation)(float pansep); - void (F_API *FSOUND_File_SetCallbacks)(FSOUND_OPENCALLBACK useropen, FSOUND_CLOSECALLBACK userclose, FSOUND_READCALLBACK userread, FSOUND_SEEKCALLBACK userseek, FSOUND_TELLCALLBACK usertell); - int (F_API *FSOUND_GetError)(); - float (F_API *FSOUND_GetVersion)(); - int (F_API *FSOUND_GetOutput)(); - void * (F_API *FSOUND_GetOutputHandle)(); - int (F_API *FSOUND_GetDriver)(); - int (F_API *FSOUND_GetMixer)(); - int (F_API *FSOUND_GetNumDrivers)(); - signed char * (F_API *FSOUND_GetDriverName)(int id); - signed char (F_API *FSOUND_GetDriverCaps)(int id, unsigned int *caps); - int (F_API *FSOUND_GetOutputRate)(); - int (F_API *FSOUND_GetMaxChannels)(); - int (F_API *FSOUND_GetMaxSamples)(); - int (F_API *FSOUND_GetSFXMasterVolume)(); - int (F_API *FSOUND_GetNumHardwareChannels)(); - int (F_API *FSOUND_GetChannelsPlaying)(); - float (F_API *FSOUND_GetCPUUsage)(); - void (F_API *FSOUND_GetMemoryStats)(unsigned int *currentalloced, unsigned int *maxalloced); - FSOUND_SAMPLE * (F_API *FSOUND_Sample_Load)(int index, const char *name_or_data, unsigned int mode, int offset, int length); - FSOUND_SAMPLE * (F_API *FSOUND_Sample_Alloc)(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); - void (F_API *FSOUND_Sample_Free)(FSOUND_SAMPLE *sptr); - signed char (F_API *FSOUND_Sample_Upload)(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); - signed char (F_API *FSOUND_Sample_Lock)(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); - signed char (F_API *FSOUND_Sample_Unlock)(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); - signed char (F_API *FSOUND_Sample_SetMode)(FSOUND_SAMPLE *sptr, unsigned int mode); - signed char (F_API *FSOUND_Sample_SetLoopPoints)(FSOUND_SAMPLE *sptr, int loopstart, int loopend); - signed char (F_API *FSOUND_Sample_SetDefaults)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); - signed char (F_API *FSOUND_Sample_SetMinMaxDistance)(FSOUND_SAMPLE *sptr, float min, float max); - signed char (F_API *FSOUND_Sample_SetMaxPlaybacks)(FSOUND_SAMPLE *sptr, int max); - FSOUND_SAMPLE * (F_API *FSOUND_Sample_Get)(int sampno); - char * (F_API *FSOUND_Sample_GetName)(FSOUND_SAMPLE *sptr); - unsigned int (F_API *FSOUND_Sample_GetLength)(FSOUND_SAMPLE *sptr); - signed char (F_API *FSOUND_Sample_GetLoopPoints)(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); - signed char (F_API *FSOUND_Sample_GetDefaults)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); - unsigned int (F_API *FSOUND_Sample_GetMode)(FSOUND_SAMPLE *sptr); - int (F_API *FSOUND_PlaySound)(int channel, FSOUND_SAMPLE *sptr); - int (F_API *FSOUND_PlaySoundEx)(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); - signed char (F_API *FSOUND_StopSound)(int channel); - signed char (F_API *FSOUND_SetFrequency)(int channel, int freq); - signed char (F_API *FSOUND_SetVolume)(int channel, int vol); - signed char (F_API *FSOUND_SetVolumeAbsolute)(int channel, int vol); - signed char (F_API *FSOUND_SetPan)(int channel, int pan); - signed char (F_API *FSOUND_SetSurround)(int channel, signed char surround); - signed char (F_API *FSOUND_SetMute)(int channel, signed char mute); - signed char (F_API *FSOUND_SetPriority)(int channel, int priority); - signed char (F_API *FSOUND_SetReserved)(int channel, signed char reserved); - signed char (F_API *FSOUND_SetPaused)(int channel, signed char paused); - signed char (F_API *FSOUND_SetLoopMode)(int channel, unsigned int loopmode); - signed char (F_API *FSOUND_SetCurrentPosition)(int channel, unsigned int offset); - signed char (F_API *FSOUND_IsPlaying)(int channel); - int (F_API *FSOUND_GetFrequency)(int channel); - int (F_API *FSOUND_GetVolume)(int channel); - int (F_API *FSOUND_GetPan)(int channel); - signed char (F_API *FSOUND_GetSurround)(int channel); - signed char (F_API *FSOUND_GetMute)(int channel); - int (F_API *FSOUND_GetPriority)(int channel); - signed char (F_API *FSOUND_GetReserved)(int channel); - signed char (F_API *FSOUND_GetPaused)(int channel); - unsigned int (F_API *FSOUND_GetLoopMode)(int channel); - unsigned int (F_API *FSOUND_GetCurrentPosition)(int channel); - FSOUND_SAMPLE * (F_API *FSOUND_GetCurrentSample)(int channel); - signed char (F_API *FSOUND_GetCurrentLevels)(int channel, float *l, float *r); - int (F_API *FSOUND_FX_Enable)(int channel, unsigned int fx); /* See FSOUND_FX_MODES */ - signed char (F_API *FSOUND_FX_Disable)(int channel); - signed char (F_API *FSOUND_FX_SetChorus)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); - signed char (F_API *FSOUND_FX_SetCompressor)(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); - signed char (F_API *FSOUND_FX_SetDistortion)(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); - signed char (F_API *FSOUND_FX_SetEcho)(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); - signed char (F_API *FSOUND_FX_SetFlanger)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); - signed char (F_API *FSOUND_FX_SetGargle)(int fxid, int RateHz, int WaveShape); - signed char (F_API *FSOUND_FX_SetI3DL2Reverb)(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); - signed char (F_API *FSOUND_FX_SetParamEQ)(int fxid, float Center, float Bandwidth, float Gain); - signed char (F_API *FSOUND_FX_SetWavesReverb)(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); - void (F_API *FSOUND_Update)(); /* you must call this once a frame */ - void (F_API *FSOUND_3D_SetDopplerFactor)(float scale); - void (F_API *FSOUND_3D_SetDistanceFactor)(float scale); - void (F_API *FSOUND_3D_SetRolloffFactor)(float scale); - signed char (F_API *FSOUND_3D_SetAttributes)(int channel, float *pos, float *vel); - signed char (F_API *FSOUND_3D_GetAttributes)(int channel, float *pos, float *vel); - void (F_API *FSOUND_3D_Listener_SetCurrent)(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ - void (F_API *FSOUND_3D_Listener_SetAttributes)(float *pos, float *vel, float fx, float fy, float fz, float tx, float ty, float tz); - void (F_API *FSOUND_3D_Listener_GetAttributes)(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); - signed char (F_API *FSOUND_Stream_SetBufferSize)(int ms); /* call this before opening streams, not after */ - FSOUND_STREAM * (F_API *FSOUND_Stream_Open)(const char *name_or_data, unsigned int mode, int offset, int length); - FSOUND_STREAM * (F_API *FSOUND_Stream_Create)(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, int userdata); - signed char (F_API *FSOUND_Stream_Close)(FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_Play)(int channel, FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_PlayEx)(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); - signed char (F_API *FSOUND_Stream_Stop)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetPosition)(FSOUND_STREAM *stream, unsigned int position); - unsigned int (F_API *FSOUND_Stream_GetPosition)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetTime)(FSOUND_STREAM *stream, int ms); - int (F_API *FSOUND_Stream_GetTime)(FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_GetLength)(FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_GetLengthMs)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetMode)(FSOUND_STREAM *stream, unsigned int mode); - unsigned int (F_API *FSOUND_Stream_GetMode)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetLoopPoints)(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); - signed char (F_API *FSOUND_Stream_SetLoopCount)(FSOUND_STREAM *stream, int count); - int (F_API *FSOUND_Stream_GetOpenState)(FSOUND_STREAM *stream); - FSOUND_SAMPLE * (F_API *FSOUND_Stream_GetSample)(FSOUND_STREAM *stream); /* every stream contains a sample to playback on */ - FSOUND_DSPUNIT * (F_API *FSOUND_Stream_CreateDSP)(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, int param); - signed char (F_API *FSOUND_Stream_SetEndCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); - signed char (F_API *FSOUND_Stream_SetSyncCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); - FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_AddSyncPoint)(FSOUND_STREAM *stream, unsigned int pcmoffset, int userdata); - signed char (F_API *FSOUND_Stream_DeleteSyncPoint)(FSOUND_SYNCPOINT *point); - int (F_API *FSOUND_Stream_GetNumSyncPoints)(FSOUND_STREAM *stream); - FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_GetSyncPoint)(FSOUND_STREAM *stream, int index); - char * (F_API *FSOUND_Stream_GetSyncPointInfo)(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); - signed char (F_API *FSOUND_Stream_SetSubStream)(FSOUND_STREAM *stream, int index); - int (F_API *FSOUND_Stream_GetNumSubStreams)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetSubStreamSentence)(FSOUND_STREAM *stream, int *sentencelist, int numitems); - signed char (F_API *FSOUND_Stream_GetNumTagFields)(FSOUND_STREAM *stream, int *num); - signed char (F_API *FSOUND_Stream_GetTagField)(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); - signed char (F_API *FSOUND_Stream_FindTagField)(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); - signed char (F_API *FSOUND_Stream_Net_SetProxy)(const char *proxy); - char * (F_API *FSOUND_Stream_Net_GetLastServerStatus)(); - signed char (F_API *FSOUND_Stream_Net_SetBufferProperties)(int buffersize, int prebuffer_percent, int rebuffer_percent); - signed char (F_API *FSOUND_Stream_Net_GetBufferProperties)(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); - signed char (F_API *FSOUND_Stream_Net_SetMetadataCallback)(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, int userdata); - signed char (F_API *FSOUND_Stream_Net_GetStatus)(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); - signed char (F_API *FSOUND_CD_Play)(char drive, int track); - void (F_API *FSOUND_CD_SetPlayMode)(char drive, signed char mode); - signed char (F_API *FSOUND_CD_Stop)(char drive); - signed char (F_API *FSOUND_CD_SetPaused)(char drive, signed char paused); - signed char (F_API *FSOUND_CD_SetVolume)(char drive, int volume); - signed char (F_API *FSOUND_CD_SetTrackTime)(char drive, unsigned int ms); - signed char (F_API *FSOUND_CD_Eject)(char drive); - signed char (F_API *FSOUND_CD_GetPaused)(char drive); - int (F_API *FSOUND_CD_GetTrack)(char drive); - int (F_API *FSOUND_CD_GetNumTracks)(char drive); - int (F_API *FSOUND_CD_GetVolume)(char drive); - int (F_API *FSOUND_CD_GetTrackLength)(char drive, int track); - int (F_API *FSOUND_CD_GetTrackTime)(char drive); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_Create)(FSOUND_DSPCALLBACK callback, int priority, int param); - void (F_API *FSOUND_DSP_Free)(FSOUND_DSPUNIT *unit); - void (F_API *FSOUND_DSP_SetPriority)(FSOUND_DSPUNIT *unit, int priority); - int (F_API *FSOUND_DSP_GetPriority)(FSOUND_DSPUNIT *unit); - void (F_API *FSOUND_DSP_SetActive)(FSOUND_DSPUNIT *unit, signed char active); - signed char (F_API *FSOUND_DSP_GetActive)(FSOUND_DSPUNIT *unit); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClearUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetSFXUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetMusicUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetFFTUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClipAndCopyUnit)(); - signed char (F_API *FSOUND_DSP_MixBuffers)(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); - void (F_API *FSOUND_DSP_ClearMixBuffer)(); - int (F_API *FSOUND_DSP_GetBufferLength)(); /* Length of each DSP update */ - int (F_API *FSOUND_DSP_GetBufferLengthTotal)(); /* Total buffer length due to FSOUND_SetBufferSize */ - float * (F_API *FSOUND_DSP_GetSpectrum)(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ - signed char (F_API *FSOUND_Reverb_SetProperties)(FSOUND_REVERB_PROPERTIES *prop); - signed char (F_API *FSOUND_Reverb_GetProperties)(FSOUND_REVERB_PROPERTIES *prop); - signed char (F_API *FSOUND_Reverb_SetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); - signed char (F_API *FSOUND_Reverb_GetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); - signed char (F_API *FSOUND_Record_SetDriver)(int outputtype); - int (F_API *FSOUND_Record_GetNumDrivers)(); - signed char * (F_API *FSOUND_Record_GetDriverName)(int id); - int (F_API *FSOUND_Record_GetDriver)(); - signed char (F_API *FSOUND_Record_StartSample)(FSOUND_SAMPLE *sptr, signed char loop); - signed char (F_API *FSOUND_Record_Stop)(); - int (F_API *FSOUND_Record_GetPosition)(); - FMUSIC_MODULE * (F_API *FMUSIC_LoadSong)(const char *name); - FMUSIC_MODULE * (F_API *FMUSIC_LoadSongEx)(const char *name_or_data, int offset, int length, unsigned int mode, int *samplelist, int samplelistnum); - int (F_API *FMUSIC_GetOpenState)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_FreeSong)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_PlaySong)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_StopSong)(FMUSIC_MODULE *mod); - void (F_API *FMUSIC_StopAllSongs)(); - signed char (F_API *FMUSIC_SetZxxCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); - signed char (F_API *FMUSIC_SetRowCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); - signed char (F_API *FMUSIC_SetOrderCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); - signed char (F_API *FMUSIC_SetInstCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); - signed char (F_API *FMUSIC_SetSample)(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); - signed char (F_API *FMUSIC_SetUserData)(FMUSIC_MODULE *mod, unsigned int userdata); - signed char (F_API *FMUSIC_OptimizeChannels)(FMUSIC_MODULE *mod, int maxchannels, int minvolume); - signed char (F_API *FMUSIC_SetReverb)(signed char reverb); /* MIDI only */ - signed char (F_API *FMUSIC_SetLooping)(FMUSIC_MODULE *mod, signed char looping); - signed char (F_API *FMUSIC_SetOrder)(FMUSIC_MODULE *mod, int order); - signed char (F_API *FMUSIC_SetPaused)(FMUSIC_MODULE *mod, signed char pause); - signed char (F_API *FMUSIC_SetMasterVolume)(FMUSIC_MODULE *mod, int volume); - signed char (F_API *FMUSIC_SetMasterSpeed)(FMUSIC_MODULE *mode, float speed); - signed char (F_API *FMUSIC_SetPanSeperation)(FMUSIC_MODULE *mod, float pansep); - char * (F_API *FMUSIC_GetName)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetType)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumOrders)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumPatterns)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumInstruments)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumSamples)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumChannels)(FMUSIC_MODULE *mod); - FSOUND_SAMPLE * (F_API *FMUSIC_GetSample)(FMUSIC_MODULE *mod, int sampno); - int (F_API *FMUSIC_GetPatternLength)(FMUSIC_MODULE *mod, int orderno); - signed char (F_API *FMUSIC_IsFinished)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_IsPlaying)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetMasterVolume)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetGlobalVolume)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetOrder)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetPattern)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetSpeed)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetBPM)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetRow)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_GetPaused)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetTime)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetRealChannel)(FMUSIC_MODULE *mod, int modchannel); - unsigned int (F_API *FMUSIC_GetUserData)(FMUSIC_MODULE *mod); -} FMOD_INSTANCE; - - -static FMOD_INSTANCE *FMOD_CreateInstance(char *dllName) -{ - FMOD_INSTANCE *instance; - - instance = (FMOD_INSTANCE *)calloc(sizeof(FMOD_INSTANCE), 1); - if (!instance) - { - return NULL; - } - -#ifdef WIN32 - instance->module = LoadLibrary(dllName); -#else - instance->module = dlopen(dllName, RTLD_LAZY); -#endif - if (!instance->module) - { - free(instance); - return NULL; - } - -#ifdef WIN32 - #define F_GETPROC(_x, _y) \ - { \ - *((unsigned int *)&instance->_x) = (unsigned int)GetProcAddress((HMODULE)instance->module, _y); \ - if (!instance->_x) \ - { \ - FreeLibrary((HMODULE)instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#else - #define F_GETPROC(_x, _y) \ - { \ - char tmp[] = _y; \ - *(strchr(tmp, '@')) = 0; \ - *((unsigned int *)&instance->_x) = (unsigned int)dlsym(instance->module, &tmp[1]); \ - if (!instance->_x) \ - { \ - dlclose(instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#endif - - F_GETPROC(FSOUND_SetOutput, "_FSOUND_SetOutput@4"); - F_GETPROC(FSOUND_SetDriver, "_FSOUND_SetDriver@4"); - F_GETPROC(FSOUND_SetMixer, "_FSOUND_SetMixer@4"); - F_GETPROC(FSOUND_SetBufferSize, "_FSOUND_SetBufferSize@4"); - F_GETPROC(FSOUND_SetHWND, "_FSOUND_SetHWND@4"); - F_GETPROC(FSOUND_SetMinHardwareChannels, "_FSOUND_SetMinHardwareChannels@4"); - F_GETPROC(FSOUND_SetMaxHardwareChannels, "_FSOUND_SetMaxHardwareChannels@4"); - F_GETPROC(FSOUND_SetMemorySystem, "_FSOUND_SetMemorySystem@20"); - F_GETPROC(FSOUND_Init, "_FSOUND_Init@12"); - F_GETPROC(FSOUND_Close, "_FSOUND_Close@0"); - F_GETPROC(FSOUND_SetSFXMasterVolume, "_FSOUND_SetSFXMasterVolume@4"); - F_GETPROC(FSOUND_SetPanSeperation, "_FSOUND_SetPanSeperation@4"); - F_GETPROC(FSOUND_SetSpeakerMode, "_FSOUND_SetSpeakerMode@4"); - F_GETPROC(FSOUND_GetError, "_FSOUND_GetError@0"); - F_GETPROC(FSOUND_GetVersion, "_FSOUND_GetVersion@0"); - F_GETPROC(FSOUND_GetOutput, "_FSOUND_GetOutput@0"); - F_GETPROC(FSOUND_GetOutputHandle, "_FSOUND_GetOutputHandle@0"); - F_GETPROC(FSOUND_GetDriver, "_FSOUND_GetDriver@0"); - F_GETPROC(FSOUND_GetMixer, "_FSOUND_GetMixer@0"); - F_GETPROC(FSOUND_GetNumDrivers, "_FSOUND_GetNumDrivers@0"); - F_GETPROC(FSOUND_GetDriverName, "_FSOUND_GetDriverName@4"); - F_GETPROC(FSOUND_GetDriverCaps, "_FSOUND_GetDriverCaps@8"); - F_GETPROC(FSOUND_GetOutputRate, "_FSOUND_GetOutputRate@0"); - F_GETPROC(FSOUND_GetMaxChannels, "_FSOUND_GetMaxChannels@0"); - F_GETPROC(FSOUND_GetMaxSamples, "_FSOUND_GetMaxSamples@0"); - F_GETPROC(FSOUND_GetSFXMasterVolume, "_FSOUND_GetSFXMasterVolume@0"); - F_GETPROC(FSOUND_GetNumHardwareChannels, "_FSOUND_GetNumHardwareChannels@0"); - F_GETPROC(FSOUND_GetChannelsPlaying, "_FSOUND_GetChannelsPlaying@0"); - F_GETPROC(FSOUND_GetCPUUsage, "_FSOUND_GetCPUUsage@0"); - F_GETPROC(FSOUND_GetMemoryStats, "_FSOUND_GetMemoryStats@8"); - F_GETPROC(FSOUND_Sample_Load, "_FSOUND_Sample_Load@20"); - F_GETPROC(FSOUND_Sample_Alloc, "_FSOUND_Sample_Alloc@28"); - F_GETPROC(FSOUND_Sample_Free, "_FSOUND_Sample_Free@4"); - F_GETPROC(FSOUND_Sample_Upload, "_FSOUND_Sample_Upload@12"); - F_GETPROC(FSOUND_Sample_Lock, "_FSOUND_Sample_Lock@28"); - F_GETPROC(FSOUND_Sample_Unlock, "_FSOUND_Sample_Unlock@20"); - F_GETPROC(FSOUND_Sample_SetMode, "_FSOUND_Sample_SetMode@8"); - F_GETPROC(FSOUND_Sample_SetLoopPoints, "_FSOUND_Sample_SetLoopPoints@12"); - F_GETPROC(FSOUND_Sample_SetDefaults, "_FSOUND_Sample_SetDefaults@20"); - F_GETPROC(FSOUND_Sample_SetMinMaxDistance, "_FSOUND_Sample_SetMinMaxDistance@12"); - F_GETPROC(FSOUND_Sample_SetMaxPlaybacks, "_FSOUND_Sample_SetMaxPlaybacks@8"); - F_GETPROC(FSOUND_Sample_Get, "_FSOUND_Sample_Get@4"); - F_GETPROC(FSOUND_Sample_GetName, "_FSOUND_Sample_GetName@4"); - F_GETPROC(FSOUND_Sample_GetLength, "_FSOUND_Sample_GetLength@4"); - F_GETPROC(FSOUND_Sample_GetLoopPoints, "_FSOUND_Sample_GetLoopPoints@12"); - F_GETPROC(FSOUND_Sample_GetDefaults, "_FSOUND_Sample_GetDefaults@20"); - F_GETPROC(FSOUND_Sample_GetMode, "_FSOUND_Sample_GetMode@4"); - F_GETPROC(FSOUND_PlaySound, "_FSOUND_PlaySound@8"); - F_GETPROC(FSOUND_PlaySoundEx, "_FSOUND_PlaySoundEx@16"); - F_GETPROC(FSOUND_StopSound, "_FSOUND_StopSound@4"); - F_GETPROC(FSOUND_SetFrequency, "_FSOUND_SetFrequency@8"); - F_GETPROC(FSOUND_SetVolume, "_FSOUND_SetVolume@8"); - F_GETPROC(FSOUND_SetVolumeAbsolute, "_FSOUND_SetVolumeAbsolute@8"); - F_GETPROC(FSOUND_SetPan, "_FSOUND_SetPan@8"); - F_GETPROC(FSOUND_SetSurround, "_FSOUND_SetSurround@8"); - F_GETPROC(FSOUND_SetMute, "_FSOUND_SetMute@8"); - F_GETPROC(FSOUND_SetPriority, "_FSOUND_SetPriority@8"); - F_GETPROC(FSOUND_SetReserved, "_FSOUND_SetReserved@8"); - F_GETPROC(FSOUND_SetPaused, "_FSOUND_SetPaused@8"); - F_GETPROC(FSOUND_SetLoopMode, "_FSOUND_SetLoopMode@8"); - F_GETPROC(FSOUND_IsPlaying, "_FSOUND_IsPlaying@4"); - F_GETPROC(FSOUND_GetFrequency, "_FSOUND_GetFrequency@4"); - F_GETPROC(FSOUND_GetVolume, "_FSOUND_GetVolume@4"); - F_GETPROC(FSOUND_GetPan, "_FSOUND_GetPan@4"); - F_GETPROC(FSOUND_GetSurround, "_FSOUND_GetSurround@4"); - F_GETPROC(FSOUND_GetMute, "_FSOUND_GetMute@4"); - F_GETPROC(FSOUND_GetPriority, "_FSOUND_GetPriority@4"); - F_GETPROC(FSOUND_GetReserved, "_FSOUND_GetReserved@4"); - F_GETPROC(FSOUND_GetPaused, "_FSOUND_GetPaused@4"); - F_GETPROC(FSOUND_GetLoopMode, "_FSOUND_GetLoopMode@4"); - F_GETPROC(FSOUND_GetCurrentPosition, "_FSOUND_GetCurrentPosition@4"); - F_GETPROC(FSOUND_SetCurrentPosition, "_FSOUND_SetCurrentPosition@8"); - F_GETPROC(FSOUND_GetCurrentSample, "_FSOUND_GetCurrentSample@4"); - F_GETPROC(FSOUND_GetCurrentLevels, "_FSOUND_GetCurrentLevels@12"); - F_GETPROC(FSOUND_FX_Enable, "_FSOUND_FX_Enable@8"); - F_GETPROC(FSOUND_FX_Disable, "_FSOUND_FX_Disable@4"); - F_GETPROC(FSOUND_FX_SetChorus, "_FSOUND_FX_SetChorus@32"); - F_GETPROC(FSOUND_FX_SetCompressor, "_FSOUND_FX_SetCompressor@28"); - F_GETPROC(FSOUND_FX_SetDistortion, "_FSOUND_FX_SetDistortion@24"); - F_GETPROC(FSOUND_FX_SetEcho, "_FSOUND_FX_SetEcho@24"); - F_GETPROC(FSOUND_FX_SetFlanger, "_FSOUND_FX_SetFlanger@32"); - F_GETPROC(FSOUND_FX_SetGargle, "_FSOUND_FX_SetGargle@12"); - F_GETPROC(FSOUND_FX_SetI3DL2Reverb, "_FSOUND_FX_SetI3DL2Reverb@52"); - F_GETPROC(FSOUND_FX_SetParamEQ, "_FSOUND_FX_SetParamEQ@16"); - F_GETPROC(FSOUND_FX_SetWavesReverb, "_FSOUND_FX_SetWavesReverb@20"); - F_GETPROC(FSOUND_Update, "_FSOUND_Update@0"); - F_GETPROC(FSOUND_3D_SetAttributes, "_FSOUND_3D_SetAttributes@12"); - F_GETPROC(FSOUND_3D_GetAttributes, "_FSOUND_3D_GetAttributes@12"); - F_GETPROC(FSOUND_3D_Listener_SetCurrent, "_FSOUND_3D_Listener_SetCurrent@8"); - F_GETPROC(FSOUND_3D_Listener_SetAttributes, "_FSOUND_3D_Listener_SetAttributes@32"); - F_GETPROC(FSOUND_3D_Listener_GetAttributes, "_FSOUND_3D_Listener_GetAttributes@32"); - F_GETPROC(FSOUND_3D_SetDopplerFactor, "_FSOUND_3D_SetDopplerFactor@4"); - F_GETPROC(FSOUND_3D_SetDistanceFactor, "_FSOUND_3D_SetDistanceFactor@4"); - F_GETPROC(FSOUND_3D_SetRolloffFactor, "_FSOUND_3D_SetRolloffFactor@4"); - F_GETPROC(FSOUND_Stream_Open, "_FSOUND_Stream_Open@16"); - F_GETPROC(FSOUND_Stream_Create, "_FSOUND_Stream_Create@20"); - F_GETPROC(FSOUND_Stream_Play, "_FSOUND_Stream_Play@8"); - F_GETPROC(FSOUND_Stream_PlayEx, "_FSOUND_Stream_PlayEx@16"); - F_GETPROC(FSOUND_Stream_Stop, "_FSOUND_Stream_Stop@4"); - F_GETPROC(FSOUND_Stream_Close, "_FSOUND_Stream_Close@4"); - F_GETPROC(FSOUND_Stream_SetEndCallback, "_FSOUND_Stream_SetEndCallback@12"); - F_GETPROC(FSOUND_Stream_SetSyncCallback, "_FSOUND_Stream_SetSyncCallback@12"); - F_GETPROC(FSOUND_Stream_GetSample, "_FSOUND_Stream_GetSample@4"); - F_GETPROC(FSOUND_Stream_CreateDSP, "_FSOUND_Stream_CreateDSP@16"); - F_GETPROC(FSOUND_Stream_SetBufferSize, "_FSOUND_Stream_SetBufferSize@4"); - F_GETPROC(FSOUND_Stream_SetPosition, "_FSOUND_Stream_SetPosition@8"); - F_GETPROC(FSOUND_Stream_GetPosition, "_FSOUND_Stream_GetPosition@4"); - F_GETPROC(FSOUND_Stream_SetTime, "_FSOUND_Stream_SetTime@8"); - F_GETPROC(FSOUND_Stream_GetTime, "_FSOUND_Stream_GetTime@4"); - F_GETPROC(FSOUND_Stream_GetLength, "_FSOUND_Stream_GetLength@4"); - F_GETPROC(FSOUND_Stream_GetLengthMs, "_FSOUND_Stream_GetLengthMs@4"); - F_GETPROC(FSOUND_Stream_SetMode, "_FSOUND_Stream_SetMode@8"); - F_GETPROC(FSOUND_Stream_GetMode, "_FSOUND_Stream_GetMode@4"); - F_GETPROC(FSOUND_Stream_SetSubStream, "_FSOUND_Stream_SetSubStream@8"); - F_GETPROC(FSOUND_Stream_GetNumSubStreams, "_FSOUND_Stream_GetNumSubStreams@4"); - F_GETPROC(FSOUND_Stream_SetSubStreamSentence, "_FSOUND_Stream_SetSubStreamSentence@12"); - F_GETPROC(FSOUND_Stream_SetLoopPoints, "_FSOUND_Stream_SetLoopPoints@12"); - F_GETPROC(FSOUND_Stream_SetLoopCount, "_FSOUND_Stream_SetLoopCount@8"); - F_GETPROC(FSOUND_Stream_AddSyncPoint, "_FSOUND_Stream_AddSyncPoint@12"); - F_GETPROC(FSOUND_Stream_DeleteSyncPoint, "_FSOUND_Stream_DeleteSyncPoint@4"); - F_GETPROC(FSOUND_Stream_GetNumSyncPoints, "_FSOUND_Stream_GetNumSyncPoints@4"); - F_GETPROC(FSOUND_Stream_GetSyncPoint, "_FSOUND_Stream_GetSyncPoint@8"); - F_GETPROC(FSOUND_Stream_GetSyncPointInfo, "_FSOUND_Stream_GetSyncPointInfo@8"); - F_GETPROC(FSOUND_Stream_GetOpenState, "_FSOUND_Stream_GetOpenState@4"); - F_GETPROC(FSOUND_Stream_GetNumTagFields, "_FSOUND_Stream_GetNumTagFields@8"); - F_GETPROC(FSOUND_Stream_GetTagField, "_FSOUND_Stream_GetTagField@24"); - F_GETPROC(FSOUND_Stream_FindTagField, "_FSOUND_Stream_FindTagField@20"); - F_GETPROC(FSOUND_Stream_Net_SetProxy, "_FSOUND_Stream_Net_SetProxy@4"); - F_GETPROC(FSOUND_Stream_Net_GetLastServerStatus, "_FSOUND_Stream_Net_GetLastServerStatus@0"); - F_GETPROC(FSOUND_Stream_Net_SetBufferProperties, "_FSOUND_Stream_Net_SetBufferProperties@12"); - F_GETPROC(FSOUND_Stream_Net_GetBufferProperties, "_FSOUND_Stream_Net_GetBufferProperties@12"); - F_GETPROC(FSOUND_Stream_Net_SetMetadataCallback, "_FSOUND_Stream_Net_SetMetadataCallback@12"); - F_GETPROC(FSOUND_Stream_Net_GetStatus, "_FSOUND_Stream_Net_GetStatus@20"); - F_GETPROC(FSOUND_CD_Play, "_FSOUND_CD_Play@8"); - F_GETPROC(FSOUND_CD_SetPlayMode, "_FSOUND_CD_SetPlayMode@8"); - F_GETPROC(FSOUND_CD_Stop, "_FSOUND_CD_Stop@4"); - F_GETPROC(FSOUND_CD_SetPaused, "_FSOUND_CD_SetPaused@8"); - F_GETPROC(FSOUND_CD_SetVolume, "_FSOUND_CD_SetVolume@8"); - F_GETPROC(FSOUND_CD_SetTrackTime, "_FSOUND_CD_SetTrackTime@8"); - F_GETPROC(FSOUND_CD_Eject, "_FSOUND_CD_Eject@4"); - F_GETPROC(FSOUND_CD_GetPaused, "_FSOUND_CD_GetPaused@4"); - F_GETPROC(FSOUND_CD_GetTrack, "_FSOUND_CD_GetTrack@4"); - F_GETPROC(FSOUND_CD_GetNumTracks, "_FSOUND_CD_GetNumTracks@4"); - F_GETPROC(FSOUND_CD_GetVolume, "_FSOUND_CD_GetVolume@4"); - F_GETPROC(FSOUND_CD_GetTrackLength, "_FSOUND_CD_GetTrackLength@8"); - F_GETPROC(FSOUND_CD_GetTrackTime, "_FSOUND_CD_GetTrackTime@4"); - F_GETPROC(FSOUND_DSP_Create, "_FSOUND_DSP_Create@12"); - F_GETPROC(FSOUND_DSP_Free, "_FSOUND_DSP_Free@4"); - F_GETPROC(FSOUND_DSP_SetPriority, "_FSOUND_DSP_SetPriority@8"); - F_GETPROC(FSOUND_DSP_GetPriority, "_FSOUND_DSP_GetPriority@4"); - F_GETPROC(FSOUND_DSP_SetActive, "_FSOUND_DSP_SetActive@8"); - F_GETPROC(FSOUND_DSP_GetActive, "_FSOUND_DSP_GetActive@4"); - F_GETPROC(FSOUND_DSP_GetClearUnit, "_FSOUND_DSP_GetClearUnit@0"); - F_GETPROC(FSOUND_DSP_GetSFXUnit, "_FSOUND_DSP_GetSFXUnit@0"); - F_GETPROC(FSOUND_DSP_GetMusicUnit, "_FSOUND_DSP_GetMusicUnit@0"); - F_GETPROC(FSOUND_DSP_GetClipAndCopyUnit, "_FSOUND_DSP_GetClipAndCopyUnit@0"); - F_GETPROC(FSOUND_DSP_GetFFTUnit, "_FSOUND_DSP_GetFFTUnit@0"); - F_GETPROC(FSOUND_DSP_MixBuffers, "_FSOUND_DSP_MixBuffers@28"); - F_GETPROC(FSOUND_DSP_ClearMixBuffer, "_FSOUND_DSP_ClearMixBuffer@0"); - F_GETPROC(FSOUND_DSP_GetBufferLength, "_FSOUND_DSP_GetBufferLength@0"); - F_GETPROC(FSOUND_DSP_GetBufferLengthTotal, "_FSOUND_DSP_GetBufferLengthTotal@0"); - F_GETPROC(FSOUND_DSP_GetSpectrum, "_FSOUND_DSP_GetSpectrum@0"); - F_GETPROC(FSOUND_Reverb_SetProperties, "_FSOUND_Reverb_SetProperties@4"); - F_GETPROC(FSOUND_Reverb_GetProperties, "_FSOUND_Reverb_GetProperties@4"); - F_GETPROC(FSOUND_Reverb_SetChannelProperties, "_FSOUND_Reverb_SetChannelProperties@8"); - F_GETPROC(FSOUND_Reverb_GetChannelProperties, "_FSOUND_Reverb_GetChannelProperties@8"); - F_GETPROC(FSOUND_Record_SetDriver, "_FSOUND_Record_SetDriver@4"); - F_GETPROC(FSOUND_Record_GetNumDrivers, "_FSOUND_Record_GetNumDrivers@0"); - F_GETPROC(FSOUND_Record_GetDriverName, "_FSOUND_Record_GetDriverName@4"); - F_GETPROC(FSOUND_Record_GetDriver, "_FSOUND_Record_GetDriver@0"); - F_GETPROC(FSOUND_Record_StartSample, "_FSOUND_Record_StartSample@8"); - F_GETPROC(FSOUND_Record_Stop, "_FSOUND_Record_Stop@0"); - F_GETPROC(FSOUND_Record_GetPosition, "_FSOUND_Record_GetPosition@0"); - F_GETPROC(FSOUND_File_SetCallbacks, "_FSOUND_File_SetCallbacks@20"); - F_GETPROC(FMUSIC_LoadSong, "_FMUSIC_LoadSong@4"); - F_GETPROC(FMUSIC_LoadSongEx, "_FMUSIC_LoadSongEx@24"); - F_GETPROC(FMUSIC_GetOpenState, "_FMUSIC_GetOpenState@4"); - F_GETPROC(FMUSIC_FreeSong, "_FMUSIC_FreeSong@4"); - F_GETPROC(FMUSIC_PlaySong, "_FMUSIC_PlaySong@4"); - F_GETPROC(FMUSIC_StopSong, "_FMUSIC_StopSong@4"); - F_GETPROC(FMUSIC_StopAllSongs, "_FMUSIC_StopAllSongs@0"); - F_GETPROC(FMUSIC_SetZxxCallback, "_FMUSIC_SetZxxCallback@8"); - F_GETPROC(FMUSIC_SetRowCallback, "_FMUSIC_SetRowCallback@12"); - F_GETPROC(FMUSIC_SetOrderCallback, "_FMUSIC_SetOrderCallback@12"); - F_GETPROC(FMUSIC_SetInstCallback, "_FMUSIC_SetInstCallback@12"); - F_GETPROC(FMUSIC_SetSample, "_FMUSIC_SetSample@12"); - F_GETPROC(FMUSIC_SetUserData, "_FMUSIC_SetUserData@8"); - F_GETPROC(FMUSIC_OptimizeChannels, "_FMUSIC_OptimizeChannels@12"); - F_GETPROC(FMUSIC_SetReverb, "_FMUSIC_SetReverb@4"); - F_GETPROC(FMUSIC_SetLooping, "_FMUSIC_SetLooping@8"); - F_GETPROC(FMUSIC_SetOrder, "_FMUSIC_SetOrder@8"); - F_GETPROC(FMUSIC_SetPaused, "_FMUSIC_SetPaused@8"); - F_GETPROC(FMUSIC_SetMasterVolume, "_FMUSIC_SetMasterVolume@8"); - F_GETPROC(FMUSIC_SetMasterSpeed, "_FMUSIC_SetMasterSpeed@8"); - F_GETPROC(FMUSIC_SetPanSeperation, "_FMUSIC_SetPanSeperation@8"); - F_GETPROC(FMUSIC_GetName, "_FMUSIC_GetName@4"); - F_GETPROC(FMUSIC_GetType, "_FMUSIC_GetType@4"); - F_GETPROC(FMUSIC_GetNumOrders, "_FMUSIC_GetNumOrders@4"); - F_GETPROC(FMUSIC_GetNumPatterns, "_FMUSIC_GetNumPatterns@4"); - F_GETPROC(FMUSIC_GetNumInstruments, "_FMUSIC_GetNumInstruments@4"); - F_GETPROC(FMUSIC_GetNumSamples, "_FMUSIC_GetNumSamples@4"); - F_GETPROC(FMUSIC_GetNumChannels, "_FMUSIC_GetNumChannels@4"); - F_GETPROC(FMUSIC_GetSample, "_FMUSIC_GetSample@8"); - F_GETPROC(FMUSIC_GetPatternLength, "_FMUSIC_GetPatternLength@8"); - F_GETPROC(FMUSIC_IsFinished, "_FMUSIC_IsFinished@4"); - F_GETPROC(FMUSIC_IsPlaying, "_FMUSIC_IsPlaying@4"); - F_GETPROC(FMUSIC_GetMasterVolume, "_FMUSIC_GetMasterVolume@4"); - F_GETPROC(FMUSIC_GetGlobalVolume, "_FMUSIC_GetGlobalVolume@4"); - F_GETPROC(FMUSIC_GetOrder, "_FMUSIC_GetOrder@4"); - F_GETPROC(FMUSIC_GetPattern, "_FMUSIC_GetPattern@4"); - F_GETPROC(FMUSIC_GetSpeed, "_FMUSIC_GetSpeed@4"); - F_GETPROC(FMUSIC_GetBPM, "_FMUSIC_GetBPM@4"); - F_GETPROC(FMUSIC_GetRow, "_FMUSIC_GetRow@4"); - F_GETPROC(FMUSIC_GetPaused, "_FMUSIC_GetPaused@4"); - F_GETPROC(FMUSIC_GetTime, "_FMUSIC_GetTime@4"); - F_GETPROC(FMUSIC_GetRealChannel, "_FMUSIC_GetRealChannel@8"); - F_GETPROC(FMUSIC_GetUserData, "_FMUSIC_GetUserData@4"); - - return instance; -} - -static void FMOD_FreeInstance(FMOD_INSTANCE *instance) -{ - if (instance) - { - if (instance->module) - { -#ifdef WIN32 - FreeLibrary((HMODULE)instance->module); -#else - dlclose(instance->module); -#endif - } - free(instance); - } -} - -#endif - +/* ========================================================================================== */ +/* FMOD Dynamic DLL loading header. Copyright (c), Firelight Technologies Pty, Ltd 1999-2003. */ +/* ========================================================================================== */ + +#ifndef _FMODDYN_H_ +#define _FMODDYN_H_ + +#ifdef WIN32 + #include +#else + #include + #include +#endif +#include + +#include "fmod.h" + +typedef struct +{ + void *module; + + signed char (F_API *FSOUND_SetOutput)(int outputtype); + signed char (F_API *FSOUND_SetDriver)(int driver); + signed char (F_API *FSOUND_SetMixer)(int mixer); + signed char (F_API *FSOUND_SetBufferSize)(int len_ms); + signed char (F_API *FSOUND_SetHWND)(void *hwnd); + signed char (F_API *FSOUND_SetMinHardwareChannels)(int min); + signed char (F_API *FSOUND_SetMaxHardwareChannels)(int max); + signed char (F_API *FSOUND_SetMemorySystem)(void *pool, int poollen, FSOUND_ALLOCCALLBACK useralloc, FSOUND_REALLOCCALLBACK userrealloc, FSOUND_FREECALLBACK userfree); + signed char (F_API *FSOUND_Init)(int mixrate, int maxsoftwarechannels, unsigned int flags); + void (F_API *FSOUND_Close)(); + void (F_API *FSOUND_SetSpeakerMode)(unsigned int speakermode); + void (F_API *FSOUND_SetSFXMasterVolume)(int volume); + void (F_API *FSOUND_SetPanSeperation)(float pansep); + void (F_API *FSOUND_File_SetCallbacks)(FSOUND_OPENCALLBACK useropen, FSOUND_CLOSECALLBACK userclose, FSOUND_READCALLBACK userread, FSOUND_SEEKCALLBACK userseek, FSOUND_TELLCALLBACK usertell); + int (F_API *FSOUND_GetError)(); + float (F_API *FSOUND_GetVersion)(); + int (F_API *FSOUND_GetOutput)(); + void * (F_API *FSOUND_GetOutputHandle)(); + int (F_API *FSOUND_GetDriver)(); + int (F_API *FSOUND_GetMixer)(); + int (F_API *FSOUND_GetNumDrivers)(); + signed char * (F_API *FSOUND_GetDriverName)(int id); + signed char (F_API *FSOUND_GetDriverCaps)(int id, unsigned int *caps); + int (F_API *FSOUND_GetOutputRate)(); + int (F_API *FSOUND_GetMaxChannels)(); + int (F_API *FSOUND_GetMaxSamples)(); + int (F_API *FSOUND_GetSFXMasterVolume)(); + int (F_API *FSOUND_GetNumHardwareChannels)(); + int (F_API *FSOUND_GetChannelsPlaying)(); + float (F_API *FSOUND_GetCPUUsage)(); + void (F_API *FSOUND_GetMemoryStats)(unsigned int *currentalloced, unsigned int *maxalloced); + FSOUND_SAMPLE * (F_API *FSOUND_Sample_Load)(int index, const char *name_or_data, unsigned int mode, int offset, int length); + FSOUND_SAMPLE * (F_API *FSOUND_Sample_Alloc)(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); + void (F_API *FSOUND_Sample_Free)(FSOUND_SAMPLE *sptr); + signed char (F_API *FSOUND_Sample_Upload)(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); + signed char (F_API *FSOUND_Sample_Lock)(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); + signed char (F_API *FSOUND_Sample_Unlock)(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + signed char (F_API *FSOUND_Sample_SetMode)(FSOUND_SAMPLE *sptr, unsigned int mode); + signed char (F_API *FSOUND_Sample_SetLoopPoints)(FSOUND_SAMPLE *sptr, int loopstart, int loopend); + signed char (F_API *FSOUND_Sample_SetDefaults)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); + signed char (F_API *FSOUND_Sample_SetMinMaxDistance)(FSOUND_SAMPLE *sptr, float min, float max); + signed char (F_API *FSOUND_Sample_SetMaxPlaybacks)(FSOUND_SAMPLE *sptr, int max); + FSOUND_SAMPLE * (F_API *FSOUND_Sample_Get)(int sampno); + char * (F_API *FSOUND_Sample_GetName)(FSOUND_SAMPLE *sptr); + unsigned int (F_API *FSOUND_Sample_GetLength)(FSOUND_SAMPLE *sptr); + signed char (F_API *FSOUND_Sample_GetLoopPoints)(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); + signed char (F_API *FSOUND_Sample_GetDefaults)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); + unsigned int (F_API *FSOUND_Sample_GetMode)(FSOUND_SAMPLE *sptr); + int (F_API *FSOUND_PlaySound)(int channel, FSOUND_SAMPLE *sptr); + int (F_API *FSOUND_PlaySoundEx)(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); + signed char (F_API *FSOUND_StopSound)(int channel); + signed char (F_API *FSOUND_SetFrequency)(int channel, int freq); + signed char (F_API *FSOUND_SetVolume)(int channel, int vol); + signed char (F_API *FSOUND_SetVolumeAbsolute)(int channel, int vol); + signed char (F_API *FSOUND_SetPan)(int channel, int pan); + signed char (F_API *FSOUND_SetSurround)(int channel, signed char surround); + signed char (F_API *FSOUND_SetMute)(int channel, signed char mute); + signed char (F_API *FSOUND_SetPriority)(int channel, int priority); + signed char (F_API *FSOUND_SetReserved)(int channel, signed char reserved); + signed char (F_API *FSOUND_SetPaused)(int channel, signed char paused); + signed char (F_API *FSOUND_SetLoopMode)(int channel, unsigned int loopmode); + signed char (F_API *FSOUND_SetCurrentPosition)(int channel, unsigned int offset); + signed char (F_API *FSOUND_IsPlaying)(int channel); + int (F_API *FSOUND_GetFrequency)(int channel); + int (F_API *FSOUND_GetVolume)(int channel); + int (F_API *FSOUND_GetPan)(int channel); + signed char (F_API *FSOUND_GetSurround)(int channel); + signed char (F_API *FSOUND_GetMute)(int channel); + int (F_API *FSOUND_GetPriority)(int channel); + signed char (F_API *FSOUND_GetReserved)(int channel); + signed char (F_API *FSOUND_GetPaused)(int channel); + unsigned int (F_API *FSOUND_GetLoopMode)(int channel); + unsigned int (F_API *FSOUND_GetCurrentPosition)(int channel); + FSOUND_SAMPLE * (F_API *FSOUND_GetCurrentSample)(int channel); + signed char (F_API *FSOUND_GetCurrentLevels)(int channel, float *l, float *r); + int (F_API *FSOUND_FX_Enable)(int channel, unsigned int fx); /* See FSOUND_FX_MODES */ + signed char (F_API *FSOUND_FX_Disable)(int channel); + signed char (F_API *FSOUND_FX_SetChorus)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); + signed char (F_API *FSOUND_FX_SetCompressor)(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); + signed char (F_API *FSOUND_FX_SetDistortion)(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); + signed char (F_API *FSOUND_FX_SetEcho)(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); + signed char (F_API *FSOUND_FX_SetFlanger)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); + signed char (F_API *FSOUND_FX_SetGargle)(int fxid, int RateHz, int WaveShape); + signed char (F_API *FSOUND_FX_SetI3DL2Reverb)(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); + signed char (F_API *FSOUND_FX_SetParamEQ)(int fxid, float Center, float Bandwidth, float Gain); + signed char (F_API *FSOUND_FX_SetWavesReverb)(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); + void (F_API *FSOUND_Update)(); /* you must call this once a frame */ + void (F_API *FSOUND_3D_SetDopplerFactor)(float scale); + void (F_API *FSOUND_3D_SetDistanceFactor)(float scale); + void (F_API *FSOUND_3D_SetRolloffFactor)(float scale); + signed char (F_API *FSOUND_3D_SetAttributes)(int channel, float *pos, float *vel); + signed char (F_API *FSOUND_3D_GetAttributes)(int channel, float *pos, float *vel); + void (F_API *FSOUND_3D_Listener_SetCurrent)(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ + void (F_API *FSOUND_3D_Listener_SetAttributes)(float *pos, float *vel, float fx, float fy, float fz, float tx, float ty, float tz); + void (F_API *FSOUND_3D_Listener_GetAttributes)(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); + signed char (F_API *FSOUND_Stream_SetBufferSize)(int ms); /* call this before opening streams, not after */ + FSOUND_STREAM * (F_API *FSOUND_Stream_Open)(const char *name_or_data, unsigned int mode, int offset, int length); + FSOUND_STREAM * (F_API *FSOUND_Stream_Create)(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, int userdata); + signed char (F_API *FSOUND_Stream_Close)(FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_Play)(int channel, FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_PlayEx)(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); + signed char (F_API *FSOUND_Stream_Stop)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetPosition)(FSOUND_STREAM *stream, unsigned int position); + unsigned int (F_API *FSOUND_Stream_GetPosition)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetTime)(FSOUND_STREAM *stream, int ms); + int (F_API *FSOUND_Stream_GetTime)(FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_GetLength)(FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_GetLengthMs)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetMode)(FSOUND_STREAM *stream, unsigned int mode); + unsigned int (F_API *FSOUND_Stream_GetMode)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetLoopPoints)(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); + signed char (F_API *FSOUND_Stream_SetLoopCount)(FSOUND_STREAM *stream, int count); + int (F_API *FSOUND_Stream_GetOpenState)(FSOUND_STREAM *stream); + FSOUND_SAMPLE * (F_API *FSOUND_Stream_GetSample)(FSOUND_STREAM *stream); /* every stream contains a sample to playback on */ + FSOUND_DSPUNIT * (F_API *FSOUND_Stream_CreateDSP)(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, int param); + signed char (F_API *FSOUND_Stream_SetEndCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); + signed char (F_API *FSOUND_Stream_SetSyncCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata); + FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_AddSyncPoint)(FSOUND_STREAM *stream, unsigned int pcmoffset, int userdata); + signed char (F_API *FSOUND_Stream_DeleteSyncPoint)(FSOUND_SYNCPOINT *point); + int (F_API *FSOUND_Stream_GetNumSyncPoints)(FSOUND_STREAM *stream); + FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_GetSyncPoint)(FSOUND_STREAM *stream, int index); + char * (F_API *FSOUND_Stream_GetSyncPointInfo)(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); + signed char (F_API *FSOUND_Stream_SetSubStream)(FSOUND_STREAM *stream, int index); + int (F_API *FSOUND_Stream_GetNumSubStreams)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetSubStreamSentence)(FSOUND_STREAM *stream, int *sentencelist, int numitems); + signed char (F_API *FSOUND_Stream_GetNumTagFields)(FSOUND_STREAM *stream, int *num); + signed char (F_API *FSOUND_Stream_GetTagField)(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); + signed char (F_API *FSOUND_Stream_FindTagField)(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); + signed char (F_API *FSOUND_Stream_Net_SetProxy)(const char *proxy); + char * (F_API *FSOUND_Stream_Net_GetLastServerStatus)(); + signed char (F_API *FSOUND_Stream_Net_SetBufferProperties)(int buffersize, int prebuffer_percent, int rebuffer_percent); + signed char (F_API *FSOUND_Stream_Net_GetBufferProperties)(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); + signed char (F_API *FSOUND_Stream_Net_SetMetadataCallback)(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, int userdata); + signed char (F_API *FSOUND_Stream_Net_GetStatus)(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); + signed char (F_API *FSOUND_CD_Play)(char drive, int track); + void (F_API *FSOUND_CD_SetPlayMode)(char drive, signed char mode); + signed char (F_API *FSOUND_CD_Stop)(char drive); + signed char (F_API *FSOUND_CD_SetPaused)(char drive, signed char paused); + signed char (F_API *FSOUND_CD_SetVolume)(char drive, int volume); + signed char (F_API *FSOUND_CD_SetTrackTime)(char drive, unsigned int ms); + signed char (F_API *FSOUND_CD_Eject)(char drive); + signed char (F_API *FSOUND_CD_GetPaused)(char drive); + int (F_API *FSOUND_CD_GetTrack)(char drive); + int (F_API *FSOUND_CD_GetNumTracks)(char drive); + int (F_API *FSOUND_CD_GetVolume)(char drive); + int (F_API *FSOUND_CD_GetTrackLength)(char drive, int track); + int (F_API *FSOUND_CD_GetTrackTime)(char drive); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_Create)(FSOUND_DSPCALLBACK callback, int priority, int param); + void (F_API *FSOUND_DSP_Free)(FSOUND_DSPUNIT *unit); + void (F_API *FSOUND_DSP_SetPriority)(FSOUND_DSPUNIT *unit, int priority); + int (F_API *FSOUND_DSP_GetPriority)(FSOUND_DSPUNIT *unit); + void (F_API *FSOUND_DSP_SetActive)(FSOUND_DSPUNIT *unit, signed char active); + signed char (F_API *FSOUND_DSP_GetActive)(FSOUND_DSPUNIT *unit); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClearUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetSFXUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetMusicUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetFFTUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClipAndCopyUnit)(); + signed char (F_API *FSOUND_DSP_MixBuffers)(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); + void (F_API *FSOUND_DSP_ClearMixBuffer)(); + int (F_API *FSOUND_DSP_GetBufferLength)(); /* Length of each DSP update */ + int (F_API *FSOUND_DSP_GetBufferLengthTotal)(); /* Total buffer length due to FSOUND_SetBufferSize */ + float * (F_API *FSOUND_DSP_GetSpectrum)(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ + signed char (F_API *FSOUND_Reverb_SetProperties)(FSOUND_REVERB_PROPERTIES *prop); + signed char (F_API *FSOUND_Reverb_GetProperties)(FSOUND_REVERB_PROPERTIES *prop); + signed char (F_API *FSOUND_Reverb_SetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); + signed char (F_API *FSOUND_Reverb_GetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); + signed char (F_API *FSOUND_Record_SetDriver)(int outputtype); + int (F_API *FSOUND_Record_GetNumDrivers)(); + signed char * (F_API *FSOUND_Record_GetDriverName)(int id); + int (F_API *FSOUND_Record_GetDriver)(); + signed char (F_API *FSOUND_Record_StartSample)(FSOUND_SAMPLE *sptr, signed char loop); + signed char (F_API *FSOUND_Record_Stop)(); + int (F_API *FSOUND_Record_GetPosition)(); + FMUSIC_MODULE * (F_API *FMUSIC_LoadSong)(const char *name); + FMUSIC_MODULE * (F_API *FMUSIC_LoadSongEx)(const char *name_or_data, int offset, int length, unsigned int mode, int *samplelist, int samplelistnum); + int (F_API *FMUSIC_GetOpenState)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_FreeSong)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_PlaySong)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_StopSong)(FMUSIC_MODULE *mod); + void (F_API *FMUSIC_StopAllSongs)(); + signed char (F_API *FMUSIC_SetZxxCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); + signed char (F_API *FMUSIC_SetRowCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); + signed char (F_API *FMUSIC_SetOrderCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); + signed char (F_API *FMUSIC_SetInstCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); + signed char (F_API *FMUSIC_SetSample)(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); + signed char (F_API *FMUSIC_SetUserData)(FMUSIC_MODULE *mod, unsigned int userdata); + signed char (F_API *FMUSIC_OptimizeChannels)(FMUSIC_MODULE *mod, int maxchannels, int minvolume); + signed char (F_API *FMUSIC_SetReverb)(signed char reverb); /* MIDI only */ + signed char (F_API *FMUSIC_SetLooping)(FMUSIC_MODULE *mod, signed char looping); + signed char (F_API *FMUSIC_SetOrder)(FMUSIC_MODULE *mod, int order); + signed char (F_API *FMUSIC_SetPaused)(FMUSIC_MODULE *mod, signed char pause); + signed char (F_API *FMUSIC_SetMasterVolume)(FMUSIC_MODULE *mod, int volume); + signed char (F_API *FMUSIC_SetMasterSpeed)(FMUSIC_MODULE *mode, float speed); + signed char (F_API *FMUSIC_SetPanSeperation)(FMUSIC_MODULE *mod, float pansep); + char * (F_API *FMUSIC_GetName)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetType)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumOrders)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumPatterns)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumInstruments)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumSamples)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumChannels)(FMUSIC_MODULE *mod); + FSOUND_SAMPLE * (F_API *FMUSIC_GetSample)(FMUSIC_MODULE *mod, int sampno); + int (F_API *FMUSIC_GetPatternLength)(FMUSIC_MODULE *mod, int orderno); + signed char (F_API *FMUSIC_IsFinished)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_IsPlaying)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetMasterVolume)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetGlobalVolume)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetOrder)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetPattern)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetSpeed)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetBPM)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetRow)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_GetPaused)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetTime)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetRealChannel)(FMUSIC_MODULE *mod, int modchannel); + unsigned int (F_API *FMUSIC_GetUserData)(FMUSIC_MODULE *mod); +} FMOD_INSTANCE; + + +static FMOD_INSTANCE *FMOD_CreateInstance(char *dllName) +{ + FMOD_INSTANCE *instance; + + instance = (FMOD_INSTANCE *)calloc(sizeof(FMOD_INSTANCE), 1); + if (!instance) + { + return NULL; + } + +#ifdef WIN32 + instance->module = LoadLibrary(dllName); +#else + instance->module = dlopen(dllName, RTLD_LAZY); +#endif + if (!instance->module) + { + free(instance); + return NULL; + } + +#ifdef WIN32 + #define F_GETPROC(_x, _y) \ + { \ + *((unsigned int *)&instance->_x) = (unsigned int)GetProcAddress((HMODULE)instance->module, _y); \ + if (!instance->_x) \ + { \ + FreeLibrary((HMODULE)instance->module); \ + free(instance); \ + return NULL; \ + } \ + } +#else + #define F_GETPROC(_x, _y) \ + { \ + char tmp[] = _y; \ + *(strchr(tmp, '@')) = 0; \ + *((unsigned int *)&instance->_x) = (unsigned int)dlsym(instance->module, &tmp[1]); \ + if (!instance->_x) \ + { \ + dlclose(instance->module); \ + free(instance); \ + return NULL; \ + } \ + } +#endif + + F_GETPROC(FSOUND_SetOutput, "_FSOUND_SetOutput@4"); + F_GETPROC(FSOUND_SetDriver, "_FSOUND_SetDriver@4"); + F_GETPROC(FSOUND_SetMixer, "_FSOUND_SetMixer@4"); + F_GETPROC(FSOUND_SetBufferSize, "_FSOUND_SetBufferSize@4"); + F_GETPROC(FSOUND_SetHWND, "_FSOUND_SetHWND@4"); + F_GETPROC(FSOUND_SetMinHardwareChannels, "_FSOUND_SetMinHardwareChannels@4"); + F_GETPROC(FSOUND_SetMaxHardwareChannels, "_FSOUND_SetMaxHardwareChannels@4"); + F_GETPROC(FSOUND_SetMemorySystem, "_FSOUND_SetMemorySystem@20"); + F_GETPROC(FSOUND_Init, "_FSOUND_Init@12"); + F_GETPROC(FSOUND_Close, "_FSOUND_Close@0"); + F_GETPROC(FSOUND_SetSFXMasterVolume, "_FSOUND_SetSFXMasterVolume@4"); + F_GETPROC(FSOUND_SetPanSeperation, "_FSOUND_SetPanSeperation@4"); + F_GETPROC(FSOUND_SetSpeakerMode, "_FSOUND_SetSpeakerMode@4"); + F_GETPROC(FSOUND_GetError, "_FSOUND_GetError@0"); + F_GETPROC(FSOUND_GetVersion, "_FSOUND_GetVersion@0"); + F_GETPROC(FSOUND_GetOutput, "_FSOUND_GetOutput@0"); + F_GETPROC(FSOUND_GetOutputHandle, "_FSOUND_GetOutputHandle@0"); + F_GETPROC(FSOUND_GetDriver, "_FSOUND_GetDriver@0"); + F_GETPROC(FSOUND_GetMixer, "_FSOUND_GetMixer@0"); + F_GETPROC(FSOUND_GetNumDrivers, "_FSOUND_GetNumDrivers@0"); + F_GETPROC(FSOUND_GetDriverName, "_FSOUND_GetDriverName@4"); + F_GETPROC(FSOUND_GetDriverCaps, "_FSOUND_GetDriverCaps@8"); + F_GETPROC(FSOUND_GetOutputRate, "_FSOUND_GetOutputRate@0"); + F_GETPROC(FSOUND_GetMaxChannels, "_FSOUND_GetMaxChannels@0"); + F_GETPROC(FSOUND_GetMaxSamples, "_FSOUND_GetMaxSamples@0"); + F_GETPROC(FSOUND_GetSFXMasterVolume, "_FSOUND_GetSFXMasterVolume@0"); + F_GETPROC(FSOUND_GetNumHardwareChannels, "_FSOUND_GetNumHardwareChannels@0"); + F_GETPROC(FSOUND_GetChannelsPlaying, "_FSOUND_GetChannelsPlaying@0"); + F_GETPROC(FSOUND_GetCPUUsage, "_FSOUND_GetCPUUsage@0"); + F_GETPROC(FSOUND_GetMemoryStats, "_FSOUND_GetMemoryStats@8"); + F_GETPROC(FSOUND_Sample_Load, "_FSOUND_Sample_Load@20"); + F_GETPROC(FSOUND_Sample_Alloc, "_FSOUND_Sample_Alloc@28"); + F_GETPROC(FSOUND_Sample_Free, "_FSOUND_Sample_Free@4"); + F_GETPROC(FSOUND_Sample_Upload, "_FSOUND_Sample_Upload@12"); + F_GETPROC(FSOUND_Sample_Lock, "_FSOUND_Sample_Lock@28"); + F_GETPROC(FSOUND_Sample_Unlock, "_FSOUND_Sample_Unlock@20"); + F_GETPROC(FSOUND_Sample_SetMode, "_FSOUND_Sample_SetMode@8"); + F_GETPROC(FSOUND_Sample_SetLoopPoints, "_FSOUND_Sample_SetLoopPoints@12"); + F_GETPROC(FSOUND_Sample_SetDefaults, "_FSOUND_Sample_SetDefaults@20"); + F_GETPROC(FSOUND_Sample_SetMinMaxDistance, "_FSOUND_Sample_SetMinMaxDistance@12"); + F_GETPROC(FSOUND_Sample_SetMaxPlaybacks, "_FSOUND_Sample_SetMaxPlaybacks@8"); + F_GETPROC(FSOUND_Sample_Get, "_FSOUND_Sample_Get@4"); + F_GETPROC(FSOUND_Sample_GetName, "_FSOUND_Sample_GetName@4"); + F_GETPROC(FSOUND_Sample_GetLength, "_FSOUND_Sample_GetLength@4"); + F_GETPROC(FSOUND_Sample_GetLoopPoints, "_FSOUND_Sample_GetLoopPoints@12"); + F_GETPROC(FSOUND_Sample_GetDefaults, "_FSOUND_Sample_GetDefaults@20"); + F_GETPROC(FSOUND_Sample_GetMode, "_FSOUND_Sample_GetMode@4"); + F_GETPROC(FSOUND_PlaySound, "_FSOUND_PlaySound@8"); + F_GETPROC(FSOUND_PlaySoundEx, "_FSOUND_PlaySoundEx@16"); + F_GETPROC(FSOUND_StopSound, "_FSOUND_StopSound@4"); + F_GETPROC(FSOUND_SetFrequency, "_FSOUND_SetFrequency@8"); + F_GETPROC(FSOUND_SetVolume, "_FSOUND_SetVolume@8"); + F_GETPROC(FSOUND_SetVolumeAbsolute, "_FSOUND_SetVolumeAbsolute@8"); + F_GETPROC(FSOUND_SetPan, "_FSOUND_SetPan@8"); + F_GETPROC(FSOUND_SetSurround, "_FSOUND_SetSurround@8"); + F_GETPROC(FSOUND_SetMute, "_FSOUND_SetMute@8"); + F_GETPROC(FSOUND_SetPriority, "_FSOUND_SetPriority@8"); + F_GETPROC(FSOUND_SetReserved, "_FSOUND_SetReserved@8"); + F_GETPROC(FSOUND_SetPaused, "_FSOUND_SetPaused@8"); + F_GETPROC(FSOUND_SetLoopMode, "_FSOUND_SetLoopMode@8"); + F_GETPROC(FSOUND_IsPlaying, "_FSOUND_IsPlaying@4"); + F_GETPROC(FSOUND_GetFrequency, "_FSOUND_GetFrequency@4"); + F_GETPROC(FSOUND_GetVolume, "_FSOUND_GetVolume@4"); + F_GETPROC(FSOUND_GetPan, "_FSOUND_GetPan@4"); + F_GETPROC(FSOUND_GetSurround, "_FSOUND_GetSurround@4"); + F_GETPROC(FSOUND_GetMute, "_FSOUND_GetMute@4"); + F_GETPROC(FSOUND_GetPriority, "_FSOUND_GetPriority@4"); + F_GETPROC(FSOUND_GetReserved, "_FSOUND_GetReserved@4"); + F_GETPROC(FSOUND_GetPaused, "_FSOUND_GetPaused@4"); + F_GETPROC(FSOUND_GetLoopMode, "_FSOUND_GetLoopMode@4"); + F_GETPROC(FSOUND_GetCurrentPosition, "_FSOUND_GetCurrentPosition@4"); + F_GETPROC(FSOUND_SetCurrentPosition, "_FSOUND_SetCurrentPosition@8"); + F_GETPROC(FSOUND_GetCurrentSample, "_FSOUND_GetCurrentSample@4"); + F_GETPROC(FSOUND_GetCurrentLevels, "_FSOUND_GetCurrentLevels@12"); + F_GETPROC(FSOUND_FX_Enable, "_FSOUND_FX_Enable@8"); + F_GETPROC(FSOUND_FX_Disable, "_FSOUND_FX_Disable@4"); + F_GETPROC(FSOUND_FX_SetChorus, "_FSOUND_FX_SetChorus@32"); + F_GETPROC(FSOUND_FX_SetCompressor, "_FSOUND_FX_SetCompressor@28"); + F_GETPROC(FSOUND_FX_SetDistortion, "_FSOUND_FX_SetDistortion@24"); + F_GETPROC(FSOUND_FX_SetEcho, "_FSOUND_FX_SetEcho@24"); + F_GETPROC(FSOUND_FX_SetFlanger, "_FSOUND_FX_SetFlanger@32"); + F_GETPROC(FSOUND_FX_SetGargle, "_FSOUND_FX_SetGargle@12"); + F_GETPROC(FSOUND_FX_SetI3DL2Reverb, "_FSOUND_FX_SetI3DL2Reverb@52"); + F_GETPROC(FSOUND_FX_SetParamEQ, "_FSOUND_FX_SetParamEQ@16"); + F_GETPROC(FSOUND_FX_SetWavesReverb, "_FSOUND_FX_SetWavesReverb@20"); + F_GETPROC(FSOUND_Update, "_FSOUND_Update@0"); + F_GETPROC(FSOUND_3D_SetAttributes, "_FSOUND_3D_SetAttributes@12"); + F_GETPROC(FSOUND_3D_GetAttributes, "_FSOUND_3D_GetAttributes@12"); + F_GETPROC(FSOUND_3D_Listener_SetCurrent, "_FSOUND_3D_Listener_SetCurrent@8"); + F_GETPROC(FSOUND_3D_Listener_SetAttributes, "_FSOUND_3D_Listener_SetAttributes@32"); + F_GETPROC(FSOUND_3D_Listener_GetAttributes, "_FSOUND_3D_Listener_GetAttributes@32"); + F_GETPROC(FSOUND_3D_SetDopplerFactor, "_FSOUND_3D_SetDopplerFactor@4"); + F_GETPROC(FSOUND_3D_SetDistanceFactor, "_FSOUND_3D_SetDistanceFactor@4"); + F_GETPROC(FSOUND_3D_SetRolloffFactor, "_FSOUND_3D_SetRolloffFactor@4"); + F_GETPROC(FSOUND_Stream_Open, "_FSOUND_Stream_Open@16"); + F_GETPROC(FSOUND_Stream_Create, "_FSOUND_Stream_Create@20"); + F_GETPROC(FSOUND_Stream_Play, "_FSOUND_Stream_Play@8"); + F_GETPROC(FSOUND_Stream_PlayEx, "_FSOUND_Stream_PlayEx@16"); + F_GETPROC(FSOUND_Stream_Stop, "_FSOUND_Stream_Stop@4"); + F_GETPROC(FSOUND_Stream_Close, "_FSOUND_Stream_Close@4"); + F_GETPROC(FSOUND_Stream_SetEndCallback, "_FSOUND_Stream_SetEndCallback@12"); + F_GETPROC(FSOUND_Stream_SetSyncCallback, "_FSOUND_Stream_SetSyncCallback@12"); + F_GETPROC(FSOUND_Stream_GetSample, "_FSOUND_Stream_GetSample@4"); + F_GETPROC(FSOUND_Stream_CreateDSP, "_FSOUND_Stream_CreateDSP@16"); + F_GETPROC(FSOUND_Stream_SetBufferSize, "_FSOUND_Stream_SetBufferSize@4"); + F_GETPROC(FSOUND_Stream_SetPosition, "_FSOUND_Stream_SetPosition@8"); + F_GETPROC(FSOUND_Stream_GetPosition, "_FSOUND_Stream_GetPosition@4"); + F_GETPROC(FSOUND_Stream_SetTime, "_FSOUND_Stream_SetTime@8"); + F_GETPROC(FSOUND_Stream_GetTime, "_FSOUND_Stream_GetTime@4"); + F_GETPROC(FSOUND_Stream_GetLength, "_FSOUND_Stream_GetLength@4"); + F_GETPROC(FSOUND_Stream_GetLengthMs, "_FSOUND_Stream_GetLengthMs@4"); + F_GETPROC(FSOUND_Stream_SetMode, "_FSOUND_Stream_SetMode@8"); + F_GETPROC(FSOUND_Stream_GetMode, "_FSOUND_Stream_GetMode@4"); + F_GETPROC(FSOUND_Stream_SetSubStream, "_FSOUND_Stream_SetSubStream@8"); + F_GETPROC(FSOUND_Stream_GetNumSubStreams, "_FSOUND_Stream_GetNumSubStreams@4"); + F_GETPROC(FSOUND_Stream_SetSubStreamSentence, "_FSOUND_Stream_SetSubStreamSentence@12"); + F_GETPROC(FSOUND_Stream_SetLoopPoints, "_FSOUND_Stream_SetLoopPoints@12"); + F_GETPROC(FSOUND_Stream_SetLoopCount, "_FSOUND_Stream_SetLoopCount@8"); + F_GETPROC(FSOUND_Stream_AddSyncPoint, "_FSOUND_Stream_AddSyncPoint@12"); + F_GETPROC(FSOUND_Stream_DeleteSyncPoint, "_FSOUND_Stream_DeleteSyncPoint@4"); + F_GETPROC(FSOUND_Stream_GetNumSyncPoints, "_FSOUND_Stream_GetNumSyncPoints@4"); + F_GETPROC(FSOUND_Stream_GetSyncPoint, "_FSOUND_Stream_GetSyncPoint@8"); + F_GETPROC(FSOUND_Stream_GetSyncPointInfo, "_FSOUND_Stream_GetSyncPointInfo@8"); + F_GETPROC(FSOUND_Stream_GetOpenState, "_FSOUND_Stream_GetOpenState@4"); + F_GETPROC(FSOUND_Stream_GetNumTagFields, "_FSOUND_Stream_GetNumTagFields@8"); + F_GETPROC(FSOUND_Stream_GetTagField, "_FSOUND_Stream_GetTagField@24"); + F_GETPROC(FSOUND_Stream_FindTagField, "_FSOUND_Stream_FindTagField@20"); + F_GETPROC(FSOUND_Stream_Net_SetProxy, "_FSOUND_Stream_Net_SetProxy@4"); + F_GETPROC(FSOUND_Stream_Net_GetLastServerStatus, "_FSOUND_Stream_Net_GetLastServerStatus@0"); + F_GETPROC(FSOUND_Stream_Net_SetBufferProperties, "_FSOUND_Stream_Net_SetBufferProperties@12"); + F_GETPROC(FSOUND_Stream_Net_GetBufferProperties, "_FSOUND_Stream_Net_GetBufferProperties@12"); + F_GETPROC(FSOUND_Stream_Net_SetMetadataCallback, "_FSOUND_Stream_Net_SetMetadataCallback@12"); + F_GETPROC(FSOUND_Stream_Net_GetStatus, "_FSOUND_Stream_Net_GetStatus@20"); + F_GETPROC(FSOUND_CD_Play, "_FSOUND_CD_Play@8"); + F_GETPROC(FSOUND_CD_SetPlayMode, "_FSOUND_CD_SetPlayMode@8"); + F_GETPROC(FSOUND_CD_Stop, "_FSOUND_CD_Stop@4"); + F_GETPROC(FSOUND_CD_SetPaused, "_FSOUND_CD_SetPaused@8"); + F_GETPROC(FSOUND_CD_SetVolume, "_FSOUND_CD_SetVolume@8"); + F_GETPROC(FSOUND_CD_SetTrackTime, "_FSOUND_CD_SetTrackTime@8"); + F_GETPROC(FSOUND_CD_Eject, "_FSOUND_CD_Eject@4"); + F_GETPROC(FSOUND_CD_GetPaused, "_FSOUND_CD_GetPaused@4"); + F_GETPROC(FSOUND_CD_GetTrack, "_FSOUND_CD_GetTrack@4"); + F_GETPROC(FSOUND_CD_GetNumTracks, "_FSOUND_CD_GetNumTracks@4"); + F_GETPROC(FSOUND_CD_GetVolume, "_FSOUND_CD_GetVolume@4"); + F_GETPROC(FSOUND_CD_GetTrackLength, "_FSOUND_CD_GetTrackLength@8"); + F_GETPROC(FSOUND_CD_GetTrackTime, "_FSOUND_CD_GetTrackTime@4"); + F_GETPROC(FSOUND_DSP_Create, "_FSOUND_DSP_Create@12"); + F_GETPROC(FSOUND_DSP_Free, "_FSOUND_DSP_Free@4"); + F_GETPROC(FSOUND_DSP_SetPriority, "_FSOUND_DSP_SetPriority@8"); + F_GETPROC(FSOUND_DSP_GetPriority, "_FSOUND_DSP_GetPriority@4"); + F_GETPROC(FSOUND_DSP_SetActive, "_FSOUND_DSP_SetActive@8"); + F_GETPROC(FSOUND_DSP_GetActive, "_FSOUND_DSP_GetActive@4"); + F_GETPROC(FSOUND_DSP_GetClearUnit, "_FSOUND_DSP_GetClearUnit@0"); + F_GETPROC(FSOUND_DSP_GetSFXUnit, "_FSOUND_DSP_GetSFXUnit@0"); + F_GETPROC(FSOUND_DSP_GetMusicUnit, "_FSOUND_DSP_GetMusicUnit@0"); + F_GETPROC(FSOUND_DSP_GetClipAndCopyUnit, "_FSOUND_DSP_GetClipAndCopyUnit@0"); + F_GETPROC(FSOUND_DSP_GetFFTUnit, "_FSOUND_DSP_GetFFTUnit@0"); + F_GETPROC(FSOUND_DSP_MixBuffers, "_FSOUND_DSP_MixBuffers@28"); + F_GETPROC(FSOUND_DSP_ClearMixBuffer, "_FSOUND_DSP_ClearMixBuffer@0"); + F_GETPROC(FSOUND_DSP_GetBufferLength, "_FSOUND_DSP_GetBufferLength@0"); + F_GETPROC(FSOUND_DSP_GetBufferLengthTotal, "_FSOUND_DSP_GetBufferLengthTotal@0"); + F_GETPROC(FSOUND_DSP_GetSpectrum, "_FSOUND_DSP_GetSpectrum@0"); + F_GETPROC(FSOUND_Reverb_SetProperties, "_FSOUND_Reverb_SetProperties@4"); + F_GETPROC(FSOUND_Reverb_GetProperties, "_FSOUND_Reverb_GetProperties@4"); + F_GETPROC(FSOUND_Reverb_SetChannelProperties, "_FSOUND_Reverb_SetChannelProperties@8"); + F_GETPROC(FSOUND_Reverb_GetChannelProperties, "_FSOUND_Reverb_GetChannelProperties@8"); + F_GETPROC(FSOUND_Record_SetDriver, "_FSOUND_Record_SetDriver@4"); + F_GETPROC(FSOUND_Record_GetNumDrivers, "_FSOUND_Record_GetNumDrivers@0"); + F_GETPROC(FSOUND_Record_GetDriverName, "_FSOUND_Record_GetDriverName@4"); + F_GETPROC(FSOUND_Record_GetDriver, "_FSOUND_Record_GetDriver@0"); + F_GETPROC(FSOUND_Record_StartSample, "_FSOUND_Record_StartSample@8"); + F_GETPROC(FSOUND_Record_Stop, "_FSOUND_Record_Stop@0"); + F_GETPROC(FSOUND_Record_GetPosition, "_FSOUND_Record_GetPosition@0"); + F_GETPROC(FSOUND_File_SetCallbacks, "_FSOUND_File_SetCallbacks@20"); + F_GETPROC(FMUSIC_LoadSong, "_FMUSIC_LoadSong@4"); + F_GETPROC(FMUSIC_LoadSongEx, "_FMUSIC_LoadSongEx@24"); + F_GETPROC(FMUSIC_GetOpenState, "_FMUSIC_GetOpenState@4"); + F_GETPROC(FMUSIC_FreeSong, "_FMUSIC_FreeSong@4"); + F_GETPROC(FMUSIC_PlaySong, "_FMUSIC_PlaySong@4"); + F_GETPROC(FMUSIC_StopSong, "_FMUSIC_StopSong@4"); + F_GETPROC(FMUSIC_StopAllSongs, "_FMUSIC_StopAllSongs@0"); + F_GETPROC(FMUSIC_SetZxxCallback, "_FMUSIC_SetZxxCallback@8"); + F_GETPROC(FMUSIC_SetRowCallback, "_FMUSIC_SetRowCallback@12"); + F_GETPROC(FMUSIC_SetOrderCallback, "_FMUSIC_SetOrderCallback@12"); + F_GETPROC(FMUSIC_SetInstCallback, "_FMUSIC_SetInstCallback@12"); + F_GETPROC(FMUSIC_SetSample, "_FMUSIC_SetSample@12"); + F_GETPROC(FMUSIC_SetUserData, "_FMUSIC_SetUserData@8"); + F_GETPROC(FMUSIC_OptimizeChannels, "_FMUSIC_OptimizeChannels@12"); + F_GETPROC(FMUSIC_SetReverb, "_FMUSIC_SetReverb@4"); + F_GETPROC(FMUSIC_SetLooping, "_FMUSIC_SetLooping@8"); + F_GETPROC(FMUSIC_SetOrder, "_FMUSIC_SetOrder@8"); + F_GETPROC(FMUSIC_SetPaused, "_FMUSIC_SetPaused@8"); + F_GETPROC(FMUSIC_SetMasterVolume, "_FMUSIC_SetMasterVolume@8"); + F_GETPROC(FMUSIC_SetMasterSpeed, "_FMUSIC_SetMasterSpeed@8"); + F_GETPROC(FMUSIC_SetPanSeperation, "_FMUSIC_SetPanSeperation@8"); + F_GETPROC(FMUSIC_GetName, "_FMUSIC_GetName@4"); + F_GETPROC(FMUSIC_GetType, "_FMUSIC_GetType@4"); + F_GETPROC(FMUSIC_GetNumOrders, "_FMUSIC_GetNumOrders@4"); + F_GETPROC(FMUSIC_GetNumPatterns, "_FMUSIC_GetNumPatterns@4"); + F_GETPROC(FMUSIC_GetNumInstruments, "_FMUSIC_GetNumInstruments@4"); + F_GETPROC(FMUSIC_GetNumSamples, "_FMUSIC_GetNumSamples@4"); + F_GETPROC(FMUSIC_GetNumChannels, "_FMUSIC_GetNumChannels@4"); + F_GETPROC(FMUSIC_GetSample, "_FMUSIC_GetSample@8"); + F_GETPROC(FMUSIC_GetPatternLength, "_FMUSIC_GetPatternLength@8"); + F_GETPROC(FMUSIC_IsFinished, "_FMUSIC_IsFinished@4"); + F_GETPROC(FMUSIC_IsPlaying, "_FMUSIC_IsPlaying@4"); + F_GETPROC(FMUSIC_GetMasterVolume, "_FMUSIC_GetMasterVolume@4"); + F_GETPROC(FMUSIC_GetGlobalVolume, "_FMUSIC_GetGlobalVolume@4"); + F_GETPROC(FMUSIC_GetOrder, "_FMUSIC_GetOrder@4"); + F_GETPROC(FMUSIC_GetPattern, "_FMUSIC_GetPattern@4"); + F_GETPROC(FMUSIC_GetSpeed, "_FMUSIC_GetSpeed@4"); + F_GETPROC(FMUSIC_GetBPM, "_FMUSIC_GetBPM@4"); + F_GETPROC(FMUSIC_GetRow, "_FMUSIC_GetRow@4"); + F_GETPROC(FMUSIC_GetPaused, "_FMUSIC_GetPaused@4"); + F_GETPROC(FMUSIC_GetTime, "_FMUSIC_GetTime@4"); + F_GETPROC(FMUSIC_GetRealChannel, "_FMUSIC_GetRealChannel@8"); + F_GETPROC(FMUSIC_GetUserData, "_FMUSIC_GetUserData@4"); + + return instance; +} + +static void FMOD_FreeInstance(FMOD_INSTANCE *instance) +{ + if (instance) + { + if (instance->module) + { +#ifdef WIN32 + FreeLibrary((HMODULE)instance->module); +#else + dlclose(instance->module); +#endif + } + free(instance); + } +} + +#endif + diff --git a/main/source/includes/fmod/inc/wincompat.h b/main/source/includes/fmod/inc/wincompat.h index f6600017..3bdbc4f2 100644 --- a/main/source/includes/fmod/inc/wincompat.h +++ b/main/source/includes/fmod/inc/wincompat.h @@ -1,81 +1,81 @@ -#if !defined(WINCOMPAT_INCLUDED) && !defined(PLATFORM_WINDOWS) && !defined(WIN32) && !defined(WINDOWS) && !defined(__WIN32__) -#define WINCOMPAT_INCLUDED - -/** - * - * Author: Magnus Naeslund (mag@fbab.net, mag@bahnhof.se) - * (c) 2000 Magnus Naeslund, all rights reserved - * - */ - -#include -#include -#include -#include -#include -#include - -#ifndef TRUE - #define TRUE 1 -#endif -#ifndef FALSE - #define FALSE 0 -#endif - -#define _kbhit kbhit -#define stricmp strcasecmp -#define strnicmp strncasecmp - -#define Sleep(x) usleep((x)*1000) - -static int inited=0; -static struct termios ori; - -static void tcatexit(){ - tcsetattr(0,0,&ori); -} - -static void init_terminal(){ - struct termios t; - tcgetattr(0,&t); - tcgetattr(0,&ori); - t.c_lflag &= ~(ICANON); - tcsetattr(0,0,&t); - atexit(tcatexit); -} - -static inline int kbhit(){ - fd_set rfds; - struct timeval tv; - - if (!inited){ - inited=1; - init_terminal(); - } - - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 10*1000; - return select(1, &rfds, NULL, NULL, &tv)>0; -} - -static inline int getch(){ - fd_set rfds; - - if (!inited){ - inited=1; - init_terminal(); - } - - FD_ZERO(&rfds); - FD_SET(0, &rfds); - if (select(1, &rfds, NULL, NULL, NULL)>0) - return getchar(); - else{ - printf("wincompat.h: select() on fd 0 failed\n"); - return 0xDeadBeef; - } -} - -#endif +#if !defined(WINCOMPAT_INCLUDED) && !defined(PLATFORM_WINDOWS) && !defined(WIN32) && !defined(WINDOWS) && !defined(__WIN32__) +#define WINCOMPAT_INCLUDED + +/** + * + * Author: Magnus Naeslund (mag@fbab.net, mag@bahnhof.se) + * (c) 2000 Magnus Naeslund, all rights reserved + * + */ + +#include +#include +#include +#include +#include +#include + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#define _kbhit kbhit +#define stricmp strcasecmp +#define strnicmp strncasecmp + +#define Sleep(x) usleep((x)*1000) + +static int inited=0; +static struct termios ori; + +static void tcatexit(){ + tcsetattr(0,0,&ori); +} + +static void init_terminal(){ + struct termios t; + tcgetattr(0,&t); + tcgetattr(0,&ori); + t.c_lflag &= ~(ICANON); + tcsetattr(0,0,&t); + atexit(tcatexit); +} + +static inline int kbhit(){ + fd_set rfds; + struct timeval tv; + + if (!inited){ + inited=1; + init_terminal(); + } + + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 10*1000; + return select(1, &rfds, NULL, NULL, &tv)>0; +} + +static inline int getch(){ + fd_set rfds; + + if (!inited){ + inited=1; + init_terminal(); + } + + FD_ZERO(&rfds); + FD_SET(0, &rfds); + if (select(1, &rfds, NULL, NULL, NULL)>0) + return getchar(); + else{ + printf("wincompat.h: select() on fd 0 failed\n"); + return 0xDeadBeef; + } +} + +#endif diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMOD.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMOD.html index 49dc4c4e..f913a01f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMOD.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMOD.html @@ -1,457 +1,457 @@ - - - - -FMOD - - - -

FMOD

- - - - - - - - - -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMOD + + + +

FMOD

+ + + + + + + + + +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMOD_ERRORS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMOD_ERRORS.html index f20f558e..8563af07 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMOD_ERRORS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMOD_ERRORS.html @@ -1,95 +1,95 @@ - - - - -FMOD_ERRORS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FMOD_ERRORS

-On failure of commands in FMOD, use FSOUND_GetError to attain what happened.
-

-

Enumerators

- - - - - - - - - - - - - - - - - - - - - -
FMOD_ERR_NONE/* No errors */
-
FMOD_ERR_BUSY/* Cannot call this command after FSOUND_Init. Call FSOUND_Close first. */
-
FMOD_ERR_UNINITIALIZED/* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */
-
FMOD_ERR_INIT/* Error initializing output device. */
-
FMOD_ERR_ALLOCATED/* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */
-
FMOD_ERR_PLAY/* Playing the sound failed. */
-
FMOD_ERR_OUTPUT_FORMAT/* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */
-
FMOD_ERR_COOPERATIVELEVEL/* Error setting cooperative level for hardware. */
-
FMOD_ERR_CREATEBUFFER/* Error creating hardware sound buffer. */
-
FMOD_ERR_FILE_NOTFOUND/* File not found */
-
FMOD_ERR_FILE_FORMAT/* Unknown file format */
-
FMOD_ERR_FILE_BAD/* Error loading file */
-
FMOD_ERR_MEMORY/* Not enough memory or resources */
-
FMOD_ERR_VERSION/* The version number of this file format is not supported */
-
FMOD_ERR_INVALID_PARAM/* An invalid parameter was passed to this function */
-
FMOD_ERR_NO_EAX/* Tried to use an EAX command on a non EAX enabled channel or output. */
-
FMOD_ERR_CHANNEL_ALLOC/* Failed to allocate a new channel */
-
FMOD_ERR_RECORD/* Recording is not supported on this machine */
-
FMOD_ERR_MEDIAPLAYER/* Windows Media Player not installed so cannot play wma or use internet streaming. */
-
FMOD_ERR_CDDEVICE/* An error occured trying to open the specified CD device */
-
-

See Also

-FSOUND_Close -, -FSOUND_GetError -, -FSOUND_Init -, -FSOUND_SetOutput -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMOD_ERRORS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FMOD_ERRORS

+On failure of commands in FMOD, use FSOUND_GetError to attain what happened.
+

+

Enumerators

+ + + + + + + + + + + + + + + + + + + + + +
FMOD_ERR_NONE/* No errors */
+
FMOD_ERR_BUSY/* Cannot call this command after FSOUND_Init. Call FSOUND_Close first. */
+
FMOD_ERR_UNINITIALIZED/* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */
+
FMOD_ERR_INIT/* Error initializing output device. */
+
FMOD_ERR_ALLOCATED/* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */
+
FMOD_ERR_PLAY/* Playing the sound failed. */
+
FMOD_ERR_OUTPUT_FORMAT/* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */
+
FMOD_ERR_COOPERATIVELEVEL/* Error setting cooperative level for hardware. */
+
FMOD_ERR_CREATEBUFFER/* Error creating hardware sound buffer. */
+
FMOD_ERR_FILE_NOTFOUND/* File not found */
+
FMOD_ERR_FILE_FORMAT/* Unknown file format */
+
FMOD_ERR_FILE_BAD/* Error loading file */
+
FMOD_ERR_MEMORY/* Not enough memory or resources */
+
FMOD_ERR_VERSION/* The version number of this file format is not supported */
+
FMOD_ERR_INVALID_PARAM/* An invalid parameter was passed to this function */
+
FMOD_ERR_NO_EAX/* Tried to use an EAX command on a non EAX enabled channel or output. */
+
FMOD_ERR_CHANNEL_ALLOC/* Failed to allocate a new channel */
+
FMOD_ERR_RECORD/* Recording is not supported on this machine */
+
FMOD_ERR_MEDIAPLAYER/* Windows Media Player not installed so cannot play wma or use internet streaming. */
+
FMOD_ERR_CDDEVICE/* An error occured trying to open the specified CD device */
+
+

See Also

+FSOUND_Close +, +FSOUND_GetError +, +FSOUND_Init +, +FSOUND_SetOutput +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC.html index c0994799..de302b37 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC.html @@ -1,194 +1,194 @@ - - - - -FMUSIC API Reference - - - - - - - - - - - -
- - - -Previous Topic -Index - -Next Topic - -
-
-
-

FMUSIC API Reference

-FMOD Api. Use this to module files etc
-

-Functions , Structures , Defines , Enums -

-

-

-- -Functions -
-

- -

-

-

-- -Structures -
-

- -

-

-

-- -Defines -
-

- -

-

-

-- -Enums -
-

- - -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC API Reference + + + + + + + + + + + +
+ + + +Previous Topic +Index + +Next Topic + +
+
+
+

FMUSIC API Reference

+FMOD Api. Use this to module files etc
+

+Functions , Structures , Defines , Enums +

+

+

+- +Functions +
+

+ +

+

+

+- +Structures +
+

+ +

+

+

+- +Defines +
+

+ +

+

+

+- +Enums +
+

+ + +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_CALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_CALLBACK.html index 6703c412..7714e8c7 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_CALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_CALLBACK.html @@ -1,69 +1,69 @@ - - - - -FMUSIC_CALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_CALLBACK

-Callback definition for FMUSIC callbacks (mod/s3m/xm/it).
-

-void F_CALLBACKAPI FMUSIC_CALLBACK(
-FMUSIC_MODULE *mod,
-unsigned char param
-);
-

Parameters

- - - -
modThe music file to have callbacks performed on.
-
paramThe argument relating specifically to the callback made, whether it is a row/order or Zxx callback. For example on the row callback, the row number would be returned.
-
-

Return Value

-void
-

Remarks

-The callbacks are made from within the mixer system, so it is best to keep the code to an absolute minimum to prevent sound breakup.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetInstCallback -, -FMUSIC_SetOrderCallback -, -FMUSIC_SetRowCallback -, -FMUSIC_SetZxxCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_CALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_CALLBACK

+Callback definition for FMUSIC callbacks (mod/s3m/xm/it).
+

+void F_CALLBACKAPI FMUSIC_CALLBACK(
+FMUSIC_MODULE *mod,
+unsigned char param
+);
+

Parameters

+ + + +
modThe music file to have callbacks performed on.
+
paramThe argument relating specifically to the callback made, whether it is a row/order or Zxx callback. For example on the row callback, the row number would be returned.
+
+

Return Value

+void
+

Remarks

+The callbacks are made from within the mixer system, so it is best to keep the code to an absolute minimum to prevent sound breakup.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetInstCallback +, +FMUSIC_SetOrderCallback +, +FMUSIC_SetRowCallback +, +FMUSIC_SetZxxCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_FreeSong.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_FreeSong.html index 6d52f71a..3330b317 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_FreeSong.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_FreeSong.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_FreeSong - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_FreeSong

-Frees memory allocated for a song and removes it from the FMUSIC system.
-

-signed char F_API FMUSIC_FreeSong(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to be freed.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-

See Also

-FMUSIC_LoadSong -, -FMUSIC_LoadSongEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_FreeSong + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_FreeSong

+Frees memory allocated for a song and removes it from the FMUSIC system.
+

+signed char F_API FMUSIC_FreeSong(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to be freed.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+

See Also

+FMUSIC_LoadSong +, +FMUSIC_LoadSongEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetBPM.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetBPM.html index 0d022dd6..76212582 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetBPM.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetBPM.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetBPM - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetBPM

-Returns the song's current BPM.
-

-int F_API FMUSIC_GetBPM(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve current song BPM from.
-
-

Return Value

-On success, song's current BPM is returned.
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetSpeed -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetBPM + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetBPM

+Returns the song's current BPM.
+

+int F_API FMUSIC_GetBPM(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve current song BPM from.
+
+

Return Value

+On success, song's current BPM is returned.
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetSpeed +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetGlobalVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetGlobalVolume.html index c64d6497..863962bd 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetGlobalVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetGlobalVolume.html @@ -1,73 +1,73 @@ - - - - -FMUSIC_GetGlobalVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetGlobalVolume

-Returns the song's current global volume
-

-int F_API FMUSIC_GetGlobalVolume(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve song global volume from.
-
-

Return Value

-Songs current global volume, from 0 (silence) to the maximum value
-determined by the music format. Global volume maximums are different in
-respect to each format, they range from 64 to 256.
-On failure, -1 is returned.
-

Remarks

-GLOBAL volume is not the same as MASTER volume. GLOBAL volume is an internal
-overall volume which can be altered by the song itself (ie there might be commands
-to fade in a particular part of the song by scaling all the volumes in the song
-up slowly from nothing).
-GLOBAL volume is different to MASTER volume in that the song can modify without
-your permission, whereas MASTER volume is an overall scalar that you can control.
-For general use, MASTER volume is more useful, but you may want to reset a song's
-GLOBAL volume at certain times in the song. (for example the song might have faded
-out by using GLOBAL volume and you want to reset it)
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetMasterVolume -, -FMUSIC_SetMasterVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetGlobalVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetGlobalVolume

+Returns the song's current global volume
+

+int F_API FMUSIC_GetGlobalVolume(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve song global volume from.
+
+

Return Value

+Songs current global volume, from 0 (silence) to the maximum value
+determined by the music format. Global volume maximums are different in
+respect to each format, they range from 64 to 256.
+On failure, -1 is returned.
+

Remarks

+GLOBAL volume is not the same as MASTER volume. GLOBAL volume is an internal
+overall volume which can be altered by the song itself (ie there might be commands
+to fade in a particular part of the song by scaling all the volumes in the song
+up slowly from nothing).
+GLOBAL volume is different to MASTER volume in that the song can modify without
+your permission, whereas MASTER volume is an overall scalar that you can control.
+For general use, MASTER volume is more useful, but you may want to reset a song's
+GLOBAL volume at certain times in the song. (for example the song might have faded
+out by using GLOBAL volume and you want to reset it)
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetMasterVolume +, +FMUSIC_SetMasterVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetMasterVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetMasterVolume.html index 6dfc5a88..9aa47f35 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetMasterVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetMasterVolume.html @@ -1,62 +1,62 @@ - - - - -FMUSIC_GetMasterVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetMasterVolume

-Returns the song's current master volume
-

-int F_API FMUSIC_GetMasterVolume(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve song master volume from.
-
-

Return Value

-On success, the song's current master volume, from 0 (silence) to 256 (full volume) is returned
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetGlobalVolume -, -FMUSIC_SetMasterVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetMasterVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetMasterVolume

+Returns the song's current master volume
+

+int F_API FMUSIC_GetMasterVolume(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve song master volume from.
+
+

Return Value

+On success, the song's current master volume, from 0 (silence) to 256 (full volume) is returned
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetGlobalVolume +, +FMUSIC_SetMasterVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetName.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetName.html index c06c553a..41e7e132 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetName.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetName.html @@ -1,58 +1,58 @@ - - - - -FMUSIC_GetName - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetName

-Returns the name of the song set by the composer. With MIDI format, the filename is returned.
-

-const char * F_API FMUSIC_GetName(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve name from.
-
-

Return Value

-On success, the name of the song as a NULL terminated string is returned.
-On failure, NULL is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetName + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetName

+Returns the name of the song set by the composer. With MIDI format, the filename is returned.
+

+const char * F_API FMUSIC_GetName(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve name from.
+
+

Return Value

+On success, the name of the song as a NULL terminated string is returned.
+On failure, NULL is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumChannels.html index 99bf8838..1449e2fb 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumChannels.html @@ -1,58 +1,58 @@ - - - - -FMUSIC_GetNumChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetNumChannels

-Returns the number of channels within this songs pattern data
-

-int F_API FMUSIC_GetNumChannels(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve number of channels from.
-
-

Return Value

-Number of channels within this songs pattern data
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetNumChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetNumChannels

+Returns the number of channels within this songs pattern data
+

+int F_API FMUSIC_GetNumChannels(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve number of channels from.
+
+

Return Value

+Number of channels within this songs pattern data
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumInstruments.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumInstruments.html index 3c58e9a0..ddd2244a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumInstruments.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumInstruments.html @@ -1,58 +1,58 @@ - - - - -FMUSIC_GetNumInstruments - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetNumInstruments

-Returns the number of instruments contained in this song.
-

-int F_API FMUSIC_GetNumInstruments(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve number of instruments from.
-
-

Return Value

-On success, the number of instruments contained in this song is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetNumInstruments + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetNumInstruments

+Returns the number of instruments contained in this song.
+

+int F_API FMUSIC_GetNumInstruments(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve number of instruments from.
+
+

Return Value

+On success, the number of instruments contained in this song is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumOrders.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumOrders.html index db4d4f12..cda92f11 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumOrders.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumOrders.html @@ -1,58 +1,58 @@ - - - - -FMUSIC_GetNumOrders - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetNumOrders

-Returns the number of orders in this song.
-

-int F_API FMUSIC_GetNumOrders(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve number of orders from.
-
-

Return Value

-On success, the number of orders in this song is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetNumOrders + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetNumOrders

+Returns the number of orders in this song.
+

+int F_API FMUSIC_GetNumOrders(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve number of orders from.
+
+

Return Value

+On success, the number of orders in this song is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumPatterns.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumPatterns.html index dfb3e7dd..6850ab81 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumPatterns.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumPatterns.html @@ -1,58 +1,58 @@ - - - - -FMUSIC_GetNumPatterns - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetNumPatterns

-Returns the number of patterns contained in this song.
-

-int F_API FMUSIC_GetNumPatterns(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve number of patterns.
-
-

Return Value

-On success, the number of patterns contained in this song is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetNumPatterns + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetNumPatterns

+Returns the number of patterns contained in this song.
+

+int F_API FMUSIC_GetNumPatterns(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve number of patterns.
+
+

Return Value

+On success, the number of patterns contained in this song is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumSamples.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumSamples.html index 1843453d..eab39b38 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumSamples.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetNumSamples.html @@ -1,58 +1,58 @@ - - - - -FMUSIC_GetNumSamples - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetNumSamples

-Returns the number of samples contained in this song.
-

-int F_API FMUSIC_GetNumSamples(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve number of samples.
-
-

Return Value

-Number of samples contained in this song.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetNumSamples + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetNumSamples

+Returns the number of samples contained in this song.
+

+int F_API FMUSIC_GetNumSamples(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve number of samples.
+
+

Return Value

+Number of samples contained in this song.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOpenState.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOpenState.html index 7640080b..539afa18 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOpenState.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOpenState.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetOpenState - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetOpenState

-If a mod is opened with FSOUND_NONBLOCKING, this function returns the state of the opening mod.
-

-int F_API FMUSIC_GetOpenState(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the mod to get the open state from.
-
-

Return Value

-0 = mod is opened and ready.
--1 = mod handle passed in is invalid.
--2 = mod is still opening
--3 = mod failed to open. (file not found, out of memory or other error).
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetOpenState + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetOpenState

+If a mod is opened with FSOUND_NONBLOCKING, this function returns the state of the opening mod.
+

+int F_API FMUSIC_GetOpenState(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the mod to get the open state from.
+
+

Return Value

+0 = mod is opened and ready.
+-1 = mod handle passed in is invalid.
+-2 = mod is still opening
+-3 = mod failed to open. (file not found, out of memory or other error).
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOrder.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOrder.html index 8a12c5d6..2f29add1 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOrder.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetOrder.html @@ -1,66 +1,66 @@ - - - - -FMUSIC_GetOrder - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetOrder

-Returns the song's current order number
-

-int F_API FMUSIC_GetOrder(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve current order number from.
-
-

Return Value

-On success, the song's current order number is returned.
-On failure, -1 is returned.
-

Remarks

-This value is latency adjusted by default, and returns the number you are hearing, not the 'mix-time' value.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want the value at mix time, which is useful if you want to control the music interactively, or from a DSP callback.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetPattern -, -FMUSIC_GetPatternLength -, -FMUSIC_SetOrder -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetOrder + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetOrder

+Returns the song's current order number
+

+int F_API FMUSIC_GetOrder(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve current order number from.
+
+

Return Value

+On success, the song's current order number is returned.
+On failure, -1 is returned.
+

Remarks

+This value is latency adjusted by default, and returns the number you are hearing, not the 'mix-time' value.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want the value at mix time, which is useful if you want to control the music interactively, or from a DSP callback.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetPattern +, +FMUSIC_GetPatternLength +, +FMUSIC_SetOrder +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPattern.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPattern.html index 4864de7c..2bc901cd 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPattern.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPattern.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetPattern - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetPattern

-Returns the song's current pattern number
-

-int F_API FMUSIC_GetPattern(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve current pattern number from.
-
-

Return Value

-On success, The song's current pattern number is returned.
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetOrder -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:25 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetPattern + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetPattern

+Returns the song's current pattern number
+

+int F_API FMUSIC_GetPattern(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve current pattern number from.
+
+

Return Value

+On success, The song's current pattern number is returned.
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetOrder +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:25 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPatternLength.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPatternLength.html index 2de4736b..03b619a4 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPatternLength.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPatternLength.html @@ -1,61 +1,61 @@ - - - - -FMUSIC_GetPatternLength - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetPatternLength

-Returns the the length in rows of the pattern for the specified order number.
-

-int F_API FMUSIC_GetPatternLength(
-FMUSIC_MODULE *mod,
-int orderno
-);
-

Parameters

- - -
modPointer to the song to .
-
-

Return Value

-On success, the songs pattern length at the specified order is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetOrder -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetPatternLength + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetPatternLength

+Returns the the length in rows of the pattern for the specified order number.
+

+int F_API FMUSIC_GetPatternLength(
+FMUSIC_MODULE *mod,
+int orderno
+);
+

Parameters

+ + +
modPointer to the song to .
+
+

Return Value

+On success, the songs pattern length at the specified order is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetOrder +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPaused.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPaused.html index 57923b35..784dcde8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPaused.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetPaused.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetPaused - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetPaused

-Returns whether song is currently paused or not.
-

-signed char F_API FMUSIC_GetPaused(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to get paused flag from.
-
-

Return Value

-On success, TRUE is returned to say the song is currently paused
-On failure, FALSE is returned to say the song is NOT currently paused
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetPaused -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetPaused + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetPaused

+Returns whether song is currently paused or not.
+

+signed char F_API FMUSIC_GetPaused(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to get paused flag from.
+
+

Return Value

+On success, TRUE is returned to say the song is currently paused
+On failure, FALSE is returned to say the song is NOT currently paused
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetPaused +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRealChannel.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRealChannel.html index 1ce468b6..bc8eb612 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRealChannel.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRealChannel.html @@ -1,63 +1,63 @@ - - - - -FMUSIC_GetRealChannel - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetRealChannel

-Returns the real FSOUND channel playing based on the mod's FMUSIC channel.
-

-int F_API FMUSIC_GetRealChannel(
-FMUSIC_MODULE *mod,
-int modchannel
-);
-

Parameters

- - - -
modPointer to the song.
-
modchannelThe mod channel index, to query the real channel from.
-
-

Return Value

-On success, the channel index for the respective mod channel is returned.
-On failure, -1 is returned.
-

Remarks

-Note FMUSIC mod playback only allocates a real channel on a mod channel the first time an instrument is played.
-NNA's will not register. This function only returns the primary real channel for the mod channel.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetRealChannel + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetRealChannel

+Returns the real FSOUND channel playing based on the mod's FMUSIC channel.
+

+int F_API FMUSIC_GetRealChannel(
+FMUSIC_MODULE *mod,
+int modchannel
+);
+

Parameters

+ + + +
modPointer to the song.
+
modchannelThe mod channel index, to query the real channel from.
+
+

Return Value

+On success, the channel index for the respective mod channel is returned.
+On failure, -1 is returned.
+

Remarks

+Note FMUSIC mod playback only allocates a real channel on a mod channel the first time an instrument is played.
+NNA's will not register. This function only returns the primary real channel for the mod channel.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRow.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRow.html index 98486654..73489abd 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRow.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetRow.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetRow - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetRow

-Returns the song's current row number.
-

-int F_API FMUSIC_GetRow(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve current row from.
-
-

Return Value

-On success, the song's current row number is returned.
-On failure, -1 is returned.
-

Remarks

-This value is latency adjusted by default, and returns the number you are hearing, not the 'mix-time' value.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want the value at mix time, which is useful if you want to control the music interactively, or from a DSP callback.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetRow + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetRow

+Returns the song's current row number.
+

+int F_API FMUSIC_GetRow(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve current row from.
+
+

Return Value

+On success, the song's current row number is returned.
+On failure, -1 is returned.
+

Remarks

+This value is latency adjusted by default, and returns the number you are hearing, not the 'mix-time' value.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want the value at mix time, which is useful if you want to control the music interactively, or from a DSP callback.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSample.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSample.html index 565f778d..7955f3ca 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSample.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSample.html @@ -1,71 +1,71 @@ - - - - -FMUSIC_GetSample - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetSample

-Returns a pointer to a sample inside a module.
-Once you have access to the module's sample, you can do a lot of things
-to it, including locking and modifying the data within; using the
-FSOUND_Sample_ functionality.
-

-FSOUND_SAMPLE * F_API FMUSIC_GetSample(
-FMUSIC_MODULE *mod,
-int sampno
-);
-

Parameters

- - - -
modPointer to the song to retrieve a sample handle from
-
sampnoindex to sample inside module.
-
-

Return Value

-On success, a valid sample handle is returned.
-On failure, NULL is returned.
-

Remarks

-Because of the instrument nature of some formats like XM, this
-function lists all the samples in order of instruments and their subsamples.
-ie if instrument 1 has 2 samples and instrument 2 contains 3 samples, then
-sampno in this case would be 0 and 1 for instrument 1's samples, and 2,3 & 4
-for instrument 2's samples.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetSample -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetSample + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetSample

+Returns a pointer to a sample inside a module.
+Once you have access to the module's sample, you can do a lot of things
+to it, including locking and modifying the data within; using the
+FSOUND_Sample_ functionality.
+

+FSOUND_SAMPLE * F_API FMUSIC_GetSample(
+FMUSIC_MODULE *mod,
+int sampno
+);
+

Parameters

+ + + +
modPointer to the song to retrieve a sample handle from
+
sampnoindex to sample inside module.
+
+

Return Value

+On success, a valid sample handle is returned.
+On failure, NULL is returned.
+

Remarks

+Because of the instrument nature of some formats like XM, this
+function lists all the samples in order of instruments and their subsamples.
+ie if instrument 1 has 2 samples and instrument 2 contains 3 samples, then
+sampno in this case would be 0 and 1 for instrument 1's samples, and 2,3 & 4
+for instrument 2's samples.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetSample +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSpeed.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSpeed.html index b52a7754..3f5a1d00 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSpeed.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetSpeed.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetSpeed - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetSpeed

-Returns the song's current speed.
-

-int F_API FMUSIC_GetSpeed(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve current song speed from.
-
-

Return Value

-On success, The song's current speed is returned
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetBPM -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetSpeed + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetSpeed

+Returns the song's current speed.
+

+int F_API FMUSIC_GetSpeed(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve current song speed from.
+
+

Return Value

+On success, The song's current speed is returned
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetBPM +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetTime.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetTime.html index 909d1869..07477572 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetTime.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetTime.html @@ -1,64 +1,64 @@ - - - - -FMUSIC_GetTime - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetTime

-Returns the time in milliseconds since the song was started. This is useful for
-synchronizing purposes becuase it will be exactly the same every time, and it is
-reliably retriggered upon starting the song. Trying to synchronize using other
-windows timers can lead to varying results, and inexact performance. This fixes that
-problem by actually using the number of samples sent to the soundcard as a reference.
-

-int F_API FMUSIC_GetTime(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to get time from.
-
-

Return Value

-On success, the time played in milliseconds is returned.
-On failure, -1 is returned.
-

Remarks

-This value is latency adjusted by default, and returns the number you are hearing, not the 'mix-time' value.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want the value at mix time, which is useful if you want to control the music interactively, or from a DSP callback.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetTime + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetTime

+Returns the time in milliseconds since the song was started. This is useful for
+synchronizing purposes becuase it will be exactly the same every time, and it is
+reliably retriggered upon starting the song. Trying to synchronize using other
+windows timers can lead to varying results, and inexact performance. This fixes that
+problem by actually using the number of samples sent to the soundcard as a reference.
+

+int F_API FMUSIC_GetTime(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to get time from.
+
+

Return Value

+On success, the time played in milliseconds is returned.
+On failure, -1 is returned.
+

Remarks

+This value is latency adjusted by default, and returns the number you are hearing, not the 'mix-time' value.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want the value at mix time, which is useful if you want to control the music interactively, or from a DSP callback.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetType.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetType.html index 1d87bd8b..4a8dee26 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetType.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetType.html @@ -1,66 +1,66 @@ - - - - -FMUSIC_GetType - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetType

-Returns the format type a song.
-

-int F_API FMUSIC_GetType(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve name from.
-
-

Return Value

-On success, the following values are returned:
-FMUSIC_TYPE_NONE
-FMUSIC_TYPE_MOD
-FMUSIC_TYPE_S3M
-FMUSIC_TYPE_XM
-FMUSIC_TYPE_IT
-FMUSIC_TYPE_MIDI
-On failure, FMUSIC_TYPE_NONE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_TYPES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetType + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetType

+Returns the format type a song.
+

+int F_API FMUSIC_GetType(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve name from.
+
+

Return Value

+On success, the following values are returned:
+FMUSIC_TYPE_NONE
+FMUSIC_TYPE_MOD
+FMUSIC_TYPE_S3M
+FMUSIC_TYPE_XM
+FMUSIC_TYPE_IT
+FMUSIC_TYPE_MIDI
+On failure, FMUSIC_TYPE_NONE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_TYPES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetUserData.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetUserData.html index 892064fb..b3d8ff49 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetUserData.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_GetUserData.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_GetUserData - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_GetUserData

-Retrieves the data set by FMUSIC_SetUserData
-

-void * F_API FMUSIC_GetUserData(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song.
-
-

Return Value

-On success, userdata set by FMUSIC_SetUserData is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetUserData -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_GetUserData + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_GetUserData

+Retrieves the data set by FMUSIC_SetUserData
+

+void * F_API FMUSIC_GetUserData(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song.
+
+

Return Value

+On success, userdata set by FMUSIC_SetUserData is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetUserData +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsFinished.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsFinished.html index 36bec5b5..5e1837e0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsFinished.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsFinished.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_IsFinished - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_IsFinished

-Returns whether the song has completed playing, or when the last order has finished playing.
-This stays set even if the song loops.
-

-signed char F_API FMUSIC_IsFinished(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song that you want check if finished or not.
-
-

Return Value

-TRUE Song has finished playing.
-FALSE Song has not finished playing.
-

Remarks

-Some songs may use a pattern break or pattern jump and never reach the last pattern.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_IsFinished + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_IsFinished

+Returns whether the song has completed playing, or when the last order has finished playing.
+This stays set even if the song loops.
+

+signed char F_API FMUSIC_IsFinished(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song that you want check if finished or not.
+
+

Return Value

+TRUE Song has finished playing.
+FALSE Song has not finished playing.
+

Remarks

+Some songs may use a pattern break or pattern jump and never reach the last pattern.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsPlaying.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsPlaying.html index 5d4a17e6..8a1bc1bc 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsPlaying.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_IsPlaying.html @@ -1,60 +1,60 @@ - - - - -FMUSIC_IsPlaying - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_IsPlaying

-Returns whether the song is currently playing or not.
-

-signed char F_API FMUSIC_IsPlaying(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to retrieve name from.
-
-

Return Value

-TRUE Song is playing.
-FALSE Song is stopped.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_PlaySong -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_IsPlaying + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_IsPlaying

+Returns whether the song is currently playing or not.
+

+signed char F_API FMUSIC_IsPlaying(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to retrieve name from.
+
+

Return Value

+TRUE Song is playing.
+FALSE Song is stopped.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_PlaySong +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSong.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSong.html index c977ed2a..6ac30090 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSong.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSong.html @@ -1,78 +1,78 @@ - - - - -FMUSIC_LoadSong - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_LoadSong

-To load a module or bank with a given filename. FMUSIC Supports loading of
-- .MOD (protracker/fasttracker modules)
-- .S3M (screamtracker 3 modules)
-- .XM (fasttracker 2 modules)
-- .IT (impulse tracker modules)
-- .MID (MIDI files)
-- .RMI (MIDI files)
-- .SGT (DirectMusic segment files)
-- .FSB (FMOD Sample Bank files)
-

-FMUSIC_MODULE * F_API FMUSIC_LoadSong(
-const char *name
-);
-

Parameters

- - -
nameFilename of module to load.
-
-

Return Value

-On success, a pointer to a FMUSIC_MODULE handle is returned.
-On failure, NULL is returned.
-

Remarks

-This function autodetects the format type, regardless of filename.
-The MIDI loader does not support user file callbacks. For WAD type data structures with embedded MIDI files FMUSIC_LoadSongEx will have to be used with memory loading.
-Various other functionality is not provided in MIDI. See relevant FMUSIC functions to see if a feature
-is supported or not.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_FreeSong -, -FMUSIC_LoadSong -, -FMUSIC_LoadSongEx -, -FSOUND_File_SetCallbacks -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_LoadSong + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_LoadSong

+To load a module or bank with a given filename. FMUSIC Supports loading of
+- .MOD (protracker/fasttracker modules)
+- .S3M (screamtracker 3 modules)
+- .XM (fasttracker 2 modules)
+- .IT (impulse tracker modules)
+- .MID (MIDI files)
+- .RMI (MIDI files)
+- .SGT (DirectMusic segment files)
+- .FSB (FMOD Sample Bank files)
+

+FMUSIC_MODULE * F_API FMUSIC_LoadSong(
+const char *name
+);
+

Parameters

+ + +
nameFilename of module to load.
+
+

Return Value

+On success, a pointer to a FMUSIC_MODULE handle is returned.
+On failure, NULL is returned.
+

Remarks

+This function autodetects the format type, regardless of filename.
+The MIDI loader does not support user file callbacks. For WAD type data structures with embedded MIDI files FMUSIC_LoadSongEx will have to be used with memory loading.
+Various other functionality is not provided in MIDI. See relevant FMUSIC functions to see if a feature
+is supported or not.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_FreeSong +, +FMUSIC_LoadSong +, +FMUSIC_LoadSongEx +, +FSOUND_File_SetCallbacks +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSongEx.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSongEx.html index ca5ba07f..8293b373 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSongEx.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_LoadSongEx.html @@ -1,89 +1,89 @@ - - - - -FMUSIC_LoadSongEx - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_LoadSongEx

-To load a module or bank with a given filename. FMUSIC Supports loading of
-- .MOD (protracker/fasttracker modules)
-- .S3M (screamtracker 3 modules)
-- .XM (fasttracker 2 modules)
-- .IT (impulse tracker modules)
-- .MID (MIDI files)
-- .RMI (MIDI files)
-- .SGT (DirectMusic segment files)
-- .FSB (FMOD Sample Bank files)
-

-FMUSIC_MODULE * F_API FMUSIC_LoadSongEx(
-const char *name_or_data,
-int offset,
-int length,
-unsigned int mode,
-const int *samplelist,
-int samplelistnum
-);
-

Parameters

- - - - - - - -
name_or_dataName of song or pointer to data containing song to load (if loading from memory and not file). On PlayStation 2 data must be 16 byte aligned if loading from memory.
-
offsetOptional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening.
-
lengthOptional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
-
modeMode for opening song. With module files, only FSOUND_LOADMEMORY, FSOUND_NONBLOCKING, FSOUND_LOOP_NORMAL, or FSOUND_LOOP_OFF are supported. For FSB files, FSOUND_2D, FSOUND_HW3D, FSOUND_FORCEMONO also work.
-
samplelistOptional. Pointer to array of sample indicies to load. Leave as NULL if you want all samples to be loaded (default behaviour). See Remarks for more on this.
-
samplelistnumOptional. Number of entries in the samplelist array.
-
-

Return Value

-On success, a FMUSIC_MODULE handle is returned.
-On failure, NULL is returned.
-

Remarks

-Loading a song from a memory handle is dangerous in one respect, if the data is corrupted or truncated, then FMUSIC could crash internally trying to load it.
-On PlayStation 2 the data and length pointer must be 16 byte aligned for DMA purposes.
-The samplelist and samplelistnum parameters are useful for limiting the amount of data fmod loads. This feature is for the FSB format only. It is especially useful if you have a bank of sounds and want to randomize the loading a bit by telling which sounds to load with random values, and consequently which not to load.
-On PlayStation 2, samplelistnum has a limit of 1536 entries.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation2, GameCube
-

See Also

-FMUSIC_FreeSong -, -FMUSIC_LoadSong -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_LoadSongEx + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_LoadSongEx

+To load a module or bank with a given filename. FMUSIC Supports loading of
+- .MOD (protracker/fasttracker modules)
+- .S3M (screamtracker 3 modules)
+- .XM (fasttracker 2 modules)
+- .IT (impulse tracker modules)
+- .MID (MIDI files)
+- .RMI (MIDI files)
+- .SGT (DirectMusic segment files)
+- .FSB (FMOD Sample Bank files)
+

+FMUSIC_MODULE * F_API FMUSIC_LoadSongEx(
+const char *name_or_data,
+int offset,
+int length,
+unsigned int mode,
+const int *samplelist,
+int samplelistnum
+);
+

Parameters

+ + + + + + + +
name_or_dataName of song or pointer to data containing song to load (if loading from memory and not file). On PlayStation 2 data must be 16 byte aligned if loading from memory.
+
offsetOptional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening.
+
lengthOptional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
+
modeMode for opening song. With module files, only FSOUND_LOADMEMORY, FSOUND_NONBLOCKING, FSOUND_LOOP_NORMAL, or FSOUND_LOOP_OFF are supported. For FSB files, FSOUND_2D, FSOUND_HW3D, FSOUND_FORCEMONO also work.
+
samplelistOptional. Pointer to array of sample indicies to load. Leave as NULL if you want all samples to be loaded (default behaviour). See Remarks for more on this.
+
samplelistnumOptional. Number of entries in the samplelist array.
+
+

Return Value

+On success, a FMUSIC_MODULE handle is returned.
+On failure, NULL is returned.
+

Remarks

+Loading a song from a memory handle is dangerous in one respect, if the data is corrupted or truncated, then FMUSIC could crash internally trying to load it.
+On PlayStation 2 the data and length pointer must be 16 byte aligned for DMA purposes.
+The samplelist and samplelistnum parameters are useful for limiting the amount of data fmod loads. This feature is for the FSB format only. It is especially useful if you have a bank of sounds and want to randomize the loading a bit by telling which sounds to load with random values, and consequently which not to load.
+On PlayStation 2, samplelistnum has a limit of 1536 entries.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation2, GameCube
+

See Also

+FMUSIC_FreeSong +, +FMUSIC_LoadSong +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_OptimizeChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_OptimizeChannels.html index 9d7d5edd..09c19ff9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_OptimizeChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_OptimizeChannels.html @@ -1,87 +1,87 @@ - - - - -FMUSIC_OptimizeChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_OptimizeChannels

-This function helps with channel usage. If you are desperate for channels, and you are prepared to
-let the music routines drop a few channels, then calling this function can help.
-It basically doesnt try to play any new sounds if a certain channel limit is being played (including sound effects),
-and the new sound is below a certain specified volume.
-ie.
-You set it to maxchannels = 16, and minvolume = 0x10.
-In this case, the mod will play normally as long as the total number of channels being played inclusing sound effefcts is below 16
-(see FSOUND_GetChannelsPlaying).
-If the number of channels playing exceeds 16 (through a change in the music, or extra sound effects
-are spawned, then sounds with a musician specified volume of less than 0x10 will be ignored.
-The volume is based on volume column/default volume/volume set commands in the mod. master volume,
-envelope volumes etc are not taken into account (this gives more control over how it will work from the
-tracker).
-

-DLL_API signed char F_API FMUSIC_OptimizeChannels(
-FMUSIC_MODULE *mod,
-int maxchannels,
-int minvolume
-);
-

Parameters

- - - - -
modPointer to the song to set channel/volume optimization settings.
-
maxchannelsChannel count to be mixed before fmusic starts to drop channels from the song.
-
minvolumeIf maxchannels is exceeded, then music channels with volumes below this value will not be
-played. Range is 0-64. This is the value the tracker displays. All trackers use 0-64.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-maxchannels will default to the number of channels allocated by FSOUND, so this will never happen
-by default.
-minvolume will default to 0, so it will always succeed by default.
-To see how many channels are currently being MIXED, use FSOUND_GetChannelsPlaying.
-As a musician mentioned to me once, most of his default volumes are set fairly high, and any low end
-volumes are usually echoes etc, and can afford to be dropped.
-------------
-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetChannelsPlaying -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_OptimizeChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_OptimizeChannels

+This function helps with channel usage. If you are desperate for channels, and you are prepared to
+let the music routines drop a few channels, then calling this function can help.
+It basically doesnt try to play any new sounds if a certain channel limit is being played (including sound effects),
+and the new sound is below a certain specified volume.
+ie.
+You set it to maxchannels = 16, and minvolume = 0x10.
+In this case, the mod will play normally as long as the total number of channels being played inclusing sound effefcts is below 16
+(see FSOUND_GetChannelsPlaying).
+If the number of channels playing exceeds 16 (through a change in the music, or extra sound effects
+are spawned, then sounds with a musician specified volume of less than 0x10 will be ignored.
+The volume is based on volume column/default volume/volume set commands in the mod. master volume,
+envelope volumes etc are not taken into account (this gives more control over how it will work from the
+tracker).
+

+DLL_API signed char F_API FMUSIC_OptimizeChannels(
+FMUSIC_MODULE *mod,
+int maxchannels,
+int minvolume
+);
+

Parameters

+ + + + +
modPointer to the song to set channel/volume optimization settings.
+
maxchannelsChannel count to be mixed before fmusic starts to drop channels from the song.
+
minvolumeIf maxchannels is exceeded, then music channels with volumes below this value will not be
+played. Range is 0-64. This is the value the tracker displays. All trackers use 0-64.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+maxchannels will default to the number of channels allocated by FSOUND, so this will never happen
+by default.
+minvolume will default to 0, so it will always succeed by default.
+To see how many channels are currently being MIXED, use FSOUND_GetChannelsPlaying.
+As a musician mentioned to me once, most of his default volumes are set fairly high, and any low end
+volumes are usually echoes etc, and can afford to be dropped.
+------------
+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetChannelsPlaying +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_PlaySong.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_PlaySong.html index 7954d4c3..3f77c331 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_PlaySong.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_PlaySong.html @@ -1,66 +1,66 @@ - - - - -FMUSIC_PlaySong - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_PlaySong

-Starts a song playing.
-

-signed char F_API FMUSIC_PlaySong(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to be played.
-
-

Return Value

-TRUE song succeeded playing
-FALSE song failed playing
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_IsPlaying -, -FMUSIC_SetLooping -, -FMUSIC_StopAllSongs -, -FMUSIC_StopSong -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_PlaySong + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_PlaySong

+Starts a song playing.
+

+signed char F_API FMUSIC_PlaySong(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to be played.
+
+

Return Value

+TRUE song succeeded playing
+FALSE song failed playing
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_IsPlaying +, +FMUSIC_SetLooping +, +FMUSIC_StopAllSongs +, +FMUSIC_StopSong +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetInstCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetInstCallback.html index 19c9bac4..96da6764 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetInstCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetInstCallback.html @@ -1,84 +1,84 @@ - - - - -FMUSIC_SetInstCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetInstCallback

-Sets a user callback to occur every time a instrument is played, triggered from a MOD, S3M, XM or IT file.
-

-signed char F_API FMUSIC_SetInstCallback(
-FMUSIC_MODULE *mod,
-FMUSIC_CALLBACK callback,
-int instrument
-);
-

Parameters

- - - - -
modThe module or song to set the callback for.
-
callbackThe callback function you supply to get called.
-
instrumentCall the callback when this instrument number is triggered.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-It is important to note that this callback will be called from directly WITHIN the
-mixer / music update thread, therefore it is imperative that whatever you do from this
-callback be extremely efficient. If the routine takes too long then breakups in the sound
-will occur, or it will basically stop mixing until you return from the function.
-This sort of function is usually best for just setting a flag, or do some simple variable
-manipulation, and then exiting, letting your main thread do what it needs to based on these
-flags or variables.
-------------
-This callback is LATENCY adjusted, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
-------------
-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_CALLBACK -, -FMUSIC_SetOrderCallback -, -FMUSIC_SetRowCallback -, -FMUSIC_SetZxxCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetInstCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetInstCallback

+Sets a user callback to occur every time a instrument is played, triggered from a MOD, S3M, XM or IT file.
+

+signed char F_API FMUSIC_SetInstCallback(
+FMUSIC_MODULE *mod,
+FMUSIC_CALLBACK callback,
+int instrument
+);
+

Parameters

+ + + + +
modThe module or song to set the callback for.
+
callbackThe callback function you supply to get called.
+
instrumentCall the callback when this instrument number is triggered.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+It is important to note that this callback will be called from directly WITHIN the
+mixer / music update thread, therefore it is imperative that whatever you do from this
+callback be extremely efficient. If the routine takes too long then breakups in the sound
+will occur, or it will basically stop mixing until you return from the function.
+This sort of function is usually best for just setting a flag, or do some simple variable
+manipulation, and then exiting, letting your main thread do what it needs to based on these
+flags or variables.
+------------
+This callback is LATENCY adjusted, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
+------------
+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_CALLBACK +, +FMUSIC_SetOrderCallback +, +FMUSIC_SetRowCallback +, +FMUSIC_SetZxxCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetLooping.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetLooping.html index 4770a520..c687c544 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetLooping.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetLooping.html @@ -1,66 +1,66 @@ - - - - -FMUSIC_SetLooping - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetLooping

-Sets looping mode for midi and mod files.
-

-signed char F_API FMUSIC_SetLooping(
-FMUSIC_MODULE *mod,
-signed char looping
-);
-

Parameters

- - - -
modPointer to the song.
-
loopingSet to TRUE to make it loop forever, or FALSE to only have it play once.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Defaults to TRUE. To disable looping you must call this function using FALSE as the parameter.
-For midi files this only takes effect before FMUSIC_PlaySong is called. For mod files this
-can be called at any time including during playback.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_PlaySong -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetLooping + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetLooping

+Sets looping mode for midi and mod files.
+

+signed char F_API FMUSIC_SetLooping(
+FMUSIC_MODULE *mod,
+signed char looping
+);
+

Parameters

+ + + +
modPointer to the song.
+
loopingSet to TRUE to make it loop forever, or FALSE to only have it play once.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Defaults to TRUE. To disable looping you must call this function using FALSE as the parameter.
+For midi files this only takes effect before FMUSIC_PlaySong is called. For mod files this
+can be called at any time including during playback.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_PlaySong +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterSpeed.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterSpeed.html index e914d2b6..3911bad7 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterSpeed.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterSpeed.html @@ -1,61 +1,61 @@ - - - - -FMUSIC_SetMasterSpeed - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetMasterSpeed

-Sets a songs master speed scale, so that the song can be sped up or slowed down.
-

-signed char F_API FMUSIC_SetMasterSpeed(
-FMUSIC_MODULE *mod,
-F_FLOAT_API speed
-);
-

Parameters

- - - -
modPointer to the song to have its speed scale set.
-
speedSpeed scale for song. 1.0 is default. Minimum is 0 (stopped), maximum is 10.0.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetMasterSpeed + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetMasterSpeed

+Sets a songs master speed scale, so that the song can be sped up or slowed down.
+

+signed char F_API FMUSIC_SetMasterSpeed(
+FMUSIC_MODULE *mod,
+F_FLOAT_API speed
+);
+

Parameters

+ + + +
modPointer to the song to have its speed scale set.
+
speedSpeed scale for song. 1.0 is default. Minimum is 0 (stopped), maximum is 10.0.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterVolume.html index f1990742..f98ab697 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetMasterVolume.html @@ -1,71 +1,71 @@ - - - - -FMUSIC_SetMasterVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetMasterVolume

-Sets a songs master volume.
-

-signed char F_API FMUSIC_SetMasterVolume(
-FMUSIC_MODULE *mod,
-int volume
-);
-

Parameters

- - - -
modPointer to the song to have its master volume set.
-
volumevalue from 0-256. 0 = silence, 256 = full volume.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Note if the hardware midi synth is selected, you cannot set the master volume.
-This command will only work reliably if FSOUND_INIT_USEDEFAULTMIDISYNTH is selected.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetGlobalVolume -, -FMUSIC_GetMasterVolume -, -FSOUND_GetSFXMasterVolume -, -FSOUND_SetSFXMasterVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetMasterVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetMasterVolume

+Sets a songs master volume.
+

+signed char F_API FMUSIC_SetMasterVolume(
+FMUSIC_MODULE *mod,
+int volume
+);
+

Parameters

+ + + +
modPointer to the song to have its master volume set.
+
volumevalue from 0-256. 0 = silence, 256 = full volume.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Note if the hardware midi synth is selected, you cannot set the master volume.
+This command will only work reliably if FSOUND_INIT_USEDEFAULTMIDISYNTH is selected.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetGlobalVolume +, +FMUSIC_GetMasterVolume +, +FSOUND_GetSFXMasterVolume +, +FSOUND_SetSFXMasterVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrder.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrder.html index cf06629d..32d8c42f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrder.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrder.html @@ -1,64 +1,64 @@ - - - - -FMUSIC_SetOrder - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetOrder

-Sets a songs order position / current playing position.
-

-signed char F_API FMUSIC_SetOrder(
-FMUSIC_MODULE *mod,
-int order
-);
-

Parameters

- - - -
modPointer to the song to have its order changed.
-
orderOrder number to jump to.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetOrder -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetOrder + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetOrder

+Sets a songs order position / current playing position.
+

+signed char F_API FMUSIC_SetOrder(
+FMUSIC_MODULE *mod,
+int order
+);
+

Parameters

+ + + +
modPointer to the song to have its order changed.
+
orderOrder number to jump to.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetOrder +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrderCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrderCallback.html index ca198961..c4cfcadf 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrderCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetOrderCallback.html @@ -1,84 +1,84 @@ - - - - -FMUSIC_SetOrderCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetOrderCallback

-Sets a user callback to occur on every order divisible by the orderstep parameter, played from a MOD, S3M, XM or IT file.
-

-signed char F_API FMUSIC_SetOrderCallback(
-FMUSIC_MODULE *mod,
-FMUSIC_CALLBACK callback,
-int orderstep
-);
-

Parameters

- - - - -
modThe module or song to set the callback for.
-
callbackThe callback function you supply to get called.
-
orderstepCall the callback every multiple of this number of orders.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-It is important to note that this callback will be called from directly WITHIN the
-mixer / music update thread, therefore it is imperative that whatever you do from this
-callback be extremely efficient. If the routine takes too long then breakups in the sound
-will occur, or it will basically stop mixing until you return from the function.
-This sort of function is usually best for just setting a flag, or do some simple variable
-manipulation, and then exiting, letting your main thread do what it needs to based on these
-flags or variables.
-------------
-This callback is LATENCY adjusted, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
-------------
-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_CALLBACK -, -FMUSIC_SetInstCallback -, -FMUSIC_SetRowCallback -, -FMUSIC_SetZxxCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetOrderCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetOrderCallback

+Sets a user callback to occur on every order divisible by the orderstep parameter, played from a MOD, S3M, XM or IT file.
+

+signed char F_API FMUSIC_SetOrderCallback(
+FMUSIC_MODULE *mod,
+FMUSIC_CALLBACK callback,
+int orderstep
+);
+

Parameters

+ + + + +
modThe module or song to set the callback for.
+
callbackThe callback function you supply to get called.
+
orderstepCall the callback every multiple of this number of orders.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+It is important to note that this callback will be called from directly WITHIN the
+mixer / music update thread, therefore it is imperative that whatever you do from this
+callback be extremely efficient. If the routine takes too long then breakups in the sound
+will occur, or it will basically stop mixing until you return from the function.
+This sort of function is usually best for just setting a flag, or do some simple variable
+manipulation, and then exiting, letting your main thread do what it needs to based on these
+flags or variables.
+------------
+This callback is LATENCY adjusted, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
+------------
+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_CALLBACK +, +FMUSIC_SetInstCallback +, +FMUSIC_SetRowCallback +, +FMUSIC_SetZxxCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPanSeperation.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPanSeperation.html index 7e4d5137..e26c175d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPanSeperation.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPanSeperation.html @@ -1,64 +1,64 @@ - - - - -FMUSIC_SetPanSeperation - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetPanSeperation

-Sets the master pan seperation for a module.
-

-signed char F_API FMUSIC_SetPanSeperation(
-FMUSIC_MODULE *mod,
-F_FLOAT_API pansep
-);
-

Parameters

- - -
pansepThe pan scale. 1.0 means full pan seperation, 0 means mono.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This is set to 1.0 by default.
-------------
-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetPanSeperation -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetPanSeperation + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetPanSeperation

+Sets the master pan seperation for a module.
+

+signed char F_API FMUSIC_SetPanSeperation(
+FMUSIC_MODULE *mod,
+F_FLOAT_API pansep
+);
+

Parameters

+ + +
pansepThe pan scale. 1.0 means full pan seperation, 0 means mono.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This is set to 1.0 by default.
+------------
+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetPanSeperation +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPaused.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPaused.html index 11ae89a0..a6cfd22c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPaused.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetPaused.html @@ -1,63 +1,63 @@ - - - - -FMUSIC_SetPaused - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetPaused

-Pauses a song
-

-signed char F_API FMUSIC_SetPaused(
-FMUSIC_MODULE *mod,
-signed char pause
-);
-

Parameters

- - - -
modPointer to the song to be paused/unpaused.
-
pauseTRUE - song should be PAUSED, FALSE - song should be UNPAUSED
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetPaused -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetPaused + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetPaused

+Pauses a song
+

+signed char F_API FMUSIC_SetPaused(
+FMUSIC_MODULE *mod,
+signed char pause
+);
+

Parameters

+ + + +
modPointer to the song to be paused/unpaused.
+
pauseTRUE - song should be PAUSED, FALSE - song should be UNPAUSED
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetPaused +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetReverb.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetReverb.html index 68090fbe..3b7c1f45 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetReverb.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetReverb.html @@ -1,59 +1,59 @@ - - - - -FMUSIC_SetReverb - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetReverb

-Turns on reverb for MIDI/RMI files.
-

-signed char F_API FMUSIC_SetReverb(
-signed char reverb
-);
-

Parameters

- - -
reverbSet to TRUE to turn MIDI reverb on, FALSE to turn MIDI reverb off.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Reverb may be enabled through software emulation in the future for MOD based formats.
-___________________
-Supported on the following platforms : Win32
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetReverb + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetReverb

+Turns on reverb for MIDI/RMI files.
+

+signed char F_API FMUSIC_SetReverb(
+signed char reverb
+);
+

Parameters

+ + +
reverbSet to TRUE to turn MIDI reverb on, FALSE to turn MIDI reverb off.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Reverb may be enabled through software emulation in the future for MOD based formats.
+___________________
+Supported on the following platforms : Win32
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetRowCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetRowCallback.html index b3db4528..642d62ea 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetRowCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetRowCallback.html @@ -1,84 +1,84 @@ - - - - -FMUSIC_SetRowCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetRowCallback

-Sets a user callback to occur on every row divisible by the rowstep parameter, played from a MOD, S3M, XM or IT file.
-

-signed char F_API FMUSIC_SetRowCallback(
-FMUSIC_MODULE *mod,
-FMUSIC_CALLBACK callback,
-int rowstep
-);
-

Parameters

- - - - -
modThe module or song to set the callback for.
-
callbackThe callback function you supply to get called.
-
rowstepCall the callback every multiple of this number of rows.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-It is important to note that this callback will be called from directly WITHIN the
-mixer / music update thread, therefore it is imperative that whatever you do from this
-callback be extremely efficient. If the routine takes too long then breakups in the sound
-will occur, or it will basically stop mixing until you return from the function.
-This sort of function is usually best for just setting a flag, or do some simple variable
-manipulation, and then exiting, letting your main thread do what it needs to based on these
-flags or variables.
-------------
-This callback is LATENCY adjusted, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
-------------
-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_CALLBACK -, -FMUSIC_SetInstCallback -, -FMUSIC_SetOrderCallback -, -FMUSIC_SetZxxCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetRowCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetRowCallback

+Sets a user callback to occur on every row divisible by the rowstep parameter, played from a MOD, S3M, XM or IT file.
+

+signed char F_API FMUSIC_SetRowCallback(
+FMUSIC_MODULE *mod,
+FMUSIC_CALLBACK callback,
+int rowstep
+);
+

Parameters

+ + + + +
modThe module or song to set the callback for.
+
callbackThe callback function you supply to get called.
+
rowstepCall the callback every multiple of this number of rows.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+It is important to note that this callback will be called from directly WITHIN the
+mixer / music update thread, therefore it is imperative that whatever you do from this
+callback be extremely efficient. If the routine takes too long then breakups in the sound
+will occur, or it will basically stop mixing until you return from the function.
+This sort of function is usually best for just setting a flag, or do some simple variable
+manipulation, and then exiting, letting your main thread do what it needs to based on these
+flags or variables.
+------------
+This callback is LATENCY adjusted, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
+------------
+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_CALLBACK +, +FMUSIC_SetInstCallback +, +FMUSIC_SetOrderCallback +, +FMUSIC_SetZxxCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetSample.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetSample.html index 541e3489..5188dfa1 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetSample.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetSample.html @@ -1,74 +1,74 @@ - - - - -FMUSIC_SetSample - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetSample

-Replaces a mod's sample with a sample definition specified.
-

-signed char F_API FMUSIC_SetSample(
-FMUSIC_MODULE *mod,
-int sampno,
-FSOUND_SAMPLE *sptr
-);
-

Parameters

- - - - -
modPointer to the song to set the sample for.
-
sampnoindex to sample inside module.
-
sptrPointer to the sample definition to replace mod sample
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Because of the instrument nature of some formats like XM, this function lists all the samples in order of instruments and their subsamples.
-ie if instrument 1 has 2 samples and instrument 2 contains 3 samples, then sampno in this case would be 0 and 1 for instrument 1's samples, and 2,3 & 4 for instrument 2's samples.
-------------
-FMOD does not free the existing mod sample that you may be overwriting. If you do overwrite an existing handle, it may be lost, and you may incur a memory leak. It is a good idea to free the existing sample first before overwriting it.
-------------
-Important: For PlayStation 2, this function has to do a blocking query to the IOP, and can take significantly more time than a standard non blocking fmod function. This means it is best to cache the pointers for samples while loading, and not call this function in realtime.
-------------
-This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetSample -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetSample + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetSample

+Replaces a mod's sample with a sample definition specified.
+

+signed char F_API FMUSIC_SetSample(
+FMUSIC_MODULE *mod,
+int sampno,
+FSOUND_SAMPLE *sptr
+);
+

Parameters

+ + + + +
modPointer to the song to set the sample for.
+
sampnoindex to sample inside module.
+
sptrPointer to the sample definition to replace mod sample
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Because of the instrument nature of some formats like XM, this function lists all the samples in order of instruments and their subsamples.
+ie if instrument 1 has 2 samples and instrument 2 contains 3 samples, then sampno in this case would be 0 and 1 for instrument 1's samples, and 2,3 & 4 for instrument 2's samples.
+------------
+FMOD does not free the existing mod sample that you may be overwriting. If you do overwrite an existing handle, it may be lost, and you may incur a memory leak. It is a good idea to free the existing sample first before overwriting it.
+------------
+Important: For PlayStation 2, this function has to do a blocking query to the IOP, and can take significantly more time than a standard non blocking fmod function. This means it is best to cache the pointers for samples while loading, and not call this function in realtime.
+------------
+This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetSample +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetUserData.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetUserData.html index 1e383598..f9c808e8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetUserData.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetUserData.html @@ -1,63 +1,63 @@ - - - - -FMUSIC_SetUserData - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetUserData

-Sets a user defined value to store with the music file to be retrieved later.
-

-signed char F_API FMUSIC_SetUserData(
-FMUSIC_MODULE *mod,
-void *userdata
-);
-

Parameters

- - - -
modPointer to the song.
-
userdataValue to store with music object.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_GetUserData -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetUserData + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetUserData

+Sets a user defined value to store with the music file to be retrieved later.
+

+signed char F_API FMUSIC_SetUserData(
+FMUSIC_MODULE *mod,
+void *userdata
+);
+

Parameters

+ + + +
modPointer to the song.
+
userdataValue to store with music object.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_GetUserData +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetZxxCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetZxxCallback.html index 43560081..a1bf2933 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetZxxCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_SetZxxCallback.html @@ -1,84 +1,84 @@ - - - - -FMUSIC_SetZxxCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_SetZxxCallback

-Sets a user callback for any Zxx commands encountered in an S3M, XM or IT file.
-

-signed char F_API FMUSIC_SetZxxCallback(
-FMUSIC_MODULE *mod,
-FMUSIC_CALLBACK callback
-);
-

Parameters

- - - -
modThe module or song to set the callback for.
-
callbackThe callback function you supply to get called upon execution of a Zxx command.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-The value passed into the param parameter of the callback is the xx value specified in the Zxx
-command by the musician.
-------------
-It is important to note that this callback will be called from directly WITHIN the
-mixer / music update thread, therefore it is imperative that whatever you do from this
-callback be extremely efficient. If the routine takes too long then breakups in the sound
-will occur, or it will basically stop mixing until you return from the function.
-This sort of function is usually best for just setting a flag, or do some simple variable
-manipulation, and then exiting, letting your main thread do what it needs to based on these
-flags or variables.
-------------
-This callback is LATENCY adjusted by default, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
-Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
-------------
-Note : This function is not supported with the MIDI format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_CALLBACK -, -FMUSIC_SetInstCallback -, -FMUSIC_SetOrderCallback -, -FMUSIC_SetRowCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_SetZxxCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_SetZxxCallback

+Sets a user callback for any Zxx commands encountered in an S3M, XM or IT file.
+

+signed char F_API FMUSIC_SetZxxCallback(
+FMUSIC_MODULE *mod,
+FMUSIC_CALLBACK callback
+);
+

Parameters

+ + + +
modThe module or song to set the callback for.
+
callbackThe callback function you supply to get called upon execution of a Zxx command.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+The value passed into the param parameter of the callback is the xx value specified in the Zxx
+command by the musician.
+------------
+It is important to note that this callback will be called from directly WITHIN the
+mixer / music update thread, therefore it is imperative that whatever you do from this
+callback be extremely efficient. If the routine takes too long then breakups in the sound
+will occur, or it will basically stop mixing until you return from the function.
+This sort of function is usually best for just setting a flag, or do some simple variable
+manipulation, and then exiting, letting your main thread do what it needs to based on these
+flags or variables.
+------------
+This callback is LATENCY adjusted by default, so that the callback happens when you HEAR the sound, not when it is mixed, for accurate synchronization.
+Use FSOUND_INIT_DONTLATENCYADJUST if you want it to be called back at mix time, which is useful if you want to control the music interactively.
+------------
+Note : This function is not supported with the MIDI format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_CALLBACK +, +FMUSIC_SetInstCallback +, +FMUSIC_SetOrderCallback +, +FMUSIC_SetRowCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopAllSongs.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopAllSongs.html index a1ab7a0c..cf367353 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopAllSongs.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopAllSongs.html @@ -1,56 +1,56 @@ - - - - -FMUSIC_StopAllSongs - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_StopAllSongs

-Stops all songs from playing. This is useful if you have multiple songs playing at once and
-want a quick way to stop them
-

-void F_API FMUSIC_StopAllSongs(
-);
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_PlaySong -, -FMUSIC_StopSong -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_StopAllSongs + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_StopAllSongs

+Stops all songs from playing. This is useful if you have multiple songs playing at once and
+want a quick way to stop them
+

+void F_API FMUSIC_StopAllSongs(
+);
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_PlaySong +, +FMUSIC_StopSong +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopSong.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopSong.html index 45eba68e..1cf5fdcd 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopSong.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_StopSong.html @@ -1,62 +1,62 @@ - - - - -FMUSIC_StopSong - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FMUSIC_StopSong

-Stops a song from playing.
-

-signed char F_API FMUSIC_StopSong(
-FMUSIC_MODULE *mod
-);
-

Parameters

- - -
modPointer to the song to be stopped.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_PlaySong -, -FMUSIC_StopAllSongs -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:26 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_StopSong + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FMUSIC_StopSong

+Stops a song from playing.
+

+signed char F_API FMUSIC_StopSong(
+FMUSIC_MODULE *mod
+);
+

Parameters

+ + +
modPointer to the song to be stopped.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_PlaySong +, +FMUSIC_StopAllSongs +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:26 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_TYPES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_TYPES.html index aafcc29e..a97462d9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_TYPES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FMUSIC_TYPES.html @@ -1,62 +1,62 @@ - - - - -FMUSIC_TYPES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FMUSIC_TYPES

-These definitions describe the type of song being played.
-

-

Enumerators

- - - - - - - - -
FMUSIC_TYPE_NONE
FMUSIC_TYPE_MOD/* Protracker / Fasttracker */
-
FMUSIC_TYPE_S3M/* ScreamTracker 3 */
-
FMUSIC_TYPE_XM/* FastTracker 2 */
-
FMUSIC_TYPE_IT/* Impulse Tracker. */
-
FMUSIC_TYPE_MIDI/* MIDI file */
-
FMUSIC_TYPE_FSB/* FMOD Sample Bank file */
-
-

See Also

-FMUSIC_GetType -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FMUSIC_TYPES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FMUSIC_TYPES

+These definitions describe the type of song being played.
+

+

Enumerators

+ + + + + + + + +
FMUSIC_TYPE_NONE
FMUSIC_TYPE_MOD/* Protracker / Fasttracker */
+
FMUSIC_TYPE_S3M/* ScreamTracker 3 */
+
FMUSIC_TYPE_XM/* FastTracker 2 */
+
FMUSIC_TYPE_IT/* Impulse Tracker. */
+
FMUSIC_TYPE_MIDI/* MIDI file */
+
FMUSIC_TYPE_FSB/* FMOD Sample Bank file */
+
+

See Also

+FMUSIC_GetType +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND.html index 71f81c9c..cdac142f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND.html @@ -1,356 +1,356 @@ - - - - -FSOUND API Reference - - - - - - - - - - - -
- - - -Previous Topic -Index - -Next Topic - -
-
-
-

FSOUND API Reference

-FSOUND Api. Use this to play sounds, streams, cd's etc
-

-Functions , Structures , Defines , Enums -

-

-

-- -Functions -
-

-
-FSOUND_3D_GetAttributes
-FSOUND_3D_GetMinMaxDistance
-FSOUND_3D_Listener_GetAttributes
-FSOUND_3D_Listener_SetAttributes
-FSOUND_3D_Listener_SetCurrent
-FSOUND_3D_SetAttributes
-FSOUND_3D_SetDistanceFactor
-FSOUND_3D_SetDopplerFactor
-FSOUND_3D_SetMinMaxDistance
-FSOUND_3D_SetRolloffFactor
-FSOUND_ALLOCCALLBACK
-FSOUND_CD_GetNumTracks
-FSOUND_CD_GetPaused
-FSOUND_CD_GetTrack
-FSOUND_CD_GetTrackLength
-FSOUND_CD_GetTrackTime
-FSOUND_CD_GetVolume
-FSOUND_CD_OpenTray
-FSOUND_CD_Play
-FSOUND_CD_SetPaused
-FSOUND_CD_SetPlayMode
-FSOUND_CD_SetTrackTime
-FSOUND_CD_SetVolume
-FSOUND_CD_Stop
-FSOUND_Close
-FSOUND_CLOSECALLBACK
-FSOUND_DSP_ClearMixBuffer
-FSOUND_DSP_Create
-FSOUND_DSP_Free
-FSOUND_DSP_GetActive
-FSOUND_DSP_GetBufferLength
-FSOUND_DSP_GetBufferLengthTotal
-FSOUND_DSP_GetClearUnit
-FSOUND_DSP_GetClipAndCopyUnit
-FSOUND_DSP_GetFFTUnit
-FSOUND_DSP_GetMusicUnit
-FSOUND_DSP_GetPriority
-FSOUND_DSP_GetSFXUnit
-FSOUND_DSP_GetSpectrum
-FSOUND_DSP_MixBuffers
-FSOUND_DSP_SetActive
-FSOUND_DSP_SetPriority
-FSOUND_DSPCALLBACK
-FSOUND_File_SetCallbacks
-FSOUND_FREECALLBACK
-FSOUND_FX_Disable
-FSOUND_FX_Enable
-FSOUND_FX_SetChorus
-FSOUND_FX_SetCompressor
-FSOUND_FX_SetDistortion
-FSOUND_FX_SetEcho
-FSOUND_FX_SetFlanger
-FSOUND_FX_SetGargle
-FSOUND_FX_SetI3DL2Reverb
-FSOUND_FX_SetParamEQ
-FSOUND_FX_SetWavesReverb
-FSOUND_GetAmplitude
-FSOUND_GetChannelsPlaying
-FSOUND_GetCPUUsage
-FSOUND_GetCurrentLevels
-FSOUND_GetCurrentPosition
-FSOUND_GetCurrentSample
-FSOUND_GetDriver
-FSOUND_GetDriverCaps
-FSOUND_GetDriverName
-FSOUND_GetError
-FSOUND_GetFreeHWRam
-FSOUND_GetFrequency
-FSOUND_GetLoopMode
-FSOUND_GetMaxChannels
-FSOUND_GetMaxSamples
-FSOUND_GetMemoryStats
-FSOUND_GetMixer
-FSOUND_GetMute
-FSOUND_GetNumDrivers
-FSOUND_GetNumHWChannels
-FSOUND_GetNumSubChannels
-FSOUND_GetOutput
-FSOUND_GetOutputHandle
-FSOUND_GetOutputRate
-FSOUND_GetPan
-FSOUND_GetPaused
-FSOUND_GetPriority
-FSOUND_GetReserved
-FSOUND_GetSFXMasterVolume
-FSOUND_GetSpeakerMode
-FSOUND_GetSubChannel
-FSOUND_GetSurround
-FSOUND_GetVersion
-FSOUND_GetVolume
-FSOUND_Init
-FSOUND_IOP_Alloc
-FSOUND_IOP_Free
-FSOUND_IsPlaying
-FSOUND_METADATACALLBACK
-FSOUND_OPENCALLBACK
-FSOUND_PlaySound
-FSOUND_PlaySoundEx
-FSOUND_READCALLBACK
-FSOUND_REALLOCCALLBACK
-FSOUND_Record_GetDriver
-FSOUND_Record_GetDriverName
-FSOUND_Record_GetNumDrivers
-FSOUND_Record_GetPosition
-FSOUND_Record_SetDriver
-FSOUND_Record_StartSample
-FSOUND_Record_Stop
-FSOUND_Reverb_GetChannelProperties
-FSOUND_Reverb_GetProperties
-FSOUND_Reverb_SetChannelProperties
-FSOUND_Reverb_SetProperties
-FSOUND_Sample_Alloc
-FSOUND_Sample_Free
-FSOUND_Sample_Get
-FSOUND_Sample_GetDefaults
-FSOUND_Sample_GetDefaultsEx
-FSOUND_Sample_GetLength
-FSOUND_Sample_GetLoopPoints
-FSOUND_Sample_GetMinMaxDistance
-FSOUND_Sample_GetMode
-FSOUND_Sample_GetName
-FSOUND_Sample_Load
-FSOUND_Sample_Lock
-FSOUND_Sample_SetDefaults
-FSOUND_Sample_SetDefaultsEx
-FSOUND_Sample_SetLoopPoints
-FSOUND_Sample_SetMaxPlaybacks
-FSOUND_Sample_SetMinMaxDistance
-FSOUND_Sample_SetMode
-FSOUND_Sample_Unlock
-FSOUND_Sample_Upload
-FSOUND_SEEKCALLBACK
-FSOUND_SendData
-FSOUND_SetBufferSize
-FSOUND_SetCurrentPosition
-FSOUND_SetDiskBusy
-FSOUND_SetDriver
-FSOUND_SetFrequency
-FSOUND_SetHWND
-FSOUND_SetLevels
-FSOUND_SetLoopMode
-FSOUND_SetMaxHardwareChannels
-FSOUND_SetMemorySystem
-FSOUND_SetMinHardwareChannels
-FSOUND_SetMixer
-FSOUND_SetMute
-FSOUND_SetOutput
-FSOUND_SetPan
-FSOUND_SetPanSeperation
-FSOUND_SetPaused
-FSOUND_SetPriority
-FSOUND_SetReserved
-FSOUND_SetSFXMasterVolume
-FSOUND_SetSpeakerMode
-FSOUND_SetSurround
-FSOUND_SetVolume
-FSOUND_SetVolumeAbsolute
-FSOUND_SPU2_Alloc
-FSOUND_SPU2_Free
-FSOUND_SPU2_GetRawAddress
-FSOUND_StopSound
-FSOUND_Stream_AddSyncPoint
-FSOUND_Stream_Close
-FSOUND_Stream_Create
-FSOUND_Stream_CreateDSP
-FSOUND_Stream_DeleteSyncPoint
-FSOUND_Stream_FindTagField
-FSOUND_Stream_GetLength
-FSOUND_Stream_GetLengthMs
-FSOUND_Stream_GetMode
-FSOUND_Stream_GetNumSubStreams
-FSOUND_Stream_GetNumSyncPoints
-FSOUND_Stream_GetNumTagFields
-FSOUND_Stream_GetOpenState
-FSOUND_Stream_GetPosition
-FSOUND_Stream_GetSample
-FSOUND_Stream_GetSyncPoint
-FSOUND_Stream_GetSyncPointInfo
-FSOUND_Stream_GetTagField
-FSOUND_Stream_GetTime
-FSOUND_Stream_Net_GetBufferProperties
-FSOUND_Stream_Net_GetLastServerStatus
-FSOUND_Stream_Net_GetStatus
-FSOUND_Stream_Net_SetBufferProperties
-FSOUND_Stream_Net_SetMetadataCallback
-FSOUND_Stream_Net_SetProxy
-FSOUND_Stream_Net_SetTimeout
-FSOUND_Stream_Open
-FSOUND_Stream_OpenFromHandle
-FSOUND_Stream_Play
-FSOUND_Stream_PlayEx
-FSOUND_Stream_SetBufferSize
-FSOUND_Stream_SetEndCallback
-FSOUND_Stream_SetLoopCount
-FSOUND_Stream_SetLoopPoints
-FSOUND_Stream_SetMode
-FSOUND_Stream_SetPosition
-FSOUND_Stream_SetSubStream
-FSOUND_Stream_SetSubStreamSentence
-FSOUND_Stream_SetSyncCallback
-FSOUND_Stream_SetTime
-FSOUND_Stream_Stop
-FSOUND_STREAMCALLBACK
-FSOUND_TELLCALLBACK
-FSOUND_Update
-sceSifAddCmdHandler
-
-

-

-

-- -Structures -
-

- -

-

-

-- -Defines -
-

- -

-

-

-- -Enums -
-

- - -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND API Reference + + + + + + + + + + + +
+ + + +Previous Topic +Index + +Next Topic + +
+
+
+

FSOUND API Reference

+FSOUND Api. Use this to play sounds, streams, cd's etc
+

+Functions , Structures , Defines , Enums +

+

+

+- +Functions +
+

+
+FSOUND_3D_GetAttributes
+FSOUND_3D_GetMinMaxDistance
+FSOUND_3D_Listener_GetAttributes
+FSOUND_3D_Listener_SetAttributes
+FSOUND_3D_Listener_SetCurrent
+FSOUND_3D_SetAttributes
+FSOUND_3D_SetDistanceFactor
+FSOUND_3D_SetDopplerFactor
+FSOUND_3D_SetMinMaxDistance
+FSOUND_3D_SetRolloffFactor
+FSOUND_ALLOCCALLBACK
+FSOUND_CD_GetNumTracks
+FSOUND_CD_GetPaused
+FSOUND_CD_GetTrack
+FSOUND_CD_GetTrackLength
+FSOUND_CD_GetTrackTime
+FSOUND_CD_GetVolume
+FSOUND_CD_OpenTray
+FSOUND_CD_Play
+FSOUND_CD_SetPaused
+FSOUND_CD_SetPlayMode
+FSOUND_CD_SetTrackTime
+FSOUND_CD_SetVolume
+FSOUND_CD_Stop
+FSOUND_Close
+FSOUND_CLOSECALLBACK
+FSOUND_DSP_ClearMixBuffer
+FSOUND_DSP_Create
+FSOUND_DSP_Free
+FSOUND_DSP_GetActive
+FSOUND_DSP_GetBufferLength
+FSOUND_DSP_GetBufferLengthTotal
+FSOUND_DSP_GetClearUnit
+FSOUND_DSP_GetClipAndCopyUnit
+FSOUND_DSP_GetFFTUnit
+FSOUND_DSP_GetMusicUnit
+FSOUND_DSP_GetPriority
+FSOUND_DSP_GetSFXUnit
+FSOUND_DSP_GetSpectrum
+FSOUND_DSP_MixBuffers
+FSOUND_DSP_SetActive
+FSOUND_DSP_SetPriority
+FSOUND_DSPCALLBACK
+FSOUND_File_SetCallbacks
+FSOUND_FREECALLBACK
+FSOUND_FX_Disable
+FSOUND_FX_Enable
+FSOUND_FX_SetChorus
+FSOUND_FX_SetCompressor
+FSOUND_FX_SetDistortion
+FSOUND_FX_SetEcho
+FSOUND_FX_SetFlanger
+FSOUND_FX_SetGargle
+FSOUND_FX_SetI3DL2Reverb
+FSOUND_FX_SetParamEQ
+FSOUND_FX_SetWavesReverb
+FSOUND_GetAmplitude
+FSOUND_GetChannelsPlaying
+FSOUND_GetCPUUsage
+FSOUND_GetCurrentLevels
+FSOUND_GetCurrentPosition
+FSOUND_GetCurrentSample
+FSOUND_GetDriver
+FSOUND_GetDriverCaps
+FSOUND_GetDriverName
+FSOUND_GetError
+FSOUND_GetFreeHWRam
+FSOUND_GetFrequency
+FSOUND_GetLoopMode
+FSOUND_GetMaxChannels
+FSOUND_GetMaxSamples
+FSOUND_GetMemoryStats
+FSOUND_GetMixer
+FSOUND_GetMute
+FSOUND_GetNumDrivers
+FSOUND_GetNumHWChannels
+FSOUND_GetNumSubChannels
+FSOUND_GetOutput
+FSOUND_GetOutputHandle
+FSOUND_GetOutputRate
+FSOUND_GetPan
+FSOUND_GetPaused
+FSOUND_GetPriority
+FSOUND_GetReserved
+FSOUND_GetSFXMasterVolume
+FSOUND_GetSpeakerMode
+FSOUND_GetSubChannel
+FSOUND_GetSurround
+FSOUND_GetVersion
+FSOUND_GetVolume
+FSOUND_Init
+FSOUND_IOP_Alloc
+FSOUND_IOP_Free
+FSOUND_IsPlaying
+FSOUND_METADATACALLBACK
+FSOUND_OPENCALLBACK
+FSOUND_PlaySound
+FSOUND_PlaySoundEx
+FSOUND_READCALLBACK
+FSOUND_REALLOCCALLBACK
+FSOUND_Record_GetDriver
+FSOUND_Record_GetDriverName
+FSOUND_Record_GetNumDrivers
+FSOUND_Record_GetPosition
+FSOUND_Record_SetDriver
+FSOUND_Record_StartSample
+FSOUND_Record_Stop
+FSOUND_Reverb_GetChannelProperties
+FSOUND_Reverb_GetProperties
+FSOUND_Reverb_SetChannelProperties
+FSOUND_Reverb_SetProperties
+FSOUND_Sample_Alloc
+FSOUND_Sample_Free
+FSOUND_Sample_Get
+FSOUND_Sample_GetDefaults
+FSOUND_Sample_GetDefaultsEx
+FSOUND_Sample_GetLength
+FSOUND_Sample_GetLoopPoints
+FSOUND_Sample_GetMinMaxDistance
+FSOUND_Sample_GetMode
+FSOUND_Sample_GetName
+FSOUND_Sample_Load
+FSOUND_Sample_Lock
+FSOUND_Sample_SetDefaults
+FSOUND_Sample_SetDefaultsEx
+FSOUND_Sample_SetLoopPoints
+FSOUND_Sample_SetMaxPlaybacks
+FSOUND_Sample_SetMinMaxDistance
+FSOUND_Sample_SetMode
+FSOUND_Sample_Unlock
+FSOUND_Sample_Upload
+FSOUND_SEEKCALLBACK
+FSOUND_SendData
+FSOUND_SetBufferSize
+FSOUND_SetCurrentPosition
+FSOUND_SetDiskBusy
+FSOUND_SetDriver
+FSOUND_SetFrequency
+FSOUND_SetHWND
+FSOUND_SetLevels
+FSOUND_SetLoopMode
+FSOUND_SetMaxHardwareChannels
+FSOUND_SetMemorySystem
+FSOUND_SetMinHardwareChannels
+FSOUND_SetMixer
+FSOUND_SetMute
+FSOUND_SetOutput
+FSOUND_SetPan
+FSOUND_SetPanSeperation
+FSOUND_SetPaused
+FSOUND_SetPriority
+FSOUND_SetReserved
+FSOUND_SetSFXMasterVolume
+FSOUND_SetSpeakerMode
+FSOUND_SetSurround
+FSOUND_SetVolume
+FSOUND_SetVolumeAbsolute
+FSOUND_SPU2_Alloc
+FSOUND_SPU2_Free
+FSOUND_SPU2_GetRawAddress
+FSOUND_StopSound
+FSOUND_Stream_AddSyncPoint
+FSOUND_Stream_Close
+FSOUND_Stream_Create
+FSOUND_Stream_CreateDSP
+FSOUND_Stream_DeleteSyncPoint
+FSOUND_Stream_FindTagField
+FSOUND_Stream_GetLength
+FSOUND_Stream_GetLengthMs
+FSOUND_Stream_GetMode
+FSOUND_Stream_GetNumSubStreams
+FSOUND_Stream_GetNumSyncPoints
+FSOUND_Stream_GetNumTagFields
+FSOUND_Stream_GetOpenState
+FSOUND_Stream_GetPosition
+FSOUND_Stream_GetSample
+FSOUND_Stream_GetSyncPoint
+FSOUND_Stream_GetSyncPointInfo
+FSOUND_Stream_GetTagField
+FSOUND_Stream_GetTime
+FSOUND_Stream_Net_GetBufferProperties
+FSOUND_Stream_Net_GetLastServerStatus
+FSOUND_Stream_Net_GetStatus
+FSOUND_Stream_Net_SetBufferProperties
+FSOUND_Stream_Net_SetMetadataCallback
+FSOUND_Stream_Net_SetProxy
+FSOUND_Stream_Net_SetTimeout
+FSOUND_Stream_Open
+FSOUND_Stream_OpenFromHandle
+FSOUND_Stream_Play
+FSOUND_Stream_PlayEx
+FSOUND_Stream_SetBufferSize
+FSOUND_Stream_SetEndCallback
+FSOUND_Stream_SetLoopCount
+FSOUND_Stream_SetLoopPoints
+FSOUND_Stream_SetMode
+FSOUND_Stream_SetPosition
+FSOUND_Stream_SetSubStream
+FSOUND_Stream_SetSubStreamSentence
+FSOUND_Stream_SetSyncCallback
+FSOUND_Stream_SetTime
+FSOUND_Stream_Stop
+FSOUND_STREAMCALLBACK
+FSOUND_TELLCALLBACK
+FSOUND_Update
+sceSifAddCmdHandler
+
+

+

+

+- +Structures +
+

+ +

+

+

+- +Defines +
+

+ +

+

+

+- +Enums +
+

+ + +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetAttributes.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetAttributes.html index f90a4f31..81528a49 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetAttributes.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetAttributes.html @@ -1,75 +1,75 @@ - - - - -FSOUND_3D_GetAttributes - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_GetAttributes

-

-signed char F_API FSOUND_3D_GetAttributes(
-int channel,
-F_FLOAT_API *pos,
-F_FLOAT_API *vel
-);
-

Parameters

- - - - -
channelChannel you want to get 3d information from
-
posPointer to a position vector (xyz float triplet) of the emitter in world space, measured in distance units.
-This can be NULL to ignore it.
-
velPointer to a velocity vector (xyz float triplet), of the emitter measured in distance units PER SECOND.
-This can be NULL to ignore it.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_Listener_SetAttributes -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -, -FSOUND_Sample_SetMinMaxDistance -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_GetAttributes + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_GetAttributes

+

+signed char F_API FSOUND_3D_GetAttributes(
+int channel,
+F_FLOAT_API *pos,
+F_FLOAT_API *vel
+);
+

Parameters

+ + + + +
channelChannel you want to get 3d information from
+
posPointer to a position vector (xyz float triplet) of the emitter in world space, measured in distance units.
+This can be NULL to ignore it.
+
velPointer to a velocity vector (xyz float triplet), of the emitter measured in distance units PER SECOND.
+This can be NULL to ignore it.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_Listener_SetAttributes +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +, +FSOUND_Sample_SetMinMaxDistance +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetMinMaxDistance.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetMinMaxDistance.html index 04d939ad..9925142f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetMinMaxDistance.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_GetMinMaxDistance.html @@ -1,70 +1,70 @@ - - - - -FSOUND_3D_GetMinMaxDistance - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_GetMinMaxDistance

-Returns the current min and max distance for a channel.
-

-DLL_API signed char F_API FSOUND_3D_GetMinMaxDistance(
-int channel,
-F_FLOAT_API *mindistance,
-F_FLOAT_API *maxdistance
-);
-

Parameters

- - - - -
channelChannel number/handle to retrieve min and max distance from.
-
mindistancePointer to a floating point value to store mindistance.
-
maxdistancePointer to a floating point value to store maxdistance.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_SetAttributes -, -FSOUND_3D_SetMinMaxDistance -, -FSOUND_Sample_SetMinMaxDistance -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_GetMinMaxDistance + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_GetMinMaxDistance

+Returns the current min and max distance for a channel.
+

+DLL_API signed char F_API FSOUND_3D_GetMinMaxDistance(
+int channel,
+F_FLOAT_API *mindistance,
+F_FLOAT_API *maxdistance
+);
+

Parameters

+ + + + +
channelChannel number/handle to retrieve min and max distance from.
+
mindistancePointer to a floating point value to store mindistance.
+
maxdistancePointer to a floating point value to store maxdistance.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_SetAttributes +, +FSOUND_3D_SetMinMaxDistance +, +FSOUND_Sample_SetMinMaxDistance +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_GetAttributes.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_GetAttributes.html index 69dbdc93..b55793f2 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_GetAttributes.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_GetAttributes.html @@ -1,111 +1,111 @@ - - - - -FSOUND_3D_Listener_GetAttributes - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_Listener_GetAttributes

-This retrieves the position, velocity and orientation of a 3d sound listener.
-

-void F_API FSOUND_3D_Listener_GetAttributes(
-F_FLOAT_API *pos,
-F_FLOAT_API *vel,
-F_FLOAT_API *fx,
-F_FLOAT_API *fy,
-F_FLOAT_API *fz,
-F_FLOAT_API *tx,
-F_FLOAT_API *ty,
-F_FLOAT_API *tz
-);
-

Parameters

- - - - - - - - - -
posPointer to a position vector (xyz float triplet), of the listener in world space,
-measured in distance units.
-This can be NULL to ignore it.
-
velPointer to a velocity vector (xyz float triplet), of the listener measured in
-distance units PER SECOND.
-This can be NULL to ignore it.
-
fxpointer to x component of a FORWARD unit length orientation vector
-This can be NULL to ignore it.
-
fypointer to y component of a FORWARD unit length orientation vector
-This can be NULL to ignore it.
-
fzpointer to z component of a FORWARD unit length orientation vector
-This can be NULL to ignore it.
-
txpointer to x component of a TOP or upwards facing unit length orientation vector
-This can be NULL to ignore it.
-
typointer to y component of a TOP or upwards facing unit length orientation vector
-This can be NULL to ignore it.
-
tzpointer to z component of a TOP or upwards facing unit length orientation vector
-This can be NULL to ignore it.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND treats +X as right, +Y as up, and +Z as forwards. (left handed)
-To map to your own coordinate system, flip and exchange these values. For example if you wanted to use right handed coordinates, you would negate the Z value of your own direction vector.
-Orientation vectors are expected to be of UNIT length. This means the magnitude of the vector should be 1.0f.
----------
-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
----------
-Please remember to use units PER SECOND, NOT PER FRAME as this is a common mistake.
-Do not just use (pos - lastpos) from the last frame's data for velocity, as this is not correct.
-You need to time compensate it so it is given in units per SECOND.
-You could alter your pos - lastpos calculation to something like this.
-vel = (pos-lastpos) / (time taken since last frame in seconds).
-I.e. at 60fps the formula would look like this
-vel = (pos-lastpos) / 0.0166667.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_Listener_SetCurrent -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -, -FSOUND_3D_SetDopplerFactor -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_Listener_GetAttributes + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_Listener_GetAttributes

+This retrieves the position, velocity and orientation of a 3d sound listener.
+

+void F_API FSOUND_3D_Listener_GetAttributes(
+F_FLOAT_API *pos,
+F_FLOAT_API *vel,
+F_FLOAT_API *fx,
+F_FLOAT_API *fy,
+F_FLOAT_API *fz,
+F_FLOAT_API *tx,
+F_FLOAT_API *ty,
+F_FLOAT_API *tz
+);
+

Parameters

+ + + + + + + + + +
posPointer to a position vector (xyz float triplet), of the listener in world space,
+measured in distance units.
+This can be NULL to ignore it.
+
velPointer to a velocity vector (xyz float triplet), of the listener measured in
+distance units PER SECOND.
+This can be NULL to ignore it.
+
fxpointer to x component of a FORWARD unit length orientation vector
+This can be NULL to ignore it.
+
fypointer to y component of a FORWARD unit length orientation vector
+This can be NULL to ignore it.
+
fzpointer to z component of a FORWARD unit length orientation vector
+This can be NULL to ignore it.
+
txpointer to x component of a TOP or upwards facing unit length orientation vector
+This can be NULL to ignore it.
+
typointer to y component of a TOP or upwards facing unit length orientation vector
+This can be NULL to ignore it.
+
tzpointer to z component of a TOP or upwards facing unit length orientation vector
+This can be NULL to ignore it.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND treats +X as right, +Y as up, and +Z as forwards. (left handed)
+To map to your own coordinate system, flip and exchange these values. For example if you wanted to use right handed coordinates, you would negate the Z value of your own direction vector.
+Orientation vectors are expected to be of UNIT length. This means the magnitude of the vector should be 1.0f.
+---------
+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+---------
+Please remember to use units PER SECOND, NOT PER FRAME as this is a common mistake.
+Do not just use (pos - lastpos) from the last frame's data for velocity, as this is not correct.
+You need to time compensate it so it is given in units per SECOND.
+You could alter your pos - lastpos calculation to something like this.
+vel = (pos-lastpos) / (time taken since last frame in seconds).
+I.e. at 60fps the formula would look like this
+vel = (pos-lastpos) / 0.0166667.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_Listener_SetCurrent +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +, +FSOUND_3D_SetDopplerFactor +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetAttributes.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetAttributes.html index 9b2660f5..28690ef8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetAttributes.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetAttributes.html @@ -1,110 +1,110 @@ - - - - -FSOUND_3D_Listener_SetAttributes - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_Listener_SetAttributes

-This updates the position, velocity and orientation of a 3d sound listener.
-

-void F_API FSOUND_3D_Listener_SetAttributes(
-const F_FLOAT_API *pos,
-const F_FLOAT_API *vel,
-F_FLOAT_API fx,
-F_FLOAT_API fy,
-F_FLOAT_API fz,
-F_FLOAT_API tx,
-F_FLOAT_API ty,
-F_FLOAT_API tz
-);
-

Parameters

- - - - - - - - - -
posPointer to a position vector (xyz float triplet), of the listener in world space, measured in distance units.
-This can be NULL to ignore it.
-
velPointer to a velocity vector (xyz float triplet), of the listener measured in distance units PER SECOND.
-This can be NULL to ignore it.
-
fxx component of a FORWARD unit length orientation vector
-
fyy component of a FORWARD unit length orientation vector
-
fzz component of a FORWARD unit length orientation vector
-
txx component of a TOP or upwards facing unit length orientation vector
-
tyy component of a TOP or upwards facing unit length orientation vector
-
tzz component of a TOP or upwards facing unit length orientation vector
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND treats +X as right, +Y as up, and +Z as forwards. (left handed)
-To map to your own coordinate system, flip and exchange these values. For example if you wanted to use
-right handed coordinates, you would negate the Z value of your own direction vector.
-Orientation vectors are expected to be of UNIT length. This means the magnitude of the vector
-should be 1.0f.
----------
-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
----------
-Please remember to use units PER SECOND, NOT PER FRAME as this is a common mistake.
-Do not just use (pos - lastpos) from the last frame's data for velocity, as this is not
-correct. You need to time compensate it so it is given in units per SECOND.
-You could alter your pos - lastpos calculation to something like this.
-vel = (pos-lastpos) / (time taken since last frame in seconds). Ie at 60fps the formula
-would look like this vel = (pos-lastpos) / 0.0166667.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_GetAttributes -, -FSOUND_3D_Listener_SetCurrent -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -, -FSOUND_3D_SetDopplerFactor -, -FSOUND_3D_SetRolloffFactor -, -FSOUND_Update -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_Listener_SetAttributes + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_Listener_SetAttributes

+This updates the position, velocity and orientation of a 3d sound listener.
+

+void F_API FSOUND_3D_Listener_SetAttributes(
+const F_FLOAT_API *pos,
+const F_FLOAT_API *vel,
+F_FLOAT_API fx,
+F_FLOAT_API fy,
+F_FLOAT_API fz,
+F_FLOAT_API tx,
+F_FLOAT_API ty,
+F_FLOAT_API tz
+);
+

Parameters

+ + + + + + + + + +
posPointer to a position vector (xyz float triplet), of the listener in world space, measured in distance units.
+This can be NULL to ignore it.
+
velPointer to a velocity vector (xyz float triplet), of the listener measured in distance units PER SECOND.
+This can be NULL to ignore it.
+
fxx component of a FORWARD unit length orientation vector
+
fyy component of a FORWARD unit length orientation vector
+
fzz component of a FORWARD unit length orientation vector
+
txx component of a TOP or upwards facing unit length orientation vector
+
tyy component of a TOP or upwards facing unit length orientation vector
+
tzz component of a TOP or upwards facing unit length orientation vector
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND treats +X as right, +Y as up, and +Z as forwards. (left handed)
+To map to your own coordinate system, flip and exchange these values. For example if you wanted to use
+right handed coordinates, you would negate the Z value of your own direction vector.
+Orientation vectors are expected to be of UNIT length. This means the magnitude of the vector
+should be 1.0f.
+---------
+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+---------
+Please remember to use units PER SECOND, NOT PER FRAME as this is a common mistake.
+Do not just use (pos - lastpos) from the last frame's data for velocity, as this is not
+correct. You need to time compensate it so it is given in units per SECOND.
+You could alter your pos - lastpos calculation to something like this.
+vel = (pos-lastpos) / (time taken since last frame in seconds). Ie at 60fps the formula
+would look like this vel = (pos-lastpos) / 0.0166667.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_GetAttributes +, +FSOUND_3D_Listener_SetCurrent +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +, +FSOUND_3D_SetDopplerFactor +, +FSOUND_3D_SetRolloffFactor +, +FSOUND_Update +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetCurrent.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetCurrent.html index 5c8ec34e..5df0b2b9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetCurrent.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_Listener_SetCurrent.html @@ -1,78 +1,78 @@ - - - - -FSOUND_3D_Listener_SetCurrent - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_Listener_SetCurrent

-Sets the current listener number and number of listeners, if the user wants to simulate multiple listeners at once.
-This is usually for the case in a game where there is a splitscreen and multiple players playing the game at once.
-

-void F_API FSOUND_3D_Listener_SetCurrent(
-int current,
-int numlisteners
-);
-

Parameters

- - - -
currentCurrent listener number. Listener commands following this function call will affect this listener number. (default: 0)
-
numlistenersNumber of listeners active. (default: 1)
-
-

Return Value

-void
-

Remarks

-Only affects FSOUND_3D_Listener_SetAttributes and FSOUND_3D_Listener_GetAttributes.
-Setting more than 1 listener will turn off doppler and cause all panning to be ignored and 3d sound will come from the center (mono).
--------------
-For WIN32 FSOUND_HW3D based sounds, channels must have their attributes set after this function is called, otherwise unexpected audible results may occur.
-For example you cannot update your channels with FSOUND_3D_SetAttributes, call FSOUND_3D_Listener_SetCurrent, and then call FSOUND_Update and expect all the voices to update correctly.
-The correct order is to call FSOUND_3D_Listener_SetCurrent first, then update all channels with FSOUND_3D_SetAttributes, then call FSOUND_Update.
-This is due to DirectSound not supporting multiple listeners, so FMOD has to do inverse transforms on the positions to simulate it with one listener, at the time FSOUND_3D_SetAttributes is called.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_Listener_GetAttributes -, -FSOUND_3D_Listener_SetAttributes -, -FSOUND_3D_Listener_SetCurrent -, -FSOUND_3D_SetAttributes -, -FSOUND_Update -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_Listener_SetCurrent + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_Listener_SetCurrent

+Sets the current listener number and number of listeners, if the user wants to simulate multiple listeners at once.
+This is usually for the case in a game where there is a splitscreen and multiple players playing the game at once.
+

+void F_API FSOUND_3D_Listener_SetCurrent(
+int current,
+int numlisteners
+);
+

Parameters

+ + + +
currentCurrent listener number. Listener commands following this function call will affect this listener number. (default: 0)
+
numlistenersNumber of listeners active. (default: 1)
+
+

Return Value

+void
+

Remarks

+Only affects FSOUND_3D_Listener_SetAttributes and FSOUND_3D_Listener_GetAttributes.
+Setting more than 1 listener will turn off doppler and cause all panning to be ignored and 3d sound will come from the center (mono).
+-------------
+For WIN32 FSOUND_HW3D based sounds, channels must have their attributes set after this function is called, otherwise unexpected audible results may occur.
+For example you cannot update your channels with FSOUND_3D_SetAttributes, call FSOUND_3D_Listener_SetCurrent, and then call FSOUND_Update and expect all the voices to update correctly.
+The correct order is to call FSOUND_3D_Listener_SetCurrent first, then update all channels with FSOUND_3D_SetAttributes, then call FSOUND_Update.
+This is due to DirectSound not supporting multiple listeners, so FMOD has to do inverse transforms on the positions to simulate it with one listener, at the time FSOUND_3D_SetAttributes is called.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_Listener_GetAttributes +, +FSOUND_3D_Listener_SetAttributes +, +FSOUND_3D_Listener_SetCurrent +, +FSOUND_3D_SetAttributes +, +FSOUND_Update +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetAttributes.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetAttributes.html index 8167cbc4..cc2a62a8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetAttributes.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetAttributes.html @@ -1,102 +1,102 @@ - - - - -FSOUND_3D_SetAttributes - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_SetAttributes

-This updates the position and velocity of a 3d sound playing on a channel.
-

-signed char F_API FSOUND_3D_SetAttributes(
-int channel,
-const F_FLOAT_API *pos,
-const F_FLOAT_API *vel
-);
-

Parameters

- - - - -
channelChannel you want to apply 3d positioning to.
-
posPointer to a position vector (xyz float triplet) of the emitter in world space, measured in distance units.
-This can be NULL to ignore it.
-
velPointer to a velocity vector (xyz float triplet), of the emitter measured in distance units PER SECOND.
-This can be NULL to ignore it.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND treats +X as right, +Y as up, and +Z as forwards.
----------
-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
----------
-FSOUND vectors expect 3 floats representing x y and z in that order. I.e. a typical definition
-of a vector is
-typedef struct
-{
-float x;
-float y;
-float z;
-} VECTOR;
-or simply an array of 3 floats.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_GetAttributes -, -FSOUND_3D_GetMinMaxDistance -, -FSOUND_3D_Listener_GetAttributes -, -FSOUND_3D_Listener_SetAttributes -, -FSOUND_3D_Listener_SetCurrent -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -, -FSOUND_3D_SetMinMaxDistance -, -FSOUND_3D_SetRolloffFactor -, -FSOUND_Sample_SetMinMaxDistance -, -FSOUND_Update -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_SetAttributes + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_SetAttributes

+This updates the position and velocity of a 3d sound playing on a channel.
+

+signed char F_API FSOUND_3D_SetAttributes(
+int channel,
+const F_FLOAT_API *pos,
+const F_FLOAT_API *vel
+);
+

Parameters

+ + + + +
channelChannel you want to apply 3d positioning to.
+
posPointer to a position vector (xyz float triplet) of the emitter in world space, measured in distance units.
+This can be NULL to ignore it.
+
velPointer to a velocity vector (xyz float triplet), of the emitter measured in distance units PER SECOND.
+This can be NULL to ignore it.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND treats +X as right, +Y as up, and +Z as forwards.
+---------
+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+---------
+FSOUND vectors expect 3 floats representing x y and z in that order. I.e. a typical definition
+of a vector is
+typedef struct
+{
+float x;
+float y;
+float z;
+} VECTOR;
+or simply an array of 3 floats.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_GetAttributes +, +FSOUND_3D_GetMinMaxDistance +, +FSOUND_3D_Listener_GetAttributes +, +FSOUND_3D_Listener_SetAttributes +, +FSOUND_3D_Listener_SetCurrent +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +, +FSOUND_3D_SetMinMaxDistance +, +FSOUND_3D_SetRolloffFactor +, +FSOUND_Sample_SetMinMaxDistance +, +FSOUND_Update +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDistanceFactor.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDistanceFactor.html index 6c6bc4d4..41b466d4 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDistanceFactor.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDistanceFactor.html @@ -1,75 +1,75 @@ - - - - -FSOUND_3D_SetDistanceFactor - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_SetDistanceFactor

-Sets FMOD's 3d engine relative distance factor, compared to 1.0 meters. It equates to
-'how many units per meter' does your engine have.
-

-void F_API FSOUND_3D_SetDistanceFactor(
-F_FLOAT_API factor
-);
-

Parameters

- - -
scale1.0 = 1 meter units. If you are using feet then scale would equal 3.28.
-
-

Return Value

-void
-

Remarks

-By default this value is set at 1.0, or meters.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_GetAttributes -, -FSOUND_3D_Listener_GetAttributes -, -FSOUND_3D_Listener_SetAttributes -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetMinMaxDistance -, -FSOUND_3D_SetRolloffFactor -, -FSOUND_Sample_GetMinMaxDistance -, -FSOUND_Sample_SetMinMaxDistance -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:27 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_SetDistanceFactor + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_SetDistanceFactor

+Sets FMOD's 3d engine relative distance factor, compared to 1.0 meters. It equates to
+'how many units per meter' does your engine have.
+

+void F_API FSOUND_3D_SetDistanceFactor(
+F_FLOAT_API factor
+);
+

Parameters

+ + +
scale1.0 = 1 meter units. If you are using feet then scale would equal 3.28.
+
+

Return Value

+void
+

Remarks

+By default this value is set at 1.0, or meters.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_GetAttributes +, +FSOUND_3D_Listener_GetAttributes +, +FSOUND_3D_Listener_SetAttributes +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetMinMaxDistance +, +FSOUND_3D_SetRolloffFactor +, +FSOUND_Sample_GetMinMaxDistance +, +FSOUND_Sample_SetMinMaxDistance +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:27 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDopplerFactor.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDopplerFactor.html index e27a4847..a90279e8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDopplerFactor.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetDopplerFactor.html @@ -1,67 +1,67 @@ - - - - -FSOUND_3D_SetDopplerFactor - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_SetDopplerFactor

-Sets the doppler shift scale factor.
-

-void F_API FSOUND_3D_SetDopplerFactor(
-F_FLOAT_API scale
-);
-

Parameters

- - -
scaleDoppler shift scale. Default value for FSOUND is 1.0f
-
-

Return Value

-void
-

Remarks

-This is a general scaling factor for how much the pitch varies due to doppler shifting.
-Increasing the value above 1.0 exaggerates the effect, whereas lowering it reduces the effect.
-0 removes the effect all together.
-FMOD's speed of sound at a DopplerFactor of 1.0 is 340 m/s.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_Listener_GetAttributes -, -FSOUND_3D_Listener_SetAttributes -, -FSOUND_Update -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_SetDopplerFactor + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_SetDopplerFactor

+Sets the doppler shift scale factor.
+

+void F_API FSOUND_3D_SetDopplerFactor(
+F_FLOAT_API scale
+);
+

Parameters

+ + +
scaleDoppler shift scale. Default value for FSOUND is 1.0f
+
+

Return Value

+void
+

Remarks

+This is a general scaling factor for how much the pitch varies due to doppler shifting.
+Increasing the value above 1.0 exaggerates the effect, whereas lowering it reduces the effect.
+0 removes the effect all together.
+FMOD's speed of sound at a DopplerFactor of 1.0 is 340 m/s.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_Listener_GetAttributes +, +FSOUND_3D_Listener_SetAttributes +, +FSOUND_Update +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetMinMaxDistance.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetMinMaxDistance.html index d85bbf1e..657f52ba 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetMinMaxDistance.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetMinMaxDistance.html @@ -1,88 +1,88 @@ - - - - -FSOUND_3D_SetMinMaxDistance - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_SetMinMaxDistance

-Sets the minimum and maximum audible distance for a channel.
-MinDistance is the minimum distance that the sound emitter will cease to continue growing
-louder at (as it approaches the listener). Within the mindistance it stays at the constant loudest volume possible. Outside of this mindistance it begins to attenuate.
-MaxDistance is the distance a sound stops attenuating at. Beyond this point it will stay at the volume it would be at maxdistance units from the listener and will not attenuate any more.
-MinDistance is useful to give the impression that the sound is loud or soft in 3d space. An example of this is a small quiet object, such as a bumblebee, which you could set a mindistance of to 0.1 for example, which would cause it to attenuate quickly and dissapear when only a few meters away from the listener.
-Another example is a jumbo jet, which you could set to a mindistance of 100.0, which would keep the sound volume at max until the listener was 100 meters away, then it would be hundreds of meters more before it would fade out.
--------
-In summary, increase the mindistance of a sound to make it 'louder' in a 3d world, and
-decrease it to make it 'quieter' in a 3d world.
-maxdistance is effectively obsolete unless you need the sound to stop fading out at a certain point. Do not adjust this from the default if you dont need to.
-Some people have the confusion that maxdistance is the point the sound will fade out to, this is not the case.
-

-signed char F_API FSOUND_3D_SetMinMaxDistance(
-int channel,
-F_FLOAT_API min,
-F_FLOAT_API max
-);
-

Parameters

- - - - -
sptrThe channel to have its minimum and maximum distance set.
-
minThe channels minimum volume distance in "units". See remarks for more on units.
-
maxThe channels maximum volume distance in "units". See remarks for more on units.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the min/max distance on ALL channels available.
-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
-The default units for minimum and maximum distances are 1.0 and 1000000000.0f.
-Volume drops off at mindistance / distance.
-To define the min and max distance per sound and not per channel use FSOUND_Sample_SetMinMaxDistance.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_GetMinMaxDistance -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -, -FSOUND_Sample_SetMinMaxDistance -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_SetMinMaxDistance + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_SetMinMaxDistance

+Sets the minimum and maximum audible distance for a channel.
+MinDistance is the minimum distance that the sound emitter will cease to continue growing
+louder at (as it approaches the listener). Within the mindistance it stays at the constant loudest volume possible. Outside of this mindistance it begins to attenuate.
+MaxDistance is the distance a sound stops attenuating at. Beyond this point it will stay at the volume it would be at maxdistance units from the listener and will not attenuate any more.
+MinDistance is useful to give the impression that the sound is loud or soft in 3d space. An example of this is a small quiet object, such as a bumblebee, which you could set a mindistance of to 0.1 for example, which would cause it to attenuate quickly and dissapear when only a few meters away from the listener.
+Another example is a jumbo jet, which you could set to a mindistance of 100.0, which would keep the sound volume at max until the listener was 100 meters away, then it would be hundreds of meters more before it would fade out.
+-------
+In summary, increase the mindistance of a sound to make it 'louder' in a 3d world, and
+decrease it to make it 'quieter' in a 3d world.
+maxdistance is effectively obsolete unless you need the sound to stop fading out at a certain point. Do not adjust this from the default if you dont need to.
+Some people have the confusion that maxdistance is the point the sound will fade out to, this is not the case.
+

+signed char F_API FSOUND_3D_SetMinMaxDistance(
+int channel,
+F_FLOAT_API min,
+F_FLOAT_API max
+);
+

Parameters

+ + + + +
sptrThe channel to have its minimum and maximum distance set.
+
minThe channels minimum volume distance in "units". See remarks for more on units.
+
maxThe channels maximum volume distance in "units". See remarks for more on units.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the min/max distance on ALL channels available.
+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+The default units for minimum and maximum distances are 1.0 and 1000000000.0f.
+Volume drops off at mindistance / distance.
+To define the min and max distance per sound and not per channel use FSOUND_Sample_SetMinMaxDistance.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_GetMinMaxDistance +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +, +FSOUND_Sample_SetMinMaxDistance +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetRolloffFactor.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetRolloffFactor.html index fd49b12e..978b72a5 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetRolloffFactor.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_3D_SetRolloffFactor.html @@ -1,73 +1,73 @@ - - - - -FSOUND_3D_SetRolloffFactor - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_3D_SetRolloffFactor

-Sets the global attenuation rolloff factor.
-Normally volume for a sample will scale at 1 / distance. This gives a logarithmic attenuation of volume as the source gets further away (or closer).
-Setting this value makes the sound drop off faster or slower. The higher the value, the faster volume will fall off.
-The lower the value, the slower it will fall off.
-For example a rolloff factor of 1 will simulate the real world, where as a value of 2 will make sounds attenuate 2 times quicker.
-

-void F_API FSOUND_3D_SetRolloffFactor(
-F_FLOAT_API factor
-);
-

Parameters

- - -
rolloffThe rolloff factor to set for this sample. Valid ranges are 0 to 10.
-
-

Return Value

-void
-

Remarks

----------
-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor.
-By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
----------
-The default rolloff factor is 1.0.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_Listener_SetAttributes -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_3D_SetRolloffFactor + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_3D_SetRolloffFactor

+Sets the global attenuation rolloff factor.
+Normally volume for a sample will scale at 1 / distance. This gives a logarithmic attenuation of volume as the source gets further away (or closer).
+Setting this value makes the sound drop off faster or slower. The higher the value, the faster volume will fall off.
+The lower the value, the slower it will fall off.
+For example a rolloff factor of 1 will simulate the real world, where as a value of 2 will make sounds attenuate 2 times quicker.
+

+void F_API FSOUND_3D_SetRolloffFactor(
+F_FLOAT_API factor
+);
+

Parameters

+ + +
rolloffThe rolloff factor to set for this sample. Valid ranges are 0 to 10.
+
+

Return Value

+void
+

Remarks

+---------
+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor.
+By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+---------
+The default rolloff factor is 1.0.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_Listener_SetAttributes +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_ALLOCCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_ALLOCCALLBACK.html index 6da446c8..7fa83d05 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_ALLOCCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_ALLOCCALLBACK.html @@ -1,67 +1,67 @@ - - - - -FSOUND_ALLOCCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_ALLOCCALLBACK

-Callback to allocate a block of memory.
-

-void * F_CALLBACKAPI FSOUND_ALLOCCALLBACK(
-unsigned int size
-);
-

Parameters

- - -
sizeSize in bytes of the memory block to be allocated and returned.
-
-

Return Value

-On success, a pointer to the newly allocated block of memory is returned.
-On failure, NULL is returned.
-

Remarks

-Returning an aligned pointer, of 16 byte alignment is recommended for speed purposes.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_FREECALLBACK -, -FSOUND_GetMemoryStats -, -FSOUND_REALLOCCALLBACK -, -FSOUND_SetMemorySystem -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_ALLOCCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_ALLOCCALLBACK

+Callback to allocate a block of memory.
+

+void * F_CALLBACKAPI FSOUND_ALLOCCALLBACK(
+unsigned int size
+);
+

Parameters

+ + +
sizeSize in bytes of the memory block to be allocated and returned.
+
+

Return Value

+On success, a pointer to the newly allocated block of memory is returned.
+On failure, NULL is returned.
+

Remarks

+Returning an aligned pointer, of 16 byte alignment is recommended for speed purposes.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_FREECALLBACK +, +FSOUND_GetMemoryStats +, +FSOUND_REALLOCCALLBACK +, +FSOUND_SetMemorySystem +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CAPS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CAPS.html index 537ac223..36004020 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CAPS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CAPS.html @@ -1,61 +1,61 @@ - - - - -FSOUND_CAPS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_CAPS

-Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated
-has the settings you are after. The enumerated driver depends on the output mode, see
-FSOUND_OUTPUTTYPES
-

- - - - - - - -
FSOUND_CAPS_HARDWARE0x1 /* This driver supports hardware accelerated 3d sound. */ -
FSOUND_CAPS_EAX20x2 /* This driver supports EAX 2 reverb */ -
FSOUND_CAPS_EAX30x10 /* This driver supports EAX 3 reverb */ -
-

See Also

-FSOUND_GetDriverCaps -, -FSOUND_OUTPUTTYPES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CAPS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_CAPS

+Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated
+has the settings you are after. The enumerated driver depends on the output mode, see
+FSOUND_OUTPUTTYPES
+

+ + + + + + + +
FSOUND_CAPS_HARDWARE0x1 /* This driver supports hardware accelerated 3d sound. */ +
FSOUND_CAPS_EAX20x2 /* This driver supports EAX 2 reverb */ +
FSOUND_CAPS_EAX30x10 /* This driver supports EAX 3 reverb */ +
+

See Also

+FSOUND_GetDriverCaps +, +FSOUND_OUTPUTTYPES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CDPLAYMODES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CDPLAYMODES.html index f8644cfe..2ad3c74f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CDPLAYMODES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CDPLAYMODES.html @@ -1,62 +1,62 @@ - - - - -FSOUND_CDPLAYMODES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_CDPLAYMODES

-Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode
-

- - - - - - - - - -
FSOUND_CD_PLAYCONTINUOUS0 /* Starts from the current track and plays to end of CD. */ -
FSOUND_CD_PLAYONCE1 /* Plays the specified track then stops. */ -
FSOUND_CD_PLAYLOOPED2 /* Plays the specified track looped, forever until stopped manually. */ -
FSOUND_CD_PLAYRANDOM3 /* Plays tracks in random order */ -
-

See Also

-FSOUND_CD_Play -, -FSOUND_CD_SetPlayMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CDPLAYMODES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_CDPLAYMODES

+Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode
+

+ + + + + + + + + +
FSOUND_CD_PLAYCONTINUOUS0 /* Starts from the current track and plays to end of CD. */ +
FSOUND_CD_PLAYONCE1 /* Plays the specified track then stops. */ +
FSOUND_CD_PLAYLOOPED2 /* Plays the specified track looped, forever until stopped manually. */ +
FSOUND_CD_PLAYRANDOM3 /* Plays tracks in random order */ +
+

See Also

+FSOUND_CD_Play +, +FSOUND_CD_SetPlayMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetNumTracks.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetNumTracks.html index 76fe4a71..72c87669 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetNumTracks.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetNumTracks.html @@ -1,60 +1,60 @@ - - - - -FSOUND_CD_GetNumTracks - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_GetNumTracks

-Returns the number of tracks on the currently inserted CD.
-

-int F_API FSOUND_CD_GetNumTracks(
-char drive
-);
-

Parameters

- - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
-

Return Value

-On success, the number of CD tracks on the currently inserted is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux
-

See Also

-FSOUND_CD_GetTrack -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_GetNumTracks + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_GetNumTracks

+Returns the number of tracks on the currently inserted CD.
+

+int F_API FSOUND_CD_GetNumTracks(
+char drive
+);
+

Parameters

+ + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
+

Return Value

+On success, the number of CD tracks on the currently inserted is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux
+

See Also

+FSOUND_CD_GetTrack +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetPaused.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetPaused.html index 0cd5eb27..aadf0541 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetPaused.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetPaused.html @@ -1,58 +1,58 @@ - - - - -FSOUND_CD_GetPaused - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_GetPaused

-Gets the pause status of the current CD audio track.
-

-signed char F_API FSOUND_CD_GetPaused(
-char drive
-);
-

Parameters

- - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
-

Return Value

-If the track is currently paused, TRUE is returned.
-If the track is currently not paused, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_GetPaused + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_GetPaused

+Gets the pause status of the current CD audio track.
+

+signed char F_API FSOUND_CD_GetPaused(
+char drive
+);
+

Parameters

+ + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
+

Return Value

+If the track is currently paused, TRUE is returned.
+If the track is currently not paused, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrack.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrack.html index ade8be86..8cdedf69 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrack.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrack.html @@ -1,60 +1,60 @@ - - - - -FSOUND_CD_GetTrack - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_GetTrack

-Returns the currently playing CD track number.
-

-int F_API FSOUND_CD_GetTrack(
-char drive
-);
-

Parameters

- - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
-

Return Value

-On success, the CD track number currently playing is returned. (starts from 1)
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_GetNumTracks -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_GetTrack + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_GetTrack

+Returns the currently playing CD track number.
+

+int F_API FSOUND_CD_GetTrack(
+char drive
+);
+

Parameters

+ + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
+

Return Value

+On success, the CD track number currently playing is returned. (starts from 1)
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_GetNumTracks +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackLength.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackLength.html index 07584c26..e6dfef9d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackLength.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackLength.html @@ -1,65 +1,65 @@ - - - - -FSOUND_CD_GetTrackLength - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_GetTrackLength

-Gets the track length of a CD.
-

-int F_API FSOUND_CD_GetTrackLength(
-char drive,
-int track
-);
-

Parameters

- - - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
trackThe CD track number to query the length of. (starts from 1)
-
-

Return Value

-On success, the length of the current track in milliseconds is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_GetTrackTime -, -FSOUND_CD_SetTrackTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_GetTrackLength + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_GetTrackLength

+Gets the track length of a CD.
+

+int F_API FSOUND_CD_GetTrackLength(
+char drive,
+int track
+);
+

Parameters

+ + + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
trackThe CD track number to query the length of. (starts from 1)
+
+

Return Value

+On success, the length of the current track in milliseconds is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_GetTrackTime +, +FSOUND_CD_SetTrackTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackTime.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackTime.html index e8174912..fad55dda 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackTime.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetTrackTime.html @@ -1,66 +1,66 @@ - - - - -FSOUND_CD_GetTrackTime - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_GetTrackTime

-Returns the current track time playing on a CD.
-

-int F_API FSOUND_CD_GetTrackTime(
-char drive
-);
-

Parameters

- - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
-

Return Value

-On success, the position of the current playing track in milliseconds is returned.
-On failure, 0 is returned.
-

Remarks

-This is easily one of the slowest functions in the FMOD API. Please use it sparingly.
-It seems like it shouldnt take long, but because of windows MCI API it does, and not just a little bit of time, it takes a LOT.
-It seems to poll the CD driver and cause a large delay upon completion of the command.
-Different algorithms were used to try and emulate this function such as simply using a timer, but this was very inaccurate, especially when pausing/unpausing a lot.
-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_GetTrackLength -, -FSOUND_CD_SetTrackTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_GetTrackTime + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_GetTrackTime

+Returns the current track time playing on a CD.
+

+int F_API FSOUND_CD_GetTrackTime(
+char drive
+);
+

Parameters

+ + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
+

Return Value

+On success, the position of the current playing track in milliseconds is returned.
+On failure, 0 is returned.
+

Remarks

+This is easily one of the slowest functions in the FMOD API. Please use it sparingly.
+It seems like it shouldnt take long, but because of windows MCI API it does, and not just a little bit of time, it takes a LOT.
+It seems to poll the CD driver and cause a large delay upon completion of the command.
+Different algorithms were used to try and emulate this function such as simply using a timer, but this was very inaccurate, especially when pausing/unpausing a lot.
+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_GetTrackLength +, +FSOUND_CD_SetTrackTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetVolume.html index a052b465..b223609d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_GetVolume.html @@ -1,64 +1,64 @@ - - - - -FSOUND_CD_GetVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_GetVolume

-Returns the volume of the playing CD audio.
-

-int F_API FSOUND_CD_GetVolume(
-char drive
-);
-

Parameters

- - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
-

Return Value

-On success, a value between 0 and 255 is returned, 0 being the lowest volume and 255 being the highest.
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_Play -, -FSOUND_CD_SetVolume -, -FSOUND_Close -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_GetVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_GetVolume

+Returns the volume of the playing CD audio.
+

+int F_API FSOUND_CD_GetVolume(
+char drive
+);
+

Parameters

+ + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
+

Return Value

+On success, a value between 0 and 255 is returned, 0 being the lowest volume and 255 being the highest.
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_Play +, +FSOUND_CD_SetVolume +, +FSOUND_Close +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_OpenTray.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_OpenTray.html index 9c71c0d1..7250a8aa 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_OpenTray.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_OpenTray.html @@ -1,61 +1,61 @@ - - - - -FSOUND_CD_OpenTray - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_OpenTray

-Opens/Closes the CD tray.
-

-signed char F_API FSOUND_CD_OpenTray(
-char drive,
-signed char open
-);
-

Parameters

- - - -
driveThe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
openIf open is set to 1, the CD tray will be opened. If open is set to 0, the CD tray will be closed.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_OpenTray + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_OpenTray

+Opens/Closes the CD tray.
+

+signed char F_API FSOUND_CD_OpenTray(
+char drive,
+signed char open
+);
+

Parameters

+ + + +
driveThe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
openIf open is set to 1, the CD tray will be opened. If open is set to 0, the CD tray will be closed.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPaused.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPaused.html index 7b77a273..58d4e18c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPaused.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPaused.html @@ -1,61 +1,61 @@ - - - - -FSOUND_CD_SetPaused - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_SetPaused

-Sets the pause status of the currently playing CD audio track.
-

-signed char F_API FSOUND_CD_SetPaused(
-char drive,
-signed char paused
-);
-

Parameters

- - - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
pausedTRUE to pause track, FALSE to unpause track.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_SetPaused + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_SetPaused

+Sets the pause status of the currently playing CD audio track.
+

+signed char F_API FSOUND_CD_SetPaused(
+char drive,
+signed char paused
+);
+

Parameters

+ + + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
pausedTRUE to pause track, FALSE to unpause track.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPlayMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPlayMode.html index 634bb3ad..bf157ef8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPlayMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetPlayMode.html @@ -1,64 +1,64 @@ - - - - -FSOUND_CD_SetPlayMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_SetPlayMode

-Sets the playback mode of the CD.
-

-void F_API FSOUND_CD_SetPlayMode(
-char drive,
-signed char mode
-);
-

Parameters

- - - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
modeSee FSOUND_CDPLAYMODES for a list of valid parameters to send to this function.
-
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_Play -, -FSOUND_CDPLAYMODES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_SetPlayMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_SetPlayMode

+Sets the playback mode of the CD.
+

+void F_API FSOUND_CD_SetPlayMode(
+char drive,
+signed char mode
+);
+

Parameters

+ + + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
modeSee FSOUND_CDPLAYMODES for a list of valid parameters to send to this function.
+
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_Play +, +FSOUND_CDPLAYMODES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetTrackTime.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetTrackTime.html index 1fa551c7..63f8b32a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetTrackTime.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetTrackTime.html @@ -1,66 +1,66 @@ - - - - -FSOUND_CD_SetTrackTime - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_SetTrackTime

-Performs a seek within a track specified by milliseconds.
-

-signed char F_API FSOUND_CD_SetTrackTime(
-char drive,
-unsigned int ms
-);
-

Parameters

- - - -
driveThe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
msTime to seek into the current track in milliseconds.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function will start the track if it is not playing.
-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_GetTrackLength -, -FSOUND_CD_GetTrackTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_SetTrackTime + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_SetTrackTime

+Performs a seek within a track specified by milliseconds.
+

+signed char F_API FSOUND_CD_SetTrackTime(
+char drive,
+unsigned int ms
+);
+

Parameters

+ + + +
driveThe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
msTime to seek into the current track in milliseconds.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function will start the track if it is not playing.
+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_GetTrackLength +, +FSOUND_CD_GetTrackTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetVolume.html index f4e2c8f9..1b1b745b 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_SetVolume.html @@ -1,67 +1,67 @@ - - - - -FSOUND_CD_SetVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_SetVolume

-Sets the volume of the playing CD audio.
-

-signed char F_API FSOUND_CD_SetVolume(
-char drive,
-int volume
-);
-

Parameters

- - - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
volumeAn integer value from 0-255. 0 being the lowest volume, 255 being the highest (full).
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_GetVolume -, -FSOUND_CD_Play -, -FSOUND_Close -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_SetVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_SetVolume

+Sets the volume of the playing CD audio.
+

+signed char F_API FSOUND_CD_SetVolume(
+char drive,
+int volume
+);
+

Parameters

+ + + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
volumeAn integer value from 0-255. 0 being the lowest volume, 255 being the highest (full).
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_GetVolume +, +FSOUND_CD_Play +, +FSOUND_Close +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_Stop.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_Stop.html index 1d00c23b..a9fd676c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_Stop.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CD_Stop.html @@ -1,60 +1,60 @@ - - - - -FSOUND_CD_Stop - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CD_Stop

-Stops the currently playing CD audio track.
-

-signed char F_API FSOUND_CD_Stop(
-char drive
-);
-

Parameters

- - -
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
-

See Also

-FSOUND_CD_Play -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CD_Stop + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CD_Stop

+Stops the currently playing CD audio track.
+

+signed char F_API FSOUND_CD_Stop(
+char drive
+);
+

Parameters

+ + +
drivethe drive ID to use. 0 is the default CD drive. Using D or E in single quotes would be D: or E: for example.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Linux, Macintosh (OSX CFM Only)
+

See Also

+FSOUND_CD_Play +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CLOSECALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CLOSECALLBACK.html index fd8c3a0a..2df7a05c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CLOSECALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_CLOSECALLBACK.html @@ -1,68 +1,68 @@ - - - - -FSOUND_CLOSECALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_CLOSECALLBACK

-Calback for closing a file.
-

-void F_CALLBACKAPI FSOUND_CLOSECALLBACK(
-void *handle
-);
-

Parameters

- - -
handleThis is the handle you returned from the open callback to use for your own file routines.
-
-

Return Value

-void
-

Remarks

-Close your file handle and do any cleanup here.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_File_SetCallbacks -, -FSOUND_OPENCALLBACK -, -FSOUND_READCALLBACK -, -FSOUND_SEEKCALLBACK -, -FSOUND_TELLCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_CLOSECALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_CLOSECALLBACK

+Calback for closing a file.
+

+void F_CALLBACKAPI FSOUND_CLOSECALLBACK(
+void *handle
+);
+

Parameters

+ + +
handleThis is the handle you returned from the open callback to use for your own file routines.
+
+

Return Value

+void
+

Remarks

+Close your file handle and do any cleanup here.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_File_SetCallbacks +, +FSOUND_OPENCALLBACK +, +FSOUND_READCALLBACK +, +FSOUND_SEEKCALLBACK +, +FSOUND_TELLCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Close.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Close.html index 871584ed..2401744c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Close.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Close.html @@ -1,84 +1,84 @@ - - - - -FSOUND_Close - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Close

-Shuts down the WHOLE FMOD Sound System.
-

-void F_API FSOUND_Close(
-);
-

Return Value

-void
-

Remarks

-This also closes down the sample management system, freeing all MANAGED samples loaded (unless they were allocated with the FSOUND_UNMANAGED flag).
-Streams are not freed. You must close them yourself.
-CD Tracks are stopped.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_CD_GetVolume -, -FSOUND_CD_SetVolume -, -FSOUND_Init -, -FSOUND_Sample_Alloc -, -FSOUND_Sample_Get -, -FSOUND_Sample_Load -, -FSOUND_SetBufferSize -, -FSOUND_SetDriver -, -FSOUND_SetHWND -, -FSOUND_SetMaxHardwareChannels -, -FSOUND_SetMemorySystem -, -FSOUND_SetMinHardwareChannels -, -FSOUND_SetMixer -, -FSOUND_SetOutput -, -FSOUND_SetSpeakerMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Close + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Close

+Shuts down the WHOLE FMOD Sound System.
+

+void F_API FSOUND_Close(
+);
+

Return Value

+void
+

Remarks

+This also closes down the sample management system, freeing all MANAGED samples loaded (unless they were allocated with the FSOUND_UNMANAGED flag).
+Streams are not freed. You must close them yourself.
+CD Tracks are stopped.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_CD_GetVolume +, +FSOUND_CD_SetVolume +, +FSOUND_Init +, +FSOUND_Sample_Alloc +, +FSOUND_Sample_Get +, +FSOUND_Sample_Load +, +FSOUND_SetBufferSize +, +FSOUND_SetDriver +, +FSOUND_SetHWND +, +FSOUND_SetMaxHardwareChannels +, +FSOUND_SetMemorySystem +, +FSOUND_SetMinHardwareChannels +, +FSOUND_SetMixer +, +FSOUND_SetOutput +, +FSOUND_SetSpeakerMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSPCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSPCALLBACK.html index 7d130dfb..60da7080 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSPCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSPCALLBACK.html @@ -1,71 +1,71 @@ - - - - -FSOUND_DSPCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSPCALLBACK

-Callback definition for DSP units.
-

-void * F_CALLBACKAPI FSOUND_DSPCALLBACK(
-void *originalbuffer,
-void *newbuffer,
-int length,
-void *userdata
-);
-

Parameters

- - - - - -
originalbufferThis is the pointer to the original buffer passed into the first DSP unit. This is useful if you want the clean, original data, and you have been returning new modified buffers for the DSP chain to use.
-
newbufferThis is a pointer to the previous DSP buffer that *it* returned. This buffer that this DSP returns will be passed into the newbuffer parameter of the NEXT unit in the DSP chain.
-
lengthThe length of the buffer provided in SAMPLES, not bytes.
-
paramA user data value specified in FSOUND_DSP_Create.
-
-

Return Value

-Pointer to a sample buffer for the next DSP unit to use.
-

Remarks

-You must return the buffer you work on, or it will not be fed through to the next DSP unit, and eventually the the system clip and copy unit, which makes the sound audible.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_Stream_CreateDSP -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSPCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSPCALLBACK

+Callback definition for DSP units.
+

+void * F_CALLBACKAPI FSOUND_DSPCALLBACK(
+void *originalbuffer,
+void *newbuffer,
+int length,
+void *userdata
+);
+

Parameters

+ + + + + +
originalbufferThis is the pointer to the original buffer passed into the first DSP unit. This is useful if you want the clean, original data, and you have been returning new modified buffers for the DSP chain to use.
+
newbufferThis is a pointer to the previous DSP buffer that *it* returned. This buffer that this DSP returns will be passed into the newbuffer parameter of the NEXT unit in the DSP chain.
+
lengthThe length of the buffer provided in SAMPLES, not bytes.
+
paramA user data value specified in FSOUND_DSP_Create.
+
+

Return Value

+Pointer to a sample buffer for the next DSP unit to use.
+

Remarks

+You must return the buffer you work on, or it will not be fed through to the next DSP unit, and eventually the the system clip and copy unit, which makes the sound audible.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_Stream_CreateDSP +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_ClearMixBuffer.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_ClearMixBuffer.html index 52938179..1cdc533e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_ClearMixBuffer.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_ClearMixBuffer.html @@ -1,75 +1,75 @@ - - - - -FSOUND_DSP_ClearMixBuffer - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_ClearMixBuffer

-Clears the mixbuffer, especially handy if you are doing a large file operation which
-halts the system.
-You might try and stop all the sounds, but if you do your file operation straight after
-this, it will not have a chance to flush the mixbuffer normally, so this function is called.
-It stops the effect of stuttering looping sound while your file operation happens.
-

-void F_API FSOUND_DSP_ClearMixBuffer(
-);
-

Return Value

-

Remarks

-The best way to do it is like this. Turn off the sfx and music DSP units, clear the mix buffer,
-then when the operation that halts the machine is done, just re-enable the sfx and music DSP units.
-Disabling these units stops the timer trying to get 1 or 2 more mixes in during the file operation,
-which will cause more stuttering.
-ie.
-FSOUND_DSP_SetActive(FSOUND_DSP_GetSFXUnit(), FALSE);
-FSOUND_DSP_SetActive(FSOUND_DSP_GetMusicUnit(), FALSE);
-FSOUND_DSP_ClearMixBuffer();
-//
-// maching halting operation here
-//
-FSOUND_DSP_SetActive(FSOUND_DSP_GetSFXUnit(), TRUE);
-FSOUND_DSP_SetActive(FSOUND_DSP_GetMusicUnit(), TRUE);
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_ClearMixBuffer -, -FSOUND_DSP_GetMusicUnit -, -FSOUND_DSP_GetSFXUnit -, -FSOUND_DSP_SetActive -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_ClearMixBuffer + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_ClearMixBuffer

+Clears the mixbuffer, especially handy if you are doing a large file operation which
+halts the system.
+You might try and stop all the sounds, but if you do your file operation straight after
+this, it will not have a chance to flush the mixbuffer normally, so this function is called.
+It stops the effect of stuttering looping sound while your file operation happens.
+

+void F_API FSOUND_DSP_ClearMixBuffer(
+);
+

Return Value

+

Remarks

+The best way to do it is like this. Turn off the sfx and music DSP units, clear the mix buffer,
+then when the operation that halts the machine is done, just re-enable the sfx and music DSP units.
+Disabling these units stops the timer trying to get 1 or 2 more mixes in during the file operation,
+which will cause more stuttering.
+ie.
+FSOUND_DSP_SetActive(FSOUND_DSP_GetSFXUnit(), FALSE);
+FSOUND_DSP_SetActive(FSOUND_DSP_GetMusicUnit(), FALSE);
+FSOUND_DSP_ClearMixBuffer();
+//
+// maching halting operation here
+//
+FSOUND_DSP_SetActive(FSOUND_DSP_GetSFXUnit(), TRUE);
+FSOUND_DSP_SetActive(FSOUND_DSP_GetMusicUnit(), TRUE);
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_ClearMixBuffer +, +FSOUND_DSP_GetMusicUnit +, +FSOUND_DSP_GetSFXUnit +, +FSOUND_DSP_SetActive +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Create.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Create.html index e9306d83..b51b458e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Create.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Create.html @@ -1,183 +1,183 @@ - - - - -FSOUND_DSP_Create - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_Create

-Creates a DSP unit, and places it in the DSP chain position specified by the priority
-parameter. Read the remarks section carefully for issues regarding DSP units.
-DSP units are freed with FSOUND_DSP_Free.
-

-FSOUND_DSPUNIT *F_API FSOUND_DSP_Create(
-FSOUND_DSPCALLBACK callback,
-int priority,
-void *userdata
-);
-

Parameters

- - - - -
callbackThis is a pointer to your DSP Unit callback, of type FSOUND_DSPCALLBACK.
-The prototype for a callback is declared in the following fashion.
-Callbacks must return a pointer to the buffer you work on, so that
-the next dsp unit can work on it.
-Here is the simplest case:
-void *callback(void *originalbuffer, void *newbuffer, int length, void *userdata)
-{
-// originalbuffer = fsounds original mixbuffer.
-// newbuffer = the buffer passed from the previous DSP unit.
-// length = length in samples at this mix time.
-// param = user parameter passed through in FSOUND_DSP_Create.
-//
-// modify the buffer in some fashion
-return newbuffer;
-}
-See the definition of FSOUND_DSPCALLBACK for more.
-
priorityOrder in the priority chain. Valid numbers are 0 to 1000, 0 being
-highest priority (first), with 1000 being lowest priority (last).
-Note that FSOUNDs soundeffects mixers and copy routines are considered
-part of this DSP unit chain which you can play with.
-
paramUser defined parameter, this gets passed into the callback when it is
-called. It is safe to leave this value 0.
-
-

Return Value

-On success, a pointer to a new valid DSP unit is returned.
-On failure, NULL is returned.
-

Remarks

-A dsp unit is NOT ACTIVE by default. You have to activate it with FSOUND_DSP_SetActive
----------------------------------------------------------------------------------------
-Priorities and default system units.
----------------------------------------------------------------------------------------
-A note on priorities. FSOUND processes DSP units in order of priority. A 0 priority
-unit gets processed first, a 1 priority unit gets processed next, and so on.
-FSOUND actually uses these DSP units to mix its sound effects and music! Yes, you have
-access to them (be careful!). It is possible to totally remove, replace or deactivate
-all of FSOUND's system units so that it does nothing at all!
-FSOUND has preinstalled default system units at the following priority locations:
-FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT (priority 0) - Clear Unit. This unit clears out
-the mixbuffer for the next units to mix into. You can disable this unit and replace
-it with something other than a clearer, such as a scaler, which fades down the mix
-buffer instead of clearing it, to produce a very rough echo effect.
-FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT (priority 100) - SFX Unit. This unit mixes sound
-effect channels into the mix buffer, which was previously cleared with the Clear
-Unit.
-FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT (priority 200) - Music Unit. This unit mixes all
-music channels into the mix buffer, which was previously mixed into with the SFX
-Unit.
-FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT (priority 1000) - Clip and Copy Unit. This
-unit takes the finally mixed buffer, and clips it to the output stream size (if it
-needs to), and then sends it off to the sound device. It is done last. If this is
-disabled you will hear no sound.
----------------------------------------------------------------------------------------
-Buffer Lengths.
----------------------------------------------------------------------------------------
-The 'length' value of the DSP callback is roughly 20ms worth of data.
-Use FSOUND_DSP_GetBufferLength to get the exact callback length.
----------------------------------------------------------------------------------------
-Buffer Widths
----------------------------------------------------------------------------------------
-Remember that FSOUND uses different buffer types depending on what type of mixer it is.
-You will have to compensate for this by writing different routines depending on the
-mixer type (ie mmx or non mmx), just like FSOUND does.
-Currently there are the 3 types of mixers and their buffer sizes.
-You can get the type of mixer being used by calling the FSOUND_GetMixer function.
-You may want to check on this inside your callback, or set up a function pointer system,
-whatever you think is suitable (it costs nothing to do a FSOUND_GetMixer every time).
-- FSOUND_MIXER_BLENDMODE : This buffer is a stereo, signed 32bit buffer (8 bytes per
-sample). The data is in integer format.
-Data written to this buffer is not clipped and passed to the output stream until the
-very end of the chain (the clip and copy unit). For this type of mixer, you dont
-have to worry about clipping becuase FSOUND does this for you.
-- FSOUND_MIXER_QUALITY_FPU / FSOUND_MIXER_QUALITY_FPU_VOLUMERAMP: This buffer is also a
-stereo, signed 32bit buffer (8 bytes per sample). This data is in floating point
-format.
-The same clip and copy rules apply here as for the above mixer.
-- Any MMX based mixer : This buffer is a stereo, signed 16bit buffer (4 bytes per sample).
-When writing to this buffer, you must make sure the result does not overflow this
-signed 16bit range.
-If you add data into to this buffer, make sure it is clipped to a signed 16bit range
-before writing it back. FSOUND only copies this data to the output stream, it does
-not clip it.
----------------------------------------------------------------------------------------
-Speed
----------------------------------------------------------------------------------------
-DSP Units are processed then and there, inside the mixing routine. Remember to make
-your process as FAST as possible, or the output device's play cursor will catch up to
-FSOUND's write cursor while your routine takes its time to complete, and make it start
-to break up.
-So basically, if it isnt fast, then FSOUND will not be able to send the data to the
-output device in time for the next mixer update, and the result will be corrupted sound.
-FSOUND_DSP_MixBuffers is available now, so if you need to mix some raw data into the output
-buffer quickly, you can use FSOUND's own optimized mixer directly to do it!
-Finally, you can see how your routine affects cpu usage, by using FSOUND_GetCPUUsage.
-The cpu usage returned by this function includes any time spent in DSP units as well.
-(this function times everything). If you are really bored, you can see how much FSOUND's
-system units take cpu-wise, by turning them on and off and seeing how they affect
-performance.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_Free -, -FSOUND_DSP_GetBufferLength -, -FSOUND_DSP_GetBufferLengthTotal -, -FSOUND_DSP_MixBuffers -, -FSOUND_DSP_PRIORITIES -, -FSOUND_DSP_SetActive -, -FSOUND_DSP_SetPriority -, -FSOUND_DSPCALLBACK -, -FSOUND_GetCPUUsage -, -FSOUND_GetMixer -, -FSOUND_MIXERTYPES -, -FSOUND_PlaySoundEx -, -FSOUND_Stream_CreateDSP -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_Create + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_Create

+Creates a DSP unit, and places it in the DSP chain position specified by the priority
+parameter. Read the remarks section carefully for issues regarding DSP units.
+DSP units are freed with FSOUND_DSP_Free.
+

+FSOUND_DSPUNIT *F_API FSOUND_DSP_Create(
+FSOUND_DSPCALLBACK callback,
+int priority,
+void *userdata
+);
+

Parameters

+ + + + +
callbackThis is a pointer to your DSP Unit callback, of type FSOUND_DSPCALLBACK.
+The prototype for a callback is declared in the following fashion.
+Callbacks must return a pointer to the buffer you work on, so that
+the next dsp unit can work on it.
+Here is the simplest case:
+void *callback(void *originalbuffer, void *newbuffer, int length, void *userdata)
+{
+// originalbuffer = fsounds original mixbuffer.
+// newbuffer = the buffer passed from the previous DSP unit.
+// length = length in samples at this mix time.
+// param = user parameter passed through in FSOUND_DSP_Create.
+//
+// modify the buffer in some fashion
+return newbuffer;
+}
+See the definition of FSOUND_DSPCALLBACK for more.
+
priorityOrder in the priority chain. Valid numbers are 0 to 1000, 0 being
+highest priority (first), with 1000 being lowest priority (last).
+Note that FSOUNDs soundeffects mixers and copy routines are considered
+part of this DSP unit chain which you can play with.
+
paramUser defined parameter, this gets passed into the callback when it is
+called. It is safe to leave this value 0.
+
+

Return Value

+On success, a pointer to a new valid DSP unit is returned.
+On failure, NULL is returned.
+

Remarks

+A dsp unit is NOT ACTIVE by default. You have to activate it with FSOUND_DSP_SetActive
+---------------------------------------------------------------------------------------
+Priorities and default system units.
+---------------------------------------------------------------------------------------
+A note on priorities. FSOUND processes DSP units in order of priority. A 0 priority
+unit gets processed first, a 1 priority unit gets processed next, and so on.
+FSOUND actually uses these DSP units to mix its sound effects and music! Yes, you have
+access to them (be careful!). It is possible to totally remove, replace or deactivate
+all of FSOUND's system units so that it does nothing at all!
+FSOUND has preinstalled default system units at the following priority locations:
+FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT (priority 0) - Clear Unit. This unit clears out
+the mixbuffer for the next units to mix into. You can disable this unit and replace
+it with something other than a clearer, such as a scaler, which fades down the mix
+buffer instead of clearing it, to produce a very rough echo effect.
+FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT (priority 100) - SFX Unit. This unit mixes sound
+effect channels into the mix buffer, which was previously cleared with the Clear
+Unit.
+FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT (priority 200) - Music Unit. This unit mixes all
+music channels into the mix buffer, which was previously mixed into with the SFX
+Unit.
+FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT (priority 1000) - Clip and Copy Unit. This
+unit takes the finally mixed buffer, and clips it to the output stream size (if it
+needs to), and then sends it off to the sound device. It is done last. If this is
+disabled you will hear no sound.
+---------------------------------------------------------------------------------------
+Buffer Lengths.
+---------------------------------------------------------------------------------------
+The 'length' value of the DSP callback is roughly 20ms worth of data.
+Use FSOUND_DSP_GetBufferLength to get the exact callback length.
+---------------------------------------------------------------------------------------
+Buffer Widths
+---------------------------------------------------------------------------------------
+Remember that FSOUND uses different buffer types depending on what type of mixer it is.
+You will have to compensate for this by writing different routines depending on the
+mixer type (ie mmx or non mmx), just like FSOUND does.
+Currently there are the 3 types of mixers and their buffer sizes.
+You can get the type of mixer being used by calling the FSOUND_GetMixer function.
+You may want to check on this inside your callback, or set up a function pointer system,
+whatever you think is suitable (it costs nothing to do a FSOUND_GetMixer every time).
+- FSOUND_MIXER_BLENDMODE : This buffer is a stereo, signed 32bit buffer (8 bytes per
+sample). The data is in integer format.
+Data written to this buffer is not clipped and passed to the output stream until the
+very end of the chain (the clip and copy unit). For this type of mixer, you dont
+have to worry about clipping becuase FSOUND does this for you.
+- FSOUND_MIXER_QUALITY_FPU / FSOUND_MIXER_QUALITY_FPU_VOLUMERAMP: This buffer is also a
+stereo, signed 32bit buffer (8 bytes per sample). This data is in floating point
+format.
+The same clip and copy rules apply here as for the above mixer.
+- Any MMX based mixer : This buffer is a stereo, signed 16bit buffer (4 bytes per sample).
+When writing to this buffer, you must make sure the result does not overflow this
+signed 16bit range.
+If you add data into to this buffer, make sure it is clipped to a signed 16bit range
+before writing it back. FSOUND only copies this data to the output stream, it does
+not clip it.
+---------------------------------------------------------------------------------------
+Speed
+---------------------------------------------------------------------------------------
+DSP Units are processed then and there, inside the mixing routine. Remember to make
+your process as FAST as possible, or the output device's play cursor will catch up to
+FSOUND's write cursor while your routine takes its time to complete, and make it start
+to break up.
+So basically, if it isnt fast, then FSOUND will not be able to send the data to the
+output device in time for the next mixer update, and the result will be corrupted sound.
+FSOUND_DSP_MixBuffers is available now, so if you need to mix some raw data into the output
+buffer quickly, you can use FSOUND's own optimized mixer directly to do it!
+Finally, you can see how your routine affects cpu usage, by using FSOUND_GetCPUUsage.
+The cpu usage returned by this function includes any time spent in DSP units as well.
+(this function times everything). If you are really bored, you can see how much FSOUND's
+system units take cpu-wise, by turning them on and off and seeing how they affect
+performance.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_Free +, +FSOUND_DSP_GetBufferLength +, +FSOUND_DSP_GetBufferLengthTotal +, +FSOUND_DSP_MixBuffers +, +FSOUND_DSP_PRIORITIES +, +FSOUND_DSP_SetActive +, +FSOUND_DSP_SetPriority +, +FSOUND_DSPCALLBACK +, +FSOUND_GetCPUUsage +, +FSOUND_GetMixer +, +FSOUND_MIXERTYPES +, +FSOUND_PlaySoundEx +, +FSOUND_Stream_CreateDSP +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Free.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Free.html index 8dfb2f42..594cd961 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Free.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_Free.html @@ -1,59 +1,59 @@ - - - - -FSOUND_DSP_Free - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_Free

-Frees and removes a DSP unit from the DSP chain.
-

-void F_API FSOUND_DSP_Free(
-FSOUND_DSPUNIT *unit
-);
-

Parameters

- - -
unitPointer to DSP unit to be freed.
-
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_Free + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_Free

+Frees and removes a DSP unit from the DSP chain.
+

+void F_API FSOUND_DSP_Free(
+FSOUND_DSPUNIT *unit
+);
+

Parameters

+ + +
unitPointer to DSP unit to be freed.
+
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetActive.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetActive.html index 277f198d..3ac9f711 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetActive.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetActive.html @@ -1,60 +1,60 @@ - - - - -FSOUND_DSP_GetActive - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetActive

-Returns if a DSP unit is active or not.
-

-signed char F_API FSOUND_DSP_GetActive(
-FSOUND_DSPUNIT *unit
-);
-

Parameters

- - -
unitPointer to DSP unit to have its active flag returned.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_SetActive -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetActive + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetActive

+Returns if a DSP unit is active or not.
+

+signed char F_API FSOUND_DSP_GetActive(
+FSOUND_DSPUNIT *unit
+);
+

Parameters

+ + +
unitPointer to DSP unit to have its active flag returned.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_SetActive +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLength.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLength.html index d12a64e2..14ee7d8e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLength.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLength.html @@ -1,59 +1,59 @@ - - - - -FSOUND_DSP_GetBufferLength - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetBufferLength

-Returns the buffer lenth passed by the DSP system to DSP unit callbacks, so you can allocate memory etc
-using this data.
-

-int F_API FSOUND_DSP_GetBufferLength(
-);
-

Return Value

-The size of the DSP unit buffer in SAMPLES (not bytes).
-

Remarks

-Remember this is samples not bytes. To convert to bytes you
-will have to multiply by 4 for mmx mixers, 8 for other mixers.
-(a stereo 16bit sample = 4 bytes, and a stereo 32bit sample (ie fpu) = 8 bytes)
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_GetBufferLengthTotal -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetBufferLength + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetBufferLength

+Returns the buffer lenth passed by the DSP system to DSP unit callbacks, so you can allocate memory etc
+using this data.
+

+int F_API FSOUND_DSP_GetBufferLength(
+);
+

Return Value

+The size of the DSP unit buffer in SAMPLES (not bytes).
+

Remarks

+Remember this is samples not bytes. To convert to bytes you
+will have to multiply by 4 for mmx mixers, 8 for other mixers.
+(a stereo 16bit sample = 4 bytes, and a stereo 32bit sample (ie fpu) = 8 bytes)
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_GetBufferLengthTotal +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLengthTotal.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLengthTotal.html index 933f7037..4108ea18 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLengthTotal.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetBufferLengthTotal.html @@ -1,61 +1,61 @@ - - - - -FSOUND_DSP_GetBufferLengthTotal - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetBufferLengthTotal

-This is the total size in samples (not bytes) of the FSOUND mix buffer. This is affected
-by FSOUND_SetBufferSize.
-

-int F_API FSOUND_DSP_GetBufferLengthTotal(
-);
-

Return Value

-The size of the FSOUND mixing buffer in SAMPLES (not bytes).
-

Remarks

-Remember this is samples not bytes. To convert to bytes you
-will have to multiply by 4 for mmx mixers, 8 for other mixers.
-(a stereo 16bit sample = 4 bytes, and a stereo 32bit sample (ie fpu) = 8 bytes)
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_GetBufferLength -, -FSOUND_SetBufferSize -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetBufferLengthTotal + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetBufferLengthTotal

+This is the total size in samples (not bytes) of the FSOUND mix buffer. This is affected
+by FSOUND_SetBufferSize.
+

+int F_API FSOUND_DSP_GetBufferLengthTotal(
+);
+

Return Value

+The size of the FSOUND mixing buffer in SAMPLES (not bytes).
+

Remarks

+Remember this is samples not bytes. To convert to bytes you
+will have to multiply by 4 for mmx mixers, 8 for other mixers.
+(a stereo 16bit sample = 4 bytes, and a stereo 32bit sample (ie fpu) = 8 bytes)
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_GetBufferLength +, +FSOUND_SetBufferSize +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClearUnit.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClearUnit.html index dbf37a02..da0c2f9d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClearUnit.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClearUnit.html @@ -1,60 +1,60 @@ - - - - -FSOUND_DSP_GetClearUnit - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetClearUnit

-Returns a pointer to FSOUND's system DSP clear unit.
-

-FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClearUnit(
-);
-

Return Value

-Pointer to the DSP unit.
-

Remarks

-The FSOUND clear DSP unit simply sets the mix buffer to 0, silencing it.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_GetClipAndCopyUnit -, -FSOUND_DSP_GetFFTUnit -, -FSOUND_DSP_GetMusicUnit -, -FSOUND_DSP_GetSFXUnit -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetClearUnit + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetClearUnit

+Returns a pointer to FSOUND's system DSP clear unit.
+

+FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClearUnit(
+);
+

Return Value

+Pointer to the DSP unit.
+

Remarks

+The FSOUND clear DSP unit simply sets the mix buffer to 0, silencing it.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_GetClipAndCopyUnit +, +FSOUND_DSP_GetFFTUnit +, +FSOUND_DSP_GetMusicUnit +, +FSOUND_DSP_GetSFXUnit +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClipAndCopyUnit.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClipAndCopyUnit.html index ad7bc700..9a23f0e8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClipAndCopyUnit.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetClipAndCopyUnit.html @@ -1,60 +1,60 @@ - - - - -FSOUND_DSP_GetClipAndCopyUnit - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetClipAndCopyUnit

-Returns a pointer to FSOUND's system Clip and Copy DSP unit.
-

-FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClipAndCopyUnit(
-);
-

Return Value

-Pointer to the DSP unit.
-

Remarks

-The FSOUND ClipAndCopy DSP unit clips the 32bit buffer down to fit the soundcard's 16bit stereo output, and sends it off to the hardware.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_GetClearUnit -, -FSOUND_DSP_GetFFTUnit -, -FSOUND_DSP_GetMusicUnit -, -FSOUND_DSP_GetSFXUnit -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetClipAndCopyUnit + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetClipAndCopyUnit

+Returns a pointer to FSOUND's system Clip and Copy DSP unit.
+

+FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClipAndCopyUnit(
+);
+

Return Value

+Pointer to the DSP unit.
+

Remarks

+The FSOUND ClipAndCopy DSP unit clips the 32bit buffer down to fit the soundcard's 16bit stereo output, and sends it off to the hardware.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_GetClearUnit +, +FSOUND_DSP_GetFFTUnit +, +FSOUND_DSP_GetMusicUnit +, +FSOUND_DSP_GetSFXUnit +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetFFTUnit.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetFFTUnit.html index d845af20..2cf0ade7 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetFFTUnit.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetFFTUnit.html @@ -1,63 +1,63 @@ - - - - -FSOUND_DSP_GetFFTUnit - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetFFTUnit

-Returns a pointer to FSOUND's system DSP FFT processing unit.
-

-DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetFFTUnit(
-);
-

Return Value

-Pointer to the DSP unit.
-

Remarks

-The FSOUND FFT DSP executes the FFT engine to allow FSOUND_DSP_GetSpectrum to be used.
-The FFT unit is off by default, due to the cpu expense incurred in running. Turn it on to use FSOUND_DSP_GetSpectrum.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_GetClearUnit -, -FSOUND_DSP_GetClipAndCopyUnit -, -FSOUND_DSP_GetMusicUnit -, -FSOUND_DSP_GetSFXUnit -, -FSOUND_DSP_GetSpectrum -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetFFTUnit + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetFFTUnit

+Returns a pointer to FSOUND's system DSP FFT processing unit.
+

+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetFFTUnit(
+);
+

Return Value

+Pointer to the DSP unit.
+

Remarks

+The FSOUND FFT DSP executes the FFT engine to allow FSOUND_DSP_GetSpectrum to be used.
+The FFT unit is off by default, due to the cpu expense incurred in running. Turn it on to use FSOUND_DSP_GetSpectrum.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_GetClearUnit +, +FSOUND_DSP_GetClipAndCopyUnit +, +FSOUND_DSP_GetMusicUnit +, +FSOUND_DSP_GetSFXUnit +, +FSOUND_DSP_GetSpectrum +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetMusicUnit.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetMusicUnit.html index 21ddb7f1..a71977e6 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetMusicUnit.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetMusicUnit.html @@ -1,62 +1,62 @@ - - - - -FSOUND_DSP_GetMusicUnit - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetMusicUnit

-Returns a pointer to FSOUND's system DSP Music mixer unit.
-

-FSOUND_DSPUNIT *F_API FSOUND_DSP_GetMusicUnit(
-);
-

Return Value

-Pointer to the DSP unit.
-

Remarks

-The FSOUND Music DSP executes the FMUSIC engine and mixes the sounds spawned by the music player.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_ClearMixBuffer -, -FSOUND_DSP_GetClearUnit -, -FSOUND_DSP_GetClipAndCopyUnit -, -FSOUND_DSP_GetFFTUnit -, -FSOUND_DSP_GetSFXUnit -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:28 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetMusicUnit + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetMusicUnit

+Returns a pointer to FSOUND's system DSP Music mixer unit.
+

+FSOUND_DSPUNIT *F_API FSOUND_DSP_GetMusicUnit(
+);
+

Return Value

+Pointer to the DSP unit.
+

Remarks

+The FSOUND Music DSP executes the FMUSIC engine and mixes the sounds spawned by the music player.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_ClearMixBuffer +, +FSOUND_DSP_GetClearUnit +, +FSOUND_DSP_GetClipAndCopyUnit +, +FSOUND_DSP_GetFFTUnit +, +FSOUND_DSP_GetSFXUnit +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:28 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetPriority.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetPriority.html index 807b796b..41315dbc 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetPriority.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetPriority.html @@ -1,60 +1,60 @@ - - - - -FSOUND_DSP_GetPriority - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetPriority

-Returns the priority status in the DSP chain, of a specified unit.
-

-int F_API FSOUND_DSP_GetPriority(
-FSOUND_DSPUNIT *unit
-);
-

Parameters

- - -
unitPointer to DSP unit to get priority value from.
-
-

Return Value

-On success, the priority of the unit, from 0 to 1000.
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_SetPriority -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetPriority + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetPriority

+Returns the priority status in the DSP chain, of a specified unit.
+

+int F_API FSOUND_DSP_GetPriority(
+FSOUND_DSPUNIT *unit
+);
+

Parameters

+ + +
unitPointer to DSP unit to get priority value from.
+
+

Return Value

+On success, the priority of the unit, from 0 to 1000.
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_SetPriority +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSFXUnit.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSFXUnit.html index cb3e547f..c5aa4617 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSFXUnit.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSFXUnit.html @@ -1,62 +1,62 @@ - - - - -FSOUND_DSP_GetSFXUnit - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetSFXUnit

-Returns a pointer to FSOUND's system DSP SFX mixer unit.
-

-FSOUND_DSPUNIT *F_API FSOUND_DSP_GetSFXUnit(
-);
-

Return Value

-Pointer to the DSP unit.
-

Remarks

-The FSOUND SFX DSP unit mixes sound effects together spawned by the user.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_ClearMixBuffer -, -FSOUND_DSP_GetClearUnit -, -FSOUND_DSP_GetClipAndCopyUnit -, -FSOUND_DSP_GetFFTUnit -, -FSOUND_DSP_GetMusicUnit -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetSFXUnit + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetSFXUnit

+Returns a pointer to FSOUND's system DSP SFX mixer unit.
+

+FSOUND_DSPUNIT *F_API FSOUND_DSP_GetSFXUnit(
+);
+

Return Value

+Pointer to the DSP unit.
+

Remarks

+The FSOUND SFX DSP unit mixes sound effects together spawned by the user.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_ClearMixBuffer +, +FSOUND_DSP_GetClearUnit +, +FSOUND_DSP_GetClipAndCopyUnit +, +FSOUND_DSP_GetFFTUnit +, +FSOUND_DSP_GetMusicUnit +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSpectrum.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSpectrum.html index 2f405922..fb11bc50 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSpectrum.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_GetSpectrum.html @@ -1,61 +1,61 @@ - - - - -FSOUND_DSP_GetSpectrum - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_GetSpectrum

-Function to return a pointer to the current spectrum buffer. The buffer contains 512 floating
-point values that represent each frequency band's amplitude for the current FMOD SoundSystem
-mixing buffer. The range of frequencies covered by the spectrum is 1 to the nyquist frequency
-or half of the output rate. So if the output rate is 44100, then frequencies provided are up
-to 22050. (entry 511)
-

-F_FLOAT_API * F_API FSOUND_DSP_GetSpectrum(
-);
-

Return Value

-A pointer to a buffer containing 512 floats.
-

Remarks

-Note that hardware sounds, MIDI, files do not register on the spectrum graph as they are not run through FMODs DSP system.
-Note that to use this you have to turn on the FSOUND FFT DSP unit. This is achieved by calling FSOUND_DSP_GetFFTUnit, then using FSOUND_DSP_SetActive to turn it on.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_DSP_GetFFTUnit -, -FSOUND_DSP_SetActive -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_GetSpectrum + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_GetSpectrum

+Function to return a pointer to the current spectrum buffer. The buffer contains 512 floating
+point values that represent each frequency band's amplitude for the current FMOD SoundSystem
+mixing buffer. The range of frequencies covered by the spectrum is 1 to the nyquist frequency
+or half of the output rate. So if the output rate is 44100, then frequencies provided are up
+to 22050. (entry 511)
+

+F_FLOAT_API * F_API FSOUND_DSP_GetSpectrum(
+);
+

Return Value

+A pointer to a buffer containing 512 floats.
+

Remarks

+Note that hardware sounds, MIDI, files do not register on the spectrum graph as they are not run through FMODs DSP system.
+Note that to use this you have to turn on the FSOUND FFT DSP unit. This is achieved by calling FSOUND_DSP_GetFFTUnit, then using FSOUND_DSP_SetActive to turn it on.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_DSP_GetFFTUnit +, +FSOUND_DSP_SetActive +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_MixBuffers.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_MixBuffers.html index eefc5e69..9660e4ec 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_MixBuffers.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_MixBuffers.html @@ -1,109 +1,109 @@ - - - - -FSOUND_DSP_MixBuffers - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_MixBuffers

-Allows the user to mix their own data from one buffer to another, using FSOUNDs optimized
-mixer routines. This was mainly provided for DSP routines, though it can be used for
-anything.
-

-signed char F_API FSOUND_DSP_MixBuffers(
-void *destbuffer,
-void *srcbuffer,
-int len,
-int freq,
-int vol,
-int pan,
-unsigned int mode
-);
-

Parameters

- - - - - - - - -
destbufferPointer to a buffer to have the data mixed into.
-
srcbufferPointer to the source buffer to be mixed in.
-
lenAmount to mix in SAMPLES.
-
freqSpeed to mix data to output buffer. Remember if you mix at a rate
-different than the output rate, the buffer lengths will have to be
-different to compensate. Ie if the output rate is 44100 and you supply
-a value of 88200 to FSOUND_DSP_MixBuffers, you will only need a destbuffer
-that is half the size of srcbuffer. If you supply a value of 22050 then
-you will need a destbuffer that is twice as big as srcbuffer. If they
-are both the same size then it will only mix half of the data.
-
volvolume scalar value of mix. Valid values are 0 (silence) to 255
-(full volume). See FSOUND_SetVolume for more information.
-
panpan value for data being mixed. Valid values are 0 (full left), 128
-(middle), 255 (full right) and FSOUND_STEREOPAN. See FSOUND_SetPan for
-more information.
-
modeBit settings to describe the source buffer. Valid values are found in
-FSOUND_MODES, but only 8/16bit and stereo/mono flags are interpreted,
-other flags are ignored.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-'destbuffer' should always the format of the mixing output buffer, as it will use the mixer
-currently running to do the mixing.
-For MMX it is 16bit stereo, so it is 4 bytes per output sample (word left, word right)
-For Standard Blend mode it is 32bit stereo, so it is 8 bytes per output sample (left dword, right dword)
-For FPU mixer it is 32bit float stereo, so it is 8 bytes per output sample (left float, right float)
-FSOUND_GetMixer can be used to determine which mixer is being used.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_MixBuffers -, -FSOUND_GetMixer -, -FSOUND_MODES -, -FSOUND_SetFrequency -, -FSOUND_SetPan -, -FSOUND_SetVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_MixBuffers + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_MixBuffers

+Allows the user to mix their own data from one buffer to another, using FSOUNDs optimized
+mixer routines. This was mainly provided for DSP routines, though it can be used for
+anything.
+

+signed char F_API FSOUND_DSP_MixBuffers(
+void *destbuffer,
+void *srcbuffer,
+int len,
+int freq,
+int vol,
+int pan,
+unsigned int mode
+);
+

Parameters

+ + + + + + + + +
destbufferPointer to a buffer to have the data mixed into.
+
srcbufferPointer to the source buffer to be mixed in.
+
lenAmount to mix in SAMPLES.
+
freqSpeed to mix data to output buffer. Remember if you mix at a rate
+different than the output rate, the buffer lengths will have to be
+different to compensate. Ie if the output rate is 44100 and you supply
+a value of 88200 to FSOUND_DSP_MixBuffers, you will only need a destbuffer
+that is half the size of srcbuffer. If you supply a value of 22050 then
+you will need a destbuffer that is twice as big as srcbuffer. If they
+are both the same size then it will only mix half of the data.
+
volvolume scalar value of mix. Valid values are 0 (silence) to 255
+(full volume). See FSOUND_SetVolume for more information.
+
panpan value for data being mixed. Valid values are 0 (full left), 128
+(middle), 255 (full right) and FSOUND_STEREOPAN. See FSOUND_SetPan for
+more information.
+
modeBit settings to describe the source buffer. Valid values are found in
+FSOUND_MODES, but only 8/16bit and stereo/mono flags are interpreted,
+other flags are ignored.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+'destbuffer' should always the format of the mixing output buffer, as it will use the mixer
+currently running to do the mixing.
+For MMX it is 16bit stereo, so it is 4 bytes per output sample (word left, word right)
+For Standard Blend mode it is 32bit stereo, so it is 8 bytes per output sample (left dword, right dword)
+For FPU mixer it is 32bit float stereo, so it is 8 bytes per output sample (left float, right float)
+FSOUND_GetMixer can be used to determine which mixer is being used.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_MixBuffers +, +FSOUND_GetMixer +, +FSOUND_MODES +, +FSOUND_SetFrequency +, +FSOUND_SetPan +, +FSOUND_SetVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_PRIORITIES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_PRIORITIES.html index 5b13b4fb..6b064c6f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_PRIORITIES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_PRIORITIES.html @@ -1,73 +1,73 @@ - - - - -FSOUND_DSP_PRIORITIES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_DSP_PRIORITIES

-These default priorities are used by FMOD internal system DSP units. They describe the
-position of the DSP chain, and the order of how audio processing is executed.
-You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP
-unit), disable or even change the priority of a DSP unit.
-

- - - - - - - - - - - - - -
FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT0 /* DSP CLEAR unit - done first */ -
FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT100 /* DSP SFX unit - done second */ -
FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT200 /* DSP MUSIC unit - done third */ -
FSOUND_DSP_DEFAULTPRIORITY_USER300 /* User priority, use this as reference for your own DSP units */ -
FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT900 /* This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units */ -
FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT1000 /* DSP CLIP AND COPY unit - last */ -
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_GetSpectrum -, -FSOUND_DSP_SetPriority -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_PRIORITIES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_DSP_PRIORITIES

+These default priorities are used by FMOD internal system DSP units. They describe the
+position of the DSP chain, and the order of how audio processing is executed.
+You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP
+unit), disable or even change the priority of a DSP unit.
+

+ + + + + + + + + + + + + +
FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT0 /* DSP CLEAR unit - done first */ +
FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT100 /* DSP SFX unit - done second */ +
FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT200 /* DSP MUSIC unit - done third */ +
FSOUND_DSP_DEFAULTPRIORITY_USER300 /* User priority, use this as reference for your own DSP units */ +
FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT900 /* This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units */ +
FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT1000 /* DSP CLIP AND COPY unit - last */ +
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_GetSpectrum +, +FSOUND_DSP_SetPriority +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetActive.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetActive.html index 3a245754..60df64b3 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetActive.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetActive.html @@ -1,70 +1,70 @@ - - - - -FSOUND_DSP_SetActive - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_SetActive

-Allows the user to toggle a DSP unit on or off.
-

-void F_API FSOUND_DSP_SetActive(
-FSOUND_DSPUNIT *unit,
-signed char active
-);
-

Parameters

- - - -
unitPointer to DSP unit to have its active flag changed.
-
activeFlag to say whether DSP unit should be rendered active or inactive. valid
-values are TRUE or FALSE.
-
-

Return Value

-void
-

Remarks

-It is possible to toggle on and off FSOUNDs internal DSP units, though not recommended.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_ClearMixBuffer -, -FSOUND_DSP_Create -, -FSOUND_DSP_GetActive -, -FSOUND_DSP_GetSpectrum -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_SetActive + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_SetActive

+Allows the user to toggle a DSP unit on or off.
+

+void F_API FSOUND_DSP_SetActive(
+FSOUND_DSPUNIT *unit,
+signed char active
+);
+

Parameters

+ + + +
unitPointer to DSP unit to have its active flag changed.
+
activeFlag to say whether DSP unit should be rendered active or inactive. valid
+values are TRUE or FALSE.
+
+

Return Value

+void
+

Remarks

+It is possible to toggle on and off FSOUNDs internal DSP units, though not recommended.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_ClearMixBuffer +, +FSOUND_DSP_Create +, +FSOUND_DSP_GetActive +, +FSOUND_DSP_GetSpectrum +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetPriority.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetPriority.html index ea92e7a7..d061ac5c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetPriority.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_DSP_SetPriority.html @@ -1,66 +1,66 @@ - - - - -FSOUND_DSP_SetPriority - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_DSP_SetPriority

-Changes a DSP Unit's priority position in the DSP chain.
-

-void F_API FSOUND_DSP_SetPriority(
-FSOUND_DSPUNIT *unit,
-int priority
-);
-

Parameters

- - - -
unitPointer to DSP unit to have its priority changed.
-
priorityOrder in the priority chain. Valid numbers are 0 to 1000, 0 being
-highest priority (first), with 1000 being lowest priority (last).
-
-

Return Value

-

Remarks

-DSP units with the same priority as a previous unit already in the chain will be placed
-AFTER all like priority units.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_GetPriority -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_DSP_SetPriority + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_DSP_SetPriority

+Changes a DSP Unit's priority position in the DSP chain.
+

+void F_API FSOUND_DSP_SetPriority(
+FSOUND_DSPUNIT *unit,
+int priority
+);
+

Parameters

+ + + +
unitPointer to DSP unit to have its priority changed.
+
priorityOrder in the priority chain. Valid numbers are 0 to 1000, 0 being
+highest priority (first), with 1000 being lowest priority (last).
+
+

Return Value

+

Remarks

+DSP units with the same priority as a previous unit already in the chain will be placed
+AFTER all like priority units.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_GetPriority +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FREECALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FREECALLBACK.html index 45beffa7..1015665e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FREECALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FREECALLBACK.html @@ -1,65 +1,65 @@ - - - - -FSOUND_FREECALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FREECALLBACK

-Callback to free a block of memory.
-

-void F_CALLBACKAPI FSOUND_FREECALLBACK(
-void *ptr
-);
-

Parameters

- - -
ptrPointer to a pre-existing block of memory to be freed.
-
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_ALLOCCALLBACK -, -FSOUND_GetMemoryStats -, -FSOUND_REALLOCCALLBACK -, -FSOUND_SetMemorySystem -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FREECALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FREECALLBACK

+Callback to free a block of memory.
+

+void F_CALLBACKAPI FSOUND_FREECALLBACK(
+void *ptr
+);
+

Parameters

+ + +
ptrPointer to a pre-existing block of memory to be freed.
+
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_ALLOCCALLBACK +, +FSOUND_GetMemoryStats +, +FSOUND_REALLOCCALLBACK +, +FSOUND_SetMemorySystem +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Disable.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Disable.html index 9828fe84..dfba7811 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Disable.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Disable.html @@ -1,80 +1,80 @@ - - - - -FSOUND_FX_Disable - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_Disable

-Disables effect processing for ALL effects on the specified channel.
-

-signed char F_API FSOUND_FX_Disable(
-int channel
-);
-

Parameters

- - -
channelChannel number/handle to disable all fx for.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will disable fx on ALL channels available.
-This command can only be issued while the channel is paused or stopped.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Enable -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_Disable + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_Disable

+Disables effect processing for ALL effects on the specified channel.
+

+signed char F_API FSOUND_FX_Disable(
+int channel
+);
+

Parameters

+ + +
channelChannel number/handle to disable all fx for.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will disable fx on ALL channels available.
+This command can only be issued while the channel is paused or stopped.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Enable +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Enable.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Enable.html index e2c12011..3bd3ddbe 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Enable.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_Enable.html @@ -1,97 +1,97 @@ - - - - -FSOUND_FX_Enable - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_Enable

-Enables effect processing for the specified channel. This command continues to add effects to a channel (up to 16) until FSOUND_FX_Disable is called.
-

-int F_API FSOUND_FX_Enable(
-int channel,
-unsigned int fxtype
-);
-

Parameters

- - - -
channelChannel number/handle to enable fx for.
-
fxA single fx enum value to enable certain effects.
-
-

Return Value

-On success, an FX id is returned.
-On failure, -1 is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will enable fx on ALL channels available.
-This command can only be issued while the channel is paused.
-If an effect is not enabled, then it will not be affected by its corresponding FSOUND_FX_Set functions.
-This function must be played after a paused PlaySoundEx (ie FSOUND_PlaySoundEx(FSOUND_FREE, sound, NULL, TRUE)), and before
-the FSOUND_SetPaused(FALSE) so that the hardware can get the resource before it starts playing.
-A total of 16 FX per channel is allowed, any more will result in an error. FX are reset to 0 after a sound is stopped or played. (but as above, before the unpausing of a play-paused sound).
-Warning : This function is expensive to call as it has to set up fx buffers etc. It is best to call it once, reserve the channel then reuse the channel index when calling playsound without calling it again.
-Note : Under DirectX 8, channels with FX enabled sounds cannot have their frequency changed. DirectX 9 and above do not have this limitation.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -, -FSOUND_PlaySound -, -FSOUND_PlaySoundEx -, -FSOUND_SetPaused -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_Enable + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_Enable

+Enables effect processing for the specified channel. This command continues to add effects to a channel (up to 16) until FSOUND_FX_Disable is called.
+

+int F_API FSOUND_FX_Enable(
+int channel,
+unsigned int fxtype
+);
+

Parameters

+ + + +
channelChannel number/handle to enable fx for.
+
fxA single fx enum value to enable certain effects.
+
+

Return Value

+On success, an FX id is returned.
+On failure, -1 is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will enable fx on ALL channels available.
+This command can only be issued while the channel is paused.
+If an effect is not enabled, then it will not be affected by its corresponding FSOUND_FX_Set functions.
+This function must be played after a paused PlaySoundEx (ie FSOUND_PlaySoundEx(FSOUND_FREE, sound, NULL, TRUE)), and before
+the FSOUND_SetPaused(FALSE) so that the hardware can get the resource before it starts playing.
+A total of 16 FX per channel is allowed, any more will result in an error. FX are reset to 0 after a sound is stopped or played. (but as above, before the unpausing of a play-paused sound).
+Warning : This function is expensive to call as it has to set up fx buffers etc. It is best to call it once, reserve the channel then reuse the channel index when calling playsound without calling it again.
+Note : Under DirectX 8, channels with FX enabled sounds cannot have their frequency changed. DirectX 9 and above do not have this limitation.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +, +FSOUND_PlaySound +, +FSOUND_PlaySoundEx +, +FSOUND_SetPaused +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_MODES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_MODES.html index 9280fcc6..5363d006 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_MODES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_MODES.html @@ -1,79 +1,79 @@ - - - - -FSOUND_FX_MODES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_FX_MODES

-These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel.
-

-

Enumerators

- - - - - - - - - - - -
FSOUND_FX_CHORUS
FSOUND_FX_COMPRESSOR
FSOUND_FX_DISTORTION
FSOUND_FX_ECHO
FSOUND_FX_FLANGER
FSOUND_FX_GARGLE
FSOUND_FX_I3DL2REVERB
FSOUND_FX_PARAMEQ
FSOUND_FX_WAVES_REVERB
FSOUND_FX_MAX
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_MODES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_FX_MODES

+These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel.
+

+

Enumerators

+ + + + + + + + + + + +
FSOUND_FX_CHORUS
FSOUND_FX_COMPRESSOR
FSOUND_FX_DISTORTION
FSOUND_FX_ECHO
FSOUND_FX_FLANGER
FSOUND_FX_GARGLE
FSOUND_FX_I3DL2REVERB
FSOUND_FX_PARAMEQ
FSOUND_FX_WAVES_REVERB
FSOUND_FX_MAX
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetChorus.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetChorus.html index 85d7a243..f8baee87 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetChorus.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetChorus.html @@ -1,110 +1,110 @@ - - - - -FSOUND_FX_SetChorus - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetChorus

-Sets the parameters for the chorus effect on a particular channel
-

-signed char F_API FSOUND_FX_SetChorus(
-int fxid,
-float WetDryMix,
-float Depth,
-float Feedback,
-float Frequency,
-int Waveform,
-float Delay,
-int Phase
-);
-

Parameters

- - - - - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set chorus parameters for.
-
WetDryMixRatio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0 through 100 (all wet).
-
DepthPercentage by which the delay time is modulated by the low-frequency oscillator, in hundredths of a percentage point. Must be in the range from 0 through 100. The default value is 25.
-
FeedbackPercentage of output signal to feed back into the effects input, in the range from -99 to 99. The default value is 0.
-
FrequencyFrequency of the LFO, in the range from 0 to 10. The default value is 0.
-
WaveformWaveform of the LFO. Defined values are
-0 triangle.
-1 sine.
-By default, the waveform is a sine.
-
DelayNumber of milliseconds the input is delayed before it is played back, in the range from 0 to 20. The default value is 0 ms.
-
PhasePhase differential between left and right LFOs, in the range from 0 through 4. Possible values are defined as follows:
-0 -180 degrees
-1 - 90 degrees
-2 0 degrees
-3 90 degrees
-4 180 degrees
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_CHORUS before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetChorus + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetChorus

+Sets the parameters for the chorus effect on a particular channel
+

+signed char F_API FSOUND_FX_SetChorus(
+int fxid,
+float WetDryMix,
+float Depth,
+float Feedback,
+float Frequency,
+int Waveform,
+float Delay,
+int Phase
+);
+

Parameters

+ + + + + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set chorus parameters for.
+
WetDryMixRatio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0 through 100 (all wet).
+
DepthPercentage by which the delay time is modulated by the low-frequency oscillator, in hundredths of a percentage point. Must be in the range from 0 through 100. The default value is 25.
+
FeedbackPercentage of output signal to feed back into the effects input, in the range from -99 to 99. The default value is 0.
+
FrequencyFrequency of the LFO, in the range from 0 to 10. The default value is 0.
+
WaveformWaveform of the LFO. Defined values are
+0 triangle.
+1 sine.
+By default, the waveform is a sine.
+
DelayNumber of milliseconds the input is delayed before it is played back, in the range from 0 to 20. The default value is 0 ms.
+
PhasePhase differential between left and right LFOs, in the range from 0 through 4. Possible values are defined as follows:
+0 -180 degrees
+1 - 90 degrees
+2 0 degrees
+3 90 degrees
+4 180 degrees
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_CHORUS before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetCompressor.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetCompressor.html index a65482e3..44786094 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetCompressor.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetCompressor.html @@ -1,99 +1,99 @@ - - - - -FSOUND_FX_SetCompressor - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetCompressor

-Sets the parameters for the compressor effect on a particular channel
-

-signed char F_API FSOUND_FX_SetCompressor(
-int fxid,
-float Gain,
-float Attack,
-float Release,
-float Threshold,
-float Ratio,
-float Predelay
-);
-

Parameters

- - - - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set compressor parameters for.
-
GainOutput gain of signal after compression, in the range from -60 to 60. The default value is 0 dB.
-
AttackTime before compression reaches its full value, in the range from 0.01 to 500. The default value is 0.01 ms.
-
ReleaseSpeed at which compression is stopped after input drops below fThreshold, in the range from 50 to 3000. The default value is 50 ms.
-
ThresholdPoint at which compression begins, in decibels, in the range from -60 to 0. The default value is -10 dB.
-
RatioCompression ratio, in the range from 1 to 100. The default value is 10, which means 10:1 compression.
-
PredelayTime after lThreshold is reached before attack phase is started, in milliseconds, in the range from 0 to 4. The default value is 0 ms.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_COMPRESSOR before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetCompressor + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetCompressor

+Sets the parameters for the compressor effect on a particular channel
+

+signed char F_API FSOUND_FX_SetCompressor(
+int fxid,
+float Gain,
+float Attack,
+float Release,
+float Threshold,
+float Ratio,
+float Predelay
+);
+

Parameters

+ + + + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set compressor parameters for.
+
GainOutput gain of signal after compression, in the range from -60 to 60. The default value is 0 dB.
+
AttackTime before compression reaches its full value, in the range from 0.01 to 500. The default value is 0.01 ms.
+
ReleaseSpeed at which compression is stopped after input drops below fThreshold, in the range from 50 to 3000. The default value is 50 ms.
+
ThresholdPoint at which compression begins, in decibels, in the range from -60 to 0. The default value is -10 dB.
+
RatioCompression ratio, in the range from 1 to 100. The default value is 10, which means 10:1 compression.
+
PredelayTime after lThreshold is reached before attack phase is started, in milliseconds, in the range from 0 to 4. The default value is 0 ms.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_COMPRESSOR before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetDistortion.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetDistortion.html index 7ec8fcf1..77f6ea29 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetDistortion.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetDistortion.html @@ -1,96 +1,96 @@ - - - - -FSOUND_FX_SetDistortion - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetDistortion

-Sets the parameters for the distortion effect on a particular channel
-

-signed char F_API FSOUND_FX_SetDistortion(
-int fxid,
-float Gain,
-float Edge,
-float PostEQCenterFrequency,
-float PostEQBandwidth,
-float PreLowpassCutoff
-);
-

Parameters

- - - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set distortion parameters for.
-
GainAmount of signal change after distortion, in the range from -60 through 0. The default value is 0 dB.
-
EdgePercentage of distortion intensity, in the range in the range from 0 through 100. The default value is 50 percent.
-
PostEQCenterFrequencyCenter frequency of harmonic content addition, in the range from 100 through 8000. The default value is 4000 Hz.
-
PostEQBandwidthWidth of frequency band that determines range of harmonic content addition, in the range from 100 through 8000. The default value is 4000 Hz.
-
PreLowpassCutoffFilter cutoff for high-frequency harmonics attenuation, in the range from 100 through 8000. The default value is 4000 Hz.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_DISTORTION before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetDistortion + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetDistortion

+Sets the parameters for the distortion effect on a particular channel
+

+signed char F_API FSOUND_FX_SetDistortion(
+int fxid,
+float Gain,
+float Edge,
+float PostEQCenterFrequency,
+float PostEQBandwidth,
+float PreLowpassCutoff
+);
+

Parameters

+ + + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set distortion parameters for.
+
GainAmount of signal change after distortion, in the range from -60 through 0. The default value is 0 dB.
+
EdgePercentage of distortion intensity, in the range in the range from 0 through 100. The default value is 50 percent.
+
PostEQCenterFrequencyCenter frequency of harmonic content addition, in the range from 100 through 8000. The default value is 4000 Hz.
+
PostEQBandwidthWidth of frequency band that determines range of harmonic content addition, in the range from 100 through 8000. The default value is 4000 Hz.
+
PreLowpassCutoffFilter cutoff for high-frequency harmonics attenuation, in the range from 100 through 8000. The default value is 4000 Hz.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_DISTORTION before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetEcho.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetEcho.html index fd9693a6..57f33b9c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetEcho.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetEcho.html @@ -1,96 +1,96 @@ - - - - -FSOUND_FX_SetEcho - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetEcho

-Sets the parameters for the echo effect on a particular channel
-

-signed char F_API FSOUND_FX_SetEcho(
-int fxid,
-float WetDryMix,
-float Feedback,
-float LeftDelay,
-float RightDelay,
-int PanDelay
-);
-

Parameters

- - - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set echo parameters for.
-
WetDryMixRatio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0 through 100 (all wet).
-
FeedbackPercentage of output fed back into input, in the range from 0 through 100. The default value is 0.
-
LeftDelayDelay for left channel, in milliseconds, in the range from 1 through 2000. The default value is 333 ms.
-
RightDelayDelay for right channel, in milliseconds, in the range from 1 through 2000. The default value is 333 ms.
-
PanDelayValue that specifies whether to swap left and right delays with each successive echo. The default value is FALSE, meaning no swap. Possible values are defined as TRUE or FALSE.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_ECHO before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetEcho + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetEcho

+Sets the parameters for the echo effect on a particular channel
+

+signed char F_API FSOUND_FX_SetEcho(
+int fxid,
+float WetDryMix,
+float Feedback,
+float LeftDelay,
+float RightDelay,
+int PanDelay
+);
+

Parameters

+ + + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set echo parameters for.
+
WetDryMixRatio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0 through 100 (all wet).
+
FeedbackPercentage of output fed back into input, in the range from 0 through 100. The default value is 0.
+
LeftDelayDelay for left channel, in milliseconds, in the range from 1 through 2000. The default value is 333 ms.
+
RightDelayDelay for right channel, in milliseconds, in the range from 1 through 2000. The default value is 333 ms.
+
PanDelayValue that specifies whether to swap left and right delays with each successive echo. The default value is FALSE, meaning no swap. Possible values are defined as TRUE or FALSE.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_ECHO before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetFlanger.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetFlanger.html index 759f8fde..4c236696 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetFlanger.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetFlanger.html @@ -1,109 +1,109 @@ - - - - -FSOUND_FX_SetFlanger - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetFlanger

-Sets the parameters for the flanger effect on a particular channel
-

-signed char F_API FSOUND_FX_SetFlanger(
-int fxid,
-float WetDryMix,
-float Depth,
-float Feedback,
-float Frequency,
-int Waveform,
-float Delay,
-int Phase
-);
-

Parameters

- - - - - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set flanger parameters for.
-
WetDryMixRatio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0 through 100 (all wet).
-
DepthPercentage by which the delay time is modulated by the low-frequency oscillator (LFO), in hundredths of a percentage point. Must be in the range from 0 through 100. The default value is 25.
-
FeedbackPercentage of output signal to feed back into the effects input, in the range from -99 to 99. The default value is 0.
-
FrequencyFrequency of the LFO, in the range from 0 to 10. The default value is 0.
-
WaveformWaveform of the LFO. By default, the waveform is a sine. Possible values are defined as follows:
-0 - Triangle.
-1 - Sine.
-
DelayNumber of milliseconds the input is delayed before it is played back, in the range from 0 to 4. The default value is 0 ms.
-
PhasePhase differential between left and right LFOs, in the range from 0 through 4. Possible values are defined as follows:
-0 -180 degrees
-1 - 90 degrees
-2 0 degrees
-3 90 degrees
-4 180 degrees
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_FLANGER before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetFlanger + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetFlanger

+Sets the parameters for the flanger effect on a particular channel
+

+signed char F_API FSOUND_FX_SetFlanger(
+int fxid,
+float WetDryMix,
+float Depth,
+float Feedback,
+float Frequency,
+int Waveform,
+float Delay,
+int Phase
+);
+

Parameters

+ + + + + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set flanger parameters for.
+
WetDryMixRatio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0 through 100 (all wet).
+
DepthPercentage by which the delay time is modulated by the low-frequency oscillator (LFO), in hundredths of a percentage point. Must be in the range from 0 through 100. The default value is 25.
+
FeedbackPercentage of output signal to feed back into the effects input, in the range from -99 to 99. The default value is 0.
+
FrequencyFrequency of the LFO, in the range from 0 to 10. The default value is 0.
+
WaveformWaveform of the LFO. By default, the waveform is a sine. Possible values are defined as follows:
+0 - Triangle.
+1 - Sine.
+
DelayNumber of milliseconds the input is delayed before it is played back, in the range from 0 to 4. The default value is 0 ms.
+
PhasePhase differential between left and right LFOs, in the range from 0 through 4. Possible values are defined as follows:
+0 -180 degrees
+1 - 90 degrees
+2 0 degrees
+3 90 degrees
+4 180 degrees
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_FLANGER before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetGargle.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetGargle.html index 06ee79b5..4230c971 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetGargle.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetGargle.html @@ -1,89 +1,89 @@ - - - - -FSOUND_FX_SetGargle - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetGargle

-Sets the parameters for the gargle effect on a particular channel
-

-signed char F_API FSOUND_FX_SetGargle(
-int fxid,
-int RateHz,
-int WaveShape
-);
-

Parameters

- - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set gargle parameters for.
-
RateHzRate of modulation, in Hertz. Must be in the range from 1 through 1000.
-
WaveShapeShape of the modulation wave. The following values are defined.
-0 - Triangular wave.
-1 - Square wave.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_GARGLE before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetGargle + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetGargle

+Sets the parameters for the gargle effect on a particular channel
+

+signed char F_API FSOUND_FX_SetGargle(
+int fxid,
+int RateHz,
+int WaveShape
+);
+

Parameters

+ + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set gargle parameters for.
+
RateHzRate of modulation, in Hertz. Must be in the range from 1 through 1000.
+
WaveShapeShape of the modulation wave. The following values are defined.
+0 - Triangular wave.
+1 - Square wave.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_GARGLE before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetI3DL2Reverb.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetI3DL2Reverb.html index 03550d9f..165c30a8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetI3DL2Reverb.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetI3DL2Reverb.html @@ -1,117 +1,117 @@ - - - - -FSOUND_FX_SetI3DL2Reverb - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetI3DL2Reverb

-Sets the parameters for the I3DL2 Reverb effect on a particular channel
-

-signed char F_API FSOUND_FX_SetI3DL2Reverb(
-int fxid,
-int Room,
-int RoomHF,
-float RoomRolloffFactor,
-float DecayTime,
-float DecayHFRatio,
-int Reflections,
-float ReflectionsDelay,
-int Reverb,
-float ReverbDelay,
-float Diffusion,
-float Density,
-float HFReference
-);
-

Parameters

- - - - - - - - - - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set I3DL2 Reverb parameters for.
-
RoomAttenuation of the room effect, in millibels (mB), in the range from -10000 to 0. The default value is -1000 mB.
-
RoomHFAttenuation of the room high-frequency effect, in mB, in the range from -10000 to 0. The default value is 0 mB.
-
RoomRolloffFactorRolloff factor for the reflected signals, in the range from 0 to 10. The default value is 0.0. The rolloff factor for the direct path is controlled by the listener.
-
DecayTimeDecay time, in seconds, in the range from .1 to 20. The default value is 1.49 seconds.
-
DecayHFRatioRatio of the decay time at high frequencies to the decay time at low frequencies, in the range from 0.1 to 2. The default value is 0.83.
-
ReflectionsAttenuation of early reflections relative to lRoom, in mB, in the range from -10000 to 1000. The default value is -2602 mB.
-
ReflectionsDelayDelay time of the first reflection relative to the direct path, in seconds, in the range from 0 to 0.3. The default value is 0.007 seconds.
-
ReverbAttenuation of late reverberation relative to lRoom, in mB, in the range from -10000 to 2000. The default value is 200 mB.
-
ReverbDelayTime limit between the early reflections and the late reverberation relative to the time of the first reflection, in seconds, in the range from 0 to 0.1. The default value is 0.011 seconds.
-
DiffusionEcho density in the late reverberation decay, in percent, in the range from 0 to 100. The default value is 100.0 percent.
-
DensityModal density in the late reverberation decay, in percent, in the range from 0 to 100. The default value is 100.0 percent.
-
HFReferenceReference high frequency, in hertz, in the range from 20 to 20000. The default value is 5000.0 Hz.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_I3DL2REVERB before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetParamEQ -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetI3DL2Reverb + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetI3DL2Reverb

+Sets the parameters for the I3DL2 Reverb effect on a particular channel
+

+signed char F_API FSOUND_FX_SetI3DL2Reverb(
+int fxid,
+int Room,
+int RoomHF,
+float RoomRolloffFactor,
+float DecayTime,
+float DecayHFRatio,
+int Reflections,
+float ReflectionsDelay,
+int Reverb,
+float ReverbDelay,
+float Diffusion,
+float Density,
+float HFReference
+);
+

Parameters

+ + + + + + + + + + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set I3DL2 Reverb parameters for.
+
RoomAttenuation of the room effect, in millibels (mB), in the range from -10000 to 0. The default value is -1000 mB.
+
RoomHFAttenuation of the room high-frequency effect, in mB, in the range from -10000 to 0. The default value is 0 mB.
+
RoomRolloffFactorRolloff factor for the reflected signals, in the range from 0 to 10. The default value is 0.0. The rolloff factor for the direct path is controlled by the listener.
+
DecayTimeDecay time, in seconds, in the range from .1 to 20. The default value is 1.49 seconds.
+
DecayHFRatioRatio of the decay time at high frequencies to the decay time at low frequencies, in the range from 0.1 to 2. The default value is 0.83.
+
ReflectionsAttenuation of early reflections relative to lRoom, in mB, in the range from -10000 to 1000. The default value is -2602 mB.
+
ReflectionsDelayDelay time of the first reflection relative to the direct path, in seconds, in the range from 0 to 0.3. The default value is 0.007 seconds.
+
ReverbAttenuation of late reverberation relative to lRoom, in mB, in the range from -10000 to 2000. The default value is 200 mB.
+
ReverbDelayTime limit between the early reflections and the late reverberation relative to the time of the first reflection, in seconds, in the range from 0 to 0.1. The default value is 0.011 seconds.
+
DiffusionEcho density in the late reverberation decay, in percent, in the range from 0 to 100. The default value is 100.0 percent.
+
DensityModal density in the late reverberation decay, in percent, in the range from 0 to 100. The default value is 100.0 percent.
+
HFReferenceReference high frequency, in hertz, in the range from 20 to 20000. The default value is 5000.0 Hz.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_I3DL2REVERB before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetParamEQ +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetParamEQ.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetParamEQ.html index 04022be7..6227ccbb 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetParamEQ.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetParamEQ.html @@ -1,90 +1,90 @@ - - - - -FSOUND_FX_SetParamEQ - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetParamEQ

-Sets the parameters for the Param EQ effect on a particular channel
-

-signed char F_API FSOUND_FX_SetParamEQ(
-int fxid,
-float Center,
-float Bandwidth,
-float Gain
-);
-

Parameters

- - - - - -
fxidfx handle generated by FSOUND_FX_Enable, to set ParamEQ parameters for.
-
CenterCenter frequency, in hertz, in the range from 80 to 16000. This value cannot exceed one-third of the frequency of the buffer. Default is 8000.
-
BandwidthBandwidth, in semitones, in the range from 1 to 36. Default is 12.
-
GainGain, in the range from -15 to 15. Default is 0.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_PARAMEQ before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetWavesReverb -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetParamEQ + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetParamEQ

+Sets the parameters for the Param EQ effect on a particular channel
+

+signed char F_API FSOUND_FX_SetParamEQ(
+int fxid,
+float Center,
+float Bandwidth,
+float Gain
+);
+

Parameters

+ + + + + +
fxidfx handle generated by FSOUND_FX_Enable, to set ParamEQ parameters for.
+
CenterCenter frequency, in hertz, in the range from 80 to 16000. This value cannot exceed one-third of the frequency of the buffer. Default is 8000.
+
BandwidthBandwidth, in semitones, in the range from 1 to 36. Default is 12.
+
GainGain, in the range from -15 to 15. Default is 0.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_Enable and FSOUND_FX_PARAMEQ before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetWavesReverb +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetWavesReverb.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetWavesReverb.html index 86de0f3f..5aa173c2 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetWavesReverb.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_FX_SetWavesReverb.html @@ -1,93 +1,93 @@ - - - - -FSOUND_FX_SetWavesReverb - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_FX_SetWavesReverb

-Sets the parameters for the Waves Reverb effect on a particular channel
-

-signed char F_API FSOUND_FX_SetWavesReverb(
-int fxid,
-float InGain,
-float ReverbMix,
-float ReverbTime,
-float HighFreqRTRatio
-);
-

Parameters

- - - - - - -
fxidfx handle generated by FSOUND_FX_Enable, number/handle to set Waves Reverb parameters for.
-
InGainInput gain of signal, in decibels (dB), in the range from -96 through 0. The default value is 0 dB.
-
ReverbMixReverb mix, in dB, in the range from -96 through 0. The default value is 0 dB.
-
ReverbTimeReverb time, in milliseconds, in the range from .001 through 3000. The default value is 1000.
-
HighFreqRTRatioIn the range from .001 through .999. The default value is 0.001.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Make sure you have enabled this effect with FSOUND_FX_WAVES_REVERB before using this function.
-___________________
-Supported on the following platforms : Win32
-

See Also

-FSOUND_FX_Disable -, -FSOUND_FX_Enable -, -FSOUND_FX_MODES -, -FSOUND_FX_SetChorus -, -FSOUND_FX_SetCompressor -, -FSOUND_FX_SetDistortion -, -FSOUND_FX_SetEcho -, -FSOUND_FX_SetFlanger -, -FSOUND_FX_SetGargle -, -FSOUND_FX_SetI3DL2Reverb -, -FSOUND_FX_SetParamEQ -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_FX_SetWavesReverb + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_FX_SetWavesReverb

+Sets the parameters for the Waves Reverb effect on a particular channel
+

+signed char F_API FSOUND_FX_SetWavesReverb(
+int fxid,
+float InGain,
+float ReverbMix,
+float ReverbTime,
+float HighFreqRTRatio
+);
+

Parameters

+ + + + + + +
fxidfx handle generated by FSOUND_FX_Enable, number/handle to set Waves Reverb parameters for.
+
InGainInput gain of signal, in decibels (dB), in the range from -96 through 0. The default value is 0 dB.
+
ReverbMixReverb mix, in dB, in the range from -96 through 0. The default value is 0 dB.
+
ReverbTimeReverb time, in milliseconds, in the range from .001 through 3000. The default value is 1000.
+
HighFreqRTRatioIn the range from .001 through .999. The default value is 0.001.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Make sure you have enabled this effect with FSOUND_FX_WAVES_REVERB before using this function.
+___________________
+Supported on the following platforms : Win32
+

See Also

+FSOUND_FX_Disable +, +FSOUND_FX_Enable +, +FSOUND_FX_MODES +, +FSOUND_FX_SetChorus +, +FSOUND_FX_SetCompressor +, +FSOUND_FX_SetDistortion +, +FSOUND_FX_SetEcho +, +FSOUND_FX_SetFlanger +, +FSOUND_FX_SetGargle +, +FSOUND_FX_SetI3DL2Reverb +, +FSOUND_FX_SetParamEQ +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_File_SetCallbacks.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_File_SetCallbacks.html index 1f18fb2b..ffb538b9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_File_SetCallbacks.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_File_SetCallbacks.html @@ -1,94 +1,94 @@ - - - - -FSOUND_File_SetCallbacks - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_File_SetCallbacks

-Specify user callbacks for FMOD's internal file manipulation functions.
-If ANY of these parameters are NULL, then FMOD will switch back to its own file routines.
-You can replace this with memory routines (ie name can be cast to a memory address for example, then open sets up
-a handle based on this information), or alternate file routines, ie a WAD file reader.
-

-DLL_API void F_API FSOUND_File_SetCallbacks(
-FSOUND_OPENCALLBACK useropen,
-FSOUND_CLOSECALLBACK userclose,
-FSOUND_READCALLBACK userread,
-FSOUND_SEEKCALLBACK userseek,
-FSOUND_TELLCALLBACK usertell
-);
-

Parameters

- - - - - - -
OpenCallbackCallback for opening a file.
-
CloseCallbackCallback for closing a file.
-
ReadCallbackCallback for reading from a file.
-
SeekCallbackCallback for seeking within a file..
-
TellCallbackCallback for returning the offset from the base of the open file in bytes.
-
-

Return Value

-void
-

Remarks

-Memory loader FMOD functions are not affected, such as FMUSIC_LoadSongMemory etc.
-WARNING : This function is dangerous in the wrong hands. You must return the right values, and each command must work properly, or FMOD will not function, or it may even crash if you give it invalid data.
-You must support SEEK_SET, SEEK_CUR and SEEK_END properly, or FMOD will not work properly. See standard I/O help files on how these work under fseek().
-Read the documentation in REMARKS and do exactly what it says. See the "simple" example for how it is used properly.
-The MIDI loader does not support user file callbacks. For WAD type data structures with embedded MIDI files FMUSIC_LoadSongMemory will have to be used.
---------------
-PlayStation 2 NOTE! This function takes IOP function pointers, not EE pointers! It is for custom IOP file systems not EE based ones.
-This function can only be called after FSOUND_Init on PlayStation 2, not before.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, PlayStation 2, XBox, GameCube
-

See Also

-FMUSIC_LoadSong -, -FSOUND_CLOSECALLBACK -, -FSOUND_Init -, -FSOUND_OPENCALLBACK -, -FSOUND_READCALLBACK -, -FSOUND_SEEKCALLBACK -, -FSOUND_TELLCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_File_SetCallbacks + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_File_SetCallbacks

+Specify user callbacks for FMOD's internal file manipulation functions.
+If ANY of these parameters are NULL, then FMOD will switch back to its own file routines.
+You can replace this with memory routines (ie name can be cast to a memory address for example, then open sets up
+a handle based on this information), or alternate file routines, ie a WAD file reader.
+

+DLL_API void F_API FSOUND_File_SetCallbacks(
+FSOUND_OPENCALLBACK useropen,
+FSOUND_CLOSECALLBACK userclose,
+FSOUND_READCALLBACK userread,
+FSOUND_SEEKCALLBACK userseek,
+FSOUND_TELLCALLBACK usertell
+);
+

Parameters

+ + + + + + +
OpenCallbackCallback for opening a file.
+
CloseCallbackCallback for closing a file.
+
ReadCallbackCallback for reading from a file.
+
SeekCallbackCallback for seeking within a file..
+
TellCallbackCallback for returning the offset from the base of the open file in bytes.
+
+

Return Value

+void
+

Remarks

+Memory loader FMOD functions are not affected, such as FMUSIC_LoadSongMemory etc.
+WARNING : This function is dangerous in the wrong hands. You must return the right values, and each command must work properly, or FMOD will not function, or it may even crash if you give it invalid data.
+You must support SEEK_SET, SEEK_CUR and SEEK_END properly, or FMOD will not work properly. See standard I/O help files on how these work under fseek().
+Read the documentation in REMARKS and do exactly what it says. See the "simple" example for how it is used properly.
+The MIDI loader does not support user file callbacks. For WAD type data structures with embedded MIDI files FMUSIC_LoadSongMemory will have to be used.
+--------------
+PlayStation 2 NOTE! This function takes IOP function pointers, not EE pointers! It is for custom IOP file systems not EE based ones.
+This function can only be called after FSOUND_Init on PlayStation 2, not before.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, PlayStation 2, XBox, GameCube
+

See Also

+FMUSIC_LoadSong +, +FSOUND_CLOSECALLBACK +, +FSOUND_Init +, +FSOUND_OPENCALLBACK +, +FSOUND_READCALLBACK +, +FSOUND_SEEKCALLBACK +, +FSOUND_TELLCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetAmplitude.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetAmplitude.html index 125c22fa..b6c052cf 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetAmplitude.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetAmplitude.html @@ -1,67 +1,67 @@ - - - - -FSOUND_GetAmplitude - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetAmplitude

-Returns the volume of the channel based on all combinations of set volume, mastervolume and 3d position.
-Works on software and hardware voices.
-

-int F_API FSOUND_GetAmplitude(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the amplitude from.
-
-

Return Value

-On success, the following values are returned : 0 = silent to 255 = full volume.
-On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
-

Remarks

-This is not the same as FSOUND_GetCurrentLevels, as that function takes the actual waveform data into account.
-This function simply gives a final volume based on 3d position and volume settings.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetCurrentLevels -, -FSOUND_GetError -, -FSOUND_SetVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetAmplitude + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetAmplitude

+Returns the volume of the channel based on all combinations of set volume, mastervolume and 3d position.
+Works on software and hardware voices.
+

+int F_API FSOUND_GetAmplitude(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the amplitude from.
+
+

Return Value

+On success, the following values are returned : 0 = silent to 255 = full volume.
+On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
+

Remarks

+This is not the same as FSOUND_GetCurrentLevels, as that function takes the actual waveform data into account.
+This function simply gives a final volume based on 3d position and volume settings.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetCurrentLevels +, +FSOUND_GetError +, +FSOUND_SetVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCPUUsage.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCPUUsage.html index 1e9c4b16..7ffd562e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCPUUsage.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCPUUsage.html @@ -1,55 +1,55 @@ - - - - -FSOUND_GetCPUUsage - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetCPUUsage

-Returns in percent of cpu time the amount of cpu usage that FSOUND/FMUSIC mixing is taking.
-

-F_FLOAT_API F_API FSOUND_GetCPUUsage(
-);
-

Return Value

-floating point value between 0.0 and 100.0.
-

Remarks

-This value represents the cpu usage used by streams, the software mixer, and subsequent calls to dsound waveout etc.
-MIDI playback is not counted as it is performed by directx.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetCPUUsage + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetCPUUsage

+Returns in percent of cpu time the amount of cpu usage that FSOUND/FMUSIC mixing is taking.
+

+F_FLOAT_API F_API FSOUND_GetCPUUsage(
+);
+

Return Value

+floating point value between 0.0 and 100.0.
+

Remarks

+This value represents the cpu usage used by streams, the software mixer, and subsequent calls to dsound waveout etc.
+MIDI playback is not counted as it is performed by directx.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetChannelsPlaying.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetChannelsPlaying.html index bbb17838..64736db2 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetChannelsPlaying.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetChannelsPlaying.html @@ -1,53 +1,53 @@ - - - - -FSOUND_GetChannelsPlaying - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetChannelsPlaying

-Returns the number of active channels in FSOUND, or ones that are playing.
-

-int F_API FSOUND_GetChannelsPlaying(
-);
-

Return Value

-Number of active channels.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_OptimizeChannels -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetChannelsPlaying + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetChannelsPlaying

+Returns the number of active channels in FSOUND, or ones that are playing.
+

+int F_API FSOUND_GetChannelsPlaying(
+);
+

Return Value

+Number of active channels.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_OptimizeChannels +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentLevels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentLevels.html index c8de2868..0840fc7c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentLevels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentLevels.html @@ -1,75 +1,75 @@ - - - - -FSOUND_GetCurrentLevels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetCurrentLevels

-Returns a left and right VU/Level reading at the current position of the specified channel.
-Levels are are only supported for software channels.
-

-DLL_API signed char F_API FSOUND_GetCurrentLevels(
-int channel,
-F_FLOAT_API *l,
-F_FLOAT_API *r
-);
-

Parameters

- - - - -
channelChannel number/handle to retrieve left and right level from.
-
lPointer to a floating point value to store left level, between 0 and 1.
-
rPointer to a floating point value to store right level, between 0 and 1.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-By default this function is only point sampled and not latency adjusted (it will appear to trigger ahead of when you hear the sound).
-To fix this and get a 'perfect' set of levels in realtime, use FSOUND_INIT_ACCURATEVULEVELS with FSOUND_Init.
--------------------
-To get an overall VU reading for all sounds, add all VU values for each channel together, and then clip at 1.0.
-Another (harder) way is to write a dsp unit that reads from the mixbuffer being passed into it.
-Note: A true 'VU' should be smoothed, but in case people were after more accuracy than a smoothed value, it was decided to return the raw amplitude, and let the user smooth the result in their own way.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetAmplitude -, -FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetCurrentLevels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetCurrentLevels

+Returns a left and right VU/Level reading at the current position of the specified channel.
+Levels are are only supported for software channels.
+

+DLL_API signed char F_API FSOUND_GetCurrentLevels(
+int channel,
+F_FLOAT_API *l,
+F_FLOAT_API *r
+);
+

Parameters

+ + + + +
channelChannel number/handle to retrieve left and right level from.
+
lPointer to a floating point value to store left level, between 0 and 1.
+
rPointer to a floating point value to store right level, between 0 and 1.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+By default this function is only point sampled and not latency adjusted (it will appear to trigger ahead of when you hear the sound).
+To fix this and get a 'perfect' set of levels in realtime, use FSOUND_INIT_ACCURATEVULEVELS with FSOUND_Init.
+-------------------
+To get an overall VU reading for all sounds, add all VU values for each channel together, and then clip at 1.0.
+Another (harder) way is to write a dsp unit that reads from the mixbuffer being passed into it.
+Note: A true 'VU' should be smoothed, but in case people were after more accuracy than a smoothed value, it was decided to return the raw amplitude, and let the user smooth the result in their own way.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetAmplitude +, +FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentPosition.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentPosition.html index 3a5f8b14..875d932f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentPosition.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentPosition.html @@ -1,62 +1,62 @@ - - - - -FSOUND_GetCurrentPosition - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetCurrentPosition

-Returns the current playcursor position of the specified channel.
-

-unsigned int F_API FSOUND_GetCurrentPosition(
-int channel
-);
-

Parameters

- - -
channelChannel number/handle to get the current position from.
-
-

Return Value

-On success, the play cursor position in SAMPLES is returned for the specified channel.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Record_StartSample -, -FSOUND_SetCurrentPosition -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetCurrentPosition + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetCurrentPosition

+Returns the current playcursor position of the specified channel.
+

+unsigned int F_API FSOUND_GetCurrentPosition(
+int channel
+);
+

Parameters

+ + +
channelChannel number/handle to get the current position from.
+
+

Return Value

+On success, the play cursor position in SAMPLES is returned for the specified channel.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Record_StartSample +, +FSOUND_SetCurrentPosition +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentSample.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentSample.html index 6cae7929..18d682e5 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentSample.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetCurrentSample.html @@ -1,59 +1,59 @@ - - - - -FSOUND_GetCurrentSample - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetCurrentSample

-Returns the current sample being played on the specified channel.
-

-FSOUND_SAMPLE * F_API FSOUND_GetCurrentSample(
-int channel
-);
-

Parameters

- - -
channelChannel number/handle to get the currently playing sample from.
-
-

Return Value

-On success, a pointer to a sample handle is returned for the specified channel.
-On failure, NULL is returned.
-

Remarks

-Note that current sample does not return to NULL when a sound has ended.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetCurrentSample + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetCurrentSample

+Returns the current sample being played on the specified channel.
+

+FSOUND_SAMPLE * F_API FSOUND_GetCurrentSample(
+int channel
+);
+

Parameters

+ + +
channelChannel number/handle to get the currently playing sample from.
+
+

Return Value

+On success, a pointer to a sample handle is returned for the specified channel.
+On failure, NULL is returned.
+

Remarks

+Note that current sample does not return to NULL when a sound has ended.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriver.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriver.html index 5821276c..fe4917af 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriver.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriver.html @@ -1,62 +1,62 @@ - - - - -FSOUND_GetDriver - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetDriver

-Returns the currently selected driver number. Drivers are enumerated when selecting a driver
-with FSOUND_SetDriver or other driver related functions such as FSOUND_GetNumDrivers or
-FSOUND_GetDriverName
-

-int F_API FSOUND_GetDriver(
-);
-

Return Value

-Currently selected driver id.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2
-

Remarks

-If no driver is manually selected, 0 is returned, or the default driver.
-

See Also

-FSOUND_GetDriver -, -FSOUND_GetDriverName -, -FSOUND_GetNumDrivers -, -FSOUND_SetDriver -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetDriver + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetDriver

+Returns the currently selected driver number. Drivers are enumerated when selecting a driver
+with FSOUND_SetDriver or other driver related functions such as FSOUND_GetNumDrivers or
+FSOUND_GetDriverName
+

+int F_API FSOUND_GetDriver(
+);
+

Return Value

+Currently selected driver id.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2
+

Remarks

+If no driver is manually selected, 0 is returned, or the default driver.
+

See Also

+FSOUND_GetDriver +, +FSOUND_GetDriverName +, +FSOUND_GetNumDrivers +, +FSOUND_SetDriver +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverCaps.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverCaps.html index 0c656c36..73089727 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverCaps.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverCaps.html @@ -1,72 +1,72 @@ - - - - -FSOUND_GetDriverCaps - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetDriverCaps

-Returns information on capabilities of the current output mode.
-

-signed char F_API FSOUND_GetDriverCaps(
-int id,
-unsigned int *caps
-);
-

Parameters

- - - -
idEnumerated driver ID. This must be in a valid range delimited by FSOUND_GetNumDrivers,
-
capsPointer to an unsigned int to have the caps bits stored.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init.
-FSOUND_SetOutput must be called to tell FMOD which output mode you are talking about.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_CAPS -, -FSOUND_GetNumDrivers -, -FSOUND_Init -, -FSOUND_SetOutput -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetDriverCaps + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetDriverCaps

+Returns information on capabilities of the current output mode.
+

+signed char F_API FSOUND_GetDriverCaps(
+int id,
+unsigned int *caps
+);
+

Parameters

+ + + +
idEnumerated driver ID. This must be in a valid range delimited by FSOUND_GetNumDrivers,
+
capsPointer to an unsigned int to have the caps bits stored.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init.
+FSOUND_SetOutput must be called to tell FMOD which output mode you are talking about.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_CAPS +, +FSOUND_GetNumDrivers +, +FSOUND_Init +, +FSOUND_SetOutput +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverName.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverName.html index f1a793b4..a06ac57a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverName.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetDriverName.html @@ -1,65 +1,65 @@ - - - - -FSOUND_GetDriverName - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetDriverName

-Returns the name of the selected driver. Drivers are enumerated when selecting a driver with
-FSOUND_SetDriver or other driver related functions such as FSOUND_GetNumDrivers or
-FSOUND_GetDriver
-

-const char * F_API FSOUND_GetDriverName(
-int id
-);
-

Parameters

- - -
idEnumerated driver ID. This must be in a valid range delimited by FSOUND_GetNumDrivers,
-
-

Return Value

-On success, a pointer to a NULL terminated string containing the name of the specified device is returned. The number of drivers enumerated can be found with FSOUND_GetNumDrivers.
-On failure, NULL is returned.
-

Remarks

-If no driver is selected, the default driver is used.
-

See Also

-FSOUND_GetDriver -, -FSOUND_GetNumDrivers -, -FSOUND_SetDriver -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetDriverName + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetDriverName

+Returns the name of the selected driver. Drivers are enumerated when selecting a driver with
+FSOUND_SetDriver or other driver related functions such as FSOUND_GetNumDrivers or
+FSOUND_GetDriver
+

+const char * F_API FSOUND_GetDriverName(
+int id
+);
+

Parameters

+ + +
idEnumerated driver ID. This must be in a valid range delimited by FSOUND_GetNumDrivers,
+
+

Return Value

+On success, a pointer to a NULL terminated string containing the name of the specified device is returned. The number of drivers enumerated can be found with FSOUND_GetNumDrivers.
+On failure, NULL is returned.
+

Remarks

+If no driver is selected, the default driver is used.
+

See Also

+FSOUND_GetDriver +, +FSOUND_GetNumDrivers +, +FSOUND_SetDriver +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetError.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetError.html index 951f8eb8..99b13247 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetError.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetError.html @@ -1,63 +1,63 @@ - - - - -FSOUND_GetError - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetError

-Returns an error code set by FMOD.
-

-int F_API FSOUND_GetError(
-);
-

Return Value

-error code, see FMOD_ERRORS
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMOD_ERRORS -, -FSOUND_GetAmplitude -, -FSOUND_GetFrequency -, -FSOUND_GetPan -, -FSOUND_GetPriority -, -FSOUND_GetVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetError + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetError

+Returns an error code set by FMOD.
+

+int F_API FSOUND_GetError(
+);
+

Return Value

+error code, see FMOD_ERRORS
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMOD_ERRORS +, +FSOUND_GetAmplitude +, +FSOUND_GetFrequency +, +FSOUND_GetPan +, +FSOUND_GetPriority +, +FSOUND_GetVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFreeHWRam.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFreeHWRam.html index 6e6554c9..b5a8584f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFreeHWRam.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFreeHWRam.html @@ -1,77 +1,77 @@ - - - - -FSOUND_GetFreeHWRam - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetFreeHWRam

-Return free SRAM and IOP ram after or before FMOD is initialized.
-

-signed char F_API FSOUND_GetFreeHWRam(
-int *spu2ram,
-int *iopram
-);
-

Parameters

- - - -
spu2ramPointer to variable to contain free SPU2 ram.
-
iopramPointer to variable to contain free IOP ram.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Free IOP ram means IOP memory free before initializing FMOD, or after FMOD memory pool size is specified with
-FSOUND_SetMemorySystem and FSOUND_Init. For example on a 2mb IOP system, before FSOUND_Init it might return
-2mb, and after, if you call FSOUND_Init with a memory pool size of 1.5mb, this function would return .5mb.
-This is different to the values returned by FSOUND_GetMemoryStats, which is the memory information within that
-1.5mb pool.
-------------------
-Note using FSOUND_INIT_DISABLE_CORE0_REVERB or/and FSOUND_INIT_DISABLE_CORE1_REVERB will regain SPU2 ram,
-but disables hardware reverb. Use this if you want to fit more sounds in and are not worried about reverb.
-------------------
-This function can be called before or after FSOUND_Init.
-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_GetMemoryStats -, -FSOUND_Init -, -FSOUND_SetMemorySystem -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetFreeHWRam + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetFreeHWRam

+Return free SRAM and IOP ram after or before FMOD is initialized.
+

+signed char F_API FSOUND_GetFreeHWRam(
+int *spu2ram,
+int *iopram
+);
+

Parameters

+ + + +
spu2ramPointer to variable to contain free SPU2 ram.
+
iopramPointer to variable to contain free IOP ram.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Free IOP ram means IOP memory free before initializing FMOD, or after FMOD memory pool size is specified with
+FSOUND_SetMemorySystem and FSOUND_Init. For example on a 2mb IOP system, before FSOUND_Init it might return
+2mb, and after, if you call FSOUND_Init with a memory pool size of 1.5mb, this function would return .5mb.
+This is different to the values returned by FSOUND_GetMemoryStats, which is the memory information within that
+1.5mb pool.
+------------------
+Note using FSOUND_INIT_DISABLE_CORE0_REVERB or/and FSOUND_INIT_DISABLE_CORE1_REVERB will regain SPU2 ram,
+but disables hardware reverb. Use this if you want to fit more sounds in and are not worried about reverb.
+------------------
+This function can be called before or after FSOUND_Init.
+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_GetMemoryStats +, +FSOUND_Init +, +FSOUND_SetMemorySystem +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFrequency.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFrequency.html index 0c1870c9..19411c0a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFrequency.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetFrequency.html @@ -1,62 +1,62 @@ - - - - -FSOUND_GetFrequency - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetFrequency

-Returns the frequency in HZ of the specified channel.
-

-int F_API FSOUND_GetFrequency(
-int channel
-);
-

Parameters

- - -
channelThe number/handle to get the frequency from.
-
-

Return Value

-On success, the frequency in HZ of the specified channel is returned.
-On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetError -, -FSOUND_SetFrequency -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetFrequency + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetFrequency

+Returns the frequency in HZ of the specified channel.
+

+int F_API FSOUND_GetFrequency(
+int channel
+);
+

Parameters

+ + +
channelThe number/handle to get the frequency from.
+
+

Return Value

+On success, the frequency in HZ of the specified channel is returned.
+On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetError +, +FSOUND_SetFrequency +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetLoopMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetLoopMode.html index 7c6a804c..ca5b2c35 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetLoopMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetLoopMode.html @@ -1,61 +1,61 @@ - - - - -FSOUND_GetLoopMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetLoopMode

-Gets the loop mode for a particular channel.
-

-unsigned int F_API FSOUND_GetLoopMode(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the loop mode from.
-
-

Return Value

-On success, the loop mode is returned.
-On failure, 0 is returned.
-

Remarks

-This works for all channel types, whereas setting it will not work.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_SetMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetLoopMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetLoopMode

+Gets the loop mode for a particular channel.
+

+unsigned int F_API FSOUND_GetLoopMode(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the loop mode from.
+
+

Return Value

+On success, the loop mode is returned.
+On failure, 0 is returned.
+

Remarks

+This works for all channel types, whereas setting it will not work.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_SetMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxChannels.html index cf7a425b..df58a7b1 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxChannels.html @@ -1,53 +1,53 @@ - - - - -FSOUND_GetMaxChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetMaxChannels

-Returns the total number of channels allocated.
-

-int F_API FSOUND_GetMaxChannels(
-);
-

Return Value

-Number of channels allocated
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetMaxChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetMaxChannels

+Returns the total number of channels allocated.
+

+int F_API FSOUND_GetMaxChannels(
+);
+

Return Value

+Number of channels allocated
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxSamples.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxSamples.html index 2c8551a5..2dfdda02 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxSamples.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMaxSamples.html @@ -1,52 +1,52 @@ - - - - -FSOUND_GetMaxSamples - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetMaxSamples

-Returns the current maximum index for a sample. This figure grows as you allocate more
-samples (in blocks)
-

-int F_API FSOUND_GetMaxSamples(
-);
-

Return Value

-Maximum sample index
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:29 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetMaxSamples + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetMaxSamples

+Returns the current maximum index for a sample. This figure grows as you allocate more
+samples (in blocks)
+

+int F_API FSOUND_GetMaxSamples(
+);
+

Return Value

+Maximum sample index
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:29 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMemoryStats.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMemoryStats.html index ecddafaa..5951fa37 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMemoryStats.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMemoryStats.html @@ -1,74 +1,74 @@ - - - - -FSOUND_GetMemoryStats - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetMemoryStats

-Returns information on the memory usage of fmod. This is useful for determining a fixed memory size to
-make FMOD work within for fixed memory machines such as pocketpc and consoles.
-

-DLL_API void F_API FSOUND_GetMemoryStats(
-unsigned int *currentalloced,
-unsigned int *maxalloced
-);
-

Parameters

- - - -
currentallocedCurrently allocated memory at time of call.
-
maxallocedMaximum allocated memory since FSOUND_Init or FSOUND_SetMemorySystem
-
-

Return Value

-void
-

Remarks

-Note that if using FSOUND_SetMemorySystem, the memory usage will be slightly higher than without it, as fmod has to have a small amount of memory overhead to manage the available memory.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_ALLOCCALLBACK -, -FSOUND_FREECALLBACK -, -FSOUND_GetFreeHWRam -, -FSOUND_Init -, -FSOUND_REALLOCCALLBACK -, -FSOUND_SetMemorySystem -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetMemoryStats + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetMemoryStats

+Returns information on the memory usage of fmod. This is useful for determining a fixed memory size to
+make FMOD work within for fixed memory machines such as pocketpc and consoles.
+

+DLL_API void F_API FSOUND_GetMemoryStats(
+unsigned int *currentalloced,
+unsigned int *maxalloced
+);
+

Parameters

+ + + +
currentallocedCurrently allocated memory at time of call.
+
maxallocedMaximum allocated memory since FSOUND_Init or FSOUND_SetMemorySystem
+
+

Return Value

+void
+

Remarks

+Note that if using FSOUND_SetMemorySystem, the memory usage will be slightly higher than without it, as fmod has to have a small amount of memory overhead to manage the available memory.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_ALLOCCALLBACK +, +FSOUND_FREECALLBACK +, +FSOUND_GetFreeHWRam +, +FSOUND_Init +, +FSOUND_REALLOCCALLBACK +, +FSOUND_SetMemorySystem +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMixer.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMixer.html index 30c33db5..09e05d99 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMixer.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMixer.html @@ -1,62 +1,62 @@ - - - - -FSOUND_GetMixer - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetMixer

-Returns the currently used mixer type.
-

-int F_API FSOUND_GetMixer(
-);
-

Return Value

-FSOUND_GetMixer returns a defenition from FSOUND_MIXERTYPES. See FSOUND_MIXERTYPES for valid
-parameters and descriptions.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSP_MixBuffers -, -FSOUND_GetMixer -, -FSOUND_MIXERTYPES -, -FSOUND_SetMixer -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetMixer + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetMixer

+Returns the currently used mixer type.
+

+int F_API FSOUND_GetMixer(
+);
+

Return Value

+FSOUND_GetMixer returns a defenition from FSOUND_MIXERTYPES. See FSOUND_MIXERTYPES for valid
+parameters and descriptions.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSP_MixBuffers +, +FSOUND_GetMixer +, +FSOUND_MIXERTYPES +, +FSOUND_SetMixer +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMute.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMute.html index 3976a3e9..461b7fe7 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMute.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetMute.html @@ -1,60 +1,60 @@ - - - - -FSOUND_GetMute - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetMute

-Returns if the channel specified is muted or not
-

-signed char F_API FSOUND_GetMute(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the mute status from
-
-

Return Value

-TRUE - The channel has mute turned ON
-FALSE - The channel has mute turned OFF
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetMute -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetMute + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetMute

+Returns if the channel specified is muted or not
+

+signed char F_API FSOUND_GetMute(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the mute status from
+
+

Return Value

+TRUE - The channel has mute turned ON
+FALSE - The channel has mute turned OFF
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetMute +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumDrivers.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumDrivers.html index 8a365dec..741598f8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumDrivers.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumDrivers.html @@ -1,60 +1,60 @@ - - - - -FSOUND_GetNumDrivers - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetNumDrivers

-Returns the number of sound cards or devices enumerated for the current output type. (Direct
-Sound, WaveOut etc.)
-

-int F_API FSOUND_GetNumDrivers(
-);
-

Return Value

-Total number of enumerated sound devices.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetDriver -, -FSOUND_GetDriverCaps -, -FSOUND_GetDriverName -, -FSOUND_SetDriver -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetNumDrivers + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetNumDrivers

+Returns the number of sound cards or devices enumerated for the current output type. (Direct
+Sound, WaveOut etc.)
+

+int F_API FSOUND_GetNumDrivers(
+);
+

Return Value

+Total number of enumerated sound devices.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetDriver +, +FSOUND_GetDriverCaps +, +FSOUND_GetDriverName +, +FSOUND_SetDriver +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHWChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHWChannels.html index fa23c427..0c42c4ec 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHWChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHWChannels.html @@ -1,64 +1,64 @@ - - - - -FSOUND_GetNumHWChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetNumHWChannels

-Returns the number of available hardware mixed 2d and 3d channels.
-

-signed char F_API FSOUND_GetNumHWChannels(
-int *num2d,
-int *num3d,
-int *total
-);
-

Parameters

- - - - -
num2dPointer to integer to store the number of available hardware mixed 2d channels.
-
num3dPointer to integer to store the number of available hardware mixed 3d channels.
-
totalUsually num2d + num3d, but on some platforms like PS2 and GameCube, this will be the same as num2d and num3d (and not the sum) because 2d and 3d voices share the same pool.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetNumHWChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetNumHWChannels

+Returns the number of available hardware mixed 2d and 3d channels.
+

+signed char F_API FSOUND_GetNumHWChannels(
+int *num2d,
+int *num3d,
+int *total
+);
+

Parameters

+ + + + +
num2dPointer to integer to store the number of available hardware mixed 2d channels.
+
num3dPointer to integer to store the number of available hardware mixed 3d channels.
+
totalUsually num2d + num3d, but on some platforms like PS2 and GameCube, this will be the same as num2d and num3d (and not the sum) because 2d and 3d voices share the same pool.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHardwareChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHardwareChannels.html index fdf12cc4..369e32e0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHardwareChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumHardwareChannels.html @@ -1,57 +1,57 @@ - - - - -FSOUND_GetNumHardwareChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetNumHardwareChannels

-Returns the number of available hardware mixed 3d channels.
-

-int F_API FSOUND_GetNumHardwareChannels(
-);
-

Return Value

-The number of available hardware mixed 3d channels.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_PlaySound -, -FSOUND_PlaySoundEx -, -FSOUND_SetFrequency -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Fri Nov 14 18:04:55 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetNumHardwareChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetNumHardwareChannels

+Returns the number of available hardware mixed 3d channels.
+

+int F_API FSOUND_GetNumHardwareChannels(
+);
+

Return Value

+The number of available hardware mixed 3d channels.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_PlaySound +, +FSOUND_PlaySoundEx +, +FSOUND_SetFrequency +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Fri Nov 14 18:04:55 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumSubChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumSubChannels.html index 928b563c..e5e0fbef 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumSubChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetNumSubChannels.html @@ -1,71 +1,71 @@ - - - - -FSOUND_GetNumSubChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetNumSubChannels

-This function returns the number of sub-channels stored in a multi-channel channel handle, which is only possible when playing back a multichannel .FSB file.
-

-int F_API FSOUND_GetNumSubChannels(
-int channel
-);
-

Parameters

- - -
channelThe value returned by FSOUND_Stream_Play, FSOUND_Stream_PlayEx, FSOUND_PlaySound, FSOUND_PlaySoundEx.
-
-

Return Value

-On success, the number of subchannels is returned
-On failure, 0 is returned.
-

Remarks

-A multichannel sound, only possible with the .FSB format, can contain multiple subchannels. When a multichannel sound is played, multiple channels are allocated at the same time.
-For example, a 8 sounds/streams can be interleaved into a multichannel FSB. This function would return 8, as 8 real hardware/software voices are used during playback.
-FSOUND_GetSubChannel can be used to get access to the secondary channels.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetSubChannel -, -FSOUND_PlaySound -, -FSOUND_PlaySoundEx -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetNumSubChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetNumSubChannels

+This function returns the number of sub-channels stored in a multi-channel channel handle, which is only possible when playing back a multichannel .FSB file.
+

+int F_API FSOUND_GetNumSubChannels(
+int channel
+);
+

Parameters

+ + +
channelThe value returned by FSOUND_Stream_Play, FSOUND_Stream_PlayEx, FSOUND_PlaySound, FSOUND_PlaySoundEx.
+
+

Return Value

+On success, the number of subchannels is returned
+On failure, 0 is returned.
+

Remarks

+A multichannel sound, only possible with the .FSB format, can contain multiple subchannels. When a multichannel sound is played, multiple channels are allocated at the same time.
+For example, a 8 sounds/streams can be interleaved into a multichannel FSB. This function would return 8, as 8 real hardware/software voices are used during playback.
+FSOUND_GetSubChannel can be used to get access to the secondary channels.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetSubChannel +, +FSOUND_PlaySound +, +FSOUND_PlaySoundEx +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutput.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutput.html index e7a55e33..aa885ad0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutput.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutput.html @@ -1,60 +1,60 @@ - - - - -FSOUND_GetOutput - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetOutput

-Returns the current id to the output type.
-See FSOUND_OUTPUTTYPES for valid parameters and descriptions.
-

-int F_API FSOUND_GetOutput(
-);
-

Return Value

-id to output type
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetOutputHandle -, -FSOUND_OUTPUTTYPES -, -FSOUND_SetFrequency -, -FSOUND_SetOutput -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetOutput + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetOutput

+Returns the current id to the output type.
+See FSOUND_OUTPUTTYPES for valid parameters and descriptions.
+

+int F_API FSOUND_GetOutput(
+);
+

Return Value

+id to output type
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetOutputHandle +, +FSOUND_OUTPUTTYPES +, +FSOUND_SetFrequency +, +FSOUND_SetOutput +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputHandle.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputHandle.html index 0fb7e578..4d8043eb 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputHandle.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputHandle.html @@ -1,77 +1,77 @@ - - - - -FSOUND_GetOutputHandle - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetOutputHandle

-Returns a pointer to the system level output device module.
-This means a pointer to a DIRECTSOUND, WINMM handle, or with NOSOUND output, NULL
-

-void * F_API FSOUND_GetOutputHandle(
-);
-

Return Value

-Pointer to output handle specific to the device.
-

Remarks

-Must be called after FSOUND_Init or else it will fail,
-Cast the resulting pointer depending on what output system pointer you are after.
-FSOUND_OUTPUT_NOSOUND, NULL is returned.
-FSOUND_OUTPUT_WINMM, HWAVEOUT is returned.
-FSOUND_OUTPUT_DSOUND, LPDIRECTSOUND is returned.
-FSOUND_OUTPUT_OSS, File handle is returned, (cast to int)
-FSOUND_OUTPUT_ESD, Handle returned by so_esd_open_sound (cast to int).
-FSOUND_OUTPUT_ALSA snd_pcm_t * is returned.
-FSOUND_OUTPUT_ASIO AsioDriverList pointer is returned.
-FSOUND_OUTPUT_XBOX LPDIRECTSOUND is returned.
-FSOUND_OUTPUT_PS2 NULL is returned.
-FSOUND_OUTPUT_MAC SndChannelPtr is returned.
-FSOUND_OUTPUT_GC NULL is returned.
-FSOUND_OUTPUT_PSP NULL is returned.
-FSOUND_OUTPUT_NOSOUND_NONREALTIME NULL is returned.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox
-

See Also

-FSOUND_GetOutput -, -FSOUND_Init -, -FSOUND_OUTPUTTYPES -, -FSOUND_SetFrequency -, -FSOUND_SetOutput -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetOutputHandle + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetOutputHandle

+Returns a pointer to the system level output device module.
+This means a pointer to a DIRECTSOUND, WINMM handle, or with NOSOUND output, NULL
+

+void * F_API FSOUND_GetOutputHandle(
+);
+

Return Value

+Pointer to output handle specific to the device.
+

Remarks

+Must be called after FSOUND_Init or else it will fail,
+Cast the resulting pointer depending on what output system pointer you are after.
+FSOUND_OUTPUT_NOSOUND, NULL is returned.
+FSOUND_OUTPUT_WINMM, HWAVEOUT is returned.
+FSOUND_OUTPUT_DSOUND, LPDIRECTSOUND is returned.
+FSOUND_OUTPUT_OSS, File handle is returned, (cast to int)
+FSOUND_OUTPUT_ESD, Handle returned by so_esd_open_sound (cast to int).
+FSOUND_OUTPUT_ALSA snd_pcm_t * is returned.
+FSOUND_OUTPUT_ASIO AsioDriverList pointer is returned.
+FSOUND_OUTPUT_XBOX LPDIRECTSOUND is returned.
+FSOUND_OUTPUT_PS2 NULL is returned.
+FSOUND_OUTPUT_MAC SndChannelPtr is returned.
+FSOUND_OUTPUT_GC NULL is returned.
+FSOUND_OUTPUT_PSP NULL is returned.
+FSOUND_OUTPUT_NOSOUND_NONREALTIME NULL is returned.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox
+

See Also

+FSOUND_GetOutput +, +FSOUND_Init +, +FSOUND_OUTPUTTYPES +, +FSOUND_SetFrequency +, +FSOUND_SetOutput +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputRate.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputRate.html index 6b03239c..bfb87119 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputRate.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetOutputRate.html @@ -1,53 +1,53 @@ - - - - -FSOUND_GetOutputRate - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetOutputRate

-Returns the current mixing rate
-

-int F_API FSOUND_GetOutputRate(
-);
-

Return Value

-Currently set output rate in HZ.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetOutputRate + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetOutputRate

+Returns the current mixing rate
+

+int F_API FSOUND_GetOutputRate(
+);
+

Return Value

+Currently set output rate in HZ.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPan.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPan.html index 2d67961b..ca961cff 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPan.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPan.html @@ -1,64 +1,64 @@ - - - - -FSOUND_GetPan - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetPan

-Returns the linear pan position of the specified channel between 0 and 255
-

-int F_API FSOUND_GetPan(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the pan from.
-
-

Return Value

-On success, the following values are returned : 0 = full left to 128 = middle to 255 = full right, FSOUND_STEREOPAN
-On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetError -, -FSOUND_SetLevels -, -FSOUND_SetPan -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetPan + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetPan

+Returns the linear pan position of the specified channel between 0 and 255
+

+int F_API FSOUND_GetPan(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the pan from.
+
+

Return Value

+On success, the following values are returned : 0 = full left to 128 = middle to 255 = full right, FSOUND_STEREOPAN
+On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetError +, +FSOUND_SetLevels +, +FSOUND_SetPan +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPaused.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPaused.html index ce3aa8bc..ff7d2ab1 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPaused.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPaused.html @@ -1,63 +1,63 @@ - - - - -FSOUND_GetPaused - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetPaused

-Gets current pause status of the channel.
-

-signed char F_API FSOUND_GetPaused(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the paused status from.
-
-

Return Value

-TRUE - The channel is currently paused.
-FALSE - The channel is running.
-

Remarks

-This function is useful for games that have a pause mode, and you dont want the sounds
-to continue playing, but you would like them to continue on from where they left off
-when you unpause.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetPaused -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetPaused + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetPaused

+Gets current pause status of the channel.
+

+signed char F_API FSOUND_GetPaused(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the paused status from.
+
+

Return Value

+TRUE - The channel is currently paused.
+FALSE - The channel is running.
+

Remarks

+This function is useful for games that have a pause mode, and you dont want the sounds
+to continue playing, but you would like them to continue on from where they left off
+when you unpause.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetPaused +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPriority.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPriority.html index 9894a268..dbc671ed 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPriority.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetPriority.html @@ -1,66 +1,66 @@ - - - - -FSOUND_GetPriority - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetPriority

-Gets a sound channels priority. Priority is used to determine if soundeffects should
-replace other sound effects when the channel limit has been reached. See
-FSOUND_SetPriority for more information.
-

-int F_API FSOUND_GetPriority(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the priority from.
-
-

Return Value

-On success, the priority of the channel is returned. Ranges between 0 and 255.
-On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetError -, -FSOUND_SetPriority -, -FSOUND_SetReserved -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetPriority + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetPriority

+Gets a sound channels priority. Priority is used to determine if soundeffects should
+replace other sound effects when the channel limit has been reached. See
+FSOUND_SetPriority for more information.
+

+int F_API FSOUND_GetPriority(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the priority from.
+
+

Return Value

+On success, the priority of the channel is returned. Ranges between 0 and 255.
+On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetError +, +FSOUND_SetPriority +, +FSOUND_SetReserved +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetReserved.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetReserved.html index 651cad34..1abffbed 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetReserved.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetReserved.html @@ -1,63 +1,63 @@ - - - - -FSOUND_GetReserved - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetReserved

-Gets a sound channels reserved status. priority is used to determine if soundeffects should muscle
-out other sound effects when the channel limit has been reached.
-

-signed char F_API FSOUND_GetReserved(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the reserved status from.
-
-

Return Value

-TRUE Channel is reserved and cannot be selected.
-FALSE Channel is reserved and can be selected.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetPriority -, -FSOUND_SetReserved -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetReserved + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetReserved

+Gets a sound channels reserved status. priority is used to determine if soundeffects should muscle
+out other sound effects when the channel limit has been reached.
+

+signed char F_API FSOUND_GetReserved(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the reserved status from.
+
+

Return Value

+TRUE Channel is reserved and cannot be selected.
+FALSE Channel is reserved and can be selected.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetPriority +, +FSOUND_SetReserved +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSFXMasterVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSFXMasterVolume.html index 4370d288..377ae7bc 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSFXMasterVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSFXMasterVolume.html @@ -1,55 +1,55 @@ - - - - -FSOUND_GetSFXMasterVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetSFXMasterVolume

-Returns the master volume for any sound effects played.
-It specifically has SFX in the function name, as it does not affect music or CD volume.
-This must also be altered with FMUSIC_SetMasterVolume.
-

-DLL_API int F_API FSOUND_GetSFXMasterVolume(
-);
-

Return Value

-On success, the SFX master volume is returned. Valid ranges are from 0 (silent) to 255 (full volume)
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetMasterVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetSFXMasterVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetSFXMasterVolume

+Returns the master volume for any sound effects played.
+It specifically has SFX in the function name, as it does not affect music or CD volume.
+This must also be altered with FMUSIC_SetMasterVolume.
+

+DLL_API int F_API FSOUND_GetSFXMasterVolume(
+);
+

Return Value

+On success, the SFX master volume is returned. Valid ranges are from 0 (silent) to 255 (full volume)
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetMasterVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSpeakerMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSpeakerMode.html index 24568e80..049de72e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSpeakerMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSpeakerMode.html @@ -1,57 +1,57 @@ - - - - -FSOUND_GetSpeakerMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetSpeakerMode

-Gets the mode for currently set speakermode.
-

-unsigned int F_API FSOUND_GetSpeakerMode(
-);
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetPanSeperation -, -FSOUND_SetSpeakerMode -, -FSOUND_SPEAKERMODES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetSpeakerMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetSpeakerMode

+Gets the mode for currently set speakermode.
+

+unsigned int F_API FSOUND_GetSpeakerMode(
+);
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetPanSeperation +, +FSOUND_SetSpeakerMode +, +FSOUND_SPEAKERMODES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSubChannel.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSubChannel.html index 9cfa49d7..43b61119 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSubChannel.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSubChannel.html @@ -1,78 +1,78 @@ - - - - -FSOUND_GetSubChannel - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetSubChannel

-This function returns a channel handle from a subchannel within a multichannel FSB file, so that it can be maniuplated seperately, instead of controlling the whole multichannel array with the parent channel that the user retrieves from FSOUND_PlaySound etc.
-

-int F_API FSOUND_GetSubChannel(
-int channel,
-int subchannel
-);
-

Parameters

- - - -
channelThe value returned by FSOUND_Stream_Play, FSOUND_Stream_PlayEx, FSOUND_PlaySound, FSOUND_PlaySoundEx.
-
subchannelOffset from the parent channel into the multichannel array.
-
-

Return Value

-On success, a raw channel handle is returned.
-On failure, -1 is returned.
-

Remarks

-A multichannel sound, only possible with the .FSB format, can contain multiple subchannels. When a multichannel sound is played, multiple channels are allocated at the same time.
-Normally you can just use the parent handle, and things like FSOUND_SetVolume will affect all subchannels at the same time. With this function, you can get access to the raw subchannels to allow manipulation of each voice seperately within the multichannel array.
-For example, a 8 sounds/streams can be interleaved into a multichannel FSB. If you specified a subchannel of 7, it would return a channel handle to the last channel in the multichannel array.
-A subchannel index of 0 is the parent channel, and the same as the voice passed in is a parameter.
-The number of subchannels within a multichannel voice can be determined with FSOUND_GetNumSubChannels.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetNumSubChannels -, -FSOUND_PlaySound -, -FSOUND_PlaySoundEx -, -FSOUND_SetVolume -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetSubChannel + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetSubChannel

+This function returns a channel handle from a subchannel within a multichannel FSB file, so that it can be maniuplated seperately, instead of controlling the whole multichannel array with the parent channel that the user retrieves from FSOUND_PlaySound etc.
+

+int F_API FSOUND_GetSubChannel(
+int channel,
+int subchannel
+);
+

Parameters

+ + + +
channelThe value returned by FSOUND_Stream_Play, FSOUND_Stream_PlayEx, FSOUND_PlaySound, FSOUND_PlaySoundEx.
+
subchannelOffset from the parent channel into the multichannel array.
+
+

Return Value

+On success, a raw channel handle is returned.
+On failure, -1 is returned.
+

Remarks

+A multichannel sound, only possible with the .FSB format, can contain multiple subchannels. When a multichannel sound is played, multiple channels are allocated at the same time.
+Normally you can just use the parent handle, and things like FSOUND_SetVolume will affect all subchannels at the same time. With this function, you can get access to the raw subchannels to allow manipulation of each voice seperately within the multichannel array.
+For example, a 8 sounds/streams can be interleaved into a multichannel FSB. If you specified a subchannel of 7, it would return a channel handle to the last channel in the multichannel array.
+A subchannel index of 0 is the parent channel, and the same as the voice passed in is a parameter.
+The number of subchannels within a multichannel voice can be determined with FSOUND_GetNumSubChannels.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetNumSubChannels +, +FSOUND_PlaySound +, +FSOUND_PlaySoundEx +, +FSOUND_SetVolume +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSurround.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSurround.html index 8d824ac2..189a4eb4 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSurround.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetSurround.html @@ -1,61 +1,61 @@ - - - - -FSOUND_GetSurround - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetSurround

-Returns the surround sound status of the specified channel.
-

-signed char F_API FSOUND_GetSurround(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the surround sound status from.
-
-

Return Value

-On success, TRUE is returned meaning the channel has surround sound turned ON
-On failure, FALSE is returned meaning the channel has surround sound turned OFF
-

Remarks

-Surround sound only works on software channels.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetSurround -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetSurround + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetSurround

+Returns the surround sound status of the specified channel.
+

+signed char F_API FSOUND_GetSurround(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the surround sound status from.
+
+

Return Value

+On success, TRUE is returned meaning the channel has surround sound turned ON
+On failure, FALSE is returned meaning the channel has surround sound turned OFF
+

Remarks

+Surround sound only works on software channels.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetSurround +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVersion.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVersion.html index 7469252c..26a61817 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVersion.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVersion.html @@ -1,53 +1,53 @@ - - - - -FSOUND_GetVersion - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetVersion

-Returns the FMOD version number.
-

-float F_API FSOUND_GetVersion(
-);
-

Return Value

-FMOD version number.
-

Remarks

-Use this to compare the header you are using against the compiled DLL version to make sure your
-DLL is up to date.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetVersion + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetVersion

+Returns the FMOD version number.
+

+float F_API FSOUND_GetVersion(
+);
+

Return Value

+FMOD version number.
+

Remarks

+Use this to compare the header you are using against the compiled DLL version to make sure your
+DLL is up to date.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVolume.html index 2c92e7d8..13d8240b 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_GetVolume.html @@ -1,64 +1,64 @@ - - - - -FSOUND_GetVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_GetVolume

-Returns the linear volume of the specified channel between 0 and 255
-

-int F_API FSOUND_GetVolume(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to get the volume from.
-
-

Return Value

-On success, the following values are returned : 0 = silent to 255 = full volume.
-On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetError -, -FSOUND_SetVolume -, -FSOUND_SetVolumeAbsolute -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_GetVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_GetVolume

+Returns the linear volume of the specified channel between 0 and 255
+

+int F_API FSOUND_GetVolume(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to get the volume from.
+
+

Return Value

+On success, the following values are returned : 0 = silent to 255 = full volume.
+On failure, 0 is returned. To quailfy if this is a real error, call FSOUND_GetError.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetError +, +FSOUND_SetVolume +, +FSOUND_SetVolumeAbsolute +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_INIT_FLAGS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_INIT_FLAGS.html index 193c992b..a576fd78 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_INIT_FLAGS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_INIT_FLAGS.html @@ -1,106 +1,106 @@ - - - - -FSOUND_INIT_FLAGS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_INIT_FLAGS

-Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour.
-FSOUND_INIT_ENABLESYSTEMCHANNELFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects.
-Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small.
-This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works.
-When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters.
-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FSOUND_INIT_USEDEFAULTMIDISYNTH0x0001 /* Win32 only - Causes MIDI playback to force software decoding. */ -
FSOUND_INIT_GLOBALFOCUS0x0002 /* Win32 only - For DirectSound output - sound is not muted when window is out of focus. */ -
FSOUND_INIT_ENABLESYSTEMCHANNELFX0x0004 /* Win32 only - For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! (use FSOUND_SYSTEMCHANNEL as channel id) */ -
FSOUND_INIT_ACCURATEVULEVELS0x0008 /* This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit */ -
FSOUND_INIT_PS2_DISABLECORE0REVERB0x0010 /* PS2 only - Disable reverb on CORE 0 (SPU2 voices 00-23) to regain SRAM */ -
FSOUND_INIT_PS2_DISABLECORE1REVERB0x0020 /* PS2 only - Disable reverb on CORE 1 (SPU2 voices 24-47) to regain SRAM */ -
FSOUND_INIT_PS2_SWAPDMACORES0x0040 /* PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around */ -
FSOUND_INIT_DONTLATENCYADJUST0x0080 /* Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate */ -
FSOUND_INIT_GC_INITLIBS0x0100 /* GC only - Initializes GC audio libraries */ -
FSOUND_INIT_STREAM_FROM_MAIN_THREAD0x0200 /* Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user */ -
FSOUND_INIT_PS2_USEVOLUMERAMPING0x0400 /* PS2 only - Turns on volume ramping system to remove hardware clicks. */ -
FSOUND_INIT_DSOUND_DEFERRED0x0800 /* Win32 only - For DirectSound output. 3D commands are batched together and executed at FSOUND_Update. */ -
FSOUND_INIT_DSOUND_HRTF_LIGHT0x1000 /* Win32 only - For DirectSound output. FSOUND_HW3D buffers use a slightly higher quality algorithm when 3d hardware acceleration is not present. */ -
FSOUND_INIT_DSOUND_HRTF_FULL0x2000 /* Win32 only - For DirectSound output. FSOUND_HW3D buffers use full quality 3d playback when 3d hardware acceleration is not present. */ -
FSOUND_INIT_XBOX_REMOVEHEADROOM0x4000 /* XBox only - By default directsound attenuates all sound by 6db to avoid clipping/distortion. CAUTION. If you use this flag you are responsible for the final mix to make sure clipping / distortion doesn't happen. */ -
FSOUND_INIT_PSP_SILENCEONUNDERRUN0x8000 /* PSP only - If streams skip / stutter when device is powered on, either increase stream buffersize, or use this flag instead to play silence while the UMD is recovering. */ -
-

See Also

-FSOUND_GetCurrentLevels -, -FSOUND_Init -, -FSOUND_SetBufferSize -, -FSOUND_Update -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_INIT_FLAGS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_INIT_FLAGS

+Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour.
+FSOUND_INIT_ENABLESYSTEMCHANNELFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects.
+Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small.
+This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works.
+When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters.
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FSOUND_INIT_USEDEFAULTMIDISYNTH0x0001 /* Win32 only - Causes MIDI playback to force software decoding. */ +
FSOUND_INIT_GLOBALFOCUS0x0002 /* Win32 only - For DirectSound output - sound is not muted when window is out of focus. */ +
FSOUND_INIT_ENABLESYSTEMCHANNELFX0x0004 /* Win32 only - For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! (use FSOUND_SYSTEMCHANNEL as channel id) */ +
FSOUND_INIT_ACCURATEVULEVELS0x0008 /* This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit */ +
FSOUND_INIT_PS2_DISABLECORE0REVERB0x0010 /* PS2 only - Disable reverb on CORE 0 (SPU2 voices 00-23) to regain SRAM */ +
FSOUND_INIT_PS2_DISABLECORE1REVERB0x0020 /* PS2 only - Disable reverb on CORE 1 (SPU2 voices 24-47) to regain SRAM */ +
FSOUND_INIT_PS2_SWAPDMACORES0x0040 /* PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around */ +
FSOUND_INIT_DONTLATENCYADJUST0x0080 /* Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate */ +
FSOUND_INIT_GC_INITLIBS0x0100 /* GC only - Initializes GC audio libraries */ +
FSOUND_INIT_STREAM_FROM_MAIN_THREAD0x0200 /* Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user */ +
FSOUND_INIT_PS2_USEVOLUMERAMPING0x0400 /* PS2 only - Turns on volume ramping system to remove hardware clicks. */ +
FSOUND_INIT_DSOUND_DEFERRED0x0800 /* Win32 only - For DirectSound output. 3D commands are batched together and executed at FSOUND_Update. */ +
FSOUND_INIT_DSOUND_HRTF_LIGHT0x1000 /* Win32 only - For DirectSound output. FSOUND_HW3D buffers use a slightly higher quality algorithm when 3d hardware acceleration is not present. */ +
FSOUND_INIT_DSOUND_HRTF_FULL0x2000 /* Win32 only - For DirectSound output. FSOUND_HW3D buffers use full quality 3d playback when 3d hardware acceleration is not present. */ +
FSOUND_INIT_XBOX_REMOVEHEADROOM0x4000 /* XBox only - By default directsound attenuates all sound by 6db to avoid clipping/distortion. CAUTION. If you use this flag you are responsible for the final mix to make sure clipping / distortion doesn't happen. */ +
FSOUND_INIT_PSP_SILENCEONUNDERRUN0x8000 /* PSP only - If streams skip / stutter when device is powered on, either increase stream buffersize, or use this flag instead to play silence while the UMD is recovering. */ +
+

See Also

+FSOUND_GetCurrentLevels +, +FSOUND_Init +, +FSOUND_SetBufferSize +, +FSOUND_Update +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Alloc.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Alloc.html index 08cbbf97..2abe1c15 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Alloc.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Alloc.html @@ -1,66 +1,66 @@ - - - - -FSOUND_IOP_Alloc - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_IOP_Alloc

-Allocates IOP Ram
-

-void * F_API FSOUND_IOP_Alloc(
-int length
-);
-

Parameters

- - -
lengthLength in bytes of IOP RAM to be allocated.
-
-

Return Value

-The IOP address of the data allocated. This is not directly addressable. The only way to get data to this value is to DMA it.
-FSOUND_SendData will DMA data from the EE to the IOP.
-

Remarks

-The memory allocated is taken from FMOD's memory pool using FMOD's internal memory manager.
-The pool of memory this is taken from is specified with FSOUND_SetMemorySystem.
-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_IOP_Free -, -FSOUND_SendData -, -FSOUND_SetMemorySystem -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_IOP_Alloc + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_IOP_Alloc

+Allocates IOP Ram
+

+void * F_API FSOUND_IOP_Alloc(
+int length
+);
+

Parameters

+ + +
lengthLength in bytes of IOP RAM to be allocated.
+
+

Return Value

+The IOP address of the data allocated. This is not directly addressable. The only way to get data to this value is to DMA it.
+FSOUND_SendData will DMA data from the EE to the IOP.
+

Remarks

+The memory allocated is taken from FMOD's memory pool using FMOD's internal memory manager.
+The pool of memory this is taken from is specified with FSOUND_SetMemorySystem.
+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_IOP_Free +, +FSOUND_SendData +, +FSOUND_SetMemorySystem +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Free.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Free.html index a3c21b5b..c4f5964c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Free.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IOP_Free.html @@ -1,59 +1,59 @@ - - - - -FSOUND_IOP_Free - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_IOP_Free

-Frees a block of IOP ram.
-

-void F_API FSOUND_IOP_Free(
-void *iopptr
-);
-

Parameters

- - -
dataIOP pointer to be freed. Must have been allocated with FSOUND_IOP_Alloc
-
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_IOP_Alloc -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_IOP_Free + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_IOP_Free

+Frees a block of IOP ram.
+

+void F_API FSOUND_IOP_Free(
+void *iopptr
+);
+

Parameters

+ + +
dataIOP pointer to be freed. Must have been allocated with FSOUND_IOP_Alloc
+
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_IOP_Alloc +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Init.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Init.html index efc831b4..6c4f9950 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Init.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Init.html @@ -1,128 +1,128 @@ - - - - -FSOUND_Init - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Init

-Initializes the FMOD Sound System.
-

-signed char F_API FSOUND_Init(
-int mixrate,
-int maxsoftwarechannels,
-unsigned int flags
-);
-

Parameters

- - - - -
mixrateOutput rate in hz between 4000 and 65535. Any thing outside this will cause
-the function to fail and return FALSE.
-PS2 Note. Only rates of 24000 and 48000 are supported.
-PSP Note. Only rates of 22050 and 44100 are supported.
-SmartPhone Note. Use 22050 or the operating system may crash outside of the control of fmod.
-
maxchannelsMaximum number of SOFTWARE channels available.
-The number of HARDWARE channels is autodetected. The total number of channels available (hardware and software) after initialization can be found with FSOUND_GetMaxChannels.
-Having a large number of maxchannels does not adversely affect cpu usage, but it means it has the POTENTIAL to mix a large number of channels, which can have an adverse effect on cpu usage.
-1024 is the highest number that can be set. Anything higher will return an error.
-
flagsSee FSOUND_INIT_FLAGS. Controls some global or initialization time aspects of playback.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-You do not have control over how many hardware channels are available to you. In a lot of
-cases it may be 0 (the sound card does not have the ability to supply hardware channels).
-This is why it is usually a good idea to supply FSOUND_Init with a good number of software
-channels to fall back onto, for example 32.
-Hardware channels are 3D hardware channels only. There is no benefit in supporting hardware
-for 2d playback of sound effects. With todays machines and FMOD's superior mixing routines,
-FMOD's software engine can sometimes be faster than the driver's hardware support!
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_File_SetCallbacks -, -FSOUND_GetCurrentLevels -, -FSOUND_GetDriverCaps -, -FSOUND_GetFreeHWRam -, -FSOUND_GetMaxChannels -, -FSOUND_GetMemoryStats -, -FSOUND_GetOutputHandle -, -FSOUND_GetOutputRate -, -FSOUND_Init -, -FSOUND_INIT_FLAGS -, -FSOUND_PlaySound -, -FSOUND_PlaySoundEx -, -FSOUND_SetBufferSize -, -FSOUND_SetDriver -, -FSOUND_SetHWND -, -FSOUND_SetMaxHardwareChannels -, -FSOUND_SetMemorySystem -, -FSOUND_SetMinHardwareChannels -, -FSOUND_SetMixer -, -FSOUND_SetOutput -, -FSOUND_SetSpeakerMode -, -FSOUND_SPU2_Alloc -, -FSOUND_Stream_Play -, -sceSifAddCmdHandler -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Init + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Init

+Initializes the FMOD Sound System.
+

+signed char F_API FSOUND_Init(
+int mixrate,
+int maxsoftwarechannels,
+unsigned int flags
+);
+

Parameters

+ + + + +
mixrateOutput rate in hz between 4000 and 65535. Any thing outside this will cause
+the function to fail and return FALSE.
+PS2 Note. Only rates of 24000 and 48000 are supported.
+PSP Note. Only rates of 22050 and 44100 are supported.
+SmartPhone Note. Use 22050 or the operating system may crash outside of the control of fmod.
+
maxchannelsMaximum number of SOFTWARE channels available.
+The number of HARDWARE channels is autodetected. The total number of channels available (hardware and software) after initialization can be found with FSOUND_GetMaxChannels.
+Having a large number of maxchannels does not adversely affect cpu usage, but it means it has the POTENTIAL to mix a large number of channels, which can have an adverse effect on cpu usage.
+1024 is the highest number that can be set. Anything higher will return an error.
+
flagsSee FSOUND_INIT_FLAGS. Controls some global or initialization time aspects of playback.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+You do not have control over how many hardware channels are available to you. In a lot of
+cases it may be 0 (the sound card does not have the ability to supply hardware channels).
+This is why it is usually a good idea to supply FSOUND_Init with a good number of software
+channels to fall back onto, for example 32.
+Hardware channels are 3D hardware channels only. There is no benefit in supporting hardware
+for 2d playback of sound effects. With todays machines and FMOD's superior mixing routines,
+FMOD's software engine can sometimes be faster than the driver's hardware support!
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_File_SetCallbacks +, +FSOUND_GetCurrentLevels +, +FSOUND_GetDriverCaps +, +FSOUND_GetFreeHWRam +, +FSOUND_GetMaxChannels +, +FSOUND_GetMemoryStats +, +FSOUND_GetOutputHandle +, +FSOUND_GetOutputRate +, +FSOUND_Init +, +FSOUND_INIT_FLAGS +, +FSOUND_PlaySound +, +FSOUND_PlaySoundEx +, +FSOUND_SetBufferSize +, +FSOUND_SetDriver +, +FSOUND_SetHWND +, +FSOUND_SetMaxHardwareChannels +, +FSOUND_SetMemorySystem +, +FSOUND_SetMinHardwareChannels +, +FSOUND_SetMixer +, +FSOUND_SetOutput +, +FSOUND_SetSpeakerMode +, +FSOUND_SPU2_Alloc +, +FSOUND_Stream_Play +, +sceSifAddCmdHandler +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IsPlaying.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IsPlaying.html index 2ff9d956..2fa2e5cb 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IsPlaying.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_IsPlaying.html @@ -1,58 +1,58 @@ - - - - -FSOUND_IsPlaying - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_IsPlaying

-Returns if the channel is currently playing or not.
-

-signed char F_API FSOUND_IsPlaying(
-int channel
-);
-

Parameters

- - -
channelChannel number/handle to get the playing status from.
-
-

Return Value

-TRUE channel is currently active and playing
-FALSE channel is currently idle.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_IsPlaying + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_IsPlaying

+Returns if the channel is currently playing or not.
+

+signed char F_API FSOUND_IsPlaying(
+int channel
+);
+

Parameters

+ + +
channelChannel number/handle to get the playing status from.
+
+

Return Value

+TRUE channel is currently active and playing
+FALSE channel is currently idle.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_METADATACALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_METADATACALLBACK.html index 5bcad110..e45bedf0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_METADATACALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_METADATACALLBACK.html @@ -1,65 +1,65 @@ - - - - -FSOUND_METADATACALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_METADATACALLBACK

-Callback to receive a new piece of metadata from an internet stream
-

-signed char F_CALLBACKAPI FSOUND_METADATACALLBACK(
-char *name,
-char *value,
-void *userdata
-);
-

Parameters

- - - - -
namePointer to the name of the piece of metadata (null-terminated ASCII string)
-
valuePointer to the metadata (null-terminated ASCII string)
-
userdataUserdata that was specified in FSOUND_Stream_Net_SetMetadataCallback
-
-

Return Value

-Currently ignored
-

Remarks

-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_Stream_Net_SetMetadataCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_METADATACALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_METADATACALLBACK

+Callback to receive a new piece of metadata from an internet stream
+

+signed char F_CALLBACKAPI FSOUND_METADATACALLBACK(
+char *name,
+char *value,
+void *userdata
+);
+

Parameters

+ + + + +
namePointer to the name of the piece of metadata (null-terminated ASCII string)
+
valuePointer to the metadata (null-terminated ASCII string)
+
userdataUserdata that was specified in FSOUND_Stream_Net_SetMetadataCallback
+
+

Return Value

+Currently ignored
+

Remarks

+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_Stream_Net_SetMetadataCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MISC_VALUES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MISC_VALUES.html index 7633b6fe..962c6395 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MISC_VALUES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MISC_VALUES.html @@ -1,74 +1,74 @@ - - - - -FSOUND_MISC_VALUES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_MISC_VALUES

-Miscellaneous values for FMOD functions.
-

- - - - - - - - - - - - - -
FSOUND_FREE-1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */ -
FSOUND_UNMANAGED-2 /* value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. */ -
FSOUND_ALL-3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */ -
FSOUND_STEREOPAN-1 /* value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. */ -
FSOUND_SYSTEMCHANNEL-1000 /* special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output channel */ -
FSOUND_SYSTEMSAMPLE-1000 /* special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample */ -
-

See Also

-FSOUND_PlaySound -, -FSOUND_PlaySoundEx -, -FSOUND_Sample_Alloc -, -FSOUND_Sample_Load -, -FSOUND_SetPan -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_MISC_VALUES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_MISC_VALUES

+Miscellaneous values for FMOD functions.
+

+ + + + + + + + + + + + + +
FSOUND_FREE-1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */ +
FSOUND_UNMANAGED-2 /* value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. */ +
FSOUND_ALL-3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */ +
FSOUND_STEREOPAN-1 /* value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. */ +
FSOUND_SYSTEMCHANNEL-1000 /* special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output channel */ +
FSOUND_SYSTEMSAMPLE-1000 /* special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample */ +
+

See Also

+FSOUND_PlaySound +, +FSOUND_PlaySoundEx +, +FSOUND_Sample_Alloc +, +FSOUND_Sample_Load +, +FSOUND_SetPan +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MIXERTYPES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MIXERTYPES.html index 9b40c2a5..41f366fb 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MIXERTYPES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MIXERTYPES.html @@ -1,73 +1,73 @@ - - - - -FSOUND_MIXERTYPES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_MIXERTYPES

-These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act
-upon for other reasons using FSOUND_GetMixer.
-It is not nescessary to set the mixer. FMOD will autodetect the best mixer for you.
-

-

Enumerators

- - - - - - - - - - - - -
FSOUND_MIXER_AUTODETECT/* CE/PS2/GC Only - Non interpolating/low quality mixer. */
-
FSOUND_MIXER_BLENDMODE/* Removed / obsolete. */
-
FSOUND_MIXER_MMXP5/* Removed / obsolete. */
-
FSOUND_MIXER_MMXP6/* Removed / obsolete. */
-
FSOUND_MIXER_QUALITY_AUTODETECT,/*
FSOUND_MIXER_QUALITY_FPU/* Win32/Linux only - Interpolating/volume ramping FPU mixer. */
-
FSOUND_MIXER_QUALITY_MMXP5/* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. */
-
FSOUND_MIXER_QUALITY_MMXP6/* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */
-
FSOUND_MIXER_MONO/* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/
-
FSOUND_MIXER_QUALITY_MONO/* CE/PS2/GC only - MONO Interpolating mixer. For speed */
-
FSOUND_MIXER_MAX
-

See Also

-FSOUND_GetMixer -, -FSOUND_SetMixer -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_MIXERTYPES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_MIXERTYPES

+These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act
+upon for other reasons using FSOUND_GetMixer.
+It is not nescessary to set the mixer. FMOD will autodetect the best mixer for you.
+

+

Enumerators

+ + + + + + + + + + + + +
FSOUND_MIXER_AUTODETECT/* CE/PS2/GC Only - Non interpolating/low quality mixer. */
+
FSOUND_MIXER_BLENDMODE/* Removed / obsolete. */
+
FSOUND_MIXER_MMXP5/* Removed / obsolete. */
+
FSOUND_MIXER_MMXP6/* Removed / obsolete. */
+
FSOUND_MIXER_QUALITY_AUTODETECT,/*
FSOUND_MIXER_QUALITY_FPU/* Win32/Linux only - Interpolating/volume ramping FPU mixer. */
+
FSOUND_MIXER_QUALITY_MMXP5/* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. */
+
FSOUND_MIXER_QUALITY_MMXP6/* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */
+
FSOUND_MIXER_MONO/* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/
+
FSOUND_MIXER_QUALITY_MONO/* CE/PS2/GC only - MONO Interpolating mixer. For speed */
+
FSOUND_MIXER_MAX
+

See Also

+FSOUND_GetMixer +, +FSOUND_SetMixer +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MODES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MODES.html index 2589cdb5..557d912e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MODES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_MODES.html @@ -1,172 +1,172 @@ - - - - -FSOUND_MODES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_MODES

-Sample description bitfields, OR them together for loading and describing samples.
-NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then
-trying to override the pre-defined format with a new set of format flags will not work. For
-example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just
-ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags
-you can specify that will really alter the behaviour of how it is loaded, are the following.
----------
-Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI
-Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D
-Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO
-Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX
-PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP
----------
-See flag descriptions for what these do.
-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FSOUND_LOOP_OFF0x00000001 /* For non looping samples. */ -
FSOUND_LOOP_NORMAL0x00000002 /* For forward looping samples. */ -
FSOUND_LOOP_BIDI0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */ -
FSOUND_8BITS0x00000008 /* For 8 bit samples. */ -
FSOUND_16BITS0x00000010 /* For 16 bit samples. */ -
FSOUND_MONO0x00000020 /* For mono samples. */ -
FSOUND_STEREO0x00000040 /* For stereo samples. */ -
FSOUND_UNSIGNED0x00000080 /* For user created source data containing unsigned samples. */ -
FSOUND_SIGNED0x00000100 /* For user created source data containing signed data. */ -
FSOUND_DELTA0x00000200 /* For user created source data stored as delta values. */ -
FSOUND_IT2140x00000400 /* For user created source data stored using IT214 compression. */ -
FSOUND_IT2150x00000800 /* For user created source data stored using IT215 compression. */ -
FSOUND_HW3D0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */ -
FSOUND_2D0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */ -
FSOUND_STREAMABLE0x00004000 /* For a streamimg sound where you feed the data to it. */ -
FSOUND_LOADMEMORY0x00008000 /* "name" will be interpreted as a pointer to data for streaming and samples. */ -
FSOUND_LOADRAW0x00010000 /* Will ignore file format and treat as raw pcm. */ -
FSOUND_MPEGACCURATE0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */ -
FSOUND_FORCEMONO0x00040000 /* For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams */ -
FSOUND_HW2D0x00080000 /* 2D hardware sounds. allows hardware specific effects */ -
FSOUND_ENABLEFX0x00100000 /* Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency */ -
FSOUND_MPEGHALFRATE0x00200000 /* For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution */ -
FSOUND_IMAADPCM0x00400000 /* Contents are stored compressed as IMA ADPCM */ -
FSOUND_VAG0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */ -
FSOUND_NONBLOCKING0x01000000 /* For FSOUND_Stream_Open/FMUSIC_LoadSong - Causes stream or music to open in the background and not block the foreground app. See FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState to determine when it IS ready. */ -
FSOUND_GCADPCM0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */ -
FSOUND_MULTICHANNEL0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */ -
FSOUND_USECORE00x08000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 00-23 */ -
FSOUND_USECORE10x10000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 24-47 */ -
FSOUND_LOADMEMORYIOP0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */ -
FSOUND_IGNORETAGS0x40000000 /* Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) */ -
FSOUND_STREAM_NET0x80000000 /* Specifies an internet stream */ -
FSOUND_NORMAL(FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO) -
-

See Also

-FMUSIC_GetOpenState -, -FMUSIC_LoadSong -, -FSOUND_Stream_GetLength -, -FSOUND_Stream_GetLengthMs -, -FSOUND_Stream_GetOpenState -, -FSOUND_Stream_Open -, -FSOUND_Stream_SetTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_MODES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_MODES

+Sample description bitfields, OR them together for loading and describing samples.
+NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then
+trying to override the pre-defined format with a new set of format flags will not work. For
+example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just
+ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags
+you can specify that will really alter the behaviour of how it is loaded, are the following.
+---------
+Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI
+Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D
+Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO
+Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX
+PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP
+---------
+See flag descriptions for what these do.
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FSOUND_LOOP_OFF0x00000001 /* For non looping samples. */ +
FSOUND_LOOP_NORMAL0x00000002 /* For forward looping samples. */ +
FSOUND_LOOP_BIDI0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */ +
FSOUND_8BITS0x00000008 /* For 8 bit samples. */ +
FSOUND_16BITS0x00000010 /* For 16 bit samples. */ +
FSOUND_MONO0x00000020 /* For mono samples. */ +
FSOUND_STEREO0x00000040 /* For stereo samples. */ +
FSOUND_UNSIGNED0x00000080 /* For user created source data containing unsigned samples. */ +
FSOUND_SIGNED0x00000100 /* For user created source data containing signed data. */ +
FSOUND_DELTA0x00000200 /* For user created source data stored as delta values. */ +
FSOUND_IT2140x00000400 /* For user created source data stored using IT214 compression. */ +
FSOUND_IT2150x00000800 /* For user created source data stored using IT215 compression. */ +
FSOUND_HW3D0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */ +
FSOUND_2D0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */ +
FSOUND_STREAMABLE0x00004000 /* For a streamimg sound where you feed the data to it. */ +
FSOUND_LOADMEMORY0x00008000 /* "name" will be interpreted as a pointer to data for streaming and samples. */ +
FSOUND_LOADRAW0x00010000 /* Will ignore file format and treat as raw pcm. */ +
FSOUND_MPEGACCURATE0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */ +
FSOUND_FORCEMONO0x00040000 /* For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams */ +
FSOUND_HW2D0x00080000 /* 2D hardware sounds. allows hardware specific effects */ +
FSOUND_ENABLEFX0x00100000 /* Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency */ +
FSOUND_MPEGHALFRATE0x00200000 /* For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution */ +
FSOUND_IMAADPCM0x00400000 /* Contents are stored compressed as IMA ADPCM */ +
FSOUND_VAG0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */ +
FSOUND_NONBLOCKING0x01000000 /* For FSOUND_Stream_Open/FMUSIC_LoadSong - Causes stream or music to open in the background and not block the foreground app. See FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState to determine when it IS ready. */ +
FSOUND_GCADPCM0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */ +
FSOUND_MULTICHANNEL0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */ +
FSOUND_USECORE00x08000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 00-23 */ +
FSOUND_USECORE10x10000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 24-47 */ +
FSOUND_LOADMEMORYIOP0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */ +
FSOUND_IGNORETAGS0x40000000 /* Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) */ +
FSOUND_STREAM_NET0x80000000 /* Specifies an internet stream */ +
FSOUND_NORMAL(FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO) +
+

See Also

+FMUSIC_GetOpenState +, +FMUSIC_LoadSong +, +FSOUND_Stream_GetLength +, +FSOUND_Stream_GetLengthMs +, +FSOUND_Stream_GetOpenState +, +FSOUND_Stream_Open +, +FSOUND_Stream_SetTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OPENCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OPENCALLBACK.html index 040ade3d..3d245e3f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OPENCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OPENCALLBACK.html @@ -1,71 +1,71 @@ - - - - -FSOUND_OPENCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_OPENCALLBACK

-Callback for opening a file.
-

-void * F_CALLBACKAPI FSOUND_OPENCALLBACK(
-const char *name
-);
-

Parameters

- - -
nameThis is the filename. You may treat this as you like.
-
-

Return Value

-On success, return a non 0 number.
-On failure, return 0.
-

Remarks

-You MUST open the file and return a handle for future file function calls. Cast the handle to an unsigned int when returning it, then in other callbacks, cast it back from the unsigned int back to your own handle type.
-Return 0 signifies an open error. This is very important.
-It is a good idea if you are using memory based file routines, to store the size of the file here, as it is needed to support SEEK_END in the seek function, described below.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_CLOSECALLBACK -, -FSOUND_File_SetCallbacks -, -FSOUND_READCALLBACK -, -FSOUND_SEEKCALLBACK -, -FSOUND_TELLCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:30 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_OPENCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_OPENCALLBACK

+Callback for opening a file.
+

+void * F_CALLBACKAPI FSOUND_OPENCALLBACK(
+const char *name
+);
+

Parameters

+ + +
nameThis is the filename. You may treat this as you like.
+
+

Return Value

+On success, return a non 0 number.
+On failure, return 0.
+

Remarks

+You MUST open the file and return a handle for future file function calls. Cast the handle to an unsigned int when returning it, then in other callbacks, cast it back from the unsigned int back to your own handle type.
+Return 0 signifies an open error. This is very important.
+It is a good idea if you are using memory based file routines, to store the size of the file here, as it is needed to support SEEK_END in the seek function, described below.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_CLOSECALLBACK +, +FSOUND_File_SetCallbacks +, +FSOUND_READCALLBACK +, +FSOUND_SEEKCALLBACK +, +FSOUND_TELLCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:30 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OUTPUTTYPES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OUTPUTTYPES.html index 3ec110f5..495ccd5a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OUTPUTTYPES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_OUTPUTTYPES.html @@ -1,84 +1,84 @@ - - - - -FSOUND_OUTPUTTYPES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_OUTPUTTYPES

-These output types are used with FSOUND_SetOutput, to choose which output driver to use.
-FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver
-does not support DirectX 6 Voice Manager Extensions.
-FSOUND_OUTPUT_WINMM is recommended for NT and CE.
-

-

Enumerators

- - - - - - - - - - - - - - - -
FSOUND_OUTPUT_NOSOUND/* NoSound driver, all calls to this succeed but do nothing. */
-
FSOUND_OUTPUT_WINMM/* Windows Multimedia driver. */
-
FSOUND_OUTPUT_DSOUND/* DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. */
-
FSOUND_OUTPUT_A3D/* A3D driver. */
-
FSOUND_OUTPUT_OSS/* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */
-
FSOUND_OUTPUT_ESD/* Linux/Unix ESD (Enlightment Sound Daemon) driver. */
-
FSOUND_OUTPUT_ALSA/* Linux Alsa driver. */
-
FSOUND_OUTPUT_ASIO/* Low latency ASIO driver */
-
FSOUND_OUTPUT_XBOX/* Xbox driver */
-
FSOUND_OUTPUT_PS2/* PlayStation 2 driver */
-
FSOUND_OUTPUT_MAC/* Mac SoundManager driver */
-
FSOUND_OUTPUT_GC/* Gamecube driver */
-
FSOUND_OUTPUT_PSP/* PlayStation Portable driver */
-
FSOUND_OUTPUT_NOSOUND_NONREALTIME/* This is the same as nosound, but the sound generation is driven by FSOUND_Update */
-
-

See Also

-FSOUND_GetOutput -, -FSOUND_SetOutput -, -FSOUND_Update -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_OUTPUTTYPES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_OUTPUTTYPES

+These output types are used with FSOUND_SetOutput, to choose which output driver to use.
+FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver
+does not support DirectX 6 Voice Manager Extensions.
+FSOUND_OUTPUT_WINMM is recommended for NT and CE.
+

+

Enumerators

+ + + + + + + + + + + + + + + +
FSOUND_OUTPUT_NOSOUND/* NoSound driver, all calls to this succeed but do nothing. */
+
FSOUND_OUTPUT_WINMM/* Windows Multimedia driver. */
+
FSOUND_OUTPUT_DSOUND/* DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. */
+
FSOUND_OUTPUT_A3D/* A3D driver. */
+
FSOUND_OUTPUT_OSS/* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */
+
FSOUND_OUTPUT_ESD/* Linux/Unix ESD (Enlightment Sound Daemon) driver. */
+
FSOUND_OUTPUT_ALSA/* Linux Alsa driver. */
+
FSOUND_OUTPUT_ASIO/* Low latency ASIO driver */
+
FSOUND_OUTPUT_XBOX/* Xbox driver */
+
FSOUND_OUTPUT_PS2/* PlayStation 2 driver */
+
FSOUND_OUTPUT_MAC/* Mac SoundManager driver */
+
FSOUND_OUTPUT_GC/* Gamecube driver */
+
FSOUND_OUTPUT_PSP/* PlayStation Portable driver */
+
FSOUND_OUTPUT_NOSOUND_NONREALTIME/* This is the same as nosound, but the sound generation is driven by FSOUND_Update */
+
+

See Also

+FSOUND_GetOutput +, +FSOUND_SetOutput +, +FSOUND_Update +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySound.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySound.html index f2710f99..05b58472 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySound.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySound.html @@ -1,108 +1,108 @@ - - - - -FSOUND_PlaySound - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_PlaySound

-Plays a sample in a specified channel, using the sample's default frequency, volume
-and pan settings.
-

-int F_API FSOUND_PlaySound(
-int channel,
-FSOUND_SAMPLE *sptr
-);
-

Parameters

- - - -
channel0+
-The absolute channel number in the channel pool.
-Remember software channels come first, followed by hardware channels.
-You cannot play a software sample on a hardware channel and vice versa.
-FSOUND_FREE
-Chooses a free channel to play in. If all channels are used then it
-selects a channel with a sample playing that has an EQUAL or LOWER priority
-than the sample to be played.
-FSOUND_ALL
-Passing this will cause ALL channels to play. (note this will make things
-VERY noisy!)
-If FSOUND_ALL is used the last channel success flag will be returned.
-
sptrPointer to the sample to be played.
-
-

Return Value

-On success, the channel handle that was selected is returned.
-On failure, -1 is returned.
-

Remarks

-If you play a FSOUND_HW3D declared sample with this function, then the position and velocity
-are set to those of the listener. Other attributes such as volume, frequency and pan are taken
-from the sample's default volume, frequency, pan etc.
-----------
-The channel handle :
-The return value is reference counted. This stops the user from updating a stolen channel.
-Basically it means the only sound you can change the attributes (ie volume/pan/frequency/3d position) for are the one you specifically called playsound for. If another sound steals that channel, and you keep trying to change its attributes (ie volume/pan/frequency/3d position), it will do nothing.
-This is great if you have sounds being updated from tasks and you just forget about it.
-You can keep updating the sound attributes and if another task steals that channel, your original task wont change the attributes of the new sound!!!
-The lower 12 bits contain the channel number. (yes this means a 4096 channel limit for FMOD :)
-The upper 19 bits contain the reference count.
-The top 1 bit is the sign bit.
-ie
-S RRRRRRRRRRRRRRRRRRR CCCCCCCCCCCC
-----------
-Remember if not using FSOUND_FREE, then the channel pool is split up into software and hardware channels.
-Software channels occupy the first n indicies specified by the value passed into FSOUND_Init.
-Hardware channels occupy the next n indicies after this, and can be a variable amount, depending on the hardware.
-Use FSOUND_GetNumHardwareChannels to query how many channels are available in hardware.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_FX_Enable -, -FSOUND_GetNumHardwareChannels -, -FSOUND_GetNumSubChannels -, -FSOUND_GetSubChannel -, -FSOUND_Init -, -FSOUND_PlaySoundEx -, -FSOUND_Sample_SetMaxPlaybacks -, -FSOUND_StopSound -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_PlaySound + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_PlaySound

+Plays a sample in a specified channel, using the sample's default frequency, volume
+and pan settings.
+

+int F_API FSOUND_PlaySound(
+int channel,
+FSOUND_SAMPLE *sptr
+);
+

Parameters

+ + + +
channel0+
+The absolute channel number in the channel pool.
+Remember software channels come first, followed by hardware channels.
+You cannot play a software sample on a hardware channel and vice versa.
+FSOUND_FREE
+Chooses a free channel to play in. If all channels are used then it
+selects a channel with a sample playing that has an EQUAL or LOWER priority
+than the sample to be played.
+FSOUND_ALL
+Passing this will cause ALL channels to play. (note this will make things
+VERY noisy!)
+If FSOUND_ALL is used the last channel success flag will be returned.
+
sptrPointer to the sample to be played.
+
+

Return Value

+On success, the channel handle that was selected is returned.
+On failure, -1 is returned.
+

Remarks

+If you play a FSOUND_HW3D declared sample with this function, then the position and velocity
+are set to those of the listener. Other attributes such as volume, frequency and pan are taken
+from the sample's default volume, frequency, pan etc.
+----------
+The channel handle :
+The return value is reference counted. This stops the user from updating a stolen channel.
+Basically it means the only sound you can change the attributes (ie volume/pan/frequency/3d position) for are the one you specifically called playsound for. If another sound steals that channel, and you keep trying to change its attributes (ie volume/pan/frequency/3d position), it will do nothing.
+This is great if you have sounds being updated from tasks and you just forget about it.
+You can keep updating the sound attributes and if another task steals that channel, your original task wont change the attributes of the new sound!!!
+The lower 12 bits contain the channel number. (yes this means a 4096 channel limit for FMOD :)
+The upper 19 bits contain the reference count.
+The top 1 bit is the sign bit.
+ie
+S RRRRRRRRRRRRRRRRRRR CCCCCCCCCCCC
+----------
+Remember if not using FSOUND_FREE, then the channel pool is split up into software and hardware channels.
+Software channels occupy the first n indicies specified by the value passed into FSOUND_Init.
+Hardware channels occupy the next n indicies after this, and can be a variable amount, depending on the hardware.
+Use FSOUND_GetNumHardwareChannels to query how many channels are available in hardware.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_FX_Enable +, +FSOUND_GetNumHardwareChannels +, +FSOUND_GetNumSubChannels +, +FSOUND_GetSubChannel +, +FSOUND_Init +, +FSOUND_PlaySoundEx +, +FSOUND_Sample_SetMaxPlaybacks +, +FSOUND_StopSound +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySoundEx.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySoundEx.html index e57cfe34..ef78d68e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySoundEx.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_PlaySoundEx.html @@ -1,120 +1,120 @@ - - - - -FSOUND_PlaySoundEx - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_PlaySoundEx

-Extended featured version of FSOUND_PlaySound.
-New functionality includes the ability to start the sound paused.
-This allows attributes of a channel to be set freely before the sound actually starts playing, until FSOUND_SetPaused(FALSE) is used.
-Also added is the ability to associate the channel to a specified DSP unit. This allows the user to 'group' channels into seperate DSP units, which allows effects to be inserted between these 'groups', and allow various things like having one group affected by reverb (wet mix) and another group of channels unaffected (dry).
-This is useful to seperate things like music from being affected by DSP effects, while other sound effects are.
-

-int F_API FSOUND_PlaySoundEx(
-int channel,
-FSOUND_SAMPLE *sptr,
-FSOUND_DSPUNIT *dspunit,
-signed char startpaused
-);
-

Parameters

- - - - - -
channel0+
-The absolute channel number in the channel pool.
-Remember software channels come first, followed by hardware channels.
-You cannot play a software sample on a hardware channel and vice versa.
-FSOUND_FREE
-Chooses a free channel to play in. If all channels are used then it
-selects a channel with a sample playing that has an EQUAL or LOWER priority
-than the sample to be played.
-FSOUND_ALL
-Plays the sound on all channels.
-
sptrPointer to the sample to be played.
-
dspunitOptional. NULL by default. Pointer to a dsp unit to attach the channel to for channel grouping. Only attach a sound to a user created DSP unit, and not a system DSP unit.
-
pausedStart the sound paused or not. Pausing the sound allows attributes to be set before the sound starts.
-
-

Return Value

-On success, the channel handle that was selected is returned.
-On failure, -1 is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will cause ALL channels to play. (note this could make things VERY noisy!)
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-----------
-The channel handle :
-The return value is reference counted. This stops the user from updating a stolen channel.
-This means the only sound you can change the attributes (ie volume/pan/frequency/3d position) for are the
-one you specifically called playsound for. If another sound steals that channel, and you keep trying to
-change its attributes (ie volume/pan/frequency/3d position), it will do nothing.
-This is great if you have sounds being updated from tasks and you just forget about it.
-You can keep updating the sound attributes and if another task steals that channel, your original task
-wont change the attributes of the new sound!!!
-The lower 12 bits contain the channel number. (yes this means a 4096 channel limit for FMOD :)
-The upper 19 bits contain the reference count.
-The top 1 bit is the sign bit.
-ie
-S RRRRRRRRRRRRRRRRRRR CCCCCCCCCCCC
-----------
-Remember if not using FSOUND_FREE, then the channel pool is split up into software and hardware channels.
-Software channels occupy the first n indicies specified by the value passed into FSOUND_Init.
-Hardware channels occupy the next n indicies after this, and can be a variable amount, depending on the hardware.
-Use FSOUND_GetNumHardwareChannels to query how many channels are available in hardware.
-----------
-If you attach a sound to a DSP unit (for grouping purposes), the callback for the DSP unit will be overwritten with fmod's internal mixer callback, so the callback the user supplied is rendered obsolete and is not called.
-Also, do not attach sounds to system DSP units, the assignment will be ignored if you do.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_FX_Enable -, -FSOUND_GetNumSubChannels -, -FSOUND_GetSubChannel -, -FSOUND_Init -, -FSOUND_PlaySound -, -FSOUND_SetPaused -, -FSOUND_StopSound -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_PlaySoundEx + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_PlaySoundEx

+Extended featured version of FSOUND_PlaySound.
+New functionality includes the ability to start the sound paused.
+This allows attributes of a channel to be set freely before the sound actually starts playing, until FSOUND_SetPaused(FALSE) is used.
+Also added is the ability to associate the channel to a specified DSP unit. This allows the user to 'group' channels into seperate DSP units, which allows effects to be inserted between these 'groups', and allow various things like having one group affected by reverb (wet mix) and another group of channels unaffected (dry).
+This is useful to seperate things like music from being affected by DSP effects, while other sound effects are.
+

+int F_API FSOUND_PlaySoundEx(
+int channel,
+FSOUND_SAMPLE *sptr,
+FSOUND_DSPUNIT *dspunit,
+signed char startpaused
+);
+

Parameters

+ + + + + +
channel0+
+The absolute channel number in the channel pool.
+Remember software channels come first, followed by hardware channels.
+You cannot play a software sample on a hardware channel and vice versa.
+FSOUND_FREE
+Chooses a free channel to play in. If all channels are used then it
+selects a channel with a sample playing that has an EQUAL or LOWER priority
+than the sample to be played.
+FSOUND_ALL
+Plays the sound on all channels.
+
sptrPointer to the sample to be played.
+
dspunitOptional. NULL by default. Pointer to a dsp unit to attach the channel to for channel grouping. Only attach a sound to a user created DSP unit, and not a system DSP unit.
+
pausedStart the sound paused or not. Pausing the sound allows attributes to be set before the sound starts.
+
+

Return Value

+On success, the channel handle that was selected is returned.
+On failure, -1 is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will cause ALL channels to play. (note this could make things VERY noisy!)
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+----------
+The channel handle :
+The return value is reference counted. This stops the user from updating a stolen channel.
+This means the only sound you can change the attributes (ie volume/pan/frequency/3d position) for are the
+one you specifically called playsound for. If another sound steals that channel, and you keep trying to
+change its attributes (ie volume/pan/frequency/3d position), it will do nothing.
+This is great if you have sounds being updated from tasks and you just forget about it.
+You can keep updating the sound attributes and if another task steals that channel, your original task
+wont change the attributes of the new sound!!!
+The lower 12 bits contain the channel number. (yes this means a 4096 channel limit for FMOD :)
+The upper 19 bits contain the reference count.
+The top 1 bit is the sign bit.
+ie
+S RRRRRRRRRRRRRRRRRRR CCCCCCCCCCCC
+----------
+Remember if not using FSOUND_FREE, then the channel pool is split up into software and hardware channels.
+Software channels occupy the first n indicies specified by the value passed into FSOUND_Init.
+Hardware channels occupy the next n indicies after this, and can be a variable amount, depending on the hardware.
+Use FSOUND_GetNumHardwareChannels to query how many channels are available in hardware.
+----------
+If you attach a sound to a DSP unit (for grouping purposes), the callback for the DSP unit will be overwritten with fmod's internal mixer callback, so the callback the user supplied is rendered obsolete and is not called.
+Also, do not attach sounds to system DSP units, the assignment will be ignored if you do.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_FX_Enable +, +FSOUND_GetNumSubChannels +, +FSOUND_GetSubChannel +, +FSOUND_Init +, +FSOUND_PlaySound +, +FSOUND_SetPaused +, +FSOUND_StopSound +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_READCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_READCALLBACK.html index 5b881f24..f8f7ad1f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_READCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_READCALLBACK.html @@ -1,74 +1,74 @@ - - - - -FSOUND_READCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_READCALLBACK

-Callback for reading from a file.
-

-int F_CALLBACKAPI FSOUND_READCALLBACK(
-void *buffer,
-int size,
-void *handle
-);
-

Parameters

- - - - -
bufferYou must read and copy your file data into this pointer.
-
lengthYou must read this many bytes from your file data.
-
handleThis is the handle you returned from the open callback to use for your own file routines.
-
-

Return Value

-Return the number of bytes that were *successfully* read here. Normally this is just the same as 'length', but if you are at the end of the file, you will probably only read successfully the number of bytes up to the end of the file (if you tried to read more than that).
-

Remarks

-You must read 'length' number of bytes into the 'buffer' provided, then if you need to, increment your file pointer.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_CLOSECALLBACK -, -FSOUND_File_SetCallbacks -, -FSOUND_OPENCALLBACK -, -FSOUND_SEEKCALLBACK -, -FSOUND_TELLCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_READCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_READCALLBACK

+Callback for reading from a file.
+

+int F_CALLBACKAPI FSOUND_READCALLBACK(
+void *buffer,
+int size,
+void *handle
+);
+

Parameters

+ + + + +
bufferYou must read and copy your file data into this pointer.
+
lengthYou must read this many bytes from your file data.
+
handleThis is the handle you returned from the open callback to use for your own file routines.
+
+

Return Value

+Return the number of bytes that were *successfully* read here. Normally this is just the same as 'length', but if you are at the end of the file, you will probably only read successfully the number of bytes up to the end of the file (if you tried to read more than that).
+

Remarks

+You must read 'length' number of bytes into the 'buffer' provided, then if you need to, increment your file pointer.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_CLOSECALLBACK +, +FSOUND_File_SetCallbacks +, +FSOUND_OPENCALLBACK +, +FSOUND_SEEKCALLBACK +, +FSOUND_TELLCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REALLOCCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REALLOCCALLBACK.html index 92452dfa..28a65fb2 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REALLOCCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REALLOCCALLBACK.html @@ -1,70 +1,70 @@ - - - - -FSOUND_REALLOCCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_REALLOCCALLBACK

-Callback to re-allocate a block of memory to a different size.
-

-void * F_CALLBACKAPI FSOUND_REALLOCCALLBACK(
-void *ptr,
-unsigned int size
-);
-

Parameters

- - - -
ptrPointer to a block of memory to be resized. If this is NULL then a new block of memory is simply allocated.
-
sizeSize of the memory to be reallocated. The original memory must be preserved.
-
-

Return Value

-On success, a pointer to the newly re-allocated block of memory is returned.
-On failure, NULL is returned.
-

Remarks

-Returning an aligned pointer, of 16 byte alignment is recommended for speed purposes.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_ALLOCCALLBACK -, -FSOUND_FREECALLBACK -, -FSOUND_GetMemoryStats -, -FSOUND_SetMemorySystem -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_REALLOCCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_REALLOCCALLBACK

+Callback to re-allocate a block of memory to a different size.
+

+void * F_CALLBACKAPI FSOUND_REALLOCCALLBACK(
+void *ptr,
+unsigned int size
+);
+

Parameters

+ + + +
ptrPointer to a block of memory to be resized. If this is NULL then a new block of memory is simply allocated.
+
sizeSize of the memory to be reallocated. The original memory must be preserved.
+
+

Return Value

+On success, a pointer to the newly re-allocated block of memory is returned.
+On failure, NULL is returned.
+

Remarks

+Returning an aligned pointer, of 16 byte alignment is recommended for speed purposes.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_ALLOCCALLBACK +, +FSOUND_FREECALLBACK +, +FSOUND_GetMemoryStats +, +FSOUND_SetMemorySystem +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELFLAGS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELFLAGS.html index b9a06240..3a69616e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELFLAGS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELFLAGS.html @@ -1,64 +1,64 @@ - - - - -FSOUND_REVERB_CHANNELFLAGS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_REVERB_CHANNELFLAGS

-Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure.
-

- - - - - - - - - - - -
FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO0x00000001 /* Automatic setting of 'Direct' due to distance from listener */ -
FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO0x00000002 /* Automatic setting of 'Room' due to distance from listener */ -
FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */ -
FSOUND_REVERB_CHANNELFLAGS_DEFAULT(FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO |
FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO|
FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO) -
-

See Also

-FSOUND_REVERB_CHANNELFLAGS -, -FSOUND_REVERB_CHANNELPROPERTIES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_REVERB_CHANNELFLAGS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_REVERB_CHANNELFLAGS

+Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure.
+

+ + + + + + + + + + + +
FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO0x00000001 /* Automatic setting of 'Direct' due to distance from listener */ +
FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO0x00000002 /* Automatic setting of 'Room' due to distance from listener */ +
FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */ +
FSOUND_REVERB_CHANNELFLAGS_DEFAULT(FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO |
FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO|
FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO) +
+

See Also

+FSOUND_REVERB_CHANNELFLAGS +, +FSOUND_REVERB_CHANNELPROPERTIES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELPROPERTIES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELPROPERTIES.html index 3adf7c4f..2cc20672 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELPROPERTIES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_CHANNELPROPERTIES.html @@ -1,122 +1,122 @@ - - - - -FSOUND_REVERB_CHANNELPROPERTIES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Structure]
-

FSOUND_REVERB_CHANNELPROPERTIES

-Structure defining the properties for a reverb source, related to a FSOUND channel.
-For more indepth descriptions of the reverb properties under win32, please see the EAX3
-documentation at http://developer.creative.com/ under the 'downloads' section.
-If they do not have the EAX3 documentation, then most information can be attained from
-the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of
-EAX2.
-Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset.
-Note that integer values that typically range from -10,000 to 1000 are represented in
-decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
-PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox).
-Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then
-the reverb should product a similar effect on either platform.
-Linux and FMODCE do not support the reverb api.
-The numerical values listed below are the maximum, minimum and default values for each variable respectively.
-

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
intDirect/* -10000, 1000, 0, direct path level (at low and mid frequencies) (WIN32/XBOX) */
-
intDirectHF/* -10000, 0, 0, relative direct path level at high frequencies (WIN32/XBOX) */
-
intRoom/* -10000, 1000, 0, room effect level (at low and mid frequencies) (WIN32/XBOX/PS2) */
-
intRoomHF/* -10000, 0, 0, relative room effect level at high frequencies (WIN32/XBOX) */
-
intObstruction/* -10000, 0, 0, main obstruction control (attenuation at high frequencies) (WIN32/XBOX) */
-
floatObstructionLFRatio/* 0.0, 1.0, 0.0, obstruction low-frequency level re. main control (WIN32/XBOX) */
-
intOcclusion/* -10000, 0, 0, main occlusion control (attenuation at high frequencies) (WIN32/XBOX) */
-
floatOcclusionLFRatio/* 0.0, 1.0, 0.25, occlusion low-frequency level re. main control (WIN32/XBOX) */
-
floatOcclusionRoomRatio/* 0.0, 10.0, 1.5, relative occlusion control for room effect (WIN32) */
-
floatOcclusionDirectRatio/* 0.0, 10.0, 1.0, relative occlusion control for direct path (WIN32) */
-
intExclusion/* -10000, 0, 0, main exlusion control (attenuation at high frequencies) (WIN32) */
-
floatExclusionLFRatio/* 0.0, 1.0, 1.0, exclusion low-frequency level re. main control (WIN32) */
-
intOutsideVolumeHF/* -10000, 0, 0, outside sound cone level at high frequencies (WIN32) */
-
floatDopplerFactor/* 0.0, 10.0, 0.0, like DS3D flDopplerFactor but per source (WIN32) */
-
floatRolloffFactor/* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but per source (WIN32) */
-
floatRoomRolloffFactor/* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but for room effect (WIN32/XBOX) */
-
floatAirAbsorptionFactor/* 0.0, 10.0, 1.0, multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (WIN32) */
-
intFlags/* FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (WIN32) */
-
-

See Also

-FSOUND_REVERB_CHANNELFLAGS -, -FSOUND_Reverb_GetChannelProperties -, -FSOUND_REVERB_PROPERTIES -, -FSOUND_Reverb_SetChannelProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_REVERB_CHANNELPROPERTIES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Structure]
+

FSOUND_REVERB_CHANNELPROPERTIES

+Structure defining the properties for a reverb source, related to a FSOUND channel.
+For more indepth descriptions of the reverb properties under win32, please see the EAX3
+documentation at http://developer.creative.com/ under the 'downloads' section.
+If they do not have the EAX3 documentation, then most information can be attained from
+the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of
+EAX2.
+Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset.
+Note that integer values that typically range from -10,000 to 1000 are represented in
+decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
+PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox).
+Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then
+the reverb should product a similar effect on either platform.
+Linux and FMODCE do not support the reverb api.
+The numerical values listed below are the maximum, minimum and default values for each variable respectively.
+

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
intDirect/* -10000, 1000, 0, direct path level (at low and mid frequencies) (WIN32/XBOX) */
+
intDirectHF/* -10000, 0, 0, relative direct path level at high frequencies (WIN32/XBOX) */
+
intRoom/* -10000, 1000, 0, room effect level (at low and mid frequencies) (WIN32/XBOX/PS2) */
+
intRoomHF/* -10000, 0, 0, relative room effect level at high frequencies (WIN32/XBOX) */
+
intObstruction/* -10000, 0, 0, main obstruction control (attenuation at high frequencies) (WIN32/XBOX) */
+
floatObstructionLFRatio/* 0.0, 1.0, 0.0, obstruction low-frequency level re. main control (WIN32/XBOX) */
+
intOcclusion/* -10000, 0, 0, main occlusion control (attenuation at high frequencies) (WIN32/XBOX) */
+
floatOcclusionLFRatio/* 0.0, 1.0, 0.25, occlusion low-frequency level re. main control (WIN32/XBOX) */
+
floatOcclusionRoomRatio/* 0.0, 10.0, 1.5, relative occlusion control for room effect (WIN32) */
+
floatOcclusionDirectRatio/* 0.0, 10.0, 1.0, relative occlusion control for direct path (WIN32) */
+
intExclusion/* -10000, 0, 0, main exlusion control (attenuation at high frequencies) (WIN32) */
+
floatExclusionLFRatio/* 0.0, 1.0, 1.0, exclusion low-frequency level re. main control (WIN32) */
+
intOutsideVolumeHF/* -10000, 0, 0, outside sound cone level at high frequencies (WIN32) */
+
floatDopplerFactor/* 0.0, 10.0, 0.0, like DS3D flDopplerFactor but per source (WIN32) */
+
floatRolloffFactor/* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but per source (WIN32) */
+
floatRoomRolloffFactor/* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but for room effect (WIN32/XBOX) */
+
floatAirAbsorptionFactor/* 0.0, 10.0, 1.0, multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (WIN32) */
+
intFlags/* FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (WIN32) */
+
+

See Also

+FSOUND_REVERB_CHANNELFLAGS +, +FSOUND_Reverb_GetChannelProperties +, +FSOUND_REVERB_PROPERTIES +, +FSOUND_Reverb_SetChannelProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_FLAGS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_FLAGS.html index 89e4dbc6..84b97cee 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_FLAGS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_FLAGS.html @@ -1,90 +1,90 @@ - - - - -FSOUND_REVERB_FLAGS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_REVERB_FLAGS

-Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure.
-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FSOUND_REVERB_FLAGS_DECAYTIMESCALE0x00000001 /* 'EnvSize' affects reverberation decay time */ -
FSOUND_REVERB_FLAGS_REFLECTIONSSCALE0x00000002 /* 'EnvSize' affects reflection level */ -
FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE0x00000004 /* 'EnvSize' affects initial reflection delay time */ -
FSOUND_REVERB_FLAGS_REVERBSCALE0x00000008 /* 'EnvSize' affects reflections level */ -
FSOUND_REVERB_FLAGS_REVERBDELAYSCALE0x00000010 /* 'EnvSize' affects late reverberation delay time */ -
FSOUND_REVERB_FLAGS_DECAYHFLIMIT0x00000020 /* AirAbsorptionHF affects DecayHFRatio */ -
FSOUND_REVERB_FLAGS_ECHOTIMESCALE0x00000040 /* 'EnvSize' affects echo time */ -
FSOUND_REVERB_FLAGS_MODULATIONTIMESCALE0x00000080 /* 'EnvSize' affects modulation time */ -
FSOUND_REVERB_FLAGS_CORE00x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */ -
FSOUND_REVERB_FLAGS_CORE10x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */ -
FSOUND_REVERB_FLAGS_DEFAULT(FSOUND_REVERB_FLAGS_DECAYTIMESCALE |
FSOUND_REVERB_FLAGS_REFLECTIONSSCALE |
FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE |
FSOUND_REVERB_FLAGS_REVERBSCALE |
FSOUND_REVERB_FLAGS_REVERBDELAYSCALE |
FSOUND_REVERB_FLAGS_DECAYHFLIMIT |
FSOUND_REVERB_FLAGS_CORE0 |
FSOUND_REVERB_FLAGS_CORE1 ) -
-

See Also

-FSOUND_REVERB_FLAGS -, -FSOUND_REVERB_PROPERTIES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_REVERB_FLAGS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_REVERB_FLAGS

+Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure.
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FSOUND_REVERB_FLAGS_DECAYTIMESCALE0x00000001 /* 'EnvSize' affects reverberation decay time */ +
FSOUND_REVERB_FLAGS_REFLECTIONSSCALE0x00000002 /* 'EnvSize' affects reflection level */ +
FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE0x00000004 /* 'EnvSize' affects initial reflection delay time */ +
FSOUND_REVERB_FLAGS_REVERBSCALE0x00000008 /* 'EnvSize' affects reflections level */ +
FSOUND_REVERB_FLAGS_REVERBDELAYSCALE0x00000010 /* 'EnvSize' affects late reverberation delay time */ +
FSOUND_REVERB_FLAGS_DECAYHFLIMIT0x00000020 /* AirAbsorptionHF affects DecayHFRatio */ +
FSOUND_REVERB_FLAGS_ECHOTIMESCALE0x00000040 /* 'EnvSize' affects echo time */ +
FSOUND_REVERB_FLAGS_MODULATIONTIMESCALE0x00000080 /* 'EnvSize' affects modulation time */ +
FSOUND_REVERB_FLAGS_CORE00x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */ +
FSOUND_REVERB_FLAGS_CORE10x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */ +
FSOUND_REVERB_FLAGS_DEFAULT(FSOUND_REVERB_FLAGS_DECAYTIMESCALE |
FSOUND_REVERB_FLAGS_REFLECTIONSSCALE |
FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE |
FSOUND_REVERB_FLAGS_REVERBSCALE |
FSOUND_REVERB_FLAGS_REVERBDELAYSCALE |
FSOUND_REVERB_FLAGS_DECAYHFLIMIT |
FSOUND_REVERB_FLAGS_CORE0 |
FSOUND_REVERB_FLAGS_CORE1 ) +
+

See Also

+FSOUND_REVERB_FLAGS +, +FSOUND_REVERB_PROPERTIES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PRESETS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PRESETS.html index 3e6456a6..35602734 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PRESETS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PRESETS.html @@ -1,161 +1,161 @@ - - - - -FSOUND_REVERB_PRESETS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_REVERB_PRESETS

-A set of predefined environment PARAMETERS, created by Creative Labs
-These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically.
-ie
-FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC;
-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FSOUND_PRESET_OFF{0, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x33f } -
FSOUND_PRESET_GENERIC{0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_PADDEDCELL{1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, { 0.0f,0.0f,0.0f }, 207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_ROOM{2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, { 0.0f,0.0f,0.0f }, 53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_BATHROOM{3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, { 0.0f,0.0f,0.0f }, 1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f } -
FSOUND_PRESET_LIVINGROOM{4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_STONEROOM{5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, { 0.0f,0.0f,0.0f }, 83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_AUDITORIUM{6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, { 0.0f,0.0f,0.0f }, -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_CONCERTHALL{7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, { 0.0f,0.0f,0.0f }, -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_CAVE{8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, { 0.0f,0.0f,0.0f }, -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -
FSOUND_PRESET_ARENA{9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, { 0.0f,0.0f,0.0f }, 16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_HANGAR{10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, { 0.0f,0.0f,0.0f }, 198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_CARPETTEDHALLWAY{11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_HALLWAY{12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, { 0.0f,0.0f,0.0f }, 441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_STONECORRIDOR{13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, { 0.0f,0.0f,0.0f }, 395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_ALLEY{14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, { 0.0f,0.0f,0.0f }, -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_FOREST{15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, { 0.0f,0.0f,0.0f }, -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f } -
FSOUND_PRESET_CITY{16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f } -
FSOUND_PRESET_MOUNTAINS{17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f } -
FSOUND_PRESET_QUARRY{18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f }, 500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_PLAIN{19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f } -
FSOUND_PRESET_PARKINGLOT{20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -
FSOUND_PRESET_SEWERPIPE{21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, { 0.0f,0.0f,0.0f }, 1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f } -
FSOUND_PRESET_UNDERWATER{22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, { 0.0f,0.0f,0.0f }, 1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } -
FSOUND_PRESET_DRUGGED{23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, { 0.0f,0.0f,0.0f }, 985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -
FSOUND_PRESET_DIZZY{24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, { 0.0f,0.0f,0.0f }, -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -
FSOUND_PRESET_PSYCHOTIC{25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, { 0.0f,0.0f,0.0f }, 774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } -
FSOUND_PRESET_PS2_ROOM{1, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_STUDIO_A{2, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_STUDIO_B{3, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_STUDIO_C{4, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_HALL{5, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_SPACE{6, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_ECHO{7, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_DELAY{8, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
FSOUND_PRESET_PS2_PIPE{9, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } -
-

See Also

-FSOUND_REVERB_PROPERTIES -, -FSOUND_Reverb_SetProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_REVERB_PRESETS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_REVERB_PRESETS

+A set of predefined environment PARAMETERS, created by Creative Labs
+These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically.
+ie
+FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC;
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FSOUND_PRESET_OFF{0, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x33f } +
FSOUND_PRESET_GENERIC{0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_PADDEDCELL{1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, { 0.0f,0.0f,0.0f }, 207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_ROOM{2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, { 0.0f,0.0f,0.0f }, 53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_BATHROOM{3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, { 0.0f,0.0f,0.0f }, 1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f } +
FSOUND_PRESET_LIVINGROOM{4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_STONEROOM{5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, { 0.0f,0.0f,0.0f }, 83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_AUDITORIUM{6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, { 0.0f,0.0f,0.0f }, -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_CONCERTHALL{7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, { 0.0f,0.0f,0.0f }, -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_CAVE{8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, { 0.0f,0.0f,0.0f }, -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +
FSOUND_PRESET_ARENA{9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, { 0.0f,0.0f,0.0f }, 16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_HANGAR{10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, { 0.0f,0.0f,0.0f }, 198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_CARPETTEDHALLWAY{11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_HALLWAY{12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, { 0.0f,0.0f,0.0f }, 441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_STONECORRIDOR{13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, { 0.0f,0.0f,0.0f }, 395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_ALLEY{14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, { 0.0f,0.0f,0.0f }, -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_FOREST{15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, { 0.0f,0.0f,0.0f }, -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f } +
FSOUND_PRESET_CITY{16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f } +
FSOUND_PRESET_MOUNTAINS{17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f } +
FSOUND_PRESET_QUARRY{18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f }, 500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_PLAIN{19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f } +
FSOUND_PRESET_PARKINGLOT{20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +
FSOUND_PRESET_SEWERPIPE{21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, { 0.0f,0.0f,0.0f }, 1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f } +
FSOUND_PRESET_UNDERWATER{22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, { 0.0f,0.0f,0.0f }, 1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +
FSOUND_PRESET_DRUGGED{23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, { 0.0f,0.0f,0.0f }, 985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +
FSOUND_PRESET_DIZZY{24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, { 0.0f,0.0f,0.0f }, -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +
FSOUND_PRESET_PSYCHOTIC{25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, { 0.0f,0.0f,0.0f }, 774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +
FSOUND_PRESET_PS2_ROOM{1, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_STUDIO_A{2, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_STUDIO_B{3, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_STUDIO_C{4, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_HALL{5, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_SPACE{6, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_ECHO{7, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_DELAY{8, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
FSOUND_PRESET_PS2_PIPE{9, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +
+

See Also

+FSOUND_REVERB_PROPERTIES +, +FSOUND_Reverb_SetProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PROPERTIES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PROPERTIES.html index 89a0f756..0f0b71d8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PROPERTIES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_REVERB_PROPERTIES.html @@ -1,144 +1,144 @@ - - - - -FSOUND_REVERB_PROPERTIES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Structure]
-

FSOUND_REVERB_PROPERTIES

-Structure defining a reverb environment.
-For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3
-documentation at http://developer.creative.com/ under the 'downloads' section.
-If they do not have the EAX3 documentation, then most information can be attained from
-the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of EAX2.
-Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset.
-Note that integer values that typically range from -10,000 to 1000 are represented in decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
-PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox).
-Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then the reverb should product a similar effect on either platform.
-The numerical values listed below are the maximum, minimum and default values for each variable respectively.
-

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned intEnvironment/* 0 , 25 , 0 , sets all listener properties (WIN32/PS2 only) */
-
floatEnvSize/* 1.0 , 100.0 , 7.5 , environment size in meters (WIN32 only) */
-
floatEnvDiffusion/* 0.0 , 1.0 , 1.0 , environment diffusion (WIN32/XBOX) */
-
intRoom/* -10000, 0 , -1000 , room effect level (at mid frequencies) (WIN32/XBOX/PS2) */
-
intRoomHF/* -10000, 0 , -100 , relative room effect level at high frequencies (WIN32/XBOX) */
-
intRoomLF/* -10000, 0 , 0 , relative room effect level at low frequencies (WIN32 only) */
-
floatDecayTime/* 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (WIN32/XBOX) */
-
floatDecayHFRatio/* 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (WIN32/XBOX) */
-
floatDecayLFRatio/* 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (WIN32 only) */
-
intReflections/* -10000, 1000 , -2602 , early reflections level relative to room effect (WIN32/XBOX) */
-
floatReflectionsDelay/* 0.0 , 0.3 , 0.007 , initial reflection delay time (WIN32/XBOX) */
-
floatReflectionsPan[3]/* , , [0,0,0], early reflections panning vector (WIN32 only) */
-
intReverb/* -10000, 2000 , 200 , late reverberation level relative to room effect (WIN32/XBOX) */
-
floatReverbDelay/* 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (WIN32/XBOX) */
-
floatReverbPan[3]/* , , [0,0,0], late reverberation panning vector (WIN32 only) */
-
floatEchoTime/* .075 , 0.25 , 0.25 , echo time (WIN32/PS2 only. PS2 = Delay time for ECHO/DELAY modes only) */
-
floatEchoDepth/* 0.0 , 1.0 , 0.0 , echo depth (WIN32/PS2 only. PS2 = Feedback level for ECHO mode only) */
-
floatModulationTime/* 0.04 , 4.0 , 0.25 , modulation time (WIN32 only) */
-
floatModulationDepth/* 0.0 , 1.0 , 0.0 , modulation depth (WIN32 only) */
-
floatAirAbsorptionHF/* -100 , 0.0 , -5.0 , change in level per meter at high frequencies (WIN32 only) */
-
floatHFReference/* 1000.0, 20000 , 5000.0 , reference high frequency (hz) (WIN32/XBOX) */
-
floatLFReference/* 20.0 , 1000.0, 250.0 , reference low frequency (hz) (WIN32 only) */
-
floatRoomRolloffFactor/* 0.0 , 10.0 , 0.0 , like FSOUND_3D_SetRolloffFactor but for room effect (WIN32/XBOX) */
-
floatDiffusion/* 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (XBOX only) */
-
floatDensity/* 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (XBOX only) */
-
unsigned intFlags/* FSOUND_REVERB_FLAGS - modifies the behavior of above properties (WIN32/PS2 only) */
-
-

See Also

-FSOUND_3D_SetRolloffFactor -, -FSOUND_REVERB_FLAGS -, -FSOUND_Reverb_GetProperties -, -FSOUND_REVERB_PRESETS -, -FSOUND_Reverb_SetProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_REVERB_PROPERTIES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Structure]
+

FSOUND_REVERB_PROPERTIES

+Structure defining a reverb environment.
+For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3
+documentation at http://developer.creative.com/ under the 'downloads' section.
+If they do not have the EAX3 documentation, then most information can be attained from
+the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of EAX2.
+Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset.
+Note that integer values that typically range from -10,000 to 1000 are represented in decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
+PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox).
+Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then the reverb should product a similar effect on either platform.
+The numerical values listed below are the maximum, minimum and default values for each variable respectively.
+

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
unsigned intEnvironment/* 0 , 25 , 0 , sets all listener properties (WIN32/PS2 only) */
+
floatEnvSize/* 1.0 , 100.0 , 7.5 , environment size in meters (WIN32 only) */
+
floatEnvDiffusion/* 0.0 , 1.0 , 1.0 , environment diffusion (WIN32/XBOX) */
+
intRoom/* -10000, 0 , -1000 , room effect level (at mid frequencies) (WIN32/XBOX/PS2) */
+
intRoomHF/* -10000, 0 , -100 , relative room effect level at high frequencies (WIN32/XBOX) */
+
intRoomLF/* -10000, 0 , 0 , relative room effect level at low frequencies (WIN32 only) */
+
floatDecayTime/* 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (WIN32/XBOX) */
+
floatDecayHFRatio/* 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (WIN32/XBOX) */
+
floatDecayLFRatio/* 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (WIN32 only) */
+
intReflections/* -10000, 1000 , -2602 , early reflections level relative to room effect (WIN32/XBOX) */
+
floatReflectionsDelay/* 0.0 , 0.3 , 0.007 , initial reflection delay time (WIN32/XBOX) */
+
floatReflectionsPan[3]/* , , [0,0,0], early reflections panning vector (WIN32 only) */
+
intReverb/* -10000, 2000 , 200 , late reverberation level relative to room effect (WIN32/XBOX) */
+
floatReverbDelay/* 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (WIN32/XBOX) */
+
floatReverbPan[3]/* , , [0,0,0], late reverberation panning vector (WIN32 only) */
+
floatEchoTime/* .075 , 0.25 , 0.25 , echo time (WIN32/PS2 only. PS2 = Delay time for ECHO/DELAY modes only) */
+
floatEchoDepth/* 0.0 , 1.0 , 0.0 , echo depth (WIN32/PS2 only. PS2 = Feedback level for ECHO mode only) */
+
floatModulationTime/* 0.04 , 4.0 , 0.25 , modulation time (WIN32 only) */
+
floatModulationDepth/* 0.0 , 1.0 , 0.0 , modulation depth (WIN32 only) */
+
floatAirAbsorptionHF/* -100 , 0.0 , -5.0 , change in level per meter at high frequencies (WIN32 only) */
+
floatHFReference/* 1000.0, 20000 , 5000.0 , reference high frequency (hz) (WIN32/XBOX) */
+
floatLFReference/* 20.0 , 1000.0, 250.0 , reference low frequency (hz) (WIN32 only) */
+
floatRoomRolloffFactor/* 0.0 , 10.0 , 0.0 , like FSOUND_3D_SetRolloffFactor but for room effect (WIN32/XBOX) */
+
floatDiffusion/* 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (XBOX only) */
+
floatDensity/* 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (XBOX only) */
+
unsigned intFlags/* FSOUND_REVERB_FLAGS - modifies the behavior of above properties (WIN32/PS2 only) */
+
+

See Also

+FSOUND_3D_SetRolloffFactor +, +FSOUND_REVERB_FLAGS +, +FSOUND_Reverb_GetProperties +, +FSOUND_REVERB_PRESETS +, +FSOUND_Reverb_SetProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriver.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriver.html index 1a82d9e2..c232ec15 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriver.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriver.html @@ -1,61 +1,61 @@ - - - - -FSOUND_Record_GetDriver - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_GetDriver

-Returns the currently selected recording driver number. Drivers are enumerated when selecting a driver
-with FSOUND_Record_SetDriver or other driver related functions such as FSOUND_Record_GetNumDrivers or
-FSOUND_Record_GetDriverName
-

-int F_API FSOUND_Record_GetDriver(
-);
-

Return Value

-Currently selected driver id.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Record_GetDriver -, -FSOUND_Record_GetDriverName -, -FSOUND_Record_GetNumDrivers -, -FSOUND_Record_SetDriver -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_GetDriver + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_GetDriver

+Returns the currently selected recording driver number. Drivers are enumerated when selecting a driver
+with FSOUND_Record_SetDriver or other driver related functions such as FSOUND_Record_GetNumDrivers or
+FSOUND_Record_GetDriverName
+

+int F_API FSOUND_Record_GetDriver(
+);
+

Return Value

+Currently selected driver id.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Record_GetDriver +, +FSOUND_Record_GetDriverName +, +FSOUND_Record_GetNumDrivers +, +FSOUND_Record_SetDriver +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriverName.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriverName.html index f2ea149d..516aee9f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriverName.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetDriverName.html @@ -1,65 +1,65 @@ - - - - -FSOUND_Record_GetDriverName - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_GetDriverName

-Returns the name of the selected recording driver. Drivers are enumerated when selecting a driver with
-FSOUND_Record_SetDriver or other driver related functions such as FSOUND_Record_GetNumDrivers or FSOUND_Record_GetDriver
-

-const char * F_API FSOUND_Record_GetDriverName(
-int id
-);
-

Parameters

- - -
idEnumerated driver ID. This must be in a valid range delimited by FSOUND_Record_GetNumDrivers,
-
-

Return Value

-On success, a pointer to a NULL terminated string containing the name of the specified device is returned. The number of drivers enumerated can be found with FSOUND_Record_GetNumDrivers.
-On failure, NULL is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Record_GetDriver -, -FSOUND_Record_GetNumDrivers -, -FSOUND_Record_SetDriver -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_GetDriverName + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_GetDriverName

+Returns the name of the selected recording driver. Drivers are enumerated when selecting a driver with
+FSOUND_Record_SetDriver or other driver related functions such as FSOUND_Record_GetNumDrivers or FSOUND_Record_GetDriver
+

+const char * F_API FSOUND_Record_GetDriverName(
+int id
+);
+

Parameters

+ + +
idEnumerated driver ID. This must be in a valid range delimited by FSOUND_Record_GetNumDrivers,
+
+

Return Value

+On success, a pointer to a NULL terminated string containing the name of the specified device is returned. The number of drivers enumerated can be found with FSOUND_Record_GetNumDrivers.
+On failure, NULL is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Record_GetDriver +, +FSOUND_Record_GetNumDrivers +, +FSOUND_Record_SetDriver +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetNumDrivers.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetNumDrivers.html index 31cd168c..7ee6c785 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetNumDrivers.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetNumDrivers.html @@ -1,58 +1,58 @@ - - - - -FSOUND_Record_GetNumDrivers - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_GetNumDrivers

-Returns the number of sound cards or devices enumerated for the current input type. (Direct
-Sound, WaveOut etc.)
-

-int F_API FSOUND_Record_GetNumDrivers(
-);
-

Return Value

-Total number of enumerated sound devices.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Record_GetDriver -, -FSOUND_Record_GetDriverName -, -FSOUND_Record_SetDriver -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_GetNumDrivers + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_GetNumDrivers

+Returns the number of sound cards or devices enumerated for the current input type. (Direct
+Sound, WaveOut etc.)
+

+int F_API FSOUND_Record_GetNumDrivers(
+);
+

Return Value

+Total number of enumerated sound devices.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Record_GetDriver +, +FSOUND_Record_GetDriverName +, +FSOUND_Record_SetDriver +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetPosition.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetPosition.html index 2a33d461..0d323584 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetPosition.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_GetPosition.html @@ -1,55 +1,55 @@ - - - - -FSOUND_Record_GetPosition - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_GetPosition

-Gets the position in the sample buffer that has been recorded to.
-

-int F_API FSOUND_Record_GetPosition(
-);
-

Return Value

-On success, the offset in SAMPLES, for the record buffer that the input device has just written up to is returned.
-On failure (recording device hasnt been started), -1 is returned.
-

Remarks

-Note. This is not the 'recording cursor', but rather the latest point that the input has been copied to your sample
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Record_StartSample -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_GetPosition + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_GetPosition

+Gets the position in the sample buffer that has been recorded to.
+

+int F_API FSOUND_Record_GetPosition(
+);
+

Return Value

+On success, the offset in SAMPLES, for the record buffer that the input device has just written up to is returned.
+On failure (recording device hasnt been started), -1 is returned.
+

Remarks

+Note. This is not the 'recording cursor', but rather the latest point that the input has been copied to your sample
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Record_StartSample +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_SetDriver.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_SetDriver.html index 53463781..8a8e03d1 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_SetDriver.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_SetDriver.html @@ -1,67 +1,67 @@ - - - - -FSOUND_Record_SetDriver - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_SetDriver

-Selects a soundcard recording driver.
-It is used when an output mode has enumerated more than one recording device and you need to select between them.
-

-signed char F_API FSOUND_Record_SetDriver(
-int driver
-);
-

Parameters

- - -
drivernoRecording driver number to select.
-<=0 will select the DEFAULT recording sound driver.
->0 Selects other valid drivers that can be listed with FSOUND_Record_GetDriverName.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Record_GetDriver -, -FSOUND_Record_GetDriverName -, -FSOUND_Record_GetNumDrivers -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_SetDriver + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_SetDriver

+Selects a soundcard recording driver.
+It is used when an output mode has enumerated more than one recording device and you need to select between them.
+

+signed char F_API FSOUND_Record_SetDriver(
+int driver
+);
+

Parameters

+ + +
drivernoRecording driver number to select.
+<=0 will select the DEFAULT recording sound driver.
+>0 Selects other valid drivers that can be listed with FSOUND_Record_GetDriverName.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Record_GetDriver +, +FSOUND_Record_GetDriverName +, +FSOUND_Record_GetNumDrivers +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_StartSample.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_StartSample.html index c50d538d..6fef5c53 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_StartSample.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_StartSample.html @@ -1,76 +1,76 @@ - - - - -FSOUND_Record_StartSample - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_StartSample

-Starts recording into a predefined sample using the sample's default playback rate as the recording rate.
-

-signed char F_API FSOUND_Record_StartSample(
-FSOUND_SAMPLE *sptr,
-signed char loop
-);
-

Parameters

- - - -
sptrThe sample to record into.
-
loopTRUE or FALSE flag whether the recorder should keep recording once it has hit the end,
-and start from the start again, therefore creating a continuous recording session into that
-sample buffer. Looping the recording buffer is good for realtime processing of recorded
-information, as you can record and playback the sample at the same time.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-If you want to play back the sample at the same time is is recording, you will have to play the sound and try and keep it just behind the recording cursor.
-Under FSOUND_OUTPUT_OSS mode, it is single duplex, so playback will stop when recording is in progress! Try FSOUND_OUTPUT_ALSA for full duplex as they have better drivers in this respect.
--------------
-The recording/playback rates are slightly innacurate and are not identical (ie 44100.0 for playback, 44100.1 for recording), so one could possibly be faster or slower than the other. In this case the recording and the playback cursor could overlap, and the output will sound corrupted.
-To counter this you might adjust the playback frequency of the channel you are playing the record sample on while it plays, using FSOUND_GetCurrentPosition and FSOUND_Record_GetPosition as calibration points.
-In the recording sample there is an example of trying to play back sound as it records, and the mechanism to try and keep the 2 cursors a safe distance from each other is employed.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_GetCurrentPosition -, -FSOUND_Record_GetPosition -, -FSOUND_Record_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_StartSample + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_StartSample

+Starts recording into a predefined sample using the sample's default playback rate as the recording rate.
+

+signed char F_API FSOUND_Record_StartSample(
+FSOUND_SAMPLE *sptr,
+signed char loop
+);
+

Parameters

+ + + +
sptrThe sample to record into.
+
loopTRUE or FALSE flag whether the recorder should keep recording once it has hit the end,
+and start from the start again, therefore creating a continuous recording session into that
+sample buffer. Looping the recording buffer is good for realtime processing of recorded
+information, as you can record and playback the sample at the same time.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+If you want to play back the sample at the same time is is recording, you will have to play the sound and try and keep it just behind the recording cursor.
+Under FSOUND_OUTPUT_OSS mode, it is single duplex, so playback will stop when recording is in progress! Try FSOUND_OUTPUT_ALSA for full duplex as they have better drivers in this respect.
+-------------
+The recording/playback rates are slightly innacurate and are not identical (ie 44100.0 for playback, 44100.1 for recording), so one could possibly be faster or slower than the other. In this case the recording and the playback cursor could overlap, and the output will sound corrupted.
+To counter this you might adjust the playback frequency of the channel you are playing the record sample on while it plays, using FSOUND_GetCurrentPosition and FSOUND_Record_GetPosition as calibration points.
+In the recording sample there is an example of trying to play back sound as it records, and the mechanism to try and keep the 2 cursors a safe distance from each other is employed.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_GetCurrentPosition +, +FSOUND_Record_GetPosition +, +FSOUND_Record_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_Stop.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_Stop.html index 20cf7633..aafd6146 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_Stop.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Record_Stop.html @@ -1,54 +1,54 @@ - - - - -FSOUND_Record_Stop - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Record_Stop

-Halts recording to the specified sample.
-

-signed char F_API FSOUND_Record_Stop(
-);
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Record_StartSample -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Record_Stop + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Record_Stop

+Halts recording to the specified sample.
+

+signed char F_API FSOUND_Record_Stop(
+);
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Record_StartSample +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetChannelProperties.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetChannelProperties.html index 3edf498f..e8a0c0e9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetChannelProperties.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetChannelProperties.html @@ -1,69 +1,69 @@ - - - - -FSOUND_Reverb_GetChannelProperties - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Reverb_GetChannelProperties

-This function gets the current reverb properties for this channel.
-

-signed char F_API FSOUND_Reverb_GetChannelProperties(
-int channel,
-FSOUND_REVERB_CHANNELPROPERTIES *prop
-);
-

Parameters

- - - -
channelThe channel to have its reverb mix returned.
-
propPointer to a FSOUND_REVERB_CHANNELPROPERTIES structure definition. The definition for this structure is given in the link below.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, XBox
-

See Also

-FSOUND_REVERB_CHANNELPROPERTIES -, -FSOUND_Reverb_GetProperties -, -FSOUND_Reverb_SetChannelProperties -, -FSOUND_Reverb_SetProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Reverb_GetChannelProperties + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Reverb_GetChannelProperties

+This function gets the current reverb properties for this channel.
+

+signed char F_API FSOUND_Reverb_GetChannelProperties(
+int channel,
+FSOUND_REVERB_CHANNELPROPERTIES *prop
+);
+

Parameters

+ + + +
channelThe channel to have its reverb mix returned.
+
propPointer to a FSOUND_REVERB_CHANNELPROPERTIES structure definition. The definition for this structure is given in the link below.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, XBox
+

See Also

+FSOUND_REVERB_CHANNELPROPERTIES +, +FSOUND_Reverb_GetProperties +, +FSOUND_Reverb_SetChannelProperties +, +FSOUND_Reverb_SetProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetProperties.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetProperties.html index f9a33bd1..fad0dd2e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetProperties.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_GetProperties.html @@ -1,67 +1,67 @@ - - - - -FSOUND_Reverb_GetProperties - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Reverb_GetProperties

-Returns the current hardware reverb environment.
-

-signed char F_API FSOUND_Reverb_GetProperties(
-FSOUND_REVERB_PROPERTIES *props
-);
-

Parameters

- - -
propsPointer to a FSOUND_REVERB_PROPERTIES structure definition. The definiotion for this structure is given in the link below.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-These values are only relevant if you are in DSOUND mode with an EAX3 compatible soundcard, or XBOX and PS2.
-___________________
-Supported on the following platforms : Win32, XBox, PlayStation 2
-

See Also

-FSOUND_Reverb_GetChannelProperties -, -FSOUND_REVERB_PROPERTIES -, -FSOUND_Reverb_SetChannelProperties -, -FSOUND_Reverb_SetProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Reverb_GetProperties + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Reverb_GetProperties

+Returns the current hardware reverb environment.
+

+signed char F_API FSOUND_Reverb_GetProperties(
+FSOUND_REVERB_PROPERTIES *props
+);
+

Parameters

+ + +
propsPointer to a FSOUND_REVERB_PROPERTIES structure definition. The definiotion for this structure is given in the link below.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+These values are only relevant if you are in DSOUND mode with an EAX3 compatible soundcard, or XBOX and PS2.
+___________________
+Supported on the following platforms : Win32, XBox, PlayStation 2
+

See Also

+FSOUND_Reverb_GetChannelProperties +, +FSOUND_REVERB_PROPERTIES +, +FSOUND_Reverb_SetChannelProperties +, +FSOUND_Reverb_SetProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetChannelProperties.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetChannelProperties.html index 2c9cf3dc..49f57b71 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetChannelProperties.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetChannelProperties.html @@ -1,82 +1,82 @@ - - - - -FSOUND_Reverb_SetChannelProperties - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Reverb_SetChannelProperties

-Sets the channel specific reverb properties for hardware, including wet/dry mix (room size), and things like obstruction and occlusion properties.
-

-signed char F_API FSOUND_Reverb_SetChannelProperties(
-int channel,
-const FSOUND_REVERB_CHANNELPROPERTIES *prop
-);
-

Parameters

- - - -
channelThe channel to have its reverb properties changed. FSOUND_ALL can also be used (see remarks)
-
propPointer to a FSOUND_REVERB_CHANNELPROPERTIES structure definition. The definition for this structure is given in the link below.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported here. Passing this will set ALL channels to specified reverb properties.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value not useful in most circumstances.
------------------
-Under Win32, you must be using FSOUND_OUTPUT_DSOUND as the output mode for this to work.
-In DSound, the reverb will only work if you have an EAX compatible soundcard such as the SBLive, and your sample/stream was created with the FSOUND_HW3D flag.
------------------
-On PlayStation2, the 'Room' parameter is the only parameter supported. The hardware only allows 'on' or 'off', so the reverb will be off when 'Room' is -10000 and on for every other value.
------------------
-On XBox, it is possible to apply reverb to 2d voices using this function. By default reverb is turned off for 2d voices.
-If this 2d voice was being positioned in a 5.1 array with the xbox only function FSOUND_SetLevels, then calling this function will disable that capability in favour of enabling reverb for the 2d voice.
-It is a limitation of the xbox hardware that only one of the other of these features can be executed at one time.
-___________________
-Supported on the following platforms : Win32, XBox, PlayStation 2.
-

See Also

-FSOUND_REVERB_CHANNELPROPERTIES -, -FSOUND_Reverb_GetChannelProperties -, -FSOUND_Reverb_GetProperties -, -FSOUND_Reverb_SetProperties -, -FSOUND_SetLevels -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Reverb_SetChannelProperties + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Reverb_SetChannelProperties

+Sets the channel specific reverb properties for hardware, including wet/dry mix (room size), and things like obstruction and occlusion properties.
+

+signed char F_API FSOUND_Reverb_SetChannelProperties(
+int channel,
+const FSOUND_REVERB_CHANNELPROPERTIES *prop
+);
+

Parameters

+ + + +
channelThe channel to have its reverb properties changed. FSOUND_ALL can also be used (see remarks)
+
propPointer to a FSOUND_REVERB_CHANNELPROPERTIES structure definition. The definition for this structure is given in the link below.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported here. Passing this will set ALL channels to specified reverb properties.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value not useful in most circumstances.
+-----------------
+Under Win32, you must be using FSOUND_OUTPUT_DSOUND as the output mode for this to work.
+In DSound, the reverb will only work if you have an EAX compatible soundcard such as the SBLive, and your sample/stream was created with the FSOUND_HW3D flag.
+-----------------
+On PlayStation2, the 'Room' parameter is the only parameter supported. The hardware only allows 'on' or 'off', so the reverb will be off when 'Room' is -10000 and on for every other value.
+-----------------
+On XBox, it is possible to apply reverb to 2d voices using this function. By default reverb is turned off for 2d voices.
+If this 2d voice was being positioned in a 5.1 array with the xbox only function FSOUND_SetLevels, then calling this function will disable that capability in favour of enabling reverb for the 2d voice.
+It is a limitation of the xbox hardware that only one of the other of these features can be executed at one time.
+___________________
+Supported on the following platforms : Win32, XBox, PlayStation 2.
+

See Also

+FSOUND_REVERB_CHANNELPROPERTIES +, +FSOUND_Reverb_GetChannelProperties +, +FSOUND_Reverb_GetProperties +, +FSOUND_Reverb_SetProperties +, +FSOUND_SetLevels +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetProperties.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetProperties.html index 97419bb0..4668fa03 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetProperties.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Reverb_SetProperties.html @@ -1,70 +1,70 @@ - - - - -FSOUND_Reverb_SetProperties - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Reverb_SetProperties

-Sets hardware reverb parameters for advanced tuning.
-The best way to modify these is to set everything to use pre-defined presets given in the header, and then start modifying values.
-

-signed char F_API FSOUND_Reverb_SetProperties(
-const FSOUND_REVERB_PROPERTIES *props
-);
-

Parameters

- - -
propA pointer to a FSOUND_REVERB_PROPERTIES struct. The definition for this structure is given in the link below.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-You must be using FSOUND_OUTPUT_DSOUND as the output mode for this to work.
-In dsound, the reverb will only work if you have an EAX compatible soundcard such as the SBLive, and your sample/stream was created with the FSOUND_HW3D flag.
-For GameCube, use FSOUND_AUXFX_xxx api.
-___________________
-Supported on the following platforms : Win32, XBox, PlayStation 2
-

See Also

-FSOUND_Reverb_GetChannelProperties -, -FSOUND_Reverb_GetProperties -, -FSOUND_REVERB_PROPERTIES -, -FSOUND_Reverb_SetChannelProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:31 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Reverb_SetProperties + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Reverb_SetProperties

+Sets hardware reverb parameters for advanced tuning.
+The best way to modify these is to set everything to use pre-defined presets given in the header, and then start modifying values.
+

+signed char F_API FSOUND_Reverb_SetProperties(
+const FSOUND_REVERB_PROPERTIES *props
+);
+

Parameters

+ + +
propA pointer to a FSOUND_REVERB_PROPERTIES struct. The definition for this structure is given in the link below.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+You must be using FSOUND_OUTPUT_DSOUND as the output mode for this to work.
+In dsound, the reverb will only work if you have an EAX compatible soundcard such as the SBLive, and your sample/stream was created with the FSOUND_HW3D flag.
+For GameCube, use FSOUND_AUXFX_xxx api.
+___________________
+Supported on the following platforms : Win32, XBox, PlayStation 2
+

See Also

+FSOUND_Reverb_GetChannelProperties +, +FSOUND_Reverb_GetProperties +, +FSOUND_REVERB_PROPERTIES +, +FSOUND_Reverb_SetChannelProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:31 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SEEKCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SEEKCALLBACK.html index 76c08b24..6225790d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SEEKCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SEEKCALLBACK.html @@ -1,75 +1,75 @@ - - - - -FSOUND_SEEKCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SEEKCALLBACK

-Callback for seeking within a file.
-

-int F_CALLBACKAPI FSOUND_SEEKCALLBACK(
-void *handle,
-int pos,
-signed char mode
-);
-

Parameters

- - - - -
handleThis is the handle you returned from the open callback to use for your own file routines.
-
posThis is the position or offset to seek by depending on the mode.
-
modeThis is the seek command. It uses and is compatible with SEEK_SET, SEEK_CUR and SEEK_END from stdio.h, so use them.
-
-

Return Value

-If successful, the seek callback returns 0. Otherwise, it returns a nonzero value. On devices incapable of seeking, the return value is undefined.
-

Remarks

-SEEK_END must reposition your file pointer at the END of the file, plus any negative offset. To do this you must know the size of the file, it is suggested you find and store this in the open function. Remember that a SEEK_END position value of -1 is the last byte.
-You must reset your file pointer based on the commands given above.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_CLOSECALLBACK -, -FSOUND_File_SetCallbacks -, -FSOUND_OPENCALLBACK -, -FSOUND_READCALLBACK -, -FSOUND_TELLCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SEEKCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SEEKCALLBACK

+Callback for seeking within a file.
+

+int F_CALLBACKAPI FSOUND_SEEKCALLBACK(
+void *handle,
+int pos,
+signed char mode
+);
+

Parameters

+ + + + +
handleThis is the handle you returned from the open callback to use for your own file routines.
+
posThis is the position or offset to seek by depending on the mode.
+
modeThis is the seek command. It uses and is compatible with SEEK_SET, SEEK_CUR and SEEK_END from stdio.h, so use them.
+
+

Return Value

+If successful, the seek callback returns 0. Otherwise, it returns a nonzero value. On devices incapable of seeking, the return value is undefined.
+

Remarks

+SEEK_END must reposition your file pointer at the END of the file, plus any negative offset. To do this you must know the size of the file, it is suggested you find and store this in the open function. Remember that a SEEK_END position value of -1 is the last byte.
+You must reset your file pointer based on the commands given above.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_CLOSECALLBACK +, +FSOUND_File_SetCallbacks +, +FSOUND_OPENCALLBACK +, +FSOUND_READCALLBACK +, +FSOUND_TELLCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPEAKERMODES.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPEAKERMODES.html index fe93c56a..b456d5bf 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPEAKERMODES.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPEAKERMODES.html @@ -1,70 +1,70 @@ - - - - -FSOUND_SPEAKERMODES - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_SPEAKERMODES

-These are speaker types defined for use with the FSOUND_SetSpeakerMode command.
-Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only
-interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo.
-Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure.
-

-

Enumerators

- - - - - - - - - - -
FSOUND_SPEAKERMODE_DOLBYDIGITAL/* Dolby Digital Output (XBOX or PC only). */
-
FSOUND_SPEAKERMODE_HEADPHONES/* The speakers are headphones. */
-
FSOUND_SPEAKERMODE_MONO/* The speakers are monaural. */
-
FSOUND_SPEAKERMODE_QUAD/* The speakers are quadraphonic. */
-
FSOUND_SPEAKERMODE_STEREO/* The speakers are stereo (default value). */
-
FSOUND_SPEAKERMODE_SURROUND/* The speakers are surround sound. */
-
FSOUND_SPEAKERMODE_DTS/* DTS output (XBOX only). */
-
FSOUND_SPEAKERMODE_PROLOGIC2/* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 doesnt support interior panning, but supports 48 voices simultaneously. */
-
FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR/* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 does support interior panning, but only supports 24 voices simultaneously. */
-
-

See Also

-FSOUND_SetSpeakerMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SPEAKERMODES + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_SPEAKERMODES

+These are speaker types defined for use with the FSOUND_SetSpeakerMode command.
+Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only
+interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo.
+Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure.
+

+

Enumerators

+ + + + + + + + + + +
FSOUND_SPEAKERMODE_DOLBYDIGITAL/* Dolby Digital Output (XBOX or PC only). */
+
FSOUND_SPEAKERMODE_HEADPHONES/* The speakers are headphones. */
+
FSOUND_SPEAKERMODE_MONO/* The speakers are monaural. */
+
FSOUND_SPEAKERMODE_QUAD/* The speakers are quadraphonic. */
+
FSOUND_SPEAKERMODE_STEREO/* The speakers are stereo (default value). */
+
FSOUND_SPEAKERMODE_SURROUND/* The speakers are surround sound. */
+
FSOUND_SPEAKERMODE_DTS/* DTS output (XBOX only). */
+
FSOUND_SPEAKERMODE_PROLOGIC2/* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 doesnt support interior panning, but supports 48 voices simultaneously. */
+
FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR/* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 does support interior panning, but only supports 24 voices simultaneously. */
+
+

See Also

+FSOUND_SetSpeakerMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Alloc.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Alloc.html index 7c226afe..ed8fca37 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Alloc.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Alloc.html @@ -1,68 +1,68 @@ - - - - -FSOUND_SPU2_Alloc - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SPU2_Alloc

-Allocates SPU2 Ram
-

-void * F_API FSOUND_SPU2_Alloc(
-int length
-);
-

Parameters

- - -
lengthLength in bytes of SPU2 sound RAM to be allocated.
-
-

Return Value

-An IOP based handle for the SPU2 ram block.
-

Remarks

-This function is mainly used to reserve memory for purposes such as 3rd party libraries needing memory for their own spu2 use.
-DO NOT use this as the offset into spu2 ram! Use FSOUND_SPU2_GetRawAddress to get the spu2 offset into sound ram from this handle.
------------
-The SPU2 has 2mb of ram available, unless reverb is activated on both cores, then it is less. You can disable reverb using
-FSOUND_INIT_PS2_DISABLECORE0REVERB and FSOUND_INIT_PS2_DISABLECORE1REVERB with FSOUND_Init.
-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_Init -, -FSOUND_SPU2_Free -, -FSOUND_SPU2_GetRawAddress -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SPU2_Alloc + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SPU2_Alloc

+Allocates SPU2 Ram
+

+void * F_API FSOUND_SPU2_Alloc(
+int length
+);
+

Parameters

+ + +
lengthLength in bytes of SPU2 sound RAM to be allocated.
+
+

Return Value

+An IOP based handle for the SPU2 ram block.
+

Remarks

+This function is mainly used to reserve memory for purposes such as 3rd party libraries needing memory for their own spu2 use.
+DO NOT use this as the offset into spu2 ram! Use FSOUND_SPU2_GetRawAddress to get the spu2 offset into sound ram from this handle.
+-----------
+The SPU2 has 2mb of ram available, unless reverb is activated on both cores, then it is less. You can disable reverb using
+FSOUND_INIT_PS2_DISABLECORE0REVERB and FSOUND_INIT_PS2_DISABLECORE1REVERB with FSOUND_Init.
+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_Init +, +FSOUND_SPU2_Free +, +FSOUND_SPU2_GetRawAddress +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Free.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Free.html index ef22ead3..3a2cc897 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Free.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_Free.html @@ -1,62 +1,62 @@ - - - - -FSOUND_SPU2_Free - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SPU2_Free

-Frees SPU2 Ram
-

-void F_API FSOUND_SPU2_Free(
-void *iopptr
-);
-

Parameters

- - -
iopptrHandle to free generated by FSOUND_SPU2_Alloc.
-
-

Return Value

-void
-

Remarks

-Pass the value from FSOUND_SPU2_Alloc, NOT the value from FSOUND_SPU2_GetRawAddress.
-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_SPU2_Alloc -, -FSOUND_SPU2_GetRawAddress -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SPU2_Free + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SPU2_Free

+Frees SPU2 Ram
+

+void F_API FSOUND_SPU2_Free(
+void *iopptr
+);
+

Parameters

+ + +
iopptrHandle to free generated by FSOUND_SPU2_Alloc.
+
+

Return Value

+void
+

Remarks

+Pass the value from FSOUND_SPU2_Alloc, NOT the value from FSOUND_SPU2_GetRawAddress.
+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_SPU2_Alloc +, +FSOUND_SPU2_GetRawAddress +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_GetRawAddress.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_GetRawAddress.html index 0c34af78..462ec062 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_GetRawAddress.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SPU2_GetRawAddress.html @@ -1,62 +1,62 @@ - - - - -FSOUND_SPU2_GetRawAddress - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SPU2_GetRawAddress

-Gets the raw SPU2 offset inside the SPU2 memory space from the handle returned from FSOUND_SPU2_Alloc
-

-unsigned int F_API FSOUND_SPU2_GetRawAddress(
-void *iopptr
-);
-

Parameters

- - -
iopptrPointer to the IOP based sound ram handle.
-
-

Return Value

-The SPU2 address of the data allocated. This is not directly addressable.
-The only way to get data to this address is to DMA it from the EE to the IOP first, then from the IOP to SRAM.
-

Remarks

-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_SPU2_Alloc -, -FSOUND_SPU2_Free -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SPU2_GetRawAddress + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SPU2_GetRawAddress

+Gets the raw SPU2 offset inside the SPU2 memory space from the handle returned from FSOUND_SPU2_Alloc
+

+unsigned int F_API FSOUND_SPU2_GetRawAddress(
+void *iopptr
+);
+

Parameters

+ + +
iopptrPointer to the IOP based sound ram handle.
+
+

Return Value

+The SPU2 address of the data allocated. This is not directly addressable.
+The only way to get data to this address is to DMA it from the EE to the IOP first, then from the IOP to SRAM.
+

Remarks

+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_SPU2_Alloc +, +FSOUND_SPU2_Free +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STATUS_FLAGS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STATUS_FLAGS.html index c394aad5..f44cddf0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STATUS_FLAGS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STATUS_FLAGS.html @@ -1,63 +1,63 @@ - - - - -FSOUND_STATUS_FLAGS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Define]
-

FSOUND_STATUS_FLAGS

-These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream.
-

- - - - - - - - - - - -
FSOUND_PROTOCOL_SHOUTCAST0x00000001 -
FSOUND_PROTOCOL_ICECAST0x00000002 -
FSOUND_PROTOCOL_HTTP0x00000004 -
FSOUND_FORMAT_MPEG0x00010000 -
FSOUND_FORMAT_OGGVORBIS0x00020000 -
-

See Also

-FSOUND_Stream_Net_GetStatus -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STATUS_FLAGS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Define]
+

FSOUND_STATUS_FLAGS

+These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream.
+

+ + + + + + + + + + + +
FSOUND_PROTOCOL_SHOUTCAST0x00000001 +
FSOUND_PROTOCOL_ICECAST0x00000002 +
FSOUND_PROTOCOL_HTTP0x00000004 +
FSOUND_FORMAT_MPEG0x00010000 +
FSOUND_FORMAT_OGGVORBIS0x00020000 +
+

See Also

+FSOUND_Stream_Net_GetStatus +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMCALLBACK.html index 2520ab5e..7ec303d9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMCALLBACK.html @@ -1,86 +1,86 @@ - - - - -FSOUND_STREAMCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_STREAMCALLBACK

-Callback used with user streams.
-

-signed char F_CALLBACKAPI FSOUND_STREAMCALLBACK(
-FSOUND_STREAM *stream,
-void *buff,
-int len,
-void *userdata
-);
-

Parameters

- - - - - -
streamPointer to the stream in question.
-
bufffrom FSOUND_Stream_Create - Pointer to the stream data buffer to write to
-from FSOUND_Stream_SetEndCallback - NULL
-from FSOUND_Stream_SetSyncCallback - Pointer to a string
-
lenfrom FSOUND_Stream_Create - Length of buffer specified in BYTES.
-from FSOUND_Stream_SetEndCallback - 0
-from FSOUND_Stream_SetSyncCallback - 0
-
paramA user data value specified from FSOUND_Stream_Create,
-
-

Return Value

-If created by FSOUND_Stream_Create -
-To allow the stream to continue, TRUE is returned.
-To stop the stream, FALSE is returned.
-The return value is ignored if created by FSOUND_Stream_SetEndCallback or FSOUND_Stream_SetSyncCallback
---------------
-PlayStation 2 IMPORTANT! For user created streams only.
-The address for 'buff' is an IOP based address, you cannot directly access it.
-You have to use FSOUND_SendData to DMA your data from the EE to the IOP.
-if FSOUND_SendData is NOT called from this callback the IOP will hang because it is waiting for this command to be executed before it can unlock its buffer and send it to the SPU.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SendData -, -FSOUND_Stream_Create -, -FSOUND_Stream_SetEndCallback -, -FSOUND_Stream_SetSyncCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STREAMCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_STREAMCALLBACK

+Callback used with user streams.
+

+signed char F_CALLBACKAPI FSOUND_STREAMCALLBACK(
+FSOUND_STREAM *stream,
+void *buff,
+int len,
+void *userdata
+);
+

Parameters

+ + + + + +
streamPointer to the stream in question.
+
bufffrom FSOUND_Stream_Create - Pointer to the stream data buffer to write to
+from FSOUND_Stream_SetEndCallback - NULL
+from FSOUND_Stream_SetSyncCallback - Pointer to a string
+
lenfrom FSOUND_Stream_Create - Length of buffer specified in BYTES.
+from FSOUND_Stream_SetEndCallback - 0
+from FSOUND_Stream_SetSyncCallback - 0
+
paramA user data value specified from FSOUND_Stream_Create,
+
+

Return Value

+If created by FSOUND_Stream_Create -
+To allow the stream to continue, TRUE is returned.
+To stop the stream, FALSE is returned.
+The return value is ignored if created by FSOUND_Stream_SetEndCallback or FSOUND_Stream_SetSyncCallback
+--------------
+PlayStation 2 IMPORTANT! For user created streams only.
+The address for 'buff' is an IOP based address, you cannot directly access it.
+You have to use FSOUND_SendData to DMA your data from the EE to the IOP.
+if FSOUND_SendData is NOT called from this callback the IOP will hang because it is waiting for this command to be executed before it can unlock its buffer and send it to the SPU.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SendData +, +FSOUND_Stream_Create +, +FSOUND_Stream_SetEndCallback +, +FSOUND_Stream_SetSyncCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMINFO_TYPE.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMINFO_TYPE.html index dfa7037d..b2349d5e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMINFO_TYPE.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAMINFO_TYPE.html @@ -1,49 +1,49 @@ - - - - -FSOUND_STREAMINFO_TYPE - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - -Next Topic -
-
-
-
[Enum]
-

FSOUND_STREAMINFO_TYPE

-

-

Enumerators

- - - - - - -
FSOUND_STREAMINFO_VORBISCOMMENT
FSOUND_STREAMINFO_ID3V1
FSOUND_STREAMINFO_ID3V2
FSOUND_STREAMINFO_SHOUTCAST
FSOUND_STREAMINFO_ICECAST
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Tue Aug 19 16:56:56 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STREAMINFO_TYPE + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + +Next Topic +
+
+
+
[Enum]
+

FSOUND_STREAMINFO_TYPE

+

+

Enumerators

+ + + + + + +
FSOUND_STREAMINFO_VORBISCOMMENT
FSOUND_STREAMINFO_ID3V1
FSOUND_STREAMINFO_ID3V2
FSOUND_STREAMINFO_SHOUTCAST
FSOUND_STREAMINFO_ICECAST
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Tue Aug 19 16:56:56 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_FORMAT.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_FORMAT.html index c010b951..553f7ce6 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_FORMAT.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_FORMAT.html @@ -1,54 +1,54 @@ - - - - -FSOUND_STREAM_NET_FORMAT - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_STREAM_NET_FORMAT

-These are the format types referenced in the format field of the FSOUND_STREAM_NET_INFO structure.
-

-

Enumerators

- - - - -
FSOUND_STREAM_NET_FORMAT_UNKNOWN
FSOUND_STREAM_NET_FORMAT_MPEG
FSOUND_STREAM_NET_FORMAT_OGGVORBIS
-

See Also

-FSOUND_Stream_Net_GetInfo -, -FSOUND_STREAM_NET_INFO -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Jul 31 17:10:14 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STREAM_NET_FORMAT + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_STREAM_NET_FORMAT

+These are the format types referenced in the format field of the FSOUND_STREAM_NET_INFO structure.
+

+

Enumerators

+ + + + +
FSOUND_STREAM_NET_FORMAT_UNKNOWN
FSOUND_STREAM_NET_FORMAT_MPEG
FSOUND_STREAM_NET_FORMAT_OGGVORBIS
+

See Also

+FSOUND_Stream_Net_GetInfo +, +FSOUND_STREAM_NET_INFO +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Jul 31 17:10:14 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_INFO.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_INFO.html index 4f4fd638..c08ee102 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_INFO.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_INFO.html @@ -1,130 +1,130 @@ - - - - -FSOUND_STREAM_NET_INFO - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Structure]
-

FSOUND_STREAM_NET_INFO

-Structure providing information on an open internet stream.
-

-

Members

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
char *hostname/* Host that this stream is being served from */
-
char *remotefile/* Filename of this stream on the remote host */
-
intprotocol/* FSOUND_STREAM_NET_PROTOCOL - What protocol this stream is using */
-
intformat/* FSOUND_STREAM_NET_FORMAT - What file format this stream is using */
-
intstatus/* FSOUND_STREAM_NET_STATUS - Status of this stream - connecting, buffering etc. */
-
intbuffersize/* Size of the stream read buffer in bytes */
-
intbufferused/* How many bytes of data currently in the stream read buffer */
-
unsigned intsizebytes/* (HTTP Only) Size of the stream */
-
unsigned intbytesread/* How many compressed bytes have been read from the stream */
-
char **comments/* Pointer to an array of comment (metadata) strings */
-
intnumcomments/* How many comment (metadata) strings are in the array pointed to by 'comments' */
-
intmetadatanum/* Incremented each time a new batch of metadata is read */
-
char *notice1/* (SHOUTcast only) General notice sent by the server */
-
char *notice2/* (SHOUTcast only) General notice sent by the server */
-
char *name/* The name of the stream */
-
char *genre/* (SHOUTcast only) The genre of the stream */
-
char *description/* (Icecast2 only) A description of the stream */
-
char *url/* A URL associated with this stream */
-
char *irc/* An IRC channel associated with this stream */
-
char *icq/* An ICQ number associated with this stream */
-
char *aim/* An AIM number associated with this stream */
-
intpub/* 1 = this stream is public, 0 = this stream is not public */
-
intmetaint/* (SHOUTcast only) The number of compressed bytes between metadata chunks */
-
char *bitrate/* A string describing the bitrate of the stream i.e. "128" or "Quality 0" */
-
intcurrentbitrate/* The current (i.e. instantaneous) bitrate of the stream i.e. 128, 192, 187 etc. */
-
-

See Also

-FSOUND_STREAM_NET_FORMAT -, -FSOUND_Stream_Net_GetInfo -, -FSOUND_STREAM_NET_PROTOCOL -, -FSOUND_STREAM_NET_STATUS -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Jul 31 17:10:14 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STREAM_NET_INFO + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Structure]
+

FSOUND_STREAM_NET_INFO

+Structure providing information on an open internet stream.
+

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
char *hostname/* Host that this stream is being served from */
+
char *remotefile/* Filename of this stream on the remote host */
+
intprotocol/* FSOUND_STREAM_NET_PROTOCOL - What protocol this stream is using */
+
intformat/* FSOUND_STREAM_NET_FORMAT - What file format this stream is using */
+
intstatus/* FSOUND_STREAM_NET_STATUS - Status of this stream - connecting, buffering etc. */
+
intbuffersize/* Size of the stream read buffer in bytes */
+
intbufferused/* How many bytes of data currently in the stream read buffer */
+
unsigned intsizebytes/* (HTTP Only) Size of the stream */
+
unsigned intbytesread/* How many compressed bytes have been read from the stream */
+
char **comments/* Pointer to an array of comment (metadata) strings */
+
intnumcomments/* How many comment (metadata) strings are in the array pointed to by 'comments' */
+
intmetadatanum/* Incremented each time a new batch of metadata is read */
+
char *notice1/* (SHOUTcast only) General notice sent by the server */
+
char *notice2/* (SHOUTcast only) General notice sent by the server */
+
char *name/* The name of the stream */
+
char *genre/* (SHOUTcast only) The genre of the stream */
+
char *description/* (Icecast2 only) A description of the stream */
+
char *url/* A URL associated with this stream */
+
char *irc/* An IRC channel associated with this stream */
+
char *icq/* An ICQ number associated with this stream */
+
char *aim/* An AIM number associated with this stream */
+
intpub/* 1 = this stream is public, 0 = this stream is not public */
+
intmetaint/* (SHOUTcast only) The number of compressed bytes between metadata chunks */
+
char *bitrate/* A string describing the bitrate of the stream i.e. "128" or "Quality 0" */
+
intcurrentbitrate/* The current (i.e. instantaneous) bitrate of the stream i.e. 128, 192, 187 etc. */
+
+

See Also

+FSOUND_STREAM_NET_FORMAT +, +FSOUND_Stream_Net_GetInfo +, +FSOUND_STREAM_NET_PROTOCOL +, +FSOUND_STREAM_NET_STATUS +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Jul 31 17:10:14 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_PROTOCOL.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_PROTOCOL.html index 9522c306..84b4c06a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_PROTOCOL.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_PROTOCOL.html @@ -1,55 +1,55 @@ - - - - -FSOUND_STREAM_NET_PROTOCOL - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_STREAM_NET_PROTOCOL

-These are the protocol types referenced in the protocol field of the FSOUND_STREAM_NET_INFO structure.
-

-

Enumerators

- - - - - -
FSOUND_STREAM_NET_PROTOCOL_UNKNOWN
FSOUND_STREAM_NET_PROTOCOL_SHOUTCAST
FSOUND_STREAM_NET_PROTOCOL_ICECAST
FSOUND_STREAM_NET_PROTOCOL_HTTP
-

See Also

-FSOUND_Stream_Net_GetInfo -, -FSOUND_STREAM_NET_INFO -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Jul 31 17:10:14 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STREAM_NET_PROTOCOL + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_STREAM_NET_PROTOCOL

+These are the protocol types referenced in the protocol field of the FSOUND_STREAM_NET_INFO structure.
+

+

Enumerators

+ + + + + +
FSOUND_STREAM_NET_PROTOCOL_UNKNOWN
FSOUND_STREAM_NET_PROTOCOL_SHOUTCAST
FSOUND_STREAM_NET_PROTOCOL_ICECAST
FSOUND_STREAM_NET_PROTOCOL_HTTP
+

See Also

+FSOUND_Stream_Net_GetInfo +, +FSOUND_STREAM_NET_INFO +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Jul 31 17:10:14 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_STATUS.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_STATUS.html index 01ce1686..8d7c40e9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_STATUS.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_STREAM_NET_STATUS.html @@ -1,59 +1,59 @@ - - - - -FSOUND_STREAM_NET_STATUS - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Enum]
-

FSOUND_STREAM_NET_STATUS

-Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream.
-

-

Enumerators

- - - - - - -
FSOUND_STREAM_NET_NOTCONNECTED/* Stream hasn't connected yet */
-
FSOUND_STREAM_NET_CONNECTING/* Stream is connecting to remote host */
-
FSOUND_STREAM_NET_BUFFERING/* Stream is buffering data */
-
FSOUND_STREAM_NET_READY/* Stream is ready to play */
-
FSOUND_STREAM_NET_ERROR/* Stream has suffered a fatal error */
-
-

See Also

-FSOUND_Stream_Net_GetStatus -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_STREAM_NET_STATUS + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Enum]
+

FSOUND_STREAM_NET_STATUS

+Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream.
+

+

Enumerators

+ + + + + + +
FSOUND_STREAM_NET_NOTCONNECTED/* Stream hasn't connected yet */
+
FSOUND_STREAM_NET_CONNECTING/* Stream is connecting to remote host */
+
FSOUND_STREAM_NET_BUFFERING/* Stream is buffering data */
+
FSOUND_STREAM_NET_READY/* Stream is ready to play */
+
FSOUND_STREAM_NET_ERROR/* Stream has suffered a fatal error */
+
+

See Also

+FSOUND_Stream_Net_GetStatus +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Alloc.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Alloc.html index 45f9fb0f..8855ef10 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Alloc.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Alloc.html @@ -1,117 +1,117 @@ - - - - -FSOUND_Sample_Alloc - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Alloc

-Allocates a new empty sample. Used if you want to create a sample from scratch and fill the databuffer with your own data (using FSOUND_Sample_Lock or FSOUND_Sample_Upload), instead of just loading a file with FSOUND_Sample_Load.
-

-FSOUND_SAMPLE * F_API FSOUND_Sample_Alloc(
-int index,
-int length,
-unsigned int mode,
-int deffreq,
-int defvol,
-int defpan,
-int defpri
-);
-

Parameters

- - - - - - - - -
indexSample pool index. See remarks for more on the sample pool.
-0 or above - The absolute index into fsounds sample pool. The pool will grow as
-the index gets larger. If a slot is already used it will be replaced.
-FSOUND_FREE - Let FSOUND select an arbitrary sample slot.
-FSOUND_UNMANAGED - Dont have fsound free this sample upon FSOUND_Close
-
lengthThe length in of the sample buffer in SAMPLES.
-
modeBitfield describing various characteristics of the sample. Valid parameters are
-described in FSOUND_MODES.
-
deffreqDefault frequency for this sample.
-
defvolDefault volume for this sample.
-
defpanDefault pan for this sample.
-
defpriDefault priority for this sample.
-
-

Return Value

-On success, a pointer to an allocated sample is returned.
-On failure, NULL is returned.
-

Remarks

-FMOD has a sample management system that holds onto any samples loaded or allocated, and
-frees them all when you call FSOUND_Close. It takes the hassle out of having to keep hold
-of a lot of sample handles and remember to free them all at the end of your application.
-It is basically an expandle array of handles that holds each sample until FMOD closes down where it does
-a cleanup. FSOUND_UNMANAGED can be used NOT to use the sample management system.
-------------
-FSOUND_Sample_Alloc is only nescessary for lower level operations with sample data. Usually
-FSOUND_Load does the work for you. lower level operations mean such things as uploading data from memory or
-your own compressed data for example.
-You can create a new sample from scratch by doing the following operations
-1. Allocate a new sample with FSOUND_Sample_Alloc
-2. Write data to the sample buffer with FSOUND_Sample_Lock and FSOUND_Sample_Unlock, or
-FSOUND_Sample_Upload.
-Note FSOUND_Sample_Lock only returns a pointer to the sample data, whereas
-FSOUND_Sample_Upload does a copy from data you give it, with format conversion to the
-correct format.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_MODES -, -FSOUND_Sample_Alloc -, -FSOUND_Sample_Free -, -FSOUND_Sample_Load -, -FSOUND_Sample_Lock -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetLoopPoints -, -FSOUND_Sample_Unlock -, -FSOUND_Sample_Upload -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Alloc + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Alloc

+Allocates a new empty sample. Used if you want to create a sample from scratch and fill the databuffer with your own data (using FSOUND_Sample_Lock or FSOUND_Sample_Upload), instead of just loading a file with FSOUND_Sample_Load.
+

+FSOUND_SAMPLE * F_API FSOUND_Sample_Alloc(
+int index,
+int length,
+unsigned int mode,
+int deffreq,
+int defvol,
+int defpan,
+int defpri
+);
+

Parameters

+ + + + + + + + +
indexSample pool index. See remarks for more on the sample pool.
+0 or above - The absolute index into fsounds sample pool. The pool will grow as
+the index gets larger. If a slot is already used it will be replaced.
+FSOUND_FREE - Let FSOUND select an arbitrary sample slot.
+FSOUND_UNMANAGED - Dont have fsound free this sample upon FSOUND_Close
+
lengthThe length in of the sample buffer in SAMPLES.
+
modeBitfield describing various characteristics of the sample. Valid parameters are
+described in FSOUND_MODES.
+
deffreqDefault frequency for this sample.
+
defvolDefault volume for this sample.
+
defpanDefault pan for this sample.
+
defpriDefault priority for this sample.
+
+

Return Value

+On success, a pointer to an allocated sample is returned.
+On failure, NULL is returned.
+

Remarks

+FMOD has a sample management system that holds onto any samples loaded or allocated, and
+frees them all when you call FSOUND_Close. It takes the hassle out of having to keep hold
+of a lot of sample handles and remember to free them all at the end of your application.
+It is basically an expandle array of handles that holds each sample until FMOD closes down where it does
+a cleanup. FSOUND_UNMANAGED can be used NOT to use the sample management system.
+------------
+FSOUND_Sample_Alloc is only nescessary for lower level operations with sample data. Usually
+FSOUND_Load does the work for you. lower level operations mean such things as uploading data from memory or
+your own compressed data for example.
+You can create a new sample from scratch by doing the following operations
+1. Allocate a new sample with FSOUND_Sample_Alloc
+2. Write data to the sample buffer with FSOUND_Sample_Lock and FSOUND_Sample_Unlock, or
+FSOUND_Sample_Upload.
+Note FSOUND_Sample_Lock only returns a pointer to the sample data, whereas
+FSOUND_Sample_Upload does a copy from data you give it, with format conversion to the
+correct format.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_MODES +, +FSOUND_Sample_Alloc +, +FSOUND_Sample_Free +, +FSOUND_Sample_Load +, +FSOUND_Sample_Lock +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetLoopPoints +, +FSOUND_Sample_Unlock +, +FSOUND_Sample_Upload +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Free.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Free.html index cddeaf37..9d14e525 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Free.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Free.html @@ -1,61 +1,61 @@ - - - - -FSOUND_Sample_Free - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Free

-Removes a sample from memory and makes its slot available again.
-

-void F_API FSOUND_Sample_Free(
-FSOUND_SAMPLE *sptr
-);
-

Parameters

- - -
sptrPointer to the sample definition to be freed.
-
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_Alloc -, -FSOUND_Sample_Load -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Free + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Free

+Removes a sample from memory and makes its slot available again.
+

+void F_API FSOUND_Sample_Free(
+FSOUND_SAMPLE *sptr
+);
+

Parameters

+ + +
sptrPointer to the sample definition to be freed.
+
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_Alloc +, +FSOUND_Sample_Load +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Get.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Get.html index 2403f5e4..2e989a80 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Get.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Get.html @@ -1,61 +1,61 @@ - - - - -FSOUND_Sample_Get - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Get

-Returns a pointer to a managed sample based on the index passed.
-

-FSOUND_SAMPLE * F_API FSOUND_Sample_Get(
-int sampno
-);
-

Parameters

- - -
sampnoThe index in the sample management pool of the requested sample.
-
-

Return Value

-Pointer to a sample.
-

Remarks

-Samples that are not created with FSOUND_UNMANAGED are stored in a table inside FMOD.
-This way when FMOD can free all samples when FSOUND_Close is called and the user doesnt have to worry about cleaning up memory.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Get + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Get

+Returns a pointer to a managed sample based on the index passed.
+

+FSOUND_SAMPLE * F_API FSOUND_Sample_Get(
+int sampno
+);
+

Parameters

+ + +
sampnoThe index in the sample management pool of the requested sample.
+
+

Return Value

+Pointer to a sample.
+

Remarks

+Samples that are not created with FSOUND_UNMANAGED are stored in a table inside FMOD.
+This way when FMOD can free all samples when FSOUND_Close is called and the user doesnt have to worry about cleaning up memory.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaults.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaults.html index d57f2e53..4932bdc7 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaults.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaults.html @@ -1,77 +1,77 @@ - - - - -FSOUND_Sample_GetDefaults - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetDefaults

-Returns the default volume, frequency, pan and priority values for the specified sample.
-

-signed char F_API FSOUND_Sample_GetDefaults(
-FSOUND_SAMPLE *sptr,
-int *deffreq,
-int *defvol,
-int *defpan,
-int *defpri
-);
-

Parameters

- - - - - - -
sptrPointer to the sample to get the default information from.
-
deffreqPointer to value to be filled with the sample default frequency. Can be NULL.
-
defvolPointer to value to be filled with the sample default volume. Can be NULL.
-
defpanPointer to value to be filled with the sample default pan. Can be NULL.
-
defpriPointer to value to be filled with the sample default priority. Can be NULL.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Passing NULL in any of these parameters will result in the value being ignored.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_GetDefaultsEx -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetDefaults + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetDefaults

+Returns the default volume, frequency, pan and priority values for the specified sample.
+

+signed char F_API FSOUND_Sample_GetDefaults(
+FSOUND_SAMPLE *sptr,
+int *deffreq,
+int *defvol,
+int *defpan,
+int *defpri
+);
+

Parameters

+ + + + + + +
sptrPointer to the sample to get the default information from.
+
deffreqPointer to value to be filled with the sample default frequency. Can be NULL.
+
defvolPointer to value to be filled with the sample default volume. Can be NULL.
+
defpanPointer to value to be filled with the sample default pan. Can be NULL.
+
defpriPointer to value to be filled with the sample default priority. Can be NULL.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Passing NULL in any of these parameters will result in the value being ignored.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_GetDefaultsEx +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaultsEx.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaultsEx.html index 54bfc478..d1ce4ab0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaultsEx.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetDefaultsEx.html @@ -1,86 +1,86 @@ - - - - -FSOUND_Sample_GetDefaultsEx - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetDefaultsEx

-Returns the default volume, frequency, pan, priority and random playback variations for the specified sample.
-

-signed char F_API FSOUND_Sample_GetDefaultsEx(
-FSOUND_SAMPLE *sptr,
-int *deffreq,
-int *defvol,
-int *defpan,
-int *defpri,
-int *varfreq,
-int *varvol,
-int *varpan
-);
-

Parameters

- - - - - - - - - -
sptrPointer to the sample to get the default information from.
-
deffreqPointer to value to be filled with the sample default frequency. Can be NULL.
-
defvolPointer to value to be filled with the sample default volume. Can be NULL.
-
defpanPointer to value to be filled with the sample default pan. Can be NULL.
-
defpriPointer to value to be filled with the sample default priority. Can be NULL.
-
varfreqPointer to value to be filled with the sample random frequency variance. Can be NULL.
-
varvolPointer to value to be filled with the sample random volume variance. Can be NULL.
-
varpanPointer to value to be filled with the sample random pan variance. Can be NULL.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Passing NULL in any of these parameters will result in the value being ignored.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_GetDefaults -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetDefaultsEx + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetDefaultsEx

+Returns the default volume, frequency, pan, priority and random playback variations for the specified sample.
+

+signed char F_API FSOUND_Sample_GetDefaultsEx(
+FSOUND_SAMPLE *sptr,
+int *deffreq,
+int *defvol,
+int *defpan,
+int *defpri,
+int *varfreq,
+int *varvol,
+int *varpan
+);
+

Parameters

+ + + + + + + + + +
sptrPointer to the sample to get the default information from.
+
deffreqPointer to value to be filled with the sample default frequency. Can be NULL.
+
defvolPointer to value to be filled with the sample default volume. Can be NULL.
+
defpanPointer to value to be filled with the sample default pan. Can be NULL.
+
defpriPointer to value to be filled with the sample default priority. Can be NULL.
+
varfreqPointer to value to be filled with the sample random frequency variance. Can be NULL.
+
varvolPointer to value to be filled with the sample random volume variance. Can be NULL.
+
varpanPointer to value to be filled with the sample random pan variance. Can be NULL.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Passing NULL in any of these parameters will result in the value being ignored.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_GetDefaults +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLength.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLength.html index ce7b7abc..6dd9e49e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLength.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLength.html @@ -1,58 +1,58 @@ - - - - -FSOUND_Sample_GetLength - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetLength

-Returns the length of the sample in SAMPLES
-

-unsigned int F_API FSOUND_Sample_GetLength(
-FSOUND_SAMPLE *sptr
-);
-

Parameters

- - -
sptrPointer to the sample to get the length from.
-
-

Return Value

-On success, the length of sample in SAMPLES is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetLength + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetLength

+Returns the length of the sample in SAMPLES
+

+unsigned int F_API FSOUND_Sample_GetLength(
+FSOUND_SAMPLE *sptr
+);
+

Parameters

+ + +
sptrPointer to the sample to get the length from.
+
+

Return Value

+On success, the length of sample in SAMPLES is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLoopPoints.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLoopPoints.html index cb50a9fd..ce2297dd 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLoopPoints.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetLoopPoints.html @@ -1,74 +1,74 @@ - - - - -FSOUND_Sample_GetLoopPoints - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetLoopPoints

-Returns the start and end positions of the specified sample loop
-in SAMPLES (not bytes)
-

-DLL_API signed char F_API FSOUND_Sample_GetLoopPoints(
-FSOUND_SAMPLE *sptr,
-int *loopstart,
-int *loopend
-);
-

Parameters

- - - - -
sptrPointer to the sample to get the loop point information from.
-
loopstartPointer to value to be filled with the sample loop start point. Can be NULL.
-
loopendPointer to value to be filled with the sample loop end point. Can be NULL.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Passing NULL in any of these parameters will result in the value being ignored.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_Sample_SetLoopPoints -, -FSOUND_Sample_SetMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetLoopPoints + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetLoopPoints

+Returns the start and end positions of the specified sample loop
+in SAMPLES (not bytes)
+

+DLL_API signed char F_API FSOUND_Sample_GetLoopPoints(
+FSOUND_SAMPLE *sptr,
+int *loopstart,
+int *loopend
+);
+

Parameters

+ + + + +
sptrPointer to the sample to get the loop point information from.
+
loopstartPointer to value to be filled with the sample loop start point. Can be NULL.
+
loopendPointer to value to be filled with the sample loop end point. Can be NULL.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Passing NULL in any of these parameters will result in the value being ignored.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_Sample_SetLoopPoints +, +FSOUND_Sample_SetMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMinMaxDistance.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMinMaxDistance.html index 086b142f..9d81484d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMinMaxDistance.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMinMaxDistance.html @@ -1,72 +1,72 @@ - - - - -FSOUND_Sample_GetMinMaxDistance - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetMinMaxDistance

-Get the minimum and maximum audible distance for a sample.
-

-signed char F_API FSOUND_Sample_GetMinMaxDistance(
-FSOUND_SAMPLE *sptr,
-F_FLOAT_API *min,
-F_FLOAT_API *max
-);
-

Parameters

- - - - -
sptrThe sample to get minimum and maximum audible distance information from.
-
minPointer to value to be filled with the minimum volume distance for the sample. See remarks for more on units.
-
maxPointer to value to be filled with the maximum volume distance for the sample. See remarks for more on units.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
-The default units for minimum and maximum distances are 1.0 and 1000000000.0f.
-Volume drops off at mindistance / distance.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_SetDistanceFactor -, -FSOUND_Sample_SetMinMaxDistance -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetMinMaxDistance + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetMinMaxDistance

+Get the minimum and maximum audible distance for a sample.
+

+signed char F_API FSOUND_Sample_GetMinMaxDistance(
+FSOUND_SAMPLE *sptr,
+F_FLOAT_API *min,
+F_FLOAT_API *max
+);
+

Parameters

+ + + + +
sptrThe sample to get minimum and maximum audible distance information from.
+
minPointer to value to be filled with the minimum volume distance for the sample. See remarks for more on units.
+
maxPointer to value to be filled with the maximum volume distance for the sample. See remarks for more on units.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+The default units for minimum and maximum distances are 1.0 and 1000000000.0f.
+Volume drops off at mindistance / distance.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_SetDistanceFactor +, +FSOUND_Sample_SetMinMaxDistance +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMode.html index 1ea1d17b..bab89c14 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetMode.html @@ -1,70 +1,70 @@ - - - - -FSOUND_Sample_GetMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetMode

-Returns a bitfield containing information about the specified sample.
-The values can be bitwise AND'ed with the values contained in FSOUND_MODES to see if certain criteria are true or not.
-Information that can be retrieved from the same in this field are loop type, bitdepth and stereo/mono.
-

-unsigned int F_API FSOUND_Sample_GetMode(
-FSOUND_SAMPLE *sptr
-);
-

Parameters

- - -
sptrPointer to the sample to get the mode information on
-
-

Return Value

-On success, the sample mode is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_Sample_SetMode -, -FSOUND_SetLoopMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetMode

+Returns a bitfield containing information about the specified sample.
+The values can be bitwise AND'ed with the values contained in FSOUND_MODES to see if certain criteria are true or not.
+Information that can be retrieved from the same in this field are loop type, bitdepth and stereo/mono.
+

+unsigned int F_API FSOUND_Sample_GetMode(
+FSOUND_SAMPLE *sptr
+);
+

Parameters

+ + +
sptrPointer to the sample to get the mode information on
+
+

Return Value

+On success, the sample mode is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_Sample_SetMode +, +FSOUND_SetLoopMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetName.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetName.html index 2b1db925..09bdcb04 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetName.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_GetName.html @@ -1,60 +1,60 @@ - - - - -FSOUND_Sample_GetName - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_GetName

-Returns a pointer to a NULL terminated string containing the sample's name.
-

-const char * F_API FSOUND_Sample_GetName(
-FSOUND_SAMPLE *sptr
-);
-

Parameters

- - -
sptrPointer to the sample to get the name from.
-
-

Return Value

-On success, the name of the sample is returned.
-On failure, NULL is returned.
-

Remarks

-The name may not always make sense. From a MOD file it contains the sample text entered
-by the musician. For non descriptive file formats it just contains the filename.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_GetName + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_GetName

+Returns a pointer to a NULL terminated string containing the sample's name.
+

+const char * F_API FSOUND_Sample_GetName(
+FSOUND_SAMPLE *sptr
+);
+

Parameters

+ + +
sptrPointer to the sample to get the name from.
+
+

Return Value

+On success, the name of the sample is returned.
+On failure, NULL is returned.
+

Remarks

+The name may not always make sense. From a MOD file it contains the sample text entered
+by the musician. For non descriptive file formats it just contains the filename.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Load.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Load.html index adf9170e..d4bfbaf6 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Load.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Load.html @@ -1,98 +1,98 @@ - - - - -FSOUND_Sample_Load - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Load

-Loads and decodes a static soundfile into memory.
-This includes such files as .WAV, .MP2, .MP3, .OGG, .RAW and others.
-

-FSOUND_SAMPLE * F_API FSOUND_Sample_Load(
-int index,
-const char *name_or_data,
-unsigned int inputmode,
-int offset,
-int length
-);
-

Parameters

- - - - - - -
indexSample pool index. See remarks for more on the sample pool.
-0 or above - The absolute index into the sample pool. The pool will grow as the index gets larger. If a slot is already used it will be replaced.
-FSOUND_FREE - Let FSOUND select an arbitrary sample slot.
-FSOUND_UNMANAGED - Dont have this sample managed within fsounds sample management system
-
name_or_dataName of sound file or pointer to memory image to load.
-
modeDescription of the data format, OR in the bits defined in FSOUND_MODES to describe the data being loaded.
-
offsetOptional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening. length must also be specified if this value is used.
-
lengthOptional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
-
-

Return Value

-On success, a sample pointer is returned.
-On failure, NULL is returned.
-

Remarks

-FMOD has a sample management system that holds onto any samples loaded or allocated, and frees them all when you call FSOUND_Close.
-It takes the hassle out of having to keep hold of a lot of sample handles and remember to free them all at the end of your application.
-It is basically an expandle array of handles that holds each sample until FMOD closes down where it does a cleanup.
-FSOUND_UNMANAGED can be used so FMOD does NOT use the sample management system. You have to make sure they are freed yourself.
---------
-Specify FSOUND_LOADMEMORY to load a file from a memory image.
-The pointer you pass to name must be the actual image of the data you want to load.
-The length parameter is to be filled out if FSOUND_LOADMEMORY is specified, otherwise if you do not specify memory loading, can be safely ignored and should be set to 0.
---------
-Compressed formats are expanded into memory. If the file is quite large, it could take a while to load.
---------
-If FSOUND_8BITS is specified and the file decodes to 16bit normally, FMOD will downgrade the sample to 8bit.
---------
-On PlayStation 2, the name_or_data pointer and length variables must be 16 byte aligned, for DMA reasons.
---------
-Note that FSOUND_NONBLOCKING is NOT supported with this function.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_MODES -, -FSOUND_Sample_Alloc -, -FSOUND_Sample_Free -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Load + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Load

+Loads and decodes a static soundfile into memory.
+This includes such files as .WAV, .MP2, .MP3, .OGG, .RAW and others.
+

+FSOUND_SAMPLE * F_API FSOUND_Sample_Load(
+int index,
+const char *name_or_data,
+unsigned int inputmode,
+int offset,
+int length
+);
+

Parameters

+ + + + + + +
indexSample pool index. See remarks for more on the sample pool.
+0 or above - The absolute index into the sample pool. The pool will grow as the index gets larger. If a slot is already used it will be replaced.
+FSOUND_FREE - Let FSOUND select an arbitrary sample slot.
+FSOUND_UNMANAGED - Dont have this sample managed within fsounds sample management system
+
name_or_dataName of sound file or pointer to memory image to load.
+
modeDescription of the data format, OR in the bits defined in FSOUND_MODES to describe the data being loaded.
+
offsetOptional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening. length must also be specified if this value is used.
+
lengthOptional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
+
+

Return Value

+On success, a sample pointer is returned.
+On failure, NULL is returned.
+

Remarks

+FMOD has a sample management system that holds onto any samples loaded or allocated, and frees them all when you call FSOUND_Close.
+It takes the hassle out of having to keep hold of a lot of sample handles and remember to free them all at the end of your application.
+It is basically an expandle array of handles that holds each sample until FMOD closes down where it does a cleanup.
+FSOUND_UNMANAGED can be used so FMOD does NOT use the sample management system. You have to make sure they are freed yourself.
+--------
+Specify FSOUND_LOADMEMORY to load a file from a memory image.
+The pointer you pass to name must be the actual image of the data you want to load.
+The length parameter is to be filled out if FSOUND_LOADMEMORY is specified, otherwise if you do not specify memory loading, can be safely ignored and should be set to 0.
+--------
+Compressed formats are expanded into memory. If the file is quite large, it could take a while to load.
+--------
+If FSOUND_8BITS is specified and the file decodes to 16bit normally, FMOD will downgrade the sample to 8bit.
+--------
+On PlayStation 2, the name_or_data pointer and length variables must be 16 byte aligned, for DMA reasons.
+--------
+Note that FSOUND_NONBLOCKING is NOT supported with this function.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_MODES +, +FSOUND_Sample_Alloc +, +FSOUND_Sample_Free +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Lock.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Lock.html index c6838821..8c446270 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Lock.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Lock.html @@ -1,91 +1,91 @@ - - - - -FSOUND_Sample_Lock - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Lock

-Returns a pointer to the beginning of the sample data for a sample.
-Data written to these pointers must be signed.
-

-signed char F_API FSOUND_Sample_Lock(
-FSOUND_SAMPLE *sptr,
-int offset,
-int length,
-void **ptr1,
-void **ptr2,
-unsigned int *len1,
-unsigned int *len2
-);
-

Parameters

- - - - - - - - -
sptrPointer to the sample definition.
-
offsetOffset in BYTES to the position you want to lock in the sample buffer.
-
lengthNumber of BYTES you want to lock in the sample buffer.
-
ptr1Address of a pointer that will point to the first part of the locked data.
-
ptr2Address of a pointer that will point to the second part of the locked data.
-This will be NULL if the data locked hasnt wrapped at the end of the buffer.
-
len1Length of data in BYTES that was locked for ptr1
-
len2Length of data in BYTES that was locked for ptr2.
-This will be 0 if the data locked hasnt wrapped at the end of the buffer.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-You must always unlock the data again after you have finished with it, using FSOUND_Sample_Unlock.
-For PCM based samples, data must be signed 8 or 16bit. For compressed samples such as those created with FSOUND_IMAADPCM, FSOUND_VAG, FSOUND_GCADPCM, the data must be in its original compressed format.
-On PlayStation 2, with FSOUND_HW2D or FSOUND_HW3D based samples, this function does not return a readable or writable buffer, it returns the SPU2 address of the sample. To send data to it you must call FSOUND_SendData.
-On GameCube, with FSOUND_HW2D or FSOUND_HW3D based samples, this function will not return the data contained within the sample. It is for upload purposes only.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_Alloc -, -FSOUND_Sample_Unlock -, -FSOUND_Sample_Upload -, -FSOUND_SendData -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Lock + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Lock

+Returns a pointer to the beginning of the sample data for a sample.
+Data written to these pointers must be signed.
+

+signed char F_API FSOUND_Sample_Lock(
+FSOUND_SAMPLE *sptr,
+int offset,
+int length,
+void **ptr1,
+void **ptr2,
+unsigned int *len1,
+unsigned int *len2
+);
+

Parameters

+ + + + + + + + +
sptrPointer to the sample definition.
+
offsetOffset in BYTES to the position you want to lock in the sample buffer.
+
lengthNumber of BYTES you want to lock in the sample buffer.
+
ptr1Address of a pointer that will point to the first part of the locked data.
+
ptr2Address of a pointer that will point to the second part of the locked data.
+This will be NULL if the data locked hasnt wrapped at the end of the buffer.
+
len1Length of data in BYTES that was locked for ptr1
+
len2Length of data in BYTES that was locked for ptr2.
+This will be 0 if the data locked hasnt wrapped at the end of the buffer.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+You must always unlock the data again after you have finished with it, using FSOUND_Sample_Unlock.
+For PCM based samples, data must be signed 8 or 16bit. For compressed samples such as those created with FSOUND_IMAADPCM, FSOUND_VAG, FSOUND_GCADPCM, the data must be in its original compressed format.
+On PlayStation 2, with FSOUND_HW2D or FSOUND_HW3D based samples, this function does not return a readable or writable buffer, it returns the SPU2 address of the sample. To send data to it you must call FSOUND_SendData.
+On GameCube, with FSOUND_HW2D or FSOUND_HW3D based samples, this function will not return the data contained within the sample. It is for upload purposes only.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_Alloc +, +FSOUND_Sample_Unlock +, +FSOUND_Sample_Upload +, +FSOUND_SendData +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaults.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaults.html index 65cb6354..01ac5fc8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaults.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaults.html @@ -1,92 +1,92 @@ - - - - -FSOUND_Sample_SetDefaults - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_SetDefaults

-Sets a sample's default attributes, so when it is played it uses these values without having to specify them later.
-

-signed char F_API FSOUND_Sample_SetDefaults(
-FSOUND_SAMPLE *sptr,
-int deffreq,
-int defvol,
-int defpan,
-int defpri
-);
-

Parameters

- - - - - - -
sptrPointer to the sample to have its attributes set.
-
deffreqDefault sample frequency. The value here is specified in hz. -1 to ignore.
-
defvolDefault sample volume. This is a value from 0 to 255. -1 to ignore.
-
defpanDefault sample pan position. This is a value from 0 to 255 or FSOUND_STEREOPAN.
-
defpriDefault sample priority. This is a value from 0 to 255. -1 to ignore.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_Alloc -, -FSOUND_Sample_GetDefaults -, -FSOUND_Sample_GetDefaultsEx -, -FSOUND_Sample_GetLoopPoints -, -FSOUND_Sample_GetMode -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_Sample_SetMode -, -FSOUND_SetFrequency -, -FSOUND_SetPan -, -FSOUND_SetPriority -, -FSOUND_SetVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_SetDefaults + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_SetDefaults

+Sets a sample's default attributes, so when it is played it uses these values without having to specify them later.
+

+signed char F_API FSOUND_Sample_SetDefaults(
+FSOUND_SAMPLE *sptr,
+int deffreq,
+int defvol,
+int defpan,
+int defpri
+);
+

Parameters

+ + + + + + +
sptrPointer to the sample to have its attributes set.
+
deffreqDefault sample frequency. The value here is specified in hz. -1 to ignore.
+
defvolDefault sample volume. This is a value from 0 to 255. -1 to ignore.
+
defpanDefault sample pan position. This is a value from 0 to 255 or FSOUND_STEREOPAN.
+
defpriDefault sample priority. This is a value from 0 to 255. -1 to ignore.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_Alloc +, +FSOUND_Sample_GetDefaults +, +FSOUND_Sample_GetDefaultsEx +, +FSOUND_Sample_GetLoopPoints +, +FSOUND_Sample_GetMode +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_Sample_SetMode +, +FSOUND_SetFrequency +, +FSOUND_SetPan +, +FSOUND_SetPriority +, +FSOUND_SetVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaultsEx.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaultsEx.html index 758acf7d..57dd0054 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaultsEx.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetDefaultsEx.html @@ -1,98 +1,98 @@ - - - - -FSOUND_Sample_SetDefaultsEx - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_SetDefaultsEx

-Sets a sample's default attributes, so when it is played it uses these values without having to specify them later.
-

-signed char F_API FSOUND_Sample_SetDefaultsEx(
-FSOUND_SAMPLE *sptr,
-int deffreq,
-int defvol,
-int defpan,
-int defpri,
-int varfreq,
-int varvol,
-int varpan
-);
-

Parameters

- - - - - - - - - -
sptrPointer to the sample to have its attributes set.
-
deffreqDefault sample frequency. The value here is specified in hz. -1 to ignore.
-
defvolDefault sample volume. This is a value from 0 to 255. -1 to ignore.
-
defpanDefault sample pan position. This is a value from 0 to 255 or FSOUND_STEREOPAN.
-
defpriDefault sample priority. This is a value from 0 to 255. -1 to ignore.
-
varfreqFrequency variation in hz to apply to deffreq each time this sample is played. -1 to ignore.
-
varvolVolume variation to apply to defvol each time this sample is played. -1 to ignore.
-
varpanPan variation to apply to defpan each time this sample is played. -1 to ignore.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Frequency, volume and pan variation values specify a +/- variation to the specified default frequency, volume and pan values i.e. with deffreq=44100, varfreq=2000 the actual frequency value used will be in the range 42100 -> 46100.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_GetDefaults -, -FSOUND_Sample_GetDefaultsEx -, -FSOUND_Sample_GetLoopPoints -, -FSOUND_Sample_GetMode -, -FSOUND_Sample_SetDefaults -, -FSOUND_SetFrequency -, -FSOUND_SetPan -, -FSOUND_SetPriority -, -FSOUND_SetVolume -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_SetDefaultsEx + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_SetDefaultsEx

+Sets a sample's default attributes, so when it is played it uses these values without having to specify them later.
+

+signed char F_API FSOUND_Sample_SetDefaultsEx(
+FSOUND_SAMPLE *sptr,
+int deffreq,
+int defvol,
+int defpan,
+int defpri,
+int varfreq,
+int varvol,
+int varpan
+);
+

Parameters

+ + + + + + + + + +
sptrPointer to the sample to have its attributes set.
+
deffreqDefault sample frequency. The value here is specified in hz. -1 to ignore.
+
defvolDefault sample volume. This is a value from 0 to 255. -1 to ignore.
+
defpanDefault sample pan position. This is a value from 0 to 255 or FSOUND_STEREOPAN.
+
defpriDefault sample priority. This is a value from 0 to 255. -1 to ignore.
+
varfreqFrequency variation in hz to apply to deffreq each time this sample is played. -1 to ignore.
+
varvolVolume variation to apply to defvol each time this sample is played. -1 to ignore.
+
varpanPan variation to apply to defpan each time this sample is played. -1 to ignore.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Frequency, volume and pan variation values specify a +/- variation to the specified default frequency, volume and pan values i.e. with deffreq=44100, varfreq=2000 the actual frequency value used will be in the range 42100 -> 46100.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_GetDefaults +, +FSOUND_Sample_GetDefaultsEx +, +FSOUND_Sample_GetLoopPoints +, +FSOUND_Sample_GetMode +, +FSOUND_Sample_SetDefaults +, +FSOUND_SetFrequency +, +FSOUND_SetPan +, +FSOUND_SetPriority +, +FSOUND_SetVolume +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetLoopPoints.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetLoopPoints.html index 74ce3ce2..65a67c82 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetLoopPoints.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetLoopPoints.html @@ -1,74 +1,74 @@ - - - - -FSOUND_Sample_SetLoopPoints - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_SetLoopPoints

-Sets a sample's loop points, specified in SAMPLES, not bytes.
-

-signed char F_API FSOUND_Sample_SetLoopPoints(
-FSOUND_SAMPLE *sptr,
-int loopstart,
-int loopend
-);
-

Parameters

- - - - -
sptrPointer to the sample to have its loop points set.
-
loopstartThe starting position of the sample loop
-
loopendThe end position of the sample loop
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Samples created with FSOUND_HW3D and FSOUND_HW2D under the FSOUND_OUTPUT_DSOUND output mode do not support this function.
-Loop points set on such a sample with be ignored, and the sample will loop in its entirety. This is a limitation of DirectSound.
-On XBOX, GameCube and Playstation 2 hardware voices using compressed data (ie XADPCM, VAG or GCADPCM), these values will not be sample accurate, but will be rounded to the nearest compression block size.
-On PlayStation 2, the loopend is ignored. The hardware cannot change the end address, so the loopend is always equivalent to length - 1 no matter what you set.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_Alloc -, -FSOUND_Sample_GetLoopPoints -, -FSOUND_Sample_SetMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_SetLoopPoints + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_SetLoopPoints

+Sets a sample's loop points, specified in SAMPLES, not bytes.
+

+signed char F_API FSOUND_Sample_SetLoopPoints(
+FSOUND_SAMPLE *sptr,
+int loopstart,
+int loopend
+);
+

Parameters

+ + + + +
sptrPointer to the sample to have its loop points set.
+
loopstartThe starting position of the sample loop
+
loopendThe end position of the sample loop
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Samples created with FSOUND_HW3D and FSOUND_HW2D under the FSOUND_OUTPUT_DSOUND output mode do not support this function.
+Loop points set on such a sample with be ignored, and the sample will loop in its entirety. This is a limitation of DirectSound.
+On XBOX, GameCube and Playstation 2 hardware voices using compressed data (ie XADPCM, VAG or GCADPCM), these values will not be sample accurate, but will be rounded to the nearest compression block size.
+On PlayStation 2, the loopend is ignored. The hardware cannot change the end address, so the loopend is always equivalent to length - 1 no matter what you set.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_Alloc +, +FSOUND_Sample_GetLoopPoints +, +FSOUND_Sample_SetMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMaxPlaybacks.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMaxPlaybacks.html index 29632bdc..0e382ecf 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMaxPlaybacks.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMaxPlaybacks.html @@ -1,61 +1,61 @@ - - - - -FSOUND_Sample_SetMaxPlaybacks - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_SetMaxPlaybacks

-Sets the maximum number of times a sample can play back at once.
-

-signed char F_API FSOUND_Sample_SetMaxPlaybacks(
-FSOUND_SAMPLE *sptr,
-int max
-);
-

Parameters

- - -
sptrPointer to the sample to have its playback behaviour changed.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_PlaySound -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_SetMaxPlaybacks + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_SetMaxPlaybacks

+Sets the maximum number of times a sample can play back at once.
+

+signed char F_API FSOUND_Sample_SetMaxPlaybacks(
+FSOUND_SAMPLE *sptr,
+int max
+);
+

Parameters

+ + +
sptrPointer to the sample to have its playback behaviour changed.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_PlaySound +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMinMaxDistance.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMinMaxDistance.html index 3def4ce5..64f03318 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMinMaxDistance.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMinMaxDistance.html @@ -1,90 +1,90 @@ - - - - -FSOUND_Sample_SetMinMaxDistance - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_SetMinMaxDistance

-Sets the minimum and maximum audible distance for a sample.
-MinDistance is the minimum distance that the sound emitter will cease to continue growing
-louder at (as it approaches the listener). Within the mindistance it stays at the constant loudest volume possible. Outside of this mindistance it begins to attenuate.
-MaxDistance is the distance a sound stops attenuating at. Beyond this point it will stay at the volume it would be at maxdistance units from the listener and will not attenuate any more.
-MinDistance is useful to give the impression that the sound is loud or soft in 3d space. An example of this is a small quiet object, such as a bumblebee, which you could set a mindistance of to 0.1 for example, which would cause it to attenuate quickly and dissapear when only a few meters away from the listener.
-Another example is a jumbo jet, which you could set to a mindistance of 100.0, which would keep the sound volume at max until the listener was 100 meters away, then it would be hundreds of meters more before it would fade out.
--------
-In summary, increase the mindistance of a sound to make it 'louder' in a 3d world, and
-decrease it to make it 'quieter' in a 3d world.
-maxdistance is effectively obsolete unless you need the sound to stop fading out at a certain point. Do not adjust this from the default if you dont need to.
-Some people have the confusion that maxdistance is the point the sound will fade out to, this is not the case.
-

-signed char F_API FSOUND_Sample_SetMinMaxDistance(
-FSOUND_SAMPLE *sptr,
-F_FLOAT_API min,
-F_FLOAT_API max
-);
-

Parameters

- - - - -
sptrThe sample to have its minimum and maximum distance set.
-
minThe samples minimum volume distance in "units". See remarks for more on units.
-
maxThe samples maximum volume distance in "units". See remarks for more on units.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
-See FSOUND_3D_SetDistanceFactor for more on this.
-The default units for minimum and maximum distances are 1.0 and 1000000000.0f.
-Volume drops off at mindistance / distance.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_GetAttributes -, -FSOUND_3D_GetMinMaxDistance -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDistanceFactor -, -FSOUND_3D_SetMinMaxDistance -, -FSOUND_Sample_GetMinMaxDistance -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_SetMinMaxDistance + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_SetMinMaxDistance

+Sets the minimum and maximum audible distance for a sample.
+MinDistance is the minimum distance that the sound emitter will cease to continue growing
+louder at (as it approaches the listener). Within the mindistance it stays at the constant loudest volume possible. Outside of this mindistance it begins to attenuate.
+MaxDistance is the distance a sound stops attenuating at. Beyond this point it will stay at the volume it would be at maxdistance units from the listener and will not attenuate any more.
+MinDistance is useful to give the impression that the sound is loud or soft in 3d space. An example of this is a small quiet object, such as a bumblebee, which you could set a mindistance of to 0.1 for example, which would cause it to attenuate quickly and dissapear when only a few meters away from the listener.
+Another example is a jumbo jet, which you could set to a mindistance of 100.0, which would keep the sound volume at max until the listener was 100 meters away, then it would be hundreds of meters more before it would fade out.
+-------
+In summary, increase the mindistance of a sound to make it 'louder' in a 3d world, and
+decrease it to make it 'quieter' in a 3d world.
+maxdistance is effectively obsolete unless you need the sound to stop fading out at a certain point. Do not adjust this from the default if you dont need to.
+Some people have the confusion that maxdistance is the point the sound will fade out to, this is not the case.
+

+signed char F_API FSOUND_Sample_SetMinMaxDistance(
+FSOUND_SAMPLE *sptr,
+F_FLOAT_API min,
+F_FLOAT_API max
+);
+

Parameters

+ + + + +
sptrThe sample to have its minimum and maximum distance set.
+
minThe samples minimum volume distance in "units". See remarks for more on units.
+
maxThe samples maximum volume distance in "units". See remarks for more on units.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+A 'distance unit' is specified by FSOUND_3D_SetDistanceFactor. By default this is set to meters which is a distance scale of 1.0.
+See FSOUND_3D_SetDistanceFactor for more on this.
+The default units for minimum and maximum distances are 1.0 and 1000000000.0f.
+Volume drops off at mindistance / distance.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_GetAttributes +, +FSOUND_3D_GetMinMaxDistance +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDistanceFactor +, +FSOUND_3D_SetMinMaxDistance +, +FSOUND_Sample_GetMinMaxDistance +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMode.html index 3934af52..d9abf4ef 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_SetMode.html @@ -1,81 +1,81 @@ - - - - -FSOUND_Sample_SetMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_SetMode

-Sets a sample's mode. This can only be FSOUND_LOOP_OFF,FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI or FSOUND_2D.
-You cannot change the description of the contents of a sample or its location. FSOUND_2D will be ignored on the Win32 platform if FSOUND_HW3D was used to create the sample.
-

-signed char F_API FSOUND_Sample_SetMode(
-FSOUND_SAMPLE *sptr,
-unsigned int mode
-);
-

Parameters

- - - -
sptrPointer to the sample to have the mode set.
-
modeThe mode bits to set from FSOUND_MODES.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Only the following modes are accepted, others will be filtered out.
-FSOUND_LOOP_BIDI, FSOUND_LOOP_NORMAL, FSOUND_LOOP_OFF, FSOUND_2D.
-Normally FSOUND_2D is accepted only if the sound is software mixed. If this is not set, the mode is set for the sample to be 3D processed.
--------------------
-On Playstation 2, XBox and GameCube, FSOUND_HW2D and FSOUND_HW3D are supported, so you can change between them at runtime.
--------------------
-On Windows, samples created with FSOUND_HW3D or FSOUND_HW2D do not support FSOUND_LOOP_BIDI. This is a limitation of Direct X.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetLoopMode -, -FSOUND_MODES -, -FSOUND_Sample_GetLoopPoints -, -FSOUND_Sample_GetMode -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetLoopPoints -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_SetMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_SetMode

+Sets a sample's mode. This can only be FSOUND_LOOP_OFF,FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI or FSOUND_2D.
+You cannot change the description of the contents of a sample or its location. FSOUND_2D will be ignored on the Win32 platform if FSOUND_HW3D was used to create the sample.
+

+signed char F_API FSOUND_Sample_SetMode(
+FSOUND_SAMPLE *sptr,
+unsigned int mode
+);
+

Parameters

+ + + +
sptrPointer to the sample to have the mode set.
+
modeThe mode bits to set from FSOUND_MODES.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Only the following modes are accepted, others will be filtered out.
+FSOUND_LOOP_BIDI, FSOUND_LOOP_NORMAL, FSOUND_LOOP_OFF, FSOUND_2D.
+Normally FSOUND_2D is accepted only if the sound is software mixed. If this is not set, the mode is set for the sample to be 3D processed.
+-------------------
+On Playstation 2, XBox and GameCube, FSOUND_HW2D and FSOUND_HW3D are supported, so you can change between them at runtime.
+-------------------
+On Windows, samples created with FSOUND_HW3D or FSOUND_HW2D do not support FSOUND_LOOP_BIDI. This is a limitation of Direct X.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetLoopMode +, +FSOUND_MODES +, +FSOUND_Sample_GetLoopPoints +, +FSOUND_Sample_GetMode +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetLoopPoints +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Unlock.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Unlock.html index ab386cc2..1a4255e9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Unlock.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Unlock.html @@ -1,77 +1,77 @@ - - - - -FSOUND_Sample_Unlock - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Unlock

-Releases previous sample data lock from FSOUND_Sample_Lock
-

-signed char F_API FSOUND_Sample_Unlock(
-FSOUND_SAMPLE *sptr,
-void *ptr1,
-void *ptr2,
-unsigned int len1,
-unsigned int len2
-);
-

Parameters

- - - - - - -
sptrPointer to the sample definition.
-
ptr1Pointer to the 1st locked portion of sample data, from FSOUND_Sample_Lock.
-
ptr2Pointer to the 2nd locked portion of sample data, from FSOUND_Sample_Lock.
-
len1Length of data in BYTES that was locked for ptr1
-
len2Length of data in BYTES that was locked for ptr2.
-This will be 0 if the data locked hasnt wrapped at the end of the buffer.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_Alloc -, -FSOUND_Sample_Lock -, -FSOUND_Sample_Upload -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Unlock + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Unlock

+Releases previous sample data lock from FSOUND_Sample_Lock
+

+signed char F_API FSOUND_Sample_Unlock(
+FSOUND_SAMPLE *sptr,
+void *ptr1,
+void *ptr2,
+unsigned int len1,
+unsigned int len2
+);
+

Parameters

+ + + + + + +
sptrPointer to the sample definition.
+
ptr1Pointer to the 1st locked portion of sample data, from FSOUND_Sample_Lock.
+
ptr2Pointer to the 2nd locked portion of sample data, from FSOUND_Sample_Lock.
+
len1Length of data in BYTES that was locked for ptr1
+
len2Length of data in BYTES that was locked for ptr2.
+This will be 0 if the data locked hasnt wrapped at the end of the buffer.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_Alloc +, +FSOUND_Sample_Lock +, +FSOUND_Sample_Upload +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Upload.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Upload.html index 07a5289f..35cb140d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Upload.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Sample_Upload.html @@ -1,77 +1,77 @@ - - - - -FSOUND_Sample_Upload - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Sample_Upload

-This function uploads new sound data from memory to a preallocated/existing sample and does conversion based on the specified source mode.
-If sample data already exists at this handle then it is replaced with the new data being uploaded.
-

-signed char F_API FSOUND_Sample_Upload(
-FSOUND_SAMPLE *sptr,
-void *srcdata,
-unsigned int mode_in
-);
-

Parameters

- - - - -
sptrPointer to the destination sample
-
srcdataPointer to the source data to be uploaded. On PlayStation 2 this is an IOP address not an EE address.
-
modeDescription of the source data format. Bitwise OR in these bits to describe the data being passed in.
-See FSOUND_MODES for valid parameters and descriptions.
-FSOUND_HW3D, FSOUND_HW2D and FSOUND_LOOP modes are ignored, the mode describes the source format, not the destination format.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Note that on PlayStation 2 the source data address is an IOP address not an EE address.
-To get data from EE RAM to the sample you must allocate some IOP memory, dma it to IOP memory then call upload. There are helper functions in fmodps2.h to achieve this.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Sample_Alloc -, -FSOUND_Sample_Lock -, -FSOUND_Sample_Unlock -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:32 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Sample_Upload + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Sample_Upload

+This function uploads new sound data from memory to a preallocated/existing sample and does conversion based on the specified source mode.
+If sample data already exists at this handle then it is replaced with the new data being uploaded.
+

+signed char F_API FSOUND_Sample_Upload(
+FSOUND_SAMPLE *sptr,
+void *srcdata,
+unsigned int mode_in
+);
+

Parameters

+ + + + +
sptrPointer to the destination sample
+
srcdataPointer to the source data to be uploaded. On PlayStation 2 this is an IOP address not an EE address.
+
modeDescription of the source data format. Bitwise OR in these bits to describe the data being passed in.
+See FSOUND_MODES for valid parameters and descriptions.
+FSOUND_HW3D, FSOUND_HW2D and FSOUND_LOOP modes are ignored, the mode describes the source format, not the destination format.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Note that on PlayStation 2 the source data address is an IOP address not an EE address.
+To get data from EE RAM to the sample you must allocate some IOP memory, dma it to IOP memory then call upload. There are helper functions in fmodps2.h to achieve this.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Sample_Alloc +, +FSOUND_Sample_Lock +, +FSOUND_Sample_Unlock +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:32 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SendData.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SendData.html index 0eedb7a3..e67b2f45 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SendData.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SendData.html @@ -1,83 +1,83 @@ - - - - -FSOUND_SendData - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SendData

-DMA's data from EE to IOP.
-For DSP and stream callbacks use this function to get data to the IOP.
-

-signed char F_API FSOUND_SendData(
-void *iopaddr,
-void *eeaddr,
-int lenbytes,
-signed char wait,
-void (*callback)(void *param),
-void *param
-);
-

Parameters

- - - - - - - -
iopaddrdestination IOP Address.
-
eeaddrsource EE Address.
-
lenbytesLength of data block in bytes.
-
waitTRUE or FALSE value to determine wether to wait on the completion of DMA or not. Set to 0 from callbacks.
-
callbackCallback for completion of DMA.
-
paramUser data that will get passed back to the end of DMA callback.
-
-

Return Value

-src and lenbytes must be 16 byte aligned.
-

Remarks

-Usually only used with a user stream callback, to get your user data to the IOP address that FMOD provided.
-You can also allocate some IOP memory with FSOUND_IOP_Alloc if so desired.
-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_IOP_Alloc -, -FSOUND_Sample_Lock -, -FSOUND_Stream_Create -, -FSOUND_STREAMCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SendData + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SendData

+DMA's data from EE to IOP.
+For DSP and stream callbacks use this function to get data to the IOP.
+

+signed char F_API FSOUND_SendData(
+void *iopaddr,
+void *eeaddr,
+int lenbytes,
+signed char wait,
+void (*callback)(void *param),
+void *param
+);
+

Parameters

+ + + + + + + +
iopaddrdestination IOP Address.
+
eeaddrsource EE Address.
+
lenbytesLength of data block in bytes.
+
waitTRUE or FALSE value to determine wether to wait on the completion of DMA or not. Set to 0 from callbacks.
+
callbackCallback for completion of DMA.
+
paramUser data that will get passed back to the end of DMA callback.
+
+

Return Value

+src and lenbytes must be 16 byte aligned.
+

Remarks

+Usually only used with a user stream callback, to get your user data to the IOP address that FMOD provided.
+You can also allocate some IOP memory with FSOUND_IOP_Alloc if so desired.
+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_IOP_Alloc +, +FSOUND_Sample_Lock +, +FSOUND_Stream_Create +, +FSOUND_STREAMCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetBufferSize.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetBufferSize.html index d926e5df..c583fc46 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetBufferSize.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetBufferSize.html @@ -1,83 +1,83 @@ - - - - -FSOUND_SetBufferSize - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetBufferSize

-Sets the FMOD internal mixing buffer size.
-It is configurable because low buffersizes use less memory, but are more instable.
-More importantly, increasing buffer size will increase sound output stability, but
-on the other hand increases latency, and to some extent, CPU usage.
-* FMOD chooses the most optimal size by default for best stability, depending on the
-output type - and if the drivers are emulated or not (NT).
-It is not recommended changing this value unless you really need to. You may get worse
-performance than the default settings chosen by FMOD.
-

-signed char F_API FSOUND_SetBufferSize(
-int len_ms
-);
-

Parameters

- - -
len_msThe buffer size in milliseconds.
-
-

Return Value

-On success, TRUE is returned.
-On failure, (ie if FMOD is already active) FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
----------
-The buffersize seting defaults to 50ms if it is not called for DSOUND.
-It defaults to 200ms for Windows Multimedia wave-out or for emulated DirectSound drivers (such as NT drivers).
-When the output is FSOUND_OUTPUT_ASIO the buffersize is ignored. The buffersize should be configured using the ASIO driver which can be done with the supplied asioconfig.exe in the FMOD SDK.
----------
-Buffer sizes lower than 50 are clamped at 50.
-Buffer sizes are also rounded DOWN to the nearest multiple of 25. This is because FMOD mixes in blocks of 25ms.
-Due to this buffersize command latency on software channels will be between 25 and 50ms on average (37.5ms) when the buffersize is set to 50.
----------
-Macintosh, PlayStation 2 and GameCube do not support this as they already achieve minimal latency and are forced to 25ms.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, XBox
-

See Also

-FSOUND_Close -, -FSOUND_DSP_GetBufferLengthTotal -, -FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetBufferSize + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetBufferSize

+Sets the FMOD internal mixing buffer size.
+It is configurable because low buffersizes use less memory, but are more instable.
+More importantly, increasing buffer size will increase sound output stability, but
+on the other hand increases latency, and to some extent, CPU usage.
+* FMOD chooses the most optimal size by default for best stability, depending on the
+output type - and if the drivers are emulated or not (NT).
+It is not recommended changing this value unless you really need to. You may get worse
+performance than the default settings chosen by FMOD.
+

+signed char F_API FSOUND_SetBufferSize(
+int len_ms
+);
+

Parameters

+ + +
len_msThe buffer size in milliseconds.
+
+

Return Value

+On success, TRUE is returned.
+On failure, (ie if FMOD is already active) FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+---------
+The buffersize seting defaults to 50ms if it is not called for DSOUND.
+It defaults to 200ms for Windows Multimedia wave-out or for emulated DirectSound drivers (such as NT drivers).
+When the output is FSOUND_OUTPUT_ASIO the buffersize is ignored. The buffersize should be configured using the ASIO driver which can be done with the supplied asioconfig.exe in the FMOD SDK.
+---------
+Buffer sizes lower than 50 are clamped at 50.
+Buffer sizes are also rounded DOWN to the nearest multiple of 25. This is because FMOD mixes in blocks of 25ms.
+Due to this buffersize command latency on software channels will be between 25 and 50ms on average (37.5ms) when the buffersize is set to 50.
+---------
+Macintosh, PlayStation 2 and GameCube do not support this as they already achieve minimal latency and are forced to 25ms.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, XBox
+

See Also

+FSOUND_Close +, +FSOUND_DSP_GetBufferLengthTotal +, +FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetCurrentPosition.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetCurrentPosition.html index b4b4b7d5..0848f794 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetCurrentPosition.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetCurrentPosition.html @@ -1,68 +1,68 @@ - - - - -FSOUND_SetCurrentPosition - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetCurrentPosition

-Sets the current position of the sound in SAMPLES not bytes.
-

-signed char F_API FSOUND_SetCurrentPosition(
-int channel,
-unsigned int pos
-);
-

Parameters

- - - -
channelThe channel number/handle to have its offset or position set.
-
offsetThe offset in SAMPLES from the start of the sound for the position to be set to.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this set the current position for the sound on ALL channels available.
-On XBOX, GameCube and Playstation 2 hardware voices using compressed data (ie XADPCM, VAG or GCADPCM),
-this value will not be sample accurate, but will be rounded to the nearest compression block size.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetCurrentPosition -, -FSOUND_SetFrequency -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetCurrentPosition + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetCurrentPosition

+Sets the current position of the sound in SAMPLES not bytes.
+

+signed char F_API FSOUND_SetCurrentPosition(
+int channel,
+unsigned int pos
+);
+

Parameters

+ + + +
channelThe channel number/handle to have its offset or position set.
+
offsetThe offset in SAMPLES from the start of the sound for the position to be set to.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this set the current position for the sound on ALL channels available.
+On XBOX, GameCube and Playstation 2 hardware voices using compressed data (ie XADPCM, VAG or GCADPCM),
+this value will not be sample accurate, but will be rounded to the nearest compression block size.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetCurrentPosition +, +FSOUND_SetFrequency +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDiskBusy.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDiskBusy.html index 73589fe1..fdb48d71 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDiskBusy.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDiskBusy.html @@ -1,72 +1,72 @@ - - - - -FSOUND_SetDiskBusy - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetDiskBusy

-Tells FMOD that the user is accessing the disk, so that FMOD will wait until it is finished with it.
-This is essential for optimal game file access in cooperation with FMOD.
-

-void F_API FSOUND_SetDiskBusy(
-signed char diskbusy
-);
-

Parameters

- - -
diskbusyTRUE to tell FMOD the caller is about to access the disk. FALSE to tell FMOD it has finished with the disk.
-
-

Return Value

-

Remarks

-It is recommended to wrap FSOUND_SetDiskBusy(TRUE) and FSOUND_SetDiskBusy(FALSE) around all game file
-access functions.
---------------------
-Note if the user halts the disk access for longer than the buffersize set by FSOUND_Stream_SetBufferSize.
-Even less than this can cause skipping or corrupted sound, due to seeking and the actual time it takes to
-do the audio stream read in the stream subsystem.
-To avoid this it is recommended to split game reads up into chunks, to allow FMOD access to the disk periodically.
---------------------
-This function will block until FMOD is not using the disk any more.
-___________________
-Supported on the following platforms : PlayStation 2
-

See Also

-FSOUND_IsDiskBusy -, -FSOUND_SetDiskBusy -, -FSOUND_Stream_SetBufferSize -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetDiskBusy + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetDiskBusy

+Tells FMOD that the user is accessing the disk, so that FMOD will wait until it is finished with it.
+This is essential for optimal game file access in cooperation with FMOD.
+

+void F_API FSOUND_SetDiskBusy(
+signed char diskbusy
+);
+

Parameters

+ + +
diskbusyTRUE to tell FMOD the caller is about to access the disk. FALSE to tell FMOD it has finished with the disk.
+
+

Return Value

+

Remarks

+It is recommended to wrap FSOUND_SetDiskBusy(TRUE) and FSOUND_SetDiskBusy(FALSE) around all game file
+access functions.
+--------------------
+Note if the user halts the disk access for longer than the buffersize set by FSOUND_Stream_SetBufferSize.
+Even less than this can cause skipping or corrupted sound, due to seeking and the actual time it takes to
+do the audio stream read in the stream subsystem.
+To avoid this it is recommended to split game reads up into chunks, to allow FMOD access to the disk periodically.
+--------------------
+This function will block until FMOD is not using the disk any more.
+___________________
+Supported on the following platforms : PlayStation 2
+

See Also

+FSOUND_IsDiskBusy +, +FSOUND_SetDiskBusy +, +FSOUND_Stream_SetBufferSize +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDriver.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDriver.html index db73e3b0..ef269983 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDriver.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetDriver.html @@ -1,77 +1,77 @@ - - - - -FSOUND_SetDriver - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetDriver

-Selects a soundcard driver.
-It is used when an output mode has enumerated more than one output device, and you need to select between them.
-

-signed char F_API FSOUND_SetDriver(
-int driver
-);
-

Parameters

- - -
drivernoDriver number to select.
-0 will select the DEFAULT sound driver.
-<0 will select an INVALID driver which will case the DEVICE to be set
-to a null (nosound) driver.
->0 Selects other valid drivers that can be listed with FSOUND_GetDriverName.
-
-

Return Value

-On success, TRUE is returned.
-On failure, (ie if FMOD is already active) FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_GetDriver -, -FSOUND_GetDriverName -, -FSOUND_GetNumDrivers -, -FSOUND_Init -, -FSOUND_SetOutput -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetDriver + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetDriver

+Selects a soundcard driver.
+It is used when an output mode has enumerated more than one output device, and you need to select between them.
+

+signed char F_API FSOUND_SetDriver(
+int driver
+);
+

Parameters

+ + +
drivernoDriver number to select.
+0 will select the DEFAULT sound driver.
+<0 will select an INVALID driver which will case the DEVICE to be set
+to a null (nosound) driver.
+>0 Selects other valid drivers that can be listed with FSOUND_GetDriverName.
+
+

Return Value

+On success, TRUE is returned.
+On failure, (ie if FMOD is already active) FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_GetDriver +, +FSOUND_GetDriverName +, +FSOUND_GetNumDrivers +, +FSOUND_Init +, +FSOUND_SetOutput +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetFrequency.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetFrequency.html index e5626a6c..01188eb5 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetFrequency.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetFrequency.html @@ -1,96 +1,96 @@ - - - - -FSOUND_SetFrequency - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetFrequency

-Sets a channels frequency or playback rate, in HZ.
-

-signed char F_API FSOUND_SetFrequency(
-int channel,
-int freq
-);
-

Parameters

- - - -
channelThe channel number/handle to change the frequency for. FSOUND_ALL can also be used (see remarks).
-
freqThe frequency to set. Valid ranges are from 100 to 705600, and -100 to -705600.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported here. Passing this will set ALL channels to specified frequency.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-Negative frequencies make the sound play backwards, so FSOUND_SetCurrentPosition would be needed to set the sound to the right position.
----------
-NOTE: FSOUND_HW3D limitations in Direct Sound.
-Every hardware device has a minimum and maximum frequency. You can determine these by looking at the DirectSound caps and viewing the members dwMaxSecondarySampleRate and dwMaxSecondarySampleRate.
-FMOD clamps frequencies to these values when playing back on hardware, so if you are setting the frequency outside of this range, the frequency will stay at either dwMinSecondarySampleRate or dwMaxSecondarySampleRate.
-To find out these two values in fmod (maybe whether to decide to drop back to software mixing or not), you can use the following code.
----------
-include <dsound.h>
-int minhwfreq, maxhwfreq;
-if (FSOUND_GetNumHardwareChannels() && FSOUND_GetOutput() == FSOUND_OUTPUT_DSOUND)
-{
-HRESULT hr;
-DSCAPS dscaps;
-memset(&dscaps, 0, sizeof(DSCAPS));
-dscaps.dwSize = sizeof(DSCAPS);
-hr = IDirectSound_GetCaps((LPDIRECTSOUND)FSOUND_GetOutputHandle(), &dscaps);
-minhwfreq = dscaps.dwMinSecondarySampleRate;
-maxhwfreq = dscaps.dwMaxSecondarySampleRate;
-}
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_MixBuffers -, -FSOUND_GetFrequency -, -FSOUND_GetOutput -, -FSOUND_GetOutputHandle -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_SetCurrentPosition -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetFrequency + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetFrequency

+Sets a channels frequency or playback rate, in HZ.
+

+signed char F_API FSOUND_SetFrequency(
+int channel,
+int freq
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the frequency for. FSOUND_ALL can also be used (see remarks).
+
freqThe frequency to set. Valid ranges are from 100 to 705600, and -100 to -705600.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported here. Passing this will set ALL channels to specified frequency.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+Negative frequencies make the sound play backwards, so FSOUND_SetCurrentPosition would be needed to set the sound to the right position.
+---------
+NOTE: FSOUND_HW3D limitations in Direct Sound.
+Every hardware device has a minimum and maximum frequency. You can determine these by looking at the DirectSound caps and viewing the members dwMaxSecondarySampleRate and dwMaxSecondarySampleRate.
+FMOD clamps frequencies to these values when playing back on hardware, so if you are setting the frequency outside of this range, the frequency will stay at either dwMinSecondarySampleRate or dwMaxSecondarySampleRate.
+To find out these two values in fmod (maybe whether to decide to drop back to software mixing or not), you can use the following code.
+---------
+include <dsound.h>
+int minhwfreq, maxhwfreq;
+if (FSOUND_GetNumHardwareChannels() && FSOUND_GetOutput() == FSOUND_OUTPUT_DSOUND)
+{
+HRESULT hr;
+DSCAPS dscaps;
+memset(&dscaps, 0, sizeof(DSCAPS));
+dscaps.dwSize = sizeof(DSCAPS);
+hr = IDirectSound_GetCaps((LPDIRECTSOUND)FSOUND_GetOutputHandle(), &dscaps);
+minhwfreq = dscaps.dwMinSecondarySampleRate;
+maxhwfreq = dscaps.dwMaxSecondarySampleRate;
+}
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_MixBuffers +, +FSOUND_GetFrequency +, +FSOUND_GetOutput +, +FSOUND_GetOutputHandle +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_SetCurrentPosition +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetHWND.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetHWND.html index eb87b7d5..4a027d3c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetHWND.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetHWND.html @@ -1,68 +1,68 @@ - - - - -FSOUND_SetHWND - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetHWND

-This is an optional function to set the window handle of the application
-you are writing, so Directsound can tell if it is in focus or not.
-

-signed char F_API FSOUND_SetHWND(
-void *hwnd
-);
-

Parameters

- - -
hwndPointer to a HWND windows handle of your application.
-NULL means it will pick the foreground application window.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
----------
-FMOD uses GetForegroundWindow if this function is not called.
-___________________
-Supported on the following platforms : Win32, WinCE
-

See Also

-FSOUND_Close -, -FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetHWND + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetHWND

+This is an optional function to set the window handle of the application
+you are writing, so Directsound can tell if it is in focus or not.
+

+signed char F_API FSOUND_SetHWND(
+void *hwnd
+);
+

Parameters

+ + +
hwndPointer to a HWND windows handle of your application.
+NULL means it will pick the foreground application window.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+---------
+FMOD uses GetForegroundWindow if this function is not called.
+___________________
+Supported on the following platforms : Win32, WinCE
+

See Also

+FSOUND_Close +, +FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLevels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLevels.html index 5f729bd5..05339b27 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLevels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLevels.html @@ -1,84 +1,84 @@ - - - - -FSOUND_SetLevels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetLevels

-XBox Only - For surround sound systems, this function allows each surround speaker level to be set individually for this channel.
-

-signed char F_API FSOUND_SetLevels(
-int channel,
-int frontleft,
-int center,
-int frontright,
-int backleft,
-int backright,
-int lfe
-);
-

Parameters

- - - - - - - - -
channelThe channel number/handle to change the output levels for. FSOUND_ALL and FSOUND_SYSTEMCHANNEL can also be used (see remarks)
-
frontleftValue from 0 to 255 inclusive, specifying a linear level for the front left speaker.
-
centerValue from 0 to 255 inclusive, specifying a linear level for the center.
-
frontrightValue from 0 to 255 inclusive, specifying a linear level for the front right speaker.
-
backleftValue from 0 to 255 inclusive, specifying a linear level for the back left speaker.
-
backrightValue from 0 to 255 inclusive, specifying a linear level for the back right speaker.
-
lfeValue from 0 to 255 inclusive, specifying a linear level for the subwoofer speaker.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the pan of ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-----------
-FSOUND_SYSTEMCHANNEL is supported. You can set the mix levels for the FMOD software engine, and ALL software mixed sounds will be affected.
-___________________
-Supported on the following platforms : XBox
-

See Also

-FSOUND_GetPan -, -FSOUND_Reverb_SetChannelProperties -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetLevels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetLevels

+XBox Only - For surround sound systems, this function allows each surround speaker level to be set individually for this channel.
+

+signed char F_API FSOUND_SetLevels(
+int channel,
+int frontleft,
+int center,
+int frontright,
+int backleft,
+int backright,
+int lfe
+);
+

Parameters

+ + + + + + + + +
channelThe channel number/handle to change the output levels for. FSOUND_ALL and FSOUND_SYSTEMCHANNEL can also be used (see remarks)
+
frontleftValue from 0 to 255 inclusive, specifying a linear level for the front left speaker.
+
centerValue from 0 to 255 inclusive, specifying a linear level for the center.
+
frontrightValue from 0 to 255 inclusive, specifying a linear level for the front right speaker.
+
backleftValue from 0 to 255 inclusive, specifying a linear level for the back left speaker.
+
backrightValue from 0 to 255 inclusive, specifying a linear level for the back right speaker.
+
lfeValue from 0 to 255 inclusive, specifying a linear level for the subwoofer speaker.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the pan of ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+----------
+FSOUND_SYSTEMCHANNEL is supported. You can set the mix levels for the FMOD software engine, and ALL software mixed sounds will be affected.
+___________________
+Supported on the following platforms : XBox
+

See Also

+FSOUND_GetPan +, +FSOUND_Reverb_SetChannelProperties +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLoopMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLoopMode.html index a2560950..f4a0027c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLoopMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetLoopMode.html @@ -1,66 +1,66 @@ - - - - -FSOUND_SetLoopMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetLoopMode

-Sets the loop mode for a particular CHANNEL, not sample.
-

-signed char F_API FSOUND_SetLoopMode(
-int channel,
-unsigned int loopmode
-);
-

Parameters

- - - -
channelThe channel number/handle to have its loop mode set.
-
loopmodeThe loopmode to set. This can be FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI or FSOUND_LOOP_OFF.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set loop modes for all channels available.
-Note, this does not work for hardware sounds played on hardware channels while they are playing. The function has to be called when the channel is paused.
-Software based sounds do not have this limitation, and can have their loop mode changed during playback, but for compatibility it is best to use the pause method, else you may get different behaviour if hardware voices do not exist.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Sample_GetMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetLoopMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetLoopMode

+Sets the loop mode for a particular CHANNEL, not sample.
+

+signed char F_API FSOUND_SetLoopMode(
+int channel,
+unsigned int loopmode
+);
+

Parameters

+ + + +
channelThe channel number/handle to have its loop mode set.
+
loopmodeThe loopmode to set. This can be FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI or FSOUND_LOOP_OFF.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set loop modes for all channels available.
+Note, this does not work for hardware sounds played on hardware channels while they are playing. The function has to be called when the channel is paused.
+Software based sounds do not have this limitation, and can have their loop mode changed during playback, but for compatibility it is best to use the pause method, else you may get different behaviour if hardware voices do not exist.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Sample_GetMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMaxHardwareChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMaxHardwareChannels.html index 74ce476a..30fef617 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMaxHardwareChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMaxHardwareChannels.html @@ -1,71 +1,71 @@ - - - - -FSOUND_SetMaxHardwareChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetMaxHardwareChannels

-This sets the maximum allocatable channels on a hardware card. FMOD automatically detects and allocates the maximum number of 3d hardware channels, so calling this will limit that number if it becomes too much.
-

-DLL_API signed char F_API FSOUND_SetMaxHardwareChannels(
-int max
-);
-

Parameters

- - -
maxThe maximum number of hardware channels to allocate, even if the soundcard supports more.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
----------
-This function has nothing to do with FSOUND_SetMinHardwareChannels, in that this is not a function that forces FMOD into software mixing if a card has a certain number of channels.
-This function only sets a limit on hardware channels, so if your card has 96 hardware channels, and you set FSOUND_SetMaxHardwareChannels(10), then you will only have 10 hardware channels to use.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_Init -, -FSOUND_SetMaxHardwareChannels -, -FSOUND_SetMinHardwareChannels -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetMaxHardwareChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetMaxHardwareChannels

+This sets the maximum allocatable channels on a hardware card. FMOD automatically detects and allocates the maximum number of 3d hardware channels, so calling this will limit that number if it becomes too much.
+

+DLL_API signed char F_API FSOUND_SetMaxHardwareChannels(
+int max
+);
+

Parameters

+ + +
maxThe maximum number of hardware channels to allocate, even if the soundcard supports more.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+---------
+This function has nothing to do with FSOUND_SetMinHardwareChannels, in that this is not a function that forces FMOD into software mixing if a card has a certain number of channels.
+This function only sets a limit on hardware channels, so if your card has 96 hardware channels, and you set FSOUND_SetMaxHardwareChannels(10), then you will only have 10 hardware channels to use.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_Init +, +FSOUND_SetMaxHardwareChannels +, +FSOUND_SetMinHardwareChannels +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMemorySystem.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMemorySystem.html index 37bb73e3..452757f9 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMemorySystem.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMemorySystem.html @@ -1,101 +1,101 @@ - - - - -FSOUND_SetMemorySystem - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetMemorySystem

-Specifies a method for FMOD to allocate memory, either through callbacks or its own internal memory management. You can also supply a pool of memory for FMOD to work with and it will do so with no extra calls to malloc or free.
-This is useful for systems that want FMOD to use their own memory management, or fixed memory devices such as PocketPC, XBox, PS2 and GameCube that dont want any allocations occuring out of their control causing fragmentation or unpredictable overflows in a tight memory space.
-See remarks for more useful information.
-

-DLL_API signed char F_API FSOUND_SetMemorySystem(
-void *poolmem,
-int poollen,
-FSOUND_ALLOCCALLBACK useralloc,
-FSOUND_REALLOCCALLBACK userrealloc,
-FSOUND_FREECALLBACK userfree
-);
-

Parameters

- - - - - - -
poolIf you want a fixed block of memory for FMOD to use, pass it in here. Specify the length in poollen. Specifying NULL doesnt use internal management and it relies on callbacks.
-
poollenLength in bytes of the pool of memory for FMOD to use specified in. Specifying 0 turns off internal memory management and relies purely on callbacks. Length must be a multiple of 512.
-
userallocOnly supported if pool is NULL. Otherwise it overrides the FMOD internal calls to alloc. Compatible with ansi malloc().
-
userreallocOnly supported if pool is NULL. Otherwise it overrides the FMOD internal calls to realloc. Compatible with ansi realloc().
-
userfreeOnly supported if pool is NULL. Otherwise it overrides the FMOD internal calls to free. Compatible with ansi free().
-
-

Return Value

-void
-

Remarks

-FMOD has been tested to stay in a limit and fail gracefully if the fixed pool size is not large enough with FMOD_ERR_MEMORY errors.
-FMOD only does allocation when creating streams, music or samples and the FSOUND_Init stage. It never allocates or deallocates memory during the course of runtime processing.
-To find out the required fixed size the user can call FSOUND_GetMemoryStats with a larger than nescessary pool size (or no pool), and find out the maximum ram usage at any one time within FMOD.
--------------------------------------
-FMOD behaves differently based on what you pass into this function in 3 different combinations.
-Here are the examples.
-NULL, 0, NULL, NULL, NULL : Falls back purely to ansi C malloc, realloc and free.
-NULL, 0, myalloc, myrealloc, myfree : Calls user supplied callbacks every time fmod does a memory allocation or deallocation.
-ptr, len, NULL, NULL, NULL : Uses "ptr" and manages memory internally. NO extra mallocs or frees are performed from this point.
--------------------------------------
-Callbacks and memory pools cannot be combined, as if a pool is specified FMOD, manipulates the pool of memory internally with its own allocate and free scheme.
-The memory management algorithm to work within a fixed size of ram is extremely efficient and faster than the standard C malloc or free.
--------------------------------------
-On XBox you MUST specify a pointer and length. The memory provided must be enough to store all sample data.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_ALLOCCALLBACK -, -FSOUND_Close -, -FSOUND_FREECALLBACK -, -FSOUND_GetFreeHWRam -, -FSOUND_GetMemoryStats -, -FSOUND_Init -, -FSOUND_IOP_Alloc -, -FSOUND_REALLOCCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetMemorySystem + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetMemorySystem

+Specifies a method for FMOD to allocate memory, either through callbacks or its own internal memory management. You can also supply a pool of memory for FMOD to work with and it will do so with no extra calls to malloc or free.
+This is useful for systems that want FMOD to use their own memory management, or fixed memory devices such as PocketPC, XBox, PS2 and GameCube that dont want any allocations occuring out of their control causing fragmentation or unpredictable overflows in a tight memory space.
+See remarks for more useful information.
+

+DLL_API signed char F_API FSOUND_SetMemorySystem(
+void *poolmem,
+int poollen,
+FSOUND_ALLOCCALLBACK useralloc,
+FSOUND_REALLOCCALLBACK userrealloc,
+FSOUND_FREECALLBACK userfree
+);
+

Parameters

+ + + + + + +
poolIf you want a fixed block of memory for FMOD to use, pass it in here. Specify the length in poollen. Specifying NULL doesnt use internal management and it relies on callbacks.
+
poollenLength in bytes of the pool of memory for FMOD to use specified in. Specifying 0 turns off internal memory management and relies purely on callbacks. Length must be a multiple of 512.
+
userallocOnly supported if pool is NULL. Otherwise it overrides the FMOD internal calls to alloc. Compatible with ansi malloc().
+
userreallocOnly supported if pool is NULL. Otherwise it overrides the FMOD internal calls to realloc. Compatible with ansi realloc().
+
userfreeOnly supported if pool is NULL. Otherwise it overrides the FMOD internal calls to free. Compatible with ansi free().
+
+

Return Value

+void
+

Remarks

+FMOD has been tested to stay in a limit and fail gracefully if the fixed pool size is not large enough with FMOD_ERR_MEMORY errors.
+FMOD only does allocation when creating streams, music or samples and the FSOUND_Init stage. It never allocates or deallocates memory during the course of runtime processing.
+To find out the required fixed size the user can call FSOUND_GetMemoryStats with a larger than nescessary pool size (or no pool), and find out the maximum ram usage at any one time within FMOD.
+-------------------------------------
+FMOD behaves differently based on what you pass into this function in 3 different combinations.
+Here are the examples.
+NULL, 0, NULL, NULL, NULL : Falls back purely to ansi C malloc, realloc and free.
+NULL, 0, myalloc, myrealloc, myfree : Calls user supplied callbacks every time fmod does a memory allocation or deallocation.
+ptr, len, NULL, NULL, NULL : Uses "ptr" and manages memory internally. NO extra mallocs or frees are performed from this point.
+-------------------------------------
+Callbacks and memory pools cannot be combined, as if a pool is specified FMOD, manipulates the pool of memory internally with its own allocate and free scheme.
+The memory management algorithm to work within a fixed size of ram is extremely efficient and faster than the standard C malloc or free.
+-------------------------------------
+On XBox you MUST specify a pointer and length. The memory provided must be enough to store all sample data.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_ALLOCCALLBACK +, +FSOUND_Close +, +FSOUND_FREECALLBACK +, +FSOUND_GetFreeHWRam +, +FSOUND_GetMemoryStats +, +FSOUND_Init +, +FSOUND_IOP_Alloc +, +FSOUND_REALLOCCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMinHardwareChannels.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMinHardwareChannels.html index 404daefc..0eaa5061 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMinHardwareChannels.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMinHardwareChannels.html @@ -1,74 +1,74 @@ - - - - -FSOUND_SetMinHardwareChannels - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetMinHardwareChannels

-This sets the minimum allowable hardware channels before FMOD drops back to 100 percent software.
-This is helpful for minimum spec cards, and not having to guess how many hardware channels
-they might have. This way you can guarantee and assume a certain number of channels for
-your application and place them all in FSOUND_HW3D without fear of the playsound failing
-because it runs out of channels on a low spec card.
-

-DLL_API signed char F_API FSOUND_SetMinHardwareChannels(
-int min
-);
-

Parameters

- - -
minThe minimum number of hardware channels allowable on a card before it uses the software engine 1004562604f the time.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
----------
-As an example, if you set your minimum to 16, you can now safely guarantee that 16 sounds can be played at once that are created with FSOUND_HW3D.
-This way if you do come across a card that only supports 4 channels, it will just drop back to playing ALL sounds in software mode.
-It may sound worse, but at least it doesnt fail on the playsound. (which could sound even worse!)
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_Init -, -FSOUND_SetMaxHardwareChannels -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetMinHardwareChannels + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetMinHardwareChannels

+This sets the minimum allowable hardware channels before FMOD drops back to 100 percent software.
+This is helpful for minimum spec cards, and not having to guess how many hardware channels
+they might have. This way you can guarantee and assume a certain number of channels for
+your application and place them all in FSOUND_HW3D without fear of the playsound failing
+because it runs out of channels on a low spec card.
+

+DLL_API signed char F_API FSOUND_SetMinHardwareChannels(
+int min
+);
+

Parameters

+ + +
minThe minimum number of hardware channels allowable on a card before it uses the software engine 1004562604f the time.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+---------
+As an example, if you set your minimum to 16, you can now safely guarantee that 16 sounds can be played at once that are created with FSOUND_HW3D.
+This way if you do come across a card that only supports 4 channels, it will just drop back to playing ALL sounds in software mode.
+It may sound worse, but at least it doesnt fail on the playsound. (which could sound even worse!)
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_Init +, +FSOUND_SetMaxHardwareChannels +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMixer.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMixer.html index d5a7bc99..b5279b11 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMixer.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMixer.html @@ -1,72 +1,72 @@ - - - - -FSOUND_SetMixer - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetMixer

-Sets a digital mixer type.
-

-signed char F_API FSOUND_SetMixer(
-int mixer
-);
-

Parameters

- - -
mixermixer type, see FSOUND_MIXERTYPES for valid parameters and descriptions.
-
-

Return Value

-On success, TRUE is returned.
-On failure, (ie if FMOD is already active) FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
-This function does not nescessarily need to be called, autodetection will select the
-fastest mixer for your machine. It is here if you need to test all mixer types for
-debugging purposes, or a mixer has a feature that the autodetected one doesnt.
-(ie low quality mixers or volume ramping)
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_GetMixer -, -FSOUND_Init -, -FSOUND_MIXERTYPES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetMixer + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetMixer

+Sets a digital mixer type.
+

+signed char F_API FSOUND_SetMixer(
+int mixer
+);
+

Parameters

+ + +
mixermixer type, see FSOUND_MIXERTYPES for valid parameters and descriptions.
+
+

Return Value

+On success, TRUE is returned.
+On failure, (ie if FMOD is already active) FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+This function does not nescessarily need to be called, autodetection will select the
+fastest mixer for your machine. It is here if you need to test all mixer types for
+debugging purposes, or a mixer has a feature that the autodetected one doesnt.
+(ie low quality mixers or volume ramping)
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_GetMixer +, +FSOUND_Init +, +FSOUND_MIXERTYPES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMute.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMute.html index b6514e59..745b8344 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMute.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetMute.html @@ -1,65 +1,65 @@ - - - - -FSOUND_SetMute - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetMute

-Mutes and un-mutes a channel.
-

-signed char F_API FSOUND_SetMute(
-int channel,
-signed char mute
-);
-

Parameters

- - - -
channelThe channel number/handle to mute/unmute. FSOUND_ALL can also be used (see remarks).
-
muteToggle value - TRUE mutes out the channel, FALSE reenables it.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will mute/unmute ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetMute -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetMute + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetMute

+Mutes and un-mutes a channel.
+

+signed char F_API FSOUND_SetMute(
+int channel,
+signed char mute
+);
+

Parameters

+ + + +
channelThe channel number/handle to mute/unmute. FSOUND_ALL can also be used (see remarks).
+
muteToggle value - TRUE mutes out the channel, FALSE reenables it.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will mute/unmute ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetMute +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetOutput.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetOutput.html index 62aae470..d8d2187c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetOutput.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetOutput.html @@ -1,84 +1,84 @@ - - - - -FSOUND_SetOutput - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetOutput

-Sets up the soundsystem output mode.
-

-signed char F_API FSOUND_SetOutput(
-int outputtype
-);
-

Parameters

- - -
outputtypeThe output system to be used. See FSOUND_OUTPUTTYPES for valid parameters and descriptions. -1 Is autodetect based on operating system.
-
-

Return Value

-On success, TRUE is returned.
-On failure, (ie if FMOD is already active) FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
--------
-Under Windows NT - Waveout is FASTER than DirectSound, achieves LOWER latency, AND
-is LESS buggy. DirectSound under NT is achieved by emulating waveout, and therefore is
-inferior to waveout. Use WAVEOUT under NT.
-Under Windows 9x and W2K - DirectSound is faster than waveout and can achieve lower latency.
-Use DIRECTSOUND under Win9x and W2K.
--------
-If you dont call FSOUND_SetOutput, FMOD will now autodetect DSOUND or WINMM based on the operating system.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_GetDriverCaps -, -FSOUND_GetOutput -, -FSOUND_GetOutputHandle -, -FSOUND_Init -, -FSOUND_OUTPUTTYPES -, -FSOUND_SetDriver -, -FSOUND_SetOutput -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:33 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetOutput + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetOutput

+Sets up the soundsystem output mode.
+

+signed char F_API FSOUND_SetOutput(
+int outputtype
+);
+

Parameters

+ + +
outputtypeThe output system to be used. See FSOUND_OUTPUTTYPES for valid parameters and descriptions. -1 Is autodetect based on operating system.
+
+

Return Value

+On success, TRUE is returned.
+On failure, (ie if FMOD is already active) FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+-------
+Under Windows NT - Waveout is FASTER than DirectSound, achieves LOWER latency, AND
+is LESS buggy. DirectSound under NT is achieved by emulating waveout, and therefore is
+inferior to waveout. Use WAVEOUT under NT.
+Under Windows 9x and W2K - DirectSound is faster than waveout and can achieve lower latency.
+Use DIRECTSOUND under Win9x and W2K.
+-------
+If you dont call FSOUND_SetOutput, FMOD will now autodetect DSOUND or WINMM based on the operating system.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_GetDriverCaps +, +FSOUND_GetOutput +, +FSOUND_GetOutputHandle +, +FSOUND_Init +, +FSOUND_OUTPUTTYPES +, +FSOUND_SetDriver +, +FSOUND_SetOutput +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:33 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPan.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPan.html index 3e107057..7eab3176 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPan.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPan.html @@ -1,90 +1,90 @@ - - - - -FSOUND_SetPan - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetPan

-Sets a channels pan position linearly
-

-signed char F_API FSOUND_SetPan(
-int channel,
-int pan
-);
-

Parameters

- - - -
channelThe channel number/handle to change the pan for. FSOUND_ALL can also be used (see remarks)
-
panThe panning position for this channel to set.
-parameters are:
-- from 0 (full left) to 255 (full right)
-- FSOUND_STEREOPAN. This is meant for stereo samples, but will work on mono
-samples as well. It makes both left and right FULL volume instead of 50/50
-as middle panning does. See remarks section for more information on this.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the pan of ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-----------
-Important : If you are playing a STEREO sample, and using normal middle panning, it will only come out at half the volume
-they are supposed to. To avoid this use FSOUND_STEREO pan.
-Panning works in the following manner:
-full left : 100to left, 0to right
-full right : 0to left, 100to right
-middle : 71to left, 71to right
-FMOD Uses 'constant power' panning. The center position is 71 4749584n each channel as it keeps an even RMS output level when
-moving the sound from left to right. Placing 50 4749584n each channel for a middle position is incorrect.
-The pan graph for constant power panning resembles a curve instead of straight lines.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_MixBuffers -, -FSOUND_GetPan -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetPan + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetPan

+Sets a channels pan position linearly
+

+signed char F_API FSOUND_SetPan(
+int channel,
+int pan
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the pan for. FSOUND_ALL can also be used (see remarks)
+
panThe panning position for this channel to set.
+parameters are:
+- from 0 (full left) to 255 (full right)
+- FSOUND_STEREOPAN. This is meant for stereo samples, but will work on mono
+samples as well. It makes both left and right FULL volume instead of 50/50
+as middle panning does. See remarks section for more information on this.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the pan of ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+----------
+Important : If you are playing a STEREO sample, and using normal middle panning, it will only come out at half the volume
+they are supposed to. To avoid this use FSOUND_STEREO pan.
+Panning works in the following manner:
+full left : 100to left, 0to right
+full right : 0to left, 100to right
+middle : 71to left, 71to right
+FMOD Uses 'constant power' panning. The center position is 71 4749584n each channel as it keeps an even RMS output level when
+moving the sound from left to right. Placing 50 4749584n each channel for a middle position is incorrect.
+The pan graph for constant power panning resembles a curve instead of straight lines.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_MixBuffers +, +FSOUND_GetPan +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPanSeperation.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPanSeperation.html index 06bb9bf4..34b27620 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPanSeperation.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPanSeperation.html @@ -1,67 +1,67 @@ - - - - -FSOUND_SetPanSeperation - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetPanSeperation

-Sets the master pan seperation for 2d sound effects.
-

-DLL_API void F_API FSOUND_SetPanSeperation(
-F_FLOAT_API pansep
-);
-

Parameters

- - -
pansepThe pan scalar. 1.0 means full pan seperation, 0 means mono.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This is set to 1.0 by default.
-Music is not affected by this. To change pan seperation for music files individually,
-see FMUSIC_SetPanSeperation
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetPanSeperation -, -FSOUND_GetSpeakerMode -, -FSOUND_SetSpeakerMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetPanSeperation + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetPanSeperation

+Sets the master pan seperation for 2d sound effects.
+

+DLL_API void F_API FSOUND_SetPanSeperation(
+F_FLOAT_API pansep
+);
+

Parameters

+ + +
pansepThe pan scalar. 1.0 means full pan seperation, 0 means mono.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This is set to 1.0 by default.
+Music is not affected by this. To change pan seperation for music files individually,
+see FMUSIC_SetPanSeperation
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetPanSeperation +, +FSOUND_GetSpeakerMode +, +FSOUND_SetSpeakerMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPaused.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPaused.html index 2fec6bb4..d97f5e40 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPaused.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPaused.html @@ -1,71 +1,71 @@ - - - - -FSOUND_SetPaused - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetPaused

-Pauses or unpauses a sound channel.
-

-signed char F_API FSOUND_SetPaused(
-int channel,
-signed char paused
-);
-

Parameters

- - - -
channelThe channel number/handle to pause or unpause. FSOUND_ALL can also be used (see remarks).
-
pausedTRUE pauses this channel, FALSE unpauses it.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will pause/unpause ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_FX_Enable -, -FSOUND_GetPaused -, -FSOUND_PlaySoundEx -, -FSOUND_Stream_PlayEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetPaused + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetPaused

+Pauses or unpauses a sound channel.
+

+signed char F_API FSOUND_SetPaused(
+int channel,
+signed char paused
+);
+

Parameters

+ + + +
channelThe channel number/handle to pause or unpause. FSOUND_ALL can also be used (see remarks).
+
pausedTRUE pauses this channel, FALSE unpauses it.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will pause/unpause ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_FX_Enable +, +FSOUND_GetPaused +, +FSOUND_PlaySoundEx +, +FSOUND_Stream_PlayEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPriority.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPriority.html index 3911b778..b3879db5 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPriority.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetPriority.html @@ -1,75 +1,75 @@ - - - - -FSOUND_SetPriority - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetPriority

-Sets a channels priority. Higher priority means it is less likely to get discarded when
-FSOUND_FREE is used to select a channel, when all channels are being used, and one has to
-be rejected. If a channel has an equal priority then it will be replaced.
-

-signed char F_API FSOUND_SetPriority(
-int channel,
-int priority
-);
-

Parameters

- - - -
channelThe channel number/handle to change the priority for. FSOUND_ALL can also be used (see remarks).
-
priorityThe priority to set. Valid ranges are from 0 (lowest) to 255 (highest)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the priority of ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetPriority -, -FSOUND_GetReserved -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_SetReserved -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetPriority + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetPriority

+Sets a channels priority. Higher priority means it is less likely to get discarded when
+FSOUND_FREE is used to select a channel, when all channels are being used, and one has to
+be rejected. If a channel has an equal priority then it will be replaced.
+

+signed char F_API FSOUND_SetPriority(
+int channel,
+int priority
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the priority for. FSOUND_ALL can also be used (see remarks).
+
priorityThe priority to set. Valid ranges are from 0 (lowest) to 255 (highest)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the priority of ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetPriority +, +FSOUND_GetReserved +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_SetReserved +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetReserved.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetReserved.html index 08bbf8c8..4b79ec3f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetReserved.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetReserved.html @@ -1,78 +1,78 @@ - - - - -FSOUND_SetReserved - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetReserved

-This sets the reserved status of a channel. Reserving a channel is related to setting its
-priority, but reserving a channel means it can NEVER be stolen by a channel request. It
-could be thought of as an extra high priority, but is different in that reserved channels do
-not steal from each other, whereas channels with equal priorities do (unless there are
-channels with lower priorities that it can steal from). If all channels were reserved and
-another request for came in for a channel, it would simply fail and the sound would not be
-played.
-

-signed char F_API FSOUND_SetReserved(
-int channel,
-signed char reserved
-);
-

Parameters

- - - -
channelThe channel number/handle to change the priority for.
-FSOUND_ALL can also be used (see remarks).
-FSOUND_FREE is NOT accepted.
-
reservedReserved flag. Values accepted are TRUE, to reserve a channel, and FALSE to
-un-reserve a channel.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set ALL channels to be reserved/unreserved.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetPriority -, -FSOUND_GetReserved -, -FSOUND_SetPriority -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetReserved + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetReserved

+This sets the reserved status of a channel. Reserving a channel is related to setting its
+priority, but reserving a channel means it can NEVER be stolen by a channel request. It
+could be thought of as an extra high priority, but is different in that reserved channels do
+not steal from each other, whereas channels with equal priorities do (unless there are
+channels with lower priorities that it can steal from). If all channels were reserved and
+another request for came in for a channel, it would simply fail and the sound would not be
+played.
+

+signed char F_API FSOUND_SetReserved(
+int channel,
+signed char reserved
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the priority for.
+FSOUND_ALL can also be used (see remarks).
+FSOUND_FREE is NOT accepted.
+
reservedReserved flag. Values accepted are TRUE, to reserve a channel, and FALSE to
+un-reserve a channel.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set ALL channels to be reserved/unreserved.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetPriority +, +FSOUND_GetReserved +, +FSOUND_SetPriority +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSFXMasterVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSFXMasterVolume.html index 77558671..25b3c1f5 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSFXMasterVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSFXMasterVolume.html @@ -1,64 +1,64 @@ - - - - -FSOUND_SetSFXMasterVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetSFXMasterVolume

-Sets the master volume for any sound effects played. Does not affect music or CD output.
-

-DLL_API void F_API FSOUND_SetSFXMasterVolume(
-int volume
-);
-

Parameters

- - -
volumeThe volume to set. Valid ranges are from 0 (silent) to 255 (full volume)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FMUSIC_SetMasterVolume -, -FSOUND_SetVolume -, -FSOUND_SetVolumeAbsolute -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetSFXMasterVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetSFXMasterVolume

+Sets the master volume for any sound effects played. Does not affect music or CD output.
+

+DLL_API void F_API FSOUND_SetSFXMasterVolume(
+int volume
+);
+

Parameters

+ + +
volumeThe volume to set. Valid ranges are from 0 (silent) to 255 (full volume)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FMUSIC_SetMasterVolume +, +FSOUND_SetVolume +, +FSOUND_SetVolumeAbsolute +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSpeakerMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSpeakerMode.html index 78c0ff03..b506255e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSpeakerMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSpeakerMode.html @@ -1,83 +1,83 @@ - - - - -FSOUND_SetSpeakerMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetSpeakerMode

-Sets the mode for the users speaker setup.
-

-void F_API FSOUND_SetSpeakerMode(
-unsigned int speakermode
-);
-

Parameters

- - -
speakermodeThis is an enum describing the users speaker setup.
-
-

Return Value

-void
-

Remarks

-Note - Only reliably works with FSOUND_OUTPUT_DSOUND on windows, or consoles such as PlayStation 2, GameCube and XBox.
-For other output types speaker mode only interprets FSOUND_SPEAKERMODE_MONO, everything else is interpreted as stere.
-----------------------------------
-To get true 5.1 dolby digital or DTS output you will need a soundcard that can encode it, and a receiver that can decode it.
-----------------------------------
-Calling this will reset the pan separation setting. It sets it to 0 if FSOUND_SPEAKERMODE_MONO is chosen, and 1 otherwise.
-You will need to reset the pan separation if required afterwards.
-----------------------------------
-XBOX
-This function must be called before FSOUND_Init to change the default speaker mode. To change on the fly, you must close down FMOD with FSOUND_Close then re-initialize it with FSOUND_Init.
-If it is called after FSOUND_Init, only headphone speakermode is interpreted to switch headphone mode on and off.
-By default the dashboard setting is used for the speakermode. It is not recommend you change this mode unless you let the user change it in-game.
-----------------------------------
-PlayStation 2.
-Only mono/stereo and prologic 2 modes are interpreted. Dolby digital or DTS are not supported.
-This function must be called before playing sounds. Calling this after playing a sound will not make that existing sound work in Prologic 2.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Close -, -FSOUND_GetSpeakerMode -, -FSOUND_Init -, -FSOUND_SetPanSeperation -, -FSOUND_SPEAKERMODES -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetSpeakerMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetSpeakerMode

+Sets the mode for the users speaker setup.
+

+void F_API FSOUND_SetSpeakerMode(
+unsigned int speakermode
+);
+

Parameters

+ + +
speakermodeThis is an enum describing the users speaker setup.
+
+

Return Value

+void
+

Remarks

+Note - Only reliably works with FSOUND_OUTPUT_DSOUND on windows, or consoles such as PlayStation 2, GameCube and XBox.
+For other output types speaker mode only interprets FSOUND_SPEAKERMODE_MONO, everything else is interpreted as stere.
+----------------------------------
+To get true 5.1 dolby digital or DTS output you will need a soundcard that can encode it, and a receiver that can decode it.
+----------------------------------
+Calling this will reset the pan separation setting. It sets it to 0 if FSOUND_SPEAKERMODE_MONO is chosen, and 1 otherwise.
+You will need to reset the pan separation if required afterwards.
+----------------------------------
+XBOX
+This function must be called before FSOUND_Init to change the default speaker mode. To change on the fly, you must close down FMOD with FSOUND_Close then re-initialize it with FSOUND_Init.
+If it is called after FSOUND_Init, only headphone speakermode is interpreted to switch headphone mode on and off.
+By default the dashboard setting is used for the speakermode. It is not recommend you change this mode unless you let the user change it in-game.
+----------------------------------
+PlayStation 2.
+Only mono/stereo and prologic 2 modes are interpreted. Dolby digital or DTS are not supported.
+This function must be called before playing sounds. Calling this after playing a sound will not make that existing sound work in Prologic 2.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Close +, +FSOUND_GetSpeakerMode +, +FSOUND_Init +, +FSOUND_SetPanSeperation +, +FSOUND_SPEAKERMODES +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSurround.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSurround.html index cb6654c0..c0430ada 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSurround.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetSurround.html @@ -1,70 +1,70 @@ - - - - -FSOUND_SetSurround - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetSurround

-Sets a channels surround sound status. This surround sound is a fake dolby trick that
-effectively pans the channel to the center, but inverts the waveform in one speaker to
-make it sound fuller or spacier, or like it is coming out of space between the 2 speakers.
-Panning is ignored while surround is in effect.
-

-signed char F_API FSOUND_SetSurround(
-int channel,
-signed char surround
-);
-

Parameters

- - - -
channelThe channel number/handle to change the surround for. FSOUND_ALL can also be used (see remarks).
-
surroundToggle value - TRUE enables surround sound on the channel, FALSE disables it.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the surround sound mode of ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
----------
-Note this only works on software channels.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation2, GameCube
-

See Also

-FSOUND_GetSurround -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetSurround + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetSurround

+Sets a channels surround sound status. This surround sound is a fake dolby trick that
+effectively pans the channel to the center, but inverts the waveform in one speaker to
+make it sound fuller or spacier, or like it is coming out of space between the 2 speakers.
+Panning is ignored while surround is in effect.
+

+signed char F_API FSOUND_SetSurround(
+int channel,
+signed char surround
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the surround for. FSOUND_ALL can also be used (see remarks).
+
surroundToggle value - TRUE enables surround sound on the channel, FALSE disables it.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the surround sound mode of ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+---------
+Note this only works on software channels.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation2, GameCube
+

See Also

+FSOUND_GetSurround +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolume.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolume.html index e621f97d..319b5613 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolume.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolume.html @@ -1,84 +1,84 @@ - - - - -FSOUND_SetVolume - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetVolume

-Sets a channels volume linearly.
-This function IS affected by FSOUND_SetSFXMasterVolume.
-

-signed char F_API FSOUND_SetVolume(
-int channel,
-int vol
-);
-

Parameters

- - - -
channelThe channel number/handle to change the volume for. FSOUND_ALL can also be used (see remarks)
-
volThe volume to set. Valid ranges are from 0 (silent) to 255 (full volume)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the volume of ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_DSP_MixBuffers -, -FSOUND_GetAmplitude -, -FSOUND_GetSubChannel -, -FSOUND_GetVolume -, -FSOUND_Sample_SetDefaults -, -FSOUND_Sample_SetDefaultsEx -, -FSOUND_SetSFXMasterVolume -, -FSOUND_SetVolumeAbsolute -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetVolume + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetVolume

+Sets a channels volume linearly.
+This function IS affected by FSOUND_SetSFXMasterVolume.
+

+signed char F_API FSOUND_SetVolume(
+int channel,
+int vol
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the volume for. FSOUND_ALL can also be used (see remarks)
+
volThe volume to set. Valid ranges are from 0 (silent) to 255 (full volume)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the volume of ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_DSP_MixBuffers +, +FSOUND_GetAmplitude +, +FSOUND_GetSubChannel +, +FSOUND_GetVolume +, +FSOUND_Sample_SetDefaults +, +FSOUND_Sample_SetDefaultsEx +, +FSOUND_SetSFXMasterVolume +, +FSOUND_SetVolumeAbsolute +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolumeAbsolute.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolumeAbsolute.html index 09c67591..54480c92 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolumeAbsolute.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SetVolumeAbsolute.html @@ -1,80 +1,80 @@ - - - - -FSOUND_SetVolumeAbsolute - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SetVolumeAbsolute

-Sets a channels volume linearly.
-This function is NOT affected by master volume.
-This function is used when you want to quiet everything down using FSOUND_SetSFXMasterVolume, but make
-a channel prominent.
-

-signed char F_API FSOUND_SetVolumeAbsolute(
-int channel,
-int vol
-);
-

Parameters

- - - -
channelThe channel number/handle to change the volume for. FSOUND_ALL can also be used (see remarks)
-
volThe volume to set. Valid ranges are from 0 (silent) to 255 (full volume)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will set the absolute volume of ALL channels available.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
--------------
-A good example of this function being used for a game needing a voice over.
-If all the background sounds were too loud and drowned out the voice over, there is no way to
-feasibly go through all the sfx channels and lower the background noise volumes (some might be allocated by music).
-Simply lower the background noise with FSOUND_SetSFXMasterVolume, and use FSOUND_SetVolumeAbsolute to bring
-up the volume of the voice over to full, and you will get one channel standing out amongst the rest.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetVolume -, -FSOUND_SetSFXMasterVolume -, -FSOUND_SetVolume -, -FSOUND_SetVolumeAbsolute -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:34 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SetVolumeAbsolute + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SetVolumeAbsolute

+Sets a channels volume linearly.
+This function is NOT affected by master volume.
+This function is used when you want to quiet everything down using FSOUND_SetSFXMasterVolume, but make
+a channel prominent.
+

+signed char F_API FSOUND_SetVolumeAbsolute(
+int channel,
+int vol
+);
+

Parameters

+ + + +
channelThe channel number/handle to change the volume for. FSOUND_ALL can also be used (see remarks)
+
volThe volume to set. Valid ranges are from 0 (silent) to 255 (full volume)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will set the absolute volume of ALL channels available.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+-------------
+A good example of this function being used for a game needing a voice over.
+If all the background sounds were too loud and drowned out the voice over, there is no way to
+feasibly go through all the sfx channels and lower the background noise volumes (some might be allocated by music).
+Simply lower the background noise with FSOUND_SetSFXMasterVolume, and use FSOUND_SetVolumeAbsolute to bring
+up the volume of the voice over to full, and you will get one channel standing out amongst the rest.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetVolume +, +FSOUND_SetSFXMasterVolume +, +FSOUND_SetVolume +, +FSOUND_SetVolumeAbsolute +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:34 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SpecifyEffectsImage.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SpecifyEffectsImage.html index 098e5788..f1e1eb96 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SpecifyEffectsImage.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_SpecifyEffectsImage.html @@ -1,66 +1,66 @@ - - - - -FSOUND_SpecifyEffectsImage - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_SpecifyEffectsImage

-XBOX ONLY
-Specifies the location of dsstdfx.bin
-Otherwise FMOD will choose a default location of d:\\media\\dsstdfx.bin
-

-void F_API FSOUND_SpecifyEffectsImage(
-char *name
-);
-

Parameters

- - -
nameLocation of DSSTDFX.BIN.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function cannot be called after FMOD is already activated with FSOUND_Init.
-It must be called before FSOUND_Init, or after FSOUND_Close.
-___________________
-Supported on the following platforms : XBox
-

See Also

-FSOUND_Close -, -FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Wed Jul 02 10:39:40 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_SpecifyEffectsImage + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_SpecifyEffectsImage

+XBOX ONLY
+Specifies the location of dsstdfx.bin
+Otherwise FMOD will choose a default location of d:\\media\\dsstdfx.bin
+

+void F_API FSOUND_SpecifyEffectsImage(
+char *name
+);
+

Parameters

+ + +
nameLocation of DSSTDFX.BIN.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function cannot be called after FMOD is already activated with FSOUND_Init.
+It must be called before FSOUND_Init, or after FSOUND_Close.
+___________________
+Supported on the following platforms : XBox
+

See Also

+FSOUND_Close +, +FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Wed Jul 02 10:39:40 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_StopSound.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_StopSound.html index 99238ea6..da5d1f15 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_StopSound.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_StopSound.html @@ -1,64 +1,64 @@ - - - - -FSOUND_StopSound - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_StopSound

-Stops a specified sound channel from playing, and frees it up for re-use.
-

-signed char F_API FSOUND_StopSound(
-int channel
-);
-

Parameters

- - -
channelThe channel number/handle to stop. FSOUND_ALL can also be used (see remarks)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-FSOUND_ALL is supported. Passing this will cause ALL channels to stop.
-If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_PlaySound -, -FSOUND_PlaySoundEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_StopSound + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_StopSound

+Stops a specified sound channel from playing, and frees it up for re-use.
+

+signed char F_API FSOUND_StopSound(
+int channel
+);
+

Parameters

+ + +
channelThe channel number/handle to stop. FSOUND_ALL can also be used (see remarks)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+FSOUND_ALL is supported. Passing this will cause ALL channels to stop.
+If FSOUND_ALL is used the last channel success flag will be returned. This return value is not useful in most circumstances.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_PlaySound +, +FSOUND_PlaySoundEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSyncPoint.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSyncPoint.html index 00623d80..6f38fe5a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSyncPoint.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSyncPoint.html @@ -1,75 +1,75 @@ - - - - -FSOUND_Stream_AddSyncPoint - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_AddSyncPoint

-Adds a user synchronization callback point into a stream.
-

-DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_AddSyncPoint(
-FSOUND_STREAM *stream,
-unsigned int pcmoffset,
-const char *name
-);
-

Parameters

- - - - -
streamThe stream to add a sync point to.
-
pcmoffsetOffset in SAMPLES (not bytes).
-
nameThe name of the syncpoint, which will be passed into the sync callback when it is triggered.
-
-

Return Value

-On success, a sync point handle is returned.
-On failure, NULL is returned.
-

Remarks

-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_DeleteSyncPoint -, -FSOUND_Stream_GetNumSyncPoints -, -FSOUND_Stream_GetSyncPoint -, -FSOUND_Stream_GetSyncPointInfo -, -FSOUND_Stream_SetSyncCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_AddSyncPoint + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_AddSyncPoint

+Adds a user synchronization callback point into a stream.
+

+DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_AddSyncPoint(
+FSOUND_STREAM *stream,
+unsigned int pcmoffset,
+const char *name
+);
+

Parameters

+ + + + +
streamThe stream to add a sync point to.
+
pcmoffsetOffset in SAMPLES (not bytes).
+
nameThe name of the syncpoint, which will be passed into the sync callback when it is triggered.
+
+

Return Value

+On success, a sync point handle is returned.
+On failure, NULL is returned.
+

Remarks

+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_DeleteSyncPoint +, +FSOUND_Stream_GetNumSyncPoints +, +FSOUND_Stream_GetSyncPoint +, +FSOUND_Stream_GetSyncPointInfo +, +FSOUND_Stream_SetSyncCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSynchPoint.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSynchPoint.html index 8bcb1e2f..268d47ae 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSynchPoint.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_AddSynchPoint.html @@ -1,73 +1,73 @@ - - - - -FSOUND_Stream_AddSynchPoint - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_AddSynchPoint

-Adds a user synchronization callback point into a stream.
-

-DLL_API int F_API FSOUND_Stream_AddSynchPoint(
-FSOUND_STREAM *stream,
-unsigned int pcmoffset,
-const char *name
-);
-

Parameters

- - - - -
streamThe stream to add a synch point to.
-
pcmoffsetOffset in SAMPLES (not bytes).
-
userdataThe value to be passed in from the synch callback. This could be cast to a string or pointer.
-
-

Return Value

-On success, a sync point index is returned.
-On failure, -1 is returned.
-

Remarks

-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_DeleteSynchPoint -, -FSOUND_Stream_GetNumSynchPoints -, -FSOUND_Stream_GetSynchPointInfo -, -FSOUND_Stream_SetSynchCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Fri Jul 11 16:00:55 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_AddSynchPoint + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_AddSynchPoint

+Adds a user synchronization callback point into a stream.
+

+DLL_API int F_API FSOUND_Stream_AddSynchPoint(
+FSOUND_STREAM *stream,
+unsigned int pcmoffset,
+const char *name
+);
+

Parameters

+ + + + +
streamThe stream to add a synch point to.
+
pcmoffsetOffset in SAMPLES (not bytes).
+
userdataThe value to be passed in from the synch callback. This could be cast to a string or pointer.
+
+

Return Value

+On success, a sync point index is returned.
+On failure, -1 is returned.
+

Remarks

+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_DeleteSynchPoint +, +FSOUND_Stream_GetNumSynchPoints +, +FSOUND_Stream_GetSynchPointInfo +, +FSOUND_Stream_SetSynchCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Fri Jul 11 16:00:55 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Close.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Close.html index 24333105..44caf592 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Close.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Close.html @@ -1,84 +1,84 @@ - - - - -FSOUND_Stream_Close - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Close

-Shuts down and releases an FSOUND stream.
-

-signed char F_API FSOUND_Stream_Close(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to the stream to be closed down.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-The only exception to this rule is for internet streams - this function will successfully close an internet stream that has been opened with FSOUND_NONBLOCKING before that stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_Create -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Close + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Close

+Shuts down and releases an FSOUND stream.
+

+signed char F_API FSOUND_Stream_Close(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to the stream to be closed down.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+The only exception to this rule is for internet streams - this function will successfully close an internet stream that has been opened with FSOUND_NONBLOCKING before that stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_Create +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Create.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Create.html index 2ac4b24b..4c6ce00f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Create.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Create.html @@ -1,90 +1,90 @@ - - - - -FSOUND_Stream_Create - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Create

-Creates a user definable stream file ready for playing. The stream is serviced through a callback.
-

-DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Create(
-FSOUND_STREAMCALLBACK callback,
-int lenbytes,
-unsigned int mode,
-int samplerate,
-void *userdata
-);
-

Parameters

- - - - - - -
callbackA pointer to a user defined stream callback function.
-
lenbytesSize of the data in BYTES the callback will require to be written to the buffer.
-
modeDescription of the raw sample data being opened. see FSOUND_MODES for a description of these modes.
-
samplerateRate of playback. Be careful you dont set the sample rate too high so that the stream servicer (ie the harddisk) may not keep up.
-
userdataUser data that is passed back into the stream callback when triggered.
-
-

Return Value

-On success, a pointer to an opened stream is returned.
-On failure, NULL is returned.
-

Remarks

-This method only supports SIGNED RAW streams to be written to the buffer supplied by the callback.
-They can be 8 or 16 bit, mono or stereo.
-'lenbytes' may be rounded down to the nearest sample alignment in bytes. Ie if you specified 1001 bytes for a 16bit stereo sample stream, len would return 1000 in the callback. (250 samples * 4 bytes per sample)
-PlayStation 2 IMPORTANT! : if FSOUND_SendData is NOT called from the stream callback the IOP will hang because it is waiting for this command to be executed before it can unlock its buffer.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_SendData -, -FSOUND_Stream_Close -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -, -FSOUND_Stream_SetBufferSize -, -FSOUND_Stream_Stop -, -FSOUND_STREAMCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Create + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Create

+Creates a user definable stream file ready for playing. The stream is serviced through a callback.
+

+DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Create(
+FSOUND_STREAMCALLBACK callback,
+int lenbytes,
+unsigned int mode,
+int samplerate,
+void *userdata
+);
+

Parameters

+ + + + + + +
callbackA pointer to a user defined stream callback function.
+
lenbytesSize of the data in BYTES the callback will require to be written to the buffer.
+
modeDescription of the raw sample data being opened. see FSOUND_MODES for a description of these modes.
+
samplerateRate of playback. Be careful you dont set the sample rate too high so that the stream servicer (ie the harddisk) may not keep up.
+
userdataUser data that is passed back into the stream callback when triggered.
+
+

Return Value

+On success, a pointer to an opened stream is returned.
+On failure, NULL is returned.
+

Remarks

+This method only supports SIGNED RAW streams to be written to the buffer supplied by the callback.
+They can be 8 or 16 bit, mono or stereo.
+'lenbytes' may be rounded down to the nearest sample alignment in bytes. Ie if you specified 1001 bytes for a 16bit stereo sample stream, len would return 1000 in the callback. (250 samples * 4 bytes per sample)
+PlayStation 2 IMPORTANT! : if FSOUND_SendData is NOT called from the stream callback the IOP will hang because it is waiting for this command to be executed before it can unlock its buffer.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_SendData +, +FSOUND_Stream_Close +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +, +FSOUND_Stream_SetBufferSize +, +FSOUND_Stream_Stop +, +FSOUND_STREAMCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_CreateDSP.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_CreateDSP.html index d122ed19..1b985600 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_CreateDSP.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_CreateDSP.html @@ -1,73 +1,73 @@ - - - - -FSOUND_Stream_CreateDSP - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_CreateDSP

-Allows the user to add a custom DSP unit to a stream.
-

-FSOUND_DSPUNIT *F_API FSOUND_Stream_CreateDSP(
-FSOUND_STREAM *stream,
-FSOUND_DSPCALLBACK callback,
-int priority,
-void *userdata
-);
-

Parameters

- - - - - -
streamThe stream pointer to have a DSP attached to.
-
callbackA standard FSOUND_DSPCALLBACK function callback pointer.
-
priorityThe priority, or position within the streams DSP chain to place the unit.
-
paramA user parameter that gets passed back into the DSP callback.
-
-

Return Value

-On success, a handle to the FSOUND_DSPUNIT is returned. All DSP functions are performable on this.
-On failure, 0 is returned.
-

Remarks

-The priority for a stream DSP unit is not related to the priorities specified in fmod.h.
-The priorities are anything fom 0 onwards, and ALWAYS come after data is read/decoded for the stream.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_DSP_Create -, -FSOUND_DSPCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_CreateDSP + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_CreateDSP

+Allows the user to add a custom DSP unit to a stream.
+

+FSOUND_DSPUNIT *F_API FSOUND_Stream_CreateDSP(
+FSOUND_STREAM *stream,
+FSOUND_DSPCALLBACK callback,
+int priority,
+void *userdata
+);
+

Parameters

+ + + + + +
streamThe stream pointer to have a DSP attached to.
+
callbackA standard FSOUND_DSPCALLBACK function callback pointer.
+
priorityThe priority, or position within the streams DSP chain to place the unit.
+
paramA user parameter that gets passed back into the DSP callback.
+
+

Return Value

+On success, a handle to the FSOUND_DSPUNIT is returned. All DSP functions are performable on this.
+On failure, 0 is returned.
+

Remarks

+The priority for a stream DSP unit is not related to the priorities specified in fmod.h.
+The priorities are anything fom 0 onwards, and ALWAYS come after data is read/decoded for the stream.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_DSP_Create +, +FSOUND_DSPCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSyncPoint.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSyncPoint.html index 1906041f..75ef9005 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSyncPoint.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSyncPoint.html @@ -1,68 +1,68 @@ - - - - -FSOUND_Stream_DeleteSyncPoint - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_DeleteSyncPoint

-Removes a user synchronization callback point from a stream.
-

-DLL_API signed char F_API FSOUND_Stream_DeleteSyncPoint(
-FSOUND_SYNCPOINT *point
-);
-

Parameters

- - -
pointThe sync point to remove
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSyncPoint -, -FSOUND_Stream_GetNumSyncPoints -, -FSOUND_Stream_GetSyncPoint -, -FSOUND_Stream_GetSyncPoints -, -FSOUND_Stream_SetSyncCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_DeleteSyncPoint + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_DeleteSyncPoint

+Removes a user synchronization callback point from a stream.
+

+DLL_API signed char F_API FSOUND_Stream_DeleteSyncPoint(
+FSOUND_SYNCPOINT *point
+);
+

Parameters

+ + +
pointThe sync point to remove
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSyncPoint +, +FSOUND_Stream_GetNumSyncPoints +, +FSOUND_Stream_GetSyncPoint +, +FSOUND_Stream_GetSyncPoints +, +FSOUND_Stream_SetSyncCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSynchPoint.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSynchPoint.html index a7e07ab5..bcbc3659 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSynchPoint.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_DeleteSynchPoint.html @@ -1,68 +1,68 @@ - - - - -FSOUND_Stream_DeleteSynchPoint - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_DeleteSynchPoint

-Removes a user synchronization callback point from a stream.
-

-DLL_API signed char F_API FSOUND_Stream_DeleteSynchPoint(
-FSOUND_STREAM *stream,
-int index
-);
-

Parameters

- - - -
streamThe stream to remove the synch point from.
-
indexThe index to delete.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-The index is not nescessarily in order of playback. Use the return value from FSOUND_Stream_AddSynchPoint.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSynchPoint -, -FSOUND_Stream_GetNumSynchPoints -, -FSOUND_Stream_SetSynchCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Fri Jul 11 16:00:55 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_DeleteSynchPoint + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_DeleteSynchPoint

+Removes a user synchronization callback point from a stream.
+

+DLL_API signed char F_API FSOUND_Stream_DeleteSynchPoint(
+FSOUND_STREAM *stream,
+int index
+);
+

Parameters

+ + + +
streamThe stream to remove the synch point from.
+
indexThe index to delete.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+The index is not nescessarily in order of playback. Use the return value from FSOUND_Stream_AddSynchPoint.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSynchPoint +, +FSOUND_Stream_GetNumSynchPoints +, +FSOUND_Stream_SetSynchCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Fri Jul 11 16:00:55 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_FindTagField.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_FindTagField.html index bd20430c..b458fa58 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_FindTagField.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_FindTagField.html @@ -1,76 +1,76 @@ - - - - -FSOUND_Stream_FindTagField - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_FindTagField

-Find a tag field associated with an open stream by name and type.
-

-signed char F_API FSOUND_Stream_FindTagField(
-FSOUND_STREAM *stream,
-int type,
-const char *name,
-void **value,
-int *length
-);
-

Parameters

- - - - - - -
streamThe stream to get the tag field from.
-
typeThe type of the tag field to retrieve. See FSOUND_TAGFIELD_TYPE.
-
nameThe name of the tag field to retrieve.
-
valuePointer to a variable that will receive a pointer to the tag field data.
-
lengthPointer to a variable that will receive the length of the tag field data.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Stream_GetNumTagFields -, -FSOUND_Stream_GetTagField -, -FSOUND_TAGFIELD_TYPE -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_FindTagField + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_FindTagField

+Find a tag field associated with an open stream by name and type.
+

+signed char F_API FSOUND_Stream_FindTagField(
+FSOUND_STREAM *stream,
+int type,
+const char *name,
+void **value,
+int *length
+);
+

Parameters

+ + + + + + +
streamThe stream to get the tag field from.
+
typeThe type of the tag field to retrieve. See FSOUND_TAGFIELD_TYPE.
+
nameThe name of the tag field to retrieve.
+
valuePointer to a variable that will receive a pointer to the tag field data.
+
lengthPointer to a variable that will receive the length of the tag field data.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Stream_GetNumTagFields +, +FSOUND_Stream_GetTagField +, +FSOUND_TAGFIELD_TYPE +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetCurrentBitrate.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetCurrentBitrate.html index 9d7aa084..9e590c4f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetCurrentBitrate.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetCurrentBitrate.html @@ -1,51 +1,51 @@ - - - - -FSOUND_Stream_GetCurrentBitrate - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetCurrentBitrate

-

-signed char F_API FSOUND_Stream_GetCurrentBitrate(
-FSOUND_STREAM *stream,
-int *bitrate
-);
-

Return Value

-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Tue Aug 19 16:56:56 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetCurrentBitrate + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetCurrentBitrate

+

+signed char F_API FSOUND_Stream_GetCurrentBitrate(
+FSOUND_STREAM *stream,
+int *bitrate
+);
+

Return Value

+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Tue Aug 19 16:56:56 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLength.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLength.html index 97e60861..59754024 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLength.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLength.html @@ -1,71 +1,71 @@ - - - - -FSOUND_Stream_GetLength - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetLength

-Returns the size of the stream in BYTES.
-

-int F_API FSOUND_Stream_GetLength(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamA pointer to the stream to have its length returned.
-
-

Return Value

-On success, the size of the stream in BYTES is returned.
-On failure, 0 is returned.
-

Remarks

-Position functions for streams work in bytes not samples.
------
-This function is not supported for URL based streams over the internet.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetLengthMs -, -FSOUND_Stream_GetPosition -, -FSOUND_Stream_Open -, -FSOUND_Stream_SetPosition -, -FSOUND_Stream_SetTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetLength + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetLength

+Returns the size of the stream in BYTES.
+

+int F_API FSOUND_Stream_GetLength(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamA pointer to the stream to have its length returned.
+
+

Return Value

+On success, the size of the stream in BYTES is returned.
+On failure, 0 is returned.
+

Remarks

+Position functions for streams work in bytes not samples.
+-----
+This function is not supported for URL based streams over the internet.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetLengthMs +, +FSOUND_Stream_GetPosition +, +FSOUND_Stream_Open +, +FSOUND_Stream_SetPosition +, +FSOUND_Stream_SetTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLengthMs.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLengthMs.html index 2449dd14..0f8ecac0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLengthMs.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetLengthMs.html @@ -1,63 +1,63 @@ - - - - -FSOUND_Stream_GetLengthMs - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetLengthMs

-Returns the size of the stream in MILLISECONDS.
-

-int F_API FSOUND_Stream_GetLengthMs(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamA pointer to the stream to have its total duration returned.
-
-

Return Value

-On success, the size of the stream in MILLISECONDS is returned.
-On failure, 0 is returned.
-

Remarks

-FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetLength -, -FSOUND_Stream_Open -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetLengthMs + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetLengthMs

+Returns the size of the stream in MILLISECONDS.
+

+int F_API FSOUND_Stream_GetLengthMs(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamA pointer to the stream to have its total duration returned.
+
+

Return Value

+On success, the size of the stream in MILLISECONDS is returned.
+On failure, 0 is returned.
+

Remarks

+FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetLength +, +FSOUND_Stream_Open +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetMode.html index 5ac6300f..4230e785 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetMode.html @@ -1,61 +1,61 @@ - - - - -FSOUND_Stream_GetMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetMode

-Retrieves the mode of the stream.
-

-unsigned int F_API FSOUND_Stream_GetMode(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to the stream to get the mode from.
-
-

Return Value

-

Remarks

-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_SetMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetMode

+Retrieves the mode of the stream.
+

+unsigned int F_API FSOUND_Stream_GetMode(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to the stream to get the mode from.
+
+

Return Value

+

Remarks

+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_SetMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSubStreams.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSubStreams.html index f692a003..e5dea804 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSubStreams.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSubStreams.html @@ -1,62 +1,62 @@ - - - - -FSOUND_Stream_GetNumSubStreams - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetNumSubStreams

-Returns the number of substreams inside a multi-stream FSB bank file.
-

-int F_API FSOUND_Stream_GetNumSubStreams(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to the stream to query.
-
-

Return Value

-On success, the number of FSB substreams is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_SetSubStream -, -FSOUND_Stream_SetSubStreamSentence -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetNumSubStreams + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetNumSubStreams

+Returns the number of substreams inside a multi-stream FSB bank file.
+

+int F_API FSOUND_Stream_GetNumSubStreams(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to the stream to query.
+
+

Return Value

+On success, the number of FSB substreams is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_SetSubStream +, +FSOUND_Stream_SetSubStreamSentence +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSyncPoints.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSyncPoints.html index bd09a4f1..1057d8d2 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSyncPoints.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSyncPoints.html @@ -1,66 +1,66 @@ - - - - -FSOUND_Stream_GetNumSyncPoints - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetNumSyncPoints

-Returns the number of sync points within a stream.
-

-DLL_API int F_API FSOUND_Stream_GetNumSyncPoints(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamThe stream to request the number of sync points from.
-
-

Return Value

-On success, The number of sync points in a stream are returned.
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSyncPoint -, -FSOUND_Stream_DeleteSyncPoint -, -FSOUND_Stream_GetSyncPointInfo -, -FSOUND_Stream_SetSyncCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:35 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetNumSyncPoints + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetNumSyncPoints

+Returns the number of sync points within a stream.
+

+DLL_API int F_API FSOUND_Stream_GetNumSyncPoints(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamThe stream to request the number of sync points from.
+
+

Return Value

+On success, The number of sync points in a stream are returned.
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSyncPoint +, +FSOUND_Stream_DeleteSyncPoint +, +FSOUND_Stream_GetSyncPointInfo +, +FSOUND_Stream_SetSyncCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:35 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSynchPoints.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSynchPoints.html index f448ffb1..87942f79 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSynchPoints.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumSynchPoints.html @@ -1,66 +1,66 @@ - - - - -FSOUND_Stream_GetNumSynchPoints - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetNumSynchPoints

-Returns the number of synch points within a stream.
-

-DLL_API int F_API FSOUND_Stream_GetNumSynchPoints(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamThe stream to request the number of synch points from.
-
-

Return Value

-On success, The number of synch points in a stream are returned.
-On failure, -1 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSynchPoint -, -FSOUND_Stream_DeleteSynchPoint -, -FSOUND_Stream_GetSynchPointInfo -, -FSOUND_Stream_SetSynchCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Fri Jul 11 16:00:55 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetNumSynchPoints + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetNumSynchPoints

+Returns the number of synch points within a stream.
+

+DLL_API int F_API FSOUND_Stream_GetNumSynchPoints(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamThe stream to request the number of synch points from.
+
+

Return Value

+On success, The number of synch points in a stream are returned.
+On failure, -1 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSynchPoint +, +FSOUND_Stream_DeleteSynchPoint +, +FSOUND_Stream_GetSynchPointInfo +, +FSOUND_Stream_SetSynchCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Fri Jul 11 16:00:55 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumTagFields.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumTagFields.html index 8a1a62bb..cbe096ee 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumTagFields.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetNumTagFields.html @@ -1,65 +1,65 @@ - - - - -FSOUND_Stream_GetNumTagFields - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetNumTagFields

-Get the number of tag fields associated with the specified stream.
-

-signed char F_API FSOUND_Stream_GetNumTagFields(
-FSOUND_STREAM *stream,
-int *num
-);
-

Parameters

- - - -
streamThe stream to get the number of tag fields for.
-
numPointer to a variable that will receive the nubmer of tag fields associated with the specified stream.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Stream_FindTagField -, -FSOUND_Stream_GetTagField -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetNumTagFields + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetNumTagFields

+Get the number of tag fields associated with the specified stream.
+

+signed char F_API FSOUND_Stream_GetNumTagFields(
+FSOUND_STREAM *stream,
+int *num
+);
+

Parameters

+ + + +
streamThe stream to get the number of tag fields for.
+
numPointer to a variable that will receive the nubmer of tag fields associated with the specified stream.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Stream_FindTagField +, +FSOUND_Stream_GetTagField +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetOpenState.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetOpenState.html index d1d8c009..2b80056a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetOpenState.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetOpenState.html @@ -1,70 +1,70 @@ - - - - -FSOUND_Stream_GetOpenState - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetOpenState

-If a stream is opened with FSOUND_NONBLOCKING, this function returns the state of the opening stream.
-

-int F_API FSOUND_Stream_GetOpenState(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to the stream to get the open state from.
-
-

Return Value

-0 = stream is opened and ready.
--1 = stream handle passed in is invalid.
--2 = stream is still opening or performing a SetSubStream command.
--3 = stream failed to open. (file not found, out of memory or other error).
--4 = connecting to remote host (internet streams only)
--5 = stream is buffering data (internet streams only)
-

Remarks

-A blocking stream will return NULL from FSOUND_Stream_Open so a return value of -3 is redundant in this case.
-A blocking stream will always return 0 if it is not NULL.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_Open -, -FSOUND_Stream_SetSubStream -, -FSOUND_Stream_SetSubStreamSentence -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetOpenState + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetOpenState

+If a stream is opened with FSOUND_NONBLOCKING, this function returns the state of the opening stream.
+

+int F_API FSOUND_Stream_GetOpenState(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to the stream to get the open state from.
+
+

Return Value

+0 = stream is opened and ready.
+-1 = stream handle passed in is invalid.
+-2 = stream is still opening or performing a SetSubStream command.
+-3 = stream failed to open. (file not found, out of memory or other error).
+-4 = connecting to remote host (internet streams only)
+-5 = stream is buffering data (internet streams only)
+

Remarks

+A blocking stream will return NULL from FSOUND_Stream_Open so a return value of -3 is redundant in this case.
+A blocking stream will always return 0 if it is not NULL.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_Open +, +FSOUND_Stream_SetSubStream +, +FSOUND_Stream_SetSubStreamSentence +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetPosition.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetPosition.html index 7497c4b3..cf927888 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetPosition.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetPosition.html @@ -1,70 +1,70 @@ - - - - -FSOUND_Stream_GetPosition - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetPosition

-Returns the current FILE position of the stream of the stream in BYTES.
-

-unsigned int F_API FSOUND_Stream_GetPosition(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to the stream to have its position returned.
-
-

Return Value

-On success, the current stream's position in BYTES is returned.
-On failure, 0 is returned.
-

Remarks

-Position functions for streams work in bytes not samples.
-Position information is also based on the current file position, not the actual playing
-position, so if the stream is only updated every 100ms, then the position will only be
-updated every 100ms.
------
-This function is not supported for URL based streams over the internet or CDDA streams
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetLength -, -FSOUND_Stream_SetPosition -, -FSOUND_Stream_SetTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetPosition + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetPosition

+Returns the current FILE position of the stream of the stream in BYTES.
+

+unsigned int F_API FSOUND_Stream_GetPosition(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to the stream to have its position returned.
+
+

Return Value

+On success, the current stream's position in BYTES is returned.
+On failure, 0 is returned.
+

Remarks

+Position functions for streams work in bytes not samples.
+Position information is also based on the current file position, not the actual playing
+position, so if the stream is only updated every 100ms, then the position will only be
+updated every 100ms.
+-----
+This function is not supported for URL based streams over the internet or CDDA streams
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetLength +, +FSOUND_Stream_SetPosition +, +FSOUND_Stream_SetTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSample.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSample.html index 60ed3469..7638bfa8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSample.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSample.html @@ -1,59 +1,59 @@ - - - - -FSOUND_Stream_GetSample - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetSample

-Returns the FSOUND_SAMPLE definition that the stream uses internally.
-You can use this to get a variety of information like the songs name, default speed and more.
-

-FSOUND_SAMPLE * F_API FSOUND_Stream_GetSample(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamA pointer to the stream to have its internal sample pointer returned.
-
-

Return Value

-On success, a handle to the FSOUND_SAMPLE definition is returned.
-On failure, 0 is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetSample + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetSample

+Returns the FSOUND_SAMPLE definition that the stream uses internally.
+You can use this to get a variety of information like the songs name, default speed and more.
+

+FSOUND_SAMPLE * F_API FSOUND_Stream_GetSample(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamA pointer to the stream to have its internal sample pointer returned.
+
+

Return Value

+On success, a handle to the FSOUND_SAMPLE definition is returned.
+On failure, 0 is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPoint.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPoint.html index b7f4e04c..1bb43ab4 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPoint.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPoint.html @@ -1,70 +1,70 @@ - - - - -FSOUND_Stream_GetSyncPoint - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetSyncPoint

-Obtains a sync point by index. This is useful when you havent created your own, ie it came from a wav file.
-

-DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_GetSyncPoint(
-FSOUND_STREAM *stream,
-int index
-);
-

Parameters

- - - -
streamThe stream to request the sync point from.
-
indexThe sync point offset into the stream.
-
-

Return Value

-On success, a handle to a sync point is returned.
-On failure, NULL is returned.
-

Remarks

-Points are loaded in order of offset, so the index will represent the smallest point to the largest.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSyncPoint -, -FSOUND_Stream_DeleteSyncPoint -, -FSOUND_Stream_GetSyncPointInfo -, -FSOUND_Stream_SetSyncCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetSyncPoint + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetSyncPoint

+Obtains a sync point by index. This is useful when you havent created your own, ie it came from a wav file.
+

+DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_GetSyncPoint(
+FSOUND_STREAM *stream,
+int index
+);
+

Parameters

+ + + +
streamThe stream to request the sync point from.
+
indexThe sync point offset into the stream.
+
+

Return Value

+On success, a handle to a sync point is returned.
+On failure, NULL is returned.
+

Remarks

+Points are loaded in order of offset, so the index will represent the smallest point to the largest.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSyncPoint +, +FSOUND_Stream_DeleteSyncPoint +, +FSOUND_Stream_GetSyncPointInfo +, +FSOUND_Stream_SetSyncCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPointInfo.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPointInfo.html index 6681c935..7c040d4a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPointInfo.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSyncPointInfo.html @@ -1,70 +1,70 @@ - - - - -FSOUND_Stream_GetSyncPointInfo - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetSyncPointInfo

-Retrieves the name and pcm offset in samples for a specified sync point.
-

-char * F_API FSOUND_Stream_GetSyncPointInfo(
-FSOUND_SYNCPOINT *point,
-unsigned int *pcmoffset
-);
-

Parameters

- - - -
pointThe handle to the sync point to retrieve information from.
-
pcmoffsetA pointer to an integer that will receive the sync point offset in pcm SAMPLES. A value of NULL will be ignored.
-
-

Return Value

-On success, the name of the syncpoint is returned as a string.
-On failure, NULL is returned.
-

Remarks

-Convert samples to time by dividing the PCM value by the default samplerate. This would give you the value in seconds. Multiply by 1000 to get milliseconds.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSyncPoint -, -FSOUND_Stream_GetNumSyncPoints -, -FSOUND_Stream_GetSyncPoint -, -FSOUND_Stream_SetSyncCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetSyncPointInfo + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetSyncPointInfo

+Retrieves the name and pcm offset in samples for a specified sync point.
+

+char * F_API FSOUND_Stream_GetSyncPointInfo(
+FSOUND_SYNCPOINT *point,
+unsigned int *pcmoffset
+);
+

Parameters

+ + + +
pointThe handle to the sync point to retrieve information from.
+
pcmoffsetA pointer to an integer that will receive the sync point offset in pcm SAMPLES. A value of NULL will be ignored.
+
+

Return Value

+On success, the name of the syncpoint is returned as a string.
+On failure, NULL is returned.
+

Remarks

+Convert samples to time by dividing the PCM value by the default samplerate. This would give you the value in seconds. Multiply by 1000 to get milliseconds.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSyncPoint +, +FSOUND_Stream_GetNumSyncPoints +, +FSOUND_Stream_GetSyncPoint +, +FSOUND_Stream_SetSyncCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSynchPointInfo.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSynchPointInfo.html index 05455a68..daeb47fa 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSynchPointInfo.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetSynchPointInfo.html @@ -1,72 +1,72 @@ - - - - -FSOUND_Stream_GetSynchPointInfo - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetSynchPointInfo

-Retrieves the name and pcm offset in samples for a specified sync point.
-

-char * F_API FSOUND_Stream_GetSynchPointInfo(
-FSOUND_STREAM *stream,
-int index,
-unsigned int *pcmoffset
-);
-

Parameters

- - - - -
streamThe stream to remove the synch point info from.
-
indexThe synch point index.
-
pcmoffsetThe synch point offset in pcm SAMPLES.
-
-

Return Value

-On success, the name of the synchpoint is returned as a string.
-On failure, NULL is returned.
-

Remarks

-The index is not nescessarily in order of playback. Use the return value from FSOUND_Stream_AddSynchPoint.
-Convert samples to time by dividing the PCM value by the default samplerate. This would give you the value in seconds. Multiply by 1000 to get milliseconds.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_AddSynchPoint -, -FSOUND_Stream_GetNumSynchPoints -, -FSOUND_Stream_SetSynchCallback -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Fri Jul 11 16:00:55 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetSynchPointInfo + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetSynchPointInfo

+Retrieves the name and pcm offset in samples for a specified sync point.
+

+char * F_API FSOUND_Stream_GetSynchPointInfo(
+FSOUND_STREAM *stream,
+int index,
+unsigned int *pcmoffset
+);
+

Parameters

+ + + + +
streamThe stream to remove the synch point info from.
+
indexThe synch point index.
+
pcmoffsetThe synch point offset in pcm SAMPLES.
+
+

Return Value

+On success, the name of the synchpoint is returned as a string.
+On failure, NULL is returned.
+

Remarks

+The index is not nescessarily in order of playback. Use the return value from FSOUND_Stream_AddSynchPoint.
+Convert samples to time by dividing the PCM value by the default samplerate. This would give you the value in seconds. Multiply by 1000 to get milliseconds.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_AddSynchPoint +, +FSOUND_Stream_GetNumSynchPoints +, +FSOUND_Stream_SetSynchCallback +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Fri Jul 11 16:00:55 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTagField.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTagField.html index df18f010..02d9fd2e 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTagField.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTagField.html @@ -1,81 +1,81 @@ - - - - -FSOUND_Stream_GetTagField - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetTagField

-Get a tag field associated with an open stream.
-

-signed char F_API FSOUND_Stream_GetTagField(
-FSOUND_STREAM *stream,
-int num,
-int *type,
-char **name,
-void **value,
-int *length
-);
-

Parameters

- - - - - - - -
streamThe stream to get the tag field from.
-
numThe number of the tag field to retrieve.
-
typePointer to a variable that will receive the type of the tag field that was retrieved. See FSOUND_TAGFIELD_TYPE.
-
namePointer to a variable that will receive the name of the tag field as a null-terminated ASCII string.
-
valuePointer to a variable that will receive a pointer to the tag field data.
-
lengthPointer to a variable that will receive the length of the tag field data.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Do not attempt to modify or free any pointers returned by this function.
-If this function returns successfully, "value" will contain a pointer to a piece of tag-field-specific data - do not assume it will always point to a null-terminated ASCII string.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh
-

See Also

-FSOUND_Stream_FindTagField -, -FSOUND_Stream_GetNumTagFields -, -FSOUND_TAGFIELD_TYPE -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetTagField + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetTagField

+Get a tag field associated with an open stream.
+

+signed char F_API FSOUND_Stream_GetTagField(
+FSOUND_STREAM *stream,
+int num,
+int *type,
+char **name,
+void **value,
+int *length
+);
+

Parameters

+ + + + + + + +
streamThe stream to get the tag field from.
+
numThe number of the tag field to retrieve.
+
typePointer to a variable that will receive the type of the tag field that was retrieved. See FSOUND_TAGFIELD_TYPE.
+
namePointer to a variable that will receive the name of the tag field as a null-terminated ASCII string.
+
valuePointer to a variable that will receive a pointer to the tag field data.
+
lengthPointer to a variable that will receive the length of the tag field data.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Do not attempt to modify or free any pointers returned by this function.
+If this function returns successfully, "value" will contain a pointer to a piece of tag-field-specific data - do not assume it will always point to a null-terminated ASCII string.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh
+

See Also

+FSOUND_Stream_FindTagField +, +FSOUND_Stream_GetNumTagFields +, +FSOUND_TAGFIELD_TYPE +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTime.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTime.html index 5838aa2b..b3a9962f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTime.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_GetTime.html @@ -1,61 +1,61 @@ - - - - -FSOUND_Stream_GetTime - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_GetTime

-Returns the current time offset in stream in milliseconds.
-

-int F_API FSOUND_Stream_GetTime(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to the stream to get the currently playing time offset.
-
-

Return Value

-On success, the current stream's position in milliseconds is returned.
-On failure, 0 is returned.
-

Remarks

-FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_SetTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_GetTime + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_GetTime

+Returns the current time offset in stream in milliseconds.
+

+int F_API FSOUND_Stream_GetTime(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to the stream to get the currently playing time offset.
+
+

Return Value

+On success, the current stream's position in milliseconds is returned.
+On failure, 0 is returned.
+

Remarks

+FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_SetTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetBufferProperties.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetBufferProperties.html index 99dcf8fb..fcc78d1d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetBufferProperties.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetBufferProperties.html @@ -1,86 +1,86 @@ - - - - -FSOUND_Stream_Net_GetBufferProperties - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_GetBufferProperties

-Gets buffer size and thresholds that will be used when opening new internet streams.
-

-signed char F_API FSOUND_Stream_Net_GetBufferProperties(
-int *buffersize,
-int *prebuffer_percent,
-int *rebuffer_percent
-);
-

Parameters

- - - - -
buffersizePointer to size in bytes of the streaming buffer.
-
prebuffer_percentPointer to how much to prebuffer when a stream is first opened. Values are expressed as a percentage from 1 to 99.
-
rebuffer_percentPointer to how much to rebuffer after a stream has suffered a buffer underrun. Values are expressed as a percentage from 1 to 99.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This function returns the values that will be used for subsequent internet stream opens. Internet streams that already exist may have different values.
-Any of the parameters can be NULL, in which case, they will be ignored.
-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_GetBufferProperties + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_GetBufferProperties

+Gets buffer size and thresholds that will be used when opening new internet streams.
+

+signed char F_API FSOUND_Stream_Net_GetBufferProperties(
+int *buffersize,
+int *prebuffer_percent,
+int *rebuffer_percent
+);
+

Parameters

+ + + + +
buffersizePointer to size in bytes of the streaming buffer.
+
prebuffer_percentPointer to how much to prebuffer when a stream is first opened. Values are expressed as a percentage from 1 to 99.
+
rebuffer_percentPointer to how much to rebuffer after a stream has suffered a buffer underrun. Values are expressed as a percentage from 1 to 99.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This function returns the values that will be used for subsequent internet stream opens. Internet streams that already exist may have different values.
+Any of the parameters can be NULL, in which case, they will be ignored.
+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetLastServerStatus.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetLastServerStatus.html index 1c7b2f9d..6360ad4a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetLastServerStatus.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetLastServerStatus.html @@ -1,72 +1,72 @@ - - - - -FSOUND_Stream_Net_GetLastServerStatus - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_GetLastServerStatus

-This function returns a pointer to the last HTTP status line that was received when connecting to an internet stream.
-

-char *F_API FSOUND_Stream_Net_GetLastServerStatus(
-);
-

Return Value

-Pointer to the last HTTP status line (null-terminated ASCII string) that was received.
-

Remarks

-The result of this function should be used for informational purposes only. This function provides no facility to discover which internet stream the last HTTP status pertains to when there are multiple internet streams open.
-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_GetLastServerStatus + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_GetLastServerStatus

+This function returns a pointer to the last HTTP status line that was received when connecting to an internet stream.
+

+char *F_API FSOUND_Stream_Net_GetLastServerStatus(
+);
+

Return Value

+Pointer to the last HTTP status line (null-terminated ASCII string) that was received.
+

Remarks

+The result of this function should be used for informational purposes only. This function provides no facility to discover which internet stream the last HTTP status pertains to when there are multiple internet streams open.
+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetStatus.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetStatus.html index 3212a6a1..61762f4f 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetStatus.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_GetStatus.html @@ -1,94 +1,94 @@ - - - - -FSOUND_Stream_Net_GetStatus - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_GetStatus

-Get various status information for an internet stream.
-

-signed char F_API FSOUND_Stream_Net_GetStatus(
-FSOUND_STREAM *stream,
-int *status,
-int *bufferused,
-int *bitrate,
-unsigned int *flags
-);
-

Parameters

- - - - - - -
streamThe stream to get status information on.
-
statusPointer to a variable that will receive a status value. See FSOUND_STREAM_NET_STATUS.
-
bufferusedPointer to a variable that will receive the percentage of the read buffer that is currently in use.
-
bitratePointer to a variable that will receive the current bitrate of the stream.
-
flagsPointer to a variable that will receive a flags field describing protocol and format information. See FSOUND_STATUS_FLAGS.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_STATUS_FLAGS -, -FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_STREAM_NET_STATUS -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_GetStatus + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_GetStatus

+Get various status information for an internet stream.
+

+signed char F_API FSOUND_Stream_Net_GetStatus(
+FSOUND_STREAM *stream,
+int *status,
+int *bufferused,
+int *bitrate,
+unsigned int *flags
+);
+

Parameters

+ + + + + + +
streamThe stream to get status information on.
+
statusPointer to a variable that will receive a status value. See FSOUND_STREAM_NET_STATUS.
+
bufferusedPointer to a variable that will receive the percentage of the read buffer that is currently in use.
+
bitratePointer to a variable that will receive the current bitrate of the stream.
+
flagsPointer to a variable that will receive a flags field describing protocol and format information. See FSOUND_STATUS_FLAGS.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_STATUS_FLAGS +, +FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_STREAM_NET_STATUS +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetBufferProperties.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetBufferProperties.html index 594772d2..7c93e8d0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetBufferProperties.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetBufferProperties.html @@ -1,85 +1,85 @@ - - - - -FSOUND_Stream_Net_SetBufferProperties - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_SetBufferProperties

-Sets buffer size and thresholds to use when opening new internet streams.
-

-signed char F_API FSOUND_Stream_Net_SetBufferProperties(
-int buffersize,
-int prebuffer_percent,
-int rebuffer_percent
-);
-

Parameters

- - - - -
buffersizeSize in bytes of the streaming buffer. Make it bigger to avoid buffer underruns. (Default = 64000)
-
prebuffer_percentHow much to prebuffer when a stream is first opened. Values are expressed as a percentage from 1 to 99. (Default = 95)
-
rebuffer_percentHow much to rebuffer after a stream has suffered a buffer underrun. Values are expressed as a percentage from 1 to 99. (Default = 95)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Call this function before FSOUND_Stream_Open. This function has no effect on internet streams that are already open.
-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_SetBufferProperties + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_SetBufferProperties

+Sets buffer size and thresholds to use when opening new internet streams.
+

+signed char F_API FSOUND_Stream_Net_SetBufferProperties(
+int buffersize,
+int prebuffer_percent,
+int rebuffer_percent
+);
+

Parameters

+ + + + +
buffersizeSize in bytes of the streaming buffer. Make it bigger to avoid buffer underruns. (Default = 64000)
+
prebuffer_percentHow much to prebuffer when a stream is first opened. Values are expressed as a percentage from 1 to 99. (Default = 95)
+
rebuffer_percentHow much to rebuffer after a stream has suffered a buffer underrun. Values are expressed as a percentage from 1 to 99. (Default = 95)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Call this function before FSOUND_Stream_Open. This function has no effect on internet streams that are already open.
+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetMetadataCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetMetadataCallback.html index 7391d6a1..cf43032b 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetMetadataCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetMetadataCallback.html @@ -1,89 +1,89 @@ - - - - -FSOUND_Stream_Net_SetMetadataCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_SetMetadataCallback

-Set a metadata callback for an internet stream.
-

-signed char F_API FSOUND_Stream_Net_SetMetadataCallback(
-FSOUND_STREAM *stream,
-FSOUND_METADATACALLBACK callback,
-void *userdata
-);
-

Parameters

- - - - -
streamThe stream to set the metadata callback for.
-
callbackPointer to the metadata callback function to attach to this stream.
-
userdataUser-defined value that will be passed to the supplied metadata callback function in the userdata parameter.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-The supplied metadata callback function will be called each time the specified internet stream receives a chunk of metadata.
-Do not do any time-consuming processing in a metadata callback function or network subsystem performance may degrade.
-Do not attempt to modify or free any memory passed to a metadata callback function.
-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_METADATACALLBACK -, -FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_SetMetadataCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_SetMetadataCallback

+Set a metadata callback for an internet stream.
+

+signed char F_API FSOUND_Stream_Net_SetMetadataCallback(
+FSOUND_STREAM *stream,
+FSOUND_METADATACALLBACK callback,
+void *userdata
+);
+

Parameters

+ + + + +
streamThe stream to set the metadata callback for.
+
callbackPointer to the metadata callback function to attach to this stream.
+
userdataUser-defined value that will be passed to the supplied metadata callback function in the userdata parameter.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+The supplied metadata callback function will be called each time the specified internet stream receives a chunk of metadata.
+Do not do any time-consuming processing in a metadata callback function or network subsystem performance may degrade.
+Do not attempt to modify or free any memory passed to a metadata callback function.
+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_METADATACALLBACK +, +FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetProxy.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetProxy.html index 5083a9c1..a37e5a95 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetProxy.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetProxy.html @@ -1,80 +1,80 @@ - - - - -FSOUND_Stream_Net_SetProxy - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_SetProxy

-Set a proxy server to use for all subsequent internet connections.
-

-signed char F_API FSOUND_Stream_Net_SetProxy(
-const char *proxy
-);
-

Parameters

- - -
proxyThe name of a proxy server in host:port format e.g. www.fmod.org:8888 (defaults to port 80 if no port is specified).
-Basic authentication is supported. To use it, this parameter must be in user:password@host:port format e.g. bob:sekrit123@www.fmod.org:8888
-Set this parameter to NULL if no proxy is required.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_SetProxy + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_SetProxy

+Set a proxy server to use for all subsequent internet connections.
+

+signed char F_API FSOUND_Stream_Net_SetProxy(
+const char *proxy
+);
+

Parameters

+ + +
proxyThe name of a proxy server in host:port format e.g. www.fmod.org:8888 (defaults to port 80 if no port is specified).
+Basic authentication is supported. To use it, this parameter must be in user:password@host:port format e.g. bob:sekrit123@www.fmod.org:8888
+Set this parameter to NULL if no proxy is required.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetTimeout.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetTimeout.html index 8b20c9f1..d34fa9d5 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetTimeout.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Net_SetTimeout.html @@ -1,78 +1,78 @@ - - - - -FSOUND_Stream_Net_SetTimeout - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Net_SetTimeout

-Sets the timeout for internet streams.
-

-signed char F_API FSOUND_Stream_Net_SetTimeout(
-int timeout
-);
-

Parameters

- - -
timeoutThe timeout value in ms
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-___________________
-Supported on the following platforms : Win32, Macintosh, Linux
-

See Also

-FSOUND_Stream_Close -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Net_SetTimeout + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Net_SetTimeout

+Sets the timeout for internet streams.
+

+signed char F_API FSOUND_Stream_Net_SetTimeout(
+int timeout
+);
+

Parameters

+ + +
timeoutThe timeout value in ms
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+___________________
+Supported on the following platforms : Win32, Macintosh, Linux
+

See Also

+FSOUND_Stream_Close +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Open.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Open.html index f6daf29c..57e58823 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Open.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Open.html @@ -1,135 +1,135 @@ - - - - -FSOUND_Stream_Open - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Open

-Opens an audio file/url/cd ready for streaming.
-This opens the file in preparation for playback in real-time, without needing to decode the whole file into memory first.
-

-FSOUND_STREAM * F_API FSOUND_Stream_Open(
-const char *name_or_data,
-unsigned int mode,
-int offset,
-int length
-);
-

Parameters

- - - - - -
name_or_dataName of the file to open, or pointer to data if FSOUND_LOADMEMORY is used.
-
modeSimple description of how to play the file. For all formats except raw PCM,
-FSOUND_LOOP*, FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_NONBLOCKING flags are the only ones supported.
-
offsetOptional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening. length must also be specified if this value is used.
-
lengthOptional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
-
-

Return Value

-On success, a pointer to an opened stream is returned.
-On failure, NULL is returned.
-

Remarks

-WAV support supports windows codec compressed WAV files.
---------------
-FSOUND_MPEGACCURATE is to be used cautiously. To open a file with this mode turned on, it has to scan the whole MP3 first. This can take several seconds if the file is big, or the harddisk/cpu is slow.
-A way to speed up this process would be to load the compressed mp3 into memory first, and use the FSOUND_LOADMEMORY flag with this function.
---------------
-NOTE : Internet stream limitations
-- URLs must start with "http://".
-- The only supported formats for HTTP streams are MP3 (must have .mp3 extension) and OggVorbis (must have .ogg extension).
---------------
-FSB streaming is not supported if the format from FSBank is 'Retain original format'. On PC platforms, only PCM and ADPCM FSB files are allowed.
---------------
-Note, on PlayStation 2 you cannot use FSOUND_LOADMEMORY, you may use FSOUND_LOADMEMORYIOP though.
---------------
-When opening with the FSOUND_NONBLOCKING flag, this function always succeeds at the point of being called.
-It will always return a valid channel handle, even though the file might fail to open. To determine any error in non blocking mode use FSOUND_Stream_GetOpenState.
---------------
-NOTE: CDDA Streaming (Win32 only!)
-To open a CD for CDDA streaming, specify the drive letter of a CD drive e.g. FSOUND_Stream_Open("d:", 0, 0, 0); FSOUND_Stream_Open will create a stream with multiple substreams, one for each CD track. Use FSOUND_Stream_SetSubStream to select which CD track to play.
-A number of options can be passed to FSOUND_Stream_Open along with the drive letter. They are :
-*? e.g. FSOUND_Stream_Open("d:*?", 0, 0, 0); This option will cause a tag field called "CD_DEVICE_INFO" to be attached to the stream. This tag field contains information on the specified CD device.
-*! e.g. FSOUND_Stream_Open("d:*!", 0, 0, 0); This option will cause the stream to be opened in "quick open" mode. When a stream is opened in this mode, calls to FSOUND_Stream_SetSubStream will return immediately making it quick to select each substream in turn and get the length of each CD track. Note that a stream in quick open mode cannot be played! Use quick open mode to get track lengths and then re-open the stream without quick open mode to actually play it.
-*j e.g. FSOUND_Stream_Open("d:*j", 0, 0, 0); This option turns jitter correction OFF.
-*a e.g. FSOUND_Stream_Open("d:*a", 0, 0, 0); This option will force FMOD to use ASPI to access the specified CD drive as opposed to NTSCSI. It should generally only be used as a last resort if FMOD is unable to access drives that are known to be working with other programs.
-Options can be combined like so: FSOUND_Stream_Open("d:*?!j", 0, 0, 0);
-If a nonblocking CDDA stream fails to open, a tag field called "CD_ERROR" will be attached to the stream. This tag field contains a textual description of why the stream failed to open.
-NOTE: FMOD will always try to use native NTSCSI support to communicate with CD devices before trying to use ASPI, unless the "*a" option is specified, in which case FMOD will only try to use ASPI. Unlike in pre-3.73 versions, FMOD can now access all CD drives when using ASPI.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_Close -, -FSOUND_Stream_GetLength -, -FSOUND_Stream_GetLengthMs -, -FSOUND_Stream_GetOpenState -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetInfo -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_OpenFromHandle -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -, -FSOUND_Stream_SetBufferSize -, -FSOUND_Stream_SetSubStream -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Open + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Open

+Opens an audio file/url/cd ready for streaming.
+This opens the file in preparation for playback in real-time, without needing to decode the whole file into memory first.
+

+FSOUND_STREAM * F_API FSOUND_Stream_Open(
+const char *name_or_data,
+unsigned int mode,
+int offset,
+int length
+);
+

Parameters

+ + + + + +
name_or_dataName of the file to open, or pointer to data if FSOUND_LOADMEMORY is used.
+
modeSimple description of how to play the file. For all formats except raw PCM,
+FSOUND_LOOP*, FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_NONBLOCKING flags are the only ones supported.
+
offsetOptional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening. length must also be specified if this value is used.
+
lengthOptional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
+
+

Return Value

+On success, a pointer to an opened stream is returned.
+On failure, NULL is returned.
+

Remarks

+WAV support supports windows codec compressed WAV files.
+--------------
+FSOUND_MPEGACCURATE is to be used cautiously. To open a file with this mode turned on, it has to scan the whole MP3 first. This can take several seconds if the file is big, or the harddisk/cpu is slow.
+A way to speed up this process would be to load the compressed mp3 into memory first, and use the FSOUND_LOADMEMORY flag with this function.
+--------------
+NOTE : Internet stream limitations
+- URLs must start with "http://".
+- The only supported formats for HTTP streams are MP3 (must have .mp3 extension) and OggVorbis (must have .ogg extension).
+--------------
+FSB streaming is not supported if the format from FSBank is 'Retain original format'. On PC platforms, only PCM and ADPCM FSB files are allowed.
+--------------
+Note, on PlayStation 2 you cannot use FSOUND_LOADMEMORY, you may use FSOUND_LOADMEMORYIOP though.
+--------------
+When opening with the FSOUND_NONBLOCKING flag, this function always succeeds at the point of being called.
+It will always return a valid channel handle, even though the file might fail to open. To determine any error in non blocking mode use FSOUND_Stream_GetOpenState.
+--------------
+NOTE: CDDA Streaming (Win32 only!)
+To open a CD for CDDA streaming, specify the drive letter of a CD drive e.g. FSOUND_Stream_Open("d:", 0, 0, 0); FSOUND_Stream_Open will create a stream with multiple substreams, one for each CD track. Use FSOUND_Stream_SetSubStream to select which CD track to play.
+A number of options can be passed to FSOUND_Stream_Open along with the drive letter. They are :
+*? e.g. FSOUND_Stream_Open("d:*?", 0, 0, 0); This option will cause a tag field called "CD_DEVICE_INFO" to be attached to the stream. This tag field contains information on the specified CD device.
+*! e.g. FSOUND_Stream_Open("d:*!", 0, 0, 0); This option will cause the stream to be opened in "quick open" mode. When a stream is opened in this mode, calls to FSOUND_Stream_SetSubStream will return immediately making it quick to select each substream in turn and get the length of each CD track. Note that a stream in quick open mode cannot be played! Use quick open mode to get track lengths and then re-open the stream without quick open mode to actually play it.
+*j e.g. FSOUND_Stream_Open("d:*j", 0, 0, 0); This option turns jitter correction OFF.
+*a e.g. FSOUND_Stream_Open("d:*a", 0, 0, 0); This option will force FMOD to use ASPI to access the specified CD drive as opposed to NTSCSI. It should generally only be used as a last resort if FMOD is unable to access drives that are known to be working with other programs.
+Options can be combined like so: FSOUND_Stream_Open("d:*?!j", 0, 0, 0);
+If a nonblocking CDDA stream fails to open, a tag field called "CD_ERROR" will be attached to the stream. This tag field contains a textual description of why the stream failed to open.
+NOTE: FMOD will always try to use native NTSCSI support to communicate with CD devices before trying to use ASPI, unless the "*a" option is specified, in which case FMOD will only try to use ASPI. Unlike in pre-3.73 versions, FMOD can now access all CD drives when using ASPI.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_Close +, +FSOUND_Stream_GetLength +, +FSOUND_Stream_GetLengthMs +, +FSOUND_Stream_GetOpenState +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetInfo +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_OpenFromHandle +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +, +FSOUND_Stream_SetBufferSize +, +FSOUND_Stream_SetSubStream +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_OpenFromHandle.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_OpenFromHandle.html index d710b922..94229cea 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_OpenFromHandle.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_OpenFromHandle.html @@ -1,64 +1,64 @@ - - - - -FSOUND_Stream_OpenFromHandle - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_OpenFromHandle

-

-FSOUND_STREAM * F_API FSOUND_Stream_OpenFromHandle(
-HANDLE handle,
-unsigned int mode
-);
-

Parameters

- - -
handleA pointer to a file HANDLE type that was retrieved from XOpenSoundtrackSong.
-
-

Return Value

-On success, a valid stream handle is returned.
-On failure, NULL is returned.
-

Remarks

-Use the XDK functions XFindFirstSoundtrack, XFindNextSoundtrack, XGetSoundtrackSongInfo and XOpenSoundtrackSong
-to enumerate and open WMA files saved onto the dashboard by users.
-___________________
-Supported on the following platforms : XBox
-

See Also

-FSOUND_Stream_Close. -, -FSOUND_Stream_Open -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_OpenFromHandle + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_OpenFromHandle

+

+FSOUND_STREAM * F_API FSOUND_Stream_OpenFromHandle(
+HANDLE handle,
+unsigned int mode
+);
+

Parameters

+ + +
handleA pointer to a file HANDLE type that was retrieved from XOpenSoundtrackSong.
+
+

Return Value

+On success, a valid stream handle is returned.
+On failure, NULL is returned.
+

Remarks

+Use the XDK functions XFindFirstSoundtrack, XFindNextSoundtrack, XGetSoundtrackSongInfo and XOpenSoundtrackSong
+to enumerate and open WMA files saved onto the dashboard by users.
+___________________
+Supported on the following platforms : XBox
+

See Also

+FSOUND_Stream_Close. +, +FSOUND_Stream_Open +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Play.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Play.html index 97fb2f05..3ff01229 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Play.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Play.html @@ -1,120 +1,120 @@ - - - - -FSOUND_Stream_Play - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Play

-Starts a pre-opened stream playing.
-

-int F_API FSOUND_Stream_Play(
-int channel,
-FSOUND_STREAM *stream
-);
-

Parameters

- - - -
channel0+ The channel index in the channel pool. This must not exceed the maximum number of channels allocated with FSOUND_Init
-FSOUND_FREE
-Chooses a free channel to play in. If all channels are used then it
-selects a channel with a sample playing that has a lower priority than the
-sample to be played.
-
streamPointer to the already opened stream to be played.
-
-

Return Value

-On success, the channel handle the stream is playing in is returned.
-On failure, -1 is returned.
-

Remarks

-When a stream starts to play, it inherits a special high priority (256).
-It cannot be rejected by other sound effect channels in the normal fashion as the user can never set a priority above 255 normally.
---------------
-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
---------------
-FSB streaming is not supported if the format from FSBank is 'Retain original format'. On PC platforms, only PCM and ADPCM FSB files are allowed.
---------------
-FSOUND_STEREOPAN is recommended for stereo streams if you call FSOUND_SetPan. This puts the left and right channel to full volume.
-Otherwise a normal pan will give half volume for left and right. See FSOUND_SetPan for more information on this.
---------------
-You can use normal channel based commands (such as FSOUND_SetVolume etc) on the return handle, as it is a channel handle.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetNumSubChannels -, -FSOUND_GetSubChannel -, -FSOUND_Init -, -FSOUND_SetPan -, -FSOUND_SetVolume -, -FSOUND_Stream_Close -, -FSOUND_Stream_Create -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_PlayEx -, -FSOUND_Stream_SetEndCallback -, -FSOUND_Stream_SetLoopCount -, -FSOUND_Stream_SetSubStream -, -FSOUND_Stream_SetSubStreamSentence -, -FSOUND_Stream_SetSyncCallback -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Play + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Play

+Starts a pre-opened stream playing.
+

+int F_API FSOUND_Stream_Play(
+int channel,
+FSOUND_STREAM *stream
+);
+

Parameters

+ + + +
channel0+ The channel index in the channel pool. This must not exceed the maximum number of channels allocated with FSOUND_Init
+FSOUND_FREE
+Chooses a free channel to play in. If all channels are used then it
+selects a channel with a sample playing that has a lower priority than the
+sample to be played.
+
streamPointer to the already opened stream to be played.
+
+

Return Value

+On success, the channel handle the stream is playing in is returned.
+On failure, -1 is returned.
+

Remarks

+When a stream starts to play, it inherits a special high priority (256).
+It cannot be rejected by other sound effect channels in the normal fashion as the user can never set a priority above 255 normally.
+--------------
+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+--------------
+FSB streaming is not supported if the format from FSBank is 'Retain original format'. On PC platforms, only PCM and ADPCM FSB files are allowed.
+--------------
+FSOUND_STEREOPAN is recommended for stereo streams if you call FSOUND_SetPan. This puts the left and right channel to full volume.
+Otherwise a normal pan will give half volume for left and right. See FSOUND_SetPan for more information on this.
+--------------
+You can use normal channel based commands (such as FSOUND_SetVolume etc) on the return handle, as it is a channel handle.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetNumSubChannels +, +FSOUND_GetSubChannel +, +FSOUND_Init +, +FSOUND_SetPan +, +FSOUND_SetVolume +, +FSOUND_Stream_Close +, +FSOUND_Stream_Create +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_PlayEx +, +FSOUND_Stream_SetEndCallback +, +FSOUND_Stream_SetLoopCount +, +FSOUND_Stream_SetSubStream +, +FSOUND_Stream_SetSubStreamSentence +, +FSOUND_Stream_SetSyncCallback +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_PlayEx.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_PlayEx.html index 6d3dc2f7..d0be5983 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_PlayEx.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_PlayEx.html @@ -1,108 +1,108 @@ - - - - -FSOUND_Stream_PlayEx - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_PlayEx

-Extended featured version of FSOUND_Stream_Play.
-Added functionality includes the ability to start the stream paused. This allows attributes
-of a stream channel to be set freely before the stream actually starts playing, until FSOUND_SetPaused(FALSE) is used.
-Also added is the ability to associate the stream channel to a specified DSP unit. This allows
-the user to 'group' channels into seperate DSP units, which allows effects to be inserted
-between these 'groups', and allow various things like having one group affected by reverb (wet mix) and another group of
-channels unaffected (dry). This is useful to seperate things like music from being affected
-by DSP effects, while other sound effects are.
-

-int F_API FSOUND_Stream_PlayEx(
-int channel,
-FSOUND_STREAM *stream,
-FSOUND_DSPUNIT *dspunit,
-signed char paused
-);
-

Parameters

- - - - - -
channel0+
-The absolute channel number in the channel pool.
-Remember software channels come first, followed by hardware channels.
-You cannot play a software sample on a hardware channel and vice versa.
-FSOUND_FREE
-Chooses a free channel to play in. If all channels are used then it
-selects a channel with a sample playing that has an EQUAL or LOWER priority
-than the sample to be played.
-
streamPointer to the already opened stream to be played.
-
dspunitPointer to a dsp unit to attach the channel to.
-
pausedStart the stream paused or not. Pausing the stream channel allows attributes to be set before it is unpaused.
-
-

Return Value

-On success, a channel handle the stream is playing in is returned.
-On failure, -1 is returned.
-

Remarks

-When a stream starts to play, it inherits a special high priority (256).
-It cannot be rejected by other sound effect channels in the normal fashion as the user can never set a priority above 255 normally.
---------
-FSOUND_STEREOPAN is recommended for stereo streams if you call FSOUND_SetPan. This puts the left and right channel to full volume.
-Otherwise a normal pan will give half volume for left and right. See FSOUND_SetPan for more information on this.
---------
-You can use normal channel based commands (such as FSOUND_SetVolume etc) on the return handle, as it is a channel handle.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_GetNumSubChannels -, -FSOUND_GetSubChannel -, -FSOUND_SetPan -, -FSOUND_SetPaused -, -FSOUND_SetVolume -, -FSOUND_Stream_Close -, -FSOUND_Stream_Create -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_Stop -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_PlayEx + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_PlayEx

+Extended featured version of FSOUND_Stream_Play.
+Added functionality includes the ability to start the stream paused. This allows attributes
+of a stream channel to be set freely before the stream actually starts playing, until FSOUND_SetPaused(FALSE) is used.
+Also added is the ability to associate the stream channel to a specified DSP unit. This allows
+the user to 'group' channels into seperate DSP units, which allows effects to be inserted
+between these 'groups', and allow various things like having one group affected by reverb (wet mix) and another group of
+channels unaffected (dry). This is useful to seperate things like music from being affected
+by DSP effects, while other sound effects are.
+

+int F_API FSOUND_Stream_PlayEx(
+int channel,
+FSOUND_STREAM *stream,
+FSOUND_DSPUNIT *dspunit,
+signed char paused
+);
+

Parameters

+ + + + + +
channel0+
+The absolute channel number in the channel pool.
+Remember software channels come first, followed by hardware channels.
+You cannot play a software sample on a hardware channel and vice versa.
+FSOUND_FREE
+Chooses a free channel to play in. If all channels are used then it
+selects a channel with a sample playing that has an EQUAL or LOWER priority
+than the sample to be played.
+
streamPointer to the already opened stream to be played.
+
dspunitPointer to a dsp unit to attach the channel to.
+
pausedStart the stream paused or not. Pausing the stream channel allows attributes to be set before it is unpaused.
+
+

Return Value

+On success, a channel handle the stream is playing in is returned.
+On failure, -1 is returned.
+

Remarks

+When a stream starts to play, it inherits a special high priority (256).
+It cannot be rejected by other sound effect channels in the normal fashion as the user can never set a priority above 255 normally.
+--------
+FSOUND_STEREOPAN is recommended for stereo streams if you call FSOUND_SetPan. This puts the left and right channel to full volume.
+Otherwise a normal pan will give half volume for left and right. See FSOUND_SetPan for more information on this.
+--------
+You can use normal channel based commands (such as FSOUND_SetVolume etc) on the return handle, as it is a channel handle.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_GetNumSubChannels +, +FSOUND_GetSubChannel +, +FSOUND_SetPan +, +FSOUND_SetPaused +, +FSOUND_SetVolume +, +FSOUND_Stream_Close +, +FSOUND_Stream_Create +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_Stop +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetBufferSize.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetBufferSize.html index 344d3481..2256bc8c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetBufferSize.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetBufferSize.html @@ -1,69 +1,69 @@ - - - - -FSOUND_Stream_SetBufferSize - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetBufferSize

-Sets the internal file buffersize for audio streaming of data for the NEXT stream opened with FSOUND_Stream_Open.
-Larger values will consume more memory (see remarks), whereas smaller values may be affected by large delays in disk access, especially from CDROM.
-

-signed char F_API FSOUND_Stream_SetBufferSize(
-int ms
-);
-

Parameters

- - -
msTime in milliseconds between stream updates. FMOD tries to access the disk and decompress data every period specified. Values less than 50 result in an error.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-The default setting is 400ms.
-To calculate memory usage for a stream buffer, it is a simple matter of calculating sizebytes = streambuffersize * sample rate / 1000 * (bitdepth / 8) * numchannels * 2, where numchannels is 1 for mono, or 2 for stereo files.
-It is multiplied by 2 because FSOUND stream buffers are double buffers.
-Note this function does not affect user created streams, as the buffer size is specified in FSOUND_Stream_Create.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_SetDiskBusy -, -FSOUND_Stream_Create -, -FSOUND_Stream_Open -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetBufferSize + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetBufferSize

+Sets the internal file buffersize for audio streaming of data for the NEXT stream opened with FSOUND_Stream_Open.
+Larger values will consume more memory (see remarks), whereas smaller values may be affected by large delays in disk access, especially from CDROM.
+

+signed char F_API FSOUND_Stream_SetBufferSize(
+int ms
+);
+

Parameters

+ + +
msTime in milliseconds between stream updates. FMOD tries to access the disk and decompress data every period specified. Values less than 50 result in an error.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+The default setting is 400ms.
+To calculate memory usage for a stream buffer, it is a simple matter of calculating sizebytes = streambuffersize * sample rate / 1000 * (bitdepth / 8) * numchannels * 2, where numchannels is 1 for mono, or 2 for stereo files.
+It is multiplied by 2 because FSOUND stream buffers are double buffers.
+Note this function does not affect user created streams, as the buffer size is specified in FSOUND_Stream_Create.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_SetDiskBusy +, +FSOUND_Stream_Create +, +FSOUND_Stream_Open +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetEndCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetEndCallback.html index b6226cb6..38c05e6c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetEndCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetEndCallback.html @@ -1,76 +1,76 @@ - - - - -FSOUND_Stream_SetEndCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetEndCallback

-Sets a callback function for when a stream has ended.
-

-signed char F_API FSOUND_Stream_SetEndCallback(
-FSOUND_STREAM *stream,
-FSOUND_STREAMCALLBACK callback,
-void *userdata
-);
-

Parameters

- - - - -
streamPointer to the stream to callback on when it is finished.
-
callbackFunction to be called when stream ends.
-
userdatadata that is passed into the callback at the end of the stream.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Only calls back when a stream stops. (not when a looping stream reaches its end point)
-Note it uses a FSOUND_STREAMCALLBACK function callback. This is normally for user streams but for
-the sake of re-usability this prototype is used. 'buff' and 'length' are NULL and 0 in this case
-when the callback occurs. The return value can be TRUE or FALSE it is ignored.
------------
-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_Play -, -FSOUND_STREAMCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetEndCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetEndCallback

+Sets a callback function for when a stream has ended.
+

+signed char F_API FSOUND_Stream_SetEndCallback(
+FSOUND_STREAM *stream,
+FSOUND_STREAMCALLBACK callback,
+void *userdata
+);
+

Parameters

+ + + + +
streamPointer to the stream to callback on when it is finished.
+
callbackFunction to be called when stream ends.
+
userdatadata that is passed into the callback at the end of the stream.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Only calls back when a stream stops. (not when a looping stream reaches its end point)
+Note it uses a FSOUND_STREAMCALLBACK function callback. This is normally for user streams but for
+the sake of re-usability this prototype is used. 'buff' and 'length' are NULL and 0 in this case
+when the callback occurs. The return value can be TRUE or FALSE it is ignored.
+-----------
+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_Play +, +FSOUND_STREAMCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopCount.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopCount.html index 39c24c8a..550c3595 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopCount.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopCount.html @@ -1,66 +1,66 @@ - - - - -FSOUND_Stream_SetLoopCount - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetLoopCount

-Sets the stream to loop the number of times specified by the user. If not called it loops forever.
-

-signed char F_API FSOUND_Stream_SetLoopCount(
-FSOUND_STREAM *stream,
-int count
-);
-

Parameters

- - - -
streamPointer to the stream to set loop count on.
-
countNumber of times to loop. 0 would be similar to having FSOUND_LOOP_OFF set. <0 is infinity.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This specifies how many loops, not how many times to play the sound back. Therefore when you specify 0, you will hear the sound once, if you specify 1, you will hear the sound twice, and so on.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_Play -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetLoopCount + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetLoopCount

+Sets the stream to loop the number of times specified by the user. If not called it loops forever.
+

+signed char F_API FSOUND_Stream_SetLoopCount(
+FSOUND_STREAM *stream,
+int count
+);
+

Parameters

+ + + +
streamPointer to the stream to set loop count on.
+
countNumber of times to loop. 0 would be similar to having FSOUND_LOOP_OFF set. <0 is infinity.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This specifies how many loops, not how many times to play the sound back. Therefore when you specify 0, you will hear the sound once, if you specify 1, you will hear the sound twice, and so on.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_Play +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopPoints.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopPoints.html index 056fa8f1..1bf3e393 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopPoints.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetLoopPoints.html @@ -1,68 +1,68 @@ - - - - -FSOUND_Stream_SetLoopPoints - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetLoopPoints

-Sets the loop points for a stream.
-

-DLL_API signed char F_API FSOUND_Stream_SetLoopPoints(
-FSOUND_STREAM *stream,
-unsigned int loopstart,
-unsigned int loopend
-);
-

Parameters

- - - - -
streamThe stream to set the loop points on.
-
loopstartThe start of the loop, specified in PCM SAMPLES.
-
loopendThe end of the loop, specified in PCM SAMPLES.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-For streams, setting looppoints is reasonably accurate but should not be assumed to be perfectly sample accurate in all cases.
-It depends on the compression format in some cases as seek positions need to be rounded to the nearest compression block offset.
-FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
-You cannot call this function wile the stream is playing, it has to be stopped.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetLoopPoints + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetLoopPoints

+Sets the loop points for a stream.
+

+DLL_API signed char F_API FSOUND_Stream_SetLoopPoints(
+FSOUND_STREAM *stream,
+unsigned int loopstart,
+unsigned int loopend
+);
+

Parameters

+ + + + +
streamThe stream to set the loop points on.
+
loopstartThe start of the loop, specified in PCM SAMPLES.
+
loopendThe end of the loop, specified in PCM SAMPLES.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+For streams, setting looppoints is reasonably accurate but should not be assumed to be perfectly sample accurate in all cases.
+It depends on the compression format in some cases as seek positions need to be rounded to the nearest compression block offset.
+FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
+You cannot call this function wile the stream is playing, it has to be stopped.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetMode.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetMode.html index 7d5ed2e2..5c7a4d64 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetMode.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetMode.html @@ -1,69 +1,69 @@ - - - - -FSOUND_Stream_SetMode - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetMode

-Set a streams mode.
-

-signed char F_API FSOUND_Stream_SetMode(
-FSOUND_STREAM *stream,
-unsigned int mode
-);
-

Parameters

- - - -
streamPointer to the stream to have the mode set.
-
modeThe mode bits to set from FSOUND_MODES.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-Only the following modes are accepted, others will be filtered out.
-FSOUND_LOOP_BIDI, FSOUND_LOOP_NORMAL, FSOUND_LOOP_OFF, FSOUND_2D. FSOUND_LOOP_BIDI is treated as FSOUND_LOOP_NORMAL. FSOUND_2D is accepted only if the sound is not hardware.
-On Playstation 2, XBox and GameCube, FSOUND_HW2D and FSOUND_HW3D are supported, so you can change between them at runtime.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_GetMode -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetMode + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetMode

+Set a streams mode.
+

+signed char F_API FSOUND_Stream_SetMode(
+FSOUND_STREAM *stream,
+unsigned int mode
+);
+

Parameters

+ + + +
streamPointer to the stream to have the mode set.
+
modeThe mode bits to set from FSOUND_MODES.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+Only the following modes are accepted, others will be filtered out.
+FSOUND_LOOP_BIDI, FSOUND_LOOP_NORMAL, FSOUND_LOOP_OFF, FSOUND_2D. FSOUND_LOOP_BIDI is treated as FSOUND_LOOP_NORMAL. FSOUND_2D is accepted only if the sound is not hardware.
+On Playstation 2, XBox and GameCube, FSOUND_HW2D and FSOUND_HW3D are supported, so you can change between them at runtime.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_GetMode +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetPosition.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetPosition.html index 3d536d6b..b38de989 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetPosition.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetPosition.html @@ -1,71 +1,71 @@ - - - - -FSOUND_Stream_SetPosition - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetPosition

-Sets the current stream's FILE position in BYTES.
-

-signed char F_API FSOUND_Stream_SetPosition(
-FSOUND_STREAM *stream,
-unsigned int position
-);
-

Parameters

- - - -
streamPointer to the stream to have its position set.
-
positionOffset in bytes from start of actual sound data (not including any header)
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Position functions for streams talk in bytes and NOT samples.
-The reason for not taking the header into account is people usually want to know the offset to seek to relative to the start of their data (ie as they see it in soundforge or whatever), not from offset 0 which is almost meaningless if you dont know the format.
---------------
-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetLength -, -FSOUND_Stream_GetPosition -, -FSOUND_Stream_SetTime -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetPosition + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetPosition

+Sets the current stream's FILE position in BYTES.
+

+signed char F_API FSOUND_Stream_SetPosition(
+FSOUND_STREAM *stream,
+unsigned int position
+);
+

Parameters

+ + + +
streamPointer to the stream to have its position set.
+
positionOffset in bytes from start of actual sound data (not including any header)
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Position functions for streams talk in bytes and NOT samples.
+The reason for not taking the header into account is people usually want to know the offset to seek to relative to the start of their data (ie as they see it in soundforge or whatever), not from offset 0 which is almost meaningless if you dont know the format.
+--------------
+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetLength +, +FSOUND_Stream_GetPosition +, +FSOUND_Stream_SetTime +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStream.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStream.html index ded2a995..aa43fa86 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStream.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStream.html @@ -1,76 +1,76 @@ - - - - -FSOUND_Stream_SetSubStream - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetSubStream

-Seeks a stream to the substream inside a multi-stream FSB bank file, specified by its index.
-

-signed char F_API FSOUND_Stream_SetSubStream(
-FSOUND_STREAM *stream,
-int index
-);
-

Parameters

- - - -
streamHandle to the stream to have its position set.
-
indexThe index of the stream within the FSB file.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-A stream will stop if this function is called, as it needs to seek and flush the buffer.
-Indicies for this function are generated as user friendly constants when compiling the FSB bank, and are available in the relevant generated header file.
---------------
-If the stream has been opened with FSOUND_NONBLOCKING, this function will ALWAYS succeed, but puts the stream back into a non-ready state. You then have to poll after calling this to make sure the stream is ready.
-You can either do this by calling FSOUND_Stream_Play repeatedly/once a frame until it is succeeds, or FSOUND_Stream_GetOpenState.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetNumSubStreams -, -FSOUND_Stream_GetOpenState -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_SetSubStreamSentence -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetSubStream + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetSubStream

+Seeks a stream to the substream inside a multi-stream FSB bank file, specified by its index.
+

+signed char F_API FSOUND_Stream_SetSubStream(
+FSOUND_STREAM *stream,
+int index
+);
+

Parameters

+ + + +
streamHandle to the stream to have its position set.
+
indexThe index of the stream within the FSB file.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+A stream will stop if this function is called, as it needs to seek and flush the buffer.
+Indicies for this function are generated as user friendly constants when compiling the FSB bank, and are available in the relevant generated header file.
+--------------
+If the stream has been opened with FSOUND_NONBLOCKING, this function will ALWAYS succeed, but puts the stream back into a non-ready state. You then have to poll after calling this to make sure the stream is ready.
+You can either do this by calling FSOUND_Stream_Play repeatedly/once a frame until it is succeeds, or FSOUND_Stream_GetOpenState.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetNumSubStreams +, +FSOUND_Stream_GetOpenState +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_SetSubStreamSentence +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStreamSentence.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStreamSentence.html index 3cb51c8a..dca826a0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStreamSentence.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSubStreamSentence.html @@ -1,81 +1,81 @@ - - - - -FSOUND_Stream_SetSubStreamSentence - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetSubStreamSentence

-This function allows the user to describe the playback order of a list of substreams. The substreams will be played back in order seamlessly.
-

-signed char F_API FSOUND_Stream_SetSubStreamSentence(
-FSOUND_STREAM *stream,
-const int *sentencelist,
-int numitems
-);
-

Parameters

- - - - -
streamPointer to the stream to have its position returned.
-
sentencelistThis is a pointer to an array of 32bit integers, describing a list of substream indicies to play back.
-
numitemsThe number of entries in the sentence list.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-This feature only works with FSB files that have multiple streams stored within it.
-To remove any sentence, simply call this function with NULL and 0.
-FMOD copies the list from the supplied pointer. Once the pointer is used, the caller can discard the original array.
-This function will fail if the stream is playing. The stream must be stopped for it to work.
-------------
-If the stream is opened with FSOUND_NONBLOCKING, and the stream is not ready (it is still opening), then this function will return FALSE.
-When it is ready, it will return TRUE, but after this call the stream is put back into a non-ready state, because it is asynchronously seeking again.
-You then have to poll after calling this to make sure the stream is ready.
-You can either do this by calling FSOUND_Stream_Play repeatedly/once a frame until it is succeeds, or FSOUND_Stream_GetOpenState.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetNumSubStreams -, -FSOUND_Stream_GetOpenState -, -FSOUND_Stream_Play -, -FSOUND_Stream_SetSubStream -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetSubStreamSentence + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetSubStreamSentence

+This function allows the user to describe the playback order of a list of substreams. The substreams will be played back in order seamlessly.
+

+signed char F_API FSOUND_Stream_SetSubStreamSentence(
+FSOUND_STREAM *stream,
+const int *sentencelist,
+int numitems
+);
+

Parameters

+ + + + +
streamPointer to the stream to have its position returned.
+
sentencelistThis is a pointer to an array of 32bit integers, describing a list of substream indicies to play back.
+
numitemsThe number of entries in the sentence list.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+This feature only works with FSB files that have multiple streams stored within it.
+To remove any sentence, simply call this function with NULL and 0.
+FMOD copies the list from the supplied pointer. Once the pointer is used, the caller can discard the original array.
+This function will fail if the stream is playing. The stream must be stopped for it to work.
+------------
+If the stream is opened with FSOUND_NONBLOCKING, and the stream is not ready (it is still opening), then this function will return FALSE.
+When it is ready, it will return TRUE, but after this call the stream is put back into a non-ready state, because it is asynchronously seeking again.
+You then have to poll after calling this to make sure the stream is ready.
+You can either do this by calling FSOUND_Stream_Play repeatedly/once a frame until it is succeeds, or FSOUND_Stream_GetOpenState.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetNumSubStreams +, +FSOUND_Stream_GetOpenState +, +FSOUND_Stream_Play +, +FSOUND_Stream_SetSubStream +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSyncCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSyncCallback.html index 7404f8be..9940a00a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSyncCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSyncCallback.html @@ -1,91 +1,91 @@ - - - - -FSOUND_Stream_SetSyncCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetSyncCallback

-Sets a callback function for when a stream passes over a WAV tag/marker. These are markers that
-a sound editing program such as Sound Forge can drop into the actual wave data. FMOD will
-trigger callbacks with these markers when the stream plays, and pass in the string through the callback that the marker contains.
-

-signed char F_API FSOUND_Stream_SetSyncCallback(
-FSOUND_STREAM *stream,
-FSOUND_STREAMCALLBACK callback,
-void *userdata
-);
-

Parameters

- - - - -
streamPointer to the stream to callback when a sync point is reached.
-
callbackFunction to call when sync point is reached.
-
userdatauser data that is passed into the callback.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Note it uses a FSOUND_STREAMCALLBACK function callback. This is normally for user streams but for
-the sake of re-usability this prototype is used. 'buff' is a null terminated string provided by
-the marker. 'len' is the offset in samples that the marker was set at.
-The return value can be TRUE or FALSE, it is ignored.
------------
-Note you can save a WAV out using an MP3 wav codec (and then just rename the WAV to MP3 if you like) to get
-sync marker support for compressed MP3 files. FMOD will pick up on this and read the markers out.
---------------
-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_AddSyncPoint -, -FSOUND_Stream_DeleteSyncPoint -, -FSOUND_Stream_GetNumSyncPoints -, -FSOUND_Stream_GetSyncPoint -, -FSOUND_Stream_GetSyncPointInfo -, -FSOUND_Stream_Play -, -FSOUND_STREAMCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetSyncCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetSyncCallback

+Sets a callback function for when a stream passes over a WAV tag/marker. These are markers that
+a sound editing program such as Sound Forge can drop into the actual wave data. FMOD will
+trigger callbacks with these markers when the stream plays, and pass in the string through the callback that the marker contains.
+

+signed char F_API FSOUND_Stream_SetSyncCallback(
+FSOUND_STREAM *stream,
+FSOUND_STREAMCALLBACK callback,
+void *userdata
+);
+

Parameters

+ + + + +
streamPointer to the stream to callback when a sync point is reached.
+
callbackFunction to call when sync point is reached.
+
userdatauser data that is passed into the callback.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Note it uses a FSOUND_STREAMCALLBACK function callback. This is normally for user streams but for
+the sake of re-usability this prototype is used. 'buff' is a null terminated string provided by
+the marker. 'len' is the offset in samples that the marker was set at.
+The return value can be TRUE or FALSE, it is ignored.
+-----------
+Note you can save a WAV out using an MP3 wav codec (and then just rename the WAV to MP3 if you like) to get
+sync marker support for compressed MP3 files. FMOD will pick up on this and read the markers out.
+--------------
+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_AddSyncPoint +, +FSOUND_Stream_DeleteSyncPoint +, +FSOUND_Stream_GetNumSyncPoints +, +FSOUND_Stream_GetSyncPoint +, +FSOUND_Stream_GetSyncPointInfo +, +FSOUND_Stream_Play +, +FSOUND_STREAMCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSynchCallback.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSynchCallback.html index d95cc30b..155c3cd0 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSynchCallback.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetSynchCallback.html @@ -1,91 +1,91 @@ - - - - -FSOUND_Stream_SetSynchCallback - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetSynchCallback

-Sets a callback function for when a stream passes over a WAV tag/marker. These are markers that
-a sound editing program such as Sound Forge can drop into the actual wave data. FMOD will
-trigger callbacks with these markers when the stream plays, and pass in the string through the callback that the marker contains.
-

-signed char F_API FSOUND_Stream_SetSynchCallback(
-FSOUND_STREAM *stream,
-FSOUND_STREAMCALLBACK callback,
-int userdata
-);
-

Parameters

- - - - -
streamPointer to the stream to callback when a synch point is reached.
-
callbackFunction to call when synch point is reached.
-
userdatauser data that is passed into the callback.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-Note it uses a FSOUND_STREAMCALLBACK function callback. This is normally for user streams but for
-the sake of re-usability this prototype is used. 'buff' is a null terminated string provided by
-the marker. 'len' is the offset in samples that the marker was set at.
-The return value can be TRUE or FALSE, it is ignored.
------------
-Note you can save a WAV out using an MP3 wav codec (and then just rename the WAV to MP3 if you like) to get
-synch marker support for compressed MP3 files. FMOD will pick up on this and read the markers out.
------------
-WMA/ASF/Internet streaming do not support this function.
---------------
-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_MODES -, -FSOUND_Stream_AddSynchPoint -, -FSOUND_Stream_DeleteSynchPoint -, -FSOUND_Stream_GetNumSynchPoints -, -FSOUND_Stream_GetSynchPointInfo -, -FSOUND_Stream_Play -, -FSOUND_STREAMCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Fri Jul 11 16:00:55 2003 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetSynchCallback + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetSynchCallback

+Sets a callback function for when a stream passes over a WAV tag/marker. These are markers that
+a sound editing program such as Sound Forge can drop into the actual wave data. FMOD will
+trigger callbacks with these markers when the stream plays, and pass in the string through the callback that the marker contains.
+

+signed char F_API FSOUND_Stream_SetSynchCallback(
+FSOUND_STREAM *stream,
+FSOUND_STREAMCALLBACK callback,
+int userdata
+);
+

Parameters

+ + + + +
streamPointer to the stream to callback when a synch point is reached.
+
callbackFunction to call when synch point is reached.
+
userdatauser data that is passed into the callback.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+Note it uses a FSOUND_STREAMCALLBACK function callback. This is normally for user streams but for
+the sake of re-usability this prototype is used. 'buff' is a null terminated string provided by
+the marker. 'len' is the offset in samples that the marker was set at.
+The return value can be TRUE or FALSE, it is ignored.
+-----------
+Note you can save a WAV out using an MP3 wav codec (and then just rename the WAV to MP3 if you like) to get
+synch marker support for compressed MP3 files. FMOD will pick up on this and read the markers out.
+-----------
+WMA/ASF/Internet streaming do not support this function.
+--------------
+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_MODES +, +FSOUND_Stream_AddSynchPoint +, +FSOUND_Stream_DeleteSynchPoint +, +FSOUND_Stream_GetNumSynchPoints +, +FSOUND_Stream_GetSynchPointInfo +, +FSOUND_Stream_Play +, +FSOUND_STREAMCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Fri Jul 11 16:00:55 2003 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetTime.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetTime.html index df070c32..f999981b 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetTime.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_SetTime.html @@ -1,71 +1,71 @@ - - - - -FSOUND_Stream_SetTime - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_SetTime

-Sets the current stream's FILE position in MILLISECONDS.
-

-signed char F_API FSOUND_Stream_SetTime(
-FSOUND_STREAM *stream,
-int ms
-);
-

Parameters

- - - -
streamPointer to the stream to have its position set.
-
msTime in milliseconds to seek to.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_GetLength -, -FSOUND_Stream_GetPosition -, -FSOUND_Stream_GetTime -, -FSOUND_Stream_SetPosition -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_SetTime + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_SetTime

+Sets the current stream's FILE position in MILLISECONDS.
+

+signed char F_API FSOUND_Stream_SetTime(
+FSOUND_STREAM *stream,
+int ms
+);
+

Parameters

+ + + +
streamPointer to the stream to have its position set.
+
msTime in milliseconds to seek to.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+FSOUND_MPEGACCURATE will need to be used with mp3 files that use VBR encoding for more accuracy.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_GetLength +, +FSOUND_Stream_GetPosition +, +FSOUND_Stream_GetTime +, +FSOUND_Stream_SetPosition +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Stop.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Stop.html index 8efcca53..dc14d1b8 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Stop.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Stream_Stop.html @@ -1,84 +1,84 @@ - - - - -FSOUND_Stream_Stop - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Stream_Stop

-Stops a stream from playing.
-

-signed char F_API FSOUND_Stream_Stop(
-FSOUND_STREAM *stream
-);
-

Parameters

- - -
streamPointer to a stream to stop.
-
-

Return Value

-On success, TRUE is returned.
-On failure, FALSE is returned.
-

Remarks

-The stream is still prepared and sitting in memory ready to go. Use FSOUND_Stream_Close on the stream to completely remove it.
-If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_Stream_Close -, -FSOUND_Stream_Create -, -FSOUND_Stream_Net_GetBufferProperties -, -FSOUND_Stream_Net_GetLastServerStatus -, -FSOUND_Stream_Net_GetStatus -, -FSOUND_Stream_Net_SetBufferProperties -, -FSOUND_Stream_Net_SetMetadataCallback -, -FSOUND_Stream_Net_SetProxy -, -FSOUND_Stream_Net_SetTimeout -, -FSOUND_Stream_Open -, -FSOUND_Stream_Play -, -FSOUND_Stream_PlayEx -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:36 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Stream_Stop + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Stream_Stop

+Stops a stream from playing.
+

+signed char F_API FSOUND_Stream_Stop(
+FSOUND_STREAM *stream
+);
+

Parameters

+ + +
streamPointer to a stream to stop.
+
+

Return Value

+On success, TRUE is returned.
+On failure, FALSE is returned.
+

Remarks

+The stream is still prepared and sitting in memory ready to go. Use FSOUND_Stream_Close on the stream to completely remove it.
+If the stream has been opened with FSOUND_NONBLOCKING, this function will not succeed until the stream is ready.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_Stream_Close +, +FSOUND_Stream_Create +, +FSOUND_Stream_Net_GetBufferProperties +, +FSOUND_Stream_Net_GetLastServerStatus +, +FSOUND_Stream_Net_GetStatus +, +FSOUND_Stream_Net_SetBufferProperties +, +FSOUND_Stream_Net_SetMetadataCallback +, +FSOUND_Stream_Net_SetProxy +, +FSOUND_Stream_Net_SetTimeout +, +FSOUND_Stream_Open +, +FSOUND_Stream_Play +, +FSOUND_Stream_PlayEx +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:36 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TAGFIELD_TYPE.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TAGFIELD_TYPE.html index dbe0391d..999f533a 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TAGFIELD_TYPE.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TAGFIELD_TYPE.html @@ -1,63 +1,63 @@ - - - - -FSOUND_TAGFIELD_TYPE - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - -Next Topic -
-
-
-
[Enum]
-

FSOUND_TAGFIELD_TYPE

-Describes the type of a particular tag field.
-

-

Enumerators

- - - - - - - -
FSOUND_TAGFIELD_VORBISCOMMENT/* A vorbis comment */
-
FSOUND_TAGFIELD_ID3V1/* Part of an ID3v1 tag */
-
FSOUND_TAGFIELD_ID3V2/* An ID3v2 frame */
-
FSOUND_TAGFIELD_SHOUTCAST/* A SHOUTcast header line */
-
FSOUND_TAGFIELD_ICECAST/* An Icecast header line */
-
FSOUND_TAGFIELD_ASF/* An Advanced Streaming Format header line */
-
-

See Also

-FSOUND_Stream_FindTagField -, -FSOUND_Stream_GetNumTagFields -, -FSOUND_Stream_GetTagField -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_TAGFIELD_TYPE + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + +Next Topic +
+
+
+
[Enum]
+

FSOUND_TAGFIELD_TYPE

+Describes the type of a particular tag field.
+

+

Enumerators

+ + + + + + + +
FSOUND_TAGFIELD_VORBISCOMMENT/* A vorbis comment */
+
FSOUND_TAGFIELD_ID3V1/* Part of an ID3v1 tag */
+
FSOUND_TAGFIELD_ID3V2/* An ID3v2 frame */
+
FSOUND_TAGFIELD_SHOUTCAST/* A SHOUTcast header line */
+
FSOUND_TAGFIELD_ICECAST/* An Icecast header line */
+
FSOUND_TAGFIELD_ASF/* An Advanced Streaming Format header line */
+
+

See Also

+FSOUND_Stream_FindTagField +, +FSOUND_Stream_GetNumTagFields +, +FSOUND_Stream_GetTagField +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TELLCALLBACK.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TELLCALLBACK.html index e2c3ee3d..95e75f63 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TELLCALLBACK.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TELLCALLBACK.html @@ -1,69 +1,69 @@ - - - - -FSOUND_TELLCALLBACK - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_TELLCALLBACK

-Callback for returning the current file pointer position within the file.
-

-int F_CALLBACKAPI FSOUND_TELLCALLBACK(
-void *handle
-);
-

Parameters

- - -
handleThis is the handle you returned from the open callback to use for your own file routines.
-
-

Return Value

-On success, the offset within the file in bytes is returned.
-On failure, -1 is returned.
-

Remarks

-You must return the offset from the base of the file, using this routine.
-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
-

See Also

-FSOUND_CLOSECALLBACK -, -FSOUND_File_SetCallbacks -, -FSOUND_OPENCALLBACK -, -FSOUND_READCALLBACK -, -FSOUND_SEEKCALLBACK -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_TELLCALLBACK + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_TELLCALLBACK

+Callback for returning the current file pointer position within the file.
+

+int F_CALLBACKAPI FSOUND_TELLCALLBACK(
+void *handle
+);
+

Parameters

+ + +
handleThis is the handle you returned from the open callback to use for your own file routines.
+
+

Return Value

+On success, the offset within the file in bytes is returned.
+On failure, -1 is returned.
+

Remarks

+You must return the offset from the base of the file, using this routine.
+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, GameCube
+

See Also

+FSOUND_CLOSECALLBACK +, +FSOUND_File_SetCallbacks +, +FSOUND_OPENCALLBACK +, +FSOUND_READCALLBACK +, +FSOUND_SEEKCALLBACK +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TOC_TAG.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TOC_TAG.html index 28c204f0..071bdebb 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TOC_TAG.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_TOC_TAG.html @@ -1,68 +1,68 @@ - - - - -FSOUND_TOC_TAG - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[Structure]
-

FSOUND_TOC_TAG

-Structure defining a CD table of contents. This structure is returned as a tag from FSOUND_Stream_FindTagField when the tag name "CD_TOC" is specified.
-Note: All tracks on the CD - including data tracks- will be represented in this structure so it's use for anything other than generating disc id information is not recommended.
-See the cdda example program for info on retrieving and using this structure.
-

-

Members

- - - - - - - - - - - -
charname[4]/* The string "TOC", just in case this structure is accidentally treated as a string */
-
intnumtracks/* The number of tracks on the CD */
-
intmin[100]/* The start offset of each track in minutes */
-
intsec[100]/* The start offset of each track in seconds */
-
intframe[100]/* The start offset of each track in frames */
-
-

See Also

-FSOUND_Stream_FindTagField -, -FSOUND_Stream_Open -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_TOC_TAG + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[Structure]
+

FSOUND_TOC_TAG

+Structure defining a CD table of contents. This structure is returned as a tag from FSOUND_Stream_FindTagField when the tag name "CD_TOC" is specified.
+Note: All tracks on the CD - including data tracks- will be represented in this structure so it's use for anything other than generating disc id information is not recommended.
+See the cdda example program for info on retrieving and using this structure.
+

+

Members

+ + + + + + + + + + + +
charname[4]/* The string "TOC", just in case this structure is accidentally treated as a string */
+
intnumtracks/* The number of tracks on the CD */
+
intmin[100]/* The start offset of each track in minutes */
+
intsec[100]/* The start offset of each track in seconds */
+
intframe[100]/* The start offset of each track in frames */
+
+

See Also

+FSOUND_Stream_FindTagField +, +FSOUND_Stream_Open +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Update.html b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Update.html index aede0145..17bfba4c 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Update.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/FSOUND_Update.html @@ -1,60 +1,60 @@ - - - - -FSOUND_Update - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

FSOUND_Update

-This updates the 3d sound engine and DMA engine (only on some platforms), and should be called once a game frame.
-This function will also update the software mixer if you have selected FSOUND_OUTPUT_NOSOUND_NONREALTIME as your output mode.
-

-void F_API FSOUND_Update(
-);
-

Return Value

-void
-

Remarks

-___________________
-Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
-

See Also

-FSOUND_3D_Listener_SetAttributes -, -FSOUND_3D_Listener_SetCurrent -, -FSOUND_3D_SetAttributes -, -FSOUND_3D_SetDopplerFactor -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +FSOUND_Update + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

FSOUND_Update

+This updates the 3d sound engine and DMA engine (only on some platforms), and should be called once a game frame.
+This function will also update the software mixer if you have selected FSOUND_OUTPUT_NOSOUND_NONREALTIME as your output mode.
+

+void F_API FSOUND_Update(
+);
+

Return Value

+void
+

Remarks

+___________________
+Supported on the following platforms : Win32, WinCE, Linux, Macintosh, XBox, PlayStation 2, GameCube
+

See Also

+FSOUND_3D_Listener_SetAttributes +, +FSOUND_3D_Listener_SetCurrent +, +FSOUND_3D_SetAttributes +, +FSOUND_3D_SetDopplerFactor +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/INDEX.HTML b/main/source/includes/fmodapi375linux/documentation/HTML/INDEX.HTML index f1715d6d..84a87950 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/INDEX.HTML +++ b/main/source/includes/fmodapi375linux/documentation/HTML/INDEX.HTML @@ -1,11 +1,11 @@ - - - - -FMOD - - - - - - + + + + +FMOD + + + + + + diff --git a/main/source/includes/fmodapi375linux/documentation/HTML/sceSifAddCmdHandler.html b/main/source/includes/fmodapi375linux/documentation/HTML/sceSifAddCmdHandler.html index 3829894d..90b84e5d 100644 --- a/main/source/includes/fmodapi375linux/documentation/HTML/sceSifAddCmdHandler.html +++ b/main/source/includes/fmodapi375linux/documentation/HTML/sceSifAddCmdHandler.html @@ -1,88 +1,88 @@ - - - - -sceSifAddCmdHandler - - - - - - - - - - - -
- - - - -Previous Topic - - -Index - - -Next Topic - -
-
-
-
[API function]
-

sceSifAddCmdHandler

-For advanced users only.
-Only used if users are getting conflicts with FMOD's command handler when writing IOP modules of their own or using other middleware that uses SIFCMD.
-This function tells FMOD about the user's SIFCMD buffer that has been set with sceSifSetCmdBuffer, and the indicies into that sceSifCmdData array that FMOD can use.
-The user may have specified a SIF command handler of their own before calling FSOUND_Init and loading FMOD.IRX when setting up their own IOP<->EE communication.
-It simply enables FMOD to know the size, and what indicies into the sceSifCmdData array the user has set that FMOD can use.
-It allows the user's app and FMOD to share the buffer that the user has created.
-FMOD uses 2 sif handlers. A main one and secondary one.
-

- sceSifAddCmdHandler(
-YOURHANDLERINDEX ,
-yourhandler ,
-NULL
-);
-

Parameters

- - - - -
buffersizeThe size of the sceSifCmdData array that the user has set.
-
bufferindexmainThe index into the user created sceSifCmdData array for the primary FMOD sifcmd handler.
-
bufferindexsecondaryThe index into the user created sceSifCmdData array for the secondary FMOD sifcmd handler.
-
-

Return Value

-void
-

Remarks

-FMOD will automatically use the previously set command buffer, as sceSifSetCmdBuffer returns the previously set buffer which FMOD uses.
-This is why you dont have to pass in the actual buffer itself.
------------
-IMPORTANT! FMOD.IRX must also be notified when it is initialized!
-The IOP side of the command handler, which is initialized when FMOD.IRX is loaded, must also be notified of the user's IOP side buffer size and indicies.
-By passing it as command line parameter with sceSifLoadModule, you can do this. If this is not done, unexpected results may occur.
-The FMOD.IRX takes 3 parameters. They are simply 3 integers seperated by a space.
-Parameter 1 is equal to 'buffersize'
-Parameter 2 is equal to 'bufferindexmain'
-Parameter 3 is equal to 'bufferindexsecondary'
-------------
-Here is an example of using sceSifLoadModule to notify FMOD.IRX of your IOP side sifCmd buffer size and command handler index.
-sprintf(s, "4989424 1238404 205", CMDBUFSIZE, FMODINDEXMAIN, FMODINDEXSECONDARY); // NOTE : must be formatted as 3 integers seperated by a space.
-sceSifLoadModule("host0:api/fmod.irx", strlen(s), s);
-Then later on the EE side, before calling FSOUND_Init, you will call this function, ie
-FSOUND_SetSifCommandInfo(CMDBUFSIZE, FMODINDEXMAIN, FMODINDEXSECONDARY);
-And before any of this, you would have set up your own command handler with something like this.
-sceSifInitCmd();
-sceSifSetCmdBuffer(&yourcommandbuffer
-

See Also

-FSOUND_Init -

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
-Generated Thu Dec 15 17:31:37 2005 - by SourceDoc v0.10, the automated source code documenter.
- - + + + + +sceSifAddCmdHandler + + + + + + + + + + + +
+ + + + +Previous Topic + + +Index + + +Next Topic + +
+
+
+
[API function]
+

sceSifAddCmdHandler

+For advanced users only.
+Only used if users are getting conflicts with FMOD's command handler when writing IOP modules of their own or using other middleware that uses SIFCMD.
+This function tells FMOD about the user's SIFCMD buffer that has been set with sceSifSetCmdBuffer, and the indicies into that sceSifCmdData array that FMOD can use.
+The user may have specified a SIF command handler of their own before calling FSOUND_Init and loading FMOD.IRX when setting up their own IOP<->EE communication.
+It simply enables FMOD to know the size, and what indicies into the sceSifCmdData array the user has set that FMOD can use.
+It allows the user's app and FMOD to share the buffer that the user has created.
+FMOD uses 2 sif handlers. A main one and secondary one.
+

+ sceSifAddCmdHandler(
+YOURHANDLERINDEX ,
+yourhandler ,
+NULL
+);
+

Parameters

+ + + + +
buffersizeThe size of the sceSifCmdData array that the user has set.
+
bufferindexmainThe index into the user created sceSifCmdData array for the primary FMOD sifcmd handler.
+
bufferindexsecondaryThe index into the user created sceSifCmdData array for the secondary FMOD sifcmd handler.
+
+

Return Value

+void
+

Remarks

+FMOD will automatically use the previously set command buffer, as sceSifSetCmdBuffer returns the previously set buffer which FMOD uses.
+This is why you dont have to pass in the actual buffer itself.
+-----------
+IMPORTANT! FMOD.IRX must also be notified when it is initialized!
+The IOP side of the command handler, which is initialized when FMOD.IRX is loaded, must also be notified of the user's IOP side buffer size and indicies.
+By passing it as command line parameter with sceSifLoadModule, you can do this. If this is not done, unexpected results may occur.
+The FMOD.IRX takes 3 parameters. They are simply 3 integers seperated by a space.
+Parameter 1 is equal to 'buffersize'
+Parameter 2 is equal to 'bufferindexmain'
+Parameter 3 is equal to 'bufferindexsecondary'
+------------
+Here is an example of using sceSifLoadModule to notify FMOD.IRX of your IOP side sifCmd buffer size and command handler index.
+sprintf(s, "4989424 1238404 205", CMDBUFSIZE, FMODINDEXMAIN, FMODINDEXSECONDARY); // NOTE : must be formatted as 3 integers seperated by a space.
+sceSifLoadModule("host0:api/fmod.irx", strlen(s), s);
+Then later on the EE side, before calling FSOUND_Init, you will call this function, ie
+FSOUND_SetSifCommandInfo(CMDBUFSIZE, FMODINDEXMAIN, FMODINDEXSECONDARY);
+And before any of this, you would have set up your own command handler with something like this.
+sceSifInitCmd();
+sceSifSetCmdBuffer(&yourcommandbuffer
+

See Also

+FSOUND_Init +

This document copyright ©Firelight Technologies, Pty, Ltd, 1999-2002. All rights reserved.
+Generated Thu Dec 15 17:31:37 2005 + by SourceDoc v0.10, the automated source code documenter.
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/3dsound.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/3dsound.htm index e5e2c93a..87444296 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/3dsound.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/3dsound.htm @@ -1,172 +1,172 @@ - - - - - -3D Sound Tutorial - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

3D SOUND AND GAME CODING

-
- - - - - - - - -
Introduction         
-
    - 3D Sound in FMOD is accomplished through a various different API's which are handled transparently to you through one unified interface. These are DirectSound 3D with EAX 2.0 and EAD 3.0/HD support, or FMOD fallback software 3D stereo engine. -

    - It is recommended when you see an API function highlighted as a link, that you check the API reference for more detail. -
- - - - - -
Hardware Support         
-
    - Allocating samples with FSOUND_HW3D is the key to getting your sounds to use 3D hardware acceleration.
    - You do this when loading wav, raw, mp3, etc samples, through the following function.

    -
  • FSOUND_Sample_Load(int index, const char *name_or_data, unsigned int inputmode, int offset, int length); - Bitwise OR in the FSOUND_HW3D flag into the mode parameter of the loading function.

    - If you have the correct hardware, the sound will be loaded into hardware mode.
    - If not, the sample will be loaded in software mode, transparently to the programmer, but it will not be accelerated or take advantage of advanced 3d algorithms and EAX.

    - Here is an example of a wav file attempting to be loaded as a 3D Hardware buffer.
    - FSOUND_Sample_Load(FSOUND_FREE, "engine.wav", FSOUND_HW3D | FSOUND_LOOP_NORMAL, 0, 0);

    - Or you can force it into software by not specifying the FSOUND_HW3D flag
    - FSOUND_Sample_Load(FSOUND_FREE, "engine.wav", FSOUND_LOOP_NORMAL, 0, 0);

    - Or you can have it as a 2D sound (2d sounds are not affected by 3d functions, and are rendered in software), using the FSOUND_2D flag.
    - FSOUND_Sample_Load(FSOUND_FREE, "engine.wav", FSOUND_2D | FSOUND_LOOP_NORMAL, 0, 0);

    -
- - - - - -
Typical game loop         
-
    - This would be a typical example of a game audio loop.

    - - do
    - {
      - UpdateGame(); // here the game is updated and the sources would be moved with FSOUND_SetAttributes
      -
      - FSOUND_3D_Listener_SetAttributes(listenerpos, listenervel, fx, fy, fz, tx, ty, tz); // update 'ears'
      - FSOUND_Update(); // needed to update 3d engine, once per frame
      -
    - } while (gamerunning);
    -
    -
    - Most games usually take the position,velocity and orientation from the camera's vectors and matrix. -
- - - - - -
Velocity parameter         
-
    - Velocity is only required if you want doppler effects. Otherwise you can pass NULL to both FSOUND_3D_Listener_SetAttributes and FSOUND_3D_SetAttributes for the velocity parameter, and no doppler effect will be heard

    - This is stressed over and over again, but can't be stressed enough. It is important that the velocity passed to FMOD is METERS PER SECOND and NOT meters per FRAME.

    - What does this mean? Use proper velocity vectors from physics code etc, and don't just subtract last frames position from the current position, as this is affected by framerate. (ie the higher the framerate the smaller the position deltas, and therefore smaller doppler effects, which is incorrect)

    - If the only way you can get the velocity is to subtract this and last frame's position vectors, then remember to time adjust them from meters per frame back up to meters per second.
    - This is done simply by scaling the difference vector obtained by subtracting the 2 position vectors, by one over the frame time delta.

    - Here is an example
    - - velx = (posx-lastposx) * 1000 / timedelta;
    - velz = (posy-lastposy) * 1000 / timedelta;
    - velz = (posz-lastposz) * 1000 / timedelta;
    -
    - timedelta is the time since the last frame in milliseconds. This can be obtained with functions such as timeGetTime().
    - So at 60fps, the timedelta would be 16.67ms. if the source moved 0.1 meters in this time, the actual velocity in meters per second would be
    - vel = 0.1 * 1000 / 16.67 = 6 meters per second.
    - Similarly, if we only have half the framerate of 30fps, then subtracting position deltas will gives us twice the distance that it would at 60fps (so it would have moved 0.2 meters this time)
    - vel = 0.2 * 1000 / 33.33 = 6 meters per second still! phew!.
    -
- - - - - -
Orientation and coordinate systems         
-
    - Getting the correct orientation set up is essential if you want the source to move around you in 3d space.
    - FMOD Uses a left handed coordinate system, (x = right, y = up, z = forwards), which is the same as DirectSound3D and A3D

    - If you use a different coordinate system, then you will need to flip certain axis or even swap them around inside the call to FSOUND_3D_Listener_SetAttributes.
    - Take the right handed coordinate system, where Z points backwards, or comes out of the screen at you. To convert this to FMOD coordinate system simply negate the Z coordinate of the listener up and forward vector.

    - Just think RIGHT, UP, FORWARDS for each element of a vector (ie x,y,z), and map whatever axis fit your model into this, to generate the 2 vectors that points forwards and up. -
- - - - - -
Channel resource management and low end cards         
-
    - Some soundcards only support 4 or 8 3D hardware channels, whereas other soundcards support 32 and 96 hardware 3D channels.
    - What do you do in your game? only play 4 3D hardware based sounds at once to meet the base spec? Not likely. It would be ridiculous to limit yourself to these 4 channels when you have the potential of other high end cards that can do nearly 100 hardware channels at once.

    - The solution is to use FSOUND_SetMinHardwareChannels. This function is called once before calling FSOUND_Init.
    - What this allows you to do is assume a number of channels will either ALL be played in hardware, or NONE in hardware (therefore in software).
    - It basically says 'if the card doesn't have n number of channels, then mix all sounds in software'. This allows you to assume that you have say 16 sounds to be playing at once, and if the hardware has at least that many channels available, it will play them all in hardware. - If you come across a card that only supports 4 hardware channels at once, then it fails the criteria and your sounds are played all in software.
    -
    - The best thing about this is NO PlaySound's fail because of running out of channels on unexpected cards! You can guarantee a certain number of channels available, and if the hardware is there, then all the better! -
- - - - - -
Use priorities!         
-
    - FMOD's priority system is there to be used. If you trigger lots of sounds on a limited number of channels, some might be more important than others.
    - If you were doing a first person shooter, the player's gunshot sound would be one of the most important sounds. So it should have a high priority set with FSOUND_SetPriority. - Other less important sounds would be rejected if the number of allocated channels became full, and that gunshot needed to be heard! -
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +3D Sound Tutorial - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

3D SOUND AND GAME CODING

+
+ + + + + + + + +
Introduction         
+
    + 3D Sound in FMOD is accomplished through a various different API's which are handled transparently to you through one unified interface. These are DirectSound 3D with EAX 2.0 and EAD 3.0/HD support, or FMOD fallback software 3D stereo engine. +

    + It is recommended when you see an API function highlighted as a link, that you check the API reference for more detail. +
+ + + + + +
Hardware Support         
+
    + Allocating samples with FSOUND_HW3D is the key to getting your sounds to use 3D hardware acceleration.
    + You do this when loading wav, raw, mp3, etc samples, through the following function.

    +
  • FSOUND_Sample_Load(int index, const char *name_or_data, unsigned int inputmode, int offset, int length); + Bitwise OR in the FSOUND_HW3D flag into the mode parameter of the loading function.

    + If you have the correct hardware, the sound will be loaded into hardware mode.
    + If not, the sample will be loaded in software mode, transparently to the programmer, but it will not be accelerated or take advantage of advanced 3d algorithms and EAX.

    + Here is an example of a wav file attempting to be loaded as a 3D Hardware buffer.
    + FSOUND_Sample_Load(FSOUND_FREE, "engine.wav", FSOUND_HW3D | FSOUND_LOOP_NORMAL, 0, 0);

    + Or you can force it into software by not specifying the FSOUND_HW3D flag
    + FSOUND_Sample_Load(FSOUND_FREE, "engine.wav", FSOUND_LOOP_NORMAL, 0, 0);

    + Or you can have it as a 2D sound (2d sounds are not affected by 3d functions, and are rendered in software), using the FSOUND_2D flag.
    + FSOUND_Sample_Load(FSOUND_FREE, "engine.wav", FSOUND_2D | FSOUND_LOOP_NORMAL, 0, 0);

    +
+ + + + + +
Typical game loop         
+
    + This would be a typical example of a game audio loop.

    + + do
    + {
      + UpdateGame(); // here the game is updated and the sources would be moved with FSOUND_SetAttributes
      +
      + FSOUND_3D_Listener_SetAttributes(listenerpos, listenervel, fx, fy, fz, tx, ty, tz); // update 'ears'
      + FSOUND_Update(); // needed to update 3d engine, once per frame
      +
    + } while (gamerunning);
    +
    +
    + Most games usually take the position,velocity and orientation from the camera's vectors and matrix. +
+ + + + + +
Velocity parameter         
+
    + Velocity is only required if you want doppler effects. Otherwise you can pass NULL to both FSOUND_3D_Listener_SetAttributes and FSOUND_3D_SetAttributes for the velocity parameter, and no doppler effect will be heard

    + This is stressed over and over again, but can't be stressed enough. It is important that the velocity passed to FMOD is METERS PER SECOND and NOT meters per FRAME.

    + What does this mean? Use proper velocity vectors from physics code etc, and don't just subtract last frames position from the current position, as this is affected by framerate. (ie the higher the framerate the smaller the position deltas, and therefore smaller doppler effects, which is incorrect)

    + If the only way you can get the velocity is to subtract this and last frame's position vectors, then remember to time adjust them from meters per frame back up to meters per second.
    + This is done simply by scaling the difference vector obtained by subtracting the 2 position vectors, by one over the frame time delta.

    + Here is an example
    + + velx = (posx-lastposx) * 1000 / timedelta;
    + velz = (posy-lastposy) * 1000 / timedelta;
    + velz = (posz-lastposz) * 1000 / timedelta;
    +
    + timedelta is the time since the last frame in milliseconds. This can be obtained with functions such as timeGetTime().
    + So at 60fps, the timedelta would be 16.67ms. if the source moved 0.1 meters in this time, the actual velocity in meters per second would be
    + vel = 0.1 * 1000 / 16.67 = 6 meters per second.
    + Similarly, if we only have half the framerate of 30fps, then subtracting position deltas will gives us twice the distance that it would at 60fps (so it would have moved 0.2 meters this time)
    + vel = 0.2 * 1000 / 33.33 = 6 meters per second still! phew!.
    +
+ + + + + +
Orientation and coordinate systems         
+
    + Getting the correct orientation set up is essential if you want the source to move around you in 3d space.
    + FMOD Uses a left handed coordinate system, (x = right, y = up, z = forwards), which is the same as DirectSound3D and A3D

    + If you use a different coordinate system, then you will need to flip certain axis or even swap them around inside the call to FSOUND_3D_Listener_SetAttributes.
    + Take the right handed coordinate system, where Z points backwards, or comes out of the screen at you. To convert this to FMOD coordinate system simply negate the Z coordinate of the listener up and forward vector.

    + Just think RIGHT, UP, FORWARDS for each element of a vector (ie x,y,z), and map whatever axis fit your model into this, to generate the 2 vectors that points forwards and up. +
+ + + + + +
Channel resource management and low end cards         
+
    + Some soundcards only support 4 or 8 3D hardware channels, whereas other soundcards support 32 and 96 hardware 3D channels.
    + What do you do in your game? only play 4 3D hardware based sounds at once to meet the base spec? Not likely. It would be ridiculous to limit yourself to these 4 channels when you have the potential of other high end cards that can do nearly 100 hardware channels at once.

    + The solution is to use FSOUND_SetMinHardwareChannels. This function is called once before calling FSOUND_Init.
    + What this allows you to do is assume a number of channels will either ALL be played in hardware, or NONE in hardware (therefore in software).
    + It basically says 'if the card doesn't have n number of channels, then mix all sounds in software'. This allows you to assume that you have say 16 sounds to be playing at once, and if the hardware has at least that many channels available, it will play them all in hardware. + If you come across a card that only supports 4 hardware channels at once, then it fails the criteria and your sounds are played all in software.
    +
    + The best thing about this is NO PlaySound's fail because of running out of channels on unexpected cards! You can guarantee a certain number of channels available, and if the hardware is there, then all the better! +
+ + + + + +
Use priorities!         
+
    + FMOD's priority system is there to be used. If you trigger lots of sounds on a limited number of channels, some might be more important than others.
    + If you were doing a first person shooter, the player's gunshot sound would be one of the most important sounds. So it should have a high priority set with FSOUND_SetPriority. + Other less important sounds would be rejected if the number of allocated channels became full, and that gunshot needed to be heard! +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/basics.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/basics.htm index 5e180ba3..553c56b8 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/basics.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/basics.htm @@ -1,199 +1,199 @@ - - - -THE BASICS - - - - -
-

- -
-
-
-

-

THE BASICS

-
- - - - -
- Introduction          -
-
    -

    This is the first place to look if you have no idea what to do when - downloading FMOD, or those with some idea but need a little bit of help. It - will give you a step by step introduction and tutorial on what to call, what - to link and where to call stuff so you can easily get on your way to great - sounding audio!

    -
- - - - -
The - package         
-
    - The first thing you will do is unzip fmod and find the following directory - structure.
    -
    -
    -
    - - - /api

    - - The files you are interested in for your own projects are held here
    - This holds
    -
    -
  • FMOD.DLL,
  • -
  • The import library (fmodvc.lib, fmodbc.lib etc) you need to link (for C users), and
  • -
  • The header (fmod.h, fmod.pas, fmod.bas depending on language) you need to include.
  • -
    -
    - C Users
    -
  • MSVC - #include "fmod.h" into your source code and link fmodvc.lib by putting it into your link section/makefile/project.
    -
  • Codewarrior - #include "fmod.h" into your source code and link fmodvc.lib by putting it into your link section/makefile/project.
    -
  • Watcom - #include "fmod.h" into your source code and link fmodwc.lib by putting it into your link section/makefile/project.
    -
  • Borland - #include "fmod.h" into your source code and link fmodbc.lib by putting it into your link section/makefile/project.
    -
  • LCC-WIN32 - #include "fmod.h" into your source code and link fmodlcc.lib by putting it into your link section/makefile/project.
    -
  • Mingw and CygWin - #include "fmod.h" into your source code and link libfmod.a by putting it into your link section/makefile/project.
    -
  • Linux / GCC - #include "fmod.h" into your source code and link with libfmod-X-Y.so (i.e gcc file.c -lfmod-3.5)
    -
    - Note there is no DJGPP support. If you ask for this you are looking in the wrong place. DJGPP is DOS only and to find a similar free WIN32 compiler try LCC-WIN32 or CygWin.
    -
    - Delphi Users
    -
  • You need to have uses FMOD in your source code somewhere. If delphi cannot find the FMOD header you need to have the path to fmod.pas in your library path. Go to Tools\Environment Options\Library. Add the path, eg. C:\fmodapi340\api\delphi (of course, use the path that you have on your system), to Library Path and it should be happy. -
    -
    - Visual Basic Users
    -
  • Add fmod.bas to your project.
    - - -
    -
    - - /documentation

    - - You must know about this already if you are reading this!
    -
    - -
    -
    - - /media

    - - This directory holds some wav files and songs that the examples use. For example jbtennis.wav which contains loop points and wav sync markers that fmod can read
    -
    - -
    -
    - - /samples

    - - This folder is for C programmers and contains a variety of samples to demonstrate 3D sound, dsp effects, recording, streams and more
    - To run the precompiled executables, first copy the FMOD.DLL file from /api into the relevant sample directory to make it accessable for the program.
    -
    -
    - -
    - - /samplesdelphi

    - - This folder is for Delphi programmers and contains a variety of samples to demonstrate using FMOD with Delphi. Written by Steve Williams
    - To run the precompiled executables, first copy the FMOD.DLL file from /api into the relevant sample directory to make it accessable for the program.
    -
    - -
    -
    - - /samplesvb

    - - This folder is for Visual Basic programmers and contains examples of using FMOD with Visual Basic.
    - To run the precompiled executables, first copy the FMOD.DLL file from /api into the relevant sample directory to make it accessable for the program.
    -
    - -
    -
    - - /tools

    - - This folder contains asioconfig.exe.
    - This program simply configures any asio devices you have on your system by bringing up the driver's native configuration screen.
    - If you run it and no entries are in the list, your asio drivers are not installed properly.
    - If you select or doubleclick an entry that does exist and no config screen appears then your asio drivers are not installed correctly or you have selected the wrong driver to configure. Take note of this when selecting the device from the FMOD api.
    -
    - -
- - - - - -
Getting started         
-
    -
  • The first thing you need to do is make sure FMOD.DLL is accessable from your program. Otherwise you will get an error something like the one below when you try and run your executable. -
    -
    - -
    -
    - Copy the FMOD.DLL file out of the /api directory and into the directory where your executable will be. If they are in the same directory then it will work as expected.
    - Now you are ready to start coding, you need to initialize FMOD first! You do this once at the start of your program.

    -
  • Do this with FSOUND_Init.
  • - The simplest way to do this is to tell FMOD to mix at 44100hz, and use 32 software channels. This is done like so.
    -
    - FSOUND_Init(44100, 32, 0);
    -
    - To get more detailed control please see the fmod.h file to see what pre-FSOUND_Init functions can be called to control things like mixer type, output device etc. Also FSOUND_Init itself has flags which you can find out more about in the relevant documentation.
    - Note that you don't have to actually use the pre-init functions as FMOD automatically detects the best settings for you.
    - If this function succeeds, (see error code if it doesnt), then FMOD is now running and some more interesting things can be done.
    - -
- - - - - - -
Samples, Streams and Songs         
-
    - You have a music file or a sound you want to play. What FMOD API should you use to load and play it?
    - Here's a guide.

    - -
  • If it is a sequenced music file such as .MOD, .S3M, .XM, .IT or .MID, then use the FMUSIC API. You will want to use FMUSIC_LoadSong to load it into memory. When this gives you a valid return handle, use that handle with FMUSIC_PlaySong to play it! The handle type for this type of file when loaded is FMUSIC_MODULE. -
  • If it is a PCM based or compressed file such as .WAV, .MP2, .MP3, .OGG or .RAW then you have a choice to make. Will it use too much memory if you load it in and decompress it into memory? or is it small enough to fit?
    - - For small sounds such as sound effects that you want to trigger multiple times at once (for example a gunshot), then you will want to use FSOUND_Sample_Load. When it gives you a valid return handle, use that handle with FSOUND_PlaySound or FSOUND_PlaySoundEx. This is the fastest way to replay sounds, as they are decompressed into memory (at load time) first before being played. The handle type for this type of file when loaded is FSOUND_SAMPLE.
    - - If the file is going to be big, and doesnt need to be played multiple times at once (note the next option cannot be played multiple times at once), then the other choice is to use FSOUND_Stream_Open. This opens a file, and prepares it for playing. When it gives you a valid return handle, use that handle with FSOUND_Stream_Play or FSOUND_Stream_PlayEx. This streams the file from the disk in realtime and decompresses the file on the fly. This option uses less memory than samples when the file is past a certain size. Note that this option uses a lot more cpu time than a sample as it has to access the disk, and if nescessary, decompress the data on the fly. FMOD decompression routines are usually fairly efficient but it can be significant on slow machines (especially CE devices), or if multiple streams are played together at once. You can of course measure this with FSOUND_GetCPUUsage or just see how it affects your framerate. The handle type for this type of file when loaded is FSOUND_STREAM.
    -
  • -
    -
    - Note : Use FSOUND_FREE when choosing a channel to play a sample or stream on. It makes the best choice for you. If you must use a value such as 0-31 etc, then carefully read the channel mapping/index informatiomn in the remarks section of FSOUND_PlaySound.
    - -
- - - - - - -
Manipulation         
-
    - Finally the last most basic things you might want to do are change the song's volume or speed or any other variety of attributes
    -
    -
  • For FMUSIC_MODULE handles you can use the FMUSIC API for commands like FMUSIC_SetPaused and FMUSIC_SetMasterVolume. See fmod.h (or equivalent) or the documentation for a list of these commands you can use.
    -
  • For FSOUND_SAMPLE handles you can use a variety of commands on a playing sound from the channel handle returned from FSOUND_PlaySound or FSOUND_PlaySoundEx. These include such commands as FSOUND_SetVolume or FSOUND_SetFrequency or a whole host of commands.
    -
  • For FSOUND_STREAM handles you can use a variety of commands on a playing stream, also from the channel handle returned from FSOUND_Stream_Play or FSOUND_Stream_PlayEx. Because these also use channels to play on, they can use the channel functions just as a sample would. You can pause a stream with FSOUND_SetPaused for example. - -
- - -
-
-
- - - + + + +THE BASICS + + + + +
+

+ +
+
+
+

+

THE BASICS

+
+ + + + +
+ Introduction          +
+
    +

    This is the first place to look if you have no idea what to do when + downloading FMOD, or those with some idea but need a little bit of help. It + will give you a step by step introduction and tutorial on what to call, what + to link and where to call stuff so you can easily get on your way to great + sounding audio!

    +
+ + + + +
The + package         
+
    + The first thing you will do is unzip fmod and find the following directory + structure.
    +
    +
    +
    + + + /api

    + + The files you are interested in for your own projects are held here
    + This holds
    +
    +
  • FMOD.DLL,
  • +
  • The import library (fmodvc.lib, fmodbc.lib etc) you need to link (for C users), and
  • +
  • The header (fmod.h, fmod.pas, fmod.bas depending on language) you need to include.
  • +
    +
    + C Users
    +
  • MSVC - #include "fmod.h" into your source code and link fmodvc.lib by putting it into your link section/makefile/project.
    +
  • Codewarrior - #include "fmod.h" into your source code and link fmodvc.lib by putting it into your link section/makefile/project.
    +
  • Watcom - #include "fmod.h" into your source code and link fmodwc.lib by putting it into your link section/makefile/project.
    +
  • Borland - #include "fmod.h" into your source code and link fmodbc.lib by putting it into your link section/makefile/project.
    +
  • LCC-WIN32 - #include "fmod.h" into your source code and link fmodlcc.lib by putting it into your link section/makefile/project.
    +
  • Mingw and CygWin - #include "fmod.h" into your source code and link libfmod.a by putting it into your link section/makefile/project.
    +
  • Linux / GCC - #include "fmod.h" into your source code and link with libfmod-X-Y.so (i.e gcc file.c -lfmod-3.5)
    +
    + Note there is no DJGPP support. If you ask for this you are looking in the wrong place. DJGPP is DOS only and to find a similar free WIN32 compiler try LCC-WIN32 or CygWin.
    +
    + Delphi Users
    +
  • You need to have uses FMOD in your source code somewhere. If delphi cannot find the FMOD header you need to have the path to fmod.pas in your library path. Go to Tools\Environment Options\Library. Add the path, eg. C:\fmodapi340\api\delphi (of course, use the path that you have on your system), to Library Path and it should be happy. +
    +
    + Visual Basic Users
    +
  • Add fmod.bas to your project.
    + + +
    +
    + + /documentation

    + + You must know about this already if you are reading this!
    +
    + +
    +
    + + /media

    + + This directory holds some wav files and songs that the examples use. For example jbtennis.wav which contains loop points and wav sync markers that fmod can read
    +
    + +
    +
    + + /samples

    + + This folder is for C programmers and contains a variety of samples to demonstrate 3D sound, dsp effects, recording, streams and more
    + To run the precompiled executables, first copy the FMOD.DLL file from /api into the relevant sample directory to make it accessable for the program.
    +
    +
    + +
    + + /samplesdelphi

    + + This folder is for Delphi programmers and contains a variety of samples to demonstrate using FMOD with Delphi. Written by Steve Williams
    + To run the precompiled executables, first copy the FMOD.DLL file from /api into the relevant sample directory to make it accessable for the program.
    +
    + +
    +
    + + /samplesvb

    + + This folder is for Visual Basic programmers and contains examples of using FMOD with Visual Basic.
    + To run the precompiled executables, first copy the FMOD.DLL file from /api into the relevant sample directory to make it accessable for the program.
    +
    + +
    +
    + + /tools

    + + This folder contains asioconfig.exe.
    + This program simply configures any asio devices you have on your system by bringing up the driver's native configuration screen.
    + If you run it and no entries are in the list, your asio drivers are not installed properly.
    + If you select or doubleclick an entry that does exist and no config screen appears then your asio drivers are not installed correctly or you have selected the wrong driver to configure. Take note of this when selecting the device from the FMOD api.
    +
    + +
+ + + + + +
Getting started         
+
    +
  • The first thing you need to do is make sure FMOD.DLL is accessable from your program. Otherwise you will get an error something like the one below when you try and run your executable. +
    +
    + +
    +
    + Copy the FMOD.DLL file out of the /api directory and into the directory where your executable will be. If they are in the same directory then it will work as expected.
    + Now you are ready to start coding, you need to initialize FMOD first! You do this once at the start of your program.

    +
  • Do this with FSOUND_Init.
  • + The simplest way to do this is to tell FMOD to mix at 44100hz, and use 32 software channels. This is done like so.
    +
    + FSOUND_Init(44100, 32, 0);
    +
    + To get more detailed control please see the fmod.h file to see what pre-FSOUND_Init functions can be called to control things like mixer type, output device etc. Also FSOUND_Init itself has flags which you can find out more about in the relevant documentation.
    + Note that you don't have to actually use the pre-init functions as FMOD automatically detects the best settings for you.
    + If this function succeeds, (see error code if it doesnt), then FMOD is now running and some more interesting things can be done.
    + +
+ + + + + + +
Samples, Streams and Songs         
+
    + You have a music file or a sound you want to play. What FMOD API should you use to load and play it?
    + Here's a guide.

    + +
  • If it is a sequenced music file such as .MOD, .S3M, .XM, .IT or .MID, then use the FMUSIC API. You will want to use FMUSIC_LoadSong to load it into memory. When this gives you a valid return handle, use that handle with FMUSIC_PlaySong to play it! The handle type for this type of file when loaded is FMUSIC_MODULE. +
  • If it is a PCM based or compressed file such as .WAV, .MP2, .MP3, .OGG or .RAW then you have a choice to make. Will it use too much memory if you load it in and decompress it into memory? or is it small enough to fit?
    + - For small sounds such as sound effects that you want to trigger multiple times at once (for example a gunshot), then you will want to use FSOUND_Sample_Load. When it gives you a valid return handle, use that handle with FSOUND_PlaySound or FSOUND_PlaySoundEx. This is the fastest way to replay sounds, as they are decompressed into memory (at load time) first before being played. The handle type for this type of file when loaded is FSOUND_SAMPLE.
    + - If the file is going to be big, and doesnt need to be played multiple times at once (note the next option cannot be played multiple times at once), then the other choice is to use FSOUND_Stream_Open. This opens a file, and prepares it for playing. When it gives you a valid return handle, use that handle with FSOUND_Stream_Play or FSOUND_Stream_PlayEx. This streams the file from the disk in realtime and decompresses the file on the fly. This option uses less memory than samples when the file is past a certain size. Note that this option uses a lot more cpu time than a sample as it has to access the disk, and if nescessary, decompress the data on the fly. FMOD decompression routines are usually fairly efficient but it can be significant on slow machines (especially CE devices), or if multiple streams are played together at once. You can of course measure this with FSOUND_GetCPUUsage or just see how it affects your framerate. The handle type for this type of file when loaded is FSOUND_STREAM.
    +
  • +
    +
    + Note : Use FSOUND_FREE when choosing a channel to play a sample or stream on. It makes the best choice for you. If you must use a value such as 0-31 etc, then carefully read the channel mapping/index informatiomn in the remarks section of FSOUND_PlaySound.
    + +
+ + + + + + +
Manipulation         
+
    + Finally the last most basic things you might want to do are change the song's volume or speed or any other variety of attributes
    +
    +
  • For FMUSIC_MODULE handles you can use the FMUSIC API for commands like FMUSIC_SetPaused and FMUSIC_SetMasterVolume. See fmod.h (or equivalent) or the documentation for a list of these commands you can use.
    +
  • For FSOUND_SAMPLE handles you can use a variety of commands on a playing sound from the channel handle returned from FSOUND_PlaySound or FSOUND_PlaySoundEx. These include such commands as FSOUND_SetVolume or FSOUND_SetFrequency or a whole host of commands.
    +
  • For FSOUND_STREAM handles you can use a variety of commands on a playing stream, also from the channel handle returned from FSOUND_Stream_Play or FSOUND_Stream_PlayEx. Because these also use channels to play on, they can use the channel functions just as a sample would. You can pause a stream with FSOUND_SetPaused for example. + +
+ + +
+
+
+ + + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/custom.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/custom.htm index ea2c9ec7..51816715 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/custom.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/custom.htm @@ -1,101 +1,101 @@ - - - - - -Custom Samples and Streams Tutorial - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

CUSTOM SAMPLES AND STREAMS

-
- - - - - - - - -
Introduction         
-
    - This answers some of the questions regarding how to create a custom/user stream, and a custom/user sample. -
- - - - - -
Custom Samples         
-
    - 1. Declare and allocate a custom sample...
    -
      - FSOUND_SAMPLE *mysamp = FSOUND_Sample_Alloc(FSOUND_FREE, length, mode, deffreq, defvol, defpan, defpri);
      -
      - Remember 'length' is measured in *samples* not bytes, and mode is a bitfield using
      - FSOUND_MODES (see the help for a description of modes to describe the sample you are allocating)
      - This will create you an empty sample to upload data into.
      -
    - 2. Upload your data to the sample.
    -
      - Use FSOUND_Sample_Lock()/FSOUND_Sample_Unlock() or FSOUND_Sample_Upload() to get your data into the sample.
      - With FSOUND_Sample_Lock()/FSOUND_Sample_Unlock(), the data you copy in MUST be in signed format.
      - FSOUND_Sample_Upload() is the favoured choice though, as you can describe the format, and it will convert it for you, but you have to pre-read the data into your own buffer first before passing it to FSOUND_Sample_Upload(), which temporarily uses more memory. This converts from all types of sources.. unsigned, delta samples, even IT compressed. more types will come in the future.
      -
    - - 3. Play it! :) - -
- - - - - -
Custom Streams         
-
    - See FSOUND_Stream_Create. You can pass a callback function pointer and a length to this function. - When you start the stream with FSOUND_Stream_Play (as you would with any other stream), you start getting callbacks. -
- - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +Custom Samples and Streams Tutorial - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

CUSTOM SAMPLES AND STREAMS

+
+ + + + + + + + +
Introduction         
+
    + This answers some of the questions regarding how to create a custom/user stream, and a custom/user sample. +
+ + + + + +
Custom Samples         
+
    + 1. Declare and allocate a custom sample...
    +
      + FSOUND_SAMPLE *mysamp = FSOUND_Sample_Alloc(FSOUND_FREE, length, mode, deffreq, defvol, defpan, defpri);
      +
      + Remember 'length' is measured in *samples* not bytes, and mode is a bitfield using
      + FSOUND_MODES (see the help for a description of modes to describe the sample you are allocating)
      + This will create you an empty sample to upload data into.
      +
    + 2. Upload your data to the sample.
    +
      + Use FSOUND_Sample_Lock()/FSOUND_Sample_Unlock() or FSOUND_Sample_Upload() to get your data into the sample.
      + With FSOUND_Sample_Lock()/FSOUND_Sample_Unlock(), the data you copy in MUST be in signed format.
      + FSOUND_Sample_Upload() is the favoured choice though, as you can describe the format, and it will convert it for you, but you have to pre-read the data into your own buffer first before passing it to FSOUND_Sample_Upload(), which temporarily uses more memory. This converts from all types of sources.. unsigned, delta samples, even IT compressed. more types will come in the future.
      +
    + + 3. Play it! :) + +
+ + + + + +
Custom Streams         
+
    + See FSOUND_Stream_Create. You can pass a callback function pointer and a length to this function. + When you start the stream with FSOUND_Stream_Play (as you would with any other stream), you start getting callbacks. +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/dsp.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/dsp.htm index 2edeab15..e8359fd9 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/dsp.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/dsp.htm @@ -1,117 +1,117 @@ - - - - - -DSP Engine - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

DSP ENGINE

-
- - - - - - - - -
Introduction         
-
    - This will briefly cover some of the essentials to using the FMOD DSP engine.
    - The DSP engine allows you to read - and process the mixed sound data as it travels to the soundcard in its various phases. This will be described in more detail below.
    - Why would you want to do this? It allows you to filter the data if you like. You could add your own reverb, distortion, EQ to the global FMOD sound stream or anything that you can think of that involves sound data.
    - Another reason is to read it and maybe do analysis or even just plot it as an oscilloscope for effect! -
- - - - - -
What is it?         
-
    - The DSP system drives FMOD's software engine.
    - Roughly every 25 milliseconds (platform dependant), FMOD mixes a batch of data to be send to the sound device.
    - To do this it executes a chain of algorithms to produce the sound. This chain is executed every time and performs the various jobs such as mixing, clipping and calling user callbacks to process the sound data.
    - At the low level, it is simply a linked list of callbacks. Each time one of these callbacks is called it is passed in the mixer buffer. You can see the callback of a DSP unit described here as FSOUND_DSPCALLBACK.
    -
    - Internally, FMOD uses these DSP callbacks to perform various stages of its own mixing routines. It is always working with the mixbuffer. This is simply a stereo buffer of integers or floats (depending on the mixer type set with FSOUND_SetOutput or determined with FSOUND_GetOutput. It is just long enough to mix 25ms worth of data, so you could probably calculate how many samples it would contain based on the sample rate, and 25ms, but there is a function supplied to work this out for you FSOUND_DSP_GetBufferLength
    -
    -
    - -
    -
- - - - - -
The "System" DSP Units         
-
    - The diagram above shows the system DSP units that are always present. -
    -
  • Clear Unit - All this DSP unit does is silence the mix buffer by setting it all to 0's. The next DSP units will generally fill in this data with audio by adding/accumulating to it (mixing). You can get a handle to this unit simply by calling FSOUND_DSP_GetClearUnit
    -
  • Mix SFX Unit - This unit calls FMOD's internal optimized mixing routines and mixes any sound effects spawned by the user with FSOUND_PlaySound or FSOUND_PlaySoundEx. You can get a handle to this unit simply by calling FSOUND_DSP_GetSFXUnit
    -
  • Mix Music Unit - This unit executes the FMUSIC music sequencing engine, and mixes the resulting channels used by the FMUSIC engine. You can get a handle to this unit simply by calling FSOUND_DSP_GetMusicUnit
    -
  • FFT Unit - This unit performs an FFT on the mixed output so that FSOUND_DSP_GetSpectrum can be used. It is turned off by default due to the CPU expense incurred, so if you want to use the FSOUND_DSP_GetSpectrum function this needs to be turned on with FSOUND_DSP_SetActive first. You can get a handle to this unit simply by calling FSOUND_DSP_GetFFTUnit
    -
  • Clip and Copy Unit - This is the final system unit in the FSOUND chain. You can get a handle to this unit simply by calling FSOUND_DSP_GetClipAndCopyUnit
    -
    - The system units can be disabled, enabled and shifted around in this list! You could even throw out the FSOUND software engine all together and replace it with your own! -
- - - - - -
Priorities         
-
    - Notice how in the diagram above each DSP unit had a 'priority'. This is simply a numeric value determining its order in the DSP chain. - The lower the priority the earlier it gets executed. Notice how the Clear Unit has a priority of 0, as it wants to be the very first unit executed.
    - This is because it wouldn't make much sense to do anything before it, as the Clear Unit will just wipe it out with zero's anyway!
    - You may disagree with this, well ok! (you may want to execute some non buffer altering logic like a timer that calls PlaySound every now and then for example), so you can simply move it with FSOUND_DSP_SetPriority.
    -
- - - - - -
Now its your turn         
-
    - You may be thinking, well this sounds like a good place if I wanted to create my own effects such as reverb or a low pass filter for example, or maybe you just want to read the data that comes in so you can graphically plot it! Well you're right this is the place to do it.
    - Just call FSOUND_DSP_Create, and give it a callback, and a priority. Set it active with FSOUND_DSP_SetActive and immediately your DSP unit will be ticking.
    - Now the data passed in will be either 16bit stereo integer (-32768 to +32767) or 32bit stereo floating point (-32768.0f to +32767.0f, not 0 to 1). This can be determined by what mixer is being used at the time, with FSOUND_GetMixer. - It's up to you now what you do with this data. One important thing to note is that FMOD mixes the data ahead of time, and the data you are processing is not the data that is immediately audible. If you are thinking of plotting the data to sync with the audible output, it is wise to buffer the data in a circular buffer, for the number of samples specified by FSOUND_DSP_GetBufferLengthTotal. This length is divisible by the DSP callback length (always a multiple of 25ms).
    - From this point then you would plot the block of data preceding the one you are filling, which is the one playing at that point in time!
    - See the FMOD example in the /samples/fmod directory for source code that does this, and many other examples of DSP processing. -
- - - - - -
FSOUND_PlaySoundEx and the 'FSOUND_DSPUNIT *dsp' parameter         
-
    - The 'dsp' parameter in this new PlaySound command, allows you to assign or 'group' a channel to a specific DSP unit. The dsp unit you assign has to be a new one and not an existing system unit, with no callback.
    - A DSP unit with sound effects attached to it does nothing but execute channel mixing, as it replaces the DSP callback with its own internal mixer callback.
    - One reason for doing this is having a wet/dry mix for an effect. This is demonstrated in the /samples/dsp directory. You may want to have some effects affected by reverb for example, but not others. This is part of the reason the Music Unit is separate from the SFX unit, as you likely don't want music affected by DSP effects but do want the in-game sound effects to be affected.
    -
- -
-
-
-
- - + + + + + +DSP Engine - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

DSP ENGINE

+
+ + + + + + + + +
Introduction         
+
    + This will briefly cover some of the essentials to using the FMOD DSP engine.
    + The DSP engine allows you to read - and process the mixed sound data as it travels to the soundcard in its various phases. This will be described in more detail below.
    + Why would you want to do this? It allows you to filter the data if you like. You could add your own reverb, distortion, EQ to the global FMOD sound stream or anything that you can think of that involves sound data.
    + Another reason is to read it and maybe do analysis or even just plot it as an oscilloscope for effect! +
+ + + + + +
What is it?         
+
    + The DSP system drives FMOD's software engine.
    + Roughly every 25 milliseconds (platform dependant), FMOD mixes a batch of data to be send to the sound device.
    + To do this it executes a chain of algorithms to produce the sound. This chain is executed every time and performs the various jobs such as mixing, clipping and calling user callbacks to process the sound data.
    + At the low level, it is simply a linked list of callbacks. Each time one of these callbacks is called it is passed in the mixer buffer. You can see the callback of a DSP unit described here as FSOUND_DSPCALLBACK.
    +
    + Internally, FMOD uses these DSP callbacks to perform various stages of its own mixing routines. It is always working with the mixbuffer. This is simply a stereo buffer of integers or floats (depending on the mixer type set with FSOUND_SetOutput or determined with FSOUND_GetOutput. It is just long enough to mix 25ms worth of data, so you could probably calculate how many samples it would contain based on the sample rate, and 25ms, but there is a function supplied to work this out for you FSOUND_DSP_GetBufferLength
    +
    +
    + +
    +
+ + + + + +
The "System" DSP Units         
+
    + The diagram above shows the system DSP units that are always present. +
    +
  • Clear Unit - All this DSP unit does is silence the mix buffer by setting it all to 0's. The next DSP units will generally fill in this data with audio by adding/accumulating to it (mixing). You can get a handle to this unit simply by calling FSOUND_DSP_GetClearUnit
    +
  • Mix SFX Unit - This unit calls FMOD's internal optimized mixing routines and mixes any sound effects spawned by the user with FSOUND_PlaySound or FSOUND_PlaySoundEx. You can get a handle to this unit simply by calling FSOUND_DSP_GetSFXUnit
    +
  • Mix Music Unit - This unit executes the FMUSIC music sequencing engine, and mixes the resulting channels used by the FMUSIC engine. You can get a handle to this unit simply by calling FSOUND_DSP_GetMusicUnit
    +
  • FFT Unit - This unit performs an FFT on the mixed output so that FSOUND_DSP_GetSpectrum can be used. It is turned off by default due to the CPU expense incurred, so if you want to use the FSOUND_DSP_GetSpectrum function this needs to be turned on with FSOUND_DSP_SetActive first. You can get a handle to this unit simply by calling FSOUND_DSP_GetFFTUnit
    +
  • Clip and Copy Unit - This is the final system unit in the FSOUND chain. You can get a handle to this unit simply by calling FSOUND_DSP_GetClipAndCopyUnit
    +
    + The system units can be disabled, enabled and shifted around in this list! You could even throw out the FSOUND software engine all together and replace it with your own! +
+ + + + + +
Priorities         
+
    + Notice how in the diagram above each DSP unit had a 'priority'. This is simply a numeric value determining its order in the DSP chain. + The lower the priority the earlier it gets executed. Notice how the Clear Unit has a priority of 0, as it wants to be the very first unit executed.
    + This is because it wouldn't make much sense to do anything before it, as the Clear Unit will just wipe it out with zero's anyway!
    + You may disagree with this, well ok! (you may want to execute some non buffer altering logic like a timer that calls PlaySound every now and then for example), so you can simply move it with FSOUND_DSP_SetPriority.
    +
+ + + + + +
Now its your turn         
+
    + You may be thinking, well this sounds like a good place if I wanted to create my own effects such as reverb or a low pass filter for example, or maybe you just want to read the data that comes in so you can graphically plot it! Well you're right this is the place to do it.
    + Just call FSOUND_DSP_Create, and give it a callback, and a priority. Set it active with FSOUND_DSP_SetActive and immediately your DSP unit will be ticking.
    + Now the data passed in will be either 16bit stereo integer (-32768 to +32767) or 32bit stereo floating point (-32768.0f to +32767.0f, not 0 to 1). This can be determined by what mixer is being used at the time, with FSOUND_GetMixer. + It's up to you now what you do with this data. One important thing to note is that FMOD mixes the data ahead of time, and the data you are processing is not the data that is immediately audible. If you are thinking of plotting the data to sync with the audible output, it is wise to buffer the data in a circular buffer, for the number of samples specified by FSOUND_DSP_GetBufferLengthTotal. This length is divisible by the DSP callback length (always a multiple of 25ms).
    + From this point then you would plot the block of data preceding the one you are filling, which is the one playing at that point in time!
    + See the FMOD example in the /samples/fmod directory for source code that does this, and many other examples of DSP processing. +
+ + + + + +
FSOUND_PlaySoundEx and the 'FSOUND_DSPUNIT *dsp' parameter         
+
    + The 'dsp' parameter in this new PlaySound command, allows you to assign or 'group' a channel to a specific DSP unit. The dsp unit you assign has to be a new one and not an existing system unit, with no callback.
    + A DSP unit with sound effects attached to it does nothing but execute channel mixing, as it replaces the DSP callback with its own internal mixer callback.
    + One reason for doing this is having a wet/dry mix for an effect. This is demonstrated in the /samples/dsp directory. You may want to have some effects affected by reverb for example, but not others. This is part of the reason the Music Unit is separate from the SFX unit, as you likely don't want music affected by DSP effects but do want the in-game sound effects to be affected.
    +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/dx8fx.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/dx8fx.htm index be97d261..444ed29f 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/dx8fx.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/dx8fx.htm @@ -1,123 +1,123 @@ - - - - - -DX8 FSOUND_FX Tutorial - Firelight Technologies Pty, Ltd. - - - - - - -
- -
-
-
-

FSOUND FX API

-
- - - - - - - -
Introduction         
-
    - The FSOUND_FX api allows you to do special effects processing per channel through Direct X 8 only.
    - You can do such effects as chorus, compression, distortion, echo, flange, gargle, reverb, and EQ through a simple API.
    -
- - - - - -
Limitations         
-
    - Before using the FSOUND_FX api, there are a few limitations that must be known about because of the DirectX API.
    -
    -
  • FX enabled samples can only be played once at a time, not multiple times at once. -
  • Samples or streams have to be created with FSOUND_HW2D or FSOUND_HW3D, and FSOUND_ENABLEFX for this to work. -
  • If you are using DirectX 8, FSOUND_SetFrequency will not work any more for that sound, you cannot change the pitch of a FX enabled sound. This is a DirectX limitation. Direct X 9 does not have this limitation. -
  • FSOUND_FX_Enable cannot be called if the sound is playing or locked. -
  • If FSOUND_FX_Disable is not called effects will build up on top of each other every time FSOUND_FX_Enable is called. -
    - Once these are taken into account, you can go for it! -
- - - - - -
Using it         
-
    - You have to use the pause feature of FSOUND_PlaySoundEx for this API to work.
    - The reason for this is DirectX needs a channel resource in hardware to be allocated, and so actually PLAYED (but paused) before the FX functions can succeed.
    -
    - Once you have it played but paused, you can enable multiple effects on one channel, and even the same effect multiple times on the same channel, then unpause it to hear what happens, but at this point you cannot enable more effects. It has to be paused or restarted.
    - You can update the parameters of effects while they are playing or while it is paused.
    -
    - Here is an example
    -
    -
      - - int channel, echoid, echoid2;
      - channel = FSOUND_PlaySoundEx(FSOUND_FREE, samp2, DrySFXUnit, TRUE);
      -
      - echoid = FSOUND_FX_Enable(channel, FSOUND_FX_ECHO); // enable echo and get the first echo handle
      - echoid2 = FSOUND_FX_Enable(channel, FSOUND_FX_ECHO); // enable echo again and get the second echo handle
      - FSOUND_FX_Enable(channel, FSOUND_FX_FLANGER); // enable the flange effect, don't bother with the handle, we'll just use the default parameters<
      -
      - FSOUND_SetPaused(channel, FALSE); // now start the sound playing
      -
      - FSOUND_FX_SetEcho(echoid, 80.0f, 70.0f, 100.0f, 100.0f, TRUE); // Alter the parameters of the first echo for the channel it was enabled on. This handle is unique to this effect and this channel. The 2nd echo we enabled will be unaffected
      -
      -
    -
    - This process must be repeated as when a sound is restarted, all FX information is reset, so effects must be enabled each time. -
- - - - - -
FX on the 'output' channel.         
-
    - This is a special feature which allows you to enable effects on the output result of the software mixed channels!
    - If you specify FSOUND_INIT_ENABLESYSTEMCHANNELFXX in the flags field of FSOUND_Init.
    - The channel ID to use for altering the output result is FSOUND_SYSTEMCHANNEL. Call FSOUND_SetPaused on this to enable effects. This will stop all software mixed sound effects. -
- - - - - -
FSOUND_FX + Spectrum and DSP?.         
-
    - - To use the FSOUND_FX api to do fx on channels requires FSOUND_HW2D or FSOUND_HW3D (and FSOUND_ENABLEFX) flags to work.
    - You may notice if you do this, you will lose the ability to do FSOUND_DSP_GetSpectrum or any DSP unit will not register, because FSOUND_FX channels play in hardware, and don't run through the FMOD DSP Engine.
    -
    - There is a way to do this though. Instead of performing EQ on a channel by channel basis, perform it on the global software mix output.
    -
    - This means you can't have per channel control, but if you are just looking for a way to do EQ on your audio for example, then use the following method.
    -
    -
  • Call FSOUND_SetBufferSize(100); When you call FSOUND_Init with FSOUND_INIT_ENABLESYSTEMCHANNELFX (see step 2) you will need a big enough software engine buffer to allow FX to be processed. FMOD defaults to 50 which is too small. This is a limitation of DirectSound and needs to be taken care of.
    -
  • Use FSOUND_INIT_ENABLESYSTEMCHANNELFXin FSOUND_Init. This will ready the software engine output to have the FX api used on it.
    -
  • Pause the software engine. You always need to pause the source when using FSOUND_FX_Enable (see step 3), so call FSOUND_SetPaused(FSOUND_SYSTEMCHANNEL, TRUE);
    -
  • Call FSOUND_FX_Enable to create all your FX handles (EQ, distortion whatever).
    -
  • Unpause the software engine. FSOUND_SetPaused(FSOUND_SYSTEMCHANNEL, FALSE);
    -
  • Now you are ready! Create streams and sounds in software mode (FSOUND_NORMAL - don't use FSOUND_HW2D or FSOUND_HW3D)
    -
    - Now that all your sounds and streams are in software, you get spectrum analysis back, and also you can use the DSP engine for your own software processing or oscilliscope plotting - with the added benefit of FSOUND_FX processing!
    -
-
-
-
-
-
- - + + + + + +DX8 FSOUND_FX Tutorial - Firelight Technologies Pty, Ltd. + + + + + + +
+ +
+
+
+

FSOUND FX API

+
+ + + + + + + +
Introduction         
+
    + The FSOUND_FX api allows you to do special effects processing per channel through Direct X 8 only.
    + You can do such effects as chorus, compression, distortion, echo, flange, gargle, reverb, and EQ through a simple API.
    +
+ + + + + +
Limitations         
+
    + Before using the FSOUND_FX api, there are a few limitations that must be known about because of the DirectX API.
    +
    +
  • FX enabled samples can only be played once at a time, not multiple times at once. +
  • Samples or streams have to be created with FSOUND_HW2D or FSOUND_HW3D, and FSOUND_ENABLEFX for this to work. +
  • If you are using DirectX 8, FSOUND_SetFrequency will not work any more for that sound, you cannot change the pitch of a FX enabled sound. This is a DirectX limitation. Direct X 9 does not have this limitation. +
  • FSOUND_FX_Enable cannot be called if the sound is playing or locked. +
  • If FSOUND_FX_Disable is not called effects will build up on top of each other every time FSOUND_FX_Enable is called. +
    + Once these are taken into account, you can go for it! +
+ + + + + +
Using it         
+
    + You have to use the pause feature of FSOUND_PlaySoundEx for this API to work.
    + The reason for this is DirectX needs a channel resource in hardware to be allocated, and so actually PLAYED (but paused) before the FX functions can succeed.
    +
    + Once you have it played but paused, you can enable multiple effects on one channel, and even the same effect multiple times on the same channel, then unpause it to hear what happens, but at this point you cannot enable more effects. It has to be paused or restarted.
    + You can update the parameters of effects while they are playing or while it is paused.
    +
    + Here is an example
    +
    +
      + + int channel, echoid, echoid2;
      + channel = FSOUND_PlaySoundEx(FSOUND_FREE, samp2, DrySFXUnit, TRUE);
      +
      + echoid = FSOUND_FX_Enable(channel, FSOUND_FX_ECHO); // enable echo and get the first echo handle
      + echoid2 = FSOUND_FX_Enable(channel, FSOUND_FX_ECHO); // enable echo again and get the second echo handle
      + FSOUND_FX_Enable(channel, FSOUND_FX_FLANGER); // enable the flange effect, don't bother with the handle, we'll just use the default parameters<
      +
      + FSOUND_SetPaused(channel, FALSE); // now start the sound playing
      +
      + FSOUND_FX_SetEcho(echoid, 80.0f, 70.0f, 100.0f, 100.0f, TRUE); // Alter the parameters of the first echo for the channel it was enabled on. This handle is unique to this effect and this channel. The 2nd echo we enabled will be unaffected
      +
      +
    +
    + This process must be repeated as when a sound is restarted, all FX information is reset, so effects must be enabled each time. +
+ + + + + +
FX on the 'output' channel.         
+
    + This is a special feature which allows you to enable effects on the output result of the software mixed channels!
    + If you specify FSOUND_INIT_ENABLESYSTEMCHANNELFXX in the flags field of FSOUND_Init.
    + The channel ID to use for altering the output result is FSOUND_SYSTEMCHANNEL. Call FSOUND_SetPaused on this to enable effects. This will stop all software mixed sound effects. +
+ + + + + +
FSOUND_FX + Spectrum and DSP?.         
+
    + + To use the FSOUND_FX api to do fx on channels requires FSOUND_HW2D or FSOUND_HW3D (and FSOUND_ENABLEFX) flags to work.
    + You may notice if you do this, you will lose the ability to do FSOUND_DSP_GetSpectrum or any DSP unit will not register, because FSOUND_FX channels play in hardware, and don't run through the FMOD DSP Engine.
    +
    + There is a way to do this though. Instead of performing EQ on a channel by channel basis, perform it on the global software mix output.
    +
    + This means you can't have per channel control, but if you are just looking for a way to do EQ on your audio for example, then use the following method.
    +
    +
  • Call FSOUND_SetBufferSize(100); When you call FSOUND_Init with FSOUND_INIT_ENABLESYSTEMCHANNELFX (see step 2) you will need a big enough software engine buffer to allow FX to be processed. FMOD defaults to 50 which is too small. This is a limitation of DirectSound and needs to be taken care of.
    +
  • Use FSOUND_INIT_ENABLESYSTEMCHANNELFXin FSOUND_Init. This will ready the software engine output to have the FX api used on it.
    +
  • Pause the software engine. You always need to pause the source when using FSOUND_FX_Enable (see step 3), so call FSOUND_SetPaused(FSOUND_SYSTEMCHANNEL, TRUE);
    +
  • Call FSOUND_FX_Enable to create all your FX handles (EQ, distortion whatever).
    +
  • Unpause the software engine. FSOUND_SetPaused(FSOUND_SYSTEMCHANNEL, FALSE);
    +
  • Now you are ready! Create streams and sounds in software mode (FSOUND_NORMAL - don't use FSOUND_HW2D or FSOUND_HW3D)
    +
    + Now that all your sounds and streams are in software, you get spectrum analysis back, and also you can use the DSP engine for your own software processing or oscilliscope plotting - with the added benefit of FSOUND_FX processing!
    +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/fsb.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/fsb.htm index 8c6b1a5a..a202aa76 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/fsb.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/fsb.htm @@ -1,161 +1,161 @@ - - - - - -The FSB Format - Firelight Technologies Pty, Ltd. - - - - - - -
- -
-
-
-

THE FSB FORMAT, BANKS, STREAMS AND SENTENCING

-
- - - - - - - -
Introduction         
-
    - FMOD Introduces a new format called .FSB, or the FMOD Sample Bank format.
    - This format is generated by the supplied tool. FSBank (fsbank.exe). It is mainly recommended for console formats, but can be used on any platform.
    - It is especially recommended for PlayStation 2, XBox and GameCube as it is a more optimal method of loading sound data into sound ram rather than using individual sound files which is slow and inefficient when coming off CD. -
- - - - - -
Compiling the FSB file         
-
    - - Creating an FSB file (or multiple fsb files!) is easy. Just open the tool called fsbank.exe provided in the tools directory. Currently this is only provided as a win32 application.
    - You will find an interface looking something like this.
    -
    -
    -
    - FSBank is very easy to use.
    - You have to first decide what type of FSB file output you want to generate. The most common is a single .FSB file containing multiple sounds. This is the default and accessible by choosing 'Generate Single FSB File' from the pull-down 'Build' menu as shown in the diagram.
    -
    - Single FSB file
    - You simply take a directory of any sound files, and specify as the 'Source Directory' field. - Then tell the compiler where to build the file to by choosing a 'Destination File'. - Now choose a platform to build to ('Choose Target' field at the bottom of the screen), and hit the big 'Build' button.
    - This generates a single .FSB file, and on top of this it also gives you a C header file to include into your program to allow indexed access to the sound data within the FSB file.
    -
    - Multiple FSB files
    - This is similar to before, but now you can generate multiple fsb files instead of 1 file. This is only useful for generating multiple .FSB files to be used for streaming (Think of it as a batch build for individual streams). Note that you can use a single FSB file as described above for streaming, but it is limited during playback to only one of the sounds in the bank at a time.
    - You simply take a directory of any sound files, and specify as the 'Source Directory' field. - Then tell the compiler where to build the file to by choosing a 'Destination Directory'. - Now choose a the platform to build too ('Choose Target' field at the bottom of the screen), and hit the big 'Build' button.
    - This generates multiple .FSB files, one for each source file, and on top of this it also gives you a C header file for each output file.
    -
    - Single Interleaved FSB File
    - This mode allows multiple sound files to be interleaved into 1 stream. It only generates 1 FSB entry, but as mono has 1 channel, stereo has 2 channels, these files can have up to 16 channels of interleaved audio. The data is multiplexed in units suitable to the hardware (ie PlayStation 2 will interleave data every 16 bytes, 36 bytes on XBox
    - Why is this useful? Well with this feature, you could get 16 channels of playback with no seeking. If you loaded and played 16 streams individually you would notice a LOT of seeking which is inneficient, and causes stuttering or the need for huge buffersizes, using up lots of RAM. Using interleaved streams will remove seeking, and reduce stream buffersizes.
    - Why would you want to have 16 tracks of sound going at once? Well this is up to the user, but the main benefits for this are
    -
      -
    • Interactive music.
      - Because these streams are interleaved, it also means they are perfectly synchronized. You can have multiple layers of soundtrack interleaved, and for the duration of the song, the majority of the channels can be set to volume 0, so they are muted. When an event or situation arises in the game you can fade up and down different tracks to bring in a new drumbeat or overlay for example, adding mood. -
    • Multichannel ambience.
      - This would be purely beneficial for the technical side of streaming, reducing the amount of seeking and memory needed to play multiple individual streams. You can have many tracks of huge ambience data streaming at once, and 3d position each subchannel if you like, so stream data comes in and out depending on location in the game world for example. -
    - Note: These interleaved files can also be statically loaded using the FMUSIC api, and played back as 'samples' as well as streams, as long as you have enough sound ram.
    - -
    - PlayStation 2
    - Streams benefit immensely from FSB compiling on PlayStation 2. As .VAG (the native ps2 format) does not support stereo data natively, .FSB overcomes this by interleaving stereo vag blocks into each other, then deinterleaving it at runtime when streaming.
    - This has a benefit of not having to play 2 mono streams at once (panning one left and one right), like you might have to with other playback systems.
    -
- - - - - -
Accessing FSB files from within your program         
-
    - - Loading an .FSB file as a static sound bank into sound ram
    - To do this, you use the FMUSIC_LoadSong or FMUSIC_LoadSongEx, and FMUSIC_GetSample functions. Because these functions already existed in the FMOD api for mod,s3m,xm,it,midi it seemed appropriate to use this API for FSB files, even though they are strictly not 'songs'.
    - - The C header generated by the FSBank tool contains #defines or indices to reference each individual sound from your code, using FMUSIC_GetSample.
    - You can simply call FSOUND_PlaySound on each of these sample handles you retrieve through the FMUSIC api and manipulate them as you would with normal samples.
    -
    - Use FMUSIC_GetNumSamples to determine the number of samples in the FSB format.
    -
    - You can modify the way all sounds are loaded by using the mode parameter of the FMUSIC_LoadSongEx function. For example if you want to make all sounds hardware 3d you just specify the FSOUND_HW3D flag. You could also make them all 2d, or maybe make them all loop with FSOUND_LOOP_NORMAL.
    -
    - Opening a multisound FSB file as a stream
    - This is the same as opening any other stream. Use FSOUND_Stream_Open.
    - To access the subsounds within the bank is different than with samples. Because it is a stream, you can only seek from one subsound to another. This is achieved with FSOUND_Stream_SetSubStream. - Because this is a seeking action, it will stop the currently playing stream, and perform the seek to the new sound. You will have to call FSOUND_Stream_Play to get it to start playing again. -
- - - - - -
Stream stitching, or sentencing         
-
    - When playing an FSB file as a stream, did you know you can stitch them together at runtime using FMOD's sentencing engine. This allows for absolutely gapless, efficient stitching of sounds, with no need for slow stopping or starting new streams, and the order of playback is determined at run time.
    - This is great for voice overs, where you can string together a bunch of sounds to make a single coherent sentence.
    -
    - How is this done in code?
    - That is easy. You just call FSOUND_Stream_SetSubStreamSentence before you call FSOUND_Stream_Play or FSOUND_Stream_PlayEx.
    - ie, say you have a bank with multiple sounds in it, with sound snippets like "Brett", "Andrew", "Scored", "Missed", "One Point", "Two Points!", "Three Points!"
    -
    - int list[3] = { SOUND_BRETT, SOUND_SCORED, SOUND_THREEPOINTS };
    - FSOUND_Stream_SetSubStreamSentence(stream, list, 3);
    - FSOUND_Stream_Play(FSOUND_FREE, stream);
    -

    - This would result in a very smooth "Brett scored three points!". -
- - - - - -
Did you know?         
-
    - If you have loaded your FSB file as a static sample bank, you can call FMUSIC_PlaySong to listen to the contents of the file? It will play each subsound one by one, which is great for previews. -
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +The FSB Format - Firelight Technologies Pty, Ltd. + + + + + + +
+ +
+
+
+

THE FSB FORMAT, BANKS, STREAMS AND SENTENCING

+
+ + + + + + + +
Introduction         
+
    + FMOD Introduces a new format called .FSB, or the FMOD Sample Bank format.
    + This format is generated by the supplied tool. FSBank (fsbank.exe). It is mainly recommended for console formats, but can be used on any platform.
    + It is especially recommended for PlayStation 2, XBox and GameCube as it is a more optimal method of loading sound data into sound ram rather than using individual sound files which is slow and inefficient when coming off CD. +
+ + + + + +
Compiling the FSB file         
+
    + + Creating an FSB file (or multiple fsb files!) is easy. Just open the tool called fsbank.exe provided in the tools directory. Currently this is only provided as a win32 application.
    + You will find an interface looking something like this.
    +
    +
    +
    + FSBank is very easy to use.
    + You have to first decide what type of FSB file output you want to generate. The most common is a single .FSB file containing multiple sounds. This is the default and accessible by choosing 'Generate Single FSB File' from the pull-down 'Build' menu as shown in the diagram.
    +
    + Single FSB file
    + You simply take a directory of any sound files, and specify as the 'Source Directory' field. + Then tell the compiler where to build the file to by choosing a 'Destination File'. + Now choose a platform to build to ('Choose Target' field at the bottom of the screen), and hit the big 'Build' button.
    + This generates a single .FSB file, and on top of this it also gives you a C header file to include into your program to allow indexed access to the sound data within the FSB file.
    +
    + Multiple FSB files
    + This is similar to before, but now you can generate multiple fsb files instead of 1 file. This is only useful for generating multiple .FSB files to be used for streaming (Think of it as a batch build for individual streams). Note that you can use a single FSB file as described above for streaming, but it is limited during playback to only one of the sounds in the bank at a time.
    + You simply take a directory of any sound files, and specify as the 'Source Directory' field. + Then tell the compiler where to build the file to by choosing a 'Destination Directory'. + Now choose a the platform to build too ('Choose Target' field at the bottom of the screen), and hit the big 'Build' button.
    + This generates multiple .FSB files, one for each source file, and on top of this it also gives you a C header file for each output file.
    +
    + Single Interleaved FSB File
    + This mode allows multiple sound files to be interleaved into 1 stream. It only generates 1 FSB entry, but as mono has 1 channel, stereo has 2 channels, these files can have up to 16 channels of interleaved audio. The data is multiplexed in units suitable to the hardware (ie PlayStation 2 will interleave data every 16 bytes, 36 bytes on XBox
    + Why is this useful? Well with this feature, you could get 16 channels of playback with no seeking. If you loaded and played 16 streams individually you would notice a LOT of seeking which is inneficient, and causes stuttering or the need for huge buffersizes, using up lots of RAM. Using interleaved streams will remove seeking, and reduce stream buffersizes.
    + Why would you want to have 16 tracks of sound going at once? Well this is up to the user, but the main benefits for this are
    +
      +
    • Interactive music.
      + Because these streams are interleaved, it also means they are perfectly synchronized. You can have multiple layers of soundtrack interleaved, and for the duration of the song, the majority of the channels can be set to volume 0, so they are muted. When an event or situation arises in the game you can fade up and down different tracks to bring in a new drumbeat or overlay for example, adding mood. +
    • Multichannel ambience.
      + This would be purely beneficial for the technical side of streaming, reducing the amount of seeking and memory needed to play multiple individual streams. You can have many tracks of huge ambience data streaming at once, and 3d position each subchannel if you like, so stream data comes in and out depending on location in the game world for example. +
    + Note: These interleaved files can also be statically loaded using the FMUSIC api, and played back as 'samples' as well as streams, as long as you have enough sound ram.
    + +
    + PlayStation 2
    + Streams benefit immensely from FSB compiling on PlayStation 2. As .VAG (the native ps2 format) does not support stereo data natively, .FSB overcomes this by interleaving stereo vag blocks into each other, then deinterleaving it at runtime when streaming.
    + This has a benefit of not having to play 2 mono streams at once (panning one left and one right), like you might have to with other playback systems.
    +
+ + + + + +
Accessing FSB files from within your program         
+
    + + Loading an .FSB file as a static sound bank into sound ram
    + To do this, you use the FMUSIC_LoadSong or FMUSIC_LoadSongEx, and FMUSIC_GetSample functions. Because these functions already existed in the FMOD api for mod,s3m,xm,it,midi it seemed appropriate to use this API for FSB files, even though they are strictly not 'songs'.
    + + The C header generated by the FSBank tool contains #defines or indices to reference each individual sound from your code, using FMUSIC_GetSample.
    + You can simply call FSOUND_PlaySound on each of these sample handles you retrieve through the FMUSIC api and manipulate them as you would with normal samples.
    +
    + Use FMUSIC_GetNumSamples to determine the number of samples in the FSB format.
    +
    + You can modify the way all sounds are loaded by using the mode parameter of the FMUSIC_LoadSongEx function. For example if you want to make all sounds hardware 3d you just specify the FSOUND_HW3D flag. You could also make them all 2d, or maybe make them all loop with FSOUND_LOOP_NORMAL.
    +
    + Opening a multisound FSB file as a stream
    + This is the same as opening any other stream. Use FSOUND_Stream_Open.
    + To access the subsounds within the bank is different than with samples. Because it is a stream, you can only seek from one subsound to another. This is achieved with FSOUND_Stream_SetSubStream. + Because this is a seeking action, it will stop the currently playing stream, and perform the seek to the new sound. You will have to call FSOUND_Stream_Play to get it to start playing again. +
+ + + + + +
Stream stitching, or sentencing         
+
    + When playing an FSB file as a stream, did you know you can stitch them together at runtime using FMOD's sentencing engine. This allows for absolutely gapless, efficient stitching of sounds, with no need for slow stopping or starting new streams, and the order of playback is determined at run time.
    + This is great for voice overs, where you can string together a bunch of sounds to make a single coherent sentence.
    +
    + How is this done in code?
    + That is easy. You just call FSOUND_Stream_SetSubStreamSentence before you call FSOUND_Stream_Play or FSOUND_Stream_PlayEx.
    + ie, say you have a bank with multiple sounds in it, with sound snippets like "Brett", "Andrew", "Scored", "Missed", "One Point", "Two Points!", "Three Points!"
    +
    + int list[3] = { SOUND_BRETT, SOUND_SCORED, SOUND_THREEPOINTS };
    + FSOUND_Stream_SetSubStreamSentence(stream, list, 3);
    + FSOUND_Stream_Play(FSOUND_FREE, stream);
    +

    + This would result in a very smooth "Brett scored three points!". +
+ + + + + +
Did you know?         
+
    + If you have loaded your FSB file as a static sample bank, you can call FMUSIC_PlaySong to listen to the contents of the file? It will play each subsound one by one, which is great for previews. +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/gc.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/gc.htm index 4bd6b23d..17b6f2e6 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/gc.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/gc.htm @@ -1,136 +1,136 @@ - - - - - -GameCube - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

GAMECUBE SPECIFIC ISSUES / FEATURES

-
- - - - - - - - -
Introduction         
-
    - This section describes how to get started with FMOD for Gamecube
    -
- - - - -
Compiling and linking         
-
    - Include fmod.h in your project, this is found in api/inc.
    -
    - To link FMOD to your project, there are the following files.
    -
  • /api/lib/fmodgc.lib - Link to this file if you are using SN Systems compiler. -
  • /api/lib/fmodgcD.lib - This is the debug version of fmodgc.lib and outputs a log of FMOD's progress and any error messages (in plain english) to the TTY. -
  • /api/lib/fmodgc_cw.a - Link to this file if you are using the Metrowerks Codewarrior compiler. -
  • /api/lib/fmodgc_cwD.a - This is the debug version of fmodgc_cw.lib and outputs a log of FMOD's progress and any error messages (in plain english) to the TTY. -
    -
- - - - -
Running the examples         
-
    - Simply load their .dsp files into Dev Studio and hit F7.
    -
    - NOTE: You will need to copy all files in the media directory to
    -
      - $DVDROOT/fmod. For example:
      -
      - copy media\*.* c:\DolphinSDK1.0\dvddata\fmod -
    -
    -
- - - - -
Conversion tools         
-
    - dspadpcm.exe -
    -
    - FMOD supports the Nintendo DSPADPCM format as output by the Nintendo tool "dspadpcm.exe". - FMOD expects the file extension ".dsp" on these files.
    - For clarity and consistency, FMOD refers to this format as FSOUND_GCADPCM.
    - NOTE: dspadpcm.exe can only convert MONO samples!
    -
    - fsbank.exe
    -
    - This is a Windows app that creates .fsb files - FMOD's native sample bank format.
    - Use it to create sample banks of either MONO or STEREO ADPCM samples suitable for playing or streaming using the GameCube ADPCM hardware.
    -
    -
- - - - -
Performance issues and Gamecube specific FMOD features.         
-
    - Hardware voice dropping
    -
    - Due to a design issue with the Gamecube hardware, the processor will drop hardware voices if it's DSP chip gets overloaded.
    - Call FSOUND_Update each game cycle and FMOD will automatically reacquire voices that get dropped.
    - FMOD's priority system has been linked into this, so it is likely to drop lower priority sounds that have their priority set with FSOUND_Sample_Defaults.
    -
    - Direct DVD streaming -
    - Use FMOD's stream API to play streams using the GameCube's DVD audio streaming capability.
    - When opening a stream, simply specify a file with a .adp extension and FMOD will stream it using the GameCube's hardware straight from the DVD to the AI, completely bypassing both ARAM and MRAM.
    -
    - Gamecube extras
    -
    - Look in fmodgc.h for GameCube-specific functions relating to such things as DVD status callbacks, AUX effects, specifying a block of ARAM for FMOD to use and accessing IPL sound settings.
    -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +GameCube - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

GAMECUBE SPECIFIC ISSUES / FEATURES

+
+ + + + + + + + +
Introduction         
+
    + This section describes how to get started with FMOD for Gamecube
    +
+ + + + +
Compiling and linking         
+
    + Include fmod.h in your project, this is found in api/inc.
    +
    + To link FMOD to your project, there are the following files.
    +
  • /api/lib/fmodgc.lib - Link to this file if you are using SN Systems compiler. +
  • /api/lib/fmodgcD.lib - This is the debug version of fmodgc.lib and outputs a log of FMOD's progress and any error messages (in plain english) to the TTY. +
  • /api/lib/fmodgc_cw.a - Link to this file if you are using the Metrowerks Codewarrior compiler. +
  • /api/lib/fmodgc_cwD.a - This is the debug version of fmodgc_cw.lib and outputs a log of FMOD's progress and any error messages (in plain english) to the TTY. +
    +
+ + + + +
Running the examples         
+
    + Simply load their .dsp files into Dev Studio and hit F7.
    +
    + NOTE: You will need to copy all files in the media directory to
    +
      + $DVDROOT/fmod. For example:
      +
      + copy media\*.* c:\DolphinSDK1.0\dvddata\fmod +
    +
    +
+ + + + +
Conversion tools         
+
    + dspadpcm.exe +
    +
    + FMOD supports the Nintendo DSPADPCM format as output by the Nintendo tool "dspadpcm.exe". + FMOD expects the file extension ".dsp" on these files.
    + For clarity and consistency, FMOD refers to this format as FSOUND_GCADPCM.
    + NOTE: dspadpcm.exe can only convert MONO samples!
    +
    + fsbank.exe
    +
    + This is a Windows app that creates .fsb files - FMOD's native sample bank format.
    + Use it to create sample banks of either MONO or STEREO ADPCM samples suitable for playing or streaming using the GameCube ADPCM hardware.
    +
    +
+ + + + +
Performance issues and Gamecube specific FMOD features.         
+
    + Hardware voice dropping
    +
    + Due to a design issue with the Gamecube hardware, the processor will drop hardware voices if it's DSP chip gets overloaded.
    + Call FSOUND_Update each game cycle and FMOD will automatically reacquire voices that get dropped.
    + FMOD's priority system has been linked into this, so it is likely to drop lower priority sounds that have their priority set with FSOUND_Sample_Defaults.
    +
    + Direct DVD streaming +
    + Use FMOD's stream API to play streams using the GameCube's DVD audio streaming capability.
    + When opening a stream, simply specify a file with a .adp extension and FMOD will stream it using the GameCube's hardware straight from the DVD to the AI, completely bypassing both ARAM and MRAM.
    +
    + Gamecube extras
    +
    + Look in fmodgc.h for GameCube-specific functions relating to such things as DVD status callbacks, AUX effects, specifying a block of ARAM for FMOD to use and accessing IPL sound settings.
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/main.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/main.htm index 3e1d35a3..497574f4 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/main.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/main.htm @@ -1,28 +1,28 @@ - - - - FMOD Documentation, Firelight Technologies Pty, Ltd. - - - -

-

- -

 

-
- -
-
-
-
-
Thank you for downloading FMOD music - and sound effects system. -

Within this package you will find the means to produce the most up to date - and efficient

-

audio in your games and applications.

-

 

-

To find out more go to http://www.fmod.org

-
- - + + + + FMOD Documentation, Firelight Technologies Pty, Ltd. + + + +

+

+ +

 

+
+ +
+
+
+
+
Thank you for downloading FMOD music + and sound effects system. +

Within this package you will find the means to produce the most up to date + and efficient

+

audio in your games and applications.

+

 

+

To find out more go to http://www.fmod.org

+
+ + diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/movieplayers.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/movieplayers.htm index c9be8ae1..8f50fc4c 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/movieplayers.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/movieplayers.htm @@ -1,164 +1,164 @@ - - - - - -Co-existing with movie players - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

FMOD AND MOVIE PLAYERS

-
- - - - - - - - -
Introduction         
-
    - This section describes how to have FMOD happily coexist with various movie playback systems available. - -
- - - - -
PlayStation 2         
-
    - The main causes on conflicts between other middleware that uses audio or the IOP, and FMOD are:
    -
    -
  • Conflict between the SPU2 DMA channels. There are 2 of these. DMA channel 0 and DMA channel 1. By default FMOD uses SPU2 DMA channel 0 for software mixing, and DMA core 1 for uploading sample data and for streaming to. This means DMA core 1 is used when FMUSIC_LoadSong / FMUSIC_LoadSongEx is being executed to load a PS2 FSB file, or streaming using FSOUND_Stream_Open / FSOUND_Stream_Play. To work around this issue see the following tips. -
      -
    • Turn off the FMOD software mixer. This will free up DMA Channel 0. Most of the time you are not going to need this. You can do this by using FSOUND_Init with software channels set to 0. -
    • Swap FMOD's mixer/upload channel usage around. If the 3rd party software still uses DMA Channel 1 (the channel FMOD uses for bank uploads and streaming), you can either change your 3rd party software to use DMA Channel 0 instead of DMA Channel 1, or tell FMOD to swap its usage around by specifying FMOD_INIT_PS2_SWAPDMACORES. If you didn't turn the software mixer off, this would make FMOD use DMA Channel 0 for streams and sample bank uploads, and DMA Channel 1 for the software mixer. -
    -
    -
  • Conflict on the SIFCMD ports. If your middleware or your own code is using the SIFCMD sony library to communicate with the IOP, then if you dont take care to share the SIFCMD buffers and ports with FMOD, messages will get lost and unexpected behaviour will occur in FMOD and your 3rd party software. -
      -
    • If you want to initialize your 3rd party software after FMOD. Use this information if the code has a way to set up its SIFCMD usage. Note that FMOD uses SIFCMD port 0 and 1, and has a buffer size of 16. -
    • If you want to initialize your 3rd party software before FMOD. If FMOD is initialized first, call FSOUND_SetSifCommandInfo from fmodps2.h. Also load your FMOD.IRX or FMODSMALL.IRX with command line parameters to allow the IOP side to get the same information. For more detailed information on this see the comment above the function prototype in fmodps2.h. -
    -
    -
  • SPU2 ram usage and SPU2 hardware voice usage. Because FMOD and the middleware might not know about each other, they might allocate memory or use SPU2 voices without any regard for the other. -
      -
    • Use FSOUND_SPU2_Alloc / FSOUND_SPU2_GetRawAddress / FSOUND_SPU2_Free. Use these functions to allocate SPU2 memory for your 3rd party application. This way it will use FMOD's memory manager. -
    • Use FSOUND_SetReserved. If the 3rd party software uses SPU2 voices, you can mark the literal SPU2 voice index as not to be used within FMOD. If the 3rd party software used SPU2 voice 0 for example FMOD would use FSOUND_SetReserved(number_of_software_channels + 0, TRUE); Note that the software channels value is mentioned because raw channel indicies are 0 to (maxnumsoftwarechannels - 1) = software voices, and after this are hardware voices. If you have the software mixer turned off, then 0 would be SPU2 voice 0 and 47 would be SPU2 voice 47. -
    -
    -
- - - - - - - -
XBOX         
-
    - The main causes on conflicts between other middleware that uses audio on the XBox, and FMOD are:
    -
    -
  • "DSOUND: CMcpxAPU::AllocateVoices: Error: Not enough free hardware voices". By default FMOD assumes it is in total control of the audio, so it allocates every XBox audio voice. If another 3rd party software application tries to allocate a hardware voice it will fail. -
      -
    • Use FSOUND_SetMaxHardwareChannels. To get around this issue just call FSOUND_SetMaxHardwareChannels to reduce the count. XBox has around 192 HW2D voices so you could reduce this and still have plenty of voices free. -
    -
    -
  • DSP Image incorrect. FMOD has an internal MCP DSP image that it loads. It is stripped down to save memory, (hundreds of kilobytes) by removing unnescessary features. This may conflict with other 3rd party software that relies on a standard DSP image such as Microsoft's dsstdfx.bin. -
      -
    • Use FSOUND_SpecifyEffectsImage. If the 3rd party middleware has a dsp image file that it relies on you can use FSOUND_SpecifyEffectsImage (found in fmodxbox.h) to make FMOD use that image. -
    • Make the other software use FMOD's image. You can get a handle to FMOD's internal dsp image structure by calling FSOUND_GetEffectImageDesc (found in fmodxbox.h) if the 3rd party has such a facility to allow this sort of external image to be used. -
    -
    -
  • Needs access to the XBox LPDIRECTSOUND handle. If the 3rd party software is initialized second, it may want to use the XBox LPDIRECTSOUND handle. -
      -
    • Use FSOUND_GetOutputHandle. If you need to get a handle to FMOD's internal DirectSound pointer, you can share it by calling FSOUND_GetOutputHandle and casting it to the appropriate pointer type. -
    -
    -
- - - - - - - -
Win32         
-
    - If you need to get a handle to FMOD's internal DirectSound pointer, you can share it by calling FSOUND_GetOutputHandle and casting it to the appropriate pointer type.
    - This also goes for XBox and other platforms, and depends on th -
- - - - - - -
Bink on PS2         
-
    - Here is a quick way to get FMOD PS2 and Bink to co-exist.
    -
    - Initialize FMOD first.
    -
    - FSOUND_Init(48000, 0, FSOUND_INIT_PS2_SWAPDMACORES);
    - FSOUND_SetReserved(0,TRUE);
    -
    - Initialize Bink
    -
    - - MovieBuffer = sceSifAllocIopHeap( RAD_IOPMemoryAmount( RAD_IOP_NEED_CORE1 ) );
    - RAD_IOPMemoryAmount(RAD_IOP_NEED_CORE1) ));
    - if ( !RAD_IOPStartUp( 1, 2, MovieBuffer, RAD_IOP_NEED_CORE1|RAD_IOP_NO_INIT_LIBSD ) )
    - {
    -
      - sceSifFreeIopHeap(MovieBuffer);
      - // error
      -
    - }
    - RAD_IOPHardwareVolumes(1, 0x3fff, 0x3fff, 0x3fff, 0x3fff);
    - BinkSoundUseRAD_IOP(1);
    -
    -
    -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +Co-existing with movie players - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

FMOD AND MOVIE PLAYERS

+
+ + + + + + + + +
Introduction         
+
    + This section describes how to have FMOD happily coexist with various movie playback systems available. + +
+ + + + +
PlayStation 2         
+
    + The main causes on conflicts between other middleware that uses audio or the IOP, and FMOD are:
    +
    +
  • Conflict between the SPU2 DMA channels. There are 2 of these. DMA channel 0 and DMA channel 1. By default FMOD uses SPU2 DMA channel 0 for software mixing, and DMA core 1 for uploading sample data and for streaming to. This means DMA core 1 is used when FMUSIC_LoadSong / FMUSIC_LoadSongEx is being executed to load a PS2 FSB file, or streaming using FSOUND_Stream_Open / FSOUND_Stream_Play. To work around this issue see the following tips. +
      +
    • Turn off the FMOD software mixer. This will free up DMA Channel 0. Most of the time you are not going to need this. You can do this by using FSOUND_Init with software channels set to 0. +
    • Swap FMOD's mixer/upload channel usage around. If the 3rd party software still uses DMA Channel 1 (the channel FMOD uses for bank uploads and streaming), you can either change your 3rd party software to use DMA Channel 0 instead of DMA Channel 1, or tell FMOD to swap its usage around by specifying FMOD_INIT_PS2_SWAPDMACORES. If you didn't turn the software mixer off, this would make FMOD use DMA Channel 0 for streams and sample bank uploads, and DMA Channel 1 for the software mixer. +
    +
    +
  • Conflict on the SIFCMD ports. If your middleware or your own code is using the SIFCMD sony library to communicate with the IOP, then if you dont take care to share the SIFCMD buffers and ports with FMOD, messages will get lost and unexpected behaviour will occur in FMOD and your 3rd party software. +
      +
    • If you want to initialize your 3rd party software after FMOD. Use this information if the code has a way to set up its SIFCMD usage. Note that FMOD uses SIFCMD port 0 and 1, and has a buffer size of 16. +
    • If you want to initialize your 3rd party software before FMOD. If FMOD is initialized first, call FSOUND_SetSifCommandInfo from fmodps2.h. Also load your FMOD.IRX or FMODSMALL.IRX with command line parameters to allow the IOP side to get the same information. For more detailed information on this see the comment above the function prototype in fmodps2.h. +
    +
    +
  • SPU2 ram usage and SPU2 hardware voice usage. Because FMOD and the middleware might not know about each other, they might allocate memory or use SPU2 voices without any regard for the other. +
      +
    • Use FSOUND_SPU2_Alloc / FSOUND_SPU2_GetRawAddress / FSOUND_SPU2_Free. Use these functions to allocate SPU2 memory for your 3rd party application. This way it will use FMOD's memory manager. +
    • Use FSOUND_SetReserved. If the 3rd party software uses SPU2 voices, you can mark the literal SPU2 voice index as not to be used within FMOD. If the 3rd party software used SPU2 voice 0 for example FMOD would use FSOUND_SetReserved(number_of_software_channels + 0, TRUE); Note that the software channels value is mentioned because raw channel indicies are 0 to (maxnumsoftwarechannels - 1) = software voices, and after this are hardware voices. If you have the software mixer turned off, then 0 would be SPU2 voice 0 and 47 would be SPU2 voice 47. +
    +
    +
+ + + + + + + +
XBOX         
+
    + The main causes on conflicts between other middleware that uses audio on the XBox, and FMOD are:
    +
    +
  • "DSOUND: CMcpxAPU::AllocateVoices: Error: Not enough free hardware voices". By default FMOD assumes it is in total control of the audio, so it allocates every XBox audio voice. If another 3rd party software application tries to allocate a hardware voice it will fail. +
      +
    • Use FSOUND_SetMaxHardwareChannels. To get around this issue just call FSOUND_SetMaxHardwareChannels to reduce the count. XBox has around 192 HW2D voices so you could reduce this and still have plenty of voices free. +
    +
    +
  • DSP Image incorrect. FMOD has an internal MCP DSP image that it loads. It is stripped down to save memory, (hundreds of kilobytes) by removing unnescessary features. This may conflict with other 3rd party software that relies on a standard DSP image such as Microsoft's dsstdfx.bin. +
      +
    • Use FSOUND_SpecifyEffectsImage. If the 3rd party middleware has a dsp image file that it relies on you can use FSOUND_SpecifyEffectsImage (found in fmodxbox.h) to make FMOD use that image. +
    • Make the other software use FMOD's image. You can get a handle to FMOD's internal dsp image structure by calling FSOUND_GetEffectImageDesc (found in fmodxbox.h) if the 3rd party has such a facility to allow this sort of external image to be used. +
    +
    +
  • Needs access to the XBox LPDIRECTSOUND handle. If the 3rd party software is initialized second, it may want to use the XBox LPDIRECTSOUND handle. +
      +
    • Use FSOUND_GetOutputHandle. If you need to get a handle to FMOD's internal DirectSound pointer, you can share it by calling FSOUND_GetOutputHandle and casting it to the appropriate pointer type. +
    +
    +
+ + + + + + + +
Win32         
+
    + If you need to get a handle to FMOD's internal DirectSound pointer, you can share it by calling FSOUND_GetOutputHandle and casting it to the appropriate pointer type.
    + This also goes for XBox and other platforms, and depends on th +
+ + + + + + +
Bink on PS2         
+
    + Here is a quick way to get FMOD PS2 and Bink to co-exist.
    +
    + Initialize FMOD first.
    +
    + FSOUND_Init(48000, 0, FSOUND_INIT_PS2_SWAPDMACORES);
    + FSOUND_SetReserved(0,TRUE);
    +
    + Initialize Bink
    +
    + + MovieBuffer = sceSifAllocIopHeap( RAD_IOPMemoryAmount( RAD_IOP_NEED_CORE1 ) );
    + RAD_IOPMemoryAmount(RAD_IOP_NEED_CORE1) ));
    + if ( !RAD_IOPStartUp( 1, 2, MovieBuffer, RAD_IOP_NEED_CORE1|RAD_IOP_NO_INIT_LIBSD ) )
    + {
    +
      + sceSifFreeIopHeap(MovieBuffer);
      + // error
      +
    + }
    + RAD_IOPHardwareVolumes(1, 0x3fff, 0x3fff, 0x3fff, 0x3fff);
    + BinkSoundUseRAD_IOP(1);
    +
    +
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/nonblocking.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/nonblocking.htm index a759ace1..dc652671 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/nonblocking.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/nonblocking.htm @@ -1,245 +1,245 @@ - - - - - -FSOUND_NONBLOCKING - Firelight Technologies Pty, Ltd. - - - - - - -
- -
-
-
-

USING THE FSOUND_NONBLOCKING FLAG

-
- - - - - - - -
Introduction         
-
    - The FSOUND_NONBLOCKING flag stops certain stream or music commands blocking the caller when being executed, by performing them in a seperate thread.
    - Mainly meant for opening streams and music, to avoid the slowness of disk access generating huge pauses, this flag makes these commands return immediately without affecting the frame-rate at all!
    - The flag must be specified in FSOUND_Stream_Open or FMUSIC_LoadSongEx using the mode parameter for it to work. You cannot use SetMode type functions to make it work, it must be called at the time of opening.
    -
    - This raises new issues though. You cannot just access a stream or music file that has been opened with the FSOUND_NONBLOCKING flag immediately! You have to wait for it to open!
    - FMOD does not 'queue' commands to non blocking streams/musics. This could lead to mis-use and overflows, or even confusion about the state of the stream behaviour at the time, so a polling method is preferred so that the user can control exactly what occurs in what order.
    - -
- - - - - -
Polling for success         
-
    - The key to working with nonblocking streams and music files is to wait for them to open before playing them. One method to do this is to poll the state of a stream using FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState.
    - Another method is to try and play the stream or access the subsounds continuously in a game loop until it succeeds.
    -
    - While a non blocking stream is opening, nearly all functions will return an error code to signify that the stream is not ready.
    - This means something like FSOUND_Stream_Play will return -1 while it is trying to open the file in the background.
    - When it returns a valid channel handle, you know it is ready and has succeeded!
    -
    - An example for playing a non blocking stream is provided below. This is a typical loop that should be used when trying to play a non blocking stream. You will notice, once it succeeds, it won't try and play again because channel is not -1 anymore. -
    - -
    - FSOUND_STREAM *stream;
    - int channel = -1;
    -
    - stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    -
    - do
    - {
    -
      - if (channel < 0)
      - {
      - - }
      -
      - GameCode();
      -
      -
    - } while (1)
    -
    -
    - Alternatively you could use the FSOUND_Stream_GetOpenState method. This is shown below.
    - -
    - FSOUND_STREAM *stream;
    - int channel = -1;
    -
    - stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    -
    - do
    - {
    - - } while (1)
    -
    -
    - It is basically the same thing and slightly redundant. -
    -
- - - - - -
FSB format, substreams and sentences.         
-
    - - Setting SubStreams
    -
    - FSB has multiple sounds packed within it, so you might want to use FSOUND_Stream_SetSubStream
    - You don't need to poll to get FSOUND_Stream_SetSubStream to work. It has been optimized so that it will immediately seek to the correct substream once the open has finished. This is a special case for this function, and no other functions allow this.
    - This means you can call it straight away, even after a non blocking stream open.
    - Here is a version of the above loop, that sets a substream.
    - -
    - FSOUND_STREAM *stream;
    - int channel = -1;
    -
    - - stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    - FSOUND_Stream_SetSubStream(stream, SOUND_4);
    -
    - do
    - {
    -
      - if (channel < 0)
      - {
      - - }
      - -
      - GameCode();
      -
      -
    - } while (1)
    -
    -
    - Note that once you call FSOUND_Stream_SetSubStream, the stream is 'not ready' again. This may not seem to be relevant if you call it after FSOUND_Stream_Open, because we already knew it was not going to be ready, but if you call it when the stream has actually finished opening and is ready (for example, you may want to set the substream long after the stream has opened, ie 30 seconds later), then you will need to remember this, but the above logic always takes care of it. You just need to set channel to -1 in the above example whenever you call FSOUND_Stream_SetSubStream and it will work.
    -
    -
    - - Setting SubStream Sentences
    -
    - Setting a sub-stream-sentence is next , and is slightly trickier. FSOUND_Stream_SetSubStreamSentence does not succeed immediately like FSOUND_Stream_SetSubStream, and will actually fail if the open is still in progress, so you cannot call it straight after FSOUND_Stream_Open like we did in the previous example.
    - What you have to do is poll for the stream to be in a ready state, then execute FSOUND_Stream_SetSubStreamSentence. Alternatively you can continually call FSOUND_Stream_SetSubStreamSentence until it succeeds, a bit like we did with the call to FSOUND_Stream_Play in the previous example.
    - Note the following code
    - -
    - FSOUND_STREAM *stream;
    - int channel = -1;
    - int setsentence = 0;
    -
    - - stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    -
    - do
    - {
    -
      - - if (!setsentence)
      - {
      - - }
      - else if (channel < 0)
      - {
      - - }
      - -
      - GameCode();
      -
      -
    - } while (1)
    -
    -
    -
    - Remember at all times, you can use FSOUND_Stream_GetOpenState just as effectively as continuously polling the command you want to succeed. It is just slightly less code using the above method.
    -
    -
- - - - - -
Things to look out for         
-
    -
    - If you suspect a file has not opened, or failed to open, poll FSOUND_Stream_GetOpenState. This will return the state of the stream, and if it has failed, it will return -3.
    - Note that even though the stream has failed to open, the stream handle is still valid when opening in non-blocking mode. You will need to close it.
    -
    - The point of FSOUND_NONBLOCKING is that it takes no cpu time away from the caller. This means it cannot check the validity of a file, as that would constitute disk access, which could block and cause frames to drop from the application.
    - All disk access is done from the FMOD asynchronous loading thread, so if it fails, the user cannot get immediate feedback, they have to check the status seperately. -
    - Don't try and close a stream before it is ready! This will cause a memory leak, as FSOUND_Stream_Close will return FALSE because it is not ready. -
    - Check the documentation for each stream function to see if it will fail or not due to not being ready in a non blocking state. -
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +FSOUND_NONBLOCKING - Firelight Technologies Pty, Ltd. + + + + + + +
+ +
+
+
+

USING THE FSOUND_NONBLOCKING FLAG

+
+ + + + + + + +
Introduction         
+
    + The FSOUND_NONBLOCKING flag stops certain stream or music commands blocking the caller when being executed, by performing them in a seperate thread.
    + Mainly meant for opening streams and music, to avoid the slowness of disk access generating huge pauses, this flag makes these commands return immediately without affecting the frame-rate at all!
    + The flag must be specified in FSOUND_Stream_Open or FMUSIC_LoadSongEx using the mode parameter for it to work. You cannot use SetMode type functions to make it work, it must be called at the time of opening.
    +
    + This raises new issues though. You cannot just access a stream or music file that has been opened with the FSOUND_NONBLOCKING flag immediately! You have to wait for it to open!
    + FMOD does not 'queue' commands to non blocking streams/musics. This could lead to mis-use and overflows, or even confusion about the state of the stream behaviour at the time, so a polling method is preferred so that the user can control exactly what occurs in what order.
    + +
+ + + + + +
Polling for success         
+
    + The key to working with nonblocking streams and music files is to wait for them to open before playing them. One method to do this is to poll the state of a stream using FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState.
    + Another method is to try and play the stream or access the subsounds continuously in a game loop until it succeeds.
    +
    + While a non blocking stream is opening, nearly all functions will return an error code to signify that the stream is not ready.
    + This means something like FSOUND_Stream_Play will return -1 while it is trying to open the file in the background.
    + When it returns a valid channel handle, you know it is ready and has succeeded!
    +
    + An example for playing a non blocking stream is provided below. This is a typical loop that should be used when trying to play a non blocking stream. You will notice, once it succeeds, it won't try and play again because channel is not -1 anymore. +
    + +
    + FSOUND_STREAM *stream;
    + int channel = -1;
    +
    + stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    +
    + do
    + {
    +
      + if (channel < 0)
      + {
      + + }
      +
      + GameCode();
      +
      +
    + } while (1)
    +
    +
    + Alternatively you could use the FSOUND_Stream_GetOpenState method. This is shown below.
    + +
    + FSOUND_STREAM *stream;
    + int channel = -1;
    +
    + stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    +
    + do
    + {
    + + } while (1)
    +
    +
    + It is basically the same thing and slightly redundant. +
    +
+ + + + + +
FSB format, substreams and sentences.         
+
    + + Setting SubStreams
    +
    + FSB has multiple sounds packed within it, so you might want to use FSOUND_Stream_SetSubStream
    + You don't need to poll to get FSOUND_Stream_SetSubStream to work. It has been optimized so that it will immediately seek to the correct substream once the open has finished. This is a special case for this function, and no other functions allow this.
    + This means you can call it straight away, even after a non blocking stream open.
    + Here is a version of the above loop, that sets a substream.
    + +
    + FSOUND_STREAM *stream;
    + int channel = -1;
    +
    + + stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    + FSOUND_Stream_SetSubStream(stream, SOUND_4);
    +
    + do
    + {
    +
      + if (channel < 0)
      + {
      + + }
      + +
      + GameCode();
      +
      +
    + } while (1)
    +
    +
    + Note that once you call FSOUND_Stream_SetSubStream, the stream is 'not ready' again. This may not seem to be relevant if you call it after FSOUND_Stream_Open, because we already knew it was not going to be ready, but if you call it when the stream has actually finished opening and is ready (for example, you may want to set the substream long after the stream has opened, ie 30 seconds later), then you will need to remember this, but the above logic always takes care of it. You just need to set channel to -1 in the above example whenever you call FSOUND_Stream_SetSubStream and it will work.
    +
    +
    + + Setting SubStream Sentences
    +
    + Setting a sub-stream-sentence is next , and is slightly trickier. FSOUND_Stream_SetSubStreamSentence does not succeed immediately like FSOUND_Stream_SetSubStream, and will actually fail if the open is still in progress, so you cannot call it straight after FSOUND_Stream_Open like we did in the previous example.
    + What you have to do is poll for the stream to be in a ready state, then execute FSOUND_Stream_SetSubStreamSentence. Alternatively you can continually call FSOUND_Stream_SetSubStreamSentence until it succeeds, a bit like we did with the call to FSOUND_Stream_Play in the previous example.
    + Note the following code
    + +
    + FSOUND_STREAM *stream;
    + int channel = -1;
    + int setsentence = 0;
    +
    + + stream = FSOUND_Stream_Open("mystream.fsb", FSOUND_NONBLOCKING, 0, 0);
    +
    + do
    + {
    +
      + + if (!setsentence)
      + {
      + + }
      + else if (channel < 0)
      + {
      + + }
      + +
      + GameCode();
      +
      +
    + } while (1)
    +
    +
    +
    + Remember at all times, you can use FSOUND_Stream_GetOpenState just as effectively as continuously polling the command you want to succeed. It is just slightly less code using the above method.
    +
    +
+ + + + + +
Things to look out for         
+
    +
    + If you suspect a file has not opened, or failed to open, poll FSOUND_Stream_GetOpenState. This will return the state of the stream, and if it has failed, it will return -3.
    + Note that even though the stream has failed to open, the stream handle is still valid when opening in non-blocking mode. You will need to close it.
    +
    + The point of FSOUND_NONBLOCKING is that it takes no cpu time away from the caller. This means it cannot check the validity of a file, as that would constitute disk access, which could block and cause frames to drop from the application.
    + All disk access is done from the FMOD asynchronous loading thread, so if it fails, the user cannot get immediate feedback, they have to check the status seperately. +
    + Don't try and close a stream before it is ready! This will cause a memory leak, as FSOUND_Stream_Close will return FALSE because it is not ready. +
    + Check the documentation for each stream function to see if it will fail or not due to not being ready in a non blocking state. +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/ps2.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/ps2.htm index 3624bbcc..2f84674a 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/ps2.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/ps2.htm @@ -1,300 +1,300 @@ - - - - - -PlayStation 2 - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

PLAYSTATION 2 SPECIFIC ISSUES / FEATURES

-
- - - - - - - - -
Introduction         
-
    - This section describes how to get started with FMOD for PS2, and also some of the PS2 specific features available.
    -
- - - - -
Getting Started         
-
    - This section describes what you will need to link, and what you need to call to get up and running for PS2 specifically.
    -
    - What to link and loading modules.
    -
    -
  • Link /api/lib/fmod.a into your project. -
  • Put /api/fmod.irx into your modules directory. You have to load the IRX yourself using sceSifLoadModule. More about this follows.
    -
    - A simple PlayStation 2 application has to do the following to use FMOD.
    -
    - 1.
    -
      - Load fmod.irx and sony's libsd.irx. This is done from host0 or cdrom0 or whatever file device you store your files on.
      - Load libsd first, then fmod.
      -
      - eg.
      - -
        - while (sceSifLoadModule(host0:modules/libsd.irx", 0, NULL) < 0)
        - {
        -
          - printf("loading libsd.irx failed\n");
          -
        - }
        - while (sceSifLoadModule("host0:modules/fmod.irx", 0, NULL) < 0)
        - {
        -
          - printf("loading fmod.irx failed\n");
          -
        - }
        -
      -
      -
      - Note that the default position for libsd.irx is at /usr/local/sce/iop/modules/ but it may differ on your machine.
      -
      - What does each module do?
      -
    • libsd.irx - This is a sony irx that contains the low level hardware routines needed by fmod.irx. -
    • fmod.irx - This is the fmod library and contains the majority of the functionality. -
    - 2. -
      - Remember to Initialize the IOP heap with sceSifInitIopHeap().
      - This is to be called after the call to sceSifInitRpc(0) and before loading any modules.
      -
      - eg.
      - - sceSifInitRpc(0);
      - sceSifInitIopHeap();
      -
      -
      - WARNING! If you reboot the IOP you have to call the above again!!! Otherwise FMOD will fail to initialize.
      -
    - 3. -
      - Call FSOUND_Init and proceed programming with the FMOD API as you would on any other platform.
      - On PS2, you must call FSOUND_Update to get commands to issue.
      -
      - Mismatching fmod.a and fmod.irx versions are not tolerated.
      - FMOD will fail to initialize if they are from different releases of FMOD.
      -
      -
    -
    - Release / Debug.
    -
    - fmod.irx and fmodD.irx have been supplied. fmodD.irx is debug, and slower, and prints out a log of FMOD progress, along with english explanations on errors if they occur.
    -
    -
    - Stripped / Non stripped.
    -
    - You may notice there is also fmod_small.irx and fmodD_small.irx. These versions use less IOP ram than the full versions, but only because they have features removed.
    - These features are removed in the _small versions.
    -
    - .MOD, .S3M, .XM, .IT, .WAV and .VAG support. Note for .VAG support, this is talking about the file format, so FSB "VAG" support still exists.
    -
    - Normal streaming (with FSB files), 3d sound and sample management remains.
    -
    -
    - EE Thread Priority.
    -
    - Note that if the EE main thread priority is not changed from the default of 1, FMOD will change it to 32.
    - No thread can start when the default priority is 1 so this is nescessary.
    - FMOD uses 1 thread to receive messages from the IOP.
    -
- - - - -
Formats supported - hardware / software         
-
    - FMOD PS2 supports .VAG and .WAV, although FSB is the highly recommended format, see the next section on FSB files for more information about this.
    - .VAG is mixed in hardware and .WAV is mixed in software. .WAV mixing in software uses IOP processing time.
    - At the moment, depending on quality settings, FMOD can only mix around 12-20 channels of PCM data at once.
    -
    - .MOD .S3M .XM and .IT music formats are supported, and are mixed in software.
    - Again currently only mods with 12-20 channels or less are recommended due to the CPU strain on the 33mhz IOP processor.
    - 32 channel mods should be supported after more optimizations.
    -
    - Software mixing speed on the IOP.
    -
    - Using FSOUND_Mixer with one of the following controls the number of channels available in software. - Remember hardware mixing is preferred so you may not have to encounter this issue.
    -
    - - FSOUND_MIXER_AUTODETECT (non interpolating stereo output - fast)
    - - FSOUND_MIXER_QUALITY_AUTODETECT (high quality interpolating stereo output - slowest)
    - - FSOUND_MIXER_MONO (non interpolating mono output - fastest)
    - - FSOUND_MIXER_QUALITY_MONO (high quality interpolating mono output - slow)
    -
    - FSOUND_Init on the PS2 accepts 24000 or 48000. 24000 is lower quality but increases the possible channel count significantly.
    - FMOD will not support other output rates! Do not try and use them! (erroneous rates just case the output rate to go to 48000)
    -
- - - - -
The FSB format - The recommended format for samples and streams.         
-
    - Although .WAV and .VAG formats are supported, for loading speed, and streaming speed it is highly recommended to use .FSB files.
    - FSB is hardware accelerated, WAV is not.
    -
    - These are compiled batches of native PlayStation 2 SPU2 sound data, arranged so when loaded, it is one read to load the headers first, then the raw vag data (which is continuous), which is streamed into SPU2 ram. This is the fastest way to load sound data.
    -
    -
- - - - -
Memory managment.         
-
    - IOP Memory.
    -
    - Upon calling FSOUND_Init, FMOD allocates ALL remaining memory on the IOP.
    - This is so FMOD can store sounds in IOP ram if needed.
    - If you want to limit FMOD's IOP memory usage, simply call FSOUND_SetMemorySystem.
    -
    - ie.
    - FSOUND_SetMemorySystem(NULL, 128*1024, NULL, NULL, NULL);
    -
    - This will force FMOD to only use 128kb of IOP memory.
    - Note that setting too low a value will cause FMOD to fail in its internal system memory allocations and FSOUND_Init could even fail.
    -
    - EE Memory.
    -
    - The EE memory footprint is minimal. There is no dynamic memory allocation on the EE.
    - The EE library is simply a command layer wrapping all FMOD api functions, and uses nothing but static structures and memory to avoid malloc/free/new/delete issues on the EE side.
    - It uses this library to pass commands to the IOP for processing on that CPU.
    -
    -
- - - - -
Reverb.         
-
    - You have access to the hardware PlayStation 2 SPU2 reverb through FMOD's FSOUND_Reverb_xxx API.
    - Note that the SPU2 Reverb is a lot more primitive than I3DL2 reverb and EAX3.
    - In the FSOUND_REVERB_PROPERTIES structure, only Environment, Room and Flags are supported.
    -
    - 'Environment' -
      - This is a value between 0 and 9 mapping to the sony reverb modes.
      - You will find 9 special presets for the PlayStation 2 with this environment value set accordingly.
      - ie
      - FSOUND_PRESET_PS2_ROOM
      - FSOUND_PRESET_PS2_STUDIO_A
      - FSOUND_PRESET_PS2_STUDIO_B
      - FSOUND_PRESET_PS2_STUDIO_C
      - FSOUND_PRESET_PS2_HALL
      - FSOUND_PRESET_PS2_SPACE
      - FSOUND_PRESET_PS2_ECHO
      - FSOUND_PRESET_PS2_DELAY
      - FSOUND_PRESET_PS2_PIPE
      - The other presets will not work, except for FSOUND_PRESET_OFF.
      -
    - 'Room' -
      - This still controls the amount of reverb mixed into the output.
      - Normally it is in decibels, between -10000 (silent) and 0 (full volume), and it is the same range on the PlayStation 2, but it is a linear scale between -10000 and 0, not a logarithmic one.
      -
    - 'Flags' -
      - This only utilizes the following fields on PlayStation 2.
      - FSOUND_REVERB_FLAGS_CORE0 (hardware voices 0 to 23)
      - FSOUND_REVERB_FLAGS_CORE1 (hardware voices 24 to 47)
      - This tells the FMOD engine which core, or set of hardware voices to apply the reverb settings to.
      - By default (in the presets) it is set to apply to both cores, but you can remove these flags to control each core seperately.
      -
    -
    - Note that FSOUND_Reverb_SetChannelProperties is supported through the 'Room' parameter only,
    - and that this value is binary, ie -10000 is 'reverb off' for the channel, and anything else is 'reverb on'.
    -
- - - - -
FSOUND_SetDiskBusy         
-
    - This function is usually not optional and is essential for smooth running disk cooperation between fmod and the game.
    - This function causes mutual exclusion for the cdrom or host0 so that you don't get read errors when trying to access the disk while fmod is playing a stream or accessing the disk in some manner (ie opening a bank or stream in FSOUND_NONBLOCKING mode)
    - In your game code you would do something like this:
    -
    - - FSOUND_SetDiskBusy(TRUE);
    - sceRead(...);
    - FSOUND_SetDiskBusy(FALSE);
    -
    -
    - This will block on a semaphore in FSOUND_SetDiskBusy(TRUE) if fmod is using the disk, and if it enters and executes the sceRead/sceCdRead, fmod will not access the disk, and instead wait until it is available to use again.
    - Note - if you set this for too long, audio streams may start to skip / stutter, because FMOD didnt get enough time to fill its audio buffer. Make sure you either split up your own reads into smaller chunks, or make a bigger buffersize for FMOD to use with FSOUND_Stream_SetBufferSize.
    -
- - - - -
Dolby Prologic 2 output         
-
    - Use FSOUND_SetSpeakerMode(FSOUND_SPEAKERMODE_PROLOGIC2) or FSOUND_SetSpeakerMode(FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR) to enable 5.1 surround sound on ps2.
    - The interior mode uses twice as many hardware voices (meaning you effectively only get 24 voices instead of 48), but allows sounds to smoothly move from left to right and vice versa, where the normal mode will 'jump' from one speaker to the other if running straight along the X axis.
    - It is a tradeoff between voices and quality, if you need to, you should evaluate both methods to see which works better.
    - Note on a stereo sound system, the interior 2 voice method will cause a phasing effect, which can sound odd or bad, it is really meant for a prologic 2 system.
    -
- - - - -
Volume ramping         
-
    - Most games released on the ps2 (not using FMOD) make click and pop noises because the hardware doesn't support smooth volume or pan changes.
    - FMOD has implemented an advanced ramping system that not many people know about or are too put off by the difficulty of the method.
    - You can enable this as a flag in FSOUND_Init using the FSOUND_INIT_PS2_USEVOLUMERAMPING flag.
    - Turning this on will reduce hardware clicks or remove them, producing clean sounding audio, giving you an advantage over your competitors!
    -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +PlayStation 2 - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

PLAYSTATION 2 SPECIFIC ISSUES / FEATURES

+
+ + + + + + + + +
Introduction         
+
    + This section describes how to get started with FMOD for PS2, and also some of the PS2 specific features available.
    +
+ + + + +
Getting Started         
+
    + This section describes what you will need to link, and what you need to call to get up and running for PS2 specifically.
    +
    + What to link and loading modules.
    +
    +
  • Link /api/lib/fmod.a into your project. +
  • Put /api/fmod.irx into your modules directory. You have to load the IRX yourself using sceSifLoadModule. More about this follows.
    +
    + A simple PlayStation 2 application has to do the following to use FMOD.
    +
    + 1.
    +
      + Load fmod.irx and sony's libsd.irx. This is done from host0 or cdrom0 or whatever file device you store your files on.
      + Load libsd first, then fmod.
      +
      + eg.
      + +
        + while (sceSifLoadModule(host0:modules/libsd.irx", 0, NULL) < 0)
        + {
        +
          + printf("loading libsd.irx failed\n");
          +
        + }
        + while (sceSifLoadModule("host0:modules/fmod.irx", 0, NULL) < 0)
        + {
        +
          + printf("loading fmod.irx failed\n");
          +
        + }
        +
      +
      +
      + Note that the default position for libsd.irx is at /usr/local/sce/iop/modules/ but it may differ on your machine.
      +
      + What does each module do?
      +
    • libsd.irx - This is a sony irx that contains the low level hardware routines needed by fmod.irx. +
    • fmod.irx - This is the fmod library and contains the majority of the functionality. +
    + 2. +
      + Remember to Initialize the IOP heap with sceSifInitIopHeap().
      + This is to be called after the call to sceSifInitRpc(0) and before loading any modules.
      +
      + eg.
      + + sceSifInitRpc(0);
      + sceSifInitIopHeap();
      +
      +
      + WARNING! If you reboot the IOP you have to call the above again!!! Otherwise FMOD will fail to initialize.
      +
    + 3. +
      + Call FSOUND_Init and proceed programming with the FMOD API as you would on any other platform.
      + On PS2, you must call FSOUND_Update to get commands to issue.
      +
      + Mismatching fmod.a and fmod.irx versions are not tolerated.
      + FMOD will fail to initialize if they are from different releases of FMOD.
      +
      +
    +
    + Release / Debug.
    +
    + fmod.irx and fmodD.irx have been supplied. fmodD.irx is debug, and slower, and prints out a log of FMOD progress, along with english explanations on errors if they occur.
    +
    +
    + Stripped / Non stripped.
    +
    + You may notice there is also fmod_small.irx and fmodD_small.irx. These versions use less IOP ram than the full versions, but only because they have features removed.
    + These features are removed in the _small versions.
    +
    + .MOD, .S3M, .XM, .IT, .WAV and .VAG support. Note for .VAG support, this is talking about the file format, so FSB "VAG" support still exists.
    +
    + Normal streaming (with FSB files), 3d sound and sample management remains.
    +
    +
    + EE Thread Priority.
    +
    + Note that if the EE main thread priority is not changed from the default of 1, FMOD will change it to 32.
    + No thread can start when the default priority is 1 so this is nescessary.
    + FMOD uses 1 thread to receive messages from the IOP.
    +
+ + + + +
Formats supported - hardware / software         
+
    + FMOD PS2 supports .VAG and .WAV, although FSB is the highly recommended format, see the next section on FSB files for more information about this.
    + .VAG is mixed in hardware and .WAV is mixed in software. .WAV mixing in software uses IOP processing time.
    + At the moment, depending on quality settings, FMOD can only mix around 12-20 channels of PCM data at once.
    +
    + .MOD .S3M .XM and .IT music formats are supported, and are mixed in software.
    + Again currently only mods with 12-20 channels or less are recommended due to the CPU strain on the 33mhz IOP processor.
    + 32 channel mods should be supported after more optimizations.
    +
    + Software mixing speed on the IOP.
    +
    + Using FSOUND_Mixer with one of the following controls the number of channels available in software. + Remember hardware mixing is preferred so you may not have to encounter this issue.
    +
    + - FSOUND_MIXER_AUTODETECT (non interpolating stereo output - fast)
    + - FSOUND_MIXER_QUALITY_AUTODETECT (high quality interpolating stereo output - slowest)
    + - FSOUND_MIXER_MONO (non interpolating mono output - fastest)
    + - FSOUND_MIXER_QUALITY_MONO (high quality interpolating mono output - slow)
    +
    + FSOUND_Init on the PS2 accepts 24000 or 48000. 24000 is lower quality but increases the possible channel count significantly.
    + FMOD will not support other output rates! Do not try and use them! (erroneous rates just case the output rate to go to 48000)
    +
+ + + + +
The FSB format - The recommended format for samples and streams.         
+
    + Although .WAV and .VAG formats are supported, for loading speed, and streaming speed it is highly recommended to use .FSB files.
    + FSB is hardware accelerated, WAV is not.
    +
    + These are compiled batches of native PlayStation 2 SPU2 sound data, arranged so when loaded, it is one read to load the headers first, then the raw vag data (which is continuous), which is streamed into SPU2 ram. This is the fastest way to load sound data.
    +
    +
+ + + + +
Memory managment.         
+
    + IOP Memory.
    +
    + Upon calling FSOUND_Init, FMOD allocates ALL remaining memory on the IOP.
    + This is so FMOD can store sounds in IOP ram if needed.
    + If you want to limit FMOD's IOP memory usage, simply call FSOUND_SetMemorySystem.
    +
    + ie.
    + FSOUND_SetMemorySystem(NULL, 128*1024, NULL, NULL, NULL);
    +
    + This will force FMOD to only use 128kb of IOP memory.
    + Note that setting too low a value will cause FMOD to fail in its internal system memory allocations and FSOUND_Init could even fail.
    +
    + EE Memory.
    +
    + The EE memory footprint is minimal. There is no dynamic memory allocation on the EE.
    + The EE library is simply a command layer wrapping all FMOD api functions, and uses nothing but static structures and memory to avoid malloc/free/new/delete issues on the EE side.
    + It uses this library to pass commands to the IOP for processing on that CPU.
    +
    +
+ + + + +
Reverb.         
+
    + You have access to the hardware PlayStation 2 SPU2 reverb through FMOD's FSOUND_Reverb_xxx API.
    + Note that the SPU2 Reverb is a lot more primitive than I3DL2 reverb and EAX3.
    + In the FSOUND_REVERB_PROPERTIES structure, only Environment, Room and Flags are supported.
    +
    + 'Environment' +
      + This is a value between 0 and 9 mapping to the sony reverb modes.
      + You will find 9 special presets for the PlayStation 2 with this environment value set accordingly.
      + ie
      + FSOUND_PRESET_PS2_ROOM
      + FSOUND_PRESET_PS2_STUDIO_A
      + FSOUND_PRESET_PS2_STUDIO_B
      + FSOUND_PRESET_PS2_STUDIO_C
      + FSOUND_PRESET_PS2_HALL
      + FSOUND_PRESET_PS2_SPACE
      + FSOUND_PRESET_PS2_ECHO
      + FSOUND_PRESET_PS2_DELAY
      + FSOUND_PRESET_PS2_PIPE
      + The other presets will not work, except for FSOUND_PRESET_OFF.
      +
    + 'Room' +
      + This still controls the amount of reverb mixed into the output.
      + Normally it is in decibels, between -10000 (silent) and 0 (full volume), and it is the same range on the PlayStation 2, but it is a linear scale between -10000 and 0, not a logarithmic one.
      +
    + 'Flags' +
      + This only utilizes the following fields on PlayStation 2.
      + FSOUND_REVERB_FLAGS_CORE0 (hardware voices 0 to 23)
      + FSOUND_REVERB_FLAGS_CORE1 (hardware voices 24 to 47)
      + This tells the FMOD engine which core, or set of hardware voices to apply the reverb settings to.
      + By default (in the presets) it is set to apply to both cores, but you can remove these flags to control each core seperately.
      +
    +
    + Note that FSOUND_Reverb_SetChannelProperties is supported through the 'Room' parameter only,
    + and that this value is binary, ie -10000 is 'reverb off' for the channel, and anything else is 'reverb on'.
    +
+ + + + +
FSOUND_SetDiskBusy         
+
    + This function is usually not optional and is essential for smooth running disk cooperation between fmod and the game.
    + This function causes mutual exclusion for the cdrom or host0 so that you don't get read errors when trying to access the disk while fmod is playing a stream or accessing the disk in some manner (ie opening a bank or stream in FSOUND_NONBLOCKING mode)
    + In your game code you would do something like this:
    +
    + + FSOUND_SetDiskBusy(TRUE);
    + sceRead(...);
    + FSOUND_SetDiskBusy(FALSE);
    +
    +
    + This will block on a semaphore in FSOUND_SetDiskBusy(TRUE) if fmod is using the disk, and if it enters and executes the sceRead/sceCdRead, fmod will not access the disk, and instead wait until it is available to use again.
    + Note - if you set this for too long, audio streams may start to skip / stutter, because FMOD didnt get enough time to fill its audio buffer. Make sure you either split up your own reads into smaller chunks, or make a bigger buffersize for FMOD to use with FSOUND_Stream_SetBufferSize.
    +
+ + + + +
Dolby Prologic 2 output         
+
    + Use FSOUND_SetSpeakerMode(FSOUND_SPEAKERMODE_PROLOGIC2) or FSOUND_SetSpeakerMode(FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR) to enable 5.1 surround sound on ps2.
    + The interior mode uses twice as many hardware voices (meaning you effectively only get 24 voices instead of 48), but allows sounds to smoothly move from left to right and vice versa, where the normal mode will 'jump' from one speaker to the other if running straight along the X axis.
    + It is a tradeoff between voices and quality, if you need to, you should evaluate both methods to see which works better.
    + Note on a stereo sound system, the interior 2 voice method will cause a phasing effect, which can sound odd or bad, it is really meant for a prologic 2 system.
    +
+ + + + +
Volume ramping         
+
    + Most games released on the ps2 (not using FMOD) make click and pop noises because the hardware doesn't support smooth volume or pan changes.
    + FMOD has implemented an advanced ramping system that not many people know about or are too put off by the difficulty of the method.
    + You can enable this as a flag in FSOUND_Init using the FSOUND_INIT_PS2_USEVOLUMERAMPING flag.
    + Turning this on will reduce hardware clicks or remove them, producing clean sounding audio, giving you an advantage over your competitors!
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/psp.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/psp.htm index 66d14877..7d817d54 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/psp.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/psp.htm @@ -1,268 +1,268 @@ - - - - - -PlayStation Portable - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

PLAYSTATION PORTABLE SPECIFIC ISSUES / FEATURES

-
- - - - - - - - -
Introduction         
-
    - This section describes how to get started with FMOD for PSP, and also some of the PSP specific features available.
    -
- - - - -
Getting Started         
-
    - This section describes what you will need to link, and what you need to call to get up and running for PSP specifically.
    -
    -
    - What to link and loading modules.
    -
    - A simple PlayStation Portable application needs the following steps to be taken to use FMOD.
    -
    -
  • Link /api/lib/fmod.a into your project.
    -
    - FMOD requires the following sony libraries and modules to be used as well to get audio support. They are linked and loaded by the user.
    -
    -
  • Link library libsas.a into your project.
    -
  • Link weak import stub library file libatrac3plus_stub_weak.a into your project.
    -
  • Load module file sc_sascore.prx at runtime.
    -
    - If you require AT3 playback support, load the following sony run-time modules.
    -
    -
  • Load module file libatrac3plus.prx
    -
  • Load module file libaudiocodec.prx
    -
    - Note that the default position for sc_sascore.prx and audiocodec.prx is at /usr/local/devkit/kmodule but it may differ on your machine.
    - libatrac3plus.prx can be found normally at /usr/local/devkit/module. -
    -
    -
    - Loading the modules.
    -
    - For examples on how to load sony modules, see the FMOD examples. -
    - Load sony's sc_sascore.prx. If AT3 support is desired also load audiocodec.prx and libatrac3plus.prx. This is done from host0 or disc0 or whatever file device you store your files on.
    -
    - eg.
    - - /* load module */
    - static SceUID load_module(const char *filename, SceKernelLMOption *lm_opt, SceKernelSMOption *sm_opt)
    - {
    -
      - SceUID mid;
      - int ret;
      -
      - /* load module */
      - mid = sceKernelLoadModule((char *)filename, 0, lm_opt);
      - if (mid < 0)
      - {
      -
        - printf("fatal error : cannot load %s 0x%08x\n", filename, mid);
        - return mid;
        -
      - }
      -
      - /* start module */
      - if ((ret = sceKernelStartModule(mid, 0, NULL, NULL, sm_opt)) < 0)
      - {
      -
        - printf("fatal error : cannot start %s 0x%08x\n", filename, ret);
        - return ret;
        -
      - }
      -
      - return mid;
      -
    - }
    -
    -
    - ... -
    -
    - SceKernelLMOption kMode;
    - SceUID sasMid;
    -
    - sasMid = 0;
    -
    - kMode.size = sizeof(kMode);
    - kMode.mpidtext = SCE_KERNEL_PRIMARY_KERNEL_PARTITION;
    - kMode.mpiddata = SCE_KERNEL_PRIMARY_KERNEL_PARTITION;
    - kMode.position = SCE_KERNEL_LMWO_POS_Low;
    - kMode.access = SCE_KERNEL_LMWO_ACCESS_Noseek;
    -
    - sasMid = load_module("host0:/usr/local/devkit/kmodule/sc_sascore.prx", &kMode, NULL);
    - if(sasMid < 0)
    - {
    -
      - printf ("fatal error : load SAS module\n");
      - return -1;
      -
    - }
    - -
    -
    -
    - Initialize FMOD.
    -
    - Call FSOUND_Init and proceed programming with the FMOD API as you would on any other platform.
    -
    -
    - Release / Debug.
    -
    - fmod.a and fmodD.a have been supplied. fmodD is debug, and slower, and prints out a log of FMOD progress, along with english explanations on errors if they occur.
    -
    -
    - Stripped / Non stripped.
    -
    - You may notice there is also fmod_small.a and fmodD_small.a. These versions use less ram than the full versions, but only because they have features removed.
    - These features are removed in the _small versions.
    -
    - .MOD, .S3M, .XM, .IT, .WAV and .VAG support. Note for .VAG support, this is talking about the file format, so FSB "VAG" support still exists.
    -
    - Normal streaming (with FSB files), 3d sound and sample management remains.
    -
    -
    -
- - - - -
Formats supported - hardware / software         
-
    - FMOD PSP supports .VAG and .WAV, although FSB is the highly recommended format, see the next section on FSB files for more information about this.
    - .VAG is mixed in hardware and .WAV is mixed in software. .WAV mixing in software uses processing time.
    - At the moment, depending on quality settings, FMOD can only mix around 12-20 channels of PCM data at once.
    -
    - .MOD .S3M .XM and .IT music formats are supported, and are mixed in software.
    -
    - Software mixing speed.
    -
    - Using FSOUND_Mixer with one of the following controls the number of channels available in software. - Remember hardware mixing is preferred so you may not have to encounter this issue.
    -
    - - FSOUND_MIXER_AUTODETECT (non interpolating stereo output - fast)
    - - FSOUND_MIXER_QUALITY_AUTODETECT (high quality interpolating stereo output - slowest)
    - - FSOUND_MIXER_MONO (non interpolating mono output - fastest)
    - - FSOUND_MIXER_QUALITY_MONO (high quality interpolating mono output - slow)
    -
    - FSOUND_Init on the PSP accepts 24000 or 48000. 24000 is lower quality but increases the possible channel count significantly.
    - FMOD will not support other output rates! Do not try and use them! (erroneous rates just case the output rate to go to 48000)
    -
- - - - -
The FSB format - The recommended format for samples and streams.         
-
    - Although .WAV and .VAG formats are supported, for loading speed, and streaming speed it is highly recommended to use .FSB files.
    - FSB is hardware accelerated, WAV is not.
    -
    - These are compiled batches of native PlayStation Portable sound data, arranged so when loaded, it is one read to load the headers first, then the raw vag data (which is continuous), which is streamed into RAM. This is the fastest way to load sound data from UMD.
    -
    -
- - - - -
Memory managment.         
-
    - If so desired, the user can limit fmod's RAM usage to a single block of pre-allocated memory.
    - If you want to limit FMOD's memory usage in this way, simply call FSOUND_SetMemorySystem.
    -
    - ie.
    - FSOUND_SetMemorySystem(NULL, 128*1024, NULL, NULL, NULL);
    -
    - This will force FMOD to only use 128kb of IOP memory.
    - Note that setting too low a value will cause FMOD to fail in its internal system memory allocations and FSOUND_Init could even fail.
    -
    -
- - - - -
Streaming ATRAC music         
-
    - FMOD supports the playback of .at3 files. All the user has to do is play it from disc0, or if they like, they can load the file into memory, then use FSOUND_OPENMEMORY to stream the file from memory.
    -
    - Note that the user can use FSOUND_Stream_SetBufferSize to adjust the amount of memory FMOD uses when streaming a file, and if it is from memory, then it will require only a very small stream buffer.
    - If streaming from UMD, the buffer size need to be a lot larger. It should be the number of milliseconds between each read, which could be anywhere up to 5000ms.
    -
- - - - -
Battery considerations         
-
    - Note, that even though FMOD supports streaming multiple streams from UMD at once, this is not recommended. On the PlayStation Portable seeking should be avoided at all times to preserve movement of the umd read head and therefore battery life.
    - This also goes for data streaming. Do not stream data and music at the same time if there is seeking involved. Continuous seeking will degrade battery life because it has to mechanically move the seek head.
    -
    - It may be preferable to play 'in memory' music such as sequenced formats like .MOD/.S3M/.XM or .IT. Another idea is to load an AT3 file into memory first, then stream the file from memory as has been mentioned previously in this documentation. As atrac can store a minute of audio per mb at 128kbs stereo, then you would need 3mb of memory for 3 minutes of music. -
    -
- - - - -
The "15-20% cpu problem"         
-
    - Some users may notice a framerate impact when implementing audio. This is a known issue with Sony, and it is common knowledge among PSP developers that simply playing one sound in 'hardware' will cause up to 15-20% of the PSP's CPU to be used by audio.
    -
    - The problem lies in Sony's libwave, and there is nothing that can be done about it from FMOD's side until the issue is resolved with sony. FMOD offers a software mixer that can bypass Sony's VAG routines, but it will still require libwave access which is the problem.
    -
    -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + + +PlayStation Portable - Firelight Technologies Pty, Ltd. + + + + + + + + + +
+ +
+
+
+

PLAYSTATION PORTABLE SPECIFIC ISSUES / FEATURES

+
+ + + + + + + + +
Introduction         
+
    + This section describes how to get started with FMOD for PSP, and also some of the PSP specific features available.
    +
+ + + + +
Getting Started         
+
    + This section describes what you will need to link, and what you need to call to get up and running for PSP specifically.
    +
    +
    + What to link and loading modules.
    +
    + A simple PlayStation Portable application needs the following steps to be taken to use FMOD.
    +
    +
  • Link /api/lib/fmod.a into your project.
    +
    + FMOD requires the following sony libraries and modules to be used as well to get audio support. They are linked and loaded by the user.
    +
    +
  • Link library libsas.a into your project.
    +
  • Link weak import stub library file libatrac3plus_stub_weak.a into your project.
    +
  • Load module file sc_sascore.prx at runtime.
    +
    + If you require AT3 playback support, load the following sony run-time modules.
    +
    +
  • Load module file libatrac3plus.prx
    +
  • Load module file libaudiocodec.prx
    +
    + Note that the default position for sc_sascore.prx and audiocodec.prx is at /usr/local/devkit/kmodule but it may differ on your machine.
    + libatrac3plus.prx can be found normally at /usr/local/devkit/module. +
    +
    +
    + Loading the modules.
    +
    + For examples on how to load sony modules, see the FMOD examples. +
    + Load sony's sc_sascore.prx. If AT3 support is desired also load audiocodec.prx and libatrac3plus.prx. This is done from host0 or disc0 or whatever file device you store your files on.
    +
    + eg.
    + + /* load module */
    + static SceUID load_module(const char *filename, SceKernelLMOption *lm_opt, SceKernelSMOption *sm_opt)
    + {
    +
      + SceUID mid;
      + int ret;
      +
      + /* load module */
      + mid = sceKernelLoadModule((char *)filename, 0, lm_opt);
      + if (mid < 0)
      + {
      +
        + printf("fatal error : cannot load %s 0x%08x\n", filename, mid);
        + return mid;
        +
      + }
      +
      + /* start module */
      + if ((ret = sceKernelStartModule(mid, 0, NULL, NULL, sm_opt)) < 0)
      + {
      +
        + printf("fatal error : cannot start %s 0x%08x\n", filename, ret);
        + return ret;
        +
      + }
      +
      + return mid;
      +
    + }
    +
    +
    + ... +
    +
    + SceKernelLMOption kMode;
    + SceUID sasMid;
    +
    + sasMid = 0;
    +
    + kMode.size = sizeof(kMode);
    + kMode.mpidtext = SCE_KERNEL_PRIMARY_KERNEL_PARTITION;
    + kMode.mpiddata = SCE_KERNEL_PRIMARY_KERNEL_PARTITION;
    + kMode.position = SCE_KERNEL_LMWO_POS_Low;
    + kMode.access = SCE_KERNEL_LMWO_ACCESS_Noseek;
    +
    + sasMid = load_module("host0:/usr/local/devkit/kmodule/sc_sascore.prx", &kMode, NULL);
    + if(sasMid < 0)
    + {
    +
      + printf ("fatal error : load SAS module\n");
      + return -1;
      +
    + }
    + +
    +
    +
    + Initialize FMOD.
    +
    + Call FSOUND_Init and proceed programming with the FMOD API as you would on any other platform.
    +
    +
    + Release / Debug.
    +
    + fmod.a and fmodD.a have been supplied. fmodD is debug, and slower, and prints out a log of FMOD progress, along with english explanations on errors if they occur.
    +
    +
    + Stripped / Non stripped.
    +
    + You may notice there is also fmod_small.a and fmodD_small.a. These versions use less ram than the full versions, but only because they have features removed.
    + These features are removed in the _small versions.
    +
    + .MOD, .S3M, .XM, .IT, .WAV and .VAG support. Note for .VAG support, this is talking about the file format, so FSB "VAG" support still exists.
    +
    + Normal streaming (with FSB files), 3d sound and sample management remains.
    +
    +
    +
+ + + + +
Formats supported - hardware / software         
+
    + FMOD PSP supports .VAG and .WAV, although FSB is the highly recommended format, see the next section on FSB files for more information about this.
    + .VAG is mixed in hardware and .WAV is mixed in software. .WAV mixing in software uses processing time.
    + At the moment, depending on quality settings, FMOD can only mix around 12-20 channels of PCM data at once.
    +
    + .MOD .S3M .XM and .IT music formats are supported, and are mixed in software.
    +
    + Software mixing speed.
    +
    + Using FSOUND_Mixer with one of the following controls the number of channels available in software. + Remember hardware mixing is preferred so you may not have to encounter this issue.
    +
    + - FSOUND_MIXER_AUTODETECT (non interpolating stereo output - fast)
    + - FSOUND_MIXER_QUALITY_AUTODETECT (high quality interpolating stereo output - slowest)
    + - FSOUND_MIXER_MONO (non interpolating mono output - fastest)
    + - FSOUND_MIXER_QUALITY_MONO (high quality interpolating mono output - slow)
    +
    + FSOUND_Init on the PSP accepts 24000 or 48000. 24000 is lower quality but increases the possible channel count significantly.
    + FMOD will not support other output rates! Do not try and use them! (erroneous rates just case the output rate to go to 48000)
    +
+ + + + +
The FSB format - The recommended format for samples and streams.         
+
    + Although .WAV and .VAG formats are supported, for loading speed, and streaming speed it is highly recommended to use .FSB files.
    + FSB is hardware accelerated, WAV is not.
    +
    + These are compiled batches of native PlayStation Portable sound data, arranged so when loaded, it is one read to load the headers first, then the raw vag data (which is continuous), which is streamed into RAM. This is the fastest way to load sound data from UMD.
    +
    +
+ + + + +
Memory managment.         
+
    + If so desired, the user can limit fmod's RAM usage to a single block of pre-allocated memory.
    + If you want to limit FMOD's memory usage in this way, simply call FSOUND_SetMemorySystem.
    +
    + ie.
    + FSOUND_SetMemorySystem(NULL, 128*1024, NULL, NULL, NULL);
    +
    + This will force FMOD to only use 128kb of IOP memory.
    + Note that setting too low a value will cause FMOD to fail in its internal system memory allocations and FSOUND_Init could even fail.
    +
    +
+ + + + +
Streaming ATRAC music         
+
    + FMOD supports the playback of .at3 files. All the user has to do is play it from disc0, or if they like, they can load the file into memory, then use FSOUND_OPENMEMORY to stream the file from memory.
    +
    + Note that the user can use FSOUND_Stream_SetBufferSize to adjust the amount of memory FMOD uses when streaming a file, and if it is from memory, then it will require only a very small stream buffer.
    + If streaming from UMD, the buffer size need to be a lot larger. It should be the number of milliseconds between each read, which could be anywhere up to 5000ms.
    +
+ + + + +
Battery considerations         
+
    + Note, that even though FMOD supports streaming multiple streams from UMD at once, this is not recommended. On the PlayStation Portable seeking should be avoided at all times to preserve movement of the umd read head and therefore battery life.
    + This also goes for data streaming. Do not stream data and music at the same time if there is seeking involved. Continuous seeking will degrade battery life because it has to mechanically move the seek head.
    +
    + It may be preferable to play 'in memory' music such as sequenced formats like .MOD/.S3M/.XM or .IT. Another idea is to load an AT3 file into memory first, then stream the file from memory as has been mentioned previously in this documentation. As atrac can store a minute of audio per mb at 128kbs stereo, then you would need 3mb of memory for 3 minutes of music. +
    +
+ + + + +
The "15-20% cpu problem"         
+
    + Some users may notice a framerate impact when implementing audio. This is a known issue with Sony, and it is common knowledge among PSP developers that simply playing one sound in 'hardware' will cause up to 15-20% of the PSP's CPU to be used by audio.
    +
    + The problem lies in Sony's libwave, and there is nothing that can be done about it from FMOD's side until the issue is resolved with sony. FMOD offers a software mixer that can bypass Sony's VAG routines, but it will still require libwave access which is the problem.
    +
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/spectrum.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/spectrum.htm index fd15b491..190e52e3 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/spectrum.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/spectrum.htm @@ -1,107 +1,107 @@ - - - - - -3D Sound Tutorial - Firelight Technologies Pty, Ltd. - - - - - - - - - -
- -
-
-
-

SPECTRUM ANALYSIS

- - -
- - - - - - - - -
Introduction         
-
    - This short section reveals how easy it is to obtain the realtime spectrum graph for FMOD's DSP output as you hear it, for graphical display or even advanced signal processing! -
- - - - - -
Using it         
-
    - The spectrum analysis unit is an FMOD System DSP Unit. If you are unsure of the FMOD DSP system then see the DSP tutorial.
    - By default it is turned off because it can consume a reasonable amount of cpu time and it doesn't want to be doing Fast Fourier Transform code when the spectrum isn't even being queried!
    - To turn it on is quite simple. Just call.
    -
    - FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit, TRUE);
    -
    - To turn it off again is just as simple. Just call.
    -
    - FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), FALSE);
    -
    - When your audio is playing, this DSP unit will every 25ms, or the rate of the DSP engine, update a snapshot of the current audible spectrum.
    -
    - The range for this FFT produces a spectrum array between 1hz and Nyquist, or in other words, 1hz and the sample rate given to FSOUND_Init divided by 2.
    - If you had a 44khz output it would produce results up to 22khz.
    -
    - To get the spectrum, use FSOUND_DSP_GetSpectrum. As the documentation for this function says, it returns a pointer to an array of 512 floating point values between 0.0 and 1.0.
    - Simply plot these values, scaling the 0 to 1 value to the height of your spectrum display, or process them for things like beat detection etc. Values above 11khz (when initialized with 44khz) become very small and are some times graphically not very interesting. The FMOD media player only plots the first 256 entries because of this. It is up to you how you interpret the data.
    - If you want a different size window beside 512 then simply interpolate, disregard or skip entries and average them to your desired range. Different window sizes for the current FFT are not planned for future releases of FMOD.
    -
    - NOTE: You can change the position of the system FFT DSP unit. It is currently positioned last in the chain of DSP units by default so that the spectrum results in feedback from everything played through the FMOD software engine. - See FSOUND_DSP_PRIORITIES for the relative system DSP unit priorities. You could move it to before the music unit and after the SFX unit for example, which would exclude mods from having its input into the spectrum graph. It would be achieved like this
    - FSOUND_DSP_SetPriority(FSOUND_DSP_GetFFTUnit(), 150); -
- - - - - -
What happens if I want to get a Spectrum but use FSOUND_FX? Aren't the 2 incompatible?.         
-
    - - It is possible but with some limitations, See this section for more information
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - + + + + + +3D Sound Tutorial - Firelight Technologies Pty, Ltd. + + + + + + + + + +
    + +
    +
    +
    +

    SPECTRUM ANALYSIS

    + + +
    + + + + + + + + +
    Introduction         
    +
      + This short section reveals how easy it is to obtain the realtime spectrum graph for FMOD's DSP output as you hear it, for graphical display or even advanced signal processing! +
    + + + + + +
    Using it         
    +
      + The spectrum analysis unit is an FMOD System DSP Unit. If you are unsure of the FMOD DSP system then see the DSP tutorial.
      + By default it is turned off because it can consume a reasonable amount of cpu time and it doesn't want to be doing Fast Fourier Transform code when the spectrum isn't even being queried!
      + To turn it on is quite simple. Just call.
      +
      + FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit, TRUE);
      +
      + To turn it off again is just as simple. Just call.
      +
      + FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), FALSE);
      +
      + When your audio is playing, this DSP unit will every 25ms, or the rate of the DSP engine, update a snapshot of the current audible spectrum.
      +
      + The range for this FFT produces a spectrum array between 1hz and Nyquist, or in other words, 1hz and the sample rate given to FSOUND_Init divided by 2.
      + If you had a 44khz output it would produce results up to 22khz.
      +
      + To get the spectrum, use FSOUND_DSP_GetSpectrum. As the documentation for this function says, it returns a pointer to an array of 512 floating point values between 0.0 and 1.0.
      + Simply plot these values, scaling the 0 to 1 value to the height of your spectrum display, or process them for things like beat detection etc. Values above 11khz (when initialized with 44khz) become very small and are some times graphically not very interesting. The FMOD media player only plots the first 256 entries because of this. It is up to you how you interpret the data.
      + If you want a different size window beside 512 then simply interpolate, disregard or skip entries and average them to your desired range. Different window sizes for the current FFT are not planned for future releases of FMOD.
      +
      + NOTE: You can change the position of the system FFT DSP unit. It is currently positioned last in the chain of DSP units by default so that the spectrum results in feedback from everything played through the FMOD software engine. + See FSOUND_DSP_PRIORITIES for the relative system DSP unit priorities. You could move it to before the music unit and after the SFX unit for example, which would exclude mods from having its input into the spectrum graph. It would be achieved like this
      + FSOUND_DSP_SetPriority(FSOUND_DSP_GetFFTUnit(), 150); +
    + + + + + +
    What happens if I want to get a Spectrum but use FSOUND_FX? Aren't the 2 incompatible?.         
    +
      + + It is possible but with some limitations, See this section for more information
      + + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/synch.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/synch.htm index bdaeca51..ba393d73 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/synch.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/synch.htm @@ -1,120 +1,120 @@ - - - - - -Synchronization Tutorial - Firelight Technologies Pty, Ltd. - - - - - - - - - -
      - -
      -
      -
      -

      MUSIC SYNCRHONIZATION

      -
      - - - - - - - -
      Introduction         
      -
        - This section will describe how to synchronize graphics with sound effectively using FMOD functions.
        - It usually involves either polling against a music value to trigger your effect, or getting a callback from FMOD.
        -
      - - - - - -
      Streams         
      -
        - The best way to synchronize a stream, such as a wav or mp3 is by using FSOUND_Stream_SetSyncCallback.
        - All you have to do is drop 'markers' into a wav editing program like SoundForge, and FMOD will automatically generate callbacks as the stream plays when the play cursor runs over the markers!.
        - The strings that you label markers with are even passed into the callback.
        - Note that only WAV files and MP3 with RIFF wrappers will work here. The markers are saved in a RIFF chunk. -
        -
        - If you don't have this luxury or want to use a format that doesn't support this feature, then the next best way to synchronize a stream is by using custom sync points. This way you can add and remove your own points that wav markers would normally generate. - See FSOUND_Stream_AddSyncPoint.
        - Add your markers manually with this and set your sync point callback with FSOUND_Stream_SetSyncCallback
        - Your callback could then look something like this but you can put what you like in the callback function.
        -
        - - signed char endcallback(FSOUND_STREAM *stream, void *buff, int len, int param)
        - {
        -
          - // end of stream callback doesn't have a 'buff' value, if it doesn't it could be a sync point.
          - if (buff)
          - { -
            - printf("\nSYNCPOINT : \"%s\"\n", buff);
            -
          - }
          -
          - return TRUE;
          -
        - }
        -
        -
        - Remember FMOD is a real-time system and the amount of time spent in a callback has to be low, or you could cause buffer underrun or stuttering.
        - -
      - - - - - -
      MODs         
      - - - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - + + + + + +Synchronization Tutorial - Firelight Technologies Pty, Ltd. + + + + + + + + + +
      + +
      +
      +
      +

      MUSIC SYNCRHONIZATION

      +
      + + + + + + + +
      Introduction         
      +
        + This section will describe how to synchronize graphics with sound effectively using FMOD functions.
        + It usually involves either polling against a music value to trigger your effect, or getting a callback from FMOD.
        +
      + + + + + +
      Streams         
      +
        + The best way to synchronize a stream, such as a wav or mp3 is by using FSOUND_Stream_SetSyncCallback.
        + All you have to do is drop 'markers' into a wav editing program like SoundForge, and FMOD will automatically generate callbacks as the stream plays when the play cursor runs over the markers!.
        + The strings that you label markers with are even passed into the callback.
        + Note that only WAV files and MP3 with RIFF wrappers will work here. The markers are saved in a RIFF chunk. +
        +
        + If you don't have this luxury or want to use a format that doesn't support this feature, then the next best way to synchronize a stream is by using custom sync points. This way you can add and remove your own points that wav markers would normally generate. + See FSOUND_Stream_AddSyncPoint.
        + Add your markers manually with this and set your sync point callback with FSOUND_Stream_SetSyncCallback
        + Your callback could then look something like this but you can put what you like in the callback function.
        +
        + + signed char endcallback(FSOUND_STREAM *stream, void *buff, int len, int param)
        + {
        +
          + // end of stream callback doesn't have a 'buff' value, if it doesn't it could be a sync point.
          + if (buff)
          + { +
            + printf("\nSYNCPOINT : \"%s\"\n", buff);
            +
          + }
          +
          + return TRUE;
          +
        + }
        +
        +
        + Remember FMOD is a real-time system and the amount of time spent in a callback has to be low, or you could cause buffer underrun or stuttering.
        + +
      + + + + + +
      MODs         
      + + + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/trouble.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/trouble.htm index f369d23c..75c7d158 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/trouble.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/trouble.htm @@ -1,138 +1,138 @@ - - - - - -TroubleShooting - Firelight Technologies Pty, Ltd. - - - - - - - - - -
      - -
      -
      -
      -

      TROUBLESHOOTING

      -
      - - - - - - - - -
      Introduction         
      -
        - This will cover some of the most common problems people come across when using FMOD. Remember if you have any problems just send a mail to support@fmod.org -
      - - - - - -
      FSOUND_Init fails on CE devices         
      -
        - This sometimes happens if the sound device is already busy, and the sound hardware will not release itself to FMOD until it finishes playing a sound.
        - This can happen when activesync starts up and plays the connection noise just as FMOD is trying to initialize.
        - To remedy this just initialize fmod in a loop until it succeeds, sleeping every 10 or 100ms or however long you prefer.
        - It is a good idea to timeout if it never succeeds then resolve the issue through checking the error code or stopping the program that is stealing the resource.
        - ie.
        -
        - int retrycount = 0;
        - while (!FSOUND_Init(22050, 32, FSOUND_INIT_GLOBALFOCUS) && retrycount < 10)
        - {
          - Sleep(100);
          - retrycount++;
        - }
        -
        - if (retrycount == 10)
        - {
          - /* Print error */
        - }
        -
        -
        - In this example it will keep retrying for about 1 second until it exits and prints an error message.
        - -
      - - - - - -
      Stuttering/Skipping sound         
      -
        - More commonly known as buffer underrun/overrun, this can be 1 or a combination of factors
        -
        - Bad soundcard drivers
        - This may be solved by upgrading your soundcard drivers. (Note it is recommended you get the latest drivers anyway)
        -
        - CPU issues
        - Machine to slow, or whatever your are trying to do with FMOD is too cpu intensive! (ie playing 100 mp3's at once will most likely bring FMOD to its knees, or maybe a user stream callback or DSP callback is spending too much time executing).
        -
        - Mixer buffersize is set too small
        - You can increase stability to combat these issues, by increasing FMOD's internal mixing buffer size. This will lead to greater stability but also larger latency on issuing commands to hearing the result.
        - Call FSOUND_SetBufferSize to alter this value (in milliseconds). It must only be called before calling FSOUND_Init, it will fail otherwise.
        - Please don't set this value to huge numbers like 2000 or 10000. It won't help increase stability and will consume larger amounts of CPU time and RAM.
        - First try a value of 100, then 150, then 200, and no more.
        -
        - Stream buffersize is set too small
        - If you are using the stream API, you might be streaming off a slow media, such as CDROM or over network, or even a fragmented harddisk, and fmod needs more time to fill its streaming backbuffer.
        - For streaming buffers, fmod defaults to a 400ms stream buffersize. This is seperate to the mixer buffersize described above and not related.
        - Changing this value does not alter latency. Streams are pre-buffered and always start instantly no matter what the buffersize.
        - Call FSOUND_Stream_SetBufferSize to alter this value (in milliseconds). It must only be before opening a stream to take effect.
        - Setting this value to large values will cause larger cpu spikes (if a compressed format) and more memory usage.
        - Values around 1000 to 2000 max are recommended. Larger values are not.
        -
        - Video Card Drivers
        - Yes video card drivers can affect sound output.
        - Always make sure you have the latest 3d/videocard drivers, and that your users are aware of this as well.
        - It has been noted that a bad VIDEO card driver can cause break ups and instability in sound output, as they are badly written and cause the bus to be taken over by the video card, not letting any sound data to be transferred to the soundcard.
        - This has been noted on S3 Virge and Voodoo 1 drivers so far, so always remember first to have the LATEST video driver, and make sure you note this in your documentation as well upon distribution.
        -
        - Frame-rate is too high!
        - Yes this can also affect the sound output, for the same reasons as described above. Excessive calls of the video driver can force the sound driver to not be serviced. It has been found that introducing a frame-rate limiter will solve this problem.
        -
        - Output type
        - FSOUND_OUTPUT_DSOUND will provide more solid output than FSOUND_OUTPUT_WINMM in anything except NT.
        - This is a problem with Windows Multimedia Services not being as realtime as it should be.
        - Under NT FSOUND_OUTPUT_WINMM is more stable, as DirectSound in NT is just emulated by using WINMM itself and is actually slower and has longer latency!.
        - NOTE: Please don't feel the need to use FSOUND_SetOutput if you don't need to. FMOD autodetects the best output mode based on the operating system. -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - + + + + + +TroubleShooting - Firelight Technologies Pty, Ltd. + + + + + + + + + +
      + +
      +
      +
      +

      TROUBLESHOOTING

      +
      + + + + + + + + +
      Introduction         
      +
        + This will cover some of the most common problems people come across when using FMOD. Remember if you have any problems just send a mail to support@fmod.org +
      + + + + + +
      FSOUND_Init fails on CE devices         
      +
        + This sometimes happens if the sound device is already busy, and the sound hardware will not release itself to FMOD until it finishes playing a sound.
        + This can happen when activesync starts up and plays the connection noise just as FMOD is trying to initialize.
        + To remedy this just initialize fmod in a loop until it succeeds, sleeping every 10 or 100ms or however long you prefer.
        + It is a good idea to timeout if it never succeeds then resolve the issue through checking the error code or stopping the program that is stealing the resource.
        + ie.
        +
        + int retrycount = 0;
        + while (!FSOUND_Init(22050, 32, FSOUND_INIT_GLOBALFOCUS) && retrycount < 10)
        + {
          + Sleep(100);
          + retrycount++;
        + }
        +
        + if (retrycount == 10)
        + {
          + /* Print error */
        + }
        +
        +
        + In this example it will keep retrying for about 1 second until it exits and prints an error message.
        + +
      + + + + + +
      Stuttering/Skipping sound         
      +
        + More commonly known as buffer underrun/overrun, this can be 1 or a combination of factors
        +
        + Bad soundcard drivers
        + This may be solved by upgrading your soundcard drivers. (Note it is recommended you get the latest drivers anyway)
        +
        + CPU issues
        + Machine to slow, or whatever your are trying to do with FMOD is too cpu intensive! (ie playing 100 mp3's at once will most likely bring FMOD to its knees, or maybe a user stream callback or DSP callback is spending too much time executing).
        +
        + Mixer buffersize is set too small
        + You can increase stability to combat these issues, by increasing FMOD's internal mixing buffer size. This will lead to greater stability but also larger latency on issuing commands to hearing the result.
        + Call FSOUND_SetBufferSize to alter this value (in milliseconds). It must only be called before calling FSOUND_Init, it will fail otherwise.
        + Please don't set this value to huge numbers like 2000 or 10000. It won't help increase stability and will consume larger amounts of CPU time and RAM.
        + First try a value of 100, then 150, then 200, and no more.
        +
        + Stream buffersize is set too small
        + If you are using the stream API, you might be streaming off a slow media, such as CDROM or over network, or even a fragmented harddisk, and fmod needs more time to fill its streaming backbuffer.
        + For streaming buffers, fmod defaults to a 400ms stream buffersize. This is seperate to the mixer buffersize described above and not related.
        + Changing this value does not alter latency. Streams are pre-buffered and always start instantly no matter what the buffersize.
        + Call FSOUND_Stream_SetBufferSize to alter this value (in milliseconds). It must only be before opening a stream to take effect.
        + Setting this value to large values will cause larger cpu spikes (if a compressed format) and more memory usage.
        + Values around 1000 to 2000 max are recommended. Larger values are not.
        +
        + Video Card Drivers
        + Yes video card drivers can affect sound output.
        + Always make sure you have the latest 3d/videocard drivers, and that your users are aware of this as well.
        + It has been noted that a bad VIDEO card driver can cause break ups and instability in sound output, as they are badly written and cause the bus to be taken over by the video card, not letting any sound data to be transferred to the soundcard.
        + This has been noted on S3 Virge and Voodoo 1 drivers so far, so always remember first to have the LATEST video driver, and make sure you note this in your documentation as well upon distribution.
        +
        + Frame-rate is too high!
        + Yes this can also affect the sound output, for the same reasons as described above. Excessive calls of the video driver can force the sound driver to not be serviced. It has been found that introducing a frame-rate limiter will solve this problem.
        +
        + Output type
        + FSOUND_OUTPUT_DSOUND will provide more solid output than FSOUND_OUTPUT_WINMM in anything except NT.
        + This is a problem with Windows Multimedia Services not being as realtime as it should be.
        + Under NT FSOUND_OUTPUT_WINMM is more stable, as DirectSound in NT is just emulated by using WINMM itself and is actually slower and has longer latency!.
        + NOTE: Please don't feel the need to use FSOUND_SetOutput if you don't need to. FMOD autodetects the best output mode based on the operating system. +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/Tutorials/xbox.htm b/main/source/includes/fmodapi375linux/documentation/Tutorials/xbox.htm index cb1fc4ae..a6281f3c 100644 --- a/main/source/includes/fmodapi375linux/documentation/Tutorials/xbox.htm +++ b/main/source/includes/fmodapi375linux/documentation/Tutorials/xbox.htm @@ -1,158 +1,158 @@ - - - - - -XBox - Firelight Technologies Pty, Ltd. - - - - - - - - - -
      - -
      -
      -
      -

      XBOX SPECIFIC ISSUES / FEATURES

      -
      - - - - - - - - -
      Introduction         
      -
        - This section describes how to get started with FMOD for XBox, and also some of the XBox specific features available.
        -
      - - - - -
      Getting Started         
      -
        - This section describes what you will need to link, and what you need to call to get up and running for XBox specifically.
        -
        - FMOD comes with 2 libraries. One is release and one is debug. The main difference is that the debug version outputs debug information to the debug window of your debugger.
        - This is useful for tracing what fmod is doing if something ever went wrong and you wanted to know where FMOD was at the time.
        -
        -
      • /api/lib/fmodxbox.lib - This is the library you will link to most of the time. Use this for shipping. -
      • /api/lib/fmodxboxD.lib - This is debug version of FMOD. It is slower, and prints out a log of FMOD progress through the debug window, along with english explanations on errors if they occur.
        -
        -
      - - - - -
      Memory Management         
      -
        - On FMOD XBox, you must call FSOUND_SetMemorySystem, and supply a pool of memory with a length.
        -
        - for example.
        -
        - - #define AUDIO_MEMLENGTH (4*1024*1024)
        - char *mem = malloc(AUDIO_MEMLENGTH);
        - FSOUND_SetMemorySystem(mem, AUDIO_MEMLENGTH, NULL, NULL, NULL);
        -
        -
        - then,
        -
        - - FSOUND_Init(....);
        -
        - etc.
        -
        - The reasoning for this is for performance issues.
        - FMOD must be able to access sample data within its own memory block to avoid a slowdown issue in DirectSound XBox.
        -
        - The memory provided must be enough to store all samples and extra system memory overhead for FMOD.
        -
        - You can call FSOUND_GetMemoryStats to determine what FMOD needs as a game runs.
        - You could run FMOD and supply it with an unrealistically high memory pool (say 8 megabytes), and then call FSOUND_GetMemoryStats to determine the maximum amount of RAM fmod needs to store sounds and for FMOD system overhead.
        -
        -
        - 8mb Memory Limitation.
        -
        - Currently for hardware sound effects, there is an 8mb limit for sound effects.
        - This is due to the XBox DirectSound architecture.
        -
        - From the XDK Documentation : "DirectSound buffers are managed in a scatter gather entry (SGE) list.
        - There is a maximum of 2,047 SGEs, which each point to a 4-KB page.
        - This means that a maximum of 8 MB are available for allocating or playing DirectSound buffers simultaneously"

        -
        - Future versions may have multiple 8mb pools if it is required by developers.
        -
        -
      - - - - -
      Special features for FMOD XBox         
      -
        - FMOD is fully functional on the XBox, including wma, mp3 and ogg vorbis streaming support, and with some extra functionality to take advantage of the 5.1 Dolby Digital surround sound support.
        -
        - FSOUND_SetLevels. (See fmodxbox.h).
        - This function allows you put position a sound in any of the 5.1 speaker array in dolby digital. This can be very useful, and you can even do cool things like 5.1 music with it. For example, use FSBank to produce a 6 channel, multichannel interleaved stream, then use FSOUND_GetSubChannel to position all 5 channels into their own speaker.
        - ie
        -
        - - channel = FSOUND_Stream_PlayEx(FSOUND_FREE, stream, 0, TRUE);
        - FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 0), 255, 0, 0, 0, 0, 0);
        - FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 1), 0, 255, 0, 0, 0, 0);
        - FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 2), 0, 0, 255, 0, 0, 0);
        - FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 3), 0, 0, 0, 255, 0, 0);
        - FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 4), 0, 0, 0, 0, 255, 0);
        - FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 5), 0, 0, 0, 0, 0, 255);
        - FSOUND_SetPaused(channel, FALSE);
        -
        -
        -
        - A musician would have to product 6 wav files for each speaker in this case before it is interleaved with FSBank into one stream.
        -
        - Even if you dont go to this extent, you can do something simple like spatialize normal stereo music. Normally music is just played through the front 2 channels, so you can improve this with something like
        -
        - - FSOUND_SetLevels(musicchannel, 255, 255, 255, 128, 128, 255);
        -
        -
        - which puts it in all speakers and half volume in the rears.
        - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - + + + + + +XBox - Firelight Technologies Pty, Ltd. + + + + + + + + + +
      + +
      +
      +
      +

      XBOX SPECIFIC ISSUES / FEATURES

      +
      + + + + + + + + +
      Introduction         
      +
        + This section describes how to get started with FMOD for XBox, and also some of the XBox specific features available.
        +
      + + + + +
      Getting Started         
      +
        + This section describes what you will need to link, and what you need to call to get up and running for XBox specifically.
        +
        + FMOD comes with 2 libraries. One is release and one is debug. The main difference is that the debug version outputs debug information to the debug window of your debugger.
        + This is useful for tracing what fmod is doing if something ever went wrong and you wanted to know where FMOD was at the time.
        +
        +
      • /api/lib/fmodxbox.lib - This is the library you will link to most of the time. Use this for shipping. +
      • /api/lib/fmodxboxD.lib - This is debug version of FMOD. It is slower, and prints out a log of FMOD progress through the debug window, along with english explanations on errors if they occur.
        +
        +
      + + + + +
      Memory Management         
      +
        + On FMOD XBox, you must call FSOUND_SetMemorySystem, and supply a pool of memory with a length.
        +
        + for example.
        +
        + + #define AUDIO_MEMLENGTH (4*1024*1024)
        + char *mem = malloc(AUDIO_MEMLENGTH);
        + FSOUND_SetMemorySystem(mem, AUDIO_MEMLENGTH, NULL, NULL, NULL);
        +
        +
        + then,
        +
        + + FSOUND_Init(....);
        +
        + etc.
        +
        + The reasoning for this is for performance issues.
        + FMOD must be able to access sample data within its own memory block to avoid a slowdown issue in DirectSound XBox.
        +
        + The memory provided must be enough to store all samples and extra system memory overhead for FMOD.
        +
        + You can call FSOUND_GetMemoryStats to determine what FMOD needs as a game runs.
        + You could run FMOD and supply it with an unrealistically high memory pool (say 8 megabytes), and then call FSOUND_GetMemoryStats to determine the maximum amount of RAM fmod needs to store sounds and for FMOD system overhead.
        +
        +
        + 8mb Memory Limitation.
        +
        + Currently for hardware sound effects, there is an 8mb limit for sound effects.
        + This is due to the XBox DirectSound architecture.
        +
        + From the XDK Documentation : "DirectSound buffers are managed in a scatter gather entry (SGE) list.
        + There is a maximum of 2,047 SGEs, which each point to a 4-KB page.
        + This means that a maximum of 8 MB are available for allocating or playing DirectSound buffers simultaneously"

        +
        + Future versions may have multiple 8mb pools if it is required by developers.
        +
        +
      + + + + +
      Special features for FMOD XBox         
      +
        + FMOD is fully functional on the XBox, including wma, mp3 and ogg vorbis streaming support, and with some extra functionality to take advantage of the 5.1 Dolby Digital surround sound support.
        +
        + FSOUND_SetLevels. (See fmodxbox.h).
        + This function allows you put position a sound in any of the 5.1 speaker array in dolby digital. This can be very useful, and you can even do cool things like 5.1 music with it. For example, use FSBank to produce a 6 channel, multichannel interleaved stream, then use FSOUND_GetSubChannel to position all 5 channels into their own speaker.
        + ie
        +
        + + channel = FSOUND_Stream_PlayEx(FSOUND_FREE, stream, 0, TRUE);
        + FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 0), 255, 0, 0, 0, 0, 0);
        + FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 1), 0, 255, 0, 0, 0, 0);
        + FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 2), 0, 0, 255, 0, 0, 0);
        + FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 3), 0, 0, 0, 255, 0, 0);
        + FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 4), 0, 0, 0, 0, 255, 0);
        + FSOUND_SetLevels(FSOUND_GetSubChannel(channel, 5), 0, 0, 0, 0, 0, 255);
        + FSOUND_SetPaused(channel, FALSE);
        +
        +
        +
        + A musician would have to product 6 wav files for each speaker in this case before it is interleaved with FSBank into one stream.
        +
        + Even if you dont go to this extent, you can do something simple like spatialize normal stereo music. Normally music is just played through the front 2 channels, so you can improve this with something like
        +
        + + FSOUND_SetLevels(musicchannel, 255, 255, 255, 128, 128, 255);
        +
        +
        + which puts it in all speakers and half volume in the rears.
        + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/main/source/includes/fmodapi375linux/documentation/index.html b/main/source/includes/fmodapi375linux/documentation/index.html index 9731413f..755d9a56 100644 --- a/main/source/includes/fmodapi375linux/documentation/index.html +++ b/main/source/includes/fmodapi375linux/documentation/index.html @@ -1,11 +1,11 @@ - - - - -FMOD - - - - - - + + + + +FMOD + + + + + + diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/Makefile.am b/main/source/includes/libcurl-7.50-nossl/include/curl/Makefile.am new file mode 100644 index 00000000..7c924fcb --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/Makefile.am @@ -0,0 +1,53 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +pkginclude_HEADERS = \ + curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \ + typecheck-gcc.h curlbuild.h curlrules.h + +pkgincludedir= $(includedir)/curl + +# curlbuild.h does not exist in the git tree. When the original libcurl +# source code distribution archive file is created, curlbuild.h.dist is +# renamed to curlbuild.h and included in the tarball so that it can be +# used directly on non-configure systems. +# +# The distributed curlbuild.h will be overwritten on configure systems +# when the configure script runs, with one that is suitable and specific +# to the library being configured and built. +# +# curlbuild.h.in is the distributed template file from which the configure +# script creates curlbuild.h at library configuration time, overwiting the +# one included in the distribution archive. +# +# curlbuild.h.dist is not included in the source code distribution archive. + +EXTRA_DIST = curlbuild.h.in + +DISTCLEANFILES = curlbuild.h + +checksrc: + @@PERL@ $(top_srcdir)/lib/checksrc.pl -Wcurlbuild.h -D$(top_srcdir)/include/curl $(pkginclude_HEADERS) $(EXTRA_DIST) + +if CURLDEBUG +# for debug builds, we scan the sources on all regular make invokes +all-local: checksrc +endif diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curl.h b/main/source/includes/libcurl-7.50-nossl/include/curl/curl.h new file mode 100644 index 00000000..bba1e6d3 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curl.h @@ -0,0 +1,2449 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char * b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL 1 +#define CURLSSLBACKEND_BORINGSSL 1 +#define CURLSSLBACKEND_WOLFSSL 6 + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 46 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h new file mode 100644 index 00000000..ae95095f --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h @@ -0,0 +1,586 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * See file include/curl/curlbuild.h.in, run configure, and forget + * that this file exists it is only used for non-configure systems. + * But you can keep reading if you want ;-) + * + */ + +/* ================================================================ */ +/* NOTES FOR NON-CONFIGURE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * Try to keep one section per platform, compiler and architecture, + * otherwise, if an existing section is reused for a different one and + * later on the original is adjusted, probably the piggybacking one can + * be adversely changed. + * + * In order to differentiate between platforms/compilers/architectures + * use only compiler built in predefined preprocessor symbols. + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a + * 64-bit wide signed integral data type. The width of this data type + * must remain constant and independent of any possible large file + * support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a + * 32-bit wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This + * rule shall only be violated if off_t is the only 64-bit data type + * available and the size of off_t is independent of large file support + * settings. Keep your build on the safe side avoiding an off_t gating. + * If you have a 64-bit off_t then take for sure that another 64-bit + * data type exists, dig deeper and you will find it. + * + * NOTE 3: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.dist or + * at file include/curl/curlbuild.h, this is due to the following reason: + * file include/curl/curlbuild.h.dist is renamed to include/curl/curlbuild.h + * when the libcurl source code distribution archive file is created. + * + * File include/curl/curlbuild.h.dist is not included in the distribution + * archive. File include/curl/curlbuild.h is not present in the git tree. + * + * The distributed include/curl/curlbuild.h file is only intended to be used + * on systems which can not run the also distributed configure script. + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + * If you check out from git on a non-configure platform, you must run the + * appropriate buildconf* script to set up curlbuild.h and other local files. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */ +/* ================================================================ */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SALFORDC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__TURBOC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__LCC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MWERKS__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(_WIN32_WCE) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MINGW32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) +# if !defined(__LP64__) && (defined(__ILP32__) || \ + defined(__i386__) || defined(__ppc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__)) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +# error "Unknown non-configure build target!" + Error Compilation_aborted_Unknown_non_configure_build_target +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +#endif /* __CURL_CURLBUILD_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.cmake b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.cmake new file mode 100644 index 00000000..bbb31a94 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.cmake @@ -0,0 +1,197 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +#cmakedefine CURL_PULL_WS2TCPIP_H +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_TYPES_H +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +#cmakedefine CURL_PULL_STDINT_H +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +#cmakedefine CURL_PULL_INTTYPES_H +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_SOCKET_H +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_POLL_H +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CURL_SIZEOF_LONG ${CURL_SIZEOF_LONG} + +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T ${CURL_TYPEOF_CURL_SOCKLEN_T} + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_SOCKLEN_T ${CURL_SIZEOF_CURL_SOCKLEN_T} + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#define CURL_TYPEOF_CURL_OFF_T ${CURL_TYPEOF_CURL_OFF_T} + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_T "${CURL_FORMAT_CURL_OFF_T}" + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_TU "${CURL_FORMAT_CURL_OFF_TU}" + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#define CURL_FORMAT_OFF_T "${CURL_FORMAT_OFF_T}" + +/* The size of `curl_off_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_OFF_T ${CURL_SIZEOF_CURL_OFF_T} + +/* curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_T ${CURL_SUFFIX_CURL_OFF_T} + +/* unsigned curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_TU ${CURL_SUFFIX_CURL_OFF_TU} + +#endif /* __CURL_CURLBUILD_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.dist b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.dist new file mode 100644 index 00000000..ae95095f --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.dist @@ -0,0 +1,586 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * See file include/curl/curlbuild.h.in, run configure, and forget + * that this file exists it is only used for non-configure systems. + * But you can keep reading if you want ;-) + * + */ + +/* ================================================================ */ +/* NOTES FOR NON-CONFIGURE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * Try to keep one section per platform, compiler and architecture, + * otherwise, if an existing section is reused for a different one and + * later on the original is adjusted, probably the piggybacking one can + * be adversely changed. + * + * In order to differentiate between platforms/compilers/architectures + * use only compiler built in predefined preprocessor symbols. + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a + * 64-bit wide signed integral data type. The width of this data type + * must remain constant and independent of any possible large file + * support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a + * 32-bit wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This + * rule shall only be violated if off_t is the only 64-bit data type + * available and the size of off_t is independent of large file support + * settings. Keep your build on the safe side avoiding an off_t gating. + * If you have a 64-bit off_t then take for sure that another 64-bit + * data type exists, dig deeper and you will find it. + * + * NOTE 3: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.dist or + * at file include/curl/curlbuild.h, this is due to the following reason: + * file include/curl/curlbuild.h.dist is renamed to include/curl/curlbuild.h + * when the libcurl source code distribution archive file is created. + * + * File include/curl/curlbuild.h.dist is not included in the distribution + * archive. File include/curl/curlbuild.h is not present in the git tree. + * + * The distributed include/curl/curlbuild.h file is only intended to be used + * on systems which can not run the also distributed configure script. + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + * If you check out from git on a non-configure platform, you must run the + * appropriate buildconf* script to set up curlbuild.h and other local files. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */ +/* ================================================================ */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SALFORDC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__TURBOC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__LCC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MWERKS__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(_WIN32_WCE) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MINGW32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) +# if !defined(__LP64__) && (defined(__ILP32__) || \ + defined(__i386__) || defined(__ppc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__)) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +# error "Unknown non-configure build target!" + Error Compilation_aborted_Unknown_non_configure_build_target +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +#endif /* __CURL_CURLBUILD_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.in b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.in new file mode 100644 index 00000000..ffab3567 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curlbuild.h.in @@ -0,0 +1,197 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +#undef CURL_PULL_WS2TCPIP_H +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#undef CURL_PULL_SYS_TYPES_H +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +#undef CURL_PULL_STDINT_H +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +#undef CURL_PULL_INTTYPES_H +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#undef CURL_PULL_SYS_SOCKET_H +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +#undef CURL_PULL_SYS_POLL_H +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#undef CURL_SIZEOF_LONG + +/* Integral data type used for curl_socklen_t. */ +#undef CURL_TYPEOF_CURL_SOCKLEN_T + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#undef CURL_SIZEOF_CURL_SOCKLEN_T + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#undef CURL_TYPEOF_CURL_OFF_T + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#undef CURL_FORMAT_CURL_OFF_T + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#undef CURL_FORMAT_CURL_OFF_TU + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#undef CURL_FORMAT_OFF_T + +/* The size of `curl_off_t', as computed by sizeof. */ +#undef CURL_SIZEOF_CURL_OFF_T + +/* curl_off_t constant suffix. */ +#undef CURL_SUFFIX_CURL_OFF_T + +/* unsigned curl_off_t constant suffix. */ +#undef CURL_SUFFIX_CURL_OFF_TU + +#endif /* __CURL_CURLBUILD_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curlrules.h b/main/source/includes/libcurl-7.50-nossl/include/curl/curlrules.h new file mode 100644 index 00000000..55d21f68 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curlrules.h @@ -0,0 +1,262 @@ +#ifndef __CURL_CURLRULES_H +#define __CURL_CURLRULES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by curl/curl.h when an application is + * being built using an already built libcurl library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the curlbuild.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the libcurl development mailing list: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built libcurl library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +#endif + +#ifndef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __curl_rule_01__ + [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * curl_off_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_02__ + [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; + +/* + * Verify at compile time that the size of curl_off_t as reported + * by sizeof() is greater or equal than the one reported for long + * for the current compilation. + */ + +typedef char + __curl_rule_03__ + [CurlchkszGE(curl_off_t, long)]; + +/* + * Verify that the size previously defined and expected for + * curl_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_04__ + [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of curl_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __curl_rule_05__ + [CurlchkszGE(curl_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +/* + * Get rid of macros private to this header file. + */ + +#undef CurlchkszEQ +#undef CurlchkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CURL_PULL_WS2TCPIP_H +#undef CURL_PULL_SYS_TYPES_H +#undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H +#undef CURL_PULL_STDINT_H +#undef CURL_PULL_INTTYPES_H + +#undef CURL_TYPEOF_CURL_SOCKLEN_T +#undef CURL_TYPEOF_CURL_OFF_T + +#ifdef CURL_NO_OLDIES +#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ +#endif + +#endif /* __CURL_CURLRULES_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/curlver.h b/main/source/includes/libcurl-7.50-nossl/include/curl/curlver.h new file mode 100644 index 00000000..9eaae719 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.50.2-DEV" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 50 +#define LIBCURL_VERSION_PATCH 2 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x073202 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "DEV" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/easy.h b/main/source/includes/libcurl-7.50-nossl/include/curl/easy.h new file mode 100644 index 00000000..afc766cd --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/mprintf.h b/main/source/includes/libcurl-7.50-nossl/include/curl/mprintf.h new file mode 100644 index 00000000..e20f546e --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/mprintf.h @@ -0,0 +1,50 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/multi.h b/main/source/includes/libcurl-7.50-nossl/include/curl/multi.h new file mode 100644 index 00000000..d1e00cc5 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/multi.h @@ -0,0 +1,439 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/stdcheaders.h b/main/source/includes/libcurl-7.50-nossl/include/curl/stdcheaders.h new file mode 100644 index 00000000..6f0f7f34 --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/include/curl/typecheck-gcc.h b/main/source/includes/libcurl-7.50-nossl/include/curl/typecheck-gcc.h new file mode 100644 index 00000000..6ec8bcfd --- /dev/null +++ b/main/source/includes/libcurl-7.50-nossl/include/curl/typecheck-gcc.h @@ -0,0 +1,622 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__ (option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__ (info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string (char* or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a FILE* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a void* or char* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a struct curl_httppost* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a struct curl_slist* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to char * for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to struct curl_slist * for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (CURLINFO_SLIST < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void*)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *)) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func), type*)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*); +typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*); +typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/main/source/includes/libcurl-7.50-nossl/libcurl_a.lib b/main/source/includes/libcurl-7.50-nossl/libcurl_a.lib new file mode 100644 index 00000000..edfe89ea Binary files /dev/null and b/main/source/includes/libcurl-7.50-nossl/libcurl_a.lib differ diff --git a/main/source/includes/lpng1251/ANNOUNCE b/main/source/includes/lpng1251/ANNOUNCE index b13dff2c..f7d49359 100644 --- a/main/source/includes/lpng1251/ANNOUNCE +++ b/main/source/includes/lpng1251/ANNOUNCE @@ -1,71 +1,71 @@ - -Libpng 1.2.51 - February 6, 2014 - -This is a public release of libpng, intended for use in production codes. - -Files available for download: - -Source files with LF line endings (for Unix/Linux) and with a -"configure" script - - libpng-1.2.51.tar.xz (LZMA-compressed, recommended) - libpng-1.2.51.tar.gz - libpng-1.2.51.tar.bz2 - -Source files with LF line endings (for Unix/Linux) without the -"configure" script - - libpng-1.2.51-no-config.tar.xz (LZMA-compressed, recommended) - libpng-1.2.51-no-config.tar.gz - libpng-1.2.51-no-config.tar.bz2 - -Source files with CRLF line endings (for Windows), without the -"configure" script - - lpng1251.zip - lpng1251.7z - lpng1251.tar.bz2 - -Project files - - libpng-1.2.51-project-netware.zip - libpng-1.2.51-project-wince.zip - -Other information: - - libpng-1.2.51-README.txt - libpng-1.2.51-KNOWNBUGS.txt - libpng-1.2.51-LICENSE.txt - libpng-1.2.51-Y2K-compliance.txt - libpng-1.2.51-[previous version]-diff.txt - -Changes since the last public release (1.2.50): - -version 1.2.51 [February 6, 2014] - -version 1.0.61 and 1.2.51 [February 6, 2014] - Ignore, with a warning, out-of-range value of num_trans in png_set_tRNS(). - Replaced AM_CONFIG_HEADER(config.h) with AC_CONFIG_HEADERS([config.h]) - in configure.ac - Changed default value of PNG_USER_CACHE_MAX from 0 to 32767 in pngconf.h. - Avoid a possible memory leak in contrib/gregbook/readpng.c - Revised libpng.3 so that "doclifter" can process it. - Changed '"%s"m' to '"%s" m' in png_debug macros to improve portability - among compilers. - Rebuilt the configure scripts with autoconf-2.69 and automake-1.14.1 - Removed potentially misleading warning from png_check_IHDR(). - Quiet set-but-not-used warnings in pngset.c - Quiet an uninitialized memory warning from VC2013 in png_get_png(). - Quiet unused variable warnings from clang by porting PNG_UNUSED() from - libpng-1.4.6. - Added -DZ_SOLO to CFLAGS in contrib/pngminim/*/makefile - Added an #ifdef PNG_FIXED_POINT_SUPPORTED/#endif in pngset.c - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) -or to glennrp at users.sourceforge.net - -Glenn R-P -#endif + +Libpng 1.2.51 - February 6, 2014 + +This is a public release of libpng, intended for use in production codes. + +Files available for download: + +Source files with LF line endings (for Unix/Linux) and with a +"configure" script + + libpng-1.2.51.tar.xz (LZMA-compressed, recommended) + libpng-1.2.51.tar.gz + libpng-1.2.51.tar.bz2 + +Source files with LF line endings (for Unix/Linux) without the +"configure" script + + libpng-1.2.51-no-config.tar.xz (LZMA-compressed, recommended) + libpng-1.2.51-no-config.tar.gz + libpng-1.2.51-no-config.tar.bz2 + +Source files with CRLF line endings (for Windows), without the +"configure" script + + lpng1251.zip + lpng1251.7z + lpng1251.tar.bz2 + +Project files + + libpng-1.2.51-project-netware.zip + libpng-1.2.51-project-wince.zip + +Other information: + + libpng-1.2.51-README.txt + libpng-1.2.51-KNOWNBUGS.txt + libpng-1.2.51-LICENSE.txt + libpng-1.2.51-Y2K-compliance.txt + libpng-1.2.51-[previous version]-diff.txt + +Changes since the last public release (1.2.50): + +version 1.2.51 [February 6, 2014] + +version 1.0.61 and 1.2.51 [February 6, 2014] + Ignore, with a warning, out-of-range value of num_trans in png_set_tRNS(). + Replaced AM_CONFIG_HEADER(config.h) with AC_CONFIG_HEADERS([config.h]) + in configure.ac + Changed default value of PNG_USER_CACHE_MAX from 0 to 32767 in pngconf.h. + Avoid a possible memory leak in contrib/gregbook/readpng.c + Revised libpng.3 so that "doclifter" can process it. + Changed '"%s"m' to '"%s" m' in png_debug macros to improve portability + among compilers. + Rebuilt the configure scripts with autoconf-2.69 and automake-1.14.1 + Removed potentially misleading warning from png_check_IHDR(). + Quiet set-but-not-used warnings in pngset.c + Quiet an uninitialized memory warning from VC2013 in png_get_png(). + Quiet unused variable warnings from clang by porting PNG_UNUSED() from + libpng-1.4.6. + Added -DZ_SOLO to CFLAGS in contrib/pngminim/*/makefile + Added an #ifdef PNG_FIXED_POINT_SUPPORTED/#endif in pngset.c + +Send comments/corrections/commendations to png-mng-implement at lists.sf.net +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) +or to glennrp at users.sourceforge.net + +Glenn R-P +#endif diff --git a/main/source/includes/lpng1251/CHANGES b/main/source/includes/lpng1251/CHANGES index 3b7a6cf2..7bd5e630 100644 --- a/main/source/includes/lpng1251/CHANGES +++ b/main/source/includes/lpng1251/CHANGES @@ -1,2824 +1,2824 @@ -#if 0 -CHANGES - changes for libpng - -version 0.2 - added reader into png.h - fixed small problems in stub file - -version 0.3 - added pull reader - split up pngwrite.c to several files - added pnglib.txt - added example.c - cleaned up writer, adding a few new transformations - fixed some bugs in writer - interfaced with zlib 0.5 - added K&R support - added check for 64 KB blocks for 16 bit machines - -version 0.4 - cleaned up code and commented code - simplified time handling into png_time - created png_color_16 and png_color_8 to handle color needs - cleaned up color type defines - fixed various bugs - made various names more consistent - interfaced with zlib 0.71 - cleaned up zTXt reader and writer (using zlib's Reset functions) - split transformations into pngrtran.c and pngwtran.c - -version 0.5 - interfaced with zlib 0.8 - fixed many reading and writing bugs - saved using 3 spaces instead of tabs - -version 0.6 - added png_large_malloc() and png_large_free() - added png_size_t - cleaned up some compiler warnings - added png_start_read_image() - -version 0.7 - cleaned up lots of bugs - finished dithering and other stuff - added test program - changed name from pnglib to libpng - -version 0.71 [June, 1995] - changed pngtest.png for zlib 0.93 - fixed error in libpng.txt and example.c - -version 0.8 - cleaned up some bugs - added png_set_filler() - split up pngstub.c into pngmem.c, pngio.c, and pngerror.c - added #define's to remove unwanted code - moved png_info_init() to png.c - added old_size into png_realloc() - added functions to manually set filtering and compression info - changed compression parameters based on image type - optimized filter selection code - added version info - changed external functions passing floats to doubles (k&r problems?) - put all the configurable stuff in pngconf.h - enabled png_set_shift to work with paletted images on read - added png_read_update_info() - updates info structure with - transformations - -version 0.81 [August, 1995] - incorporated Tim Wegner's medium model code (thanks, Tim) - -version 0.82 [September, 1995] - [unspecified changes] - -version 0.85 [December, 1995] - added more medium model code (almost everything's a far) - added i/o, error, and memory callback functions - fixed some bugs (16 bit, 4 bit interlaced, etc.) - added first run progressive reader (barely tested) - -version 0.86 [January, 1996] - fixed bugs - improved documentation - -version 0.87 [January, 1996] - fixed medium model bugs - fixed other bugs introduced in 0.85 and 0.86 - added some minor documentation - -version 0.88 [January, 1996] - fixed progressive bugs - replaced tabs with spaces - cleaned up documentation - added callbacks for read/write and warning/error functions - -version 0.89 [July, 1996] - added new initialization API to make libpng work better with shared libs - we now have png_create_read_struct(), png_create_write_struct(), - png_create_info_struct(), png_destroy_read_struct(), and - png_destroy_write_struct() instead of the separate calls to - malloc and png_read_init(), png_info_init(), and png_write_init() - changed warning/error callback functions to fix bug - this means you - should use the new initialization API if you were using the old - png_set_message_fn() calls, and that the old API no longer exists - so that people are aware that they need to change their code - changed filter selection API to allow selection of multiple filters - since it didn't work in previous versions of libpng anyways - optimized filter selection code - fixed png_set_background() to allow using an arbitrary RGB color for - paletted images - fixed gamma and background correction for paletted images, so - png_correct_palette is not needed unless you are correcting an - external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED - in pngconf.h) - if nobody uses this, it may disappear in the future. - fixed bug with Borland 64K memory allocation (Alexander Lehmann) - fixed bug in interlace handling (Smarasderagd, I think) - added more error checking for writing and image to reduce invalid files - separated read and write functions so that they won't both be linked - into a binary when only reading or writing functionality is used - new pngtest image also has interlacing and zTXt - updated documentation to reflect new API - -version 0.90 [January, 1997] - made CRC errors/warnings on critical and ancillary chunks configurable - libpng will use the zlib CRC routines by (compile-time) default - changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) - added external C++ wrapper statements to png.h (Gilles Dauphin) - allow PNG file to be read when some or all of file signature has already - been read from the beginning of the stream. ****This affects the size - of info_struct and invalidates all programs that use a shared libpng**** - fixed png_filler() declarations - fixed? background color conversions - fixed order of error function pointers to match documentation - current chunk name is now available in png_struct to reduce the number - of nearly identical error messages (will simplify multi-lingual - support when available) - try to get ready for unknown-chunk callback functions: - - previously read critical chunks are flagged, so the chunk handling - routines can determine if the chunk is in the right place - - all chunk handling routines have the same prototypes, so we will - be able to handle all chunks via a callback mechanism - try to fix Linux "setjmp" buffer size problems - removed png_large_malloc, png_large_free, and png_realloc functions. - -version 0.95 [March, 1997] - fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never - fixed bug in PNG file signature compares when start != 0 - changed parameter type of png_set_filler(...filler...) from png_byte - to png_uint_32 - added test for MACOS to ensure that both math.h and fp.h are not #included - added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) - added "packswap" transformation, which changes the endianness of - packed-pixel bytes (Kevin Bracey) - added "strip_alpha" transformation, which removes the alpha channel of - input images without using it (not necessarily a good idea) - added "swap_alpha" transformation, which puts the alpha channel in front - of the color bytes instead of after - removed all implicit variable tests which assume NULL == 0 (I think) - changed several variables to "png_size_t" to show 16/32-bit limitations - added new pCAL chunk read/write support - added experimental filter selection weighting (Greg Roelofs) - removed old png_set_rgbx() and png_set_xrgb() functions that have been - obsolete for about 2 years now (use png_set_filler() instead) - added macros to read 16- and 32-bit ints directly from buffer, to be - used only on those systems that support it (namely PowerPC and 680x0) - With some testing, this may become the default for MACOS/PPC systems. - only calculate CRC on data if we are going to use it - added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? - added macros for simple libpng debugging output selectable at compile time - removed PNG_READ_END_MODE in progressive reader (Smarasderagd) - more description of info_struct in libpng.txt and png.h - more instructions in example.c - more chunk types tested in pngtest.c - renamed pngrcb.c to pngset.c, and all png_read_ functions to be - png_set_. We now have corresponding png_get_ - functions in pngget.c to get information in info_ptr. This isolates - the application from the internal organization of png_info_struct - (good for shared library implementations). - -version 0.96 [May, 1997] - fixed serious bug with < 8bpp images introduced in 0.95 - fixed 256-color transparency bug (Greg Roelofs) - fixed up documentation (Greg Roelofs, Laszlo Nyul) - fixed "error" in pngconf.h for Linux setjmp() behaviour - fixed DOS medium model support (Tim Wegner) - fixed png_check_keyword() for case with error in static string text - added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) - added typecasts to quiet compiler errors - added more debugging info - -version 0.97 [January, 1998] - removed PNG_USE_OWN_CRC capability - relocated png_set_crc_action from pngrutil.c to pngrtran.c - fixed typecasts of "new_key", etc. (Andreas Dilger) - added RFC 1152 [sic] date support - fixed bug in gamma handling of 4-bit grayscale - added 2-bit grayscale gamma handling (Glenn R-P) - added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) - minor corrections in libpng.txt - added simple sRGB support (Glenn R-P) - easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; - all configurable options can be selected from command-line instead - of having to edit pngconf.h (Glenn R-P) - fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) - added more conditions for png_do_background, to avoid changing - black pixels to background when a background is supplied and - no pixels are transparent - repaired PNG_NO_STDIO behaviour - tested NODIV support and made it default behaviour (Greg Roelofs) - added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) - regularized version numbering scheme and bumped shared-library major - version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs) - -version 0.98 [January, 1998] - cleaned up some typos in libpng.txt and in code documentation - fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) - cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c - changed recommendation about file_gamma for PC images to .51 from .45, - in example.c and libpng.txt, added comments to distinguish between - screen_gamma, viewing_gamma, and display_gamma. - changed all references to RFC1152 to read RFC1123 and changed the - PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED - added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) - changed srgb_intent from png_byte to int to avoid compiler bugs - -version 0.99 [January 30, 1998] - free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) - fixed a longstanding "packswap" bug in pngtrans.c - fixed some inconsistencies in pngconf.h that prevented compiling with - PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined - fixed some typos and made other minor rearrangement of libpng.txt (Andreas) - changed recommendation about file_gamma for PC images to .50 from .51 in - example.c and libpng.txt, and changed file_gamma for sRGB images to .45 - added a number of functions to access information from the png structure - png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) - added TARGET_MACOS similar to zlib-1.0.8 - define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined - added type casting to all png_malloc() function calls -version 0.99a [January 31, 1998] - Added type casts and parentheses to all returns that return a value.(Tim W.) -version 0.99b [February 4, 1998] - Added type cast png_uint_32 on malloc function calls where needed. - Changed type of num_hist from png_uint_32 to int (same as num_palette). - Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. - Renamed makefile.elf to makefile.lnx. -version 0.99c [February 7, 1998] - More type casting. Removed erroneous overflow test in pngmem.c. - Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. - Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. -version 0.99d [February 11, 1998] - Renamed "far_to_near()" "png_far_to_near()" - Revised libpng.3 - Version 99c "buffered" operations didn't work as intended. Replaced them - with png_memcpy_check() and png_memset_check(). - Added many "if (png_ptr == NULL) return" to quell compiler warnings about - unused png_ptr, mostly in pngget.c and pngset.c. - Check for overlength tRNS chunk present when indexed-color PLTE is read. - Cleaned up spelling errors in libpng.3/libpng.txt - Corrected a problem with png_get_tRNS() which returned undefined trans array -version 0.99e [February 28, 1998] - Corrected png_get_tRNS() again. - Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". - Touched up example.c to make more of it compileable, although the entire - file still can't be compiled (Willem van Schaik) - Fixed a bug in png_do_shift() (Bryan Tsai) - Added a space in png.h prototype for png_write_chunk_start() - Replaced pngtest.png with one created with zlib 1.1.1 - Changed pngtest to report PASS even when file size is different (Jean-loup G.) - Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) -version 0.99f [March 5, 1998] - Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) - Moved makefiles into a "scripts" directory, and added INSTALL instruction file - Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) - Added pointers to "note on libpng versions" in makefile.lnx and README - Added row callback feature when reading and writing nonprogressive rows - and added a test of this feature in pngtest.c - Added user transform callbacks, with test of the feature in pngtest.c -version 0.99g [March 6, 1998, morning] - Minor changes to pngtest.c to suppress compiler warnings. - Removed "beta" language from documentation. -version 0.99h [March 6, 1998, evening] - Minor changes to previous minor changes to pngtest.c - Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED - and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro - Added user transform capability - -version 1.00 [March 7, 1998] - Changed several typedefs in pngrutil.c - Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) - replaced "while(1)" with "for(;;)" - added PNGARG() to prototypes in pngtest.c and removed some prototypes - updated some of the makefiles (Tom Lane) - changed some typedefs (s_start, etc.) in pngrutil.c - fixed dimensions of "short_months" array in pngwrite.c - Replaced ansi2knr.c with the one from jpeg-v6 - -version 1.0.0 [March 8, 1998] - Changed name from 1.00 to 1.0.0 (Adam Costello) - Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) -version 1.0.0a [March 9, 1998] - Fixed three bugs in pngrtran.c to make gamma+background handling consistent - (Greg Roelofs) - Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz - for major, minor, and bugfix releases. This is 10001. (Adam Costello, - Tom Lane) - Make months range from 1-12 in png_convert_to_rfc1123 -version 1.0.0b [March 13, 1998] - Quieted compiler complaints about two empty "for" loops in pngrutil.c - Minor changes to makefile.s2x - Removed #ifdef/#endif around a png_free() in pngread.c - -version 1.0.1 [March 14, 1998] - Changed makefile.s2x to reduce security risk of using a relative pathname - Fixed some typos in the documentation (Greg). - Fixed a problem with value of "channels" returned by png_read_update_info() -version 1.0.1a [April 21, 1998] - Optimized Paeth calculations by replacing abs() function calls with intrinsics - plus other loop optimizations. Improves avg decoding speed by about 20%. - Commented out i386istic "align" compiler flags in makefile.lnx. - Reduced the default warning level in some makefiles, to make them consistent. - Removed references to IJG and JPEG in the ansi2knr.c copyright statement. - Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. - Added grayscale and 16-bit capability to png_do_read_filler(). - Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes - too large when writing an image with bit_depth < 8 (Bob Dellaca). - Corrected some bugs in the experimental weighted filtering heuristics. - Moved a misplaced pngrutil code block that truncates tRNS if it has more - than num_palette entries -- test was done before num_palette was defined. - Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). - Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen). -version 1.0.1b [May 2, 1998] - Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). - Relocated the png_composite macros from pngrtran.c to png.h (Greg). - Added makefile.sco (contributed by Mike Hopkirk). - Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. - Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. - More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert). - More work on loop optimization which may help when compiled with C++ compilers. - Added warnings when people try to use transforms they've defined out. - Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. - Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) -version 1.0.1c [May 11, 1998] - Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for - filler bytes should have been 0xff instead of 0xf. - Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. - Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED - out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h - Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, - for consistency, in pngconf.h - Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier - to remove unwanted capabilities via the compile line - Made some corrections to grammar (which, it's) in documentation (Greg). - Corrected example.c, use of row_pointers in png_write_image(). -version 1.0.1d [May 24, 1998] - Corrected several statements that used side effects illegally in pngrutil.c - and pngtrans.c, that were introduced in version 1.0.1b - Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) - More corrections to example.c, use of row_pointers in png_write_image() - and png_read_rows(). - Added pngdll.mak and pngdef.pas to scripts directory, contributed by - Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 - Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) - Changed several loops from count-down to count-up, for consistency. -version 1.0.1e [June 6, 1998] - Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and - added warnings when people try to set png_read_fn and png_write_fn in - the same structure. - Added a test such that png_do_gamma will be done when num_trans==0 - for truecolor images that have defined a background. This corrects an - error that was introduced in libpng-0.90 that can cause gamma processing - to be skipped. - Added tests in png.h to include "trans" and "trans_values" in structures - when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. - Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() - Moved png_convert_to_rfc_1123() from pngwrite.c to png.c - Added capability for user-provided malloc_fn() and free_fn() functions, - and revised pngtest.c to demonstrate their use, replacing the - PNGTEST_DEBUG_MEM feature. - Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). - -version 1.0.2 [June 14, 1998] - Fixed two bugs in makefile.bor . -version 1.0.2a [December 30, 1998] - Replaced and extended code that was removed from png_set_filler() in 1.0.1a. - Fixed a bug in png_do_filler() that made it fail to write filler bytes in - the left-most pixel of each row (Kevin Bracey). - Changed "static pngcharp tIME_string" to "static char tIME_string[30]" - in pngtest.c (Duncan Simpson). - Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk - even when no tIME chunk was present in the source file. - Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. - Fixed a problem in png_read_push_finish_row(), which would not skip some - passes that it should skip, for images that are less than 3 pixels high. - Interchanged the order of calls to png_do_swap() and png_do_shift() - in pngwtran.c (John Cromer). - Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . - Changed "bad adaptive filter type" from error to warning in pngrutil.c . - Fixed a documentation error about default filtering with 8-bit indexed-color. - Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO - (L. Peter Deutsch). - Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. - Added png_get_copyright() and png_get_header_version() functions. - Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c - Added information about debugging in libpng.txt and libpng.3 . - Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco. - Removed lines after Dynamic Dependencies" in makefile.aco . - Revised makefile.dec to make a shared library (Jeremie Petit). - Removed trailing blanks from all files. -version 1.0.2a [January 6, 1999] - Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h - Added "if" tests to silence complaints about unused png_ptr in png.h and png.c - Changed "check_if_png" function in example.c to return true (nonzero) if PNG. - Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() - which is obsolete. - -version 1.0.3 [January 14, 1999] - Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) - Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. -version 1.0.3a [August 12, 1999] - Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning - if an attempt is made to read an interlaced image when it's not supported. - Added check if png_ptr->trans is defined before freeing it in pngread.c - Modified the Y2K statement to include versions back to version 0.71 - Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c - Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) - Replaced leading blanks with tab characters in makefile.hux - Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. - Changed (float)red and (float)green to (double)red, (double)green - in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. - Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). - Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). - Updated documentation to refer to the PNG-1.2 specification. - Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c - in makefile.knr, INSTALL, and README (L. Peter Deutsch) - Fixed bugs in calculation of the length of rowbytes when adding alpha - channels to 16-bit images, in pngrtran.c (Chris Nokleberg) - Added function png_set_user_transform_info() to store user_transform_ptr, - user_depth, and user_channels into the png_struct, and a function - png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) - Added function png_set_empty_plte_permitted() to make libpng useable - in MNG applications. - Corrected the typedef for png_free_ptr in png.h (Jesse Jones). - Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be - consistent with PNG-1.2, and allow variance of 500 before complaining. - Added assembler code contributed by Intel in file pngvcrd.c and modified - makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, Gilles Vollant) - Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. - Added some aliases for png_set_expand() in pngrtran.c, namely - png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() - (Greg Roelofs, in "PNG: The Definitive Guide"). - Added makefile.beo for BEOS on X86, contributed by Sander Stok. -version 1.0.3b [August 26, 1999] - Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h - Changed leading blanks to tabs in all makefiles. - Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. - Made alternate versions of png_set_expand() in pngrtran.c, namely - png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha - (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. - Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h - Revised calculation of num_blocks in pngmem.c to avoid a potentially - negative shift distance, whose results are undefined in the C language. - Added a check in pngset.c to prevent writing multiple tIME chunks. - Added a check in pngwrite.c to detect invalid small window_bits sizes. -version 1.0.3d [September 4, 1999] - Fixed type casting of igamma in pngrutil.c - Added new png_expand functions to scripts/pngdef.pas and pngos2.def - Added a demo read_user_transform_fn that examines the row filters in pngtest.c - -version 1.0.4 [September 24, 1999] - Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined - Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h - Made several minor corrections to pngtest.c - Renamed the makefiles with longer but more user friendly extensions. - Copied the PNG copyright and license to a separate LICENSE file. - Revised documentation, png.h, and example.c to remove reference to - "viewing_gamma" which no longer appears in the PNG specification. - Revised pngvcrd.c to use MMX code for interlacing only on the final pass. - Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a - Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX - assembler code) and makefile.vcwin32 (doesn't). - Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) - Added a copy of pngnow.png to the distribution. -version 1.0.4a [September 25, 1999] - Increase max_pixel_depth in pngrutil.c if a user transform needs it. - Changed several division operations to right-shifts in pngvcrd.c -version 1.0.4b [September 30, 1999] - Added parentheses in line 3732 of pngvcrd.c - Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 -version 1.0.4c [October 1, 1999] - Added a "png_check_version" function in png.c and pngtest.c that will generate - a helpful compiler error if an old png.h is found in the search path. - Changed type of png_user_transform_depth|channels from int to png_byte. -version 1.0.4d [October 6, 1999] - Changed 0.45 to 0.45455 in png_set_sRGB() - Removed unused PLTE entries from pngnow.png - Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. -version 1.0.4e [October 10, 1999] - Fixed sign error in pngvcrd.c (Greg Roelofs) - Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) -version 1.0.4f [October 15, 1999] - Surrounded example.c code with #if 0 .. #endif to prevent people from - inadvertently trying to compile it. - Changed png_get_header_version() from a function to a macro in png.h - Added type casting mostly in pngrtran.c and pngwtran.c - Removed some pointless "ptr = NULL" in pngmem.c - Added a "contrib" directory containing the source code from Greg's book. - -version 1.0.5 [October 15, 1999] - Minor editing of the INSTALL and README files. -version 1.0.5a [October 23, 1999] - Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) - Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) - Further optimization and bugfix of pngvcrd.c - Revised pngset.c so that it does not allocate or free memory in the user's - text_ptr structure. Instead, it makes its own copy. - Created separate write_end_info_struct in pngtest.c for a more severe test. - Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. -version 1.0.5b [November 23, 1999] - Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and - PNG_FLAG_WROTE_tIME from flags to mode. - Added png_write_info_before_PLTE() function. - Fixed some typecasting in contrib/gregbook/*.c - Updated scripts/makevms.com and added makevms.com to contrib/gregbook - and contrib/pngminus (Martin Zinser) -version 1.0.5c [November 26, 1999] - Moved png_get_header_version from png.h to png.c, to accommodate ansi2knr. - Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to - accommodate making DLL's: Moved usr_png_ver from global variable to function - png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and - eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays - into pngtypes.h. Eliminated use of global png_pass arrays. Declared the - png_CHNK and png_pass arrays to be "const". Made the global arrays - available to applications (although none are used in libpng itself) when - PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. - Removed some extraneous "-I" from contrib/pngminus/makefile.std - Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. - Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 -version 1.0.5d [November 29, 1999] - Add type cast (png_const_charp) two places in png.c - Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. - Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available - to applications a macro "PNG_USE_LOCAL_ARRAYS". - Remove all the new declarations with #ifdef/#endif when - PNG_USE_GLOBAL_ARRAYS is defined. - Added PNG_EXPORT_VAR macro to accommodate making DLL's. -version 1.0.5e [November 30, 1999] - Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text - structure; refactored the inflate/deflate support to make adding new chunks - with trailing compressed parts easier in the future, and added new functions - png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, - png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). - NOTE: Applications that write text chunks MUST define png_text->lang - before calling png_set_text(). It must be set to NULL if you want to - write tEXt or zTXt chunks. If you want your application to be able to - run with older versions of libpng, use - - #ifdef PNG_iTXt_SUPPORTED - png_text[i].lang = NULL; - #endif - - Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned - offsets (Eric S. Raymond). - Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into - PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED - macros, leaving the separate macros also available. - Removed comments on #endifs at the end of many short, non-nested #if-blocks. -version 1.0.5f [December 6, 1999] - Changed makefile.solaris to issue a warning about potential problems when - the ucb "ld" is in the path ahead of the ccs "ld". - Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. - Added sCAL chunk support (Eric S. Raymond). -version 1.0.5g [December 7, 1999] - Fixed "png_free_spallettes" typo in png.h - Added code to handle new chunks in pngpread.c - Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block - Added "translated_key" to png_text structure and png_write_iTXt(). - Added code in pngwrite.c to work around a newly discovered zlib bug. -version 1.0.5h [December 10, 1999] - NOTE: regarding the note for version 1.0.5e, the following must also - be included in your code: - png_text[i].translated_key = NULL; - Unknown chunk handling is now supported. - Option to eliminate all floating point support was added. Some new - fixed-point functions such as png_set_gAMA_fixed() were added. - Expanded tabs and removed trailing blanks in source files. -version 1.0.5i [December 13, 1999] - Added some type casts to silence compiler warnings. - Renamed "png_free_spalette" to "png_free_spalettes" for consistency. - Removed leading blanks from a #define in pngvcrd.c - Added some parameters to the new png_set_keep_unknown_chunks() function. - Added a test for up->location != 0 in the first instance of writing - unknown chunks in pngwrite.c - Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to - prevent recursion. - Added png_free_hIST() function. - Various patches to fix bugs in the sCAL and integer cHRM processing, - and to add some convenience macros for use with sCAL. -version 1.0.5j [December 21, 1999] - Changed "unit" parameter of png_write_sCAL from png_byte to int, to work - around buggy compilers. - Added new type "png_fixed_point" for integers that hold float*100000 values - Restored backward compatibility of tEXt/zTXt chunk processing: - Restored the first four members of png_text to the same order as v.1.0.5d. - Added members "lang_key" and "itxt_length" to png_text struct. Set - text_length=0 when "text" contains iTXt data. Use the "compression" - member to distinguish among tEXt/zTXt/iTXt types. Added - PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. - The "Note" above, about backward incompatibility of libpng-1.0.5e, no - longer applies. - Fixed png_read|write_iTXt() to read|write parameters in the right order, - and to write the iTXt chunk after IDAT if it appears in the end_ptr. - Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) - Reversed the order of trying to write floating-point and fixed-point gAMA. -version 1.0.5k [December 27, 1999] - Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" - Added png_handle_as_unknown() function (Glenn) - Added png_free_chunk_list() function and chunk_list and num_chunk_list members - of png_ptr. - Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. - Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings - about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) - Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). - Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. - Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). -version 1.0.5l [January 1, 2000] - Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() - for setting a callback function to handle unknown chunks and for - retrieving the associated user pointer (Glenn). -version 1.0.5m [January 7, 2000] - Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). -version 1.0.5n [January 9, 2000] - Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its - own memory for info_ptr->palette. This makes it safe for the calling - application to free its copy of the palette any time after it calls - png_set_PLTE(). -version 1.0.5o [January 20, 2000] - Cosmetic changes only (removed some trailing blanks and TABs) -version 1.0.5p [January 31, 2000] - Renamed pngdll.mak to makefile.bd32 - Cosmetic changes in pngtest.c -version 1.0.5q [February 5, 2000] - Relocated the makefile.solaris warning about PATH problems. - Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) - Revised makefile.gcmmx - Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros -version 1.0.5r [February 7, 2000] - Removed superfluous prototype for png_get_itxt from png.h - Fixed a bug in pngrtran.c that improperly expanded the background color. - Return *num_text=0 from png_get_text() when appropriate, and fix documentation - of png_get_text() in libpng.txt/libpng.3. -version 1.0.5s [February 18, 2000] - Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the - new error handler that's planned for the next libpng release, and changed - example.c, pngtest.c, and contrib programs to use this macro. - Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) - Fixed a bug in png_read_png() that caused it to fail to expand some images - that it should have expanded. - Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions - in pngget.c - Changed the allocation of palette, history, and trans arrays back to - the version 1.0.5 method (linking instead of copying) which restores - backward compatibility with version 1.0.5. Added some remarks about - that in example.c. Added "free_me" member to info_ptr and png_ptr - and added png_free_data() function. - Updated makefile.linux and makefile.gccmmx to make directories conditionally. - Made cosmetic changes to pngasmrd.h - Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). - Modified png_read_png() to allocate info_ptr->row_pointers only if it - hasn't already been allocated. -version 1.0.5t [March 4, 2000] - Changed png_jmp_env() migration aiding macro to png_jmpbuf(). - Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c - Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when - PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b - Files in contrib/gregbook were revised to use png_jmpbuf() and to select - a 24-bit visual if one is available, and to allow abbreviated options. - Files in contrib/pngminus were revised to use the png_jmpbuf() macro. - Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s -version 1.0.5u [March 5, 2000] - Simplified the code that detects old png.h in png.c and pngtest.c - Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) - Increased precision of rgb_to_gray calculations from 8 to 15 bits and - added png_set_rgb_to_gray_fixed() function. - Added makefile.bc32 (32-bit Borland C++, C mode) -version 1.0.5v [March 11, 2000] - Added some parentheses to the png_jmpbuf macro definition. - Updated references to the zlib home page, which has moved to freesoftware.com. - Corrected bugs in documentation regarding png_read_row() and png_write_row(). - Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. - Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, - revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) - -version 1.0.6 [March 20, 2000] - Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c - Added makefile.sggcc (SGI IRIX with gcc) -version 1.0.6d [April 7, 2000] - Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO - Added data_length parameter to png_decompress_chunk() function - Revised documentation to remove reference to abandoned png_free_chnk functions - Fixed an error in png_rgb_to_gray_fixed() - Revised example.c, usage of png_destroy_write_struct(). - Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file - Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c - Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). -version 1.0.6e [April 9, 2000] - Added png_data_freer() function. - In the code that checks for over-length tRNS chunks, added check of - info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) - Minor revisions of libpng.txt/libpng.3. - Check for existing data and free it if the free_me flag is set, in png_set_*() - and png_handle_*(). - Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED - is defined. - Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c - and mentioned the purposes of the two macros in libpng.txt/libpng.3. -version 1.0.6f [April 14, 2000] - Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. - Add checks in png_set_text() for NULL members of the input text structure. - Revised libpng.txt/libpng.3. - Removed superfluous prototype for png_set_itxt from png.h - Removed "else" from pngread.c, after png_error(), and changed "0" to "length". - Changed several png_errors about malformed ancillary chunks to png_warnings. -version 1.0.6g [April 24, 2000] - Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. - Relocated paragraph about png_set_background() in libpng.3/libpng.txt - and other revisions (Matthias Benckmann) - Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and - png_ptr members to restore binary compatibility with libpng-1.0.5 - (breaks compatibility with libpng-1.0.6). -version 1.0.6h [April 24, 2000] - Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds - libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) - This is a temporary change for test purposes. -version 1.0.6i [May 2, 2000] - Rearranged some members at the end of png_info and png_struct, to put - unknown_chunks_num and free_me within the original size of the png_structs - and free_me, png_read_user_fn, and png_free_fn within the original png_info, - because some old applications allocate the structs directly instead of - using png_create_*(). - Added documentation of user memory functions in libpng.txt/libpng.3 - Modified png_read_png so that it will use user_allocated row_pointers - if present, unless free_me directs that it be freed, and added description - of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. - Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version - 1.00) members of png_struct and png_info, to regain binary compatibility - when you define this macro. Capabilities lost in this event - are user transforms (new in version 1.0.0),the user transform pointer - (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, - the high-level interface, and unknown chunks support (all new in 1.0.6). - This was necessary because of old applications that allocate the structs - directly as authors were instructed to do in libpng-0.88 and earlier, - instead of using png_create_*(). - Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which - can be used to detect codes that directly allocate the structs, and - code to check these modes in png_read_init() and png_write_init() and - generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED - was not defined. - Added makefile.intel and updated makefile.watcom (Pawel Mrochen) -version 1.0.6j [May 3, 2000] - Overloaded png_read_init() and png_write_init() with macros that convert - calls to png_read_init_2() or png_write_init_2() that check the version - and structure sizes. -version 1.0.7beta11 [May 7, 2000] - Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes - which are no longer used. - Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is - defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED - is defined. - Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory - overrun when old applications fill the info_ptr->text structure directly. - Added PNGAPI macro, and added it to the definitions of all exported functions. - Relocated version macro definitions ahead of the includes of zlib.h and - pngconf.h in png.h. -version 1.0.7beta12 [May 12, 2000] - Revised pngset.c to avoid a problem with expanding the png_debug macro. - Deleted some extraneous defines from pngconf.h - Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. - Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. - Added png_access_version_number() function. - Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). - Expanded libpng.3/libpng.txt information about png_data_freer(). -version 1.0.7beta14 [May 17, 2000] (beta13 was not published) - Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as - warnings instead of errors, as pngrutil.c does. - Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() - will actually write IDATs. - Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. - Make png_free_data() ignore its final parameter except when freeing data - that can have multiple instances (text, sPLT, unknowns). - Fixed a new bug in png_set_rows(). - Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. - Added png_set_invalid() function. - Fixed incorrect illustrations of png_destroy_write_struct() in example.c. -version 1.0.7beta15 [May 30, 2000] - Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce - fewer error messages. - Rearranged checks for Z_OK to check the most likely path first in pngpread.c - and pngwutil.c. - Added checks in pngtest.c for png_create_*() returning NULL, and mentioned - in libpng.txt/libpng.3 the need for applications to check this. - Changed names of png_default_*() functions in pngtest to pngtest_*(). - Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. - Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c - Set each pointer to NULL after freeing it in png_free_data(). - Worked around a problem in pngconf.h; AIX's strings.h defines an "index" - macro that conflicts with libpng's png_color_16.index. (Dimitri Papadapoulos) - Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). -version 1.0.7beta16 [June 4, 2000] - Revised the workaround of AIX string.h "index" bug. - Added a check for overlength PLTE chunk in pngrutil.c. - Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer - indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. - Added a warning in png_decompress_chunk() when it runs out of data, e.g. - when it tries to read an erroneous PhotoShop iCCP chunk. - Added PNG_USE_DLL macro. - Revised the copyright/disclaimer/license notice. - Added contrib/msvctest directory -version 1.0.7rc1 [June 9, 2000] - Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) - Added contrib/visupng directory (Willem van Schaik) -version 1.0.7beta18 [June 23, 2000] - Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ - and do not redefine PNGAPI if it is passed in via a compiler directive. - Revised visupng/PngFile.c to remove returns from within the Try block. - Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. - Updated contrib/visupng/cexcept.h to version 1.0.0. - Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. -version 1.0.7rc2 [June 28, 2000] - Updated license to include disclaimers required by UCITA. - Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. - -version 1.0.7 [July 1, 2000] - Revised the definition of "trans_values" in libpng.3/libpng.txt -version 1.0.8beta1 [July 8, 2000] - Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. - Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and - pngwutil.c. - Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. - Removed unused "#include " from png.c - Added WindowsCE support. - Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. -version 1.0.8beta2 [July 10, 2000] - Added project files to the wince directory and made further revisions - of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. -version 1.0.8beta3 [July 11, 2000] - Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() - for indexed-color input files to avoid potential double-freeing trans array - under some unusual conditions; problem was introduced in version 1.0.6f. - Further revisions to pngtest.c and files in the wince subdirectory. -version 1.0.8beta4 [July 14, 2000] - Added the files pngbar.png and pngbar.jpg to the distribution. - Added makefile.cygwin, and cygwin support in pngconf.h - Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) -version 1.0.8rc1 [July 16, 2000] - Revised png_debug() macros and statements to eliminate compiler warnings. - -version 1.0.8 [July 24, 2000] - Added png_flush() in pngwrite.c, after png_write_IEND(). - Updated makefile.hpux to build a shared library. -version 1.0.9beta1 [November 10, 2000] - Fixed typo in scripts/makefile.hpux - Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) - Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) - Changed "cdrom.com" in documentation to "libpng.org" - Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). - Changed type of "params" from voidp to png_voidp in png_read|write_png(). - Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. - Revised the 3 instances of WRITEFILE in pngtest.c. - Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. - Updated png.rc in dll/msvc project - Revised makefile.dec to define and use LIBPATH and INCPATH - Increased size of global png_libpng_ver[] array from 12 to 18 chars. - Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. - Removed duplicate png_crc_finish() from png_handle_bKGD() function. - Added a warning when application calls png_read_update_info() multiple times. - Revised makefile.cygwin - Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. - Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). -version 1.0.9beta2 [November 19, 2000] - Renamed the "dll" subdirectory "projects". - Added borland project files to "projects" subdirectory. - Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. - Add error message in png_set_compression_buffer_size() when malloc fails. -version 1.0.9beta3 [November 23, 2000] - Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. - Removed the png_flush() in pngwrite.c that crashes some applications - that don't set png_output_flush_fn. - Added makefile.macosx and makefile.aix to scripts directory. -version 1.0.9beta4 [December 1, 2000] - Change png_chunk_warning to png_warning in png_check_keyword(). - Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). -version 1.0.9beta5 [December 15, 2000] - Added support for filter method 64 (for PNG datastreams embedded in MNG). -version 1.0.9beta6 [December 18, 2000] - Revised png_set_filter() to accept filter method 64 when appropriate. - Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to - help prevent applications from using MNG features in PNG datastreams. - Added png_permit_mng_features() function. - Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". -version 1.0.9rc1 [December 23, 2000] - Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c - Fixed error handling of unknown compression type in png_decompress_chunk(). - In pngconf.h, define __cdecl when _MSC_VER is defined. -version 1.0.9beta7 [December 28, 2000] - Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. - Revised memory management in png_set_hIST and png_handle_hIST in a backward - compatible manner. PLTE and tRNS were revised similarly. - Revised the iCCP chunk reader to ignore trailing garbage. -version 1.0.9beta8 [January 12, 2001] - Moved pngasmrd.h into pngconf.h. - Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. -version 1.0.9beta9 [January 15, 2001] - Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to - wince and msvc project module definition files. - Minor revision of makefile.cygwin. - Fixed bug with progressive reading of narrow interlaced images in pngpread.c -version 1.0.9beta10 [January 16, 2001] - Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. - Fixed "png_mmx_supported" typo in project definition files. -version 1.0.9beta11 [January 19, 2001] - Updated makefile.sgi to make shared library. - Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED - by default, for the benefit of DLL forward compatibility. These will - be re-enabled in version 1.2.0. -version 1.0.9rc2 [January 22, 2001] - Revised cygwin support. - -version 1.0.9 [January 31, 2001] - Added check of cygwin's ALL_STATIC in pngconf.h - Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. -version 1.0.10beta1 [March 14, 2001] - Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. - Reformatted libpng.3 to eliminate bad line breaks. - Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c - Added prototype for png_mmx_support() near the top of pnggccrd.c - Moved some error checking from png_handle_IHDR to png_set_IHDR. - Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. - Revised png_mmx_support() function in pnggccrd.c - Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c - Fixed memory leak in contrib/visupng/PngFile.c - Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) - Added warnings when retrieving or setting gamma=0. - Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). -version 1.0.10rc1 [March 23, 2001] - Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, - and png_strlen. - Revised png_mmx_supported() function in pnggccrd.c to return proper value. - Fixed bug in progressive reading (pngpread.c) with small images (height < 8). - -version 1.0.10 [March 30, 2001] - Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin - Added beos project files (Chris Herborth) -version 1.0.11beta1 [April 3, 2001] - Added type casts on several png_malloc() calls (Dimitri Papadapoulos). - Removed a no-longer needed AIX work-around from pngconf.h - Changed several "//" single-line comments to C-style in pnggccrd.c -version 1.0.11beta2 [April 11, 2001] - Removed PNGAPI from several functions whose prototypes did not have PNGAPI. - Updated scripts/pngos2.def -version 1.0.11beta3 [April 14, 2001] - Added checking the results of many instances of png_malloc() for NULL -version 1.0.11beta4 [April 20, 2001] - Undid the changes from version 1.0.11beta3. Added a check for NULL return - from user's malloc_fn(). - Removed some useless type casts of the NULL pointer. - Added makefile.netbsd - -version 1.0.11 [April 27, 2001] - Revised makefile.netbsd -version 1.0.12beta1 [May 14, 2001] - Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) - Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h - Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. - Eliminated the png_error about apps using png_read|write_init(). Instead, - libpng will reallocate the png_struct and info_struct if they are too small. - This retains future binary compatibility for old applications written for - libpng-0.88 and earlier. -version 1.2.0beta1 [May 6, 2001] - Bumped DLLNUM to 2. - Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED - by default. - Added runtime selection of MMX features. - Added png_set_strip_error_numbers function and related macros. -version 1.2.0beta2 [May 7, 2001] - Finished merging 1.2.0beta1 with version 1.0.11 - Added a check for attempts to read or write PLTE in grayscale PNG datastreams. -version 1.2.0beta3 [May 17, 2001] - Enabled user memory function by default. - Modified png_create_struct so it passes user mem_ptr to user memory allocator. - Increased png_mng_features flag from png_byte to png_uint_32. - Bumped shared-library (so-number) and dll-number to 3. -version 1.2.0beta4 [June 23, 2001] - Check for missing profile length field in iCCP chunk and free chunk_data - in case of truncated iCCP chunk. - Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc - Bumped dll-number from 2 to 3 in makefile.cygwin - Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly - if user attempts to run it on an 8-bit display. - Updated contrib/gregbook - Use png_malloc instead of png_zalloc to allocate palette in pngset.c - Updated makefile.ibmc - Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes - of png_write_oFFS width and height from png_uint_32 to png_int_32. - Updated example.c - Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c -version 1.2.0beta5 [August 8, 2001] - Revised contrib/gregbook - Revised makefile.gcmmx - Revised pnggccrd.c to conditionally compile some thread-unsafe code only - when PNG_THREAD_UNSAFE_OK is defined. - Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with - value exceeding 2^bit_depth-1 - Revised makefile.sgi and makefile.sggcc - Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c - Removed restriction that do_invert_mono only operate on 1-bit opaque files - -version 1.2.0 [September 1, 2001] - Changed a png_warning() to png_debug() in pnggccrd.c - Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). -version 1.2.1beta1 [October 19, 2001] - Revised makefile.std in contrib/pngminus - Include background_1 in png_struct regardless of gamma support. - Revised makefile.netbsd and makefile.macosx, added makefile.darwin. - Revised example.c to provide more details about using row_callback(). -version 1.2.1beta2 [October 25, 2001] - Added type cast to each NULL appearing in a function call, except for - WINCE functions. - Added makefile.so9. -version 1.2.1beta3 [October 27, 2001] - Removed type casts from all NULLs. - Simplified png_create_struct_2(). -version 1.2.1beta4 [November 7, 2001] - Revised png_create_info_struct() and png_creat_struct_2(). - Added error message if png_write_info() was omitted. - Type cast NULLs appearing in function calls when _NO_PROTO or - PNG_TYPECAST_NULL is defined. -version 1.2.1rc1 [November 24, 2001] - Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL - is defined. - Changed typecast of "size" argument to png_size_t in pngmem.c calls to - the user malloc_fn, to agree with the prototype in png.h - Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) - Updated makefile.sgi to recognize LIBPATH and INCPATH. - Updated various makefiles so "make clean" does not remove previous major - version of the shared library. -version 1.2.1rc2 [December 4, 2001] - Always allocate 256-entry internal palette, hist, and trans arrays, to - avoid out-of-bounds memory reference caused by invalid PNG datastreams. - Added a check for prefix_length > data_length in iCCP chunk handler. - -version 1.2.1 [December 7, 2001] - None. -version 1.2.2beta1 [February 22, 2002] - Fixed a bug with reading the length of iCCP profiles (Larry Reeves). - Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate - libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h - Revised makefile.darwin to remove "-undefined suppress" option. - Added checks for gamma and chromaticity values over 21474.83, which exceed - the limit for PNG unsigned 32-bit integers when encoded. - Revised calls to png_create_read_struct() and png_create_write_struct() - for simpler debugging. - Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) -version 1.2.2beta2 [February 23, 2002] - Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. - Check for invalid image dimensions in png_get_IHDR. - Added missing "fi;" in the install target of the SGI makefiles. - Added install-static to all makefiles that make shared libraries. - Always do gamma compensation when image is partially transparent. -version 1.2.2beta3 [March 7, 2002] - Compute background.gray and background_1.gray even when color_type is RGB - in case image gets reduced to gray later. - Modified shared-library makefiles to install pkgconfig/libpngNN.pc. - Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown - Removed unused png_write_destroy_info prototype from png.h - Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case - Added install-shared target to all makefiles that make shared libraries. - Stopped a double free of palette, hist, and trans when not using free_me. - Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. -version 1.2.2beta4 [March 8, 2002] - Compute background.gray and background_1.gray even when color_type is RGB - in case image gets reduced to gray later (Jason Summers). - Relocated a misplaced /bin/rm in the "install-shared" makefile targets - Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. -version 1.2.2beta5 [March 26, 2002] - Added missing PNGAPI to several function definitions. - Check for invalid bit_depth or color_type in png_get_IHDR(), and - check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). - Revised iTXt support to accept NULL for lang and lang_key. - Compute gamma for color components of background even when color_type is gray. - Changed "()" to "{}" in scripts/libpng.pc.in. - Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN - Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so -version 1.2.2beta6 [March 31, 2002] -version 1.0.13beta1 [March 31, 2002] - Prevent png_zalloc() from trying to memset memory that it failed to acquire. - Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). - Ensure that the right function (user or default) is used to free the - png_struct after an error in png_create_read_struct_2(). -version 1.2.2rc1 [April 7, 2002] -version 1.0.13rc1 [April 7, 2002] - Save the ebx register in pnggccrd.c (Sami Farin) - Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). - Updated makefiles to put headers in include/libpng and remove old include/*.h. - -version 1.2.2 [April 15, 2002] -version 1.0.13 [April 15, 2002] - Revised description of png_set_filter() in libpng.3/libpng.txt. - Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd -version 1.0.13patch01 [April 17, 2002] -version 1.2.2patch01 [April 17, 2002] - Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and makefile.sggcc - Fixed VER -> PNGVER typo in makefile.macosx and added install-static to install - Added install: target to makefile.32sunu and makefile.64sunu -version 1.0.13patch03 [April 18, 2002] -version 1.2.2patch03 [April 18, 2002] - Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng - subdirectory to libpngNN subdirectory without the full pathname. - Moved generation of libpng.pc from "install" to "all" in 15 makefiles. -version 1.2.3rc1 [April 28, 2002] - Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). - Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) - Fixed bug with $prefix, should be $(prefix) in makefile.hpux. - Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin - Added a link from libpngNN.pc to libpng.pc in 15 makefiles. - Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. - Revised makefile.darwin to make relative links without full pathname. - Added setjmp() at the end of png_create_*_struct_2() in case user forgets - to put one in their application. - Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and - removed them from module definition files. -version 1.2.3rc2 [May 1, 2002] - Fixed bug in reporting number of channels in pngget.c and pngset.c, - that was introduced in version 1.2.2beta5. - Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), - png_default_flush(), and png_push_fill_buffer() and included them in - module definition files. - Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. -version 1.2.3rc3 [May 1, 2002] - Revised prototype for png_default_flush() - Remove old libpng.pc and libpngNN.pc before installing new ones. -version 1.2.3rc4 [May 2, 2002] - Typos in *.def files (png_default_read|write -> png_default_read|write_data) - In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc - Added libpng-config and libpngNN-config and modified makefiles to install them. - Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles - Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp -version 1.2.3rc5 [May 11, 2002] - Changed "error" and "message" in prototypes to "error_message" and - "warning_message" to avoid namespace conflict. - Revised 15 makefiles to build libpng-config from libpng-config-*.in - Once more restored png_zalloc and png_zfree to regular nonexported form. - Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer - to nonexported form, but with PNGAPI, and removed them from module def files. -version 1.2.3rc6 [May 14, 2002] - Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c - Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. - Removed leftover libpng-config "sed" script from four makefiles. - Revised libpng-config creating script in 16 makefiles. - -version 1.2.3 [May 22, 2002] - Revised libpng-config target in makefile.cygwin. - Removed description of png_set_mem_fn() from documentation. - Revised makefile.freebsd. - Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). - Revised projects/msvc/README.txt - Changed -lpng to -lpngNN in LDFLAGS in several makefiles. -version 1.2.4beta1 [May 24, 2002] - Added libpng.pc and libpng-config to "all:" target in 16 makefiles. - Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) - Added missing "\" before closing double quote in makefile.gcmmx. - Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() - functions. -version 1.2.4beta2 [June 25, 2002] - Plugged memory leak of png_ptr->current_text (Matt Holgate). - Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) - Added -soname to the loader flags in makefile.dec, makefile.sgi, and - makefile.sggcc. - Added "test-installed" target to makefile.linux, makefile.gcmmx, - makefile.sgi, and makefile.sggcc. -version 1.2.4beta3 [June 28, 2002] - Plugged memory leak of row_buf in pngtest.c when there is a png_error(). - Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. - Added "test-installed" target to makefile.32sunu, makefile.64sunu, - makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, - makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. -version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] - Added "test-installed" target to makefile.cygwin and makefile.sco. - Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. - -version 1.2.4 and 1.0.14 [July 8, 2002] - Changed png_warning() to png_error() when width is too large to process. -version 1.2.4patch01 [July 20, 2002] - Revised makefile.cygwin to use DLL number 12 instead of 13. -version 1.2.5beta1 [August 6, 2002] - Added code to contrib/gregbook/readpng2.c to ignore unused chunks. - Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) - Removed some stray *.o files from contrib/gregbook. - Changed png_error() to png_warning() about "Too much data" in pngpread.c - and about "Extra compressed data" in pngrutil.c. - Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). - Updated makefile.hpgcc - Updated png.c and pnggccrd.c handling of return from png_mmx_support() -version 1.2.5beta2 [August 15, 2002] - Only issue png_warning() about "Too much data" in pngpread.c when avail_in - is nonzero. - Updated makefiles to install a separate libpng.so.3 with its own rpath. -version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] - Revised makefiles to not remove previous minor versions of shared libraries. -version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] - Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared - library loader directive. - Added missing "$OBJSDLL" line to makefile.gcmmx. - Added missing "; fi" to makefile.32sunu. -version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] - Revised libpng-config script. - -version 1.2.5 and 1.0.15 [October 3, 2002] - Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, - and makefile.aix. - Relocated two misplaced PNGAPI lines in pngtest.c -version 1.2.6beta1 [October 22, 2002] - Commented out warning about uninitialized mmx_support in pnggccrd.c. - Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. - Relocated two more misplaced PNGAPI lines in pngtest.c - Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, - introduced in version 1.0.2. - Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. -version 1.2.6beta2 [November 1, 2002] - Added libpng-config "--ldopts" output. - Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" - in makefiles. -version 1.2.6beta3 [July 18, 2004] - Reverted makefile changes from version 1.2.6beta2 and some of the changes - from version 1.2.6beta1; these will be postponed until version 1.2.7. - Version 1.2.6 is going to be a simple bugfix release. - Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. - Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. - Added "#!/bin/sh" at the top of configure, for recognition of the - 'x' flag under Cygwin (Cosmin). - Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). - Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). - Fixed the special memory handler for Borland C under DOS, in pngmem.c - (Cosmin). - Removed some spurious assignments in pngrutil.c (Cosmin). - Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings - on 16-bit platforms (Cosmin). - Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). - Used proper type png_fixed_point, to avoid problems on 16-bit platforms, - in png_handle_sRGB() (Cosmin). - Added compression_type to png_struct, and optimized the window size - inside the deflate stream (Cosmin). - Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). - Fixed handling of unknown chunks that come after IDAT (Cosmin). - Allowed png_error() and png_warning() to work even if png_ptr == NULL - (Cosmin). - Replaced row_info->rowbytes with row_bytes in png_write_find_filter() - (Cosmin). - Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). - Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded - values in png.c (Simon-Pierre, Cosmin). - Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). - Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc - (Simon-Pierre). - Moved the definition of PNG_HEADER_VERSION_STRING near the definitions - of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). - Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). - Updated scripts/makefile.vc(a)win32 (Cosmin). - Updated the MSVC project (Simon-Pierre, Cosmin). - Updated the Borland C++ Builder project (Cosmin). - Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). - Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). - Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). - Added extra guard around inclusion of Turbo C memory headers, in pngconf.h - (Cosmin). - Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to - projects/cbuilder5/ (Cosmin). - Moved projects/visualc6/png32ms.def to scripts/pngw32.def, - and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). - Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). - Changed line endings to DOS style in cbuilder5 and visualc6 files, even - in the tar.* distributions (Cosmin). - Updated contrib/visupng/VisualPng.dsp (Cosmin). - Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). - Added a separate distribution with "configure" and supporting files (Junichi). -version 1.2.6beta4 [July 28, 2004] - Added user ability to change png_size_t via a PNG_SIZE_T macro. - Added png_sizeof() and png_convert_size() functions. - Added PNG_SIZE_MAX (maximum value of a png_size_t variable. - Added check in png_malloc_default() for (size_t)size != (png_uint_32)size - which would indicate an overflow. - Changed sPLT failure action from png_error to png_warning and abandon chunk. - Changed sCAL and iCCP failures from png_error to png_warning and abandon. - Added png_get_uint_31(png_ptr, buf) function. - Added PNG_UINT_32_MAX macro. - Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. - Made png_zalloc() issue a png_warning and return NULL on potential - overflow. - Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x - Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. - Revised Borland portion of png_malloc() to return NULL or issue - png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. - Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove - sequential read support. - Added some "#if PNG_WRITE_SUPPORTED" blocks. - Removed some redundancy with #ifdef/#endif in png_malloc_default(). - Use png_malloc instead of png_zalloc to allocate the pallete. -version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] - Fixed buffer overflow vulnerability in png_handle_tRNS() - Fixed integer arithmetic overflow vulnerability in png_read_png(). - Fixed some harmless bugs in png_handle_sBIT, etc, that would cause - duplicate chunk types to go undetected. - Fixed some timestamps in the -config version - Rearranged order of processing of color types in png_handle_tRNS(). - Added ROWBYTES macro to calculate rowbytes without integer overflow. - Updated makefile.darwin and removed makefile.macosx from scripts directory. - Imposed default one million column, one-million row limits on the image - dimensions, and added png_set_user_limits() function to override them. - Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. - Fixed wrong cast of returns from png_get_user_width|height_max(). - Changed some "keep the compiler happy" from empty statements to returns, - Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution -version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] - Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. - Revised pngtest's png_debug_malloc() to use png_malloc() instead of - png_malloc_default() which is not supposed to be exported. - Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in - pngpread.c. Bug was introduced in 1.2.6rc1. - Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. - Fixed old bug in RGB to Gray transformation. - Fixed problem with 64-bit compilers by casting arguments to abs() - to png_int_32. - Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). - Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) - Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. - Added code to update the row_info->colortype in png_do_read_filler() (MSB). -version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] - Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid - trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. - Revised documentation of png_set_keep_unknown_chunks(). - Check handle_as_unknown status in pngpread.c, as in pngread.c previously. - Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h - Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c -version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] - Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of - "pinfo" was out of place). -version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] - Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED - section of png.h where they were inadvertently placed in version rc3. - -version 1.2.6 and 1.0.16 [August 15, 2004] - Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. -version 1.2.7beta1 [August 26, 2004] - Removed unused pngasmrd.h file. - Removed references to uu.net for archived files. Added references to - PNG Spec (second edition) and the PNG ISO/IEC Standard. - Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. - Fixed bug with "optimized window size" in the IDAT datastream, that - causes libpng to write PNG files with incorrect zlib header bytes. -version 1.2.7beta2 [August 28, 2004] - Fixed bug with sCAL chunk and big-endian machines (David Munro). - Undid new code added in 1.2.6rc2 to update the color_type in - png_set_filler(). - Added png_set_add_alpha() that updates color type. -version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] - Revised png_set_strip_filler() to not remove alpha if color_type has alpha. - -version 1.2.7 and 1.0.17 [September 12, 2004] - Added makefile.hp64 - Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin -version 1.2.8beta1 [November 1, 2004] - Fixed bug in png_text_compress() that would fail to complete a large block. - Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during - strip alpha operation in png_do_strip_filler(). - Added PNG_1_2_X definition in pngconf.h - Comment out with #ifdef/#endif png_info_init in png.c and png_read_init - in pngread.c (as of 1.3.0) -version 1.2.8beta2 [November 2, 2004] - Reduce color_type to a nonalpha type after strip alpha operation in - png_do_strip_filler(). -version 1.2.8beta3 [November 3, 2004] - Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM -version 1.2.8beta4 [November 12, 2004] - Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). - Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). - Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection - of data type in deflate (Cosmin). - Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of - PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. -version 1.2.8beta5 [November 20, 2004] - Use png_ptr->flags instead of png_ptr->transformations to pass - PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI - compatibility. - Revised handling of SPECIALBUILD, PRIVATEBUILD, - PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. -version 1.2.8rc1 [November 24, 2004] - Moved handling of BUILD macros from pngconf.h to png.h - Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently - omitted from beta5. - Revised scripts/pngw32.rc - Despammed mailing addresses by masking "@" with "at". - Inadvertently installed a supposedly faster test version of pngrutil.c -version 1.2.8rc2 [November 26, 2004] - Added two missing "\" in png.h - Change tests in pngread.c and pngpread.c to - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); -version 1.2.8rc3 [November 28, 2004] - Reverted pngrutil.c to version libpng-1.2.8beta5. - Added scripts/makefile.elf with supporting code in pngconf.h for symbol - versioning (John Bowler). -version 1.2.8rc4 [November 29, 2004] - Added projects/visualc7 (Simon-pierre). -version 1.2.8rc5 [November 29, 2004] - Fixed new typo in scripts/pngw32.rc - -version 1.2.8 [December 3, 2004] - Removed projects/visualc7, added projects/visualc71. - -version 1.2.9beta1 [February 21, 2006] - - Initialized some structure members in pngwutil.c to avoid gcc-4.0.0 complaints - Revised man page and libpng.txt to make it clear that one should not call - png_read_end or png_write_end after png_read_png or png_write_png. - Updated references to png-mng-implement mailing list. - Fixed an incorrect typecast in pngrutil.c - Added PNG_NO_READ_SUPPORTED conditional for making a write-only library. - Added PNG_NO_WRITE_INTERLACING_SUPPORTED conditional. - Optimized alpha-inversion loops in pngwtran.c - Moved test for nonzero gamma outside of png_build_gamma_table() in pngrtran.c - Make sure num_trans is <= 256 before copying data in png_set_tRNS(). - Make sure num_palette is <= 256 before copying data in png_set_PLTE(). - Interchanged order of write_swap_alpha and write_invert_alpha transforms. - Added parentheses in the definition of PNG_LIBPNG_BUILD_TYPE (Cosmin). - Optimized zlib window flag (CINFO) in contrib/pngsuite/*.png (Cosmin). - Updated scripts/makefile.bc32 for Borland C++ 5.6 (Cosmin). - Exported png_get_uint_32, png_save_uint_32, png_get_uint_16, png_save_uint_16, - png_get_int_32, png_save_int_32, png_get_uint_31 (Cosmin). - Added type cast (png_byte) in png_write_sCAL() (Cosmin). - Fixed scripts/makefile.cygwin (Christian Biesinger, Cosmin). - Default iTXt support was inadvertently enabled. - -version 1.2.9beta2 [February 21, 2006] - - Check for png_rgb_to_gray and png_gray_to_rgb read transformations before - checking for png_read_dither in pngrtran.c - Revised checking of chromaticity limits to accommodate extended RGB - colorspace (John Denker). - Changed line endings in some of the project files to CRLF, even in the - "Unix" tar distributions (Cosmin). - Made png_get_int_32 and png_save_int_32 always available (Cosmin). - Updated scripts/pngos2.def, scripts/pngw32.def and projects/wince/png32ce.def - with the newly exported functions. - Eliminated distributions without the "configure" script. - Updated INSTALL instructions. - -version 1.2.9beta3 [February 24, 2006] - - Fixed CRCRLF line endings in contrib/visupng/VisualPng.dsp - Made libpng.pc respect EXEC_PREFIX (D. P. Kreil, J. Bowler) - Removed reference to pngasmrd.h from Makefile.am - Renamed CHANGES to ChangeLog. - Renamed LICENSE to COPYING. - Renamed ANNOUNCE to NEWS. - Created AUTHORS file. - -version 1.2.9beta4 [March 3, 2006] - - Changed definition of PKGCONFIG from $prefix/lib to $libdir in configure.ac - Reverted to filenames LICENSE and ANNOUNCE; removed AUTHORS and COPYING. - Removed newline from the end of some error and warning messages. - Removed test for sqrt() from configure.ac and configure. - Made swap tables in pngtrans.c PNG_CONST (Carlo Bramix). - Disabled default iTXt support that was inadvertently enabled in - libpng-1.2.9beta1. - Added "OS2" to list of systems that don't need underscores, in pnggccrd.c - Removed libpng version and date from *.c files. - -version 1.2.9beta5 [March 4, 2006] - Removed trailing blanks from source files. - Put version and date of latest change in each source file, and changed - copyright year accordingly. - More cleanup of configure.ac, Makefile.am, and associated scripts. - Restored scripts/makefile.elf which was inadvertently deleted. - -version 1.2.9beta6 [March 6, 2006] - Fixed typo (RELEASE) in configuration files. - -version 1.2.9beta7 [March 7, 2006] - Removed libpng.vers and libpng.sym from libpng12_la_SOURCES in Makefile.am - Fixed inconsistent #ifdef's around png_sig_bytes() and png_set_sCAL_s() - in png.h. - Updated makefile.elf as suggested by debian. - Made cosmetic changes to some makefiles, adding LN_SF and other macros. - Made some makefiles accept "exec_prefix". - -version 1.2.9beta8 [March 9, 2006] - Fixed some "#if defined (..." which should be "#if defined(..." - Bug introduced in libpng-1.2.8. - Fixed inconsistency in definition of png_default_read_data() - Restored blank that was lost from makefile.sggcc "clean" target in beta7. - Revised calculation of "current" and "major" for irix in ltmain.sh - Changed "mkdir" to "MKDIR_P" in some makefiles. - Separated PNG_EXPAND and PNG_EXPAND_tRNS. - Added png_set_expand_gray_1_2_4_to_8() and deprecated - png_set_gray_1_2_4_to_8() which also expands tRNS to alpha. - -version 1.2.9beta9 [March 10, 2006] - Include "config.h" in pngconf.h when available. - Added some checks for NULL png_ptr or NULL info_ptr (timeless) - -version 1.2.9beta10 [March 20, 2006] - Removed extra CR from contrib/visualpng/VisualPng.dsw (Cosmin) - Made pnggccrd.c PIC-compliant (Christian Aichinger). - Added makefile.mingw (Wolfgang Glas). - Revised pngconf.h MMX checking. - -version 1.2.9beta11 [March 22, 2006] - Fixed out-of-order declaration in pngwrite.c that was introduced in beta9 - Simplified some makefiles by using LIBSO, LIBSOMAJ, and LIBSOVER macros. - -version 1.2.9rc1 [March 31, 2006] - Defined PNG_USER_PRIVATEBUILD when including "pngusr.h" (Cosmin). - Removed nonsensical assertion check from pngtest.c (Cosmin). - -version 1.2.9 [April 14, 2006] - Revised makefile.beos and added "none" selector in ltmain.sh - -version 1.2.10beta1 [April 15, 2006] - Renamed "config.h" to "png_conf.h" and revised Makefile.am to add - -DPNG_BUILDING_LIBPNG to compile directive, and modified pngconf.h - to include png_conf.h only when PNG_BUILDING_LIBPNG is defined. - -version 1.2.10beta2 [April 15, 2006] - Manually updated Makefile.in and configure. Changed png_conf.h.in - back to config.h. - -version 1.2.10beta3 [April 15, 2006] - Change png_conf.h back to config.h in pngconf.h. - -version 1.2.10beta4 [April 16, 2006] - Change PNG_BUILDING_LIBPNG to PNG_CONFIGURE_LIBPNG in config/Makefile*. - -version 1.2.10beta5 [April 16, 2006] - Added a configure check for compiling assembler code in pnggccrd.c - -version 1.2.10beta6 [April 17, 2006] - Revised the configure check for pnggccrd.c - Moved -DPNG_CONFIGURE_LIBPNG into @LIBPNG_DEFINES@ - Added @LIBPNG_DEFINES@ to arguments when building libpng.sym - -version 1.2.10beta7 [April 18, 2006] - Change "exec_prefix=$prefix" to "exec_prefix=$(prefix)" in makefiles. - -version 1.2.10rc1 [April 19, 2006] - Ensure pngconf.h doesn't define both PNG_USE_PNGGCCRD and PNG_USE_PNGVCRD - Fixed "LN_FS" typo in makefile.sco and makefile.solaris. - -version 1.2.10rc2 [April 20, 2006] - Added a backslash between -DPNG_CONFIGURE_LIBPNG and -DPNG_NO_ASSEMBLER_CODE - in configure.ac and configure - Made the configure warning about versioned symbols less arrogant. - -version 1.2.10rc3 [April 21, 2006] - Added a note in libpng.txt that png_set_sig_bytes(8) can be used when - writing an embedded PNG without the 8-byte signature. - Revised makefiles and configure to avoid making links to libpng.so.* - -version 1.2.10 [April 23, 2006] - Reverted configure to "rc2" state. - -version 1.2.11beta1 [May 31, 2006] - scripts/libpng.pc.in contained "configure" style version info and would - not work with makefiles. - The shared-library makefiles were linking to libpng.so.0 instead of - libpng.so.3 compatibility as the library. - -version 1.2.11beta2 [June 2, 2006] - Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - Fixed bug in example.c (png_set_palette_rgb -> png_set_palette_to_rgb) - -version 1.2.11beta3 [June 5, 2006] - Prepended "#! /bin/sh" to ltmail.sh and contrib/pngminus/*.sh (Cosmin). - Removed the accidental leftover Makefile.in~ (Cosmin). - Avoided potential buffer overflow and optimized buffer in - png_write_sCAL(), png_write_sCAL_s() (Cosmin). - Removed the include directories and libraries from CFLAGS and LDFLAGS - in scripts/makefile.gcc (Nelson A. de Oliveira, Cosmin). - -version 1.2.11beta4 [June 6, 2006] - Allow zero-length IDAT chunks after the entire zlib datastream, but not - after another intervening chunk type. - -version 1.0.19rc1, 1.2.11rc1 [June 13, 2006] - Deleted extraneous square brackets from [config.h] in configure.ac - -version 1.0.19rc2, 1.2.11rc2 [June 14, 2006] - Added prototypes for PNG_INCH_CONVERSIONS functions to png.h - Revised INSTALL and autogen.sh - Fixed typo in several makefiles (-W1 should be -Wl) - Added typedef for png_int_32 and png_uint_32 on 64-bit systems. - -version 1.0.19rc3, 1.2.11rc3 [June 15, 2006] - Removed the new typedefs for 64-bit systems (delay until version 1.4.0) - Added one zero element to png_gamma_shift[] array in pngrtran.c to avoid - reading out of bounds. - -version 1.0.19rc4, 1.2.11rc4 [June 15, 2006] - Really removed the new typedefs for 64-bit systems. - -version 1.0.19rc5, 1.2.11rc5 [June 22, 2006] - Removed png_sig_bytes entry from scripts/pngw32.def - -version 1.0.19, 1.2.11 [June 26, 2006] - None. - -version 1.0.20, 1.2.12 [June 27, 2006] - Really increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - -version 1.2.13beta1 [October 2, 2006] - Removed AC_FUNC_MALLOC from configure.ac - Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h - Change "logical" to "bitwise" throughout documentation. - Detect and fix attempt to write wrong iCCP profile length. - -version 1.0.21, 1.2.13 [November 14, 2006] - Fix potential buffer overflow in sPLT chunk handler. - Fix Makefile.am to not try to link to noexistent files. - Check all exported functions for NULL png_ptr. - -version 1.2.14beta1 [November 17, 2006] - Relocated three misplaced tests for NULL png_ptr. - Built Makefile.in with automake-1.9.6 instead of 1.9.2. - Build configure with autoconf-2.60 instead of 2.59 - -version 1.2.14beta2 [November 17, 2006] - Added some typecasts in png_zalloc(). - -version 1.2.14rc1 [November 20, 2006] - Changed "strtod" to "png_strtod" in pngrutil.c - -version 1.0.22, 1.2.14 [November 27, 2006] - Added missing "$(srcdir)" in Makefile.am and Makefile.in - -version 1.2.15beta1 [December 3, 2006] - Generated configure with autoconf-2.61 instead of 2.60 - Revised configure.ac to update libpng.pc and libpng-config. - -version 1.2.15beta2 [December 3, 2006] - Always export MMX asm functions, just stubs if not building pnggccrd.c - -version 1.2.15beta3 [December 4, 2006] - Add "png_bytep" typecast to profile while calculating length in pngwutil.c - -version 1.2.15beta4 [December 7, 2006] - Added scripts/CMakeLists.txt - Changed PNG_NO_ASSEMBLER_CODE to PNG_NO_MMX_CODE in scripts, like 1.4.0beta - -version 1.2.15beta5 [December 7, 2006] - Changed some instances of PNG_ASSEMBLER_* to PNG_MMX_* in pnggccrd.c - Revised scripts/CMakeLists.txt - -version 1.2.15beta6 [December 13, 2006] - Revised scripts/CMakeLists.txt and configure.ac - -version 1.2.15rc1 [December 18, 2006] - Revised scripts/CMakeLists.txt - -version 1.2.15rc2 [December 21, 2006] - Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. - Added scripts/makefile.nommx - -version 1.2.15rc3 [December 25, 2006] - Fixed shared library numbering error that was introduced in 1.2.15beta6. - -version 1.2.15rc4 [December 27, 2006] - Fixed handling of rgb_to_gray when png_ptr->color.gray isn't set. - -version 1.2.15rc5 [December 31, 2006] - Revised handling of rgb_to_gray. - -version 1.0.23, 1.2.15 [January 5, 2007] - Added some (unsigned long) typecasts in pngtest.c to avoid printing errors. - -version 1.2.16beta1 [January 6, 2007] - Fix bugs in makefile.nommx - -version 1.2.16beta2 [January 16, 2007] - Revised scripts/CMakeLists.txt - -version 1.0.24, 1.2.16 [January 31, 2007] - No changes. - -version 1.2.17beta1 [March 6, 2007] - Revised scripts/CMakeLists.txt to install both shared and static libraries. - Deleted a redundant line from pngset.c. - -version 1.2.17beta2 [April 26, 2007] - Relocated misplaced test for png_ptr == NULL in pngpread.c - Change "==" to "&" for testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN - flags. - Changed remaining instances of PNG_ASSEMBLER_* to PNG_MMX_* - Added pngerror() when write_IHDR fails in deflateInit2(). - Added "const" to some array declarations. - Mention examples of libpng usage in the libpng*.txt and libpng.3 documents. - -version 1.2.17rc1 [May 4, 2007] - No changes. - -version 1.2.17rc2 [May 8, 2007] - Moved several PNG_HAVE_* macros out of PNG_INTERNAL because applications - calling set_unknown_chunk_location() need them. - Changed transformation flag from PNG_EXPAND_tRNS to PNG_EXPAND in - png_set_expand_gray_1_2_4_to_8(). - Added png_ptr->unknown_chunk to hold working unknown chunk data, so it - can be free'ed in case of error. Revised unknown chunk handling in - pngrutil.c and pngpread.c to use this structure. - -version 1.2.17rc3 [May 8, 2007] - Revised symbol-handling in configure script. - -version 1.2.17rc4 [May 10, 2007] - Revised unknown chunk handling to avoid storing unknown critical chunks. - -version 1.0.25 [May 15, 2007] -version 1.2.17 [May 15, 2007] - Added "png_ptr->num_trans=0" before error return in png_handle_tRNS, - to eliminate a vulnerability (CVE-2007-2445, CERT VU#684664) - -version 1.0.26 [May 15, 2007] -version 1.2.18 [May 15, 2007] - Reverted the libpng-1.2.17rc3 change to symbol-handling in configure script - -version 1.2.19beta1 [May 18, 2007] - Changed "const static" to "static PNG_CONST" everywhere, mostly undoing - change of libpng-1.2.17beta2. Changed other "const" to "PNG_CONST" - Changed some handling of unused parameters, to avoid compiler warnings. - "if (unused == NULL) return;" becomes "unused = unused". - -version 1.2.19beta2 [May 18, 2007] - Only use the valid bits of tRNS value in png_do_expand() (Brian Cartier) - -version 1.2.19beta3 [May 19, 2007] - Add some "png_byte" typecasts in png_check_keyword() and write new_key - instead of key in zTXt chunk (Kevin Ryde). - -version 1.2.19beta4 [May 21, 2007] - Add png_snprintf() function and use it in place of sprint() for improved - defense against buffer overflows. - -version 1.2.19beta5 [May 21, 2007] - Fixed png_handle_tRNS() to only use the valid bits of tRNS value. - Changed handling of more unused parameters, to avoid compiler warnings. - Removed some PNG_CONST in pngwutil.c to avoid compiler warnings. - -version 1.2.19beta6 [May 22, 2007] - Added some #ifdef PNG_MMX_CODE_SUPPORTED where needed in pngvcrd.c - Added a special "_MSC_VER" case that defines png_snprintf to _snprintf - -version 1.2.19beta7 [May 22, 2007] - Squelched png_squelch_warnings() in pnggccrd.c and added - an #ifdef PNG_MMX_CODE_SUPPORTED/#endif block around the declarations - that caused the warnings that png_squelch_warnings was squelching. - -version 1.2.19beta8 [May 22, 2007] - Removed __MMX__ from test in pngconf.h. - -version 1.2.19beta9 [May 23, 2007] - Made png_squelch_warnings() available via PNG_SQUELCH_WARNINGS macro. - Revised png_squelch_warnings() so it might work. - Updated makefile.sgcc and makefile.solaris; added makefile.solaris-x86. - -version 1.2.19beta10 [May 24, 2007] - Resquelched png_squelch_warnings(), use "__attribute__((used))" instead. - -version 1.2.19beta11 [May 28, 2007] - Return 0 from png_get_sPLT() and png_get_unknown_chunks() if png_ptr is NULL; - changed three remaining instances of png_strcpy() to png_strncpy() (David - Hill). - Make test for NULL row_buf at the beginning of png_do_read_transformations - unconditional. - -version 1.2.19beta12 [May 28, 2007] - Revised pnggccrd.c. - -version 1.2.19beta13 [June 14, 2007] - Prefer PNG_USE_PNGVCRD when _MSC_VER is defined in pngconf.h - -version 1.2.19beta14 [June 16, 2007] - Fix bug with handling of 16-bit transparency, introduced in 1.2.19beta2 - -version 1.2.19beta15 [June 17, 2007] - Revised pnggccrd.c. - -version 1.2.19beta16 [June 18, 2007] - Revised pnggccrd.c again. - Updated contrib/gregbook. - Changed '#include "pnggccrd.c"' to 'include "$srcdir/pnggccrd.c"' - in configure.ac - -version 1.2.19beta17 [June 19, 2007] - Revised many of the makefiles, to set -DPNG_NO_MMX_CODE where needed - and to not use -O3 unless -DPNG_NO_MMX_CODE is also set. - -version 1.2.19beta18 [June 23, 2007] - Replaced some C++ style comments with C style comments in pnggccrd.c. - Copied optimized C code from pnggccrd.c to pngrutil.c, removed dependency - on pnggccrd.o from many makefiles. - Added sl and dylib to list of extensions be installed by Makefile.am - -version 1.2.19beta19 [June 28, 2007] - Fixed testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN in pngrtran.c - More cleanup of pnggccrd.c and pngvcrd.c - -version 1.2.19beta20 [June 29, 2007] - Rebuilt Makefile.in and configure using libtool-1.5.24. - Fixed typo in pnggccrd.c - -version 1.2.19beta21 [June 30, 2007] - More revision of pnggccrd.c - Added "test" target to Makefile.in and Makefile.am - -version 1.2.19beta22 [July 3, 2007] - Added info about pngrutil/pnggccrd/pngvcrd to png_get_header_version() - Fix type definition of dummy_value_a, b in pnggccrd.c - -version 1.2.19beta23 [July 10, 2007] - Revert change to type definition of dummy_value_a, b in pnggccrd.c - Make sure __PIC__ is defined in pnggccrd.c when PIC is defined. - Require gcc-4.1 or better to use PNG_HAVE_MMX_FILTER_ROW on x86_64 platforms - -version 1.2.19beta24 [July 14, 2007] - Added PNG_NO_READ_FILTER, PNG_NO_WRITE_FILTER, PNG_NO_WARNING macros. - Added contrib/pngminim to demonstrate building minimal encoder and decoder - -version 1.2.19beta25 [July 15, 2007] - Removed the new PNG_NO_READ_FILTER macro since it would make the library - unable to read valid PNG files, and filtering is at the heart of the - PNG format. - -version 1.2.19beta26 [July 16, 2007] - Changed "png_free(str)" to "png_free(png_ptr,str)" in pngrutil.c WinCE - code (Yves Piguet). This bug was introduced in libpng-1.2.14. - Updated scripts/CMakeLists.txt - Relocated a misplaced #endif in pnggccrd.c - -version 1.2.19beta27 [July 17, 2007] - Fixed incorrect stride and number of bytes copied (was 4 instead of - 6 bytes) in the cleanup loop of pnggccrd.c and pngvcrd.c for handling - the end of 48-bit interlaced rows (Glenn R-P). - -version 1.2.19beta28 [July 19, 2007] - Removed requirement for gcc-4.1 or better to use PNG_HAVE_MMX_FILTER_ROW - on x86_64 platforms - Added png_warning() in pngrutil.c for short iCCP, iTXt, sPLT, or zTXT chunks. - Revised pngtest.c so warnings are displayed regardless of PNG_NO_STDIO. - -version 1.2.19beta29 [July 20, 2007] - Fix typo in pnggccrd.c (%%eax should be %%ax in secondloop48) - -version 1.2.19beta30 [July 26, 2007] - Revised pnggccrd.c - -version 1.2.19beta31 [July 27, 2007] - Fix typos in pnggccrd.c - -version 1.0.27rc1 and 1.2.19rc1 [July 31, 2007] - Disable PNG_MMX_CODE_SUPPORTED when PNG_ASSEMBLER_CODE_SUPPORTED is off. - Enable PNG_MMX_READ_FILTER_* by default, except when gcc-3.x is being - used (they were inadvertently disabled in libpng-1.2.19beta23). - Fix some debugging statements in pnggccrd.c and pngrutil.c - Added information about disabling the MMX code in libpng documentation. - -version 1.0.27rc2 and 1.2.19rc2 [August 4, 2007] - Removed some "#if 0" blocks. - Made a global struct local in pngvcrd.c to make it thread safe. - Issue a png_error() if application attempts to transform a row tht - has not been initialized. - -version 1.0.27rc3 and 1.2.19rc3 [August 9, 2007] - Slightly revised pngvcrd.c - -version 1.0.27rc4 and 1.2.19rc4 [August 9, 2007] - Revised pnggccrd.c debugging change of rc1, which was broken. - Revised scripts/CMakeLists.txt - Change default to PNG_NO_GLOBAL_ARRAYS for MSVC. - Turn off PNG_FLAG_ROW_INIT flag when setting transforms that expand pixels. - -version 1.0.27rc5 and 1.2.19rc5 [August 10, 2007] - Fix typo (missing '"') in pnggccrd.c - Revise handling of png_strtod in recent versions of WINCE - -version 1.0.27rc6 and 1.2.19rc6 [August 15, 2007] - Fix typo (missing ',') in contrib/gregbook/readpng2.c - Undid row initialization error exit added to rc2 and rc4. - -version 1.0.27 and 1.2.19 [August 18, 2007] - Conditionally restored row initialization error exit. - -version 1.2.20beta01 [August 19, 2007] - Fixed problem with compiling pnggccrd.c on Intel-Apple platforms. - Changed png_malloc() to png_malloc_warn() in png_set_sPLT(). - Added PNG_NO_ERROR_TEXT feature, with demo in contrib/pngminim - Removed define PNG_WARN_UNINITIALIZED_ROW 1 /* 0: warning; 1: error */ - because it caused some trouble. - -version 1.2.20beta02 [August 20, 2007] - Avoid compiling pnggccrd.c on Intel-Apple platforms. - -version 1.2.20beta03 [August 20, 2007] - Added "/D PNG_NO_MMX_CODE" to the non-mmx builds of projects/visualc6 - and visualc71. - -version 1.2.20beta04 [August 21, 2007] - Revised pngvcrd.c for improved efficiency (Steve Snyder). - -version 1.2.20rc1 [August 23, 2007] - Revised pngconf.h to set PNG_NO_MMX_CODE for gcc-3.x compilers. - -version 1.2.20rc2 [August 27, 2007] - Revised scripts/CMakeLists.txt - Revised #ifdefs to ensure one and only one of pnggccrd.c, pngvcrd.c, - or part of pngrutil.c is selected. - -version 1.2.20rc3 [August 30, 2007] - Remove a little more code in pngwutil.c when PNG_NO_WRITE_FILTER is selected. - Added /D _CRT_SECURE_NO_WARNINGS to visual6c and visualc71 projects. - Compile png_mmx_support() in png.c even when PNG_NO_MMX_CODE is defined. - Restored a "superfluous" #ifdef that was removed from 1.2.20rc2 pnggccrd.c, - breaking the png_mmx_support() function. - -version 1.2.20rc4 [September 1, 2007] - Removed Intel contributions (MMX, Optimized C). - -version 1.2.20rc5 [September 2, 2007] - Restored configure and Makefile.in to rc3 and put a snippet of code in - pnggccrd.c, to ensure configure makes the same PNG_NO_MMX_CODE selection - -version 1.2.20rc6 [September 2, 2007] - Fixed bugs in scripts/CMakeLists.txt - Removed pngvcrd.c references from msvc projects. - -version 1.0.28 and 1.2.20 [September 8, 2007] - Removed "(NO READ SUPPORT)" from png_get_header_version() string. - -version 1.2.21beta1 [September 14, 2007] - Fixed various mistakes reported by George Cook and Jeff Phillips: - logical vs bitwise NOT in pngrtran.c, bug introduced in 1.2.19rc2 - 16-bit cheap transparency expansion, bug introduced in 1.2.19beta2 - errors with sizeof(unknown_chunk.name), bugs introduced in 1.2.19beta11 - <= compare with unsigned var in pngset.c, should be ==. - -version 1.2.21beta2 [September 18, 2007] - Removed some extraneous typecasts. - -version 1.2.21rc1 [September 25, 2007] - Fixed potential out-of-bounds reads in png_handle_pCAL() and - png_handle_ztXt() ("flayer" results reported by Tavis Ormandy). - -version 1.2.21rc2 [September 26, 2007] - Fixed potential out-of-bounds reads in png_handle_sCAL(), - png_handle_iTXt(), and png_push_read_tEXt(). - Remove some PNG_CONST declarations from pngwutil.c to avoid compiler warnings - Revised makefiles to update paths in libpng.pc properly. - -version 1.2.21rc3 [September 27, 2007] - Revised makefiles to update "Libs" in libpng.pc properly. - -version 1.0.29 and 1.2.21rc3 [October 4, 2007] - No changes. - -version 1.2.22beta1 [October 4, 2007] - Again, fixed logical vs bitwise NOT in pngrtran.c, bug introduced - in 1.2.19rc2 - -version 1.2.22beta2 [October 5, 2007] - Fixed string length error in pngset.c (caused crashes while decoding iCCP) - Add terminating NULL after each instance of png_strncpy(). - -version 1.2.22beta3 [October 6, 2007] - Fix two off-by-one terminating NULL after png_strncpy(). - -version 1.2.22beta4 [October 7, 2007] - Changed some 0 to '\0'. - -version 1.0.30rc1 and 1.2.22rc1 [October 8, 2007] - No changes. - -version 1.0.30 and 1.2.22 [October 13, 2007] - No changes. - -version 1.2.23beta01 [October 15, 2007] - Reduced number of invocations of png_strlen() in pngset.c. - Changed [azAZ09_] to [_abcde...89] in Makefile.am for better localization. - -version 1.2.23beta02 [October 16, 2007] - Eliminated png_strncpy() and png_strcpy() (Pierre Poissinger) - Changed $AN to $(AN) in Makefile.am. - -version 1.2.23beta03 [October 16, 2007] - Fixed off-by-one error in pngset.c - Restore statement to set last character of buffer to \0 in pngerror.c - -version 1.2.23beta04 [October 23, 2007] - Reject attempt to set all-zero cHRM values. - -version 1.2.23beta05 [October 26, 2007] - Add missing quotes in projects/visualc6, lost in version 1.2.20rc3 - -version 1.2.23rc01 [November 2, 2007] - No changes. - -version 1.2.23 [November 6, 2007] - No changes. - -version 1.2.24beta01 [November 19, 2007] - Moved misplaced test for malloc failure in png_set_sPLT(). This bug was - introduced in libpng-1.2.20beta01. - Ifdef out avg_row etc from png.h and pngwrite.c when PNG_NO_WRITE_FILTER - Do not use png_ptr->free_fn and png_ptr->mem_fn in png_destroy_read_struct() - when png_ptr is NULL (Marshall Clow). - Updated handling of symbol prefixes in Makefile.am and configure.ac (Mike - Frysinger). - -version 1.2.24beta02 [November 30, 2007] - Removed a useless test and fixed incorrect test in png_set_cHRM_fixed() - (David Hill). - -version 1.2.24rc01 [December 7, 2007] - No changes. - -version 1.2.24 [December 14, 2007] - Make sure not to redefine _BSD_SOURCE in pngconf.h - Revised gather.sh and makefile.std in contrib/pngminim to avoid compiling - unused files. - -version 1.2.25beta01 [January 7, 2008] - Fixed bug with unknown chunk handling, introduced in version 1.2.17rc2 - -version 1.2.25beta02 [January 10, 2008] - Prevent gamma from being applied twice. - -version 1.2.25rc01 [January 17, 2008] - No changes. - -version 1.2.25beta03 [January 22, 2008] - Fixed some continue-after-malloc-failure errors in pngset.c (David Hill) - Check for info_ptr == NULL in png_read_info() and png_process_data(). - Check for possible use of NULL user_png_ver[] in png_create_read_struct(). - Change "if (swidth == NULL)" to "if (sheight == NULL)" in png_handle_sCAL - (bug introduced in libpng-1.2.4/1.0.13). - Return from png_destroy_read_struct() if png_ptr_ptr is NULL. - Fix overflow of "msg" in png_decompress_chunk(). - -version 1.2.25beta04 [January 26, 2008] - Work around Coverity bug report by slightly refactoring - png_read_push_finish_row() - -version 1.2.25beta05 [January 31, 2008] - Added libpng-1.2.25beta05.tar.lzma to distribution. Get the lzma codec - from . - Added lp1225b05.7z to distribution. Get the 7-zip decoder from - from . - Fixed some broken links in the README file. - -version 1.2.25beta06 [February 6, 2008] - Refactored png_read_push_finish_row() again, trying to satisfy Coverity. - Fixed potential NULL dereference of png_ptr in png_destroy_write_struct(); - clarified potential NULL dereference of png_ptr in png_destroy_read_struct(); - fixed potential NULL dereference of info_ptr in png_handle_bKGD(); - fixed potential NULL dereference of user_png_ver[] in - png_create_write_struct_2(). (Coverity) - -version 1.2.25rc02 [February 10, 2008] - Reset png_ptr->pass in png_read_push_finish_row() before break. - Changed "pass" from png_byte to int. - -version 1.2.25 and 1.0.31 [February 18, 2008] - No changes. - -version 1.2.26beta01 [February 21, 2008] - Added missing "(" in pngmem.c. Bug introduced in libpng-1.2.2/1.0.13 - -version 1.2.26beta02 [March 12, 2008] - Refined error message returned from deflateInit2 in pngwutil.c - Check IHDR length in png_push_read_chunk() before saving it. - -version 1.2.26beta03 [March 16, 2008] - Revised contrib/gregbook to handle premature end-of-file and file - read errors correctly. - -version 1.2.26beta04 [March 18, 2008] - Free png_ptr->big_row_buf and png_ptr->prev_row before allocating - new copies in png_read_start_row(). Bug introduced in libpng-1.2.22. - -version 1.2.26beta05 [March 19, 2008] - Removed extra png_free() added in libpng-1.2.26beta04. - -version 1.2.26beta06 [March 19, 2008] - Avoid reallocating big_row_buf and prev_row when the size does not increase. - -version 1.2.26rc01 [March 26, 2008] - Ifdef out some code that is unused when interlacing is not supported. - -versions 1.0.32 and 1.2.26 [April 2, 2008] - No changes. - -version 1.2.27beta01 [April 12, 2008] - Fixed bug (introduced in libpng-1.0.5h) with handling zero-length - unknown chunks. - Added more information about png_set_keep_unknown_chunks() to the - documentation. - Reject tRNS chunk with out-of-range samples instead of masking off - the invalid high bits as done in since libpng-1.2.19beta5. - -version 1.2.27beta02 [April 13, 2008] - Revised documentation about unknown chunk and user chunk handling. - Keep tRNS chunk with out-of-range samples and issue a png_warning(). - -version 1.2.27beta03 [April 14, 2008] - Added check for NULL ptr in TURBOC version of png_free_default(). - Removed several unnecessary checks for NULL before calling png_free(). - Revised png_set_tRNS() so that calling it twice removes and invalidates - the previous call. - Revised pngtest to check for out-of-range tRNS samples. - -version 1.2.27beta04 [April 18, 2008] - Added AC_LIBTOOL_WIN32_DLL to configure.ac - Rebuilt Makefile.in, aclocal.m4, and configure with autoconf-2.62 - -version 1.2.27beta05 [April 19, 2008] - Added MAINTAINERCLEANFILES variable to Makefile.am - -version 1.2.27beta06 [April 21, 2008] - Avoid changing color_type from GRAY to RGB by - png_set_expand_gray_1_2_4_to_8(). - -version 1.2.27rc01 [April 23, 2008] - Fix broken URL for rfc2083 in png.5 and libpng-*.txt - -version 1.0.33 and 1.2.27 [April 30, 2008] - No changes. - -version 1.0.34 and 1.2.28 [April 30, 2008] - Rebuilt Makefile.in, aclocal.m4, and configure with autoconf-2.61 - due to backward incompatibilities. - Removed a stray object file from contrib/gregbook - -version 1.2.29beta01 [May 1, 2008] - Removed some stray *.diff and *.orig files - -version 1.2.29beta02 [May 1, 2008] - Reverted Makefile.in, aclocal.m4, and configure to the libpng-1.2.26 - versions. - -version 1.2.29beta03 [May 2, 2008] - Added --force to autogen libtoolize options and --force-missing to - automake options. - Changed $(ECHO) to echo in Makefile.am and Makefile.in - Updated all configure files to autoconf-2.62 - Comment out pnggcrd.c code with #ifdef/#endif if using MSC_VER - -version 1.2.29rc01 [May 4, 2008] - No changes. - -version 1.0.35 and 1.2.29 [May 8, 2008] - No changes. - -version 1.0.37 [May 9, 2008] - Updated Makefile.in and configure (omitted version 1.0.36). - -version 1.2.30beta01 [May 29, 2008] - Updated libpng.pc-configure.in and libpng-config.in per debian bug reports. - -version 1.2.30beta02 [June 25, 2008] - Restored png_flush(png_ptr) at the end of png_write_end(), that was - removed from libpng-1.0.9beta03. - -version 1.2.30beta03 [July 6, 2008] - Merged some cosmetic whitespace changes from libpng-1.4.0beta19. - Inline call of png_get_uint_32() in png_get_uint_31(), as in 1.4.0beta19. - Added demo of decoding vpAg and sTER chunks to pngtest.c, from 1.4.0beta19. - Changed PNGMAJ from 0 to 12 in makefile.darwin, which does not like 0. - Added new private function png_read_chunk_header() from 1.4.0beta19. - Merge reading of chunk length and chunk type into a single 8-byte read. - Merge writing of chunk length and chunk type into a single 8-byte write. - -version 1.2.30beta04 [July 10, 2008] - Merged more cosmetic whitespace changes from libpng-1.4.0beta19. - -version 1.0.38rc01, 1.2.30rc01 [July 18, 2008] - No changes. - -version 1.0.38rc02, 1.2.30rc02 [July 21, 2008] - Moved local array "chunkdata" from pngrutil.c to the png_struct, so - it will be freed by png_read_destroy() in case of a read error (Kurt - Christensen). - -version 1.0.38rc03, 1.2.30rc03 [July 21, 2008] - Changed "purpose" and "buffer" to png_ptr->chunkdata to avoid memory leaking. - -version 1.0.38rc04, 1.2.30rc04 [July 22, 2008] - Changed "chunkdata = NULL" to "png_ptr->chunkdata = NULL" several places in - png_decompress_chunk(). - -version 1.0.38rc05, 1.2.30rc05 [July 25, 2008] - Changed all remaining "chunkdata" to "png_ptr->chunkdata" in - png_decompress_chunk() and remove chunkdata from parameter list. - Put a call to png_check_chunk_name() in png_read_chunk_header(). - Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. - Removed two calls to png_check_chunk_name() occuring later in the process. - -version 1.0.38rc06, 1.2.30rc06 [July 29, 2008] - Added a call to png_check_chunk_name() in pngpread.c - Reverted png_check_chunk_name() to accept a name with a lowercase 3rd byte. - -version 1.0.38r07, 1.2.30r07 [August 2, 2008] - Changed "-Wall" to "-W -Wall" in the CFLAGS in all makefiles (Cosmin Truta) - Declared png_ptr "volatile" in pngread.c and pngwrite.c to avoid warnings. - Added code in pngset.c to quiet compiler warnings. - Updated contrib/visupng/cexcept.h to version 2.0.1 - Relocated a misplaced "#endif /* PNG_NO_WRITE_FILTER */" in pngwutil.c - -version 1.0.38r08, 1.2.30r08 [August 2, 2008] - Enclose "volatile" declarations in #ifdef PNG_SETJMP_SUPPORTED (Cosmin). - -version 1.0.38, 1.2.30 [August 14, 2008] - No changes. - -version 1.2.31rc01 [August 19, 2008] - Removed extra crc check at the end of png_handle_cHRM(). Bug introduced - in libpng-1.2.30beta03 (Heiko Nitzsche). - -version 1.2.31rc02 [August 19, 2008] - Added PNG_WRITE_FLUSH_SUPPORTED block around new png_flush() call. - -version 1.2.31rc03 [August 19, 2008] - Added PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED block, off by default, around - new png_flush(). - -version 1.0.39, 1.2.31 [August 21, 2008] - No changes. - -version 1.2.32beta01 [September 6, 2008] - Shortened tIME_string to 29 bytes in pngtest.c (bug introduced in - libpng-1.2.22). - Fixed off-by-one error introduced in png_push_read_zTXt() function in - libpng-1.2.30beta04/pngpread.c (Harald van Dijk) - These bugs have been given the vulnerability id CVE-2008-3964. - -version 1.0.40, 1.2.32 [September 18, 2008] - No changes. - -version 1.2.33beta01 [October 6, 2008] - Revised makefile.darwin to fix shared library numbering. - Change png_set_gray_1_2_4_to_8() to png_set_expand_gray_1_2_4_to_8() - in example.c (debian bug report) - -version 1.2.33rc01 [October 15, 2008] - No changes. - -version 1.0.41rc01, version 1.2.33rc02 [October 23, 2008] - Changed remaining "key" to "png_ptr->chunkdata" in png_handle_tEXt() - to avoid memory leak after memory failure while reading tEXt chunk.` - -version 1.2.33 [October 31, 2008] - No changes. - -version 1.2.34beta01 [November 27, 2008] - Revised png_warning() to write its message on standard output by default - when warning_fn is NULL. This was the behavior prior to libpng-1.2.9beta9. - Fixed string vs pointer-to-string error in png_check_keyword(). - Added png_check_cHRM_fixed() in png.c and moved checking from pngget.c, - pngrutil.c, and pngwrite.c, and eliminated floating point cHRM checking. - Added check for zero-area RGB cHRM triangle in png_check_cHRM_fixed(). - In png_check_cHRM_fixed(), ensure white_y is > 0, and removed redundant - check for all-zero coordinates that is detected by the triangle check. - Revised png_warning() to write its message on standard output by default - when warning_fn is NULL. - -version 1.2.34beta02 [November 28, 2008] - Corrected off-by-one error in bKGD validity check in png_write_bKGD() - and in png_handle_bKGD(). - -version 1.2.34beta03 [December 1, 2008] - Revised bKGD validity check to use >= x instead of > x + 1 - Merged with png_debug from libpng-1.4.0 to remove newlines. - -version 1.2.34beta04 [December 2, 2008] - More merging with png_debug from libpng-1.4.0 to remove newlines. - -version 1.2.34beta05 [December 5, 2008] - Removed redundant check for key==NULL before calling png_check_keyword() - to ensure that new_key gets initialized and removed extra warning - (Arvan Pritchard). - -version 1.2.34beta06 [December 9, 2008] - In png_write_png(), respect the placement of the filler bytes in an earlier - call to png_set_filler() (Jim Barry). - -version 1.2.34beta07 [December 9, 2008] - Undid previous change and added PNG_TRANSFORM_STRIP_FILLER_BEFORE and - PNG_TRANSFORM_STRIP_FILLER_AFTER conditionals and deprecated - PNG_TRANSFORM_STRIP_FILLER (Jim Barry). - -version 1.0.42rc01, 1.2.34rc01 [December 11, 2008] - No changes. - -version 1.0.42, 1.2.34 [December 18, 2008] - No changes. - -version 1.2.35beta01 [February 4, 2009] - Zero out some arrays of pointers after png_malloc(). (Tavis Ormandy) - -version 1.2.35beta02 [February 4, 2009] - Zero out more arrays of pointers after png_malloc(). - -version 1.2.35beta03 [February 5, 2009] - Use png_memset() instead of a loop to intialize pointers. We realize - this will not work on platforms where the NULL pointer is not all zeroes. - -version 1.2.35rc01 [February 11, 2009] - No changes. - -version 1.2.35rc02 [February 12, 2009] - Fix typo in new png_memset call in pngset.c (png_color should be png_charp) - -version 1.0.43 and 1.2.35 [February 14, 2009] - No changes. - -version 1.2.36beta01 [February 28, 2009] - Revised comments in png_set_read_fn() and png_set_write_fn(). - Revised order of #ifdef's and indentation in png_debug definitions of png.h - bug introduced in libpng-1.2.34. - -version 1.2.36beta02 [March 21, 2009] - Use png_memset() after png_malloc() of big_row_buf when reading an - interlaced file, to avoid a possible UMR. - Undid recent revision of PNG_NO_STDIO version of png_write_flush(). Users - having trouble with fflush() can build with PNG_NO_WRITE_FLUSH defined. - Revised libpng*.txt documentation about use of png_write_flush(). - Removed fflush() from pngtest.c. - Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h - -version 1.2.36beta03 [March 27, 2009] - Relocated misplaced PNG_1_0_X define in png.h that caused the prototype - for png_set_strip_error_numbers() to be omitted from PNG_NO_ASSEMBLER_CODE - builds. This bug was introduced in libpng-1.2.15beta4. - Added a section on differences between 1.0.x and 1.2.x to libpng.3/libpng.txt - -version 1.2.36beta04 [April 5, 2009] - Fixed potential memory leak of "new_name" in png_write_iCCP() (Ralph Giles) - -version 1.2.36beta05 [April 24, 2009] - Added "ifndef PNG_SKIP_SETJMP_CHECK" block in pngconf.h to allow - application code writers to bypass the check for multiple inclusion - of setjmp.h when they know that it is safe to ignore the situation. - Made some cosmetic changes to whitespace in pngtest output. - Renamed "user_chunk_data" to "my_user_chunk_data" in pngtest.c to suppress - "shadowed declaration" warning from gcc-4.3.3. - Renamed "gamma" to "png_gamma" in pngset.c to avoid "shadowed declaration" - warning about a global "gamma" variable in math.h on some platforms. - -version 1.2.36rc01 [April 30, 2009] - No changes. - -version 1.0.44 and 1.2.36 [May 7, 2009] - No changes. - -version 1.2.37beta01 [May 14, 2009] - Fixed inconsistency in pngrutil.c, introduced in libpng-1.2.36. The - memset() was using "png_ptr->rowbytes" instead of "row_bytes", which - the corresponding png_malloc() uses (Joe Drew). - Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri) - Updated some of the makefiles in the scripts directory (merged with - those in libpng-1.4.0beta57). - -version 1.2.37beta02 [May 19, 2009] - Fixed typo in libpng documentation (FILTER_AVE should be FILTER_AVG) - Relocated misplaced #endif in pngwrite.c, sCAL chunk handler. - Conditionally compile png_read_finish_row() which is not used by - progressive readers. - Added contrib/pngminim/preader to demonstrate building minimal progressive - decoder, based on contrib/gregbook with embedded libpng and zlib. - -version 1.2.37beta03 [May 20, 2009] - In contrib/pngminim/*, renamed "makefile.std" to "makefile", since there - is only one makefile in those directories, and revised the README files - accordingly. - Reformated sources in libpng style (3-space indentation, comment format) - -version 1.2.37rc01 [May 27, 2009] - No changes. - -versions 1.2.37 and 1.0.45 [June 4, 2009] - Reformatted several remaining "else statement;" and "if () statement;" into - two lines. - Added "#define PNG_NO_WRITE_SWAP" to contrib/pngminim/encoder/pngusr.h - and "define PNG_NO_READ_SWAP" to decoder/pngusr.h and preader/pngusr.h - Added sections about the git repository and our coding style to the - documentation (merged from libpng-1.4.0beta62) - Added a section to the libpng documentation about using png_get_io_ptr() - in configure scripts to detect the presence of libpng. - -version 1.2.38beta01 [June 17, 2009] - Revised libpng*.txt and libpng.3 to mention calling png_set_IHDR() - multiple times and to specify the sample order in the tRNS chunk, - because the ISO PNG specification has a typo in the tRNS table. - Changed several PNG_UNKNOWN_CHUNK_SUPPORTED to - PNG_HANDLE_AS_UNKNOWN_SUPPORTED, to make the png_set_keep mechanism - available for ignoring known chunks even when not saving unknown chunks. - Adopted preference for consistent use of "#ifdef" and "#ifndef" versus - "#if defined()" and "if !defined()" where possible. - Added PNG_NO_HANDLE_AS_UNKNOWN in the PNG_LEGACY_SUPPORTED block of - pngconf.h, and moved the various unknown chunk macro definitions - outside of the PNG_READ|WRITE_ANCILLARY_CHUNK_SUPPORTED blocks. - -version 1.0.46 [June 18, 2009] - Removed some editing cruft from scripts/libpng.pc.in and some makefiles. - -version 1.2.38rc01 [June 24, 2009] - No changes. - -version 1.2.38rc02 [June 29, 2009] - Added a reference to the libpng license in each source file. - -version 1.2.38rc03 [July 11, 2009] - Revised references to the libpng license in pngconf.h and contrib/visupng - source files. - Rebuilt configure scripts with autoconf-2.63. - -version 1.0.47 and 1.2.38 [July 16, 2009] - No changes. - -version 1.2.39beta01 [July 25, 2009] - Added a prototype for png_64bit_product() in png.c - -version 1.2.39beta02 [July 27, 2009] - Avoid a possible NULL dereference in debug build, in png_set_text_2(). - (bug introduced in libpng-0.95, discovered by Evan Rouault) - -version 1.2.39beta03 [July 29, 2009] - Relocated new png_64_bit_product() prototype into png.h - Expanded the information about prototypes in the libpng style section of - the documentation. - Rebuilt configure scripts with autoconf-2.64. - -version 1.2.39beta04 [August 1, 2009] - Replaced *.tar.lzma with *.txz in distribution. Get the xz codec - from . - -version 1.2.39beta05 [August 1, 2009] - Reject attempt to write iCCP chunk with negative embedded profile length - (JD Chen) - -version 1.2.39c01 [August 6, 2009] - No changes. - -version 1.2.39 and 1.0.48 [August 13, 2009] - No changes. - -version 1.2.40beta01 [August 20, 2009] - Removed an extra png_debug() recently added to png_write_find_filter(). - Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. - -version 1.2.40rc01 [September 2, 2009] - Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) - -version 1.2.40 and 1.0.49 [September 2, 2009] - No changes. - -version 1.0.50 [September 10, 2009] - Removed some editing cruft from pngset.c and pngwutil.c. - -version 1.2.41beta01 [September 25, 2009] - Moved redundant IHDR checking into new png_check_IHDR() in png.c - and report all errors found in the IHDR data. - Eliminated useless call to png_check_cHRM() from pngset.c - Expanded TAB characters in pngrtran.c - -version 1.2.41beta02 [September 30, 2009] - Revised png_check_IHDR(). - -version 1.2.41beta03 [October 1, 2009] - Revised png_check_IHDR() again, to check info_ptr members instead of - the contents of the returned parameters. - -version 1.2.41beta04 [October 7, 2009] - Added "xcode" project similar one already in libpng-1.4.0beta (Alam Arias). - Ported some cosmetic changes from libpng-1.4.0beta86. - Eliminated a shadowed declaration of "pp" in png_handle_sPLT(). - -version 1.2.41beta05 [October 17, 2009] - Revised pngconf.h to make it easier to enable iTXt support. From libpng - version 1.2.9 through 1.2.40, defining PNG_iTXt_SUPPORTED did not work - as expected. - Ported some cosmetic changes from libpng-1.4.0beta87, changing - many "#if defined(x)" to "#ifdef x". - -version 1.2.41beta06 [October 18, 2009] - Restored PNG_USE_LOCAL_ARRAYS code in pngread.c that was inadvertently - deleted in libpng-1.2.41beta05. - Converted all PNG_NO_* tests to PNG_*_SUPPORTED everywhere except pngconf.h - as in libpng-1.4.0beta78 and later. - -version 1.2.41beta07 [October 21, 2009] - Ported some cosmetic changes from libpng-1.4.0rc01, changing - many "#if defined(x)" to "#ifdef x" in png.h and pngconf.h. - -version 1.2.41beta08 [October 30, 2009] - Ported from libpng-1.4.0rc01: png_calloc(), png_get_io_chunk_name(), - png_get_io_state(), png_set_user_cache_max(), png_get_user_cache_max(), - png_set_premultiply_alpha, and png_do_read_premultiply_alpha(). - Relocated png_do_chop() ahead of building gamma tables in pngrtran.c - This avoids building 16-bit gamma tables unnecessarily. - -version 1.2.41beta09 [November 1, 2009] - Removed a harmless extra png_set_invert_alpha() from pngwrite.c - More bugfixes and improvements to CMakeLists.txt (Philip Lowman) - Moved CMakeLists.txt from scripts into the main libpng directory. - Apply png_user_chunk_cache_max within png_decompress_chunk(). - Merged libpng-1.2.41.txt with libpng-1.4.0.txt where appropriate. - -version 1.2.41beta10 [November 1, 2009] - Enabled iTXt support by default. To ensure binary compatibility with - previous versions, the "lang" and "lang_key" members will be assumed - to be omitted from previous versions unless the current libpng - version was built with PNG_iTXt_SUPPORTED (which is otherwise no - longer necessary to gain iTXt support), as a signal that the user has - been building previous versions with PNG_iTXt_SUPPORTED as well. - -version 1.2.41beta11 [November 2, 2009] - Store user's user_png_ver in new png_ptr->user_png_ver element. - Revised iTXt support. To ensure binary compatibility with - previous versions, the "lang" and "lang_key" members will be assumed - to be omitted from versions prior to 1.2.41beta11 whenever there is a - library mismatch. - -version 1.2.41beta12 [November 2, 2009] - Free png_ptr->user_png_ver when destroying png_ptr. - -version 1.2.41beta13 [November 3, 2009] - Updated scripts/pngw32.def and projects/wince/png32ce.def - Copied projects/wince/png32ce.def to the scripts directory. - Added scripts/makefile.wce - Patched ltmain.sh for wince support. - Added PNG_CONVERT_tIME_SUPPORTED macro. - -version 1.2.41beta14 [November 8, 2009] - versions 1.2.41beta05 through 1.2.41beta13 were abandoned. - The 1.0.x/1.2.x series will only receive security updates from now on. - Make inclusion of time.h in pngconf.h depend on PNG_CONVERT_tIME_SUPPORTED - Make #define PNG_CONVERT_tIME_SUPPORTED depend on PNG_WRITE_tIME_SUPPORTED - Reverted iTXt compatibility stuff from 1.2.41beta05, 1.2.41beta11, and - 1.2.41beta12. - Reverted IOSTATE feature, user_cache_max, and premultiply_alpha features - from 1.2.41beta08. - Retained png_calloc() from 1.2.41beta08 but as a non-exported function, - and removed reference to png_calloc from scripts/*.def - -version 1.2.41beta15 [November 8, 2009] - Added PNG_DEPSTRUCT, PNG_DEPRECATED, PNG_USE_RESULT, PNG_NORETURN, and - PNG_ALLOCATED macros to detect deprecated direct access to the - png_struct or info_struct members and other deprecated usage in - applications (John Bowler). - Updated scripts/makefile* to add "-DPNG_CONFIGURE_LIBPNG" to CFLAGS, - to prevent warnings about direct access to png structs by libpng - functions while building libpng. They need to be tested, especially - those using compilers other than gcc. - Updated projects/visualc6 and visualc71 with "/d PNG_CONFIGURE_LIBPNG". - -version 1.2.41beta16 [November 9, 2009] - Removed three direct references to read_info_ptr members in pngtest.c - that were detected by the new PNG_DEPSTRUCT macro. - Only #define PNG_DEPSTRUCT, etc. in pngconf.h if not already defined. - -version 1.2.41beta17 [November 10, 2009] - Updated CMakeLists.txt to add "-DPNG_CONFIGURE_LIBPNG" to the definitions. - Marked deprecated function prototypes with PNG_DEPRECATED. - Marked memory allocation function prototypes with PNG_ALLOCATED. - Changed png_check_sig() to !png_sig_cmp() in contrib programs. - Corrected the png_get_IHDR() call in contrib/gregbook/readpng2.c - Added "-DPNG_CONFIGURE_LIBPNG" to the contrib/pngminum makefiles. - -version 1.2.41beta18 [November 11, 2009] - Renamed scripts/makefile.wce to scripts/makefile.cegcc - Marked nonexported functions with PNG_PRIVATE macro. - -version 1.2.41rc01 and 1.0.51rc01 [November 18, 2009] - Revised scripts/*.def to reflect functions actually exported by libpng. - Updated the copyright year in scripts/pngw32.rc from 2004 to 2009. - Moved descriptions of makefiles and other scripts out of INSTALL into - scripts/README.txt - -version 1.2.41rc02 [November 22, 2009] - Rebuilt the configure scripts with autoconf-2.65 - -version 1.2.41rc03 [November 25, 2009] - Disabled the new pedantic warnings about deprecated function use - and deprecated structure access unless the user defines - PNG_PEDANTIC_WARNINGS. - Added "#define PNG_NO_PEDANTIC_WARNINGS" in the libpng source files. - Removed "-DPNG_CONFIGURE_LIBPNG" from the makefiles and projects. - -version 1.2.41 and 1.0.51 [December 3, 2009] - Updated the list of files and made some cosmetic changes in README. - -version 1.2.42beta01 [December 4, 2009] - Removed "#define PNG_NO_ERROR_NUMBERS" that was inadvertently added - to pngconf.h in version 1.2.41. - Revised scripts/makefile.netbsd, makefile.openbsd, and makefile.sco - to put png.h and pngconf.h in $prefix/include, like the other scripts, - instead of in $prefix/include/libpng. Also revised makefile.sco - to put them in $prefix/include/libpng12 instead of in - $prefix/include/libpng/libpng12. - Removed leftover "-DPNG_CONFIGURE_LIBPNG" from scripts/makefile.darwin - -version 1.2.42beta02 [December 11, 2009] - Removed leftover "-DPNG_CONFIGURE_LIBPNG" from contrib/pngminim/*/makefile - Relocated png_do_chop() to its original position in pngrtran.c. The - change in version 1.2.41beta08 caused transparency to be handled wrong - in some 16-bit datastreams (Yusaku Sugai). - -version 1.2.42rc01 [December 17, 2009] - No changes. - -version 1.2.42rc02 [December 22, 2009] - Renamed libpng-pc.in back to libpng.pc.in and revised CMakeLists.txt - (revising changes made in 1.2.41beta17 and 1.2.41rc01) - -version 1.2.42rc03 [December 25, 2009] - Swapped PNG_UNKNOWN_CHUNKS_SUPPORTED and PNG_HANDLE_AS_UNKNOWN_SUPPORTED - in pngset.c to be consistent with other changes in version 1.2.38. - -version 1.2.42rc04 [January 1, 2010] - Marked png_memcpy_check() and png_memset_check() PNG_DEPRECATED. - Updated copyright year. - -version 1.2.42rc05 [January 2, 2010] - Avoid deprecated references to png_ptr-io_ptr and png_ptr->error_ptr - in pngtest.c - -version 1.2.42 and 1.0.52 [January 3, 2010] - No changes. - -version 1.2.43beta01 [January 27, 2010] - Updated CMakeLists.txt for consistent indentation and to avoid an - unclosed if-statement warning (Philip Lowman). - Removed "#ifdef PNG_1_0_X / #endif" surrounding - PNG_READ_16_TO_8_SUPPORTED and PNG_READ_GRAY_TO_RGB_SUPPORTED - in pngconf.h. These were added in libpng-1.2.41beta08 and libpng-1.0.51, - which introduced a binary incompatibility with libpng-1.0.50. - Backported new png_decompress_chunk() algorithm from libpng-1.4.1. - -version 1.2.43beta02 [February 1, 2010] - Backported two-pass png_decompress_chunk() algorithm from libpng-1.4.1. - -version 1.2.43beta03 [February 6, 2010] - Backported fast png_push_save_buffer() algorithm from libpng-1.4.1. - Backported some cosmetic changes from libpng-1.4.1. - -version 1.2.43beta04 [February 8, 2010] - Reverted recent changes to png_push_save-buffer(). - Removed PNGAPI declaration of png_calloc() and png_write_sig() in - 1ibpng-1.2.X, introduced by mistake in libpng-1.2.41. - Return allocated "old_buffer" in png_push_save_buffer() before png_error() - to avoid a potential memory leak. - -version 1.2.43beta05 [February 8, 2010] - Ported rewritten png_decompress_chunk() by John Bowler from libpng-1.4.1. - -version 1.0.53rc01 and 1.2.43rc01 [February 18, 2010] - No changes. - -version 1.0.53rc02 and 1.2.43rc02 [February 19, 2010] - Define _ALL_SOURCE in configure.ac, makefile.aix, and CMakeLists.txt - when using AIX compiler. - -version 1.0.53 and 1.2.43 [February 25, 2010] - Removed unused gzio.c from contrib/pngminim gather and makefile scripts - -version 1.2.44beta01 [June 18, 2010] - In pngpread.c: png_push_have_row() add check for new_row > height - Removed the now-redundant check for out-of-bounds new_row from example.c - -version 1.2.44beta02 [June 19, 2010] - In pngpread.c: png_push_process_row() add check for too many rows. - Removed the now-redundant check for new_row > height in png_push_have_row(). - -version 1.2.44beta03 [June 20, 2010] - Rewrote png_process_IDAT_data() to consistently treat extra data as warnings - and handle end conditions more cleanly. - Removed the new (beta02) check in png_push_process_row(). - -version 1.2.44rc01 [June 21, 2010] - Revised some comments in png_process_IDAT_data(). - -version 1.2.44rc02 [June 22, 2010] - Stop memory leak when reading a malformed sCAL chunk. - -version 1.2.44rc03 [June 23, 2010] - Revised pngpread.c patch of beta05 to avoid an endless loop. - -version 1.2.44 [June 26, 2010] - Updated some of the "last changed" dates. - -version 1.2.45beta01 [June 7, 2011] - Fixed uninitialized memory read in png_format_buffer() (Bug - report by Frank Busse, related to CVE-2004-0421). - Pass "" instead of '\0' to png_default_error() in png_err(). This mistake - was introduced in libpng-1.2.20beta01. - Check for up->location !PNG_AFTER_IDAT when writing unknown chunks - before IDAT. - Ported bugfix in pngrtran.c from 1.5.3: when expanding a paletted image, - always expand to RGBA if transparency is present. - -version 1.2.45beta02 [June 8, 2011] - Check for integer overflow in png_set_rgb_to_gray(). - -version 1.2.45beta03 [June 19, 2011] - Check for sCAL chunk too short. - -version 1.2.45rc01 and 1.0.55rc01 [June 30, 2011] - Updated "last changed" dates and copyright year. - -version 1.2.45 and 1.0.55 [July 7, 2011] - No changes. - -version 1.2.46rc01 and 1.0.56rc01 [July 8, 2011] - Reverted changes to Makefile.am and Makefile.in to libpng-1.2.44 versions. - -version 1.2.46rc02 and 1.0.56rc02 [July 8, 2011] - Added CMakeLists.txt, projects/xcode, and pnggccrd.c to EXTRA_DIST in - Makefile.am and Makefile.in - -version 1.2.46 and 1.0.56 [July 9, 2011] - Udated copyright year to 2011. - -version 1.2.47beta01 [February 17, 2012] - Updated contrib/pngminus/makefile.std (Samuli Souminen) - -version 1.0.57rc01 and 1.2.47rc01 [February 17, 2012] - Fixed CVE-2011-3026 buffer overrun bug. This bug was introduced when - iCCP chunk support was added at libpng-1.0.6. - -version 1.0.57 and 1.2.47 [February 18, 2012] - No changes. - -version 1.2.48beta01 [February 27, 2012] - Removed two useless #ifdef directives from pngread.c and one from pngrutil.c - Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from - pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; - now that png_ptr->buffer is inaccessible to applications, the special - handling is no longer useful. - Fixed bug with png_handle_hIST with odd chunk length (Frank Busse). - Fixed incorrect type (int copy should be png_size_t copy) in png_inflate(). - Fixed off-by-one bug in png_handle_sCAL() when using fixed point arithmetic, - causing out-of-bounds read in png_set_sCAL() because of failure to copy - the string terminators. This bug was introduced in libpng-1.0.6 (Frank - Busse). - -version 1.2.48rc01 [March 2, 2012] - Removed the png_free() of unused png_ptr->current_text from pngread.c. - Added libpng license text to pnggccrd.c and pngvcrd.c (requested by Chrome). - -version 1.2.48rc02 [March 2, 2012] - Removed all of the assembler code from pnggccrd.c and just "return 2;". - -version 1.0.58 and 1.2.48 [March 8, 2012] - No changes. - -version 1.0.59 and 1.2.49 [March 29, 2012] - Revised png_set_text_2() to avoid potential memory corruption (fixes - CVE-2011-3048, also known as CVE-2012-3425). - Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. - -version 1.0.60 and 1.2.50 [July 9, 2012] - Changed "a+w" to "u+w" in Makefile.in to fix CVE-2012-3386. - -version 1.2.51beta01 [January 22, 2013] - Ignore, with a warning, out-of-range value of num_trans in png_set_tRNS(). - Replaced AM_CONFIG_HEADER(config.h) with AC_CONFIG_HEADERS([config.h]) - in configure.ac - Changed default value of PNG_USER_CACHE_MAX from 0 to 32767 in pngconf.h. - -version 1.2.51beta02 [June 13, 2013] - Avoid a possible memory leak in contrib/gregbook/readpng.c - Revised libpng.3 so that "doclifter" can process it. - -version 1.2.51beta03 [January 1, 2014] - Changed '"%s"m' to '"%s" m' in png_debug macros to improve portability - among compilers. - Rebuilt the configure scripts with autoconf-2.69 and automake-1.14.1 - -version 1.2.51beta04 [January 10, 2014] - Removed potentially misleading warning from png_check_IHDR(). - -version 1.2.51beta05 [January 22, 2014] - Quiet set-but-not-used warnings in pngset.c - -version 1.2.51rc01 [January 28, 2014] - No changes. - -version 1.2.51rc02 [January 30, 2014] - Quiet an uninitialized memory warning from VC2013 in png_get_png(). - -version 1.2.51rc03 [February 3, 2014] - Quiet unused variable warnings from clang by porting PNG_UNUSED() from - libpng-1.4.6. - -version 1.2.51rc04 [February 3, 2014] - Added -DZ_SOLO to CFLAGS in contrib/pngminim/*/makefile - -version 1.0.61 and 1.2.51 [February 6, 2014] - Added an #ifdef PNG_FIXED_POINT_SUPPORTED/#endif in pngset.c - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) -or to glennrp at users.sourceforge.net - -Glenn R-P -#endif +#if 0 +CHANGES - changes for libpng + +version 0.2 + added reader into png.h + fixed small problems in stub file + +version 0.3 + added pull reader + split up pngwrite.c to several files + added pnglib.txt + added example.c + cleaned up writer, adding a few new transformations + fixed some bugs in writer + interfaced with zlib 0.5 + added K&R support + added check for 64 KB blocks for 16 bit machines + +version 0.4 + cleaned up code and commented code + simplified time handling into png_time + created png_color_16 and png_color_8 to handle color needs + cleaned up color type defines + fixed various bugs + made various names more consistent + interfaced with zlib 0.71 + cleaned up zTXt reader and writer (using zlib's Reset functions) + split transformations into pngrtran.c and pngwtran.c + +version 0.5 + interfaced with zlib 0.8 + fixed many reading and writing bugs + saved using 3 spaces instead of tabs + +version 0.6 + added png_large_malloc() and png_large_free() + added png_size_t + cleaned up some compiler warnings + added png_start_read_image() + +version 0.7 + cleaned up lots of bugs + finished dithering and other stuff + added test program + changed name from pnglib to libpng + +version 0.71 [June, 1995] + changed pngtest.png for zlib 0.93 + fixed error in libpng.txt and example.c + +version 0.8 + cleaned up some bugs + added png_set_filler() + split up pngstub.c into pngmem.c, pngio.c, and pngerror.c + added #define's to remove unwanted code + moved png_info_init() to png.c + added old_size into png_realloc() + added functions to manually set filtering and compression info + changed compression parameters based on image type + optimized filter selection code + added version info + changed external functions passing floats to doubles (k&r problems?) + put all the configurable stuff in pngconf.h + enabled png_set_shift to work with paletted images on read + added png_read_update_info() - updates info structure with + transformations + +version 0.81 [August, 1995] + incorporated Tim Wegner's medium model code (thanks, Tim) + +version 0.82 [September, 1995] + [unspecified changes] + +version 0.85 [December, 1995] + added more medium model code (almost everything's a far) + added i/o, error, and memory callback functions + fixed some bugs (16 bit, 4 bit interlaced, etc.) + added first run progressive reader (barely tested) + +version 0.86 [January, 1996] + fixed bugs + improved documentation + +version 0.87 [January, 1996] + fixed medium model bugs + fixed other bugs introduced in 0.85 and 0.86 + added some minor documentation + +version 0.88 [January, 1996] + fixed progressive bugs + replaced tabs with spaces + cleaned up documentation + added callbacks for read/write and warning/error functions + +version 0.89 [July, 1996] + added new initialization API to make libpng work better with shared libs + we now have png_create_read_struct(), png_create_write_struct(), + png_create_info_struct(), png_destroy_read_struct(), and + png_destroy_write_struct() instead of the separate calls to + malloc and png_read_init(), png_info_init(), and png_write_init() + changed warning/error callback functions to fix bug - this means you + should use the new initialization API if you were using the old + png_set_message_fn() calls, and that the old API no longer exists + so that people are aware that they need to change their code + changed filter selection API to allow selection of multiple filters + since it didn't work in previous versions of libpng anyways + optimized filter selection code + fixed png_set_background() to allow using an arbitrary RGB color for + paletted images + fixed gamma and background correction for paletted images, so + png_correct_palette is not needed unless you are correcting an + external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED + in pngconf.h) - if nobody uses this, it may disappear in the future. + fixed bug with Borland 64K memory allocation (Alexander Lehmann) + fixed bug in interlace handling (Smarasderagd, I think) + added more error checking for writing and image to reduce invalid files + separated read and write functions so that they won't both be linked + into a binary when only reading or writing functionality is used + new pngtest image also has interlacing and zTXt + updated documentation to reflect new API + +version 0.90 [January, 1997] + made CRC errors/warnings on critical and ancillary chunks configurable + libpng will use the zlib CRC routines by (compile-time) default + changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) + added external C++ wrapper statements to png.h (Gilles Dauphin) + allow PNG file to be read when some or all of file signature has already + been read from the beginning of the stream. ****This affects the size + of info_struct and invalidates all programs that use a shared libpng**** + fixed png_filler() declarations + fixed? background color conversions + fixed order of error function pointers to match documentation + current chunk name is now available in png_struct to reduce the number + of nearly identical error messages (will simplify multi-lingual + support when available) + try to get ready for unknown-chunk callback functions: + - previously read critical chunks are flagged, so the chunk handling + routines can determine if the chunk is in the right place + - all chunk handling routines have the same prototypes, so we will + be able to handle all chunks via a callback mechanism + try to fix Linux "setjmp" buffer size problems + removed png_large_malloc, png_large_free, and png_realloc functions. + +version 0.95 [March, 1997] + fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never + fixed bug in PNG file signature compares when start != 0 + changed parameter type of png_set_filler(...filler...) from png_byte + to png_uint_32 + added test for MACOS to ensure that both math.h and fp.h are not #included + added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) + added "packswap" transformation, which changes the endianness of + packed-pixel bytes (Kevin Bracey) + added "strip_alpha" transformation, which removes the alpha channel of + input images without using it (not necessarily a good idea) + added "swap_alpha" transformation, which puts the alpha channel in front + of the color bytes instead of after + removed all implicit variable tests which assume NULL == 0 (I think) + changed several variables to "png_size_t" to show 16/32-bit limitations + added new pCAL chunk read/write support + added experimental filter selection weighting (Greg Roelofs) + removed old png_set_rgbx() and png_set_xrgb() functions that have been + obsolete for about 2 years now (use png_set_filler() instead) + added macros to read 16- and 32-bit ints directly from buffer, to be + used only on those systems that support it (namely PowerPC and 680x0) + With some testing, this may become the default for MACOS/PPC systems. + only calculate CRC on data if we are going to use it + added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? + added macros for simple libpng debugging output selectable at compile time + removed PNG_READ_END_MODE in progressive reader (Smarasderagd) + more description of info_struct in libpng.txt and png.h + more instructions in example.c + more chunk types tested in pngtest.c + renamed pngrcb.c to pngset.c, and all png_read_ functions to be + png_set_. We now have corresponding png_get_ + functions in pngget.c to get information in info_ptr. This isolates + the application from the internal organization of png_info_struct + (good for shared library implementations). + +version 0.96 [May, 1997] + fixed serious bug with < 8bpp images introduced in 0.95 + fixed 256-color transparency bug (Greg Roelofs) + fixed up documentation (Greg Roelofs, Laszlo Nyul) + fixed "error" in pngconf.h for Linux setjmp() behaviour + fixed DOS medium model support (Tim Wegner) + fixed png_check_keyword() for case with error in static string text + added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) + added typecasts to quiet compiler errors + added more debugging info + +version 0.97 [January, 1998] + removed PNG_USE_OWN_CRC capability + relocated png_set_crc_action from pngrutil.c to pngrtran.c + fixed typecasts of "new_key", etc. (Andreas Dilger) + added RFC 1152 [sic] date support + fixed bug in gamma handling of 4-bit grayscale + added 2-bit grayscale gamma handling (Glenn R-P) + added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) + minor corrections in libpng.txt + added simple sRGB support (Glenn R-P) + easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; + all configurable options can be selected from command-line instead + of having to edit pngconf.h (Glenn R-P) + fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) + added more conditions for png_do_background, to avoid changing + black pixels to background when a background is supplied and + no pixels are transparent + repaired PNG_NO_STDIO behaviour + tested NODIV support and made it default behaviour (Greg Roelofs) + added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) + regularized version numbering scheme and bumped shared-library major + version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs) + +version 0.98 [January, 1998] + cleaned up some typos in libpng.txt and in code documentation + fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) + cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c + changed recommendation about file_gamma for PC images to .51 from .45, + in example.c and libpng.txt, added comments to distinguish between + screen_gamma, viewing_gamma, and display_gamma. + changed all references to RFC1152 to read RFC1123 and changed the + PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED + added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) + changed srgb_intent from png_byte to int to avoid compiler bugs + +version 0.99 [January 30, 1998] + free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) + fixed a longstanding "packswap" bug in pngtrans.c + fixed some inconsistencies in pngconf.h that prevented compiling with + PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined + fixed some typos and made other minor rearrangement of libpng.txt (Andreas) + changed recommendation about file_gamma for PC images to .50 from .51 in + example.c and libpng.txt, and changed file_gamma for sRGB images to .45 + added a number of functions to access information from the png structure + png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) + added TARGET_MACOS similar to zlib-1.0.8 + define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined + added type casting to all png_malloc() function calls +version 0.99a [January 31, 1998] + Added type casts and parentheses to all returns that return a value.(Tim W.) +version 0.99b [February 4, 1998] + Added type cast png_uint_32 on malloc function calls where needed. + Changed type of num_hist from png_uint_32 to int (same as num_palette). + Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. + Renamed makefile.elf to makefile.lnx. +version 0.99c [February 7, 1998] + More type casting. Removed erroneous overflow test in pngmem.c. + Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. + Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. +version 0.99d [February 11, 1998] + Renamed "far_to_near()" "png_far_to_near()" + Revised libpng.3 + Version 99c "buffered" operations didn't work as intended. Replaced them + with png_memcpy_check() and png_memset_check(). + Added many "if (png_ptr == NULL) return" to quell compiler warnings about + unused png_ptr, mostly in pngget.c and pngset.c. + Check for overlength tRNS chunk present when indexed-color PLTE is read. + Cleaned up spelling errors in libpng.3/libpng.txt + Corrected a problem with png_get_tRNS() which returned undefined trans array +version 0.99e [February 28, 1998] + Corrected png_get_tRNS() again. + Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". + Touched up example.c to make more of it compileable, although the entire + file still can't be compiled (Willem van Schaik) + Fixed a bug in png_do_shift() (Bryan Tsai) + Added a space in png.h prototype for png_write_chunk_start() + Replaced pngtest.png with one created with zlib 1.1.1 + Changed pngtest to report PASS even when file size is different (Jean-loup G.) + Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) +version 0.99f [March 5, 1998] + Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) + Moved makefiles into a "scripts" directory, and added INSTALL instruction file + Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) + Added pointers to "note on libpng versions" in makefile.lnx and README + Added row callback feature when reading and writing nonprogressive rows + and added a test of this feature in pngtest.c + Added user transform callbacks, with test of the feature in pngtest.c +version 0.99g [March 6, 1998, morning] + Minor changes to pngtest.c to suppress compiler warnings. + Removed "beta" language from documentation. +version 0.99h [March 6, 1998, evening] + Minor changes to previous minor changes to pngtest.c + Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED + and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro + Added user transform capability + +version 1.00 [March 7, 1998] + Changed several typedefs in pngrutil.c + Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) + replaced "while(1)" with "for(;;)" + added PNGARG() to prototypes in pngtest.c and removed some prototypes + updated some of the makefiles (Tom Lane) + changed some typedefs (s_start, etc.) in pngrutil.c + fixed dimensions of "short_months" array in pngwrite.c + Replaced ansi2knr.c with the one from jpeg-v6 + +version 1.0.0 [March 8, 1998] + Changed name from 1.00 to 1.0.0 (Adam Costello) + Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) +version 1.0.0a [March 9, 1998] + Fixed three bugs in pngrtran.c to make gamma+background handling consistent + (Greg Roelofs) + Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz + for major, minor, and bugfix releases. This is 10001. (Adam Costello, + Tom Lane) + Make months range from 1-12 in png_convert_to_rfc1123 +version 1.0.0b [March 13, 1998] + Quieted compiler complaints about two empty "for" loops in pngrutil.c + Minor changes to makefile.s2x + Removed #ifdef/#endif around a png_free() in pngread.c + +version 1.0.1 [March 14, 1998] + Changed makefile.s2x to reduce security risk of using a relative pathname + Fixed some typos in the documentation (Greg). + Fixed a problem with value of "channels" returned by png_read_update_info() +version 1.0.1a [April 21, 1998] + Optimized Paeth calculations by replacing abs() function calls with intrinsics + plus other loop optimizations. Improves avg decoding speed by about 20%. + Commented out i386istic "align" compiler flags in makefile.lnx. + Reduced the default warning level in some makefiles, to make them consistent. + Removed references to IJG and JPEG in the ansi2knr.c copyright statement. + Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. + Added grayscale and 16-bit capability to png_do_read_filler(). + Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes + too large when writing an image with bit_depth < 8 (Bob Dellaca). + Corrected some bugs in the experimental weighted filtering heuristics. + Moved a misplaced pngrutil code block that truncates tRNS if it has more + than num_palette entries -- test was done before num_palette was defined. + Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). + Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen). +version 1.0.1b [May 2, 1998] + Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). + Relocated the png_composite macros from pngrtran.c to png.h (Greg). + Added makefile.sco (contributed by Mike Hopkirk). + Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. + Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. + More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert). + More work on loop optimization which may help when compiled with C++ compilers. + Added warnings when people try to use transforms they've defined out. + Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. + Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) +version 1.0.1c [May 11, 1998] + Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for + filler bytes should have been 0xff instead of 0xf. + Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. + Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED + out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h + Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, + for consistency, in pngconf.h + Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier + to remove unwanted capabilities via the compile line + Made some corrections to grammar (which, it's) in documentation (Greg). + Corrected example.c, use of row_pointers in png_write_image(). +version 1.0.1d [May 24, 1998] + Corrected several statements that used side effects illegally in pngrutil.c + and pngtrans.c, that were introduced in version 1.0.1b + Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) + More corrections to example.c, use of row_pointers in png_write_image() + and png_read_rows(). + Added pngdll.mak and pngdef.pas to scripts directory, contributed by + Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 + Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) + Changed several loops from count-down to count-up, for consistency. +version 1.0.1e [June 6, 1998] + Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and + added warnings when people try to set png_read_fn and png_write_fn in + the same structure. + Added a test such that png_do_gamma will be done when num_trans==0 + for truecolor images that have defined a background. This corrects an + error that was introduced in libpng-0.90 that can cause gamma processing + to be skipped. + Added tests in png.h to include "trans" and "trans_values" in structures + when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. + Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() + Moved png_convert_to_rfc_1123() from pngwrite.c to png.c + Added capability for user-provided malloc_fn() and free_fn() functions, + and revised pngtest.c to demonstrate their use, replacing the + PNGTEST_DEBUG_MEM feature. + Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). + +version 1.0.2 [June 14, 1998] + Fixed two bugs in makefile.bor . +version 1.0.2a [December 30, 1998] + Replaced and extended code that was removed from png_set_filler() in 1.0.1a. + Fixed a bug in png_do_filler() that made it fail to write filler bytes in + the left-most pixel of each row (Kevin Bracey). + Changed "static pngcharp tIME_string" to "static char tIME_string[30]" + in pngtest.c (Duncan Simpson). + Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk + even when no tIME chunk was present in the source file. + Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. + Fixed a problem in png_read_push_finish_row(), which would not skip some + passes that it should skip, for images that are less than 3 pixels high. + Interchanged the order of calls to png_do_swap() and png_do_shift() + in pngwtran.c (John Cromer). + Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . + Changed "bad adaptive filter type" from error to warning in pngrutil.c . + Fixed a documentation error about default filtering with 8-bit indexed-color. + Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO + (L. Peter Deutsch). + Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. + Added png_get_copyright() and png_get_header_version() functions. + Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c + Added information about debugging in libpng.txt and libpng.3 . + Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco. + Removed lines after Dynamic Dependencies" in makefile.aco . + Revised makefile.dec to make a shared library (Jeremie Petit). + Removed trailing blanks from all files. +version 1.0.2a [January 6, 1999] + Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h + Added "if" tests to silence complaints about unused png_ptr in png.h and png.c + Changed "check_if_png" function in example.c to return true (nonzero) if PNG. + Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() + which is obsolete. + +version 1.0.3 [January 14, 1999] + Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) + Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. +version 1.0.3a [August 12, 1999] + Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning + if an attempt is made to read an interlaced image when it's not supported. + Added check if png_ptr->trans is defined before freeing it in pngread.c + Modified the Y2K statement to include versions back to version 0.71 + Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c + Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) + Replaced leading blanks with tab characters in makefile.hux + Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. + Changed (float)red and (float)green to (double)red, (double)green + in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. + Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). + Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). + Updated documentation to refer to the PNG-1.2 specification. + Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c + in makefile.knr, INSTALL, and README (L. Peter Deutsch) + Fixed bugs in calculation of the length of rowbytes when adding alpha + channels to 16-bit images, in pngrtran.c (Chris Nokleberg) + Added function png_set_user_transform_info() to store user_transform_ptr, + user_depth, and user_channels into the png_struct, and a function + png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) + Added function png_set_empty_plte_permitted() to make libpng useable + in MNG applications. + Corrected the typedef for png_free_ptr in png.h (Jesse Jones). + Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be + consistent with PNG-1.2, and allow variance of 500 before complaining. + Added assembler code contributed by Intel in file pngvcrd.c and modified + makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, Gilles Vollant) + Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. + Added some aliases for png_set_expand() in pngrtran.c, namely + png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() + (Greg Roelofs, in "PNG: The Definitive Guide"). + Added makefile.beo for BEOS on X86, contributed by Sander Stok. +version 1.0.3b [August 26, 1999] + Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h + Changed leading blanks to tabs in all makefiles. + Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. + Made alternate versions of png_set_expand() in pngrtran.c, namely + png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha + (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. + Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h + Revised calculation of num_blocks in pngmem.c to avoid a potentially + negative shift distance, whose results are undefined in the C language. + Added a check in pngset.c to prevent writing multiple tIME chunks. + Added a check in pngwrite.c to detect invalid small window_bits sizes. +version 1.0.3d [September 4, 1999] + Fixed type casting of igamma in pngrutil.c + Added new png_expand functions to scripts/pngdef.pas and pngos2.def + Added a demo read_user_transform_fn that examines the row filters in pngtest.c + +version 1.0.4 [September 24, 1999] + Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined + Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h + Made several minor corrections to pngtest.c + Renamed the makefiles with longer but more user friendly extensions. + Copied the PNG copyright and license to a separate LICENSE file. + Revised documentation, png.h, and example.c to remove reference to + "viewing_gamma" which no longer appears in the PNG specification. + Revised pngvcrd.c to use MMX code for interlacing only on the final pass. + Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a + Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX + assembler code) and makefile.vcwin32 (doesn't). + Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) + Added a copy of pngnow.png to the distribution. +version 1.0.4a [September 25, 1999] + Increase max_pixel_depth in pngrutil.c if a user transform needs it. + Changed several division operations to right-shifts in pngvcrd.c +version 1.0.4b [September 30, 1999] + Added parentheses in line 3732 of pngvcrd.c + Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 +version 1.0.4c [October 1, 1999] + Added a "png_check_version" function in png.c and pngtest.c that will generate + a helpful compiler error if an old png.h is found in the search path. + Changed type of png_user_transform_depth|channels from int to png_byte. +version 1.0.4d [October 6, 1999] + Changed 0.45 to 0.45455 in png_set_sRGB() + Removed unused PLTE entries from pngnow.png + Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. +version 1.0.4e [October 10, 1999] + Fixed sign error in pngvcrd.c (Greg Roelofs) + Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) +version 1.0.4f [October 15, 1999] + Surrounded example.c code with #if 0 .. #endif to prevent people from + inadvertently trying to compile it. + Changed png_get_header_version() from a function to a macro in png.h + Added type casting mostly in pngrtran.c and pngwtran.c + Removed some pointless "ptr = NULL" in pngmem.c + Added a "contrib" directory containing the source code from Greg's book. + +version 1.0.5 [October 15, 1999] + Minor editing of the INSTALL and README files. +version 1.0.5a [October 23, 1999] + Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) + Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) + Further optimization and bugfix of pngvcrd.c + Revised pngset.c so that it does not allocate or free memory in the user's + text_ptr structure. Instead, it makes its own copy. + Created separate write_end_info_struct in pngtest.c for a more severe test. + Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. +version 1.0.5b [November 23, 1999] + Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and + PNG_FLAG_WROTE_tIME from flags to mode. + Added png_write_info_before_PLTE() function. + Fixed some typecasting in contrib/gregbook/*.c + Updated scripts/makevms.com and added makevms.com to contrib/gregbook + and contrib/pngminus (Martin Zinser) +version 1.0.5c [November 26, 1999] + Moved png_get_header_version from png.h to png.c, to accommodate ansi2knr. + Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to + accommodate making DLL's: Moved usr_png_ver from global variable to function + png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and + eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays + into pngtypes.h. Eliminated use of global png_pass arrays. Declared the + png_CHNK and png_pass arrays to be "const". Made the global arrays + available to applications (although none are used in libpng itself) when + PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. + Removed some extraneous "-I" from contrib/pngminus/makefile.std + Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. + Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 +version 1.0.5d [November 29, 1999] + Add type cast (png_const_charp) two places in png.c + Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. + Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available + to applications a macro "PNG_USE_LOCAL_ARRAYS". + Remove all the new declarations with #ifdef/#endif when + PNG_USE_GLOBAL_ARRAYS is defined. + Added PNG_EXPORT_VAR macro to accommodate making DLL's. +version 1.0.5e [November 30, 1999] + Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text + structure; refactored the inflate/deflate support to make adding new chunks + with trailing compressed parts easier in the future, and added new functions + png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, + png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). + NOTE: Applications that write text chunks MUST define png_text->lang + before calling png_set_text(). It must be set to NULL if you want to + write tEXt or zTXt chunks. If you want your application to be able to + run with older versions of libpng, use + + #ifdef PNG_iTXt_SUPPORTED + png_text[i].lang = NULL; + #endif + + Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned + offsets (Eric S. Raymond). + Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into + PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED + macros, leaving the separate macros also available. + Removed comments on #endifs at the end of many short, non-nested #if-blocks. +version 1.0.5f [December 6, 1999] + Changed makefile.solaris to issue a warning about potential problems when + the ucb "ld" is in the path ahead of the ccs "ld". + Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. + Added sCAL chunk support (Eric S. Raymond). +version 1.0.5g [December 7, 1999] + Fixed "png_free_spallettes" typo in png.h + Added code to handle new chunks in pngpread.c + Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block + Added "translated_key" to png_text structure and png_write_iTXt(). + Added code in pngwrite.c to work around a newly discovered zlib bug. +version 1.0.5h [December 10, 1999] + NOTE: regarding the note for version 1.0.5e, the following must also + be included in your code: + png_text[i].translated_key = NULL; + Unknown chunk handling is now supported. + Option to eliminate all floating point support was added. Some new + fixed-point functions such as png_set_gAMA_fixed() were added. + Expanded tabs and removed trailing blanks in source files. +version 1.0.5i [December 13, 1999] + Added some type casts to silence compiler warnings. + Renamed "png_free_spalette" to "png_free_spalettes" for consistency. + Removed leading blanks from a #define in pngvcrd.c + Added some parameters to the new png_set_keep_unknown_chunks() function. + Added a test for up->location != 0 in the first instance of writing + unknown chunks in pngwrite.c + Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to + prevent recursion. + Added png_free_hIST() function. + Various patches to fix bugs in the sCAL and integer cHRM processing, + and to add some convenience macros for use with sCAL. +version 1.0.5j [December 21, 1999] + Changed "unit" parameter of png_write_sCAL from png_byte to int, to work + around buggy compilers. + Added new type "png_fixed_point" for integers that hold float*100000 values + Restored backward compatibility of tEXt/zTXt chunk processing: + Restored the first four members of png_text to the same order as v.1.0.5d. + Added members "lang_key" and "itxt_length" to png_text struct. Set + text_length=0 when "text" contains iTXt data. Use the "compression" + member to distinguish among tEXt/zTXt/iTXt types. Added + PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. + The "Note" above, about backward incompatibility of libpng-1.0.5e, no + longer applies. + Fixed png_read|write_iTXt() to read|write parameters in the right order, + and to write the iTXt chunk after IDAT if it appears in the end_ptr. + Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) + Reversed the order of trying to write floating-point and fixed-point gAMA. +version 1.0.5k [December 27, 1999] + Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" + Added png_handle_as_unknown() function (Glenn) + Added png_free_chunk_list() function and chunk_list and num_chunk_list members + of png_ptr. + Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. + Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings + about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) + Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). + Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. + Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). +version 1.0.5l [January 1, 2000] + Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() + for setting a callback function to handle unknown chunks and for + retrieving the associated user pointer (Glenn). +version 1.0.5m [January 7, 2000] + Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). +version 1.0.5n [January 9, 2000] + Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its + own memory for info_ptr->palette. This makes it safe for the calling + application to free its copy of the palette any time after it calls + png_set_PLTE(). +version 1.0.5o [January 20, 2000] + Cosmetic changes only (removed some trailing blanks and TABs) +version 1.0.5p [January 31, 2000] + Renamed pngdll.mak to makefile.bd32 + Cosmetic changes in pngtest.c +version 1.0.5q [February 5, 2000] + Relocated the makefile.solaris warning about PATH problems. + Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) + Revised makefile.gcmmx + Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros +version 1.0.5r [February 7, 2000] + Removed superfluous prototype for png_get_itxt from png.h + Fixed a bug in pngrtran.c that improperly expanded the background color. + Return *num_text=0 from png_get_text() when appropriate, and fix documentation + of png_get_text() in libpng.txt/libpng.3. +version 1.0.5s [February 18, 2000] + Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the + new error handler that's planned for the next libpng release, and changed + example.c, pngtest.c, and contrib programs to use this macro. + Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) + Fixed a bug in png_read_png() that caused it to fail to expand some images + that it should have expanded. + Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions + in pngget.c + Changed the allocation of palette, history, and trans arrays back to + the version 1.0.5 method (linking instead of copying) which restores + backward compatibility with version 1.0.5. Added some remarks about + that in example.c. Added "free_me" member to info_ptr and png_ptr + and added png_free_data() function. + Updated makefile.linux and makefile.gccmmx to make directories conditionally. + Made cosmetic changes to pngasmrd.h + Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). + Modified png_read_png() to allocate info_ptr->row_pointers only if it + hasn't already been allocated. +version 1.0.5t [March 4, 2000] + Changed png_jmp_env() migration aiding macro to png_jmpbuf(). + Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c + Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when + PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b + Files in contrib/gregbook were revised to use png_jmpbuf() and to select + a 24-bit visual if one is available, and to allow abbreviated options. + Files in contrib/pngminus were revised to use the png_jmpbuf() macro. + Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s +version 1.0.5u [March 5, 2000] + Simplified the code that detects old png.h in png.c and pngtest.c + Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) + Increased precision of rgb_to_gray calculations from 8 to 15 bits and + added png_set_rgb_to_gray_fixed() function. + Added makefile.bc32 (32-bit Borland C++, C mode) +version 1.0.5v [March 11, 2000] + Added some parentheses to the png_jmpbuf macro definition. + Updated references to the zlib home page, which has moved to freesoftware.com. + Corrected bugs in documentation regarding png_read_row() and png_write_row(). + Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. + Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, + revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) + +version 1.0.6 [March 20, 2000] + Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c + Added makefile.sggcc (SGI IRIX with gcc) +version 1.0.6d [April 7, 2000] + Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO + Added data_length parameter to png_decompress_chunk() function + Revised documentation to remove reference to abandoned png_free_chnk functions + Fixed an error in png_rgb_to_gray_fixed() + Revised example.c, usage of png_destroy_write_struct(). + Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file + Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c + Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). +version 1.0.6e [April 9, 2000] + Added png_data_freer() function. + In the code that checks for over-length tRNS chunks, added check of + info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) + Minor revisions of libpng.txt/libpng.3. + Check for existing data and free it if the free_me flag is set, in png_set_*() + and png_handle_*(). + Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED + is defined. + Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c + and mentioned the purposes of the two macros in libpng.txt/libpng.3. +version 1.0.6f [April 14, 2000] + Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. + Add checks in png_set_text() for NULL members of the input text structure. + Revised libpng.txt/libpng.3. + Removed superfluous prototype for png_set_itxt from png.h + Removed "else" from pngread.c, after png_error(), and changed "0" to "length". + Changed several png_errors about malformed ancillary chunks to png_warnings. +version 1.0.6g [April 24, 2000] + Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. + Relocated paragraph about png_set_background() in libpng.3/libpng.txt + and other revisions (Matthias Benckmann) + Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and + png_ptr members to restore binary compatibility with libpng-1.0.5 + (breaks compatibility with libpng-1.0.6). +version 1.0.6h [April 24, 2000] + Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds + libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) + This is a temporary change for test purposes. +version 1.0.6i [May 2, 2000] + Rearranged some members at the end of png_info and png_struct, to put + unknown_chunks_num and free_me within the original size of the png_structs + and free_me, png_read_user_fn, and png_free_fn within the original png_info, + because some old applications allocate the structs directly instead of + using png_create_*(). + Added documentation of user memory functions in libpng.txt/libpng.3 + Modified png_read_png so that it will use user_allocated row_pointers + if present, unless free_me directs that it be freed, and added description + of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. + Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version + 1.00) members of png_struct and png_info, to regain binary compatibility + when you define this macro. Capabilities lost in this event + are user transforms (new in version 1.0.0),the user transform pointer + (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, + the high-level interface, and unknown chunks support (all new in 1.0.6). + This was necessary because of old applications that allocate the structs + directly as authors were instructed to do in libpng-0.88 and earlier, + instead of using png_create_*(). + Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which + can be used to detect codes that directly allocate the structs, and + code to check these modes in png_read_init() and png_write_init() and + generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED + was not defined. + Added makefile.intel and updated makefile.watcom (Pawel Mrochen) +version 1.0.6j [May 3, 2000] + Overloaded png_read_init() and png_write_init() with macros that convert + calls to png_read_init_2() or png_write_init_2() that check the version + and structure sizes. +version 1.0.7beta11 [May 7, 2000] + Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes + which are no longer used. + Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is + defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED + is defined. + Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory + overrun when old applications fill the info_ptr->text structure directly. + Added PNGAPI macro, and added it to the definitions of all exported functions. + Relocated version macro definitions ahead of the includes of zlib.h and + pngconf.h in png.h. +version 1.0.7beta12 [May 12, 2000] + Revised pngset.c to avoid a problem with expanding the png_debug macro. + Deleted some extraneous defines from pngconf.h + Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. + Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. + Added png_access_version_number() function. + Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). + Expanded libpng.3/libpng.txt information about png_data_freer(). +version 1.0.7beta14 [May 17, 2000] (beta13 was not published) + Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as + warnings instead of errors, as pngrutil.c does. + Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() + will actually write IDATs. + Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. + Make png_free_data() ignore its final parameter except when freeing data + that can have multiple instances (text, sPLT, unknowns). + Fixed a new bug in png_set_rows(). + Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. + Added png_set_invalid() function. + Fixed incorrect illustrations of png_destroy_write_struct() in example.c. +version 1.0.7beta15 [May 30, 2000] + Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce + fewer error messages. + Rearranged checks for Z_OK to check the most likely path first in pngpread.c + and pngwutil.c. + Added checks in pngtest.c for png_create_*() returning NULL, and mentioned + in libpng.txt/libpng.3 the need for applications to check this. + Changed names of png_default_*() functions in pngtest to pngtest_*(). + Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. + Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c + Set each pointer to NULL after freeing it in png_free_data(). + Worked around a problem in pngconf.h; AIX's strings.h defines an "index" + macro that conflicts with libpng's png_color_16.index. (Dimitri Papadapoulos) + Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). +version 1.0.7beta16 [June 4, 2000] + Revised the workaround of AIX string.h "index" bug. + Added a check for overlength PLTE chunk in pngrutil.c. + Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer + indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. + Added a warning in png_decompress_chunk() when it runs out of data, e.g. + when it tries to read an erroneous PhotoShop iCCP chunk. + Added PNG_USE_DLL macro. + Revised the copyright/disclaimer/license notice. + Added contrib/msvctest directory +version 1.0.7rc1 [June 9, 2000] + Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) + Added contrib/visupng directory (Willem van Schaik) +version 1.0.7beta18 [June 23, 2000] + Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ + and do not redefine PNGAPI if it is passed in via a compiler directive. + Revised visupng/PngFile.c to remove returns from within the Try block. + Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. + Updated contrib/visupng/cexcept.h to version 1.0.0. + Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. +version 1.0.7rc2 [June 28, 2000] + Updated license to include disclaimers required by UCITA. + Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. + +version 1.0.7 [July 1, 2000] + Revised the definition of "trans_values" in libpng.3/libpng.txt +version 1.0.8beta1 [July 8, 2000] + Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. + Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and + pngwutil.c. + Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. + Removed unused "#include " from png.c + Added WindowsCE support. + Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. +version 1.0.8beta2 [July 10, 2000] + Added project files to the wince directory and made further revisions + of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. +version 1.0.8beta3 [July 11, 2000] + Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() + for indexed-color input files to avoid potential double-freeing trans array + under some unusual conditions; problem was introduced in version 1.0.6f. + Further revisions to pngtest.c and files in the wince subdirectory. +version 1.0.8beta4 [July 14, 2000] + Added the files pngbar.png and pngbar.jpg to the distribution. + Added makefile.cygwin, and cygwin support in pngconf.h + Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) +version 1.0.8rc1 [July 16, 2000] + Revised png_debug() macros and statements to eliminate compiler warnings. + +version 1.0.8 [July 24, 2000] + Added png_flush() in pngwrite.c, after png_write_IEND(). + Updated makefile.hpux to build a shared library. +version 1.0.9beta1 [November 10, 2000] + Fixed typo in scripts/makefile.hpux + Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) + Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) + Changed "cdrom.com" in documentation to "libpng.org" + Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). + Changed type of "params" from voidp to png_voidp in png_read|write_png(). + Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. + Revised the 3 instances of WRITEFILE in pngtest.c. + Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. + Updated png.rc in dll/msvc project + Revised makefile.dec to define and use LIBPATH and INCPATH + Increased size of global png_libpng_ver[] array from 12 to 18 chars. + Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. + Removed duplicate png_crc_finish() from png_handle_bKGD() function. + Added a warning when application calls png_read_update_info() multiple times. + Revised makefile.cygwin + Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. + Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). +version 1.0.9beta2 [November 19, 2000] + Renamed the "dll" subdirectory "projects". + Added borland project files to "projects" subdirectory. + Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. + Add error message in png_set_compression_buffer_size() when malloc fails. +version 1.0.9beta3 [November 23, 2000] + Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. + Removed the png_flush() in pngwrite.c that crashes some applications + that don't set png_output_flush_fn. + Added makefile.macosx and makefile.aix to scripts directory. +version 1.0.9beta4 [December 1, 2000] + Change png_chunk_warning to png_warning in png_check_keyword(). + Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). +version 1.0.9beta5 [December 15, 2000] + Added support for filter method 64 (for PNG datastreams embedded in MNG). +version 1.0.9beta6 [December 18, 2000] + Revised png_set_filter() to accept filter method 64 when appropriate. + Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to + help prevent applications from using MNG features in PNG datastreams. + Added png_permit_mng_features() function. + Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". +version 1.0.9rc1 [December 23, 2000] + Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c + Fixed error handling of unknown compression type in png_decompress_chunk(). + In pngconf.h, define __cdecl when _MSC_VER is defined. +version 1.0.9beta7 [December 28, 2000] + Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. + Revised memory management in png_set_hIST and png_handle_hIST in a backward + compatible manner. PLTE and tRNS were revised similarly. + Revised the iCCP chunk reader to ignore trailing garbage. +version 1.0.9beta8 [January 12, 2001] + Moved pngasmrd.h into pngconf.h. + Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. +version 1.0.9beta9 [January 15, 2001] + Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to + wince and msvc project module definition files. + Minor revision of makefile.cygwin. + Fixed bug with progressive reading of narrow interlaced images in pngpread.c +version 1.0.9beta10 [January 16, 2001] + Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. + Fixed "png_mmx_supported" typo in project definition files. +version 1.0.9beta11 [January 19, 2001] + Updated makefile.sgi to make shared library. + Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED + by default, for the benefit of DLL forward compatibility. These will + be re-enabled in version 1.2.0. +version 1.0.9rc2 [January 22, 2001] + Revised cygwin support. + +version 1.0.9 [January 31, 2001] + Added check of cygwin's ALL_STATIC in pngconf.h + Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. +version 1.0.10beta1 [March 14, 2001] + Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. + Reformatted libpng.3 to eliminate bad line breaks. + Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c + Added prototype for png_mmx_support() near the top of pnggccrd.c + Moved some error checking from png_handle_IHDR to png_set_IHDR. + Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. + Revised png_mmx_support() function in pnggccrd.c + Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c + Fixed memory leak in contrib/visupng/PngFile.c + Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) + Added warnings when retrieving or setting gamma=0. + Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). +version 1.0.10rc1 [March 23, 2001] + Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, + and png_strlen. + Revised png_mmx_supported() function in pnggccrd.c to return proper value. + Fixed bug in progressive reading (pngpread.c) with small images (height < 8). + +version 1.0.10 [March 30, 2001] + Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin + Added beos project files (Chris Herborth) +version 1.0.11beta1 [April 3, 2001] + Added type casts on several png_malloc() calls (Dimitri Papadapoulos). + Removed a no-longer needed AIX work-around from pngconf.h + Changed several "//" single-line comments to C-style in pnggccrd.c +version 1.0.11beta2 [April 11, 2001] + Removed PNGAPI from several functions whose prototypes did not have PNGAPI. + Updated scripts/pngos2.def +version 1.0.11beta3 [April 14, 2001] + Added checking the results of many instances of png_malloc() for NULL +version 1.0.11beta4 [April 20, 2001] + Undid the changes from version 1.0.11beta3. Added a check for NULL return + from user's malloc_fn(). + Removed some useless type casts of the NULL pointer. + Added makefile.netbsd + +version 1.0.11 [April 27, 2001] + Revised makefile.netbsd +version 1.0.12beta1 [May 14, 2001] + Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) + Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h + Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. + Eliminated the png_error about apps using png_read|write_init(). Instead, + libpng will reallocate the png_struct and info_struct if they are too small. + This retains future binary compatibility for old applications written for + libpng-0.88 and earlier. +version 1.2.0beta1 [May 6, 2001] + Bumped DLLNUM to 2. + Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED + by default. + Added runtime selection of MMX features. + Added png_set_strip_error_numbers function and related macros. +version 1.2.0beta2 [May 7, 2001] + Finished merging 1.2.0beta1 with version 1.0.11 + Added a check for attempts to read or write PLTE in grayscale PNG datastreams. +version 1.2.0beta3 [May 17, 2001] + Enabled user memory function by default. + Modified png_create_struct so it passes user mem_ptr to user memory allocator. + Increased png_mng_features flag from png_byte to png_uint_32. + Bumped shared-library (so-number) and dll-number to 3. +version 1.2.0beta4 [June 23, 2001] + Check for missing profile length field in iCCP chunk and free chunk_data + in case of truncated iCCP chunk. + Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc + Bumped dll-number from 2 to 3 in makefile.cygwin + Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly + if user attempts to run it on an 8-bit display. + Updated contrib/gregbook + Use png_malloc instead of png_zalloc to allocate palette in pngset.c + Updated makefile.ibmc + Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes + of png_write_oFFS width and height from png_uint_32 to png_int_32. + Updated example.c + Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c +version 1.2.0beta5 [August 8, 2001] + Revised contrib/gregbook + Revised makefile.gcmmx + Revised pnggccrd.c to conditionally compile some thread-unsafe code only + when PNG_THREAD_UNSAFE_OK is defined. + Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with + value exceeding 2^bit_depth-1 + Revised makefile.sgi and makefile.sggcc + Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c + Removed restriction that do_invert_mono only operate on 1-bit opaque files + +version 1.2.0 [September 1, 2001] + Changed a png_warning() to png_debug() in pnggccrd.c + Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). +version 1.2.1beta1 [October 19, 2001] + Revised makefile.std in contrib/pngminus + Include background_1 in png_struct regardless of gamma support. + Revised makefile.netbsd and makefile.macosx, added makefile.darwin. + Revised example.c to provide more details about using row_callback(). +version 1.2.1beta2 [October 25, 2001] + Added type cast to each NULL appearing in a function call, except for + WINCE functions. + Added makefile.so9. +version 1.2.1beta3 [October 27, 2001] + Removed type casts from all NULLs. + Simplified png_create_struct_2(). +version 1.2.1beta4 [November 7, 2001] + Revised png_create_info_struct() and png_creat_struct_2(). + Added error message if png_write_info() was omitted. + Type cast NULLs appearing in function calls when _NO_PROTO or + PNG_TYPECAST_NULL is defined. +version 1.2.1rc1 [November 24, 2001] + Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL + is defined. + Changed typecast of "size" argument to png_size_t in pngmem.c calls to + the user malloc_fn, to agree with the prototype in png.h + Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) + Updated makefile.sgi to recognize LIBPATH and INCPATH. + Updated various makefiles so "make clean" does not remove previous major + version of the shared library. +version 1.2.1rc2 [December 4, 2001] + Always allocate 256-entry internal palette, hist, and trans arrays, to + avoid out-of-bounds memory reference caused by invalid PNG datastreams. + Added a check for prefix_length > data_length in iCCP chunk handler. + +version 1.2.1 [December 7, 2001] + None. +version 1.2.2beta1 [February 22, 2002] + Fixed a bug with reading the length of iCCP profiles (Larry Reeves). + Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate + libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h + Revised makefile.darwin to remove "-undefined suppress" option. + Added checks for gamma and chromaticity values over 21474.83, which exceed + the limit for PNG unsigned 32-bit integers when encoded. + Revised calls to png_create_read_struct() and png_create_write_struct() + for simpler debugging. + Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) +version 1.2.2beta2 [February 23, 2002] + Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. + Check for invalid image dimensions in png_get_IHDR. + Added missing "fi;" in the install target of the SGI makefiles. + Added install-static to all makefiles that make shared libraries. + Always do gamma compensation when image is partially transparent. +version 1.2.2beta3 [March 7, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later. + Modified shared-library makefiles to install pkgconfig/libpngNN.pc. + Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown + Removed unused png_write_destroy_info prototype from png.h + Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case + Added install-shared target to all makefiles that make shared libraries. + Stopped a double free of palette, hist, and trans when not using free_me. + Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. +version 1.2.2beta4 [March 8, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later (Jason Summers). + Relocated a misplaced /bin/rm in the "install-shared" makefile targets + Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. +version 1.2.2beta5 [March 26, 2002] + Added missing PNGAPI to several function definitions. + Check for invalid bit_depth or color_type in png_get_IHDR(), and + check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). + Revised iTXt support to accept NULL for lang and lang_key. + Compute gamma for color components of background even when color_type is gray. + Changed "()" to "{}" in scripts/libpng.pc.in. + Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN + Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so +version 1.2.2beta6 [March 31, 2002] +version 1.0.13beta1 [March 31, 2002] + Prevent png_zalloc() from trying to memset memory that it failed to acquire. + Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). + Ensure that the right function (user or default) is used to free the + png_struct after an error in png_create_read_struct_2(). +version 1.2.2rc1 [April 7, 2002] +version 1.0.13rc1 [April 7, 2002] + Save the ebx register in pnggccrd.c (Sami Farin) + Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). + Updated makefiles to put headers in include/libpng and remove old include/*.h. + +version 1.2.2 [April 15, 2002] +version 1.0.13 [April 15, 2002] + Revised description of png_set_filter() in libpng.3/libpng.txt. + Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd +version 1.0.13patch01 [April 17, 2002] +version 1.2.2patch01 [April 17, 2002] + Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and makefile.sggcc + Fixed VER -> PNGVER typo in makefile.macosx and added install-static to install + Added install: target to makefile.32sunu and makefile.64sunu +version 1.0.13patch03 [April 18, 2002] +version 1.2.2patch03 [April 18, 2002] + Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng + subdirectory to libpngNN subdirectory without the full pathname. + Moved generation of libpng.pc from "install" to "all" in 15 makefiles. +version 1.2.3rc1 [April 28, 2002] + Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). + Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) + Fixed bug with $prefix, should be $(prefix) in makefile.hpux. + Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin + Added a link from libpngNN.pc to libpng.pc in 15 makefiles. + Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. + Revised makefile.darwin to make relative links without full pathname. + Added setjmp() at the end of png_create_*_struct_2() in case user forgets + to put one in their application. + Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and + removed them from module definition files. +version 1.2.3rc2 [May 1, 2002] + Fixed bug in reporting number of channels in pngget.c and pngset.c, + that was introduced in version 1.2.2beta5. + Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), + png_default_flush(), and png_push_fill_buffer() and included them in + module definition files. + Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. +version 1.2.3rc3 [May 1, 2002] + Revised prototype for png_default_flush() + Remove old libpng.pc and libpngNN.pc before installing new ones. +version 1.2.3rc4 [May 2, 2002] + Typos in *.def files (png_default_read|write -> png_default_read|write_data) + In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc + Added libpng-config and libpngNN-config and modified makefiles to install them. + Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles + Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp +version 1.2.3rc5 [May 11, 2002] + Changed "error" and "message" in prototypes to "error_message" and + "warning_message" to avoid namespace conflict. + Revised 15 makefiles to build libpng-config from libpng-config-*.in + Once more restored png_zalloc and png_zfree to regular nonexported form. + Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer + to nonexported form, but with PNGAPI, and removed them from module def files. +version 1.2.3rc6 [May 14, 2002] + Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c + Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. + Removed leftover libpng-config "sed" script from four makefiles. + Revised libpng-config creating script in 16 makefiles. + +version 1.2.3 [May 22, 2002] + Revised libpng-config target in makefile.cygwin. + Removed description of png_set_mem_fn() from documentation. + Revised makefile.freebsd. + Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). + Revised projects/msvc/README.txt + Changed -lpng to -lpngNN in LDFLAGS in several makefiles. +version 1.2.4beta1 [May 24, 2002] + Added libpng.pc and libpng-config to "all:" target in 16 makefiles. + Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) + Added missing "\" before closing double quote in makefile.gcmmx. + Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() + functions. +version 1.2.4beta2 [June 25, 2002] + Plugged memory leak of png_ptr->current_text (Matt Holgate). + Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) + Added -soname to the loader flags in makefile.dec, makefile.sgi, and + makefile.sggcc. + Added "test-installed" target to makefile.linux, makefile.gcmmx, + makefile.sgi, and makefile.sggcc. +version 1.2.4beta3 [June 28, 2002] + Plugged memory leak of row_buf in pngtest.c when there is a png_error(). + Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. + Added "test-installed" target to makefile.32sunu, makefile.64sunu, + makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, + makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. +version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] + Added "test-installed" target to makefile.cygwin and makefile.sco. + Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. + +version 1.2.4 and 1.0.14 [July 8, 2002] + Changed png_warning() to png_error() when width is too large to process. +version 1.2.4patch01 [July 20, 2002] + Revised makefile.cygwin to use DLL number 12 instead of 13. +version 1.2.5beta1 [August 6, 2002] + Added code to contrib/gregbook/readpng2.c to ignore unused chunks. + Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) + Removed some stray *.o files from contrib/gregbook. + Changed png_error() to png_warning() about "Too much data" in pngpread.c + and about "Extra compressed data" in pngrutil.c. + Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). + Updated makefile.hpgcc + Updated png.c and pnggccrd.c handling of return from png_mmx_support() +version 1.2.5beta2 [August 15, 2002] + Only issue png_warning() about "Too much data" in pngpread.c when avail_in + is nonzero. + Updated makefiles to install a separate libpng.so.3 with its own rpath. +version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] + Revised makefiles to not remove previous minor versions of shared libraries. +version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] + Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared + library loader directive. + Added missing "$OBJSDLL" line to makefile.gcmmx. + Added missing "; fi" to makefile.32sunu. +version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] + Revised libpng-config script. + +version 1.2.5 and 1.0.15 [October 3, 2002] + Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, + and makefile.aix. + Relocated two misplaced PNGAPI lines in pngtest.c +version 1.2.6beta1 [October 22, 2002] + Commented out warning about uninitialized mmx_support in pnggccrd.c. + Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. + Relocated two more misplaced PNGAPI lines in pngtest.c + Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, + introduced in version 1.0.2. + Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. +version 1.2.6beta2 [November 1, 2002] + Added libpng-config "--ldopts" output. + Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" + in makefiles. +version 1.2.6beta3 [July 18, 2004] + Reverted makefile changes from version 1.2.6beta2 and some of the changes + from version 1.2.6beta1; these will be postponed until version 1.2.7. + Version 1.2.6 is going to be a simple bugfix release. + Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. + Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. + Added "#!/bin/sh" at the top of configure, for recognition of the + 'x' flag under Cygwin (Cosmin). + Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). + Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). + Fixed the special memory handler for Borland C under DOS, in pngmem.c + (Cosmin). + Removed some spurious assignments in pngrutil.c (Cosmin). + Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings + on 16-bit platforms (Cosmin). + Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). + Used proper type png_fixed_point, to avoid problems on 16-bit platforms, + in png_handle_sRGB() (Cosmin). + Added compression_type to png_struct, and optimized the window size + inside the deflate stream (Cosmin). + Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). + Fixed handling of unknown chunks that come after IDAT (Cosmin). + Allowed png_error() and png_warning() to work even if png_ptr == NULL + (Cosmin). + Replaced row_info->rowbytes with row_bytes in png_write_find_filter() + (Cosmin). + Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). + Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded + values in png.c (Simon-Pierre, Cosmin). + Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). + Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc + (Simon-Pierre). + Moved the definition of PNG_HEADER_VERSION_STRING near the definitions + of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). + Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). + Updated scripts/makefile.vc(a)win32 (Cosmin). + Updated the MSVC project (Simon-Pierre, Cosmin). + Updated the Borland C++ Builder project (Cosmin). + Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). + Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). + Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). + Added extra guard around inclusion of Turbo C memory headers, in pngconf.h + (Cosmin). + Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to + projects/cbuilder5/ (Cosmin). + Moved projects/visualc6/png32ms.def to scripts/pngw32.def, + and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). + Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). + Changed line endings to DOS style in cbuilder5 and visualc6 files, even + in the tar.* distributions (Cosmin). + Updated contrib/visupng/VisualPng.dsp (Cosmin). + Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). + Added a separate distribution with "configure" and supporting files (Junichi). +version 1.2.6beta4 [July 28, 2004] + Added user ability to change png_size_t via a PNG_SIZE_T macro. + Added png_sizeof() and png_convert_size() functions. + Added PNG_SIZE_MAX (maximum value of a png_size_t variable. + Added check in png_malloc_default() for (size_t)size != (png_uint_32)size + which would indicate an overflow. + Changed sPLT failure action from png_error to png_warning and abandon chunk. + Changed sCAL and iCCP failures from png_error to png_warning and abandon. + Added png_get_uint_31(png_ptr, buf) function. + Added PNG_UINT_32_MAX macro. + Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. + Made png_zalloc() issue a png_warning and return NULL on potential + overflow. + Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x + Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. + Revised Borland portion of png_malloc() to return NULL or issue + png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. + Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove + sequential read support. + Added some "#if PNG_WRITE_SUPPORTED" blocks. + Removed some redundancy with #ifdef/#endif in png_malloc_default(). + Use png_malloc instead of png_zalloc to allocate the pallete. +version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] + Fixed buffer overflow vulnerability in png_handle_tRNS() + Fixed integer arithmetic overflow vulnerability in png_read_png(). + Fixed some harmless bugs in png_handle_sBIT, etc, that would cause + duplicate chunk types to go undetected. + Fixed some timestamps in the -config version + Rearranged order of processing of color types in png_handle_tRNS(). + Added ROWBYTES macro to calculate rowbytes without integer overflow. + Updated makefile.darwin and removed makefile.macosx from scripts directory. + Imposed default one million column, one-million row limits on the image + dimensions, and added png_set_user_limits() function to override them. + Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. + Fixed wrong cast of returns from png_get_user_width|height_max(). + Changed some "keep the compiler happy" from empty statements to returns, + Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution +version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] + Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. + Revised pngtest's png_debug_malloc() to use png_malloc() instead of + png_malloc_default() which is not supposed to be exported. + Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in + pngpread.c. Bug was introduced in 1.2.6rc1. + Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. + Fixed old bug in RGB to Gray transformation. + Fixed problem with 64-bit compilers by casting arguments to abs() + to png_int_32. + Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). + Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) + Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. + Added code to update the row_info->colortype in png_do_read_filler() (MSB). +version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] + Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid + trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. + Revised documentation of png_set_keep_unknown_chunks(). + Check handle_as_unknown status in pngpread.c, as in pngread.c previously. + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h + Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c +version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] + Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of + "pinfo" was out of place). +version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED + section of png.h where they were inadvertently placed in version rc3. + +version 1.2.6 and 1.0.16 [August 15, 2004] + Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. +version 1.2.7beta1 [August 26, 2004] + Removed unused pngasmrd.h file. + Removed references to uu.net for archived files. Added references to + PNG Spec (second edition) and the PNG ISO/IEC Standard. + Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. + Fixed bug with "optimized window size" in the IDAT datastream, that + causes libpng to write PNG files with incorrect zlib header bytes. +version 1.2.7beta2 [August 28, 2004] + Fixed bug with sCAL chunk and big-endian machines (David Munro). + Undid new code added in 1.2.6rc2 to update the color_type in + png_set_filler(). + Added png_set_add_alpha() that updates color type. +version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] + Revised png_set_strip_filler() to not remove alpha if color_type has alpha. + +version 1.2.7 and 1.0.17 [September 12, 2004] + Added makefile.hp64 + Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin +version 1.2.8beta1 [November 1, 2004] + Fixed bug in png_text_compress() that would fail to complete a large block. + Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during + strip alpha operation in png_do_strip_filler(). + Added PNG_1_2_X definition in pngconf.h + Comment out with #ifdef/#endif png_info_init in png.c and png_read_init + in pngread.c (as of 1.3.0) +version 1.2.8beta2 [November 2, 2004] + Reduce color_type to a nonalpha type after strip alpha operation in + png_do_strip_filler(). +version 1.2.8beta3 [November 3, 2004] + Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM +version 1.2.8beta4 [November 12, 2004] + Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). + Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). + Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection + of data type in deflate (Cosmin). + Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. +version 1.2.8beta5 [November 20, 2004] + Use png_ptr->flags instead of png_ptr->transformations to pass + PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI + compatibility. + Revised handling of SPECIALBUILD, PRIVATEBUILD, + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. +version 1.2.8rc1 [November 24, 2004] + Moved handling of BUILD macros from pngconf.h to png.h + Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently + omitted from beta5. + Revised scripts/pngw32.rc + Despammed mailing addresses by masking "@" with "at". + Inadvertently installed a supposedly faster test version of pngrutil.c +version 1.2.8rc2 [November 26, 2004] + Added two missing "\" in png.h + Change tests in pngread.c and pngpread.c to + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); +version 1.2.8rc3 [November 28, 2004] + Reverted pngrutil.c to version libpng-1.2.8beta5. + Added scripts/makefile.elf with supporting code in pngconf.h for symbol + versioning (John Bowler). +version 1.2.8rc4 [November 29, 2004] + Added projects/visualc7 (Simon-pierre). +version 1.2.8rc5 [November 29, 2004] + Fixed new typo in scripts/pngw32.rc + +version 1.2.8 [December 3, 2004] + Removed projects/visualc7, added projects/visualc71. + +version 1.2.9beta1 [February 21, 2006] + + Initialized some structure members in pngwutil.c to avoid gcc-4.0.0 complaints + Revised man page and libpng.txt to make it clear that one should not call + png_read_end or png_write_end after png_read_png or png_write_png. + Updated references to png-mng-implement mailing list. + Fixed an incorrect typecast in pngrutil.c + Added PNG_NO_READ_SUPPORTED conditional for making a write-only library. + Added PNG_NO_WRITE_INTERLACING_SUPPORTED conditional. + Optimized alpha-inversion loops in pngwtran.c + Moved test for nonzero gamma outside of png_build_gamma_table() in pngrtran.c + Make sure num_trans is <= 256 before copying data in png_set_tRNS(). + Make sure num_palette is <= 256 before copying data in png_set_PLTE(). + Interchanged order of write_swap_alpha and write_invert_alpha transforms. + Added parentheses in the definition of PNG_LIBPNG_BUILD_TYPE (Cosmin). + Optimized zlib window flag (CINFO) in contrib/pngsuite/*.png (Cosmin). + Updated scripts/makefile.bc32 for Borland C++ 5.6 (Cosmin). + Exported png_get_uint_32, png_save_uint_32, png_get_uint_16, png_save_uint_16, + png_get_int_32, png_save_int_32, png_get_uint_31 (Cosmin). + Added type cast (png_byte) in png_write_sCAL() (Cosmin). + Fixed scripts/makefile.cygwin (Christian Biesinger, Cosmin). + Default iTXt support was inadvertently enabled. + +version 1.2.9beta2 [February 21, 2006] + + Check for png_rgb_to_gray and png_gray_to_rgb read transformations before + checking for png_read_dither in pngrtran.c + Revised checking of chromaticity limits to accommodate extended RGB + colorspace (John Denker). + Changed line endings in some of the project files to CRLF, even in the + "Unix" tar distributions (Cosmin). + Made png_get_int_32 and png_save_int_32 always available (Cosmin). + Updated scripts/pngos2.def, scripts/pngw32.def and projects/wince/png32ce.def + with the newly exported functions. + Eliminated distributions without the "configure" script. + Updated INSTALL instructions. + +version 1.2.9beta3 [February 24, 2006] + + Fixed CRCRLF line endings in contrib/visupng/VisualPng.dsp + Made libpng.pc respect EXEC_PREFIX (D. P. Kreil, J. Bowler) + Removed reference to pngasmrd.h from Makefile.am + Renamed CHANGES to ChangeLog. + Renamed LICENSE to COPYING. + Renamed ANNOUNCE to NEWS. + Created AUTHORS file. + +version 1.2.9beta4 [March 3, 2006] + + Changed definition of PKGCONFIG from $prefix/lib to $libdir in configure.ac + Reverted to filenames LICENSE and ANNOUNCE; removed AUTHORS and COPYING. + Removed newline from the end of some error and warning messages. + Removed test for sqrt() from configure.ac and configure. + Made swap tables in pngtrans.c PNG_CONST (Carlo Bramix). + Disabled default iTXt support that was inadvertently enabled in + libpng-1.2.9beta1. + Added "OS2" to list of systems that don't need underscores, in pnggccrd.c + Removed libpng version and date from *.c files. + +version 1.2.9beta5 [March 4, 2006] + Removed trailing blanks from source files. + Put version and date of latest change in each source file, and changed + copyright year accordingly. + More cleanup of configure.ac, Makefile.am, and associated scripts. + Restored scripts/makefile.elf which was inadvertently deleted. + +version 1.2.9beta6 [March 6, 2006] + Fixed typo (RELEASE) in configuration files. + +version 1.2.9beta7 [March 7, 2006] + Removed libpng.vers and libpng.sym from libpng12_la_SOURCES in Makefile.am + Fixed inconsistent #ifdef's around png_sig_bytes() and png_set_sCAL_s() + in png.h. + Updated makefile.elf as suggested by debian. + Made cosmetic changes to some makefiles, adding LN_SF and other macros. + Made some makefiles accept "exec_prefix". + +version 1.2.9beta8 [March 9, 2006] + Fixed some "#if defined (..." which should be "#if defined(..." + Bug introduced in libpng-1.2.8. + Fixed inconsistency in definition of png_default_read_data() + Restored blank that was lost from makefile.sggcc "clean" target in beta7. + Revised calculation of "current" and "major" for irix in ltmain.sh + Changed "mkdir" to "MKDIR_P" in some makefiles. + Separated PNG_EXPAND and PNG_EXPAND_tRNS. + Added png_set_expand_gray_1_2_4_to_8() and deprecated + png_set_gray_1_2_4_to_8() which also expands tRNS to alpha. + +version 1.2.9beta9 [March 10, 2006] + Include "config.h" in pngconf.h when available. + Added some checks for NULL png_ptr or NULL info_ptr (timeless) + +version 1.2.9beta10 [March 20, 2006] + Removed extra CR from contrib/visualpng/VisualPng.dsw (Cosmin) + Made pnggccrd.c PIC-compliant (Christian Aichinger). + Added makefile.mingw (Wolfgang Glas). + Revised pngconf.h MMX checking. + +version 1.2.9beta11 [March 22, 2006] + Fixed out-of-order declaration in pngwrite.c that was introduced in beta9 + Simplified some makefiles by using LIBSO, LIBSOMAJ, and LIBSOVER macros. + +version 1.2.9rc1 [March 31, 2006] + Defined PNG_USER_PRIVATEBUILD when including "pngusr.h" (Cosmin). + Removed nonsensical assertion check from pngtest.c (Cosmin). + +version 1.2.9 [April 14, 2006] + Revised makefile.beos and added "none" selector in ltmain.sh + +version 1.2.10beta1 [April 15, 2006] + Renamed "config.h" to "png_conf.h" and revised Makefile.am to add + -DPNG_BUILDING_LIBPNG to compile directive, and modified pngconf.h + to include png_conf.h only when PNG_BUILDING_LIBPNG is defined. + +version 1.2.10beta2 [April 15, 2006] + Manually updated Makefile.in and configure. Changed png_conf.h.in + back to config.h. + +version 1.2.10beta3 [April 15, 2006] + Change png_conf.h back to config.h in pngconf.h. + +version 1.2.10beta4 [April 16, 2006] + Change PNG_BUILDING_LIBPNG to PNG_CONFIGURE_LIBPNG in config/Makefile*. + +version 1.2.10beta5 [April 16, 2006] + Added a configure check for compiling assembler code in pnggccrd.c + +version 1.2.10beta6 [April 17, 2006] + Revised the configure check for pnggccrd.c + Moved -DPNG_CONFIGURE_LIBPNG into @LIBPNG_DEFINES@ + Added @LIBPNG_DEFINES@ to arguments when building libpng.sym + +version 1.2.10beta7 [April 18, 2006] + Change "exec_prefix=$prefix" to "exec_prefix=$(prefix)" in makefiles. + +version 1.2.10rc1 [April 19, 2006] + Ensure pngconf.h doesn't define both PNG_USE_PNGGCCRD and PNG_USE_PNGVCRD + Fixed "LN_FS" typo in makefile.sco and makefile.solaris. + +version 1.2.10rc2 [April 20, 2006] + Added a backslash between -DPNG_CONFIGURE_LIBPNG and -DPNG_NO_ASSEMBLER_CODE + in configure.ac and configure + Made the configure warning about versioned symbols less arrogant. + +version 1.2.10rc3 [April 21, 2006] + Added a note in libpng.txt that png_set_sig_bytes(8) can be used when + writing an embedded PNG without the 8-byte signature. + Revised makefiles and configure to avoid making links to libpng.so.* + +version 1.2.10 [April 23, 2006] + Reverted configure to "rc2" state. + +version 1.2.11beta1 [May 31, 2006] + scripts/libpng.pc.in contained "configure" style version info and would + not work with makefiles. + The shared-library makefiles were linking to libpng.so.0 instead of + libpng.so.3 compatibility as the library. + +version 1.2.11beta2 [June 2, 2006] + Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + Fixed bug in example.c (png_set_palette_rgb -> png_set_palette_to_rgb) + +version 1.2.11beta3 [June 5, 2006] + Prepended "#! /bin/sh" to ltmail.sh and contrib/pngminus/*.sh (Cosmin). + Removed the accidental leftover Makefile.in~ (Cosmin). + Avoided potential buffer overflow and optimized buffer in + png_write_sCAL(), png_write_sCAL_s() (Cosmin). + Removed the include directories and libraries from CFLAGS and LDFLAGS + in scripts/makefile.gcc (Nelson A. de Oliveira, Cosmin). + +version 1.2.11beta4 [June 6, 2006] + Allow zero-length IDAT chunks after the entire zlib datastream, but not + after another intervening chunk type. + +version 1.0.19rc1, 1.2.11rc1 [June 13, 2006] + Deleted extraneous square brackets from [config.h] in configure.ac + +version 1.0.19rc2, 1.2.11rc2 [June 14, 2006] + Added prototypes for PNG_INCH_CONVERSIONS functions to png.h + Revised INSTALL and autogen.sh + Fixed typo in several makefiles (-W1 should be -Wl) + Added typedef for png_int_32 and png_uint_32 on 64-bit systems. + +version 1.0.19rc3, 1.2.11rc3 [June 15, 2006] + Removed the new typedefs for 64-bit systems (delay until version 1.4.0) + Added one zero element to png_gamma_shift[] array in pngrtran.c to avoid + reading out of bounds. + +version 1.0.19rc4, 1.2.11rc4 [June 15, 2006] + Really removed the new typedefs for 64-bit systems. + +version 1.0.19rc5, 1.2.11rc5 [June 22, 2006] + Removed png_sig_bytes entry from scripts/pngw32.def + +version 1.0.19, 1.2.11 [June 26, 2006] + None. + +version 1.0.20, 1.2.12 [June 27, 2006] + Really increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + +version 1.2.13beta1 [October 2, 2006] + Removed AC_FUNC_MALLOC from configure.ac + Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h + Change "logical" to "bitwise" throughout documentation. + Detect and fix attempt to write wrong iCCP profile length. + +version 1.0.21, 1.2.13 [November 14, 2006] + Fix potential buffer overflow in sPLT chunk handler. + Fix Makefile.am to not try to link to noexistent files. + Check all exported functions for NULL png_ptr. + +version 1.2.14beta1 [November 17, 2006] + Relocated three misplaced tests for NULL png_ptr. + Built Makefile.in with automake-1.9.6 instead of 1.9.2. + Build configure with autoconf-2.60 instead of 2.59 + +version 1.2.14beta2 [November 17, 2006] + Added some typecasts in png_zalloc(). + +version 1.2.14rc1 [November 20, 2006] + Changed "strtod" to "png_strtod" in pngrutil.c + +version 1.0.22, 1.2.14 [November 27, 2006] + Added missing "$(srcdir)" in Makefile.am and Makefile.in + +version 1.2.15beta1 [December 3, 2006] + Generated configure with autoconf-2.61 instead of 2.60 + Revised configure.ac to update libpng.pc and libpng-config. + +version 1.2.15beta2 [December 3, 2006] + Always export MMX asm functions, just stubs if not building pnggccrd.c + +version 1.2.15beta3 [December 4, 2006] + Add "png_bytep" typecast to profile while calculating length in pngwutil.c + +version 1.2.15beta4 [December 7, 2006] + Added scripts/CMakeLists.txt + Changed PNG_NO_ASSEMBLER_CODE to PNG_NO_MMX_CODE in scripts, like 1.4.0beta + +version 1.2.15beta5 [December 7, 2006] + Changed some instances of PNG_ASSEMBLER_* to PNG_MMX_* in pnggccrd.c + Revised scripts/CMakeLists.txt + +version 1.2.15beta6 [December 13, 2006] + Revised scripts/CMakeLists.txt and configure.ac + +version 1.2.15rc1 [December 18, 2006] + Revised scripts/CMakeLists.txt + +version 1.2.15rc2 [December 21, 2006] + Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. + Added scripts/makefile.nommx + +version 1.2.15rc3 [December 25, 2006] + Fixed shared library numbering error that was introduced in 1.2.15beta6. + +version 1.2.15rc4 [December 27, 2006] + Fixed handling of rgb_to_gray when png_ptr->color.gray isn't set. + +version 1.2.15rc5 [December 31, 2006] + Revised handling of rgb_to_gray. + +version 1.0.23, 1.2.15 [January 5, 2007] + Added some (unsigned long) typecasts in pngtest.c to avoid printing errors. + +version 1.2.16beta1 [January 6, 2007] + Fix bugs in makefile.nommx + +version 1.2.16beta2 [January 16, 2007] + Revised scripts/CMakeLists.txt + +version 1.0.24, 1.2.16 [January 31, 2007] + No changes. + +version 1.2.17beta1 [March 6, 2007] + Revised scripts/CMakeLists.txt to install both shared and static libraries. + Deleted a redundant line from pngset.c. + +version 1.2.17beta2 [April 26, 2007] + Relocated misplaced test for png_ptr == NULL in pngpread.c + Change "==" to "&" for testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN + flags. + Changed remaining instances of PNG_ASSEMBLER_* to PNG_MMX_* + Added pngerror() when write_IHDR fails in deflateInit2(). + Added "const" to some array declarations. + Mention examples of libpng usage in the libpng*.txt and libpng.3 documents. + +version 1.2.17rc1 [May 4, 2007] + No changes. + +version 1.2.17rc2 [May 8, 2007] + Moved several PNG_HAVE_* macros out of PNG_INTERNAL because applications + calling set_unknown_chunk_location() need them. + Changed transformation flag from PNG_EXPAND_tRNS to PNG_EXPAND in + png_set_expand_gray_1_2_4_to_8(). + Added png_ptr->unknown_chunk to hold working unknown chunk data, so it + can be free'ed in case of error. Revised unknown chunk handling in + pngrutil.c and pngpread.c to use this structure. + +version 1.2.17rc3 [May 8, 2007] + Revised symbol-handling in configure script. + +version 1.2.17rc4 [May 10, 2007] + Revised unknown chunk handling to avoid storing unknown critical chunks. + +version 1.0.25 [May 15, 2007] +version 1.2.17 [May 15, 2007] + Added "png_ptr->num_trans=0" before error return in png_handle_tRNS, + to eliminate a vulnerability (CVE-2007-2445, CERT VU#684664) + +version 1.0.26 [May 15, 2007] +version 1.2.18 [May 15, 2007] + Reverted the libpng-1.2.17rc3 change to symbol-handling in configure script + +version 1.2.19beta1 [May 18, 2007] + Changed "const static" to "static PNG_CONST" everywhere, mostly undoing + change of libpng-1.2.17beta2. Changed other "const" to "PNG_CONST" + Changed some handling of unused parameters, to avoid compiler warnings. + "if (unused == NULL) return;" becomes "unused = unused". + +version 1.2.19beta2 [May 18, 2007] + Only use the valid bits of tRNS value in png_do_expand() (Brian Cartier) + +version 1.2.19beta3 [May 19, 2007] + Add some "png_byte" typecasts in png_check_keyword() and write new_key + instead of key in zTXt chunk (Kevin Ryde). + +version 1.2.19beta4 [May 21, 2007] + Add png_snprintf() function and use it in place of sprint() for improved + defense against buffer overflows. + +version 1.2.19beta5 [May 21, 2007] + Fixed png_handle_tRNS() to only use the valid bits of tRNS value. + Changed handling of more unused parameters, to avoid compiler warnings. + Removed some PNG_CONST in pngwutil.c to avoid compiler warnings. + +version 1.2.19beta6 [May 22, 2007] + Added some #ifdef PNG_MMX_CODE_SUPPORTED where needed in pngvcrd.c + Added a special "_MSC_VER" case that defines png_snprintf to _snprintf + +version 1.2.19beta7 [May 22, 2007] + Squelched png_squelch_warnings() in pnggccrd.c and added + an #ifdef PNG_MMX_CODE_SUPPORTED/#endif block around the declarations + that caused the warnings that png_squelch_warnings was squelching. + +version 1.2.19beta8 [May 22, 2007] + Removed __MMX__ from test in pngconf.h. + +version 1.2.19beta9 [May 23, 2007] + Made png_squelch_warnings() available via PNG_SQUELCH_WARNINGS macro. + Revised png_squelch_warnings() so it might work. + Updated makefile.sgcc and makefile.solaris; added makefile.solaris-x86. + +version 1.2.19beta10 [May 24, 2007] + Resquelched png_squelch_warnings(), use "__attribute__((used))" instead. + +version 1.2.19beta11 [May 28, 2007] + Return 0 from png_get_sPLT() and png_get_unknown_chunks() if png_ptr is NULL; + changed three remaining instances of png_strcpy() to png_strncpy() (David + Hill). + Make test for NULL row_buf at the beginning of png_do_read_transformations + unconditional. + +version 1.2.19beta12 [May 28, 2007] + Revised pnggccrd.c. + +version 1.2.19beta13 [June 14, 2007] + Prefer PNG_USE_PNGVCRD when _MSC_VER is defined in pngconf.h + +version 1.2.19beta14 [June 16, 2007] + Fix bug with handling of 16-bit transparency, introduced in 1.2.19beta2 + +version 1.2.19beta15 [June 17, 2007] + Revised pnggccrd.c. + +version 1.2.19beta16 [June 18, 2007] + Revised pnggccrd.c again. + Updated contrib/gregbook. + Changed '#include "pnggccrd.c"' to 'include "$srcdir/pnggccrd.c"' + in configure.ac + +version 1.2.19beta17 [June 19, 2007] + Revised many of the makefiles, to set -DPNG_NO_MMX_CODE where needed + and to not use -O3 unless -DPNG_NO_MMX_CODE is also set. + +version 1.2.19beta18 [June 23, 2007] + Replaced some C++ style comments with C style comments in pnggccrd.c. + Copied optimized C code from pnggccrd.c to pngrutil.c, removed dependency + on pnggccrd.o from many makefiles. + Added sl and dylib to list of extensions be installed by Makefile.am + +version 1.2.19beta19 [June 28, 2007] + Fixed testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN in pngrtran.c + More cleanup of pnggccrd.c and pngvcrd.c + +version 1.2.19beta20 [June 29, 2007] + Rebuilt Makefile.in and configure using libtool-1.5.24. + Fixed typo in pnggccrd.c + +version 1.2.19beta21 [June 30, 2007] + More revision of pnggccrd.c + Added "test" target to Makefile.in and Makefile.am + +version 1.2.19beta22 [July 3, 2007] + Added info about pngrutil/pnggccrd/pngvcrd to png_get_header_version() + Fix type definition of dummy_value_a, b in pnggccrd.c + +version 1.2.19beta23 [July 10, 2007] + Revert change to type definition of dummy_value_a, b in pnggccrd.c + Make sure __PIC__ is defined in pnggccrd.c when PIC is defined. + Require gcc-4.1 or better to use PNG_HAVE_MMX_FILTER_ROW on x86_64 platforms + +version 1.2.19beta24 [July 14, 2007] + Added PNG_NO_READ_FILTER, PNG_NO_WRITE_FILTER, PNG_NO_WARNING macros. + Added contrib/pngminim to demonstrate building minimal encoder and decoder + +version 1.2.19beta25 [July 15, 2007] + Removed the new PNG_NO_READ_FILTER macro since it would make the library + unable to read valid PNG files, and filtering is at the heart of the + PNG format. + +version 1.2.19beta26 [July 16, 2007] + Changed "png_free(str)" to "png_free(png_ptr,str)" in pngrutil.c WinCE + code (Yves Piguet). This bug was introduced in libpng-1.2.14. + Updated scripts/CMakeLists.txt + Relocated a misplaced #endif in pnggccrd.c + +version 1.2.19beta27 [July 17, 2007] + Fixed incorrect stride and number of bytes copied (was 4 instead of + 6 bytes) in the cleanup loop of pnggccrd.c and pngvcrd.c for handling + the end of 48-bit interlaced rows (Glenn R-P). + +version 1.2.19beta28 [July 19, 2007] + Removed requirement for gcc-4.1 or better to use PNG_HAVE_MMX_FILTER_ROW + on x86_64 platforms + Added png_warning() in pngrutil.c for short iCCP, iTXt, sPLT, or zTXT chunks. + Revised pngtest.c so warnings are displayed regardless of PNG_NO_STDIO. + +version 1.2.19beta29 [July 20, 2007] + Fix typo in pnggccrd.c (%%eax should be %%ax in secondloop48) + +version 1.2.19beta30 [July 26, 2007] + Revised pnggccrd.c + +version 1.2.19beta31 [July 27, 2007] + Fix typos in pnggccrd.c + +version 1.0.27rc1 and 1.2.19rc1 [July 31, 2007] + Disable PNG_MMX_CODE_SUPPORTED when PNG_ASSEMBLER_CODE_SUPPORTED is off. + Enable PNG_MMX_READ_FILTER_* by default, except when gcc-3.x is being + used (they were inadvertently disabled in libpng-1.2.19beta23). + Fix some debugging statements in pnggccrd.c and pngrutil.c + Added information about disabling the MMX code in libpng documentation. + +version 1.0.27rc2 and 1.2.19rc2 [August 4, 2007] + Removed some "#if 0" blocks. + Made a global struct local in pngvcrd.c to make it thread safe. + Issue a png_error() if application attempts to transform a row tht + has not been initialized. + +version 1.0.27rc3 and 1.2.19rc3 [August 9, 2007] + Slightly revised pngvcrd.c + +version 1.0.27rc4 and 1.2.19rc4 [August 9, 2007] + Revised pnggccrd.c debugging change of rc1, which was broken. + Revised scripts/CMakeLists.txt + Change default to PNG_NO_GLOBAL_ARRAYS for MSVC. + Turn off PNG_FLAG_ROW_INIT flag when setting transforms that expand pixels. + +version 1.0.27rc5 and 1.2.19rc5 [August 10, 2007] + Fix typo (missing '"') in pnggccrd.c + Revise handling of png_strtod in recent versions of WINCE + +version 1.0.27rc6 and 1.2.19rc6 [August 15, 2007] + Fix typo (missing ',') in contrib/gregbook/readpng2.c + Undid row initialization error exit added to rc2 and rc4. + +version 1.0.27 and 1.2.19 [August 18, 2007] + Conditionally restored row initialization error exit. + +version 1.2.20beta01 [August 19, 2007] + Fixed problem with compiling pnggccrd.c on Intel-Apple platforms. + Changed png_malloc() to png_malloc_warn() in png_set_sPLT(). + Added PNG_NO_ERROR_TEXT feature, with demo in contrib/pngminim + Removed define PNG_WARN_UNINITIALIZED_ROW 1 /* 0: warning; 1: error */ + because it caused some trouble. + +version 1.2.20beta02 [August 20, 2007] + Avoid compiling pnggccrd.c on Intel-Apple platforms. + +version 1.2.20beta03 [August 20, 2007] + Added "/D PNG_NO_MMX_CODE" to the non-mmx builds of projects/visualc6 + and visualc71. + +version 1.2.20beta04 [August 21, 2007] + Revised pngvcrd.c for improved efficiency (Steve Snyder). + +version 1.2.20rc1 [August 23, 2007] + Revised pngconf.h to set PNG_NO_MMX_CODE for gcc-3.x compilers. + +version 1.2.20rc2 [August 27, 2007] + Revised scripts/CMakeLists.txt + Revised #ifdefs to ensure one and only one of pnggccrd.c, pngvcrd.c, + or part of pngrutil.c is selected. + +version 1.2.20rc3 [August 30, 2007] + Remove a little more code in pngwutil.c when PNG_NO_WRITE_FILTER is selected. + Added /D _CRT_SECURE_NO_WARNINGS to visual6c and visualc71 projects. + Compile png_mmx_support() in png.c even when PNG_NO_MMX_CODE is defined. + Restored a "superfluous" #ifdef that was removed from 1.2.20rc2 pnggccrd.c, + breaking the png_mmx_support() function. + +version 1.2.20rc4 [September 1, 2007] + Removed Intel contributions (MMX, Optimized C). + +version 1.2.20rc5 [September 2, 2007] + Restored configure and Makefile.in to rc3 and put a snippet of code in + pnggccrd.c, to ensure configure makes the same PNG_NO_MMX_CODE selection + +version 1.2.20rc6 [September 2, 2007] + Fixed bugs in scripts/CMakeLists.txt + Removed pngvcrd.c references from msvc projects. + +version 1.0.28 and 1.2.20 [September 8, 2007] + Removed "(NO READ SUPPORT)" from png_get_header_version() string. + +version 1.2.21beta1 [September 14, 2007] + Fixed various mistakes reported by George Cook and Jeff Phillips: + logical vs bitwise NOT in pngrtran.c, bug introduced in 1.2.19rc2 + 16-bit cheap transparency expansion, bug introduced in 1.2.19beta2 + errors with sizeof(unknown_chunk.name), bugs introduced in 1.2.19beta11 + <= compare with unsigned var in pngset.c, should be ==. + +version 1.2.21beta2 [September 18, 2007] + Removed some extraneous typecasts. + +version 1.2.21rc1 [September 25, 2007] + Fixed potential out-of-bounds reads in png_handle_pCAL() and + png_handle_ztXt() ("flayer" results reported by Tavis Ormandy). + +version 1.2.21rc2 [September 26, 2007] + Fixed potential out-of-bounds reads in png_handle_sCAL(), + png_handle_iTXt(), and png_push_read_tEXt(). + Remove some PNG_CONST declarations from pngwutil.c to avoid compiler warnings + Revised makefiles to update paths in libpng.pc properly. + +version 1.2.21rc3 [September 27, 2007] + Revised makefiles to update "Libs" in libpng.pc properly. + +version 1.0.29 and 1.2.21rc3 [October 4, 2007] + No changes. + +version 1.2.22beta1 [October 4, 2007] + Again, fixed logical vs bitwise NOT in pngrtran.c, bug introduced + in 1.2.19rc2 + +version 1.2.22beta2 [October 5, 2007] + Fixed string length error in pngset.c (caused crashes while decoding iCCP) + Add terminating NULL after each instance of png_strncpy(). + +version 1.2.22beta3 [October 6, 2007] + Fix two off-by-one terminating NULL after png_strncpy(). + +version 1.2.22beta4 [October 7, 2007] + Changed some 0 to '\0'. + +version 1.0.30rc1 and 1.2.22rc1 [October 8, 2007] + No changes. + +version 1.0.30 and 1.2.22 [October 13, 2007] + No changes. + +version 1.2.23beta01 [October 15, 2007] + Reduced number of invocations of png_strlen() in pngset.c. + Changed [azAZ09_] to [_abcde...89] in Makefile.am for better localization. + +version 1.2.23beta02 [October 16, 2007] + Eliminated png_strncpy() and png_strcpy() (Pierre Poissinger) + Changed $AN to $(AN) in Makefile.am. + +version 1.2.23beta03 [October 16, 2007] + Fixed off-by-one error in pngset.c + Restore statement to set last character of buffer to \0 in pngerror.c + +version 1.2.23beta04 [October 23, 2007] + Reject attempt to set all-zero cHRM values. + +version 1.2.23beta05 [October 26, 2007] + Add missing quotes in projects/visualc6, lost in version 1.2.20rc3 + +version 1.2.23rc01 [November 2, 2007] + No changes. + +version 1.2.23 [November 6, 2007] + No changes. + +version 1.2.24beta01 [November 19, 2007] + Moved misplaced test for malloc failure in png_set_sPLT(). This bug was + introduced in libpng-1.2.20beta01. + Ifdef out avg_row etc from png.h and pngwrite.c when PNG_NO_WRITE_FILTER + Do not use png_ptr->free_fn and png_ptr->mem_fn in png_destroy_read_struct() + when png_ptr is NULL (Marshall Clow). + Updated handling of symbol prefixes in Makefile.am and configure.ac (Mike + Frysinger). + +version 1.2.24beta02 [November 30, 2007] + Removed a useless test and fixed incorrect test in png_set_cHRM_fixed() + (David Hill). + +version 1.2.24rc01 [December 7, 2007] + No changes. + +version 1.2.24 [December 14, 2007] + Make sure not to redefine _BSD_SOURCE in pngconf.h + Revised gather.sh and makefile.std in contrib/pngminim to avoid compiling + unused files. + +version 1.2.25beta01 [January 7, 2008] + Fixed bug with unknown chunk handling, introduced in version 1.2.17rc2 + +version 1.2.25beta02 [January 10, 2008] + Prevent gamma from being applied twice. + +version 1.2.25rc01 [January 17, 2008] + No changes. + +version 1.2.25beta03 [January 22, 2008] + Fixed some continue-after-malloc-failure errors in pngset.c (David Hill) + Check for info_ptr == NULL in png_read_info() and png_process_data(). + Check for possible use of NULL user_png_ver[] in png_create_read_struct(). + Change "if (swidth == NULL)" to "if (sheight == NULL)" in png_handle_sCAL + (bug introduced in libpng-1.2.4/1.0.13). + Return from png_destroy_read_struct() if png_ptr_ptr is NULL. + Fix overflow of "msg" in png_decompress_chunk(). + +version 1.2.25beta04 [January 26, 2008] + Work around Coverity bug report by slightly refactoring + png_read_push_finish_row() + +version 1.2.25beta05 [January 31, 2008] + Added libpng-1.2.25beta05.tar.lzma to distribution. Get the lzma codec + from . + Added lp1225b05.7z to distribution. Get the 7-zip decoder from + from . + Fixed some broken links in the README file. + +version 1.2.25beta06 [February 6, 2008] + Refactored png_read_push_finish_row() again, trying to satisfy Coverity. + Fixed potential NULL dereference of png_ptr in png_destroy_write_struct(); + clarified potential NULL dereference of png_ptr in png_destroy_read_struct(); + fixed potential NULL dereference of info_ptr in png_handle_bKGD(); + fixed potential NULL dereference of user_png_ver[] in + png_create_write_struct_2(). (Coverity) + +version 1.2.25rc02 [February 10, 2008] + Reset png_ptr->pass in png_read_push_finish_row() before break. + Changed "pass" from png_byte to int. + +version 1.2.25 and 1.0.31 [February 18, 2008] + No changes. + +version 1.2.26beta01 [February 21, 2008] + Added missing "(" in pngmem.c. Bug introduced in libpng-1.2.2/1.0.13 + +version 1.2.26beta02 [March 12, 2008] + Refined error message returned from deflateInit2 in pngwutil.c + Check IHDR length in png_push_read_chunk() before saving it. + +version 1.2.26beta03 [March 16, 2008] + Revised contrib/gregbook to handle premature end-of-file and file + read errors correctly. + +version 1.2.26beta04 [March 18, 2008] + Free png_ptr->big_row_buf and png_ptr->prev_row before allocating + new copies in png_read_start_row(). Bug introduced in libpng-1.2.22. + +version 1.2.26beta05 [March 19, 2008] + Removed extra png_free() added in libpng-1.2.26beta04. + +version 1.2.26beta06 [March 19, 2008] + Avoid reallocating big_row_buf and prev_row when the size does not increase. + +version 1.2.26rc01 [March 26, 2008] + Ifdef out some code that is unused when interlacing is not supported. + +versions 1.0.32 and 1.2.26 [April 2, 2008] + No changes. + +version 1.2.27beta01 [April 12, 2008] + Fixed bug (introduced in libpng-1.0.5h) with handling zero-length + unknown chunks. + Added more information about png_set_keep_unknown_chunks() to the + documentation. + Reject tRNS chunk with out-of-range samples instead of masking off + the invalid high bits as done in since libpng-1.2.19beta5. + +version 1.2.27beta02 [April 13, 2008] + Revised documentation about unknown chunk and user chunk handling. + Keep tRNS chunk with out-of-range samples and issue a png_warning(). + +version 1.2.27beta03 [April 14, 2008] + Added check for NULL ptr in TURBOC version of png_free_default(). + Removed several unnecessary checks for NULL before calling png_free(). + Revised png_set_tRNS() so that calling it twice removes and invalidates + the previous call. + Revised pngtest to check for out-of-range tRNS samples. + +version 1.2.27beta04 [April 18, 2008] + Added AC_LIBTOOL_WIN32_DLL to configure.ac + Rebuilt Makefile.in, aclocal.m4, and configure with autoconf-2.62 + +version 1.2.27beta05 [April 19, 2008] + Added MAINTAINERCLEANFILES variable to Makefile.am + +version 1.2.27beta06 [April 21, 2008] + Avoid changing color_type from GRAY to RGB by + png_set_expand_gray_1_2_4_to_8(). + +version 1.2.27rc01 [April 23, 2008] + Fix broken URL for rfc2083 in png.5 and libpng-*.txt + +version 1.0.33 and 1.2.27 [April 30, 2008] + No changes. + +version 1.0.34 and 1.2.28 [April 30, 2008] + Rebuilt Makefile.in, aclocal.m4, and configure with autoconf-2.61 + due to backward incompatibilities. + Removed a stray object file from contrib/gregbook + +version 1.2.29beta01 [May 1, 2008] + Removed some stray *.diff and *.orig files + +version 1.2.29beta02 [May 1, 2008] + Reverted Makefile.in, aclocal.m4, and configure to the libpng-1.2.26 + versions. + +version 1.2.29beta03 [May 2, 2008] + Added --force to autogen libtoolize options and --force-missing to + automake options. + Changed $(ECHO) to echo in Makefile.am and Makefile.in + Updated all configure files to autoconf-2.62 + Comment out pnggcrd.c code with #ifdef/#endif if using MSC_VER + +version 1.2.29rc01 [May 4, 2008] + No changes. + +version 1.0.35 and 1.2.29 [May 8, 2008] + No changes. + +version 1.0.37 [May 9, 2008] + Updated Makefile.in and configure (omitted version 1.0.36). + +version 1.2.30beta01 [May 29, 2008] + Updated libpng.pc-configure.in and libpng-config.in per debian bug reports. + +version 1.2.30beta02 [June 25, 2008] + Restored png_flush(png_ptr) at the end of png_write_end(), that was + removed from libpng-1.0.9beta03. + +version 1.2.30beta03 [July 6, 2008] + Merged some cosmetic whitespace changes from libpng-1.4.0beta19. + Inline call of png_get_uint_32() in png_get_uint_31(), as in 1.4.0beta19. + Added demo of decoding vpAg and sTER chunks to pngtest.c, from 1.4.0beta19. + Changed PNGMAJ from 0 to 12 in makefile.darwin, which does not like 0. + Added new private function png_read_chunk_header() from 1.4.0beta19. + Merge reading of chunk length and chunk type into a single 8-byte read. + Merge writing of chunk length and chunk type into a single 8-byte write. + +version 1.2.30beta04 [July 10, 2008] + Merged more cosmetic whitespace changes from libpng-1.4.0beta19. + +version 1.0.38rc01, 1.2.30rc01 [July 18, 2008] + No changes. + +version 1.0.38rc02, 1.2.30rc02 [July 21, 2008] + Moved local array "chunkdata" from pngrutil.c to the png_struct, so + it will be freed by png_read_destroy() in case of a read error (Kurt + Christensen). + +version 1.0.38rc03, 1.2.30rc03 [July 21, 2008] + Changed "purpose" and "buffer" to png_ptr->chunkdata to avoid memory leaking. + +version 1.0.38rc04, 1.2.30rc04 [July 22, 2008] + Changed "chunkdata = NULL" to "png_ptr->chunkdata = NULL" several places in + png_decompress_chunk(). + +version 1.0.38rc05, 1.2.30rc05 [July 25, 2008] + Changed all remaining "chunkdata" to "png_ptr->chunkdata" in + png_decompress_chunk() and remove chunkdata from parameter list. + Put a call to png_check_chunk_name() in png_read_chunk_header(). + Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. + Removed two calls to png_check_chunk_name() occuring later in the process. + +version 1.0.38rc06, 1.2.30rc06 [July 29, 2008] + Added a call to png_check_chunk_name() in pngpread.c + Reverted png_check_chunk_name() to accept a name with a lowercase 3rd byte. + +version 1.0.38r07, 1.2.30r07 [August 2, 2008] + Changed "-Wall" to "-W -Wall" in the CFLAGS in all makefiles (Cosmin Truta) + Declared png_ptr "volatile" in pngread.c and pngwrite.c to avoid warnings. + Added code in pngset.c to quiet compiler warnings. + Updated contrib/visupng/cexcept.h to version 2.0.1 + Relocated a misplaced "#endif /* PNG_NO_WRITE_FILTER */" in pngwutil.c + +version 1.0.38r08, 1.2.30r08 [August 2, 2008] + Enclose "volatile" declarations in #ifdef PNG_SETJMP_SUPPORTED (Cosmin). + +version 1.0.38, 1.2.30 [August 14, 2008] + No changes. + +version 1.2.31rc01 [August 19, 2008] + Removed extra crc check at the end of png_handle_cHRM(). Bug introduced + in libpng-1.2.30beta03 (Heiko Nitzsche). + +version 1.2.31rc02 [August 19, 2008] + Added PNG_WRITE_FLUSH_SUPPORTED block around new png_flush() call. + +version 1.2.31rc03 [August 19, 2008] + Added PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED block, off by default, around + new png_flush(). + +version 1.0.39, 1.2.31 [August 21, 2008] + No changes. + +version 1.2.32beta01 [September 6, 2008] + Shortened tIME_string to 29 bytes in pngtest.c (bug introduced in + libpng-1.2.22). + Fixed off-by-one error introduced in png_push_read_zTXt() function in + libpng-1.2.30beta04/pngpread.c (Harald van Dijk) + These bugs have been given the vulnerability id CVE-2008-3964. + +version 1.0.40, 1.2.32 [September 18, 2008] + No changes. + +version 1.2.33beta01 [October 6, 2008] + Revised makefile.darwin to fix shared library numbering. + Change png_set_gray_1_2_4_to_8() to png_set_expand_gray_1_2_4_to_8() + in example.c (debian bug report) + +version 1.2.33rc01 [October 15, 2008] + No changes. + +version 1.0.41rc01, version 1.2.33rc02 [October 23, 2008] + Changed remaining "key" to "png_ptr->chunkdata" in png_handle_tEXt() + to avoid memory leak after memory failure while reading tEXt chunk.` + +version 1.2.33 [October 31, 2008] + No changes. + +version 1.2.34beta01 [November 27, 2008] + Revised png_warning() to write its message on standard output by default + when warning_fn is NULL. This was the behavior prior to libpng-1.2.9beta9. + Fixed string vs pointer-to-string error in png_check_keyword(). + Added png_check_cHRM_fixed() in png.c and moved checking from pngget.c, + pngrutil.c, and pngwrite.c, and eliminated floating point cHRM checking. + Added check for zero-area RGB cHRM triangle in png_check_cHRM_fixed(). + In png_check_cHRM_fixed(), ensure white_y is > 0, and removed redundant + check for all-zero coordinates that is detected by the triangle check. + Revised png_warning() to write its message on standard output by default + when warning_fn is NULL. + +version 1.2.34beta02 [November 28, 2008] + Corrected off-by-one error in bKGD validity check in png_write_bKGD() + and in png_handle_bKGD(). + +version 1.2.34beta03 [December 1, 2008] + Revised bKGD validity check to use >= x instead of > x + 1 + Merged with png_debug from libpng-1.4.0 to remove newlines. + +version 1.2.34beta04 [December 2, 2008] + More merging with png_debug from libpng-1.4.0 to remove newlines. + +version 1.2.34beta05 [December 5, 2008] + Removed redundant check for key==NULL before calling png_check_keyword() + to ensure that new_key gets initialized and removed extra warning + (Arvan Pritchard). + +version 1.2.34beta06 [December 9, 2008] + In png_write_png(), respect the placement of the filler bytes in an earlier + call to png_set_filler() (Jim Barry). + +version 1.2.34beta07 [December 9, 2008] + Undid previous change and added PNG_TRANSFORM_STRIP_FILLER_BEFORE and + PNG_TRANSFORM_STRIP_FILLER_AFTER conditionals and deprecated + PNG_TRANSFORM_STRIP_FILLER (Jim Barry). + +version 1.0.42rc01, 1.2.34rc01 [December 11, 2008] + No changes. + +version 1.0.42, 1.2.34 [December 18, 2008] + No changes. + +version 1.2.35beta01 [February 4, 2009] + Zero out some arrays of pointers after png_malloc(). (Tavis Ormandy) + +version 1.2.35beta02 [February 4, 2009] + Zero out more arrays of pointers after png_malloc(). + +version 1.2.35beta03 [February 5, 2009] + Use png_memset() instead of a loop to intialize pointers. We realize + this will not work on platforms where the NULL pointer is not all zeroes. + +version 1.2.35rc01 [February 11, 2009] + No changes. + +version 1.2.35rc02 [February 12, 2009] + Fix typo in new png_memset call in pngset.c (png_color should be png_charp) + +version 1.0.43 and 1.2.35 [February 14, 2009] + No changes. + +version 1.2.36beta01 [February 28, 2009] + Revised comments in png_set_read_fn() and png_set_write_fn(). + Revised order of #ifdef's and indentation in png_debug definitions of png.h + bug introduced in libpng-1.2.34. + +version 1.2.36beta02 [March 21, 2009] + Use png_memset() after png_malloc() of big_row_buf when reading an + interlaced file, to avoid a possible UMR. + Undid recent revision of PNG_NO_STDIO version of png_write_flush(). Users + having trouble with fflush() can build with PNG_NO_WRITE_FLUSH defined. + Revised libpng*.txt documentation about use of png_write_flush(). + Removed fflush() from pngtest.c. + Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h + +version 1.2.36beta03 [March 27, 2009] + Relocated misplaced PNG_1_0_X define in png.h that caused the prototype + for png_set_strip_error_numbers() to be omitted from PNG_NO_ASSEMBLER_CODE + builds. This bug was introduced in libpng-1.2.15beta4. + Added a section on differences between 1.0.x and 1.2.x to libpng.3/libpng.txt + +version 1.2.36beta04 [April 5, 2009] + Fixed potential memory leak of "new_name" in png_write_iCCP() (Ralph Giles) + +version 1.2.36beta05 [April 24, 2009] + Added "ifndef PNG_SKIP_SETJMP_CHECK" block in pngconf.h to allow + application code writers to bypass the check for multiple inclusion + of setjmp.h when they know that it is safe to ignore the situation. + Made some cosmetic changes to whitespace in pngtest output. + Renamed "user_chunk_data" to "my_user_chunk_data" in pngtest.c to suppress + "shadowed declaration" warning from gcc-4.3.3. + Renamed "gamma" to "png_gamma" in pngset.c to avoid "shadowed declaration" + warning about a global "gamma" variable in math.h on some platforms. + +version 1.2.36rc01 [April 30, 2009] + No changes. + +version 1.0.44 and 1.2.36 [May 7, 2009] + No changes. + +version 1.2.37beta01 [May 14, 2009] + Fixed inconsistency in pngrutil.c, introduced in libpng-1.2.36. The + memset() was using "png_ptr->rowbytes" instead of "row_bytes", which + the corresponding png_malloc() uses (Joe Drew). + Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri) + Updated some of the makefiles in the scripts directory (merged with + those in libpng-1.4.0beta57). + +version 1.2.37beta02 [May 19, 2009] + Fixed typo in libpng documentation (FILTER_AVE should be FILTER_AVG) + Relocated misplaced #endif in pngwrite.c, sCAL chunk handler. + Conditionally compile png_read_finish_row() which is not used by + progressive readers. + Added contrib/pngminim/preader to demonstrate building minimal progressive + decoder, based on contrib/gregbook with embedded libpng and zlib. + +version 1.2.37beta03 [May 20, 2009] + In contrib/pngminim/*, renamed "makefile.std" to "makefile", since there + is only one makefile in those directories, and revised the README files + accordingly. + Reformated sources in libpng style (3-space indentation, comment format) + +version 1.2.37rc01 [May 27, 2009] + No changes. + +versions 1.2.37 and 1.0.45 [June 4, 2009] + Reformatted several remaining "else statement;" and "if () statement;" into + two lines. + Added "#define PNG_NO_WRITE_SWAP" to contrib/pngminim/encoder/pngusr.h + and "define PNG_NO_READ_SWAP" to decoder/pngusr.h and preader/pngusr.h + Added sections about the git repository and our coding style to the + documentation (merged from libpng-1.4.0beta62) + Added a section to the libpng documentation about using png_get_io_ptr() + in configure scripts to detect the presence of libpng. + +version 1.2.38beta01 [June 17, 2009] + Revised libpng*.txt and libpng.3 to mention calling png_set_IHDR() + multiple times and to specify the sample order in the tRNS chunk, + because the ISO PNG specification has a typo in the tRNS table. + Changed several PNG_UNKNOWN_CHUNK_SUPPORTED to + PNG_HANDLE_AS_UNKNOWN_SUPPORTED, to make the png_set_keep mechanism + available for ignoring known chunks even when not saving unknown chunks. + Adopted preference for consistent use of "#ifdef" and "#ifndef" versus + "#if defined()" and "if !defined()" where possible. + Added PNG_NO_HANDLE_AS_UNKNOWN in the PNG_LEGACY_SUPPORTED block of + pngconf.h, and moved the various unknown chunk macro definitions + outside of the PNG_READ|WRITE_ANCILLARY_CHUNK_SUPPORTED blocks. + +version 1.0.46 [June 18, 2009] + Removed some editing cruft from scripts/libpng.pc.in and some makefiles. + +version 1.2.38rc01 [June 24, 2009] + No changes. + +version 1.2.38rc02 [June 29, 2009] + Added a reference to the libpng license in each source file. + +version 1.2.38rc03 [July 11, 2009] + Revised references to the libpng license in pngconf.h and contrib/visupng + source files. + Rebuilt configure scripts with autoconf-2.63. + +version 1.0.47 and 1.2.38 [July 16, 2009] + No changes. + +version 1.2.39beta01 [July 25, 2009] + Added a prototype for png_64bit_product() in png.c + +version 1.2.39beta02 [July 27, 2009] + Avoid a possible NULL dereference in debug build, in png_set_text_2(). + (bug introduced in libpng-0.95, discovered by Evan Rouault) + +version 1.2.39beta03 [July 29, 2009] + Relocated new png_64_bit_product() prototype into png.h + Expanded the information about prototypes in the libpng style section of + the documentation. + Rebuilt configure scripts with autoconf-2.64. + +version 1.2.39beta04 [August 1, 2009] + Replaced *.tar.lzma with *.txz in distribution. Get the xz codec + from . + +version 1.2.39beta05 [August 1, 2009] + Reject attempt to write iCCP chunk with negative embedded profile length + (JD Chen) + +version 1.2.39c01 [August 6, 2009] + No changes. + +version 1.2.39 and 1.0.48 [August 13, 2009] + No changes. + +version 1.2.40beta01 [August 20, 2009] + Removed an extra png_debug() recently added to png_write_find_filter(). + Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. + +version 1.2.40rc01 [September 2, 2009] + Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) + +version 1.2.40 and 1.0.49 [September 2, 2009] + No changes. + +version 1.0.50 [September 10, 2009] + Removed some editing cruft from pngset.c and pngwutil.c. + +version 1.2.41beta01 [September 25, 2009] + Moved redundant IHDR checking into new png_check_IHDR() in png.c + and report all errors found in the IHDR data. + Eliminated useless call to png_check_cHRM() from pngset.c + Expanded TAB characters in pngrtran.c + +version 1.2.41beta02 [September 30, 2009] + Revised png_check_IHDR(). + +version 1.2.41beta03 [October 1, 2009] + Revised png_check_IHDR() again, to check info_ptr members instead of + the contents of the returned parameters. + +version 1.2.41beta04 [October 7, 2009] + Added "xcode" project similar one already in libpng-1.4.0beta (Alam Arias). + Ported some cosmetic changes from libpng-1.4.0beta86. + Eliminated a shadowed declaration of "pp" in png_handle_sPLT(). + +version 1.2.41beta05 [October 17, 2009] + Revised pngconf.h to make it easier to enable iTXt support. From libpng + version 1.2.9 through 1.2.40, defining PNG_iTXt_SUPPORTED did not work + as expected. + Ported some cosmetic changes from libpng-1.4.0beta87, changing + many "#if defined(x)" to "#ifdef x". + +version 1.2.41beta06 [October 18, 2009] + Restored PNG_USE_LOCAL_ARRAYS code in pngread.c that was inadvertently + deleted in libpng-1.2.41beta05. + Converted all PNG_NO_* tests to PNG_*_SUPPORTED everywhere except pngconf.h + as in libpng-1.4.0beta78 and later. + +version 1.2.41beta07 [October 21, 2009] + Ported some cosmetic changes from libpng-1.4.0rc01, changing + many "#if defined(x)" to "#ifdef x" in png.h and pngconf.h. + +version 1.2.41beta08 [October 30, 2009] + Ported from libpng-1.4.0rc01: png_calloc(), png_get_io_chunk_name(), + png_get_io_state(), png_set_user_cache_max(), png_get_user_cache_max(), + png_set_premultiply_alpha, and png_do_read_premultiply_alpha(). + Relocated png_do_chop() ahead of building gamma tables in pngrtran.c + This avoids building 16-bit gamma tables unnecessarily. + +version 1.2.41beta09 [November 1, 2009] + Removed a harmless extra png_set_invert_alpha() from pngwrite.c + More bugfixes and improvements to CMakeLists.txt (Philip Lowman) + Moved CMakeLists.txt from scripts into the main libpng directory. + Apply png_user_chunk_cache_max within png_decompress_chunk(). + Merged libpng-1.2.41.txt with libpng-1.4.0.txt where appropriate. + +version 1.2.41beta10 [November 1, 2009] + Enabled iTXt support by default. To ensure binary compatibility with + previous versions, the "lang" and "lang_key" members will be assumed + to be omitted from previous versions unless the current libpng + version was built with PNG_iTXt_SUPPORTED (which is otherwise no + longer necessary to gain iTXt support), as a signal that the user has + been building previous versions with PNG_iTXt_SUPPORTED as well. + +version 1.2.41beta11 [November 2, 2009] + Store user's user_png_ver in new png_ptr->user_png_ver element. + Revised iTXt support. To ensure binary compatibility with + previous versions, the "lang" and "lang_key" members will be assumed + to be omitted from versions prior to 1.2.41beta11 whenever there is a + library mismatch. + +version 1.2.41beta12 [November 2, 2009] + Free png_ptr->user_png_ver when destroying png_ptr. + +version 1.2.41beta13 [November 3, 2009] + Updated scripts/pngw32.def and projects/wince/png32ce.def + Copied projects/wince/png32ce.def to the scripts directory. + Added scripts/makefile.wce + Patched ltmain.sh for wince support. + Added PNG_CONVERT_tIME_SUPPORTED macro. + +version 1.2.41beta14 [November 8, 2009] + versions 1.2.41beta05 through 1.2.41beta13 were abandoned. + The 1.0.x/1.2.x series will only receive security updates from now on. + Make inclusion of time.h in pngconf.h depend on PNG_CONVERT_tIME_SUPPORTED + Make #define PNG_CONVERT_tIME_SUPPORTED depend on PNG_WRITE_tIME_SUPPORTED + Reverted iTXt compatibility stuff from 1.2.41beta05, 1.2.41beta11, and + 1.2.41beta12. + Reverted IOSTATE feature, user_cache_max, and premultiply_alpha features + from 1.2.41beta08. + Retained png_calloc() from 1.2.41beta08 but as a non-exported function, + and removed reference to png_calloc from scripts/*.def + +version 1.2.41beta15 [November 8, 2009] + Added PNG_DEPSTRUCT, PNG_DEPRECATED, PNG_USE_RESULT, PNG_NORETURN, and + PNG_ALLOCATED macros to detect deprecated direct access to the + png_struct or info_struct members and other deprecated usage in + applications (John Bowler). + Updated scripts/makefile* to add "-DPNG_CONFIGURE_LIBPNG" to CFLAGS, + to prevent warnings about direct access to png structs by libpng + functions while building libpng. They need to be tested, especially + those using compilers other than gcc. + Updated projects/visualc6 and visualc71 with "/d PNG_CONFIGURE_LIBPNG". + +version 1.2.41beta16 [November 9, 2009] + Removed three direct references to read_info_ptr members in pngtest.c + that were detected by the new PNG_DEPSTRUCT macro. + Only #define PNG_DEPSTRUCT, etc. in pngconf.h if not already defined. + +version 1.2.41beta17 [November 10, 2009] + Updated CMakeLists.txt to add "-DPNG_CONFIGURE_LIBPNG" to the definitions. + Marked deprecated function prototypes with PNG_DEPRECATED. + Marked memory allocation function prototypes with PNG_ALLOCATED. + Changed png_check_sig() to !png_sig_cmp() in contrib programs. + Corrected the png_get_IHDR() call in contrib/gregbook/readpng2.c + Added "-DPNG_CONFIGURE_LIBPNG" to the contrib/pngminum makefiles. + +version 1.2.41beta18 [November 11, 2009] + Renamed scripts/makefile.wce to scripts/makefile.cegcc + Marked nonexported functions with PNG_PRIVATE macro. + +version 1.2.41rc01 and 1.0.51rc01 [November 18, 2009] + Revised scripts/*.def to reflect functions actually exported by libpng. + Updated the copyright year in scripts/pngw32.rc from 2004 to 2009. + Moved descriptions of makefiles and other scripts out of INSTALL into + scripts/README.txt + +version 1.2.41rc02 [November 22, 2009] + Rebuilt the configure scripts with autoconf-2.65 + +version 1.2.41rc03 [November 25, 2009] + Disabled the new pedantic warnings about deprecated function use + and deprecated structure access unless the user defines + PNG_PEDANTIC_WARNINGS. + Added "#define PNG_NO_PEDANTIC_WARNINGS" in the libpng source files. + Removed "-DPNG_CONFIGURE_LIBPNG" from the makefiles and projects. + +version 1.2.41 and 1.0.51 [December 3, 2009] + Updated the list of files and made some cosmetic changes in README. + +version 1.2.42beta01 [December 4, 2009] + Removed "#define PNG_NO_ERROR_NUMBERS" that was inadvertently added + to pngconf.h in version 1.2.41. + Revised scripts/makefile.netbsd, makefile.openbsd, and makefile.sco + to put png.h and pngconf.h in $prefix/include, like the other scripts, + instead of in $prefix/include/libpng. Also revised makefile.sco + to put them in $prefix/include/libpng12 instead of in + $prefix/include/libpng/libpng12. + Removed leftover "-DPNG_CONFIGURE_LIBPNG" from scripts/makefile.darwin + +version 1.2.42beta02 [December 11, 2009] + Removed leftover "-DPNG_CONFIGURE_LIBPNG" from contrib/pngminim/*/makefile + Relocated png_do_chop() to its original position in pngrtran.c. The + change in version 1.2.41beta08 caused transparency to be handled wrong + in some 16-bit datastreams (Yusaku Sugai). + +version 1.2.42rc01 [December 17, 2009] + No changes. + +version 1.2.42rc02 [December 22, 2009] + Renamed libpng-pc.in back to libpng.pc.in and revised CMakeLists.txt + (revising changes made in 1.2.41beta17 and 1.2.41rc01) + +version 1.2.42rc03 [December 25, 2009] + Swapped PNG_UNKNOWN_CHUNKS_SUPPORTED and PNG_HANDLE_AS_UNKNOWN_SUPPORTED + in pngset.c to be consistent with other changes in version 1.2.38. + +version 1.2.42rc04 [January 1, 2010] + Marked png_memcpy_check() and png_memset_check() PNG_DEPRECATED. + Updated copyright year. + +version 1.2.42rc05 [January 2, 2010] + Avoid deprecated references to png_ptr-io_ptr and png_ptr->error_ptr + in pngtest.c + +version 1.2.42 and 1.0.52 [January 3, 2010] + No changes. + +version 1.2.43beta01 [January 27, 2010] + Updated CMakeLists.txt for consistent indentation and to avoid an + unclosed if-statement warning (Philip Lowman). + Removed "#ifdef PNG_1_0_X / #endif" surrounding + PNG_READ_16_TO_8_SUPPORTED and PNG_READ_GRAY_TO_RGB_SUPPORTED + in pngconf.h. These were added in libpng-1.2.41beta08 and libpng-1.0.51, + which introduced a binary incompatibility with libpng-1.0.50. + Backported new png_decompress_chunk() algorithm from libpng-1.4.1. + +version 1.2.43beta02 [February 1, 2010] + Backported two-pass png_decompress_chunk() algorithm from libpng-1.4.1. + +version 1.2.43beta03 [February 6, 2010] + Backported fast png_push_save_buffer() algorithm from libpng-1.4.1. + Backported some cosmetic changes from libpng-1.4.1. + +version 1.2.43beta04 [February 8, 2010] + Reverted recent changes to png_push_save-buffer(). + Removed PNGAPI declaration of png_calloc() and png_write_sig() in + 1ibpng-1.2.X, introduced by mistake in libpng-1.2.41. + Return allocated "old_buffer" in png_push_save_buffer() before png_error() + to avoid a potential memory leak. + +version 1.2.43beta05 [February 8, 2010] + Ported rewritten png_decompress_chunk() by John Bowler from libpng-1.4.1. + +version 1.0.53rc01 and 1.2.43rc01 [February 18, 2010] + No changes. + +version 1.0.53rc02 and 1.2.43rc02 [February 19, 2010] + Define _ALL_SOURCE in configure.ac, makefile.aix, and CMakeLists.txt + when using AIX compiler. + +version 1.0.53 and 1.2.43 [February 25, 2010] + Removed unused gzio.c from contrib/pngminim gather and makefile scripts + +version 1.2.44beta01 [June 18, 2010] + In pngpread.c: png_push_have_row() add check for new_row > height + Removed the now-redundant check for out-of-bounds new_row from example.c + +version 1.2.44beta02 [June 19, 2010] + In pngpread.c: png_push_process_row() add check for too many rows. + Removed the now-redundant check for new_row > height in png_push_have_row(). + +version 1.2.44beta03 [June 20, 2010] + Rewrote png_process_IDAT_data() to consistently treat extra data as warnings + and handle end conditions more cleanly. + Removed the new (beta02) check in png_push_process_row(). + +version 1.2.44rc01 [June 21, 2010] + Revised some comments in png_process_IDAT_data(). + +version 1.2.44rc02 [June 22, 2010] + Stop memory leak when reading a malformed sCAL chunk. + +version 1.2.44rc03 [June 23, 2010] + Revised pngpread.c patch of beta05 to avoid an endless loop. + +version 1.2.44 [June 26, 2010] + Updated some of the "last changed" dates. + +version 1.2.45beta01 [June 7, 2011] + Fixed uninitialized memory read in png_format_buffer() (Bug + report by Frank Busse, related to CVE-2004-0421). + Pass "" instead of '\0' to png_default_error() in png_err(). This mistake + was introduced in libpng-1.2.20beta01. + Check for up->location !PNG_AFTER_IDAT when writing unknown chunks + before IDAT. + Ported bugfix in pngrtran.c from 1.5.3: when expanding a paletted image, + always expand to RGBA if transparency is present. + +version 1.2.45beta02 [June 8, 2011] + Check for integer overflow in png_set_rgb_to_gray(). + +version 1.2.45beta03 [June 19, 2011] + Check for sCAL chunk too short. + +version 1.2.45rc01 and 1.0.55rc01 [June 30, 2011] + Updated "last changed" dates and copyright year. + +version 1.2.45 and 1.0.55 [July 7, 2011] + No changes. + +version 1.2.46rc01 and 1.0.56rc01 [July 8, 2011] + Reverted changes to Makefile.am and Makefile.in to libpng-1.2.44 versions. + +version 1.2.46rc02 and 1.0.56rc02 [July 8, 2011] + Added CMakeLists.txt, projects/xcode, and pnggccrd.c to EXTRA_DIST in + Makefile.am and Makefile.in + +version 1.2.46 and 1.0.56 [July 9, 2011] + Udated copyright year to 2011. + +version 1.2.47beta01 [February 17, 2012] + Updated contrib/pngminus/makefile.std (Samuli Souminen) + +version 1.0.57rc01 and 1.2.47rc01 [February 17, 2012] + Fixed CVE-2011-3026 buffer overrun bug. This bug was introduced when + iCCP chunk support was added at libpng-1.0.6. + +version 1.0.57 and 1.2.47 [February 18, 2012] + No changes. + +version 1.2.48beta01 [February 27, 2012] + Removed two useless #ifdef directives from pngread.c and one from pngrutil.c + Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from + pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; + now that png_ptr->buffer is inaccessible to applications, the special + handling is no longer useful. + Fixed bug with png_handle_hIST with odd chunk length (Frank Busse). + Fixed incorrect type (int copy should be png_size_t copy) in png_inflate(). + Fixed off-by-one bug in png_handle_sCAL() when using fixed point arithmetic, + causing out-of-bounds read in png_set_sCAL() because of failure to copy + the string terminators. This bug was introduced in libpng-1.0.6 (Frank + Busse). + +version 1.2.48rc01 [March 2, 2012] + Removed the png_free() of unused png_ptr->current_text from pngread.c. + Added libpng license text to pnggccrd.c and pngvcrd.c (requested by Chrome). + +version 1.2.48rc02 [March 2, 2012] + Removed all of the assembler code from pnggccrd.c and just "return 2;". + +version 1.0.58 and 1.2.48 [March 8, 2012] + No changes. + +version 1.0.59 and 1.2.49 [March 29, 2012] + Revised png_set_text_2() to avoid potential memory corruption (fixes + CVE-2011-3048, also known as CVE-2012-3425). + Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. + +version 1.0.60 and 1.2.50 [July 9, 2012] + Changed "a+w" to "u+w" in Makefile.in to fix CVE-2012-3386. + +version 1.2.51beta01 [January 22, 2013] + Ignore, with a warning, out-of-range value of num_trans in png_set_tRNS(). + Replaced AM_CONFIG_HEADER(config.h) with AC_CONFIG_HEADERS([config.h]) + in configure.ac + Changed default value of PNG_USER_CACHE_MAX from 0 to 32767 in pngconf.h. + +version 1.2.51beta02 [June 13, 2013] + Avoid a possible memory leak in contrib/gregbook/readpng.c + Revised libpng.3 so that "doclifter" can process it. + +version 1.2.51beta03 [January 1, 2014] + Changed '"%s"m' to '"%s" m' in png_debug macros to improve portability + among compilers. + Rebuilt the configure scripts with autoconf-2.69 and automake-1.14.1 + +version 1.2.51beta04 [January 10, 2014] + Removed potentially misleading warning from png_check_IHDR(). + +version 1.2.51beta05 [January 22, 2014] + Quiet set-but-not-used warnings in pngset.c + +version 1.2.51rc01 [January 28, 2014] + No changes. + +version 1.2.51rc02 [January 30, 2014] + Quiet an uninitialized memory warning from VC2013 in png_get_png(). + +version 1.2.51rc03 [February 3, 2014] + Quiet unused variable warnings from clang by porting PNG_UNUSED() from + libpng-1.4.6. + +version 1.2.51rc04 [February 3, 2014] + Added -DZ_SOLO to CFLAGS in contrib/pngminim/*/makefile + +version 1.0.61 and 1.2.51 [February 6, 2014] + Added an #ifdef PNG_FIXED_POINT_SUPPORTED/#endif in pngset.c + +Send comments/corrections/commendations to png-mng-implement at lists.sf.net +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) +or to glennrp at users.sourceforge.net + +Glenn R-P +#endif diff --git a/main/source/includes/lpng1251/CMakeLists.txt b/main/source/includes/lpng1251/CMakeLists.txt index 65c59287..c7976a03 100644 --- a/main/source/includes/lpng1251/CMakeLists.txt +++ b/main/source/includes/lpng1251/CMakeLists.txt @@ -1,284 +1,284 @@ -cmake_minimum_required(VERSION 2.4.3) -set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) - -if(UNIX AND NOT DEFINED CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING - "Choose the type of build, options are: - None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) - Debug - Release - RelWithDebInfo - MinSizeRel.") -endif() - -project(libpng C) -enable_testing() - -# Copyright (C) 2007-2010 Glenn Randers-Pehrson - -# This code is released under the libpng license. -# For conditions of distribution and use, see the disclaimer -# and license in png.h - -set(PNGLIB_MAJOR 1) -set(PNGLIB_MINOR 2) -set(PNGLIB_RELEASE 51) -set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) -set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) - -# needed packages -find_package(ZLIB REQUIRED) -include_directories(${ZLIB_INCLUDE_DIR}) - -if(NOT WIN32) - find_library(M_LIBRARY - NAMES m - PATHS /usr/lib /usr/local/lib - ) - if(NOT M_LIBRARY) - message(STATUS - "math library 'libm' not found - floating point support disabled") - endif() -else() - # not needed on windows - set(M_LIBRARY "") -endif() - -# COMMAND LINE OPTIONS -if(DEFINED PNG_SHARED) - option(PNG_SHARED "Build shared lib" ${PNG_SHARED}) -else() - option(PNG_SHARED "Build shared lib" ON) -endif() -if(DEFINED PNG_STATIC) - option(PNG_STATIC "Build static lib" ${PNG_STATIC}) -else() - option(PNG_STATIC "Build static lib" ON) -endif() - -if(MINGW) - option(PNG_TESTS "Build pngtest" NO) -else() - option(PNG_TESTS "Build pngtest" YES) -endif() - -option(PNG_NO_CONSOLE_IO "FIXME" YES) -option(PNG_NO_STDIO "FIXME" YES) -option(PNG_DEBUG "Build with debug output" NO) -option(PNGARG "FIXME" YES) -#TODO: -# PNG_CONSOLE_IO_SUPPORTED - -# maybe needs improving, but currently I don't know when we can enable what :) -set(png_asm_tmp "OFF") -if(NOT WIN32) - find_program(uname_executable NAMES uname PATHS /bin /usr/bin /usr/local/bin) - if(uname_executable) - exec_program(${uname_executable} - ARGS --machine OUTPUT_VARIABLE uname_output) - if("uname_output" MATCHES "^.*i[1-9]86.*$") - set(png_asm_tmp "ON") - else("uname_output" MATCHES "^.*i[1-9]86.*$") - set(png_asm_tmp "OFF") - endif("uname_output" MATCHES "^.*i[1-9]86.*$") - endif(uname_executable) -else() - # this env var is normally only set on win64 - set(TEXT "ProgramFiles(x86)") - if("$ENV{${TEXT}}" STREQUAL "") - set(png_asm_tmp "ON") - endif("$ENV{${TEXT}}" STREQUAL "") -endif() - -# SET LIBNAME -set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR}) - -# to distinguish between debug and release lib -set(CMAKE_DEBUG_POSTFIX "d") - - -# OUR SOURCES -set(libpng_sources - png.h - pngconf.h - png.c - pngerror.c - pngget.c - pngmem.c - pngpread.c - pngread.c - pngrio.c - pngrtran.c - pngrutil.c - pngset.c - pngtrans.c - pngwio.c - pngwrite.c - pngwtran.c - pngwutil.c -) -set(pngtest_sources - pngtest.c -) -# SOME NEEDED DEFINITIONS - -add_definitions(-DPNG_CONFIGURE_LIBPNG) - -if(_AIX) - add_definitions(-D_ALL_SOURCE) -endif(_AIX) - -if(MSVC) - add_definitions(-DPNG_NO_MODULEDEF -D_CRT_SECURE_NO_DEPRECATE) -endif(MSVC) - -if(PNG_SHARED OR NOT MSVC) - #if building msvc static this has NOT to be defined - add_definitions(-DZLIB_DLL) -endif() - -add_definitions(-DLIBPNG_NO_MMX) -add_definitions(-DPNG_NO_MMX_CODE) - - -if(PNG_CONSOLE_IO_SUPPORTED) - add_definitions(-DPNG_CONSOLE_IO_SUPPORTED) -endif() - -if(PNG_NO_CONSOLE_IO) - add_definitions(-DPNG_NO_CONSOLE_IO) -endif() - -if(PNG_NO_STDIO) - add_definitions(-DPNG_NO_STDIO) -endif() - -if(PNG_DEBUG) - add_definitions(-DPNG_DEBUG) -endif() - -if(NOT M_LIBRARY AND NOT WIN32) - add_definitions(-DPNG_NO_FLOATING_POINT_SUPPORTED) -endif() - -# NOW BUILD OUR TARGET -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIR}) - -if(PNG_SHARED) - add_library(${PNG_LIB_NAME} SHARED ${libpng_sources}) - if(MSVC) - # msvc does not append 'lib' - do it here to have consistent name - set_target_properties(${PNG_LIB_NAME} PROPERTIES PREFIX "lib") - endif() - target_link_libraries(${PNG_LIB_NAME} ${ZLIB_LIBRARY} ${M_LIBRARY}) -endif() - -if(PNG_STATIC) -# does not work without changing name - set(PNG_LIB_NAME_STATIC ${PNG_LIB_NAME}_static) - add_library(${PNG_LIB_NAME_STATIC} STATIC ${libpng_sources}) - if(MSVC) - # msvc does not append 'lib' - do it here to have consistent name - set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES PREFIX "lib") - endif() -endif() - - -if(PNG_SHARED AND WIN32) - set_target_properties(${PNG_LIB_NAME} PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL) -endif() - -if(PNG_TESTS AND PNG_SHARED) - # does not work with msvc due to png_lib_ver issue - add_executable(pngtest ${pngtest_sources}) - target_link_libraries(pngtest ${PNG_LIB_NAME}) - add_test(pngtest pngtest ${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png) -endif() - - -# CREATE PKGCONFIG FILES -# we use the same files like ./configure, so we have to set its vars -set(prefix ${CMAKE_INSTALL_PREFIX}) -set(exec_prefix ${CMAKE_INSTALL_PREFIX}) -set(libdir ${CMAKE_INSTALL_PREFIX}/lib) -set(includedir ${CMAKE_INSTALL_PREFIX}/include) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng-config.in - ${CMAKE_CURRENT_BINARY_DIR}/libpng-config) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng-config.in - ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config) - -# SET UP LINKS -if(PNG_SHARED) - set_target_properties(${PNG_LIB_NAME} PROPERTIES -# VERSION 0.${PNGLIB_RELEASE}.1.2.51 - VERSION 0.${PNGLIB_RELEASE}.0 - SOVERSION 0 - CLEAN_DIRECT_OUTPUT 1) -endif() -if(PNG_STATIC) - if(NOT WIN32) - # that's uncool on win32 - it overwrites our static import lib... - set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES - OUTPUT_NAME ${PNG_LIB_NAME} - CLEAN_DIRECT_OUTPUT 1) - endif() -endif() - -# INSTALL -if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) - if(PNG_SHARED) - install(TARGETS ${PNG_LIB_NAME} - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) - endif() - if(PNG_STATIC) - install(TARGETS ${PNG_LIB_NAME_STATIC} - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) - endif() -endif() - -if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) - install(FILES png.h pngconf.h DESTINATION include) - install(FILES png.h pngconf.h DESTINATION include/${PNGLIB_NAME}) -endif() -if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL ) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config DESTINATION bin) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config - DESTINATION bin) -endif() -if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) - # Install man pages - install(FILES libpng.3 libpngpf.3 DESTINATION man/man3) - install(FILES png.5 DESTINATION man/man5) - # Install pkg-config files - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc - DESTINATION lib/pkgconfig) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng-config - DESTINATION bin) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc - DESTINATION lib/pkgconfig) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config - DESTINATION bin) -endif() - -# what's with libpng.txt and all the extra files? - - -# UNINSTALL -# do we need this? - - -# DIST -# do we need this? - -# to create msvc import lib for mingw compiled shared lib -# pexports libpng.dll > libpng.def -# lib /def:libpng.def /machine:x86 - +cmake_minimum_required(VERSION 2.4.3) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +if(UNIX AND NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING + "Choose the type of build, options are: + None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) + Debug + Release + RelWithDebInfo + MinSizeRel.") +endif() + +project(libpng C) +enable_testing() + +# Copyright (C) 2007-2010 Glenn Randers-Pehrson + +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +set(PNGLIB_MAJOR 1) +set(PNGLIB_MINOR 2) +set(PNGLIB_RELEASE 51) +set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) +set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) + +# needed packages +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIR}) + +if(NOT WIN32) + find_library(M_LIBRARY + NAMES m + PATHS /usr/lib /usr/local/lib + ) + if(NOT M_LIBRARY) + message(STATUS + "math library 'libm' not found - floating point support disabled") + endif() +else() + # not needed on windows + set(M_LIBRARY "") +endif() + +# COMMAND LINE OPTIONS +if(DEFINED PNG_SHARED) + option(PNG_SHARED "Build shared lib" ${PNG_SHARED}) +else() + option(PNG_SHARED "Build shared lib" ON) +endif() +if(DEFINED PNG_STATIC) + option(PNG_STATIC "Build static lib" ${PNG_STATIC}) +else() + option(PNG_STATIC "Build static lib" ON) +endif() + +if(MINGW) + option(PNG_TESTS "Build pngtest" NO) +else() + option(PNG_TESTS "Build pngtest" YES) +endif() + +option(PNG_NO_CONSOLE_IO "FIXME" YES) +option(PNG_NO_STDIO "FIXME" YES) +option(PNG_DEBUG "Build with debug output" NO) +option(PNGARG "FIXME" YES) +#TODO: +# PNG_CONSOLE_IO_SUPPORTED + +# maybe needs improving, but currently I don't know when we can enable what :) +set(png_asm_tmp "OFF") +if(NOT WIN32) + find_program(uname_executable NAMES uname PATHS /bin /usr/bin /usr/local/bin) + if(uname_executable) + exec_program(${uname_executable} + ARGS --machine OUTPUT_VARIABLE uname_output) + if("uname_output" MATCHES "^.*i[1-9]86.*$") + set(png_asm_tmp "ON") + else("uname_output" MATCHES "^.*i[1-9]86.*$") + set(png_asm_tmp "OFF") + endif("uname_output" MATCHES "^.*i[1-9]86.*$") + endif(uname_executable) +else() + # this env var is normally only set on win64 + set(TEXT "ProgramFiles(x86)") + if("$ENV{${TEXT}}" STREQUAL "") + set(png_asm_tmp "ON") + endif("$ENV{${TEXT}}" STREQUAL "") +endif() + +# SET LIBNAME +set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR}) + +# to distinguish between debug and release lib +set(CMAKE_DEBUG_POSTFIX "d") + + +# OUR SOURCES +set(libpng_sources + png.h + pngconf.h + png.c + pngerror.c + pngget.c + pngmem.c + pngpread.c + pngread.c + pngrio.c + pngrtran.c + pngrutil.c + pngset.c + pngtrans.c + pngwio.c + pngwrite.c + pngwtran.c + pngwutil.c +) +set(pngtest_sources + pngtest.c +) +# SOME NEEDED DEFINITIONS + +add_definitions(-DPNG_CONFIGURE_LIBPNG) + +if(_AIX) + add_definitions(-D_ALL_SOURCE) +endif(_AIX) + +if(MSVC) + add_definitions(-DPNG_NO_MODULEDEF -D_CRT_SECURE_NO_DEPRECATE) +endif(MSVC) + +if(PNG_SHARED OR NOT MSVC) + #if building msvc static this has NOT to be defined + add_definitions(-DZLIB_DLL) +endif() + +add_definitions(-DLIBPNG_NO_MMX) +add_definitions(-DPNG_NO_MMX_CODE) + + +if(PNG_CONSOLE_IO_SUPPORTED) + add_definitions(-DPNG_CONSOLE_IO_SUPPORTED) +endif() + +if(PNG_NO_CONSOLE_IO) + add_definitions(-DPNG_NO_CONSOLE_IO) +endif() + +if(PNG_NO_STDIO) + add_definitions(-DPNG_NO_STDIO) +endif() + +if(PNG_DEBUG) + add_definitions(-DPNG_DEBUG) +endif() + +if(NOT M_LIBRARY AND NOT WIN32) + add_definitions(-DPNG_NO_FLOATING_POINT_SUPPORTED) +endif() + +# NOW BUILD OUR TARGET +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIR}) + +if(PNG_SHARED) + add_library(${PNG_LIB_NAME} SHARED ${libpng_sources}) + if(MSVC) + # msvc does not append 'lib' - do it here to have consistent name + set_target_properties(${PNG_LIB_NAME} PROPERTIES PREFIX "lib") + endif() + target_link_libraries(${PNG_LIB_NAME} ${ZLIB_LIBRARY} ${M_LIBRARY}) +endif() + +if(PNG_STATIC) +# does not work without changing name + set(PNG_LIB_NAME_STATIC ${PNG_LIB_NAME}_static) + add_library(${PNG_LIB_NAME_STATIC} STATIC ${libpng_sources}) + if(MSVC) + # msvc does not append 'lib' - do it here to have consistent name + set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES PREFIX "lib") + endif() +endif() + + +if(PNG_SHARED AND WIN32) + set_target_properties(${PNG_LIB_NAME} PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL) +endif() + +if(PNG_TESTS AND PNG_SHARED) + # does not work with msvc due to png_lib_ver issue + add_executable(pngtest ${pngtest_sources}) + target_link_libraries(pngtest ${PNG_LIB_NAME}) + add_test(pngtest pngtest ${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png) +endif() + + +# CREATE PKGCONFIG FILES +# we use the same files like ./configure, so we have to set its vars +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix ${CMAKE_INSTALL_PREFIX}) +set(libdir ${CMAKE_INSTALL_PREFIX}/lib) +set(includedir ${CMAKE_INSTALL_PREFIX}/include) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng-config.in + ${CMAKE_CURRENT_BINARY_DIR}/libpng-config) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/libpng-config.in + ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config) + +# SET UP LINKS +if(PNG_SHARED) + set_target_properties(${PNG_LIB_NAME} PROPERTIES +# VERSION 0.${PNGLIB_RELEASE}.1.2.51 + VERSION 0.${PNGLIB_RELEASE}.0 + SOVERSION 0 + CLEAN_DIRECT_OUTPUT 1) +endif() +if(PNG_STATIC) + if(NOT WIN32) + # that's uncool on win32 - it overwrites our static import lib... + set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES + OUTPUT_NAME ${PNG_LIB_NAME} + CLEAN_DIRECT_OUTPUT 1) + endif() +endif() + +# INSTALL +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + if(PNG_SHARED) + install(TARGETS ${PNG_LIB_NAME} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + endif() + if(PNG_STATIC) + install(TARGETS ${PNG_LIB_NAME_STATIC} + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + endif() +endif() + +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES png.h pngconf.h DESTINATION include) + install(FILES png.h pngconf.h DESTINATION include/${PNGLIB_NAME}) +endif() +if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL ) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config DESTINATION bin) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config + DESTINATION bin) +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + # Install man pages + install(FILES libpng.3 libpngpf.3 DESTINATION man/man3) + install(FILES png.5 DESTINATION man/man5) + # Install pkg-config files + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc + DESTINATION lib/pkgconfig) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng-config + DESTINATION bin) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc + DESTINATION lib/pkgconfig) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config + DESTINATION bin) +endif() + +# what's with libpng.txt and all the extra files? + + +# UNINSTALL +# do we need this? + + +# DIST +# do we need this? + +# to create msvc import lib for mingw compiled shared lib +# pexports libpng.dll > libpng.def +# lib /def:libpng.def /machine:x86 + diff --git a/main/source/includes/lpng1251/INSTALL b/main/source/includes/lpng1251/INSTALL index 3b857117..f7a6fc6a 100644 --- a/main/source/includes/lpng1251/INSTALL +++ b/main/source/includes/lpng1251/INSTALL @@ -1,143 +1,143 @@ - -Installing libpng version 1.2.51 - February 6, 2014 - -On Unix/Linux and similar systems, you can simply type - - ./configure [--prefix=/path] - make check - make install - -and ignore the rest of this document. - -If configure does not work on your system and you have a reasonably -up-to-date set of tools, running ./autogen.sh before running ./configure -may fix the problem. You can also run the individual commands in -autogen.sh with the --force option, if supported by your version of -the tools. If you run 'libtoolize --force', though, this will replace -the distributed, patched, version of ltmain.sh with an unpatched version -and your shared library builds may fail to produce libraries with the -correct version numbers. - -Instead, you can use one of the custom-built makefiles in the -"scripts" directory - - cp scripts/makefile.system makefile - make test - make install - -The files that are presently available in the scripts directory -are listed and described in scripts/README.txt. - -Or you can use one of the "projects" in the "projects" directory. - -Before installing libpng, you must first install zlib, if it -is not already on your system. zlib can usually be found -wherever you got libpng. zlib can be placed in another directory, -at the same level as libpng. - -If you want to use "cmake" (see www.cmake.org), type - - cmake . -DCMAKE_INSTALL_PREFIX=/path - make - make install - -If your system already has a preinstalled zlib you will still need -to have access to the zlib.h and zconf.h include files that -correspond to the version of zlib that's installed. - -You can rename the directories that you downloaded (they -might be called "libpng-1.2.51" or "libpng12" and "zlib-1.2.3" -or "zlib123") so that you have directories called "zlib" and "libpng". - -Your directory structure should look like this: - - .. (the parent directory) - libpng (this directory) - INSTALL (this file) - README - *.h - *.c - CMakeLists.txt => "cmake" script - configuration files: - configure.ac, configure, Makefile.am, Makefile.in, - autogen.sh, config.guess, ltmain.sh, missing, - aclocal.m4, config.h.in, config.sub, - depcomp, install-sh, mkinstalldirs, test-pngtest.sh - contrib - gregbook - pngminim - pngminus - pngsuite - visupng - projects - cbuilder5 (Borland) - visualc6 (msvc) - visualc71 - xcode - scripts - makefile.* - *.def (module definition files) - pngtest.png - etc. - zlib - README - *.h - *.c - contrib - etc. - -If the line endings in the files look funny, you may wish to get the other -distribution of libpng. It is available in both tar.gz (UNIX style line -endings) and zip (DOS style line endings) formats. - -If you are building libpng with MSVC, you can enter the -libpng projects\visualc6 or visualc71 directory and follow the instructions -in README.txt. - -Otherwise enter the zlib directory and follow the instructions in zlib/README, -then come back here and run "configure" or choose the appropriate -makefile.sys in the scripts directory. - -Copy the file (or files) that you need from the -scripts directory into this directory, for example - - MSDOS example: copy scripts\makefile.msc makefile - UNIX example: cp scripts/makefile.std makefile - -Read the makefile to see if you need to change any source or -target directories to match your preferences. - -Then read pngconf.h to see if you want to make any configuration -changes. - -Then just run "make" which will create the libpng library in -this directory and "make test" which will run a quick test that reads -the "pngtest.png" file and writes a "pngout.png" file that should be -identical to it. Look for "9782 zero samples" in the output of the -test. For more confidence, you can run another test by typing -"pngtest pngnow.png" and looking for "289 zero samples" in the output. -Also, you can run "pngtest -m contrib/pngsuite/*.png" and compare -your output with the result shown in contrib/pngsuite/README. - -Most of the makefiles will allow you to run "make install" to -put the library in its final resting place (if you want to -do that, run "make install" in the zlib directory first if necessary). -Some also allow you to run "make test-installed" after you have -run "make install". - -If you encounter a compiler error message complaining about the -lines - - __png.h__ already includes setjmp.h; - __dont__ include it again.; - -this means you have compiled another module that includes setjmp.h, -which is hazardous because the two modules might not include exactly -the same setjmp.h. If you are sure that you know what you are doing -and that they are exactly the same, then you can comment out or -delete the two lines. Better yet, use the cexcept interface -instead, as demonstrated in contrib/visupng of the libpng distribution. - -Further information can be found in the README and libpng.txt -files, in the individual makefiles, in png.h, and the manual pages -libpng.3 and png.5. + +Installing libpng version 1.2.51 - February 6, 2014 + +On Unix/Linux and similar systems, you can simply type + + ./configure [--prefix=/path] + make check + make install + +and ignore the rest of this document. + +If configure does not work on your system and you have a reasonably +up-to-date set of tools, running ./autogen.sh before running ./configure +may fix the problem. You can also run the individual commands in +autogen.sh with the --force option, if supported by your version of +the tools. If you run 'libtoolize --force', though, this will replace +the distributed, patched, version of ltmain.sh with an unpatched version +and your shared library builds may fail to produce libraries with the +correct version numbers. + +Instead, you can use one of the custom-built makefiles in the +"scripts" directory + + cp scripts/makefile.system makefile + make test + make install + +The files that are presently available in the scripts directory +are listed and described in scripts/README.txt. + +Or you can use one of the "projects" in the "projects" directory. + +Before installing libpng, you must first install zlib, if it +is not already on your system. zlib can usually be found +wherever you got libpng. zlib can be placed in another directory, +at the same level as libpng. + +If you want to use "cmake" (see www.cmake.org), type + + cmake . -DCMAKE_INSTALL_PREFIX=/path + make + make install + +If your system already has a preinstalled zlib you will still need +to have access to the zlib.h and zconf.h include files that +correspond to the version of zlib that's installed. + +You can rename the directories that you downloaded (they +might be called "libpng-1.2.51" or "libpng12" and "zlib-1.2.3" +or "zlib123") so that you have directories called "zlib" and "libpng". + +Your directory structure should look like this: + + .. (the parent directory) + libpng (this directory) + INSTALL (this file) + README + *.h + *.c + CMakeLists.txt => "cmake" script + configuration files: + configure.ac, configure, Makefile.am, Makefile.in, + autogen.sh, config.guess, ltmain.sh, missing, + aclocal.m4, config.h.in, config.sub, + depcomp, install-sh, mkinstalldirs, test-pngtest.sh + contrib + gregbook + pngminim + pngminus + pngsuite + visupng + projects + cbuilder5 (Borland) + visualc6 (msvc) + visualc71 + xcode + scripts + makefile.* + *.def (module definition files) + pngtest.png + etc. + zlib + README + *.h + *.c + contrib + etc. + +If the line endings in the files look funny, you may wish to get the other +distribution of libpng. It is available in both tar.gz (UNIX style line +endings) and zip (DOS style line endings) formats. + +If you are building libpng with MSVC, you can enter the +libpng projects\visualc6 or visualc71 directory and follow the instructions +in README.txt. + +Otherwise enter the zlib directory and follow the instructions in zlib/README, +then come back here and run "configure" or choose the appropriate +makefile.sys in the scripts directory. + +Copy the file (or files) that you need from the +scripts directory into this directory, for example + + MSDOS example: copy scripts\makefile.msc makefile + UNIX example: cp scripts/makefile.std makefile + +Read the makefile to see if you need to change any source or +target directories to match your preferences. + +Then read pngconf.h to see if you want to make any configuration +changes. + +Then just run "make" which will create the libpng library in +this directory and "make test" which will run a quick test that reads +the "pngtest.png" file and writes a "pngout.png" file that should be +identical to it. Look for "9782 zero samples" in the output of the +test. For more confidence, you can run another test by typing +"pngtest pngnow.png" and looking for "289 zero samples" in the output. +Also, you can run "pngtest -m contrib/pngsuite/*.png" and compare +your output with the result shown in contrib/pngsuite/README. + +Most of the makefiles will allow you to run "make install" to +put the library in its final resting place (if you want to +do that, run "make install" in the zlib directory first if necessary). +Some also allow you to run "make test-installed" after you have +run "make install". + +If you encounter a compiler error message complaining about the +lines + + __png.h__ already includes setjmp.h; + __dont__ include it again.; + +this means you have compiled another module that includes setjmp.h, +which is hazardous because the two modules might not include exactly +the same setjmp.h. If you are sure that you know what you are doing +and that they are exactly the same, then you can comment out or +delete the two lines. Better yet, use the cexcept interface +instead, as demonstrated in contrib/visupng of the libpng distribution. + +Further information can be found in the README and libpng.txt +files, in the individual makefiles, in png.h, and the manual pages +libpng.3 and png.5. diff --git a/main/source/includes/lpng1251/KNOWNBUG b/main/source/includes/lpng1251/KNOWNBUG index b759dde8..f63e3cb7 100644 --- a/main/source/includes/lpng1251/KNOWNBUG +++ b/main/source/includes/lpng1251/KNOWNBUG @@ -1,22 +1,22 @@ - -Known bugs in libpng version 1.2.51 - -1. February 23, 2006: The custom makefiles don't build libpng with -lz. - - STATUS: This is a subject of debate. The change will probably be made - as a part of a major overhaul of the makefiles in libpng version 1.4.0. - -2. February 24, 2006: The Makefile generated by the "configure" script - fails to install symbolic links - libpng12.so => libpng12.so.0.1.2.9betaN - that are generated by the custom makefiles. - -3. September 4, 2007: There is a report that pngtest crashes on MacOS 10. - - STATUS: workarounds are - 1) Compile without optimization (crashes are observed with - -arch i386 and -O2 or -O3, using gcc-4.0.1). - 2) Compile pngtest.c with PNG_DEBUG defined (the bug goes away if - you try to look at it). - 3) Ignore the crash. The library itself seems to be OK. - + +Known bugs in libpng version 1.2.51 + +1. February 23, 2006: The custom makefiles don't build libpng with -lz. + + STATUS: This is a subject of debate. The change will probably be made + as a part of a major overhaul of the makefiles in libpng version 1.4.0. + +2. February 24, 2006: The Makefile generated by the "configure" script + fails to install symbolic links + libpng12.so => libpng12.so.0.1.2.9betaN + that are generated by the custom makefiles. + +3. September 4, 2007: There is a report that pngtest crashes on MacOS 10. + + STATUS: workarounds are + 1) Compile without optimization (crashes are observed with + -arch i386 and -O2 or -O3, using gcc-4.0.1). + 2) Compile pngtest.c with PNG_DEBUG defined (the bug goes away if + you try to look at it). + 3) Ignore the crash. The library itself seems to be OK. + diff --git a/main/source/includes/lpng1251/LICENSE b/main/source/includes/lpng1251/LICENSE index fc105dd1..b7364180 100644 --- a/main/source/includes/lpng1251/LICENSE +++ b/main/source/includes/lpng1251/LICENSE @@ -1,111 +1,111 @@ - -This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.2.6, August 15, 2004, through 1.2.51, February 6, 2014, are -Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.2.5 -with the following individual added to the list of Contributing Authors - - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are -Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6 -with the following individuals added to the list of Contributing Authors - - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-0.96, -with the following individuals added to the list of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88, -with the following individuals added to the list of Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about" -boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a -certification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -February 6, 2014 + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.2.6, August 15, 2004, through 1.2.51, February 6, 2014, are +Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +February 6, 2014 diff --git a/main/source/includes/lpng1251/README b/main/source/includes/lpng1251/README index e0c28df3..20e1fda7 100644 --- a/main/source/includes/lpng1251/README +++ b/main/source/includes/lpng1251/README @@ -1,277 +1,277 @@ -README for libpng version 1.2.51 - February 6, 2014 (shared library 12.0) -See the note about version numbers near the top of png.h - -See INSTALL for instructions on how to install libpng. - -Libpng comes in several distribution formats. Get libpng-*.tar.gz, -libpng-*.tar.xz, or libpng-*.tar.bz2 if you want UNIX-style line -endings in the text files, or lpng*.7z or lpng*.zip if you want DOS-style -line endings. You can get UNIX-style line endings from the *.zip file -by using "unzip -a" but there seems to be no simple way to recover -UNIX-style line endings from the *.7z file. The *.tar.xz file is -recommended for *NIX users instead. - -Version 0.89 was the first official release of libpng. Don't let the -fact that it's the first release fool you. The libpng library has been in -extensive use and testing since mid-1995. By late 1997 it had -finally gotten to the stage where there hadn't been significant -changes to the API in some time, and people have a bad feeling about -libraries with versions < 1.0. Version 1.0.0 was released in -March 1998. - -**** -Note that some of the changes to the png_info structure render this -version of the library binary incompatible with libpng-0.89 or -earlier versions if you are using a shared library. The type of the -"filler" parameter for png_set_filler() has changed from png_byte to -png_uint_32, which will affect shared-library applications that use -this function. - -To avoid problems with changes to the internals of png_info_struct, -new APIs have been made available in 0.95 to avoid direct application -access to info_ptr. These functions are the png_set_ and -png_get_ functions. These functions should be used when -accessing/storing the info_struct data, rather than manipulating it -directly, to avoid such problems in the future. - -It is important to note that the APIs do not make current programs -that access the info struct directly incompatible with the new -library. However, it is strongly suggested that new programs use -the new APIs (as shown in example.c and pngtest.c), and older programs -be converted to the new format, to facilitate upgrades in the future. -**** - -Additions since 0.90 include the ability to compile libpng as a -Windows DLL, and new APIs for accessing data in the info struct. -Experimental functions include the ability to set weighting and cost -factors for row filter selection, direct reads of integers from buffers -on big-endian processors that support misaligned data access, faster -methods of doing alpha composition, and more accurate 16->8 bit color -conversion. - -The additions since 0.89 include the ability to read from a PNG stream -which has had some (or all) of the signature bytes read by the calling -application. This also allows the reading of embedded PNG streams that -do not have the PNG file signature. As well, it is now possible to set -the library action on the detection of chunk CRC errors. It is possible -to set different actions based on whether the CRC error occurred in a -critical or an ancillary chunk. - -The changes made to the library, and bugs fixed are based on discussions -on the png-mng-implement mailing list and not on material submitted -privately to Guy, Andreas, or Glenn. They will forward any good -suggestions to the list. - -For a detailed description on using libpng, read libpng.txt. For -examples of libpng in a program, see example.c and pngtest.c. For usage -information and restrictions (what little they are) on libpng, see -png.h. For a description on using zlib (the compression library used by -libpng) and zlib's restrictions, see zlib.h - -I have included a general makefile, as well as several machine and -compiler specific ones, but you may have to modify one for your own needs. - -You should use zlib 1.0.4 or later to run this, but it MAY work with -versions as old as zlib 0.95. Even so, there are bugs in older zlib -versions which can cause the output of invalid compression streams for -some images. You will definitely need zlib 1.0.4 or later if you are -taking advantage of the MS-DOS "far" structure allocation for the small -and medium memory models. You should also note that zlib is a -compression library that is useful for more things than just PNG files. -You can use zlib as a drop-in replacement for fread() and fwrite() if -you are so inclined. - -zlib should be available at the same place that libpng is, or at -ftp://ftp.simplesystems.org/pub/png/src/ - -You may also want a copy of the PNG specification. It is available -as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find -these at http://www.libpng.org/pub/png/pngdocs.html - -This code is currently being archived at libpng.sf.net in the -[DOWNLOAD] area, and on CompuServe, Lib 20 (PNG SUPPORT) -at GO GRAPHSUP. If you can't find it in any of those places, -e-mail me, and I'll help you find it. - -If you have any code changes, requests, problems, etc., please e-mail -them to me. Also, I'd appreciate any make files or project files, -and any modifications you needed to make to get libpng to compile, -along with a #define variable to tell what compiler/system you are on. -If you needed to add transformations to libpng, or wish libpng would -provide the image in a different way, drop me a note (and code, if -possible), so I can consider supporting the transformation. -Finally, if you get any warning messages when compiling libpng -(note: not zlib), and they are easy to fix, I'd appreciate the -fix. Please mention "libpng" somewhere in the subject line. Thanks. - -This release was created and will be supported by myself (of course -based in a large way on Guy's and Andreas' earlier work), and the PNG -development group. - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) or to glennrp at users.sourceforge.net - -You can't reach Guy, the original libpng author, at the addresses -given in previous versions of this document. He and Andreas will -read mail addressed to the png-mng-implement list, however. - -Please do not send general questions about PNG. Send them to -the (png-mng-misc at lists.sourceforge.net, subscription required, visit -https://lists.sourceforge.net/lists/listinfo/png-mng-misc to -subscribe). On the other hand, please do not send libpng questions to -that address, send them to me or to the png-mng-implement list. I'll -get them in the end anyway. If you have a question about something -in the PNG specification that is related to using libpng, send it -to me. Send me any questions that start with "I was using libpng, -and ...". If in doubt, send questions to me. I'll bounce them -to others, if necessary. - -Please do not send suggestions on how to change PNG. We have -been discussing PNG for nineteen years now, and it is official and -finished. If you have suggestions for libpng, however, I'll -gladly listen. Even if your suggestion is not used immediately, -it may be used later. - -Files in this distribution: - - ANNOUNCE => Announcement of this version, with recent changes - CHANGES => Description of changes between libpng versions - KNOWNBUG => List of known bugs and deficiencies - LICENSE => License to use and redistribute libpng - README => This file - TODO => Things not implemented in the current library - Y2KINFO => Statement of Y2K compliance - example.c => Example code for using libpng functions - libpng-*-*-diff.txt => Diff from previous release - libpng.3 => manual page for libpng (includes libpng.txt) - libpng.txt => Description of libpng and its functions - libpngpf.3 => manual page for libpng's private functions - png.5 => manual page for the PNG format - png.c => Basic interface functions common to library - png.h => Library function and interface declarations - pngconf.h => System specific library configuration - pngerror.c => Error/warning message I/O functions - pngget.c => Functions for retrieving info from struct - pngmem.c => Memory handling functions - pngbar.png => PNG logo, 88x31 - pngnow.png => PNG logo, 98x31 - pngpread.c => Progressive reading functions - pngread.c => Read data/helper high-level functions - pngrio.c => Lowest-level data read I/O functions - pngrtran.c => Read data transformation functions - pngrutil.c => Read data utility functions - pngset.c => Functions for storing data into the info_struct - pngtest.c => Library test program - pngtest.png => Library test sample image - pngtrans.c => Common data transformation functions - pngwio.c => Lowest-level write I/O functions - pngwrite.c => High-level write functions - pngwtran.c => Write data transformations - pngwutil.c => Write utility functions - contrib => Contributions - gregbook => source code for PNG reading and writing, from - Greg Roelofs' "PNG: The Definitive Guide", - O'Reilly, 1999 - pngminim => Minimal pnm2pngm and png2pnmm programs - pngminus => Simple pnm2png and png2pnm programs - pngsuite => Test images - visupng => Contains a MSVC workspace for VisualPng - projects => Contains project files and workspaces for - building a DLL - beos => Contains a Beos workspace for building libpng - c5builder => Contains a Borland workspace for building - libpng and zlib - MacOSX => Contains a MacOSX workspace for building libpng - netware.txt => Contains instructions for downloading a set - of project files for building libpng and - zlib on Netware. - visualc6 => Contains a Microsoft Visual C++ (MSVC) - workspace for building libpng and zlib - visualc71 => Contains a Microsoft Visual C++ (MSVC) - workspace for building libpng and zlib - wince.txt => Contains instructions for downloading a - Microsoft Visual C++ (Windows CD Toolkit) - workspace for building libpng and zlib on - WindowsCE - xcode => Contains xcode project files - scripts => Directory containing scripts for building libpng: - descrip.mms => VMS makefile for MMS or MMK - makefile.std => Generic UNIX makefile (cc, creates static - libpng.a) - makefile.elf => Linux/ELF gcc makefile symbol versioning, - creates libpng12.so.0.1.2.51) - makefile.linux => Linux/ELF makefile (gcc, creates - libpng12.so.0.1.2.51) - makefile.gcmmx => Linux/ELF makefile (gcc, creates - libpng12.so.0.1.2.51, previously - used assembler code tuned for Intel MMX - platform) - makefile.gcc => Generic makefile (gcc, creates static - libpng.a) - makefile.knr => Archaic UNIX Makefile that converts files - with ansi2knr (Requires ansi2knr.c from - ftp://ftp.cs.wisc.edu/ghost) - makefile.aix => AIX makefile - makefile.cygwin => Cygwin/gcc makefile - makefile.darwin => Darwin makefile - makefile.dec => DEC Alpha UNIX makefile - makefile.freebsd => FreeBSD makefile - makefile.hpgcc => HPUX makefile using gcc - makefile.hpux => HPUX (10.20 and 11.00) makefile - makefile.hp64 => HPUX (10.20 and 11.00) makefile, 64 bit - makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 - (static) - makefile.intel => Intel C/C++ version 4.0 and later - libpng.icc => Project file, IBM VisualAge/C++ 4.0 or later - makefile.netbsd => NetBSD/cc makefile, makes libpng.so. - makefile.ne12bsd => NetBSD/cc makefile, makes libpng12.so - makefile.openbsd => OpenBSD makefile - makefile.sgi => Silicon Graphics IRIX (cc, creates static lib) - makefile.sggcc => Silicon Graphics - (gcc, creates libpng12.so.0.1.2.51) - makefile.sunos => Sun makefile - makefile.solaris => Solaris 2.X makefile - (gcc, creates libpng12.so.0.1.2.51) - makefile.so9 => Solaris 9 makefile - (gcc, creates libpng12.so.0.1.2.51) - makefile.32sunu => Sun Ultra 32-bit makefile - makefile.64sunu => Sun Ultra 64-bit makefile - makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc - makefile.mips => MIPS makefile - makefile.acorn => Acorn makefile - makefile.amiga => Amiga makefile - smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC - compiler (Requires SCOPTIONS, copied from - scripts/SCOPTIONS.ppc) - makefile.atari => Atari makefile - makefile.beos => BEOS makefile for X86 - makefile.bor => Borland makefile (uses bcc) - makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) - makefile.tc3 => Turbo C 3.0 makefile - makefile.dj2 => DJGPP 2 makefile - makefile.msc => Microsoft C makefile - makefile.vcawin32=> makefile for Microsoft Visual C++ 5.0 and - later (previously used assembler code tuned - for Intel MMX platform) - makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and - later (does not use assembler code) - makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) - pngos2.def => OS/2 module definition file used by makefile.os2 - makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model - makevms.com => VMS build script - SCOPTIONS.ppc => Used with smakefile.ppc - -Good luck, and happy coding. - --Glenn Randers-Pehrson (current maintainer, since 1998) - Internet: glennrp at users.sourceforge.net - --Andreas Eric Dilger (former maintainer, 1996-1997) - Internet: adilger at enel.ucalgary.ca - Web: http://members.shaw.ca/adilger/ - --Guy Eric Schalnat (original author and former maintainer, 1995-1996) - (formerly of Group 42, Inc) - Internet: gschal at infinet.com +README for libpng version 1.2.51 - February 6, 2014 (shared library 12.0) +See the note about version numbers near the top of png.h + +See INSTALL for instructions on how to install libpng. + +Libpng comes in several distribution formats. Get libpng-*.tar.gz, +libpng-*.tar.xz, or libpng-*.tar.bz2 if you want UNIX-style line +endings in the text files, or lpng*.7z or lpng*.zip if you want DOS-style +line endings. You can get UNIX-style line endings from the *.zip file +by using "unzip -a" but there seems to be no simple way to recover +UNIX-style line endings from the *.7z file. The *.tar.xz file is +recommended for *NIX users instead. + +Version 0.89 was the first official release of libpng. Don't let the +fact that it's the first release fool you. The libpng library has been in +extensive use and testing since mid-1995. By late 1997 it had +finally gotten to the stage where there hadn't been significant +changes to the API in some time, and people have a bad feeling about +libraries with versions < 1.0. Version 1.0.0 was released in +March 1998. + +**** +Note that some of the changes to the png_info structure render this +version of the library binary incompatible with libpng-0.89 or +earlier versions if you are using a shared library. The type of the +"filler" parameter for png_set_filler() has changed from png_byte to +png_uint_32, which will affect shared-library applications that use +this function. + +To avoid problems with changes to the internals of png_info_struct, +new APIs have been made available in 0.95 to avoid direct application +access to info_ptr. These functions are the png_set_ and +png_get_ functions. These functions should be used when +accessing/storing the info_struct data, rather than manipulating it +directly, to avoid such problems in the future. + +It is important to note that the APIs do not make current programs +that access the info struct directly incompatible with the new +library. However, it is strongly suggested that new programs use +the new APIs (as shown in example.c and pngtest.c), and older programs +be converted to the new format, to facilitate upgrades in the future. +**** + +Additions since 0.90 include the ability to compile libpng as a +Windows DLL, and new APIs for accessing data in the info struct. +Experimental functions include the ability to set weighting and cost +factors for row filter selection, direct reads of integers from buffers +on big-endian processors that support misaligned data access, faster +methods of doing alpha composition, and more accurate 16->8 bit color +conversion. + +The additions since 0.89 include the ability to read from a PNG stream +which has had some (or all) of the signature bytes read by the calling +application. This also allows the reading of embedded PNG streams that +do not have the PNG file signature. As well, it is now possible to set +the library action on the detection of chunk CRC errors. It is possible +to set different actions based on whether the CRC error occurred in a +critical or an ancillary chunk. + +The changes made to the library, and bugs fixed are based on discussions +on the png-mng-implement mailing list and not on material submitted +privately to Guy, Andreas, or Glenn. They will forward any good +suggestions to the list. + +For a detailed description on using libpng, read libpng.txt. For +examples of libpng in a program, see example.c and pngtest.c. For usage +information and restrictions (what little they are) on libpng, see +png.h. For a description on using zlib (the compression library used by +libpng) and zlib's restrictions, see zlib.h + +I have included a general makefile, as well as several machine and +compiler specific ones, but you may have to modify one for your own needs. + +You should use zlib 1.0.4 or later to run this, but it MAY work with +versions as old as zlib 0.95. Even so, there are bugs in older zlib +versions which can cause the output of invalid compression streams for +some images. You will definitely need zlib 1.0.4 or later if you are +taking advantage of the MS-DOS "far" structure allocation for the small +and medium memory models. You should also note that zlib is a +compression library that is useful for more things than just PNG files. +You can use zlib as a drop-in replacement for fread() and fwrite() if +you are so inclined. + +zlib should be available at the same place that libpng is, or at +ftp://ftp.simplesystems.org/pub/png/src/ + +You may also want a copy of the PNG specification. It is available +as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find +these at http://www.libpng.org/pub/png/pngdocs.html + +This code is currently being archived at libpng.sf.net in the +[DOWNLOAD] area, and on CompuServe, Lib 20 (PNG SUPPORT) +at GO GRAPHSUP. If you can't find it in any of those places, +e-mail me, and I'll help you find it. + +If you have any code changes, requests, problems, etc., please e-mail +them to me. Also, I'd appreciate any make files or project files, +and any modifications you needed to make to get libpng to compile, +along with a #define variable to tell what compiler/system you are on. +If you needed to add transformations to libpng, or wish libpng would +provide the image in a different way, drop me a note (and code, if +possible), so I can consider supporting the transformation. +Finally, if you get any warning messages when compiling libpng +(note: not zlib), and they are easy to fix, I'd appreciate the +fix. Please mention "libpng" somewhere in the subject line. Thanks. + +This release was created and will be supported by myself (of course +based in a large way on Guy's and Andreas' earlier work), and the PNG +development group. + +Send comments/corrections/commendations to png-mng-implement at lists.sf.net +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) or to glennrp at users.sourceforge.net + +You can't reach Guy, the original libpng author, at the addresses +given in previous versions of this document. He and Andreas will +read mail addressed to the png-mng-implement list, however. + +Please do not send general questions about PNG. Send them to +the (png-mng-misc at lists.sourceforge.net, subscription required, visit +https://lists.sourceforge.net/lists/listinfo/png-mng-misc to +subscribe). On the other hand, please do not send libpng questions to +that address, send them to me or to the png-mng-implement list. I'll +get them in the end anyway. If you have a question about something +in the PNG specification that is related to using libpng, send it +to me. Send me any questions that start with "I was using libpng, +and ...". If in doubt, send questions to me. I'll bounce them +to others, if necessary. + +Please do not send suggestions on how to change PNG. We have +been discussing PNG for nineteen years now, and it is official and +finished. If you have suggestions for libpng, however, I'll +gladly listen. Even if your suggestion is not used immediately, +it may be used later. + +Files in this distribution: + + ANNOUNCE => Announcement of this version, with recent changes + CHANGES => Description of changes between libpng versions + KNOWNBUG => List of known bugs and deficiencies + LICENSE => License to use and redistribute libpng + README => This file + TODO => Things not implemented in the current library + Y2KINFO => Statement of Y2K compliance + example.c => Example code for using libpng functions + libpng-*-*-diff.txt => Diff from previous release + libpng.3 => manual page for libpng (includes libpng.txt) + libpng.txt => Description of libpng and its functions + libpngpf.3 => manual page for libpng's private functions + png.5 => manual page for the PNG format + png.c => Basic interface functions common to library + png.h => Library function and interface declarations + pngconf.h => System specific library configuration + pngerror.c => Error/warning message I/O functions + pngget.c => Functions for retrieving info from struct + pngmem.c => Memory handling functions + pngbar.png => PNG logo, 88x31 + pngnow.png => PNG logo, 98x31 + pngpread.c => Progressive reading functions + pngread.c => Read data/helper high-level functions + pngrio.c => Lowest-level data read I/O functions + pngrtran.c => Read data transformation functions + pngrutil.c => Read data utility functions + pngset.c => Functions for storing data into the info_struct + pngtest.c => Library test program + pngtest.png => Library test sample image + pngtrans.c => Common data transformation functions + pngwio.c => Lowest-level write I/O functions + pngwrite.c => High-level write functions + pngwtran.c => Write data transformations + pngwutil.c => Write utility functions + contrib => Contributions + gregbook => source code for PNG reading and writing, from + Greg Roelofs' "PNG: The Definitive Guide", + O'Reilly, 1999 + pngminim => Minimal pnm2pngm and png2pnmm programs + pngminus => Simple pnm2png and png2pnm programs + pngsuite => Test images + visupng => Contains a MSVC workspace for VisualPng + projects => Contains project files and workspaces for + building a DLL + beos => Contains a Beos workspace for building libpng + c5builder => Contains a Borland workspace for building + libpng and zlib + MacOSX => Contains a MacOSX workspace for building libpng + netware.txt => Contains instructions for downloading a set + of project files for building libpng and + zlib on Netware. + visualc6 => Contains a Microsoft Visual C++ (MSVC) + workspace for building libpng and zlib + visualc71 => Contains a Microsoft Visual C++ (MSVC) + workspace for building libpng and zlib + wince.txt => Contains instructions for downloading a + Microsoft Visual C++ (Windows CD Toolkit) + workspace for building libpng and zlib on + WindowsCE + xcode => Contains xcode project files + scripts => Directory containing scripts for building libpng: + descrip.mms => VMS makefile for MMS or MMK + makefile.std => Generic UNIX makefile (cc, creates static + libpng.a) + makefile.elf => Linux/ELF gcc makefile symbol versioning, + creates libpng12.so.0.1.2.51) + makefile.linux => Linux/ELF makefile (gcc, creates + libpng12.so.0.1.2.51) + makefile.gcmmx => Linux/ELF makefile (gcc, creates + libpng12.so.0.1.2.51, previously + used assembler code tuned for Intel MMX + platform) + makefile.gcc => Generic makefile (gcc, creates static + libpng.a) + makefile.knr => Archaic UNIX Makefile that converts files + with ansi2knr (Requires ansi2knr.c from + ftp://ftp.cs.wisc.edu/ghost) + makefile.aix => AIX makefile + makefile.cygwin => Cygwin/gcc makefile + makefile.darwin => Darwin makefile + makefile.dec => DEC Alpha UNIX makefile + makefile.freebsd => FreeBSD makefile + makefile.hpgcc => HPUX makefile using gcc + makefile.hpux => HPUX (10.20 and 11.00) makefile + makefile.hp64 => HPUX (10.20 and 11.00) makefile, 64 bit + makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 + (static) + makefile.intel => Intel C/C++ version 4.0 and later + libpng.icc => Project file, IBM VisualAge/C++ 4.0 or later + makefile.netbsd => NetBSD/cc makefile, makes libpng.so. + makefile.ne12bsd => NetBSD/cc makefile, makes libpng12.so + makefile.openbsd => OpenBSD makefile + makefile.sgi => Silicon Graphics IRIX (cc, creates static lib) + makefile.sggcc => Silicon Graphics + (gcc, creates libpng12.so.0.1.2.51) + makefile.sunos => Sun makefile + makefile.solaris => Solaris 2.X makefile + (gcc, creates libpng12.so.0.1.2.51) + makefile.so9 => Solaris 9 makefile + (gcc, creates libpng12.so.0.1.2.51) + makefile.32sunu => Sun Ultra 32-bit makefile + makefile.64sunu => Sun Ultra 64-bit makefile + makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc + makefile.mips => MIPS makefile + makefile.acorn => Acorn makefile + makefile.amiga => Amiga makefile + smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC + compiler (Requires SCOPTIONS, copied from + scripts/SCOPTIONS.ppc) + makefile.atari => Atari makefile + makefile.beos => BEOS makefile for X86 + makefile.bor => Borland makefile (uses bcc) + makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) + makefile.tc3 => Turbo C 3.0 makefile + makefile.dj2 => DJGPP 2 makefile + makefile.msc => Microsoft C makefile + makefile.vcawin32=> makefile for Microsoft Visual C++ 5.0 and + later (previously used assembler code tuned + for Intel MMX platform) + makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and + later (does not use assembler code) + makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) + pngos2.def => OS/2 module definition file used by makefile.os2 + makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model + makevms.com => VMS build script + SCOPTIONS.ppc => Used with smakefile.ppc + +Good luck, and happy coding. + +-Glenn Randers-Pehrson (current maintainer, since 1998) + Internet: glennrp at users.sourceforge.net + +-Andreas Eric Dilger (former maintainer, 1996-1997) + Internet: adilger at enel.ucalgary.ca + Web: http://members.shaw.ca/adilger/ + +-Guy Eric Schalnat (original author and former maintainer, 1995-1996) + (formerly of Group 42, Inc) + Internet: gschal at infinet.com diff --git a/main/source/includes/lpng1251/TODO b/main/source/includes/lpng1251/TODO index e2cdcaff..face7658 100644 --- a/main/source/includes/lpng1251/TODO +++ b/main/source/includes/lpng1251/TODO @@ -1,25 +1,25 @@ -TODO - list of things to do for libpng: - -Final bug fixes. -Improve API by hiding the png_struct and png_info structs. -Finish work on the no-floating-point version (including gamma compensation) -Better C++ wrapper/full C++ implementation? -Fix problem with C++ and EXTERN "C". -cHRM transformation. -Improve setjmp/longjmp usage or remove it in favor of returning error codes. -Add "grayscale->palette" transformation and "palette->grayscale" detection. -Improved dithering. -Multi-lingual error and warning message support. -Complete sRGB transformation (presently it simply uses gamma=0.45455). -Man pages for function calls. -Better documentation. -Better filter selection - (counting huffman bits/precompression? filter inertia? filter costs?). -Histogram creation. -Text conversion between different code pages (Latin-1 -> Mac and DOS). -Should we always malloc 2^bit_depth PLTE/tRNS/hIST entries for safety? -Build gamma tables using fixed point (and do away with floating point entirely). -Use greater precision when changing to linear gamma for compositing against - background and doing rgb-to-gray transformation. -Investigate pre-incremented loop counters and other loop constructions. -Add interpolated method of handling interlacing. +TODO - list of things to do for libpng: + +Final bug fixes. +Improve API by hiding the png_struct and png_info structs. +Finish work on the no-floating-point version (including gamma compensation) +Better C++ wrapper/full C++ implementation? +Fix problem with C++ and EXTERN "C". +cHRM transformation. +Improve setjmp/longjmp usage or remove it in favor of returning error codes. +Add "grayscale->palette" transformation and "palette->grayscale" detection. +Improved dithering. +Multi-lingual error and warning message support. +Complete sRGB transformation (presently it simply uses gamma=0.45455). +Man pages for function calls. +Better documentation. +Better filter selection + (counting huffman bits/precompression? filter inertia? filter costs?). +Histogram creation. +Text conversion between different code pages (Latin-1 -> Mac and DOS). +Should we always malloc 2^bit_depth PLTE/tRNS/hIST entries for safety? +Build gamma tables using fixed point (and do away with floating point entirely). +Use greater precision when changing to linear gamma for compositing against + background and doing rgb-to-gray transformation. +Investigate pre-incremented loop counters and other loop constructions. +Add interpolated method of handling interlacing. diff --git a/main/source/includes/lpng1251/Y2KINFO b/main/source/includes/lpng1251/Y2KINFO index c1e81f04..1bbe7123 100644 --- a/main/source/includes/lpng1251/Y2KINFO +++ b/main/source/includes/lpng1251/Y2KINFO @@ -1,55 +1,55 @@ - Y2K compliance in libpng: - ========================= - - February 6, 2014 - - Since the PNG Development group is an ad-hoc body, we can't make - an official declaration. - - This is your unofficial assurance that libpng from version 0.71 and - upward through 1.2.51 are Y2K compliant. It is my belief that earlier - versions were also Y2K compliant. - - Libpng only has three year fields. One is a 2-byte unsigned integer - that will hold years up to 65535. The other two hold the date in text - format, and will hold years up to 9999. - - The integer is - "png_uint_16 year" in png_time_struct. - - The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. - - There are seven time-related functions: - - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) - png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c - png_convert_from_time_t() in pngwrite.c - png_get_tIME() in pngget.c - png_handle_tIME() in pngrutil.c, called in pngread.c - png_set_tIME() in pngset.c - png_write_tIME() in pngwutil.c, called in pngwrite.c - - All appear to handle dates properly in a Y2K environment. The - png_convert_from_time_t() function calls gmtime() to convert from system - clock time, which returns (year - 1900), which we properly convert to - the full 4-digit year. There is a possibility that applications using - libpng are not passing 4-digit years into the png_convert_to_rfc_1123() - function, or that they are incorrectly passing only a 2-digit year - instead of "year - 1900" into the png_convert_from_struct_tm() function, - but this is not under our control. The libpng documentation has always - stated that it works with 4-digit years, and the APIs have been - documented as such. - - The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned - integer to hold the year, and can hold years as large as 65535. - - zlib, upon which libpng depends, is also Y2K compliant. It contains - no date-related code. - - - Glenn Randers-Pehrson - libpng maintainer - PNG Development Group + Y2K compliance in libpng: + ========================= + + February 6, 2014 + + Since the PNG Development group is an ad-hoc body, we can't make + an official declaration. + + This is your unofficial assurance that libpng from version 0.71 and + upward through 1.2.51 are Y2K compliant. It is my belief that earlier + versions were also Y2K compliant. + + Libpng only has three year fields. One is a 2-byte unsigned integer + that will hold years up to 65535. The other two hold the date in text + format, and will hold years up to 9999. + + The integer is + "png_uint_16 year" in png_time_struct. + + The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + + There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + + All appear to handle dates properly in a Y2K environment. The + png_convert_from_time_t() function calls gmtime() to convert from system + clock time, which returns (year - 1900), which we properly convert to + the full 4-digit year. There is a possibility that applications using + libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + function, or that they are incorrectly passing only a 2-digit year + instead of "year - 1900" into the png_convert_from_struct_tm() function, + but this is not under our control. The libpng documentation has always + stated that it works with 4-digit years, and the APIs have been + documented as such. + + The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + integer to hold the year, and can hold years as large as 65535. + + zlib, upon which libpng depends, is also Y2K compliant. It contains + no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/main/source/includes/lpng1251/configure b/main/source/includes/lpng1251/configure index 8ffbb7a2..40bdfe25 100644 --- a/main/source/includes/lpng1251/configure +++ b/main/source/includes/lpng1251/configure @@ -1,13 +1,13 @@ -#!/bin/sh -echo " - There is no \"configure\" script in this distribution of - libpng-1.2.51. - - Instead, please copy the appropriate makefile for your system from the - \"scripts\" directory. Read the INSTALL file for more details. - - Update, July 2004: you can get a \"configure\" based distribution - from the libpng distribution sites. Download the file - libpng-1.2.51.tar.gz, libpng-1.2.51.tar.xz, or libpng-1.2.51.tar.bz2 -" - +#!/bin/sh +echo " + There is no \"configure\" script in this distribution of + libpng-1.2.51. + + Instead, please copy the appropriate makefile for your system from the + \"scripts\" directory. Read the INSTALL file for more details. + + Update, July 2004: you can get a \"configure\" based distribution + from the libpng distribution sites. Download the file + libpng-1.2.51.tar.gz, libpng-1.2.51.tar.xz, or libpng-1.2.51.tar.bz2 +" + diff --git a/main/source/includes/lpng1251/example.c b/main/source/includes/lpng1251/example.c index 1a9db2da..49b87242 100644 --- a/main/source/includes/lpng1251/example.c +++ b/main/source/includes/lpng1251/example.c @@ -1,832 +1,832 @@ - -#if 0 /* in case someone actually tries to compile this */ - -/* example.c - an example of using libpng - * Last changed in libpng 1.2.37 [June 4, 2009] - * This file has been placed in the public domain by the authors. - * Maintained 1998-2010 Glenn Randers-Pehrson - * Maintained 1996, 1997 Andreas Dilger) - * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - */ - -/* This is an example of how to use libpng to read and write PNG files. - * The file libpng.txt is much more verbose then this. If you have not - * read it, do so first. This was designed to be a starting point of an - * implementation. This is not officially part of libpng, is hereby placed - * in the public domain, and therefore does not require a copyright notice. - * - * This file does not currently compile, because it is missing certain - * parts, like allocating memory to hold an image. You will have to - * supply these parts to get it to compile. For an example of a minimal - * working PNG reader/writer, see pngtest.c, included in this distribution; - * see also the programs in the contrib directory. - */ - -#include "png.h" - - /* The png_jmpbuf() macro, used in error handling, became available in - * libpng version 1.0.6. If you want to be able to run your code with older - * versions of libpng, you must define the macro yourself (but only if it - * is not already defined by libpng!). - */ - -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#endif - -/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() - * returns zero if the image is a PNG and nonzero if it isn't a PNG. - * - * The function check_if_png() shown here, but not used, returns nonzero (true) - * if the file can be opened and is a PNG, 0 (false) otherwise. - * - * If this call is successful, and you are going to keep the file open, - * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once - * you have created the png_ptr, so that libpng knows your application - * has read that many bytes from the start of the file. Make sure you - * don't call png_set_sig_bytes() with more than 8 bytes read or give it - * an incorrect number of bytes read, or you will either have read too - * many bytes (your fault), or you are telling libpng to read the wrong - * number of magic bytes (also your fault). - * - * Many applications already read the first 2 or 4 bytes from the start - * of the image to determine the file type, so it would be easiest just - * to pass the bytes to png_sig_cmp() or even skip that if you know - * you have a PNG file, and call png_set_sig_bytes(). - */ -#define PNG_BYTES_TO_CHECK 4 -int check_if_png(char *file_name, FILE **fp) -{ - char buf[PNG_BYTES_TO_CHECK]; - - /* Open the prospective PNG file. */ - if ((*fp = fopen(file_name, "rb")) == NULL) - return 0; - - /* Read in some of the signature bytes */ - if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) - return 0; - - /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. - Return nonzero (true) if they match */ - - return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); -} - -/* Read a PNG file. You may want to return an error code if the read - * fails (depending upon the failure). There are two "prototypes" given - * here - one where we are given the filename, and we need to open the - * file, and the other where we are given an open file (possibly with - * some or all of the magic bytes read - see comments above). - */ -#ifdef open_file /* prototype 1 */ -void read_png(char *file_name) /* We need to open the file */ -{ - png_structp png_ptr; - png_infop info_ptr; - unsigned int sig_read = 0; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - FILE *fp; - - if ((fp = fopen(file_name, "rb")) == NULL) - return (ERROR); - -#else no_open_file /* prototype 2 */ -void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ -{ - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; -#endif no_open_file /* Only use one prototype! */ - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also supply the - * the compiler header file version, so that we know if the application - * was compiled with a compatible version of the library. REQUIRED - */ - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (png_ptr == NULL) - { - fclose(fp); - return (ERROR); - } - - /* Allocate/initialize the memory for image information. REQUIRED. */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return (ERROR); - } - - /* Set error handling if you are using the setjmp/longjmp method (this is - * the normal method of doing things with libpng). REQUIRED unless you - * set up your own error handlers in the png_create_read_struct() earlier. - */ - - if (setjmp(png_jmpbuf(png_ptr))) - { - /* Free all of the memory associated with the png_ptr and info_ptr */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - fclose(fp); - /* If we get here, we had a problem reading the file */ - return (ERROR); - } - - /* One of the following I/O initialization methods is REQUIRED */ -#ifdef streams /* PNG file I/O method 1 */ - /* Set up the input control if you are using standard C streams */ - png_init_io(png_ptr, fp); - -#else no_streams /* PNG file I/O method 2 */ - /* If you are using replacement read functions, instead of calling - * png_init_io() here you would call: - */ - png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); - /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* Use only one I/O method! */ - - /* If we have already read some of the signature */ - png_set_sig_bytes(png_ptr, sig_read); - -#ifdef hilevel - /* - * If you have enough memory to read in the entire image at once, - * and you need to specify only transforms that can be controlled - * with one of the PNG_TRANSFORM_* bits (this presently excludes - * dithering, filling, setting background, and doing gamma - * adjustment), then you can read the entire image (including - * pixels) into the info structure with this call: - */ - png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); - -#else - /* OK, you're doing it the hard way, with the lower-level functions */ - - /* The call to png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). REQUIRED - */ - png_read_info(png_ptr, info_ptr); - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, int_p_NULL, int_p_NULL); - - /* Set up the data transformations you want. Note that these are all - * optional. Only call them if you want/need them. Many of the - * transformations only work on specific types of images, and many - * are mutually exclusive. - */ - - /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ - png_set_strip_16(png_ptr); - - /* Strip alpha bytes from the input data without combining with the - * background (not recommended). - */ - png_set_strip_alpha(png_ptr); - - /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). - */ - png_set_packing(png_ptr); - - /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). */ - png_set_packswap(png_ptr); - - /* Expand paletted colors into true RGB triplets */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(png_ptr); - - /* Expand paletted or RGB images with transparency to full alpha channels - * so the data will be available as RGBA quartets. - */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - - /* Set the background color to draw transparent and alpha images over. - * It is possible to set the red, green, and blue components directly - * for paletted images instead of supplying a palette index. Note that - * even if the PNG file supplies a background, you are not required to - * use it - you should use the (solid) application background if it has one. - */ - - png_color_16 my_background, *image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - - /* Some suggestions as to how to get a screen gamma value - * - * Note that screen gamma is the display_exponent, which includes - * the CRT_exponent and any correction for viewing conditions - */ - if (/* We have a user-defined screen gamma value */) - { - screen_gamma = user-defined screen_gamma; - } - /* This is one way that applications share the same screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) - { - screen_gamma = atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a PC monitor in a dimly - lit room */ - screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ - } - - /* Tell libpng to handle the gamma conversion for you. The final call - * is a good guess for PC generated images, but it should be configurable - * by the user at run time by the user. It is strongly suggested that - * your application support gamma correction. - */ - - int intent; - - if (png_get_sRGB(png_ptr, info_ptr, &intent)) - png_set_gamma(png_ptr, screen_gamma, 0.45455); - else - { - double image_gamma; - if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) - png_set_gamma(png_ptr, screen_gamma, image_gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - } - - /* Dither RGB files down to 8 bit palette or reduce palettes - * to the number of colors available on your screen. - */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - int num_palette; - png_colorp palette; - - /* This reduces the image to the application supplied palette */ - if (/* We have our own palette */) - { - /* An array of colors to which the image should be dithered */ - png_color std_color_cube[MAX_SCREEN_COLORS]; - - png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, - MAX_SCREEN_COLORS, png_uint_16p_NULL, 0); - } - /* This reduces the image to the palette supplied in the file */ - else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, &histogram); - - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 0); - } - } - - /* Invert monochrome files to have 0 as white and 1 as black */ - png_set_invert_mono(png_ptr); - - /* If you want to shift the pixel values from the range [0,255] or - * [0,65535] to the original [0,7] or [0,31], or whatever range the - * colors were originally in: - */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) - { - png_color_8p sig_bit_p; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); - png_set_shift(png_ptr, sig_bit_p); - } - - /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ - if (color_type & PNG_COLOR_MASK_COLOR) - png_set_bgr(png_ptr); - - /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ - png_set_swap_alpha(png_ptr); - - /* Swap bytes of 16 bit files to least significant byte first */ - png_set_swap(png_ptr); - - /* Add filler (or alpha) byte (before/after each RGB triplet) */ - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - - /* Turn on interlace handling. REQUIRED if you are not using - * png_read_image(). To see how to handle interlacing passes, - * see the png_read_row() method below: - */ - number_passes = png_set_interlace_handling(png_ptr); - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (ie you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - /* Allocate the memory to hold the image using the fields of info_ptr. */ - - /* The easiest way to read the image: */ - png_bytep row_pointers[height]; - - /* Clear the pointer array */ - for (row = 0; row < height; row++) - row_pointers[row] = NULL; - - for (row = 0; row < height; row++) - row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, - info_ptr)); - - /* Now it's time to read the image. One of these methods is REQUIRED */ -#ifdef entire /* Read the entire image in one go */ - png_read_image(png_ptr, row_pointers); - -#else no_entire /* Read the image one or more scanlines at a time */ - /* The other way to read images - deal with interlacing: */ - - for (pass = 0; pass < number_passes; pass++) - { -#ifdef single /* Read the image a single row at a time */ - for (y = 0; y < height; y++) - { - png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1); - } - -#else no_single /* Read the image several rows at a time */ - for (y = 0; y < height; y += number_of_rows) - { -#ifdef sparkle /* Read the image using the "sparkle" effect. */ - png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, - number_of_rows); -#else no_sparkle /* Read the image using the "rectangle" effect */ - png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y], - number_of_rows); -#endif no_sparkle /* Use only one of these two methods */ - } - - /* If you want to display the image after every pass, do so here */ -#endif no_single /* Use only one of these two methods */ - } -#endif no_entire /* Use only one of these two methods */ - - /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); -#endif hilevel - - /* At this point you have read the entire image */ - - /* Clean up after the read, and free any memory allocated - REQUIRED */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - - /* Close the file */ - fclose(fp); - - /* That's it */ - return (OK); -} - -/* Progressively read a file */ - -int -initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) -{ - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible in case we are using dynamically - * linked libraries. - */ - *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (*png_ptr == NULL) - { - *info_ptr = NULL; - return (ERROR); - } - - *info_ptr = png_create_info_struct(png_ptr); - - if (*info_ptr == NULL) - { - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf((*png_ptr)))) - { - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - /* This one's new. You will need to provide all three - * function callbacks, even if you aren't using them all. - * If you aren't using all functions, you can specify NULL - * parameters. Even when all three functions are NULL, - * you need to call png_set_progressive_read_fn(). - * These functions shouldn't be dependent on global or - * static variables if you are decoding several images - * simultaneously. You should store stream specific data - * in a separate struct, given as the second parameter, - * and retrieve the pointer from inside the callbacks using - * the function png_get_progressive_ptr(png_ptr). - */ - png_set_progressive_read_fn(*png_ptr, (void *)stream_data, - info_callback, row_callback, end_callback); - - return (OK); -} - -int -process_data(png_structp *png_ptr, png_infop *info_ptr, - png_bytep buffer, png_uint_32 length) -{ - if (setjmp(png_jmpbuf((*png_ptr)))) - { - /* Free the png_ptr and info_ptr memory on error */ - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - /* This one's new also. Simply give it chunks of data as - * they arrive from the data stream (in order, of course). - * On segmented machines, don't give it any more than 64K. - * The library seems to run fine with sizes of 4K, although - * you can give it much less if necessary (I assume you can - * give it chunks of 1 byte, but I haven't tried with less - * than 256 bytes yet). When this function returns, you may - * want to display any rows that were generated in the row - * callback, if you aren't already displaying them there. - */ - png_process_data(*png_ptr, *info_ptr, buffer, length); - return (OK); -} - -info_callback(png_structp png_ptr, png_infop info) -{ - /* Do any setup here, including setting any of the transformations - * mentioned in the Reading PNG files section. For now, you _must_ - * call either png_start_read_image() or png_read_update_info() - * after all the transformations are set (even if you don't set - * any). You may start getting rows before png_process_data() - * returns, so this is your last chance to prepare for that. - */ -} - -row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) -{ - /* - * This function is called for every row in the image. If the - * image is interlaced, and you turned on the interlace handler, - * this function will be called for every row in every pass. - * - * In this function you will receive a pointer to new row data from - * libpng called new_row that is to replace a corresponding row (of - * the same data format) in a buffer allocated by your application. - * - * The new row data pointer "new_row" may be NULL, indicating there is - * no new data to be replaced (in cases of interlace loading). - * - * If new_row is not NULL then you need to call - * png_progressive_combine_row() to replace the corresponding row as - * shown below: - */ - - /* Get pointer to corresponding row in our - * PNG read buffer. - */ - png_bytep old_row = ((png_bytep *)our_data)[row_num]; - - /* If both rows are allocated then copy the new row - * data to the corresponding row data. - */ - if ((old_row != NULL) && (new_row != NULL)) - png_progressive_combine_row(png_ptr, old_row, new_row); - - /* - * The rows and passes are called in order, so you don't really - * need the row_num and pass, but I'm supplying them because it - * may make your life easier. - * - * For the non-NULL rows of interlaced images, you must call - * png_progressive_combine_row() passing in the new row and the - * old row, as demonstrated above. You can call this function for - * NULL rows (it will just return) and for non-interlaced images - * (it just does the png_memcpy for you) if it will make the code - * easier. Thus, you can just do this for all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, new_row); - - /* where old_row is what was displayed for previous rows. Note - * that the first pass (pass == 0 really) will completely cover - * the old row, so the rows do not have to be initialized. After - * the first pass (and only for interlaced images), you will have - * to pass the current row as new_row, and the function will combine - * the old row and the new row. - */ -} - -end_callback(png_structp png_ptr, png_infop info) -{ - /* This function is called when the whole image has been read, - * including any chunks after the image (up to and including - * the IEND). You will usually have the same info chunk as you - * had in the header, although some data may have been added - * to the comments and time fields. - * - * Most people won't do much here, perhaps setting a flag that - * marks the image as finished. - */ -} - -/* Write a png file */ -void write_png(char *file_name /* , ... other image information ... */) -{ - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - png_colorp palette; - - /* Open the file */ - fp = fopen(file_name, "wb"); - if (fp == NULL) - return (ERROR); - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible with the one used at compile time, - * in case we are using dynamically linked libraries. REQUIRED. - */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (png_ptr == NULL) - { - fclose(fp); - return (ERROR); - } - - /* Allocate/initialize the image information data. REQUIRED */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_write_struct(&png_ptr, png_infopp_NULL); - return (ERROR); - } - - /* Set error handling. REQUIRED if you aren't supplying your own - * error handling functions in the png_create_write_struct() call. - */ - if (setjmp(png_jmpbuf(png_ptr))) - { - /* If we get here, we had a problem writing the file */ - fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - return (ERROR); - } - - /* One of the following I/O initialization functions is REQUIRED */ - -#ifdef streams /* I/O initialization method 1 */ - /* Set up the output control if you are using standard C streams */ - png_init_io(png_ptr, fp); - -#else no_streams /* I/O initialization method 2 */ - /* If you are using replacement write functions, instead of calling - * png_init_io() here you would call - */ - png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, - user_IO_flush_function); - /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* Only use one initialization method */ - -#ifdef hilevel - /* This is the easy way. Use it if you already have all the - * image info living in the structure. You could "|" many - * PNG_TRANSFORM flags into the png_transforms integer here. - */ - png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); - -#else - /* This is the hard way */ - - /* Set the image information here. Width and height are up to 2^31, - * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on - * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, - * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, - * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or - * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST - * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED - */ - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, - PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - /* Set the palette if there is one. REQUIRED for indexed-color images */ - palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH - * png_sizeof(png_color)); - /* ... Set palette colors ... */ - png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - /* You must not free palette here, because png_set_PLTE only makes a link to - * the palette that you malloced. Wait until you are about to destroy - * the png structure. - */ - - /* Optional significant bit (sBIT) chunk */ - png_color_8 sig_bit; - /* If we are dealing with a grayscale image then */ - sig_bit.gray = true_bit_depth; - /* Otherwise, if we are dealing with a color image then */ - sig_bit.red = true_red_bit_depth; - sig_bit.green = true_green_bit_depth; - sig_bit.blue = true_blue_bit_depth; - /* If the image has an alpha channel then */ - sig_bit.alpha = true_alpha_bit_depth; - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - - - /* Optional gamma chunk is strongly suggested if you have any guess - * as to the correct gamma of the image. - */ - png_set_gAMA(png_ptr, info_ptr, gamma); - - /* Optionally write comments into the image */ - text_ptr[0].key = "Title"; - text_ptr[0].text = "Mona Lisa"; - text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr[1].key = "Author"; - text_ptr[1].text = "Leonardo DaVinci"; - text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr[2].key = "Description"; - text_ptr[2].text = ""; - text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; -#ifdef PNG_iTXt_SUPPORTED - text_ptr[0].lang = NULL; - text_ptr[1].lang = NULL; - text_ptr[2].lang = NULL; -#endif - png_set_text(png_ptr, info_ptr, text_ptr, 3); - - /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ - - /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored - * on read and, if your application chooses to write them, they must - * be written in accordance with the sRGB profile - */ - - /* Write the file header information. REQUIRED */ - png_write_info(png_ptr, info_ptr); - - /* If you want, you can write the info in two steps, in case you need to - * write your private chunk ahead of PLTE: - * - * png_write_info_before_PLTE(write_ptr, write_info_ptr); - * write_my_chunk(); - * png_write_info(png_ptr, info_ptr); - * - * However, given the level of known- and unknown-chunk support in 1.2.0 - * and up, this should no longer be necessary. - */ - - /* Once we write out the header, the compression type on the text - * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or - * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again - * at the end. - */ - - /* Set up the transformations you want. Note that these are - * all optional. Only call them if you want them. - */ - - /* Invert monochrome pixels */ - png_set_invert_mono(png_ptr); - - /* Shift the pixels up to a legal bit depth and fill in - * as appropriate to correctly scale the image. - */ - png_set_shift(png_ptr, &sig_bit); - - /* Pack pixels into bytes */ - png_set_packing(png_ptr); - - /* Swap location of alpha bytes from ARGB to RGBA */ - png_set_swap_alpha(png_ptr); - - /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into - * RGB (4 channels -> 3 channels). The second parameter is not used. - */ - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - - /* Flip BGR pixels to RGB */ - png_set_bgr(png_ptr); - - /* Swap bytes of 16-bit files to most significant byte first */ - png_set_swap(png_ptr); - - /* Swap bits of 1, 2, 4 bit packed pixel formats */ - png_set_packswap(png_ptr); - - /* Turn on interlace handling if you are not using png_write_image() */ - if (interlacing) - number_passes = png_set_interlace_handling(png_ptr); - else - number_passes = 1; - - /* The easiest way to write the image (you may have a different memory - * layout, however, so choose what fits your needs best). You need to - * use the first method if you aren't handling interlacing yourself. - */ - png_uint_32 k, height, width; - png_byte image[height][width*bytes_per_pixel]; - png_bytep row_pointers[height]; - - if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) - png_error (png_ptr, "Image is too tall to process in memory"); - - for (k = 0; k < height; k++) - row_pointers[k] = image + k*width*bytes_per_pixel; - - /* One of the following output methods is REQUIRED */ - -#ifdef entire /* Write out the entire image data in one call */ - png_write_image(png_ptr, row_pointers); - - /* The other way to write the image - deal with interlacing */ - -#else no_entire /* Write out the image data by one or more scanlines */ - - /* The number of passes is either 1 for non-interlaced images, - * or 7 for interlaced images. - */ - for (pass = 0; pass < number_passes; pass++) - { - /* Write a few rows at a time. */ - png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); - - /* If you are only writing one row at a time, this works */ - for (y = 0; y < height; y++) - png_write_rows(png_ptr, &row_pointers[y], 1); - } -#endif no_entire /* Use only one output method */ - - /* You can write optional chunks like tEXt, zTXt, and tIME at the end - * as well. Shouldn't be necessary in 1.2.0 and up as all the public - * chunks are supported and you can use png_set_unknown_chunks() to - * register unknown chunks into the info structure to be written out. - */ - - /* It is REQUIRED to call this to finish writing the rest of the file */ - png_write_end(png_ptr, info_ptr); -#endif hilevel - - /* If you png_malloced a palette, free it here (don't free info_ptr->palette, - * as recommended in versions 1.0.5m and earlier of this example; if - * libpng mallocs info_ptr->palette, libpng will free it). If you - * allocated it with malloc() instead of png_malloc(), use free() instead - * of png_free(). - */ - png_free(png_ptr, palette); - palette = NULL; - - /* Similarly, if you png_malloced any data that you passed in with - * png_set_something(), such as a hist or trans array, free it here, - * when you can be sure that libpng is through with it. - */ - png_free(png_ptr, trans); - trans = NULL; - /* Whenever you use png_free() it is a good idea to set the pointer to - * NULL in case your application inadvertently tries to png_free() it - * again. When png_free() sees a NULL it returns without action, thus - * avoiding the double-free security problem. - */ - - /* Clean up after the write, and free any memory allocated */ - png_destroy_write_struct(&png_ptr, &info_ptr); - - /* Close the file */ - fclose(fp); - - /* That's it */ - return (OK); -} - -#endif /* if 0 */ + +#if 0 /* in case someone actually tries to compile this */ + +/* example.c - an example of using libpng + * Last changed in libpng 1.2.37 [June 4, 2009] + * This file has been placed in the public domain by the authors. + * Maintained 1998-2010 Glenn Randers-Pehrson + * Maintained 1996, 1997 Andreas Dilger) + * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* This is an example of how to use libpng to read and write PNG files. + * The file libpng.txt is much more verbose then this. If you have not + * read it, do so first. This was designed to be a starting point of an + * implementation. This is not officially part of libpng, is hereby placed + * in the public domain, and therefore does not require a copyright notice. + * + * This file does not currently compile, because it is missing certain + * parts, like allocating memory to hold an image. You will have to + * supply these parts to get it to compile. For an example of a minimal + * working PNG reader/writer, see pngtest.c, included in this distribution; + * see also the programs in the contrib directory. + */ + +#include "png.h" + + /* The png_jmpbuf() macro, used in error handling, became available in + * libpng version 1.0.6. If you want to be able to run your code with older + * versions of libpng, you must define the macro yourself (but only if it + * is not already defined by libpng!). + */ + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +#define PNG_BYTES_TO_CHECK 4 +int check_if_png(char *file_name, FILE **fp) +{ + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if ((*fp = fopen(file_name, "rb")) == NULL) + return 0; + + /* Read in some of the signature bytes */ + if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) + return 0; + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + + return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +/* Read a PNG file. You may want to return an error code if the read + * fails (depending upon the failure). There are two "prototypes" given + * here - one where we are given the filename, and we need to open the + * file, and the other where we are given an open file (possibly with + * some or all of the magic bytes read - see comments above). + */ +#ifdef open_file /* prototype 1 */ +void read_png(char *file_name) /* We need to open the file */ +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned int sig_read = 0; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + FILE *fp; + + if ((fp = fopen(file_name, "rb")) == NULL) + return (ERROR); + +#else no_open_file /* prototype 2 */ +void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; +#endif no_open_file /* Only use one prototype! */ + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also supply the + * the compiler header file version, so that we know if the application + * was compiled with a compatible version of the library. REQUIRED + */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the memory for image information. REQUIRED. */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); + return (ERROR); + } + + /* Set error handling if you are using the setjmp/longjmp method (this is + * the normal method of doing things with libpng). REQUIRED unless you + * set up your own error handlers in the png_create_read_struct() earlier. + */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + /* Free all of the memory associated with the png_ptr and info_ptr */ + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + fclose(fp); + /* If we get here, we had a problem reading the file */ + return (ERROR); + } + + /* One of the following I/O initialization methods is REQUIRED */ +#ifdef streams /* PNG file I/O method 1 */ + /* Set up the input control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* PNG file I/O method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call: + */ + png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Use only one I/O method! */ + + /* If we have already read some of the signature */ + png_set_sig_bytes(png_ptr, sig_read); + +#ifdef hilevel + /* + * If you have enough memory to read in the entire image at once, + * and you need to specify only transforms that can be controlled + * with one of the PNG_TRANSFORM_* bits (this presently excludes + * dithering, filling, setting background, and doing gamma + * adjustment), then you can read the entire image (including + * pixels) into the info structure with this call: + */ + png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); + +#else + /* OK, you're doing it the hard way, with the lower-level functions */ + + /* The call to png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). REQUIRED + */ + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, int_p_NULL, int_p_NULL); + + /* Set up the data transformations you want. Note that these are all + * optional. Only call them if you want/need them. Many of the + * transformations only work on specific types of images, and many + * are mutually exclusive. + */ + + /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ + png_set_strip_16(png_ptr); + + /* Strip alpha bytes from the input data without combining with the + * background (not recommended). + */ + png_set_strip_alpha(png_ptr); + + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + png_set_packing(png_ptr); + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). */ + png_set_packswap(png_ptr); + + /* Expand paletted colors into true RGB triplets */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + + /* Expand paletted or RGB images with transparency to full alpha channels + * so the data will be available as RGBA quartets. + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + + /* Set the background color to draw transparent and alpha images over. + * It is possible to set the red, green, and blue components directly + * for paletted images instead of supplying a palette index. Note that + * even if the PNG file supplies a background, you are not required to + * use it - you should use the (solid) application background if it has one. + */ + + png_color_16 my_background, *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + /* Some suggestions as to how to get a screen gamma value + * + * Note that screen gamma is the display_exponent, which includes + * the CRT_exponent and any correction for viewing conditions + */ + if (/* We have a user-defined screen gamma value */) + { + screen_gamma = user-defined screen_gamma; + } + /* This is one way that applications share the same screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) + { + screen_gamma = atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a PC monitor in a dimly + lit room */ + screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ + } + + /* Tell libpng to handle the gamma conversion for you. The final call + * is a good guess for PC generated images, but it should be configurable + * by the user at run time by the user. It is strongly suggested that + * your application support gamma correction. + */ + + int intent; + + if (png_get_sRGB(png_ptr, info_ptr, &intent)) + png_set_gamma(png_ptr, screen_gamma, 0.45455); + else + { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) + png_set_gamma(png_ptr, screen_gamma, image_gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + + /* Dither RGB files down to 8 bit palette or reduce palettes + * to the number of colors available on your screen. + */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + int num_palette; + png_colorp palette; + + /* This reduces the image to the application supplied palette */ + if (/* We have our own palette */) + { + /* An array of colors to which the image should be dithered */ + png_color std_color_cube[MAX_SCREEN_COLORS]; + + png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, + MAX_SCREEN_COLORS, png_uint_16p_NULL, 0); + } + /* This reduces the image to the palette supplied in the file */ + else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, &histogram); + + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 0); + } + } + + /* Invert monochrome files to have 0 as white and 1 as black */ + png_set_invert_mono(png_ptr); + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit_p; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); + png_set_shift(png_ptr, sig_bit_p); + } + + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (color_type & PNG_COLOR_MASK_COLOR) + png_set_bgr(png_ptr); + + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + png_set_swap_alpha(png_ptr); + + /* Swap bytes of 16 bit files to least significant byte first */ + png_set_swap(png_ptr); + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + + /* Turn on interlace handling. REQUIRED if you are not using + * png_read_image(). To see how to handle interlacing passes, + * see the png_read_row() method below: + */ + number_passes = png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (ie you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* Allocate the memory to hold the image using the fields of info_ptr. */ + + /* The easiest way to read the image: */ + png_bytep row_pointers[height]; + + /* Clear the pointer array */ + for (row = 0; row < height; row++) + row_pointers[row] = NULL; + + for (row = 0; row < height; row++) + row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + + /* Now it's time to read the image. One of these methods is REQUIRED */ +#ifdef entire /* Read the entire image in one go */ + png_read_image(png_ptr, row_pointers); + +#else no_entire /* Read the image one or more scanlines at a time */ + /* The other way to read images - deal with interlacing: */ + + for (pass = 0; pass < number_passes; pass++) + { +#ifdef single /* Read the image a single row at a time */ + for (y = 0; y < height; y++) + { + png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1); + } + +#else no_single /* Read the image several rows at a time */ + for (y = 0; y < height; y += number_of_rows) + { +#ifdef sparkle /* Read the image using the "sparkle" effect. */ + png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, + number_of_rows); +#else no_sparkle /* Read the image using the "rectangle" effect */ + png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y], + number_of_rows); +#endif no_sparkle /* Use only one of these two methods */ + } + + /* If you want to display the image after every pass, do so here */ +#endif no_single /* Use only one of these two methods */ + } +#endif no_entire /* Use only one of these two methods */ + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); +#endif hilevel + + /* At this point you have read the entire image */ + + /* Clean up after the read, and free any memory allocated - REQUIRED */ + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return (OK); +} + +/* Progressively read a file */ + +int +initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) +{ + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible in case we are using dynamically + * linked libraries. + */ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (*png_ptr == NULL) + { + *info_ptr = NULL; + return (ERROR); + } + + *info_ptr = png_create_info_struct(png_ptr); + + if (*info_ptr == NULL) + { + png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf((*png_ptr)))) + { + png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); + return (ERROR); + } + + /* This one's new. You will need to provide all three + * function callbacks, even if you aren't using them all. + * If you aren't using all functions, you can specify NULL + * parameters. Even when all three functions are NULL, + * you need to call png_set_progressive_read_fn(). + * These functions shouldn't be dependent on global or + * static variables if you are decoding several images + * simultaneously. You should store stream specific data + * in a separate struct, given as the second parameter, + * and retrieve the pointer from inside the callbacks using + * the function png_get_progressive_ptr(png_ptr). + */ + png_set_progressive_read_fn(*png_ptr, (void *)stream_data, + info_callback, row_callback, end_callback); + + return (OK); +} + +int +process_data(png_structp *png_ptr, png_infop *info_ptr, + png_bytep buffer, png_uint_32 length) +{ + if (setjmp(png_jmpbuf((*png_ptr)))) + { + /* Free the png_ptr and info_ptr memory on error */ + png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); + return (ERROR); + } + + /* This one's new also. Simply give it chunks of data as + * they arrive from the data stream (in order, of course). + * On segmented machines, don't give it any more than 64K. + * The library seems to run fine with sizes of 4K, although + * you can give it much less if necessary (I assume you can + * give it chunks of 1 byte, but I haven't tried with less + * than 256 bytes yet). When this function returns, you may + * want to display any rows that were generated in the row + * callback, if you aren't already displaying them there. + */ + png_process_data(*png_ptr, *info_ptr, buffer, length); + return (OK); +} + +info_callback(png_structp png_ptr, png_infop info) +{ + /* Do any setup here, including setting any of the transformations + * mentioned in the Reading PNG files section. For now, you _must_ + * call either png_start_read_image() or png_read_update_info() + * after all the transformations are set (even if you don't set + * any). You may start getting rows before png_process_data() + * returns, so this is your last chance to prepare for that. + */ +} + +row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ + /* + * This function is called for every row in the image. If the + * image is interlaced, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * + * In this function you will receive a pointer to new row data from + * libpng called new_row that is to replace a corresponding row (of + * the same data format) in a buffer allocated by your application. + * + * The new row data pointer "new_row" may be NULL, indicating there is + * no new data to be replaced (in cases of interlace loading). + * + * If new_row is not NULL then you need to call + * png_progressive_combine_row() to replace the corresponding row as + * shown below: + */ + + /* Get pointer to corresponding row in our + * PNG read buffer. + */ + png_bytep old_row = ((png_bytep *)our_data)[row_num]; + + /* If both rows are allocated then copy the new row + * data to the corresponding row data. + */ + if ((old_row != NULL) && (new_row != NULL)) + png_progressive_combine_row(png_ptr, old_row, new_row); + + /* + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the new row and the + * old row, as demonstrated above. You can call this function for + * NULL rows (it will just return) and for non-interlaced images + * (it just does the png_memcpy for you) if it will make the code + * easier. Thus, you can just do this for all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, new_row); + + /* where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * to pass the current row as new_row, and the function will combine + * the old row and the new row. + */ +} + +end_callback(png_structp png_ptr, png_infop info) +{ + /* This function is called when the whole image has been read, + * including any chunks after the image (up to and including + * the IEND). You will usually have the same info chunk as you + * had in the header, although some data may have been added + * to the comments and time fields. + * + * Most people won't do much here, perhaps setting a flag that + * marks the image as finished. + */ +} + +/* Write a png file */ +void write_png(char *file_name /* , ... other image information ... */) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette; + + /* Open the file */ + fp = fopen(file_name, "wb"); + if (fp == NULL) + return (ERROR); + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the image information data. REQUIRED */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_write_struct(&png_ptr, png_infopp_NULL); + return (ERROR); + } + + /* Set error handling. REQUIRED if you aren't supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png_ptr))) + { + /* If we get here, we had a problem writing the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, &info_ptr); + return (ERROR); + } + + /* One of the following I/O initialization functions is REQUIRED */ + +#ifdef streams /* I/O initialization method 1 */ + /* Set up the output control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* I/O initialization method 2 */ + /* If you are using replacement write functions, instead of calling + * png_init_io() here you would call + */ + png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, + user_IO_flush_function); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Only use one initialization method */ + +#ifdef hilevel + /* This is the easy way. Use it if you already have all the + * image info living in the structure. You could "|" many + * PNG_TRANSFORM flags into the png_transforms integer here. + */ + png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); + +#else + /* This is the hard way */ + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + */ + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, + PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Set the palette if there is one. REQUIRED for indexed-color images */ + palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH + * png_sizeof(png_color)); + /* ... Set palette colors ... */ + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + /* You must not free palette here, because png_set_PLTE only makes a link to + * the palette that you malloced. Wait until you are about to destroy + * the png structure. + */ + + /* Optional significant bit (sBIT) chunk */ + png_color_8 sig_bit; + /* If we are dealing with a grayscale image then */ + sig_bit.gray = true_bit_depth; + /* Otherwise, if we are dealing with a color image then */ + sig_bit.red = true_red_bit_depth; + sig_bit.green = true_green_bit_depth; + sig_bit.blue = true_blue_bit_depth; + /* If the image has an alpha channel then */ + sig_bit.alpha = true_alpha_bit_depth; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + + /* Optional gamma chunk is strongly suggested if you have any guess + * as to the correct gamma of the image. + */ + png_set_gAMA(png_ptr, info_ptr, gamma); + + /* Optionally write comments into the image */ + text_ptr[0].key = "Title"; + text_ptr[0].text = "Mona Lisa"; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[1].key = "Author"; + text_ptr[1].text = "Leonardo DaVinci"; + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[2].key = "Description"; + text_ptr[2].text = ""; + text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; +#ifdef PNG_iTXt_SUPPORTED + text_ptr[0].lang = NULL; + text_ptr[1].lang = NULL; + text_ptr[2].lang = NULL; +#endif + png_set_text(png_ptr, info_ptr, text_ptr, 3); + + /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ + + /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored + * on read and, if your application chooses to write them, they must + * be written in accordance with the sRGB profile + */ + + /* Write the file header information. REQUIRED */ + png_write_info(png_ptr, info_ptr); + + /* If you want, you can write the info in two steps, in case you need to + * write your private chunk ahead of PLTE: + * + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + * write_my_chunk(); + * png_write_info(png_ptr, info_ptr); + * + * However, given the level of known- and unknown-chunk support in 1.2.0 + * and up, this should no longer be necessary. + */ + + /* Once we write out the header, the compression type on the text + * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or + * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again + * at the end. + */ + + /* Set up the transformations you want. Note that these are + * all optional. Only call them if you want them. + */ + + /* Invert monochrome pixels */ + png_set_invert_mono(png_ptr); + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + png_set_shift(png_ptr, &sig_bit); + + /* Pack pixels into bytes */ + png_set_packing(png_ptr); + + /* Swap location of alpha bytes from ARGB to RGBA */ + png_set_swap_alpha(png_ptr); + + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + + /* Flip BGR pixels to RGB */ + png_set_bgr(png_ptr); + + /* Swap bytes of 16-bit files to most significant byte first */ + png_set_swap(png_ptr); + + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + png_set_packswap(png_ptr); + + /* Turn on interlace handling if you are not using png_write_image() */ + if (interlacing) + number_passes = png_set_interlace_handling(png_ptr); + else + number_passes = 1; + + /* The easiest way to write the image (you may have a different memory + * layout, however, so choose what fits your needs best). You need to + * use the first method if you aren't handling interlacing yourself. + */ + png_uint_32 k, height, width; + png_byte image[height][width*bytes_per_pixel]; + png_bytep row_pointers[height]; + + if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error (png_ptr, "Image is too tall to process in memory"); + + for (k = 0; k < height; k++) + row_pointers[k] = image + k*width*bytes_per_pixel; + + /* One of the following output methods is REQUIRED */ + +#ifdef entire /* Write out the entire image data in one call */ + png_write_image(png_ptr, row_pointers); + + /* The other way to write the image - deal with interlacing */ + +#else no_entire /* Write out the image data by one or more scanlines */ + + /* The number of passes is either 1 for non-interlaced images, + * or 7 for interlaced images. + */ + for (pass = 0; pass < number_passes; pass++) + { + /* Write a few rows at a time. */ + png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); + + /* If you are only writing one row at a time, this works */ + for (y = 0; y < height; y++) + png_write_rows(png_ptr, &row_pointers[y], 1); + } +#endif no_entire /* Use only one output method */ + + /* You can write optional chunks like tEXt, zTXt, and tIME at the end + * as well. Shouldn't be necessary in 1.2.0 and up as all the public + * chunks are supported and you can use png_set_unknown_chunks() to + * register unknown chunks into the info structure to be written out. + */ + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); +#endif hilevel + + /* If you png_malloced a palette, free it here (don't free info_ptr->palette, + * as recommended in versions 1.0.5m and earlier of this example; if + * libpng mallocs info_ptr->palette, libpng will free it). If you + * allocated it with malloc() instead of png_malloc(), use free() instead + * of png_free(). + */ + png_free(png_ptr, palette); + palette = NULL; + + /* Similarly, if you png_malloced any data that you passed in with + * png_set_something(), such as a hist or trans array, free it here, + * when you can be sure that libpng is through with it. + */ + png_free(png_ptr, trans); + trans = NULL; + /* Whenever you use png_free() it is a good idea to set the pointer to + * NULL in case your application inadvertently tries to png_free() it + * again. When png_free() sees a NULL it returns without action, thus + * avoiding the double-free security problem. + */ + + /* Clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return (OK); +} + +#endif /* if 0 */ diff --git a/main/source/includes/lpng1251/libpng-1.2.51.txt b/main/source/includes/lpng1251/libpng-1.2.51.txt index 0c3be159..98f50706 100644 --- a/main/source/includes/lpng1251/libpng-1.2.51.txt +++ b/main/source/includes/lpng1251/libpng-1.2.51.txt @@ -1,3237 +1,3237 @@ -libpng.txt - A description on how to use and modify libpng - - libpng version 1.2.51 - February 6, 2014 - Updated and distributed by Glenn Randers-Pehrson - - Copyright (c) 1998-2014 Glenn Randers-Pehrson - - This document is released under the libpng license. - For conditions of distribution and use, see the disclaimer - and license in png.h - - Based on: - - libpng versions 0.97, January 1998, through 1.2.51 - February 6, 2014 - Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2014 Glenn Randers-Pehrson - - libpng 1.0 beta 6 version 0.96 May 28, 1997 - Updated and distributed by Andreas Dilger - Copyright (c) 1996, 1997 Andreas Dilger - - libpng 1.0 beta 2 - version 0.88 January 26, 1996 - For conditions of distribution and use, see copyright - notice in png.h. Copyright (c) 1995, 1996 Guy Eric - Schalnat, Group 42, Inc. - - Updated/rewritten per request in the libpng FAQ - Copyright (c) 1995, 1996 Frank J. T. Wojcik - December 18, 1995 & January 20, 1996 - -I. Introduction - -This file describes how to use and modify the PNG reference library -(known as libpng) for your own use. There are five sections to this -file: introduction, structures, reading, writing, and modification and -configuration notes for various special platforms. In addition to this -file, example.c is a good starting point for using the library, as -it is heavily commented and should include everything most people -will need. We assume that libpng is already installed; see the -INSTALL file for instructions on how to install libpng. - -For examples of libpng usage, see the files "example.c", "pngtest.c", -and the files in the "contrib" directory, all of which are included in -the libpng distribution. - -Libpng was written as a companion to the PNG specification, as a way -of reducing the amount of time and effort it takes to support the PNG -file format in application programs. - -The PNG specification (second edition), November 2003, is available as -a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at -. It is technically equivalent -to the PNG specification (second edition) but has some additional material. - -The PNG-1.0 specification is available -as RFC 2083 and as a -W3C Recommendation . - -Some additional chunks are described in the special-purpose public chunks -documents at . - -Other information -about PNG, and the latest version of libpng, can be found at the PNG home -page, . - -Most users will not have to modify the library significantly; advanced -users may want to modify it more. All attempts were made to make it as -complete as possible, while keeping the code easy to understand. -Currently, this library only supports C. Support for other languages -is being considered. - -Libpng has been designed to handle multiple sessions at one time, -to be easily modifiable, to be portable to the vast majority of -machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy -to use. The ultimate goal of libpng is to promote the acceptance of -the PNG file format in whatever way possible. While there is still -work to be done (see the TODO file), libpng should cover the -majority of the needs of its users. - -Libpng uses zlib for its compression and decompression of PNG files. -Further information about zlib, and the latest version of zlib, can -be found at the zlib home page, . -The zlib compression utility is a general purpose utility that is -useful for more than PNG files, and can be used without libpng. -See the documentation delivered with zlib for more details. -You can usually find the source files for the zlib utility wherever you -find the libpng source files. - -Libpng is thread safe, provided the threads are using different -instances of the structures. Each thread should have its own -png_struct and png_info instances, and thus its own image. -Libpng does not protect itself against two threads using the -same instance of a structure. - -II. Structures - -There are two main structures that are important to libpng, png_struct -and png_info. The first, png_struct, is an internal structure that -will not, for the most part, be used by a user except as the first -variable passed to every libpng function call. - -The png_info structure is designed to provide information about the -PNG file. At one time, the fields of png_info were intended to be -directly accessible to the user. However, this tended to cause problems -with applications using dynamically loaded libraries, and as a result -a set of interface functions for png_info (the png_get_*() and png_set_*() -functions) was developed. The fields of png_info are still available for -older applications, but it is suggested that applications use the new -interfaces if at all possible. - -Applications that do make direct access to the members of png_struct (except -for png_ptr->jmpbuf) must be recompiled whenever the library is updated, -and applications that make direct access to the members of png_info must -be recompiled if they were compiled or loaded with libpng version 1.0.6, -in which the members were in a different order. In version 1.0.7, the -members of the png_info structure reverted to the old order, as they were -in versions 0.97c through 1.0.5. Starting with version 2.0.0, both -structures are going to be hidden, and the contents of the structures will -only be accessible through the png_get/png_set functions. - -The png.h header file is an invaluable reference for programming with libpng. -And while I'm on the topic, make sure you include the libpng header file: - -#include - -III. Reading - -We'll now walk you through the possible functions to call when reading -in a PNG file sequentially, briefly explaining the syntax and purpose -of each one. See example.c and png.h for more detail. While -progressive reading is covered in the next section, you will still -need some of the functions discussed in this section to read a PNG -file. - -Setup - -You will want to do the I/O initialization(*) before you get into libpng, -so if it doesn't work, you don't have much to undo. Of course, you -will also want to insure that you are, in fact, dealing with a PNG -file. Libpng provides a simple check to see if a file is a PNG file. -To use it, pass in the first 1 to 8 bytes of the file to the function -png_sig_cmp(), and it will return 0 (false) if the bytes match the -corresponding bytes of the PNG signature, or nonzero (true) otherwise. -Of course, the more bytes you pass in, the greater the accuracy of the -prediction. - -If you are intending to keep the file pointer open for use in libpng, -you must ensure you don't read more than 8 bytes from the beginning -of the file, and you also have to make a call to png_set_sig_bytes_read() -with the number of bytes you read from the beginning. Libpng will -then only check the bytes (if any) that your program didn't read. - -(*): If you are not using the standard I/O functions, you will need -to replace them with custom functions. See the discussion under -Customizing libpng. - - - FILE *fp = fopen(file_name, "rb"); - if (!fp) - { - return (ERROR); - } - fread(header, 1, number, fp); - is_png = !png_sig_cmp(header, 0, number); - if (!is_png) - { - return (NOT_PNG); - } - - -Next, png_struct and png_info need to be allocated and initialized. In -order to ensure that the size of these structures is correct even with a -dynamically linked libpng, there are functions to initialize and -allocate the structures. We also pass the library version, optional -pointers to error handling functions, and a pointer to a data struct for -use by the error functions, if necessary (the pointer and functions can -be NULL if the default error handlers are to be used). See the section -on Changes to Libpng below regarding the old initialization functions. -The structure allocation functions quietly return NULL if they fail to -create the structure, so your application should check for that. - - png_structp png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, - (png_infopp)NULL, (png_infopp)NULL); - return (ERROR); - } - - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_read_struct_2() instead of png_create_read_struct(): - - png_structp png_ptr = png_create_read_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -The error handling routines passed to png_create_read_struct() -and the memory alloc/free routines passed to png_create_struct_2() -are only necessary if you are not using the libpng supplied error -handling and memory alloc/free functions. - -When libpng encounters an error, it expects to longjmp back -to your routine. Therefore, you will need to call setjmp and pass -your png_jmpbuf(png_ptr). If you read the file from different -routines, you will need to update the jmpbuf field every time you enter -a new routine that will call a png_*() function. - -See your documentation of setjmp/longjmp for your compiler for more -information on setjmp/longjmp. See the discussion on libpng error -handling in the Customizing Libpng section below for more information -on the libpng error handling. If an error occurs, and libpng longjmp's -back to your setjmp, you will want to call png_destroy_read_struct() to -free any memory. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - fclose(fp); - return (ERROR); - } - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the input code. The default for libpng is to -use the C function fread(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. If you wish to handle reading data in another -way, you need not call the png_init_io() function, but you must then -implement the libpng I/O methods discussed in the Customizing Libpng -section below. - - png_init_io(png_ptr, fp); - -If you had previously opened the file and read any of the signature from -the beginning in order to see if this was a PNG file, you need to let -libpng know that there are some bytes missing from the start of the file. - - png_set_sig_bytes(png_ptr, number); - -Setting up callback code - -You can set up a callback function to handle any unknown chunks in the -input stream. You must supply the function - - read_chunk_callback(png_ptr ptr, - png_unknown_chunkp chunk); - { - /* The unknown chunk structure contains your - chunk data, along with similar data for any other - unknown chunks: */ - - png_byte name[5]; - png_byte *data; - png_size_t size; - - /* Note that libpng has already taken care of - the CRC handling */ - - /* put your code here. Search for your chunk in the - unknown chunk structure, process it, and return one - of the following: */ - - return (-n); /* chunk had an error */ - return (0); /* did not recognize */ - return (n); /* success */ - } - -(You can give your function another name that you like instead of -"read_chunk_callback") - -To inform libpng about your function, use - - png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, - read_chunk_callback); - -This names not only the callback function, but also a user pointer that -you can retrieve with - - png_get_user_chunk_ptr(png_ptr); - -If you call the png_set_read_user_chunk_fn() function, then all unknown -chunks will be saved when read, in case your callback function will need -one or more of them. This behavior can be changed with the -png_set_keep_unknown_chunks() function, described below. - -At this point, you can set up a callback function that will be -called after each row has been read, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void read_row_callback(png_ptr ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "read_row_callback") - -To inform libpng about your function, use - - png_set_read_status_fn(png_ptr, read_row_callback); - -Unknown-chunk handling - -Now you get to set the way the library processes unknown chunks in the -input PNG stream. Both known and unknown chunks will be read. Normal -behavior is that known chunks will be parsed into information in -various info_ptr members while unknown chunks will be discarded. This -behavior can be wasteful if your application will never use some known -chunk types. To change this, you can call: - - png_set_keep_unknown_chunks(png_ptr, keep, - chunk_list, num_chunks); - keep - 0: default unknown chunk handling - 1: ignore; do not keep - 2: keep only if safe-to-copy - 3: keep even if unsafe-to-copy - You can use these definitions: - PNG_HANDLE_CHUNK_AS_DEFAULT 0 - PNG_HANDLE_CHUNK_NEVER 1 - PNG_HANDLE_CHUNK_IF_SAFE 2 - PNG_HANDLE_CHUNK_ALWAYS 3 - chunk_list - list of chunks affected (a byte string, - five bytes per chunk, NULL or '\0' if - num_chunks is 0) - num_chunks - number of chunks affected; if 0, all - unknown chunks are affected. If nonzero, - only the chunks in the list are affected - -Unknown chunks declared in this way will be saved as raw data onto a -list of png_unknown_chunk structures. If a chunk that is normally -known to libpng is named in the list, it will be handled as unknown, -according to the "keep" directive. If a chunk is named in successive -instances of png_set_keep_unknown_chunks(), the final instance will -take precedence. The IHDR and IEND chunks should not be named in -chunk_list; if they are, libpng will process them normally anyway. - -Here is an example of the usage of png_set_keep_unknown_chunks(), -where the private "vpAg" chunk will later be processed by a user chunk -callback function: - - png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - png_byte unused_chunks[]= - { - 104, 73, 83, 84, (png_byte) '\0', /* hIST */ - 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ - 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ - 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ - 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ - 116, 73, 77, 69, (png_byte) '\0', /* tIME */ - }; - #endif - - ... - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - /* ignore all unknown chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, NULL, 0); - /* except for vpAg: */ - png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); - /* also ignore unused known chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - #endif - -User limits - -The PNG specification allows the width and height of an image to be as -large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. -Since very few applications really need to process such large images, -we have imposed an arbitrary 1-million limit on rows and columns. -Larger images will be rejected immediately with a png_error() call. If -you wish to override this limit, you can use - - png_set_user_limits(png_ptr, width_max, height_max); - -to set your own limits, or use width_max = height_max = 0x7fffffffL -to allow all valid dimensions (libpng may reject some very large images -anyway because of potential buffer overflow conditions). - -You should put this statement after you create the PNG structure and -before calling png_read_info(), png_read_png(), or png_process_data(). -If you need to retrieve the limits that are being applied, use - - width_max = png_get_user_width_max(png_ptr); - height_max = png_get_user_height_max(png_ptr); - -The PNG specification sets no limit on the number of ancillary chunks -allowed in a PNG datastream. You can impose a limit on the total number -of sPLT, tEXt, iTXt, zTXt, and unknown chunks that will be stored, with - - png_set_chunk_cache_max(png_ptr, user_chunk_cache_max); - -where 0x7fffffffL means unlimited. You can retrieve this limit with - - chunk_cache_max = png_get_chunk_cache_max(png_ptr); - -This limit also applies to the number of buffers that can be allocated -by png_decompress_chunk() while decompressing iTXt, zTXt, and iCCP chunks. - -The high-level read interface - -At this point there are two ways to proceed; through the high-level -read interface, or through a sequence of low-level read operations. -You can use the high-level interface if (a) you are willing to read -the entire image into memory, and (b) the input transformations -you want to do are limited to the following set: - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to - 8 bits - PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel - PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit - samples to bytes - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_EXPAND Perform set_expand() - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples - to RGB (or GA to RGBA) - -(This excludes setting a background color, doing gamma transformation, -dithering, and setting filler.) If this is the case, simply do this: - - png_read_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of some -set of transformation flags. This call is equivalent to png_read_info(), -followed the set of transformations indicated by the transform mask, -then png_read_image(), and finally png_read_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future input transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_read_png(). - -After you have called png_read_png(), you can retrieve the image data -with - - row_pointers = png_get_rows(png_ptr, info_ptr); - -where row_pointers is an array of pointers to the pixel data for each row: - - png_bytep row_pointers[height]; - -If you know your image size and pixel size ahead of time, you can allocate -row_pointers prior to calling png_read_png() with - - if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) - png_error (png_ptr, - "Image is too tall to process in memory"); - if (width > PNG_UINT_32_MAX/pixel_size) - png_error (png_ptr, - "Image is too wide to process in memory"); - row_pointers = png_malloc(png_ptr, - height*png_sizeof(png_bytep)); - for (int i=0; i) and -png_get_(png_ptr, info_ptr, ...) functions return non-zero if the -data has been read, or zero if it is missing. The parameters to the -png_get_ are set directly if they are simple data types, or a -pointer into the info_ptr is returned for any complex types. - - png_get_PLTE(png_ptr, info_ptr, &palette, - &num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_get_gAMA(png_ptr, info_ptr, &gamma); - gamma - the gamma the file is written - at (PNG_INFO_gAMA) - - png_get_sRGB(png_ptr, info_ptr, &srgb_intent); - srgb_intent - the rendering intent (PNG_INFO_sRGB) - The presence of the sRGB chunk - means that the pixel data is in the - sRGB color space. This chunk also - implies specific values of gAMA and - cHRM. - - png_get_iCCP(png_ptr, info_ptr, &name, - &compression_type, &profile, &proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, - red, green, and blue channels, - whichever are appropriate for the - given color type (png_color_16) - - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, - &trans_values); - trans - array of transparent - entries for palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values of - the single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_get_hIST(png_ptr, info_ptr, &hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_get_tIME(png_ptr, info_ptr, &mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_get_bKGD(png_ptr, info_ptr, &background); - background - background color (PNG_VALID_bKGD) - valid 16-bit red, green and blue - values, regardless of color_type - - num_comments = png_get_text(png_ptr, info_ptr, - &text_ptr, &num_text); - num_comments - number of comments - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (empty - string for unknown). - text_ptr[i].lang_key - keyword in UTF-8 - (empty string for unknown). - Note that the itxt_length, lang, and lang_key - members of the text_ptr structure only exist - when the library is built with iTXt chunk support. - - num_text - number of comments (same as - num_comments; you can put NULL here - to avoid the duplication) - Note while png_set_text() will accept text, language, - and translated keywords that can be NULL pointers, the - structure returned by png_get_text will always contain - regular zero-terminated C strings. They might be - empty strings but they will never be NULL pointers. - - num_spalettes = png_get_sPLT(png_ptr, info_ptr, - &palette_ptr); - palette_ptr - array of palette structures holding - contents of one or more sPLT chunks - read. - num_spalettes - number of sPLT chunks read. - - png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, - &unit_type); - offset_x - positive offset from the left edge - of the screen - offset_y - positive offset from the top edge - of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, - &unit_type); - res_x - pixels/unit physical resolution in - x direction - res_y - pixels/unit physical resolution in - x direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_get_sCAL(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - num_unknown_chunks = png_get_unknown_chunks(png_ptr, - info_ptr, &unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position of chunk in file - - The value of "i" corresponds to the order in which the - chunks were read from the PNG file or inserted with the - png_set_unknown_chunks() function. - -The data from the pHYs chunk can be retrieved in several convenient -forms: - - res_x = png_get_x_pixels_per_meter(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_meter(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_meter(png_ptr, - info_ptr) - res_x = png_get_x_pixels_per_inch(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_inch(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_inch(png_ptr, - info_ptr) - aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, - info_ptr) - - (Each of these returns 0 [signifying "unknown"] if - the data is not present or if res_x is 0; - res_x_and_y is 0 if res_x != res_y) - -The data from the oFFs chunk can be retrieved in several convenient -forms: - - x_offset = png_get_x_offset_microns(png_ptr, info_ptr); - y_offset = png_get_y_offset_microns(png_ptr, info_ptr); - x_offset = png_get_x_offset_inches(png_ptr, info_ptr); - y_offset = png_get_y_offset_inches(png_ptr, info_ptr); - - (Each of these returns 0 [signifying "unknown" if both - x and y are 0] if the data is not present or if the - chunk is present but the unit is the pixel) - -For more information, see the png_info definition in png.h and the -PNG specification for chunk contents. Be careful with trusting -rowbytes, as some of the transformations could increase the space -needed to hold a row (expand, filler, gray_to_rgb, etc.). -See png_read_update_info(), below. - -A quick word about text_ptr and num_text. PNG stores comments in -keyword/text pairs, one pair per chunk, with no limit on the number -of text chunks, and a 2^31 byte limit on their size. While there are -suggested keywords, there is no requirement to restrict the use to these -strings. It is strongly suggested that keywords and text be sensible -to humans (that's the point), so don't use abbreviations. Non-printing -symbols are not allowed. See the PNG specification for more details. -There is also no requirement to have text after the keyword. - -Keywords should be limited to 79 Latin-1 characters without leading or -trailing spaces, but non-consecutive spaces are allowed within the -keyword. It is possible to have the same keyword any number of times. -The text_ptr is an array of png_text structures, each holding a -pointer to a language string, a pointer to a keyword and a pointer to -a text string. The text string, language code, and translated -keyword may be empty or NULL pointers. The keyword/text -pairs are put into the array in the order that they are received. -However, some or all of the text chunks may be after the image, so, to -make sure you have read all the text chunks, don't mess with these -until after you read the stuff after the image. This will be -mentioned again below in the discussion that goes with png_read_end(). - -Input transformations - -After you've read the header information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -The colors used for the background and transparency values should be -supplied in the same format/depth as the current image data. They -are stored in the same format/depth as the image data in a bKGD or tRNS -chunk, so this is what libpng expects for this data. The colors are -transformed to keep in sync with the image data when an application -calls the png_read_update_info() routine (see below). - -Data will be decoded into the supplied row buffers packed into bytes -unless the library has been told to transform it into another format. -For example, 4 bit/pixel paletted or grayscale data will be returned -2 pixels/byte with the leftmost pixel in the high-order bits of the -byte, unless png_set_packing() is called. 8-bit RGB data will be stored -in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() -is called to insert filler bytes, either before or after each RGB triplet. -16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant -byte of the color value first, unless png_set_strip_16() is called to -transform it to regular RGB RGB triplets, or png_set_filler() or -png_set_add alpha() is called to insert filler bytes, either before or -after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can -be modified with -png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). - -The following code transforms grayscale images of less than 8 to 8 bits, -changes paletted images to RGB, and adds a full alpha channel if there is -transparency information in a tRNS chunk. This is most useful on -grayscale images with bit depths of 2 or 4 or if there is a multiple-image -viewing application that wishes to treat all images in the same way. - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && - bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); - - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); - -These three functions are actually aliases for png_set_expand(), added -in libpng version 1.0.4, with the function names expanded to improve code -readability. In some future version they may actually do different -things. - -As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was -added. It expands the sample depth without changing tRNS to alpha. - -As of libpng version 1.2.51, not all possible expansions are supported. - -In the following table, the 01 means grayscale with depth<8, 31 means -indexed with depth<8, other numerals represent the color type, "T" means -the tRNS chunk is present, A means an alpha channel is present, and O -means tRNS or alpha is present but all pixels in the image are opaque. - - FROM 01 31 0 0T 0O 2 2T 2O 3 3T 3O 4A 4O 6A 6O - TO - 01 - - 31 - - 0 1 - - 0T - - 0O - - 2 GX - - 2T - - 2O - - 3 1 - - 3T - - 3O - - 4A T - - 4O - - 6A GX TX TX - - 6O GX TX - - -Within the matrix, - "-" means the transformation is not supported. - "X" means the transformation is obtained by png_set_expand(). - "1" means the transformation is obtained by - png_set_expand_gray_1_2_4_to_8 - "G" means the transformation is obtained by - png_set_gray_to_rgb(). - "P" means the transformation is obtained by - png_set_expand_palette_to_rgb(). - "T" means the transformation is obtained by - png_set_tRNS_to_alpha(). - -PNG can have files with 16 bits per channel. If you only can handle -8 bits per channel, this will strip the pixels down to 8 bit. - - if (bit_depth == 16) - png_set_strip_16(png_ptr); - -If, for some reason, you don't need the alpha channel on an image, -and you want to remove it rather than combining it with the background -(but the image author certainly had in mind that you *would* combine -it with the background, so that's what you should probably do): - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(png_ptr); - -In PNG files, the alpha channel in an image -is the level of opacity. If you need the alpha channel in an image to -be the level of transparency instead of opacity, you can invert the -alpha channel (or the tRNS chunk data) after it's read, so that 0 is -fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit -images) is fully transparent, with - - png_set_invert_alpha(png_ptr); - -The PNG format only supports pixels with postmultiplied alpha. -If you want to replace the pixels, after reading them, with pixels -that have premultiplied color samples, you can do this with - - png_set_premultiply_alpha(png_ptr); - -If you do this, any input with a tRNS chunk will be expanded to -have an alpha channel. - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit -files. This code expands to 1 pixel per byte without changing the -values of the pixels: - - if (bit_depth < 8) - png_set_packing(png_ptr); - -PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels -stored in a PNG image have been "scaled" or "shifted" up to the next -higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] -to 8 bits/sample in the range [0, 255]). However, it is also possible -to convert the PNG pixel data back to the original bit depth of the -image. This call reduces the pixels back down to the original bit depth: - - png_color_8p sig_bit; - - if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) - png_set_shift(png_ptr, sig_bit); - -PNG files store 3-color pixels in red, green, blue order. This code -changes the storage of the pixels to blue, green, red: - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_bgr(png_ptr); - -PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them -into 4 or 8 bytes for windowing systems that need them in this format: - - if (color_type == PNG_COLOR_TYPE_RGB) - png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); - -where "filler" is the 8 or 16-bit number to fill with, and the location is -either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether -you want the filler before the RGB or after. This transformation -does not affect images that already have full alpha channels. To add an -opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which -will generate RGBA pixels. - -Note that png_set_filler() does not change the color type. If you want -to do that, you can add a true alpha channel with - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY) - png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); - -where "filler" contains the alpha value to assign to each pixel. -This function was added in libpng-1.2.7. - -If you are reading an image with an alpha channel, and you need the -data as ARGB instead of the normal PNG format RGBA: - - if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_swap_alpha(png_ptr); - -For some uses, you may want a grayscale image to be represented as -RGB. This code will do that conversion: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - -Conversely, you can convert an RGB or RGBA image to grayscale or grayscale -with alpha. - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, error_action, - int red_weight, int green_weight); - - error_action = 1: silently do the conversion - error_action = 2: issue a warning if the original - image has any pixel where - red != green or red != blue - error_action = 3: issue an error and abort the - conversion if the original - image has any pixel where - red != green or red != blue - - red_weight: weight of red component times 100000 - green_weight: weight of green component times 100000 - If either weight is negative, default - weights (21268, 71514) are used. - -If you have set error_action = 1 or 2, you can -later check whether the image really was gray, after processing -the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. -It will return a png_byte that is zero if the image was gray or -1 if there were any non-gray pixels. bKGD and sBIT data -will be silently converted to grayscale, using the green channel -data, regardless of the error_action setting. - -With red_weight+green_weight<=100000, -the normalized graylevel is computed: - - int rw = red_weight * 65536; - int gw = green_weight * 65536; - int bw = 65536 - (rw + gw); - gray = (rw*red + gw*green + bw*blue)/65536; - -The default values approximate those recommended in the Charles -Poynton's Color FAQ, -Copyright (c) 1998-01-04 Charles Poynton - - Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - -Libpng approximates this with - - Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - -which can be expressed with integers as - - Y = (6969 * R + 23434 * G + 2365 * B)/32768 - -The calculation is done in a linear colorspace, if the image gamma -is known. - -If you have a grayscale and you are using png_set_expand_depth(), -png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to -a higher bit-depth, you must either supply the background color as a gray -value at the original file bit-depth (need_expand = 1) or else supply the -background color as an RGB triplet at the final, expanded bit depth -(need_expand = 0). Similarly, if you are reading a paletted image, you -must either supply the background color as a palette index (need_expand = 1) -or as an RGB triplet that may or may not be in the palette (need_expand = 0). - - png_color_16 my_background; - png_color_16p image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - -The png_set_background() function tells libpng to composite images -with alpha or simple transparency against the supplied background -color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), -you may use this color, or supply another color more suitable for -the current display (e.g., the background color from a web page). You -need to tell libpng whether the color is in the gamma space of the -display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file -(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one -that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't -know why anyone would use this, but it's here). - -To properly display PNG images on any kind of system, the application needs -to know what the display gamma is. Ideally, the user will know this, and -the application will allow them to set it. One method of allowing the user -to set the display gamma separately for each system is to check for a -SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be -correctly set. - -Note that display_gamma is the overall gamma correction required to produce -pleasing results, which depends on the lighting conditions in the surrounding -environment. In a dim or brightly lit room, no compensation other than -the physical gamma exponent of the monitor is needed, while in a dark room -a slightly smaller exponent is better. - - double gamma, screen_gamma; - - if (/* We have a user-defined screen - gamma value */) - { - screen_gamma = user_defined_screen_gamma; - } - /* One way that applications can share the same - screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) - != NULL) - { - screen_gamma = (double)atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a - PC monitor in a bright office or a dim room */ - screen_gamma = 2.0; /* A good guess for a - PC monitor in a dark room */ - screen_gamma = 1.7 or 1.0; /* A good - guess for Mac systems */ - } - -The png_set_gamma() function handles gamma transformations of the data. -Pass both the file gamma and the current screen_gamma. If the file does -not have a gamma value, you can pass one anyway if you have an idea what -it is (usually 0.45455 is a good guess for GIF images on PCs). Note -that file gammas are inverted from screen gammas. See the discussions -on gamma in the PNG specification for an excellent description of what -gamma is, and why all applications should support it. It is strongly -recommended that PNG viewers support gamma correction. - - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma(png_ptr, screen_gamma, gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - -If you need to reduce an RGB file to a paletted file, or if a paletted -file has more entries then will fit on your screen, png_set_dither() -will do that. Note that this is a simple match dither that merely -finds the closest color available. This should work fairly well with -optimized palettes, and fairly badly with linear color cubes. If you -pass a palette that is larger then maximum_colors, the file will -reduce the number of colors in the palette so it will fit into -maximum_colors. If there is a histogram, it will use it to make -more intelligent choices when reducing the palette. If there is no -histogram, it may not do as good a job. - - if (color_type & PNG_COLOR_MASK_COLOR) - { - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_PLTE)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, - &histogram); - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 1); - } - else - { - png_color std_color_cube[MAX_SCREEN_COLORS] = - { ... colors ... }; - - png_set_dither(png_ptr, std_color_cube, - MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, - NULL,0); - } - } - -PNG files describe monochrome as black being zero and white being one. -The following code will reverse this (make black be one and white be -zero): - - if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) - png_set_invert_mono(png_ptr); - -This function can also be used to invert grayscale and gray-alpha images: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_invert_mono(png_ptr); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code changes the storage to the -other way (little-endian, i.e. least significant bits first, the -way PCs store them): - - if (bit_depth == 16) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_read_user_transform_fn(png_ptr, - read_transform_fn); - -You must supply the function - - void read_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -after all of the other transformations have been processed. - -You can also set up a pointer to a user structure for use by your -callback function, and you can inform libpng that your transform -function will change the number of channels or bit depth with the -function - - png_set_user_transform_info(png_ptr, user_ptr, - user_depth, user_channels); - -The user's application, not libpng, is responsible for allocating and -freeing any memory required for the user structure. - -You can retrieve the pointer via the function -png_get_user_transform_ptr(). For example: - - voidp read_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -The last thing to handle is interlacing; this is covered in detail below, -but you must call the function here if you want libpng to handle expansion -of the interlaced image. - - number_of_passes = png_set_interlace_handling(png_ptr); - -After setting the transformations, libpng can update your png_info -structure to reflect any transformations you've requested with this -call. This is most useful to update the info structure's rowbytes -field so you can use it to allocate your image memory. This function -will also update your palette with the correct screen_gamma and -background if these have been given with the calls above. - - png_read_update_info(png_ptr, info_ptr); - -After you call png_read_update_info(), you can allocate any -memory you need to hold the image. The row data is simply -raw byte data for all forms of images. As the actual allocation -varies among applications, no example will be given. If you -are allocating one large chunk, you will need to build an -array of pointers to each row, as it will be needed for some -of the functions below. - -Reading image data - -After you've allocated memory, you can read the image data. -The simplest way to do this is in one function call. If you are -allocating enough memory to hold the whole image, you can just -call png_read_image() and libpng will read in all the image data -and put it in the memory area supplied. You will need to pass in -an array of pointers to each row. - -This function automatically handles interlacing, so you don't need -to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_read_rows(). - - png_read_image(png_ptr, row_pointers); - -where row_pointers is: - - png_bytep row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to read in the whole image at once, you can -use png_read_rows() instead. If there is no interlacing (check -interlace_type == PNG_INTERLACE_NONE), this is simple: - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -where row_pointers is the same as in the png_read_image() call. - -If you are doing this just one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - png_read_row(png_ptr, row_pointer, NULL); - -If the file is interlaced (interlace_type != 0 in the IHDR chunk), things -get somewhat harder. The only current (PNG Specification version 1.2) -interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) -is a somewhat complicated 2D interlace scheme, known as Adam7, that -breaks down an image into seven smaller images of varying size, based -on an 8x8 grid. - -libpng can fill out those images or it can give them to you "as is". -If you want them filled out, there are two ways to do that. The one -mentioned in the PNG specification is to expand each pixel to cover -those pixels that have not been read yet (the "rectangle" method). -This results in a blocky image for the first pass, which gradually -smooths out as more pixels are read. The other method is the "sparkle" -method, where pixels are drawn only in their final locations, with the -rest of the image remaining whatever colors they were initialized to -before the start of the read. The first method usually looks better, -but tends to be slower, as there are more pixels to put in the rows. - -If you don't want libpng to handle the interlacing details, just call -png_read_rows() seven times to read in all seven images. Each of the -images is a valid image by itself, or they can all be combined on an -8x8 grid to form a single image (although if you intend to combine them -you would be far better off using the libpng interlace handling). - -The first pass will return an image 1/8 as wide as the entire image -(every 8th column starting in column 0) and 1/8 as high as the original -(every 8th row starting in row 0), the second will be 1/8 as wide -(starting in column 4) and 1/8 as high (also starting in row 0). The -third pass will be 1/4 as wide (every 4th pixel starting in column 0) and -1/8 as high (every 8th row starting in row 4), and the fourth pass will -be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, -and every 4th row starting in row 0). The fifth pass will return an -image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), -while the sixth pass will be 1/2 as wide and 1/2 as high as the original -(starting in column 1 and row 0). The seventh and final pass will be as -wide as the original, and 1/2 as high, containing all of the odd -numbered scanlines. Phew! - -If you want libpng to expand the images, call this before calling -png_start_read_image() or png_read_update_info(): - - if (interlace_type == PNG_INTERLACE_ADAM7) - number_of_passes - = png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this -is seven, but may change if another interlace type is added. -This function can be called even if the file is not interlaced, -where it will return one pass. - -If you are not going to display the image after each pass, but are -going to wait until the entire image is read in, use the sparkle -effect. This effect is faster and the end result of either method -is exactly the same. If you are planning on displaying the image -after each pass, the "rectangle" effect is generally considered the -better looking one. - -If you only want the "sparkle" effect, just call png_read_rows() as -normal, with the third parameter NULL. Make sure you make pass over -the image number_of_passes times, and you don't change the data in the -rows between calls. You can change the locations of the data, just -not the data. Each pass only writes the pixels appropriate for that -pass, and assumes the data from previous passes is still valid. - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -If you only want the first effect (the rectangles), do the same as -before except pass the row buffer in the third parameter, and leave -the second parameter NULL. - - png_read_rows(png_ptr, NULL, row_pointers, - number_of_rows); - -Finishing a sequential read - -After you are finished reading the image through the -low-level interface, you can finish reading the file. If you are -interested in comments or time, which may be stored either before or -after the image data, you should pass the separate png_info struct if -you want to keep the comments from before and after the image -separate. If you are not interested, you can pass NULL. - - png_read_end(png_ptr, end_info); - -When you are done, you can free all memory allocated by libpng like this: - - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. -The "seq" parameter is ignored if only one item of the selected data -type, such as PLTE, is allowed. If "seq" is not -1, and multiple items -are allowed for the data type identified in the mask, such as text or -sPLT, only the n'th item in the structure is freed, where n is "seq". - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -This function only affects data that has already been allocated. -You can call this function after reading the PNG data but before calling -any png_set_*() functions, to control whether the user or the png_set_*() -function is responsible for freeing any existing data that might be present, -and again after the png_set_*() functions to control whether the user -or png_destroy_*() is supposed to free the data. When the user assumes -responsibility for libpng-allocated data, the application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated your row_pointers in a single block, as suggested above in -the description of the high level read interface, you must not transfer -responsibility for freeing it to the png_set_rows or png_read_destroy function, -because they would also try to free the individual row_pointers[i]. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. - -The png_free_data() function will turn off the "valid" flag for anything -it frees. If you need to turn the flag off for a chunk that was freed by -your application instead of by libpng, you can use - - png_set_invalid(png_ptr, info_ptr, mask); - mask - identifies the chunks to be made invalid, - containing the bitwise OR of one or - more of - PNG_INFO_gAMA, PNG_INFO_sBIT, - PNG_INFO_cHRM, PNG_INFO_PLTE, - PNG_INFO_tRNS, PNG_INFO_bKGD, - PNG_INFO_hIST, PNG_INFO_pHYs, - PNG_INFO_oFFs, PNG_INFO_tIME, - PNG_INFO_pCAL, PNG_INFO_sRGB, - PNG_INFO_iCCP, PNG_INFO_sPLT, - PNG_INFO_sCAL, PNG_INFO_IDAT - -For a more compact example of reading a PNG image, see the file example.c. - -Reading PNG files progressively - -The progressive reader is slightly different then the non-progressive -reader. Instead of calling png_read_info(), png_read_rows(), and -png_read_end(), you make one call to png_process_data(), which calls -callbacks when it has the info, a row, or the end of the image. You -set up these callbacks with png_set_progressive_read_fn(). You don't -have to worry about the input/output functions of libpng, as you are -giving the library the data directly in png_process_data(). I will -assume that you have read the section on reading PNG files above, -so I will only highlight the differences (although I will show -all of the code). - -png_structp png_ptr; -png_infop info_ptr; - - /* An example code fragment of how you would - initialize the progressive reader in your - application. */ - int - initialize_png_reader() - { - png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, - (png_infopp)NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new. You can provide functions - to be called when the header info is valid, - when each row is completed, and when the image - is finished. If you aren't using all functions, - you can specify NULL parameters. Even when all - three functions are NULL, you need to call - png_set_progressive_read_fn(). You can use - any struct as the user_ptr (cast to a void pointer - for the function call), and retrieve the pointer - from inside the callbacks using the function - - png_get_progressive_ptr(png_ptr); - - which will return a void pointer, which you have - to cast appropriately. - */ - png_set_progressive_read_fn(png_ptr, (void *)user_ptr, - info_callback, row_callback, end_callback); - - return 0; - } - - /* A code fragment that you call as you receive blocks - of data */ - int - process_data(png_bytep buffer, png_uint_32 length) - { - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new also. Simply give it a chunk - of data from the file stream (in order, of - course). On machines with segmented memory - models machines, don't give it any more than - 64K. The library seems to run fine with sizes - of 4K. Although you can give it much less if - necessary (I assume you can give it chunks of - 1 byte, I haven't tried less then 256 bytes - yet). When this function returns, you may - want to display any rows that were generated - in the row callback if you don't already do - so there. - */ - png_process_data(png_ptr, info_ptr, buffer, length); - return 0; - } - - /* This function is called (as set by - png_set_progressive_read_fn() above) when enough data - has been supplied so all of the header has been - read. - */ - void - info_callback(png_structp png_ptr, png_infop info) - { - /* Do any setup here, including setting any of - the transformations mentioned in the Reading - PNG files section. For now, you _must_ call - either png_start_read_image() or - png_read_update_info() after all the - transformations are set (even if you don't set - any). You may start getting rows before - png_process_data() returns, so this is your - last chance to prepare for that. - */ - } - - /* This function is called when each row of image - data is complete */ - void - row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) - { - /* If the image is interlaced, and you turned - on the interlace handler, this function will - be called for every row in every pass. Some - of these rows will not be changed from the - previous pass. When the row is not changed, - the new_row variable will be NULL. The rows - and passes are called in order, so you don't - really need the row_num and pass, but I'm - supplying them because it may make your life - easier. - - For the non-NULL rows of interlaced images, - you must call png_progressive_combine_row() - passing in the row and the old row. You can - call this function for NULL rows (it will just - return) and for non-interlaced images (it just - does the memcpy for you) if it will make the - code easier. Thus, you can just do this for - all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, - new_row); - - /* where old_row is what was displayed for - previously for the row. Note that the first - pass (pass == 0, really) will completely cover - the old row, so the rows do not have to be - initialized. After the first pass (and only - for interlaced images), you will have to pass - the current row, and the function will combine - the old row and the new row. - */ - } - - void - end_callback(png_structp png_ptr, png_infop info) - { - /* This function is called after the whole image - has been read, including any chunks after the - image (up to and including the IEND). You - will usually have the same info chunk as you - had in the header, although some data may have - been added to the comments and time fields. - - Most people won't do much here, perhaps setting - a flag that marks the image as finished. - */ - } - - - -IV. Writing - -Much of this is very similar to reading. However, everything of -importance is repeated here, so you won't have to constantly look -back up in the reading section to understand writing. - -Setup - -You will want to do the I/O initialization before you get into libpng, -so if it doesn't work, you don't have anything to undo. If you are not -using the standard I/O functions, you will need to replace them with -custom writing functions. See the discussion under Customizing libpng. - - FILE *fp = fopen(file_name, "wb"); - if (!fp) - { - return (ERROR); - } - -Next, png_struct and png_info need to be allocated and initialized. -As these can be both relatively large, you may not want to store these -on the stack, unless you have stack space to spare. Of course, you -will want to check if they return NULL. If you are also reading, -you won't want to name your read structure and your write structure -both "png_ptr"; you can call them anything you like, such as -"read_ptr" and "write_ptr". Look at pngtest.c, for example. - - png_structp png_ptr = png_create_write_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_write_struct(&png_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_write_struct_2() instead of png_create_write_struct(): - - png_structp png_ptr = png_create_write_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -After you have these structures, you will need to set up the -error handling. When libpng encounters an error, it expects to -longjmp() back to your routine. Therefore, you will need to call -setjmp() and pass the png_jmpbuf(png_ptr). If you -write the file from different routines, you will need to update -the png_jmpbuf(png_ptr) every time you enter a new routine that will -call a png_*() function. See your documentation of setjmp/longjmp -for your compiler for more information on setjmp/longjmp. See -the discussion on libpng error handling in the Customizing Libpng -section below for more information on the libpng error handling. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return (ERROR); - } - ... - return; - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the output code. The default for libpng is to -use the C function fwrite(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. Again, if you wish to handle writing data in -another way, see the discussion on libpng I/O handling in the Customizing -Libpng section below. - - png_init_io(png_ptr, fp); - -If you are embedding your PNG into a datastream such as MNG, and don't -want libpng to write the 8-byte signature, or if you have already -written the signature in your application, use - - png_set_sig_bytes(png_ptr, 8); - -to inform libpng that it should not write a signature. - -Write callbacks - -At this point, you can set up a callback function that will be -called after each row has been written, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void write_row_callback(png_ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "write_row_callback") - -To inform libpng about your function, use - - png_set_write_status_fn(png_ptr, write_row_callback); - -You now have the option of modifying how the compression library will -run. The following functions are mainly for testing, but may be useful -in some cases, like if you need to write PNG files extremely fast and -are willing to give up some compression, or if you want to get the -maximum possible compression at the expense of slower writing. If you -have no special needs in this area, let the library do what it wants by -not calling this function at all, as it has been tuned to deliver a good -speed/compression ratio. The second parameter to png_set_filter() is -the filter method, for which the only valid values are 0 (as of the -July 1999 PNG specification, version 1.2) or 64 (if you are writing -a PNG datastream that is to be embedded in a MNG datastream). The third -parameter is a flag that indicates which filter type(s) are to be tested -for each scanline. See the PNG specification for details on the specific -filter types. - - - /* turn on or off filtering, and/or choose - specific filters. You can use either a single - PNG_FILTER_VALUE_NAME or the bitwise OR of one - or more PNG_FILTER_NAME masks. */ - png_set_filter(png_ptr, 0, - PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | - PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | - PNG_FILTER_UP | PNG_FILTER_VALUE_UP | - PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | - PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| - PNG_ALL_FILTERS); - -If an application -wants to start and stop using particular filters during compression, -it should start out with all of the filters (to ensure that the previous -row of pixels will be stored in case it's needed later), and then add -and remove them after the start of compression. - -If you are writing a PNG datastream that is to be embedded in a MNG -datastream, the second parameter can be either 0 or 64. - -The png_set_compression_*() functions interface to the zlib compression -library, and should mostly be ignored unless you really know what you are -doing. The only generally useful call is png_set_compression_level() -which changes how much time zlib spends on trying to compress the image -data. See the Compression Library (zlib.h and algorithm.txt, distributed -with zlib) for details on the compression levels. - - /* set the zlib compression level */ - png_set_compression_level(png_ptr, - Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr, - Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192) - -extern PNG_EXPORT(void,png_set_zbuf_size) - -Setting the contents of info for output - -You now need to fill in the png_info structure with all the data you -wish to write before the actual image. Note that the only thing you -are allowed to write after the image is the text chunks and the time -chunk (as of PNG Specification 1.2, anyway). See png_write_end() and -the latest PNG specification for more information on that. If you -wish to write them before the image, fill them in now, and flag that -data as being valid. If you want to wait until after the data, don't -fill them until png_write_end(). For all the fields in png_info and -their data types, see png.h. For explanations of what the fields -contain, see the PNG specification. - -Some of the more important parts of the png_info are: - - png_set_IHDR(png_ptr, info_ptr, width, height, - bit_depth, color_type, interlace_type, - compression_type, filter_method) - width - holds the width of the image - in pixels (up to 2^31). - height - holds the height of the image - in pixels (up to 2^31). - bit_depth - holds the bit depth of one of the - image channels. - (valid values are 1, 2, 4, 8, 16 - and depend also on the - color_type. See also significant - bits (sBIT) below). - color_type - describes which color/alpha - channels are present. - PNG_COLOR_TYPE_GRAY - (bit depths 1, 2, 4, 8, 16) - PNG_COLOR_TYPE_GRAY_ALPHA - (bit depths 8, 16) - PNG_COLOR_TYPE_PALETTE - (bit depths 1, 2, 4, 8) - PNG_COLOR_TYPE_RGB - (bit_depths 8, 16) - PNG_COLOR_TYPE_RGB_ALPHA - (bit_depths 8, 16) - - PNG_COLOR_MASK_PALETTE - PNG_COLOR_MASK_COLOR - PNG_COLOR_MASK_ALPHA - - interlace_type - PNG_INTERLACE_NONE or - PNG_INTERLACE_ADAM7 - compression_type - (must be - PNG_COMPRESSION_TYPE_DEFAULT) - filter_method - (must be PNG_FILTER_TYPE_DEFAULT - or, if you are writing a PNG to - be embedded in a MNG datastream, - can also be - PNG_INTRAPIXEL_DIFFERENCING) - -If you call png_set_IHDR(), the call must appear before any of the -other png_set_*() functions, because they might require access to some of -the IHDR settings. The remaining png_set_*() functions can be called -in any order. - -If you wish, you can reset the compression_type, interlace_type, or -filter_method later by calling png_set_IHDR() again; if you do this, the -width, height, bit_depth, and color_type must be the same in each call. - - png_set_PLTE(png_ptr, info_ptr, palette, - num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_set_gAMA(png_ptr, info_ptr, gamma); - gamma - the gamma the image was created - at (PNG_INFO_gAMA) - - png_set_sRGB(png_ptr, info_ptr, srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of - the sRGB chunk means that the pixel - data is in the sRGB color space. - This chunk also implies specific - values of gAMA and cHRM. Rendering - intent is the CSS-1 property that - has been defined by the International - Color Consortium - (http://www.color.org). - It can be one of - PNG_sRGB_INTENT_SATURATION, - PNG_sRGB_INTENT_PERCEPTUAL, - PNG_sRGB_INTENT_ABSOLUTE, or - PNG_sRGB_INTENT_RELATIVE. - - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, - srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of the - sRGB chunk means that the pixel - data is in the sRGB color space. - This function also causes gAMA and - cHRM chunks with the specific values - that are consistent with sRGB to be - written. - - png_set_iCCP(png_ptr, info_ptr, name, compression_type, - profile, proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_set_sBIT(png_ptr, info_ptr, sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, red, - green, and blue channels, whichever are - appropriate for the given color type - (png_color_16) - - png_set_tRNS(png_ptr, info_ptr, trans, num_trans, - trans_values); - trans - array of transparent - entries for palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values - (in order red, green, blue) of the - single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_set_hIST(png_ptr, info_ptr, hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_set_tIME(png_ptr, info_ptr, mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_set_bKGD(png_ptr, info_ptr, background); - background - background color (PNG_VALID_bKGD) - - png_set_text(png_ptr, info_ptr, text_ptr, num_text); - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be NULL or empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (NULL or - empty for unknown). - text_ptr[i].translated_keyword - keyword in UTF-8 (NULL - or empty for unknown). - Note that the itxt_length, lang, and lang_key - members of the text_ptr structure only exist - when the library is built with iTXt chunk support. - - num_text - number of comments - - png_set_sPLT(png_ptr, info_ptr, &palette_ptr, - num_spalettes); - palette_ptr - array of png_sPLT_struct structures - to be added to the list of palettes - in the info structure. - num_spalettes - number of palette structures to be - added. - - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, - unit_type); - offset_x - positive offset from the left - edge of the screen - offset_y - positive offset from the top - edge of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, - unit_type); - res_x - pixels/unit physical resolution - in x direction - res_y - pixels/unit physical resolution - in y direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_set_sCAL(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, - num_unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position to write chunk in file - 0: do not write chunk - PNG_HAVE_IHDR: before PLTE - PNG_HAVE_PLTE: before IDAT - PNG_AFTER_IDAT: after IDAT - -The "location" member is set automatically according to -what part of the output file has already been written. -You can change its value after calling png_set_unknown_chunks() -as demonstrated in pngtest.c. Within each of the "locations", -the chunks are sequenced according to their position in the -structure (that is, the value of "i", which is the order in which -the chunk was either read from the input file or defined with -png_set_unknown_chunks). - -A quick word about text and num_text. text is an array of png_text -structures. num_text is the number of valid structures in the array. -Each png_text structure holds a language code, a keyword, a text value, -and a compression type. - -The compression types have the same valid numbers as the compression -types of the image data. Currently, the only valid number is zero. -However, you can store text either compressed or uncompressed, unlike -images, which always have to be compressed. So if you don't want the -text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. -Because tEXt and zTXt chunks don't have a language field, if you -specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt -any language code or translated keyword will not be written out. - -Until text gets around 1000 bytes, it is not worth compressing it. -After the text has been written out to the file, the compression type -is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, -so that it isn't written out again at the end (in case you are calling -png_write_end() with the same struct. - -The keywords that are given in the PNG Specification are: - - Title Short (one line) title or - caption for image - Author Name of image's creator - Description Description of image (possibly long) - Copyright Copyright notice - Creation Time Time of original image creation - (usually RFC 1123 format, see below) - Software Software used to create the image - Disclaimer Legal disclaimer - Warning Warning of nature of content - Source Device used to create the image - Comment Miscellaneous comment; conversion - from other image format - -The keyword-text pairs work like this. Keywords should be short -simple descriptions of what the comment is about. Some typical -keywords are found in the PNG specification, as is some recommendations -on keywords. You can repeat keywords in a file. You can even write -some text before the image and some after. For example, you may want -to put a description of the image before the image, but leave the -disclaimer until after, so viewers working over modem connections -don't have to wait for the disclaimer to go over the modem before -they start seeing the image. Finally, keywords should be full -words, not abbreviations. Keywords and text are in the ISO 8859-1 -(Latin-1) character set (a superset of regular ASCII) and can not -contain NUL characters, and should not contain control or other -unprintable characters. To make the comments widely readable, stick -with basic ASCII, and avoid machine specific character set extensions -like the IBM-PC character set. The keyword must be present, but -you can leave off the text string on non-compressed pairs. -Compressed pairs must have a text string, as only the text string -is compressed anyway, so the compression would be meaningless. - -PNG supports modification time via the png_time structure. Two -conversion routines are provided, png_convert_from_time_t() for -time_t and png_convert_from_struct_tm() for struct tm. The -time_t routine uses gmtime(). You don't have to use either of -these, but if you wish to fill in the png_time structure directly, -you should provide the time in universal time (GMT) if possible -instead of your local time. Note that the year number is the full -year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and -that months start with 1. - -If you want to store the time of the original image creation, you should -use a plain tEXt chunk with the "Creation Time" keyword. This is -necessary because the "creation time" of a PNG image is somewhat vague, -depending on whether you mean the PNG file, the time the image was -created in a non-PNG format, a still photo from which the image was -scanned, or possibly the subject matter itself. In order to facilitate -machine-readable dates, it is recommended that the "Creation Time" -tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), -although this isn't a requirement. Unlike the tIME chunk, the -"Creation Time" tEXt chunk is not expected to be automatically changed -by the software. To facilitate the use of RFC 1123 dates, a function -png_convert_to_rfc1123(png_timep) is provided to convert from PNG -time to an RFC 1123 format string. - -Writing unknown chunks - -You can use the png_set_unknown_chunks function to queue up chunks -for writing. You give it a chunk name, raw data, and a size; that's -all there is to it. The chunks will be written by the next following -png_write_info_before_PLTE, png_write_info, or png_write_end function. -Any chunks previously read into the info structure's unknown-chunk -list will also be written out in a sequence that satisfies the PNG -specification's ordering rules. - -The high-level write interface - -At this point there are two ways to proceed; through the high-level -write interface, or through a sequence of low-level write operations. -You can use the high-level interface if your image data is present -in the info structure. All defined output -transformations are permitted, enabled by the following masks. - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - PNG_TRANSFORM_STRIP_FILLER Strip out filler - bytes (deprecated). - PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading - filler bytes - PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing - filler bytes - -If you have valid image data in the info structure (you can use -png_set_rows() to put image data in the info structure), simply do this: - - png_write_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of some set of -transformation flags. This call is equivalent to png_write_info(), -followed the set of transformations indicated by the transform mask, -then png_write_image(), and finally png_write_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future output transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_write_png(). - -The low-level write interface - -If you are going the low-level route instead, you are now ready to -write all the file information up to the actual image data. You do -this with a call to png_write_info(). - - png_write_info(png_ptr, info_ptr); - -Note that there is one transformation you may need to do before -png_write_info(). In PNG files, the alpha channel in an image is the -level of opacity. If your data is supplied as a level of transparency, -you can invert the alpha channel before you write it, so that 0 is -fully transparent and 255 (in 8-bit or paletted images) or 65535 -(in 16-bit images) is fully opaque, with - - png_set_invert_alpha(png_ptr); - -This must appear before png_write_info() instead of later with the -other transformations because in the case of paletted images the tRNS -chunk data has to be inverted before the tRNS chunk is written. If -your image is not a paletted image, the tRNS data (which in such cases -represents a single color to be rendered as transparent) won't need to -be changed, and you can safely do this transformation after your -png_write_info() call. - -If you need to write a private chunk that you want to appear before -the PLTE chunk when PLTE is present, you can write the PNG info in -two steps, and insert code to write your own chunk between them: - - png_write_info_before_PLTE(png_ptr, info_ptr); - png_set_unknown_chunks(png_ptr, info_ptr, ...); - png_write_info(png_ptr, info_ptr); - -After you've written the file information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -PNG files store RGB pixels packed into 3 or 6 bytes. This code tells -the library to strip input data that has 4 or 8 bytes per pixel down -to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 -bytes per pixel). - - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - -where the 0 is unused, and the location is either PNG_FILLER_BEFORE or -PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel -is stored XRGB or RGBX. - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit files. -If the data is supplied at 1 pixel per byte, use this code, which will -correctly pack the pixels into a single byte: - - png_set_packing(png_ptr); - -PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your -data is of another bit depth, you can write an sBIT chunk into the -file so that decoders can recover the original data if desired. - - /* Set the true bit depth of the image data */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit.red = true_bit_depth; - sig_bit.green = true_bit_depth; - sig_bit.blue = true_bit_depth; - } - else - { - sig_bit.gray = true_bit_depth; - } - if (color_type & PNG_COLOR_MASK_ALPHA) - { - sig_bit.alpha = true_bit_depth; - } - - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - -If the data is stored in the row buffer in a bit depth other than -one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), -this will scale the values to appear to be the correct bit depth as -is required by PNG. - - png_set_shift(png_ptr, &sig_bit); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code would be used if they are -supplied the other way (little-endian, i.e. least significant bits -first, the way PCs store them): - - if (bit_depth > 8) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -PNG files store 3 color pixels in red, green, blue order. This code -would be used if they are supplied as blue, green, red: - - png_set_bgr(png_ptr); - -PNG files describe monochrome as black being zero and white being -one. This code would be used if the pixels are supplied with this reversed -(black being one and white being zero): - - png_set_invert_mono(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_write_user_transform_fn(png_ptr, - write_transform_fn); - -You must supply the function - - void write_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -before any of the other transformations are processed. - -You can also set up a pointer to a user structure for use by your -callback function. - - png_set_user_transform_info(png_ptr, user_ptr, 0, 0); - -The user_channels and user_depth parameters of this function are ignored -when writing; you can set them to zero as shown. - -You can retrieve the pointer via the function png_get_user_transform_ptr(). -For example: - - voidp write_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -It is possible to have libpng flush any pending output, either manually, -or automatically after a certain number of lines have been written. To -flush the output stream a single time call: - - png_write_flush(png_ptr); - -and to have libpng flush the output stream periodically after a certain -number of scanlines have been written, call: - - png_set_flush(png_ptr, nrows); - -Note that the distance between rows is from the last time png_write_flush() -was called, or the first row of the image if it has never been called. -So if you write 50 lines, and then png_set_flush 25, it will flush the -output on the next scanline, and every 25 lines thereafter, unless -png_write_flush() is called before 25 more lines have been written. -If nrows is too small (less than about 10 lines for a 640 pixel wide -RGB image) the image compression may decrease noticeably (although this -may be acceptable for real-time applications). Infrequent flushing will -only degrade the compression performance by a few percent over images -that do not use flushing. - -Writing the image data - -That's it for the transformations. Now you can write the image data. -The simplest way to do this is in one function call. If you have the -whole image in memory, you can just call png_write_image() and libpng -will write the image. You will need to pass in an array of pointers to -each row. This function automatically handles interlacing, so you don't -need to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_write_rows(). - - png_write_image(png_ptr, row_pointers); - -where row_pointers is: - - png_byte *row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to write the whole image at once, you can -use png_write_rows() instead. If the file is not interlaced, -this is simple: - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -row_pointers is the same as in the png_write_image() call. - -If you are just writing one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - - png_write_row(png_ptr, row_pointer); - -When the file is interlaced, things can get a good deal more complicated. -The only currently (as of the PNG Specification version 1.2, dated July -1999) defined interlacing scheme for PNG files is the "Adam7" interlace -scheme, that breaks down an image into seven smaller images of varying -size. libpng will build these images for you, or you can do them -yourself. If you want to build them yourself, see the PNG specification -for details of which pixels to write when. - -If you don't want libpng to handle the interlacing details, just -use png_set_interlace_handling() and call png_write_rows() the -correct number of times to write all seven sub-images. - -If you want libpng to build the sub-images, call this before you start -writing any rows: - - number_of_passes = - png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this is seven, -but may change if another interlace type is added. - -Then write the complete image number_of_passes times. - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -As some of these rows are not used, and thus return immediately, you may -want to read about interlacing in the PNG specification, and only update -the rows that are actually used. - -Finishing a sequential write - -After you are finished writing the image, you should finish writing -the file. If you are interested in writing comments or time, you should -pass an appropriately filled png_info pointer. If you are not interested, -you can pass NULL. - - png_write_end(png_ptr, info_ptr); - -When you are done, you can free all memory used by libpng like this: - - png_destroy_write_struct(&png_ptr, &info_ptr); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. -The "seq" parameter is ignored if only one item of the selected data -type, such as PLTE, is allowed. If "seq" is not -1, and multiple items -are allowed for the data type identified in the mask, such as text or -sPLT, only the n'th item in the structure is freed, where n is "seq". - -If you allocated data such as a palette that you passed in to libpng -with png_set_*, you must not free it until just before the call to -png_destroy_write_struct(). - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -For example, to transfer responsibility for some data from a read structure -to a write structure, you could use - - png_data_freer(read_ptr, read_info_ptr, - PNG_USER_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - png_data_freer(write_ptr, write_info_ptr, - PNG_DESTROY_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - -thereby briefly reassigning responsibility for freeing to the user but -immediately afterwards reassigning it once more to the write_destroy -function. Having done this, it would then be safe to destroy the read -structure and continue to use the PLTE, tRNS, and hIST data in the write -structure. - -This function only affects data that has already been allocated. -You can call this function before calling after the png_set_*() functions -to control whether the user or png_destroy_*() is supposed to free the data. -When the user assumes responsibility for libpng-allocated data, the -application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. -For a more compact example of writing a PNG image, see the file example.c. - -V. Modifying/Customizing libpng: - -There are two issues here. The first is changing how libpng does -standard things like memory allocation, input/output, and error handling. -The second deals with more complicated things like adding new chunks, -adding new transformations, and generally changing how libpng works. -Both of those are compile-time issues; that is, they are generally -determined at the time the code is written, and there is rarely a need -to provide the user with a means of changing them. - -Memory allocation, input/output, and error handling - -All of the memory allocation, input/output, and error handling in libpng -goes through callbacks that are user-settable. The default routines are -in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change -these functions, call the appropriate png_set_*_fn() function. - -Memory allocation is done through the functions png_malloc(), png_calloc(), -and png_free(). These currently just call the standard C functions. -png_calloc() calls png_malloc() and then png_memset() to clear the newly -allocated memory to zero. If your pointers can't access more then 64K -at a time, you will want to set MAXSEG_64K in zlib.h. Since it is -unlikely that the method of handling memory allocation on a platform -will change between applications, these functions must be modified in -the library at compile time. If you prefer to use a different method -of allocating and freeing data, you can use png_create_read_struct_2() or -png_create_write_struct_2() to register your own functions as described -above. These functions also provide a void pointer that can be retrieved -via - - mem_ptr=png_get_mem_ptr(png_ptr); - -Your replacement memory functions must have prototypes as follows: - - png_voidp malloc_fn(png_structp png_ptr, - png_size_t size); - void free_fn(png_structp png_ptr, png_voidp ptr); - -Your malloc_fn() must return NULL in case of failure. The png_malloc() -function will normally call png_error() if it receives a NULL from the -system memory allocator or from your replacement malloc_fn(). - -Your free_fn() will never be called with a NULL ptr, since libpng's -png_free() checks for NULL before calling free_fn(). - -Input/Output in libpng is done through png_read() and png_write(), -which currently just call fread() and fwrite(). The FILE * is stored in -png_struct and is initialized via png_init_io(). If you wish to change -the method of I/O, the library supplies callbacks that you can set -through the function png_set_read_fn() and png_set_write_fn() at run -time, instead of calling the png_init_io() function. These functions -also provide a void pointer that can be retrieved via the function -png_get_io_ptr(). For example: - - png_set_read_fn(png_structp read_ptr, - voidp read_io_ptr, png_rw_ptr read_data_fn) - - png_set_write_fn(png_structp write_ptr, - voidp write_io_ptr, png_rw_ptr write_data_fn, - png_flush_ptr output_flush_fn); - - voidp read_io_ptr = png_get_io_ptr(read_ptr); - voidp write_io_ptr = png_get_io_ptr(write_ptr); - -The replacement I/O functions must have prototypes as follows: - - void user_read_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_write_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_flush_data(png_structp png_ptr); - -The user_read_data() function is responsible for detecting and -handling end-of-data errors. - -Supplying NULL for the read, write, or flush functions sets them back -to using the default C stream functions, which expect the io_ptr to -point to a standard *FILE structure. It is probably a mistake -to use NULL for one of write_data_fn and output_flush_fn but not both -of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. -It is an error to read from a write stream, and vice versa. - -Error handling in libpng is done through png_error() and png_warning(). -Errors handled through png_error() are fatal, meaning that png_error() -should never return to its caller. Currently, this is handled via -setjmp() and longjmp() (unless you have compiled libpng with -PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), -but you could change this to do things like exit() if you should wish. - -On non-fatal errors, png_warning() is called -to print a warning message, and then control returns to the calling code. -By default png_error() and png_warning() print a message on stderr via -fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined -(because you don't want the messages) or PNG_NO_STDIO defined (because -fprintf() isn't available). If you wish to change the behavior of the error -functions, you will need to set up your own message callbacks. These -functions are normally supplied at the time that the png_struct is created. -It is also possible to redirect errors and warnings to your own replacement -functions after png_create_*_struct() has been called by calling: - - png_set_error_fn(png_structp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warning_fn); - - png_voidp error_ptr = png_get_error_ptr(png_ptr); - -If NULL is supplied for either error_fn or warning_fn, then the libpng -default function will be used, calling fprintf() and/or longjmp() if a -problem is encountered. The replacement error functions should have -parameters as follows: - - void user_error_fn(png_structp png_ptr, - png_const_charp error_msg); - void user_warning_fn(png_structp png_ptr, - png_const_charp warning_msg); - -The motivation behind using setjmp() and longjmp() is the C++ throw and -catch exception handling methods. This makes the code much easier to write, -as there is no need to check every return code of every function call. -However, there are some uncertainties about the status of local variables -after a longjmp, so the user may want to be careful about doing anything -after setjmp returns non-zero besides returning itself. Consult your -compiler documentation for more details. For an alternative approach, you -may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net). - -Custom chunks - -If you need to read or write custom chunks, you may need to get deeper -into the libpng code. The library now has mechanisms for storing -and writing chunks of unknown type; you can even declare callbacks -for custom chunks. However, this may not be good enough if the -library code itself needs to know about interactions between your -chunk and existing `intrinsic' chunks. - -If you need to write a new intrinsic chunk, first read the PNG -specification. Acquire a first level of understanding of how it works. -Pay particular attention to the sections that describe chunk names, -and look at how other chunks were designed, so you can do things -similarly. Second, check out the sections of libpng that read and -write chunks. Try to find a chunk that is similar to yours and use -it as a template. More details can be found in the comments inside -the code. It is best to handle unknown chunks in a generic method, -via callback functions, instead of by modifying libpng functions. - -If you wish to write your own transformation for the data, look through -the part of the code that does the transformations, and check out some of -the simpler ones to get an idea of how they work. Try to find a similar -transformation to the one you want to add and copy off of it. More details -can be found in the comments inside the code itself. - -Configuring for 16 bit platforms - -You will want to look into zconf.h to tell zlib (and thus libpng) that -it cannot allocate more then 64K at a time. Even if you can, the memory -won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. - -Configuring for DOS - -For DOS users who only have access to the lower 640K, you will -have to limit zlib's memory usage via a png_set_compression_mem_level() -call. See zlib.h or zconf.h in the zlib library for more information. - -Configuring for Medium Model - -Libpng's support for medium model has been tested on most of the popular -compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets -defined, and FAR gets defined to far in pngconf.h, and you should be -all set. Everything in the library (except for zlib's structure) is -expecting far data. You must use the typedefs with the p or pp on -the end for pointers (or at least look at them and be careful). Make -note that the rows of data are defined as png_bytepp, which is an -unsigned char far * far *. - -Configuring for gui/windowing platforms: - -You will need to write new error and warning functions that use the GUI -interface, as described previously, and set them to be the error and -warning functions at the time that png_create_*_struct() is called, -in order to have them available during the structure initialization. -They can be changed later via png_set_error_fn(). On some compilers, -you may also have to change the memory allocators (png_malloc, etc.). - -Configuring for compiler xxx: - -All includes for libpng are in pngconf.h. If you need to add, change -or delete an include, this is the place to do it. -The includes that are not needed outside libpng are protected by the -PNG_INTERNAL definition, which is only defined for those routines inside -libpng itself. The files in libpng proper only include png.h, which -includes pngconf.h. - -Configuring zlib: - -There are special functions to configure the compression. Perhaps the -most useful one changes the compression level, which currently uses -input compression values in the range 0 - 9. The library normally -uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests -have shown that for a large majority of images, compression values in -the range 3-6 compress nearly as well as higher levels, and do so much -faster. For online applications it may be desirable to have maximum speed -(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also -specify no compression (Z_NO_COMPRESSION = 0), but this would create -files larger than just storing the raw bitmap. You can specify the -compression level by calling: - - png_set_compression_level(png_ptr, level); - -Another useful one is to reduce the memory level used by the library. -The memory level defaults to 8, but it can be lowered if you are -short on memory (running DOS, for example, where you only have 640K). -Note that the memory level does have an effect on compression; among -other things, lower levels will result in sections of incompressible -data being emitted in smaller stored blocks, with a correspondingly -larger relative overhead of up to 15% in the worst case. - - png_set_compression_mem_level(png_ptr, level); - -The other functions are for configuring zlib. They are not recommended -for normal use and may result in writing an invalid PNG file. See -zlib.h for more information on what these mean. - - png_set_compression_strategy(png_ptr, - strategy); - png_set_compression_window_bits(png_ptr, - window_bits); - png_set_compression_method(png_ptr, method); - png_set_compression_buffer_size(png_ptr, size); - -Controlling row filtering - -If you want to control whether libpng uses filtering or not, which -filters are used, and how it goes about picking row filters, you -can call one of these functions. The selection and configuration -of row filters can have a significant impact on the size and -encoding speed and a somewhat lesser impact on the decoding speed -of an image. Filtering is enabled by default for RGB and grayscale -images (with and without alpha), but not for paletted images nor -for any images with bit depths less than 8 bits/pixel. - -The 'method' parameter sets the main filtering method, which is -currently only '0' in the PNG 1.2 specification. The 'filters' -parameter sets which filter(s), if any, should be used for each -scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS -to turn filtering on and off, respectively. - -Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, -PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise -ORed together with '|' to specify one or more filters to use. -These filters are described in more detail in the PNG specification. -If you intend to change the filter type during the course of writing -the image, you should start with flags set for all of the filters -you intend to use so that libpng can initialize its internal -structures appropriately for all of the filter types. (Note that this -means the first row must always be adaptively filtered, because libpng -currently does not allocate the filter buffers until png_write_row() -is called for the first time.) - - filters = PNG_FILTER_NONE | PNG_FILTER_SUB - PNG_FILTER_UP | PNG_FILTER_AVG | - PNG_FILTER_PAETH | PNG_ALL_FILTERS; - - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, - filters); - The second parameter can also be - PNG_INTRAPIXEL_DIFFERENCING if you are - writing a PNG to be embedded in a MNG - datastream. This parameter must be the - same as the value of filter_method used - in png_set_IHDR(). - -It is also possible to influence how libpng chooses from among the -available filters. This is done in one or both of two ways - by -telling it how important it is to keep the same filter for successive -rows, and by telling it the relative computational costs of the filters. - - double weights[3] = {1.5, 1.3, 1.1}, - costs[PNG_FILTER_VALUE_LAST] = - {1.0, 1.3, 1.3, 1.5, 1.7}; - - png_set_filter_heuristics(png_ptr, - PNG_FILTER_HEURISTIC_WEIGHTED, 3, - weights, costs); - -The weights are multiplying factors that indicate to libpng that the -row filter should be the same for successive rows unless another row filter -is that many times better than the previous filter. In the above example, -if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a -"sum of absolute differences" 1.5 x 1.3 times higher than other filters -and still be chosen, while the NONE filter could have a sum 1.1 times -higher than other filters and still be chosen. Unspecified weights are -taken to be 1.0, and the specified weights should probably be declining -like those above in order to emphasize recent filters over older filters. - -The filter costs specify for each filter type a relative decoding cost -to be considered when selecting row filters. This means that filters -with higher costs are less likely to be chosen over filters with lower -costs, unless their "sum of absolute differences" is that much smaller. -The costs do not necessarily reflect the exact computational speeds of -the various filters, since this would unduly influence the final image -size. - -Note that the numbers above were invented purely for this example and -are given only to help explain the function usage. Little testing has -been done to find optimum values for either the costs or the weights. - -Removing unwanted object code - -There are a bunch of #define's in pngconf.h that control what parts of -libpng are compiled. All the defines end in _SUPPORTED. If you are -never going to use a capability, you can change the #define to #undef -before recompiling libpng and save yourself code and data space, or -you can turn off individual capabilities with defines that begin with -PNG_NO_. - -You can also turn all of the transforms and ancillary chunk capabilities -off en masse with compiler directives that define -PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, -or all four, -along with directives to turn on any of the capabilities that you do -want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the extra -transformations but still leave the library fully capable of reading -and writing PNG files with all known public chunks. Use of the -PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library -that is incapable of reading or writing ancillary chunks. If you are -not using the progressive reading capability, you can turn that off -with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING -capability, which you'll still have). - -All the reading and writing specific code are in separate files, so the -linker should only grab the files it needs. However, if you want to -make sure, or if you are building a stand alone library, all the -reading files start with pngr and all the writing files start with -pngw. The files that don't match either (like png.c, pngtrans.c, etc.) -are used for both reading and writing, and always need to be included. -The progressive reader is in pngpread.c - -If you are creating or distributing a dynamically linked library (a .so -or DLL file), you should not remove or disable any parts of the library, -as this will cause applications linked with different versions of the -library to fail if they call functions not available in your library. -The size of the library itself should not be an issue, because only -those sections that are actually used will be loaded into memory. - -Requesting debug printout - -The macro definition PNG_DEBUG can be used to request debugging -printout. Set it to an integer value in the range 0 to 3. Higher -numbers result in increasing amounts of debugging information. The -information is printed to the "stderr" file, unless another file -name is specified in the PNG_DEBUG_FILE macro definition. - -When PNG_DEBUG > 0, the following functions (macros) become available: - - png_debug(level, message) - png_debug1(level, message, p1) - png_debug2(level, message, p1, p2) - -in which "level" is compared to PNG_DEBUG to decide whether to print -the message, "message" is the formatted string to be printed, -and p1 and p2 are parameters that are to be embedded in the string -according to printf-style formatting directives. For example, - - png_debug1(2, "foo=%d", foo); - -is expanded to - - if(PNG_DEBUG > 2) - fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); - -When PNG_DEBUG is defined but is zero, the macros aren't defined, but you -can still use PNG_DEBUG to control your own debugging: - - #ifdef PNG_DEBUG - fprintf(stderr, ... - #endif - -When PNG_DEBUG = 1, the macros are defined, but only png_debug statements -having level = 0 will be printed. There aren't any such statements in -this version of libpng, but if you insert some they will be printed. - -VI. MNG support - -The MNG specification (available at http://www.libpng.org/pub/mng) allows -certain extensions to PNG for PNG images that are embedded in MNG datastreams. -Libpng can support some of these extensions. To enable them, use the -png_permit_mng_features() function: - - feature_set = png_permit_mng_features(png_ptr, mask) - mask is a png_uint_32 containing the bitwise OR of the - features you want to enable. These include - PNG_FLAG_MNG_EMPTY_PLTE - PNG_FLAG_MNG_FILTER_64 - PNG_ALL_MNG_FEATURES - feature_set is a png_uint_32 that is the bitwise AND of - your mask with the set of MNG features that is - supported by the version of libpng that you are using. - -It is an error to use this function when reading or writing a standalone -PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped -in a MNG datastream. As a minimum, it must have the MNG 8-byte signature -and the MHDR and MEND chunks. Libpng does not provide support for these -or any other MNG chunks; your application must provide its own support for -them. You may wish to consider using libmng (available at -http://www.libmng.com) instead. - -VII. Changes to Libpng from version 0.88 - -It should be noted that versions of libpng later than 0.96 are not -distributed by the original libpng author, Guy Schalnat, nor by -Andreas Dilger, who had taken over from Guy during 1996 and 1997, and -distributed versions 0.89 through 0.96, but rather by another member -of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are -still alive and well, but they have moved on to other things. - -The old libpng functions png_read_init(), png_write_init(), -png_info_init(), png_read_destroy(), and png_write_destroy() have been -moved to PNG_INTERNAL in version 0.95 to discourage their use. These -functions will be removed from libpng version 2.0.0. - -The preferred method of creating and initializing the libpng structures is -via the png_create_read_struct(), png_create_write_struct(), and -png_create_info_struct() because they isolate the size of the structures -from the application, allow version error checking, and also allow the -use of custom error handling routines during the initialization, which -the old functions do not. The functions png_read_destroy() and -png_write_destroy() do not actually free the memory that libpng -allocated for these structs, but just reset the data structures, so they -can be used instead of png_destroy_read_struct() and -png_destroy_write_struct() if you feel there is too much system overhead -allocating and freeing the png_struct for each image read. - -Setting the error callbacks via png_set_message_fn() before -png_read_init() as was suggested in libpng-0.88 is no longer supported -because this caused applications that do not use custom error functions -to fail if the png_ptr was not initialized to zero. It is still possible -to set the error callbacks AFTER png_read_init(), or to change them with -png_set_error_fn(), which is essentially the same function, but with a new -name to force compilation errors with applications that try to use the old -method. - -Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; -however, iTXt support was not enabled by default. - -Starting with version 1.0.7, you can find out which version of the library -you are using at run-time: - - png_uint_32 libpng_vn = png_access_version_number(); - -The number libpng_vn is constructed from the major version, minor -version with leading zero, and release number with leading zero, -(e.g., libpng_vn for version 1.0.7 is 10007). - -You can also check which version of png.h you used when compiling your -application: - - png_uint_32 application_vn = PNG_LIBPNG_VER; - -VIII. Changes to Libpng from version 1.0.x to 1.2.x - -Support for user memory management was enabled by default. To -accomplish this, the functions png_create_read_struct_2(), -png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), -png_malloc_default(), and png_free_default() were added. - -Support for the iTXt chunk has been enabled by default as of -version 1.2.41. - -Support for certain MNG features was enabled. - -Support for numbered error messages was added. However, we never got -around to actually numbering the error messages. The function -png_set_strip_error_numbers() was added (Note: the prototype for this -function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE -builds of libpng-1.2.15. It was restored in libpng-1.2.36). - -The png_malloc_warn() function was added at libpng-1.2.3. This issues -a png_warning and returns NULL instead of aborting when it fails to -acquire the requested memory allocation. - -Support for setting user limits on image width and height was enabled -by default. The functions png_set_user_limits(), png_get_user_width_max(), -and png_get_user_height_max() were added at libpng-1.2.6. - -The png_set_add_alpha() function was added at libpng-1.2.7. - -The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. -Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the -tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is -deprecated. - -A number of macro definitions in support of runtime selection of -assembler code features (especially Intel MMX code support) were -added at libpng-1.2.0: - - PNG_ASM_FLAG_MMX_SUPPORT_COMPILED - PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU - PNG_ASM_FLAG_MMX_READ_COMBINE_ROW - PNG_ASM_FLAG_MMX_READ_INTERLACE - PNG_ASM_FLAG_MMX_READ_FILTER_SUB - PNG_ASM_FLAG_MMX_READ_FILTER_UP - PNG_ASM_FLAG_MMX_READ_FILTER_AVG - PNG_ASM_FLAG_MMX_READ_FILTER_PAETH - PNG_ASM_FLAGS_INITIALIZED - PNG_MMX_READ_FLAGS - PNG_MMX_FLAGS - PNG_MMX_WRITE_FLAGS - PNG_MMX_FLAGS - -We added the following functions in support of runtime -selection of assembler code features: - - png_get_mmx_flagmask() - png_set_mmx_thresholds() - png_get_asm_flags() - png_get_mmx_bitdepth_threshold() - png_get_mmx_rowbytes_threshold() - png_set_asm_flags() - -We replaced all of these functions with simple stubs in libpng-1.2.20, -when the Intel assembler code was removed due to a licensing issue. - -These macros are deprecated: - - PNG_READ_TRANSFORMS_NOT_SUPPORTED - PNG_PROGRESSIVE_READ_NOT_SUPPORTED - PNG_NO_SEQUENTIAL_READ_SUPPORTED - PNG_WRITE_TRANSFORMS_NOT_SUPPORTED - PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED - PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED - -They have been replaced, respectively, by: - - PNG_NO_READ_TRANSFORMS - PNG_NO_PROGRESSIVE_READ - PNG_NO_SEQUENTIAL_READ - PNG_NO_WRITE_TRANSFORMS - PNG_NO_READ_ANCILLARY_CHUNKS - PNG_NO_WRITE_ANCILLARY_CHUNKS - -PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been -deprecated since libpng-1.0.16 and libpng-1.2.6. - -The function - png_check_sig(sig, num) -was replaced with - !png_sig_cmp(sig, 0, num) -It has been deprecated since libpng-0.90. - -The function - png_set_gray_1_2_4_to_8() -which also expands tRNS to alpha was replaced with - png_set_expand_gray_1_2_4_to_8() -which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. - -IX. (Omitted) - - -X. Detecting libpng - -The png_get_io_ptr() function has been present since libpng-0.88, has never -changed, and is unaffected by conditional compilation macros. It is the -best choice for use in configure scripts for detecting the presence of any -libpng version since 0.88. In an autoconf "configure.in" you could use - - AC_CHECK_LIB(png, png_get_io_ptr, ... - -XI. Source code repository - -Since about February 2009, version 1.2.34, libpng has been under "git" source -control. The git repository was built from old libpng-x.y.z.tar.gz files -going back to version 0.70. You can access the git repository (read only) -at - - git://git.code.sf.net/p/libpng/code - -or you can browse it with a web browser by selecting the "code" button at - - https://sourceforge.net/projects/libpng/ - -Patches can be sent to glennrp at users.sourceforge.net or to -png-mng-implement at lists.sourceforge.net or you can upload them to -the libpng bug tracker at - - http://libpng.sourceforge.net - -XII. Coding style - -Our coding style is similar to the "Allman" style, with curly -braces on separate lines: - - if (condition) - { - action; - } - - else if (another condition) - { - another action; - } - -The braces can be omitted from simple one-line actions: - - if (condition) - return (0); - -We use 3-space indentation, except for continued statements which -are usually indented the same as the first line of the statement -plus four more spaces. - -For macro definitions we use 2-space indentation, always leaving the "#" -in the first column. - - #ifndef PNG_NO_FEATURE - # ifndef PNG_FEATURE_SUPPORTED - # define PNG_FEATURE_SUPPORTED - # endif - #endif - -Comments appear with the leading "/*" at the same indentation as -the statement that follows the comment: - - /* Single-line comment */ - statement; - - /* Multiple-line - * comment - */ - statement; - -Very short comments can be placed at the end of the statement -to which they pertain: - - statement; /* comment */ - -We don't use C++ style ("//") comments. We have, however, -used them in the past in some now-abandoned MMX assembler -code. - -Functions and their curly braces are not indented, and -exported functions are marked with PNGAPI: - - /* This is a public function that is visible to - * application programers. It does thus-and-so. - */ - void PNGAPI - png_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for all exported functions appear in png.h, -above the comment that says - - /* Maintainer: Put new public prototypes here ... */ - -We mark all non-exported functions with "/* PRIVATE */"": - - void /* PRIVATE */ - png_non_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for non-exported functions (except for those in -pngtest) appear in -the PNG_INTERNAL section of png.h -above the comment that says - - /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -The names of all exported functions and variables begin -with "png_", and all publicly visible C preprocessor -macros begin with "PNG". - -We put a space after each comma and after each semicolon -in "for" statments, and we put spaces before and after each -C binary operator and after "for" or "while". We don't -put a space between a typecast and the expression being -cast, nor do we put one between a function name and the -left parenthesis that follows it: - - for (i = 2; i > 0; --i) - y[i] = a(x) + (int)b; - -We prefer #ifdef and #ifndef to #if defined() and if !defined() -when there is only one macro being tested. - -We do not use the TAB character for indentation in the C sources. - -Lines do not exceed 80 characters. - -Other rules can be inferred by inspecting the libpng source. - -XIII. Y2K Compliance in libpng - -February 6, 2014 - -Since the PNG Development group is an ad-hoc body, we can't make -an official declaration. - -This is your unofficial assurance that libpng from version 0.71 and -upward through 1.2.51 are Y2K compliant. It is my belief that earlier -versions were also Y2K compliant. - -Libpng only has three year fields. One is a 2-byte unsigned integer that -will hold years up to 65535. The other two hold the date in text -format, and will hold years up to 9999. - -The integer is - "png_uint_16 year" in png_time_struct. - -The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. - -There are seven time-related functions: - - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) - png_convert_from_struct_tm() in pngwrite.c, called - in pngwrite.c - png_convert_from_time_t() in pngwrite.c - png_get_tIME() in pngget.c - png_handle_tIME() in pngrutil.c, called in pngread.c - png_set_tIME() in pngset.c - png_write_tIME() in pngwutil.c, called in pngwrite.c - -All appear to handle dates properly in a Y2K environment. The -png_convert_from_time_t() function calls gmtime() to convert from system -clock time, which returns (year - 1900), which we properly convert to -the full 4-digit year. There is a possibility that applications using -libpng are not passing 4-digit years into the png_convert_to_rfc_1123() -function, or that they are incorrectly passing only a 2-digit year -instead of "year - 1900" into the png_convert_from_struct_tm() function, -but this is not under our control. The libpng documentation has always -stated that it works with 4-digit years, and the APIs have been -documented as such. - -The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned -integer to hold the year, and can hold years as large as 65535. - -zlib, upon which libpng depends, is also Y2K compliant. It contains -no date-related code. - - - Glenn Randers-Pehrson - libpng maintainer - PNG Development Group +libpng.txt - A description on how to use and modify libpng + + libpng version 1.2.51 - February 6, 2014 + Updated and distributed by Glenn Randers-Pehrson + + Copyright (c) 1998-2014 Glenn Randers-Pehrson + + This document is released under the libpng license. + For conditions of distribution and use, see the disclaimer + and license in png.h + + Based on: + + libpng versions 0.97, January 1998, through 1.2.51 - February 6, 2014 + Updated and distributed by Glenn Randers-Pehrson + Copyright (c) 1998-2014 Glenn Randers-Pehrson + + libpng 1.0 beta 6 version 0.96 May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + +I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. There are five sections to this +file: introduction, structures, reading, writing, and modification and +configuration notes for various special platforms. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to install libpng. + +For examples of libpng usage, see the files "example.c", "pngtest.c", +and the files in the "contrib" directory, all of which are included in +the libpng distribution. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG specification (second edition), November 2003, is available as +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at +. It is technically equivalent +to the PNG specification (second edition) but has some additional material. + +The PNG-1.0 specification is available +as RFC 2083 and as a +W3C Recommendation . + +Some additional chunks are described in the special-purpose public chunks +documents at . + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, . + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, . +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. + +II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. The first, png_struct, is an internal structure that +will not, for the most part, be used by a user except as the first +variable passed to every libpng function call. + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed. The fields of png_info are still available for +older applications, but it is suggested that applications use the new +interfaces if at all possible. + +Applications that do make direct access to the members of png_struct (except +for png_ptr->jmpbuf) must be recompiled whenever the library is updated, +and applications that make direct access to the members of png_info must +be recompiled if they were compiled or loaded with libpng version 1.0.6, +in which the members were in a different order. In version 1.0.7, the +members of the png_info structure reverted to the old order, as they were +in versions 0.97c through 1.0.5. Starting with version 2.0.0, both +structures are going to be hidden, and the contents of the structures will +only be accessible through the png_get/png_set functions. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include + +III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 (false) if the bytes match the +corresponding bytes of the PNG signature, or nonzero (true) otherwise. +Of course, the more bytes you pass in, the greater the accuracy of the +prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes_read() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + fread(header, 1, number, fp); + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the jmpbuf field every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_ptr ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data, along with similar data for any other + unknown chunks: */ + + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Search for your chunk in the + unknown chunk structure, process it, and return one + of the following: */ + + return (-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +If you call the png_set_read_user_chunk_fn() function, then all unknown +chunks will be saved when read, in case your callback function will need +one or more of them. This behavior can be changed with the +png_set_keep_unknown_chunks() function, described below. + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_ptr ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members while unknown chunks will be discarded. This +behavior can be wasteful if your application will never use some known +chunk types. To change this, you can call: + + png_set_keep_unknown_chunks(png_ptr, keep, + chunk_list, num_chunks); + keep - 0: default unknown chunk handling + 1: ignore; do not keep + 2: keep only if safe-to-copy + 3: keep even if unsafe-to-copy + You can use these definitions: + PNG_HANDLE_CHUNK_AS_DEFAULT 0 + PNG_HANDLE_CHUNK_NEVER 1 + PNG_HANDLE_CHUNK_IF_SAFE 2 + PNG_HANDLE_CHUNK_ALWAYS 3 + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is 0) + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected. If nonzero, + only the chunks in the list are affected + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. The IHDR and IEND chunks should not be named in +chunk_list; if they are, libpng will process them normally anyway. + +Here is an example of the usage of png_set_keep_unknown_chunks(), +where the private "vpAg" chunk will later be processed by a user chunk +callback function: + + png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + png_byte unused_chunks[]= + { + 104, 73, 83, 84, (png_byte) '\0', /* hIST */ + 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ + 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ + 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ + 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ + 116, 73, 77, 69, (png_byte) '\0', /* tIME */ + }; + #endif + + ... + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* ignore all unknown chunks: */ + png_set_keep_unknown_chunks(read_ptr, 1, NULL, 0); + /* except for vpAg: */ + png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); + /* also ignore unused known chunks: */ + png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, + (int)sizeof(unused_chunks)/5); + #endif + +User limits + +The PNG specification allows the width and height of an image to be as +large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. +Since very few applications really need to process such large images, +we have imposed an arbitrary 1-million limit on rows and columns. +Larger images will be rejected immediately with a png_error() call. If +you wish to override this limit, you can use + + png_set_user_limits(png_ptr, width_max, height_max); + +to set your own limits, or use width_max = height_max = 0x7fffffffL +to allow all valid dimensions (libpng may reject some very large images +anyway because of potential buffer overflow conditions). + +You should put this statement after you create the PNG structure and +before calling png_read_info(), png_read_png(), or png_process_data(). +If you need to retrieve the limits that are being applied, use + + width_max = png_get_user_width_max(png_ptr); + height_max = png_get_user_height_max(png_ptr); + +The PNG specification sets no limit on the number of ancillary chunks +allowed in a PNG datastream. You can impose a limit on the total number +of sPLT, tEXt, iTXt, zTXt, and unknown chunks that will be stored, with + + png_set_chunk_cache_max(png_ptr, user_chunk_cache_max); + +where 0x7fffffffL means unlimited. You can retrieve this limit with + + chunk_cache_max = png_get_chunk_cache_max(png_ptr); + +This limit also applies to the number of buffers that can be allocated +by png_decompress_chunk() while decompressing iTXt, zTXt, and iCCP chunks. + +The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to + 8 bits + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples + to RGB (or GA to RGBA) + +(This excludes setting a background color, doing gamma transformation, +dithering, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some +set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_read_png(). + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) + png_error (png_ptr, + "Image is too tall to process in memory"); + if (width > PNG_UINT_32_MAX/pixel_size) + png_error (png_ptr, + "Image is too wide to process in memory"); + row_pointers = png_malloc(png_ptr, + height*png_sizeof(png_bytep)); + for (int i=0; i) and +png_get_(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_ are set directly if they are simple data types, or a +pointer into the info_ptr is returned for any complex types. + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &gamma); + gamma - the gamma the file is written + at (PNG_INFO_gAMA) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + &trans_values); + trans - array of transparent + entries for palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + background - background color (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + num_comments - number of comments + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (empty + string for unknown). + text_ptr[i].lang_key - keyword in UTF-8 + (empty string for unknown). + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist + when the library is built with iTXt chunk support. + + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + num_spalettes - number of sPLT chunks read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + offset_x - positive offset from the left edge + of the screen + offset_y - positive offset from the top edge + of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + res_x - pixels/unit physical resolution in + x direction + res_y - pixels/unit physical resolution in + x direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + (Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y) + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + (Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel) + +For more information, see the png_info definition in png.h and the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +The colors used for the background and transparency values should be +supplied in the same format/depth as the current image data. They +are stored in the same format/depth as the image data in a bKGD or tRNS +chunk, so this is what libpng expects for this data. The colors are +transformed to keep in sync with the image data when an application +calls the png_read_update_info() routine (see below). + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the +byte, unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() +is called to insert filler bytes, either before or after each RGB triplet. +16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant +byte of the color value first, unless png_set_strip_16() is called to +transform it to regular RGB RGB triplets, or png_set_filler() or +png_set_add alpha() is called to insert filler bytes, either before or +after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can +be modified with +png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + +These three functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was +added. It expands the sample depth without changing tRNS to alpha. + +As of libpng version 1.2.51, not all possible expansions are supported. + +In the following table, the 01 means grayscale with depth<8, 31 means +indexed with depth<8, other numerals represent the color type, "T" means +the tRNS chunk is present, A means an alpha channel is present, and O +means tRNS or alpha is present but all pixels in the image are opaque. + + FROM 01 31 0 0T 0O 2 2T 2O 3 3T 3O 4A 4O 6A 6O + TO + 01 - + 31 - + 0 1 - + 0T - + 0O - + 2 GX - + 2T - + 2O - + 3 1 - + 3T - + 3O - + 4A T - + 4O - + 6A GX TX TX - + 6O GX TX - + +Within the matrix, + "-" means the transformation is not supported. + "X" means the transformation is obtained by png_set_expand(). + "1" means the transformation is obtained by + png_set_expand_gray_1_2_4_to_8 + "G" means the transformation is obtained by + png_set_gray_to_rgb(). + "P" means the transformation is obtained by + png_set_expand_palette_to_rgb(). + "T" means the transformation is obtained by + png_set_tRNS_to_alpha(). + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8 bit. + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + +If, for some reason, you don't need the alpha channel on an image, +and you want to remove it rather than combining it with the background +(but the image author certainly had in mind that you *would* combine +it with the background, so that's what you should probably do): + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +The PNG format only supports pixels with postmultiplied alpha. +If you want to replace the pixels, after reading them, with pixels +that have premultiplied color samples, you can do this with + + png_set_premultiply_alpha(png_ptr); + +If you do this, any input with a tRNS chunk will be expanded to +have an alpha channel. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] +to 8 bits/sample in the range [0, 255]). However, it is also possible +to convert the PNG pixel data back to the original bit depth of the +image. This call reduces the pixels back down to the original bit depth: + + png_color_8p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them +into 4 or 8 bytes for windowing systems that need them in this format: + + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" is the 8 or 16-bit number to fill with, and the location is +either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. This transformation +does not affect images that already have full alpha channels. To add an +opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which +will generate RGBA pixels. + +Note that png_set_filler() does not change the color type. If you want +to do that, you can add a true alpha channel with + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); + +where "filler" contains the alpha value to assign to each pixel. +This function was added in libpng-1.2.7. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray_fixed(png_ptr, error_action, + int red_weight, int green_weight); + + error_action = 1: silently do the conversion + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component times 100000 + green_weight: weight of green component times 100000 + If either weight is negative, default + weights (21268, 71514) are used. + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. bKGD and sBIT data +will be silently converted to grayscale, using the green channel +data, regardless of the error_action setting. + +With red_weight+green_weight<=100000, +the normalized graylevel is computed: + + int rw = red_weight * 65536; + int gw = green_weight * 65536; + int bw = 65536 - (rw + gw); + gray = (rw*red + gw*green + bw*blue)/65536; + +The default values approximate those recommended in the Charles +Poynton's Color FAQ, +Copyright (c) 1998-01-04 Charles Poynton + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng approximates this with + + Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + +which can be expressed with integers as + + Y = (6969 * R + 23434 * G + 2365 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +is known. + +If you have a grayscale and you are using png_set_expand_depth(), +png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to +a higher bit-depth, you must either supply the background color as a gray +value at the original file bit-depth (need_expand = 1) or else supply the +background color as an RGB triplet at the final, expanded bit depth +(need_expand = 0). Similarly, if you are reading a paletted image, you +must either supply the background color as a palette index (need_expand = 1) +or as an RGB triplet that may or may not be in the palette (need_expand = 0). + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + +The png_set_background() function tells libpng to composite images +with alpha or simple transparency against the supplied background +color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng whether the color is in the gamma space of the +display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file +(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one +that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't +know why anyone would use this, but it's here). + +To properly display PNG images on any kind of system, the application needs +to know what the display gamma is. Ideally, the user will know this, and +the application will allow them to set it. One method of allowing the user +to set the display gamma separately for each system is to check for a +SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be +correctly set. + +Note that display_gamma is the overall gamma correction required to produce +pleasing results, which depends on the lighting conditions in the surrounding +environment. In a dim or brightly lit room, no compensation other than +the physical gamma exponent of the monitor is needed, while in a dark room +a slightly smaller exponent is better. + + double gamma, screen_gamma; + + if (/* We have a user-defined screen + gamma value */) + { + screen_gamma = user_defined_screen_gamma; + } + /* One way that applications can share the same + screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) + != NULL) + { + screen_gamma = (double)atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a + PC monitor in a bright office or a dim room */ + screen_gamma = 2.0; /* A good guess for a + PC monitor in a dark room */ + screen_gamma = 1.7 or 1.0; /* A good + guess for Mac systems */ + } + +The png_set_gamma() function handles gamma transformations of the data. +Pass both the file gamma and the current screen_gamma. If the file does +not have a gamma value, you can pass one anyway if you have an idea what +it is (usually 0.45455 is a good guess for GIF images on PCs). Note +that file gammas are inverted from screen gammas. See the discussions +on gamma in the PNG specification for an excellent description of what +gamma is, and why all applications should support it. It is strongly +recommended that PNG viewers support gamma correction. + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries then will fit on your screen, png_set_dither() +will do that. Note that this is a simple match dither that merely +finds the closest color available. This should work fairly well with +optimized palettes, and fairly badly with linear color cubes. If you +pass a palette that is larger then maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, it will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_dither(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) + png_set_invert_mono(png_ptr); + +This function can also be used to invert grayscale and gray-alpha images: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_invert_mono(png_ptr); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. + + png_read_update_info(png_ptr, info_ptr); + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't need +to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) +is a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. + +libpng can fill out those images or it can give them to you "as is". +If you want them filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() seven times to read in all seven images. Each of the +images is a valid image by itself, or they can all be combined on an +8x8 grid to form a single image (although if you intend to combine them +you would be far better off using the libpng interlace handling). + +The first pass will return an image 1/8 as wide as the entire image +(every 8th column starting in column 0) and 1/8 as high as the original +(every 8th row starting in row 0), the second will be 1/8 as wide +(starting in column 4) and 1/8 as high (also starting in row 0). The +third pass will be 1/4 as wide (every 4th pixel starting in column 0) and +1/8 as high (every 8th row starting in row 4), and the fourth pass will +be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, +and every 4th row starting in row 0). The fifth pass will return an +image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), +while the sixth pass will be 1/2 as wide and 1/2 as high as the original +(starting in column 1 and row 0). The seventh and final pass will be as +wide as the original, and 1/2 as high, containing all of the odd +numbered scanlines. Phew! + +If you want libpng to expand the images, call this before calling +png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. +This function can be called even if the file is not interlaced, +where it will return one pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +Finishing a sequential read + +After you are finished reading the image through the +low-level interface, you can finish reading the file. If you are +interested in comments or time, which may be stored either before or +after the image data, you should pass the separate png_info struct if +you want to keep the comments from before and after the image +separate. If you are not interested, you can pass NULL. + + png_read_end(png_ptr, end_info); + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not -1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by +your application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + mask - identifies the chunks to be made invalid, + containing the bitwise OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +Reading PNG files progressively + +The progressive reader is slightly different then the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, + (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less then 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + */ + } + + /* This function is called when each row of image + data is complete */ + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + For the non-NULL rows of interlaced images, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed for + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + if (!fp) + { + return (ERROR); + } + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +If you are embedding your PNG into a datastream such as MNG, and don't +want libpng to write the 8-byte signature, or if you have already +written the signature in your application, use + + png_set_sig_bytes(png_ptr, 8); + +to inform libpng that it should not write a signature. + +Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific +filter types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the bitwise OR of one + or more PNG_FILTER_NAME masks. */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS); + +If an application +wants to start and stop using particular filters during compression, +it should start out with all of the filters (to ensure that the previous +row of pixels will be stored in case it's needed later), and then add +and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + +extern PNG_EXPORT(void,png_set_zbuf_size) + +Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + +If you call png_set_IHDR(), the call must appear before any of the +other png_set_*() functions, because they might require access to some of +the IHDR settings. The remaining png_set_*() functions can be called +in any order. + +If you wish, you can reset the compression_type, interlace_type, or +filter_method later by calling png_set_IHDR() again; if you do this, the +width, height, bit_depth, and color_type must be the same in each call. + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_set_gAMA(png_ptr, info_ptr, gamma); + gamma - the gamma the image was created + at (PNG_INFO_gAMA) + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, + trans_values); + trans - array of transparent + entries for palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values + (in order red, green, blue) of the + single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_set_tIME(png_ptr, info_ptr, mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + background - background color (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist + when the library is built with iTXt chunk support. + + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + offset_x - positive offset from the left + edge of the screen + offset_y - positive offset from the top + edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + res_x - pixels/unit physical resolution + in x direction + res_y - pixels/unit physical resolution + in y direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around 1000 bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct. + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + Author Name of image's creator + Description Description of image (possibly long) + Copyright Copyright notice + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123(png_timep) is provided to convert from PNG +time to an RFC 1123 format string. + +Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up chunks +for writing. You give it a chunk name, raw data, and a size; that's +all there is to it. The chunks will be written by the next following +png_write_info_before_PLTE, png_write_info, or png_write_end function. +Any chunks previously read into the info structure's unknown-chunk +list will also be written out in a sequence that satisfies the PNG +specification's ordering rules. + +The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler + bytes (deprecated). + PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading + filler bytes + PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing + filler bytes + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_write_png(). + +The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of transparency, +you can invert the alpha channel before you write it, so that 0 is +fully transparent and 255 (in 8-bit or paletted images) or 65535 +(in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + else + { + sig_bit.gray = true_bit_depth; + } + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more complicated. +The only currently (as of the PNG Specification version 1.2, dated July +1999) defined interlacing scheme for PNG files is the "Adam7" interlace +scheme, that breaks down an image into seven smaller images of varying +size. libpng will build these images for you, or you can do them +yourself. If you want to build them yourself, see the PNG specification +for details of which pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all seven sub-images. + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = + png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this is seven, +but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +As some of these rows are not used, and thus return immediately, you may +want to read about interlacing in the PNG specification, and only update +the rows that are actually used. + +Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not -1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +If you allocated data such as a palette that you passed in to libpng +with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +V. Modifying/Customizing libpng: + +There are two issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc(), png_calloc(), +and png_free(). These currently just call the standard C functions. +png_calloc() calls png_malloc() and then png_memset() to clear the newly +allocated memory to zero. If your pointers can't access more then 64K +at a time, you will want to set MAXSEG_64K in zlib.h. Since it is +unlikely that the method of handling memory allocation on a platform +will change between applications, these functions must be modified in +the library at compile time. If you prefer to use a different method +of allocating and freeing data, you can use png_create_read_struct_2() or +png_create_write_struct_2() to register your own functions as described +above. These functions also provide a void pointer that can be retrieved +via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_size_t size); + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() must return NULL in case of failure. The png_malloc() +function will normally call png_error() if it receives a NULL from the +system memory allocator or from your replacement malloc_fn(). + +Your free_fn() will never be called with a NULL ptr, since libpng's +png_free() checks for NULL before calling free_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_write_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_flush_data(png_structp png_ptr); + +The user_read_data() function is responsible for detecting and +handling end-of-data errors. + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions, which expect the io_ptr to +point to a standard *FILE structure. It is probably a mistake +to use NULL for one of write_data_fn and output_flush_fn but not both +of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. +It is an error to read from a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything +after setjmp returns non-zero besides returning itself. Consult your +compiler documentation for more details. For an alternative approach, you +may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net). + +Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. However, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of understanding of how it works. +Pay particular attention to the sections that describe chunk names, +and look at how other chunks were designed, so you can do things +similarly. Second, check out the sections of libpng that read and +write chunks. Try to find a chunk that is similar to yours and use +it as a template. More details can be found in the comments inside +the code. It is best to handle unknown chunks in a generic method, +via callback functions, instead of by modifying libpng functions. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +Configuring for 16 bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more then 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is an +unsigned char far * far *. + +Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add, change +or delete an include, this is the place to do it. +The includes that are not needed outside libpng are protected by the +PNG_INTERNAL definition, which is only defined for those routines inside +libpng itself. The files in libpng proper only include png.h, which +includes pngconf.h. + +Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). +Note that the memory level does have an effect on compression; among +other things, lower levels will result in sections of incompressible +data being emitted in smaller stored blocks, with a correspondingly +larger relative overhead of up to 15% in the worst case. + + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + png_set_compression_strategy(png_ptr, + strategy); + png_set_compression_window_bits(png_ptr, + window_bits); + png_set_compression_method(png_ptr, method); + png_set_compression_buffer_size(png_ptr, size); + +Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS +to turn filtering on and off, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. +If you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. (Note that this +means the first row must always be adaptively filtered, because libpng +currently does not allocate the filter buffers until png_write_row() +is called for the first time.) + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB + PNG_FILTER_UP | PNG_FILTER_AVG | + PNG_FILTER_PAETH | PNG_ALL_FILTERS; + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +It is also possible to influence how libpng chooses from among the +available filters. This is done in one or both of two ways - by +telling it how important it is to keep the same filter for successive +rows, and by telling it the relative computational costs of the filters. + + double weights[3] = {1.5, 1.3, 1.1}, + costs[PNG_FILTER_VALUE_LAST] = + {1.0, 1.3, 1.3, 1.5, 1.7}; + + png_set_filter_heuristics(png_ptr, + PNG_FILTER_HEURISTIC_WEIGHTED, 3, + weights, costs); + +The weights are multiplying factors that indicate to libpng that the +row filter should be the same for successive rows unless another row filter +is that many times better than the previous filter. In the above example, +if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a +"sum of absolute differences" 1.5 x 1.3 times higher than other filters +and still be chosen, while the NONE filter could have a sum 1.1 times +higher than other filters and still be chosen. Unspecified weights are +taken to be 1.0, and the specified weights should probably be declining +like those above in order to emphasize recent filters over older filters. + +The filter costs specify for each filter type a relative decoding cost +to be considered when selecting row filters. This means that filters +with higher costs are less likely to be chosen over filters with lower +costs, unless their "sum of absolute differences" is that much smaller. +The costs do not necessarily reflect the exact computational speeds of +the various filters, since this would unduly influence the final image +size. + +Note that the numbers above were invented purely for this example and +are given only to help explain the function usage. Little testing has +been done to find optimum values for either the costs or the weights. + +Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, +along with directives to turn on any of the capabilities that you do +want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the extra +transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks. Use of the +PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library +that is incapable of reading or writing ancillary chunks. If you are +not using the progressive reading capability, you can turn that off +with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING +capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with pngr and all the writing files start with +pngw. The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d", foo); + +is expanded to + + if(PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + +VI. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + mask is a png_uint_32 containing the bitwise OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + feature_set is a png_uint_32 that is the bitwise AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +VII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 2.0.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; +however, iTXt support was not enabled by default. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +VIII. Changes to Libpng from version 1.0.x to 1.2.x + +Support for user memory management was enabled by default. To +accomplish this, the functions png_create_read_struct_2(), +png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), +png_malloc_default(), and png_free_default() were added. + +Support for the iTXt chunk has been enabled by default as of +version 1.2.41. + +Support for certain MNG features was enabled. + +Support for numbered error messages was added. However, we never got +around to actually numbering the error messages. The function +png_set_strip_error_numbers() was added (Note: the prototype for this +function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE +builds of libpng-1.2.15. It was restored in libpng-1.2.36). + +The png_malloc_warn() function was added at libpng-1.2.3. This issues +a png_warning and returns NULL instead of aborting when it fails to +acquire the requested memory allocation. + +Support for setting user limits on image width and height was enabled +by default. The functions png_set_user_limits(), png_get_user_width_max(), +and png_get_user_height_max() were added at libpng-1.2.6. + +The png_set_add_alpha() function was added at libpng-1.2.7. + +The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. +Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the +tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is +deprecated. + +A number of macro definitions in support of runtime selection of +assembler code features (especially Intel MMX code support) were +added at libpng-1.2.0: + + PNG_ASM_FLAG_MMX_SUPPORT_COMPILED + PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW + PNG_ASM_FLAG_MMX_READ_INTERLACE + PNG_ASM_FLAG_MMX_READ_FILTER_SUB + PNG_ASM_FLAG_MMX_READ_FILTER_UP + PNG_ASM_FLAG_MMX_READ_FILTER_AVG + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH + PNG_ASM_FLAGS_INITIALIZED + PNG_MMX_READ_FLAGS + PNG_MMX_FLAGS + PNG_MMX_WRITE_FLAGS + PNG_MMX_FLAGS + +We added the following functions in support of runtime +selection of assembler code features: + + png_get_mmx_flagmask() + png_set_mmx_thresholds() + png_get_asm_flags() + png_get_mmx_bitdepth_threshold() + png_get_mmx_rowbytes_threshold() + png_set_asm_flags() + +We replaced all of these functions with simple stubs in libpng-1.2.20, +when the Intel assembler code was removed due to a licensing issue. + +These macros are deprecated: + + PNG_READ_TRANSFORMS_NOT_SUPPORTED + PNG_PROGRESSIVE_READ_NOT_SUPPORTED + PNG_NO_SEQUENTIAL_READ_SUPPORTED + PNG_WRITE_TRANSFORMS_NOT_SUPPORTED + PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED + PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED + +They have been replaced, respectively, by: + + PNG_NO_READ_TRANSFORMS + PNG_NO_PROGRESSIVE_READ + PNG_NO_SEQUENTIAL_READ + PNG_NO_WRITE_TRANSFORMS + PNG_NO_READ_ANCILLARY_CHUNKS + PNG_NO_WRITE_ANCILLARY_CHUNKS + +PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been +deprecated since libpng-1.0.16 and libpng-1.2.6. + +The function + png_check_sig(sig, num) +was replaced with + !png_sig_cmp(sig, 0, num) +It has been deprecated since libpng-0.90. + +The function + png_set_gray_1_2_4_to_8() +which also expands tRNS to alpha was replaced with + png_set_expand_gray_1_2_4_to_8() +which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. + +IX. (Omitted) + + +X. Detecting libpng + +The png_get_io_ptr() function has been present since libpng-0.88, has never +changed, and is unaffected by conditional compilation macros. It is the +best choice for use in configure scripts for detecting the presence of any +libpng version since 0.88. In an autoconf "configure.in" you could use + + AC_CHECK_LIB(png, png_get_io_ptr, ... + +XI. Source code repository + +Since about February 2009, version 1.2.34, libpng has been under "git" source +control. The git repository was built from old libpng-x.y.z.tar.gz files +going back to version 0.70. You can access the git repository (read only) +at + + git://git.code.sf.net/p/libpng/code + +or you can browse it with a web browser by selecting the "code" button at + + https://sourceforge.net/projects/libpng/ + +Patches can be sent to glennrp at users.sourceforge.net or to +png-mng-implement at lists.sourceforge.net or you can upload them to +the libpng bug tracker at + + http://libpng.sourceforge.net + +XII. Coding style + +Our coding style is similar to the "Allman" style, with curly +braces on separate lines: + + if (condition) + { + action; + } + + else if (another condition) + { + another action; + } + +The braces can be omitted from simple one-line actions: + + if (condition) + return (0); + +We use 3-space indentation, except for continued statements which +are usually indented the same as the first line of the statement +plus four more spaces. + +For macro definitions we use 2-space indentation, always leaving the "#" +in the first column. + + #ifndef PNG_NO_FEATURE + # ifndef PNG_FEATURE_SUPPORTED + # define PNG_FEATURE_SUPPORTED + # endif + #endif + +Comments appear with the leading "/*" at the same indentation as +the statement that follows the comment: + + /* Single-line comment */ + statement; + + /* Multiple-line + * comment + */ + statement; + +Very short comments can be placed at the end of the statement +to which they pertain: + + statement; /* comment */ + +We don't use C++ style ("//") comments. We have, however, +used them in the past in some now-abandoned MMX assembler +code. + +Functions and their curly braces are not indented, and +exported functions are marked with PNGAPI: + + /* This is a public function that is visible to + * application programers. It does thus-and-so. + */ + void PNGAPI + png_exported_function(png_ptr, png_info, foo) + { + body; + } + +The prototypes for all exported functions appear in png.h, +above the comment that says + + /* Maintainer: Put new public prototypes here ... */ + +We mark all non-exported functions with "/* PRIVATE */"": + + void /* PRIVATE */ + png_non_exported_function(png_ptr, png_info, foo) + { + body; + } + +The prototypes for non-exported functions (except for those in +pngtest) appear in +the PNG_INTERNAL section of png.h +above the comment that says + + /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +The names of all exported functions and variables begin +with "png_", and all publicly visible C preprocessor +macros begin with "PNG". + +We put a space after each comma and after each semicolon +in "for" statments, and we put spaces before and after each +C binary operator and after "for" or "while". We don't +put a space between a typecast and the expression being +cast, nor do we put one between a function name and the +left parenthesis that follows it: + + for (i = 2; i > 0; --i) + y[i] = a(x) + (int)b; + +We prefer #ifdef and #ifndef to #if defined() and if !defined() +when there is only one macro being tested. + +We do not use the TAB character for indentation in the C sources. + +Lines do not exceed 80 characters. + +Other rules can be inferred by inspecting the libpng source. + +XIII. Y2K Compliance in libpng + +February 6, 2014 + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.2.51 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has three year fields. One is a 2-byte unsigned integer that +will hold years up to 65535. The other two hold the date in text +format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + +There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/main/source/includes/lpng1251/libpng.3 b/main/source/includes/lpng1251/libpng.3 index 9842d36d..29a54aee 100644 --- a/main/source/includes/lpng1251/libpng.3 +++ b/main/source/includes/lpng1251/libpng.3 @@ -1,4108 +1,4108 @@ -.TH LIBPNG 3 "February 6, 2014" -.SH NAME -libpng \- Portable Network Graphics (PNG) Reference Library 1.2.51 -.SH SYNOPSIS -\fB -#include \fP - -\fBpng_uint_32 png_access_version_number \fI(void\fP\fB);\fP - -\fBint png_check_sig (png_bytep \fP\fIsig\fP\fB, int \fInum\fP\fB);\fP - -\fBvoid png_chunk_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP - -\fBvoid png_chunk_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP - -\fBvoid png_convert_from_struct_tm (png_timep \fP\fIptime\fP\fB, struct tm FAR * \fIttime\fP\fB);\fP - -\fBvoid png_convert_from_time_t (png_timep \fP\fIptime\fP\fB, time_t \fIttime\fP\fB);\fP - -\fBpng_charp png_convert_to_rfc1123 (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fIptime\fP\fB);\fP - -\fBpng_infop png_create_info_struct (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_structp png_create_read_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP - -\fBpng_structp png_create_read_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP - -\fBpng_structp png_create_write_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP - -\fBpng_structp png_create_write_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP - -\fBint png_debug(int \fP\fIlevel\fP\fB, png_const_charp \fImessage\fP\fB);\fP - -\fBint png_debug1(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fIp1\fP\fB);\fP - -\fBint png_debug2(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fP\fIp1\fP\fB, \fIp2\fP\fB);\fP - -\fBvoid png_destroy_info_struct (png_structp \fP\fIpng_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP - -\fBvoid png_destroy_read_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fP\fIinfo_ptr_ptr\fP\fB, png_infopp \fIend_info_ptr_ptr\fP\fB);\fP - -\fBvoid png_destroy_write_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP - -\fBvoid png_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP - -\fBvoid png_free (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP - -\fBvoid png_free_chunk_list (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_free_default(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP - -\fBvoid png_free_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fInum\fP\fB);\fP - -\fBpng_byte png_get_bit_depth (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fI*background\fP\fB);\fP - -\fBpng_byte png_get_channels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*white_x\fP\fB, double \fP\fI*white_y\fP\fB, double \fP\fI*red_x\fP\fB, double \fP\fI*red_y\fP\fB, double \fP\fI*green_x\fP\fB, double \fP\fI*green_y\fP\fB, double \fP\fI*blue_x\fP\fB, double \fI*blue_y\fP\fB);\fP - -\fBpng_uint_32 png_get_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*white_x\fP\fB, png_uint_32 \fP\fI*white_y\fP\fB, png_uint_32 \fP\fI*red_x\fP\fB, png_uint_32 \fP\fI*red_y\fP\fB, png_uint_32 \fP\fI*green_x\fP\fB, png_uint_32 \fP\fI*green_y\fP\fB, png_uint_32 \fP\fI*blue_x\fP\fB, png_uint_32 \fI*blue_y\fP\fB);\fP - -\fBpng_byte png_get_color_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_byte png_get_compression_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_byte png_get_copyright (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_voidp png_get_error_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_byte png_get_filter_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fI*file_gamma\fP\fB);\fP - -\fBpng_uint_32 png_get_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fI*int_file_gamma\fP\fB);\fP - -\fBpng_byte png_get_header_ver (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_byte png_get_header_version (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fI*hist\fP\fB);\fP - -\fBpng_uint_32 png_get_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charpp \fP\fIname\fP\fB, int \fP\fI*compression_type\fP\fB, png_charpp \fP\fIprofile\fP\fB, png_uint_32 \fI*proflen\fP\fB);\fP - -\fBpng_uint_32 png_get_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*width\fP\fB, png_uint_32 \fP\fI*height\fP\fB, int \fP\fI*bit_depth\fP\fB, int \fP\fI*color_type\fP\fB, int \fP\fI*interlace_type\fP\fB, int \fP\fI*compression_type\fP\fB, int \fI*filter_type\fP\fB);\fP - -\fBpng_uint_32 png_get_image_height (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_image_width (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fB#if !defined(PNG_1_0_X) png_int_32 png_get_int_32 (png_bytep buf); \fI#endif - -\fBpng_byte png_get_interlace_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_voidp png_get_io_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_byte png_get_libpng_ver (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_voidp png_get_mem_ptr(png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*offset_x\fP\fB, png_uint_32 \fP\fI*offset_y\fP\fB, int \fI*unit_type\fP\fB);\fP - -\fBpng_uint_32 png_get_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fI*purpose\fP\fB, png_int_32 \fP\fI*X0\fP\fB, png_int_32 \fP\fI*X1\fP\fB, int \fP\fI*type\fP\fB, int \fP\fI*nparams\fP\fB, png_charp \fP\fI*units\fP\fB, png_charpp \fI*params\fP\fB);\fP - -\fBpng_uint_32 png_get_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP - -\fBfloat png_get_pixel_aspect_ratio (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_voidp png_get_progressive_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fI*palette\fP\fB, int \fI*num_palette\fP\fB);\fP - -\fBpng_byte png_get_rgb_to_gray_status (png_structp png_ptr) png_uint_32 png_get_rowbytes (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_bytepp png_get_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fI*sig_bit\fP\fB);\fP - -\fBpng_bytep png_get_signature (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fI*splt_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fI*intent\fP\fB);\fP - -\fBpng_uint_32 png_get_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fI*text_ptr\fP\fB, int \fI*num_text\fP\fB);\fP - -\fBpng_uint_32 png_get_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fI*mod_time\fP\fB);\fP - -\fBpng_uint_32 png_get_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fI*trans\fP\fB, int \fP\fI*num_trans\fP\fB, png_color_16p \fI*trans_values\fP\fB);\fP - -\fB#if !defined(PNG_1_0_X) png_uint_16 png_get_uint_16 (png_bytep \fIbuf\fP\fB);\fP - -\fBpng_uint_32 png_get_uint_31 (png_bytep \fIbuf\fP\fB);\fP - -\fBpng_uint_32 png_get_uint_32 (png_bytep buf); \fI#endif - -\fBpng_uint_32 png_get_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkpp \fIunknowns\fP\fB);\fP - -\fBpng_voidp png_get_user_chunk_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_user_height_max( png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_voidp png_get_user_transform_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_user_width_max (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_valid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIflag\fP\fB);\fP - -\fBpng_int_32 png_get_x_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_int_32 png_get_x_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_x_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_int_32 png_get_y_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_int_32 png_get_y_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_y_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBpng_uint_32 png_get_compression_buffer_size (png_structp \fIpng_ptr\fP\fB);\fP - -\fBint png_handle_as_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP - -\fBvoid png_init_io (png_structp \fP\fIpng_ptr\fP\fB, FILE \fI*fp\fP\fB);\fP - -\fBDEPRECATED void png_info_init (png_infop \fIinfo_ptr\fP\fB);\fP - -\fBDEPRECATED void png_info_init_2 (png_infopp \fP\fIptr_ptr\fP\fB, png_size_t \fIpng_info_struct_size\fP\fB);\fP - -\fBpng_voidp png_malloc (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fBpng_voidp png_malloc_default(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fBvoidp png_memcpy (png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_size_t \fIsize\fP\fB);\fP - -\fBpng_voidp png_memcpy_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fBvoidp png_memset (png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_size_t \fIsize\fP\fB);\fP - -\fBpng_voidp png_memset_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fBDEPRECATED void png_permit_empty_plte (png_structp \fP\fIpng_ptr\fP\fB, int \fIempty_plte_permitted\fP\fB);\fP - -\fBvoid png_process_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_size\fP\fB);\fP - -\fBvoid png_progressive_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIold_row\fP\fB, png_bytep \fInew_row\fP\fB);\fP - -\fBvoid png_read_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_infop \fIend_info_ptr\fP\fB);\fP - -\fBvoid png_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_read_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP - -\fBDEPRECATED void png_read_init (png_structp \fIpng_ptr\fP\fB);\fP - -\fBDEPRECATED void png_read_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP - -\fBvoid png_read_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_read_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP - -\fBvoid png_read_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fIdisplay_row\fP\fB);\fP - -\fBvoid png_read_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_bytepp \fP\fIdisplay_row\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP - -\fBvoid png_read_update_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fB#if !defined(PNG_1_0_X) png_save_int_32 (png_bytep \fP\fIbuf\fP\fB, png_int_32 \fIi\fP\fB);\fP - -\fBvoid png_save_uint_16 (png_bytep \fP\fIbuf\fP\fB, unsigned int \fIi\fP\fB);\fP - -\fBvoid png_save_uint_32 (png_bytep \fP\fIbuf\fP\fB, png_uint_32 \fIi\fP\fB);\fP - -\fBvoid png_set_add_alpha (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int flags); \fI#endif - -\fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP - -\fBvoid png_set_bgr (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fIbackground\fP\fB);\fP - -\fBvoid png_set_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP - -\fBvoid png_set_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP - -\fBvoid png_set_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP - -\fBvoid png_set_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP - -\fBvoid png_set_compression_method (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod\fP\fB);\fP - -\fBvoid png_set_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP - -\fBvoid png_set_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP - -\fBvoid png_set_crc_action (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcrit_action\fP\fB, int \fIancil_action\fP\fB);\fP - -\fBvoid png_set_dither (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fP\fInum_palette\fP\fB, int \fP\fImaximum_colors\fP\fB, png_uint_16p \fP\fIhistogram\fP\fB, int \fIfull_dither\fP\fB);\fP - -\fBvoid png_set_error_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarning_fn\fP\fB);\fP - -\fBvoid png_set_expand (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_expand_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_filler (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP - -\fBvoid png_set_filter (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImethod\fP\fB, int \fIfilters\fP\fB);\fP - -\fBvoid png_set_filter_heuristics (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_doublep \fP\fIfilter_weights\fP\fB, png_doublep \fIfilter_costs\fP\fB);\fP - -\fBvoid png_set_flush (png_structp \fP\fIpng_ptr\fP\fB, int \fInrows\fP\fB);\fP - -\fBvoid png_set_gamma (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIscreen_gamma\fP\fB, double \fIdefault_file_gamma\fP\fB);\fP - -\fBvoid png_set_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP - -\fBvoid png_set_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIfile_gamma\fP\fB);\fP - -\fBvoid png_set_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_gray_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fIhist\fP\fB);\fP - -\fBvoid png_set_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, png_uint_32 \fIproflen\fP\fB);\fP - -\fBint png_set_interlace_handling (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_invalid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fImask\fP\fB);\fP - -\fBvoid png_set_invert_alpha (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_invert_mono (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP - -\fBvoid png_set_keep_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIkeep\fP\fB, png_bytep \fP\fIchunk_list\fP\fB, int \fInum_chunks\fP\fB);\fP - -\fBvoid png_set_mem_fn(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP - -\fBvoid png_set_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIoffset_x\fP\fB, png_uint_32 \fP\fIoffset_y\fP\fB, int \fIunit_type\fP\fB);\fP - -\fBvoid png_set_packing (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_packswap (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_palette_to_rgb(png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP - -\fBvoid png_set_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIres_x\fP\fB, png_uint_32 \fP\fIres_y\fP\fB, int \fIunit_type\fP\fB);\fP - -\fBvoid png_set_progressive_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIprogressive_ptr\fP\fB, png_progressive_info_ptr \fP\fIinfo_fn\fP\fB, png_progressive_row_ptr \fP\fIrow_fn\fP\fB, png_progressive_end_ptr \fIend_fn\fP\fB);\fP - -\fBvoid png_set_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP - -\fBvoid png_set_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fIread_data_fn\fP\fB);\fP - -\fBvoid png_set_read_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_read_status_ptr \fIread_row_fn\fP\fB);\fP - -\fBvoid png_set_read_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIread_user_transform_fn\fP\fB);\fP - -\fBvoid png_set_rgb_to_gray (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIerror_action\fP\fB, double \fP\fIred\fP\fB, double \fIgreen\fP\fB);\fP - -\fBvoid png_set_rgb_to_gray_fixed (png_structp \fP\fIpng_ptr\fP\fB, int error_action png_fixed_point \fP\fIred\fP\fB, png_fixed_point \fIgreen\fP\fB);\fP - -\fBvoid png_set_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytepp \fIrow_pointers\fP\fB);\fP - -\fBvoid png_set_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fIsig_bit\fP\fB);\fP - -\fBvoid png_set_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP - -\fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP - -\fBvoid png_set_sig_bytes (png_structp \fP\fIpng_ptr\fP\fB, int \fInum_bytes\fP\fB);\fP - -\fBvoid png_set_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fP\fIsplt_ptr\fP\fB, int \fInum_spalettes\fP\fB);\fP - -\fBvoid png_set_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP - -\fBvoid png_set_sRGB_gAMA_and_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP - -\fBvoid png_set_strip_16 (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_strip_alpha (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_swap (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_swap_alpha (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_set_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP - -\fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP - -\fBvoid png_set_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fP\fInum_trans\fP\fB, png_color_16p \fItrans_values\fP\fB);\fP - -\fBvoid png_set_tRNS_to_alpha(png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_set_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkp \fP\fIunknowns\fP\fB, int \fP\fInum\fP\fB, int \fIlocation\fP\fB);\fP - -\fBvoid png_set_unknown_chunk_location(png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIchunk\fP\fB, int \fIlocation\fP\fB);\fP - -\fBvoid png_set_read_user_chunk_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_chunk_ptr\fP\fB, png_user_chunk_ptr \fIread_user_chunk_fn\fP\fB);\fP - -\fBvoid png_set_user_limits (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIuser_width_max\fP\fB, png_uint_32 \fIuser_height_max\fP\fB);\fP - -\fBvoid png_set_user_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_transform_ptr\fP\fB, int \fP\fIuser_transform_depth\fP\fB, int \fIuser_transform_channels\fP\fB);\fP - -\fBvoid png_set_write_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fP\fIwrite_data_fn\fP\fB, png_flush_ptr \fIoutput_flush_fn\fP\fB);\fP - -\fBvoid png_set_write_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_write_status_ptr \fIwrite_row_fn\fP\fB);\fP - -\fBvoid png_set_write_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIwrite_user_transform_fn\fP\fB);\fP - -\fBvoid png_set_compression_buffer_size(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fBint png_sig_cmp (png_bytep \fP\fIsig\fP\fB, png_size_t \fP\fIstart\fP\fB, png_size_t \fInum_to_check\fP\fB);\fP - -\fBvoid png_start_read_image (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP - -\fBvoid png_write_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBvoid png_write_chunk_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBvoid png_write_chunk_end (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_chunk_start (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_write_destroy (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_write_flush (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP - -\fBDEPRECATED void png_write_init (png_structp \fIpng_ptr\fP\fB);\fP - -\fBDEPRECATED void png_write_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP - -\fBvoid png_write_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_write_info_before_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_write_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP - -\fBvoid png_write_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_write_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP - -\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP - -\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP - -.SH DESCRIPTION -The -.I libpng -library supports encoding, decoding, and various manipulations of -the Portable Network Graphics (PNG) format image files. It uses the -.IR zlib(3) -compression library. -Following is a copy of the libpng.txt file that accompanies libpng. -.SH LIBPNG.TXT -libpng.txt - A description on how to use and modify libpng - - libpng version 1.2.51 - February 6, 2014 - Updated and distributed by Glenn Randers-Pehrson - - Copyright (c) 1998-2014 Glenn Randers-Pehrson - - This document is released under the libpng license. - For conditions of distribution and use, see the disclaimer - and license in png.h - - Based on: - - libpng versions 0.97, January 1998, through 1.2.51 - February 6, 2014 - Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2014 Glenn Randers-Pehrson - - libpng 1.0 beta 6 version 0.96 May 28, 1997 - Updated and distributed by Andreas Dilger - Copyright (c) 1996, 1997 Andreas Dilger - - libpng 1.0 beta 2 - version 0.88 January 26, 1996 - For conditions of distribution and use, see copyright - notice in png.h. Copyright (c) 1995, 1996 Guy Eric - Schalnat, Group 42, Inc. - - Updated/rewritten per request in the libpng FAQ - Copyright (c) 1995, 1996 Frank J. T. Wojcik - December 18, 1995 & January 20, 1996 - -.SH I. Introduction - -This file describes how to use and modify the PNG reference library -(known as libpng) for your own use. There are five sections to this -file: introduction, structures, reading, writing, and modification and -configuration notes for various special platforms. In addition to this -file, example.c is a good starting point for using the library, as -it is heavily commented and should include everything most people -will need. We assume that libpng is already installed; see the -INSTALL file for instructions on how to install libpng. - -For examples of libpng usage, see the files "example.c", "pngtest.c", -and the files in the "contrib" directory, all of which are included in -the libpng distribution. - -Libpng was written as a companion to the PNG specification, as a way -of reducing the amount of time and effort it takes to support the PNG -file format in application programs. - -The PNG specification (second edition), November 2003, is available as -a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at -. It is technically equivalent -to the PNG specification (second edition) but has some additional material. - -The PNG-1.0 specification is available -as RFC 2083 and as a -W3C Recommendation . - -Some additional chunks are described in the special-purpose public chunks -documents at . - -Other information -about PNG, and the latest version of libpng, can be found at the PNG home -page, . - -Most users will not have to modify the library significantly; advanced -users may want to modify it more. All attempts were made to make it as -complete as possible, while keeping the code easy to understand. -Currently, this library only supports C. Support for other languages -is being considered. - -Libpng has been designed to handle multiple sessions at one time, -to be easily modifiable, to be portable to the vast majority of -machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy -to use. The ultimate goal of libpng is to promote the acceptance of -the PNG file format in whatever way possible. While there is still -work to be done (see the TODO file), libpng should cover the -majority of the needs of its users. - -Libpng uses zlib for its compression and decompression of PNG files. -Further information about zlib, and the latest version of zlib, can -be found at the zlib home page, . -The zlib compression utility is a general purpose utility that is -useful for more than PNG files, and can be used without libpng. -See the documentation delivered with zlib for more details. -You can usually find the source files for the zlib utility wherever you -find the libpng source files. - -Libpng is thread safe, provided the threads are using different -instances of the structures. Each thread should have its own -png_struct and png_info instances, and thus its own image. -Libpng does not protect itself against two threads using the -same instance of a structure. - -.SH II. Structures - -There are two main structures that are important to libpng, png_struct -and png_info. The first, png_struct, is an internal structure that -will not, for the most part, be used by a user except as the first -variable passed to every libpng function call. - -The png_info structure is designed to provide information about the -PNG file. At one time, the fields of png_info were intended to be -directly accessible to the user. However, this tended to cause problems -with applications using dynamically loaded libraries, and as a result -a set of interface functions for png_info (the png_get_*() and png_set_*() -functions) was developed. The fields of png_info are still available for -older applications, but it is suggested that applications use the new -interfaces if at all possible. - -Applications that do make direct access to the members of png_struct (except -for png_ptr->jmpbuf) must be recompiled whenever the library is updated, -and applications that make direct access to the members of png_info must -be recompiled if they were compiled or loaded with libpng version 1.0.6, -in which the members were in a different order. In version 1.0.7, the -members of the png_info structure reverted to the old order, as they were -in versions 0.97c through 1.0.5. Starting with version 2.0.0, both -structures are going to be hidden, and the contents of the structures will -only be accessible through the png_get/png_set functions. - -The png.h header file is an invaluable reference for programming with libpng. -And while I'm on the topic, make sure you include the libpng header file: - -#include - -.SH III. Reading - -We'll now walk you through the possible functions to call when reading -in a PNG file sequentially, briefly explaining the syntax and purpose -of each one. See example.c and png.h for more detail. While -progressive reading is covered in the next section, you will still -need some of the functions discussed in this section to read a PNG -file. - -.SS Setup - -You will want to do the I/O initialization(*) before you get into libpng, -so if it doesn't work, you don't have much to undo. Of course, you -will also want to insure that you are, in fact, dealing with a PNG -file. Libpng provides a simple check to see if a file is a PNG file. -To use it, pass in the first 1 to 8 bytes of the file to the function -png_sig_cmp(), and it will return 0 (false) if the bytes match the -corresponding bytes of the PNG signature, or nonzero (true) otherwise. -Of course, the more bytes you pass in, the greater the accuracy of the -prediction. - -If you are intending to keep the file pointer open for use in libpng, -you must ensure you don't read more than 8 bytes from the beginning -of the file, and you also have to make a call to png_set_sig_bytes_read() -with the number of bytes you read from the beginning. Libpng will -then only check the bytes (if any) that your program didn't read. - -(*): If you are not using the standard I/O functions, you will need -to replace them with custom functions. See the discussion under -Customizing libpng. - - - FILE *fp = fopen(file_name, "rb"); - if (!fp) - { - return (ERROR); - } - fread(header, 1, number, fp); - is_png = !png_sig_cmp(header, 0, number); - if (!is_png) - { - return (NOT_PNG); - } - - -Next, png_struct and png_info need to be allocated and initialized. In -order to ensure that the size of these structures is correct even with a -dynamically linked libpng, there are functions to initialize and -allocate the structures. We also pass the library version, optional -pointers to error handling functions, and a pointer to a data struct for -use by the error functions, if necessary (the pointer and functions can -be NULL if the default error handlers are to be used). See the section -on Changes to Libpng below regarding the old initialization functions. -The structure allocation functions quietly return NULL if they fail to -create the structure, so your application should check for that. - - png_structp png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, - (png_infopp)NULL, (png_infopp)NULL); - return (ERROR); - } - - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_read_struct_2() instead of png_create_read_struct(): - - png_structp png_ptr = png_create_read_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -The error handling routines passed to png_create_read_struct() -and the memory alloc/free routines passed to png_create_struct_2() -are only necessary if you are not using the libpng supplied error -handling and memory alloc/free functions. - -When libpng encounters an error, it expects to longjmp back -to your routine. Therefore, you will need to call setjmp and pass -your png_jmpbuf(png_ptr). If you read the file from different -routines, you will need to update the jmpbuf field every time you enter -a new routine that will call a png_*() function. - -See your documentation of setjmp/longjmp for your compiler for more -information on setjmp/longjmp. See the discussion on libpng error -handling in the Customizing Libpng section below for more information -on the libpng error handling. If an error occurs, and libpng longjmp's -back to your setjmp, you will want to call png_destroy_read_struct() to -free any memory. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - fclose(fp); - return (ERROR); - } - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the input code. The default for libpng is to -use the C function fread(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. If you wish to handle reading data in another -way, you need not call the png_init_io() function, but you must then -implement the libpng I/O methods discussed in the Customizing Libpng -section below. - - png_init_io(png_ptr, fp); - -If you had previously opened the file and read any of the signature from -the beginning in order to see if this was a PNG file, you need to let -libpng know that there are some bytes missing from the start of the file. - - png_set_sig_bytes(png_ptr, number); - -.SS Setting up callback code - -You can set up a callback function to handle any unknown chunks in the -input stream. You must supply the function - - read_chunk_callback(png_ptr ptr, - png_unknown_chunkp chunk); - { - /* The unknown chunk structure contains your - chunk data, along with similar data for any other - unknown chunks: */ - - png_byte name[5]; - png_byte *data; - png_size_t size; - - /* Note that libpng has already taken care of - the CRC handling */ - - /* put your code here. Search for your chunk in the - unknown chunk structure, process it, and return one - of the following: */ - - return (\-n); /* chunk had an error */ - return (0); /* did not recognize */ - return (n); /* success */ - } - -(You can give your function another name that you like instead of -"read_chunk_callback") - -To inform libpng about your function, use - - png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, - read_chunk_callback); - -This names not only the callback function, but also a user pointer that -you can retrieve with - - png_get_user_chunk_ptr(png_ptr); - -If you call the png_set_read_user_chunk_fn() function, then all unknown -chunks will be saved when read, in case your callback function will need -one or more of them. This behavior can be changed with the -png_set_keep_unknown_chunks() function, described below. - -At this point, you can set up a callback function that will be -called after each row has been read, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void read_row_callback(png_ptr ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "read_row_callback") - -To inform libpng about your function, use - - png_set_read_status_fn(png_ptr, read_row_callback); - -.SS Unknown-chunk handling - -Now you get to set the way the library processes unknown chunks in the -input PNG stream. Both known and unknown chunks will be read. Normal -behavior is that known chunks will be parsed into information in -various info_ptr members while unknown chunks will be discarded. This -behavior can be wasteful if your application will never use some known -chunk types. To change this, you can call: - - png_set_keep_unknown_chunks(png_ptr, keep, - chunk_list, num_chunks); - keep - 0: default unknown chunk handling - 1: ignore; do not keep - 2: keep only if safe-to-copy - 3: keep even if unsafe-to-copy - You can use these definitions: - PNG_HANDLE_CHUNK_AS_DEFAULT 0 - PNG_HANDLE_CHUNK_NEVER 1 - PNG_HANDLE_CHUNK_IF_SAFE 2 - PNG_HANDLE_CHUNK_ALWAYS 3 - chunk_list - list of chunks affected (a byte string, - five bytes per chunk, NULL or '\0' if - num_chunks is 0) - num_chunks - number of chunks affected; if 0, all - unknown chunks are affected. If nonzero, - only the chunks in the list are affected - -Unknown chunks declared in this way will be saved as raw data onto a -list of png_unknown_chunk structures. If a chunk that is normally -known to libpng is named in the list, it will be handled as unknown, -according to the "keep" directive. If a chunk is named in successive -instances of png_set_keep_unknown_chunks(), the final instance will -take precedence. The IHDR and IEND chunks should not be named in -chunk_list; if they are, libpng will process them normally anyway. - -Here is an example of the usage of png_set_keep_unknown_chunks(), -where the private "vpAg" chunk will later be processed by a user chunk -callback function: - - png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - png_byte unused_chunks[]= - { - 104, 73, 83, 84, (png_byte) '\0', /* hIST */ - 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ - 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ - 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ - 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ - 116, 73, 77, 69, (png_byte) '\0', /* tIME */ - }; - #endif - - ... - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - /* ignore all unknown chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, NULL, 0); - /* except for vpAg: */ - png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); - /* also ignore unused known chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - #endif - -.SS User limits - -The PNG specification allows the width and height of an image to be as -large as 2^(31\-1 (0x7fffffff), or about 2.147 billion rows and columns. -Since very few applications really need to process such large images, -we have imposed an arbitrary 1-million limit on rows and columns. -Larger images will be rejected immediately with a png_error() call. If -you wish to override this limit, you can use - - png_set_user_limits(png_ptr, width_max, height_max); - -to set your own limits, or use width_max = height_max = 0x7fffffffL -to allow all valid dimensions (libpng may reject some very large images -anyway because of potential buffer overflow conditions). - -You should put this statement after you create the PNG structure and -before calling png_read_info(), png_read_png(), or png_process_data(). -If you need to retrieve the limits that are being applied, use - - width_max = png_get_user_width_max(png_ptr); - height_max = png_get_user_height_max(png_ptr); - -The PNG specification sets no limit on the number of ancillary chunks -allowed in a PNG datastream. You can impose a limit on the total number -of sPLT, tEXt, iTXt, zTXt, and unknown chunks that will be stored, with - - png_set_chunk_cache_max(png_ptr, user_chunk_cache_max); - -where 0x7fffffffL means unlimited. You can retrieve this limit with - - chunk_cache_max = png_get_chunk_cache_max(png_ptr); - -This limit also applies to the number of buffers that can be allocated -by png_decompress_chunk() while decompressing iTXt, zTXt, and iCCP chunks. - -.SS The high-level read interface - -At this point there are two ways to proceed; through the high-level -read interface, or through a sequence of low-level read operations. -You can use the high-level interface if (a) you are willing to read -the entire image into memory, and (b) the input transformations -you want to do are limited to the following set: - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to - 8 bits - PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel - PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit - samples to bytes - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_EXPAND Perform set_expand() - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples - to RGB (or GA to RGBA) - -(This excludes setting a background color, doing gamma transformation, -dithering, and setting filler.) If this is the case, simply do this: - - png_read_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of some -set of transformation flags. This call is equivalent to png_read_info(), -followed the set of transformations indicated by the transform mask, -then png_read_image(), and finally png_read_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future input transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_read_png(). - -After you have called png_read_png(), you can retrieve the image data -with - - row_pointers = png_get_rows(png_ptr, info_ptr); - -where row_pointers is an array of pointers to the pixel data for each row: - - png_bytep row_pointers[height]; - -If you know your image size and pixel size ahead of time, you can allocate -row_pointers prior to calling png_read_png() with - - if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) - png_error (png_ptr, - "Image is too tall to process in memory"); - if (width > PNG_UINT_32_MAX/pixel_size) - png_error (png_ptr, - "Image is too wide to process in memory"); - row_pointers = png_malloc(png_ptr, - height*png_sizeof(png_bytep)); - for (int i=0; i) and -png_get_(png_ptr, info_ptr, ...) functions return non-zero if the -data has been read, or zero if it is missing. The parameters to the -png_get_ are set directly if they are simple data types, or a -pointer into the info_ptr is returned for any complex types. - - png_get_PLTE(png_ptr, info_ptr, &palette, - &num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_get_gAMA(png_ptr, info_ptr, &gamma); - gamma - the gamma the file is written - at (PNG_INFO_gAMA) - - png_get_sRGB(png_ptr, info_ptr, &srgb_intent); - srgb_intent - the rendering intent (PNG_INFO_sRGB) - The presence of the sRGB chunk - means that the pixel data is in the - sRGB color space. This chunk also - implies specific values of gAMA and - cHRM. - - png_get_iCCP(png_ptr, info_ptr, &name, - &compression_type, &profile, &proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, - red, green, and blue channels, - whichever are appropriate for the - given color type (png_color_16) - - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, - &trans_values); - trans - array of transparent - entries for palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values of - the single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_get_hIST(png_ptr, info_ptr, &hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_get_tIME(png_ptr, info_ptr, &mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_get_bKGD(png_ptr, info_ptr, &background); - background - background color (PNG_VALID_bKGD) - valid 16-bit red, green and blue - values, regardless of color_type - - num_comments = png_get_text(png_ptr, info_ptr, - &text_ptr, &num_text); - num_comments - number of comments - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (empty - string for unknown). - text_ptr[i].lang_key - keyword in UTF-8 - (empty string for unknown). - Note that the itxt_length, lang, and lang_key - members of the text_ptr structure only exist - when the library is built with iTXt chunk support. - - num_text - number of comments (same as - num_comments; you can put NULL here - to avoid the duplication) - Note while png_set_text() will accept text, language, - and translated keywords that can be NULL pointers, the - structure returned by png_get_text will always contain - regular zero-terminated C strings. They might be - empty strings but they will never be NULL pointers. - - num_spalettes = png_get_sPLT(png_ptr, info_ptr, - &palette_ptr); - palette_ptr - array of palette structures holding - contents of one or more sPLT chunks - read. - num_spalettes - number of sPLT chunks read. - - png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, - &unit_type); - offset_x - positive offset from the left edge - of the screen - offset_y - positive offset from the top edge - of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, - &unit_type); - res_x - pixels/unit physical resolution in - x direction - res_y - pixels/unit physical resolution in - x direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_get_sCAL(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - num_unknown_chunks = png_get_unknown_chunks(png_ptr, - info_ptr, &unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position of chunk in file - - The value of "i" corresponds to the order in which the - chunks were read from the PNG file or inserted with the - png_set_unknown_chunks() function. - -The data from the pHYs chunk can be retrieved in several convenient -forms: - - res_x = png_get_x_pixels_per_meter(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_meter(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_meter(png_ptr, - info_ptr) - res_x = png_get_x_pixels_per_inch(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_inch(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_inch(png_ptr, - info_ptr) - aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, - info_ptr) - - (Each of these returns 0 [signifying "unknown"] if - the data is not present or if res_x is 0; - res_x_and_y is 0 if res_x != res_y) - -The data from the oFFs chunk can be retrieved in several convenient -forms: - - x_offset = png_get_x_offset_microns(png_ptr, info_ptr); - y_offset = png_get_y_offset_microns(png_ptr, info_ptr); - x_offset = png_get_x_offset_inches(png_ptr, info_ptr); - y_offset = png_get_y_offset_inches(png_ptr, info_ptr); - - (Each of these returns 0 [signifying "unknown" if both - x and y are 0] if the data is not present or if the - chunk is present but the unit is the pixel) - -For more information, see the png_info definition in png.h and the -PNG specification for chunk contents. Be careful with trusting -rowbytes, as some of the transformations could increase the space -needed to hold a row (expand, filler, gray_to_rgb, etc.). -See png_read_update_info(), below. - -A quick word about text_ptr and num_text. PNG stores comments in -keyword/text pairs, one pair per chunk, with no limit on the number -of text chunks, and a 2^31 byte limit on their size. While there are -suggested keywords, there is no requirement to restrict the use to these -strings. It is strongly suggested that keywords and text be sensible -to humans (that's the point), so don't use abbreviations. Non-printing -symbols are not allowed. See the PNG specification for more details. -There is also no requirement to have text after the keyword. - -Keywords should be limited to 79 Latin-1 characters without leading or -trailing spaces, but non-consecutive spaces are allowed within the -keyword. It is possible to have the same keyword any number of times. -The text_ptr is an array of png_text structures, each holding a -pointer to a language string, a pointer to a keyword and a pointer to -a text string. The text string, language code, and translated -keyword may be empty or NULL pointers. The keyword/text -pairs are put into the array in the order that they are received. -However, some or all of the text chunks may be after the image, so, to -make sure you have read all the text chunks, don't mess with these -until after you read the stuff after the image. This will be -mentioned again below in the discussion that goes with png_read_end(). - -.SS Input transformations - -After you've read the header information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -The colors used for the background and transparency values should be -supplied in the same format/depth as the current image data. They -are stored in the same format/depth as the image data in a bKGD or tRNS -chunk, so this is what libpng expects for this data. The colors are -transformed to keep in sync with the image data when an application -calls the png_read_update_info() routine (see below). - -Data will be decoded into the supplied row buffers packed into bytes -unless the library has been told to transform it into another format. -For example, 4 bit/pixel paletted or grayscale data will be returned -2 pixels/byte with the leftmost pixel in the high-order bits of the -byte, unless png_set_packing() is called. 8-bit RGB data will be stored -in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() -is called to insert filler bytes, either before or after each RGB triplet. -16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant -byte of the color value first, unless png_set_strip_16() is called to -transform it to regular RGB RGB triplets, or png_set_filler() or -png_set_add alpha() is called to insert filler bytes, either before or -after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can -be modified with -png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). - -The following code transforms grayscale images of less than 8 to 8 bits, -changes paletted images to RGB, and adds a full alpha channel if there is -transparency information in a tRNS chunk. This is most useful on -grayscale images with bit depths of 2 or 4 or if there is a multiple-image -viewing application that wishes to treat all images in the same way. - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && - bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); - - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); - -These three functions are actually aliases for png_set_expand(), added -in libpng version 1.0.4, with the function names expanded to improve code -readability. In some future version they may actually do different -things. - -As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was -added. It expands the sample depth without changing tRNS to alpha. - -As of libpng version 1.2.51, not all possible expansions are supported. - -In the following table, the 01 means grayscale with depth<8, 31 means -indexed with depth<8, other numerals represent the color type, "T" means -the tRNS chunk is present, A means an alpha channel is present, and O -means tRNS or alpha is present but all pixels in the image are opaque. - - FROM 01 31 0 0T 0O 2 2T 2O 3 3T 3O 4A 4O 6A 6O - TO - 01 - - 31 - - 0 1 - - 0T - - 0O - - 2 GX - - 2T - - 2O - - 3 1 - - 3T - - 3O - - 4A T - - 4O - - 6A GX TX TX - - 6O GX TX - - -Within the matrix, - "-" means the transformation is not supported. - "X" means the transformation is obtained by png_set_expand(). - "1" means the transformation is obtained by - png_set_expand_gray_1_2_4_to_8 - "G" means the transformation is obtained by - png_set_gray_to_rgb(). - "P" means the transformation is obtained by - png_set_expand_palette_to_rgb(). - "T" means the transformation is obtained by - png_set_tRNS_to_alpha(). - -PNG can have files with 16 bits per channel. If you only can handle -8 bits per channel, this will strip the pixels down to 8 bit. - - if (bit_depth == 16) - png_set_strip_16(png_ptr); - -If, for some reason, you don't need the alpha channel on an image, -and you want to remove it rather than combining it with the background -(but the image author certainly had in mind that you *would* combine -it with the background, so that's what you should probably do): - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(png_ptr); - -In PNG files, the alpha channel in an image -is the level of opacity. If you need the alpha channel in an image to -be the level of transparency instead of opacity, you can invert the -alpha channel (or the tRNS chunk data) after it's read, so that 0 is -fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit -images) is fully transparent, with - - png_set_invert_alpha(png_ptr); - -The PNG format only supports pixels with postmultiplied alpha. -If you want to replace the pixels, after reading them, with pixels -that have premultiplied color samples, you can do this with - - png_set_premultiply_alpha(png_ptr); - -If you do this, any input with a tRNS chunk will be expanded to -have an alpha channel. - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit -files. This code expands to 1 pixel per byte without changing the -values of the pixels: - - if (bit_depth < 8) - png_set_packing(png_ptr); - -PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels -stored in a PNG image have been "scaled" or "shifted" up to the next -higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] -to 8 bits/sample in the range [0, 255]). However, it is also possible -to convert the PNG pixel data back to the original bit depth of the -image. This call reduces the pixels back down to the original bit depth: - - png_color_8p sig_bit; - - if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) - png_set_shift(png_ptr, sig_bit); - -PNG files store 3-color pixels in red, green, blue order. This code -changes the storage of the pixels to blue, green, red: - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_bgr(png_ptr); - -PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them -into 4 or 8 bytes for windowing systems that need them in this format: - - if (color_type == PNG_COLOR_TYPE_RGB) - png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); - -where "filler" is the 8 or 16-bit number to fill with, and the location is -either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether -you want the filler before the RGB or after. This transformation -does not affect images that already have full alpha channels. To add an -opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which -will generate RGBA pixels. - -Note that png_set_filler() does not change the color type. If you want -to do that, you can add a true alpha channel with - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY) - png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); - -where "filler" contains the alpha value to assign to each pixel. -This function was added in libpng-1.2.7. - -If you are reading an image with an alpha channel, and you need the -data as ARGB instead of the normal PNG format RGBA: - - if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_swap_alpha(png_ptr); - -For some uses, you may want a grayscale image to be represented as -RGB. This code will do that conversion: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - -Conversely, you can convert an RGB or RGBA image to grayscale or grayscale -with alpha. - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, error_action, - int red_weight, int green_weight); - - error_action = 1: silently do the conversion - error_action = 2: issue a warning if the original - image has any pixel where - red != green or red != blue - error_action = 3: issue an error and abort the - conversion if the original - image has any pixel where - red != green or red != blue - - red_weight: weight of red component times 100000 - green_weight: weight of green component times 100000 - If either weight is negative, default - weights (21268, 71514) are used. - -If you have set error_action = 1 or 2, you can -later check whether the image really was gray, after processing -the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. -It will return a png_byte that is zero if the image was gray or -1 if there were any non-gray pixels. bKGD and sBIT data -will be silently converted to grayscale, using the green channel -data, regardless of the error_action setting. - -With red_weight+green_weight<=100000, -the normalized graylevel is computed: - - int rw = red_weight * 65536; - int gw = green_weight * 65536; - int bw = 65536 - (rw + gw); - gray = (rw*red + gw*green + bw*blue)/65536; - -The default values approximate those recommended in the Charles -Poynton's Color FAQ, -Copyright (c) 1998-01-04 Charles Poynton - - Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - -Libpng approximates this with - - Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - -which can be expressed with integers as - - Y = (6969 * R + 23434 * G + 2365 * B)/32768 - -The calculation is done in a linear colorspace, if the image gamma -is known. - -If you have a grayscale and you are using png_set_expand_depth(), -png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to -a higher bit-depth, you must either supply the background color as a gray -value at the original file bit-depth (need_expand = 1) or else supply the -background color as an RGB triplet at the final, expanded bit depth -(need_expand = 0). Similarly, if you are reading a paletted image, you -must either supply the background color as a palette index (need_expand = 1) -or as an RGB triplet that may or may not be in the palette (need_expand = 0). - - png_color_16 my_background; - png_color_16p image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - -The png_set_background() function tells libpng to composite images -with alpha or simple transparency against the supplied background -color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), -you may use this color, or supply another color more suitable for -the current display (e.g., the background color from a web page). You -need to tell libpng whether the color is in the gamma space of the -display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file -(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one -that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't -know why anyone would use this, but it's here). - -To properly display PNG images on any kind of system, the application needs -to know what the display gamma is. Ideally, the user will know this, and -the application will allow them to set it. One method of allowing the user -to set the display gamma separately for each system is to check for a -SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be -correctly set. - -Note that display_gamma is the overall gamma correction required to produce -pleasing results, which depends on the lighting conditions in the surrounding -environment. In a dim or brightly lit room, no compensation other than -the physical gamma exponent of the monitor is needed, while in a dark room -a slightly smaller exponent is better. - - double gamma, screen_gamma; - - if (/* We have a user-defined screen - gamma value */) - { - screen_gamma = user_defined_screen_gamma; - } - /* One way that applications can share the same - screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) - != NULL) - { - screen_gamma = (double)atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a - PC monitor in a bright office or a dim room */ - screen_gamma = 2.0; /* A good guess for a - PC monitor in a dark room */ - screen_gamma = 1.7 or 1.0; /* A good - guess for Mac systems */ - } - -The png_set_gamma() function handles gamma transformations of the data. -Pass both the file gamma and the current screen_gamma. If the file does -not have a gamma value, you can pass one anyway if you have an idea what -it is (usually 0.45455 is a good guess for GIF images on PCs). Note -that file gammas are inverted from screen gammas. See the discussions -on gamma in the PNG specification for an excellent description of what -gamma is, and why all applications should support it. It is strongly -recommended that PNG viewers support gamma correction. - - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma(png_ptr, screen_gamma, gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - -If you need to reduce an RGB file to a paletted file, or if a paletted -file has more entries then will fit on your screen, png_set_dither() -will do that. Note that this is a simple match dither that merely -finds the closest color available. This should work fairly well with -optimized palettes, and fairly badly with linear color cubes. If you -pass a palette that is larger then maximum_colors, the file will -reduce the number of colors in the palette so it will fit into -maximum_colors. If there is a histogram, it will use it to make -more intelligent choices when reducing the palette. If there is no -histogram, it may not do as good a job. - - if (color_type & PNG_COLOR_MASK_COLOR) - { - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_PLTE)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, - &histogram); - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 1); - } - else - { - png_color std_color_cube[MAX_SCREEN_COLORS] = - { ... colors ... }; - - png_set_dither(png_ptr, std_color_cube, - MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, - NULL,0); - } - } - -PNG files describe monochrome as black being zero and white being one. -The following code will reverse this (make black be one and white be -zero): - - if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) - png_set_invert_mono(png_ptr); - -This function can also be used to invert grayscale and gray-alpha images: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_invert_mono(png_ptr); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code changes the storage to the -other way (little-endian, i.e. least significant bits first, the -way PCs store them): - - if (bit_depth == 16) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_read_user_transform_fn(png_ptr, - read_transform_fn); - -You must supply the function - - void read_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -after all of the other transformations have been processed. - -You can also set up a pointer to a user structure for use by your -callback function, and you can inform libpng that your transform -function will change the number of channels or bit depth with the -function - - png_set_user_transform_info(png_ptr, user_ptr, - user_depth, user_channels); - -The user's application, not libpng, is responsible for allocating and -freeing any memory required for the user structure. - -You can retrieve the pointer via the function -png_get_user_transform_ptr(). For example: - - voidp read_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -The last thing to handle is interlacing; this is covered in detail below, -but you must call the function here if you want libpng to handle expansion -of the interlaced image. - - number_of_passes = png_set_interlace_handling(png_ptr); - -After setting the transformations, libpng can update your png_info -structure to reflect any transformations you've requested with this -call. This is most useful to update the info structure's rowbytes -field so you can use it to allocate your image memory. This function -will also update your palette with the correct screen_gamma and -background if these have been given with the calls above. - - png_read_update_info(png_ptr, info_ptr); - -After you call png_read_update_info(), you can allocate any -memory you need to hold the image. The row data is simply -raw byte data for all forms of images. As the actual allocation -varies among applications, no example will be given. If you -are allocating one large chunk, you will need to build an -array of pointers to each row, as it will be needed for some -of the functions below. - -.SS Reading image data - -After you've allocated memory, you can read the image data. -The simplest way to do this is in one function call. If you are -allocating enough memory to hold the whole image, you can just -call png_read_image() and libpng will read in all the image data -and put it in the memory area supplied. You will need to pass in -an array of pointers to each row. - -This function automatically handles interlacing, so you don't need -to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_read_rows(). - - png_read_image(png_ptr, row_pointers); - -where row_pointers is: - - png_bytep row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to read in the whole image at once, you can -use png_read_rows() instead. If there is no interlacing (check -interlace_type == PNG_INTERLACE_NONE), this is simple: - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -where row_pointers is the same as in the png_read_image() call. - -If you are doing this just one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - png_read_row(png_ptr, row_pointer, NULL); - -If the file is interlaced (interlace_type != 0 in the IHDR chunk), things -get somewhat harder. The only current (PNG Specification version 1.2) -interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) -is a somewhat complicated 2D interlace scheme, known as Adam7, that -breaks down an image into seven smaller images of varying size, based -on an 8x8 grid. - -libpng can fill out those images or it can give them to you "as is". -If you want them filled out, there are two ways to do that. The one -mentioned in the PNG specification is to expand each pixel to cover -those pixels that have not been read yet (the "rectangle" method). -This results in a blocky image for the first pass, which gradually -smooths out as more pixels are read. The other method is the "sparkle" -method, where pixels are drawn only in their final locations, with the -rest of the image remaining whatever colors they were initialized to -before the start of the read. The first method usually looks better, -but tends to be slower, as there are more pixels to put in the rows. - -If you don't want libpng to handle the interlacing details, just call -png_read_rows() seven times to read in all seven images. Each of the -images is a valid image by itself, or they can all be combined on an -8x8 grid to form a single image (although if you intend to combine them -you would be far better off using the libpng interlace handling). - -The first pass will return an image 1/8 as wide as the entire image -(every 8th column starting in column 0) and 1/8 as high as the original -(every 8th row starting in row 0), the second will be 1/8 as wide -(starting in column 4) and 1/8 as high (also starting in row 0). The -third pass will be 1/4 as wide (every 4th pixel starting in column 0) and -1/8 as high (every 8th row starting in row 4), and the fourth pass will -be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, -and every 4th row starting in row 0). The fifth pass will return an -image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), -while the sixth pass will be 1/2 as wide and 1/2 as high as the original -(starting in column 1 and row 0). The seventh and final pass will be as -wide as the original, and 1/2 as high, containing all of the odd -numbered scanlines. Phew! - -If you want libpng to expand the images, call this before calling -png_start_read_image() or png_read_update_info(): - - if (interlace_type == PNG_INTERLACE_ADAM7) - number_of_passes - = png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this -is seven, but may change if another interlace type is added. -This function can be called even if the file is not interlaced, -where it will return one pass. - -If you are not going to display the image after each pass, but are -going to wait until the entire image is read in, use the sparkle -effect. This effect is faster and the end result of either method -is exactly the same. If you are planning on displaying the image -after each pass, the "rectangle" effect is generally considered the -better looking one. - -If you only want the "sparkle" effect, just call png_read_rows() as -normal, with the third parameter NULL. Make sure you make pass over -the image number_of_passes times, and you don't change the data in the -rows between calls. You can change the locations of the data, just -not the data. Each pass only writes the pixels appropriate for that -pass, and assumes the data from previous passes is still valid. - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -If you only want the first effect (the rectangles), do the same as -before except pass the row buffer in the third parameter, and leave -the second parameter NULL. - - png_read_rows(png_ptr, NULL, row_pointers, - number_of_rows); - -.SS Finishing a sequential read - -After you are finished reading the image through the -low-level interface, you can finish reading the file. If you are -interested in comments or time, which may be stored either before or -after the image data, you should pass the separate png_info struct if -you want to keep the comments from before and after the image -separate. If you are not interested, you can pass NULL. - - png_read_end(png_ptr, end_info); - -When you are done, you can free all memory allocated by libpng like this: - - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (\-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. -The "seq" parameter is ignored if only one item of the selected data -type, such as PLTE, is allowed. If "seq" is not \-1, and multiple items -are allowed for the data type identified in the mask, such as text or -sPLT, only the n'th item in the structure is freed, where n is "seq". - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -This function only affects data that has already been allocated. -You can call this function after reading the PNG data but before calling -any png_set_*() functions, to control whether the user or the png_set_*() -function is responsible for freeing any existing data that might be present, -and again after the png_set_*() functions to control whether the user -or png_destroy_*() is supposed to free the data. When the user assumes -responsibility for libpng-allocated data, the application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated your row_pointers in a single block, as suggested above in -the description of the high level read interface, you must not transfer -responsibility for freeing it to the png_set_rows or png_read_destroy function, -because they would also try to free the individual row_pointers[i]. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. - -The png_free_data() function will turn off the "valid" flag for anything -it frees. If you need to turn the flag off for a chunk that was freed by -your application instead of by libpng, you can use - - png_set_invalid(png_ptr, info_ptr, mask); - mask - identifies the chunks to be made invalid, - containing the bitwise OR of one or - more of - PNG_INFO_gAMA, PNG_INFO_sBIT, - PNG_INFO_cHRM, PNG_INFO_PLTE, - PNG_INFO_tRNS, PNG_INFO_bKGD, - PNG_INFO_hIST, PNG_INFO_pHYs, - PNG_INFO_oFFs, PNG_INFO_tIME, - PNG_INFO_pCAL, PNG_INFO_sRGB, - PNG_INFO_iCCP, PNG_INFO_sPLT, - PNG_INFO_sCAL, PNG_INFO_IDAT - -For a more compact example of reading a PNG image, see the file example.c. - -.SS Reading PNG files progressively - -The progressive reader is slightly different then the non-progressive -reader. Instead of calling png_read_info(), png_read_rows(), and -png_read_end(), you make one call to png_process_data(), which calls -callbacks when it has the info, a row, or the end of the image. You -set up these callbacks with png_set_progressive_read_fn(). You don't -have to worry about the input/output functions of libpng, as you are -giving the library the data directly in png_process_data(). I will -assume that you have read the section on reading PNG files above, -so I will only highlight the differences (although I will show -all of the code). - -png_structp png_ptr; -png_infop info_ptr; - - /* An example code fragment of how you would - initialize the progressive reader in your - application. */ - int - initialize_png_reader() - { - png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, - (png_infopp)NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new. You can provide functions - to be called when the header info is valid, - when each row is completed, and when the image - is finished. If you aren't using all functions, - you can specify NULL parameters. Even when all - three functions are NULL, you need to call - png_set_progressive_read_fn(). You can use - any struct as the user_ptr (cast to a void pointer - for the function call), and retrieve the pointer - from inside the callbacks using the function - - png_get_progressive_ptr(png_ptr); - - which will return a void pointer, which you have - to cast appropriately. - */ - png_set_progressive_read_fn(png_ptr, (void *)user_ptr, - info_callback, row_callback, end_callback); - - return 0; - } - - /* A code fragment that you call as you receive blocks - of data */ - int - process_data(png_bytep buffer, png_uint_32 length) - { - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new also. Simply give it a chunk - of data from the file stream (in order, of - course). On machines with segmented memory - models machines, don't give it any more than - 64K. The library seems to run fine with sizes - of 4K. Although you can give it much less if - necessary (I assume you can give it chunks of - 1 byte, I haven't tried less then 256 bytes - yet). When this function returns, you may - want to display any rows that were generated - in the row callback if you don't already do - so there. - */ - png_process_data(png_ptr, info_ptr, buffer, length); - return 0; - } - - /* This function is called (as set by - png_set_progressive_read_fn() above) when enough data - has been supplied so all of the header has been - read. - */ - void - info_callback(png_structp png_ptr, png_infop info) - { - /* Do any setup here, including setting any of - the transformations mentioned in the Reading - PNG files section. For now, you _must_ call - either png_start_read_image() or - png_read_update_info() after all the - transformations are set (even if you don't set - any). You may start getting rows before - png_process_data() returns, so this is your - last chance to prepare for that. - */ - } - - /* This function is called when each row of image - data is complete */ - void - row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) - { - /* If the image is interlaced, and you turned - on the interlace handler, this function will - be called for every row in every pass. Some - of these rows will not be changed from the - previous pass. When the row is not changed, - the new_row variable will be NULL. The rows - and passes are called in order, so you don't - really need the row_num and pass, but I'm - supplying them because it may make your life - easier. - - For the non-NULL rows of interlaced images, - you must call png_progressive_combine_row() - passing in the row and the old row. You can - call this function for NULL rows (it will just - return) and for non-interlaced images (it just - does the memcpy for you) if it will make the - code easier. Thus, you can just do this for - all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, - new_row); - - /* where old_row is what was displayed for - previously for the row. Note that the first - pass (pass == 0, really) will completely cover - the old row, so the rows do not have to be - initialized. After the first pass (and only - for interlaced images), you will have to pass - the current row, and the function will combine - the old row and the new row. - */ - } - - void - end_callback(png_structp png_ptr, png_infop info) - { - /* This function is called after the whole image - has been read, including any chunks after the - image (up to and including the IEND). You - will usually have the same info chunk as you - had in the header, although some data may have - been added to the comments and time fields. - - Most people won't do much here, perhaps setting - a flag that marks the image as finished. - */ - } - - - -.SH IV. Writing - -Much of this is very similar to reading. However, everything of -importance is repeated here, so you won't have to constantly look -back up in the reading section to understand writing. - -.SS Setup - -You will want to do the I/O initialization before you get into libpng, -so if it doesn't work, you don't have anything to undo. If you are not -using the standard I/O functions, you will need to replace them with -custom writing functions. See the discussion under Customizing libpng. - - FILE *fp = fopen(file_name, "wb"); - if (!fp) - { - return (ERROR); - } - -Next, png_struct and png_info need to be allocated and initialized. -As these can be both relatively large, you may not want to store these -on the stack, unless you have stack space to spare. Of course, you -will want to check if they return NULL. If you are also reading, -you won't want to name your read structure and your write structure -both "png_ptr"; you can call them anything you like, such as -"read_ptr" and "write_ptr". Look at pngtest.c, for example. - - png_structp png_ptr = png_create_write_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_write_struct(&png_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_write_struct_2() instead of png_create_write_struct(): - - png_structp png_ptr = png_create_write_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -After you have these structures, you will need to set up the -error handling. When libpng encounters an error, it expects to -longjmp() back to your routine. Therefore, you will need to call -setjmp() and pass the png_jmpbuf(png_ptr). If you -write the file from different routines, you will need to update -the png_jmpbuf(png_ptr) every time you enter a new routine that will -call a png_*() function. See your documentation of setjmp/longjmp -for your compiler for more information on setjmp/longjmp. See -the discussion on libpng error handling in the Customizing Libpng -section below for more information on the libpng error handling. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return (ERROR); - } - ... - return; - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the output code. The default for libpng is to -use the C function fwrite(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. Again, if you wish to handle writing data in -another way, see the discussion on libpng I/O handling in the Customizing -Libpng section below. - - png_init_io(png_ptr, fp); - -If you are embedding your PNG into a datastream such as MNG, and don't -want libpng to write the 8-byte signature, or if you have already -written the signature in your application, use - - png_set_sig_bytes(png_ptr, 8); - -to inform libpng that it should not write a signature. - -.SS Write callbacks - -At this point, you can set up a callback function that will be -called after each row has been written, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void write_row_callback(png_ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "write_row_callback") - -To inform libpng about your function, use - - png_set_write_status_fn(png_ptr, write_row_callback); - -You now have the option of modifying how the compression library will -run. The following functions are mainly for testing, but may be useful -in some cases, like if you need to write PNG files extremely fast and -are willing to give up some compression, or if you want to get the -maximum possible compression at the expense of slower writing. If you -have no special needs in this area, let the library do what it wants by -not calling this function at all, as it has been tuned to deliver a good -speed/compression ratio. The second parameter to png_set_filter() is -the filter method, for which the only valid values are 0 (as of the -July 1999 PNG specification, version 1.2) or 64 (if you are writing -a PNG datastream that is to be embedded in a MNG datastream). The third -parameter is a flag that indicates which filter type(s) are to be tested -for each scanline. See the PNG specification for details on the specific -filter types. - - - /* turn on or off filtering, and/or choose - specific filters. You can use either a single - PNG_FILTER_VALUE_NAME or the bitwise OR of one - or more PNG_FILTER_NAME masks. */ - png_set_filter(png_ptr, 0, - PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | - PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | - PNG_FILTER_UP | PNG_FILTER_VALUE_UP | - PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | - PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| - PNG_ALL_FILTERS); - -If an application -wants to start and stop using particular filters during compression, -it should start out with all of the filters (to ensure that the previous -row of pixels will be stored in case it's needed later), and then add -and remove them after the start of compression. - -If you are writing a PNG datastream that is to be embedded in a MNG -datastream, the second parameter can be either 0 or 64. - -The png_set_compression_*() functions interface to the zlib compression -library, and should mostly be ignored unless you really know what you are -doing. The only generally useful call is png_set_compression_level() -which changes how much time zlib spends on trying to compress the image -data. See the Compression Library (zlib.h and algorithm.txt, distributed -with zlib) for details on the compression levels. - - /* set the zlib compression level */ - png_set_compression_level(png_ptr, - Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr, - Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192) - -extern PNG_EXPORT(void,png_set_zbuf_size) - -.SS Setting the contents of info for output - -You now need to fill in the png_info structure with all the data you -wish to write before the actual image. Note that the only thing you -are allowed to write after the image is the text chunks and the time -chunk (as of PNG Specification 1.2, anyway). See png_write_end() and -the latest PNG specification for more information on that. If you -wish to write them before the image, fill them in now, and flag that -data as being valid. If you want to wait until after the data, don't -fill them until png_write_end(). For all the fields in png_info and -their data types, see png.h. For explanations of what the fields -contain, see the PNG specification. - -Some of the more important parts of the png_info are: - - png_set_IHDR(png_ptr, info_ptr, width, height, - bit_depth, color_type, interlace_type, - compression_type, filter_method) - width - holds the width of the image - in pixels (up to 2^31). - height - holds the height of the image - in pixels (up to 2^31). - bit_depth - holds the bit depth of one of the - image channels. - (valid values are 1, 2, 4, 8, 16 - and depend also on the - color_type. See also significant - bits (sBIT) below). - color_type - describes which color/alpha - channels are present. - PNG_COLOR_TYPE_GRAY - (bit depths 1, 2, 4, 8, 16) - PNG_COLOR_TYPE_GRAY_ALPHA - (bit depths 8, 16) - PNG_COLOR_TYPE_PALETTE - (bit depths 1, 2, 4, 8) - PNG_COLOR_TYPE_RGB - (bit_depths 8, 16) - PNG_COLOR_TYPE_RGB_ALPHA - (bit_depths 8, 16) - - PNG_COLOR_MASK_PALETTE - PNG_COLOR_MASK_COLOR - PNG_COLOR_MASK_ALPHA - - interlace_type - PNG_INTERLACE_NONE or - PNG_INTERLACE_ADAM7 - compression_type - (must be - PNG_COMPRESSION_TYPE_DEFAULT) - filter_method - (must be PNG_FILTER_TYPE_DEFAULT - or, if you are writing a PNG to - be embedded in a MNG datastream, - can also be - PNG_INTRAPIXEL_DIFFERENCING) - -If you call png_set_IHDR(), the call must appear before any of the -other png_set_*() functions, because they might require access to some of -the IHDR settings. The remaining png_set_*() functions can be called -in any order. - -If you wish, you can reset the compression_type, interlace_type, or -filter_method later by calling png_set_IHDR() again; if you do this, the -width, height, bit_depth, and color_type must be the same in each call. - - png_set_PLTE(png_ptr, info_ptr, palette, - num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_set_gAMA(png_ptr, info_ptr, gamma); - gamma - the gamma the image was created - at (PNG_INFO_gAMA) - - png_set_sRGB(png_ptr, info_ptr, srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of - the sRGB chunk means that the pixel - data is in the sRGB color space. - This chunk also implies specific - values of gAMA and cHRM. Rendering - intent is the CSS-1 property that - has been defined by the International - Color Consortium - (http://www.color.org). - It can be one of - PNG_sRGB_INTENT_SATURATION, - PNG_sRGB_INTENT_PERCEPTUAL, - PNG_sRGB_INTENT_ABSOLUTE, or - PNG_sRGB_INTENT_RELATIVE. - - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, - srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of the - sRGB chunk means that the pixel - data is in the sRGB color space. - This function also causes gAMA and - cHRM chunks with the specific values - that are consistent with sRGB to be - written. - - png_set_iCCP(png_ptr, info_ptr, name, compression_type, - profile, proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_set_sBIT(png_ptr, info_ptr, sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, red, - green, and blue channels, whichever are - appropriate for the given color type - (png_color_16) - - png_set_tRNS(png_ptr, info_ptr, trans, num_trans, - trans_values); - trans - array of transparent - entries for palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values - (in order red, green, blue) of the - single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_set_hIST(png_ptr, info_ptr, hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_set_tIME(png_ptr, info_ptr, mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_set_bKGD(png_ptr, info_ptr, background); - background - background color (PNG_VALID_bKGD) - - png_set_text(png_ptr, info_ptr, text_ptr, num_text); - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be NULL or empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (NULL or - empty for unknown). - text_ptr[i].translated_keyword - keyword in UTF-8 (NULL - or empty for unknown). - Note that the itxt_length, lang, and lang_key - members of the text_ptr structure only exist - when the library is built with iTXt chunk support. - - num_text - number of comments - - png_set_sPLT(png_ptr, info_ptr, &palette_ptr, - num_spalettes); - palette_ptr - array of png_sPLT_struct structures - to be added to the list of palettes - in the info structure. - num_spalettes - number of palette structures to be - added. - - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, - unit_type); - offset_x - positive offset from the left - edge of the screen - offset_y - positive offset from the top - edge of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, - unit_type); - res_x - pixels/unit physical resolution - in x direction - res_y - pixels/unit physical resolution - in y direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_set_sCAL(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, - num_unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position to write chunk in file - 0: do not write chunk - PNG_HAVE_IHDR: before PLTE - PNG_HAVE_PLTE: before IDAT - PNG_AFTER_IDAT: after IDAT - -The "location" member is set automatically according to -what part of the output file has already been written. -You can change its value after calling png_set_unknown_chunks() -as demonstrated in pngtest.c. Within each of the "locations", -the chunks are sequenced according to their position in the -structure (that is, the value of "i", which is the order in which -the chunk was either read from the input file or defined with -png_set_unknown_chunks). - -A quick word about text and num_text. text is an array of png_text -structures. num_text is the number of valid structures in the array. -Each png_text structure holds a language code, a keyword, a text value, -and a compression type. - -The compression types have the same valid numbers as the compression -types of the image data. Currently, the only valid number is zero. -However, you can store text either compressed or uncompressed, unlike -images, which always have to be compressed. So if you don't want the -text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. -Because tEXt and zTXt chunks don't have a language field, if you -specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt -any language code or translated keyword will not be written out. - -Until text gets around 1000 bytes, it is not worth compressing it. -After the text has been written out to the file, the compression type -is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, -so that it isn't written out again at the end (in case you are calling -png_write_end() with the same struct. - -The keywords that are given in the PNG Specification are: - - Title Short (one line) title or - caption for image - Author Name of image's creator - Description Description of image (possibly long) - Copyright Copyright notice - Creation Time Time of original image creation - (usually RFC 1123 format, see below) - Software Software used to create the image - Disclaimer Legal disclaimer - Warning Warning of nature of content - Source Device used to create the image - Comment Miscellaneous comment; conversion - from other image format - -The keyword-text pairs work like this. Keywords should be short -simple descriptions of what the comment is about. Some typical -keywords are found in the PNG specification, as is some recommendations -on keywords. You can repeat keywords in a file. You can even write -some text before the image and some after. For example, you may want -to put a description of the image before the image, but leave the -disclaimer until after, so viewers working over modem connections -don't have to wait for the disclaimer to go over the modem before -they start seeing the image. Finally, keywords should be full -words, not abbreviations. Keywords and text are in the ISO 8859-1 -(Latin-1) character set (a superset of regular ASCII) and can not -contain NUL characters, and should not contain control or other -unprintable characters. To make the comments widely readable, stick -with basic ASCII, and avoid machine specific character set extensions -like the IBM-PC character set. The keyword must be present, but -you can leave off the text string on non-compressed pairs. -Compressed pairs must have a text string, as only the text string -is compressed anyway, so the compression would be meaningless. - -PNG supports modification time via the png_time structure. Two -conversion routines are provided, png_convert_from_time_t() for -time_t and png_convert_from_struct_tm() for struct tm. The -time_t routine uses gmtime(). You don't have to use either of -these, but if you wish to fill in the png_time structure directly, -you should provide the time in universal time (GMT) if possible -instead of your local time. Note that the year number is the full -year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and -that months start with 1. - -If you want to store the time of the original image creation, you should -use a plain tEXt chunk with the "Creation Time" keyword. This is -necessary because the "creation time" of a PNG image is somewhat vague, -depending on whether you mean the PNG file, the time the image was -created in a non-PNG format, a still photo from which the image was -scanned, or possibly the subject matter itself. In order to facilitate -machine-readable dates, it is recommended that the "Creation Time" -tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), -although this isn't a requirement. Unlike the tIME chunk, the -"Creation Time" tEXt chunk is not expected to be automatically changed -by the software. To facilitate the use of RFC 1123 dates, a function -png_convert_to_rfc1123(png_timep) is provided to convert from PNG -time to an RFC 1123 format string. - -.SS Writing unknown chunks - -You can use the png_set_unknown_chunks function to queue up chunks -for writing. You give it a chunk name, raw data, and a size; that's -all there is to it. The chunks will be written by the next following -png_write_info_before_PLTE, png_write_info, or png_write_end function. -Any chunks previously read into the info structure's unknown-chunk -list will also be written out in a sequence that satisfies the PNG -specification's ordering rules. - -.SS The high-level write interface - -At this point there are two ways to proceed; through the high-level -write interface, or through a sequence of low-level write operations. -You can use the high-level interface if your image data is present -in the info structure. All defined output -transformations are permitted, enabled by the following masks. - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - PNG_TRANSFORM_STRIP_FILLER Strip out filler - bytes (deprecated). - PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading - filler bytes - PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing - filler bytes - -If you have valid image data in the info structure (you can use -png_set_rows() to put image data in the info structure), simply do this: - - png_write_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of some set of -transformation flags. This call is equivalent to png_write_info(), -followed the set of transformations indicated by the transform mask, -then png_write_image(), and finally png_write_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future output transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_write_png(). - -.SS The low-level write interface - -If you are going the low-level route instead, you are now ready to -write all the file information up to the actual image data. You do -this with a call to png_write_info(). - - png_write_info(png_ptr, info_ptr); - -Note that there is one transformation you may need to do before -png_write_info(). In PNG files, the alpha channel in an image is the -level of opacity. If your data is supplied as a level of transparency, -you can invert the alpha channel before you write it, so that 0 is -fully transparent and 255 (in 8-bit or paletted images) or 65535 -(in 16-bit images) is fully opaque, with - - png_set_invert_alpha(png_ptr); - -This must appear before png_write_info() instead of later with the -other transformations because in the case of paletted images the tRNS -chunk data has to be inverted before the tRNS chunk is written. If -your image is not a paletted image, the tRNS data (which in such cases -represents a single color to be rendered as transparent) won't need to -be changed, and you can safely do this transformation after your -png_write_info() call. - -If you need to write a private chunk that you want to appear before -the PLTE chunk when PLTE is present, you can write the PNG info in -two steps, and insert code to write your own chunk between them: - - png_write_info_before_PLTE(png_ptr, info_ptr); - png_set_unknown_chunks(png_ptr, info_ptr, ...); - png_write_info(png_ptr, info_ptr); - -After you've written the file information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -PNG files store RGB pixels packed into 3 or 6 bytes. This code tells -the library to strip input data that has 4 or 8 bytes per pixel down -to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 -bytes per pixel). - - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - -where the 0 is unused, and the location is either PNG_FILLER_BEFORE or -PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel -is stored XRGB or RGBX. - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit files. -If the data is supplied at 1 pixel per byte, use this code, which will -correctly pack the pixels into a single byte: - - png_set_packing(png_ptr); - -PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your -data is of another bit depth, you can write an sBIT chunk into the -file so that decoders can recover the original data if desired. - - /* Set the true bit depth of the image data */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit.red = true_bit_depth; - sig_bit.green = true_bit_depth; - sig_bit.blue = true_bit_depth; - } - else - { - sig_bit.gray = true_bit_depth; - } - if (color_type & PNG_COLOR_MASK_ALPHA) - { - sig_bit.alpha = true_bit_depth; - } - - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - -If the data is stored in the row buffer in a bit depth other than -one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), -this will scale the values to appear to be the correct bit depth as -is required by PNG. - - png_set_shift(png_ptr, &sig_bit); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code would be used if they are -supplied the other way (little-endian, i.e. least significant bits -first, the way PCs store them): - - if (bit_depth > 8) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -PNG files store 3 color pixels in red, green, blue order. This code -would be used if they are supplied as blue, green, red: - - png_set_bgr(png_ptr); - -PNG files describe monochrome as black being zero and white being -one. This code would be used if the pixels are supplied with this reversed -(black being one and white being zero): - - png_set_invert_mono(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_write_user_transform_fn(png_ptr, - write_transform_fn); - -You must supply the function - - void write_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -before any of the other transformations are processed. - -You can also set up a pointer to a user structure for use by your -callback function. - - png_set_user_transform_info(png_ptr, user_ptr, 0, 0); - -The user_channels and user_depth parameters of this function are ignored -when writing; you can set them to zero as shown. - -You can retrieve the pointer via the function png_get_user_transform_ptr(). -For example: - - voidp write_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -It is possible to have libpng flush any pending output, either manually, -or automatically after a certain number of lines have been written. To -flush the output stream a single time call: - - png_write_flush(png_ptr); - -and to have libpng flush the output stream periodically after a certain -number of scanlines have been written, call: - - png_set_flush(png_ptr, nrows); - -Note that the distance between rows is from the last time png_write_flush() -was called, or the first row of the image if it has never been called. -So if you write 50 lines, and then png_set_flush 25, it will flush the -output on the next scanline, and every 25 lines thereafter, unless -png_write_flush() is called before 25 more lines have been written. -If nrows is too small (less than about 10 lines for a 640 pixel wide -RGB image) the image compression may decrease noticeably (although this -may be acceptable for real-time applications). Infrequent flushing will -only degrade the compression performance by a few percent over images -that do not use flushing. - -.SS Writing the image data - -That's it for the transformations. Now you can write the image data. -The simplest way to do this is in one function call. If you have the -whole image in memory, you can just call png_write_image() and libpng -will write the image. You will need to pass in an array of pointers to -each row. This function automatically handles interlacing, so you don't -need to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_write_rows(). - - png_write_image(png_ptr, row_pointers); - -where row_pointers is: - - png_byte *row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to write the whole image at once, you can -use png_write_rows() instead. If the file is not interlaced, -this is simple: - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -row_pointers is the same as in the png_write_image() call. - -If you are just writing one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - - png_write_row(png_ptr, row_pointer); - -When the file is interlaced, things can get a good deal more complicated. -The only currently (as of the PNG Specification version 1.2, dated July -1999) defined interlacing scheme for PNG files is the "Adam7" interlace -scheme, that breaks down an image into seven smaller images of varying -size. libpng will build these images for you, or you can do them -yourself. If you want to build them yourself, see the PNG specification -for details of which pixels to write when. - -If you don't want libpng to handle the interlacing details, just -use png_set_interlace_handling() and call png_write_rows() the -correct number of times to write all seven sub-images. - -If you want libpng to build the sub-images, call this before you start -writing any rows: - - number_of_passes = - png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this is seven, -but may change if another interlace type is added. - -Then write the complete image number_of_passes times. - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -As some of these rows are not used, and thus return immediately, you may -want to read about interlacing in the PNG specification, and only update -the rows that are actually used. - -.SS Finishing a sequential write - -After you are finished writing the image, you should finish writing -the file. If you are interested in writing comments or time, you should -pass an appropriately filled png_info pointer. If you are not interested, -you can pass NULL. - - png_write_end(png_ptr, info_ptr); - -When you are done, you can free all memory used by libpng like this: - - png_destroy_write_struct(&png_ptr, &info_ptr); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (\-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. -The "seq" parameter is ignored if only one item of the selected data -type, such as PLTE, is allowed. If "seq" is not \-1, and multiple items -are allowed for the data type identified in the mask, such as text or -sPLT, only the n'th item in the structure is freed, where n is "seq". - -If you allocated data such as a palette that you passed in to libpng -with png_set_*, you must not free it until just before the call to -png_destroy_write_struct(). - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -For example, to transfer responsibility for some data from a read structure -to a write structure, you could use - - png_data_freer(read_ptr, read_info_ptr, - PNG_USER_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - png_data_freer(write_ptr, write_info_ptr, - PNG_DESTROY_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - -thereby briefly reassigning responsibility for freeing to the user but -immediately afterwards reassigning it once more to the write_destroy -function. Having done this, it would then be safe to destroy the read -structure and continue to use the PLTE, tRNS, and hIST data in the write -structure. - -This function only affects data that has already been allocated. -You can call this function before calling after the png_set_*() functions -to control whether the user or png_destroy_*() is supposed to free the data. -When the user assumes responsibility for libpng-allocated data, the -application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. -For a more compact example of writing a PNG image, see the file example.c. - -.SH V. Modifying/Customizing libpng: - -There are two issues here. The first is changing how libpng does -standard things like memory allocation, input/output, and error handling. -The second deals with more complicated things like adding new chunks, -adding new transformations, and generally changing how libpng works. -Both of those are compile-time issues; that is, they are generally -determined at the time the code is written, and there is rarely a need -to provide the user with a means of changing them. - -Memory allocation, input/output, and error handling - -All of the memory allocation, input/output, and error handling in libpng -goes through callbacks that are user-settable. The default routines are -in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change -these functions, call the appropriate png_set_*_fn() function. - -Memory allocation is done through the functions png_malloc(), png_calloc(), -and png_free(). These currently just call the standard C functions. -png_calloc() calls png_malloc() and then png_memset() to clear the newly -allocated memory to zero. If your pointers can't access more then 64K -at a time, you will want to set MAXSEG_64K in zlib.h. Since it is -unlikely that the method of handling memory allocation on a platform -will change between applications, these functions must be modified in -the library at compile time. If you prefer to use a different method -of allocating and freeing data, you can use png_create_read_struct_2() or -png_create_write_struct_2() to register your own functions as described -above. These functions also provide a void pointer that can be retrieved -via - - mem_ptr=png_get_mem_ptr(png_ptr); - -Your replacement memory functions must have prototypes as follows: - - png_voidp malloc_fn(png_structp png_ptr, - png_size_t size); - void free_fn(png_structp png_ptr, png_voidp ptr); - -Your malloc_fn() must return NULL in case of failure. The png_malloc() -function will normally call png_error() if it receives a NULL from the -system memory allocator or from your replacement malloc_fn(). - -Your free_fn() will never be called with a NULL ptr, since libpng's -png_free() checks for NULL before calling free_fn(). - -Input/Output in libpng is done through png_read() and png_write(), -which currently just call fread() and fwrite(). The FILE * is stored in -png_struct and is initialized via png_init_io(). If you wish to change -the method of I/O, the library supplies callbacks that you can set -through the function png_set_read_fn() and png_set_write_fn() at run -time, instead of calling the png_init_io() function. These functions -also provide a void pointer that can be retrieved via the function -png_get_io_ptr(). For example: - - png_set_read_fn(png_structp read_ptr, - voidp read_io_ptr, png_rw_ptr read_data_fn) - - png_set_write_fn(png_structp write_ptr, - voidp write_io_ptr, png_rw_ptr write_data_fn, - png_flush_ptr output_flush_fn); - - voidp read_io_ptr = png_get_io_ptr(read_ptr); - voidp write_io_ptr = png_get_io_ptr(write_ptr); - -The replacement I/O functions must have prototypes as follows: - - void user_read_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_write_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_flush_data(png_structp png_ptr); - -The user_read_data() function is responsible for detecting and -handling end-of-data errors. - -Supplying NULL for the read, write, or flush functions sets them back -to using the default C stream functions, which expect the io_ptr to -point to a standard *FILE structure. It is probably a mistake -to use NULL for one of write_data_fn and output_flush_fn but not both -of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. -It is an error to read from a write stream, and vice versa. - -Error handling in libpng is done through png_error() and png_warning(). -Errors handled through png_error() are fatal, meaning that png_error() -should never return to its caller. Currently, this is handled via -setjmp() and longjmp() (unless you have compiled libpng with -PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), -but you could change this to do things like exit() if you should wish. - -On non-fatal errors, png_warning() is called -to print a warning message, and then control returns to the calling code. -By default png_error() and png_warning() print a message on stderr via -fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined -(because you don't want the messages) or PNG_NO_STDIO defined (because -fprintf() isn't available). If you wish to change the behavior of the error -functions, you will need to set up your own message callbacks. These -functions are normally supplied at the time that the png_struct is created. -It is also possible to redirect errors and warnings to your own replacement -functions after png_create_*_struct() has been called by calling: - - png_set_error_fn(png_structp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warning_fn); - - png_voidp error_ptr = png_get_error_ptr(png_ptr); - -If NULL is supplied for either error_fn or warning_fn, then the libpng -default function will be used, calling fprintf() and/or longjmp() if a -problem is encountered. The replacement error functions should have -parameters as follows: - - void user_error_fn(png_structp png_ptr, - png_const_charp error_msg); - void user_warning_fn(png_structp png_ptr, - png_const_charp warning_msg); - -The motivation behind using setjmp() and longjmp() is the C++ throw and -catch exception handling methods. This makes the code much easier to write, -as there is no need to check every return code of every function call. -However, there are some uncertainties about the status of local variables -after a longjmp, so the user may want to be careful about doing anything -after setjmp returns non-zero besides returning itself. Consult your -compiler documentation for more details. For an alternative approach, you -may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net). - -.SS Custom chunks - -If you need to read or write custom chunks, you may need to get deeper -into the libpng code. The library now has mechanisms for storing -and writing chunks of unknown type; you can even declare callbacks -for custom chunks. However, this may not be good enough if the -library code itself needs to know about interactions between your -chunk and existing `intrinsic' chunks. - -If you need to write a new intrinsic chunk, first read the PNG -specification. Acquire a first level of understanding of how it works. -Pay particular attention to the sections that describe chunk names, -and look at how other chunks were designed, so you can do things -similarly. Second, check out the sections of libpng that read and -write chunks. Try to find a chunk that is similar to yours and use -it as a template. More details can be found in the comments inside -the code. It is best to handle unknown chunks in a generic method, -via callback functions, instead of by modifying libpng functions. - -If you wish to write your own transformation for the data, look through -the part of the code that does the transformations, and check out some of -the simpler ones to get an idea of how they work. Try to find a similar -transformation to the one you want to add and copy off of it. More details -can be found in the comments inside the code itself. - -.SS Configuring for 16 bit platforms - -You will want to look into zconf.h to tell zlib (and thus libpng) that -it cannot allocate more then 64K at a time. Even if you can, the memory -won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. - -.SS Configuring for DOS - -For DOS users who only have access to the lower 640K, you will -have to limit zlib's memory usage via a png_set_compression_mem_level() -call. See zlib.h or zconf.h in the zlib library for more information. - -.SS Configuring for Medium Model - -Libpng's support for medium model has been tested on most of the popular -compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets -defined, and FAR gets defined to far in pngconf.h, and you should be -all set. Everything in the library (except for zlib's structure) is -expecting far data. You must use the typedefs with the p or pp on -the end for pointers (or at least look at them and be careful). Make -note that the rows of data are defined as png_bytepp, which is an -unsigned char far * far *. - -.SS Configuring for gui/windowing platforms: - -You will need to write new error and warning functions that use the GUI -interface, as described previously, and set them to be the error and -warning functions at the time that png_create_*_struct() is called, -in order to have them available during the structure initialization. -They can be changed later via png_set_error_fn(). On some compilers, -you may also have to change the memory allocators (png_malloc, etc.). - -.SS Configuring for compiler xxx: - -All includes for libpng are in pngconf.h. If you need to add, change -or delete an include, this is the place to do it. -The includes that are not needed outside libpng are protected by the -PNG_INTERNAL definition, which is only defined for those routines inside -libpng itself. The files in libpng proper only include png.h, which -includes pngconf.h. - -.SS Configuring zlib: - -There are special functions to configure the compression. Perhaps the -most useful one changes the compression level, which currently uses -input compression values in the range 0 - 9. The library normally -uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests -have shown that for a large majority of images, compression values in -the range 3-6 compress nearly as well as higher levels, and do so much -faster. For online applications it may be desirable to have maximum speed -(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also -specify no compression (Z_NO_COMPRESSION = 0), but this would create -files larger than just storing the raw bitmap. You can specify the -compression level by calling: - - png_set_compression_level(png_ptr, level); - -Another useful one is to reduce the memory level used by the library. -The memory level defaults to 8, but it can be lowered if you are -short on memory (running DOS, for example, where you only have 640K). -Note that the memory level does have an effect on compression; among -other things, lower levels will result in sections of incompressible -data being emitted in smaller stored blocks, with a correspondingly -larger relative overhead of up to 15% in the worst case. - - png_set_compression_mem_level(png_ptr, level); - -The other functions are for configuring zlib. They are not recommended -for normal use and may result in writing an invalid PNG file. See -zlib.h for more information on what these mean. - - png_set_compression_strategy(png_ptr, - strategy); - png_set_compression_window_bits(png_ptr, - window_bits); - png_set_compression_method(png_ptr, method); - png_set_compression_buffer_size(png_ptr, size); - -.SS Controlling row filtering - -If you want to control whether libpng uses filtering or not, which -filters are used, and how it goes about picking row filters, you -can call one of these functions. The selection and configuration -of row filters can have a significant impact on the size and -encoding speed and a somewhat lesser impact on the decoding speed -of an image. Filtering is enabled by default for RGB and grayscale -images (with and without alpha), but not for paletted images nor -for any images with bit depths less than 8 bits/pixel. - -The 'method' parameter sets the main filtering method, which is -currently only '0' in the PNG 1.2 specification. The 'filters' -parameter sets which filter(s), if any, should be used for each -scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS -to turn filtering on and off, respectively. - -Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, -PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise -ORed together with '|' to specify one or more filters to use. -These filters are described in more detail in the PNG specification. -If you intend to change the filter type during the course of writing -the image, you should start with flags set for all of the filters -you intend to use so that libpng can initialize its internal -structures appropriately for all of the filter types. (Note that this -means the first row must always be adaptively filtered, because libpng -currently does not allocate the filter buffers until png_write_row() -is called for the first time.) - - filters = PNG_FILTER_NONE | PNG_FILTER_SUB - PNG_FILTER_UP | PNG_FILTER_AVG | - PNG_FILTER_PAETH | PNG_ALL_FILTERS; - - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, - filters); - The second parameter can also be - PNG_INTRAPIXEL_DIFFERENCING if you are - writing a PNG to be embedded in a MNG - datastream. This parameter must be the - same as the value of filter_method used - in png_set_IHDR(). - -It is also possible to influence how libpng chooses from among the -available filters. This is done in one or both of two ways - by -telling it how important it is to keep the same filter for successive -rows, and by telling it the relative computational costs of the filters. - - double weights[3] = {1.5, 1.3, 1.1}, - costs[PNG_FILTER_VALUE_LAST] = - {1.0, 1.3, 1.3, 1.5, 1.7}; - - png_set_filter_heuristics(png_ptr, - PNG_FILTER_HEURISTIC_WEIGHTED, 3, - weights, costs); - -The weights are multiplying factors that indicate to libpng that the -row filter should be the same for successive rows unless another row filter -is that many times better than the previous filter. In the above example, -if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a -"sum of absolute differences" 1.5 x 1.3 times higher than other filters -and still be chosen, while the NONE filter could have a sum 1.1 times -higher than other filters and still be chosen. Unspecified weights are -taken to be 1.0, and the specified weights should probably be declining -like those above in order to emphasize recent filters over older filters. - -The filter costs specify for each filter type a relative decoding cost -to be considered when selecting row filters. This means that filters -with higher costs are less likely to be chosen over filters with lower -costs, unless their "sum of absolute differences" is that much smaller. -The costs do not necessarily reflect the exact computational speeds of -the various filters, since this would unduly influence the final image -size. - -Note that the numbers above were invented purely for this example and -are given only to help explain the function usage. Little testing has -been done to find optimum values for either the costs or the weights. - -.SS Removing unwanted object code - -There are a bunch of #define's in pngconf.h that control what parts of -libpng are compiled. All the defines end in _SUPPORTED. If you are -never going to use a capability, you can change the #define to #undef -before recompiling libpng and save yourself code and data space, or -you can turn off individual capabilities with defines that begin with -PNG_NO_. - -You can also turn all of the transforms and ancillary chunk capabilities -off en masse with compiler directives that define -PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, -or all four, -along with directives to turn on any of the capabilities that you do -want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the extra -transformations but still leave the library fully capable of reading -and writing PNG files with all known public chunks. Use of the -PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library -that is incapable of reading or writing ancillary chunks. If you are -not using the progressive reading capability, you can turn that off -with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING -capability, which you'll still have). - -All the reading and writing specific code are in separate files, so the -linker should only grab the files it needs. However, if you want to -make sure, or if you are building a stand alone library, all the -reading files start with pngr and all the writing files start with -pngw. The files that don't match either (like png.c, pngtrans.c, etc.) -are used for both reading and writing, and always need to be included. -The progressive reader is in pngpread.c - -If you are creating or distributing a dynamically linked library (a .so -or DLL file), you should not remove or disable any parts of the library, -as this will cause applications linked with different versions of the -library to fail if they call functions not available in your library. -The size of the library itself should not be an issue, because only -those sections that are actually used will be loaded into memory. - -.SS Requesting debug printout - -The macro definition PNG_DEBUG can be used to request debugging -printout. Set it to an integer value in the range 0 to 3. Higher -numbers result in increasing amounts of debugging information. The -information is printed to the "stderr" file, unless another file -name is specified in the PNG_DEBUG_FILE macro definition. - -When PNG_DEBUG > 0, the following functions (macros) become available: - - png_debug(level, message) - png_debug1(level, message, p1) - png_debug2(level, message, p1, p2) - -in which "level" is compared to PNG_DEBUG to decide whether to print -the message, "message" is the formatted string to be printed, -and p1 and p2 are parameters that are to be embedded in the string -according to printf-style formatting directives. For example, - - png_debug1(2, "foo=%d", foo); - -is expanded to - - if(PNG_DEBUG > 2) - fprintf(PNG_DEBUG_FILE, "foo=%d\en", foo); - -When PNG_DEBUG is defined but is zero, the macros aren't defined, but you -can still use PNG_DEBUG to control your own debugging: - - #ifdef PNG_DEBUG - fprintf(stderr, ... - #endif - -When PNG_DEBUG = 1, the macros are defined, but only png_debug statements -having level = 0 will be printed. There aren't any such statements in -this version of libpng, but if you insert some they will be printed. - -.SH VI. MNG support - -The MNG specification (available at http://www.libpng.org/pub/mng) allows -certain extensions to PNG for PNG images that are embedded in MNG datastreams. -Libpng can support some of these extensions. To enable them, use the -png_permit_mng_features() function: - - feature_set = png_permit_mng_features(png_ptr, mask) - mask is a png_uint_32 containing the bitwise OR of the - features you want to enable. These include - PNG_FLAG_MNG_EMPTY_PLTE - PNG_FLAG_MNG_FILTER_64 - PNG_ALL_MNG_FEATURES - feature_set is a png_uint_32 that is the bitwise AND of - your mask with the set of MNG features that is - supported by the version of libpng that you are using. - -It is an error to use this function when reading or writing a standalone -PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped -in a MNG datastream. As a minimum, it must have the MNG 8-byte signature -and the MHDR and MEND chunks. Libpng does not provide support for these -or any other MNG chunks; your application must provide its own support for -them. You may wish to consider using libmng (available at -http://www.libmng.com) instead. - -.SH VII. Changes to Libpng from version 0.88 - -It should be noted that versions of libpng later than 0.96 are not -distributed by the original libpng author, Guy Schalnat, nor by -Andreas Dilger, who had taken over from Guy during 1996 and 1997, and -distributed versions 0.89 through 0.96, but rather by another member -of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are -still alive and well, but they have moved on to other things. - -The old libpng functions png_read_init(), png_write_init(), -png_info_init(), png_read_destroy(), and png_write_destroy() have been -moved to PNG_INTERNAL in version 0.95 to discourage their use. These -functions will be removed from libpng version 2.0.0. - -The preferred method of creating and initializing the libpng structures is -via the png_create_read_struct(), png_create_write_struct(), and -png_create_info_struct() because they isolate the size of the structures -from the application, allow version error checking, and also allow the -use of custom error handling routines during the initialization, which -the old functions do not. The functions png_read_destroy() and -png_write_destroy() do not actually free the memory that libpng -allocated for these structs, but just reset the data structures, so they -can be used instead of png_destroy_read_struct() and -png_destroy_write_struct() if you feel there is too much system overhead -allocating and freeing the png_struct for each image read. - -Setting the error callbacks via png_set_message_fn() before -png_read_init() as was suggested in libpng-0.88 is no longer supported -because this caused applications that do not use custom error functions -to fail if the png_ptr was not initialized to zero. It is still possible -to set the error callbacks AFTER png_read_init(), or to change them with -png_set_error_fn(), which is essentially the same function, but with a new -name to force compilation errors with applications that try to use the old -method. - -Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; -however, iTXt support was not enabled by default. - -Starting with version 1.0.7, you can find out which version of the library -you are using at run-time: - - png_uint_32 libpng_vn = png_access_version_number(); - -The number libpng_vn is constructed from the major version, minor -version with leading zero, and release number with leading zero, -(e.g., libpng_vn for version 1.0.7 is 10007). - -You can also check which version of png.h you used when compiling your -application: - - png_uint_32 application_vn = PNG_LIBPNG_VER; - -.SH VIII. Changes to Libpng from version 1.0.x to 1.2.x - -Support for user memory management was enabled by default. To -accomplish this, the functions png_create_read_struct_2(), -png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), -png_malloc_default(), and png_free_default() were added. - -Support for the iTXt chunk has been enabled by default as of -version 1.2.41. - -Support for certain MNG features was enabled. - -Support for numbered error messages was added. However, we never got -around to actually numbering the error messages. The function -png_set_strip_error_numbers() was added (Note: the prototype for this -function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE -builds of libpng-1.2.15. It was restored in libpng-1.2.36). - -The png_malloc_warn() function was added at libpng-1.2.3. This issues -a png_warning and returns NULL instead of aborting when it fails to -acquire the requested memory allocation. - -Support for setting user limits on image width and height was enabled -by default. The functions png_set_user_limits(), png_get_user_width_max(), -and png_get_user_height_max() were added at libpng-1.2.6. - -The png_set_add_alpha() function was added at libpng-1.2.7. - -The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. -Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the -tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is -deprecated. - -A number of macro definitions in support of runtime selection of -assembler code features (especially Intel MMX code support) were -added at libpng-1.2.0: - - PNG_ASM_FLAG_MMX_SUPPORT_COMPILED - PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU - PNG_ASM_FLAG_MMX_READ_COMBINE_ROW - PNG_ASM_FLAG_MMX_READ_INTERLACE - PNG_ASM_FLAG_MMX_READ_FILTER_SUB - PNG_ASM_FLAG_MMX_READ_FILTER_UP - PNG_ASM_FLAG_MMX_READ_FILTER_AVG - PNG_ASM_FLAG_MMX_READ_FILTER_PAETH - PNG_ASM_FLAGS_INITIALIZED - PNG_MMX_READ_FLAGS - PNG_MMX_FLAGS - PNG_MMX_WRITE_FLAGS - PNG_MMX_FLAGS - -We added the following functions in support of runtime -selection of assembler code features: - - png_get_mmx_flagmask() - png_set_mmx_thresholds() - png_get_asm_flags() - png_get_mmx_bitdepth_threshold() - png_get_mmx_rowbytes_threshold() - png_set_asm_flags() - -We replaced all of these functions with simple stubs in libpng-1.2.20, -when the Intel assembler code was removed due to a licensing issue. - -These macros are deprecated: - - PNG_READ_TRANSFORMS_NOT_SUPPORTED - PNG_PROGRESSIVE_READ_NOT_SUPPORTED - PNG_NO_SEQUENTIAL_READ_SUPPORTED - PNG_WRITE_TRANSFORMS_NOT_SUPPORTED - PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED - PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED - -They have been replaced, respectively, by: - - PNG_NO_READ_TRANSFORMS - PNG_NO_PROGRESSIVE_READ - PNG_NO_SEQUENTIAL_READ - PNG_NO_WRITE_TRANSFORMS - PNG_NO_READ_ANCILLARY_CHUNKS - PNG_NO_WRITE_ANCILLARY_CHUNKS - -PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been -deprecated since libpng-1.0.16 and libpng-1.2.6. - -The function - png_check_sig(sig, num) -was replaced with - !png_sig_cmp(sig, 0, num) -It has been deprecated since libpng-0.90. - -The function - png_set_gray_1_2_4_to_8() -which also expands tRNS to alpha was replaced with - png_set_expand_gray_1_2_4_to_8() -which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. - -.SH IX. (Omitted) - - -.SH X. Detecting libpng - -The png_get_io_ptr() function has been present since libpng-0.88, has never -changed, and is unaffected by conditional compilation macros. It is the -best choice for use in configure scripts for detecting the presence of any -libpng version since 0.88. In an autoconf "configure.in" you could use - - AC_CHECK_LIB(png, png_get_io_ptr, ... - -.SH XI. Source code repository - -Since about February 2009, version 1.2.34, libpng has been under "git" source -control. The git repository was built from old libpng-x.y.z.tar.gz files -going back to version 0.70. You can access the git repository (read only) -at - - git://git.code.sf.net/p/libpng/code - -or you can browse it with a web browser by selecting the "code" button at - - https://sourceforge.net/projects/libpng/ - -Patches can be sent to glennrp at users.sourceforge.net or to -png-mng-implement at lists.sourceforge.net or you can upload them to -the libpng bug tracker at - - http://libpng.sourceforge.net - -.SH XII. Coding style - -Our coding style is similar to the "Allman" style, with curly -braces on separate lines: - - if (condition) - { - action; - } - - else if (another condition) - { - another action; - } - -The braces can be omitted from simple one-line actions: - - if (condition) - return (0); - -We use 3-space indentation, except for continued statements which -are usually indented the same as the first line of the statement -plus four more spaces. - -For macro definitions we use 2-space indentation, always leaving the "#" -in the first column. - - #ifndef PNG_NO_FEATURE - # ifndef PNG_FEATURE_SUPPORTED - # define PNG_FEATURE_SUPPORTED - # endif - #endif - -Comments appear with the leading "/*" at the same indentation as -the statement that follows the comment: - - /* Single-line comment */ - statement; - - /* Multiple-line - * comment - */ - statement; - -Very short comments can be placed at the end of the statement -to which they pertain: - - statement; /* comment */ - -We don't use C++ style ("//") comments. We have, however, -used them in the past in some now-abandoned MMX assembler -code. - -Functions and their curly braces are not indented, and -exported functions are marked with PNGAPI: - - /* This is a public function that is visible to - * application programers. It does thus-and-so. - */ - void PNGAPI - png_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for all exported functions appear in png.h, -above the comment that says - - /* Maintainer: Put new public prototypes here ... */ - -We mark all non-exported functions with "/* PRIVATE */"": - - void /* PRIVATE */ - png_non_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for non-exported functions (except for those in -pngtest) appear in -the PNG_INTERNAL section of png.h -above the comment that says - - /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -The names of all exported functions and variables begin -with "png_", and all publicly visible C preprocessor -macros begin with "PNG". - -We put a space after each comma and after each semicolon -in "for" statments, and we put spaces before and after each -C binary operator and after "for" or "while". We don't -put a space between a typecast and the expression being -cast, nor do we put one between a function name and the -left parenthesis that follows it: - - for (i = 2; i > 0; --i) - y[i] = a(x) + (int)b; - -We prefer #ifdef and #ifndef to #if defined() and if !defined() -when there is only one macro being tested. - -We do not use the TAB character for indentation in the C sources. - -Lines do not exceed 80 characters. - -Other rules can be inferred by inspecting the libpng source. - -.SH XIII. Y2K Compliance in libpng - -February 6, 2014 - -Since the PNG Development group is an ad-hoc body, we can't make -an official declaration. - -This is your unofficial assurance that libpng from version 0.71 and -upward through 1.2.51 are Y2K compliant. It is my belief that earlier -versions were also Y2K compliant. - -Libpng only has three year fields. One is a 2-byte unsigned integer that -will hold years up to 65535. The other two hold the date in text -format, and will hold years up to 9999. - -The integer is - "png_uint_16 year" in png_time_struct. - -The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. - -There are seven time-related functions: - - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) - png_convert_from_struct_tm() in pngwrite.c, called - in pngwrite.c - png_convert_from_time_t() in pngwrite.c - png_get_tIME() in pngget.c - png_handle_tIME() in pngrutil.c, called in pngread.c - png_set_tIME() in pngset.c - png_write_tIME() in pngwutil.c, called in pngwrite.c - -All appear to handle dates properly in a Y2K environment. The -png_convert_from_time_t() function calls gmtime() to convert from system -clock time, which returns (year - 1900), which we properly convert to -the full 4-digit year. There is a possibility that applications using -libpng are not passing 4-digit years into the png_convert_to_rfc_1123() -function, or that they are incorrectly passing only a 2-digit year -instead of "year - 1900" into the png_convert_from_struct_tm() function, -but this is not under our control. The libpng documentation has always -stated that it works with 4-digit years, and the APIs have been -documented as such. - -The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned -integer to hold the year, and can hold years as large as 65535. - -zlib, upon which libpng depends, is also Y2K compliant. It contains -no date-related code. - - - Glenn Randers-Pehrson - libpng maintainer - PNG Development Group - -.SH NOTE - -Note about libpng version numbers: - -Due to various miscommunications, unforeseen code incompatibilities -and occasional factors outside the authors' control, version numbering -on the library has not always been consistent and straightforward. -The following table summarizes matters since version 0.89c, which was -the first widely used release: - - source png.h png.h shared-lib - version string int version - ------- ------ ----- ---------- - 0.89c ("beta 3") 0.89 89 1.0.89 - 0.90 ("beta 4") 0.90 90 0.90 - 0.95 ("beta 5") 0.95 95 0.95 - 0.96 ("beta 6") 0.96 96 0.96 - 0.97b ("beta 7") 1.00.97 97 1.0.1 - 0.97c 0.97 97 2.0.97 - 0.98 0.98 98 2.0.98 - 0.99 0.99 98 2.0.99 - 0.99a-m 0.99 99 2.0.99 - 1.00 1.00 100 2.1.0 - 1.0.0 1.0.0 100 2.1.0 - 1.0.0 (from here on, the 100 2.1.0 - 1.0.1 png.h string is 10001 2.1.0 - 1.0.1a-e identical to the 10002 from here on, the - 1.0.2 source version) 10002 shared library is 2.V - 1.0.2a-b 10003 where V is the source - 1.0.1 10001 code version except as - 1.0.1a-e 10002 2.1.0.1a-e noted. - 1.0.2 10002 2.1.0.2 - 1.0.2a-b 10003 2.1.0.2a-b - 1.0.3 10003 2.1.0.3 - 1.0.3a-d 10004 2.1.0.3a-d - 1.0.4 10004 2.1.0.4 - 1.0.4a-f 10005 2.1.0.4a-f - 1.0.5 (+ 2 patches) 10005 2.1.0.5 - 1.0.5a-d 10006 2.1.0.5a-d - 1.0.5e-r 10100 2.1.0.5e-r - 1.0.5s-v 10006 2.1.0.5s-v - 1.0.6 (+ 3 patches) 10006 2.1.0.6 - 1.0.6d-g 10007 2.1.0.6d-g - 1.0.6h 10007 10.6h - 1.0.6i 10007 10.6i - 1.0.6j 10007 2.1.0.6j - 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 - 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 - 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 - 1.0.7 1 10007 2.1.0.7 - 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 - 1.0.8rc1 1 10008 2.1.0.8rc1 - 1.0.8 1 10008 2.1.0.8 - 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 - 1.0.9rc1 1 10009 2.1.0.9rc1 - 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 - 1.0.9rc2 1 10009 2.1.0.9rc2 - 1.0.9 1 10009 2.1.0.9 - 1.0.10beta1 1 10010 2.1.0.10beta1 - 1.0.10rc1 1 10010 2.1.0.10rc1 - 1.0.10 1 10010 2.1.0.10 - 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 - 1.0.11rc1 1 10011 2.1.0.11rc1 - 1.0.11 1 10011 2.1.0.11 - 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 - 1.0.12rc1 2 10012 2.1.0.12rc1 - 1.0.12 2 10012 2.1.0.12 - 1.1.0a-f - 10100 2.1.1.0a-f abandoned - 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 - 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 - 1.2.0rc1 3 10200 3.1.2.0rc1 - 1.2.0 3 10200 3.1.2.0 - 1.2.1beta-4 3 10201 3.1.2.1beta1-4 - 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 - 1.2.1 3 10201 3.1.2.1 - 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 - 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 - 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 - 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 - 1.0.13 10 10013 10.so.0.1.0.13 - 1.2.2 12 10202 12.so.0.1.2.2 - 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 - 1.2.3 12 10203 12.so.0.1.2.3 - 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 - 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 - 1.0.14 10 10014 10.so.0.1.0.14 - 1.2.4 13 10204 12.so.0.1.2.4 - 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 - 1.0.15rc1 10 10015 10.so.0.1.0.15rc1 - 1.0.15 10 10015 10.so.0.1.0.15 - 1.2.5 13 10205 12.so.0.1.2.5 - 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 - 1.2.6rc1-5 13 10206 12.so.0.1.2.6rc1-5 - 1.0.16 10 10016 10.so.0.1.0.16 - 1.2.6 13 10206 12.so.0.1.2.6 - 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 - 1.0.17rc1 10 10017 10.so.0.1.0.17rc1 - 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 - 1.0.17 10 10017 10.so.0.1.0.17 - 1.2.7 13 10207 12.so.0.1.2.7 - 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 - 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5 - 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 - 1.0.18 10 10018 10.so.0.1.0.18 - 1.2.8 13 10208 12.so.0.1.2.8 - 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 - 1.2.9beta4-11 13 10209 12.so.0.9[.0] - 1.2.9rc1 13 10209 12.so.0.9[.0] - 1.2.9 13 10209 12.so.0.9[.0] - 1.2.10beta1-8 13 10210 12.so.0.10[.0] - 1.2.10rc1-3 13 10210 12.so.0.10[.0] - 1.2.10 13 10210 12.so.0.10[.0] - 1.2.11beta1-4 13 10211 12.so.0.11[.0] - 1.0.19rc1-5 10 10019 10.so.0.19[.0] - 1.2.11rc1-5 13 10211 12.so.0.11[.0] - 1.0.19 10 10019 10.so.0.19[.0] - 1.2.11 13 10211 12.so.0.11[.0] - 1.0.20 10 10020 10.so.0.20[.0] - 1.2.12 13 10212 12.so.0.12[.0] - 1.2.13beta1 13 10213 12.so.0.13[.0] - 1.0.21 10 10021 10.so.0.21[.0] - 1.2.13 13 10213 12.so.0.13[.0] - 1.2.14beta1-2 13 10214 12.so.0.14[.0] - 1.0.22rc1 10 10022 10.so.0.22[.0] - 1.2.14rc1 13 10214 12.so.0.14[.0] - 1.2.15beta1-6 13 10215 12.so.0.15[.0] - 1.0.23rc1-5 10 10023 10.so.0.23[.0] - 1.2.15rc1-5 13 10215 12.so.0.15[.0] - 1.0.23 10 10023 10.so.0.23[.0] - 1.2.15 13 10215 12.so.0.15[.0] - 1.2.16beta1-2 13 10216 12.so.0.16[.0] - 1.2.16rc1 13 10216 12.so.0.16[.0] - 1.0.24 10 10024 10.so.0.24[.0] - 1.2.16 13 10216 12.so.0.16[.0] - 1.2.17beta1-2 13 10217 12.so.0.17[.0] - 1.0.25rc1 10 10025 10.so.0.25[.0] - 1.2.17rc1-3 13 10217 12.so.0.17[.0] - 1.0.25 10 10025 10.so.0.25[.0] - 1.2.17 13 10217 12.so.0.17[.0] - 1.0.26 10 10026 10.so.0.26[.0] - 1.2.18 13 10218 12.so.0.18[.0] - 1.2.19beta1-31 13 10219 12.so.0.19[.0] - 1.0.27rc1-6 10 10027 10.so.0.27[.0] - 1.2.19rc1-6 13 10219 12.so.0.19[.0] - 1.0.27 10 10027 10.so.0.27[.0] - 1.2.19 13 10219 12.so.0.19[.0] - 1.2.20beta01-04 13 10220 12.so.0.20[.0] - 1.0.28rc1-6 10 10028 10.so.0.28[.0] - 1.2.20rc1-6 13 10220 12.so.0.20[.0] - 1.0.28 10 10028 10.so.0.28[.0] - 1.2.20 13 10220 12.so.0.20[.0] - 1.2.21beta1-2 13 10221 12.so.0.21[.0] - 1.2.21rc1-3 13 10221 12.so.0.21[.0] - 1.0.29 10 10029 10.so.0.29[.0] - 1.2.21 13 10221 12.so.0.21[.0] - 1.2.22beta1-4 13 10222 12.so.0.22[.0] - 1.0.30rc1 13 10030 10.so.0.30[.0] - 1.2.22rc1 13 10222 12.so.0.22[.0] - 1.0.30 10 10030 10.so.0.30[.0] - 1.2.22 13 10222 12.so.0.22[.0] - 1.2.23beta01-05 13 10223 12.so.0.23[.0] - 1.2.23rc01 13 10223 12.so.0.23[.0] - 1.2.23 13 10223 12.so.0.23[.0] - 1.2.24beta01-02 13 10224 12.so.0.24[.0] - 1.2.24rc01 13 10224 12.so.0.24[.0] - 1.2.24 13 10224 12.so.0.24[.0] - 1.2.25beta01-06 13 10225 12.so.0.25[.0] - 1.2.25rc01-02 13 10225 12.so.0.25[.0] - 1.0.31 10 10031 10.so.0.31[.0] - 1.2.25 13 10225 12.so.0.25[.0] - 1.2.26beta01-06 13 10226 12.so.0.26[.0] - 1.2.26rc01 13 10226 12.so.0.26[.0] - 1.2.26 13 10226 12.so.0.26[.0] - 1.0.32 10 10032 10.so.0.32[.0] - 1.2.27beta01-06 13 10227 12.so.0.27[.0] - 1.2.27rc01 13 10227 12.so.0.27[.0] - 1.0.33 10 10033 10.so.0.33[.0] - 1.2.27 13 10227 12.so.0.27[.0] - 1.0.34 10 10034 10.so.0.34[.0] - 1.2.28 13 10228 12.so.0.28[.0] - 1.2.29beta01-03 13 10229 12.so.0.29[.0] - 1.2.29rc01 13 10229 12.so.0.29[.0] - 1.0.35 10 10035 10.so.0.35[.0] - 1.2.29 13 10229 12.so.0.29[.0] - 1.0.37 10 10037 10.so.0.37[.0] - 1.2.30beta01-04 13 10230 12.so.0.30[.0] - 1.0.38rc01-08 10 10038 10.so.0.38[.0] - 1.2.30rc01-08 13 10230 12.so.0.30[.0] - 1.0.38 10 10038 10.so.0.38[.0] - 1.2.30 13 10230 12.so.0.30[.0] - 1.0.39rc01-03 10 10039 10.so.0.39[.0] - 1.2.31rc01-03 13 10231 12.so.0.31[.0] - 1.0.39 10 10039 10.so.0.39[.0] - 1.2.31 13 10231 12.so.0.31[.0] - 1.2.32beta01-02 13 10232 12.so.0.32[.0] - 1.0.40rc01 10 10040 10.so.0.40[.0] - 1.2.32rc01 13 10232 12.so.0.32[.0] - 1.0.40 10 10040 10.so.0.40[.0] - 1.2.32 13 10232 12.so.0.32[.0] - 1.2.33beta01-02 13 10233 12.so.0.33[.0] - 1.2.33rc01-02 13 10233 12.so.0.33[.0] - 1.0.41rc01 10 10041 10.so.0.41[.0] - 1.2.33 13 10233 12.so.0.33[.0] - 1.0.41 10 10041 10.so.0.41[.0] - 1.2.34beta01-07 13 10234 12.so.0.34[.0] - 1.0.42rc01 10 10042 10.so.0.42[.0] - 1.2.34rc01 13 10234 12.so.0.34[.0] - 1.0.42 10 10042 10.so.0.42[.0] - 1.2.34 13 10234 12.so.0.34[.0] - 1.2.35beta01-03 13 10235 12.so.0.35[.0] - 1.0.43rc01-02 10 10043 10.so.0.43[.0] - 1.2.35rc01-02 13 10235 12.so.0.35[.0] - 1.0.43 10 10043 10.so.0.43[.0] - 1.2.35 13 10235 12.so.0.35[.0] - 1.2.36beta01-05 13 10236 12.so.0.36[.0] - 1.2.36rc01 13 10236 12.so.0.36[.0] - 1.0.44 10 10044 10.so.0.44[.0] - 1.2.36 13 10236 12.so.0.36[.0] - 1.2.37beta01-03 13 10237 12.so.0.37[.0] - 1.2.37rc01 13 10237 12.so.0.37[.0] - 1.2.37 13 10237 12.so.0.37[.0] - 1.0.45 10 10045 12.so.0.45[.0] - 1.0.46 10 10046 10.so.0.46[.0] - 1.2.38beta01 13 10238 12.so.0.38[.0] - 1.2.38rc01-03 13 10238 12.so.0.38[.0] - 1.0.47 10 10047 10.so.0.47[.0] - 1.2.38 13 10238 12.so.0.38[.0] - 1.2.39beta01-05 13 10239 12.so.0.39[.0] - 1.2.39rc01 13 10239 12.so.0.39[.0] - 1.0.48 10 10048 10.so.0.48[.0] - 1.2.39 13 10239 12.so.0.39[.0] - 1.2.40beta01 13 10240 12.so.0.40[.0] - 1.2.40rc01 13 10240 12.so.0.40[.0] - 1.0.49 10 10049 10.so.0.49[.0] - 1.2.40 13 10240 12.so.0.40[.0] - 1.0.50 10 10050 10.so.0.50[.0] - 1.2.41beta01-18 13 10241 12.so.0.41[.0] - 1.0.51rc01 10 10051 10.so.0.51[.0] - 1.2.41rc01-03 13 10241 12.so.0.41[.0] - 1.0.51 10 10051 10.so.0.51[.0] - 1.2.41 13 10241 12.so.0.41[.0] - 1.2.42beta01-02 13 10242 12.so.0.42[.0] - 1.2.42rc01-05 13 10242 12.so.0.42[.0] - 1.0.52 10 10052 10.so.0.52[.0] - 1.2.42 13 10242 12.so.0.42[.0] - 1.2.43beta01-05 13 10243 12.so.0.43[.0] - 1.0.53rc01-02 10 10053 10.so.0.53[.0] - 1.2.43rc01-02 13 10243 12.so.0.43[.0] - 1.0.53 10 10053 10.so.0.53[.0] - 1.2.43 13 10243 12.so.0.43[.0] - 1.2.44beta01-03 13 10244 12.so.0.44[.0] - 1.2.44rc01-03 13 10244 12.so.0.44[.0] - 1.2.44 13 10244 12.so.0.44[.0] - 1.2.45beta01-03 13 10245 12.so.0.45[.0] - 1.0.55rc01 10 10055 10.so.0.55[.0] - 1.2.45rc01 13 10245 12.so.0.45[.0] - 1.0.55 10 10055 10.so.0.55[.0] - 1.2.45 13 10245 12.so.0.45[.0] - 1.2.46rc01-02 13 10246 12.so.0.46[.0] - 1.0.56 10 10056 10.so.0.56[.0] - 1.2.46 13 10246 12.so.0.46[.0] - 1.2.47beta01 13 10247 12.so.0.47[.0] - 1.2.47rc01 13 10247 12.so.0.47[.0] - 1.0.57rc01 10 10057 10.so.0.57[.0] - 1.2.47 13 10247 12.so.0.47[.0] - 1.0.57 10 10057 10.so.0.57[.0] - 1.2.48beta01 13 10248 12.so.0.48[.0] - 1.2.48rc01-02 13 10248 12.so.0.48[.0] - 1.0.58 10 10058 10.so.0.58[.0] - 1.2.48 13 10248 12.so.0.48[.0] - 1.2.49rc01 13 10249 12.so.0.49[.0] - 1.0.59 10 10059 10.so.0.59[.0] - 1.2.49 13 10249 12.so.0.49[.0] - 1.2.50 13 10250 12.so.0.50[.0] - 1.0.60 10 10060 10.so.0.60[.0] - 1.2.51beta01-05 13 10251 12.so.0.51[.0] - 1.2.51rc01-04 13 10251 12.so.0.51[.0] - 1.0.61 10 10061 10.so.0.61[.0] - 1.2.51 13 10251 12.so.0.51[.0] - -Henceforth the source version will match the shared-library minor -and patch numbers; the shared-library major version number will be -used for changes in backward compatibility, as it is intended. The -PNG_PNGLIB_VER macro, which is not used within libpng but is available -for applications, is an unsigned integer of the form xyyzz corresponding -to the source version x.y.z (leading zeros in y and z). Beta versions -were given the previous public release number plus a letter, until -version 1.0.6j; from then on they were given the upcoming public -release number plus "betaNN" or "rcNN". - -.SH "SEE ALSO" -.IR libpngpf(3) ", " png(5) -.LP -.IR libpng : -.IP -http://libpng.sourceforge.net (follow the [DOWNLOAD] link) -http://www.libpng.org/pub/png - -.LP -.IR zlib : -.IP -(generally) at the same location as -.I libpng -or at -.br -ftp://ftp.info-zip.org/pub/infozip/zlib - -.LP -.IR PNG specification: RFC 2083 -.IP -(generally) at the same location as -.I libpng -or at -.br -ftp://ftp.rfc-editor.org:/in-notes/rfc2083.txt -.br -or (as a W3C Recommendation) at -.br -http://www.w3.org/TR/REC-png.html - -.LP -In the case of any inconsistency between the PNG specification -and this library, the specification takes precedence. - -.SH AUTHORS -This man page: Glenn Randers-Pehrson - - -The contributing authors would like to thank all those who helped -with testing, bug fixes, and patience. This wouldn't have been -possible without all of you. - -Thanks to Frank J. T. Wojcik for helping with the documentation. - -Libpng version 1.2.51 - February 6, 2014: -Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc. -Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net). - -Supported by the PNG development group -.br -png-mng-implement at lists.sf.net -(subscription required; visit -png-mng-implement at lists.sourceforge.net (subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe). - -.SH COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -(This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail.) - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.2.6, August 15, 2004, through 1.2.51, February 6, 2014, are -Copyright (c) 2004,2006-2008 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.2.5 -with the following individual added to the list of Contributing Authors - - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are -Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6 -with the following individuals added to the list of Contributing Authors - - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your - enjoyment of the library or against infringement. - There is no warranty that our efforts or the library - will fulfill any of your particular purposes or needs. - This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and - effort is with the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998, 1999 Glenn Randers-Pehrson -Distributed according to the same disclaimer and license as libpng-0.96, -with the following individuals added to the list of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88, -with the following individuals added to the list of Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and - must not be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from - any source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about" -boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a -certification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -February 6, 2014 - -.\" end of man page - +.TH LIBPNG 3 "February 6, 2014" +.SH NAME +libpng \- Portable Network Graphics (PNG) Reference Library 1.2.51 +.SH SYNOPSIS +\fB +#include \fP + +\fBpng_uint_32 png_access_version_number \fI(void\fP\fB);\fP + +\fBint png_check_sig (png_bytep \fP\fIsig\fP\fB, int \fInum\fP\fB);\fP + +\fBvoid png_chunk_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fBvoid png_chunk_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fBvoid png_convert_from_struct_tm (png_timep \fP\fIptime\fP\fB, struct tm FAR * \fIttime\fP\fB);\fP + +\fBvoid png_convert_from_time_t (png_timep \fP\fIptime\fP\fB, time_t \fIttime\fP\fB);\fP + +\fBpng_charp png_convert_to_rfc1123 (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fIptime\fP\fB);\fP + +\fBpng_infop png_create_info_struct (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_structp png_create_read_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP + +\fBpng_structp png_create_read_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fBpng_structp png_create_write_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP + +\fBpng_structp png_create_write_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fBint png_debug(int \fP\fIlevel\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fBint png_debug1(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fIp1\fP\fB);\fP + +\fBint png_debug2(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fP\fIp1\fP\fB, \fIp2\fP\fB);\fP + +\fBvoid png_destroy_info_struct (png_structp \fP\fIpng_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP + +\fBvoid png_destroy_read_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fP\fIinfo_ptr_ptr\fP\fB, png_infopp \fIend_info_ptr_ptr\fP\fB);\fP + +\fBvoid png_destroy_write_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP + +\fBvoid png_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fBvoid png_free (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP + +\fBvoid png_free_chunk_list (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_free_default(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP + +\fBvoid png_free_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fInum\fP\fB);\fP + +\fBpng_byte png_get_bit_depth (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fI*background\fP\fB);\fP + +\fBpng_byte png_get_channels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*white_x\fP\fB, double \fP\fI*white_y\fP\fB, double \fP\fI*red_x\fP\fB, double \fP\fI*red_y\fP\fB, double \fP\fI*green_x\fP\fB, double \fP\fI*green_y\fP\fB, double \fP\fI*blue_x\fP\fB, double \fI*blue_y\fP\fB);\fP + +\fBpng_uint_32 png_get_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*white_x\fP\fB, png_uint_32 \fP\fI*white_y\fP\fB, png_uint_32 \fP\fI*red_x\fP\fB, png_uint_32 \fP\fI*red_y\fP\fB, png_uint_32 \fP\fI*green_x\fP\fB, png_uint_32 \fP\fI*green_y\fP\fB, png_uint_32 \fP\fI*blue_x\fP\fB, png_uint_32 \fI*blue_y\fP\fB);\fP + +\fBpng_byte png_get_color_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_byte png_get_compression_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_byte png_get_copyright (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_voidp png_get_error_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_filter_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fI*file_gamma\fP\fB);\fP + +\fBpng_uint_32 png_get_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fI*int_file_gamma\fP\fB);\fP + +\fBpng_byte png_get_header_ver (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_header_version (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fI*hist\fP\fB);\fP + +\fBpng_uint_32 png_get_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charpp \fP\fIname\fP\fB, int \fP\fI*compression_type\fP\fB, png_charpp \fP\fIprofile\fP\fB, png_uint_32 \fI*proflen\fP\fB);\fP + +\fBpng_uint_32 png_get_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*width\fP\fB, png_uint_32 \fP\fI*height\fP\fB, int \fP\fI*bit_depth\fP\fB, int \fP\fI*color_type\fP\fB, int \fP\fI*interlace_type\fP\fB, int \fP\fI*compression_type\fP\fB, int \fI*filter_type\fP\fB);\fP + +\fBpng_uint_32 png_get_image_height (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_image_width (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fB#if !defined(PNG_1_0_X) png_int_32 png_get_int_32 (png_bytep buf); \fI#endif + +\fBpng_byte png_get_interlace_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_voidp png_get_io_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_libpng_ver (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_voidp png_get_mem_ptr(png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*offset_x\fP\fB, png_uint_32 \fP\fI*offset_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fBpng_uint_32 png_get_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fI*purpose\fP\fB, png_int_32 \fP\fI*X0\fP\fB, png_int_32 \fP\fI*X1\fP\fB, int \fP\fI*type\fP\fB, int \fP\fI*nparams\fP\fB, png_charp \fP\fI*units\fP\fB, png_charpp \fI*params\fP\fB);\fP + +\fBpng_uint_32 png_get_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fBfloat png_get_pixel_aspect_ratio (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_voidp png_get_progressive_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fI*palette\fP\fB, int \fI*num_palette\fP\fB);\fP + +\fBpng_byte png_get_rgb_to_gray_status (png_structp png_ptr) png_uint_32 png_get_rowbytes (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_bytepp png_get_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fI*sig_bit\fP\fB);\fP + +\fBpng_bytep png_get_signature (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fI*splt_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fI*intent\fP\fB);\fP + +\fBpng_uint_32 png_get_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fI*text_ptr\fP\fB, int \fI*num_text\fP\fB);\fP + +\fBpng_uint_32 png_get_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fI*mod_time\fP\fB);\fP + +\fBpng_uint_32 png_get_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fI*trans\fP\fB, int \fP\fI*num_trans\fP\fB, png_color_16p \fI*trans_values\fP\fB);\fP + +\fB#if !defined(PNG_1_0_X) png_uint_16 png_get_uint_16 (png_bytep \fIbuf\fP\fB);\fP + +\fBpng_uint_32 png_get_uint_31 (png_bytep \fIbuf\fP\fB);\fP + +\fBpng_uint_32 png_get_uint_32 (png_bytep buf); \fI#endif + +\fBpng_uint_32 png_get_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkpp \fIunknowns\fP\fB);\fP + +\fBpng_voidp png_get_user_chunk_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_user_height_max( png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_voidp png_get_user_transform_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_user_width_max (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_valid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIflag\fP\fB);\fP + +\fBpng_int_32 png_get_x_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_x_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_x_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_y_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_y_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_y_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_compression_buffer_size (png_structp \fIpng_ptr\fP\fB);\fP + +\fBint png_handle_as_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP + +\fBvoid png_init_io (png_structp \fP\fIpng_ptr\fP\fB, FILE \fI*fp\fP\fB);\fP + +\fBDEPRECATED void png_info_init (png_infop \fIinfo_ptr\fP\fB);\fP + +\fBDEPRECATED void png_info_init_2 (png_infopp \fP\fIptr_ptr\fP\fB, png_size_t \fIpng_info_struct_size\fP\fB);\fP + +\fBpng_voidp png_malloc (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fBpng_voidp png_malloc_default(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fBvoidp png_memcpy (png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_size_t \fIsize\fP\fB);\fP + +\fBpng_voidp png_memcpy_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fBvoidp png_memset (png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_size_t \fIsize\fP\fB);\fP + +\fBpng_voidp png_memset_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fBDEPRECATED void png_permit_empty_plte (png_structp \fP\fIpng_ptr\fP\fB, int \fIempty_plte_permitted\fP\fB);\fP + +\fBvoid png_process_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_size\fP\fB);\fP + +\fBvoid png_progressive_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIold_row\fP\fB, png_bytep \fInew_row\fP\fB);\fP + +\fBvoid png_read_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_infop \fIend_info_ptr\fP\fB);\fP + +\fBvoid png_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_read_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP + +\fBDEPRECATED void png_read_init (png_structp \fIpng_ptr\fP\fB);\fP + +\fBDEPRECATED void png_read_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP + +\fBvoid png_read_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_read_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP + +\fBvoid png_read_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fIdisplay_row\fP\fB);\fP + +\fBvoid png_read_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_bytepp \fP\fIdisplay_row\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP + +\fBvoid png_read_update_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fB#if !defined(PNG_1_0_X) png_save_int_32 (png_bytep \fP\fIbuf\fP\fB, png_int_32 \fIi\fP\fB);\fP + +\fBvoid png_save_uint_16 (png_bytep \fP\fIbuf\fP\fB, unsigned int \fIi\fP\fB);\fP + +\fBvoid png_save_uint_32 (png_bytep \fP\fIbuf\fP\fB, png_uint_32 \fIi\fP\fB);\fP + +\fBvoid png_set_add_alpha (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int flags); \fI#endif + +\fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP + +\fBvoid png_set_bgr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fIbackground\fP\fB);\fP + +\fBvoid png_set_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP + +\fBvoid png_set_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP + +\fBvoid png_set_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP + +\fBvoid png_set_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP + +\fBvoid png_set_compression_method (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod\fP\fB);\fP + +\fBvoid png_set_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP + +\fBvoid png_set_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP + +\fBvoid png_set_crc_action (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcrit_action\fP\fB, int \fIancil_action\fP\fB);\fP + +\fBvoid png_set_dither (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fP\fInum_palette\fP\fB, int \fP\fImaximum_colors\fP\fB, png_uint_16p \fP\fIhistogram\fP\fB, int \fIfull_dither\fP\fB);\fP + +\fBvoid png_set_error_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarning_fn\fP\fB);\fP + +\fBvoid png_set_expand (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_expand_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_filler (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP + +\fBvoid png_set_filter (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImethod\fP\fB, int \fIfilters\fP\fB);\fP + +\fBvoid png_set_filter_heuristics (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_doublep \fP\fIfilter_weights\fP\fB, png_doublep \fIfilter_costs\fP\fB);\fP + +\fBvoid png_set_flush (png_structp \fP\fIpng_ptr\fP\fB, int \fInrows\fP\fB);\fP + +\fBvoid png_set_gamma (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIscreen_gamma\fP\fB, double \fIdefault_file_gamma\fP\fB);\fP + +\fBvoid png_set_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP + +\fBvoid png_set_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIfile_gamma\fP\fB);\fP + +\fBvoid png_set_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_gray_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fIhist\fP\fB);\fP + +\fBvoid png_set_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, png_uint_32 \fIproflen\fP\fB);\fP + +\fBint png_set_interlace_handling (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_invalid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fImask\fP\fB);\fP + +\fBvoid png_set_invert_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_invert_mono (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP + +\fBvoid png_set_keep_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIkeep\fP\fB, png_bytep \fP\fIchunk_list\fP\fB, int \fInum_chunks\fP\fB);\fP + +\fBvoid png_set_mem_fn(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fBvoid png_set_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIoffset_x\fP\fB, png_uint_32 \fP\fIoffset_y\fP\fB, int \fIunit_type\fP\fB);\fP + +\fBvoid png_set_packing (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_packswap (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_palette_to_rgb(png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP + +\fBvoid png_set_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIres_x\fP\fB, png_uint_32 \fP\fIres_y\fP\fB, int \fIunit_type\fP\fB);\fP + +\fBvoid png_set_progressive_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIprogressive_ptr\fP\fB, png_progressive_info_ptr \fP\fIinfo_fn\fP\fB, png_progressive_row_ptr \fP\fIrow_fn\fP\fB, png_progressive_end_ptr \fIend_fn\fP\fB);\fP + +\fBvoid png_set_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP + +\fBvoid png_set_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fIread_data_fn\fP\fB);\fP + +\fBvoid png_set_read_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_read_status_ptr \fIread_row_fn\fP\fB);\fP + +\fBvoid png_set_read_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIread_user_transform_fn\fP\fB);\fP + +\fBvoid png_set_rgb_to_gray (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIerror_action\fP\fB, double \fP\fIred\fP\fB, double \fIgreen\fP\fB);\fP + +\fBvoid png_set_rgb_to_gray_fixed (png_structp \fP\fIpng_ptr\fP\fB, int error_action png_fixed_point \fP\fIred\fP\fB, png_fixed_point \fIgreen\fP\fB);\fP + +\fBvoid png_set_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytepp \fIrow_pointers\fP\fB);\fP + +\fBvoid png_set_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fIsig_bit\fP\fB);\fP + +\fBvoid png_set_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP + +\fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP + +\fBvoid png_set_sig_bytes (png_structp \fP\fIpng_ptr\fP\fB, int \fInum_bytes\fP\fB);\fP + +\fBvoid png_set_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fP\fIsplt_ptr\fP\fB, int \fInum_spalettes\fP\fB);\fP + +\fBvoid png_set_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP + +\fBvoid png_set_sRGB_gAMA_and_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP + +\fBvoid png_set_strip_16 (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_strip_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_swap (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_swap_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP + +\fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP + +\fBvoid png_set_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fP\fInum_trans\fP\fB, png_color_16p \fItrans_values\fP\fB);\fP + +\fBvoid png_set_tRNS_to_alpha(png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_set_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkp \fP\fIunknowns\fP\fB, int \fP\fInum\fP\fB, int \fIlocation\fP\fB);\fP + +\fBvoid png_set_unknown_chunk_location(png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIchunk\fP\fB, int \fIlocation\fP\fB);\fP + +\fBvoid png_set_read_user_chunk_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_chunk_ptr\fP\fB, png_user_chunk_ptr \fIread_user_chunk_fn\fP\fB);\fP + +\fBvoid png_set_user_limits (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIuser_width_max\fP\fB, png_uint_32 \fIuser_height_max\fP\fB);\fP + +\fBvoid png_set_user_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_transform_ptr\fP\fB, int \fP\fIuser_transform_depth\fP\fB, int \fIuser_transform_channels\fP\fB);\fP + +\fBvoid png_set_write_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fP\fIwrite_data_fn\fP\fB, png_flush_ptr \fIoutput_flush_fn\fP\fB);\fP + +\fBvoid png_set_write_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_write_status_ptr \fIwrite_row_fn\fP\fB);\fP + +\fBvoid png_set_write_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIwrite_user_transform_fn\fP\fB);\fP + +\fBvoid png_set_compression_buffer_size(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fBint png_sig_cmp (png_bytep \fP\fIsig\fP\fB, png_size_t \fP\fIstart\fP\fB, png_size_t \fInum_to_check\fP\fB);\fP + +\fBvoid png_start_read_image (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fBvoid png_write_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_write_chunk_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_write_chunk_end (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_chunk_start (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_write_destroy (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_write_flush (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP + +\fBDEPRECATED void png_write_init (png_structp \fIpng_ptr\fP\fB);\fP + +\fBDEPRECATED void png_write_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP + +\fBvoid png_write_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_write_info_before_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_write_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP + +\fBvoid png_write_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_write_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP + +\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP + +\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP + +.SH DESCRIPTION +The +.I libpng +library supports encoding, decoding, and various manipulations of +the Portable Network Graphics (PNG) format image files. It uses the +.IR zlib(3) +compression library. +Following is a copy of the libpng.txt file that accompanies libpng. +.SH LIBPNG.TXT +libpng.txt - A description on how to use and modify libpng + + libpng version 1.2.51 - February 6, 2014 + Updated and distributed by Glenn Randers-Pehrson + + Copyright (c) 1998-2014 Glenn Randers-Pehrson + + This document is released under the libpng license. + For conditions of distribution and use, see the disclaimer + and license in png.h + + Based on: + + libpng versions 0.97, January 1998, through 1.2.51 - February 6, 2014 + Updated and distributed by Glenn Randers-Pehrson + Copyright (c) 1998-2014 Glenn Randers-Pehrson + + libpng 1.0 beta 6 version 0.96 May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + +.SH I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. There are five sections to this +file: introduction, structures, reading, writing, and modification and +configuration notes for various special platforms. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to install libpng. + +For examples of libpng usage, see the files "example.c", "pngtest.c", +and the files in the "contrib" directory, all of which are included in +the libpng distribution. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG specification (second edition), November 2003, is available as +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at +. It is technically equivalent +to the PNG specification (second edition) but has some additional material. + +The PNG-1.0 specification is available +as RFC 2083 and as a +W3C Recommendation . + +Some additional chunks are described in the special-purpose public chunks +documents at . + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, . + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, . +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. + +.SH II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. The first, png_struct, is an internal structure that +will not, for the most part, be used by a user except as the first +variable passed to every libpng function call. + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed. The fields of png_info are still available for +older applications, but it is suggested that applications use the new +interfaces if at all possible. + +Applications that do make direct access to the members of png_struct (except +for png_ptr->jmpbuf) must be recompiled whenever the library is updated, +and applications that make direct access to the members of png_info must +be recompiled if they were compiled or loaded with libpng version 1.0.6, +in which the members were in a different order. In version 1.0.7, the +members of the png_info structure reverted to the old order, as they were +in versions 0.97c through 1.0.5. Starting with version 2.0.0, both +structures are going to be hidden, and the contents of the structures will +only be accessible through the png_get/png_set functions. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include + +.SH III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +.SS Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 (false) if the bytes match the +corresponding bytes of the PNG signature, or nonzero (true) otherwise. +Of course, the more bytes you pass in, the greater the accuracy of the +prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes_read() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + fread(header, 1, number, fp); + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the jmpbuf field every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +.SS Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_ptr ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data, along with similar data for any other + unknown chunks: */ + + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Search for your chunk in the + unknown chunk structure, process it, and return one + of the following: */ + + return (\-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +If you call the png_set_read_user_chunk_fn() function, then all unknown +chunks will be saved when read, in case your callback function will need +one or more of them. This behavior can be changed with the +png_set_keep_unknown_chunks() function, described below. + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_ptr ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +.SS Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members while unknown chunks will be discarded. This +behavior can be wasteful if your application will never use some known +chunk types. To change this, you can call: + + png_set_keep_unknown_chunks(png_ptr, keep, + chunk_list, num_chunks); + keep - 0: default unknown chunk handling + 1: ignore; do not keep + 2: keep only if safe-to-copy + 3: keep even if unsafe-to-copy + You can use these definitions: + PNG_HANDLE_CHUNK_AS_DEFAULT 0 + PNG_HANDLE_CHUNK_NEVER 1 + PNG_HANDLE_CHUNK_IF_SAFE 2 + PNG_HANDLE_CHUNK_ALWAYS 3 + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is 0) + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected. If nonzero, + only the chunks in the list are affected + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. The IHDR and IEND chunks should not be named in +chunk_list; if they are, libpng will process them normally anyway. + +Here is an example of the usage of png_set_keep_unknown_chunks(), +where the private "vpAg" chunk will later be processed by a user chunk +callback function: + + png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + png_byte unused_chunks[]= + { + 104, 73, 83, 84, (png_byte) '\0', /* hIST */ + 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ + 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ + 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ + 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ + 116, 73, 77, 69, (png_byte) '\0', /* tIME */ + }; + #endif + + ... + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* ignore all unknown chunks: */ + png_set_keep_unknown_chunks(read_ptr, 1, NULL, 0); + /* except for vpAg: */ + png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); + /* also ignore unused known chunks: */ + png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, + (int)sizeof(unused_chunks)/5); + #endif + +.SS User limits + +The PNG specification allows the width and height of an image to be as +large as 2^(31\-1 (0x7fffffff), or about 2.147 billion rows and columns. +Since very few applications really need to process such large images, +we have imposed an arbitrary 1-million limit on rows and columns. +Larger images will be rejected immediately with a png_error() call. If +you wish to override this limit, you can use + + png_set_user_limits(png_ptr, width_max, height_max); + +to set your own limits, or use width_max = height_max = 0x7fffffffL +to allow all valid dimensions (libpng may reject some very large images +anyway because of potential buffer overflow conditions). + +You should put this statement after you create the PNG structure and +before calling png_read_info(), png_read_png(), or png_process_data(). +If you need to retrieve the limits that are being applied, use + + width_max = png_get_user_width_max(png_ptr); + height_max = png_get_user_height_max(png_ptr); + +The PNG specification sets no limit on the number of ancillary chunks +allowed in a PNG datastream. You can impose a limit on the total number +of sPLT, tEXt, iTXt, zTXt, and unknown chunks that will be stored, with + + png_set_chunk_cache_max(png_ptr, user_chunk_cache_max); + +where 0x7fffffffL means unlimited. You can retrieve this limit with + + chunk_cache_max = png_get_chunk_cache_max(png_ptr); + +This limit also applies to the number of buffers that can be allocated +by png_decompress_chunk() while decompressing iTXt, zTXt, and iCCP chunks. + +.SS The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to + 8 bits + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples + to RGB (or GA to RGBA) + +(This excludes setting a background color, doing gamma transformation, +dithering, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some +set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_read_png(). + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) + png_error (png_ptr, + "Image is too tall to process in memory"); + if (width > PNG_UINT_32_MAX/pixel_size) + png_error (png_ptr, + "Image is too wide to process in memory"); + row_pointers = png_malloc(png_ptr, + height*png_sizeof(png_bytep)); + for (int i=0; i) and +png_get_(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_ are set directly if they are simple data types, or a +pointer into the info_ptr is returned for any complex types. + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &gamma); + gamma - the gamma the file is written + at (PNG_INFO_gAMA) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + &trans_values); + trans - array of transparent + entries for palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + background - background color (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + num_comments - number of comments + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (empty + string for unknown). + text_ptr[i].lang_key - keyword in UTF-8 + (empty string for unknown). + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist + when the library is built with iTXt chunk support. + + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + num_spalettes - number of sPLT chunks read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + offset_x - positive offset from the left edge + of the screen + offset_y - positive offset from the top edge + of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + res_x - pixels/unit physical resolution in + x direction + res_y - pixels/unit physical resolution in + x direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + (Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y) + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + (Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel) + +For more information, see the png_info definition in png.h and the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +.SS Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +The colors used for the background and transparency values should be +supplied in the same format/depth as the current image data. They +are stored in the same format/depth as the image data in a bKGD or tRNS +chunk, so this is what libpng expects for this data. The colors are +transformed to keep in sync with the image data when an application +calls the png_read_update_info() routine (see below). + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the +byte, unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() +is called to insert filler bytes, either before or after each RGB triplet. +16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant +byte of the color value first, unless png_set_strip_16() is called to +transform it to regular RGB RGB triplets, or png_set_filler() or +png_set_add alpha() is called to insert filler bytes, either before or +after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can +be modified with +png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + +These three functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was +added. It expands the sample depth without changing tRNS to alpha. + +As of libpng version 1.2.51, not all possible expansions are supported. + +In the following table, the 01 means grayscale with depth<8, 31 means +indexed with depth<8, other numerals represent the color type, "T" means +the tRNS chunk is present, A means an alpha channel is present, and O +means tRNS or alpha is present but all pixels in the image are opaque. + + FROM 01 31 0 0T 0O 2 2T 2O 3 3T 3O 4A 4O 6A 6O + TO + 01 - + 31 - + 0 1 - + 0T - + 0O - + 2 GX - + 2T - + 2O - + 3 1 - + 3T - + 3O - + 4A T - + 4O - + 6A GX TX TX - + 6O GX TX - + +Within the matrix, + "-" means the transformation is not supported. + "X" means the transformation is obtained by png_set_expand(). + "1" means the transformation is obtained by + png_set_expand_gray_1_2_4_to_8 + "G" means the transformation is obtained by + png_set_gray_to_rgb(). + "P" means the transformation is obtained by + png_set_expand_palette_to_rgb(). + "T" means the transformation is obtained by + png_set_tRNS_to_alpha(). + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8 bit. + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + +If, for some reason, you don't need the alpha channel on an image, +and you want to remove it rather than combining it with the background +(but the image author certainly had in mind that you *would* combine +it with the background, so that's what you should probably do): + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +The PNG format only supports pixels with postmultiplied alpha. +If you want to replace the pixels, after reading them, with pixels +that have premultiplied color samples, you can do this with + + png_set_premultiply_alpha(png_ptr); + +If you do this, any input with a tRNS chunk will be expanded to +have an alpha channel. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] +to 8 bits/sample in the range [0, 255]). However, it is also possible +to convert the PNG pixel data back to the original bit depth of the +image. This call reduces the pixels back down to the original bit depth: + + png_color_8p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them +into 4 or 8 bytes for windowing systems that need them in this format: + + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" is the 8 or 16-bit number to fill with, and the location is +either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. This transformation +does not affect images that already have full alpha channels. To add an +opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which +will generate RGBA pixels. + +Note that png_set_filler() does not change the color type. If you want +to do that, you can add a true alpha channel with + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); + +where "filler" contains the alpha value to assign to each pixel. +This function was added in libpng-1.2.7. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray_fixed(png_ptr, error_action, + int red_weight, int green_weight); + + error_action = 1: silently do the conversion + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component times 100000 + green_weight: weight of green component times 100000 + If either weight is negative, default + weights (21268, 71514) are used. + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. bKGD and sBIT data +will be silently converted to grayscale, using the green channel +data, regardless of the error_action setting. + +With red_weight+green_weight<=100000, +the normalized graylevel is computed: + + int rw = red_weight * 65536; + int gw = green_weight * 65536; + int bw = 65536 - (rw + gw); + gray = (rw*red + gw*green + bw*blue)/65536; + +The default values approximate those recommended in the Charles +Poynton's Color FAQ, +Copyright (c) 1998-01-04 Charles Poynton + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng approximates this with + + Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + +which can be expressed with integers as + + Y = (6969 * R + 23434 * G + 2365 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +is known. + +If you have a grayscale and you are using png_set_expand_depth(), +png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to +a higher bit-depth, you must either supply the background color as a gray +value at the original file bit-depth (need_expand = 1) or else supply the +background color as an RGB triplet at the final, expanded bit depth +(need_expand = 0). Similarly, if you are reading a paletted image, you +must either supply the background color as a palette index (need_expand = 1) +or as an RGB triplet that may or may not be in the palette (need_expand = 0). + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + +The png_set_background() function tells libpng to composite images +with alpha or simple transparency against the supplied background +color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng whether the color is in the gamma space of the +display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file +(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one +that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't +know why anyone would use this, but it's here). + +To properly display PNG images on any kind of system, the application needs +to know what the display gamma is. Ideally, the user will know this, and +the application will allow them to set it. One method of allowing the user +to set the display gamma separately for each system is to check for a +SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be +correctly set. + +Note that display_gamma is the overall gamma correction required to produce +pleasing results, which depends on the lighting conditions in the surrounding +environment. In a dim or brightly lit room, no compensation other than +the physical gamma exponent of the monitor is needed, while in a dark room +a slightly smaller exponent is better. + + double gamma, screen_gamma; + + if (/* We have a user-defined screen + gamma value */) + { + screen_gamma = user_defined_screen_gamma; + } + /* One way that applications can share the same + screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) + != NULL) + { + screen_gamma = (double)atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a + PC monitor in a bright office or a dim room */ + screen_gamma = 2.0; /* A good guess for a + PC monitor in a dark room */ + screen_gamma = 1.7 or 1.0; /* A good + guess for Mac systems */ + } + +The png_set_gamma() function handles gamma transformations of the data. +Pass both the file gamma and the current screen_gamma. If the file does +not have a gamma value, you can pass one anyway if you have an idea what +it is (usually 0.45455 is a good guess for GIF images on PCs). Note +that file gammas are inverted from screen gammas. See the discussions +on gamma in the PNG specification for an excellent description of what +gamma is, and why all applications should support it. It is strongly +recommended that PNG viewers support gamma correction. + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries then will fit on your screen, png_set_dither() +will do that. Note that this is a simple match dither that merely +finds the closest color available. This should work fairly well with +optimized palettes, and fairly badly with linear color cubes. If you +pass a palette that is larger then maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, it will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_dither(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) + png_set_invert_mono(png_ptr); + +This function can also be used to invert grayscale and gray-alpha images: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_invert_mono(png_ptr); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. + + png_read_update_info(png_ptr, info_ptr); + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +.SS Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't need +to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) +is a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. + +libpng can fill out those images or it can give them to you "as is". +If you want them filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() seven times to read in all seven images. Each of the +images is a valid image by itself, or they can all be combined on an +8x8 grid to form a single image (although if you intend to combine them +you would be far better off using the libpng interlace handling). + +The first pass will return an image 1/8 as wide as the entire image +(every 8th column starting in column 0) and 1/8 as high as the original +(every 8th row starting in row 0), the second will be 1/8 as wide +(starting in column 4) and 1/8 as high (also starting in row 0). The +third pass will be 1/4 as wide (every 4th pixel starting in column 0) and +1/8 as high (every 8th row starting in row 4), and the fourth pass will +be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, +and every 4th row starting in row 0). The fifth pass will return an +image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), +while the sixth pass will be 1/2 as wide and 1/2 as high as the original +(starting in column 1 and row 0). The seventh and final pass will be as +wide as the original, and 1/2 as high, containing all of the odd +numbered scanlines. Phew! + +If you want libpng to expand the images, call this before calling +png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. +This function can be called even if the file is not interlaced, +where it will return one pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +.SS Finishing a sequential read + +After you are finished reading the image through the +low-level interface, you can finish reading the file. If you are +interested in comments or time, which may be stored either before or +after the image data, you should pass the separate png_info struct if +you want to keep the comments from before and after the image +separate. If you are not interested, you can pass NULL. + + png_read_end(png_ptr, end_info); + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (\-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not \-1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by +your application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + mask - identifies the chunks to be made invalid, + containing the bitwise OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +.SS Reading PNG files progressively + +The progressive reader is slightly different then the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, + (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less then 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + */ + } + + /* This function is called when each row of image + data is complete */ + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + For the non-NULL rows of interlaced images, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed for + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +.SH IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +.SS Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + if (!fp) + { + return (ERROR); + } + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +If you are embedding your PNG into a datastream such as MNG, and don't +want libpng to write the 8-byte signature, or if you have already +written the signature in your application, use + + png_set_sig_bytes(png_ptr, 8); + +to inform libpng that it should not write a signature. + +.SS Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific +filter types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the bitwise OR of one + or more PNG_FILTER_NAME masks. */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS); + +If an application +wants to start and stop using particular filters during compression, +it should start out with all of the filters (to ensure that the previous +row of pixels will be stored in case it's needed later), and then add +and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + +extern PNG_EXPORT(void,png_set_zbuf_size) + +.SS Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + +If you call png_set_IHDR(), the call must appear before any of the +other png_set_*() functions, because they might require access to some of +the IHDR settings. The remaining png_set_*() functions can be called +in any order. + +If you wish, you can reset the compression_type, interlace_type, or +filter_method later by calling png_set_IHDR() again; if you do this, the +width, height, bit_depth, and color_type must be the same in each call. + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_set_gAMA(png_ptr, info_ptr, gamma); + gamma - the gamma the image was created + at (PNG_INFO_gAMA) + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, + trans_values); + trans - array of transparent + entries for palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values + (in order red, green, blue) of the + single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_set_tIME(png_ptr, info_ptr, mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + background - background color (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist + when the library is built with iTXt chunk support. + + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + offset_x - positive offset from the left + edge of the screen + offset_y - positive offset from the top + edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + res_x - pixels/unit physical resolution + in x direction + res_y - pixels/unit physical resolution + in y direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around 1000 bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct. + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + Author Name of image's creator + Description Description of image (possibly long) + Copyright Copyright notice + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123(png_timep) is provided to convert from PNG +time to an RFC 1123 format string. + +.SS Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up chunks +for writing. You give it a chunk name, raw data, and a size; that's +all there is to it. The chunks will be written by the next following +png_write_info_before_PLTE, png_write_info, or png_write_end function. +Any chunks previously read into the info structure's unknown-chunk +list will also be written out in a sequence that satisfies the PNG +specification's ordering rules. + +.SS The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler + bytes (deprecated). + PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading + filler bytes + PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing + filler bytes + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_write_png(). + +.SS The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of transparency, +you can invert the alpha channel before you write it, so that 0 is +fully transparent and 255 (in 8-bit or paletted images) or 65535 +(in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + else + { + sig_bit.gray = true_bit_depth; + } + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +.SS Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more complicated. +The only currently (as of the PNG Specification version 1.2, dated July +1999) defined interlacing scheme for PNG files is the "Adam7" interlace +scheme, that breaks down an image into seven smaller images of varying +size. libpng will build these images for you, or you can do them +yourself. If you want to build them yourself, see the PNG specification +for details of which pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all seven sub-images. + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = + png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this is seven, +but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +As some of these rows are not used, and thus return immediately, you may +want to read about interlacing in the PNG specification, and only update +the rows that are actually used. + +.SS Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (\-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not \-1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +If you allocated data such as a palette that you passed in to libpng +with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +.SH V. Modifying/Customizing libpng: + +There are two issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc(), png_calloc(), +and png_free(). These currently just call the standard C functions. +png_calloc() calls png_malloc() and then png_memset() to clear the newly +allocated memory to zero. If your pointers can't access more then 64K +at a time, you will want to set MAXSEG_64K in zlib.h. Since it is +unlikely that the method of handling memory allocation on a platform +will change between applications, these functions must be modified in +the library at compile time. If you prefer to use a different method +of allocating and freeing data, you can use png_create_read_struct_2() or +png_create_write_struct_2() to register your own functions as described +above. These functions also provide a void pointer that can be retrieved +via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_size_t size); + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() must return NULL in case of failure. The png_malloc() +function will normally call png_error() if it receives a NULL from the +system memory allocator or from your replacement malloc_fn(). + +Your free_fn() will never be called with a NULL ptr, since libpng's +png_free() checks for NULL before calling free_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_write_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_flush_data(png_structp png_ptr); + +The user_read_data() function is responsible for detecting and +handling end-of-data errors. + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions, which expect the io_ptr to +point to a standard *FILE structure. It is probably a mistake +to use NULL for one of write_data_fn and output_flush_fn but not both +of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. +It is an error to read from a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything +after setjmp returns non-zero besides returning itself. Consult your +compiler documentation for more details. For an alternative approach, you +may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net). + +.SS Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. However, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of understanding of how it works. +Pay particular attention to the sections that describe chunk names, +and look at how other chunks were designed, so you can do things +similarly. Second, check out the sections of libpng that read and +write chunks. Try to find a chunk that is similar to yours and use +it as a template. More details can be found in the comments inside +the code. It is best to handle unknown chunks in a generic method, +via callback functions, instead of by modifying libpng functions. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +.SS Configuring for 16 bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more then 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +.SS Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +.SS Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is an +unsigned char far * far *. + +.SS Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +.SS Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add, change +or delete an include, this is the place to do it. +The includes that are not needed outside libpng are protected by the +PNG_INTERNAL definition, which is only defined for those routines inside +libpng itself. The files in libpng proper only include png.h, which +includes pngconf.h. + +.SS Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). +Note that the memory level does have an effect on compression; among +other things, lower levels will result in sections of incompressible +data being emitted in smaller stored blocks, with a correspondingly +larger relative overhead of up to 15% in the worst case. + + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + png_set_compression_strategy(png_ptr, + strategy); + png_set_compression_window_bits(png_ptr, + window_bits); + png_set_compression_method(png_ptr, method); + png_set_compression_buffer_size(png_ptr, size); + +.SS Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS +to turn filtering on and off, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. +If you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. (Note that this +means the first row must always be adaptively filtered, because libpng +currently does not allocate the filter buffers until png_write_row() +is called for the first time.) + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB + PNG_FILTER_UP | PNG_FILTER_AVG | + PNG_FILTER_PAETH | PNG_ALL_FILTERS; + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +It is also possible to influence how libpng chooses from among the +available filters. This is done in one or both of two ways - by +telling it how important it is to keep the same filter for successive +rows, and by telling it the relative computational costs of the filters. + + double weights[3] = {1.5, 1.3, 1.1}, + costs[PNG_FILTER_VALUE_LAST] = + {1.0, 1.3, 1.3, 1.5, 1.7}; + + png_set_filter_heuristics(png_ptr, + PNG_FILTER_HEURISTIC_WEIGHTED, 3, + weights, costs); + +The weights are multiplying factors that indicate to libpng that the +row filter should be the same for successive rows unless another row filter +is that many times better than the previous filter. In the above example, +if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a +"sum of absolute differences" 1.5 x 1.3 times higher than other filters +and still be chosen, while the NONE filter could have a sum 1.1 times +higher than other filters and still be chosen. Unspecified weights are +taken to be 1.0, and the specified weights should probably be declining +like those above in order to emphasize recent filters over older filters. + +The filter costs specify for each filter type a relative decoding cost +to be considered when selecting row filters. This means that filters +with higher costs are less likely to be chosen over filters with lower +costs, unless their "sum of absolute differences" is that much smaller. +The costs do not necessarily reflect the exact computational speeds of +the various filters, since this would unduly influence the final image +size. + +Note that the numbers above were invented purely for this example and +are given only to help explain the function usage. Little testing has +been done to find optimum values for either the costs or the weights. + +.SS Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, +along with directives to turn on any of the capabilities that you do +want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the extra +transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks. Use of the +PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library +that is incapable of reading or writing ancillary chunks. If you are +not using the progressive reading capability, you can turn that off +with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING +capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with pngr and all the writing files start with +pngw. The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +.SS Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d", foo); + +is expanded to + + if(PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\en", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + +.SH VI. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + mask is a png_uint_32 containing the bitwise OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + feature_set is a png_uint_32 that is the bitwise AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +.SH VII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 2.0.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; +however, iTXt support was not enabled by default. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +.SH VIII. Changes to Libpng from version 1.0.x to 1.2.x + +Support for user memory management was enabled by default. To +accomplish this, the functions png_create_read_struct_2(), +png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), +png_malloc_default(), and png_free_default() were added. + +Support for the iTXt chunk has been enabled by default as of +version 1.2.41. + +Support for certain MNG features was enabled. + +Support for numbered error messages was added. However, we never got +around to actually numbering the error messages. The function +png_set_strip_error_numbers() was added (Note: the prototype for this +function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE +builds of libpng-1.2.15. It was restored in libpng-1.2.36). + +The png_malloc_warn() function was added at libpng-1.2.3. This issues +a png_warning and returns NULL instead of aborting when it fails to +acquire the requested memory allocation. + +Support for setting user limits on image width and height was enabled +by default. The functions png_set_user_limits(), png_get_user_width_max(), +and png_get_user_height_max() were added at libpng-1.2.6. + +The png_set_add_alpha() function was added at libpng-1.2.7. + +The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. +Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the +tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is +deprecated. + +A number of macro definitions in support of runtime selection of +assembler code features (especially Intel MMX code support) were +added at libpng-1.2.0: + + PNG_ASM_FLAG_MMX_SUPPORT_COMPILED + PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW + PNG_ASM_FLAG_MMX_READ_INTERLACE + PNG_ASM_FLAG_MMX_READ_FILTER_SUB + PNG_ASM_FLAG_MMX_READ_FILTER_UP + PNG_ASM_FLAG_MMX_READ_FILTER_AVG + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH + PNG_ASM_FLAGS_INITIALIZED + PNG_MMX_READ_FLAGS + PNG_MMX_FLAGS + PNG_MMX_WRITE_FLAGS + PNG_MMX_FLAGS + +We added the following functions in support of runtime +selection of assembler code features: + + png_get_mmx_flagmask() + png_set_mmx_thresholds() + png_get_asm_flags() + png_get_mmx_bitdepth_threshold() + png_get_mmx_rowbytes_threshold() + png_set_asm_flags() + +We replaced all of these functions with simple stubs in libpng-1.2.20, +when the Intel assembler code was removed due to a licensing issue. + +These macros are deprecated: + + PNG_READ_TRANSFORMS_NOT_SUPPORTED + PNG_PROGRESSIVE_READ_NOT_SUPPORTED + PNG_NO_SEQUENTIAL_READ_SUPPORTED + PNG_WRITE_TRANSFORMS_NOT_SUPPORTED + PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED + PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED + +They have been replaced, respectively, by: + + PNG_NO_READ_TRANSFORMS + PNG_NO_PROGRESSIVE_READ + PNG_NO_SEQUENTIAL_READ + PNG_NO_WRITE_TRANSFORMS + PNG_NO_READ_ANCILLARY_CHUNKS + PNG_NO_WRITE_ANCILLARY_CHUNKS + +PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been +deprecated since libpng-1.0.16 and libpng-1.2.6. + +The function + png_check_sig(sig, num) +was replaced with + !png_sig_cmp(sig, 0, num) +It has been deprecated since libpng-0.90. + +The function + png_set_gray_1_2_4_to_8() +which also expands tRNS to alpha was replaced with + png_set_expand_gray_1_2_4_to_8() +which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. + +.SH IX. (Omitted) + + +.SH X. Detecting libpng + +The png_get_io_ptr() function has been present since libpng-0.88, has never +changed, and is unaffected by conditional compilation macros. It is the +best choice for use in configure scripts for detecting the presence of any +libpng version since 0.88. In an autoconf "configure.in" you could use + + AC_CHECK_LIB(png, png_get_io_ptr, ... + +.SH XI. Source code repository + +Since about February 2009, version 1.2.34, libpng has been under "git" source +control. The git repository was built from old libpng-x.y.z.tar.gz files +going back to version 0.70. You can access the git repository (read only) +at + + git://git.code.sf.net/p/libpng/code + +or you can browse it with a web browser by selecting the "code" button at + + https://sourceforge.net/projects/libpng/ + +Patches can be sent to glennrp at users.sourceforge.net or to +png-mng-implement at lists.sourceforge.net or you can upload them to +the libpng bug tracker at + + http://libpng.sourceforge.net + +.SH XII. Coding style + +Our coding style is similar to the "Allman" style, with curly +braces on separate lines: + + if (condition) + { + action; + } + + else if (another condition) + { + another action; + } + +The braces can be omitted from simple one-line actions: + + if (condition) + return (0); + +We use 3-space indentation, except for continued statements which +are usually indented the same as the first line of the statement +plus four more spaces. + +For macro definitions we use 2-space indentation, always leaving the "#" +in the first column. + + #ifndef PNG_NO_FEATURE + # ifndef PNG_FEATURE_SUPPORTED + # define PNG_FEATURE_SUPPORTED + # endif + #endif + +Comments appear with the leading "/*" at the same indentation as +the statement that follows the comment: + + /* Single-line comment */ + statement; + + /* Multiple-line + * comment + */ + statement; + +Very short comments can be placed at the end of the statement +to which they pertain: + + statement; /* comment */ + +We don't use C++ style ("//") comments. We have, however, +used them in the past in some now-abandoned MMX assembler +code. + +Functions and their curly braces are not indented, and +exported functions are marked with PNGAPI: + + /* This is a public function that is visible to + * application programers. It does thus-and-so. + */ + void PNGAPI + png_exported_function(png_ptr, png_info, foo) + { + body; + } + +The prototypes for all exported functions appear in png.h, +above the comment that says + + /* Maintainer: Put new public prototypes here ... */ + +We mark all non-exported functions with "/* PRIVATE */"": + + void /* PRIVATE */ + png_non_exported_function(png_ptr, png_info, foo) + { + body; + } + +The prototypes for non-exported functions (except for those in +pngtest) appear in +the PNG_INTERNAL section of png.h +above the comment that says + + /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +The names of all exported functions and variables begin +with "png_", and all publicly visible C preprocessor +macros begin with "PNG". + +We put a space after each comma and after each semicolon +in "for" statments, and we put spaces before and after each +C binary operator and after "for" or "while". We don't +put a space between a typecast and the expression being +cast, nor do we put one between a function name and the +left parenthesis that follows it: + + for (i = 2; i > 0; --i) + y[i] = a(x) + (int)b; + +We prefer #ifdef and #ifndef to #if defined() and if !defined() +when there is only one macro being tested. + +We do not use the TAB character for indentation in the C sources. + +Lines do not exceed 80 characters. + +Other rules can be inferred by inspecting the libpng source. + +.SH XIII. Y2K Compliance in libpng + +February 6, 2014 + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.2.51 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has three year fields. One is a 2-byte unsigned integer that +will hold years up to 65535. The other two hold the date in text +format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + +There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group + +.SH NOTE + +Note about libpng version numbers: + +Due to various miscommunications, unforeseen code incompatibilities +and occasional factors outside the authors' control, version numbering +on the library has not always been consistent and straightforward. +The following table summarizes matters since version 0.89c, which was +the first widely used release: + + source png.h png.h shared-lib + version string int version + ------- ------ ----- ---------- + 0.89c ("beta 3") 0.89 89 1.0.89 + 0.90 ("beta 4") 0.90 90 0.90 + 0.95 ("beta 5") 0.95 95 0.95 + 0.96 ("beta 6") 0.96 96 0.96 + 0.97b ("beta 7") 1.00.97 97 1.0.1 + 0.97c 0.97 97 2.0.97 + 0.98 0.98 98 2.0.98 + 0.99 0.99 98 2.0.99 + 0.99a-m 0.99 99 2.0.99 + 1.00 1.00 100 2.1.0 + 1.0.0 1.0.0 100 2.1.0 + 1.0.0 (from here on, the 100 2.1.0 + 1.0.1 png.h string is 10001 2.1.0 + 1.0.1a-e identical to the 10002 from here on, the + 1.0.2 source version) 10002 shared library is 2.V + 1.0.2a-b 10003 where V is the source + 1.0.1 10001 code version except as + 1.0.1a-e 10002 2.1.0.1a-e noted. + 1.0.2 10002 2.1.0.2 + 1.0.2a-b 10003 2.1.0.2a-b + 1.0.3 10003 2.1.0.3 + 1.0.3a-d 10004 2.1.0.3a-d + 1.0.4 10004 2.1.0.4 + 1.0.4a-f 10005 2.1.0.4a-f + 1.0.5 (+ 2 patches) 10005 2.1.0.5 + 1.0.5a-d 10006 2.1.0.5a-d + 1.0.5e-r 10100 2.1.0.5e-r + 1.0.5s-v 10006 2.1.0.5s-v + 1.0.6 (+ 3 patches) 10006 2.1.0.6 + 1.0.6d-g 10007 2.1.0.6d-g + 1.0.6h 10007 10.6h + 1.0.6i 10007 10.6i + 1.0.6j 10007 2.1.0.6j + 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 + 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 + 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 + 1.0.7 1 10007 2.1.0.7 + 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + 1.0.8rc1 1 10008 2.1.0.8rc1 + 1.0.8 1 10008 2.1.0.8 + 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + 1.0.9rc1 1 10009 2.1.0.9rc1 + 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + 1.0.9rc2 1 10009 2.1.0.9rc2 + 1.0.9 1 10009 2.1.0.9 + 1.0.10beta1 1 10010 2.1.0.10beta1 + 1.0.10rc1 1 10010 2.1.0.10rc1 + 1.0.10 1 10010 2.1.0.10 + 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + 1.0.11rc1 1 10011 2.1.0.11rc1 + 1.0.11 1 10011 2.1.0.11 + 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + 1.0.12rc1 2 10012 2.1.0.12rc1 + 1.0.12 2 10012 2.1.0.12 + 1.1.0a-f - 10100 2.1.1.0a-f abandoned + 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + 1.2.0rc1 3 10200 3.1.2.0rc1 + 1.2.0 3 10200 3.1.2.0 + 1.2.1beta-4 3 10201 3.1.2.1beta1-4 + 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + 1.2.1 3 10201 3.1.2.1 + 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + 1.0.13 10 10013 10.so.0.1.0.13 + 1.2.2 12 10202 12.so.0.1.2.2 + 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + 1.2.3 12 10203 12.so.0.1.2.3 + 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + 1.0.14 10 10014 10.so.0.1.0.14 + 1.2.4 13 10204 12.so.0.1.2.4 + 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + 1.0.15rc1 10 10015 10.so.0.1.0.15rc1 + 1.0.15 10 10015 10.so.0.1.0.15 + 1.2.5 13 10205 12.so.0.1.2.5 + 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + 1.2.6rc1-5 13 10206 12.so.0.1.2.6rc1-5 + 1.0.16 10 10016 10.so.0.1.0.16 + 1.2.6 13 10206 12.so.0.1.2.6 + 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + 1.0.17rc1 10 10017 10.so.0.1.0.17rc1 + 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + 1.0.17 10 10017 10.so.0.1.0.17 + 1.2.7 13 10207 12.so.0.1.2.7 + 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5 + 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + 1.0.18 10 10018 10.so.0.1.0.18 + 1.2.8 13 10208 12.so.0.1.2.8 + 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + 1.2.9beta4-11 13 10209 12.so.0.9[.0] + 1.2.9rc1 13 10209 12.so.0.9[.0] + 1.2.9 13 10209 12.so.0.9[.0] + 1.2.10beta1-8 13 10210 12.so.0.10[.0] + 1.2.10rc1-3 13 10210 12.so.0.10[.0] + 1.2.10 13 10210 12.so.0.10[.0] + 1.2.11beta1-4 13 10211 12.so.0.11[.0] + 1.0.19rc1-5 10 10019 10.so.0.19[.0] + 1.2.11rc1-5 13 10211 12.so.0.11[.0] + 1.0.19 10 10019 10.so.0.19[.0] + 1.2.11 13 10211 12.so.0.11[.0] + 1.0.20 10 10020 10.so.0.20[.0] + 1.2.12 13 10212 12.so.0.12[.0] + 1.2.13beta1 13 10213 12.so.0.13[.0] + 1.0.21 10 10021 10.so.0.21[.0] + 1.2.13 13 10213 12.so.0.13[.0] + 1.2.14beta1-2 13 10214 12.so.0.14[.0] + 1.0.22rc1 10 10022 10.so.0.22[.0] + 1.2.14rc1 13 10214 12.so.0.14[.0] + 1.2.15beta1-6 13 10215 12.so.0.15[.0] + 1.0.23rc1-5 10 10023 10.so.0.23[.0] + 1.2.15rc1-5 13 10215 12.so.0.15[.0] + 1.0.23 10 10023 10.so.0.23[.0] + 1.2.15 13 10215 12.so.0.15[.0] + 1.2.16beta1-2 13 10216 12.so.0.16[.0] + 1.2.16rc1 13 10216 12.so.0.16[.0] + 1.0.24 10 10024 10.so.0.24[.0] + 1.2.16 13 10216 12.so.0.16[.0] + 1.2.17beta1-2 13 10217 12.so.0.17[.0] + 1.0.25rc1 10 10025 10.so.0.25[.0] + 1.2.17rc1-3 13 10217 12.so.0.17[.0] + 1.0.25 10 10025 10.so.0.25[.0] + 1.2.17 13 10217 12.so.0.17[.0] + 1.0.26 10 10026 10.so.0.26[.0] + 1.2.18 13 10218 12.so.0.18[.0] + 1.2.19beta1-31 13 10219 12.so.0.19[.0] + 1.0.27rc1-6 10 10027 10.so.0.27[.0] + 1.2.19rc1-6 13 10219 12.so.0.19[.0] + 1.0.27 10 10027 10.so.0.27[.0] + 1.2.19 13 10219 12.so.0.19[.0] + 1.2.20beta01-04 13 10220 12.so.0.20[.0] + 1.0.28rc1-6 10 10028 10.so.0.28[.0] + 1.2.20rc1-6 13 10220 12.so.0.20[.0] + 1.0.28 10 10028 10.so.0.28[.0] + 1.2.20 13 10220 12.so.0.20[.0] + 1.2.21beta1-2 13 10221 12.so.0.21[.0] + 1.2.21rc1-3 13 10221 12.so.0.21[.0] + 1.0.29 10 10029 10.so.0.29[.0] + 1.2.21 13 10221 12.so.0.21[.0] + 1.2.22beta1-4 13 10222 12.so.0.22[.0] + 1.0.30rc1 13 10030 10.so.0.30[.0] + 1.2.22rc1 13 10222 12.so.0.22[.0] + 1.0.30 10 10030 10.so.0.30[.0] + 1.2.22 13 10222 12.so.0.22[.0] + 1.2.23beta01-05 13 10223 12.so.0.23[.0] + 1.2.23rc01 13 10223 12.so.0.23[.0] + 1.2.23 13 10223 12.so.0.23[.0] + 1.2.24beta01-02 13 10224 12.so.0.24[.0] + 1.2.24rc01 13 10224 12.so.0.24[.0] + 1.2.24 13 10224 12.so.0.24[.0] + 1.2.25beta01-06 13 10225 12.so.0.25[.0] + 1.2.25rc01-02 13 10225 12.so.0.25[.0] + 1.0.31 10 10031 10.so.0.31[.0] + 1.2.25 13 10225 12.so.0.25[.0] + 1.2.26beta01-06 13 10226 12.so.0.26[.0] + 1.2.26rc01 13 10226 12.so.0.26[.0] + 1.2.26 13 10226 12.so.0.26[.0] + 1.0.32 10 10032 10.so.0.32[.0] + 1.2.27beta01-06 13 10227 12.so.0.27[.0] + 1.2.27rc01 13 10227 12.so.0.27[.0] + 1.0.33 10 10033 10.so.0.33[.0] + 1.2.27 13 10227 12.so.0.27[.0] + 1.0.34 10 10034 10.so.0.34[.0] + 1.2.28 13 10228 12.so.0.28[.0] + 1.2.29beta01-03 13 10229 12.so.0.29[.0] + 1.2.29rc01 13 10229 12.so.0.29[.0] + 1.0.35 10 10035 10.so.0.35[.0] + 1.2.29 13 10229 12.so.0.29[.0] + 1.0.37 10 10037 10.so.0.37[.0] + 1.2.30beta01-04 13 10230 12.so.0.30[.0] + 1.0.38rc01-08 10 10038 10.so.0.38[.0] + 1.2.30rc01-08 13 10230 12.so.0.30[.0] + 1.0.38 10 10038 10.so.0.38[.0] + 1.2.30 13 10230 12.so.0.30[.0] + 1.0.39rc01-03 10 10039 10.so.0.39[.0] + 1.2.31rc01-03 13 10231 12.so.0.31[.0] + 1.0.39 10 10039 10.so.0.39[.0] + 1.2.31 13 10231 12.so.0.31[.0] + 1.2.32beta01-02 13 10232 12.so.0.32[.0] + 1.0.40rc01 10 10040 10.so.0.40[.0] + 1.2.32rc01 13 10232 12.so.0.32[.0] + 1.0.40 10 10040 10.so.0.40[.0] + 1.2.32 13 10232 12.so.0.32[.0] + 1.2.33beta01-02 13 10233 12.so.0.33[.0] + 1.2.33rc01-02 13 10233 12.so.0.33[.0] + 1.0.41rc01 10 10041 10.so.0.41[.0] + 1.2.33 13 10233 12.so.0.33[.0] + 1.0.41 10 10041 10.so.0.41[.0] + 1.2.34beta01-07 13 10234 12.so.0.34[.0] + 1.0.42rc01 10 10042 10.so.0.42[.0] + 1.2.34rc01 13 10234 12.so.0.34[.0] + 1.0.42 10 10042 10.so.0.42[.0] + 1.2.34 13 10234 12.so.0.34[.0] + 1.2.35beta01-03 13 10235 12.so.0.35[.0] + 1.0.43rc01-02 10 10043 10.so.0.43[.0] + 1.2.35rc01-02 13 10235 12.so.0.35[.0] + 1.0.43 10 10043 10.so.0.43[.0] + 1.2.35 13 10235 12.so.0.35[.0] + 1.2.36beta01-05 13 10236 12.so.0.36[.0] + 1.2.36rc01 13 10236 12.so.0.36[.0] + 1.0.44 10 10044 10.so.0.44[.0] + 1.2.36 13 10236 12.so.0.36[.0] + 1.2.37beta01-03 13 10237 12.so.0.37[.0] + 1.2.37rc01 13 10237 12.so.0.37[.0] + 1.2.37 13 10237 12.so.0.37[.0] + 1.0.45 10 10045 12.so.0.45[.0] + 1.0.46 10 10046 10.so.0.46[.0] + 1.2.38beta01 13 10238 12.so.0.38[.0] + 1.2.38rc01-03 13 10238 12.so.0.38[.0] + 1.0.47 10 10047 10.so.0.47[.0] + 1.2.38 13 10238 12.so.0.38[.0] + 1.2.39beta01-05 13 10239 12.so.0.39[.0] + 1.2.39rc01 13 10239 12.so.0.39[.0] + 1.0.48 10 10048 10.so.0.48[.0] + 1.2.39 13 10239 12.so.0.39[.0] + 1.2.40beta01 13 10240 12.so.0.40[.0] + 1.2.40rc01 13 10240 12.so.0.40[.0] + 1.0.49 10 10049 10.so.0.49[.0] + 1.2.40 13 10240 12.so.0.40[.0] + 1.0.50 10 10050 10.so.0.50[.0] + 1.2.41beta01-18 13 10241 12.so.0.41[.0] + 1.0.51rc01 10 10051 10.so.0.51[.0] + 1.2.41rc01-03 13 10241 12.so.0.41[.0] + 1.0.51 10 10051 10.so.0.51[.0] + 1.2.41 13 10241 12.so.0.41[.0] + 1.2.42beta01-02 13 10242 12.so.0.42[.0] + 1.2.42rc01-05 13 10242 12.so.0.42[.0] + 1.0.52 10 10052 10.so.0.52[.0] + 1.2.42 13 10242 12.so.0.42[.0] + 1.2.43beta01-05 13 10243 12.so.0.43[.0] + 1.0.53rc01-02 10 10053 10.so.0.53[.0] + 1.2.43rc01-02 13 10243 12.so.0.43[.0] + 1.0.53 10 10053 10.so.0.53[.0] + 1.2.43 13 10243 12.so.0.43[.0] + 1.2.44beta01-03 13 10244 12.so.0.44[.0] + 1.2.44rc01-03 13 10244 12.so.0.44[.0] + 1.2.44 13 10244 12.so.0.44[.0] + 1.2.45beta01-03 13 10245 12.so.0.45[.0] + 1.0.55rc01 10 10055 10.so.0.55[.0] + 1.2.45rc01 13 10245 12.so.0.45[.0] + 1.0.55 10 10055 10.so.0.55[.0] + 1.2.45 13 10245 12.so.0.45[.0] + 1.2.46rc01-02 13 10246 12.so.0.46[.0] + 1.0.56 10 10056 10.so.0.56[.0] + 1.2.46 13 10246 12.so.0.46[.0] + 1.2.47beta01 13 10247 12.so.0.47[.0] + 1.2.47rc01 13 10247 12.so.0.47[.0] + 1.0.57rc01 10 10057 10.so.0.57[.0] + 1.2.47 13 10247 12.so.0.47[.0] + 1.0.57 10 10057 10.so.0.57[.0] + 1.2.48beta01 13 10248 12.so.0.48[.0] + 1.2.48rc01-02 13 10248 12.so.0.48[.0] + 1.0.58 10 10058 10.so.0.58[.0] + 1.2.48 13 10248 12.so.0.48[.0] + 1.2.49rc01 13 10249 12.so.0.49[.0] + 1.0.59 10 10059 10.so.0.59[.0] + 1.2.49 13 10249 12.so.0.49[.0] + 1.2.50 13 10250 12.so.0.50[.0] + 1.0.60 10 10060 10.so.0.60[.0] + 1.2.51beta01-05 13 10251 12.so.0.51[.0] + 1.2.51rc01-04 13 10251 12.so.0.51[.0] + 1.0.61 10 10061 10.so.0.61[.0] + 1.2.51 13 10251 12.so.0.51[.0] + +Henceforth the source version will match the shared-library minor +and patch numbers; the shared-library major version number will be +used for changes in backward compatibility, as it is intended. The +PNG_PNGLIB_VER macro, which is not used within libpng but is available +for applications, is an unsigned integer of the form xyyzz corresponding +to the source version x.y.z (leading zeros in y and z). Beta versions +were given the previous public release number plus a letter, until +version 1.0.6j; from then on they were given the upcoming public +release number plus "betaNN" or "rcNN". + +.SH "SEE ALSO" +.IR libpngpf(3) ", " png(5) +.LP +.IR libpng : +.IP +http://libpng.sourceforge.net (follow the [DOWNLOAD] link) +http://www.libpng.org/pub/png + +.LP +.IR zlib : +.IP +(generally) at the same location as +.I libpng +or at +.br +ftp://ftp.info-zip.org/pub/infozip/zlib + +.LP +.IR PNG specification: RFC 2083 +.IP +(generally) at the same location as +.I libpng +or at +.br +ftp://ftp.rfc-editor.org:/in-notes/rfc2083.txt +.br +or (as a W3C Recommendation) at +.br +http://www.w3.org/TR/REC-png.html + +.LP +In the case of any inconsistency between the PNG specification +and this library, the specification takes precedence. + +.SH AUTHORS +This man page: Glenn Randers-Pehrson + + +The contributing authors would like to thank all those who helped +with testing, bug fixes, and patience. This wouldn't have been +possible without all of you. + +Thanks to Frank J. T. Wojcik for helping with the documentation. + +Libpng version 1.2.51 - February 6, 2014: +Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc. +Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net). + +Supported by the PNG development group +.br +png-mng-implement at lists.sf.net +(subscription required; visit +png-mng-implement at lists.sourceforge.net (subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe). + +.SH COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +(This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail.) + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.2.6, August 15, 2004, through 1.2.51, February 6, 2014, are +Copyright (c) 2004,2006-2008 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your + enjoyment of the library or against infringement. + There is no warranty that our efforts or the library + will fulfill any of your particular purposes or needs. + This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and + effort is with the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson +Distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and + must not be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from + any source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +February 6, 2014 + +.\" end of man page + diff --git a/main/source/includes/lpng1251/libpngpf.3 b/main/source/includes/lpng1251/libpngpf.3 index 368c3c41..37c5d646 100644 --- a/main/source/includes/lpng1251/libpngpf.3 +++ b/main/source/includes/lpng1251/libpngpf.3 @@ -1,282 +1,282 @@ -.TH LIBPNGPF 3 "February 6, 2014" -.SH NAME -libpng \- Portable Network Graphics (PNG) Reference Library 1.2.51 -(private functions) -.SH SYNOPSIS -\fB#include \fP - -\fBvoid png_64bit_product (long \fP\fIv1\fP\fB, long \fP\fIv2\fP\fB, unsigned long \fP\fI*hi_product\fP\fB, unsigned long \fI*lo_product\fP\fB);\fP - -\fBvoid png_build_gamma_table (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_build_grayscale_palette (int \fP\fIbit_depth\fP\fB, png_colorp \fIpalette\fP\fB);\fP - -\fBvoid png_calculate_crc (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIptr\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBint png_check_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_fixed_point \fP\fIint_white_x\fP\fB, png_fixed_point \fP\fIint_white_y\fP\fB, png_fixed_point \fP\fIint_red_x\fP\fB, png_fixed_point \fP\fIint_red_y\fP\fB, png_fixed_point \fP\fIint_green_x\fP\fB, png_fixed_point \fP\fIint_green_y\fP\fB, png_fixed_point \fP\fIint_blue_x\fP\fB, png_fixed_point \fIint_blue_y\fP\fB);\fP - -\fBvoid png_check_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP - -\fBvoid png_check_chunk_name (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP - -\fBpng_size_t png_check_keyword (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charpp \fInew_key\fP\fB);\fP - -\fBvoid png_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fImask\fP\fB);\fP - -\fBvoid png_correct_palette (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP - -\fBint png_crc_error (png_structp \fIpng_ptr\fP\fB);\fP - -\fBint png_crc_finish (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIskip\fP\fB);\fP - -\fBvoid png_crc_read (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuf\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBpng_voidp png_create_struct (int \fItype\fP\fB);\fP - -\fBpng_voidp png_create_struct_2 (int \fP\fItype\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP - -\fBvoid png_decompress_chunk (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcomp_type\fP\fB, png_charp \fP\fIchunkdata\fP\fB, png_size_t \fP\fIchunklength\fP\fB, png_size_t \fP\fIprefix_length\fP\fB, png_size_t \fI*data_length\fP\fB);\fP - -\fBvoid png_destroy_struct (png_voidp \fIstruct_ptr\fP\fB);\fP - -\fBvoid png_destroy_struct_2 (png_voidp \fP\fIstruct_ptr\fP\fB, png_free_ptr \fP\fIfree_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP - -\fBvoid png_do_background (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fP\fItrans_values\fP\fB, png_color_16p \fP\fIbackground\fP\fB, png_color_16p \fP\fIbackground_1\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_bytep \fP\fIgamma_from_1\fP\fB, png_bytep \fP\fIgamma_to_1\fP\fB, png_uint_16pp \fP\fIgamma_16\fP\fB, png_uint_16pp \fP\fIgamma_16_from_1\fP\fB, png_uint_16pp \fP\fIgamma_16_to_1\fP\fB, int \fIgamma_shift\fP\fB);\fP - -\fBvoid png_do_bgr (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_chop (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_dither (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIpalette_lookup\fP\fB, png_bytep \fIdither_lookup\fP\fB);\fP - -\fBvoid png_do_expand (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fItrans_value\fP\fB);\fP - -\fBvoid png_do_expand_palette (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fInum_trans\fP\fB);\fP - -\fBvoid png_do_gamma (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_uint_16pp \fP\fIgamma_16_table\fP\fB, int \fIgamma_shift\fP\fB);\fP - -\fBvoid png_do_gray_to_rgb (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_invert (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_pack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIbit_depth\fP\fB);\fP - -\fBvoid png_do_packswap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_read_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, png_uint_32 \fIflags\fP\fB);\fP - -\fBvoid png_do_read_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fP\fIpass\fP\fB, png_uint_32 \fItransformations\fP\fB);\fP - -\fBvoid png_do_read_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_read_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP - -\fBint png_do_rgb_to_gray (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_shift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIbit_depth\fP\fB);\fP - -\fBvoid png_do_strip_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIflags\fP\fB);\fP - -\fBvoid png_do_swap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_unpack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_unshift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIsig_bits\fP\fB);\fP - -\fBvoid png_do_write_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fIpass\fP\fB);\fP - -\fBvoid png_do_write_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_write_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_do_write_transformations (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid *png_far_to_near (png_structp png_ptr,png_voidp \fP\fIptr\fP\fB, int \fIcheck\fP\fB);\fP - -\fBvoid png_flush (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_handle_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_IEND (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_iTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_info_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_init_mmx_flags (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_init_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_process_IDAT_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP - -\fBvoid png_process_some_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_check_crc (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_push_crc_finish (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_push_crc_skip (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_push_fill_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBvoid png_push_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_push_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_push_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fBvoid png_push_have_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_have_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_have_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fBvoid png_push_process_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_push_read_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_read_IDAT (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_push_read_sig (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_read_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_read_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_push_restore_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP - -\fBvoid png_push_save_buffer (png_structp \fIpng_ptr\fP\fB);\fP - -\fBpng_uint_32 png_read_chunk_header (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_read_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBvoid png_read_filter_row (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIprev_row\fP\fB, int \fIfilter\fP\fB);\fP - -\fBvoid png_read_finish_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_read_push_finish_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_read_start_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_read_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fBvoid png_reset_crc (png_structp \fIpng_ptr\fP\fB);\fP - -\fBint png_set_text_2 (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP - -\fBvoid png_write_cHRM (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP - -\fBvoid png_write_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP - -\fBvoid png_write_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBvoid png_write_filtered_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIfiltered_row\fP\fB);\fP - -\fBvoid png_write_find_filter (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fIrow_info\fP\fB);\fP - -\fBvoid png_write_finish_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_gAMA (png_structp \fP\fIpng_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP - -\fBvoid png_write_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIint_file_gamma\fP\fB);\fP - -\fBvoid png_write_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_uint_16p \fP\fIhist\fP\fB, int \fInum_hist\fP\fB);\fP - -\fBvoid png_write_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, int \fIproflen\fP\fB);\fP - -\fBvoid png_write_IDAT (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fBvoid png_write_IEND (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fP\fIfilter_type\fP\fB, int \fIinterlace_type\fP\fB);\fP - -\fBvoid png_write_iTXt (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcompression\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fIlang\fP\fB, png_charp \fP\fItranslated_key\fP\fB, png_charp \fItext\fP\fB);\fP - -\fBvoid png_write_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_offset\fP\fB, png_uint_32 \fP\fIy_offset\fP\fB, int \fIunit_type\fP\fB);\fP - -\fBvoid png_write_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP - -\fBvoid png_write_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_pixels_per_unit\fP\fB, png_uint_32 \fP\fIy_pixels_per_unit\fP\fB, int \fIunit_type\fP\fB);\fP - -\fBvoid png_write_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_uint_32 \fInum_pal\fP\fB);\fP - -\fBvoid png_write_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fP\fIsbit\fP\fB, int \fIcolor_type\fP\fB);\fP - -\fBvoid png_write_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP - -\fBvoid png_write_sCAL_s (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, png_charp \fP\fIwidth\fP\fB, png_charp \fIheight\fP\fB);\fP - -\fBvoid png_write_sig (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_sRGB (png_structp \fP\fIpng_ptr\fP\fB, int \fIintent\fP\fB);\fP - -\fBvoid png_write_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_spalette_p \fIpalette\fP\fB);\fP - -\fBvoid png_write_start_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fBvoid png_write_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fItext_len\fP\fB);\fP - -\fBvoid png_write_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP - -\fBvoid png_write_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, png_color_16p \fP\fIvalues\fP\fB, int \fP\fInumber\fP\fB, int \fIcolor_type\fP\fB);\fP - -\fBvoid png_write_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fP\fItext_len\fP\fB, int \fIcompression\fP\fB);\fP - -\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP - -\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP - -\fI\fB - -.SH DESCRIPTION -The functions listed above are used privately by libpng -and are not recommended for use by applications. They are -not "exported" to applications using shared libraries. They -are listed alphabetically here as an aid to libpng maintainers. -See png.h for more information on these functions. - -.SH SEE ALSO -.IR libpng(3) ", " png(5) -.SH AUTHOR -Glenn Randers-Pehrson +.TH LIBPNGPF 3 "February 6, 2014" +.SH NAME +libpng \- Portable Network Graphics (PNG) Reference Library 1.2.51 +(private functions) +.SH SYNOPSIS +\fB#include \fP + +\fBvoid png_64bit_product (long \fP\fIv1\fP\fB, long \fP\fIv2\fP\fB, unsigned long \fP\fI*hi_product\fP\fB, unsigned long \fI*lo_product\fP\fB);\fP + +\fBvoid png_build_gamma_table (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_build_grayscale_palette (int \fP\fIbit_depth\fP\fB, png_colorp \fIpalette\fP\fB);\fP + +\fBvoid png_calculate_crc (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIptr\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBint png_check_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_fixed_point \fP\fIint_white_x\fP\fB, png_fixed_point \fP\fIint_white_y\fP\fB, png_fixed_point \fP\fIint_red_x\fP\fB, png_fixed_point \fP\fIint_red_y\fP\fB, png_fixed_point \fP\fIint_green_x\fP\fB, png_fixed_point \fP\fIint_green_y\fP\fB, png_fixed_point \fP\fIint_blue_x\fP\fB, png_fixed_point \fIint_blue_y\fP\fB);\fP + +\fBvoid png_check_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP + +\fBvoid png_check_chunk_name (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP + +\fBpng_size_t png_check_keyword (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charpp \fInew_key\fP\fB);\fP + +\fBvoid png_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fImask\fP\fB);\fP + +\fBvoid png_correct_palette (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP + +\fBint png_crc_error (png_structp \fIpng_ptr\fP\fB);\fP + +\fBint png_crc_finish (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIskip\fP\fB);\fP + +\fBvoid png_crc_read (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuf\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBpng_voidp png_create_struct (int \fItype\fP\fB);\fP + +\fBpng_voidp png_create_struct_2 (int \fP\fItype\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP + +\fBvoid png_decompress_chunk (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcomp_type\fP\fB, png_charp \fP\fIchunkdata\fP\fB, png_size_t \fP\fIchunklength\fP\fB, png_size_t \fP\fIprefix_length\fP\fB, png_size_t \fI*data_length\fP\fB);\fP + +\fBvoid png_destroy_struct (png_voidp \fIstruct_ptr\fP\fB);\fP + +\fBvoid png_destroy_struct_2 (png_voidp \fP\fIstruct_ptr\fP\fB, png_free_ptr \fP\fIfree_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP + +\fBvoid png_do_background (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fP\fItrans_values\fP\fB, png_color_16p \fP\fIbackground\fP\fB, png_color_16p \fP\fIbackground_1\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_bytep \fP\fIgamma_from_1\fP\fB, png_bytep \fP\fIgamma_to_1\fP\fB, png_uint_16pp \fP\fIgamma_16\fP\fB, png_uint_16pp \fP\fIgamma_16_from_1\fP\fB, png_uint_16pp \fP\fIgamma_16_to_1\fP\fB, int \fIgamma_shift\fP\fB);\fP + +\fBvoid png_do_bgr (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_chop (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_dither (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIpalette_lookup\fP\fB, png_bytep \fIdither_lookup\fP\fB);\fP + +\fBvoid png_do_expand (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fItrans_value\fP\fB);\fP + +\fBvoid png_do_expand_palette (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fInum_trans\fP\fB);\fP + +\fBvoid png_do_gamma (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_uint_16pp \fP\fIgamma_16_table\fP\fB, int \fIgamma_shift\fP\fB);\fP + +\fBvoid png_do_gray_to_rgb (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_invert (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_pack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIbit_depth\fP\fB);\fP + +\fBvoid png_do_packswap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_read_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, png_uint_32 \fIflags\fP\fB);\fP + +\fBvoid png_do_read_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fP\fIpass\fP\fB, png_uint_32 \fItransformations\fP\fB);\fP + +\fBvoid png_do_read_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_read_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP + +\fBint png_do_rgb_to_gray (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_shift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIbit_depth\fP\fB);\fP + +\fBvoid png_do_strip_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIflags\fP\fB);\fP + +\fBvoid png_do_swap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_unpack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_unshift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIsig_bits\fP\fB);\fP + +\fBvoid png_do_write_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fIpass\fP\fB);\fP + +\fBvoid png_do_write_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_write_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_do_write_transformations (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid *png_far_to_near (png_structp png_ptr,png_voidp \fP\fIptr\fP\fB, int \fIcheck\fP\fB);\fP + +\fBvoid png_flush (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_handle_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_IEND (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_iTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_info_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_init_mmx_flags (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_init_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_process_IDAT_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP + +\fBvoid png_process_some_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_check_crc (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_push_crc_finish (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_push_crc_skip (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_push_fill_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_push_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_push_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_push_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_push_have_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_have_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_have_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_push_process_row (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_push_read_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_read_IDAT (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_push_read_sig (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_read_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_read_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_push_restore_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP + +\fBvoid png_push_save_buffer (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_read_chunk_header (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_read_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_read_filter_row (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIprev_row\fP\fB, int \fIfilter\fP\fB);\fP + +\fBvoid png_read_finish_row (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_read_push_finish_row (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_read_start_row (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_read_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_reset_crc (png_structp \fIpng_ptr\fP\fB);\fP + +\fBint png_set_text_2 (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP + +\fBvoid png_write_cHRM (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP + +\fBvoid png_write_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP + +\fBvoid png_write_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_write_filtered_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIfiltered_row\fP\fB);\fP + +\fBvoid png_write_find_filter (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fIrow_info\fP\fB);\fP + +\fBvoid png_write_finish_row (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_gAMA (png_structp \fP\fIpng_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP + +\fBvoid png_write_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIint_file_gamma\fP\fB);\fP + +\fBvoid png_write_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_uint_16p \fP\fIhist\fP\fB, int \fInum_hist\fP\fB);\fP + +\fBvoid png_write_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, int \fIproflen\fP\fB);\fP + +\fBvoid png_write_IDAT (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_write_IEND (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fP\fIfilter_type\fP\fB, int \fIinterlace_type\fP\fB);\fP + +\fBvoid png_write_iTXt (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcompression\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fIlang\fP\fB, png_charp \fP\fItranslated_key\fP\fB, png_charp \fItext\fP\fB);\fP + +\fBvoid png_write_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_offset\fP\fB, png_uint_32 \fP\fIy_offset\fP\fB, int \fIunit_type\fP\fB);\fP + +\fBvoid png_write_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP + +\fBvoid png_write_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_pixels_per_unit\fP\fB, png_uint_32 \fP\fIy_pixels_per_unit\fP\fB, int \fIunit_type\fP\fB);\fP + +\fBvoid png_write_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_uint_32 \fInum_pal\fP\fB);\fP + +\fBvoid png_write_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fP\fIsbit\fP\fB, int \fIcolor_type\fP\fB);\fP + +\fBvoid png_write_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP + +\fBvoid png_write_sCAL_s (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, png_charp \fP\fIwidth\fP\fB, png_charp \fIheight\fP\fB);\fP + +\fBvoid png_write_sig (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_sRGB (png_structp \fP\fIpng_ptr\fP\fB, int \fIintent\fP\fB);\fP + +\fBvoid png_write_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_spalette_p \fIpalette\fP\fB);\fP + +\fBvoid png_write_start_row (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fItext_len\fP\fB);\fP + +\fBvoid png_write_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP + +\fBvoid png_write_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, png_color_16p \fP\fIvalues\fP\fB, int \fP\fInumber\fP\fB, int \fIcolor_type\fP\fB);\fP + +\fBvoid png_write_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fP\fItext_len\fP\fB, int \fIcompression\fP\fB);\fP + +\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP + +\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP + +\fI\fB + +.SH DESCRIPTION +The functions listed above are used privately by libpng +and are not recommended for use by applications. They are +not "exported" to applications using shared libraries. They +are listed alphabetically here as an aid to libpng maintainers. +See png.h for more information on these functions. + +.SH SEE ALSO +.IR libpng(3) ", " png(5) +.SH AUTHOR +Glenn Randers-Pehrson diff --git a/main/source/includes/lpng1251/png.5 b/main/source/includes/lpng1251/png.5 index 69d3bccb..d61b17ed 100644 --- a/main/source/includes/lpng1251/png.5 +++ b/main/source/includes/lpng1251/png.5 @@ -1,74 +1,74 @@ -.TH PNG 5 "February 6, 2014" -.SH NAME -png \- Portable Network Graphics (PNG) format -.SH DESCRIPTION -PNG (Portable Network Graphics) is an extensible file format for the -lossless, portable, well-compressed storage of raster images. PNG provides -a patent-free replacement for GIF and can also replace many -common uses of TIFF. Indexed-color, grayscale, and truecolor images are -supported, plus an optional alpha channel. Sample depths range from -1 to 16 bits. -.br - -PNG is designed to work well in online viewing applications, such as the -World Wide Web, so it is fully streamable with a progressive display -option. PNG is robust, providing both full file integrity checking and -fast, simple detection of common transmission errors. Also, PNG can store -gamma and chromaticity data for improved color matching on heterogeneous -platforms. - -.SH "SEE ALSO" -.IR libpng(3) ", " zlib(3) ", " deflate(5) ", and " zlib(5) -.LP -PNG specification (second edition), November 2003: -.IP -.br - 8) - png_error(png_ptr, "Too many bytes for PNG signature."); - - png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); -} - -/* Checks whether the supplied bytes match the PNG signature. We allow - * checking less than the full 8-byte signature so that those apps that - * already read the first few bytes of a file to determine the file type - * can simply check the remaining bytes for extra assurance. Returns - * an integer less than, equal to, or greater than zero if sig is found, - * respectively, to be less than, to match, or be greater than the correct - * PNG signature (this is the same behaviour as strcmp, memcmp, etc). - */ -int PNGAPI -png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) -{ - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - if (num_to_check > 8) - num_to_check = 8; - else if (num_to_check < 1) - return (-1); - - if (start > 7) - return (-1); - - if (start + num_to_check > 8) - num_to_check = 8 - start; - - return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); -} - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* (Obsolete) function to check signature bytes. It does not allow one - * to check a partial signature. This function might be removed in the - * future - use png_sig_cmp(). Returns true (nonzero) if the file is PNG. - */ -int PNGAPI -png_check_sig(png_bytep sig, int num) -{ - return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num)); -} -#endif -#endif /* PNG_READ_SUPPORTED */ - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -/* Function to allocate memory for zlib and clear it to 0. */ -#ifdef PNG_1_0_X -voidpf PNGAPI -#else -voidpf /* PRIVATE */ -#endif -png_zalloc(voidpf png_ptr, uInt items, uInt size) -{ - png_voidp ptr; - png_structp p=(png_structp)png_ptr; - png_uint_32 save_flags=p->flags; - png_uint_32 num_bytes; - - if (png_ptr == NULL) - return (NULL); - if (items > PNG_UINT_32_MAX/size) - { - png_warning (p, "Potential overflow in png_zalloc()"); - return (NULL); - } - num_bytes = (png_uint_32)items * size; - - p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); - p->flags=save_flags; - -#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO) - if (ptr == NULL) - return ((voidpf)ptr); - - if (num_bytes > (png_uint_32)0x8000L) - { - png_memset(ptr, 0, (png_size_t)0x8000L); - png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0, - (png_size_t)(num_bytes - (png_uint_32)0x8000L)); - } - else - { - png_memset(ptr, 0, (png_size_t)num_bytes); - } -#endif - return ((voidpf)ptr); -} - -/* Function to free memory for zlib */ -#ifdef PNG_1_0_X -void PNGAPI -#else -void /* PRIVATE */ -#endif -png_zfree(voidpf png_ptr, voidpf ptr) -{ - png_free((png_structp)png_ptr, (png_voidp)ptr); -} - -/* Reset the CRC variable to 32 bits of 1's. Care must be taken - * in case CRC is > 32 bits to leave the top bits 0. - */ -void /* PRIVATE */ -png_reset_crc(png_structp png_ptr) -{ - png_ptr->crc = crc32(0, Z_NULL, 0); -} - -/* Calculate the CRC over a section of data. We can only pass as - * much data to this routine as the largest single buffer size. We - * also check that this data will actually be used before going to the - * trouble of calculating it. - */ -void /* PRIVATE */ -png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) -{ - int need_crc = 1; - - if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - - if (need_crc) - png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); -} - -/* Allocate the memory for an info_struct for the application. We don't - * really need the png_ptr, but it could potentially be useful in the - * future. This should be used in favour of malloc(png_sizeof(png_info)) - * and png_info_init() so that applications that want to use a shared - * libpng don't have to be recompiled if png_info changes size. - */ -png_infop PNGAPI -png_create_info_struct(png_structp png_ptr) -{ - png_infop info_ptr; - - png_debug(1, "in png_create_info_struct"); - - if (png_ptr == NULL) - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, - png_ptr->malloc_fn, png_ptr->mem_ptr); -#else - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); -#endif - if (info_ptr != NULL) - png_info_init_3(&info_ptr, png_sizeof(png_info)); - - return (info_ptr); -} - -/* This function frees the memory associated with a single info struct. - * Normally, one would use either png_destroy_read_struct() or - * png_destroy_write_struct() to free an info struct, but this may be - * useful for some applications. - */ -void PNGAPI -png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) -{ - png_infop info_ptr = NULL; - - png_debug(1, "in png_destroy_info_struct"); - - if (png_ptr == NULL) - return; - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - png_info_destroy(png_ptr, info_ptr); - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, - png_ptr->mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } -} - -/* Initialize the info structure. This is now an internal function (0.89) - * and applications using it are urged to use png_create_info_struct() - * instead. - */ -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -#undef png_info_init -void PNGAPI -png_info_init(png_infop info_ptr) -{ - /* We only come here via pre-1.0.12-compiled applications */ - png_info_init_3(&info_ptr, 0); -} -#endif - -void PNGAPI -png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) -{ - png_infop info_ptr = *ptr_ptr; - - png_debug(1, "in png_info_init_3"); - - if (info_ptr == NULL) - return; - - if (png_sizeof(png_info) > png_info_struct_size) - { - png_destroy_struct(info_ptr); - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); - *ptr_ptr = info_ptr; - } - - /* Set everything to 0 */ - png_memset(info_ptr, 0, png_sizeof(png_info)); -} - -#ifdef PNG_FREE_ME_SUPPORTED -void PNGAPI -png_data_freer(png_structp png_ptr, png_infop info_ptr, - int freer, png_uint_32 mask) -{ - png_debug(1, "in png_data_freer"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (freer == PNG_DESTROY_WILL_FREE_DATA) - info_ptr->free_me |= mask; - else if (freer == PNG_USER_WILL_FREE_DATA) - info_ptr->free_me &= ~mask; - else - png_warning(png_ptr, - "Unknown freer parameter in png_data_freer."); -} -#endif - -void PNGAPI -png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, - int num) -{ - png_debug(1, "in png_free_data"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - -#ifdef PNG_TEXT_SUPPORTED - /* Free text item num or (if num == -1) all text items */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) -#else - if (mask & PNG_FREE_TEXT) -#endif - { - if (num != -1) - { - if (info_ptr->text && info_ptr->text[num].key) - { - png_free(png_ptr, info_ptr->text[num].key); - info_ptr->text[num].key = NULL; - } - } - else - { - int i; - for (i = 0; i < info_ptr->num_text; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); - png_free(png_ptr, info_ptr->text); - info_ptr->text = NULL; - info_ptr->num_text=0; - } - } -#endif - -#ifdef PNG_tRNS_SUPPORTED - /* Free any tRNS entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) -#else - if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS)) -#endif - { - png_free(png_ptr, info_ptr->trans); - info_ptr->trans = NULL; - info_ptr->valid &= ~PNG_INFO_tRNS; -#ifndef PNG_FREE_ME_SUPPORTED - png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; -#endif - } -#endif - -#ifdef PNG_sCAL_SUPPORTED - /* Free any sCAL entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) -#else - if (mask & PNG_FREE_SCAL) -#endif - { -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, info_ptr->scal_s_width); - png_free(png_ptr, info_ptr->scal_s_height); - info_ptr->scal_s_width = NULL; - info_ptr->scal_s_height = NULL; -#endif - info_ptr->valid &= ~PNG_INFO_sCAL; - } -#endif - -#ifdef PNG_pCAL_SUPPORTED - /* Free any pCAL entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) -#else - if (mask & PNG_FREE_PCAL) -#endif - { - png_free(png_ptr, info_ptr->pcal_purpose); - png_free(png_ptr, info_ptr->pcal_units); - info_ptr->pcal_purpose = NULL; - info_ptr->pcal_units = NULL; - if (info_ptr->pcal_params != NULL) - { - int i; - for (i = 0; i < (int)info_ptr->pcal_nparams; i++) - { - png_free(png_ptr, info_ptr->pcal_params[i]); - info_ptr->pcal_params[i] = NULL; - } - png_free(png_ptr, info_ptr->pcal_params); - info_ptr->pcal_params = NULL; - } - info_ptr->valid &= ~PNG_INFO_pCAL; - } -#endif - -#ifdef PNG_iCCP_SUPPORTED - /* Free any iCCP entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) -#else - if (mask & PNG_FREE_ICCP) -#endif - { - png_free(png_ptr, info_ptr->iccp_name); - png_free(png_ptr, info_ptr->iccp_profile); - info_ptr->iccp_name = NULL; - info_ptr->iccp_profile = NULL; - info_ptr->valid &= ~PNG_INFO_iCCP; - } -#endif - -#ifdef PNG_sPLT_SUPPORTED - /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) -#else - if (mask & PNG_FREE_SPLT) -#endif - { - if (num != -1) - { - if (info_ptr->splt_palettes) - { - png_free(png_ptr, info_ptr->splt_palettes[num].name); - png_free(png_ptr, info_ptr->splt_palettes[num].entries); - info_ptr->splt_palettes[num].name = NULL; - info_ptr->splt_palettes[num].entries = NULL; - } - } - else - { - if (info_ptr->splt_palettes_num) - { - int i; - for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); - - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; - } - info_ptr->valid &= ~PNG_INFO_sPLT; - } - } -#endif - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - if (png_ptr->unknown_chunk.data) - { - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) -#else - if (mask & PNG_FREE_UNKN) -#endif - { - if (num != -1) - { - if (info_ptr->unknown_chunks) - { - png_free(png_ptr, info_ptr->unknown_chunks[num].data); - info_ptr->unknown_chunks[num].data = NULL; - } - } - else - { - int i; - - if (info_ptr->unknown_chunks_num) - { - for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); - - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; - } - } - } -#endif - -#ifdef PNG_hIST_SUPPORTED - /* Free any hIST entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_HIST) & info_ptr->free_me) -#else - if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST)) -#endif - { - png_free(png_ptr, info_ptr->hist); - info_ptr->hist = NULL; - info_ptr->valid &= ~PNG_INFO_hIST; -#ifndef PNG_FREE_ME_SUPPORTED - png_ptr->flags &= ~PNG_FLAG_FREE_HIST; -#endif - } -#endif - - /* Free any PLTE entry that was internally allocated */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) -#else - if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE)) -#endif - { - png_zfree(png_ptr, info_ptr->palette); - info_ptr->palette = NULL; - info_ptr->valid &= ~PNG_INFO_PLTE; -#ifndef PNG_FREE_ME_SUPPORTED - png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; -#endif - info_ptr->num_palette = 0; - } - -#ifdef PNG_INFO_IMAGE_SUPPORTED - /* Free any image bits attached to the info structure */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) -#else - if (mask & PNG_FREE_ROWS) -#endif - { - if (info_ptr->row_pointers) - { - int row; - for (row = 0; row < (int)info_ptr->height; row++) - { - png_free(png_ptr, info_ptr->row_pointers[row]); - info_ptr->row_pointers[row] = NULL; - } - png_free(png_ptr, info_ptr->row_pointers); - info_ptr->row_pointers = NULL; - } - info_ptr->valid &= ~PNG_INFO_IDAT; - } -#endif - -#ifdef PNG_FREE_ME_SUPPORTED - if (num == -1) - info_ptr->free_me &= ~mask; - else - info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); -#endif -} - -/* This is an internal routine to free any memory that the info struct is - * pointing to before re-using it or freeing the struct itself. Recall - * that png_free() checks for NULL pointers for us. - */ -void /* PRIVATE */ -png_info_destroy(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_info_destroy"); - - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list = NULL; - png_ptr->num_chunk_list = 0; - } -#endif - - png_info_init_3(&info_ptr, png_sizeof(png_info)); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -/* This function returns a pointer to the io_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy() or png_read_destroy() are called. - */ -png_voidp PNGAPI -png_get_io_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - return (png_ptr->io_ptr); -} - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_STDIO_SUPPORTED -/* Initialize the default input/output functions for the PNG file. If you - * use your own read or write routines, you can call either png_set_read_fn() - * or png_set_write_fn() instead of png_init_io(). If you have defined - * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't - * necessarily available. - */ -void PNGAPI -png_init_io(png_structp png_ptr, png_FILE_p fp) -{ - png_debug(1, "in png_init_io"); - - if (png_ptr == NULL) - return; - - png_ptr->io_ptr = (png_voidp)fp; -} -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED -/* Convert the supplied time into an RFC 1123 string suitable for use in - * a "Creation Time" or other text-based time string. - */ -png_charp PNGAPI -png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) -{ - static PNG_CONST char short_months[12][4] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - - if (png_ptr == NULL) - return (NULL); - if (png_ptr->time_buffer == NULL) - { - png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* - png_sizeof(char))); - } - -#ifdef _WIN32_WCE - { - wchar_t time_buf[29]; - wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"), - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); - WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, - 29, NULL, NULL); - } -#else -#ifdef USE_FAR_KEYWORD - { - char near_time_buf[29]; - png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000", - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); - png_memcpy(png_ptr->time_buffer, near_time_buf, - 29*png_sizeof(char)); - } -#else - png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000", - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); -#endif -#endif /* _WIN32_WCE */ - return ((png_charp)png_ptr->time_buffer); -} -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -png_charp PNGAPI -png_get_copyright(png_structp png_ptr) -{ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ -#ifdef PNG_STRING_COPYRIGHT - return PNG_STRING_COPYRIGHT -#else -#ifdef __STDC__ - return ((png_charp) PNG_STRING_NEWLINE \ - "libpng version 1.2.51 - February 6, 2014" PNG_STRING_NEWLINE \ - "Copyright (c) 1998-2014 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ - "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ - "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ - PNG_STRING_NEWLINE); -#else - return ((png_charp) "libpng version 1.2.51 - February 6, 2014\ - Copyright (c) 1998-2014 Glenn Randers-Pehrson\ - Copyright (c) 1996-1997 Andreas Dilger\ - Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."); -#endif -#endif -} - -/* The following return the library version as a short string in the - * format 1.0.0 through 99.99.99zz. To get the version of *.h files - * used with your application, print out PNG_LIBPNG_VER_STRING, which - * is defined in png.h. - * Note: now there is no difference between png_get_libpng_ver() and - * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, - * it is guaranteed that png.c uses the correct version of png.h. - */ -png_charp PNGAPI -png_get_libpng_ver(png_structp png_ptr) -{ - /* Version of *.c files used when building libpng */ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_LIBPNG_VER_STRING); -} - -png_charp PNGAPI -png_get_header_ver(png_structp png_ptr) -{ - /* Version of *.h files used when building libpng */ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_LIBPNG_VER_STRING); -} - -png_charp PNGAPI -png_get_header_version(png_structp png_ptr) -{ - /* Returns longer string containing both version and date */ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ -#ifdef __STDC__ - return ((png_charp) PNG_HEADER_VERSION_STRING -#ifndef PNG_READ_SUPPORTED - " (NO READ SUPPORT)" -#endif - PNG_STRING_NEWLINE); -#else - return ((png_charp) PNG_HEADER_VERSION_STRING); -#endif -} - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -int PNGAPI -png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) -{ - /* Check chunk_name and return "keep" value if it's on the list, else 0 */ - int i; - png_bytep p; - if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0) - return 0; - p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5; - for (i = png_ptr->num_chunk_list; i; i--, p -= 5) - if (!png_memcmp(chunk_name, p, 4)) - return ((int)*(p + 4)); - return 0; -} -#endif - -/* This function, added to libpng-1.0.6g, is untested. */ -int PNGAPI -png_reset_zstream(png_structp png_ptr) -{ - if (png_ptr == NULL) - return Z_STREAM_ERROR; - return (inflateReset(&png_ptr->zstream)); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -/* This function was added to libpng-1.0.7 */ -png_uint_32 PNGAPI -png_access_version_number(void) -{ - /* Version of *.c files used when building libpng */ - return((png_uint_32) PNG_LIBPNG_VER); -} - - -#if defined(PNG_READ_SUPPORTED) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) -#ifndef PNG_1_0_X -/* This function was added to libpng 1.2.0 */ -int PNGAPI -png_mmx_support(void) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return -1; -} -#endif /* PNG_1_0_X */ -#endif /* PNG_READ_SUPPORTED && PNG_ASSEMBLER_CODE_SUPPORTED */ - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_SIZE_T -/* Added at libpng version 1.2.6 */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); -png_size_t PNGAPI -png_convert_size(size_t size) -{ - if (size > (png_size_t)-1) - PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ - return ((png_size_t)size); -} -#endif /* PNG_SIZE_T */ - -/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_CHECK_cHRM_SUPPORTED - -/* - * Multiply two 32-bit numbers, V1 and V2, using 32-bit - * arithmetic, to produce a 64 bit result in the HI/LO words. - * - * A B - * x C D - * ------ - * AD || BD - * AC || CB || 0 - * - * where A and B are the high and low 16-bit words of V1, - * C and D are the 16-bit words of V2, AD is the product of - * A and D, and X || Y is (X << 16) + Y. -*/ - -void /* PRIVATE */ -png_64bit_product (long v1, long v2, unsigned long *hi_product, - unsigned long *lo_product) -{ - int a, b, c, d; - long lo, hi, x, y; - - a = (v1 >> 16) & 0xffff; - b = v1 & 0xffff; - c = (v2 >> 16) & 0xffff; - d = v2 & 0xffff; - - lo = b * d; /* BD */ - x = a * d + c * b; /* AD + CB */ - y = ((lo >> 16) & 0xffff) + x; - - lo = (lo & 0xffff) | ((y & 0xffff) << 16); - hi = (y >> 16) & 0xffff; - - hi += a * c; /* AC */ - - *hi_product = (unsigned long)hi; - *lo_product = (unsigned long)lo; -} - -int /* PRIVATE */ -png_check_cHRM_fixed(png_structp png_ptr, - png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, - png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, - png_fixed_point blue_x, png_fixed_point blue_y) -{ - int ret = 1; - unsigned long xy_hi,xy_lo,yx_hi,yx_lo; - - png_debug(1, "in function png_check_cHRM_fixed"); - - if (png_ptr == NULL) - return 0; - - if (white_x < 0 || white_y <= 0 || - red_x < 0 || red_y < 0 || - green_x < 0 || green_y < 0 || - blue_x < 0 || blue_y < 0) - { - png_warning(png_ptr, - "Ignoring attempt to set negative chromaticity value"); - ret = 0; - } - if (white_x > (png_fixed_point) PNG_UINT_31_MAX || - white_y > (png_fixed_point) PNG_UINT_31_MAX || - red_x > (png_fixed_point) PNG_UINT_31_MAX || - red_y > (png_fixed_point) PNG_UINT_31_MAX || - green_x > (png_fixed_point) PNG_UINT_31_MAX || - green_y > (png_fixed_point) PNG_UINT_31_MAX || - blue_x > (png_fixed_point) PNG_UINT_31_MAX || - blue_y > (png_fixed_point) PNG_UINT_31_MAX ) - { - png_warning(png_ptr, - "Ignoring attempt to set chromaticity value exceeding 21474.83"); - ret = 0; - } - if (white_x > 100000L - white_y) - { - png_warning(png_ptr, "Invalid cHRM white point"); - ret = 0; - } - if (red_x > 100000L - red_y) - { - png_warning(png_ptr, "Invalid cHRM red point"); - ret = 0; - } - if (green_x > 100000L - green_y) - { - png_warning(png_ptr, "Invalid cHRM green point"); - ret = 0; - } - if (blue_x > 100000L - blue_y) - { - png_warning(png_ptr, "Invalid cHRM blue point"); - ret = 0; - } - - png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo); - png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo); - - if (xy_hi == yx_hi && xy_lo == yx_lo) - { - png_warning(png_ptr, - "Ignoring attempt to set cHRM RGB triangle with zero area"); - ret = 0; - } - - return ret; -} -#endif /* PNG_CHECK_cHRM_SUPPORTED */ -#endif /* PNG_cHRM_SUPPORTED */ - -void /* PRIVATE */ -png_check_IHDR(png_structp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type) -{ - int error = 0; - - /* Check for width and height valid values */ - if (width == 0) - { - png_warning(png_ptr, "Image width is zero in IHDR"); - error = 1; - } - - if (height == 0) - { - png_warning(png_ptr, "Image height is zero in IHDR"); - error = 1; - } - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX) -#else - if (width > PNG_USER_WIDTH_MAX) -#endif - { - png_warning(png_ptr, "Image width exceeds user limit in IHDR"); - error = 1; - } - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX) -#else - if (height > PNG_USER_HEIGHT_MAX) -#endif - { - png_warning(png_ptr, "Image height exceeds user limit in IHDR"); - error = 1; - } - - if (width > PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Invalid image width in IHDR"); - error = 1; - } - - if ( height > PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Invalid image height in IHDR"); - error = 1; - } - - /* Check other values */ - if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && - bit_depth != 8 && bit_depth != 16) - { - png_warning(png_ptr, "Invalid bit depth in IHDR"); - error = 1; - } - - if (color_type < 0 || color_type == 1 || - color_type == 5 || color_type > 6) - { - png_warning(png_ptr, "Invalid color type in IHDR"); - error = 1; - } - - if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || - ((color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) - { - png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); - error = 1; - } - - if (interlace_type >= PNG_INTERLACE_LAST) - { - png_warning(png_ptr, "Unknown interlace method in IHDR"); - error = 1; - } - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - { - png_warning(png_ptr, "Unknown compression method in IHDR"); - error = 1; - } - -#ifdef PNG_MNG_FEATURES_SUPPORTED - /* Accept filter_method 64 (intrapixel differencing) only if - * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and - * 2. Libpng did not read a PNG signature (this filter_method is only - * used in PNG datastreams that are embedded in MNG datastreams) and - * 3. The application called png_permit_mng_features with a mask that - * included PNG_FLAG_MNG_FILTER_64 and - * 4. The filter_method is 64 and - * 5. The color_type is RGB or RGBA - */ - if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && - png_ptr->mng_features_permitted) - png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); - - if (filter_type != PNG_FILTER_TYPE_BASE) - { - if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && - ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && - (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA))) - { - png_warning(png_ptr, "Unknown filter method in IHDR"); - error = 1; - } - - if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) - { - png_warning(png_ptr, "Invalid filter method in IHDR"); - error = 1; - } - } - -#else - if (filter_type != PNG_FILTER_TYPE_BASE) - { - png_warning(png_ptr, "Unknown filter method in IHDR"); - error = 1; - } -#endif - - if (error == 1) - png_error(png_ptr, "Invalid IHDR data"); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +/* png.c - location for general purpose libpng functions + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_INTERNAL +#define PNG_NO_EXTERN +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_2_51 Your_png_h_is_not_version_1_2_51; + +/* Version information for C files. This had better match the version + * string defined in png.h. + */ + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* png_libpng_ver was changed to a function in version 1.0.5c */ +PNG_CONST char png_libpng_ver[18] = PNG_LIBPNG_VER_STRING; + +#ifdef PNG_READ_SUPPORTED + +/* png_sig was changed to a function in version 1.0.5c */ +/* Place to hold the signature string for a PNG file. */ +PNG_CONST png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; +#endif /* PNG_READ_SUPPORTED */ + +/* Invoke global declarations for constant strings for known chunk types */ +PNG_IHDR; +PNG_IDAT; +PNG_IEND; +PNG_PLTE; +PNG_bKGD; +PNG_cHRM; +PNG_gAMA; +PNG_hIST; +PNG_iCCP; +PNG_iTXt; +PNG_oFFs; +PNG_pCAL; +PNG_sCAL; +PNG_pHYs; +PNG_sBIT; +PNG_sPLT; +PNG_sRGB; +PNG_tEXt; +PNG_tIME; +PNG_tRNS; +PNG_zTXt; + +#ifdef PNG_READ_SUPPORTED +/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + +/* Start of interlace block */ +PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + +/* Offset to next interlace block */ +PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + +/* Start of interlace block in the y direction */ +PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + +/* Offset to next interlace block in the y direction */ +PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + +/* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h +PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; +*/ + +/* Mask to determine which pixels are valid in a pass */ +PNG_CONST int FARDATA png_pass_mask[] = + {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; + +/* Mask to determine which pixels to overwrite while displaying */ +PNG_CONST int FARDATA png_pass_dsp_mask[] + = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; + +#endif /* PNG_READ_SUPPORTED */ +#endif /* PNG_USE_GLOBAL_ARRAYS */ + +/* Tells libpng that we have already handled the first "num_bytes" bytes + * of the PNG file signature. If the PNG data is embedded into another + * stream we can set num_bytes = 8 so that libpng will not attempt to read + * or write any of the magic bytes before it starts on the IHDR. + */ + +#ifdef PNG_READ_SUPPORTED +void PNGAPI +png_set_sig_bytes(png_structp png_ptr, int num_bytes) +{ + png_debug(1, "in png_set_sig_bytes"); + + if (png_ptr == NULL) + return; + + if (num_bytes > 8) + png_error(png_ptr, "Too many bytes for PNG signature."); + + png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behaviour as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + if (num_to_check > 8) + num_to_check = 8; + else if (num_to_check < 1) + return (-1); + + if (start > 7) + return (-1); + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); +} + +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* (Obsolete) function to check signature bytes. It does not allow one + * to check a partial signature. This function might be removed in the + * future - use png_sig_cmp(). Returns true (nonzero) if the file is PNG. + */ +int PNGAPI +png_check_sig(png_bytep sig, int num) +{ + return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num)); +} +#endif +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Function to allocate memory for zlib and clear it to 0. */ +#ifdef PNG_1_0_X +voidpf PNGAPI +#else +voidpf /* PRIVATE */ +#endif +png_zalloc(voidpf png_ptr, uInt items, uInt size) +{ + png_voidp ptr; + png_structp p=(png_structp)png_ptr; + png_uint_32 save_flags=p->flags; + png_uint_32 num_bytes; + + if (png_ptr == NULL) + return (NULL); + if (items > PNG_UINT_32_MAX/size) + { + png_warning (p, "Potential overflow in png_zalloc()"); + return (NULL); + } + num_bytes = (png_uint_32)items * size; + + p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; + ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); + p->flags=save_flags; + +#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO) + if (ptr == NULL) + return ((voidpf)ptr); + + if (num_bytes > (png_uint_32)0x8000L) + { + png_memset(ptr, 0, (png_size_t)0x8000L); + png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0, + (png_size_t)(num_bytes - (png_uint_32)0x8000L)); + } + else + { + png_memset(ptr, 0, (png_size_t)num_bytes); + } +#endif + return ((voidpf)ptr); +} + +/* Function to free memory for zlib */ +#ifdef PNG_1_0_X +void PNGAPI +#else +void /* PRIVATE */ +#endif +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free((png_structp)png_ptr, (png_voidp)ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structp png_ptr) +{ + png_ptr->crc = crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + if (need_crc) + png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); +} + +/* Allocate the memory for an info_struct for the application. We don't + * really need the png_ptr, but it could potentially be useful in the + * future. This should be used in favour of malloc(png_sizeof(png_info)) + * and png_info_init() so that applications that want to use a shared + * libpng don't have to be recompiled if png_info changes size. + */ +png_infop PNGAPI +png_create_info_struct(png_structp png_ptr) +{ + png_infop info_ptr; + + png_debug(1, "in png_create_info_struct"); + + if (png_ptr == NULL) + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, + png_ptr->malloc_fn, png_ptr->mem_ptr); +#else + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); +#endif + if (info_ptr != NULL) + png_info_init_3(&info_ptr, png_sizeof(png_info)); + + return (info_ptr); +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. + */ +void PNGAPI +png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) +{ + png_infop info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct"); + + if (png_ptr == NULL) + return; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + png_info_destroy(png_ptr, info_ptr); + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, + png_ptr->mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. + */ +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +#undef png_info_init +void PNGAPI +png_info_init(png_infop info_ptr) +{ + /* We only come here via pre-1.0.12-compiled applications */ + png_info_init_3(&info_ptr, 0); +} +#endif + +void PNGAPI +png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) +{ + png_infop info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3"); + + if (info_ptr == NULL) + return; + + if (png_sizeof(png_info) > png_info_struct_size) + { + png_destroy_struct(info_ptr); + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); + *ptr_ptr = info_ptr; + } + + /* Set everything to 0 */ + png_memset(info_ptr, 0, png_sizeof(png_info)); +} + +#ifdef PNG_FREE_ME_SUPPORTED +void PNGAPI +png_data_freer(png_structp png_ptr, png_infop info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + else if (freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + else + png_warning(png_ptr, + "Unknown freer parameter in png_data_freer."); +} +#endif + +void PNGAPI +png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_TEXT_SUPPORTED + /* Free text item num or (if num == -1) all text items */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) +#else + if (mask & PNG_FREE_TEXT) +#endif + { + if (num != -1) + { + if (info_ptr->text && info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + } + else + { + int i; + for (i = 0; i < info_ptr->num_text; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text=0; + } + } +#endif + +#ifdef PNG_tRNS_SUPPORTED + /* Free any tRNS entry */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) +#else + if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS)) +#endif + { + png_free(png_ptr, info_ptr->trans); + info_ptr->trans = NULL; + info_ptr->valid &= ~PNG_INFO_tRNS; +#ifndef PNG_FREE_ME_SUPPORTED + png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; +#endif + } +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* Free any sCAL entry */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) +#else + if (mask & PNG_FREE_SCAL) +#endif + { +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; +#endif + info_ptr->valid &= ~PNG_INFO_sCAL; + } +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* Free any pCAL entry */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) +#else + if (mask & PNG_FREE_PCAL) +#endif + { + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + if (info_ptr->pcal_params != NULL) + { + int i; + for (i = 0; i < (int)info_ptr->pcal_nparams; i++) + { + png_free(png_ptr, info_ptr->pcal_params[i]); + info_ptr->pcal_params[i] = NULL; + } + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; + } +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* Free any iCCP entry */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) +#else + if (mask & PNG_FREE_ICCP) +#endif + { + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; + } +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) +#else + if (mask & PNG_FREE_SPLT) +#endif + { + if (num != -1) + { + if (info_ptr->splt_palettes) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + } + else + { + if (info_ptr->splt_palettes_num) + { + int i; + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + } + info_ptr->valid &= ~PNG_INFO_sPLT; + } + } +#endif + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_chunk.data) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) +#else + if (mask & PNG_FREE_UNKN) +#endif + { + if (num != -1) + { + if (info_ptr->unknown_chunks) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + } + else + { + int i; + + if (info_ptr->unknown_chunks_num) + { + for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } + } +#endif + +#ifdef PNG_hIST_SUPPORTED + /* Free any hIST entry */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_HIST) & info_ptr->free_me) +#else + if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST)) +#endif + { + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; +#ifndef PNG_FREE_ME_SUPPORTED + png_ptr->flags &= ~PNG_FLAG_FREE_HIST; +#endif + } +#endif + + /* Free any PLTE entry that was internally allocated */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) +#else + if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE)) +#endif + { + png_zfree(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; +#ifndef PNG_FREE_ME_SUPPORTED + png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; +#endif + info_ptr->num_palette = 0; + } + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Free any image bits attached to the info structure */ +#ifdef PNG_FREE_ME_SUPPORTED + if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) +#else + if (mask & PNG_FREE_ROWS) +#endif + { + if (info_ptr->row_pointers) + { + int row; + for (row = 0; row < (int)info_ptr->height; row++) + { + png_free(png_ptr, info_ptr->row_pointers[row]); + info_ptr->row_pointers[row] = NULL; + } + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers = NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; + } +#endif + +#ifdef PNG_FREE_ME_SUPPORTED + if (num == -1) + info_ptr->free_me &= ~mask; + else + info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); +#endif +} + +/* This is an internal routine to free any memory that the info struct is + * pointing to before re-using it or freeing the struct itself. Recall + * that png_free() checks for NULL pointers for us. + */ +void /* PRIVATE */ +png_info_destroy(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_info_destroy"); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; + png_ptr->num_chunk_list = 0; + } +#endif + + png_info_init_3(&info_ptr, png_sizeof(png_info)); +} +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + return (png_ptr->io_ptr); +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't + * necessarily available. + */ +void PNGAPI +png_init_io(png_structp png_ptr, png_FILE_p fp) +{ + png_debug(1, "in png_init_io"); + + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = (png_voidp)fp; +} +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +png_charp PNGAPI +png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) +{ + static PNG_CONST char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (png_ptr == NULL) + return (NULL); + if (png_ptr->time_buffer == NULL) + { + png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* + png_sizeof(char))); + } + +#ifdef _WIN32_WCE + { + wchar_t time_buf[29]; + wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"), + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, + 29, NULL, NULL); + } +#else +#ifdef USE_FAR_KEYWORD + { + char near_time_buf[29]; + png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + png_memcpy(png_ptr->time_buffer, near_time_buf, + 29*png_sizeof(char)); + } +#else + png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); +#endif +#endif /* _WIN32_WCE */ + return ((png_charp)png_ptr->time_buffer); +} +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +png_charp PNGAPI +png_get_copyright(png_structp png_ptr) +{ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT +#else +#ifdef __STDC__ + return ((png_charp) PNG_STRING_NEWLINE \ + "libpng version 1.2.51 - February 6, 2014" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2014 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ + "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ + "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ + PNG_STRING_NEWLINE); +#else + return ((png_charp) "libpng version 1.2.51 - February 6, 2014\ + Copyright (c) 1998-2014 Glenn Randers-Pehrson\ + Copyright (c) 1996-1997 Andreas Dilger\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."); +#endif +#endif +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. + */ +png_charp PNGAPI +png_get_libpng_ver(png_structp png_ptr) +{ + /* Version of *.c files used when building libpng */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); +} + +png_charp PNGAPI +png_get_header_ver(png_structp png_ptr) +{ + /* Version of *.h files used when building libpng */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); +} + +png_charp PNGAPI +png_get_header_version(png_structp png_ptr) +{ + /* Returns longer string containing both version and date */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef __STDC__ + return ((png_charp) PNG_HEADER_VERSION_STRING +#ifndef PNG_READ_SUPPORTED + " (NO READ SUPPORT)" +#endif + PNG_STRING_NEWLINE); +#else + return ((png_charp) PNG_HEADER_VERSION_STRING); +#endif +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) +{ + /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + int i; + png_bytep p; + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0) + return 0; + p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5; + for (i = png_ptr->num_chunk_list; i; i--, p -= 5) + if (!png_memcmp(chunk_name, p, 4)) + return ((int)*(p + 4)); + return 0; +} +#endif + +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structp png_ptr) +{ + if (png_ptr == NULL) + return Z_STREAM_ERROR; + return (inflateReset(&png_ptr->zstream)); +} +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return((png_uint_32) PNG_LIBPNG_VER); +} + + +#if defined(PNG_READ_SUPPORTED) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) +#ifndef PNG_1_0_X +/* This function was added to libpng 1.2.0 */ +int PNGAPI +png_mmx_support(void) +{ + /* Obsolete, to be removed from libpng-1.4.0 */ + return -1; +} +#endif /* PNG_1_0_X */ +#endif /* PNG_READ_SUPPORTED && PNG_ASSEMBLER_CODE_SUPPORTED */ + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#ifdef PNG_SIZE_T +/* Added at libpng version 1.2.6 */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); +png_size_t PNGAPI +png_convert_size(size_t size) +{ + if (size > (png_size_t)-1) + PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ + return ((png_size_t)size); +} +#endif /* PNG_SIZE_T */ + +/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_CHECK_cHRM_SUPPORTED + +/* + * Multiply two 32-bit numbers, V1 and V2, using 32-bit + * arithmetic, to produce a 64 bit result in the HI/LO words. + * + * A B + * x C D + * ------ + * AD || BD + * AC || CB || 0 + * + * where A and B are the high and low 16-bit words of V1, + * C and D are the 16-bit words of V2, AD is the product of + * A and D, and X || Y is (X << 16) + Y. +*/ + +void /* PRIVATE */ +png_64bit_product (long v1, long v2, unsigned long *hi_product, + unsigned long *lo_product) +{ + int a, b, c, d; + long lo, hi, x, y; + + a = (v1 >> 16) & 0xffff; + b = v1 & 0xffff; + c = (v2 >> 16) & 0xffff; + d = v2 & 0xffff; + + lo = b * d; /* BD */ + x = a * d + c * b; /* AD + CB */ + y = ((lo >> 16) & 0xffff) + x; + + lo = (lo & 0xffff) | ((y & 0xffff) << 16); + hi = (y >> 16) & 0xffff; + + hi += a * c; /* AC */ + + *hi_product = (unsigned long)hi; + *lo_product = (unsigned long)lo; +} + +int /* PRIVATE */ +png_check_cHRM_fixed(png_structp png_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + int ret = 1; + unsigned long xy_hi,xy_lo,yx_hi,yx_lo; + + png_debug(1, "in function png_check_cHRM_fixed"); + + if (png_ptr == NULL) + return 0; + + if (white_x < 0 || white_y <= 0 || + red_x < 0 || red_y < 0 || + green_x < 0 || green_y < 0 || + blue_x < 0 || blue_y < 0) + { + png_warning(png_ptr, + "Ignoring attempt to set negative chromaticity value"); + ret = 0; + } + if (white_x > (png_fixed_point) PNG_UINT_31_MAX || + white_y > (png_fixed_point) PNG_UINT_31_MAX || + red_x > (png_fixed_point) PNG_UINT_31_MAX || + red_y > (png_fixed_point) PNG_UINT_31_MAX || + green_x > (png_fixed_point) PNG_UINT_31_MAX || + green_y > (png_fixed_point) PNG_UINT_31_MAX || + blue_x > (png_fixed_point) PNG_UINT_31_MAX || + blue_y > (png_fixed_point) PNG_UINT_31_MAX ) + { + png_warning(png_ptr, + "Ignoring attempt to set chromaticity value exceeding 21474.83"); + ret = 0; + } + if (white_x > 100000L - white_y) + { + png_warning(png_ptr, "Invalid cHRM white point"); + ret = 0; + } + if (red_x > 100000L - red_y) + { + png_warning(png_ptr, "Invalid cHRM red point"); + ret = 0; + } + if (green_x > 100000L - green_y) + { + png_warning(png_ptr, "Invalid cHRM green point"); + ret = 0; + } + if (blue_x > 100000L - blue_y) + { + png_warning(png_ptr, "Invalid cHRM blue point"); + ret = 0; + } + + png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo); + png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo); + + if (xy_hi == yx_hi && xy_lo == yx_lo) + { + png_warning(png_ptr, + "Ignoring attempt to set cHRM RGB triangle with zero area"); + ret = 0; + } + + return ret; +} +#endif /* PNG_CHECK_cHRM_SUPPORTED */ +#endif /* PNG_cHRM_SUPPORTED */ + +void /* PRIVATE */ +png_check_IHDR(png_structp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + int error = 0; + + /* Check for width and height valid values */ + if (width == 0) + { + png_warning(png_ptr, "Image width is zero in IHDR"); + error = 1; + } + + if (height == 0) + { + png_warning(png_ptr, "Image height is zero in IHDR"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX) +#else + if (width > PNG_USER_WIDTH_MAX) +#endif + { + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX) +#else + if (height > PNG_USER_HEIGHT_MAX) +#endif + { + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } + + if (width > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image width in IHDR"); + error = 1; + } + + if ( height > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image height in IHDR"); + error = 1; + } + + /* Check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + { + png_warning(png_ptr, "Invalid bit depth in IHDR"); + error = 1; + } + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + { + png_warning(png_ptr, "Invalid color type in IHDR"); + error = 1; + } + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + { + png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); + error = 1; + } + + if (interlace_type >= PNG_INTERLACE_LAST) + { + png_warning(png_ptr, "Unknown interlace method in IHDR"); + error = 1; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Unknown compression method in IHDR"); + error = 1; + } + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && + png_ptr->mng_features_permitted) + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + + if (filter_type != PNG_FILTER_TYPE_BASE) + { + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } + + if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) + { + png_warning(png_ptr, "Invalid filter method in IHDR"); + error = 1; + } + } + +#else + if (filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } +#endif + + if (error == 1) + png_error(png_ptr, "Invalid IHDR data"); +} +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ diff --git a/main/source/includes/lpng1251/png.h b/main/source/includes/lpng1251/png.h index c5aa5837..1c5ce845 100644 --- a/main/source/includes/lpng1251/png.h +++ b/main/source/includes/lpng1251/png.h @@ -1,3814 +1,3814 @@ -/* png.h - header file for PNG reference library - * - * libpng version 1.2.51 - February 6, 2014 - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license (See LICENSE, below) - * - * Authors and maintainers: - * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat - * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.2.51 - February 6, 2014: Glenn - * See also "Contributing Authors", below. - * - * Note about libpng version numbers: - * - * Due to various miscommunications, unforeseen code incompatibilities - * and occasional factors outside the authors' control, version numbering - * on the library has not always been consistent and straightforward. - * The following table summarizes matters since version 0.89c, which was - * the first widely used release: - * - * source png.h png.h shared-lib - * version string int version - * ------- ------ ----- ---------- - * 0.89c "1.0 beta 3" 0.89 89 1.0.89 - * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] - * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] - * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] - * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] - * 0.97c 0.97 97 2.0.97 - * 0.98 0.98 98 2.0.98 - * 0.99 0.99 98 2.0.99 - * 0.99a-m 0.99 99 2.0.99 - * 1.00 1.00 100 2.1.0 [100 should be 10000] - * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] - * 1.0.1 png.h string is 10001 2.1.0 - * 1.0.1a-e identical to the 10002 from here on, the shared library - * 1.0.2 source version) 10002 is 2.V where V is the source code - * 1.0.2a-b 10003 version, except as noted. - * 1.0.3 10003 - * 1.0.3a-d 10004 - * 1.0.4 10004 - * 1.0.4a-f 10005 - * 1.0.5 (+ 2 patches) 10005 - * 1.0.5a-d 10006 - * 1.0.5e-r 10100 (not source compatible) - * 1.0.5s-v 10006 (not binary compatible) - * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) - * 1.0.6d-f 10007 (still binary incompatible) - * 1.0.6g 10007 - * 1.0.6h 10007 10.6h (testing xy.z so-numbering) - * 1.0.6i 10007 10.6i - * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) - * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) - * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) - * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) - * 1.0.7 1 10007 (still compatible) - * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 - * 1.0.8rc1 1 10008 2.1.0.8rc1 - * 1.0.8 1 10008 2.1.0.8 - * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 - * 1.0.9rc1 1 10009 2.1.0.9rc1 - * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 - * 1.0.9rc2 1 10009 2.1.0.9rc2 - * 1.0.9 1 10009 2.1.0.9 - * 1.0.10beta1 1 10010 2.1.0.10beta1 - * 1.0.10rc1 1 10010 2.1.0.10rc1 - * 1.0.10 1 10010 2.1.0.10 - * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 - * 1.0.11rc1 1 10011 2.1.0.11rc1 - * 1.0.11 1 10011 2.1.0.11 - * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 - * 1.0.12rc1 2 10012 2.1.0.12rc1 - * 1.0.12 2 10012 2.1.0.12 - * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) - * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 - * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 - * 1.2.0rc1 3 10200 3.1.2.0rc1 - * 1.2.0 3 10200 3.1.2.0 - * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 - * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 - * 1.2.1 3 10201 3.1.2.1 - * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 - * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 - * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 - * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 - * 1.0.13 10 10013 10.so.0.1.0.13 - * 1.2.2 12 10202 12.so.0.1.2.2 - * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 - * 1.2.3 12 10203 12.so.0.1.2.3 - * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 - * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 - * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 - * 1.0.14 10 10014 10.so.0.1.0.14 - * 1.2.4 13 10204 12.so.0.1.2.4 - * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 - * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 - * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 - * 1.0.15 10 10015 10.so.0.1.0.15 - * 1.2.5 13 10205 12.so.0.1.2.5 - * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 - * 1.0.16 10 10016 10.so.0.1.0.16 - * 1.2.6 13 10206 12.so.0.1.2.6 - * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 - * 1.0.17rc1 10 10017 10.so.0.1.0.17rc1 - * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 - * 1.0.17 10 10017 10.so.0.1.0.17 - * 1.2.7 13 10207 12.so.0.1.2.7 - * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 - * 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5 - * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 - * 1.0.18 10 10018 10.so.0.1.0.18 - * 1.2.8 13 10208 12.so.0.1.2.8 - * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 - * 1.2.9beta4-11 13 10209 12.so.0.9[.0] - * 1.2.9rc1 13 10209 12.so.0.9[.0] - * 1.2.9 13 10209 12.so.0.9[.0] - * 1.2.10beta1-8 13 10210 12.so.0.10[.0] - * 1.2.10rc1-3 13 10210 12.so.0.10[.0] - * 1.2.10 13 10210 12.so.0.10[.0] - * 1.2.11beta1-4 13 10211 12.so.0.11[.0] - * 1.0.19rc1-5 10 10019 10.so.0.19[.0] - * 1.2.11rc1-5 13 10211 12.so.0.11[.0] - * 1.0.19 10 10019 10.so.0.19[.0] - * 1.2.11 13 10211 12.so.0.11[.0] - * 1.0.20 10 10020 10.so.0.20[.0] - * 1.2.12 13 10212 12.so.0.12[.0] - * 1.2.13beta1 13 10213 12.so.0.13[.0] - * 1.0.21 10 10021 10.so.0.21[.0] - * 1.2.13 13 10213 12.so.0.13[.0] - * 1.2.14beta1-2 13 10214 12.so.0.14[.0] - * 1.0.22rc1 10 10022 10.so.0.22[.0] - * 1.2.14rc1 13 10214 12.so.0.14[.0] - * 1.0.22 10 10022 10.so.0.22[.0] - * 1.2.14 13 10214 12.so.0.14[.0] - * 1.2.15beta1-6 13 10215 12.so.0.15[.0] - * 1.0.23rc1-5 10 10023 10.so.0.23[.0] - * 1.2.15rc1-5 13 10215 12.so.0.15[.0] - * 1.0.23 10 10023 10.so.0.23[.0] - * 1.2.15 13 10215 12.so.0.15[.0] - * 1.2.16beta1-2 13 10216 12.so.0.16[.0] - * 1.2.16rc1 13 10216 12.so.0.16[.0] - * 1.0.24 10 10024 10.so.0.24[.0] - * 1.2.16 13 10216 12.so.0.16[.0] - * 1.2.17beta1-2 13 10217 12.so.0.17[.0] - * 1.0.25rc1 10 10025 10.so.0.25[.0] - * 1.2.17rc1-3 13 10217 12.so.0.17[.0] - * 1.0.25 10 10025 10.so.0.25[.0] - * 1.2.17 13 10217 12.so.0.17[.0] - * 1.0.26 10 10026 10.so.0.26[.0] - * 1.2.18 13 10218 12.so.0.18[.0] - * 1.2.19beta1-31 13 10219 12.so.0.19[.0] - * 1.0.27rc1-6 10 10027 10.so.0.27[.0] - * 1.2.19rc1-6 13 10219 12.so.0.19[.0] - * 1.0.27 10 10027 10.so.0.27[.0] - * 1.2.19 13 10219 12.so.0.19[.0] - * 1.2.20beta01-04 13 10220 12.so.0.20[.0] - * 1.0.28rc1-6 10 10028 10.so.0.28[.0] - * 1.2.20rc1-6 13 10220 12.so.0.20[.0] - * 1.0.28 10 10028 10.so.0.28[.0] - * 1.2.20 13 10220 12.so.0.20[.0] - * 1.2.21beta1-2 13 10221 12.so.0.21[.0] - * 1.2.21rc1-3 13 10221 12.so.0.21[.0] - * 1.0.29 10 10029 10.so.0.29[.0] - * 1.2.21 13 10221 12.so.0.21[.0] - * 1.2.22beta1-4 13 10222 12.so.0.22[.0] - * 1.0.30rc1 10 10030 10.so.0.30[.0] - * 1.2.22rc1 13 10222 12.so.0.22[.0] - * 1.0.30 10 10030 10.so.0.30[.0] - * 1.2.22 13 10222 12.so.0.22[.0] - * 1.2.23beta01-05 13 10223 12.so.0.23[.0] - * 1.2.23rc01 13 10223 12.so.0.23[.0] - * 1.2.23 13 10223 12.so.0.23[.0] - * 1.2.24beta01-02 13 10224 12.so.0.24[.0] - * 1.2.24rc01 13 10224 12.so.0.24[.0] - * 1.2.24 13 10224 12.so.0.24[.0] - * 1.2.25beta01-06 13 10225 12.so.0.25[.0] - * 1.2.25rc01-02 13 10225 12.so.0.25[.0] - * 1.0.31 10 10031 10.so.0.31[.0] - * 1.2.25 13 10225 12.so.0.25[.0] - * 1.2.26beta01-06 13 10226 12.so.0.26[.0] - * 1.2.26rc01 13 10226 12.so.0.26[.0] - * 1.2.26 13 10226 12.so.0.26[.0] - * 1.0.32 10 10032 10.so.0.32[.0] - * 1.2.27beta01-06 13 10227 12.so.0.27[.0] - * 1.2.27rc01 13 10227 12.so.0.27[.0] - * 1.0.33 10 10033 10.so.0.33[.0] - * 1.2.27 13 10227 12.so.0.27[.0] - * 1.0.34 10 10034 10.so.0.34[.0] - * 1.2.28 13 10228 12.so.0.28[.0] - * 1.2.29beta01-03 13 10229 12.so.0.29[.0] - * 1.2.29rc01 13 10229 12.so.0.29[.0] - * 1.0.35 10 10035 10.so.0.35[.0] - * 1.2.29 13 10229 12.so.0.29[.0] - * 1.0.37 10 10037 10.so.0.37[.0] - * 1.2.30beta01-04 13 10230 12.so.0.30[.0] - * 1.0.38rc01-08 10 10038 10.so.0.38[.0] - * 1.2.30rc01-08 13 10230 12.so.0.30[.0] - * 1.0.38 10 10038 10.so.0.38[.0] - * 1.2.30 13 10230 12.so.0.30[.0] - * 1.0.39rc01-03 10 10039 10.so.0.39[.0] - * 1.2.31rc01-03 13 10231 12.so.0.31[.0] - * 1.0.39 10 10039 10.so.0.39[.0] - * 1.2.31 13 10231 12.so.0.31[.0] - * 1.2.32beta01-02 13 10232 12.so.0.32[.0] - * 1.0.40rc01 10 10040 10.so.0.40[.0] - * 1.2.32rc01 13 10232 12.so.0.32[.0] - * 1.0.40 10 10040 10.so.0.40[.0] - * 1.2.32 13 10232 12.so.0.32[.0] - * 1.2.33beta01-02 13 10233 12.so.0.33[.0] - * 1.2.33rc01-02 13 10233 12.so.0.33[.0] - * 1.0.41rc01 10 10041 10.so.0.41[.0] - * 1.2.33 13 10233 12.so.0.33[.0] - * 1.0.41 10 10041 10.so.0.41[.0] - * 1.2.34beta01-07 13 10234 12.so.0.34[.0] - * 1.0.42rc01 10 10042 10.so.0.42[.0] - * 1.2.34rc01 13 10234 12.so.0.34[.0] - * 1.0.42 10 10042 10.so.0.42[.0] - * 1.2.34 13 10234 12.so.0.34[.0] - * 1.2.35beta01-03 13 10235 12.so.0.35[.0] - * 1.0.43rc01-02 10 10043 10.so.0.43[.0] - * 1.2.35rc01-02 13 10235 12.so.0.35[.0] - * 1.0.43 10 10043 10.so.0.43[.0] - * 1.2.35 13 10235 12.so.0.35[.0] - * 1.2.36beta01-05 13 10236 12.so.0.36[.0] - * 1.2.36rc01 13 10236 12.so.0.36[.0] - * 1.0.44 10 10044 10.so.0.44[.0] - * 1.2.36 13 10236 12.so.0.36[.0] - * 1.2.37beta01-03 13 10237 12.so.0.37[.0] - * 1.2.37rc01 13 10237 12.so.0.37[.0] - * 1.2.37 13 10237 12.so.0.37[.0] - * 1.0.45 10 10045 12.so.0.45[.0] - * 1.0.46 10 10046 10.so.0.46[.0] - * 1.2.38beta01 13 10238 12.so.0.38[.0] - * 1.2.38rc01-03 13 10238 12.so.0.38[.0] - * 1.0.47 10 10047 10.so.0.47[.0] - * 1.2.38 13 10238 12.so.0.38[.0] - * 1.2.39beta01-05 13 10239 12.so.0.39[.0] - * 1.2.39rc01 13 10239 12.so.0.39[.0] - * 1.0.48 10 10048 10.so.0.48[.0] - * 1.2.39 13 10239 12.so.0.39[.0] - * 1.2.40beta01 13 10240 12.so.0.40[.0] - * 1.2.40rc01 13 10240 12.so.0.40[.0] - * 1.0.49 10 10049 10.so.0.49[.0] - * 1.2.40 13 10240 12.so.0.40[.0] - * 1.2.41beta01-18 13 10241 12.so.0.41[.0] - * 1.0.51rc01 10 10051 10.so.0.51[.0] - * 1.2.41rc01-03 13 10241 12.so.0.41[.0] - * 1.0.51 10 10051 10.so.0.51[.0] - * 1.2.41 13 10241 12.so.0.41[.0] - * 1.2.42beta01-02 13 10242 12.so.0.42[.0] - * 1.2.42rc01-05 13 10242 12.so.0.42[.0] - * 1.0.52 10 10052 10.so.0.52[.0] - * 1.2.42 13 10242 12.so.0.42[.0] - * 1.2.43beta01-05 13 10243 12.so.0.43[.0] - * 1.0.53rc01-02 10 10053 10.so.0.53[.0] - * 1.2.43rc01-02 13 10243 12.so.0.43[.0] - * 1.0.53 10 10053 10.so.0.53[.0] - * 1.2.43 13 10243 12.so.0.43[.0] - * 1.2.44beta01-03 13 10244 12.so.0.44[.0] - * 1.2.44rc01-03 13 10244 12.so.0.44[.0] - * 1.2.44 13 10244 12.so.0.44[.0] - * 1.2.45beta01-03 13 10245 12.so.0.45[.0] - * 1.0.55rc01 10 10055 10.so.0.55[.0] - * 1.2.45rc01 13 10245 12.so.0.45[.0] - * 1.0.55 10 10055 10.so.0.55[.0] - * 1.2.45 13 10245 12.so.0.45[.0] - * 1.2.46rc01-02 13 10246 12.so.0.46[.0] - * 1.0.56 10 10056 10.so.0.56[.0] - * 1.2.46 13 10246 12.so.0.46[.0] - * 1.2.47beta01 13 10247 12.so.0.47[.0] - * 1.2.47rc01 13 10247 12.so.0.47[.0] - * 1.0.57rc01 10 10057 10.so.0.57[.0] - * 1.2.47 13 10247 12.so.0.47[.0] - * 1.0.57 10 10057 10.so.0.57[.0] - * 1.2.48beta01 13 10248 12.so.0.48[.0] - * 1.2.48rc01-02 13 10248 12.so.0.48[.0] - * 1.0.58 10 10058 10.so.0.58[.0] - * 1.2.48 13 10248 12.so.0.48[.0] - * 1.2.49rc01 13 10249 12.so.0.49[.0] - * 1.0.59 10 10059 10.so.0.59[.0] - * 1.2.49 13 10249 12.so.0.49[.0] - * 1.0.60 10 10060 10.so.0.60[.0] - * 1.2.50 13 10250 12.so.0.50[.0] - * 1.2.51beta01-05 13 10251 12.so.0.51[.0] - * 1.2.51rc01-04 13 10251 12.so.0.51[.0] - * 1.0.61 10 10061 10.so.0.61[.0] - * 1.2.51 13 10251 12.so.0.51[.0] - * - * Henceforth the source version will match the shared-library major - * and minor numbers; the shared-library major version number will be - * used for changes in backward compatibility, as it is intended. The - * PNG_LIBPNG_VER macro, which is not used within libpng but is available - * for applications, is an unsigned integer of the form xyyzz corresponding - * to the source version x.y.z (leading zeros in y and z). Beta versions - * were given the previous public release number plus a letter, until - * version 1.0.6j; from then on they were given the upcoming public - * release number plus "betaNN" or "rcNN". - * - * Binary incompatibility exists only when applications make direct access - * to the info_ptr or png_ptr members through png.h, and the compiled - * application is loaded with a different version of the library. - * - * DLLNUM will change each time there are forward or backward changes - * in binary compatibility (e.g., when a new feature is added). - * - * See libpng.txt or libpng.3 for more information. The PNG specification - * is available as a W3C Recommendation and as an ISO Specification, - * defines should NOT be changed. - */ -#define PNG_INFO_gAMA 0x0001 -#define PNG_INFO_sBIT 0x0002 -#define PNG_INFO_cHRM 0x0004 -#define PNG_INFO_PLTE 0x0008 -#define PNG_INFO_tRNS 0x0010 -#define PNG_INFO_bKGD 0x0020 -#define PNG_INFO_hIST 0x0040 -#define PNG_INFO_pHYs 0x0080 -#define PNG_INFO_oFFs 0x0100 -#define PNG_INFO_tIME 0x0200 -#define PNG_INFO_pCAL 0x0400 -#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ -#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ -#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ -#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ -#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ - -/* This is used for the transformation routines, as some of them - * change these values for the row. It also should enable using - * the routines for other purposes. - */ -typedef struct png_row_info_struct -{ - png_uint_32 width; /* width of row */ - png_uint_32 rowbytes; /* number of bytes in row */ - png_byte color_type; /* color type of row */ - png_byte bit_depth; /* bit depth of row */ - png_byte channels; /* number of channels (1, 2, 3, or 4) */ - png_byte pixel_depth; /* bits per pixel (depth * channels) */ -} png_row_info; - -typedef png_row_info FAR * png_row_infop; -typedef png_row_info FAR * FAR * png_row_infopp; - -/* These are the function types for the I/O functions and for the functions - * that allow the user to override the default I/O functions with his or her - * own. The png_error_ptr type should match that of user-supplied warning - * and error functions, while the png_rw_ptr type should match that of the - * user read/write data functions. - */ -typedef struct png_struct_def png_struct; -typedef png_struct FAR * png_structp; - -typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); -typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); -typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); -typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, - int)); -typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, - int)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); -typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); -typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, - png_uint_32, int)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, - png_row_infop, png_bytep)); -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); -#endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); -#endif - -/* Transform masks for the high-level interface */ -#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ -#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ -#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ -#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ -#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ -#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ -#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ -#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ -#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ -#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ -#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ -#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ -#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only, deprecated */ -/* Added to libpng-1.2.34 */ -#define PNG_TRANSFORM_STRIP_FILLER_BEFORE 0x0800 /* write only */ -#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ -/* Added to libpng-1.2.41 */ -#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ - -/* Flags for MNG supported features */ -#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 -#define PNG_FLAG_MNG_FILTER_64 0x04 -#define PNG_ALL_MNG_FEATURES 0x05 - -typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); -typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); - -/* The structure that holds the information to read and write PNG files. - * The only people who need to care about what is inside of this are the - * people who will be modifying the library for their own special needs. - * It should NOT be accessed directly by an application, except to store - * the jmp_buf. - */ - -struct png_struct_def -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf jmpbuf; /* used in png_error */ -#endif - png_error_ptr error_fn PNG_DEPSTRUCT; /* function for printing errors and aborting */ - png_error_ptr warning_fn PNG_DEPSTRUCT; /* function for printing warnings */ - png_voidp error_ptr PNG_DEPSTRUCT; /* user supplied struct for error functions */ - png_rw_ptr write_data_fn PNG_DEPSTRUCT; /* function for writing output data */ - png_rw_ptr read_data_fn PNG_DEPSTRUCT; /* function for reading input data */ - png_voidp io_ptr PNG_DEPSTRUCT; /* ptr to application struct for I/O functions */ - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - png_user_transform_ptr read_user_transform_fn PNG_DEPSTRUCT; /* user read transform */ -#endif - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - png_user_transform_ptr write_user_transform_fn PNG_DEPSTRUCT; /* user write transform */ -#endif - -/* These were added in libpng-1.0.2 */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_voidp user_transform_ptr PNG_DEPSTRUCT; /* user supplied struct for user transform */ - png_byte user_transform_depth PNG_DEPSTRUCT; /* bit depth of user transformed pixels */ - png_byte user_transform_channels PNG_DEPSTRUCT; /* channels in user transformed pixels */ -#endif -#endif - - png_uint_32 mode PNG_DEPSTRUCT; /* tells us where we are in the PNG file */ - png_uint_32 flags PNG_DEPSTRUCT; /* flags indicating various things to libpng */ - png_uint_32 transformations PNG_DEPSTRUCT; /* which transformations to perform */ - - z_stream zstream PNG_DEPSTRUCT; /* pointer to decompression structure (below) */ - png_bytep zbuf PNG_DEPSTRUCT; /* buffer for zlib */ - png_size_t zbuf_size PNG_DEPSTRUCT; /* size of zbuf */ - int zlib_level PNG_DEPSTRUCT; /* holds zlib compression level */ - int zlib_method PNG_DEPSTRUCT; /* holds zlib compression method */ - int zlib_window_bits PNG_DEPSTRUCT; /* holds zlib compression window bits */ - int zlib_mem_level PNG_DEPSTRUCT; /* holds zlib compression memory level */ - int zlib_strategy PNG_DEPSTRUCT; /* holds zlib compression strategy */ - - png_uint_32 width PNG_DEPSTRUCT; /* width of image in pixels */ - png_uint_32 height PNG_DEPSTRUCT; /* height of image in pixels */ - png_uint_32 num_rows PNG_DEPSTRUCT; /* number of rows in current pass */ - png_uint_32 usr_width PNG_DEPSTRUCT; /* width of row at start of write */ - png_uint_32 rowbytes PNG_DEPSTRUCT; /* size of row in bytes */ -#if 0 /* Replaced with the following in libpng-1.2.43 */ - png_size_t irowbytes PNG_DEPSTRUCT; -#endif -/* Added in libpng-1.2.43 */ -#ifdef PNG_USER_LIMITS_SUPPORTED - /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown - * chunks that can be stored (0 means unlimited). - */ - png_uint_32 user_chunk_cache_max PNG_DEPSTRUCT; -#endif - png_uint_32 iwidth PNG_DEPSTRUCT; /* width of current interlaced row in pixels */ - png_uint_32 row_number PNG_DEPSTRUCT; /* current row in interlace pass */ - png_bytep prev_row PNG_DEPSTRUCT; /* buffer to save previous (unfiltered) row */ - png_bytep row_buf PNG_DEPSTRUCT; /* buffer to save current (unfiltered) row */ -#ifndef PNG_NO_WRITE_FILTER - png_bytep sub_row PNG_DEPSTRUCT; /* buffer to save "sub" row when filtering */ - png_bytep up_row PNG_DEPSTRUCT; /* buffer to save "up" row when filtering */ - png_bytep avg_row PNG_DEPSTRUCT; /* buffer to save "avg" row when filtering */ - png_bytep paeth_row PNG_DEPSTRUCT; /* buffer to save "Paeth" row when filtering */ -#endif - png_row_info row_info PNG_DEPSTRUCT; /* used for transformation routines */ - - png_uint_32 idat_size PNG_DEPSTRUCT; /* current IDAT size for read */ - png_uint_32 crc PNG_DEPSTRUCT; /* current chunk CRC value */ - png_colorp palette PNG_DEPSTRUCT; /* palette from the input file */ - png_uint_16 num_palette PNG_DEPSTRUCT; /* number of color entries in palette */ - png_uint_16 num_trans PNG_DEPSTRUCT; /* number of transparency values */ - png_byte chunk_name[5] PNG_DEPSTRUCT; /* null-terminated name of current chunk */ - png_byte compression PNG_DEPSTRUCT; /* file compression type (always 0) */ - png_byte filter PNG_DEPSTRUCT; /* file filter type (always 0) */ - png_byte interlaced PNG_DEPSTRUCT; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - png_byte pass PNG_DEPSTRUCT; /* current interlace pass (0 - 6) */ - png_byte do_filter PNG_DEPSTRUCT; /* row filter flags (see PNG_FILTER_ below ) */ - png_byte color_type PNG_DEPSTRUCT; /* color type of file */ - png_byte bit_depth PNG_DEPSTRUCT; /* bit depth of file */ - png_byte usr_bit_depth PNG_DEPSTRUCT; /* bit depth of users row */ - png_byte pixel_depth PNG_DEPSTRUCT; /* number of bits per pixel */ - png_byte channels PNG_DEPSTRUCT; /* number of channels in file */ - png_byte usr_channels PNG_DEPSTRUCT; /* channels at start of write */ - png_byte sig_bytes PNG_DEPSTRUCT; /* magic bytes read/written from start of file */ - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -#ifdef PNG_LEGACY_SUPPORTED - png_byte filler PNG_DEPSTRUCT; /* filler byte for pixel expansion */ -#else - png_uint_16 filler PNG_DEPSTRUCT; /* filler bytes for pixel expansion */ -#endif -#endif - -#ifdef PNG_bKGD_SUPPORTED - png_byte background_gamma_type PNG_DEPSTRUCT; -# ifdef PNG_FLOATING_POINT_SUPPORTED - float background_gamma PNG_DEPSTRUCT; -# endif - png_color_16 background PNG_DEPSTRUCT; /* background color in screen gamma space */ -#ifdef PNG_READ_GAMMA_SUPPORTED - png_color_16 background_1 PNG_DEPSTRUCT; /* background normalized to gamma 1.0 */ -#endif -#endif /* PNG_bKGD_SUPPORTED */ - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_flush_ptr output_flush_fn PNG_DEPSTRUCT; /* Function for flushing output */ - png_uint_32 flush_dist PNG_DEPSTRUCT; /* how many rows apart to flush, 0 - no flush */ - png_uint_32 flush_rows PNG_DEPSTRUCT; /* number of rows written since last flush */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - int gamma_shift PNG_DEPSTRUCT; /* number of "insignificant" bits 16-bit gamma */ -#ifdef PNG_FLOATING_POINT_SUPPORTED - float gamma PNG_DEPSTRUCT; /* file gamma value */ - float screen_gamma PNG_DEPSTRUCT; /* screen gamma value (display_exponent) */ -#endif -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep gamma_table PNG_DEPSTRUCT; /* gamma table for 8-bit depth files */ - png_bytep gamma_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to screen */ - png_bytep gamma_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ - png_uint_16pp gamma_16_table PNG_DEPSTRUCT; /* gamma table for 16-bit depth files */ - png_uint_16pp gamma_16_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to screen */ - png_uint_16pp gamma_16_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) - png_color_8 sig_bit PNG_DEPSTRUCT; /* significant bits in each available channel */ -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift PNG_DEPSTRUCT; /* shift for significant bit tranformation */ -#endif - -#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ - || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep trans PNG_DEPSTRUCT; /* transparency values for paletted files */ - png_color_16 trans_values PNG_DEPSTRUCT; /* transparency values for non-paletted files */ -#endif - - png_read_status_ptr read_row_fn PNG_DEPSTRUCT; /* called after each row is decoded */ - png_write_status_ptr write_row_fn PNG_DEPSTRUCT; /* called after each row is encoded */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_info_ptr info_fn PNG_DEPSTRUCT; /* called after header data fully read */ - png_progressive_row_ptr row_fn PNG_DEPSTRUCT; /* called after each prog. row is decoded */ - png_progressive_end_ptr end_fn PNG_DEPSTRUCT; /* called after image is complete */ - png_bytep save_buffer_ptr PNG_DEPSTRUCT; /* current location in save_buffer */ - png_bytep save_buffer PNG_DEPSTRUCT; /* buffer for previously read data */ - png_bytep current_buffer_ptr PNG_DEPSTRUCT; /* current location in current_buffer */ - png_bytep current_buffer PNG_DEPSTRUCT; /* buffer for recently used data */ - png_uint_32 push_length PNG_DEPSTRUCT; /* size of current input chunk */ - png_uint_32 skip_length PNG_DEPSTRUCT; /* bytes to skip in input data */ - png_size_t save_buffer_size PNG_DEPSTRUCT; /* amount of data now in save_buffer */ - png_size_t save_buffer_max PNG_DEPSTRUCT; /* total size of save_buffer */ - png_size_t buffer_size PNG_DEPSTRUCT; /* total amount of available input data */ - png_size_t current_buffer_size PNG_DEPSTRUCT; /* amount of data now in current_buffer */ - int process_mode PNG_DEPSTRUCT; /* what push library is currently doing */ - int cur_palette PNG_DEPSTRUCT; /* current push library palette index */ - -# ifdef PNG_TEXT_SUPPORTED - png_size_t current_text_size PNG_DEPSTRUCT; /* current size of text input data */ - png_size_t current_text_left PNG_DEPSTRUCT; /* how much text left to read in input */ - png_charp current_text PNG_DEPSTRUCT; /* current text chunk buffer */ - png_charp current_text_ptr PNG_DEPSTRUCT; /* current location in current_text */ -# endif /* PNG_TEXT_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* for the Borland special 64K segment handler */ - png_bytepp offset_table_ptr PNG_DEPSTRUCT; - png_bytep offset_table PNG_DEPSTRUCT; - png_uint_16 offset_table_number PNG_DEPSTRUCT; - png_uint_16 offset_table_count PNG_DEPSTRUCT; - png_uint_16 offset_table_count_free PNG_DEPSTRUCT; -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED - png_bytep palette_lookup PNG_DEPSTRUCT; /* lookup table for dithering */ - png_bytep dither_index PNG_DEPSTRUCT; /* index translation for palette files */ -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) - png_uint_16p hist PNG_DEPSTRUCT; /* histogram */ -#endif - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_byte heuristic_method PNG_DEPSTRUCT; /* heuristic for row filter selection */ - png_byte num_prev_filters PNG_DEPSTRUCT; /* number of weights for previous rows */ - png_bytep prev_filters PNG_DEPSTRUCT; /* filter type(s) of previous row(s) */ - png_uint_16p filter_weights PNG_DEPSTRUCT; /* weight(s) for previous line(s) */ - png_uint_16p inv_filter_weights PNG_DEPSTRUCT; /* 1/weight(s) for previous line(s) */ - png_uint_16p filter_costs PNG_DEPSTRUCT; /* relative filter calculation cost */ - png_uint_16p inv_filter_costs PNG_DEPSTRUCT; /* 1/relative filter calculation cost */ -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_charp time_buffer PNG_DEPSTRUCT; /* String to hold RFC 1123 time text */ -#endif - -/* New members added in libpng-1.0.6 */ - -#ifdef PNG_FREE_ME_SUPPORTED - png_uint_32 free_me PNG_DEPSTRUCT; /* flags items libpng is responsible for freeing */ -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED - png_voidp user_chunk_ptr PNG_DEPSTRUCT; - png_user_chunk_ptr read_user_chunk_fn PNG_DEPSTRUCT; /* user read chunk handler */ -#endif - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int num_chunk_list PNG_DEPSTRUCT; - png_bytep chunk_list PNG_DEPSTRUCT; -#endif - -/* New members added in libpng-1.0.3 */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - png_byte rgb_to_gray_status PNG_DEPSTRUCT; - /* These were changed from png_byte in libpng-1.0.6 */ - png_uint_16 rgb_to_gray_red_coeff PNG_DEPSTRUCT; - png_uint_16 rgb_to_gray_green_coeff PNG_DEPSTRUCT; - png_uint_16 rgb_to_gray_blue_coeff PNG_DEPSTRUCT; -#endif - -/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ -#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ - defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ - defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) -/* Changed from png_byte to png_uint_32 at version 1.2.0 */ -#ifdef PNG_1_0_X - png_byte mng_features_permitted PNG_DEPSTRUCT; -#else - png_uint_32 mng_features_permitted PNG_DEPSTRUCT; -#endif /* PNG_1_0_X */ -#endif - -/* New member added in libpng-1.0.7 */ -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_fixed_point int_gamma PNG_DEPSTRUCT; -#endif - -/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_byte filter_type PNG_DEPSTRUCT; -#endif - -#ifdef PNG_1_0_X -/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ - png_uint_32 row_buf_size PNG_DEPSTRUCT; -#endif - -/* New members added in libpng-1.2.0 */ -#ifdef PNG_ASSEMBLER_CODE_SUPPORTED -# ifndef PNG_1_0_X -# ifdef PNG_MMX_CODE_SUPPORTED - png_byte mmx_bitdepth_threshold PNG_DEPSTRUCT; - png_uint_32 mmx_rowbytes_threshold PNG_DEPSTRUCT; -# endif - png_uint_32 asm_flags PNG_DEPSTRUCT; -# endif -#endif - -/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ -#ifdef PNG_USER_MEM_SUPPORTED - png_voidp mem_ptr PNG_DEPSTRUCT; /* user supplied struct for mem functions */ - png_malloc_ptr malloc_fn PNG_DEPSTRUCT; /* function for allocating memory */ - png_free_ptr free_fn PNG_DEPSTRUCT; /* function for freeing memory */ -#endif - -/* New member added in libpng-1.0.13 and 1.2.0 */ - png_bytep big_row_buf PNG_DEPSTRUCT; /* buffer to save current (unfiltered) row */ - -#ifdef PNG_READ_DITHER_SUPPORTED -/* The following three members were added at version 1.0.14 and 1.2.4 */ - png_bytep dither_sort PNG_DEPSTRUCT; /* working sort array */ - png_bytep index_to_palette PNG_DEPSTRUCT; /* where the original index currently is */ - /* in the palette */ - png_bytep palette_to_index PNG_DEPSTRUCT; /* which original index points to this */ - /* palette color */ -#endif - -/* New members added in libpng-1.0.16 and 1.2.6 */ - png_byte compression_type PNG_DEPSTRUCT; - -#ifdef PNG_USER_LIMITS_SUPPORTED - png_uint_32 user_width_max PNG_DEPSTRUCT; - png_uint_32 user_height_max PNG_DEPSTRUCT; -#endif - -/* New member added in libpng-1.0.25 and 1.2.17 */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - /* Storage for unknown chunk that the library doesn't recognize. */ - png_unknown_chunk unknown_chunk PNG_DEPSTRUCT; -#endif - -/* New members added in libpng-1.2.26 */ - png_uint_32 old_big_row_buf_size PNG_DEPSTRUCT; - png_uint_32 old_prev_row_size PNG_DEPSTRUCT; - -/* New member added in libpng-1.2.30 */ - png_charp chunkdata PNG_DEPSTRUCT; /* buffer for reading chunk data */ - - -}; - - -/* This triggers a compiler error in png.c, if png.c and png.h - * do not agree upon the version number. - */ -typedef png_structp version_1_2_51; - -typedef png_struct FAR * FAR * png_structpp; - -/* Here are the function definitions most commonly used. This is not - * the place to find out how to use libpng. See libpng.txt for the - * full explanation, see example.c for the summary. This just provides - * a simple one line description of the use of each function. - */ - -/* Returns the version number of the library */ -extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); - -/* Tell lib we have already handled the first magic bytes. - * Handling more than 8 bytes from the beginning of the file is an error. - */ -extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, - int num_bytes)); - -/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a - * PNG file. Returns zero if the supplied bytes match the 8-byte PNG - * signature, and non-zero otherwise. Having num_to_check == 0 or - * start > 7 will always fail (ie return non-zero). - */ -extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, - png_size_t num_to_check)); - -/* Simple signature checking function. This is the same as calling - * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). - */ -extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)) PNG_DEPRECATED; - -/* Allocate and initialize png_ptr struct for reading, and any other memory. */ -extern PNG_EXPORT(png_structp,png_create_read_struct) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn)) PNG_ALLOCATED; - -/* Allocate and initialize png_ptr struct for writing, and any other memory */ -extern PNG_EXPORT(png_structp,png_create_write_struct) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn)) PNG_ALLOCATED; - -#ifdef PNG_WRITE_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) - PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_WRITE_SUPPORTED -extern PNG_EXPORT(void,png_set_compression_buffer_size) - PNGARG((png_structp png_ptr, png_uint_32 size)); -#endif - -/* Reset the compression stream */ -extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); - -/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ -#ifdef PNG_USER_MEM_SUPPORTED -extern PNG_EXPORT(png_structp,png_create_read_struct_2) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)) PNG_ALLOCATED; -extern PNG_EXPORT(png_structp,png_create_write_struct_2) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)) PNG_ALLOCATED; -#endif - -/* Write a PNG chunk - size, type, (optional) data, CRC. */ -extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, - png_bytep chunk_name, png_bytep data, png_size_t length)); - -/* Write the start of a PNG chunk - length and chunk name. */ -extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, - png_bytep chunk_name, png_uint_32 length)); - -/* Write the data of a PNG chunk started with png_write_chunk_start(). */ -extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); - -/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ -extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); - -/* Allocate and initialize the info structure */ -extern PNG_EXPORT(png_infop,png_create_info_struct) - PNGARG((png_structp png_ptr)) PNG_ALLOCATED; - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Initialize the info structure (old interface - DEPRECATED) */ -extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)) - PNG_DEPRECATED; -#undef png_info_init -#define png_info_init(info_ptr) png_info_init_3(&info_ptr,\ - png_sizeof(png_info)); -#endif - -extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, - png_size_t png_info_struct_size)); - -/* Writes all the PNG information before the image. */ -extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the information before the actual image data. */ -extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED -extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) - PNGARG((png_structp png_ptr, png_timep ptime)); -#endif - -#ifdef PNG_CONVERT_tIME_SUPPORTED -/* Convert from a struct tm to png_time */ -extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, - struct tm FAR * ttime)); - -/* Convert from time_t to png_time. Uses gmtime() */ -extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, - time_t ttime)); -#endif /* PNG_CONVERT_tIME_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ -extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); -#ifndef PNG_1_0_X -extern PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp - png_ptr)); -#endif -extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Deprecated */ -extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp - png_ptr)) PNG_DEPRECATED; -#endif -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Use blue, green, red order for pixels. */ -extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -/* Expand the grayscale to 24-bit RGB if necessary. */ -extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -/* Reduce RGB to grayscale. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, - int error_action, double red, double green )); -#endif -extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, - int error_action, png_fixed_point red, png_fixed_point green )); -extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp - png_ptr)); -#endif - -extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, - png_colorp palette)); - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ -extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, - png_uint_32 filler, int flags)); -/* The values of the PNG_FILLER_ defines should NOT be changed */ -#define PNG_FILLER_BEFORE 0 -#define PNG_FILLER_AFTER 1 -/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ -#ifndef PNG_1_0_X -extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, - png_uint_32 filler, int flags)); -#endif -#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Swap bytes in 16-bit depth files. */ -extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) -/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ -extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) -/* Swap packing order of pixels in bytes. */ -extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) -/* Converts files to legal bit depths. */ -extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, - png_color_8p true_bits)); -#endif - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) -/* Have the code handle the interlacing. Returns the number of passes. */ -extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -/* Invert monochrome files */ -extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Handle alpha and tRNS by replacing with a background color. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, - png_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma)); -#endif -#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 -#define PNG_BACKGROUND_GAMMA_SCREEN 1 -#define PNG_BACKGROUND_GAMMA_FILE 2 -#define PNG_BACKGROUND_GAMMA_UNIQUE 3 -#endif - -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Strip the second byte of information from a 16-bit depth file. */ -extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED -/* Turn on dithering, and reduce the palette to the number of colors available. */ -extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette, int maximum_colors, - png_uint_16p histogram, int full_dither)); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* Handle gamma correction. Screen_gamma=(display_exponent) */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, - double screen_gamma, double default_file_gamma)); -#endif -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ - defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) -/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ -/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ -extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, - int empty_plte_permitted)) PNG_DEPRECATED; -#endif -#endif - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set how many lines between output flushes - 0 for no flushing */ -extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); -/* Flush the current PNG output buffer */ -extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); -#endif - -/* Optional update palette with requested transformations */ -extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); - -/* Optional call to update the users info structure */ -extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read one or more rows of image data. */ -extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, - png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); -#endif - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read a row of data. */ -extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, - png_bytep row, - png_bytep display_row)); -#endif - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the whole image into memory at once. */ -extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, - png_bytepp image)); -#endif - -/* Write a row of image data */ -extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, - png_bytep row)); - -/* Write a few rows of image data */ -extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, - png_bytepp row, png_uint_32 num_rows)); - -/* Write the image data */ -extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, - png_bytepp image)); - -/* Writes the end of the PNG file. */ -extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the end of the PNG file. */ -extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -/* Free any memory associated with the png_info_struct */ -extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, - png_infopp info_ptr_ptr)); - -/* Free any memory associated with the png_struct and the png_info_structs */ -extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp - png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); - -/* Free all memory used by the read (old method - NOT DLL EXPORTED) */ -extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, - png_infop end_info_ptr)) PNG_DEPRECATED; - -/* Free any memory associated with the png_struct and the png_info_structs */ -extern PNG_EXPORT(void,png_destroy_write_struct) - PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); - -/* Free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ -extern void png_write_destroy PNGARG((png_structp png_ptr)) PNG_DEPRECATED; - -/* Set the libpng method of handling chunk CRC errors */ -extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, - int crit_action, int ancil_action)); - -/* Values for png_set_crc_action() to say how to handle CRC errors in - * ancillary and critical chunks, and whether to use the data contained - * therein. Note that it is impossible to "discard" data in a critical - * chunk. For versions prior to 0.90, the action was always error/quit, - * whereas in version 0.90 and later, the action for CRC errors in ancillary - * chunks is warn/discard. These values should NOT be changed. - * - * value action:critical action:ancillary - */ -#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ -#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ -#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ -#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ -#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ -#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ - -/* These functions give the user control over the scan-line filtering in - * libpng and the compression methods used by zlib. These functions are - * mainly useful for testing, as the defaults should work with most users. - * Those users who are tight on memory or want faster performance at the - * expense of compression can modify them. See the compression library - * header file (zlib.h) for an explination of the compression functions. - */ - -/* Set the filtering method(s) used by libpng. Currently, the only valid - * value for "method" is 0. - */ -extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, - int filters)); - -/* Flags for png_set_filter() to say which filters to use. The flags - * are chosen so that they don't conflict with real filter types - * below, in case they are supplied instead of the #defined constants. - * These values should NOT be changed. - */ -#define PNG_NO_FILTERS 0x00 -#define PNG_FILTER_NONE 0x08 -#define PNG_FILTER_SUB 0x10 -#define PNG_FILTER_UP 0x20 -#define PNG_FILTER_AVG 0x40 -#define PNG_FILTER_PAETH 0x80 -#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ - PNG_FILTER_AVG | PNG_FILTER_PAETH) - -/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. - * These defines should NOT be changed. - */ -#define PNG_FILTER_VALUE_NONE 0 -#define PNG_FILTER_VALUE_SUB 1 -#define PNG_FILTER_VALUE_UP 2 -#define PNG_FILTER_VALUE_AVG 3 -#define PNG_FILTER_VALUE_PAETH 4 -#define PNG_FILTER_VALUE_LAST 5 - -#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ -/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ - * defines, either the default (minimum-sum-of-absolute-differences), or - * the experimental method (weighted-minimum-sum-of-absolute-differences). - * - * Weights are factors >= 1.0, indicating how important it is to keep the - * filter type consistent between rows. Larger numbers mean the current - * filter is that many times as likely to be the same as the "num_weights" - * previous filters. This is cumulative for each previous row with a weight. - * There needs to be "num_weights" values in "filter_weights", or it can be - * NULL if the weights aren't being specified. Weights have no influence on - * the selection of the first row filter. Well chosen weights can (in theory) - * improve the compression for a given image. - * - * Costs are factors >= 1.0 indicating the relative decoding costs of a - * filter type. Higher costs indicate more decoding expense, and are - * therefore less likely to be selected over a filter with lower computational - * costs. There needs to be a value in "filter_costs" for each valid filter - * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't - * setting the costs. Costs try to improve the speed of decompression without - * unduly increasing the compressed image size. - * - * A negative weight or cost indicates the default value is to be used, and - * values in the range [0.0, 1.0) indicate the value is to remain unchanged. - * The default values for both weights and costs are currently 1.0, but may - * change if good general weighting/cost heuristics can be found. If both - * the weights and costs are set to 1.0, this degenerates the WEIGHTED method - * to the UNWEIGHTED method, but with added encoding time/computation. - */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, - int heuristic_method, int num_weights, png_doublep filter_weights, - png_doublep filter_costs)); -#endif -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ - -/* Heuristic used for row filter selection. These defines should NOT be - * changed. - */ -#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ -#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ -#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ -#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ - -/* Set the library compression level. Currently, valid values range from - * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 - * (0 - no compression, 9 - "maximal" compression). Note that tests have - * shown that zlib compression levels 3-6 usually perform as well as level 9 - * for PNG images, and do considerably fewer caclulations. In the future, - * these values may not correspond directly to the zlib compression levels. - */ -extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, - int level)); - -extern PNG_EXPORT(void,png_set_compression_mem_level) - PNGARG((png_structp png_ptr, int mem_level)); - -extern PNG_EXPORT(void,png_set_compression_strategy) - PNGARG((png_structp png_ptr, int strategy)); - -extern PNG_EXPORT(void,png_set_compression_window_bits) - PNGARG((png_structp png_ptr, int window_bits)); - -extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, - int method)); - -/* These next functions are called for input/output, memory, and error - * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, - * and call standard C I/O routines such as fread(), fwrite(), and - * fprintf(). These functions can be made to use other I/O routines - * at run time for those applications that need to handle I/O in a - * different manner by calling png_set_???_fn(). See libpng.txt for - * more information. - */ - -#ifdef PNG_STDIO_SUPPORTED -/* Initialize the input/output for the PNG file to the default functions. */ -extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); -#endif - -/* Replace the (error and abort), and warning functions with user - * supplied functions. If no messages are to be printed you must still - * write and use replacement functions. The replacement error_fn should - * still do a longjmp to the last setjmp location if you are using this - * method of error handling. If error_fn or warning_fn is NULL, the - * default function will be used. - */ - -extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); - -/* Return the user pointer associated with the error functions */ -extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); - -/* Replace the default data output functions with a user supplied one(s). - * If buffered output is not used, then output_flush_fn can be set to NULL. - * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time - * output_flush_fn will be ignored (and thus can be NULL). - * It is probably a mistake to use NULL for output_flush_fn if - * write_data_fn is not also NULL unless you have built libpng with - * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's - * default flush function, which uses the standard *FILE structure, will - * be used. - */ -extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); - -/* Replace the default data input function with a user supplied one. */ -extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, png_rw_ptr read_data_fn)); - -/* Return the user pointer associated with the I/O functions */ -extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); - -extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, - png_read_status_ptr read_row_fn)); - -extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, - png_write_status_ptr write_row_fn)); - -#ifdef PNG_USER_MEM_SUPPORTED -/* Replace the default memory allocation functions with user supplied one(s). */ -extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, - png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); -/* Return the user pointer associated with the memory functions */ -extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp - png_ptr, png_user_transform_ptr read_user_transform_fn)); -#endif - -#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp - png_ptr, png_user_transform_ptr write_user_transform_fn)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp - png_ptr, png_voidp user_transform_ptr, int user_transform_depth, - int user_transform_channels)); -/* Return the user pointer associated with the user transform functions */ -extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) - PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, - png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); -extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp - png_ptr)); -#endif - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -/* Sets the function callbacks for the push reader, and a pointer to a - * user-defined structure available to the callback functions. - */ -extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, - png_voidp progressive_ptr, - png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, - png_progressive_end_ptr end_fn)); - -/* Returns the user pointer associated with the push read functions */ -extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) - PNGARG((png_structp png_ptr)); - -/* Function to be called when data becomes available */ -extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); - -/* Function that combines rows. Not very much different than the - * png_combine_row() call. Is this even used????? - */ -extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, - png_bytep old_row, png_bytep new_row)); -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, - png_uint_32 size)) PNG_ALLOCATED; - -#ifdef PNG_1_0_X -# define png_malloc_warn png_malloc -#else -/* Added at libpng version 1.2.4 */ -extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, - png_uint_32 size)) PNG_ALLOCATED; -#endif - -/* Frees a pointer allocated by png_malloc() */ -extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); - -#ifdef PNG_1_0_X -/* Function to allocate memory for zlib. */ -extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, - uInt size)); - -/* Function to free memory for zlib */ -extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); -#endif - -/* Free data that was allocated internally */ -extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 free_me, int num)); -#ifdef PNG_FREE_ME_SUPPORTED -/* Reassign responsibility for freeing existing data, whether allocated - * by libpng or by the application - */ -extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, - png_infop info_ptr, int freer, png_uint_32 mask)); -#endif -/* Assignments for png_data_freer */ -#define PNG_DESTROY_WILL_FREE_DATA 1 -#define PNG_SET_WILL_FREE_DATA 1 -#define PNG_USER_WILL_FREE_DATA 2 -/* Flags for png_ptr->free_me and info_ptr->free_me */ -#define PNG_FREE_HIST 0x0008 -#define PNG_FREE_ICCP 0x0010 -#define PNG_FREE_SPLT 0x0020 -#define PNG_FREE_ROWS 0x0040 -#define PNG_FREE_PCAL 0x0080 -#define PNG_FREE_SCAL 0x0100 -#define PNG_FREE_UNKN 0x0200 -#define PNG_FREE_LIST 0x0400 -#define PNG_FREE_PLTE 0x1000 -#define PNG_FREE_TRNS 0x2000 -#define PNG_FREE_TEXT 0x4000 -#define PNG_FREE_ALL 0x7fff -#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ - -#ifdef PNG_USER_MEM_SUPPORTED -extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, - png_uint_32 size)) PNG_ALLOCATED; -extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, - png_voidp ptr)); -#endif - -extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, - png_voidp s1, png_voidp s2, png_uint_32 size)) PNG_DEPRECATED; - -extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, - png_voidp s1, int value, png_uint_32 size)) PNG_DEPRECATED; - -#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ -extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, - int check)); -#endif /* USE_FAR_KEYWORD */ - -#ifndef PNG_NO_ERROR_TEXT -/* Fatal error in PNG image of libpng - can't continue */ -extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)) PNG_NORETURN; - -/* The same, but the chunk name is prepended to the error string. */ -extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)) PNG_NORETURN; -#else -/* Fatal error in PNG image of libpng - can't continue */ -extern PNG_EXPORT(void,png_err) PNGARG((png_structp png_ptr)) PNG_NORETURN; -#endif - -#ifndef PNG_NO_WARNINGS -/* Non-fatal error in libpng. Can continue, but may have a problem. */ -extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); - -#ifdef PNG_READ_SUPPORTED -/* Non-fatal error in libpng, chunk name is prepended to message. */ -extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); -#endif /* PNG_READ_SUPPORTED */ -#endif /* PNG_NO_WARNINGS */ - -/* The png_set_ functions are for storing values in the png_info_struct. - * Similarly, the png_get_ calls are used to read values from the - * png_info_struct, either storing the parameters in the passed variables, or - * setting pointers into the png_info_struct where the data is stored. The - * png_get_ functions return a non-zero value if the data was available - * in info_ptr, or return zero and do not change any of the parameters if the - * data was not available. - * - * These functions should be used instead of directly accessing png_info - * to avoid problems with future changes in the size and internal layout of - * png_info_struct. - */ -/* Returns "flag" if chunk data is valid in info_ptr. */ -extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, -png_infop info_ptr, png_uint_32 flag)); - -/* Returns number of bytes needed to hold a transformed row. */ -extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#ifdef PNG_INFO_IMAGE_SUPPORTED -/* Returns row_pointers, which is an array of pointers to scanlines that was - * returned from png_read_png(). - */ -extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, -png_infop info_ptr)); -/* Set row_pointers, which is an array of pointers to scanlines for use - * by png_write_png(). - */ -extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytepp row_pointers)); -#endif - -/* Returns number of color channels in image. */ -extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#ifdef PNG_EASY_ACCESS_SUPPORTED -/* Returns image width in pixels. */ -extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image height in pixels. */ -extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image bit_depth. */ -extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image color_type. */ -extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image filter_type. */ -extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image interlace_type. */ -extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image compression_type. */ -extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image resolution in pixels per meter, from pHYs chunk data. */ -extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns pixel aspect ratio, computed from pHYs chunk data. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -#endif - -/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ -extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ - -/* Returns pointer to signature string read from PNG header */ -extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#ifdef PNG_bKGD_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_16p *background)); -#endif - -#ifdef PNG_bKGD_SUPPORTED -extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_16p background)); -#endif - -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, double *white_x, double *white_y, double *red_x, - double *red_y, double *green_x, double *green_y, double *blue_x, - double *blue_y)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point - *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, - png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point - *int_blue_x, png_fixed_point *int_blue_y)); -#endif -#endif - -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, double white_x, double white_y, double red_x, - double red_y, double green_x, double green_y, double blue_x, double blue_y)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif -#endif - -#ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, double *file_gamma)); -#endif -extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point *int_file_gamma)); -#endif - -#ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, double file_gamma)); -#endif -extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_file_gamma)); -#endif - -#ifdef PNG_hIST_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_16p *hist)); -#endif - -#ifdef PNG_hIST_SUPPORTED -extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_16p hist)); -#endif - -extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, - int *bit_depth, int *color_type, int *interlace_method, - int *compression_method, int *filter_method)); - -extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_method, int compression_method, - int filter_method)); - -#ifdef PNG_oFFs_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, - int *unit_type)); -#endif - -#ifdef PNG_oFFs_SUPPORTED -extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, - int unit_type)); -#endif - -#ifdef PNG_pCAL_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, - int *type, int *nparams, png_charp *units, png_charpp *params)); -#endif - -#ifdef PNG_pCAL_SUPPORTED -extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, - int type, int nparams, png_charp units, png_charpp params)); -#endif - -#ifdef PNG_pHYs_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -#endif - -#ifdef PNG_pHYs_SUPPORTED -extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); -#endif - -extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_colorp *palette, int *num_palette)); - -extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_colorp palette, int num_palette)); - -#ifdef PNG_sBIT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_8p *sig_bit)); -#endif - -#ifdef PNG_sBIT_SUPPORTED -extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_8p sig_bit)); -#endif - -#ifdef PNG_sRGB_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *intent)); -#endif - -#ifdef PNG_sRGB_SUPPORTED -extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, int intent)); -extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, int intent)); -#endif - -#ifdef PNG_iCCP_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charpp name, int *compression_type, - png_charpp profile, png_uint_32 *proflen)); - /* Note to maintainer: profile should be png_bytepp */ -#endif - -#ifdef PNG_iCCP_SUPPORTED -extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp name, int compression_type, - png_charp profile, png_uint_32 proflen)); - /* Note to maintainer: profile should be png_bytep */ -#endif - -#ifdef PNG_sPLT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_sPLT_tpp entries)); -#endif - -#ifdef PNG_sPLT_SUPPORTED -extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_sPLT_tp entries, int nentries)); -#endif - -#ifdef PNG_TEXT_SUPPORTED -/* png_get_text also returns the number of text chunks in *num_text */ -extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp *text_ptr, int *num_text)); -#endif - -/* - * Note while png_set_text() will accept a structure whose text, - * language, and translated keywords are NULL pointers, the structure - * returned by png_get_text will always contain regular - * zero-terminated C strings. They might be empty strings but - * they will never be NULL pointers. - */ - -#ifdef PNG_TEXT_SUPPORTED -extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)); -#endif - -#ifdef PNG_tIME_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_timep *mod_time)); -#endif - -#ifdef PNG_tIME_SUPPORTED -extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_timep mod_time)); -#endif - -#ifdef PNG_tRNS_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep *trans, int *num_trans, - png_color_16p *trans_values)); -#endif - -#ifdef PNG_tRNS_SUPPORTED -extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep trans, int num_trans, - png_color_16p trans_values)); -#endif - -#ifdef PNG_tRNS_SUPPORTED -#endif - -#ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *unit, double *width, double *height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); -#endif -#endif -#endif /* PNG_sCAL_SUPPORTED */ - -#ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, int unit, double width, double height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, - png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); -#endif -#endif -#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -/* Provide a list of chunks and how they are to be handled, if the built-in - handling or default unknown chunk handling is not desired. Any chunks not - listed will be handled in the default manner. The IHDR and IEND chunks - must not be listed. - keep = 0: follow default behaviour - = 1: do not keep - = 2: keep only if safe-to-copy - = 3: keep even if unsafe-to-copy -*/ -extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp - png_ptr, int keep, png_bytep chunk_list, int num_chunks)); -PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep - chunk_name)); -#endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); -extern PNG_EXPORT(void, png_set_unknown_chunk_location) - PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); -extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp - png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); -#endif - -/* Png_free_data() will turn off the "valid" flag for anything it frees. - * If you need to turn it off for a chunk that your application has freed, - * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); - */ -extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, - png_infop info_ptr, int mask)); - -#ifdef PNG_INFO_IMAGE_SUPPORTED -/* The "params" pointer is currently not used and is for future expansion. */ -extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); -extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); -#endif - -/* Define PNG_DEBUG at compile time for debugging information. Higher - * numbers for PNG_DEBUG mean more debugging information. This has - * only been added since version 0.95 so it is not implemented throughout - * libpng yet, but more support will be added as needed. - */ -#ifdef PNG_DEBUG -#if (PNG_DEBUG > 0) -#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) -#include -#if (PNG_DEBUG > 1) -#ifndef _DEBUG -# define _DEBUG -#endif -#ifndef png_debug -#define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) -#endif -#ifndef png_debug1 -#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) -#endif -#ifndef png_debug2 -#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) -#endif -#endif -#else /* PNG_DEBUG_FILE || !_MSC_VER */ -#ifndef PNG_DEBUG_FILE -#define PNG_DEBUG_FILE stderr -#endif /* PNG_DEBUG_FILE */ - -#if (PNG_DEBUG > 1) -/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on non-ISO - * compilers. - */ -# ifdef __STDC__ -# ifndef png_debug -# define png_debug(l,m) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ - } -# endif -# ifndef png_debug1 -# define png_debug1(l,m,p1) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ - } -# endif -# ifndef png_debug2 -# define png_debug2(l,m,p1,p2) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ - } -# endif -# else /* __STDC __ */ -# ifndef png_debug -# define png_debug(l,m) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format); \ - } -# endif -# ifndef png_debug1 -# define png_debug1(l,m,p1) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format,p1); \ - } -# endif -# ifndef png_debug2 -# define png_debug2(l,m,p1,p2) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format,p1,p2); \ - } -# endif -# endif /* __STDC __ */ -#endif /* (PNG_DEBUG > 1) */ - -#endif /* _MSC_VER */ -#endif /* (PNG_DEBUG > 0) */ -#endif /* PNG_DEBUG */ -#ifndef png_debug -#define png_debug(l, m) -#endif -#ifndef png_debug1 -#define png_debug1(l, m, p1) -#endif -#ifndef png_debug2 -#define png_debug2(l, m, p1, p2) -#endif - -extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); - -#ifdef PNG_MNG_FEATURES_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp - png_ptr, png_uint_32 mng_features_permitted)); -#endif - -/* For use in png_set_keep_unknown, added to version 1.2.6 */ -#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 -#define PNG_HANDLE_CHUNK_NEVER 1 -#define PNG_HANDLE_CHUNK_IF_SAFE 2 -#define PNG_HANDLE_CHUNK_ALWAYS 3 - -/* Added to version 1.2.0 */ -#ifdef PNG_ASSEMBLER_CODE_SUPPORTED -#ifdef PNG_MMX_CODE_SUPPORTED -#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ -#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ -#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 -#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 -#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 -#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 -#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 -#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 -#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ - -#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ - | PNG_ASM_FLAG_MMX_READ_INTERLACE \ - | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ - | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ - | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ - | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ) -#define PNG_MMX_WRITE_FLAGS ( 0 ) - -#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \ - | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \ - | PNG_MMX_READ_FLAGS \ - | PNG_MMX_WRITE_FLAGS ) - -#define PNG_SELECT_READ 1 -#define PNG_SELECT_WRITE 2 -#endif /* PNG_MMX_CODE_SUPPORTED */ - -#ifndef PNG_1_0_X -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) - PNGARG((int flag_select, int *compilerID)); - -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) - PNGARG((int flag_select)); - -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_asm_flags) - PNGARG((png_structp png_ptr)); - -/* pngget.c */ -extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) - PNGARG((png_structp png_ptr)); - -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) - PNGARG((png_structp png_ptr)); - -/* pngset.c */ -extern PNG_EXPORT(void,png_set_asm_flags) - PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); - -/* pngset.c */ -extern PNG_EXPORT(void,png_set_mmx_thresholds) - PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, - png_uint_32 mmx_rowbytes_threshold)); - -#endif /* PNG_1_0_X */ - -#ifndef PNG_1_0_X -/* png.c, pnggccrd.c, or pngvcrd.c */ -extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); -#endif /* PNG_1_0_X */ -#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ - -/* Strip the prepended error numbers ("#nnn ") from error and warning - * messages before passing them to the error or warning handler. - */ -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp - png_ptr, png_uint_32 strip_mode)); -#endif - -/* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp - png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); -extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp - png_ptr)); -extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp - png_ptr)); -#endif -/* Maintainer: Put new public prototypes here ^, in libpng.3, and in - * project defs - */ - -#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED -/* With these routines we avoid an integer divide, which will be slower on - * most machines. However, it does take more operations than the corresponding - * divide method, so it may be slower on a few RISC systems. There are two - * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. - * - * Note that the rounding factors are NOT supposed to be the same! 128 and - * 32768 are correct for the NODIV code; 127 and 32767 are correct for the - * standard method. - * - * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] - */ - - /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ - -# define png_composite(composite, fg, alpha, bg) \ - { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ - + (png_uint_16)(bg)*(png_uint_16)(255 - \ - (png_uint_16)(alpha)) + (png_uint_16)128); \ - (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } - -# define png_composite_16(composite, fg, alpha, bg) \ - { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ - + (png_uint_32)(bg)*(png_uint_32)(65535L - \ - (png_uint_32)(alpha)) + (png_uint_32)32768L); \ - (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } - -#else /* Standard method using integer division */ - -# define png_composite(composite, fg, alpha, bg) \ - (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ - (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ - (png_uint_16)127) / 255) - -# define png_composite_16(composite, fg, alpha, bg) \ - (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ - (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ - (png_uint_32)32767) / (png_uint_32)65535L) - -#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ - -/* Inline macros to do direct reads of bytes from the input buffer. These - * require that you are using an architecture that uses PNG byte ordering - * (MSB first) and supports unaligned data storage. I think that PowerPC - * in big-endian mode and 680x0 are the only ones that will support this. - * The x86 line of processors definitely do not. The png_get_int_32() - * routine also assumes we are using two's complement format for negative - * values, which is almost certainly true. - */ -#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED -# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) -# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) -# define png_get_int_32(buf) ( *((png_int_32p) (buf))) -#else -extern PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf)); -extern PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf)); -extern PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf)); -#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ -extern PNG_EXPORT(png_uint_32,png_get_uint_31) - PNGARG((png_structp png_ptr, png_bytep buf)); -/* No png_get_int_16 -- may be added if there's a real need for it. */ - -/* Place a 32-bit number into a buffer in PNG byte order (big-endian). - */ -extern PNG_EXPORT(void,png_save_uint_32) - PNGARG((png_bytep buf, png_uint_32 i)); -extern PNG_EXPORT(void,png_save_int_32) - PNGARG((png_bytep buf, png_int_32 i)); - -/* Place a 16-bit number into a buffer in PNG byte order. - * The parameter is declared unsigned int, not png_uint_16, - * just to avoid potential problems on pre-ANSI C compilers. - */ -extern PNG_EXPORT(void,png_save_uint_16) - PNGARG((png_bytep buf, unsigned int i)); -/* No png_save_int_16 -- may be added if there's a real need for it. */ - -/* ************************************************************************* */ - -/* These next functions are used internally in the code. They generally - * shouldn't be used unless you are writing code to add or replace some - * functionality in libpng. More information about most functions can - * be found in the files where the functions are located. - */ - - -/* Various modes of operation, that are visible to applications because - * they are used for unknown chunk location. - */ -#define PNG_HAVE_IHDR 0x01 -#define PNG_HAVE_PLTE 0x02 -#define PNG_HAVE_IDAT 0x04 -#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ -#define PNG_HAVE_IEND 0x10 - -#ifdef PNG_INTERNAL - -/* More modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. - */ -#define PNG_HAVE_gAMA 0x20 -#define PNG_HAVE_cHRM 0x40 -#define PNG_HAVE_sRGB 0x80 -#define PNG_HAVE_CHUNK_HEADER 0x100 -#define PNG_WROTE_tIME 0x200 -#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 -#define PNG_BACKGROUND_IS_GRAY 0x800 -#define PNG_HAVE_PNG_SIGNATURE 0x1000 -#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ - -/* Flags for the transformations the PNG library does on the image data */ -#define PNG_BGR 0x0001 -#define PNG_INTERLACE 0x0002 -#define PNG_PACK 0x0004 -#define PNG_SHIFT 0x0008 -#define PNG_SWAP_BYTES 0x0010 -#define PNG_INVERT_MONO 0x0020 -#define PNG_DITHER 0x0040 -#define PNG_BACKGROUND 0x0080 -#define PNG_BACKGROUND_EXPAND 0x0100 - /* 0x0200 unused */ -#define PNG_16_TO_8 0x0400 -#define PNG_RGBA 0x0800 -#define PNG_EXPAND 0x1000 -#define PNG_GAMMA 0x2000 -#define PNG_GRAY_TO_RGB 0x4000 -#define PNG_FILLER 0x8000L -#define PNG_PACKSWAP 0x10000L -#define PNG_SWAP_ALPHA 0x20000L -#define PNG_STRIP_ALPHA 0x40000L -#define PNG_INVERT_ALPHA 0x80000L -#define PNG_USER_TRANSFORM 0x100000L -#define PNG_RGB_TO_GRAY_ERR 0x200000L -#define PNG_RGB_TO_GRAY_WARN 0x400000L -#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ - /* 0x800000L Unused */ -#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ -#define PNG_PREMULTIPLY_ALPHA 0x4000000L /* Added to libpng-1.2.41 */ - /* by volker */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - -/* Flags for png_create_struct */ -#define PNG_STRUCT_PNG 0x0001 -#define PNG_STRUCT_INFO 0x0002 - -/* Scaling factor for filter heuristic weighting calculations */ -#define PNG_WEIGHT_SHIFT 8 -#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) -#define PNG_COST_SHIFT 3 -#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) - -/* Flags for the png_ptr->flags rather than declaring a byte for each one */ -#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 -#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 -#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 -#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 -#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 -#define PNG_FLAG_ZLIB_FINISHED 0x0020 -#define PNG_FLAG_ROW_INIT 0x0040 -#define PNG_FLAG_FILLER_AFTER 0x0080 -#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 -#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 -#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 -#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 -#define PNG_FLAG_FREE_PLTE 0x1000 -#define PNG_FLAG_FREE_TRNS 0x2000 -#define PNG_FLAG_FREE_HIST 0x4000 -#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L -#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L -#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L -#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L -#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L -#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L -#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ - /* 0x800000L unused */ - /* 0x1000000L unused */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - -#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ - PNG_FLAG_CRC_ANCILLARY_NOWARN) - -#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ - PNG_FLAG_CRC_CRITICAL_IGNORE) - -#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ - PNG_FLAG_CRC_CRITICAL_MASK) - -/* Save typing and make code easier to understand */ - -#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ - abs((int)((c1).green) - (int)((c2).green)) + \ - abs((int)((c1).blue) - (int)((c2).blue))) - -/* Added to libpng-1.2.6 JB */ -#define PNG_ROWBYTES(pixel_bits, width) \ - ((pixel_bits) >= 8 ? \ - ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \ - (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) ) - -/* PNG_OUT_OF_RANGE returns true if value is outside the range - * ideal-delta..ideal+delta. Each argument is evaluated twice. - * "ideal" and "delta" should be constants, normally simple - * integers, "value" a variable. Added to libpng-1.2.6 JB - */ -#define PNG_OUT_OF_RANGE(value, ideal, delta) \ - ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) - -/* Variables declared in png.c - only it needs to define PNG_NO_EXTERN */ -#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) -/* Place to hold the signature string for a PNG file. */ -#ifdef PNG_USE_GLOBAL_ARRAYS - PNG_EXPORT_VAR (PNG_CONST png_byte FARDATA) png_sig[8]; -#else -#endif -#endif /* PNG_NO_EXTERN */ - -/* Constant strings for known chunk types. If you need to add a chunk, - * define the name here, and add an invocation of the macro in png.c and - * wherever it's needed. - */ -#define PNG_IHDR png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} -#define PNG_IDAT png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} -#define PNG_IEND png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} -#define PNG_PLTE png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} -#define PNG_bKGD png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} -#define PNG_cHRM png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} -#define PNG_gAMA png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} -#define PNG_hIST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} -#define PNG_iCCP png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} -#define PNG_iTXt png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} -#define PNG_oFFs png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} -#define PNG_pCAL png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} -#define PNG_sCAL png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} -#define PNG_pHYs png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} -#define PNG_sBIT png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} -#define PNG_sPLT png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} -#define PNG_sRGB png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} -#define PNG_tEXt png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} -#define PNG_tIME png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} -#define PNG_tRNS png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} -#define PNG_zTXt png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} - -#ifdef PNG_USE_GLOBAL_ARRAYS -PNG_EXPORT_VAR (png_byte FARDATA) png_IHDR[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_IDAT[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_IEND[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_PLTE[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_bKGD[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_cHRM[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_gAMA[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_hIST[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_iCCP[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_iTXt[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_oFFs[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_pCAL[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sCAL[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_pHYs[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sBIT[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sPLT[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sRGB[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_tEXt[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_tIME[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_tRNS[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_zTXt[5]; -#endif /* PNG_USE_GLOBAL_ARRAYS */ - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Initialize png_ptr struct for reading, and allocate any other memory. - * (old interface - DEPRECATED - use png_create_read_struct instead). - */ -extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)) - PNG_DEPRECATED; -#undef png_read_init -#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ - PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); -#endif - -extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size)); -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t - png_info_size)); -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Initialize png_ptr struct for writing, and allocate any other memory. - * (old interface - DEPRECATED - use png_create_write_struct instead). - */ -extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)) - PNG_DEPRECATED; -#undef png_write_init -#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ - PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); -#endif - -extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size)); -extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t - png_info_size)); - -/* Allocate memory for an internal libpng struct */ -PNG_EXTERN png_voidp png_create_struct PNGARG((int type)) PNG_PRIVATE; - -/* Free memory from internal libpng struct */ -PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)) PNG_PRIVATE; - -PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr - malloc_fn, png_voidp mem_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, - png_free_ptr free_fn, png_voidp mem_ptr)) PNG_PRIVATE; - -/* Free any memory that info_ptr points to and reset struct. */ -PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; - -#ifndef PNG_1_0_X -/* Function to allocate memory for zlib. */ -PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, - uInt size)) PNG_PRIVATE; - -/* Function to free memory for zlib */ -PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)) PNG_PRIVATE; - -#ifdef PNG_SIZE_T -/* Function to convert a sizeof an item to png_sizeof item */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)) - PNG_PRIVATE; -#endif - -/* Next four functions are used internally as callbacks. PNGAPI is required - * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. - */ - -PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)) PNG_PRIVATE; - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)) PNG_PRIVATE; -#endif - -PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)) PNG_PRIVATE; - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -#ifdef PNG_STDIO_SUPPORTED -PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)) - PNG_PRIVATE; -#endif -#endif -#else /* PNG_1_0_X */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)) PNG_PRIVATE; -#endif -#endif /* PNG_1_0_X */ - -/* Reset the CRC variable */ -PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -/* Write the "data" buffer to whatever output you are using. */ -PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)) PNG_PRIVATE; - -/* Read data from whatever input you are using into the "data" buffer */ -PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)) PNG_PRIVATE; - -/* Read bytes into buf, and update png_ptr->crc */ -PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, - png_size_t length)) PNG_PRIVATE; - -/* Decompress data in a chunk that uses compression */ -#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ - defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) -PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, - int comp_type, png_size_t chunklength, - png_size_t prefix_length, png_size_t *data_length)) PNG_PRIVATE; -#endif - -/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ -PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip) - PNG_PRIVATE); - -/* Read the CRC from the file and compare it to the libpng calculated CRC */ -PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -/* Calculate the CRC over a section of data. Note that we are only - * passing a maximum of 64K on systems that have this as a memory limit, - * since this is the maximum buffer size we can specify. - */ -PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, - png_size_t length)) PNG_PRIVATE; - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)) PNG_PRIVATE; -#endif - -/* Simple function to write the signature */ -PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -/* Write various chunks */ - -/* Write the IHDR chunk, and update the png_struct with the necessary - * information. - */ -PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, - png_uint_32 height, - int bit_depth, int color_type, int compression_method, int filter_method, - int interlace_method)) PNG_PRIVATE; - -PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, - png_uint_32 num_pal)) PNG_PRIVATE; - -PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)) PNG_PRIVATE; - -PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -#ifdef PNG_WRITE_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)) - PNG_PRIVATE; -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, - png_fixed_point file_gamma)) PNG_PRIVATE; -#endif -#endif - -#ifdef PNG_WRITE_sBIT_SUPPORTED -PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, - int color_type)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, - double white_x, double white_y, - double red_x, double red_y, double green_x, double green_y, - double blue_x, double blue_y)) PNG_PRIVATE; -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)) PNG_PRIVATE; -#endif -#endif - -#ifdef PNG_WRITE_sRGB_SUPPORTED -PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, - int intent)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_iCCP_SUPPORTED -PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, - png_charp name, int compression_type, - png_charp profile, int proflen)) PNG_PRIVATE; - /* Note to maintainer: profile should be png_bytep */ -#endif - -#ifdef PNG_WRITE_sPLT_SUPPORTED -PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_sPLT_tp palette)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_tRNS_SUPPORTED -PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, - png_color_16p values, int number, int color_type)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_bKGD_SUPPORTED -PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, - png_color_16p values, int color_type)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_hIST_SUPPORTED -PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, - int num_hist)) PNG_PRIVATE; -#endif - -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, - png_charp key, png_charpp new_key)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_tEXt_SUPPORTED -PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_zTXt_SUPPORTED -PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len, int compression)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_iTXt_SUPPORTED -PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, - int compression, png_charp key, png_charp lang, png_charp lang_key, - png_charp text)) PNG_PRIVATE; -#endif - -#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ -PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_oFFs_SUPPORTED -PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_pCAL_SUPPORTED -PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, - png_int_32 X0, png_int_32 X1, int type, int nparams, - png_charp units, png_charpp params)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_pHYs_SUPPORTED -PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, - png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, - int unit_type)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_tIME_SUPPORTED -PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, - png_timep mod_time)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_sCAL_SUPPORTED -#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) -PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, - int unit, double width, double height)) PNG_PRIVATE; -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, - int unit, png_charp width, png_charp height)) PNG_PRIVATE; -#endif -#endif -#endif - -/* Called when finished processing a row of data */ -PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -/* Internal use only. Called before first row of data */ -PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)) PNG_PRIVATE; -#endif - -/* Combine a row of data, dealing with alpha, etc. if requested */ -PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, - int mask)) PNG_PRIVATE; - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* Expand an interlaced row */ -/* OLD pre-1.0.9 interface: -PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass, png_uint_32 transformations)) PNG_PRIVATE; - */ -PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)) PNG_PRIVATE; -#endif - -/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED -/* Grab pixels out of a row for an interlaced pass */ -PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass)) PNG_PRIVATE; -#endif - -/* Unfilter a row */ -PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, - png_row_infop row_info, png_bytep row, png_bytep prev_row, - int filter)) PNG_PRIVATE; - -/* Choose the best filter to use and filter the row data */ -PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, - png_row_infop row_info)) PNG_PRIVATE; - -/* Write out the filtered row. */ -PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, - png_bytep filtered_row)) PNG_PRIVATE; -/* Finish a row while reading, dealing with interlacing passes, etc. */ -PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); - -/* Initialize the row buffers, etc. */ -PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; -/* Optional call to update the users info structure */ -PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; - -/* These are the functions that do the transformations */ -#ifdef PNG_READ_FILLER_SUPPORTED -PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 filler, png_uint_32 flags)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ - defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 flags)) PNG_PRIVATE; -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) -PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop - row_info, png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_PACK_SUPPORTED -PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p sig_bits)) PNG_PRIVATE; -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_16_TO_8_SUPPORTED -PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED -PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, - png_bytep row, png_bytep palette_lookup, - png_bytep dither_lookup)) PNG_PRIVATE; - -# ifdef PNG_CORRECT_PALETTE_SUPPORTED -PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette)) PNG_PRIVATE; -# endif -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED -PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 bit_depth)) PNG_PRIVATE; -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED -PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p bit_depth)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background, - png_color_16p background_1, - png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, - png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, - png_uint_16pp gamma_16_to_1, int gamma_shift)) PNG_PRIVATE; -#else -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background)) PNG_PRIVATE; -#endif -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, - png_bytep gamma_table, png_uint_16pp gamma_16_table, - int gamma_shift)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, - png_bytep row, png_colorp palette, png_bytep trans, - int num_trans)) PNG_PRIVATE; -PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, - png_bytep row, png_color_16p trans_value)) PNG_PRIVATE; -#endif - -/* The following decodes the appropriate chunks, and does error correction, - * then calls the appropriate callback for the chunk if it is valid. - */ - -/* Decode the IHDR chunk */ -PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); - -#ifdef PNG_READ_bKGD_SUPPORTED -PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_cHRM_SUPPORTED -PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_gAMA_SUPPORTED -PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_hIST_SUPPORTED -PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_iCCP_SUPPORTED -extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#ifdef PNG_READ_iTXt_SUPPORTED -PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_oFFs_SUPPORTED -PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED -PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_pHYs_SUPPORTED -PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_sBIT_SUPPORTED -PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_sCAL_SUPPORTED -PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_sPLT_SUPPORTED -extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#ifdef PNG_READ_sRGB_SUPPORTED -PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_tEXt_SUPPORTED -PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_tIME_SUPPORTED -PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_tRNS_SUPPORTED -PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -#ifdef PNG_READ_zTXt_SUPPORTED -PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)) PNG_PRIVATE; -#endif - -PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; - -PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, - png_bytep chunk_name)) PNG_PRIVATE; - -/* Handle the transformations for reading and writing */ -PNG_EXTERN void png_do_read_transformations - PNGARG((png_structp png_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_do_write_transformations - PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -PNG_EXTERN void png_init_read_transformations - PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, - png_uint_32 length)) PNG_PRIVATE; -PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)) PNG_PRIVATE; -PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)) PNG_PRIVATE; -PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; -PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, - png_bytep row)) PNG_PRIVATE; -PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -PNG_EXTERN void png_read_push_finish_row - PNGARG((png_structp png_ptr)) PNG_PRIVATE; -#ifdef PNG_READ_tEXt_SUPPORTED -PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; -PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED -PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; -PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED -PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; -PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)) PNG_PRIVATE; -#endif - -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)) PNG_PRIVATE; -#endif - -#ifdef PNG_ASSEMBLER_CODE_SUPPORTED -#ifdef PNG_MMX_CODE_SUPPORTED -/* png.c */ /* PRIVATE */ -PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)) PNG_PRIVATE; -#endif -#endif - - -/* The following six functions will be exported in libpng-1.4.0. */ -#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) -PNG_EXTERN png_uint_32 png_get_pixels_per_inch PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN png_uint_32 png_get_x_pixels_per_inch PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN png_uint_32 png_get_y_pixels_per_inch PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN float png_get_x_offset_inches PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN float png_get_y_offset_inches PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#ifdef PNG_pHYs_SUPPORTED -PNG_EXTERN png_uint_32 png_get_pHYs_dpi PNGARG((png_structp png_ptr, -png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ - -/* Read the chunk header (length + type name) */ -PNG_EXTERN png_uint_32 png_read_chunk_header - PNGARG((png_structp png_ptr)) PNG_PRIVATE; - -/* Added at libpng version 1.2.34 */ -#ifdef PNG_cHRM_SUPPORTED -PNG_EXTERN int png_check_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)) PNG_PRIVATE; -#endif - -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_CHECK_cHRM_SUPPORTED -/* Added at libpng version 1.2.34 */ -PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2, - unsigned long *hi_product, unsigned long *lo_product)) PNG_PRIVATE; -#endif -#endif - -/* Added at libpng version 1.2.41 */ -PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type)) PNG_PRIVATE; - -/* Added at libpng version 1.2.41 */ -PNG_EXTERN png_voidp png_calloc PNGARG((png_structp png_ptr, - png_uint_32 size)); - -/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -#endif /* PNG_INTERNAL */ - -#ifdef __cplusplus -} -#endif - -#endif /* PNG_VERSION_INFO_ONLY */ -/* Do not put anything past this line */ -#endif /* PNG_H */ +/* png.h - header file for PNG reference library + * + * libpng version 1.2.51 - February 6, 2014 + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license (See LICENSE, below) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.2.51 - February 6, 2014: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 10.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 10.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 10.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + * 1.2.9beta4-11 13 10209 12.so.0.9[.0] + * 1.2.9rc1 13 10209 12.so.0.9[.0] + * 1.2.9 13 10209 12.so.0.9[.0] + * 1.2.10beta1-8 13 10210 12.so.0.10[.0] + * 1.2.10rc1-3 13 10210 12.so.0.10[.0] + * 1.2.10 13 10210 12.so.0.10[.0] + * 1.2.11beta1-4 13 10211 12.so.0.11[.0] + * 1.0.19rc1-5 10 10019 10.so.0.19[.0] + * 1.2.11rc1-5 13 10211 12.so.0.11[.0] + * 1.0.19 10 10019 10.so.0.19[.0] + * 1.2.11 13 10211 12.so.0.11[.0] + * 1.0.20 10 10020 10.so.0.20[.0] + * 1.2.12 13 10212 12.so.0.12[.0] + * 1.2.13beta1 13 10213 12.so.0.13[.0] + * 1.0.21 10 10021 10.so.0.21[.0] + * 1.2.13 13 10213 12.so.0.13[.0] + * 1.2.14beta1-2 13 10214 12.so.0.14[.0] + * 1.0.22rc1 10 10022 10.so.0.22[.0] + * 1.2.14rc1 13 10214 12.so.0.14[.0] + * 1.0.22 10 10022 10.so.0.22[.0] + * 1.2.14 13 10214 12.so.0.14[.0] + * 1.2.15beta1-6 13 10215 12.so.0.15[.0] + * 1.0.23rc1-5 10 10023 10.so.0.23[.0] + * 1.2.15rc1-5 13 10215 12.so.0.15[.0] + * 1.0.23 10 10023 10.so.0.23[.0] + * 1.2.15 13 10215 12.so.0.15[.0] + * 1.2.16beta1-2 13 10216 12.so.0.16[.0] + * 1.2.16rc1 13 10216 12.so.0.16[.0] + * 1.0.24 10 10024 10.so.0.24[.0] + * 1.2.16 13 10216 12.so.0.16[.0] + * 1.2.17beta1-2 13 10217 12.so.0.17[.0] + * 1.0.25rc1 10 10025 10.so.0.25[.0] + * 1.2.17rc1-3 13 10217 12.so.0.17[.0] + * 1.0.25 10 10025 10.so.0.25[.0] + * 1.2.17 13 10217 12.so.0.17[.0] + * 1.0.26 10 10026 10.so.0.26[.0] + * 1.2.18 13 10218 12.so.0.18[.0] + * 1.2.19beta1-31 13 10219 12.so.0.19[.0] + * 1.0.27rc1-6 10 10027 10.so.0.27[.0] + * 1.2.19rc1-6 13 10219 12.so.0.19[.0] + * 1.0.27 10 10027 10.so.0.27[.0] + * 1.2.19 13 10219 12.so.0.19[.0] + * 1.2.20beta01-04 13 10220 12.so.0.20[.0] + * 1.0.28rc1-6 10 10028 10.so.0.28[.0] + * 1.2.20rc1-6 13 10220 12.so.0.20[.0] + * 1.0.28 10 10028 10.so.0.28[.0] + * 1.2.20 13 10220 12.so.0.20[.0] + * 1.2.21beta1-2 13 10221 12.so.0.21[.0] + * 1.2.21rc1-3 13 10221 12.so.0.21[.0] + * 1.0.29 10 10029 10.so.0.29[.0] + * 1.2.21 13 10221 12.so.0.21[.0] + * 1.2.22beta1-4 13 10222 12.so.0.22[.0] + * 1.0.30rc1 10 10030 10.so.0.30[.0] + * 1.2.22rc1 13 10222 12.so.0.22[.0] + * 1.0.30 10 10030 10.so.0.30[.0] + * 1.2.22 13 10222 12.so.0.22[.0] + * 1.2.23beta01-05 13 10223 12.so.0.23[.0] + * 1.2.23rc01 13 10223 12.so.0.23[.0] + * 1.2.23 13 10223 12.so.0.23[.0] + * 1.2.24beta01-02 13 10224 12.so.0.24[.0] + * 1.2.24rc01 13 10224 12.so.0.24[.0] + * 1.2.24 13 10224 12.so.0.24[.0] + * 1.2.25beta01-06 13 10225 12.so.0.25[.0] + * 1.2.25rc01-02 13 10225 12.so.0.25[.0] + * 1.0.31 10 10031 10.so.0.31[.0] + * 1.2.25 13 10225 12.so.0.25[.0] + * 1.2.26beta01-06 13 10226 12.so.0.26[.0] + * 1.2.26rc01 13 10226 12.so.0.26[.0] + * 1.2.26 13 10226 12.so.0.26[.0] + * 1.0.32 10 10032 10.so.0.32[.0] + * 1.2.27beta01-06 13 10227 12.so.0.27[.0] + * 1.2.27rc01 13 10227 12.so.0.27[.0] + * 1.0.33 10 10033 10.so.0.33[.0] + * 1.2.27 13 10227 12.so.0.27[.0] + * 1.0.34 10 10034 10.so.0.34[.0] + * 1.2.28 13 10228 12.so.0.28[.0] + * 1.2.29beta01-03 13 10229 12.so.0.29[.0] + * 1.2.29rc01 13 10229 12.so.0.29[.0] + * 1.0.35 10 10035 10.so.0.35[.0] + * 1.2.29 13 10229 12.so.0.29[.0] + * 1.0.37 10 10037 10.so.0.37[.0] + * 1.2.30beta01-04 13 10230 12.so.0.30[.0] + * 1.0.38rc01-08 10 10038 10.so.0.38[.0] + * 1.2.30rc01-08 13 10230 12.so.0.30[.0] + * 1.0.38 10 10038 10.so.0.38[.0] + * 1.2.30 13 10230 12.so.0.30[.0] + * 1.0.39rc01-03 10 10039 10.so.0.39[.0] + * 1.2.31rc01-03 13 10231 12.so.0.31[.0] + * 1.0.39 10 10039 10.so.0.39[.0] + * 1.2.31 13 10231 12.so.0.31[.0] + * 1.2.32beta01-02 13 10232 12.so.0.32[.0] + * 1.0.40rc01 10 10040 10.so.0.40[.0] + * 1.2.32rc01 13 10232 12.so.0.32[.0] + * 1.0.40 10 10040 10.so.0.40[.0] + * 1.2.32 13 10232 12.so.0.32[.0] + * 1.2.33beta01-02 13 10233 12.so.0.33[.0] + * 1.2.33rc01-02 13 10233 12.so.0.33[.0] + * 1.0.41rc01 10 10041 10.so.0.41[.0] + * 1.2.33 13 10233 12.so.0.33[.0] + * 1.0.41 10 10041 10.so.0.41[.0] + * 1.2.34beta01-07 13 10234 12.so.0.34[.0] + * 1.0.42rc01 10 10042 10.so.0.42[.0] + * 1.2.34rc01 13 10234 12.so.0.34[.0] + * 1.0.42 10 10042 10.so.0.42[.0] + * 1.2.34 13 10234 12.so.0.34[.0] + * 1.2.35beta01-03 13 10235 12.so.0.35[.0] + * 1.0.43rc01-02 10 10043 10.so.0.43[.0] + * 1.2.35rc01-02 13 10235 12.so.0.35[.0] + * 1.0.43 10 10043 10.so.0.43[.0] + * 1.2.35 13 10235 12.so.0.35[.0] + * 1.2.36beta01-05 13 10236 12.so.0.36[.0] + * 1.2.36rc01 13 10236 12.so.0.36[.0] + * 1.0.44 10 10044 10.so.0.44[.0] + * 1.2.36 13 10236 12.so.0.36[.0] + * 1.2.37beta01-03 13 10237 12.so.0.37[.0] + * 1.2.37rc01 13 10237 12.so.0.37[.0] + * 1.2.37 13 10237 12.so.0.37[.0] + * 1.0.45 10 10045 12.so.0.45[.0] + * 1.0.46 10 10046 10.so.0.46[.0] + * 1.2.38beta01 13 10238 12.so.0.38[.0] + * 1.2.38rc01-03 13 10238 12.so.0.38[.0] + * 1.0.47 10 10047 10.so.0.47[.0] + * 1.2.38 13 10238 12.so.0.38[.0] + * 1.2.39beta01-05 13 10239 12.so.0.39[.0] + * 1.2.39rc01 13 10239 12.so.0.39[.0] + * 1.0.48 10 10048 10.so.0.48[.0] + * 1.2.39 13 10239 12.so.0.39[.0] + * 1.2.40beta01 13 10240 12.so.0.40[.0] + * 1.2.40rc01 13 10240 12.so.0.40[.0] + * 1.0.49 10 10049 10.so.0.49[.0] + * 1.2.40 13 10240 12.so.0.40[.0] + * 1.2.41beta01-18 13 10241 12.so.0.41[.0] + * 1.0.51rc01 10 10051 10.so.0.51[.0] + * 1.2.41rc01-03 13 10241 12.so.0.41[.0] + * 1.0.51 10 10051 10.so.0.51[.0] + * 1.2.41 13 10241 12.so.0.41[.0] + * 1.2.42beta01-02 13 10242 12.so.0.42[.0] + * 1.2.42rc01-05 13 10242 12.so.0.42[.0] + * 1.0.52 10 10052 10.so.0.52[.0] + * 1.2.42 13 10242 12.so.0.42[.0] + * 1.2.43beta01-05 13 10243 12.so.0.43[.0] + * 1.0.53rc01-02 10 10053 10.so.0.53[.0] + * 1.2.43rc01-02 13 10243 12.so.0.43[.0] + * 1.0.53 10 10053 10.so.0.53[.0] + * 1.2.43 13 10243 12.so.0.43[.0] + * 1.2.44beta01-03 13 10244 12.so.0.44[.0] + * 1.2.44rc01-03 13 10244 12.so.0.44[.0] + * 1.2.44 13 10244 12.so.0.44[.0] + * 1.2.45beta01-03 13 10245 12.so.0.45[.0] + * 1.0.55rc01 10 10055 10.so.0.55[.0] + * 1.2.45rc01 13 10245 12.so.0.45[.0] + * 1.0.55 10 10055 10.so.0.55[.0] + * 1.2.45 13 10245 12.so.0.45[.0] + * 1.2.46rc01-02 13 10246 12.so.0.46[.0] + * 1.0.56 10 10056 10.so.0.56[.0] + * 1.2.46 13 10246 12.so.0.46[.0] + * 1.2.47beta01 13 10247 12.so.0.47[.0] + * 1.2.47rc01 13 10247 12.so.0.47[.0] + * 1.0.57rc01 10 10057 10.so.0.57[.0] + * 1.2.47 13 10247 12.so.0.47[.0] + * 1.0.57 10 10057 10.so.0.57[.0] + * 1.2.48beta01 13 10248 12.so.0.48[.0] + * 1.2.48rc01-02 13 10248 12.so.0.48[.0] + * 1.0.58 10 10058 10.so.0.58[.0] + * 1.2.48 13 10248 12.so.0.48[.0] + * 1.2.49rc01 13 10249 12.so.0.49[.0] + * 1.0.59 10 10059 10.so.0.59[.0] + * 1.2.49 13 10249 12.so.0.49[.0] + * 1.0.60 10 10060 10.so.0.60[.0] + * 1.2.50 13 10250 12.so.0.50[.0] + * 1.2.51beta01-05 13 10251 12.so.0.51[.0] + * 1.2.51rc01-04 13 10251 12.so.0.51[.0] + * 1.0.61 10 10061 10.so.0.61[.0] + * 1.2.51 13 10251 12.so.0.51[.0] + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcNN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as a W3C Recommendation and as an ISO Specification, + * defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_uint_32 rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. + */ +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only, deprecated */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE 0x0800 /* write only */ +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.2.41 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application, except to store + * the jmp_buf. + */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmpbuf; /* used in png_error */ +#endif + png_error_ptr error_fn PNG_DEPSTRUCT; /* function for printing errors and aborting */ + png_error_ptr warning_fn PNG_DEPSTRUCT; /* function for printing warnings */ + png_voidp error_ptr PNG_DEPSTRUCT; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn PNG_DEPSTRUCT; /* function for writing output data */ + png_rw_ptr read_data_fn PNG_DEPSTRUCT; /* function for reading input data */ + png_voidp io_ptr PNG_DEPSTRUCT; /* ptr to application struct for I/O functions */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn PNG_DEPSTRUCT; /* user read transform */ +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr write_user_transform_fn PNG_DEPSTRUCT; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr PNG_DEPSTRUCT; /* user supplied struct for user transform */ + png_byte user_transform_depth PNG_DEPSTRUCT; /* bit depth of user transformed pixels */ + png_byte user_transform_channels PNG_DEPSTRUCT; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode PNG_DEPSTRUCT; /* tells us where we are in the PNG file */ + png_uint_32 flags PNG_DEPSTRUCT; /* flags indicating various things to libpng */ + png_uint_32 transformations PNG_DEPSTRUCT; /* which transformations to perform */ + + z_stream zstream PNG_DEPSTRUCT; /* pointer to decompression structure (below) */ + png_bytep zbuf PNG_DEPSTRUCT; /* buffer for zlib */ + png_size_t zbuf_size PNG_DEPSTRUCT; /* size of zbuf */ + int zlib_level PNG_DEPSTRUCT; /* holds zlib compression level */ + int zlib_method PNG_DEPSTRUCT; /* holds zlib compression method */ + int zlib_window_bits PNG_DEPSTRUCT; /* holds zlib compression window bits */ + int zlib_mem_level PNG_DEPSTRUCT; /* holds zlib compression memory level */ + int zlib_strategy PNG_DEPSTRUCT; /* holds zlib compression strategy */ + + png_uint_32 width PNG_DEPSTRUCT; /* width of image in pixels */ + png_uint_32 height PNG_DEPSTRUCT; /* height of image in pixels */ + png_uint_32 num_rows PNG_DEPSTRUCT; /* number of rows in current pass */ + png_uint_32 usr_width PNG_DEPSTRUCT; /* width of row at start of write */ + png_uint_32 rowbytes PNG_DEPSTRUCT; /* size of row in bytes */ +#if 0 /* Replaced with the following in libpng-1.2.43 */ + png_size_t irowbytes PNG_DEPSTRUCT; +#endif +/* Added in libpng-1.2.43 */ +#ifdef PNG_USER_LIMITS_SUPPORTED + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max PNG_DEPSTRUCT; +#endif + png_uint_32 iwidth PNG_DEPSTRUCT; /* width of current interlaced row in pixels */ + png_uint_32 row_number PNG_DEPSTRUCT; /* current row in interlace pass */ + png_bytep prev_row PNG_DEPSTRUCT; /* buffer to save previous (unfiltered) row */ + png_bytep row_buf PNG_DEPSTRUCT; /* buffer to save current (unfiltered) row */ +#ifndef PNG_NO_WRITE_FILTER + png_bytep sub_row PNG_DEPSTRUCT; /* buffer to save "sub" row when filtering */ + png_bytep up_row PNG_DEPSTRUCT; /* buffer to save "up" row when filtering */ + png_bytep avg_row PNG_DEPSTRUCT; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row PNG_DEPSTRUCT; /* buffer to save "Paeth" row when filtering */ +#endif + png_row_info row_info PNG_DEPSTRUCT; /* used for transformation routines */ + + png_uint_32 idat_size PNG_DEPSTRUCT; /* current IDAT size for read */ + png_uint_32 crc PNG_DEPSTRUCT; /* current chunk CRC value */ + png_colorp palette PNG_DEPSTRUCT; /* palette from the input file */ + png_uint_16 num_palette PNG_DEPSTRUCT; /* number of color entries in palette */ + png_uint_16 num_trans PNG_DEPSTRUCT; /* number of transparency values */ + png_byte chunk_name[5] PNG_DEPSTRUCT; /* null-terminated name of current chunk */ + png_byte compression PNG_DEPSTRUCT; /* file compression type (always 0) */ + png_byte filter PNG_DEPSTRUCT; /* file filter type (always 0) */ + png_byte interlaced PNG_DEPSTRUCT; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass PNG_DEPSTRUCT; /* current interlace pass (0 - 6) */ + png_byte do_filter PNG_DEPSTRUCT; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type PNG_DEPSTRUCT; /* color type of file */ + png_byte bit_depth PNG_DEPSTRUCT; /* bit depth of file */ + png_byte usr_bit_depth PNG_DEPSTRUCT; /* bit depth of users row */ + png_byte pixel_depth PNG_DEPSTRUCT; /* number of bits per pixel */ + png_byte channels PNG_DEPSTRUCT; /* number of channels in file */ + png_byte usr_channels PNG_DEPSTRUCT; /* channels at start of write */ + png_byte sig_bytes PNG_DEPSTRUCT; /* magic bytes read/written from start of file */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +#ifdef PNG_LEGACY_SUPPORTED + png_byte filler PNG_DEPSTRUCT; /* filler byte for pixel expansion */ +#else + png_uint_16 filler PNG_DEPSTRUCT; /* filler bytes for pixel expansion */ +#endif +#endif + +#ifdef PNG_bKGD_SUPPORTED + png_byte background_gamma_type PNG_DEPSTRUCT; +# ifdef PNG_FLOATING_POINT_SUPPORTED + float background_gamma PNG_DEPSTRUCT; +# endif + png_color_16 background PNG_DEPSTRUCT; /* background color in screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1 PNG_DEPSTRUCT; /* background normalized to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_flush_ptr output_flush_fn PNG_DEPSTRUCT; /* Function for flushing output */ + png_uint_32 flush_dist PNG_DEPSTRUCT; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows PNG_DEPSTRUCT; /* number of rows written since last flush */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + int gamma_shift PNG_DEPSTRUCT; /* number of "insignificant" bits 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float gamma PNG_DEPSTRUCT; /* file gamma value */ + float screen_gamma PNG_DEPSTRUCT; /* screen gamma value (display_exponent) */ +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table PNG_DEPSTRUCT; /* gamma table for 8-bit depth files */ + png_bytep gamma_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to screen */ + png_bytep gamma_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table PNG_DEPSTRUCT; /* gamma table for 16-bit depth files */ + png_uint_16pp gamma_16_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit PNG_DEPSTRUCT; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift PNG_DEPSTRUCT; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans PNG_DEPSTRUCT; /* transparency values for paletted files */ + png_color_16 trans_values PNG_DEPSTRUCT; /* transparency values for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn PNG_DEPSTRUCT; /* called after each row is decoded */ + png_write_status_ptr write_row_fn PNG_DEPSTRUCT; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn PNG_DEPSTRUCT; /* called after header data fully read */ + png_progressive_row_ptr row_fn PNG_DEPSTRUCT; /* called after each prog. row is decoded */ + png_progressive_end_ptr end_fn PNG_DEPSTRUCT; /* called after image is complete */ + png_bytep save_buffer_ptr PNG_DEPSTRUCT; /* current location in save_buffer */ + png_bytep save_buffer PNG_DEPSTRUCT; /* buffer for previously read data */ + png_bytep current_buffer_ptr PNG_DEPSTRUCT; /* current location in current_buffer */ + png_bytep current_buffer PNG_DEPSTRUCT; /* buffer for recently used data */ + png_uint_32 push_length PNG_DEPSTRUCT; /* size of current input chunk */ + png_uint_32 skip_length PNG_DEPSTRUCT; /* bytes to skip in input data */ + png_size_t save_buffer_size PNG_DEPSTRUCT; /* amount of data now in save_buffer */ + png_size_t save_buffer_max PNG_DEPSTRUCT; /* total size of save_buffer */ + png_size_t buffer_size PNG_DEPSTRUCT; /* total amount of available input data */ + png_size_t current_buffer_size PNG_DEPSTRUCT; /* amount of data now in current_buffer */ + int process_mode PNG_DEPSTRUCT; /* what push library is currently doing */ + int cur_palette PNG_DEPSTRUCT; /* current push library palette index */ + +# ifdef PNG_TEXT_SUPPORTED + png_size_t current_text_size PNG_DEPSTRUCT; /* current size of text input data */ + png_size_t current_text_left PNG_DEPSTRUCT; /* how much text left to read in input */ + png_charp current_text PNG_DEPSTRUCT; /* current text chunk buffer */ + png_charp current_text_ptr PNG_DEPSTRUCT; /* current location in current_text */ +# endif /* PNG_TEXT_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* for the Borland special 64K segment handler */ + png_bytepp offset_table_ptr PNG_DEPSTRUCT; + png_bytep offset_table PNG_DEPSTRUCT; + png_uint_16 offset_table_number PNG_DEPSTRUCT; + png_uint_16 offset_table_count PNG_DEPSTRUCT; + png_uint_16 offset_table_count_free PNG_DEPSTRUCT; +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED + png_bytep palette_lookup PNG_DEPSTRUCT; /* lookup table for dithering */ + png_bytep dither_index PNG_DEPSTRUCT; /* index translation for palette files */ +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) + png_uint_16p hist PNG_DEPSTRUCT; /* histogram */ +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_byte heuristic_method PNG_DEPSTRUCT; /* heuristic for row filter selection */ + png_byte num_prev_filters PNG_DEPSTRUCT; /* number of weights for previous rows */ + png_bytep prev_filters PNG_DEPSTRUCT; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights PNG_DEPSTRUCT; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights PNG_DEPSTRUCT; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs PNG_DEPSTRUCT; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs PNG_DEPSTRUCT; /* 1/relative filter calculation cost */ +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + png_charp time_buffer PNG_DEPSTRUCT; /* String to hold RFC 1123 time text */ +#endif + +/* New members added in libpng-1.0.6 */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me PNG_DEPSTRUCT; /* flags items libpng is responsible for freeing */ +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr PNG_DEPSTRUCT; + png_user_chunk_ptr read_user_chunk_fn PNG_DEPSTRUCT; /* user read chunk handler */ +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int num_chunk_list PNG_DEPSTRUCT; + png_bytep chunk_list PNG_DEPSTRUCT; +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status PNG_DEPSTRUCT; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff PNG_DEPSTRUCT; + png_uint_16 rgb_to_gray_green_coeff PNG_DEPSTRUCT; + png_uint_16 rgb_to_gray_blue_coeff PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ +#ifdef PNG_1_0_X + png_byte mng_features_permitted PNG_DEPSTRUCT; +#else + png_uint_32 mng_features_permitted PNG_DEPSTRUCT; +#endif /* PNG_1_0_X */ +#endif + +/* New member added in libpng-1.0.7 */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_fixed_point int_gamma PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type PNG_DEPSTRUCT; +#endif + +#ifdef PNG_1_0_X +/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ + png_uint_32 row_buf_size PNG_DEPSTRUCT; +#endif + +/* New members added in libpng-1.2.0 */ +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +# ifndef PNG_1_0_X +# ifdef PNG_MMX_CODE_SUPPORTED + png_byte mmx_bitdepth_threshold PNG_DEPSTRUCT; + png_uint_32 mmx_rowbytes_threshold PNG_DEPSTRUCT; +# endif + png_uint_32 asm_flags PNG_DEPSTRUCT; +# endif +#endif + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr PNG_DEPSTRUCT; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn PNG_DEPSTRUCT; /* function for allocating memory */ + png_free_ptr free_fn PNG_DEPSTRUCT; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf PNG_DEPSTRUCT; /* buffer to save current (unfiltered) row */ + +#ifdef PNG_READ_DITHER_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep dither_sort PNG_DEPSTRUCT; /* working sort array */ + png_bytep index_to_palette PNG_DEPSTRUCT; /* where the original index currently is */ + /* in the palette */ + png_bytep palette_to_index PNG_DEPSTRUCT; /* which original index points to this */ + /* palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type PNG_DEPSTRUCT; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max PNG_DEPSTRUCT; + png_uint_32 user_height_max PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunk that the library doesn't recognize. */ + png_unknown_chunk unknown_chunk PNG_DEPSTRUCT; +#endif + +/* New members added in libpng-1.2.26 */ + png_uint_32 old_big_row_buf_size PNG_DEPSTRUCT; + png_uint_32 old_prev_row_size PNG_DEPSTRUCT; + +/* New member added in libpng-1.2.30 */ + png_charp chunkdata PNG_DEPSTRUCT; /* buffer for reading chunk data */ + + +}; + + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef png_structp version_1_2_51; + +typedef png_struct FAR * FAR * png_structpp; + +/* Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + */ + +/* Returns the version number of the library */ +extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)) PNG_DEPRECATED; + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +extern PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)) PNG_ALLOCATED; + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +extern PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)) PNG_ALLOCATED; + +#ifdef PNG_WRITE_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_WRITE_SUPPORTED +extern PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_uint_32 size)); +#endif + +/* Reset the compression stream */ +extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)) PNG_ALLOCATED; +extern PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)) PNG_ALLOCATED; +#endif + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +extern PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)) PNG_ALLOCATED; + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +/* Initialize the info structure (old interface - DEPRECATED) */ +extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)) + PNG_DEPRECATED; +#undef png_info_init +#define png_info_init(info_ptr) png_info_init_3(&info_ptr,\ + png_sizeof(png_info)); +#endif + +extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_CONVERT_tIME_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +#ifndef PNG_1_0_X +extern PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp + png_ptr)); +#endif +extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +/* Deprecated */ +extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp + png_ptr)) PNG_DEPRECATED; +#endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); +#endif +extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); +#endif + +extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +#define PNG_FILLER_BEFORE 0 +#define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +#ifndef PNG_1_0_X +extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +#endif +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. */ +extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +#endif +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +/* Strip the second byte of information from a 16-bit depth file. */ +extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED +/* Turn on dithering, and reduce the palette to the number of colors available. */ +extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_dither)); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); +#endif +#endif + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ +/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ +extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, + int empty_plte_permitted)) PNG_DEPRECATED; +#endif +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); + +/* Optional call to update the users info structure */ +extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); +#endif + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); +#endif + +/* Write a row of image data */ +extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); + +/* Write a few rows of image data */ +extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); + +/* Write the image data */ +extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* Writes the end of the PNG file. */ +extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free all memory used by the read (old method - NOT DLL EXPORTED) */ +extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)) PNG_DEPRECATED; + +/* Free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); + +/* Free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ +extern void png_write_destroy PNGARG((png_structp png_ptr)) PNG_DEPRECATED; + +/* Set the libpng method of handling chunk CRC errors */ +extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() to say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); +#endif +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); + +extern PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); + +extern PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); + +extern PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); + +extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); + +/* Function to be called when data becomes available */ +extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* Function that combines rows. Not very much different than the + * png_combine_row() call. Is this even used????? + */ +extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)) PNG_ALLOCATED; + +#ifdef PNG_1_0_X +# define png_malloc_warn png_malloc +#else +/* Added at libpng version 1.2.4 */ +extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, + png_uint_32 size)) PNG_ALLOCATED; +#endif + +/* Frees a pointer allocated by png_malloc() */ +extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); + +#ifdef PNG_1_0_X +/* Function to allocate memory for zlib. */ +extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, + uInt size)); + +/* Function to free memory for zlib */ +extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); +#endif + +/* Free data that was allocated internally */ +extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); +#ifdef PNG_FREE_ME_SUPPORTED +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application + */ +extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); +#endif +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_uint_32 size)) PNG_ALLOCATED; +extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); +#endif + +extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, + png_voidp s1, png_voidp s2, png_uint_32 size)) PNG_DEPRECATED; + +extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, + png_voidp s1, int value, png_uint_32 size)) PNG_DEPRECATED; + +#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ +extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ + +#ifndef PNG_NO_ERROR_TEXT +/* Fatal error in PNG image of libpng - can't continue */ +extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)) PNG_NORETURN; + +/* The same, but the chunk name is prepended to the error string. */ +extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)) PNG_NORETURN; +#else +/* Fatal error in PNG image of libpng - can't continue */ +extern PNG_EXPORT(void,png_err) PNGARG((png_structp png_ptr)) PNG_NORETURN; +#endif + +#ifndef PNG_NO_WARNINGS +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +#ifdef PNG_READ_SUPPORTED +/* Non-fatal error in libpng, chunk name is prepended to message. */ +extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); +#endif /* PNG_READ_SUPPORTED */ +#endif /* PNG_NO_WARNINGS */ + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image height in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image bit_depth. */ +extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image color_type. */ +extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image filter_type. */ +extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image interlace_type. */ +extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image compression_type. */ +extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +#endif + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_bKGD_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); +#endif +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +#endif +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#ifdef PNG_hIST_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); +#endif + +#ifdef PNG_hIST_SUPPORTED +extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); + +extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ +#endif + +#ifdef PNG_iCCP_SUPPORTED +extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#ifdef PNG_sPLT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* + * Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans, int *num_trans, + png_color_16p *trans_values)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans, int num_trans, + png_color_16p trans_values)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +#endif + +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED */ + +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +/* Provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. + keep = 0: follow default behaviour + = 1: do not keep + = 2: keep only if safe-to-copy + = 3: keep even if unsafe-to-copy +*/ +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep + chunk_name)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +#endif + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + */ +#ifdef PNG_DEBUG +#if (PNG_DEBUG > 0) +#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +#include +#if (PNG_DEBUG > 1) +#ifndef _DEBUG +# define _DEBUG +#endif +#ifndef png_debug +#define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +#endif +#ifndef png_debug1 +#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +#endif +#ifndef png_debug2 +#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +#endif +#endif +#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#ifndef PNG_DEBUG_FILE +#define PNG_DEBUG_FILE stderr +#endif /* PNG_DEBUG_FILE */ + +#if (PNG_DEBUG > 1) +/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on non-ISO + * compilers. + */ +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ + } +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ + } +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ + } +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } +# endif +# endif /* __STDC __ */ +#endif /* (PNG_DEBUG > 1) */ + +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +#define png_debug(l, m) +#endif +#ifndef png_debug1 +#define png_debug1(l, m, p1) +#endif +#ifndef png_debug2 +#define png_debug2(l, m, p1, p2) +#endif + +extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 + +/* Added to version 1.2.0 */ +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +#ifdef PNG_MMX_CODE_SUPPORTED +#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 +#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 +#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 +#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 +#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 +#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 +#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ + +#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_INTERLACE \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ) +#define PNG_MMX_WRITE_FLAGS ( 0 ) + +#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \ + | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \ + | PNG_MMX_READ_FLAGS \ + | PNG_MMX_WRITE_FLAGS ) + +#define PNG_SELECT_READ 1 +#define PNG_SELECT_WRITE 2 +#endif /* PNG_MMX_CODE_SUPPORTED */ + +#ifndef PNG_1_0_X +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) + PNGARG((int flag_select, int *compilerID)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) + PNGARG((int flag_select)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flags) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) + PNGARG((png_structp png_ptr)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_asm_flags) + PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_mmx_thresholds) + PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold)); + +#endif /* PNG_1_0_X */ + +#ifndef PNG_1_0_X +/* png.c, pnggccrd.c, or pngvcrd.c */ +extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); +#endif /* PNG_1_0_X */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); +#endif + +/* Added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp + png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); +extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp + png_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp + png_ptr)); +#endif +/* Maintainer: Put new public prototypes here ^, in libpng.3, and in + * project defs + */ + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 - \ + (png_uint_16)(alpha)) + (png_uint_16)128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(png_uint_32)(65535L - \ + (png_uint_32)(alpha)) + (png_uint_32)32768L); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + (png_uint_16)127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ + (png_uint_32)32767) / (png_uint_32)65535L) + +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +/* Inline macros to do direct reads of bytes from the input buffer. These + * require that you are using an architecture that uses PNG byte ordering + * (MSB first) and supports unaligned data storage. I think that PowerPC + * in big-endian mode and 680x0 are the only ones that will support this. + * The x86 line of processors definitely do not. The png_get_int_32() + * routine also assumes we are using two's complement format for negative + * values, which is almost certainly true. + */ +#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED +# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) +# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) +# define png_get_int_32(buf) ( *((png_int_32p) (buf))) +#else +extern PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf)); +extern PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf)); +extern PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf)); +#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ +extern PNG_EXPORT(png_uint_32,png_get_uint_31) + PNGARG((png_structp png_ptr, png_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). + */ +extern PNG_EXPORT(void,png_save_uint_32) + PNGARG((png_bytep buf, png_uint_32 i)); +extern PNG_EXPORT(void,png_save_int_32) + PNGARG((png_bytep buf, png_int_32 i)); + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +extern PNG_EXPORT(void,png_save_uint_16) + PNGARG((png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ + +/* ************************************************************************* */ + +/* These next functions are used internally in the code. They generally + * shouldn't be used unless you are writing code to add or replace some + * functionality in libpng. More information about most functions can + * be found in the files where the functions are located. + */ + + +/* Various modes of operation, that are visible to applications because + * they are used for unknown chunk location. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ +#define PNG_HAVE_IEND 0x10 + +#ifdef PNG_INTERNAL + +/* More modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 +#define PNG_HAVE_sRGB 0x80 +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + +/* Flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_DITHER 0x0040 +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 + /* 0x0200 unused */ +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000L +#define PNG_PACKSWAP 0x10000L +#define PNG_SWAP_ALPHA 0x20000L +#define PNG_STRIP_ALPHA 0x40000L +#define PNG_INVERT_ALPHA 0x80000L +#define PNG_USER_TRANSFORM 0x100000L +#define PNG_RGB_TO_GRAY_ERR 0x200000L +#define PNG_RGB_TO_GRAY_WARN 0x400000L +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + /* 0x800000L Unused */ +#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ +#define PNG_PREMULTIPLY_ALPHA 0x4000000L /* Added to libpng-1.2.41 */ + /* by volker */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ + +/* Flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_SHIFT 8 +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_SHIFT 3 +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* Flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 +#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_FREE_PLTE 0x1000 +#define PNG_FLAG_FREE_TRNS 0x2000 +#define PNG_FLAG_FREE_HIST 0x4000 +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L +#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L +#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ +#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ + /* 0x800000L unused */ + /* 0x1000000L unused */ + /* 0x2000000L unused */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* Save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \ + (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + * ideal-delta..ideal+delta. Each argument is evaluated twice. + * "ideal" and "delta" should be constants, normally simple + * integers, "value" a variable. Added to libpng-1.2.6 JB + */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* Variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* Place to hold the signature string for a PNG file. */ +#ifdef PNG_USE_GLOBAL_ARRAYS + PNG_EXPORT_VAR (PNG_CONST png_byte FARDATA) png_sig[8]; +#else +#endif +#endif /* PNG_NO_EXTERN */ + +/* Constant strings for known chunk types. If you need to add a chunk, + * define the name here, and add an invocation of the macro in png.c and + * wherever it's needed. + */ +#define PNG_IHDR png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} +#define PNG_IDAT png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} +#define PNG_IEND png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} +#define PNG_PLTE png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} +#define PNG_bKGD png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} +#define PNG_cHRM png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} +#define PNG_gAMA png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} +#define PNG_hIST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} +#define PNG_iCCP png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} +#define PNG_iTXt png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} +#define PNG_oFFs png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} +#define PNG_pCAL png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} +#define PNG_sCAL png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} +#define PNG_pHYs png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} +#define PNG_sBIT png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} +#define PNG_sPLT png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} +#define PNG_sRGB png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} +#define PNG_tEXt png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} +#define PNG_tIME png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} +#define PNG_tRNS png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} +#define PNG_zTXt png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} + +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (png_byte FARDATA) png_IHDR[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_IDAT[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_IEND[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_PLTE[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_bKGD[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_cHRM[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_gAMA[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_hIST[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_iCCP[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_iTXt[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_oFFs[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_pCAL[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_sCAL[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_pHYs[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_sBIT[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_sPLT[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_sRGB[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_tEXt[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_tIME[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_tRNS[5]; +PNG_EXPORT_VAR (png_byte FARDATA) png_zTXt[5]; +#endif /* PNG_USE_GLOBAL_ARRAYS */ + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +/* Initialize png_ptr struct for reading, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_read_struct instead). + */ +extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)) + PNG_DEPRECATED; +#undef png_read_init +#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); +#endif + +extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); +#endif + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +/* Initialize png_ptr struct for writing, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_write_struct instead). + */ +extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)) + PNG_DEPRECATED; +#undef png_write_init +#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); +#endif + +extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Allocate memory for an internal libpng struct */ +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)) PNG_PRIVATE; + +/* Free memory from internal libpng struct */ +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)) PNG_PRIVATE; + +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)) PNG_PRIVATE; + +/* Free any memory that info_ptr points to and reset struct. */ +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; + +#ifndef PNG_1_0_X +/* Function to allocate memory for zlib. */ +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, + uInt size)) PNG_PRIVATE; + +/* Function to free memory for zlib */ +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)) PNG_PRIVATE; + +#ifdef PNG_SIZE_T +/* Function to convert a sizeof an item to png_sizeof item */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)) + PNG_PRIVATE; +#endif + +/* Next four functions are used internally as callbacks. PNGAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. + */ + +PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)) PNG_PRIVATE; + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)) PNG_PRIVATE; +#endif + +PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)) PNG_PRIVATE; + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED +PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)) + PNG_PRIVATE; +#endif +#endif +#else /* PNG_1_0_X */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)) PNG_PRIVATE; +#endif +#endif /* PNG_1_0_X */ + +/* Reset the CRC variable */ +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +/* Write the "data" buffer to whatever output you are using. */ +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)) PNG_PRIVATE; + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)) PNG_PRIVATE; + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)) PNG_PRIVATE; + +/* Decompress data in a chunk that uses compression */ +#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_size_t chunklength, + png_size_t prefix_length, png_size_t *data_length)) PNG_PRIVATE; +#endif + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip) + PNG_PRIVATE); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)) PNG_PRIVATE; + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)) PNG_PRIVATE; +#endif + +/* Simple function to write the signature */ +PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +/* Write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)) PNG_PRIVATE; + +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)) PNG_PRIVATE; + +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)) PNG_PRIVATE; + +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +#ifdef PNG_WRITE_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)) + PNG_PRIVATE; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, + png_fixed_point file_gamma)) PNG_PRIVATE; +#endif +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)) PNG_PRIVATE; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) PNG_PRIVATE; +#endif +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)) PNG_PRIVATE; + /* Note to maintainer: profile should be png_bytep */ +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)) PNG_PRIVATE; +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)) PNG_PRIVATE; +#endif + +#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ +PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)) PNG_PRIVATE; +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)) PNG_PRIVATE; +#endif +#endif +#endif + +/* Called when finished processing a row of data */ +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +/* Internal use only. Called before first row of data */ +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)) PNG_PRIVATE; +#endif + +/* Combine a row of data, dealing with alpha, etc. if requested */ +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)) PNG_PRIVATE; + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Expand an interlaced row */ +/* OLD pre-1.0.9 interface: +PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations)) PNG_PRIVATE; + */ +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)) PNG_PRIVATE; +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Grab pixels out of a row for an interlaced pass */ +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)) PNG_PRIVATE; +#endif + +/* Unfilter a row */ +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, + int filter)) PNG_PRIVATE; + +/* Choose the best filter to use and filter the row data */ +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)) PNG_PRIVATE; + +/* Write out the filtered row. */ +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)) PNG_PRIVATE; +/* Finish a row while reading, dealing with interlacing passes, etc. */ +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); + +/* Initialize the row buffers, etc. */ +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; +/* Optional call to update the users info structure */ +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; + +/* These are the functions that do the transformations */ +#ifdef PNG_READ_FILLER_SUPPORTED +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)) PNG_PRIVATE; +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_PACK_SUPPORTED +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)) PNG_PRIVATE; +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED +PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, + png_bytep dither_lookup)) PNG_PRIVATE; + +# ifdef PNG_CORRECT_PALETTE_SUPPORTED +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)) PNG_PRIVATE; +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)) PNG_PRIVATE; +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)) PNG_PRIVATE; +#else +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background)) PNG_PRIVATE; +#endif +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, + int num_trans)) PNG_PRIVATE; +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)) PNG_PRIVATE; +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* Decode the IHDR chunk */ +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); + +#ifdef PNG_READ_bKGD_SUPPORTED +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED +extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED +extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_sRGB_SUPPORTED +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)) PNG_PRIVATE; +#endif + +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; + +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)) PNG_PRIVATE; + +/* Handle the transformations for reading and writing */ +PNG_EXTERN void png_do_read_transformations + PNGARG((png_structp png_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_do_write_transformations + PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +PNG_EXTERN void png_init_read_transformations + PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)) PNG_PRIVATE; +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)) PNG_PRIVATE; +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)) PNG_PRIVATE; +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, + png_bytep row)) PNG_PRIVATE; +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +PNG_EXTERN void png_read_push_finish_row + PNGARG((png_structp png_ptr)) PNG_PRIVATE; +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)) PNG_PRIVATE; +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)) PNG_PRIVATE; +#endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)) PNG_PRIVATE; +#endif + +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +#ifdef PNG_MMX_CODE_SUPPORTED +/* png.c */ /* PRIVATE */ +PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)) PNG_PRIVATE; +#endif +#endif + + +/* The following six functions will be exported in libpng-1.4.0. */ +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) +PNG_EXTERN png_uint_32 png_get_pixels_per_inch PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXTERN png_uint_32 png_get_x_pixels_per_inch PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXTERN png_uint_32 png_get_y_pixels_per_inch PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXTERN float png_get_x_offset_inches PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXTERN float png_get_y_offset_inches PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXTERN png_uint_32 png_get_pHYs_dpi PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ + +/* Read the chunk header (length + type name) */ +PNG_EXTERN png_uint_32 png_read_chunk_header + PNGARG((png_structp png_ptr)) PNG_PRIVATE; + +/* Added at libpng version 1.2.34 */ +#ifdef PNG_cHRM_SUPPORTED +PNG_EXTERN int png_check_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) PNG_PRIVATE; +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_CHECK_cHRM_SUPPORTED +/* Added at libpng version 1.2.34 */ +PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2, + unsigned long *hi_product, unsigned long *lo_product)) PNG_PRIVATE; +#endif +#endif + +/* Added at libpng version 1.2.41 */ +PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type)) PNG_PRIVATE; + +/* Added at libpng version 1.2.41 */ +PNG_EXTERN png_voidp png_calloc PNGARG((png_structp png_ptr, + png_uint_32 size)); + +/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +#endif /* PNG_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/main/source/includes/lpng1251/pngconf.h b/main/source/includes/lpng1251/pngconf.h index 9c7705e3..de6e8e29 100644 --- a/main/source/includes/lpng1251/pngconf.h +++ b/main/source/includes/lpng1251/pngconf.h @@ -1,1677 +1,1677 @@ - -/* pngconf.h - machine configurable file for libpng - * - * libpng version 1.2.51 - February 6, 2014 - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -/* Any machine specific code is near the front of this file, so if you - * are configuring libpng for a machine, you may want to read the section - * starting here down to where it starts to typedef png_color, png_text, - * and png_info. - */ - -#ifndef PNGCONF_H -#define PNGCONF_H - -#define PNG_1_2_X - -/* - * PNG_USER_CONFIG has to be defined on the compiler command line. This - * includes the resource compiler for Windows DLL configurations. - */ -#ifdef PNG_USER_CONFIG -# ifndef PNG_USER_PRIVATEBUILD -# define PNG_USER_PRIVATEBUILD -# endif -#include "pngusr.h" -#endif - -/* PNG_CONFIGURE_LIBPNG is set by the "configure" script. */ -#ifdef PNG_CONFIGURE_LIBPNG -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#endif - -/* - * Added at libpng-1.2.8 - * - * If you create a private DLL you need to define in "pngusr.h" the followings: - * #define PNG_USER_PRIVATEBUILD - * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." - * #define PNG_USER_DLLFNAME_POSTFIX - * e.g. // private DLL "libpng13gx.dll" - * #define PNG_USER_DLLFNAME_POSTFIX "gx" - * - * The following macros are also at your disposal if you want to complete the - * DLL VERSIONINFO structure. - * - PNG_USER_VERSIONINFO_COMMENTS - * - PNG_USER_VERSIONINFO_COMPANYNAME - * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS - */ - -#ifdef __STDC__ -#ifdef SPECIALBUILD -# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ - are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") -#endif - -#ifdef PRIVATEBUILD -# pragma message("PRIVATEBUILD is deprecated.\ - Use PNG_USER_PRIVATEBUILD instead.") -# define PNG_USER_PRIVATEBUILD PRIVATEBUILD -#endif -#endif /* __STDC__ */ - -#ifndef PNG_VERSION_INFO_ONLY - -/* End of material added to libpng-1.2.8 */ - -/* Added at libpng-1.2.19, removed at libpng-1.2.20 because it caused trouble - Restored at libpng-1.2.21 */ -#if !defined(PNG_NO_WARN_UNINITIALIZED_ROW) && \ - !defined(PNG_WARN_UNINITIALIZED_ROW) -# define PNG_WARN_UNINITIALIZED_ROW 1 -#endif -/* End of material added at libpng-1.2.19/1.2.21 */ - -/* Added at libpng-1.2.51 (ported from 1.4.6) */ -#ifndef PNG_UNUSED -/* Unused formal parameter warnings are silenced using the following macro - * which is expected to have no bad effects on performance (optimizing - * compilers will probably remove it entirely). Note that if you replace - * it with something other than whitespace, you must include the terminating - * semicolon. - */ -# define PNG_UNUSED(param) (void)param; -#endif -/* End of material added to libpng-1.4.6 */ - -/* This is the size of the compression buffer, and thus the size of - * an IDAT chunk. Make this whatever size you feel is best for your - * machine. One of these will be allocated per png_struct. When this - * is full, it writes the data to the disk, and does some other - * calculations. Making this an extremely small size will slow - * the library down, but you may want to experiment to determine - * where it becomes significant, if you are concerned with memory - * usage. Note that zlib allocates at least 32Kb also. For readers, - * this describes the size of the buffer available to read the data in. - * Unless this gets smaller than the size of a row (compressed), - * it should not make much difference how big this is. - */ - -#ifndef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 8192 -#endif - -/* Enable if you want a write-only libpng */ - -#ifndef PNG_NO_READ_SUPPORTED -# define PNG_READ_SUPPORTED -#endif - -/* Enable if you want a read-only libpng */ - -#ifndef PNG_NO_WRITE_SUPPORTED -# define PNG_WRITE_SUPPORTED -#endif - -/* Enabled in 1.2.41. */ -#ifdef PNG_ALLOW_BENIGN_ERRORS -# define png_benign_error png_warning -# define png_chunk_benign_error png_chunk_warning -#else -# ifndef PNG_BENIGN_ERRORS_SUPPORTED -# define png_benign_error png_error -# define png_chunk_benign_error png_chunk_error -# endif -#endif - -/* Added in libpng-1.2.41 */ -#if !defined(PNG_NO_WARNINGS) && !defined(PNG_WARNINGS_SUPPORTED) -# define PNG_WARNINGS_SUPPORTED -#endif - -#if !defined(PNG_NO_ERROR_TEXT) && !defined(PNG_ERROR_TEXT_SUPPORTED) -# define PNG_ERROR_TEXT_SUPPORTED -#endif - -#if !defined(PNG_NO_CHECK_cHRM) && !defined(PNG_CHECK_cHRM_SUPPORTED) -# define PNG_CHECK_cHRM_SUPPORTED -#endif - -/* Enabled by default in 1.2.0. You can disable this if you don't need to - * support PNGs that are embedded in MNG datastreams - */ -#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES) -# ifndef PNG_MNG_FEATURES_SUPPORTED -# define PNG_MNG_FEATURES_SUPPORTED -# endif -#endif - -#ifndef PNG_NO_FLOATING_POINT_SUPPORTED -# ifndef PNG_FLOATING_POINT_SUPPORTED -# define PNG_FLOATING_POINT_SUPPORTED -# endif -#endif - -/* If you are running on a machine where you cannot allocate more - * than 64K of memory at once, uncomment this. While libpng will not - * normally need that much memory in a chunk (unless you load up a very - * large file), zlib needs to know how big of a chunk it can use, and - * libpng thus makes sure to check any memory allocation to verify it - * will fit into memory. -#define PNG_MAX_MALLOC_64K - */ -#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) -# define PNG_MAX_MALLOC_64K -#endif - -/* Special munging to support doing things the 'cygwin' way: - * 'Normal' png-on-win32 defines/defaults: - * PNG_BUILD_DLL -- building dll - * PNG_USE_DLL -- building an application, linking to dll - * (no define) -- building static library, or building an - * application and linking to the static lib - * 'Cygwin' defines/defaults: - * PNG_BUILD_DLL -- (ignored) building the dll - * (no define) -- (ignored) building an application, linking to the dll - * PNG_STATIC -- (ignored) building the static lib, or building an - * application that links to the static lib. - * ALL_STATIC -- (ignored) building various static libs, or building an - * application that links to the static libs. - * Thus, - * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and - * this bit of #ifdefs will define the 'correct' config variables based on - * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but - * unnecessary. - * - * Also, the precedence order is: - * ALL_STATIC (since we can't #undef something outside our namespace) - * PNG_BUILD_DLL - * PNG_STATIC - * (nothing) == PNG_USE_DLL - * - * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent - * of auto-import in binutils, we no longer need to worry about - * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, - * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes - * to __declspec() stuff. However, we DO need to worry about - * PNG_BUILD_DLL and PNG_STATIC because those change some defaults - * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed. - */ -#ifdef __CYGWIN__ -# ifdef ALL_STATIC -# ifdef PNG_BUILD_DLL -# undef PNG_BUILD_DLL -# endif -# ifdef PNG_USE_DLL -# undef PNG_USE_DLL -# endif -# ifdef PNG_DLL -# undef PNG_DLL -# endif -# ifndef PNG_STATIC -# define PNG_STATIC -# endif -# else -# ifdef PNG_BUILD_DLL -# ifdef PNG_STATIC -# undef PNG_STATIC -# endif -# ifdef PNG_USE_DLL -# undef PNG_USE_DLL -# endif -# ifndef PNG_DLL -# define PNG_DLL -# endif -# else -# ifdef PNG_STATIC -# ifdef PNG_USE_DLL -# undef PNG_USE_DLL -# endif -# ifdef PNG_DLL -# undef PNG_DLL -# endif -# else -# ifndef PNG_USE_DLL -# define PNG_USE_DLL -# endif -# ifndef PNG_DLL -# define PNG_DLL -# endif -# endif -# endif -# endif -#endif - -/* This protects us against compilers that run on a windowing system - * and thus don't have or would rather us not use the stdio types: - * stdin, stdout, and stderr. The only one currently used is stderr - * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will - * prevent these from being compiled and used. #defining PNG_NO_STDIO - * will also prevent these, plus will prevent the entire set of stdio - * macros and functions (FILE *, printf, etc.) from being compiled and used, - * unless (PNG_DEBUG > 0) has been #defined. - * - * #define PNG_NO_CONSOLE_IO - * #define PNG_NO_STDIO - */ - -#if !defined(PNG_NO_STDIO) && !defined(PNG_STDIO_SUPPORTED) -# define PNG_STDIO_SUPPORTED -#endif - -#ifdef _WIN32_WCE -# include - /* Console I/O functions are not supported on WindowsCE */ -# define PNG_NO_CONSOLE_IO - /* abort() may not be supported on some/all Windows CE platforms */ -# define PNG_ABORT() exit(-1) -# ifdef PNG_DEBUG -# undef PNG_DEBUG -# endif -#endif - -#ifdef PNG_BUILD_DLL -# ifndef PNG_CONSOLE_IO_SUPPORTED -# ifndef PNG_NO_CONSOLE_IO -# define PNG_NO_CONSOLE_IO -# endif -# endif -#endif - -# ifdef PNG_NO_STDIO -# ifndef PNG_NO_CONSOLE_IO -# define PNG_NO_CONSOLE_IO -# endif -# ifdef PNG_DEBUG -# if (PNG_DEBUG > 0) -# include -# endif -# endif -# else -# ifndef _WIN32_WCE -/* "stdio.h" functions are not supported on WindowsCE */ -# include -# endif -# endif - -#if !(defined PNG_NO_CONSOLE_IO) && !defined(PNG_CONSOLE_IO_SUPPORTED) -# define PNG_CONSOLE_IO_SUPPORTED -#endif - -/* This macro protects us against machines that don't have function - * prototypes (ie K&R style headers). If your compiler does not handle - * function prototypes, define this macro and use the included ansi2knr. - * I've always been able to use _NO_PROTO as the indicator, but you may - * need to drag the empty declaration out in front of here, or change the - * ifdef to suit your own needs. - */ -#ifndef PNGARG - -#ifdef OF /* zlib prototype munger */ -# define PNGARG(arglist) OF(arglist) -#else - -#ifdef _NO_PROTO -# define PNGARG(arglist) () -# ifndef PNG_TYPECAST_NULL -# define PNG_TYPECAST_NULL -# endif -#else -# define PNGARG(arglist) arglist -#endif /* _NO_PROTO */ - - -#endif /* OF */ - -#endif /* PNGARG */ - -/* Try to determine if we are compiling on a Mac. Note that testing for - * just __MWERKS__ is not good enough, because the Codewarrior is now used - * on non-Mac platforms. - */ -#ifndef MACOS -# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ - defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) -# define MACOS -# endif -#endif - -/* enough people need this for various reasons to include it here */ -#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) -# include -#endif - -#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) -# define PNG_SETJMP_SUPPORTED -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* This is an attempt to force a single setjmp behaviour on Linux. If - * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. - * - * You can bypass this test if you know that your application uses exactly - * the same setjmp.h that was included when libpng was built. Only define - * PNG_SKIP_SETJMP_CHECK while building your application, prior to the - * application's '#include "png.h"'. Don't define PNG_SKIP_SETJMP_CHECK - * while building a separate libpng library for general use. - */ - -# ifndef PNG_SKIP_SETJMP_CHECK -# ifdef __linux__ -# ifdef _BSD_SOURCE -# define PNG_SAVE_BSD_SOURCE -# undef _BSD_SOURCE -# endif -# ifdef _SETJMP_H - /* If you encounter a compiler error here, see the explanation - * near the end of INSTALL. - */ - __pngconf.h__ in libpng already includes setjmp.h; - __dont__ include it again.; -# endif -# endif /* __linux__ */ -# endif /* PNG_SKIP_SETJMP_CHECK */ - - /* include setjmp.h for error handling */ -# include - -# ifdef __linux__ -# ifdef PNG_SAVE_BSD_SOURCE -# ifndef _BSD_SOURCE -# define _BSD_SOURCE -# endif -# undef PNG_SAVE_BSD_SOURCE -# endif -# endif /* __linux__ */ -#endif /* PNG_SETJMP_SUPPORTED */ - -#ifdef BSD -# include -#else -# include -#endif - -/* Other defines for things like memory and the like can go here. */ -#ifdef PNG_INTERNAL - -#include - -/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which - * aren't usually used outside the library (as far as I know), so it is - * debatable if they should be exported at all. In the future, when it is - * possible to have run-time registry of chunk-handling functions, some of - * these will be made available again. -#define PNG_EXTERN extern - */ -#define PNG_EXTERN - -/* Other defines specific to compilers can go here. Try to keep - * them inside an appropriate ifdef/endif pair for portability. - */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED -# ifdef MACOS - /* We need to check that hasn't already been included earlier - * as it seems it doesn't agree with , yet we should really use - * if possible. - */ -# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) -# include -# endif -# else -# include -# endif -# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) - /* Amiga SAS/C: We must include builtin FPU functions when compiling using - * MATH=68881 - */ -# include -# endif -#endif - -/* Codewarrior on NT has linking problems without this. */ -#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) -# define PNG_ALWAYS_EXTERN -#endif - -/* This provides the non-ANSI (far) memory allocation routines. */ -#if defined(__TURBOC__) && defined(__MSDOS__) -# include -# include -#endif - -/* I have no idea why is this necessary... */ -#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ - defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) -# include -#endif - -/* This controls how fine the dithering gets. As this allocates - * a largish chunk of memory (32K), those who are not as concerned - * with dithering quality can decrease some or all of these. - */ -#ifndef PNG_DITHER_RED_BITS -# define PNG_DITHER_RED_BITS 5 -#endif -#ifndef PNG_DITHER_GREEN_BITS -# define PNG_DITHER_GREEN_BITS 5 -#endif -#ifndef PNG_DITHER_BLUE_BITS -# define PNG_DITHER_BLUE_BITS 5 -#endif - -/* This controls how fine the gamma correction becomes when you - * are only interested in 8 bits anyway. Increasing this value - * results in more memory being used, and more pow() functions - * being called to fill in the gamma tables. Don't set this value - * less then 8, and even that may not work (I haven't tested it). - */ - -#ifndef PNG_MAX_GAMMA_8 -# define PNG_MAX_GAMMA_8 11 -#endif - -/* This controls how much a difference in gamma we can tolerate before - * we actually start doing gamma conversion. - */ -#ifndef PNG_GAMMA_THRESHOLD -# define PNG_GAMMA_THRESHOLD 0.05 -#endif - -#endif /* PNG_INTERNAL */ - -/* The following uses const char * instead of char * for error - * and warning message functions, so some compilers won't complain. - * If you do not want to use const, define PNG_NO_CONST here. - */ - -#ifndef PNG_NO_CONST -# define PNG_CONST const -#else -# define PNG_CONST -#endif - -/* The following defines give you the ability to remove code from the - * library that you will not be using. I wish I could figure out how to - * automate this, but I can't do that without making it seriously hard - * on the users. So if you are not using an ability, change the #define - * to and #undef, and that part of the library will not be compiled. If - * your linker can't find a function, you may want to make sure the - * ability is defined here. Some of these depend upon some others being - * defined. I haven't figured out all the interactions here, so you may - * have to experiment awhile to get everything to compile. If you are - * creating or using a shared library, you probably shouldn't touch this, - * as it will affect the size of the structures, and this will cause bad - * things to happen if the library and/or application ever change. - */ - -/* Any features you will not be using can be undef'ed here */ - -/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user - * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS - * on the compile line, then pick and choose which ones to define without - * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED - * if you only want to have a png-compliant reader/writer but don't need - * any of the extra transformations. This saves about 80 kbytes in a - * typical installation of the library. (PNG_NO_* form added in version - * 1.0.1c, for consistency) - */ - -/* The size of the png_text structure changed in libpng-1.0.6 when - * iTXt support was added. iTXt support was turned off by default through - * libpng-1.2.x, to support old apps that malloc the png_text structure - * instead of calling png_set_text() and letting libpng malloc it. It - * will be turned on by default in libpng-1.4.0. - */ - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -# ifndef PNG_NO_iTXt_SUPPORTED -# define PNG_NO_iTXt_SUPPORTED -# endif -# ifndef PNG_NO_READ_iTXt -# define PNG_NO_READ_iTXt -# endif -# ifndef PNG_NO_WRITE_iTXt -# define PNG_NO_WRITE_iTXt -# endif -#endif - -#if !defined(PNG_NO_iTXt_SUPPORTED) -# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt) -# define PNG_READ_iTXt -# endif -# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt) -# define PNG_WRITE_iTXt -# endif -#endif - -/* The following support, added after version 1.0.0, can be turned off here en - * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility - * with old applications that require the length of png_struct and png_info - * to remain unchanged. - */ - -#ifdef PNG_LEGACY_SUPPORTED -# define PNG_NO_FREE_ME -# define PNG_NO_READ_UNKNOWN_CHUNKS -# define PNG_NO_WRITE_UNKNOWN_CHUNKS -# define PNG_NO_HANDLE_AS_UNKNOWN -# define PNG_NO_READ_USER_CHUNKS -# define PNG_NO_READ_iCCP -# define PNG_NO_WRITE_iCCP -# define PNG_NO_READ_iTXt -# define PNG_NO_WRITE_iTXt -# define PNG_NO_READ_sCAL -# define PNG_NO_WRITE_sCAL -# define PNG_NO_READ_sPLT -# define PNG_NO_WRITE_sPLT -# define PNG_NO_INFO_IMAGE -# define PNG_NO_READ_RGB_TO_GRAY -# define PNG_NO_READ_USER_TRANSFORM -# define PNG_NO_WRITE_USER_TRANSFORM -# define PNG_NO_USER_MEM -# define PNG_NO_READ_EMPTY_PLTE -# define PNG_NO_MNG_FEATURES -# define PNG_NO_FIXED_POINT_SUPPORTED -#endif - -/* Ignore attempt to turn off both floating and fixed point support */ -#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ - !defined(PNG_NO_FIXED_POINT_SUPPORTED) -# define PNG_FIXED_POINT_SUPPORTED -#endif - -#ifndef PNG_NO_FREE_ME -# define PNG_FREE_ME_SUPPORTED -#endif - -#ifdef PNG_READ_SUPPORTED - -#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ - !defined(PNG_NO_READ_TRANSFORMS) -# define PNG_READ_TRANSFORMS_SUPPORTED -#endif - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -# ifndef PNG_NO_READ_EXPAND -# define PNG_READ_EXPAND_SUPPORTED -# endif -# ifndef PNG_NO_READ_SHIFT -# define PNG_READ_SHIFT_SUPPORTED -# endif -# ifndef PNG_NO_READ_PACK -# define PNG_READ_PACK_SUPPORTED -# endif -# ifndef PNG_NO_READ_BGR -# define PNG_READ_BGR_SUPPORTED -# endif -# ifndef PNG_NO_READ_SWAP -# define PNG_READ_SWAP_SUPPORTED -# endif -# ifndef PNG_NO_READ_PACKSWAP -# define PNG_READ_PACKSWAP_SUPPORTED -# endif -# ifndef PNG_NO_READ_INVERT -# define PNG_READ_INVERT_SUPPORTED -# endif -# ifndef PNG_NO_READ_DITHER -# define PNG_READ_DITHER_SUPPORTED -# endif -# ifndef PNG_NO_READ_BACKGROUND -# define PNG_READ_BACKGROUND_SUPPORTED -# endif -# ifndef PNG_NO_READ_16_TO_8 -# define PNG_READ_16_TO_8_SUPPORTED -# endif -# ifndef PNG_NO_READ_FILLER -# define PNG_READ_FILLER_SUPPORTED -# endif -# ifndef PNG_NO_READ_GAMMA -# define PNG_READ_GAMMA_SUPPORTED -# endif -# ifndef PNG_NO_READ_GRAY_TO_RGB -# define PNG_READ_GRAY_TO_RGB_SUPPORTED -# endif -# ifndef PNG_NO_READ_SWAP_ALPHA -# define PNG_READ_SWAP_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_READ_INVERT_ALPHA -# define PNG_READ_INVERT_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_READ_STRIP_ALPHA -# define PNG_READ_STRIP_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_READ_USER_TRANSFORM -# define PNG_READ_USER_TRANSFORM_SUPPORTED -# endif -# ifndef PNG_NO_READ_RGB_TO_GRAY -# define PNG_READ_RGB_TO_GRAY_SUPPORTED -# endif -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -/* PNG_PROGRESSIVE_READ_NOT_SUPPORTED is deprecated. */ -#if !defined(PNG_NO_PROGRESSIVE_READ) && \ - !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ -# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ -#endif /* about interlacing capability! You'll */ - /* still have interlacing unless you change the following define: */ -#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ - -/* PNG_NO_SEQUENTIAL_READ_SUPPORTED is deprecated. */ -#if !defined(PNG_NO_SEQUENTIAL_READ) && \ - !defined(PNG_SEQUENTIAL_READ_SUPPORTED) && \ - !defined(PNG_NO_SEQUENTIAL_READ_SUPPORTED) -# define PNG_SEQUENTIAL_READ_SUPPORTED -#endif - -#define PNG_READ_INTERLACING_SUPPORTED /* required in PNG-compliant decoders */ - -#ifndef PNG_NO_READ_COMPOSITE_NODIV -# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ -# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ -# endif -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Deprecated, will be removed from version 2.0.0. - Use PNG_MNG_FEATURES_SUPPORTED instead. */ -#ifndef PNG_NO_READ_EMPTY_PLTE -# define PNG_READ_EMPTY_PLTE_SUPPORTED -#endif -#endif - -#endif /* PNG_READ_SUPPORTED */ - -#ifdef PNG_WRITE_SUPPORTED - -# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ - !defined(PNG_NO_WRITE_TRANSFORMS) -# define PNG_WRITE_TRANSFORMS_SUPPORTED -#endif - -#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -# ifndef PNG_NO_WRITE_SHIFT -# define PNG_WRITE_SHIFT_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_PACK -# define PNG_WRITE_PACK_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_BGR -# define PNG_WRITE_BGR_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_SWAP -# define PNG_WRITE_SWAP_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_PACKSWAP -# define PNG_WRITE_PACKSWAP_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_INVERT -# define PNG_WRITE_INVERT_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_FILLER -# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ -# endif -# ifndef PNG_NO_WRITE_SWAP_ALPHA -# define PNG_WRITE_SWAP_ALPHA_SUPPORTED -# endif -#ifndef PNG_1_0_X -# ifndef PNG_NO_WRITE_INVERT_ALPHA -# define PNG_WRITE_INVERT_ALPHA_SUPPORTED -# endif -#endif -# ifndef PNG_NO_WRITE_USER_TRANSFORM -# define PNG_WRITE_USER_TRANSFORM_SUPPORTED -# endif -#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ - -#if !defined(PNG_NO_WRITE_INTERLACING_SUPPORTED) && \ - !defined(PNG_WRITE_INTERLACING_SUPPORTED) -#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant - encoders, but can cause trouble - if left undefined */ -#endif - -#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ - !defined(PNG_WRITE_WEIGHTED_FILTER) && \ - defined(PNG_FLOATING_POINT_SUPPORTED) -# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED -#endif - -#ifndef PNG_NO_WRITE_FLUSH -# define PNG_WRITE_FLUSH_SUPPORTED -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ -#ifndef PNG_NO_WRITE_EMPTY_PLTE -# define PNG_WRITE_EMPTY_PLTE_SUPPORTED -#endif -#endif - -#endif /* PNG_WRITE_SUPPORTED */ - -#ifndef PNG_1_0_X -# ifndef PNG_NO_ERROR_NUMBERS -# define PNG_ERROR_NUMBERS_SUPPORTED -# endif -#endif /* PNG_1_0_X */ - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -# ifndef PNG_NO_USER_TRANSFORM_PTR -# define PNG_USER_TRANSFORM_PTR_SUPPORTED -# endif -#endif - -#ifndef PNG_NO_STDIO -# define PNG_TIME_RFC1123_SUPPORTED -#endif - -/* This adds extra functions in pngget.c for accessing data from the - * info pointer (added in version 0.99) - * png_get_image_width() - * png_get_image_height() - * png_get_bit_depth() - * png_get_color_type() - * png_get_compression_type() - * png_get_filter_type() - * png_get_interlace_type() - * png_get_pixel_aspect_ratio() - * png_get_pixels_per_meter() - * png_get_x_offset_pixels() - * png_get_y_offset_pixels() - * png_get_x_offset_microns() - * png_get_y_offset_microns() - */ -#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) -# define PNG_EASY_ACCESS_SUPPORTED -#endif - -/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 - * and removed from version 1.2.20. The following will be removed - * from libpng-1.4.0 -*/ - -#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_OPTIMIZED_CODE) -# ifndef PNG_OPTIMIZED_CODE_SUPPORTED -# define PNG_OPTIMIZED_CODE_SUPPORTED -# endif -#endif - -#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) -# ifndef PNG_ASSEMBLER_CODE_SUPPORTED -# define PNG_ASSEMBLER_CODE_SUPPORTED -# endif - -# if defined(__GNUC__) && defined(__x86_64__) && (__GNUC__ < 4) - /* work around 64-bit gcc compiler bugs in gcc-3.x */ -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_NO_MMX_CODE -# endif -# endif - -# ifdef __APPLE__ -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_NO_MMX_CODE -# endif -# endif - -# if (defined(__MWERKS__) && ((__MWERKS__ < 0x0900) || macintosh)) -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_NO_MMX_CODE -# endif -# endif - -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_MMX_CODE_SUPPORTED -# endif - -#endif -/* end of obsolete code to be removed from libpng-1.4.0 */ - -/* Added at libpng-1.2.0 */ -#ifndef PNG_1_0_X -#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) -# define PNG_USER_MEM_SUPPORTED -#endif -#endif /* PNG_1_0_X */ - -/* Added at libpng-1.2.6 */ -#ifndef PNG_1_0_X -# ifndef PNG_SET_USER_LIMITS_SUPPORTED -# ifndef PNG_NO_SET_USER_LIMITS -# define PNG_SET_USER_LIMITS_SUPPORTED -# endif -# endif -#endif /* PNG_1_0_X */ - -/* Added at libpng-1.0.53 and 1.2.43 */ -#ifndef PNG_USER_LIMITS_SUPPORTED -# ifndef PNG_NO_USER_LIMITS -# define PNG_USER_LIMITS_SUPPORTED -# endif -#endif - -/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter - * how large, set these limits to 0x7fffffffL - */ -#ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000L -#endif -#ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000L -#endif - -/* Added at libpng-1.2.43. To accept all valid PNGs no matter - * how large, set these two limits to 0. - */ -#ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 32765 -#endif - -/* Added at libpng-1.2.43 */ -#ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 0 -#endif - -#ifndef PNG_LITERAL_SHARP -# define PNG_LITERAL_SHARP 0x23 -#endif -#ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET -# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b -#endif -#ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET -# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d -#endif - -/* Added at libpng-1.2.34 */ -#ifndef PNG_STRING_NEWLINE -#define PNG_STRING_NEWLINE "\n" -#endif - -/* These are currently experimental features, define them if you want */ - -/* very little testing */ -/* -#ifdef PNG_READ_SUPPORTED -# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED -# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED -# endif -#endif -*/ - -/* This is only for PowerPC big-endian and 680x0 systems */ -/* some testing */ -/* -#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED -# define PNG_READ_BIG_ENDIAN_SUPPORTED -#endif -*/ - -/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ -/* -#define PNG_NO_POINTER_INDEXING -*/ - -#if !defined(PNG_NO_POINTER_INDEXING) && \ - !defined(PNG_POINTER_INDEXING_SUPPORTED) -# define PNG_POINTER_INDEXING_SUPPORTED -#endif - -/* These functions are turned off by default, as they will be phased out. */ -/* -#define PNG_USELESS_TESTS_SUPPORTED -#define PNG_CORRECT_PALETTE_SUPPORTED -*/ - -/* Any chunks you are not interested in, you can undef here. The - * ones that allocate memory may be expecially important (hIST, - * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info - * a bit smaller. - */ - -#if defined(PNG_READ_SUPPORTED) && \ - !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ - !defined(PNG_NO_READ_ANCILLARY_CHUNKS) -# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED -#endif - -#if defined(PNG_WRITE_SUPPORTED) && \ - !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ - !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) -# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED -#endif - -#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED - -#ifdef PNG_NO_READ_TEXT -# define PNG_NO_READ_iTXt -# define PNG_NO_READ_tEXt -# define PNG_NO_READ_zTXt -#endif -#ifndef PNG_NO_READ_bKGD -# define PNG_READ_bKGD_SUPPORTED -# define PNG_bKGD_SUPPORTED -#endif -#ifndef PNG_NO_READ_cHRM -# define PNG_READ_cHRM_SUPPORTED -# define PNG_cHRM_SUPPORTED -#endif -#ifndef PNG_NO_READ_gAMA -# define PNG_READ_gAMA_SUPPORTED -# define PNG_gAMA_SUPPORTED -#endif -#ifndef PNG_NO_READ_hIST -# define PNG_READ_hIST_SUPPORTED -# define PNG_hIST_SUPPORTED -#endif -#ifndef PNG_NO_READ_iCCP -# define PNG_READ_iCCP_SUPPORTED -# define PNG_iCCP_SUPPORTED -#endif -#ifndef PNG_NO_READ_iTXt -# ifndef PNG_READ_iTXt_SUPPORTED -# define PNG_READ_iTXt_SUPPORTED -# endif -# ifndef PNG_iTXt_SUPPORTED -# define PNG_iTXt_SUPPORTED -# endif -#endif -#ifndef PNG_NO_READ_oFFs -# define PNG_READ_oFFs_SUPPORTED -# define PNG_oFFs_SUPPORTED -#endif -#ifndef PNG_NO_READ_pCAL -# define PNG_READ_pCAL_SUPPORTED -# define PNG_pCAL_SUPPORTED -#endif -#ifndef PNG_NO_READ_sCAL -# define PNG_READ_sCAL_SUPPORTED -# define PNG_sCAL_SUPPORTED -#endif -#ifndef PNG_NO_READ_pHYs -# define PNG_READ_pHYs_SUPPORTED -# define PNG_pHYs_SUPPORTED -#endif -#ifndef PNG_NO_READ_sBIT -# define PNG_READ_sBIT_SUPPORTED -# define PNG_sBIT_SUPPORTED -#endif -#ifndef PNG_NO_READ_sPLT -# define PNG_READ_sPLT_SUPPORTED -# define PNG_sPLT_SUPPORTED -#endif -#ifndef PNG_NO_READ_sRGB -# define PNG_READ_sRGB_SUPPORTED -# define PNG_sRGB_SUPPORTED -#endif -#ifndef PNG_NO_READ_tEXt -# define PNG_READ_tEXt_SUPPORTED -# define PNG_tEXt_SUPPORTED -#endif -#ifndef PNG_NO_READ_tIME -# define PNG_READ_tIME_SUPPORTED -# define PNG_tIME_SUPPORTED -#endif -#ifndef PNG_NO_READ_tRNS -# define PNG_READ_tRNS_SUPPORTED -# define PNG_tRNS_SUPPORTED -#endif -#ifndef PNG_NO_READ_zTXt -# define PNG_READ_zTXt_SUPPORTED -# define PNG_zTXt_SUPPORTED -#endif -#ifndef PNG_NO_READ_OPT_PLTE -# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ -#endif /* optional PLTE chunk in RGB and RGBA images */ -#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ - defined(PNG_READ_zTXt_SUPPORTED) -# define PNG_READ_TEXT_SUPPORTED -# define PNG_TEXT_SUPPORTED -#endif - -#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ - -#ifndef PNG_NO_READ_UNKNOWN_CHUNKS -# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_UNKNOWN_CHUNKS_SUPPORTED -# endif -#endif -#if !defined(PNG_NO_READ_USER_CHUNKS) && \ - defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) -# define PNG_READ_USER_CHUNKS_SUPPORTED -# define PNG_USER_CHUNKS_SUPPORTED -# ifdef PNG_NO_READ_UNKNOWN_CHUNKS -# undef PNG_NO_READ_UNKNOWN_CHUNKS -# endif -# ifdef PNG_NO_HANDLE_AS_UNKNOWN -# undef PNG_NO_HANDLE_AS_UNKNOWN -# endif -#endif - -#ifndef PNG_NO_HANDLE_AS_UNKNOWN -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# endif -#endif - -#ifdef PNG_WRITE_SUPPORTED -#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED - -#ifdef PNG_NO_WRITE_TEXT -# define PNG_NO_WRITE_iTXt -# define PNG_NO_WRITE_tEXt -# define PNG_NO_WRITE_zTXt -#endif -#ifndef PNG_NO_WRITE_bKGD -# define PNG_WRITE_bKGD_SUPPORTED -# ifndef PNG_bKGD_SUPPORTED -# define PNG_bKGD_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_cHRM -# define PNG_WRITE_cHRM_SUPPORTED -# ifndef PNG_cHRM_SUPPORTED -# define PNG_cHRM_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_gAMA -# define PNG_WRITE_gAMA_SUPPORTED -# ifndef PNG_gAMA_SUPPORTED -# define PNG_gAMA_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_hIST -# define PNG_WRITE_hIST_SUPPORTED -# ifndef PNG_hIST_SUPPORTED -# define PNG_hIST_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_iCCP -# define PNG_WRITE_iCCP_SUPPORTED -# ifndef PNG_iCCP_SUPPORTED -# define PNG_iCCP_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_iTXt -# ifndef PNG_WRITE_iTXt_SUPPORTED -# define PNG_WRITE_iTXt_SUPPORTED -# endif -# ifndef PNG_iTXt_SUPPORTED -# define PNG_iTXt_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_oFFs -# define PNG_WRITE_oFFs_SUPPORTED -# ifndef PNG_oFFs_SUPPORTED -# define PNG_oFFs_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_pCAL -# define PNG_WRITE_pCAL_SUPPORTED -# ifndef PNG_pCAL_SUPPORTED -# define PNG_pCAL_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sCAL -# define PNG_WRITE_sCAL_SUPPORTED -# ifndef PNG_sCAL_SUPPORTED -# define PNG_sCAL_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_pHYs -# define PNG_WRITE_pHYs_SUPPORTED -# ifndef PNG_pHYs_SUPPORTED -# define PNG_pHYs_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sBIT -# define PNG_WRITE_sBIT_SUPPORTED -# ifndef PNG_sBIT_SUPPORTED -# define PNG_sBIT_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sPLT -# define PNG_WRITE_sPLT_SUPPORTED -# ifndef PNG_sPLT_SUPPORTED -# define PNG_sPLT_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sRGB -# define PNG_WRITE_sRGB_SUPPORTED -# ifndef PNG_sRGB_SUPPORTED -# define PNG_sRGB_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_tEXt -# define PNG_WRITE_tEXt_SUPPORTED -# ifndef PNG_tEXt_SUPPORTED -# define PNG_tEXt_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_tIME -# define PNG_WRITE_tIME_SUPPORTED -# ifndef PNG_tIME_SUPPORTED -# define PNG_tIME_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_tRNS -# define PNG_WRITE_tRNS_SUPPORTED -# ifndef PNG_tRNS_SUPPORTED -# define PNG_tRNS_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_zTXt -# define PNG_WRITE_zTXt_SUPPORTED -# ifndef PNG_zTXt_SUPPORTED -# define PNG_zTXt_SUPPORTED -# endif -#endif -#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ - defined(PNG_WRITE_zTXt_SUPPORTED) -# define PNG_WRITE_TEXT_SUPPORTED -# ifndef PNG_TEXT_SUPPORTED -# define PNG_TEXT_SUPPORTED -# endif -#endif - -#ifdef PNG_WRITE_tIME_SUPPORTED -# ifndef PNG_NO_CONVERT_tIME -# ifndef _WIN32_WCE -/* The "tm" structure is not supported on WindowsCE */ -# ifndef PNG_CONVERT_tIME_SUPPORTED -# define PNG_CONVERT_tIME_SUPPORTED -# endif -# endif -# endif -#endif - -#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ - -#if !defined(PNG_NO_WRITE_FILTER) && !defined(PNG_WRITE_FILTER_SUPPORTED) -# define PNG_WRITE_FILTER_SUPPORTED -#endif - -#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS -# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_UNKNOWN_CHUNKS_SUPPORTED -# endif -#endif - -#ifndef PNG_NO_HANDLE_AS_UNKNOWN -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# endif -#endif -#endif /* PNG_WRITE_SUPPORTED */ - -/* Turn this off to disable png_read_png() and - * png_write_png() and leave the row_pointers member - * out of the info structure. - */ -#ifndef PNG_NO_INFO_IMAGE -# define PNG_INFO_IMAGE_SUPPORTED -#endif - -/* Need the time information for converting tIME chunks */ -#ifdef PNG_CONVERT_tIME_SUPPORTED - /* "time.h" functions are not supported on WindowsCE */ -# include -#endif - -/* Some typedefs to get us started. These should be safe on most of the - * common platforms. The typedefs should be at least as large as the - * numbers suggest (a png_uint_32 must be at least 32 bits long), but they - * don't have to be exactly that size. Some compilers dislike passing - * unsigned shorts as function parameters, so you may be better off using - * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may - * want to have unsigned int for png_uint_32 instead of unsigned long. - */ - -typedef unsigned long png_uint_32; -typedef long png_int_32; -typedef unsigned short png_uint_16; -typedef short png_int_16; -typedef unsigned char png_byte; - -/* This is usually size_t. It is typedef'ed just in case you need it to - change (I'm not sure if you will or not, so I thought I'd be safe) */ -#ifdef PNG_SIZE_T - typedef PNG_SIZE_T png_size_t; -# define png_sizeof(x) png_convert_size(sizeof(x)) -#else - typedef size_t png_size_t; -# define png_sizeof(x) sizeof(x) -#endif - -/* The following is needed for medium model support. It cannot be in the - * PNG_INTERNAL section. Needs modification for other compilers besides - * MSC. Model independent support declares all arrays and pointers to be - * large using the far keyword. The zlib version used must also support - * model independent data. As of version zlib 1.0.4, the necessary changes - * have been made in zlib. The USE_FAR_KEYWORD define triggers other - * changes that are needed. (Tim Wegner) - */ - -/* Separate compiler dependencies (problem here is that zlib.h always - defines FAR. (SJT) */ -#ifdef __BORLANDC__ -# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) -# define LDATA 1 -# else -# define LDATA 0 -# endif - /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ -# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) -# define PNG_MAX_MALLOC_64K -# if (LDATA != 1) -# ifndef FAR -# define FAR __far -# endif -# define USE_FAR_KEYWORD -# endif /* LDATA != 1 */ - /* Possibly useful for moving data out of default segment. - * Uncomment it if you want. Could also define FARDATA as - * const if your compiler supports it. (SJT) -# define FARDATA FAR - */ -# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ -#endif /* __BORLANDC__ */ - - -/* Suggest testing for specific compiler first before testing for - * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, - * making reliance oncertain keywords suspect. (SJT) - */ - -/* MSC Medium model */ -#ifdef FAR -# ifdef M_I86MM -# define USE_FAR_KEYWORD -# define FARDATA FAR -# include -# endif -#endif - -/* SJT: default case */ -#ifndef FAR -# define FAR -#endif - -/* At this point FAR is always defined */ -#ifndef FARDATA -# define FARDATA -#endif - -/* Typedef for floating-point numbers that are converted - to fixed-point with a multiple of 100,000, e.g., int_gamma */ -typedef png_int_32 png_fixed_point; - -/* Add typedefs for pointers */ -typedef void FAR * png_voidp; -typedef png_byte FAR * png_bytep; -typedef png_uint_32 FAR * png_uint_32p; -typedef png_int_32 FAR * png_int_32p; -typedef png_uint_16 FAR * png_uint_16p; -typedef png_int_16 FAR * png_int_16p; -typedef PNG_CONST char FAR * png_const_charp; -typedef char FAR * png_charp; -typedef png_fixed_point FAR * png_fixed_point_p; - -#ifndef PNG_NO_STDIO -#ifdef _WIN32_WCE -typedef HANDLE png_FILE_p; -#else -typedef FILE * png_FILE_p; -#endif -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR * png_doublep; -#endif - -/* Pointers to pointers; i.e. arrays */ -typedef png_byte FAR * FAR * png_bytepp; -typedef png_uint_32 FAR * FAR * png_uint_32pp; -typedef png_int_32 FAR * FAR * png_int_32pp; -typedef png_uint_16 FAR * FAR * png_uint_16pp; -typedef png_int_16 FAR * FAR * png_int_16pp; -typedef PNG_CONST char FAR * FAR * png_const_charpp; -typedef char FAR * FAR * png_charpp; -typedef png_fixed_point FAR * FAR * png_fixed_point_pp; -#ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR * FAR * png_doublepp; -#endif - -/* Pointers to pointers to pointers; i.e., pointer to array */ -typedef char FAR * FAR * FAR * png_charppp; - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* SPC - Is this stuff deprecated? */ -/* It'll be removed as of libpng-1.4.0 - GR-P */ -/* libpng typedefs for types in zlib. If zlib changes - * or another compression library is used, then change these. - * Eliminates need to change all the source files. - */ -typedef charf * png_zcharp; -typedef charf * FAR * png_zcharpp; -typedef z_stream FAR * png_zstreamp; -#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */ - -/* - * Define PNG_BUILD_DLL if the module being built is a Windows - * LIBPNG DLL. - * - * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. - * It is equivalent to Microsoft predefined macro _DLL that is - * automatically defined when you compile using the share - * version of the CRT (C Run-Time library) - * - * The cygwin mods make this behavior a little different: - * Define PNG_BUILD_DLL if you are building a dll for use with cygwin - * Define PNG_STATIC if you are building a static library for use with cygwin, - * -or- if you are building an application that you want to link to the - * static library. - * PNG_USE_DLL is defined by default (no user action needed) unless one of - * the other flags is defined. - */ - -#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) -# define PNG_DLL -#endif -/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. - * When building a static lib, default to no GLOBAL ARRAYS, but allow - * command-line override - */ -#ifdef __CYGWIN__ -# ifndef PNG_STATIC -# ifdef PNG_USE_GLOBAL_ARRAYS -# undef PNG_USE_GLOBAL_ARRAYS -# endif -# ifndef PNG_USE_LOCAL_ARRAYS -# define PNG_USE_LOCAL_ARRAYS -# endif -# else -# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) -# ifdef PNG_USE_GLOBAL_ARRAYS -# undef PNG_USE_GLOBAL_ARRAYS -# endif -# endif -# endif -# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) -# define PNG_USE_LOCAL_ARRAYS -# endif -#endif - -/* Do not use global arrays (helps with building DLL's) - * They are no longer used in libpng itself, since version 1.0.5c, - * but might be required for some pre-1.0.5c applications. - */ -#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) -# if defined(PNG_NO_GLOBAL_ARRAYS) || \ - (defined(__GNUC__) && defined(PNG_DLL)) || defined(_MSC_VER) -# define PNG_USE_LOCAL_ARRAYS -# else -# define PNG_USE_GLOBAL_ARRAYS -# endif -#endif - -#ifdef __CYGWIN__ -# undef PNGAPI -# define PNGAPI __cdecl -# undef PNG_IMPEXP -# define PNG_IMPEXP -#endif - -/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", - * you may get warnings regarding the linkage of png_zalloc and png_zfree. - * Don't ignore those warnings; you must also reset the default calling - * convention in your compiler to match your PNGAPI, and you must build - * zlib and your applications the same way you build libpng. - */ - -#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) -# ifndef PNG_NO_MODULEDEF -# define PNG_NO_MODULEDEF -# endif -#endif - -#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) -# define PNG_IMPEXP -#endif - -#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ - (( defined(_Windows) || defined(_WINDOWS) || \ - defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) - -# ifndef PNGAPI -# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) -# define PNGAPI __cdecl -# else -# define PNGAPI _cdecl -# endif -# endif - -# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ - 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) -# define PNG_IMPEXP -# endif - -# ifndef PNG_IMPEXP - -# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol -# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol - - /* Borland/Microsoft */ -# if defined(_MSC_VER) || defined(__BORLANDC__) -# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) -# define PNG_EXPORT PNG_EXPORT_TYPE1 -# else -# define PNG_EXPORT PNG_EXPORT_TYPE2 -# ifdef PNG_BUILD_DLL -# define PNG_IMPEXP __export -# else -# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in - VC++ */ -# endif /* Exists in Borland C++ for - C++ classes (== huge) */ -# endif -# endif - -# ifndef PNG_IMPEXP -# ifdef PNG_BUILD_DLL -# define PNG_IMPEXP __declspec(dllexport) -# else -# define PNG_IMPEXP __declspec(dllimport) -# endif -# endif -# endif /* PNG_IMPEXP */ -#else /* !(DLL || non-cygwin WINDOWS) */ -# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) -# ifndef PNGAPI -# define PNGAPI _System -# endif -# else -# if 0 /* ... other platforms, with other meanings */ -# endif -# endif -#endif - -#ifndef PNGAPI -# define PNGAPI -#endif -#ifndef PNG_IMPEXP -# define PNG_IMPEXP -#endif - -#ifdef PNG_BUILDSYMS -# ifndef PNG_EXPORT -# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END -# endif -# ifdef PNG_USE_GLOBAL_ARRAYS -# ifndef PNG_EXPORT_VAR -# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT -# endif -# endif -#endif - -#ifndef PNG_EXPORT -# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol -#endif - -#ifdef PNG_USE_GLOBAL_ARRAYS -# ifndef PNG_EXPORT_VAR -# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type -# endif -#endif - -#ifdef PNG_PEDANTIC_WARNINGS -# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED -# define PNG_PEDANTIC_WARNINGS_SUPPORTED -# endif -#endif - -#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED -/* Support for compiler specific function attributes. These are used - * so that where compiler support is available incorrect use of API - * functions in png.h will generate compiler warnings. Added at libpng - * version 1.2.41. - */ -# ifdef __GNUC__ -# ifndef PNG_USE_RESULT -# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) -# endif -# ifndef PNG_NORETURN -# define PNG_NORETURN __attribute__((__noreturn__)) -# endif -# ifndef PNG_ALLOCATED -# define PNG_ALLOCATED __attribute__((__malloc__)) -# endif - - /* This specifically protects structure members that should only be - * accessed from within the library, therefore should be empty during - * a library build. - */ -# ifndef PNG_DEPRECATED -# define PNG_DEPRECATED __attribute__((__deprecated__)) -# endif -# ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT __attribute__((__deprecated__)) -# endif -# ifndef PNG_PRIVATE -# if 0 /* Doesn't work so we use deprecated instead*/ -# define PNG_PRIVATE \ - __attribute__((warning("This function is not exported by libpng."))) -# else -# define PNG_PRIVATE \ - __attribute__((__deprecated__)) -# endif -# endif /* PNG_PRIVATE */ -# endif /* __GNUC__ */ -#endif /* PNG_PEDANTIC_WARNINGS */ - -#ifndef PNG_DEPRECATED -# define PNG_DEPRECATED /* Use of this function is deprecated */ -#endif -#ifndef PNG_USE_RESULT -# define PNG_USE_RESULT /* The result of this function must be checked */ -#endif -#ifndef PNG_NORETURN -# define PNG_NORETURN /* This function does not return */ -#endif -#ifndef PNG_ALLOCATED -# define PNG_ALLOCATED /* The result of the function is new memory */ -#endif -#ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT /* Access to this struct member is deprecated */ -#endif -#ifndef PNG_PRIVATE -# define PNG_PRIVATE /* This is a private libpng function */ -#endif - -/* User may want to use these so they are not in PNG_INTERNAL. Any library - * functions that are passed far data must be model independent. - */ - -#ifndef PNG_ABORT -# define PNG_ABORT() abort() -#endif - -#ifdef PNG_SETJMP_SUPPORTED -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#else -# define png_jmpbuf(png_ptr) \ - (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) -#endif - -#ifdef USE_FAR_KEYWORD /* memory model independent fns */ -/* Use this to make far-to-near assignments */ -# define CHECK 1 -# define NOCHECK 0 -# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) -# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) -# define png_snprintf _fsnprintf /* Added to v 1.2.19 */ -# define png_strlen _fstrlen -# define png_memcmp _fmemcmp /* SJT: added */ -# define png_memcpy _fmemcpy -# define png_memset _fmemset -#else /* Use the usual functions */ -# define CVT_PTR(ptr) (ptr) -# define CVT_PTR_NOCHECK(ptr) (ptr) -# ifndef PNG_NO_SNPRINTF -# ifdef _MSC_VER -# define png_snprintf _snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 _snprintf -# define png_snprintf6 _snprintf -# else -# define png_snprintf snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 snprintf -# define png_snprintf6 snprintf -# endif -# else - /* You don't have or don't want to use snprintf(). Caution: Using - * sprintf instead of snprintf exposes your application to accidental - * or malevolent buffer overflows. If you don't have snprintf() - * as a general rule you should provide one (you can get one from - * Portable OpenSSH). - */ -# define png_snprintf(s1,n,fmt,x1) sprintf(s1,fmt,x1) -# define png_snprintf2(s1,n,fmt,x1,x2) sprintf(s1,fmt,x1,x2) -# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \ - sprintf(s1,fmt,x1,x2,x3,x4,x5,x6) -# endif -# define png_strlen strlen -# define png_memcmp memcmp /* SJT: added */ -# define png_memcpy memcpy -# define png_memset memset -#endif -/* End of memory model independent support */ - -/* Just a little check that someone hasn't tried to define something - * contradictory. - */ -#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) -# undef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 65536L -#endif - -/* Added at libpng-1.2.8 */ -#endif /* PNG_VERSION_INFO_ONLY */ - -#endif /* PNGCONF_H */ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.2.51 - February 6, 2014 + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +#define PNG_1_2_X + +/* + * PNG_USER_CONFIG has to be defined on the compiler command line. This + * includes the resource compiler for Windows DLL configurations. + */ +#ifdef PNG_USER_CONFIG +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD +# endif +#include "pngusr.h" +#endif + +/* PNG_CONFIGURE_LIBPNG is set by the "configure" script. */ +#ifdef PNG_CONFIGURE_LIBPNG +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +/* + * Added at libpng-1.2.8 + * + * If you create a private DLL you need to define in "pngusr.h" the followings: + * #define PNG_USER_PRIVATEBUILD + * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." + * #define PNG_USER_DLLFNAME_POSTFIX + * e.g. // private DLL "libpng13gx.dll" + * #define PNG_USER_DLLFNAME_POSTFIX "gx" + * + * The following macros are also at your disposal if you want to complete the + * DLL VERSIONINFO structure. + * - PNG_USER_VERSIONINFO_COMMENTS + * - PNG_USER_VERSIONINFO_COMPANYNAME + * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS + */ + +#ifdef __STDC__ +#ifdef SPECIALBUILD +# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ + are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") +#endif + +#ifdef PRIVATEBUILD +# pragma message("PRIVATEBUILD is deprecated.\ + Use PNG_USER_PRIVATEBUILD instead.") +# define PNG_USER_PRIVATEBUILD PRIVATEBUILD +#endif +#endif /* __STDC__ */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* End of material added to libpng-1.2.8 */ + +/* Added at libpng-1.2.19, removed at libpng-1.2.20 because it caused trouble + Restored at libpng-1.2.21 */ +#if !defined(PNG_NO_WARN_UNINITIALIZED_ROW) && \ + !defined(PNG_WARN_UNINITIALIZED_ROW) +# define PNG_WARN_UNINITIALIZED_ROW 1 +#endif +/* End of material added at libpng-1.2.19/1.2.21 */ + +/* Added at libpng-1.2.51 (ported from 1.4.6) */ +#ifndef PNG_UNUSED +/* Unused formal parameter warnings are silenced using the following macro + * which is expected to have no bad effects on performance (optimizing + * compilers will probably remove it entirely). Note that if you replace + * it with something other than whitespace, you must include the terminating + * semicolon. + */ +# define PNG_UNUSED(param) (void)param; +#endif +/* End of material added to libpng-1.4.6 */ + +/* This is the size of the compression buffer, and thus the size of + * an IDAT chunk. Make this whatever size you feel is best for your + * machine. One of these will be allocated per png_struct. When this + * is full, it writes the data to the disk, and does some other + * calculations. Making this an extremely small size will slow + * the library down, but you may want to experiment to determine + * where it becomes significant, if you are concerned with memory + * usage. Note that zlib allocates at least 32Kb also. For readers, + * this describes the size of the buffer available to read the data in. + * Unless this gets smaller than the size of a row (compressed), + * it should not make much difference how big this is. + */ + +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif + +/* Enable if you want a write-only libpng */ + +#ifndef PNG_NO_READ_SUPPORTED +# define PNG_READ_SUPPORTED +#endif + +/* Enable if you want a read-only libpng */ + +#ifndef PNG_NO_WRITE_SUPPORTED +# define PNG_WRITE_SUPPORTED +#endif + +/* Enabled in 1.2.41. */ +#ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +#else +# ifndef PNG_BENIGN_ERRORS_SUPPORTED +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* Added in libpng-1.2.41 */ +#if !defined(PNG_NO_WARNINGS) && !defined(PNG_WARNINGS_SUPPORTED) +# define PNG_WARNINGS_SUPPORTED +#endif + +#if !defined(PNG_NO_ERROR_TEXT) && !defined(PNG_ERROR_TEXT_SUPPORTED) +# define PNG_ERROR_TEXT_SUPPORTED +#endif + +#if !defined(PNG_NO_CHECK_cHRM) && !defined(PNG_CHECK_cHRM_SUPPORTED) +# define PNG_CHECK_cHRM_SUPPORTED +#endif + +/* Enabled by default in 1.2.0. You can disable this if you don't need to + * support PNGs that are embedded in MNG datastreams + */ +#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES) +# ifndef PNG_MNG_FEATURES_SUPPORTED +# define PNG_MNG_FEATURES_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FLOATING_POINT_SUPPORTED +# endif +#endif + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. +#define PNG_MAX_MALLOC_64K + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +/* Special munging to support doing things the 'cygwin' way: + * 'Normal' png-on-win32 defines/defaults: + * PNG_BUILD_DLL -- building dll + * PNG_USE_DLL -- building an application, linking to dll + * (no define) -- building static library, or building an + * application and linking to the static lib + * 'Cygwin' defines/defaults: + * PNG_BUILD_DLL -- (ignored) building the dll + * (no define) -- (ignored) building an application, linking to the dll + * PNG_STATIC -- (ignored) building the static lib, or building an + * application that links to the static lib. + * ALL_STATIC -- (ignored) building various static libs, or building an + * application that links to the static libs. + * Thus, + * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and + * this bit of #ifdefs will define the 'correct' config variables based on + * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but + * unnecessary. + * + * Also, the precedence order is: + * ALL_STATIC (since we can't #undef something outside our namespace) + * PNG_BUILD_DLL + * PNG_STATIC + * (nothing) == PNG_USE_DLL + * + * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent + * of auto-import in binutils, we no longer need to worry about + * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, + * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes + * to __declspec() stuff. However, we DO need to worry about + * PNG_BUILD_DLL and PNG_STATIC because those change some defaults + * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed. + */ +#ifdef __CYGWIN__ +# ifdef ALL_STATIC +# ifdef PNG_BUILD_DLL +# undef PNG_BUILD_DLL +# endif +# ifdef PNG_USE_DLL +# undef PNG_USE_DLL +# endif +# ifdef PNG_DLL +# undef PNG_DLL +# endif +# ifndef PNG_STATIC +# define PNG_STATIC +# endif +# else +# ifdef PNG_BUILD_DLL +# ifdef PNG_STATIC +# undef PNG_STATIC +# endif +# ifdef PNG_USE_DLL +# undef PNG_USE_DLL +# endif +# ifndef PNG_DLL +# define PNG_DLL +# endif +# else +# ifdef PNG_STATIC +# ifdef PNG_USE_DLL +# undef PNG_USE_DLL +# endif +# ifdef PNG_DLL +# undef PNG_DLL +# endif +# else +# ifndef PNG_USE_DLL +# define PNG_USE_DLL +# endif +# ifndef PNG_DLL +# define PNG_DLL +# endif +# endif +# endif +# endif +#endif + +/* This protects us against compilers that run on a windowing system + * and thus don't have or would rather us not use the stdio types: + * stdin, stdout, and stderr. The only one currently used is stderr + * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will + * prevent these from being compiled and used. #defining PNG_NO_STDIO + * will also prevent these, plus will prevent the entire set of stdio + * macros and functions (FILE *, printf, etc.) from being compiled and used, + * unless (PNG_DEBUG > 0) has been #defined. + * + * #define PNG_NO_CONSOLE_IO + * #define PNG_NO_STDIO + */ + +#if !defined(PNG_NO_STDIO) && !defined(PNG_STDIO_SUPPORTED) +# define PNG_STDIO_SUPPORTED +#endif + +#ifdef _WIN32_WCE +# include + /* Console I/O functions are not supported on WindowsCE */ +# define PNG_NO_CONSOLE_IO + /* abort() may not be supported on some/all Windows CE platforms */ +# define PNG_ABORT() exit(-1) +# ifdef PNG_DEBUG +# undef PNG_DEBUG +# endif +#endif + +#ifdef PNG_BUILD_DLL +# ifndef PNG_CONSOLE_IO_SUPPORTED +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# endif +#endif + +# ifdef PNG_NO_STDIO +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# include +# endif +# endif +# else +# ifndef _WIN32_WCE +/* "stdio.h" functions are not supported on WindowsCE */ +# include +# endif +# endif + +#if !(defined PNG_NO_CONSOLE_IO) && !defined(PNG_CONSOLE_IO_SUPPORTED) +# define PNG_CONSOLE_IO_SUPPORTED +#endif + +/* This macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +#ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +#else + +#ifdef _NO_PROTO +# define PNGARG(arglist) () +# ifndef PNG_TYPECAST_NULL +# define PNG_TYPECAST_NULL +# endif +#else +# define PNGARG(arglist) arglist +#endif /* _NO_PROTO */ + + +#endif /* OF */ + +#endif /* PNGARG */ + +/* Try to determine if we are compiling on a Mac. Note that testing for + * just __MWERKS__ is not good enough, because the Codewarrior is now used + * on non-Mac platforms. + */ +#ifndef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) +# define MACOS +# endif +#endif + +/* enough people need this for various reasons to include it here */ +#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) +# include +#endif + +#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) +# define PNG_SETJMP_SUPPORTED +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This is an attempt to force a single setjmp behaviour on Linux. If + * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. + * + * You can bypass this test if you know that your application uses exactly + * the same setjmp.h that was included when libpng was built. Only define + * PNG_SKIP_SETJMP_CHECK while building your application, prior to the + * application's '#include "png.h"'. Don't define PNG_SKIP_SETJMP_CHECK + * while building a separate libpng library for general use. + */ + +# ifndef PNG_SKIP_SETJMP_CHECK +# ifdef __linux__ +# ifdef _BSD_SOURCE +# define PNG_SAVE_BSD_SOURCE +# undef _BSD_SOURCE +# endif +# ifdef _SETJMP_H + /* If you encounter a compiler error here, see the explanation + * near the end of INSTALL. + */ + __pngconf.h__ in libpng already includes setjmp.h; + __dont__ include it again.; +# endif +# endif /* __linux__ */ +# endif /* PNG_SKIP_SETJMP_CHECK */ + + /* include setjmp.h for error handling */ +# include + +# ifdef __linux__ +# ifdef PNG_SAVE_BSD_SOURCE +# ifndef _BSD_SOURCE +# define _BSD_SOURCE +# endif +# undef PNG_SAVE_BSD_SOURCE +# endif +# endif /* __linux__ */ +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef BSD +# include +#else +# include +#endif + +/* Other defines for things like memory and the like can go here. */ +#ifdef PNG_INTERNAL + +#include + +/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which + * aren't usually used outside the library (as far as I know), so it is + * debatable if they should be exported at all. In the future, when it is + * possible to have run-time registry of chunk-handling functions, some of + * these will be made available again. +#define PNG_EXTERN extern + */ +#define PNG_EXTERN + +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED +# ifdef MACOS + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* Codewarrior on NT has linking problems without this. */ +#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) +# define PNG_ALWAYS_EXTERN +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include +# include +#endif + +/* I have no idea why is this necessary... */ +#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ + defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) +# include +#endif + +/* This controls how fine the dithering gets. As this allocates + * a largish chunk of memory (32K), those who are not as concerned + * with dithering quality can decrease some or all of these. + */ +#ifndef PNG_DITHER_RED_BITS +# define PNG_DITHER_RED_BITS 5 +#endif +#ifndef PNG_DITHER_GREEN_BITS +# define PNG_DITHER_GREEN_BITS 5 +#endif +#ifndef PNG_DITHER_BLUE_BITS +# define PNG_DITHER_BLUE_BITS 5 +#endif + +/* This controls how fine the gamma correction becomes when you + * are only interested in 8 bits anyway. Increasing this value + * results in more memory being used, and more pow() functions + * being called to fill in the gamma tables. Don't set this value + * less then 8, and even that may not work (I haven't tested it). + */ + +#ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +#endif + +/* This controls how much a difference in gamma we can tolerate before + * we actually start doing gamma conversion. + */ +#ifndef PNG_GAMMA_THRESHOLD +# define PNG_GAMMA_THRESHOLD 0.05 +#endif + +#endif /* PNG_INTERNAL */ + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST here. + */ + +#ifndef PNG_NO_CONST +# define PNG_CONST const +#else +# define PNG_CONST +#endif + +/* The following defines give you the ability to remove code from the + * library that you will not be using. I wish I could figure out how to + * automate this, but I can't do that without making it seriously hard + * on the users. So if you are not using an ability, change the #define + * to and #undef, and that part of the library will not be compiled. If + * your linker can't find a function, you may want to make sure the + * ability is defined here. Some of these depend upon some others being + * defined. I haven't figured out all the interactions here, so you may + * have to experiment awhile to get everything to compile. If you are + * creating or using a shared library, you probably shouldn't touch this, + * as it will affect the size of the structures, and this will cause bad + * things to happen if the library and/or application ever change. + */ + +/* Any features you will not be using can be undef'ed here */ + +/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user + * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS + * on the compile line, then pick and choose which ones to define without + * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED + * if you only want to have a png-compliant reader/writer but don't need + * any of the extra transformations. This saves about 80 kbytes in a + * typical installation of the library. (PNG_NO_* form added in version + * 1.0.1c, for consistency) + */ + +/* The size of the png_text structure changed in libpng-1.0.6 when + * iTXt support was added. iTXt support was turned off by default through + * libpng-1.2.x, to support old apps that malloc the png_text structure + * instead of calling png_set_text() and letting libpng malloc it. It + * will be turned on by default in libpng-1.4.0. + */ + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +# ifndef PNG_NO_iTXt_SUPPORTED +# define PNG_NO_iTXt_SUPPORTED +# endif +# ifndef PNG_NO_READ_iTXt +# define PNG_NO_READ_iTXt +# endif +# ifndef PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_iTXt +# endif +#endif + +#if !defined(PNG_NO_iTXt_SUPPORTED) +# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt) +# define PNG_READ_iTXt +# endif +# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt) +# define PNG_WRITE_iTXt +# endif +#endif + +/* The following support, added after version 1.0.0, can be turned off here en + * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility + * with old applications that require the length of png_struct and png_info + * to remain unchanged. + */ + +#ifdef PNG_LEGACY_SUPPORTED +# define PNG_NO_FREE_ME +# define PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_NO_HANDLE_AS_UNKNOWN +# define PNG_NO_READ_USER_CHUNKS +# define PNG_NO_READ_iCCP +# define PNG_NO_WRITE_iCCP +# define PNG_NO_READ_iTXt +# define PNG_NO_WRITE_iTXt +# define PNG_NO_READ_sCAL +# define PNG_NO_WRITE_sCAL +# define PNG_NO_READ_sPLT +# define PNG_NO_WRITE_sPLT +# define PNG_NO_INFO_IMAGE +# define PNG_NO_READ_RGB_TO_GRAY +# define PNG_NO_READ_USER_TRANSFORM +# define PNG_NO_WRITE_USER_TRANSFORM +# define PNG_NO_USER_MEM +# define PNG_NO_READ_EMPTY_PLTE +# define PNG_NO_MNG_FEATURES +# define PNG_NO_FIXED_POINT_SUPPORTED +#endif + +/* Ignore attempt to turn off both floating and fixed point support */ +#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ + !defined(PNG_NO_FIXED_POINT_SUPPORTED) +# define PNG_FIXED_POINT_SUPPORTED +#endif + +#ifndef PNG_NO_FREE_ME +# define PNG_FREE_ME_SUPPORTED +#endif + +#ifdef PNG_READ_SUPPORTED + +#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_TRANSFORMS) +# define PNG_READ_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_READ_EXPAND +# define PNG_READ_EXPAND_SUPPORTED +# endif +# ifndef PNG_NO_READ_SHIFT +# define PNG_READ_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACK +# define PNG_READ_PACK_SUPPORTED +# endif +# ifndef PNG_NO_READ_BGR +# define PNG_READ_BGR_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP +# define PNG_READ_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACKSWAP +# define PNG_READ_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT +# define PNG_READ_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_READ_DITHER +# define PNG_READ_DITHER_SUPPORTED +# endif +# ifndef PNG_NO_READ_BACKGROUND +# define PNG_READ_BACKGROUND_SUPPORTED +# endif +# ifndef PNG_NO_READ_16_TO_8 +# define PNG_READ_16_TO_8_SUPPORTED +# endif +# ifndef PNG_NO_READ_FILLER +# define PNG_READ_FILLER_SUPPORTED +# endif +# ifndef PNG_NO_READ_GAMMA +# define PNG_READ_GAMMA_SUPPORTED +# endif +# ifndef PNG_NO_READ_GRAY_TO_RGB +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP_ALPHA +# define PNG_READ_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT_ALPHA +# define PNG_READ_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_STRIP_ALPHA +# define PNG_READ_STRIP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_USER_TRANSFORM +# define PNG_READ_USER_TRANSFORM_SUPPORTED +# endif +# ifndef PNG_NO_READ_RGB_TO_GRAY +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +/* PNG_PROGRESSIVE_READ_NOT_SUPPORTED is deprecated. */ +#if !defined(PNG_NO_PROGRESSIVE_READ) && \ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following define: */ +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ + +/* PNG_NO_SEQUENTIAL_READ_SUPPORTED is deprecated. */ +#if !defined(PNG_NO_SEQUENTIAL_READ) && \ + !defined(PNG_SEQUENTIAL_READ_SUPPORTED) && \ + !defined(PNG_NO_SEQUENTIAL_READ_SUPPORTED) +# define PNG_SEQUENTIAL_READ_SUPPORTED +#endif + +#define PNG_READ_INTERLACING_SUPPORTED /* required in PNG-compliant decoders */ + +#ifndef PNG_NO_READ_COMPOSITE_NODIV +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# endif +#endif + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +/* Deprecated, will be removed from version 2.0.0. + Use PNG_MNG_FEATURES_SUPPORTED instead. */ +#ifndef PNG_NO_READ_EMPTY_PLTE +# define PNG_READ_EMPTY_PLTE_SUPPORTED +#endif +#endif + +#endif /* PNG_READ_SUPPORTED */ + +#ifdef PNG_WRITE_SUPPORTED + +# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_TRANSFORMS) +# define PNG_WRITE_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_WRITE_SHIFT +# define PNG_WRITE_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACK +# define PNG_WRITE_PACK_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_BGR +# define PNG_WRITE_BGR_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_SWAP +# define PNG_WRITE_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACKSWAP +# define PNG_WRITE_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT +# define PNG_WRITE_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_FILLER +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# endif +# ifndef PNG_NO_WRITE_SWAP_ALPHA +# define PNG_WRITE_SWAP_ALPHA_SUPPORTED +# endif +#ifndef PNG_1_0_X +# ifndef PNG_NO_WRITE_INVERT_ALPHA +# define PNG_WRITE_INVERT_ALPHA_SUPPORTED +# endif +#endif +# ifndef PNG_NO_WRITE_USER_TRANSFORM +# define PNG_WRITE_USER_TRANSFORM_SUPPORTED +# endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#if !defined(PNG_NO_WRITE_INTERLACING_SUPPORTED) && \ + !defined(PNG_WRITE_INTERLACING_SUPPORTED) +#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant + encoders, but can cause trouble + if left undefined */ +#endif + +#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ + !defined(PNG_WRITE_WEIGHTED_FILTER) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#endif + +#ifndef PNG_NO_WRITE_FLUSH +# define PNG_WRITE_FLUSH_SUPPORTED +#endif + +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ +#ifndef PNG_NO_WRITE_EMPTY_PLTE +# define PNG_WRITE_EMPTY_PLTE_SUPPORTED +#endif +#endif + +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef PNG_1_0_X +# ifndef PNG_NO_ERROR_NUMBERS +# define PNG_ERROR_NUMBERS_SUPPORTED +# endif +#endif /* PNG_1_0_X */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_STDIO +# define PNG_TIME_RFC1123_SUPPORTED +#endif + +/* This adds extra functions in pngget.c for accessing data from the + * info pointer (added in version 0.99) + * png_get_image_width() + * png_get_image_height() + * png_get_bit_depth() + * png_get_color_type() + * png_get_compression_type() + * png_get_filter_type() + * png_get_interlace_type() + * png_get_pixel_aspect_ratio() + * png_get_pixels_per_meter() + * png_get_x_offset_pixels() + * png_get_y_offset_pixels() + * png_get_x_offset_microns() + * png_get_y_offset_microns() + */ +#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) +# define PNG_EASY_ACCESS_SUPPORTED +#endif + +/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 + * and removed from version 1.2.20. The following will be removed + * from libpng-1.4.0 +*/ + +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_OPTIMIZED_CODE) +# ifndef PNG_OPTIMIZED_CODE_SUPPORTED +# define PNG_OPTIMIZED_CODE_SUPPORTED +# endif +#endif + +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) +# ifndef PNG_ASSEMBLER_CODE_SUPPORTED +# define PNG_ASSEMBLER_CODE_SUPPORTED +# endif + +# if defined(__GNUC__) && defined(__x86_64__) && (__GNUC__ < 4) + /* work around 64-bit gcc compiler bugs in gcc-3.x */ +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_NO_MMX_CODE +# endif +# endif + +# ifdef __APPLE__ +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_NO_MMX_CODE +# endif +# endif + +# if (defined(__MWERKS__) && ((__MWERKS__ < 0x0900) || macintosh)) +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_NO_MMX_CODE +# endif +# endif + +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_MMX_CODE_SUPPORTED +# endif + +#endif +/* end of obsolete code to be removed from libpng-1.4.0 */ + +/* Added at libpng-1.2.0 */ +#ifndef PNG_1_0_X +#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) +# define PNG_USER_MEM_SUPPORTED +#endif +#endif /* PNG_1_0_X */ + +/* Added at libpng-1.2.6 */ +#ifndef PNG_1_0_X +# ifndef PNG_SET_USER_LIMITS_SUPPORTED +# ifndef PNG_NO_SET_USER_LIMITS +# define PNG_SET_USER_LIMITS_SUPPORTED +# endif +# endif +#endif /* PNG_1_0_X */ + +/* Added at libpng-1.0.53 and 1.2.43 */ +#ifndef PNG_USER_LIMITS_SUPPORTED +# ifndef PNG_NO_USER_LIMITS +# define PNG_USER_LIMITS_SUPPORTED +# endif +#endif + +/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter + * how large, set these limits to 0x7fffffffL + */ +#ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +#endif +#ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +#endif + +/* Added at libpng-1.2.43. To accept all valid PNGs no matter + * how large, set these two limits to 0. + */ +#ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 32765 +#endif + +/* Added at libpng-1.2.43 */ +#ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 0 +#endif + +#ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +#endif +#ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +#endif +#ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +#endif + +/* Added at libpng-1.2.34 */ +#ifndef PNG_STRING_NEWLINE +#define PNG_STRING_NEWLINE "\n" +#endif + +/* These are currently experimental features, define them if you want */ + +/* very little testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# endif +#endif +*/ + +/* This is only for PowerPC big-endian and 680x0 systems */ +/* some testing */ +/* +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED +#endif +*/ + +/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ +/* +#define PNG_NO_POINTER_INDEXING +*/ + +#if !defined(PNG_NO_POINTER_INDEXING) && \ + !defined(PNG_POINTER_INDEXING_SUPPORTED) +# define PNG_POINTER_INDEXING_SUPPORTED +#endif + +/* These functions are turned off by default, as they will be phased out. */ +/* +#define PNG_USELESS_TESTS_SUPPORTED +#define PNG_CORRECT_PALETTE_SUPPORTED +*/ + +/* Any chunks you are not interested in, you can undef here. The + * ones that allocate memory may be expecially important (hIST, + * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info + * a bit smaller. + */ + +#if defined(PNG_READ_SUPPORTED) && \ + !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_ANCILLARY_CHUNKS) +# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#if defined(PNG_WRITE_SUPPORTED) && \ + !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) +# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif +#ifndef PNG_NO_READ_bKGD +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +#endif +#ifndef PNG_NO_READ_cHRM +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +#endif +#ifndef PNG_NO_READ_gAMA +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +#endif +#ifndef PNG_NO_READ_hIST +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +#endif +#ifndef PNG_NO_READ_iCCP +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +#endif +#ifndef PNG_NO_READ_iTXt +# ifndef PNG_READ_iTXt_SUPPORTED +# define PNG_READ_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_READ_oFFs +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +#endif +#ifndef PNG_NO_READ_pCAL +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_sCAL +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_pHYs +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +#endif +#ifndef PNG_NO_READ_sBIT +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sPLT +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sRGB +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +#endif +#ifndef PNG_NO_READ_tEXt +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_tIME +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +#endif +#ifndef PNG_NO_READ_tRNS +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +#endif +#ifndef PNG_NO_READ_zTXt +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_OPT_PLTE +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ +#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +#endif + +#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +#endif +#if !defined(PNG_NO_READ_USER_CHUNKS) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# define PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_USER_CHUNKS_SUPPORTED +# ifdef PNG_NO_READ_UNKNOWN_CHUNKS +# undef PNG_NO_READ_UNKNOWN_CHUNKS +# endif +# ifdef PNG_NO_HANDLE_AS_UNKNOWN +# undef PNG_NO_HANDLE_AS_UNKNOWN +# endif +#endif + +#ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt +#endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_cHRM +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_gAMA +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_hIST +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iCCP +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iTXt +# ifndef PNG_WRITE_iTXt_SUPPORTED +# define PNG_WRITE_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_oFFs +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pCAL +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sCAL +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pHYs +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sBIT +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sPLT +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sRGB +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tEXt +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tIME +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tRNS +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_zTXt +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif +#endif +#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_WRITE_zTXt_SUPPORTED) +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_NO_CONVERT_tIME +# ifndef _WIN32_WCE +/* The "tm" structure is not supported on WindowsCE */ +# ifndef PNG_CONVERT_tIME_SUPPORTED +# define PNG_CONVERT_tIME_SUPPORTED +# endif +# endif +# endif +#endif + +#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ + +#if !defined(PNG_NO_WRITE_FILTER) && !defined(PNG_WRITE_FILTER_SUPPORTED) +# define PNG_WRITE_FILTER_SUPPORTED +#endif + +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +/* Turn this off to disable png_read_png() and + * png_write_png() and leave the row_pointers member + * out of the info structure. + */ +#ifndef PNG_NO_INFO_IMAGE +# define PNG_INFO_IMAGE_SUPPORTED +#endif + +/* Need the time information for converting tIME chunks */ +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* "time.h" functions are not supported on WindowsCE */ +# include +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may + * want to have unsigned int for png_uint_32 instead of unsigned long. + */ + +typedef unsigned long png_uint_32; +typedef long png_int_32; +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +/* This is usually size_t. It is typedef'ed just in case you need it to + change (I'm not sure if you will or not, so I thought I'd be safe) */ +#ifdef PNG_SIZE_T + typedef PNG_SIZE_T png_size_t; +# define png_sizeof(x) png_convert_size(sizeof(x)) +#else + typedef size_t png_size_t; +# define png_sizeof(x) sizeof(x) +#endif + +/* The following is needed for medium model support. It cannot be in the + * PNG_INTERNAL section. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + defines FAR. (SJT) */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#ifdef FAR +# ifdef M_I86MM +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; + +#ifndef PNG_NO_STDIO +#ifdef _WIN32_WCE +typedef HANDLE png_FILE_p; +#else +typedef FILE * png_FILE_p; +#endif +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* SPC - Is this stuff deprecated? */ +/* It'll be removed as of libpng-1.4.0 - GR-P */ +/* libpng typedefs for types in zlib. If zlib changes + * or another compression library is used, then change these. + * Eliminates need to change all the source files. + */ +typedef charf * png_zcharp; +typedef charf * FAR * png_zcharpp; +typedef z_stream FAR * png_zstreamp; +#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */ + +/* + * Define PNG_BUILD_DLL if the module being built is a Windows + * LIBPNG DLL. + * + * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. + * It is equivalent to Microsoft predefined macro _DLL that is + * automatically defined when you compile using the share + * version of the CRT (C Run-Time library) + * + * The cygwin mods make this behavior a little different: + * Define PNG_BUILD_DLL if you are building a dll for use with cygwin + * Define PNG_STATIC if you are building a static library for use with cygwin, + * -or- if you are building an application that you want to link to the + * static library. + * PNG_USE_DLL is defined by default (no user action needed) unless one of + * the other flags is defined. + */ + +#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) +# define PNG_DLL +#endif +/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. + * When building a static lib, default to no GLOBAL ARRAYS, but allow + * command-line override + */ +#ifdef __CYGWIN__ +# ifndef PNG_STATIC +# ifdef PNG_USE_GLOBAL_ARRAYS +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# ifndef PNG_USE_LOCAL_ARRAYS +# define PNG_USE_LOCAL_ARRAYS +# endif +# else +# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) +# ifdef PNG_USE_GLOBAL_ARRAYS +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# endif +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +#endif + +/* Do not use global arrays (helps with building DLL's) + * They are no longer used in libpng itself, since version 1.0.5c, + * but might be required for some pre-1.0.5c applications. + */ +#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# if defined(PNG_NO_GLOBAL_ARRAYS) || \ + (defined(__GNUC__) && defined(PNG_DLL)) || defined(_MSC_VER) +# define PNG_USE_LOCAL_ARRAYS +# else +# define PNG_USE_GLOBAL_ARRAYS +# endif +#endif + +#ifdef __CYGWIN__ +# undef PNGAPI +# define PNGAPI __cdecl +# undef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", + * you may get warnings regarding the linkage of png_zalloc and png_zfree. + * Don't ignore those warnings; you must also reset the default calling + * convention in your compiler to match your PNGAPI, and you must build + * zlib and your applications the same way you build libpng. + */ + +#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) +# ifndef PNG_NO_MODULEDEF +# define PNG_NO_MODULEDEF +# endif +#endif + +#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) +# define PNG_IMPEXP +#endif + +#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ + (( defined(_Windows) || defined(_WINDOWS) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) + +# ifndef PNGAPI +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif +# endif + +# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ + 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) +# define PNG_IMPEXP +# endif + +# ifndef PNG_IMPEXP + +# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol +# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol + + /* Borland/Microsoft */ +# if defined(_MSC_VER) || defined(__BORLANDC__) +# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) +# define PNG_EXPORT PNG_EXPORT_TYPE1 +# else +# define PNG_EXPORT PNG_EXPORT_TYPE2 +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP __export +# else +# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in + VC++ */ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ +# endif +# endif + +# ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP __declspec(dllexport) +# else +# define PNG_IMPEXP __declspec(dllimport) +# endif +# endif +# endif /* PNG_IMPEXP */ +#else /* !(DLL || non-cygwin WINDOWS) */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# ifndef PNGAPI +# define PNGAPI _System +# endif +# else +# if 0 /* ... other platforms, with other meanings */ +# endif +# endif +#endif + +#ifndef PNGAPI +# define PNGAPI +#endif +#ifndef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifdef PNG_BUILDSYMS +# ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END +# endif +# ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT +# endif +# endif +#endif + +#ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. + */ +# ifdef __GNUC__ +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif + + /* This specifically protects structure members that should only be + * accessed from within the library, therefore should be empty during + * a library build. + */ +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_DEPSTRUCT +# define PNG_DEPSTRUCT __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif /* PNG_PRIVATE */ +# endif /* __GNUC__ */ +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_DEPSTRUCT +# define PNG_DEPSTRUCT /* Access to this struct member is deprecated */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif + +/* User may want to use these so they are not in PNG_INTERNAL. Any library + * functions that are passed far data must be model independent. + */ + +#ifndef PNG_ABORT +# define PNG_ABORT() abort() +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) +#endif + +#ifdef USE_FAR_KEYWORD /* memory model independent fns */ +/* Use this to make far-to-near assignments */ +# define CHECK 1 +# define NOCHECK 0 +# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) +# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) +# define png_snprintf _fsnprintf /* Added to v 1.2.19 */ +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset +#else /* Use the usual functions */ +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# ifndef PNG_NO_SNPRINTF +# ifdef _MSC_VER +# define png_snprintf _snprintf /* Added to v 1.2.19 */ +# define png_snprintf2 _snprintf +# define png_snprintf6 _snprintf +# else +# define png_snprintf snprintf /* Added to v 1.2.19 */ +# define png_snprintf2 snprintf +# define png_snprintf6 snprintf +# endif +# else + /* You don't have or don't want to use snprintf(). Caution: Using + * sprintf instead of snprintf exposes your application to accidental + * or malevolent buffer overflows. If you don't have snprintf() + * as a general rule you should provide one (you can get one from + * Portable OpenSSH). + */ +# define png_snprintf(s1,n,fmt,x1) sprintf(s1,fmt,x1) +# define png_snprintf2(s1,n,fmt,x1,x2) sprintf(s1,fmt,x1,x2) +# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \ + sprintf(s1,fmt,x1,x2,x3,x4,x5,x6) +# endif +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset +#endif +/* End of memory model independent support */ + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +/* Added at libpng-1.2.8 */ +#endif /* PNG_VERSION_INFO_ONLY */ + +#endif /* PNGCONF_H */ diff --git a/main/source/includes/lpng1251/pngerror.c b/main/source/includes/lpng1251/pngerror.c index 1cd9f788..d8e79284 100644 --- a/main/source/includes/lpng1251/pngerror.c +++ b/main/source/includes/lpng1251/pngerror.c @@ -1,396 +1,396 @@ - -/* pngerror.c - stub functions for i/o and memory allocation - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all error handling. Users who - * need special error handling are expected to write replacement functions - * and use png_set_error_fn() to use those functions. See the instructions - * at each function. - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -static void /* PRIVATE */ -png_default_error PNGARG((png_structp png_ptr, - png_const_charp error_message)) PNG_NORETURN; -#ifdef PNG_WARNINGS_SUPPORTED -static void /* PRIVATE */ -png_default_warning PNGARG((png_structp png_ptr, - png_const_charp warning_message)); -#endif /* PNG_WARNINGS_SUPPORTED */ - -/* This function is called whenever there is a fatal error. This function - * should not be changed. If there is a need to handle errors differently, - * you should supply a replacement error function and use png_set_error_fn() - * to replace the error function at run-time. - */ -#ifdef PNG_ERROR_TEXT_SUPPORTED -void PNGAPI -png_error(png_structp png_ptr, png_const_charp error_message) -{ -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - char msg[16]; - if (png_ptr != NULL) - { - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) - { - if (*error_message == PNG_LITERAL_SHARP) - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - for (offset = 1; offset<15; offset++) - if (error_message[offset] == ' ') - break; - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - int i; - for (i = 0; i < offset - 1; i++) - msg[i] = error_message[i + 1]; - msg[i - 1] = '\0'; - error_message = msg; - } - else - error_message += offset; - } - else - { - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - msg[0] = '0'; - msg[1] = '\0'; - error_message = msg; - } - } - } - } -#endif - if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, error_message); - - /* If the custom handler doesn't exist, or if it returns, - use the default handler, which will not return. */ - png_default_error(png_ptr, error_message); -} -#else -void PNGAPI -png_err(png_structp png_ptr) -{ - /* Prior to 1.2.45 the error_fn received a NULL pointer, expressed - * erroneously as '\0', instead of the empty string "". This was - * apparently an error, introduced in libpng-1.2.20, and png_default_error - * will crash in this case. - */ - if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, ""); - - /* If the custom handler doesn't exist, or if it returns, - use the default handler, which will not return. */ - png_default_error(png_ptr, ""); -} -#endif /* PNG_ERROR_TEXT_SUPPORTED */ - -#ifdef PNG_WARNINGS_SUPPORTED -/* This function is called whenever there is a non-fatal error. This function - * should not be changed. If there is a need to handle warnings differently, - * you should supply a replacement warning function and use - * png_set_error_fn() to replace the warning function at run-time. - */ -void PNGAPI -png_warning(png_structp png_ptr, png_const_charp warning_message) -{ - int offset = 0; - if (png_ptr != NULL) - { -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) -#endif - { - if (*warning_message == PNG_LITERAL_SHARP) - { - for (offset = 1; offset < 15; offset++) - if (warning_message[offset] == ' ') - break; - } - } - } - if (png_ptr != NULL && png_ptr->warning_fn != NULL) - (*(png_ptr->warning_fn))(png_ptr, warning_message + offset); - else - png_default_warning(png_ptr, warning_message + offset); -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_benign_error(png_structp png_ptr, png_const_charp error_message) -{ - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); -} -#endif - -/* These utilities are used internally to build an error message that relates - * to the current chunk. The chunk name comes from png_ptr->chunk_name, - * this is used to prefix the message. The message is limited in length - * to 63 bytes, the name characters are output as hex digits wrapped in [] - * if the character is invalid. - */ -#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) -static PNG_CONST char png_digit[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' -}; - -#define PNG_MAX_ERROR_TEXT 64 -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) -static void /* PRIVATE */ -png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp - error_message) -{ - int iout = 0, iin = 0; - - while (iin < 4) - { - int c = png_ptr->chunk_name[iin++]; - if (isnonalpha(c)) - { - buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; - buffer[iout++] = png_digit[(c & 0xf0) >> 4]; - buffer[iout++] = png_digit[c & 0x0f]; - buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; - } - else - { - buffer[iout++] = (png_byte)c; - } - } - - if (error_message == NULL) - buffer[iout] = '\0'; - else - { - buffer[iout++] = ':'; - buffer[iout++] = ' '; - - iin = 0; - while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') - buffer[iout++] = error_message[iin++]; - - /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ - buffer[iout] = '\0'; - } -} - -#ifdef PNG_READ_SUPPORTED -void PNGAPI -png_chunk_error(png_structp png_ptr, png_const_charp error_message) -{ - char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) - png_error(png_ptr, error_message); - else - { - png_format_buffer(png_ptr, msg, error_message); - png_error(png_ptr, msg); - } -} -#endif /* PNG_READ_SUPPORTED */ -#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ - -#ifdef PNG_WARNINGS_SUPPORTED -void PNGAPI -png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) -{ - char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) - png_warning(png_ptr, warning_message); - else - { - png_format_buffer(png_ptr, msg, warning_message); - png_warning(png_ptr, msg); - } -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -#ifdef PNG_READ_SUPPORTED -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message) -{ - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) - png_chunk_warning(png_ptr, error_message); - else - png_chunk_error(png_ptr, error_message); -} -#endif -#endif /* PNG_READ_SUPPORTED */ - -/* This is the default error handling function. Note that replacements for - * this function MUST NOT RETURN, or the program will likely crash. This - * function is used by default, or if the program supplies NULL for the - * error function pointer in png_set_error_fn(). - */ -static void /* PRIVATE */ -png_default_error(png_structp png_ptr, png_const_charp error_message) -{ -#ifdef PNG_CONSOLE_IO_SUPPORTED -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*error_message == PNG_LITERAL_SHARP) - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - char error_number[16]; - for (offset = 0; offset<15; offset++) - { - error_number[offset] = error_message[offset + 1]; - if (error_message[offset] == ' ') - break; - } - if ((offset > 1) && (offset < 15)) - { - error_number[offset - 1] = '\0'; - fprintf(stderr, "libpng error no. %s: %s", - error_number, error_message + offset + 1); - fprintf(stderr, PNG_STRING_NEWLINE); - } - else - { - fprintf(stderr, "libpng error: %s, offset=%d", - error_message, offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -#endif - { - fprintf(stderr, "libpng error: %s", error_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } -#endif - -#ifdef PNG_SETJMP_SUPPORTED - if (png_ptr) - { -# ifdef USE_FAR_KEYWORD - { - jmp_buf jmpbuf; - png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf)); - longjmp(jmpbuf,1); - } -# else - longjmp(png_ptr->jmpbuf, 1); -# endif - } -#endif - /* Here if not setjmp support or if png_ptr is null. */ - PNG_ABORT(); -#ifndef PNG_CONSOLE_IO_SUPPORTED - PNG_UNUSED(error_message) /* Make compiler happy */ -#endif -} - -#ifdef PNG_WARNINGS_SUPPORTED -/* This function is called when there is a warning, but the library thinks - * it can continue anyway. Replacement functions don't have to do anything - * here if you don't want them to. In the default configuration, png_ptr is - * not used, but it is passed in case it may be useful. - */ -static void /* PRIVATE */ -png_default_warning(png_structp png_ptr, png_const_charp warning_message) -{ -#ifdef PNG_CONSOLE_IO_SUPPORTED -# ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*warning_message == PNG_LITERAL_SHARP) - { - int offset; - char warning_number[16]; - for (offset = 0; offset < 15; offset++) - { - warning_number[offset] = warning_message[offset + 1]; - if (warning_message[offset] == ' ') - break; - } - if ((offset > 1) && (offset < 15)) - { - warning_number[offset + 1] = '\0'; - fprintf(stderr, "libpng warning no. %s: %s", - warning_number, warning_message + offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - else - { - fprintf(stderr, "libpng warning: %s", - warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -# endif - { - fprintf(stderr, "libpng warning: %s", warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } -#else - PNG_UNUSED(warning_message) /* Make compiler happy */ -#endif - PNG_UNUSED(png_ptr) /* Make compiler happy */ -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -/* This function is called when the application wants to use another method - * of handling errors and warnings. Note that the error function MUST NOT - * return to the calling routine or serious problems will occur. The return - * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) - */ -void PNGAPI -png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warning_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->error_ptr = error_ptr; - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; -} - - -/* This function returns a pointer to the error_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy and png_read_destroy are called. - */ -png_voidp PNGAPI -png_get_error_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return NULL; - return ((png_voidp)png_ptr->error_ptr); -} - - -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -void PNGAPI -png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) -{ - if (png_ptr != NULL) - { - png_ptr->flags &= - ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); - } -} -#endif -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +/* pngerror.c - stub functions for i/o and memory allocation + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +static void /* PRIVATE */ +png_default_error PNGARG((png_structp png_ptr, + png_const_charp error_message)) PNG_NORETURN; +#ifdef PNG_WARNINGS_SUPPORTED +static void /* PRIVATE */ +png_default_warning PNGARG((png_structp png_ptr, + png_const_charp warning_message)); +#endif /* PNG_WARNINGS_SUPPORTED */ + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +#ifdef PNG_ERROR_TEXT_SUPPORTED +void PNGAPI +png_error(png_structp png_ptr, png_const_charp error_message) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr != NULL) + { + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') + break; + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + else + error_message += offset; + } + else + { + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } + } + } + } +#endif + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_ptr, error_message); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, error_message); +} +#else +void PNGAPI +png_err(png_structp png_ptr) +{ + /* Prior to 1.2.45 the error_fn received a NULL pointer, expressed + * erroneously as '\0', instead of the empty string "". This was + * apparently an error, introduced in libpng-1.2.20, and png_default_error + * will crash in this case. + */ + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_ptr, ""); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, ""); +} +#endif /* PNG_ERROR_TEXT_SUPPORTED */ + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_structp png_ptr, png_const_charp warning_message) +{ + int offset = 0; + if (png_ptr != NULL) + { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) +#endif + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') + break; + } + } + } + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_ptr, warning_message + offset); + else + png_default_warning(png_ptr, warning_message + offset); +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_benign_error(png_structp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); +} +#endif + +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * this is used to prefix the message. The message is limited in length + * to 63 bytes, the name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +static PNG_CONST char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +#define PNG_MAX_ERROR_TEXT 64 +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) +static void /* PRIVATE */ +png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp + error_message) +{ + int iout = 0, iin = 0; + + while (iin < 4) + { + int c = png_ptr->chunk_name[iin++]; + if (isnonalpha(c)) + { + buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; + } + else + { + buffer[iout++] = (png_byte)c; + } + } + + if (error_message == NULL) + buffer[iout] = '\0'; + else + { + buffer[iout++] = ':'; + buffer[iout++] = ' '; + + iin = 0; + while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') + buffer[iout++] = error_message[iin++]; + + /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ + buffer[iout] = '\0'; + } +} + +#ifdef PNG_READ_SUPPORTED +void PNGAPI +png_chunk_error(png_structp png_ptr, png_const_charp error_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_error(png_ptr, error_message); + else + { + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); + } +} +#endif /* PNG_READ_SUPPORTED */ +#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ + +#ifdef PNG_WARNINGS_SUPPORTED +void PNGAPI +png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_warning(png_ptr, warning_message); + else + { + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); + } +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +#ifdef PNG_READ_SUPPORTED +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_chunk_warning(png_ptr, error_message); + else + png_chunk_error(png_ptr, error_message); +} +#endif +#endif /* PNG_READ_SUPPORTED */ + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void /* PRIVATE */ +png_default_error(png_structp png_ptr, png_const_charp error_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { + error_number[offset] = error_message[offset + 1]; + if (error_message[offset] == ' ') + break; + } + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +#endif + { + fprintf(stderr, "libpng error: %s", error_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#endif + +#ifdef PNG_SETJMP_SUPPORTED + if (png_ptr) + { +# ifdef USE_FAR_KEYWORD + { + jmp_buf jmpbuf; + png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf)); + longjmp(jmpbuf,1); + } +# else + longjmp(png_ptr->jmpbuf, 1); +# endif + } +#endif + /* Here if not setjmp support or if png_ptr is null. */ + PNG_ABORT(); +#ifndef PNG_CONSOLE_IO_SUPPORTED + PNG_UNUSED(error_message) /* Make compiler happy */ +#endif +} + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_structp png_ptr, png_const_charp warning_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == PNG_LITERAL_SHARP) + { + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') + break; + } + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +# endif + { + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(warning_message) /* Make compiler happy */ +#endif + PNG_UNUSED(png_ptr) /* Make compiler happy */ +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) + */ +void PNGAPI +png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + return ((png_voidp)png_ptr->error_ptr); +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void PNGAPI +png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) +{ + if (png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pnggccrd.c b/main/source/includes/lpng1251/pnggccrd.c index 074df593..7eb7f67d 100644 --- a/main/source/includes/lpng1251/pnggccrd.c +++ b/main/source/includes/lpng1251/pnggccrd.c @@ -1,26 +1,26 @@ -/* pnggccrd.c - * - * Last changed in libpng 1.2.48 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This code snippet is for use by configure's compilation test. Most of the - * remainder of the file was removed from libpng-1.2.20, and all of the - * assembler code was removed from libpng-1.2.48. - */ - -#if (!defined _MSC_VER) && \ - defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \ - defined(PNG_MMX_CODE_SUPPORTED) - -int PNGAPI png_dummy_mmx_support(void); - -int PNGAPI png_dummy_mmx_support(void) -{ - /* 0: no MMX; 1: MMX supported; 2: not tested */ - return 2; -} -#endif +/* pnggccrd.c + * + * Last changed in libpng 1.2.48 [March 8, 2012] + * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This code snippet is for use by configure's compilation test. Most of the + * remainder of the file was removed from libpng-1.2.20, and all of the + * assembler code was removed from libpng-1.2.48. + */ + +#if (!defined _MSC_VER) && \ + defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \ + defined(PNG_MMX_CODE_SUPPORTED) + +int PNGAPI png_dummy_mmx_support(void); + +int PNGAPI png_dummy_mmx_support(void) +{ + /* 0: no MMX; 1: MMX supported; 2: not tested */ + return 2; +} +#endif diff --git a/main/source/includes/lpng1251/pngget.c b/main/source/includes/lpng1251/pngget.c index 9f291910..c5d65433 100644 --- a/main/source/includes/lpng1251/pngget.c +++ b/main/source/includes/lpng1251/pngget.c @@ -1,944 +1,944 @@ - -/* pngget.c - retrieval of values from info struct - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -png_uint_32 PNGAPI -png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->valid & flag); - - else - return(0); -} - -png_uint_32 PNGAPI -png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->rowbytes); - - else - return(0); -} - -#ifdef PNG_INFO_IMAGE_SUPPORTED -png_bytepp PNGAPI -png_get_rows(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->row_pointers); - - else - return(0); -} -#endif - -#ifdef PNG_EASY_ACCESS_SUPPORTED -/* Easy access to info, added in libpng-0.99 */ -png_uint_32 PNGAPI -png_get_image_width(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->width; - - return (0); -} - -png_uint_32 PNGAPI -png_get_image_height(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->height; - - return (0); -} - -png_byte PNGAPI -png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->bit_depth; - - return (0); -} - -png_byte PNGAPI -png_get_color_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->color_type; - - return (0); -} - -png_byte PNGAPI -png_get_filter_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->filter_type; - - return (0); -} - -png_byte PNGAPI -png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->interlace_type; - - return (0); -} - -png_byte PNGAPI -png_get_compression_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->compression_type; - - return (0); -} - -png_uint_32 PNGAPI -png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#ifdef PNG_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); - - if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) - return (0); - - else - return (info_ptr->x_pixels_per_unit); - } -#else - return (0); -#endif - return (0); -} - -png_uint_32 PNGAPI -png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#ifdef PNG_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); - - if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) - return (0); - - else - return (info_ptr->y_pixels_per_unit); - } -#else - return (0); -#endif - return (0); -} - -png_uint_32 PNGAPI -png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#ifdef PNG_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); - - if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER || - info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) - return (0); - - else - return (info_ptr->x_pixels_per_unit); - } -#else - return (0); -#endif - return (0); -} - -#ifdef PNG_FLOATING_POINT_SUPPORTED -float PNGAPI -png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) - { - if (png_ptr != NULL && info_ptr != NULL) -#ifdef PNG_pHYs_SUPPORTED - - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); - - if (info_ptr->x_pixels_per_unit == 0) - return ((float)0.0); - - else - return ((float)((float)info_ptr->y_pixels_per_unit - /(float)info_ptr->x_pixels_per_unit)); - } -#else - return (0.0); -#endif - return ((float)0.0); -} -#endif - -png_int_32 PNGAPI -png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#ifdef PNG_oFFs_SUPPORTED - - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) - return (0); - - else - return (info_ptr->x_offset); - } -#else - return (0); -#endif - return (0); -} - -png_int_32 PNGAPI -png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - -#ifdef PNG_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) - return (0); - - else - return (info_ptr->y_offset); - } -#else - return (0); -#endif - return (0); -} - -png_int_32 PNGAPI -png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - -#ifdef PNG_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) - return (0); - - else - return (info_ptr->x_offset); - } -#else - return (0); -#endif - return (0); -} - -png_int_32 PNGAPI -png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - -#ifdef PNG_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) - return (0); - - else - return (info_ptr->y_offset); - } -#else - return (0); -#endif - return (0); -} - -#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) -png_uint_32 PNGAPI -png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); -} - -png_uint_32 PNGAPI -png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); -} - -png_uint_32 PNGAPI -png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); -} - -float PNGAPI -png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) -{ - return ((float)png_get_x_offset_microns(png_ptr, info_ptr) - *.00003937); -} - -float PNGAPI -png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) -{ - return ((float)png_get_y_offset_microns(png_ptr, info_ptr) - *.00003937); -} - -#ifdef PNG_pHYs_SUPPORTED -png_uint_32 PNGAPI -png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) -{ - png_uint_32 retval = 0; - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", "pHYs"); - - if (res_x != NULL) - { - *res_x = info_ptr->x_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - if (res_y != NULL) - { - *res_y = info_ptr->y_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - if (unit_type != NULL) - { - *unit_type = (int)info_ptr->phys_unit_type; - retval |= PNG_INFO_pHYs; - if (*unit_type == 1) - { - if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); - if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); - } - } - } - return (retval); -} -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ - -/* png_get_channels really belongs in here, too, but it's been around longer */ - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ - -png_byte PNGAPI -png_get_channels(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->channels); - else - return (0); -} - -png_bytep PNGAPI -png_get_signature(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->signature); - else - return (NULL); -} - -#ifdef PNG_bKGD_SUPPORTED -png_uint_32 PNGAPI -png_get_bKGD(png_structp png_ptr, png_infop info_ptr, - png_color_16p *background) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) - && background != NULL) - { - png_debug1(1, "in %s retrieval function", "bKGD"); - - *background = &(info_ptr->background); - return (PNG_INFO_bKGD); - } - return (0); -} -#endif - -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cHRM(png_structp png_ptr, png_infop info_ptr, - double *white_x, double *white_y, double *red_x, double *red_y, - double *green_x, double *green_y, double *blue_x, double *blue_y) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - { - png_debug1(1, "in %s retrieval function", "cHRM"); - - if (white_x != NULL) - *white_x = (double)info_ptr->x_white; - if (white_y != NULL) - *white_y = (double)info_ptr->y_white; - if (red_x != NULL) - *red_x = (double)info_ptr->x_red; - if (red_y != NULL) - *red_y = (double)info_ptr->y_red; - if (green_x != NULL) - *green_x = (double)info_ptr->x_green; - if (green_y != NULL) - *green_y = (double)info_ptr->y_green; - if (blue_x != NULL) - *blue_x = (double)info_ptr->x_blue; - if (blue_y != NULL) - *blue_y = (double)info_ptr->y_blue; - return (PNG_INFO_cHRM); - } - return (0); -} -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, - png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, - png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, - png_fixed_point *blue_x, png_fixed_point *blue_y) -{ - png_debug1(1, "in %s retrieval function", "cHRM"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - { - if (white_x != NULL) - *white_x = info_ptr->int_x_white; - if (white_y != NULL) - *white_y = info_ptr->int_y_white; - if (red_x != NULL) - *red_x = info_ptr->int_x_red; - if (red_y != NULL) - *red_y = info_ptr->int_y_red; - if (green_x != NULL) - *green_x = info_ptr->int_x_green; - if (green_y != NULL) - *green_y = info_ptr->int_y_green; - if (blue_x != NULL) - *blue_x = info_ptr->int_x_blue; - if (blue_y != NULL) - *blue_y = info_ptr->int_y_blue; - return (PNG_INFO_cHRM); - } - return (0); -} -#endif -#endif - -#ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) -{ - png_debug1(1, "in %s retrieval function", "gAMA"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && file_gamma != NULL) - { - *file_gamma = (double)info_ptr->gamma; - return (PNG_INFO_gAMA); - } - return (0); -} -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, - png_fixed_point *int_file_gamma) -{ - png_debug1(1, "in %s retrieval function", "gAMA"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && int_file_gamma != NULL) - { - *int_file_gamma = info_ptr->int_gamma; - return (PNG_INFO_gAMA); - } - return (0); -} -#endif -#endif - -#ifdef PNG_sRGB_SUPPORTED -png_uint_32 PNGAPI -png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) -{ - png_debug1(1, "in %s retrieval function", "sRGB"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) - && file_srgb_intent != NULL) - { - *file_srgb_intent = (int)info_ptr->srgb_intent; - return (PNG_INFO_sRGB); - } - return (0); -} -#endif - -#ifdef PNG_iCCP_SUPPORTED -png_uint_32 PNGAPI -png_get_iCCP(png_structp png_ptr, png_infop info_ptr, - png_charpp name, int *compression_type, - png_charpp profile, png_uint_32 *proflen) -{ - png_debug1(1, "in %s retrieval function", "iCCP"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) - && name != NULL && profile != NULL && proflen != NULL) - { - *name = info_ptr->iccp_name; - *profile = info_ptr->iccp_profile; - /* Compression_type is a dummy so the API won't have to change - * if we introduce multiple compression types later. - */ - *proflen = (int)info_ptr->iccp_proflen; - *compression_type = (int)info_ptr->iccp_compression; - return (PNG_INFO_iCCP); - } - return (0); -} -#endif - -#ifdef PNG_sPLT_SUPPORTED -png_uint_32 PNGAPI -png_get_sPLT(png_structp png_ptr, png_infop info_ptr, - png_sPLT_tpp spalettes) -{ - if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) - { - *spalettes = info_ptr->splt_palettes; - return ((png_uint_32)info_ptr->splt_palettes_num); - } - return (0); -} -#endif - -#ifdef PNG_hIST_SUPPORTED -png_uint_32 PNGAPI -png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) -{ - png_debug1(1, "in %s retrieval function", "hIST"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) - && hist != NULL) - { - *hist = info_ptr->hist; - return (PNG_INFO_hIST); - } - return (0); -} -#endif - -png_uint_32 PNGAPI -png_get_IHDR(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *width, png_uint_32 *height, int *bit_depth, - int *color_type, int *interlace_type, int *compression_type, - int *filter_type) - -{ - png_debug1(1, "in %s retrieval function", "IHDR"); - - if (png_ptr == NULL || info_ptr == NULL || width == NULL || - height == NULL || bit_depth == NULL || color_type == NULL) - return (0); - - *width = info_ptr->width; - *height = info_ptr->height; - *bit_depth = info_ptr->bit_depth; - *color_type = info_ptr->color_type; - - if (compression_type != NULL) - *compression_type = info_ptr->compression_type; - - if (filter_type != NULL) - *filter_type = info_ptr->filter_type; - - if (interlace_type != NULL) - *interlace_type = info_ptr->interlace_type; - - /* This is redundant if we can be sure that the info_ptr values were all - * assigned in png_set_IHDR(). We do the check anyhow in case an - * application has ignored our advice not to mess with the members - * of info_ptr directly. - */ - png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, - info_ptr->compression_type, info_ptr->filter_type); - - return (1); -} - -#ifdef PNG_oFFs_SUPPORTED -png_uint_32 PNGAPI -png_get_oFFs(png_structp png_ptr, png_infop info_ptr, - png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) -{ - png_debug1(1, "in %s retrieval function", "oFFs"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) - && offset_x != NULL && offset_y != NULL && unit_type != NULL) - { - *offset_x = info_ptr->x_offset; - *offset_y = info_ptr->y_offset; - *unit_type = (int)info_ptr->offset_unit_type; - return (PNG_INFO_oFFs); - } - return (0); -} -#endif - -#ifdef PNG_pCAL_SUPPORTED -png_uint_32 PNGAPI -png_get_pCAL(png_structp png_ptr, png_infop info_ptr, - png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, - png_charp *units, png_charpp *params) -{ - png_debug1(1, "in %s retrieval function", "pCAL"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) - && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && - nparams != NULL && units != NULL && params != NULL) - { - *purpose = info_ptr->pcal_purpose; - *X0 = info_ptr->pcal_X0; - *X1 = info_ptr->pcal_X1; - *type = (int)info_ptr->pcal_type; - *nparams = (int)info_ptr->pcal_nparams; - *units = info_ptr->pcal_units; - *params = info_ptr->pcal_params; - return (PNG_INFO_pCAL); - } - return (0); -} -#endif - -#ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_sCAL(png_structp png_ptr, png_infop info_ptr, - int *unit, double *width, double *height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - *width = info_ptr->scal_pixel_width; - *height = info_ptr->scal_pixel_height; - return (PNG_INFO_sCAL); - } - return(0); -} -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, - int *unit, png_charpp width, png_charpp height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - *width = info_ptr->scal_s_width; - *height = info_ptr->scal_s_height; - return (PNG_INFO_sCAL); - } - return(0); -} -#endif -#endif -#endif - -#ifdef PNG_pHYs_SUPPORTED -png_uint_32 PNGAPI -png_get_pHYs(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) -{ - png_uint_32 retval = 0; - - png_debug1(1, "in %s retrieval function", "pHYs"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs)) - { - if (res_x != NULL) - { - *res_x = info_ptr->x_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (res_y != NULL) - { - *res_y = info_ptr->y_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (unit_type != NULL) - { - *unit_type = (int)info_ptr->phys_unit_type; - retval |= PNG_INFO_pHYs; - } - } - return (retval); -} -#endif - -png_uint_32 PNGAPI -png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, - int *num_palette) -{ - png_debug1(1, "in %s retrieval function", "PLTE"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) - && palette != NULL) - { - *palette = info_ptr->palette; - *num_palette = info_ptr->num_palette; - png_debug1(3, "num_palette = %d", *num_palette); - return (PNG_INFO_PLTE); - } - return (0); -} - -#ifdef PNG_sBIT_SUPPORTED -png_uint_32 PNGAPI -png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) -{ - png_debug1(1, "in %s retrieval function", "sBIT"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) - && sig_bit != NULL) - { - *sig_bit = &(info_ptr->sig_bit); - return (PNG_INFO_sBIT); - } - return (0); -} -#endif - -#ifdef PNG_TEXT_SUPPORTED -png_uint_32 PNGAPI -png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, - int *num_text) -{ - if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) - { - png_debug1(1, "in %s retrieval function", - (png_ptr->chunk_name[0] == '\0' ? "text" - : (png_const_charp)png_ptr->chunk_name)); - - if (text_ptr != NULL) - *text_ptr = info_ptr->text; - - if (num_text != NULL) - *num_text = info_ptr->num_text; - - return ((png_uint_32)info_ptr->num_text); - } - if (num_text != NULL) - *num_text = 0; - return(0); -} -#endif - -#ifdef PNG_tIME_SUPPORTED -png_uint_32 PNGAPI -png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) -{ - png_debug1(1, "in %s retrieval function", "tIME"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) - && mod_time != NULL) - { - *mod_time = &(info_ptr->mod_time); - return (PNG_INFO_tIME); - } - return (0); -} -#endif - -#ifdef PNG_tRNS_SUPPORTED -png_uint_32 PNGAPI -png_get_tRNS(png_structp png_ptr, png_infop info_ptr, - png_bytep *trans, int *num_trans, png_color_16p *trans_values) -{ - png_uint_32 retval = 0; - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - png_debug1(1, "in %s retrieval function", "tRNS"); - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (trans != NULL) - { - *trans = info_ptr->trans; - retval |= PNG_INFO_tRNS; - } - - if (trans_values != NULL) - *trans_values = &(info_ptr->trans_values); - } - else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ - { - if (trans_values != NULL) - { - *trans_values = &(info_ptr->trans_values); - retval |= PNG_INFO_tRNS; - } - - if (trans != NULL) - *trans = NULL; - } - if (num_trans != NULL) - { - *num_trans = info_ptr->num_trans; - retval |= PNG_INFO_tRNS; - } - } - return (retval); -} -#endif - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -png_uint_32 PNGAPI -png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, - png_unknown_chunkpp unknowns) -{ - if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) - { - *unknowns = info_ptr->unknown_chunks; - return ((png_uint_32)info_ptr->unknown_chunks_num); - } - return (0); -} -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -png_byte PNGAPI -png_get_rgb_to_gray_status (png_structp png_ptr) -{ - return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); -} -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -png_voidp PNGAPI -png_get_user_chunk_ptr(png_structp png_ptr) -{ - return (png_ptr? png_ptr->user_chunk_ptr : NULL); -} -#endif - -png_uint_32 PNGAPI -png_get_compression_buffer_size(png_structp png_ptr) -{ - return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L); -} - -#ifdef PNG_ASSEMBLER_CODE_SUPPORTED -#ifndef PNG_1_0_X -/* This function was added to libpng 1.2.0 and should exist by default */ -png_uint_32 PNGAPI -png_get_asm_flags (png_structp png_ptr) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return (png_ptr? 0L: 0L); -} - -/* This function was added to libpng 1.2.0 and should exist by default */ -png_uint_32 PNGAPI -png_get_asm_flagmask (int flag_select) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - PNG_UNUSED(flag_select) - return 0L; -} - - /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */ -/* This function was added to libpng 1.2.0 */ -png_uint_32 PNGAPI -png_get_mmx_flagmask (int flag_select, int *compilerID) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - PNG_UNUSED(flag_select) - *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */ - return 0L; -} - -/* This function was added to libpng 1.2.0 */ -png_byte PNGAPI -png_get_mmx_bitdepth_threshold (png_structp png_ptr) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return (png_ptr? 0: 0); -} - -/* This function was added to libpng 1.2.0 */ -png_uint_32 PNGAPI -png_get_mmx_rowbytes_threshold (png_structp png_ptr) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return (png_ptr? 0L: 0L); -} -#endif /* ?PNG_1_0_X */ -#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -/* These functions were added to libpng 1.2.6 but not enabled -* by default. They will be enabled in libpng-1.4.0 */ -png_uint_32 PNGAPI -png_get_user_width_max (png_structp png_ptr) -{ - return (png_ptr? png_ptr->user_width_max : 0); -} -png_uint_32 PNGAPI -png_get_user_height_max (png_structp png_ptr) -{ - return (png_ptr? png_ptr->user_height_max : 0); -} -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ - -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +/* pngget.c - retrieval of values from info struct + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +png_uint_32 PNGAPI +png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->valid & flag); + + else + return(0); +} + +png_uint_32 PNGAPI +png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->rowbytes); + + else + return(0); +} + +#ifdef PNG_INFO_IMAGE_SUPPORTED +png_bytepp PNGAPI +png_get_rows(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->row_pointers); + + else + return(0); +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->width; + + return (0); +} + +png_uint_32 PNGAPI +png_get_image_height(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->height; + + return (0); +} + +png_byte PNGAPI +png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->bit_depth; + + return (0); +} + +png_byte PNGAPI +png_get_color_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->color_type; + + return (0); +} + +png_byte PNGAPI +png_get_filter_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->filter_type; + + return (0); +} + +png_byte PNGAPI +png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->interlace_type; + + return (0); +} + +png_byte PNGAPI +png_get_compression_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->compression_type; + + return (0); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); + + if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + + else + return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); + + if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + + else + return (info_ptr->y_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); + + if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER || + info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) + return (0); + + else + return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) + { + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); + + if (info_ptr->x_pixels_per_unit == 0) + return ((float)0.0); + + else + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); + } +#else + return (0.0); +#endif + return ((float)0.0); +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_oFFs_SUPPORTED + + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + + else + return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + +#ifdef PNG_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + + else + return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + +#ifdef PNG_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + + else + return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + +#ifdef PNG_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + + else + return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +float PNGAPI +png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_x_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +float PNGAPI +png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_y_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + if (*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + return (retval); +} +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +png_byte PNGAPI +png_get_channels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->channels); + else + return (0); +} + +png_bytep PNGAPI +png_get_signature(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->signature); + else + return (NULL); +} + +#ifdef PNG_bKGD_SUPPORTED +png_uint_32 PNGAPI +png_get_bKGD(png_structp png_ptr, png_infop info_ptr, + png_color_16p *background) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) + && background != NULL) + { + png_debug1(1, "in %s retrieval function", "bKGD"); + + *background = &(info_ptr->background); + return (PNG_INFO_bKGD); + } + return (0); +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_structp png_ptr, png_infop info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (white_x != NULL) + *white_x = (double)info_ptr->x_white; + if (white_y != NULL) + *white_y = (double)info_ptr->y_white; + if (red_x != NULL) + *red_x = (double)info_ptr->x_red; + if (red_y != NULL) + *red_y = (double)info_ptr->y_red; + if (green_x != NULL) + *green_x = (double)info_ptr->x_green; + if (green_y != NULL) + *green_y = (double)info_ptr->y_green; + if (blue_x != NULL) + *blue_x = (double)info_ptr->x_blue; + if (blue_y != NULL) + *blue_y = (double)info_ptr->y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + if (white_x != NULL) + *white_x = info_ptr->int_x_white; + if (white_y != NULL) + *white_y = info_ptr->int_y_white; + if (red_x != NULL) + *red_x = info_ptr->int_x_red; + if (red_y != NULL) + *red_y = info_ptr->int_y_red; + if (green_x != NULL) + *green_x = info_ptr->int_x_green; + if (green_y != NULL) + *green_y = info_ptr->int_y_green; + if (blue_x != NULL) + *blue_x = info_ptr->int_x_blue; + if (blue_y != NULL) + *blue_y = info_ptr->int_y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && file_gamma != NULL) + { + *file_gamma = (double)info_ptr->gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *int_file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && int_file_gamma != NULL) + { + *int_file_gamma = info_ptr->int_gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#endif + +#ifdef PNG_sRGB_SUPPORTED +png_uint_32 PNGAPI +png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) +{ + png_debug1(1, "in %s retrieval function", "sRGB"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) + && file_srgb_intent != NULL) + { + *file_srgb_intent = (int)info_ptr->srgb_intent; + return (PNG_INFO_sRGB); + } + return (0); +} +#endif + +#ifdef PNG_iCCP_SUPPORTED +png_uint_32 PNGAPI +png_get_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen) +{ + png_debug1(1, "in %s retrieval function", "iCCP"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) + && name != NULL && profile != NULL && proflen != NULL) + { + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + /* Compression_type is a dummy so the API won't have to change + * if we introduce multiple compression types later. + */ + *proflen = (int)info_ptr->iccp_proflen; + *compression_type = (int)info_ptr->iccp_compression; + return (PNG_INFO_iCCP); + } + return (0); +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +png_uint_32 PNGAPI +png_get_sPLT(png_structp png_ptr, png_infop info_ptr, + png_sPLT_tpp spalettes) +{ + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + { + *spalettes = info_ptr->splt_palettes; + return ((png_uint_32)info_ptr->splt_palettes_num); + } + return (0); +} +#endif + +#ifdef PNG_hIST_SUPPORTED +png_uint_32 PNGAPI +png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) +{ + png_debug1(1, "in %s retrieval function", "hIST"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) + && hist != NULL) + { + *hist = info_ptr->hist; + return (PNG_INFO_hIST); + } + return (0); +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) + +{ + png_debug1(1, "in %s retrieval function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL || width == NULL || + height == NULL || bit_depth == NULL || color_type == NULL) + return (0); + + *width = info_ptr->width; + *height = info_ptr->height; + *bit_depth = info_ptr->bit_depth; + *color_type = info_ptr->color_type; + + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* This is redundant if we can be sure that the info_ptr values were all + * assigned in png_set_IHDR(). We do the check anyhow in case an + * application has ignored our advice not to mess with the members + * of info_ptr directly. + */ + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + return (1); +} + +#ifdef PNG_oFFs_SUPPORTED +png_uint_32 PNGAPI +png_get_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + png_debug1(1, "in %s retrieval function", "oFFs"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) + && offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return (PNG_INFO_oFFs); + } + return (0); +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +png_uint_32 PNGAPI +png_get_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + png_debug1(1, "in %s retrieval function", "pCAL"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) + && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return (PNG_INFO_pCAL); + } + return (0); +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_structp png_ptr, png_infop info_ptr, + int *unit, double *width, double *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_pixel_width; + *height = info_ptr->scal_pixel_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#endif +#endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs)) + { + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + return (retval); +} +#endif + +png_uint_32 PNGAPI +png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, + int *num_palette) +{ + png_debug1(1, "in %s retrieval function", "PLTE"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) + && palette != NULL) + { + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d", *num_palette); + return (PNG_INFO_PLTE); + } + return (0); +} + +#ifdef PNG_sBIT_SUPPORTED +png_uint_32 PNGAPI +png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) +{ + png_debug1(1, "in %s retrieval function", "sBIT"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) + && sig_bit != NULL) + { + *sig_bit = &(info_ptr->sig_bit); + return (PNG_INFO_sBIT); + } + return (0); +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +png_uint_32 PNGAPI +png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, + int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in %s retrieval function", + (png_ptr->chunk_name[0] == '\0' ? "text" + : (png_const_charp)png_ptr->chunk_name)); + + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + + if (num_text != NULL) + *num_text = info_ptr->num_text; + + return ((png_uint_32)info_ptr->num_text); + } + if (num_text != NULL) + *num_text = 0; + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +png_uint_32 PNGAPI +png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) +{ + png_debug1(1, "in %s retrieval function", "tIME"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) + && mod_time != NULL) + { + *mod_time = &(info_ptr->mod_time); + return (PNG_INFO_tIME); + } + return (0); +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +png_uint_32 PNGAPI +png_get_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep *trans, int *num_trans, png_color_16p *trans_values) +{ + png_uint_32 retval = 0; + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_debug1(1, "in %s retrieval function", "tRNS"); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans != NULL) + { + *trans = info_ptr->trans; + retval |= PNG_INFO_tRNS; + } + + if (trans_values != NULL) + *trans_values = &(info_ptr->trans_values); + } + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_values != NULL) + { + *trans_values = &(info_ptr->trans_values); + retval |= PNG_INFO_tRNS; + } + + if (trans != NULL) + *trans = NULL; + } + if (num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + return (retval); +} +#endif + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +png_uint_32 PNGAPI +png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + { + *unknowns = info_ptr->unknown_chunks; + return ((png_uint_32)info_ptr->unknown_chunks_num); + } + return (0); +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +png_byte PNGAPI +png_get_rgb_to_gray_status (png_structp png_ptr) +{ + return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +png_voidp PNGAPI +png_get_user_chunk_ptr(png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_chunk_ptr : NULL); +} +#endif + +png_uint_32 PNGAPI +png_get_compression_buffer_size(png_structp png_ptr) +{ + return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L); +} + +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +#ifndef PNG_1_0_X +/* This function was added to libpng 1.2.0 and should exist by default */ +png_uint_32 PNGAPI +png_get_asm_flags (png_structp png_ptr) +{ + /* Obsolete, to be removed from libpng-1.4.0 */ + return (png_ptr? 0L: 0L); +} + +/* This function was added to libpng 1.2.0 and should exist by default */ +png_uint_32 PNGAPI +png_get_asm_flagmask (int flag_select) +{ + /* Obsolete, to be removed from libpng-1.4.0 */ + PNG_UNUSED(flag_select) + return 0L; +} + + /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */ +/* This function was added to libpng 1.2.0 */ +png_uint_32 PNGAPI +png_get_mmx_flagmask (int flag_select, int *compilerID) +{ + /* Obsolete, to be removed from libpng-1.4.0 */ + PNG_UNUSED(flag_select) + *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */ + return 0L; +} + +/* This function was added to libpng 1.2.0 */ +png_byte PNGAPI +png_get_mmx_bitdepth_threshold (png_structp png_ptr) +{ + /* Obsolete, to be removed from libpng-1.4.0 */ + return (png_ptr? 0: 0); +} + +/* This function was added to libpng 1.2.0 */ +png_uint_32 PNGAPI +png_get_mmx_rowbytes_threshold (png_structp png_ptr) +{ + /* Obsolete, to be removed from libpng-1.4.0 */ + return (png_ptr? 0L: 0L); +} +#endif /* ?PNG_1_0_X */ +#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* These functions were added to libpng 1.2.6 but not enabled +* by default. They will be enabled in libpng-1.4.0 */ +png_uint_32 PNGAPI +png_get_user_width_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_width_max : 0); +} +png_uint_32 PNGAPI +png_get_user_height_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_height_max : 0); +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngmem.c b/main/source/includes/lpng1251/pngmem.c index 019c7d25..a18719b8 100644 --- a/main/source/includes/lpng1251/pngmem.c +++ b/main/source/includes/lpng1251/pngmem.c @@ -1,641 +1,641 @@ - -/* pngmem.c - stub functions for memory allocation - * - * Last changed in libpng 1.2.41 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all memory allocation. Users who - * need special memory handling are expected to supply replacement - * functions for png_malloc() and png_free(), and to use - * png_create_read_struct_2() and png_create_write_struct_2() to - * identify the replacement functions. - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -/* Borland DOS special memory handler */ -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* If you change this, be sure to change the one in png.h also */ - -/* Allocate memory for a png_struct. The malloc and memset can be replaced - by a single call to calloc() if this is thought to improve performance. */ -png_voidp /* PRIVATE */ -png_create_struct(int type) -{ -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); -} - -/* Alternate version of png_create_struct, for use with user-defined malloc. */ -png_voidp /* PRIVATE */ -png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - png_size_t size; - png_voidp struct_ptr; - - if (type == PNG_STRUCT_INFO) - size = png_sizeof(png_info); - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - else - return (png_get_copyright(NULL)); - -#ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size); - } - else -#endif /* PNG_USER_MEM_SUPPORTED */ - struct_ptr = (png_voidp)farmalloc(size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - return (struct_ptr); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) -{ -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, - png_voidp mem_ptr) -{ -#endif - if (struct_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - if (free_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - (*(free_fn))(png_ptr, struct_ptr); - return; - } -#endif /* PNG_USER_MEM_SUPPORTED */ - farfree (struct_ptr); - } -} - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - * - * Borland seems to have a problem in DOS mode for exactly 64K. - * It gives you a segment with an offset of 8 (perhaps to store its - * memory stuff). zlib doesn't like this at all, so we have to - * detect and deal with it. This code should not be needed in - * Windows or OS/2 modes, and only in 16 bit mode. This code has - * been updated by Alexander Lehmann for version 0.89 to waste less - * memory. - * - * Note that we can't use png_size_t for the "size" declaration, - * since on some systems a png_size_t is a 16-bit quantity, and as a - * result, we would be truncating potentially larger memory requests - * (which should cause a fatal error) and introducing major problems. - */ -png_voidp /* PRIVATE */ -png_calloc(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; - - ret = (png_malloc(png_ptr, size)); - if (ret != NULL) - png_memset(ret,0,(png_size_t)size); - return (ret); -} - -png_voidp PNGAPI -png_malloc(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - else - ret = (png_malloc_default(png_ptr, size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory!"); - return (ret); -} - -png_voidp PNGAPI -png_malloc_default(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { - png_warning(png_ptr, "Cannot Allocate > 64K"); - ret = NULL; - } - else -#endif - - if (size != (size_t)size) - ret = NULL; - else if (size == (png_uint_32)65536L) - { - if (png_ptr->offset_table == NULL) - { - /* Try to see if we need to do any of this fancy stuff */ - ret = farmalloc(size); - if (ret == NULL || ((png_size_t)ret & 0xffff)) - { - int num_blocks; - png_uint_32 total_size; - png_bytep table; - int i; - png_byte huge * hptr; - - if (ret != NULL) - { - farfree(ret); - ret = NULL; - } - - if (png_ptr->zlib_window_bits > 14) - num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); - else - num_blocks = 1; - if (png_ptr->zlib_mem_level >= 7) - num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); - else - num_blocks++; - - total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; - - table = farmalloc(total_size); - - if (table == NULL) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of Memory."); /* Note "O", "M" */ - else - png_warning(png_ptr, "Out Of Memory."); -#endif - return (NULL); - } - - if ((png_size_t)table & 0xfff0) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, - "Farmalloc didn't return normalized pointer"); - else - png_warning(png_ptr, - "Farmalloc didn't return normalized pointer"); -#endif - return (NULL); - } - - png_ptr->offset_table = table; - png_ptr->offset_table_ptr = farmalloc(num_blocks * - png_sizeof(png_bytep)); - - if (png_ptr->offset_table_ptr == NULL) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of memory."); /* Note "O", "m" */ - else - png_warning(png_ptr, "Out Of memory."); -#endif - return (NULL); - } - - hptr = (png_byte huge *)table; - if ((png_size_t)hptr & 0xf) - { - hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); - hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ - } - for (i = 0; i < num_blocks; i++) - { - png_ptr->offset_table_ptr[i] = (png_bytep)hptr; - hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ - } - - png_ptr->offset_table_number = num_blocks; - png_ptr->offset_table_count = 0; - png_ptr->offset_table_count_free = 0; - } - } - - if (png_ptr->offset_table_count >= png_ptr->offset_table_number) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */ - else - png_warning(png_ptr, "Out of Memory."); -#endif - return (NULL); - } - - ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; - } - else - ret = farmalloc(size); - -#ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL) - { - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */ - else - png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */ - } -#endif - - return (ret); -} - -/* Free a pointer allocated by png_malloc(). In the default - * configuration, png_ptr is not used, but is passed in case it - * is needed. If ptr is NULL, return without taking any action. - */ -void PNGAPI -png_free(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->free_fn != NULL) - { - (*(png_ptr->free_fn))(png_ptr, ptr); - return; - } - else - png_free_default(png_ptr, ptr); -} - -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || ptr == NULL) - return; - - if (png_ptr->offset_table != NULL) - { - int i; - - for (i = 0; i < png_ptr->offset_table_count; i++) - { - if (ptr == png_ptr->offset_table_ptr[i]) - { - ptr = NULL; - png_ptr->offset_table_count_free++; - break; - } - } - if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) - { - farfree(png_ptr->offset_table); - farfree(png_ptr->offset_table_ptr); - png_ptr->offset_table = NULL; - png_ptr->offset_table_ptr = NULL; - } - } - - if (ptr != NULL) - { - farfree(ptr); - } -} - -#else /* Not the Borland DOS special memory handler */ - -/* Allocate memory for a png_struct or a png_info. The malloc and - memset can be replaced by a single call to calloc() if this is thought - to improve performance noticably. */ -png_voidp /* PRIVATE */ -png_create_struct(int type) -{ -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); -} - -/* Allocate memory for a png_struct or a png_info. The malloc and - memset can be replaced by a single call to calloc() if this is thought - to improve performance noticably. */ -png_voidp /* PRIVATE */ -png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - png_size_t size; - png_voidp struct_ptr; - - if (type == PNG_STRUCT_INFO) - size = png_sizeof(png_info); - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - else - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - return (struct_ptr); - } -#endif /* PNG_USER_MEM_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(__FLAT__) - struct_ptr = (png_voidp)farmalloc(size); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - struct_ptr = (png_voidp)halloc(size, 1); -# else - struct_ptr = (png_voidp)malloc(size); -# endif -#endif - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - - return (struct_ptr); -} - - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) -{ -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, - png_voidp mem_ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - if (struct_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - if (free_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - (*(free_fn))(png_ptr, struct_ptr); - return; - } -#endif /* PNG_USER_MEM_SUPPORTED */ -#if defined(__TURBOC__) && !defined(__FLAT__) - farfree(struct_ptr); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - hfree(struct_ptr); -# else - free(struct_ptr); -# endif -#endif - } -} - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - */ - -png_voidp /* PRIVATE */ -png_calloc(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; - - ret = (png_malloc(png_ptr, size)); - if (ret != NULL) - png_memset(ret,0,(png_size_t)size); - return (ret); -} - -png_voidp PNGAPI -png_malloc(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr == NULL || size == 0) - return (NULL); - - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - else - ret = (png_malloc_default(png_ptr, size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory!"); - return (ret); -} - -png_voidp PNGAPI -png_malloc_default(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Cannot Allocate > 64K"); - else -#endif - return NULL; - } -#endif - - /* Check for overflow */ -#if defined(__TURBOC__) && !defined(__FLAT__) - if (size != (unsigned long)size) - ret = NULL; - else - ret = farmalloc(size); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - if (size != (unsigned long)size) - ret = NULL; - else - ret = halloc(size, 1); -# else - if (size != (size_t)size) - ret = NULL; - else - ret = malloc((size_t)size); -# endif -#endif - -#ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); -#endif - - return (ret); -} - -/* Free a pointer allocated by png_malloc(). If ptr is NULL, return - * without taking any action. - */ -void PNGAPI -png_free(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->free_fn != NULL) - { - (*(png_ptr->free_fn))(png_ptr, ptr); - return; - } - else - png_free_default(png_ptr, ptr); -} -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#endif /* PNG_USER_MEM_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(__FLAT__) - farfree(ptr); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - hfree(ptr); -# else - free(ptr); -# endif -#endif -} - -#endif /* Not Borland DOS special memory handler */ - -#ifdef PNG_1_0_X -# define png_malloc_warn png_malloc -#else -/* This function was added at libpng version 1.2.3. The png_malloc_warn() - * function will set up png_malloc() to issue a png_warning and return NULL - * instead of issuing a png_error, if it fails to allocate the requested - * memory. - */ -png_voidp PNGAPI -png_malloc_warn(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ptr; - png_uint_32 save_flags; - if (png_ptr == NULL) - return (NULL); - - save_flags = png_ptr->flags; - png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); - png_ptr->flags=save_flags; - return(ptr); -} -#endif - -png_voidp PNGAPI -png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2, - png_uint_32 length) -{ - png_size_t size; - - size = (png_size_t)length; - if ((png_uint_32)size != length) - png_error(png_ptr, "Overflow in png_memcpy_check."); - - return(png_memcpy (s1, s2, size)); -} - -png_voidp PNGAPI -png_memset_check (png_structp png_ptr, png_voidp s1, int value, - png_uint_32 length) -{ - png_size_t size; - - size = (png_size_t)length; - if ((png_uint_32)size != length) - png_error(png_ptr, "Overflow in png_memset_check."); - - return (png_memset (s1, value, size)); - -} - -#ifdef PNG_USER_MEM_SUPPORTED -/* This function is called when the application wants to use another method - * of allocating and freeing memory. - */ -void PNGAPI -png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr - malloc_fn, png_free_ptr free_fn) -{ - if (png_ptr != NULL) - { - png_ptr->mem_ptr = mem_ptr; - png_ptr->malloc_fn = malloc_fn; - png_ptr->free_fn = free_fn; - } -} - -/* This function returns a pointer to the mem_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy and png_read_destroy are called. - */ -png_voidp PNGAPI -png_get_mem_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - return ((png_voidp)png_ptr->mem_ptr); -} -#endif /* PNG_USER_MEM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +/* pngmem.c - stub functions for memory allocation + * + * Last changed in libpng 1.2.41 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +/* Borland DOS special memory handler */ +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* If you change this, be sure to change the one in png.h also */ + +/* Allocate memory for a png_struct. The malloc and memset can be replaced + by a single call to calloc() if this is thought to improve performance. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); +} + +/* Alternate version of png_create_struct, for use with user-defined malloc. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = png_sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = png_sizeof(png_struct); + else + return (png_get_copyright(NULL)); + +#ifdef PNG_USER_MEM_SUPPORTED + if (malloc_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size); + } + else +#endif /* PNG_USER_MEM_SUPPORTED */ + struct_ptr = (png_voidp)farmalloc(size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ + farfree (struct_ptr); + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * Borland seems to have a problem in DOS mode for exactly 64K. + * It gives you a segment with an offset of 8 (perhaps to store its + * memory stuff). zlib doesn't like this at all, so we have to + * detect and deal with it. This code should not be needed in + * Windows or OS/2 modes, and only in 16 bit mode. This code has + * been updated by Alexander Lehmann for version 0.89 to waste less + * memory. + * + * Note that we can't use png_size_t for the "size" declaration, + * since on some systems a png_size_t is a 16-bit quantity, and as a + * result, we would be truncating potentially larger memory requests + * (which should cause a fatal error) and introducing major problems. + */ +png_voidp /* PRIVATE */ +png_calloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + + ret = (png_malloc(png_ptr, size)); + if (ret != NULL) + png_memset(ret,0,(png_size_t)size); + return (ret); +} + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->malloc_fn != NULL) + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + else + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory!"); + return (ret); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + { + png_warning(png_ptr, "Cannot Allocate > 64K"); + ret = NULL; + } + else +#endif + + if (size != (size_t)size) + ret = NULL; + else if (size == (png_uint_32)65536L) + { + if (png_ptr->offset_table == NULL) + { + /* Try to see if we need to do any of this fancy stuff */ + ret = farmalloc(size); + if (ret == NULL || ((png_size_t)ret & 0xffff)) + { + int num_blocks; + png_uint_32 total_size; + png_bytep table; + int i; + png_byte huge * hptr; + + if (ret != NULL) + { + farfree(ret); + ret = NULL; + } + + if (png_ptr->zlib_window_bits > 14) + num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); + else + num_blocks = 1; + if (png_ptr->zlib_mem_level >= 7) + num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); + else + num_blocks++; + + total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; + + table = farmalloc(total_size); + + if (table == NULL) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out Of Memory."); /* Note "O", "M" */ + else + png_warning(png_ptr, "Out Of Memory."); +#endif + return (NULL); + } + + if ((png_size_t)table & 0xfff0) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, + "Farmalloc didn't return normalized pointer"); + else + png_warning(png_ptr, + "Farmalloc didn't return normalized pointer"); +#endif + return (NULL); + } + + png_ptr->offset_table = table; + png_ptr->offset_table_ptr = farmalloc(num_blocks * + png_sizeof(png_bytep)); + + if (png_ptr->offset_table_ptr == NULL) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out Of memory."); /* Note "O", "m" */ + else + png_warning(png_ptr, "Out Of memory."); +#endif + return (NULL); + } + + hptr = (png_byte huge *)table; + if ((png_size_t)hptr & 0xf) + { + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ + } + for (i = 0; i < num_blocks; i++) + { + png_ptr->offset_table_ptr[i] = (png_bytep)hptr; + hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ + } + + png_ptr->offset_table_number = num_blocks; + png_ptr->offset_table_count = 0; + png_ptr->offset_table_count_free = 0; + } + } + + if (png_ptr->offset_table_count >= png_ptr->offset_table_number) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */ + else + png_warning(png_ptr, "Out of Memory."); +#endif + return (NULL); + } + + ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; + } + else + ret = farmalloc(size); + +#ifndef PNG_USER_MEM_SUPPORTED + if (ret == NULL) + { + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */ + else + png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */ + } +#endif + + return (ret); +} + +/* Free a pointer allocated by png_malloc(). In the default + * configuration, png_ptr is not used, but is passed in case it + * is needed. If ptr is NULL, return without taking any action. + */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else + png_free_default(png_ptr, ptr); +} + +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || ptr == NULL) + return; + + if (png_ptr->offset_table != NULL) + { + int i; + + for (i = 0; i < png_ptr->offset_table_count; i++) + { + if (ptr == png_ptr->offset_table_ptr[i]) + { + ptr = NULL; + png_ptr->offset_table_count_free++; + break; + } + } + if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) + { + farfree(png_ptr->offset_table); + farfree(png_ptr->offset_table_ptr); + png_ptr->offset_table = NULL; + png_ptr->offset_table_ptr = NULL; + } + } + + if (ptr != NULL) + { + farfree(ptr); + } +} + +#else /* Not the Borland DOS special memory handler */ + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); +} + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = png_sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = png_sizeof(png_struct); + else + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if (malloc_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); + } +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + struct_ptr = (png_voidp)farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + struct_ptr = (png_voidp)halloc(size, 1); +# else + struct_ptr = (png_voidp)malloc(size); +# endif +#endif + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(struct_ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(struct_ptr); +# else + free(struct_ptr); +# endif +#endif + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + */ + +png_voidp /* PRIVATE */ +png_calloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + + ret = (png_malloc(png_ptr, size)); + if (ret != NULL) + png_memset(ret,0,(png_size_t)size); + return (ret); +} + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr == NULL || size == 0) + return (NULL); + + if (png_ptr->malloc_fn != NULL) + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + else + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory!"); + return (ret); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Cannot Allocate > 64K"); + else +#endif + return NULL; + } +#endif + + /* Check for overflow */ +#if defined(__TURBOC__) && !defined(__FLAT__) + if (size != (unsigned long)size) + ret = NULL; + else + ret = farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + if (size != (unsigned long)size) + ret = NULL; + else + ret = halloc(size, 1); +# else + if (size != (size_t)size) + ret = NULL; + else + ret = malloc((size_t)size); +# endif +#endif + +#ifndef PNG_USER_MEM_SUPPORTED + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory"); +#endif + + return (ret); +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + * without taking any action. + */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else + png_free_default(png_ptr, ptr); +} +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(ptr); +# else + free(ptr); +# endif +#endif +} + +#endif /* Not Borland DOS special memory handler */ + +#ifdef PNG_1_0_X +# define png_malloc_warn png_malloc +#else +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will set up png_malloc() to issue a png_warning and return NULL + * instead of issuing a png_error, if it fails to allocate the requested + * memory. + */ +png_voidp PNGAPI +png_malloc_warn(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ptr; + png_uint_32 save_flags; + if (png_ptr == NULL) + return (NULL); + + save_flags = png_ptr->flags; + png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; + ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); + png_ptr->flags=save_flags; + return(ptr); +} +#endif + +png_voidp PNGAPI +png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2, + png_uint_32 length) +{ + png_size_t size; + + size = (png_size_t)length; + if ((png_uint_32)size != length) + png_error(png_ptr, "Overflow in png_memcpy_check."); + + return(png_memcpy (s1, s2, size)); +} + +png_voidp PNGAPI +png_memset_check (png_structp png_ptr, png_voidp s1, int value, + png_uint_32 length) +{ + png_size_t size; + + size = (png_size_t)length; + if ((png_uint_32)size != length) + png_error(png_ptr, "Overflow in png_memset_check."); + + return (png_memset (s1, value, size)); + +} + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + if (png_ptr != NULL) + { + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; + } +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + return ((png_voidp)png_ptr->mem_ptr); +} +#endif /* PNG_USER_MEM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngpread.c b/main/source/includes/lpng1251/pngpread.c index 9d40c313..5af209d4 100644 --- a/main/source/includes/lpng1251/pngpread.c +++ b/main/source/includes/lpng1251/pngpread.c @@ -1,1241 +1,1241 @@ - -/* pngpread.c - read a png file in push mode - * - * Last changed in libpng 1.2.44 [June 26, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - -/* Push model modes */ -#define PNG_READ_SIG_MODE 0 -#define PNG_READ_CHUNK_MODE 1 -#define PNG_READ_IDAT_MODE 2 -#define PNG_SKIP_MODE 3 -#define PNG_READ_tEXt_MODE 4 -#define PNG_READ_zTXt_MODE 5 -#define PNG_READ_DONE_MODE 6 -#define PNG_READ_iTXt_MODE 7 -#define PNG_ERROR_MODE 8 - -void PNGAPI -png_process_data(png_structp png_ptr, png_infop info_ptr, - png_bytep buffer, png_size_t buffer_size) -{ - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_push_restore_buffer(png_ptr, buffer, buffer_size); - - while (png_ptr->buffer_size) - { - png_process_some_data(png_ptr, info_ptr); - } -} - -/* What we do with the incoming data depends on what we were previously - * doing before we ran out of data... - */ -void /* PRIVATE */ -png_process_some_data(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr == NULL) - return; - - switch (png_ptr->process_mode) - { - case PNG_READ_SIG_MODE: - { - png_push_read_sig(png_ptr, info_ptr); - break; - } - - case PNG_READ_CHUNK_MODE: - { - png_push_read_chunk(png_ptr, info_ptr); - break; - } - - case PNG_READ_IDAT_MODE: - { - png_push_read_IDAT(png_ptr); - break; - } - - case PNG_SKIP_MODE: - { - png_push_crc_finish(png_ptr); - break; - } - - default: - { - png_ptr->buffer_size = 0; - break; - } - } -} - -/* Read any remaining signature bytes from the stream and compare them with - * the correct PNG signature. It is possible that this routine is called - * with bytes already read from the signature, either because they have been - * checked by the calling application, or because of multiple calls to this - * routine. - */ -void /* PRIVATE */ -png_push_read_sig(png_structp png_ptr, png_infop info_ptr) -{ - png_size_t num_checked = png_ptr->sig_bytes, - num_to_check = 8 - num_checked; - - if (png_ptr->buffer_size < num_to_check) - { - num_to_check = png_ptr->buffer_size; - } - - png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), - num_to_check); - png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); - - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) - { - if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) - png_error(png_ptr, "Not a PNG file"); - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - else - { - if (png_ptr->sig_bytes >= 8) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } - } -} - -void /* PRIVATE */ -png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IHDR; - PNG_CONST PNG_IDAT; - PNG_CONST PNG_IEND; - PNG_CONST PNG_PLTE; -#ifdef PNG_READ_bKGD_SUPPORTED - PNG_CONST PNG_bKGD; -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - PNG_CONST PNG_cHRM; -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - PNG_CONST PNG_gAMA; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - PNG_CONST PNG_hIST; -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - PNG_CONST PNG_iCCP; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - PNG_CONST PNG_iTXt; -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - PNG_CONST PNG_oFFs; -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - PNG_CONST PNG_pCAL; -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - PNG_CONST PNG_pHYs; -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - PNG_CONST PNG_sBIT; -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - PNG_CONST PNG_sCAL; -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - PNG_CONST PNG_sRGB; -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - PNG_CONST PNG_sPLT; -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - PNG_CONST PNG_tEXt; -#endif -#ifdef PNG_READ_tIME_SUPPORTED - PNG_CONST PNG_tIME; -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - PNG_CONST PNG_tRNS; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - PNG_CONST PNG_zTXt; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - - /* First we make sure we have enough data for the 4 byte chunk name - * and the 4 byte chunk length before proceeding with decoding the - * chunk data. To fully decode each of these chunks, we also make - * sure we have enough data in the buffer for the 4 byte CRC at the - * end of every chunk (except IDAT, which is handled separately). - */ - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) - { - png_byte chunk_length[4]; - - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - } - - if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; - - if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) - { - if (png_ptr->push_length != 13) - png_error(png_ptr, "Invalid IHDR length"); - - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); - - png_ptr->process_mode = PNG_READ_DONE_MODE; - png_push_have_end(png_ptr, info_ptr); - } - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_ptr->mode |= PNG_HAVE_IDAT; - - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); - - if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) - png_ptr->mode |= PNG_HAVE_PLTE; - - else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - } - } - -#endif - else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - { - /* If we reach an IDAT chunk, this means we have read all of the - * header chunks, and we can start reading the image (or if this - * is called after the image has been read - we have an error). - */ - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - { - if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - if (png_ptr->push_length == 0) - return; - - if (png_ptr->mode & PNG_AFTER_IDAT) - png_error(png_ptr, "Too many IDAT's found"); - } - - png_ptr->idat_size = png_ptr->push_length; - png_ptr->mode |= PNG_HAVE_IDAT; - png_ptr->process_mode = PNG_READ_IDAT_MODE; - png_push_have_info(png_ptr, info_ptr); - png_ptr->zstream.avail_out = - (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; - png_ptr->zstream.next_out = png_ptr->row_buf; - return; - } - -#ifdef PNG_READ_gAMA_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_bKGD_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_hIST_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); - } -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_tIME_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif - else - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); - } - - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; -} - -void /* PRIVATE */ -png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) -{ - png_ptr->process_mode = PNG_SKIP_MODE; - png_ptr->skip_length = skip; -} - -void /* PRIVATE */ -png_push_crc_finish(png_structp png_ptr) -{ - if (png_ptr->skip_length && png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size) - save_size = (png_size_t)png_ptr->skip_length; - else - save_size = png_ptr->save_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_ptr->skip_length -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (png_ptr->skip_length && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size) - save_size = (png_size_t)png_ptr->skip_length; - else - save_size = png_ptr->current_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_ptr->skip_length -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } - if (!png_ptr->skip_length) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_crc_finish(png_ptr, 0); - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } -} - -void PNGAPI -png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) -{ - png_bytep ptr; - - if (png_ptr == NULL) - return; - - ptr = buffer; - if (png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (length < png_ptr->save_buffer_size) - save_size = length; - else - save_size = png_ptr->save_buffer_size; - - png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); - length -= save_size; - ptr += save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (length && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (length < png_ptr->current_buffer_size) - save_size = length; - - else - save_size = png_ptr->current_buffer_size; - - png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } -} - -void /* PRIVATE */ -png_push_save_buffer(png_structp png_ptr) -{ - if (png_ptr->save_buffer_size) - { - if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) - { - png_size_t i, istop; - png_bytep sp; - png_bytep dp; - - istop = png_ptr->save_buffer_size; - for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; - i < istop; i++, sp++, dp++) - { - *dp = *sp; - } - } - } - if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > - png_ptr->save_buffer_max) - { - png_size_t new_max; - png_bytep old_buffer; - - if (png_ptr->save_buffer_size > PNG_SIZE_MAX - - (png_ptr->current_buffer_size + 256)) - { - png_error(png_ptr, "Potential overflow of save_buffer"); - } - - new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; - old_buffer = png_ptr->save_buffer; - png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, - (png_uint_32)new_max); - if (png_ptr->save_buffer == NULL) - { - png_free(png_ptr, old_buffer); - png_error(png_ptr, "Insufficient memory for save_buffer"); - } - png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); - png_free(png_ptr, old_buffer); - png_ptr->save_buffer_max = new_max; - } - if (png_ptr->current_buffer_size) - { - png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, - png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); - png_ptr->save_buffer_size += png_ptr->current_buffer_size; - png_ptr->current_buffer_size = 0; - } - png_ptr->save_buffer_ptr = png_ptr->save_buffer; - png_ptr->buffer_size = 0; -} - -void /* PRIVATE */ -png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, - png_size_t buffer_length) -{ - png_ptr->current_buffer = buffer; - png_ptr->current_buffer_size = buffer_length; - png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; - png_ptr->current_buffer_ptr = png_ptr->current_buffer; -} - -void /* PRIVATE */ -png_push_read_IDAT(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) - { - png_byte chunk_length[4]; - - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); - png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - png_error(png_ptr, "Not enough compressed data"); - return; - } - - png_ptr->idat_size = png_ptr->push_length; - } - if (png_ptr->idat_size && png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) - { - save_size = (png_size_t)png_ptr->idat_size; - - /* Check for overflow */ - if ((png_uint_32)save_size != png_ptr->idat_size) - png_error(png_ptr, "save_size overflowed in pngpread"); - } - else - save_size = png_ptr->save_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_ptr->idat_size -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (png_ptr->idat_size && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) - { - save_size = (png_size_t)png_ptr->idat_size; - - /* Check for overflow */ - if ((png_uint_32)save_size != png_ptr->idat_size) - png_error(png_ptr, "save_size overflowed in pngpread"); - } - else - save_size = png_ptr->current_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_ptr->idat_size -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } - if (!png_ptr->idat_size) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_crc_finish(png_ptr, 0); - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - png_ptr->mode |= PNG_AFTER_IDAT; - } -} - -void /* PRIVATE */ -png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, - png_size_t buffer_length) -{ - /* The caller checks for a non-zero buffer length. */ - if (!(buffer_length > 0) || buffer == NULL) - png_error(png_ptr, "No IDAT data (internal error)"); - - /* This routine must process all the data it has been given - * before returning, calling the row callback as required to - * handle the uncompressed results. - */ - png_ptr->zstream.next_in = buffer; - png_ptr->zstream.avail_in = (uInt)buffer_length; - - /* Keep going until the decompressed data is all processed - * or the stream marked as finished. - */ - while (png_ptr->zstream.avail_in > 0 && - !(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - { - int ret; - - /* We have data for zlib, but we must check that zlib - * has somewhere to put the results. It doesn't matter - * if we don't expect any results -- it may be the input - * data is just the LZ end code. - */ - if (!(png_ptr->zstream.avail_out > 0)) - { - png_ptr->zstream.avail_out = - (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; - png_ptr->zstream.next_out = png_ptr->row_buf; - } - - /* Using Z_SYNC_FLUSH here means that an unterminated - * LZ stream can still be handled (a stream with a missing - * end code), otherwise (Z_NO_FLUSH) a future zlib - * implementation might defer output and, therefore, - * change the current behavior. (See comments in inflate.c - * for why this doesn't happen at present with zlib 1.2.5.) - */ - ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); - - /* Check for any failure before proceeding. */ - if (ret != Z_OK && ret != Z_STREAM_END) - { - /* Terminate the decompression. */ - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - - /* This may be a truncated stream (missing or - * damaged end code). Treat that as a warning. - */ - if (png_ptr->row_number >= png_ptr->num_rows || - png_ptr->pass > 6) - png_warning(png_ptr, "Truncated compressed data in IDAT"); - else - png_error(png_ptr, "Decompression error in IDAT"); - - /* Skip the check on unprocessed input */ - return; - } - - /* Did inflate output any data? */ - if (png_ptr->zstream.next_out != png_ptr->row_buf) - { - /* Is this unexpected data after the last row? - * If it is, artificially terminate the LZ output - * here. - */ - if (png_ptr->row_number >= png_ptr->num_rows || - png_ptr->pass > 6) - { - /* Extra data. */ - png_warning(png_ptr, "Extra compressed data in IDAT"); - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - /* Do no more processing; skip the unprocessed - * input check below. - */ - return; - } - - /* Do we have a complete row? */ - if (png_ptr->zstream.avail_out == 0) - png_push_process_row(png_ptr); - } - - /* And check for the end of the stream. */ - if (ret == Z_STREAM_END) - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - } - - /* All the data should have been processed, if anything - * is left at this point we have bytes of IDAT data - * after the zlib end code. - */ - if (png_ptr->zstream.avail_in > 0) - png_warning(png_ptr, "Extra compression data"); -} - -void /* PRIVATE */ -png_push_process_row(png_structp png_ptr) -{ - png_ptr->row_info.color_type = png_ptr->color_type; - png_ptr->row_info.width = png_ptr->iwidth; - png_ptr->row_info.channels = png_ptr->channels; - png_ptr->row_info.bit_depth = png_ptr->bit_depth; - png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; - - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - png_read_filter_row(png_ptr, &(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->prev_row + 1, - (int)(png_ptr->row_buf[0])); - - png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, - png_ptr->rowbytes + 1); - - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - if (png_ptr->pass < 6) -/* old interface (pre-1.0.9): - png_do_read_interlace(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); - */ - png_do_read_interlace(png_ptr); - - switch (png_ptr->pass) - { - case 0: - { - int i; - for (i = 0; i < 8 && png_ptr->pass == 0; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ - } - - if (png_ptr->pass == 2) /* Pass 1 might be empty */ - { - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - if (png_ptr->pass == 4 && png_ptr->height <= 4) - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - if (png_ptr->pass == 6 && png_ptr->height <= 4) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - case 1: - { - int i; - for (i = 0; i < 8 && png_ptr->pass == 1; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 2) /* Skip top 4 generated rows */ - { - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 2: - { - int i; - - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 4) /* Pass 3 might be empty */ - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 3: - { - int i; - - for (i = 0; i < 4 && png_ptr->pass == 3; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 4) /* Skip top two generated rows */ - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 4: - { - int i; - - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 6) /* Pass 5 might be empty */ - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - case 5: - { - int i; - - for (i = 0; i < 2 && png_ptr->pass == 5; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 6) /* Skip top generated row */ - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - case 6: - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - - if (png_ptr->pass != 6) - break; - - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - } - else -#endif - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } -} - -void /* PRIVATE */ -png_read_push_finish_row(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; - - /* Height of interlace block. This is not currently used - if you need - * it, uncomment it here and in png.h - PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; - */ -#endif - - png_ptr->row_number++; - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - png_memset_check(png_ptr, png_ptr->prev_row, 0, - png_ptr->rowbytes + 1); - do - { - png_ptr->pass++; - if ((png_ptr->pass == 1 && png_ptr->width < 5) || - (png_ptr->pass == 3 && png_ptr->width < 3) || - (png_ptr->pass == 5 && png_ptr->width < 2)) - png_ptr->pass++; - - if (png_ptr->pass > 7) - png_ptr->pass--; - - if (png_ptr->pass >= 7) - break; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - if (png_ptr->transformations & PNG_INTERLACE) - break; - - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - - } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); - } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -} - -void /* PRIVATE */ -png_push_have_info(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr->info_fn != NULL) - (*(png_ptr->info_fn))(png_ptr, info_ptr); -} - -void /* PRIVATE */ -png_push_have_end(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr->end_fn != NULL) - (*(png_ptr->end_fn))(png_ptr, info_ptr); -} - -void /* PRIVATE */ -png_push_have_row(png_structp png_ptr, png_bytep row) -{ - if (png_ptr->row_fn != NULL) - (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, - (int)png_ptr->pass); -} - -void PNGAPI -png_progressive_combine_row (png_structp png_ptr, - png_bytep old_row, png_bytep new_row) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST int FARDATA png_pass_dsp_mask[7] = - {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; -#endif - - if (png_ptr == NULL) - return; - - if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */ - png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]); -} - -void PNGAPI -png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, - png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, - png_progressive_end_ptr end_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->info_fn = info_fn; - png_ptr->row_fn = row_fn; - png_ptr->end_fn = end_fn; - - png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); -} - -png_voidp PNGAPI -png_get_progressive_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - - return png_ptr->io_ptr; -} -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +/* pngpread.c - read a png file in push mode + * + * Last changed in libpng 1.2.44 [June 26, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + +/* Push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_SKIP_MODE 3 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +void PNGAPI +png_process_data(png_structp png_ptr, png_infop info_ptr, + png_bytep buffer, png_size_t buffer_size) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr == NULL) + return; + + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } + + case PNG_SKIP_MODE: + { + png_push_crc_finish(png_ptr); + break; + } + + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structp png_ptr, png_infop info_ptr) +{ + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST PNG_IHDR; + PNG_CONST PNG_IDAT; + PNG_CONST PNG_IEND; + PNG_CONST PNG_PLTE; +#ifdef PNG_READ_bKGD_SUPPORTED + PNG_CONST PNG_bKGD; +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + PNG_CONST PNG_cHRM; +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + PNG_CONST PNG_gAMA; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + PNG_CONST PNG_hIST; +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + PNG_CONST PNG_iCCP; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + PNG_CONST PNG_iTXt; +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + PNG_CONST PNG_oFFs; +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + PNG_CONST PNG_pCAL; +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + PNG_CONST PNG_pHYs; +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + PNG_CONST PNG_sBIT; +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + PNG_CONST PNG_sCAL; +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + PNG_CONST PNG_sRGB; +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + PNG_CONST PNG_sPLT; +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + PNG_CONST PNG_tEXt; +#endif +#ifdef PNG_READ_tIME_SUPPORTED + PNG_CONST PNG_tIME; +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + PNG_CONST PNG_tRNS; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + PNG_CONST PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + + /* First we make sure we have enough data for the 4 byte chunk name + * and the 4 byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4 byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + if (png_ptr->mode & PNG_AFTER_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + { + if (png_ptr->push_length != 13) + png_error(png_ptr, "Invalid IHDR length"); + + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + } + } + +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + { + if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if (png_ptr->push_length == 0) + return; + + if (png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + } + + png_ptr->idat_size = png_ptr->push_length; + png_ptr->mode |= PNG_HAVE_IDAT; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_bKGD_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif + else + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void /* PRIVATE */ +png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) +{ + png_ptr->process_mode = PNG_SKIP_MODE; + png_ptr->skip_length = skip; +} + +void /* PRIVATE */ +png_push_crc_finish(png_structp png_ptr) +{ + if (png_ptr->skip_length && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->skip_length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->skip_length) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } +} + +void PNGAPI +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) +{ + png_bytep ptr; + + if (png_ptr == NULL) + return; + + ptr = buffer; + if (png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + else + save_size = png_ptr->save_buffer_size; + + png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + + else + save_size = png_ptr->current_buffer_size; + + png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structp png_ptr) +{ + if (png_ptr->save_buffer_size) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + png_size_t i, istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + png_size_t new_max; + png_bytep old_buffer; + + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } + + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, + (png_uint_32)new_max); + if (png_ptr->save_buffer == NULL) + { + png_free(png_ptr, old_buffer); + png_error(png_ptr, "Insufficient memory for save_buffer"); + } + png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST PNG_IDAT; +#endif + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_error(png_ptr, "Not enough compressed data"); + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + if (png_ptr->idat_size && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + + /* Check for overflow */ + if ((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->idat_size && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + + /* Check for overflow */ + if ((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->idat_size) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + /* The caller checks for a non-zero buffer length. */ + if (!(buffer_length > 0) || buffer == NULL) + png_error(png_ptr, "No IDAT data (internal error)"); + + /* This routine must process all the data it has been given + * before returning, calling the row callback as required to + * handle the uncompressed results. + */ + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = (uInt)buffer_length; + + /* Keep going until the decompressed data is all processed + * or the stream marked as finished. + */ + while (png_ptr->zstream.avail_in > 0 && + !(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + { + int ret; + + /* We have data for zlib, but we must check that zlib + * has somewhere to put the results. It doesn't matter + * if we don't expect any results -- it may be the input + * data is just the LZ end code. + */ + if (!(png_ptr->zstream.avail_out > 0)) + { + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + } + + /* Using Z_SYNC_FLUSH here means that an unterminated + * LZ stream can still be handled (a stream with a missing + * end code), otherwise (Z_NO_FLUSH) a future zlib + * implementation might defer output and, therefore, + * change the current behavior. (See comments in inflate.c + * for why this doesn't happen at present with zlib 1.2.5.) + */ + ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); + + /* Check for any failure before proceeding. */ + if (ret != Z_OK && ret != Z_STREAM_END) + { + /* Terminate the decompression. */ + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + + /* This may be a truncated stream (missing or + * damaged end code). Treat that as a warning. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + png_warning(png_ptr, "Truncated compressed data in IDAT"); + else + png_error(png_ptr, "Decompression error in IDAT"); + + /* Skip the check on unprocessed input */ + return; + } + + /* Did inflate output any data? */ + if (png_ptr->zstream.next_out != png_ptr->row_buf) + { + /* Is this unexpected data after the last row? + * If it is, artificially terminate the LZ output + * here. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + { + /* Extra data. */ + png_warning(png_ptr, "Extra compressed data in IDAT"); + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + /* Do no more processing; skip the unprocessed + * input check below. + */ + return; + } + + /* Do we have a complete row? */ + if (png_ptr->zstream.avail_out == 0) + png_push_process_row(png_ptr); + } + + /* And check for the end of the stream. */ + if (ret == Z_STREAM_END) + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + } + + /* All the data should have been processed, if anything + * is left at this point we have bytes of IDAT data + * after the zlib end code. + */ + if (png_ptr->zstream.avail_in > 0) + png_warning(png_ptr, "Extra compression data"); +} + +void /* PRIVATE */ +png_push_process_row(png_structp png_ptr) +{ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, + png_ptr->rowbytes + 1); + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) +/* old interface (pre-1.0.9): + png_do_read_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ + } + + if (png_ptr->pass == 2) /* Pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 2) /* Skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 2: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 3: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 4: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Pass 5 might be empty */ + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 5: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Skip top generated row */ + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + + if (png_ptr->pass != 6) + break; + + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ +#endif + + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset_check(png_ptr, png_ptr->prev_row, 0, + png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass > 7) + png_ptr->pass--; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if (png_ptr->transformations & PNG_INTERLACE) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +} + +void /* PRIVATE */ +png_push_have_info(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +void PNGAPI +png_progressive_combine_row (png_structp png_ptr, + png_bytep old_row, png_bytep new_row) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST int FARDATA png_pass_dsp_mask[7] = + {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; +#endif + + if (png_ptr == NULL) + return; + + if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */ + png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]); +} + +void PNGAPI +png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return png_ptr->io_ptr; +} +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngread.c b/main/source/includes/lpng1251/pngread.c index c463122b..2197ff17 100644 --- a/main/source/includes/lpng1251/pngread.c +++ b/main/source/includes/lpng1251/pngread.c @@ -1,1509 +1,1509 @@ - -/* pngread.c - read a PNG file - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains routines that an application calls directly to - * read a PNG file or stream. - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED - -/* Create a PNG structure for reading, and allocate any memory needed. */ -png_structp PNGAPI -png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn) -{ - -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); -} - -/* Alternate create PNG structure for reading, and allocate any memory - * needed. - */ -png_structp PNGAPI -png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - - int i; - - png_debug(1, "in png_create_read_struct"); - -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif - if (png_ptr == NULL) - return (NULL); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; - /* Added at libpng-1.2.43 and 1.4.0 */ - png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; -#endif - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_ptr->jmpbuf)) -#endif - { - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, - (png_free_ptr)free_fn, (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - return (NULL); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif /* PNG_SETJMP_SUPPORTED */ - -#ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); -#endif - - png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - - if (user_png_ver) - { - i = 0; - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - else - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - - - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) - { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first digit. - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char msg[80]; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "Application is running with png.c from libpng-%.20s", - png_libpng_ver); - png_warning(png_ptr, msg); -#endif -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "Incompatible libpng version in application and library"); - } - } - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - switch (inflateInit(&png_ptr->zstream)) - { - case Z_OK: /* Do nothing */ break; - case Z_MEM_ERROR: - case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); - break; - case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); - break; - default: png_error(png_ptr, "Unknown zlib error"); - } - - - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); - -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then - encounter a png_error() will longjmp here. Since the jmpbuf is - then meaningless we abort instead of returning. */ -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) - PNG_ABORT(); - png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); -#else - if (setjmp(png_ptr->jmpbuf)) - PNG_ABORT(); -#endif -#endif /* PNG_SETJMP_SUPPORTED */ - - return (png_ptr); -} - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* Initialize PNG structure for reading, and allocate any memory needed. - * This interface is deprecated in favour of the png_create_read_struct(), - * and it will disappear as of libpng-1.3.0. - */ -#undef png_read_init -void PNGAPI -png_read_init(png_structp png_ptr) -{ - /* We only come here via pre-1.0.7-compiled applications */ - png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0); -} - -void PNGAPI -png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, - png_size_t png_struct_size, png_size_t png_info_size) -{ - /* We only come here via pre-1.0.12-compiled applications */ - if (png_ptr == NULL) - return; -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - if (png_sizeof(png_struct) > png_struct_size || - png_sizeof(png_info) > png_info_size) - { - char msg[80]; - png_ptr->warning_fn = NULL; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "Application is running with png.c from libpng-%.20s", - png_libpng_ver); - png_warning(png_ptr, msg); - } -#endif - if (png_sizeof(png_struct) > png_struct_size) - { - png_ptr->error_fn = NULL; -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "The png struct allocated by the application for reading is" - " too small."); - } - if (png_sizeof(png_info) > png_info_size) - { - png_ptr->error_fn = NULL; -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "The info struct allocated by application for reading is" - " too small."); - } - png_read_init_3(&png_ptr, user_png_ver, png_struct_size); -} -#endif /* PNG_1_0_X || PNG_1_2_X */ - -void PNGAPI -png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, - png_size_t png_struct_size) -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; /* to save current jump buffer */ -#endif - - int i = 0; - - png_structp png_ptr=*ptr_ptr; - - if (png_ptr == NULL) - return; - - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - { -#ifdef PNG_LEGACY_SUPPORTED - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; -#else - png_ptr->warning_fn = NULL; - png_warning(png_ptr, - "Application uses deprecated png_read_init() and should be" - " recompiled."); - break; -#endif - } - } while (png_libpng_ver[i++]); - - png_debug(1, "in png_read_init_3"); - -#ifdef PNG_SETJMP_SUPPORTED - /* Save jump buffer and error functions */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); -#endif - - if (png_sizeof(png_struct) > png_struct_size) - { - png_destroy_struct(png_ptr); - *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); - png_ptr = *ptr_ptr; - } - - /* Reset all variables to 0 */ - png_memset(png_ptr, 0, png_sizeof(png_struct)); - -#ifdef PNG_SETJMP_SUPPORTED - /* Restore jump buffer */ - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif - - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; -#endif - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - switch (inflateInit(&png_ptr->zstream)) - { - case Z_OK: /* Do nothing */ break; - case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; - case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); - break; - default: png_error(png_ptr, "Unknown zlib error"); - } - - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); -} - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the information before the actual image data. This has been - * changed in v0.90 to allow reading a file that already has the magic - * bytes read from the stream. You can tell libpng how many bytes have - * been read from the beginning of the stream (up to the maximum of 8) - * via png_set_sig_bytes(), and we will only check the remaining bytes - * here. The application can then have access to the signature bytes we - * read if it is determined that this isn't a valid PNG file. - */ -void PNGAPI -png_read_info(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_info"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* If we haven't checked all of the PNG signature bytes, do so now. */ - if (png_ptr->sig_bytes < 8) - { - png_size_t num_checked = png_ptr->sig_bytes, - num_to_check = 8 - num_checked; - - png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); - png_ptr->sig_bytes = 8; - - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) - { - if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) - png_error(png_ptr, "Not a PNG file"); - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - if (num_checked < 3) - png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; - } - - for (;;) - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IHDR; - PNG_CONST PNG_IDAT; - PNG_CONST PNG_IEND; - PNG_CONST PNG_PLTE; -#ifdef PNG_READ_bKGD_SUPPORTED - PNG_CONST PNG_bKGD; -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - PNG_CONST PNG_cHRM; -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - PNG_CONST PNG_gAMA; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - PNG_CONST PNG_hIST; -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - PNG_CONST PNG_iCCP; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - PNG_CONST PNG_iTXt; -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - PNG_CONST PNG_oFFs; -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - PNG_CONST PNG_pCAL; -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - PNG_CONST PNG_pHYs; -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - PNG_CONST PNG_sBIT; -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - PNG_CONST PNG_sCAL; -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - PNG_CONST PNG_sPLT; -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - PNG_CONST PNG_sRGB; -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - PNG_CONST PNG_tEXt; -#endif -#ifdef PNG_READ_tIME_SUPPORTED - PNG_CONST PNG_tIME; -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - PNG_CONST PNG_tRNS; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - PNG_CONST PNG_zTXt; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - png_uint_32 length = png_read_chunk_header(png_ptr); - PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; - - /* This should be a binary subdivision search or a hash for - * matching the chunk name rather than a linear search. - */ - if (!png_memcmp(chunk_name, png_IDAT, 4)) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; - - if (!png_memcmp(chunk_name, png_IHDR, 4)) - png_handle_IHDR(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IEND, 4)) - png_handle_IEND(png_ptr, info_ptr, length); -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, chunk_name)) - { - if (!png_memcmp(chunk_name, png_IDAT, 4)) - png_ptr->mode |= PNG_HAVE_IDAT; - png_handle_unknown(png_ptr, info_ptr, length); - if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_ptr->mode |= PNG_HAVE_PLTE; - else if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - break; - } - } -#endif - else if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_handle_PLTE(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - - png_ptr->idat_size = length; - png_ptr->mode |= PNG_HAVE_IDAT; - break; - } -#ifdef PNG_READ_bKGD_SUPPORTED - else if (!png_memcmp(chunk_name, png_bKGD, 4)) - png_handle_bKGD(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - else if (!png_memcmp(chunk_name, png_cHRM, 4)) - png_handle_cHRM(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - else if (!png_memcmp(chunk_name, png_gAMA, 4)) - png_handle_gAMA(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_hIST_SUPPORTED - else if (!png_memcmp(chunk_name, png_hIST, 4)) - png_handle_hIST(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - else if (!png_memcmp(chunk_name, png_oFFs, 4)) - png_handle_oFFs(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_pCAL, 4)) - png_handle_pCAL(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_sCAL, 4)) - png_handle_sCAL(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - else if (!png_memcmp(chunk_name, png_pHYs, 4)) - png_handle_pHYs(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sBIT, 4)) - png_handle_sBIT(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - else if (!png_memcmp(chunk_name, png_sRGB, 4)) - png_handle_sRGB(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - else if (!png_memcmp(chunk_name, png_iCCP, 4)) - png_handle_iCCP(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sPLT, 4)) - png_handle_sPLT(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_tEXt, 4)) - png_handle_tEXt(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_tIME_SUPPORTED - else if (!png_memcmp(chunk_name, png_tIME, 4)) - png_handle_tIME(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - else if (!png_memcmp(chunk_name, png_tRNS, 4)) - png_handle_tRNS(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_zTXt, 4)) - png_handle_zTXt(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_iTXt, 4)) - png_handle_iTXt(png_ptr, info_ptr, length); -#endif - else - png_handle_unknown(png_ptr, info_ptr, length); - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -/* Optional call to update the users info_ptr structure */ -void PNGAPI -png_read_update_info(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_update_info"); - - if (png_ptr == NULL) - return; - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); - else - png_warning(png_ptr, - "Ignoring extra png_read_update_info() call; row buffer not reallocated"); - - png_read_transform_info(png_ptr, info_ptr); -} - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Initialize palette, background, etc, after transformations - * are set, but before any reading takes place. This allows - * the user to obtain a gamma-corrected palette, for example. - * If the user doesn't call this, we will do it ourselves. - */ -void PNGAPI -png_start_read_image(png_structp png_ptr) -{ - png_debug(1, "in png_start_read_image"); - - if (png_ptr == NULL) - return; - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -void PNGAPI -png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) -{ - PNG_CONST PNG_IDAT; - PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, - 0xff}; - PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; - int ret; - - if (png_ptr == NULL) - return; - - png_debug2(1, "in png_read_row (row %lu, pass %d)", - png_ptr->row_number, png_ptr->pass); - - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); - if (png_ptr->row_number == 0 && png_ptr->pass == 0) - { - /* Check for transforms that have been set but were defined out */ -#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) - png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) - png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ - !defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) - png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) - png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) - png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined."); -#endif - } - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* If interlaced and we do not need a new row, combine row and return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - switch (png_ptr->pass) - { - case 0: - if (png_ptr->row_number & 0x07) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 2: - if ((png_ptr->row_number & 0x07) != 4) - { - if (dsp_row != NULL && (png_ptr->row_number & 4)) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 3: - if ((png_ptr->row_number & 3) || png_ptr->width < 3) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 4: - if ((png_ptr->row_number & 3) != 2) - { - if (dsp_row != NULL && (png_ptr->row_number & 2)) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 5: - if ((png_ptr->row_number & 1) || png_ptr->width < 2) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 6: - if (!(png_ptr->row_number & 1)) - { - png_read_finish_row(png_ptr); - return; - } - break; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IDAT)) - png_error(png_ptr, "Invalid attempt to read row data"); - - png_ptr->zstream.next_out = png_ptr->row_buf; - png_ptr->zstream.avail_out = - (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1); - do - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_crc_finish(png_ptr, 0); - - png_ptr->idat_size = png_read_chunk_header(png_ptr); - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_error(png_ptr, "Not enough image data"); - } - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - png_crc_read(png_ptr, png_ptr->zbuf, - (png_size_t)png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret == Z_STREAM_END) - { - if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_error(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression error"); - - } while (png_ptr->zstream.avail_out); - - png_ptr->row_info.color_type = png_ptr->color_type; - png_ptr->row_info.width = png_ptr->iwidth; - png_ptr->row_info.channels = png_ptr->channels; - png_ptr->row_info.bit_depth = png_ptr->bit_depth; - png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - if (png_ptr->row_buf[0]) - png_read_filter_row(png_ptr, &(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->prev_row + 1, - (int)(png_ptr->row_buf[0])); - - png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, - png_ptr->rowbytes + 1); - -#ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) - { - /* Intrapixel differencing */ - png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); - } -#endif - - - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && - (png_ptr->transformations & PNG_INTERLACE)) - { - if (png_ptr->pass < 6) - /* Old interface (pre-1.0.9): - * png_do_read_interlace(&(png_ptr->row_info), - * png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); - */ - png_do_read_interlace(png_ptr); - - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - if (row != NULL) - png_combine_row(png_ptr, row, - png_pass_mask[png_ptr->pass]); - } - else -#endif - { - if (row != NULL) - png_combine_row(png_ptr, row, 0xff); - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 0xff); - } - png_read_finish_row(png_ptr); - - if (png_ptr->read_row_fn != NULL) - (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read one or more rows of image data. If the image is interlaced, - * and png_set_interlace_handling() has been called, the rows need to - * contain the contents of the rows from the previous pass. If the - * image has alpha or transparency, and png_handle_alpha()[*] has been - * called, the rows contents must be initialized to the contents of the - * screen. - * - * "row" holds the actual image, and pixels are placed in it - * as they arrive. If the image is displayed after each pass, it will - * appear to "sparkle" in. "display_row" can be used to display a - * "chunky" progressive image, with finer detail added as it becomes - * available. If you do not want this "chunky" display, you may pass - * NULL for display_row. If you do not want the sparkle display, and - * you have not called png_handle_alpha(), you may pass NULL for rows. - * If you have called png_handle_alpha(), and the image has either an - * alpha channel or a transparency chunk, you must provide a buffer for - * rows. In this case, you do not have to provide a display_row buffer - * also, but you may. If the image is not interlaced, or if you have - * not called png_set_interlace_handling(), the display_row buffer will - * be ignored, so pass NULL to it. - * - * [*] png_handle_alpha() does not exist yet, as of this version of libpng - */ - -void PNGAPI -png_read_rows(png_structp png_ptr, png_bytepp row, - png_bytepp display_row, png_uint_32 num_rows) -{ - png_uint_32 i; - png_bytepp rp; - png_bytepp dp; - - png_debug(1, "in png_read_rows"); - - if (png_ptr == NULL) - return; - rp = row; - dp = display_row; - if (rp != NULL && dp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep rptr = *rp++; - png_bytep dptr = *dp++; - - png_read_row(png_ptr, rptr, dptr); - } - else if (rp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep rptr = *rp; - png_read_row(png_ptr, rptr, png_bytep_NULL); - rp++; - } - else if (dp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep dptr = *dp; - png_read_row(png_ptr, png_bytep_NULL, dptr); - dp++; - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the entire image. If the image has an alpha channel or a tRNS - * chunk, and you have called png_handle_alpha()[*], you will need to - * initialize the image to the current image that PNG will be overlaying. - * We set the num_rows again here, in case it was incorrectly set in - * png_read_start_row() by a call to png_read_update_info() or - * png_start_read_image() if png_set_interlace_handling() wasn't called - * prior to either of these functions like it should have been. You can - * only call this function once. If you desire to have an image for - * each pass of a interlaced image, use png_read_rows() instead. - * - * [*] png_handle_alpha() does not exist yet, as of this version of libpng - */ -void PNGAPI -png_read_image(png_structp png_ptr, png_bytepp image) -{ - png_uint_32 i, image_height; - int pass, j; - png_bytepp rp; - - png_debug(1, "in png_read_image"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - pass = png_set_interlace_handling(png_ptr); -#else - if (png_ptr->interlaced) - png_error(png_ptr, - "Cannot read interlaced image -- interlace handler disabled."); - pass = 1; -#endif - - - image_height=png_ptr->height; - png_ptr->num_rows = image_height; /* Make sure this is set correctly */ - - for (j = 0; j < pass; j++) - { - rp = image; - for (i = 0; i < image_height; i++) - { - png_read_row(png_ptr, *rp, png_bytep_NULL); - rp++; - } - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the end of the PNG file. Will not read past the end of the - * file, will verify the end is accurate, and will read any comments - * or time information at the end of the file, if info is not NULL. - */ -void PNGAPI -png_read_end(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_end"); - - if (png_ptr == NULL) - return; - png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ - - do - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IHDR; - PNG_CONST PNG_IDAT; - PNG_CONST PNG_IEND; - PNG_CONST PNG_PLTE; -#ifdef PNG_READ_bKGD_SUPPORTED - PNG_CONST PNG_bKGD; -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - PNG_CONST PNG_cHRM; -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - PNG_CONST PNG_gAMA; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - PNG_CONST PNG_hIST; -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - PNG_CONST PNG_iCCP; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - PNG_CONST PNG_iTXt; -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - PNG_CONST PNG_oFFs; -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - PNG_CONST PNG_pCAL; -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - PNG_CONST PNG_pHYs; -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - PNG_CONST PNG_sBIT; -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - PNG_CONST PNG_sCAL; -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - PNG_CONST PNG_sPLT; -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - PNG_CONST PNG_sRGB; -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - PNG_CONST PNG_tEXt; -#endif -#ifdef PNG_READ_tIME_SUPPORTED - PNG_CONST PNG_tIME; -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - PNG_CONST PNG_tRNS; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - PNG_CONST PNG_zTXt; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - png_uint_32 length = png_read_chunk_header(png_ptr); - PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; - - if (!png_memcmp(chunk_name, png_IHDR, 4)) - png_handle_IHDR(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IEND, 4)) - png_handle_IEND(png_ptr, info_ptr, length); -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, chunk_name)) - { - if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - png_error(png_ptr, "Too many IDAT's found"); - } - png_handle_unknown(png_ptr, info_ptr, length); - if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_ptr->mode |= PNG_HAVE_PLTE; - } -#endif - else if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - /* Zero length IDATs are legal after the last IDAT has been - * read, but not after other chunks have been read. - */ - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - png_error(png_ptr, "Too many IDAT's found"); - png_crc_finish(png_ptr, length); - } - else if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_handle_PLTE(png_ptr, info_ptr, length); -#ifdef PNG_READ_bKGD_SUPPORTED - else if (!png_memcmp(chunk_name, png_bKGD, 4)) - png_handle_bKGD(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - else if (!png_memcmp(chunk_name, png_cHRM, 4)) - png_handle_cHRM(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - else if (!png_memcmp(chunk_name, png_gAMA, 4)) - png_handle_gAMA(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_hIST_SUPPORTED - else if (!png_memcmp(chunk_name, png_hIST, 4)) - png_handle_hIST(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - else if (!png_memcmp(chunk_name, png_oFFs, 4)) - png_handle_oFFs(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_pCAL, 4)) - png_handle_pCAL(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_sCAL, 4)) - png_handle_sCAL(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - else if (!png_memcmp(chunk_name, png_pHYs, 4)) - png_handle_pHYs(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sBIT, 4)) - png_handle_sBIT(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - else if (!png_memcmp(chunk_name, png_sRGB, 4)) - png_handle_sRGB(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - else if (!png_memcmp(chunk_name, png_iCCP, 4)) - png_handle_iCCP(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sPLT, 4)) - png_handle_sPLT(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_tEXt, 4)) - png_handle_tEXt(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_tIME_SUPPORTED - else if (!png_memcmp(chunk_name, png_tIME, 4)) - png_handle_tIME(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - else if (!png_memcmp(chunk_name, png_tRNS, 4)) - png_handle_tRNS(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_zTXt, 4)) - png_handle_zTXt(png_ptr, info_ptr, length); -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_iTXt, 4)) - png_handle_iTXt(png_ptr, info_ptr, length); -#endif - else - png_handle_unknown(png_ptr, info_ptr, length); - } while (!(png_ptr->mode & PNG_HAVE_IEND)); -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -/* Free all memory used by the read */ -void PNGAPI -png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, - png_infopp end_info_ptr_ptr) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL, end_info_ptr = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; -#endif - - png_debug(1, "in png_destroy_read_struct"); - - if (png_ptr_ptr != NULL) - png_ptr = *png_ptr_ptr; - if (png_ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (end_info_ptr_ptr != NULL) - end_info_ptr = *end_info_ptr_ptr; - - png_read_destroy(png_ptr, info_ptr, end_info_ptr); - - if (info_ptr != NULL) - { -#ifdef PNG_TEXT_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); -#endif - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } - - if (end_info_ptr != NULL) - { -#ifdef PNG_READ_TEXT_SUPPORTED - png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); -#endif -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)end_info_ptr); -#endif - *end_info_ptr_ptr = NULL; - } - - if (png_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - *png_ptr_ptr = NULL; - } -} - -/* Free all memory used by the read (old method) */ -void /* PRIVATE */ -png_read_destroy(png_structp png_ptr, png_infop info_ptr, - png_infop end_info_ptr) -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; -#endif - png_error_ptr error_fn; - png_error_ptr warning_fn; - png_voidp error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn; -#endif - - png_debug(1, "in png_read_destroy"); - - if (info_ptr != NULL) - png_info_destroy(png_ptr, info_ptr); - - if (end_info_ptr != NULL) - png_info_destroy(png_ptr, end_info_ptr); - - png_free(png_ptr, png_ptr->zbuf); - png_free(png_ptr, png_ptr->big_row_buf); - png_free(png_ptr, png_ptr->prev_row); - png_free(png_ptr, png_ptr->chunkdata); -#ifdef PNG_READ_DITHER_SUPPORTED - png_free(png_ptr, png_ptr->palette_lookup); - png_free(png_ptr, png_ptr->dither_index); -#endif -#ifdef PNG_READ_GAMMA_SUPPORTED - png_free(png_ptr, png_ptr->gamma_table); -#endif -#ifdef PNG_READ_BACKGROUND_SUPPORTED - png_free(png_ptr, png_ptr->gamma_from_1); - png_free(png_ptr, png_ptr->gamma_to_1); -#endif -#ifdef PNG_FREE_ME_SUPPORTED - if (png_ptr->free_me & PNG_FREE_PLTE) - png_zfree(png_ptr, png_ptr->palette); - png_ptr->free_me &= ~PNG_FREE_PLTE; -#else - if (png_ptr->flags & PNG_FLAG_FREE_PLTE) - png_zfree(png_ptr, png_ptr->palette); - png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; -#endif -#if defined(PNG_tRNS_SUPPORTED) || \ - defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) -#ifdef PNG_FREE_ME_SUPPORTED - if (png_ptr->free_me & PNG_FREE_TRNS) - png_free(png_ptr, png_ptr->trans); - png_ptr->free_me &= ~PNG_FREE_TRNS; -#else - if (png_ptr->flags & PNG_FLAG_FREE_TRNS) - png_free(png_ptr, png_ptr->trans); - png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; -#endif -#endif -#ifdef PNG_READ_hIST_SUPPORTED -#ifdef PNG_FREE_ME_SUPPORTED - if (png_ptr->free_me & PNG_FREE_HIST) - png_free(png_ptr, png_ptr->hist); - png_ptr->free_me &= ~PNG_FREE_HIST; -#else - if (png_ptr->flags & PNG_FLAG_FREE_HIST) - png_free(png_ptr, png_ptr->hist); - png_ptr->flags &= ~PNG_FLAG_FREE_HIST; -#endif -#endif -#ifdef PNG_READ_GAMMA_SUPPORTED - if (png_ptr->gamma_16_table != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_table[i]); - } - png_free(png_ptr, png_ptr->gamma_16_table); - } -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->gamma_16_from_1 != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_from_1[i]); - } - png_free(png_ptr, png_ptr->gamma_16_from_1); - } - if (png_ptr->gamma_16_to_1 != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_to_1[i]); - } - png_free(png_ptr, png_ptr->gamma_16_to_1); - } -#endif -#endif -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_free(png_ptr, png_ptr->time_buffer); -#endif - - inflateEnd(&png_ptr->zstream); -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_free(png_ptr, png_ptr->save_buffer); -#endif - - /* Save the important info out of the png_struct, in case it is - * being used again. - */ -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); -#endif - - error_fn = png_ptr->error_fn; - warning_fn = png_ptr->warning_fn; - error_ptr = png_ptr->error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; -#endif - - png_memset(png_ptr, 0, png_sizeof(png_struct)); - - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; - png_ptr->error_ptr = error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr->free_fn = free_fn; -#endif - -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif - -} - -void PNGAPI -png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->read_row_fn = read_row_fn; -} - - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -#ifdef PNG_INFO_IMAGE_SUPPORTED -void PNGAPI -png_read_png(png_structp png_ptr, png_infop info_ptr, - int transforms, - voidp params) -{ - int row; - - if (png_ptr == NULL) - return; -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency - */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif - - /* png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). - */ - png_read_info(png_ptr, info_ptr); - if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) - png_error(png_ptr, "Image is too high to process with png_read_png()"); - - /* -------------- image transformations start here ------------------- */ - -#ifdef PNG_READ_16_TO_8_SUPPORTED - /* Tell libpng to strip 16 bit/color files down to 8 bits per color. - */ - if (transforms & PNG_TRANSFORM_STRIP_16) - png_set_strip_16(png_ptr); -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - /* Strip alpha bytes from the input data without combining with - * the background (not recommended). - */ - if (transforms & PNG_TRANSFORM_STRIP_ALPHA) - png_set_strip_alpha(png_ptr); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) - /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). - */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). - */ - if (transforms & PNG_TRANSFORM_PACKSWAP) - png_set_packswap(png_ptr); -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED - /* Expand paletted colors into true RGB triplets - * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel - * Expand paletted or RGB images with transparency to full alpha - * channels so the data will be available as RGBA quartets. - */ - if (transforms & PNG_TRANSFORM_EXPAND) - if ((png_ptr->bit_depth < 8) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || - (info_ptr->valid & PNG_INFO_tRNS)) - png_set_expand(png_ptr); -#endif - - /* We don't handle background color or gamma transformation or dithering. - */ - -#ifdef PNG_READ_INVERT_SUPPORTED - /* Invert monochrome files to have 0 as white and 1 as black - */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) - png_set_invert_mono(png_ptr); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - /* If you want to shift the pixel values from the range [0,255] or - * [0,65535] to the original [0,7] or [0,31], or whatever range the - * colors were originally in: - */ - if ((transforms & PNG_TRANSFORM_SHIFT) && (info_ptr->valid & PNG_INFO_sBIT)) - png_set_shift(png_ptr, &info_ptr->sig_bit); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - /* Flip the RGB pixels to BGR (or RGBA to BGRA) - */ - if (transforms & PNG_TRANSFORM_BGR) - png_set_bgr(png_ptr); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) - */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) - png_set_swap_alpha(png_ptr); -#endif - -#ifdef PNG_READ_SWAP_SUPPORTED - /* Swap bytes of 16 bit files to least significant byte first - */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) - png_set_swap(png_ptr); -#endif - -/* Added at libpng-1.2.41 */ -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency - */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif - -/* Added at libpng-1.2.41 */ -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* Expand grayscale image to RGB - */ - if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) - png_set_gray_to_rgb(png_ptr); -#endif - - /* We don't handle adding filler bytes */ - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (i.e., you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - /* -------------- image transformations end here ------------------- */ - -#ifdef PNG_FREE_ME_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); -#endif - if (info_ptr->row_pointers == NULL) - { - info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, - info_ptr->height * png_sizeof(png_bytep)); - png_memset(info_ptr->row_pointers, 0, info_ptr->height - * png_sizeof(png_bytep)); - -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_ROWS; -#endif - - for (row = 0; row < (int)info_ptr->height; row++) - info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, - png_get_rowbytes(png_ptr, info_ptr)); - } - - png_read_image(png_ptr, info_ptr->row_pointers); - info_ptr->valid |= PNG_INFO_IDAT; - - /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); - - PNG_UNUSED(transforms) /* Quiet compiler warnings */ - PNG_UNUSED(params) - -} -#endif /* PNG_INFO_IMAGE_SUPPORTED */ -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ + +/* pngread.c - read a PNG file + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED + +/* Create a PNG structure for reading, and allocate any memory needed. */ +png_structp PNGAPI +png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ + +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); +} + +/* Alternate create PNG structure for reading, and allocate any memory + * needed. + */ +png_structp PNGAPI +png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + +#ifdef PNG_SETJMP_SUPPORTED + volatile +#endif + png_structp png_ptr; + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + int i; + + png_debug(1, "in png_create_read_struct"); + +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); +#else + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); +#endif + if (png_ptr == NULL) + return (NULL); + + /* Added at libpng-1.2.6 */ +#ifdef PNG_USER_LIMITS_SUPPORTED + png_ptr->user_width_max = PNG_USER_WIDTH_MAX; + png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; + /* Added at libpng-1.2.43 and 1.4.0 */ + png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +#endif + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_ptr->jmpbuf)) +#endif + { + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, + (png_free_ptr)free_fn, (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + return (NULL); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); +#endif +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif + + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + if (user_png_ver) + { + i = 0; + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + } + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + png_snprintf(msg, 80, + "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + png_snprintf(msg, 80, + "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_error(png_ptr, + "Incompatible libpng version in application and library"); + } + } + + /* Initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); + break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); + break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); + +#ifdef PNG_SETJMP_SUPPORTED +/* Applications that neglect to set up their own setjmp() and then + encounter a png_error() will longjmp here. Since the jmpbuf is + then meaningless we abort instead of returning. */ +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) + PNG_ABORT(); + png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); +#else + if (setjmp(png_ptr->jmpbuf)) + PNG_ABORT(); +#endif +#endif /* PNG_SETJMP_SUPPORTED */ + + return (png_ptr); +} + +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* Initialize PNG structure for reading, and allocate any memory needed. + * This interface is deprecated in favour of the png_create_read_struct(), + * and it will disappear as of libpng-1.3.0. + */ +#undef png_read_init +void PNGAPI +png_read_init(png_structp png_ptr) +{ + /* We only come here via pre-1.0.7-compiled applications */ + png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0); +} + +void PNGAPI +png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size, png_size_t png_info_size) +{ + /* We only come here via pre-1.0.12-compiled applications */ + if (png_ptr == NULL) + return; +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + if (png_sizeof(png_struct) > png_struct_size || + png_sizeof(png_info) > png_info_size) + { + char msg[80]; + png_ptr->warning_fn = NULL; + if (user_png_ver) + { + png_snprintf(msg, 80, + "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + png_snprintf(msg, 80, + "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); + } +#endif + if (png_sizeof(png_struct) > png_struct_size) + { + png_ptr->error_fn = NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_error(png_ptr, + "The png struct allocated by the application for reading is" + " too small."); + } + if (png_sizeof(png_info) > png_info_size) + { + png_ptr->error_fn = NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_error(png_ptr, + "The info struct allocated by application for reading is" + " too small."); + } + png_read_init_3(&png_ptr, user_png_ver, png_struct_size); +} +#endif /* PNG_1_0_X || PNG_1_2_X */ + +void PNGAPI +png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* to save current jump buffer */ +#endif + + int i = 0; + + png_structp png_ptr=*ptr_ptr; + + if (png_ptr == NULL) + return; + + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + { +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; +#else + png_ptr->warning_fn = NULL; + png_warning(png_ptr, + "Application uses deprecated png_read_init() and should be" + " recompiled."); + break; +#endif + } + } while (png_libpng_ver[i++]); + + png_debug(1, "in png_read_init_3"); + +#ifdef PNG_SETJMP_SUPPORTED + /* Save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#endif + + if (png_sizeof(png_struct) > png_struct_size) + { + png_destroy_struct(png_ptr); + *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); + png_ptr = *ptr_ptr; + } + + /* Reset all variables to 0 */ + png_memset(png_ptr, 0, png_sizeof(png_struct)); + +#ifdef PNG_SETJMP_SUPPORTED + /* Restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); +#endif + + /* Added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max = PNG_USER_WIDTH_MAX; + png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; +#endif + + /* Initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); + break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* If we haven't checked all of the PNG signature bytes, do so now. */ + if (png_ptr->sig_bytes < 8) + { + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; + } + + for (;;) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST PNG_IHDR; + PNG_CONST PNG_IDAT; + PNG_CONST PNG_IEND; + PNG_CONST PNG_PLTE; +#ifdef PNG_READ_bKGD_SUPPORTED + PNG_CONST PNG_bKGD; +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + PNG_CONST PNG_cHRM; +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + PNG_CONST PNG_gAMA; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + PNG_CONST PNG_hIST; +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + PNG_CONST PNG_iCCP; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + PNG_CONST PNG_iTXt; +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + PNG_CONST PNG_oFFs; +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + PNG_CONST PNG_pCAL; +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + PNG_CONST PNG_pHYs; +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + PNG_CONST PNG_sBIT; +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + PNG_CONST PNG_sCAL; +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + PNG_CONST PNG_sPLT; +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + PNG_CONST PNG_sRGB; +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + PNG_CONST PNG_tEXt; +#endif +#ifdef PNG_READ_tIME_SUPPORTED + PNG_CONST PNG_tIME; +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + PNG_CONST PNG_tRNS; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + PNG_CONST PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + png_uint_32 length = png_read_chunk_header(png_ptr); + PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; + + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ + if (!png_memcmp(chunk_name, png_IDAT, 4)) + if (png_ptr->mode & PNG_AFTER_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + if (!png_memcmp(chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, chunk_name)) + { + if (!png_memcmp(chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + else if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + break; + } + } +#endif + else if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); + else if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->idat_size = length; + png_ptr->mode |= PNG_HAVE_IDAT; + break; + } +#ifdef PNG_READ_bKGD_SUPPORTED + else if (!png_memcmp(chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (!png_memcmp(chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + else if (!png_memcmp(chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (!png_memcmp(chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (!png_memcmp(chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (!png_memcmp(chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (!png_memcmp(chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (!png_memcmp(chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (!png_memcmp(chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (!png_memcmp(chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +/* Optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_update_info"); + + if (png_ptr == NULL) + return; + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + else + png_warning(png_ptr, + "Ignoring extra png_read_update_info() call; row buffer not reallocated"); + + png_read_transform_info(png_ptr, info_ptr); +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structp png_ptr) +{ + png_debug(1, "in png_start_read_image"); + + if (png_ptr == NULL) + return; + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void PNGAPI +png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) +{ + PNG_CONST PNG_IDAT; + PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, + 0xff}; + PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; + int ret; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_read_row (row %lu, pass %d)", + png_ptr->row_number, png_ptr->pass); + + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + !defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined."); +#endif + } + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* If interlaced and we do not need a new row, combine row and return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 1)) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "Invalid attempt to read row data"); + + png_ptr->zstream.next_out = png_ptr->row_buf; + png_ptr->zstream.avail_out = + (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); + do + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, + (png_size_t)png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_error(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression error"); + + } while (png_ptr->zstream.avail_out); + + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + if (png_ptr->row_buf[0]) + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, + png_ptr->rowbytes + 1); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && + (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) + /* Old interface (pre-1.0.9): + * png_do_read_interlace(&(png_ptr->row_info), + * png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + if (row != NULL) + png_combine_row(png_ptr, row, + png_pass_mask[png_ptr->pass]); + } + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, 0xff); + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 0xff); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ + +void PNGAPI +png_read_rows(png_structp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows"); + + if (png_ptr == NULL) + return; + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + else if (rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, png_bytep_NULL); + rp++; + } + else if (dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, png_bytep_NULL, dptr); + dp++; + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ +void PNGAPI +png_read_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i, image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + pass = png_set_interlace_handling(png_ptr); +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled."); + pass = 1; +#endif + + + image_height=png_ptr->height; + png_ptr->num_rows = image_height; /* Make sure this is set correctly */ + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, png_bytep_NULL); + rp++; + } + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_end"); + + if (png_ptr == NULL) + return; + png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ + + do + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST PNG_IHDR; + PNG_CONST PNG_IDAT; + PNG_CONST PNG_IEND; + PNG_CONST PNG_PLTE; +#ifdef PNG_READ_bKGD_SUPPORTED + PNG_CONST PNG_bKGD; +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + PNG_CONST PNG_cHRM; +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + PNG_CONST PNG_gAMA; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + PNG_CONST PNG_hIST; +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + PNG_CONST PNG_iCCP; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + PNG_CONST PNG_iTXt; +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + PNG_CONST PNG_oFFs; +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + PNG_CONST PNG_pCAL; +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + PNG_CONST PNG_pHYs; +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + PNG_CONST PNG_sBIT; +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + PNG_CONST PNG_sCAL; +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + PNG_CONST PNG_sPLT; +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + PNG_CONST PNG_sRGB; +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + PNG_CONST PNG_tEXt; +#endif +#ifdef PNG_READ_tIME_SUPPORTED + PNG_CONST PNG_tIME; +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + PNG_CONST PNG_tRNS; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + PNG_CONST PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + png_uint_32 length = png_read_chunk_header(png_ptr); + PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; + + if (!png_memcmp(chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, chunk_name)) + { + if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_error(png_ptr, "Too many IDAT's found"); + } + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + else if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. + */ + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_error(png_ptr, "Too many IDAT's found"); + png_crc_finish(png_ptr, length); + } + else if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); +#ifdef PNG_READ_bKGD_SUPPORTED + else if (!png_memcmp(chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (!png_memcmp(chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + else if (!png_memcmp(chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (!png_memcmp(chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (!png_memcmp(chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (!png_memcmp(chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (!png_memcmp(chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (!png_memcmp(chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (!png_memcmp(chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (!png_memcmp(chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } while (!(png_ptr->mode & PNG_HAVE_IEND)); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +/* Free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL, end_info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_read_struct"); + + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + if (png_ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (end_info_ptr_ptr != NULL) + end_info_ptr = *end_info_ptr_ptr; + + png_read_destroy(png_ptr, info_ptr, end_info_ptr); + + if (info_ptr != NULL) + { +#ifdef PNG_TEXT_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } + + if (end_info_ptr != NULL) + { +#ifdef PNG_READ_TEXT_SUPPORTED + png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); +#endif +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)end_info_ptr); +#endif + *end_info_ptr_ptr = NULL; + } + + if (png_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = NULL; + } +} + +/* Free all memory used by the read (old method) */ +void /* PRIVATE */ +png_read_destroy(png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_read_destroy"); + + if (info_ptr != NULL) + png_info_destroy(png_ptr, info_ptr); + + if (end_info_ptr != NULL) + png_info_destroy(png_ptr, end_info_ptr); + + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->chunkdata); +#ifdef PNG_READ_DITHER_SUPPORTED + png_free(png_ptr, png_ptr->palette_lookup); + png_free(png_ptr, png_ptr->dither_index); +#endif +#ifdef PNG_READ_GAMMA_SUPPORTED + png_free(png_ptr, png_ptr->gamma_table); +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED + png_free(png_ptr, png_ptr->gamma_from_1); + png_free(png_ptr, png_ptr->gamma_to_1); +#endif +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->free_me &= ~PNG_FREE_PLTE; +#else + if (png_ptr->flags & PNG_FLAG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; +#endif +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans); + png_ptr->free_me &= ~PNG_FREE_TRNS; +#else + if (png_ptr->flags & PNG_FLAG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans); + png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; +#endif +#endif +#ifdef PNG_READ_hIST_SUPPORTED +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->free_me &= ~PNG_FREE_HIST; +#else + if (png_ptr->flags & PNG_FLAG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->flags &= ~PNG_FLAG_FREE_HIST; +#endif +#endif +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + } +#endif +#endif +#ifdef PNG_TIME_RFC1123_SUPPORTED + png_free(png_ptr, png_ptr->time_buffer); +#endif + + inflateEnd(&png_ptr->zstream); +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); +#endif + + /* Save the important info out of the png_struct, in case it is + * being used again. + */ +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, png_sizeof(png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); +#endif + +} + +void PNGAPI +png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->read_row_fn = read_row_fn; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_read_png(png_structp png_ptr, png_infop info_ptr, + int transforms, + voidp params) +{ + int row; + + if (png_ptr == NULL) + return; +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency + */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error(png_ptr, "Image is too high to process with png_read_png()"); + + /* -------------- image transformations start here ------------------- */ + +#ifdef PNG_READ_16_TO_8_SUPPORTED + /* Tell libpng to strip 16 bit/color files down to 8 bits per color. + */ + if (transforms & PNG_TRANSFORM_STRIP_16) + png_set_strip_16(png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). + */ + if (transforms & PNG_TRANSFORM_STRIP_ALPHA) + png_set_strip_alpha(png_ptr); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). + */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if (transforms & PNG_TRANSFORM_EXPAND) + if ((png_ptr->bit_depth < 8) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || + (info_ptr->valid & PNG_INFO_tRNS)) + png_set_expand(png_ptr); +#endif + + /* We don't handle background color or gamma transformation or dithering. + */ + +#ifdef PNG_READ_INVERT_SUPPORTED + /* Invert monochrome files to have 0 as white and 1 as black + */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + /* Flip the RGB pixels to BGR (or RGBA to BGRA) + */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) + */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#ifdef PNG_READ_SWAP_SUPPORTED + /* Swap bytes of 16 bit files to least significant byte first + */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency + */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Expand grayscale image to RGB + */ + if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) + png_set_gray_to_rgb(png_ptr); +#endif + + /* We don't handle adding filler bytes */ + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); +#endif + if (info_ptr->row_pointers == NULL) + { + info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, + info_ptr->height * png_sizeof(png_bytep)); + png_memset(info_ptr->row_pointers, 0, info_ptr->height + * png_sizeof(png_bytep)); + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_ROWS; +#endif + + for (row = 0; row < (int)info_ptr->height; row++) + info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr)); + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + PNG_UNUSED(transforms) /* Quiet compiler warnings */ + PNG_UNUSED(params) + +} +#endif /* PNG_INFO_IMAGE_SUPPORTED */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngrio.c b/main/source/includes/lpng1251/pngrio.c index e84380e2..6978682c 100644 --- a/main/source/includes/lpng1251/pngrio.c +++ b/main/source/includes/lpng1251/pngrio.c @@ -1,180 +1,180 @@ - -/* pngrio.c - functions for data input - * - * Last changed in libpng 1.2.43 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all input. Users who need - * special handling are expected to write a function that has the same - * arguments as this and performs a similar function, but that possibly - * has a different input method. Note that you shouldn't change this - * function, but rather write a replacement function and then make - * libpng use it at run time with png_set_read_fn(...). - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED - -/* Read the data from whatever input you are using. The default routine - * reads from a file pointer. Note that this routine sometimes gets called - * with very small lengths, so you should implement some kind of simple - * buffering if you are using unbuffered reads. This should never be asked - * to read more then 64K on a 16 bit machine. - */ -void /* PRIVATE */ -png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_debug1(4, "reading %d bytes", (int)length); - - if (png_ptr->read_data_fn != NULL) - (*(png_ptr->read_data_fn))(png_ptr, data, length); - else - png_error(png_ptr, "Call to NULL read function"); -} - -#ifdef PNG_STDIO_SUPPORTED -/* This is the function that does the actual reading of data. If you are - * not reading from a standard C stream, you should create a replacement - * read_data function and use it at run time with png_set_read_fn(), rather - * than changing the library. - */ -#ifndef USE_FAR_KEYWORD -void PNGAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - - if (png_ptr == NULL) - return; - /* fread() returns 0 on error, so it is OK to store this in a png_size_t - * instead of an int, which is what fread() actually returns. - */ -#ifdef _WIN32_WCE - if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) - check = 0; -#else - check = (png_size_t)fread(data, (png_size_t)1, length, - (png_FILE_p)png_ptr->io_ptr); -#endif - - if (check != length) - png_error(png_ptr, "Read Error"); -} -#else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void PNGAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - int check; - png_byte *n_data; - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - /* Check if data really is near. If so, use usual code. */ - n_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)n_data == data) - { -#ifdef _WIN32_WCE - if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, - NULL) ) - check = 0; -#else - check = fread(n_data, 1, length, io_ptr); -#endif - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); -#ifdef _WIN32_WCE - if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) ) - err = 0; -#else - err = fread(buf, (png_size_t)1, read, io_ptr); -#endif - png_memcpy(data, buf, read); /* copy far buffer to near buffer */ - if (err != read) - break; - else - check += err; - data += read; - remaining -= read; - } - while (remaining != 0); - } - if ((png_uint_32)check != (png_uint_32)length) - png_error(png_ptr, "read Error"); -} -#endif -#endif - -/* This function allows the application to supply a new input function - * for libpng if standard C streams aren't being used. - * - * This function takes as its arguments: - * png_ptr - pointer to a png input data structure - * io_ptr - pointer to user supplied structure containing info about - * the input functions. May be NULL. - * read_data_fn - pointer to a new input function that takes as its - * arguments a pointer to a png_struct, a pointer to - * a location where input data can be stored, and a 32-bit - * unsigned int that is the number of bytes to be read. - * To exit and output any fatal error messages the new write - * function should call png_error(png_ptr, "Error msg"). - * May be NULL, in which case libpng's default function will - * be used. - */ -void PNGAPI -png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, - png_rw_ptr read_data_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->io_ptr = io_ptr; - -#ifdef PNG_STDIO_SUPPORTED - if (read_data_fn != NULL) - png_ptr->read_data_fn = read_data_fn; - else - png_ptr->read_data_fn = png_default_read_data; -#else - png_ptr->read_data_fn = read_data_fn; -#endif - - /* It is an error to write to a read device */ - if (png_ptr->write_data_fn != NULL) - { - png_ptr->write_data_fn = NULL; - png_warning(png_ptr, - "It's an error to set both read_data_fn and write_data_fn in the "); - png_warning(png_ptr, - "same structure. Resetting write_data_fn to NULL."); - } - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_ptr->output_flush_fn = NULL; -#endif -} -#endif /* PNG_READ_SUPPORTED */ + +/* pngrio.c - functions for data input + * + * Last changed in libpng 1.2.43 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED + +/* Read the data from whatever input you are using. The default routine + * reads from a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered reads. This should never be asked + * to read more then 64K on a 16 bit machine. + */ +void /* PRIVATE */ +png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_debug1(4, "reading %d bytes", (int)length); + + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL read function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + if (png_ptr == NULL) + return; + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ +#ifdef _WIN32_WCE + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = (png_size_t)fread(data, (png_size_t)1, length, + (png_FILE_p)png_ptr->io_ptr); +#endif + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#else +/* This is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void PNGAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + if (png_ptr == NULL) + return; + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { +#ifdef _WIN32_WCE + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, + NULL) ) + check = 0; +#else + check = fread(n_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); +#ifdef _WIN32_WCE + if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) ) + err = 0; +#else + err = fread(buf, (png_size_t)1, read, io_ptr); +#endif + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if (err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if ((png_uint_32)check != (png_uint_32)length) + png_error(png_ptr, "read Error"); +} +#endif +#endif + +/* This function allows the application to supply a new input function + * for libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png input data structure + * io_ptr - pointer to user supplied structure containing info about + * the input functions. May be NULL. + * read_data_fn - pointer to a new input function that takes as its + * arguments a pointer to a png_struct, a pointer to + * a location where input data can be stored, and a 32-bit + * unsigned int that is the number of bytes to be read. + * To exit and output any fatal error messages the new write + * function should call png_error(png_ptr, "Error msg"). + * May be NULL, in which case libpng's default function will + * be used. + */ +void PNGAPI +png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "It's an error to set both read_data_fn and write_data_fn in the "); + png_warning(png_ptr, + "same structure. Resetting write_data_fn to NULL."); + } + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->output_flush_fn = NULL; +#endif +} +#endif /* PNG_READ_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngrtran.c b/main/source/includes/lpng1251/pngrtran.c index b50da4d9..9e8ff9f0 100644 --- a/main/source/includes/lpng1251/pngrtran.c +++ b/main/source/includes/lpng1251/pngrtran.c @@ -1,4473 +1,4473 @@ - -/* pngrtran.c - transforms the data in a row for PNG readers - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains functions optionally called by an application - * in order to tell libpng how to handle data when reading a PNG. - * Transformations that are used in both reading and writing are - * in pngtrans.c. - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED - -/* Set the action on getting a CRC error for an ancillary or critical chunk. */ -void PNGAPI -png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) -{ - png_debug(1, "in png_set_crc_action"); - - if (png_ptr == NULL) - return; - - /* Tell libpng how we react to CRC errors in critical chunks */ - switch (crit_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | - PNG_FLAG_CRC_CRITICAL_IGNORE; - break; - - case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ - png_warning(png_ptr, - "Can't discard critical data on CRC error."); - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - break; - } - - /* Tell libpng how we react to CRC errors in ancillary chunks */ - switch (ancil_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | - PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - break; - } -} - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - defined(PNG_FLOATING_POINT_SUPPORTED) -/* Handle alpha and tRNS via a background color */ -void PNGAPI -png_set_background(png_structp png_ptr, - png_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma) -{ - png_debug(1, "in png_set_background"); - - if (png_ptr == NULL) - return; - if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) - { - png_warning(png_ptr, "Application must supply a known background gamma"); - return; - } - - png_ptr->transformations |= PNG_BACKGROUND; - png_memcpy(&(png_ptr->background), background_color, - png_sizeof(png_color_16)); - png_ptr->background_gamma = (float)background_gamma; - png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); -} -#endif - -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Strip 16 bit depth files to 8 bit depth */ -void PNGAPI -png_set_strip_16(png_structp png_ptr) -{ - png_debug(1, "in png_set_strip_16"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_16_TO_8; -} -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -void PNGAPI -png_set_strip_alpha(png_structp png_ptr) -{ - png_debug(1, "in png_set_strip_alpha"); - - if (png_ptr == NULL) - return; - png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; -} -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED -/* Dither file to 8 bit. Supply a palette, the current number - * of elements in the palette, the maximum number of elements - * allowed, and a histogram if possible. If the current number - * of colors is greater then the maximum number, the palette will be - * modified to fit in the maximum number. "full_dither" indicates - * whether we need a dithering cube set up for RGB images, or if we - * simply are reducing the number of colors in a paletted image. - */ - -typedef struct png_dsort_struct -{ - struct png_dsort_struct FAR * next; - png_byte left; - png_byte right; -} png_dsort; -typedef png_dsort FAR * png_dsortp; -typedef png_dsort FAR * FAR * png_dsortpp; - -void PNGAPI -png_set_dither(png_structp png_ptr, png_colorp palette, - int num_palette, int maximum_colors, png_uint_16p histogram, - int full_dither) -{ - png_debug(1, "in png_set_dither"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_DITHER; - - if (!full_dither) - { - int i; - - png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - for (i = 0; i < num_palette; i++) - png_ptr->dither_index[i] = (png_byte)i; - } - - if (num_palette > maximum_colors) - { - if (histogram != NULL) - { - /* This is easy enough, just throw out the least used colors. - * Perhaps not the best solution, but good enough. - */ - - int i; - - /* Initialize an array to sort colors */ - png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - - /* Initialize the dither_sort array */ - for (i = 0; i < num_palette; i++) - png_ptr->dither_sort[i] = (png_byte)i; - - /* Find the least used palette entries by starting a - * bubble sort, and running it until we have sorted - * out enough colors. Note that we don't care about - * sorting all the colors, just finding which are - * least used. - */ - - for (i = num_palette - 1; i >= maximum_colors; i--) - { - int done; /* To stop early if the list is pre-sorted */ - int j; - - done = 1; - for (j = 0; j < i; j++) - { - if (histogram[png_ptr->dither_sort[j]] - < histogram[png_ptr->dither_sort[j + 1]]) - { - png_byte t; - - t = png_ptr->dither_sort[j]; - png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1]; - png_ptr->dither_sort[j + 1] = t; - done = 0; - } - } - if (done) - break; - } - - /* Swap the palette around, and set up a table, if necessary */ - if (full_dither) - { - int j = num_palette; - - /* Put all the useful colors within the max, but don't - * move the others. - */ - for (i = 0; i < maximum_colors; i++) - { - if ((int)png_ptr->dither_sort[i] >= maximum_colors) - { - do - j--; - while ((int)png_ptr->dither_sort[j] >= maximum_colors); - palette[i] = palette[j]; - } - } - } - else - { - int j = num_palette; - - /* Move all the used colors inside the max limit, and - * develop a translation table. - */ - for (i = 0; i < maximum_colors; i++) - { - /* Only move the colors we need to */ - if ((int)png_ptr->dither_sort[i] >= maximum_colors) - { - png_color tmp_color; - - do - j--; - while ((int)png_ptr->dither_sort[j] >= maximum_colors); - - tmp_color = palette[j]; - palette[j] = palette[i]; - palette[i] = tmp_color; - /* Indicate where the color went */ - png_ptr->dither_index[j] = (png_byte)i; - png_ptr->dither_index[i] = (png_byte)j; - } - } - - /* Find closest color for those colors we are not using */ - for (i = 0; i < num_palette; i++) - { - if ((int)png_ptr->dither_index[i] >= maximum_colors) - { - int min_d, k, min_k, d_index; - - /* Find the closest color to one we threw out */ - d_index = png_ptr->dither_index[i]; - min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); - for (k = 1, min_k = 0; k < maximum_colors; k++) - { - int d; - - d = PNG_COLOR_DIST(palette[d_index], palette[k]); - - if (d < min_d) - { - min_d = d; - min_k = k; - } - } - /* Point to closest color */ - png_ptr->dither_index[i] = (png_byte)min_k; - } - } - } - png_free(png_ptr, png_ptr->dither_sort); - png_ptr->dither_sort = NULL; - } - else - { - /* This is much harder to do simply (and quickly). Perhaps - * we need to go through a median cut routine, but those - * don't always behave themselves with only a few colors - * as input. So we will just find the closest two colors, - * and throw out one of them (chosen somewhat randomly). - * [We don't understand this at all, so if someone wants to - * work on improving it, be our guest - AED, GRP] - */ - int i; - int max_d; - int num_new_palette; - png_dsortp t; - png_dsortpp hash; - - t = NULL; - - /* Initialize palette index arrays */ - png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - - /* Initialize the sort array */ - for (i = 0; i < num_palette; i++) - { - png_ptr->index_to_palette[i] = (png_byte)i; - png_ptr->palette_to_index[i] = (png_byte)i; - } - - hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * - png_sizeof(png_dsortp))); - - num_new_palette = num_palette; - - /* Initial wild guess at how far apart the farthest pixel - * pair we will be eliminating will be. Larger - * numbers mean more areas will be allocated, Smaller - * numbers run the risk of not saving enough data, and - * having to do this all over again. - * - * I have not done extensive checking on this number. - */ - max_d = 96; - - while (num_new_palette > maximum_colors) - { - for (i = 0; i < num_new_palette - 1; i++) - { - int j; - - for (j = i + 1; j < num_new_palette; j++) - { - int d; - - d = PNG_COLOR_DIST(palette[i], palette[j]); - - if (d <= max_d) - { - - t = (png_dsortp)png_malloc_warn(png_ptr, - (png_uint_32)(png_sizeof(png_dsort))); - if (t == NULL) - break; - t->next = hash[d]; - t->left = (png_byte)i; - t->right = (png_byte)j; - hash[d] = t; - } - } - if (t == NULL) - break; - } - - if (t != NULL) - for (i = 0; i <= max_d; i++) - { - if (hash[i] != NULL) - { - png_dsortp p; - - for (p = hash[i]; p; p = p->next) - { - if ((int)png_ptr->index_to_palette[p->left] - < num_new_palette && - (int)png_ptr->index_to_palette[p->right] - < num_new_palette) - { - int j, next_j; - - if (num_new_palette & 0x01) - { - j = p->left; - next_j = p->right; - } - else - { - j = p->right; - next_j = p->left; - } - - num_new_palette--; - palette[png_ptr->index_to_palette[j]] - = palette[num_new_palette]; - if (!full_dither) - { - int k; - - for (k = 0; k < num_palette; k++) - { - if (png_ptr->dither_index[k] == - png_ptr->index_to_palette[j]) - png_ptr->dither_index[k] = - png_ptr->index_to_palette[next_j]; - if ((int)png_ptr->dither_index[k] == - num_new_palette) - png_ptr->dither_index[k] = - png_ptr->index_to_palette[j]; - } - } - - png_ptr->index_to_palette[png_ptr->palette_to_index - [num_new_palette]] = png_ptr->index_to_palette[j]; - png_ptr->palette_to_index[png_ptr->index_to_palette[j]] - = png_ptr->palette_to_index[num_new_palette]; - - png_ptr->index_to_palette[j] = - (png_byte)num_new_palette; - png_ptr->palette_to_index[num_new_palette] = - (png_byte)j; - } - if (num_new_palette <= maximum_colors) - break; - } - if (num_new_palette <= maximum_colors) - break; - } - } - - for (i = 0; i < 769; i++) - { - if (hash[i] != NULL) - { - png_dsortp p = hash[i]; - while (p) - { - t = p->next; - png_free(png_ptr, p); - p = t; - } - } - hash[i] = 0; - } - max_d += 96; - } - png_free(png_ptr, hash); - png_free(png_ptr, png_ptr->palette_to_index); - png_free(png_ptr, png_ptr->index_to_palette); - png_ptr->palette_to_index = NULL; - png_ptr->index_to_palette = NULL; - } - num_palette = maximum_colors; - } - if (png_ptr->palette == NULL) - { - png_ptr->palette = palette; - } - png_ptr->num_palette = (png_uint_16)num_palette; - - if (full_dither) - { - int i; - png_bytep distance; - int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS + - PNG_DITHER_BLUE_BITS; - int num_red = (1 << PNG_DITHER_RED_BITS); - int num_green = (1 << PNG_DITHER_GREEN_BITS); - int num_blue = (1 << PNG_DITHER_BLUE_BITS); - png_size_t num_entries = ((png_size_t)1 << total_bits); - - png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr, - (png_uint_32)(num_entries * png_sizeof(png_byte))); - - distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * - png_sizeof(png_byte))); - png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); - - for (i = 0; i < num_palette; i++) - { - int ir, ig, ib; - int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS)); - int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS)); - int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS)); - - for (ir = 0; ir < num_red; ir++) - { - /* int dr = abs(ir - r); */ - int dr = ((ir > r) ? ir - r : r - ir); - int index_r = (ir << (PNG_DITHER_BLUE_BITS + - PNG_DITHER_GREEN_BITS)); - - for (ig = 0; ig < num_green; ig++) - { - /* int dg = abs(ig - g); */ - int dg = ((ig > g) ? ig - g : g - ig); - int dt = dr + dg; - int dm = ((dr > dg) ? dr : dg); - int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS); - - for (ib = 0; ib < num_blue; ib++) - { - int d_index = index_g | ib; - /* int db = abs(ib - b); */ - int db = ((ib > b) ? ib - b : b - ib); - int dmax = ((dm > db) ? dm : db); - int d = dmax + dt + db; - - if (d < (int)distance[d_index]) - { - distance[d_index] = (png_byte)d; - png_ptr->palette_lookup[d_index] = (png_byte)i; - } - } - } - } - } - - png_free(png_ptr, distance); - } -} -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) -/* Transform the image from the file_gamma to the screen_gamma. We - * only do transformations on images where the file_gamma and screen_gamma - * are not close reciprocals, otherwise it slows things down slightly, and - * also needlessly introduces small errors. - * - * We will turn off gamma transformation later if no semitransparent entries - * are present in the tRNS array for palette images. We can't do it here - * because we don't necessarily have the tRNS chunk yet. - */ -void PNGAPI -png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) -{ - png_debug(1, "in png_set_gamma"); - - if (png_ptr == NULL) - return; - - if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) - png_ptr->transformations |= PNG_GAMMA; - png_ptr->gamma = (float)file_gamma; - png_ptr->screen_gamma = (float)scrn_gamma; -} -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* Expand paletted images to RGB, expand grayscale images of - * less than 8-bit depth to 8-bit depth, and expand tRNS chunks - * to alpha channels. - */ -void PNGAPI -png_set_expand(png_structp png_ptr) -{ - png_debug(1, "in png_set_expand"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} - -/* GRR 19990627: the following three functions currently are identical - * to png_set_expand(). However, it is entirely reasonable that someone - * might wish to expand an indexed image to RGB but *not* expand a single, - * fully transparent palette entry to a full alpha channel--perhaps instead - * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace - * the transparent color with a particular RGB value, or drop tRNS entirely. - * IOW, a future version of the library may make the transformations flag - * a bit more fine-grained, with separate bits for each of these three - * functions. - * - * More to the point, these functions make it obvious what libpng will be - * doing, whereas "expand" can (and does) mean any number of things. - * - * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified - * to expand only the sample depth but not to expand the tRNS to alpha - * and its name was changed to png_set_expand_gray_1_2_4_to_8(). - */ - -/* Expand paletted images to RGB. */ -void PNGAPI -png_set_palette_to_rgb(png_structp png_ptr) -{ - png_debug(1, "in png_set_palette_to_rgb"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} - -#ifndef PNG_1_0_X -/* Expand grayscale images of less than 8-bit depth to 8 bits. */ -void PNGAPI -png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) -{ - png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_EXPAND; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} -#endif - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* Expand grayscale images of less than 8-bit depth to 8 bits. */ -/* Deprecated as of libpng-1.2.9 */ -void PNGAPI -png_set_gray_1_2_4_to_8(png_structp png_ptr) -{ - png_debug(1, "in png_set_gray_1_2_4_to_8"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); -} -#endif - - -/* Expand tRNS chunks to alpha channels. */ -void PNGAPI -png_set_tRNS_to_alpha(png_structp png_ptr) -{ - png_debug(1, "in png_set_tRNS_to_alpha"); - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} -#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -void PNGAPI -png_set_gray_to_rgb(png_structp png_ptr) -{ - png_debug(1, "in png_set_gray_to_rgb"); - - png_ptr->transformations |= PNG_GRAY_TO_RGB; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -/* Convert a RGB image to a grayscale of the same width. This allows us, - * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. - */ - -void PNGAPI -png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, - double green) -{ - int red_fixed, green_fixed; - if (png_ptr == NULL) - return; - if (red > 21474.83647 || red < -21474.83648 || - green > 21474.83647 || green < -21474.83648) - { - png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); - red_fixed = -1; - green_fixed = -1; - } - else - { - red_fixed = (int)((float)red*100000.0 + 0.5); - green_fixed = (int)((float)green*100000.0 + 0.5); - } - png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); -} -#endif - -void PNGAPI -png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, - png_fixed_point red, png_fixed_point green) -{ - png_debug(1, "in png_set_rgb_to_gray"); - - if (png_ptr == NULL) - return; - - switch(error_action) - { - case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY; - break; - - case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; - break; - - case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; - } - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#ifdef PNG_READ_EXPAND_SUPPORTED - png_ptr->transformations |= PNG_EXPAND; -#else - { - png_warning(png_ptr, - "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED."); - png_ptr->transformations &= ~PNG_RGB_TO_GRAY; - } -#endif - { - png_uint_16 red_int, green_int; - if (red < 0 || green < 0) - { - red_int = 6968; /* .212671 * 32768 + .5 */ - green_int = 23434; /* .715160 * 32768 + .5 */ - } - else if (red + green < 100000L) - { - red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); - green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); - } - else - { - png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); - red_int = 6968; - green_int = 23434; - } - png_ptr->rgb_to_gray_red_coeff = red_int; - png_ptr->rgb_to_gray_green_coeff = green_int; - png_ptr->rgb_to_gray_blue_coeff = - (png_uint_16)(32768 - red_int - green_int); - } -} -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -void PNGAPI -png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr - read_user_transform_fn) -{ - png_debug(1, "in png_set_read_user_transform_fn"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - png_ptr->transformations |= PNG_USER_TRANSFORM; - png_ptr->read_user_transform_fn = read_user_transform_fn; -#endif -#ifdef PNG_LEGACY_SUPPORTED - if (read_user_transform_fn) - png_warning(png_ptr, - "This version of libpng does not support user transforms"); -#endif -} -#endif - -/* Initialize everything needed for the read. This includes modifying - * the palette. - */ -void /* PRIVATE */ -png_init_read_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_init_read_transformations"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (png_ptr != NULL) -#endif - { -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_SHIFT_SUPPORTED) || \ - defined(PNG_READ_GAMMA_SUPPORTED) - int color_type = png_ptr->color_type; -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* Detect gray background and attempt to enable optimization - * for gray --> RGB case - * - * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or - * RGB_ALPHA (in which case need_expand is superfluous anyway), the - * background color might actually be gray yet not be flagged as such. - * This is not a problem for the current code, which uses - * PNG_BACKGROUND_IS_GRAY only to decide when to do the - * png_do_gray_to_rgb() transformation. - */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - !(color_type & PNG_COLOR_MASK_COLOR)) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - } else if ((png_ptr->transformations & PNG_BACKGROUND) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_GRAY_TO_RGB) && - png_ptr->background.red == png_ptr->background.green && - png_ptr->background.red == png_ptr->background.blue) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - png_ptr->background.gray = png_ptr->background.red; - } -#endif - - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND)) - { - if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ - { - /* Expand background and tRNS chunks */ - switch (png_ptr->bit_depth) - { - case 1: - png_ptr->background.gray *= (png_uint_16)0xff; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_values.gray *= (png_uint_16)0xff; - png_ptr->trans_values.red = png_ptr->trans_values.green - = png_ptr->trans_values.blue = png_ptr->trans_values.gray; - } - break; - - case 2: - png_ptr->background.gray *= (png_uint_16)0x55; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_values.gray *= (png_uint_16)0x55; - png_ptr->trans_values.red = png_ptr->trans_values.green - = png_ptr->trans_values.blue = png_ptr->trans_values.gray; - } - break; - - case 4: - png_ptr->background.gray *= (png_uint_16)0x11; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_values.gray *= (png_uint_16)0x11; - png_ptr->trans_values.red = png_ptr->trans_values.green - = png_ptr->trans_values.blue = png_ptr->trans_values.gray; - } - break; - - case 8: - - case 16: - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - break; - } - } - else if (color_type == PNG_COLOR_TYPE_PALETTE) - { - png_ptr->background.red = - png_ptr->palette[png_ptr->background.index].red; - png_ptr->background.green = - png_ptr->palette[png_ptr->background.index].green; - png_ptr->background.blue = - png_ptr->palette[png_ptr->background.index].blue; - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - { -#ifdef PNG_READ_EXPAND_SUPPORTED - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) -#endif - { - /* Invert the alpha channel (in tRNS) unless the pixels are - * going to be expanded, in which case leave it for later - */ - int i, istop; - istop=(int)png_ptr->num_trans; - for (i=0; itrans[i] = (png_byte)(255 - png_ptr->trans[i]); - } - } -#endif - - } - } -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - png_ptr->background_1 = png_ptr->background; -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) - - if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) - && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0) - < PNG_GAMMA_THRESHOLD)) - { - int i, k; - k=0; - for (i=0; inum_trans; i++) - { - if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff) - { - k=1; /* Partial transparency is present */ - break; - } - } - if (k == 0) - png_ptr->transformations &= ~PNG_GAMMA; - } - - if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) && - png_ptr->gamma != 0.0) - { - png_build_gamma_table(png_ptr); - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) - { - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - /* Could skip if no transparency */ - png_color back, back_1; - png_colorp palette = png_ptr->palette; - int num_palette = png_ptr->num_palette; - int i; - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) - { - back.red = png_ptr->gamma_table[png_ptr->background.red]; - back.green = png_ptr->gamma_table[png_ptr->background.green]; - back.blue = png_ptr->gamma_table[png_ptr->background.blue]; - - back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; - back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; - back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; - } - else - { - double g, gs; - - switch (png_ptr->background_gamma_type) - { - case PNG_BACKGROUND_GAMMA_SCREEN: - g = (png_ptr->screen_gamma); - gs = 1.0; - break; - - case PNG_BACKGROUND_GAMMA_FILE: - g = 1.0 / (png_ptr->gamma); - gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - break; - - case PNG_BACKGROUND_GAMMA_UNIQUE: - g = 1.0 / (png_ptr->background_gamma); - gs = 1.0 / (png_ptr->background_gamma * - png_ptr->screen_gamma); - break; - default: - g = 1.0; /* back_1 */ - gs = 1.0; /* back */ - } - - if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) - { - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - } - else - { - back.red = (png_byte)(pow( - (double)png_ptr->background.red/255, gs) * 255.0 + .5); - back.green = (png_byte)(pow( - (double)png_ptr->background.green/255, gs) * 255.0 - + .5); - back.blue = (png_byte)(pow( - (double)png_ptr->background.blue/255, gs) * 255.0 + .5); - } - - back_1.red = (png_byte)(pow( - (double)png_ptr->background.red/255, g) * 255.0 + .5); - back_1.green = (png_byte)(pow( - (double)png_ptr->background.green/255, g) * 255.0 + .5); - back_1.blue = (png_byte)(pow( - (double)png_ptr->background.blue/255, g) * 255.0 + .5); - } - for (i = 0; i < num_palette; i++) - { - if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff) - { - if (png_ptr->trans[i] == 0) - { - palette[i] = back; - } - else /* if (png_ptr->trans[i] != 0xff) */ - { - png_byte v, w; - - v = png_ptr->gamma_to_1[palette[i].red]; - png_composite(w, v, png_ptr->trans[i], back_1.red); - palette[i].red = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].green]; - png_composite(w, v, png_ptr->trans[i], back_1.green); - palette[i].green = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].blue]; - png_composite(w, v, png_ptr->trans[i], back_1.blue); - palette[i].blue = png_ptr->gamma_from_1[w]; - } - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - /* Prevent the transformations being done again, and make sure - * that the now spurious alpha channel is stripped - the code - * has just reduced background composition and gamma correction - * to a simple alpha channel strip. - */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations &= ~PNG_GAMMA; - png_ptr->transformations |= PNG_STRIP_ALPHA; - } - /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ - else - /* color_type != PNG_COLOR_TYPE_PALETTE */ - { - double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1); - double g = 1.0; - double gs = 1.0; - - switch (png_ptr->background_gamma_type) - { - case PNG_BACKGROUND_GAMMA_SCREEN: - g = (png_ptr->screen_gamma); - gs = 1.0; - break; - - case PNG_BACKGROUND_GAMMA_FILE: - g = 1.0 / (png_ptr->gamma); - gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - break; - - case PNG_BACKGROUND_GAMMA_UNIQUE: - g = 1.0 / (png_ptr->background_gamma); - gs = 1.0 / (png_ptr->background_gamma * - png_ptr->screen_gamma); - break; - } - - png_ptr->background_1.gray = (png_uint_16)(pow( - (double)png_ptr->background.gray / m, g) * m + .5); - png_ptr->background.gray = (png_uint_16)(pow( - (double)png_ptr->background.gray / m, gs) * m + .5); - - if ((png_ptr->background.red != png_ptr->background.green) || - (png_ptr->background.red != png_ptr->background.blue) || - (png_ptr->background.red != png_ptr->background.gray)) - { - /* RGB or RGBA with color background */ - png_ptr->background_1.red = (png_uint_16)(pow( - (double)png_ptr->background.red / m, g) * m + .5); - png_ptr->background_1.green = (png_uint_16)(pow( - (double)png_ptr->background.green / m, g) * m + .5); - png_ptr->background_1.blue = (png_uint_16)(pow( - (double)png_ptr->background.blue / m, g) * m + .5); - png_ptr->background.red = (png_uint_16)(pow( - (double)png_ptr->background.red / m, gs) * m + .5); - png_ptr->background.green = (png_uint_16)(pow( - (double)png_ptr->background.green / m, gs) * m + .5); - png_ptr->background.blue = (png_uint_16)(pow( - (double)png_ptr->background.blue / m, gs) * m + .5); - } - else - { - /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ - png_ptr->background_1.red = png_ptr->background_1.green - = png_ptr->background_1.blue = png_ptr->background_1.gray; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - } - } - } - else - /* Transformation does not include PNG_BACKGROUND */ -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - png_colorp palette = png_ptr->palette; - int num_palette = png_ptr->num_palette; - int i; - - for (i = 0; i < num_palette; i++) - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - - /* Done the gamma correction. */ - png_ptr->transformations &= ~PNG_GAMMA; - } - } -#ifdef PNG_READ_BACKGROUND_SUPPORTED - else -#endif -#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */ -#ifdef PNG_READ_BACKGROUND_SUPPORTED - /* No GAMMA transformation */ - if ((png_ptr->transformations & PNG_BACKGROUND) && - (color_type == PNG_COLOR_TYPE_PALETTE)) - { - int i; - int istop = (int)png_ptr->num_trans; - png_color back; - png_colorp palette = png_ptr->palette; - - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - - for (i = 0; i < istop; i++) - { - if (png_ptr->trans[i] == 0) - { - palette[i] = back; - } - else if (png_ptr->trans[i] != 0xff) - { - /* The png_composite() macro is defined in png.h */ - png_composite(palette[i].red, palette[i].red, - png_ptr->trans[i], back.red); - png_composite(palette[i].green, palette[i].green, - png_ptr->trans[i], back.green); - png_composite(palette[i].blue, palette[i].blue, - png_ptr->trans[i], back.blue); - } - } - - /* Handled alpha, still need to strip the channel. */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations |= PNG_STRIP_ALPHA; - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - -#ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) && - !(png_ptr->transformations & PNG_EXPAND) && - (color_type == PNG_COLOR_TYPE_PALETTE)) - { - png_uint_16 i; - png_uint_16 istop = png_ptr->num_palette; - int sr = 8 - png_ptr->sig_bit.red; - int sg = 8 - png_ptr->sig_bit.green; - int sb = 8 - png_ptr->sig_bit.blue; - - if (sr < 0 || sr > 8) - sr = 0; - if (sg < 0 || sg > 8) - sg = 0; - if (sb < 0 || sb > 8) - sb = 0; - for (i = 0; i < istop; i++) - { - png_ptr->palette[i].red >>= sr; - png_ptr->palette[i].green >>= sg; - png_ptr->palette[i].blue >>= sb; - } - - png_ptr->transformations &= ~PNG_SHIFT; - } -#endif /* PNG_READ_SHIFT_SUPPORTED */ - } -#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ - && !defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr) - return; -#endif -} - -/* Modify the info structure to reflect the transformations. The - * info should be updated so a PNG file could be written with it, - * assuming the transformations result in valid PNG data. - */ -void /* PRIVATE */ -png_read_transform_info(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_transform_info"); - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (png_ptr->num_trans) - info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - else - info_ptr->color_type = PNG_COLOR_TYPE_RGB; - info_ptr->bit_depth = 8; - info_ptr->num_trans = 0; - } - else - { - if (png_ptr->num_trans) - { - if (png_ptr->transformations & PNG_EXPAND_tRNS) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; - } - if (info_ptr->bit_depth < 8) - info_ptr->bit_depth = 8; - info_ptr->num_trans = 0; - } - } -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) - { - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; - info_ptr->num_trans = 0; - info_ptr->background = png_ptr->background; - } -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if (png_ptr->transformations & PNG_GAMMA) - { -#ifdef PNG_FLOATING_POINT_SUPPORTED - info_ptr->gamma = png_ptr->gamma; -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_gamma = png_ptr->int_gamma; -#endif - } -#endif - -#ifdef PNG_READ_16_TO_8_SUPPORTED - if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) - info_ptr->bit_depth = 8; -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - info_ptr->color_type |= PNG_COLOR_MASK_COLOR; -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED - if (png_ptr->transformations & PNG_DITHER) - { - if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && - png_ptr->palette_lookup && info_ptr->bit_depth == 8) - { - info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; - } - } -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) - info_ptr->bit_depth = 8; -#endif - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) - info_ptr->channels = 3; - else - info_ptr->channels = 1; - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; -#endif - - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - info_ptr->channels++; - -#ifdef PNG_READ_FILLER_SUPPORTED - /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ - if ((png_ptr->transformations & PNG_FILLER) && - ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) - { - info_ptr->channels++; - /* If adding a true alpha channel not just filler */ -#ifndef PNG_1_0_X - if (png_ptr->transformations & PNG_ADD_ALPHA) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; -#endif - } -#endif - -#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ -defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (info_ptr->bit_depth < png_ptr->user_transform_depth) - info_ptr->bit_depth = png_ptr->user_transform_depth; - if (info_ptr->channels < png_ptr->user_transform_channels) - info_ptr->channels = png_ptr->user_transform_channels; - } -#endif - - info_ptr->pixel_depth = (png_byte)(info_ptr->channels * - info_ptr->bit_depth); - - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); - -#ifndef PNG_READ_EXPAND_SUPPORTED - if (png_ptr) - return; -#endif -} - -/* Transform the row. The order of transformations is significant, - * and is very touchy. If you add a transformation, take care to - * decide how it fits in with the other transformations here. - */ -void /* PRIVATE */ -png_do_read_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_do_read_transformations"); - - if (png_ptr->row_buf == NULL) - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char msg[50]; - - png_snprintf2(msg, 50, - "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number, - png_ptr->pass); - png_error(png_ptr, msg); -#else - png_error(png_ptr, "NULL row buffer"); -#endif - } -#ifdef PNG_WARN_UNINITIALIZED_ROW - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - /* Application has failed to call either png_read_start_image() - * or png_read_update_info() after setting transforms that expand - * pixels. This check added to libpng-1.2.19 - */ -#if (PNG_WARN_UNINITIALIZED_ROW==1) - png_error(png_ptr, "Uninitialized row"); -#else - png_warning(png_ptr, "Uninitialized row"); -#endif -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) - { - png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette, png_ptr->trans, png_ptr->num_trans); - } - else - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_values)); - else - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - NULL); - } - } -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) - png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - { - int rgb_error = - png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), - png_ptr->row_buf + 1); - if (rgb_error) - { - png_ptr->rgb_to_gray_status=1; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_WARN) - png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_ERR) - png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - } - } -#endif - -/* From Andreas Dilger e-mail to png-implement, 26 March 1998: - * - * In most cases, the "simple transparency" should be done prior to doing - * gray-to-RGB, or you will have to test 3x as many bytes to check if a - * pixel is transparent. You would also need to make sure that the - * transparency information is upgraded to RGB. - * - * To summarize, the current flow is: - * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite - * with background "in place" if transparent, - * convert to RGB if necessary - * - Gray + alpha -> composite with gray background and remove alpha bytes, - * convert to RGB if necessary - * - * To support RGB backgrounds for gray images we need: - * - Gray + simple transparency -> convert to RGB + simple transparency, - * compare 3 or 6 bytes and composite with - * background "in place" if transparent - * (3x compare/pixel compared to doing - * composite with gray bkgrnd) - * - Gray + alpha -> convert to RGB + alpha, composite with background and - * remove alpha bytes (3x float - * operations/pixel compared with composite - * on gray background) - * - * Greg's change will do this. The reason it wasn't done before is for - * performance, as this increases the per-pixel operations. If we would check - * in advance if the background was gray or RGB, and position the gray-to-RGB - * transform appropriately, then it would save a lot of work/time. - */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* If gray -> RGB, do so now only if background is non-gray; else do later - * for performance reasons - */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if ((png_ptr->transformations & PNG_BACKGROUND) && - ((png_ptr->num_trans != 0 ) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) - png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_values), &(png_ptr->background) -#ifdef PNG_READ_GAMMA_SUPPORTED - , &(png_ptr->background_1), - png_ptr->gamma_table, png_ptr->gamma_from_1, - png_ptr->gamma_to_1, png_ptr->gamma_16_table, - png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, - png_ptr->gamma_shift -#endif -); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if ((png_ptr->transformations & PNG_GAMMA) && -#ifdef PNG_READ_BACKGROUND_SUPPORTED - !((png_ptr->transformations & PNG_BACKGROUND) && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && -#endif - (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->gamma_table, png_ptr->gamma_16_table, - png_ptr->gamma_shift); -#endif - -#ifdef PNG_READ_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_16_TO_8) - png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED - if (png_ptr->transformations & PNG_DITHER) - { - png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->dither_index); - if (png_ptr->row_info.rowbytes == (png_uint_32)0) - png_error(png_ptr, "png_do_dither returned rowbytes=0"); - } -#endif - -#ifdef PNG_READ_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* If gray -> RGB, do so now only if we did not do so above */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - (png_uint_32)png_ptr->filler, png_ptr->flags); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (png_ptr->read_user_transform_fn != NULL) - (*(png_ptr->read_user_transform_fn)) /* User read transform function */ - (png_ptr, /* png_ptr */ - &(png_ptr->row_info), /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_uint_32 rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - if (png_ptr->user_transform_depth) - png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; - if (png_ptr->user_transform_channels) - png_ptr->row_info.channels = png_ptr->user_transform_channels; -#endif - png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * - png_ptr->row_info.channels); - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - } -#endif - -} - -#ifdef PNG_READ_PACK_SUPPORTED -/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, - * without changing the actual values. Thus, if you had a row with - * a bit depth of 1, you would end up with bytes that only contained - * the numbers 0 or 1. If you would rather they contain 0 and 255, use - * png_do_shift() after this. - */ -void /* PRIVATE */ -png_do_unpack(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_unpack"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL && row_info->bit_depth < 8) -#else - if (row_info->bit_depth < 8) -#endif - { - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - switch (row_info->bit_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x01); - if (shift == 7) - { - shift = 0; - sp--; - } - else - shift++; - - dp--; - } - break; - } - - case 2: - { - - png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x03); - if (shift == 6) - { - shift = 0; - sp--; - } - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x0f); - if (shift == 4) - { - shift = 0; - sp--; - } - else - shift = 4; - - dp--; - } - break; - } - } - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_width * row_info->channels; - } -} -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -/* Reverse the effects of png_do_shift. This routine merely shifts the - * pixels back to their significant bits values. Thus, if you have - * a row of bit depth 8, but only 5 are significant, this will shift - * the values back to 0 through 31. - */ -void /* PRIVATE */ -png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits) -{ - png_debug(1, "in png_do_unshift"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && sig_bits != NULL && -#endif - row_info->color_type != PNG_COLOR_TYPE_PALETTE) - { - int shift[4]; - int channels = 0; - int c; - png_uint_16 value = 0; - png_uint_32 row_width = row_info->width; - - if (row_info->color_type & PNG_COLOR_MASK_COLOR) - { - shift[channels++] = row_info->bit_depth - sig_bits->red; - shift[channels++] = row_info->bit_depth - sig_bits->green; - shift[channels++] = row_info->bit_depth - sig_bits->blue; - } - else - { - shift[channels++] = row_info->bit_depth - sig_bits->gray; - } - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - shift[channels++] = row_info->bit_depth - sig_bits->alpha; - } - - for (c = 0; c < channels; c++) - { - if (shift[c] <= 0) - shift[c] = 0; - else - value = 1; - } - - if (!value) - return; - - switch (row_info->bit_depth) - { - case 2: - { - png_bytep bp; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - - for (bp = row, i = 0; i < istop; i++) - { - *bp >>= 1; - *bp++ &= 0x55; - } - break; - } - - case 4: - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | - (png_byte)((int)0xf >> shift[0])); - - for (i = 0; i < istop; i++) - { - *bp >>= shift[0]; - *bp++ &= mask; - } - break; - } - - case 8: - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = row_width * channels; - - for (i = 0; i < istop; i++) - { - *bp++ >>= shift[i%channels]; - } - break; - } - - case 16: - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = channels * row_width; - - for (i = 0; i < istop; i++) - { - value = (png_uint_16)((*bp << 8) + *(bp + 1)); - value >>= shift[i%channels]; - *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); - } - break; - } - } - } -} -#endif - -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Chop rows of bit depth 16 down to 8 */ -void /* PRIVATE */ -png_do_chop(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_chop"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL && row_info->bit_depth == 16) -#else - if (row_info->bit_depth == 16) -#endif - { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - png_uint_32 istop = row_info->width * row_info->channels; - - for (i = 0; i> 8)) >> 8; - * - * Approximate calculation with shift/add instead of multiply/divide: - * *dp = ((((png_uint_32)(*sp) << 8) | - * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; - * - * What we actually do to avoid extra shifting and conversion: - */ - - *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); -#else - /* Simply discard the low order byte */ - *dp = *sp; -#endif - } - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_info->width * row_info->channels; - } -} -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_swap_alpha"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - png_uint_32 row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This converts from RGBA to ARGB */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } - } - /* This converts from RRGGBBAA to AARRGGBB */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This converts from GA to AG */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } - } - /* This converts from GGAA to AAGG */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; - } - } - } - } -} -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_invert_alpha"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - png_uint_32 row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This inverts the alpha channel in RGBA */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - -/* This does nothing: - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - We can replace it with: -*/ - sp-=3; - dp=sp; - } - } - /* This inverts the alpha channel in RRGGBBAA */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = (png_byte)(255 - *(--sp)); - -/* This does nothing: - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - We can replace it with: -*/ - sp-=6; - dp=sp; - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This inverts the alpha channel in GA */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = *(--sp); - } - } - /* This inverts the alpha channel in GGAA */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = (png_byte)(255 - *(--sp)); -/* - *(--dp) = *(--sp); - *(--dp) = *(--sp); -*/ - sp-=2; - dp=sp; - } - } - } - } -} -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED -/* Add filler channel if we have RGB color */ -void /* PRIVATE */ -png_do_read_filler(png_row_infop row_info, png_bytep row, - png_uint_32 filler, png_uint_32 flags) -{ - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - png_byte hi_filler = (png_byte)((filler>>8) & 0xff); - png_byte lo_filler = (png_byte)(filler & 0xff); - - png_debug(1, "in png_do_read_filler"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - if (row_info->bit_depth == 8) - { - /* This changes the data from G to GX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 1; i < row_width; i++) - { - *(--dp) = lo_filler; - *(--dp) = *(--sp); - } - *(--dp) = lo_filler; - row_info->channels = 2; - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - /* This changes the data from G to XG */ - else - { - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = lo_filler; - } - row_info->channels = 2; - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - } - else if (row_info->bit_depth == 16) - { - /* This changes the data from GG to GGXX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width * 2; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 1; i < row_width; i++) - { - *(--dp) = hi_filler; - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = hi_filler; - *(--dp) = lo_filler; - row_info->channels = 2; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - /* This changes the data from GG to XXGG */ - else - { - png_bytep sp = row + (png_size_t)row_width * 2; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = hi_filler; - *(--dp) = lo_filler; - } - row_info->channels = 2; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - } - } /* COLOR_TYPE == GRAY */ - else if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - if (row_info->bit_depth == 8) - { - /* This changes the data from RGB to RGBX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 1; i < row_width; i++) - { - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = lo_filler; - row_info->channels = 4; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - /* This changes the data from RGB to XRGB */ - else - { - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = lo_filler; - } - row_info->channels = 4; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - } - else if (row_info->bit_depth == 16) - { - /* This changes the data from RRGGBB to RRGGBBXX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width * 6; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 1; i < row_width; i++) - { - *(--dp) = hi_filler; - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = hi_filler; - *(--dp) = lo_filler; - row_info->channels = 4; - row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; - } - /* This changes the data from RRGGBB to XXRRGGBB */ - else - { - png_bytep sp = row + (png_size_t)row_width * 6; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = hi_filler; - *(--dp) = lo_filler; - } - row_info->channels = 4; - row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; - } - } - } /* COLOR_TYPE == RGB */ -} -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -/* Expand grayscale files to RGB, with or without alpha */ -void /* PRIVATE */ -png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) -{ - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - png_debug(1, "in png_do_gray_to_rgb"); - - if (row_info->bit_depth >= 8 && -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - !(row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - if (row_info->bit_depth == 8) - { - png_bytep sp = row + (png_size_t)row_width - 1; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(dp--) = *sp; - *(dp--) = *sp; - *(dp--) = *(sp--); - } - } - else - { - png_bytep sp = row + (png_size_t)row_width * 2 - 1; - png_bytep dp = sp + (png_size_t)row_width * 4; - for (i = 0; i < row_width; i++) - { - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *(sp--); - *(dp--) = *(sp--); - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (row_info->bit_depth == 8) - { - png_bytep sp = row + (png_size_t)row_width * 2 - 1; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(dp--) = *(sp--); - *(dp--) = *sp; - *(dp--) = *sp; - *(dp--) = *(sp--); - } - } - else - { - png_bytep sp = row + (png_size_t)row_width * 4 - 1; - png_bytep dp = sp + (png_size_t)row_width * 4; - for (i = 0; i < row_width; i++) - { - *(dp--) = *(sp--); - *(dp--) = *(sp--); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *(sp--); - *(dp--) = *(sp--); - } - } - } - row_info->channels += (png_byte)2; - row_info->color_type |= PNG_COLOR_MASK_COLOR; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } -} -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -/* Reduce RGB files to grayscale, with or without alpha - * using the equation given in Poynton's ColorFAQ at - * (THIS LINK IS DEAD June 2008) - * New link: - * - * Charles Poynton poynton at poynton.com - * - * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - * - * We approximate this with - * - * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - * - * which can be expressed with integers as - * - * Y = (6969 * R + 23434 * G + 2365 * B)/32768 - * - * The calculation is to be done in a linear colorspace. - * - * Other integer coefficents can be used via png_set_rgb_to_gray(). - */ -int /* PRIVATE */ -png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) - -{ - png_uint_32 i; - - png_uint_32 row_width = row_info->width; - int rgb_error = 0; - - png_debug(1, "in png_do_rgb_to_gray"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; - png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; - png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - - for (i = 0; i < row_width; i++) - { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - if (red != green || red != blue) - { - rgb_error |= 1; - *(dp++) = png_ptr->gamma_from_1[ - (rc*red + gc*green + bc*blue)>>15]; - } - else - *(dp++) = *(sp - 1); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - if (red != green || red != blue) - { - rgb_error |= 1; - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - } - else - *(dp++) = *(sp - 1); - } - } - } - - else /* RGB bit_depth == 16 */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - - if (red == green && red == blue) - w = red; - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> - png_ptr->gamma_shift][red>>8]; - png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> - png_ptr->gamma_shift][blue>>8]; - png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 - + bc*blue_1)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - - red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - - if (red != green || red != blue) - rgb_error |= 1; - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - } - } - } - } - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - if (red != green || red != blue) - rgb_error |= 1; - *(dp++) = png_ptr->gamma_from_1 - [(rc*red + gc*green + bc*blue)>>15]; - *(dp++) = *(sp++); /* alpha */ - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - if (red != green || red != blue) - rgb_error |= 1; - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = *(sp++); /* alpha */ - } - } - } - else /* RGBA bit_depth == 16 */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - - if (red == green && red == blue) - w = red; - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> - png_ptr->gamma_shift][red>>8]; - png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> - png_ptr->gamma_shift][blue>>8]; - png_uint_16 gray16 = (png_uint_16)((rc * red_1 - + gc * green_1 + bc * blue_1)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - *(dp++) = *(sp++); /* alpha */ - *(dp++) = *(sp++); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; - if (red != green || red != blue) - rgb_error |= 1; - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - *(dp++) = *(sp++); /* alpha */ - *(dp++) = *(sp++); - } - } - } - } - row_info->channels -= (png_byte)2; - row_info->color_type &= ~PNG_COLOR_MASK_COLOR; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - return rgb_error; -} -#endif - -/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth - * large of png_color. This lets grayscale images be treated as - * paletted. Most useful for gamma correction and simplification - * of code. - */ -void PNGAPI -png_build_grayscale_palette(int bit_depth, png_colorp palette) -{ - int num_palette; - int color_inc; - int i; - int v; - - png_debug(1, "in png_do_build_grayscale_palette"); - - if (palette == NULL) - return; - - switch (bit_depth) - { - case 1: - num_palette = 2; - color_inc = 0xff; - break; - - case 2: - num_palette = 4; - color_inc = 0x55; - break; - - case 4: - num_palette = 16; - color_inc = 0x11; - break; - - case 8: - num_palette = 256; - color_inc = 1; - break; - - default: - num_palette = 0; - color_inc = 0; - break; - } - - for (i = 0, v = 0; i < num_palette; i++, v += color_inc) - { - palette[i].red = (png_byte)v; - palette[i].green = (png_byte)v; - palette[i].blue = (png_byte)v; - } -} - -/* This function is currently unused. Do we really need it? */ -#if defined(PNG_READ_DITHER_SUPPORTED) && \ - defined(PNG_CORRECT_PALETTE_SUPPORTED) -void /* PRIVATE */ -png_correct_palette(png_structp png_ptr, png_colorp palette, - int num_palette) -{ - png_debug(1, "in png_correct_palette"); - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - defined(PNG_READ_GAMMA_SUPPORTED) && \ - defined(PNG_FLOATING_POINT_SUPPORTED) - if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND)) - { - png_color back, back_1; - - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) - { - back.red = png_ptr->gamma_table[png_ptr->background.red]; - back.green = png_ptr->gamma_table[png_ptr->background.green]; - back.blue = png_ptr->gamma_table[png_ptr->background.blue]; - - back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; - back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; - back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; - } - else - { - double g; - - g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma); - - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN - || fabs(g - 1.0) < PNG_GAMMA_THRESHOLD) - { - back.red = png_ptr->background.red; - back.green = png_ptr->background.green; - back.blue = png_ptr->background.blue; - } - else - { - back.red = - (png_byte)(pow((double)png_ptr->background.red/255, g) * - 255.0 + 0.5); - back.green = - (png_byte)(pow((double)png_ptr->background.green/255, g) * - 255.0 + 0.5); - back.blue = - (png_byte)(pow((double)png_ptr->background.blue/255, g) * - 255.0 + 0.5); - } - - g = 1.0 / png_ptr->background_gamma; - - back_1.red = - (png_byte)(pow((double)png_ptr->background.red/255, g) * - 255.0 + 0.5); - back_1.green = - (png_byte)(pow((double)png_ptr->background.green/255, g) * - 255.0 + 0.5); - back_1.blue = - (png_byte)(pow((double)png_ptr->background.blue/255, g) * - 255.0 + 0.5); - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_uint_32 i; - - for (i = 0; i < (png_uint_32)num_palette; i++) - { - if (i < png_ptr->num_trans && png_ptr->trans[i] == 0) - { - palette[i] = back; - } - else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff) - { - png_byte v, w; - - v = png_ptr->gamma_to_1[png_ptr->palette[i].red]; - png_composite(w, v, png_ptr->trans[i], back_1.red); - palette[i].red = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[png_ptr->palette[i].green]; - png_composite(w, v, png_ptr->trans[i], back_1.green); - palette[i].green = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[png_ptr->palette[i].blue]; - png_composite(w, v, png_ptr->trans[i], back_1.blue); - palette[i].blue = png_ptr->gamma_from_1[w]; - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - } - else - { - int i; - - for (i = 0; i < num_palette; i++) - { - if (palette[i].red == (png_byte)png_ptr->trans_values.gray) - { - palette[i] = back; - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - } - } - else -#endif -#ifdef PNG_READ_GAMMA_SUPPORTED - if (png_ptr->transformations & PNG_GAMMA) - { - int i; - - for (i = 0; i < num_palette; i++) - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } -#ifdef PNG_READ_BACKGROUND_SUPPORTED - else -#endif -#endif -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_color back; - - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - - for (i = 0; i < (int)png_ptr->num_trans; i++) - { - if (png_ptr->trans[i] == 0) - { - palette[i].red = back.red; - palette[i].green = back.green; - palette[i].blue = back.blue; - } - else if (png_ptr->trans[i] != 0xff) - { - png_composite(palette[i].red, png_ptr->palette[i].red, - png_ptr->trans[i], back.red); - png_composite(palette[i].green, png_ptr->palette[i].green, - png_ptr->trans[i], back.green); - png_composite(palette[i].blue, png_ptr->palette[i].blue, - png_ptr->trans[i], back.blue); - } - } - } - else /* Assume grayscale palette (what else could it be?) */ - { - int i; - - for (i = 0; i < num_palette; i++) - { - if (i == (png_byte)png_ptr->trans_values.gray) - { - palette[i].red = (png_byte)png_ptr->background.red; - palette[i].green = (png_byte)png_ptr->background.green; - palette[i].blue = (png_byte)png_ptr->background.blue; - } - } - } - } -#endif -} -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Replace any alpha or transparency with the supplied background color. - * "background" is already in the screen gamma, while "background_1" is - * at a gamma of 1.0. Paletted files have already been taken care of. - */ -void /* PRIVATE */ -png_do_background(png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background -#ifdef PNG_READ_GAMMA_SUPPORTED - , png_color_16p background_1, - png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, - png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, - png_uint_16pp gamma_16_to_1, int gamma_shift -#endif - ) -{ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - int shift; - - png_debug(1, "in png_do_background"); - - if (background != NULL && -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || - (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values))) - { - switch (row_info->color_type) - { - case PNG_COLOR_TYPE_GRAY: - { - switch (row_info->bit_depth) - { - case 1: - { - sp = row; - shift = 7; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x01) - == trans_values->gray) - { - *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - if (!shift) - { - shift = 7; - sp++; - } - else - shift--; - } - break; - } - - case 2: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_values->gray) - { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - else - { - png_byte p = (png_byte)((*sp >> shift) & 0x03); - png_byte g = (png_byte)((gamma_table [p | (p << 2) | - (p << 4) | (p << 6)] >> 6) & 0x03); - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); - } - if (!shift) - { - shift = 6; - sp++; - } - else - shift -= 2; - } - } - else -#endif - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_values->gray) - { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - if (!shift) - { - shift = 6; - sp++; - } - else - shift -= 2; - } - } - break; - } - - case 4: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_values->gray) - { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - else - { - png_byte p = (png_byte)((*sp >> shift) & 0x0f); - png_byte g = (png_byte)((gamma_table[p | - (p << 4)] >> 4) & 0x0f); - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); - } - if (!shift) - { - shift = 4; - sp++; - } - else - shift -= 4; - } - } - else -#endif - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_values->gray) - { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - if (!shift) - { - shift = 4; - sp++; - } - else - shift -= 4; - } - } - break; - } - - case 8: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - if (*sp == trans_values->gray) - { - *sp = (png_byte)background->gray; - } - else - { - *sp = gamma_table[*sp]; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - if (*sp == trans_values->gray) - { - *sp = (png_byte)background->gray; - } - } - } - break; - } - - case 16: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 v; - - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_values->gray) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); - } - else - { - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 v; - - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_values->gray) - { - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); - } - } - } - break; - } - } - break; - } - - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == trans_values->red && - *(sp + 1) == trans_values->green && - *(sp + 2) == trans_values->blue) - { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; - } - else - { - *sp = gamma_table[*sp]; - *(sp + 1) = gamma_table[*(sp + 1)]; - *(sp + 2) = gamma_table[*(sp + 2)]; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == trans_values->red && - *(sp + 1) == trans_values->green && - *(sp + 2) == trans_values->blue) - { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); - if (r == trans_values->red && g == trans_values->green && - b == trans_values->blue) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((background->red >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->red & 0xff); - *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(sp + 3) = (png_byte)(background->green & 0xff); - *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(sp + 5) = (png_byte)(background->blue & 0xff); - } - else - { - png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1)); - png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); - - if (r == trans_values->red && g == trans_values->green && - b == trans_values->blue) - { - *sp = (png_byte)((background->red >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->red & 0xff); - *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(sp + 3) = (png_byte)(background->green & 0xff); - *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(sp + 5) = (png_byte)(background->blue & 0xff); - } - } - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) - { - png_uint_16 a = *(sp + 1); - - if (a == 0xff) - { - *dp = gamma_table[*sp]; - } - else if (a == 0) - { - /* Background is already in screen gamma */ - *dp = (png_byte)background->gray; - } - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, background_1->gray); - *dp = gamma_from_1[w]; - } - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) - { - png_byte a = *(sp + 1); - - if (a == 0xff) - { - *dp = *sp; - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) - { - *dp = (png_byte)background->gray; - } - else - { - png_composite(*dp, *sp, a, background_1->gray); - } -#else - *dp = (png_byte)background->gray; -#endif - } - } - } - else /* if (png_ptr->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) - { - png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) -#else - else -#endif - { - /* Background is already in screen gamma */ - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else - { - png_uint_16 g, v, w; - - g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(v, g, a, background_1->gray); - w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; - *dp = (png_byte)((w >> 8) & 0xff); - *(dp + 1) = (png_byte)(w & 0xff); - } -#endif - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) - { - png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - if (a == (png_uint_16)0xffff) - { - png_memcpy(dp, sp, 2); - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) -#else - else -#endif - { - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else - { - png_uint_16 g, v; - - g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, background_1->gray); - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - } -#endif - } - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) - { - png_byte a = *(sp + 3); - - if (a == 0xff) - { - *dp = gamma_table[*sp]; - *(dp + 1) = gamma_table[*(sp + 1)]; - *(dp + 2) = gamma_table[*(sp + 2)]; - } - else if (a == 0) - { - /* Background is already in screen gamma */ - *dp = (png_byte)background->red; - *(dp + 1) = (png_byte)background->green; - *(dp + 2) = (png_byte)background->blue; - } - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, background_1->red); - *dp = gamma_from_1[w]; - v = gamma_to_1[*(sp + 1)]; - png_composite(w, v, a, background_1->green); - *(dp + 1) = gamma_from_1[w]; - v = gamma_to_1[*(sp + 2)]; - png_composite(w, v, a, background_1->blue); - *(dp + 2) = gamma_from_1[w]; - } - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) - { - png_byte a = *(sp + 3); - - if (a == 0xff) - { - *dp = *sp; - *(dp + 1) = *(sp + 1); - *(dp + 2) = *(sp + 2); - } - else if (a == 0) - { - *dp = (png_byte)background->red; - *(dp + 1) = (png_byte)background->green; - *(dp + 2) = (png_byte)background->blue; - } - else - { - png_composite(*dp, *sp, a, background->red); - png_composite(*(dp + 1), *(sp + 1), a, - background->green); - png_composite(*(dp + 2), *(sp + 2), a, - background->blue); - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(dp + 2) = (png_byte)((v >> 8) & 0xff); - *(dp + 3) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(dp + 4) = (png_byte)((v >> 8) & 0xff); - *(dp + 5) = (png_byte)(v & 0xff); - } - else if (a == 0) - { - /* Background is already in screen gamma */ - *dp = (png_byte)((background->red >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->red & 0xff); - *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(dp + 3) = (png_byte)(background->green & 0xff); - *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(dp + 5) = (png_byte)(background->blue & 0xff); - } - else - { - png_uint_16 v, w, x; - - v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(w, v, a, background_1->red); - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *dp = (png_byte)((x >> 8) & 0xff); - *(dp + 1) = (png_byte)(x & 0xff); - v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; - png_composite_16(w, v, a, background_1->green); - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *(dp + 2) = (png_byte)((x >> 8) & 0xff); - *(dp + 3) = (png_byte)(x & 0xff); - v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; - png_composite_16(w, v, a, background_1->blue); - x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; - *(dp + 4) = (png_byte)((x >> 8) & 0xff); - *(dp + 5) = (png_byte)(x & 0xff); - } - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - if (a == (png_uint_16)0xffff) - { - png_memcpy(dp, sp, 6); - } - else if (a == 0) - { - *dp = (png_byte)((background->red >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->red & 0xff); - *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(dp + 3) = (png_byte)(background->green & 0xff); - *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(dp + 5) = (png_byte)(background->blue & 0xff); - } - else - { - png_uint_16 v; - - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - png_composite_16(v, r, a, background->red); - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - png_composite_16(v, g, a, background->green); - *(dp + 2) = (png_byte)((v >> 8) & 0xff); - *(dp + 3) = (png_byte)(v & 0xff); - png_composite_16(v, b, a, background->blue); - *(dp + 4) = (png_byte)((v >> 8) & 0xff); - *(dp + 5) = (png_byte)(v & 0xff); - } - } - } - } - break; - } - } - - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; - row_info->channels--; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - } -} -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* Gamma correct the image, avoiding the alpha channel. Make sure - * you do this after you deal with the transparency issue on grayscale - * or RGB images. If your bit depth is 8, use gamma_table, if it - * is 16, use gamma_16_table and gamma_shift. Build these with - * build_gamma_table(). - */ -void /* PRIVATE */ -png_do_gamma(png_row_infop row_info, png_bytep row, - png_bytep gamma_table, png_uint_16pp gamma_16_table, - int gamma_shift) -{ - png_bytep sp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_gamma"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - ((row_info->bit_depth <= 8 && gamma_table != NULL) || - (row_info->bit_depth == 16 && gamma_16_table != NULL))) - { - switch (row_info->color_type) - { - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - } - } - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - sp++; - } - } - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 4; - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp += 2; - } - } - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 4; - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY: - { - if (row_info->bit_depth == 2) - { - sp = row; - for (i = 0; i < row_width; i += 4) - { - int a = *sp & 0xc0; - int b = *sp & 0x30; - int c = *sp & 0x0c; - int d = *sp & 0x03; - - *sp = (png_byte)( - ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| - ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| - ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| - ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); - sp++; - } - } - - if (row_info->bit_depth == 4) - { - sp = row; - for (i = 0; i < row_width; i += 2) - { - int msb = *sp & 0xf0; - int lsb = *sp & 0x0f; - - *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) - | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); - sp++; - } - } - - else if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - } - } - - else if (row_info->bit_depth == 16) - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - } - } - break; - } - } - } -} -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* Expands a palette row to an RGB or RGBA row depending - * upon whether you supply trans and num_trans. - */ -void /* PRIVATE */ -png_do_expand_palette(png_row_infop row_info, png_bytep row, - png_colorp palette, png_bytep trans, int num_trans) -{ - int shift, value; - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_expand_palette"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - row_info->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (row_info->bit_depth < 8) - { - switch (row_info->bit_depth) - { - case 1: - { - sp = row + (png_size_t)((row_width - 1) >> 3); - dp = row + (png_size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - if ((*sp >> shift) & 0x01) - *dp = 1; - else - *dp = 0; - if (shift == 7) - { - shift = 0; - sp--; - } - else - shift++; - - dp--; - } - break; - } - - case 2: - { - sp = row + (png_size_t)((row_width - 1) >> 2); - dp = row + (png_size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)value; - if (shift == 6) - { - shift = 0; - sp--; - } - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - sp = row + (png_size_t)((row_width - 1) >> 1); - dp = row + (png_size_t)row_width - 1; - shift = (int)((row_width & 0x01) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)value; - if (shift == 4) - { - shift = 0; - sp--; - } - else - shift += 4; - - dp--; - } - break; - } - } - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - switch (row_info->bit_depth) - { - case 8: - { - if (trans != NULL) - { - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width << 2) - 1; - - for (i = 0; i < row_width; i++) - { - if ((int)(*sp) >= num_trans) - *dp-- = 0xff; - else - *dp-- = trans[*sp]; - *dp-- = palette[*sp].blue; - *dp-- = palette[*sp].green; - *dp-- = palette[*sp].red; - sp--; - } - row_info->bit_depth = 8; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - row_info->color_type = 6; - row_info->channels = 4; - } - else - { - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width * 3) - 1; - - for (i = 0; i < row_width; i++) - { - *dp-- = palette[*sp].blue; - *dp-- = palette[*sp].green; - *dp-- = palette[*sp].red; - sp--; - } - - row_info->bit_depth = 8; - row_info->pixel_depth = 24; - row_info->rowbytes = row_width * 3; - row_info->color_type = 2; - row_info->channels = 3; - } - break; - } - } - } -} - -/* If the bit depth < 8, it is expanded to 8. Also, if the already - * expanded transparency value is supplied, an alpha channel is built. - */ -void /* PRIVATE */ -png_do_expand(png_row_infop row_info, png_bytep row, - png_color_16p trans_value) -{ - int shift, value; - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_expand"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); - - if (row_info->bit_depth < 8) - { - switch (row_info->bit_depth) - { - case 1: - { - gray = (png_uint_16)((gray&0x01)*0xff); - sp = row + (png_size_t)((row_width - 1) >> 3); - dp = row + (png_size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - if ((*sp >> shift) & 0x01) - *dp = 0xff; - else - *dp = 0; - if (shift == 7) - { - shift = 0; - sp--; - } - else - shift++; - - dp--; - } - break; - } - - case 2: - { - gray = (png_uint_16)((gray&0x03)*0x55); - sp = row + (png_size_t)((row_width - 1) >> 2); - dp = row + (png_size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)(value | (value << 2) | (value << 4) | - (value << 6)); - if (shift == 6) - { - shift = 0; - sp--; - } - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - gray = (png_uint_16)((gray&0x0f)*0x11); - sp = row + (png_size_t)((row_width - 1) >> 1); - dp = row + (png_size_t)row_width - 1; - shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)(value | (value << 4)); - if (shift == 4) - { - shift = 0; - sp--; - } - else - shift = 4; - - dp--; - } - break; - } - } - - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - - if (trans_value != NULL) - { - if (row_info->bit_depth == 8) - { - gray = gray & 0xff; - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width << 1) - 1; - for (i = 0; i < row_width; i++) - { - if (*sp == gray) - *dp-- = 0; - else - *dp-- = 0xff; - *dp-- = *sp--; - } - } - - else if (row_info->bit_depth == 16) - { - png_byte gray_high = (gray >> 8) & 0xff; - png_byte gray_low = gray & 0xff; - sp = row + row_info->rowbytes - 1; - dp = row + (row_info->rowbytes << 1) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 1) == gray_high && *(sp) == gray_low) - { - *dp-- = 0; - *dp-- = 0; - } - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - *dp-- = *sp--; - *dp-- = *sp--; - } - } - - row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - row_info->channels = 2; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_width); - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) - { - if (row_info->bit_depth == 8) - { - png_byte red = trans_value->red & 0xff; - png_byte green = trans_value->green & 0xff; - png_byte blue = trans_value->blue & 0xff; - sp = row + (png_size_t)row_info->rowbytes - 1; - dp = row + (png_size_t)(row_width << 2) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) - *dp-- = 0; - else - *dp-- = 0xff; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - else if (row_info->bit_depth == 16) - { - png_byte red_high = (trans_value->red >> 8) & 0xff; - png_byte green_high = (trans_value->green >> 8) & 0xff; - png_byte blue_high = (trans_value->blue >> 8) & 0xff; - png_byte red_low = trans_value->red & 0xff; - png_byte green_low = trans_value->green & 0xff; - png_byte blue_low = trans_value->blue & 0xff; - sp = row + row_info->rowbytes - 1; - dp = row + (png_size_t)(row_width << 3) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 5) == red_high && - *(sp - 4) == red_low && - *(sp - 3) == green_high && - *(sp - 2) == green_low && - *(sp - 1) == blue_high && - *(sp ) == blue_low) - { - *dp-- = 0; - *dp-- = 0; - } - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - row_info->channels = 4; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - } -} -#endif - -#ifdef PNG_READ_DITHER_SUPPORTED -void /* PRIVATE */ -png_do_dither(png_row_infop row_info, png_bytep row, - png_bytep palette_lookup, png_bytep dither_lookup) -{ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_dither"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB && - palette_lookup && row_info->bit_depth == 8) - { - int r, g, b, p; - sp = row; - dp = row; - for (i = 0; i < row_width; i++) - { - r = *sp++; - g = *sp++; - b = *sp++; - - /* This looks real messy, but the compiler will reduce - * it down to a reasonable formula. For example, with - * 5 bits per color, we get: - * p = (((r >> 3) & 0x1f) << 10) | - * (((g >> 3) & 0x1f) << 5) | - * ((b >> 3) & 0x1f); - */ - p = (((r >> (8 - PNG_DITHER_RED_BITS)) & - ((1 << PNG_DITHER_RED_BITS) - 1)) << - (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | - (((g >> (8 - PNG_DITHER_GREEN_BITS)) & - ((1 << PNG_DITHER_GREEN_BITS) - 1)) << - (PNG_DITHER_BLUE_BITS)) | - ((b >> (8 - PNG_DITHER_BLUE_BITS)) & - ((1 << PNG_DITHER_BLUE_BITS) - 1)); - - *dp++ = palette_lookup[p]; - } - row_info->color_type = PNG_COLOR_TYPE_PALETTE; - row_info->channels = 1; - row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - palette_lookup != NULL && row_info->bit_depth == 8) - { - int r, g, b, p; - sp = row; - dp = row; - for (i = 0; i < row_width; i++) - { - r = *sp++; - g = *sp++; - b = *sp++; - sp++; - - p = (((r >> (8 - PNG_DITHER_RED_BITS)) & - ((1 << PNG_DITHER_RED_BITS) - 1)) << - (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | - (((g >> (8 - PNG_DITHER_GREEN_BITS)) & - ((1 << PNG_DITHER_GREEN_BITS) - 1)) << - (PNG_DITHER_BLUE_BITS)) | - ((b >> (8 - PNG_DITHER_BLUE_BITS)) & - ((1 << PNG_DITHER_BLUE_BITS) - 1)); - - *dp++ = palette_lookup[p]; - } - row_info->color_type = PNG_COLOR_TYPE_PALETTE; - row_info->channels = 1; - row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && - dither_lookup && row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - *sp = dither_lookup[*sp]; - } - } - } -} -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -#ifdef PNG_READ_GAMMA_SUPPORTED -static PNG_CONST int png_gamma_shift[] = - {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00}; - -/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit - * tables, we don't make a full table if we are reducing to 8-bit in - * the future. Note also how the gamma_16 tables are segmented so that - * we don't need to allocate > 64K chunks for a full 16-bit table. - * - * See the PNG extensions document for an integer algorithm for creating - * the gamma tables. Maybe we will implement that here someday. - * - * We should only reach this point if - * - * the file_gamma is known (i.e., the gAMA or sRGB chunk is present, - * or the application has provided a file_gamma) - * - * AND - * { - * the screen_gamma is known - * OR - * - * RGB_to_gray transformation is being performed - * } - * - * AND - * { - * the screen_gamma is different from the reciprocal of the - * file_gamma by more than the specified threshold - * - * OR - * - * a background color has been specified and the file_gamma - * and screen_gamma are not 1.0, within the specified threshold. - * } - */ - -void /* PRIVATE */ -png_build_gamma_table(png_structp png_ptr) -{ - png_debug(1, "in png_build_gamma_table"); - - if (png_ptr->bit_depth <= 8) - { - int i; - double g; - - if (png_ptr->screen_gamma > .000001) - g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - - else - g = 1.0; - - png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr, - (png_uint_32)256); - - for (i = 0; i < 256; i++) - { - png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0, - g) * 255.0 + .5); - } - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) - { - - g = 1.0 / (png_ptr->gamma); - - png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr, - (png_uint_32)256); - - for (i = 0; i < 256; i++) - { - png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0, - g) * 255.0 + .5); - } - - - png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, - (png_uint_32)256); - - if (png_ptr->screen_gamma > 0.000001) - g = 1.0 / png_ptr->screen_gamma; - - else - g = png_ptr->gamma; /* Probably doing rgb_to_gray */ - - for (i = 0; i < 256; i++) - { - png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0, - g) * 255.0 + .5); - - } - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ - } - else - { - double g; - int i, j, shift, num; - int sig_bit; - png_uint_32 ig; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit = (int)png_ptr->sig_bit.red; - - if ((int)png_ptr->sig_bit.green > sig_bit) - sig_bit = png_ptr->sig_bit.green; - - if ((int)png_ptr->sig_bit.blue > sig_bit) - sig_bit = png_ptr->sig_bit.blue; - } - else - { - sig_bit = (int)png_ptr->sig_bit.gray; - } - - if (sig_bit > 0) - shift = 16 - sig_bit; - - else - shift = 0; - - if (png_ptr->transformations & PNG_16_TO_8) - { - if (shift < (16 - PNG_MAX_GAMMA_8)) - shift = (16 - PNG_MAX_GAMMA_8); - } - - if (shift > 8) - shift = 8; - - if (shift < 0) - shift = 0; - - png_ptr->gamma_shift = (png_byte)shift; - - num = (1 << (8 - shift)); - - if (png_ptr->screen_gamma > .000001) - g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - else - g = 1.0; - - png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr, - (png_uint_32)(num * png_sizeof(png_uint_16p))); - - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) - { - double fin, fout; - png_uint_32 last, max; - - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - } - - g = 1.0 / g; - last = 0; - for (i = 0; i < 256; i++) - { - fout = ((double)i + 0.5) / 256.0; - fin = pow(fout, g); - max = (png_uint_32)(fin * (double)((png_uint_32)num << 8)); - while (last <= max) - { - png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] - [(int)(last >> (8 - shift))] = (png_uint_16)( - (png_uint_16)i | ((png_uint_16)i << 8)); - last++; - } - } - while (last < ((png_uint_32)num << 8)) - { - png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] - [(int)(last >> (8 - shift))] = (png_uint_16)65535L; - last++; - } - } - else - { - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - - ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); - - for (j = 0; j < 256; j++) - { - png_ptr->gamma_16_table[i][j] = - (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / - 65535.0, g) * 65535.0 + .5); - } - } - } - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) - { - - g = 1.0 / (png_ptr->gamma); - - png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr, - (png_uint_32)(num * png_sizeof(png_uint_16p ))); - - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - - ig = (((png_uint_32)i * - (png_uint_32)png_gamma_shift[shift]) >> 4); - for (j = 0; j < 256; j++) - { - png_ptr->gamma_16_to_1[i][j] = - (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / - 65535.0, g) * 65535.0 + .5); - } - } - - if (png_ptr->screen_gamma > 0.000001) - g = 1.0 / png_ptr->screen_gamma; - - else - g = png_ptr->gamma; /* Probably doing rgb_to_gray */ - - png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr, - (png_uint_32)(num * png_sizeof(png_uint_16p))); - - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - - ig = (((png_uint_32)i * - (png_uint_32)png_gamma_shift[shift]) >> 4); - - for (j = 0; j < 256; j++) - { - png_ptr->gamma_16_from_1[i][j] = - (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / - 65535.0, g) * 65535.0 + .5); - } - } - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ - } -} -#endif -/* To do: install integer version of png_build_gamma_table here */ -#endif - -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ -void /* PRIVATE */ -png_do_read_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_intrapixel"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff); - *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff); - } - } - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp+1) = (png_byte)(red & 0xff); - *(rp+4) = (png_byte)((blue >> 8) & 0xff); - *(rp+5) = (png_byte)(blue & 0xff); - } - } - } -} -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ + +/* pngrtran.c - transforms the data in a row for PNG readers + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action"); + + if (png_ptr == NULL) + return; + + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + + case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ + png_warning(png_ptr, + "Can't discard critical data on CRC error."); + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + /* Tell libpng how we react to CRC errors in ancillary chunks */ + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* Handle alpha and tRNS via a background color */ +void PNGAPI +png_set_background(png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_debug(1, "in png_set_background"); + + if (png_ptr == NULL) + return; + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_BACKGROUND; + png_memcpy(&(png_ptr->background), background_color, + png_sizeof(png_color_16)); + png_ptr->background_gamma = (float)background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); +} +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +/* Strip 16 bit depth files to 8 bit depth */ +void PNGAPI +png_set_strip_16(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_16"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +void PNGAPI +png_set_strip_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; +} +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED +/* Dither file to 8 bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater then the maximum number, the palette will be + * modified to fit in the maximum number. "full_dither" indicates + * whether we need a dithering cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct FAR * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort FAR * png_dsortp; +typedef png_dsort FAR * FAR * png_dsortpp; + +void PNGAPI +png_set_dither(png_structp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_uint_16p histogram, + int full_dither) +{ + png_debug(1, "in png_set_dither"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_DITHER; + + if (!full_dither) + { + int i; + + png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + for (i = 0; i < num_palette; i++) + png_ptr->dither_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + * Perhaps not the best solution, but good enough. + */ + + int i; + + /* Initialize an array to sort colors */ + png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + + /* Initialize the dither_sort array */ + for (i = 0; i < num_palette; i++) + png_ptr->dither_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + * bubble sort, and running it until we have sorted + * out enough colors. Note that we don't care about + * sorting all the colors, just finding which are + * least used. + */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* To stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[png_ptr->dither_sort[j]] + < histogram[png_ptr->dither_sort[j + 1]]) + { + png_byte t; + + t = png_ptr->dither_sort[j]; + png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1]; + png_ptr->dither_sort[j + 1] = t; + done = 0; + } + } + if (done) + break; + } + + /* Swap the palette around, and set up a table, if necessary */ + if (full_dither) + { + int j = num_palette; + + /* Put all the useful colors within the max, but don't + * move the others. + */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)png_ptr->dither_sort[i] >= maximum_colors) + { + do + j--; + while ((int)png_ptr->dither_sort[j] >= maximum_colors); + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* Move all the used colors inside the max limit, and + * develop a translation table. + */ + for (i = 0; i < maximum_colors; i++) + { + /* Only move the colors we need to */ + if ((int)png_ptr->dither_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)png_ptr->dither_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* Indicate where the color went */ + png_ptr->dither_index[j] = (png_byte)i; + png_ptr->dither_index[i] = (png_byte)j; + } + } + + /* Find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->dither_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* Find the closest color to one we threw out */ + d_index = png_ptr->dither_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* Point to closest color */ + png_ptr->dither_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, png_ptr->dither_sort); + png_ptr->dither_sort = NULL; + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + * we need to go through a median cut routine, but those + * don't always behave themselves with only a few colors + * as input. So we will just find the closest two colors, + * and throw out one of them (chosen somewhat randomly). + * [We don't understand this at all, so if someone wants to + * work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortp t; + png_dsortpp hash; + + t = NULL; + + /* Initialize palette index arrays */ + png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + + /* Initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + png_ptr->index_to_palette[i] = (png_byte)i; + png_ptr->palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * + png_sizeof(png_dsortp))); + + num_new_palette = num_palette; + + /* Initial wild guess at how far apart the farthest pixel + * pair we will be eliminating will be. Larger + * numbers mean more areas will be allocated, Smaller + * numbers run the risk of not saving enough data, and + * having to do this all over again. + * + * I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + + t = (png_dsortp)png_malloc_warn(png_ptr, + (png_uint_32)(png_sizeof(png_dsort))); + if (t == NULL) + break; + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + if (t == NULL) + break; + } + + if (t != NULL) + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)png_ptr->index_to_palette[p->left] + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[png_ptr->index_to_palette[j]] + = palette[num_new_palette]; + if (!full_dither) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->dither_index[k] == + png_ptr->index_to_palette[j]) + png_ptr->dither_index[k] = + png_ptr->index_to_palette[next_j]; + if ((int)png_ptr->dither_index[k] == + num_new_palette) + png_ptr->dither_index[k] = + png_ptr->index_to_palette[j]; + } + } + + png_ptr->index_to_palette[png_ptr->palette_to_index + [num_new_palette]] = png_ptr->index_to_palette[j]; + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] + = png_ptr->palette_to_index[num_new_palette]; + + png_ptr->index_to_palette[j] = + (png_byte)num_new_palette; + png_ptr->palette_to_index[num_new_palette] = + (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, png_ptr->palette_to_index); + png_free(png_ptr, png_ptr->index_to_palette); + png_ptr->palette_to_index = NULL; + png_ptr->index_to_palette = NULL; + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_dither) + { + int i; + png_bytep distance; + int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS + + PNG_DITHER_BLUE_BITS; + int num_red = (1 << PNG_DITHER_RED_BITS); + int num_green = (1 << PNG_DITHER_GREEN_BITS); + int num_blue = (1 << PNG_DITHER_BLUE_BITS); + png_size_t num_entries = ((png_size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr, + (png_uint_32)(num_entries * png_sizeof(png_byte))); + + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + png_sizeof(png_byte))); + png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); + int index_r = (ir << (PNG_DITHER_BLUE_BITS + + PNG_DITHER_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) +/* Transform the image from the file_gamma to the screen_gamma. We + * only do transformations on images where the file_gamma and screen_gamma + * are not close reciprocals, otherwise it slows things down slightly, and + * also needlessly introduces small errors. + * + * We will turn off gamma transformation later if no semitransparent entries + * are present in the tRNS array for palette images. We can't do it here + * because we don't necessarily have the tRNS chunk yet. + */ +void PNGAPI +png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) +{ + png_debug(1, "in png_set_gamma"); + + if (png_ptr == NULL) + return; + + if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + png_ptr->transformations |= PNG_GAMMA; + png_ptr->gamma = (float)file_gamma; + png_ptr->screen_gamma = (float)scrn_gamma; +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + * + * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified + * to expand only the sample depth but not to expand the tRNS to alpha + * and its name was changed to png_set_expand_gray_1_2_4_to_8(). + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_palette_to_rgb"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} + +#ifndef PNG_1_0_X +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_EXPAND; + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif + +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +/* Deprecated as of libpng-1.2.9 */ +void PNGAPI +png_set_gray_1_2_4_to_8(png_structp png_ptr) +{ + png_debug(1, "in png_set_gray_1_2_4_to_8"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif + + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_tRNS_to_alpha"); + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +void PNGAPI +png_set_gray_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb"); + + png_ptr->transformations |= PNG_GRAY_TO_RGB; + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, + double green) +{ + int red_fixed, green_fixed; + if (png_ptr == NULL) + return; + if (red > 21474.83647 || red < -21474.83648 || + green > 21474.83647 || green < -21474.83648) + { + png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); + red_fixed = -1; + green_fixed = -1; + } + else + { + red_fixed = (int)((float)red*100000.0 + 0.5); + green_fixed = (int)((float)green*100000.0 + 0.5); + } + png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); +} +#endif + +void PNGAPI +png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray"); + + if (png_ptr == NULL) + return; + + switch(error_action) + { + case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + + case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + + case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + } + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_ptr->transformations |= PNG_EXPAND; +#else + { + png_warning(png_ptr, + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED."); + png_ptr->transformations &= ~PNG_RGB_TO_GRAY; + } +#endif + { + png_uint_16 red_int, green_int; + if (red < 0 || green < 0) + { + red_int = 6968; /* .212671 * 32768 + .5 */ + green_int = 23434; /* .715160 * 32768 + .5 */ + } + else if (red + green < 100000L) + { + red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); + green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); + } + else + { + png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); + red_int = 6968; + green_int = 23434; + } + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_blue_coeff = + (png_uint_16)(32768 - red_int - green_int); + } +} +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +#ifdef PNG_LEGACY_SUPPORTED + if (read_user_transform_fn) + png_warning(png_ptr, + "This version of libpng does not support user transforms"); +#endif +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ +void /* PRIVATE */ +png_init_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_init_read_transformations"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (png_ptr != NULL) +#endif + { +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_SHIFT_SUPPORTED) || \ + defined(PNG_READ_GAMMA_SUPPORTED) + int color_type = png_ptr->color_type; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Detect gray background and attempt to enable optimization + * for gray --> RGB case + * + * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or + * RGB_ALPHA (in which case need_expand is superfluous anyway), the + * background color might actually be gray yet not be flagged as such. + * This is not a problem for the current code, which uses + * PNG_BACKGROUND_IS_GRAY only to decide when to do the + * png_do_gray_to_rgb() transformation. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + !(color_type & PNG_COLOR_MASK_COLOR)) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + } else if ((png_ptr->transformations & PNG_BACKGROUND) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_GRAY_TO_RGB) && + png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; + } +#endif + + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND)) + { + if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ + { + /* Expand background and tRNS chunks */ + switch (png_ptr->bit_depth) + { + case 1: + png_ptr->background.gray *= (png_uint_16)0xff; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_values.gray *= (png_uint_16)0xff; + png_ptr->trans_values.red = png_ptr->trans_values.green + = png_ptr->trans_values.blue = png_ptr->trans_values.gray; + } + break; + + case 2: + png_ptr->background.gray *= (png_uint_16)0x55; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_values.gray *= (png_uint_16)0x55; + png_ptr->trans_values.red = png_ptr->trans_values.green + = png_ptr->trans_values.blue = png_ptr->trans_values.gray; + } + break; + + case 4: + png_ptr->background.gray *= (png_uint_16)0x11; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_values.gray *= (png_uint_16)0x11; + png_ptr->trans_values.red = png_ptr->trans_values.green + = png_ptr->trans_values.blue = png_ptr->trans_values.gray; + } + break; + + case 8: + + case 16: + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + break; + } + } + else if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { +#ifdef PNG_READ_EXPAND_SUPPORTED + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) +#endif + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop; + istop=(int)png_ptr->num_trans; + for (i=0; itrans[i] = (png_byte)(255 - png_ptr->trans[i]); + } + } +#endif + + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + png_ptr->background_1 = png_ptr->background; +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + + if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) + && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0) + < PNG_GAMMA_THRESHOLD)) + { + int i, k; + k=0; + for (i=0; inum_trans; i++) + { + if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff) + { + k=1; /* Partial transparency is present */ + break; + } + } + if (k == 0) + png_ptr->transformations &= ~PNG_GAMMA; + } + + if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) && + png_ptr->gamma != 0.0) + { + png_build_gamma_table(png_ptr); + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + /* Could skip if no transparency */ + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + default: + g = 1.0; /* back_1 */ + gs = 1.0; /* back */ + } + + if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + else + { + back.red = (png_byte)(pow( + (double)png_ptr->background.red/255, gs) * 255.0 + .5); + back.green = (png_byte)(pow( + (double)png_ptr->background.green/255, gs) * 255.0 + + .5); + back.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255, gs) * 255.0 + .5); + } + + back_1.red = (png_byte)(pow( + (double)png_ptr->background.red/255, g) * 255.0 + .5); + back_1.green = (png_byte)(pow( + (double)png_ptr->background.green/255, g) * 255.0 + .5); + back_1.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255, g) * 255.0 + .5); + } + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + /* Prevent the transformations being done again, and make sure + * that the now spurious alpha channel is stripped - the code + * has just reduced background composition and gamma correction + * to a simple alpha channel strip. + */ + png_ptr->transformations &= ~PNG_BACKGROUND; + png_ptr->transformations &= ~PNG_GAMMA; + png_ptr->transformations |= PNG_STRIP_ALPHA; + } + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ + else + /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1); + double g = 1.0; + double gs = 1.0; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + } + + png_ptr->background_1.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, g) * m + .5); + png_ptr->background.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, gs) * m + .5); + + if ((png_ptr->background.red != png_ptr->background.green) || + (png_ptr->background.red != png_ptr->background.blue) || + (png_ptr->background.red != png_ptr->background.gray)) + { + /* RGB or RGBA with color background */ + png_ptr->background_1.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, g) * m + .5); + png_ptr->background_1.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, g) * m + .5); + png_ptr->background_1.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, g) * m + .5); + png_ptr->background.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, gs) * m + .5); + png_ptr->background.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, gs) * m + .5); + png_ptr->background.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, gs) * m + .5); + } + else + { + /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ + png_ptr->background_1.red = png_ptr->background_1.green + = png_ptr->background_1.blue = png_ptr->background_1.gray; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + } + } + } + else + /* Transformation does not include PNG_BACKGROUND */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + + /* Done the gamma correction. */ + png_ptr->transformations &= ~PNG_GAMMA; + } + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + else +#endif +#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */ +#ifdef PNG_READ_BACKGROUND_SUPPORTED + /* No GAMMA transformation */ + if ((png_ptr->transformations & PNG_BACKGROUND) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (png_ptr->trans[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans[i], back.red); + png_composite(palette[i].green, palette[i].green, + png_ptr->trans[i], back.green); + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans[i], back.blue); + } + } + + /* Handled alpha, still need to strip the channel. */ + png_ptr->transformations &= ~PNG_BACKGROUND; + png_ptr->transformations |= PNG_STRIP_ALPHA; + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) && + !(png_ptr->transformations & PNG_EXPAND) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + png_uint_16 i; + png_uint_16 istop = png_ptr->num_palette; + int sr = 8 - png_ptr->sig_bit.red; + int sg = 8 - png_ptr->sig_bit.green; + int sb = 8 - png_ptr->sig_bit.blue; + + if (sr < 0 || sr > 8) + sr = 0; + if (sg < 0 || sg > 8) + sg = 0; + if (sb < 0 || sb > 8) + sb = 0; + for (i = 0; i < istop; i++) + { + png_ptr->palette[i].red >>= sr; + png_ptr->palette[i].green >>= sg; + png_ptr->palette[i].blue >>= sb; + } + + png_ptr->transformations &= ~PNG_SHIFT; + } +#endif /* PNG_READ_SHIFT_SUPPORTED */ + } +#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ + && !defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr) + return; +#endif +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_transform_info"); + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + else + { + if (png_ptr->num_trans) + { + if (png_ptr->transformations & PNG_EXPAND_tRNS) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + } +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->transformations & PNG_BACKGROUND) + { + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->num_trans = 0; + info_ptr->background = png_ptr->background; + } +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->transformations & PNG_GAMMA) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = png_ptr->gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_ptr->int_gamma; +#endif + } +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) + info_ptr->bit_depth = 8; +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + info_ptr->color_type |= PNG_COLOR_MASK_COLOR; +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED + if (png_ptr->transformations & PNG_DITHER) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; +#endif + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + +#ifdef PNG_READ_FILLER_SUPPORTED + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + { + info_ptr->channels++; + /* If adding a true alpha channel not just filler */ +#ifndef PNG_1_0_X + if (png_ptr->transformations & PNG_ADD_ALPHA) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; +#endif + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (info_ptr->bit_depth < png_ptr->user_transform_depth) + info_ptr->bit_depth = png_ptr->user_transform_depth; + if (info_ptr->channels < png_ptr->user_transform_channels) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + +#ifndef PNG_READ_EXPAND_SUPPORTED + if (png_ptr) + return; +#endif +} + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char msg[50]; + + png_snprintf2(msg, 50, + "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number, + png_ptr->pass); + png_error(png_ptr, msg); +#else + png_error(png_ptr, "NULL row buffer"); +#endif + } +#ifdef PNG_WARN_UNINITIALIZED_ROW + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + /* Application has failed to call either png_read_start_image() + * or png_read_update_info() after setting transforms that expand + * pixels. This check added to libpng-1.2.19 + */ +#if (PNG_WARN_UNINITIALIZED_ROW==1) + png_error(png_ptr, "Uninitialized row"); +#else + png_warning(png_ptr, "Uninitialized row"); +#endif +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans, png_ptr->num_trans); + } + else + { + if (png_ptr->num_trans && + (png_ptr->transformations & PNG_EXPAND_tRNS)) + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_values)); + else + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1); + if (rgb_error) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if ((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0 ) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) + png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_values), &(png_ptr->background) +#ifdef PNG_READ_GAMMA_SUPPORTED + , &(png_ptr->background_1), + png_ptr->gamma_table, png_ptr->gamma_from_1, + png_ptr->gamma_to_1, png_ptr->gamma_16_table, + png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, + png_ptr->gamma_shift +#endif +); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) && +#ifdef PNG_READ_BACKGROUND_SUPPORTED + !((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && +#endif + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->gamma_table, png_ptr->gamma_16_table, + png_ptr->gamma_shift); +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED + if (png_ptr->transformations & PNG_DITHER) + { + png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->dither_index); + if (png_ptr->row_info.rowbytes == (png_uint_32)0) + png_error(png_ptr, "png_do_dither returned rowbytes=0"); + } +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if we did not do so above */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth) + png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; + if (png_ptr->user_transform_channels) + png_ptr->row_info.channels = png_ptr->user_transform_channels; +#endif + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + } +#endif + +} + +#ifdef PNG_READ_PACK_SUPPORTED +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +void /* PRIVATE */ +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL && row_info->bit_depth < 8) +#else + if (row_info->bit_depth < 8) +#endif + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +void /* PRIVATE */ +png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits) +{ + png_debug(1, "in png_do_unshift"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && sig_bits != NULL && +#endif + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int c; + png_uint_16 value = 0; + png_uint_32 row_width = row_info->width; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift[channels++] = row_info->bit_depth - sig_bits->red; + shift[channels++] = row_info->bit_depth - sig_bits->green; + shift[channels++] = row_info->bit_depth - sig_bits->blue; + } + else + { + shift[channels++] = row_info->bit_depth - sig_bits->gray; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift[channels++] = row_info->bit_depth - sig_bits->alpha; + } + + for (c = 0; c < channels; c++) + { + if (shift[c] <= 0) + shift[c] = 0; + else + value = 1; + } + + if (!value) + return; + + switch (row_info->bit_depth) + { + case 2: + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (bp = row, i = 0; i < istop; i++) + { + *bp >>= 1; + *bp++ &= 0x55; + } + break; + } + + case 4: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | + (png_byte)((int)0xf >> shift[0])); + + for (i = 0; i < istop; i++) + { + *bp >>= shift[0]; + *bp++ &= mask; + } + break; + } + + case 8: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_width * channels; + + for (i = 0; i < istop; i++) + { + *bp++ >>= shift[i%channels]; + } + break; + } + + case 16: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_width; + + for (i = 0; i < istop; i++) + { + value = (png_uint_16)((*bp << 8) + *(bp + 1)); + value >>= shift[i%channels]; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + break; + } + } + } +} +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +/* Chop rows of bit depth 16 down to 8 */ +void /* PRIVATE */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL && row_info->bit_depth == 16) +#else + if (row_info->bit_depth == 16) +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + png_uint_32 istop = row_info->width * row_info->channels; + + for (i = 0; i> 8)) >> 8; + * + * Approximate calculation with shift/add instead of multiply/divide: + * *dp = ((((png_uint_32)(*sp) << 8) | + * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; + * + * What we actually do to avoid extra shifting and conversion: + */ + + *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); +#else + /* Simply discard the low order byte */ + *dp = *sp; +#endif + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_swap_alpha"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + } +} +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_invert_alpha"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } + } + } +} +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED +/* Add filler channel if we have RGB color */ +void /* PRIVATE */ +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_byte hi_filler = (png_byte)((filler>>8) & 0xff); + png_byte lo_filler = (png_byte)(filler & 0xff); + + png_debug(1, "in png_do_read_filler"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + /* This changes the data from G to GX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + /* This changes the data from G to XG */ + else + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + else if (row_info->bit_depth == 16) + { + /* This changes the data from GG to GGXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from GG to XXGG */ + else + { + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { + /* This changes the data from RGB to RGBX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from RGB to XRGB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + else if (row_info->bit_depth == 16) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + /* This changes the data from RRGGBB to XXRRGGBB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } + } /* COLOR_TYPE == RGB */ +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand grayscale files to RGB, with or without alpha */ +void /* PRIVATE */ +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb"); + + if (row_info->bit_depth >= 8 && +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels += (png_byte)2; + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ at + * (THIS LINK IS DEAD June 2008) + * New link: + * + * Charles Poynton poynton at poynton.com + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * We approximate this with + * + * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * The calculation is to be done in a linear colorspace. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). + */ +int /* PRIVATE */ +png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) + +{ + png_uint_32 i; + + png_uint_32 row_width = row_info->width; + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if (red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue)>>15]; + } + else + *(dp++) = *(sp - 1); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if (red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + } + else + *(dp++) = *(sp - 1); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if (red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if (red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + } + } + } + } + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if (red != green || red != blue) + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1 + [(rc*red + gc*green + bc*blue)>>15]; + *(dp++) = *(sp++); /* alpha */ + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if (red != green || red != blue) + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = *(sp++); /* alpha */ + } + } + } + else /* RGBA bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if (red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc * red_1 + + gc * green_1 + bc * blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + if (red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + } + } + row_info->channels -= (png_byte)2; + row_info->color_type &= ~PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + return rgb_error; +} +#endif + +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)v; + palette[i].green = (png_byte)v; + palette[i].blue = (png_byte)v; + } +} + +/* This function is currently unused. Do we really need it? */ +#if defined(PNG_READ_DITHER_SUPPORTED) && \ + defined(PNG_CORRECT_PALETTE_SUPPORTED) +void /* PRIVATE */ +png_correct_palette(png_structp png_ptr, png_colorp palette, + int num_palette) +{ + png_debug(1, "in png_correct_palette"); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_GAMMA_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) + if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND)) + { + png_color back, back_1; + + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g; + + g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma); + + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN + || fabs(g - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = png_ptr->background.red; + back.green = png_ptr->background.green; + back.blue = png_ptr->background.blue; + } + else + { + back.red = + (png_byte)(pow((double)png_ptr->background.red/255, g) * + 255.0 + 0.5); + back.green = + (png_byte)(pow((double)png_ptr->background.green/255, g) * + 255.0 + 0.5); + back.blue = + (png_byte)(pow((double)png_ptr->background.blue/255, g) * + 255.0 + 0.5); + } + + g = 1.0 / png_ptr->background_gamma; + + back_1.red = + (png_byte)(pow((double)png_ptr->background.red/255, g) * + 255.0 + 0.5); + back_1.green = + (png_byte)(pow((double)png_ptr->background.green/255, g) * + 255.0 + 0.5); + back_1.blue = + (png_byte)(pow((double)png_ptr->background.blue/255, g) * + 255.0 + 0.5); + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_uint_32 i; + + for (i = 0; i < (png_uint_32)num_palette; i++) + { + if (i < png_ptr->num_trans && png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff) + { + png_byte v, w; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].red]; + png_composite(w, v, png_ptr->trans[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].green]; + png_composite(w, v, png_ptr->trans[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].blue]; + png_composite(w, v, png_ptr->trans[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + else + { + int i; + + for (i = 0; i < num_palette; i++) + { + if (palette[i].red == (png_byte)png_ptr->trans_values.gray) + { + palette[i] = back; + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + } + else +#endif +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->transformations & PNG_GAMMA) + { + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + else +#endif +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_color back; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < (int)png_ptr->num_trans; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i].red = back.red; + palette[i].green = back.green; + palette[i].blue = back.blue; + } + else if (png_ptr->trans[i] != 0xff) + { + png_composite(palette[i].red, png_ptr->palette[i].red, + png_ptr->trans[i], back.red); + png_composite(palette[i].green, png_ptr->palette[i].green, + png_ptr->trans[i], back.green); + png_composite(palette[i].blue, png_ptr->palette[i].blue, + png_ptr->trans[i], back.blue); + } + } + } + else /* Assume grayscale palette (what else could it be?) */ + { + int i; + + for (i = 0; i < num_palette; i++) + { + if (i == (png_byte)png_ptr->trans_values.gray) + { + palette[i].red = (png_byte)png_ptr->background.red; + palette[i].green = (png_byte)png_ptr->background.green; + palette[i].blue = (png_byte)png_ptr->background.blue; + } + } + } + } +#endif +} +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +void /* PRIVATE */ +png_do_background(png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background +#ifdef PNG_READ_GAMMA_SUPPORTED + , png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift +#endif + ) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + int shift; + + png_debug(1, "in png_do_background"); + + if (background != NULL && +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || + (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == trans_values->gray) + { + *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 7; + sp++; + } + else + shift--; + } + break; + } + + case 2: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_values->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x03); + png_byte g = (png_byte)((gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03); + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_values->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + break; + } + + case 4: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_values->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x0f); + png_byte g = (png_byte)((gamma_table[p | + (p << 4)] >> 4) & 0x0f); + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_values->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + break; + } + + case 8: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_values->gray) + { + *sp = (png_byte)background->gray; + } + else + { + *sp = gamma_table[*sp]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_values->gray) + { + *sp = (png_byte)background->gray; + } + } + } + break; + } + + case 16: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_values->gray) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_values->gray) + { + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + } + } + break; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_values->red && + *(sp + 1) == trans_values->green && + *(sp + 2) == trans_values->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_values->red && + *(sp + 1) == trans_values->green && + *(sp + 2) == trans_values->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + if (r == trans_values->red && g == trans_values->green && + b == trans_values->blue) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + + if (r == trans_values->red && g == trans_values->green && + b == trans_values->blue) + { + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + } + else if (a == 0) + { + /* Background is already in screen gamma */ + *dp = (png_byte)background->gray; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->gray); + *dp = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_byte a = *(sp + 1); + + if (a == 0xff) + { + *dp = *sp; + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) + { + *dp = (png_byte)background->gray; + } + else + { + png_composite(*dp, *sp, a, background_1->gray); + } +#else + *dp = (png_byte)background->gray; +#endif + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) +#else + else +#endif + { + /* Background is already in screen gamma */ + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, background_1->gray); + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *dp = (png_byte)((w >> 8) & 0xff); + *(dp + 1) = (png_byte)(w & 0xff); + } +#endif + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 2); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) +#else + else +#endif + { + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, background_1->gray); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } +#endif + } + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + *(dp + 1) = gamma_table[*(sp + 1)]; + *(dp + 2) = gamma_table[*(sp + 2)]; + } + else if (a == 0) + { + /* Background is already in screen gamma */ + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->red); + *dp = gamma_from_1[w]; + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, background_1->green); + *(dp + 1) = gamma_from_1[w]; + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, background_1->blue); + *(dp + 2) = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = *sp; + *(dp + 1) = *(sp + 1); + *(dp + 2) = *(sp + 2); + } + else if (a == 0) + { + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_composite(*dp, *sp, a, background->red); + png_composite(*(dp + 1), *(sp + 1), a, + background->green); + png_composite(*(dp + 2), *(sp + 2), a, + background->blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + else if (a == 0) + { + /* Background is already in screen gamma */ + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v, w, x; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, background_1->red); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *dp = (png_byte)((x >> 8) & 0xff); + *(dp + 1) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, background_1->green); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *(dp + 2) = (png_byte)((x >> 8) & 0xff); + *(dp + 3) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, background_1->blue); + x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; + *(dp + 4) = (png_byte)((x >> 8) & 0xff); + *(dp + 5) = (png_byte)(x & 0xff); + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 6); + } + else if (a == 0) + { + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, background->red); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + png_composite_16(v, g, a, background->green); + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + png_composite_16(v, b, a, background->blue); + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + } + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + row_info->channels--; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + } +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +void /* PRIVATE */ +png_do_gamma(png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift) +{ + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + ((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + } + } +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +void /* PRIVATE */ +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_colorp palette, png_bytep trans, int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + + case 2: + { + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift += 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + switch (row_info->bit_depth) + { + case 8: + { + if (trans != NULL) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + + for (i = 0; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + else + *dp-- = trans[*sp]; + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + else + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; + + for (i = 0; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + break; + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the already + * expanded transparency value is supplied, an alpha channel is built. + */ +void /* PRIVATE */ +png_do_expand(png_row_infop row_info, png_bytep row, + png_color_16p trans_value) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (png_uint_16)((gray&0x01)*0xff); + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + + case 2: + { + gray = (png_uint_16)((gray&0x03)*0x55); + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + gray = (png_uint_16)((gray&0x0f)*0x11); + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_value != NULL) + { + if (row_info->bit_depth == 8) + { + gray = gray & 0xff; + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*sp == gray) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + } + } + + else if (row_info->bit_depth == 16) + { + png_byte gray_high = (gray >> 8) & 0xff; + png_byte gray_low = gray & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 1) == gray_high && *(sp) == gray_low) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + } + } + + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) + { + if (row_info->bit_depth == 8) + { + png_byte red = trans_value->red & 0xff; + png_byte green = trans_value->green & 0xff; + png_byte blue = trans_value->blue & 0xff; + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + png_byte red_high = (trans_value->red >> 8) & 0xff; + png_byte green_high = (trans_value->green >> 8) & 0xff; + png_byte blue_high = (trans_value->blue >> 8) & 0xff; + png_byte red_low = trans_value->red & 0xff; + png_byte green_low = trans_value->green & 0xff; + png_byte blue_low = trans_value->blue & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 5) == red_high && + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + } +} +#endif + +#ifdef PNG_READ_DITHER_SUPPORTED +void /* PRIVATE */ +png_do_dither(png_row_infop row_info, png_bytep row, + png_bytep palette_lookup, png_bytep dither_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_dither"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && + palette_lookup && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* This looks real messy, but the compiler will reduce + * it down to a reasonable formula. For example, with + * 5 bits per color, we get: + * p = (((r >> 3) & 0x1f) << 10) | + * (((g >> 3) & 0x1f) << 5) | + * ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_DITHER_RED_BITS)) & + ((1 << PNG_DITHER_RED_BITS) - 1)) << + (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | + (((g >> (8 - PNG_DITHER_GREEN_BITS)) & + ((1 << PNG_DITHER_GREEN_BITS) - 1)) << + (PNG_DITHER_BLUE_BITS)) | + ((b >> (8 - PNG_DITHER_BLUE_BITS)) & + ((1 << PNG_DITHER_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_DITHER_RED_BITS)) & + ((1 << PNG_DITHER_RED_BITS) - 1)) << + (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | + (((g >> (8 - PNG_DITHER_GREEN_BITS)) & + ((1 << PNG_DITHER_GREEN_BITS) - 1)) << + (PNG_DITHER_BLUE_BITS)) | + ((b >> (8 - PNG_DITHER_BLUE_BITS)) & + ((1 << PNG_DITHER_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + dither_lookup && row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + *sp = dither_lookup[*sp]; + } + } + } +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +static PNG_CONST int png_gamma_shift[] = + {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00}; + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + * + * See the PNG extensions document for an integer algorithm for creating + * the gamma tables. Maybe we will implement that here someday. + * + * We should only reach this point if + * + * the file_gamma is known (i.e., the gAMA or sRGB chunk is present, + * or the application has provided a file_gamma) + * + * AND + * { + * the screen_gamma is known + * OR + * + * RGB_to_gray transformation is being performed + * } + * + * AND + * { + * the screen_gamma is different from the reciprocal of the + * file_gamma by more than the specified threshold + * + * OR + * + * a background color has been specified and the file_gamma + * and screen_gamma are not 1.0, within the specified threshold. + * } + */ + +void /* PRIVATE */ +png_build_gamma_table(png_structp png_ptr) +{ + png_debug(1, "in png_build_gamma_table"); + + if (png_ptr->bit_depth <= 8) + { + int i; + double g; + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + + else + g = 1.0; + + png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + + + png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + if (png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + + else + g = png_ptr->gamma; /* Probably doing rgb_to_gray */ + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } + else + { + double g; + int i, j, shift, num; + int sig_bit; + png_uint_32 ig; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit = (int)png_ptr->sig_bit.red; + + if ((int)png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if ((int)png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + { + sig_bit = (int)png_ptr->sig_bit.gray; + } + + if (sig_bit > 0) + shift = 16 - sig_bit; + + else + shift = 0; + + if (png_ptr->transformations & PNG_16_TO_8) + { + if (shift < (16 - PNG_MAX_GAMMA_8)) + shift = (16 - PNG_MAX_GAMMA_8); + } + + if (shift > 8) + shift = 8; + + if (shift < 0) + shift = 0; + + png_ptr->gamma_shift = (png_byte)shift; + + num = (1 << (8 - shift)); + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + else + g = 1.0; + + png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr, + (png_uint_32)(num * png_sizeof(png_uint_16p))); + + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) + { + double fin, fout; + png_uint_32 last, max; + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + } + + g = 1.0 / g; + last = 0; + for (i = 0; i < 256; i++) + { + fout = ((double)i + 0.5) / 256.0; + fin = pow(fout, g); + max = (png_uint_32)(fin * (double)((png_uint_32)num << 8)); + while (last <= max) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)( + (png_uint_16)i | ((png_uint_16)i << 8)); + last++; + } + } + while (last < ((png_uint_32)num << 8)) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)65535L; + last++; + } + } + else + { + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + + ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); + + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_table[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr, + (png_uint_32)(num * png_sizeof(png_uint_16p ))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_to_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + + if (png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + + else + g = png_ptr->gamma; /* Probably doing rgb_to_gray */ + + png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr, + (png_uint_32)(num * png_sizeof(png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_from_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } +} +#endif +/* To do: install integer version of png_build_gamma_table here */ +#endif + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff); + *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngrutil.c b/main/source/includes/lpng1251/pngrutil.c index 7722da02..543b7e0e 100644 --- a/main/source/includes/lpng1251/pngrutil.c +++ b/main/source/includes/lpng1251/pngrutil.c @@ -1,3386 +1,3386 @@ - -/* pngrutil.c - utilities to read a PNG file - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains routines that are only called from within - * libpng itself during the course of reading an image. - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED - -#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500) -# define WIN32_WCE_OLD -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -# ifdef WIN32_WCE_OLD -/* The strtod() function is not supported on WindowsCE */ -__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr, - char **endptr) -{ - double result = 0; - int len; - wchar_t *str, *end; - - len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0); - str = (wchar_t *)png_malloc(png_ptr, len * png_sizeof(wchar_t)); - if ( NULL != str ) - { - MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len); - result = wcstod(str, &end); - len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL); - *endptr = (char *)nptr + (png_strlen(nptr) - len + 1); - png_free(png_ptr, str); - } - return result; -} -# else -# define png_strtod(p,a,b) strtod(a,b) -# endif -#endif - -png_uint_32 PNGAPI -png_get_uint_31(png_structp png_ptr, png_bytep buf) -{ -#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED - png_uint_32 i = png_get_uint_32(buf); -#else - /* Avoid an extra function call by inlining the result. */ - png_uint_32 i = ((png_uint_32)(*buf) << 24) + - ((png_uint_32)(*(buf + 1)) << 16) + - ((png_uint_32)(*(buf + 2)) << 8) + - (png_uint_32)(*(buf + 3)); -#endif - if (i > PNG_UINT_31_MAX) - png_error(png_ptr, "PNG unsigned integer out of range."); - return (i); -} -#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED -/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ -png_uint_32 PNGAPI -png_get_uint_32(png_bytep buf) -{ - png_uint_32 i = ((png_uint_32)(*buf) << 24) + - ((png_uint_32)(*(buf + 1)) << 16) + - ((png_uint_32)(*(buf + 2)) << 8) + - (png_uint_32)(*(buf + 3)); - - return (i); -} - -/* Grab a signed 32-bit integer from a buffer in big-endian format. The - * data is stored in the PNG file in two's complement format, and it is - * assumed that the machine format for signed integers is the same. - */ -png_int_32 PNGAPI -png_get_int_32(png_bytep buf) -{ - png_int_32 i = ((png_int_32)(*buf) << 24) + - ((png_int_32)(*(buf + 1)) << 16) + - ((png_int_32)(*(buf + 2)) << 8) + - (png_int_32)(*(buf + 3)); - - return (i); -} - -/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ -png_uint_16 PNGAPI -png_get_uint_16(png_bytep buf) -{ - png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) + - (png_uint_16)(*(buf + 1))); - - return (i); -} -#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */ - -/* Read the chunk header (length + type name). - * Put the type name into png_ptr->chunk_name, and return the length. - */ -png_uint_32 /* PRIVATE */ -png_read_chunk_header(png_structp png_ptr) -{ - png_byte buf[8]; - png_uint_32 length; - - /* Read the length and the chunk name */ - png_read_data(png_ptr, buf, 8); - length = png_get_uint_31(png_ptr, buf); - - /* Put the chunk name into png_ptr->chunk_name */ - png_memcpy(png_ptr->chunk_name, buf + 4, 4); - - png_debug2(0, "Reading %s chunk, length = %lu", - png_ptr->chunk_name, length); - - /* Reset the crc and run it over the chunk name */ - png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); - - /* Check to see if chunk name is valid */ - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - - return length; -} - -/* Read data, and (optionally) run it through the CRC. */ -void /* PRIVATE */ -png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) -{ - if (png_ptr == NULL) - return; - png_read_data(png_ptr, buf, length); - png_calculate_crc(png_ptr, buf, length); -} - -/* Optionally skip data and then check the CRC. Depending on whether we - * are reading a ancillary or critical chunk, and how the program has set - * things up, we may calculate the CRC on the data and print a message. - * Returns '1' if there was a CRC error, '0' otherwise. - */ -int /* PRIVATE */ -png_crc_finish(png_structp png_ptr, png_uint_32 skip) -{ - png_size_t i; - png_size_t istop = png_ptr->zbuf_size; - - for (i = (png_size_t)skip; i > istop; i -= istop) - { - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - } - if (i) - { - png_crc_read(png_ptr, png_ptr->zbuf, i); - } - - if (png_crc_error(png_ptr)) - { - if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ - !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || - (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) - { - png_chunk_warning(png_ptr, "CRC error"); - } - else - { - png_chunk_error(png_ptr, "CRC error"); - } - return (1); - } - - return (0); -} - -/* Compare the CRC stored in the PNG file with that calculated by libpng from - * the data it has read thus far. - */ -int /* PRIVATE */ -png_crc_error(png_structp png_ptr) -{ - png_byte crc_bytes[4]; - png_uint_32 crc; - int need_crc = 1; - - if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - - png_read_data(png_ptr, crc_bytes, 4); - - if (need_crc) - { - crc = png_get_uint_32(crc_bytes); - return ((int)(crc != png_ptr->crc)); - } - else - return (0); -} - -#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ - defined(PNG_READ_iCCP_SUPPORTED) -static png_size_t -png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size, - png_bytep output, png_size_t output_size) -{ - png_size_t count = 0; - - png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */ - png_ptr->zstream.avail_in = size; - - while (1) - { - int ret, avail; - - /* Reset the output buffer each time round - we empty it - * after every inflate call. - */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = png_ptr->zbuf_size; - - ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); - avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; - - /* First copy/count any new output - but only if we didn't - * get an error code. - */ - if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) - { - if (output != 0 && output_size > count) - { - png_size_t copy = output_size - count; - if ((png_size_t) avail < copy) copy = (png_size_t) avail; - png_memcpy(output + count, png_ptr->zbuf, copy); - } - count += avail; - } - - if (ret == Z_OK) - continue; - - /* Termination conditions - always reset the zstream, it - * must be left in inflateInit state. - */ - png_ptr->zstream.avail_in = 0; - inflateReset(&png_ptr->zstream); - - if (ret == Z_STREAM_END) - return count; /* NOTE: may be zero. */ - - /* Now handle the error codes - the API always returns 0 - * and the error message is dumped into the uncompressed - * buffer if available. - */ - { - PNG_CONST char *msg; - if (png_ptr->zstream.msg != 0) - msg = png_ptr->zstream.msg; - else - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char umsg[52]; - - switch (ret) - { - case Z_BUF_ERROR: - msg = "Buffer error in compressed datastream in %s chunk"; - break; - case Z_DATA_ERROR: - msg = "Data error in compressed datastream in %s chunk"; - break; - default: - msg = "Incomplete compressed datastream in %s chunk"; - break; - } - - png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); - msg = umsg; -#else - msg = "Damaged compressed datastream in chunk other than IDAT"; -#endif - } - - png_warning(png_ptr, msg); - } - - /* 0 means an error - notice that this code simple ignores - * zero length compressed chunks as a result. - */ - return 0; - } -} - -/* - * Decompress trailing data in a chunk. The assumption is that chunkdata - * points at an allocated area holding the contents of a chunk with a - * trailing compressed part. What we get back is an allocated area - * holding the original prefix part and an uncompressed version of the - * trailing part (the malloc area passed in is freed). - */ -void /* PRIVATE */ -png_decompress_chunk(png_structp png_ptr, int comp_type, - png_size_t chunklength, - png_size_t prefix_size, png_size_t *newlength) -{ - /* The caller should guarantee this */ - if (prefix_size > chunklength) - { - /* The recovery is to delete the chunk. */ - png_warning(png_ptr, "invalid chunklength"); - prefix_size = 0; /* To delete everything */ - } - - else if (comp_type == PNG_COMPRESSION_TYPE_BASE) - { - png_size_t expanded_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - 0/*output*/, 0/*output size*/); - - /* Now check the limits on this chunk - if the limit fails the - * compressed data will be removed, the prefix will remain. - */ - if (prefix_size >= (~(png_size_t)0) - 1 || - expanded_size >= (~(png_size_t)0) - 1 - prefix_size -#ifdef PNG_USER_CHUNK_MALLOC_MAX - || ((PNG_USER_CHUNK_MALLOC_MAX > 0) && - prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) -#endif - ) - png_warning(png_ptr, "Exceeded size limit while expanding chunk"); - - /* If the size is zero either there was an error and a message - * has already been output (warning) or the size really is zero - * and we have nothing to do - the code will exit through the - * error case below. - */ - else if (expanded_size > 0) - { - /* Success (maybe) - really uncompress the chunk. */ - png_size_t new_size = 0; - - png_charp text = png_malloc_warn(png_ptr, - prefix_size + expanded_size + 1); - - if (text != NULL) - { - png_memcpy(text, png_ptr->chunkdata, prefix_size); - new_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - (png_bytep)(text + prefix_size), expanded_size); - text[prefix_size + expanded_size] = 0; /* just in case */ - - if (new_size == expanded_size) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - *newlength = prefix_size + expanded_size; - return; /* The success return! */ - } - - png_warning(png_ptr, "png_inflate logic error"); - png_free(png_ptr, text); - } - else - png_warning(png_ptr, "Not enough memory to decompress chunk."); - } - } - - else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char umsg[50]; - - png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", - comp_type); - png_warning(png_ptr, umsg); -#else - png_warning(png_ptr, "Unknown zTXt compression type"); -#endif - - /* The recovery is to simply drop the data. */ - } - - /* Generic error return - leave the prefix, delete the compressed - * data, reallocate the chunkdata to remove the potentially large - * amount of compressed data. - */ - { - png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); - if (text != NULL) - { - if (prefix_size > 0) - png_memcpy(text, png_ptr->chunkdata, prefix_size); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - - /* This is an extra zero in the 'uncompressed' part. */ - *(png_ptr->chunkdata + prefix_size) = 0x00; - } - /* Ignore a malloc error here - it is safe. */ - } - - *newlength = prefix_size; -} -#endif - -/* Read and check the IDHR chunk */ -void /* PRIVATE */ -png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[13]; - png_uint_32 width, height; - int bit_depth, color_type, compression_type, filter_type; - int interlace_type; - - png_debug(1, "in png_handle_IHDR"); - - if (png_ptr->mode & PNG_HAVE_IHDR) - png_error(png_ptr, "Out of place IHDR"); - - /* Check the length */ - if (length != 13) - png_error(png_ptr, "Invalid IHDR chunk"); - - png_ptr->mode |= PNG_HAVE_IHDR; - - png_crc_read(png_ptr, buf, 13); - png_crc_finish(png_ptr, 0); - - width = png_get_uint_31(png_ptr, buf); - height = png_get_uint_31(png_ptr, buf + 4); - bit_depth = buf[8]; - color_type = buf[9]; - compression_type = buf[10]; - filter_type = buf[11]; - interlace_type = buf[12]; - - /* Set internal variables */ - png_ptr->width = width; - png_ptr->height = height; - png_ptr->bit_depth = (png_byte)bit_depth; - png_ptr->interlaced = (png_byte)interlace_type; - png_ptr->color_type = (png_byte)color_type; -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_ptr->filter_type = (png_byte)filter_type; -#endif - png_ptr->compression_type = (png_byte)compression_type; - - /* Find number of channels */ - switch (png_ptr->color_type) - { - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_PALETTE: - png_ptr->channels = 1; - break; - - case PNG_COLOR_TYPE_RGB: - png_ptr->channels = 3; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - png_ptr->channels = 2; - break; - - case PNG_COLOR_TYPE_RGB_ALPHA: - png_ptr->channels = 4; - break; - } - - /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * - png_ptr->channels); - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); - png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); - png_debug1(3, "channels = %d", png_ptr->channels); - png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes); - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, - color_type, interlace_type, compression_type, filter_type); -} - -/* Read and check the palette */ -void /* PRIVATE */ -png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_color palette[PNG_MAX_PALETTE_LENGTH]; - int num, i; -#ifdef PNG_POINTER_INDEXING_SUPPORTED - png_colorp pal_ptr; -#endif - - png_debug(1, "in png_handle_PLTE"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before PLTE"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid PLTE after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - png_error(png_ptr, "Duplicate PLTE chunk"); - - png_ptr->mode |= PNG_HAVE_PLTE; - - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) - { - png_warning(png_ptr, - "Ignoring PLTE chunk in grayscale PNG"); - png_crc_finish(png_ptr, length); - return; - } -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_crc_finish(png_ptr, length); - return; - } -#endif - - if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) - { - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_warning(png_ptr, "Invalid palette chunk"); - png_crc_finish(png_ptr, length); - return; - } - - else - { - png_error(png_ptr, "Invalid palette chunk"); - } - } - - num = (int)length / 3; - -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) - { - png_byte buf[3]; - - png_crc_read(png_ptr, buf, 3); - pal_ptr->red = buf[0]; - pal_ptr->green = buf[1]; - pal_ptr->blue = buf[2]; - } -#else - for (i = 0; i < num; i++) - { - png_byte buf[3]; - - png_crc_read(png_ptr, buf, 3); - /* Don't depend upon png_color being any order */ - palette[i].red = buf[0]; - palette[i].green = buf[1]; - palette[i].blue = buf[2]; - } -#endif - - /* If we actually NEED the PLTE chunk (ie for a paletted image), we do - * whatever the normal CRC configuration tells us. However, if we - * have an RGB image, the PLTE can be considered ancillary, so - * we will act as though it is. - */ -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#endif - { - png_crc_finish(png_ptr, 0); - } -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ - { - /* If we don't want to use the data from an ancillary chunk, - we have two options: an error abort, or a warning and we - ignore the data in this chunk (which should be OK, since - it's considered ancillary for a RGB or RGBA image). */ - if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) - { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - { - png_chunk_error(png_ptr, "CRC error"); - } - else - { - png_chunk_warning(png_ptr, "CRC error"); - return; - } - } - /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { - png_chunk_warning(png_ptr, "CRC error"); - } - } -#endif - - png_set_PLTE(png_ptr, info_ptr, palette, num); - -#ifdef PNG_READ_tRNS_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - if (png_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); - png_ptr->num_trans = (png_uint_16)num; - } - if (info_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); - info_ptr->num_trans = (png_uint_16)num; - } - } - } -#endif - -} - -void /* PRIVATE */ -png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_debug(1, "in png_handle_IEND"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) - { - png_error(png_ptr, "No image in file"); - } - - png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); - - if (length != 0) - { - png_warning(png_ptr, "Incorrect IEND chunk length"); - } - png_crc_finish(png_ptr, length); - - PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ -} - -#ifdef PNG_READ_gAMA_SUPPORTED -void /* PRIVATE */ -png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_fixed_point igamma; -#ifdef PNG_FLOATING_POINT_SUPPORTED - float file_gamma; -#endif - png_byte buf[4]; - - png_debug(1, "in png_handle_gAMA"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before gAMA"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid gAMA after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place gAMA chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) -#ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) - { - png_warning(png_ptr, "Duplicate gAMA chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 4) - { - png_warning(png_ptr, "Incorrect gAMA chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 4); - if (png_crc_finish(png_ptr, 0)) - return; - - igamma = (png_fixed_point)png_get_uint_32(buf); - /* Check for zero gamma */ - if (igamma == 0) - { - png_warning(png_ptr, - "Ignoring gAMA chunk with gamma=0"); - return; - } - -#ifdef PNG_READ_sRGB_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "gamma = (%d/100000)", (int)igamma); -#endif - return; - } -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - file_gamma = (float)igamma / (float)100000.0; -# ifdef PNG_READ_GAMMA_SUPPORTED - png_ptr->gamma = file_gamma; -# endif - png_set_gAMA(png_ptr, info_ptr, file_gamma); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_gAMA_fixed(png_ptr, info_ptr, igamma); -#endif -} -#endif - -#ifdef PNG_READ_sBIT_SUPPORTED -void /* PRIVATE */ -png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_size_t truelen; - png_byte buf[4]; - - png_debug(1, "in png_handle_sBIT"); - - buf[0] = buf[1] = buf[2] = buf[3] = 0; - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sBIT"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sBIT after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - { - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sBIT chunk"); - } - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) - { - png_warning(png_ptr, "Duplicate sBIT chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - truelen = 3; - else - truelen = (png_size_t)png_ptr->channels; - - if (length != truelen || length > 4) - { - png_warning(png_ptr, "Incorrect sBIT chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) - return; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - { - png_ptr->sig_bit.red = buf[0]; - png_ptr->sig_bit.green = buf[1]; - png_ptr->sig_bit.blue = buf[2]; - png_ptr->sig_bit.alpha = buf[3]; - } - else - { - png_ptr->sig_bit.gray = buf[0]; - png_ptr->sig_bit.red = buf[0]; - png_ptr->sig_bit.green = buf[0]; - png_ptr->sig_bit.blue = buf[0]; - png_ptr->sig_bit.alpha = buf[1]; - } - png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); -} -#endif - -#ifdef PNG_READ_cHRM_SUPPORTED -void /* PRIVATE */ -png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[32]; -#ifdef PNG_FLOATING_POINT_SUPPORTED - float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; -#endif - png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, - int_y_green, int_x_blue, int_y_blue; - - png_uint_32 uint_x, uint_y; - - png_debug(1, "in png_handle_cHRM"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before cHRM"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid cHRM after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Missing PLTE before cHRM"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) -#ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) - { - png_warning(png_ptr, "Duplicate cHRM chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 32) - { - png_warning(png_ptr, "Incorrect cHRM chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 32); - if (png_crc_finish(png_ptr, 0)) - return; - - uint_x = png_get_uint_32(buf); - uint_y = png_get_uint_32(buf + 4); - int_x_white = (png_fixed_point)uint_x; - int_y_white = (png_fixed_point)uint_y; - - uint_x = png_get_uint_32(buf + 8); - uint_y = png_get_uint_32(buf + 12); - int_x_red = (png_fixed_point)uint_x; - int_y_red = (png_fixed_point)uint_y; - - uint_x = png_get_uint_32(buf + 16); - uint_y = png_get_uint_32(buf + 20); - int_x_green = (png_fixed_point)uint_x; - int_y_green = (png_fixed_point)uint_y; - - uint_x = png_get_uint_32(buf + 24); - uint_y = png_get_uint_32(buf + 28); - int_x_blue = (png_fixed_point)uint_x; - int_y_blue = (png_fixed_point)uint_y; - -#ifdef PNG_FLOATING_POINT_SUPPORTED - white_x = (float)int_x_white / (float)100000.0; - white_y = (float)int_y_white / (float)100000.0; - red_x = (float)int_x_red / (float)100000.0; - red_y = (float)int_y_red / (float)100000.0; - green_x = (float)int_x_green / (float)100000.0; - green_y = (float)int_y_green / (float)100000.0; - blue_x = (float)int_x_blue / (float)100000.0; - blue_y = (float)int_y_blue / (float)100000.0; -#endif - -#ifdef PNG_READ_sRGB_SUPPORTED - if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) - { - if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED - fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n", - white_x, white_y, red_x, red_y); - fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n", - green_x, green_y, blue_x, blue_y); -#else - fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", - (long)int_x_white, (long)int_y_white, - (long)int_x_red, (long)int_y_red); - fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n", - (long)int_x_green, (long)int_y_green, - (long)int_x_blue, (long)int_y_blue); -#endif -#endif /* PNG_CONSOLE_IO_SUPPORTED */ - } - return; - } -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_cHRM(png_ptr, info_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_cHRM_fixed(png_ptr, info_ptr, - int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, - int_y_green, int_x_blue, int_y_blue); -#endif -} -#endif - -#ifdef PNG_READ_sRGB_SUPPORTED -void /* PRIVATE */ -png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - int intent; - png_byte buf[1]; - - png_debug(1, "in png_handle_sRGB"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sRGB"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sRGB after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sRGB chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - { - png_warning(png_ptr, "Duplicate sRGB chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 1) - { - png_warning(png_ptr, "Incorrect sRGB chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 1); - if (png_crc_finish(png_ptr, 0)) - return; - - intent = buf[0]; - /* Check for bad intent */ - if (intent >= PNG_sRGB_INTENT_LAST) - { - png_warning(png_ptr, "Unknown sRGB intent"); - return; - } - -#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) - { - png_fixed_point igamma; -#ifdef PNG_FIXED_POINT_SUPPORTED - igamma=info_ptr->int_gamma; -#else -# ifdef PNG_FLOATING_POINT_SUPPORTED - igamma=(png_fixed_point)(info_ptr->gamma * 100000.); -# endif -#endif - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED - fprintf(stderr, "incorrect gamma=(%d/100000)\n", - (int)png_ptr->int_gamma); -# else -# ifdef PNG_FLOATING_POINT_SUPPORTED - fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma); -# endif -# endif -#endif - } - } -#endif /* PNG_READ_gAMA_SUPPORTED */ - -#ifdef PNG_READ_cHRM_SUPPORTED -#ifdef PNG_FIXED_POINT_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); - } -#endif /* PNG_FIXED_POINT_SUPPORTED */ -#endif /* PNG_READ_cHRM_SUPPORTED */ - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); -} -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_READ_iCCP_SUPPORTED -void /* PRIVATE */ -png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ -{ - png_byte compression_type; - png_bytep pC; - png_charp profile; - png_uint_32 skip = 0; - png_uint_32 profile_size, profile_length; - png_size_t slength, prefix_length, data_length; - - png_debug(1, "in png_handle_iCCP"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iCCP"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid iCCP after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place iCCP chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) - { - png_warning(png_ptr, "Duplicate iCCP chunk"); - png_crc_finish(png_ptr, length); - return; - } - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "iCCP chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (profile = png_ptr->chunkdata; *profile; profile++) - /* Empty loop to find end of name */ ; - - ++profile; - - /* There should be at least one zero (the compression type byte) - * following the separator, and we should be on it - */ - if ( profile >= png_ptr->chunkdata + slength - 1) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Malformed iCCP chunk"); - return; - } - - /* Compression_type should always be zero */ - compression_type = *profile++; - if (compression_type) - { - png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); - compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 - wrote nonzero) */ - } - - prefix_length = profile - png_ptr->chunkdata; - png_decompress_chunk(png_ptr, compression_type, - slength, prefix_length, &data_length); - - profile_length = data_length - prefix_length; - - if ( prefix_length > data_length || profile_length < 4) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Profile size field missing from iCCP chunk"); - return; - } - - /* Check the profile_size recorded in the first 32 bits of the ICC profile */ - pC = (png_bytep)(png_ptr->chunkdata + prefix_length); - profile_size = ((*(pC ))<<24) | - ((*(pC + 1))<<16) | - ((*(pC + 2))<< 8) | - ((*(pC + 3)) ); - - if (profile_size < profile_length) - profile_length = profile_size; - - if (profile_size > profile_length) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Ignoring truncated iCCP profile."); - return; - } - - png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, - compression_type, png_ptr->chunkdata + prefix_length, profile_length); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -} -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#ifdef PNG_READ_sPLT_SUPPORTED -void /* PRIVATE */ -png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ -{ - png_bytep entry_start; - png_sPLT_t new_palette; -#ifdef PNG_POINTER_INDEXING_SUPPORTED - png_sPLT_entryp pp; -#endif - int data_length, entry_size, i; - png_uint_32 skip = 0; - png_size_t slength; - - png_debug(1, "in png_handle_sPLT"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for sPLT"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sPLT"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sPLT after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "sPLT chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; - entry_start++) - /* Empty loop to find end of name */ ; - ++entry_start; - - /* A sample depth should follow the separator, and we should be on it */ - if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "malformed sPLT chunk"); - return; - } - - new_palette.depth = *entry_start++; - entry_size = (new_palette.depth == 8 ? 6 : 10); - data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata)); - - /* Integrity-check the data length */ - if (data_length % entry_size) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "sPLT chunk has bad length"); - return; - } - - new_palette.nentries = (png_int_32) ( data_length / entry_size); - if ((png_uint_32) new_palette.nentries > - (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry))) - { - png_warning(png_ptr, "sPLT chunk too long"); - return; - } - new_palette.entries = (png_sPLT_entryp)png_malloc_warn( - png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); - if (new_palette.entries == NULL) - { - png_warning(png_ptr, "sPLT chunk requires too much memory"); - return; - } - -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (i = 0; i < new_palette.nentries; i++) - { - pp = new_palette.entries + i; - - if (new_palette.depth == 8) - { - pp->red = *entry_start++; - pp->green = *entry_start++; - pp->blue = *entry_start++; - pp->alpha = *entry_start++; - } - else - { - pp->red = png_get_uint_16(entry_start); entry_start += 2; - pp->green = png_get_uint_16(entry_start); entry_start += 2; - pp->blue = png_get_uint_16(entry_start); entry_start += 2; - pp->alpha = png_get_uint_16(entry_start); entry_start += 2; - } - pp->frequency = png_get_uint_16(entry_start); entry_start += 2; - } -#else - pp = new_palette.entries; - for (i = 0; i < new_palette.nentries; i++) - { - - if (new_palette.depth == 8) - { - pp[i].red = *entry_start++; - pp[i].green = *entry_start++; - pp[i].blue = *entry_start++; - pp[i].alpha = *entry_start++; - } - else - { - pp[i].red = png_get_uint_16(entry_start); entry_start += 2; - pp[i].green = png_get_uint_16(entry_start); entry_start += 2; - pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; - pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; - } - pp->frequency = png_get_uint_16(entry_start); entry_start += 2; - } -#endif - - /* Discard all chunk data except the name and stash that */ - new_palette.name = png_ptr->chunkdata; - - png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, new_palette.entries); -} -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#ifdef PNG_READ_tRNS_SUPPORTED -void /* PRIVATE */ -png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; - - png_debug(1, "in png_handle_tRNS"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tRNS"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid tRNS after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - png_warning(png_ptr, "Duplicate tRNS chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - png_byte buf[2]; - - if (length != 2) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 2); - png_ptr->num_trans = 1; - png_ptr->trans_values.gray = png_get_uint_16(buf); - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_byte buf[6]; - - if (length != 6) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - png_crc_read(png_ptr, buf, (png_size_t)length); - png_ptr->num_trans = 1; - png_ptr->trans_values.red = png_get_uint_16(buf); - png_ptr->trans_values.green = png_get_uint_16(buf + 2); - png_ptr->trans_values.blue = png_get_uint_16(buf + 4); - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - /* Should be an error, but we can cope with it. */ - png_warning(png_ptr, "Missing PLTE before tRNS"); - } - if (length > (png_uint_32)png_ptr->num_palette || - length > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - if (length == 0) - { - png_warning(png_ptr, "Zero length tRNS chunk"); - png_crc_finish(png_ptr, length); - return; - } - png_crc_read(png_ptr, readbuf, (png_size_t)length); - png_ptr->num_trans = (png_uint_16)length; - } - else - { - png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_crc_finish(png_ptr, 0)) - { - png_ptr->num_trans = 0; - return; - } - - png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, - &(png_ptr->trans_values)); -} -#endif - -#ifdef PNG_READ_bKGD_SUPPORTED -void /* PRIVATE */ -png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_size_t truelen; - png_byte buf[6]; - - png_debug(1, "in png_handle_bKGD"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before bKGD"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid bKGD after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - { - png_warning(png_ptr, "Missing PLTE before bKGD"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) - { - png_warning(png_ptr, "Duplicate bKGD chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - truelen = 1; - else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - truelen = 6; - else - truelen = 2; - - if (length != truelen) - { - png_warning(png_ptr, "Incorrect bKGD chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) - return; - - /* We convert the index value into RGB components so that we can allow - * arbitrary RGB values for background when we have transparency, and - * so it is easy to determine the RGB values of the background color - * from the info_ptr struct. */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_ptr->background.index = buf[0]; - if (info_ptr && info_ptr->num_palette) - { - if (buf[0] >= info_ptr->num_palette) - { - png_warning(png_ptr, "Incorrect bKGD chunk index value"); - return; - } - png_ptr->background.red = - (png_uint_16)png_ptr->palette[buf[0]].red; - png_ptr->background.green = - (png_uint_16)png_ptr->palette[buf[0]].green; - png_ptr->background.blue = - (png_uint_16)png_ptr->palette[buf[0]].blue; - } - } - else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ - { - png_ptr->background.red = - png_ptr->background.green = - png_ptr->background.blue = - png_ptr->background.gray = png_get_uint_16(buf); - } - else - { - png_ptr->background.red = png_get_uint_16(buf); - png_ptr->background.green = png_get_uint_16(buf + 2); - png_ptr->background.blue = png_get_uint_16(buf + 4); - } - - png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); -} -#endif - -#ifdef PNG_READ_hIST_SUPPORTED -void /* PRIVATE */ -png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - unsigned int num, i; - png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; - - png_debug(1, "in png_handle_hIST"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before hIST"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid hIST after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - png_warning(png_ptr, "Missing PLTE before hIST"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) - { - png_warning(png_ptr, "Duplicate hIST chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length > 2*PNG_MAX_PALETTE_LENGTH || - length != (unsigned int) (2*png_ptr->num_palette)) - { - png_warning(png_ptr, "Incorrect hIST chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - num = length / 2 ; - - for (i = 0; i < num; i++) - { - png_byte buf[2]; - - png_crc_read(png_ptr, buf, 2); - readbuf[i] = png_get_uint_16(buf); - } - - if (png_crc_finish(png_ptr, 0)) - return; - - png_set_hIST(png_ptr, info_ptr, readbuf); -} -#endif - -#ifdef PNG_READ_pHYs_SUPPORTED -void /* PRIVATE */ -png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[9]; - png_uint_32 res_x, res_y; - int unit_type; - - png_debug(1, "in png_handle_pHYs"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pHYs"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid pHYs after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_warning(png_ptr, "Duplicate pHYs chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 9) - { - png_warning(png_ptr, "Incorrect pHYs chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) - return; - - res_x = png_get_uint_32(buf); - res_y = png_get_uint_32(buf + 4); - unit_type = buf[8]; - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); -} -#endif - -#ifdef PNG_READ_oFFs_SUPPORTED -void /* PRIVATE */ -png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[9]; - png_int_32 offset_x, offset_y; - int unit_type; - - png_debug(1, "in png_handle_oFFs"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before oFFs"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid oFFs after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_warning(png_ptr, "Duplicate oFFs chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 9) - { - png_warning(png_ptr, "Incorrect oFFs chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) - return; - - offset_x = png_get_int_32(buf); - offset_y = png_get_int_32(buf + 4); - unit_type = buf[8]; - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); -} -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED -/* Read the pCAL chunk (described in the PNG Extensions document) */ -void /* PRIVATE */ -png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_int_32 X0, X1; - png_byte type, nparams; - png_charp buf, units, endptr; - png_charpp params; - png_size_t slength; - int i; - - png_debug(1, "in png_handle_pCAL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pCAL"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid pCAL after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) - { - png_warning(png_ptr, "Duplicate pCAL chunk"); - png_crc_finish(png_ptr, length); - return; - } - - png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)", - length + 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory for pCAL purpose."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - - png_debug(3, "Finding end of pCAL purpose string"); - for (buf = png_ptr->chunkdata; *buf; buf++) - /* Empty loop */ ; - - endptr = png_ptr->chunkdata + slength; - - /* We need to have at least 12 bytes after the purpose string - in order to get the parameter information. */ - if (endptr <= buf + 12) - { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); - X0 = png_get_int_32((png_bytep)buf+1); - X1 = png_get_int_32((png_bytep)buf+5); - type = buf[9]; - nparams = buf[10]; - units = buf + 11; - - png_debug(3, "Checking pCAL equation type and number of parameters"); - /* Check that we have the right number of parameters for known - equation types. */ - if ((type == PNG_EQUATION_LINEAR && nparams != 2) || - (type == PNG_EQUATION_BASE_E && nparams != 3) || - (type == PNG_EQUATION_ARBITRARY && nparams != 3) || - (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) - { - png_warning(png_ptr, "Invalid pCAL parameters for equation type"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - else if (type >= PNG_EQUATION_LAST) - { - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); - } - - for (buf = units; *buf; buf++) - /* Empty loop to move past the units string. */ ; - - png_debug(3, "Allocating pCAL parameters array"); - params = (png_charpp)png_malloc_warn(png_ptr, - (png_uint_32)(nparams * png_sizeof(png_charp))) ; - if (params == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "No memory for pCAL params."); - return; - } - - /* Get pointers to the start of each parameter string. */ - for (i = 0; i < (int)nparams; i++) - { - buf++; /* Skip the null string terminator from previous parameter. */ - - png_debug1(3, "Reading pCAL parameter %d", i); - for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) - /* Empty loop to move past each parameter string */ ; - - /* Make sure we haven't run out of data yet */ - if (buf > endptr) - { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, params); - return; - } - } - - png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, - units, params); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, params); -} -#endif - -#ifdef PNG_READ_sCAL_SUPPORTED -/* Read the sCAL chunk */ -void /* PRIVATE */ -png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_charp ep; -#ifdef PNG_FLOATING_POINT_SUPPORTED - double width, height; - png_charp vp; -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - png_charp swidth, sheight; -#endif -#endif - png_size_t slength; - - png_debug(1, "in png_handle_sCAL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sCAL"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sCAL after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) - { - png_warning(png_ptr, "Duplicate sCAL chunk"); - png_crc_finish(png_ptr, length); - return; - } - - /* Need unit type, width, \0, height: minimum 4 bytes */ - else if (length < 4) - { - png_warning(png_ptr, "sCAL chunk too short"); - png_crc_finish(png_ptr, length); - return; - } - - png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)", - length + 1); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk"); - png_crc_finish(png_ptr, length); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - - ep = png_ptr->chunkdata + 1; /* Skip unit byte */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - width = png_strtod(png_ptr, ep, &vp); - if (*vp) - { - png_warning(png_ptr, "malformed width string in sCAL chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (swidth == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - png_memcpy(swidth, ep, (png_size_t)png_strlen(ep) + 1); -#endif -#endif - - for (ep = png_ptr->chunkdata + 1; *ep; ep++) - /* Empty loop */ ; - ep++; - - if (png_ptr->chunkdata + slength < ep) - { - png_warning(png_ptr, "Truncated sCAL chunk"); -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); -#endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - -#ifdef PNG_FLOATING_POINT_SUPPORTED - height = png_strtod(png_ptr, ep, &vp); - if (*vp) - { - png_warning(png_ptr, "malformed height string in sCAL chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); -#endif - return; - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (sheight == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); -#endif - return; - } - png_memcpy(sheight, ep, (png_size_t)png_strlen(ep) + 1); -#endif -#endif - - if (png_ptr->chunkdata + slength < ep -#ifdef PNG_FLOATING_POINT_SUPPORTED - || width <= 0. || height <= 0. -#endif - ) - { - png_warning(png_ptr, "Invalid sCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); - png_free(png_ptr, sheight); -#endif - return; - } - - -#ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight); -#endif -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); - png_free(png_ptr, sheight); -#endif -} -#endif - -#ifdef PNG_READ_tIME_SUPPORTED -void /* PRIVATE */ -png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[7]; - png_time mod_time; - - png_debug(1, "in png_handle_tIME"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Out of place tIME chunk"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) - { - png_warning(png_ptr, "Duplicate tIME chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - - if (length != 7) - { - png_warning(png_ptr, "Incorrect tIME chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 7); - if (png_crc_finish(png_ptr, 0)) - return; - - mod_time.second = buf[6]; - mod_time.minute = buf[5]; - mod_time.hour = buf[4]; - mod_time.day = buf[3]; - mod_time.month = buf[2]; - mod_time.year = png_get_uint_16(buf); - - png_set_tIME(png_ptr, info_ptr, &mod_time); -} -#endif - -#ifdef PNG_READ_tEXt_SUPPORTED -/* Note: this does not properly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_textp text_ptr; - png_charp key; - png_charp text; - png_uint_32 skip = 0; - png_size_t slength; - int ret; - - png_debug(1, "in png_handle_tEXt"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for tEXt"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tEXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "tEXt chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory to process text chunk."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - key = png_ptr->chunkdata; - - key[slength] = 0x00; - - for (text = key; *text; text++) - /* Empty loop to find end of key */ ; - - if (text != key + slength) - text++; - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process text chunk."); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->key = key; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; -#endif - text_ptr->text = text; - text_ptr->text_length = png_strlen(text); - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, text_ptr); - if (ret) - png_warning(png_ptr, "Insufficient memory to process text chunk."); -} -#endif - -#ifdef PNG_READ_zTXt_SUPPORTED -/* Note: this does not correctly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_textp text_ptr; - png_charp text; - int comp_type; - int ret; - png_size_t slength, prefix_len, data_len; - - png_debug(1, "in png_handle_zTXt"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for zTXt"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before zTXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - there is no hard and fast rule to tell us where to stop. */ - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "zTXt chunk too large to fit in memory"); - png_crc_finish(png_ptr, length); - return; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "Out of memory processing zTXt chunk."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (text = png_ptr->chunkdata; *text; text++) - /* Empty loop */ ; - - /* zTXt must have some text after the chunkdataword */ - if (text >= png_ptr->chunkdata + slength - 2) - { - png_warning(png_ptr, "Truncated zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - else - { - comp_type = *(++text); - if (comp_type != PNG_TEXT_COMPRESSION_zTXt) - { - png_warning(png_ptr, "Unknown compression type in zTXt chunk"); - comp_type = PNG_TEXT_COMPRESSION_zTXt; - } - text++; /* Skip the compression_method byte */ - } - prefix_len = text - png_ptr->chunkdata; - - png_decompress_chunk(png_ptr, comp_type, - (png_size_t)length, prefix_len, &data_len); - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process zTXt chunk."); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = comp_type; - text_ptr->key = png_ptr->chunkdata; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; -#endif - text_ptr->text = png_ptr->chunkdata + prefix_len; - text_ptr->text_length = data_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - if (ret) - png_error(png_ptr, "Insufficient memory to store zTXt chunk."); -} -#endif - -#ifdef PNG_READ_iTXt_SUPPORTED -/* Note: this does not correctly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_textp text_ptr; - png_charp key, lang, text, lang_key; - int comp_flag; - int comp_type = 0; - int ret; - png_size_t slength, prefix_len, data_len; - - png_debug(1, "in png_handle_iTXt"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for iTXt"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iTXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - there is no hard and fast rule to tell us where to stop. */ - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "iTXt chunk too large to fit in memory"); - png_crc_finish(png_ptr, length); - return; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory to process iTXt chunk."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (lang = png_ptr->chunkdata; *lang; lang++) - /* Empty loop */ ; - lang++; /* Skip NUL separator */ - - /* iTXt must have a language tag (possibly empty), two compression bytes, - * translated keyword (possibly empty), and possibly some text after the - * keyword - */ - - if (lang >= png_ptr->chunkdata + slength - 3) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - else - { - comp_flag = *lang++; - comp_type = *lang++; - } - - for (lang_key = lang; *lang_key; lang_key++) - /* Empty loop */ ; - lang_key++; /* Skip NUL separator */ - - if (lang_key >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - for (text = lang_key; *text; text++) - /* Empty loop */ ; - text++; /* Skip NUL separator */ - if (text >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Malformed iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - prefix_len = text - png_ptr->chunkdata; - - key=png_ptr->chunkdata; - if (comp_flag) - png_decompress_chunk(png_ptr, comp_type, - (size_t)length, prefix_len, &data_len); - else - data_len = png_strlen(png_ptr->chunkdata + prefix_len); - text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process iTXt chunk."); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = (int)comp_flag + 1; - text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); - text_ptr->lang = png_ptr->chunkdata + (lang - key); - text_ptr->itxt_length = data_len; - text_ptr->text_length = 0; - text_ptr->key = png_ptr->chunkdata; - text_ptr->text = png_ptr->chunkdata + prefix_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - if (ret) - png_error(png_ptr, "Insufficient memory to store iTXt chunk."); -} -#endif - -/* This function is called when we haven't found a handler for a - chunk. If there isn't a problem with the chunk itself (ie bad - chunk name, CRC, or a critical chunk), the chunk is silently ignored - -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which - case it will be saved away to be written out later. */ -void /* PRIVATE */ -png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_uint_32 skip = 0; - - png_debug(1, "in png_handle_unknown"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for unknown chunk"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (png_ptr->mode & PNG_HAVE_IDAT) - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ - png_ptr->mode |= PNG_AFTER_IDAT; - } - - if (!(png_ptr->chunk_name[0] & 0x20)) - { -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - } - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - || (png_ptr->read_user_chunk_fn != NULL) -#endif - ) - { -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "unknown chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - png_memcpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof(png_ptr->unknown_chunk.name)); - png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] - = '\0'; - png_ptr->unknown_chunk.size = (png_size_t)length; - if (length == 0) - png_ptr->unknown_chunk.data = NULL; - else - { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); - } -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - if (png_ptr->read_user_chunk_fn != NULL) - { - /* Callback to user unknown chunk handler */ - int ret; - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - if (ret == 0) - { - if (!(png_ptr->chunk_name[0] & 0x20)) -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - } - } - else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - else -#endif - skip = length; - - png_crc_finish(png_ptr, skip); - -#ifndef PNG_READ_USER_CHUNKS_SUPPORTED - PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ -#endif -} - -/* This function is called to verify that a chunk name is valid. - This function can't have the "critical chunk check" incorporated - into it, since in the future we will need to be able to call user - functions to handle unknown critical chunks after we check that - the chunk name itself is valid. */ - -#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) - -void /* PRIVATE */ -png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) -{ - png_debug(1, "in png_check_chunk_name"); - if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || - isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) - { - png_chunk_error(png_ptr, "invalid chunk type"); - } -} - -/* Combines the row recently read in with the existing pixels in the - row. This routine takes care of alpha and transparency if requested. - This routine also handles the two methods of progressive display - of interlaced images, depending on the mask value. - The mask value describes which pixels are to be combined with - the row. The pattern always repeats every 8 pixels, so just 8 - bits are needed. A one indicates the pixel is to be combined, - a zero indicates the pixel is to be skipped. This is in addition - to any alpha or transparency value associated with the pixel. If - you want all pixels to be combined, pass 0xff (255) in mask. */ - -void /* PRIVATE */ -png_combine_row(png_structp png_ptr, png_bytep row, int mask) -{ - png_debug(1, "in png_combine_row"); - if (mask == 0xff) - { - png_memcpy(row, png_ptr->row_buf + 1, - PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); - } - else - { - switch (png_ptr->row_info.pixel_depth) - { - case 1: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_inc, s_start, s_end; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 7; - s_inc = 1; - } - else -#endif - { - s_start = 7; - s_end = 0; - s_inc = -1; - } - - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - int value; - - value = (*sp >> shift) & 0x01; - *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - else - shift += s_inc; - - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - case 2: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_start, s_end, s_inc; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - int value; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 6; - s_inc = 2; - } - else -#endif - { - s_start = 6; - s_end = 0; - s_inc = -2; - } - - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - value = (*sp >> shift) & 0x03; - *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - else - shift += s_inc; - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - case 4: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_start, s_end, s_inc; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - int value; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 4; - s_inc = 4; - } - else -#endif - { - s_start = 4; - s_end = 0; - s_inc = -4; - } - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - value = (*sp >> shift) & 0xf; - *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - else - shift += s_inc; - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - default: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - png_byte m = 0x80; - - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - png_memcpy(dp, sp, pixel_bytes); - } - - sp += pixel_bytes; - dp += pixel_bytes; - - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - } - } -} - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* OLD pre-1.0.9 interface: -void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, - png_uint_32 transformations) - */ -void /* PRIVATE */ -png_do_read_interlace(png_structp png_ptr) -{ - png_row_infop row_info = &(png_ptr->row_info); - png_bytep row = png_ptr->row_buf + 1; - int pass = png_ptr->pass; - png_uint_32 transformations = png_ptr->transformations; - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - png_debug(1, "in png_do_read_interlace"); - if (row != NULL && row_info != NULL) - { - png_uint_32 final_width; - - final_width = row_info->width * png_pass_inc[pass]; - - switch (row_info->pixel_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); - png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); - int sshift, dshift; - int s_start, s_end, s_inc; - int jstop = png_pass_inc[pass]; - png_byte v; - png_uint_32 i; - int j; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) - { - sshift = (int)((row_info->width + 7) & 0x07); - dshift = (int)((final_width + 7) & 0x07); - s_start = 7; - s_end = 0; - s_inc = -1; - } - else -#endif - { - sshift = 7 - (int)((row_info->width + 7) & 0x07); - dshift = 7 - (int)((final_width + 7) & 0x07); - s_start = 0; - s_end = 7; - s_inc = 1; - } - - for (i = 0; i < row_info->width; i++) - { - v = (png_byte)((*sp >> sshift) & 0x01); - for (j = 0; j < jstop; j++) - { - *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - else - dshift += s_inc; - } - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - else - sshift += s_inc; - } - break; - } - case 2: - { - png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); - png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); - int sshift, dshift; - int s_start, s_end, s_inc; - int jstop = png_pass_inc[pass]; - png_uint_32 i; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) - { - sshift = (int)(((row_info->width + 3) & 0x03) << 1); - dshift = (int)(((final_width + 3) & 0x03) << 1); - s_start = 6; - s_end = 0; - s_inc = -2; - } - else -#endif - { - sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); - dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); - s_start = 0; - s_end = 6; - s_inc = 2; - } - - for (i = 0; i < row_info->width; i++) - { - png_byte v; - int j; - - v = (png_byte)((*sp >> sshift) & 0x03); - for (j = 0; j < jstop; j++) - { - *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - else - dshift += s_inc; - } - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - else - sshift += s_inc; - } - break; - } - case 4: - { - png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); - png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); - int sshift, dshift; - int s_start, s_end, s_inc; - png_uint_32 i; - int jstop = png_pass_inc[pass]; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) - { - sshift = (int)(((row_info->width + 1) & 0x01) << 2); - dshift = (int)(((final_width + 1) & 0x01) << 2); - s_start = 4; - s_end = 0; - s_inc = -4; - } - else -#endif - { - sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); - dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); - s_start = 0; - s_end = 4; - s_inc = 4; - } - - for (i = 0; i < row_info->width; i++) - { - png_byte v = (png_byte)((*sp >> sshift) & 0xf); - int j; - - for (j = 0; j < jstop; j++) - { - *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - else - dshift += s_inc; - } - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - else - sshift += s_inc; - } - break; - } - default: - { - png_size_t pixel_bytes = (row_info->pixel_depth >> 3); - png_bytep sp = row + (png_size_t)(row_info->width - 1) - * pixel_bytes; - png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; - - int jstop = png_pass_inc[pass]; - png_uint_32 i; - - for (i = 0; i < row_info->width; i++) - { - png_byte v[8]; - int j; - - png_memcpy(v, sp, pixel_bytes); - for (j = 0; j < jstop; j++) - { - png_memcpy(dp, v, pixel_bytes); - dp -= pixel_bytes; - } - sp -= pixel_bytes; - } - break; - } - } - row_info->width = final_width; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); - } -#ifndef PNG_READ_PACKSWAP_SUPPORTED - PNG_UNUSED(transformations) /* Silence compiler warning */ -#endif -} -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - -void /* PRIVATE */ -png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, - png_bytep prev_row, int filter) -{ - png_debug(1, "in png_read_filter_row"); - png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter); - switch (filter) - { - case PNG_FILTER_VALUE_NONE: - break; - case PNG_FILTER_VALUE_SUB: - { - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; - png_bytep rp = row + bpp; - png_bytep lp = row; - - for (i = bpp; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_UP: - { - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - png_bytep rp = row; - png_bytep pp = prev_row; - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_AVG: - { - png_uint_32 i; - png_bytep rp = row; - png_bytep pp = prev_row; - png_bytep lp = row; - png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; - png_uint_32 istop = row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + - ((int)(*pp++) / 2 )) & 0xff); - rp++; - } - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + - (int)(*pp++ + *lp++) / 2 ) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_PAETH: - { - png_uint_32 i; - png_bytep rp = row; - png_bytep pp = prev_row; - png_bytep lp = row; - png_bytep cp = prev_row; - png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; - png_uint_32 istop=row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } - - for (i = 0; i < istop; i++) /* Use leftover rp,pp */ - { - int a, b, c, pa, pb, pc, p; - - a = *lp++; - b = *pp++; - c = *cp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - /* - if (pa <= pb && pa <= pc) - p = a; - else if (pb <= pc) - p = b; - else - p = c; - */ - - p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; - - *rp = (png_byte)(((int)(*rp) + p) & 0xff); - rp++; - } - break; - } - default: - png_warning(png_ptr, "Ignoring bad adaptive filter type"); - *row = 0; - break; - } -} - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -void /* PRIVATE */ -png_read_finish_row(png_structp png_ptr) -{ -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - png_debug(1, "in png_read_finish_row"); - png_ptr->row_number++; - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - png_memset_check(png_ptr, png_ptr->prev_row, 0, - png_ptr->rowbytes + 1); - do - { - png_ptr->pass++; - if (png_ptr->pass >= 7) - break; - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - if (!(png_ptr->transformations & PNG_INTERLACE)) - { - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - if (!(png_ptr->num_rows)) - continue; - } - else /* if (png_ptr->transformations & PNG_INTERLACE) */ - break; - } while (png_ptr->iwidth == 0); - - if (png_ptr->pass < 7) - return; - } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif - char extra; - int ret; - - png_ptr->zstream.next_out = (Byte *)&extra; - png_ptr->zstream.avail_out = (uInt)1; - for (;;) - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_byte chunk_length[4]; - - png_crc_finish(png_ptr, 0); - - png_read_data(png_ptr, chunk_length, 4); - png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_error(png_ptr, "Not enough image data"); - - } - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret == Z_STREAM_END) - { - if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_warning(png_ptr, "Extra compressed data."); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression Error"); - - if (!(png_ptr->zstream.avail_out)) - { - png_warning(png_ptr, "Extra compressed data."); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - } - png_ptr->zstream.avail_out = 0; - } - - if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_warning(png_ptr, "Extra compression data."); - - inflateReset(&png_ptr->zstream); - - png_ptr->mode |= PNG_AFTER_IDAT; -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -void /* PRIVATE */ -png_read_start_row(png_structp png_ptr) -{ -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - - int max_pixel_depth; - png_size_t row_bytes; - - png_debug(1, "in png_read_start_row"); - png_ptr->zstream.avail_in = 0; - png_init_read_transformations(png_ptr); -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - if (!(png_ptr->transformations & PNG_INTERLACE)) - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; - else - png_ptr->num_rows = png_ptr->height; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - } - else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - { - png_ptr->num_rows = png_ptr->height; - png_ptr->iwidth = png_ptr->width; - } - max_pixel_depth = png_ptr->pixel_depth; - -#ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) - max_pixel_depth = 8; -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (png_ptr->num_trans) - max_pixel_depth = 32; - else - max_pixel_depth = 24; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - if (max_pixel_depth < 8) - max_pixel_depth = 8; - if (png_ptr->num_trans) - max_pixel_depth *= 2; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - if (png_ptr->num_trans) - { - max_pixel_depth *= 4; - max_pixel_depth /= 3; - } - } - } -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & (PNG_FILLER)) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - max_pixel_depth = 32; - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - if (max_pixel_depth <= 8) - max_pixel_depth = 16; - else - max_pixel_depth = 32; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - if (max_pixel_depth <= 32) - max_pixel_depth = 32; - else - max_pixel_depth = 64; - } - } -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - { - if ( -#ifdef PNG_READ_EXPAND_SUPPORTED - (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || -#endif -#ifdef PNG_READ_FILLER_SUPPORTED - (png_ptr->transformations & (PNG_FILLER)) || -#endif - png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (max_pixel_depth <= 16) - max_pixel_depth = 32; - else - max_pixel_depth = 64; - } - else - { - if (max_pixel_depth <= 8) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - max_pixel_depth = 32; - else - max_pixel_depth = 24; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - max_pixel_depth = 64; - else - max_pixel_depth = 48; - } - } -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ -defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - int user_pixel_depth = png_ptr->user_transform_depth* - png_ptr->user_transform_channels; - if (user_pixel_depth > max_pixel_depth) - max_pixel_depth=user_pixel_depth; - } -#endif - - /* Align the width on the next larger 8 pixels. Mainly used - * for interlacing - */ - row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); - /* Calculate the maximum bytes needed, adding a byte and a pixel - * for safety's sake - */ - row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + - 1 + ((max_pixel_depth + 7) >> 3); -#ifdef PNG_MAX_MALLOC_64K - if (row_bytes > (png_uint_32)65536L) - png_error(png_ptr, "This image requires a row greater than 64KB"); -#endif - - if (row_bytes + 64 > png_ptr->old_big_row_buf_size) - { - png_free(png_ptr, png_ptr->big_row_buf); - if (png_ptr->interlaced) - png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, - row_bytes + 64); - else - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, - row_bytes + 64); - png_ptr->old_big_row_buf_size = row_bytes + 64; - - /* Use 32 bytes of padding before and after row_buf. */ - png_ptr->row_buf = png_ptr->big_row_buf + 32; - png_ptr->old_big_row_buf_size = row_bytes + 64; - } - -#ifdef PNG_MAX_MALLOC_64K - if ((png_uint_32)row_bytes + 1 > (png_uint_32)65536L) - png_error(png_ptr, "This image requires a row greater than 64KB"); -#endif - if ((png_uint_32)row_bytes > (png_uint_32)(PNG_SIZE_MAX - 1)) - png_error(png_ptr, "Row has too many bytes to allocate in memory."); - - if (row_bytes + 1 > png_ptr->old_prev_row_size) - { - png_free(png_ptr, png_ptr->prev_row); - png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( - row_bytes + 1)); - png_memset_check(png_ptr, png_ptr->prev_row, 0, row_bytes + 1); - png_ptr->old_prev_row_size = row_bytes + 1; - } - - png_ptr->rowbytes = row_bytes; - - png_debug1(3, "width = %lu,", png_ptr->width); - png_debug1(3, "height = %lu,", png_ptr->height); - png_debug1(3, "iwidth = %lu,", png_ptr->iwidth); - png_debug1(3, "num_rows = %lu,", png_ptr->num_rows); - png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes); - png_debug1(3, "irowbytes = %lu", - PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); - - png_ptr->flags |= PNG_FLAG_ROW_INIT; -} -#endif /* PNG_READ_SUPPORTED */ + +/* pngrutil.c - utilities to read a PNG file + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED + +#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500) +# define WIN32_WCE_OLD +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +# ifdef WIN32_WCE_OLD +/* The strtod() function is not supported on WindowsCE */ +__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr, + char **endptr) +{ + double result = 0; + int len; + wchar_t *str, *end; + + len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0); + str = (wchar_t *)png_malloc(png_ptr, len * png_sizeof(wchar_t)); + if ( NULL != str ) + { + MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len); + result = wcstod(str, &end); + len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL); + *endptr = (char *)nptr + (png_strlen(nptr) - len + 1); + png_free(png_ptr, str); + } + return result; +} +# else +# define png_strtod(p,a,b) strtod(a,b) +# endif +#endif + +png_uint_32 PNGAPI +png_get_uint_31(png_structp png_ptr, png_bytep buf) +{ +#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED + png_uint_32 i = png_get_uint_32(buf); +#else + /* Avoid an extra function call by inlining the result. */ + png_uint_32 i = ((png_uint_32)(*buf) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + (png_uint_32)(*(buf + 3)); +#endif + if (i > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range."); + return (i); +} +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 PNGAPI +png_get_uint_32(png_bytep buf) +{ + png_uint_32 i = ((png_uint_32)(*buf) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + (png_uint_32)(*(buf + 3)); + + return (i); +} + +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format, and it is + * assumed that the machine format for signed integers is the same. + */ +png_int_32 PNGAPI +png_get_int_32(png_bytep buf) +{ + png_int_32 i = ((png_int_32)(*buf) << 24) + + ((png_int_32)(*(buf + 1)) << 16) + + ((png_int_32)(*(buf + 2)) << 8) + + (png_int_32)(*(buf + 3)); + + return (i); +} + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 PNGAPI +png_get_uint_16(png_bytep buf) +{ + png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) + + (png_uint_16)(*(buf + 1))); + + return (i); +} +#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */ + +/* Read the chunk header (length + type name). + * Put the type name into png_ptr->chunk_name, and return the length. + */ +png_uint_32 /* PRIVATE */ +png_read_chunk_header(png_structp png_ptr) +{ + png_byte buf[8]; + png_uint_32 length; + + /* Read the length and the chunk name */ + png_read_data(png_ptr, buf, 8); + length = png_get_uint_31(png_ptr, buf); + + /* Put the chunk name into png_ptr->chunk_name */ + png_memcpy(png_ptr->chunk_name, buf + 4, 4); + + png_debug2(0, "Reading %s chunk, length = %lu", + png_ptr->chunk_name, length); + + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); + + /* Check to see if chunk name is valid */ + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + + return length; +} + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +{ + if (png_ptr == NULL) + return; + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + * are reading a ancillary or critical chunk, and how the program has set + * things up, we may calculate the CRC on the data and print a message. + * Returns '1' if there was a CRC error, '0' otherwise. + */ +int /* PRIVATE */ +png_crc_finish(png_structp png_ptr, png_uint_32 skip) +{ + png_size_t i; + png_size_t istop = png_ptr->zbuf_size; + + for (i = (png_size_t)skip; i > istop; i -= istop) + { + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + } + if (i) + { + png_crc_read(png_ptr, png_ptr->zbuf, i); + } + + if (png_crc_error(png_ptr)) + { + if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || + (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) + { + png_chunk_warning(png_ptr, "CRC error"); + } + else + { + png_chunk_error(png_ptr, "CRC error"); + } + return (1); + } + + return (0); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. + */ +int /* PRIVATE */ +png_crc_error(png_structp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + else + return (0); +} + +#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ + defined(PNG_READ_iCCP_SUPPORTED) +static png_size_t +png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size, + png_bytep output, png_size_t output_size) +{ + png_size_t count = 0; + + png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */ + png_ptr->zstream.avail_in = size; + + while (1) + { + int ret, avail; + + /* Reset the output buffer each time round - we empty it + * after every inflate call. + */ + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = png_ptr->zbuf_size; + + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; + + /* First copy/count any new output - but only if we didn't + * get an error code. + */ + if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) + { + if (output != 0 && output_size > count) + { + png_size_t copy = output_size - count; + if ((png_size_t) avail < copy) copy = (png_size_t) avail; + png_memcpy(output + count, png_ptr->zbuf, copy); + } + count += avail; + } + + if (ret == Z_OK) + continue; + + /* Termination conditions - always reset the zstream, it + * must be left in inflateInit state. + */ + png_ptr->zstream.avail_in = 0; + inflateReset(&png_ptr->zstream); + + if (ret == Z_STREAM_END) + return count; /* NOTE: may be zero. */ + + /* Now handle the error codes - the API always returns 0 + * and the error message is dumped into the uncompressed + * buffer if available. + */ + { + PNG_CONST char *msg; + if (png_ptr->zstream.msg != 0) + msg = png_ptr->zstream.msg; + else + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char umsg[52]; + + switch (ret) + { + case Z_BUF_ERROR: + msg = "Buffer error in compressed datastream in %s chunk"; + break; + case Z_DATA_ERROR: + msg = "Data error in compressed datastream in %s chunk"; + break; + default: + msg = "Incomplete compressed datastream in %s chunk"; + break; + } + + png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); + msg = umsg; +#else + msg = "Damaged compressed datastream in chunk other than IDAT"; +#endif + } + + png_warning(png_ptr, msg); + } + + /* 0 means an error - notice that this code simple ignores + * zero length compressed chunks as a result. + */ + return 0; + } +} + +/* + * Decompress trailing data in a chunk. The assumption is that chunkdata + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +void /* PRIVATE */ +png_decompress_chunk(png_structp png_ptr, int comp_type, + png_size_t chunklength, + png_size_t prefix_size, png_size_t *newlength) +{ + /* The caller should guarantee this */ + if (prefix_size > chunklength) + { + /* The recovery is to delete the chunk. */ + png_warning(png_ptr, "invalid chunklength"); + prefix_size = 0; /* To delete everything */ + } + + else if (comp_type == PNG_COMPRESSION_TYPE_BASE) + { + png_size_t expanded_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + 0/*output*/, 0/*output size*/); + + /* Now check the limits on this chunk - if the limit fails the + * compressed data will be removed, the prefix will remain. + */ + if (prefix_size >= (~(png_size_t)0) - 1 || + expanded_size >= (~(png_size_t)0) - 1 - prefix_size +#ifdef PNG_USER_CHUNK_MALLOC_MAX + || ((PNG_USER_CHUNK_MALLOC_MAX > 0) && + prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) +#endif + ) + png_warning(png_ptr, "Exceeded size limit while expanding chunk"); + + /* If the size is zero either there was an error and a message + * has already been output (warning) or the size really is zero + * and we have nothing to do - the code will exit through the + * error case below. + */ + else if (expanded_size > 0) + { + /* Success (maybe) - really uncompress the chunk. */ + png_size_t new_size = 0; + + png_charp text = png_malloc_warn(png_ptr, + prefix_size + expanded_size + 1); + + if (text != NULL) + { + png_memcpy(text, png_ptr->chunkdata, prefix_size); + new_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + (png_bytep)(text + prefix_size), expanded_size); + text[prefix_size + expanded_size] = 0; /* just in case */ + + if (new_size == expanded_size) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + *newlength = prefix_size + expanded_size; + return; /* The success return! */ + } + + png_warning(png_ptr, "png_inflate logic error"); + png_free(png_ptr, text); + } + else + png_warning(png_ptr, "Not enough memory to decompress chunk."); + } + } + + else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char umsg[50]; + + png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", + comp_type); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, "Unknown zTXt compression type"); +#endif + + /* The recovery is to simply drop the data. */ + } + + /* Generic error return - leave the prefix, delete the compressed + * data, reallocate the chunkdata to remove the potentially large + * amount of compressed data. + */ + { + png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); + if (text != NULL) + { + if (prefix_size > 0) + png_memcpy(text, png_ptr->chunkdata, prefix_size); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + + /* This is an extra zero in the 'uncompressed' part. */ + *(png_ptr->chunkdata + prefix_size) = 0x00; + } + /* Ignore a malloc error here - it is safe. */ + } + + *newlength = prefix_size; +} +#endif + +/* Read and check the IDHR chunk */ +void /* PRIVATE */ +png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR"); + + if (png_ptr->mode & PNG_HAVE_IHDR) + png_error(png_ptr, "Out of place IHDR"); + + /* Check the length */ + if (length != 13) + png_error(png_ptr, "Invalid IHDR chunk"); + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + /* Set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + + /* Find number of channels */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* Set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * + png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); + png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); + png_debug1(3, "channels = %d", png_ptr->channels); + png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes); + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); +} + +/* Read and check the palette */ +void /* PRIVATE */ +png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int num, i; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_colorp pal_ptr; +#endif + + png_debug(1, "in png_handle_PLTE"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before PLTE"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid PLTE after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_error(png_ptr, "Duplicate PLTE chunk"); + + png_ptr->mode |= PNG_HAVE_PLTE; + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring PLTE chunk in grayscale PNG"); + png_crc_finish(png_ptr, length); + return; + } +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_warning(png_ptr, "Invalid palette chunk"); + png_crc_finish(png_ptr, length); + return; + } + + else + { + png_error(png_ptr, "Invalid palette chunk"); + } + } + + num = (int)length / 3; + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* Don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually NEED the PLTE chunk (ie for a paletted image), we do + * whatever the normal CRC configuration tells us. However, if we + * have an RGB image, the PLTE can be considered ancillary, so + * we will act as though it is. + */ +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, 0); + } +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + we have two options: an error abort, or a warning and we + ignore the data in this chunk (which should be OK, since + it's considered ancillary for a RGB or RGBA image). */ + if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + { + if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) + { + png_chunk_error(png_ptr, "CRC error"); + } + else + { + png_chunk_warning(png_ptr, "CRC error"); + return; + } + } + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + } +#endif + + png_set_PLTE(png_ptr, info_ptr, palette, num); + +#ifdef PNG_READ_tRNS_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + if (png_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); + png_ptr->num_trans = (png_uint_16)num; + } + if (info_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); + info_ptr->num_trans = (png_uint_16)num; + } + } + } +#endif + +} + +void /* PRIVATE */ +png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) + { + png_error(png_ptr, "No image in file"); + } + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + if (length != 0) + { + png_warning(png_ptr, "Incorrect IEND chunk length"); + } + png_crc_finish(png_ptr, length); + + PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ +} + +#ifdef PNG_READ_gAMA_SUPPORTED +void /* PRIVATE */ +png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_fixed_point igamma; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before gAMA"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid gAMA after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place gAMA chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) +#ifdef PNG_READ_sRGB_SUPPORTED + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate gAMA chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 4) + { + png_warning(png_ptr, "Incorrect gAMA chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 4); + if (png_crc_finish(png_ptr, 0)) + return; + + igamma = (png_fixed_point)png_get_uint_32(buf); + /* Check for zero gamma */ + if (igamma == 0) + { + png_warning(png_ptr, + "Ignoring gAMA chunk with gamma=0"); + return; + } + +#ifdef PNG_READ_sRGB_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifdef PNG_CONSOLE_IO_SUPPORTED + fprintf(stderr, "gamma = (%d/100000)", (int)igamma); +#endif + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float)igamma / (float)100000.0; +# ifdef PNG_READ_GAMMA_SUPPORTED + png_ptr->gamma = file_gamma; +# endif + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, igamma); +#endif +} +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +void /* PRIVATE */ +png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT"); + + buf[0] = buf[1] = buf[2] = buf[3] = 0; + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sBIT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sBIT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + { + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sBIT chunk"); + } + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + { + png_warning(png_ptr, "Duplicate sBIT chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 3; + else + truelen = (png_size_t)png_ptr->channels; + + if (length != truelen || length > 4) + { + png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + else + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); +} +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +void /* PRIVATE */ +png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[32]; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue; + + png_uint_32 uint_x, uint_y; + + png_debug(1, "in png_handle_cHRM"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before cHRM"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid cHRM after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before cHRM"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) +#ifdef PNG_READ_sRGB_SUPPORTED + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate cHRM chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 32) + { + png_warning(png_ptr, "Incorrect cHRM chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 32); + if (png_crc_finish(png_ptr, 0)) + return; + + uint_x = png_get_uint_32(buf); + uint_y = png_get_uint_32(buf + 4); + int_x_white = (png_fixed_point)uint_x; + int_y_white = (png_fixed_point)uint_y; + + uint_x = png_get_uint_32(buf + 8); + uint_y = png_get_uint_32(buf + 12); + int_x_red = (png_fixed_point)uint_x; + int_y_red = (png_fixed_point)uint_y; + + uint_x = png_get_uint_32(buf + 16); + uint_y = png_get_uint_32(buf + 20); + int_x_green = (png_fixed_point)uint_x; + int_y_green = (png_fixed_point)uint_y; + + uint_x = png_get_uint_32(buf + 24); + uint_y = png_get_uint_32(buf + 28); + int_x_blue = (png_fixed_point)uint_x; + int_y_blue = (png_fixed_point)uint_y; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float)int_x_white / (float)100000.0; + white_y = (float)int_y_white / (float)100000.0; + red_x = (float)int_x_red / (float)100000.0; + red_y = (float)int_y_red / (float)100000.0; + green_x = (float)int_x_green / (float)100000.0; + green_y = (float)int_y_green / (float)100000.0; + blue_x = (float)int_x_blue / (float)100000.0; + blue_y = (float)int_y_blue / (float)100000.0; +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) + { + if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) + { + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n", + white_x, white_y, red_x, red_y); + fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n", + green_x, green_y, blue_x, blue_y); +#else + fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", + (long)int_x_white, (long)int_y_white, + (long)int_x_red, (long)int_y_red); + fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n", + (long)int_x_green, (long)int_y_green, + (long)int_x_blue, (long)int_y_blue); +#endif +#endif /* PNG_CONSOLE_IO_SUPPORTED */ + } + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue); +#endif +} +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED +void /* PRIVATE */ +png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + int intent; + png_byte buf[1]; + + png_debug(1, "in png_handle_sRGB"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sRGB"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sRGB after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sRGB chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + { + png_warning(png_ptr, "Duplicate sRGB chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 1) + { + png_warning(png_ptr, "Incorrect sRGB chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 1); + if (png_crc_finish(png_ptr, 0)) + return; + + intent = buf[0]; + /* Check for bad intent */ + if (intent >= PNG_sRGB_INTENT_LAST) + { + png_warning(png_ptr, "Unknown sRGB intent"); + return; + } + +#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) + { + png_fixed_point igamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + igamma=info_ptr->int_gamma; +#else +# ifdef PNG_FLOATING_POINT_SUPPORTED + igamma=(png_fixed_point)(info_ptr->gamma * 100000.); +# endif +#endif + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED + fprintf(stderr, "incorrect gamma=(%d/100000)\n", + (int)png_ptr->int_gamma); +# else +# ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma); +# endif +# endif +#endif + } + } +#endif /* PNG_READ_gAMA_SUPPORTED */ + +#ifdef PNG_READ_cHRM_SUPPORTED +#ifdef PNG_FIXED_POINT_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000)) + { + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); + } +#endif /* PNG_FIXED_POINT_SUPPORTED */ +#endif /* PNG_READ_cHRM_SUPPORTED */ + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_READ_iCCP_SUPPORTED +void /* PRIVATE */ +png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_byte compression_type; + png_bytep pC; + png_charp profile; + png_uint_32 skip = 0; + png_uint_32 profile_size, profile_length; + png_size_t slength, prefix_length, data_length; + + png_debug(1, "in png_handle_iCCP"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iCCP"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid iCCP after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place iCCP chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) + { + png_warning(png_ptr, "Duplicate iCCP chunk"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "iCCP chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (profile = png_ptr->chunkdata; *profile; profile++) + /* Empty loop to find end of name */ ; + + ++profile; + + /* There should be at least one zero (the compression type byte) + * following the separator, and we should be on it + */ + if ( profile >= png_ptr->chunkdata + slength - 1) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Malformed iCCP chunk"); + return; + } + + /* Compression_type should always be zero */ + compression_type = *profile++; + if (compression_type) + { + png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); + compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 + wrote nonzero) */ + } + + prefix_length = profile - png_ptr->chunkdata; + png_decompress_chunk(png_ptr, compression_type, + slength, prefix_length, &data_length); + + profile_length = data_length - prefix_length; + + if ( prefix_length > data_length || profile_length < 4) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Profile size field missing from iCCP chunk"); + return; + } + + /* Check the profile_size recorded in the first 32 bits of the ICC profile */ + pC = (png_bytep)(png_ptr->chunkdata + prefix_length); + profile_size = ((*(pC ))<<24) | + ((*(pC + 1))<<16) | + ((*(pC + 2))<< 8) | + ((*(pC + 3)) ); + + if (profile_size < profile_length) + profile_length = profile_size; + + if (profile_size > profile_length) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Ignoring truncated iCCP profile."); + return; + } + + png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, + compression_type, png_ptr->chunkdata + prefix_length, profile_length); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +} +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_sPLT_SUPPORTED +void /* PRIVATE */ +png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep entry_start; + png_sPLT_t new_palette; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_sPLT_entryp pp; +#endif + int data_length, entry_size, i; + png_uint_32 skip = 0; + png_size_t slength; + + png_debug(1, "in png_handle_sPLT"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sPLT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sPLT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "sPLT chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; + entry_start++) + /* Empty loop to find end of name */ ; + ++entry_start; + + /* A sample depth should follow the separator, and we should be on it */ + if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "malformed sPLT chunk"); + return; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata)); + + /* Integrity-check the data length */ + if (data_length % entry_size) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "sPLT chunk has bad length"); + return; + } + + new_palette.nentries = (png_int_32) ( data_length / entry_size); + if ((png_uint_32) new_palette.nentries > + (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry))) + { + png_warning(png_ptr, "sPLT chunk too long"); + return; + } + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; + } + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0; i < new_palette.nentries; i++) + { + pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#else + pp = new_palette.entries; + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif + + /* Discard all chunk data except the name and stash that */ + new_palette.name = png_ptr->chunkdata; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, new_palette.entries); +} +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_tRNS_SUPPORTED +void /* PRIVATE */ +png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tRNS"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid tRNS after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_warning(png_ptr, "Duplicate tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[2]; + + if (length != 2) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_values.gray = png_get_uint_16(buf); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, buf, (png_size_t)length); + png_ptr->num_trans = 1; + png_ptr->trans_values.red = png_get_uint_16(buf); + png_ptr->trans_values.green = png_get_uint_16(buf + 2); + png_ptr->trans_values.blue = png_get_uint_16(buf + 4); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* Should be an error, but we can cope with it. */ + png_warning(png_ptr, "Missing PLTE before tRNS"); + } + if (length > (png_uint_32)png_ptr->num_palette || + length > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + if (length == 0) + { + png_warning(png_ptr, "Zero length tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_ptr->num_trans = (png_uint_16)length; + } + else + { + png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_crc_finish(png_ptr, 0)) + { + png_ptr->num_trans = 0; + return; + } + + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_values)); +} +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED +void /* PRIVATE */ +png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[6]; + + png_debug(1, "in png_handle_bKGD"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before bKGD"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid bKGD after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before bKGD"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + { + png_warning(png_ptr, "Duplicate bKGD chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + truelen = 6; + else + truelen = 2; + + if (length != truelen) + { + png_warning(png_ptr, "Incorrect bKGD chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.index = buf[0]; + if (info_ptr && info_ptr->num_palette) + { + if (buf[0] >= info_ptr->num_palette) + { + png_warning(png_ptr, "Incorrect bKGD chunk index value"); + return; + } + png_ptr->background.red = + (png_uint_16)png_ptr->palette[buf[0]].red; + png_ptr->background.green = + (png_uint_16)png_ptr->palette[buf[0]].green; + png_ptr->background.blue = + (png_uint_16)png_ptr->palette[buf[0]].blue; + } + } + else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + { + png_ptr->background.red = + png_ptr->background.green = + png_ptr->background.blue = + png_ptr->background.gray = png_get_uint_16(buf); + } + else + { + png_ptr->background.red = png_get_uint_16(buf); + png_ptr->background.green = png_get_uint_16(buf + 2); + png_ptr->background.blue = png_get_uint_16(buf + 4); + } + + png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); +} +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +void /* PRIVATE */ +png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + unsigned int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before hIST"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid hIST after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before hIST"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) + { + png_warning(png_ptr, "Duplicate hIST chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length > 2*PNG_MAX_PALETTE_LENGTH || + length != (unsigned int) (2*png_ptr->num_palette)) + { + png_warning(png_ptr, "Incorrect hIST chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + num = length / 2 ; + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_hIST(png_ptr, info_ptr, readbuf); +} +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +void /* PRIVATE */ +png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pHYs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pHYs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_warning(png_ptr, "Duplicate pHYs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect pHYs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); +} +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +void /* PRIVATE */ +png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before oFFs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid oFFs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_warning(png_ptr, "Duplicate oFFs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect oFFs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); +} +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +/* Read the pCAL chunk (described in the PNG Extensions document) */ +void /* PRIVATE */ +png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_int_32 X0, X1; + png_byte type, nparams; + png_charp buf, units, endptr; + png_charpp params; + png_size_t slength; + int i; + + png_debug(1, "in png_handle_pCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + { + png_warning(png_ptr, "Duplicate pCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)", + length + 1); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "No memory for pCAL purpose."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string"); + for (buf = png_ptr->chunkdata; *buf; buf++) + /* Empty loop */ ; + + endptr = png_ptr->chunkdata + slength; + + /* We need to have at least 12 bytes after the purpose string + in order to get the parameter information. */ + if (endptr <= buf + 12) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters"); + /* Check that we have the right number of parameters for known + equation types. */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_warning(png_ptr, "Invalid pCAL parameters for equation type"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + else if (type >= PNG_EQUATION_LAST) + { + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array"); + params = (png_charpp)png_malloc_warn(png_ptr, + (png_uint_32)(nparams * png_sizeof(png_charp))) ; + if (params == NULL) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "No memory for pCAL params."); + return; + } + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < (int)nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d", i); + for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, params); + return; + } + } + + png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, + units, params); + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, params); +} +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +/* Read the sCAL chunk */ +void /* PRIVATE */ +png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp ep; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double width, height; + png_charp vp; +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp swidth, sheight; +#endif +#endif + png_size_t slength; + + png_debug(1, "in png_handle_sCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + { + png_warning(png_ptr, "Duplicate sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + /* Need unit type, width, \0, height: minimum 4 bytes */ + else if (length < 4) + { + png_warning(png_ptr, "sCAL chunk too short"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)", + length + 1); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + + ep = png_ptr->chunkdata + 1; /* Skip unit byte */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + width = png_strtod(png_ptr, ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed width string in sCAL chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); + if (swidth == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + png_memcpy(swidth, ep, (png_size_t)png_strlen(ep) + 1); +#endif +#endif + + for (ep = png_ptr->chunkdata + 1; *ep; ep++) + /* Empty loop */ ; + ep++; + + if (png_ptr->chunkdata + slength < ep) + { + png_warning(png_ptr, "Truncated sCAL chunk"); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); +#endif + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + +#ifdef PNG_FLOATING_POINT_SUPPORTED + height = png_strtod(png_ptr, ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed height string in sCAL chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); +#endif + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); + if (sheight == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); +#endif + return; + } + png_memcpy(sheight, ep, (png_size_t)png_strlen(ep) + 1); +#endif +#endif + + if (png_ptr->chunkdata + slength < ep +#ifdef PNG_FLOATING_POINT_SUPPORTED + || width <= 0. || height <= 0. +#endif + ) + { + png_warning(png_ptr, "Invalid sCAL data"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif + return; + } + + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight); +#endif +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif +} +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +void /* PRIVATE */ +png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Out of place tIME chunk"); + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + { + png_warning(png_ptr, "Duplicate tIME chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 7) + { + png_warning(png_ptr, "Incorrect tIME chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 7); + if (png_crc_finish(png_ptr, 0)) + return; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); +} +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +/* Note: this does not properly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + png_size_t slength; + int ret; + + png_debug(1, "in png_handle_tEXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for tEXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tEXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "No memory to process text chunk."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + key = png_ptr->chunkdata; + + key[slength] = 0x00; + + for (text = key; *text; text++) + /* Empty loop to find end of key */ ; + + if (text != key + slength) + text++; + + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process text chunk."); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = text; + text_ptr->text_length = png_strlen(text); + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, text_ptr); + if (ret) + png_warning(png_ptr, "Insufficient memory to process text chunk."); +} +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp text; + int comp_type; + int ret; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_zTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for zTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before zTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "zTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "Out of memory processing zTXt chunk."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (text = png_ptr->chunkdata; *text; text++) + /* Empty loop */ ; + + /* zTXt must have some text after the chunkdataword */ + if (text >= png_ptr->chunkdata + slength - 2) + { + png_warning(png_ptr, "Truncated zTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + else + { + comp_type = *(++text); + if (comp_type != PNG_TEXT_COMPRESSION_zTXt) + { + png_warning(png_ptr, "Unknown compression type in zTXt chunk"); + comp_type = PNG_TEXT_COMPRESSION_zTXt; + } + text++; /* Skip the compression_method byte */ + } + prefix_len = text - png_ptr->chunkdata; + + png_decompress_chunk(png_ptr, comp_type, + (png_size_t)length, prefix_len, &data_len); + + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process zTXt chunk."); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + text_ptr->compression = comp_type; + text_ptr->key = png_ptr->chunkdata; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = png_ptr->chunkdata + prefix_len; + text_ptr->text_length = data_len; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + if (ret) + png_error(png_ptr, "Insufficient memory to store zTXt chunk."); +} +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp key, lang, text, lang_key; + int comp_flag; + int comp_type = 0; + int ret; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_iTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for iTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "iTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "No memory to process iTXt chunk."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (lang = png_ptr->chunkdata; *lang; lang++) + /* Empty loop */ ; + lang++; /* Skip NUL separator */ + + /* iTXt must have a language tag (possibly empty), two compression bytes, + * translated keyword (possibly empty), and possibly some text after the + * keyword + */ + + if (lang >= png_ptr->chunkdata + slength - 3) + { + png_warning(png_ptr, "Truncated iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + else + { + comp_flag = *lang++; + comp_type = *lang++; + } + + for (lang_key = lang; *lang_key; lang_key++) + /* Empty loop */ ; + lang_key++; /* Skip NUL separator */ + + if (lang_key >= png_ptr->chunkdata + slength) + { + png_warning(png_ptr, "Truncated iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + for (text = lang_key; *text; text++) + /* Empty loop */ ; + text++; /* Skip NUL separator */ + if (text >= png_ptr->chunkdata + slength) + { + png_warning(png_ptr, "Malformed iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + prefix_len = text - png_ptr->chunkdata; + + key=png_ptr->chunkdata; + if (comp_flag) + png_decompress_chunk(png_ptr, comp_type, + (size_t)length, prefix_len, &data_len); + else + data_len = png_strlen(png_ptr->chunkdata + prefix_len); + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process iTXt chunk."); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + text_ptr->compression = (int)comp_flag + 1; + text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); + text_ptr->lang = png_ptr->chunkdata + (lang - key); + text_ptr->itxt_length = data_len; + text_ptr->text_length = 0; + text_ptr->key = png_ptr->chunkdata; + text_ptr->text = png_ptr->chunkdata + prefix_len; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + if (ret) + png_error(png_ptr, "Insufficient memory to store iTXt chunk."); +} +#endif + +/* This function is called when we haven't found a handler for a + chunk. If there isn't a problem with the chunk itself (ie bad + chunk name, CRC, or a critical chunk), the chunk is silently ignored + -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which + case it will be saved away to be written out later. */ +void /* PRIVATE */ +png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_unknown"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for unknown chunk"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (png_ptr->mode & PNG_HAVE_IDAT) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST PNG_IDAT; +#endif + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ + png_ptr->mode |= PNG_AFTER_IDAT; + } + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + } + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + || (png_ptr->read_user_chunk_fn != NULL) +#endif + ) + { +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + png_memcpy((png_charp)png_ptr->unknown_chunk.name, + (png_charp)png_ptr->chunk_name, + png_sizeof(png_ptr->unknown_chunk.name)); + png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] + = '\0'; + png_ptr->unknown_chunk.size = (png_size_t)length; + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + else + { + png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); + } +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + if (png_ptr->read_user_chunk_fn != NULL) + { + /* Callback to user unknown chunk handler */ + int ret; + ret = (*(png_ptr->read_user_chunk_fn)) + (png_ptr, &png_ptr->unknown_chunk); + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + if (ret == 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + } + } + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + else +#endif + skip = length; + + png_crc_finish(png_ptr, skip); + +#ifndef PNG_READ_USER_CHUNKS_SUPPORTED + PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ +#endif +} + +/* This function is called to verify that a chunk name is valid. + This function can't have the "critical chunk check" incorporated + into it, since in the future we will need to be able to call user + functions to handle unknown critical chunks after we check that + the chunk name itself is valid. */ + +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) + +void /* PRIVATE */ +png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) +{ + png_debug(1, "in png_check_chunk_name"); + if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || + isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) + { + png_chunk_error(png_ptr, "invalid chunk type"); + } +} + +/* Combines the row recently read in with the existing pixels in the + row. This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined, + a zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. If + you want all pixels to be combined, pass 0xff (255) in mask. */ + +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1, "in png_combine_row"); + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); + } + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_inc, s_start, s_end; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x01; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 2: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x03; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 4: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + default: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + png_byte m = 0x80; + + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + png_memcpy(dp, sp, pixel_bytes); + } + + sp += pixel_bytes; + dp += pixel_bytes; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + } + } +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* OLD pre-1.0.9 interface: +void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations) + */ +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; + png_uint_32 transformations = png_ptr->transformations; + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* Offset to next interlace block */ + PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_read_interlace"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_uint_32 i; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 4: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + int jstop = png_pass_inc[pass]; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0xf); + int j; + + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + default: + { + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); + png_bytep sp = row + (png_size_t)(row_info->width - 1) + * pixel_bytes; + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; + + int jstop = png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; + int j; + + png_memcpy(v, sp, pixel_bytes); + for (j = 0; j < jstop; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sp -= pixel_bytes; + } + break; + } + } + row_info->width = final_width; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); + } +#ifndef PNG_READ_PACKSWAP_SUPPORTED + PNG_UNUSED(transformations) /* Silence compiler warning */ +#endif +} +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, + png_bytep prev_row, int filter) +{ + png_debug(1, "in png_read_filter_row"); + png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter); + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + case PNG_FILTER_VALUE_SUB: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_UP: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_AVG: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *lp++) / 2 ) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_PAETH: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) /* Use leftover rp,pp */ + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + break; + } + default: + png_warning(png_ptr, "Ignoring bad adaptive filter type"); + *row = 0; + break; + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void /* PRIVATE */ +png_read_finish_row(png_structp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + png_debug(1, "in png_read_finish_row"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset_check(png_ptr, png_ptr->prev_row, 0, + png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (!(png_ptr->num_rows)) + continue; + } + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; + } while (png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_CONST PNG_IDAT; +#endif + char extra; + int ret; + + png_ptr->zstream.next_out = (Byte *)&extra; + png_ptr->zstream.avail_out = (uInt)1; + for (;;) + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_byte chunk_length[4]; + + png_crc_finish(png_ptr, 0); + + png_read_data(png_ptr, chunk_length, 4); + png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_warning(png_ptr, "Extra compressed data."); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression Error"); + + if (!(png_ptr->zstream.avail_out)) + { + png_warning(png_ptr, "Extra compressed data."); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + + } + png_ptr->zstream.avail_out = 0; + } + + if (png_ptr->idat_size || png_ptr->zstream.avail_in) + png_warning(png_ptr, "Extra compression data."); + + inflateReset(&png_ptr->zstream); + + png_ptr->mode |= PNG_AFTER_IDAT; +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +void /* PRIVATE */ +png_read_start_row(png_structp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int max_pixel_depth; + png_size_t row_bytes; + + png_debug(1, "in png_read_start_row"); + png_ptr->zstream.avail_in = 0; + png_init_read_transformations(png_ptr); +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + } + else +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + } + max_pixel_depth = png_ptr->pixel_depth; + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + if (png_ptr->num_trans) + max_pixel_depth *= 2; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & (PNG_FILLER)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + max_pixel_depth = 32; + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + else + max_pixel_depth = 32; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + } +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if ( +#ifdef PNG_READ_EXPAND_SUPPORTED + (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || +#endif +#ifdef PNG_READ_FILLER_SUPPORTED + (png_ptr->transformations & (PNG_FILLER)) || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + int user_pixel_depth = png_ptr->user_transform_depth* + png_ptr->user_transform_channels; + if (user_pixel_depth > max_pixel_depth) + max_pixel_depth=user_pixel_depth; + } +#endif + + /* Align the width on the next larger 8 pixels. Mainly used + * for interlacing + */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* Calculate the maximum bytes needed, adding a byte and a pixel + * for safety's sake + */ + row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + + 1 + ((max_pixel_depth + 7) >> 3); +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + + if (row_bytes + 64 > png_ptr->old_big_row_buf_size) + { + png_free(png_ptr, png_ptr->big_row_buf); + if (png_ptr->interlaced) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 64); + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, + row_bytes + 64); + png_ptr->old_big_row_buf_size = row_bytes + 64; + + /* Use 32 bytes of padding before and after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 32; + png_ptr->old_big_row_buf_size = row_bytes + 64; + } + +#ifdef PNG_MAX_MALLOC_64K + if ((png_uint_32)row_bytes + 1 > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + if ((png_uint_32)row_bytes > (png_uint_32)(PNG_SIZE_MAX - 1)) + png_error(png_ptr, "Row has too many bytes to allocate in memory."); + + if (row_bytes + 1 > png_ptr->old_prev_row_size) + { + png_free(png_ptr, png_ptr->prev_row); + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( + row_bytes + 1)); + png_memset_check(png_ptr, png_ptr->prev_row, 0, row_bytes + 1); + png_ptr->old_prev_row_size = row_bytes + 1; + } + + png_ptr->rowbytes = row_bytes; + + png_debug1(3, "width = %lu,", png_ptr->width); + png_debug1(3, "height = %lu,", png_ptr->height); + png_debug1(3, "iwidth = %lu,", png_ptr->iwidth); + png_debug1(3, "num_rows = %lu,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} +#endif /* PNG_READ_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngset.c b/main/source/includes/lpng1251/pngset.c index fc28311b..fed6a55b 100644 --- a/main/source/includes/lpng1251/pngset.c +++ b/main/source/includes/lpng1251/pngset.c @@ -1,1241 +1,1241 @@ - -/* pngset.c - storage of image information into info struct - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * The functions here are used during reads to store data from the file - * into the info struct, and during writes to store application data - * into the info struct for writing into the file. This abstracts the - * info struct and allows us to change the structure in the future. - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -#ifdef PNG_bKGD_SUPPORTED -void PNGAPI -png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) -{ - png_debug1(1, "in %s storage function", "bKGD"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); - info_ptr->valid |= PNG_INFO_bKGD; -} -#endif - -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_cHRM(png_structp png_ptr, png_infop info_ptr, - double white_x, double white_y, double red_x, double red_y, - double green_x, double green_y, double blue_x, double blue_y) -{ - png_debug1(1, "in %s storage function", "cHRM"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->x_white = (float)white_x; - info_ptr->y_white = (float)white_y; - info_ptr->x_red = (float)red_x; - info_ptr->y_red = (float)red_y; - info_ptr->x_green = (float)green_x; - info_ptr->y_green = (float)green_y; - info_ptr->x_blue = (float)blue_x; - info_ptr->y_blue = (float)blue_y; -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5); - info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5); - info_ptr->int_x_red = (png_fixed_point)( red_x*100000.+0.5); - info_ptr->int_y_red = (png_fixed_point)( red_y*100000.+0.5); - info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5); - info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5); - info_ptr->int_x_blue = (png_fixed_point)( blue_x*100000.+0.5); - info_ptr->int_y_blue = (png_fixed_point)( blue_y*100000.+0.5); -#endif - info_ptr->valid |= PNG_INFO_cHRM; -} -#endif /* PNG_FLOATING_POINT_SUPPORTED */ - -#ifdef PNG_FIXED_POINT_SUPPORTED -void PNGAPI -png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, - png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, - png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, - png_fixed_point blue_x, png_fixed_point blue_y) -{ - png_debug1(1, "in %s storage function", "cHRM fixed"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y)) -#endif - { - info_ptr->int_x_white = white_x; - info_ptr->int_y_white = white_y; - info_ptr->int_x_red = red_x; - info_ptr->int_y_red = red_y; - info_ptr->int_x_green = green_x; - info_ptr->int_y_green = green_y; - info_ptr->int_x_blue = blue_x; - info_ptr->int_y_blue = blue_y; -#ifdef PNG_FLOATING_POINT_SUPPORTED - info_ptr->x_white = (float)(white_x/100000.); - info_ptr->y_white = (float)(white_y/100000.); - info_ptr->x_red = (float)( red_x/100000.); - info_ptr->y_red = (float)( red_y/100000.); - info_ptr->x_green = (float)(green_x/100000.); - info_ptr->y_green = (float)(green_y/100000.); - info_ptr->x_blue = (float)( blue_x/100000.); - info_ptr->y_blue = (float)( blue_y/100000.); -#endif - info_ptr->valid |= PNG_INFO_cHRM; - } -} -#endif /* PNG_FIXED_POINT_SUPPORTED */ -#endif /* PNG_cHRM_SUPPORTED */ - -#ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) -{ - double png_gamma; - - png_debug1(1, "in %s storage function", "gAMA"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Check for overflow */ - if (file_gamma > 21474.83) - { - png_warning(png_ptr, "Limiting gamma to 21474.83"); - png_gamma=21474.83; - } - else - png_gamma = file_gamma; - info_ptr->gamma = (float)png_gamma; -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_gamma = (int)(png_gamma*100000.+.5); -#endif - info_ptr->valid |= PNG_INFO_gAMA; - if (png_gamma == 0.0) - png_warning(png_ptr, "Setting gamma=0"); -} -#endif -void PNGAPI -png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point - int_gamma) -{ - png_fixed_point png_gamma; - - png_debug1(1, "in %s storage function", "gAMA"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (int_gamma > (png_fixed_point)PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Limiting gamma to 21474.83"); - png_gamma=PNG_UINT_31_MAX; - } - else - { - if (int_gamma < 0) - { - png_warning(png_ptr, "Setting negative gamma to zero"); - png_gamma = 0; - } - else - png_gamma = int_gamma; - } -#ifdef PNG_FLOATING_POINT_SUPPORTED - info_ptr->gamma = (float)(png_gamma/100000.); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_gamma = png_gamma; -#endif - info_ptr->valid |= PNG_INFO_gAMA; - if (png_gamma == 0) - png_warning(png_ptr, "Setting gamma=0"); -} -#endif - -#ifdef PNG_hIST_SUPPORTED -void PNGAPI -png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) -{ - int i; - - png_debug1(1, "in %s storage function", "hIST"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (info_ptr->num_palette == 0 || info_ptr->num_palette - > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, - "Invalid palette size, hIST allocation skipped."); - return; - } - -#ifdef PNG_FREE_ME_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); -#endif - /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in - * version 1.2.1 - */ - png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, - (png_uint_32)(PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16))); - if (png_ptr->hist == NULL) - { - png_warning(png_ptr, "Insufficient memory for hIST chunk data."); - return; - } - - for (i = 0; i < info_ptr->num_palette; i++) - png_ptr->hist[i] = hist[i]; - info_ptr->hist = png_ptr->hist; - info_ptr->valid |= PNG_INFO_hIST; - -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_HIST; -#else - png_ptr->flags |= PNG_FLAG_FREE_HIST; -#endif -} -#endif - -void PNGAPI -png_set_IHDR(png_structp png_ptr, png_infop info_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type) -{ - png_debug1(1, "in %s storage function", "IHDR"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->width = width; - info_ptr->height = height; - info_ptr->bit_depth = (png_byte)bit_depth; - info_ptr->color_type = (png_byte)color_type; - info_ptr->compression_type = (png_byte)compression_type; - info_ptr->filter_type = (png_byte)filter_type; - info_ptr->interlace_type = (png_byte)interlace_type; - - png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, - info_ptr->compression_type, info_ptr->filter_type); - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) - info_ptr->channels = 3; - else - info_ptr->channels = 1; - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - info_ptr->channels++; - info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - - /* Check for potential overflow */ - if (width > (PNG_UINT_32_MAX - >> 3) /* 8-byte RGBA pixels */ - - 64 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - info_ptr->rowbytes = (png_size_t)0; - else - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); -} - -#ifdef PNG_oFFs_SUPPORTED -void PNGAPI -png_set_oFFs(png_structp png_ptr, png_infop info_ptr, - png_int_32 offset_x, png_int_32 offset_y, int unit_type) -{ - png_debug1(1, "in %s storage function", "oFFs"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->x_offset = offset_x; - info_ptr->y_offset = offset_y; - info_ptr->offset_unit_type = (png_byte)unit_type; - info_ptr->valid |= PNG_INFO_oFFs; -} -#endif - -#ifdef PNG_pCAL_SUPPORTED -void PNGAPI -png_set_pCAL(png_structp png_ptr, png_infop info_ptr, - png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, - png_charp units, png_charpp params) -{ - png_uint_32 length; - int i; - - png_debug1(1, "in %s storage function", "pCAL"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - length = png_strlen(purpose) + 1; - png_debug1(3, "allocating purpose for info (%lu bytes)", - (unsigned long)length); - info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); - if (info_ptr->pcal_purpose == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL purpose."); - return; - } - png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length); - - png_debug(3, "storing X0, X1, type, and nparams in info"); - info_ptr->pcal_X0 = X0; - info_ptr->pcal_X1 = X1; - info_ptr->pcal_type = (png_byte)type; - info_ptr->pcal_nparams = (png_byte)nparams; - - length = png_strlen(units) + 1; - png_debug1(3, "allocating units for info (%lu bytes)", - (unsigned long)length); - info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); - if (info_ptr->pcal_units == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL units."); - return; - } - png_memcpy(info_ptr->pcal_units, units, (png_size_t)length); - - info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, - (png_uint_32)((nparams + 1) * png_sizeof(png_charp))); - if (info_ptr->pcal_params == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL params."); - return; - } - - png_memset(info_ptr->pcal_params, 0, (nparams + 1) * png_sizeof(png_charp)); - - for (i = 0; i < nparams; i++) - { - length = png_strlen(params[i]) + 1; - png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, - (unsigned long)length); - info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); - if (info_ptr->pcal_params[i] == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL parameter."); - return; - } - png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length); - } - - info_ptr->valid |= PNG_INFO_pCAL; -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_PCAL; -#endif -} -#endif - -#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_sCAL(png_structp png_ptr, png_infop info_ptr, - int unit, double width, double height) -{ - png_debug1(1, "in %s storage function", "sCAL"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->scal_unit = (png_byte)unit; - info_ptr->scal_pixel_width = width; - info_ptr->scal_pixel_height = height; - - info_ptr->valid |= PNG_INFO_sCAL; -} -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -void PNGAPI -png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, - int unit, png_charp swidth, png_charp sheight) -{ - png_uint_32 length; - - png_debug1(1, "in %s storage function", "sCAL"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->scal_unit = (png_byte)unit; - - length = png_strlen(swidth) + 1; - png_debug1(3, "allocating unit for info (%u bytes)", - (unsigned int)length); - info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length); - if (info_ptr->scal_s_width == NULL) - { - png_warning(png_ptr, - "Memory allocation failed while processing sCAL."); - return; - } - png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length); - - length = png_strlen(sheight) + 1; - png_debug1(3, "allocating unit for info (%u bytes)", - (unsigned int)length); - info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length); - if (info_ptr->scal_s_height == NULL) - { - png_free (png_ptr, info_ptr->scal_s_width); - info_ptr->scal_s_width = NULL; - png_warning(png_ptr, - "Memory allocation failed while processing sCAL."); - return; - } - png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length); - info_ptr->valid |= PNG_INFO_sCAL; -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_SCAL; -#endif -} -#endif -#endif -#endif - -#ifdef PNG_pHYs_SUPPORTED -void PNGAPI -png_set_pHYs(png_structp png_ptr, png_infop info_ptr, - png_uint_32 res_x, png_uint_32 res_y, int unit_type) -{ - png_debug1(1, "in %s storage function", "pHYs"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->x_pixels_per_unit = res_x; - info_ptr->y_pixels_per_unit = res_y; - info_ptr->phys_unit_type = (png_byte)unit_type; - info_ptr->valid |= PNG_INFO_pHYs; -} -#endif - -void PNGAPI -png_set_PLTE(png_structp png_ptr, png_infop info_ptr, - png_colorp palette, int num_palette) -{ - - png_debug1(1, "in %s storage function", "PLTE"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) - { - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - png_error(png_ptr, "Invalid palette length"); - else - { - png_warning(png_ptr, "Invalid palette length"); - return; - } - } - - /* It may not actually be necessary to set png_ptr->palette here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - */ -#ifdef PNG_FREE_ME_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); -#endif - - /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead - * of num_palette entries, in case of an invalid PNG file that has - * too-large sample values. - */ - png_ptr->palette = (png_colorp)png_calloc(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); - png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); - info_ptr->palette = png_ptr->palette; - info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; - -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_PLTE; -#else - png_ptr->flags |= PNG_FLAG_FREE_PLTE; -#endif - - info_ptr->valid |= PNG_INFO_PLTE; -} - -#ifdef PNG_sBIT_SUPPORTED -void PNGAPI -png_set_sBIT(png_structp png_ptr, png_infop info_ptr, - png_color_8p sig_bit) -{ - png_debug1(1, "in %s storage function", "sBIT"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof(png_color_8)); - info_ptr->valid |= PNG_INFO_sBIT; -} -#endif - -#ifdef PNG_sRGB_SUPPORTED -void PNGAPI -png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) -{ - png_debug1(1, "in %s storage function", "sRGB"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->srgb_intent = (png_byte)intent; - info_ptr->valid |= PNG_INFO_sRGB; -} - -void PNGAPI -png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, - int intent) -{ -#ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED - float file_gamma; -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_fixed_point int_file_gamma; -#endif -#endif -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED - float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, - int_green_y, int_blue_x, int_blue_y; -#endif -#endif - png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_set_sRGB(png_ptr, info_ptr, intent); - -#ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED - file_gamma = (float).45455; - png_set_gAMA(png_ptr, info_ptr, file_gamma); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - int_file_gamma = 45455L; - png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); -#endif -#endif - -#ifdef PNG_cHRM_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED - int_white_x = 31270L; - int_white_y = 32900L; - int_red_x = 64000L; - int_red_y = 33000L; - int_green_x = 30000L; - int_green_y = 60000L; - int_blue_x = 15000L; - int_blue_y = 6000L; - png_set_cHRM_fixed(png_ptr, info_ptr, - int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, - int_green_y, int_blue_x, int_blue_y); -# endif - -# ifdef PNG_FLOATING_POINT_SUPPORTED - white_x = (float).3127; - white_y = (float).3290; - red_x = (float).64; - red_y = (float).33; - green_x = (float).30; - green_y = (float).60; - blue_x = (float).15; - blue_y = (float).06; - png_set_cHRM(png_ptr, info_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); -# endif -#endif /* cHRM */ -} -#endif /* sRGB */ - - -#ifdef PNG_iCCP_SUPPORTED -void PNGAPI -png_set_iCCP(png_structp png_ptr, png_infop info_ptr, - png_charp name, int compression_type, - png_charp profile, png_uint_32 proflen) -{ - png_charp new_iccp_name; - png_charp new_iccp_profile; - png_uint_32 length; - - png_debug1(1, "in %s storage function", "iCCP"); - - if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) - return; - - length = png_strlen(name)+1; - new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length); - if (new_iccp_name == NULL) - { - png_warning(png_ptr, "Insufficient memory to process iCCP chunk."); - return; - } - png_memcpy(new_iccp_name, name, length); - new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen); - if (new_iccp_profile == NULL) - { - png_free (png_ptr, new_iccp_name); - png_warning(png_ptr, - "Insufficient memory to process iCCP profile."); - return; - } - png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); - - png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); - - info_ptr->iccp_proflen = proflen; - info_ptr->iccp_name = new_iccp_name; - info_ptr->iccp_profile = new_iccp_profile; - /* Compression is always zero but is here so the API and info structure - * does not have to change if we introduce multiple compression types - */ - info_ptr->iccp_compression = (png_byte)compression_type; -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_ICCP; -#endif - info_ptr->valid |= PNG_INFO_iCCP; -} -#endif - -#ifdef PNG_TEXT_SUPPORTED -void PNGAPI -png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, - int num_text) -{ - int ret; - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); - if (ret) - png_error(png_ptr, "Insufficient memory to store text"); -} - -int /* PRIVATE */ -png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, - int num_text) -{ - int i; - - png_debug1(1, "in %s storage function", ((png_ptr == NULL || - png_ptr->chunk_name[0] == '\0') ? - "text" : (png_const_charp)png_ptr->chunk_name)); - - if (png_ptr == NULL || info_ptr == NULL || num_text == 0) - return(0); - - /* Make sure we have enough space in the "text" array in info_struct - * to hold all of the incoming text_ptr objects. - */ - if (info_ptr->num_text + num_text > info_ptr->max_text) - { - int old_max_text = info_ptr->max_text; - int old_num_text = info_ptr->num_text; - - if (info_ptr->text != NULL) - { - png_textp old_text; - - info_ptr->max_text = info_ptr->num_text + num_text + 8; - old_text = info_ptr->text; - - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)(info_ptr->max_text * png_sizeof(png_text))); - if (info_ptr->text == NULL) - { - /* Restore to previous condition */ - info_ptr->max_text = old_max_text; - info_ptr->text = old_text; - return(1); - } - png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max_text * - png_sizeof(png_text))); - png_free(png_ptr, old_text); - } - else - { - info_ptr->max_text = num_text + 8; - info_ptr->num_text = 0; - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)(info_ptr->max_text * png_sizeof(png_text))); - if (info_ptr->text == NULL) - { - /* Restore to previous condition */ - info_ptr->num_text = old_num_text; - info_ptr->max_text = old_max_text; - return(1); - } -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_TEXT; -#endif - } - png_debug1(3, "allocated %d entries for info_ptr->text", - info_ptr->max_text); - } - - for (i = 0; i < num_text; i++) - { - png_size_t text_length, key_len; - png_size_t lang_len, lang_key_len; - png_textp textp = &(info_ptr->text[info_ptr->num_text]); - - if (text_ptr[i].key == NULL) - continue; - - key_len = png_strlen(text_ptr[i].key); - - if (text_ptr[i].compression <= 0) - { - lang_len = 0; - lang_key_len = 0; - } - - else -#ifdef PNG_iTXt_SUPPORTED - { - /* Set iTXt data */ - - if (text_ptr[i].lang != NULL) - lang_len = png_strlen(text_ptr[i].lang); - else - lang_len = 0; - if (text_ptr[i].lang_key != NULL) - lang_key_len = png_strlen(text_ptr[i].lang_key); - else - lang_key_len = 0; - } -#else /* PNG_iTXt_SUPPORTED */ - { - png_warning(png_ptr, "iTXt chunk not supported."); - continue; - } -#endif - - if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') - { - text_length = 0; -#ifdef PNG_iTXt_SUPPORTED - if (text_ptr[i].compression > 0) - textp->compression = PNG_ITXT_COMPRESSION_NONE; - else -#endif - textp->compression = PNG_TEXT_COMPRESSION_NONE; - } - - else - { - text_length = png_strlen(text_ptr[i].text); - textp->compression = text_ptr[i].compression; - } - - textp->key = (png_charp)png_malloc_warn(png_ptr, - (png_uint_32) - (key_len + text_length + lang_len + lang_key_len + 4)); - if (textp->key == NULL) - return(1); - png_debug2(2, "Allocated %lu bytes at %x in png_set_text", - (png_uint_32) - (key_len + lang_len + lang_key_len + text_length + 4), - (int)textp->key); - - png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len)); - *(textp->key + key_len) = '\0'; -#ifdef PNG_iTXt_SUPPORTED - if (text_ptr[i].compression > 0) - { - textp->lang = textp->key + key_len + 1; - png_memcpy(textp->lang, text_ptr[i].lang, lang_len); - *(textp->lang + lang_len) = '\0'; - textp->lang_key = textp->lang + lang_len + 1; - png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); - *(textp->lang_key + lang_key_len) = '\0'; - textp->text = textp->lang_key + lang_key_len + 1; - } - else -#endif - { -#ifdef PNG_iTXt_SUPPORTED - textp->lang=NULL; - textp->lang_key=NULL; -#endif - textp->text = textp->key + key_len + 1; - } - if (text_length) - png_memcpy(textp->text, text_ptr[i].text, - (png_size_t)(text_length)); - *(textp->text + text_length) = '\0'; - -#ifdef PNG_iTXt_SUPPORTED - if (textp->compression > 0) - { - textp->text_length = 0; - textp->itxt_length = text_length; - } - else -#endif - - { - textp->text_length = text_length; -#ifdef PNG_iTXt_SUPPORTED - textp->itxt_length = 0; -#endif - } - info_ptr->num_text++; - png_debug1(3, "transferred text chunk %d", info_ptr->num_text); - } - return(0); -} -#endif - -#ifdef PNG_tIME_SUPPORTED -void PNGAPI -png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) -{ - png_debug1(1, "in %s storage function", "tIME"); - - if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_tIME)) - return; - - png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof(png_time)); - info_ptr->valid |= PNG_INFO_tIME; -} -#endif - -#ifdef PNG_tRNS_SUPPORTED -void PNGAPI -png_set_tRNS(png_structp png_ptr, png_infop info_ptr, - png_bytep trans, int num_trans, png_color_16p trans_values) -{ - png_debug1(1, "in %s storage function", "tRNS"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (num_trans < 0 || num_trans > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, "Ignoring invalid num_trans value"); - return; - } - - if (trans != NULL) - { - /* It may not actually be necessary to set png_ptr->trans here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - */ - -#ifdef PNG_FREE_ME_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); -#endif - - /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ - png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr, - (png_uint_32)PNG_MAX_PALETTE_LENGTH); - if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) - png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans); - } - - if (trans_values != NULL) - { - int sample_max = (1 << info_ptr->bit_depth); - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_values->gray > sample_max) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_values->red > sample_max || - (int)trans_values->green > sample_max || - (int)trans_values->blue > sample_max))) - png_warning(png_ptr, - "tRNS chunk has out-of-range samples for bit_depth"); - png_memcpy(&(info_ptr->trans_values), trans_values, - png_sizeof(png_color_16)); - if (num_trans == 0) - num_trans = 1; - } - - info_ptr->num_trans = (png_uint_16)num_trans; - if (num_trans != 0) - { - info_ptr->valid |= PNG_INFO_tRNS; -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_TRNS; -#else - png_ptr->flags |= PNG_FLAG_FREE_TRNS; -#endif - } -} -#endif - -#ifdef PNG_sPLT_SUPPORTED -void PNGAPI -png_set_sPLT(png_structp png_ptr, - png_infop info_ptr, png_sPLT_tp entries, int nentries) -/* - * entries - array of png_sPLT_t structures - * to be added to the list of palettes - * in the info structure. - * nentries - number of palette structures to be - * added. - */ -{ - png_sPLT_tp np; - int i; - - if (png_ptr == NULL || info_ptr == NULL) - return; - - np = (png_sPLT_tp)png_malloc_warn(png_ptr, - (info_ptr->splt_palettes_num + nentries) * - (png_uint_32)png_sizeof(png_sPLT_t)); - if (np == NULL) - { - png_warning(png_ptr, "No memory for sPLT palettes."); - return; - } - - png_memcpy(np, info_ptr->splt_palettes, - info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes=NULL; - - for (i = 0; i < nentries; i++) - { - png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; - png_sPLT_tp from = entries + i; - png_uint_32 length; - - length = png_strlen(from->name) + 1; - to->name = (png_charp)png_malloc_warn(png_ptr, length); - if (to->name == NULL) - { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); - continue; - } - png_memcpy(to->name, from->name, length); - to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, - (png_uint_32)(from->nentries * png_sizeof(png_sPLT_entry))); - if (to->entries == NULL) - { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); - png_free(png_ptr, to->name); - to->name = NULL; - continue; - } - png_memcpy(to->entries, from->entries, - from->nentries * png_sizeof(png_sPLT_entry)); - to->nentries = from->nentries; - to->depth = from->depth; - } - - info_ptr->splt_palettes = np; - info_ptr->splt_palettes_num += nentries; - info_ptr->valid |= PNG_INFO_sPLT; -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_SPLT; -#endif -} -#endif /* PNG_sPLT_SUPPORTED */ - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -void PNGAPI -png_set_unknown_chunks(png_structp png_ptr, - png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns) -{ - png_unknown_chunkp np; - int i; - - if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) - return; - - np = (png_unknown_chunkp)png_malloc_warn(png_ptr, - (png_uint_32)((info_ptr->unknown_chunks_num + num_unknowns) * - png_sizeof(png_unknown_chunk))); - if (np == NULL) - { - png_warning(png_ptr, - "Out of memory while processing unknown chunk."); - return; - } - - png_memcpy(np, info_ptr->unknown_chunks, - info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk)); - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - - for (i = 0; i < num_unknowns; i++) - { - png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; - png_unknown_chunkp from = unknowns + i; - - png_memcpy((png_charp)to->name, (png_charp)from->name, - png_sizeof(from->name)); - to->name[png_sizeof(to->name)-1] = '\0'; - to->size = from->size; - /* Note our location in the read or write sequence */ - to->location = (png_byte)(png_ptr->mode & 0xff); - - if (from->size == 0) - to->data=NULL; - else - { - to->data = (png_bytep)png_malloc_warn(png_ptr, - (png_uint_32)from->size); - if (to->data == NULL) - { - png_warning(png_ptr, - "Out of memory while processing unknown chunk."); - to->size = 0; - } - else - png_memcpy(to->data, from->data, from->size); - } - } - - info_ptr->unknown_chunks = np; - info_ptr->unknown_chunks_num += num_unknowns; -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_UNKN; -#endif -} -void PNGAPI -png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, - int chunk, int location) -{ - if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < - (int)info_ptr->unknown_chunks_num) - info_ptr->unknown_chunks[chunk].location = (png_byte)location; -} -#endif - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ - defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) -void PNGAPI -png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted) -{ - /* This function is deprecated in favor of png_permit_mng_features() - and will be removed from libpng-1.3.0 */ - - png_debug(1, "in png_permit_empty_plte, DEPRECATED."); - - if (png_ptr == NULL) - return; - png_ptr->mng_features_permitted = (png_byte) - ((png_ptr->mng_features_permitted & (~PNG_FLAG_MNG_EMPTY_PLTE)) | - ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE))); -} -#endif -#endif - -#ifdef PNG_MNG_FEATURES_SUPPORTED -png_uint_32 PNGAPI -png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) -{ - png_debug(1, "in png_permit_mng_features"); - - if (png_ptr == NULL) - return (png_uint_32)0; - png_ptr->mng_features_permitted = - (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); - return (png_uint_32)png_ptr->mng_features_permitted; -} -#endif - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -void PNGAPI -png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep - chunk_list, int num_chunks) -{ - png_bytep new_list, p; - int i, old_num_chunks; - if (png_ptr == NULL) - return; - if (num_chunks == 0) - { - if (keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) - png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; - - if (keep == PNG_HANDLE_CHUNK_ALWAYS) - png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; - return; - } - if (chunk_list == NULL) - return; - old_num_chunks = png_ptr->num_chunk_list; - new_list=(png_bytep)png_malloc(png_ptr, - (png_uint_32) - (5*(num_chunks + old_num_chunks))); - if (png_ptr->chunk_list != NULL) - { - png_memcpy(new_list, png_ptr->chunk_list, - (png_size_t)(5*old_num_chunks)); - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list=NULL; - } - png_memcpy(new_list + 5*old_num_chunks, chunk_list, - (png_size_t)(5*num_chunks)); - for (p = new_list + 5*old_num_chunks + 4, i = 0; inum_chunk_list = old_num_chunks + num_chunks; - png_ptr->chunk_list = new_list; -#ifdef PNG_FREE_ME_SUPPORTED - png_ptr->free_me |= PNG_FREE_LIST; -#endif -} -#endif - -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED -void PNGAPI -png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, - png_user_chunk_ptr read_user_chunk_fn) -{ - png_debug(1, "in png_set_read_user_chunk_fn"); - - if (png_ptr == NULL) - return; - - png_ptr->read_user_chunk_fn = read_user_chunk_fn; - png_ptr->user_chunk_ptr = user_chunk_ptr; -} -#endif - -#ifdef PNG_INFO_IMAGE_SUPPORTED -void PNGAPI -png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) -{ - png_debug1(1, "in %s storage function", "rows"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) - png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); - info_ptr->row_pointers = row_pointers; - if (row_pointers) - info_ptr->valid |= PNG_INFO_IDAT; -} -#endif - -void PNGAPI -png_set_compression_buffer_size(png_structp png_ptr, - png_uint_32 size) -{ - if (png_ptr == NULL) - return; - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf_size = (png_size_t)size; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; -} - -void PNGAPI -png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) -{ - if (png_ptr && info_ptr) - info_ptr->valid &= ~mask; -} - - -#ifndef PNG_1_0_X -#ifdef PNG_ASSEMBLER_CODE_SUPPORTED -/* Function was added to libpng 1.2.0 and should always exist by default */ -void PNGAPI -png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags) -{ -/* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */ - if (png_ptr != NULL) - png_ptr->asm_flags = 0; - PNG_UNUSED(asm_flags) /* Quiet the compiler */ -} - -/* This function was added to libpng 1.2.0 */ -void PNGAPI -png_set_mmx_thresholds (png_structp png_ptr, - png_byte mmx_bitdepth_threshold, - png_uint_32 mmx_rowbytes_threshold) -{ -/* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */ - if (png_ptr == NULL) - return; - /* Quiet the compiler */ - PNG_UNUSED(mmx_bitdepth_threshold) - PNG_UNUSED(mmx_rowbytes_threshold) -} -#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -/* This function was added to libpng 1.2.6 */ -void PNGAPI -png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, - png_uint_32 user_height_max) -{ - /* Images with dimensions larger than these limits will be - * rejected by png_set_IHDR(). To accept any PNG datastream - * regardless of dimensions, set both limits to 0x7ffffffL. - */ - if (png_ptr == NULL) - return; - png_ptr->user_width_max = user_width_max; - png_ptr->user_height_max = user_height_max; -} -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ - - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_set_benign_errors(png_structp png_ptr, int allowed) -{ - png_debug(1, "in png_set_benign_errors"); - - if (allowed) - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; - else - png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; -} -#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ -#endif /* ?PNG_1_0_X */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +/* pngset.c - storage of image information into info struct + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#ifdef PNG_bKGD_SUPPORTED +void PNGAPI +png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) +{ + png_debug1(1, "in %s storage function", "bKGD"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_structp png_ptr, png_infop info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_debug1(1, "in %s storage function", "cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_white = (float)white_x; + info_ptr->y_white = (float)white_y; + info_ptr->x_red = (float)red_x; + info_ptr->y_red = (float)red_y; + info_ptr->x_green = (float)green_x; + info_ptr->y_green = (float)green_y; + info_ptr->x_blue = (float)blue_x; + info_ptr->y_blue = (float)blue_y; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5); + info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5); + info_ptr->int_x_red = (png_fixed_point)( red_x*100000.+0.5); + info_ptr->int_y_red = (png_fixed_point)( red_y*100000.+0.5); + info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5); + info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5); + info_ptr->int_x_blue = (png_fixed_point)( blue_x*100000.+0.5); + info_ptr->int_y_blue = (png_fixed_point)( blue_y*100000.+0.5); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif /* PNG_FLOATING_POINT_SUPPORTED */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_debug1(1, "in %s storage function", "cHRM fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_CHECK_cHRM_SUPPORTED + if (png_check_cHRM_fixed(png_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y)) +#endif + { + info_ptr->int_x_white = white_x; + info_ptr->int_y_white = white_y; + info_ptr->int_x_red = red_x; + info_ptr->int_y_red = red_y; + info_ptr->int_x_green = green_x; + info_ptr->int_y_green = green_y; + info_ptr->int_x_blue = blue_x; + info_ptr->int_y_blue = blue_y; +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->x_white = (float)(white_x/100000.); + info_ptr->y_white = (float)(white_y/100000.); + info_ptr->x_red = (float)( red_x/100000.); + info_ptr->y_red = (float)( red_y/100000.); + info_ptr->x_green = (float)(green_x/100000.); + info_ptr->y_green = (float)(green_y/100000.); + info_ptr->x_blue = (float)( blue_x/100000.); + info_ptr->y_blue = (float)( blue_y/100000.); +#endif + info_ptr->valid |= PNG_INFO_cHRM; + } +} +#endif /* PNG_FIXED_POINT_SUPPORTED */ +#endif /* PNG_cHRM_SUPPORTED */ + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +{ + double png_gamma; + + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Check for overflow */ + if (file_gamma > 21474.83) + { + png_warning(png_ptr, "Limiting gamma to 21474.83"); + png_gamma=21474.83; + } + else + png_gamma = file_gamma; + info_ptr->gamma = (float)png_gamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = (int)(png_gamma*100000.+.5); +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if (png_gamma == 0.0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif +void PNGAPI +png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point + int_gamma) +{ + png_fixed_point png_gamma; + + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (int_gamma > (png_fixed_point)PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Limiting gamma to 21474.83"); + png_gamma=PNG_UINT_31_MAX; + } + else + { + if (int_gamma < 0) + { + png_warning(png_ptr, "Setting negative gamma to zero"); + png_gamma = 0; + } + else + png_gamma = int_gamma; + } +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = (float)(png_gamma/100000.); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_gamma; +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if (png_gamma == 0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif + +#ifdef PNG_hIST_SUPPORTED +void PNGAPI +png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function", "hIST"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->num_palette == 0 || info_ptr->num_palette + > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, + "Invalid palette size, hIST allocation skipped."); + return; + } + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); +#endif + /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in + * version 1.2.1 + */ + png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, + (png_uint_32)(PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16))); + if (png_ptr->hist == NULL) + { + png_warning(png_ptr, "Insufficient memory for hIST chunk data."); + return; + } + + for (i = 0; i < info_ptr->num_palette; i++) + png_ptr->hist[i] = hist[i]; + info_ptr->hist = png_ptr->hist; + info_ptr->valid |= PNG_INFO_hIST; + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_HIST; +#else + png_ptr->flags |= PNG_FLAG_FREE_HIST; +#endif +} +#endif + +void PNGAPI +png_set_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + png_debug1(1, "in %s storage function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type = (png_byte)color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + /* Check for potential overflow */ + if (width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + info_ptr->rowbytes = (png_size_t)0; + else + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); +} + +#ifdef PNG_oFFs_SUPPORTED +void PNGAPI +png_set_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "oFFs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +void PNGAPI +png_set_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params) +{ + png_uint_32 length; + int i; + + png_debug1(1, "in %s storage function", "pCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + length = png_strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)", + (unsigned long)length); + info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_purpose == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL purpose."); + return; + } + png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length); + + png_debug(3, "storing X0, X1, type, and nparams in info"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = png_strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)", + (unsigned long)length); + info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_units == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL units."); + return; + } + png_memcpy(info_ptr->pcal_units, units, (png_size_t)length); + + info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, + (png_uint_32)((nparams + 1) * png_sizeof(png_charp))); + if (info_ptr->pcal_params == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL params."); + return; + } + + png_memset(info_ptr->pcal_params, 0, (nparams + 1) * png_sizeof(png_charp)); + + for (i = 0; i < nparams; i++) + { + length = png_strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, + (unsigned long)length); + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_params[i] == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL parameter."); + return; + } + png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length); + } + + info_ptr->valid |= PNG_INFO_pCAL; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_PCAL; +#endif +} +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_structp png_ptr, png_infop info_ptr, + int unit, double width, double height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + info_ptr->scal_pixel_width = width; + info_ptr->scal_pixel_height = height; + + info_ptr->valid |= PNG_INFO_sCAL; +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int unit, png_charp swidth, png_charp sheight) +{ + png_uint_32 length; + + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + + length = png_strlen(swidth) + 1; + png_debug1(3, "allocating unit for info (%u bytes)", + (unsigned int)length); + info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, + "Memory allocation failed while processing sCAL."); + return; + } + png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length); + + length = png_strlen(sheight) + 1; + png_debug1(3, "allocating unit for info (%u bytes)", + (unsigned int)length); + info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_height == NULL) + { + png_free (png_ptr, info_ptr->scal_s_width); + info_ptr->scal_s_width = NULL; + png_warning(png_ptr, + "Memory allocation failed while processing sCAL."); + return; + } + png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length); + info_ptr->valid |= PNG_INFO_sCAL; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_SCAL; +#endif +} +#endif +#endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +void PNGAPI +png_set_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "pHYs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structp png_ptr, png_infop info_ptr, + png_colorp palette, int num_palette) +{ + + png_debug1(1, "in %s storage function", "PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Invalid palette length"); + else + { + png_warning(png_ptr, "Invalid palette length"); + return; + } + } + + /* It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); +#endif + + /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead + * of num_palette entries, in case of an invalid PNG file that has + * too-large sample values. + */ + png_ptr->palette = (png_colorp)png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); + png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_PLTE; +#else + png_ptr->flags |= PNG_FLAG_FREE_PLTE; +#endif + + info_ptr->valid |= PNG_INFO_PLTE; +} + +#ifdef PNG_sBIT_SUPPORTED +void PNGAPI +png_set_sBIT(png_structp png_ptr, png_infop info_ptr, + png_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function", "sBIT"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof(png_color_8)); + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#ifdef PNG_sRGB_SUPPORTED +void PNGAPI +png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) +{ + png_debug1(1, "in %s storage function", "sRGB"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->srgb_intent = (png_byte)intent; + info_ptr->valid |= PNG_INFO_sRGB; +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, + int intent) +{ +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_file_gamma; +#endif +#endif +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y; +#endif +#endif + png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_set_sRGB(png_ptr, info_ptr, intent); + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float).45455; + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + int_file_gamma = 45455L; + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); +#endif +#endif + +#ifdef PNG_cHRM_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED + int_white_x = 31270L; + int_white_y = 32900L; + int_red_x = 64000L; + int_red_y = 33000L; + int_green_x = 30000L; + int_green_y = 60000L; + int_blue_x = 15000L; + int_blue_y = 6000L; + png_set_cHRM_fixed(png_ptr, info_ptr, + int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y); +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float).3127; + white_y = (float).3290; + red_x = (float).64; + red_y = (float).33; + green_x = (float).30; + green_y = (float).60; + blue_x = (float).15; + blue_y = (float).06; + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +# endif +#endif /* cHRM */ +} +#endif /* sRGB */ + + +#ifdef PNG_iCCP_SUPPORTED +void PNGAPI +png_set_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_charp new_iccp_profile; + png_uint_32 length; + + png_debug1(1, "in %s storage function", "iCCP"); + + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + length = png_strlen(name)+1; + new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length); + if (new_iccp_name == NULL) + { + png_warning(png_ptr, "Insufficient memory to process iCCP chunk."); + return; + } + png_memcpy(new_iccp_name, name, length); + new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen); + if (new_iccp_profile == NULL) + { + png_free (png_ptr, new_iccp_name); + png_warning(png_ptr, + "Insufficient memory to process iCCP profile."); + return; + } + png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + /* Compression is always zero but is here so the API and info structure + * does not have to change if we introduce multiple compression types + */ + info_ptr->iccp_compression = (png_byte)compression_type; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_ICCP; +#endif + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +void PNGAPI +png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int ret; + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); + if (ret) + png_error(png_ptr, "Insufficient memory to store text"); +} + +int /* PRIVATE */ +png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int i; + + png_debug1(1, "in %s storage function", ((png_ptr == NULL || + png_ptr->chunk_name[0] == '\0') ? + "text" : (png_const_charp)png_ptr->chunk_name)); + + if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + return(0); + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. + */ + if (info_ptr->num_text + num_text > info_ptr->max_text) + { + int old_max_text = info_ptr->max_text; + int old_num_text = info_ptr->num_text; + + if (info_ptr->text != NULL) + { + png_textp old_text; + + info_ptr->max_text = info_ptr->num_text + num_text + 8; + old_text = info_ptr->text; + + info_ptr->text = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)(info_ptr->max_text * png_sizeof(png_text))); + if (info_ptr->text == NULL) + { + /* Restore to previous condition */ + info_ptr->max_text = old_max_text; + info_ptr->text = old_text; + return(1); + } + png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max_text * + png_sizeof(png_text))); + png_free(png_ptr, old_text); + } + else + { + info_ptr->max_text = num_text + 8; + info_ptr->num_text = 0; + info_ptr->text = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)(info_ptr->max_text * png_sizeof(png_text))); + if (info_ptr->text == NULL) + { + /* Restore to previous condition */ + info_ptr->num_text = old_num_text; + info_ptr->max_text = old_max_text; + return(1); + } +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_TEXT; +#endif + } + png_debug1(3, "allocated %d entries for info_ptr->text", + info_ptr->max_text); + } + + for (i = 0; i < num_text; i++) + { + png_size_t text_length, key_len; + png_size_t lang_len, lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + key_len = png_strlen(text_ptr[i].key); + + if (text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + + else +#ifdef PNG_iTXt_SUPPORTED + { + /* Set iTXt data */ + + if (text_ptr[i].lang != NULL) + lang_len = png_strlen(text_ptr[i].lang); + else + lang_len = 0; + if (text_ptr[i].lang_key != NULL) + lang_key_len = png_strlen(text_ptr[i].lang_key); + else + lang_key_len = 0; + } +#else /* PNG_iTXt_SUPPORTED */ + { + png_warning(png_ptr, "iTXt chunk not supported."); + continue; + } +#endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +#ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + else +#endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + + else + { + text_length = png_strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = (png_charp)png_malloc_warn(png_ptr, + (png_uint_32) + (key_len + text_length + lang_len + lang_key_len + 4)); + if (textp->key == NULL) + return(1); + png_debug2(2, "Allocated %lu bytes at %x in png_set_text", + (png_uint_32) + (key_len + lang_len + lang_key_len + text_length + 4), + (int)textp->key); + + png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len)); + *(textp->key + key_len) = '\0'; +#ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + { + textp->lang = textp->key + key_len + 1; + png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang + lang_len) = '\0'; + textp->lang_key = textp->lang + lang_len + 1; + png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key + lang_key_len) = '\0'; + textp->text = textp->lang_key + lang_key_len + 1; + } + else +#endif + { +#ifdef PNG_iTXt_SUPPORTED + textp->lang=NULL; + textp->lang_key=NULL; +#endif + textp->text = textp->key + key_len + 1; + } + if (text_length) + png_memcpy(textp->text, text_ptr[i].text, + (png_size_t)(text_length)); + *(textp->text + text_length) = '\0'; + +#ifdef PNG_iTXt_SUPPORTED + if (textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + else +#endif + + { + textp->text_length = text_length; +#ifdef PNG_iTXt_SUPPORTED + textp->itxt_length = 0; +#endif + } + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d", info_ptr->num_text); + } + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +void PNGAPI +png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) +{ + png_debug1(1, "in %s storage function", "tIME"); + + if (png_ptr == NULL || info_ptr == NULL || + (png_ptr->mode & PNG_WROTE_tIME)) + return; + + png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof(png_time)); + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +void PNGAPI +png_set_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep trans, int num_trans, png_color_16p trans_values) +{ + png_debug1(1, "in %s storage function", "tRNS"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (num_trans < 0 || num_trans > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Ignoring invalid num_trans value"); + return; + } + + if (trans != NULL) + { + /* It may not actually be necessary to set png_ptr->trans here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); +#endif + + /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr, + (png_uint_32)PNG_MAX_PALETTE_LENGTH); + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans); + } + + if (trans_values != NULL) + { + int sample_max = (1 << info_ptr->bit_depth); + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + (int)trans_values->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + ((int)trans_values->red > sample_max || + (int)trans_values->green > sample_max || + (int)trans_values->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + png_memcpy(&(info_ptr->trans_values), trans_values, + png_sizeof(png_color_16)); + if (num_trans == 0) + num_trans = 1; + } + + info_ptr->num_trans = (png_uint_16)num_trans; + if (num_trans != 0) + { + info_ptr->valid |= PNG_INFO_tRNS; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_TRNS; +#else + png_ptr->flags |= PNG_FLAG_FREE_TRNS; +#endif + } +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +void PNGAPI +png_set_sPLT(png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries) +/* + * entries - array of png_sPLT_t structures + * to be added to the list of palettes + * in the info structure. + * nentries - number of palette structures to be + * added. + */ +{ + png_sPLT_tp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL) + return; + + np = (png_sPLT_tp)png_malloc_warn(png_ptr, + (info_ptr->splt_palettes_num + nentries) * + (png_uint_32)png_sizeof(png_sPLT_t)); + if (np == NULL) + { + png_warning(png_ptr, "No memory for sPLT palettes."); + return; + } + + png_memcpy(np, info_ptr->splt_palettes, + info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes=NULL; + + for (i = 0; i < nentries; i++) + { + png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; + png_sPLT_tp from = entries + i; + png_uint_32 length; + + length = png_strlen(from->name) + 1; + to->name = (png_charp)png_malloc_warn(png_ptr, length); + if (to->name == NULL) + { + png_warning(png_ptr, + "Out of memory while processing sPLT chunk"); + continue; + } + png_memcpy(to->name, from->name, length); + to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, + (png_uint_32)(from->nentries * png_sizeof(png_sPLT_entry))); + if (to->entries == NULL) + { + png_warning(png_ptr, + "Out of memory while processing sPLT chunk"); + png_free(png_ptr, to->name); + to->name = NULL; + continue; + } + png_memcpy(to->entries, from->entries, + from->nentries * png_sizeof(png_sPLT_entry)); + to->nentries = from->nentries; + to->depth = from->depth; + } + + info_ptr->splt_palettes = np; + info_ptr->splt_palettes_num += nentries; + info_ptr->valid |= PNG_INFO_sPLT; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_SPLT; +#endif +} +#endif /* PNG_sPLT_SUPPORTED */ + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +void PNGAPI +png_set_unknown_chunks(png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + return; + + np = (png_unknown_chunkp)png_malloc_warn(png_ptr, + (png_uint_32)((info_ptr->unknown_chunks_num + num_unknowns) * + png_sizeof(png_unknown_chunk))); + if (np == NULL) + { + png_warning(png_ptr, + "Out of memory while processing unknown chunk."); + return; + } + + png_memcpy(np, info_ptr->unknown_chunks, + info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk)); + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + + for (i = 0; i < num_unknowns; i++) + { + png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; + png_unknown_chunkp from = unknowns + i; + + png_memcpy((png_charp)to->name, (png_charp)from->name, + png_sizeof(from->name)); + to->name[png_sizeof(to->name)-1] = '\0'; + to->size = from->size; + /* Note our location in the read or write sequence */ + to->location = (png_byte)(png_ptr->mode & 0xff); + + if (from->size == 0) + to->data=NULL; + else + { + to->data = (png_bytep)png_malloc_warn(png_ptr, + (png_uint_32)from->size); + if (to->data == NULL) + { + png_warning(png_ptr, + "Out of memory while processing unknown chunk."); + to->size = 0; + } + else + png_memcpy(to->data, from->data, from->size); + } + } + + info_ptr->unknown_chunks = np; + info_ptr->unknown_chunks_num += num_unknowns; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_UNKN; +#endif +} +void PNGAPI +png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, + int chunk, int location) +{ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < + (int)info_ptr->unknown_chunks_num) + info_ptr->unknown_chunks[chunk].location = (png_byte)location; +} +#endif + +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +void PNGAPI +png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted) +{ + /* This function is deprecated in favor of png_permit_mng_features() + and will be removed from libpng-1.3.0 */ + + png_debug(1, "in png_permit_empty_plte, DEPRECATED."); + + if (png_ptr == NULL) + return; + png_ptr->mng_features_permitted = (png_byte) + ((png_ptr->mng_features_permitted & (~PNG_FLAG_MNG_EMPTY_PLTE)) | + ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE))); +} +#endif +#endif + +#ifdef PNG_MNG_FEATURES_SUPPORTED +png_uint_32 PNGAPI +png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features"); + + if (png_ptr == NULL) + return (png_uint_32)0; + png_ptr->mng_features_permitted = + (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); + return (png_uint_32)png_ptr->mng_features_permitted; +} +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +void PNGAPI +png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep + chunk_list, int num_chunks) +{ + png_bytep new_list, p; + int i, old_num_chunks; + if (png_ptr == NULL) + return; + if (num_chunks == 0) + { + if (keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) + png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS) + png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + return; + } + if (chunk_list == NULL) + return; + old_num_chunks = png_ptr->num_chunk_list; + new_list=(png_bytep)png_malloc(png_ptr, + (png_uint_32) + (5*(num_chunks + old_num_chunks))); + if (png_ptr->chunk_list != NULL) + { + png_memcpy(new_list, png_ptr->chunk_list, + (png_size_t)(5*old_num_chunks)); + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + } + png_memcpy(new_list + 5*old_num_chunks, chunk_list, + (png_size_t)(5*num_chunks)); + for (p = new_list + 5*old_num_chunks + 4, i = 0; inum_chunk_list = old_num_chunks + num_chunks; + png_ptr->chunk_list = new_list; +#ifdef PNG_FREE_ME_SUPPORTED + png_ptr->free_me |= PNG_FREE_LIST; +#endif +} +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +void PNGAPI +png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +{ + png_debug1(1, "in %s storage function", "rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + info_ptr->row_pointers = row_pointers; + if (row_pointers) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +void PNGAPI +png_set_compression_buffer_size(png_structp png_ptr, + png_uint_32 size) +{ + if (png_ptr == NULL) + return; + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf_size = (png_size_t)size; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; +} + +void PNGAPI +png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +{ + if (png_ptr && info_ptr) + info_ptr->valid &= ~mask; +} + + +#ifndef PNG_1_0_X +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +/* Function was added to libpng 1.2.0 and should always exist by default */ +void PNGAPI +png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags) +{ +/* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */ + if (png_ptr != NULL) + png_ptr->asm_flags = 0; + PNG_UNUSED(asm_flags) /* Quiet the compiler */ +} + +/* This function was added to libpng 1.2.0 */ +void PNGAPI +png_set_mmx_thresholds (png_structp png_ptr, + png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold) +{ +/* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */ + if (png_ptr == NULL) + return; + /* Quiet the compiler */ + PNG_UNUSED(mmx_bitdepth_threshold) + PNG_UNUSED(mmx_rowbytes_threshold) +} +#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* This function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7ffffffL. + */ + if (png_ptr == NULL) + return; + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_set_benign_errors(png_structp png_ptr, int allowed) +{ + png_debug(1, "in png_set_benign_errors"); + + if (allowed) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + else + png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; +} +#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ +#endif /* ?PNG_1_0_X */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngtest.c b/main/source/includes/lpng1251/pngtest.c index 6c2e7649..7ce2ee61 100644 --- a/main/source/includes/lpng1251/pngtest.c +++ b/main/source/includes/lpng1251/pngtest.c @@ -1,1705 +1,1705 @@ - -/* pngtest.c - a simple test program to test libpng - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This program reads in a PNG image, writes it out again, and then - * compares the two files. If the files are identical, this shows that - * the basic chunk handling, filtering, and (de)compression code is working - * properly. It does not currently test all of the transforms, although - * it probably should. - * - * The program will report "FAIL" in certain legitimate cases: - * 1) when the compression level or filter selection method is changed. - * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. - * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks - * exist in the input file. - * 4) others not listed here... - * In these cases, it is best to check with another tool such as "pngcheck" - * to see what the differences between the two files are. - * - * If a filename is given on the command-line, then this file is used - * for the input, rather than the default "pngtest.png". This allows - * testing a wide variety of files easily. You can also test a number - * of files at once by typing "pngtest -m file1.png file2.png ..." - */ - -#define PNG_PEDANTIC_WARNINGS -#include "png.h" - -#ifdef _WIN32_WCE -# if _WIN32_WCE < 211 - __error__ (f|w)printf functions are not supported on old WindowsCE.; -# endif -# include -# include -# define READFILE(file, data, length, check) \ - if (ReadFile(file, data, length, &check, NULL)) check = 0 -# define WRITEFILE(file, data, length, check)) \ - if (WriteFile(file, data, length, &check, NULL)) check = 0 -# define FCLOSE(file) CloseHandle(file) -#else -# include -# include -# define READFILE(file, data, length, check) \ - check=(png_size_t)fread(data, (png_size_t)1, length, file) -# define WRITEFILE(file, data, length, check) \ - check=(png_size_t)fwrite(data, (png_size_t)1, length, file) -# define FCLOSE(file) fclose(file) -#endif - -#ifndef PNG_STDIO_SUPPORTED -# ifdef _WIN32_WCE - typedef HANDLE png_FILE_p; -# else - typedef FILE * png_FILE_p; -# endif -#endif - -/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ -#ifndef PNG_DEBUG -# define PNG_DEBUG 0 -#endif - -#if !PNG_DEBUG -# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ -#endif - -/* Turn on CPU timing -#define PNGTEST_TIMING -*/ - -#ifndef PNG_FLOATING_POINT_SUPPORTED -#undef PNGTEST_TIMING -#endif - -#ifdef PNGTEST_TIMING -static float t_start, t_stop, t_decode, t_encode, t_misc; -#include -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED -#define PNG_tIME_STRING_LENGTH 29 -static int tIME_chunk_present = 0; -static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; -#endif - -static int verbose = 0; - -int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); - -#ifdef __TURBOC__ -#include -#endif - -/* Defined so I can write to a file on gui/windowing platforms */ -/* #define STDERR stderr */ -#define STDERR stdout /* For DOS */ - -/* In case a system header (e.g., on AIX) defined jmpbuf */ -#ifdef jmpbuf -# undef jmpbuf -#endif - -/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) png_ptr->jmpbuf -#endif - -/* Example of using row callbacks to make a simple progress meter */ -static int status_pass = 1; -static int status_dots_requested = 0; -static int status_dots = 1; - -void -#ifdef PNG_1_0_X -PNGAPI -#endif -read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) -{ - if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) - return; - if (status_pass != pass) - { - fprintf(stdout, "\n Pass %d: ", pass); - status_pass = pass; - status_dots = 31; - } - status_dots--; - if (status_dots == 0) - { - fprintf(stdout, "\n "); - status_dots=30; - } - fprintf(stdout, "r"); -} - -void -#ifdef PNG_1_0_X -PNGAPI -#endif -write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) -{ - if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) - return; - fprintf(stdout, "w"); -} - - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED -/* Example of using user transform callback (we don't transform anything, - * but merely examine the row filters. We set this to 256 rather than - * 5 in case illegal filter values are present.) - */ -static png_uint_32 filters_used[256]; -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - if (png_ptr != NULL && row_info != NULL) - ++filters_used[*(data - 1)]; -} -#endif - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -/* Example of using user transform callback (we don't transform anything, - * but merely count the zero samples) - */ - -static png_uint_32 zero_samples; - -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - png_bytep dp = data; - if (png_ptr == NULL)return; - - /* Contents of row_info: - * png_uint_32 width width of row - * png_uint_32 rowbytes number of bytes in row - * png_byte color_type color type of pixels - * png_byte bit_depth bit depth of samples - * png_byte channels number of channels (1-4) - * png_byte pixel_depth bits per pixel (depth*channels) - */ - - /* Counts the number of zero samples (or zero pixels if color_type is 3 */ - - if (row_info->color_type == 0 || row_info->color_type == 3) - { - int pos = 0; - png_uint_32 n, nstop; - for (n = 0, nstop=row_info->width; nbit_depth == 1) - { - if (((*dp << pos++ ) & 0x80) == 0) - zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } - if (row_info->bit_depth == 2) - { - if (((*dp << (pos+=2)) & 0xc0) == 0) - zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } - if (row_info->bit_depth == 4) - { - if (((*dp << (pos+=4)) & 0xf0) == 0) - zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } - if (row_info->bit_depth == 8) - if (*dp++ == 0) - zero_samples++; - if (row_info->bit_depth == 16) - { - if ((*dp | *(dp+1)) == 0) - zero_samples++; - dp+=2; - } - } - } - else /* Other color types */ - { - png_uint_32 n, nstop; - int channel; - int color_channels = row_info->channels; - if (row_info->color_type > 3)color_channels--; - - for (n = 0, nstop=row_info->width; nbit_depth == 8) - if (*dp++ == 0) - zero_samples++; - if (row_info->bit_depth == 16) - { - if ((*dp | *(dp+1)) == 0) - zero_samples++; - dp+=2; - } - } - if (row_info->color_type > 3) - { - dp++; - if (row_info->bit_depth == 16) - dp++; - } - } - } -} -#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ - -static int wrote_question = 0; - -#ifndef PNG_STDIO_SUPPORTED -/* START of code to validate stdio-free compilation */ -/* These copies of the default read/write functions come from pngrio.c and - * pngwio.c. They allow "don't include stdio" testing of the library. - * This is the function that does the actual reading of data. If you are - * not reading from a standard C stream, you should create a replacement - * read_data function and use it at run time with png_set_read_fn(), rather - * than changing the library. - */ - -#ifndef USE_FAR_KEYWORD -static void -pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check = 0; - png_voidp io_ptr; - - /* fread() returns 0 on error, so it is OK to store this in a png_size_t - * instead of an int, which is what fread() actually returns. - */ - io_ptr = png_get_io_ptr(png_ptr); - if (io_ptr != NULL) - { - READFILE((png_FILE_p)io_ptr, data, length, check); - } - - if (check != length) - { - png_error(png_ptr, "Read Error!"); - } -} -#else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void -pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - int check; - png_byte *n_data; - png_FILE_p io_ptr; - - /* Check if data really is near. If so, use usual code. */ - n_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)n_data == data) - { - READFILE(io_ptr, n_data, length, check); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); - READFILE(io_ptr, buf, 1, err); - png_memcpy(data, buf, read); /* Copy far buffer to near buffer */ - if (err != read) - break; - else - check += err; - data += read; - remaining -= read; - } - while (remaining != 0); - } - if (check != length) - png_error(png_ptr, "read Error"); -} -#endif /* USE_FAR_KEYWORD */ - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -static void -pngtest_flush(png_structp png_ptr) -{ - /* Do nothing; fflush() is said to be just a waste of energy. */ - PNG_UNUSED(png_ptr) /* Stifle compiler warning */ -} -#endif - -/* This is the function that does the actual writing of data. If you are - * not writing to a standard C stream, you should create a replacement - * write_data function and use it at run time with png_set_write_fn(), rather - * than changing the library. - */ -#ifndef USE_FAR_KEYWORD -static void -pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - - WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} -#else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void -pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ - png_FILE_p io_ptr; - - /* Check if data really is near. If so, use usual code. */ - near_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)near_data == data) - { - WRITEFILE(io_ptr, near_data, length, check); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t written, remaining, err; - check = 0; - remaining = length; - do - { - written = MIN(NEAR_BUF_SIZE, remaining); - png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ - WRITEFILE(io_ptr, buf, written, err); - if (err != written) - break; - else - check += err; - data += written; - remaining -= written; - } - while (remaining != 0); - } - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} -#endif /* USE_FAR_KEYWORD */ - -/* This function is called when there is a warning, but the library thinks - * it can continue anyway. Replacement functions don't have to do anything - * here if you don't want to. In the default configuration, png_ptr is - * not used, but it is passed in case it may be useful. - */ -static void -pngtest_warning(png_structp png_ptr, png_const_charp message) -{ - PNG_CONST char *name = "UNKNOWN (ERROR!)"; - char *test; - test = png_get_error_ptr(png_ptr); - if (test == NULL) - fprintf(STDERR, "%s: libpng warning: %s\n", name, message); - else - fprintf(STDERR, "%s: libpng warning: %s\n", test, message); -} - -/* This is the default error handling function. Note that replacements for - * this function MUST NOT RETURN, or the program will likely crash. This - * function is used by default, or if the program supplies NULL for the - * error function pointer in png_set_error_fn(). - */ -static void -pngtest_error(png_structp png_ptr, png_const_charp message) -{ - pngtest_warning(png_ptr, message); - /* We can return because png_error calls the default handler, which is - * actually OK in this case. - */ -} -#endif /* !PNG_STDIO_SUPPORTED */ -/* END of code to validate stdio-free compilation */ - -/* START of code to validate memory allocation and deallocation */ -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - * - * This piece of code can be compiled to validate max 64K allocations - * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. - */ -typedef struct memory_information -{ - png_uint_32 size; - png_voidp pointer; - struct memory_information FAR *next; -} memory_information; -typedef memory_information FAR *memory_infop; - -static memory_infop pinformation = NULL; -static int current_allocation = 0; -static int maximum_allocation = 0; -static int total_allocation = 0; -static int num_allocations = 0; - -png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size)); -void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); - -png_voidp -png_debug_malloc(png_structp png_ptr, png_uint_32 size) -{ - - /* png_malloc has already tested for NULL; png_create_struct calls - * png_debug_malloc directly, with png_ptr == NULL which is OK - */ - - if (size == 0) - return (NULL); - - /* This calls the library allocator twice, once to get the requested - buffer and once to get a new free list entry. */ - { - /* Disable malloc_fn and free_fn */ - memory_infop pinfo; - png_set_mem_fn(png_ptr, NULL, NULL, NULL); - pinfo = (memory_infop)png_malloc(png_ptr, - (png_uint_32)png_sizeof(*pinfo)); - pinfo->size = size; - current_allocation += size; - total_allocation += size; - num_allocations ++; - if (current_allocation > maximum_allocation) - maximum_allocation = current_allocation; - pinfo->pointer = (png_voidp)png_malloc(png_ptr, size); - /* Restore malloc_fn and free_fn */ - png_set_mem_fn(png_ptr, - png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, - (png_free_ptr)png_debug_free); - if (size != 0 && pinfo->pointer == NULL) - { - current_allocation -= size; - total_allocation -= size; - png_error(png_ptr, - "out of memory in pngtest->png_debug_malloc."); - } - pinfo->next = pinformation; - pinformation = pinfo; - /* Make sure the caller isn't assuming zeroed memory. */ - png_memset(pinfo->pointer, 0xdd, pinfo->size); - if (verbose) - printf("png_malloc %lu bytes at %x\n", (unsigned long)size, - pinfo->pointer); - return (png_voidp)(pinfo->pointer); - } -} - -/* Free a pointer. It is removed from the list at the same time. */ -void -png_debug_free(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL) - fprintf(STDERR, "NULL pointer to png_debug_free.\n"); - if (ptr == 0) - { -#if 0 /* This happens all the time. */ - fprintf(STDERR, "WARNING: freeing NULL pointer\n"); -#endif - return; - } - - /* Unlink the element from the list. */ - { - memory_infop FAR *ppinfo = &pinformation; - for (;;) - { - memory_infop pinfo = *ppinfo; - if (pinfo->pointer == ptr) - { - *ppinfo = pinfo->next; - current_allocation -= pinfo->size; - if (current_allocation < 0) - fprintf(STDERR, "Duplicate free of memory\n"); - /* We must free the list element too, but first kill - the memory that is to be freed. */ - png_memset(ptr, 0x55, pinfo->size); - png_free_default(png_ptr, pinfo); - pinfo = NULL; - break; - } - if (pinfo->next == NULL) - { - fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); - break; - } - ppinfo = &pinfo->next; - } - } - - /* Finally free the data. */ - if (verbose) - printf("Freeing %x\n", ptr); - png_free_default(png_ptr, ptr); - ptr = NULL; -} -#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ -/* END of code to test memory allocation/deallocation */ - - -/* Demonstration of user chunk support of the sTER and vpAg chunks */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - -/* (sTER is a public chunk not yet known by libpng. vpAg is a private -chunk used in ImageMagick to store "virtual page" size). */ - -static png_uint_32 user_chunk_data[4]; - - /* 0: sTER mode + 1 - * 1: vpAg width - * 2: vpAg height - * 3: vpAg units - */ - -static int read_user_chunk_callback(png_struct *png_ptr, - png_unknown_chunkp chunk) -{ - png_uint_32 - *my_user_chunk_data; - - /* Return one of the following: - * return (-n); chunk had an error - * return (0); did not recognize - * return (n); success - * - * The unknown chunk structure contains the chunk data: - * png_byte name[5]; - * png_byte *data; - * png_size_t size; - * - * Note that libpng has already taken care of the CRC handling. - */ - - if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ - chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ - { - /* Found sTER chunk */ - if (chunk->size != 1) - return (-1); /* Error return */ - if (chunk->data[0] != 0 && chunk->data[0] != 1) - return (-1); /* Invalid mode */ - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - my_user_chunk_data[0]=chunk->data[0]+1; - return (1); - } - - if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ - chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ - return (0); /* Did not recognize */ - - /* Found ImageMagick vpAg chunk */ - - if (chunk->size != 9) - return (-1); /* Error return */ - - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - - my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); - my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); - my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; - - return (1); - -} -#endif -/* END of code to demonstrate user chunk support */ - -/* Test one file */ -int -test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) -{ - static png_FILE_p fpin; - static png_FILE_p fpout; /* "static" prevents setjmp corruption */ - png_structp read_ptr; - png_infop read_info_ptr, end_info_ptr; -#ifdef PNG_WRITE_SUPPORTED - png_structp write_ptr; - png_infop write_info_ptr; - png_infop write_end_info_ptr; -#else - png_structp write_ptr = NULL; - png_infop write_info_ptr = NULL; - png_infop write_end_info_ptr = NULL; -#endif - png_bytep row_buf; - png_uint_32 y; - png_uint_32 width, height; - int num_pass, pass; - int bit_depth, color_type; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - -#ifdef _WIN32_WCE - TCHAR path[MAX_PATH]; -#endif - char inbuf[256], outbuf[256]; - - row_buf = NULL; - -#ifdef _WIN32_WCE - MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); - if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, - NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpin = fopen(inname, "rb")) == NULL) -#endif - { - fprintf(STDERR, "Could not find input file %s\n", inname); - return (1); - } - -#ifdef _WIN32_WCE - MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); - if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpout = fopen(outname, "wb")) == NULL) -#endif - { - fprintf(STDERR, "Could not open output file %s\n", outname); - FCLOSE(fpin); - return (1); - } - - png_debug(0, "Allocating read and write structures"); -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - read_ptr = - png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); -#else - read_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL); -#endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - user_chunk_data[0] = 0; - user_chunk_data[1] = 0; - user_chunk_data[2] = 0; - user_chunk_data[3] = 0; - png_set_read_user_chunk_fn(read_ptr, user_chunk_data, - read_user_chunk_callback); - -#endif -#ifdef PNG_WRITE_SUPPORTED -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - write_ptr = - png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); -#else - write_ptr = - png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL); -#endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif -#endif - png_debug(0, "Allocating read_info, write_info and end_info structures"); - read_info_ptr = png_create_info_struct(read_ptr); - end_info_ptr = png_create_info_struct(read_ptr); -#ifdef PNG_WRITE_SUPPORTED - write_info_ptr = png_create_info_struct(write_ptr); - write_end_info_ptr = png_create_info_struct(write_ptr); -#endif - -#ifdef PNG_SETJMP_SUPPORTED - png_debug(0, "Setting jmpbuf for read struct"); -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(read_ptr))) -#endif - { - fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); - png_free(read_ptr, row_buf); - row_buf = NULL; - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - FCLOSE(fpin); - FCLOSE(fpout); - return (1); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf)); -#endif - -#ifdef PNG_WRITE_SUPPORTED - png_debug(0, "Setting jmpbuf for write struct"); -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(write_ptr))) -#endif - { - fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - png_destroy_info_struct(write_ptr, &write_end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - FCLOSE(fpin); - FCLOSE(fpout); - return (1); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif -#endif - - png_debug(0, "Initializing input and output streams"); -#ifdef PNG_STDIO_SUPPORTED - png_init_io(read_ptr, fpin); -# ifdef PNG_WRITE_SUPPORTED - png_init_io(write_ptr, fpout); -# endif -#else - png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); -# ifdef PNG_WRITE_SUPPORTED - png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, -# ifdef PNG_WRITE_FLUSH_SUPPORTED - pngtest_flush); -# else - NULL); -# endif -# endif -#endif - if (status_dots_requested == 1) - { -#ifdef PNG_WRITE_SUPPORTED - png_set_write_status_fn(write_ptr, write_row_callback); -#endif - png_set_read_status_fn(read_ptr, read_row_callback); - } - else - { -#ifdef PNG_WRITE_SUPPORTED - png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL); -#endif - png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); - } - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - { - int i; - for (i = 0; i<256; i++) - filters_used[i] = 0; - png_set_read_user_transform_fn(read_ptr, count_filters); - } -#endif -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - zero_samples = 0; - png_set_write_user_transform_fn(write_ptr, count_zero_samples); -#endif - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_HANDLE_CHUNK_ALWAYS -# define PNG_HANDLE_CHUNK_ALWAYS 3 -# endif - png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, - png_bytep_NULL, 0); -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_HANDLE_CHUNK_IF_SAFE -# define PNG_HANDLE_CHUNK_IF_SAFE 2 -# endif - png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, - png_bytep_NULL, 0); -#endif - - png_debug(0, "Reading info struct"); - png_read_info(read_ptr, read_info_ptr); - - png_debug(0, "Transferring info struct"); - { - int interlace_type, compression_type, filter_type; - - if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, - &color_type, &interlace_type, &compression_type, &filter_type)) - { - png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - color_type, interlace_type, compression_type, filter_type); -#else - color_type, PNG_INTERLACE_NONE, compression_type, filter_type); -#endif - } - } -#ifdef PNG_FIXED_POINT_SUPPORTED -#ifdef PNG_cHRM_SUPPORTED - { - png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; - if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) - { - png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); - } - } -#endif -#ifdef PNG_gAMA_SUPPORTED - { - png_fixed_point gamma; - - if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) - png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); - } -#endif -#else /* Use floating point versions */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -#ifdef PNG_cHRM_SUPPORTED - { - double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; - if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, - &red_y, &green_x, &green_y, &blue_x, &blue_y)) - { - png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); - } - } -#endif -#ifdef PNG_gAMA_SUPPORTED - { - double gamma; - - if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) - png_set_gAMA(write_ptr, write_info_ptr, gamma); - } -#endif -#endif /* Floating point */ -#endif /* Fixed point */ -#ifdef PNG_iCCP_SUPPORTED - { - png_charp name; - png_charp profile; - png_uint_32 proflen; - int compression_type; - - if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, - &profile, &proflen)) - { - png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, - profile, proflen); - } - } -#endif -#ifdef PNG_sRGB_SUPPORTED - { - int intent; - - if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) - png_set_sRGB(write_ptr, write_info_ptr, intent); - } -#endif - { - png_colorp palette; - int num_palette; - - if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) - png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); - } -#ifdef PNG_bKGD_SUPPORTED - { - png_color_16p background; - - if (png_get_bKGD(read_ptr, read_info_ptr, &background)) - { - png_set_bKGD(write_ptr, write_info_ptr, background); - } - } -#endif -#ifdef PNG_hIST_SUPPORTED - { - png_uint_16p hist; - - if (png_get_hIST(read_ptr, read_info_ptr, &hist)) - png_set_hIST(write_ptr, write_info_ptr, hist); - } -#endif -#ifdef PNG_oFFs_SUPPORTED - { - png_int_32 offset_x, offset_y; - int unit_type; - - if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, - &unit_type)) - { - png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); - } - } -#endif -#ifdef PNG_pCAL_SUPPORTED - { - png_charp purpose, units; - png_charpp params; - png_int_32 X0, X1; - int type, nparams; - - if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, - &nparams, &units, ¶ms)) - { - png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, - nparams, units, params); - } - } -#endif -#ifdef PNG_pHYs_SUPPORTED - { - png_uint_32 res_x, res_y; - int unit_type; - - if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) - png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); - } -#endif -#ifdef PNG_sBIT_SUPPORTED - { - png_color_8p sig_bit; - - if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) - png_set_sBIT(write_ptr, write_info_ptr, sig_bit); - } -#endif -#ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED - { - int unit; - double scal_width, scal_height; - - if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height)) - { - png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); - } - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - { - int unit; - png_charp scal_width, scal_height; - - if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height)) - { - png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, - scal_height); - } - } -#endif -#endif -#endif -#ifdef PNG_TEXT_SUPPORTED - { - png_textp text_ptr; - int num_text; - - if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) - { - png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); - png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); - } - } -#endif -#ifdef PNG_tIME_SUPPORTED - { - png_timep mod_time; - - if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) - { - png_set_tIME(write_ptr, write_info_ptr, mod_time); -#ifdef PNG_TIME_RFC1123_SUPPORTED - /* We have to use png_memcpy instead of "=" because the string - * pointed to by png_convert_to_rfc1123() gets free'ed before - * we use it. - */ - png_memcpy(tIME_string, - png_convert_to_rfc1123(read_ptr, mod_time), - png_sizeof(tIME_string)); - tIME_string[png_sizeof(tIME_string) - 1] = '\0'; - tIME_chunk_present++; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } -#endif -#ifdef PNG_tRNS_SUPPORTED - { - png_bytep trans; - int num_trans; - png_color_16p trans_values; - - if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, - &trans_values)) - { - int sample_max = (1 << bit_depth); - /* libpng doesn't reject a tRNS chunk with out-of-range samples */ - if (!((color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_values->gray > sample_max) || - (color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_values->red > sample_max || - (int)trans_values->green > sample_max || - (int)trans_values->blue > sample_max)))) - png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, - trans_values); - } - } -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - { - png_unknown_chunkp unknowns; - int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, - &unknowns); - if (num_unknowns) - { - png_size_t i; - png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, - num_unknowns); - /* Copy the locations from the read_info_ptr. The automatically - * generated locations in write_info_ptr are wrong because we - * haven't written anything yet. - */ - for (i = 0; i < (png_size_t)num_unknowns; i++) - png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, - unknowns[i].location); - } - } -#endif - -#ifdef PNG_WRITE_SUPPORTED - png_debug(0, "Writing info struct"); - -/* If we wanted, we could write info in two steps: - * png_write_info_before_PLTE(write_ptr, write_info_ptr); - */ - png_write_info(write_ptr, write_info_ptr); - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - if (user_chunk_data[0] != 0) - { - png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; - - unsigned char - ster_chunk_data[1]; - - if (verbose) - fprintf(STDERR, "\n stereo mode = %lu\n", - (unsigned long)(user_chunk_data[0] - 1)); - ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1); - png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1); - } - if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0) - { - png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; - - unsigned char - vpag_chunk_data[9]; - - if (verbose) - fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n", - (unsigned long)user_chunk_data[1], - (unsigned long)user_chunk_data[2], - (unsigned long)user_chunk_data[3]); - png_save_uint_32(vpag_chunk_data, user_chunk_data[1]); - png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]); - vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff); - png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); - } - -#endif -#endif - -#ifdef SINGLE_ROWBUF_ALLOC - png_debug(0, "Allocating row buffer..."); - row_buf = (png_bytep)png_malloc(read_ptr, - png_get_rowbytes(read_ptr, read_info_ptr)); - png_debug1(0, "0x%08lx", (unsigned long)row_buf); -#endif /* SINGLE_ROWBUF_ALLOC */ - png_debug(0, "Writing row data"); - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) - num_pass = png_set_interlace_handling(read_ptr); -# ifdef PNG_WRITE_SUPPORTED - png_set_interlace_handling(write_ptr); -# endif -#else - num_pass = 1; -#endif - -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_misc += (t_stop - t_start); - t_start = t_stop; -#endif - for (pass = 0; pass < num_pass; pass++) - { - png_debug1(0, "Writing row data for pass %d", pass); - for (y = 0; y < height; y++) - { -#ifndef SINGLE_ROWBUF_ALLOC - png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); - row_buf = (png_bytep)png_malloc(read_ptr, - png_get_rowbytes(read_ptr, read_info_ptr)); - png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, - png_get_rowbytes(read_ptr, read_info_ptr)); -#endif /* !SINGLE_ROWBUF_ALLOC */ - png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); - -#ifdef PNG_WRITE_SUPPORTED -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_decode += (t_stop - t_start); - t_start = t_stop; -#endif - png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_encode += (t_stop - t_start); - t_start = t_stop; -#endif -#endif /* PNG_WRITE_SUPPORTED */ - -#ifndef SINGLE_ROWBUF_ALLOC - png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); - png_free(read_ptr, row_buf); - row_buf = NULL; -#endif /* !SINGLE_ROWBUF_ALLOC */ - } - } - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); -#endif - - png_debug(0, "Reading and writing end_info data"); - - png_read_end(read_ptr, end_info_ptr); -#ifdef PNG_TEXT_SUPPORTED - { - png_textp text_ptr; - int num_text; - - if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) - { - png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); - png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); - } - } -#endif -#ifdef PNG_tIME_SUPPORTED - { - png_timep mod_time; - - if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) - { - png_set_tIME(write_ptr, write_end_info_ptr, mod_time); -#ifdef PNG_TIME_RFC1123_SUPPORTED - /* We have to use png_memcpy instead of "=" because the string - pointed to by png_convert_to_rfc1123() gets free'ed before - we use it */ - png_memcpy(tIME_string, - png_convert_to_rfc1123(read_ptr, mod_time), - png_sizeof(tIME_string)); - tIME_string[png_sizeof(tIME_string) - 1] = '\0'; - tIME_chunk_present++; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - { - png_unknown_chunkp unknowns; - int num_unknowns; - num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, - &unknowns); - if (num_unknowns) - { - png_size_t i; - png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, - num_unknowns); - /* Copy the locations from the read_info_ptr. The automatically - * generated locations in write_end_info_ptr are wrong because we - * haven't written the end_info yet. - */ - for (i = 0; i < (png_size_t)num_unknowns; i++) - png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, - unknowns[i].location); - } - } -#endif -#ifdef PNG_WRITE_SUPPORTED - png_write_end(write_ptr, write_end_info_ptr); -#endif - -#ifdef PNG_EASY_ACCESS_SUPPORTED - if (verbose) - { - png_uint_32 iwidth, iheight; - iwidth = png_get_image_width(write_ptr, write_info_ptr); - iheight = png_get_image_height(write_ptr, write_info_ptr); - fprintf(STDERR, "\n Image width = %lu, height = %lu\n", - (unsigned long)iwidth, (unsigned long)iheight); - } -#endif - - png_debug(0, "Destroying data structs"); -#ifdef SINGLE_ROWBUF_ALLOC - png_debug(1, "destroying row_buf for read_ptr"); - png_free(read_ptr, row_buf); - row_buf = NULL; -#endif /* SINGLE_ROWBUF_ALLOC */ - png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_debug(1, "destroying write_end_info_ptr"); - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_debug(1, "destroying write_ptr, write_info_ptr"); - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - png_debug(0, "Destruction complete."); - - FCLOSE(fpin); - FCLOSE(fpout); - - png_debug(0, "Opening files for comparison"); -#ifdef _WIN32_WCE - MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); - if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, - 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpin = fopen(inname, "rb")) == NULL) -#endif - { - fprintf(STDERR, "Could not find file %s\n", inname); - return (1); - } - -#ifdef _WIN32_WCE - MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); - if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, - 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpout = fopen(outname, "rb")) == NULL) -#endif - { - fprintf(STDERR, "Could not find file %s\n", outname); - FCLOSE(fpin); - return (1); - } - - for (;;) - { - png_size_t num_in, num_out; - - READFILE(fpin, inbuf, 1, num_in); - READFILE(fpout, outbuf, 1, num_out); - - if (num_in != num_out) - { - fprintf(STDERR, "\nFiles %s and %s are of a different size\n", - inname, outname); - if (wrote_question == 0) - { - fprintf(STDERR, - " Was %s written with the same maximum IDAT chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); - fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); - fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); - wrote_question = 1; - } - FCLOSE(fpin); - FCLOSE(fpout); - return (0); - } - - if (!num_in) - break; - - if (png_memcmp(inbuf, outbuf, num_in)) - { - fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); - if (wrote_question == 0) - { - fprintf(STDERR, - " Was %s written with the same maximum IDAT chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); - fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); - fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); - wrote_question = 1; - } - FCLOSE(fpin); - FCLOSE(fpout); - return (0); - } - } - - FCLOSE(fpin); - FCLOSE(fpout); - - return (0); -} - -/* Input and output filenames */ -#ifdef RISCOS -static PNG_CONST char *inname = "pngtest/png"; -static PNG_CONST char *outname = "pngout/png"; -#else -static PNG_CONST char *inname = "pngtest.png"; -static PNG_CONST char *outname = "pngout.png"; -#endif - -int -main(int argc, char *argv[]) -{ - int multiple = 0; - int ierror = 0; - - fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); - fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); - fprintf(STDERR, "%s", png_get_copyright(NULL)); - /* Show the version of libpng used in building the library */ - fprintf(STDERR, " library (%lu):%s", - (unsigned long)png_access_version_number(), - png_get_header_version(NULL)); - /* Show the version of libpng used in building the application */ - fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, - PNG_HEADER_VERSION_STRING); - fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n", - (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); - - /* Do some consistency checking on the memory allocation settings, I'm - * not sure this matters, but it is nice to know, the first of these - * tests should be impossible because of the way the macros are set - * in pngconf.h - */ -#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) - fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); -#endif - /* I think the following can happen. */ -#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) - fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); -#endif - - if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) - { - fprintf(STDERR, - "Warning: versions are different between png.h and png.c\n"); - fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); - fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); - ++ierror; - } - - if (argc > 1) - { - if (strcmp(argv[1], "-m") == 0) - { - multiple = 1; - status_dots_requested = 0; - } - else if (strcmp(argv[1], "-mv") == 0 || - strcmp(argv[1], "-vm") == 0 ) - { - multiple = 1; - verbose = 1; - status_dots_requested = 1; - } - else if (strcmp(argv[1], "-v") == 0) - { - verbose = 1; - status_dots_requested = 1; - inname = argv[2]; - } - else - { - inname = argv[1]; - status_dots_requested = 0; - } - } - - if (!multiple && argc == 3 + verbose) - outname = argv[2 + verbose]; - - if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) - { - fprintf(STDERR, - "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", - argv[0], argv[0]); - fprintf(STDERR, - " reads/writes one PNG file (without -m) or multiple files (-m)\n"); - fprintf(STDERR, - " with -m %s is used as a temporary file\n", outname); - exit(1); - } - - if (multiple) - { - int i; -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - int allocation_now = current_allocation; -#endif - for (i=2; isize, - (unsigned int) pinfo->pointer); - pinfo = pinfo->next; - } - } -#endif - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - fprintf(STDERR, " Current memory allocation: %10d bytes\n", - current_allocation); - fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", - maximum_allocation); - fprintf(STDERR, " Total memory allocation: %10d bytes\n", - total_allocation); - fprintf(STDERR, " Number of allocations: %10d\n", - num_allocations); -#endif - } - else - { - int i; - for (i = 0; i<3; ++i) - { - int kerror; -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - int allocation_now = current_allocation; -#endif - if (i == 1) status_dots_requested = 1; - else if (verbose == 0)status_dots_requested = 0; - if (i == 0 || verbose == 1 || ierror != 0) - fprintf(STDERR, "\n Testing %s:", inname); - kerror = test_one_file(inname, outname); - if (kerror == 0) - { - if (verbose == 1 || i == 2) - { -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - int k; -#endif -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - fprintf(STDERR, "\n PASS (%lu zero samples)\n", - (unsigned long)zero_samples); -#else - fprintf(STDERR, " PASS\n"); -#endif -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - for (k = 0; k<256; k++) - if (filters_used[k]) - fprintf(STDERR, " Filter %d was used %lu times\n", - k, (unsigned long)filters_used[k]); -#endif -#ifdef PNG_TIME_RFC1123_SUPPORTED - if (tIME_chunk_present != 0) - fprintf(STDERR, " tIME = %s\n", tIME_string); -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } - else - { - if (verbose == 0 && i != 2) - fprintf(STDERR, "\n Testing %s:", inname); - fprintf(STDERR, " FAIL\n"); - ierror += kerror; - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - if (allocation_now != current_allocation) - fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", - current_allocation - allocation_now); - if (current_allocation != 0) - { - memory_infop pinfo = pinformation; - - fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", - current_allocation); - while (pinfo != NULL) - { - fprintf(STDERR, " %lu bytes at %x\n", - (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); - pinfo = pinfo->next; - } - } -#endif - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - fprintf(STDERR, " Current memory allocation: %10d bytes\n", - current_allocation); - fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", - maximum_allocation); - fprintf(STDERR, " Total memory allocation: %10d bytes\n", - total_allocation); - fprintf(STDERR, " Number of allocations: %10d\n", - num_allocations); -#endif - } - -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_misc += (t_stop - t_start); - t_start = t_stop; - fprintf(STDERR, " CPU time used = %.3f seconds", - (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); - fprintf(STDERR, " (decoding %.3f,\n", - t_decode/(float)CLOCKS_PER_SEC); - fprintf(STDERR, " encoding %.3f ,", - t_encode/(float)CLOCKS_PER_SEC); - fprintf(STDERR, " other %.3f seconds)\n\n", - t_misc/(float)CLOCKS_PER_SEC); -#endif - - if (ierror == 0) - fprintf(STDERR, " libpng passes test\n"); - else - fprintf(STDERR, " libpng FAILS test\n"); - return (int)(ierror != 0); -} - -/* Generate a compiler error if there is an old png.h in the search path. */ -typedef version_1_2_51 your_png_h_is_not_version_1_2_51; + +/* pngtest.c - a simple test program to test libpng + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This program reads in a PNG image, writes it out again, and then + * compares the two files. If the files are identical, this shows that + * the basic chunk handling, filtering, and (de)compression code is working + * properly. It does not currently test all of the transforms, although + * it probably should. + * + * The program will report "FAIL" in certain legitimate cases: + * 1) when the compression level or filter selection method is changed. + * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. + * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks + * exist in the input file. + * 4) others not listed here... + * In these cases, it is best to check with another tool such as "pngcheck" + * to see what the differences between the two files are. + * + * If a filename is given on the command-line, then this file is used + * for the input, rather than the default "pngtest.png". This allows + * testing a wide variety of files easily. You can also test a number + * of files at once by typing "pngtest -m file1.png file2.png ..." + */ + +#define PNG_PEDANTIC_WARNINGS +#include "png.h" + +#ifdef _WIN32_WCE +# if _WIN32_WCE < 211 + __error__ (f|w)printf functions are not supported on old WindowsCE.; +# endif +# include +# include +# define READFILE(file, data, length, check) \ + if (ReadFile(file, data, length, &check, NULL)) check = 0 +# define WRITEFILE(file, data, length, check)) \ + if (WriteFile(file, data, length, &check, NULL)) check = 0 +# define FCLOSE(file) CloseHandle(file) +#else +# include +# include +# define READFILE(file, data, length, check) \ + check=(png_size_t)fread(data, (png_size_t)1, length, file) +# define WRITEFILE(file, data, length, check) \ + check=(png_size_t)fwrite(data, (png_size_t)1, length, file) +# define FCLOSE(file) fclose(file) +#endif + +#ifndef PNG_STDIO_SUPPORTED +# ifdef _WIN32_WCE + typedef HANDLE png_FILE_p; +# else + typedef FILE * png_FILE_p; +# endif +#endif + +/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ +#endif + +/* Turn on CPU timing +#define PNGTEST_TIMING +*/ + +#ifndef PNG_FLOATING_POINT_SUPPORTED +#undef PNGTEST_TIMING +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#include +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +#define PNG_tIME_STRING_LENGTH 29 +static int tIME_chunk_present = 0; +static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; +#endif + +static int verbose = 0; + +int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); + +#ifdef __TURBOC__ +#include +#endif + +/* Defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* For DOS */ + +/* In case a system header (e.g., on AIX) defined jmpbuf */ +#ifdef jmpbuf +# undef jmpbuf +#endif + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +/* Example of using row callbacks to make a simple progress meter */ +static int status_pass = 1; +static int status_dots_requested = 0; +static int status_dots = 1; + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) + return; + if (status_pass != pass) + { + fprintf(stdout, "\n Pass %d: ", pass); + status_pass = pass; + status_dots = 31; + } + status_dots--; + if (status_dots == 0) + { + fprintf(stdout, "\n "); + status_dots=30; + } + fprintf(stdout, "r"); +} + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) + return; + fprintf(stdout, "w"); +} + + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +/* Example of using user transform callback (we don't transform anything, + * but merely examine the row filters. We set this to 256 rather than + * 5 in case illegal filter values are present.) + */ +static png_uint_32 filters_used[256]; +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + if (png_ptr != NULL && row_info != NULL) + ++filters_used[*(data - 1)]; +} +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +/* Example of using user transform callback (we don't transform anything, + * but merely count the zero samples) + */ + +static png_uint_32 zero_samples; + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + png_bytep dp = data; + if (png_ptr == NULL)return; + + /* Contents of row_info: + * png_uint_32 width width of row + * png_uint_32 rowbytes number of bytes in row + * png_byte color_type color type of pixels + * png_byte bit_depth bit depth of samples + * png_byte channels number of channels (1-4) + * png_byte pixel_depth bits per pixel (depth*channels) + */ + + /* Counts the number of zero samples (or zero pixels if color_type is 3 */ + + if (row_info->color_type == 0 || row_info->color_type == 3) + { + int pos = 0; + png_uint_32 n, nstop; + for (n = 0, nstop=row_info->width; nbit_depth == 1) + { + if (((*dp << pos++ ) & 0x80) == 0) + zero_samples++; + if (pos == 8) + { + pos = 0; + dp++; + } + } + if (row_info->bit_depth == 2) + { + if (((*dp << (pos+=2)) & 0xc0) == 0) + zero_samples++; + if (pos == 8) + { + pos = 0; + dp++; + } + } + if (row_info->bit_depth == 4) + { + if (((*dp << (pos+=4)) & 0xf0) == 0) + zero_samples++; + if (pos == 8) + { + pos = 0; + dp++; + } + } + if (row_info->bit_depth == 8) + if (*dp++ == 0) + zero_samples++; + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + dp+=2; + } + } + } + else /* Other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if (row_info->color_type > 3)color_channels--; + + for (n = 0, nstop=row_info->width; nbit_depth == 8) + if (*dp++ == 0) + zero_samples++; + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + dp+=2; + } + } + if (row_info->color_type > 3) + { + dp++; + if (row_info->bit_depth == 16) + dp++; + } + } + } +} +#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ + +static int wrote_question = 0; + +#ifndef PNG_STDIO_SUPPORTED +/* START of code to validate stdio-free compilation */ +/* These copies of the default read/write functions come from pngrio.c and + * pngwio.c. They allow "don't include stdio" testing of the library. + * This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ + +#ifndef USE_FAR_KEYWORD +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check = 0; + png_voidp io_ptr; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + io_ptr = png_get_io_ptr(png_ptr); + if (io_ptr != NULL) + { + READFILE((png_FILE_p)io_ptr, data, length, check); + } + + if (check != length) + { + png_error(png_ptr, "Read Error!"); + } +} +#else +/* This is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { + READFILE(io_ptr, n_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + READFILE(io_ptr, buf, 1, err); + png_memcpy(data, buf, read); /* Copy far buffer to near buffer */ + if (err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "read Error"); +} +#endif /* USE_FAR_KEYWORD */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +static void +pngtest_flush(png_structp png_ptr) +{ + /* Do nothing; fflush() is said to be just a waste of energy. */ + PNG_UNUSED(png_ptr) /* Stifle compiler warning */ +} +#endif + +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +#ifndef USE_FAR_KEYWORD +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + + WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#else +/* This is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { + WRITEFILE(io_ptr, near_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ + WRITEFILE(io_ptr, buf, written, err); + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#endif /* USE_FAR_KEYWORD */ + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void +pngtest_warning(png_structp png_ptr, png_const_charp message) +{ + PNG_CONST char *name = "UNKNOWN (ERROR!)"; + char *test; + test = png_get_error_ptr(png_ptr); + if (test == NULL) + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); + else + fprintf(STDERR, "%s: libpng warning: %s\n", test, message); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void +pngtest_error(png_structp png_ptr, png_const_charp message) +{ + pngtest_warning(png_ptr, message); + /* We can return because png_error calls the default handler, which is + * actually OK in this case. + */ +} +#endif /* !PNG_STDIO_SUPPORTED */ +/* END of code to validate stdio-free compilation */ + +/* START of code to validate memory allocation and deallocation */ +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * This piece of code can be compiled to validate max 64K allocations + * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. + */ +typedef struct memory_information +{ + png_uint_32 size; + png_voidp pointer; + struct memory_information FAR *next; +} memory_information; +typedef memory_information FAR *memory_infop; + +static memory_infop pinformation = NULL; +static int current_allocation = 0; +static int maximum_allocation = 0; +static int total_allocation = 0; +static int num_allocations = 0; + +png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size)); +void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); + +png_voidp +png_debug_malloc(png_structp png_ptr, png_uint_32 size) +{ + + /* png_malloc has already tested for NULL; png_create_struct calls + * png_debug_malloc directly, with png_ptr == NULL which is OK + */ + + if (size == 0) + return (NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + /* Disable malloc_fn and free_fn */ + memory_infop pinfo; + png_set_mem_fn(png_ptr, NULL, NULL, NULL); + pinfo = (memory_infop)png_malloc(png_ptr, + (png_uint_32)png_sizeof(*pinfo)); + pinfo->size = size; + current_allocation += size; + total_allocation += size; + num_allocations ++; + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + pinfo->pointer = (png_voidp)png_malloc(png_ptr, size); + /* Restore malloc_fn and free_fn */ + png_set_mem_fn(png_ptr, + png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, + (png_free_ptr)png_debug_free); + if (size != 0 && pinfo->pointer == NULL) + { + current_allocation -= size; + total_allocation -= size; + png_error(png_ptr, + "out of memory in pngtest->png_debug_malloc."); + } + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + png_memset(pinfo->pointer, 0xdd, pinfo->size); + if (verbose) + printf("png_malloc %lu bytes at %x\n", (unsigned long)size, + pinfo->pointer); + return (png_voidp)(pinfo->pointer); + } +} + +/* Free a pointer. It is removed from the list at the same time. */ +void +png_debug_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + if (ptr == 0) + { +#if 0 /* This happens all the time. */ + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); +#endif + return; + } + + /* Unlink the element from the list. */ + { + memory_infop FAR *ppinfo = &pinformation; + for (;;) + { + memory_infop pinfo = *ppinfo; + if (pinfo->pointer == ptr) + { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + png_memset(ptr, 0x55, pinfo->size); + png_free_default(png_ptr, pinfo); + pinfo = NULL; + break; + } + if (pinfo->next == NULL) + { + fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); + break; + } + ppinfo = &pinfo->next; + } + } + + /* Finally free the data. */ + if (verbose) + printf("Freeing %x\n", ptr); + png_free_default(png_ptr, ptr); + ptr = NULL; +} +#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ +/* END of code to test memory allocation/deallocation */ + + +/* Demonstration of user chunk support of the sTER and vpAg chunks */ +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + +/* (sTER is a public chunk not yet known by libpng. vpAg is a private +chunk used in ImageMagick to store "virtual page" size). */ + +static png_uint_32 user_chunk_data[4]; + + /* 0: sTER mode + 1 + * 1: vpAg width + * 2: vpAg height + * 3: vpAg units + */ + +static int read_user_chunk_callback(png_struct *png_ptr, + png_unknown_chunkp chunk) +{ + png_uint_32 + *my_user_chunk_data; + + /* Return one of the following: + * return (-n); chunk had an error + * return (0); did not recognize + * return (n); success + * + * The unknown chunk structure contains the chunk data: + * png_byte name[5]; + * png_byte *data; + * png_size_t size; + * + * Note that libpng has already taken care of the CRC handling. + */ + + if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ + chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ + { + /* Found sTER chunk */ + if (chunk->size != 1) + return (-1); /* Error return */ + if (chunk->data[0] != 0 && chunk->data[0] != 1) + return (-1); /* Invalid mode */ + my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); + my_user_chunk_data[0]=chunk->data[0]+1; + return (1); + } + + if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ + chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ + return (0); /* Did not recognize */ + + /* Found ImageMagick vpAg chunk */ + + if (chunk->size != 9) + return (-1); /* Error return */ + + my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); + + my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); + my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); + my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; + + return (1); + +} +#endif +/* END of code to demonstrate user chunk support */ + +/* Test one file */ +int +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) +{ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + png_structp read_ptr; + png_infop read_info_ptr, end_info_ptr; +#ifdef PNG_WRITE_SUPPORTED + png_structp write_ptr; + png_infop write_info_ptr; + png_infop write_end_info_ptr; +#else + png_structp write_ptr = NULL; + png_infop write_info_ptr = NULL; + png_infop write_end_info_ptr = NULL; +#endif + png_bytep row_buf; + png_uint_32 y; + png_uint_32 width, height; + int num_pass, pass; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + +#ifdef _WIN32_WCE + TCHAR path[MAX_PATH]; +#endif + char inbuf[256], outbuf[256]; + + row_buf = NULL; + +#ifdef _WIN32_WCE + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, + NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find input file %s\n", inname); + return (1); + } + +#ifdef _WIN32_WCE + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "wb")) == NULL) +#endif + { + fprintf(STDERR, "Could not open output file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + png_debug(0, "Allocating read and write structures"); +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + read_ptr = + png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + read_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL); +#endif +#ifndef PNG_STDIO_SUPPORTED + png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + user_chunk_data[0] = 0; + user_chunk_data[1] = 0; + user_chunk_data[2] = 0; + user_chunk_data[3] = 0; + png_set_read_user_chunk_fn(read_ptr, user_chunk_data, + read_user_chunk_callback); + +#endif +#ifdef PNG_WRITE_SUPPORTED +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + write_ptr = + png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + write_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL); +#endif +#ifndef PNG_STDIO_SUPPORTED + png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#endif + png_debug(0, "Allocating read_info, write_info and end_info structures"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); +#ifdef PNG_WRITE_SUPPORTED + write_info_ptr = png_create_info_struct(write_ptr); + write_end_info_ptr = png_create_info_struct(write_ptr); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_debug(0, "Setting jmpbuf for read struct"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(read_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); + png_free(read_ptr, row_buf); + row_buf = NULL; + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf)); +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Setting jmpbuf for write struct"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(write_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf)); +#endif +#endif +#endif + + png_debug(0, "Initializing input and output streams"); +#ifdef PNG_STDIO_SUPPORTED + png_init_io(read_ptr, fpin); +# ifdef PNG_WRITE_SUPPORTED + png_init_io(write_ptr, fpout); +# endif +#else + png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); +# ifdef PNG_WRITE_SUPPORTED + png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, +# ifdef PNG_WRITE_FLUSH_SUPPORTED + pngtest_flush); +# else + NULL); +# endif +# endif +#endif + if (status_dots_requested == 1) + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, write_row_callback); +#endif + png_set_read_status_fn(read_ptr, read_row_callback); + } + else + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL); +#endif + png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); + } + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + { + int i; + for (i = 0; i<256; i++) + filters_used[i] = 0; + png_set_read_user_transform_fn(read_ptr, count_filters); + } +#endif +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + zero_samples = 0; + png_set_write_user_transform_fn(write_ptr, count_zero_samples); +#endif + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +# endif + png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, + png_bytep_NULL, 0); +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +# endif + png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, + png_bytep_NULL, 0); +#endif + + png_debug(0, "Reading info struct"); + png_read_info(read_ptr, read_info_ptr); + + png_debug(0, "Transferring info struct"); + { + int interlace_type, compression_type, filter_type; + + if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, &compression_type, &filter_type)) + { + png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + color_type, interlace_type, compression_type, filter_type); +#else + color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#endif + } + } +#ifdef PNG_FIXED_POINT_SUPPORTED +#ifdef PNG_cHRM_SUPPORTED + { + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, + &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#ifdef PNG_gAMA_SUPPORTED + { + png_fixed_point gamma; + + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) + png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); + } +#endif +#else /* Use floating point versions */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +#ifdef PNG_cHRM_SUPPORTED + { + double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#ifdef PNG_gAMA_SUPPORTED + { + double gamma; + + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) + png_set_gAMA(write_ptr, write_info_ptr, gamma); + } +#endif +#endif /* Floating point */ +#endif /* Fixed point */ +#ifdef PNG_iCCP_SUPPORTED + { + png_charp name; + png_charp profile; + png_uint_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen)) + { + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif +#ifdef PNG_sRGB_SUPPORTED + { + int intent; + + if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) + png_set_sRGB(write_ptr, write_info_ptr, intent); + } +#endif + { + png_colorp palette; + int num_palette; + + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); + } +#ifdef PNG_bKGD_SUPPORTED + { + png_color_16p background; + + if (png_get_bKGD(read_ptr, read_info_ptr, &background)) + { + png_set_bKGD(write_ptr, write_info_ptr, background); + } + } +#endif +#ifdef PNG_hIST_SUPPORTED + { + png_uint_16p hist; + + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) + png_set_hIST(write_ptr, write_info_ptr, hist); + } +#endif +#ifdef PNG_oFFs_SUPPORTED + { + png_int_32 offset_x, offset_y; + int unit_type; + + if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, + &unit_type)) + { + png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } + } +#endif +#ifdef PNG_pCAL_SUPPORTED + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; + + if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, + &nparams, &units, ¶ms)) + { + png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, + nparams, units, params); + } + } +#endif +#ifdef PNG_pHYs_SUPPORTED + { + png_uint_32 res_x, res_y; + int unit_type; + + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); + } +#endif +#ifdef PNG_sBIT_SUPPORTED + { + png_color_8p sig_bit; + + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) + png_set_sBIT(write_ptr, write_info_ptr, sig_bit); + } +#endif +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + { + int unit; + double scal_width, scal_height; + + if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + { + int unit; + png_charp scal_width, scal_height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, + scal_height); + } + } +#endif +#endif +#endif +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); + png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); + } + } +#endif +#ifdef PNG_tIME_SUPPORTED + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_info_ptr, mod_time); +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* We have to use png_memcpy instead of "=" because the string + * pointed to by png_convert_to_rfc1123() gets free'ed before + * we use it. + */ + png_memcpy(tIME_string, + png_convert_to_rfc1123(read_ptr, mod_time), + png_sizeof(tIME_string)); + tIME_string[png_sizeof(tIME_string) - 1] = '\0'; + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#ifdef PNG_tRNS_SUPPORTED + { + png_bytep trans; + int num_trans; + png_color_16p trans_values; + + if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, + &trans_values)) + { + int sample_max = (1 << bit_depth); + /* libpng doesn't reject a tRNS chunk with out-of-range samples */ + if (!((color_type == PNG_COLOR_TYPE_GRAY && + (int)trans_values->gray > sample_max) || + (color_type == PNG_COLOR_TYPE_RGB && + ((int)trans_values->red > sample_max || + (int)trans_values->green > sample_max || + (int)trans_values->blue > sample_max)))) + png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, + trans_values); + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); + /* Copy the locations from the read_info_ptr. The automatically + * generated locations in write_info_ptr are wrong because we + * haven't written anything yet. + */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, + unknowns[i].location); + } + } +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Writing info struct"); + +/* If we wanted, we could write info in two steps: + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + */ + png_write_info(write_ptr, write_info_ptr); + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + if (user_chunk_data[0] != 0) + { + png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; + + unsigned char + ster_chunk_data[1]; + + if (verbose) + fprintf(STDERR, "\n stereo mode = %lu\n", + (unsigned long)(user_chunk_data[0] - 1)); + ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1); + png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1); + } + if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0) + { + png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; + + unsigned char + vpag_chunk_data[9]; + + if (verbose) + fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n", + (unsigned long)user_chunk_data[1], + (unsigned long)user_chunk_data[2], + (unsigned long)user_chunk_data[3]); + png_save_uint_32(vpag_chunk_data, user_chunk_data[1]); + png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]); + vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff); + png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); + } + +#endif +#endif + +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(0, "Allocating row buffer..."); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug1(0, "0x%08lx", (unsigned long)row_buf); +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(0, "Writing row data"); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) + num_pass = png_set_interlace_handling(read_ptr); +# ifdef PNG_WRITE_SUPPORTED + png_set_interlace_handling(write_ptr); +# endif +#else + num_pass = 1; +#endif + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; +#endif + for (pass = 0; pass < num_pass; pass++) + { + png_debug1(0, "Writing row data for pass %d", pass); + for (y = 0; y < height; y++) + { +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, + png_get_rowbytes(read_ptr, read_info_ptr)); +#endif /* !SINGLE_ROWBUF_ALLOC */ + png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_decode += (t_stop - t_start); + t_start = t_stop; +#endif + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_encode += (t_stop - t_start); + t_start = t_stop; +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); + png_free(read_ptr, row_buf); + row_buf = NULL; +#endif /* !SINGLE_ROWBUF_ALLOC */ + } + } + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); +#endif + + png_debug(0, "Reading and writing end_info data"); + + png_read_end(read_ptr, end_info_ptr); +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); + png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); + } + } +#endif +#ifdef PNG_tIME_SUPPORTED + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_end_info_ptr, mod_time); +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* We have to use png_memcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_memcpy(tIME_string, + png_convert_to_rfc1123(read_ptr, mod_time), + png_sizeof(tIME_string)); + tIME_string[png_sizeof(tIME_string) - 1] = '\0'; + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + { + png_unknown_chunkp unknowns; + int num_unknowns; + num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, + num_unknowns); + /* Copy the locations from the read_info_ptr. The automatically + * generated locations in write_end_info_ptr are wrong because we + * haven't written the end_info yet. + */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, + unknowns[i].location); + } + } +#endif +#ifdef PNG_WRITE_SUPPORTED + png_write_end(write_ptr, write_end_info_ptr); +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED + if (verbose) + { + png_uint_32 iwidth, iheight; + iwidth = png_get_image_width(write_ptr, write_info_ptr); + iheight = png_get_image_height(write_ptr, write_info_ptr); + fprintf(STDERR, "\n Image width = %lu, height = %lu\n", + (unsigned long)iwidth, (unsigned long)iheight); + } +#endif + + png_debug(0, "Destroying data structs"); +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(1, "destroying row_buf for read_ptr"); + png_free(read_ptr, row_buf); + row_buf = NULL; +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_debug(1, "destroying write_end_info_ptr"); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_debug(1, "destroying write_ptr, write_info_ptr"); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + png_debug(0, "Destruction complete."); + + FCLOSE(fpin); + FCLOSE(fpout); + + png_debug(0, "Opening files for comparison"); +#ifdef _WIN32_WCE + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, + 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", inname); + return (1); + } + +#ifdef _WIN32_WCE + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, + 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + for (;;) + { + png_size_t num_in, num_out; + + READFILE(fpin, inbuf, 1, num_in); + READFILE(fpout, outbuf, 1, num_out); + + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); + if (wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + + if (!num_in) + break; + + if (png_memcmp(inbuf, outbuf, num_in)) + { + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); + if (wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + } + + FCLOSE(fpin); + FCLOSE(fpout); + + return (0); +} + +/* Input and output filenames */ +#ifdef RISCOS +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; +#else +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; +#endif + +int +main(int argc, char *argv[]) +{ + int multiple = 0; + int ierror = 0; + + fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); + fprintf(STDERR, "%s", png_get_copyright(NULL)); + /* Show the version of libpng used in building the library */ + fprintf(STDERR, " library (%lu):%s", + (unsigned long)png_access_version_number(), + png_get_header_version(NULL)); + /* Show the version of libpng used in building the application */ + fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, + PNG_HEADER_VERSION_STRING); + fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n", + (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); + + /* Do some consistency checking on the memory allocation settings, I'm + * not sure this matters, but it is nice to know, the first of these + * tests should be impossible because of the way the macros are set + * in pngconf.h + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); +#endif + /* I think the following can happen. */ +#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); +#endif + + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) + { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + ++ierror; + } + + if (argc > 1) + { + if (strcmp(argv[1], "-m") == 0) + { + multiple = 1; + status_dots_requested = 0; + } + else if (strcmp(argv[1], "-mv") == 0 || + strcmp(argv[1], "-vm") == 0 ) + { + multiple = 1; + verbose = 1; + status_dots_requested = 1; + } + else if (strcmp(argv[1], "-v") == 0) + { + verbose = 1; + status_dots_requested = 1; + inname = argv[2]; + } + else + { + inname = argv[1]; + status_dots_requested = 0; + } + } + + if (!multiple && argc == 3 + verbose) + outname = argv[2 + verbose]; + + if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) + { + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); + } + + if (multiple) + { + int i; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + for (i=2; isize, + (unsigned int) pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + else + { + int i; + for (i = 0; i<3; ++i) + { + int kerror; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + if (i == 1) status_dots_requested = 1; + else if (verbose == 0)status_dots_requested = 0; + if (i == 0 || verbose == 1 || ierror != 0) + fprintf(STDERR, "\n Testing %s:", inname); + kerror = test_one_file(inname, outname); + if (kerror == 0) + { + if (verbose == 1 || i == 2) + { +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + int k; +#endif +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + fprintf(STDERR, "\n PASS (%lu zero samples)\n", + (unsigned long)zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + for (k = 0; k<256; k++) + if (filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k, (unsigned long)filters_used[k]); +#endif +#ifdef PNG_TIME_RFC1123_SUPPORTED + if (tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n", tIME_string); +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } + else + { + if (verbose == 0 && i != 2) + fprintf(STDERR, "\n Testing %s:", inname); + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation - allocation_now); + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) + { + fprintf(STDERR, " %lu bytes at %x\n", + (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; + fprintf(STDERR, " CPU time used = %.3f seconds", + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " (decoding %.3f,\n", + t_decode/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " encoding %.3f ,", + t_encode/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " other %.3f seconds)\n\n", + t_misc/(float)CLOCKS_PER_SEC); +#endif + + if (ierror == 0) + fprintf(STDERR, " libpng passes test\n"); + else + fprintf(STDERR, " libpng FAILS test\n"); + return (int)(ierror != 0); +} + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_2_51 your_png_h_is_not_version_1_2_51; diff --git a/main/source/includes/lpng1251/pngtrans.c b/main/source/includes/lpng1251/pngtrans.c index 2122839b..6ad9dcf6 100644 --- a/main/source/includes/lpng1251/pngtrans.c +++ b/main/source/includes/lpng1251/pngtrans.c @@ -1,699 +1,699 @@ - -/* pngtrans.c - transforms the data in a row (used by both readers and writers) - * - * Last changed in libpng 1.2.41 [December 3, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Turn on BGR-to-RGB mapping */ -void PNGAPI -png_set_bgr(png_structp png_ptr) -{ - png_debug(1, "in png_set_bgr"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_BGR; -} -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Turn on 16 bit byte swapping */ -void PNGAPI -png_set_swap(png_structp png_ptr) -{ - png_debug(1, "in png_set_swap"); - - if (png_ptr == NULL) - return; - if (png_ptr->bit_depth == 16) - png_ptr->transformations |= PNG_SWAP_BYTES; -} -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) -/* Turn on pixel packing */ -void PNGAPI -png_set_packing(png_structp png_ptr) -{ - png_debug(1, "in png_set_packing"); - - if (png_ptr == NULL) - return; - if (png_ptr->bit_depth < 8) - { - png_ptr->transformations |= PNG_PACK; - png_ptr->usr_bit_depth = 8; - } -} -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) -/* Turn on packed pixel swapping */ -void PNGAPI -png_set_packswap(png_structp png_ptr) -{ - png_debug(1, "in png_set_packswap"); - - if (png_ptr == NULL) - return; - if (png_ptr->bit_depth < 8) - png_ptr->transformations |= PNG_PACKSWAP; -} -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) -void PNGAPI -png_set_shift(png_structp png_ptr, png_color_8p true_bits) -{ - png_debug(1, "in png_set_shift"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_SHIFT; - png_ptr->shift = *true_bits; -} -#endif - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) -int PNGAPI -png_set_interlace_handling(png_structp png_ptr) -{ - png_debug(1, "in png_set_interlace handling"); - - if (png_ptr && png_ptr->interlaced) - { - png_ptr->transformations |= PNG_INTERLACE; - return (7); - } - - return (1); -} -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -/* Add a filler byte on read, or remove a filler or alpha byte on write. - * The filler type has changed in v0.95 to allow future 2-byte fillers - * for 48-bit input data, as well as to avoid problems with some compilers - * that don't like bytes as parameters. - */ -void PNGAPI -png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) -{ - png_debug(1, "in png_set_filler"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_FILLER; -#ifdef PNG_LEGACY_SUPPORTED - png_ptr->filler = (png_byte)filler; -#else - png_ptr->filler = (png_uint_16)filler; -#endif - if (filler_loc == PNG_FILLER_AFTER) - png_ptr->flags |= PNG_FLAG_FILLER_AFTER; - else - png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; - - /* This should probably go in the "do_read_filler" routine. - * I attempted to do that in libpng-1.0.1a but that caused problems - * so I restored it in libpng-1.0.2a - */ - - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_ptr->usr_channels = 4; - } - - /* Also I added this in libpng-1.0.2a (what happens when we expand - * a less-than-8-bit grayscale to GA? */ - - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) - { - png_ptr->usr_channels = 2; - } -} - -#ifndef PNG_1_0_X -/* Added to libpng-1.2.7 */ -void PNGAPI -png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) -{ - png_debug(1, "in png_set_add_alpha"); - - if (png_ptr == NULL) - return; - png_set_filler(png_ptr, filler, filler_loc); - png_ptr->transformations |= PNG_ADD_ALPHA; -} -#endif - -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -void PNGAPI -png_set_swap_alpha(png_structp png_ptr) -{ - png_debug(1, "in png_set_swap_alpha"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_SWAP_ALPHA; -} -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -void PNGAPI -png_set_invert_alpha(png_structp png_ptr) -{ - png_debug(1, "in png_set_invert_alpha"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_INVERT_ALPHA; -} -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -void PNGAPI -png_set_invert_mono(png_structp png_ptr) -{ - png_debug(1, "in png_set_invert_mono"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_INVERT_MONO; -} - -/* Invert monochrome grayscale data */ -void /* PRIVATE */ -png_do_invert(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_invert"); - - /* This test removed from libpng version 1.0.13 and 1.2.0: - * if (row_info->bit_depth == 1 && - */ -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row == NULL || row_info == NULL) - return; -#endif - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(~(*rp)); - rp++; - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - row_info->bit_depth == 8) - { - png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - - for (i = 0; i < istop; i+=2) - { - *rp = (png_byte)(~(*rp)); - rp+=2; - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - row_info->bit_depth == 16) - { - png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - - for (i = 0; i < istop; i+=4) - { - *rp = (png_byte)(~(*rp)); - *(rp+1) = (png_byte)(~(*(rp+1))); - rp+=4; - } - } -} -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Swaps byte order on 16 bit depth images */ -void /* PRIVATE */ -png_do_swap(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_swap"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - row_info->bit_depth == 16) - { - png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop= row_info->width * row_info->channels; - - for (i = 0; i < istop; i++, rp += 2) - { - png_byte t = *rp; - *rp = *(rp + 1); - *(rp + 1) = t; - } - } -} -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) -static PNG_CONST png_byte onebppswaptable[256] = { - 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, - 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, - 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, - 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, - 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, - 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, - 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, - 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, - 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, - 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, - 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, - 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, - 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, - 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, - 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, - 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, - 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, - 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, - 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, - 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, - 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, - 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, - 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, - 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, - 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, - 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, - 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, - 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, - 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, - 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, - 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, - 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF -}; - -static PNG_CONST png_byte twobppswaptable[256] = { - 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, - 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, - 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, - 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, - 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, - 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, - 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, - 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, - 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, - 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, - 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, - 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, - 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, - 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, - 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, - 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, - 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, - 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, - 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, - 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, - 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, - 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, - 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, - 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, - 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, - 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, - 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, - 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, - 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, - 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, - 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, - 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF -}; - -static PNG_CONST png_byte fourbppswaptable[256] = { - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, - 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, - 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, - 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, - 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, - 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, - 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, - 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, - 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, - 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, - 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, - 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, - 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, - 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, - 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, - 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, - 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, - 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, - 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, - 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, - 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, - 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, - 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, - 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, - 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, - 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, - 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, - 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, - 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, - 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, - 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, - 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF -}; - -/* Swaps pixel packing order within bytes */ -void /* PRIVATE */ -png_do_packswap(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_packswap"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - row_info->bit_depth < 8) - { - png_bytep rp, end, table; - - end = row + row_info->rowbytes; - - if (row_info->bit_depth == 1) - table = (png_bytep)onebppswaptable; - else if (row_info->bit_depth == 2) - table = (png_bytep)twobppswaptable; - else if (row_info->bit_depth == 4) - table = (png_bytep)fourbppswaptable; - else - return; - - for (rp = row; rp < end; rp++) - *rp = table[*rp]; - } -} -#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ - -#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ - defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -/* Remove filler or alpha byte(s) */ -void /* PRIVATE */ -png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) -{ - png_debug(1, "in png_do_strip_filler"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - png_bytep sp=row; - png_bytep dp=row; - png_uint_32 row_width=row_info->width; - png_uint_32 i; - - if ((row_info->color_type == PNG_COLOR_TYPE_RGB || - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - (flags & PNG_FLAG_STRIP_ALPHA))) && - row_info->channels == 4) - { - if (row_info->bit_depth == 8) - { - /* This converts from RGBX or RGBA to RGB */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - dp+=3; sp+=4; - for (i = 1; i < row_width; i++) - { - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - sp++; - } - } - /* This converts from XRGB or ARGB to RGB */ - else - { - for (i = 0; i < row_width; i++) - { - sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - } - } - row_info->pixel_depth = 24; - row_info->rowbytes = row_width * 3; - } - else /* if (row_info->bit_depth == 16) */ - { - if (flags & PNG_FLAG_FILLER_AFTER) - { - /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */ - sp += 8; dp += 6; - for (i = 1; i < row_width; i++) - { - /* This could be (although png_memcpy is probably slower): - png_memcpy(dp, sp, 6); - sp += 8; - dp += 6; - */ - - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - sp += 2; - } - } - else - { - /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */ - for (i = 0; i < row_width; i++) - { - /* This could be (although png_memcpy is probably slower): - png_memcpy(dp, sp, 6); - sp += 8; - dp += 6; - */ - - sp+=2; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - *dp++ = *sp++; - } - } - row_info->pixel_depth = 48; - row_info->rowbytes = row_width * 6; - } - row_info->channels = 3; - } - else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY || - (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - (flags & PNG_FLAG_STRIP_ALPHA))) && - row_info->channels == 2) - { - if (row_info->bit_depth == 8) - { - /* This converts from GX or GA to G */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - for (i = 0; i < row_width; i++) - { - *dp++ = *sp++; - sp++; - } - } - /* This converts from XG or AG to G */ - else - { - for (i = 0; i < row_width; i++) - { - sp++; - *dp++ = *sp++; - } - } - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - else /* if (row_info->bit_depth == 16) */ - { - if (flags & PNG_FLAG_FILLER_AFTER) - { - /* This converts from GGXX or GGAA to GG */ - sp += 4; dp += 2; - for (i = 1; i < row_width; i++) - { - *dp++ = *sp++; - *dp++ = *sp++; - sp += 2; - } - } - else - { - /* This converts from XXGG or AAGG to GG */ - for (i = 0; i < row_width; i++) - { - sp += 2; - *dp++ = *sp++; - *dp++ = *sp++; - } - } - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - row_info->channels = 1; - } - if (flags & PNG_FLAG_STRIP_ALPHA) - row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; - } -} -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Swaps red and blue bytes within a pixel */ -void /* PRIVATE */ -png_do_bgr(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_bgr"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 3) - { - png_byte save = *rp; - *rp = *(rp + 2); - *(rp + 2) = save; - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 4) - { - png_byte save = *rp; - *rp = *(rp + 2); - *(rp + 2) = save; - } - } - } - else if (row_info->bit_depth == 16) - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 6) - { - png_byte save = *rp; - *rp = *(rp + 4); - *(rp + 4) = save; - save = *(rp + 1); - *(rp + 1) = *(rp + 5); - *(rp + 5) = save; - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 8) - { - png_byte save = *rp; - *rp = *(rp + 4); - *(rp + 4) = save; - save = *(rp + 1); - *(rp + 1) = *(rp + 5); - *(rp + 5) = save; - } - } - } - } -} -#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -void PNGAPI -png_set_user_transform_info(png_structp png_ptr, png_voidp - user_transform_ptr, int user_transform_depth, int user_transform_channels) -{ - png_debug(1, "in png_set_user_transform_info"); - - if (png_ptr == NULL) - return; -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - png_ptr->user_transform_ptr = user_transform_ptr; - png_ptr->user_transform_depth = (png_byte)user_transform_depth; - png_ptr->user_transform_channels = (png_byte)user_transform_channels; -#else - if (user_transform_ptr || user_transform_depth || user_transform_channels) - png_warning(png_ptr, - "This version of libpng does not support user transform info"); -#endif -} -#endif - -/* This function returns a pointer to the user_transform_ptr associated with - * the user transform functions. The application should free any memory - * associated with this pointer before png_write_destroy and png_read_destroy - * are called. - */ -png_voidp PNGAPI -png_get_user_transform_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - return ((png_voidp)png_ptr->user_transform_ptr); -#else - return (NULL); -#endif -} -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * Last changed in libpng 1.2.41 [December 3, 2009] + * Copyright (c) 1998-2009 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structp png_ptr) +{ + png_debug(1, "in png_set_bgr"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Turn on 16 bit byte swapping */ +void PNGAPI +png_set_swap(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap"); + + if (png_ptr == NULL) + return; + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Turn on pixel packing */ +void PNGAPI +png_set_packing(png_structp png_ptr) +{ + png_debug(1, "in png_set_packing"); + + if (png_ptr == NULL) + return; + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; + png_ptr->usr_bit_depth = 8; + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structp png_ptr) +{ + png_debug(1, "in png_set_packswap"); + + if (png_ptr == NULL) + return; + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structp png_ptr, png_color_8p true_bits) +{ + png_debug(1, "in png_set_shift"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structp png_ptr) +{ + png_debug(1, "in png_set_interlace handling"); + + if (png_ptr && png_ptr->interlaced) + { + png_ptr->transformations |= PNG_INTERLACE; + return (7); + } + + return (1); +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_FILLER; +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->filler = (png_byte)filler; +#else + png_ptr->filler = (png_uint_16)filler; +#endif + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; + + /* This should probably go in the "do_read_filler" routine. + * I attempted to do that in libpng-1.0.1a but that caused problems + * so I restored it in libpng-1.0.2a + */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_ptr->usr_channels = 4; + } + + /* Also I added this in libpng-1.0.2a (what happens when we expand + * a less-than-8-bit grayscale to GA? */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + } +} + +#ifndef PNG_1_0_X +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha"); + + if (png_ptr == NULL) + return; + png_set_filler(png_ptr, filler, filler_loc); + png_ptr->transformations |= PNG_ADD_ALPHA; +} +#endif + +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_mono"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* Invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert"); + + /* This test removed from libpng version 1.0.13 and 1.2.0: + * if (row_info->bit_depth == 1 && + */ +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row == NULL || row_info == NULL) + return; +#endif + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 8) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i+=2) + { + *rp = (png_byte)(~(*rp)); + rp+=2; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i+=4) + { + *rp = (png_byte)(~(*rp)); + *(rp+1) = (png_byte)(~(*(rp+1))); + rp+=4; + } + } +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swaps byte order on 16 bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; + } + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static PNG_CONST png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static PNG_CONST png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static PNG_CONST png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* Swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + row_info->bit_depth < 8) + { + png_bytep rp, end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = (png_bytep)onebppswaptable; + else if (row_info->bit_depth == 2) + table = (png_bytep)twobppswaptable; + else if (row_info->bit_depth == 4) + table = (png_bytep)fourbppswaptable; + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* Remove filler or alpha byte(s) */ +void /* PRIVATE */ +png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) +{ + png_debug(1, "in png_do_strip_filler"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + png_bytep sp=row; + png_bytep dp=row; + png_uint_32 row_width=row_info->width; + png_uint_32 i; + + if ((row_info->color_type == PNG_COLOR_TYPE_RGB || + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + /* This converts from RGBX or RGBA to RGB */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + dp+=3; sp+=4; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp++; + } + } + /* This converts from XRGB or ARGB to RGB */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */ + sp += 8; dp += 6; + for (i = 1; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */ + for (i = 0; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + sp+=2; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 48; + row_info->rowbytes = row_width * 6; + } + row_info->channels = 3; + } + else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY || + (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + /* This converts from GX or GA to G */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + for (i = 0; i < row_width; i++) + { + *dp++ = *sp++; + sp++; + } + } + /* This converts from XG or AG to G */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from GGXX or GGAA to GG */ + sp += 4; dp += 2; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXGG or AAGG to GG */ + for (i = 0; i < row_width; i++) + { + sp += 2; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + row_info->channels = 1; + } + if (flags & PNG_FLAG_STRIP_ALPHA) + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + } +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } + } +} +#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_user_transform_info(png_structp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info"); + + if (png_ptr == NULL) + return; +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +#else + if (user_transform_ptr || user_transform_depth || user_transform_channels) + png_warning(png_ptr, + "This version of libpng does not support user transform info"); +#endif +} +#endif + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +png_voidp PNGAPI +png_get_user_transform_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + return ((png_voidp)png_ptr->user_transform_ptr); +#else + return (NULL); +#endif +} +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngvcrd.c b/main/source/includes/lpng1251/pngvcrd.c index 5792af3e..f5531388 100644 --- a/main/source/includes/lpng1251/pngvcrd.c +++ b/main/source/includes/lpng1251/pngvcrd.c @@ -1,12 +1,12 @@ -/* pngvcrd.c - * - * Last changed in libpng 1.2.48 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This nearly empty file is for use by configure's compilation test. The - * remainder of the file was removed from libpng-1.2.20. - */ +/* pngvcrd.c + * + * Last changed in libpng 1.2.48 [March 8, 2012] + * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This nearly empty file is for use by configure's compilation test. The + * remainder of the file was removed from libpng-1.2.20. + */ diff --git a/main/source/includes/lpng1251/pngwio.c b/main/source/includes/lpng1251/pngwio.c index 9ca65d6f..44e5ea91 100644 --- a/main/source/includes/lpng1251/pngwio.c +++ b/main/source/includes/lpng1251/pngwio.c @@ -1,260 +1,260 @@ - -/* pngwio.c - functions for data output - * - * Last changed in libpng 1.2.41 [December 3, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all output. Users who need - * special handling are expected to write functions that have the same - * arguments as these and perform similar functions, but that possibly - * use different output methods. Note that you shouldn't change these - * functions, but rather write replacement functions and then change - * them at run time with png_set_write_fn(...). - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED - -/* Write the data to whatever output you are using. The default routine - * writes to a file pointer. Note that this routine sometimes gets called - * with very small lengths, so you should implement some kind of simple - * buffering if you are using unbuffered writes. This should never be asked - * to write more than 64K on a 16 bit machine. - */ - -void /* PRIVATE */ -png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - if (png_ptr->write_data_fn != NULL ) - (*(png_ptr->write_data_fn))(png_ptr, data, length); - else - png_error(png_ptr, "Call to NULL write function"); -} - -#ifdef PNG_STDIO_SUPPORTED -/* This is the function that does the actual writing of data. If you are - * not writing to a standard C stream, you should create a replacement - * write_data function and use it at run time with png_set_write_fn(), rather - * than changing the library. - */ -#ifndef USE_FAR_KEYWORD -void PNGAPI -png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - - if (png_ptr == NULL) - return; -#ifdef _WIN32_WCE - if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) - check = 0; -#else - check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); -#endif - if (check != length) - png_error(png_ptr, "Write Error"); -} -#else -/* This is the model-independent version. Since the standard I/O library - * can't handle far buffers in the medium and small models, we have to copy - * the data. - */ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -void PNGAPI -png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - /* Check if data really is near. If so, use usual code. */ - near_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)near_data == data) - { -#ifdef _WIN32_WCE - if ( !WriteFile(io_ptr, near_data, length, &check, NULL) ) - check = 0; -#else - check = fwrite(near_data, 1, length, io_ptr); -#endif - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t written, remaining, err; - check = 0; - remaining = length; - do - { - written = MIN(NEAR_BUF_SIZE, remaining); - png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ -#ifdef _WIN32_WCE - if ( !WriteFile(io_ptr, buf, written, &err, NULL) ) - err = 0; -#else - err = fwrite(buf, 1, written, io_ptr); -#endif - if (err != written) - break; - - else - check += err; - - data += written; - remaining -= written; - } - while (remaining != 0); - } - if (check != length) - png_error(png_ptr, "Write Error"); -} - -#endif -#endif - -/* This function is called to output any data pending writing (normally - * to disk). After png_flush is called, there should be no data pending - * writing in any buffers. - */ -#ifdef PNG_WRITE_FLUSH_SUPPORTED -void /* PRIVATE */ -png_flush(png_structp png_ptr) -{ - if (png_ptr->output_flush_fn != NULL) - (*(png_ptr->output_flush_fn))(png_ptr); -} - -#ifdef PNG_STDIO_SUPPORTED -void PNGAPI -png_default_flush(png_structp png_ptr) -{ -#ifndef _WIN32_WCE - png_FILE_p io_ptr; -#endif - if (png_ptr == NULL) - return; -#ifndef _WIN32_WCE - io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); - fflush(io_ptr); -#endif -} -#endif -#endif - -/* This function allows the application to supply new output functions for - * libpng if standard C streams aren't being used. - * - * This function takes as its arguments: - * png_ptr - pointer to a png output data structure - * io_ptr - pointer to user supplied structure containing info about - * the output functions. May be NULL. - * write_data_fn - pointer to a new output function that takes as its - * arguments a pointer to a png_struct, a pointer to - * data to be written, and a 32-bit unsigned int that is - * the number of bytes to be written. The new write - * function should call png_error(png_ptr, "Error msg") - * to exit and output any fatal error messages. May be - * NULL, in which case libpng's default function will - * be used. - * flush_data_fn - pointer to a new flush function that takes as its - * arguments a pointer to a png_struct. After a call to - * the flush function, there should be no data in any buffers - * or pending transmission. If the output method doesn't do - * any buffering of output, a function prototype must still be - * supplied although it doesn't have to do anything. If - * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile - * time, output_flush_fn will be ignored, although it must be - * supplied for compatibility. May be NULL, in which case - * libpng's default function will be used, if - * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not - * a good idea if io_ptr does not point to a standard - * *FILE structure. - */ -void PNGAPI -png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, - png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->io_ptr = io_ptr; - -#ifdef PNG_STDIO_SUPPORTED - if (write_data_fn != NULL) - png_ptr->write_data_fn = write_data_fn; - - else - png_ptr->write_data_fn = png_default_write_data; -#else - png_ptr->write_data_fn = write_data_fn; -#endif - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -#ifdef PNG_STDIO_SUPPORTED - if (output_flush_fn != NULL) - png_ptr->output_flush_fn = output_flush_fn; - - else - png_ptr->output_flush_fn = png_default_flush; -#else - png_ptr->output_flush_fn = output_flush_fn; -#endif -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - - /* It is an error to read while writing a png file */ - if (png_ptr->read_data_fn != NULL) - { - png_ptr->read_data_fn = NULL; - png_warning(png_ptr, - "Attempted to set both read_data_fn and write_data_fn in"); - png_warning(png_ptr, - "the same structure. Resetting read_data_fn to NULL."); - } -} - -#ifdef USE_FAR_KEYWORD -#ifdef _MSC_VER -void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) -{ - void *near_ptr; - void FAR *far_ptr; - FP_OFF(near_ptr) = FP_OFF(ptr); - far_ptr = (void FAR *)near_ptr; - - if (check != 0) - if (FP_SEG(ptr) != FP_SEG(far_ptr)) - png_error(png_ptr, "segment lost in conversion"); - - return(near_ptr); -} -# else -void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) -{ - void *near_ptr; - void FAR *far_ptr; - near_ptr = (void FAR *)ptr; - far_ptr = (void FAR *)near_ptr; - - if (check != 0) - if (far_ptr != ptr) - png_error(png_ptr, "segment lost in conversion"); - - return(near_ptr); -} -# endif -# endif -#endif /* PNG_WRITE_SUPPORTED */ + +/* pngwio.c - functions for data output + * + * Last changed in libpng 1.2.41 [December 3, 2009] + * Copyright (c) 1998-2009 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Write the data to whatever output you are using. The default routine + * writes to a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered writes. This should never be asked + * to write more than 64K on a 16 bit machine. + */ + +void /* PRIVATE */ +png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL write function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + + if (png_ptr == NULL) + return; +#ifdef _WIN32_WCE + if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); +#endif + if (check != length) + png_error(png_ptr, "Write Error"); +} +#else +/* This is the model-independent version. Since the standard I/O library + * can't handle far buffers in the medium and small models, we have to copy + * the data. + */ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + if (png_ptr == NULL) + return; + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { +#ifdef _WIN32_WCE + if ( !WriteFile(io_ptr, near_data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(near_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ +#ifdef _WIN32_WCE + if ( !WriteFile(io_ptr, buf, written, &err, NULL) ) + err = 0; +#else + err = fwrite(buf, 1, written, io_ptr); +#endif + if (err != written) + break; + + else + check += err; + + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "Write Error"); +} + +#endif +#endif + +/* This function is called to output any data pending writing (normally + * to disk). After png_flush is called, there should be no data pending + * writing in any buffers. + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void /* PRIVATE */ +png_flush(png_structp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +#ifdef PNG_STDIO_SUPPORTED +void PNGAPI +png_default_flush(png_structp png_ptr) +{ +#ifndef _WIN32_WCE + png_FILE_p io_ptr; +#endif + if (png_ptr == NULL) + return; +#ifndef _WIN32_WCE + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + fflush(io_ptr); +#endif +} +#endif +#endif + +/* This function allows the application to supply new output functions for + * libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png output data structure + * io_ptr - pointer to user supplied structure containing info about + * the output functions. May be NULL. + * write_data_fn - pointer to a new output function that takes as its + * arguments a pointer to a png_struct, a pointer to + * data to be written, and a 32-bit unsigned int that is + * the number of bytes to be written. The new write + * function should call png_error(png_ptr, "Error msg") + * to exit and output any fatal error messages. May be + * NULL, in which case libpng's default function will + * be used. + * flush_data_fn - pointer to a new flush function that takes as its + * arguments a pointer to a png_struct. After a call to + * the flush function, there should be no data in any buffers + * or pending transmission. If the output method doesn't do + * any buffering of output, a function prototype must still be + * supplied although it doesn't have to do anything. If + * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + * time, output_flush_fn will be ignored, although it must be + * supplied for compatibility. May be NULL, in which case + * libpng's default function will be used, if + * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not + * a good idea if io_ptr does not point to a standard + * *FILE structure. + */ +void PNGAPI +png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + + else + png_ptr->output_flush_fn = png_default_flush; +#else + png_ptr->output_flush_fn = output_flush_fn; +#endif +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + png_warning(png_ptr, + "Attempted to set both read_data_fn and write_data_fn in"); + png_warning(png_ptr, + "the same structure. Resetting read_data_fn to NULL."); + } +} + +#ifdef USE_FAR_KEYWORD +#ifdef _MSC_VER +void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + FP_OFF(near_ptr) = FP_OFF(ptr); + far_ptr = (void FAR *)near_ptr; + + if (check != 0) + if (FP_SEG(ptr) != FP_SEG(far_ptr)) + png_error(png_ptr, "segment lost in conversion"); + + return(near_ptr); +} +# else +void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + near_ptr = (void FAR *)ptr; + far_ptr = (void FAR *)near_ptr; + + if (check != 0) + if (far_ptr != ptr) + png_error(png_ptr, "segment lost in conversion"); + + return(near_ptr); +} +# endif +# endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngwrite.c b/main/source/includes/lpng1251/pngwrite.c index 0bdd2ba6..1d94404d 100644 --- a/main/source/includes/lpng1251/pngwrite.c +++ b/main/source/includes/lpng1251/pngwrite.c @@ -1,1593 +1,1593 @@ - -/* pngwrite.c - general routines to write a PNG file - * - * Last changed in libpng 1.2.51 [February 6, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -/* Get internal access to png.h */ -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED - -/* Writes all the PNG information. This is the suggested way to use the - * library. If you have a new chunk to add, make a function to write it, - * and put it in the correct location here. If you want the chunk written - * after the image data, put it in png_write_end(). I strongly encourage - * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing - * the chunk, as that will keep the code from breaking if you want to just - * write a plain PNG file. If you have long comments, I suggest writing - * them in png_write_end(), and compressing them. - */ -void PNGAPI -png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_write_info_before_PLTE"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) - { - /* Write PNG signature */ - png_write_sig(png_ptr); -#ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ - (png_ptr->mng_features_permitted)) - { - png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); - png_ptr->mng_features_permitted = 0; - } -#endif - /* Write IHDR information. */ - png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, - info_ptr->filter_type, -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - info_ptr->interlace_type); -#else - 0); -#endif - /* The rest of these check to see if the valid field has the appropriate - * flag set, and if it does, writes the chunk. - */ -#ifdef PNG_WRITE_gAMA_SUPPORTED - if (info_ptr->valid & PNG_INFO_gAMA) - { -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_write_gAMA(png_ptr, info_ptr->gamma); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); -# endif -#endif - } -#endif -#ifdef PNG_WRITE_sRGB_SUPPORTED - if (info_ptr->valid & PNG_INFO_sRGB) - png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); -#endif -#ifdef PNG_WRITE_iCCP_SUPPORTED - if (info_ptr->valid & PNG_INFO_iCCP) - png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, - info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); -#endif -#ifdef PNG_WRITE_sBIT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sBIT) - png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); -#endif -#ifdef PNG_WRITE_cHRM_SUPPORTED - if (info_ptr->valid & PNG_INFO_cHRM) - { -#ifdef PNG_FLOATING_POINT_SUPPORTED - png_write_cHRM(png_ptr, - info_ptr->x_white, info_ptr->y_white, - info_ptr->x_red, info_ptr->y_red, - info_ptr->x_green, info_ptr->y_green, - info_ptr->x_blue, info_ptr->y_blue); -#else -# ifdef PNG_FIXED_POINT_SUPPORTED - png_write_cHRM_fixed(png_ptr, - info_ptr->int_x_white, info_ptr->int_y_white, - info_ptr->int_x_red, info_ptr->int_y_red, - info_ptr->int_x_green, info_ptr->int_y_green, - info_ptr->int_x_blue, info_ptr->int_y_blue); -# endif -#endif - } -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && !(up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - if (up->size == 0) - png_warning(png_ptr, "Writing zero-length unknown chunk"); - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } -#endif - png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; - } -} - -void PNGAPI -png_write_info(png_structp png_ptr, png_infop info_ptr) -{ -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) - int i; -#endif - - png_debug(1, "in png_write_info"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_write_info_before_PLTE(png_ptr, info_ptr); - - if (info_ptr->valid & PNG_INFO_PLTE) - png_write_PLTE(png_ptr, info_ptr->palette, - (png_uint_32)info_ptr->num_palette); - else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - png_error(png_ptr, "Valid palette required for paletted images"); - -#ifdef PNG_WRITE_tRNS_SUPPORTED - if (info_ptr->valid & PNG_INFO_tRNS) - { -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel (in tRNS) */ - if ((png_ptr->transformations & PNG_INVERT_ALPHA) && - info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - int j; - for (j = 0; j<(int)info_ptr->num_trans; j++) - info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); - } -#endif - png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), - info_ptr->num_trans, info_ptr->color_type); - } -#endif -#ifdef PNG_WRITE_bKGD_SUPPORTED - if (info_ptr->valid & PNG_INFO_bKGD) - png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); -#endif -#ifdef PNG_WRITE_hIST_SUPPORTED - if (info_ptr->valid & PNG_INFO_hIST) - png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); -#endif -#ifdef PNG_WRITE_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) - png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, - info_ptr->offset_unit_type); -#endif -#ifdef PNG_WRITE_pCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_pCAL) - png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, - info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, - info_ptr->pcal_units, info_ptr->pcal_params); -#endif - -#ifdef PNG_sCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_sCAL) -#ifdef PNG_WRITE_sCAL_SUPPORTED -#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) - png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, - info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); -#else /* !FLOATING_POINT */ -#ifdef PNG_FIXED_POINT_SUPPORTED - png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, - info_ptr->scal_s_width, info_ptr->scal_s_height); -#endif /* FIXED_POINT */ -#endif /* FLOATING_POINT */ -#else /* !WRITE_sCAL */ - png_warning(png_ptr, - "png_write_sCAL not supported; sCAL chunk not written."); -#endif /* WRITE_sCAL */ -#endif /* sCAL */ - -#ifdef PNG_WRITE_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) - png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, - info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); -#endif /* pHYs */ - -#ifdef PNG_WRITE_tIME_SUPPORTED - if (info_ptr->valid & PNG_INFO_tIME) - { - png_write_tIME(png_ptr, &(info_ptr->mod_time)); - png_ptr->mode |= PNG_WROTE_tIME; - } -#endif /* tIME */ - -#ifdef PNG_WRITE_sPLT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sPLT) - for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) - png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); -#endif /* sPLT */ - -#ifdef PNG_WRITE_TEXT_SUPPORTED - /* Check to see if we need to write text chunks */ - for (i = 0; i < info_ptr->num_text; i++) - { - png_debug2(2, "Writing header text chunk %d, type %d", i, - info_ptr->text[i].compression); - /* An internationalized chunk? */ - if (info_ptr->text[i].compression > 0) - { -#ifdef PNG_WRITE_iTXt_SUPPORTED - /* Write international chunk */ - png_write_iTXt(png_ptr, - info_ptr->text[i].compression, - info_ptr->text[i].key, - info_ptr->text[i].lang, - info_ptr->text[i].lang_key, - info_ptr->text[i].text); -#else - png_warning(png_ptr, "Unable to write international text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - } - /* If we want a compressed text chunk */ - else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) - { -#ifdef PNG_WRITE_zTXt_SUPPORTED - /* Write compressed chunk */ - png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); -#else - png_warning(png_ptr, "Unable to write compressed text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; - } - else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) - { -#ifdef PNG_WRITE_tEXt_SUPPORTED - /* Write uncompressed chunk */ - png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, - 0); - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; -#else - /* Can't get here */ - png_warning(png_ptr, "Unable to write uncompressed text"); -#endif - } - } -#endif /* tEXt */ - -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && (up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - !(up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } -#endif -} - -/* Writes the end of the PNG file. If you don't want to write comments or - * time information, you can pass NULL for info. If you already wrote these - * in png_write_info(), do not write them again here. If you have long - * comments, I suggest writing them here, and compressing them. - */ -void PNGAPI -png_write_end(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_write_end"); - - if (png_ptr == NULL) - return; - if (!(png_ptr->mode & PNG_HAVE_IDAT)) - png_error(png_ptr, "No IDATs written into file"); - - /* See if user wants us to write information chunks */ - if (info_ptr != NULL) - { -#ifdef PNG_WRITE_TEXT_SUPPORTED - int i; /* local index variable */ -#endif -#ifdef PNG_WRITE_tIME_SUPPORTED - /* Check to see if user has supplied a time chunk */ - if ((info_ptr->valid & PNG_INFO_tIME) && - !(png_ptr->mode & PNG_WROTE_tIME)) - png_write_tIME(png_ptr, &(info_ptr->mod_time)); -#endif -#ifdef PNG_WRITE_TEXT_SUPPORTED - /* Loop through comment chunks */ - for (i = 0; i < info_ptr->num_text; i++) - { - png_debug2(2, "Writing trailer text chunk %d, type %d", i, - info_ptr->text[i].compression); - /* An internationalized chunk? */ - if (info_ptr->text[i].compression > 0) - { -#ifdef PNG_WRITE_iTXt_SUPPORTED - /* Write international chunk */ - png_write_iTXt(png_ptr, - info_ptr->text[i].compression, - info_ptr->text[i].key, - info_ptr->text[i].lang, - info_ptr->text[i].lang_key, - info_ptr->text[i].text); -#else - png_warning(png_ptr, "Unable to write international text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - } - else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) - { -#ifdef PNG_WRITE_zTXt_SUPPORTED - /* Write compressed chunk */ - png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); -#else - png_warning(png_ptr, "Unable to write compressed text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; - } - else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) - { -#ifdef PNG_WRITE_tEXt_SUPPORTED - /* Write uncompressed chunk */ - png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0); -#else - png_warning(png_ptr, "Unable to write uncompressed text"); -#endif - - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - } - } -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && (up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } -#endif - } - - png_ptr->mode |= PNG_AFTER_IDAT; - - /* Write end of PNG file */ - png_write_IEND(png_ptr); - /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, - * and restored again in libpng-1.2.30, may cause some applications that - * do not set png_ptr->output_flush_fn to crash. If your application - * experiences a problem, please try building libpng with - * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to - * png-mng-implement at lists.sf.net . - */ -#ifdef PNG_WRITE_FLUSH_SUPPORTED -# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED - png_flush(png_ptr); -# endif -#endif -} - -#ifdef PNG_CONVERT_tIME_SUPPORTED -/* "tm" structure is not supported on WindowsCE */ -void PNGAPI -png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) -{ - png_debug(1, "in png_convert_from_struct_tm"); - - ptime->year = (png_uint_16)(1900 + ttime->tm_year); - ptime->month = (png_byte)(ttime->tm_mon + 1); - ptime->day = (png_byte)ttime->tm_mday; - ptime->hour = (png_byte)ttime->tm_hour; - ptime->minute = (png_byte)ttime->tm_min; - ptime->second = (png_byte)ttime->tm_sec; -} - -void PNGAPI -png_convert_from_time_t(png_timep ptime, time_t ttime) -{ - struct tm *tbuf; - - png_debug(1, "in png_convert_from_time_t"); - - tbuf = gmtime(&ttime); - png_convert_from_struct_tm(ptime, tbuf); -} -#endif - -/* Initialize png_ptr structure, and allocate any memory needed */ -png_structp PNGAPI -png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn) -{ -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); -} - -/* Alternate initialize png_ptr structure, and allocate any memory needed */ -png_structp PNGAPI -png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - int i; - - png_debug(1, "in png_create_write_struct"); - -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif /* PNG_USER_MEM_SUPPORTED */ - if (png_ptr == NULL) - return (NULL); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; -#endif - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_ptr->jmpbuf)) -#endif - { - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, - (png_free_ptr)free_fn, (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - return (NULL); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif - -#ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); -#endif /* PNG_USER_MEM_SUPPORTED */ - png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - - if (user_png_ver) - { - i = 0; - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) - { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first digit. - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char msg[80]; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "Application is running with png.c from libpng-%.20s", - png_libpng_ver); - png_warning(png_ptr, msg); -#endif -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "Incompatible libpng version in application and library"); - } - } - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - - png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, - png_flush_ptr_NULL); - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, - 1, png_doublep_NULL, png_doublep_NULL); -#endif - -#ifdef PNG_SETJMP_SUPPORTED - /* Applications that neglect to set up their own setjmp() and then - * encounter a png_error() will longjmp here. Since the jmpbuf is - * then meaningless we abort instead of returning. - */ -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) - PNG_ABORT(); - png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); -#else - if (setjmp(png_ptr->jmpbuf)) - PNG_ABORT(); -#endif -#endif - return (png_ptr); -} - -/* Initialize png_ptr structure, and allocate any memory needed */ -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* Deprecated. */ -#undef png_write_init -void PNGAPI -png_write_init(png_structp png_ptr) -{ - /* We only come here via pre-1.0.7-compiled applications */ - png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0); -} - -void PNGAPI -png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, - png_size_t png_struct_size, png_size_t png_info_size) -{ - /* We only come here via pre-1.0.12-compiled applications */ - if (png_ptr == NULL) return; -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - if (png_sizeof(png_struct) > png_struct_size || - png_sizeof(png_info) > png_info_size) - { - char msg[80]; - png_ptr->warning_fn = NULL; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "Application is running with png.c from libpng-%.20s", - png_libpng_ver); - png_warning(png_ptr, msg); - } -#endif - if (png_sizeof(png_struct) > png_struct_size) - { - png_ptr->error_fn = NULL; -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "The png struct allocated by the application for writing is" - " too small."); - } - if (png_sizeof(png_info) > png_info_size) - { - png_ptr->error_fn = NULL; -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "The info struct allocated by the application for writing is" - " too small."); - } - png_write_init_3(&png_ptr, user_png_ver, png_struct_size); -} -#endif /* PNG_1_0_X || PNG_1_2_X */ - - -void PNGAPI -png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, - png_size_t png_struct_size) -{ - png_structp png_ptr = *ptr_ptr; -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; /* to save current jump buffer */ -#endif - - int i = 0; - - if (png_ptr == NULL) - return; - - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - { -#ifdef PNG_LEGACY_SUPPORTED - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; -#else - png_ptr->warning_fn = NULL; - png_warning(png_ptr, - "Application uses deprecated png_write_init() and should be recompiled."); -#endif - } - } while (png_libpng_ver[i++]); - - png_debug(1, "in png_write_init_3"); - -#ifdef PNG_SETJMP_SUPPORTED - /* Save jump buffer and error functions */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); -#endif - - if (png_sizeof(png_struct) > png_struct_size) - { - png_destroy_struct(png_ptr); - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); - *ptr_ptr = png_ptr; - } - - /* Reset all variables to 0 */ - png_memset(png_ptr, 0, png_sizeof(png_struct)); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; -#endif - -#ifdef PNG_SETJMP_SUPPORTED - /* Restore jump buffer */ - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif - - png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, - png_flush_ptr_NULL); - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, - 1, png_doublep_NULL, png_doublep_NULL); -#endif -} - -/* Write a few rows of image data. If the image is interlaced, - * either you will have to write the 7 sub images, or, if you - * have called png_set_interlace_handling(), you will have to - * "write" the image seven times. - */ -void PNGAPI -png_write_rows(png_structp png_ptr, png_bytepp row, - png_uint_32 num_rows) -{ - png_uint_32 i; /* row counter */ - png_bytepp rp; /* row pointer */ - - png_debug(1, "in png_write_rows"); - - if (png_ptr == NULL) - return; - - /* Loop through the rows */ - for (i = 0, rp = row; i < num_rows; i++, rp++) - { - png_write_row(png_ptr, *rp); - } -} - -/* Write the image. You only need to call this function once, even - * if you are writing an interlaced image. - */ -void PNGAPI -png_write_image(png_structp png_ptr, png_bytepp image) -{ - png_uint_32 i; /* row index */ - int pass, num_pass; /* pass variables */ - png_bytepp rp; /* points to current row */ - - if (png_ptr == NULL) - return; - - png_debug(1, "in png_write_image"); - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Initialize interlace handling. If image is not interlaced, - * this will set pass to 1 - */ - num_pass = png_set_interlace_handling(png_ptr); -#else - num_pass = 1; -#endif - /* Loop through passes */ - for (pass = 0; pass < num_pass; pass++) - { - /* Loop through image */ - for (i = 0, rp = image; i < png_ptr->height; i++, rp++) - { - png_write_row(png_ptr, *rp); - } - } -} - -/* Called by user to write a row of image data */ -void PNGAPI -png_write_row(png_structp png_ptr, png_bytep row) -{ - if (png_ptr == NULL) - return; - - png_debug2(1, "in png_write_row (row %ld, pass %d)", - png_ptr->row_number, png_ptr->pass); - - /* Initialize transformations and other stuff if first time */ - if (png_ptr->row_number == 0 && png_ptr->pass == 0) - { - /* Make sure we wrote the header info */ - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) - png_error(png_ptr, - "png_write_info was never called before png_write_row."); - - /* Check for transforms that have been set but were defined out */ -#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) - png_warning(png_ptr, - "PNG_WRITE_INVERT_SUPPORTED is not defined."); -#endif -#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) - png_warning(png_ptr, - "PNG_WRITE_FILLER_SUPPORTED is not defined."); -#endif -#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ - defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - png_warning(png_ptr, - "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); -#endif -#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) - png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); -#endif -#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) - png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); -#endif -#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) - png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); -#endif -#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); -#endif - - png_write_start_row(png_ptr); - } - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* If interlaced and not interested in row, return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - switch (png_ptr->pass) - { - case 0: - if (png_ptr->row_number & 0x07) - { - png_write_finish_row(png_ptr); - return; - } - break; - case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) - { - png_write_finish_row(png_ptr); - return; - } - break; - case 2: - if ((png_ptr->row_number & 0x07) != 4) - { - png_write_finish_row(png_ptr); - return; - } - break; - case 3: - if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) - { - png_write_finish_row(png_ptr); - return; - } - break; - case 4: - if ((png_ptr->row_number & 0x03) != 2) - { - png_write_finish_row(png_ptr); - return; - } - break; - case 5: - if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) - { - png_write_finish_row(png_ptr); - return; - } - break; - case 6: - if (!(png_ptr->row_number & 0x01)) - { - png_write_finish_row(png_ptr); - return; - } - break; - } - } -#endif - - /* Set up row info for transformations */ - png_ptr->row_info.color_type = png_ptr->color_type; - png_ptr->row_info.width = png_ptr->usr_width; - png_ptr->row_info.channels = png_ptr->usr_channels; - png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; - png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * - png_ptr->row_info.channels); - - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); - png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width); - png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); - png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); - png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); - png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes); - - /* Copy user's row into buffer, leaving room for filter byte. */ - png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, - png_ptr->row_info.rowbytes); - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Handle interlacing */ - if (png_ptr->interlaced && png_ptr->pass < 6 && - (png_ptr->transformations & PNG_INTERLACE)) - { - png_do_write_interlace(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->pass); - /* This should always get caught above, but still ... */ - if (!(png_ptr->row_info.width)) - { - png_write_finish_row(png_ptr); - return; - } - } -#endif - - /* Handle other transformations */ - if (png_ptr->transformations) - png_do_write_transformations(png_ptr); - -#ifdef PNG_MNG_FEATURES_SUPPORTED - /* Write filter_method 64 (intrapixel differencing) only if - * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and - * 2. Libpng did not write a PNG signature (this filter_method is only - * used in PNG datastreams that are embedded in MNG datastreams) and - * 3. The application called png_permit_mng_features with a mask that - * included PNG_FLAG_MNG_FILTER_64 and - * 4. The filter_method is 64 and - * 5. The color_type is RGB or RGBA - */ - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) - { - /* Intrapixel differencing */ - png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); - } -#endif - - /* Find a filter if necessary, filter the row and write it out. */ - png_write_find_filter(png_ptr, &(png_ptr->row_info)); - - if (png_ptr->write_row_fn != NULL) - (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); -} - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set the automatic flush interval or 0 to turn flushing off */ -void PNGAPI -png_set_flush(png_structp png_ptr, int nrows) -{ - png_debug(1, "in png_set_flush"); - - if (png_ptr == NULL) - return; - png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); -} - -/* Flush the current output buffers now */ -void PNGAPI -png_write_flush(png_structp png_ptr) -{ - int wrote_IDAT; - - png_debug(1, "in png_write_flush"); - - if (png_ptr == NULL) - return; - /* We have already written out all of the data */ - if (png_ptr->row_number >= png_ptr->num_rows) - return; - - do - { - int ret; - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); - wrote_IDAT = 0; - - /* Check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - else - png_error(png_ptr, "zlib error"); - } - - if (!(png_ptr->zstream.avail_out)) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, - png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - wrote_IDAT = 1; - } - } while(wrote_IDAT == 1); - - /* If there is any data left to be output, write it into a new IDAT */ - if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, - png_ptr->zbuf_size - png_ptr->zstream.avail_out); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - png_ptr->flush_rows = 0; - png_flush(png_ptr); -} -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - -/* Free all memory used by the write */ -void PNGAPI -png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; -#endif - - png_debug(1, "in png_destroy_write_struct"); - - if (png_ptr_ptr != NULL) - { - png_ptr = *png_ptr_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - } - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr != NULL) - { - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; - } -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - if (png_ptr != NULL) - { - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list = NULL; - png_ptr->num_chunk_list = 0; - } -#endif - } - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } - - if (png_ptr != NULL) - { - png_write_destroy(png_ptr); -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - *png_ptr_ptr = NULL; - } -} - - -/* Free any memory used in png_ptr struct (old method) */ -void /* PRIVATE */ -png_write_destroy(png_structp png_ptr) -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; /* Save jump buffer */ -#endif - png_error_ptr error_fn; - png_error_ptr warning_fn; - png_voidp error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn; -#endif - - png_debug(1, "in png_write_destroy"); - - /* Free any memory zlib uses */ - deflateEnd(&png_ptr->zstream); - - /* Free our memory. png_free checks NULL for us. */ - png_free(png_ptr, png_ptr->zbuf); - png_free(png_ptr, png_ptr->row_buf); -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_free(png_ptr, png_ptr->prev_row); - png_free(png_ptr, png_ptr->sub_row); - png_free(png_ptr, png_ptr->up_row); - png_free(png_ptr, png_ptr->avg_row); - png_free(png_ptr, png_ptr->paeth_row); -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_free(png_ptr, png_ptr->time_buffer); -#endif - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_free(png_ptr, png_ptr->prev_filters); - png_free(png_ptr, png_ptr->filter_weights); - png_free(png_ptr, png_ptr->inv_filter_weights); - png_free(png_ptr, png_ptr->filter_costs); - png_free(png_ptr, png_ptr->inv_filter_costs); -#endif - -#ifdef PNG_SETJMP_SUPPORTED - /* Reset structure */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); -#endif - - error_fn = png_ptr->error_fn; - warning_fn = png_ptr->warning_fn; - error_ptr = png_ptr->error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; -#endif - - png_memset(png_ptr, 0, png_sizeof(png_struct)); - - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; - png_ptr->error_ptr = error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr->free_fn = free_fn; -#endif - -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif -} - -/* Allow the application to select one or more row filters to use. */ -void PNGAPI -png_set_filter(png_structp png_ptr, int method, int filters) -{ - png_debug(1, "in png_set_filter"); - - if (png_ptr == NULL) - return; -#ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (method == PNG_INTRAPIXEL_DIFFERENCING)) - method = PNG_FILTER_TYPE_BASE; -#endif - if (method == PNG_FILTER_TYPE_BASE) - { - switch (filters & (PNG_ALL_FILTERS | 0x07)) - { -#ifdef PNG_WRITE_FILTER_SUPPORTED - case 5: - case 6: - case 7: png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - case PNG_FILTER_VALUE_NONE: - png_ptr->do_filter = PNG_FILTER_NONE; break; -#ifdef PNG_WRITE_FILTER_SUPPORTED - case PNG_FILTER_VALUE_SUB: - png_ptr->do_filter = PNG_FILTER_SUB; break; - case PNG_FILTER_VALUE_UP: - png_ptr->do_filter = PNG_FILTER_UP; break; - case PNG_FILTER_VALUE_AVG: - png_ptr->do_filter = PNG_FILTER_AVG; break; - case PNG_FILTER_VALUE_PAETH: - png_ptr->do_filter = PNG_FILTER_PAETH; break; - default: png_ptr->do_filter = (png_byte)filters; break; -#else - default: png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - } - - /* If we have allocated the row_buf, this means we have already started - * with the image and we should have allocated all of the filter buffers - * that have been selected. If prev_row isn't already allocated, then - * it is too late to start using the filters that need it, since we - * will be missing the data in the previous row. If an application - * wants to start and stop using particular filters during compression, - * it should start out with all of the filters, and then add and - * remove them after the start of compression. - */ - if (png_ptr->row_buf != NULL) - { -#ifdef PNG_WRITE_FILTER_SUPPORTED - if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) - { - png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; - } - - if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) - { - if (png_ptr->prev_row == NULL) - { - png_warning(png_ptr, "Can't add Up filter after starting"); - png_ptr->do_filter &= ~PNG_FILTER_UP; - } - else - { - png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; - } - } - - if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) - { - if (png_ptr->prev_row == NULL) - { - png_warning(png_ptr, "Can't add Average filter after starting"); - png_ptr->do_filter &= ~PNG_FILTER_AVG; - } - else - { - png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; - } - } - - if ((png_ptr->do_filter & PNG_FILTER_PAETH) && - png_ptr->paeth_row == NULL) - { - if (png_ptr->prev_row == NULL) - { - png_warning(png_ptr, "Can't add Paeth filter after starting"); - png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); - } - else - { - png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; - } - } - - if (png_ptr->do_filter == PNG_NO_FILTERS) -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - png_ptr->do_filter = PNG_FILTER_NONE; - } - } - else - png_error(png_ptr, "Unknown custom filter method"); -} - -/* This allows us to influence the way in which libpng chooses the "best" - * filter for the current scanline. While the "minimum-sum-of-absolute- - * differences metric is relatively fast and effective, there is some - * question as to whether it can be improved upon by trying to keep the - * filtered data going to zlib more consistent, hopefully resulting in - * better compression. - */ -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ -void PNGAPI -png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, - int num_weights, png_doublep filter_weights, - png_doublep filter_costs) -{ - int i; - - png_debug(1, "in png_set_filter_heuristics"); - - if (png_ptr == NULL) - return; - if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) - { - png_warning(png_ptr, "Unknown filter heuristic method"); - return; - } - - if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) - { - heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; - } - - if (num_weights < 0 || filter_weights == NULL || - heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) - { - num_weights = 0; - } - - png_ptr->num_prev_filters = (png_byte)num_weights; - png_ptr->heuristic_method = (png_byte)heuristic_method; - - if (num_weights > 0) - { - if (png_ptr->prev_filters == NULL) - { - png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_byte) * num_weights)); - - /* To make sure that the weighting starts out fairly */ - for (i = 0; i < num_weights; i++) - { - png_ptr->prev_filters[i] = 255; - } - } - - if (png_ptr->filter_weights == NULL) - { - png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); - - png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); - for (i = 0; i < num_weights; i++) - { - png_ptr->inv_filter_weights[i] = - png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; - } - } - - for (i = 0; i < num_weights; i++) - { - if (filter_weights[i] < 0.0) - { - png_ptr->inv_filter_weights[i] = - png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; - } - else - { - png_ptr->inv_filter_weights[i] = - (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); - png_ptr->filter_weights[i] = - (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); - } - } - } - - /* If, in the future, there are other filter methods, this would - * need to be based on png_ptr->filter. - */ - if (png_ptr->filter_costs == NULL) - { - png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); - - png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); - - for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) - { - png_ptr->inv_filter_costs[i] = - png_ptr->filter_costs[i] = PNG_COST_FACTOR; - } - } - - /* Here is where we set the relative costs of the different filters. We - * should take the desired compression level into account when setting - * the costs, so that Paeth, for instance, has a high relative cost at low - * compression levels, while it has a lower relative cost at higher - * compression settings. The filter types are in order of increasing - * relative cost, so it would be possible to do this with an algorithm. - */ - for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) - { - if (filter_costs == NULL || filter_costs[i] < 0.0) - { - png_ptr->inv_filter_costs[i] = - png_ptr->filter_costs[i] = PNG_COST_FACTOR; - } - else if (filter_costs[i] >= 1.0) - { - png_ptr->inv_filter_costs[i] = - (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); - png_ptr->filter_costs[i] = - (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); - } - } -} -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ - -void PNGAPI -png_set_compression_level(png_structp png_ptr, int level) -{ - png_debug(1, "in png_set_compression_level"); - - if (png_ptr == NULL) - return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; - png_ptr->zlib_level = level; -} - -void PNGAPI -png_set_compression_mem_level(png_structp png_ptr, int mem_level) -{ - png_debug(1, "in png_set_compression_mem_level"); - - if (png_ptr == NULL) - return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; - png_ptr->zlib_mem_level = mem_level; -} - -void PNGAPI -png_set_compression_strategy(png_structp png_ptr, int strategy) -{ - png_debug(1, "in png_set_compression_strategy"); - - if (png_ptr == NULL) - return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; - png_ptr->zlib_strategy = strategy; -} - -void PNGAPI -png_set_compression_window_bits(png_structp png_ptr, int window_bits) -{ - if (png_ptr == NULL) - return; - if (window_bits > 15) - png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); - else if (window_bits < 8) - png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); -#ifndef WBITS_8_OK - /* Avoid libpng bug with 256-byte windows */ - if (window_bits == 8) - { - png_warning(png_ptr, "Compression window is being reset to 512"); - window_bits = 9; - } -#endif - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; - png_ptr->zlib_window_bits = window_bits; -} - -void PNGAPI -png_set_compression_method(png_structp png_ptr, int method) -{ - png_debug(1, "in png_set_compression_method"); - - if (png_ptr == NULL) - return; - if (method != 8) - png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; - png_ptr->zlib_method = method; -} - -void PNGAPI -png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->write_row_fn = write_row_fn; -} - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -void PNGAPI -png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr - write_user_transform_fn) -{ - png_debug(1, "in png_set_write_user_transform_fn"); - - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_USER_TRANSFORM; - png_ptr->write_user_transform_fn = write_user_transform_fn; -} -#endif - - -#ifdef PNG_INFO_IMAGE_SUPPORTED -void PNGAPI -png_write_png(png_structp png_ptr, png_infop info_ptr, - int transforms, voidp params) -{ - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Write the file header information. */ - png_write_info(png_ptr, info_ptr); - - /* ------ these transformations don't touch the info structure ------- */ - -#ifdef PNG_WRITE_INVERT_SUPPORTED - /* Invert monochrome pixels */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) - png_set_invert_mono(png_ptr); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED - /* Shift the pixels up to a legal bit depth and fill in - * as appropriate to correctly scale the image. - */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && (info_ptr->valid & PNG_INFO_sBIT)) - png_set_shift(png_ptr, &info_ptr->sig_bit); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED - /* Pack pixels into bytes */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - /* Swap location of alpha bytes from ARGB to RGBA */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) - png_set_swap_alpha(png_ptr); -#endif - -#ifdef PNG_WRITE_FILLER_SUPPORTED - /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ - if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); - else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); -#endif - -#ifdef PNG_WRITE_BGR_SUPPORTED - /* Flip BGR pixels to RGB */ - if (transforms & PNG_TRANSFORM_BGR) - png_set_bgr(png_ptr); -#endif - -#ifdef PNG_WRITE_SWAP_SUPPORTED - /* Swap bytes of 16-bit files to most significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) - png_set_swap(png_ptr); -#endif - -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - /* Swap bits of 1, 2, 4 bit packed pixel formats */ - if (transforms & PNG_TRANSFORM_PACKSWAP) - png_set_packswap(png_ptr); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif - - /* ----------------------- end of transformations ------------------- */ - - /* Write the bits */ - if (info_ptr->valid & PNG_INFO_IDAT) - png_write_image(png_ptr, info_ptr->row_pointers); - - /* It is REQUIRED to call this to finish writing the rest of the file */ - png_write_end(png_ptr, info_ptr); - - PNG_UNUSED(transforms) /* Quiet compiler warnings */ - PNG_UNUSED(params) -} -#endif -#endif /* PNG_WRITE_SUPPORTED */ + +/* pngwrite.c - general routines to write a PNG file + * + * Last changed in libpng 1.2.51 [February 6, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Get internal access to png.h */ +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + { + /* Write PNG signature */ + png_write_sig(png_ptr); +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ + (png_ptr->mng_features_permitted)) + { + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + png_ptr->mng_features_permitted = 0; + } +#endif + /* Write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + info_ptr->interlace_type); +#else + 0); +#endif + /* The rest of these check to see if the valid field has the appropriate + * flag set, and if it does, writes the chunk. + */ +#ifdef PNG_WRITE_gAMA_SUPPORTED + if (info_ptr->valid & PNG_INFO_gAMA) + { +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_gAMA(png_ptr, info_ptr->gamma); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); +# endif +#endif + } +#endif +#ifdef PNG_WRITE_sRGB_SUPPORTED + if (info_ptr->valid & PNG_INFO_sRGB) + png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); +#endif +#ifdef PNG_WRITE_iCCP_SUPPORTED + if (info_ptr->valid & PNG_INFO_iCCP) + png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, + info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); +#endif +#ifdef PNG_WRITE_sBIT_SUPPORTED + if (info_ptr->valid & PNG_INFO_sBIT) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif +#ifdef PNG_WRITE_cHRM_SUPPORTED + if (info_ptr->valid & PNG_INFO_cHRM) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_cHRM(png_ptr, + info_ptr->x_white, info_ptr->y_white, + info_ptr->x_red, info_ptr->y_red, + info_ptr->x_green, info_ptr->y_green, + info_ptr->x_blue, info_ptr->y_blue); +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + png_write_cHRM_fixed(png_ptr, + info_ptr->int_x_white, info_ptr->int_y_white, + info_ptr->int_x_red, info_ptr->int_y_red, + info_ptr->int_x_green, info_ptr->int_y_green, + info_ptr->int_x_blue, info_ptr->int_y_blue); +# endif +#endif + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep = png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && !(up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structp png_ptr, png_infop info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if (info_ptr->valid & PNG_INFO_PLTE) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images"); + +#ifdef PNG_WRITE_tRNS_SUPPORTED + if (info_ptr->valid & PNG_INFO_tRNS) + { +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j; + for (j = 0; j<(int)info_ptr->num_trans; j++) + info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#ifdef PNG_WRITE_bKGD_SUPPORTED + if (info_ptr->valid & PNG_INFO_bKGD) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif +#ifdef PNG_WRITE_hIST_SUPPORTED + if (info_ptr->valid & PNG_INFO_hIST) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif +#ifdef PNG_WRITE_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED + if (info_ptr->valid & PNG_INFO_pCAL) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif + +#ifdef PNG_sCAL_SUPPORTED + if (info_ptr->valid & PNG_INFO_sCAL) +#ifdef PNG_WRITE_sCAL_SUPPORTED +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) + png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); +#else /* !FLOATING_POINT */ +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#endif /* FIXED_POINT */ +#endif /* FLOATING_POINT */ +#else /* !WRITE_sCAL */ + png_warning(png_ptr, + "png_write_sCAL not supported; sCAL chunk not written."); +#endif /* WRITE_sCAL */ +#endif /* sCAL */ + +#ifdef PNG_WRITE_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif /* pHYs */ + +#ifdef PNG_WRITE_tIME_SUPPORTED + if (info_ptr->valid & PNG_INFO_tIME) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif /* tIME */ + +#ifdef PNG_WRITE_sPLT_SUPPORTED + if (info_ptr->valid & PNG_INFO_sPLT) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif /* sPLT */ + +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + /* Can't get here */ + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif /* tEXt */ + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep = png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + !(up->location & PNG_AFTER_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_end"); + + if (png_ptr == NULL) + return; + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "No IDATs written into file"); + + /* See if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#ifdef PNG_WRITE_TEXT_SUPPORTED + int i; /* local index variable */ +#endif +#ifdef PNG_WRITE_tIME_SUPPORTED + /* Check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) && + !(png_ptr->mode & PNG_WROTE_tIME)) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); +#endif +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep = png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_AFTER_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* Write end of PNG file */ + png_write_IEND(png_ptr); + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, + * and restored again in libpng-1.2.30, may cause some applications that + * do not set png_ptr->output_flush_fn to crash. If your application + * experiences a problem, please try building libpng with + * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to + * png-mng-implement at lists.sf.net . + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + png_flush(png_ptr); +# endif +#endif +} + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* "tm" structure is not supported on WindowsCE */ +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm"); + + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t"); + + tbuf = gmtime(&ttime); + png_convert_from_struct_tm(ptime, tbuf); +} +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ +#ifdef PNG_SETJMP_SUPPORTED + volatile +#endif + png_structp png_ptr; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + int i; + + png_debug(1, "in png_create_write_struct"); + +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); +#else + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); +#endif /* PNG_USER_MEM_SUPPORTED */ + if (png_ptr == NULL) + return (NULL); + + /* Added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max = PNG_USER_WIDTH_MAX; + png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; +#endif + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_ptr->jmpbuf)) +#endif + { + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, + (png_free_ptr)free_fn, (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + return (NULL); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); +#endif +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + if (user_png_ver) + { + i = 0; + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + } + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + png_snprintf(msg, 80, + "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + png_snprintf(msg, 80, + "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_error(png_ptr, + "Incompatible libpng version in application and library"); + } + } + + /* Initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + + png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, + png_flush_ptr_NULL); + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, png_doublep_NULL, png_doublep_NULL); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Applications that neglect to set up their own setjmp() and then + * encounter a png_error() will longjmp here. Since the jmpbuf is + * then meaningless we abort instead of returning. + */ +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) + PNG_ABORT(); + png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); +#else + if (setjmp(png_ptr->jmpbuf)) + PNG_ABORT(); +#endif +#endif + return (png_ptr); +} + +/* Initialize png_ptr structure, and allocate any memory needed */ +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* Deprecated. */ +#undef png_write_init +void PNGAPI +png_write_init(png_structp png_ptr) +{ + /* We only come here via pre-1.0.7-compiled applications */ + png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0); +} + +void PNGAPI +png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size, png_size_t png_info_size) +{ + /* We only come here via pre-1.0.12-compiled applications */ + if (png_ptr == NULL) return; +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + if (png_sizeof(png_struct) > png_struct_size || + png_sizeof(png_info) > png_info_size) + { + char msg[80]; + png_ptr->warning_fn = NULL; + if (user_png_ver) + { + png_snprintf(msg, 80, + "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + png_snprintf(msg, 80, + "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); + } +#endif + if (png_sizeof(png_struct) > png_struct_size) + { + png_ptr->error_fn = NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_error(png_ptr, + "The png struct allocated by the application for writing is" + " too small."); + } + if (png_sizeof(png_info) > png_info_size) + { + png_ptr->error_fn = NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_error(png_ptr, + "The info struct allocated by the application for writing is" + " too small."); + } + png_write_init_3(&png_ptr, user_png_ver, png_struct_size); +} +#endif /* PNG_1_0_X || PNG_1_2_X */ + + +void PNGAPI +png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size) +{ + png_structp png_ptr = *ptr_ptr; +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* to save current jump buffer */ +#endif + + int i = 0; + + if (png_ptr == NULL) + return; + + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + { +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; +#else + png_ptr->warning_fn = NULL; + png_warning(png_ptr, + "Application uses deprecated png_write_init() and should be recompiled."); +#endif + } + } while (png_libpng_ver[i++]); + + png_debug(1, "in png_write_init_3"); + +#ifdef PNG_SETJMP_SUPPORTED + /* Save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#endif + + if (png_sizeof(png_struct) > png_struct_size) + { + png_destroy_struct(png_ptr); + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); + *ptr_ptr = png_ptr; + } + + /* Reset all variables to 0 */ + png_memset(png_ptr, 0, png_sizeof(png_struct)); + + /* Added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max = PNG_USER_WIDTH_MAX; + png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); +#endif + + png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, + png_flush_ptr_NULL); + + /* Initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, png_doublep_NULL, png_doublep_NULL); +#endif +} + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows"); + + if (png_ptr == NULL) + return; + + /* Loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + if (png_ptr == NULL) + return; + + png_debug(1, "in png_write_image"); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Initialize interlace handling. If image is not interlaced, + * this will set pass to 1 + */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* Loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* Loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +/* Called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structp png_ptr, png_bytep row) +{ + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_write_row (row %ld, pass %d)", + png_ptr->row_number, png_ptr->pass); + + /* Initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Make sure we wrote the header info */ + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + png_error(png_ptr, + "png_write_info was never called before png_write_row."); + + /* Check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, + "PNG_WRITE_INVERT_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, + "PNG_WRITE_FILLER_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, + "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); +#endif + + png_write_start_row(png_ptr); + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced and not interested in row, return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 0x01)) + { + png_write_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + /* Set up row info for transformations */ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->usr_width; + png_ptr->row_info.channels = png_ptr->usr_channels; + png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); + png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width); + png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, + png_ptr->row_info.rowbytes); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE)) + { + png_do_write_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass); + /* This should always get caught above, but still ... */ + if (!(png_ptr->row_info.width)) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + + /* Handle other transformations */ + if (png_ptr->transformations) + png_do_write_transformations(png_ptr); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &(png_ptr->row_info)); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush"); + + if (png_ptr == NULL) + return; + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* Flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structp png_ptr) +{ + int wrote_IDAT; + + png_debug(1, "in png_write_flush"); + + if (png_ptr == NULL) + return; + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + do + { + int ret; + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); + wrote_IDAT = 0; + + /* Check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + if (!(png_ptr->zstream.avail_out)) + { + /* Write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + wrote_IDAT = 1; + } + } while(wrote_IDAT == 1); + + /* If there is any data left to be output, write it into a new IDAT */ + if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) + { + /* Write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + +/* Free all memory used by the write */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_write_struct"); + + if (png_ptr_ptr != NULL) + { + png_ptr = *png_ptr_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + } + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL) + { + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; + } +#endif + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + if (png_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; + png_ptr->num_chunk_list = 0; + } +#endif + } + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } + + if (png_ptr != NULL) + { + png_write_destroy(png_ptr); +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = NULL; + } +} + + +/* Free any memory used in png_ptr struct (old method) */ +void /* PRIVATE */ +png_write_destroy(png_structp png_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* Save jump buffer */ +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_write_destroy"); + + /* Free any memory zlib uses */ + deflateEnd(&png_ptr->zstream); + + /* Free our memory. png_free checks NULL for us. */ + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->row_buf); +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->sub_row); + png_free(png_ptr, png_ptr->up_row); + png_free(png_ptr, png_ptr->avg_row); + png_free(png_ptr, png_ptr->paeth_row); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + png_free(png_ptr, png_ptr->time_buffer); +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_filters); + png_free(png_ptr, png_ptr->filter_weights); + png_free(png_ptr, png_ptr->inv_filter_weights); + png_free(png_ptr, png_ptr->filter_costs); + png_free(png_ptr, png_ptr->inv_filter_costs); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Reset structure */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, png_sizeof(png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); +#endif +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter"); + + if (png_ptr == NULL) + return; +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + case 5: + case 6: + case 7: png_warning(png_ptr, "Unknown row filter for method 0"); +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + case PNG_FILTER_VALUE_NONE: + png_ptr->do_filter = PNG_FILTER_NONE; break; +#ifdef PNG_WRITE_FILTER_SUPPORTED + case PNG_FILTER_VALUE_SUB: + png_ptr->do_filter = PNG_FILTER_SUB; break; + case PNG_FILTER_VALUE_UP: + png_ptr->do_filter = PNG_FILTER_UP; break; + case PNG_FILTER_VALUE_AVG: + png_ptr->do_filter = PNG_FILTER_AVG; break; + case PNG_FILTER_VALUE_PAETH: + png_ptr->do_filter = PNG_FILTER_PAETH; break; + default: png_ptr->do_filter = (png_byte)filters; break; +#else + default: png_warning(png_ptr, "Unknown row filter for method 0"); +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + } + + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then add and + * remove them after the start of compression. + */ + if (png_ptr->row_buf != NULL) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Up filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_UP; + } + else + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Average filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_AVG; + } + else + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + png_ptr->paeth_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); + } + else + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + png_ptr->do_filter = PNG_FILTER_NONE; + } + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +/* This allows us to influence the way in which libpng chooses the "best" + * filter for the current scanline. While the "minimum-sum-of-absolute- + * differences metric is relatively fast and effective, there is some + * question as to whether it can be improved upon by trying to keep the + * filtered data going to zlib more consistent, hopefully resulting in + * better compression. + */ +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ +void PNGAPI +png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, + int num_weights, png_doublep filter_weights, + png_doublep filter_costs) +{ + int i; + + png_debug(1, "in png_set_filter_heuristics"); + + if (png_ptr == NULL) + return; + if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return; + } + + if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) + { + heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + } + + if (num_weights < 0 || filter_weights == NULL || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + { + num_weights = 0; + } + + png_ptr->num_prev_filters = (png_byte)num_weights; + png_ptr->heuristic_method = (png_byte)heuristic_method; + + if (num_weights > 0) + { + if (png_ptr->prev_filters == NULL) + { + png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_byte) * num_weights)); + + /* To make sure that the weighting starts out fairly */ + for (i = 0; i < num_weights; i++) + { + png_ptr->prev_filters[i] = 255; + } + } + + if (png_ptr->filter_weights == NULL) + { + png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + + png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + for (i = 0; i < num_weights; i++) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + } + + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] < 0.0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + else + { + png_ptr->inv_filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); + png_ptr->filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); + } + } + } + + /* If, in the future, there are other filter methods, this would + * need to be based on png_ptr->filter. + */ + if (png_ptr->filter_costs == NULL) + { + png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + if (filter_costs == NULL || filter_costs[i] < 0.0) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + else if (filter_costs[i] >= 1.0) + { + png_ptr->inv_filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); + png_ptr->filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); + } + } +} +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +void PNGAPI +png_set_compression_level(png_structp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +void PNGAPI +png_set_compression_window_bits(png_structp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + if (window_bits > 15) + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + else if (window_bits < 8) + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); +#ifndef WBITS_8_OK + /* Avoid libpng bug with 256-byte windows */ + if (window_bits == 8) + { + png_warning(png_ptr, "Compression window is being reset to 512"); + window_bits = 9; + } +#endif + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method"); + + if (png_ptr == NULL) + return; + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; + png_ptr->zlib_method = method; +} + +void PNGAPI +png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->write_row_fn = write_row_fn; +} + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +void PNGAPI +png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_write_png(png_structp png_ptr, png_infop info_ptr, + int transforms, voidp params) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + +#ifdef PNG_WRITE_INVERT_SUPPORTED + /* Invert monochrome pixels */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + /* Pack pixels into bytes */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + /* Swap location of alpha bytes from ARGB to RGBA */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ + if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + /* Flip BGR pixels to RGB */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED + /* Swap bytes of 16-bit files to most significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* Write the bits */ + if (info_ptr->valid & PNG_INFO_IDAT) + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + PNG_UNUSED(transforms) /* Quiet compiler warnings */ + PNG_UNUSED(params) +} +#endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngwtran.c b/main/source/includes/lpng1251/pngwtran.c index 473099bc..0ce9b9b5 100644 --- a/main/source/includes/lpng1251/pngwtran.c +++ b/main/source/includes/lpng1251/pngwtran.c @@ -1,582 +1,582 @@ - -/* pngwtran.c - transforms the data in a row for PNG writers - * - * Last changed in libpng 1.2.43 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED - -/* Transform the data according to the user's wishes. The order of - * transformations is significant. - */ -void /* PRIVATE */ -png_do_write_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_do_write_transformations"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - if (png_ptr->write_user_transform_fn != NULL) - (*(png_ptr->write_user_transform_fn)) /* User write transform - function */ - (png_ptr, /* png_ptr */ - &(png_ptr->row_info), /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_uint_32 rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#endif -#ifdef PNG_WRITE_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->flags); -#endif -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef PNG_WRITE_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, - (png_uint_32)png_ptr->bit_depth); -#endif -#ifdef PNG_WRITE_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef PNG_WRITE_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef PNG_WRITE_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef PNG_WRITE_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -} - -#ifdef PNG_WRITE_PACK_SUPPORTED -/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The - * row_info bit depth should be 8 (one pixel per byte). The channels - * should be 1 (this only happens on grayscale and paletted images). - */ -void /* PRIVATE */ -png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) -{ - png_debug(1, "in png_do_pack"); - - if (row_info->bit_depth == 8 && -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - row_info->channels == 1) - { - switch ((int)bit_depth) - { - case 1: - { - png_bytep sp, dp; - int mask, v; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - sp = row; - dp = row; - mask = 0x80; - v = 0; - - for (i = 0; i < row_width; i++) - { - if (*sp != 0) - v |= mask; - sp++; - if (mask > 1) - mask >>= 1; - else - { - mask = 0x80; - *dp = (png_byte)v; - dp++; - v = 0; - } - } - if (mask != 0x80) - *dp = (png_byte)v; - break; - } - case 2: - { - png_bytep sp, dp; - int shift, v; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - sp = row; - dp = row; - shift = 6; - v = 0; - for (i = 0; i < row_width; i++) - { - png_byte value; - - value = (png_byte)(*sp & 0x03); - v |= (value << shift); - if (shift == 0) - { - shift = 6; - *dp = (png_byte)v; - dp++; - v = 0; - } - else - shift -= 2; - sp++; - } - if (shift != 6) - *dp = (png_byte)v; - break; - } - case 4: - { - png_bytep sp, dp; - int shift, v; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - sp = row; - dp = row; - shift = 4; - v = 0; - for (i = 0; i < row_width; i++) - { - png_byte value; - - value = (png_byte)(*sp & 0x0f); - v |= (value << shift); - - if (shift == 0) - { - shift = 4; - *dp = (png_byte)v; - dp++; - v = 0; - } - else - shift -= 4; - - sp++; - } - if (shift != 4) - *dp = (png_byte)v; - break; - } - } - row_info->bit_depth = (png_byte)bit_depth; - row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_info->width); - } -} -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED -/* Shift pixel values to take advantage of whole range. Pass the - * true number of bits in bit_depth. The row should be packed - * according to row_info->bit_depth. Thus, if you had a row of - * bit depth 4, but the pixels only had values from 0 to 7, you - * would pass 3 as bit_depth, and this routine would translate the - * data to 0 to 15. - */ -void /* PRIVATE */ -png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) -{ - png_debug(1, "in png_do_shift"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL && -#else - if ( -#endif - row_info->color_type != PNG_COLOR_TYPE_PALETTE) - { - int shift_start[4], shift_dec[4]; - int channels = 0; - - if (row_info->color_type & PNG_COLOR_MASK_COLOR) - { - shift_start[channels] = row_info->bit_depth - bit_depth->red; - shift_dec[channels] = bit_depth->red; - channels++; - shift_start[channels] = row_info->bit_depth - bit_depth->green; - shift_dec[channels] = bit_depth->green; - channels++; - shift_start[channels] = row_info->bit_depth - bit_depth->blue; - shift_dec[channels] = bit_depth->blue; - channels++; - } - else - { - shift_start[channels] = row_info->bit_depth - bit_depth->gray; - shift_dec[channels] = bit_depth->gray; - channels++; - } - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - shift_start[channels] = row_info->bit_depth - bit_depth->alpha; - shift_dec[channels] = bit_depth->alpha; - channels++; - } - - /* With low row depths, could only be grayscale, so one channel */ - if (row_info->bit_depth < 8) - { - png_bytep bp = row; - png_uint_32 i; - png_byte mask; - png_uint_32 row_bytes = row_info->rowbytes; - - if (bit_depth->gray == 1 && row_info->bit_depth == 2) - mask = 0x55; - else if (row_info->bit_depth == 4 && bit_depth->gray == 3) - mask = 0x11; - else - mask = 0xff; - - for (i = 0; i < row_bytes; i++, bp++) - { - png_uint_16 v; - int j; - - v = *bp; - *bp = 0; - for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) - { - if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); - else - *bp |= (png_byte)((v >> (-j)) & mask); - } - } - } - else if (row_info->bit_depth == 8) - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = channels * row_info->width; - - for (i = 0; i < istop; i++, bp++) - { - - png_uint_16 v; - int j; - int c = (int)(i%channels); - - v = *bp; - *bp = 0; - for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) - { - if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); - else - *bp |= (png_byte)((v >> (-j)) & 0xff); - } - } - } - else - { - png_bytep bp; - png_uint_32 i; - png_uint_32 istop = channels * row_info->width; - - for (bp = row, i = 0; i < istop; i++) - { - int c = (int)(i%channels); - png_uint_16 value, v; - int j; - - v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); - value = 0; - for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) - { - if (j > 0) - value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); - else - value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); - } - *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); - } - } - } -} -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_swap_alpha"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This converts from ARGB to RGBA */ - if (row_info->bit_depth == 8) - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save; - } - } - /* This converts from AARRGGBB to RRGGBBAA */ - else - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save[2]; - save[0] = *(sp++); - save[1] = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save[0]; - *(dp++) = save[1]; - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This converts from AG to GA */ - if (row_info->bit_depth == 8) - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save; - } - } - /* This converts from AAGG to GGAA */ - else - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save[2]; - save[0] = *(sp++); - save[1] = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save[0]; - *(dp++) = save[1]; - } - } - } - } -} -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_invert_alpha"); - -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL) -#endif - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This inverts the alpha channel in RGBA */ - if (row_info->bit_depth == 8) - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - for (i = 0, sp = dp = row; i < row_width; i++) - { - /* Does nothing - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - */ - sp+=3; dp = sp; - *(dp++) = (png_byte)(255 - *(sp++)); - } - } - /* This inverts the alpha channel in RRGGBBAA */ - else - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - /* Does nothing - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - */ - sp+=6; dp = sp; - *(dp++) = (png_byte)(255 - *(sp++)); - *(dp++) = (png_byte)(255 - *(sp++)); - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This inverts the alpha channel in GA */ - if (row_info->bit_depth == 8) - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - *(dp++) = *(sp++); - *(dp++) = (png_byte)(255 - *(sp++)); - } - } - /* This inverts the alpha channel in GGAA */ - else - { - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - /* Does nothing - *(dp++) = *(sp++); - *(dp++) = *(sp++); - */ - sp+=2; dp = sp; - *(dp++) = (png_byte)(255 - *(sp++)); - *(dp++) = (png_byte)(255 - *(sp++)); - } - } - } - } -} -#endif - -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ -void /* PRIVATE */ -png_do_write_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_intrapixel"); - - if ( -#ifdef PNG_USELESS_TESTS_SUPPORTED - row != NULL && row_info != NULL && -#endif - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((*rp - *(rp+1))&0xff); - *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff); - } - } - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); - png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); - png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); - png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp+1) = (png_byte)(red & 0xff); - *(rp+4) = (png_byte)((blue >> 8) & 0xff); - *(rp+5) = (png_byte)(blue & 0xff); - } - } - } -} -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_WRITE_SUPPORTED */ + +/* pngwtran.c - transforms the data in a row for PNG writers + * + * Last changed in libpng 1.2.43 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif +#ifdef PNG_WRITE_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->flags); +#endif +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif +#ifdef PNG_WRITE_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +} + +#ifdef PNG_WRITE_PACK_SUPPORTED +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +void /* PRIVATE */ +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack"); + + if (row_info->bit_depth == 8 && +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + sp++; + if (mask > 1) + mask >>= 1; + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + if (mask != 0x80) + *dp = (png_byte)v; + break; + } + case 2: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 2; + sp++; + } + if (shift != 6) + *dp = (png_byte)v; + break; + } + case 4: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 4; + + sp++; + } + if (shift != 4) + *dp = (png_byte)v; + break; + } + } + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +void /* PRIVATE */ +png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL && +#else + if ( +#endif + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + int channels = 0; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* With low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + png_uint_32 i; + png_byte mask; + png_uint_32 row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + png_uint_16 v; + int j; + + v = *bp; + *bp = 0; + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & mask); + } + } + } + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + + png_uint_16 v; + int j; + int c = (int)(i%channels); + + v = *bp; + *bp = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & 0xff); + } + } + } + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + int c = (int)(i%channels); + png_uint_16 value, v; + int j; + + v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + value = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); + else + value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + } + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from ARGB to RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AARRGGBB to RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from AG to GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AAGG to GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + } +} +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha"); + +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=3; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=6; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=2; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + } +} +#endif + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ( +#ifdef PNG_USELESS_TESTS_SUPPORTED + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp+1))&0xff); + *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); + png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); + png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1251/pngwutil.c b/main/source/includes/lpng1251/pngwutil.c index 50568f5a..c75f53eb 100644 --- a/main/source/includes/lpng1251/pngwutil.c +++ b/main/source/includes/lpng1251/pngwutil.c @@ -1,2832 +1,2832 @@ - -/* pngwutil.c - utilities to write a PNG file - * - * Last changed in libpng 1.2.43 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#define PNG_INTERNAL -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED - -/* Place a 32-bit number into a buffer in PNG byte order. We work - * with unsigned numbers for convenience, although one supported - * ancillary chunk uses signed (two's complement) numbers. - */ -void PNGAPI -png_save_uint_32(png_bytep buf, png_uint_32 i) -{ - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); -} - -/* The png_save_int_32 function assumes integers are stored in two's - * complement format. If this isn't the case, then this routine needs to - * be modified to write data in two's complement format. - */ -void PNGAPI -png_save_int_32(png_bytep buf, png_int_32 i) -{ - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); -} - -/* Place a 16-bit number into a buffer in PNG byte order. - * The parameter is declared unsigned int, not png_uint_16, - * just to avoid potential problems on pre-ANSI C compilers. - */ -void PNGAPI -png_save_uint_16(png_bytep buf, unsigned int i) -{ - buf[0] = (png_byte)((i >> 8) & 0xff); - buf[1] = (png_byte)(i & 0xff); -} - -/* Simple function to write the signature. If we have already written - * the magic bytes of the signature, or more likely, the PNG stream is - * being embedded into another stream and doesn't need its own signature, - * we should call png_set_sig_bytes() to tell libpng how many of the - * bytes have already been written. - */ -void /* PRIVATE */ -png_write_sig(png_structp png_ptr) -{ - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - - /* Write the rest of the 8 byte signature */ - png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], - (png_size_t)(8 - png_ptr->sig_bytes)); - if (png_ptr->sig_bytes < 3) - png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; -} - -/* Write a PNG chunk all at once. The type is an array of ASCII characters - * representing the chunk name. The array must be at least 4 bytes in - * length, and does not need to be null terminated. To be safe, pass the - * pre-defined chunk names here, and if you need a new one, define it - * where the others are defined. The length is the length of the data. - * All the data must be present. If that is not possible, use the - * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() - * functions instead. - */ -void PNGAPI -png_write_chunk(png_structp png_ptr, png_bytep chunk_name, - png_bytep data, png_size_t length) -{ - if (png_ptr == NULL) - return; - png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); - png_write_chunk_data(png_ptr, data, (png_size_t)length); - png_write_chunk_end(png_ptr); -} - -/* Write the start of a PNG chunk. The type is the chunk type. - * The total_length is the sum of the lengths of all the data you will be - * passing in png_write_chunk_data(). - */ -void PNGAPI -png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, - png_uint_32 length) -{ - png_byte buf[8]; - - png_debug2(0, "Writing %s chunk, length = %lu", chunk_name, - (unsigned long)length); - - if (png_ptr == NULL) - return; - - - /* Write the length and the chunk name */ - png_save_uint_32(buf, length); - png_memcpy(buf + 4, chunk_name, 4); - png_write_data(png_ptr, buf, (png_size_t)8); - /* Put the chunk name into png_ptr->chunk_name */ - png_memcpy(png_ptr->chunk_name, chunk_name, 4); - /* Reset the crc and run it over the chunk name */ - png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); -} - -/* Write the data of a PNG chunk started with png_write_chunk_start(). - * Note that multiple calls to this function are allowed, and that the - * sum of the lengths from these calls *must* add up to the total_length - * given to png_write_chunk_start(). - */ -void PNGAPI -png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - /* Write the data, and run the CRC over it */ - if (png_ptr == NULL) - return; - if (data != NULL && length > 0) - { - png_write_data(png_ptr, data, length); - /* Update the CRC after writing the data, - * in case that the user I/O routine alters it. - */ - png_calculate_crc(png_ptr, data, length); - } -} - -/* Finish a chunk started with png_write_chunk_start(). */ -void PNGAPI -png_write_chunk_end(png_structp png_ptr) -{ - png_byte buf[4]; - - if (png_ptr == NULL) return; - - /* Write the crc in a single operation */ - png_save_uint_32(buf, png_ptr->crc); - - png_write_data(png_ptr, buf, (png_size_t)4); -} - -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) -/* This pair of functions encapsulates the operation of (a) compressing a - * text string, and (b) issuing it later as a series of chunk data writes. - * The compression_state structure is shared context for these functions - * set up by the caller in order to make the whole mess thread-safe. - */ - -typedef struct -{ - char *input; /* The uncompressed input data */ - int input_len; /* Its length */ - int num_output_ptr; /* Number of output pointers used */ - int max_output_ptr; /* Size of output_ptr */ - png_charpp output_ptr; /* Array of pointers to output */ -} compression_state; - -/* Compress given text into storage in the png_ptr structure */ -static int /* PRIVATE */ -png_text_compress(png_structp png_ptr, - png_charp text, png_size_t text_len, int compression, - compression_state *comp) -{ - int ret; - - comp->num_output_ptr = 0; - comp->max_output_ptr = 0; - comp->output_ptr = NULL; - comp->input = NULL; - comp->input_len = 0; - - /* We may just want to pass the text right through */ - if (compression == PNG_TEXT_COMPRESSION_NONE) - { - comp->input = text; - comp->input_len = text_len; - return((int)text_len); - } - - if (compression >= PNG_TEXT_COMPRESSION_LAST) - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char msg[50]; - png_snprintf(msg, 50, "Unknown compression type %d", compression); - png_warning(png_ptr, msg); -#else - png_warning(png_ptr, "Unknown compression type"); -#endif - } - - /* We can't write the chunk until we find out how much data we have, - * which means we need to run the compressor first and save the - * output. This shouldn't be a problem, as the vast majority of - * comments should be reasonable, but we will set up an array of - * malloc'd pointers to be sure. - * - * If we knew the application was well behaved, we could simplify this - * greatly by assuming we can always malloc an output buffer large - * enough to hold the compressed text ((1001 * text_len / 1000) + 12) - * and malloc this directly. The only time this would be a bad idea is - * if we can't malloc more than 64K and we have 64K of random input - * data, or if the input string is incredibly large (although this - * wouldn't cause a failure, just a slowdown due to swapping). - */ - - /* Set up the compression buffers */ - png_ptr->zstream.avail_in = (uInt)text_len; - png_ptr->zstream.next_in = (Bytef *)text; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; - - /* This is the same compression loop as in png_write_row() */ - do - { - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); - if (ret != Z_OK) - { - /* Error */ - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - else - png_error(png_ptr, "zlib error"); - } - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - /* Make sure the output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) - { - int old_max; - - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) - { - png_charpp old_ptr; - - old_ptr = comp->output_ptr; - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32) - (comp->max_output_ptr * png_sizeof(png_charpp))); - png_memcpy(comp->output_ptr, old_ptr, old_max - * png_sizeof(png_charp)); - png_free(png_ptr, old_ptr); - } - else - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32) - (comp->max_output_ptr * png_sizeof(png_charp))); - } - - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_charp)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); - comp->num_output_ptr++; - - /* and reset the buffer */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - } - /* Continue until we don't have any more to compress */ - } while (png_ptr->zstream.avail_in); - - /* Finish the compression */ - do - { - /* Tell zlib we are finished */ - ret = deflate(&png_ptr->zstream, Z_FINISH); - - if (ret == Z_OK) - { - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - /* Check to make sure our output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) - { - int old_max; - - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) - { - png_charpp old_ptr; - - old_ptr = comp->output_ptr; - /* This could be optimized to realloc() */ - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32)(comp->max_output_ptr * - png_sizeof(png_charp))); - png_memcpy(comp->output_ptr, old_ptr, - old_max * png_sizeof(png_charp)); - png_free(png_ptr, old_ptr); - } - else - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32)(comp->max_output_ptr * - png_sizeof(png_charp))); - } - - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_charp)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); - comp->num_output_ptr++; - - /* and reset the buffer pointers */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - } - } - else if (ret != Z_STREAM_END) - { - /* We got an error */ - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - else - png_error(png_ptr, "zlib error"); - } - } while (ret != Z_STREAM_END); - - /* Text length is number of buffers plus last buffer */ - text_len = png_ptr->zbuf_size * comp->num_output_ptr; - if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) - text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; - - return((int)text_len); -} - -/* Ship the compressed text out via chunk writes */ -static void /* PRIVATE */ -png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) -{ - int i; - - /* Handle the no-compression case */ - if (comp->input) - { - png_write_chunk_data(png_ptr, (png_bytep)comp->input, - (png_size_t)comp->input_len); - return; - } - - /* Write saved output buffers, if any */ - for (i = 0; i < comp->num_output_ptr; i++) - { - png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i], - (png_size_t)png_ptr->zbuf_size); - png_free(png_ptr, comp->output_ptr[i]); - comp->output_ptr[i]=NULL; - } - if (comp->max_output_ptr != 0) - png_free(png_ptr, comp->output_ptr); - comp->output_ptr=NULL; - /* Write anything left in zbuf */ - if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) - png_write_chunk_data(png_ptr, png_ptr->zbuf, - (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); - - /* Reset zlib for another zTXt/iTXt or image data */ - deflateReset(&png_ptr->zstream); - png_ptr->zstream.data_type = Z_BINARY; -} -#endif - -/* Write the IHDR chunk, and update the png_struct with the necessary - * information. Note that the rest of this code depends upon this - * information being correct. - */ -void /* PRIVATE */ -png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, - int bit_depth, int color_type, int compression_type, int filter_type, - int interlace_type) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_IHDR; -#endif - int ret; - - png_byte buf[13]; /* Buffer to store the IHDR info */ - - png_debug(1, "in png_write_IHDR"); - - /* Check that we have valid input data from the application info */ - switch (color_type) - { - case PNG_COLOR_TYPE_GRAY: - switch (bit_depth) - { - case 1: - case 2: - case 4: - case 8: - case 16: png_ptr->channels = 1; break; - default: png_error(png_ptr, - "Invalid bit depth for grayscale image"); - } - break; - case PNG_COLOR_TYPE_RGB: - if (bit_depth != 8 && bit_depth != 16) - png_error(png_ptr, "Invalid bit depth for RGB image"); - png_ptr->channels = 3; - break; - case PNG_COLOR_TYPE_PALETTE: - switch (bit_depth) - { - case 1: - case 2: - case 4: - case 8: png_ptr->channels = 1; break; - default: png_error(png_ptr, "Invalid bit depth for paletted image"); - } - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - if (bit_depth != 8 && bit_depth != 16) - png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); - png_ptr->channels = 2; - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - if (bit_depth != 8 && bit_depth != 16) - png_error(png_ptr, "Invalid bit depth for RGBA image"); - png_ptr->channels = 4; - break; - default: - png_error(png_ptr, "Invalid image color type specified"); - } - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - { - png_warning(png_ptr, "Invalid compression type specified"); - compression_type = PNG_COMPRESSION_TYPE_BASE; - } - - /* Write filter_method 64 (intrapixel differencing) only if - * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and - * 2. Libpng did not write a PNG signature (this filter_method is only - * used in PNG datastreams that are embedded in MNG datastreams) and - * 3. The application called png_permit_mng_features with a mask that - * included PNG_FLAG_MNG_FILTER_64 and - * 4. The filter_method is 64 and - * 5. The color_type is RGB or RGBA - */ - if ( -#ifdef PNG_MNG_FEATURES_SUPPORTED - !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && - (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) && - (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && -#endif - filter_type != PNG_FILTER_TYPE_BASE) - { - png_warning(png_ptr, "Invalid filter type specified"); - filter_type = PNG_FILTER_TYPE_BASE; - } - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - if (interlace_type != PNG_INTERLACE_NONE && - interlace_type != PNG_INTERLACE_ADAM7) - { - png_warning(png_ptr, "Invalid interlace type specified"); - interlace_type = PNG_INTERLACE_ADAM7; - } -#else - interlace_type=PNG_INTERLACE_NONE; -#endif - - /* Save the relevent information */ - png_ptr->bit_depth = (png_byte)bit_depth; - png_ptr->color_type = (png_byte)color_type; - png_ptr->interlaced = (png_byte)interlace_type; -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_ptr->filter_type = (png_byte)filter_type; -#endif - png_ptr->compression_type = (png_byte)compression_type; - png_ptr->width = width; - png_ptr->height = height; - - png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); - /* Set the usr info, so any transformations can modify it */ - png_ptr->usr_width = png_ptr->width; - png_ptr->usr_bit_depth = png_ptr->bit_depth; - png_ptr->usr_channels = png_ptr->channels; - - /* Pack the header information into the buffer */ - png_save_uint_32(buf, width); - png_save_uint_32(buf + 4, height); - buf[8] = (png_byte)bit_depth; - buf[9] = (png_byte)color_type; - buf[10] = (png_byte)compression_type; - buf[11] = (png_byte)filter_type; - buf[12] = (png_byte)interlace_type; - - /* Write the chunk */ - png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); - - /* Initialize zlib with PNG info */ - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - if (!(png_ptr->do_filter)) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || - png_ptr->bit_depth < 8) - png_ptr->do_filter = PNG_FILTER_NONE; - else - png_ptr->do_filter = PNG_ALL_FILTERS; - } - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) - { - if (png_ptr->do_filter != PNG_FILTER_NONE) - png_ptr->zlib_strategy = Z_FILTERED; - else - png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; - } - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) - png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) - png_ptr->zlib_mem_level = 8; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) - png_ptr->zlib_window_bits = 15; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) - png_ptr->zlib_method = 8; - ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, - png_ptr->zlib_method, png_ptr->zlib_window_bits, - png_ptr->zlib_mem_level, png_ptr->zlib_strategy); - if (ret != Z_OK) - { - if (ret == Z_VERSION_ERROR) png_error(png_ptr, - "zlib failed to initialize compressor -- version error"); - if (ret == Z_STREAM_ERROR) png_error(png_ptr, - "zlib failed to initialize compressor -- stream error"); - if (ret == Z_MEM_ERROR) png_error(png_ptr, - "zlib failed to initialize compressor -- mem error"); - png_error(png_ptr, "zlib failed to initialize compressor"); - } - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - /* libpng is not interested in zstream.data_type */ - /* Set it to a predefined value, to avoid its evaluation inside zlib */ - png_ptr->zstream.data_type = Z_BINARY; - - png_ptr->mode = PNG_HAVE_IHDR; -} - -/* Write the palette. We are careful not to trust png_color to be in the - * correct order for PNG, so people can redefine it to any convenient - * structure. - */ -void /* PRIVATE */ -png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_PLTE; -#endif - png_uint_32 i; - png_colorp pal_ptr; - png_byte buf[3]; - - png_debug(1, "in png_write_PLTE"); - - if (( -#ifdef PNG_MNG_FEATURES_SUPPORTED - !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && -#endif - num_pal == 0) || num_pal > 256) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_error(png_ptr, "Invalid number of colors in palette"); - } - else - { - png_warning(png_ptr, "Invalid number of colors in palette"); - return; - } - } - - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) - { - png_warning(png_ptr, - "Ignoring request to write a PLTE chunk in grayscale PNG"); - return; - } - - png_ptr->num_palette = (png_uint_16)num_pal; - png_debug1(3, "num_palette = %d", png_ptr->num_palette); - - png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, - (png_uint_32)(num_pal * 3)); -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) - { - buf[0] = pal_ptr->red; - buf[1] = pal_ptr->green; - buf[2] = pal_ptr->blue; - png_write_chunk_data(png_ptr, buf, (png_size_t)3); - } -#else - /* This is a little slower but some buggy compilers need to do this - * instead - */ - pal_ptr=palette; - for (i = 0; i < num_pal; i++) - { - buf[0] = pal_ptr[i].red; - buf[1] = pal_ptr[i].green; - buf[2] = pal_ptr[i].blue; - png_write_chunk_data(png_ptr, buf, (png_size_t)3); - } -#endif - png_write_chunk_end(png_ptr); - png_ptr->mode |= PNG_HAVE_PLTE; -} - -/* Write an IDAT chunk */ -void /* PRIVATE */ -png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_IDAT; -#endif - - png_debug(1, "in png_write_IDAT"); - - /* Optimize the CMF field in the zlib stream. */ - /* This hack of the zlib stream is compliant to the stream specification. */ - if (!(png_ptr->mode & PNG_HAVE_IDAT) && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) - { - unsigned int z_cmf = data[0]; /* zlib compression method and flags */ - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) - { - /* Avoid memory underflows and multiplication overflows. - * - * The conditions below are practically always satisfied; - * however, they still must be checked. - */ - if (length >= 2 && - png_ptr->height < 16384 && png_ptr->width < 16384) - { - png_uint_32 uncompressed_idat_size = png_ptr->height * - ((png_ptr->width * - png_ptr->channels * png_ptr->bit_depth + 15) >> 3); - unsigned int z_cinfo = z_cmf >> 4; - unsigned int half_z_window_size = 1 << (z_cinfo + 7); - while (uncompressed_idat_size <= half_z_window_size && - half_z_window_size >= 256) - { - z_cinfo--; - half_z_window_size >>= 1; - } - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); - if (data[0] != (png_byte)z_cmf) - { - data[0] = (png_byte)z_cmf; - data[1] &= 0xe0; - data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); - } - } - } - else - png_error(png_ptr, - "Invalid zlib compression method or flags in IDAT"); - } - - png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); - png_ptr->mode |= PNG_HAVE_IDAT; -} - -/* Write an IEND chunk */ -void /* PRIVATE */ -png_write_IEND(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_IEND; -#endif - - png_debug(1, "in png_write_IEND"); - - png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL, - (png_size_t)0); - png_ptr->mode |= PNG_HAVE_IEND; -} - -#ifdef PNG_WRITE_gAMA_SUPPORTED -/* Write a gAMA chunk */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -void /* PRIVATE */ -png_write_gAMA(png_structp png_ptr, double file_gamma) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_gAMA; -#endif - png_uint_32 igamma; - png_byte buf[4]; - - png_debug(1, "in png_write_gAMA"); - - /* file_gamma is saved in 1/100,000ths */ - igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); - png_save_uint_32(buf, igamma); - png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); -} -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -void /* PRIVATE */ -png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_gAMA; -#endif - png_byte buf[4]; - - png_debug(1, "in png_write_gAMA"); - - /* file_gamma is saved in 1/100,000ths */ - png_save_uint_32(buf, (png_uint_32)file_gamma); - png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); -} -#endif -#endif - -#ifdef PNG_WRITE_sRGB_SUPPORTED -/* Write a sRGB chunk */ -void /* PRIVATE */ -png_write_sRGB(png_structp png_ptr, int srgb_intent) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_sRGB; -#endif - png_byte buf[1]; - - png_debug(1, "in png_write_sRGB"); - - if (srgb_intent >= PNG_sRGB_INTENT_LAST) - png_warning(png_ptr, - "Invalid sRGB rendering intent specified"); - buf[0]=(png_byte)srgb_intent; - png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); -} -#endif - -#ifdef PNG_WRITE_iCCP_SUPPORTED -/* Write an iCCP chunk */ -void /* PRIVATE */ -png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, - png_charp profile, int profile_len) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_iCCP; -#endif - png_size_t name_len; - png_charp new_name; - compression_state comp; - int embedded_profile_len = 0; - - png_debug(1, "in png_write_iCCP"); - - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((name_len = png_check_keyword(png_ptr, name, - &new_name)) == 0) - return; - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - png_warning(png_ptr, "Unknown compression type in iCCP chunk"); - - if (profile == NULL) - profile_len = 0; - - if (profile_len > 3) - embedded_profile_len = - ((*( (png_bytep)profile ))<<24) | - ((*( (png_bytep)profile + 1))<<16) | - ((*( (png_bytep)profile + 2))<< 8) | - ((*( (png_bytep)profile + 3)) ); - - if (embedded_profile_len < 0) - { - png_warning(png_ptr, - "Embedded profile length in iCCP chunk is negative"); - png_free(png_ptr, new_name); - return; - } - - if (profile_len < embedded_profile_len) - { - png_warning(png_ptr, - "Embedded profile length too large in iCCP chunk"); - png_free(png_ptr, new_name); - return; - } - - if (profile_len > embedded_profile_len) - { - png_warning(png_ptr, - "Truncating profile to actual length in iCCP chunk"); - profile_len = embedded_profile_len; - } - - if (profile_len) - profile_len = png_text_compress(png_ptr, profile, - (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); - - /* Make sure we include the NULL after the name and the compression type */ - png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, - (png_uint_32)(name_len + profile_len + 2)); - new_name[name_len + 1] = 0x00; - png_write_chunk_data(png_ptr, (png_bytep)new_name, - (png_size_t)(name_len + 2)); - - if (profile_len) - png_write_compressed_data_out(png_ptr, &comp); - - png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); -} -#endif - -#ifdef PNG_WRITE_sPLT_SUPPORTED -/* Write a sPLT chunk */ -void /* PRIVATE */ -png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_sPLT; -#endif - png_size_t name_len; - png_charp new_name; - png_byte entrybuf[10]; - int entry_size = (spalette->depth == 8 ? 6 : 10); - int palette_size = entry_size * spalette->nentries; - png_sPLT_entryp ep; -#ifndef PNG_POINTER_INDEXING_SUPPORTED - int i; -#endif - - png_debug(1, "in png_write_sPLT"); - - if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) - return; - - /* Make sure we include the NULL after the name */ - png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, - (png_uint_32)(name_len + 2 + palette_size)); - png_write_chunk_data(png_ptr, (png_bytep)new_name, - (png_size_t)(name_len + 1)); - png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1); - - /* Loop through each palette entry, writing appropriately */ -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (ep = spalette->entries; epentries + spalette->nentries; ep++) - { - if (spalette->depth == 8) - { - entrybuf[0] = (png_byte)ep->red; - entrybuf[1] = (png_byte)ep->green; - entrybuf[2] = (png_byte)ep->blue; - entrybuf[3] = (png_byte)ep->alpha; - png_save_uint_16(entrybuf + 4, ep->frequency); - } - else - { - png_save_uint_16(entrybuf + 0, ep->red); - png_save_uint_16(entrybuf + 2, ep->green); - png_save_uint_16(entrybuf + 4, ep->blue); - png_save_uint_16(entrybuf + 6, ep->alpha); - png_save_uint_16(entrybuf + 8, ep->frequency); - } - png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); - } -#else - ep=spalette->entries; - for (i=0; i>spalette->nentries; i++) - { - if (spalette->depth == 8) - { - entrybuf[0] = (png_byte)ep[i].red; - entrybuf[1] = (png_byte)ep[i].green; - entrybuf[2] = (png_byte)ep[i].blue; - entrybuf[3] = (png_byte)ep[i].alpha; - png_save_uint_16(entrybuf + 4, ep[i].frequency); - } - else - { - png_save_uint_16(entrybuf + 0, ep[i].red); - png_save_uint_16(entrybuf + 2, ep[i].green); - png_save_uint_16(entrybuf + 4, ep[i].blue); - png_save_uint_16(entrybuf + 6, ep[i].alpha); - png_save_uint_16(entrybuf + 8, ep[i].frequency); - } - png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); - } -#endif - - png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); -} -#endif - -#ifdef PNG_WRITE_sBIT_SUPPORTED -/* Write the sBIT chunk */ -void /* PRIVATE */ -png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_sBIT; -#endif - png_byte buf[4]; - png_size_t size; - - png_debug(1, "in png_write_sBIT"); - - /* Make sure we don't depend upon the order of PNG_COLOR_8 */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - png_byte maxbits; - - maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : - png_ptr->usr_bit_depth); - if (sbit->red == 0 || sbit->red > maxbits || - sbit->green == 0 || sbit->green > maxbits || - sbit->blue == 0 || sbit->blue > maxbits) - { - png_warning(png_ptr, "Invalid sBIT depth specified"); - return; - } - buf[0] = sbit->red; - buf[1] = sbit->green; - buf[2] = sbit->blue; - size = 3; - } - else - { - if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) - { - png_warning(png_ptr, "Invalid sBIT depth specified"); - return; - } - buf[0] = sbit->gray; - size = 1; - } - - if (color_type & PNG_COLOR_MASK_ALPHA) - { - if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) - { - png_warning(png_ptr, "Invalid sBIT depth specified"); - return; - } - buf[size++] = sbit->alpha; - } - - png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); -} -#endif - -#ifdef PNG_WRITE_cHRM_SUPPORTED -/* Write the cHRM chunk */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -void /* PRIVATE */ -png_write_cHRM(png_structp png_ptr, double white_x, double white_y, - double red_x, double red_y, double green_x, double green_y, - double blue_x, double blue_y) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_cHRM; -#endif - png_byte buf[32]; - - png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, - int_green_x, int_green_y, int_blue_x, int_blue_y; - - png_debug(1, "in png_write_cHRM"); - - int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5); - int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5); - int_red_x = (png_uint_32)(red_x * 100000.0 + 0.5); - int_red_y = (png_uint_32)(red_y * 100000.0 + 0.5); - int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5); - int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5); - int_blue_x = (png_uint_32)(blue_x * 100000.0 + 0.5); - int_blue_y = (png_uint_32)(blue_y * 100000.0 + 0.5); - -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, int_white_x, int_white_y, - int_red_x, int_red_y, int_green_x, int_green_y, int_blue_x, int_blue_y)) -#endif - { - /* Each value is saved in 1/100,000ths */ - - png_save_uint_32(buf, int_white_x); - png_save_uint_32(buf + 4, int_white_y); - - png_save_uint_32(buf + 8, int_red_x); - png_save_uint_32(buf + 12, int_red_y); - - png_save_uint_32(buf + 16, int_green_x); - png_save_uint_32(buf + 20, int_green_y); - - png_save_uint_32(buf + 24, int_blue_x); - png_save_uint_32(buf + 28, int_blue_y); - - png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); - } -} -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -void /* PRIVATE */ -png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, - png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, - png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, - png_fixed_point blue_y) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_cHRM; -#endif - png_byte buf[32]; - - png_debug(1, "in png_write_cHRM"); - - /* Each value is saved in 1/100,000ths */ -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, - green_x, green_y, blue_x, blue_y)) -#endif - { - png_save_uint_32(buf, (png_uint_32)white_x); - png_save_uint_32(buf + 4, (png_uint_32)white_y); - - png_save_uint_32(buf + 8, (png_uint_32)red_x); - png_save_uint_32(buf + 12, (png_uint_32)red_y); - - png_save_uint_32(buf + 16, (png_uint_32)green_x); - png_save_uint_32(buf + 20, (png_uint_32)green_y); - - png_save_uint_32(buf + 24, (png_uint_32)blue_x); - png_save_uint_32(buf + 28, (png_uint_32)blue_y); - - png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); - } -} -#endif -#endif - -#ifdef PNG_WRITE_tRNS_SUPPORTED -/* Write the tRNS chunk */ -void /* PRIVATE */ -png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, - int num_trans, int color_type) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_tRNS; -#endif - png_byte buf[6]; - - png_debug(1, "in png_write_tRNS"); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) - { - png_warning(png_ptr, "Invalid number of transparent colors specified"); - return; - } - /* Write the chunk out as it is */ - png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, - (png_size_t)num_trans); - } - else if (color_type == PNG_COLOR_TYPE_GRAY) - { - /* One 16 bit value */ - if (tran->gray >= (1 << png_ptr->bit_depth)) - { - png_warning(png_ptr, - "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); - return; - } - png_save_uint_16(buf, tran->gray); - png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); - } - else if (color_type == PNG_COLOR_TYPE_RGB) - { - /* Three 16 bit values */ - png_save_uint_16(buf, tran->red); - png_save_uint_16(buf + 2, tran->green); - png_save_uint_16(buf + 4, tran->blue); - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) - { - png_warning(png_ptr, - "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); - return; - } - png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); - } - else - { - png_warning(png_ptr, "Can't write tRNS with an alpha channel"); - } -} -#endif - -#ifdef PNG_WRITE_bKGD_SUPPORTED -/* Write the background chunk */ -void /* PRIVATE */ -png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_bKGD; -#endif - png_byte buf[6]; - - png_debug(1, "in png_write_bKGD"); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - if ( -#ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->num_palette || - (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && -#endif - back->index >= png_ptr->num_palette) - { - png_warning(png_ptr, "Invalid background palette index"); - return; - } - buf[0] = back->index; - png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); - } - else if (color_type & PNG_COLOR_MASK_COLOR) - { - png_save_uint_16(buf, back->red); - png_save_uint_16(buf + 2, back->green); - png_save_uint_16(buf + 4, back->blue); - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) - { - png_warning(png_ptr, - "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); - return; - } - png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); - } - else - { - if (back->gray >= (1 << png_ptr->bit_depth)) - { - png_warning(png_ptr, - "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); - return; - } - png_save_uint_16(buf, back->gray); - png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); - } -} -#endif - -#ifdef PNG_WRITE_hIST_SUPPORTED -/* Write the histogram */ -void /* PRIVATE */ -png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_hIST; -#endif - int i; - png_byte buf[3]; - - png_debug(1, "in png_write_hIST"); - - if (num_hist > (int)png_ptr->num_palette) - { - png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, - png_ptr->num_palette); - png_warning(png_ptr, "Invalid number of histogram entries specified"); - return; - } - - png_write_chunk_start(png_ptr, (png_bytep)png_hIST, - (png_uint_32)(num_hist * 2)); - for (i = 0; i < num_hist; i++) - { - png_save_uint_16(buf, hist[i]); - png_write_chunk_data(png_ptr, buf, (png_size_t)2); - } - png_write_chunk_end(png_ptr); -} -#endif - -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, - * and if invalid, correct the keyword rather than discarding the entire - * chunk. The PNG 1.0 specification requires keywords 1-79 characters in - * length, forbids leading or trailing whitespace, multiple internal spaces, - * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. - * - * The new_key is allocated to hold the corrected keyword and must be freed - * by the calling routine. This avoids problems with trying to write to - * static keywords without having to have duplicate copies of the strings. - */ -png_size_t /* PRIVATE */ -png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) -{ - png_size_t key_len; - png_charp kp, dp; - int kflag; - int kwarn=0; - - png_debug(1, "in png_check_keyword"); - - *new_key = NULL; - - if (key == NULL || (key_len = png_strlen(key)) == 0) - { - png_warning(png_ptr, "zero length keyword"); - return ((png_size_t)0); - } - - png_debug1(2, "Keyword to be checked is '%s'", key); - - *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); - if (*new_key == NULL) - { - png_warning(png_ptr, "Out of memory while procesing keyword"); - return ((png_size_t)0); - } - - /* Replace non-printing characters with a blank and print a warning */ - for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) - { - if ((png_byte)*kp < 0x20 || - ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char msg[40]; - - png_snprintf(msg, 40, - "invalid keyword character 0x%02X", (png_byte)*kp); - png_warning(png_ptr, msg); -#else - png_warning(png_ptr, "invalid character in keyword"); -#endif - *dp = ' '; - } - else - { - *dp = *kp; - } - } - *dp = '\0'; - - /* Remove any trailing white space. */ - kp = *new_key + key_len - 1; - if (*kp == ' ') - { - png_warning(png_ptr, "trailing spaces removed from keyword"); - - while (*kp == ' ') - { - *(kp--) = '\0'; - key_len--; - } - } - - /* Remove any leading white space. */ - kp = *new_key; - if (*kp == ' ') - { - png_warning(png_ptr, "leading spaces removed from keyword"); - - while (*kp == ' ') - { - kp++; - key_len--; - } - } - - png_debug1(2, "Checking for multiple internal spaces in '%s'", kp); - - /* Remove multiple internal spaces. */ - for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) - { - if (*kp == ' ' && kflag == 0) - { - *(dp++) = *kp; - kflag = 1; - } - else if (*kp == ' ') - { - key_len--; - kwarn=1; - } - else - { - *(dp++) = *kp; - kflag = 0; - } - } - *dp = '\0'; - if (kwarn) - png_warning(png_ptr, "extra interior spaces removed from keyword"); - - if (key_len == 0) - { - png_free(png_ptr, *new_key); - *new_key=NULL; - png_warning(png_ptr, "Zero length keyword"); - } - - if (key_len > 79) - { - png_warning(png_ptr, "keyword length must be 1 - 79 characters"); - (*new_key)[79] = '\0'; - key_len = 79; - } - - return (key_len); -} -#endif - -#ifdef PNG_WRITE_tEXt_SUPPORTED -/* Write a tEXt chunk */ -void /* PRIVATE */ -png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, - png_size_t text_len) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_tEXt; -#endif - png_size_t key_len; - png_charp new_key; - - png_debug(1, "in png_write_tEXt"); - - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - return; - - if (text == NULL || *text == '\0') - text_len = 0; - else - text_len = png_strlen(text); - - /* Make sure we include the 0 after the key */ - png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, - (png_uint_32)(key_len + text_len + 1)); - /* - * We leave it to the application to meet PNG-1.0 requirements on the - * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of - * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. - * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. - */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); - if (text_len) - png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len); - - png_write_chunk_end(png_ptr); - png_free(png_ptr, new_key); -} -#endif - -#ifdef PNG_WRITE_zTXt_SUPPORTED -/* Write a compressed text chunk */ -void /* PRIVATE */ -png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, - png_size_t text_len, int compression) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_zTXt; -#endif - png_size_t key_len; - char buf[1]; - png_charp new_key; - compression_state comp; - - png_debug(1, "in png_write_zTXt"); - - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - { - png_free(png_ptr, new_key); - return; - } - - if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) - { - png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); - png_free(png_ptr, new_key); - return; - } - - text_len = png_strlen(text); - - /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression, - &comp); - - /* Write start of chunk */ - png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, - (png_uint_32)(key_len+text_len + 2)); - /* Write key */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); - png_free(png_ptr, new_key); - - buf[0] = (png_byte)compression; - /* Write compression */ - png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); - /* Write the compressed data */ - png_write_compressed_data_out(png_ptr, &comp); - - /* Close the chunk */ - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_iTXt_SUPPORTED -/* Write an iTXt chunk */ -void /* PRIVATE */ -png_write_iTXt(png_structp png_ptr, int compression, png_charp key, - png_charp lang, png_charp lang_key, png_charp text) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_iTXt; -#endif - png_size_t lang_len, key_len, lang_key_len, text_len; - png_charp new_lang; - png_charp new_key = NULL; - png_byte cbuf[2]; - compression_state comp; - - png_debug(1, "in png_write_iTXt"); - - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - return; - - if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) - { - png_warning(png_ptr, "Empty language field in iTXt chunk"); - new_lang = NULL; - lang_len = 0; - } - - if (lang_key == NULL) - lang_key_len = 0; - else - lang_key_len = png_strlen(lang_key); - - if (text == NULL) - text_len = 0; - else - text_len = png_strlen(text); - - /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression-2, - &comp); - - - /* Make sure we include the compression flag, the compression byte, - * and the NULs after the key, lang, and lang_key parts */ - - png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, - (png_uint_32)( - 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ - + key_len - + lang_len - + lang_key_len - + text_len)); - - /* We leave it to the application to meet PNG-1.0 requirements on the - * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of - * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. - * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. - */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); - - /* Set the compression flag */ - if (compression == PNG_ITXT_COMPRESSION_NONE || \ - compression == PNG_TEXT_COMPRESSION_NONE) - cbuf[0] = 0; - else /* compression == PNG_ITXT_COMPRESSION_zTXt */ - cbuf[0] = 1; - /* Set the compression method */ - cbuf[1] = 0; - png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); - - cbuf[0] = 0; - png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), - (png_size_t)(lang_len + 1)); - png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), - (png_size_t)(lang_key_len + 1)); - png_write_compressed_data_out(png_ptr, &comp); - - png_write_chunk_end(png_ptr); - png_free(png_ptr, new_key); - png_free(png_ptr, new_lang); -} -#endif - -#ifdef PNG_WRITE_oFFs_SUPPORTED -/* Write the oFFs chunk */ -void /* PRIVATE */ -png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, - int unit_type) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_oFFs; -#endif - png_byte buf[9]; - - png_debug(1, "in png_write_oFFs"); - - if (unit_type >= PNG_OFFSET_LAST) - png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); - - png_save_int_32(buf, x_offset); - png_save_int_32(buf + 4, y_offset); - buf[8] = (png_byte)unit_type; - - png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); -} -#endif -#ifdef PNG_WRITE_pCAL_SUPPORTED -/* Write the pCAL chunk (described in the PNG extensions document) */ -void /* PRIVATE */ -png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, - png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_pCAL; -#endif - png_size_t purpose_len, units_len, total_len; - png_uint_32p params_len; - png_byte buf[10]; - png_charp new_purpose; - int i; - - png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); - - if (type >= PNG_EQUATION_LAST) - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); - - purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; - png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); - units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); - png_debug1(3, "pCAL units length = %d", (int)units_len); - total_len = purpose_len + units_len + 10; - - params_len = (png_uint_32p)png_malloc(png_ptr, - (png_uint_32)(nparams * png_sizeof(png_uint_32))); - - /* Find the length of each parameter, making sure we don't count the - null terminator for the last parameter. */ - for (i = 0; i < nparams; i++) - { - params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); - png_debug2(3, "pCAL parameter %d length = %lu", i, - (unsigned long) params_len[i]); - total_len += (png_size_t)params_len[i]; - } - - png_debug1(3, "pCAL total length = %d", (int)total_len); - png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, (png_bytep)new_purpose, - (png_size_t)purpose_len); - png_save_int_32(buf, X0); - png_save_int_32(buf + 4, X1); - buf[8] = (png_byte)type; - buf[9] = (png_byte)nparams; - png_write_chunk_data(png_ptr, buf, (png_size_t)10); - png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); - - png_free(png_ptr, new_purpose); - - for (i = 0; i < nparams; i++) - { - png_write_chunk_data(png_ptr, (png_bytep)params[i], - (png_size_t)params_len[i]); - } - - png_free(png_ptr, params_len); - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_sCAL_SUPPORTED -/* Write the sCAL chunk */ -#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) -void /* PRIVATE */ -png_write_sCAL(png_structp png_ptr, int unit, double width, double height) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_sCAL; -#endif - char buf[64]; - png_size_t total_len; - - png_debug(1, "in png_write_sCAL"); - - buf[0] = (char)unit; -#ifdef _WIN32_WCE -/* sprintf() function is not supported on WindowsCE */ - { - wchar_t wc_buf[32]; - size_t wc_len; - swprintf(wc_buf, TEXT("%12.12e"), width); - wc_len = wcslen(wc_buf); - WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, - NULL); - total_len = wc_len + 2; - swprintf(wc_buf, TEXT("%12.12e"), height); - wc_len = wcslen(wc_buf); - WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len, - NULL, NULL); - total_len += wc_len; - } -#else - png_snprintf(buf + 1, 63, "%12.12e", width); - total_len = 1 + png_strlen(buf + 1) + 1; - png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); - total_len += png_strlen(buf + total_len); -#endif - - png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); - png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len); -} -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -void /* PRIVATE */ -png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, - png_charp height) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_sCAL; -#endif - png_byte buf[64]; - png_size_t wlen, hlen, total_len; - - png_debug(1, "in png_write_sCAL_s"); - - wlen = png_strlen(width); - hlen = png_strlen(height); - total_len = wlen + hlen + 2; - if (total_len > 64) - { - png_warning(png_ptr, "Can't write sCAL (buffer too small)"); - return; - } - - buf[0] = (png_byte)unit; - png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ - png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ - - png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); - png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len); -} -#endif -#endif -#endif - -#ifdef PNG_WRITE_pHYs_SUPPORTED -/* Write the pHYs chunk */ -void /* PRIVATE */ -png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, - png_uint_32 y_pixels_per_unit, - int unit_type) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_pHYs; -#endif - png_byte buf[9]; - - png_debug(1, "in png_write_pHYs"); - - if (unit_type >= PNG_RESOLUTION_LAST) - png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); - - png_save_uint_32(buf, x_pixels_per_unit); - png_save_uint_32(buf + 4, y_pixels_per_unit); - buf[8] = (png_byte)unit_type; - - png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); -} -#endif - -#ifdef PNG_WRITE_tIME_SUPPORTED -/* Write the tIME chunk. Use either png_convert_from_struct_tm() - * or png_convert_from_time_t(), or fill in the structure yourself. - */ -void /* PRIVATE */ -png_write_tIME(png_structp png_ptr, png_timep mod_time) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_tIME; -#endif - png_byte buf[7]; - - png_debug(1, "in png_write_tIME"); - - if (mod_time->month > 12 || mod_time->month < 1 || - mod_time->day > 31 || mod_time->day < 1 || - mod_time->hour > 23 || mod_time->second > 60) - { - png_warning(png_ptr, "Invalid time specified for tIME chunk"); - return; - } - - png_save_uint_16(buf, mod_time->year); - buf[2] = mod_time->month; - buf[3] = mod_time->day; - buf[4] = mod_time->hour; - buf[5] = mod_time->minute; - buf[6] = mod_time->second; - - png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); -} -#endif - -/* Initializes the row writing capability of libpng */ -void /* PRIVATE */ -png_write_start_row(png_structp png_ptr) -{ -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - - png_size_t buf_size; - - png_debug(1, "in png_write_start_row"); - - buf_size = (png_size_t)(PNG_ROWBYTES( - png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); - - /* Set up row buffer */ - png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)buf_size); - png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; - -#ifdef PNG_WRITE_FILTER_SUPPORTED - /* Set up filtering buffer, if using this filter */ - if (png_ptr->do_filter & PNG_FILTER_SUB) - { - png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); - png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; - } - - /* We only need to keep the previous row if we are using one of these. */ - if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) - { - /* Set up previous row buffer */ - png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, - (png_uint_32)buf_size); - - if (png_ptr->do_filter & PNG_FILTER_UP) - { - png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); - png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; - } - - if (png_ptr->do_filter & PNG_FILTER_AVG) - { - png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); - png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; - } - - if (png_ptr->do_filter & PNG_FILTER_PAETH) - { - png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); - png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; - } - } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* If interlaced, we need to set up width and height of pass */ - if (png_ptr->interlaced) - { - if (!(png_ptr->transformations & PNG_INTERLACE)) - { - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; - png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - - png_pass_start[0]) / png_pass_inc[0]; - } - else - { - png_ptr->num_rows = png_ptr->height; - png_ptr->usr_width = png_ptr->width; - } - } - else -#endif - { - png_ptr->num_rows = png_ptr->height; - png_ptr->usr_width = png_ptr->width; - } - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; -} - -/* Internal use only. Called when finished processing a row of data. */ -void /* PRIVATE */ -png_write_finish_row(png_structp png_ptr) -{ -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - - int ret; - - png_debug(1, "in png_write_finish_row"); - - /* Next row */ - png_ptr->row_number++; - - /* See if we are done */ - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* If interlaced, go to next pass */ - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - if (png_ptr->transformations & PNG_INTERLACE) - { - png_ptr->pass++; - } - else - { - /* Loop until we find a non-zero width or height pass */ - do - { - png_ptr->pass++; - if (png_ptr->pass >= 7) - break; - png_ptr->usr_width = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - if (png_ptr->transformations & PNG_INTERLACE) - break; - } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); - - } - - /* Reset the row above the image for the next pass */ - if (png_ptr->pass < 7) - { - if (png_ptr->prev_row != NULL) - png_memset(png_ptr->prev_row, 0, - (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* - png_ptr->usr_bit_depth, png_ptr->width)) + 1); - return; - } - } -#endif - - /* If we get here, we've just written the last row, so we need - to flush the compressor */ - do - { - /* Tell the compressor we are done */ - ret = deflate(&png_ptr->zstream, Z_FINISH); - /* Check for an error */ - if (ret == Z_OK) - { - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - } - else if (ret != Z_STREAM_END) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - else - png_error(png_ptr, "zlib error"); - } - } while (ret != Z_STREAM_END); - - /* Write any extra space */ - if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) - { - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - - png_ptr->zstream.avail_out); - } - - deflateReset(&png_ptr->zstream); - png_ptr->zstream.data_type = Z_BINARY; -} - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED -/* Pick out the correct pixels for the interlace pass. - * The basic idea here is to go through the row with a source - * pointer and a destination pointer (sp and dp), and copy the - * correct pixels for the pass. As the row gets compacted, - * sp will always be >= dp, so we should never overwrite anything. - * See the default: case for the easiest code to understand. - */ -void /* PRIVATE */ -png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) -{ - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - png_debug(1, "in png_do_write_interlace"); - - /* We don't have to do anything on the last pass (6) */ -#ifdef PNG_USELESS_TESTS_SUPPORTED - if (row != NULL && row_info != NULL && pass < 6) -#else - if (pass < 6) -#endif - { - /* Each pixel depth is handled separately */ - switch (row_info->pixel_depth) - { - case 1: - { - png_bytep sp; - png_bytep dp; - int shift; - int d; - int value; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - dp = row; - d = 0; - shift = 7; - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - sp = row + (png_size_t)(i >> 3); - value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; - d |= (value << shift); - - if (shift == 0) - { - shift = 7; - *dp++ = (png_byte)d; - d = 0; - } - else - shift--; - - } - if (shift != 7) - *dp = (png_byte)d; - break; - } - case 2: - { - png_bytep sp; - png_bytep dp; - int shift; - int d; - int value; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - dp = row; - shift = 6; - d = 0; - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - sp = row + (png_size_t)(i >> 2); - value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; - d |= (value << shift); - - if (shift == 0) - { - shift = 6; - *dp++ = (png_byte)d; - d = 0; - } - else - shift -= 2; - } - if (shift != 6) - *dp = (png_byte)d; - break; - } - case 4: - { - png_bytep sp; - png_bytep dp; - int shift; - int d; - int value; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - dp = row; - shift = 4; - d = 0; - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - sp = row + (png_size_t)(i >> 1); - value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; - d |= (value << shift); - - if (shift == 0) - { - shift = 4; - *dp++ = (png_byte)d; - d = 0; - } - else - shift -= 4; - } - if (shift != 4) - *dp = (png_byte)d; - break; - } - default: - { - png_bytep sp; - png_bytep dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - png_size_t pixel_bytes; - - /* Start at the beginning */ - dp = row; - /* Find out how many bytes each pixel takes up */ - pixel_bytes = (row_info->pixel_depth >> 3); - /* Loop through the row, only looking at the pixels that - matter */ - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - /* Find out where the original pixel is */ - sp = row + (png_size_t)i * pixel_bytes; - /* Move the pixel */ - if (dp != sp) - png_memcpy(dp, sp, pixel_bytes); - /* Next pixel */ - dp += pixel_bytes; - } - break; - } - } - /* Set new row width */ - row_info->width = (row_info->width + - png_pass_inc[pass] - 1 - - png_pass_start[pass]) / - png_pass_inc[pass]; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_info->width); - } -} -#endif - -/* This filters the row, chooses which filter to use, if it has not already - * been specified by the application, and then writes the row out with the - * chosen filter. - */ -#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) -#define PNG_HISHIFT 10 -#define PNG_LOMASK ((png_uint_32)0xffffL) -#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) -void /* PRIVATE */ -png_write_find_filter(png_structp png_ptr, png_row_infop row_info) -{ - png_bytep best_row; -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_bytep prev_row, row_buf; - png_uint_32 mins, bpp; - png_byte filter_to_do = png_ptr->do_filter; - png_uint_32 row_bytes = row_info->rowbytes; -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - int num_p_filters = (int)png_ptr->num_prev_filters; -#endif - - png_debug(1, "in png_write_find_filter"); - -#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) - { - /* These will never be selected so we need not test them. */ - filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); - } -#endif - - /* Find out how many bytes offset each pixel is */ - bpp = (row_info->pixel_depth + 7) >> 3; - - prev_row = png_ptr->prev_row; -#endif - best_row = png_ptr->row_buf; -#ifdef PNG_WRITE_FILTER_SUPPORTED - row_buf = best_row; - mins = PNG_MAXSUM; - - /* The prediction method we use is to find which method provides the - * smallest value when summing the absolute values of the distances - * from zero, using anything >= 128 as negative numbers. This is known - * as the "minimum sum of absolute differences" heuristic. Other - * heuristics are the "weighted minimum sum of absolute differences" - * (experimental and can in theory improve compression), and the "zlib - * predictive" method (not implemented yet), which does test compressions - * of lines using different filter methods, and then chooses the - * (series of) filter(s) that give minimum compressed data size (VERY - * computationally expensive). - * - * GRR 980525: consider also - * (1) minimum sum of absolute differences from running average (i.e., - * keep running sum of non-absolute differences & count of bytes) - * [track dispersion, too? restart average if dispersion too large?] - * (1b) minimum sum of absolute differences from sliding average, probably - * with window size <= deflate window (usually 32K) - * (2) minimum sum of squared differences from zero or running average - * (i.e., ~ root-mean-square approach) - */ - - - /* We don't need to test the 'no filter' case if this is the only filter - * that has been chosen, as it doesn't actually do anything to the data. - */ - if ((filter_to_do & PNG_FILTER_NONE) && - filter_to_do != PNG_FILTER_NONE) - { - png_bytep rp; - png_uint_32 sum = 0; - png_uint_32 i; - int v; - - for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) - { - v = *rp; - sum += (v < 128) ? v : 256 - v; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - png_uint_32 sumhi, sumlo; - int j; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ - - /* Reduce the sum if we match any of the previous rows */ - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - /* Factor in the cost of this filter (this is here for completeness, - * but it makes no sense to have a "cost" for the NONE filter, as - * it has the minimum possible computational cost - none). - */ - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> - PNG_COST_SHIFT; - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - mins = sum; - } - - /* Sub filter */ - if (filter_to_do == PNG_FILTER_SUB) - /* It's the only filter so no testing is needed */ - { - png_bytep rp, lp, dp; - png_uint_32 i; - for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; - i++, rp++, dp++) - { - *dp = *rp; - } - for (lp = row_buf + 1; i < row_bytes; - i++, rp++, lp++, dp++) - { - *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - } - best_row = png_ptr->sub_row; - } - - else if (filter_to_do & PNG_FILTER_SUB) - { - png_bytep rp, dp, lp; - png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; - int v; - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - /* We temporarily increase the "minimum sum" by the factor we - * would reduce the sum of this filter, so that we can do the - * early exit comparison without scaling the sum each time. - */ - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; - i++, rp++, dp++) - { - v = *dp = *rp; - - sum += (v < 128) ? v : 256 - v; - } - for (lp = row_buf + 1; i < row_bytes; - i++, rp++, lp++, dp++) - { - v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) - { - sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - mins = sum; - best_row = png_ptr->sub_row; - } - } - - /* Up filter */ - if (filter_to_do == PNG_FILTER_UP) - { - png_bytep rp, dp, pp; - png_uint_32 i; - - for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, - pp = prev_row + 1; i < row_bytes; - i++, rp++, pp++, dp++) - { - *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); - } - best_row = png_ptr->up_row; - } - - else if (filter_to_do & PNG_FILTER_UP) - { - png_bytep rp, dp, pp; - png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; - int v; - - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, - pp = prev_row + 1; i < row_bytes; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - mins = sum; - best_row = png_ptr->up_row; - } - } - - /* Avg filter */ - if (filter_to_do == PNG_FILTER_AVG) - { - png_bytep rp, dp, pp, lp; - png_uint_32 i; - for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); - } - for (lp = row_buf + 1; i < row_bytes; i++) - { - *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); - } - best_row = png_ptr->avg_row; - } - - else if (filter_to_do & PNG_FILTER_AVG) - { - png_bytep rp, dp, pp, lp; - png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; - int v; - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); - - sum += (v < 128) ? v : 256 - v; - } - for (lp = row_buf + 1; i < row_bytes; i++) - { - v = *dp++ = - (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - mins = sum; - best_row = png_ptr->avg_row; - } - } - - /* Paeth filter */ - if (filter_to_do == PNG_FILTER_PAETH) - { - png_bytep rp, dp, pp, cp, lp; - png_uint_32 i; - for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - } - - for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) - { - int a, b, c, pa, pb, pc, p; - - b = *pp++; - c = *cp++; - a = *lp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - - *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); - } - best_row = png_ptr->paeth_row; - } - - else if (filter_to_do & PNG_FILTER_PAETH) - { - png_bytep rp, dp, pp, cp, lp; - png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; - int v; - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - - sum += (v < 128) ? v : 256 - v; - } - - for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) - { - int a, b, c, pa, pb, pc, p; - - b = *pp++; - c = *cp++; - a = *lp++; - -#ifndef PNG_SLOW_PAETH - p = b - c; - pc = a - c; -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; -#else /* PNG_SLOW_PAETH */ - p = a + b - c; - pa = abs(p - a); - pb = abs(p - b); - pc = abs(p - c); - if (pa <= pb && pa <= pc) - p = a; - else if (pb <= pc) - p = b; - else - p = c; -#endif /* PNG_SLOW_PAETH */ - - v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - best_row = png_ptr->paeth_row; - } - } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - /* Do the actual writing of the filtered row data from the chosen filter. */ - - png_write_filtered_row(png_ptr, best_row); - -#ifdef PNG_WRITE_FILTER_SUPPORTED -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - /* Save the type of filter we picked this time for future calculations */ - if (png_ptr->num_prev_filters > 0) - { - int j; - for (j = 1; j < num_p_filters; j++) - { - png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; - } - png_ptr->prev_filters[j] = best_row[0]; - } -#endif -#endif /* PNG_WRITE_FILTER_SUPPORTED */ -} - - -/* Do the actual writing of a previously filtered row. */ -void /* PRIVATE */ -png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) -{ - png_debug(1, "in png_write_filtered_row"); - - png_debug1(2, "filter = %d", filtered_row[0]); - /* Set up the zlib input buffer */ - - png_ptr->zstream.next_in = filtered_row; - png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; - /* Repeat until we have compressed all the data */ - do - { - int ret; /* Return of zlib */ - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); - /* Check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - else - png_error(png_ptr, "zlib error"); - } - - /* See if it is time to write another IDAT */ - if (!(png_ptr->zstream.avail_out)) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - /* Repeat until all data has been compressed */ - } while (png_ptr->zstream.avail_in); - - /* Swap the current and previous rows */ - if (png_ptr->prev_row != NULL) - { - png_bytep tptr; - - tptr = png_ptr->prev_row; - png_ptr->prev_row = png_ptr->row_buf; - png_ptr->row_buf = tptr; - } - - /* Finish row - updates counters and flushes zlib if last row */ - png_write_finish_row(png_ptr); - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_ptr->flush_rows++; - - if (png_ptr->flush_dist > 0 && - png_ptr->flush_rows >= png_ptr->flush_dist) - { - png_write_flush(png_ptr); - } -#endif -} -#endif /* PNG_WRITE_SUPPORTED */ + +/* pngwutil.c - utilities to write a PNG file + * + * Last changed in libpng 1.2.43 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void PNGAPI +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} + +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. + */ +void PNGAPI +png_save_int_32(png_bytep buf, png_int_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void PNGAPI +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xff); + buf[1] = (png_byte)(i & 0xff); +} + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void /* PRIVATE */ +png_write_sig(png_structp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + + /* Write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (png_size_t)(8 - png_ptr->sig_bytes)); + if (png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +void PNGAPI +png_write_chunk(png_structp png_ptr, png_bytep chunk_name, + png_bytep data, png_size_t length) +{ + if (png_ptr == NULL) + return; + png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, (png_size_t)length); + png_write_chunk_end(png_ptr); +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +void PNGAPI +png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, + png_uint_32 length) +{ + png_byte buf[8]; + + png_debug2(0, "Writing %s chunk, length = %lu", chunk_name, + (unsigned long)length); + + if (png_ptr == NULL) + return; + + + /* Write the length and the chunk name */ + png_save_uint_32(buf, length); + png_memcpy(buf + 4, chunk_name, 4); + png_write_data(png_ptr, buf, (png_size_t)8); + /* Put the chunk name into png_ptr->chunk_name */ + png_memcpy(png_ptr->chunk_name, chunk_name, 4); + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); +} + +/* Write the data of a PNG chunk started with png_write_chunk_start(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_start(). + */ +void PNGAPI +png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + /* Write the data, and run the CRC over it */ + if (png_ptr == NULL) + return; + if (data != NULL && length > 0) + { + png_write_data(png_ptr, data, length); + /* Update the CRC after writing the data, + * in case that the user I/O routine alters it. + */ + png_calculate_crc(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_start(). */ +void PNGAPI +png_write_chunk_end(png_structp png_ptr) +{ + png_byte buf[4]; + + if (png_ptr == NULL) return; + + /* Write the crc in a single operation */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, (png_size_t)4); +} + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) +/* This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller in order to make the whole mess thread-safe. + */ + +typedef struct +{ + char *input; /* The uncompressed input data */ + int input_len; /* Its length */ + int num_output_ptr; /* Number of output pointers used */ + int max_output_ptr; /* Size of output_ptr */ + png_charpp output_ptr; /* Array of pointers to output */ +} compression_state; + +/* Compress given text into storage in the png_ptr structure */ +static int /* PRIVATE */ +png_text_compress(png_structp png_ptr, + png_charp text, png_size_t text_len, int compression, + compression_state *comp) +{ + int ret; + + comp->num_output_ptr = 0; + comp->max_output_ptr = 0; + comp->output_ptr = NULL; + comp->input = NULL; + comp->input_len = 0; + + /* We may just want to pass the text right through */ + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + comp->input = text; + comp->input_len = text_len; + return((int)text_len); + } + + if (compression >= PNG_TEXT_COMPRESSION_LAST) + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char msg[50]; + png_snprintf(msg, 50, "Unknown compression type %d", compression); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "Unknown compression type"); +#endif + } + + /* We can't write the chunk until we find out how much data we have, + * which means we need to run the compressor first and save the + * output. This shouldn't be a problem, as the vast majority of + * comments should be reasonable, but we will set up an array of + * malloc'd pointers to be sure. + * + * If we knew the application was well behaved, we could simplify this + * greatly by assuming we can always malloc an output buffer large + * enough to hold the compressed text ((1001 * text_len / 1000) + 12) + * and malloc this directly. The only time this would be a bad idea is + * if we can't malloc more than 64K and we have 64K of random input + * data, or if the input string is incredibly large (although this + * wouldn't cause a failure, just a slowdown due to swapping). + */ + + /* Set up the compression buffers */ + png_ptr->zstream.avail_in = (uInt)text_len; + png_ptr->zstream.next_in = (Bytef *)text; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; + + /* This is the same compression loop as in png_write_row() */ + do + { + /* Compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + if (ret != Z_OK) + { + /* Error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + /* Check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* Make sure the output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32) + (comp->max_output_ptr * png_sizeof(png_charpp))); + png_memcpy(comp->output_ptr, old_ptr, old_max + * png_sizeof(png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32) + (comp->max_output_ptr * png_sizeof(png_charp))); + } + + /* Save the data */ + comp->output_ptr[comp->num_output_ptr] = + (png_charp)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + /* Continue until we don't have any more to compress */ + } while (png_ptr->zstream.avail_in); + + /* Finish the compression */ + do + { + /* Tell zlib we are finished */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + + if (ret == Z_OK) + { + /* Check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* Check to make sure our output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + /* This could be optimized to realloc() */ + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * + png_sizeof(png_charp))); + png_memcpy(comp->output_ptr, old_ptr, + old_max * png_sizeof(png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * + png_sizeof(png_charp))); + } + + /* Save the data */ + comp->output_ptr[comp->num_output_ptr] = + (png_charp)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer pointers */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + } + else if (ret != Z_STREAM_END) + { + /* We got an error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* Text length is number of buffers plus last buffer */ + text_len = png_ptr->zbuf_size * comp->num_output_ptr; + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; + + return((int)text_len); +} + +/* Ship the compressed text out via chunk writes */ +static void /* PRIVATE */ +png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) +{ + int i; + + /* Handle the no-compression case */ + if (comp->input) + { + png_write_chunk_data(png_ptr, (png_bytep)comp->input, + (png_size_t)comp->input_len); + return; + } + + /* Write saved output buffers, if any */ + for (i = 0; i < comp->num_output_ptr; i++) + { + png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i], + (png_size_t)png_ptr->zbuf_size); + png_free(png_ptr, comp->output_ptr[i]); + comp->output_ptr[i]=NULL; + } + if (comp->max_output_ptr != 0) + png_free(png_ptr, comp->output_ptr); + comp->output_ptr=NULL; + /* Write anything left in zbuf */ + if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) + png_write_chunk_data(png_ptr, png_ptr->zbuf, + (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); + + /* Reset zlib for another zTXt/iTXt or image data */ + deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; +} +#endif + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; +#endif + int ret; + + png_byte buf[13]; /* Buffer to store the IHDR info */ + + png_debug(1, "in png_write_IHDR"); + + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + case 16: png_ptr->channels = 1; break; + default: png_error(png_ptr, + "Invalid bit depth for grayscale image"); + } + break; + case PNG_COLOR_TYPE_RGB: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGB image"); + png_ptr->channels = 3; + break; + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: png_ptr->channels = 1; break; + default: png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + png_ptr->channels = 2; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGBA image"); + png_ptr->channels = 4; + break; + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* Save the relevent information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); + /* Set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* Pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* Write the chunk */ + png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); + + /* Initialize zlib with PNG info */ + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + if (!(png_ptr->do_filter)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) + { + if (png_ptr->do_filter != PNG_FILTER_NONE) + png_ptr->zlib_strategy = Z_FILTERED; + else + png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) + png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) + png_ptr->zlib_mem_level = 8; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) + png_ptr->zlib_window_bits = 15; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) + png_ptr->zlib_method = 8; + ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, + png_ptr->zlib_method, png_ptr->zlib_window_bits, + png_ptr->zlib_mem_level, png_ptr->zlib_strategy); + if (ret != Z_OK) + { + if (ret == Z_VERSION_ERROR) png_error(png_ptr, + "zlib failed to initialize compressor -- version error"); + if (ret == Z_STREAM_ERROR) png_error(png_ptr, + "zlib failed to initialize compressor -- stream error"); + if (ret == Z_MEM_ERROR) png_error(png_ptr, + "zlib failed to initialize compressor -- mem error"); + png_error(png_ptr, "zlib failed to initialize compressor"); + } + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + /* libpng is not interested in zstream.data_type */ + /* Set it to a predefined value, to avoid its evaluation inside zlib */ + png_ptr->zstream.data_type = Z_BINARY; + + png_ptr->mode = PNG_HAVE_IHDR; +} + +/* Write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_PLTE; +#endif + png_uint_32 i; + png_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE"); + + if (( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && +#endif + num_pal == 0) || num_pal > 256) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d", png_ptr->num_palette); + + png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, + (png_uint_32)(num_pal * 3)); +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#else + /* This is a little slower but some buggy compilers need to do this + * instead + */ + pal_ptr=palette; + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* Write an IDAT chunk */ +void /* PRIVATE */ +png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + + png_debug(1, "in png_write_IDAT"); + + /* Optimize the CMF field in the zlib stream. */ + /* This hack of the zlib stream is compliant to the stream specification. */ + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + /* Avoid memory underflows and multiplication overflows. + * + * The conditions below are practically always satisfied; + * however, they still must be checked. + */ + if (length >= 2 && + png_ptr->height < 16384 && png_ptr->width < 16384) + { + png_uint_32 uncompressed_idat_size = png_ptr->height * + ((png_ptr->width * + png_ptr->channels * png_ptr->bit_depth + 15) >> 3); + unsigned int z_cinfo = z_cmf >> 4; + unsigned int half_z_window_size = 1 << (z_cinfo + 7); + while (uncompressed_idat_size <= half_z_window_size && + half_z_window_size >= 256) + { + z_cinfo--; + half_z_window_size >>= 1; + } + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + if (data[0] != (png_byte)z_cmf) + { + data[0] = (png_byte)z_cmf; + data[1] &= 0xe0; + data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); + } + } + } + else + png_error(png_ptr, + "Invalid zlib compression method or flags in IDAT"); + } + + png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); + png_ptr->mode |= PNG_HAVE_IDAT; +} + +/* Write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IEND; +#endif + + png_debug(1, "in png_write_IEND"); + + png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL, + (png_size_t)0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#ifdef PNG_WRITE_gAMA_SUPPORTED +/* Write a gAMA chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA(png_structp png_ptr, double file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_uint_32 igamma; + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); + png_save_uint_32(buf, igamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, (png_uint_32)file_gamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +/* Write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structp png_ptr, int srgb_intent) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sRGB; +#endif + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB"); + + if (srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + buf[0]=(png_byte)srgb_intent; + png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); +} +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +/* Write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, + png_charp profile, int profile_len) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_iCCP; +#endif + png_size_t name_len; + png_charp new_name; + compression_state comp; + int embedded_profile_len = 0; + + png_debug(1, "in png_write_iCCP"); + + comp.num_output_ptr = 0; + comp.max_output_ptr = 0; + comp.output_ptr = NULL; + comp.input = NULL; + comp.input_len = 0; + + if ((name_len = png_check_keyword(png_ptr, name, + &new_name)) == 0) + return; + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_warning(png_ptr, "Unknown compression type in iCCP chunk"); + + if (profile == NULL) + profile_len = 0; + + if (profile_len > 3) + embedded_profile_len = + ((*( (png_bytep)profile ))<<24) | + ((*( (png_bytep)profile + 1))<<16) | + ((*( (png_bytep)profile + 2))<< 8) | + ((*( (png_bytep)profile + 3)) ); + + if (embedded_profile_len < 0) + { + png_warning(png_ptr, + "Embedded profile length in iCCP chunk is negative"); + png_free(png_ptr, new_name); + return; + } + + if (profile_len < embedded_profile_len) + { + png_warning(png_ptr, + "Embedded profile length too large in iCCP chunk"); + png_free(png_ptr, new_name); + return; + } + + if (profile_len > embedded_profile_len) + { + png_warning(png_ptr, + "Truncating profile to actual length in iCCP chunk"); + profile_len = embedded_profile_len; + } + + if (profile_len) + profile_len = png_text_compress(png_ptr, profile, + (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); + + /* Make sure we include the NULL after the name and the compression type */ + png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, + (png_uint_32)(name_len + profile_len + 2)); + new_name[name_len + 1] = 0x00; + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 2)); + + if (profile_len) + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +/* Write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sPLT; +#endif + png_size_t name_len; + png_charp new_name; + png_byte entrybuf[10]; + int entry_size = (spalette->depth == 8 ? 6 : 10); + int palette_size = entry_size * spalette->nentries; + png_sPLT_entryp ep; +#ifndef PNG_POINTER_INDEXING_SUPPORTED + int i; +#endif + + png_debug(1, "in png_write_sPLT"); + + if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) + return; + + /* Make sure we include the NULL after the name */ + png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 1)); + png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1); + + /* Loop through each palette entry, writing appropriately */ +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (ep = spalette->entries; epentries + spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + } +#else + ep=spalette->entries; + for (i=0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + } +#endif + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +/* Write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sBIT; +#endif + png_byte buf[4]; + png_size_t size; + + png_debug(1, "in png_write_sBIT"); + + /* Make sure we don't depend upon the order of PNG_COLOR_8 */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->gray; + size = 1; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[size++] = sbit->alpha; + } + + png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); +} +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +/* Write the cHRM chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM(png_structp png_ptr, double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, + int_green_x, int_green_y, int_blue_x, int_blue_y; + + png_debug(1, "in png_write_cHRM"); + + int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5); + int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5); + int_red_x = (png_uint_32)(red_x * 100000.0 + 0.5); + int_red_y = (png_uint_32)(red_y * 100000.0 + 0.5); + int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5); + int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5); + int_blue_x = (png_uint_32)(blue_x * 100000.0 + 0.5); + int_blue_y = (png_uint_32)(blue_y * 100000.0 + 0.5); + +#ifdef PNG_CHECK_cHRM_SUPPORTED + if (png_check_cHRM_fixed(png_ptr, int_white_x, int_white_y, + int_red_x, int_red_y, int_green_x, int_green_y, int_blue_x, int_blue_y)) +#endif + { + /* Each value is saved in 1/100,000ths */ + + png_save_uint_32(buf, int_white_x); + png_save_uint_32(buf + 4, int_white_y); + + png_save_uint_32(buf + 8, int_red_x); + png_save_uint_32(buf + 12, int_red_y); + + png_save_uint_32(buf + 16, int_green_x); + png_save_uint_32(buf + 20, int_green_y); + + png_save_uint_32(buf + 24, int_blue_x); + png_save_uint_32(buf + 28, int_blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); + } +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, + png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, + png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, + png_fixed_point blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM"); + + /* Each value is saved in 1/100,000ths */ +#ifdef PNG_CHECK_cHRM_SUPPORTED + if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, + green_x, green_y, blue_x, blue_y)) +#endif + { + png_save_uint_32(buf, (png_uint_32)white_x); + png_save_uint_32(buf + 4, (png_uint_32)white_y); + + png_save_uint_32(buf + 8, (png_uint_32)red_x); + png_save_uint_32(buf + 12, (png_uint_32)red_y); + + png_save_uint_32(buf + 16, (png_uint_32)green_x); + png_save_uint_32(buf + 20, (png_uint_32)green_y); + + png_save_uint_32(buf + 24, (png_uint_32)blue_x); + png_save_uint_32(buf + 28, (png_uint_32)blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); + } +} +#endif +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +/* Write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, + int num_trans, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tRNS; +#endif + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid number of transparent colors specified"); + return; + } + /* Write the chunk out as it is */ + png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, + (png_size_t)num_trans); + } + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* One 16 bit value */ + if (tran->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + return; + } + png_save_uint_16(buf, tran->gray); + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); + } + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* Three 16 bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + return; + } + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); + } + else + { + png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +/* Write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_bKGD; +#endif + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->num_palette || + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && +#endif + back->index >= png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + buf[0] = back->index; + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); + } + else if (color_type & PNG_COLOR_MASK_COLOR) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + return; + } + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); + } + else + { + if (back->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + return; + } + png_save_uint_16(buf, back->gray); + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); + } +} +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +/* Write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_hIST; +#endif + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST"); + + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, + png_ptr->num_palette); + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_start(png_ptr, (png_bytep)png_hIST, + (png_uint_32)(num_hist * 2)); + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); + } + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The new_key is allocated to hold the corrected keyword and must be freed + * by the calling routine. This avoids problems with trying to write to + * static keywords without having to have duplicate copies of the strings. + */ +png_size_t /* PRIVATE */ +png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) +{ + png_size_t key_len; + png_charp kp, dp; + int kflag; + int kwarn=0; + + png_debug(1, "in png_check_keyword"); + + *new_key = NULL; + + if (key == NULL || (key_len = png_strlen(key)) == 0) + { + png_warning(png_ptr, "zero length keyword"); + return ((png_size_t)0); + } + + png_debug1(2, "Keyword to be checked is '%s'", key); + + *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); + if (*new_key == NULL) + { + png_warning(png_ptr, "Out of memory while procesing keyword"); + return ((png_size_t)0); + } + + /* Replace non-printing characters with a blank and print a warning */ + for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) + { + if ((png_byte)*kp < 0x20 || + ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + char msg[40]; + + png_snprintf(msg, 40, + "invalid keyword character 0x%02X", (png_byte)*kp); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "invalid character in keyword"); +#endif + *dp = ' '; + } + else + { + *dp = *kp; + } + } + *dp = '\0'; + + /* Remove any trailing white space. */ + kp = *new_key + key_len - 1; + if (*kp == ' ') + { + png_warning(png_ptr, "trailing spaces removed from keyword"); + + while (*kp == ' ') + { + *(kp--) = '\0'; + key_len--; + } + } + + /* Remove any leading white space. */ + kp = *new_key; + if (*kp == ' ') + { + png_warning(png_ptr, "leading spaces removed from keyword"); + + while (*kp == ' ') + { + kp++; + key_len--; + } + } + + png_debug1(2, "Checking for multiple internal spaces in '%s'", kp); + + /* Remove multiple internal spaces. */ + for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) + { + if (*kp == ' ' && kflag == 0) + { + *(dp++) = *kp; + kflag = 1; + } + else if (*kp == ' ') + { + key_len--; + kwarn=1; + } + else + { + *(dp++) = *kp; + kflag = 0; + } + } + *dp = '\0'; + if (kwarn) + png_warning(png_ptr, "extra interior spaces removed from keyword"); + + if (key_len == 0) + { + png_free(png_ptr, *new_key); + *new_key=NULL; + png_warning(png_ptr, "Zero length keyword"); + } + + if (key_len > 79) + { + png_warning(png_ptr, "keyword length must be 1 - 79 characters"); + (*new_key)[79] = '\0'; + key_len = 79; + } + + return (key_len); +} +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +/* Write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tEXt; +#endif + png_size_t key_len; + png_charp new_key; + + png_debug(1, "in png_write_tEXt"); + + if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + return; + + if (text == NULL || *text == '\0') + text_len = 0; + else + text_len = png_strlen(text); + + /* Make sure we include the 0 after the key */ + png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, + (png_uint_32)(key_len + text_len + 1)); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, + (png_size_t)(key_len + 1)); + if (text_len) + png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); +} +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +/* Write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len, int compression) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_zTXt; +#endif + png_size_t key_len; + char buf[1]; + png_charp new_key; + compression_state comp; + + png_debug(1, "in png_write_zTXt"); + + comp.num_output_ptr = 0; + comp.max_output_ptr = 0; + comp.output_ptr = NULL; + comp.input = NULL; + comp.input_len = 0; + + if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_free(png_ptr, new_key); + return; + } + + if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); + png_free(png_ptr, new_key); + return; + } + + text_len = png_strlen(text); + + /* Compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression, + &comp); + + /* Write start of chunk */ + png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, + (png_uint_32)(key_len+text_len + 2)); + /* Write key */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, + (png_size_t)(key_len + 1)); + png_free(png_ptr, new_key); + + buf[0] = (png_byte)compression; + /* Write compression */ + png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); + /* Write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* Close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +/* Write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structp png_ptr, int compression, png_charp key, + png_charp lang, png_charp lang_key, png_charp text) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_iTXt; +#endif + png_size_t lang_len, key_len, lang_key_len, text_len; + png_charp new_lang; + png_charp new_key = NULL; + png_byte cbuf[2]; + compression_state comp; + + png_debug(1, "in png_write_iTXt"); + + comp.num_output_ptr = 0; + comp.max_output_ptr = 0; + comp.output_ptr = NULL; + comp.input = NULL; + + if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + return; + + if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) + { + png_warning(png_ptr, "Empty language field in iTXt chunk"); + new_lang = NULL; + lang_len = 0; + } + + if (lang_key == NULL) + lang_key_len = 0; + else + lang_key_len = png_strlen(lang_key); + + if (text == NULL) + text_len = 0; + else + text_len = png_strlen(text); + + /* Compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression-2, + &comp); + + + /* Make sure we include the compression flag, the compression byte, + * and the NULs after the key, lang, and lang_key parts */ + + png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, + (png_uint_32)( + 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ + + key_len + + lang_len + + lang_key_len + + text_len)); + + /* We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, + (png_size_t)(key_len + 1)); + + /* Set the compression flag */ + if (compression == PNG_ITXT_COMPRESSION_NONE || \ + compression == PNG_TEXT_COMPRESSION_NONE) + cbuf[0] = 0; + else /* compression == PNG_ITXT_COMPRESSION_zTXt */ + cbuf[0] = 1; + /* Set the compression method */ + cbuf[1] = 0; + png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); + + cbuf[0] = 0; + png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), + (png_size_t)(lang_len + 1)); + png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), + (png_size_t)(lang_key_len + 1)); + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); + png_free(png_ptr, new_lang); +} +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +/* Write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_oFFs; +#endif + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs"); + + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_int_32(buf, x_offset); + png_save_int_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); +} +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED +/* Write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_pCAL; +#endif + png_size_t purpose_len, units_len, total_len; + png_uint_32p params_len; + png_byte buf[10]; + png_charp new_purpose; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); + + if (type >= PNG_EQUATION_LAST) + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; + png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); + units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (png_uint_32p)png_malloc(png_ptr, + (png_uint_32)(nparams * png_sizeof(png_uint_32))); + + /* Find the length of each parameter, making sure we don't count the + null terminator for the last parameter. */ + for (i = 0; i < nparams; i++) + { + params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu", i, + (unsigned long) params_len[i]); + total_len += (png_size_t)params_len[i]; + } + + png_debug1(3, "pCAL total length = %d", (int)total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)new_purpose, + (png_size_t)purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); + + png_free(png_ptr, new_purpose); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_bytep)params[i], + (png_size_t)params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +/* Write the sCAL chunk */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +void /* PRIVATE */ +png_write_sCAL(png_structp png_ptr, int unit, double width, double height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + char buf[64]; + png_size_t total_len; + + png_debug(1, "in png_write_sCAL"); + + buf[0] = (char)unit; +#ifdef _WIN32_WCE +/* sprintf() function is not supported on WindowsCE */ + { + wchar_t wc_buf[32]; + size_t wc_len; + swprintf(wc_buf, TEXT("%12.12e"), width); + wc_len = wcslen(wc_buf); + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, + NULL); + total_len = wc_len + 2; + swprintf(wc_buf, TEXT("%12.12e"), height); + wc_len = wcslen(wc_buf); + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len, + NULL, NULL); + total_len += wc_len; + } +#else + png_snprintf(buf + 1, 63, "%12.12e", width); + total_len = 1 + png_strlen(buf + 1) + 1; + png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); + total_len += png_strlen(buf + total_len); +#endif + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, + png_charp height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + png_byte buf[64]; + png_size_t wlen, hlen, total_len; + + png_debug(1, "in png_write_sCAL_s"); + + wlen = png_strlen(width); + hlen = png_strlen(height); + total_len = wlen + hlen + 2; + if (total_len > 64) + { + png_warning(png_ptr, "Can't write sCAL (buffer too small)"); + return; + } + + buf[0] = (png_byte)unit; + png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len); +} +#endif +#endif +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +/* Write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_pHYs; +#endif + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs"); + + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); +} +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structp png_ptr, png_timep mod_time) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tIME; +#endif + png_byte buf[7]; + + png_debug(1, "in png_write_tIME"); + + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); +} +#endif + +/* Initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_size_t buf_size; + + png_debug(1, "in png_write_start_row"); + + buf_size = (png_size_t)(PNG_ROWBYTES( + png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); + + /* Set up row buffer */ + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)buf_size); + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* Set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + /* We only need to keep the previous row if we are using one of these. */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* Set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, + (png_uint_32)buf_size); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int ret; + + png_debug(1, "in png_write_finish_row"); + + /* Next row */ + png_ptr->row_number++; + + /* See if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, go to next pass */ + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + if (png_ptr->transformations & PNG_INTERLACE) + { + png_ptr->pass++; + } + else + { + /* Loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (png_ptr->transformations & PNG_INTERLACE) + break; + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* Reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + png_memset(png_ptr->prev_row, 0, + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth, png_ptr->width)) + 1); + return; + } + } +#endif + + /* If we get here, we've just written the last row, so we need + to flush the compressor */ + do + { + /* Tell the compressor we are done */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + /* Check for an error */ + if (ret == Z_OK) + { + /* Check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else if (ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* Write any extra space */ + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - + png_ptr->zstream.avail_out); + } + + deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; +} + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_write_interlace"); + + /* We don't have to do anything on the last pass (6) */ +#ifdef PNG_USELESS_TESTS_SUPPORTED + if (row != NULL && row_info != NULL && pass < 6) +#else + if (pass < 6) +#endif + { + /* Each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + break; + } + case 2: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + break; + } + case 4: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + break; + } + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + png_size_t pixel_bytes; + + /* Start at the beginning */ + dp = row; + /* Find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + /* Loop through the row, only looking at the pixels that + matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* Find out where the original pixel is */ + sp = row + (png_size_t)i * pixel_bytes; + /* Move the pixel */ + if (dp != sp) + png_memcpy(dp, sp, pixel_bytes); + /* Next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* Set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) +#define PNG_HISHIFT 10 +#define PNG_LOMASK ((png_uint_32)0xffffL) +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) +void /* PRIVATE */ +png_write_find_filter(png_structp png_ptr, png_row_infop row_info) +{ + png_bytep best_row; +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_bytep prev_row, row_buf; + png_uint_32 mins, bpp; + png_byte filter_to_do = png_ptr->do_filter; + png_uint_32 row_bytes = row_info->rowbytes; +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + int num_p_filters = (int)png_ptr->num_prev_filters; +#endif + + png_debug(1, "in png_write_find_filter"); + +#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) + { + /* These will never be selected so we need not test them. */ + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); + } +#endif + + /* Find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) >> 3; + + prev_row = png_ptr->prev_row; +#endif + best_row = png_ptr->row_buf; +#ifdef PNG_WRITE_FILTER_SUPPORTED + row_buf = best_row; + mins = PNG_MAXSUM; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + if ((filter_to_do & PNG_FILTER_NONE) && + filter_to_do != PNG_FILTER_NONE) + { + png_bytep rp; + png_uint_32 sum = 0; + png_uint_32 i; + int v; + + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + png_uint_32 sumhi, sumlo; + int j; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ + + /* Reduce the sum if we match any of the previous rows */ + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + /* Factor in the cost of this filter (this is here for completeness, + * but it makes no sense to have a "cost" for the NONE filter, as + * it has the minimum possible computational cost - none). + */ + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + mins = sum; + } + + /* Sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* It's the only filter so no testing is needed */ + { + png_bytep rp, lp, dp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } + best_row = png_ptr->sub_row; + } + + else if (filter_to_do & PNG_FILTER_SUB) + { + png_bytep rp, dp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* We temporarily increase the "minimum sum" by the factor we + * would reduce the sum of this filter, so that we can do the + * early exit comparison without scaling the sum each time. + */ + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->sub_row; + } + } + + /* Up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } + best_row = png_ptr->up_row; + } + + else if (filter_to_do & PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->up_row; + } + } + + /* Avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } + best_row = png_ptr->avg_row; + } + + else if (filter_to_do & PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->avg_row; + } + } + + /* Paeth filter */ + if (filter_to_do == PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } + best_row = png_ptr->paeth_row; + } + + else if (filter_to_do & PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + +#ifndef PNG_SLOW_PAETH + p = b - c; + pc = a - c; +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; +#else /* PNG_SLOW_PAETH */ + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; +#endif /* PNG_SLOW_PAETH */ + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + best_row = png_ptr->paeth_row; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + /* Do the actual writing of the filtered row data from the chosen filter. */ + + png_write_filtered_row(png_ptr, best_row); + +#ifdef PNG_WRITE_FILTER_SUPPORTED +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* Save the type of filter we picked this time for future calculations */ + if (png_ptr->num_prev_filters > 0) + { + int j; + for (j = 1; j < num_p_filters; j++) + { + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; + } + png_ptr->prev_filters[j] = best_row[0]; + } +#endif +#endif /* PNG_WRITE_FILTER_SUPPORTED */ +} + + +/* Do the actual writing of a previously filtered row. */ +void /* PRIVATE */ +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +{ + png_debug(1, "in png_write_filtered_row"); + + png_debug1(2, "filter = %d", filtered_row[0]); + /* Set up the zlib input buffer */ + + png_ptr->zstream.next_in = filtered_row; + png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; + /* Repeat until we have compressed all the data */ + do + { + int ret; /* Return of zlib */ + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + /* Check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + /* See if it is time to write another IDAT */ + if (!(png_ptr->zstream.avail_out)) + { + /* Write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + /* Repeat until all data has been compressed */ + } while (png_ptr->zstream.avail_in); + + /* Swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } + + /* Finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif +} +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/main/source/includes/lpng1610/ANNOUNCE b/main/source/includes/lpng1610/ANNOUNCE index bfd62d13..9f198806 100644 --- a/main/source/includes/lpng1610/ANNOUNCE +++ b/main/source/includes/lpng1610/ANNOUNCE @@ -1,93 +1,93 @@ - -Libpng 1.6.10 - March 6, 2014 - -This is a public release of libpng, intended for use in production codes. - -Files available for download: - -Source files with LF line endings (for Unix/Linux) and with a -"configure" script - - libpng-1.6.10.tar.xz (LZMA-compressed, recommended) - libpng-1.6.10.tar.gz - -Source files with CRLF line endings (for Windows), without the -"configure" script - - lpng1610.7z (LZMA-compressed, recommended) - lpng1610.zip - -Other information: - - libpng-1.6.10-README.txt - libpng-1.6.10-LICENSE.txt - libpng-1.6.10-*.asc (armored detached GPG signatures) - -Changes since the last public release (1.6.9): - Backported changes from libpng-1.7.0beta30 and beta31: - Fixed a large number of instances where PNGCBAPI was omitted from - function definitions. - Added pngimage test program for png_read_png() and png_write_png() - with two new test scripts. - Removed dependence on !PNG_READ_EXPAND_SUPPORTED for calling - png_set_packing() in png_read_png(). - Fixed combination of ~alpha with shift. On read invert alpha, processing - occurred after shift processing, which causes the final values to be - outside the range that should be produced by the shift. Reversing the - order on read makes the two transforms work together correctly and mirrors - the order used on write. - Do not read invalid sBIT chunks. Previously libpng only checked sBIT - values on write, so a malicious PNG writer could therefore cause - the read code to return an invalid sBIT chunk, which might lead to - application errors or crashes. Such chunks are now skipped (with - chunk_benign_error). - Make png_read_png() and png_write_png() prototypes in png.h depend - upon PNG_READ_SUPPORTED and PNG_WRITE_SUPPORTED. - Support builds with unsupported PNG_TRANSFORM_* values. All of the - PNG_TRANSFORM_* values are always defined in png.h and, because they - are used for both read and write in some cases, it is not reliable - to #if out ones that are totally unsupported. This change adds error - detection in png_read_image() and png_write_image() to do a - png_app_error() if the app requests something that cannot be done - and it adds corresponding code to pngimage.c to handle such options - by not attempting to test them. - Moved redefines of png_error(), png_warning(), png_chunk_error(), - and png_chunk_warning() from pngpriv.h to png.h to make them visible - to libpng-calling applications. - Moved OS dependent code from arm/arm_init.c, to allow the included - implementation of the ARM NEON discovery function to be set at - build-time and provide sample implementations from the current code in the - contrib/arm-neon subdirectory. The __linux__ code has also been changed to - compile and link on Android by using /proc/cpuinfo, and the old linux code - is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux - dependencies apart from opening /proc/cpuinfo and is C90 compliant. - Check for info_ptr == NULL early in png_read_end() so we don't need to - run all the png_handle_*() and depend on them to return if info_ptr == NULL. - This improves the performance of png_read_end(png_ptr, NULL) and makes - it more robust against future programming errors. - Check for __has_extension before using it in pngconf.h, to - support older Clang versions (Jeremy Sequoia). - Treat CRC error handling with png_set_crc_action(), instead of with - png_set_benign_errors(), which has been the case since libpng-1.6.0beta18. - Use a user warning handler in contrib/gregbook/readpng2.c instead of default, - so warnings will be put on stderr even if libpng has CONSOLE_IO disabled. - Added png_ptr->process_mode = PNG_READ_IDAT_MODE in png_push_read_chunk - after recognizing the IDAT chunk, which avoids an infinite loop while - reading a datastream whose first IDAT chunk is of zero-length. - This fixes CERT VU#684412 and CVE-2014-0333. - Don't recognize known sRGB profiles as sRGB if they have been hacked, - but don't reject them and don't issue a copyright violation warning. - Moved some documentation from png.h to libpng.3 and libpng-manual.txt - Minor editing of contrib/arm-neon/README and contrib/examples/*.c - Fixed typos in the manual and in scripts/pnglibconf.dfa (CFLAGS -> CPPFLAGS - and PNG_USR_CONFIG -> PNG_USER_CONFIG). - Un-deprecated png_data_freer(). - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) -or to glennrp at users.sourceforge.net - -Glenn R-P -#endif + +Libpng 1.6.10 - March 6, 2014 + +This is a public release of libpng, intended for use in production codes. + +Files available for download: + +Source files with LF line endings (for Unix/Linux) and with a +"configure" script + + libpng-1.6.10.tar.xz (LZMA-compressed, recommended) + libpng-1.6.10.tar.gz + +Source files with CRLF line endings (for Windows), without the +"configure" script + + lpng1610.7z (LZMA-compressed, recommended) + lpng1610.zip + +Other information: + + libpng-1.6.10-README.txt + libpng-1.6.10-LICENSE.txt + libpng-1.6.10-*.asc (armored detached GPG signatures) + +Changes since the last public release (1.6.9): + Backported changes from libpng-1.7.0beta30 and beta31: + Fixed a large number of instances where PNGCBAPI was omitted from + function definitions. + Added pngimage test program for png_read_png() and png_write_png() + with two new test scripts. + Removed dependence on !PNG_READ_EXPAND_SUPPORTED for calling + png_set_packing() in png_read_png(). + Fixed combination of ~alpha with shift. On read invert alpha, processing + occurred after shift processing, which causes the final values to be + outside the range that should be produced by the shift. Reversing the + order on read makes the two transforms work together correctly and mirrors + the order used on write. + Do not read invalid sBIT chunks. Previously libpng only checked sBIT + values on write, so a malicious PNG writer could therefore cause + the read code to return an invalid sBIT chunk, which might lead to + application errors or crashes. Such chunks are now skipped (with + chunk_benign_error). + Make png_read_png() and png_write_png() prototypes in png.h depend + upon PNG_READ_SUPPORTED and PNG_WRITE_SUPPORTED. + Support builds with unsupported PNG_TRANSFORM_* values. All of the + PNG_TRANSFORM_* values are always defined in png.h and, because they + are used for both read and write in some cases, it is not reliable + to #if out ones that are totally unsupported. This change adds error + detection in png_read_image() and png_write_image() to do a + png_app_error() if the app requests something that cannot be done + and it adds corresponding code to pngimage.c to handle such options + by not attempting to test them. + Moved redefines of png_error(), png_warning(), png_chunk_error(), + and png_chunk_warning() from pngpriv.h to png.h to make them visible + to libpng-calling applications. + Moved OS dependent code from arm/arm_init.c, to allow the included + implementation of the ARM NEON discovery function to be set at + build-time and provide sample implementations from the current code in the + contrib/arm-neon subdirectory. The __linux__ code has also been changed to + compile and link on Android by using /proc/cpuinfo, and the old linux code + is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux + dependencies apart from opening /proc/cpuinfo and is C90 compliant. + Check for info_ptr == NULL early in png_read_end() so we don't need to + run all the png_handle_*() and depend on them to return if info_ptr == NULL. + This improves the performance of png_read_end(png_ptr, NULL) and makes + it more robust against future programming errors. + Check for __has_extension before using it in pngconf.h, to + support older Clang versions (Jeremy Sequoia). + Treat CRC error handling with png_set_crc_action(), instead of with + png_set_benign_errors(), which has been the case since libpng-1.6.0beta18. + Use a user warning handler in contrib/gregbook/readpng2.c instead of default, + so warnings will be put on stderr even if libpng has CONSOLE_IO disabled. + Added png_ptr->process_mode = PNG_READ_IDAT_MODE in png_push_read_chunk + after recognizing the IDAT chunk, which avoids an infinite loop while + reading a datastream whose first IDAT chunk is of zero-length. + This fixes CERT VU#684412 and CVE-2014-0333. + Don't recognize known sRGB profiles as sRGB if they have been hacked, + but don't reject them and don't issue a copyright violation warning. + Moved some documentation from png.h to libpng.3 and libpng-manual.txt + Minor editing of contrib/arm-neon/README and contrib/examples/*.c + Fixed typos in the manual and in scripts/pnglibconf.dfa (CFLAGS -> CPPFLAGS + and PNG_USR_CONFIG -> PNG_USER_CONFIG). + Un-deprecated png_data_freer(). + +Send comments/corrections/commendations to png-mng-implement at lists.sf.net +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) +or to glennrp at users.sourceforge.net + +Glenn R-P +#endif diff --git a/main/source/includes/lpng1610/CHANGES b/main/source/includes/lpng1610/CHANGES index 8d9a4f35..b3e09f85 100644 --- a/main/source/includes/lpng1610/CHANGES +++ b/main/source/includes/lpng1610/CHANGES @@ -1,4884 +1,4884 @@ -#if 0 -CHANGES - changes for libpng - -Version 0.2 - added reader into png.h - fixed small problems in stub file - -Version 0.3 - added pull reader - split up pngwrite.c to several files - added pnglib.txt - added example.c - cleaned up writer, adding a few new transformations - fixed some bugs in writer - interfaced with zlib 0.5 - added K&R support - added check for 64 KB blocks for 16-bit machines - -Version 0.4 - cleaned up code and commented code - simplified time handling into png_time - created png_color_16 and png_color_8 to handle color needs - cleaned up color type defines - fixed various bugs - made various names more consistent - interfaced with zlib 0.71 - cleaned up zTXt reader and writer (using zlib's Reset functions) - split transformations into pngrtran.c and pngwtran.c - -Version 0.5 - interfaced with zlib 0.8 - fixed many reading and writing bugs - saved using 3 spaces instead of tabs - -Version 0.6 - added png_large_malloc() and png_large_free() - added png_size_t - cleaned up some compiler warnings - added png_start_read_image() - -Version 0.7 - cleaned up lots of bugs - finished dithering and other stuff - added test program - changed name from pnglib to libpng - -Version 0.71 [June, 1995] - changed pngtest.png for zlib 0.93 - fixed error in libpng.txt and example.c - -Version 0.8 - cleaned up some bugs - added png_set_filler() - split up pngstub.c into pngmem.c, pngio.c, and pngerror.c - added #define's to remove unwanted code - moved png_info_init() to png.c - added old_size into png_realloc() - added functions to manually set filtering and compression info - changed compression parameters based on image type - optimized filter selection code - added version info - changed external functions passing floats to doubles (k&r problems?) - put all the configurable stuff in pngconf.h - enabled png_set_shift to work with paletted images on read - added png_read_update_info() - updates info structure with transformations - -Version 0.81 [August, 1995] - incorporated Tim Wegner's medium model code (thanks, Tim) - -Version 0.82 [September, 1995] - [unspecified changes] - -Version 0.85 [December, 1995] - added more medium model code (almost everything's a far) - added i/o, error, and memory callback functions - fixed some bugs (16-bit, 4-bit interlaced, etc.) - added first run progressive reader (barely tested) - -Version 0.86 [January, 1996] - fixed bugs - improved documentation - -Version 0.87 [January, 1996] - fixed medium model bugs - fixed other bugs introduced in 0.85 and 0.86 - added some minor documentation - -Version 0.88 [January, 1996] - fixed progressive bugs - replaced tabs with spaces - cleaned up documentation - added callbacks for read/write and warning/error functions - -Version 0.89 [July, 1996] - Added new initialization API to make libpng work better with shared libs - we now have png_create_read_struct(), png_create_write_struct(), - png_create_info_struct(), png_destroy_read_struct(), and - png_destroy_write_struct() instead of the separate calls to - malloc and png_read_init(), png_info_init(), and png_write_init() - Changed warning/error callback functions to fix bug - this means you - should use the new initialization API if you were using the old - png_set_message_fn() calls, and that the old API no longer exists - so that people are aware that they need to change their code - Changed filter selection API to allow selection of multiple filters - since it didn't work in previous versions of libpng anyways - Optimized filter selection code - Fixed png_set_background() to allow using an arbitrary RGB color for - paletted images - Fixed gamma and background correction for paletted images, so - png_correct_palette is not needed unless you are correcting an - external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED - in pngconf.h) - if nobody uses this, it may disappear in the future. - Fixed bug with Borland 64K memory allocation (Alexander Lehmann) - Fixed bug in interlace handling (Smarasderagd, I think) - Added more error checking for writing and image to reduce invalid files - Separated read and write functions so that they won't both be linked - into a binary when only reading or writing functionality is used - New pngtest image also has interlacing and zTXt - Updated documentation to reflect new API - -Version 0.90 [January, 1997] - Made CRC errors/warnings on critical and ancillary chunks configurable - libpng will use the zlib CRC routines by (compile-time) default - Changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) - Added external C++ wrapper statements to png.h (Gilles Dauphin) - Allow PNG file to be read when some or all of file signature has already - been read from the beginning of the stream. ****This affects the size - of info_struct and invalidates all programs that use a shared libpng**** - Fixed png_filler() declarations - Fixed? background color conversions - Fixed order of error function pointers to match documentation - Current chunk name is now available in png_struct to reduce the number - of nearly identical error messages (will simplify multi-lingual - support when available) - Try to get ready for unknown-chunk callback functions: - - previously read critical chunks are flagged, so the chunk handling - routines can determine if the chunk is in the right place - - all chunk handling routines have the same prototypes, so we will - be able to handle all chunks via a callback mechanism - Try to fix Linux "setjmp" buffer size problems - Removed png_large_malloc, png_large_free, and png_realloc functions. - -Version 0.95 [March, 1997] - Fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never - Fixed bug in PNG file signature compares when start != 0 - Changed parameter type of png_set_filler(...filler...) from png_byte - to png_uint_32 - Added test for MACOS to ensure that both math.h and fp.h are not #included - Added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) - Added "packswap" transformation, which changes the endianness of - packed-pixel bytes (Kevin Bracey) - Added "strip_alpha" transformation, which removes the alpha channel of - input images without using it (not necessarily a good idea) - Added "swap_alpha" transformation, which puts the alpha channel in front - of the color bytes instead of after - Removed all implicit variable tests which assume NULL == 0 (I think) - Changed several variables to "png_size_t" to show 16/32-bit limitations - Added new pCAL chunk read/write support - Added experimental filter selection weighting (Greg Roelofs) - Removed old png_set_rgbx() and png_set_xrgb() functions that have been - obsolete for about 2 years now (use png_set_filler() instead) - Added macros to read 16- and 32-bit ints directly from buffer, to be - used only on those systems that support it (namely PowerPC and 680x0) - With some testing, this may become the default for MACOS/PPC systems. - Only calculate CRC on data if we are going to use it - Added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? - Added macros for simple libpng debugging output selectable at compile time - Removed PNG_READ_END_MODE in progressive reader (Smarasderagd) - More description of info_struct in libpng.txt and png.h - More instructions in example.c - More chunk types tested in pngtest.c - Renamed pngrcb.c to pngset.c, and all png_read_ functions to be - png_set_. We now have corresponding png_get_ - functions in pngget.c to get information in info_ptr. This isolates - the application from the internal organization of png_info_struct - (good for shared library implementations). - -Version 0.96 [May, 1997] - Fixed serious bug with < 8bpp images introduced in 0.95 - Fixed 256-color transparency bug (Greg Roelofs) - Fixed up documentation (Greg Roelofs, Laszlo Nyul) - Fixed "error" in pngconf.h for Linux setjmp() behavior - Fixed DOS medium model support (Tim Wegner) - Fixed png_check_keyword() for case with error in static string text - Added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) - Added typecasts to quiet compiler errors - Added more debugging info - -Version 0.97 [January, 1998] - Removed PNG_USE_OWN_CRC capability - Relocated png_set_crc_action from pngrutil.c to pngrtran.c - Fixed typecasts of "new_key", etc. (Andreas Dilger) - Added RFC 1152 [sic] date support - Fixed bug in gamma handling of 4-bit grayscale - Added 2-bit grayscale gamma handling (Glenn R-P) - Added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) - Minor corrections in libpng.txt - Added simple sRGB support (Glenn R-P) - Easier conditional compiling, e.g., - define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; - all configurable options can be selected from command-line instead - of having to edit pngconf.h (Glenn R-P) - Fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) - Added more conditions for png_do_background, to avoid changing - black pixels to background when a background is supplied and - no pixels are transparent - Repaired PNG_NO_STDIO behavior - Tested NODIV support and made it default behavior (Greg Roelofs) - Added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) - Regularized version numbering scheme and bumped shared-library major - version number to 2 to avoid problems with libpng 0.89 apps - (Greg Roelofs) - -Version 0.98 [January, 1998] - Cleaned up some typos in libpng.txt and in code documentation - Fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) - Cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c - Changed recommendation about file_gamma for PC images to .51 from .45, - in example.c and libpng.txt, added comments to distinguish between - screen_gamma, viewing_gamma, and display_gamma. - Changed all references to RFC1152 to read RFC1123 and changed the - PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED - Added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) - Changed srgb_intent from png_byte to int to avoid compiler bugs - -Version 0.99 [January 30, 1998] - Free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) - Fixed a longstanding "packswap" bug in pngtrans.c - Fixed some inconsistencies in pngconf.h that prevented compiling with - PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined - Fixed some typos and made other minor rearrangement of libpng.txt (Andreas) - Changed recommendation about file_gamma for PC images to .50 from .51 in - example.c and libpng.txt, and changed file_gamma for sRGB images to .45 - Added a number of functions to access information from the png structure - png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) - Added TARGET_MACOS similar to zlib-1.0.8 - Define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined - Added type casting to all png_malloc() function calls - -Version 0.99a [January 31, 1998] - Added type casts and parentheses to all returns that return a value.(Tim W.) - -Version 0.99b [February 4, 1998] - Added type cast png_uint_32 on malloc function calls where needed. - Changed type of num_hist from png_uint_32 to int (same as num_palette). - Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. - Renamed makefile.elf to makefile.lnx. - -Version 0.99c [February 7, 1998] - More type casting. Removed erroneous overflow test in pngmem.c. - Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. - Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. - -Version 0.99d [February 11, 1998] - Renamed "far_to_near()" "png_far_to_near()" - Revised libpng.3 - Version 99c "buffered" operations didn't work as intended. Replaced them - with png_memcpy_check() and png_memset_check(). - Added many "if (png_ptr == NULL) return" to quell compiler warnings about - unused png_ptr, mostly in pngget.c and pngset.c. - Check for overlength tRNS chunk present when indexed-color PLTE is read. - Cleaned up spelling errors in libpng.3/libpng.txt - Corrected a problem with png_get_tRNS() which returned undefined trans array - -Version 0.99e [February 28, 1998] - Corrected png_get_tRNS() again. - Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". - Touched up example.c to make more of it compileable, although the entire - file still can't be compiled (Willem van Schaik) - Fixed a bug in png_do_shift() (Bryan Tsai) - Added a space in png.h prototype for png_write_chunk_start() - Replaced pngtest.png with one created with zlib 1.1.1 - Changed pngtest to report PASS even when file size is different (Jean-loup G.) - Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) - -Version 0.99f [March 5, 1998] - Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) - Moved makefiles into a "scripts" directory, and added INSTALL instruction file - Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) - Added pointers to "note on libpng versions" in makefile.lnx and README - Added row callback feature when reading and writing nonprogressive rows - and added a test of this feature in pngtest.c - Added user transform callbacks, with test of the feature in pngtest.c - -Version 0.99g [March 6, 1998, morning] - Minor changes to pngtest.c to suppress compiler warnings. - Removed "beta" language from documentation. - -Version 0.99h [March 6, 1998, evening] - Minor changes to previous minor changes to pngtest.c - Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED - and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro - Added user transform capability - -Version 1.00 [March 7, 1998] - Changed several typedefs in pngrutil.c - Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) - Replaced "while(1)" with "for(;;)" - Added PNGARG() to prototypes in pngtest.c and removed some prototypes - Updated some of the makefiles (Tom Lane) - Changed some typedefs (s_start, etc.) in pngrutil.c - Fixed dimensions of "short_months" array in pngwrite.c - Replaced ansi2knr.c with the one from jpeg-v6 - -Version 1.0.0 [March 8, 1998] - Changed name from 1.00 to 1.0.0 (Adam Costello) - Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) - -Version 1.0.0a [March 9, 1998] - Fixed three bugs in pngrtran.c to make gamma+background handling consistent - (Greg Roelofs) - Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz - for major, minor, and bugfix releases. This is 10001. (Adam Costello, - Tom Lane) - Make months range from 1-12 in png_convert_to_rfc1123 - -Version 1.0.0b [March 13, 1998] - Quieted compiler complaints about two empty "for" loops in pngrutil.c - Minor changes to makefile.s2x - Removed #ifdef/#endif around a png_free() in pngread.c - -Version 1.0.1 [March 14, 1998] - Changed makefile.s2x to reduce security risk of using a relative pathname - Fixed some typos in the documentation (Greg). - Fixed a problem with value of "channels" returned by png_read_update_info() - -Version 1.0.1a [April 21, 1998] - Optimized Paeth calculations by replacing abs() function calls with intrinsics - plus other loop optimizations. Improves avg decoding speed by about 20%. - Commented out i386istic "align" compiler flags in makefile.lnx. - Reduced the default warning level in some makefiles, to make them consistent. - Removed references to IJG and JPEG in the ansi2knr.c copyright statement. - Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. - Added grayscale and 16-bit capability to png_do_read_filler(). - Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes - too large when writing an image with bit_depth < 8 (Bob Dellaca). - Corrected some bugs in the experimental weighted filtering heuristics. - Moved a misplaced pngrutil code block that truncates tRNS if it has more - than num_palette entries -- test was done before num_palette was defined. - Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). - Changed compiler flags in makefile.wat for better optimization - (Pawel Mrochen). - -Version 1.0.1b [May 2, 1998] - Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). - Relocated the png_composite macros from pngrtran.c to png.h (Greg). - Added makefile.sco (contributed by Mike Hopkirk). - Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. - Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. - More work on the Paeth-filtering, achieving imperceptible speedup - (A Kleinert). - More work on loop optimization which may help when compiled with C++ - compilers. - Added warnings when people try to use transforms they've defined out. - Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. - Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) - -Version 1.0.1c [May 11, 1998] - Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for - filler bytes should have been 0xff instead of 0xf. - Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. - Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED - out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h - Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, - for consistency, in pngconf.h - Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier - to remove unwanted capabilities via the compile line - Made some corrections to grammar (which, it's) in documentation (Greg). - Corrected example.c, use of row_pointers in png_write_image(). - -Version 1.0.1d [May 24, 1998] - Corrected several statements that used side effects illegally in pngrutil.c - and pngtrans.c, that were introduced in version 1.0.1b - Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) - More corrections to example.c, use of row_pointers in png_write_image() - and png_read_rows(). - Added pngdll.mak and pngdef.pas to scripts directory, contributed by - Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 - Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) - Changed several loops from count-down to count-up, for consistency. - -Version 1.0.1e [June 6, 1998] - Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and - added warnings when people try to set png_read_fn and png_write_fn in - the same structure. - Added a test such that png_do_gamma will be done when num_trans==0 - for truecolor images that have defined a background. This corrects an - error that was introduced in libpng-0.90 that can cause gamma processing - to be skipped. - Added tests in png.h to include "trans" and "trans_values" in structures - when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. - Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() - Moved png_convert_to_rfc_1123() from pngwrite.c to png.c - Added capability for user-provided malloc_fn() and free_fn() functions, - and revised pngtest.c to demonstrate their use, replacing the - PNGTEST_DEBUG_MEM feature. - Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). - -Version 1.0.2 [June 14, 1998] - Fixed two bugs in makefile.bor . - -Version 1.0.2a [December 30, 1998] - Replaced and extended code that was removed from png_set_filler() in 1.0.1a. - Fixed a bug in png_do_filler() that made it fail to write filler bytes in - the left-most pixel of each row (Kevin Bracey). - Changed "static pngcharp tIME_string" to "static char tIME_string[30]" - in pngtest.c (Duncan Simpson). - Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk - even when no tIME chunk was present in the source file. - Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. - Fixed a problem in png_read_push_finish_row(), which would not skip some - passes that it should skip, for images that are less than 3 pixels high. - Interchanged the order of calls to png_do_swap() and png_do_shift() - in pngwtran.c (John Cromer). - Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . - Changed "bad adaptive filter type" from error to warning in pngrutil.c . - Fixed a documentation error about default filtering with 8-bit indexed-color. - Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO - (L. Peter Deutsch). - Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. - Added png_get_copyright() and png_get_header_version() functions. - Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c - Added information about debugging in libpng.txt and libpng.3 . - Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and - makefile.sco. - Removed lines after Dynamic Dependencies" in makefile.aco . - Revised makefile.dec to make a shared library (Jeremie Petit). - Removed trailing blanks from all files. - -Version 1.0.2a [January 6, 1999] - Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h - Added "if" tests to silence complaints about unused png_ptr in png.h and png.c - Changed "check_if_png" function in example.c to return true (nonzero) if PNG. - Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() - which is obsolete. - -Version 1.0.3 [January 14, 1999] - Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) - Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. - -Version 1.0.3a [August 12, 1999] - Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning - if an attempt is made to read an interlaced image when it's not supported. - Added check if png_ptr->trans is defined before freeing it in pngread.c - Modified the Y2K statement to include versions back to version 0.71 - Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c - Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) - Replaced leading blanks with tab characters in makefile.hux - Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. - Changed (float)red and (float)green to (double)red, (double)green - in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. - Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). - Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). - Updated documentation to refer to the PNG-1.2 specification. - Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c - in makefile.knr, INSTALL, and README (L. Peter Deutsch) - Fixed bugs in calculation of the length of rowbytes when adding alpha - channels to 16-bit images, in pngrtran.c (Chris Nokleberg) - Added function png_set_user_transform_info() to store user_transform_ptr, - user_depth, and user_channels into the png_struct, and a function - png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) - Added function png_set_empty_plte_permitted() to make libpng useable - in MNG applications. - Corrected the typedef for png_free_ptr in png.h (Jesse Jones). - Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be - consistent with PNG-1.2, and allow variance of 500 before complaining. - Added assembler code contributed by Intel in file pngvcrd.c and modified - makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, - Gilles Vollant) - Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. - Added some aliases for png_set_expand() in pngrtran.c, namely - png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() - (Greg Roelofs, in "PNG: The Definitive Guide"). - Added makefile.beo for BEOS on X86, contributed by Sander Stok. - -Version 1.0.3b [August 26, 1999] - Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h - Changed leading blanks to tabs in all makefiles. - Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. - Made alternate versions of png_set_expand() in pngrtran.c, namely - png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha - (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. - Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h - Revised calculation of num_blocks in pngmem.c to avoid a potentially - negative shift distance, whose results are undefined in the C language. - Added a check in pngset.c to prevent writing multiple tIME chunks. - Added a check in pngwrite.c to detect invalid small window_bits sizes. - -Version 1.0.3d [September 4, 1999] - Fixed type casting of igamma in pngrutil.c - Added new png_expand functions to scripts/pngdef.pas and pngos2.def - Added a demo read_user_transform_fn that examines the row filters in pngtest.c - -Version 1.0.4 [September 24, 1999] - Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined - Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h - Made several minor corrections to pngtest.c - Renamed the makefiles with longer but more user friendly extensions. - Copied the PNG copyright and license to a separate LICENSE file. - Revised documentation, png.h, and example.c to remove reference to - "viewing_gamma" which no longer appears in the PNG specification. - Revised pngvcrd.c to use MMX code for interlacing only on the final pass. - Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a - Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX - assembler code) and makefile.vcwin32 (doesn't). - Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) - Added a copy of pngnow.png to the distribution. - -Version 1.0.4a [September 25, 1999] - Increase max_pixel_depth in pngrutil.c if a user transform needs it. - Changed several division operations to right-shifts in pngvcrd.c - -Version 1.0.4b [September 30, 1999] - Added parentheses in line 3732 of pngvcrd.c - Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 - -Version 1.0.4c [October 1, 1999] - Added a "png_check_version" function in png.c and pngtest.c that will generate - a helpful compiler error if an old png.h is found in the search path. - Changed type of png_user_transform_depth|channels from int to png_byte. - -Version 1.0.4d [October 6, 1999] - Changed 0.45 to 0.45455 in png_set_sRGB() - Removed unused PLTE entries from pngnow.png - Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. - -Version 1.0.4e [October 10, 1999] - Fixed sign error in pngvcrd.c (Greg Roelofs) - Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) - -Version 1.0.4f [October 15, 1999] - Surrounded example.c code with #if 0 .. #endif to prevent people from - inadvertently trying to compile it. - Changed png_get_header_version() from a function to a macro in png.h - Added type casting mostly in pngrtran.c and pngwtran.c - Removed some pointless "ptr = NULL" in pngmem.c - Added a "contrib" directory containing the source code from Greg's book. - -Version 1.0.5 [October 15, 1999] - Minor editing of the INSTALL and README files. - -Version 1.0.5a [October 23, 1999] - Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) - Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) - Further optimization and bugfix of pngvcrd.c - Revised pngset.c so that it does not allocate or free memory in the user's - text_ptr structure. Instead, it makes its own copy. - Created separate write_end_info_struct in pngtest.c for a more severe test. - Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. - -Version 1.0.5b [November 23, 1999] - Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and - PNG_FLAG_WROTE_tIME from flags to mode. - Added png_write_info_before_PLTE() function. - Fixed some typecasting in contrib/gregbook/*.c - Updated scripts/makevms.com and added makevms.com to contrib/gregbook - and contrib/pngminus (Martin Zinser) - -Version 1.0.5c [November 26, 1999] - Moved png_get_header_version from png.h to png.c, to accommodate ansi2knr. - Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to - accommodate making DLL's: Moved usr_png_ver from global variable to function - png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and - eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays - into pngtypes.h. Eliminated use of global png_pass arrays. Declared the - png_CHNK and png_pass arrays to be "const". Made the global arrays - available to applications (although none are used in libpng itself) when - PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. - Removed some extraneous "-I" from contrib/pngminus/makefile.std - Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. - Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 - -Version 1.0.5d [November 29, 1999] - Add type cast (png_const_charp) two places in png.c - Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. - Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available - to applications a macro "PNG_USE_LOCAL_ARRAYS". - comment out (with #ifdef) all the new declarations when - PNG_USE_GLOBAL_ARRAYS is defined. - Added PNG_EXPORT_VAR macro to accommodate making DLL's. - -Version 1.0.5e [November 30, 1999] - Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text - structure; refactored the inflate/deflate support to make adding new chunks - with trailing compressed parts easier in the future, and added new functions - png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, - png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). - NOTE: Applications that write text chunks MUST define png_text->lang - before calling png_set_text(). It must be set to NULL if you want to - write tEXt or zTXt chunks. If you want your application to be able to - run with older versions of libpng, use - - #ifdef PNG_iTXt_SUPPORTED - png_text[i].lang = NULL; - #endif - - Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned - offsets (Eric S. Raymond). - Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into - PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED - macros, leaving the separate macros also available. - Removed comments on #endifs at the end of many short, non-nested #if-blocks. - -Version 1.0.5f [December 6, 1999] - Changed makefile.solaris to issue a warning about potential problems when - the ucb "ld" is in the path ahead of the ccs "ld". - Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. - Added sCAL chunk support (Eric S. Raymond). - -Version 1.0.5g [December 7, 1999] - Fixed "png_free_spallettes" typo in png.h - Added code to handle new chunks in pngpread.c - Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block - Added "translated_key" to png_text structure and png_write_iTXt(). - Added code in pngwrite.c to work around a newly discovered zlib bug. - -Version 1.0.5h [December 10, 1999] - NOTE: regarding the note for version 1.0.5e, the following must also - be included in your code: - png_text[i].translated_key = NULL; - Unknown chunk handling is now supported. - Option to eliminate all floating point support was added. Some new - fixed-point functions such as png_set_gAMA_fixed() were added. - Expanded tabs and removed trailing blanks in source files. - -Version 1.0.5i [December 13, 1999] - Added some type casts to silence compiler warnings. - Renamed "png_free_spalette" to "png_free_spalettes" for consistency. - Removed leading blanks from a #define in pngvcrd.c - Added some parameters to the new png_set_keep_unknown_chunks() function. - Added a test for up->location != 0 in the first instance of writing - unknown chunks in pngwrite.c - Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to - prevent recursion. - Added png_free_hIST() function. - Various patches to fix bugs in the sCAL and integer cHRM processing, - and to add some convenience macros for use with sCAL. - -Version 1.0.5j [December 21, 1999] - Changed "unit" parameter of png_write_sCAL from png_byte to int, to work - around buggy compilers. - Added new type "png_fixed_point" for integers that hold float*100000 values - Restored backward compatibility of tEXt/zTXt chunk processing: - Restored the first four members of png_text to the same order as v.1.0.5d. - Added members "lang_key" and "itxt_length" to png_text struct. Set - text_length=0 when "text" contains iTXt data. Use the "compression" - member to distinguish among tEXt/zTXt/iTXt types. Added - PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. - The "Note" above, about backward incompatibility of libpng-1.0.5e, no - longer applies. - Fixed png_read|write_iTXt() to read|write parameters in the right order, - and to write the iTXt chunk after IDAT if it appears in the end_ptr. - Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) - Reversed the order of trying to write floating-point and fixed-point gAMA. - -Version 1.0.5k [December 27, 1999] - Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" - Added png_handle_as_unknown() function (Glenn) - Added png_free_chunk_list() function and chunk_list and num_chunk_list members - of png_ptr. - Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. - Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings - about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) - Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). - Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. - Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). - -Version 1.0.5l [January 1, 2000] - Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() - for setting a callback function to handle unknown chunks and for - retrieving the associated user pointer (Glenn). - -Version 1.0.5m [January 7, 2000] - Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). - -Version 1.0.5n [January 9, 2000] - Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its - own memory for info_ptr->palette. This makes it safe for the calling - application to free its copy of the palette any time after it calls - png_set_PLTE(). - -Version 1.0.5o [January 20, 2000] - Cosmetic changes only (removed some trailing blanks and TABs) - -Version 1.0.5p [January 31, 2000] - Renamed pngdll.mak to makefile.bd32 - Cosmetic changes in pngtest.c - -Version 1.0.5q [February 5, 2000] - Relocated the makefile.solaris warning about PATH problems. - Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) - Revised makefile.gcmmx - Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros - -Version 1.0.5r [February 7, 2000] - Removed superfluous prototype for png_get_itxt from png.h - Fixed a bug in pngrtran.c that improperly expanded the background color. - Return *num_text=0 from png_get_text() when appropriate, and fix documentation - of png_get_text() in libpng.txt/libpng.3. - -Version 1.0.5s [February 18, 2000] - Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the - new error handler that's planned for the next libpng release, and changed - example.c, pngtest.c, and contrib programs to use this macro. - Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) - Fixed a bug in png_read_png() that caused it to fail to expand some images - that it should have expanded. - Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions - in pngget.c - Changed the allocation of palette, history, and trans arrays back to - the version 1.0.5 method (linking instead of copying) which restores - backward compatibility with version 1.0.5. Added some remarks about - that in example.c. Added "free_me" member to info_ptr and png_ptr - and added png_free_data() function. - Updated makefile.linux and makefile.gccmmx to make directories conditionally. - Made cosmetic changes to pngasmrd.h - Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). - Modified png_read_png() to allocate info_ptr->row_pointers only if it - hasn't already been allocated. - -Version 1.0.5t [March 4, 2000] - Changed png_jmp_env() migration aiding macro to png_jmpbuf(). - Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c - Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when - PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b - Files in contrib/gregbook were revised to use png_jmpbuf() and to select - a 24-bit visual if one is available, and to allow abbreviated options. - Files in contrib/pngminus were revised to use the png_jmpbuf() macro. - Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s - -Version 1.0.5u [March 5, 2000] - Simplified the code that detects old png.h in png.c and pngtest.c - Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) - Increased precision of rgb_to_gray calculations from 8 to 15 bits and - added png_set_rgb_to_gray_fixed() function. - Added makefile.bc32 (32-bit Borland C++, C mode) - -Version 1.0.5v [March 11, 2000] - Added some parentheses to the png_jmpbuf macro definition. - Updated references to the zlib home page, which has moved to freesoftware.com. - Corrected bugs in documentation regarding png_read_row() and png_write_row(). - Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. - Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, - revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) - -Version 1.0.6 [March 20, 2000] - Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c - Added makefile.sggcc (SGI IRIX with gcc) - -Version 1.0.6d [April 7, 2000] - Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO - Added data_length parameter to png_decompress_chunk() function - Revised documentation to remove reference to abandoned png_free_chnk functions - Fixed an error in png_rgb_to_gray_fixed() - Revised example.c, usage of png_destroy_write_struct(). - Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file - Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c - Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). - -Version 1.0.6e [April 9, 2000] - Added png_data_freer() function. - In the code that checks for over-length tRNS chunks, added check of - info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) - Minor revisions of libpng.txt/libpng.3. - Check for existing data and free it if the free_me flag is set, in png_set_*() - and png_handle_*(). - Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED - is defined. - Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c - and mentioned the purposes of the two macros in libpng.txt/libpng.3. - -Version 1.0.6f [April 14, 2000] - Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. - Add checks in png_set_text() for NULL members of the input text structure. - Revised libpng.txt/libpng.3. - Removed superfluous prototype for png_set_iTXt from png.h - Removed "else" from pngread.c, after png_error(), and changed "0" to "length". - Changed several png_errors about malformed ancillary chunks to png_warnings. - -Version 1.0.6g [April 24, 2000] - Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. - Relocated paragraph about png_set_background() in libpng.3/libpng.txt - and other revisions (Matthias Benckmann) - Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and - png_ptr members to restore binary compatibility with libpng-1.0.5 - (breaks compatibility with libpng-1.0.6). - -Version 1.0.6h [April 24, 2000] - Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds - libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) - This is a temporary change for test purposes. - -Version 1.0.6i [May 2, 2000] - Rearranged some members at the end of png_info and png_struct, to put - unknown_chunks_num and free_me within the original size of the png_structs - and free_me, png_read_user_fn, and png_free_fn within the original png_info, - because some old applications allocate the structs directly instead of - using png_create_*(). - Added documentation of user memory functions in libpng.txt/libpng.3 - Modified png_read_png so that it will use user_allocated row_pointers - if present, unless free_me directs that it be freed, and added description - of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. - Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version - 1.00) members of png_struct and png_info, to regain binary compatibility - when you define this macro. Capabilities lost in this event - are user transforms (new in version 1.0.0),the user transform pointer - (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, - the high-level interface, and unknown chunks support (all new in 1.0.6). - This was necessary because of old applications that allocate the structs - directly as authors were instructed to do in libpng-0.88 and earlier, - instead of using png_create_*(). - Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which - can be used to detect codes that directly allocate the structs, and - code to check these modes in png_read_init() and png_write_init() and - generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED - was not defined. - Added makefile.intel and updated makefile.watcom (Pawel Mrochen) - -Version 1.0.6j [May 3, 2000] - Overloaded png_read_init() and png_write_init() with macros that convert - calls to png_read_init_2() or png_write_init_2() that check the version - and structure sizes. - -Version 1.0.7beta11 [May 7, 2000] - Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes - which are no longer used. - Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is - defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED - is defined. - Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory - overrun when old applications fill the info_ptr->text structure directly. - Added PNGAPI macro, and added it to the definitions of all exported functions. - Relocated version macro definitions ahead of the includes of zlib.h and - pngconf.h in png.h. - -Version 1.0.7beta12 [May 12, 2000] - Revised pngset.c to avoid a problem with expanding the png_debug macro. - Deleted some extraneous defines from pngconf.h - Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. - Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. - Added png_access_version_number() function. - Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). - Expanded libpng.3/libpng.txt information about png_data_freer(). - -Version 1.0.7beta14 [May 17, 2000] (beta13 was not published) - Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as - warnings instead of errors, as pngrutil.c does. - Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() - will actually write IDATs. - Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. - Make png_free_data() ignore its final parameter except when freeing data - that can have multiple instances (text, sPLT, unknowns). - Fixed a new bug in png_set_rows(). - Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. - Added png_set_invalid() function. - Fixed incorrect illustrations of png_destroy_write_struct() in example.c. - -Version 1.0.7beta15 [May 30, 2000] - Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce - fewer error messages. - Rearranged checks for Z_OK to check the most likely path first in pngpread.c - and pngwutil.c. - Added checks in pngtest.c for png_create_*() returning NULL, and mentioned - in libpng.txt/libpng.3 the need for applications to check this. - Changed names of png_default_*() functions in pngtest to pngtest_*(). - Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. - Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c - Set each pointer to NULL after freeing it in png_free_data(). - Worked around a problem in pngconf.h; AIX's strings.h defines an "index" - macro that conflicts with libpng's png_color_16.index. (Dimitri - Papadapoulos) - Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). - -Version 1.0.7beta16 [June 4, 2000] - Revised the workaround of AIX string.h "index" bug. - Added a check for overlength PLTE chunk in pngrutil.c. - Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer - indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. - Added a warning in png_decompress_chunk() when it runs out of data, e.g. - when it tries to read an erroneous PhotoShop iCCP chunk. - Added PNG_USE_DLL macro. - Revised the copyright/disclaimer/license notice. - Added contrib/msvctest directory - -Version 1.0.7rc1 [June 9, 2000] - Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) - Added contrib/visupng directory (Willem van Schaik) - -Version 1.0.7beta18 [June 23, 2000] - Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ - and do not redefine PNGAPI if it is passed in via a compiler directive. - Revised visupng/PngFile.c to remove returns from within the Try block. - Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. - Updated contrib/visupng/cexcept.h to version 1.0.0. - Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. - -Version 1.0.7rc2 [June 28, 2000] - Updated license to include disclaimers required by UCITA. - Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. - -Version 1.0.7 [July 1, 2000] - Revised the definition of "trans_values" in libpng.3/libpng.txt - -Version 1.0.8beta1 [July 8, 2000] - Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. - Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and - pngwutil.c. - Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. - Removed unused "#include " from png.c - Added WindowsCE support. - Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. - -Version 1.0.8beta2 [July 10, 2000] - Added project files to the wince directory and made further revisions - of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. - -Version 1.0.8beta3 [July 11, 2000] - Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() - for indexed-color input files to avoid potential double-freeing trans array - under some unusual conditions; problem was introduced in version 1.0.6f. - Further revisions to pngtest.c and files in the wince subdirectory. - -Version 1.0.8beta4 [July 14, 2000] - Added the files pngbar.png and pngbar.jpg to the distribution. - Added makefile.cygwin, and cygwin support in pngconf.h - Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) - -Version 1.0.8rc1 [July 16, 2000] - Revised png_debug() macros and statements to eliminate compiler warnings. - -Version 1.0.8 [July 24, 2000] - Added png_flush() in pngwrite.c, after png_write_IEND(). - Updated makefile.hpux to build a shared library. - -Version 1.0.9beta1 [November 10, 2000] - Fixed typo in scripts/makefile.hpux - Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) - Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) - Changed "cdrom.com" in documentation to "libpng.org" - Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). - Changed type of "params" from voidp to png_voidp in png_read|write_png(). - Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. - Revised the 3 instances of WRITEFILE in pngtest.c. - Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. - Updated png.rc in dll/msvc project - Revised makefile.dec to define and use LIBPATH and INCPATH - Increased size of global png_libpng_ver[] array from 12 to 18 chars. - Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. - Removed duplicate png_crc_finish() from png_handle_bKGD() function. - Added a warning when application calls png_read_update_info() multiple times. - Revised makefile.cygwin - Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. - Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). - -Version 1.0.9beta2 [November 19, 2000] - Renamed the "dll" subdirectory "projects". - Added borland project files to "projects" subdirectory. - Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. - Add error message in png_set_compression_buffer_size() when malloc fails. - -Version 1.0.9beta3 [November 23, 2000] - Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. - Removed the png_flush() in pngwrite.c that crashes some applications - that don't set png_output_flush_fn. - Added makefile.macosx and makefile.aix to scripts directory. - -Version 1.0.9beta4 [December 1, 2000] - Change png_chunk_warning to png_warning in png_check_keyword(). - Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). - -Version 1.0.9beta5 [December 15, 2000] - Added support for filter method 64 (for PNG datastreams embedded in MNG). - -Version 1.0.9beta6 [December 18, 2000] - Revised png_set_filter() to accept filter method 64 when appropriate. - Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to - help prevent applications from using MNG features in PNG datastreams. - Added png_permit_mng_features() function. - Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". - -Version 1.0.9rc1 [December 23, 2000] - Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c - Fixed error handling of unknown compression type in png_decompress_chunk(). - In pngconf.h, define __cdecl when _MSC_VER is defined. - -Version 1.0.9beta7 [December 28, 2000] - Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. - Revised memory management in png_set_hIST and png_handle_hIST in a backward - compatible manner. PLTE and tRNS were revised similarly. - Revised the iCCP chunk reader to ignore trailing garbage. - -Version 1.0.9beta8 [January 12, 2001] - Moved pngasmrd.h into pngconf.h. - Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. - -Version 1.0.9beta9 [January 15, 2001] - Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to - wince and msvc project module definition files. - Minor revision of makefile.cygwin. - Fixed bug with progressive reading of narrow interlaced images in pngpread.c - -Version 1.0.9beta10 [January 16, 2001] - Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. - Fixed "png_mmx_supported" typo in project definition files. - -Version 1.0.9beta11 [January 19, 2001] - Updated makefile.sgi to make shared library. - Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED - by default, for the benefit of DLL forward compatibility. These will - be re-enabled in version 1.2.0. - -Version 1.0.9rc2 [January 22, 2001] - Revised cygwin support. - -Version 1.0.9 [January 31, 2001] - Added check of cygwin's ALL_STATIC in pngconf.h - Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. - -Version 1.0.10beta1 [March 14, 2001] - Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. - Reformatted libpng.3 to eliminate bad line breaks. - Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c - Added prototype for png_mmx_support() near the top of pnggccrd.c - Moved some error checking from png_handle_IHDR to png_set_IHDR. - Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. - Revised png_mmx_support() function in pnggccrd.c - Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c - Fixed memory leak in contrib/visupng/PngFile.c - Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) - Added warnings when retrieving or setting gamma=0. - Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). - -Version 1.0.10rc1 [March 23, 2001] - Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, - and png_strlen. - Revised png_mmx_supported() function in pnggccrd.c to return proper value. - Fixed bug in progressive reading (pngpread.c) with small images (height < 8). - -Version 1.0.10 [March 30, 2001] - Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin - Added beos project files (Chris Herborth) - -Version 1.0.11beta1 [April 3, 2001] - Added type casts on several png_malloc() calls (Dimitri Papadapoulos). - Removed a no-longer needed AIX work-around from pngconf.h - Changed several "//" single-line comments to C-style in pnggccrd.c - -Version 1.0.11beta2 [April 11, 2001] - Removed PNGAPI from several functions whose prototypes did not have PNGAPI. - Updated scripts/pngos2.def - -Version 1.0.11beta3 [April 14, 2001] - Added checking the results of many instances of png_malloc() for NULL - -Version 1.0.11beta4 [April 20, 2001] - Undid the changes from version 1.0.11beta3. Added a check for NULL return - from user's malloc_fn(). - Removed some useless type casts of the NULL pointer. - Added makefile.netbsd - -Version 1.0.11 [April 27, 2001] - Revised makefile.netbsd - -Version 1.0.12beta1 [May 14, 2001] - Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) - Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h - Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. - Eliminated the png_error about apps using png_read|write_init(). Instead, - libpng will reallocate the png_struct and info_struct if they are too small. - This retains future binary compatibility for old applications written for - libpng-0.88 and earlier. - -Version 1.2.0beta1 [May 6, 2001] - Bumped DLLNUM to 2. - Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED - by default. - Added runtime selection of MMX features. - Added png_set_strip_error_numbers function and related macros. - -Version 1.2.0beta2 [May 7, 2001] - Finished merging 1.2.0beta1 with version 1.0.11 - Added a check for attempts to read or write PLTE in grayscale PNG datastreams. - -Version 1.2.0beta3 [May 17, 2001] - Enabled user memory function by default. - Modified png_create_struct so it passes user mem_ptr to user memory allocator. - Increased png_mng_features flag from png_byte to png_uint_32. - Bumped shared-library (so-number) and dll-number to 3. - -Version 1.2.0beta4 [June 23, 2001] - Check for missing profile length field in iCCP chunk and free chunk_data - in case of truncated iCCP chunk. - Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc - Bumped dll-number from 2 to 3 in makefile.cygwin - Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly - if user attempts to run it on an 8-bit display. - Updated contrib/gregbook - Use png_malloc instead of png_zalloc to allocate palette in pngset.c - Updated makefile.ibmc - Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes - of png_write_oFFS width and height from png_uint_32 to png_int_32. - Updated example.c - Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c - -Version 1.2.0beta5 [August 8, 2001] - Revised contrib/gregbook - Revised makefile.gcmmx - Revised pnggccrd.c to conditionally compile some thread-unsafe code only - when PNG_THREAD_UNSAFE_OK is defined. - Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with - value exceeding 2^bit_depth-1 - Revised makefile.sgi and makefile.sggcc - Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c - Removed restriction that do_invert_mono only operate on 1-bit opaque files - -Version 1.2.0 [September 1, 2001] - Changed a png_warning() to png_debug() in pnggccrd.c - Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). - -Version 1.2.1beta1 [October 19, 2001] - Revised makefile.std in contrib/pngminus - Include background_1 in png_struct regardless of gamma support. - Revised makefile.netbsd and makefile.macosx, added makefile.darwin. - Revised example.c to provide more details about using row_callback(). - -Version 1.2.1beta2 [October 25, 2001] - Added type cast to each NULL appearing in a function call, except for - WINCE functions. - Added makefile.so9. - -Version 1.2.1beta3 [October 27, 2001] - Removed type casts from all NULLs. - Simplified png_create_struct_2(). - -Version 1.2.1beta4 [November 7, 2001] - Revised png_create_info_struct() and png_creat_struct_2(). - Added error message if png_write_info() was omitted. - Type cast NULLs appearing in function calls when _NO_PROTO or - PNG_TYPECAST_NULL is defined. - -Version 1.2.1rc1 [November 24, 2001] - Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL - is defined. - Changed typecast of "size" argument to png_size_t in pngmem.c calls to - the user malloc_fn, to agree with the prototype in png.h - Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) - Updated makefile.sgi to recognize LIBPATH and INCPATH. - Updated various makefiles so "make clean" does not remove previous major - version of the shared library. - -Version 1.2.1rc2 [December 4, 2001] - Always allocate 256-entry internal palette, hist, and trans arrays, to - avoid out-of-bounds memory reference caused by invalid PNG datastreams. - Added a check for prefix_length > data_length in iCCP chunk handler. - -Version 1.2.1 [December 7, 2001] - None. - -Version 1.2.2beta1 [February 22, 2002] - Fixed a bug with reading the length of iCCP profiles (Larry Reeves). - Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate - libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h - Revised makefile.darwin to remove "-undefined suppress" option. - Added checks for gamma and chromaticity values over 21474.83, which exceed - the limit for PNG unsigned 32-bit integers when encoded. - Revised calls to png_create_read_struct() and png_create_write_struct() - for simpler debugging. - Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) - -Version 1.2.2beta2 [February 23, 2002] - Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. - Check for invalid image dimensions in png_get_IHDR. - Added missing "fi;" in the install target of the SGI makefiles. - Added install-static to all makefiles that make shared libraries. - Always do gamma compensation when image is partially transparent. - -Version 1.2.2beta3 [March 7, 2002] - Compute background.gray and background_1.gray even when color_type is RGB - in case image gets reduced to gray later. - Modified shared-library makefiles to install pkgconfig/libpngNN.pc. - Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown - Removed unused png_write_destroy_info prototype from png.h - Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case - Added install-shared target to all makefiles that make shared libraries. - Stopped a double free of palette, hist, and trans when not using free_me. - Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. - -Version 1.2.2beta4 [March 8, 2002] - Compute background.gray and background_1.gray even when color_type is RGB - in case image gets reduced to gray later (Jason Summers). - Relocated a misplaced /bin/rm in the "install-shared" makefile targets - Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. - -Version 1.2.2beta5 [March 26, 2002] - Added missing PNGAPI to several function definitions. - Check for invalid bit_depth or color_type in png_get_IHDR(), and - check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). - Revised iTXt support to accept NULL for lang and lang_key. - Compute gamma for color components of background even when color_type is gray. - Changed "()" to "{}" in scripts/libpng.pc.in. - Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN - Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so - -Version 1.2.2beta6 [March 31, 2002] - -Version 1.0.13beta1 [March 31, 2002] - Prevent png_zalloc() from trying to memset memory that it failed to acquire. - Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). - Ensure that the right function (user or default) is used to free the - png_struct after an error in png_create_read_struct_2(). - -Version 1.2.2rc1 [April 7, 2002] - -Version 1.0.13rc1 [April 7, 2002] - Save the ebx register in pnggccrd.c (Sami Farin) - Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). - Updated makefiles to put headers in include/libpng and remove old include/*.h. - -Version 1.2.2 [April 15, 2002] - -Version 1.0.13 [April 15, 2002] - Revised description of png_set_filter() in libpng.3/libpng.txt. - Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd - -Version 1.0.13patch01 [April 17, 2002] - -Version 1.2.2patch01 [April 17, 2002] - Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and - makefile.sggcc - Fixed VER -> PNGVER typo in makefile.macosx and added install-static to - install - Added install: target to makefile.32sunu and makefile.64sunu - -Version 1.0.13patch03 [April 18, 2002] - -Version 1.2.2patch03 [April 18, 2002] - Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng - subdirectory to libpngNN subdirectory without the full pathname. - Moved generation of libpng.pc from "install" to "all" in 15 makefiles. - -Version 1.2.3rc1 [April 28, 2002] - Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). - Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) - Fixed bug with $prefix, should be $(prefix) in makefile.hpux. - Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin - Added a link from libpngNN.pc to libpng.pc in 15 makefiles. - Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. - Revised makefile.darwin to make relative links without full pathname. - Added setjmp() at the end of png_create_*_struct_2() in case user forgets - to put one in their application. - Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and - removed them from module definition files. - -Version 1.2.3rc2 [May 1, 2002] - Fixed bug in reporting number of channels in pngget.c and pngset.c, - that was introduced in version 1.2.2beta5. - Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), - png_default_flush(), and png_push_fill_buffer() and included them in - module definition files. - Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. - -Version 1.2.3rc3 [May 1, 2002] - Revised prototype for png_default_flush() - Remove old libpng.pc and libpngNN.pc before installing new ones. - -Version 1.2.3rc4 [May 2, 2002] - Typos in *.def files (png_default_read|write -> png_default_read|write_data) - In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc - Added libpng-config and libpngNN-config and modified makefiles to install - them. - Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles - Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp - -Version 1.2.3rc5 [May 11, 2002] - Changed "error" and "message" in prototypes to "error_message" and - "warning_message" to avoid namespace conflict. - Revised 15 makefiles to build libpng-config from libpng-config-*.in - Once more restored png_zalloc and png_zfree to regular nonexported form. - Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer - to nonexported form, but with PNGAPI, and removed them from module def - files. - -Version 1.2.3rc6 [May 14, 2002] - Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c - Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. - Removed leftover libpng-config "sed" script from four makefiles. - Revised libpng-config creating script in 16 makefiles. - -Version 1.2.3 [May 22, 2002] - Revised libpng-config target in makefile.cygwin. - Removed description of png_set_mem_fn() from documentation. - Revised makefile.freebsd. - Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). - Revised projects/msvc/README.txt - Changed -lpng to -lpngNN in LDFLAGS in several makefiles. - -Version 1.2.4beta1 [May 24, 2002] - Added libpng.pc and libpng-config to "all:" target in 16 makefiles. - Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) - Added missing "\" before closing double quote in makefile.gcmmx. - Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() - functions. - -Version 1.2.4beta2 [June 25, 2002] - Plugged memory leak of png_ptr->current_text (Matt Holgate). - Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) - Added -soname to the loader flags in makefile.dec, makefile.sgi, and - makefile.sggcc. - Added "test-installed" target to makefile.linux, makefile.gcmmx, - makefile.sgi, and makefile.sggcc. - -Version 1.2.4beta3 [June 28, 2002] - Plugged memory leak of row_buf in pngtest.c when there is a png_error(). - Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. - Added "test-installed" target to makefile.32sunu, makefile.64sunu, - makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, - makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. - -Version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] - Added "test-installed" target to makefile.cygwin and makefile.sco. - Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. - -Version 1.2.4 and 1.0.14 [July 8, 2002] - Changed png_warning() to png_error() when width is too large to process. - -Version 1.2.4patch01 [July 20, 2002] - Revised makefile.cygwin to use DLL number 12 instead of 13. - -Version 1.2.5beta1 [August 6, 2002] - Added code to contrib/gregbook/readpng2.c to ignore unused chunks. - Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) - Removed some stray *.o files from contrib/gregbook. - Changed png_error() to png_warning() about "Too much data" in pngpread.c - and about "Extra compressed data" in pngrutil.c. - Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). - Updated makefile.hpgcc - Updated png.c and pnggccrd.c handling of return from png_mmx_support() - -Version 1.2.5beta2 [August 15, 2002] - Only issue png_warning() about "Too much data" in pngpread.c when avail_in - is nonzero. - Updated makefiles to install a separate libpng.so.3 with its own rpath. - -Version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] - Revised makefiles to not remove previous minor versions of shared libraries. - -Version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] - Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared - library loader directive. - Added missing "$OBJSDLL" line to makefile.gcmmx. - Added missing "; fi" to makefile.32sunu. - -Version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] - Revised libpng-config script. - -Version 1.2.5 and 1.0.15 [October 3, 2002] - Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, - and makefile.aix. - Relocated two misplaced PNGAPI lines in pngtest.c - -Version 1.2.6beta1 [October 22, 2002] - Commented out warning about uninitialized mmx_support in pnggccrd.c. - Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. - Relocated two more misplaced PNGAPI lines in pngtest.c - Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, - introduced in version 1.0.2. - Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. - -Version 1.2.6beta2 [November 1, 2002] - Added libpng-config "--ldopts" output. - Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" - in makefiles. - -Version 1.2.6beta3 [July 18, 2004] - Reverted makefile changes from version 1.2.6beta2 and some of the changes - from version 1.2.6beta1; these will be postponed until version 1.2.7. - Version 1.2.6 is going to be a simple bugfix release. - Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. - Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. - Added "#!/bin/sh" at the top of configure, for recognition of the - 'x' flag under Cygwin (Cosmin). - Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). - Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). - Fixed the special memory handler for Borland C under DOS, in pngmem.c - (Cosmin). - Removed some spurious assignments in pngrutil.c (Cosmin). - Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings - on 16-bit platforms (Cosmin). - Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). - Used proper type png_fixed_point, to avoid problems on 16-bit platforms, - in png_handle_sRGB() (Cosmin). - Added compression_type to png_struct, and optimized the window size - inside the deflate stream (Cosmin). - Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). - Fixed handling of unknown chunks that come after IDAT (Cosmin). - Allowed png_error() and png_warning() to work even if png_ptr == NULL - (Cosmin). - Replaced row_info->rowbytes with row_bytes in png_write_find_filter() - (Cosmin). - Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). - Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded - values in png.c (Simon-Pierre, Cosmin). - Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). - Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc - (Simon-Pierre). - Moved the definition of PNG_HEADER_VERSION_STRING near the definitions - of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). - Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). - Updated scripts/makefile.vc(a)win32 (Cosmin). - Updated the MSVC project (Simon-Pierre, Cosmin). - Updated the Borland C++ Builder project (Cosmin). - Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). - Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). - Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). - Added extra guard around inclusion of Turbo C memory headers, in pngconf.h - (Cosmin). - Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to - projects/cbuilder5/ (Cosmin). - Moved projects/visualc6/png32ms.def to scripts/pngw32.def, - and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). - Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). - Changed line endings to DOS style in cbuilder5 and visualc6 files, even - in the tar.* distributions (Cosmin). - Updated contrib/visupng/VisualPng.dsp (Cosmin). - Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). - Added a separate distribution with "configure" and supporting files (Junichi). - -Version 1.2.6beta4 [July 28, 2004] - Added user ability to change png_size_t via a PNG_SIZE_T macro. - Added png_sizeof() and png_convert_size() functions. - Added PNG_SIZE_MAX (maximum value of a png_size_t variable. - Added check in png_malloc_default() for (size_t)size != (png_uint_32)size - which would indicate an overflow. - Changed sPLT failure action from png_error to png_warning and abandon chunk. - Changed sCAL and iCCP failures from png_error to png_warning and abandon. - Added png_get_uint_31(png_ptr, buf) function. - Added PNG_UINT_32_MAX macro. - Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. - Made png_zalloc() issue a png_warning and return NULL on potential - overflow. - Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x - Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. - Revised Borland portion of png_malloc() to return NULL or issue - png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. - Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove - sequential read support. - Added some "#if PNG_WRITE_SUPPORTED" blocks. - Added #ifdef to remove some redundancy in png_malloc_default(). - Use png_malloc instead of png_zalloc to allocate the pallete. - -Version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] - Fixed buffer overflow vulnerability in png_handle_tRNS() - Fixed integer arithmetic overflow vulnerability in png_read_png(). - Fixed some harmless bugs in png_handle_sBIT, etc, that would cause - duplicate chunk types to go undetected. - Fixed some timestamps in the -config version - Rearranged order of processing of color types in png_handle_tRNS(). - Added ROWBYTES macro to calculate rowbytes without integer overflow. - Updated makefile.darwin and removed makefile.macosx from scripts directory. - Imposed default one million column, one-million row limits on the image - dimensions, and added png_set_user_limits() function to override them. - Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. - Fixed wrong cast of returns from png_get_user_width|height_max(). - Changed some "keep the compiler happy" from empty statements to returns, - Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution - -Version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] - Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. - Revised pngtest's png_debug_malloc() to use png_malloc() instead of - png_malloc_default() which is not supposed to be exported. - Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in - pngpread.c. Bug was introduced in 1.2.6rc1. - Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. - Fixed old bug in RGB to Gray transformation. - Fixed problem with 64-bit compilers by casting arguments to abs() - to png_int_32. - Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). - Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) - Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. - Added code to update the row_info->colortype in png_do_read_filler() (MSB). - -Version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] - Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid - trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. - Revised documentation of png_set_keep_unknown_chunks(). - Check handle_as_unknown status in pngpread.c, as in pngread.c previously. - Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h - Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c - -Version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] - Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of - "pinfo" was out of place). - -Version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] - Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED - section of png.h where they were inadvertently placed in version rc3. - -Version 1.2.6 and 1.0.16 [August 15, 2004] - Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. - -Version 1.2.7beta1 [August 26, 2004] - Removed unused pngasmrd.h file. - Removed references to uu.net for archived files. Added references to - PNG Spec (second edition) and the PNG ISO/IEC Standard. - Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. - Fixed bug with "optimized window size" in the IDAT datastream, that - causes libpng to write PNG files with incorrect zlib header bytes. - -Version 1.2.7beta2 [August 28, 2004] - Fixed bug with sCAL chunk and big-endian machines (David Munro). - Undid new code added in 1.2.6rc2 to update the color_type in - png_set_filler(). - Added png_set_add_alpha() that updates color type. - -Version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] - Revised png_set_strip_filler() to not remove alpha if color_type has alpha. - -Version 1.2.7 and 1.0.17 [September 12, 2004] - Added makefile.hp64 - Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin - -Version 1.2.8beta1 [November 1, 2004] - Fixed bug in png_text_compress() that would fail to complete a large block. - Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during - strip alpha operation in png_do_strip_filler(). - Added PNG_1_2_X definition in pngconf.h - Use #ifdef to comment out png_info_init in png.c and png_read_init in - pngread.c (as of 1.3.0) - -Version 1.2.8beta2 [November 2, 2004] - Reduce color_type to a nonalpha type after strip alpha operation in - png_do_strip_filler(). - -Version 1.2.8beta3 [November 3, 2004] - Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM - -Version 1.2.8beta4 [November 12, 2004] - Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). - Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). - Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection - of data type in deflate (Cosmin). - Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of - PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. - -Version 1.2.8beta5 [November 20, 2004] - Use png_ptr->flags instead of png_ptr->transformations to pass - PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI - compatibility. - Revised handling of SPECIALBUILD, PRIVATEBUILD, - PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. - -Version 1.2.8rc1 [November 24, 2004] - Moved handling of BUILD macros from pngconf.h to png.h - Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently - omitted from beta5. - Revised scripts/pngw32.rc - Despammed mailing addresses by masking "@" with "at". - Inadvertently installed a supposedly faster test version of pngrutil.c - -Version 1.2.8rc2 [November 26, 2004] - Added two missing "\" in png.h - Change tests in pngread.c and pngpread.c to - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); - -Version 1.2.8rc3 [November 28, 2004] - Reverted pngrutil.c to version libpng-1.2.8beta5. - Added scripts/makefile.elf with supporting code in pngconf.h for symbol - versioning (John Bowler). - -Version 1.2.8rc4 [November 29, 2004] - Added projects/visualc7 (Simon-pierre). - -Version 1.2.8rc5 [November 29, 2004] - Fixed new typo in scripts/pngw32.rc - -Version 1.2.8 [December 3, 2004] - Removed projects/visualc7, added projects/visualc71. - -Version 1.2.9beta1 [February 21, 2006] - Initialized some structure members in pngwutil.c to avoid gcc-4.0.0 complaints - Revised man page and libpng.txt to make it clear that one should not call - png_read_end or png_write_end after png_read_png or png_write_png. - Updated references to png-mng-implement mailing list. - Fixed an incorrect typecast in pngrutil.c - Added PNG_NO_READ_SUPPORTED conditional for making a write-only library. - Added PNG_NO_WRITE_INTERLACING_SUPPORTED conditional. - Optimized alpha-inversion loops in pngwtran.c - Moved test for nonzero gamma outside of png_build_gamma_table() in pngrtran.c - Make sure num_trans is <= 256 before copying data in png_set_tRNS(). - Make sure num_palette is <= 256 before copying data in png_set_PLTE(). - Interchanged order of write_swap_alpha and write_invert_alpha transforms. - Added parentheses in the definition of PNG_LIBPNG_BUILD_TYPE (Cosmin). - Optimized zlib window flag (CINFO) in contrib/pngsuite/*.png (Cosmin). - Updated scripts/makefile.bc32 for Borland C++ 5.6 (Cosmin). - Exported png_get_uint_32, png_save_uint_32, png_get_uint_16, png_save_uint_16, - png_get_int_32, png_save_int_32, png_get_uint_31 (Cosmin). - Added type cast (png_byte) in png_write_sCAL() (Cosmin). - Fixed scripts/makefile.cygwin (Christian Biesinger, Cosmin). - Default iTXt support was inadvertently enabled. - -Version 1.2.9beta2 [February 21, 2006] - Check for png_rgb_to_gray and png_gray_to_rgb read transformations before - checking for png_read_dither in pngrtran.c - Revised checking of chromaticity limits to accommodate extended RGB - colorspace (John Denker). - Changed line endings in some of the project files to CRLF, even in the - "Unix" tar distributions (Cosmin). - Made png_get_int_32 and png_save_int_32 always available (Cosmin). - Updated scripts/pngos2.def, scripts/pngw32.def and projects/wince/png32ce.def - with the newly exported functions. - Eliminated distributions without the "configure" script. - Updated INSTALL instructions. - -Version 1.2.9beta3 [February 24, 2006] - Fixed CRCRLF line endings in contrib/visupng/VisualPng.dsp - Made libpng.pc respect EXEC_PREFIX (D. P. Kreil, J. Bowler) - Removed reference to pngasmrd.h from Makefile.am - Renamed CHANGES to ChangeLog. - Renamed LICENSE to COPYING. - Renamed ANNOUNCE to NEWS. - Created AUTHORS file. - -Version 1.2.9beta4 [March 3, 2006] - Changed definition of PKGCONFIG from $prefix/lib to $libdir in configure.ac - Reverted to filenames LICENSE and ANNOUNCE; removed AUTHORS and COPYING. - Removed newline from the end of some error and warning messages. - Removed test for sqrt() from configure.ac and configure. - Made swap tables in pngtrans.c PNG_CONST (Carlo Bramix). - Disabled default iTXt support that was inadvertently enabled in - libpng-1.2.9beta1. - Added "OS2" to list of systems that don't need underscores, in pnggccrd.c - Removed libpng version and date from *.c files. - -Version 1.2.9beta5 [March 4, 2006] - Removed trailing blanks from source files. - Put version and date of latest change in each source file, and changed - copyright year accordingly. - More cleanup of configure.ac, Makefile.am, and associated scripts. - Restored scripts/makefile.elf which was inadvertently deleted. - -Version 1.2.9beta6 [March 6, 2006] - Fixed typo (RELEASE) in configuration files. - -Version 1.2.9beta7 [March 7, 2006] - Removed libpng.vers and libpng.sym from libpng12_la_SOURCES in Makefile.am - Fixed inconsistent #ifdef's around png_sig_bytes() and png_set_sCAL_s() - in png.h. - Updated makefile.elf as suggested by debian. - Made cosmetic changes to some makefiles, adding LN_SF and other macros. - Made some makefiles accept "exec_prefix". - -Version 1.2.9beta8 [March 9, 2006] - Fixed some "#if defined (..." which should be "#if defined(..." - Bug introduced in libpng-1.2.8. - Fixed inconsistency in definition of png_default_read_data() - Restored blank that was lost from makefile.sggcc "clean" target in beta7. - Revised calculation of "current" and "major" for irix in ltmain.sh - Changed "mkdir" to "MKDIR_P" in some makefiles. - Separated PNG_EXPAND and PNG_EXPAND_tRNS. - Added png_set_expand_gray_1_2_4_to_8() and deprecated - png_set_gray_1_2_4_to_8() which also expands tRNS to alpha. - -Version 1.2.9beta9 [March 10, 2006] - Include "config.h" in pngconf.h when available. - Added some checks for NULL png_ptr or NULL info_ptr (timeless) - -Version 1.2.9beta10 [March 20, 2006] - Removed extra CR from contrib/visualpng/VisualPng.dsw (Cosmin) - Made pnggccrd.c PIC-compliant (Christian Aichinger). - Added makefile.mingw (Wolfgang Glas). - Revised pngconf.h MMX checking. - -Version 1.2.9beta11 [March 22, 2006] - Fixed out-of-order declaration in pngwrite.c that was introduced in beta9 - Simplified some makefiles by using LIBSO, LIBSOMAJ, and LIBSOVER macros. - -Version 1.2.9rc1 [March 31, 2006] - Defined PNG_USER_PRIVATEBUILD when including "pngusr.h" (Cosmin). - Removed nonsensical assertion check from pngtest.c (Cosmin). - -Version 1.2.9 [April 14, 2006] - Revised makefile.beos and added "none" selector in ltmain.sh - -Version 1.2.10beta1 [April 15, 2006] - Renamed "config.h" to "png_conf.h" and revised Makefile.am to add - -DPNG_BUILDING_LIBPNG to compile directive, and modified pngconf.h - to include png_conf.h only when PNG_BUILDING_LIBPNG is defined. - -Version 1.2.10beta2 [April 15, 2006] - Manually updated Makefile.in and configure. Changed png_conf.h.in - back to config.h. - -Version 1.2.10beta3 [April 15, 2006] - Change png_conf.h back to config.h in pngconf.h. - -Version 1.2.10beta4 [April 16, 2006] - Change PNG_BUILDING_LIBPNG to PNG_CONFIGURE_LIBPNG in config/Makefile*. - -Version 1.2.10beta5 [April 16, 2006] - Added a configure check for compiling assembler code in pnggccrd.c - -Version 1.2.10beta6 [April 17, 2006] - Revised the configure check for pnggccrd.c - Moved -DPNG_CONFIGURE_LIBPNG into @LIBPNG_DEFINES@ - Added @LIBPNG_DEFINES@ to arguments when building libpng.sym - -Version 1.2.10beta7 [April 18, 2006] - Change "exec_prefix=$prefix" to "exec_prefix=$(prefix)" in makefiles. - -Version 1.2.10rc1 [April 19, 2006] - Ensure pngconf.h doesn't define both PNG_USE_PNGGCCRD and PNG_USE_PNGVCRD - Fixed "LN_FS" typo in makefile.sco and makefile.solaris. - -Version 1.2.10rc2 [April 20, 2006] - Added a backslash between -DPNG_CONFIGURE_LIBPNG and -DPNG_NO_ASSEMBLER_CODE - in configure.ac and configure - Made the configure warning about versioned symbols less arrogant. - -Version 1.2.10rc3 [April 21, 2006] - Added a note in libpng.txt that png_set_sig_bytes(8) can be used when - writing an embedded PNG without the 8-byte signature. - Revised makefiles and configure to avoid making links to libpng.so.* - -Version 1.2.10 [April 23, 2006] - Reverted configure to "rc2" state. - -Version 1.2.11beta1 [May 31, 2006] - scripts/libpng.pc.in contained "configure" style version info and would - not work with makefiles. - The shared-library makefiles were linking to libpng.so.0 instead of - libpng.so.3 compatibility as the library. - -Version 1.2.11beta2 [June 2, 2006] - Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - Fixed bug in example.c (png_set_palette_rgb -> png_set_palette_to_rgb) - -Version 1.2.11beta3 [June 5, 2006] - Prepended "#! /bin/sh" to ltmail.sh and contrib/pngminus/*.sh (Cosmin). - Removed the accidental leftover Makefile.in~ (Cosmin). - Avoided potential buffer overflow and optimized buffer in - png_write_sCAL(), png_write_sCAL_s() (Cosmin). - Removed the include directories and libraries from CFLAGS and LDFLAGS - in scripts/makefile.gcc (Nelson A. de Oliveira, Cosmin). - -Version 1.2.11beta4 [June 6, 2006] - Allow zero-length IDAT chunks after the entire zlib datastream, but not - after another intervening chunk type. - -Version 1.0.19rc1, 1.2.11rc1 [June 13, 2006] - Deleted extraneous square brackets from [config.h] in configure.ac - -Version 1.0.19rc2, 1.2.11rc2 [June 14, 2006] - Added prototypes for PNG_INCH_CONVERSIONS functions to png.h - Revised INSTALL and autogen.sh - Fixed typo in several makefiles (-W1 should be -Wl) - Added typedef for png_int_32 and png_uint_32 on 64-bit systems. - -Version 1.0.19rc3, 1.2.11rc3 [June 15, 2006] - Removed the new typedefs for 64-bit systems (delay until version 1.4.0) - Added one zero element to png_gamma_shift[] array in pngrtran.c to avoid - reading out of bounds. - -Version 1.0.19rc4, 1.2.11rc4 [June 15, 2006] - Really removed the new typedefs for 64-bit systems. - -Version 1.0.19rc5, 1.2.11rc5 [June 22, 2006] - Removed png_sig_bytes entry from scripts/pngw32.def - -Version 1.0.19, 1.2.11 [June 26, 2006] - None. - -Version 1.0.20, 1.2.12 [June 27, 2006] - Really increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - -Version 1.2.13beta1 [October 2, 2006] - Removed AC_FUNC_MALLOC from configure.ac - Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h - Change "logical" to "bitwise" throughout documentation. - Detect and fix attempt to write wrong iCCP profile length (CVE-2006-7244) - -Version 1.0.21, 1.2.13 [November 14, 2006] - Fix potential buffer overflow in sPLT chunk handler. - Fix Makefile.am to not try to link to noexistent files. - Check all exported functions for NULL png_ptr. - -Version 1.2.14beta1 [November 17, 2006] - Relocated three misplaced tests for NULL png_ptr. - Built Makefile.in with automake-1.9.6 instead of 1.9.2. - Build configure with autoconf-2.60 instead of 2.59 - -Version 1.2.14beta2 [November 17, 2006] - Added some typecasts in png_zalloc(). - -Version 1.2.14rc1 [November 20, 2006] - Changed "strtod" to "png_strtod" in pngrutil.c - -Version 1.0.22, 1.2.14 [November 27, 2006] - Added missing "$(srcdir)" in Makefile.am and Makefile.in - -Version 1.2.15beta1 [December 3, 2006] - Generated configure with autoconf-2.61 instead of 2.60 - Revised configure.ac to update libpng.pc and libpng-config. - -Version 1.2.15beta2 [December 3, 2006] - Always export MMX asm functions, just stubs if not building pnggccrd.c - -Version 1.2.15beta3 [December 4, 2006] - Add "png_bytep" typecast to profile while calculating length in pngwutil.c - -Version 1.2.15beta4 [December 7, 2006] - Added scripts/CMakeLists.txt - Changed PNG_NO_ASSEMBLER_CODE to PNG_NO_MMX_CODE in scripts, like 1.4.0beta - -Version 1.2.15beta5 [December 7, 2006] - Changed some instances of PNG_ASSEMBLER_* to PNG_MMX_* in pnggccrd.c - Revised scripts/CMakeLists.txt - -Version 1.2.15beta6 [December 13, 2006] - Revised scripts/CMakeLists.txt and configure.ac - -Version 1.2.15rc1 [December 18, 2006] - Revised scripts/CMakeLists.txt - -Version 1.2.15rc2 [December 21, 2006] - Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. - Added scripts/makefile.nommx - -Version 1.2.15rc3 [December 25, 2006] - Fixed shared library numbering error that was introduced in 1.2.15beta6. - -Version 1.2.15rc4 [December 27, 2006] - Fixed handling of rgb_to_gray when png_ptr->color.gray isn't set. - -Version 1.2.15rc5 [December 31, 2006] - Revised handling of rgb_to_gray. - -Version 1.2.15 [January 5, 2007] - Added some (unsigned long) typecasts in pngtest.c to avoid printing errors. - -Version 1.2.16beta1 [January 6, 2007] - Fix bugs in makefile.nommx - -Version 1.2.16beta2 [January 16, 2007] - Revised scripts/CMakeLists.txt - -Version 1.2.16 [January 31, 2007] - No changes. - -Version 1.2.17beta1 [March 6, 2007] - Revised scripts/CMakeLists.txt to install both shared and static libraries. - Deleted a redundant line from pngset.c. - -Version 1.2.17beta2 [April 26, 2007] - Relocated misplaced test for png_ptr == NULL in pngpread.c - Change "==" to "&" for testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN - flags. - Changed remaining instances of PNG_ASSEMBLER_* to PNG_MMX_* - Added pngerror() when write_IHDR fails in deflateInit2(). - Added "const" to some array declarations. - Mention examples of libpng usage in the libpng*.txt and libpng.3 documents. - -Version 1.2.17rc1 [May 4, 2007] - No changes. - -Version 1.2.17rc2 [May 8, 2007] - Moved several PNG_HAVE_* macros out of PNG_INTERNAL because applications - calling set_unknown_chunk_location() need them. - Changed transformation flag from PNG_EXPAND_tRNS to PNG_EXPAND in - png_set_expand_gray_1_2_4_to_8(). - Added png_ptr->unknown_chunk to hold working unknown chunk data, so it - can be free'ed in case of error. Revised unknown chunk handling in - pngrutil.c and pngpread.c to use this structure. - -Version 1.2.17rc3 [May 8, 2007] - Revised symbol-handling in configure script. - -Version 1.2.17rc4 [May 10, 2007] - Revised unknown chunk handling to avoid storing unknown critical chunks. - -Version 1.0.25 [May 15, 2007] -Version 1.2.17 [May 15, 2007] - Added "png_ptr->num_trans=0" before error return in png_handle_tRNS, - to eliminate a vulnerability (CVE-2007-2445, CERT VU#684664) - -Version 1.0.26 [May 15, 2007] -Version 1.2.18 [May 15, 2007] - Reverted the libpng-1.2.17rc3 change to symbol-handling in configure script - -Version 1.2.19beta1 [May 18, 2007] - Changed "const static" to "static PNG_CONST" everywhere, mostly undoing - change of libpng-1.2.17beta2. Changed other "const" to "PNG_CONST" - Changed some handling of unused parameters, to avoid compiler warnings. - "if (unused == NULL) return;" becomes "unused = unused". - -Version 1.2.19beta2 [May 18, 2007] - Only use the valid bits of tRNS value in png_do_expand() (Brian Cartier) - -Version 1.2.19beta3 [May 19, 2007] - Add some "png_byte" typecasts in png_check_keyword() and write new_key - instead of key in zTXt chunk (Kevin Ryde). - -Version 1.2.19beta4 [May 21, 2007] - Add png_snprintf() function and use it in place of sprint() for improved - defense against buffer overflows. - -Version 1.2.19beta5 [May 21, 2007] - Fixed png_handle_tRNS() to only use the valid bits of tRNS value. - Changed handling of more unused parameters, to avoid compiler warnings. - Removed some PNG_CONST in pngwutil.c to avoid compiler warnings. - -Version 1.2.19beta6 [May 22, 2007] - Added some #ifdef PNG_MMX_CODE_SUPPORTED where needed in pngvcrd.c - Added a special "_MSC_VER" case that defines png_snprintf to _snprintf - -Version 1.2.19beta7 [May 22, 2007] - Squelched png_squelch_warnings() in pnggccrd.c and added - an #ifdef PNG_MMX_CODE_SUPPORTED block around the declarations that caused - the warnings that png_squelch_warnings was squelching. - -Version 1.2.19beta8 [May 22, 2007] - Removed __MMX__ from test in pngconf.h. - -Version 1.2.19beta9 [May 23, 2007] - Made png_squelch_warnings() available via PNG_SQUELCH_WARNINGS macro. - Revised png_squelch_warnings() so it might work. - Updated makefile.sgcc and makefile.solaris; added makefile.solaris-x86. - -Version 1.2.19beta10 [May 24, 2007] - Resquelched png_squelch_warnings(), use "__attribute__((used))" instead. - -Version 1.4.0beta1 [April 20, 2006] - Enabled iTXt support (changes png_struct, thus requires so-number change). - Cleaned up PNG_ASSEMBLER_CODE_SUPPORTED vs PNG_MMX_CODE_SUPPORTED - Eliminated PNG_1_0_X and PNG_1_2_X macros. - Removed deprecated functions png_read_init, png_write_init, png_info_init, - png_permit_empty_plte, png_set_gray_1_2_4_to_8, png_check_sig, and - removed the deprecated macro PNG_MAX_UINT. - Moved "PNG_INTERNAL" parts of png.h and pngconf.h into pngintrn.h - Removed many WIN32_WCE #ifdefs (Cosmin). - Reduced dependency on C-runtime library when on Windows (Simon-Pierre) - Replaced sprintf() with png_sprintf() (Simon-Pierre) - -Version 1.4.0beta2 [April 20, 2006] - Revised makefiles and configure to avoid making links to libpng.so.* - Moved some leftover MMX-related defines from pngconf.h to pngintrn.h - Updated scripts/pngos2.def, pngw32.def, and projects/wince/png32ce.def - -Version 1.4.0beta3 [May 10, 2006] - Updated scripts/pngw32.def to comment out MMX functions. - Added PNG_NO_GET_INT_32 and PNG_NO_SAVE_INT_32 macros. - Scripts/libpng.pc.in contained "configure" style version info and would - not work with makefiles. - Revised pngconf.h and added pngconf.h.in, so makefiles and configure can - pass defines to libpng and applications. - -Version 1.4.0beta4 [May 11, 2006] - Revised configure.ac, Makefile.am, and many of the makefiles to write - their defines in pngconf.h. - -Version 1.4.0beta5 [May 15, 2006] - Added a missing semicolon in Makefile.am and Makefile.in - Deleted extraneous square brackets from configure.ac - -Version 1.4.0beta6 [June 2, 2006] - Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - Changed sonum from 0 to 1. - Removed unused prototype for png_check_sig() from png.h - -Version 1.4.0beta7 [June 16, 2006] - Exported png_write_sig (Cosmin). - Optimized buffer in png_handle_cHRM() (Cosmin). - Set pHYs = 2835 x 2835 pixels per meter, and added - sCAL = 0.352778e-3 x 0.352778e-3 meters, in pngtest.png (Cosmin). - Added png_set_benign_errors(), png_benign_error(), png_chunk_benign_error(). - Added typedef for png_int_32 and png_uint_32 on 64-bit systems. - Added "(unsigned long)" typecast on png_uint_32 variables in printf lists. - -Version 1.4.0beta8 [June 22, 2006] - Added demonstration of user chunk support in pngtest.c, to support the - public sTER chunk and a private vpAg chunk. - -Version 1.4.0beta9 [July 3, 2006] - Removed ordinals from scripts/pngw32.def and removed png_info_int and - png_set_gray_1_2_4_to_8 entries. - Inline call of png_get_uint_32() in png_get_uint_31(). - Use png_get_uint_31() to get vpAg width and height in pngtest.c - Removed WINCE and Netware projects. - Removed standalone Y2KINFO file. - -Version 1.4.0beta10 [July 12, 2006] - Eliminated automatic copy of pngconf.h to pngconf.h.in from configure and - some makefiles, because it was not working reliably. Instead, distribute - pngconf.h.in along with pngconf.h and cause configure and some of the - makefiles to update pngconf.h from pngconf.h.in. - Added pngconf.h to DEPENDENCIES in Makefile.am - -Version 1.4.0beta11 [August 19, 2006] - Removed AC_FUNC_MALLOC from configure.ac. - Added a warning when writing iCCP profile with mismatched profile length. - Patched pnggccrd.c to assemble on x86_64 platforms. - Moved chunk header reading into a separate function png_read_chunk_header() - in pngrutil.c. The chunk header (len+sig) is now serialized in a single - operation (Cosmin). - Implemented support for I/O states. Added png_ptr member io_state, and - functions png_get_io_chunk_name() and png_get_io_state() in pngget.c - (Cosmin). - Added png_get_io_chunk_name and png_get_io_state to scripts/*.def (Cosmin). - Renamed scripts/pngw32.* to scripts/pngwin.* (Cosmin). - Removed the include directories and libraries from CFLAGS and LDFLAGS - in scripts/makefile.gcc (Cosmin). - Used png_save_uint_32() to set vpAg width and height in pngtest.c (Cosmin). - Cast to proper type when getting/setting vpAg units in pngtest.c (Cosmin). - Added pngintrn.h to the Visual C++ projects (Cosmin). - Removed scripts/list (Cosmin). - Updated copyright year in scripts/pngwin.def (Cosmin). - Removed PNG_TYPECAST_NULL and used standard NULL consistently (Cosmin). - Disallowed the user to redefine png_size_t, and enforced a consistent use - of png_size_t across libpng (Cosmin). - Changed the type of png_ptr->rowbytes, PNG_ROWBYTES() and friends - to png_size_t (Cosmin). - Removed png_convert_size() and replaced png_sizeof with sizeof (Cosmin). - Removed some unnecessary type casts (Cosmin). - Changed prototype of png_get_compression_buffer_size() and - png_set_compression_buffer_size() to work with png_size_t instead of - png_uint_32 (Cosmin). - Removed png_memcpy_check() and png_memset_check() (Cosmin). - Fixed a typo (png_byte --> png_bytep) in libpng.3 and libpng.txt (Cosmin). - Clarified that png_zalloc() does not clear the allocated memory, - and png_zalloc() and png_zfree() cannot be PNGAPI (Cosmin). - Renamed png_mem_size_t to png_alloc_size_t, fixed its definition in - pngconf.h, and used it in all memory allocation functions (Cosmin). - Renamed pngintrn.h to pngpriv.h, added a comment at the top of the file - mentioning that the symbols declared in that file are private, and - updated the scripts and the Visual C++ projects accordingly (Cosmin). - Removed circular references between pngconf.h and pngconf.h.in in - scripts/makefile.vc*win32 (Cosmin). - Removing trailing '.' from the warning and error messages (Cosmin). - Added pngdefs.h that is built by makefile or configure, instead of - pngconf.h.in (Glenn). - Detect and fix attempt to write wrong iCCP profile length. - -Version 1.4.0beta12 [October 19, 2006] - Changed "logical" to "bitwise" in the documentation. - Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h - Add a typecast to stifle compiler warning in pngrutil.c - -Version 1.4.0beta13 [November 10, 2006] - Fix potential buffer overflow in sPLT chunk handler. - Fix Makefile.am to not try to link to noexistent files. - -Version 1.4.0beta14 [November 15, 2006] - Check all exported functions for NULL png_ptr. - -Version 1.4.0beta15 [November 17, 2006] - Relocated two misplaced tests for NULL png_ptr. - Built Makefile.in with automake-1.9.6 instead of 1.9.2. - Build configure with autoconf-2.60 instead of 2.59 - Add "install: all" in Makefile.am so "configure; make install" will work. - -Version 1.4.0beta16 [November 17, 2006] - Added a typecast in png_zalloc(). - -Version 1.4.0beta17 [December 4, 2006] - Changed "new_key[79] = '\0';" to "(*new_key)[79] = '\0';" in pngwutil.c - Add "png_bytep" typecast to profile while calculating length in pngwutil.c - -Version 1.4.0beta18 [December 7, 2006] - Added scripts/CMakeLists.txt - -Version 1.4.0beta19 [May 16, 2007] - Revised scripts/CMakeLists.txt - Rebuilt configure and Makefile.in with newer tools. - Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. - Added scripts/makefile.nommx - -Version 1.4.0beta20 [July 9, 2008] - Moved several PNG_HAVE_* macros from pngpriv.h to png.h because applications - calling set_unknown_chunk_location() need them. - Moved several macro definitions from pngpriv.h to pngconf.h - Merge with changes to the 1.2.X branch, as of 1.2.30beta04. - Deleted all use of the MMX assembler code and Intel-licensed optimizations. - Revised makefile.mingw - -Version 1.4.0beta21 [July 21, 2008] - Moved local array "chunkdata" from pngrutil.c to the png_struct, so - it will be freed by png_read_destroy() in case of a read error (Kurt - Christensen). - -Version 1.4.0beta22 [July 21, 2008] - Change "purpose" and "buffer" to png_ptr->chunkdata to avoid memory leaking. - -Version 1.4.0beta23 [July 22, 2008] - Change "chunkdata = NULL" to "png_ptr->chunkdata = NULL" several places in - png_decompress_chunk(). - -Version 1.4.0beta24 [July 25, 2008] - Change all remaining "chunkdata" to "png_ptr->chunkdata" in - png_decompress_chunk(), and remove "chunkdata" from parameter list. - Put a call to png_check_chunk_name() in png_read_chunk_header(). - Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. - Removed two calls to png_check_chunk_name() occuring later in the process. - Define PNG_NO_ERROR_NUMBERS by default in pngconf.h - -Version 1.4.0beta25 [July 30, 2008] - Added a call to png_check_chunk_name() in pngpread.c - Reverted png_check_chunk_name() to accept a name with a lowercase 3rd byte. - Added png_push_have_buffer() function to pngpread.c - Eliminated PNG_BIG_ENDIAN_SUPPORTED and associated png_get_* macros. - Made inline expansion of png_get_*() optional with PNG_USE_READ_MACROS. - Eliminated all PNG_USELESS_TESTS and PNG_CORRECT_PALETTE_SUPPORTED code. - Synced contrib directory and configure files with libpng-1.2.30beta06. - Eliminated no-longer-used pngdefs.h (but it's still built in the makefiles) - Relocated a misplaced "#endif /* PNG_NO_WRITE_FILTER */" in pngwutil.c - -Version 1.4.0beta26 [August 4, 2008] - Removed png_push_have_buffer() function in pngpread.c. It increased the - compiled library size slightly. - Changed "-Wall" to "-W -Wall" in the CFLAGS in all makefiles (Cosmin Truta) - Declared png_ptr "volatile" in pngread.c and pngwrite.c to avoid warnings. - Updated contrib/visupng/cexcept.h to version 2.0.1 - Added PNG_LITERAL_CHARACTER macros for #, [, and ]. - -Version 1.4.0beta27 [August 5, 2008] - Revised usage of PNG_LITERAL_SHARP in pngerror.c. - Moved newline character from individual png_debug messages into the - png_debug macros. - Allow user to #define their own png_debug, png_debug1, and png_debug2. - -Version 1.4.0beta28 [August 5, 2008] - Revised usage of PNG_LITERAL_SHARP in pngerror.c. - Added PNG_STRING_NEWLINE macro - -Version 1.4.0beta29 [August 9, 2008] - Revised usage of PNG_STRING_NEWLINE to work on non-ISO compilers. - Added PNG_STRING_COPYRIGHT macro. - Added non-ISO versions of png_debug macros. - -Version 1.4.0beta30 [August 14, 2008] - Added premultiplied alpha feature (Volker Wiendl). - -Version 1.4.0beta31 [August 18, 2008] - Moved png_set_premultiply_alpha from pngtrans.c to pngrtran.c - Removed extra crc check at the end of png_handle_cHRM(). Bug introduced - in libpng-1.4.0beta20. - -Version 1.4.0beta32 [August 19, 2008] - Added PNG_WRITE_FLUSH_SUPPORTED block around new png_flush() call. - Revised PNG_NO_STDIO version of png_write_flush() - -Version 1.4.0beta33 [August 20, 2008] - Added png_get|set_chunk_cache_max() to limit the total number of sPLT, - text, and unknown chunks that can be stored. - -Version 1.4.0beta34 [September 6, 2008] - Shortened tIME_string to 29 bytes in pngtest.c - Fixed off-by-one error introduced in png_push_read_zTXt() function in - libpng-1.2.30beta04/pngpread.c (Harald van Dijk) - -Version 1.4.0beta35 [October 6, 2008] - Changed "trans_values" to "trans_color". - Changed so-number from 0 to 14. Some OS do not like 0. - Revised makefile.darwin to fix shared library numbering. - Change png_set_gray_1_2_4_to_8() to png_set_expand_gray_1_2_4_to_8() - in example.c (debian bug report) - -Version 1.4.0beta36 [October 25, 2008] - Sync with tEXt vulnerability fix in libpng-1.2.33rc02. - -Version 1.4.0beta37 [November 13, 2008] - Added png_check_cHRM in png.c and moved checking from pngget.c, pngrutil.c, - and pngwrite.c - -Version 1.4.0beta38 [November 22, 2008] - Added check for zero-area RGB cHRM triangle in png_check_cHRM() and - png_check_cHRM_fixed(). - -Version 1.4.0beta39 [November 23, 2008] - Revised png_warning() to write its message on standard output by default - when warning_fn is NULL. - -Version 1.4.0beta40 [November 24, 2008] - Eliminated png_check_cHRM(). Instead, always use png_check_cHRM_fixed(). - In png_check_cHRM_fixed(), ensure white_y is > 0, and removed redundant - check for all-zero coordinates that is detected by the triangle check. - -Version 1.4.0beta41 [November 26, 2008] - Fixed string vs pointer-to-string error in png_check_keyword(). - Rearranged test expressions in png_check_cHRM_fixed() to avoid internal - overflows. - Added PNG_NO_CHECK_cHRM conditional. - -Version 1.4.0beta42, 43 [December 1, 2008] - Merge png_debug with version 1.2.34beta04. - -Version 1.4.0beta44 [December 6, 2008] - Removed redundant check for key==NULL before calling png_check_keyword() - to ensure that new_key gets initialized and removed extra warning - (Merge with version 1.2.34beta05 -- Arvan Pritchard). - -Version 1.4.0beta45 [December 9, 2008] - In png_write_png(), respect the placement of the filler bytes in an earlier - call to png_set_filler() (Jim Barry). - -Version 1.4.0beta46 [December 10, 2008] - Undid previous change and added PNG_TRANSFORM_STRIP_FILLER_BEFORE and - PNG_TRANSFORM_STRIP_FILLER_AFTER conditionals and deprecated - PNG_TRANSFORM_STRIP_FILLER (Jim Barry). - -Version 1.4.0beta47 [December 15, 2008] - Support for dithering was disabled by default, because it has never - been well tested and doesn't work very well. The code has not - been removed, however, and can be enabled by building libpng with - PNG_READ_DITHER_SUPPORTED defined. - -Version 1.4.0beta48 [February 14, 2009] - Added new exported function png_calloc(). - Combined several instances of png_malloc(); png_memset() into png_calloc(). - Removed prototype for png_freeptr() that was added in libpng-1.4.0beta24 - but was never defined. - -Version 1.4.0beta49 [February 28, 2009] - Added png_fileno() macro to pngconf.h, used in pngwio.c - Corrected order of #ifdef's in png_debug definition in png.h - Fixed bug introduced in libpng-1.4.0beta48 with the memset arguments - for pcal_params. - Fixed order of #ifdef directives in the png_debug defines in png.h - (bug introduced in libpng-1.2.34/1.4.0beta29). - Revised comments in png_set_read_fn() and png_set_write_fn(). - -Version 1.4.0beta50 [March 18, 2009] - Use png_calloc() instead of png_malloc() to allocate big_row_buf when - reading an interlaced file, to avoid a possible UMR. - Undid revision of PNG_NO_STDIO version of png_write_flush(). Users - having trouble with fflush() can build with PNG_NO_WRITE_FLUSH defined - or supply their own flush_fn() replacement. - Revised libpng*.txt and png.h documentation about use of png_write_flush() - and png_set_write_fn(). - Removed fflush() from pngtest.c. - Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h - -Version 1.4.0beta51 [March 21, 2009] - Removed new png_fileno() macro from pngconf.h . - -Version 1.4.0beta52 [March 27, 2009] - Relocated png_do_chop() ahead of building gamma tables in pngrtran.c - This avoids building 16-bit gamma tables unnecessarily. - Removed fflush() from pngtest.c. - Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h - Added a section on differences between 1.0.x and 1.2.x to libpng.3/libpng.txt - -Version 1.4.0beta53 [April 1, 2009] - Removed some remaining MMX macros from pngpriv.h - Fixed potential memory leak of "new_name" in png_write_iCCP() (Ralph Giles) - -Version 1.4.0beta54 [April 13, 2009] - Added "ifndef PNG_SKIP_SETJMP_CHECK" block in pngconf.h to allow - application code writers to bypass the check for multiple inclusion - of setjmp.h when they know that it is safe to ignore the situation. - Eliminated internal use of setjmp() in pngread.c and pngwrite.c - Reordered ancillary chunks in pngtest.png to be the same as what - pngtest now produces, and made some cosmetic changes to pngtest output. - Eliminated deprecated png_read_init_3() and png_write_init_3() functions. - -Version 1.4.0beta55 [April 15, 2009] - Simplified error handling in pngread.c and pngwrite.c by putting - the new png_read_cleanup() and png_write_cleanup() functions inline. - -Version 1.4.0beta56 [April 25, 2009] - Renamed "user_chunk_data" to "my_user_chunk_data" in pngtest.c to suppress - "shadowed declaration" warning from gcc-4.3.3. - Renamed "gamma" to "png_gamma" in pngset.c to avoid "shadowed declaration" - warning about a global "gamma" variable in math.h on some platforms. - -Version 1.4.0beta57 [May 2, 2009] - Removed prototype for png_freeptr() that was added in libpng-1.4.0beta24 - but was never defined (again). - Rebuilt configure scripts with autoconf-2.63 instead of 2.62 - Removed pngprefs.h and MMX from makefiles - -Version 1.4.0beta58 [May 14, 2009] - Changed pngw32.def to pngwin.def in makefile.mingw (typo was introduced - in beta57). - Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri) - -Version 1.4.0beta59 [May 15, 2009] - Reformated sources in libpng style (3-space intentation, comment format) - Fixed typo in libpng docs (PNG_FILTER_AVE should be PNG_FILTER_AVG) - Added sections about the git repository and our coding style to the - documentation - Relocated misplaced #endif in pngwrite.c, sCAL chunk handler. - -Version 1.4.0beta60 [May 19, 2009] - Conditionally compile png_read_finish_row() which is not used by - progressive readers. - Added contrib/pngminim/preader to demonstrate building minimal progressive - decoder, based on contrib/gregbook with embedded libpng and zlib. - -Version 1.4.0beta61 [May 20, 2009] - In contrib/pngminim/*, renamed "makefile.std" to "makefile", since there - is only one makefile in those directories, and revised the README files - accordingly. - More reformatting of comments, mostly to capitalize sentences. - -Version 1.4.0beta62 [June 2, 2009] - Added "#define PNG_NO_WRITE_SWAP" to contrib/pngminim/encoder/pngusr.h - and "define PNG_NO_READ_SWAP" to decoder/pngusr.h and preader/pngusr.h - Reformatted several remaining "else statement" into two lines. - Added a section to the libpng documentation about using png_get_io_ptr() - in configure scripts to detect the presence of libpng. - -Version 1.4.0beta63 [June 15, 2009] - Revised libpng*.txt and libpng.3 to mention calling png_set_IHDR() - multiple times and to specify the sample order in the tRNS chunk, - because the ISO PNG specification has a typo in the tRNS table. - Changed several PNG_UNKNOWN_CHUNK_SUPPORTED to - PNG_HANDLE_AS_UNKNOWN_SUPPORTED, to make the png_set_keep mechanism - available for ignoring known chunks even when not saving unknown chunks. - Adopted preference for consistent use of "#ifdef" and "#ifndef" versus - "#if defined()" and "if !defined()" where possible. - -Version 1.4.0beta64 [June 24, 2009] - Eliminated PNG_LEGACY_SUPPORTED code. - Moved the various unknown chunk macro definitions outside of the - PNG_READ|WRITE_ANCILLARY_CHUNK_SUPPORTED blocks. - -Version 1.4.0beta65 [June 26, 2009] - Added a reference to the libpng license in each file. - -Version 1.4.0beta66 [June 27, 2009] - Refer to the libpng license instead of the libpng license in each file. - -Version 1.4.0beta67 [July 6, 2009] - Relocated INVERT_ALPHA within png_read_png() and png_write_png(). - Added high-level API transform PNG_TRANSFORM_GRAY_TO_RGB. - Added an "xcode" project to the projects directory (Alam Arias). - -Version 1.4.0beta68 [July 19, 2009] - Avoid some tests in filter selection in pngwutil.c - -Version 1.4.0beta69 [July 25, 2009] - Simplified the new filter-selection test. This runs faster in the - common "PNG_ALL_FILTERS" and PNG_FILTER_NONE cases. - Removed extraneous declaration from the new call to png_read_gray_to_rgb() - (bug introduced in libpng-1.4.0beta67). - Fixed up xcode project (Alam Arias) - Added a prototype for png_64bit_product() in png.c - -Version 1.4.0beta70 [July 27, 2009] - Avoid a possible NULL dereference in debug build, in png_set_text_2(). - (bug introduced in libpng-0.95, discovered by Evan Rouault) - -Version 1.4.0beta71 [July 29, 2009] - Rebuilt configure scripts with autoconf-2.64. - -Version 1.4.0beta72 [August 1, 2009] - Replaced *.tar.lzma with *.tar.xz in distribution. Get the xz codec - from . - -Version 1.4.0beta73 [August 1, 2009] - Reject attempt to write iCCP chunk with negative embedded profile length - (JD Chen) (CVE-2009-5063). - -Version 1.4.0beta74 [August 8, 2009] - Changed png_ptr and info_ptr member "trans" to "trans_alpha". - -Version 1.4.0beta75 [August 21, 2009] - Removed an extra png_debug() recently added to png_write_find_filter(). - Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. - -Version 1.4.0beta76 [August 22, 2009] - Moved an incorrectly located test in png_read_row() in pngread.c - -Version 1.4.0beta77 [August 27, 2009] - Removed lpXYZ.tar.bz2 (with CRLF), KNOWNBUG, libpng-x.y.z-KNOWNBUG.txt, - and the "noconfig" files from the distribution. - Moved CMakeLists.txt from scripts into the main libpng directory. - Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) - -Version 1.4.0beta78 [August 31, 2009] - Converted all PNG_NO_* tests to PNG_*_SUPPORTED everywhere except pngconf.h - Eliminated PNG_NO_FREE_ME and PNG_FREE_ME_SUPPORTED macros. - Use png_malloc plus a loop instead of png_calloc() to initialize - row_pointers in png_read_png(). - -Version 1.4.0beta79 [September 1, 2009] - Eliminated PNG_GLOBAL_ARRAYS and PNG_LOCAL_ARRAYS; always use local arrays. - Eliminated PNG_CALLOC_SUPPORTED macro and always provide png_calloc(). - -Version 1.4.0beta80 [September 17, 2009] - Removed scripts/libpng.icc - Changed typecast of filler from png_byte to png_uint_16 in png_set_filler(). - (Dennis Gustafsson) - Fixed typo introduced in beta78 in pngtest.c ("#if def " should be "#ifdef ") - -Version 1.4.0beta81 [September 23, 2009] - Eliminated unused PNG_FLAG_FREE_* defines from pngpriv.h - Expanded TAB characters in pngrtran.c - Removed PNG_CONST from all "PNG_CONST PNG_CHNK" declarations to avoid - compiler complaints about doubly declaring things "const". - Changed all "#if [!]defined(X)" to "if[n]def X" where possible. - Eliminated unused png_ptr->row_buf_size - -Version 1.4.0beta82 [September 25, 2009] - Moved redundant IHDR checking into new png_check_IHDR() in png.c - and report all errors found in the IHDR data. - Eliminated useless call to png_check_cHRM() from pngset.c - -Version 1.4.0beta83 [September 25, 2009] - Revised png_check_IHDR() to eliminate bogus complaint about filter_type. - -Version 1.4.0beta84 [September 30, 2009] - Fixed some inconsistent indentation in pngconf.h - Revised png_check_IHDR() to add a test for width variable less than 32-bit. - -Version 1.4.0beta85 [October 1, 2009] - Revised png_check_IHDR() again, to check info_ptr members instead of - the contents of the returned parameters. - -Version 1.4.0beta86 [October 9, 2009] - Updated the "xcode" project (Alam Arias). - Eliminated a shadowed declaration of "pp" in png_handle_sPLT(). - -Version 1.4.0rc01 [October 19, 2009] - Trivial cosmetic changes. - -Version 1.4.0beta87 [October 30, 2009] - Moved version 1.4.0 back into beta. - -Version 1.4.0beta88 [October 30, 2009] - Revised libpng*.txt section about differences between 1.2.x and 1.4.0 - because most of the new features have now been ported back to 1.2.41 - -Version 1.4.0beta89 [November 1, 2009] - More bugfixes and improvements to CMakeLists.txt (Philip Lowman) - Removed a harmless extra png_set_invert_alpha() from pngwrite.c - Apply png_user_chunk_cache_max within png_decompress_chunk(). - Merged libpng-1.2.41.txt with libpng-1.4.0.txt where appropriate. - -Version 1.4.0beta90 [November 2, 2009] - Removed all remaining WIN32_WCE #ifdefs except those involving the - time.h "tm" structure - -Version 1.4.0beta91 [November 3, 2009] - Updated scripts/pngw32.def and projects/wince/png32ce.def - Copied projects/wince/png32ce.def to the scripts directory. - Added scripts/makefile.wce - Patched ltmain.sh for wince support. - Added PNG_CONVERT_tIME_SUPPORTED macro. - -Version 1.4.0beta92 [November 4, 2009] - Make inclusion of time.h in pngconf.h depend on PNG_CONVERT_tIME_SUPPORTED - Make #define PNG_CONVERT_tIME_SUPPORTED depend on PNG_WRITE_tIME_SUPPORTED - Revised libpng*.txt to describe differences from 1.2.40 to 1.4.0 (instead - of differences from 1.2.41 to 1.4.0) - -Version 1.4.0beta93 [November 7, 2009] - Added PNG_DEPSTRUCT, PNG_DEPRECATED, PNG_USE_RESULT, PNG_NORETURN, and - PNG_ALLOCATED macros to detect deprecated direct access to the - png_struct or info_struct members and other deprecated usage in - applications (John Bowler). - Updated scripts/makefile* to add "-DPNG_CONFIGURE_LIBPNG" to CFLAGS, - to prevent warnings about direct access to png structs by libpng - functions while building libpng. They need to be tested, especially - those using compilers other than gcc. - Updated projects/visualc6 and visualc71 with "/d PNG_CONFIGURE_LIBPNG". - They should work but still need to be updated to remove - references to pnggccrd.c or pngvcrd.c and ASM building. - Added README.txt to the beos, cbuilder5, netware, and xcode projects warning - that they need to be updated, to remove references to pnggccrd.c and - pngvcrd.c and to depend on pngpriv.h - Removed three direct references to read_info_ptr members in pngtest.c - that were detected by the new PNG_DEPSTRUCT macro. - Moved the png_debug macro definitions and the png_read_destroy(), - png_write_destroy() and png_far_to_near() prototypes from png.h - to pngpriv.h (John Bowler) - Moved the synopsis lines for png_read_destroy(), png_write_destroy() - png_debug(), png_debug1(), and png_debug2() from libpng.3 to libpngpf.3. - -Version 1.4.0beta94 [November 9, 2009] - Removed the obsolete, unused pnggccrd.c and pngvcrd.c files. - Updated CMakeLists.txt to add "-DPNG_CONFIGURE_LIBPNG" to the definitions. - Removed dependency of pngtest.o on pngpriv.h in the makefiles. - Only #define PNG_DEPSTRUCT, etc. in pngconf.h if not already defined. - -Version 1.4.0beta95 [November 10, 2009] - Changed png_check_sig() to !png_sig_cmp() in contrib programs. - Added -DPNG_CONFIGURE_LIBPNG to contrib/pngminm/*/makefile - Changed png_check_sig() to !png_sig_cmp() in contrib programs. - Corrected the png_get_IHDR() call in contrib/gregbook/readpng2.c - Changed pngminim/*/gather.sh to stop trying to remove pnggccrd.c and pngvcrd.c - Added dependency on pngpriv.h in contrib/pngminim/*/makefile - -Version 1.4.0beta96 [November 12, 2009] - Renamed scripts/makefile.wce to scripts/makefile.cegcc - Revised Makefile.am to use libpng.sys while building libpng.so - so that only PNG_EXPORT functions are exported. - Removed the deprecated png_check_sig() function/macro. - Removed recently removed function names from scripts/*.def - Revised pngtest.png to put chunks in the same order written by pngtest - (evidently the same change made in libpng-1.0beta54 was lost). - Added PNG_PRIVATE macro definition in pngconf.h for possible future use. - -Version 1.4.0beta97 [November 13, 2009] - Restored pngtest.png to the libpng-1.4.0beta7 version. - Removed projects/beos and netware.txt; no one seems to be supporting them. - Revised Makefile.in - -Version 1.4.0beta98 [November 13, 2009] - Added the "xcode" project to zip distributions, - Fixed a typo in scripts/pngwin.def introduced in beta97. - -Version 1.4.0beta99 [November 14, 2009] - Moved libpng-config.in and libpng.pc-configure.in out of the scripts - directory, to libpng-config.in and libpng-pc.in, respectively, and - modified Makefile.am and configure.ac accordingly. Now "configure" - needs nothing from the "scripts" directory. - Avoid redefining PNG_CONST in pngconf.h - -Version 1.4.0beta100 [November 14, 2009] - Removed ASM builds from projects/visualc6 and projects/visualc71 - Removed scripts/makefile.nommx and makefile.vcawin32 - Revised CMakeLists.txt to account for new location of libpng-config.in - and libpng-pc.in - Updated INSTALL to reflect removal and relocation of files. - -Version 1.4.0beta101 [November 14, 2009] - Restored the binary files (*.jpg, *.png, some project files) that were - accidentally deleted from the zip and 7z distributions when the xcode - project was added. - -Version 1.4.0beta102 [November 18, 2009] - Added libpng-config.in and libpng-pc.in to the zip and 7z distributions. - Fixed a typo in projects/visualc6/pngtest.dsp, introduced in beta100. - Moved descriptions of makefiles and other scripts out of INSTALL into - scripts/README.txt - Updated the copyright year in scripts/pngwin.rc from 2006 to 2009. - -Version 1.4.0beta103 [November 21, 2009] - Removed obsolete comments about ASM from projects/visualc71/README_zlib.txt - Align row_buf on 16-byte boundary in memory. - Restored the PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED guard around the call - to png_flush() after png_write_IEND(). See 1.4.0beta32, 1.4.0beta50 - changes above and 1.2.30, 1.2.30rc01 and rc03 in 1.2.41 CHANGES. Someone - needs this feature. - Make the 'png_jmpbuf' macro expand to a call that records the correct - longjmp function as well as returning a pointer to the setjmp - jmp_buf buffer, and marked direct access to jmpbuf 'deprecated'. - (John Bowler) - -Version 1.4.0beta104 [November 22, 2009] - Removed png_longjmp_ptr from scripts/*.def and libpng.3 - Rebuilt configure scripts with autoconf-2.65 - -Version 1.4.0beta105 [November 25, 2009] - Use fast integer PNG_DIVIDE_BY_255() or PNG_DIVIDE_BY_65535() - to accomplish alpha premultiplication when - PNG_READ_COMPOSITE_NODIV_SUPPORTED is defined. - Changed "/255" to "/255.0" in background calculations to make it clear - that the 255 is used as a double. - -Version 1.4.0beta106 [November 27, 2009] - Removed premultiplied alpha feature. - -Version 1.4.0beta107 [December 4, 2009] - Updated README - Added "#define PNG_NO_PEDANTIC_WARNINGS" in the libpng source files. - Removed "-DPNG_CONFIGURE_LIBPNG" from the makefiles and projects. - Revised scripts/makefile.netbsd, makefile.openbsd, and makefile.sco - to put png.h and pngconf.h in $prefix/include, like the other scripts, - instead of in $prefix/include/libpng. Also revised makefile.sco - to put them in $prefix/include/libpng15 instead of in - $prefix/include/libpng/libpng15. - -Version 1.4.0beta108 [December 11, 2009] - Removed leftover "-DPNG_CONFIGURE_LIBPNG" from contrib/pngminim/*/makefile - Relocated png_do_chop() to its original position in pngrtran.c; the - change in version 1.2.41beta08 caused transparency to be handled wrong - in some 16-bit datastreams (Yusaku Sugai). - -Version 1.4.0beta109 [December 13, 2009] - Added "bit_depth" parameter to the private png_build_gamma_table() function. - Pass bit_depth=8 to png_build_gamma_table() when bit_depth is 16 but the - PNG_16_TO_8 transform has been set, to avoid unnecessary build of 16-bit - tables. - -Version 1.4.0rc02 [December 20, 2009] - Declared png_cleanup_needed "volatile" in pngread.c and pngwrite.c - -Version 1.4.0rc03 [December 22, 2009] - Renamed libpng-pc.in back to libpng.pc.in and revised CMakeLists.txt - (revising the change in 1.4.0beta99) - -Version 1.4.0rc04 [December 25, 2009] - Swapped PNG_UNKNOWN_CHUNKS_SUPPORTED and PNG_HANDLE_AS_UNKNOWN_SUPPORTED - in pngset.c to be consistent with other changes in version 1.2.38. - -Version 1.4.0rc05 [December 25, 2009] - Changed "libpng-pc.in" to "libpng.pc.in" in configure.ac, configure, and - Makefile.in to be consistent with changes in libpng-1.4.0rc03 - -Version 1.4.0rc06 [December 29, 2009] - Reverted the gamma_table changes from libpng-1.4.0beta109. - Fixed some indentation errors. - -Version 1.4.0rc07 [January 1, 2010] - Revised libpng*.txt and libpng.3 about 1.2.x->1.4.x differences. - Use png_calloc() instead of png_malloc(); png_memset() in pngrutil.c - Update copyright year to 2010. - -Version 1.4.0rc08 [January 2, 2010] - Avoid deprecated references to png_ptr-io_ptr and png_ptr->error_ptr - in pngtest.c - -Version 1.4.0 [January 3, 2010] - No changes. - -Version 1.4.1beta01 [January 8, 2010] - Updated CMakeLists.txt for consistent indentation and to avoid an - unclosed if-statement warning (Philip Lowman). - Revised Makefile.am and Makefile.in to remove references to Y2KINFO, - KNOWNBUG, and libpng.la (Robert Schwebel). - Revised the makefiles to install the same files and symbolic - links as configure, except for libpng.la and libpng14.la. - Make png_set|get_compression_buffer_size() available even when - PNG_WRITE_SUPPORTED is not enabled. - Revised Makefile.am and Makefile.in to simplify their maintenance. - Revised scripts/makefile.linux to install a link to libpng14.so.14.1 - -Version 1.4.1beta02 [January 9, 2010] - Revised the rest of the makefiles to install a link to libpng14.so.14.1 - -Version 1.4.1beta03 [January 10, 2010] - Removed png_set_premultiply_alpha() from scripts/*.def - -Version 1.4.1rc01 [January 16, 2010] - No changes. - -Version 1.4.1beta04 [January 23, 2010] - Revised png_decompress_chunk() to improve speed and memory usage when - decoding large chunks. - Added png_set|get_chunk_malloc_max() functions. - -Version 1.4.1beta05 [January 26, 2010] - Relocated "int k" declaration in pngtest.c to minimize its scope. - -Version 1.4.1beta06 [January 28, 2010] - Revised png_decompress_chunk() to use a two-pass method suggested by - John Bowler. - -Version 1.4.1beta07 [February 6, 2010] - Folded some long lines in the source files. - Added defineable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX, - and a PNG_USER_LIMITS_SUPPORTED flag. - Eliminated use of png_ptr->irowbytes and reused the slot in png_ptr as - png_ptr->png_user_chunk_malloc_max. - Revised png_push_save_buffer() to do fewer but larger png_malloc() calls. - -Version 1.4.1beta08 [February 6, 2010] - Minor cleanup and updating of dates and copyright year. - -Version 1.5.0beta01 [February 7, 2010] - Moved declaration of png_struct into private pngstruct.h and png_info - into pnginfo.h - -Version 1.4.1beta09 and 1.5.0beta02 [February 7, 2010] - Reverted to original png_push_save_buffer() code. - -Version 1.4.1beta10 and 1.5.0beta03 [February 8, 2010] - Return allocated "old_buffer" in png_push_save_buffer() before - calling png_error(), to avoid a potential memory leak. - Updated configure script to use SO number 15. - -Version 1.5.0beta04 [February 9, 2010] - Removed malformed "incomplete struct declaration" of png_info from png.h - -Version 1.5.0beta05 [February 12, 2010] - Removed PNG_DEPSTRUCT markup in pngstruct.h and pnginfo.h, and undid the - linewrapping that it entailed. - Revised comments in pngstruct.h and pnginfo.h and added pointers to - the libpng license. - Changed PNG_INTERNAL to PNG_EXPOSE_INTERNAL_STRUCTURES - Removed the cbuilder5 project, which has not been updated to 1.4.0. - -Version 1.4.1beta12 and 1.5.0beta06 [February 14, 2010] - Fixed type declaration of png_get_chunk_malloc_max() in pngget.c (Daisuke - Nishikawa) - -Version 1.5.0beta07 [omitted] - -Version 1.5.0beta08 [February 19, 2010] - Changed #ifdef PNG_NO_STDIO_SUPPORTED to #ifdef PNG_NO_CONSOLE_IO_SUPPORTED - wherever png_snprintf() is used to construct error and warning messages. - Noted in scripts/makefile.mingw that it expects to be run under MSYS. - Removed obsolete unused MMX-querying support from contrib/gregbook - Added exported png_longjmp() function. - Removed the AIX redefinition of jmpbuf in png.h - Added -D_ALLSOURCE in configure.ac, makefile.aix, and CMakeLists.txt - when building on AIX. - -Version 1.5.0beta09 [February 19, 2010] - Removed -D_ALLSOURCE from configure.ac, makefile.aix, and CMakeLists.txt. - Changed the name of png_ptr->jmpbuf to png_ptr->png_jmpbuf in pngstruct.h - -Version 1.5.0beta10 [February 25, 2010] - Removed unused gzio.c from contrib/pngminim gather and makefile scripts - Removed replacement error handlers from contrib/gregbook. Because of - the new png_longjmp() function they are no longer needed. - -Version 1.5.0beta11 [March 6, 2010] - Removed checking for already-included setjmp.h from pngconf.h - Fixed inconsistent indentations and made numerous cosmetic changes. - Revised the "SEE ALSO" style of libpng.3, libpngpf.3, and png.5 - -Version 1.5.0beta12 [March 9, 2010] - Moved "#include png.h" inside pngpriv.h and removed "#include png.h" from - the source files, along with "#define PNG_EXPOSE_INTERNAL_STRUCTURES" - and "#define PNG_NO_PEDANTIC_WARNINGS" (John Bowler). - Created new pngdebug.h and moved debug definitions there. - -Version 1.5.0beta13 [March 10, 2010] - Protect pngstruct.h, pnginfo.h, and pngdebug.h from being included twice. - Revise the "#ifdef" blocks in png_inflate() so it will compile when neither - PNG_USER_CHUNK_MALLOC_MAX nor PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - is defined. - Removed unused png_measure_compressed_chunk() from pngpriv.h and libpngpf.3 - Moved the 'config.h' support from pngconf.h to pngpriv.h - Removed PNGAPI from the png_longjmp_ptr typedef. - Eliminated dependence of pngtest.c on the private pngdebug.h file. - Make all png_debug macros into *unterminated* statements or - expressions (i.e. a trailing ';' must always be added) and correct - the format statements in various png_debug messages. - -Version 1.5.0beta14 [March 14, 2010] - Removed direct access to png_ptr->io_ptr from the Windows code in pngtest.c - Revised Makefile.am to account for recent additions and replacements. - Corrected CE and OS/2 DEF files (scripts/png*def) for symbols removed and - added ordinal numbers to the Windows DEF file and corrected the duplicated - ordinal numbers on CE symbols that are commented out. - Added back in export symbols that can be present in the Windows build but - are disabled by default. - PNG_EXPORT changed to include an 'ordinal' field for DEF file generation. - PNG_CALLBACK added to make callback definitions uniform. PNGAPI split - into PNGCAPI (base C form), PNGAPI (exports) and PNGCBAPI (callbacks), - and appropriate changes made to all files. Cygwin builds re-hinged to - allow procedure call standard changes and to remove the need for the DEF - file (fixes build on Cygwin). - Enabled 'attribute' warnings that are relevant to library APIs and callbacks. - Changed rules for generation of the various symbol files and added a new - rule for a DEF file (which is also added to the distribution). - Updated the symbol file generation to stop it adding spurious spaces - to EOL (coming from preprocessor macro expansion). Added a facility - to join tokens in the output and rewrite *.dfn to use this. - Eliminated scripts/*.def in favor of libpng.def; updated projects/visualc71 - and removed scripts/makefile.cygwin. - Made PNG_BUILD_DLL safe: it can be set whenever a DLL is being built. - Removed the include of sys/types.h - apparently unnecessary now on the - platforms on which it happened (all but Mac OS and RISC OS). - Moved the Mac OS test into pngpriv.h (the only place it is used.) - -Version 1.5.0beta15 [March 17, 2010] - Added symbols.chk target to Makefile.am to validate the symbols in png.h - against the new DEF file scripts/symbols.def. - Changed the default DEF file back to pngwin.def. - Removed makefile.mingw. - Eliminated PNG_NO_EXTERN and PNG_ALL_EXTERN - -Version 1.5.0beta16 [April 1, 2010] - Make png_text_struct independent of PNG_iTXt_SUPPORTED, so that - fields are initialized in all configurations. The READ/WRITE - macros (PNG_(READ|WRITE)_iTXt_SUPPORTED) still function as - before to disable code to actually read or write iTXt chunks - and iTXt_SUPPORTED can be used to detect presence of either - read or write support (but it is probably better to check for - the one actually required - read or write.) - Combined multiple png_warning() calls for a single error. - Restored the macro definition of png_check_sig(). - -Version 1.5.0beta17 [April 17, 2010] - Added some "(long)" typecasts to printf calls in png_handle_cHRM(). - Documented the fact that png_set_dither() was disabled since libpng-1.4.0. - Reenabled png_set_dither() but renamed it to png_set_quantize() to reflect - more accurately what it actually does. At the same time, renamed - the PNG_DITHER_[RED,GREEN_BLUE]_BITS macros to - PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS. - Added some "(long)" typecasts to printf calls in png_handle_cHRM(). - Freeze build-time only configuration in the build. - In all prior versions of libpng most configuration options - controlled by compiler #defines had to be repeated by the - application code that used libpng. This patch changes this - so that compilation options that can only be changed at build - time are frozen in the build. Options that are compiler - dependent (and those that are system dependent) are evaluated - each time - pngconf.h holds these. Options that can be changed - per-file in the application are in png.h. Frozen options are - in the new installed header file pnglibconf.h (John Bowler) - Removed the xcode project because it has not been updated to work - with libpng-1.5.0. - Removed the ability to include optional pngusr.h - -Version 1.5.0beta18 [April 17, 2010] - Restored the ability to include optional pngusr.h - Moved replacements for png_error() and png_warning() from the - contrib/pngminim project to pngerror.c, for use when warnings or - errors are disabled via PNG_NO_WARN or PNG_NO_ERROR_TEXT, to avoid - storing unneeded error/warning text. - Updated contrib/pngminim project to work with the new pnglibconf.h - Added some PNG_NO_* defines to contrib/pngminim/*/pngusr.h to save space. - -Version 1.5.0beta19 [April 24, 2010] - Added PNG_{READ,WRITE}_INT_FUNCTIONS_SUPPORTED. This allows the functions - to read and write ints to be disabled independently of PNG_USE_READ_MACROS, - which allows libpng to be built with the functions even though the default - is to use the macros - this allows applications to choose at app build - time whether or not to use macros (previously impossible because the - functions weren't in the default build.) - Changed Windows calling convention back to __cdecl for API functions. - For Windows/x86 platforms only: - __stdcall is no longer needed for Visual Basic, so libpng-1.5.0 uses - __cdecl throughout (both API functions and callbacks) on Windows/x86 - platforms. - Replaced visualc6 and visualc71 projects with new vstudio project - Relaxed the overly-restrictive permissions of some files. - -Version 1.5.0beta20 [April 24, 2010] - Relaxed more overly-restrictive permissions of some files. - -Version 1.5.0beta21 [April 27, 2010] - Removed some unwanted binary bytes and changed CRLF to NEWLINE in the new - vstudio project files, and some trivial editing of some files in the - scripts directory. - Set PNG_NO_READ_BGR, PNG_NO_IO_STATE, and PNG_NO_TIME_RFC1123 in - contrib/pngminim/decoder/pngusr.h to make a smaller decoder application. - -Version 1.5.0beta22 [April 28, 2010] - Fixed dependencies of GET_INT_32 - it does not require READ_INT_FUNCTIONS - because it has a macro equivalent. - Improved the options.awk script; added an "everything off" option. - Revised contrib/pngminim to use the "everything off" option in pngusr.dfa. - -Version 1.5.0beta23 [April 29, 2010] - Corrected PNG_REMOVED macro to take five arguments. - The macro was documented with two arguments (name,ordinal), however - the symbol checking .dfn files assumed five arguments. The five - argument form seems more useful so it is changed to that. - Corrected PNG_UNKNOWN_CHUNKS_SUPPORTED to PNG_HANDLE_AS_UNKNOWN_SUPPORTED - in gregbook/readpng2.c - Corrected protection of png_get_user_transform_ptr. The API declaration in - png.h is removed if both READ and WRITE USER_TRANSFORM are turned off - but was left defined in pngtrans.c - Added logunsupported=1 to cause pnglibconf.h to document disabled options. - This makes the installed pnglibconf.h more readable but causes no - other change. The intention is that users of libpng will find it - easier to understand if an API they need is missing. - Include png_reset_zstream() in png.c only when PNG_READ_SUPPORTED is defined. - Removed dummy_inflate.c from contrib/pngminim/encoder - Removed contrib/pngminim/*/gather.sh; gathering is now done in the makefile. - -Version 1.5.0beta24 [May 7, 2010] - Use bitwise "&" instead of arithmetic mod in pngrutil.c calculation of the - offset of the png_ptr->rowbuf pointer into png_ptr->big_row_buf. - Added more blank lines for readability. - -Version 1.5.0beta25 [June 18, 2010] - In pngpread.c: png_push_have_row() add check for new_row > height - Removed the now-redundant check for out-of-bounds new_row from example.c - -Version 1.5.0beta26 [June 18, 2010] - In pngpread.c: png_push_process_row() add check for too many rows. - -Version 1.5.0beta27 [June 18, 2010] - Removed the check added in beta25 as it is now redundant. - -Version 1.5.0beta28 [June 20, 2010] - Rewrote png_process_IDAT_data to consistently treat extra data as warnings - and handle end conditions more cleanly. - Removed the new (beta26) check in png_push_process_row(). - -Version 1.5.0beta29 [June 21, 2010] - Revised scripts/options.awk to work on Sunos (but still doesn't work) - Added comment to options.awk and contrib/pngminim/*/makefile to try nawk. - -Version 1.5.0beta30 [June 22, 2010] - Stop memory leak when reading a malformed sCAL chunk. - -Version 1.5.0beta31 [June 26, 2010] - Revised pngpread.c patch of beta28 to avoid an endless loop. - Removed some trailing blanks. - -Version 1.5.0beta32 [June 26, 2010] - Removed leftover scripts/options.patch and scripts/options.rej - -Version 1.5.0beta33 [July 6, 3010] - Made FIXED and FLOATING options consistent in the APIs they enable and - disable. Corrected scripts/options.awk to handle both command line - options and options specified in the .dfa files. - Changed char *msg to PNG_CONST char *msg in pngrutil.c - Make png_set_sRGB_gAMA_and_cHRM set values using either the fixed or - floating point APIs, but not both. - Reversed patch to remove error handler when the jmp_buf is stored in the - main program structure, not the png_struct. - The error handler is needed because the default handler in libpng will - always use the jmp_buf in the library control structure; this is never - set. The gregbook code is a useful example because, even though it - uses setjmp/longjmp, it shows how error handling can be implemented - using control mechanisms not directly supported by libpng. The - technique will work correctly with mechanisms such as Microsoft - Structure Exceptions or C++ exceptions (compiler willing - note that gcc - does not by default support interworking of C and C++ error handling.) - Reverted changes to call png_longjmp in contrib/gregbook where it is not - appropriate. If mainprog->jmpbuf is used by setjmp, then png_longjmp - cannot be used. - Changed "extern PNG_EXPORT" to "PNG_EXPORT" in png.h (Jan Nijtmans) - Changed "extern" to "PNG_EXTERN" in pngpriv.h (except for the 'extern "C" {') - -Version 1.5.0beta34 [July 12, 2010] - Put #ifndef PNG_EXTERN, #endif around the define PNG_EXTERN in pngpriv.h - -Version 1.5.0beta35 [July 24, 2010] - Removed some newly-added TAB characters. - Added -DNO_PNG_SNPRINTF to CFLAGS in scripts/makefile.dj2 - Moved the definition of png_snprintf() outside of the enclosing - #ifdef blocks in pngconf.h - -Version 1.5.0beta36 [July 29, 2010] - Patches by John Bowler: - Fixed point APIs are now supported throughout (no missing APIs). - Internal fixed point arithmetic support exists for all internal floating - point operations. - sCAL validates the floating point strings it is passed. - Safe, albeit rudimentary, Watcom support is provided by PNG_API_RULE==2 - Two new APIs exist to get the number of passes without turning on the - PNG_INTERLACE transform and to get the number of rows in the current - pass. - A new test program, pngvalid.c, validates the gamma code. - Errors in the 16-bit gamma correction (overflows) have been corrected. - cHRM chunk testing is done consistently (previously the floating point - API bypassed it, because the test really didn't work on FP, now the test - is performed on the actual values to be stored in the PNG file so it - works in the FP case too.) - Most floating point APIs now simply call the fixed point APIs after - converting the values to the fixed point form used in the PNG file. - The standard headers no longer include zlib.h, which is currently only - required for pngstruct.h and can therefore be internal. - Revised png_get_int_32 to undo the PNG two's complement representation of - negative numbers. - -Version 1.5.0beta37 [July 30, 2010] - Added a typecast in png_get_int_32() in png.h and pngrutil.h to avoid - a compiler warning. - Replaced oFFs 0,0 with oFFs -10,20 in pngtest.png - -Version 1.5.0beta38 [July 31, 2010] - Implemented remaining "_fixed" functions. - Corrected a number of recently introduced warnings mostly resulting from - safe but uncast assignments to shorter integers. Also added a zlib - VStudio release library project because the latest zlib Official Windows - build does not include such a thing. - Revised png_get_int_16() to be similar to png_get_int_32(). - Restored projects/visualc71. - -Version 1.5.0beta39 [August 2, 2010] - VisualC/GCC warning fixes, VisualC build fixes - The changes include support for function attributes in VC in addition to - those already present in GCC - necessary because without these some - warnings are unavoidable. Fixes include signed/unsigned fixes in - pngvalid and checks with gcc -Wall -Wextra -Wunused. - VC requires function attributes on function definitions as well as - declarations, PNG_FUNCTION has been added to enable this and the - relevant function definitions changed. - -Version 1.5.0beta40 [August 6, 2010] - Correct use of _WINDOWS_ in pngconf.h - Removed png_mem_ #defines; they are no longer used. - Added the sRGB chunk to pngtest.png - -Version 1.5.0beta41 [August 11, 2010] - Added the cHRM chunk to pngtest.png - Don't try to use version-script with cygwin/mingw. - Revised contrib/gregbook to work under cygwin/mingw. - -Version 1.5.0beta42 [August 18, 2010] - Add .dll.a to the list of extensions to be symlinked by Makefile.am (Yaakov) - Made all API functions that have const arguments and constant string - literal pointers declare them (John Bowler). - -Version 1.5.0beta43 [August 20, 2010] - Removed spurious tabs, shorten long lines (no source change) - Also added scripts/chkfmt to validate the format of all the files that can - reasonably be validated (it is suggested to run "make distclean" before - checking, because some machine generated files have long lines.) - Reformatted the CHANGES file to be more consistent throughout. - Made changes to address various issues identified by GCC, mostly - signed/unsigned and shortening problems on assignment but also a few - difficult to optimize (for GCC) loops. - Fixed non-GCC fixed point builds. In png.c a declaration was misplaced - in an earlier update. Fixed to declare the auto variables at the head. - Use cexcept.h in pngvalid.c. - -Version 1.5.0beta44 [August 24, 2010] - Updated CMakeLists.txt to use CMAKE_INSTALL_LIBDIR variable; useful for - installing libpng in /usr/lib64 (Funda Wang). - Revised CMakeLists.txt to put the man pages in share/man/man* not man/man* - Revised CMakeLists.txt to make symlinks instead of copies when installing. - Changed PNG_LIB_NAME from pngNN to libpngNN in CMakeLists.txt (Philip Lowman) - Implemented memory checks within pngvalid - Reformatted/rearranged pngvalid.c to assist use of progressive reader. - Check interlaced images in pngvalid - Clarified pngusr.h comments in pnglibconf.dfa - Simplified the pngvalid error-handling code now that cexcept.h is in place. - Implemented progressive reader in pngvalid.c for standard tests - Implemented progressive read in pngvalid.c gamma tests - Turn on progressive reader in pngvalid.c by default and tidy code. - -Version 1.5.0beta45 [August 26, 2010] - Added an explicit make step to projects/vstudio for pnglibconf.h - Also corrected zlib.vcxproj into which Visual Studio had introduced - what it calls an "authoring error". The change to make pnglibconf.h - simply copies the file; in the future it may actually generate the - file from scripts/pnglibconf.dfa as the other build systems do. - Changed pngvalid to work when floating point APIs are disabled - Renamed the prebuilt scripts/pnglibconf.h to scripts/pnglibconf.h.prebuilt - Supply default values for PNG_USER_PRIVATEBUILD and PNG_USER_DLLFNAME_POSTFIX - in pngpriv.h in case the user neglected to define them in their pngusr.h - -Version 1.5.0beta46 [August 28, 2010] - Added new private header files to libpng_sources in CMakeLists.txt - Added PNG_READ_16BIT, PNG_WRITE_16BIT, and PNG_16BIT options. - Added reference to scripts/pnglibconf.h.prebuilt in the visualc71 project. - -Version 1.5.0beta47 [September 11, 2010] - Fixed a number of problems with 64-bit compilation reported by Visual - Studio 2010 (John Bowler). - -Version 1.5.0beta48 [October 4, 2010] - Updated CMakeLists.txt (Philip Lowman). - Revised autogen.sh to recognize and use $AUTOCONF, $AUTOMAKE, $AUTOHEADER, - $AUTOPOINT, $ACLOCAL and $LIBTOOLIZE - Fixed problem with symbols creation in Makefile.am which was assuming that - all versions of ccp write to standard output by default (Martin Banky). The - bug was introduced in libpng-1.2.9beta5. - Removed unused mkinstalldirs. - -Version 1.5.0beta49 [October 8, 2010] - Undid Makefile.am revision of 1.5.0beta48. - -Version 1.5.0beta50 [October 14, 2010] - Revised Makefile.in to account for mkinstalldirs being removed. - Added some "(unsigned long)" typecasts in printf statements in pngvalid.c. - Suppressed a compiler warning in png_handle_sPLT(). - Check for out-of-range text compression mode in png_set_text(). - -Version 1.5.0beta51 [October 15, 2010] - Changed embedded dates to "(PENDING RELEASE) in beta releases (and future - rc releases) to minimize the difference between releases. - -Version 1.5.0beta52 [October 16, 2010] - Restored some of the embedded dates (in png.h, png.c, documentation, etc.) - -Version 1.5.0beta53 [October 18, 2010] - Updated INSTALL to mention using "make maintainer-clean" and to remove - obsolete statement about a custom ltmain.sh - Disabled "color-tests" by default in Makefile.am so it will work with - automake versions earlier than 1.11.1 - Use document name "libpng-manual.txt" instead of "libpng-.txt" - to simplify version differences. - Removed obsolete remarks about setjmp handling from INSTALL. - Revised and renamed the typedef in png.h and png.c that was designed - to catch library and header mismatch. - -Version 1.5.0beta54 [November 10, 2010] - Require 48 bytes, not 64 bytes, for big_row_buf in overflow checks. - Used a consistent structure for the pngget.c functions. - -Version 1.5.0beta55 [November 21, 2010] - Revised png_get_uint_32, png_get_int_32, png_get_uint_16 (Cosmin) - Moved reading of file signature into png_read_sig (Cosmin) - Fixed atomicity of chunk header serialization (Cosmin) - Added test for io_state in pngtest.c (Cosmin) - Added "#!/bin/sh" at the top of contrib/pngminim/*/gather.sh scripts. - Changes to remove gcc warnings (John Bowler) - Certain optional gcc warning flags resulted in warnings in libpng code. - With these changes only -Wconversion and -Wcast-qual cannot be turned on. - Changes are trivial rearrangements of code. -Wconversion is not possible - for pngrutil.c (because of the widespread use of += et al on variables - smaller than (int) or (unsigned int)) and -Wcast-qual is not possible - with pngwio.c and pngwutil.c because the 'write' callback and zlib - compression both fail to declare their input buffers with 'const'. - -Version 1.5.0beta56 [December 7, 2010] - Added the private PNG_UNUSED() macro definition in pngpriv.h. - Added some commentary about PNG_EXPORT in png.h and pngconf.h - Revised PNG_EXPORT() macro and added PNG_EXPORTA() macro, with the - objective of simplifying and improving the cosmetic appearance of png.h. - Fixed some incorrect "=" macro names in pnglibconf.dfa - Included documentation of changes in 1.5.0 from 1.4.x in libpng-manual.txt - -Version 1.5.0beta57 [December 9, 2010] - Documented the pngvalid gamma error summary with additional comments and - print statements. - Improved missing symbol handling in checksym.awk; symbols missing in both - the old and new files can now be optionally ignored, treated as errors - or warnings. - Removed references to pngvcrd.c and pnggccrd.c from the vstudio project. - Updated "libpng14" to "libpng15" in the visualc71 project. - Enabled the strip16 tests in pngvalid.` - Don't display test results (except PASS/FAIL) when running "make test". - Instead put them in pngtest-log.txt - Added "--with-zprefix=" to configure.ac - Updated the prebuilt configuration files to autoconf version 2.68 - -Version 1.5.0beta58 [December 19, 2010] - Fixed interlace image handling and add test cases (John Bowler) - Fixed the clean rule in Makefile.am to remove pngtest-log.txt - Made minor changes to work around warnings in gcc 3.4 - -Version 1.5.0rc01 [December 27, 2010] - No changes. - -Version 1.5.0rc02 [December 27, 2010] - Eliminated references to the scripts/*.def files in project/visualc71. - -Version 1.5.0rc03 [December 28, 2010] - Eliminated scripts/*.def and revised Makefile.am accordingly - -Version 1.5.0rc04 [December 29, 2010] - Fixed bug in background transformation handling in pngrtran.c (it was - looking for the flag in png_ptr->transformations instead of in - png_ptr->flags) (David Raymond). - -Version 1.5.0rc05 [December 31, 2010] - Fixed typo in a comment in CMakeLists.txt (libpng14 => libpng15) (Cosmin) - -Version 1.5.0rc06 [January 4, 2011] - Changed the new configure option "zprefix=string" to "zlib-prefix=string" - -Version 1.5.0rc07 [January 4, 2011] - Updated copyright year. - -Version 1.5.0 [January 6, 2011] - No changes. - -version 1.5.1beta01 [January 8, 2011] - Added description of png_set_crc_action() to the manual. - Added a note in the manual that the type of the iCCP profile was changed - from png_charpp to png_bytepp in png_get_iCCP(). This change happened - in version 1.5.0beta36 but is not noted in the CHANGES. Similarly, - it was changed from png_charpp to png_const_bytepp in png_set_iCCP(). - Ensure that png_rgb_to_gray ignores palette mapped images, if libpng - internally happens to call it with one, and fixed a failure to handle - palette mapped images correctly. This fixes CVE-2690. - -Version 1.5.1beta02 [January 14, 2011] - Fixed a bug in handling of interlaced images (bero at arklinux.org). - Updated CMakeLists.txt (Clifford Yapp) - -Version 1.5.1beta03 [January 14, 2011] - Fixed typecasting of some png_debug() statements (Cosmin) - -Version 1.5.1beta04 [January 16, 2011] - Updated documentation of png_set|get_tRNS() (Thomas Klausner). - Mentioned in the documentation that applications must #include "zlib.h" - if they need access to anything in zlib.h, and that a number of - macros such as png_memset() are no longer accessible by applications. - Corrected pngvalid gamma test "sample" function to access all of the color - samples of each pixel, instead of sampling the red channel three times. - Prefixed variable names index, div, exp, gamma with "png_" to avoid "shadow" - warnings, and (mistakenly) changed png_exp() to exp(). - -Version 1.5.1beta05 [January 16, 2011] - Changed variable names png_index, png_div, png_exp, and png_gamma to - char_index, divisor, exp_b10, and gamma_val, respectively, and - changed exp() back to png_exp(). - -Version 1.5.1beta06 [January 20, 2011] - Prevent png_push_crc_skip() from hanging while reading an unknown chunk - or an over-large compressed zTXt chunk with the progressive reader. - Eliminated more GCC "shadow" warnings. - Revised png_fixed() in png.c to avoid compiler warning about reaching the - end without returning anything. - -Version 1.5.1beta07 [January 22, 2011] - In the manual, describe the png_get_IHDR() arguments in the correct order. - Added const_png_structp and const_png_infop types, and used them in - prototypes for most png_get_*() functions. - -Version 1.5.1beta08 [January 23, 2011] - Added png_get_io_chunk_type() and deprecated png_get_io_chunk_name() - Added synopses for the IO_STATE functions and other missing synopses - to the manual. Removed the synopses from libpngpf.3 because they - were out of date and no longer useful. Better information can be - obtained by reading the prototypes and comments in pngpriv.h - Attempted to fix cpp on Solaris with S. Studio 12 cc, fix build - Added a make macro DFNCPP that is a CPP that will accept the tokens in - a .dfn file and adds configure stuff to test for such a CPP. ./configure - should fail if one is not available. - Corrected const_png_ in png.h to png_const_ to avoid polluting the namespace. - Added png_get_current_row_number and png_get_current_pass_number for the - benefit of the user transform callback. - Added png_process_data_pause and png_process_data_skip for the benefit of - progressive readers that need to stop data processing or want to optimize - skipping of unread data (e.g., if the reader marks a chunk to be skipped.) - -Version 1.5.1beta09 [January 24, 2011] - Enhanced pngvalid, corrected an error in gray_to_rgb, corrected doc error. - pngvalid contains tests of transforms, which tests are currently disabled - because they are incompletely tested. gray_to_rgb was failing to expand - the bit depth for smaller bit depth images; this seems to be a long - standing error and resulted, apparently, in invalid output - (CVE-2011-0408, CERT VU#643140). The documentation did not accurately - describe what libpng really does when converting RGB to gray. - -Version 1.5.1beta10 [January 27, 2010] - Fixed incorrect examples of callback prototypes in the manual, that were - introduced in libpng-1.0.0. - In addition the order of the png_get_uint macros with respect to the - relevant function definitions has been reversed. This helps the - preprocessing of the symbol files be more robust. Furthermore, the - symbol file preprocessing now uses -DPNG_NO_USE_READ_MACROS even when - the library may actually be built with PNG_USE_READ_MACROS; this stops - the read macros interfering with the symbol file format. - Made the manual, synopses, and function prototypes use the function - argument names file_gamma, int_file_gamma, and srgb_intent consistently. - -Version 1.5.1beta11 [January 28, 2011] - Changed PNG_UNUSED from "param=param;" to "{if(param){}}". - Corrected local variable type in new API png_process_data_skip() - The type was self-evidently incorrect but only causes problems on 64-bit - architectures. - Added transform tests to pngvalid and simplified the arguments. - -Version 1.5.1rc01 [January 29, 2011] - No changes. - -Version 1.5.1rc02 [January 31, 2011] - Added a request in the manual that applications do not use "png_" or - "PNG_" to begin any of their own symbols. - Changed PNG_UNUSED to "(void)param;" and updated the commentary in pngpriv.h - -Version 1.5.1 [February 3, 2011] - No changes. - -Version 1.5.2beta01 [February 13, 2011] - More -Wshadow fixes for older gcc compilers. Older gcc versions apparently - check formal parameters names in function declarations (as well as - definitions) to see if they match a name in the global namespace. - Revised PNG_EXPORTA macro to not use an empty parameter, to accommodate the - old VisualC++ preprocessor. - Turned on interlace handling in png_read_png(). - Fixed gcc pendantic warnings. - Handle longjmp in Cygwin. - Fixed png_get_current_row_number() in the interlaced case. - Cleaned up ALPHA flags and transformations. - Implemented expansion to 16 bits. - -Version 1.5.2beta02 [February 19, 2011] - Fixed mistake in the descriptions of user read_transform and write_transform - function prototypes in the manual. The row_info struct is png_row_infop. - Reverted png_get_current_row_number() to previous (1.5.2beta01) behavior. - Corrected png_get_current_row_number documentation - Fixed the read/write row callback documentation. - This documents the current behavior, where the callback is called after - every row with information pertaining to the next row. - -Version 1.5.2beta03 [March 3, 2011] - Fixed scripts/makefile.vcwin32 - Updated contrib/pngsuite/README to add the word "modify". - Define PNG_ALLOCATED to blank when _MSC_VER<1300. - -Version 1.5.2rc01 [March 19, 2011] - Define remaining attributes to blank when MSC_VER<1300. - ifdef out mask arrays in pngread.c when interlacing is not supported. - -Version 1.5.2rc02 [March 22, 2011] - Added a hint to try CPP=/bin/cpp if "cpp -E" fails in scripts/pnglibconf.mak - and in contrib/pngminim/*/makefile, eg., on SunOS 5.10, and removed "strip" - from the makefiles. - Fixed a bug (present since libpng-1.0.7) that makes png_handle_sPLT() fail - to compile when PNG_NO_POINTER_INDEXING is defined (Chubanov Kirill) - -Version 1.5.2rc03 [March 24, 2011] - Don't include standard header files in png.h while building the symbol table, - to avoid cpp failure on SunOS (introduced PNG_BUILDING_SYMBOL_TABLE macro). - -Version 1.5.2 [March 31, 2011] - No changes. - -Version 1.5.3beta01 [April 1, 2011] - Re-initialize the zlib compressor before compressing non-IDAT chunks. - Added API functions (png_set_text_compression_level() and four others) to - set parameters for zlib compression of non-IDAT chunks. - -Version 1.5.3beta02 [April 3, 2011] - Updated scripts/symbols.def with new API functions. - Only compile the new zlib re-initializing code when text or iCCP is - supported, using PNG_WRITE_COMPRESSED_TEXT_SUPPORTED macro. - Improved the optimization of the zlib CMF byte (see libpng-1.2.6beta03). - Optimize the zlib CMF byte in non-IDAT compressed chunks - -Version 1.5.3beta03 [April 16, 2011] - Fixed gcc -ansi -pedantic compile. A strict ANSI system does not have - snprintf, and the "__STRICT_ANSI__" detects that condition more reliably - than __STDC__ (John Bowler). - Removed the PNG_PTR_NORETURN attribute because it too dangerous. It tells - the compiler that a user supplied callback (the error handler) does not - return, yet there is no guarantee in practice that the application code - will correctly implement the error handler because the compiler only - issues a warning if there is a mistake (John Bowler). - Removed the no-longer-used PNG_DEPSTRUCT macro. - Updated the zlib version to 1.2.5 in the VStudio project. - Fixed 64-bit builds where png_uint_32 is smaller than png_size_t in - pngwutil.c (John Bowler). - Fixed bug with stripping the filler or alpha channel when writing, that - was introduced in libpng-1.5.2beta01 (bug report by Andrew Church). - -Version 1.5.3beta04 [April 27, 2011] - Updated pngtest.png with the new zlib CMF optimization. - Cleaned up conditional compilation code and of background/gamma handling - Internal changes only except a new option to avoid compiling the - png_build_grayscale_palette API (which is not used at all internally.) - The main change is to move the transform tests (READ_TRANSFORMS, - WRITE_TRANSFORMS) up one level to the caller of the APIs. This avoids - calls to spurious functions if all transforms are disabled and slightly - simplifies those functions. Pngvalid modified to handle this. - A minor change is to stop the strip_16 and expand_16 interfaces from - disabling each other; this allows the future alpha premultiplication - code to use 16-bit intermediate values while still producing 8-bit output. - png_do_background and png_do_gamma have been simplified to take a single - pointer to the png_struct rather than pointers to every item required - from the png_struct. This makes no practical difference to the internal - code. - A serious bug in the pngvalid internal routine 'standard_display_init' has - been fixed - this failed to initialize the red channel and accidentally - initialized the alpha channel twice. - Changed png_struct jmp_buf member name from png_jmpbuf to tmp_jmpbuf to - avoid a possible clash with the png_jmpbuf macro on some platforms. - -Version 1.5.3beta05 [May 6, 2011] - Added the "_POSIX_SOURCE" feature test macro to ensure libpng sees the - correct API. _POSIX_SOURCE is defined in pngpriv.h, pngtest.c and - pngvalid.c to ensure that POSIX conformant systems disable non-POSIX APIs. - Removed png_snprintf and added formatted warning messages. This change adds - internal APIs to allow png_warning messages to have parameters without - requiring the host OS to implement snprintf. As a side effect the - dependency of the tIME-supporting RFC1132 code on stdio is removed and - PNG_NO_WARNINGS does actually work now. - Pass "" instead of '\0' to png_default_error() in png_err(). This mistake - was introduced in libpng-1.2.20beta01. This fixes CVE-2011-2691. - Added PNG_WRITE_OPTIMIZE_CMF_SUPPORTED macro to make the zlib "CMF" byte - optimization configureable. - IDAT compression failed if preceded by a compressed text chunk (bug - introduced in libpng-1.5.3beta01-02). This was because the attempt to - reset the zlib stream in png_write_IDAT happened after the first IDAT - chunk had been deflated - much too late. In this change internal - functions were added to claim/release the z_stream and, hopefully, make - the code more robust. Also deflateEnd checking is added - previously - libpng would ignore an error at the end of the stream. - -Version 1.5.3beta06 [May 8, 2011] - Removed the -D_ALL_SOURCE from definitions for AIX in CMakeLists.txt - Implemented premultiplied alpha support: png_set_alpha_mode API - -Version 1.5.3beta07 [May 11, 2011] - Added expand_16 support to the high level interface. - Added named value and 'flag' gamma support to png_set_gamma. Made a minor - change from the previous (unreleased) ABI/API to hide the exact value used - for Macs - it's not a good idea to embed this in the ABI! - Moved macro definitions for PNG_HAVE_IHDR, PNG_HAVE_PLTE, and PNG_AFTER_IDAT - from pngpriv.h to png.h because they must be visible to applications - that call png_set_unknown_chunks(). - Check for up->location !PNG_AFTER_IDAT when writing unknown chunks - before IDAT. - -Version 1.5.3beta08 [May 16, 2011] - Improved "pngvalid --speed" to exclude more of pngvalid from the time. - Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt - The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative - parameters are supplied by the caller), while in the absence of cHRM - sRGB/Rec 709 values are still used. This introduced a divide-by-zero - bug in png_handle_cHRM(). - The bKGD chunk no longer overwrites the background value set by - png_set_background(), allowing the latter to be used before the file - header is read. It never performed any useful function to override - the default anyway. - Added memory overwrite and palette image checks to pngvalid.c - Previously palette image code was poorly checked. Since the transformation - code has a special palette path in most cases this was a severe weakness. - Minor cleanup and some extra checking in pngrutil.c and pngrtran.c. When - expanding an indexed image, always expand to RGBA if transparency is - present. - -Version 1.5.3beta09 [May 17, 2011] - Reversed earlier 1.5.3 change of transformation order; move png_expand_16 - back where it was. The change doesn't work because it requires 16-bit - gamma tables when the code only generates 8-bit ones. This fails - silently; the libpng code just doesn't do any gamma correction. Moving - the tests back leaves the old, inaccurate, 8-bit gamma calculations, but - these are clearly better than none! - -Version 1.5.3beta10 [May 20, 2011] - - png_set_background() and png_expand_16() did not work together correctly. - This problem is present in 1.5.2; if png_set_background is called with - need_expand false and the matching 16 bit color libpng erroneously just - treats it as an 8-bit color because of where png_do_expand_16 is in the - transform list. This simple fix reduces the supplied colour to 8-bits, - so it gets smashed, but this is better than the current behavior. - Added tests for expand16, more fixes for palette image tests to pngvalid. - Corrects the code for palette image tests and disables attempts to - validate palette colors. - -Version 1.5.3rc01 [June 3, 2011] - No changes. - -Version 1.5.3rc02 [June 8, 2011] - Fixed uninitialized memory read in png_format_buffer() (Bug report by - Frank Busse, CVE-2011-2501, related to CVE-2004-0421). - -Version 1.5.3beta11 [June 11, 2011] - Fixed png_handle_sCAL which is broken in 1.5. This fixes CVE 2011-2692. - Added sCAL to pngtest.png - Revised documentation about png_set_user_limits() to say that it also affects - png writing. - Revised handling of png_set_user_limits() so that it can increase the - limit beyond the PNG_USER_WIDTH|HEIGHT_MAX; previously it could only - reduce it. - Make the 16-to-8 scaling accurate. Dividing by 256 with no rounding is - wrong (high by one) 25% of the time. Dividing by 257 with rounding is - wrong in 128 out of 65536 cases. Getting the right answer all the time - without division is easy. - Added "_SUPPORTED" to the PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION macro. - Added projects/owatcom, an IDE project for OpenWatcom to replace - scripts/makefile.watcom. This project works with OpenWatcom 1.9. The - IDE autogenerates appropriate makefiles (libpng.mk) for batch processing. - The project is configurable, unlike the Visual Studio project, so long - as the developer has an awk. - Changed png_set_gAMA to limit the gamma value range so that the inverse - of the stored value cannot overflow the fixed point representation, - and changed other things OpenWatcom warns about. - Revised pngvalid.c to test PNG_ALPHA_MODE_SUPPORTED correctly. This allows - pngvalid to build when ALPHA_MODE is not supported, which is required if - it is to build on libpng 1.4. - Removed string/memory macros that are no longer used and are not - necessarily fully supportable, particularly png_strncpy and png_snprintf. - Added log option to pngvalid.c and attempted to improve gamma messages. - -Version 1.5.3 [omitted] - People found the presence of a beta release following an rc release - to be confusing; therefore we bump the version to libpng-1.5.4beta01 - and there will be no libpng-1.5.3 release. - -Version 1.5.4beta01 [June 14, 2011] - Made it possible to undefine PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED - to get the same (inaccurate) output as libpng-1.5.2 and earlier. - Moved definitions of PNG_HAVE_IHDR, PNG_AFTER_IDAT, and PNG_HAVE_PLTE - outside of an unknown-chunk block in png.h because they are also - needed for other uses. - -Version 1.5.4beta02 [June 14, 2011] - Fixed and clarified LEGACY 16-to-8 scaling code. - Added png_set_chop_16() API, to match inaccurate results from previous - libpng versions. - Removed the ACCURATE and LEGACY options (they are no longer useable) - Use the old scaling method for background if png_set_chop_16() was - called. - Made png_set_chop_16() API removeable by disabling PNG_CHOP_16_TO_8_SUPPORTED - -Version 1.5.4beta03 [June 15, 2011] - Fixed a problem in png_do_expand_palette() exposed by optimization in - 1.5.3beta06 - Also removed a spurious and confusing "trans" member ("trans") from png_info. - The palette expand optimization prevented expansion to an intermediate RGBA - form if tRNS was present but alpha was marked to be stripped; this exposed - a check for tRNS in png_do_expand_palette() which is inconsistent with the - code elsewhere in libpng. - Correction to the expand_16 code; removed extra instance of - png_set_scale_16_to_8 from pngpriv.h - -Version 1.5.4beta04 [June 16, 2011] - Added a missing "#ifdef PNG_READ_BACKGROUND_SUPPORTED/#endif" in pngrtran.c - Added PNG_TRANSFORM_CHOP_16 to the high-level read transforms. - Made PNG_READ_16_TO_8_ACCURATE_SCALE configurable again. If this is - not enabled, png_set_strip_16() and png_do_scale_16_to_8() aren't built. - Revised contrib/visupng, gregbook, and pngminim to demonstrate chop_16_to_8 - -Version 1.5.4beta05 [June 16, 2011] - Renamed png_set_strip_16() to png_set_scale_16() and renamed - png_set_chop_16() to png_set_strip(16) in an attempt to minimize the - behavior changes between libpng14 and libpng15. - -Version 1.5.4beta06 [June 18, 2011] - Fixed new bug that was causing both strip_16 and scale_16 to be applied. - -Version 1.5.4beta07 [June 19, 2011] - Fixed pngvalid, simplified macros, added checking for 0 in sCAL. - The ACCURATE scale macro is no longer defined in 1.5 - call the - png_scale_16_to_8 API. Made sure that PNG_READ_16_TO_8 is still defined - if the png_strip_16_to_8 API is present. png_check_fp_number now - maintains some state so that positive, negative and zero values are - identified. sCAL uses these to be strictly spec conformant. - -Version 1.5.4beta08 [June 23, 2011] - Fixed pngvalid if ACCURATE_SCALE is defined. - Updated scripts/pnglibconf.h.prebuilt. - -Version 1.5.4rc01 [June 30, 2011] - Define PNG_ALLOCATED to "restrict" only if MSC_VER >= 1400. - -Version 1.5.4 [July 7, 2011] - No changes. - -Version 1.5.5beta01 [July 13, 2011] - Fixed some typos and made other minor changes in the manual. - Updated contrib/pngminus/makefile.std (Samuli Souminen) - -Version 1.5.5beta02 [July 14, 2011] - Revised Makefile.am and Makefile.in to look in the right directory for - pnglibconf.h.prebuilt - -Version 1.5.5beta03 [July 27, 2011] - Enabled compilation with g++ compiler. This compiler does not recognize - the file extension, so it always compiles with C++ rules. Made minor - changes to pngrutil.c to cast results where C++ expects it but C does not. - Minor editing of libpng.3 and libpng-manual.txt. - -Version 1.5.5beta04 [July 29, 2011] - Revised CMakeLists.txt (Clifford Yapp) - Updated commentary about the png_rgb_to_gray() default coefficients - in the manual and in pngrtran.c - -Version 1.5.5beta05 [August 17, 2011] - Prevent unexpected API exports from non-libpng DLLs on Windows. The "_DLL" - is removed from the test of whether a DLL is being built (this erroneously - caused the libpng APIs to be marked as DLL exports in static builds under - Microsoft Visual Studio). Almost all of the libpng building configuration - is moved from pngconf.h to pngpriv.h, but PNG_DLL_EXPORT remains in - pngconf.h, though, so that it is colocated with the import definition (it - is no longer used anywhere in the installed headers). The VStudio project - definitions have been cleaned up: "_USRDLL" has been removed from the - static library builds (this was incorrect), and PNG_USE_DLL has been added - to pngvalid to test the functionality (pngtest does not supply it, - deliberately). The spurious "_EXPORTS" has been removed from the - libpng build (all these errors were a result of copy/paste between project - configurations.) - Added new types and internal functions for CIE RGB end point handling to - pngpriv.h (functions yet to be implemented). - -Version 1.5.5beta06 [August 26, 2011] - Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set in CMakeLists.txt - (Clifford Yap) - Fixes to rgb_to_gray and cHRM XYZ APIs (John Bowler): - The rgb_to_gray code had errors when combined with gamma correction. - Some pixels were treated as true grey when they weren't and such pixels - and true grey ones were not gamma corrected (the original value of the - red component was used instead). APIs to get and set cHRM using color - space end points have been added and the rgb_to_gray code that defaults - based on cHRM, and the divide-by-zero bug in png_handle_cHRM (CERT - VU#477046, CVE-2011-3328, introduced in 1.5.4) have been corrected. - A considerable number of tests has been added to pngvalid for the - rgb_to_gray transform. - Arithmetic errors in rgb_to_gray whereby the calculated gray value was - truncated to the bit depth rather than rounded have been fixed except in - the 8-bit non-gamma-corrected case (where consistency seems more important - than correctness.) The code still has considerable inaccuracies in the - 8-bit case because 8-bit linear arithmetic is used. - -Version 1.5.5beta07 [September 7, 2011] - Added "$(ARCH)" option to makefile.darwin - Added SunOS support to configure.ac and Makefile.am - Changed png_chunk_benign_error() to png_warning() in png.c, in - png_XYZ_from_xy_checked(). - -Version 1.5.5beta08 [September 10, 2011] - Fixed 64-bit compilation errors (gcc). The errors fixed relate - to conditions where types that are 32 bits in the GCC 32-bit - world (uLong and png_size_t) become 64 bits in the 64-bit - world. This produces potential truncation errors which the - compiler correctly flags. - Relocated new HAVE_SOLARIS_LD definition in configure.ac - Constant changes for 64-bit compatibility (removal of L suffixes). The - 16-bit cases still use "L" as we don't have a 16-bit test system. - -Version 1.5.5rc01 [September 15, 2011] - Removed "L" suffixes in pngpriv.h - -Version 1.5.5 [September 22, 2011] - No changes. - -Version 1.5.6beta01 [September 22, 2011] - Fixed some 64-bit type conversion warnings in pngrtran.c - Moved row_info from png_struct to a local variable. - The various interlace mask arrays have been made into arrays of - bytes and made PNG_CONST and static (previously some arrays were - marked PNG_CONST and some weren't). - Additional checks have been added to the transform code to validate the - pixel depths after the transforms on both read and write. - Removed some redundant code from pngwrite.c, in png_destroy_write_struct(). - Changed chunk reading/writing code to use png_uint_32 instead of png_byte[4]. - This removes the need to allocate temporary strings for chunk names on - the stack in the read/write code. Unknown chunk handling still uses the - string form because this is exposed in the API. - -Version 1.5.6beta02 [September 26, 2011] - Added a note in the manual the png_read_update_info() must be called only - once with a particular info_ptr. - Fixed a typo in the definition of the new PNG_STRING_FROM_CHUNK(s,c) macro. - -Version 1.5.6beta03 [September 28, 2011] - Revised test-pngtest.sh to report FAIL when pngtest fails. - Added "--strict" option to pngtest, to report FAIL when the failure is - only because the resulting valid files are different. - Revised CMakeLists.txt to work with mingw and removed some material from - CMakeLists.txt that is no longer useful in libpng-1.5. - -Version 1.5.6beta04 [October 5, 2011] - Fixed typo in Makefile.in and Makefile.am ("-M Wl" should be "-M -Wl")." - -Version 1.5.6beta05 [October 12, 2011] - Speed up png_combine_row() for interlaced images. This reduces the generality - of the code, allowing it to be optimized for Adam7 interlace. The masks - passed to png_combine_row() are now generated internally, avoiding - some code duplication and localizing the interlace handling somewhat. - Align png_struct::row_buf - previously it was always unaligned, caused by - a bug in the code that attempted to align it; the code needs to subtract - one from the pointer to take account of the filter byte prepended to - each row. - Optimized png_combine_row() when rows are aligned. This gains a small - percentage for 16-bit and 32-bit pixels in the typical case where the - output row buffers are appropriately aligned. The optimization was not - previously possible because the png_struct buffer was always misaligned. - Fixed bug in png_write_chunk_header() debug print, introduced in 1.5.6beta01. - -Version 1.5.6beta06 [October 17, 2011] - Removed two redundant tests for unitialized row. - Fixed a relatively harmless memory overwrite in compressed text writing - with a 1 byte zlib buffer. - Add ability to call png_read_update_info multiple times to pngvalid.c. - Fixes for multiple calls to png_read_update_info. These fixes attend to - most of the errors revealed in pngvalid, however doing the gamma work - twice results in inaccuracies that can't be easily fixed. There is now - a warning in the code if this is going to happen. - Turned on multiple png_read_update_info in pngvalid transform tests. - Prevent libpng from overwriting unused bits at the end of the image when - it is not byte aligned, while reading. Prior to libpng-1.5.6 libpng would - overwrite the partial byte at the end of each row if the row width was not - an exact multiple of 8 bits and the image is not interlaced. - -Version 1.5.6beta07 [October 21, 2011] - Made png_ptr->prev_row an aligned pointer into png_ptr->big_prev_row - (Mans Rullgard). - -Version 1.5.6rc01 [October 26, 2011] - Changed misleading "Missing PLTE before cHRM" warning to "Out of place cHRM" - -Version 1.5.6rc02 [October 27, 2011] - Added LSR() macro to defend against buggy compilers that evaluate non-taken - code branches and complain about out-of-range shifts. - -Version 1.5.6rc03 [October 28, 2011] - Renamed the LSR() macro to PNG_LSR() and added PNG_LSL() macro. - Fixed compiler warnings with Intel and MSYS compilers. The logical shift - fix for Microsoft Visual C is required by other compilers, so this - enables that fix for all compilers when using compile-time constants. - Under MSYS 'byte' is a name declared in a system header file, so we - changed the name of a local variable to avoid the warnings that result. - Added #define PNG_ALIGN_TYPE PNG_ALIGN_NONE to contrib/pngminim/*/pngusr.h - -Version 1.5.6 [November 3, 2011] - No changes. - -Version 1.5.7beta01 [November 4, 2011] - Added support for ARM processor, when decoding all PNG up-filtered rows - and any other-filtered rows with 3 or 4 bytes per pixel (Mans Rullgard). - Fixed bug in pngvalid on early allocation failure; fixed type cast in - pngmem.c; pngvalid would attempt to call png_error() if the allocation - of a png_struct or png_info failed. This would probably have led to a - crash. The pngmem.c implementation of png_malloc() included a cast - to png_size_t which would fail on large allocations on 16-bit systems. - Fix for the preprocessor of the Intel C compiler. The preprocessor - splits adjacent @ signs with a space; this changes the concatentation - token from @-@-@ to PNG_JOIN; that should work with all compiler - preprocessors. - Paeth filter speed improvements from work by Siarhei Siamashka. This - changes the 'Paeth' reconstruction function to improve the GCC code - generation on x86. The changes are only part of the suggested ones; - just the changes that definitely improve speed and remain simple. - The changes also slightly increase the clarity of the code. - -Version 1.5.7beta02 [November 11, 2011] - Check compression_type parameter in png_get_iCCP and remove spurious - casts. The compression_type parameter is always assigned to, so must - be non-NULL. The cast of the profile length potentially truncated the - value unnecessarily on a 16-bit int system, so the cast of the (byte) - compression type to (int) is specified by ANSI-C anyway. - Fixed FP division by zero in pngvalid.c; the 'test_pixel' code left - the sBIT fields in the test pixel as 0, which resulted in a floating - point division by zero which was irrelevant but causes systems where - FP exceptions cause a crash. Added code to pngvalid to turn on FP - exceptions if the appropriate glibc support is there to ensure this is - tested in the future. - Updated scripts/pnglibconf.mak and scripts/makefile.std to handle the - new PNG_JOIN macro. - Added versioning to pnglibconf.h comments. - Simplified read/write API initial version; basic read/write tested on - a variety of images, limited documentation (in the header file.) - Installed more accurate linear to sRGB conversion tables. The slightly - modified tables reduce the number of 16-bit values that - convert to an off-by-one 8-bit value. The "makesRGB.c" code that was used - to generate the tables is now in a contrib/sRGBtables sub-directory. - -Version 1.5.7beta03 [November 17, 2011] - Removed PNG_CONST from the sRGB table declarations in pngpriv.h and png.c - Added run-time detection of NEON support. - Added contrib/libtests; includes simplified API test and timing test and - a color conversion utility for rapid checking of failed 'pngstest' results. - Multiple transform bug fixes plus a work-round for double gamma correction. - libpng does not support more than one transform that requires linear data - at once - if this is tried typically the results is double gamma - correction. Since the simplified APIs can need rgb to gray combined with - a compose operation it is necessary to do one of these outside the main - libpng transform code. This check-in also contains fixes to various bugs - in the simplified APIs themselves and to some bugs in compose and rgb to - gray (on palette) itself. - Fixes for C++ compilation using g++ When libpng source is compiled - using g++. The compiler imposes C++ rules on the C source; thus it - is desireable to make the source work with either C or C++ rules - without throwing away useful error information. This change adds - png_voidcast to allow C semantic (void*) cases or the corresponding - C++ static_cast operation, as appropriate. - Added --noexecstack to assembler file compilation. GCC does not set - this on assembler compilation, even though it does on C compilation. - This creates security issues if assembler code is enabled; the - work-around is to set it by default in the flags for $(CCAS) - Work around compilers that don't support declaration of const data. Some - compilers fault 'extern const' data declarations (because the data is - not initialized); this turns on const-ness only for compilers where - this is known to work. - -Version 1.5.7beta04 [November 17, 2011] - Since the gcc driver does not recognize the --noexecstack flag, we must - use the -Wa prefix to have it passed through to the assembler. - Also removed a duplicate setting of this flag. - Added files that were omitted from the libpng-1.5.7beta03 zip distribution. - -Version 1.5.7beta05 [November 25, 2011] - Removed "zTXt" from warning in generic chunk decompression function. - Validate time settings passed to pngset() and png_convert_to_rfc1123() - (Frank Busse). - Added MINGW support to CMakeLists.txt - Reject invalid compression flag or method when reading the iTXt chunk. - Backed out 'simplified' API changes. The API seems too complex and there - is a lack of consensus or enthusiasm for the proposals. The API also - reveals significant bugs inside libpng (double gamma correction and the - known bug of being unable to retrieve a corrected palette). It seems - better to wait until the bugs, at least, are corrected. - Moved pngvalid.c into contrib/libtests - Rebuilt Makefile.in, configure, etc., with autoconf-2.68 - -Version 1.5.7rc01 [December 1, 2011] - Replaced an "#if" with "#ifdef" in pngrtran.c - Revised #if PNG_DO_BC block in png.c (use #ifdef and add #else) - -Version 1.5.7rc02 [December 5, 2011] - Revised project files and contrib/pngvalid/pngvalid.c to account for - the relocation of pngvalid into contrib/libtests. - Revised pngconf.h to use " __declspec(restrict)" only when MSC_VER >= 1400, - as in libpng-1.5.4. - Put CRLF line endings in the owatcom project files. - -Version 1.5.7rc03 [December 7, 2011] - Updated CMakeLists.txt to account for the relocation of pngvalid.c - -Version 1.5.7 [December 15, 2011] - Minor fixes to pngvalid.c for gcc 4.6.2 compatibility to remove warnings - reported by earlier versions. - Fixed minor memset/sizeof errors in pngvalid.c. - -Version 1.6.0beta01 [December 15, 2011] - Removed machine-generated configure files from the GIT repository (they will - continue to appear in the tarball distributions and in the libpng15 and - earlier GIT branches). - Restored the new 'simplified' API, which was started in libpng-1.5.7beta02 - but later deleted from libpng-1.5.7beta05. - Added example programs for the new 'simplified' API. - Added ANSI-C (C90) headers and require them, and take advantage of the - change. Also fixed some of the projects/* and contrib/* files that needed - updates for libpng16 and the move of pngvalid.c. - With this change the required ANSI-C header files are assumed to exist: the - implementation must provide float.h, limits.h, stdarg.h and stddef.h and - libpng relies on limits.h and stddef.h existing and behaving as defined - (the other two required headers aren't used). Non-ANSI systems that don't - have stddef.h or limits.h will have to provide an appropriate fake - containing the relevant types and #defines. - The use of FAR/far has been eliminated and the definition of png_alloc_size_t - is now controlled by a flag so that 'small size_t' systems can select it - if necessary. Libpng 1.6 may not currently work on such systems -- it - seems likely that it will ask 'malloc' for more than 65535 bytes with any - image that has a sufficiently large row size (rather than simply failing - to read such images). - New tools directory containing tools used to generate libpng code. - Fixed race conditions in parallel make builds. With higher degrees of - parallelism during 'make' the use of the same temporary file names such - as 'dfn*' can result in a race where a temporary file from one arm of the - build is deleted or overwritten in another arm. This changes the - temporary files for suffix rules to always use $* and ensures that the - non-suffix rules use unique file names. - -Version 1.6.0beta02 [December 21, 2011] - Correct configure builds where build and source directories are separate. - The include path of 'config.h' was erroneously made relative in pngvalid.c - in libpng 1.5.7. - -Version 1.6.0beta03 [December 22, 2011] - Start-up code size improvements, error handler flexibility. These changes - alter how the tricky allocation of the initial png_struct and png_info - structures are handled. png_info is now handled in pretty much the same - way as everything else, except that the allocations handle NULL return - silently. png_struct is changed in a similar way on allocation and on - deallocation a 'safety' error handler is put in place (which should never - be required). The error handler itself is changed to permit mismatches - in the application and libpng error buffer size; however, this means a - silent change to the API to return the jmp_buf if the size doesn't match - the size from the libpng compilation; libpng now allocates the memory and - this may fail. Overall these changes result in slight code size - reductions; however, this is a reduction in code that is always executed - so is particularly valuable. Overall on a 64-bit system the libpng DLL - decreases in code size by 1733 bytes. pngerror.o increases in size by - about 465 bytes because of the new functionality. - Added png_convert_to_rfc1123_buffer() and deprecated png_convert_to_rfc1123() - to avoid including a spurious buffer in the png_struct. - -Version 1.6.0beta04 [December 30, 2011] - Regenerated configure scripts with automake-1.11.2 - Eliminated png_info_destroy(). It is now used only in png.c and only calls - one other internal function and memset(). - Enabled png_get_sCAL_fixed() if floating point APIs are enabled. Previously - it was disabled whenever internal fixed point arithmetic was selected, - which meant it didn't exist even on systems where FP was available but not - preferred. - Added pngvalid.c compile time checks for const APIs. - Implemented 'restrict' for png_info and png_struct. Because of the way - libpng works both png_info and png_struct are always accessed via a - single pointer. This means adding C99 'restrict' to the pointer gives - the compiler some opportunity to optimize the code. This change allows - that. - Moved AC_MSG_CHECKING([if libraries can be versioned]) later to the proper - location in configure.ac (Gilles Espinasse). - Changed png_memcpy to C assignment where appropriate. Changed all those - uses of png_memcpy that were doing a simple assignment to assignments - (all those cases where the thing being copied is a non-array C L-value). - Added some error checking to png_set_*() routines. - Removed the reference to the non-exported function png_memcpy() from - example.c. - Fixed the Visual C 64-bit build - it requires jmp_buf to be aligned, but - it had become misaligned. - Revised contrib/pngminus/pnm2png.c to avoid warnings when png_uint_32 - and unsigned long are of different sizes. - -Version 1.6.0beta05 [January 15, 2012] - Updated manual with description of the simplified API (copied from png.h) - Fix bug in pngerror.c: some long warnings were being improperly truncated - (CVE-2011-3464, bug introduced in libpng-1.5.3beta05). - -Version 1.6.0beta06 [January 24, 2012] - Added palette support to the simplified APIs. This commit - changes some of the macro definitions in png.h, app code - may need corresponding changes. - Increased the formatted warning buffer to 192 bytes. - Added color-map support to simplified API. This is an initial version for - review; the documentation has not yet been updated. - Fixed Min/GW uninstall to remove libpng.dll.a - -Version 1.6.0beta07 [January 28, 2012] - Eliminated Intel icc/icl compiler warnings. The Intel (GCC derived) - compiler issues slightly different warnings from those issued by the - current vesions of GCC. This eliminates those warnings by - adding/removing casts and small code rewrites. - Updated configure.ac from autoupdate: added --enable-werror option. - Also some layout regularization and removal of introduced tab characters - (replaced with 3-character indentation). Obsolete macros identified by - autoupdate have been removed; the replacements are all in 2.59 so - the pre-req hasn't been changed. --enable-werror checks for support - for -Werror (or the given argument) in the compiler. This mimics the - gcc configure option by allowing -Werror to be turned on safely; without - the option the tests written in configure itself fail compilation because - they cause compiler warnings. - Rewrote autogen.sh to run autoreconf instead of running tools one-by-one. - Conditionalize the install rules for MINGW and CYGWIN in CMakeLists.txt and - set CMAKE_LIBRARY_OUTPUT_DIRECTORY to "lib" on all platforms (C. Yapp). - Freeze libtool files in the 'scripts' directory. This version of autogen.sh - attempts to dissuade people from running it when it is not, or should not, - be necessary. In fact, autogen.sh does not work when run in a libpng - directory extracted from a tar distribution anymore. You must run it in - a GIT clone instead. - Added two images to contrib/pngsuite (1-bit and 2-bit transparent grayscale), - and renamed three whose names were inconsistent with those in - pngsuite/README.txt. - -Version 1.6.0beta08 [February 1, 2012] - Fixed Image::colormap misalignment in pngstest.c - Check libtool/libtoolize version number (2.4.2) in configure.ac - Divide test-pngstest.sh into separate pngstest runs for basic and - transparent images. - Moved automake options to AM_INIT_AUTOMAKE in configure.ac - Added color-tests, silent-rules (Not yet implemented in Makefile.am) and - version checking to configure.ac - Improved pngstest speed by not doing redundant tests and add const to - the background parameter of png_image_finish_read. The --background - option is now done automagically only when required, so that commandline - option no longer exists. - Cleaned up pngpriv.h to consistently declare all functions and data. - Also eliminated PNG_CONST_DATA, which is apparently not needed but we - can't be sure until it is gone. - Added symbol prefixing that allows all the libpng external symbols - to be prefixed (suggested by Reuben Hawkins). - Updated "ftbb*.png" list in the owatcom and vstudio projects. - Fixed 'prefix' builds on clean systems. The generation of pngprefix.h - should not require itself. - Updated INSTALL to explain that autogen.sh must be run in a GIT clone, - not in a libpng directory extracted from a tar distribution. - -Version 1.6.0beta09 [February 1, 2012] - Reverted the prebuilt configure files to libpng-1.6.0beta05 condition. - -Version 1.6.0beta10 [February 3, 2012] - Added Z_SOLO for zlib-1.2.6+ and correct pngstest tests - Updated list of test images in CMakeLists.txt - Updated the prebuilt configure files to current condition. - Revised INSTALL information about autogen.sh; it works in tar distributions. - -Version 1.6.0beta11 [February 16, 2012] - Fix character count in pngstest command in projects/owatcom/pngstest.tgt - Revised test-pngstest.sh to report PASS/FAIL for each image. - Updated documentation about the simplified API. - Corrected estimate of error in libpng png_set_rgb_to_gray API. The API is - extremely inaccurate for sRGB conversions because it uses an 8-bit - intermediate linear value and it does not use the sRGB transform, so it - suffers from the known instability in gamma transforms for values close - to 0 (see Poynton). The net result is that the calculation has a maximum - error of 14.99/255; 0.5/255^(1/2.2). pngstest now uses 15 for the - permitted 8-bit error. This may still not be enough because of arithmetic - error. - Removed some unused arrays (with #ifdef) from png_read_push_finish_row(). - Fixed a memory overwrite bug in simplified read of RGB PNG with - non-linear gamma Also bugs in the error checking in pngread.c and changed - quite a lot of the checks in pngstest.c to be correct; either correctly - written or not over-optimistic. The pngstest changes are insufficient to - allow all possible RGB transforms to be passed; pngstest cmppixel needs - to be rewritten to make it clearer which errors it allows and then changed - to permit known inaccuracies. - Removed tests for no-longer-used *_EMPTY_PLTE_SUPPORTED from pngstruct.h - Fixed fixed/float API export conditionals. 1) If FIXED_POINT or - FLOATING_POINT options were switched off, png.h ended up with lone ';' - characters. This is not valid ANSI-C outside a function. The ';' - characters have been moved inside the definition of PNG_FP_EXPORT and - PNG_FIXED_EXPORT. 2) If either option was switched off, the declaration - of the corresponding functions were completely omitted, even though some - of them are still used internally. The result is still valid, but - produces warnings from gcc with some warning options (including -Wall). The - fix is to cause png.h to declare the functions with PNG_INTERNAL_FUNCTION - when png.h is included from pngpriv.h. - Check for invalid palette index while reading paletted PNG. When one is - found, issue a warning and increase png_ptr->num_palette accordingly. - Apps are responsible for checking to see if that happened. - -Version 1.6.0beta12 [February 18, 2012] - Do not increase num_palette on invalid_index. - Relocated check for invalid palette index to pngrtran.c, after unpacking - the sub-8-bit pixels. - Fixed CVE-2011-3026 buffer overrun bug. This bug was introduced when - iCCP chunk support was added at libpng-1.0.6. Deal more correctly with the - test on iCCP chunk length. Also removed spurious casts that may hide - problems on 16-bit systems. - -Version 1.6.0beta13 [February 24, 2012] - Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from - pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; - now that png_ptr->buffer is inaccessible to applications, the special - handling is no longer useful. - Added PNG_SAFE_LIMITS feature to pnglibconf.dfa, pngpriv.h, and new - pngusr.dfa to reset the user limits to safe ones if PNG_SAFE_LIMITS is - defined. To enable, use "CPPFLAGS=-DPNG_SAFE_LIMITS_SUPPORTED=1" on the - configure command or put #define PNG_SAFE_LIMITS_SUPPORTED in - pnglibconf.h.prebuilt and pnglibconf.h. - -Version 1.6.0beta14 [February 27, 2012] - Added information about the new limits in the manual. - Updated Makefile.in - -Version 1.6.0beta15 [March 2, 2012] - Removed unused "current_text" members of png_struct and the png_free() - of png_ptr->current_text from pngread.c - Rewrote pngstest.c for substantial speed improvement. - Fixed transparent pixel and 16-bit rgb tests in pngstest and removed a - spurious check in pngwrite.c - Added PNG_IMAGE_FLAG_FAST for the benefit of applications that store - intermediate files, or intermediate in-memory data, while processing - image data with the simplified API. The option makes the files larger - but faster to write and read. pngstest now uses this by default; this - can be disabled with the --slow option. - Improved pngstest fine tuning of error numbers, new test file generator. - The generator generates images that test the full range of sample values, - allow the error numbers in pngstest to be tuned and checked. makepng - also allows generation of images with extra chunks, although this is - still work-in-progress. - Added check for invalid palette index while reading. - Fixed some bugs in ICC profile writing. The code should now accept - all potentially valid ICC profiles and reject obviously invalid ones. - It now uses png_error() to do so rather than casually writing a PNG - without the necessary color data. - Removed whitespace from the end of lines in all source files and scripts. - -Version 1.6.0beta16 [March 6, 2012] - Relocated palette-index checking function from pngrutil.c to pngtrans.c - Added palette-index checking while writing. - Changed png_inflate() and calling routines to avoid overflow problems. - This is an intermediate check-in that solves the immediate problems and - introduces one performance improvement (avoiding a copy via png_ptr->zbuf.) - Further changes will be made to make ICC profile handling more secure. - Fixed build warnings (MSVC, GCC, GCC v3). Cygwin GCC with default options - declares 'index' as a global, causing a warning if it is used as a local - variable. GCC 64-bit warns about assigning a (size_t) (unsigned 64-bit) - to an (int) (signed 32-bit). MSVC, however, warns about using the - unary '-' operator on an unsigned value (even though it is well defined - by ANSI-C to be ~x+1). The padding calculation was changed to use a - different method. Removed the tests on png_ptr->pass. - Added contrib/libtests/tarith.c to test internal arithmetic functions from - png.c. This is a libpng maintainer program used to validate changes to the - internal arithmetic functions. - Made read 'inflate' handling like write 'deflate' handling. The read - code now claims and releases png_ptr->zstream, like the write code. - The bug whereby the progressive reader failed to release the zstream - is now fixed, all initialization is delayed, and the code checks for - changed parameters on deflate rather than always calling - deflatedEnd/deflateInit. - Validate the zTXt strings in pngvalid. - Added code to validate the windowBits value passed to deflateInit2(). - If the call to deflateInit2() is wrong a png_warning will be issued - (in fact this is harmless, but the PNG data produced may be sub-optimal). - -Version 1.6.0beta17 [March 10, 2012] - Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. - Reject all iCCP chunks after the first, even if the first one is invalid. - Deflate/inflate was reworked to move common zlib calls into single - functions [rw]util.c. A new shared keyword check routine was also added - and the 'zbuf' is no longer allocated on progressive read. It is now - possible to call png_inflate() incrementally. A warning is no longer - issued if the language tag or translated keyword in the iTXt chunk - has zero length. - If benign errors are disabled use maximum window on ancilliary inflate. - This works round a bug introduced in 1.5.4 where compressed ancillary - chunks could end up with a too-small windowBits value in the deflate - header. - -Version 1.6.0beta18 [March 16, 2012] - Issue a png_benign_error() instead of png_warning() about bad palette index. - In pngtest, treat benign errors as errors if "-strict" is present. - Fixed an off-by-one error in the palette index checking function. - Fixed a compiler warning under Cygwin (Windows-7, 32-bit system) - Revised example.c to put text strings in a temporary character array - instead of directly assigning string constants to png_textp members. - This avoids compiler warnings when -Wwrite-strings is enabled. - Added output flushing to aid debugging under Visual Studio. Unfortunately - this is necessary because the VS2010 output window otherwise simply loses - the error messages on error (they weren't flushed to the window before - the process exited, apparently!) - Added configuration support for benign errors and changed the read - default. Also changed some warnings in the iCCP and sRGB handling - from to benign errors. Configuration now makes read benign - errors warnings and write benign errors to errors by default (thus - changing the behavior on read). The simplified API always forces - read benign errors to warnings (regardless of the system default, unless - this is disabled in which case the simplified API can't be built.) - -Version 1.6.0beta19 [March 18, 2012] - Work around for duplicate row start calls; added warning messages. - This turns on PNG_FLAG_DETECT_UNINITIALIZED to detect app code that - fails to call one of the 'start' routines (not enabled in libpng-1.5 - because it is technically an API change, since it did normally work - before.) It also makes duplicate calls to png_read_start_row (an - internal function called at the start of the image read) benign, as - they were before changes to use png_inflate_claim. Somehow webkit is - causing this to happen; this is probably a mis-feature in the zlib - changes so this commit is only a work-round. - Removed erroneous setting of DETECT_UNINITIALIZED and added more - checks. The code now does a png_error if an attempt is made to do the - row initialization twice; this is an application error and it has - serious consequences because the transform data in png_struct is - changed by each call. - Added application error reporting and added chunk names to read - benign errors; also added --strict to pngstest - not enabled - yet because a warning is produced. - Avoid the double gamma correction warning in the simplified API. - This allows the --strict option to pass in the pngstest checks - -Version 1.6.0beta20 [March 29, 2012] - Changed chunk handler warnings into benign errors, incrementally load iCCP - Added checksum-icc.c to contrib/tools - Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. - Recognize known sRGB ICC profiles while reading; prefer writing the - iCCP profile over writing the sRGB chunk, controlled by the - PNG_sRGB_PROFILE_CHECKS option. - Revised png_set_text_2() to avoid potential memory corruption (fixes - CVE-2011-3048, also known as CVE-2012-3425). - -Version 1.6.0beta21 [April 27, 2012] - Revised scripts/makefile.darwin: use system zlib; remove quotes around - architecture list; add missing ppc architecture; add architecture options - to shared library link; don't try to create a shared lib based on missing - RELEASE variable. - Enable png_set_check_for_invalid_index() for both read and write. - Removed #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED in pngpriv.h around - declaration of png_handle_unknown(). - Added -lssp_nonshared in a comment in scripts/makefile.freebsd - and changed deprecated NOOBJ and NOPROFILE to NO_OBJ and NO_PROFILE. - -Version 1.6.0beta22 [May 23, 2012] - Removed need for -Wno-cast-align with clang. clang correctly warns on - alignment increasing pointer casts when -Wcast-align is passed. This - fixes the cases that clang warns about either by eliminating the - casts from png_bytep to png_uint_16p (pngread.c), or, for pngrutil.c - where the cast is previously verified or pngstest.c where it is OK, by - introducing new png_aligncast macros to do the cast in a way that clang - accepts. - -Version 1.6.0beta23 [June 6, 2012] - Revised CMakeLists.txt to not attempt to make a symlink under mingw. - Made fixes for new optimization warnings from gcc 4.7.0. The compiler - performs an optimization which is safe; however it then warns about it. - Changing the type of 'palette_number' in pngvalid.c removes the warning. - Do not depend upon a GCC feature macro being available for use in generating - the linker mapfile symbol prefix. - Improved performance of new do_check_palette_indexes() function (only - update the value when it actually increases, move test for whether - the check is wanted out of the function. - -Version 1.6.0beta24 [June 7, 2012] - Don't check palette indexes if num_palette is 0 (as it can be in MNG files). - -Version 1.6.0beta25 [June 16, 2012] - Revised png_set_keep_unknown_chunks() so num_chunks < 0 means ignore all - unknown chunks and all known chunks except for IHDR, PLTE, tRNS, IDAT, - and IEND. Previously it only meant ignore all unknown chunks, the - same as num_chunks == 0. Revised png_image_skip_unused_chunks() to - provide a list of chunks to be processed instead of a list of chunks to - ignore. Revised contrib/gregbook/readpng2.c accordingly. - -Version 1.6.0beta26 [July 10, 2012] - Removed scripts/makefile.cegcc from the *.zip and *.7z distributions; it - depends on configure, which is not included in those archives. - Moved scripts/chkfmt to contrib/tools. - Changed "a+w" to "u+w" in Makefile.in to fix CVE-2012-3386. - -Version 1.6.0beta27 [August 11, 2012] - Do not compile PNG_DEPRECATED, PNG_ALLOC and PNG_PRIVATE when __GNUC__ < 3. - Do not use __restrict when GNUC is <= 3.1 - Removed references to png_zalloc() and png_zfree() from the manual. - Fixed configurations where floating point is completely disabled. Because - of the changes to support symbol prefixing PNG_INTERNAL_FUNCTION declares - floating point APIs during libpng builds even if they are completely - disabled. This requires the png floating point types (png_double*) to be - declared even though the functions are never actually defined. This - change provides a dummy definition so that the declarations work, yet any - implementation will fail to compile because of an incomplete type. - Re-eliminated the use of strcpy() in pngtest.c. An unncessary use of - strcpy() was accidentally re-introduced in libpng16; this change replaces - it with strncpy(). - Eliminated use of png_sizeof(); use sizeof() instead. - Use a consistent style for (sizeof type) and (sizeof (array)) - Cleanup of png_set_filler(). This function does very different things on - read and write. In libpng 1.6 the two cases can be distinguished and - considerable code cleanup, and extra error checking, is possible. This - makes calls on the write side that have no effect be ignored with a - png_app_error(), which can be disabled in the app using - png_set_benign_errors(), and removes the spurious use of usr_channels - on the read side. - Insist on autotools 1.12.1 for git builds because there are security issues - with 1.12 and insisting on anything less would allow 1.12 to be used. - Removed info_ptr->signature[8] from WRITE-only builds. - Add some conditions for compiling png_fixed(). This is a small function - but it requires "-lm" on some platforms. - Cause pngtest --strict to fail on any warning from libpng (not just errors) - and cause it not to fail at the comparison step if libpng lacks support - for writing chunks that it reads from the input (currently only implemented - for compressed text chunks). - Make all three "make check" test programs work without READ or WRITE support. - Now "make check" will succeed even if libpng is compiled with -DPNG_NO_READ - or -DPNG_NO_WRITE. The tests performed are reduced, but the basic reading - and writing of a PNG file is always tested by one or more of the tests. - Consistently use strlen(), memset(), memcpy(), and memcmp() instead of the - png_strlen(), png_memset(), png_memcpy(), and png_memcmp() macros. - Removed the png_sizeof(), png_strlen(), png_memset(), png_memcpy(), and - png_memcmp() macros. - Work around gcc 3.x and Microsoft Visual Studio 2010 complaints. Both object - to the split initialization of num_chunks. - -Version 1.6.0beta28 [August 29, 2012] - Unknown handling fixes and clean up. This adds more correct option - control of the unknown handling, corrects the pre-existing bug where - the per-chunk 'keep' setting is ignored and makes it possible to skip - IDAT chunks in the sequential reader (broken in earlier 1.6 versions). - There is a new test program, test-unknown.c, which is a work in progress - (not currently part of the test suite). Comments in the header files now - explain how the unknown handling works. - Allow fine grain control of unknown chunk APIs. This change allows - png_set_keep_unknown_chunks() to be turned off if not required and causes - both read and write to behave appropriately (on read this is only possible - if the user callback is used to handle unknown chunks). The change - also removes the support for storing unknown chunks in the info_struct - if the only unknown handling enabled is via the callback, allowing libpng - to be configured with callback reading and none of the unnecessary code. - Corrected fix for unknown handling in pngtest. This reinstates the - libpng handling of unknown chunks other than vpAg and sTER (including - unsafe-to-copy chunks which were dropped before) and eliminates the - repositioning of vpAg and sTER in pngtest.png by changing pngtest.png - (so the chunks are where libpng would put them). - Added "tunknown" test and corrected a logic error in png_handle_unknown() - when SAVE support is absent. Moved the shell test scripts for - contrib/libtests from the libpng top directory to contrib/libtests. - png_handle_unknown() must always read or skip the chunk, if - SAVE_UNKNOWN_CHUNKS is turned off *and* the application does not set - a user callback an unknown chunk will not be read, leading to a read - error, which was revealed by the "tunknown" test. - Cleaned up and corrected ICC profile handling. - contrib/libtests/makepng: corrected 'rgb' and 'gray' cases. profile_error - messages could be truncated; made a correct buffer size calculation and - adjusted pngerror.c appropriately. png_icc_check_* checking improved; - changed the functions to receive the correct color type of the PNG on read - or write and check that it matches the color space of the profile (despite - what the comments said before, there is danger in assuming the app will - cope correctly with an RGB profile on a grayscale image and, since it - violates the PNG spec, allowing it is certain to produce inconsistent - app behavior and might even cause app crashes.) Check that profiles - contain the tags needed to process the PNG (tags all required by the ICC - spec). Removed unused PNG_STATIC from pngpriv.h. - -Version 1.6.0beta29 [September 4, 2012] - Fixed the simplified API example programs to add the *colormap parameter - to several of he API and improved the error message if the version field - is not set. - Added contrib/examples/* to the *.zip and *.7z distributions. - Updated simplified API synopses and description of the png_image structure - in the manual. - Made makepng and pngtest produce identical PNGs, add "--relaxed" option - to pngtest. The "--relaxed" option turns off the benign errors that are - enabled by default in pre-RC builds. makepng can now write ICC profiles - where the length has not been extended to a multiple of 4, and pngtest - now intercepts all libpng errors, allowing the previously-introduced - "--strict test" on no warnings to actually work. - Improved ICC profile handling including cHRM chunk generation and fixed - Cygwin+MSVC build errors. The ICC profile handling now includes more - checking. Several errors that caused rejection of the profile are now - handled with a warning in such a way that the invalid profiles will be - read by default in release (but not pre-RC) builds but will not be - written by default. The easy part of handling the cHRM chunk is written, - where the ICC profile contains the required data. The more difficult - part plus guessing a gAMA value requires code to pass selected RGB values - through the profile. - -Version 1.6.0beta30 [October 24, 2012] - Changed ICC profile matrix/vector types to not depend on array type rules. - By the ANSI-C standard the new types should be identical to the previous - versions, and all known versions of gcc tested with the previous versions - except for GCC-4.2.1 work with this version. The change makes the ANSI-C - rule that const applied to an array of elements applies instead to the - elements in the array moot by explicitly applying const to the base - elements of the png_icc_matrix and png_icc_vector types. The accidental - (harmless) 'const' previously applied to the parameters of two of the - functions have also been removed. - Added a work around for GCC 4.2 optimization bug. - Marked the broken (bad white point) original HP sRGB profiles correctly and - correct comments. - Added -DZ_SOLO to contrib/pngminim/*/makefile to work with zlib-1.2.7 - Use /MDd for vstudio debug builds. Also added pngunkown to the vstudio - builds, fixed build errors and corrected a minor exit code error in - pngvalid if the 'touch' file name is invalid. - Add updated WARNING file to projects/vstudio from libpng 1.5/vstudio - Fixed build when using #define PNG_NO_READ_GAMMA in png_do_compose() in - pngrtran.c (Domani Hannes). - -Version 1.6.0beta31 [November 1, 2012] - Undid the erroneous change to vstudio/pngvalid build in libpng-1.6.0beta30. - Made pngvalid so that it will build outside the libpng source tree. - Made builds -DPNG_NO_READ_GAMMA compile (the unit tests still fail). - Made PNG_NO_READ_GAMMA switch off interfaces that depend on READ_GAMMA. - Prior to 1.6.0 switching off READ_GAMMA did unpredictable things to the - interfaces that use it (specifically, png_do_background in 1.4 would - simply display composite for grayscale images but do composition - with the incorrect arithmetic for color ones). In 1.6 the semantic - of -DPNG_NO_READ_GAMMA is changed to simply disable any interface that - depends on it; this obliges people who set it to consider whether they - really want it off if they happen to use any of the interfaces in - question (typically most users who disable it won't). - Fixed GUIDs in projects/vstudio. Some were duplicated or missing, - resulting in VS2010 having to update the files. - Removed non-working ICC profile support code that was mostly added to - libpng-1.6.0beta29 and beta30. There was too much code for too little - gain; implementing full ICC color correction may be desireable but is left - up to applications. - -Version 1.6.0beta32 [November 25, 2012] - Fixed an intermittent SEGV in pngstest due to an uninitialized array element. - Added the ability for contrib/libtests/makepng.c to make a PNG with just one - color. This is useful for debugging pngstest color inaccuracy reports. - Fixed error checking in the simplified write API (Olaf van der Spek) - Made png_user_version_check() ok to use with libpng version 1.10.x and later. - -Version 1.6.0beta33 [December 15, 2012] - Fixed typo in png.c (PNG_SET_CHUNK_MALLOC_MAX should be PNG_CHUNK_MALLOC_MAX) - that causes the MALLOC_MAX limit not to work (John Bowler) - Change png_warning() to png_app_error() in pngwrite.c and comment the - fall-through condition. - Change png_warning() to png_app_warning() in png_write_tRNS(). - Rearranged the ARM-NEON optimizations: Isolated the machine specific code - to the hardware subdirectory and added comments to pngrutil.c so that - implementors of other optimizations know what to do. - Fixed cases of unquoted DESTDIR in Makefile.am - Rebuilt Makefile.in, etc., with autoconf-2.69 and automake-1.12.5. - -Version 1.6.0beta34 [December 19, 2012] - Cleaned up whitespace in the synopsis portion of the manpage "libpng.3" - Disassembled the version number in scripts/options.awk (necessary for - building on SunOs). - -Version 1.6.0beta35 [December 23, 2012] - Made default Zlib compression settings be configurable. This adds #defines to - pnglibconf.h to control the defaults. - Fixed Windows build issues, enabled ARM compilation. Various warnings issued - by earlier versions of GCC fixed for Cygwin and Min/GW (which both use old - GCCs.) ARM support is enabled by default in zlib.props (unsupported by - Microsoft) and ARM compilation is made possible by deleting the check for - x86. The test programs cannot be run because they are not signed. - -Version 1.6.0beta36 [January 2, 2013] - Discontinued distributing libpng-1.x.x.tar.bz2. - Discontinued distributing libpng-1.7.0-1.6.0-diff.txt and similar. - Rebuilt configure with autoconf-2.69 (inadvertently not done in beta33) - Fixed 'make distcheck' on SUN OS - libpng.so was not being removed - -Version 1.6.0beta37 [January 10, 2013] - Fixed conceivable but difficult to repro overflow. Also added two test - programs to generate and test a PNG which should have the problem. - -Version 1.6.0beta39 [January 19, 2013] - Again corrected attempt at overflow detection in png_set_unknown_chunks(). - Added overflow detection in png_set_sPLT() and png_set_text_2(). - -Version 1.6.0beta40 [January 20, 2013] - Use consistent handling of overflows in text, sPLT and unknown png_set_* APIs - -Version 1.6.0rc01 [January 26, 2013] - No changes. - -Version 1.6.0rc02 [February 4, 2013] - Added png_get_palette_max() function. - -Version 1.6.0rc03 [February 5, 2013] - Fixed the png_get_palette_max API. - -Version 1.6.0rc04 [February 7, 2013] - Turn serial tests back on (recently turned off by autotools upgrade). - -Version 1.6.0rc05 [February 8, 2013] - Update manual about png_get_palette_max(). - -Version 1.6.0rc06 [February 9, 2013] - Fixed missing dependency in --prefix builds The intermediate - internal 'prefix.h' file can only be generated correctly after - pnglibconf.h, however the dependency was not in Makefile.am. The - symptoms are unpredictable depending on the order make chooses to - build pngprefix.h and pnglibconf.h, often the error goes unnoticed - because there is a system pnglibconf.h to use instead. - -Version 1.6.0rc07 [February 10, 2013] - Enclosed the new png_get_palette_max in #ifdef PNG_GET_PALETTE_MAX_SUPPORTED - block, and revised pnglibconf.h and pnglibconf.h.prebuilt accordingly. - -Version 1.6.0rc08 [February 10, 2013] - Fix typo in png.h #ifdef - -Version 1.6.0 [February 14, 2013] - No changes. - -Version 1.6.1beta01 [February 16, 2013] - Made symbol prefixing work with the ARM neon optimizations. Also allow - pngpriv.h to be included for preprocessor definitions only, so it can - be used in non-C/C++ files. Back ported from libpng 1.7. - Made sRGB check numbers consistent. - Ported libpng 1.5 options.awk/dfn file handling to 1.6, fixed one bug. - Removed cc -E workround, corrected png_get_palette_max API Tested on - SUN OS cc 5.9, which demonstrates the tokenization problem previously - avoided by using /lib/cpp. Since all .dfn output is now protected in - double quotes unless it is to be macro substituted the fix should - work everywhere. - Enabled parallel tests - back ported from libpng-1.7. - scripts/pnglibconf.dfa formatting improvements back ported from libpng17. - Fixed a race condition in the creation of the build 'scripts' directory - while building with a parallel make. - Use approved/supported Android method to check for NEON, use Linux/POSIX - 1003.1 API to check /proc/self/auxv avoiding buffer allocation and other - library calls (ported from libpng15). - -Version 1.6.1beta02 [February 19, 2013] - Use parentheses more consistently in "#if defined(MACRO)" tests. - Folded long lines. - Reenabled code to allow zero length PLTE chunks for MNG. - -Version 1.6.1beta03 [February 22, 2013] - Fixed ALIGNED_MEMORY support. - Allow run-time ARM NEON checking to be disabled. A new configure option: - --enable-arm-neon=always will stop the run-time checks. New checks - within arm/arm_init.c will cause the code not to be compiled unless - __ARM_NEON__ is set. This should make it fail safe (if someone asks - for it on then the build will fail if it can't be done.) - Updated the INSTALL document. - -Version 1.6.1beta04 [February 27, 2013] - Revised INSTALL to recommend using CPPFLAGS instead of INCLUDES. - Revised scripts/makefile.freebsd to respect ZLIBLIB and ZLIBINC. - Revised scripts/dfn.awk to work with the buggy MSYS awk that has trouble - with CRLF line endings. - -Version 1.6.1beta05 [March 1, 2013] - Avoid a possible memory leak in contrib/gregbook/readpng.c - -Version 1.6.1beta06 [March 4, 2013] - Better documentation of unknown handling API interactions. - Corrected Android builds and corrected libpng.vers with symbol - prefixing This adds an API to set optimization options externally, - providing an alternative and general solution for the non-portable - run-time tests used by the ARM Neon code. It also makes those tests - compile and link on Android. - The order of settings vs options in pnglibconf.h is reversed to allow - settings to depend on options and options can now set (or override) the - defaults for settings. - -Version 1.6.1beta07 [March 7, 2013] - Corrected simplified API default gamma for color-mapped output, added - a flag to change default. In 1.6.0 when the simplified API was used - to produce color-mapped output from an input image with no gamma - information the gamma assumed for the input could be different from - that assumed for non-color-mapped output. In particular 16-bit depth - input files were assumed to be sRGB encoded, whereas in the 'direct' - case they were assumed to have linear data. This was an error. The - fix makes the simplified API treat all input files the same way and - adds a new flag to the png_image::flags member to allow the - application/user to specify that 16-bit files contain sRGB data - rather than the default linear. - Fixed bugs in the pngpixel and makepng test programs. - -Version 1.6.1beta08 [March 7, 2013] - Fixed CMakelists.txt to allow building a single variant of the library - (Claudio Bley): - Introduced a PNG_LIB_TARGETS variable that lists all activated library - targets. It is an error if this variable ends up empty, ie. you have - to build at least one library variant. - Made the *_COPY targets only depend on library targets actually being build. - Use PNG_LIB_TARGETS to unify a code path. - Changed the CREATE_SYMLINK macro to expect the full path to a file as the - first argument. When symlinking the filename component of that path is - determined and used as the link target. - Use copy_if_different in the CREATE_SYMLINK macro. - -Version 1.6.1beta09 [March 13, 2013] - Eliminated two warnings from the Intel C compiler. The warnings are - technically valid, although a reasonable treatment of division would - show it to be incorrect. - -Version 1.6.1rc01 [March 21, 2013] - No changes. - -Version 1.6.1 [March 28, 2013] - No changes. - -Version 1.6.2beta01 [April 14, 2013] - Updated documentation of 1.5.x to 1.6.x changes in iCCP chunk handling. - Fixed incorrect warning of excess deflate data. End condition - the - warning would be produced if the end of the deflate stream wasn't read - in the last row. The warning is harmless. - Corrected the test on user transform changes on read. It was in the - png_set of the transform function, but that doesn't matter unless the - transform function changes the rowbuf size, and that is only valid if - transform_info is called. - Corrected a misplaced closing bracket in contrib/libtests/pngvalid.c - (Flavio Medeiros). - Corrected length written to uncompressed iTXt chunks (Samuli Suominen). - Bug was introduced in libpng-1.6.0. - -Version 1.6.2rc01 [April 18, 2013] - Added contrib/tools/fixitxt.c, to repair the erroneous iTXt chunk length - written by libpng-1.6.0 and 1.6.1. - Disallow storing sRGB information when the sRGB is not supported. - -Version 1.6.2rc02 [April 18, 2013] - Merge pngtest.c with libpng-1.7.0 - -Version 1.6.2rc03 [April 22, 2013] - Trivial spelling cleanup. - -Version 1.6.2rc04 and 1.6.2rc05 [omitted] - -Version 1.6.2rc06 [April 24, 2013] - Reverted to version 1.6.2rc03. Recent changes to arm/neon support - have been ported to libpng-1.7.0beta09 and will reappear in version - 1.6.3beta01. - -Version 1.6.2 [April 25, 2013] - No changes. - -Version 1.6.3beta01 [April 25, 2013] - Revised stack marking in arm/filter_neon.S and configure.ac. - Ensure that NEON filter stuff is completely disabled when switched 'off'. - Previously the ARM NEON specific files were still built if the option - was switched 'off' as opposed to being explicitly disabled. - -Version 1.6.3beta02 [April 26, 2013] - Test for 'arm*' not just 'arm' in the host_cpu configure variable. - Rebuilt the configure scripts. - -Version 1.6.3beta03 [April 30, 2013] - Expanded manual paragraph about writing private chunks, particularly - the need to call png_set_keep_unknown_chunks() when writing them. - Avoid dereferencing NULL pointer possibly returned from - png_create_write_struct() (Andrew Church). - -Version 1.6.3beta05 [May 9, 2013] - Calculate our own zlib windowBits when decoding rather than trusting the - CMF bytes in the PNG datastream. - Added an option to force maximum window size for inflating, which was - the behavior of libpng15 and earlier. - Added png-fix-itxt and png-fix-too-far-back to the built programs and - removed warnings from the source code and timepng that are revealed as - a result. - Detect wrong libpng versions linked to png-fix-too-far-back, which currently - only works with libpng versions that can be made to reliably fail when - the deflate data contains an out-of-window reference. This means only - 1.6 and later. - Fixed gnu issues: g++ needs a static_cast, gcc 4.4.7 has a broken warning - message which it is easier to work round than ignore. - Updated contrib/pngminus/pnm2png.c (Paul Stewart): - Check for EOF - Ignore "#" delimited comments in input file to pnm2png.c. - Fixed whitespace handling - Added a call to png_set_packing() - Initialize dimension values so if sscanf fails at least we have known - invalid values. - Attempt to detect configuration issues with png-fix-too-far-back, which - requires both the correct libpng and the correct zlib to function - correctly. - Check ZLIB_VERNUM for mismatches, enclose #error in quotes - Added information in the documentation about problems with and fixes for - the bad CRC and bad iTXt chunk situations. - -Version 1.6.3beta06 [May 12, 2013] - Allow contrib/pngminus/pnm2png.c to compile without WRITE_INVERT and - WRITE_PACK supported (writes error message that it can't read P1 or - P4 PBM files). - Improved png-fix-too-far-back usage message, added --suffix option. - Revised contrib/pngminim/*/makefile to generate pnglibconf.h with the - right zlib header files. - Separated CPPFLAGS and CFLAGS in contrib/pngminim/*/makefile - -Version 1.6.3beta07 [June 8, 2013] - Removed a redundant test in png_set_IHDR(). - Added set(CMAKE_CONFIGURATION_TYPES ...) to CMakeLists.txt (Andrew Hundt) - Deleted set(CMAKE_BUILD_TYPE) block from CMakeLists.txt - Enclose the prototypes for the simplified write API in - #ifdef PNG_STDIO_SUPPORTED/#endif - Make ARM NEON support work at compile time (not just configure time). - This moves the test on __ARM_NEON__ into pngconf.h to avoid issues when - using a compiler that compiles for multiple architectures at one time. - Removed PNG_FILTER_OPTIMIZATIONS and PNG_ARM_NEON_SUPPORTED from - pnglibconf.h, allowing more of the decisions to be made internally - (pngpriv.h) during the compile. Without this, symbol prefixing is broken - under certain circumstances on ARM platforms. Now only the API parts of - the optimizations ('check' vs 'api') are exposed in the public header files - except that the new setting PNG_ARM_NEON_OPT documents how libpng makes the - decision about whether or not to use the optimizations. - Protect symbol prefixing against CC/CPPFLAGS/CFLAGS useage. - Previous iOS/Xcode fixes for the ARM NEON optimizations moved the test - on __ARM_NEON__ from configure time to compile time. This breaks symbol - prefixing because the definition of the special png_init_filter_functions - call was hidden at configure time if the relevant compiler arguments are - passed in CFLAGS as opposed to CC. This change attempts to avoid all - the confusion that would result by declaring the init function even when - it is not used, so that it will always get prefixed. - -Version 1.6.3beta08 [June 18, 2013] - Revised libpng.3 so that "doclifter" can process it. - -Version 1.6.3beta09 [June 27, 2013] - Revised example.c to illustrate use of PNG_DEFAULT_sRGB and PNG_GAMMA_MAC_18 - as parameters for png_set_gamma(). These have been available since - libpng-1.5.4. - Renamed contrib/tools/png-fix-too-far-back.c to pngfix.c and revised it - to check all compressed chunks known to libpng. - -Version 1.6.3beta10 [July 5, 2013] - Updated documentation to show default behavior of benign errors correctly. - Only compile ARM code when PNG_READ_SUPPORTED is defined. - Fixed undefined behavior in contrib/tools/pngfix.c and added new strip - option. pngfix relied on undefined behavior and even a simple change from - gcc to g++ caused it to fail. The new strip option 'unsafe' has been - implemented and is the default if --max is given. Option names have - been clarified, with --strip=transform now stripping the bKGD chunk, - which was stripped previously with --strip=unused. - Added all documented chunk types to pngpriv.h - Unified pngfix.c source with libpng17. - -Version 1.6.3rc01 [July 11, 2013] - No changes. - -Version 1.6.3 [July 18, 2013] - Revised manual about changes in iTXt chunk handling made in libpng-1.6.0. - Added "/* SAFE */" comments in pngrutil.c and pngrtran.c where warnings - may be erroneously issued by code-checking applications. - -Version 1.6.4beta01 [August 21, 2013] - Added information about png_set_options() to the manual. - Delay calling png_init_filter_functions() until a row with nonzero filter - is found. - -Version 1.6.4beta02 [August 30, 2013] - Fixed inconsistent conditional compilation of png_chunk_unknown_handling() - prototype, definition, and usage. Made it depend on - PNG_HANDLE_AS_UNKNOWN_SUPPORTED everywhere. - -Version 1.6.4rc01 [September 5, 2013] - No changes. - -Version 1.6.4 [September 12, 2013] - No changes. - -Version 1.6.5 [September 14, 2013] - Removed two stray lines of code from arm/arm_init.c. - -Version 1.6.6 [September 16, 2013] - Removed two stray lines of code from arm/arm_init.c, again. - -Version 1.6.7beta01 [September 30, 2013] - Revised unknown chunk code to correct several bugs in the NO_SAVE_/NO_WRITE - combination - Allow HANDLE_AS_UNKNOWN to work when other options are configured off. Also - fixed the pngminim makefiles to work when $(MAKEFLAGS) contains stuff - which terminates the make options (as by default in recent versions of - Gentoo). - Avoid up-cast warnings in pngvalid.c. On ARM the alignment requirements of - png_modifier are greater than that of png_store and as a consequence - compilation of pngvalid.c results in a warning about increased alignment - requirements because of the bare cast to (png_modifier*). The code is safe, - because the pointer is known to point to a stack allocated png_modifier, - but this change avoids the warning. - Fixed default behavior of ARM_NEON_API. If the ARM NEON API option was - compiled without the CHECK option it defaulted to on, not off. - Check user callback behavior in pngunknown.c. Previous versions compiled - if SAVE_UNKNOWN was not available but did nothing since the callback - was never implemented. - Merged pngunknown.c with 1.7 version and back ported 1.7 improvements/fixes - -Version 1.6.7beta02 [October 12, 2013] - Made changes for compatibility with automake 1.14: - 1) Added the 'compile' program to the list of programs that must be cleaned - in autogen.sh - 2) Added 'subdir-objects' which causes .c files in sub-directories to be - compiled such that the corresponding .o files are also in the - sub-directory. This is because automake 1.14 warns that the - current behavior of compiling to the top level directory may be removed - in the future. - 3) Updated dependencies on pnglibconf.h to match the new .o locations and - added all the files in contrib/libtests and contrib/tools that depend - on pnglibconf.h - 4) Added 'BUILD_SOURCES = pnglibconf.h'; this is the automake recommended - way of handling the dependencies of sources that are machine generated; - unfortunately it only works if the user does 'make all' or 'make check', - so the dependencies (3) are still required. - Cleaned up (char*) casts of zlib messages. The latest version of the Intel C - compiler complains about casting a string literal as (char*), so copied the - treatment of z_const from the library code into pngfix.c - Simplified error message code in pngunknown. The simplification has the - useful side effect of avoiding a bogus warning generated by the latest - version of the Intel C compiler (it objects to - condition ? string-literal : string-literal). - Make autogen.sh work with automake 1.13 as well as 1.14. Do this by always - removing the 1.14 'compile' script but never checking for it. - -Version 1.6.7beta03 [October 19, 2013] - Added ARMv8 support (James Yu ). Added file - arm/filter_neon_intrinsics.c; enable with -mfpu=neon. - Revised pngvalid to generate size images with as many filters as it can - manage, limited by the number of rows. - Cleaned up ARM NEON compilation handling. The tests are now in pngpriv.h - and detect the broken GCC compilers. - -Version 1.6.7beta04 [October 26, 2013] - Allow clang derived from older GCC versions to use ARM intrinsics. This - causes all clang builds that use -mfpu=neon to use the intrinsics code, - not the assembler code. This has only been tested on iOS 7. It may be - necessary to exclude some earlier clang versions but this seems unlikely. - Changed NEON implementation selection mechanism. This allows assembler - or intrinsics to be turned on at compile time during the build by defining - PNG_ARM_NEON_IMPLEMENTATION to the correct value (2 or 1). This macro - is undefined by default and the build type is selected in pngpriv.h. - -Version 1.6.7rc01 [November 2, 2013] - No changes. - -Version 1.6.7rc02 [November 7, 2013] - Fixed #include in filter_neon_intrinsics.c and ctype macros. The ctype char - checking macros take an unsigned char argument, not a signed char. - -Version 1.6.7 [November 14, 2013] - No changes. - -Version 1.6.8beta01 [November 24, 2013] - Moved prototype for png_handle_unknown() in pngpriv.h outside of - the #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED/#endif block. - Added "-Wall" to CFLAGS in contrib/pngminim/*/makefile - Conditionally compile some unused functions reported by -Wall in - pngminim. - Fixed 'minimal' builds. Various obviously useful minimal configurations - don't build because of missing contrib/libtests test programs and - overly complex dependencies in scripts/pnglibconf.dfa. This change - adds contrib/conftest/*.dfa files that can be used in automatic build - scripts to ensure that these configurations continue to build. - Enabled WRITE_INVERT and WRITE_PACK in contrib/pngminim/encoder. - Fixed pngvalid 'fail' function declaration on the Intel C Compiler. - This reverts to the previous 'static' implementation and works round - the 'unused static function' warning by using PNG_UNUSED(). - -Version 1.6.8beta02 [November 30, 2013] - Removed or marked PNG_UNUSED some harmless "dead assignments" reported - by clang scan-build. - Changed tabs to 3 spaces in png_debug macros and changed '"%s"m' - to '"%s" m' to improve portability among compilers. - Changed png_free_default() to free() in pngtest.c - -Version 1.6.8rc01 [December 12, 2013] - Tidied up pngfix inits and fixed pngtest no-write builds. - -Version 1.6.8rc02 [December 14, 2013] - Handle zero-length PLTE chunk or NULL palette with png_error() - instead of png_chunk_report(), which by default issues a warning - rather than an error, leading to later reading from a NULL pointer - (png_ptr->palette) in png_do_expand_palette(). This is CVE-2013-6954 - and VU#650142. Libpng-1.6.1 through 1.6.7 are vulnerable. - Libpng-1.6.0 and earlier do not have this bug. - -Version 1.6.8 [December 19, 2013] - No changes. - -Version 1.6.9beta01 [December 26, 2013] - Bookkeeping: Moved functions around (no changes). Moved transform - function definitions before the place where they are called so that - they can be made static. Move the intrapixel functions and the - grayscale palette builder out of the png?tran.c files. The latter - isn't a transform function and is no longer used internally, and the - former MNG specific functions are better placed in pngread/pngwrite.c - Made transform implementation functions static. This makes the internal - functions called by png_do_{read|write}_transformations static. On an - x86-64 DLL build (Gentoo Linux) this reduces the size of the text - segment of the DLL by 1208 bytes, about 0.6%. It also simplifies - maintenance by removing the declarations from pngpriv.h and allowing - easier changes to the internal interfaces. - Rebuilt configure scripts with automake-1.14.1 and autoconf-2.69 - in the tar distributions. - -Version 1.6.9beta02 [January 1, 2014] - Added checks for libpng 1.5 to pngvalid.c. This supports the use of - this version of pngvalid in libpng 1.5 - Merged with pngvalid.c from libpng-1.7 changes to create a single - pngvalid.c - Removed #error macro from contrib/tools/pngfix.c (Thomas Klausner). - Merged pngrio.c, pngtrans.c, pngwio.c, and pngerror.c with libpng-1.7.0 - Merged libpng-1.7.0 changes to make no-interlace configurations work - with test programs. - Revised pngvalid.c to support libpng 1.5, which does not support the - PNG_MAXIMUM_INFLATE_WINDOW option, so #define it out when appropriate in - pngvalid.c - Allow unversioned links created on install to be disabled in configure. - In configure builds 'make install' changes/adds links like png.h - and libpng.a to point to the newly installed, versioned, files (e.g. - libpng17/png.h and libpng17.a). Three new configure options and some - rearrangement of Makefile.am allow creation of these links to be disabled. - -Version 1.6.9beta03 [January 10, 2014] - Removed potentially misleading warning from png_check_IHDR(). - -Version 1.6.9beta04 [January 20, 2014] - Updated scripts/makefile.* to use CPPFLAGS (Cosmin). - Added clang attribute support (Cosmin). - -Version 1.6.9rc01 [January 28, 2014] - No changes. - -Version 1.6.9rc02 [January 30, 2014] - Quiet an uninitialized memory warning from VC2013 in png_get_png(). - -Version 1.6.9 [February 6, 2014] - -Version 1.6.10beta01 [February 9, 2014] - Backported changes from libpng-1.7.0beta30 and beta31: - Fixed a large number of instances where PNGCBAPI was omitted from - function definitions. - Added pngimage test program for png_read_png() and png_write_png() - with two new test scripts. - Removed dependence on !PNG_READ_EXPAND_SUPPORTED for calling - png_set_packing() in png_read_png(). - Fixed combination of ~alpha with shift. On read invert alpha, processing - occurred after shift processing, which causes the final values to be - outside the range that should be produced by the shift. Reversing the - order on read makes the two transforms work together correctly and mirrors - the order used on write. - Do not read invalid sBIT chunks. Previously libpng only checked sBIT - values on write, so a malicious PNG writer could therefore cause - the read code to return an invalid sBIT chunk, which might lead to - application errors or crashes. Such chunks are now skipped (with - chunk_benign_error). - Make png_read_png() and png_write_png() prototypes in png.h depend - upon PNG_READ_SUPPORTED and PNG_WRITE_SUPPORTED. - Support builds with unsupported PNG_TRANSFORM_* values. All of the - PNG_TRANSFORM_* values are always defined in png.h and, because they - are used for both read and write in some cases, it is not reliable - to #if out ones that are totally unsupported. This change adds error - detection in png_read_image() and png_write_image() to do a - png_app_error() if the app requests something that cannot be done - and it adds corresponding code to pngimage.c to handle such options - by not attempting to test them. - -Version 1.6.10beta02 [February 23, 2014] - Moved redefines of png_error(), png_warning(), png_chunk_error(), - and png_chunk_warning() from pngpriv.h to png.h to make them visible - to libpng-calling applications. - Moved OS dependent code from arm/arm_init.c, to allow the included - implementation of the ARM NEON discovery function to be set at - build-time and provide sample implementations from the current code in the - contrib/arm-neon subdirectory. The __linux__ code has also been changed to - compile and link on Android by using /proc/cpuinfo, and the old linux code - is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux - dependencies apart from opening /proc/cpuinfo and is C90 compliant. - Check for info_ptr == NULL early in png_read_end() so we don't need to - run all the png_handle_*() and depend on them to return if info_ptr == NULL. - This improves the performance of png_read_end(png_ptr, NULL) and makes - it more robust against future programming errors. - Check for __has_extension before using it in pngconf.h, to - support older Clang versions (Jeremy Sequoia). - Treat CRC error handling with png_set_crc_action(), instead of with - png_set_benign_errors(), which has been the case since libpng-1.6.0beta18. - Use a user warning handler in contrib/gregbook/readpng2.c instead of default, - so warnings will be put on stderr even if libpng has CONSOLE_IO disabled. - Added png_ptr->process_mode = PNG_READ_IDAT_MODE in png_push_read_chunk - after recognizing the IDAT chunk, which avoids an infinite loop while - reading a datastream whose first IDAT chunk is of zero-length. - This fixes CERT VU#684412 and CVE-2014-0333. - Don't recognize known sRGB profiles as sRGB if they have been hacked, - but don't reject them and don't issue a copyright violation warning. - -Version 1.6.10beta03 [February 25, 2014] - Moved some documentation from png.h to libpng.3 and libpng-manual.txt - Minor editing of contrib/arm-neon/README and contrib/examples/*.c - -Version 1.6.10rc01 [February 27, 2014] - Fixed typos in the manual and in scripts/pnglibconf.dfa (CFLAGS -> CPPFLAGS - and PNG_USR_CONFIG -> PNG_USER_CONFIG). - -Version 1.6.10rc02 [February 28, 2014] - Removed unreachable return statement after png_chunk_error() - in pngrutil.c - -Version 1.6.10rc03 [March 4, 2014] - Un-deprecated png_data_freer(). - -Version 1.6.10 [March 6, 2014] - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) -or to glennrp at users.sourceforge.net - -Glenn R-P -#endif +#if 0 +CHANGES - changes for libpng + +Version 0.2 + added reader into png.h + fixed small problems in stub file + +Version 0.3 + added pull reader + split up pngwrite.c to several files + added pnglib.txt + added example.c + cleaned up writer, adding a few new transformations + fixed some bugs in writer + interfaced with zlib 0.5 + added K&R support + added check for 64 KB blocks for 16-bit machines + +Version 0.4 + cleaned up code and commented code + simplified time handling into png_time + created png_color_16 and png_color_8 to handle color needs + cleaned up color type defines + fixed various bugs + made various names more consistent + interfaced with zlib 0.71 + cleaned up zTXt reader and writer (using zlib's Reset functions) + split transformations into pngrtran.c and pngwtran.c + +Version 0.5 + interfaced with zlib 0.8 + fixed many reading and writing bugs + saved using 3 spaces instead of tabs + +Version 0.6 + added png_large_malloc() and png_large_free() + added png_size_t + cleaned up some compiler warnings + added png_start_read_image() + +Version 0.7 + cleaned up lots of bugs + finished dithering and other stuff + added test program + changed name from pnglib to libpng + +Version 0.71 [June, 1995] + changed pngtest.png for zlib 0.93 + fixed error in libpng.txt and example.c + +Version 0.8 + cleaned up some bugs + added png_set_filler() + split up pngstub.c into pngmem.c, pngio.c, and pngerror.c + added #define's to remove unwanted code + moved png_info_init() to png.c + added old_size into png_realloc() + added functions to manually set filtering and compression info + changed compression parameters based on image type + optimized filter selection code + added version info + changed external functions passing floats to doubles (k&r problems?) + put all the configurable stuff in pngconf.h + enabled png_set_shift to work with paletted images on read + added png_read_update_info() - updates info structure with transformations + +Version 0.81 [August, 1995] + incorporated Tim Wegner's medium model code (thanks, Tim) + +Version 0.82 [September, 1995] + [unspecified changes] + +Version 0.85 [December, 1995] + added more medium model code (almost everything's a far) + added i/o, error, and memory callback functions + fixed some bugs (16-bit, 4-bit interlaced, etc.) + added first run progressive reader (barely tested) + +Version 0.86 [January, 1996] + fixed bugs + improved documentation + +Version 0.87 [January, 1996] + fixed medium model bugs + fixed other bugs introduced in 0.85 and 0.86 + added some minor documentation + +Version 0.88 [January, 1996] + fixed progressive bugs + replaced tabs with spaces + cleaned up documentation + added callbacks for read/write and warning/error functions + +Version 0.89 [July, 1996] + Added new initialization API to make libpng work better with shared libs + we now have png_create_read_struct(), png_create_write_struct(), + png_create_info_struct(), png_destroy_read_struct(), and + png_destroy_write_struct() instead of the separate calls to + malloc and png_read_init(), png_info_init(), and png_write_init() + Changed warning/error callback functions to fix bug - this means you + should use the new initialization API if you were using the old + png_set_message_fn() calls, and that the old API no longer exists + so that people are aware that they need to change their code + Changed filter selection API to allow selection of multiple filters + since it didn't work in previous versions of libpng anyways + Optimized filter selection code + Fixed png_set_background() to allow using an arbitrary RGB color for + paletted images + Fixed gamma and background correction for paletted images, so + png_correct_palette is not needed unless you are correcting an + external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED + in pngconf.h) - if nobody uses this, it may disappear in the future. + Fixed bug with Borland 64K memory allocation (Alexander Lehmann) + Fixed bug in interlace handling (Smarasderagd, I think) + Added more error checking for writing and image to reduce invalid files + Separated read and write functions so that they won't both be linked + into a binary when only reading or writing functionality is used + New pngtest image also has interlacing and zTXt + Updated documentation to reflect new API + +Version 0.90 [January, 1997] + Made CRC errors/warnings on critical and ancillary chunks configurable + libpng will use the zlib CRC routines by (compile-time) default + Changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) + Added external C++ wrapper statements to png.h (Gilles Dauphin) + Allow PNG file to be read when some or all of file signature has already + been read from the beginning of the stream. ****This affects the size + of info_struct and invalidates all programs that use a shared libpng**** + Fixed png_filler() declarations + Fixed? background color conversions + Fixed order of error function pointers to match documentation + Current chunk name is now available in png_struct to reduce the number + of nearly identical error messages (will simplify multi-lingual + support when available) + Try to get ready for unknown-chunk callback functions: + - previously read critical chunks are flagged, so the chunk handling + routines can determine if the chunk is in the right place + - all chunk handling routines have the same prototypes, so we will + be able to handle all chunks via a callback mechanism + Try to fix Linux "setjmp" buffer size problems + Removed png_large_malloc, png_large_free, and png_realloc functions. + +Version 0.95 [March, 1997] + Fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never + Fixed bug in PNG file signature compares when start != 0 + Changed parameter type of png_set_filler(...filler...) from png_byte + to png_uint_32 + Added test for MACOS to ensure that both math.h and fp.h are not #included + Added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) + Added "packswap" transformation, which changes the endianness of + packed-pixel bytes (Kevin Bracey) + Added "strip_alpha" transformation, which removes the alpha channel of + input images without using it (not necessarily a good idea) + Added "swap_alpha" transformation, which puts the alpha channel in front + of the color bytes instead of after + Removed all implicit variable tests which assume NULL == 0 (I think) + Changed several variables to "png_size_t" to show 16/32-bit limitations + Added new pCAL chunk read/write support + Added experimental filter selection weighting (Greg Roelofs) + Removed old png_set_rgbx() and png_set_xrgb() functions that have been + obsolete for about 2 years now (use png_set_filler() instead) + Added macros to read 16- and 32-bit ints directly from buffer, to be + used only on those systems that support it (namely PowerPC and 680x0) + With some testing, this may become the default for MACOS/PPC systems. + Only calculate CRC on data if we are going to use it + Added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? + Added macros for simple libpng debugging output selectable at compile time + Removed PNG_READ_END_MODE in progressive reader (Smarasderagd) + More description of info_struct in libpng.txt and png.h + More instructions in example.c + More chunk types tested in pngtest.c + Renamed pngrcb.c to pngset.c, and all png_read_ functions to be + png_set_. We now have corresponding png_get_ + functions in pngget.c to get information in info_ptr. This isolates + the application from the internal organization of png_info_struct + (good for shared library implementations). + +Version 0.96 [May, 1997] + Fixed serious bug with < 8bpp images introduced in 0.95 + Fixed 256-color transparency bug (Greg Roelofs) + Fixed up documentation (Greg Roelofs, Laszlo Nyul) + Fixed "error" in pngconf.h for Linux setjmp() behavior + Fixed DOS medium model support (Tim Wegner) + Fixed png_check_keyword() for case with error in static string text + Added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) + Added typecasts to quiet compiler errors + Added more debugging info + +Version 0.97 [January, 1998] + Removed PNG_USE_OWN_CRC capability + Relocated png_set_crc_action from pngrutil.c to pngrtran.c + Fixed typecasts of "new_key", etc. (Andreas Dilger) + Added RFC 1152 [sic] date support + Fixed bug in gamma handling of 4-bit grayscale + Added 2-bit grayscale gamma handling (Glenn R-P) + Added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) + Minor corrections in libpng.txt + Added simple sRGB support (Glenn R-P) + Easier conditional compiling, e.g., + define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; + all configurable options can be selected from command-line instead + of having to edit pngconf.h (Glenn R-P) + Fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) + Added more conditions for png_do_background, to avoid changing + black pixels to background when a background is supplied and + no pixels are transparent + Repaired PNG_NO_STDIO behavior + Tested NODIV support and made it default behavior (Greg Roelofs) + Added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) + Regularized version numbering scheme and bumped shared-library major + version number to 2 to avoid problems with libpng 0.89 apps + (Greg Roelofs) + +Version 0.98 [January, 1998] + Cleaned up some typos in libpng.txt and in code documentation + Fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) + Cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c + Changed recommendation about file_gamma for PC images to .51 from .45, + in example.c and libpng.txt, added comments to distinguish between + screen_gamma, viewing_gamma, and display_gamma. + Changed all references to RFC1152 to read RFC1123 and changed the + PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED + Added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) + Changed srgb_intent from png_byte to int to avoid compiler bugs + +Version 0.99 [January 30, 1998] + Free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) + Fixed a longstanding "packswap" bug in pngtrans.c + Fixed some inconsistencies in pngconf.h that prevented compiling with + PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined + Fixed some typos and made other minor rearrangement of libpng.txt (Andreas) + Changed recommendation about file_gamma for PC images to .50 from .51 in + example.c and libpng.txt, and changed file_gamma for sRGB images to .45 + Added a number of functions to access information from the png structure + png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) + Added TARGET_MACOS similar to zlib-1.0.8 + Define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined + Added type casting to all png_malloc() function calls + +Version 0.99a [January 31, 1998] + Added type casts and parentheses to all returns that return a value.(Tim W.) + +Version 0.99b [February 4, 1998] + Added type cast png_uint_32 on malloc function calls where needed. + Changed type of num_hist from png_uint_32 to int (same as num_palette). + Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. + Renamed makefile.elf to makefile.lnx. + +Version 0.99c [February 7, 1998] + More type casting. Removed erroneous overflow test in pngmem.c. + Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. + Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. + +Version 0.99d [February 11, 1998] + Renamed "far_to_near()" "png_far_to_near()" + Revised libpng.3 + Version 99c "buffered" operations didn't work as intended. Replaced them + with png_memcpy_check() and png_memset_check(). + Added many "if (png_ptr == NULL) return" to quell compiler warnings about + unused png_ptr, mostly in pngget.c and pngset.c. + Check for overlength tRNS chunk present when indexed-color PLTE is read. + Cleaned up spelling errors in libpng.3/libpng.txt + Corrected a problem with png_get_tRNS() which returned undefined trans array + +Version 0.99e [February 28, 1998] + Corrected png_get_tRNS() again. + Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". + Touched up example.c to make more of it compileable, although the entire + file still can't be compiled (Willem van Schaik) + Fixed a bug in png_do_shift() (Bryan Tsai) + Added a space in png.h prototype for png_write_chunk_start() + Replaced pngtest.png with one created with zlib 1.1.1 + Changed pngtest to report PASS even when file size is different (Jean-loup G.) + Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) + +Version 0.99f [March 5, 1998] + Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) + Moved makefiles into a "scripts" directory, and added INSTALL instruction file + Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) + Added pointers to "note on libpng versions" in makefile.lnx and README + Added row callback feature when reading and writing nonprogressive rows + and added a test of this feature in pngtest.c + Added user transform callbacks, with test of the feature in pngtest.c + +Version 0.99g [March 6, 1998, morning] + Minor changes to pngtest.c to suppress compiler warnings. + Removed "beta" language from documentation. + +Version 0.99h [March 6, 1998, evening] + Minor changes to previous minor changes to pngtest.c + Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED + and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro + Added user transform capability + +Version 1.00 [March 7, 1998] + Changed several typedefs in pngrutil.c + Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) + Replaced "while(1)" with "for(;;)" + Added PNGARG() to prototypes in pngtest.c and removed some prototypes + Updated some of the makefiles (Tom Lane) + Changed some typedefs (s_start, etc.) in pngrutil.c + Fixed dimensions of "short_months" array in pngwrite.c + Replaced ansi2knr.c with the one from jpeg-v6 + +Version 1.0.0 [March 8, 1998] + Changed name from 1.00 to 1.0.0 (Adam Costello) + Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) + +Version 1.0.0a [March 9, 1998] + Fixed three bugs in pngrtran.c to make gamma+background handling consistent + (Greg Roelofs) + Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz + for major, minor, and bugfix releases. This is 10001. (Adam Costello, + Tom Lane) + Make months range from 1-12 in png_convert_to_rfc1123 + +Version 1.0.0b [March 13, 1998] + Quieted compiler complaints about two empty "for" loops in pngrutil.c + Minor changes to makefile.s2x + Removed #ifdef/#endif around a png_free() in pngread.c + +Version 1.0.1 [March 14, 1998] + Changed makefile.s2x to reduce security risk of using a relative pathname + Fixed some typos in the documentation (Greg). + Fixed a problem with value of "channels" returned by png_read_update_info() + +Version 1.0.1a [April 21, 1998] + Optimized Paeth calculations by replacing abs() function calls with intrinsics + plus other loop optimizations. Improves avg decoding speed by about 20%. + Commented out i386istic "align" compiler flags in makefile.lnx. + Reduced the default warning level in some makefiles, to make them consistent. + Removed references to IJG and JPEG in the ansi2knr.c copyright statement. + Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. + Added grayscale and 16-bit capability to png_do_read_filler(). + Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes + too large when writing an image with bit_depth < 8 (Bob Dellaca). + Corrected some bugs in the experimental weighted filtering heuristics. + Moved a misplaced pngrutil code block that truncates tRNS if it has more + than num_palette entries -- test was done before num_palette was defined. + Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). + Changed compiler flags in makefile.wat for better optimization + (Pawel Mrochen). + +Version 1.0.1b [May 2, 1998] + Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). + Relocated the png_composite macros from pngrtran.c to png.h (Greg). + Added makefile.sco (contributed by Mike Hopkirk). + Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. + Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. + More work on the Paeth-filtering, achieving imperceptible speedup + (A Kleinert). + More work on loop optimization which may help when compiled with C++ + compilers. + Added warnings when people try to use transforms they've defined out. + Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. + Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) + +Version 1.0.1c [May 11, 1998] + Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for + filler bytes should have been 0xff instead of 0xf. + Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. + Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED + out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h + Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, + for consistency, in pngconf.h + Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier + to remove unwanted capabilities via the compile line + Made some corrections to grammar (which, it's) in documentation (Greg). + Corrected example.c, use of row_pointers in png_write_image(). + +Version 1.0.1d [May 24, 1998] + Corrected several statements that used side effects illegally in pngrutil.c + and pngtrans.c, that were introduced in version 1.0.1b + Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) + More corrections to example.c, use of row_pointers in png_write_image() + and png_read_rows(). + Added pngdll.mak and pngdef.pas to scripts directory, contributed by + Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 + Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) + Changed several loops from count-down to count-up, for consistency. + +Version 1.0.1e [June 6, 1998] + Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and + added warnings when people try to set png_read_fn and png_write_fn in + the same structure. + Added a test such that png_do_gamma will be done when num_trans==0 + for truecolor images that have defined a background. This corrects an + error that was introduced in libpng-0.90 that can cause gamma processing + to be skipped. + Added tests in png.h to include "trans" and "trans_values" in structures + when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. + Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() + Moved png_convert_to_rfc_1123() from pngwrite.c to png.c + Added capability for user-provided malloc_fn() and free_fn() functions, + and revised pngtest.c to demonstrate their use, replacing the + PNGTEST_DEBUG_MEM feature. + Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). + +Version 1.0.2 [June 14, 1998] + Fixed two bugs in makefile.bor . + +Version 1.0.2a [December 30, 1998] + Replaced and extended code that was removed from png_set_filler() in 1.0.1a. + Fixed a bug in png_do_filler() that made it fail to write filler bytes in + the left-most pixel of each row (Kevin Bracey). + Changed "static pngcharp tIME_string" to "static char tIME_string[30]" + in pngtest.c (Duncan Simpson). + Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk + even when no tIME chunk was present in the source file. + Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. + Fixed a problem in png_read_push_finish_row(), which would not skip some + passes that it should skip, for images that are less than 3 pixels high. + Interchanged the order of calls to png_do_swap() and png_do_shift() + in pngwtran.c (John Cromer). + Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . + Changed "bad adaptive filter type" from error to warning in pngrutil.c . + Fixed a documentation error about default filtering with 8-bit indexed-color. + Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO + (L. Peter Deutsch). + Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. + Added png_get_copyright() and png_get_header_version() functions. + Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c + Added information about debugging in libpng.txt and libpng.3 . + Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and + makefile.sco. + Removed lines after Dynamic Dependencies" in makefile.aco . + Revised makefile.dec to make a shared library (Jeremie Petit). + Removed trailing blanks from all files. + +Version 1.0.2a [January 6, 1999] + Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h + Added "if" tests to silence complaints about unused png_ptr in png.h and png.c + Changed "check_if_png" function in example.c to return true (nonzero) if PNG. + Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() + which is obsolete. + +Version 1.0.3 [January 14, 1999] + Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) + Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. + +Version 1.0.3a [August 12, 1999] + Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning + if an attempt is made to read an interlaced image when it's not supported. + Added check if png_ptr->trans is defined before freeing it in pngread.c + Modified the Y2K statement to include versions back to version 0.71 + Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c + Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) + Replaced leading blanks with tab characters in makefile.hux + Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. + Changed (float)red and (float)green to (double)red, (double)green + in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. + Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). + Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). + Updated documentation to refer to the PNG-1.2 specification. + Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c + in makefile.knr, INSTALL, and README (L. Peter Deutsch) + Fixed bugs in calculation of the length of rowbytes when adding alpha + channels to 16-bit images, in pngrtran.c (Chris Nokleberg) + Added function png_set_user_transform_info() to store user_transform_ptr, + user_depth, and user_channels into the png_struct, and a function + png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) + Added function png_set_empty_plte_permitted() to make libpng useable + in MNG applications. + Corrected the typedef for png_free_ptr in png.h (Jesse Jones). + Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be + consistent with PNG-1.2, and allow variance of 500 before complaining. + Added assembler code contributed by Intel in file pngvcrd.c and modified + makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, + Gilles Vollant) + Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. + Added some aliases for png_set_expand() in pngrtran.c, namely + png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() + (Greg Roelofs, in "PNG: The Definitive Guide"). + Added makefile.beo for BEOS on X86, contributed by Sander Stok. + +Version 1.0.3b [August 26, 1999] + Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h + Changed leading blanks to tabs in all makefiles. + Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. + Made alternate versions of png_set_expand() in pngrtran.c, namely + png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha + (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. + Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h + Revised calculation of num_blocks in pngmem.c to avoid a potentially + negative shift distance, whose results are undefined in the C language. + Added a check in pngset.c to prevent writing multiple tIME chunks. + Added a check in pngwrite.c to detect invalid small window_bits sizes. + +Version 1.0.3d [September 4, 1999] + Fixed type casting of igamma in pngrutil.c + Added new png_expand functions to scripts/pngdef.pas and pngos2.def + Added a demo read_user_transform_fn that examines the row filters in pngtest.c + +Version 1.0.4 [September 24, 1999] + Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined + Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h + Made several minor corrections to pngtest.c + Renamed the makefiles with longer but more user friendly extensions. + Copied the PNG copyright and license to a separate LICENSE file. + Revised documentation, png.h, and example.c to remove reference to + "viewing_gamma" which no longer appears in the PNG specification. + Revised pngvcrd.c to use MMX code for interlacing only on the final pass. + Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a + Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX + assembler code) and makefile.vcwin32 (doesn't). + Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) + Added a copy of pngnow.png to the distribution. + +Version 1.0.4a [September 25, 1999] + Increase max_pixel_depth in pngrutil.c if a user transform needs it. + Changed several division operations to right-shifts in pngvcrd.c + +Version 1.0.4b [September 30, 1999] + Added parentheses in line 3732 of pngvcrd.c + Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 + +Version 1.0.4c [October 1, 1999] + Added a "png_check_version" function in png.c and pngtest.c that will generate + a helpful compiler error if an old png.h is found in the search path. + Changed type of png_user_transform_depth|channels from int to png_byte. + +Version 1.0.4d [October 6, 1999] + Changed 0.45 to 0.45455 in png_set_sRGB() + Removed unused PLTE entries from pngnow.png + Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. + +Version 1.0.4e [October 10, 1999] + Fixed sign error in pngvcrd.c (Greg Roelofs) + Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) + +Version 1.0.4f [October 15, 1999] + Surrounded example.c code with #if 0 .. #endif to prevent people from + inadvertently trying to compile it. + Changed png_get_header_version() from a function to a macro in png.h + Added type casting mostly in pngrtran.c and pngwtran.c + Removed some pointless "ptr = NULL" in pngmem.c + Added a "contrib" directory containing the source code from Greg's book. + +Version 1.0.5 [October 15, 1999] + Minor editing of the INSTALL and README files. + +Version 1.0.5a [October 23, 1999] + Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) + Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) + Further optimization and bugfix of pngvcrd.c + Revised pngset.c so that it does not allocate or free memory in the user's + text_ptr structure. Instead, it makes its own copy. + Created separate write_end_info_struct in pngtest.c for a more severe test. + Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. + +Version 1.0.5b [November 23, 1999] + Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and + PNG_FLAG_WROTE_tIME from flags to mode. + Added png_write_info_before_PLTE() function. + Fixed some typecasting in contrib/gregbook/*.c + Updated scripts/makevms.com and added makevms.com to contrib/gregbook + and contrib/pngminus (Martin Zinser) + +Version 1.0.5c [November 26, 1999] + Moved png_get_header_version from png.h to png.c, to accommodate ansi2knr. + Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to + accommodate making DLL's: Moved usr_png_ver from global variable to function + png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and + eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays + into pngtypes.h. Eliminated use of global png_pass arrays. Declared the + png_CHNK and png_pass arrays to be "const". Made the global arrays + available to applications (although none are used in libpng itself) when + PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. + Removed some extraneous "-I" from contrib/pngminus/makefile.std + Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. + Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 + +Version 1.0.5d [November 29, 1999] + Add type cast (png_const_charp) two places in png.c + Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. + Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available + to applications a macro "PNG_USE_LOCAL_ARRAYS". + comment out (with #ifdef) all the new declarations when + PNG_USE_GLOBAL_ARRAYS is defined. + Added PNG_EXPORT_VAR macro to accommodate making DLL's. + +Version 1.0.5e [November 30, 1999] + Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text + structure; refactored the inflate/deflate support to make adding new chunks + with trailing compressed parts easier in the future, and added new functions + png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, + png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). + NOTE: Applications that write text chunks MUST define png_text->lang + before calling png_set_text(). It must be set to NULL if you want to + write tEXt or zTXt chunks. If you want your application to be able to + run with older versions of libpng, use + + #ifdef PNG_iTXt_SUPPORTED + png_text[i].lang = NULL; + #endif + + Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned + offsets (Eric S. Raymond). + Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into + PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED + macros, leaving the separate macros also available. + Removed comments on #endifs at the end of many short, non-nested #if-blocks. + +Version 1.0.5f [December 6, 1999] + Changed makefile.solaris to issue a warning about potential problems when + the ucb "ld" is in the path ahead of the ccs "ld". + Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. + Added sCAL chunk support (Eric S. Raymond). + +Version 1.0.5g [December 7, 1999] + Fixed "png_free_spallettes" typo in png.h + Added code to handle new chunks in pngpread.c + Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block + Added "translated_key" to png_text structure and png_write_iTXt(). + Added code in pngwrite.c to work around a newly discovered zlib bug. + +Version 1.0.5h [December 10, 1999] + NOTE: regarding the note for version 1.0.5e, the following must also + be included in your code: + png_text[i].translated_key = NULL; + Unknown chunk handling is now supported. + Option to eliminate all floating point support was added. Some new + fixed-point functions such as png_set_gAMA_fixed() were added. + Expanded tabs and removed trailing blanks in source files. + +Version 1.0.5i [December 13, 1999] + Added some type casts to silence compiler warnings. + Renamed "png_free_spalette" to "png_free_spalettes" for consistency. + Removed leading blanks from a #define in pngvcrd.c + Added some parameters to the new png_set_keep_unknown_chunks() function. + Added a test for up->location != 0 in the first instance of writing + unknown chunks in pngwrite.c + Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to + prevent recursion. + Added png_free_hIST() function. + Various patches to fix bugs in the sCAL and integer cHRM processing, + and to add some convenience macros for use with sCAL. + +Version 1.0.5j [December 21, 1999] + Changed "unit" parameter of png_write_sCAL from png_byte to int, to work + around buggy compilers. + Added new type "png_fixed_point" for integers that hold float*100000 values + Restored backward compatibility of tEXt/zTXt chunk processing: + Restored the first four members of png_text to the same order as v.1.0.5d. + Added members "lang_key" and "itxt_length" to png_text struct. Set + text_length=0 when "text" contains iTXt data. Use the "compression" + member to distinguish among tEXt/zTXt/iTXt types. Added + PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. + The "Note" above, about backward incompatibility of libpng-1.0.5e, no + longer applies. + Fixed png_read|write_iTXt() to read|write parameters in the right order, + and to write the iTXt chunk after IDAT if it appears in the end_ptr. + Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) + Reversed the order of trying to write floating-point and fixed-point gAMA. + +Version 1.0.5k [December 27, 1999] + Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" + Added png_handle_as_unknown() function (Glenn) + Added png_free_chunk_list() function and chunk_list and num_chunk_list members + of png_ptr. + Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. + Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings + about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) + Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). + Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. + Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). + +Version 1.0.5l [January 1, 2000] + Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() + for setting a callback function to handle unknown chunks and for + retrieving the associated user pointer (Glenn). + +Version 1.0.5m [January 7, 2000] + Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). + +Version 1.0.5n [January 9, 2000] + Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its + own memory for info_ptr->palette. This makes it safe for the calling + application to free its copy of the palette any time after it calls + png_set_PLTE(). + +Version 1.0.5o [January 20, 2000] + Cosmetic changes only (removed some trailing blanks and TABs) + +Version 1.0.5p [January 31, 2000] + Renamed pngdll.mak to makefile.bd32 + Cosmetic changes in pngtest.c + +Version 1.0.5q [February 5, 2000] + Relocated the makefile.solaris warning about PATH problems. + Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) + Revised makefile.gcmmx + Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros + +Version 1.0.5r [February 7, 2000] + Removed superfluous prototype for png_get_itxt from png.h + Fixed a bug in pngrtran.c that improperly expanded the background color. + Return *num_text=0 from png_get_text() when appropriate, and fix documentation + of png_get_text() in libpng.txt/libpng.3. + +Version 1.0.5s [February 18, 2000] + Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the + new error handler that's planned for the next libpng release, and changed + example.c, pngtest.c, and contrib programs to use this macro. + Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) + Fixed a bug in png_read_png() that caused it to fail to expand some images + that it should have expanded. + Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions + in pngget.c + Changed the allocation of palette, history, and trans arrays back to + the version 1.0.5 method (linking instead of copying) which restores + backward compatibility with version 1.0.5. Added some remarks about + that in example.c. Added "free_me" member to info_ptr and png_ptr + and added png_free_data() function. + Updated makefile.linux and makefile.gccmmx to make directories conditionally. + Made cosmetic changes to pngasmrd.h + Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). + Modified png_read_png() to allocate info_ptr->row_pointers only if it + hasn't already been allocated. + +Version 1.0.5t [March 4, 2000] + Changed png_jmp_env() migration aiding macro to png_jmpbuf(). + Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c + Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when + PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b + Files in contrib/gregbook were revised to use png_jmpbuf() and to select + a 24-bit visual if one is available, and to allow abbreviated options. + Files in contrib/pngminus were revised to use the png_jmpbuf() macro. + Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s + +Version 1.0.5u [March 5, 2000] + Simplified the code that detects old png.h in png.c and pngtest.c + Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) + Increased precision of rgb_to_gray calculations from 8 to 15 bits and + added png_set_rgb_to_gray_fixed() function. + Added makefile.bc32 (32-bit Borland C++, C mode) + +Version 1.0.5v [March 11, 2000] + Added some parentheses to the png_jmpbuf macro definition. + Updated references to the zlib home page, which has moved to freesoftware.com. + Corrected bugs in documentation regarding png_read_row() and png_write_row(). + Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. + Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, + revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) + +Version 1.0.6 [March 20, 2000] + Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c + Added makefile.sggcc (SGI IRIX with gcc) + +Version 1.0.6d [April 7, 2000] + Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO + Added data_length parameter to png_decompress_chunk() function + Revised documentation to remove reference to abandoned png_free_chnk functions + Fixed an error in png_rgb_to_gray_fixed() + Revised example.c, usage of png_destroy_write_struct(). + Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file + Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c + Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). + +Version 1.0.6e [April 9, 2000] + Added png_data_freer() function. + In the code that checks for over-length tRNS chunks, added check of + info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) + Minor revisions of libpng.txt/libpng.3. + Check for existing data and free it if the free_me flag is set, in png_set_*() + and png_handle_*(). + Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED + is defined. + Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c + and mentioned the purposes of the two macros in libpng.txt/libpng.3. + +Version 1.0.6f [April 14, 2000] + Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. + Add checks in png_set_text() for NULL members of the input text structure. + Revised libpng.txt/libpng.3. + Removed superfluous prototype for png_set_iTXt from png.h + Removed "else" from pngread.c, after png_error(), and changed "0" to "length". + Changed several png_errors about malformed ancillary chunks to png_warnings. + +Version 1.0.6g [April 24, 2000] + Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. + Relocated paragraph about png_set_background() in libpng.3/libpng.txt + and other revisions (Matthias Benckmann) + Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and + png_ptr members to restore binary compatibility with libpng-1.0.5 + (breaks compatibility with libpng-1.0.6). + +Version 1.0.6h [April 24, 2000] + Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds + libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) + This is a temporary change for test purposes. + +Version 1.0.6i [May 2, 2000] + Rearranged some members at the end of png_info and png_struct, to put + unknown_chunks_num and free_me within the original size of the png_structs + and free_me, png_read_user_fn, and png_free_fn within the original png_info, + because some old applications allocate the structs directly instead of + using png_create_*(). + Added documentation of user memory functions in libpng.txt/libpng.3 + Modified png_read_png so that it will use user_allocated row_pointers + if present, unless free_me directs that it be freed, and added description + of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. + Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version + 1.00) members of png_struct and png_info, to regain binary compatibility + when you define this macro. Capabilities lost in this event + are user transforms (new in version 1.0.0),the user transform pointer + (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, + the high-level interface, and unknown chunks support (all new in 1.0.6). + This was necessary because of old applications that allocate the structs + directly as authors were instructed to do in libpng-0.88 and earlier, + instead of using png_create_*(). + Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which + can be used to detect codes that directly allocate the structs, and + code to check these modes in png_read_init() and png_write_init() and + generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED + was not defined. + Added makefile.intel and updated makefile.watcom (Pawel Mrochen) + +Version 1.0.6j [May 3, 2000] + Overloaded png_read_init() and png_write_init() with macros that convert + calls to png_read_init_2() or png_write_init_2() that check the version + and structure sizes. + +Version 1.0.7beta11 [May 7, 2000] + Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes + which are no longer used. + Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is + defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED + is defined. + Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory + overrun when old applications fill the info_ptr->text structure directly. + Added PNGAPI macro, and added it to the definitions of all exported functions. + Relocated version macro definitions ahead of the includes of zlib.h and + pngconf.h in png.h. + +Version 1.0.7beta12 [May 12, 2000] + Revised pngset.c to avoid a problem with expanding the png_debug macro. + Deleted some extraneous defines from pngconf.h + Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. + Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. + Added png_access_version_number() function. + Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). + Expanded libpng.3/libpng.txt information about png_data_freer(). + +Version 1.0.7beta14 [May 17, 2000] (beta13 was not published) + Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as + warnings instead of errors, as pngrutil.c does. + Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() + will actually write IDATs. + Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. + Make png_free_data() ignore its final parameter except when freeing data + that can have multiple instances (text, sPLT, unknowns). + Fixed a new bug in png_set_rows(). + Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. + Added png_set_invalid() function. + Fixed incorrect illustrations of png_destroy_write_struct() in example.c. + +Version 1.0.7beta15 [May 30, 2000] + Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce + fewer error messages. + Rearranged checks for Z_OK to check the most likely path first in pngpread.c + and pngwutil.c. + Added checks in pngtest.c for png_create_*() returning NULL, and mentioned + in libpng.txt/libpng.3 the need for applications to check this. + Changed names of png_default_*() functions in pngtest to pngtest_*(). + Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. + Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c + Set each pointer to NULL after freeing it in png_free_data(). + Worked around a problem in pngconf.h; AIX's strings.h defines an "index" + macro that conflicts with libpng's png_color_16.index. (Dimitri + Papadapoulos) + Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). + +Version 1.0.7beta16 [June 4, 2000] + Revised the workaround of AIX string.h "index" bug. + Added a check for overlength PLTE chunk in pngrutil.c. + Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer + indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. + Added a warning in png_decompress_chunk() when it runs out of data, e.g. + when it tries to read an erroneous PhotoShop iCCP chunk. + Added PNG_USE_DLL macro. + Revised the copyright/disclaimer/license notice. + Added contrib/msvctest directory + +Version 1.0.7rc1 [June 9, 2000] + Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) + Added contrib/visupng directory (Willem van Schaik) + +Version 1.0.7beta18 [June 23, 2000] + Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ + and do not redefine PNGAPI if it is passed in via a compiler directive. + Revised visupng/PngFile.c to remove returns from within the Try block. + Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. + Updated contrib/visupng/cexcept.h to version 1.0.0. + Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. + +Version 1.0.7rc2 [June 28, 2000] + Updated license to include disclaimers required by UCITA. + Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. + +Version 1.0.7 [July 1, 2000] + Revised the definition of "trans_values" in libpng.3/libpng.txt + +Version 1.0.8beta1 [July 8, 2000] + Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. + Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and + pngwutil.c. + Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. + Removed unused "#include " from png.c + Added WindowsCE support. + Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. + +Version 1.0.8beta2 [July 10, 2000] + Added project files to the wince directory and made further revisions + of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. + +Version 1.0.8beta3 [July 11, 2000] + Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() + for indexed-color input files to avoid potential double-freeing trans array + under some unusual conditions; problem was introduced in version 1.0.6f. + Further revisions to pngtest.c and files in the wince subdirectory. + +Version 1.0.8beta4 [July 14, 2000] + Added the files pngbar.png and pngbar.jpg to the distribution. + Added makefile.cygwin, and cygwin support in pngconf.h + Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) + +Version 1.0.8rc1 [July 16, 2000] + Revised png_debug() macros and statements to eliminate compiler warnings. + +Version 1.0.8 [July 24, 2000] + Added png_flush() in pngwrite.c, after png_write_IEND(). + Updated makefile.hpux to build a shared library. + +Version 1.0.9beta1 [November 10, 2000] + Fixed typo in scripts/makefile.hpux + Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) + Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) + Changed "cdrom.com" in documentation to "libpng.org" + Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). + Changed type of "params" from voidp to png_voidp in png_read|write_png(). + Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. + Revised the 3 instances of WRITEFILE in pngtest.c. + Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. + Updated png.rc in dll/msvc project + Revised makefile.dec to define and use LIBPATH and INCPATH + Increased size of global png_libpng_ver[] array from 12 to 18 chars. + Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. + Removed duplicate png_crc_finish() from png_handle_bKGD() function. + Added a warning when application calls png_read_update_info() multiple times. + Revised makefile.cygwin + Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. + Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). + +Version 1.0.9beta2 [November 19, 2000] + Renamed the "dll" subdirectory "projects". + Added borland project files to "projects" subdirectory. + Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. + Add error message in png_set_compression_buffer_size() when malloc fails. + +Version 1.0.9beta3 [November 23, 2000] + Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. + Removed the png_flush() in pngwrite.c that crashes some applications + that don't set png_output_flush_fn. + Added makefile.macosx and makefile.aix to scripts directory. + +Version 1.0.9beta4 [December 1, 2000] + Change png_chunk_warning to png_warning in png_check_keyword(). + Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). + +Version 1.0.9beta5 [December 15, 2000] + Added support for filter method 64 (for PNG datastreams embedded in MNG). + +Version 1.0.9beta6 [December 18, 2000] + Revised png_set_filter() to accept filter method 64 when appropriate. + Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to + help prevent applications from using MNG features in PNG datastreams. + Added png_permit_mng_features() function. + Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". + +Version 1.0.9rc1 [December 23, 2000] + Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c + Fixed error handling of unknown compression type in png_decompress_chunk(). + In pngconf.h, define __cdecl when _MSC_VER is defined. + +Version 1.0.9beta7 [December 28, 2000] + Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. + Revised memory management in png_set_hIST and png_handle_hIST in a backward + compatible manner. PLTE and tRNS were revised similarly. + Revised the iCCP chunk reader to ignore trailing garbage. + +Version 1.0.9beta8 [January 12, 2001] + Moved pngasmrd.h into pngconf.h. + Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. + +Version 1.0.9beta9 [January 15, 2001] + Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to + wince and msvc project module definition files. + Minor revision of makefile.cygwin. + Fixed bug with progressive reading of narrow interlaced images in pngpread.c + +Version 1.0.9beta10 [January 16, 2001] + Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. + Fixed "png_mmx_supported" typo in project definition files. + +Version 1.0.9beta11 [January 19, 2001] + Updated makefile.sgi to make shared library. + Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED + by default, for the benefit of DLL forward compatibility. These will + be re-enabled in version 1.2.0. + +Version 1.0.9rc2 [January 22, 2001] + Revised cygwin support. + +Version 1.0.9 [January 31, 2001] + Added check of cygwin's ALL_STATIC in pngconf.h + Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. + +Version 1.0.10beta1 [March 14, 2001] + Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. + Reformatted libpng.3 to eliminate bad line breaks. + Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c + Added prototype for png_mmx_support() near the top of pnggccrd.c + Moved some error checking from png_handle_IHDR to png_set_IHDR. + Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. + Revised png_mmx_support() function in pnggccrd.c + Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c + Fixed memory leak in contrib/visupng/PngFile.c + Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) + Added warnings when retrieving or setting gamma=0. + Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). + +Version 1.0.10rc1 [March 23, 2001] + Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, + and png_strlen. + Revised png_mmx_supported() function in pnggccrd.c to return proper value. + Fixed bug in progressive reading (pngpread.c) with small images (height < 8). + +Version 1.0.10 [March 30, 2001] + Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin + Added beos project files (Chris Herborth) + +Version 1.0.11beta1 [April 3, 2001] + Added type casts on several png_malloc() calls (Dimitri Papadapoulos). + Removed a no-longer needed AIX work-around from pngconf.h + Changed several "//" single-line comments to C-style in pnggccrd.c + +Version 1.0.11beta2 [April 11, 2001] + Removed PNGAPI from several functions whose prototypes did not have PNGAPI. + Updated scripts/pngos2.def + +Version 1.0.11beta3 [April 14, 2001] + Added checking the results of many instances of png_malloc() for NULL + +Version 1.0.11beta4 [April 20, 2001] + Undid the changes from version 1.0.11beta3. Added a check for NULL return + from user's malloc_fn(). + Removed some useless type casts of the NULL pointer. + Added makefile.netbsd + +Version 1.0.11 [April 27, 2001] + Revised makefile.netbsd + +Version 1.0.12beta1 [May 14, 2001] + Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) + Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h + Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. + Eliminated the png_error about apps using png_read|write_init(). Instead, + libpng will reallocate the png_struct and info_struct if they are too small. + This retains future binary compatibility for old applications written for + libpng-0.88 and earlier. + +Version 1.2.0beta1 [May 6, 2001] + Bumped DLLNUM to 2. + Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED + by default. + Added runtime selection of MMX features. + Added png_set_strip_error_numbers function and related macros. + +Version 1.2.0beta2 [May 7, 2001] + Finished merging 1.2.0beta1 with version 1.0.11 + Added a check for attempts to read or write PLTE in grayscale PNG datastreams. + +Version 1.2.0beta3 [May 17, 2001] + Enabled user memory function by default. + Modified png_create_struct so it passes user mem_ptr to user memory allocator. + Increased png_mng_features flag from png_byte to png_uint_32. + Bumped shared-library (so-number) and dll-number to 3. + +Version 1.2.0beta4 [June 23, 2001] + Check for missing profile length field in iCCP chunk and free chunk_data + in case of truncated iCCP chunk. + Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc + Bumped dll-number from 2 to 3 in makefile.cygwin + Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly + if user attempts to run it on an 8-bit display. + Updated contrib/gregbook + Use png_malloc instead of png_zalloc to allocate palette in pngset.c + Updated makefile.ibmc + Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes + of png_write_oFFS width and height from png_uint_32 to png_int_32. + Updated example.c + Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c + +Version 1.2.0beta5 [August 8, 2001] + Revised contrib/gregbook + Revised makefile.gcmmx + Revised pnggccrd.c to conditionally compile some thread-unsafe code only + when PNG_THREAD_UNSAFE_OK is defined. + Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with + value exceeding 2^bit_depth-1 + Revised makefile.sgi and makefile.sggcc + Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c + Removed restriction that do_invert_mono only operate on 1-bit opaque files + +Version 1.2.0 [September 1, 2001] + Changed a png_warning() to png_debug() in pnggccrd.c + Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). + +Version 1.2.1beta1 [October 19, 2001] + Revised makefile.std in contrib/pngminus + Include background_1 in png_struct regardless of gamma support. + Revised makefile.netbsd and makefile.macosx, added makefile.darwin. + Revised example.c to provide more details about using row_callback(). + +Version 1.2.1beta2 [October 25, 2001] + Added type cast to each NULL appearing in a function call, except for + WINCE functions. + Added makefile.so9. + +Version 1.2.1beta3 [October 27, 2001] + Removed type casts from all NULLs. + Simplified png_create_struct_2(). + +Version 1.2.1beta4 [November 7, 2001] + Revised png_create_info_struct() and png_creat_struct_2(). + Added error message if png_write_info() was omitted. + Type cast NULLs appearing in function calls when _NO_PROTO or + PNG_TYPECAST_NULL is defined. + +Version 1.2.1rc1 [November 24, 2001] + Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL + is defined. + Changed typecast of "size" argument to png_size_t in pngmem.c calls to + the user malloc_fn, to agree with the prototype in png.h + Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) + Updated makefile.sgi to recognize LIBPATH and INCPATH. + Updated various makefiles so "make clean" does not remove previous major + version of the shared library. + +Version 1.2.1rc2 [December 4, 2001] + Always allocate 256-entry internal palette, hist, and trans arrays, to + avoid out-of-bounds memory reference caused by invalid PNG datastreams. + Added a check for prefix_length > data_length in iCCP chunk handler. + +Version 1.2.1 [December 7, 2001] + None. + +Version 1.2.2beta1 [February 22, 2002] + Fixed a bug with reading the length of iCCP profiles (Larry Reeves). + Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate + libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h + Revised makefile.darwin to remove "-undefined suppress" option. + Added checks for gamma and chromaticity values over 21474.83, which exceed + the limit for PNG unsigned 32-bit integers when encoded. + Revised calls to png_create_read_struct() and png_create_write_struct() + for simpler debugging. + Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) + +Version 1.2.2beta2 [February 23, 2002] + Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. + Check for invalid image dimensions in png_get_IHDR. + Added missing "fi;" in the install target of the SGI makefiles. + Added install-static to all makefiles that make shared libraries. + Always do gamma compensation when image is partially transparent. + +Version 1.2.2beta3 [March 7, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later. + Modified shared-library makefiles to install pkgconfig/libpngNN.pc. + Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown + Removed unused png_write_destroy_info prototype from png.h + Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case + Added install-shared target to all makefiles that make shared libraries. + Stopped a double free of palette, hist, and trans when not using free_me. + Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. + +Version 1.2.2beta4 [March 8, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later (Jason Summers). + Relocated a misplaced /bin/rm in the "install-shared" makefile targets + Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. + +Version 1.2.2beta5 [March 26, 2002] + Added missing PNGAPI to several function definitions. + Check for invalid bit_depth or color_type in png_get_IHDR(), and + check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). + Revised iTXt support to accept NULL for lang and lang_key. + Compute gamma for color components of background even when color_type is gray. + Changed "()" to "{}" in scripts/libpng.pc.in. + Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN + Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so + +Version 1.2.2beta6 [March 31, 2002] + +Version 1.0.13beta1 [March 31, 2002] + Prevent png_zalloc() from trying to memset memory that it failed to acquire. + Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). + Ensure that the right function (user or default) is used to free the + png_struct after an error in png_create_read_struct_2(). + +Version 1.2.2rc1 [April 7, 2002] + +Version 1.0.13rc1 [April 7, 2002] + Save the ebx register in pnggccrd.c (Sami Farin) + Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). + Updated makefiles to put headers in include/libpng and remove old include/*.h. + +Version 1.2.2 [April 15, 2002] + +Version 1.0.13 [April 15, 2002] + Revised description of png_set_filter() in libpng.3/libpng.txt. + Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd + +Version 1.0.13patch01 [April 17, 2002] + +Version 1.2.2patch01 [April 17, 2002] + Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and + makefile.sggcc + Fixed VER -> PNGVER typo in makefile.macosx and added install-static to + install + Added install: target to makefile.32sunu and makefile.64sunu + +Version 1.0.13patch03 [April 18, 2002] + +Version 1.2.2patch03 [April 18, 2002] + Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng + subdirectory to libpngNN subdirectory without the full pathname. + Moved generation of libpng.pc from "install" to "all" in 15 makefiles. + +Version 1.2.3rc1 [April 28, 2002] + Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). + Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) + Fixed bug with $prefix, should be $(prefix) in makefile.hpux. + Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin + Added a link from libpngNN.pc to libpng.pc in 15 makefiles. + Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. + Revised makefile.darwin to make relative links without full pathname. + Added setjmp() at the end of png_create_*_struct_2() in case user forgets + to put one in their application. + Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and + removed them from module definition files. + +Version 1.2.3rc2 [May 1, 2002] + Fixed bug in reporting number of channels in pngget.c and pngset.c, + that was introduced in version 1.2.2beta5. + Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), + png_default_flush(), and png_push_fill_buffer() and included them in + module definition files. + Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. + +Version 1.2.3rc3 [May 1, 2002] + Revised prototype for png_default_flush() + Remove old libpng.pc and libpngNN.pc before installing new ones. + +Version 1.2.3rc4 [May 2, 2002] + Typos in *.def files (png_default_read|write -> png_default_read|write_data) + In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc + Added libpng-config and libpngNN-config and modified makefiles to install + them. + Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles + Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp + +Version 1.2.3rc5 [May 11, 2002] + Changed "error" and "message" in prototypes to "error_message" and + "warning_message" to avoid namespace conflict. + Revised 15 makefiles to build libpng-config from libpng-config-*.in + Once more restored png_zalloc and png_zfree to regular nonexported form. + Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer + to nonexported form, but with PNGAPI, and removed them from module def + files. + +Version 1.2.3rc6 [May 14, 2002] + Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c + Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. + Removed leftover libpng-config "sed" script from four makefiles. + Revised libpng-config creating script in 16 makefiles. + +Version 1.2.3 [May 22, 2002] + Revised libpng-config target in makefile.cygwin. + Removed description of png_set_mem_fn() from documentation. + Revised makefile.freebsd. + Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). + Revised projects/msvc/README.txt + Changed -lpng to -lpngNN in LDFLAGS in several makefiles. + +Version 1.2.4beta1 [May 24, 2002] + Added libpng.pc and libpng-config to "all:" target in 16 makefiles. + Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) + Added missing "\" before closing double quote in makefile.gcmmx. + Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() + functions. + +Version 1.2.4beta2 [June 25, 2002] + Plugged memory leak of png_ptr->current_text (Matt Holgate). + Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) + Added -soname to the loader flags in makefile.dec, makefile.sgi, and + makefile.sggcc. + Added "test-installed" target to makefile.linux, makefile.gcmmx, + makefile.sgi, and makefile.sggcc. + +Version 1.2.4beta3 [June 28, 2002] + Plugged memory leak of row_buf in pngtest.c when there is a png_error(). + Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. + Added "test-installed" target to makefile.32sunu, makefile.64sunu, + makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, + makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. + +Version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] + Added "test-installed" target to makefile.cygwin and makefile.sco. + Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. + +Version 1.2.4 and 1.0.14 [July 8, 2002] + Changed png_warning() to png_error() when width is too large to process. + +Version 1.2.4patch01 [July 20, 2002] + Revised makefile.cygwin to use DLL number 12 instead of 13. + +Version 1.2.5beta1 [August 6, 2002] + Added code to contrib/gregbook/readpng2.c to ignore unused chunks. + Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) + Removed some stray *.o files from contrib/gregbook. + Changed png_error() to png_warning() about "Too much data" in pngpread.c + and about "Extra compressed data" in pngrutil.c. + Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). + Updated makefile.hpgcc + Updated png.c and pnggccrd.c handling of return from png_mmx_support() + +Version 1.2.5beta2 [August 15, 2002] + Only issue png_warning() about "Too much data" in pngpread.c when avail_in + is nonzero. + Updated makefiles to install a separate libpng.so.3 with its own rpath. + +Version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] + Revised makefiles to not remove previous minor versions of shared libraries. + +Version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] + Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared + library loader directive. + Added missing "$OBJSDLL" line to makefile.gcmmx. + Added missing "; fi" to makefile.32sunu. + +Version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] + Revised libpng-config script. + +Version 1.2.5 and 1.0.15 [October 3, 2002] + Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, + and makefile.aix. + Relocated two misplaced PNGAPI lines in pngtest.c + +Version 1.2.6beta1 [October 22, 2002] + Commented out warning about uninitialized mmx_support in pnggccrd.c. + Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. + Relocated two more misplaced PNGAPI lines in pngtest.c + Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, + introduced in version 1.0.2. + Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. + +Version 1.2.6beta2 [November 1, 2002] + Added libpng-config "--ldopts" output. + Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" + in makefiles. + +Version 1.2.6beta3 [July 18, 2004] + Reverted makefile changes from version 1.2.6beta2 and some of the changes + from version 1.2.6beta1; these will be postponed until version 1.2.7. + Version 1.2.6 is going to be a simple bugfix release. + Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. + Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. + Added "#!/bin/sh" at the top of configure, for recognition of the + 'x' flag under Cygwin (Cosmin). + Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). + Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). + Fixed the special memory handler for Borland C under DOS, in pngmem.c + (Cosmin). + Removed some spurious assignments in pngrutil.c (Cosmin). + Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings + on 16-bit platforms (Cosmin). + Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). + Used proper type png_fixed_point, to avoid problems on 16-bit platforms, + in png_handle_sRGB() (Cosmin). + Added compression_type to png_struct, and optimized the window size + inside the deflate stream (Cosmin). + Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). + Fixed handling of unknown chunks that come after IDAT (Cosmin). + Allowed png_error() and png_warning() to work even if png_ptr == NULL + (Cosmin). + Replaced row_info->rowbytes with row_bytes in png_write_find_filter() + (Cosmin). + Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). + Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded + values in png.c (Simon-Pierre, Cosmin). + Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). + Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc + (Simon-Pierre). + Moved the definition of PNG_HEADER_VERSION_STRING near the definitions + of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). + Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). + Updated scripts/makefile.vc(a)win32 (Cosmin). + Updated the MSVC project (Simon-Pierre, Cosmin). + Updated the Borland C++ Builder project (Cosmin). + Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). + Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). + Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). + Added extra guard around inclusion of Turbo C memory headers, in pngconf.h + (Cosmin). + Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to + projects/cbuilder5/ (Cosmin). + Moved projects/visualc6/png32ms.def to scripts/pngw32.def, + and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). + Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). + Changed line endings to DOS style in cbuilder5 and visualc6 files, even + in the tar.* distributions (Cosmin). + Updated contrib/visupng/VisualPng.dsp (Cosmin). + Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). + Added a separate distribution with "configure" and supporting files (Junichi). + +Version 1.2.6beta4 [July 28, 2004] + Added user ability to change png_size_t via a PNG_SIZE_T macro. + Added png_sizeof() and png_convert_size() functions. + Added PNG_SIZE_MAX (maximum value of a png_size_t variable. + Added check in png_malloc_default() for (size_t)size != (png_uint_32)size + which would indicate an overflow. + Changed sPLT failure action from png_error to png_warning and abandon chunk. + Changed sCAL and iCCP failures from png_error to png_warning and abandon. + Added png_get_uint_31(png_ptr, buf) function. + Added PNG_UINT_32_MAX macro. + Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. + Made png_zalloc() issue a png_warning and return NULL on potential + overflow. + Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x + Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. + Revised Borland portion of png_malloc() to return NULL or issue + png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. + Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove + sequential read support. + Added some "#if PNG_WRITE_SUPPORTED" blocks. + Added #ifdef to remove some redundancy in png_malloc_default(). + Use png_malloc instead of png_zalloc to allocate the pallete. + +Version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] + Fixed buffer overflow vulnerability in png_handle_tRNS() + Fixed integer arithmetic overflow vulnerability in png_read_png(). + Fixed some harmless bugs in png_handle_sBIT, etc, that would cause + duplicate chunk types to go undetected. + Fixed some timestamps in the -config version + Rearranged order of processing of color types in png_handle_tRNS(). + Added ROWBYTES macro to calculate rowbytes without integer overflow. + Updated makefile.darwin and removed makefile.macosx from scripts directory. + Imposed default one million column, one-million row limits on the image + dimensions, and added png_set_user_limits() function to override them. + Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. + Fixed wrong cast of returns from png_get_user_width|height_max(). + Changed some "keep the compiler happy" from empty statements to returns, + Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution + +Version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] + Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. + Revised pngtest's png_debug_malloc() to use png_malloc() instead of + png_malloc_default() which is not supposed to be exported. + Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in + pngpread.c. Bug was introduced in 1.2.6rc1. + Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. + Fixed old bug in RGB to Gray transformation. + Fixed problem with 64-bit compilers by casting arguments to abs() + to png_int_32. + Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). + Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) + Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. + Added code to update the row_info->colortype in png_do_read_filler() (MSB). + +Version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] + Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid + trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. + Revised documentation of png_set_keep_unknown_chunks(). + Check handle_as_unknown status in pngpread.c, as in pngread.c previously. + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h + Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c + +Version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] + Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of + "pinfo" was out of place). + +Version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED + section of png.h where they were inadvertently placed in version rc3. + +Version 1.2.6 and 1.0.16 [August 15, 2004] + Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. + +Version 1.2.7beta1 [August 26, 2004] + Removed unused pngasmrd.h file. + Removed references to uu.net for archived files. Added references to + PNG Spec (second edition) and the PNG ISO/IEC Standard. + Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. + Fixed bug with "optimized window size" in the IDAT datastream, that + causes libpng to write PNG files with incorrect zlib header bytes. + +Version 1.2.7beta2 [August 28, 2004] + Fixed bug with sCAL chunk and big-endian machines (David Munro). + Undid new code added in 1.2.6rc2 to update the color_type in + png_set_filler(). + Added png_set_add_alpha() that updates color type. + +Version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] + Revised png_set_strip_filler() to not remove alpha if color_type has alpha. + +Version 1.2.7 and 1.0.17 [September 12, 2004] + Added makefile.hp64 + Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin + +Version 1.2.8beta1 [November 1, 2004] + Fixed bug in png_text_compress() that would fail to complete a large block. + Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during + strip alpha operation in png_do_strip_filler(). + Added PNG_1_2_X definition in pngconf.h + Use #ifdef to comment out png_info_init in png.c and png_read_init in + pngread.c (as of 1.3.0) + +Version 1.2.8beta2 [November 2, 2004] + Reduce color_type to a nonalpha type after strip alpha operation in + png_do_strip_filler(). + +Version 1.2.8beta3 [November 3, 2004] + Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM + +Version 1.2.8beta4 [November 12, 2004] + Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). + Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). + Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection + of data type in deflate (Cosmin). + Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. + +Version 1.2.8beta5 [November 20, 2004] + Use png_ptr->flags instead of png_ptr->transformations to pass + PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI + compatibility. + Revised handling of SPECIALBUILD, PRIVATEBUILD, + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. + +Version 1.2.8rc1 [November 24, 2004] + Moved handling of BUILD macros from pngconf.h to png.h + Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently + omitted from beta5. + Revised scripts/pngw32.rc + Despammed mailing addresses by masking "@" with "at". + Inadvertently installed a supposedly faster test version of pngrutil.c + +Version 1.2.8rc2 [November 26, 2004] + Added two missing "\" in png.h + Change tests in pngread.c and pngpread.c to + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +Version 1.2.8rc3 [November 28, 2004] + Reverted pngrutil.c to version libpng-1.2.8beta5. + Added scripts/makefile.elf with supporting code in pngconf.h for symbol + versioning (John Bowler). + +Version 1.2.8rc4 [November 29, 2004] + Added projects/visualc7 (Simon-pierre). + +Version 1.2.8rc5 [November 29, 2004] + Fixed new typo in scripts/pngw32.rc + +Version 1.2.8 [December 3, 2004] + Removed projects/visualc7, added projects/visualc71. + +Version 1.2.9beta1 [February 21, 2006] + Initialized some structure members in pngwutil.c to avoid gcc-4.0.0 complaints + Revised man page and libpng.txt to make it clear that one should not call + png_read_end or png_write_end after png_read_png or png_write_png. + Updated references to png-mng-implement mailing list. + Fixed an incorrect typecast in pngrutil.c + Added PNG_NO_READ_SUPPORTED conditional for making a write-only library. + Added PNG_NO_WRITE_INTERLACING_SUPPORTED conditional. + Optimized alpha-inversion loops in pngwtran.c + Moved test for nonzero gamma outside of png_build_gamma_table() in pngrtran.c + Make sure num_trans is <= 256 before copying data in png_set_tRNS(). + Make sure num_palette is <= 256 before copying data in png_set_PLTE(). + Interchanged order of write_swap_alpha and write_invert_alpha transforms. + Added parentheses in the definition of PNG_LIBPNG_BUILD_TYPE (Cosmin). + Optimized zlib window flag (CINFO) in contrib/pngsuite/*.png (Cosmin). + Updated scripts/makefile.bc32 for Borland C++ 5.6 (Cosmin). + Exported png_get_uint_32, png_save_uint_32, png_get_uint_16, png_save_uint_16, + png_get_int_32, png_save_int_32, png_get_uint_31 (Cosmin). + Added type cast (png_byte) in png_write_sCAL() (Cosmin). + Fixed scripts/makefile.cygwin (Christian Biesinger, Cosmin). + Default iTXt support was inadvertently enabled. + +Version 1.2.9beta2 [February 21, 2006] + Check for png_rgb_to_gray and png_gray_to_rgb read transformations before + checking for png_read_dither in pngrtran.c + Revised checking of chromaticity limits to accommodate extended RGB + colorspace (John Denker). + Changed line endings in some of the project files to CRLF, even in the + "Unix" tar distributions (Cosmin). + Made png_get_int_32 and png_save_int_32 always available (Cosmin). + Updated scripts/pngos2.def, scripts/pngw32.def and projects/wince/png32ce.def + with the newly exported functions. + Eliminated distributions without the "configure" script. + Updated INSTALL instructions. + +Version 1.2.9beta3 [February 24, 2006] + Fixed CRCRLF line endings in contrib/visupng/VisualPng.dsp + Made libpng.pc respect EXEC_PREFIX (D. P. Kreil, J. Bowler) + Removed reference to pngasmrd.h from Makefile.am + Renamed CHANGES to ChangeLog. + Renamed LICENSE to COPYING. + Renamed ANNOUNCE to NEWS. + Created AUTHORS file. + +Version 1.2.9beta4 [March 3, 2006] + Changed definition of PKGCONFIG from $prefix/lib to $libdir in configure.ac + Reverted to filenames LICENSE and ANNOUNCE; removed AUTHORS and COPYING. + Removed newline from the end of some error and warning messages. + Removed test for sqrt() from configure.ac and configure. + Made swap tables in pngtrans.c PNG_CONST (Carlo Bramix). + Disabled default iTXt support that was inadvertently enabled in + libpng-1.2.9beta1. + Added "OS2" to list of systems that don't need underscores, in pnggccrd.c + Removed libpng version and date from *.c files. + +Version 1.2.9beta5 [March 4, 2006] + Removed trailing blanks from source files. + Put version and date of latest change in each source file, and changed + copyright year accordingly. + More cleanup of configure.ac, Makefile.am, and associated scripts. + Restored scripts/makefile.elf which was inadvertently deleted. + +Version 1.2.9beta6 [March 6, 2006] + Fixed typo (RELEASE) in configuration files. + +Version 1.2.9beta7 [March 7, 2006] + Removed libpng.vers and libpng.sym from libpng12_la_SOURCES in Makefile.am + Fixed inconsistent #ifdef's around png_sig_bytes() and png_set_sCAL_s() + in png.h. + Updated makefile.elf as suggested by debian. + Made cosmetic changes to some makefiles, adding LN_SF and other macros. + Made some makefiles accept "exec_prefix". + +Version 1.2.9beta8 [March 9, 2006] + Fixed some "#if defined (..." which should be "#if defined(..." + Bug introduced in libpng-1.2.8. + Fixed inconsistency in definition of png_default_read_data() + Restored blank that was lost from makefile.sggcc "clean" target in beta7. + Revised calculation of "current" and "major" for irix in ltmain.sh + Changed "mkdir" to "MKDIR_P" in some makefiles. + Separated PNG_EXPAND and PNG_EXPAND_tRNS. + Added png_set_expand_gray_1_2_4_to_8() and deprecated + png_set_gray_1_2_4_to_8() which also expands tRNS to alpha. + +Version 1.2.9beta9 [March 10, 2006] + Include "config.h" in pngconf.h when available. + Added some checks for NULL png_ptr or NULL info_ptr (timeless) + +Version 1.2.9beta10 [March 20, 2006] + Removed extra CR from contrib/visualpng/VisualPng.dsw (Cosmin) + Made pnggccrd.c PIC-compliant (Christian Aichinger). + Added makefile.mingw (Wolfgang Glas). + Revised pngconf.h MMX checking. + +Version 1.2.9beta11 [March 22, 2006] + Fixed out-of-order declaration in pngwrite.c that was introduced in beta9 + Simplified some makefiles by using LIBSO, LIBSOMAJ, and LIBSOVER macros. + +Version 1.2.9rc1 [March 31, 2006] + Defined PNG_USER_PRIVATEBUILD when including "pngusr.h" (Cosmin). + Removed nonsensical assertion check from pngtest.c (Cosmin). + +Version 1.2.9 [April 14, 2006] + Revised makefile.beos and added "none" selector in ltmain.sh + +Version 1.2.10beta1 [April 15, 2006] + Renamed "config.h" to "png_conf.h" and revised Makefile.am to add + -DPNG_BUILDING_LIBPNG to compile directive, and modified pngconf.h + to include png_conf.h only when PNG_BUILDING_LIBPNG is defined. + +Version 1.2.10beta2 [April 15, 2006] + Manually updated Makefile.in and configure. Changed png_conf.h.in + back to config.h. + +Version 1.2.10beta3 [April 15, 2006] + Change png_conf.h back to config.h in pngconf.h. + +Version 1.2.10beta4 [April 16, 2006] + Change PNG_BUILDING_LIBPNG to PNG_CONFIGURE_LIBPNG in config/Makefile*. + +Version 1.2.10beta5 [April 16, 2006] + Added a configure check for compiling assembler code in pnggccrd.c + +Version 1.2.10beta6 [April 17, 2006] + Revised the configure check for pnggccrd.c + Moved -DPNG_CONFIGURE_LIBPNG into @LIBPNG_DEFINES@ + Added @LIBPNG_DEFINES@ to arguments when building libpng.sym + +Version 1.2.10beta7 [April 18, 2006] + Change "exec_prefix=$prefix" to "exec_prefix=$(prefix)" in makefiles. + +Version 1.2.10rc1 [April 19, 2006] + Ensure pngconf.h doesn't define both PNG_USE_PNGGCCRD and PNG_USE_PNGVCRD + Fixed "LN_FS" typo in makefile.sco and makefile.solaris. + +Version 1.2.10rc2 [April 20, 2006] + Added a backslash between -DPNG_CONFIGURE_LIBPNG and -DPNG_NO_ASSEMBLER_CODE + in configure.ac and configure + Made the configure warning about versioned symbols less arrogant. + +Version 1.2.10rc3 [April 21, 2006] + Added a note in libpng.txt that png_set_sig_bytes(8) can be used when + writing an embedded PNG without the 8-byte signature. + Revised makefiles and configure to avoid making links to libpng.so.* + +Version 1.2.10 [April 23, 2006] + Reverted configure to "rc2" state. + +Version 1.2.11beta1 [May 31, 2006] + scripts/libpng.pc.in contained "configure" style version info and would + not work with makefiles. + The shared-library makefiles were linking to libpng.so.0 instead of + libpng.so.3 compatibility as the library. + +Version 1.2.11beta2 [June 2, 2006] + Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + Fixed bug in example.c (png_set_palette_rgb -> png_set_palette_to_rgb) + +Version 1.2.11beta3 [June 5, 2006] + Prepended "#! /bin/sh" to ltmail.sh and contrib/pngminus/*.sh (Cosmin). + Removed the accidental leftover Makefile.in~ (Cosmin). + Avoided potential buffer overflow and optimized buffer in + png_write_sCAL(), png_write_sCAL_s() (Cosmin). + Removed the include directories and libraries from CFLAGS and LDFLAGS + in scripts/makefile.gcc (Nelson A. de Oliveira, Cosmin). + +Version 1.2.11beta4 [June 6, 2006] + Allow zero-length IDAT chunks after the entire zlib datastream, but not + after another intervening chunk type. + +Version 1.0.19rc1, 1.2.11rc1 [June 13, 2006] + Deleted extraneous square brackets from [config.h] in configure.ac + +Version 1.0.19rc2, 1.2.11rc2 [June 14, 2006] + Added prototypes for PNG_INCH_CONVERSIONS functions to png.h + Revised INSTALL and autogen.sh + Fixed typo in several makefiles (-W1 should be -Wl) + Added typedef for png_int_32 and png_uint_32 on 64-bit systems. + +Version 1.0.19rc3, 1.2.11rc3 [June 15, 2006] + Removed the new typedefs for 64-bit systems (delay until version 1.4.0) + Added one zero element to png_gamma_shift[] array in pngrtran.c to avoid + reading out of bounds. + +Version 1.0.19rc4, 1.2.11rc4 [June 15, 2006] + Really removed the new typedefs for 64-bit systems. + +Version 1.0.19rc5, 1.2.11rc5 [June 22, 2006] + Removed png_sig_bytes entry from scripts/pngw32.def + +Version 1.0.19, 1.2.11 [June 26, 2006] + None. + +Version 1.0.20, 1.2.12 [June 27, 2006] + Really increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + +Version 1.2.13beta1 [October 2, 2006] + Removed AC_FUNC_MALLOC from configure.ac + Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h + Change "logical" to "bitwise" throughout documentation. + Detect and fix attempt to write wrong iCCP profile length (CVE-2006-7244) + +Version 1.0.21, 1.2.13 [November 14, 2006] + Fix potential buffer overflow in sPLT chunk handler. + Fix Makefile.am to not try to link to noexistent files. + Check all exported functions for NULL png_ptr. + +Version 1.2.14beta1 [November 17, 2006] + Relocated three misplaced tests for NULL png_ptr. + Built Makefile.in with automake-1.9.6 instead of 1.9.2. + Build configure with autoconf-2.60 instead of 2.59 + +Version 1.2.14beta2 [November 17, 2006] + Added some typecasts in png_zalloc(). + +Version 1.2.14rc1 [November 20, 2006] + Changed "strtod" to "png_strtod" in pngrutil.c + +Version 1.0.22, 1.2.14 [November 27, 2006] + Added missing "$(srcdir)" in Makefile.am and Makefile.in + +Version 1.2.15beta1 [December 3, 2006] + Generated configure with autoconf-2.61 instead of 2.60 + Revised configure.ac to update libpng.pc and libpng-config. + +Version 1.2.15beta2 [December 3, 2006] + Always export MMX asm functions, just stubs if not building pnggccrd.c + +Version 1.2.15beta3 [December 4, 2006] + Add "png_bytep" typecast to profile while calculating length in pngwutil.c + +Version 1.2.15beta4 [December 7, 2006] + Added scripts/CMakeLists.txt + Changed PNG_NO_ASSEMBLER_CODE to PNG_NO_MMX_CODE in scripts, like 1.4.0beta + +Version 1.2.15beta5 [December 7, 2006] + Changed some instances of PNG_ASSEMBLER_* to PNG_MMX_* in pnggccrd.c + Revised scripts/CMakeLists.txt + +Version 1.2.15beta6 [December 13, 2006] + Revised scripts/CMakeLists.txt and configure.ac + +Version 1.2.15rc1 [December 18, 2006] + Revised scripts/CMakeLists.txt + +Version 1.2.15rc2 [December 21, 2006] + Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. + Added scripts/makefile.nommx + +Version 1.2.15rc3 [December 25, 2006] + Fixed shared library numbering error that was introduced in 1.2.15beta6. + +Version 1.2.15rc4 [December 27, 2006] + Fixed handling of rgb_to_gray when png_ptr->color.gray isn't set. + +Version 1.2.15rc5 [December 31, 2006] + Revised handling of rgb_to_gray. + +Version 1.2.15 [January 5, 2007] + Added some (unsigned long) typecasts in pngtest.c to avoid printing errors. + +Version 1.2.16beta1 [January 6, 2007] + Fix bugs in makefile.nommx + +Version 1.2.16beta2 [January 16, 2007] + Revised scripts/CMakeLists.txt + +Version 1.2.16 [January 31, 2007] + No changes. + +Version 1.2.17beta1 [March 6, 2007] + Revised scripts/CMakeLists.txt to install both shared and static libraries. + Deleted a redundant line from pngset.c. + +Version 1.2.17beta2 [April 26, 2007] + Relocated misplaced test for png_ptr == NULL in pngpread.c + Change "==" to "&" for testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN + flags. + Changed remaining instances of PNG_ASSEMBLER_* to PNG_MMX_* + Added pngerror() when write_IHDR fails in deflateInit2(). + Added "const" to some array declarations. + Mention examples of libpng usage in the libpng*.txt and libpng.3 documents. + +Version 1.2.17rc1 [May 4, 2007] + No changes. + +Version 1.2.17rc2 [May 8, 2007] + Moved several PNG_HAVE_* macros out of PNG_INTERNAL because applications + calling set_unknown_chunk_location() need them. + Changed transformation flag from PNG_EXPAND_tRNS to PNG_EXPAND in + png_set_expand_gray_1_2_4_to_8(). + Added png_ptr->unknown_chunk to hold working unknown chunk data, so it + can be free'ed in case of error. Revised unknown chunk handling in + pngrutil.c and pngpread.c to use this structure. + +Version 1.2.17rc3 [May 8, 2007] + Revised symbol-handling in configure script. + +Version 1.2.17rc4 [May 10, 2007] + Revised unknown chunk handling to avoid storing unknown critical chunks. + +Version 1.0.25 [May 15, 2007] +Version 1.2.17 [May 15, 2007] + Added "png_ptr->num_trans=0" before error return in png_handle_tRNS, + to eliminate a vulnerability (CVE-2007-2445, CERT VU#684664) + +Version 1.0.26 [May 15, 2007] +Version 1.2.18 [May 15, 2007] + Reverted the libpng-1.2.17rc3 change to symbol-handling in configure script + +Version 1.2.19beta1 [May 18, 2007] + Changed "const static" to "static PNG_CONST" everywhere, mostly undoing + change of libpng-1.2.17beta2. Changed other "const" to "PNG_CONST" + Changed some handling of unused parameters, to avoid compiler warnings. + "if (unused == NULL) return;" becomes "unused = unused". + +Version 1.2.19beta2 [May 18, 2007] + Only use the valid bits of tRNS value in png_do_expand() (Brian Cartier) + +Version 1.2.19beta3 [May 19, 2007] + Add some "png_byte" typecasts in png_check_keyword() and write new_key + instead of key in zTXt chunk (Kevin Ryde). + +Version 1.2.19beta4 [May 21, 2007] + Add png_snprintf() function and use it in place of sprint() for improved + defense against buffer overflows. + +Version 1.2.19beta5 [May 21, 2007] + Fixed png_handle_tRNS() to only use the valid bits of tRNS value. + Changed handling of more unused parameters, to avoid compiler warnings. + Removed some PNG_CONST in pngwutil.c to avoid compiler warnings. + +Version 1.2.19beta6 [May 22, 2007] + Added some #ifdef PNG_MMX_CODE_SUPPORTED where needed in pngvcrd.c + Added a special "_MSC_VER" case that defines png_snprintf to _snprintf + +Version 1.2.19beta7 [May 22, 2007] + Squelched png_squelch_warnings() in pnggccrd.c and added + an #ifdef PNG_MMX_CODE_SUPPORTED block around the declarations that caused + the warnings that png_squelch_warnings was squelching. + +Version 1.2.19beta8 [May 22, 2007] + Removed __MMX__ from test in pngconf.h. + +Version 1.2.19beta9 [May 23, 2007] + Made png_squelch_warnings() available via PNG_SQUELCH_WARNINGS macro. + Revised png_squelch_warnings() so it might work. + Updated makefile.sgcc and makefile.solaris; added makefile.solaris-x86. + +Version 1.2.19beta10 [May 24, 2007] + Resquelched png_squelch_warnings(), use "__attribute__((used))" instead. + +Version 1.4.0beta1 [April 20, 2006] + Enabled iTXt support (changes png_struct, thus requires so-number change). + Cleaned up PNG_ASSEMBLER_CODE_SUPPORTED vs PNG_MMX_CODE_SUPPORTED + Eliminated PNG_1_0_X and PNG_1_2_X macros. + Removed deprecated functions png_read_init, png_write_init, png_info_init, + png_permit_empty_plte, png_set_gray_1_2_4_to_8, png_check_sig, and + removed the deprecated macro PNG_MAX_UINT. + Moved "PNG_INTERNAL" parts of png.h and pngconf.h into pngintrn.h + Removed many WIN32_WCE #ifdefs (Cosmin). + Reduced dependency on C-runtime library when on Windows (Simon-Pierre) + Replaced sprintf() with png_sprintf() (Simon-Pierre) + +Version 1.4.0beta2 [April 20, 2006] + Revised makefiles and configure to avoid making links to libpng.so.* + Moved some leftover MMX-related defines from pngconf.h to pngintrn.h + Updated scripts/pngos2.def, pngw32.def, and projects/wince/png32ce.def + +Version 1.4.0beta3 [May 10, 2006] + Updated scripts/pngw32.def to comment out MMX functions. + Added PNG_NO_GET_INT_32 and PNG_NO_SAVE_INT_32 macros. + Scripts/libpng.pc.in contained "configure" style version info and would + not work with makefiles. + Revised pngconf.h and added pngconf.h.in, so makefiles and configure can + pass defines to libpng and applications. + +Version 1.4.0beta4 [May 11, 2006] + Revised configure.ac, Makefile.am, and many of the makefiles to write + their defines in pngconf.h. + +Version 1.4.0beta5 [May 15, 2006] + Added a missing semicolon in Makefile.am and Makefile.in + Deleted extraneous square brackets from configure.ac + +Version 1.4.0beta6 [June 2, 2006] + Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + Changed sonum from 0 to 1. + Removed unused prototype for png_check_sig() from png.h + +Version 1.4.0beta7 [June 16, 2006] + Exported png_write_sig (Cosmin). + Optimized buffer in png_handle_cHRM() (Cosmin). + Set pHYs = 2835 x 2835 pixels per meter, and added + sCAL = 0.352778e-3 x 0.352778e-3 meters, in pngtest.png (Cosmin). + Added png_set_benign_errors(), png_benign_error(), png_chunk_benign_error(). + Added typedef for png_int_32 and png_uint_32 on 64-bit systems. + Added "(unsigned long)" typecast on png_uint_32 variables in printf lists. + +Version 1.4.0beta8 [June 22, 2006] + Added demonstration of user chunk support in pngtest.c, to support the + public sTER chunk and a private vpAg chunk. + +Version 1.4.0beta9 [July 3, 2006] + Removed ordinals from scripts/pngw32.def and removed png_info_int and + png_set_gray_1_2_4_to_8 entries. + Inline call of png_get_uint_32() in png_get_uint_31(). + Use png_get_uint_31() to get vpAg width and height in pngtest.c + Removed WINCE and Netware projects. + Removed standalone Y2KINFO file. + +Version 1.4.0beta10 [July 12, 2006] + Eliminated automatic copy of pngconf.h to pngconf.h.in from configure and + some makefiles, because it was not working reliably. Instead, distribute + pngconf.h.in along with pngconf.h and cause configure and some of the + makefiles to update pngconf.h from pngconf.h.in. + Added pngconf.h to DEPENDENCIES in Makefile.am + +Version 1.4.0beta11 [August 19, 2006] + Removed AC_FUNC_MALLOC from configure.ac. + Added a warning when writing iCCP profile with mismatched profile length. + Patched pnggccrd.c to assemble on x86_64 platforms. + Moved chunk header reading into a separate function png_read_chunk_header() + in pngrutil.c. The chunk header (len+sig) is now serialized in a single + operation (Cosmin). + Implemented support for I/O states. Added png_ptr member io_state, and + functions png_get_io_chunk_name() and png_get_io_state() in pngget.c + (Cosmin). + Added png_get_io_chunk_name and png_get_io_state to scripts/*.def (Cosmin). + Renamed scripts/pngw32.* to scripts/pngwin.* (Cosmin). + Removed the include directories and libraries from CFLAGS and LDFLAGS + in scripts/makefile.gcc (Cosmin). + Used png_save_uint_32() to set vpAg width and height in pngtest.c (Cosmin). + Cast to proper type when getting/setting vpAg units in pngtest.c (Cosmin). + Added pngintrn.h to the Visual C++ projects (Cosmin). + Removed scripts/list (Cosmin). + Updated copyright year in scripts/pngwin.def (Cosmin). + Removed PNG_TYPECAST_NULL and used standard NULL consistently (Cosmin). + Disallowed the user to redefine png_size_t, and enforced a consistent use + of png_size_t across libpng (Cosmin). + Changed the type of png_ptr->rowbytes, PNG_ROWBYTES() and friends + to png_size_t (Cosmin). + Removed png_convert_size() and replaced png_sizeof with sizeof (Cosmin). + Removed some unnecessary type casts (Cosmin). + Changed prototype of png_get_compression_buffer_size() and + png_set_compression_buffer_size() to work with png_size_t instead of + png_uint_32 (Cosmin). + Removed png_memcpy_check() and png_memset_check() (Cosmin). + Fixed a typo (png_byte --> png_bytep) in libpng.3 and libpng.txt (Cosmin). + Clarified that png_zalloc() does not clear the allocated memory, + and png_zalloc() and png_zfree() cannot be PNGAPI (Cosmin). + Renamed png_mem_size_t to png_alloc_size_t, fixed its definition in + pngconf.h, and used it in all memory allocation functions (Cosmin). + Renamed pngintrn.h to pngpriv.h, added a comment at the top of the file + mentioning that the symbols declared in that file are private, and + updated the scripts and the Visual C++ projects accordingly (Cosmin). + Removed circular references between pngconf.h and pngconf.h.in in + scripts/makefile.vc*win32 (Cosmin). + Removing trailing '.' from the warning and error messages (Cosmin). + Added pngdefs.h that is built by makefile or configure, instead of + pngconf.h.in (Glenn). + Detect and fix attempt to write wrong iCCP profile length. + +Version 1.4.0beta12 [October 19, 2006] + Changed "logical" to "bitwise" in the documentation. + Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h + Add a typecast to stifle compiler warning in pngrutil.c + +Version 1.4.0beta13 [November 10, 2006] + Fix potential buffer overflow in sPLT chunk handler. + Fix Makefile.am to not try to link to noexistent files. + +Version 1.4.0beta14 [November 15, 2006] + Check all exported functions for NULL png_ptr. + +Version 1.4.0beta15 [November 17, 2006] + Relocated two misplaced tests for NULL png_ptr. + Built Makefile.in with automake-1.9.6 instead of 1.9.2. + Build configure with autoconf-2.60 instead of 2.59 + Add "install: all" in Makefile.am so "configure; make install" will work. + +Version 1.4.0beta16 [November 17, 2006] + Added a typecast in png_zalloc(). + +Version 1.4.0beta17 [December 4, 2006] + Changed "new_key[79] = '\0';" to "(*new_key)[79] = '\0';" in pngwutil.c + Add "png_bytep" typecast to profile while calculating length in pngwutil.c + +Version 1.4.0beta18 [December 7, 2006] + Added scripts/CMakeLists.txt + +Version 1.4.0beta19 [May 16, 2007] + Revised scripts/CMakeLists.txt + Rebuilt configure and Makefile.in with newer tools. + Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. + Added scripts/makefile.nommx + +Version 1.4.0beta20 [July 9, 2008] + Moved several PNG_HAVE_* macros from pngpriv.h to png.h because applications + calling set_unknown_chunk_location() need them. + Moved several macro definitions from pngpriv.h to pngconf.h + Merge with changes to the 1.2.X branch, as of 1.2.30beta04. + Deleted all use of the MMX assembler code and Intel-licensed optimizations. + Revised makefile.mingw + +Version 1.4.0beta21 [July 21, 2008] + Moved local array "chunkdata" from pngrutil.c to the png_struct, so + it will be freed by png_read_destroy() in case of a read error (Kurt + Christensen). + +Version 1.4.0beta22 [July 21, 2008] + Change "purpose" and "buffer" to png_ptr->chunkdata to avoid memory leaking. + +Version 1.4.0beta23 [July 22, 2008] + Change "chunkdata = NULL" to "png_ptr->chunkdata = NULL" several places in + png_decompress_chunk(). + +Version 1.4.0beta24 [July 25, 2008] + Change all remaining "chunkdata" to "png_ptr->chunkdata" in + png_decompress_chunk(), and remove "chunkdata" from parameter list. + Put a call to png_check_chunk_name() in png_read_chunk_header(). + Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. + Removed two calls to png_check_chunk_name() occuring later in the process. + Define PNG_NO_ERROR_NUMBERS by default in pngconf.h + +Version 1.4.0beta25 [July 30, 2008] + Added a call to png_check_chunk_name() in pngpread.c + Reverted png_check_chunk_name() to accept a name with a lowercase 3rd byte. + Added png_push_have_buffer() function to pngpread.c + Eliminated PNG_BIG_ENDIAN_SUPPORTED and associated png_get_* macros. + Made inline expansion of png_get_*() optional with PNG_USE_READ_MACROS. + Eliminated all PNG_USELESS_TESTS and PNG_CORRECT_PALETTE_SUPPORTED code. + Synced contrib directory and configure files with libpng-1.2.30beta06. + Eliminated no-longer-used pngdefs.h (but it's still built in the makefiles) + Relocated a misplaced "#endif /* PNG_NO_WRITE_FILTER */" in pngwutil.c + +Version 1.4.0beta26 [August 4, 2008] + Removed png_push_have_buffer() function in pngpread.c. It increased the + compiled library size slightly. + Changed "-Wall" to "-W -Wall" in the CFLAGS in all makefiles (Cosmin Truta) + Declared png_ptr "volatile" in pngread.c and pngwrite.c to avoid warnings. + Updated contrib/visupng/cexcept.h to version 2.0.1 + Added PNG_LITERAL_CHARACTER macros for #, [, and ]. + +Version 1.4.0beta27 [August 5, 2008] + Revised usage of PNG_LITERAL_SHARP in pngerror.c. + Moved newline character from individual png_debug messages into the + png_debug macros. + Allow user to #define their own png_debug, png_debug1, and png_debug2. + +Version 1.4.0beta28 [August 5, 2008] + Revised usage of PNG_LITERAL_SHARP in pngerror.c. + Added PNG_STRING_NEWLINE macro + +Version 1.4.0beta29 [August 9, 2008] + Revised usage of PNG_STRING_NEWLINE to work on non-ISO compilers. + Added PNG_STRING_COPYRIGHT macro. + Added non-ISO versions of png_debug macros. + +Version 1.4.0beta30 [August 14, 2008] + Added premultiplied alpha feature (Volker Wiendl). + +Version 1.4.0beta31 [August 18, 2008] + Moved png_set_premultiply_alpha from pngtrans.c to pngrtran.c + Removed extra crc check at the end of png_handle_cHRM(). Bug introduced + in libpng-1.4.0beta20. + +Version 1.4.0beta32 [August 19, 2008] + Added PNG_WRITE_FLUSH_SUPPORTED block around new png_flush() call. + Revised PNG_NO_STDIO version of png_write_flush() + +Version 1.4.0beta33 [August 20, 2008] + Added png_get|set_chunk_cache_max() to limit the total number of sPLT, + text, and unknown chunks that can be stored. + +Version 1.4.0beta34 [September 6, 2008] + Shortened tIME_string to 29 bytes in pngtest.c + Fixed off-by-one error introduced in png_push_read_zTXt() function in + libpng-1.2.30beta04/pngpread.c (Harald van Dijk) + +Version 1.4.0beta35 [October 6, 2008] + Changed "trans_values" to "trans_color". + Changed so-number from 0 to 14. Some OS do not like 0. + Revised makefile.darwin to fix shared library numbering. + Change png_set_gray_1_2_4_to_8() to png_set_expand_gray_1_2_4_to_8() + in example.c (debian bug report) + +Version 1.4.0beta36 [October 25, 2008] + Sync with tEXt vulnerability fix in libpng-1.2.33rc02. + +Version 1.4.0beta37 [November 13, 2008] + Added png_check_cHRM in png.c and moved checking from pngget.c, pngrutil.c, + and pngwrite.c + +Version 1.4.0beta38 [November 22, 2008] + Added check for zero-area RGB cHRM triangle in png_check_cHRM() and + png_check_cHRM_fixed(). + +Version 1.4.0beta39 [November 23, 2008] + Revised png_warning() to write its message on standard output by default + when warning_fn is NULL. + +Version 1.4.0beta40 [November 24, 2008] + Eliminated png_check_cHRM(). Instead, always use png_check_cHRM_fixed(). + In png_check_cHRM_fixed(), ensure white_y is > 0, and removed redundant + check for all-zero coordinates that is detected by the triangle check. + +Version 1.4.0beta41 [November 26, 2008] + Fixed string vs pointer-to-string error in png_check_keyword(). + Rearranged test expressions in png_check_cHRM_fixed() to avoid internal + overflows. + Added PNG_NO_CHECK_cHRM conditional. + +Version 1.4.0beta42, 43 [December 1, 2008] + Merge png_debug with version 1.2.34beta04. + +Version 1.4.0beta44 [December 6, 2008] + Removed redundant check for key==NULL before calling png_check_keyword() + to ensure that new_key gets initialized and removed extra warning + (Merge with version 1.2.34beta05 -- Arvan Pritchard). + +Version 1.4.0beta45 [December 9, 2008] + In png_write_png(), respect the placement of the filler bytes in an earlier + call to png_set_filler() (Jim Barry). + +Version 1.4.0beta46 [December 10, 2008] + Undid previous change and added PNG_TRANSFORM_STRIP_FILLER_BEFORE and + PNG_TRANSFORM_STRIP_FILLER_AFTER conditionals and deprecated + PNG_TRANSFORM_STRIP_FILLER (Jim Barry). + +Version 1.4.0beta47 [December 15, 2008] + Support for dithering was disabled by default, because it has never + been well tested and doesn't work very well. The code has not + been removed, however, and can be enabled by building libpng with + PNG_READ_DITHER_SUPPORTED defined. + +Version 1.4.0beta48 [February 14, 2009] + Added new exported function png_calloc(). + Combined several instances of png_malloc(); png_memset() into png_calloc(). + Removed prototype for png_freeptr() that was added in libpng-1.4.0beta24 + but was never defined. + +Version 1.4.0beta49 [February 28, 2009] + Added png_fileno() macro to pngconf.h, used in pngwio.c + Corrected order of #ifdef's in png_debug definition in png.h + Fixed bug introduced in libpng-1.4.0beta48 with the memset arguments + for pcal_params. + Fixed order of #ifdef directives in the png_debug defines in png.h + (bug introduced in libpng-1.2.34/1.4.0beta29). + Revised comments in png_set_read_fn() and png_set_write_fn(). + +Version 1.4.0beta50 [March 18, 2009] + Use png_calloc() instead of png_malloc() to allocate big_row_buf when + reading an interlaced file, to avoid a possible UMR. + Undid revision of PNG_NO_STDIO version of png_write_flush(). Users + having trouble with fflush() can build with PNG_NO_WRITE_FLUSH defined + or supply their own flush_fn() replacement. + Revised libpng*.txt and png.h documentation about use of png_write_flush() + and png_set_write_fn(). + Removed fflush() from pngtest.c. + Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h + +Version 1.4.0beta51 [March 21, 2009] + Removed new png_fileno() macro from pngconf.h . + +Version 1.4.0beta52 [March 27, 2009] + Relocated png_do_chop() ahead of building gamma tables in pngrtran.c + This avoids building 16-bit gamma tables unnecessarily. + Removed fflush() from pngtest.c. + Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h + Added a section on differences between 1.0.x and 1.2.x to libpng.3/libpng.txt + +Version 1.4.0beta53 [April 1, 2009] + Removed some remaining MMX macros from pngpriv.h + Fixed potential memory leak of "new_name" in png_write_iCCP() (Ralph Giles) + +Version 1.4.0beta54 [April 13, 2009] + Added "ifndef PNG_SKIP_SETJMP_CHECK" block in pngconf.h to allow + application code writers to bypass the check for multiple inclusion + of setjmp.h when they know that it is safe to ignore the situation. + Eliminated internal use of setjmp() in pngread.c and pngwrite.c + Reordered ancillary chunks in pngtest.png to be the same as what + pngtest now produces, and made some cosmetic changes to pngtest output. + Eliminated deprecated png_read_init_3() and png_write_init_3() functions. + +Version 1.4.0beta55 [April 15, 2009] + Simplified error handling in pngread.c and pngwrite.c by putting + the new png_read_cleanup() and png_write_cleanup() functions inline. + +Version 1.4.0beta56 [April 25, 2009] + Renamed "user_chunk_data" to "my_user_chunk_data" in pngtest.c to suppress + "shadowed declaration" warning from gcc-4.3.3. + Renamed "gamma" to "png_gamma" in pngset.c to avoid "shadowed declaration" + warning about a global "gamma" variable in math.h on some platforms. + +Version 1.4.0beta57 [May 2, 2009] + Removed prototype for png_freeptr() that was added in libpng-1.4.0beta24 + but was never defined (again). + Rebuilt configure scripts with autoconf-2.63 instead of 2.62 + Removed pngprefs.h and MMX from makefiles + +Version 1.4.0beta58 [May 14, 2009] + Changed pngw32.def to pngwin.def in makefile.mingw (typo was introduced + in beta57). + Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri) + +Version 1.4.0beta59 [May 15, 2009] + Reformated sources in libpng style (3-space intentation, comment format) + Fixed typo in libpng docs (PNG_FILTER_AVE should be PNG_FILTER_AVG) + Added sections about the git repository and our coding style to the + documentation + Relocated misplaced #endif in pngwrite.c, sCAL chunk handler. + +Version 1.4.0beta60 [May 19, 2009] + Conditionally compile png_read_finish_row() which is not used by + progressive readers. + Added contrib/pngminim/preader to demonstrate building minimal progressive + decoder, based on contrib/gregbook with embedded libpng and zlib. + +Version 1.4.0beta61 [May 20, 2009] + In contrib/pngminim/*, renamed "makefile.std" to "makefile", since there + is only one makefile in those directories, and revised the README files + accordingly. + More reformatting of comments, mostly to capitalize sentences. + +Version 1.4.0beta62 [June 2, 2009] + Added "#define PNG_NO_WRITE_SWAP" to contrib/pngminim/encoder/pngusr.h + and "define PNG_NO_READ_SWAP" to decoder/pngusr.h and preader/pngusr.h + Reformatted several remaining "else statement" into two lines. + Added a section to the libpng documentation about using png_get_io_ptr() + in configure scripts to detect the presence of libpng. + +Version 1.4.0beta63 [June 15, 2009] + Revised libpng*.txt and libpng.3 to mention calling png_set_IHDR() + multiple times and to specify the sample order in the tRNS chunk, + because the ISO PNG specification has a typo in the tRNS table. + Changed several PNG_UNKNOWN_CHUNK_SUPPORTED to + PNG_HANDLE_AS_UNKNOWN_SUPPORTED, to make the png_set_keep mechanism + available for ignoring known chunks even when not saving unknown chunks. + Adopted preference for consistent use of "#ifdef" and "#ifndef" versus + "#if defined()" and "if !defined()" where possible. + +Version 1.4.0beta64 [June 24, 2009] + Eliminated PNG_LEGACY_SUPPORTED code. + Moved the various unknown chunk macro definitions outside of the + PNG_READ|WRITE_ANCILLARY_CHUNK_SUPPORTED blocks. + +Version 1.4.0beta65 [June 26, 2009] + Added a reference to the libpng license in each file. + +Version 1.4.0beta66 [June 27, 2009] + Refer to the libpng license instead of the libpng license in each file. + +Version 1.4.0beta67 [July 6, 2009] + Relocated INVERT_ALPHA within png_read_png() and png_write_png(). + Added high-level API transform PNG_TRANSFORM_GRAY_TO_RGB. + Added an "xcode" project to the projects directory (Alam Arias). + +Version 1.4.0beta68 [July 19, 2009] + Avoid some tests in filter selection in pngwutil.c + +Version 1.4.0beta69 [July 25, 2009] + Simplified the new filter-selection test. This runs faster in the + common "PNG_ALL_FILTERS" and PNG_FILTER_NONE cases. + Removed extraneous declaration from the new call to png_read_gray_to_rgb() + (bug introduced in libpng-1.4.0beta67). + Fixed up xcode project (Alam Arias) + Added a prototype for png_64bit_product() in png.c + +Version 1.4.0beta70 [July 27, 2009] + Avoid a possible NULL dereference in debug build, in png_set_text_2(). + (bug introduced in libpng-0.95, discovered by Evan Rouault) + +Version 1.4.0beta71 [July 29, 2009] + Rebuilt configure scripts with autoconf-2.64. + +Version 1.4.0beta72 [August 1, 2009] + Replaced *.tar.lzma with *.tar.xz in distribution. Get the xz codec + from . + +Version 1.4.0beta73 [August 1, 2009] + Reject attempt to write iCCP chunk with negative embedded profile length + (JD Chen) (CVE-2009-5063). + +Version 1.4.0beta74 [August 8, 2009] + Changed png_ptr and info_ptr member "trans" to "trans_alpha". + +Version 1.4.0beta75 [August 21, 2009] + Removed an extra png_debug() recently added to png_write_find_filter(). + Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. + +Version 1.4.0beta76 [August 22, 2009] + Moved an incorrectly located test in png_read_row() in pngread.c + +Version 1.4.0beta77 [August 27, 2009] + Removed lpXYZ.tar.bz2 (with CRLF), KNOWNBUG, libpng-x.y.z-KNOWNBUG.txt, + and the "noconfig" files from the distribution. + Moved CMakeLists.txt from scripts into the main libpng directory. + Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) + +Version 1.4.0beta78 [August 31, 2009] + Converted all PNG_NO_* tests to PNG_*_SUPPORTED everywhere except pngconf.h + Eliminated PNG_NO_FREE_ME and PNG_FREE_ME_SUPPORTED macros. + Use png_malloc plus a loop instead of png_calloc() to initialize + row_pointers in png_read_png(). + +Version 1.4.0beta79 [September 1, 2009] + Eliminated PNG_GLOBAL_ARRAYS and PNG_LOCAL_ARRAYS; always use local arrays. + Eliminated PNG_CALLOC_SUPPORTED macro and always provide png_calloc(). + +Version 1.4.0beta80 [September 17, 2009] + Removed scripts/libpng.icc + Changed typecast of filler from png_byte to png_uint_16 in png_set_filler(). + (Dennis Gustafsson) + Fixed typo introduced in beta78 in pngtest.c ("#if def " should be "#ifdef ") + +Version 1.4.0beta81 [September 23, 2009] + Eliminated unused PNG_FLAG_FREE_* defines from pngpriv.h + Expanded TAB characters in pngrtran.c + Removed PNG_CONST from all "PNG_CONST PNG_CHNK" declarations to avoid + compiler complaints about doubly declaring things "const". + Changed all "#if [!]defined(X)" to "if[n]def X" where possible. + Eliminated unused png_ptr->row_buf_size + +Version 1.4.0beta82 [September 25, 2009] + Moved redundant IHDR checking into new png_check_IHDR() in png.c + and report all errors found in the IHDR data. + Eliminated useless call to png_check_cHRM() from pngset.c + +Version 1.4.0beta83 [September 25, 2009] + Revised png_check_IHDR() to eliminate bogus complaint about filter_type. + +Version 1.4.0beta84 [September 30, 2009] + Fixed some inconsistent indentation in pngconf.h + Revised png_check_IHDR() to add a test for width variable less than 32-bit. + +Version 1.4.0beta85 [October 1, 2009] + Revised png_check_IHDR() again, to check info_ptr members instead of + the contents of the returned parameters. + +Version 1.4.0beta86 [October 9, 2009] + Updated the "xcode" project (Alam Arias). + Eliminated a shadowed declaration of "pp" in png_handle_sPLT(). + +Version 1.4.0rc01 [October 19, 2009] + Trivial cosmetic changes. + +Version 1.4.0beta87 [October 30, 2009] + Moved version 1.4.0 back into beta. + +Version 1.4.0beta88 [October 30, 2009] + Revised libpng*.txt section about differences between 1.2.x and 1.4.0 + because most of the new features have now been ported back to 1.2.41 + +Version 1.4.0beta89 [November 1, 2009] + More bugfixes and improvements to CMakeLists.txt (Philip Lowman) + Removed a harmless extra png_set_invert_alpha() from pngwrite.c + Apply png_user_chunk_cache_max within png_decompress_chunk(). + Merged libpng-1.2.41.txt with libpng-1.4.0.txt where appropriate. + +Version 1.4.0beta90 [November 2, 2009] + Removed all remaining WIN32_WCE #ifdefs except those involving the + time.h "tm" structure + +Version 1.4.0beta91 [November 3, 2009] + Updated scripts/pngw32.def and projects/wince/png32ce.def + Copied projects/wince/png32ce.def to the scripts directory. + Added scripts/makefile.wce + Patched ltmain.sh for wince support. + Added PNG_CONVERT_tIME_SUPPORTED macro. + +Version 1.4.0beta92 [November 4, 2009] + Make inclusion of time.h in pngconf.h depend on PNG_CONVERT_tIME_SUPPORTED + Make #define PNG_CONVERT_tIME_SUPPORTED depend on PNG_WRITE_tIME_SUPPORTED + Revised libpng*.txt to describe differences from 1.2.40 to 1.4.0 (instead + of differences from 1.2.41 to 1.4.0) + +Version 1.4.0beta93 [November 7, 2009] + Added PNG_DEPSTRUCT, PNG_DEPRECATED, PNG_USE_RESULT, PNG_NORETURN, and + PNG_ALLOCATED macros to detect deprecated direct access to the + png_struct or info_struct members and other deprecated usage in + applications (John Bowler). + Updated scripts/makefile* to add "-DPNG_CONFIGURE_LIBPNG" to CFLAGS, + to prevent warnings about direct access to png structs by libpng + functions while building libpng. They need to be tested, especially + those using compilers other than gcc. + Updated projects/visualc6 and visualc71 with "/d PNG_CONFIGURE_LIBPNG". + They should work but still need to be updated to remove + references to pnggccrd.c or pngvcrd.c and ASM building. + Added README.txt to the beos, cbuilder5, netware, and xcode projects warning + that they need to be updated, to remove references to pnggccrd.c and + pngvcrd.c and to depend on pngpriv.h + Removed three direct references to read_info_ptr members in pngtest.c + that were detected by the new PNG_DEPSTRUCT macro. + Moved the png_debug macro definitions and the png_read_destroy(), + png_write_destroy() and png_far_to_near() prototypes from png.h + to pngpriv.h (John Bowler) + Moved the synopsis lines for png_read_destroy(), png_write_destroy() + png_debug(), png_debug1(), and png_debug2() from libpng.3 to libpngpf.3. + +Version 1.4.0beta94 [November 9, 2009] + Removed the obsolete, unused pnggccrd.c and pngvcrd.c files. + Updated CMakeLists.txt to add "-DPNG_CONFIGURE_LIBPNG" to the definitions. + Removed dependency of pngtest.o on pngpriv.h in the makefiles. + Only #define PNG_DEPSTRUCT, etc. in pngconf.h if not already defined. + +Version 1.4.0beta95 [November 10, 2009] + Changed png_check_sig() to !png_sig_cmp() in contrib programs. + Added -DPNG_CONFIGURE_LIBPNG to contrib/pngminm/*/makefile + Changed png_check_sig() to !png_sig_cmp() in contrib programs. + Corrected the png_get_IHDR() call in contrib/gregbook/readpng2.c + Changed pngminim/*/gather.sh to stop trying to remove pnggccrd.c and pngvcrd.c + Added dependency on pngpriv.h in contrib/pngminim/*/makefile + +Version 1.4.0beta96 [November 12, 2009] + Renamed scripts/makefile.wce to scripts/makefile.cegcc + Revised Makefile.am to use libpng.sys while building libpng.so + so that only PNG_EXPORT functions are exported. + Removed the deprecated png_check_sig() function/macro. + Removed recently removed function names from scripts/*.def + Revised pngtest.png to put chunks in the same order written by pngtest + (evidently the same change made in libpng-1.0beta54 was lost). + Added PNG_PRIVATE macro definition in pngconf.h for possible future use. + +Version 1.4.0beta97 [November 13, 2009] + Restored pngtest.png to the libpng-1.4.0beta7 version. + Removed projects/beos and netware.txt; no one seems to be supporting them. + Revised Makefile.in + +Version 1.4.0beta98 [November 13, 2009] + Added the "xcode" project to zip distributions, + Fixed a typo in scripts/pngwin.def introduced in beta97. + +Version 1.4.0beta99 [November 14, 2009] + Moved libpng-config.in and libpng.pc-configure.in out of the scripts + directory, to libpng-config.in and libpng-pc.in, respectively, and + modified Makefile.am and configure.ac accordingly. Now "configure" + needs nothing from the "scripts" directory. + Avoid redefining PNG_CONST in pngconf.h + +Version 1.4.0beta100 [November 14, 2009] + Removed ASM builds from projects/visualc6 and projects/visualc71 + Removed scripts/makefile.nommx and makefile.vcawin32 + Revised CMakeLists.txt to account for new location of libpng-config.in + and libpng-pc.in + Updated INSTALL to reflect removal and relocation of files. + +Version 1.4.0beta101 [November 14, 2009] + Restored the binary files (*.jpg, *.png, some project files) that were + accidentally deleted from the zip and 7z distributions when the xcode + project was added. + +Version 1.4.0beta102 [November 18, 2009] + Added libpng-config.in and libpng-pc.in to the zip and 7z distributions. + Fixed a typo in projects/visualc6/pngtest.dsp, introduced in beta100. + Moved descriptions of makefiles and other scripts out of INSTALL into + scripts/README.txt + Updated the copyright year in scripts/pngwin.rc from 2006 to 2009. + +Version 1.4.0beta103 [November 21, 2009] + Removed obsolete comments about ASM from projects/visualc71/README_zlib.txt + Align row_buf on 16-byte boundary in memory. + Restored the PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED guard around the call + to png_flush() after png_write_IEND(). See 1.4.0beta32, 1.4.0beta50 + changes above and 1.2.30, 1.2.30rc01 and rc03 in 1.2.41 CHANGES. Someone + needs this feature. + Make the 'png_jmpbuf' macro expand to a call that records the correct + longjmp function as well as returning a pointer to the setjmp + jmp_buf buffer, and marked direct access to jmpbuf 'deprecated'. + (John Bowler) + +Version 1.4.0beta104 [November 22, 2009] + Removed png_longjmp_ptr from scripts/*.def and libpng.3 + Rebuilt configure scripts with autoconf-2.65 + +Version 1.4.0beta105 [November 25, 2009] + Use fast integer PNG_DIVIDE_BY_255() or PNG_DIVIDE_BY_65535() + to accomplish alpha premultiplication when + PNG_READ_COMPOSITE_NODIV_SUPPORTED is defined. + Changed "/255" to "/255.0" in background calculations to make it clear + that the 255 is used as a double. + +Version 1.4.0beta106 [November 27, 2009] + Removed premultiplied alpha feature. + +Version 1.4.0beta107 [December 4, 2009] + Updated README + Added "#define PNG_NO_PEDANTIC_WARNINGS" in the libpng source files. + Removed "-DPNG_CONFIGURE_LIBPNG" from the makefiles and projects. + Revised scripts/makefile.netbsd, makefile.openbsd, and makefile.sco + to put png.h and pngconf.h in $prefix/include, like the other scripts, + instead of in $prefix/include/libpng. Also revised makefile.sco + to put them in $prefix/include/libpng15 instead of in + $prefix/include/libpng/libpng15. + +Version 1.4.0beta108 [December 11, 2009] + Removed leftover "-DPNG_CONFIGURE_LIBPNG" from contrib/pngminim/*/makefile + Relocated png_do_chop() to its original position in pngrtran.c; the + change in version 1.2.41beta08 caused transparency to be handled wrong + in some 16-bit datastreams (Yusaku Sugai). + +Version 1.4.0beta109 [December 13, 2009] + Added "bit_depth" parameter to the private png_build_gamma_table() function. + Pass bit_depth=8 to png_build_gamma_table() when bit_depth is 16 but the + PNG_16_TO_8 transform has been set, to avoid unnecessary build of 16-bit + tables. + +Version 1.4.0rc02 [December 20, 2009] + Declared png_cleanup_needed "volatile" in pngread.c and pngwrite.c + +Version 1.4.0rc03 [December 22, 2009] + Renamed libpng-pc.in back to libpng.pc.in and revised CMakeLists.txt + (revising the change in 1.4.0beta99) + +Version 1.4.0rc04 [December 25, 2009] + Swapped PNG_UNKNOWN_CHUNKS_SUPPORTED and PNG_HANDLE_AS_UNKNOWN_SUPPORTED + in pngset.c to be consistent with other changes in version 1.2.38. + +Version 1.4.0rc05 [December 25, 2009] + Changed "libpng-pc.in" to "libpng.pc.in" in configure.ac, configure, and + Makefile.in to be consistent with changes in libpng-1.4.0rc03 + +Version 1.4.0rc06 [December 29, 2009] + Reverted the gamma_table changes from libpng-1.4.0beta109. + Fixed some indentation errors. + +Version 1.4.0rc07 [January 1, 2010] + Revised libpng*.txt and libpng.3 about 1.2.x->1.4.x differences. + Use png_calloc() instead of png_malloc(); png_memset() in pngrutil.c + Update copyright year to 2010. + +Version 1.4.0rc08 [January 2, 2010] + Avoid deprecated references to png_ptr-io_ptr and png_ptr->error_ptr + in pngtest.c + +Version 1.4.0 [January 3, 2010] + No changes. + +Version 1.4.1beta01 [January 8, 2010] + Updated CMakeLists.txt for consistent indentation and to avoid an + unclosed if-statement warning (Philip Lowman). + Revised Makefile.am and Makefile.in to remove references to Y2KINFO, + KNOWNBUG, and libpng.la (Robert Schwebel). + Revised the makefiles to install the same files and symbolic + links as configure, except for libpng.la and libpng14.la. + Make png_set|get_compression_buffer_size() available even when + PNG_WRITE_SUPPORTED is not enabled. + Revised Makefile.am and Makefile.in to simplify their maintenance. + Revised scripts/makefile.linux to install a link to libpng14.so.14.1 + +Version 1.4.1beta02 [January 9, 2010] + Revised the rest of the makefiles to install a link to libpng14.so.14.1 + +Version 1.4.1beta03 [January 10, 2010] + Removed png_set_premultiply_alpha() from scripts/*.def + +Version 1.4.1rc01 [January 16, 2010] + No changes. + +Version 1.4.1beta04 [January 23, 2010] + Revised png_decompress_chunk() to improve speed and memory usage when + decoding large chunks. + Added png_set|get_chunk_malloc_max() functions. + +Version 1.4.1beta05 [January 26, 2010] + Relocated "int k" declaration in pngtest.c to minimize its scope. + +Version 1.4.1beta06 [January 28, 2010] + Revised png_decompress_chunk() to use a two-pass method suggested by + John Bowler. + +Version 1.4.1beta07 [February 6, 2010] + Folded some long lines in the source files. + Added defineable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX, + and a PNG_USER_LIMITS_SUPPORTED flag. + Eliminated use of png_ptr->irowbytes and reused the slot in png_ptr as + png_ptr->png_user_chunk_malloc_max. + Revised png_push_save_buffer() to do fewer but larger png_malloc() calls. + +Version 1.4.1beta08 [February 6, 2010] + Minor cleanup and updating of dates and copyright year. + +Version 1.5.0beta01 [February 7, 2010] + Moved declaration of png_struct into private pngstruct.h and png_info + into pnginfo.h + +Version 1.4.1beta09 and 1.5.0beta02 [February 7, 2010] + Reverted to original png_push_save_buffer() code. + +Version 1.4.1beta10 and 1.5.0beta03 [February 8, 2010] + Return allocated "old_buffer" in png_push_save_buffer() before + calling png_error(), to avoid a potential memory leak. + Updated configure script to use SO number 15. + +Version 1.5.0beta04 [February 9, 2010] + Removed malformed "incomplete struct declaration" of png_info from png.h + +Version 1.5.0beta05 [February 12, 2010] + Removed PNG_DEPSTRUCT markup in pngstruct.h and pnginfo.h, and undid the + linewrapping that it entailed. + Revised comments in pngstruct.h and pnginfo.h and added pointers to + the libpng license. + Changed PNG_INTERNAL to PNG_EXPOSE_INTERNAL_STRUCTURES + Removed the cbuilder5 project, which has not been updated to 1.4.0. + +Version 1.4.1beta12 and 1.5.0beta06 [February 14, 2010] + Fixed type declaration of png_get_chunk_malloc_max() in pngget.c (Daisuke + Nishikawa) + +Version 1.5.0beta07 [omitted] + +Version 1.5.0beta08 [February 19, 2010] + Changed #ifdef PNG_NO_STDIO_SUPPORTED to #ifdef PNG_NO_CONSOLE_IO_SUPPORTED + wherever png_snprintf() is used to construct error and warning messages. + Noted in scripts/makefile.mingw that it expects to be run under MSYS. + Removed obsolete unused MMX-querying support from contrib/gregbook + Added exported png_longjmp() function. + Removed the AIX redefinition of jmpbuf in png.h + Added -D_ALLSOURCE in configure.ac, makefile.aix, and CMakeLists.txt + when building on AIX. + +Version 1.5.0beta09 [February 19, 2010] + Removed -D_ALLSOURCE from configure.ac, makefile.aix, and CMakeLists.txt. + Changed the name of png_ptr->jmpbuf to png_ptr->png_jmpbuf in pngstruct.h + +Version 1.5.0beta10 [February 25, 2010] + Removed unused gzio.c from contrib/pngminim gather and makefile scripts + Removed replacement error handlers from contrib/gregbook. Because of + the new png_longjmp() function they are no longer needed. + +Version 1.5.0beta11 [March 6, 2010] + Removed checking for already-included setjmp.h from pngconf.h + Fixed inconsistent indentations and made numerous cosmetic changes. + Revised the "SEE ALSO" style of libpng.3, libpngpf.3, and png.5 + +Version 1.5.0beta12 [March 9, 2010] + Moved "#include png.h" inside pngpriv.h and removed "#include png.h" from + the source files, along with "#define PNG_EXPOSE_INTERNAL_STRUCTURES" + and "#define PNG_NO_PEDANTIC_WARNINGS" (John Bowler). + Created new pngdebug.h and moved debug definitions there. + +Version 1.5.0beta13 [March 10, 2010] + Protect pngstruct.h, pnginfo.h, and pngdebug.h from being included twice. + Revise the "#ifdef" blocks in png_inflate() so it will compile when neither + PNG_USER_CHUNK_MALLOC_MAX nor PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + is defined. + Removed unused png_measure_compressed_chunk() from pngpriv.h and libpngpf.3 + Moved the 'config.h' support from pngconf.h to pngpriv.h + Removed PNGAPI from the png_longjmp_ptr typedef. + Eliminated dependence of pngtest.c on the private pngdebug.h file. + Make all png_debug macros into *unterminated* statements or + expressions (i.e. a trailing ';' must always be added) and correct + the format statements in various png_debug messages. + +Version 1.5.0beta14 [March 14, 2010] + Removed direct access to png_ptr->io_ptr from the Windows code in pngtest.c + Revised Makefile.am to account for recent additions and replacements. + Corrected CE and OS/2 DEF files (scripts/png*def) for symbols removed and + added ordinal numbers to the Windows DEF file and corrected the duplicated + ordinal numbers on CE symbols that are commented out. + Added back in export symbols that can be present in the Windows build but + are disabled by default. + PNG_EXPORT changed to include an 'ordinal' field for DEF file generation. + PNG_CALLBACK added to make callback definitions uniform. PNGAPI split + into PNGCAPI (base C form), PNGAPI (exports) and PNGCBAPI (callbacks), + and appropriate changes made to all files. Cygwin builds re-hinged to + allow procedure call standard changes and to remove the need for the DEF + file (fixes build on Cygwin). + Enabled 'attribute' warnings that are relevant to library APIs and callbacks. + Changed rules for generation of the various symbol files and added a new + rule for a DEF file (which is also added to the distribution). + Updated the symbol file generation to stop it adding spurious spaces + to EOL (coming from preprocessor macro expansion). Added a facility + to join tokens in the output and rewrite *.dfn to use this. + Eliminated scripts/*.def in favor of libpng.def; updated projects/visualc71 + and removed scripts/makefile.cygwin. + Made PNG_BUILD_DLL safe: it can be set whenever a DLL is being built. + Removed the include of sys/types.h - apparently unnecessary now on the + platforms on which it happened (all but Mac OS and RISC OS). + Moved the Mac OS test into pngpriv.h (the only place it is used.) + +Version 1.5.0beta15 [March 17, 2010] + Added symbols.chk target to Makefile.am to validate the symbols in png.h + against the new DEF file scripts/symbols.def. + Changed the default DEF file back to pngwin.def. + Removed makefile.mingw. + Eliminated PNG_NO_EXTERN and PNG_ALL_EXTERN + +Version 1.5.0beta16 [April 1, 2010] + Make png_text_struct independent of PNG_iTXt_SUPPORTED, so that + fields are initialized in all configurations. The READ/WRITE + macros (PNG_(READ|WRITE)_iTXt_SUPPORTED) still function as + before to disable code to actually read or write iTXt chunks + and iTXt_SUPPORTED can be used to detect presence of either + read or write support (but it is probably better to check for + the one actually required - read or write.) + Combined multiple png_warning() calls for a single error. + Restored the macro definition of png_check_sig(). + +Version 1.5.0beta17 [April 17, 2010] + Added some "(long)" typecasts to printf calls in png_handle_cHRM(). + Documented the fact that png_set_dither() was disabled since libpng-1.4.0. + Reenabled png_set_dither() but renamed it to png_set_quantize() to reflect + more accurately what it actually does. At the same time, renamed + the PNG_DITHER_[RED,GREEN_BLUE]_BITS macros to + PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS. + Added some "(long)" typecasts to printf calls in png_handle_cHRM(). + Freeze build-time only configuration in the build. + In all prior versions of libpng most configuration options + controlled by compiler #defines had to be repeated by the + application code that used libpng. This patch changes this + so that compilation options that can only be changed at build + time are frozen in the build. Options that are compiler + dependent (and those that are system dependent) are evaluated + each time - pngconf.h holds these. Options that can be changed + per-file in the application are in png.h. Frozen options are + in the new installed header file pnglibconf.h (John Bowler) + Removed the xcode project because it has not been updated to work + with libpng-1.5.0. + Removed the ability to include optional pngusr.h + +Version 1.5.0beta18 [April 17, 2010] + Restored the ability to include optional pngusr.h + Moved replacements for png_error() and png_warning() from the + contrib/pngminim project to pngerror.c, for use when warnings or + errors are disabled via PNG_NO_WARN or PNG_NO_ERROR_TEXT, to avoid + storing unneeded error/warning text. + Updated contrib/pngminim project to work with the new pnglibconf.h + Added some PNG_NO_* defines to contrib/pngminim/*/pngusr.h to save space. + +Version 1.5.0beta19 [April 24, 2010] + Added PNG_{READ,WRITE}_INT_FUNCTIONS_SUPPORTED. This allows the functions + to read and write ints to be disabled independently of PNG_USE_READ_MACROS, + which allows libpng to be built with the functions even though the default + is to use the macros - this allows applications to choose at app build + time whether or not to use macros (previously impossible because the + functions weren't in the default build.) + Changed Windows calling convention back to __cdecl for API functions. + For Windows/x86 platforms only: + __stdcall is no longer needed for Visual Basic, so libpng-1.5.0 uses + __cdecl throughout (both API functions and callbacks) on Windows/x86 + platforms. + Replaced visualc6 and visualc71 projects with new vstudio project + Relaxed the overly-restrictive permissions of some files. + +Version 1.5.0beta20 [April 24, 2010] + Relaxed more overly-restrictive permissions of some files. + +Version 1.5.0beta21 [April 27, 2010] + Removed some unwanted binary bytes and changed CRLF to NEWLINE in the new + vstudio project files, and some trivial editing of some files in the + scripts directory. + Set PNG_NO_READ_BGR, PNG_NO_IO_STATE, and PNG_NO_TIME_RFC1123 in + contrib/pngminim/decoder/pngusr.h to make a smaller decoder application. + +Version 1.5.0beta22 [April 28, 2010] + Fixed dependencies of GET_INT_32 - it does not require READ_INT_FUNCTIONS + because it has a macro equivalent. + Improved the options.awk script; added an "everything off" option. + Revised contrib/pngminim to use the "everything off" option in pngusr.dfa. + +Version 1.5.0beta23 [April 29, 2010] + Corrected PNG_REMOVED macro to take five arguments. + The macro was documented with two arguments (name,ordinal), however + the symbol checking .dfn files assumed five arguments. The five + argument form seems more useful so it is changed to that. + Corrected PNG_UNKNOWN_CHUNKS_SUPPORTED to PNG_HANDLE_AS_UNKNOWN_SUPPORTED + in gregbook/readpng2.c + Corrected protection of png_get_user_transform_ptr. The API declaration in + png.h is removed if both READ and WRITE USER_TRANSFORM are turned off + but was left defined in pngtrans.c + Added logunsupported=1 to cause pnglibconf.h to document disabled options. + This makes the installed pnglibconf.h more readable but causes no + other change. The intention is that users of libpng will find it + easier to understand if an API they need is missing. + Include png_reset_zstream() in png.c only when PNG_READ_SUPPORTED is defined. + Removed dummy_inflate.c from contrib/pngminim/encoder + Removed contrib/pngminim/*/gather.sh; gathering is now done in the makefile. + +Version 1.5.0beta24 [May 7, 2010] + Use bitwise "&" instead of arithmetic mod in pngrutil.c calculation of the + offset of the png_ptr->rowbuf pointer into png_ptr->big_row_buf. + Added more blank lines for readability. + +Version 1.5.0beta25 [June 18, 2010] + In pngpread.c: png_push_have_row() add check for new_row > height + Removed the now-redundant check for out-of-bounds new_row from example.c + +Version 1.5.0beta26 [June 18, 2010] + In pngpread.c: png_push_process_row() add check for too many rows. + +Version 1.5.0beta27 [June 18, 2010] + Removed the check added in beta25 as it is now redundant. + +Version 1.5.0beta28 [June 20, 2010] + Rewrote png_process_IDAT_data to consistently treat extra data as warnings + and handle end conditions more cleanly. + Removed the new (beta26) check in png_push_process_row(). + +Version 1.5.0beta29 [June 21, 2010] + Revised scripts/options.awk to work on Sunos (but still doesn't work) + Added comment to options.awk and contrib/pngminim/*/makefile to try nawk. + +Version 1.5.0beta30 [June 22, 2010] + Stop memory leak when reading a malformed sCAL chunk. + +Version 1.5.0beta31 [June 26, 2010] + Revised pngpread.c patch of beta28 to avoid an endless loop. + Removed some trailing blanks. + +Version 1.5.0beta32 [June 26, 2010] + Removed leftover scripts/options.patch and scripts/options.rej + +Version 1.5.0beta33 [July 6, 3010] + Made FIXED and FLOATING options consistent in the APIs they enable and + disable. Corrected scripts/options.awk to handle both command line + options and options specified in the .dfa files. + Changed char *msg to PNG_CONST char *msg in pngrutil.c + Make png_set_sRGB_gAMA_and_cHRM set values using either the fixed or + floating point APIs, but not both. + Reversed patch to remove error handler when the jmp_buf is stored in the + main program structure, not the png_struct. + The error handler is needed because the default handler in libpng will + always use the jmp_buf in the library control structure; this is never + set. The gregbook code is a useful example because, even though it + uses setjmp/longjmp, it shows how error handling can be implemented + using control mechanisms not directly supported by libpng. The + technique will work correctly with mechanisms such as Microsoft + Structure Exceptions or C++ exceptions (compiler willing - note that gcc + does not by default support interworking of C and C++ error handling.) + Reverted changes to call png_longjmp in contrib/gregbook where it is not + appropriate. If mainprog->jmpbuf is used by setjmp, then png_longjmp + cannot be used. + Changed "extern PNG_EXPORT" to "PNG_EXPORT" in png.h (Jan Nijtmans) + Changed "extern" to "PNG_EXTERN" in pngpriv.h (except for the 'extern "C" {') + +Version 1.5.0beta34 [July 12, 2010] + Put #ifndef PNG_EXTERN, #endif around the define PNG_EXTERN in pngpriv.h + +Version 1.5.0beta35 [July 24, 2010] + Removed some newly-added TAB characters. + Added -DNO_PNG_SNPRINTF to CFLAGS in scripts/makefile.dj2 + Moved the definition of png_snprintf() outside of the enclosing + #ifdef blocks in pngconf.h + +Version 1.5.0beta36 [July 29, 2010] + Patches by John Bowler: + Fixed point APIs are now supported throughout (no missing APIs). + Internal fixed point arithmetic support exists for all internal floating + point operations. + sCAL validates the floating point strings it is passed. + Safe, albeit rudimentary, Watcom support is provided by PNG_API_RULE==2 + Two new APIs exist to get the number of passes without turning on the + PNG_INTERLACE transform and to get the number of rows in the current + pass. + A new test program, pngvalid.c, validates the gamma code. + Errors in the 16-bit gamma correction (overflows) have been corrected. + cHRM chunk testing is done consistently (previously the floating point + API bypassed it, because the test really didn't work on FP, now the test + is performed on the actual values to be stored in the PNG file so it + works in the FP case too.) + Most floating point APIs now simply call the fixed point APIs after + converting the values to the fixed point form used in the PNG file. + The standard headers no longer include zlib.h, which is currently only + required for pngstruct.h and can therefore be internal. + Revised png_get_int_32 to undo the PNG two's complement representation of + negative numbers. + +Version 1.5.0beta37 [July 30, 2010] + Added a typecast in png_get_int_32() in png.h and pngrutil.h to avoid + a compiler warning. + Replaced oFFs 0,0 with oFFs -10,20 in pngtest.png + +Version 1.5.0beta38 [July 31, 2010] + Implemented remaining "_fixed" functions. + Corrected a number of recently introduced warnings mostly resulting from + safe but uncast assignments to shorter integers. Also added a zlib + VStudio release library project because the latest zlib Official Windows + build does not include such a thing. + Revised png_get_int_16() to be similar to png_get_int_32(). + Restored projects/visualc71. + +Version 1.5.0beta39 [August 2, 2010] + VisualC/GCC warning fixes, VisualC build fixes + The changes include support for function attributes in VC in addition to + those already present in GCC - necessary because without these some + warnings are unavoidable. Fixes include signed/unsigned fixes in + pngvalid and checks with gcc -Wall -Wextra -Wunused. + VC requires function attributes on function definitions as well as + declarations, PNG_FUNCTION has been added to enable this and the + relevant function definitions changed. + +Version 1.5.0beta40 [August 6, 2010] + Correct use of _WINDOWS_ in pngconf.h + Removed png_mem_ #defines; they are no longer used. + Added the sRGB chunk to pngtest.png + +Version 1.5.0beta41 [August 11, 2010] + Added the cHRM chunk to pngtest.png + Don't try to use version-script with cygwin/mingw. + Revised contrib/gregbook to work under cygwin/mingw. + +Version 1.5.0beta42 [August 18, 2010] + Add .dll.a to the list of extensions to be symlinked by Makefile.am (Yaakov) + Made all API functions that have const arguments and constant string + literal pointers declare them (John Bowler). + +Version 1.5.0beta43 [August 20, 2010] + Removed spurious tabs, shorten long lines (no source change) + Also added scripts/chkfmt to validate the format of all the files that can + reasonably be validated (it is suggested to run "make distclean" before + checking, because some machine generated files have long lines.) + Reformatted the CHANGES file to be more consistent throughout. + Made changes to address various issues identified by GCC, mostly + signed/unsigned and shortening problems on assignment but also a few + difficult to optimize (for GCC) loops. + Fixed non-GCC fixed point builds. In png.c a declaration was misplaced + in an earlier update. Fixed to declare the auto variables at the head. + Use cexcept.h in pngvalid.c. + +Version 1.5.0beta44 [August 24, 2010] + Updated CMakeLists.txt to use CMAKE_INSTALL_LIBDIR variable; useful for + installing libpng in /usr/lib64 (Funda Wang). + Revised CMakeLists.txt to put the man pages in share/man/man* not man/man* + Revised CMakeLists.txt to make symlinks instead of copies when installing. + Changed PNG_LIB_NAME from pngNN to libpngNN in CMakeLists.txt (Philip Lowman) + Implemented memory checks within pngvalid + Reformatted/rearranged pngvalid.c to assist use of progressive reader. + Check interlaced images in pngvalid + Clarified pngusr.h comments in pnglibconf.dfa + Simplified the pngvalid error-handling code now that cexcept.h is in place. + Implemented progressive reader in pngvalid.c for standard tests + Implemented progressive read in pngvalid.c gamma tests + Turn on progressive reader in pngvalid.c by default and tidy code. + +Version 1.5.0beta45 [August 26, 2010] + Added an explicit make step to projects/vstudio for pnglibconf.h + Also corrected zlib.vcxproj into which Visual Studio had introduced + what it calls an "authoring error". The change to make pnglibconf.h + simply copies the file; in the future it may actually generate the + file from scripts/pnglibconf.dfa as the other build systems do. + Changed pngvalid to work when floating point APIs are disabled + Renamed the prebuilt scripts/pnglibconf.h to scripts/pnglibconf.h.prebuilt + Supply default values for PNG_USER_PRIVATEBUILD and PNG_USER_DLLFNAME_POSTFIX + in pngpriv.h in case the user neglected to define them in their pngusr.h + +Version 1.5.0beta46 [August 28, 2010] + Added new private header files to libpng_sources in CMakeLists.txt + Added PNG_READ_16BIT, PNG_WRITE_16BIT, and PNG_16BIT options. + Added reference to scripts/pnglibconf.h.prebuilt in the visualc71 project. + +Version 1.5.0beta47 [September 11, 2010] + Fixed a number of problems with 64-bit compilation reported by Visual + Studio 2010 (John Bowler). + +Version 1.5.0beta48 [October 4, 2010] + Updated CMakeLists.txt (Philip Lowman). + Revised autogen.sh to recognize and use $AUTOCONF, $AUTOMAKE, $AUTOHEADER, + $AUTOPOINT, $ACLOCAL and $LIBTOOLIZE + Fixed problem with symbols creation in Makefile.am which was assuming that + all versions of ccp write to standard output by default (Martin Banky). The + bug was introduced in libpng-1.2.9beta5. + Removed unused mkinstalldirs. + +Version 1.5.0beta49 [October 8, 2010] + Undid Makefile.am revision of 1.5.0beta48. + +Version 1.5.0beta50 [October 14, 2010] + Revised Makefile.in to account for mkinstalldirs being removed. + Added some "(unsigned long)" typecasts in printf statements in pngvalid.c. + Suppressed a compiler warning in png_handle_sPLT(). + Check for out-of-range text compression mode in png_set_text(). + +Version 1.5.0beta51 [October 15, 2010] + Changed embedded dates to "(PENDING RELEASE) in beta releases (and future + rc releases) to minimize the difference between releases. + +Version 1.5.0beta52 [October 16, 2010] + Restored some of the embedded dates (in png.h, png.c, documentation, etc.) + +Version 1.5.0beta53 [October 18, 2010] + Updated INSTALL to mention using "make maintainer-clean" and to remove + obsolete statement about a custom ltmain.sh + Disabled "color-tests" by default in Makefile.am so it will work with + automake versions earlier than 1.11.1 + Use document name "libpng-manual.txt" instead of "libpng-.txt" + to simplify version differences. + Removed obsolete remarks about setjmp handling from INSTALL. + Revised and renamed the typedef in png.h and png.c that was designed + to catch library and header mismatch. + +Version 1.5.0beta54 [November 10, 2010] + Require 48 bytes, not 64 bytes, for big_row_buf in overflow checks. + Used a consistent structure for the pngget.c functions. + +Version 1.5.0beta55 [November 21, 2010] + Revised png_get_uint_32, png_get_int_32, png_get_uint_16 (Cosmin) + Moved reading of file signature into png_read_sig (Cosmin) + Fixed atomicity of chunk header serialization (Cosmin) + Added test for io_state in pngtest.c (Cosmin) + Added "#!/bin/sh" at the top of contrib/pngminim/*/gather.sh scripts. + Changes to remove gcc warnings (John Bowler) + Certain optional gcc warning flags resulted in warnings in libpng code. + With these changes only -Wconversion and -Wcast-qual cannot be turned on. + Changes are trivial rearrangements of code. -Wconversion is not possible + for pngrutil.c (because of the widespread use of += et al on variables + smaller than (int) or (unsigned int)) and -Wcast-qual is not possible + with pngwio.c and pngwutil.c because the 'write' callback and zlib + compression both fail to declare their input buffers with 'const'. + +Version 1.5.0beta56 [December 7, 2010] + Added the private PNG_UNUSED() macro definition in pngpriv.h. + Added some commentary about PNG_EXPORT in png.h and pngconf.h + Revised PNG_EXPORT() macro and added PNG_EXPORTA() macro, with the + objective of simplifying and improving the cosmetic appearance of png.h. + Fixed some incorrect "=" macro names in pnglibconf.dfa + Included documentation of changes in 1.5.0 from 1.4.x in libpng-manual.txt + +Version 1.5.0beta57 [December 9, 2010] + Documented the pngvalid gamma error summary with additional comments and + print statements. + Improved missing symbol handling in checksym.awk; symbols missing in both + the old and new files can now be optionally ignored, treated as errors + or warnings. + Removed references to pngvcrd.c and pnggccrd.c from the vstudio project. + Updated "libpng14" to "libpng15" in the visualc71 project. + Enabled the strip16 tests in pngvalid.` + Don't display test results (except PASS/FAIL) when running "make test". + Instead put them in pngtest-log.txt + Added "--with-zprefix=" to configure.ac + Updated the prebuilt configuration files to autoconf version 2.68 + +Version 1.5.0beta58 [December 19, 2010] + Fixed interlace image handling and add test cases (John Bowler) + Fixed the clean rule in Makefile.am to remove pngtest-log.txt + Made minor changes to work around warnings in gcc 3.4 + +Version 1.5.0rc01 [December 27, 2010] + No changes. + +Version 1.5.0rc02 [December 27, 2010] + Eliminated references to the scripts/*.def files in project/visualc71. + +Version 1.5.0rc03 [December 28, 2010] + Eliminated scripts/*.def and revised Makefile.am accordingly + +Version 1.5.0rc04 [December 29, 2010] + Fixed bug in background transformation handling in pngrtran.c (it was + looking for the flag in png_ptr->transformations instead of in + png_ptr->flags) (David Raymond). + +Version 1.5.0rc05 [December 31, 2010] + Fixed typo in a comment in CMakeLists.txt (libpng14 => libpng15) (Cosmin) + +Version 1.5.0rc06 [January 4, 2011] + Changed the new configure option "zprefix=string" to "zlib-prefix=string" + +Version 1.5.0rc07 [January 4, 2011] + Updated copyright year. + +Version 1.5.0 [January 6, 2011] + No changes. + +version 1.5.1beta01 [January 8, 2011] + Added description of png_set_crc_action() to the manual. + Added a note in the manual that the type of the iCCP profile was changed + from png_charpp to png_bytepp in png_get_iCCP(). This change happened + in version 1.5.0beta36 but is not noted in the CHANGES. Similarly, + it was changed from png_charpp to png_const_bytepp in png_set_iCCP(). + Ensure that png_rgb_to_gray ignores palette mapped images, if libpng + internally happens to call it with one, and fixed a failure to handle + palette mapped images correctly. This fixes CVE-2690. + +Version 1.5.1beta02 [January 14, 2011] + Fixed a bug in handling of interlaced images (bero at arklinux.org). + Updated CMakeLists.txt (Clifford Yapp) + +Version 1.5.1beta03 [January 14, 2011] + Fixed typecasting of some png_debug() statements (Cosmin) + +Version 1.5.1beta04 [January 16, 2011] + Updated documentation of png_set|get_tRNS() (Thomas Klausner). + Mentioned in the documentation that applications must #include "zlib.h" + if they need access to anything in zlib.h, and that a number of + macros such as png_memset() are no longer accessible by applications. + Corrected pngvalid gamma test "sample" function to access all of the color + samples of each pixel, instead of sampling the red channel three times. + Prefixed variable names index, div, exp, gamma with "png_" to avoid "shadow" + warnings, and (mistakenly) changed png_exp() to exp(). + +Version 1.5.1beta05 [January 16, 2011] + Changed variable names png_index, png_div, png_exp, and png_gamma to + char_index, divisor, exp_b10, and gamma_val, respectively, and + changed exp() back to png_exp(). + +Version 1.5.1beta06 [January 20, 2011] + Prevent png_push_crc_skip() from hanging while reading an unknown chunk + or an over-large compressed zTXt chunk with the progressive reader. + Eliminated more GCC "shadow" warnings. + Revised png_fixed() in png.c to avoid compiler warning about reaching the + end without returning anything. + +Version 1.5.1beta07 [January 22, 2011] + In the manual, describe the png_get_IHDR() arguments in the correct order. + Added const_png_structp and const_png_infop types, and used them in + prototypes for most png_get_*() functions. + +Version 1.5.1beta08 [January 23, 2011] + Added png_get_io_chunk_type() and deprecated png_get_io_chunk_name() + Added synopses for the IO_STATE functions and other missing synopses + to the manual. Removed the synopses from libpngpf.3 because they + were out of date and no longer useful. Better information can be + obtained by reading the prototypes and comments in pngpriv.h + Attempted to fix cpp on Solaris with S. Studio 12 cc, fix build + Added a make macro DFNCPP that is a CPP that will accept the tokens in + a .dfn file and adds configure stuff to test for such a CPP. ./configure + should fail if one is not available. + Corrected const_png_ in png.h to png_const_ to avoid polluting the namespace. + Added png_get_current_row_number and png_get_current_pass_number for the + benefit of the user transform callback. + Added png_process_data_pause and png_process_data_skip for the benefit of + progressive readers that need to stop data processing or want to optimize + skipping of unread data (e.g., if the reader marks a chunk to be skipped.) + +Version 1.5.1beta09 [January 24, 2011] + Enhanced pngvalid, corrected an error in gray_to_rgb, corrected doc error. + pngvalid contains tests of transforms, which tests are currently disabled + because they are incompletely tested. gray_to_rgb was failing to expand + the bit depth for smaller bit depth images; this seems to be a long + standing error and resulted, apparently, in invalid output + (CVE-2011-0408, CERT VU#643140). The documentation did not accurately + describe what libpng really does when converting RGB to gray. + +Version 1.5.1beta10 [January 27, 2010] + Fixed incorrect examples of callback prototypes in the manual, that were + introduced in libpng-1.0.0. + In addition the order of the png_get_uint macros with respect to the + relevant function definitions has been reversed. This helps the + preprocessing of the symbol files be more robust. Furthermore, the + symbol file preprocessing now uses -DPNG_NO_USE_READ_MACROS even when + the library may actually be built with PNG_USE_READ_MACROS; this stops + the read macros interfering with the symbol file format. + Made the manual, synopses, and function prototypes use the function + argument names file_gamma, int_file_gamma, and srgb_intent consistently. + +Version 1.5.1beta11 [January 28, 2011] + Changed PNG_UNUSED from "param=param;" to "{if(param){}}". + Corrected local variable type in new API png_process_data_skip() + The type was self-evidently incorrect but only causes problems on 64-bit + architectures. + Added transform tests to pngvalid and simplified the arguments. + +Version 1.5.1rc01 [January 29, 2011] + No changes. + +Version 1.5.1rc02 [January 31, 2011] + Added a request in the manual that applications do not use "png_" or + "PNG_" to begin any of their own symbols. + Changed PNG_UNUSED to "(void)param;" and updated the commentary in pngpriv.h + +Version 1.5.1 [February 3, 2011] + No changes. + +Version 1.5.2beta01 [February 13, 2011] + More -Wshadow fixes for older gcc compilers. Older gcc versions apparently + check formal parameters names in function declarations (as well as + definitions) to see if they match a name in the global namespace. + Revised PNG_EXPORTA macro to not use an empty parameter, to accommodate the + old VisualC++ preprocessor. + Turned on interlace handling in png_read_png(). + Fixed gcc pendantic warnings. + Handle longjmp in Cygwin. + Fixed png_get_current_row_number() in the interlaced case. + Cleaned up ALPHA flags and transformations. + Implemented expansion to 16 bits. + +Version 1.5.2beta02 [February 19, 2011] + Fixed mistake in the descriptions of user read_transform and write_transform + function prototypes in the manual. The row_info struct is png_row_infop. + Reverted png_get_current_row_number() to previous (1.5.2beta01) behavior. + Corrected png_get_current_row_number documentation + Fixed the read/write row callback documentation. + This documents the current behavior, where the callback is called after + every row with information pertaining to the next row. + +Version 1.5.2beta03 [March 3, 2011] + Fixed scripts/makefile.vcwin32 + Updated contrib/pngsuite/README to add the word "modify". + Define PNG_ALLOCATED to blank when _MSC_VER<1300. + +Version 1.5.2rc01 [March 19, 2011] + Define remaining attributes to blank when MSC_VER<1300. + ifdef out mask arrays in pngread.c when interlacing is not supported. + +Version 1.5.2rc02 [March 22, 2011] + Added a hint to try CPP=/bin/cpp if "cpp -E" fails in scripts/pnglibconf.mak + and in contrib/pngminim/*/makefile, eg., on SunOS 5.10, and removed "strip" + from the makefiles. + Fixed a bug (present since libpng-1.0.7) that makes png_handle_sPLT() fail + to compile when PNG_NO_POINTER_INDEXING is defined (Chubanov Kirill) + +Version 1.5.2rc03 [March 24, 2011] + Don't include standard header files in png.h while building the symbol table, + to avoid cpp failure on SunOS (introduced PNG_BUILDING_SYMBOL_TABLE macro). + +Version 1.5.2 [March 31, 2011] + No changes. + +Version 1.5.3beta01 [April 1, 2011] + Re-initialize the zlib compressor before compressing non-IDAT chunks. + Added API functions (png_set_text_compression_level() and four others) to + set parameters for zlib compression of non-IDAT chunks. + +Version 1.5.3beta02 [April 3, 2011] + Updated scripts/symbols.def with new API functions. + Only compile the new zlib re-initializing code when text or iCCP is + supported, using PNG_WRITE_COMPRESSED_TEXT_SUPPORTED macro. + Improved the optimization of the zlib CMF byte (see libpng-1.2.6beta03). + Optimize the zlib CMF byte in non-IDAT compressed chunks + +Version 1.5.3beta03 [April 16, 2011] + Fixed gcc -ansi -pedantic compile. A strict ANSI system does not have + snprintf, and the "__STRICT_ANSI__" detects that condition more reliably + than __STDC__ (John Bowler). + Removed the PNG_PTR_NORETURN attribute because it too dangerous. It tells + the compiler that a user supplied callback (the error handler) does not + return, yet there is no guarantee in practice that the application code + will correctly implement the error handler because the compiler only + issues a warning if there is a mistake (John Bowler). + Removed the no-longer-used PNG_DEPSTRUCT macro. + Updated the zlib version to 1.2.5 in the VStudio project. + Fixed 64-bit builds where png_uint_32 is smaller than png_size_t in + pngwutil.c (John Bowler). + Fixed bug with stripping the filler or alpha channel when writing, that + was introduced in libpng-1.5.2beta01 (bug report by Andrew Church). + +Version 1.5.3beta04 [April 27, 2011] + Updated pngtest.png with the new zlib CMF optimization. + Cleaned up conditional compilation code and of background/gamma handling + Internal changes only except a new option to avoid compiling the + png_build_grayscale_palette API (which is not used at all internally.) + The main change is to move the transform tests (READ_TRANSFORMS, + WRITE_TRANSFORMS) up one level to the caller of the APIs. This avoids + calls to spurious functions if all transforms are disabled and slightly + simplifies those functions. Pngvalid modified to handle this. + A minor change is to stop the strip_16 and expand_16 interfaces from + disabling each other; this allows the future alpha premultiplication + code to use 16-bit intermediate values while still producing 8-bit output. + png_do_background and png_do_gamma have been simplified to take a single + pointer to the png_struct rather than pointers to every item required + from the png_struct. This makes no practical difference to the internal + code. + A serious bug in the pngvalid internal routine 'standard_display_init' has + been fixed - this failed to initialize the red channel and accidentally + initialized the alpha channel twice. + Changed png_struct jmp_buf member name from png_jmpbuf to tmp_jmpbuf to + avoid a possible clash with the png_jmpbuf macro on some platforms. + +Version 1.5.3beta05 [May 6, 2011] + Added the "_POSIX_SOURCE" feature test macro to ensure libpng sees the + correct API. _POSIX_SOURCE is defined in pngpriv.h, pngtest.c and + pngvalid.c to ensure that POSIX conformant systems disable non-POSIX APIs. + Removed png_snprintf and added formatted warning messages. This change adds + internal APIs to allow png_warning messages to have parameters without + requiring the host OS to implement snprintf. As a side effect the + dependency of the tIME-supporting RFC1132 code on stdio is removed and + PNG_NO_WARNINGS does actually work now. + Pass "" instead of '\0' to png_default_error() in png_err(). This mistake + was introduced in libpng-1.2.20beta01. This fixes CVE-2011-2691. + Added PNG_WRITE_OPTIMIZE_CMF_SUPPORTED macro to make the zlib "CMF" byte + optimization configureable. + IDAT compression failed if preceded by a compressed text chunk (bug + introduced in libpng-1.5.3beta01-02). This was because the attempt to + reset the zlib stream in png_write_IDAT happened after the first IDAT + chunk had been deflated - much too late. In this change internal + functions were added to claim/release the z_stream and, hopefully, make + the code more robust. Also deflateEnd checking is added - previously + libpng would ignore an error at the end of the stream. + +Version 1.5.3beta06 [May 8, 2011] + Removed the -D_ALL_SOURCE from definitions for AIX in CMakeLists.txt + Implemented premultiplied alpha support: png_set_alpha_mode API + +Version 1.5.3beta07 [May 11, 2011] + Added expand_16 support to the high level interface. + Added named value and 'flag' gamma support to png_set_gamma. Made a minor + change from the previous (unreleased) ABI/API to hide the exact value used + for Macs - it's not a good idea to embed this in the ABI! + Moved macro definitions for PNG_HAVE_IHDR, PNG_HAVE_PLTE, and PNG_AFTER_IDAT + from pngpriv.h to png.h because they must be visible to applications + that call png_set_unknown_chunks(). + Check for up->location !PNG_AFTER_IDAT when writing unknown chunks + before IDAT. + +Version 1.5.3beta08 [May 16, 2011] + Improved "pngvalid --speed" to exclude more of pngvalid from the time. + Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt + The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative + parameters are supplied by the caller), while in the absence of cHRM + sRGB/Rec 709 values are still used. This introduced a divide-by-zero + bug in png_handle_cHRM(). + The bKGD chunk no longer overwrites the background value set by + png_set_background(), allowing the latter to be used before the file + header is read. It never performed any useful function to override + the default anyway. + Added memory overwrite and palette image checks to pngvalid.c + Previously palette image code was poorly checked. Since the transformation + code has a special palette path in most cases this was a severe weakness. + Minor cleanup and some extra checking in pngrutil.c and pngrtran.c. When + expanding an indexed image, always expand to RGBA if transparency is + present. + +Version 1.5.3beta09 [May 17, 2011] + Reversed earlier 1.5.3 change of transformation order; move png_expand_16 + back where it was. The change doesn't work because it requires 16-bit + gamma tables when the code only generates 8-bit ones. This fails + silently; the libpng code just doesn't do any gamma correction. Moving + the tests back leaves the old, inaccurate, 8-bit gamma calculations, but + these are clearly better than none! + +Version 1.5.3beta10 [May 20, 2011] + + png_set_background() and png_expand_16() did not work together correctly. + This problem is present in 1.5.2; if png_set_background is called with + need_expand false and the matching 16 bit color libpng erroneously just + treats it as an 8-bit color because of where png_do_expand_16 is in the + transform list. This simple fix reduces the supplied colour to 8-bits, + so it gets smashed, but this is better than the current behavior. + Added tests for expand16, more fixes for palette image tests to pngvalid. + Corrects the code for palette image tests and disables attempts to + validate palette colors. + +Version 1.5.3rc01 [June 3, 2011] + No changes. + +Version 1.5.3rc02 [June 8, 2011] + Fixed uninitialized memory read in png_format_buffer() (Bug report by + Frank Busse, CVE-2011-2501, related to CVE-2004-0421). + +Version 1.5.3beta11 [June 11, 2011] + Fixed png_handle_sCAL which is broken in 1.5. This fixes CVE 2011-2692. + Added sCAL to pngtest.png + Revised documentation about png_set_user_limits() to say that it also affects + png writing. + Revised handling of png_set_user_limits() so that it can increase the + limit beyond the PNG_USER_WIDTH|HEIGHT_MAX; previously it could only + reduce it. + Make the 16-to-8 scaling accurate. Dividing by 256 with no rounding is + wrong (high by one) 25% of the time. Dividing by 257 with rounding is + wrong in 128 out of 65536 cases. Getting the right answer all the time + without division is easy. + Added "_SUPPORTED" to the PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION macro. + Added projects/owatcom, an IDE project for OpenWatcom to replace + scripts/makefile.watcom. This project works with OpenWatcom 1.9. The + IDE autogenerates appropriate makefiles (libpng.mk) for batch processing. + The project is configurable, unlike the Visual Studio project, so long + as the developer has an awk. + Changed png_set_gAMA to limit the gamma value range so that the inverse + of the stored value cannot overflow the fixed point representation, + and changed other things OpenWatcom warns about. + Revised pngvalid.c to test PNG_ALPHA_MODE_SUPPORTED correctly. This allows + pngvalid to build when ALPHA_MODE is not supported, which is required if + it is to build on libpng 1.4. + Removed string/memory macros that are no longer used and are not + necessarily fully supportable, particularly png_strncpy and png_snprintf. + Added log option to pngvalid.c and attempted to improve gamma messages. + +Version 1.5.3 [omitted] + People found the presence of a beta release following an rc release + to be confusing; therefore we bump the version to libpng-1.5.4beta01 + and there will be no libpng-1.5.3 release. + +Version 1.5.4beta01 [June 14, 2011] + Made it possible to undefine PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED + to get the same (inaccurate) output as libpng-1.5.2 and earlier. + Moved definitions of PNG_HAVE_IHDR, PNG_AFTER_IDAT, and PNG_HAVE_PLTE + outside of an unknown-chunk block in png.h because they are also + needed for other uses. + +Version 1.5.4beta02 [June 14, 2011] + Fixed and clarified LEGACY 16-to-8 scaling code. + Added png_set_chop_16() API, to match inaccurate results from previous + libpng versions. + Removed the ACCURATE and LEGACY options (they are no longer useable) + Use the old scaling method for background if png_set_chop_16() was + called. + Made png_set_chop_16() API removeable by disabling PNG_CHOP_16_TO_8_SUPPORTED + +Version 1.5.4beta03 [June 15, 2011] + Fixed a problem in png_do_expand_palette() exposed by optimization in + 1.5.3beta06 + Also removed a spurious and confusing "trans" member ("trans") from png_info. + The palette expand optimization prevented expansion to an intermediate RGBA + form if tRNS was present but alpha was marked to be stripped; this exposed + a check for tRNS in png_do_expand_palette() which is inconsistent with the + code elsewhere in libpng. + Correction to the expand_16 code; removed extra instance of + png_set_scale_16_to_8 from pngpriv.h + +Version 1.5.4beta04 [June 16, 2011] + Added a missing "#ifdef PNG_READ_BACKGROUND_SUPPORTED/#endif" in pngrtran.c + Added PNG_TRANSFORM_CHOP_16 to the high-level read transforms. + Made PNG_READ_16_TO_8_ACCURATE_SCALE configurable again. If this is + not enabled, png_set_strip_16() and png_do_scale_16_to_8() aren't built. + Revised contrib/visupng, gregbook, and pngminim to demonstrate chop_16_to_8 + +Version 1.5.4beta05 [June 16, 2011] + Renamed png_set_strip_16() to png_set_scale_16() and renamed + png_set_chop_16() to png_set_strip(16) in an attempt to minimize the + behavior changes between libpng14 and libpng15. + +Version 1.5.4beta06 [June 18, 2011] + Fixed new bug that was causing both strip_16 and scale_16 to be applied. + +Version 1.5.4beta07 [June 19, 2011] + Fixed pngvalid, simplified macros, added checking for 0 in sCAL. + The ACCURATE scale macro is no longer defined in 1.5 - call the + png_scale_16_to_8 API. Made sure that PNG_READ_16_TO_8 is still defined + if the png_strip_16_to_8 API is present. png_check_fp_number now + maintains some state so that positive, negative and zero values are + identified. sCAL uses these to be strictly spec conformant. + +Version 1.5.4beta08 [June 23, 2011] + Fixed pngvalid if ACCURATE_SCALE is defined. + Updated scripts/pnglibconf.h.prebuilt. + +Version 1.5.4rc01 [June 30, 2011] + Define PNG_ALLOCATED to "restrict" only if MSC_VER >= 1400. + +Version 1.5.4 [July 7, 2011] + No changes. + +Version 1.5.5beta01 [July 13, 2011] + Fixed some typos and made other minor changes in the manual. + Updated contrib/pngminus/makefile.std (Samuli Souminen) + +Version 1.5.5beta02 [July 14, 2011] + Revised Makefile.am and Makefile.in to look in the right directory for + pnglibconf.h.prebuilt + +Version 1.5.5beta03 [July 27, 2011] + Enabled compilation with g++ compiler. This compiler does not recognize + the file extension, so it always compiles with C++ rules. Made minor + changes to pngrutil.c to cast results where C++ expects it but C does not. + Minor editing of libpng.3 and libpng-manual.txt. + +Version 1.5.5beta04 [July 29, 2011] + Revised CMakeLists.txt (Clifford Yapp) + Updated commentary about the png_rgb_to_gray() default coefficients + in the manual and in pngrtran.c + +Version 1.5.5beta05 [August 17, 2011] + Prevent unexpected API exports from non-libpng DLLs on Windows. The "_DLL" + is removed from the test of whether a DLL is being built (this erroneously + caused the libpng APIs to be marked as DLL exports in static builds under + Microsoft Visual Studio). Almost all of the libpng building configuration + is moved from pngconf.h to pngpriv.h, but PNG_DLL_EXPORT remains in + pngconf.h, though, so that it is colocated with the import definition (it + is no longer used anywhere in the installed headers). The VStudio project + definitions have been cleaned up: "_USRDLL" has been removed from the + static library builds (this was incorrect), and PNG_USE_DLL has been added + to pngvalid to test the functionality (pngtest does not supply it, + deliberately). The spurious "_EXPORTS" has been removed from the + libpng build (all these errors were a result of copy/paste between project + configurations.) + Added new types and internal functions for CIE RGB end point handling to + pngpriv.h (functions yet to be implemented). + +Version 1.5.5beta06 [August 26, 2011] + Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set in CMakeLists.txt + (Clifford Yap) + Fixes to rgb_to_gray and cHRM XYZ APIs (John Bowler): + The rgb_to_gray code had errors when combined with gamma correction. + Some pixels were treated as true grey when they weren't and such pixels + and true grey ones were not gamma corrected (the original value of the + red component was used instead). APIs to get and set cHRM using color + space end points have been added and the rgb_to_gray code that defaults + based on cHRM, and the divide-by-zero bug in png_handle_cHRM (CERT + VU#477046, CVE-2011-3328, introduced in 1.5.4) have been corrected. + A considerable number of tests has been added to pngvalid for the + rgb_to_gray transform. + Arithmetic errors in rgb_to_gray whereby the calculated gray value was + truncated to the bit depth rather than rounded have been fixed except in + the 8-bit non-gamma-corrected case (where consistency seems more important + than correctness.) The code still has considerable inaccuracies in the + 8-bit case because 8-bit linear arithmetic is used. + +Version 1.5.5beta07 [September 7, 2011] + Added "$(ARCH)" option to makefile.darwin + Added SunOS support to configure.ac and Makefile.am + Changed png_chunk_benign_error() to png_warning() in png.c, in + png_XYZ_from_xy_checked(). + +Version 1.5.5beta08 [September 10, 2011] + Fixed 64-bit compilation errors (gcc). The errors fixed relate + to conditions where types that are 32 bits in the GCC 32-bit + world (uLong and png_size_t) become 64 bits in the 64-bit + world. This produces potential truncation errors which the + compiler correctly flags. + Relocated new HAVE_SOLARIS_LD definition in configure.ac + Constant changes for 64-bit compatibility (removal of L suffixes). The + 16-bit cases still use "L" as we don't have a 16-bit test system. + +Version 1.5.5rc01 [September 15, 2011] + Removed "L" suffixes in pngpriv.h + +Version 1.5.5 [September 22, 2011] + No changes. + +Version 1.5.6beta01 [September 22, 2011] + Fixed some 64-bit type conversion warnings in pngrtran.c + Moved row_info from png_struct to a local variable. + The various interlace mask arrays have been made into arrays of + bytes and made PNG_CONST and static (previously some arrays were + marked PNG_CONST and some weren't). + Additional checks have been added to the transform code to validate the + pixel depths after the transforms on both read and write. + Removed some redundant code from pngwrite.c, in png_destroy_write_struct(). + Changed chunk reading/writing code to use png_uint_32 instead of png_byte[4]. + This removes the need to allocate temporary strings for chunk names on + the stack in the read/write code. Unknown chunk handling still uses the + string form because this is exposed in the API. + +Version 1.5.6beta02 [September 26, 2011] + Added a note in the manual the png_read_update_info() must be called only + once with a particular info_ptr. + Fixed a typo in the definition of the new PNG_STRING_FROM_CHUNK(s,c) macro. + +Version 1.5.6beta03 [September 28, 2011] + Revised test-pngtest.sh to report FAIL when pngtest fails. + Added "--strict" option to pngtest, to report FAIL when the failure is + only because the resulting valid files are different. + Revised CMakeLists.txt to work with mingw and removed some material from + CMakeLists.txt that is no longer useful in libpng-1.5. + +Version 1.5.6beta04 [October 5, 2011] + Fixed typo in Makefile.in and Makefile.am ("-M Wl" should be "-M -Wl")." + +Version 1.5.6beta05 [October 12, 2011] + Speed up png_combine_row() for interlaced images. This reduces the generality + of the code, allowing it to be optimized for Adam7 interlace. The masks + passed to png_combine_row() are now generated internally, avoiding + some code duplication and localizing the interlace handling somewhat. + Align png_struct::row_buf - previously it was always unaligned, caused by + a bug in the code that attempted to align it; the code needs to subtract + one from the pointer to take account of the filter byte prepended to + each row. + Optimized png_combine_row() when rows are aligned. This gains a small + percentage for 16-bit and 32-bit pixels in the typical case where the + output row buffers are appropriately aligned. The optimization was not + previously possible because the png_struct buffer was always misaligned. + Fixed bug in png_write_chunk_header() debug print, introduced in 1.5.6beta01. + +Version 1.5.6beta06 [October 17, 2011] + Removed two redundant tests for unitialized row. + Fixed a relatively harmless memory overwrite in compressed text writing + with a 1 byte zlib buffer. + Add ability to call png_read_update_info multiple times to pngvalid.c. + Fixes for multiple calls to png_read_update_info. These fixes attend to + most of the errors revealed in pngvalid, however doing the gamma work + twice results in inaccuracies that can't be easily fixed. There is now + a warning in the code if this is going to happen. + Turned on multiple png_read_update_info in pngvalid transform tests. + Prevent libpng from overwriting unused bits at the end of the image when + it is not byte aligned, while reading. Prior to libpng-1.5.6 libpng would + overwrite the partial byte at the end of each row if the row width was not + an exact multiple of 8 bits and the image is not interlaced. + +Version 1.5.6beta07 [October 21, 2011] + Made png_ptr->prev_row an aligned pointer into png_ptr->big_prev_row + (Mans Rullgard). + +Version 1.5.6rc01 [October 26, 2011] + Changed misleading "Missing PLTE before cHRM" warning to "Out of place cHRM" + +Version 1.5.6rc02 [October 27, 2011] + Added LSR() macro to defend against buggy compilers that evaluate non-taken + code branches and complain about out-of-range shifts. + +Version 1.5.6rc03 [October 28, 2011] + Renamed the LSR() macro to PNG_LSR() and added PNG_LSL() macro. + Fixed compiler warnings with Intel and MSYS compilers. The logical shift + fix for Microsoft Visual C is required by other compilers, so this + enables that fix for all compilers when using compile-time constants. + Under MSYS 'byte' is a name declared in a system header file, so we + changed the name of a local variable to avoid the warnings that result. + Added #define PNG_ALIGN_TYPE PNG_ALIGN_NONE to contrib/pngminim/*/pngusr.h + +Version 1.5.6 [November 3, 2011] + No changes. + +Version 1.5.7beta01 [November 4, 2011] + Added support for ARM processor, when decoding all PNG up-filtered rows + and any other-filtered rows with 3 or 4 bytes per pixel (Mans Rullgard). + Fixed bug in pngvalid on early allocation failure; fixed type cast in + pngmem.c; pngvalid would attempt to call png_error() if the allocation + of a png_struct or png_info failed. This would probably have led to a + crash. The pngmem.c implementation of png_malloc() included a cast + to png_size_t which would fail on large allocations on 16-bit systems. + Fix for the preprocessor of the Intel C compiler. The preprocessor + splits adjacent @ signs with a space; this changes the concatentation + token from @-@-@ to PNG_JOIN; that should work with all compiler + preprocessors. + Paeth filter speed improvements from work by Siarhei Siamashka. This + changes the 'Paeth' reconstruction function to improve the GCC code + generation on x86. The changes are only part of the suggested ones; + just the changes that definitely improve speed and remain simple. + The changes also slightly increase the clarity of the code. + +Version 1.5.7beta02 [November 11, 2011] + Check compression_type parameter in png_get_iCCP and remove spurious + casts. The compression_type parameter is always assigned to, so must + be non-NULL. The cast of the profile length potentially truncated the + value unnecessarily on a 16-bit int system, so the cast of the (byte) + compression type to (int) is specified by ANSI-C anyway. + Fixed FP division by zero in pngvalid.c; the 'test_pixel' code left + the sBIT fields in the test pixel as 0, which resulted in a floating + point division by zero which was irrelevant but causes systems where + FP exceptions cause a crash. Added code to pngvalid to turn on FP + exceptions if the appropriate glibc support is there to ensure this is + tested in the future. + Updated scripts/pnglibconf.mak and scripts/makefile.std to handle the + new PNG_JOIN macro. + Added versioning to pnglibconf.h comments. + Simplified read/write API initial version; basic read/write tested on + a variety of images, limited documentation (in the header file.) + Installed more accurate linear to sRGB conversion tables. The slightly + modified tables reduce the number of 16-bit values that + convert to an off-by-one 8-bit value. The "makesRGB.c" code that was used + to generate the tables is now in a contrib/sRGBtables sub-directory. + +Version 1.5.7beta03 [November 17, 2011] + Removed PNG_CONST from the sRGB table declarations in pngpriv.h and png.c + Added run-time detection of NEON support. + Added contrib/libtests; includes simplified API test and timing test and + a color conversion utility for rapid checking of failed 'pngstest' results. + Multiple transform bug fixes plus a work-round for double gamma correction. + libpng does not support more than one transform that requires linear data + at once - if this is tried typically the results is double gamma + correction. Since the simplified APIs can need rgb to gray combined with + a compose operation it is necessary to do one of these outside the main + libpng transform code. This check-in also contains fixes to various bugs + in the simplified APIs themselves and to some bugs in compose and rgb to + gray (on palette) itself. + Fixes for C++ compilation using g++ When libpng source is compiled + using g++. The compiler imposes C++ rules on the C source; thus it + is desireable to make the source work with either C or C++ rules + without throwing away useful error information. This change adds + png_voidcast to allow C semantic (void*) cases or the corresponding + C++ static_cast operation, as appropriate. + Added --noexecstack to assembler file compilation. GCC does not set + this on assembler compilation, even though it does on C compilation. + This creates security issues if assembler code is enabled; the + work-around is to set it by default in the flags for $(CCAS) + Work around compilers that don't support declaration of const data. Some + compilers fault 'extern const' data declarations (because the data is + not initialized); this turns on const-ness only for compilers where + this is known to work. + +Version 1.5.7beta04 [November 17, 2011] + Since the gcc driver does not recognize the --noexecstack flag, we must + use the -Wa prefix to have it passed through to the assembler. + Also removed a duplicate setting of this flag. + Added files that were omitted from the libpng-1.5.7beta03 zip distribution. + +Version 1.5.7beta05 [November 25, 2011] + Removed "zTXt" from warning in generic chunk decompression function. + Validate time settings passed to pngset() and png_convert_to_rfc1123() + (Frank Busse). + Added MINGW support to CMakeLists.txt + Reject invalid compression flag or method when reading the iTXt chunk. + Backed out 'simplified' API changes. The API seems too complex and there + is a lack of consensus or enthusiasm for the proposals. The API also + reveals significant bugs inside libpng (double gamma correction and the + known bug of being unable to retrieve a corrected palette). It seems + better to wait until the bugs, at least, are corrected. + Moved pngvalid.c into contrib/libtests + Rebuilt Makefile.in, configure, etc., with autoconf-2.68 + +Version 1.5.7rc01 [December 1, 2011] + Replaced an "#if" with "#ifdef" in pngrtran.c + Revised #if PNG_DO_BC block in png.c (use #ifdef and add #else) + +Version 1.5.7rc02 [December 5, 2011] + Revised project files and contrib/pngvalid/pngvalid.c to account for + the relocation of pngvalid into contrib/libtests. + Revised pngconf.h to use " __declspec(restrict)" only when MSC_VER >= 1400, + as in libpng-1.5.4. + Put CRLF line endings in the owatcom project files. + +Version 1.5.7rc03 [December 7, 2011] + Updated CMakeLists.txt to account for the relocation of pngvalid.c + +Version 1.5.7 [December 15, 2011] + Minor fixes to pngvalid.c for gcc 4.6.2 compatibility to remove warnings + reported by earlier versions. + Fixed minor memset/sizeof errors in pngvalid.c. + +Version 1.6.0beta01 [December 15, 2011] + Removed machine-generated configure files from the GIT repository (they will + continue to appear in the tarball distributions and in the libpng15 and + earlier GIT branches). + Restored the new 'simplified' API, which was started in libpng-1.5.7beta02 + but later deleted from libpng-1.5.7beta05. + Added example programs for the new 'simplified' API. + Added ANSI-C (C90) headers and require them, and take advantage of the + change. Also fixed some of the projects/* and contrib/* files that needed + updates for libpng16 and the move of pngvalid.c. + With this change the required ANSI-C header files are assumed to exist: the + implementation must provide float.h, limits.h, stdarg.h and stddef.h and + libpng relies on limits.h and stddef.h existing and behaving as defined + (the other two required headers aren't used). Non-ANSI systems that don't + have stddef.h or limits.h will have to provide an appropriate fake + containing the relevant types and #defines. + The use of FAR/far has been eliminated and the definition of png_alloc_size_t + is now controlled by a flag so that 'small size_t' systems can select it + if necessary. Libpng 1.6 may not currently work on such systems -- it + seems likely that it will ask 'malloc' for more than 65535 bytes with any + image that has a sufficiently large row size (rather than simply failing + to read such images). + New tools directory containing tools used to generate libpng code. + Fixed race conditions in parallel make builds. With higher degrees of + parallelism during 'make' the use of the same temporary file names such + as 'dfn*' can result in a race where a temporary file from one arm of the + build is deleted or overwritten in another arm. This changes the + temporary files for suffix rules to always use $* and ensures that the + non-suffix rules use unique file names. + +Version 1.6.0beta02 [December 21, 2011] + Correct configure builds where build and source directories are separate. + The include path of 'config.h' was erroneously made relative in pngvalid.c + in libpng 1.5.7. + +Version 1.6.0beta03 [December 22, 2011] + Start-up code size improvements, error handler flexibility. These changes + alter how the tricky allocation of the initial png_struct and png_info + structures are handled. png_info is now handled in pretty much the same + way as everything else, except that the allocations handle NULL return + silently. png_struct is changed in a similar way on allocation and on + deallocation a 'safety' error handler is put in place (which should never + be required). The error handler itself is changed to permit mismatches + in the application and libpng error buffer size; however, this means a + silent change to the API to return the jmp_buf if the size doesn't match + the size from the libpng compilation; libpng now allocates the memory and + this may fail. Overall these changes result in slight code size + reductions; however, this is a reduction in code that is always executed + so is particularly valuable. Overall on a 64-bit system the libpng DLL + decreases in code size by 1733 bytes. pngerror.o increases in size by + about 465 bytes because of the new functionality. + Added png_convert_to_rfc1123_buffer() and deprecated png_convert_to_rfc1123() + to avoid including a spurious buffer in the png_struct. + +Version 1.6.0beta04 [December 30, 2011] + Regenerated configure scripts with automake-1.11.2 + Eliminated png_info_destroy(). It is now used only in png.c and only calls + one other internal function and memset(). + Enabled png_get_sCAL_fixed() if floating point APIs are enabled. Previously + it was disabled whenever internal fixed point arithmetic was selected, + which meant it didn't exist even on systems where FP was available but not + preferred. + Added pngvalid.c compile time checks for const APIs. + Implemented 'restrict' for png_info and png_struct. Because of the way + libpng works both png_info and png_struct are always accessed via a + single pointer. This means adding C99 'restrict' to the pointer gives + the compiler some opportunity to optimize the code. This change allows + that. + Moved AC_MSG_CHECKING([if libraries can be versioned]) later to the proper + location in configure.ac (Gilles Espinasse). + Changed png_memcpy to C assignment where appropriate. Changed all those + uses of png_memcpy that were doing a simple assignment to assignments + (all those cases where the thing being copied is a non-array C L-value). + Added some error checking to png_set_*() routines. + Removed the reference to the non-exported function png_memcpy() from + example.c. + Fixed the Visual C 64-bit build - it requires jmp_buf to be aligned, but + it had become misaligned. + Revised contrib/pngminus/pnm2png.c to avoid warnings when png_uint_32 + and unsigned long are of different sizes. + +Version 1.6.0beta05 [January 15, 2012] + Updated manual with description of the simplified API (copied from png.h) + Fix bug in pngerror.c: some long warnings were being improperly truncated + (CVE-2011-3464, bug introduced in libpng-1.5.3beta05). + +Version 1.6.0beta06 [January 24, 2012] + Added palette support to the simplified APIs. This commit + changes some of the macro definitions in png.h, app code + may need corresponding changes. + Increased the formatted warning buffer to 192 bytes. + Added color-map support to simplified API. This is an initial version for + review; the documentation has not yet been updated. + Fixed Min/GW uninstall to remove libpng.dll.a + +Version 1.6.0beta07 [January 28, 2012] + Eliminated Intel icc/icl compiler warnings. The Intel (GCC derived) + compiler issues slightly different warnings from those issued by the + current vesions of GCC. This eliminates those warnings by + adding/removing casts and small code rewrites. + Updated configure.ac from autoupdate: added --enable-werror option. + Also some layout regularization and removal of introduced tab characters + (replaced with 3-character indentation). Obsolete macros identified by + autoupdate have been removed; the replacements are all in 2.59 so + the pre-req hasn't been changed. --enable-werror checks for support + for -Werror (or the given argument) in the compiler. This mimics the + gcc configure option by allowing -Werror to be turned on safely; without + the option the tests written in configure itself fail compilation because + they cause compiler warnings. + Rewrote autogen.sh to run autoreconf instead of running tools one-by-one. + Conditionalize the install rules for MINGW and CYGWIN in CMakeLists.txt and + set CMAKE_LIBRARY_OUTPUT_DIRECTORY to "lib" on all platforms (C. Yapp). + Freeze libtool files in the 'scripts' directory. This version of autogen.sh + attempts to dissuade people from running it when it is not, or should not, + be necessary. In fact, autogen.sh does not work when run in a libpng + directory extracted from a tar distribution anymore. You must run it in + a GIT clone instead. + Added two images to contrib/pngsuite (1-bit and 2-bit transparent grayscale), + and renamed three whose names were inconsistent with those in + pngsuite/README.txt. + +Version 1.6.0beta08 [February 1, 2012] + Fixed Image::colormap misalignment in pngstest.c + Check libtool/libtoolize version number (2.4.2) in configure.ac + Divide test-pngstest.sh into separate pngstest runs for basic and + transparent images. + Moved automake options to AM_INIT_AUTOMAKE in configure.ac + Added color-tests, silent-rules (Not yet implemented in Makefile.am) and + version checking to configure.ac + Improved pngstest speed by not doing redundant tests and add const to + the background parameter of png_image_finish_read. The --background + option is now done automagically only when required, so that commandline + option no longer exists. + Cleaned up pngpriv.h to consistently declare all functions and data. + Also eliminated PNG_CONST_DATA, which is apparently not needed but we + can't be sure until it is gone. + Added symbol prefixing that allows all the libpng external symbols + to be prefixed (suggested by Reuben Hawkins). + Updated "ftbb*.png" list in the owatcom and vstudio projects. + Fixed 'prefix' builds on clean systems. The generation of pngprefix.h + should not require itself. + Updated INSTALL to explain that autogen.sh must be run in a GIT clone, + not in a libpng directory extracted from a tar distribution. + +Version 1.6.0beta09 [February 1, 2012] + Reverted the prebuilt configure files to libpng-1.6.0beta05 condition. + +Version 1.6.0beta10 [February 3, 2012] + Added Z_SOLO for zlib-1.2.6+ and correct pngstest tests + Updated list of test images in CMakeLists.txt + Updated the prebuilt configure files to current condition. + Revised INSTALL information about autogen.sh; it works in tar distributions. + +Version 1.6.0beta11 [February 16, 2012] + Fix character count in pngstest command in projects/owatcom/pngstest.tgt + Revised test-pngstest.sh to report PASS/FAIL for each image. + Updated documentation about the simplified API. + Corrected estimate of error in libpng png_set_rgb_to_gray API. The API is + extremely inaccurate for sRGB conversions because it uses an 8-bit + intermediate linear value and it does not use the sRGB transform, so it + suffers from the known instability in gamma transforms for values close + to 0 (see Poynton). The net result is that the calculation has a maximum + error of 14.99/255; 0.5/255^(1/2.2). pngstest now uses 15 for the + permitted 8-bit error. This may still not be enough because of arithmetic + error. + Removed some unused arrays (with #ifdef) from png_read_push_finish_row(). + Fixed a memory overwrite bug in simplified read of RGB PNG with + non-linear gamma Also bugs in the error checking in pngread.c and changed + quite a lot of the checks in pngstest.c to be correct; either correctly + written or not over-optimistic. The pngstest changes are insufficient to + allow all possible RGB transforms to be passed; pngstest cmppixel needs + to be rewritten to make it clearer which errors it allows and then changed + to permit known inaccuracies. + Removed tests for no-longer-used *_EMPTY_PLTE_SUPPORTED from pngstruct.h + Fixed fixed/float API export conditionals. 1) If FIXED_POINT or + FLOATING_POINT options were switched off, png.h ended up with lone ';' + characters. This is not valid ANSI-C outside a function. The ';' + characters have been moved inside the definition of PNG_FP_EXPORT and + PNG_FIXED_EXPORT. 2) If either option was switched off, the declaration + of the corresponding functions were completely omitted, even though some + of them are still used internally. The result is still valid, but + produces warnings from gcc with some warning options (including -Wall). The + fix is to cause png.h to declare the functions with PNG_INTERNAL_FUNCTION + when png.h is included from pngpriv.h. + Check for invalid palette index while reading paletted PNG. When one is + found, issue a warning and increase png_ptr->num_palette accordingly. + Apps are responsible for checking to see if that happened. + +Version 1.6.0beta12 [February 18, 2012] + Do not increase num_palette on invalid_index. + Relocated check for invalid palette index to pngrtran.c, after unpacking + the sub-8-bit pixels. + Fixed CVE-2011-3026 buffer overrun bug. This bug was introduced when + iCCP chunk support was added at libpng-1.0.6. Deal more correctly with the + test on iCCP chunk length. Also removed spurious casts that may hide + problems on 16-bit systems. + +Version 1.6.0beta13 [February 24, 2012] + Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from + pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; + now that png_ptr->buffer is inaccessible to applications, the special + handling is no longer useful. + Added PNG_SAFE_LIMITS feature to pnglibconf.dfa, pngpriv.h, and new + pngusr.dfa to reset the user limits to safe ones if PNG_SAFE_LIMITS is + defined. To enable, use "CPPFLAGS=-DPNG_SAFE_LIMITS_SUPPORTED=1" on the + configure command or put #define PNG_SAFE_LIMITS_SUPPORTED in + pnglibconf.h.prebuilt and pnglibconf.h. + +Version 1.6.0beta14 [February 27, 2012] + Added information about the new limits in the manual. + Updated Makefile.in + +Version 1.6.0beta15 [March 2, 2012] + Removed unused "current_text" members of png_struct and the png_free() + of png_ptr->current_text from pngread.c + Rewrote pngstest.c for substantial speed improvement. + Fixed transparent pixel and 16-bit rgb tests in pngstest and removed a + spurious check in pngwrite.c + Added PNG_IMAGE_FLAG_FAST for the benefit of applications that store + intermediate files, or intermediate in-memory data, while processing + image data with the simplified API. The option makes the files larger + but faster to write and read. pngstest now uses this by default; this + can be disabled with the --slow option. + Improved pngstest fine tuning of error numbers, new test file generator. + The generator generates images that test the full range of sample values, + allow the error numbers in pngstest to be tuned and checked. makepng + also allows generation of images with extra chunks, although this is + still work-in-progress. + Added check for invalid palette index while reading. + Fixed some bugs in ICC profile writing. The code should now accept + all potentially valid ICC profiles and reject obviously invalid ones. + It now uses png_error() to do so rather than casually writing a PNG + without the necessary color data. + Removed whitespace from the end of lines in all source files and scripts. + +Version 1.6.0beta16 [March 6, 2012] + Relocated palette-index checking function from pngrutil.c to pngtrans.c + Added palette-index checking while writing. + Changed png_inflate() and calling routines to avoid overflow problems. + This is an intermediate check-in that solves the immediate problems and + introduces one performance improvement (avoiding a copy via png_ptr->zbuf.) + Further changes will be made to make ICC profile handling more secure. + Fixed build warnings (MSVC, GCC, GCC v3). Cygwin GCC with default options + declares 'index' as a global, causing a warning if it is used as a local + variable. GCC 64-bit warns about assigning a (size_t) (unsigned 64-bit) + to an (int) (signed 32-bit). MSVC, however, warns about using the + unary '-' operator on an unsigned value (even though it is well defined + by ANSI-C to be ~x+1). The padding calculation was changed to use a + different method. Removed the tests on png_ptr->pass. + Added contrib/libtests/tarith.c to test internal arithmetic functions from + png.c. This is a libpng maintainer program used to validate changes to the + internal arithmetic functions. + Made read 'inflate' handling like write 'deflate' handling. The read + code now claims and releases png_ptr->zstream, like the write code. + The bug whereby the progressive reader failed to release the zstream + is now fixed, all initialization is delayed, and the code checks for + changed parameters on deflate rather than always calling + deflatedEnd/deflateInit. + Validate the zTXt strings in pngvalid. + Added code to validate the windowBits value passed to deflateInit2(). + If the call to deflateInit2() is wrong a png_warning will be issued + (in fact this is harmless, but the PNG data produced may be sub-optimal). + +Version 1.6.0beta17 [March 10, 2012] + Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. + Reject all iCCP chunks after the first, even if the first one is invalid. + Deflate/inflate was reworked to move common zlib calls into single + functions [rw]util.c. A new shared keyword check routine was also added + and the 'zbuf' is no longer allocated on progressive read. It is now + possible to call png_inflate() incrementally. A warning is no longer + issued if the language tag or translated keyword in the iTXt chunk + has zero length. + If benign errors are disabled use maximum window on ancilliary inflate. + This works round a bug introduced in 1.5.4 where compressed ancillary + chunks could end up with a too-small windowBits value in the deflate + header. + +Version 1.6.0beta18 [March 16, 2012] + Issue a png_benign_error() instead of png_warning() about bad palette index. + In pngtest, treat benign errors as errors if "-strict" is present. + Fixed an off-by-one error in the palette index checking function. + Fixed a compiler warning under Cygwin (Windows-7, 32-bit system) + Revised example.c to put text strings in a temporary character array + instead of directly assigning string constants to png_textp members. + This avoids compiler warnings when -Wwrite-strings is enabled. + Added output flushing to aid debugging under Visual Studio. Unfortunately + this is necessary because the VS2010 output window otherwise simply loses + the error messages on error (they weren't flushed to the window before + the process exited, apparently!) + Added configuration support for benign errors and changed the read + default. Also changed some warnings in the iCCP and sRGB handling + from to benign errors. Configuration now makes read benign + errors warnings and write benign errors to errors by default (thus + changing the behavior on read). The simplified API always forces + read benign errors to warnings (regardless of the system default, unless + this is disabled in which case the simplified API can't be built.) + +Version 1.6.0beta19 [March 18, 2012] + Work around for duplicate row start calls; added warning messages. + This turns on PNG_FLAG_DETECT_UNINITIALIZED to detect app code that + fails to call one of the 'start' routines (not enabled in libpng-1.5 + because it is technically an API change, since it did normally work + before.) It also makes duplicate calls to png_read_start_row (an + internal function called at the start of the image read) benign, as + they were before changes to use png_inflate_claim. Somehow webkit is + causing this to happen; this is probably a mis-feature in the zlib + changes so this commit is only a work-round. + Removed erroneous setting of DETECT_UNINITIALIZED and added more + checks. The code now does a png_error if an attempt is made to do the + row initialization twice; this is an application error and it has + serious consequences because the transform data in png_struct is + changed by each call. + Added application error reporting and added chunk names to read + benign errors; also added --strict to pngstest - not enabled + yet because a warning is produced. + Avoid the double gamma correction warning in the simplified API. + This allows the --strict option to pass in the pngstest checks + +Version 1.6.0beta20 [March 29, 2012] + Changed chunk handler warnings into benign errors, incrementally load iCCP + Added checksum-icc.c to contrib/tools + Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. + Recognize known sRGB ICC profiles while reading; prefer writing the + iCCP profile over writing the sRGB chunk, controlled by the + PNG_sRGB_PROFILE_CHECKS option. + Revised png_set_text_2() to avoid potential memory corruption (fixes + CVE-2011-3048, also known as CVE-2012-3425). + +Version 1.6.0beta21 [April 27, 2012] + Revised scripts/makefile.darwin: use system zlib; remove quotes around + architecture list; add missing ppc architecture; add architecture options + to shared library link; don't try to create a shared lib based on missing + RELEASE variable. + Enable png_set_check_for_invalid_index() for both read and write. + Removed #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED in pngpriv.h around + declaration of png_handle_unknown(). + Added -lssp_nonshared in a comment in scripts/makefile.freebsd + and changed deprecated NOOBJ and NOPROFILE to NO_OBJ and NO_PROFILE. + +Version 1.6.0beta22 [May 23, 2012] + Removed need for -Wno-cast-align with clang. clang correctly warns on + alignment increasing pointer casts when -Wcast-align is passed. This + fixes the cases that clang warns about either by eliminating the + casts from png_bytep to png_uint_16p (pngread.c), or, for pngrutil.c + where the cast is previously verified or pngstest.c where it is OK, by + introducing new png_aligncast macros to do the cast in a way that clang + accepts. + +Version 1.6.0beta23 [June 6, 2012] + Revised CMakeLists.txt to not attempt to make a symlink under mingw. + Made fixes for new optimization warnings from gcc 4.7.0. The compiler + performs an optimization which is safe; however it then warns about it. + Changing the type of 'palette_number' in pngvalid.c removes the warning. + Do not depend upon a GCC feature macro being available for use in generating + the linker mapfile symbol prefix. + Improved performance of new do_check_palette_indexes() function (only + update the value when it actually increases, move test for whether + the check is wanted out of the function. + +Version 1.6.0beta24 [June 7, 2012] + Don't check palette indexes if num_palette is 0 (as it can be in MNG files). + +Version 1.6.0beta25 [June 16, 2012] + Revised png_set_keep_unknown_chunks() so num_chunks < 0 means ignore all + unknown chunks and all known chunks except for IHDR, PLTE, tRNS, IDAT, + and IEND. Previously it only meant ignore all unknown chunks, the + same as num_chunks == 0. Revised png_image_skip_unused_chunks() to + provide a list of chunks to be processed instead of a list of chunks to + ignore. Revised contrib/gregbook/readpng2.c accordingly. + +Version 1.6.0beta26 [July 10, 2012] + Removed scripts/makefile.cegcc from the *.zip and *.7z distributions; it + depends on configure, which is not included in those archives. + Moved scripts/chkfmt to contrib/tools. + Changed "a+w" to "u+w" in Makefile.in to fix CVE-2012-3386. + +Version 1.6.0beta27 [August 11, 2012] + Do not compile PNG_DEPRECATED, PNG_ALLOC and PNG_PRIVATE when __GNUC__ < 3. + Do not use __restrict when GNUC is <= 3.1 + Removed references to png_zalloc() and png_zfree() from the manual. + Fixed configurations where floating point is completely disabled. Because + of the changes to support symbol prefixing PNG_INTERNAL_FUNCTION declares + floating point APIs during libpng builds even if they are completely + disabled. This requires the png floating point types (png_double*) to be + declared even though the functions are never actually defined. This + change provides a dummy definition so that the declarations work, yet any + implementation will fail to compile because of an incomplete type. + Re-eliminated the use of strcpy() in pngtest.c. An unncessary use of + strcpy() was accidentally re-introduced in libpng16; this change replaces + it with strncpy(). + Eliminated use of png_sizeof(); use sizeof() instead. + Use a consistent style for (sizeof type) and (sizeof (array)) + Cleanup of png_set_filler(). This function does very different things on + read and write. In libpng 1.6 the two cases can be distinguished and + considerable code cleanup, and extra error checking, is possible. This + makes calls on the write side that have no effect be ignored with a + png_app_error(), which can be disabled in the app using + png_set_benign_errors(), and removes the spurious use of usr_channels + on the read side. + Insist on autotools 1.12.1 for git builds because there are security issues + with 1.12 and insisting on anything less would allow 1.12 to be used. + Removed info_ptr->signature[8] from WRITE-only builds. + Add some conditions for compiling png_fixed(). This is a small function + but it requires "-lm" on some platforms. + Cause pngtest --strict to fail on any warning from libpng (not just errors) + and cause it not to fail at the comparison step if libpng lacks support + for writing chunks that it reads from the input (currently only implemented + for compressed text chunks). + Make all three "make check" test programs work without READ or WRITE support. + Now "make check" will succeed even if libpng is compiled with -DPNG_NO_READ + or -DPNG_NO_WRITE. The tests performed are reduced, but the basic reading + and writing of a PNG file is always tested by one or more of the tests. + Consistently use strlen(), memset(), memcpy(), and memcmp() instead of the + png_strlen(), png_memset(), png_memcpy(), and png_memcmp() macros. + Removed the png_sizeof(), png_strlen(), png_memset(), png_memcpy(), and + png_memcmp() macros. + Work around gcc 3.x and Microsoft Visual Studio 2010 complaints. Both object + to the split initialization of num_chunks. + +Version 1.6.0beta28 [August 29, 2012] + Unknown handling fixes and clean up. This adds more correct option + control of the unknown handling, corrects the pre-existing bug where + the per-chunk 'keep' setting is ignored and makes it possible to skip + IDAT chunks in the sequential reader (broken in earlier 1.6 versions). + There is a new test program, test-unknown.c, which is a work in progress + (not currently part of the test suite). Comments in the header files now + explain how the unknown handling works. + Allow fine grain control of unknown chunk APIs. This change allows + png_set_keep_unknown_chunks() to be turned off if not required and causes + both read and write to behave appropriately (on read this is only possible + if the user callback is used to handle unknown chunks). The change + also removes the support for storing unknown chunks in the info_struct + if the only unknown handling enabled is via the callback, allowing libpng + to be configured with callback reading and none of the unnecessary code. + Corrected fix for unknown handling in pngtest. This reinstates the + libpng handling of unknown chunks other than vpAg and sTER (including + unsafe-to-copy chunks which were dropped before) and eliminates the + repositioning of vpAg and sTER in pngtest.png by changing pngtest.png + (so the chunks are where libpng would put them). + Added "tunknown" test and corrected a logic error in png_handle_unknown() + when SAVE support is absent. Moved the shell test scripts for + contrib/libtests from the libpng top directory to contrib/libtests. + png_handle_unknown() must always read or skip the chunk, if + SAVE_UNKNOWN_CHUNKS is turned off *and* the application does not set + a user callback an unknown chunk will not be read, leading to a read + error, which was revealed by the "tunknown" test. + Cleaned up and corrected ICC profile handling. + contrib/libtests/makepng: corrected 'rgb' and 'gray' cases. profile_error + messages could be truncated; made a correct buffer size calculation and + adjusted pngerror.c appropriately. png_icc_check_* checking improved; + changed the functions to receive the correct color type of the PNG on read + or write and check that it matches the color space of the profile (despite + what the comments said before, there is danger in assuming the app will + cope correctly with an RGB profile on a grayscale image and, since it + violates the PNG spec, allowing it is certain to produce inconsistent + app behavior and might even cause app crashes.) Check that profiles + contain the tags needed to process the PNG (tags all required by the ICC + spec). Removed unused PNG_STATIC from pngpriv.h. + +Version 1.6.0beta29 [September 4, 2012] + Fixed the simplified API example programs to add the *colormap parameter + to several of he API and improved the error message if the version field + is not set. + Added contrib/examples/* to the *.zip and *.7z distributions. + Updated simplified API synopses and description of the png_image structure + in the manual. + Made makepng and pngtest produce identical PNGs, add "--relaxed" option + to pngtest. The "--relaxed" option turns off the benign errors that are + enabled by default in pre-RC builds. makepng can now write ICC profiles + where the length has not been extended to a multiple of 4, and pngtest + now intercepts all libpng errors, allowing the previously-introduced + "--strict test" on no warnings to actually work. + Improved ICC profile handling including cHRM chunk generation and fixed + Cygwin+MSVC build errors. The ICC profile handling now includes more + checking. Several errors that caused rejection of the profile are now + handled with a warning in such a way that the invalid profiles will be + read by default in release (but not pre-RC) builds but will not be + written by default. The easy part of handling the cHRM chunk is written, + where the ICC profile contains the required data. The more difficult + part plus guessing a gAMA value requires code to pass selected RGB values + through the profile. + +Version 1.6.0beta30 [October 24, 2012] + Changed ICC profile matrix/vector types to not depend on array type rules. + By the ANSI-C standard the new types should be identical to the previous + versions, and all known versions of gcc tested with the previous versions + except for GCC-4.2.1 work with this version. The change makes the ANSI-C + rule that const applied to an array of elements applies instead to the + elements in the array moot by explicitly applying const to the base + elements of the png_icc_matrix and png_icc_vector types. The accidental + (harmless) 'const' previously applied to the parameters of two of the + functions have also been removed. + Added a work around for GCC 4.2 optimization bug. + Marked the broken (bad white point) original HP sRGB profiles correctly and + correct comments. + Added -DZ_SOLO to contrib/pngminim/*/makefile to work with zlib-1.2.7 + Use /MDd for vstudio debug builds. Also added pngunkown to the vstudio + builds, fixed build errors and corrected a minor exit code error in + pngvalid if the 'touch' file name is invalid. + Add updated WARNING file to projects/vstudio from libpng 1.5/vstudio + Fixed build when using #define PNG_NO_READ_GAMMA in png_do_compose() in + pngrtran.c (Domani Hannes). + +Version 1.6.0beta31 [November 1, 2012] + Undid the erroneous change to vstudio/pngvalid build in libpng-1.6.0beta30. + Made pngvalid so that it will build outside the libpng source tree. + Made builds -DPNG_NO_READ_GAMMA compile (the unit tests still fail). + Made PNG_NO_READ_GAMMA switch off interfaces that depend on READ_GAMMA. + Prior to 1.6.0 switching off READ_GAMMA did unpredictable things to the + interfaces that use it (specifically, png_do_background in 1.4 would + simply display composite for grayscale images but do composition + with the incorrect arithmetic for color ones). In 1.6 the semantic + of -DPNG_NO_READ_GAMMA is changed to simply disable any interface that + depends on it; this obliges people who set it to consider whether they + really want it off if they happen to use any of the interfaces in + question (typically most users who disable it won't). + Fixed GUIDs in projects/vstudio. Some were duplicated or missing, + resulting in VS2010 having to update the files. + Removed non-working ICC profile support code that was mostly added to + libpng-1.6.0beta29 and beta30. There was too much code for too little + gain; implementing full ICC color correction may be desireable but is left + up to applications. + +Version 1.6.0beta32 [November 25, 2012] + Fixed an intermittent SEGV in pngstest due to an uninitialized array element. + Added the ability for contrib/libtests/makepng.c to make a PNG with just one + color. This is useful for debugging pngstest color inaccuracy reports. + Fixed error checking in the simplified write API (Olaf van der Spek) + Made png_user_version_check() ok to use with libpng version 1.10.x and later. + +Version 1.6.0beta33 [December 15, 2012] + Fixed typo in png.c (PNG_SET_CHUNK_MALLOC_MAX should be PNG_CHUNK_MALLOC_MAX) + that causes the MALLOC_MAX limit not to work (John Bowler) + Change png_warning() to png_app_error() in pngwrite.c and comment the + fall-through condition. + Change png_warning() to png_app_warning() in png_write_tRNS(). + Rearranged the ARM-NEON optimizations: Isolated the machine specific code + to the hardware subdirectory and added comments to pngrutil.c so that + implementors of other optimizations know what to do. + Fixed cases of unquoted DESTDIR in Makefile.am + Rebuilt Makefile.in, etc., with autoconf-2.69 and automake-1.12.5. + +Version 1.6.0beta34 [December 19, 2012] + Cleaned up whitespace in the synopsis portion of the manpage "libpng.3" + Disassembled the version number in scripts/options.awk (necessary for + building on SunOs). + +Version 1.6.0beta35 [December 23, 2012] + Made default Zlib compression settings be configurable. This adds #defines to + pnglibconf.h to control the defaults. + Fixed Windows build issues, enabled ARM compilation. Various warnings issued + by earlier versions of GCC fixed for Cygwin and Min/GW (which both use old + GCCs.) ARM support is enabled by default in zlib.props (unsupported by + Microsoft) and ARM compilation is made possible by deleting the check for + x86. The test programs cannot be run because they are not signed. + +Version 1.6.0beta36 [January 2, 2013] + Discontinued distributing libpng-1.x.x.tar.bz2. + Discontinued distributing libpng-1.7.0-1.6.0-diff.txt and similar. + Rebuilt configure with autoconf-2.69 (inadvertently not done in beta33) + Fixed 'make distcheck' on SUN OS - libpng.so was not being removed + +Version 1.6.0beta37 [January 10, 2013] + Fixed conceivable but difficult to repro overflow. Also added two test + programs to generate and test a PNG which should have the problem. + +Version 1.6.0beta39 [January 19, 2013] + Again corrected attempt at overflow detection in png_set_unknown_chunks(). + Added overflow detection in png_set_sPLT() and png_set_text_2(). + +Version 1.6.0beta40 [January 20, 2013] + Use consistent handling of overflows in text, sPLT and unknown png_set_* APIs + +Version 1.6.0rc01 [January 26, 2013] + No changes. + +Version 1.6.0rc02 [February 4, 2013] + Added png_get_palette_max() function. + +Version 1.6.0rc03 [February 5, 2013] + Fixed the png_get_palette_max API. + +Version 1.6.0rc04 [February 7, 2013] + Turn serial tests back on (recently turned off by autotools upgrade). + +Version 1.6.0rc05 [February 8, 2013] + Update manual about png_get_palette_max(). + +Version 1.6.0rc06 [February 9, 2013] + Fixed missing dependency in --prefix builds The intermediate + internal 'prefix.h' file can only be generated correctly after + pnglibconf.h, however the dependency was not in Makefile.am. The + symptoms are unpredictable depending on the order make chooses to + build pngprefix.h and pnglibconf.h, often the error goes unnoticed + because there is a system pnglibconf.h to use instead. + +Version 1.6.0rc07 [February 10, 2013] + Enclosed the new png_get_palette_max in #ifdef PNG_GET_PALETTE_MAX_SUPPORTED + block, and revised pnglibconf.h and pnglibconf.h.prebuilt accordingly. + +Version 1.6.0rc08 [February 10, 2013] + Fix typo in png.h #ifdef + +Version 1.6.0 [February 14, 2013] + No changes. + +Version 1.6.1beta01 [February 16, 2013] + Made symbol prefixing work with the ARM neon optimizations. Also allow + pngpriv.h to be included for preprocessor definitions only, so it can + be used in non-C/C++ files. Back ported from libpng 1.7. + Made sRGB check numbers consistent. + Ported libpng 1.5 options.awk/dfn file handling to 1.6, fixed one bug. + Removed cc -E workround, corrected png_get_palette_max API Tested on + SUN OS cc 5.9, which demonstrates the tokenization problem previously + avoided by using /lib/cpp. Since all .dfn output is now protected in + double quotes unless it is to be macro substituted the fix should + work everywhere. + Enabled parallel tests - back ported from libpng-1.7. + scripts/pnglibconf.dfa formatting improvements back ported from libpng17. + Fixed a race condition in the creation of the build 'scripts' directory + while building with a parallel make. + Use approved/supported Android method to check for NEON, use Linux/POSIX + 1003.1 API to check /proc/self/auxv avoiding buffer allocation and other + library calls (ported from libpng15). + +Version 1.6.1beta02 [February 19, 2013] + Use parentheses more consistently in "#if defined(MACRO)" tests. + Folded long lines. + Reenabled code to allow zero length PLTE chunks for MNG. + +Version 1.6.1beta03 [February 22, 2013] + Fixed ALIGNED_MEMORY support. + Allow run-time ARM NEON checking to be disabled. A new configure option: + --enable-arm-neon=always will stop the run-time checks. New checks + within arm/arm_init.c will cause the code not to be compiled unless + __ARM_NEON__ is set. This should make it fail safe (if someone asks + for it on then the build will fail if it can't be done.) + Updated the INSTALL document. + +Version 1.6.1beta04 [February 27, 2013] + Revised INSTALL to recommend using CPPFLAGS instead of INCLUDES. + Revised scripts/makefile.freebsd to respect ZLIBLIB and ZLIBINC. + Revised scripts/dfn.awk to work with the buggy MSYS awk that has trouble + with CRLF line endings. + +Version 1.6.1beta05 [March 1, 2013] + Avoid a possible memory leak in contrib/gregbook/readpng.c + +Version 1.6.1beta06 [March 4, 2013] + Better documentation of unknown handling API interactions. + Corrected Android builds and corrected libpng.vers with symbol + prefixing This adds an API to set optimization options externally, + providing an alternative and general solution for the non-portable + run-time tests used by the ARM Neon code. It also makes those tests + compile and link on Android. + The order of settings vs options in pnglibconf.h is reversed to allow + settings to depend on options and options can now set (or override) the + defaults for settings. + +Version 1.6.1beta07 [March 7, 2013] + Corrected simplified API default gamma for color-mapped output, added + a flag to change default. In 1.6.0 when the simplified API was used + to produce color-mapped output from an input image with no gamma + information the gamma assumed for the input could be different from + that assumed for non-color-mapped output. In particular 16-bit depth + input files were assumed to be sRGB encoded, whereas in the 'direct' + case they were assumed to have linear data. This was an error. The + fix makes the simplified API treat all input files the same way and + adds a new flag to the png_image::flags member to allow the + application/user to specify that 16-bit files contain sRGB data + rather than the default linear. + Fixed bugs in the pngpixel and makepng test programs. + +Version 1.6.1beta08 [March 7, 2013] + Fixed CMakelists.txt to allow building a single variant of the library + (Claudio Bley): + Introduced a PNG_LIB_TARGETS variable that lists all activated library + targets. It is an error if this variable ends up empty, ie. you have + to build at least one library variant. + Made the *_COPY targets only depend on library targets actually being build. + Use PNG_LIB_TARGETS to unify a code path. + Changed the CREATE_SYMLINK macro to expect the full path to a file as the + first argument. When symlinking the filename component of that path is + determined and used as the link target. + Use copy_if_different in the CREATE_SYMLINK macro. + +Version 1.6.1beta09 [March 13, 2013] + Eliminated two warnings from the Intel C compiler. The warnings are + technically valid, although a reasonable treatment of division would + show it to be incorrect. + +Version 1.6.1rc01 [March 21, 2013] + No changes. + +Version 1.6.1 [March 28, 2013] + No changes. + +Version 1.6.2beta01 [April 14, 2013] + Updated documentation of 1.5.x to 1.6.x changes in iCCP chunk handling. + Fixed incorrect warning of excess deflate data. End condition - the + warning would be produced if the end of the deflate stream wasn't read + in the last row. The warning is harmless. + Corrected the test on user transform changes on read. It was in the + png_set of the transform function, but that doesn't matter unless the + transform function changes the rowbuf size, and that is only valid if + transform_info is called. + Corrected a misplaced closing bracket in contrib/libtests/pngvalid.c + (Flavio Medeiros). + Corrected length written to uncompressed iTXt chunks (Samuli Suominen). + Bug was introduced in libpng-1.6.0. + +Version 1.6.2rc01 [April 18, 2013] + Added contrib/tools/fixitxt.c, to repair the erroneous iTXt chunk length + written by libpng-1.6.0 and 1.6.1. + Disallow storing sRGB information when the sRGB is not supported. + +Version 1.6.2rc02 [April 18, 2013] + Merge pngtest.c with libpng-1.7.0 + +Version 1.6.2rc03 [April 22, 2013] + Trivial spelling cleanup. + +Version 1.6.2rc04 and 1.6.2rc05 [omitted] + +Version 1.6.2rc06 [April 24, 2013] + Reverted to version 1.6.2rc03. Recent changes to arm/neon support + have been ported to libpng-1.7.0beta09 and will reappear in version + 1.6.3beta01. + +Version 1.6.2 [April 25, 2013] + No changes. + +Version 1.6.3beta01 [April 25, 2013] + Revised stack marking in arm/filter_neon.S and configure.ac. + Ensure that NEON filter stuff is completely disabled when switched 'off'. + Previously the ARM NEON specific files were still built if the option + was switched 'off' as opposed to being explicitly disabled. + +Version 1.6.3beta02 [April 26, 2013] + Test for 'arm*' not just 'arm' in the host_cpu configure variable. + Rebuilt the configure scripts. + +Version 1.6.3beta03 [April 30, 2013] + Expanded manual paragraph about writing private chunks, particularly + the need to call png_set_keep_unknown_chunks() when writing them. + Avoid dereferencing NULL pointer possibly returned from + png_create_write_struct() (Andrew Church). + +Version 1.6.3beta05 [May 9, 2013] + Calculate our own zlib windowBits when decoding rather than trusting the + CMF bytes in the PNG datastream. + Added an option to force maximum window size for inflating, which was + the behavior of libpng15 and earlier. + Added png-fix-itxt and png-fix-too-far-back to the built programs and + removed warnings from the source code and timepng that are revealed as + a result. + Detect wrong libpng versions linked to png-fix-too-far-back, which currently + only works with libpng versions that can be made to reliably fail when + the deflate data contains an out-of-window reference. This means only + 1.6 and later. + Fixed gnu issues: g++ needs a static_cast, gcc 4.4.7 has a broken warning + message which it is easier to work round than ignore. + Updated contrib/pngminus/pnm2png.c (Paul Stewart): + Check for EOF + Ignore "#" delimited comments in input file to pnm2png.c. + Fixed whitespace handling + Added a call to png_set_packing() + Initialize dimension values so if sscanf fails at least we have known + invalid values. + Attempt to detect configuration issues with png-fix-too-far-back, which + requires both the correct libpng and the correct zlib to function + correctly. + Check ZLIB_VERNUM for mismatches, enclose #error in quotes + Added information in the documentation about problems with and fixes for + the bad CRC and bad iTXt chunk situations. + +Version 1.6.3beta06 [May 12, 2013] + Allow contrib/pngminus/pnm2png.c to compile without WRITE_INVERT and + WRITE_PACK supported (writes error message that it can't read P1 or + P4 PBM files). + Improved png-fix-too-far-back usage message, added --suffix option. + Revised contrib/pngminim/*/makefile to generate pnglibconf.h with the + right zlib header files. + Separated CPPFLAGS and CFLAGS in contrib/pngminim/*/makefile + +Version 1.6.3beta07 [June 8, 2013] + Removed a redundant test in png_set_IHDR(). + Added set(CMAKE_CONFIGURATION_TYPES ...) to CMakeLists.txt (Andrew Hundt) + Deleted set(CMAKE_BUILD_TYPE) block from CMakeLists.txt + Enclose the prototypes for the simplified write API in + #ifdef PNG_STDIO_SUPPORTED/#endif + Make ARM NEON support work at compile time (not just configure time). + This moves the test on __ARM_NEON__ into pngconf.h to avoid issues when + using a compiler that compiles for multiple architectures at one time. + Removed PNG_FILTER_OPTIMIZATIONS and PNG_ARM_NEON_SUPPORTED from + pnglibconf.h, allowing more of the decisions to be made internally + (pngpriv.h) during the compile. Without this, symbol prefixing is broken + under certain circumstances on ARM platforms. Now only the API parts of + the optimizations ('check' vs 'api') are exposed in the public header files + except that the new setting PNG_ARM_NEON_OPT documents how libpng makes the + decision about whether or not to use the optimizations. + Protect symbol prefixing against CC/CPPFLAGS/CFLAGS useage. + Previous iOS/Xcode fixes for the ARM NEON optimizations moved the test + on __ARM_NEON__ from configure time to compile time. This breaks symbol + prefixing because the definition of the special png_init_filter_functions + call was hidden at configure time if the relevant compiler arguments are + passed in CFLAGS as opposed to CC. This change attempts to avoid all + the confusion that would result by declaring the init function even when + it is not used, so that it will always get prefixed. + +Version 1.6.3beta08 [June 18, 2013] + Revised libpng.3 so that "doclifter" can process it. + +Version 1.6.3beta09 [June 27, 2013] + Revised example.c to illustrate use of PNG_DEFAULT_sRGB and PNG_GAMMA_MAC_18 + as parameters for png_set_gamma(). These have been available since + libpng-1.5.4. + Renamed contrib/tools/png-fix-too-far-back.c to pngfix.c and revised it + to check all compressed chunks known to libpng. + +Version 1.6.3beta10 [July 5, 2013] + Updated documentation to show default behavior of benign errors correctly. + Only compile ARM code when PNG_READ_SUPPORTED is defined. + Fixed undefined behavior in contrib/tools/pngfix.c and added new strip + option. pngfix relied on undefined behavior and even a simple change from + gcc to g++ caused it to fail. The new strip option 'unsafe' has been + implemented and is the default if --max is given. Option names have + been clarified, with --strip=transform now stripping the bKGD chunk, + which was stripped previously with --strip=unused. + Added all documented chunk types to pngpriv.h + Unified pngfix.c source with libpng17. + +Version 1.6.3rc01 [July 11, 2013] + No changes. + +Version 1.6.3 [July 18, 2013] + Revised manual about changes in iTXt chunk handling made in libpng-1.6.0. + Added "/* SAFE */" comments in pngrutil.c and pngrtran.c where warnings + may be erroneously issued by code-checking applications. + +Version 1.6.4beta01 [August 21, 2013] + Added information about png_set_options() to the manual. + Delay calling png_init_filter_functions() until a row with nonzero filter + is found. + +Version 1.6.4beta02 [August 30, 2013] + Fixed inconsistent conditional compilation of png_chunk_unknown_handling() + prototype, definition, and usage. Made it depend on + PNG_HANDLE_AS_UNKNOWN_SUPPORTED everywhere. + +Version 1.6.4rc01 [September 5, 2013] + No changes. + +Version 1.6.4 [September 12, 2013] + No changes. + +Version 1.6.5 [September 14, 2013] + Removed two stray lines of code from arm/arm_init.c. + +Version 1.6.6 [September 16, 2013] + Removed two stray lines of code from arm/arm_init.c, again. + +Version 1.6.7beta01 [September 30, 2013] + Revised unknown chunk code to correct several bugs in the NO_SAVE_/NO_WRITE + combination + Allow HANDLE_AS_UNKNOWN to work when other options are configured off. Also + fixed the pngminim makefiles to work when $(MAKEFLAGS) contains stuff + which terminates the make options (as by default in recent versions of + Gentoo). + Avoid up-cast warnings in pngvalid.c. On ARM the alignment requirements of + png_modifier are greater than that of png_store and as a consequence + compilation of pngvalid.c results in a warning about increased alignment + requirements because of the bare cast to (png_modifier*). The code is safe, + because the pointer is known to point to a stack allocated png_modifier, + but this change avoids the warning. + Fixed default behavior of ARM_NEON_API. If the ARM NEON API option was + compiled without the CHECK option it defaulted to on, not off. + Check user callback behavior in pngunknown.c. Previous versions compiled + if SAVE_UNKNOWN was not available but did nothing since the callback + was never implemented. + Merged pngunknown.c with 1.7 version and back ported 1.7 improvements/fixes + +Version 1.6.7beta02 [October 12, 2013] + Made changes for compatibility with automake 1.14: + 1) Added the 'compile' program to the list of programs that must be cleaned + in autogen.sh + 2) Added 'subdir-objects' which causes .c files in sub-directories to be + compiled such that the corresponding .o files are also in the + sub-directory. This is because automake 1.14 warns that the + current behavior of compiling to the top level directory may be removed + in the future. + 3) Updated dependencies on pnglibconf.h to match the new .o locations and + added all the files in contrib/libtests and contrib/tools that depend + on pnglibconf.h + 4) Added 'BUILD_SOURCES = pnglibconf.h'; this is the automake recommended + way of handling the dependencies of sources that are machine generated; + unfortunately it only works if the user does 'make all' or 'make check', + so the dependencies (3) are still required. + Cleaned up (char*) casts of zlib messages. The latest version of the Intel C + compiler complains about casting a string literal as (char*), so copied the + treatment of z_const from the library code into pngfix.c + Simplified error message code in pngunknown. The simplification has the + useful side effect of avoiding a bogus warning generated by the latest + version of the Intel C compiler (it objects to + condition ? string-literal : string-literal). + Make autogen.sh work with automake 1.13 as well as 1.14. Do this by always + removing the 1.14 'compile' script but never checking for it. + +Version 1.6.7beta03 [October 19, 2013] + Added ARMv8 support (James Yu ). Added file + arm/filter_neon_intrinsics.c; enable with -mfpu=neon. + Revised pngvalid to generate size images with as many filters as it can + manage, limited by the number of rows. + Cleaned up ARM NEON compilation handling. The tests are now in pngpriv.h + and detect the broken GCC compilers. + +Version 1.6.7beta04 [October 26, 2013] + Allow clang derived from older GCC versions to use ARM intrinsics. This + causes all clang builds that use -mfpu=neon to use the intrinsics code, + not the assembler code. This has only been tested on iOS 7. It may be + necessary to exclude some earlier clang versions but this seems unlikely. + Changed NEON implementation selection mechanism. This allows assembler + or intrinsics to be turned on at compile time during the build by defining + PNG_ARM_NEON_IMPLEMENTATION to the correct value (2 or 1). This macro + is undefined by default and the build type is selected in pngpriv.h. + +Version 1.6.7rc01 [November 2, 2013] + No changes. + +Version 1.6.7rc02 [November 7, 2013] + Fixed #include in filter_neon_intrinsics.c and ctype macros. The ctype char + checking macros take an unsigned char argument, not a signed char. + +Version 1.6.7 [November 14, 2013] + No changes. + +Version 1.6.8beta01 [November 24, 2013] + Moved prototype for png_handle_unknown() in pngpriv.h outside of + the #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED/#endif block. + Added "-Wall" to CFLAGS in contrib/pngminim/*/makefile + Conditionally compile some unused functions reported by -Wall in + pngminim. + Fixed 'minimal' builds. Various obviously useful minimal configurations + don't build because of missing contrib/libtests test programs and + overly complex dependencies in scripts/pnglibconf.dfa. This change + adds contrib/conftest/*.dfa files that can be used in automatic build + scripts to ensure that these configurations continue to build. + Enabled WRITE_INVERT and WRITE_PACK in contrib/pngminim/encoder. + Fixed pngvalid 'fail' function declaration on the Intel C Compiler. + This reverts to the previous 'static' implementation and works round + the 'unused static function' warning by using PNG_UNUSED(). + +Version 1.6.8beta02 [November 30, 2013] + Removed or marked PNG_UNUSED some harmless "dead assignments" reported + by clang scan-build. + Changed tabs to 3 spaces in png_debug macros and changed '"%s"m' + to '"%s" m' to improve portability among compilers. + Changed png_free_default() to free() in pngtest.c + +Version 1.6.8rc01 [December 12, 2013] + Tidied up pngfix inits and fixed pngtest no-write builds. + +Version 1.6.8rc02 [December 14, 2013] + Handle zero-length PLTE chunk or NULL palette with png_error() + instead of png_chunk_report(), which by default issues a warning + rather than an error, leading to later reading from a NULL pointer + (png_ptr->palette) in png_do_expand_palette(). This is CVE-2013-6954 + and VU#650142. Libpng-1.6.1 through 1.6.7 are vulnerable. + Libpng-1.6.0 and earlier do not have this bug. + +Version 1.6.8 [December 19, 2013] + No changes. + +Version 1.6.9beta01 [December 26, 2013] + Bookkeeping: Moved functions around (no changes). Moved transform + function definitions before the place where they are called so that + they can be made static. Move the intrapixel functions and the + grayscale palette builder out of the png?tran.c files. The latter + isn't a transform function and is no longer used internally, and the + former MNG specific functions are better placed in pngread/pngwrite.c + Made transform implementation functions static. This makes the internal + functions called by png_do_{read|write}_transformations static. On an + x86-64 DLL build (Gentoo Linux) this reduces the size of the text + segment of the DLL by 1208 bytes, about 0.6%. It also simplifies + maintenance by removing the declarations from pngpriv.h and allowing + easier changes to the internal interfaces. + Rebuilt configure scripts with automake-1.14.1 and autoconf-2.69 + in the tar distributions. + +Version 1.6.9beta02 [January 1, 2014] + Added checks for libpng 1.5 to pngvalid.c. This supports the use of + this version of pngvalid in libpng 1.5 + Merged with pngvalid.c from libpng-1.7 changes to create a single + pngvalid.c + Removed #error macro from contrib/tools/pngfix.c (Thomas Klausner). + Merged pngrio.c, pngtrans.c, pngwio.c, and pngerror.c with libpng-1.7.0 + Merged libpng-1.7.0 changes to make no-interlace configurations work + with test programs. + Revised pngvalid.c to support libpng 1.5, which does not support the + PNG_MAXIMUM_INFLATE_WINDOW option, so #define it out when appropriate in + pngvalid.c + Allow unversioned links created on install to be disabled in configure. + In configure builds 'make install' changes/adds links like png.h + and libpng.a to point to the newly installed, versioned, files (e.g. + libpng17/png.h and libpng17.a). Three new configure options and some + rearrangement of Makefile.am allow creation of these links to be disabled. + +Version 1.6.9beta03 [January 10, 2014] + Removed potentially misleading warning from png_check_IHDR(). + +Version 1.6.9beta04 [January 20, 2014] + Updated scripts/makefile.* to use CPPFLAGS (Cosmin). + Added clang attribute support (Cosmin). + +Version 1.6.9rc01 [January 28, 2014] + No changes. + +Version 1.6.9rc02 [January 30, 2014] + Quiet an uninitialized memory warning from VC2013 in png_get_png(). + +Version 1.6.9 [February 6, 2014] + +Version 1.6.10beta01 [February 9, 2014] + Backported changes from libpng-1.7.0beta30 and beta31: + Fixed a large number of instances where PNGCBAPI was omitted from + function definitions. + Added pngimage test program for png_read_png() and png_write_png() + with two new test scripts. + Removed dependence on !PNG_READ_EXPAND_SUPPORTED for calling + png_set_packing() in png_read_png(). + Fixed combination of ~alpha with shift. On read invert alpha, processing + occurred after shift processing, which causes the final values to be + outside the range that should be produced by the shift. Reversing the + order on read makes the two transforms work together correctly and mirrors + the order used on write. + Do not read invalid sBIT chunks. Previously libpng only checked sBIT + values on write, so a malicious PNG writer could therefore cause + the read code to return an invalid sBIT chunk, which might lead to + application errors or crashes. Such chunks are now skipped (with + chunk_benign_error). + Make png_read_png() and png_write_png() prototypes in png.h depend + upon PNG_READ_SUPPORTED and PNG_WRITE_SUPPORTED. + Support builds with unsupported PNG_TRANSFORM_* values. All of the + PNG_TRANSFORM_* values are always defined in png.h and, because they + are used for both read and write in some cases, it is not reliable + to #if out ones that are totally unsupported. This change adds error + detection in png_read_image() and png_write_image() to do a + png_app_error() if the app requests something that cannot be done + and it adds corresponding code to pngimage.c to handle such options + by not attempting to test them. + +Version 1.6.10beta02 [February 23, 2014] + Moved redefines of png_error(), png_warning(), png_chunk_error(), + and png_chunk_warning() from pngpriv.h to png.h to make them visible + to libpng-calling applications. + Moved OS dependent code from arm/arm_init.c, to allow the included + implementation of the ARM NEON discovery function to be set at + build-time and provide sample implementations from the current code in the + contrib/arm-neon subdirectory. The __linux__ code has also been changed to + compile and link on Android by using /proc/cpuinfo, and the old linux code + is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux + dependencies apart from opening /proc/cpuinfo and is C90 compliant. + Check for info_ptr == NULL early in png_read_end() so we don't need to + run all the png_handle_*() and depend on them to return if info_ptr == NULL. + This improves the performance of png_read_end(png_ptr, NULL) and makes + it more robust against future programming errors. + Check for __has_extension before using it in pngconf.h, to + support older Clang versions (Jeremy Sequoia). + Treat CRC error handling with png_set_crc_action(), instead of with + png_set_benign_errors(), which has been the case since libpng-1.6.0beta18. + Use a user warning handler in contrib/gregbook/readpng2.c instead of default, + so warnings will be put on stderr even if libpng has CONSOLE_IO disabled. + Added png_ptr->process_mode = PNG_READ_IDAT_MODE in png_push_read_chunk + after recognizing the IDAT chunk, which avoids an infinite loop while + reading a datastream whose first IDAT chunk is of zero-length. + This fixes CERT VU#684412 and CVE-2014-0333. + Don't recognize known sRGB profiles as sRGB if they have been hacked, + but don't reject them and don't issue a copyright violation warning. + +Version 1.6.10beta03 [February 25, 2014] + Moved some documentation from png.h to libpng.3 and libpng-manual.txt + Minor editing of contrib/arm-neon/README and contrib/examples/*.c + +Version 1.6.10rc01 [February 27, 2014] + Fixed typos in the manual and in scripts/pnglibconf.dfa (CFLAGS -> CPPFLAGS + and PNG_USR_CONFIG -> PNG_USER_CONFIG). + +Version 1.6.10rc02 [February 28, 2014] + Removed unreachable return statement after png_chunk_error() + in pngrutil.c + +Version 1.6.10rc03 [March 4, 2014] + Un-deprecated png_data_freer(). + +Version 1.6.10 [March 6, 2014] + +Send comments/corrections/commendations to png-mng-implement at lists.sf.net +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) +or to glennrp at users.sourceforge.net + +Glenn R-P +#endif diff --git a/main/source/includes/lpng1610/CMakeLists.txt b/main/source/includes/lpng1610/CMakeLists.txt index b67b5640..34d62b5d 100644 --- a/main/source/includes/lpng1610/CMakeLists.txt +++ b/main/source/includes/lpng1610/CMakeLists.txt @@ -1,364 +1,364 @@ -# CMakeLists.txt - -# Copyright (C) 2007-2013 Glenn Randers-Pehrson - -# This code is released under the libpng license. -# For conditions of distribution and use, see the disclaimer -# and license in png.h - -cmake_minimum_required(VERSION 2.4.4) -set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) - -set(CMAKE_CONFIGURATION_TYPES "Release;Debug;MinSizeRel;RelWithDebInfo") - -project(libpng C) -enable_testing() - -set(PNGLIB_MAJOR 1) -set(PNGLIB_MINOR 6) -set(PNGLIB_RELEASE 10) -set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) -set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) - -# needed packages -find_package(ZLIB REQUIRED) -include_directories(${ZLIB_INCLUDE_DIR}) - -if(NOT WIN32) - find_library(M_LIBRARY - NAMES m - PATHS /usr/lib /usr/local/lib - ) - if(NOT M_LIBRARY) - message(STATUS - "math library 'libm' not found - floating point support disabled") - endif() -else() - # not needed on windows - set(M_LIBRARY "") -endif() - -# COMMAND LINE OPTIONS -if(DEFINED PNG_SHARED) - option(PNG_SHARED "Build shared lib" ${PNG_SHARED}) -else() - option(PNG_SHARED "Build shared lib" ON) -endif() -if(DEFINED PNG_STATIC) - option(PNG_STATIC "Build static lib" ${PNG_STATIC}) -else() - option(PNG_STATIC "Build static lib" ON) -endif() - -option(PNG_TESTS "Build libpng tests" YES) - -# Many more configuration options could be added here -option(PNG_DEBUG "Build with debug output" NO) -option(PNGARG "Disable ANSI-C prototypes" NO) - -# SET LIBNAME -set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR}) - -# to distinguish between debug and release lib -set(CMAKE_DEBUG_POSTFIX "d") - -# Use the prebuilt pnglibconf.h file from the scripts folder -# TODO: fix this by building with awk; without this no cmake build can be -# configured directly (to do so indirectly use your local awk to build a -# pnglibconf.h in the build directory.) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt - ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -# OUR SOURCES -set(libpng_public_hdrs - png.h - pngconf.h - ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h -) -set(libpng_sources - ${libpng_public_hdrs} - pngdebug.h - pnginfo.h - pngpriv.h - pngstruct.h - png.c - pngerror.c - pngget.c - pngmem.c - pngpread.c - pngread.c - pngrio.c - pngrtran.c - pngrutil.c - pngset.c - pngtrans.c - pngwio.c - pngwrite.c - pngwtran.c - pngwutil.c -) -set(pngtest_sources - pngtest.c -) -set(pngvalid_sources - contrib/libtests/pngvalid.c -) -set(pngstest_sources - contrib/libtests/pngstest.c -) -# SOME NEEDED DEFINITIONS - -if(MSVC) - add_definitions(-D_CRT_SECURE_NO_DEPRECATE) -endif(MSVC) - -if(PNG_DEBUG) - add_definitions(-DPNG_DEBUG) -endif() - -# NOW BUILD OUR TARGET -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIR}) - -unset(PNG_LIB_TARGETS) - -if(PNG_SHARED) - add_library(${PNG_LIB_NAME} SHARED ${libpng_sources}) - set(PNG_LIB_TARGETS ${PNG_LIB_NAME}) - if(MSVC) - # msvc does not append 'lib' - do it here to have consistent name - set_target_properties(${PNG_LIB_NAME} PROPERTIES PREFIX "lib") - set_target_properties(${PNG_LIB_NAME} PROPERTIES IMPORT_PREFIX "lib") - endif() - target_link_libraries(${PNG_LIB_NAME} ${ZLIB_LIBRARY} ${M_LIBRARY}) -endif() - -if(PNG_STATIC) -# does not work without changing name - set(PNG_LIB_NAME_STATIC ${PNG_LIB_NAME}_static) - add_library(${PNG_LIB_NAME_STATIC} STATIC ${libpng_sources}) - list(APPEND PNG_LIB_TARGETS ${PNG_LIB_NAME_STATIC}) - if(MSVC) - # msvc does not append 'lib' - do it here to have consistent name - set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES PREFIX "lib") - endif() - target_link_libraries(${PNG_LIB_NAME_STATIC} ${ZLIB_LIBRARY} ${M_LIBRARY}) -endif() - -if(NOT PNG_LIB_TARGETS) - message(SEND_ERROR - "No library variant selected to build. " - "Please enable at least one of the following options: PNG_STATIC, PNG_SHARED") -endif() - -if(PNG_SHARED AND WIN32) - set_target_properties(${PNG_LIB_NAME} PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL) -endif() - -if(PNG_TESTS AND PNG_SHARED) - # does not work with msvc due to png_lib_ver issue - add_executable(pngtest ${pngtest_sources}) - target_link_libraries(pngtest ${PNG_LIB_NAME}) - add_test(pngtest ./pngtest ${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png) - # - add_executable(pngvalid ${pngvalid_sources}) - target_link_libraries(pngvalid ${PNG_LIB_NAME}) - add_test(pngvalid ./pngvalid) - add_executable(pngstest ${pngstest_sources}) - target_link_libraries(pngstest ${PNG_LIB_NAME}) - add_test(pngstest ./pngstest - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g01.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g02.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g04.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn2c08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn2c16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p01.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p02.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p04.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn4a08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn4a16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn6a08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn6a16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn0g01.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn0g02.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn0g04.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn2c16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn3p08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbgn2c16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbgn3p08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbrn2c08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbwn0g16.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbwn3p08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbyn3p08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp0n0g08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp0n2c08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp0n3p08.png - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp1n3p08.png - ) -endif() - -# Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set -IF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) - SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "lib") -ENDIF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) - -# Set a variable with CMake code which: -# Creates a symlink from src to dest (if possible) or alternatively -# copies if different. -macro(CREATE_SYMLINK SRC_FILE DEST_FILE) - FILE(REMOVE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE}) - if(WIN32 AND NOT CYGWIN AND NOT MSYS) - ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${DEST_FILE} - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" ${CMAKE_CURRENT_BINARY_DIR}/${DEST_FILE} - DEPENDS ${PNG_LIB_TARGETS} - ) - ADD_CUSTOM_TARGET(${DEST_FILE}_COPY ALL DEPENDS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE}) - else(WIN32 AND NOT CYGWIN AND NOT MSYS) - get_filename_component(LINK_TARGET "${SRC_FILE}" NAME) - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${LINK_TARGET}" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${LINK_TARGET}" ${DEST_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif(WIN32 AND NOT CYGWIN AND NOT MSYS) -endmacro() - -# libpng is a library so default to 'lib' -if(NOT DEFINED CMAKE_INSTALL_LIBDIR) - set(CMAKE_INSTALL_LIBDIR lib) -endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) - -# CREATE PKGCONFIG FILES -# we use the same files like ./configure, so we have to set its vars -# Only do this on Windows for Cygwin - the files don't make much sense outside -# a UNIX look alike -if(NOT WIN32 OR CYGWIN OR MINGW) - set(prefix ${CMAKE_INSTALL_PREFIX}) - set(exec_prefix ${CMAKE_INSTALL_PREFIX}) - set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) - set(includedir ${CMAKE_INSTALL_PREFIX}/include) - set(LIBS "-lz -lm") - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc @ONLY) - CREATE_SYMLINK(${PNGLIB_NAME}.pc libpng.pc) - - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng-config.in - ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config @ONLY) - CREATE_SYMLINK(${PNGLIB_NAME}-config libpng-config) -endif(NOT WIN32 OR CYGWIN OR MINGW) - -# SET UP LINKS -if(PNG_SHARED) - set_target_properties(${PNG_LIB_NAME} PROPERTIES -# VERSION 16.${PNGLIB_RELEASE}.1.6.10 - VERSION 16.${PNGLIB_RELEASE}.0 - SOVERSION 16 - CLEAN_DIRECT_OUTPUT 1) -endif() -if(PNG_STATIC) - # MSVC doesn't use a different file extension for shared vs. static - # libs. We are able to change OUTPUT_NAME to remove the _static - # for all other platforms. - if(NOT MSVC) - set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES - OUTPUT_NAME ${PNG_LIB_NAME} - CLEAN_DIRECT_OUTPUT 1) - endif() -endif() - -# If CMake > 2.4.x, we set a variable used below to export -# targets to an export file. -# TODO: Use VERSION_GREATER after our cmake_minimum_required >= 2.6.2 -if(CMAKE_MAJOR_VERSION GREATER 1 AND CMAKE_MINOR_VERSION GREATER 4) - set(PNG_EXPORT_RULE EXPORT libpng) -elseif(CMAKE_MAJOR_VERSION GREATER 2) # future proof - set(PNG_EXPORT_RULE EXPORT libpng) -endif() - -# INSTALL -if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) - install(TARGETS ${PNG_LIB_TARGETS} - ${PNG_EXPORT_RULE} - RUNTIME DESTINATION bin - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - if(PNG_SHARED) - # Create a symlink for libpng.dll.a => libpng16.dll.a on Cygwin - if(CYGWIN OR MINGW) - get_target_property(BUILD_TARGET_LOCATION ${PNG_LIB_NAME} LOCATION_${CMAKE_BUILD_TYPE}) - CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_IMPORT_LIBRARY_SUFFIX}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} - DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif(CYGWIN OR MINGW) - - if(NOT WIN32) - get_target_property(BUILD_TARGET_LOCATION ${PNG_LIB_NAME} LOCATION_${CMAKE_BUILD_TYPE}) - CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_SHARED_LIBRARY_SUFFIX}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_SHARED_LIBRARY_SUFFIX} - DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif(NOT WIN32) - endif(PNG_SHARED) - - if(PNG_STATIC) - if(NOT WIN32 OR CYGWIN OR MINGW) - get_target_property(BUILD_TARGET_LOCATION ${PNG_LIB_NAME_STATIC} LOCATION_${CMAKE_BUILD_TYPE}) - CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_STATIC_LIBRARY_SUFFIX}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_STATIC_LIBRARY_SUFFIX} - DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif(NOT WIN32 OR CYGWIN OR MINGW) - endif() -endif() - -if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) - install(FILES ${libpng_public_hdrs} DESTINATION include) - install(FILES ${libpng_public_hdrs} DESTINATION include/${PNGLIB_NAME}) -endif() -if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL ) - if(NOT WIN32 OR CYGWIN OR MINGW) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config DESTINATION bin) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config - DESTINATION bin) - endif(NOT WIN32 OR CYGWIN OR MINGW) -endif() - -if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) - # Install man pages - if(NOT PNG_MAN_DIR) - set(PNG_MAN_DIR "share/man") - endif() - install(FILES libpng.3 libpngpf.3 DESTINATION ${PNG_MAN_DIR}/man3) - install(FILES png.5 DESTINATION ${PNG_MAN_DIR}/man5) - # Install pkg-config files - if(NOT WIN32 OR CYGWIN OR MINGW) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config - DESTINATION bin) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config - DESTINATION bin) - endif(NOT WIN32 OR CYGWIN OR MINGW) -endif() - -# On versions of CMake that support it, create an export file CMake -# users can include() to import our targets -if(PNG_EXPORT_RULE AND NOT SKIP_INSTALL_EXPORT AND NOT SKIP_INSTALL_ALL ) - install(EXPORT libpng DESTINATION lib/libpng FILE lib${PNG_LIB_NAME}.cmake) -endif() - -# what's with libpng-$VER%.txt and all the extra files? - -# UNINSTALL -# do we need this? - -# DIST -# do we need this? - -# to create msvc import lib for mingw compiled shared lib -# pexports libpng.dll > libpng.def -# lib /def:libpng.def /machine:x86 - +# CMakeLists.txt + +# Copyright (C) 2007-2013 Glenn Randers-Pehrson + +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +set(CMAKE_CONFIGURATION_TYPES "Release;Debug;MinSizeRel;RelWithDebInfo") + +project(libpng C) +enable_testing() + +set(PNGLIB_MAJOR 1) +set(PNGLIB_MINOR 6) +set(PNGLIB_RELEASE 10) +set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) +set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) + +# needed packages +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIR}) + +if(NOT WIN32) + find_library(M_LIBRARY + NAMES m + PATHS /usr/lib /usr/local/lib + ) + if(NOT M_LIBRARY) + message(STATUS + "math library 'libm' not found - floating point support disabled") + endif() +else() + # not needed on windows + set(M_LIBRARY "") +endif() + +# COMMAND LINE OPTIONS +if(DEFINED PNG_SHARED) + option(PNG_SHARED "Build shared lib" ${PNG_SHARED}) +else() + option(PNG_SHARED "Build shared lib" ON) +endif() +if(DEFINED PNG_STATIC) + option(PNG_STATIC "Build static lib" ${PNG_STATIC}) +else() + option(PNG_STATIC "Build static lib" ON) +endif() + +option(PNG_TESTS "Build libpng tests" YES) + +# Many more configuration options could be added here +option(PNG_DEBUG "Build with debug output" NO) +option(PNGARG "Disable ANSI-C prototypes" NO) + +# SET LIBNAME +set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR}) + +# to distinguish between debug and release lib +set(CMAKE_DEBUG_POSTFIX "d") + +# Use the prebuilt pnglibconf.h file from the scripts folder +# TODO: fix this by building with awk; without this no cmake build can be +# configured directly (to do so indirectly use your local awk to build a +# pnglibconf.h in the build directory.) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt + ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# OUR SOURCES +set(libpng_public_hdrs + png.h + pngconf.h + ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h +) +set(libpng_sources + ${libpng_public_hdrs} + pngdebug.h + pnginfo.h + pngpriv.h + pngstruct.h + png.c + pngerror.c + pngget.c + pngmem.c + pngpread.c + pngread.c + pngrio.c + pngrtran.c + pngrutil.c + pngset.c + pngtrans.c + pngwio.c + pngwrite.c + pngwtran.c + pngwutil.c +) +set(pngtest_sources + pngtest.c +) +set(pngvalid_sources + contrib/libtests/pngvalid.c +) +set(pngstest_sources + contrib/libtests/pngstest.c +) +# SOME NEEDED DEFINITIONS + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) +endif(MSVC) + +if(PNG_DEBUG) + add_definitions(-DPNG_DEBUG) +endif() + +# NOW BUILD OUR TARGET +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIR}) + +unset(PNG_LIB_TARGETS) + +if(PNG_SHARED) + add_library(${PNG_LIB_NAME} SHARED ${libpng_sources}) + set(PNG_LIB_TARGETS ${PNG_LIB_NAME}) + if(MSVC) + # msvc does not append 'lib' - do it here to have consistent name + set_target_properties(${PNG_LIB_NAME} PROPERTIES PREFIX "lib") + set_target_properties(${PNG_LIB_NAME} PROPERTIES IMPORT_PREFIX "lib") + endif() + target_link_libraries(${PNG_LIB_NAME} ${ZLIB_LIBRARY} ${M_LIBRARY}) +endif() + +if(PNG_STATIC) +# does not work without changing name + set(PNG_LIB_NAME_STATIC ${PNG_LIB_NAME}_static) + add_library(${PNG_LIB_NAME_STATIC} STATIC ${libpng_sources}) + list(APPEND PNG_LIB_TARGETS ${PNG_LIB_NAME_STATIC}) + if(MSVC) + # msvc does not append 'lib' - do it here to have consistent name + set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES PREFIX "lib") + endif() + target_link_libraries(${PNG_LIB_NAME_STATIC} ${ZLIB_LIBRARY} ${M_LIBRARY}) +endif() + +if(NOT PNG_LIB_TARGETS) + message(SEND_ERROR + "No library variant selected to build. " + "Please enable at least one of the following options: PNG_STATIC, PNG_SHARED") +endif() + +if(PNG_SHARED AND WIN32) + set_target_properties(${PNG_LIB_NAME} PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL) +endif() + +if(PNG_TESTS AND PNG_SHARED) + # does not work with msvc due to png_lib_ver issue + add_executable(pngtest ${pngtest_sources}) + target_link_libraries(pngtest ${PNG_LIB_NAME}) + add_test(pngtest ./pngtest ${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png) + # + add_executable(pngvalid ${pngvalid_sources}) + target_link_libraries(pngvalid ${PNG_LIB_NAME}) + add_test(pngvalid ./pngvalid) + add_executable(pngstest ${pngstest_sources}) + target_link_libraries(pngstest ${PNG_LIB_NAME}) + add_test(pngstest ./pngstest + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g01.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g02.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g04.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn0g16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn2c08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn2c16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p01.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p02.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p04.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn3p08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn4a08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn4a16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn6a08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/basn6a16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn0g01.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn0g02.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn0g04.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn2c16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbbn3p08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbgn2c16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbgn3p08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbrn2c08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbwn0g16.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbwn3p08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftbyn3p08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp0n0g08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp0n2c08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp0n3p08.png + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/ftp1n3p08.png + ) +endif() + +# Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set +IF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "lib") +ENDIF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + +# Set a variable with CMake code which: +# Creates a symlink from src to dest (if possible) or alternatively +# copies if different. +macro(CREATE_SYMLINK SRC_FILE DEST_FILE) + FILE(REMOVE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE}) + if(WIN32 AND NOT CYGWIN AND NOT MSYS) + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${DEST_FILE} + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" ${CMAKE_CURRENT_BINARY_DIR}/${DEST_FILE} + DEPENDS ${PNG_LIB_TARGETS} + ) + ADD_CUSTOM_TARGET(${DEST_FILE}_COPY ALL DEPENDS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE}) + else(WIN32 AND NOT CYGWIN AND NOT MSYS) + get_filename_component(LINK_TARGET "${SRC_FILE}" NAME) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${LINK_TARGET}" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${LINK_TARGET}" ${DEST_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif(WIN32 AND NOT CYGWIN AND NOT MSYS) +endmacro() + +# libpng is a library so default to 'lib' +if(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR lib) +endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + +# CREATE PKGCONFIG FILES +# we use the same files like ./configure, so we have to set its vars +# Only do this on Windows for Cygwin - the files don't make much sense outside +# a UNIX look alike +if(NOT WIN32 OR CYGWIN OR MINGW) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_PREFIX}) + set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_PREFIX}/include) + set(LIBS "-lz -lm") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc @ONLY) + CREATE_SYMLINK(${PNGLIB_NAME}.pc libpng.pc) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng-config.in + ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config @ONLY) + CREATE_SYMLINK(${PNGLIB_NAME}-config libpng-config) +endif(NOT WIN32 OR CYGWIN OR MINGW) + +# SET UP LINKS +if(PNG_SHARED) + set_target_properties(${PNG_LIB_NAME} PROPERTIES +# VERSION 16.${PNGLIB_RELEASE}.1.6.10 + VERSION 16.${PNGLIB_RELEASE}.0 + SOVERSION 16 + CLEAN_DIRECT_OUTPUT 1) +endif() +if(PNG_STATIC) + # MSVC doesn't use a different file extension for shared vs. static + # libs. We are able to change OUTPUT_NAME to remove the _static + # for all other platforms. + if(NOT MSVC) + set_target_properties(${PNG_LIB_NAME_STATIC} PROPERTIES + OUTPUT_NAME ${PNG_LIB_NAME} + CLEAN_DIRECT_OUTPUT 1) + endif() +endif() + +# If CMake > 2.4.x, we set a variable used below to export +# targets to an export file. +# TODO: Use VERSION_GREATER after our cmake_minimum_required >= 2.6.2 +if(CMAKE_MAJOR_VERSION GREATER 1 AND CMAKE_MINOR_VERSION GREATER 4) + set(PNG_EXPORT_RULE EXPORT libpng) +elseif(CMAKE_MAJOR_VERSION GREATER 2) # future proof + set(PNG_EXPORT_RULE EXPORT libpng) +endif() + +# INSTALL +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS ${PNG_LIB_TARGETS} + ${PNG_EXPORT_RULE} + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + if(PNG_SHARED) + # Create a symlink for libpng.dll.a => libpng16.dll.a on Cygwin + if(CYGWIN OR MINGW) + get_target_property(BUILD_TARGET_LOCATION ${PNG_LIB_NAME} LOCATION_${CMAKE_BUILD_TYPE}) + CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_IMPORT_LIBRARY_SUFFIX}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(CYGWIN OR MINGW) + + if(NOT WIN32) + get_target_property(BUILD_TARGET_LOCATION ${PNG_LIB_NAME} LOCATION_${CMAKE_BUILD_TYPE}) + CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_SHARED_LIBRARY_SUFFIX}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_SHARED_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(NOT WIN32) + endif(PNG_SHARED) + + if(PNG_STATIC) + if(NOT WIN32 OR CYGWIN OR MINGW) + get_target_property(BUILD_TARGET_LOCATION ${PNG_LIB_NAME_STATIC} LOCATION_${CMAKE_BUILD_TYPE}) + CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_STATIC_LIBRARY_SUFFIX}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_STATIC_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(NOT WIN32 OR CYGWIN OR MINGW) + endif() +endif() + +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${libpng_public_hdrs} DESTINATION include) + install(FILES ${libpng_public_hdrs} DESTINATION include/${PNGLIB_NAME}) +endif() +if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL ) + if(NOT WIN32 OR CYGWIN OR MINGW) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config DESTINATION bin) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config + DESTINATION bin) + endif(NOT WIN32 OR CYGWIN OR MINGW) +endif() + +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + # Install man pages + if(NOT PNG_MAN_DIR) + set(PNG_MAN_DIR "share/man") + endif() + install(FILES libpng.3 libpngpf.3 DESTINATION ${PNG_MAN_DIR}/man3) + install(FILES png.5 DESTINATION ${PNG_MAN_DIR}/man5) + # Install pkg-config files + if(NOT WIN32 OR CYGWIN OR MINGW) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config + DESTINATION bin) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config + DESTINATION bin) + endif(NOT WIN32 OR CYGWIN OR MINGW) +endif() + +# On versions of CMake that support it, create an export file CMake +# users can include() to import our targets +if(PNG_EXPORT_RULE AND NOT SKIP_INSTALL_EXPORT AND NOT SKIP_INSTALL_ALL ) + install(EXPORT libpng DESTINATION lib/libpng FILE lib${PNG_LIB_NAME}.cmake) +endif() + +# what's with libpng-$VER%.txt and all the extra files? + +# UNINSTALL +# do we need this? + +# DIST +# do we need this? + +# to create msvc import lib for mingw compiled shared lib +# pexports libpng.dll > libpng.def +# lib /def:libpng.def /machine:x86 + diff --git a/main/source/includes/lpng1610/INSTALL b/main/source/includes/lpng1610/INSTALL index 8ed9b1d5..b567de5a 100644 --- a/main/source/includes/lpng1610/INSTALL +++ b/main/source/includes/lpng1610/INSTALL @@ -1,150 +1,150 @@ - -Installing libpng - -On Unix/Linux and similar systems, you can simply type - - ./configure [--prefix=/path] - make check - make install - -and ignore the rest of this document. - -If configure does not work on your system, or if you have a need to -change configure.ac or Makefile.am, and you have a reasonably -up-to-date set of tools, running ./autogen.sh in a git clone before -running ./configure may fix the problem. To be really sure that you -aren't using any of the included pre-built scripts, you can do this: - - ./configure --enable-maintainer-mode - make maintainer-clean - ./autogen.sh --maintainer --clean - ./autogen.sh --maintainer - ./configure [--prefix=/path] [other options] - make - make install - make check - -Instead, you can use one of the custom-built makefiles in the -"scripts" directory - - cp scripts/makefile.system makefile - make test - make install - -The files that are presently available in the scripts directory -are listed and described in scripts/README.txt. - -Or you can use one of the "projects" in the "projects" directory. - -Before installing libpng, you must first install zlib, if it -is not already on your system. zlib can usually be found -wherever you got libpng. zlib can be placed in another directory, -at the same level as libpng. - -If your system already has a preinstalled zlib you will still need -to have access to the zlib.h and zconf.h include files that -correspond to the version of zlib that's installed. - -If you wish to test with a particular zlib that is not first in the -standard library search path, put ZLIBLIB, ZLIBINC, CPPFLAGS, LDFLAGS, -and LD_LIBRARY_PATH in your environment before running "make test" -or "make distcheck": - -ZLIBLIB=/path/to/lib export ZLIBLIB -ZLIBINC=/path/to/include export ZLIBINC -CPPFLAGS="-I$ZLIBINC" export CPPFLAGS -LDFLAGS="-L$ZLIBLIB" export LDFLAGS -LD_LIBRARY_PATH="$ZLIBLIB:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH - -If you are using one of the makefile scripts, put ZLIBLIB and ZLIBINC -in your environment and type "make ZLIBLIB=$ZLIBLIB ZLIBINC=$ZLIBINC test". - -If you want to use "cmake" (see www.cmake.org), type - - cmake . -DCMAKE_INSTALL_PREFIX=/path - make - make install - -You can rename the directories that you downloaded (they -might be called "libpng-x.y.z" or "libpngNN" and "zlib-1.2.7" -or "zlib127") so that you have directories called "zlib" and "libpng". - -Your directory structure should look like this: - - .. (the parent directory) - libpng (this directory) - INSTALL (this file) - README - *.h - *.c - CMakeLists.txt => "cmake" script - configuration files: - configure.ac, configure, Makefile.am, Makefile.in, - autogen.sh, config.guess, ltmain.sh, missing, libpng.pc.in, - libpng-config.in, aclocal.m4, config.h.in, config.sub, - depcomp, install-sh, mkinstalldirs, test-pngtest.sh - contrib - gregbook - libtests - pngminim - pngminus - pngsuite - visupng - projects - visualc71 - vstudio - scripts - makefile.* - *.def (module definition files) - etc. - pngtest.png - etc. - zlib - README - *.h - *.c - contrib - etc. - -If the line endings in the files look funny, you may wish to get the other -distribution of libpng. It is available in both tar.gz (UNIX style line -endings) and zip (DOS style line endings) formats. - -If you are building libpng with MSVC, you can enter the -libpng projects\visualc6 or visualc71 directory and follow the instructions -in README.txt. - -Otherwise enter the zlib directory and follow the instructions in zlib/README, -then come back here and run "configure" or choose the appropriate -makefile.sys in the scripts directory. - -Copy the file (or files) that you need from the -scripts directory into this directory, for example - - MSDOS example: copy scripts\makefile.msc makefile - UNIX example: cp scripts/makefile.std makefile - -Read the makefile to see if you need to change any source or -target directories to match your preferences. - -Then read pnglibconf.dfa to see if you want to make any configuration -changes. - -Then just run "make" which will create the libpng library in -this directory and "make test" which will run a quick test that reads -the "pngtest.png" file and writes a "pngout.png" file that should be -identical to it. Look for "9782 zero samples" in the output of the -test. For more confidence, you can run another test by typing -"pngtest pngnow.png" and looking for "289 zero samples" in the output. -Also, you can run "pngtest -m contrib/pngsuite/*.png" and compare -your output with the result shown in contrib/pngsuite/README. - -Most of the makefiles will allow you to run "make install" to -put the library in its final resting place (if you want to -do that, run "make install" in the zlib directory first if necessary). -Some also allow you to run "make test-installed" after you have -run "make install". - -Further information can be found in the README and libpng-manual.txt -files, in the individual makefiles, in png.h, and the manual pages -libpng.3 and png.5. + +Installing libpng + +On Unix/Linux and similar systems, you can simply type + + ./configure [--prefix=/path] + make check + make install + +and ignore the rest of this document. + +If configure does not work on your system, or if you have a need to +change configure.ac or Makefile.am, and you have a reasonably +up-to-date set of tools, running ./autogen.sh in a git clone before +running ./configure may fix the problem. To be really sure that you +aren't using any of the included pre-built scripts, you can do this: + + ./configure --enable-maintainer-mode + make maintainer-clean + ./autogen.sh --maintainer --clean + ./autogen.sh --maintainer + ./configure [--prefix=/path] [other options] + make + make install + make check + +Instead, you can use one of the custom-built makefiles in the +"scripts" directory + + cp scripts/makefile.system makefile + make test + make install + +The files that are presently available in the scripts directory +are listed and described in scripts/README.txt. + +Or you can use one of the "projects" in the "projects" directory. + +Before installing libpng, you must first install zlib, if it +is not already on your system. zlib can usually be found +wherever you got libpng. zlib can be placed in another directory, +at the same level as libpng. + +If your system already has a preinstalled zlib you will still need +to have access to the zlib.h and zconf.h include files that +correspond to the version of zlib that's installed. + +If you wish to test with a particular zlib that is not first in the +standard library search path, put ZLIBLIB, ZLIBINC, CPPFLAGS, LDFLAGS, +and LD_LIBRARY_PATH in your environment before running "make test" +or "make distcheck": + +ZLIBLIB=/path/to/lib export ZLIBLIB +ZLIBINC=/path/to/include export ZLIBINC +CPPFLAGS="-I$ZLIBINC" export CPPFLAGS +LDFLAGS="-L$ZLIBLIB" export LDFLAGS +LD_LIBRARY_PATH="$ZLIBLIB:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH + +If you are using one of the makefile scripts, put ZLIBLIB and ZLIBINC +in your environment and type "make ZLIBLIB=$ZLIBLIB ZLIBINC=$ZLIBINC test". + +If you want to use "cmake" (see www.cmake.org), type + + cmake . -DCMAKE_INSTALL_PREFIX=/path + make + make install + +You can rename the directories that you downloaded (they +might be called "libpng-x.y.z" or "libpngNN" and "zlib-1.2.7" +or "zlib127") so that you have directories called "zlib" and "libpng". + +Your directory structure should look like this: + + .. (the parent directory) + libpng (this directory) + INSTALL (this file) + README + *.h + *.c + CMakeLists.txt => "cmake" script + configuration files: + configure.ac, configure, Makefile.am, Makefile.in, + autogen.sh, config.guess, ltmain.sh, missing, libpng.pc.in, + libpng-config.in, aclocal.m4, config.h.in, config.sub, + depcomp, install-sh, mkinstalldirs, test-pngtest.sh + contrib + gregbook + libtests + pngminim + pngminus + pngsuite + visupng + projects + visualc71 + vstudio + scripts + makefile.* + *.def (module definition files) + etc. + pngtest.png + etc. + zlib + README + *.h + *.c + contrib + etc. + +If the line endings in the files look funny, you may wish to get the other +distribution of libpng. It is available in both tar.gz (UNIX style line +endings) and zip (DOS style line endings) formats. + +If you are building libpng with MSVC, you can enter the +libpng projects\visualc6 or visualc71 directory and follow the instructions +in README.txt. + +Otherwise enter the zlib directory and follow the instructions in zlib/README, +then come back here and run "configure" or choose the appropriate +makefile.sys in the scripts directory. + +Copy the file (or files) that you need from the +scripts directory into this directory, for example + + MSDOS example: copy scripts\makefile.msc makefile + UNIX example: cp scripts/makefile.std makefile + +Read the makefile to see if you need to change any source or +target directories to match your preferences. + +Then read pnglibconf.dfa to see if you want to make any configuration +changes. + +Then just run "make" which will create the libpng library in +this directory and "make test" which will run a quick test that reads +the "pngtest.png" file and writes a "pngout.png" file that should be +identical to it. Look for "9782 zero samples" in the output of the +test. For more confidence, you can run another test by typing +"pngtest pngnow.png" and looking for "289 zero samples" in the output. +Also, you can run "pngtest -m contrib/pngsuite/*.png" and compare +your output with the result shown in contrib/pngsuite/README. + +Most of the makefiles will allow you to run "make install" to +put the library in its final resting place (if you want to +do that, run "make install" in the zlib directory first if necessary). +Some also allow you to run "make test-installed" after you have +run "make install". + +Further information can be found in the README and libpng-manual.txt +files, in the individual makefiles, in png.h, and the manual pages +libpng.3 and png.5. diff --git a/main/source/includes/lpng1610/LICENSE b/main/source/includes/lpng1610/LICENSE index ea1841e4..94f5e950 100644 --- a/main/source/includes/lpng1610/LICENSE +++ b/main/source/includes/lpng1610/LICENSE @@ -1,111 +1,111 @@ - -This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.2.6, August 15, 2004, through 1.6.10, March 6, 2014, are -Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.2.5 -with the following individual added to the list of Contributing Authors - - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are -Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6 -with the following individuals added to the list of Contributing Authors - - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-0.96, -with the following individuals added to the list of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88, -with the following individuals added to the list of Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about" -boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a -certification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -March 6, 2014 + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.2.6, August 15, 2004, through 1.6.10, March 6, 2014, are +Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +March 6, 2014 diff --git a/main/source/includes/lpng1610/README b/main/source/includes/lpng1610/README index d7b19371..57f287bf 100644 --- a/main/source/includes/lpng1610/README +++ b/main/source/includes/lpng1610/README @@ -1,202 +1,202 @@ -README for libpng version 1.6.10 - March 6, 2014 (shared library 16.0) -See the note about version numbers near the top of png.h - -See INSTALL for instructions on how to install libpng. - -Libpng comes in several distribution formats. Get libpng-*.tar.gz or -libpng-*.tar.xz or if you want UNIX-style line endings in the text files, -or lpng*.7z or lpng*.zip if you want DOS-style line endings. - -Version 0.89 was the first official release of libpng. Don't let the -fact that it's the first release fool you. The libpng library has been in -extensive use and testing since mid-1995. By late 1997 it had -finally gotten to the stage where there hadn't been significant -changes to the API in some time, and people have a bad feeling about -libraries with versions < 1.0. Version 1.0.0 was released in -March 1998. - -**** -Note that some of the changes to the png_info structure render this -version of the library binary incompatible with libpng-0.89 or -earlier versions if you are using a shared library. The type of the -"filler" parameter for png_set_filler() has changed from png_byte to -png_uint_32, which will affect shared-library applications that use -this function. - -To avoid problems with changes to the internals of png_info_struct, -new APIs have been made available in 0.95 to avoid direct application -access to info_ptr. These functions are the png_set_ and -png_get_ functions. These functions should be used when -accessing/storing the info_struct data, rather than manipulating it -directly, to avoid such problems in the future. - -It is important to note that the APIs do not make current programs -that access the info struct directly incompatible with the new -library. However, it is strongly suggested that new programs use -the new APIs (as shown in example.c and pngtest.c), and older programs -be converted to the new format, to facilitate upgrades in the future. -**** - -Additions since 0.90 include the ability to compile libpng as a -Windows DLL, and new APIs for accessing data in the info struct. -Experimental functions include the ability to set weighting and cost -factors for row filter selection, direct reads of integers from buffers -on big-endian processors that support misaligned data access, faster -methods of doing alpha composition, and more accurate 16->8 bit color -conversion. - -The additions since 0.89 include the ability to read from a PNG stream -which has had some (or all) of the signature bytes read by the calling -application. This also allows the reading of embedded PNG streams that -do not have the PNG file signature. As well, it is now possible to set -the library action on the detection of chunk CRC errors. It is possible -to set different actions based on whether the CRC error occurred in a -critical or an ancillary chunk. - -The changes made to the library, and bugs fixed are based on discussions -on the PNG-implement mailing list and not on material submitted -privately to Guy, Andreas, or Glenn. They will forward any good -suggestions to the list. - -For a detailed description on using libpng, read libpng-manual.txt. For -examples of libpng in a program, see example.c and pngtest.c. For usage -information and restrictions (what little they are) on libpng, see -png.h. For a description on using zlib (the compression library used by -libpng) and zlib's restrictions, see zlib.h - -I have included a general makefile, as well as several machine and -compiler specific ones, but you may have to modify one for your own needs. - -You should use zlib 1.0.4 or later to run this, but it MAY work with -versions as old as zlib 0.95. Even so, there are bugs in older zlib -versions which can cause the output of invalid compression streams for -some images. You will definitely need zlib 1.0.4 or later if you are -taking advantage of the MS-DOS "far" structure allocation for the small -and medium memory models. You should also note that zlib is a -compression library that is useful for more things than just PNG files. -You can use zlib as a drop-in replacement for fread() and fwrite() if -you are so inclined. - -zlib should be available at the same place that libpng is, or at zlib.net. - -You may also want a copy of the PNG specification. It is available -as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find -these at http://www.libpng.org/pub/png/documents/ - -This code is currently being archived at libpng.sf.net in the -[DOWNLOAD] area, and at ftp://ftp.simplesystems.org. If you can't find it -in any of those places, e-mail me, and I'll help you find it. - -If you have any code changes, requests, problems, etc., please e-mail -them to me. Also, I'd appreciate any make files or project files, -and any modifications you needed to make to get libpng to compile, -along with a #define variable to tell what compiler/system you are on. -If you needed to add transformations to libpng, or wish libpng would -provide the image in a different way, drop me a note (and code, if -possible), so I can consider supporting the transformation. -Finally, if you get any warning messages when compiling libpng -(note: not zlib), and they are easy to fix, I'd appreciate the -fix. Please mention "libpng" somewhere in the subject line. Thanks. - -This release was created and will be supported by myself (of course -based in a large way on Guy's and Andreas' earlier work), and the PNG -development group. - -Send comments/corrections/commendations to png-mng-implement at -lists.sourceforge.net (subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) or to glennrp at users.sourceforge.net - -You can't reach Guy, the original libpng author, at the addresses -given in previous versions of this document. He and Andreas will -read mail addressed to the png-implement list, however. - -Please do not send general questions about PNG. Send them to -png-mng-misc at lists.sf.net (subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-misc to -subscribe). If you have a question about something -in the PNG specification that is related to using libpng, send it -to me. Send me any questions that start with "I was using libpng, -and ...". If in doubt, send questions to me. I'll bounce them -to others, if necessary. - -Please do not send suggestions on how to change PNG. We have -been discussing PNG for nineteen years now, and it is official and -finished. If you have suggestions for libpng, however, I'll -gladly listen. Even if your suggestion is not used immediately, -it may be used later. - -Files in this distribution: - - ANNOUNCE => Announcement of this version, with recent changes - CHANGES => Description of changes between libpng versions - KNOWNBUG => List of known bugs and deficiencies - LICENSE => License to use and redistribute libpng - README => This file - TODO => Things not implemented in the current library - Y2KINFO => Statement of Y2K compliance - example.c => Example code for using libpng functions - libpng.3 => manual page for libpng (includes libpng-manual.txt) - libpng-manual.txt => Description of libpng and its functions - libpngpf.3 => manual page for libpng's private functions - png.5 => manual page for the PNG format - png.c => Basic interface functions common to library - png.h => Library function and interface declarations (public) - pngpriv.h => Library function and interface declarations (private) - pngconf.h => System specific library configuration (public) - pngstruct.h => png_struct declaration (private) - pnginfo.h => png_info struct declaration (private) - pngdebug.h => debugging macros (private) - pngerror.c => Error/warning message I/O functions - pngget.c => Functions for retrieving info from struct - pngmem.c => Memory handling functions - pngbar.png => PNG logo, 88x31 - pngnow.png => PNG logo, 98x31 - pngpread.c => Progressive reading functions - pngread.c => Read data/helper high-level functions - pngrio.c => Lowest-level data read I/O functions - pngrtran.c => Read data transformation functions - pngrutil.c => Read data utility functions - pngset.c => Functions for storing data into the info_struct - pngtest.c => Library test program - pngtest.png => Library test sample image - pngtrans.c => Common data transformation functions - pngwio.c => Lowest-level write I/O functions - pngwrite.c => High-level write functions - pngwtran.c => Write data transformations - pngwutil.c => Write utility functions - arm => Contains optimized code for the ARM platform - contrib => Contributions - examples => Example programs - gregbook => source code for PNG reading and writing, from - Greg Roelofs' "PNG: The Definitive Guide", - O'Reilly, 1999 - libtests => Test programs - pngminim => Minimal decoder, encoder, and progressive decoder - programs demonstrating use of pngusr.dfa - pngminus => Simple pnm2png and png2pnm programs - pngsuite => Test images - tools => Various tools - visupng => Contains a MSVC workspace for VisualPng - projects => Contains project files and workspaces for - building a DLL - owatcom => Contains a WATCOM project for building libpng - visualc71 => Contains a Microsoft Visual C++ (MSVC) - workspace for building libpng and zlib - vstudio => Contains a Microsoft Visual C++ (MSVC) - workspace for building libpng and zlib - scripts => Directory containing scripts for building libpng: - (see scripts/README.txt for the list of scripts) - -Good luck, and happy coding. - --Glenn Randers-Pehrson (current maintainer, since 1998) - Internet: glennrp at users.sourceforge.net - --Andreas Eric Dilger (former maintainer, 1996-1997) - Internet: adilger at enel.ucalgary.ca - Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/ - --Guy Eric Schalnat (original author and former maintainer, 1995-1996) - (formerly of Group 42, Inc) - Internet: gschal at infinet.com +README for libpng version 1.6.10 - March 6, 2014 (shared library 16.0) +See the note about version numbers near the top of png.h + +See INSTALL for instructions on how to install libpng. + +Libpng comes in several distribution formats. Get libpng-*.tar.gz or +libpng-*.tar.xz or if you want UNIX-style line endings in the text files, +or lpng*.7z or lpng*.zip if you want DOS-style line endings. + +Version 0.89 was the first official release of libpng. Don't let the +fact that it's the first release fool you. The libpng library has been in +extensive use and testing since mid-1995. By late 1997 it had +finally gotten to the stage where there hadn't been significant +changes to the API in some time, and people have a bad feeling about +libraries with versions < 1.0. Version 1.0.0 was released in +March 1998. + +**** +Note that some of the changes to the png_info structure render this +version of the library binary incompatible with libpng-0.89 or +earlier versions if you are using a shared library. The type of the +"filler" parameter for png_set_filler() has changed from png_byte to +png_uint_32, which will affect shared-library applications that use +this function. + +To avoid problems with changes to the internals of png_info_struct, +new APIs have been made available in 0.95 to avoid direct application +access to info_ptr. These functions are the png_set_ and +png_get_ functions. These functions should be used when +accessing/storing the info_struct data, rather than manipulating it +directly, to avoid such problems in the future. + +It is important to note that the APIs do not make current programs +that access the info struct directly incompatible with the new +library. However, it is strongly suggested that new programs use +the new APIs (as shown in example.c and pngtest.c), and older programs +be converted to the new format, to facilitate upgrades in the future. +**** + +Additions since 0.90 include the ability to compile libpng as a +Windows DLL, and new APIs for accessing data in the info struct. +Experimental functions include the ability to set weighting and cost +factors for row filter selection, direct reads of integers from buffers +on big-endian processors that support misaligned data access, faster +methods of doing alpha composition, and more accurate 16->8 bit color +conversion. + +The additions since 0.89 include the ability to read from a PNG stream +which has had some (or all) of the signature bytes read by the calling +application. This also allows the reading of embedded PNG streams that +do not have the PNG file signature. As well, it is now possible to set +the library action on the detection of chunk CRC errors. It is possible +to set different actions based on whether the CRC error occurred in a +critical or an ancillary chunk. + +The changes made to the library, and bugs fixed are based on discussions +on the PNG-implement mailing list and not on material submitted +privately to Guy, Andreas, or Glenn. They will forward any good +suggestions to the list. + +For a detailed description on using libpng, read libpng-manual.txt. For +examples of libpng in a program, see example.c and pngtest.c. For usage +information and restrictions (what little they are) on libpng, see +png.h. For a description on using zlib (the compression library used by +libpng) and zlib's restrictions, see zlib.h + +I have included a general makefile, as well as several machine and +compiler specific ones, but you may have to modify one for your own needs. + +You should use zlib 1.0.4 or later to run this, but it MAY work with +versions as old as zlib 0.95. Even so, there are bugs in older zlib +versions which can cause the output of invalid compression streams for +some images. You will definitely need zlib 1.0.4 or later if you are +taking advantage of the MS-DOS "far" structure allocation for the small +and medium memory models. You should also note that zlib is a +compression library that is useful for more things than just PNG files. +You can use zlib as a drop-in replacement for fread() and fwrite() if +you are so inclined. + +zlib should be available at the same place that libpng is, or at zlib.net. + +You may also want a copy of the PNG specification. It is available +as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find +these at http://www.libpng.org/pub/png/documents/ + +This code is currently being archived at libpng.sf.net in the +[DOWNLOAD] area, and at ftp://ftp.simplesystems.org. If you can't find it +in any of those places, e-mail me, and I'll help you find it. + +If you have any code changes, requests, problems, etc., please e-mail +them to me. Also, I'd appreciate any make files or project files, +and any modifications you needed to make to get libpng to compile, +along with a #define variable to tell what compiler/system you are on. +If you needed to add transformations to libpng, or wish libpng would +provide the image in a different way, drop me a note (and code, if +possible), so I can consider supporting the transformation. +Finally, if you get any warning messages when compiling libpng +(note: not zlib), and they are easy to fix, I'd appreciate the +fix. Please mention "libpng" somewhere in the subject line. Thanks. + +This release was created and will be supported by myself (of course +based in a large way on Guy's and Andreas' earlier work), and the PNG +development group. + +Send comments/corrections/commendations to png-mng-implement at +lists.sourceforge.net (subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) or to glennrp at users.sourceforge.net + +You can't reach Guy, the original libpng author, at the addresses +given in previous versions of this document. He and Andreas will +read mail addressed to the png-implement list, however. + +Please do not send general questions about PNG. Send them to +png-mng-misc at lists.sf.net (subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-misc to +subscribe). If you have a question about something +in the PNG specification that is related to using libpng, send it +to me. Send me any questions that start with "I was using libpng, +and ...". If in doubt, send questions to me. I'll bounce them +to others, if necessary. + +Please do not send suggestions on how to change PNG. We have +been discussing PNG for nineteen years now, and it is official and +finished. If you have suggestions for libpng, however, I'll +gladly listen. Even if your suggestion is not used immediately, +it may be used later. + +Files in this distribution: + + ANNOUNCE => Announcement of this version, with recent changes + CHANGES => Description of changes between libpng versions + KNOWNBUG => List of known bugs and deficiencies + LICENSE => License to use and redistribute libpng + README => This file + TODO => Things not implemented in the current library + Y2KINFO => Statement of Y2K compliance + example.c => Example code for using libpng functions + libpng.3 => manual page for libpng (includes libpng-manual.txt) + libpng-manual.txt => Description of libpng and its functions + libpngpf.3 => manual page for libpng's private functions + png.5 => manual page for the PNG format + png.c => Basic interface functions common to library + png.h => Library function and interface declarations (public) + pngpriv.h => Library function and interface declarations (private) + pngconf.h => System specific library configuration (public) + pngstruct.h => png_struct declaration (private) + pnginfo.h => png_info struct declaration (private) + pngdebug.h => debugging macros (private) + pngerror.c => Error/warning message I/O functions + pngget.c => Functions for retrieving info from struct + pngmem.c => Memory handling functions + pngbar.png => PNG logo, 88x31 + pngnow.png => PNG logo, 98x31 + pngpread.c => Progressive reading functions + pngread.c => Read data/helper high-level functions + pngrio.c => Lowest-level data read I/O functions + pngrtran.c => Read data transformation functions + pngrutil.c => Read data utility functions + pngset.c => Functions for storing data into the info_struct + pngtest.c => Library test program + pngtest.png => Library test sample image + pngtrans.c => Common data transformation functions + pngwio.c => Lowest-level write I/O functions + pngwrite.c => High-level write functions + pngwtran.c => Write data transformations + pngwutil.c => Write utility functions + arm => Contains optimized code for the ARM platform + contrib => Contributions + examples => Example programs + gregbook => source code for PNG reading and writing, from + Greg Roelofs' "PNG: The Definitive Guide", + O'Reilly, 1999 + libtests => Test programs + pngminim => Minimal decoder, encoder, and progressive decoder + programs demonstrating use of pngusr.dfa + pngminus => Simple pnm2png and png2pnm programs + pngsuite => Test images + tools => Various tools + visupng => Contains a MSVC workspace for VisualPng + projects => Contains project files and workspaces for + building a DLL + owatcom => Contains a WATCOM project for building libpng + visualc71 => Contains a Microsoft Visual C++ (MSVC) + workspace for building libpng and zlib + vstudio => Contains a Microsoft Visual C++ (MSVC) + workspace for building libpng and zlib + scripts => Directory containing scripts for building libpng: + (see scripts/README.txt for the list of scripts) + +Good luck, and happy coding. + +-Glenn Randers-Pehrson (current maintainer, since 1998) + Internet: glennrp at users.sourceforge.net + +-Andreas Eric Dilger (former maintainer, 1996-1997) + Internet: adilger at enel.ucalgary.ca + Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/ + +-Guy Eric Schalnat (original author and former maintainer, 1995-1996) + (formerly of Group 42, Inc) + Internet: gschal at infinet.com diff --git a/main/source/includes/lpng1610/TODO b/main/source/includes/lpng1610/TODO index 4659b70d..63613b8d 100644 --- a/main/source/includes/lpng1610/TODO +++ b/main/source/includes/lpng1610/TODO @@ -1,28 +1,28 @@ -/* -TODO - list of things to do for libpng: - -Final bug fixes. -Better C++ wrapper/full C++ implementation? -Fix problem with C++ and EXTERN "C". -cHRM transformation. -Remove setjmp/longjmp usage in favor of returning error codes. -Add "grayscale->palette" transformation and "palette->grayscale" detection. -Improved dithering. -Multi-lingual error and warning message support. -Complete sRGB transformation (presently it simply uses gamma=0.45455). -Make profile checking optional via a png_set_something() call. -Man pages for function calls. -Better documentation. -Better filter selection - (counting huffman bits/precompression? filter inertia? filter costs?). -Histogram creation. -Text conversion between different code pages (Latin-1 -> Mac and DOS). -Avoid building gamma tables whenever possible. -Use greater precision when changing to linear gamma for compositing against - background and doing rgb-to-gray transformation. -Investigate pre-incremented loop counters and other loop constructions. -Add interpolated method of handling interlacing. -Switch to the simpler zlib (zlib/libpng) license if legally possible. -Extend pngvalid.c to validate more of the libpng transformations. - -*/ +/* +TODO - list of things to do for libpng: + +Final bug fixes. +Better C++ wrapper/full C++ implementation? +Fix problem with C++ and EXTERN "C". +cHRM transformation. +Remove setjmp/longjmp usage in favor of returning error codes. +Add "grayscale->palette" transformation and "palette->grayscale" detection. +Improved dithering. +Multi-lingual error and warning message support. +Complete sRGB transformation (presently it simply uses gamma=0.45455). +Make profile checking optional via a png_set_something() call. +Man pages for function calls. +Better documentation. +Better filter selection + (counting huffman bits/precompression? filter inertia? filter costs?). +Histogram creation. +Text conversion between different code pages (Latin-1 -> Mac and DOS). +Avoid building gamma tables whenever possible. +Use greater precision when changing to linear gamma for compositing against + background and doing rgb-to-gray transformation. +Investigate pre-incremented loop counters and other loop constructions. +Add interpolated method of handling interlacing. +Switch to the simpler zlib (zlib/libpng) license if legally possible. +Extend pngvalid.c to validate more of the libpng transformations. + +*/ diff --git a/main/source/includes/lpng1610/configure b/main/source/includes/lpng1610/configure index 4dbd0267..e6cc4fed 100644 --- a/main/source/includes/lpng1610/configure +++ b/main/source/includes/lpng1610/configure @@ -1,19 +1,19 @@ - -echo " - There is no \"configure\" script in this distribution (*.zip or *.7z) of - libpng-1.6.10. - - Instead, please copy the appropriate makefile for your system from the - \"scripts\" directory. Read the INSTALL file for more details. - - Update, July 2004: you can get a \"configure\" based distribution - from the libpng distribution sites. Download the file - libpng-1.6.10.tar.gz, libpng-1.6.10.tar.xz, or libpng-1.6.10.tar.bz2 - - If the line endings in the files look funny, which is likely to be the - case if you were trying to run \"configure\" on a Linux machine, you may - wish to get the other distribution of libpng. It is available in both - tar.gz/tar.xz (UNIX style line endings, with \"configure\") and .7z/.zip - (DOS style line endings, without \"configure\") formats. -" - + +echo " + There is no \"configure\" script in this distribution (*.zip or *.7z) of + libpng-1.6.10. + + Instead, please copy the appropriate makefile for your system from the + \"scripts\" directory. Read the INSTALL file for more details. + + Update, July 2004: you can get a \"configure\" based distribution + from the libpng distribution sites. Download the file + libpng-1.6.10.tar.gz, libpng-1.6.10.tar.xz, or libpng-1.6.10.tar.bz2 + + If the line endings in the files look funny, which is likely to be the + case if you were trying to run \"configure\" on a Linux machine, you may + wish to get the other distribution of libpng. It is available in both + tar.gz/tar.xz (UNIX style line endings, with \"configure\") and .7z/.zip + (DOS style line endings, without \"configure\") formats. +" + diff --git a/main/source/includes/lpng1610/contrib/README.txt b/main/source/includes/lpng1610/contrib/README.txt index 7e9b7d06..bcd433d3 100644 --- a/main/source/includes/lpng1610/contrib/README.txt +++ b/main/source/includes/lpng1610/contrib/README.txt @@ -1,4 +1,4 @@ - -This "contrib" directory contains contributions which are not necessarily under -the libpng license, although all are open source. They are not part of -libpng proper and are not used for building the library. + +This "contrib" directory contains contributions which are not necessarily under +the libpng license, although all are open source. They are not part of +libpng proper and are not used for building the library. diff --git a/main/source/includes/lpng1610/contrib/arm-neon/README b/main/source/includes/lpng1610/contrib/arm-neon/README index 9c72d0a8..535c8d3f 100644 --- a/main/source/includes/lpng1610/contrib/arm-neon/README +++ b/main/source/includes/lpng1610/contrib/arm-neon/README @@ -1,83 +1,83 @@ -OPERATING SYSTEM SPECIFIC ARM NEON DETECTION --------------------------------------------- - -Detection of the ability to exexcute ARM NEON on an ARM processor requires -operating system support. (The information is not available in user mode.) - -HOW TO USE THIS ---------------- - -This directory contains C code fragments that can be included in arm/arm_init.c -by setting the macro PNG_ARM_NEON_FILE to the file name in "" or <> at build -time. This setting is not recorded in pnglibconf.h and can be changed simply by -rebuilding arm/arm_init.o with the required macro definition. - -For any of this code to be used the ARM NEON code must be enabled and run time -checks must be supported. I.e.: - -#if PNG_ARM_NEON_OPT > 0 -#ifdef PNG_ARM_NEON_CHECK_SUPPORTED - -This is done in a 'configure' build by passing configure the argument: - - --enable-arm-neon=check - -Apart from the basic Linux implementation in contrib/arm-neon/linux.c this code -is unsupported. That means that it is not even compiled on a regular basis and -may be broken in any given minor release. - -FILE FORMAT ------------ - -Each file documents its testing status as of the last time it was tested (which -may have been a long time ago): - -STATUS: one of: - SUPPORTED: This indicates that the file is included in the regularly - performed test builds and bugs are fixed when discovered. - COMPILED: This indicates that the code did compile at least once. See the - more detailed description for the extent to which the result was - successful. - TESTED: This means the code was fully compiled into the libpng test programs - and these were run at least once. - -BUG REPORTS: an email address to which to send reports of problems - -The file is a fragment of C code. It should not define any 'extern' symbols; -everything should be static. It must define the function: - -static int png_have_neon(png_structp png_ptr); - -That function must return 1 if ARM NEON instructions are supported, 0 if not. -It must not execute png_error unless it detects a bug. A png_error will prevent -the reading of the PNG and in the future, writing too. - -BUG REPORTS ------------ - -If you mail a bug report for any file that is not SUPPORTED there may only be -limited response. Consider fixing it and sending a patch to fix the problem - -this is more likely to result in action. - -CONTRIBUTIONS -------------- - -You may send contributions of new implementations to -png-mng-implement@sourceforge.net. Please write code in strict C90 C where -possible. Obviously OS dependencies are to be expected. If you submit code you -must have the authors permission and it must have a license that is acceptable -to the current maintainer; in particular that license must permit modification -and redistribution. - -Please try to make the contribution a single file and give the file a clear and -unambiguous name that identifies the target OS. If multiple files really are -required put them all in a sub-directory. - -You must also be prepared to handle bug reports from users of the code, either -by joining the png-mng-implement mailing list or by providing an email for the -"BUG REPORTS" entry or both. Please make sure that the header of the file -contains the STATUS and BUG REPORTS fields as above. - -Please list the OS requirements as precisely as possible. Ideally you should -also list the environment in which the code has been tested and certainly list -any environments where you suspect it might not work. +OPERATING SYSTEM SPECIFIC ARM NEON DETECTION +-------------------------------------------- + +Detection of the ability to exexcute ARM NEON on an ARM processor requires +operating system support. (The information is not available in user mode.) + +HOW TO USE THIS +--------------- + +This directory contains C code fragments that can be included in arm/arm_init.c +by setting the macro PNG_ARM_NEON_FILE to the file name in "" or <> at build +time. This setting is not recorded in pnglibconf.h and can be changed simply by +rebuilding arm/arm_init.o with the required macro definition. + +For any of this code to be used the ARM NEON code must be enabled and run time +checks must be supported. I.e.: + +#if PNG_ARM_NEON_OPT > 0 +#ifdef PNG_ARM_NEON_CHECK_SUPPORTED + +This is done in a 'configure' build by passing configure the argument: + + --enable-arm-neon=check + +Apart from the basic Linux implementation in contrib/arm-neon/linux.c this code +is unsupported. That means that it is not even compiled on a regular basis and +may be broken in any given minor release. + +FILE FORMAT +----------- + +Each file documents its testing status as of the last time it was tested (which +may have been a long time ago): + +STATUS: one of: + SUPPORTED: This indicates that the file is included in the regularly + performed test builds and bugs are fixed when discovered. + COMPILED: This indicates that the code did compile at least once. See the + more detailed description for the extent to which the result was + successful. + TESTED: This means the code was fully compiled into the libpng test programs + and these were run at least once. + +BUG REPORTS: an email address to which to send reports of problems + +The file is a fragment of C code. It should not define any 'extern' symbols; +everything should be static. It must define the function: + +static int png_have_neon(png_structp png_ptr); + +That function must return 1 if ARM NEON instructions are supported, 0 if not. +It must not execute png_error unless it detects a bug. A png_error will prevent +the reading of the PNG and in the future, writing too. + +BUG REPORTS +----------- + +If you mail a bug report for any file that is not SUPPORTED there may only be +limited response. Consider fixing it and sending a patch to fix the problem - +this is more likely to result in action. + +CONTRIBUTIONS +------------- + +You may send contributions of new implementations to +png-mng-implement@sourceforge.net. Please write code in strict C90 C where +possible. Obviously OS dependencies are to be expected. If you submit code you +must have the authors permission and it must have a license that is acceptable +to the current maintainer; in particular that license must permit modification +and redistribution. + +Please try to make the contribution a single file and give the file a clear and +unambiguous name that identifies the target OS. If multiple files really are +required put them all in a sub-directory. + +You must also be prepared to handle bug reports from users of the code, either +by joining the png-mng-implement mailing list or by providing an email for the +"BUG REPORTS" entry or both. Please make sure that the header of the file +contains the STATUS and BUG REPORTS fields as above. + +Please list the OS requirements as precisely as possible. Ideally you should +also list the environment in which the code has been tested and certainly list +any environments where you suspect it might not work. diff --git a/main/source/includes/lpng1610/contrib/arm-neon/android-ndk.c b/main/source/includes/lpng1610/contrib/arm-neon/android-ndk.c index 9d0e7b9b..72401234 100644 --- a/main/source/includes/lpng1610/contrib/arm-neon/android-ndk.c +++ b/main/source/includes/lpng1610/contrib/arm-neon/android-ndk.c @@ -1,39 +1,39 @@ -/* contrib/arm-neon/android-ndk.c - * - * Copyright (c) 2014 Glenn Randers-Pehrson - * Written by John Bowler, 2014. - * Last changed in libpng 1.6.10 [March 6, 2014] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * SEE contrib/arm-neon/README before reporting bugs - * - * STATUS: COMPILED, UNTESTED - * BUG REPORTS: png-mng-implement@sourceforge.net - * - * png_have_neon implemented for the Android NDK, see: - * - * Documentation: - * http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html - * http://code.google.com/p/android/issues/detail?id=49065 - * - * NOTE: this requires that libpng is built against the Android NDK and linked - * with an implementation of the Android ARM 'cpu-features' library. The code - * has been compiled only, not linked: no version of the library has been found, - * only the header files exist in the NDK. - */ -#include - -static int -png_have_neon(png_structp png_ptr) -{ - /* This is a whole lot easier than the linux code, however it is probably - * implemented as below, therefore it is better to cache the result (these - * function calls may be slow!) - */ - PNG_UNUSED(png_ptr) - return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && - (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; -} +/* contrib/arm-neon/android-ndk.c + * + * Copyright (c) 2014 Glenn Randers-Pehrson + * Written by John Bowler, 2014. + * Last changed in libpng 1.6.10 [March 6, 2014] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * SEE contrib/arm-neon/README before reporting bugs + * + * STATUS: COMPILED, UNTESTED + * BUG REPORTS: png-mng-implement@sourceforge.net + * + * png_have_neon implemented for the Android NDK, see: + * + * Documentation: + * http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html + * http://code.google.com/p/android/issues/detail?id=49065 + * + * NOTE: this requires that libpng is built against the Android NDK and linked + * with an implementation of the Android ARM 'cpu-features' library. The code + * has been compiled only, not linked: no version of the library has been found, + * only the header files exist in the NDK. + */ +#include + +static int +png_have_neon(png_structp png_ptr) +{ + /* This is a whole lot easier than the linux code, however it is probably + * implemented as below, therefore it is better to cache the result (these + * function calls may be slow!) + */ + PNG_UNUSED(png_ptr) + return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && + (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; +} diff --git a/main/source/includes/lpng1610/contrib/arm-neon/linux-auxv.c b/main/source/includes/lpng1610/contrib/arm-neon/linux-auxv.c index 4a02e980..696e297e 100644 --- a/main/source/includes/lpng1610/contrib/arm-neon/linux-auxv.c +++ b/main/source/includes/lpng1610/contrib/arm-neon/linux-auxv.c @@ -1,120 +1,120 @@ -/* contrib/arm-neon/linux-auxv.c - * - * Copyright (c) 2014 Glenn Randers-Pehrson - * Written by Mans Rullgard, 2011. - * Last changed in libpng 1.6.10 [March 6, 2014] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * SEE contrib/arm-neon/README before reporting bugs - * - * STATUS: COMPILED, TESTED - * BUG REPORTS: png-mng-implement@sourceforge.net - * - * png_have_neon implemented for Linux versions which allow access to - * /proc/self/auxv. This is probably faster, cleaner and safer than the code to - * read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece - * of potentially untested code and has more complex dependencies than the code - * to read cpuinfo. - * - * This generic __linux__ implementation requires reading /proc/self/auxv and - * looking at each element for one that records NEON capabilities. - */ -#include /* for POSIX 1003.1 */ -#include /* for EINTR */ - -#include -#include -#include -#include -#include - -/* A read call may be interrupted, in which case it returns -1 and sets errno to - * EINTR if nothing was done, otherwise (if something was done) a partial read - * may result. - */ -static size_t -safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes) -{ - size_t ntotal = 0; - char *buffer = png_voidcast(char*, buffer_in); - - while (nbytes > 0) - { - unsigned int nread; - int iread; - - /* Passing nread > INT_MAX to read is implementation defined in POSIX - * 1003.1, therefore despite the unsigned argument portable code must - * limit the value to INT_MAX! - */ - if (nbytes > INT_MAX) - nread = INT_MAX; - - else - nread = (unsigned int)/*SAFE*/nbytes; - - iread = read(fd, buffer, nread); - - if (iread == -1) - { - /* This is the devil in the details, a read can terminate early with 0 - * bytes read because of EINTR, yet it still returns -1 otherwise end - * of file cannot be distinguished. - */ - if (errno != EINTR) - { - png_warning(png_ptr, "/proc read failed"); - return 0; /* I.e., a permanent failure */ - } - } - - else if (iread < 0) - { - /* Not a valid 'read' result: */ - png_warning(png_ptr, "OS /proc read bug"); - return 0; - } - - else if (iread > 0) - { - /* Continue reading until a permanent failure, or EOF */ - buffer += iread; - nbytes -= (unsigned int)/*SAFE*/iread; - ntotal += (unsigned int)/*SAFE*/iread; - } - - else - return ntotal; - } - - return ntotal; /* nbytes == 0 */ -} - -static int -png_have_neon(png_structp png_ptr) -{ - int fd = open("/proc/self/auxv", O_RDONLY); - Elf32_auxv_t aux; - - /* Failsafe: failure to open means no NEON */ - if (fd == -1) - { - png_warning(png_ptr, "/proc/self/auxv open failed"); - return 0; - } - - while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux) - { - if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0) - { - close(fd); - return 1; - } - } - - close(fd); - return 0; -} +/* contrib/arm-neon/linux-auxv.c + * + * Copyright (c) 2014 Glenn Randers-Pehrson + * Written by Mans Rullgard, 2011. + * Last changed in libpng 1.6.10 [March 6, 2014] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * SEE contrib/arm-neon/README before reporting bugs + * + * STATUS: COMPILED, TESTED + * BUG REPORTS: png-mng-implement@sourceforge.net + * + * png_have_neon implemented for Linux versions which allow access to + * /proc/self/auxv. This is probably faster, cleaner and safer than the code to + * read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece + * of potentially untested code and has more complex dependencies than the code + * to read cpuinfo. + * + * This generic __linux__ implementation requires reading /proc/self/auxv and + * looking at each element for one that records NEON capabilities. + */ +#include /* for POSIX 1003.1 */ +#include /* for EINTR */ + +#include +#include +#include +#include +#include + +/* A read call may be interrupted, in which case it returns -1 and sets errno to + * EINTR if nothing was done, otherwise (if something was done) a partial read + * may result. + */ +static size_t +safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes) +{ + size_t ntotal = 0; + char *buffer = png_voidcast(char*, buffer_in); + + while (nbytes > 0) + { + unsigned int nread; + int iread; + + /* Passing nread > INT_MAX to read is implementation defined in POSIX + * 1003.1, therefore despite the unsigned argument portable code must + * limit the value to INT_MAX! + */ + if (nbytes > INT_MAX) + nread = INT_MAX; + + else + nread = (unsigned int)/*SAFE*/nbytes; + + iread = read(fd, buffer, nread); + + if (iread == -1) + { + /* This is the devil in the details, a read can terminate early with 0 + * bytes read because of EINTR, yet it still returns -1 otherwise end + * of file cannot be distinguished. + */ + if (errno != EINTR) + { + png_warning(png_ptr, "/proc read failed"); + return 0; /* I.e., a permanent failure */ + } + } + + else if (iread < 0) + { + /* Not a valid 'read' result: */ + png_warning(png_ptr, "OS /proc read bug"); + return 0; + } + + else if (iread > 0) + { + /* Continue reading until a permanent failure, or EOF */ + buffer += iread; + nbytes -= (unsigned int)/*SAFE*/iread; + ntotal += (unsigned int)/*SAFE*/iread; + } + + else + return ntotal; + } + + return ntotal; /* nbytes == 0 */ +} + +static int +png_have_neon(png_structp png_ptr) +{ + int fd = open("/proc/self/auxv", O_RDONLY); + Elf32_auxv_t aux; + + /* Failsafe: failure to open means no NEON */ + if (fd == -1) + { + png_warning(png_ptr, "/proc/self/auxv open failed"); + return 0; + } + + while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux) + { + if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0) + { + close(fd); + return 1; + } + } + + close(fd); + return 0; +} diff --git a/main/source/includes/lpng1610/contrib/arm-neon/linux.c b/main/source/includes/lpng1610/contrib/arm-neon/linux.c index 8d066565..182f3760 100644 --- a/main/source/includes/lpng1610/contrib/arm-neon/linux.c +++ b/main/source/includes/lpng1610/contrib/arm-neon/linux.c @@ -1,159 +1,159 @@ -/* contrib/arm-neon/linux.c - * - * Copyright (c) 2014 Glenn Randers-Pehrson - * Written by John Bowler, 2014. - * Last changed in libpng 1.6.10 [March 6, 2014] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * SEE contrib/arm-neon/README before reporting bugs - * - * STATUS: SUPPORTED - * BUG REPORTS: png-mng-implement@sourceforge.net - * - * png_have_neon implemented for Linux by reading the widely available - * pseudo-file /proc/cpuinfo. - * - * This code is strict ANSI-C and is probably moderately portable, it does - * however use and assumes that /proc/cpuinfo is never localized. - */ -#include - -static int -png_have_neon(png_structp png_ptr) -{ - FILE *f = fopen("/proc/cpuinfo", "rb"); - - if (f != NULL) - { - /* This is a simple state machine which reads the input byte-by-byte until - * it gets a match on the 'neon' feature or reaches the end of the stream. - */ - static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 }; - static const char ch_neon[] = { 78, 69, 79, 78 }; - - enum - { - StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine - } state; - int counter; - - for (state=StartLine, counter=0;;) - { - int ch = fgetc(f); - - if (ch == EOF) - { - /* EOF means error or end-of-file, return false; neon at EOF is - * assumed to be a mistake. - */ - fclose(f); - return 0; - } - - switch (state) - { - case StartLine: - /* Match spaces at the start of line */ - if (ch <= 32) /* skip control characters and space */ - break; - - counter=0; - state = Feature; - /* FALL THROUGH */ - - case Feature: - /* Match 'FEATURE', ASCII case insensitive. */ - if ((ch & ~0x20) == ch_feature[counter]) - { - if (++counter == (sizeof ch_feature)) - state = Colon; - break; - } - - /* did not match 'feature' */ - state = SkipLine; - /* FALL THROUGH */ - - case SkipLine: - skipLine: - /* Skip everything until we see linefeed or carriage return */ - if (ch != 10 && ch != 13) - break; - - state = StartLine; - break; - - case Colon: - /* Match any number of space or tab followed by ':' */ - if (ch == 32 || ch == 9) - break; - - if (ch == 58) /* i.e. ':' */ - { - state = StartTag; - break; - } - - /* Either a bad line format or a 'feature' prefix followed by - * other characters. - */ - state = SkipLine; - goto skipLine; - - case StartTag: - /* Skip space characters before a tag */ - if (ch == 32 || ch == 9) - break; - - state = Neon; - counter = 0; - /* FALL THROUGH */ - - case Neon: - /* Look for 'neon' tag */ - if ((ch & ~0x20) == ch_neon[counter]) - { - if (++counter == (sizeof ch_neon)) - state = HaveNeon; - break; - } - - state = SkipTag; - /* FALL THROUGH */ - - case SkipTag: - /* Skip non-space characters */ - if (ch == 10 || ch == 13) - state = StartLine; - - else if (ch == 32 || ch == 9) - state = StartTag; - break; - - case HaveNeon: - /* Have seen a 'neon' prefix, but there must be a space or new - * line character to terminate it. - */ - if (ch == 10 || ch == 13 || ch == 32 || ch == 9) - { - fclose(f); - return 1; - } - - state = SkipTag; - break; - - default: - png_error(png_ptr, "png_have_neon: internal error (bug)"); - } - } - } - - else - png_warning(png_ptr, "/proc/cpuinfo open failed"); - - return 0; -} +/* contrib/arm-neon/linux.c + * + * Copyright (c) 2014 Glenn Randers-Pehrson + * Written by John Bowler, 2014. + * Last changed in libpng 1.6.10 [March 6, 2014] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * SEE contrib/arm-neon/README before reporting bugs + * + * STATUS: SUPPORTED + * BUG REPORTS: png-mng-implement@sourceforge.net + * + * png_have_neon implemented for Linux by reading the widely available + * pseudo-file /proc/cpuinfo. + * + * This code is strict ANSI-C and is probably moderately portable, it does + * however use and assumes that /proc/cpuinfo is never localized. + */ +#include + +static int +png_have_neon(png_structp png_ptr) +{ + FILE *f = fopen("/proc/cpuinfo", "rb"); + + if (f != NULL) + { + /* This is a simple state machine which reads the input byte-by-byte until + * it gets a match on the 'neon' feature or reaches the end of the stream. + */ + static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 }; + static const char ch_neon[] = { 78, 69, 79, 78 }; + + enum + { + StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine + } state; + int counter; + + for (state=StartLine, counter=0;;) + { + int ch = fgetc(f); + + if (ch == EOF) + { + /* EOF means error or end-of-file, return false; neon at EOF is + * assumed to be a mistake. + */ + fclose(f); + return 0; + } + + switch (state) + { + case StartLine: + /* Match spaces at the start of line */ + if (ch <= 32) /* skip control characters and space */ + break; + + counter=0; + state = Feature; + /* FALL THROUGH */ + + case Feature: + /* Match 'FEATURE', ASCII case insensitive. */ + if ((ch & ~0x20) == ch_feature[counter]) + { + if (++counter == (sizeof ch_feature)) + state = Colon; + break; + } + + /* did not match 'feature' */ + state = SkipLine; + /* FALL THROUGH */ + + case SkipLine: + skipLine: + /* Skip everything until we see linefeed or carriage return */ + if (ch != 10 && ch != 13) + break; + + state = StartLine; + break; + + case Colon: + /* Match any number of space or tab followed by ':' */ + if (ch == 32 || ch == 9) + break; + + if (ch == 58) /* i.e. ':' */ + { + state = StartTag; + break; + } + + /* Either a bad line format or a 'feature' prefix followed by + * other characters. + */ + state = SkipLine; + goto skipLine; + + case StartTag: + /* Skip space characters before a tag */ + if (ch == 32 || ch == 9) + break; + + state = Neon; + counter = 0; + /* FALL THROUGH */ + + case Neon: + /* Look for 'neon' tag */ + if ((ch & ~0x20) == ch_neon[counter]) + { + if (++counter == (sizeof ch_neon)) + state = HaveNeon; + break; + } + + state = SkipTag; + /* FALL THROUGH */ + + case SkipTag: + /* Skip non-space characters */ + if (ch == 10 || ch == 13) + state = StartLine; + + else if (ch == 32 || ch == 9) + state = StartTag; + break; + + case HaveNeon: + /* Have seen a 'neon' prefix, but there must be a space or new + * line character to terminate it. + */ + if (ch == 10 || ch == 13 || ch == 32 || ch == 9) + { + fclose(f); + return 1; + } + + state = SkipTag; + break; + + default: + png_error(png_ptr, "png_have_neon: internal error (bug)"); + } + } + } + + else + png_warning(png_ptr, "/proc/cpuinfo open failed"); + + return 0; +} diff --git a/main/source/includes/lpng1610/contrib/examples/README.txt b/main/source/includes/lpng1610/contrib/examples/README.txt index 18e76824..0525c9d3 100644 --- a/main/source/includes/lpng1610/contrib/examples/README.txt +++ b/main/source/includes/lpng1610/contrib/examples/README.txt @@ -1,24 +1,24 @@ - -This directory (contrib/examples) contains examples of libpng usage. - -NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY. - -To the extent possible under law, the authors have waived all copyright and -related or neighboring rights to this work. This work is published from: -United States. - -The files may be used freely in any way. The intention is that appropriate -parts of the files be used in other libpng-using programs without any need for -the authors of the using code to seek copyright or license from the original -authors. - -The source code and comments in this directory are the original work of the -people named below. No other person or organization has made contributions to -the work in this directory. - -ORIGINAL AUTHORS - The following people have contributed to the code in this directory. None - of the people below claim any rights with regard to the contents of this - directory. - - John Bowler + +This directory (contrib/examples) contains examples of libpng usage. + +NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY. + +To the extent possible under law, the authors have waived all copyright and +related or neighboring rights to this work. This work is published from: +United States. + +The files may be used freely in any way. The intention is that appropriate +parts of the files be used in other libpng-using programs without any need for +the authors of the using code to seek copyright or license from the original +authors. + +The source code and comments in this directory are the original work of the +people named below. No other person or organization has made contributions to +the work in this directory. + +ORIGINAL AUTHORS + The following people have contributed to the code in this directory. None + of the people below claim any rights with regard to the contents of this + directory. + + John Bowler diff --git a/main/source/includes/lpng1610/contrib/examples/iccfrompng.c b/main/source/includes/lpng1610/contrib/examples/iccfrompng.c index ec04b3fe..386e522a 100644 --- a/main/source/includes/lpng1610/contrib/examples/iccfrompng.c +++ b/main/source/includes/lpng1610/contrib/examples/iccfrompng.c @@ -1,180 +1,180 @@ -/*- iccfrompng - * - * COPYRIGHT: Written by John Cunningham Bowler, 2011. - * To the extent possible under law, the author has waived all copyright and - * related or neighboring rights to this work. This work is published from: - * United States. - * - * Extract any icc profiles found in the given PNG files. This is a simple - * example of a program that extracts information from the header of a PNG file - * without processing the image. Notice that some header information may occur - * after the image data. Textual data and comments are an example; the approach - * in this file won't work reliably for such data because it only looks for the - * information in the section of the file that preceeds the image data. - * - * Compile and link against libpng and zlib, plus anything else required on the - * system you use. - * - * To use supply a list of PNG files containing iCCP chunks, the chunks will be - * extracted to a similarly named file with the extension replaced by 'icc', - * which will be overwritten without warning. - */ -#include -#include -#include -#include - -#include - -static int verbose = 1; -static png_byte no_profile[] = "no profile"; - -static png_bytep -extract(FILE *fp, png_uint_32 *proflen) -{ - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); - png_infop info_ptr = NULL; - png_bytep result = NULL; - - /* Initialize for error or no profile: */ - *proflen = 0; - - if (png_ptr == NULL) - { - fprintf(stderr, "iccfrompng: version library mismatch?\n"); - return 0; - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 0; - } - - png_init_io(png_ptr, fp); - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - png_error(png_ptr, "OOM allocating info structure"); - - png_read_info(png_ptr, info_ptr); - - { - png_charp name; - int compression_type; - png_bytep profile; - - if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile, - proflen) & PNG_INFO_iCCP) - { - result = malloc(*proflen); - if (result != NULL) - memcpy(result, profile, *proflen); - - else - png_error(png_ptr, "OOM allocating profile buffer"); - } - - else - result = no_profile; - } - - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return result; -} - -static int -extract_one_file(const char *filename) -{ - int result = 0; - FILE *fp = fopen(filename, "rb"); - - if (fp != NULL) - { - png_uint_32 proflen = 0; - png_bytep profile = extract(fp, &proflen); - - if (profile != NULL && profile != no_profile) - { - size_t len; - char *output; - - { - const char *ep = strrchr(filename, '.'); - - if (ep != NULL) - len = ep-filename; - - else - len = strlen(filename); - } - - output = malloc(len + 5); - if (output != NULL) - { - FILE *of; - - memcpy(output, filename, len); - strcpy(output+len, ".icc"); - - of = fopen(output, "wb"); - if (of != NULL) - { - if (fwrite(profile, proflen, 1, of) == 1 && - fflush(of) == 0 && - fclose(of) == 0) - { - if (verbose) - printf("%s -> %s\n", filename, output); - /* Success return */ - result = 1; - } - - else - { - fprintf(stderr, "%s: error writing profile\n", output); - if (remove(output)) - fprintf(stderr, "%s: could not remove file\n", output); - } - } - - else - fprintf(stderr, "%s: failed to open output file\n", output); - - free(output); - } - - else - fprintf(stderr, "%s: OOM allocating string!\n", filename); - - free(profile); - } - - else if (verbose && profile == no_profile) - printf("%s has no profile\n", filename); - } - - else - fprintf(stderr, "%s: could not open file\n", filename); - - return result; -} - -int -main(int argc, char **argv) -{ - int i; - int extracted = 0; - - for (i=1; i +#include +#include +#include + +#include + +static int verbose = 1; +static png_byte no_profile[] = "no profile"; + +static png_bytep +extract(FILE *fp, png_uint_32 *proflen) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + png_infop info_ptr = NULL; + png_bytep result = NULL; + + /* Initialize for error or no profile: */ + *proflen = 0; + + if (png_ptr == NULL) + { + fprintf(stderr, "iccfrompng: version library mismatch?\n"); + return 0; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 0; + } + + png_init_io(png_ptr, fp); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + png_read_info(png_ptr, info_ptr); + + { + png_charp name; + int compression_type; + png_bytep profile; + + if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile, + proflen) & PNG_INFO_iCCP) + { + result = malloc(*proflen); + if (result != NULL) + memcpy(result, profile, *proflen); + + else + png_error(png_ptr, "OOM allocating profile buffer"); + } + + else + result = no_profile; + } + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return result; +} + +static int +extract_one_file(const char *filename) +{ + int result = 0; + FILE *fp = fopen(filename, "rb"); + + if (fp != NULL) + { + png_uint_32 proflen = 0; + png_bytep profile = extract(fp, &proflen); + + if (profile != NULL && profile != no_profile) + { + size_t len; + char *output; + + { + const char *ep = strrchr(filename, '.'); + + if (ep != NULL) + len = ep-filename; + + else + len = strlen(filename); + } + + output = malloc(len + 5); + if (output != NULL) + { + FILE *of; + + memcpy(output, filename, len); + strcpy(output+len, ".icc"); + + of = fopen(output, "wb"); + if (of != NULL) + { + if (fwrite(profile, proflen, 1, of) == 1 && + fflush(of) == 0 && + fclose(of) == 0) + { + if (verbose) + printf("%s -> %s\n", filename, output); + /* Success return */ + result = 1; + } + + else + { + fprintf(stderr, "%s: error writing profile\n", output); + if (remove(output)) + fprintf(stderr, "%s: could not remove file\n", output); + } + } + + else + fprintf(stderr, "%s: failed to open output file\n", output); + + free(output); + } + + else + fprintf(stderr, "%s: OOM allocating string!\n", filename); + + free(profile); + } + + else if (verbose && profile == no_profile) + printf("%s has no profile\n", filename); + } + + else + fprintf(stderr, "%s: could not open file\n", filename); + + return result; +} + +int +main(int argc, char **argv) +{ + int i; + int extracted = 0; + + for (i=1; i -#include -#include /* required for error handling */ - -/* Normally use here to get the installed libpng, but this is done to - * ensure the code picks up the local libpng implementation: - */ -#include "../../png.h" - -/* Return component 'c' of pixel 'x' from the given row. */ -static unsigned int -component(png_const_bytep row, png_uint_32 x, unsigned int c, - unsigned int bit_depth, unsigned int channels) -{ - /* PNG images can be up to 2^31 pixels wide, but this means they can be up to - * 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence 2^34 - * bytes wide. Since the row fitted into memory, however, the following must - * work: - */ - png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels); - png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c); - - row = (png_const_bytep)(((PNG_CONST png_byte (*)[8])row) + bit_offset_hi); - row += bit_offset_lo >> 3; - bit_offset_lo &= 0x07; - - /* PNG pixels are packed into bytes to put the first pixel in the highest - * bits of the byte and into two bytes for 16-bit values with the high 8 bits - * first, so: - */ - switch (bit_depth) - { - case 1: return (row[0] >> (7-bit_offset_lo)) & 0x01; - case 2: return (row[0] >> (6-bit_offset_lo)) & 0x03; - case 4: return (row[0] >> (4-bit_offset_lo)) & 0x0f; - case 8: return row[0]; - case 16: return (row[0] << 8) + row[1]; - default: - /* This should never happen; it indicates a bug in this program or in - * libpng itself: - */ - fprintf(stderr, "pngpixel: invalid bit depth %u\n", bit_depth); - exit(1); - } -} - -/* Print a pixel from a row returned by libpng; determine the row format, find - * the pixel, and print the relevant information to stdout. - */ -static void -print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row, - png_uint_32 x) -{ - PNG_CONST unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr); - - switch (png_get_color_type(png_ptr, info_ptr)) - { - case PNG_COLOR_TYPE_GRAY: - printf("GRAY %u\n", component(row, x, 0, bit_depth, 1)); - return; - - /* The palette case is slightly more difficult - the palette and, if - * present, the tRNS ('transparency', though the values are really - * opacity) data must be read to give the full picture: - */ - case PNG_COLOR_TYPE_PALETTE: - { - PNG_CONST unsigned int index = component(row, x, 0, bit_depth, 1); - png_colorp palette = NULL; - int num_palette = 0; - - if ((png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) & - PNG_INFO_PLTE) && num_palette > 0 && palette != NULL) - { - png_bytep trans_alpha = NULL; - int num_trans = 0; - if ((png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, - NULL) & PNG_INFO_tRNS) && num_trans > 0 && - trans_alpha != NULL) - printf("INDEXED %u = %d %d %d %d\n", index, - palette[index].red, palette[index].green, - palette[index].blue, - index < num_trans ? trans_alpha[index] : 255); - - else /* no transparency */ - printf("INDEXED %u = %d %d %d\n", index, - palette[index].red, palette[index].green, - palette[index].blue); - } - - else - printf("INDEXED %u = invalid index\n", index); - } - return; - - case PNG_COLOR_TYPE_RGB: - printf("RGB %u %u %u\n", component(row, x, 0, bit_depth, 3), - component(row, x, 1, bit_depth, 3), - component(row, x, 2, bit_depth, 3)); - return; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - printf("GRAY+ALPHA %u %u\n", component(row, x, 0, bit_depth, 2), - component(row, x, 1, bit_depth, 2)); - return; - - case PNG_COLOR_TYPE_RGB_ALPHA: - printf("RGBA %u %u %u %u\n", component(row, x, 0, bit_depth, 4), - component(row, x, 1, bit_depth, 4), - component(row, x, 2, bit_depth, 4), - component(row, x, 3, bit_depth, 4)); - return; - - default: - png_error(png_ptr, "pngpixel: invalid color type"); - } -} - -int main(int argc, const char **argv) -{ - /* This program uses the default, based, libpng error handling - * mechanism, therefore any local variable that exists before the call to - * setjmp and is changed after the call to setjmp returns successfully must - * be declared with 'volatile' to ensure that their values don't get - * destroyed by longjmp: - */ - volatile int result = 1/*fail*/; - - if (argc == 4) - { - long x = atol(argv[1]); - long y = atol(argv[2]); - FILE *f = fopen(argv[3], "rb"); - volatile png_bytep row = NULL; - - if (f != NULL) - { - /* libpng requires a callback function for handling errors; this - * callback must not return. The default callback function uses a - * stored style jmp_buf which is held in a png_struct and - * writes error messages to stderr. Creating the png_struct is a - * little tricky; just copy the following code. - */ - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); - - if (png_ptr != NULL) - { - png_infop info_ptr = png_create_info_struct(png_ptr); - - if (info_ptr != NULL) - { - /* Declare stack variables to hold pointers to locally allocated - * data. - */ - - /* Initialize the error control buffer: */ - if (setjmp(png_jmpbuf(png_ptr)) == 0) - { - png_uint_32 width, height; - int bit_depth, color_type, interlace_method, - compression_method, filter_method; - png_bytep row_tmp; - - /* Now associate the recently opened (FILE*) with the default - * libpng initialization functions. Sometimes libpng is - * compiled without stdio support (it can be difficult to do - * in some environments); in that case you will have to write - * your own read callback to read data from the (FILE*). - */ - png_init_io(png_ptr, f); - - /* And read the first part of the PNG file - the header and - * all the information up to the first pixel. - */ - png_read_info(png_ptr, info_ptr); - - /* This fills in enough information to tell us the width of - * each row in bytes, allocate the appropriate amount of - * space. In this case png_malloc is used - it will not - * return if memory isn't available. - */ - row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, - info_ptr)); - - /* To avoid the overhead of using a volatile auto copy row_tmp - * to a local here - just use row for the png_free below. - */ - row_tmp = row; - - /* All the information we need is in the header is returned by - * png_get_IHDR, if this fails we can now use 'png_error' to - * signal the error and return control to the setjmp above. - */ - if (png_get_IHDR(png_ptr, info_ptr, &width, &height, - &bit_depth, &color_type, &interlace_method, - &compression_method, &filter_method)) - { - int passes, pass; - - /* png_set_interlace_handling returns the number of - * passes required as well as turning on libpng's - * handling, but since we do it ourselves this is - * necessary: - */ - switch (interlace_method) - { - case PNG_INTERLACE_NONE: - passes = 1; - break; - - case PNG_INTERLACE_ADAM7: - passes = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - png_error(png_ptr, "pngpixel: unknown interlace"); - } - - /* Now read the pixels, pass-by-pass, row-by-row: */ - png_start_read_image(png_ptr); - - for (pass=0; pass +#include +#include /* required for error handling */ + +/* Normally use here to get the installed libpng, but this is done to + * ensure the code picks up the local libpng implementation: + */ +#include "../../png.h" + +/* Return component 'c' of pixel 'x' from the given row. */ +static unsigned int +component(png_const_bytep row, png_uint_32 x, unsigned int c, + unsigned int bit_depth, unsigned int channels) +{ + /* PNG images can be up to 2^31 pixels wide, but this means they can be up to + * 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence 2^34 + * bytes wide. Since the row fitted into memory, however, the following must + * work: + */ + png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels); + png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c); + + row = (png_const_bytep)(((PNG_CONST png_byte (*)[8])row) + bit_offset_hi); + row += bit_offset_lo >> 3; + bit_offset_lo &= 0x07; + + /* PNG pixels are packed into bytes to put the first pixel in the highest + * bits of the byte and into two bytes for 16-bit values with the high 8 bits + * first, so: + */ + switch (bit_depth) + { + case 1: return (row[0] >> (7-bit_offset_lo)) & 0x01; + case 2: return (row[0] >> (6-bit_offset_lo)) & 0x03; + case 4: return (row[0] >> (4-bit_offset_lo)) & 0x0f; + case 8: return row[0]; + case 16: return (row[0] << 8) + row[1]; + default: + /* This should never happen; it indicates a bug in this program or in + * libpng itself: + */ + fprintf(stderr, "pngpixel: invalid bit depth %u\n", bit_depth); + exit(1); + } +} + +/* Print a pixel from a row returned by libpng; determine the row format, find + * the pixel, and print the relevant information to stdout. + */ +static void +print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row, + png_uint_32 x) +{ + PNG_CONST unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + + switch (png_get_color_type(png_ptr, info_ptr)) + { + case PNG_COLOR_TYPE_GRAY: + printf("GRAY %u\n", component(row, x, 0, bit_depth, 1)); + return; + + /* The palette case is slightly more difficult - the palette and, if + * present, the tRNS ('transparency', though the values are really + * opacity) data must be read to give the full picture: + */ + case PNG_COLOR_TYPE_PALETTE: + { + PNG_CONST unsigned int index = component(row, x, 0, bit_depth, 1); + png_colorp palette = NULL; + int num_palette = 0; + + if ((png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) & + PNG_INFO_PLTE) && num_palette > 0 && palette != NULL) + { + png_bytep trans_alpha = NULL; + int num_trans = 0; + if ((png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, + NULL) & PNG_INFO_tRNS) && num_trans > 0 && + trans_alpha != NULL) + printf("INDEXED %u = %d %d %d %d\n", index, + palette[index].red, palette[index].green, + palette[index].blue, + index < num_trans ? trans_alpha[index] : 255); + + else /* no transparency */ + printf("INDEXED %u = %d %d %d\n", index, + palette[index].red, palette[index].green, + palette[index].blue); + } + + else + printf("INDEXED %u = invalid index\n", index); + } + return; + + case PNG_COLOR_TYPE_RGB: + printf("RGB %u %u %u\n", component(row, x, 0, bit_depth, 3), + component(row, x, 1, bit_depth, 3), + component(row, x, 2, bit_depth, 3)); + return; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + printf("GRAY+ALPHA %u %u\n", component(row, x, 0, bit_depth, 2), + component(row, x, 1, bit_depth, 2)); + return; + + case PNG_COLOR_TYPE_RGB_ALPHA: + printf("RGBA %u %u %u %u\n", component(row, x, 0, bit_depth, 4), + component(row, x, 1, bit_depth, 4), + component(row, x, 2, bit_depth, 4), + component(row, x, 3, bit_depth, 4)); + return; + + default: + png_error(png_ptr, "pngpixel: invalid color type"); + } +} + +int main(int argc, const char **argv) +{ + /* This program uses the default, based, libpng error handling + * mechanism, therefore any local variable that exists before the call to + * setjmp and is changed after the call to setjmp returns successfully must + * be declared with 'volatile' to ensure that their values don't get + * destroyed by longjmp: + */ + volatile int result = 1/*fail*/; + + if (argc == 4) + { + long x = atol(argv[1]); + long y = atol(argv[2]); + FILE *f = fopen(argv[3], "rb"); + volatile png_bytep row = NULL; + + if (f != NULL) + { + /* libpng requires a callback function for handling errors; this + * callback must not return. The default callback function uses a + * stored style jmp_buf which is held in a png_struct and + * writes error messages to stderr. Creating the png_struct is a + * little tricky; just copy the following code. + */ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + /* Declare stack variables to hold pointers to locally allocated + * data. + */ + + /* Initialize the error control buffer: */ + if (setjmp(png_jmpbuf(png_ptr)) == 0) + { + png_uint_32 width, height; + int bit_depth, color_type, interlace_method, + compression_method, filter_method; + png_bytep row_tmp; + + /* Now associate the recently opened (FILE*) with the default + * libpng initialization functions. Sometimes libpng is + * compiled without stdio support (it can be difficult to do + * in some environments); in that case you will have to write + * your own read callback to read data from the (FILE*). + */ + png_init_io(png_ptr, f); + + /* And read the first part of the PNG file - the header and + * all the information up to the first pixel. + */ + png_read_info(png_ptr, info_ptr); + + /* This fills in enough information to tell us the width of + * each row in bytes, allocate the appropriate amount of + * space. In this case png_malloc is used - it will not + * return if memory isn't available. + */ + row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + + /* To avoid the overhead of using a volatile auto copy row_tmp + * to a local here - just use row for the png_free below. + */ + row_tmp = row; + + /* All the information we need is in the header is returned by + * png_get_IHDR, if this fails we can now use 'png_error' to + * signal the error and return control to the setjmp above. + */ + if (png_get_IHDR(png_ptr, info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_method, + &compression_method, &filter_method)) + { + int passes, pass; + + /* png_set_interlace_handling returns the number of + * passes required as well as turning on libpng's + * handling, but since we do it ourselves this is + * necessary: + */ + switch (interlace_method) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "pngpixel: unknown interlace"); + } + + /* Now read the pixels, pass-by-pass, row-by-row: */ + png_start_read_image(png_ptr); + + for (pass=0; pass -#include -#include -#include - -/* Normally use here to get the installed libpng, but this is done to - * ensure the code picks up the local libpng implementation: - */ -#include "../../png.h" - -int main(int argc, const char **argv) -{ - int result = 1; - - if (argc == 3) - { - png_image image; - - /* Only the image structure version number needs to be set. */ - memset(&image, 0, sizeof image); - image.version = PNG_IMAGE_VERSION; - - if (png_image_begin_read_from_file(&image, argv[1])) - { - png_bytep buffer; - - /* Change this to try different formats! If you set a colormap format - * then you must also supply a colormap below. - */ - image.format = PNG_FORMAT_RGBA; - - buffer = malloc(PNG_IMAGE_SIZE(image)); - - if (buffer != NULL) - { - if (png_image_finish_read(&image, NULL/*background*/, buffer, - 0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */)) - { - if (png_image_write_to_file(&image, argv[2], - 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, - NULL/*colormap*/)) - result = 0; - - else - fprintf(stderr, "pngtopng: write %s: %s\n", argv[2], - image.message); - - free(buffer); - } - - else - { - fprintf(stderr, "pngtopng: read %s: %s\n", argv[1], - image.message); - - /* This is the only place where a 'free' is required; libpng does - * the cleanup on error and success, but in this case we couldn't - * complete the read because of running out of memory. - */ - png_image_free(&image); - } - } - - else - fprintf(stderr, "pngtopng: out of memory: %lu bytes\n", - (unsigned long)PNG_IMAGE_SIZE(image)); - } - - else - /* Failed to read the first argument: */ - fprintf(stderr, "pngtopng: %s: %s\n", argv[1], image.message); - } - - else - /* Wrong number of arguments */ - fprintf(stderr, "pngtopng: usage: pngtopng input-file output-file\n"); - - return result; -} +/*- pngtopng + * + * COPYRIGHT: Written by John Cunningham Bowler, 2011. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Read a PNG and write it out in a fixed format, using the 'simplified API' + * that was introduced in libpng-1.6.0. + * + * This sample code is just the code from the top of 'example.c' with some error + * handling added. See example.c for more comments. + */ +#include +#include +#include +#include + +/* Normally use here to get the installed libpng, but this is done to + * ensure the code picks up the local libpng implementation: + */ +#include "../../png.h" + +int main(int argc, const char **argv) +{ + int result = 1; + + if (argc == 3) + { + png_image image; + + /* Only the image structure version number needs to be set. */ + memset(&image, 0, sizeof image); + image.version = PNG_IMAGE_VERSION; + + if (png_image_begin_read_from_file(&image, argv[1])) + { + png_bytep buffer; + + /* Change this to try different formats! If you set a colormap format + * then you must also supply a colormap below. + */ + image.format = PNG_FORMAT_RGBA; + + buffer = malloc(PNG_IMAGE_SIZE(image)); + + if (buffer != NULL) + { + if (png_image_finish_read(&image, NULL/*background*/, buffer, + 0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */)) + { + if (png_image_write_to_file(&image, argv[2], + 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, + NULL/*colormap*/)) + result = 0; + + else + fprintf(stderr, "pngtopng: write %s: %s\n", argv[2], + image.message); + + free(buffer); + } + + else + { + fprintf(stderr, "pngtopng: read %s: %s\n", argv[1], + image.message); + + /* This is the only place where a 'free' is required; libpng does + * the cleanup on error and success, but in this case we couldn't + * complete the read because of running out of memory. + */ + png_image_free(&image); + } + } + + else + fprintf(stderr, "pngtopng: out of memory: %lu bytes\n", + (unsigned long)PNG_IMAGE_SIZE(image)); + } + + else + /* Failed to read the first argument: */ + fprintf(stderr, "pngtopng: %s: %s\n", argv[1], image.message); + } + + else + /* Wrong number of arguments */ + fprintf(stderr, "pngtopng: usage: pngtopng input-file output-file\n"); + + return result; +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/COPYING b/main/source/includes/lpng1610/contrib/gregbook/COPYING index c2d382b9..a3e97747 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/COPYING +++ b/main/source/includes/lpng1610/contrib/gregbook/COPYING @@ -1,340 +1,340 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/main/source/includes/lpng1610/contrib/gregbook/LICENSE b/main/source/includes/lpng1610/contrib/gregbook/LICENSE index 40a0c8ec..d9567178 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/LICENSE +++ b/main/source/includes/lpng1610/contrib/gregbook/LICENSE @@ -1,50 +1,50 @@ - --------------------------------------------------------------------------- - - Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - --------------------------------------------------------------------------- + --------------------------------------------------------------------------- + + Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + --------------------------------------------------------------------------- diff --git a/main/source/includes/lpng1610/contrib/gregbook/Makefile.mingw32 b/main/source/includes/lpng1610/contrib/gregbook/Makefile.mingw32 index f833e9bb..3a3ff607 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/Makefile.mingw32 +++ b/main/source/includes/lpng1610/contrib/gregbook/Makefile.mingw32 @@ -1,131 +1,131 @@ -# Sample makefile for rpng-win / rpng2-win / wpng using mingw32-gcc and make. -# Greg Roelofs -# Last modified: 2 June 2007 -# -# The programs built by this makefile are described in the book, -# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and -# Associates, 1999). Go buy a copy, eh? Well, OK, it's not -# generally for sale anymore, but it's the thought that counts, -# right? (Hint: http://www.libpng.org/pub/png/book/ ) -# -# Invoke this makefile from a DOS-prompt window via: -# -# make -f Makefile.mingw32 -# -# This makefile assumes libpng and zlib have already been built or downloaded -# and are in subdirectories at the same level as the current subdirectory -# (as indicated by the PNGDIR and ZDIR macros below). It makes no assumptions -# at all about the mingw32 installation tree (W32DIR). Edit as appropriate. -# -# Note that the names of the dynamic and static libpng and zlib libraries -# used below may change in later releases of the libraries. This makefile -# builds both statically and dynamically linked executables by default. -# (You need only one set, but for testing it can be handy to have both.) - - -# macros -------------------------------------------------------------------- - -#PNGDIR = ../..# for libpng-x.y.z/contrib/gregbook builds -PNGDIR = ../libpng-win32 -PNGINC = -I$(PNGDIR) -PNGLIBd = $(PNGDIR)/libpng.dll.a # dynamically linked -PNGLIBs = $(PNGDIR)/libpng.a # statically linked, local libpng - -#ZDIR = ../../../zlib-win32# for libpng-x.y.z/contrib/gregbook builds -ZDIR = ../zlib-win32 -ZINC = -I$(ZDIR) -ZLIBd = $(ZDIR)/libzdll.a -ZLIBs = $(ZDIR)/libz.a - -# change this to be the path where mingw32 installs its stuff: -W32DIR = -#W32DIR = /usr/local/cross-tools/i386-mingw32msvc -W32INC = -I$(W32DIR)/include -W32LIB = $(W32DIR)/lib/libuser32.a $(W32DIR)/lib/libgdi32.a - -CC = gcc -#CC = i386-mingw32msvc-gcc # e.g., Linux -> Win32 cross-compilation -LD = $(CC) -RM = rm -f -CPPFLAGS = $(INCS) -CFLAGS = -O -Wall $(MINGW_CCFLAGS) -# [note that -Wall is a gcc-specific compilation flag ("most warnings on")] -# [-ansi, -pedantic and -W can also be used] -LDFLAGS = $(MINGW_LDFLAGS) -O = .o -E = .exe - -INCS = $(PNGINC) $(ZINC) $(W32INC) -RLIBSd = $(PNGLIBd) $(ZLIBd) $(W32LIB) -lm -RLIBSs = $(PNGLIBs) $(ZLIBs) $(W32LIB) -lm -WLIBSd = $(PNGLIBd) $(ZLIBd) -WLIBSs = $(PNGLIBs) $(ZLIBs) - -RPNG = rpng-win -RPNG2 = rpng2-win -WPNG = wpng - -ROBJSd = $(RPNG)$(O) readpng.pic$(O) -ROBJS2d = $(RPNG2)$(O) readpng2.pic$(O) -WOBJSd = $(WPNG)$(O) writepng.pic$(O) - -RPNGs = $(RPNG)-static -RPNG2s = $(RPNG2)-static -WPNGs = $(WPNG)-static - -ROBJSs = $(RPNG)$(O) readpng$(O) -ROBJS2s = $(RPNG2)$(O) readpng2$(O) -WOBJSs = $(WPNG)$(O) writepng$(O) - -STATIC_EXES = $(RPNGs)$(E) $(RPNG2s)$(E) $(WPNGs)$(E) -DYNAMIC_EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) - -EXES = $(STATIC_EXES) $(DYNAMIC_EXES) - - -# implicit make rules ------------------------------------------------------- - -.c$(O): - $(CC) -c $(CPPFLAGS) $(CFLAGS) $< - -%.pic$(O): %.c - $(CC) -c $(CPPFLAGS) $(CFLAGS) -DPNG_BUILD_DLL -o $@ $< - - -# dependencies -------------------------------------------------------------- - -all: $(EXES) - -$(RPNGs)$(E): $(ROBJSs) - $(LD) $(LDFLAGS) -o $@ $(ROBJSs) $(RLIBSs) - -$(RPNG)$(E): $(ROBJSd) - $(LD) $(LDFLAGS) -o $@ $(ROBJSd) $(RLIBSd) - -$(RPNG2s)$(E): $(ROBJS2s) - $(LD) $(LDFLAGS) -o $@ $(ROBJS2s) $(RLIBSs) - -$(RPNG2)$(E): $(ROBJS2d) - $(LD) $(LDFLAGS) -o $@ $(ROBJS2d) $(RLIBSd) - -$(WPNGs)$(E): $(WOBJSs) - $(LD) $(LDFLAGS) -o $@ $(WOBJSs) $(WLIBSs) - -$(WPNG)$(E): $(WOBJSd) - $(LD) $(LDFLAGS) -o $@ $(WOBJSd) $(WLIBSd) - -$(RPNG)$(O): $(RPNG).c readpng.h -$(RPNG2)$(O): $(RPNG2).c readpng2.h -$(WPNG)$(O): $(WPNG).c writepng.h - -readpng$(O) readpng.pic$(O): readpng.c readpng.h -readpng2$(O) readpng2.pic$(O): readpng2.c readpng2.h -writepng$(O) writepng.pic$(O): writepng.c writepng.h - - -# maintenance --------------------------------------------------------------- - -clean: - $(RM) $(EXES) - $(RM) $(ROBJSs) $(ROBJS2s) $(WOBJSs) - $(RM) $(ROBJSd) $(ROBJS2d) $(WOBJSd) +# Sample makefile for rpng-win / rpng2-win / wpng using mingw32-gcc and make. +# Greg Roelofs +# Last modified: 2 June 2007 +# +# The programs built by this makefile are described in the book, +# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and +# Associates, 1999). Go buy a copy, eh? Well, OK, it's not +# generally for sale anymore, but it's the thought that counts, +# right? (Hint: http://www.libpng.org/pub/png/book/ ) +# +# Invoke this makefile from a DOS-prompt window via: +# +# make -f Makefile.mingw32 +# +# This makefile assumes libpng and zlib have already been built or downloaded +# and are in subdirectories at the same level as the current subdirectory +# (as indicated by the PNGDIR and ZDIR macros below). It makes no assumptions +# at all about the mingw32 installation tree (W32DIR). Edit as appropriate. +# +# Note that the names of the dynamic and static libpng and zlib libraries +# used below may change in later releases of the libraries. This makefile +# builds both statically and dynamically linked executables by default. +# (You need only one set, but for testing it can be handy to have both.) + + +# macros -------------------------------------------------------------------- + +#PNGDIR = ../..# for libpng-x.y.z/contrib/gregbook builds +PNGDIR = ../libpng-win32 +PNGINC = -I$(PNGDIR) +PNGLIBd = $(PNGDIR)/libpng.dll.a # dynamically linked +PNGLIBs = $(PNGDIR)/libpng.a # statically linked, local libpng + +#ZDIR = ../../../zlib-win32# for libpng-x.y.z/contrib/gregbook builds +ZDIR = ../zlib-win32 +ZINC = -I$(ZDIR) +ZLIBd = $(ZDIR)/libzdll.a +ZLIBs = $(ZDIR)/libz.a + +# change this to be the path where mingw32 installs its stuff: +W32DIR = +#W32DIR = /usr/local/cross-tools/i386-mingw32msvc +W32INC = -I$(W32DIR)/include +W32LIB = $(W32DIR)/lib/libuser32.a $(W32DIR)/lib/libgdi32.a + +CC = gcc +#CC = i386-mingw32msvc-gcc # e.g., Linux -> Win32 cross-compilation +LD = $(CC) +RM = rm -f +CPPFLAGS = $(INCS) +CFLAGS = -O -Wall $(MINGW_CCFLAGS) +# [note that -Wall is a gcc-specific compilation flag ("most warnings on")] +# [-ansi, -pedantic and -W can also be used] +LDFLAGS = $(MINGW_LDFLAGS) +O = .o +E = .exe + +INCS = $(PNGINC) $(ZINC) $(W32INC) +RLIBSd = $(PNGLIBd) $(ZLIBd) $(W32LIB) -lm +RLIBSs = $(PNGLIBs) $(ZLIBs) $(W32LIB) -lm +WLIBSd = $(PNGLIBd) $(ZLIBd) +WLIBSs = $(PNGLIBs) $(ZLIBs) + +RPNG = rpng-win +RPNG2 = rpng2-win +WPNG = wpng + +ROBJSd = $(RPNG)$(O) readpng.pic$(O) +ROBJS2d = $(RPNG2)$(O) readpng2.pic$(O) +WOBJSd = $(WPNG)$(O) writepng.pic$(O) + +RPNGs = $(RPNG)-static +RPNG2s = $(RPNG2)-static +WPNGs = $(WPNG)-static + +ROBJSs = $(RPNG)$(O) readpng$(O) +ROBJS2s = $(RPNG2)$(O) readpng2$(O) +WOBJSs = $(WPNG)$(O) writepng$(O) + +STATIC_EXES = $(RPNGs)$(E) $(RPNG2s)$(E) $(WPNGs)$(E) +DYNAMIC_EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) + +EXES = $(STATIC_EXES) $(DYNAMIC_EXES) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< + +%.pic$(O): %.c + $(CC) -c $(CPPFLAGS) $(CFLAGS) -DPNG_BUILD_DLL -o $@ $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + +$(RPNGs)$(E): $(ROBJSs) + $(LD) $(LDFLAGS) -o $@ $(ROBJSs) $(RLIBSs) + +$(RPNG)$(E): $(ROBJSd) + $(LD) $(LDFLAGS) -o $@ $(ROBJSd) $(RLIBSd) + +$(RPNG2s)$(E): $(ROBJS2s) + $(LD) $(LDFLAGS) -o $@ $(ROBJS2s) $(RLIBSs) + +$(RPNG2)$(E): $(ROBJS2d) + $(LD) $(LDFLAGS) -o $@ $(ROBJS2d) $(RLIBSd) + +$(WPNGs)$(E): $(WOBJSs) + $(LD) $(LDFLAGS) -o $@ $(WOBJSs) $(WLIBSs) + +$(WPNG)$(E): $(WOBJSd) + $(LD) $(LDFLAGS) -o $@ $(WOBJSd) $(WLIBSd) + +$(RPNG)$(O): $(RPNG).c readpng.h +$(RPNG2)$(O): $(RPNG2).c readpng2.h +$(WPNG)$(O): $(WPNG).c writepng.h + +readpng$(O) readpng.pic$(O): readpng.c readpng.h +readpng2$(O) readpng2.pic$(O): readpng2.c readpng2.h +writepng$(O) writepng.pic$(O): writepng.c writepng.h + + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) + $(RM) $(ROBJSs) $(ROBJS2s) $(WOBJSs) + $(RM) $(ROBJSd) $(ROBJS2d) $(WOBJSd) diff --git a/main/source/includes/lpng1610/contrib/gregbook/Makefile.sgi b/main/source/includes/lpng1610/contrib/gregbook/Makefile.sgi index c78adf70..94d61b46 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/Makefile.sgi +++ b/main/source/includes/lpng1610/contrib/gregbook/Makefile.sgi @@ -1,105 +1,105 @@ -# Sample makefile for rpng-x / rpng2-x / wpng for SGI using cc and make. -# Greg Roelofs -# Last modified: 7 March 2002 -# -# The programs built by this makefile are described in the book, -# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and -# Associates, 1999). Go buy a copy, eh? Buy some for friends -# and family, too. (Not that this is a blatant plug or anything.) -# -# Invoke this makefile from a shell prompt in the usual way; for example: -# -# make -f Makefile.sgi -# -# This makefile assumes libpng and zlib have already been built or downloaded -# and are both installed in /usr/local/{include,lib} (as indicated by the -# PNG* and Z* macros below). Edit as appropriate--choose only ONE each of -# the PNGINC, PNGLIB, ZINC and ZLIB lines. -# -# This makefile builds dynamically linked executables (against libpng and zlib, -# that is), but that can be changed by uncommenting the appropriate PNGLIB and -# ZLIB lines. - - -# macros -------------------------------------------------------------------- - -PNGINC = -I/usr/local/include/libpng16 -PNGLIB = -L/usr/local/lib -lpng16 # dynamically linked against libpng -#PNGLIB = /usr/local/lib/libpng16.a # statically linked against libpng -# or: -#PNGINC = -I../.. -#PNGLIB = -L../.. -lpng -#PNGLIB = ../../libpng.a - -ZINC = -I/usr/local/include -ZLIB = -L/usr/local/lib -lz # dynamically linked against zlib -#ZLIB = /usr/local/lib/libz.a # statically linked against zlib -#ZINC = -I../zlib -#ZLIB = -L../zlib -lz -#ZLIB = ../../../zlib/libz.a - -XINC = -I/usr/include/X11 # old-style, stock X distributions -XLIB = -L/usr/lib/X11 -lX11 -#XINC = -I/usr/openwin/include # Sun workstations (OpenWindows) -#XLIB = -L/usr/openwin/lib -lX11 -#XINC = -I/usr/X11R6/include # new X distributions (XFree86, etc.) -#XLIB = -L/usr/X11R6/lib -lX11 - -INCS = $(PNGINC) $(ZINC) $(XINC) -RLIBS = $(PNGLIB) $(ZLIB) $(XLIB) -lm -WLIBS = $(PNGLIB) $(ZLIB) - -CC = cc -LD = cc -RM = rm -f -# ABI must be the same as that used to build libpng. -ABI = -CPPFLAGS = -CFLAGS = $(ABI) -O -fullwarn $(INCS) -LDFLAGS = $(ABI) -O = .o -E = - -RPNG = rpng-x -RPNG2 = rpng2-x -WPNG = wpng - -ROBJS = $(RPNG)$(O) readpng$(O) -ROBJS2 = $(RPNG2)$(O) readpng2$(O) -WOBJS = $(WPNG)$(O) writepng$(O) - -EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) - - -# implicit make rules ------------------------------------------------------- - -.c$(O): - $(CC) -c $(CPPFLAGS) $(CFLAGS) $< - - -# dependencies -------------------------------------------------------------- - -all: $(EXES) - -$(RPNG)$(E): $(ROBJS) - $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBS) - -$(RPNG2)$(E): $(ROBJS2) - $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBS) - -$(WPNG)$(E): $(WOBJS) - $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBS) - -$(RPNG)$(O): $(RPNG).c readpng.h -$(RPNG2)$(O): $(RPNG2).c readpng2.h -$(WPNG)$(O): $(WPNG).c writepng.h - -readpng$(O): readpng.c readpng.h -readpng2$(O): readpng2.c readpng2.h -writepng$(O): writepng.c writepng.h - - -# maintenance --------------------------------------------------------------- - -clean: - $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS) +# Sample makefile for rpng-x / rpng2-x / wpng for SGI using cc and make. +# Greg Roelofs +# Last modified: 7 March 2002 +# +# The programs built by this makefile are described in the book, +# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and +# Associates, 1999). Go buy a copy, eh? Buy some for friends +# and family, too. (Not that this is a blatant plug or anything.) +# +# Invoke this makefile from a shell prompt in the usual way; for example: +# +# make -f Makefile.sgi +# +# This makefile assumes libpng and zlib have already been built or downloaded +# and are both installed in /usr/local/{include,lib} (as indicated by the +# PNG* and Z* macros below). Edit as appropriate--choose only ONE each of +# the PNGINC, PNGLIB, ZINC and ZLIB lines. +# +# This makefile builds dynamically linked executables (against libpng and zlib, +# that is), but that can be changed by uncommenting the appropriate PNGLIB and +# ZLIB lines. + + +# macros -------------------------------------------------------------------- + +PNGINC = -I/usr/local/include/libpng16 +PNGLIB = -L/usr/local/lib -lpng16 # dynamically linked against libpng +#PNGLIB = /usr/local/lib/libpng16.a # statically linked against libpng +# or: +#PNGINC = -I../.. +#PNGLIB = -L../.. -lpng +#PNGLIB = ../../libpng.a + +ZINC = -I/usr/local/include +ZLIB = -L/usr/local/lib -lz # dynamically linked against zlib +#ZLIB = /usr/local/lib/libz.a # statically linked against zlib +#ZINC = -I../zlib +#ZLIB = -L../zlib -lz +#ZLIB = ../../../zlib/libz.a + +XINC = -I/usr/include/X11 # old-style, stock X distributions +XLIB = -L/usr/lib/X11 -lX11 +#XINC = -I/usr/openwin/include # Sun workstations (OpenWindows) +#XLIB = -L/usr/openwin/lib -lX11 +#XINC = -I/usr/X11R6/include # new X distributions (XFree86, etc.) +#XLIB = -L/usr/X11R6/lib -lX11 + +INCS = $(PNGINC) $(ZINC) $(XINC) +RLIBS = $(PNGLIB) $(ZLIB) $(XLIB) -lm +WLIBS = $(PNGLIB) $(ZLIB) + +CC = cc +LD = cc +RM = rm -f +# ABI must be the same as that used to build libpng. +ABI = +CPPFLAGS = +CFLAGS = $(ABI) -O -fullwarn $(INCS) +LDFLAGS = $(ABI) +O = .o +E = + +RPNG = rpng-x +RPNG2 = rpng2-x +WPNG = wpng + +ROBJS = $(RPNG)$(O) readpng$(O) +ROBJS2 = $(RPNG2)$(O) readpng2$(O) +WOBJS = $(WPNG)$(O) writepng$(O) + +EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + +$(RPNG)$(E): $(ROBJS) + $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBS) + +$(RPNG2)$(E): $(ROBJS2) + $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBS) + +$(WPNG)$(E): $(WOBJS) + $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBS) + +$(RPNG)$(O): $(RPNG).c readpng.h +$(RPNG2)$(O): $(RPNG2).c readpng2.h +$(WPNG)$(O): $(WPNG).c writepng.h + +readpng$(O): readpng.c readpng.h +readpng2$(O): readpng2.c readpng2.h +writepng$(O): writepng.c writepng.h + + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS) diff --git a/main/source/includes/lpng1610/contrib/gregbook/Makefile.unx b/main/source/includes/lpng1610/contrib/gregbook/Makefile.unx index 2d899d8c..c8cadf87 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/Makefile.unx +++ b/main/source/includes/lpng1610/contrib/gregbook/Makefile.unx @@ -1,133 +1,133 @@ -# Sample makefile for rpng-x / rpng2-x / wpng using gcc and make. -# Greg Roelofs -# Last modified: 2 June 2007 -# -# The programs built by this makefile are described in the book, -# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and -# Associates, 1999). Go buy a copy, eh? Well, OK, it's not -# generally for sale anymore, but it's the thought that counts, -# right? (Hint: http://www.libpng.org/pub/png/book/ ) -# -# Invoke this makefile from a shell prompt in the usual way; for example: -# -# make -f Makefile.unx -# -# This makefile assumes libpng and zlib have already been built or downloaded -# and are installed in /usr/local/{include,lib} or as otherwise indicated by -# the PNG* and Z* macros below. Edit as appropriate--choose only ONE each of -# the PNGINC, PNGLIBd, PNGLIBs, ZINC, ZLIBd and ZLIBs lines. -# -# This makefile builds both dynamically and statically linked executables -# (against libpng and zlib, that is), but that can be changed by modifying -# the "EXES =" line. (You need only one set, but for testing it can be handy -# to have both.) - - -# macros -------------------------------------------------------------------- - -#PNGDIR = /usr/local/lib -#PNGINC = -I/usr/local/include/libpng16 -#PNGLIBd = -L$(PNGDIR) -lpng16 # dynamically linked, installed libpng -#PNGLIBs = $(PNGDIR)/libpng16.a # statically linked, installed libpng -# or: -PNGDIR = ../..# this one is for libpng-x.y.z/contrib/gregbook builds -#PNGDIR = ../libpng -PNGINC = -I$(PNGDIR) -PNGLIBd = -Wl,-rpath,$(PNGDIR) -L$(PNGDIR) -lpng16 # dynamically linked -PNGLIBs = $(PNGDIR)/libpng.a # statically linked, local libpng - -ZDIR = /usr/local/lib -#ZDIR = /usr/lib64 -ZINC = -I/usr/local/include -ZLIBd = -L$(ZDIR) -lz # dynamically linked against zlib -ZLIBs = $(ZDIR)/libz.a # statically linked against zlib -# or: -#ZDIR = ../zlib -#ZINC = -I$(ZDIR) -#ZLIBd = -Wl,-rpath,$(ZDIR) -L$(ZDIR) -lz # -rpath allows in-place testing -#ZLIBs = $(ZDIR)/libz.a - -#XINC = -I/usr/include # old-style, stock X distributions -#XLIB = -L/usr/lib/X11 -lX11 # (including SGI IRIX) -#XINC = -I/usr/openwin/include # Sun workstations (OpenWindows) -#XLIB = -L/usr/openwin/lib -lX11 -XINC = -I/usr/X11R6/include # new X distributions (X.org, etc.) -XLIB = -L/usr/X11R6/lib -lX11 -#XLIB = -L/usr/X11R6/lib64 -lX11 # e.g., Red Hat on AMD64 - -INCS = $(PNGINC) $(ZINC) $(XINC) -RLIBSd = $(PNGLIBd) $(ZLIBd) $(XLIB) -lm -RLIBSs = $(PNGLIBs) $(ZLIBs) $(XLIB) -lm -WLIBSd = $(PNGLIBd) $(ZLIBd) -lm -WLIBSs = $(PNGLIBs) $(ZLIBs) - -CC = gcc -LD = gcc -RM = rm -f -CPPFLAGS = $(INCS) -DFEATURE_LOOP -CFLAGS = -O -Wall -# [note that -Wall is a gcc-specific compilation flag ("most warnings on")] -# [-ansi, -pedantic and -W can also be used] -LDFLAGS = -O = .o -E = - -RPNG = rpng-x -RPNG2 = rpng2-x -WPNG = wpng - -RPNGs = $(RPNG)-static -RPNG2s = $(RPNG2)-static -WPNGs = $(WPNG)-static - -ROBJS = $(RPNG)$(O) readpng$(O) -ROBJS2 = $(RPNG2)$(O) readpng2$(O) -WOBJS = $(WPNG)$(O) writepng$(O) - -STATIC_EXES = $(RPNGs)$(E) $(RPNG2s)$(E) $(WPNGs)$(E) -DYNAMIC_EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) - -EXES = $(STATIC_EXES) $(DYNAMIC_EXES) - - -# implicit make rules ------------------------------------------------------- - -.c$(O): - $(CC) -c $(CPPFLAGS) $(CFLAGS) $< - - -# dependencies -------------------------------------------------------------- - -all: $(EXES) - -$(RPNGs)$(E): $(ROBJS) - $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBSs) - -$(RPNG)$(E): $(ROBJS) - $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBSd) - -$(RPNG2s)$(E): $(ROBJS2) - $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBSs) - -$(RPNG2)$(E): $(ROBJS2) - $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBSd) - -$(WPNGs)$(E): $(WOBJS) - $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBSs) - -$(WPNG)$(E): $(WOBJS) - $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBSd) - -$(RPNG)$(O): $(RPNG).c readpng.h -$(RPNG2)$(O): $(RPNG2).c readpng2.h -$(WPNG)$(O): $(WPNG).c writepng.h - -readpng$(O): readpng.c readpng.h -readpng2$(O): readpng2.c readpng2.h -writepng$(O): writepng.c writepng.h - - -# maintenance --------------------------------------------------------------- - -clean: - $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS) +# Sample makefile for rpng-x / rpng2-x / wpng using gcc and make. +# Greg Roelofs +# Last modified: 2 June 2007 +# +# The programs built by this makefile are described in the book, +# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and +# Associates, 1999). Go buy a copy, eh? Well, OK, it's not +# generally for sale anymore, but it's the thought that counts, +# right? (Hint: http://www.libpng.org/pub/png/book/ ) +# +# Invoke this makefile from a shell prompt in the usual way; for example: +# +# make -f Makefile.unx +# +# This makefile assumes libpng and zlib have already been built or downloaded +# and are installed in /usr/local/{include,lib} or as otherwise indicated by +# the PNG* and Z* macros below. Edit as appropriate--choose only ONE each of +# the PNGINC, PNGLIBd, PNGLIBs, ZINC, ZLIBd and ZLIBs lines. +# +# This makefile builds both dynamically and statically linked executables +# (against libpng and zlib, that is), but that can be changed by modifying +# the "EXES =" line. (You need only one set, but for testing it can be handy +# to have both.) + + +# macros -------------------------------------------------------------------- + +#PNGDIR = /usr/local/lib +#PNGINC = -I/usr/local/include/libpng16 +#PNGLIBd = -L$(PNGDIR) -lpng16 # dynamically linked, installed libpng +#PNGLIBs = $(PNGDIR)/libpng16.a # statically linked, installed libpng +# or: +PNGDIR = ../..# this one is for libpng-x.y.z/contrib/gregbook builds +#PNGDIR = ../libpng +PNGINC = -I$(PNGDIR) +PNGLIBd = -Wl,-rpath,$(PNGDIR) -L$(PNGDIR) -lpng16 # dynamically linked +PNGLIBs = $(PNGDIR)/libpng.a # statically linked, local libpng + +ZDIR = /usr/local/lib +#ZDIR = /usr/lib64 +ZINC = -I/usr/local/include +ZLIBd = -L$(ZDIR) -lz # dynamically linked against zlib +ZLIBs = $(ZDIR)/libz.a # statically linked against zlib +# or: +#ZDIR = ../zlib +#ZINC = -I$(ZDIR) +#ZLIBd = -Wl,-rpath,$(ZDIR) -L$(ZDIR) -lz # -rpath allows in-place testing +#ZLIBs = $(ZDIR)/libz.a + +#XINC = -I/usr/include # old-style, stock X distributions +#XLIB = -L/usr/lib/X11 -lX11 # (including SGI IRIX) +#XINC = -I/usr/openwin/include # Sun workstations (OpenWindows) +#XLIB = -L/usr/openwin/lib -lX11 +XINC = -I/usr/X11R6/include # new X distributions (X.org, etc.) +XLIB = -L/usr/X11R6/lib -lX11 +#XLIB = -L/usr/X11R6/lib64 -lX11 # e.g., Red Hat on AMD64 + +INCS = $(PNGINC) $(ZINC) $(XINC) +RLIBSd = $(PNGLIBd) $(ZLIBd) $(XLIB) -lm +RLIBSs = $(PNGLIBs) $(ZLIBs) $(XLIB) -lm +WLIBSd = $(PNGLIBd) $(ZLIBd) -lm +WLIBSs = $(PNGLIBs) $(ZLIBs) + +CC = gcc +LD = gcc +RM = rm -f +CPPFLAGS = $(INCS) -DFEATURE_LOOP +CFLAGS = -O -Wall +# [note that -Wall is a gcc-specific compilation flag ("most warnings on")] +# [-ansi, -pedantic and -W can also be used] +LDFLAGS = +O = .o +E = + +RPNG = rpng-x +RPNG2 = rpng2-x +WPNG = wpng + +RPNGs = $(RPNG)-static +RPNG2s = $(RPNG2)-static +WPNGs = $(WPNG)-static + +ROBJS = $(RPNG)$(O) readpng$(O) +ROBJS2 = $(RPNG2)$(O) readpng2$(O) +WOBJS = $(WPNG)$(O) writepng$(O) + +STATIC_EXES = $(RPNGs)$(E) $(RPNG2s)$(E) $(WPNGs)$(E) +DYNAMIC_EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) + +EXES = $(STATIC_EXES) $(DYNAMIC_EXES) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + +$(RPNGs)$(E): $(ROBJS) + $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBSs) + +$(RPNG)$(E): $(ROBJS) + $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBSd) + +$(RPNG2s)$(E): $(ROBJS2) + $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBSs) + +$(RPNG2)$(E): $(ROBJS2) + $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBSd) + +$(WPNGs)$(E): $(WOBJS) + $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBSs) + +$(WPNG)$(E): $(WOBJS) + $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBSd) + +$(RPNG)$(O): $(RPNG).c readpng.h +$(RPNG2)$(O): $(RPNG2).c readpng2.h +$(WPNG)$(O): $(WPNG).c writepng.h + +readpng$(O): readpng.c readpng.h +readpng2$(O): readpng2.c readpng2.h +writepng$(O): writepng.c writepng.h + + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS) diff --git a/main/source/includes/lpng1610/contrib/gregbook/Makefile.w32 b/main/source/includes/lpng1610/contrib/gregbook/Makefile.w32 index 6afee0d8..ab7dcf7c 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/Makefile.w32 +++ b/main/source/includes/lpng1610/contrib/gregbook/Makefile.w32 @@ -1,114 +1,114 @@ -# Sample makefile for rpng-win / rpng2-win / wpng using MSVC and NMAKE. -# Greg Roelofs -# Last modified: 2 June 2007 -# -# The programs built by this makefile are described in the book, -# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and -# Associates, 1999). Go buy a copy, eh? Well, OK, it's not -# generally for sale anymore, but it's the thought that counts, -# right? (Hint: http://www.libpng.org/pub/png/book/ ) -# -# Invoke this makefile from a DOS prompt window via: -# -# %devstudio%\vc\bin\vcvars32.bat -# nmake -nologo -f Makefile.w32 -# -# where %devstudio% is the installation directory for MSVC / DevStudio. If -# you get "environment out of space" errors, create a desktop shortcut with -# "c:\windows\command.com /e:4096" as the program command line and set the -# working directory to this directory. Then double-click to open the new -# DOS-prompt window with a bigger environment and retry the commands above. -# -# This makefile assumes libpng and zlib have already been built or downloaded -# and are in subdirectories at the same level as the current subdirectory -# (as indicated by the PNGPATH and ZPATH macros below). Edit as appropriate. -# -# Note that the names of the dynamic and static libpng and zlib libraries -# used below may change in later releases of the libraries. This makefile -# builds statically linked executables, but that can be changed by uncom- -# menting the appropriate PNGLIB and ZLIB lines. - -!include - - -# macros -------------------------------------------------------------------- - -PNGPATH = ../libpng -PNGINC = -I$(PNGPATH) -#PNGLIB = $(PNGPATH)/pngdll.lib -PNGLIB = $(PNGPATH)/libpng.lib - -ZPATH = ../zlib -ZINC = -I$(ZPATH) -#ZLIB = $(ZPATH)/zlibdll.lib -ZLIB = $(ZPATH)/zlibstat.lib - -WINLIBS = -defaultlib:user32.lib gdi32.lib -# ["real" apps may also need comctl32.lib, comdlg32.lib, winmm.lib, etc.] - -INCS = $(PNGINC) $(ZINC) -RLIBS = $(PNGLIB) $(ZLIB) $(WINLIBS) -WLIBS = $(PNGLIB) $(ZLIB) - -CC = cl -LD = link -RM = del -CPPFLAGS = $(INCS) -CFLAGS = -nologo -O -W3 $(cvars) -# [note that -W3 is an MSVC-specific compilation flag ("all warnings on")] -# [see %devstudio%\vc\include\win32.mak for cvars macro definition] -O = .obj -E = .exe - -RLDFLAGS = -nologo -subsystem:windows -WLDFLAGS = -nologo - -RPNG = rpng-win -RPNG2 = rpng2-win -WPNG = wpng - -ROBJS = $(RPNG)$(O) readpng$(O) -ROBJS2 = $(RPNG2)$(O) readpng2$(O) -WOBJS = $(WPNG)$(O) writepng$(O) - -EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) - - -# implicit make rules ------------------------------------------------------- - -.c$(O): - $(CC) -c $(CPPFLAGS) $(CFLAGS) $< - - -# dependencies -------------------------------------------------------------- - -all: $(EXES) - -$(RPNG)$(E): $(ROBJS) - $(LD) $(RLDFLAGS) -out:$@ $(ROBJS) $(RLIBS) - -$(RPNG2)$(E): $(ROBJS2) - $(LD) $(RLDFLAGS) -out:$@ $(ROBJS2) $(RLIBS) - -$(WPNG)$(E): $(WOBJS) - $(LD) $(WLDFLAGS) -out:$@ $(WOBJS) $(WLIBS) - -$(RPNG)$(O): $(RPNG).c readpng.h -$(RPNG2)$(O): $(RPNG2).c readpng2.h -$(WPNG)$(O): $(WPNG).c writepng.h - -readpng$(O): readpng.c readpng.h -readpng2$(O): readpng2.c readpng2.h -writepng$(O): writepng.c writepng.h - - -# maintenance --------------------------------------------------------------- - -clean: -# ideally we could just do this: -# $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS) -# ...but the Windows "DEL" command is none too bright, so: - $(RM) r*$(E) - $(RM) w*$(E) - $(RM) r*$(O) - $(RM) w*$(O) +# Sample makefile for rpng-win / rpng2-win / wpng using MSVC and NMAKE. +# Greg Roelofs +# Last modified: 2 June 2007 +# +# The programs built by this makefile are described in the book, +# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and +# Associates, 1999). Go buy a copy, eh? Well, OK, it's not +# generally for sale anymore, but it's the thought that counts, +# right? (Hint: http://www.libpng.org/pub/png/book/ ) +# +# Invoke this makefile from a DOS prompt window via: +# +# %devstudio%\vc\bin\vcvars32.bat +# nmake -nologo -f Makefile.w32 +# +# where %devstudio% is the installation directory for MSVC / DevStudio. If +# you get "environment out of space" errors, create a desktop shortcut with +# "c:\windows\command.com /e:4096" as the program command line and set the +# working directory to this directory. Then double-click to open the new +# DOS-prompt window with a bigger environment and retry the commands above. +# +# This makefile assumes libpng and zlib have already been built or downloaded +# and are in subdirectories at the same level as the current subdirectory +# (as indicated by the PNGPATH and ZPATH macros below). Edit as appropriate. +# +# Note that the names of the dynamic and static libpng and zlib libraries +# used below may change in later releases of the libraries. This makefile +# builds statically linked executables, but that can be changed by uncom- +# menting the appropriate PNGLIB and ZLIB lines. + +!include + + +# macros -------------------------------------------------------------------- + +PNGPATH = ../libpng +PNGINC = -I$(PNGPATH) +#PNGLIB = $(PNGPATH)/pngdll.lib +PNGLIB = $(PNGPATH)/libpng.lib + +ZPATH = ../zlib +ZINC = -I$(ZPATH) +#ZLIB = $(ZPATH)/zlibdll.lib +ZLIB = $(ZPATH)/zlibstat.lib + +WINLIBS = -defaultlib:user32.lib gdi32.lib +# ["real" apps may also need comctl32.lib, comdlg32.lib, winmm.lib, etc.] + +INCS = $(PNGINC) $(ZINC) +RLIBS = $(PNGLIB) $(ZLIB) $(WINLIBS) +WLIBS = $(PNGLIB) $(ZLIB) + +CC = cl +LD = link +RM = del +CPPFLAGS = $(INCS) +CFLAGS = -nologo -O -W3 $(cvars) +# [note that -W3 is an MSVC-specific compilation flag ("all warnings on")] +# [see %devstudio%\vc\include\win32.mak for cvars macro definition] +O = .obj +E = .exe + +RLDFLAGS = -nologo -subsystem:windows +WLDFLAGS = -nologo + +RPNG = rpng-win +RPNG2 = rpng2-win +WPNG = wpng + +ROBJS = $(RPNG)$(O) readpng$(O) +ROBJS2 = $(RPNG2)$(O) readpng2$(O) +WOBJS = $(WPNG)$(O) writepng$(O) + +EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + +$(RPNG)$(E): $(ROBJS) + $(LD) $(RLDFLAGS) -out:$@ $(ROBJS) $(RLIBS) + +$(RPNG2)$(E): $(ROBJS2) + $(LD) $(RLDFLAGS) -out:$@ $(ROBJS2) $(RLIBS) + +$(WPNG)$(E): $(WOBJS) + $(LD) $(WLDFLAGS) -out:$@ $(WOBJS) $(WLIBS) + +$(RPNG)$(O): $(RPNG).c readpng.h +$(RPNG2)$(O): $(RPNG2).c readpng2.h +$(WPNG)$(O): $(WPNG).c writepng.h + +readpng$(O): readpng.c readpng.h +readpng2$(O): readpng2.c readpng2.h +writepng$(O): writepng.c writepng.h + + +# maintenance --------------------------------------------------------------- + +clean: +# ideally we could just do this: +# $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS) +# ...but the Windows "DEL" command is none too bright, so: + $(RM) r*$(E) + $(RM) w*$(E) + $(RM) r*$(O) + $(RM) w*$(O) diff --git a/main/source/includes/lpng1610/contrib/gregbook/README b/main/source/includes/lpng1610/contrib/gregbook/README index 791fec8d..7b1f6a3e 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/README +++ b/main/source/includes/lpng1610/contrib/gregbook/README @@ -1,186 +1,186 @@ - =========================== - PNG: The Definitive Guide - =========================== - - Source Code - -Chapters 13, 14 and 15 of "PNG: The Definitive Guide" discuss three free, -cross-platform demo programs that show how to use the libpng reference -library: rpng, rpng2 and wpng. rpng and rpng2 are viewers; the first is -a very simple example that that shows how a standard file-viewer might use -libpng, while the second is designed to process streaming data and shows -how a web browser might be written. wpng is a simple command-line program -that reads binary PGM and PPM files (the ``raw'' grayscale and RGB subsets -of PBMPLUS/NetPBM) and converts them to PNG. - -The source code for all three demo programs currently compiles under -Unix, OpenVMS, and 32-bit Windows. (Special thanks to Martin Zinser, -zinser@decus.de, for making the necessary changes for OpenVMS and for -providing an appropriate build script.) Build instructions can be found -below. - -Files: - - README this file - LICENSE terms of distribution and reuse (BSD-like or GNU GPL) - COPYING GNU General Public License (GPL) - - Makefile.unx Unix makefile - Makefile.w32 Windows (MSVC) makefile - makevms.com OpenVMS build script - - rpng-win.c Windows front end for the basic viewer - rpng-x.c X Window System (Unix, OpenVMS) front end - readpng.c generic back end for the basic viewer - readpng.h header file for the basic viewer - - rpng2-win.c Windows front end for the progressive viewer - rpng2-x.c X front end for the progressive viewer - readpng2.c generic back end for the progressive viewer - readpng2.h header file for the progressive viewer - - wpng.c generic (text) front end for the converter - writepng.c generic back end for the converter - writepng.h header file for the converter - - toucan.png transparent PNG for testing (by Stefan Schneider) - -Note that, although the programs are designed to be functional, their -primary purpose is to illustrate how to use libpng to add PNG support to -other programs. As such, their user interfaces are crude and definitely -are not intended for everyday use. - -Please see http://www.libpng.org/pub/png/pngbook.html for further infor- -mation and links to the latest version of the source code, and Chapters -13-15 of the book for detailed discussion of the three programs. - -Greg Roelofs -http://pobox.com/~newt/greg_contact.html -16 March 2008 - - -BUILD INSTRUCTIONS - - - Prerequisites (in order of compilation): - - - zlib http://zlib.net/ - - libpng http://www.libpng.org/pub/png/libpng.html - - pngbook http://www.libpng.org/pub/png/book/sources.html - - The pngbook demo programs are explicitly designed to demonstrate proper - coding techniques for using the libpng reference library. As a result, - you need to download and build both zlib (on which libpng depends) and - libpng. A common build setup is to place the zlib, libpng and pngbook - subdirectory trees ("folders") in the same parent directory. Then the - libpng build can refer to files in ../zlib (or ..\zlib or [-.zlib]), - and similarly for the pngbook build. - - Note that all three packages are designed to be built from a command - line by default; those who wish to use a graphical or other integrated - development environments are on their own. - - - - Unix: - - Unpack the latest pngbook sources (which should correspond to this - README file) into a directory and change into that directory. - - Copy Makefile.unx to Makefile and edit the PNG* and Z* variables - appropriately (possibly also the X* variables if necessary). - - make - - There is no "install" target, so copy the three executables somewhere - in your path or run them from the current directory. All three will - print a basic usage screen when run without any command-line arguments; - see the book for more details. - - - - Windows: - - Unpack the latest pngbook sources (which should correspond to this - README file) into a folder, open a "DOS shell" or "command prompt" - or equivalent command-line window, and cd into the folder where you - unpacked the source code. - - For MSVC, set up the necessary environment variables by invoking - - %devstudio%\vc\bin\vcvars32.bat - - where where %devstudio% is the installation directory for MSVC / - DevStudio. If you get "environment out of space" errors under 95/98, - create a desktop shortcut with "c:\windows\command.com /e:4096" as - the program command line and set the working directory to the pngbook - directory. Then double-click to open the new DOS-prompt window with - a bigger environment and retry the commands above. - - Copy Makefile.w32 to Makefile and edit the PNGPATH and ZPATH variables - appropriately (possibly also the "INC" and "LIB" variables if needed). - Note that the names of the dynamic and static libpng and zlib libraries - used in the makefile may change in later releases of the libraries. - Also note that, as of libpng version 1.0.5, MSVC DLL builds do not work. - This makefile therefore builds statically linked executables, but if - the DLL problems ever get fixed, uncommenting the appropriate PNGLIB - and ZLIB lines will build dynamically linked executables instead. - - Do the build by typing - - nmake - - The result should be three executables: rpng-win.exe, rpng2-win.exe, - and wpng.exe. Copy them somewhere in your PATH or run them from the - current folder. Like the Unix versions, the two windowed programs - (rpng and rpng2) now display a usage screen in a console window when - invoked without command-line arguments; this is new behavior as of - the June 2001 release. Note that the programs use the Unix-style "-" - character to specify options, instead of the more common DOS/Windows - "/" character. (For example: "rpng2-win -bgpat 4 foo.png", not - "rpng2-win /bgpat 4 foo.png") - - - - OpenVMS: - - Unpack the pngbook sources into a subdirectory and change into that - subdirectory. - - Edit makevms.com appropriately, specifically the zpath and pngpath - variables. - - @makevms - - To run the programs, they probably first need to be set up as "foreign - symbols," with "disk" and "dir" set appropriately: - - $ rpng == "$disk:[dir]rpng-x.exe" - $ rpng2 == "$disk:[dir]rpng2-x.exe" - $ wpng == "$disk:[dir]wpng.exe" - - All three will print a basic usage screen when run without any command- - line arguments; see the book for more details. Note that the options - style is Unix-like, i.e., preceded by "-" rather than "/". - - -RUNNING THE PROGRAMS: (VERY) BRIEF INTRO - - rpng is a simple PNG viewer that can display transparent PNGs with a - specified background color; for example, - - rpng -bgcolor \#ff0000 toucan.png - - would display the image with a red background. rpng2 is a progressive - viewer that simulates a web browser in some respects; it can display - images against either a background color or a dynamically generated - background image. For example: - - rpng2 -bgpat 16 toucan.png - - wpng is a purely command-line image converter from binary PBMPLUS/NetPBM - format (.pgm or .ppm) to PNG; for example, - - wpng -time < toucan-notrans.ppm > toucan-notrans.png - - would convert the specified PPM file (using redirection) to PNG, auto- - matically setting the PNG modification-time chunk. - - All options can be abbreviated to the shortest unique value; for example, - "-bgc" for -bgcolor (versus "-bgp" for -bgpat), or "-g" for -gamma. + =========================== + PNG: The Definitive Guide + =========================== + + Source Code + +Chapters 13, 14 and 15 of "PNG: The Definitive Guide" discuss three free, +cross-platform demo programs that show how to use the libpng reference +library: rpng, rpng2 and wpng. rpng and rpng2 are viewers; the first is +a very simple example that that shows how a standard file-viewer might use +libpng, while the second is designed to process streaming data and shows +how a web browser might be written. wpng is a simple command-line program +that reads binary PGM and PPM files (the ``raw'' grayscale and RGB subsets +of PBMPLUS/NetPBM) and converts them to PNG. + +The source code for all three demo programs currently compiles under +Unix, OpenVMS, and 32-bit Windows. (Special thanks to Martin Zinser, +zinser@decus.de, for making the necessary changes for OpenVMS and for +providing an appropriate build script.) Build instructions can be found +below. + +Files: + + README this file + LICENSE terms of distribution and reuse (BSD-like or GNU GPL) + COPYING GNU General Public License (GPL) + + Makefile.unx Unix makefile + Makefile.w32 Windows (MSVC) makefile + makevms.com OpenVMS build script + + rpng-win.c Windows front end for the basic viewer + rpng-x.c X Window System (Unix, OpenVMS) front end + readpng.c generic back end for the basic viewer + readpng.h header file for the basic viewer + + rpng2-win.c Windows front end for the progressive viewer + rpng2-x.c X front end for the progressive viewer + readpng2.c generic back end for the progressive viewer + readpng2.h header file for the progressive viewer + + wpng.c generic (text) front end for the converter + writepng.c generic back end for the converter + writepng.h header file for the converter + + toucan.png transparent PNG for testing (by Stefan Schneider) + +Note that, although the programs are designed to be functional, their +primary purpose is to illustrate how to use libpng to add PNG support to +other programs. As such, their user interfaces are crude and definitely +are not intended for everyday use. + +Please see http://www.libpng.org/pub/png/pngbook.html for further infor- +mation and links to the latest version of the source code, and Chapters +13-15 of the book for detailed discussion of the three programs. + +Greg Roelofs +http://pobox.com/~newt/greg_contact.html +16 March 2008 + + +BUILD INSTRUCTIONS + + - Prerequisites (in order of compilation): + + - zlib http://zlib.net/ + - libpng http://www.libpng.org/pub/png/libpng.html + - pngbook http://www.libpng.org/pub/png/book/sources.html + + The pngbook demo programs are explicitly designed to demonstrate proper + coding techniques for using the libpng reference library. As a result, + you need to download and build both zlib (on which libpng depends) and + libpng. A common build setup is to place the zlib, libpng and pngbook + subdirectory trees ("folders") in the same parent directory. Then the + libpng build can refer to files in ../zlib (or ..\zlib or [-.zlib]), + and similarly for the pngbook build. + + Note that all three packages are designed to be built from a command + line by default; those who wish to use a graphical or other integrated + development environments are on their own. + + + - Unix: + + Unpack the latest pngbook sources (which should correspond to this + README file) into a directory and change into that directory. + + Copy Makefile.unx to Makefile and edit the PNG* and Z* variables + appropriately (possibly also the X* variables if necessary). + + make + + There is no "install" target, so copy the three executables somewhere + in your path or run them from the current directory. All three will + print a basic usage screen when run without any command-line arguments; + see the book for more details. + + + - Windows: + + Unpack the latest pngbook sources (which should correspond to this + README file) into a folder, open a "DOS shell" or "command prompt" + or equivalent command-line window, and cd into the folder where you + unpacked the source code. + + For MSVC, set up the necessary environment variables by invoking + + %devstudio%\vc\bin\vcvars32.bat + + where where %devstudio% is the installation directory for MSVC / + DevStudio. If you get "environment out of space" errors under 95/98, + create a desktop shortcut with "c:\windows\command.com /e:4096" as + the program command line and set the working directory to the pngbook + directory. Then double-click to open the new DOS-prompt window with + a bigger environment and retry the commands above. + + Copy Makefile.w32 to Makefile and edit the PNGPATH and ZPATH variables + appropriately (possibly also the "INC" and "LIB" variables if needed). + Note that the names of the dynamic and static libpng and zlib libraries + used in the makefile may change in later releases of the libraries. + Also note that, as of libpng version 1.0.5, MSVC DLL builds do not work. + This makefile therefore builds statically linked executables, but if + the DLL problems ever get fixed, uncommenting the appropriate PNGLIB + and ZLIB lines will build dynamically linked executables instead. + + Do the build by typing + + nmake + + The result should be three executables: rpng-win.exe, rpng2-win.exe, + and wpng.exe. Copy them somewhere in your PATH or run them from the + current folder. Like the Unix versions, the two windowed programs + (rpng and rpng2) now display a usage screen in a console window when + invoked without command-line arguments; this is new behavior as of + the June 2001 release. Note that the programs use the Unix-style "-" + character to specify options, instead of the more common DOS/Windows + "/" character. (For example: "rpng2-win -bgpat 4 foo.png", not + "rpng2-win /bgpat 4 foo.png") + + + - OpenVMS: + + Unpack the pngbook sources into a subdirectory and change into that + subdirectory. + + Edit makevms.com appropriately, specifically the zpath and pngpath + variables. + + @makevms + + To run the programs, they probably first need to be set up as "foreign + symbols," with "disk" and "dir" set appropriately: + + $ rpng == "$disk:[dir]rpng-x.exe" + $ rpng2 == "$disk:[dir]rpng2-x.exe" + $ wpng == "$disk:[dir]wpng.exe" + + All three will print a basic usage screen when run without any command- + line arguments; see the book for more details. Note that the options + style is Unix-like, i.e., preceded by "-" rather than "/". + + +RUNNING THE PROGRAMS: (VERY) BRIEF INTRO + + rpng is a simple PNG viewer that can display transparent PNGs with a + specified background color; for example, + + rpng -bgcolor \#ff0000 toucan.png + + would display the image with a red background. rpng2 is a progressive + viewer that simulates a web browser in some respects; it can display + images against either a background color or a dynamically generated + background image. For example: + + rpng2 -bgpat 16 toucan.png + + wpng is a purely command-line image converter from binary PBMPLUS/NetPBM + format (.pgm or .ppm) to PNG; for example, + + wpng -time < toucan-notrans.ppm > toucan-notrans.png + + would convert the specified PPM file (using redirection) to PNG, auto- + matically setting the PNG modification-time chunk. + + All options can be abbreviated to the shortest unique value; for example, + "-bgc" for -bgcolor (versus "-bgp" for -bgpat), or "-g" for -gamma. diff --git a/main/source/includes/lpng1610/contrib/gregbook/readpng.c b/main/source/includes/lpng1610/contrib/gregbook/readpng.c index 686bcd39..f5e1fb1a 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/readpng.c +++ b/main/source/includes/lpng1610/contrib/gregbook/readpng.c @@ -1,316 +1,316 @@ -/*--------------------------------------------------------------------------- - - rpng - simple PNG display program readpng.c - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#include -#include -#include - -#include "png.h" /* libpng header */ -#include "readpng.h" /* typedefs, common macros, public prototypes */ - -/* future versions of libpng will provide this macro: */ -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#endif - - -static png_structp png_ptr = NULL; -static png_infop info_ptr = NULL; - -png_uint_32 width, height; -int bit_depth, color_type; -uch *image_data = NULL; - - -void readpng_version_info(void) -{ - fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", - PNG_LIBPNG_VER_STRING, png_libpng_ver); - fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", - ZLIB_VERSION, zlib_version); -} - - -/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ - -int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) -{ - uch sig[8]; - - - /* first do a quick check that the file really is a PNG image; could - * have used slightly more general png_sig_cmp() function instead */ - - fread(sig, 1, 8, infile); - if (png_sig_cmp(sig, 0, 8)) - return 1; /* bad signature */ - - - /* could pass pointers to user-defined error handlers instead of NULLs: */ - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - return 4; /* out of memory */ - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - return 4; /* out of memory */ - } - - - /* we could create a second info struct here (end_info), but it's only - * useful if we want to keep pre- and post-IDAT chunk info separated - * (mainly for PNG-aware image editors and converters) */ - - - /* setjmp() must be called in every function that calls a PNG-reading - * libpng function */ - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 2; - } - - - png_init_io(png_ptr, infile); - png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ - - png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ - - - /* alternatively, could make separate calls to png_get_image_width(), - * etc., but want bit_depth and color_type for later [don't care about - * compression_type and filter_type => NULLs] */ - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - NULL, NULL, NULL); - *pWidth = width; - *pHeight = height; - - - /* OK, that's all we need for now; return happy */ - - return 0; -} - - - - -/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; - * scales values to 8-bit if necessary */ - -int readpng_get_bgcolor(uch *red, uch *green, uch *blue) -{ - png_color_16p pBackground; - - - /* setjmp() must be called in every function that calls a PNG-reading - * libpng function */ - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 2; - } - - - if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) - return 1; - - /* it is not obvious from the libpng documentation, but this function - * takes a pointer to a pointer, and it always returns valid red, green - * and blue values, regardless of color_type: */ - - png_get_bKGD(png_ptr, info_ptr, &pBackground); - - - /* however, it always returns the raw bKGD data, regardless of any - * bit-depth transformations, so check depth and adjust if necessary */ - - if (bit_depth == 16) { - *red = pBackground->red >> 8; - *green = pBackground->green >> 8; - *blue = pBackground->blue >> 8; - } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - if (bit_depth == 1) - *red = *green = *blue = pBackground->gray? 255 : 0; - else if (bit_depth == 2) - *red = *green = *blue = (255/3) * pBackground->gray; - else /* bit_depth == 4 */ - *red = *green = *blue = (255/15) * pBackground->gray; - } else { - *red = (uch)pBackground->red; - *green = (uch)pBackground->green; - *blue = (uch)pBackground->blue; - } - - return 0; -} - - - - -/* display_exponent == LUT_exponent * CRT_exponent */ - -uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) -{ - double gamma; - png_uint_32 i, rowbytes; - png_bytepp row_pointers = NULL; - - - /* setjmp() must be called in every function that calls a PNG-reading - * libpng function */ - - if (setjmp(png_jmpbuf(png_ptr))) { - free(image_data); - image_data = NULL; - free(row_pointers); - row_pointers = NULL; - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - - /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, - * transparency chunks to full alpha channel; strip 16-bit-per-sample - * images to 8 bits per sample; and convert grayscale to RGB[A] */ - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand(png_ptr); - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand(png_ptr); -#ifdef PNG_READ_16_TO_8_SUPPORTED - if (bit_depth == 16) -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - png_set_scale_16(png_ptr); -# else - png_set_strip_16(png_ptr); -# endif -#endif - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - - - /* unlike the example in the libpng documentation, we have *no* idea where - * this file may have come from--so if it doesn't have a file gamma, don't - * do any correction ("do no harm") */ - - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma(png_ptr, display_exponent, gamma); - - - /* all transformations have been registered; now update info_ptr data, - * get rowbytes and channels, and allocate image memory */ - - png_read_update_info(png_ptr, info_ptr); - - *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); - *pChannels = (int)png_get_channels(png_ptr, info_ptr); - - if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - free(image_data); - image_data = NULL; - return NULL; - } - - Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", - *pChannels, rowbytes, height)); - - - /* set the individual row_pointers to point at the correct offsets */ - - for (i = 0; i < height; ++i) - row_pointers[i] = image_data + i*rowbytes; - - - /* now we can go ahead and just read the whole image */ - - png_read_image(png_ptr, row_pointers); - - - /* and we're done! (png_read_end() can be omitted if no processing of - * post-IDAT text/time/etc. is desired) */ - - free(row_pointers); - row_pointers = NULL; - - png_read_end(png_ptr, NULL); - - return image_data; -} - - -void readpng_cleanup(int free_image_data) -{ - if (free_image_data && image_data) { - free(image_data); - image_data = NULL; - } - - if (png_ptr && info_ptr) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - png_ptr = NULL; - info_ptr = NULL; - } -} +/*--------------------------------------------------------------------------- + + rpng - simple PNG display program readpng.c + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#include +#include +#include + +#include "png.h" /* libpng header */ +#include "readpng.h" /* typedefs, common macros, public prototypes */ + +/* future versions of libpng will provide this macro: */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + + +static png_structp png_ptr = NULL; +static png_infop info_ptr = NULL; + +png_uint_32 width, height; +int bit_depth, color_type; +uch *image_data = NULL; + + +void readpng_version_info(void) +{ + fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", + PNG_LIBPNG_VER_STRING, png_libpng_ver); + fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", + ZLIB_VERSION, zlib_version); +} + + +/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ + +int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) +{ + uch sig[8]; + + + /* first do a quick check that the file really is a PNG image; could + * have used slightly more general png_sig_cmp() function instead */ + + fread(sig, 1, 8, infile); + if (png_sig_cmp(sig, 0, 8)) + return 1; /* bad signature */ + + + /* could pass pointers to user-defined error handlers instead of NULLs: */ + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + return 4; /* out of memory */ + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + return 4; /* out of memory */ + } + + + /* we could create a second info struct here (end_info), but it's only + * useful if we want to keep pre- and post-IDAT chunk info separated + * (mainly for PNG-aware image editors and converters) */ + + + /* setjmp() must be called in every function that calls a PNG-reading + * libpng function */ + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 2; + } + + + png_init_io(png_ptr, infile); + png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ + + png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ + + + /* alternatively, could make separate calls to png_get_image_width(), + * etc., but want bit_depth and color_type for later [don't care about + * compression_type and filter_type => NULLs] */ + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + *pWidth = width; + *pHeight = height; + + + /* OK, that's all we need for now; return happy */ + + return 0; +} + + + + +/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; + * scales values to 8-bit if necessary */ + +int readpng_get_bgcolor(uch *red, uch *green, uch *blue) +{ + png_color_16p pBackground; + + + /* setjmp() must be called in every function that calls a PNG-reading + * libpng function */ + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 2; + } + + + if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) + return 1; + + /* it is not obvious from the libpng documentation, but this function + * takes a pointer to a pointer, and it always returns valid red, green + * and blue values, regardless of color_type: */ + + png_get_bKGD(png_ptr, info_ptr, &pBackground); + + + /* however, it always returns the raw bKGD data, regardless of any + * bit-depth transformations, so check depth and adjust if necessary */ + + if (bit_depth == 16) { + *red = pBackground->red >> 8; + *green = pBackground->green >> 8; + *blue = pBackground->blue >> 8; + } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { + if (bit_depth == 1) + *red = *green = *blue = pBackground->gray? 255 : 0; + else if (bit_depth == 2) + *red = *green = *blue = (255/3) * pBackground->gray; + else /* bit_depth == 4 */ + *red = *green = *blue = (255/15) * pBackground->gray; + } else { + *red = (uch)pBackground->red; + *green = (uch)pBackground->green; + *blue = (uch)pBackground->blue; + } + + return 0; +} + + + + +/* display_exponent == LUT_exponent * CRT_exponent */ + +uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) +{ + double gamma; + png_uint_32 i, rowbytes; + png_bytepp row_pointers = NULL; + + + /* setjmp() must be called in every function that calls a PNG-reading + * libpng function */ + + if (setjmp(png_jmpbuf(png_ptr))) { + free(image_data); + image_data = NULL; + free(row_pointers); + row_pointers = NULL; + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + + /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, + * transparency chunks to full alpha channel; strip 16-bit-per-sample + * images to 8 bits per sample; and convert grayscale to RGB[A] */ + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (bit_depth == 16) +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +# else + png_set_strip_16(png_ptr); +# endif +#endif + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + + /* unlike the example in the libpng documentation, we have *no* idea where + * this file may have come from--so if it doesn't have a file gamma, don't + * do any correction ("do no harm") */ + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, display_exponent, gamma); + + + /* all transformations have been registered; now update info_ptr data, + * get rowbytes and channels, and allocate image memory */ + + png_read_update_info(png_ptr, info_ptr); + + *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); + *pChannels = (int)png_get_channels(png_ptr, info_ptr); + + if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + free(image_data); + image_data = NULL; + return NULL; + } + + Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", + *pChannels, rowbytes, height)); + + + /* set the individual row_pointers to point at the correct offsets */ + + for (i = 0; i < height; ++i) + row_pointers[i] = image_data + i*rowbytes; + + + /* now we can go ahead and just read the whole image */ + + png_read_image(png_ptr, row_pointers); + + + /* and we're done! (png_read_end() can be omitted if no processing of + * post-IDAT text/time/etc. is desired) */ + + free(row_pointers); + row_pointers = NULL; + + png_read_end(png_ptr, NULL); + + return image_data; +} + + +void readpng_cleanup(int free_image_data) +{ + if (free_image_data && image_data) { + free(image_data); + image_data = NULL; + } + + if (png_ptr && info_ptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_ptr = NULL; + info_ptr = NULL; + } +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/readpng.h b/main/source/includes/lpng1610/contrib/gregbook/readpng.h index ec6b483c..fad9fe3b 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/readpng.h +++ b/main/source/includes/lpng1610/contrib/gregbook/readpng.h @@ -1,88 +1,88 @@ -/*--------------------------------------------------------------------------- - - rpng - simple PNG display program readpng.h - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#ifndef MAX -# define MAX(a,b) ((a) > (b)? (a) : (b)) -# define MIN(a,b) ((a) < (b)? (a) : (b)) -#endif - -#ifdef DEBUG -# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} -#else -# define Trace(x) ; -#endif - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - - -/* prototypes for public functions in readpng.c */ - -void readpng_version_info(void); - -int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight); - -int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue); - -uch *readpng_get_image(double display_exponent, int *pChannels, - ulg *pRowbytes); - -void readpng_cleanup(int free_image_data); +/*--------------------------------------------------------------------------- + + rpng - simple PNG display program readpng.h + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b)? (a) : (b)) +# define MIN(a,b) ((a) < (b)? (a) : (b)) +#endif + +#ifdef DEBUG +# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} +#else +# define Trace(x) ; +#endif + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + + +/* prototypes for public functions in readpng.c */ + +void readpng_version_info(void); + +int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight); + +int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue); + +uch *readpng_get_image(double display_exponent, int *pChannels, + ulg *pRowbytes); + +void readpng_cleanup(int free_image_data); diff --git a/main/source/includes/lpng1610/contrib/gregbook/readpng2.c b/main/source/includes/lpng1610/contrib/gregbook/readpng2.c index 6b72a4a9..e6a132ec 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/readpng2.c +++ b/main/source/includes/lpng1610/contrib/gregbook/readpng2.c @@ -1,510 +1,510 @@ -/*--------------------------------------------------------------------------- - - rpng2 - progressive-model PNG display program readpng2.c - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - - -#include /* for exit() prototype */ -#include - -#include -#include "png.h" /* libpng header from the local directory */ -#include "readpng2.h" /* typedefs, common macros, public prototypes */ - - -/* local prototypes */ - -static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr); -static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass); -static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr); -static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg); -static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg); - - - - -void readpng2_version_info(void) -{ - fprintf(stderr, " Compiled with libpng %s; using libpng %s\n", - PNG_LIBPNG_VER_STRING, png_libpng_ver); - - fprintf(stderr, " and with zlib %s; using zlib %s.\n", - ZLIB_VERSION, zlib_version); -} - - - - -int readpng2_check_sig(uch *sig, int num) -{ - return !png_sig_cmp(sig, 0, num); -} - - - - -/* returns 0 for success, 2 for libpng problem, 4 for out of memory */ - -int readpng2_init(mainprog_info *mainprog_ptr) -{ - png_structp png_ptr; /* note: temporary variables! */ - png_infop info_ptr; - - - /* could also replace libpng warning-handler (final NULL), but no need: */ - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, - readpng2_error_handler, readpng2_warning_handler); - if (!png_ptr) - return 4; /* out of memory */ - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - return 4; /* out of memory */ - } - - - /* we could create a second info struct here (end_info), but it's only - * useful if we want to keep pre- and post-IDAT chunk info separated - * (mainly for PNG-aware image editors and converters) */ - - - /* setjmp() must be called in every function that calls a PNG-reading - * libpng function, unless an alternate error handler was installed-- - * but compatible error handlers must either use longjmp() themselves - * (as in this program) or exit immediately, so here we are: */ - - if (setjmp(mainprog_ptr->jmpbuf)) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 2; - } - - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - /* prepare the reader to ignore all recognized chunks whose data won't be - * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT, - * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */ - { - /* These byte strings were copied from png.h. If a future version - * of readpng2.c recognizes more chunks, add them to this list. - */ - static PNG_CONST png_byte chunks_to_process[] = { - 98, 75, 71, 68, '\0', /* bKGD */ - 103, 65, 77, 65, '\0', /* gAMA */ - 115, 82, 71, 66, '\0', /* sRGB */ - }; - - /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */ - png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */, - NULL, -1); - - /* But do not ignore chunks in the "chunks_to_process" list */ - png_set_keep_unknown_chunks(png_ptr, - 0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process, - sizeof(chunks_to_process)/5); - } -#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ - - - /* instead of doing png_init_io() here, now we set up our callback - * functions for progressive decoding */ - - png_set_progressive_read_fn(png_ptr, mainprog_ptr, - readpng2_info_callback, readpng2_row_callback, readpng2_end_callback); - - - /* make sure we save our pointers for use in readpng2_decode_data() */ - - mainprog_ptr->png_ptr = png_ptr; - mainprog_ptr->info_ptr = info_ptr; - - - /* and that's all there is to initialization */ - - return 0; -} - - - - -/* returns 0 for success, 2 for libpng (longjmp) problem */ - -int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length) -{ - png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; - png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; - - - /* setjmp() must be called in every function that calls a PNG-reading - * libpng function */ - - if (setjmp(mainprog_ptr->jmpbuf)) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - mainprog_ptr->png_ptr = NULL; - mainprog_ptr->info_ptr = NULL; - return 2; - } - - - /* hand off the next chunk of input data to libpng for decoding */ - - png_process_data(png_ptr, info_ptr, rawbuf, length); - - return 0; -} - - - - -static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr) -{ - mainprog_info *mainprog_ptr; - int color_type, bit_depth; - png_uint_32 width, height; -#ifdef PNG_FLOATING_POINT_SUPPORTED - double gamma; -#else - png_fixed_point gamma; -#endif - - - /* setjmp() doesn't make sense here, because we'd either have to exit(), - * longjmp() ourselves, or return control to libpng, which doesn't want - * to see us again. By not doing anything here, libpng will instead jump - * to readpng2_decode_data(), which can return an error value to the main - * program. */ - - - /* retrieve the pointer to our special-purpose struct, using the png_ptr - * that libpng passed back to us (i.e., not a global this time--there's - * no real difference for a single image, but for a multithreaded browser - * decoding several PNG images at the same time, one needs to avoid mixing - * up different images' structs) */ - - mainprog_ptr = png_get_progressive_ptr(png_ptr); - - if (mainprog_ptr == NULL) { /* we be hosed */ - fprintf(stderr, - "readpng2 error: main struct not recoverable in info_callback.\n"); - fflush(stderr); - return; - /* - * Alternatively, we could call our error-handler just like libpng - * does, which would effectively terminate the program. Since this - * can only happen if png_ptr gets redirected somewhere odd or the - * main PNG struct gets wiped, we're probably toast anyway. (If - * png_ptr itself is NULL, we would not have been called.) - */ - } - - - /* this is just like in the non-progressive case */ - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - NULL, NULL, NULL); - mainprog_ptr->width = (ulg)width; - mainprog_ptr->height = (ulg)height; - - - /* since we know we've read all of the PNG file's "header" (i.e., up - * to IDAT), we can check for a background color here */ - - if (mainprog_ptr->need_bgcolor && - png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) - { - png_color_16p pBackground; - - /* it is not obvious from the libpng documentation, but this function - * takes a pointer to a pointer, and it always returns valid red, - * green and blue values, regardless of color_type: */ - png_get_bKGD(png_ptr, info_ptr, &pBackground); - - /* however, it always returns the raw bKGD data, regardless of any - * bit-depth transformations, so check depth and adjust if necessary */ - if (bit_depth == 16) { - mainprog_ptr->bg_red = pBackground->red >> 8; - mainprog_ptr->bg_green = pBackground->green >> 8; - mainprog_ptr->bg_blue = pBackground->blue >> 8; - } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - if (bit_depth == 1) - mainprog_ptr->bg_red = mainprog_ptr->bg_green = - mainprog_ptr->bg_blue = pBackground->gray? 255 : 0; - else if (bit_depth == 2) - mainprog_ptr->bg_red = mainprog_ptr->bg_green = - mainprog_ptr->bg_blue = (255/3) * pBackground->gray; - else /* bit_depth == 4 */ - mainprog_ptr->bg_red = mainprog_ptr->bg_green = - mainprog_ptr->bg_blue = (255/15) * pBackground->gray; - } else { - mainprog_ptr->bg_red = (uch)pBackground->red; - mainprog_ptr->bg_green = (uch)pBackground->green; - mainprog_ptr->bg_blue = (uch)pBackground->blue; - } - } - - - /* as before, let libpng expand palette images to RGB, low-bit-depth - * grayscale images to 8 bits, transparency chunks to full alpha channel; - * strip 16-bit-per-sample images to 8 bits per sample; and convert - * grayscale to RGB[A] */ - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand(png_ptr); - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand(png_ptr); -#ifdef PNG_READ_16_TO_8_SUPPORTED - if (bit_depth == 16) -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - png_set_scale_16(png_ptr); -# else - png_set_strip_16(png_ptr); -# endif -#endif - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - - - /* Unlike the basic viewer, which was designed to operate on local files, - * this program is intended to simulate a web browser--even though we - * actually read from a local file, too. But because we are pretending - * that most of the images originate on the Internet, we follow the recom- - * mendation of the sRGB proposal and treat unlabelled images (no gAMA - * chunk) as existing in the sRGB color space. That is, we assume that - * such images have a file gamma of 0.45455, which corresponds to a PC-like - * display system. This change in assumptions will have no effect on a - * PC-like system, but on a Mac, SGI, NeXT or other system with a non- - * identity lookup table, it will darken unlabelled images, which effec- - * tively favors images from PC-like systems over those originating on - * the local platform. Note that mainprog_ptr->display_exponent is the - * "gamma" value for the entire display system, i.e., the product of - * LUT_exponent and CRT_exponent. */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma); - else - png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455); -#else - if (png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) - png_set_gamma_fixed(png_ptr, - (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), gamma); - else - png_set_gamma_fixed(png_ptr, - (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), 45455); -#endif - - /* we'll let libpng expand interlaced images, too */ - - mainprog_ptr->passes = png_set_interlace_handling(png_ptr); - - - /* all transformations have been registered; now update info_ptr data and - * then get rowbytes and channels */ - - png_read_update_info(png_ptr, info_ptr); - - mainprog_ptr->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr); - mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr); - - - /* Call the main program to allocate memory for the image buffer and - * initialize windows and whatnot. (The old-style function-pointer - * invocation is used for compatibility with a few supposedly ANSI - * compilers that nevertheless barf on "fn_ptr()"-style syntax.) */ - - (*mainprog_ptr->mainprog_init)(); - - - /* and that takes care of initialization */ - - return; -} - - - - - -static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) -{ - mainprog_info *mainprog_ptr; - - - /* first check whether the row differs from the previous pass; if not, - * nothing to combine or display */ - - if (!new_row) - return; - - - /* retrieve the pointer to our special-purpose struct so we can access - * the old rows and image-display callback function */ - - mainprog_ptr = png_get_progressive_ptr(png_ptr); - - - /* save the pass number for optional use by the front end */ - - mainprog_ptr->pass = pass; - - - /* have libpng either combine the new row data with the existing row data - * from previous passes (if interlaced) or else just copy the new row - * into the main program's image buffer */ - - png_progressive_combine_row(png_ptr, mainprog_ptr->row_pointers[row_num], - new_row); - - - /* finally, call the display routine in the main program with the number - * of the row we just updated */ - - (*mainprog_ptr->mainprog_display_row)(row_num); - - - /* and we're ready for more */ - - return; -} - - - - - -static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr) -{ - mainprog_info *mainprog_ptr; - - - /* retrieve the pointer to our special-purpose struct */ - - mainprog_ptr = png_get_progressive_ptr(png_ptr); - - - /* let the main program know that it should flush any buffered image - * data to the display now and set a "done" flag or whatever, but note - * that it SHOULD NOT DESTROY THE PNG STRUCTS YET--in other words, do - * NOT call readpng2_cleanup() either here or in the finish_display() - * routine; wait until control returns to the main program via - * readpng2_decode_data() */ - - (*mainprog_ptr->mainprog_finish_display)(); - - - /* all done */ - - return; -} - - - - - -void readpng2_cleanup(mainprog_info *mainprog_ptr) -{ - png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; - png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; - - if (png_ptr && info_ptr) - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - - mainprog_ptr->png_ptr = NULL; - mainprog_ptr->info_ptr = NULL; -} - - -static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg) -{ - fprintf(stderr, "readpng2 libpng warning: %s\n", msg); - fflush(stderr); -} - - -static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg) -{ - mainprog_info *mainprog_ptr; - - /* This function, aside from the extra step of retrieving the "error - * pointer" (below) and the fact that it exists within the application - * rather than within libpng, is essentially identical to libpng's - * default error handler. The second point is critical: since both - * setjmp() and longjmp() are called from the same code, they are - * guaranteed to have compatible notions of how big a jmp_buf is, - * regardless of whether _BSD_SOURCE or anything else has (or has not) - * been defined. */ - - fprintf(stderr, "readpng2 libpng error: %s\n", msg); - fflush(stderr); - - mainprog_ptr = png_get_error_ptr(png_ptr); - if (mainprog_ptr == NULL) { /* we are completely hosed now */ - fprintf(stderr, - "readpng2 severe error: jmpbuf not recoverable; terminating.\n"); - fflush(stderr); - exit(99); - } - - /* Now we have our data structure we can use the information in it - * to return control to our own higher level code (all the points - * where 'setjmp' is called in this file.) This will work with other - * error handling mechanisms as well - libpng always calls png_error - * when it can proceed no further, thus, so long as the error handler - * is intercepted, application code can do its own error recovery. - */ - longjmp(mainprog_ptr->jmpbuf, 1); -} +/*--------------------------------------------------------------------------- + + rpng2 - progressive-model PNG display program readpng2.c + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + + +#include /* for exit() prototype */ +#include + +#include +#include "png.h" /* libpng header from the local directory */ +#include "readpng2.h" /* typedefs, common macros, public prototypes */ + + +/* local prototypes */ + +static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr); +static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass); +static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr); +static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg); +static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg); + + + + +void readpng2_version_info(void) +{ + fprintf(stderr, " Compiled with libpng %s; using libpng %s\n", + PNG_LIBPNG_VER_STRING, png_libpng_ver); + + fprintf(stderr, " and with zlib %s; using zlib %s.\n", + ZLIB_VERSION, zlib_version); +} + + + + +int readpng2_check_sig(uch *sig, int num) +{ + return !png_sig_cmp(sig, 0, num); +} + + + + +/* returns 0 for success, 2 for libpng problem, 4 for out of memory */ + +int readpng2_init(mainprog_info *mainprog_ptr) +{ + png_structp png_ptr; /* note: temporary variables! */ + png_infop info_ptr; + + + /* could also replace libpng warning-handler (final NULL), but no need: */ + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, + readpng2_error_handler, readpng2_warning_handler); + if (!png_ptr) + return 4; /* out of memory */ + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + return 4; /* out of memory */ + } + + + /* we could create a second info struct here (end_info), but it's only + * useful if we want to keep pre- and post-IDAT chunk info separated + * (mainly for PNG-aware image editors and converters) */ + + + /* setjmp() must be called in every function that calls a PNG-reading + * libpng function, unless an alternate error handler was installed-- + * but compatible error handlers must either use longjmp() themselves + * (as in this program) or exit immediately, so here we are: */ + + if (setjmp(mainprog_ptr->jmpbuf)) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 2; + } + + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + /* prepare the reader to ignore all recognized chunks whose data won't be + * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT, + * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */ + { + /* These byte strings were copied from png.h. If a future version + * of readpng2.c recognizes more chunks, add them to this list. + */ + static PNG_CONST png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 103, 65, 77, 65, '\0', /* gAMA */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */ + png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */, + NULL, -1); + + /* But do not ignore chunks in the "chunks_to_process" list */ + png_set_keep_unknown_chunks(png_ptr, + 0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process, + sizeof(chunks_to_process)/5); + } +#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ + + + /* instead of doing png_init_io() here, now we set up our callback + * functions for progressive decoding */ + + png_set_progressive_read_fn(png_ptr, mainprog_ptr, + readpng2_info_callback, readpng2_row_callback, readpng2_end_callback); + + + /* make sure we save our pointers for use in readpng2_decode_data() */ + + mainprog_ptr->png_ptr = png_ptr; + mainprog_ptr->info_ptr = info_ptr; + + + /* and that's all there is to initialization */ + + return 0; +} + + + + +/* returns 0 for success, 2 for libpng (longjmp) problem */ + +int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length) +{ + png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; + png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; + + + /* setjmp() must be called in every function that calls a PNG-reading + * libpng function */ + + if (setjmp(mainprog_ptr->jmpbuf)) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + mainprog_ptr->png_ptr = NULL; + mainprog_ptr->info_ptr = NULL; + return 2; + } + + + /* hand off the next chunk of input data to libpng for decoding */ + + png_process_data(png_ptr, info_ptr, rawbuf, length); + + return 0; +} + + + + +static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr) +{ + mainprog_info *mainprog_ptr; + int color_type, bit_depth; + png_uint_32 width, height; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double gamma; +#else + png_fixed_point gamma; +#endif + + + /* setjmp() doesn't make sense here, because we'd either have to exit(), + * longjmp() ourselves, or return control to libpng, which doesn't want + * to see us again. By not doing anything here, libpng will instead jump + * to readpng2_decode_data(), which can return an error value to the main + * program. */ + + + /* retrieve the pointer to our special-purpose struct, using the png_ptr + * that libpng passed back to us (i.e., not a global this time--there's + * no real difference for a single image, but for a multithreaded browser + * decoding several PNG images at the same time, one needs to avoid mixing + * up different images' structs) */ + + mainprog_ptr = png_get_progressive_ptr(png_ptr); + + if (mainprog_ptr == NULL) { /* we be hosed */ + fprintf(stderr, + "readpng2 error: main struct not recoverable in info_callback.\n"); + fflush(stderr); + return; + /* + * Alternatively, we could call our error-handler just like libpng + * does, which would effectively terminate the program. Since this + * can only happen if png_ptr gets redirected somewhere odd or the + * main PNG struct gets wiped, we're probably toast anyway. (If + * png_ptr itself is NULL, we would not have been called.) + */ + } + + + /* this is just like in the non-progressive case */ + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + mainprog_ptr->width = (ulg)width; + mainprog_ptr->height = (ulg)height; + + + /* since we know we've read all of the PNG file's "header" (i.e., up + * to IDAT), we can check for a background color here */ + + if (mainprog_ptr->need_bgcolor && + png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) + { + png_color_16p pBackground; + + /* it is not obvious from the libpng documentation, but this function + * takes a pointer to a pointer, and it always returns valid red, + * green and blue values, regardless of color_type: */ + png_get_bKGD(png_ptr, info_ptr, &pBackground); + + /* however, it always returns the raw bKGD data, regardless of any + * bit-depth transformations, so check depth and adjust if necessary */ + if (bit_depth == 16) { + mainprog_ptr->bg_red = pBackground->red >> 8; + mainprog_ptr->bg_green = pBackground->green >> 8; + mainprog_ptr->bg_blue = pBackground->blue >> 8; + } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { + if (bit_depth == 1) + mainprog_ptr->bg_red = mainprog_ptr->bg_green = + mainprog_ptr->bg_blue = pBackground->gray? 255 : 0; + else if (bit_depth == 2) + mainprog_ptr->bg_red = mainprog_ptr->bg_green = + mainprog_ptr->bg_blue = (255/3) * pBackground->gray; + else /* bit_depth == 4 */ + mainprog_ptr->bg_red = mainprog_ptr->bg_green = + mainprog_ptr->bg_blue = (255/15) * pBackground->gray; + } else { + mainprog_ptr->bg_red = (uch)pBackground->red; + mainprog_ptr->bg_green = (uch)pBackground->green; + mainprog_ptr->bg_blue = (uch)pBackground->blue; + } + } + + + /* as before, let libpng expand palette images to RGB, low-bit-depth + * grayscale images to 8 bits, transparency chunks to full alpha channel; + * strip 16-bit-per-sample images to 8 bits per sample; and convert + * grayscale to RGB[A] */ + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (bit_depth == 16) +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +# else + png_set_strip_16(png_ptr); +# endif +#endif + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + + /* Unlike the basic viewer, which was designed to operate on local files, + * this program is intended to simulate a web browser--even though we + * actually read from a local file, too. But because we are pretending + * that most of the images originate on the Internet, we follow the recom- + * mendation of the sRGB proposal and treat unlabelled images (no gAMA + * chunk) as existing in the sRGB color space. That is, we assume that + * such images have a file gamma of 0.45455, which corresponds to a PC-like + * display system. This change in assumptions will have no effect on a + * PC-like system, but on a Mac, SGI, NeXT or other system with a non- + * identity lookup table, it will darken unlabelled images, which effec- + * tively favors images from PC-like systems over those originating on + * the local platform. Note that mainprog_ptr->display_exponent is the + * "gamma" value for the entire display system, i.e., the product of + * LUT_exponent and CRT_exponent. */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma); + else + png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455); +#else + if (png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) + png_set_gamma_fixed(png_ptr, + (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), gamma); + else + png_set_gamma_fixed(png_ptr, + (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), 45455); +#endif + + /* we'll let libpng expand interlaced images, too */ + + mainprog_ptr->passes = png_set_interlace_handling(png_ptr); + + + /* all transformations have been registered; now update info_ptr data and + * then get rowbytes and channels */ + + png_read_update_info(png_ptr, info_ptr); + + mainprog_ptr->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr); + mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr); + + + /* Call the main program to allocate memory for the image buffer and + * initialize windows and whatnot. (The old-style function-pointer + * invocation is used for compatibility with a few supposedly ANSI + * compilers that nevertheless barf on "fn_ptr()"-style syntax.) */ + + (*mainprog_ptr->mainprog_init)(); + + + /* and that takes care of initialization */ + + return; +} + + + + + +static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ + mainprog_info *mainprog_ptr; + + + /* first check whether the row differs from the previous pass; if not, + * nothing to combine or display */ + + if (!new_row) + return; + + + /* retrieve the pointer to our special-purpose struct so we can access + * the old rows and image-display callback function */ + + mainprog_ptr = png_get_progressive_ptr(png_ptr); + + + /* save the pass number for optional use by the front end */ + + mainprog_ptr->pass = pass; + + + /* have libpng either combine the new row data with the existing row data + * from previous passes (if interlaced) or else just copy the new row + * into the main program's image buffer */ + + png_progressive_combine_row(png_ptr, mainprog_ptr->row_pointers[row_num], + new_row); + + + /* finally, call the display routine in the main program with the number + * of the row we just updated */ + + (*mainprog_ptr->mainprog_display_row)(row_num); + + + /* and we're ready for more */ + + return; +} + + + + + +static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr) +{ + mainprog_info *mainprog_ptr; + + + /* retrieve the pointer to our special-purpose struct */ + + mainprog_ptr = png_get_progressive_ptr(png_ptr); + + + /* let the main program know that it should flush any buffered image + * data to the display now and set a "done" flag or whatever, but note + * that it SHOULD NOT DESTROY THE PNG STRUCTS YET--in other words, do + * NOT call readpng2_cleanup() either here or in the finish_display() + * routine; wait until control returns to the main program via + * readpng2_decode_data() */ + + (*mainprog_ptr->mainprog_finish_display)(); + + + /* all done */ + + return; +} + + + + + +void readpng2_cleanup(mainprog_info *mainprog_ptr) +{ + png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; + png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; + + if (png_ptr && info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + mainprog_ptr->png_ptr = NULL; + mainprog_ptr->info_ptr = NULL; +} + + +static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg) +{ + fprintf(stderr, "readpng2 libpng warning: %s\n", msg); + fflush(stderr); +} + + +static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg) +{ + mainprog_info *mainprog_ptr; + + /* This function, aside from the extra step of retrieving the "error + * pointer" (below) and the fact that it exists within the application + * rather than within libpng, is essentially identical to libpng's + * default error handler. The second point is critical: since both + * setjmp() and longjmp() are called from the same code, they are + * guaranteed to have compatible notions of how big a jmp_buf is, + * regardless of whether _BSD_SOURCE or anything else has (or has not) + * been defined. */ + + fprintf(stderr, "readpng2 libpng error: %s\n", msg); + fflush(stderr); + + mainprog_ptr = png_get_error_ptr(png_ptr); + if (mainprog_ptr == NULL) { /* we are completely hosed now */ + fprintf(stderr, + "readpng2 severe error: jmpbuf not recoverable; terminating.\n"); + fflush(stderr); + exit(99); + } + + /* Now we have our data structure we can use the information in it + * to return control to our own higher level code (all the points + * where 'setjmp' is called in this file.) This will work with other + * error handling mechanisms as well - libpng always calls png_error + * when it can proceed no further, thus, so long as the error handler + * is intercepted, application code can do its own error recovery. + */ + longjmp(mainprog_ptr->jmpbuf, 1); +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/readpng2.h b/main/source/includes/lpng1610/contrib/gregbook/readpng2.h index 7a592637..6b3660d7 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/readpng2.h +++ b/main/source/includes/lpng1610/contrib/gregbook/readpng2.h @@ -1,116 +1,116 @@ -/*--------------------------------------------------------------------------- - - rpng2 - progressive-model PNG display program readpng2.h - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#ifndef MAX -# define MAX(a,b) ((a) > (b)? (a) : (b)) -# define MIN(a,b) ((a) < (b)? (a) : (b)) -#endif - -#ifdef DEBUG -# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} -#else -# define Trace(x) ; -#endif - -enum rpng2_states { - kPreInit = 0, - kWindowInit, - kDone -}; - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -typedef struct _mainprog_info { - double display_exponent; - ulg width; - ulg height; - void *png_ptr; - void *info_ptr; - void (*mainprog_init)(void); - void (*mainprog_display_row)(ulg row_num); - void (*mainprog_finish_display)(void); - uch *image_data; - uch **row_pointers; - jmp_buf jmpbuf; - int passes; /* not used */ - int pass; - int rowbytes; - int channels; - int need_bgcolor; - int state; - uch bg_red; - uch bg_green; - uch bg_blue; -} mainprog_info; - - -/* prototypes for public functions in readpng2.c */ - -void readpng2_version_info(void); - -int readpng2_check_sig(uch *sig, int num); - -int readpng2_init(mainprog_info *mainprog_ptr); - -int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length); - -void readpng2_cleanup(mainprog_info *mainprog_ptr); +/*--------------------------------------------------------------------------- + + rpng2 - progressive-model PNG display program readpng2.h + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b)? (a) : (b)) +# define MIN(a,b) ((a) < (b)? (a) : (b)) +#endif + +#ifdef DEBUG +# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} +#else +# define Trace(x) ; +#endif + +enum rpng2_states { + kPreInit = 0, + kWindowInit, + kDone +}; + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +typedef struct _mainprog_info { + double display_exponent; + ulg width; + ulg height; + void *png_ptr; + void *info_ptr; + void (*mainprog_init)(void); + void (*mainprog_display_row)(ulg row_num); + void (*mainprog_finish_display)(void); + uch *image_data; + uch **row_pointers; + jmp_buf jmpbuf; + int passes; /* not used */ + int pass; + int rowbytes; + int channels; + int need_bgcolor; + int state; + uch bg_red; + uch bg_green; + uch bg_blue; +} mainprog_info; + + +/* prototypes for public functions in readpng2.c */ + +void readpng2_version_info(void); + +int readpng2_check_sig(uch *sig, int num); + +int readpng2_init(mainprog_info *mainprog_ptr); + +int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length); + +void readpng2_cleanup(mainprog_info *mainprog_ptr); diff --git a/main/source/includes/lpng1610/contrib/gregbook/readppm.c b/main/source/includes/lpng1610/contrib/gregbook/readppm.c index 1ba20921..be9a56d9 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/readppm.c +++ b/main/source/includes/lpng1610/contrib/gregbook/readppm.c @@ -1,179 +1,179 @@ -/*--------------------------------------------------------------------------- - - rpng - simple PNG display program readppm.c - - --------------------------------------------------------------------------- - - This is a special-purpose replacement for readpng.c that allows binary - PPM files to be used in place of PNG images. - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#include -#include - -#include "readpng.h" /* typedefs, common macros, public prototypes */ - - -ulg width, height; -int bit_depth, color_type, channels; -uch *image_data = NULL; -FILE *saved_infile; - - -void readpng_version_info() -{ - fprintf(stderr, " Compiled without libpng, zlib or PBMPLUS/NetPBM.\n"); -} - - -/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ - -int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) -{ - static uch ppmline[256]; - int maxval; - - - saved_infile = infile; - - fgets(ppmline, 256, infile); - if (ppmline[0] != 'P' || ppmline[1] != '6') { - fprintf(stderr, "ERROR: not a PPM file\n"); - return 1; - } - /* possible color types: P5 = grayscale (0), P6 = RGB (2), P8 = RGBA (6) */ - if (ppmline[1] == '6') { - color_type = 2; - channels = 3; - } else if (ppmline[1] == '8') { - color_type = 6; - channels = 4; - } else /* if (ppmline[1] == '5') */ { - color_type = 0; - channels = 1; - } - - do { - fgets(ppmline, 256, infile); - } while (ppmline[0] == '#'); - sscanf(ppmline, "%lu %lu", &width, &height); - - do { - fgets(ppmline, 256, infile); - } while (ppmline[0] == '#'); - sscanf(ppmline, "%d", &maxval); - if (maxval != 255) { - fprintf(stderr, "ERROR: maxval = %d\n", maxval); - return 2; - } - bit_depth = 8; - - *pWidth = width; - *pHeight = height; - - return 0; -} - - - - -/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; - * scales values to 8-bit if necessary */ - -int readpng_get_bgcolor(uch *red, uch *green, uch *blue) -{ - return 1; -} - - - - -/* display_exponent == LUT_exponent * CRT_exponent */ - -uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) -{ - ulg rowbytes; - - - /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, - * transparency chunks to full alpha channel; strip 16-bit-per-sample - * images to 8 bits per sample; and convert grayscale to RGB[A] */ - - /* GRR WARNING: grayscale needs to be expanded and channels reset! */ - - *pRowbytes = rowbytes = channels*width; - *pChannels = channels; - - if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { - return NULL; - } - - Trace((stderr, "readpng_get_image: rowbytes = %ld, height = %ld\n", rowbytes, height)); - - - /* now we can go ahead and just read the whole image */ - - fread(image_data, 1L, rowbytes*height, saved_infile); - - - return image_data; -} - - -void readpng_cleanup(int free_image_data) -{ - if (free_image_data && image_data) { - free(image_data); - image_data = NULL; - } -} +/*--------------------------------------------------------------------------- + + rpng - simple PNG display program readppm.c + + --------------------------------------------------------------------------- + + This is a special-purpose replacement for readpng.c that allows binary + PPM files to be used in place of PNG images. + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#include +#include + +#include "readpng.h" /* typedefs, common macros, public prototypes */ + + +ulg width, height; +int bit_depth, color_type, channels; +uch *image_data = NULL; +FILE *saved_infile; + + +void readpng_version_info() +{ + fprintf(stderr, " Compiled without libpng, zlib or PBMPLUS/NetPBM.\n"); +} + + +/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ + +int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) +{ + static uch ppmline[256]; + int maxval; + + + saved_infile = infile; + + fgets(ppmline, 256, infile); + if (ppmline[0] != 'P' || ppmline[1] != '6') { + fprintf(stderr, "ERROR: not a PPM file\n"); + return 1; + } + /* possible color types: P5 = grayscale (0), P6 = RGB (2), P8 = RGBA (6) */ + if (ppmline[1] == '6') { + color_type = 2; + channels = 3; + } else if (ppmline[1] == '8') { + color_type = 6; + channels = 4; + } else /* if (ppmline[1] == '5') */ { + color_type = 0; + channels = 1; + } + + do { + fgets(ppmline, 256, infile); + } while (ppmline[0] == '#'); + sscanf(ppmline, "%lu %lu", &width, &height); + + do { + fgets(ppmline, 256, infile); + } while (ppmline[0] == '#'); + sscanf(ppmline, "%d", &maxval); + if (maxval != 255) { + fprintf(stderr, "ERROR: maxval = %d\n", maxval); + return 2; + } + bit_depth = 8; + + *pWidth = width; + *pHeight = height; + + return 0; +} + + + + +/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; + * scales values to 8-bit if necessary */ + +int readpng_get_bgcolor(uch *red, uch *green, uch *blue) +{ + return 1; +} + + + + +/* display_exponent == LUT_exponent * CRT_exponent */ + +uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) +{ + ulg rowbytes; + + + /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, + * transparency chunks to full alpha channel; strip 16-bit-per-sample + * images to 8 bits per sample; and convert grayscale to RGB[A] */ + + /* GRR WARNING: grayscale needs to be expanded and channels reset! */ + + *pRowbytes = rowbytes = channels*width; + *pChannels = channels; + + if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { + return NULL; + } + + Trace((stderr, "readpng_get_image: rowbytes = %ld, height = %ld\n", rowbytes, height)); + + + /* now we can go ahead and just read the whole image */ + + fread(image_data, 1L, rowbytes*height, saved_infile); + + + return image_data; +} + + +void readpng_cleanup(int free_image_data) +{ + if (free_image_data && image_data) { + free(image_data); + image_data = NULL; + } +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/rpng-win.c b/main/source/includes/lpng1610/contrib/gregbook/rpng-win.c index 1c22282c..f53ddc8e 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/rpng-win.c +++ b/main/source/includes/lpng1610/contrib/gregbook/rpng-win.c @@ -1,728 +1,728 @@ -/*--------------------------------------------------------------------------- - - rpng - simple PNG display program rpng-win.c - - This program decodes and displays PNG images, with gamma correction and - optionally with a user-specified background color (in case the image has - transparency). It is very nearly the most basic PNG viewer possible. - This version is for 32-bit Windows; it may compile under 16-bit Windows - with a little tweaking (or maybe not). - - to do: - - handle quoted command-line args (especially filenames with spaces) - - have minimum window width: oh well - - use %.1023s to simplify truncation of title-bar string? - - --------------------------------------------------------------------------- - - Changelog: - - 1.00: initial public release - - 1.01: modified to allow abbreviated options; fixed long/ulong mis- - match; switched to png_jmpbuf() macro - - 1.02: added extra set of parentheses to png_jmpbuf() macro; fixed - command-line parsing bug - - 1.10: enabled "message window"/console (thanks to David Geldreich) - - 2.00: dual-licensed (added GNU GPL) - - 2.01: fixed improper display of usage screen on PNG error(s) - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#define PROGNAME "rpng-win" -#define LONGNAME "Simple PNG Viewer for Windows" -#define VERSION "2.01 of 16 March 2008" - -#include -#include -#include -#include -#include -#ifdef __CYGWIN__ -/* getch replacement. Turns out, we don't really need this, - * but leave it here if we ever enable any of the uses of - * _getch in the main code - */ -#include -#include -#include -int repl_getch( void ) -{ - char ch; - int fd = fileno(stdin); - struct termio old_tty, new_tty; - - ioctl(fd, TCGETA, &old_tty); - new_tty = old_tty; - new_tty.c_lflag &= ~(ICANON | ECHO | ISIG); - ioctl(fd, TCSETA, &new_tty); - fread(&ch, 1, sizeof(ch), stdin); - ioctl(fd, TCSETA, &old_tty); - - return ch; -} -#define _getch repl_getch -#else -#include /* only for _getch() */ -#endif - -/* #define DEBUG : this enables the Trace() macros */ - -#include "readpng.h" /* typedefs, common macros, readpng prototypes */ - - -/* could just include png.h, but this macro is the only thing we need - * (name and typedefs changed to local versions); note that side effects - * only happen with alpha (which could easily be avoided with - * "ush acopy = (alpha);") */ - -#define alpha_composite(composite, fg, alpha, bg) { \ - ush temp = ((ush)(fg)*(ush)(alpha) + \ - (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \ - (composite) = (uch)((temp + (temp >> 8)) >> 8); \ -} - - -/* local prototypes */ -static int rpng_win_create_window(HINSTANCE hInst, int showmode); -static int rpng_win_display_image(void); -static void rpng_win_cleanup(void); -LRESULT CALLBACK rpng_win_wndproc(HWND, UINT, WPARAM, LPARAM); - - -static char titlebar[1024]; -static char *progname = PROGNAME; -static char *appname = LONGNAME; -static char *filename; -static FILE *infile; - -static char *bgstr; -static uch bg_red=0, bg_green=0, bg_blue=0; - -static double display_exponent; - -static ulg image_width, image_height, image_rowbytes; -static int image_channels; -static uch *image_data; - -/* Windows-specific variables */ -static ulg wimage_rowbytes; -static uch *dib; -static uch *wimage_data; -static BITMAPINFOHEADER *bmih; - -static HWND global_hwnd; - - - - -int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode) -{ - char *args[1024]; /* arbitrary limit, but should suffice */ - char *p, *q, **argv = args; - int argc = 0; - int rc, alen, flen; - int error = 0; - int have_bg = FALSE; - double LUT_exponent; /* just the lookup table */ - double CRT_exponent = 2.2; /* just the monitor */ - double default_display_exponent; /* whole display system */ - MSG msg; - - - filename = (char *)NULL; - -#ifndef __CYGWIN__ - /* First reenable console output, which normally goes to the bit bucket - * for windowed apps. Closing the console window will terminate the - * app. Thanks to David.Geldreich@realviz.com for supplying the magical - * incantation. */ - - AllocConsole(); - freopen("CONOUT$", "a", stderr); - freopen("CONOUT$", "a", stdout); -#endif - - - /* Next set the default value for our display-system exponent, i.e., - * the product of the CRT exponent and the exponent corresponding to - * the frame-buffer's lookup table (LUT), if any. This is not an - * exhaustive list of LUT values (e.g., OpenStep has a lot of weird - * ones), but it should cover 99% of the current possibilities. And - * yes, these ifdefs are completely wasted in a Windows program... */ - -#if defined(NeXT) - LUT_exponent = 1.0 / 2.2; - /* - if (some_next_function_that_returns_gamma(&next_gamma)) - LUT_exponent = 1.0 / next_gamma; - */ -#elif defined(sgi) - LUT_exponent = 1.0 / 1.7; - /* there doesn't seem to be any documented function to get the - * "gamma" value, so we do it the hard way */ - infile = fopen("/etc/config/system.glGammaVal", "r"); - if (infile) { - double sgi_gamma; - - fgets(tmpline, 80, infile); - fclose(infile); - sgi_gamma = atof(tmpline); - if (sgi_gamma > 0.0) - LUT_exponent = 1.0 / sgi_gamma; - } -#elif defined(Macintosh) - LUT_exponent = 1.8 / 2.61; - /* - if (some_mac_function_that_returns_gamma(&mac_gamma)) - LUT_exponent = mac_gamma / 2.61; - */ -#else - LUT_exponent = 1.0; /* assume no LUT: most PCs */ -#endif - - /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ - default_display_exponent = LUT_exponent * CRT_exponent; - - - /* If the user has set the SCREEN_GAMMA environment variable as suggested - * (somewhat imprecisely) in the libpng documentation, use that; otherwise - * use the default value we just calculated. Either way, the user may - * override this via a command-line option. */ - - if ((p = getenv("SCREEN_GAMMA")) != NULL) - display_exponent = atof(p); - else - display_exponent = default_display_exponent; - - - /* Windows really hates command lines, so we have to set up our own argv. - * Note that we do NOT bother with quoted arguments here, so don't use - * filenames with spaces in 'em! */ - - argv[argc++] = PROGNAME; - p = cmd; - for (;;) { - if (*p == ' ') - while (*++p == ' ') - ; - /* now p points at the first non-space after some spaces */ - if (*p == '\0') - break; /* nothing after the spaces: done */ - argv[argc++] = q = p; - while (*q && *q != ' ') - ++q; - /* now q points at a space or the end of the string */ - if (*q == '\0') - break; /* last argv already terminated; quit */ - *q = '\0'; /* change space to terminator */ - p = q + 1; - } - argv[argc] = NULL; /* terminate the argv array itself */ - - - /* Now parse the command line for options and the PNG filename. */ - - while (*++argv && !error) { - if (!strncmp(*argv, "-gamma", 2)) { - if (!*++argv) - ++error; - else { - display_exponent = atof(*argv); - if (display_exponent <= 0.0) - ++error; - } - } else if (!strncmp(*argv, "-bgcolor", 2)) { - if (!*++argv) - ++error; - else { - bgstr = *argv; - if (strlen(bgstr) != 7 || bgstr[0] != '#') - ++error; - else - have_bg = TRUE; - } - } else { - if (**argv != '-') { - filename = *argv; - if (argv[1]) /* shouldn't be any more args after filename */ - ++error; - } else - ++error; /* not expecting any other options */ - } - } - - if (!filename) - ++error; - - - /* print usage screen if any errors up to this point */ - - if (error) { -#ifndef __CYGWIN__ - int ch; -#endif - - fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname); - readpng_version_info(); - fprintf(stderr, "\n" - "Usage: %s [-gamma exp] [-bgcolor bg] file.png\n" - " exp \ttransfer-function exponent (``gamma'') of the display\n" - "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" - "\t\t to the product of the lookup-table exponent (varies)\n" - "\t\t and the CRT exponent (usually 2.2); must be positive\n" - " bg \tdesired background color in 7-character hex RGB format\n" - "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" - "\t\t used with transparent images\n" - "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n" -#ifndef __CYGWIN__ - "Press Q or Esc to quit this usage screen.\n" -#endif - "\n", PROGNAME, default_display_exponent); -#ifndef __CYGWIN__ - do - ch = _getch(); - while (ch != 'q' && ch != 'Q' && ch != 0x1B); -#endif - exit(1); - } - - - if (!(infile = fopen(filename, "rb"))) { - fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); - ++error; - } else { - if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) { - switch (rc) { - case 1: - fprintf(stderr, PROGNAME - ": [%s] is not a PNG file: incorrect signature\n", - filename); - break; - case 2: - fprintf(stderr, PROGNAME - ": [%s] has bad IHDR (libpng longjmp)\n", filename); - break; - case 4: - fprintf(stderr, PROGNAME ": insufficient memory\n"); - break; - default: - fprintf(stderr, PROGNAME - ": unknown readpng_init() error\n"); - break; - } - ++error; - } - if (error) - fclose(infile); - } - - - if (error) { -#ifndef __CYGWIN__ - int ch; -#endif - - fprintf(stderr, PROGNAME ": aborting.\n"); -#ifndef __CYGWIN__ - do - ch = _getch(); - while (ch != 'q' && ch != 'Q' && ch != 0x1B); -#endif - exit(2); - } else { - fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); -#ifndef __CYGWIN__ - fprintf(stderr, - "\n [console window: closing this window will terminate %s]\n\n", - PROGNAME); -#endif - } - - - /* set the title-bar string, but make sure buffer doesn't overflow */ - - alen = strlen(appname); - flen = strlen(filename); - if (alen + flen + 3 > 1023) - sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); - else - sprintf(titlebar, "%s: %s", appname, filename); - - - /* if the user didn't specify a background color on the command line, - * check for one in the PNG file--if not, the initialized values of 0 - * (black) will be used */ - - if (have_bg) { - unsigned r, g, b; /* this approach quiets compiler warnings */ - - sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); - bg_red = (uch)r; - bg_green = (uch)g; - bg_blue = (uch)b; - } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) { - readpng_cleanup(TRUE); - fprintf(stderr, PROGNAME - ": libpng error while checking for background color\n"); - exit(2); - } - - - /* do the basic Windows initialization stuff, make the window and fill it - * with the background color */ - - if (rpng_win_create_window(hInst, showmode)) - exit(2); - - - /* decode the image, all at once */ - - Trace((stderr, "calling readpng_get_image()\n")) - image_data = readpng_get_image(display_exponent, &image_channels, - &image_rowbytes); - Trace((stderr, "done with readpng_get_image()\n")) - - - /* done with PNG file, so clean up to minimize memory usage (but do NOT - * nuke image_data!) */ - - readpng_cleanup(FALSE); - fclose(infile); - - if (!image_data) { - fprintf(stderr, PROGNAME ": unable to decode PNG image\n"); - exit(3); - } - - - /* display image (composite with background if requested) */ - - Trace((stderr, "calling rpng_win_display_image()\n")) - if (rpng_win_display_image()) { - free(image_data); - exit(4); - } - Trace((stderr, "done with rpng_win_display_image()\n")) - - - /* wait for the user to tell us when to quit */ - - printf( -#ifndef __CYGWIN__ - "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n" -#else - "Done. Press mouse button 1 (within image window) to quit.\n" -#endif - ); - fflush(stdout); - - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - - /* OK, we're done: clean up all image and Windows resources and go away */ - - rpng_win_cleanup(); - - return msg.wParam; -} - - - - - -static int rpng_win_create_window(HINSTANCE hInst, int showmode) -{ - uch *dest; - int extra_width, extra_height; - ulg i, j; - WNDCLASSEX wndclass; - - -/*--------------------------------------------------------------------------- - Allocate memory for the display-specific version of the image (round up - to multiple of 4 for Windows DIB). - ---------------------------------------------------------------------------*/ - - wimage_rowbytes = ((3*image_width + 3L) >> 2) << 2; - - if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) + - wimage_rowbytes*image_height))) - { - return 4; /* fail */ - } - -/*--------------------------------------------------------------------------- - Initialize the DIB. Negative height means to use top-down BMP ordering - (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8 - implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values - directly => wimage_data begins immediately after BMP header. - ---------------------------------------------------------------------------*/ - - memset(dib, 0, sizeof(BITMAPINFOHEADER)); - bmih = (BITMAPINFOHEADER *)dib; - bmih->biSize = sizeof(BITMAPINFOHEADER); - bmih->biWidth = image_width; - bmih->biHeight = -((long)image_height); - bmih->biPlanes = 1; - bmih->biBitCount = 24; - bmih->biCompression = 0; - wimage_data = dib + sizeof(BITMAPINFOHEADER); - -/*--------------------------------------------------------------------------- - Fill in background color (black by default); data are in BGR order. - ---------------------------------------------------------------------------*/ - - for (j = 0; j < image_height; ++j) { - dest = wimage_data + j*wimage_rowbytes; - for (i = image_width; i > 0; --i) { - *dest++ = bg_blue; - *dest++ = bg_green; - *dest++ = bg_red; - } - } - -/*--------------------------------------------------------------------------- - Set the window parameters. - ---------------------------------------------------------------------------*/ - - memset(&wndclass, 0, sizeof(wndclass)); - - wndclass.cbSize = sizeof(wndclass); - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = rpng_win_wndproc; - wndclass.hInstance = hInst; - wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = progname; - wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - RegisterClassEx(&wndclass); - -/*--------------------------------------------------------------------------- - Finally, create the window. - ---------------------------------------------------------------------------*/ - - extra_width = 2*(GetSystemMetrics(SM_CXBORDER) + - GetSystemMetrics(SM_CXDLGFRAME)); - extra_height = 2*(GetSystemMetrics(SM_CYBORDER) + - GetSystemMetrics(SM_CYDLGFRAME)) + - GetSystemMetrics(SM_CYCAPTION); - - global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, image_width+extra_width, - image_height+extra_height, NULL, NULL, hInst, NULL); - - ShowWindow(global_hwnd, showmode); - UpdateWindow(global_hwnd); - - return 0; - -} /* end function rpng_win_create_window() */ - - - - - -static int rpng_win_display_image() -{ - uch *src, *dest; - uch r, g, b, a; - ulg i, row, lastrow; - RECT rect; - - - Trace((stderr, "beginning display loop (image_channels == %d)\n", - image_channels)) - Trace((stderr, "(width = %ld, rowbytes = %ld, wimage_rowbytes = %d)\n", - image_width, image_rowbytes, wimage_rowbytes)) - - -/*--------------------------------------------------------------------------- - Blast image data to buffer. This whole routine takes place before the - message loop begins, so there's no real point in any pseudo-progressive - display... - ---------------------------------------------------------------------------*/ - - for (lastrow = row = 0; row < image_height; ++row) { - src = image_data + row*image_rowbytes; - dest = wimage_data + row*wimage_rowbytes; - if (image_channels == 3) { - for (i = image_width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - *dest++ = b; - *dest++ = g; /* note reverse order */ - *dest++ = r; - } - } else /* if (image_channels == 4) */ { - for (i = image_width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (a == 255) { - *dest++ = b; - *dest++ = g; - *dest++ = r; - } else if (a == 0) { - *dest++ = bg_blue; - *dest++ = bg_green; - *dest++ = bg_red; - } else { - /* this macro (copied from png.h) composites the - * foreground and background values and puts the - * result into the first argument; there are no - * side effects with the first argument */ - alpha_composite(*dest++, b, a, bg_blue); - alpha_composite(*dest++, g, a, bg_green); - alpha_composite(*dest++, r, a, bg_red); - } - } - } - /* display after every 16 lines */ - if (((row+1) & 0xf) == 0) { - rect.left = 0L; - rect.top = (LONG)lastrow; - rect.right = (LONG)image_width; /* possibly off by one? */ - rect.bottom = (LONG)lastrow + 16L; /* possibly off by one? */ - InvalidateRect(global_hwnd, &rect, FALSE); - UpdateWindow(global_hwnd); /* similar to XFlush() */ - lastrow = row + 1; - } - } - - Trace((stderr, "calling final image-flush routine\n")) - if (lastrow < image_height) { - rect.left = 0L; - rect.top = (LONG)lastrow; - rect.right = (LONG)image_width; /* possibly off by one? */ - rect.bottom = (LONG)image_height; /* possibly off by one? */ - InvalidateRect(global_hwnd, &rect, FALSE); - UpdateWindow(global_hwnd); /* similar to XFlush() */ - } - -/* - last param determines whether or not background is wiped before paint - InvalidateRect(global_hwnd, NULL, TRUE); - UpdateWindow(global_hwnd); - */ - - return 0; -} - - - - - -static void rpng_win_cleanup() -{ - if (image_data) { - free(image_data); - image_data = NULL; - } - - if (dib) { - free(dib); - dib = NULL; - } -} - - - - - -LRESULT CALLBACK rpng_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP) -{ - HDC hdc; - PAINTSTRUCT ps; - int rc; - - switch (iMsg) { - case WM_CREATE: - /* one-time processing here, if any */ - return 0; - - case WM_PAINT: - hdc = BeginPaint(hwnd, &ps); - /* dest */ - rc = StretchDIBits(hdc, 0, 0, image_width, image_height, - /* source */ - 0, 0, image_width, image_height, - wimage_data, (BITMAPINFO *)bmih, - /* iUsage: no clue */ - 0, SRCCOPY); - EndPaint(hwnd, &ps); - return 0; - - /* wait for the user to tell us when to quit */ - case WM_CHAR: - switch (wP) { /* only need one, so ignore repeat count */ - case 'q': - case 'Q': - case 0x1B: /* Esc key */ - PostQuitMessage(0); - } - return 0; - - case WM_LBUTTONDOWN: /* another way of quitting */ - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, iMsg, wP, lP); -} +/*--------------------------------------------------------------------------- + + rpng - simple PNG display program rpng-win.c + + This program decodes and displays PNG images, with gamma correction and + optionally with a user-specified background color (in case the image has + transparency). It is very nearly the most basic PNG viewer possible. + This version is for 32-bit Windows; it may compile under 16-bit Windows + with a little tweaking (or maybe not). + + to do: + - handle quoted command-line args (especially filenames with spaces) + - have minimum window width: oh well + - use %.1023s to simplify truncation of title-bar string? + + --------------------------------------------------------------------------- + + Changelog: + - 1.00: initial public release + - 1.01: modified to allow abbreviated options; fixed long/ulong mis- + match; switched to png_jmpbuf() macro + - 1.02: added extra set of parentheses to png_jmpbuf() macro; fixed + command-line parsing bug + - 1.10: enabled "message window"/console (thanks to David Geldreich) + - 2.00: dual-licensed (added GNU GPL) + - 2.01: fixed improper display of usage screen on PNG error(s) + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#define PROGNAME "rpng-win" +#define LONGNAME "Simple PNG Viewer for Windows" +#define VERSION "2.01 of 16 March 2008" + +#include +#include +#include +#include +#include +#ifdef __CYGWIN__ +/* getch replacement. Turns out, we don't really need this, + * but leave it here if we ever enable any of the uses of + * _getch in the main code + */ +#include +#include +#include +int repl_getch( void ) +{ + char ch; + int fd = fileno(stdin); + struct termio old_tty, new_tty; + + ioctl(fd, TCGETA, &old_tty); + new_tty = old_tty; + new_tty.c_lflag &= ~(ICANON | ECHO | ISIG); + ioctl(fd, TCSETA, &new_tty); + fread(&ch, 1, sizeof(ch), stdin); + ioctl(fd, TCSETA, &old_tty); + + return ch; +} +#define _getch repl_getch +#else +#include /* only for _getch() */ +#endif + +/* #define DEBUG : this enables the Trace() macros */ + +#include "readpng.h" /* typedefs, common macros, readpng prototypes */ + + +/* could just include png.h, but this macro is the only thing we need + * (name and typedefs changed to local versions); note that side effects + * only happen with alpha (which could easily be avoided with + * "ush acopy = (alpha);") */ + +#define alpha_composite(composite, fg, alpha, bg) { \ + ush temp = ((ush)(fg)*(ush)(alpha) + \ + (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \ + (composite) = (uch)((temp + (temp >> 8)) >> 8); \ +} + + +/* local prototypes */ +static int rpng_win_create_window(HINSTANCE hInst, int showmode); +static int rpng_win_display_image(void); +static void rpng_win_cleanup(void); +LRESULT CALLBACK rpng_win_wndproc(HWND, UINT, WPARAM, LPARAM); + + +static char titlebar[1024]; +static char *progname = PROGNAME; +static char *appname = LONGNAME; +static char *filename; +static FILE *infile; + +static char *bgstr; +static uch bg_red=0, bg_green=0, bg_blue=0; + +static double display_exponent; + +static ulg image_width, image_height, image_rowbytes; +static int image_channels; +static uch *image_data; + +/* Windows-specific variables */ +static ulg wimage_rowbytes; +static uch *dib; +static uch *wimage_data; +static BITMAPINFOHEADER *bmih; + +static HWND global_hwnd; + + + + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode) +{ + char *args[1024]; /* arbitrary limit, but should suffice */ + char *p, *q, **argv = args; + int argc = 0; + int rc, alen, flen; + int error = 0; + int have_bg = FALSE; + double LUT_exponent; /* just the lookup table */ + double CRT_exponent = 2.2; /* just the monitor */ + double default_display_exponent; /* whole display system */ + MSG msg; + + + filename = (char *)NULL; + +#ifndef __CYGWIN__ + /* First reenable console output, which normally goes to the bit bucket + * for windowed apps. Closing the console window will terminate the + * app. Thanks to David.Geldreich@realviz.com for supplying the magical + * incantation. */ + + AllocConsole(); + freopen("CONOUT$", "a", stderr); + freopen("CONOUT$", "a", stdout); +#endif + + + /* Next set the default value for our display-system exponent, i.e., + * the product of the CRT exponent and the exponent corresponding to + * the frame-buffer's lookup table (LUT), if any. This is not an + * exhaustive list of LUT values (e.g., OpenStep has a lot of weird + * ones), but it should cover 99% of the current possibilities. And + * yes, these ifdefs are completely wasted in a Windows program... */ + +#if defined(NeXT) + LUT_exponent = 1.0 / 2.2; + /* + if (some_next_function_that_returns_gamma(&next_gamma)) + LUT_exponent = 1.0 / next_gamma; + */ +#elif defined(sgi) + LUT_exponent = 1.0 / 1.7; + /* there doesn't seem to be any documented function to get the + * "gamma" value, so we do it the hard way */ + infile = fopen("/etc/config/system.glGammaVal", "r"); + if (infile) { + double sgi_gamma; + + fgets(tmpline, 80, infile); + fclose(infile); + sgi_gamma = atof(tmpline); + if (sgi_gamma > 0.0) + LUT_exponent = 1.0 / sgi_gamma; + } +#elif defined(Macintosh) + LUT_exponent = 1.8 / 2.61; + /* + if (some_mac_function_that_returns_gamma(&mac_gamma)) + LUT_exponent = mac_gamma / 2.61; + */ +#else + LUT_exponent = 1.0; /* assume no LUT: most PCs */ +#endif + + /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ + default_display_exponent = LUT_exponent * CRT_exponent; + + + /* If the user has set the SCREEN_GAMMA environment variable as suggested + * (somewhat imprecisely) in the libpng documentation, use that; otherwise + * use the default value we just calculated. Either way, the user may + * override this via a command-line option. */ + + if ((p = getenv("SCREEN_GAMMA")) != NULL) + display_exponent = atof(p); + else + display_exponent = default_display_exponent; + + + /* Windows really hates command lines, so we have to set up our own argv. + * Note that we do NOT bother with quoted arguments here, so don't use + * filenames with spaces in 'em! */ + + argv[argc++] = PROGNAME; + p = cmd; + for (;;) { + if (*p == ' ') + while (*++p == ' ') + ; + /* now p points at the first non-space after some spaces */ + if (*p == '\0') + break; /* nothing after the spaces: done */ + argv[argc++] = q = p; + while (*q && *q != ' ') + ++q; + /* now q points at a space or the end of the string */ + if (*q == '\0') + break; /* last argv already terminated; quit */ + *q = '\0'; /* change space to terminator */ + p = q + 1; + } + argv[argc] = NULL; /* terminate the argv array itself */ + + + /* Now parse the command line for options and the PNG filename. */ + + while (*++argv && !error) { + if (!strncmp(*argv, "-gamma", 2)) { + if (!*++argv) + ++error; + else { + display_exponent = atof(*argv); + if (display_exponent <= 0.0) + ++error; + } + } else if (!strncmp(*argv, "-bgcolor", 2)) { + if (!*++argv) + ++error; + else { + bgstr = *argv; + if (strlen(bgstr) != 7 || bgstr[0] != '#') + ++error; + else + have_bg = TRUE; + } + } else { + if (**argv != '-') { + filename = *argv; + if (argv[1]) /* shouldn't be any more args after filename */ + ++error; + } else + ++error; /* not expecting any other options */ + } + } + + if (!filename) + ++error; + + + /* print usage screen if any errors up to this point */ + + if (error) { +#ifndef __CYGWIN__ + int ch; +#endif + + fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname); + readpng_version_info(); + fprintf(stderr, "\n" + "Usage: %s [-gamma exp] [-bgcolor bg] file.png\n" + " exp \ttransfer-function exponent (``gamma'') of the display\n" + "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" + "\t\t to the product of the lookup-table exponent (varies)\n" + "\t\t and the CRT exponent (usually 2.2); must be positive\n" + " bg \tdesired background color in 7-character hex RGB format\n" + "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" + "\t\t used with transparent images\n" + "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n" +#ifndef __CYGWIN__ + "Press Q or Esc to quit this usage screen.\n" +#endif + "\n", PROGNAME, default_display_exponent); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + exit(1); + } + + + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); + ++error; + } else { + if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) { + switch (rc) { + case 1: + fprintf(stderr, PROGNAME + ": [%s] is not a PNG file: incorrect signature\n", + filename); + break; + case 2: + fprintf(stderr, PROGNAME + ": [%s] has bad IHDR (libpng longjmp)\n", filename); + break; + case 4: + fprintf(stderr, PROGNAME ": insufficient memory\n"); + break; + default: + fprintf(stderr, PROGNAME + ": unknown readpng_init() error\n"); + break; + } + ++error; + } + if (error) + fclose(infile); + } + + + if (error) { +#ifndef __CYGWIN__ + int ch; +#endif + + fprintf(stderr, PROGNAME ": aborting.\n"); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + exit(2); + } else { + fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); +#ifndef __CYGWIN__ + fprintf(stderr, + "\n [console window: closing this window will terminate %s]\n\n", + PROGNAME); +#endif + } + + + /* set the title-bar string, but make sure buffer doesn't overflow */ + + alen = strlen(appname); + flen = strlen(filename); + if (alen + flen + 3 > 1023) + sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); + else + sprintf(titlebar, "%s: %s", appname, filename); + + + /* if the user didn't specify a background color on the command line, + * check for one in the PNG file--if not, the initialized values of 0 + * (black) will be used */ + + if (have_bg) { + unsigned r, g, b; /* this approach quiets compiler warnings */ + + sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); + bg_red = (uch)r; + bg_green = (uch)g; + bg_blue = (uch)b; + } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) { + readpng_cleanup(TRUE); + fprintf(stderr, PROGNAME + ": libpng error while checking for background color\n"); + exit(2); + } + + + /* do the basic Windows initialization stuff, make the window and fill it + * with the background color */ + + if (rpng_win_create_window(hInst, showmode)) + exit(2); + + + /* decode the image, all at once */ + + Trace((stderr, "calling readpng_get_image()\n")) + image_data = readpng_get_image(display_exponent, &image_channels, + &image_rowbytes); + Trace((stderr, "done with readpng_get_image()\n")) + + + /* done with PNG file, so clean up to minimize memory usage (but do NOT + * nuke image_data!) */ + + readpng_cleanup(FALSE); + fclose(infile); + + if (!image_data) { + fprintf(stderr, PROGNAME ": unable to decode PNG image\n"); + exit(3); + } + + + /* display image (composite with background if requested) */ + + Trace((stderr, "calling rpng_win_display_image()\n")) + if (rpng_win_display_image()) { + free(image_data); + exit(4); + } + Trace((stderr, "done with rpng_win_display_image()\n")) + + + /* wait for the user to tell us when to quit */ + + printf( +#ifndef __CYGWIN__ + "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n" +#else + "Done. Press mouse button 1 (within image window) to quit.\n" +#endif + ); + fflush(stdout); + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + + /* OK, we're done: clean up all image and Windows resources and go away */ + + rpng_win_cleanup(); + + return msg.wParam; +} + + + + + +static int rpng_win_create_window(HINSTANCE hInst, int showmode) +{ + uch *dest; + int extra_width, extra_height; + ulg i, j; + WNDCLASSEX wndclass; + + +/*--------------------------------------------------------------------------- + Allocate memory for the display-specific version of the image (round up + to multiple of 4 for Windows DIB). + ---------------------------------------------------------------------------*/ + + wimage_rowbytes = ((3*image_width + 3L) >> 2) << 2; + + if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) + + wimage_rowbytes*image_height))) + { + return 4; /* fail */ + } + +/*--------------------------------------------------------------------------- + Initialize the DIB. Negative height means to use top-down BMP ordering + (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8 + implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values + directly => wimage_data begins immediately after BMP header. + ---------------------------------------------------------------------------*/ + + memset(dib, 0, sizeof(BITMAPINFOHEADER)); + bmih = (BITMAPINFOHEADER *)dib; + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = image_width; + bmih->biHeight = -((long)image_height); + bmih->biPlanes = 1; + bmih->biBitCount = 24; + bmih->biCompression = 0; + wimage_data = dib + sizeof(BITMAPINFOHEADER); + +/*--------------------------------------------------------------------------- + Fill in background color (black by default); data are in BGR order. + ---------------------------------------------------------------------------*/ + + for (j = 0; j < image_height; ++j) { + dest = wimage_data + j*wimage_rowbytes; + for (i = image_width; i > 0; --i) { + *dest++ = bg_blue; + *dest++ = bg_green; + *dest++ = bg_red; + } + } + +/*--------------------------------------------------------------------------- + Set the window parameters. + ---------------------------------------------------------------------------*/ + + memset(&wndclass, 0, sizeof(wndclass)); + + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = rpng_win_wndproc; + wndclass.hInstance = hInst; + wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = progname; + wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + RegisterClassEx(&wndclass); + +/*--------------------------------------------------------------------------- + Finally, create the window. + ---------------------------------------------------------------------------*/ + + extra_width = 2*(GetSystemMetrics(SM_CXBORDER) + + GetSystemMetrics(SM_CXDLGFRAME)); + extra_height = 2*(GetSystemMetrics(SM_CYBORDER) + + GetSystemMetrics(SM_CYDLGFRAME)) + + GetSystemMetrics(SM_CYCAPTION); + + global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, image_width+extra_width, + image_height+extra_height, NULL, NULL, hInst, NULL); + + ShowWindow(global_hwnd, showmode); + UpdateWindow(global_hwnd); + + return 0; + +} /* end function rpng_win_create_window() */ + + + + + +static int rpng_win_display_image() +{ + uch *src, *dest; + uch r, g, b, a; + ulg i, row, lastrow; + RECT rect; + + + Trace((stderr, "beginning display loop (image_channels == %d)\n", + image_channels)) + Trace((stderr, "(width = %ld, rowbytes = %ld, wimage_rowbytes = %d)\n", + image_width, image_rowbytes, wimage_rowbytes)) + + +/*--------------------------------------------------------------------------- + Blast image data to buffer. This whole routine takes place before the + message loop begins, so there's no real point in any pseudo-progressive + display... + ---------------------------------------------------------------------------*/ + + for (lastrow = row = 0; row < image_height; ++row) { + src = image_data + row*image_rowbytes; + dest = wimage_data + row*wimage_rowbytes; + if (image_channels == 3) { + for (i = image_width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + *dest++ = b; + *dest++ = g; /* note reverse order */ + *dest++ = r; + } + } else /* if (image_channels == 4) */ { + for (i = image_width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (a == 255) { + *dest++ = b; + *dest++ = g; + *dest++ = r; + } else if (a == 0) { + *dest++ = bg_blue; + *dest++ = bg_green; + *dest++ = bg_red; + } else { + /* this macro (copied from png.h) composites the + * foreground and background values and puts the + * result into the first argument; there are no + * side effects with the first argument */ + alpha_composite(*dest++, b, a, bg_blue); + alpha_composite(*dest++, g, a, bg_green); + alpha_composite(*dest++, r, a, bg_red); + } + } + } + /* display after every 16 lines */ + if (((row+1) & 0xf) == 0) { + rect.left = 0L; + rect.top = (LONG)lastrow; + rect.right = (LONG)image_width; /* possibly off by one? */ + rect.bottom = (LONG)lastrow + 16L; /* possibly off by one? */ + InvalidateRect(global_hwnd, &rect, FALSE); + UpdateWindow(global_hwnd); /* similar to XFlush() */ + lastrow = row + 1; + } + } + + Trace((stderr, "calling final image-flush routine\n")) + if (lastrow < image_height) { + rect.left = 0L; + rect.top = (LONG)lastrow; + rect.right = (LONG)image_width; /* possibly off by one? */ + rect.bottom = (LONG)image_height; /* possibly off by one? */ + InvalidateRect(global_hwnd, &rect, FALSE); + UpdateWindow(global_hwnd); /* similar to XFlush() */ + } + +/* + last param determines whether or not background is wiped before paint + InvalidateRect(global_hwnd, NULL, TRUE); + UpdateWindow(global_hwnd); + */ + + return 0; +} + + + + + +static void rpng_win_cleanup() +{ + if (image_data) { + free(image_data); + image_data = NULL; + } + + if (dib) { + free(dib); + dib = NULL; + } +} + + + + + +LRESULT CALLBACK rpng_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP) +{ + HDC hdc; + PAINTSTRUCT ps; + int rc; + + switch (iMsg) { + case WM_CREATE: + /* one-time processing here, if any */ + return 0; + + case WM_PAINT: + hdc = BeginPaint(hwnd, &ps); + /* dest */ + rc = StretchDIBits(hdc, 0, 0, image_width, image_height, + /* source */ + 0, 0, image_width, image_height, + wimage_data, (BITMAPINFO *)bmih, + /* iUsage: no clue */ + 0, SRCCOPY); + EndPaint(hwnd, &ps); + return 0; + + /* wait for the user to tell us when to quit */ + case WM_CHAR: + switch (wP) { /* only need one, so ignore repeat count */ + case 'q': + case 'Q': + case 0x1B: /* Esc key */ + PostQuitMessage(0); + } + return 0; + + case WM_LBUTTONDOWN: /* another way of quitting */ + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, iMsg, wP, lP); +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/rpng-x.c b/main/source/includes/lpng1610/contrib/gregbook/rpng-x.c index fc8be88a..6d10e1b8 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/rpng-x.c +++ b/main/source/includes/lpng1610/contrib/gregbook/rpng-x.c @@ -1,904 +1,904 @@ -/*--------------------------------------------------------------------------- - - rpng - simple PNG display program rpng-x.c - - This program decodes and displays PNG images, with gamma correction and - optionally with a user-specified background color (in case the image has - transparency). It is very nearly the most basic PNG viewer possible. - This version is for the X Window System (tested by author under Unix and - by Martin Zinser under OpenVMS; may work under OS/2 with some tweaking). - - to do: - - 8-bit (colormapped) X support - - use %.1023s to simplify truncation of title-bar string? - - --------------------------------------------------------------------------- - - Changelog: - - 1.01: initial public release - - 1.02: modified to allow abbreviated options; fixed long/ulong mis- - match; switched to png_jmpbuf() macro - - 1.10: added support for non-default visuals; fixed X pixel-conversion - - 1.11: added extra set of parentheses to png_jmpbuf() macro; fixed - command-line parsing bug - - 1.12: fixed some small X memory leaks (thanks to François Petitjean) - - 1.13: fixed XFreeGC() crash bug (thanks to Patrick Welche) - - 1.14: added support for X resources (thanks to Gerhard Niklasch) - - 2.00: dual-licensed (added GNU GPL) - - 2.01: fixed improper display of usage screen on PNG error(s) - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#define PROGNAME "rpng-x" -#define LONGNAME "Simple PNG Viewer for X" -#define VERSION "2.01 of 16 March 2008" -#define RESNAME "rpng" /* our X resource application name */ -#define RESCLASS "Rpng" /* our X resource class name */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG : this enables the Trace() macros */ - -#include "readpng.h" /* typedefs, common macros, readpng prototypes */ - - -/* could just include png.h, but this macro is the only thing we need - * (name and typedefs changed to local versions); note that side effects - * only happen with alpha (which could easily be avoided with - * "ush acopy = (alpha);") */ - -#define alpha_composite(composite, fg, alpha, bg) { \ - ush temp = ((ush)(fg)*(ush)(alpha) + \ - (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \ - (composite) = (uch)((temp + (temp >> 8)) >> 8); \ -} - - -/* local prototypes */ -static int rpng_x_create_window(void); -static int rpng_x_display_image(void); -static void rpng_x_cleanup(void); -static int rpng_x_msb(ulg u32val); - - -static char titlebar[1024], *window_name = titlebar; -static char *appname = LONGNAME; -static char *icon_name = PROGNAME; -static char *res_name = RESNAME; -static char *res_class = RESCLASS; -static char *filename; -static FILE *infile; - -static char *bgstr; -static uch bg_red=0, bg_green=0, bg_blue=0; - -static double display_exponent; - -static ulg image_width, image_height, image_rowbytes; -static int image_channels; -static uch *image_data; - -/* X-specific variables */ -static char *displayname; -static XImage *ximage; -static Display *display; -static int depth; -static Visual *visual; -static XVisualInfo *visual_list; -static int RShift, GShift, BShift; -static ulg RMask, GMask, BMask; -static Window window; -static GC gc; -static Colormap colormap; - -static int have_nondefault_visual = FALSE; -static int have_colormap = FALSE; -static int have_window = FALSE; -static int have_gc = FALSE; -/* -ulg numcolors=0, pixels[256]; -ush reds[256], greens[256], blues[256]; - */ - - - - -int main(int argc, char **argv) -{ -#ifdef sgi - char tmpline[80]; -#endif - char *p; - int rc, alen, flen; - int error = 0; - int have_bg = FALSE; - double LUT_exponent; /* just the lookup table */ - double CRT_exponent = 2.2; /* just the monitor */ - double default_display_exponent; /* whole display system */ - XEvent e; - KeySym k; - - - displayname = (char *)NULL; - filename = (char *)NULL; - - - /* First set the default value for our display-system exponent, i.e., - * the product of the CRT exponent and the exponent corresponding to - * the frame-buffer's lookup table (LUT), if any. This is not an - * exhaustive list of LUT values (e.g., OpenStep has a lot of weird - * ones), but it should cover 99% of the current possibilities. */ - -#if defined(NeXT) - LUT_exponent = 1.0 / 2.2; - /* - if (some_next_function_that_returns_gamma(&next_gamma)) - LUT_exponent = 1.0 / next_gamma; - */ -#elif defined(sgi) - LUT_exponent = 1.0 / 1.7; - /* there doesn't seem to be any documented function to get the - * "gamma" value, so we do it the hard way */ - infile = fopen("/etc/config/system.glGammaVal", "r"); - if (infile) { - double sgi_gamma; - - fgets(tmpline, 80, infile); - fclose(infile); - sgi_gamma = atof(tmpline); - if (sgi_gamma > 0.0) - LUT_exponent = 1.0 / sgi_gamma; - } -#elif defined(Macintosh) - LUT_exponent = 1.8 / 2.61; - /* - if (some_mac_function_that_returns_gamma(&mac_gamma)) - LUT_exponent = mac_gamma / 2.61; - */ -#else - LUT_exponent = 1.0; /* assume no LUT: most PCs */ -#endif - - /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ - default_display_exponent = LUT_exponent * CRT_exponent; - - - /* If the user has set the SCREEN_GAMMA environment variable as suggested - * (somewhat imprecisely) in the libpng documentation, use that; otherwise - * use the default value we just calculated. Either way, the user may - * override this via a command-line option. */ - - if ((p = getenv("SCREEN_GAMMA")) != NULL) - display_exponent = atof(p); - else - display_exponent = default_display_exponent; - - - /* Now parse the command line for options and the PNG filename. */ - - while (*++argv && !error) { - if (!strncmp(*argv, "-display", 2)) { - if (!*++argv) - ++error; - else - displayname = *argv; - } else if (!strncmp(*argv, "-gamma", 2)) { - if (!*++argv) - ++error; - else { - display_exponent = atof(*argv); - if (display_exponent <= 0.0) - ++error; - } - } else if (!strncmp(*argv, "-bgcolor", 2)) { - if (!*++argv) - ++error; - else { - bgstr = *argv; - if (strlen(bgstr) != 7 || bgstr[0] != '#') - ++error; - else - have_bg = TRUE; - } - } else { - if (**argv != '-') { - filename = *argv; - if (argv[1]) /* shouldn't be any more args after filename */ - ++error; - } else - ++error; /* not expecting any other options */ - } - } - - if (!filename) - ++error; - - - /* print usage screen if any errors up to this point */ - - if (error) { - fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); - readpng_version_info(); - fprintf(stderr, "\n" - "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg] file.png\n" - " xdpy\tname of the target X display (e.g., ``hostname:0'')\n" - " exp \ttransfer-function exponent (``gamma'') of the display\n" - "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" - "\t\t to the product of the lookup-table exponent (varies)\n" - "\t\t and the CRT exponent (usually 2.2); must be positive\n" - " bg \tdesired background color in 7-character hex RGB format\n" - "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" - "\t\t used with transparent images\n" - "\nPress Q, Esc or mouse button 1 (within image window, after image\n" - "is displayed) to quit.\n" - "\n", PROGNAME, default_display_exponent); - exit(1); - } - - - if (!(infile = fopen(filename, "rb"))) { - fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); - ++error; - } else { - if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) { - switch (rc) { - case 1: - fprintf(stderr, PROGNAME - ": [%s] is not a PNG file: incorrect signature\n", - filename); - break; - case 2: - fprintf(stderr, PROGNAME - ": [%s] has bad IHDR (libpng longjmp)\n", filename); - break; - case 4: - fprintf(stderr, PROGNAME ": insufficient memory\n"); - break; - default: - fprintf(stderr, PROGNAME - ": unknown readpng_init() error\n"); - break; - } - ++error; - } else { - display = XOpenDisplay(displayname); - if (!display) { - readpng_cleanup(TRUE); - fprintf(stderr, PROGNAME ": can't open X display [%s]\n", - displayname? displayname : "default"); - ++error; - } - } - if (error) - fclose(infile); - } - - - if (error) { - fprintf(stderr, PROGNAME ": aborting.\n"); - exit(2); - } - - - /* set the title-bar string, but make sure buffer doesn't overflow */ - - alen = strlen(appname); - flen = strlen(filename); - if (alen + flen + 3 > 1023) - sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); - else - sprintf(titlebar, "%s: %s", appname, filename); - - - /* if the user didn't specify a background color on the command line, - * check for one in the PNG file--if not, the initialized values of 0 - * (black) will be used */ - - if (have_bg) { - unsigned r, g, b; /* this approach quiets compiler warnings */ - - sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); - bg_red = (uch)r; - bg_green = (uch)g; - bg_blue = (uch)b; - } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) { - readpng_cleanup(TRUE); - fprintf(stderr, PROGNAME - ": libpng error while checking for background color\n"); - exit(2); - } - - - /* do the basic X initialization stuff, make the window and fill it - * with the background color */ - - if (rpng_x_create_window()) - exit(2); - - - /* decode the image, all at once */ - - Trace((stderr, "calling readpng_get_image()\n")) - image_data = readpng_get_image(display_exponent, &image_channels, - &image_rowbytes); - Trace((stderr, "done with readpng_get_image()\n")) - - - /* done with PNG file, so clean up to minimize memory usage (but do NOT - * nuke image_data!) */ - - readpng_cleanup(FALSE); - fclose(infile); - - if (!image_data) { - fprintf(stderr, PROGNAME ": unable to decode PNG image\n"); - exit(3); - } - - - /* display image (composite with background if requested) */ - - Trace((stderr, "calling rpng_x_display_image()\n")) - if (rpng_x_display_image()) { - free(image_data); - exit(4); - } - Trace((stderr, "done with rpng_x_display_image()\n")) - - - /* wait for the user to tell us when to quit */ - - printf( - "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n"); - fflush(stdout); - - do - XNextEvent(display, &e); - while (!(e.type == ButtonPress && e.xbutton.button == Button1) && - !(e.type == KeyPress && /* v--- or 1 for shifted keys */ - ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) )); - - - /* OK, we're done: clean up all image and X resources and go away */ - - rpng_x_cleanup(); - - return 0; -} - - - - - -static int rpng_x_create_window(void) -{ - uch *xdata; - int need_colormap = FALSE; - int screen, pad; - ulg bg_pixel = 0L; - ulg attrmask; - Window root; - XEvent e; - XGCValues gcvalues; - XSetWindowAttributes attr; - XTextProperty windowName, *pWindowName = &windowName; - XTextProperty iconName, *pIconName = &iconName; - XVisualInfo visual_info; - XSizeHints *size_hints; - XWMHints *wm_hints; - XClassHint *class_hints; - - - screen = DefaultScreen(display); - depth = DisplayPlanes(display, screen); - root = RootWindow(display, screen); - -#ifdef DEBUG - XSynchronize(display, True); -#endif - -#if 0 -/* GRR: add 8-bit support */ - if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) { - fprintf(stderr, - "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n", - depth); - return 2; - } - - XMatchVisualInfo(display, screen, depth, - (depth == 8)? PseudoColor : TrueColor, &visual_info); - visual = visual_info.visual; -#else - if (depth != 16 && depth != 24 && depth != 32) { - int visuals_matched = 0; - - Trace((stderr, "default depth is %d: checking other visuals\n", - depth)) - - /* 24-bit first */ - visual_info.screen = screen; - visual_info.depth = 24; - visual_list = XGetVisualInfo(display, - VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched); - if (visuals_matched == 0) { -/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */ - fprintf(stderr, "default screen depth %d not supported, and no" - " 24-bit visuals found\n", depth); - return 2; - } - Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n", - visuals_matched)) - visual = visual_list[0].visual; - depth = visual_list[0].depth; -/* - colormap_size = visual_list[0].colormap_size; - visual_class = visual->class; - visualID = XVisualIDFromVisual(visual); - */ - have_nondefault_visual = TRUE; - need_colormap = TRUE; - } else { - XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info); - visual = visual_info.visual; - } -#endif - - RMask = visual->red_mask; - GMask = visual->green_mask; - BMask = visual->blue_mask; - -/* GRR: add/check 8-bit support */ - if (depth == 8 || need_colormap) { - colormap = XCreateColormap(display, root, visual, AllocNone); - if (!colormap) { - fprintf(stderr, "XCreateColormap() failed\n"); - return 2; - } - have_colormap = TRUE; - } - if (depth == 15 || depth == 16) { - RShift = 15 - rpng_x_msb(RMask); /* these are right-shifts */ - GShift = 15 - rpng_x_msb(GMask); - BShift = 15 - rpng_x_msb(BMask); - } else if (depth > 16) { -#define NO_24BIT_MASKS -#ifdef NO_24BIT_MASKS - RShift = rpng_x_msb(RMask) - 7; /* these are left-shifts */ - GShift = rpng_x_msb(GMask) - 7; - BShift = rpng_x_msb(BMask) - 7; -#else - RShift = 7 - rpng_x_msb(RMask); /* these are right-shifts, too */ - GShift = 7 - rpng_x_msb(GMask); - BShift = 7 - rpng_x_msb(BMask); -#endif - } - if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) { - fprintf(stderr, "rpng internal logic error: negative X shift(s)!\n"); - return 2; - } - -/*--------------------------------------------------------------------------- - Finally, create the window. - ---------------------------------------------------------------------------*/ - - attr.backing_store = Always; - attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask; - attrmask = CWBackingStore | CWEventMask; - if (have_nondefault_visual) { - attr.colormap = colormap; - attr.background_pixel = 0; - attr.border_pixel = 1; - attrmask |= CWColormap | CWBackPixel | CWBorderPixel; - } - - window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0, - depth, InputOutput, visual, attrmask, &attr); - - if (window == None) { - fprintf(stderr, "XCreateWindow() failed\n"); - return 2; - } else - have_window = TRUE; - - if (depth == 8) - XSetWindowColormap(display, window, colormap); - - if (!XStringListToTextProperty(&window_name, 1, pWindowName)) - pWindowName = NULL; - if (!XStringListToTextProperty(&icon_name, 1, pIconName)) - pIconName = NULL; - - /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */ - - if ((size_hints = XAllocSizeHints()) != NULL) { - /* window will not be resizable */ - size_hints->flags = PMinSize | PMaxSize; - size_hints->min_width = size_hints->max_width = (int)image_width; - size_hints->min_height = size_hints->max_height = (int)image_height; - } - - if ((wm_hints = XAllocWMHints()) != NULL) { - wm_hints->initial_state = NormalState; - wm_hints->input = True; - /* wm_hints->icon_pixmap = icon_pixmap; */ - wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ; - } - - if ((class_hints = XAllocClassHint()) != NULL) { - class_hints->res_name = res_name; - class_hints->res_class = res_class; - } - - XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0, - size_hints, wm_hints, class_hints); - - /* various properties and hints no longer needed; free memory */ - if (pWindowName) - XFree(pWindowName->value); - if (pIconName) - XFree(pIconName->value); - if (size_hints) - XFree(size_hints); - if (wm_hints) - XFree(wm_hints); - if (class_hints) - XFree(class_hints); - - XMapWindow(display, window); - - gc = XCreateGC(display, window, 0, &gcvalues); - have_gc = TRUE; - -/*--------------------------------------------------------------------------- - Fill window with the specified background color. - ---------------------------------------------------------------------------*/ - - if (depth == 24 || depth == 32) { - bg_pixel = ((ulg)bg_red << RShift) | - ((ulg)bg_green << GShift) | - ((ulg)bg_blue << BShift); - } else if (depth == 16) { - bg_pixel = ((((ulg)bg_red << 8) >> RShift) & RMask) | - ((((ulg)bg_green << 8) >> GShift) & GMask) | - ((((ulg)bg_blue << 8) >> BShift) & BMask); - } else /* depth == 8 */ { - - /* GRR: add 8-bit support */ - - } - - XSetForeground(display, gc, bg_pixel); - XFillRectangle(display, window, gc, 0, 0, image_width, image_height); - -/*--------------------------------------------------------------------------- - Wait for first Expose event to do any drawing, then flush. - ---------------------------------------------------------------------------*/ - - do - XNextEvent(display, &e); - while (e.type != Expose || e.xexpose.count); - - XFlush(display); - -/*--------------------------------------------------------------------------- - Allocate memory for the X- and display-specific version of the image. - ---------------------------------------------------------------------------*/ - - if (depth == 24 || depth == 32) { - xdata = (uch *)malloc(4*image_width*image_height); - pad = 32; - } else if (depth == 16) { - xdata = (uch *)malloc(2*image_width*image_height); - pad = 16; - } else /* depth == 8 */ { - xdata = (uch *)malloc(image_width*image_height); - pad = 8; - } - - if (!xdata) { - fprintf(stderr, PROGNAME ": unable to allocate image memory\n"); - return 4; - } - - ximage = XCreateImage(display, visual, depth, ZPixmap, 0, - (char *)xdata, image_width, image_height, pad, 0); - - if (!ximage) { - fprintf(stderr, PROGNAME ": XCreateImage() failed\n"); - free(xdata); - return 3; - } - - /* to avoid testing the byte order every pixel (or doubling the size of - * the drawing routine with a giant if-test), we arbitrarily set the byte - * order to MSBFirst and let Xlib worry about inverting things on little- - * endian machines (like Linux/x86, old VAXen, etc.)--this is not the most - * efficient approach (the giant if-test would be better), but in the - * interest of clarity, we take the easy way out... */ - - ximage->byte_order = MSBFirst; - - return 0; - -} /* end function rpng_x_create_window() */ - - - - - -static int rpng_x_display_image(void) -{ - uch *src; - char *dest; - uch r, g, b, a; - ulg i, row, lastrow = 0; - ulg pixel; - int ximage_rowbytes = ximage->bytes_per_line; -/* int bpp = ximage->bits_per_pixel; */ - - - Trace((stderr, "beginning display loop (image_channels == %d)\n", - image_channels)) - Trace((stderr, " (width = %ld, rowbytes = %ld, ximage_rowbytes = %d)\n", - image_width, image_rowbytes, ximage_rowbytes)) - Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel)) - Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst? - "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown"))) - - if (depth == 24 || depth == 32) { - ulg red, green, blue; - - for (lastrow = row = 0; row < image_height; ++row) { - src = image_data + row*image_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (image_channels == 3) { - for (i = image_width; i > 0; --i) { - red = *src++; - green = *src++; - blue = *src++; -#ifdef NO_24BIT_MASKS - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - /* GRR BUG: this assumes bpp == 32, but may be 24: */ - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); -#else - red = (RShift < 0)? red << (-RShift) : red >> RShift; - green = (GShift < 0)? green << (-GShift) : green >> GShift; - blue = (BShift < 0)? blue << (-BShift) : blue >> BShift; - pixel = (red & RMask) | (green & GMask) | (blue & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); -#endif - } - } else /* if (image_channels == 4) */ { - for (i = image_width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (a == 255) { - red = r; - green = g; - blue = b; - } else if (a == 0) { - red = bg_red; - green = bg_green; - blue = bg_blue; - } else { - /* this macro (from png.h) composites the foreground - * and background values and puts the result into the - * first argument */ - alpha_composite(red, r, a, bg_red); - alpha_composite(green, g, a, bg_green); - alpha_composite(blue, b, a, bg_blue); - } - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - /* display after every 16 lines */ - if (((row+1) & 0xf) == 0) { - XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, image_width, 16); - XFlush(display); - lastrow = row + 1; - } - } - - } else if (depth == 16) { - ush red, green, blue; - - for (lastrow = row = 0; row < image_height; ++row) { - src = image_data + row*image_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (image_channels == 3) { - for (i = image_width; i > 0; --i) { - red = ((ush)(*src) << 8); - ++src; - green = ((ush)(*src) << 8); - ++src; - blue = ((ush)(*src) << 8); - ++src; - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } else /* if (image_channels == 4) */ { - for (i = image_width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (a == 255) { - red = ((ush)r << 8); - green = ((ush)g << 8); - blue = ((ush)b << 8); - } else if (a == 0) { - red = ((ush)bg_red << 8); - green = ((ush)bg_green << 8); - blue = ((ush)bg_blue << 8); - } else { - /* this macro (from png.h) composites the foreground - * and background values and puts the result back into - * the first argument (== fg byte here: safe) */ - alpha_composite(r, r, a, bg_red); - alpha_composite(g, g, a, bg_green); - alpha_composite(b, b, a, bg_blue); - red = ((ush)r << 8); - green = ((ush)g << 8); - blue = ((ush)b << 8); - } - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - /* display after every 16 lines */ - if (((row+1) & 0xf) == 0) { - XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, image_width, 16); - XFlush(display); - lastrow = row + 1; - } - } - - } else /* depth == 8 */ { - - /* GRR: add 8-bit support */ - - } - - Trace((stderr, "calling final XPutImage()\n")) - if (lastrow < image_height) { - XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, image_width, image_height-lastrow); - XFlush(display); - } - - return 0; -} - - - - -static void rpng_x_cleanup(void) -{ - if (image_data) { - free(image_data); - image_data = NULL; - } - - if (ximage) { - if (ximage->data) { - free(ximage->data); /* we allocated it, so we free it */ - ximage->data = (char *)NULL; /* instead of XDestroyImage() */ - } - XDestroyImage(ximage); - ximage = NULL; - } - - if (have_gc) - XFreeGC(display, gc); - - if (have_window) - XDestroyWindow(display, window); - - if (have_colormap) - XFreeColormap(display, colormap); - - if (have_nondefault_visual) - XFree(visual_list); -} - - - - - -static int rpng_x_msb(ulg u32val) -{ - int i; - - for (i = 31; i >= 0; --i) { - if (u32val & 0x80000000L) - break; - u32val <<= 1; - } - return i; -} +/*--------------------------------------------------------------------------- + + rpng - simple PNG display program rpng-x.c + + This program decodes and displays PNG images, with gamma correction and + optionally with a user-specified background color (in case the image has + transparency). It is very nearly the most basic PNG viewer possible. + This version is for the X Window System (tested by author under Unix and + by Martin Zinser under OpenVMS; may work under OS/2 with some tweaking). + + to do: + - 8-bit (colormapped) X support + - use %.1023s to simplify truncation of title-bar string? + + --------------------------------------------------------------------------- + + Changelog: + - 1.01: initial public release + - 1.02: modified to allow abbreviated options; fixed long/ulong mis- + match; switched to png_jmpbuf() macro + - 1.10: added support for non-default visuals; fixed X pixel-conversion + - 1.11: added extra set of parentheses to png_jmpbuf() macro; fixed + command-line parsing bug + - 1.12: fixed some small X memory leaks (thanks to François Petitjean) + - 1.13: fixed XFreeGC() crash bug (thanks to Patrick Welche) + - 1.14: added support for X resources (thanks to Gerhard Niklasch) + - 2.00: dual-licensed (added GNU GPL) + - 2.01: fixed improper display of usage screen on PNG error(s) + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#define PROGNAME "rpng-x" +#define LONGNAME "Simple PNG Viewer for X" +#define VERSION "2.01 of 16 March 2008" +#define RESNAME "rpng" /* our X resource application name */ +#define RESCLASS "Rpng" /* our X resource class name */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG : this enables the Trace() macros */ + +#include "readpng.h" /* typedefs, common macros, readpng prototypes */ + + +/* could just include png.h, but this macro is the only thing we need + * (name and typedefs changed to local versions); note that side effects + * only happen with alpha (which could easily be avoided with + * "ush acopy = (alpha);") */ + +#define alpha_composite(composite, fg, alpha, bg) { \ + ush temp = ((ush)(fg)*(ush)(alpha) + \ + (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \ + (composite) = (uch)((temp + (temp >> 8)) >> 8); \ +} + + +/* local prototypes */ +static int rpng_x_create_window(void); +static int rpng_x_display_image(void); +static void rpng_x_cleanup(void); +static int rpng_x_msb(ulg u32val); + + +static char titlebar[1024], *window_name = titlebar; +static char *appname = LONGNAME; +static char *icon_name = PROGNAME; +static char *res_name = RESNAME; +static char *res_class = RESCLASS; +static char *filename; +static FILE *infile; + +static char *bgstr; +static uch bg_red=0, bg_green=0, bg_blue=0; + +static double display_exponent; + +static ulg image_width, image_height, image_rowbytes; +static int image_channels; +static uch *image_data; + +/* X-specific variables */ +static char *displayname; +static XImage *ximage; +static Display *display; +static int depth; +static Visual *visual; +static XVisualInfo *visual_list; +static int RShift, GShift, BShift; +static ulg RMask, GMask, BMask; +static Window window; +static GC gc; +static Colormap colormap; + +static int have_nondefault_visual = FALSE; +static int have_colormap = FALSE; +static int have_window = FALSE; +static int have_gc = FALSE; +/* +ulg numcolors=0, pixels[256]; +ush reds[256], greens[256], blues[256]; + */ + + + + +int main(int argc, char **argv) +{ +#ifdef sgi + char tmpline[80]; +#endif + char *p; + int rc, alen, flen; + int error = 0; + int have_bg = FALSE; + double LUT_exponent; /* just the lookup table */ + double CRT_exponent = 2.2; /* just the monitor */ + double default_display_exponent; /* whole display system */ + XEvent e; + KeySym k; + + + displayname = (char *)NULL; + filename = (char *)NULL; + + + /* First set the default value for our display-system exponent, i.e., + * the product of the CRT exponent and the exponent corresponding to + * the frame-buffer's lookup table (LUT), if any. This is not an + * exhaustive list of LUT values (e.g., OpenStep has a lot of weird + * ones), but it should cover 99% of the current possibilities. */ + +#if defined(NeXT) + LUT_exponent = 1.0 / 2.2; + /* + if (some_next_function_that_returns_gamma(&next_gamma)) + LUT_exponent = 1.0 / next_gamma; + */ +#elif defined(sgi) + LUT_exponent = 1.0 / 1.7; + /* there doesn't seem to be any documented function to get the + * "gamma" value, so we do it the hard way */ + infile = fopen("/etc/config/system.glGammaVal", "r"); + if (infile) { + double sgi_gamma; + + fgets(tmpline, 80, infile); + fclose(infile); + sgi_gamma = atof(tmpline); + if (sgi_gamma > 0.0) + LUT_exponent = 1.0 / sgi_gamma; + } +#elif defined(Macintosh) + LUT_exponent = 1.8 / 2.61; + /* + if (some_mac_function_that_returns_gamma(&mac_gamma)) + LUT_exponent = mac_gamma / 2.61; + */ +#else + LUT_exponent = 1.0; /* assume no LUT: most PCs */ +#endif + + /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ + default_display_exponent = LUT_exponent * CRT_exponent; + + + /* If the user has set the SCREEN_GAMMA environment variable as suggested + * (somewhat imprecisely) in the libpng documentation, use that; otherwise + * use the default value we just calculated. Either way, the user may + * override this via a command-line option. */ + + if ((p = getenv("SCREEN_GAMMA")) != NULL) + display_exponent = atof(p); + else + display_exponent = default_display_exponent; + + + /* Now parse the command line for options and the PNG filename. */ + + while (*++argv && !error) { + if (!strncmp(*argv, "-display", 2)) { + if (!*++argv) + ++error; + else + displayname = *argv; + } else if (!strncmp(*argv, "-gamma", 2)) { + if (!*++argv) + ++error; + else { + display_exponent = atof(*argv); + if (display_exponent <= 0.0) + ++error; + } + } else if (!strncmp(*argv, "-bgcolor", 2)) { + if (!*++argv) + ++error; + else { + bgstr = *argv; + if (strlen(bgstr) != 7 || bgstr[0] != '#') + ++error; + else + have_bg = TRUE; + } + } else { + if (**argv != '-') { + filename = *argv; + if (argv[1]) /* shouldn't be any more args after filename */ + ++error; + } else + ++error; /* not expecting any other options */ + } + } + + if (!filename) + ++error; + + + /* print usage screen if any errors up to this point */ + + if (error) { + fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); + readpng_version_info(); + fprintf(stderr, "\n" + "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg] file.png\n" + " xdpy\tname of the target X display (e.g., ``hostname:0'')\n" + " exp \ttransfer-function exponent (``gamma'') of the display\n" + "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" + "\t\t to the product of the lookup-table exponent (varies)\n" + "\t\t and the CRT exponent (usually 2.2); must be positive\n" + " bg \tdesired background color in 7-character hex RGB format\n" + "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" + "\t\t used with transparent images\n" + "\nPress Q, Esc or mouse button 1 (within image window, after image\n" + "is displayed) to quit.\n" + "\n", PROGNAME, default_display_exponent); + exit(1); + } + + + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); + ++error; + } else { + if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) { + switch (rc) { + case 1: + fprintf(stderr, PROGNAME + ": [%s] is not a PNG file: incorrect signature\n", + filename); + break; + case 2: + fprintf(stderr, PROGNAME + ": [%s] has bad IHDR (libpng longjmp)\n", filename); + break; + case 4: + fprintf(stderr, PROGNAME ": insufficient memory\n"); + break; + default: + fprintf(stderr, PROGNAME + ": unknown readpng_init() error\n"); + break; + } + ++error; + } else { + display = XOpenDisplay(displayname); + if (!display) { + readpng_cleanup(TRUE); + fprintf(stderr, PROGNAME ": can't open X display [%s]\n", + displayname? displayname : "default"); + ++error; + } + } + if (error) + fclose(infile); + } + + + if (error) { + fprintf(stderr, PROGNAME ": aborting.\n"); + exit(2); + } + + + /* set the title-bar string, but make sure buffer doesn't overflow */ + + alen = strlen(appname); + flen = strlen(filename); + if (alen + flen + 3 > 1023) + sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); + else + sprintf(titlebar, "%s: %s", appname, filename); + + + /* if the user didn't specify a background color on the command line, + * check for one in the PNG file--if not, the initialized values of 0 + * (black) will be used */ + + if (have_bg) { + unsigned r, g, b; /* this approach quiets compiler warnings */ + + sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); + bg_red = (uch)r; + bg_green = (uch)g; + bg_blue = (uch)b; + } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) { + readpng_cleanup(TRUE); + fprintf(stderr, PROGNAME + ": libpng error while checking for background color\n"); + exit(2); + } + + + /* do the basic X initialization stuff, make the window and fill it + * with the background color */ + + if (rpng_x_create_window()) + exit(2); + + + /* decode the image, all at once */ + + Trace((stderr, "calling readpng_get_image()\n")) + image_data = readpng_get_image(display_exponent, &image_channels, + &image_rowbytes); + Trace((stderr, "done with readpng_get_image()\n")) + + + /* done with PNG file, so clean up to minimize memory usage (but do NOT + * nuke image_data!) */ + + readpng_cleanup(FALSE); + fclose(infile); + + if (!image_data) { + fprintf(stderr, PROGNAME ": unable to decode PNG image\n"); + exit(3); + } + + + /* display image (composite with background if requested) */ + + Trace((stderr, "calling rpng_x_display_image()\n")) + if (rpng_x_display_image()) { + free(image_data); + exit(4); + } + Trace((stderr, "done with rpng_x_display_image()\n")) + + + /* wait for the user to tell us when to quit */ + + printf( + "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n"); + fflush(stdout); + + do + XNextEvent(display, &e); + while (!(e.type == ButtonPress && e.xbutton.button == Button1) && + !(e.type == KeyPress && /* v--- or 1 for shifted keys */ + ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) )); + + + /* OK, we're done: clean up all image and X resources and go away */ + + rpng_x_cleanup(); + + return 0; +} + + + + + +static int rpng_x_create_window(void) +{ + uch *xdata; + int need_colormap = FALSE; + int screen, pad; + ulg bg_pixel = 0L; + ulg attrmask; + Window root; + XEvent e; + XGCValues gcvalues; + XSetWindowAttributes attr; + XTextProperty windowName, *pWindowName = &windowName; + XTextProperty iconName, *pIconName = &iconName; + XVisualInfo visual_info; + XSizeHints *size_hints; + XWMHints *wm_hints; + XClassHint *class_hints; + + + screen = DefaultScreen(display); + depth = DisplayPlanes(display, screen); + root = RootWindow(display, screen); + +#ifdef DEBUG + XSynchronize(display, True); +#endif + +#if 0 +/* GRR: add 8-bit support */ + if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) { + fprintf(stderr, + "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n", + depth); + return 2; + } + + XMatchVisualInfo(display, screen, depth, + (depth == 8)? PseudoColor : TrueColor, &visual_info); + visual = visual_info.visual; +#else + if (depth != 16 && depth != 24 && depth != 32) { + int visuals_matched = 0; + + Trace((stderr, "default depth is %d: checking other visuals\n", + depth)) + + /* 24-bit first */ + visual_info.screen = screen; + visual_info.depth = 24; + visual_list = XGetVisualInfo(display, + VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched); + if (visuals_matched == 0) { +/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */ + fprintf(stderr, "default screen depth %d not supported, and no" + " 24-bit visuals found\n", depth); + return 2; + } + Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n", + visuals_matched)) + visual = visual_list[0].visual; + depth = visual_list[0].depth; +/* + colormap_size = visual_list[0].colormap_size; + visual_class = visual->class; + visualID = XVisualIDFromVisual(visual); + */ + have_nondefault_visual = TRUE; + need_colormap = TRUE; + } else { + XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info); + visual = visual_info.visual; + } +#endif + + RMask = visual->red_mask; + GMask = visual->green_mask; + BMask = visual->blue_mask; + +/* GRR: add/check 8-bit support */ + if (depth == 8 || need_colormap) { + colormap = XCreateColormap(display, root, visual, AllocNone); + if (!colormap) { + fprintf(stderr, "XCreateColormap() failed\n"); + return 2; + } + have_colormap = TRUE; + } + if (depth == 15 || depth == 16) { + RShift = 15 - rpng_x_msb(RMask); /* these are right-shifts */ + GShift = 15 - rpng_x_msb(GMask); + BShift = 15 - rpng_x_msb(BMask); + } else if (depth > 16) { +#define NO_24BIT_MASKS +#ifdef NO_24BIT_MASKS + RShift = rpng_x_msb(RMask) - 7; /* these are left-shifts */ + GShift = rpng_x_msb(GMask) - 7; + BShift = rpng_x_msb(BMask) - 7; +#else + RShift = 7 - rpng_x_msb(RMask); /* these are right-shifts, too */ + GShift = 7 - rpng_x_msb(GMask); + BShift = 7 - rpng_x_msb(BMask); +#endif + } + if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) { + fprintf(stderr, "rpng internal logic error: negative X shift(s)!\n"); + return 2; + } + +/*--------------------------------------------------------------------------- + Finally, create the window. + ---------------------------------------------------------------------------*/ + + attr.backing_store = Always; + attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask; + attrmask = CWBackingStore | CWEventMask; + if (have_nondefault_visual) { + attr.colormap = colormap; + attr.background_pixel = 0; + attr.border_pixel = 1; + attrmask |= CWColormap | CWBackPixel | CWBorderPixel; + } + + window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0, + depth, InputOutput, visual, attrmask, &attr); + + if (window == None) { + fprintf(stderr, "XCreateWindow() failed\n"); + return 2; + } else + have_window = TRUE; + + if (depth == 8) + XSetWindowColormap(display, window, colormap); + + if (!XStringListToTextProperty(&window_name, 1, pWindowName)) + pWindowName = NULL; + if (!XStringListToTextProperty(&icon_name, 1, pIconName)) + pIconName = NULL; + + /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */ + + if ((size_hints = XAllocSizeHints()) != NULL) { + /* window will not be resizable */ + size_hints->flags = PMinSize | PMaxSize; + size_hints->min_width = size_hints->max_width = (int)image_width; + size_hints->min_height = size_hints->max_height = (int)image_height; + } + + if ((wm_hints = XAllocWMHints()) != NULL) { + wm_hints->initial_state = NormalState; + wm_hints->input = True; + /* wm_hints->icon_pixmap = icon_pixmap; */ + wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ; + } + + if ((class_hints = XAllocClassHint()) != NULL) { + class_hints->res_name = res_name; + class_hints->res_class = res_class; + } + + XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0, + size_hints, wm_hints, class_hints); + + /* various properties and hints no longer needed; free memory */ + if (pWindowName) + XFree(pWindowName->value); + if (pIconName) + XFree(pIconName->value); + if (size_hints) + XFree(size_hints); + if (wm_hints) + XFree(wm_hints); + if (class_hints) + XFree(class_hints); + + XMapWindow(display, window); + + gc = XCreateGC(display, window, 0, &gcvalues); + have_gc = TRUE; + +/*--------------------------------------------------------------------------- + Fill window with the specified background color. + ---------------------------------------------------------------------------*/ + + if (depth == 24 || depth == 32) { + bg_pixel = ((ulg)bg_red << RShift) | + ((ulg)bg_green << GShift) | + ((ulg)bg_blue << BShift); + } else if (depth == 16) { + bg_pixel = ((((ulg)bg_red << 8) >> RShift) & RMask) | + ((((ulg)bg_green << 8) >> GShift) & GMask) | + ((((ulg)bg_blue << 8) >> BShift) & BMask); + } else /* depth == 8 */ { + + /* GRR: add 8-bit support */ + + } + + XSetForeground(display, gc, bg_pixel); + XFillRectangle(display, window, gc, 0, 0, image_width, image_height); + +/*--------------------------------------------------------------------------- + Wait for first Expose event to do any drawing, then flush. + ---------------------------------------------------------------------------*/ + + do + XNextEvent(display, &e); + while (e.type != Expose || e.xexpose.count); + + XFlush(display); + +/*--------------------------------------------------------------------------- + Allocate memory for the X- and display-specific version of the image. + ---------------------------------------------------------------------------*/ + + if (depth == 24 || depth == 32) { + xdata = (uch *)malloc(4*image_width*image_height); + pad = 32; + } else if (depth == 16) { + xdata = (uch *)malloc(2*image_width*image_height); + pad = 16; + } else /* depth == 8 */ { + xdata = (uch *)malloc(image_width*image_height); + pad = 8; + } + + if (!xdata) { + fprintf(stderr, PROGNAME ": unable to allocate image memory\n"); + return 4; + } + + ximage = XCreateImage(display, visual, depth, ZPixmap, 0, + (char *)xdata, image_width, image_height, pad, 0); + + if (!ximage) { + fprintf(stderr, PROGNAME ": XCreateImage() failed\n"); + free(xdata); + return 3; + } + + /* to avoid testing the byte order every pixel (or doubling the size of + * the drawing routine with a giant if-test), we arbitrarily set the byte + * order to MSBFirst and let Xlib worry about inverting things on little- + * endian machines (like Linux/x86, old VAXen, etc.)--this is not the most + * efficient approach (the giant if-test would be better), but in the + * interest of clarity, we take the easy way out... */ + + ximage->byte_order = MSBFirst; + + return 0; + +} /* end function rpng_x_create_window() */ + + + + + +static int rpng_x_display_image(void) +{ + uch *src; + char *dest; + uch r, g, b, a; + ulg i, row, lastrow = 0; + ulg pixel; + int ximage_rowbytes = ximage->bytes_per_line; +/* int bpp = ximage->bits_per_pixel; */ + + + Trace((stderr, "beginning display loop (image_channels == %d)\n", + image_channels)) + Trace((stderr, " (width = %ld, rowbytes = %ld, ximage_rowbytes = %d)\n", + image_width, image_rowbytes, ximage_rowbytes)) + Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel)) + Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst? + "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown"))) + + if (depth == 24 || depth == 32) { + ulg red, green, blue; + + for (lastrow = row = 0; row < image_height; ++row) { + src = image_data + row*image_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (image_channels == 3) { + for (i = image_width; i > 0; --i) { + red = *src++; + green = *src++; + blue = *src++; +#ifdef NO_24BIT_MASKS + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + /* GRR BUG: this assumes bpp == 32, but may be 24: */ + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); +#else + red = (RShift < 0)? red << (-RShift) : red >> RShift; + green = (GShift < 0)? green << (-GShift) : green >> GShift; + blue = (BShift < 0)? blue << (-BShift) : blue >> BShift; + pixel = (red & RMask) | (green & GMask) | (blue & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); +#endif + } + } else /* if (image_channels == 4) */ { + for (i = image_width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (a == 255) { + red = r; + green = g; + blue = b; + } else if (a == 0) { + red = bg_red; + green = bg_green; + blue = bg_blue; + } else { + /* this macro (from png.h) composites the foreground + * and background values and puts the result into the + * first argument */ + alpha_composite(red, r, a, bg_red); + alpha_composite(green, g, a, bg_green); + alpha_composite(blue, b, a, bg_blue); + } + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + /* display after every 16 lines */ + if (((row+1) & 0xf) == 0) { + XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, image_width, 16); + XFlush(display); + lastrow = row + 1; + } + } + + } else if (depth == 16) { + ush red, green, blue; + + for (lastrow = row = 0; row < image_height; ++row) { + src = image_data + row*image_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (image_channels == 3) { + for (i = image_width; i > 0; --i) { + red = ((ush)(*src) << 8); + ++src; + green = ((ush)(*src) << 8); + ++src; + blue = ((ush)(*src) << 8); + ++src; + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } else /* if (image_channels == 4) */ { + for (i = image_width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (a == 255) { + red = ((ush)r << 8); + green = ((ush)g << 8); + blue = ((ush)b << 8); + } else if (a == 0) { + red = ((ush)bg_red << 8); + green = ((ush)bg_green << 8); + blue = ((ush)bg_blue << 8); + } else { + /* this macro (from png.h) composites the foreground + * and background values and puts the result back into + * the first argument (== fg byte here: safe) */ + alpha_composite(r, r, a, bg_red); + alpha_composite(g, g, a, bg_green); + alpha_composite(b, b, a, bg_blue); + red = ((ush)r << 8); + green = ((ush)g << 8); + blue = ((ush)b << 8); + } + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + /* display after every 16 lines */ + if (((row+1) & 0xf) == 0) { + XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, image_width, 16); + XFlush(display); + lastrow = row + 1; + } + } + + } else /* depth == 8 */ { + + /* GRR: add 8-bit support */ + + } + + Trace((stderr, "calling final XPutImage()\n")) + if (lastrow < image_height) { + XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, image_width, image_height-lastrow); + XFlush(display); + } + + return 0; +} + + + + +static void rpng_x_cleanup(void) +{ + if (image_data) { + free(image_data); + image_data = NULL; + } + + if (ximage) { + if (ximage->data) { + free(ximage->data); /* we allocated it, so we free it */ + ximage->data = (char *)NULL; /* instead of XDestroyImage() */ + } + XDestroyImage(ximage); + ximage = NULL; + } + + if (have_gc) + XFreeGC(display, gc); + + if (have_window) + XDestroyWindow(display, window); + + if (have_colormap) + XFreeColormap(display, colormap); + + if (have_nondefault_visual) + XFree(visual_list); +} + + + + + +static int rpng_x_msb(ulg u32val) +{ + int i; + + for (i = 31; i >= 0; --i) { + if (u32val & 0x80000000L) + break; + u32val <<= 1; + } + return i; +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/rpng2-win.c b/main/source/includes/lpng1610/contrib/gregbook/rpng2-win.c index 2303b58f..223e7374 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/rpng2-win.c +++ b/main/source/includes/lpng1610/contrib/gregbook/rpng2-win.c @@ -1,1253 +1,1253 @@ -/*--------------------------------------------------------------------------- - - rpng2 - progressive-model PNG display program rpng2-win.c - - This program decodes and displays PNG files progressively, as if it were - a web browser (though the front end is only set up to read from files). - It supports gamma correction, user-specified background colors, and user- - specified background patterns (for transparent images). This version is - for 32-bit Windows; it may compile under 16-bit Windows with a little - tweaking (or maybe not). Thanks to Adam Costello and Pieter S. van der - Meulen for the "diamond" and "radial waves" patterns, respectively. - - to do (someday, maybe): - - handle quoted command-line args (especially filenames with spaces) - - finish resizable checkerboard-gradient (sizes 4-128?) - - use %.1023s to simplify truncation of title-bar string? - - have minimum window width: oh well - - --------------------------------------------------------------------------- - - Changelog: - - 1.01: initial public release - - 1.02: fixed cut-and-paste error in usage screen (oops...) - - 1.03: modified to allow abbreviated options - - 1.04: removed bogus extra argument from usage fprintf() [Glenn R-P?]; - fixed command-line parsing bug - - 1.10: enabled "message window"/console (thanks to David Geldreich) - - 1.20: added runtime MMX-enabling/disabling and new -mmx* options - - 1.21: made minor tweak to usage screen to fit within 25-line console - - 1.22: added AMD64/EM64T support (__x86_64__) - - 2.00: dual-licensed (added GNU GPL) - - 2.01: fixed 64-bit typo in readpng2.c - - 2.02: fixed improper display of usage screen on PNG error(s); fixed - unexpected-EOF and file-read-error cases - - 2.03: removed runtime MMX-enabling/disabling and obsolete -mmx* options - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#define PROGNAME "rpng2-win" -#define LONGNAME "Progressive PNG Viewer for Windows" -#define VERSION "2.02 of 16 March 2008" - -#include -#include -#include -#include /* for jmpbuf declaration in readpng2.h */ -#include -#include /* only for PvdM background code */ -#include -#ifdef __CYGWIN__ -/* getch replacement. Turns out, we don't really need this, - * but leave it here if we ever enable any of the uses of - * _getch in the main code - */ -#include -#include -#include -int repl_getch( void ) -{ - char ch; - int fd = fileno(stdin); - struct termio old_tty, new_tty; - - ioctl(fd, TCGETA, &old_tty); - new_tty = old_tty; - new_tty.c_lflag &= ~(ICANON | ECHO | ISIG); - ioctl(fd, TCSETA, &new_tty); - fread(&ch, 1, sizeof(ch), stdin); - ioctl(fd, TCSETA, &old_tty); - - return ch; -} -#define _getch repl_getch -#else -#include /* only for _getch() */ -#endif - -/* all for PvdM background code: */ -#ifndef PI -# define PI 3.141592653589793238 -#endif -#define PI_2 (PI*0.5) -#define INV_PI_360 (360.0 / PI) -#define MAX(a,b) (a>b?a:b) -#define MIN(a,b) (a> 8)) >> 8); \ -} - - -#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this - * block size corresponds roughly to a download - * speed 10% faster than theoretical 33.6K maximum - * (assuming 8 data bits, 1 stop bit and no other - * overhead) */ - -/* local prototypes */ -static void rpng2_win_init(void); -static int rpng2_win_create_window(void); -static int rpng2_win_load_bg_image(void); -static void rpng2_win_display_row(ulg row); -static void rpng2_win_finish_display(void); -static void rpng2_win_cleanup(void); -LRESULT CALLBACK rpng2_win_wndproc(HWND, UINT, WPARAM, LPARAM); - - -static char titlebar[1024]; -static char *progname = PROGNAME; -static char *appname = LONGNAME; -static char *filename; -static FILE *infile; - -static mainprog_info rpng2_info; - -static uch inbuf[INBUFSIZE]; -static int incount; - -static int pat = 6; /* must be less than num_bgpat */ -static int bg_image = 0; -static int bgscale = 16; -static ulg bg_rowbytes; -static uch *bg_data; - -static struct rgb_color { - uch r, g, b; -} rgb[] = { - { 0, 0, 0}, /* 0: black */ - {255, 255, 255}, /* 1: white */ - {173, 132, 57}, /* 2: tan */ - { 64, 132, 0}, /* 3: medium green */ - {189, 117, 1}, /* 4: gold */ - {253, 249, 1}, /* 5: yellow */ - { 0, 0, 255}, /* 6: blue */ - { 0, 0, 120}, /* 7: medium blue */ - {255, 0, 255}, /* 8: magenta */ - { 64, 0, 64}, /* 9: dark magenta */ - {255, 0, 0}, /* 10: red */ - { 64, 0, 0}, /* 11: dark red */ - {255, 127, 0}, /* 12: orange */ - {192, 96, 0}, /* 13: darker orange */ - { 24, 60, 0}, /* 14: dark green-yellow */ - { 85, 125, 200} /* 15: ice blue */ -}; -/* not used for now, but should be for error-checking: -static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color); - */ - -/* - This whole struct is a fairly cheesy way to keep the number of - command-line options to a minimum. The radial-waves background - type is a particularly poor fit to the integer elements of the - struct...but a few macros and a little fixed-point math will do - wonders for ya. - - type bits: - F E D C B A 9 8 7 6 5 4 3 2 1 0 - | | | | | - | | +-+-+-- 0 = sharp-edged checkerboard - | | 1 = soft diamonds - | | 2 = radial waves - | | 3-7 = undefined - | +-- gradient #2 inverted? - +-- alternating columns inverted? - */ -static struct background_pattern { - ush type; - int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */ - int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/ -} bg[] = { - {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */ - {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */ - {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */ - {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */ - {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */ - {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */ - {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */ - {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */ - {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */ - {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */ - {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */ - {1, 3,0, 0,0}, /* diamonds: medium green vs. black */ - {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */ - {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */ - {2, 16, 256, 100, 250}, /* radial: very tight spiral */ - {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */ -}; -static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern); - - -/* Windows-specific global variables (could go in struct, but messy...) */ -static ulg wimage_rowbytes; -static uch *dib; -static uch *wimage_data; -static BITMAPINFOHEADER *bmih; - -static HWND global_hwnd; -static HINSTANCE global_hInst; -static int global_showmode; - - - - -int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode) -{ - char *args[1024]; /* arbitrary limit, but should suffice */ - char **argv = args; - char *p, *q, *bgstr = NULL; - int argc = 0; - int rc, alen, flen; - int error = 0; - int timing = FALSE; - int have_bg = FALSE; - double LUT_exponent; /* just the lookup table */ - double CRT_exponent = 2.2; /* just the monitor */ - double default_display_exponent; /* whole display system */ - MSG msg; - - - /* First initialize a few things, just to be sure--memset takes care of - * default background color (black), booleans (FALSE), pointers (NULL), - * etc. */ - - global_hInst = hInst; - global_showmode = showmode; - filename = (char *)NULL; - memset(&rpng2_info, 0, sizeof(mainprog_info)); - -#ifndef __CYGWIN__ - /* Next reenable console output, which normally goes to the bit bucket - * for windowed apps. Closing the console window will terminate the - * app. Thanks to David.Geldreich@realviz.com for supplying the magical - * incantation. */ - - AllocConsole(); - freopen("CONOUT$", "a", stderr); - freopen("CONOUT$", "a", stdout); -#endif - - /* Set the default value for our display-system exponent, i.e., the - * product of the CRT exponent and the exponent corresponding to - * the frame-buffer's lookup table (LUT), if any. This is not an - * exhaustive list of LUT values (e.g., OpenStep has a lot of weird - * ones), but it should cover 99% of the current possibilities. And - * yes, these ifdefs are completely wasted in a Windows program... */ - -#if defined(NeXT) - /* third-party utilities can modify the default LUT exponent */ - LUT_exponent = 1.0 / 2.2; - /* - if (some_next_function_that_returns_gamma(&next_gamma)) - LUT_exponent = 1.0 / next_gamma; - */ -#elif defined(sgi) - LUT_exponent = 1.0 / 1.7; - /* there doesn't seem to be any documented function to - * get the "gamma" value, so we do it the hard way */ - infile = fopen("/etc/config/system.glGammaVal", "r"); - if (infile) { - double sgi_gamma; - - fgets(tmpline, 80, infile); - fclose(infile); - sgi_gamma = atof(tmpline); - if (sgi_gamma > 0.0) - LUT_exponent = 1.0 / sgi_gamma; - } -#elif defined(Macintosh) - LUT_exponent = 1.8 / 2.61; - /* - if (some_mac_function_that_returns_gamma(&mac_gamma)) - LUT_exponent = mac_gamma / 2.61; - */ -#else - LUT_exponent = 1.0; /* assume no LUT: most PCs */ -#endif - - /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ - default_display_exponent = LUT_exponent * CRT_exponent; - - - /* If the user has set the SCREEN_GAMMA environment variable as suggested - * (somewhat imprecisely) in the libpng documentation, use that; otherwise - * use the default value we just calculated. Either way, the user may - * override this via a command-line option. */ - - if ((p = getenv("SCREEN_GAMMA")) != NULL) - rpng2_info.display_exponent = atof(p); - else - rpng2_info.display_exponent = default_display_exponent; - - - /* Windows really hates command lines, so we have to set up our own argv. - * Note that we do NOT bother with quoted arguments here, so don't use - * filenames with spaces in 'em! */ - - argv[argc++] = PROGNAME; - p = cmd; - for (;;) { - if (*p == ' ') - while (*++p == ' ') - ; - /* now p points at the first non-space after some spaces */ - if (*p == '\0') - break; /* nothing after the spaces: done */ - argv[argc++] = q = p; - while (*q && *q != ' ') - ++q; - /* now q points at a space or the end of the string */ - if (*q == '\0') - break; /* last argv already terminated; quit */ - *q = '\0'; /* change space to terminator */ - p = q + 1; - } - argv[argc] = NULL; /* terminate the argv array itself */ - - - /* Now parse the command line for options and the PNG filename. */ - - while (*++argv && !error) { - if (!strncmp(*argv, "-gamma", 2)) { - if (!*++argv) - ++error; - else { - rpng2_info.display_exponent = atof(*argv); - if (rpng2_info.display_exponent <= 0.0) - ++error; - } - } else if (!strncmp(*argv, "-bgcolor", 4)) { - if (!*++argv) - ++error; - else { - bgstr = *argv; - if (strlen(bgstr) != 7 || bgstr[0] != '#') - ++error; - else { - have_bg = TRUE; - bg_image = FALSE; - } - } - } else if (!strncmp(*argv, "-bgpat", 4)) { - if (!*++argv) - ++error; - else { - pat = atoi(*argv) - 1; - if (pat < 0 || pat >= num_bgpat) - ++error; - else { - bg_image = TRUE; - have_bg = FALSE; - } - } - } else if (!strncmp(*argv, "-timing", 2)) { - timing = TRUE; - } else { - if (**argv != '-') { - filename = *argv; - if (argv[1]) /* shouldn't be any more args after filename */ - ++error; - } else - ++error; /* not expecting any other options */ - } - } - - if (!filename) - ++error; - - - /* print usage screen if any errors up to this point */ - - if (error) { -#ifndef __CYGWIN__ - int ch; -#endif - - fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname); - readpng2_version_info(); - fprintf(stderr, "\n" - "Usage: %s [-gamma exp] [-bgcolor bg | -bgpat pat] [-timing]\n" - " %*s file.png\n\n" - " exp \ttransfer-function exponent (``gamma'') of the display\n" - "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" - "\t\t to the product of the lookup-table exponent (varies)\n" - "\t\t and the CRT exponent (usually 2.2); must be positive\n" - " bg \tdesired background color in 7-character hex RGB format\n" - "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" - "\t\t used with transparent images; overrides -bgpat option\n" - " pat \tdesired background pattern number (1-%d); used with\n" - "\t\t transparent images; overrides -bgcolor option\n" - " -timing\tenables delay for every block read, to simulate modem\n" - "\t\t download of image (~36 Kbps)\n" - "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n" -#ifndef __CYGWIN__ - "Press Q or Esc to quit this usage screen. ", -#else - , -#endif - PROGNAME, -#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \ - !(defined(__CYGWIN__) || defined(__MINGW32__)) - (int)strlen(PROGNAME), " ", -#endif - (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat); - fflush(stderr); -#ifndef __CYGWIN__ - do - ch = _getch(); - while (ch != 'q' && ch != 'Q' && ch != 0x1B); -#endif - exit(1); - } - - - if (!(infile = fopen(filename, "rb"))) { - fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); - ++error; - } else { - incount = fread(inbuf, 1, INBUFSIZE, infile); - if (incount < 8 || !readpng2_check_sig(inbuf, 8)) { - fprintf(stderr, PROGNAME - ": [%s] is not a PNG file: incorrect signature\n", - filename); - ++error; - } else if ((rc = readpng2_init(&rpng2_info)) != 0) { - switch (rc) { - case 2: - fprintf(stderr, PROGNAME - ": [%s] has bad IHDR (libpng longjmp)\n", filename); - break; - case 4: - fprintf(stderr, PROGNAME ": insufficient memory\n"); - break; - default: - fprintf(stderr, PROGNAME - ": unknown readpng2_init() error\n"); - break; - } - ++error; - } - if (error) - fclose(infile); - } - - - if (error) { -#ifndef __CYGWIN__ - int ch; -#endif - - fprintf(stderr, PROGNAME ": aborting.\n"); -#ifndef __CYGWIN__ - do - ch = _getch(); - while (ch != 'q' && ch != 'Q' && ch != 0x1B); -#endif - exit(2); - } else { - fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); -#ifndef __CYGWIN__ - fprintf(stderr, - "\n [console window: closing this window will terminate %s]\n\n", - PROGNAME); -#endif - fflush(stderr); - } - - - /* set the title-bar string, but make sure buffer doesn't overflow */ - - alen = strlen(appname); - flen = strlen(filename); - if (alen + flen + 3 > 1023) - sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); - else - sprintf(titlebar, "%s: %s", appname, filename); - - - /* set some final rpng2_info variables before entering main data loop */ - - if (have_bg) { - unsigned r, g, b; /* this approach quiets compiler warnings */ - - sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); - rpng2_info.bg_red = (uch)r; - rpng2_info.bg_green = (uch)g; - rpng2_info.bg_blue = (uch)b; - } else - rpng2_info.need_bgcolor = TRUE; - - rpng2_info.state = kPreInit; - rpng2_info.mainprog_init = rpng2_win_init; - rpng2_info.mainprog_display_row = rpng2_win_display_row; - rpng2_info.mainprog_finish_display = rpng2_win_finish_display; - - - /* OK, this is the fun part: call readpng2_decode_data() at the start of - * the loop to deal with our first buffer of data (read in above to verify - * that the file is a PNG image), then loop through the file and continue - * calling the same routine to handle each chunk of data. It in turn - * passes the data to libpng, which will invoke one or more of our call- - * backs as decoded data become available. We optionally call Sleep() for - * one second per iteration to simulate downloading the image via an analog - * modem. */ - - for (;;) { - Trace((stderr, "about to call readpng2_decode_data()\n")) - if (readpng2_decode_data(&rpng2_info, inbuf, incount)) - ++error; - Trace((stderr, "done with readpng2_decode_data()\n")) - - if (error || incount != INBUFSIZE || rpng2_info.state == kDone) { - if (rpng2_info.state == kDone) { - Trace((stderr, "done decoding PNG image\n")) - } else if (ferror(infile)) { - fprintf(stderr, PROGNAME - ": error while reading PNG image file\n"); - exit(3); - } else if (feof(infile)) { - fprintf(stderr, PROGNAME ": end of file reached " - "(unexpectedly) while reading PNG image file\n"); - exit(3); - } else /* if (error) */ { - /* will print error message below */ - } - break; - } - - if (timing) - Sleep(1000L); - - incount = fread(inbuf, 1, INBUFSIZE, infile); - } - - - /* clean up PNG stuff and report any decoding errors */ - - fclose(infile); - Trace((stderr, "about to call readpng2_cleanup()\n")) - readpng2_cleanup(&rpng2_info); - - if (error) { - fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n"); - exit(3); - } - - - /* wait for the user to tell us when to quit */ - - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - - /* we're done: clean up all image and Windows resources and go away */ - - Trace((stderr, "about to call rpng2_win_cleanup()\n")) - rpng2_win_cleanup(); - - return msg.wParam; -} - - - - - -/* this function is called by readpng2_info_callback() in readpng2.c, which - * in turn is called by libpng after all of the pre-IDAT chunks have been - * read and processed--i.e., we now have enough info to finish initializing */ - -static void rpng2_win_init() -{ - ulg i; - ulg rowbytes = rpng2_info.rowbytes; - - Trace((stderr, "beginning rpng2_win_init()\n")) - Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes)) - Trace((stderr, " width = %ld\n", rpng2_info.width)) - Trace((stderr, " height = %ld\n", rpng2_info.height)) - - rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height); - if (!rpng2_info.image_data) { - readpng2_cleanup(&rpng2_info); - return; - } - - rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *)); - if (!rpng2_info.row_pointers) { - free(rpng2_info.image_data); - rpng2_info.image_data = NULL; - readpng2_cleanup(&rpng2_info); - return; - } - - for (i = 0; i < rpng2_info.height; ++i) - rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes; - -/*--------------------------------------------------------------------------- - Do the basic Windows initialization stuff, make the window, and fill it - with the user-specified, file-specified or default background color. - ---------------------------------------------------------------------------*/ - - if (rpng2_win_create_window()) { - readpng2_cleanup(&rpng2_info); - return; - } - - rpng2_info.state = kWindowInit; -} - - - - - -static int rpng2_win_create_window() -{ - uch bg_red = rpng2_info.bg_red; - uch bg_green = rpng2_info.bg_green; - uch bg_blue = rpng2_info.bg_blue; - uch *dest; - int extra_width, extra_height; - ulg i, j; - WNDCLASSEX wndclass; - RECT rect; - - -/*--------------------------------------------------------------------------- - Allocate memory for the display-specific version of the image (round up - to multiple of 4 for Windows DIB). - ---------------------------------------------------------------------------*/ - - wimage_rowbytes = ((3*rpng2_info.width + 3L) >> 2) << 2; - - if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) + - wimage_rowbytes*rpng2_info.height))) - { - return 4; /* fail */ - } - -/*--------------------------------------------------------------------------- - Initialize the DIB. Negative height means to use top-down BMP ordering - (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8 - implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values - directly => wimage_data begins immediately after BMP header. - ---------------------------------------------------------------------------*/ - - memset(dib, 0, sizeof(BITMAPINFOHEADER)); - bmih = (BITMAPINFOHEADER *)dib; - bmih->biSize = sizeof(BITMAPINFOHEADER); - bmih->biWidth = rpng2_info.width; - bmih->biHeight = -((long)rpng2_info.height); - bmih->biPlanes = 1; - bmih->biBitCount = 24; - bmih->biCompression = 0; - wimage_data = dib + sizeof(BITMAPINFOHEADER); - -/*--------------------------------------------------------------------------- - Fill window with the specified background color (default is black), but - defer loading faked "background image" until window is displayed (may be - slow to compute). Data are in BGR order. - ---------------------------------------------------------------------------*/ - - if (bg_image) { /* just fill with black for now */ - memset(wimage_data, 0, wimage_rowbytes*rpng2_info.height); - } else { - for (j = 0; j < rpng2_info.height; ++j) { - dest = wimage_data + j*wimage_rowbytes; - for (i = rpng2_info.width; i > 0; --i) { - *dest++ = bg_blue; - *dest++ = bg_green; - *dest++ = bg_red; - } - } - } - -/*--------------------------------------------------------------------------- - Set the window parameters. - ---------------------------------------------------------------------------*/ - - memset(&wndclass, 0, sizeof(wndclass)); - - wndclass.cbSize = sizeof(wndclass); - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = rpng2_win_wndproc; - wndclass.hInstance = global_hInst; - wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = progname; - wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - RegisterClassEx(&wndclass); - -/*--------------------------------------------------------------------------- - Finally, create the window. - ---------------------------------------------------------------------------*/ - - extra_width = 2*(GetSystemMetrics(SM_CXBORDER) + - GetSystemMetrics(SM_CXDLGFRAME)); - extra_height = 2*(GetSystemMetrics(SM_CYBORDER) + - GetSystemMetrics(SM_CYDLGFRAME)) + - GetSystemMetrics(SM_CYCAPTION); - - global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, rpng2_info.width+extra_width, - rpng2_info.height+extra_height, NULL, NULL, global_hInst, NULL); - - ShowWindow(global_hwnd, global_showmode); - UpdateWindow(global_hwnd); - -/*--------------------------------------------------------------------------- - Now compute the background image and display it. If it fails (memory - allocation), revert to a plain background color. - ---------------------------------------------------------------------------*/ - - if (bg_image) { - static const char *msg = "Computing background image..."; - int x, y, len = strlen(msg); - HDC hdc = GetDC(global_hwnd); - TEXTMETRIC tm; - - GetTextMetrics(hdc, &tm); - x = (rpng2_info.width - len*tm.tmAveCharWidth)/2; - y = (rpng2_info.height - tm.tmHeight)/2; - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - /* this can still begin out of bounds even if x is positive (???): */ - TextOut(hdc, ((x < 0)? 0 : x), ((y < 0)? 0 : y), msg, len); - ReleaseDC(global_hwnd, hdc); - - rpng2_win_load_bg_image(); /* resets bg_image if fails */ - } - - if (!bg_image) { - for (j = 0; j < rpng2_info.height; ++j) { - dest = wimage_data + j*wimage_rowbytes; - for (i = rpng2_info.width; i > 0; --i) { - *dest++ = bg_blue; - *dest++ = bg_green; - *dest++ = bg_red; - } - } - } - - rect.left = 0L; - rect.top = 0L; - rect.right = (LONG)rpng2_info.width; /* possibly off by one? */ - rect.bottom = (LONG)rpng2_info.height; /* possibly off by one? */ - InvalidateRect(global_hwnd, &rect, FALSE); - UpdateWindow(global_hwnd); /* similar to XFlush() */ - - return 0; - -} /* end function rpng2_win_create_window() */ - - - - - -static int rpng2_win_load_bg_image() -{ - uch *src, *dest; - uch r1, r2, g1, g2, b1, b2; - uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv; - int k, hmax, max; - int xidx, yidx, yidx_max = (bgscale-1); - int even_odd_vert, even_odd_horiz, even_odd; - int invert_gradient2 = (bg[pat].type & 0x08); - int invert_column; - ulg i, row; - -/*--------------------------------------------------------------------------- - Allocate buffer for fake background image to be used with transparent - images; if this fails, revert to plain background color. - ---------------------------------------------------------------------------*/ - - bg_rowbytes = 3 * rpng2_info.width; - bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height); - if (!bg_data) { - fprintf(stderr, PROGNAME - ": unable to allocate memory for background image\n"); - bg_image = 0; - return 1; - } - -/*--------------------------------------------------------------------------- - Vertical gradients (ramps) in NxN squares, alternating direction and - colors (N == bgscale). - ---------------------------------------------------------------------------*/ - - if ((bg[pat].type & 0x07) == 0) { - uch r1_min = rgb[bg[pat].rgb1_min].r; - uch g1_min = rgb[bg[pat].rgb1_min].g; - uch b1_min = rgb[bg[pat].rgb1_min].b; - uch r2_min = rgb[bg[pat].rgb2_min].r; - uch g2_min = rgb[bg[pat].rgb2_min].g; - uch b2_min = rgb[bg[pat].rgb2_min].b; - int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min; - int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min; - int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min; - int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min; - int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min; - int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min; - - for (row = 0; row < rpng2_info.height; ++row) { - yidx = row % bgscale; - even_odd_vert = (row / bgscale) & 1; - - r1 = r1_min + (r1_diff * yidx) / yidx_max; - g1 = g1_min + (g1_diff * yidx) / yidx_max; - b1 = b1_min + (b1_diff * yidx) / yidx_max; - r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max; - g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max; - b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max; - - r2 = r2_min + (r2_diff * yidx) / yidx_max; - g2 = g2_min + (g2_diff * yidx) / yidx_max; - b2 = b2_min + (b2_diff * yidx) / yidx_max; - r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max; - g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max; - b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max; - - dest = bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - even_odd_horiz = (i / bgscale) & 1; - even_odd = even_odd_vert ^ even_odd_horiz; - invert_column = - (even_odd_horiz && (bg[pat].type & 0x10)); - if (even_odd == 0) { /* gradient #1 */ - if (invert_column) { - *dest++ = r1_inv; - *dest++ = g1_inv; - *dest++ = b1_inv; - } else { - *dest++ = r1; - *dest++ = g1; - *dest++ = b1; - } - } else { /* gradient #2 */ - if ((invert_column && invert_gradient2) || - (!invert_column && !invert_gradient2)) - { - *dest++ = r2; /* not inverted or */ - *dest++ = g2; /* doubly inverted */ - *dest++ = b2; - } else { - *dest++ = r2_inv; - *dest++ = g2_inv; /* singly inverted */ - *dest++ = b2_inv; - } - } - } - } - -/*--------------------------------------------------------------------------- - Soft gradient-diamonds with scale = bgscale. Code contributed by Adam - M. Costello. - ---------------------------------------------------------------------------*/ - - } else if ((bg[pat].type & 0x07) == 1) { - - hmax = (bgscale-1)/2; /* half the max weight of a color */ - max = 2*hmax; /* the max weight of a color */ - - r1 = rgb[bg[pat].rgb1_max].r; - g1 = rgb[bg[pat].rgb1_max].g; - b1 = rgb[bg[pat].rgb1_max].b; - r2 = rgb[bg[pat].rgb2_max].r; - g2 = rgb[bg[pat].rgb2_max].g; - b2 = rgb[bg[pat].rgb2_max].b; - - for (row = 0; row < rpng2_info.height; ++row) { - yidx = row % bgscale; - if (yidx > hmax) - yidx = bgscale-1 - yidx; - dest = bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - xidx = i % bgscale; - if (xidx > hmax) - xidx = bgscale-1 - xidx; - k = xidx + yidx; - *dest++ = (k*r1 + (max-k)*r2) / max; - *dest++ = (k*g1 + (max-k)*g2) / max; - *dest++ = (k*b1 + (max-k)*b2) / max; - } - } - -/*--------------------------------------------------------------------------- - Radial "starburst" with azimuthal sinusoids; [eventually number of sinu- - soids will equal bgscale?]. This one is slow but very cool. Code con- - tributed by Pieter S. van der Meulen (originally in Smalltalk). - ---------------------------------------------------------------------------*/ - - } else if ((bg[pat].type & 0x07) == 2) { - uch ch; - int ii, x, y, hw, hh, grayspot; - double freq, rotate, saturate, gray, intensity; - double angle=0.0, aoffset=0.0, maxDist, dist; - double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t; - - fprintf(stderr, "%s: computing radial background...", - PROGNAME); - fflush(stderr); - - hh = rpng2_info.height / 2; - hw = rpng2_info.width / 2; - - /* variables for radial waves: - * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED] - * freq: number of color beams originating from the center - * grayspot: size of the graying center area (anti-alias) - * rotate: rotation of the beams as a function of radius - * saturate: saturation of beams' shape azimuthally - */ - angle = CLIP(angle, 0.0, 360.0); - grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw)); - freq = MAX((double)bg[pat].bg_freq, 0.0); - saturate = (double)bg[pat].bg_bsat * 0.1; - rotate = (double)bg[pat].bg_brot * 0.1; - gray = 0.0; - intensity = 0.0; - maxDist = (double)((hw*hw) + (hh*hh)); - - for (row = 0; row < rpng2_info.height; ++row) { - y = row - hh; - dest = bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - x = i - hw; - angle = (x == 0)? PI_2 : atan((double)y / (double)x); - gray = (double)MAX(ABS(y), ABS(x)) / grayspot; - gray = MIN(1.0, gray); - dist = (double)((x*x) + (y*y)) / maxDist; - intensity = cos((angle+(rotate*dist*PI)) * freq) * - gray * saturate; - intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5; - hue = (angle + PI) * INV_PI_360 + aoffset; - s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh)); - s = MIN(MAX(s,0.0), 1.0); - v = MIN(MAX(intensity,0.0), 1.0); - - if (s == 0.0) { - ch = (uch)(v * 255.0); - *dest++ = ch; - *dest++ = ch; - *dest++ = ch; - } else { - if ((hue < 0.0) || (hue >= 360.0)) - hue -= (((int)(hue / 360.0)) * 360.0); - hue /= 60.0; - ii = (int)hue; - f = hue - (double)ii; - p = (1.0 - s) * v; - q = (1.0 - (s * f)) * v; - t = (1.0 - (s * (1.0 - f))) * v; - if (ii == 0) { red = v; green = t; blue = p; } - else if (ii == 1) { red = q; green = v; blue = p; } - else if (ii == 2) { red = p; green = v; blue = t; } - else if (ii == 3) { red = p; green = q; blue = v; } - else if (ii == 4) { red = t; green = p; blue = v; } - else if (ii == 5) { red = v; green = p; blue = q; } - *dest++ = (uch)(red * 255.0); - *dest++ = (uch)(green * 255.0); - *dest++ = (uch)(blue * 255.0); - } - } - } - fprintf(stderr, "done.\n"); - fflush(stderr); - } - -/*--------------------------------------------------------------------------- - Blast background image to display buffer before beginning PNG decode; - calling function will handle invalidation and UpdateWindow() call. - ---------------------------------------------------------------------------*/ - - for (row = 0; row < rpng2_info.height; ++row) { - src = bg_data + row*bg_rowbytes; - dest = wimage_data + row*wimage_rowbytes; - for (i = rpng2_info.width; i > 0; --i) { - r1 = *src++; - g1 = *src++; - b1 = *src++; - *dest++ = b1; - *dest++ = g1; /* note reverse order */ - *dest++ = r1; - } - } - - return 0; - -} /* end function rpng2_win_load_bg_image() */ - - - - - -static void rpng2_win_display_row(ulg row) -{ - uch bg_red = rpng2_info.bg_red; - uch bg_green = rpng2_info.bg_green; - uch bg_blue = rpng2_info.bg_blue; - uch *src, *src2=NULL, *dest; - uch r, g, b, a; - ulg i; - static int rows=0; - static ulg firstrow; - -/*--------------------------------------------------------------------------- - rows and firstrow simply track how many rows (and which ones) have not - yet been displayed; alternatively, we could call InvalidateRect() for - every row and not bother with the records-keeping. - ---------------------------------------------------------------------------*/ - - Trace((stderr, "beginning rpng2_win_display_row()\n")) - - if (rows == 0) - firstrow = row; /* first row not yet displayed */ - - ++rows; /* count of rows received but not yet displayed */ - -/*--------------------------------------------------------------------------- - Aside from the use of the rpng2_info struct and the lack of an outer - loop (over rows), this routine is identical to rpng_win_display_image() - in the non-progressive version of the program. - ---------------------------------------------------------------------------*/ - - src = rpng2_info.image_data + row*rpng2_info.rowbytes; - if (bg_image) - src2 = bg_data + row*bg_rowbytes; - dest = wimage_data + row*wimage_rowbytes; - - if (rpng2_info.channels == 3) { - for (i = rpng2_info.width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - *dest++ = b; - *dest++ = g; /* note reverse order */ - *dest++ = r; - } - } else /* if (rpng2_info.channels == 4) */ { - for (i = rpng2_info.width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (bg_image) { - bg_red = *src2++; - bg_green = *src2++; - bg_blue = *src2++; - } - if (a == 255) { - *dest++ = b; - *dest++ = g; - *dest++ = r; - } else if (a == 0) { - *dest++ = bg_blue; - *dest++ = bg_green; - *dest++ = bg_red; - } else { - /* this macro (copied from png.h) composites the - * foreground and background values and puts the - * result into the first argument; there are no - * side effects with the first argument */ - alpha_composite(*dest++, b, a, bg_blue); - alpha_composite(*dest++, g, a, bg_green); - alpha_composite(*dest++, r, a, bg_red); - } - } - } - -/*--------------------------------------------------------------------------- - Display after every 16 rows or when on last row. (Region may include - previously displayed lines due to interlacing--i.e., not contiguous.) - ---------------------------------------------------------------------------*/ - - if ((rows & 0xf) == 0 || row == rpng2_info.height-1) { - RECT rect; - - rect.left = 0L; - rect.top = (LONG)firstrow; - rect.right = (LONG)rpng2_info.width; /* possibly off by one? */ - rect.bottom = (LONG)row + 1L; /* possibly off by one? */ - InvalidateRect(global_hwnd, &rect, FALSE); - UpdateWindow(global_hwnd); /* similar to XFlush() */ - rows = 0; - } - -} /* end function rpng2_win_display_row() */ - - - - - -static void rpng2_win_finish_display() -{ - Trace((stderr, "beginning rpng2_win_finish_display()\n")) - - /* last row has already been displayed by rpng2_win_display_row(), so - * we have nothing to do here except set a flag and let the user know - * that the image is done */ - - rpng2_info.state = kDone; - printf( -#ifndef __CYGWIN__ - "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n" -#else - "Done. Press mouse button 1 (within image window) to quit.\n" -#endif - ); - fflush(stdout); -} - - - - - -static void rpng2_win_cleanup() -{ - if (bg_image && bg_data) { - free(bg_data); - bg_data = NULL; - } - - if (rpng2_info.image_data) { - free(rpng2_info.image_data); - rpng2_info.image_data = NULL; - } - - if (rpng2_info.row_pointers) { - free(rpng2_info.row_pointers); - rpng2_info.row_pointers = NULL; - } - - if (dib) { - free(dib); - dib = NULL; - } -} - - - - - -LRESULT CALLBACK rpng2_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP) -{ - HDC hdc; - PAINTSTRUCT ps; - int rc; - - switch (iMsg) { - case WM_CREATE: - /* one-time processing here, if any */ - return 0; - - case WM_PAINT: - hdc = BeginPaint(hwnd, &ps); - rc = StretchDIBits(hdc, 0, 0, rpng2_info.width, rpng2_info.height, - 0, 0, rpng2_info.width, rpng2_info.height, - wimage_data, (BITMAPINFO *)bmih, - 0, SRCCOPY); - EndPaint(hwnd, &ps); - return 0; - - /* wait for the user to tell us when to quit */ - case WM_CHAR: - switch (wP) { /* only need one, so ignore repeat count */ - case 'q': - case 'Q': - case 0x1B: /* Esc key */ - PostQuitMessage(0); - } - return 0; - - case WM_LBUTTONDOWN: /* another way of quitting */ - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, iMsg, wP, lP); -} +/*--------------------------------------------------------------------------- + + rpng2 - progressive-model PNG display program rpng2-win.c + + This program decodes and displays PNG files progressively, as if it were + a web browser (though the front end is only set up to read from files). + It supports gamma correction, user-specified background colors, and user- + specified background patterns (for transparent images). This version is + for 32-bit Windows; it may compile under 16-bit Windows with a little + tweaking (or maybe not). Thanks to Adam Costello and Pieter S. van der + Meulen for the "diamond" and "radial waves" patterns, respectively. + + to do (someday, maybe): + - handle quoted command-line args (especially filenames with spaces) + - finish resizable checkerboard-gradient (sizes 4-128?) + - use %.1023s to simplify truncation of title-bar string? + - have minimum window width: oh well + + --------------------------------------------------------------------------- + + Changelog: + - 1.01: initial public release + - 1.02: fixed cut-and-paste error in usage screen (oops...) + - 1.03: modified to allow abbreviated options + - 1.04: removed bogus extra argument from usage fprintf() [Glenn R-P?]; + fixed command-line parsing bug + - 1.10: enabled "message window"/console (thanks to David Geldreich) + - 1.20: added runtime MMX-enabling/disabling and new -mmx* options + - 1.21: made minor tweak to usage screen to fit within 25-line console + - 1.22: added AMD64/EM64T support (__x86_64__) + - 2.00: dual-licensed (added GNU GPL) + - 2.01: fixed 64-bit typo in readpng2.c + - 2.02: fixed improper display of usage screen on PNG error(s); fixed + unexpected-EOF and file-read-error cases + - 2.03: removed runtime MMX-enabling/disabling and obsolete -mmx* options + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#define PROGNAME "rpng2-win" +#define LONGNAME "Progressive PNG Viewer for Windows" +#define VERSION "2.02 of 16 March 2008" + +#include +#include +#include +#include /* for jmpbuf declaration in readpng2.h */ +#include +#include /* only for PvdM background code */ +#include +#ifdef __CYGWIN__ +/* getch replacement. Turns out, we don't really need this, + * but leave it here if we ever enable any of the uses of + * _getch in the main code + */ +#include +#include +#include +int repl_getch( void ) +{ + char ch; + int fd = fileno(stdin); + struct termio old_tty, new_tty; + + ioctl(fd, TCGETA, &old_tty); + new_tty = old_tty; + new_tty.c_lflag &= ~(ICANON | ECHO | ISIG); + ioctl(fd, TCSETA, &new_tty); + fread(&ch, 1, sizeof(ch), stdin); + ioctl(fd, TCSETA, &old_tty); + + return ch; +} +#define _getch repl_getch +#else +#include /* only for _getch() */ +#endif + +/* all for PvdM background code: */ +#ifndef PI +# define PI 3.141592653589793238 +#endif +#define PI_2 (PI*0.5) +#define INV_PI_360 (360.0 / PI) +#define MAX(a,b) (a>b?a:b) +#define MIN(a,b) (a> 8)) >> 8); \ +} + + +#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this + * block size corresponds roughly to a download + * speed 10% faster than theoretical 33.6K maximum + * (assuming 8 data bits, 1 stop bit and no other + * overhead) */ + +/* local prototypes */ +static void rpng2_win_init(void); +static int rpng2_win_create_window(void); +static int rpng2_win_load_bg_image(void); +static void rpng2_win_display_row(ulg row); +static void rpng2_win_finish_display(void); +static void rpng2_win_cleanup(void); +LRESULT CALLBACK rpng2_win_wndproc(HWND, UINT, WPARAM, LPARAM); + + +static char titlebar[1024]; +static char *progname = PROGNAME; +static char *appname = LONGNAME; +static char *filename; +static FILE *infile; + +static mainprog_info rpng2_info; + +static uch inbuf[INBUFSIZE]; +static int incount; + +static int pat = 6; /* must be less than num_bgpat */ +static int bg_image = 0; +static int bgscale = 16; +static ulg bg_rowbytes; +static uch *bg_data; + +static struct rgb_color { + uch r, g, b; +} rgb[] = { + { 0, 0, 0}, /* 0: black */ + {255, 255, 255}, /* 1: white */ + {173, 132, 57}, /* 2: tan */ + { 64, 132, 0}, /* 3: medium green */ + {189, 117, 1}, /* 4: gold */ + {253, 249, 1}, /* 5: yellow */ + { 0, 0, 255}, /* 6: blue */ + { 0, 0, 120}, /* 7: medium blue */ + {255, 0, 255}, /* 8: magenta */ + { 64, 0, 64}, /* 9: dark magenta */ + {255, 0, 0}, /* 10: red */ + { 64, 0, 0}, /* 11: dark red */ + {255, 127, 0}, /* 12: orange */ + {192, 96, 0}, /* 13: darker orange */ + { 24, 60, 0}, /* 14: dark green-yellow */ + { 85, 125, 200} /* 15: ice blue */ +}; +/* not used for now, but should be for error-checking: +static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color); + */ + +/* + This whole struct is a fairly cheesy way to keep the number of + command-line options to a minimum. The radial-waves background + type is a particularly poor fit to the integer elements of the + struct...but a few macros and a little fixed-point math will do + wonders for ya. + + type bits: + F E D C B A 9 8 7 6 5 4 3 2 1 0 + | | | | | + | | +-+-+-- 0 = sharp-edged checkerboard + | | 1 = soft diamonds + | | 2 = radial waves + | | 3-7 = undefined + | +-- gradient #2 inverted? + +-- alternating columns inverted? + */ +static struct background_pattern { + ush type; + int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */ + int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/ +} bg[] = { + {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */ + {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */ + {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */ + {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */ + {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */ + {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */ + {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */ + {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */ + {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */ + {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */ + {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */ + {1, 3,0, 0,0}, /* diamonds: medium green vs. black */ + {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */ + {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */ + {2, 16, 256, 100, 250}, /* radial: very tight spiral */ + {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */ +}; +static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern); + + +/* Windows-specific global variables (could go in struct, but messy...) */ +static ulg wimage_rowbytes; +static uch *dib; +static uch *wimage_data; +static BITMAPINFOHEADER *bmih; + +static HWND global_hwnd; +static HINSTANCE global_hInst; +static int global_showmode; + + + + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode) +{ + char *args[1024]; /* arbitrary limit, but should suffice */ + char **argv = args; + char *p, *q, *bgstr = NULL; + int argc = 0; + int rc, alen, flen; + int error = 0; + int timing = FALSE; + int have_bg = FALSE; + double LUT_exponent; /* just the lookup table */ + double CRT_exponent = 2.2; /* just the monitor */ + double default_display_exponent; /* whole display system */ + MSG msg; + + + /* First initialize a few things, just to be sure--memset takes care of + * default background color (black), booleans (FALSE), pointers (NULL), + * etc. */ + + global_hInst = hInst; + global_showmode = showmode; + filename = (char *)NULL; + memset(&rpng2_info, 0, sizeof(mainprog_info)); + +#ifndef __CYGWIN__ + /* Next reenable console output, which normally goes to the bit bucket + * for windowed apps. Closing the console window will terminate the + * app. Thanks to David.Geldreich@realviz.com for supplying the magical + * incantation. */ + + AllocConsole(); + freopen("CONOUT$", "a", stderr); + freopen("CONOUT$", "a", stdout); +#endif + + /* Set the default value for our display-system exponent, i.e., the + * product of the CRT exponent and the exponent corresponding to + * the frame-buffer's lookup table (LUT), if any. This is not an + * exhaustive list of LUT values (e.g., OpenStep has a lot of weird + * ones), but it should cover 99% of the current possibilities. And + * yes, these ifdefs are completely wasted in a Windows program... */ + +#if defined(NeXT) + /* third-party utilities can modify the default LUT exponent */ + LUT_exponent = 1.0 / 2.2; + /* + if (some_next_function_that_returns_gamma(&next_gamma)) + LUT_exponent = 1.0 / next_gamma; + */ +#elif defined(sgi) + LUT_exponent = 1.0 / 1.7; + /* there doesn't seem to be any documented function to + * get the "gamma" value, so we do it the hard way */ + infile = fopen("/etc/config/system.glGammaVal", "r"); + if (infile) { + double sgi_gamma; + + fgets(tmpline, 80, infile); + fclose(infile); + sgi_gamma = atof(tmpline); + if (sgi_gamma > 0.0) + LUT_exponent = 1.0 / sgi_gamma; + } +#elif defined(Macintosh) + LUT_exponent = 1.8 / 2.61; + /* + if (some_mac_function_that_returns_gamma(&mac_gamma)) + LUT_exponent = mac_gamma / 2.61; + */ +#else + LUT_exponent = 1.0; /* assume no LUT: most PCs */ +#endif + + /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ + default_display_exponent = LUT_exponent * CRT_exponent; + + + /* If the user has set the SCREEN_GAMMA environment variable as suggested + * (somewhat imprecisely) in the libpng documentation, use that; otherwise + * use the default value we just calculated. Either way, the user may + * override this via a command-line option. */ + + if ((p = getenv("SCREEN_GAMMA")) != NULL) + rpng2_info.display_exponent = atof(p); + else + rpng2_info.display_exponent = default_display_exponent; + + + /* Windows really hates command lines, so we have to set up our own argv. + * Note that we do NOT bother with quoted arguments here, so don't use + * filenames with spaces in 'em! */ + + argv[argc++] = PROGNAME; + p = cmd; + for (;;) { + if (*p == ' ') + while (*++p == ' ') + ; + /* now p points at the first non-space after some spaces */ + if (*p == '\0') + break; /* nothing after the spaces: done */ + argv[argc++] = q = p; + while (*q && *q != ' ') + ++q; + /* now q points at a space or the end of the string */ + if (*q == '\0') + break; /* last argv already terminated; quit */ + *q = '\0'; /* change space to terminator */ + p = q + 1; + } + argv[argc] = NULL; /* terminate the argv array itself */ + + + /* Now parse the command line for options and the PNG filename. */ + + while (*++argv && !error) { + if (!strncmp(*argv, "-gamma", 2)) { + if (!*++argv) + ++error; + else { + rpng2_info.display_exponent = atof(*argv); + if (rpng2_info.display_exponent <= 0.0) + ++error; + } + } else if (!strncmp(*argv, "-bgcolor", 4)) { + if (!*++argv) + ++error; + else { + bgstr = *argv; + if (strlen(bgstr) != 7 || bgstr[0] != '#') + ++error; + else { + have_bg = TRUE; + bg_image = FALSE; + } + } + } else if (!strncmp(*argv, "-bgpat", 4)) { + if (!*++argv) + ++error; + else { + pat = atoi(*argv) - 1; + if (pat < 0 || pat >= num_bgpat) + ++error; + else { + bg_image = TRUE; + have_bg = FALSE; + } + } + } else if (!strncmp(*argv, "-timing", 2)) { + timing = TRUE; + } else { + if (**argv != '-') { + filename = *argv; + if (argv[1]) /* shouldn't be any more args after filename */ + ++error; + } else + ++error; /* not expecting any other options */ + } + } + + if (!filename) + ++error; + + + /* print usage screen if any errors up to this point */ + + if (error) { +#ifndef __CYGWIN__ + int ch; +#endif + + fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname); + readpng2_version_info(); + fprintf(stderr, "\n" + "Usage: %s [-gamma exp] [-bgcolor bg | -bgpat pat] [-timing]\n" + " %*s file.png\n\n" + " exp \ttransfer-function exponent (``gamma'') of the display\n" + "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" + "\t\t to the product of the lookup-table exponent (varies)\n" + "\t\t and the CRT exponent (usually 2.2); must be positive\n" + " bg \tdesired background color in 7-character hex RGB format\n" + "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" + "\t\t used with transparent images; overrides -bgpat option\n" + " pat \tdesired background pattern number (1-%d); used with\n" + "\t\t transparent images; overrides -bgcolor option\n" + " -timing\tenables delay for every block read, to simulate modem\n" + "\t\t download of image (~36 Kbps)\n" + "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n" +#ifndef __CYGWIN__ + "Press Q or Esc to quit this usage screen. ", +#else + , +#endif + PROGNAME, +#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \ + !(defined(__CYGWIN__) || defined(__MINGW32__)) + (int)strlen(PROGNAME), " ", +#endif + (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat); + fflush(stderr); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + exit(1); + } + + + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); + ++error; + } else { + incount = fread(inbuf, 1, INBUFSIZE, infile); + if (incount < 8 || !readpng2_check_sig(inbuf, 8)) { + fprintf(stderr, PROGNAME + ": [%s] is not a PNG file: incorrect signature\n", + filename); + ++error; + } else if ((rc = readpng2_init(&rpng2_info)) != 0) { + switch (rc) { + case 2: + fprintf(stderr, PROGNAME + ": [%s] has bad IHDR (libpng longjmp)\n", filename); + break; + case 4: + fprintf(stderr, PROGNAME ": insufficient memory\n"); + break; + default: + fprintf(stderr, PROGNAME + ": unknown readpng2_init() error\n"); + break; + } + ++error; + } + if (error) + fclose(infile); + } + + + if (error) { +#ifndef __CYGWIN__ + int ch; +#endif + + fprintf(stderr, PROGNAME ": aborting.\n"); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + exit(2); + } else { + fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); +#ifndef __CYGWIN__ + fprintf(stderr, + "\n [console window: closing this window will terminate %s]\n\n", + PROGNAME); +#endif + fflush(stderr); + } + + + /* set the title-bar string, but make sure buffer doesn't overflow */ + + alen = strlen(appname); + flen = strlen(filename); + if (alen + flen + 3 > 1023) + sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); + else + sprintf(titlebar, "%s: %s", appname, filename); + + + /* set some final rpng2_info variables before entering main data loop */ + + if (have_bg) { + unsigned r, g, b; /* this approach quiets compiler warnings */ + + sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); + rpng2_info.bg_red = (uch)r; + rpng2_info.bg_green = (uch)g; + rpng2_info.bg_blue = (uch)b; + } else + rpng2_info.need_bgcolor = TRUE; + + rpng2_info.state = kPreInit; + rpng2_info.mainprog_init = rpng2_win_init; + rpng2_info.mainprog_display_row = rpng2_win_display_row; + rpng2_info.mainprog_finish_display = rpng2_win_finish_display; + + + /* OK, this is the fun part: call readpng2_decode_data() at the start of + * the loop to deal with our first buffer of data (read in above to verify + * that the file is a PNG image), then loop through the file and continue + * calling the same routine to handle each chunk of data. It in turn + * passes the data to libpng, which will invoke one or more of our call- + * backs as decoded data become available. We optionally call Sleep() for + * one second per iteration to simulate downloading the image via an analog + * modem. */ + + for (;;) { + Trace((stderr, "about to call readpng2_decode_data()\n")) + if (readpng2_decode_data(&rpng2_info, inbuf, incount)) + ++error; + Trace((stderr, "done with readpng2_decode_data()\n")) + + if (error || incount != INBUFSIZE || rpng2_info.state == kDone) { + if (rpng2_info.state == kDone) { + Trace((stderr, "done decoding PNG image\n")) + } else if (ferror(infile)) { + fprintf(stderr, PROGNAME + ": error while reading PNG image file\n"); + exit(3); + } else if (feof(infile)) { + fprintf(stderr, PROGNAME ": end of file reached " + "(unexpectedly) while reading PNG image file\n"); + exit(3); + } else /* if (error) */ { + /* will print error message below */ + } + break; + } + + if (timing) + Sleep(1000L); + + incount = fread(inbuf, 1, INBUFSIZE, infile); + } + + + /* clean up PNG stuff and report any decoding errors */ + + fclose(infile); + Trace((stderr, "about to call readpng2_cleanup()\n")) + readpng2_cleanup(&rpng2_info); + + if (error) { + fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n"); + exit(3); + } + + + /* wait for the user to tell us when to quit */ + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + + /* we're done: clean up all image and Windows resources and go away */ + + Trace((stderr, "about to call rpng2_win_cleanup()\n")) + rpng2_win_cleanup(); + + return msg.wParam; +} + + + + + +/* this function is called by readpng2_info_callback() in readpng2.c, which + * in turn is called by libpng after all of the pre-IDAT chunks have been + * read and processed--i.e., we now have enough info to finish initializing */ + +static void rpng2_win_init() +{ + ulg i; + ulg rowbytes = rpng2_info.rowbytes; + + Trace((stderr, "beginning rpng2_win_init()\n")) + Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes)) + Trace((stderr, " width = %ld\n", rpng2_info.width)) + Trace((stderr, " height = %ld\n", rpng2_info.height)) + + rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height); + if (!rpng2_info.image_data) { + readpng2_cleanup(&rpng2_info); + return; + } + + rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *)); + if (!rpng2_info.row_pointers) { + free(rpng2_info.image_data); + rpng2_info.image_data = NULL; + readpng2_cleanup(&rpng2_info); + return; + } + + for (i = 0; i < rpng2_info.height; ++i) + rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes; + +/*--------------------------------------------------------------------------- + Do the basic Windows initialization stuff, make the window, and fill it + with the user-specified, file-specified or default background color. + ---------------------------------------------------------------------------*/ + + if (rpng2_win_create_window()) { + readpng2_cleanup(&rpng2_info); + return; + } + + rpng2_info.state = kWindowInit; +} + + + + + +static int rpng2_win_create_window() +{ + uch bg_red = rpng2_info.bg_red; + uch bg_green = rpng2_info.bg_green; + uch bg_blue = rpng2_info.bg_blue; + uch *dest; + int extra_width, extra_height; + ulg i, j; + WNDCLASSEX wndclass; + RECT rect; + + +/*--------------------------------------------------------------------------- + Allocate memory for the display-specific version of the image (round up + to multiple of 4 for Windows DIB). + ---------------------------------------------------------------------------*/ + + wimage_rowbytes = ((3*rpng2_info.width + 3L) >> 2) << 2; + + if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) + + wimage_rowbytes*rpng2_info.height))) + { + return 4; /* fail */ + } + +/*--------------------------------------------------------------------------- + Initialize the DIB. Negative height means to use top-down BMP ordering + (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8 + implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values + directly => wimage_data begins immediately after BMP header. + ---------------------------------------------------------------------------*/ + + memset(dib, 0, sizeof(BITMAPINFOHEADER)); + bmih = (BITMAPINFOHEADER *)dib; + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = rpng2_info.width; + bmih->biHeight = -((long)rpng2_info.height); + bmih->biPlanes = 1; + bmih->biBitCount = 24; + bmih->biCompression = 0; + wimage_data = dib + sizeof(BITMAPINFOHEADER); + +/*--------------------------------------------------------------------------- + Fill window with the specified background color (default is black), but + defer loading faked "background image" until window is displayed (may be + slow to compute). Data are in BGR order. + ---------------------------------------------------------------------------*/ + + if (bg_image) { /* just fill with black for now */ + memset(wimage_data, 0, wimage_rowbytes*rpng2_info.height); + } else { + for (j = 0; j < rpng2_info.height; ++j) { + dest = wimage_data + j*wimage_rowbytes; + for (i = rpng2_info.width; i > 0; --i) { + *dest++ = bg_blue; + *dest++ = bg_green; + *dest++ = bg_red; + } + } + } + +/*--------------------------------------------------------------------------- + Set the window parameters. + ---------------------------------------------------------------------------*/ + + memset(&wndclass, 0, sizeof(wndclass)); + + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = rpng2_win_wndproc; + wndclass.hInstance = global_hInst; + wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = progname; + wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + RegisterClassEx(&wndclass); + +/*--------------------------------------------------------------------------- + Finally, create the window. + ---------------------------------------------------------------------------*/ + + extra_width = 2*(GetSystemMetrics(SM_CXBORDER) + + GetSystemMetrics(SM_CXDLGFRAME)); + extra_height = 2*(GetSystemMetrics(SM_CYBORDER) + + GetSystemMetrics(SM_CYDLGFRAME)) + + GetSystemMetrics(SM_CYCAPTION); + + global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, rpng2_info.width+extra_width, + rpng2_info.height+extra_height, NULL, NULL, global_hInst, NULL); + + ShowWindow(global_hwnd, global_showmode); + UpdateWindow(global_hwnd); + +/*--------------------------------------------------------------------------- + Now compute the background image and display it. If it fails (memory + allocation), revert to a plain background color. + ---------------------------------------------------------------------------*/ + + if (bg_image) { + static const char *msg = "Computing background image..."; + int x, y, len = strlen(msg); + HDC hdc = GetDC(global_hwnd); + TEXTMETRIC tm; + + GetTextMetrics(hdc, &tm); + x = (rpng2_info.width - len*tm.tmAveCharWidth)/2; + y = (rpng2_info.height - tm.tmHeight)/2; + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + /* this can still begin out of bounds even if x is positive (???): */ + TextOut(hdc, ((x < 0)? 0 : x), ((y < 0)? 0 : y), msg, len); + ReleaseDC(global_hwnd, hdc); + + rpng2_win_load_bg_image(); /* resets bg_image if fails */ + } + + if (!bg_image) { + for (j = 0; j < rpng2_info.height; ++j) { + dest = wimage_data + j*wimage_rowbytes; + for (i = rpng2_info.width; i > 0; --i) { + *dest++ = bg_blue; + *dest++ = bg_green; + *dest++ = bg_red; + } + } + } + + rect.left = 0L; + rect.top = 0L; + rect.right = (LONG)rpng2_info.width; /* possibly off by one? */ + rect.bottom = (LONG)rpng2_info.height; /* possibly off by one? */ + InvalidateRect(global_hwnd, &rect, FALSE); + UpdateWindow(global_hwnd); /* similar to XFlush() */ + + return 0; + +} /* end function rpng2_win_create_window() */ + + + + + +static int rpng2_win_load_bg_image() +{ + uch *src, *dest; + uch r1, r2, g1, g2, b1, b2; + uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv; + int k, hmax, max; + int xidx, yidx, yidx_max = (bgscale-1); + int even_odd_vert, even_odd_horiz, even_odd; + int invert_gradient2 = (bg[pat].type & 0x08); + int invert_column; + ulg i, row; + +/*--------------------------------------------------------------------------- + Allocate buffer for fake background image to be used with transparent + images; if this fails, revert to plain background color. + ---------------------------------------------------------------------------*/ + + bg_rowbytes = 3 * rpng2_info.width; + bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height); + if (!bg_data) { + fprintf(stderr, PROGNAME + ": unable to allocate memory for background image\n"); + bg_image = 0; + return 1; + } + +/*--------------------------------------------------------------------------- + Vertical gradients (ramps) in NxN squares, alternating direction and + colors (N == bgscale). + ---------------------------------------------------------------------------*/ + + if ((bg[pat].type & 0x07) == 0) { + uch r1_min = rgb[bg[pat].rgb1_min].r; + uch g1_min = rgb[bg[pat].rgb1_min].g; + uch b1_min = rgb[bg[pat].rgb1_min].b; + uch r2_min = rgb[bg[pat].rgb2_min].r; + uch g2_min = rgb[bg[pat].rgb2_min].g; + uch b2_min = rgb[bg[pat].rgb2_min].b; + int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min; + int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min; + int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min; + int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min; + int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min; + int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min; + + for (row = 0; row < rpng2_info.height; ++row) { + yidx = row % bgscale; + even_odd_vert = (row / bgscale) & 1; + + r1 = r1_min + (r1_diff * yidx) / yidx_max; + g1 = g1_min + (g1_diff * yidx) / yidx_max; + b1 = b1_min + (b1_diff * yidx) / yidx_max; + r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max; + g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max; + b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max; + + r2 = r2_min + (r2_diff * yidx) / yidx_max; + g2 = g2_min + (g2_diff * yidx) / yidx_max; + b2 = b2_min + (b2_diff * yidx) / yidx_max; + r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max; + g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max; + b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max; + + dest = bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + even_odd_horiz = (i / bgscale) & 1; + even_odd = even_odd_vert ^ even_odd_horiz; + invert_column = + (even_odd_horiz && (bg[pat].type & 0x10)); + if (even_odd == 0) { /* gradient #1 */ + if (invert_column) { + *dest++ = r1_inv; + *dest++ = g1_inv; + *dest++ = b1_inv; + } else { + *dest++ = r1; + *dest++ = g1; + *dest++ = b1; + } + } else { /* gradient #2 */ + if ((invert_column && invert_gradient2) || + (!invert_column && !invert_gradient2)) + { + *dest++ = r2; /* not inverted or */ + *dest++ = g2; /* doubly inverted */ + *dest++ = b2; + } else { + *dest++ = r2_inv; + *dest++ = g2_inv; /* singly inverted */ + *dest++ = b2_inv; + } + } + } + } + +/*--------------------------------------------------------------------------- + Soft gradient-diamonds with scale = bgscale. Code contributed by Adam + M. Costello. + ---------------------------------------------------------------------------*/ + + } else if ((bg[pat].type & 0x07) == 1) { + + hmax = (bgscale-1)/2; /* half the max weight of a color */ + max = 2*hmax; /* the max weight of a color */ + + r1 = rgb[bg[pat].rgb1_max].r; + g1 = rgb[bg[pat].rgb1_max].g; + b1 = rgb[bg[pat].rgb1_max].b; + r2 = rgb[bg[pat].rgb2_max].r; + g2 = rgb[bg[pat].rgb2_max].g; + b2 = rgb[bg[pat].rgb2_max].b; + + for (row = 0; row < rpng2_info.height; ++row) { + yidx = row % bgscale; + if (yidx > hmax) + yidx = bgscale-1 - yidx; + dest = bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + xidx = i % bgscale; + if (xidx > hmax) + xidx = bgscale-1 - xidx; + k = xidx + yidx; + *dest++ = (k*r1 + (max-k)*r2) / max; + *dest++ = (k*g1 + (max-k)*g2) / max; + *dest++ = (k*b1 + (max-k)*b2) / max; + } + } + +/*--------------------------------------------------------------------------- + Radial "starburst" with azimuthal sinusoids; [eventually number of sinu- + soids will equal bgscale?]. This one is slow but very cool. Code con- + tributed by Pieter S. van der Meulen (originally in Smalltalk). + ---------------------------------------------------------------------------*/ + + } else if ((bg[pat].type & 0x07) == 2) { + uch ch; + int ii, x, y, hw, hh, grayspot; + double freq, rotate, saturate, gray, intensity; + double angle=0.0, aoffset=0.0, maxDist, dist; + double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t; + + fprintf(stderr, "%s: computing radial background...", + PROGNAME); + fflush(stderr); + + hh = rpng2_info.height / 2; + hw = rpng2_info.width / 2; + + /* variables for radial waves: + * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED] + * freq: number of color beams originating from the center + * grayspot: size of the graying center area (anti-alias) + * rotate: rotation of the beams as a function of radius + * saturate: saturation of beams' shape azimuthally + */ + angle = CLIP(angle, 0.0, 360.0); + grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw)); + freq = MAX((double)bg[pat].bg_freq, 0.0); + saturate = (double)bg[pat].bg_bsat * 0.1; + rotate = (double)bg[pat].bg_brot * 0.1; + gray = 0.0; + intensity = 0.0; + maxDist = (double)((hw*hw) + (hh*hh)); + + for (row = 0; row < rpng2_info.height; ++row) { + y = row - hh; + dest = bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + x = i - hw; + angle = (x == 0)? PI_2 : atan((double)y / (double)x); + gray = (double)MAX(ABS(y), ABS(x)) / grayspot; + gray = MIN(1.0, gray); + dist = (double)((x*x) + (y*y)) / maxDist; + intensity = cos((angle+(rotate*dist*PI)) * freq) * + gray * saturate; + intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5; + hue = (angle + PI) * INV_PI_360 + aoffset; + s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh)); + s = MIN(MAX(s,0.0), 1.0); + v = MIN(MAX(intensity,0.0), 1.0); + + if (s == 0.0) { + ch = (uch)(v * 255.0); + *dest++ = ch; + *dest++ = ch; + *dest++ = ch; + } else { + if ((hue < 0.0) || (hue >= 360.0)) + hue -= (((int)(hue / 360.0)) * 360.0); + hue /= 60.0; + ii = (int)hue; + f = hue - (double)ii; + p = (1.0 - s) * v; + q = (1.0 - (s * f)) * v; + t = (1.0 - (s * (1.0 - f))) * v; + if (ii == 0) { red = v; green = t; blue = p; } + else if (ii == 1) { red = q; green = v; blue = p; } + else if (ii == 2) { red = p; green = v; blue = t; } + else if (ii == 3) { red = p; green = q; blue = v; } + else if (ii == 4) { red = t; green = p; blue = v; } + else if (ii == 5) { red = v; green = p; blue = q; } + *dest++ = (uch)(red * 255.0); + *dest++ = (uch)(green * 255.0); + *dest++ = (uch)(blue * 255.0); + } + } + } + fprintf(stderr, "done.\n"); + fflush(stderr); + } + +/*--------------------------------------------------------------------------- + Blast background image to display buffer before beginning PNG decode; + calling function will handle invalidation and UpdateWindow() call. + ---------------------------------------------------------------------------*/ + + for (row = 0; row < rpng2_info.height; ++row) { + src = bg_data + row*bg_rowbytes; + dest = wimage_data + row*wimage_rowbytes; + for (i = rpng2_info.width; i > 0; --i) { + r1 = *src++; + g1 = *src++; + b1 = *src++; + *dest++ = b1; + *dest++ = g1; /* note reverse order */ + *dest++ = r1; + } + } + + return 0; + +} /* end function rpng2_win_load_bg_image() */ + + + + + +static void rpng2_win_display_row(ulg row) +{ + uch bg_red = rpng2_info.bg_red; + uch bg_green = rpng2_info.bg_green; + uch bg_blue = rpng2_info.bg_blue; + uch *src, *src2=NULL, *dest; + uch r, g, b, a; + ulg i; + static int rows=0; + static ulg firstrow; + +/*--------------------------------------------------------------------------- + rows and firstrow simply track how many rows (and which ones) have not + yet been displayed; alternatively, we could call InvalidateRect() for + every row and not bother with the records-keeping. + ---------------------------------------------------------------------------*/ + + Trace((stderr, "beginning rpng2_win_display_row()\n")) + + if (rows == 0) + firstrow = row; /* first row not yet displayed */ + + ++rows; /* count of rows received but not yet displayed */ + +/*--------------------------------------------------------------------------- + Aside from the use of the rpng2_info struct and the lack of an outer + loop (over rows), this routine is identical to rpng_win_display_image() + in the non-progressive version of the program. + ---------------------------------------------------------------------------*/ + + src = rpng2_info.image_data + row*rpng2_info.rowbytes; + if (bg_image) + src2 = bg_data + row*bg_rowbytes; + dest = wimage_data + row*wimage_rowbytes; + + if (rpng2_info.channels == 3) { + for (i = rpng2_info.width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + *dest++ = b; + *dest++ = g; /* note reverse order */ + *dest++ = r; + } + } else /* if (rpng2_info.channels == 4) */ { + for (i = rpng2_info.width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (bg_image) { + bg_red = *src2++; + bg_green = *src2++; + bg_blue = *src2++; + } + if (a == 255) { + *dest++ = b; + *dest++ = g; + *dest++ = r; + } else if (a == 0) { + *dest++ = bg_blue; + *dest++ = bg_green; + *dest++ = bg_red; + } else { + /* this macro (copied from png.h) composites the + * foreground and background values and puts the + * result into the first argument; there are no + * side effects with the first argument */ + alpha_composite(*dest++, b, a, bg_blue); + alpha_composite(*dest++, g, a, bg_green); + alpha_composite(*dest++, r, a, bg_red); + } + } + } + +/*--------------------------------------------------------------------------- + Display after every 16 rows or when on last row. (Region may include + previously displayed lines due to interlacing--i.e., not contiguous.) + ---------------------------------------------------------------------------*/ + + if ((rows & 0xf) == 0 || row == rpng2_info.height-1) { + RECT rect; + + rect.left = 0L; + rect.top = (LONG)firstrow; + rect.right = (LONG)rpng2_info.width; /* possibly off by one? */ + rect.bottom = (LONG)row + 1L; /* possibly off by one? */ + InvalidateRect(global_hwnd, &rect, FALSE); + UpdateWindow(global_hwnd); /* similar to XFlush() */ + rows = 0; + } + +} /* end function rpng2_win_display_row() */ + + + + + +static void rpng2_win_finish_display() +{ + Trace((stderr, "beginning rpng2_win_finish_display()\n")) + + /* last row has already been displayed by rpng2_win_display_row(), so + * we have nothing to do here except set a flag and let the user know + * that the image is done */ + + rpng2_info.state = kDone; + printf( +#ifndef __CYGWIN__ + "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n" +#else + "Done. Press mouse button 1 (within image window) to quit.\n" +#endif + ); + fflush(stdout); +} + + + + + +static void rpng2_win_cleanup() +{ + if (bg_image && bg_data) { + free(bg_data); + bg_data = NULL; + } + + if (rpng2_info.image_data) { + free(rpng2_info.image_data); + rpng2_info.image_data = NULL; + } + + if (rpng2_info.row_pointers) { + free(rpng2_info.row_pointers); + rpng2_info.row_pointers = NULL; + } + + if (dib) { + free(dib); + dib = NULL; + } +} + + + + + +LRESULT CALLBACK rpng2_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP) +{ + HDC hdc; + PAINTSTRUCT ps; + int rc; + + switch (iMsg) { + case WM_CREATE: + /* one-time processing here, if any */ + return 0; + + case WM_PAINT: + hdc = BeginPaint(hwnd, &ps); + rc = StretchDIBits(hdc, 0, 0, rpng2_info.width, rpng2_info.height, + 0, 0, rpng2_info.width, rpng2_info.height, + wimage_data, (BITMAPINFO *)bmih, + 0, SRCCOPY); + EndPaint(hwnd, &ps); + return 0; + + /* wait for the user to tell us when to quit */ + case WM_CHAR: + switch (wP) { /* only need one, so ignore repeat count */ + case 'q': + case 'Q': + case 0x1B: /* Esc key */ + PostQuitMessage(0); + } + return 0; + + case WM_LBUTTONDOWN: /* another way of quitting */ + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, iMsg, wP, lP); +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/rpng2-x.c b/main/source/includes/lpng1610/contrib/gregbook/rpng2-x.c index 6c687dbd..7f24b632 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/rpng2-x.c +++ b/main/source/includes/lpng1610/contrib/gregbook/rpng2-x.c @@ -1,2107 +1,2107 @@ -/*--------------------------------------------------------------------------- - - rpng2 - progressive-model PNG display program rpng2-x.c - - This program decodes and displays PNG files progressively, as if it were - a web browser (though the front end is only set up to read from files). - It supports gamma correction, user-specified background colors, and user- - specified background patterns (for transparent images). This version is - for the X Window System (tested by the author under Unix and by Martin - Zinser under OpenVMS; may work under OS/2 with a little tweaking). - - Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond" - and "radial waves" patterns, respectively. - - to do (someday, maybe): - - fix expose/redraw code: don't draw entire row if only part exposed - - 8-bit (colormapped) X support - - finish resizable checkerboard-gradient (sizes 4-128?) - - use %.1023s to simplify truncation of title-bar string? - - --------------------------------------------------------------------------- - - Changelog: - - 1.01: initial public release - - 1.02: modified to allow abbreviated options; fixed char/uchar mismatch - - 1.10: added support for non-default visuals; fixed X pixel-conversion - - 1.11: added -usleep option for demos; fixed command-line parsing bug - - 1.12: added -pause option for demos and testing - - 1.20: added runtime MMX-enabling/disabling and new -mmx* options - - 1.21: fixed some small X memory leaks (thanks to François Petitjean) - - 1.22: fixed XFreeGC() crash bug (thanks to Patrick Welche) - - 1.23: added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares) - - 1.30: added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp = - 24; added support for X resources (thanks to Gerhard Niklasch) - - 1.31: added code to skip unused chunks (thanks to Glenn Randers-Pehrson) - - 1.32: added AMD64/EM64T support (__x86_64__); added basic expose/redraw - handling - - 2.00: dual-licensed (added GNU GPL) - - 2.01: fixed 64-bit typo in readpng2.c; fixed -pause usage description - - 2.02: fixed improper display of usage screen on PNG error(s); fixed - unexpected-EOF and file-read-error cases; fixed Trace() cut-and- - paste bugs - - 2.03: deleted runtime MMX-enabling/disabling and obsolete -mmx* options - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#define PROGNAME "rpng2-x" -#define LONGNAME "Progressive PNG Viewer for X" -#define VERSION "2.03 of 25 February 2010" -#define RESNAME "rpng2" /* our X resource application name */ -#define RESCLASS "Rpng" /* our X resource class name */ - -#include -#include -#include -#include -#include /* for jmpbuf declaration in readpng2.h */ -#include -#include /* only for PvdM background code */ -#include -#include -#include -#include /* defines XK_* macros */ - -#ifdef VMS -# include -#endif - -/* all for PvdM background code: */ -#ifndef PI -# define PI 3.141592653589793238 -#endif -#define PI_2 (PI*0.5) -#define INV_PI_360 (360.0 / PI) -#define MAX(a,b) (a>b?a:b) -#define MIN(a,b) (a> 8)) >> 8); \ -} - - -#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this - * block size corresponds roughly to a download - * speed 10% faster than theoretical 33.6K maximum - * (assuming 8 data bits, 1 stop bit and no other - * overhead) */ - -/* local prototypes */ -static void rpng2_x_init (void); -static int rpng2_x_create_window (void); -static int rpng2_x_load_bg_image (void); -static void rpng2_x_display_row (ulg row); -static void rpng2_x_finish_display (void); -static void rpng2_x_redisplay_image (ulg startcol, ulg startrow, - ulg width, ulg height); -#ifdef FEATURE_LOOP -static void rpng2_x_reload_bg_image (void); -static int is_number (char *p); -#endif -static void rpng2_x_cleanup (void); -static int rpng2_x_msb (ulg u32val); - - -static char titlebar[1024], *window_name = titlebar; -static char *appname = LONGNAME; -static char *icon_name = PROGNAME; -static char *res_name = RESNAME; -static char *res_class = RESCLASS; -static char *filename; -static FILE *infile; - -static mainprog_info rpng2_info; - -static uch inbuf[INBUFSIZE]; -static int incount; - -static int pat = 6; /* must be less than num_bgpat */ -static int bg_image = 0; -static int bgscale, bgscale_default = 16; -static ulg bg_rowbytes; -static uch *bg_data; - -int pause_after_pass = FALSE; -int demo_timing = FALSE; -ulg usleep_duration = 0L; - -static struct rgb_color { - uch r, g, b; -} rgb[] = { - { 0, 0, 0}, /* 0: black */ - {255, 255, 255}, /* 1: white */ - {173, 132, 57}, /* 2: tan */ - { 64, 132, 0}, /* 3: medium green */ - {189, 117, 1}, /* 4: gold */ - {253, 249, 1}, /* 5: yellow */ - { 0, 0, 255}, /* 6: blue */ - { 0, 0, 120}, /* 7: medium blue */ - {255, 0, 255}, /* 8: magenta */ - { 64, 0, 64}, /* 9: dark magenta */ - {255, 0, 0}, /* 10: red */ - { 64, 0, 0}, /* 11: dark red */ - {255, 127, 0}, /* 12: orange */ - {192, 96, 0}, /* 13: darker orange */ - { 24, 60, 0}, /* 14: dark green-yellow */ - { 85, 125, 200}, /* 15: ice blue */ - {192, 192, 192} /* 16: Netscape/Mosaic gray */ -}; -/* not used for now, but should be for error-checking: -static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color); - */ - -/* - This whole struct is a fairly cheesy way to keep the number of - command-line options to a minimum. The radial-waves background - type is a particularly poor fit to the integer elements of the - struct...but a few macros and a little fixed-point math will do - wonders for ya. - - type bits: - F E D C B A 9 8 7 6 5 4 3 2 1 0 - | | | | | - | | +-+-+-- 0 = sharp-edged checkerboard - | | 1 = soft diamonds - | | 2 = radial waves - | | 3-7 = undefined - | +-- gradient #2 inverted? - +-- alternating columns inverted? - */ -static struct background_pattern { - ush type; - int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */ - int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/ -} bg[] = { - {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */ - {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */ - {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */ - {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */ - {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */ - {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */ - {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */ - {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */ - {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */ - {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */ - {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */ - {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */ - {1, 3,0, 0,0}, /* diamonds: medium green vs. black */ - {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */ - {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */ - {2, 16, 256, 100, 250}, /* radial: very tight spiral */ - {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */ -}; -static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern); - - -/* X-specific variables */ -static char *displayname; -static XImage *ximage; -static Display *display; -static int depth; -static Visual *visual; -static XVisualInfo *visual_list; -static int RShift, GShift, BShift; -static ulg RMask, GMask, BMask; -static Window window; -static GC gc; -static Colormap colormap; - -static int have_nondefault_visual = FALSE; -static int have_colormap = FALSE; -static int have_window = FALSE; -static int have_gc = FALSE; - - - - -int main(int argc, char **argv) -{ -#ifdef sgi - char tmpline[80]; -#endif - char *p, *bgstr = NULL; - int rc, alen, flen; - int error = 0; - int timing = FALSE; - int have_bg = FALSE; -#ifdef FEATURE_LOOP - int loop = FALSE; - long loop_interval = -1; /* seconds (100,000 max) */ -#endif - double LUT_exponent; /* just the lookup table */ - double CRT_exponent = 2.2; /* just the monitor */ - double default_display_exponent; /* whole display system */ - XEvent e; - KeySym k; - - - /* First initialize a few things, just to be sure--memset takes care of - * default background color (black), booleans (FALSE), pointers (NULL), - * etc. */ - - displayname = (char *)NULL; - filename = (char *)NULL; - memset(&rpng2_info, 0, sizeof(mainprog_info)); - - - /* Set the default value for our display-system exponent, i.e., the - * product of the CRT exponent and the exponent corresponding to - * the frame-buffer's lookup table (LUT), if any. This is not an - * exhaustive list of LUT values (e.g., OpenStep has a lot of weird - * ones), but it should cover 99% of the current possibilities. */ - -#if defined(NeXT) - /* third-party utilities can modify the default LUT exponent */ - LUT_exponent = 1.0 / 2.2; - /* - if (some_next_function_that_returns_gamma(&next_gamma)) - LUT_exponent = 1.0 / next_gamma; - */ -#elif defined(sgi) - LUT_exponent = 1.0 / 1.7; - /* there doesn't seem to be any documented function to - * get the "gamma" value, so we do it the hard way */ - infile = fopen("/etc/config/system.glGammaVal", "r"); - if (infile) { - double sgi_gamma; - - fgets(tmpline, 80, infile); - fclose(infile); - sgi_gamma = atof(tmpline); - if (sgi_gamma > 0.0) - LUT_exponent = 1.0 / sgi_gamma; - } -#elif defined(Macintosh) - LUT_exponent = 1.8 / 2.61; - /* - if (some_mac_function_that_returns_gamma(&mac_gamma)) - LUT_exponent = mac_gamma / 2.61; - */ -#else - LUT_exponent = 1.0; /* assume no LUT: most PCs */ -#endif - - /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ - default_display_exponent = LUT_exponent * CRT_exponent; - - - /* If the user has set the SCREEN_GAMMA environment variable as suggested - * (somewhat imprecisely) in the libpng documentation, use that; otherwise - * use the default value we just calculated. Either way, the user may - * override this via a command-line option. */ - - if ((p = getenv("SCREEN_GAMMA")) != NULL) - rpng2_info.display_exponent = atof(p); - else - rpng2_info.display_exponent = default_display_exponent; - - - /* Now parse the command line for options and the PNG filename. */ - - while (*++argv && !error) { - if (!strncmp(*argv, "-display", 2)) { - if (!*++argv) - ++error; - else - displayname = *argv; - } else if (!strncmp(*argv, "-gamma", 2)) { - if (!*++argv) - ++error; - else { - rpng2_info.display_exponent = atof(*argv); - if (rpng2_info.display_exponent <= 0.0) - ++error; - } - } else if (!strncmp(*argv, "-bgcolor", 4)) { - if (!*++argv) - ++error; - else { - bgstr = *argv; - if (strlen(bgstr) != 7 || bgstr[0] != '#') - ++error; - else { - have_bg = TRUE; - bg_image = FALSE; - } - } - } else if (!strncmp(*argv, "-bgpat", 4)) { - if (!*++argv) - ++error; - else { - pat = atoi(*argv); - if (pat >= 0 && pat < num_bgpat) { - bg_image = TRUE; - have_bg = FALSE; - } else - ++error; - } - } else if (!strncmp(*argv, "-usleep", 2)) { - if (!*++argv) - ++error; - else { - usleep_duration = (ulg)atol(*argv); - demo_timing = TRUE; - } - } else if (!strncmp(*argv, "-pause", 2)) { - pause_after_pass = TRUE; - } else if (!strncmp(*argv, "-timing", 2)) { - timing = TRUE; -#ifdef FEATURE_LOOP - } else if (!strncmp(*argv, "-loop", 2)) { - loop = TRUE; - if (!argv[1] || !is_number(argv[1])) - loop_interval = 2; - else { - ++argv; - loop_interval = atol(*argv); - if (loop_interval < 0) - loop_interval = 2; - else if (loop_interval > 100000) /* bit more than one day */ - loop_interval = 100000; - } -#endif - } else { - if (**argv != '-') { - filename = *argv; - if (argv[1]) /* shouldn't be any more args after filename */ - ++error; - } else - ++error; /* not expecting any other options */ - } - } - - if (!filename) - ++error; - - - /* print usage screen if any errors up to this point */ - - if (error) { - fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname); - readpng2_version_info(); - fprintf(stderr, "\n" - "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n" -#ifdef FEATURE_LOOP - " %*s [-usleep dur | -timing] [-pause] [-loop [sec]] file.png\n\n" -#else - " %*s [-usleep dur | -timing] [-pause] file.png\n\n" -#endif - " xdpy\tname of the target X display (e.g., ``hostname:0'')\n" - " exp \ttransfer-function exponent (``gamma'') of the display\n" - "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" - "\t\t to the product of the lookup-table exponent (varies)\n" - "\t\t and the CRT exponent (usually 2.2); must be positive\n" - " bg \tdesired background color in 7-character hex RGB format\n" - "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" - "\t\t used with transparent images; overrides -bgpat\n" - " pat \tdesired background pattern number (0-%d); used with\n" - "\t\t transparent images; overrides -bgcolor\n" -#ifdef FEATURE_LOOP - " -loop\tloops through background images after initial display\n" - "\t\t is complete (depends on -bgpat)\n" - " sec \tseconds to display each background image (default = 2)\n" -#endif - " dur \tduration in microseconds to wait after displaying each\n" - "\t\t row (for demo purposes)\n" - " -timing\tenables delay for every block read, to simulate modem\n" - "\t\t download of image (~36 Kbps)\n" - " -pause\tpauses after displaying each pass until mouse clicked\n" - "\nPress Q, Esc or mouse button 1 (within image window, after image\n" - "is displayed) to quit.\n" - "\n", PROGNAME, - (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat-1); - exit(1); - } - - - if (!(infile = fopen(filename, "rb"))) { - fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); - ++error; - } else { - incount = fread(inbuf, 1, INBUFSIZE, infile); - if (incount < 8 || !readpng2_check_sig(inbuf, 8)) { - fprintf(stderr, PROGNAME - ": [%s] is not a PNG file: incorrect signature\n", - filename); - ++error; - } else if ((rc = readpng2_init(&rpng2_info)) != 0) { - switch (rc) { - case 2: - fprintf(stderr, PROGNAME - ": [%s] has bad IHDR (libpng longjmp)\n", filename); - break; - case 4: - fprintf(stderr, PROGNAME ": insufficient memory\n"); - break; - default: - fprintf(stderr, PROGNAME - ": unknown readpng2_init() error\n"); - break; - } - ++error; - } else { - Trace((stderr, "about to call XOpenDisplay()\n")) - display = XOpenDisplay(displayname); - if (!display) { - readpng2_cleanup(&rpng2_info); - fprintf(stderr, PROGNAME ": can't open X display [%s]\n", - displayname? displayname : "default"); - ++error; - } - } - if (error) - fclose(infile); - } - - - if (error) { - fprintf(stderr, PROGNAME ": aborting.\n"); - exit(2); - } - - - /* set the title-bar string, but make sure buffer doesn't overflow */ - - alen = strlen(appname); - flen = strlen(filename); - if (alen + flen + 3 > 1023) - sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); - else - sprintf(titlebar, "%s: %s", appname, filename); - - - /* set some final rpng2_info variables before entering main data loop */ - - if (have_bg) { - unsigned r, g, b; /* this approach quiets compiler warnings */ - - sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); - rpng2_info.bg_red = (uch)r; - rpng2_info.bg_green = (uch)g; - rpng2_info.bg_blue = (uch)b; - } else - rpng2_info.need_bgcolor = TRUE; - - rpng2_info.state = kPreInit; - rpng2_info.mainprog_init = rpng2_x_init; - rpng2_info.mainprog_display_row = rpng2_x_display_row; - rpng2_info.mainprog_finish_display = rpng2_x_finish_display; - - - /* OK, this is the fun part: call readpng2_decode_data() at the start of - * the loop to deal with our first buffer of data (read in above to verify - * that the file is a PNG image), then loop through the file and continue - * calling the same routine to handle each chunk of data. It in turn - * passes the data to libpng, which will invoke one or more of our call- - * backs as decoded data become available. We optionally call sleep() for - * one second per iteration to simulate downloading the image via an analog - * modem. */ - - for (;;) { - Trace((stderr, "about to call readpng2_decode_data()\n")) - if (readpng2_decode_data(&rpng2_info, inbuf, incount)) - ++error; - Trace((stderr, "done with readpng2_decode_data()\n")) - - if (error || incount != INBUFSIZE || rpng2_info.state == kDone) { - if (rpng2_info.state == kDone) { - Trace((stderr, "done decoding PNG image\n")) - } else if (ferror(infile)) { - fprintf(stderr, PROGNAME - ": error while reading PNG image file\n"); - exit(3); - } else if (feof(infile)) { - fprintf(stderr, PROGNAME ": end of file reached " - "(unexpectedly) while reading PNG image file\n"); - exit(3); - } else /* if (error) */ { - /* will print error message below */ - } - break; - } - - if (timing) - sleep(1); - - incount = fread(inbuf, 1, INBUFSIZE, infile); - } - - - /* clean up PNG stuff and report any decoding errors */ - - fclose(infile); - Trace((stderr, "about to call readpng2_cleanup()\n")) - readpng2_cleanup(&rpng2_info); - - if (error) { - fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n"); - exit(3); - } - - -#ifdef FEATURE_LOOP - - if (loop && bg_image) { - Trace((stderr, "entering -loop loop (FEATURE_LOOP)\n")) - for (;;) { - int i, use_sleep; - struct timeval now, then; - - /* get current time and add loop_interval to get target time */ - if (gettimeofday(&then, NULL) == 0) { - then.tv_sec += loop_interval; - use_sleep = FALSE; - } else - use_sleep = TRUE; - - /* do quick check for a quit event but don't wait for it */ - /* GRR BUG: should also check for Expose events and redraw... */ - if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &e)) - if (QUIT(e,k)) - break; - - /* generate next background image */ - if (++pat >= num_bgpat) - pat = 0; - rpng2_x_reload_bg_image(); - - /* wait for timeout, using whatever means are available */ - if (use_sleep || gettimeofday(&now, NULL) != 0) { - for (i = loop_interval; i > 0; --i) { - sleep(1); - /* GRR BUG: also need to check for Expose (and redraw!) */ - if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, - &e) && QUIT(e,k)) - break; - } - } else { - /* Y2038 BUG! */ - if (now.tv_sec < then.tv_sec || - (now.tv_sec == then.tv_sec && now.tv_usec < then.tv_usec)) - { - int quit = FALSE; - long seconds_to_go = then.tv_sec - now.tv_sec; - long usleep_usec; - - /* basically chew up most of remaining loop-interval with - * calls to sleep(1) interleaved with checks for quit - * events, but also recalc time-to-go periodically; when - * done, clean up any remaining time with usleep() call - * (could also use SIGALRM, but signals are a pain...) */ - while (seconds_to_go-- > 1) { - int seconds_done = 0; - - for (i = seconds_to_go; i > 0 && !quit; --i) { - sleep(1); - /* GRR BUG: need to check for Expose and redraw */ - if (XCheckMaskEvent(display, KeyPressMask | - ButtonPressMask, &e) && QUIT(e,k)) - quit = TRUE; - if (++seconds_done > 1000) - break; /* time to redo seconds_to_go meas. */ - } - if (quit) - break; - - /* OK, more than 1000 seconds since last check: - * correct the time-to-go measurement for drift */ - if (gettimeofday(&now, NULL) == 0) { - if (now.tv_sec >= then.tv_sec) - break; - seconds_to_go = then.tv_sec - now.tv_sec; - } else - ++seconds_to_go; /* restore what we subtracted */ - } - if (quit) - break; /* breaks outer do-loop, skips redisplay */ - - /* since difference between "now" and "then" is already - * eaten up to within a couple of seconds, don't need to - * worry about overflow--but might have overshot (neg.) */ - if (gettimeofday(&now, NULL) == 0) { - usleep_usec = 1000000L*(then.tv_sec - now.tv_sec) + - then.tv_usec - now.tv_usec; - if (usleep_usec > 0) - usleep((ulg)usleep_usec); - } - } - } - - /* composite image against new background and display (note that - * we do not take into account the time spent doing this...) */ - rpng2_x_redisplay_image (0, 0, rpng2_info.width, rpng2_info.height); - } - - } else /* FALL THROUGH and do the normal thing */ - -#endif /* FEATURE_LOOP */ - - /* wait for the user to tell us when to quit */ - - if (rpng2_info.state >= kWindowInit) { - Trace((stderr, "entering final wait-for-quit-event loop\n")) - do { - XNextEvent(display, &e); - if (e.type == Expose) { - XExposeEvent *ex = (XExposeEvent *)&e; - rpng2_x_redisplay_image (ex->x, ex->y, ex->width, ex->height); - } - } while (!QUIT(e,k)); - } else { - fprintf(stderr, PROGNAME ": init callback never called: probable " - "libpng error while decoding PNG metadata\n"); - exit(4); - } - - - /* we're done: clean up all image and X resources and go away */ - - Trace((stderr, "about to call rpng2_x_cleanup()\n")) - rpng2_x_cleanup(); - - return 0; -} - - - - - -/* this function is called by readpng2_info_callback() in readpng2.c, which - * in turn is called by libpng after all of the pre-IDAT chunks have been - * read and processed--i.e., we now have enough info to finish initializing */ - -static void rpng2_x_init(void) -{ - ulg i; - ulg rowbytes = rpng2_info.rowbytes; - - Trace((stderr, "beginning rpng2_x_init()\n")) - Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes)) - Trace((stderr, " width = %ld\n", rpng2_info.width)) - Trace((stderr, " height = %ld\n", rpng2_info.height)) - - rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height); - if (!rpng2_info.image_data) { - readpng2_cleanup(&rpng2_info); - return; - } - - rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *)); - if (!rpng2_info.row_pointers) { - free(rpng2_info.image_data); - rpng2_info.image_data = NULL; - readpng2_cleanup(&rpng2_info); - return; - } - - for (i = 0; i < rpng2_info.height; ++i) - rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes; - - - /* do the basic X initialization stuff, make the window, and fill it with - * the user-specified, file-specified or default background color or - * pattern */ - - if (rpng2_x_create_window()) { - - /* GRR TEMPORARY HACK: this is fundamentally no different from cases - * above; libpng should call our error handler to longjmp() back to us - * when png_ptr goes away. If we/it segfault instead, seems like a - * libpng bug... */ - - /* we're here via libpng callback, so if window fails, clean and bail */ - readpng2_cleanup(&rpng2_info); - rpng2_x_cleanup(); - exit(2); - } - - rpng2_info.state = kWindowInit; -} - - - - - -static int rpng2_x_create_window(void) -{ - ulg bg_red = rpng2_info.bg_red; - ulg bg_green = rpng2_info.bg_green; - ulg bg_blue = rpng2_info.bg_blue; - ulg bg_pixel = 0L; - ulg attrmask; - int need_colormap = FALSE; - int screen, pad; - uch *xdata; - Window root; - XEvent e; - XGCValues gcvalues; - XSetWindowAttributes attr; - XTextProperty windowName, *pWindowName = &windowName; - XTextProperty iconName, *pIconName = &iconName; - XVisualInfo visual_info; - XSizeHints *size_hints; - XWMHints *wm_hints; - XClassHint *class_hints; - - - Trace((stderr, "beginning rpng2_x_create_window()\n")) - - screen = DefaultScreen(display); - depth = DisplayPlanes(display, screen); - root = RootWindow(display, screen); - -#ifdef DEBUG - XSynchronize(display, True); -#endif - - if (depth != 16 && depth != 24 && depth != 32) { - int visuals_matched = 0; - - Trace((stderr, "default depth is %d: checking other visuals\n", - depth)) - - /* 24-bit first */ - visual_info.screen = screen; - visual_info.depth = 24; - visual_list = XGetVisualInfo(display, - VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched); - if (visuals_matched == 0) { -/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */ - fprintf(stderr, "default screen depth %d not supported, and no" - " 24-bit visuals found\n", depth); - return 2; - } - Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n", - visuals_matched)) - visual = visual_list[0].visual; - depth = visual_list[0].depth; -/* - colormap_size = visual_list[0].colormap_size; - visual_class = visual->class; - visualID = XVisualIDFromVisual(visual); - */ - have_nondefault_visual = TRUE; - need_colormap = TRUE; - } else { - XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info); - visual = visual_info.visual; - } - - RMask = visual->red_mask; - GMask = visual->green_mask; - BMask = visual->blue_mask; - -/* GRR: add/check 8-bit support */ - if (depth == 8 || need_colormap) { - colormap = XCreateColormap(display, root, visual, AllocNone); - if (!colormap) { - fprintf(stderr, "XCreateColormap() failed\n"); - return 2; - } - have_colormap = TRUE; - if (depth == 8) - bg_image = FALSE; /* gradient just wastes palette entries */ - } - if (depth == 15 || depth == 16) { - RShift = 15 - rpng2_x_msb(RMask); /* these are right-shifts */ - GShift = 15 - rpng2_x_msb(GMask); - BShift = 15 - rpng2_x_msb(BMask); - } else if (depth > 16) { - RShift = rpng2_x_msb(RMask) - 7; /* these are left-shifts */ - GShift = rpng2_x_msb(GMask) - 7; - BShift = rpng2_x_msb(BMask) - 7; - } - if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) { - fprintf(stderr, "rpng2 internal logic error: negative X shift(s)!\n"); - return 2; - } - -/*--------------------------------------------------------------------------- - Finally, create the window. - ---------------------------------------------------------------------------*/ - - attr.backing_store = Always; - attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask; - attrmask = CWBackingStore | CWEventMask; - if (have_nondefault_visual) { - attr.colormap = colormap; - attr.background_pixel = 0; - attr.border_pixel = 1; - attrmask |= CWColormap | CWBackPixel | CWBorderPixel; - } - - window = XCreateWindow(display, root, 0, 0, rpng2_info.width, - rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr); - - if (window == None) { - fprintf(stderr, "XCreateWindow() failed\n"); - return 2; - } else - have_window = TRUE; - - if (depth == 8) - XSetWindowColormap(display, window, colormap); - - if (!XStringListToTextProperty(&window_name, 1, pWindowName)) - pWindowName = NULL; - if (!XStringListToTextProperty(&icon_name, 1, pIconName)) - pIconName = NULL; - - /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */ - - if ((size_hints = XAllocSizeHints()) != NULL) { - /* window will not be resizable */ - size_hints->flags = PMinSize | PMaxSize; - size_hints->min_width = size_hints->max_width = (int)rpng2_info.width; - size_hints->min_height = size_hints->max_height = - (int)rpng2_info.height; - } - - if ((wm_hints = XAllocWMHints()) != NULL) { - wm_hints->initial_state = NormalState; - wm_hints->input = True; - /* wm_hints->icon_pixmap = icon_pixmap; */ - wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ; - } - - if ((class_hints = XAllocClassHint()) != NULL) { - class_hints->res_name = res_name; - class_hints->res_class = res_class; - } - - XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0, - size_hints, wm_hints, class_hints); - - /* various properties and hints no longer needed; free memory */ - if (pWindowName) - XFree(pWindowName->value); - if (pIconName) - XFree(pIconName->value); - if (size_hints) - XFree(size_hints); - if (wm_hints) - XFree(wm_hints); - if (class_hints) - XFree(class_hints); - - XMapWindow(display, window); - - gc = XCreateGC(display, window, 0, &gcvalues); - have_gc = TRUE; - -/*--------------------------------------------------------------------------- - Allocate memory for the X- and display-specific version of the image. - ---------------------------------------------------------------------------*/ - - if (depth == 24 || depth == 32) { - xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height); - pad = 32; - } else if (depth == 16) { - xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height); - pad = 16; - } else /* depth == 8 */ { - xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height); - pad = 8; - } - - if (!xdata) { - fprintf(stderr, PROGNAME ": unable to allocate image memory\n"); - return 4; - } - - ximage = XCreateImage(display, visual, depth, ZPixmap, 0, - (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0); - - if (!ximage) { - fprintf(stderr, PROGNAME ": XCreateImage() failed\n"); - free(xdata); - return 3; - } - - /* to avoid testing the byte order every pixel (or doubling the size of - * the drawing routine with a giant if-test), we arbitrarily set the byte - * order to MSBFirst and let Xlib worry about inverting things on little- - * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the - * most efficient approach (the giant if-test would be better), but in - * the interest of clarity, we'll take the easy way out... */ - - ximage->byte_order = MSBFirst; - -/*--------------------------------------------------------------------------- - Fill window with the specified background color (default is black) or - faked "background image" (but latter is disabled if 8-bit; gradients - just waste palette entries). - ---------------------------------------------------------------------------*/ - - if (bg_image) - rpng2_x_load_bg_image(); /* resets bg_image if fails */ - - if (!bg_image) { - if (depth == 24 || depth == 32) { - bg_pixel = (bg_red << RShift) | - (bg_green << GShift) | - (bg_blue << BShift); - } else if (depth == 16) { - bg_pixel = (((bg_red << 8) >> RShift) & RMask) | - (((bg_green << 8) >> GShift) & GMask) | - (((bg_blue << 8) >> BShift) & BMask); - } else /* depth == 8 */ { - - /* GRR: add 8-bit support */ - - } - XSetForeground(display, gc, bg_pixel); - XFillRectangle(display, window, gc, 0, 0, rpng2_info.width, - rpng2_info.height); - } - -/*--------------------------------------------------------------------------- - Wait for first Expose event to do any drawing, then flush and return. - ---------------------------------------------------------------------------*/ - - do - XNextEvent(display, &e); - while (e.type != Expose || e.xexpose.count); - - XFlush(display); - - return 0; - -} /* end function rpng2_x_create_window() */ - - - - - -static int rpng2_x_load_bg_image(void) -{ - uch *src; - char *dest; - uch r1, r2, g1, g2, b1, b2; - uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv; - int k, hmax, max; - int xidx, yidx, yidx_max; - int even_odd_vert, even_odd_horiz, even_odd; - int invert_gradient2 = (bg[pat].type & 0x08); - int invert_column; - int ximage_rowbytes = ximage->bytes_per_line; - ulg i, row; - ulg pixel; - -/*--------------------------------------------------------------------------- - Allocate buffer for fake background image to be used with transparent - images; if this fails, revert to plain background color. - ---------------------------------------------------------------------------*/ - - bg_rowbytes = 3 * rpng2_info.width; - bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height); - if (!bg_data) { - fprintf(stderr, PROGNAME - ": unable to allocate memory for background image\n"); - bg_image = 0; - return 1; - } - - bgscale = (pat == 0)? 8 : bgscale_default; - yidx_max = bgscale - 1; - -/*--------------------------------------------------------------------------- - Vertical gradients (ramps) in NxN squares, alternating direction and - colors (N == bgscale). - ---------------------------------------------------------------------------*/ - - if ((bg[pat].type & 0x07) == 0) { - uch r1_min = rgb[bg[pat].rgb1_min].r; - uch g1_min = rgb[bg[pat].rgb1_min].g; - uch b1_min = rgb[bg[pat].rgb1_min].b; - uch r2_min = rgb[bg[pat].rgb2_min].r; - uch g2_min = rgb[bg[pat].rgb2_min].g; - uch b2_min = rgb[bg[pat].rgb2_min].b; - int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min; - int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min; - int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min; - int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min; - int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min; - int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min; - - for (row = 0; row < rpng2_info.height; ++row) { - yidx = (int)(row % bgscale); - even_odd_vert = (int)((row / bgscale) & 1); - - r1 = r1_min + (r1_diff * yidx) / yidx_max; - g1 = g1_min + (g1_diff * yidx) / yidx_max; - b1 = b1_min + (b1_diff * yidx) / yidx_max; - r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max; - g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max; - b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max; - - r2 = r2_min + (r2_diff * yidx) / yidx_max; - g2 = g2_min + (g2_diff * yidx) / yidx_max; - b2 = b2_min + (b2_diff * yidx) / yidx_max; - r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max; - g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max; - b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max; - - dest = (char *)bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - even_odd_horiz = (int)((i / bgscale) & 1); - even_odd = even_odd_vert ^ even_odd_horiz; - invert_column = - (even_odd_horiz && (bg[pat].type & 0x10)); - if (even_odd == 0) { /* gradient #1 */ - if (invert_column) { - *dest++ = r1_inv; - *dest++ = g1_inv; - *dest++ = b1_inv; - } else { - *dest++ = r1; - *dest++ = g1; - *dest++ = b1; - } - } else { /* gradient #2 */ - if ((invert_column && invert_gradient2) || - (!invert_column && !invert_gradient2)) - { - *dest++ = r2; /* not inverted or */ - *dest++ = g2; /* doubly inverted */ - *dest++ = b2; - } else { - *dest++ = r2_inv; - *dest++ = g2_inv; /* singly inverted */ - *dest++ = b2_inv; - } - } - } - } - -/*--------------------------------------------------------------------------- - Soft gradient-diamonds with scale = bgscale. Code contributed by Adam - M. Costello. - ---------------------------------------------------------------------------*/ - - } else if ((bg[pat].type & 0x07) == 1) { - - hmax = (bgscale-1)/2; /* half the max weight of a color */ - max = 2*hmax; /* the max weight of a color */ - - r1 = rgb[bg[pat].rgb1_max].r; - g1 = rgb[bg[pat].rgb1_max].g; - b1 = rgb[bg[pat].rgb1_max].b; - r2 = rgb[bg[pat].rgb2_max].r; - g2 = rgb[bg[pat].rgb2_max].g; - b2 = rgb[bg[pat].rgb2_max].b; - - for (row = 0; row < rpng2_info.height; ++row) { - yidx = (int)(row % bgscale); - if (yidx > hmax) - yidx = bgscale-1 - yidx; - dest = (char *)bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - xidx = (int)(i % bgscale); - if (xidx > hmax) - xidx = bgscale-1 - xidx; - k = xidx + yidx; - *dest++ = (k*r1 + (max-k)*r2) / max; - *dest++ = (k*g1 + (max-k)*g2) / max; - *dest++ = (k*b1 + (max-k)*b2) / max; - } - } - -/*--------------------------------------------------------------------------- - Radial "starburst" with azimuthal sinusoids; [eventually number of sinu- - soids will equal bgscale?]. This one is slow but very cool. Code con- - tributed by Pieter S. van der Meulen (originally in Smalltalk). - ---------------------------------------------------------------------------*/ - - } else if ((bg[pat].type & 0x07) == 2) { - uch ch; - int ii, x, y, hw, hh, grayspot; - double freq, rotate, saturate, gray, intensity; - double angle=0.0, aoffset=0.0, maxDist, dist; - double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t; - - fprintf(stderr, "%s: computing radial background...", - PROGNAME); - fflush(stderr); - - hh = (int)(rpng2_info.height / 2); - hw = (int)(rpng2_info.width / 2); - - /* variables for radial waves: - * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED] - * freq: number of color beams originating from the center - * grayspot: size of the graying center area (anti-alias) - * rotate: rotation of the beams as a function of radius - * saturate: saturation of beams' shape azimuthally - */ - angle = CLIP(angle, 0.0, 360.0); - grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw)); - freq = MAX((double)bg[pat].bg_freq, 0.0); - saturate = (double)bg[pat].bg_bsat * 0.1; - rotate = (double)bg[pat].bg_brot * 0.1; - gray = 0.0; - intensity = 0.0; - maxDist = (double)((hw*hw) + (hh*hh)); - - for (row = 0; row < rpng2_info.height; ++row) { - y = (int)(row - hh); - dest = (char *)bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - x = (int)(i - hw); - angle = (x == 0)? PI_2 : atan((double)y / (double)x); - gray = (double)MAX(ABS(y), ABS(x)) / grayspot; - gray = MIN(1.0, gray); - dist = (double)((x*x) + (y*y)) / maxDist; - intensity = cos((angle+(rotate*dist*PI)) * freq) * - gray * saturate; - intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5; - hue = (angle + PI) * INV_PI_360 + aoffset; - s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh)); - s = MIN(MAX(s,0.0), 1.0); - v = MIN(MAX(intensity,0.0), 1.0); - - if (s == 0.0) { - ch = (uch)(v * 255.0); - *dest++ = ch; - *dest++ = ch; - *dest++ = ch; - } else { - if ((hue < 0.0) || (hue >= 360.0)) - hue -= (((int)(hue / 360.0)) * 360.0); - hue /= 60.0; - ii = (int)hue; - f = hue - (double)ii; - p = (1.0 - s) * v; - q = (1.0 - (s * f)) * v; - t = (1.0 - (s * (1.0 - f))) * v; - if (ii == 0) { red = v; green = t; blue = p; } - else if (ii == 1) { red = q; green = v; blue = p; } - else if (ii == 2) { red = p; green = v; blue = t; } - else if (ii == 3) { red = p; green = q; blue = v; } - else if (ii == 4) { red = t; green = p; blue = v; } - else if (ii == 5) { red = v; green = p; blue = q; } - *dest++ = (uch)(red * 255.0); - *dest++ = (uch)(green * 255.0); - *dest++ = (uch)(blue * 255.0); - } - } - } - fprintf(stderr, "done.\n"); - fflush(stderr); - } - -/*--------------------------------------------------------------------------- - Blast background image to display buffer before beginning PNG decode. - ---------------------------------------------------------------------------*/ - - if (depth == 24 || depth == 32) { - ulg red, green, blue; - int bpp = ximage->bits_per_pixel; - - for (row = 0; row < rpng2_info.height; ++row) { - src = bg_data + row*bg_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (bpp == 32) { /* slightly optimized version */ - for (i = rpng2_info.width; i > 0; --i) { - red = *src++; - green = *src++; - blue = *src++; - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } else { - for (i = rpng2_info.width; i > 0; --i) { - red = *src++; - green = *src++; - blue = *src++; - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - /* GRR BUG? this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift, RMask, etc.) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - } - - } else if (depth == 16) { - ush red, green, blue; - - for (row = 0; row < rpng2_info.height; ++row) { - src = bg_data + row*bg_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - for (i = rpng2_info.width; i > 0; --i) { - red = ((ush)(*src) << 8); ++src; - green = ((ush)(*src) << 8); ++src; - blue = ((ush)(*src) << 8); ++src; - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - - } else /* depth == 8 */ { - - /* GRR: add 8-bit support */ - - } - - XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width, - rpng2_info.height); - - return 0; - -} /* end function rpng2_x_load_bg_image() */ - - - - - -static void rpng2_x_display_row(ulg row) -{ - uch bg_red = rpng2_info.bg_red; - uch bg_green = rpng2_info.bg_green; - uch bg_blue = rpng2_info.bg_blue; - uch *src, *src2=NULL; - char *dest; - uch r, g, b, a; - int ximage_rowbytes = ximage->bytes_per_line; - ulg i, pixel; - static int rows=0, prevpass=(-1); - static ulg firstrow; - -/*--------------------------------------------------------------------------- - rows and firstrow simply track how many rows (and which ones) have not - yet been displayed; alternatively, we could call XPutImage() for every - row and not bother with the records-keeping. - ---------------------------------------------------------------------------*/ - - Trace((stderr, "beginning rpng2_x_display_row()\n")) - - if (rpng2_info.pass != prevpass) { - if (pause_after_pass && rpng2_info.pass > 0) { - XEvent e; - KeySym k; - - fprintf(stderr, - "%s: end of pass %d of 7; click in image window to continue\n", - PROGNAME, prevpass + 1); - do - XNextEvent(display, &e); - while (!QUIT(e,k)); - } - fprintf(stderr, "%s: pass %d of 7\r", PROGNAME, rpng2_info.pass + 1); - fflush(stderr); - prevpass = rpng2_info.pass; - } - - if (rows == 0) - firstrow = row; /* first row that is not yet displayed */ - - ++rows; /* count of rows received but not yet displayed */ - -/*--------------------------------------------------------------------------- - Aside from the use of the rpng2_info struct, the lack of an outer loop - (over rows) and moving the XPutImage() call outside the "if (depth)" - tests, this routine is identical to rpng_x_display_image() in the non- - progressive version of the program. - ---------------------------------------------------------------------------*/ - - if (depth == 24 || depth == 32) { - ulg red, green, blue; - int bpp = ximage->bits_per_pixel; - - src = rpng2_info.image_data + row*rpng2_info.rowbytes; - if (bg_image) - src2 = bg_data + row*bg_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (rpng2_info.channels == 3) { - for (i = rpng2_info.width; i > 0; --i) { - red = *src++; - green = *src++; - blue = *src++; - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - if (bpp == 32) { - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } else { - /* GRR BUG? this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift, RMask, etc.) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - } else /* if (rpng2_info.channels == 4) */ { - for (i = rpng2_info.width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (bg_image) { - bg_red = *src2++; - bg_green = *src2++; - bg_blue = *src2++; - } - if (a == 255) { - red = r; - green = g; - blue = b; - } else if (a == 0) { - red = bg_red; - green = bg_green; - blue = bg_blue; - } else { - /* this macro (from png.h) composites the foreground - * and background values and puts the result into the - * first argument */ - alpha_composite(red, r, a, bg_red); - alpha_composite(green, g, a, bg_green); - alpha_composite(blue, b, a, bg_blue); - } - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - if (bpp == 32) { - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } else { - /* GRR BUG? this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift, RMask, etc.) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - } - - } else if (depth == 16) { - ush red, green, blue; - - src = rpng2_info.row_pointers[row]; - if (bg_image) - src2 = bg_data + row*bg_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (rpng2_info.channels == 3) { - for (i = rpng2_info.width; i > 0; --i) { - red = ((ush)(*src) << 8); - ++src; - green = ((ush)(*src) << 8); - ++src; - blue = ((ush)(*src) << 8); - ++src; - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } else /* if (rpng2_info.channels == 4) */ { - for (i = rpng2_info.width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (bg_image) { - bg_red = *src2++; - bg_green = *src2++; - bg_blue = *src2++; - } - if (a == 255) { - red = ((ush)r << 8); - green = ((ush)g << 8); - blue = ((ush)b << 8); - } else if (a == 0) { - red = ((ush)bg_red << 8); - green = ((ush)bg_green << 8); - blue = ((ush)bg_blue << 8); - } else { - /* this macro (from png.h) composites the foreground - * and background values and puts the result back into - * the first argument (== fg byte here: safe) */ - alpha_composite(r, r, a, bg_red); - alpha_composite(g, g, a, bg_green); - alpha_composite(b, b, a, bg_blue); - red = ((ush)r << 8); - green = ((ush)g << 8); - blue = ((ush)b << 8); - } - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - - } else /* depth == 8 */ { - - /* GRR: add 8-bit support */ - - } - - -/*--------------------------------------------------------------------------- - Display after every 16 rows or when on one of last two rows. (Region - may include previously displayed lines due to interlacing--i.e., not - contiguous. Also, second-to-last row is final one in interlaced images - with odd number of rows.) For demos, flush (and delay) after every 16th - row so "sparse" passes don't go twice as fast. - ---------------------------------------------------------------------------*/ - - if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) { - XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0, - (int)firstrow, rpng2_info.width, row - firstrow + 1); - XFlush(display); - rows = 0; - usleep(usleep_duration); - } else - if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) { - XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0, - (int)firstrow, rpng2_info.width, row - firstrow + 1); - XFlush(display); - rows = 0; - } - -} - - - - - -static void rpng2_x_finish_display(void) -{ - Trace((stderr, "beginning rpng2_x_finish_display()\n")) - - /* last row has already been displayed by rpng2_x_display_row(), so we - * have nothing to do here except set a flag and let the user know that - * the image is done */ - - rpng2_info.state = kDone; - printf( - "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n"); - fflush(stdout); -} - - - - - -static void rpng2_x_redisplay_image(ulg startcol, ulg startrow, - ulg width, ulg height) -{ - uch bg_red = rpng2_info.bg_red; - uch bg_green = rpng2_info.bg_green; - uch bg_blue = rpng2_info.bg_blue; - uch *src, *src2=NULL; - char *dest; - uch r, g, b, a; - ulg i, row, lastrow = 0; - ulg pixel; - int ximage_rowbytes = ximage->bytes_per_line; - - - Trace((stderr, "beginning display loop (image_channels == %d)\n", - rpng2_info.channels)) - Trace((stderr, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n", - rpng2_info.width, rpng2_info.rowbytes, ximage_rowbytes)) - Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel)) - Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst? - "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown"))) - -/*--------------------------------------------------------------------------- - Aside from the use of the rpng2_info struct and of src2 (for background - image), this routine is identical to rpng_x_display_image() in the non- - progressive version of the program--for the simple reason that redisplay - of the image against a new background happens after the image is fully - decoded and therefore is, by definition, non-progressive. - ---------------------------------------------------------------------------*/ - - if (depth == 24 || depth == 32) { - ulg red, green, blue; - int bpp = ximage->bits_per_pixel; - - for (lastrow = row = startrow; row < startrow+height; ++row) { - src = rpng2_info.image_data + row*rpng2_info.rowbytes; - if (bg_image) - src2 = bg_data + row*bg_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (rpng2_info.channels == 3) { - for (i = rpng2_info.width; i > 0; --i) { - red = *src++; - green = *src++; - blue = *src++; -#ifdef NO_24BIT_MASKS - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - if (bpp == 32) { - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } else { - /* this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift, RMask, etc.) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } -#else - red = (RShift < 0)? red << (-RShift) : red >> RShift; - green = (GShift < 0)? green << (-GShift) : green >> GShift; - blue = (BShift < 0)? blue << (-BShift) : blue >> BShift; - pixel = (red & RMask) | (green & GMask) | (blue & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - if (bpp == 32) { - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } else { - /* GRR BUG */ - /* this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift/RMask/etc. here, too) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } -#endif - } - - } else /* if (rpng2_info.channels == 4) */ { - for (i = rpng2_info.width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (bg_image) { - bg_red = *src2++; - bg_green = *src2++; - bg_blue = *src2++; - } - if (a == 255) { - red = r; - green = g; - blue = b; - } else if (a == 0) { - red = bg_red; - green = bg_green; - blue = bg_blue; - } else { - /* this macro (from png.h) composites the foreground - * and background values and puts the result into the - * first argument */ - alpha_composite(red, r, a, bg_red); - alpha_composite(green, g, a, bg_green); - alpha_composite(blue, b, a, bg_blue); - } -#ifdef NO_24BIT_MASKS - pixel = (red << RShift) | - (green << GShift) | - (blue << BShift); - /* recall that we set ximage->byte_order = MSBFirst above */ - if (bpp == 32) { - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } else { - /* this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift, RMask, etc.) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } -#else - red = (RShift < 0)? red << (-RShift) : red >> RShift; - green = (GShift < 0)? green << (-GShift) : green >> GShift; - blue = (BShift < 0)? blue << (-BShift) : blue >> BShift; - pixel = (red & RMask) | (green & GMask) | (blue & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - if (bpp == 32) { - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } else { - /* GRR BUG */ - /* this assumes bpp == 24 & bits are packed low */ - /* (probably need to use RShift/RMask/etc. here, too) */ - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } -#endif - } - } - /* display after every 16 lines */ - if (((row+1) & 0xf) == 0) { - XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, rpng2_info.width, 16); - XFlush(display); - lastrow = row + 1; - } - } - - } else if (depth == 16) { - ush red, green, blue; - - for (lastrow = row = startrow; row < startrow+height; ++row) { - src = rpng2_info.row_pointers[row]; - if (bg_image) - src2 = bg_data + row*bg_rowbytes; - dest = ximage->data + row*ximage_rowbytes; - if (rpng2_info.channels == 3) { - for (i = rpng2_info.width; i > 0; --i) { - red = ((ush)(*src) << 8); - ++src; - green = ((ush)(*src) << 8); - ++src; - blue = ((ush)(*src) << 8); - ++src; - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } else /* if (rpng2_info.channels == 4) */ { - for (i = rpng2_info.width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (bg_image) { - bg_red = *src2++; - bg_green = *src2++; - bg_blue = *src2++; - } - if (a == 255) { - red = ((ush)r << 8); - green = ((ush)g << 8); - blue = ((ush)b << 8); - } else if (a == 0) { - red = ((ush)bg_red << 8); - green = ((ush)bg_green << 8); - blue = ((ush)bg_blue << 8); - } else { - /* this macro (from png.h) composites the foreground - * and background values and puts the result back into - * the first argument (== fg byte here: safe) */ - alpha_composite(r, r, a, bg_red); - alpha_composite(g, g, a, bg_green); - alpha_composite(b, b, a, bg_blue); - red = ((ush)r << 8); - green = ((ush)g << 8); - blue = ((ush)b << 8); - } - pixel = ((red >> RShift) & RMask) | - ((green >> GShift) & GMask) | - ((blue >> BShift) & BMask); - /* recall that we set ximage->byte_order = MSBFirst above */ - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)( pixel & 0xff); - } - } - /* display after every 16 lines */ - if (((row+1) & 0xf) == 0) { - XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, rpng2_info.width, 16); - XFlush(display); - lastrow = row + 1; - } - } - - } else /* depth == 8 */ { - - /* GRR: add 8-bit support */ - - } - - Trace((stderr, "calling final XPutImage()\n")) - if (lastrow < startrow+height) { - XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, rpng2_info.width, rpng2_info.height-lastrow); - XFlush(display); - } - -} /* end function rpng2_x_redisplay_image() */ - - - - - -#ifdef FEATURE_LOOP - -static void rpng2_x_reload_bg_image(void) -{ - char *dest; - uch r1, r2, g1, g2, b1, b2; - uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv; - int k, hmax, max; - int xidx, yidx, yidx_max; - int even_odd_vert, even_odd_horiz, even_odd; - int invert_gradient2 = (bg[pat].type & 0x08); - int invert_column; - ulg i, row; - - - bgscale = (pat == 0)? 8 : bgscale_default; - yidx_max = bgscale - 1; - -/*--------------------------------------------------------------------------- - Vertical gradients (ramps) in NxN squares, alternating direction and - colors (N == bgscale). - ---------------------------------------------------------------------------*/ - - if ((bg[pat].type & 0x07) == 0) { - uch r1_min = rgb[bg[pat].rgb1_min].r; - uch g1_min = rgb[bg[pat].rgb1_min].g; - uch b1_min = rgb[bg[pat].rgb1_min].b; - uch r2_min = rgb[bg[pat].rgb2_min].r; - uch g2_min = rgb[bg[pat].rgb2_min].g; - uch b2_min = rgb[bg[pat].rgb2_min].b; - int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min; - int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min; - int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min; - int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min; - int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min; - int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min; - - for (row = 0; row < rpng2_info.height; ++row) { - yidx = (int)(row % bgscale); - even_odd_vert = (int)((row / bgscale) & 1); - - r1 = r1_min + (r1_diff * yidx) / yidx_max; - g1 = g1_min + (g1_diff * yidx) / yidx_max; - b1 = b1_min + (b1_diff * yidx) / yidx_max; - r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max; - g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max; - b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max; - - r2 = r2_min + (r2_diff * yidx) / yidx_max; - g2 = g2_min + (g2_diff * yidx) / yidx_max; - b2 = b2_min + (b2_diff * yidx) / yidx_max; - r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max; - g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max; - b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max; - - dest = (char *)bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - even_odd_horiz = (int)((i / bgscale) & 1); - even_odd = even_odd_vert ^ even_odd_horiz; - invert_column = - (even_odd_horiz && (bg[pat].type & 0x10)); - if (even_odd == 0) { /* gradient #1 */ - if (invert_column) { - *dest++ = r1_inv; - *dest++ = g1_inv; - *dest++ = b1_inv; - } else { - *dest++ = r1; - *dest++ = g1; - *dest++ = b1; - } - } else { /* gradient #2 */ - if ((invert_column && invert_gradient2) || - (!invert_column && !invert_gradient2)) - { - *dest++ = r2; /* not inverted or */ - *dest++ = g2; /* doubly inverted */ - *dest++ = b2; - } else { - *dest++ = r2_inv; - *dest++ = g2_inv; /* singly inverted */ - *dest++ = b2_inv; - } - } - } - } - -/*--------------------------------------------------------------------------- - Soft gradient-diamonds with scale = bgscale. Code contributed by Adam - M. Costello. - ---------------------------------------------------------------------------*/ - - } else if ((bg[pat].type & 0x07) == 1) { - - hmax = (bgscale-1)/2; /* half the max weight of a color */ - max = 2*hmax; /* the max weight of a color */ - - r1 = rgb[bg[pat].rgb1_max].r; - g1 = rgb[bg[pat].rgb1_max].g; - b1 = rgb[bg[pat].rgb1_max].b; - r2 = rgb[bg[pat].rgb2_max].r; - g2 = rgb[bg[pat].rgb2_max].g; - b2 = rgb[bg[pat].rgb2_max].b; - - for (row = 0; row < rpng2_info.height; ++row) { - yidx = (int)(row % bgscale); - if (yidx > hmax) - yidx = bgscale-1 - yidx; - dest = (char *)bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - xidx = (int)(i % bgscale); - if (xidx > hmax) - xidx = bgscale-1 - xidx; - k = xidx + yidx; - *dest++ = (k*r1 + (max-k)*r2) / max; - *dest++ = (k*g1 + (max-k)*g2) / max; - *dest++ = (k*b1 + (max-k)*b2) / max; - } - } - -/*--------------------------------------------------------------------------- - Radial "starburst" with azimuthal sinusoids; [eventually number of sinu- - soids will equal bgscale?]. This one is slow but very cool. Code con- - tributed by Pieter S. van der Meulen (originally in Smalltalk). - ---------------------------------------------------------------------------*/ - - } else if ((bg[pat].type & 0x07) == 2) { - uch ch; - int ii, x, y, hw, hh, grayspot; - double freq, rotate, saturate, gray, intensity; - double angle=0.0, aoffset=0.0, maxDist, dist; - double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t; - - hh = (int)(rpng2_info.height / 2); - hw = (int)(rpng2_info.width / 2); - - /* variables for radial waves: - * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED] - * freq: number of color beams originating from the center - * grayspot: size of the graying center area (anti-alias) - * rotate: rotation of the beams as a function of radius - * saturate: saturation of beams' shape azimuthally - */ - angle = CLIP(angle, 0.0, 360.0); - grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw)); - freq = MAX((double)bg[pat].bg_freq, 0.0); - saturate = (double)bg[pat].bg_bsat * 0.1; - rotate = (double)bg[pat].bg_brot * 0.1; - gray = 0.0; - intensity = 0.0; - maxDist = (double)((hw*hw) + (hh*hh)); - - for (row = 0; row < rpng2_info.height; ++row) { - y = (int)(row - hh); - dest = (char *)bg_data + row*bg_rowbytes; - for (i = 0; i < rpng2_info.width; ++i) { - x = (int)(i - hw); - angle = (x == 0)? PI_2 : atan((double)y / (double)x); - gray = (double)MAX(ABS(y), ABS(x)) / grayspot; - gray = MIN(1.0, gray); - dist = (double)((x*x) + (y*y)) / maxDist; - intensity = cos((angle+(rotate*dist*PI)) * freq) * - gray * saturate; - intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5; - hue = (angle + PI) * INV_PI_360 + aoffset; - s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh)); - s = MIN(MAX(s,0.0), 1.0); - v = MIN(MAX(intensity,0.0), 1.0); - - if (s == 0.0) { - ch = (uch)(v * 255.0); - *dest++ = ch; - *dest++ = ch; - *dest++ = ch; - } else { - if ((hue < 0.0) || (hue >= 360.0)) - hue -= (((int)(hue / 360.0)) * 360.0); - hue /= 60.0; - ii = (int)hue; - f = hue - (double)ii; - p = (1.0 - s) * v; - q = (1.0 - (s * f)) * v; - t = (1.0 - (s * (1.0 - f))) * v; - if (ii == 0) { red = v; green = t; blue = p; } - else if (ii == 1) { red = q; green = v; blue = p; } - else if (ii == 2) { red = p; green = v; blue = t; } - else if (ii == 3) { red = p; green = q; blue = v; } - else if (ii == 4) { red = t; green = p; blue = v; } - else if (ii == 5) { red = v; green = p; blue = q; } - *dest++ = (uch)(red * 255.0); - *dest++ = (uch)(green * 255.0); - *dest++ = (uch)(blue * 255.0); - } - } - } - } - -} /* end function rpng2_x_reload_bg_image() */ - - - - - -static int is_number(char *p) -{ - while (*p) { - if (!isdigit(*p)) - return FALSE; - ++p; - } - return TRUE; -} - -#endif /* FEATURE_LOOP */ - - - - - -static void rpng2_x_cleanup(void) -{ - if (bg_image && bg_data) { - free(bg_data); - bg_data = NULL; - } - - if (rpng2_info.image_data) { - free(rpng2_info.image_data); - rpng2_info.image_data = NULL; - } - - if (rpng2_info.row_pointers) { - free(rpng2_info.row_pointers); - rpng2_info.row_pointers = NULL; - } - - if (ximage) { - if (ximage->data) { - free(ximage->data); /* we allocated it, so we free it */ - ximage->data = (char *)NULL; /* instead of XDestroyImage() */ - } - XDestroyImage(ximage); - ximage = NULL; - } - - if (have_gc) - XFreeGC(display, gc); - - if (have_window) - XDestroyWindow(display, window); - - if (have_colormap) - XFreeColormap(display, colormap); - - if (have_nondefault_visual) - XFree(visual_list); -} - - - - - -static int rpng2_x_msb(ulg u32val) -{ - int i; - - for (i = 31; i >= 0; --i) { - if (u32val & 0x80000000L) - break; - u32val <<= 1; - } - return i; -} +/*--------------------------------------------------------------------------- + + rpng2 - progressive-model PNG display program rpng2-x.c + + This program decodes and displays PNG files progressively, as if it were + a web browser (though the front end is only set up to read from files). + It supports gamma correction, user-specified background colors, and user- + specified background patterns (for transparent images). This version is + for the X Window System (tested by the author under Unix and by Martin + Zinser under OpenVMS; may work under OS/2 with a little tweaking). + + Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond" + and "radial waves" patterns, respectively. + + to do (someday, maybe): + - fix expose/redraw code: don't draw entire row if only part exposed + - 8-bit (colormapped) X support + - finish resizable checkerboard-gradient (sizes 4-128?) + - use %.1023s to simplify truncation of title-bar string? + + --------------------------------------------------------------------------- + + Changelog: + - 1.01: initial public release + - 1.02: modified to allow abbreviated options; fixed char/uchar mismatch + - 1.10: added support for non-default visuals; fixed X pixel-conversion + - 1.11: added -usleep option for demos; fixed command-line parsing bug + - 1.12: added -pause option for demos and testing + - 1.20: added runtime MMX-enabling/disabling and new -mmx* options + - 1.21: fixed some small X memory leaks (thanks to François Petitjean) + - 1.22: fixed XFreeGC() crash bug (thanks to Patrick Welche) + - 1.23: added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares) + - 1.30: added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp = + 24; added support for X resources (thanks to Gerhard Niklasch) + - 1.31: added code to skip unused chunks (thanks to Glenn Randers-Pehrson) + - 1.32: added AMD64/EM64T support (__x86_64__); added basic expose/redraw + handling + - 2.00: dual-licensed (added GNU GPL) + - 2.01: fixed 64-bit typo in readpng2.c; fixed -pause usage description + - 2.02: fixed improper display of usage screen on PNG error(s); fixed + unexpected-EOF and file-read-error cases; fixed Trace() cut-and- + paste bugs + - 2.03: deleted runtime MMX-enabling/disabling and obsolete -mmx* options + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2008 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#define PROGNAME "rpng2-x" +#define LONGNAME "Progressive PNG Viewer for X" +#define VERSION "2.03 of 25 February 2010" +#define RESNAME "rpng2" /* our X resource application name */ +#define RESCLASS "Rpng" /* our X resource class name */ + +#include +#include +#include +#include +#include /* for jmpbuf declaration in readpng2.h */ +#include +#include /* only for PvdM background code */ +#include +#include +#include +#include /* defines XK_* macros */ + +#ifdef VMS +# include +#endif + +/* all for PvdM background code: */ +#ifndef PI +# define PI 3.141592653589793238 +#endif +#define PI_2 (PI*0.5) +#define INV_PI_360 (360.0 / PI) +#define MAX(a,b) (a>b?a:b) +#define MIN(a,b) (a> 8)) >> 8); \ +} + + +#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this + * block size corresponds roughly to a download + * speed 10% faster than theoretical 33.6K maximum + * (assuming 8 data bits, 1 stop bit and no other + * overhead) */ + +/* local prototypes */ +static void rpng2_x_init (void); +static int rpng2_x_create_window (void); +static int rpng2_x_load_bg_image (void); +static void rpng2_x_display_row (ulg row); +static void rpng2_x_finish_display (void); +static void rpng2_x_redisplay_image (ulg startcol, ulg startrow, + ulg width, ulg height); +#ifdef FEATURE_LOOP +static void rpng2_x_reload_bg_image (void); +static int is_number (char *p); +#endif +static void rpng2_x_cleanup (void); +static int rpng2_x_msb (ulg u32val); + + +static char titlebar[1024], *window_name = titlebar; +static char *appname = LONGNAME; +static char *icon_name = PROGNAME; +static char *res_name = RESNAME; +static char *res_class = RESCLASS; +static char *filename; +static FILE *infile; + +static mainprog_info rpng2_info; + +static uch inbuf[INBUFSIZE]; +static int incount; + +static int pat = 6; /* must be less than num_bgpat */ +static int bg_image = 0; +static int bgscale, bgscale_default = 16; +static ulg bg_rowbytes; +static uch *bg_data; + +int pause_after_pass = FALSE; +int demo_timing = FALSE; +ulg usleep_duration = 0L; + +static struct rgb_color { + uch r, g, b; +} rgb[] = { + { 0, 0, 0}, /* 0: black */ + {255, 255, 255}, /* 1: white */ + {173, 132, 57}, /* 2: tan */ + { 64, 132, 0}, /* 3: medium green */ + {189, 117, 1}, /* 4: gold */ + {253, 249, 1}, /* 5: yellow */ + { 0, 0, 255}, /* 6: blue */ + { 0, 0, 120}, /* 7: medium blue */ + {255, 0, 255}, /* 8: magenta */ + { 64, 0, 64}, /* 9: dark magenta */ + {255, 0, 0}, /* 10: red */ + { 64, 0, 0}, /* 11: dark red */ + {255, 127, 0}, /* 12: orange */ + {192, 96, 0}, /* 13: darker orange */ + { 24, 60, 0}, /* 14: dark green-yellow */ + { 85, 125, 200}, /* 15: ice blue */ + {192, 192, 192} /* 16: Netscape/Mosaic gray */ +}; +/* not used for now, but should be for error-checking: +static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color); + */ + +/* + This whole struct is a fairly cheesy way to keep the number of + command-line options to a minimum. The radial-waves background + type is a particularly poor fit to the integer elements of the + struct...but a few macros and a little fixed-point math will do + wonders for ya. + + type bits: + F E D C B A 9 8 7 6 5 4 3 2 1 0 + | | | | | + | | +-+-+-- 0 = sharp-edged checkerboard + | | 1 = soft diamonds + | | 2 = radial waves + | | 3-7 = undefined + | +-- gradient #2 inverted? + +-- alternating columns inverted? + */ +static struct background_pattern { + ush type; + int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */ + int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/ +} bg[] = { + {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */ + {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */ + {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */ + {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */ + {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */ + {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */ + {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */ + {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */ + {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */ + {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */ + {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */ + {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */ + {1, 3,0, 0,0}, /* diamonds: medium green vs. black */ + {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */ + {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */ + {2, 16, 256, 100, 250}, /* radial: very tight spiral */ + {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */ +}; +static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern); + + +/* X-specific variables */ +static char *displayname; +static XImage *ximage; +static Display *display; +static int depth; +static Visual *visual; +static XVisualInfo *visual_list; +static int RShift, GShift, BShift; +static ulg RMask, GMask, BMask; +static Window window; +static GC gc; +static Colormap colormap; + +static int have_nondefault_visual = FALSE; +static int have_colormap = FALSE; +static int have_window = FALSE; +static int have_gc = FALSE; + + + + +int main(int argc, char **argv) +{ +#ifdef sgi + char tmpline[80]; +#endif + char *p, *bgstr = NULL; + int rc, alen, flen; + int error = 0; + int timing = FALSE; + int have_bg = FALSE; +#ifdef FEATURE_LOOP + int loop = FALSE; + long loop_interval = -1; /* seconds (100,000 max) */ +#endif + double LUT_exponent; /* just the lookup table */ + double CRT_exponent = 2.2; /* just the monitor */ + double default_display_exponent; /* whole display system */ + XEvent e; + KeySym k; + + + /* First initialize a few things, just to be sure--memset takes care of + * default background color (black), booleans (FALSE), pointers (NULL), + * etc. */ + + displayname = (char *)NULL; + filename = (char *)NULL; + memset(&rpng2_info, 0, sizeof(mainprog_info)); + + + /* Set the default value for our display-system exponent, i.e., the + * product of the CRT exponent and the exponent corresponding to + * the frame-buffer's lookup table (LUT), if any. This is not an + * exhaustive list of LUT values (e.g., OpenStep has a lot of weird + * ones), but it should cover 99% of the current possibilities. */ + +#if defined(NeXT) + /* third-party utilities can modify the default LUT exponent */ + LUT_exponent = 1.0 / 2.2; + /* + if (some_next_function_that_returns_gamma(&next_gamma)) + LUT_exponent = 1.0 / next_gamma; + */ +#elif defined(sgi) + LUT_exponent = 1.0 / 1.7; + /* there doesn't seem to be any documented function to + * get the "gamma" value, so we do it the hard way */ + infile = fopen("/etc/config/system.glGammaVal", "r"); + if (infile) { + double sgi_gamma; + + fgets(tmpline, 80, infile); + fclose(infile); + sgi_gamma = atof(tmpline); + if (sgi_gamma > 0.0) + LUT_exponent = 1.0 / sgi_gamma; + } +#elif defined(Macintosh) + LUT_exponent = 1.8 / 2.61; + /* + if (some_mac_function_that_returns_gamma(&mac_gamma)) + LUT_exponent = mac_gamma / 2.61; + */ +#else + LUT_exponent = 1.0; /* assume no LUT: most PCs */ +#endif + + /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ + default_display_exponent = LUT_exponent * CRT_exponent; + + + /* If the user has set the SCREEN_GAMMA environment variable as suggested + * (somewhat imprecisely) in the libpng documentation, use that; otherwise + * use the default value we just calculated. Either way, the user may + * override this via a command-line option. */ + + if ((p = getenv("SCREEN_GAMMA")) != NULL) + rpng2_info.display_exponent = atof(p); + else + rpng2_info.display_exponent = default_display_exponent; + + + /* Now parse the command line for options and the PNG filename. */ + + while (*++argv && !error) { + if (!strncmp(*argv, "-display", 2)) { + if (!*++argv) + ++error; + else + displayname = *argv; + } else if (!strncmp(*argv, "-gamma", 2)) { + if (!*++argv) + ++error; + else { + rpng2_info.display_exponent = atof(*argv); + if (rpng2_info.display_exponent <= 0.0) + ++error; + } + } else if (!strncmp(*argv, "-bgcolor", 4)) { + if (!*++argv) + ++error; + else { + bgstr = *argv; + if (strlen(bgstr) != 7 || bgstr[0] != '#') + ++error; + else { + have_bg = TRUE; + bg_image = FALSE; + } + } + } else if (!strncmp(*argv, "-bgpat", 4)) { + if (!*++argv) + ++error; + else { + pat = atoi(*argv); + if (pat >= 0 && pat < num_bgpat) { + bg_image = TRUE; + have_bg = FALSE; + } else + ++error; + } + } else if (!strncmp(*argv, "-usleep", 2)) { + if (!*++argv) + ++error; + else { + usleep_duration = (ulg)atol(*argv); + demo_timing = TRUE; + } + } else if (!strncmp(*argv, "-pause", 2)) { + pause_after_pass = TRUE; + } else if (!strncmp(*argv, "-timing", 2)) { + timing = TRUE; +#ifdef FEATURE_LOOP + } else if (!strncmp(*argv, "-loop", 2)) { + loop = TRUE; + if (!argv[1] || !is_number(argv[1])) + loop_interval = 2; + else { + ++argv; + loop_interval = atol(*argv); + if (loop_interval < 0) + loop_interval = 2; + else if (loop_interval > 100000) /* bit more than one day */ + loop_interval = 100000; + } +#endif + } else { + if (**argv != '-') { + filename = *argv; + if (argv[1]) /* shouldn't be any more args after filename */ + ++error; + } else + ++error; /* not expecting any other options */ + } + } + + if (!filename) + ++error; + + + /* print usage screen if any errors up to this point */ + + if (error) { + fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname); + readpng2_version_info(); + fprintf(stderr, "\n" + "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n" +#ifdef FEATURE_LOOP + " %*s [-usleep dur | -timing] [-pause] [-loop [sec]] file.png\n\n" +#else + " %*s [-usleep dur | -timing] [-pause] file.png\n\n" +#endif + " xdpy\tname of the target X display (e.g., ``hostname:0'')\n" + " exp \ttransfer-function exponent (``gamma'') of the display\n" + "\t\t system in floating-point format (e.g., ``%.1f''); equal\n" + "\t\t to the product of the lookup-table exponent (varies)\n" + "\t\t and the CRT exponent (usually 2.2); must be positive\n" + " bg \tdesired background color in 7-character hex RGB format\n" + "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n" + "\t\t used with transparent images; overrides -bgpat\n" + " pat \tdesired background pattern number (0-%d); used with\n" + "\t\t transparent images; overrides -bgcolor\n" +#ifdef FEATURE_LOOP + " -loop\tloops through background images after initial display\n" + "\t\t is complete (depends on -bgpat)\n" + " sec \tseconds to display each background image (default = 2)\n" +#endif + " dur \tduration in microseconds to wait after displaying each\n" + "\t\t row (for demo purposes)\n" + " -timing\tenables delay for every block read, to simulate modem\n" + "\t\t download of image (~36 Kbps)\n" + " -pause\tpauses after displaying each pass until mouse clicked\n" + "\nPress Q, Esc or mouse button 1 (within image window, after image\n" + "is displayed) to quit.\n" + "\n", PROGNAME, + (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat-1); + exit(1); + } + + + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename); + ++error; + } else { + incount = fread(inbuf, 1, INBUFSIZE, infile); + if (incount < 8 || !readpng2_check_sig(inbuf, 8)) { + fprintf(stderr, PROGNAME + ": [%s] is not a PNG file: incorrect signature\n", + filename); + ++error; + } else if ((rc = readpng2_init(&rpng2_info)) != 0) { + switch (rc) { + case 2: + fprintf(stderr, PROGNAME + ": [%s] has bad IHDR (libpng longjmp)\n", filename); + break; + case 4: + fprintf(stderr, PROGNAME ": insufficient memory\n"); + break; + default: + fprintf(stderr, PROGNAME + ": unknown readpng2_init() error\n"); + break; + } + ++error; + } else { + Trace((stderr, "about to call XOpenDisplay()\n")) + display = XOpenDisplay(displayname); + if (!display) { + readpng2_cleanup(&rpng2_info); + fprintf(stderr, PROGNAME ": can't open X display [%s]\n", + displayname? displayname : "default"); + ++error; + } + } + if (error) + fclose(infile); + } + + + if (error) { + fprintf(stderr, PROGNAME ": aborting.\n"); + exit(2); + } + + + /* set the title-bar string, but make sure buffer doesn't overflow */ + + alen = strlen(appname); + flen = strlen(filename); + if (alen + flen + 3 > 1023) + sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023)); + else + sprintf(titlebar, "%s: %s", appname, filename); + + + /* set some final rpng2_info variables before entering main data loop */ + + if (have_bg) { + unsigned r, g, b; /* this approach quiets compiler warnings */ + + sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); + rpng2_info.bg_red = (uch)r; + rpng2_info.bg_green = (uch)g; + rpng2_info.bg_blue = (uch)b; + } else + rpng2_info.need_bgcolor = TRUE; + + rpng2_info.state = kPreInit; + rpng2_info.mainprog_init = rpng2_x_init; + rpng2_info.mainprog_display_row = rpng2_x_display_row; + rpng2_info.mainprog_finish_display = rpng2_x_finish_display; + + + /* OK, this is the fun part: call readpng2_decode_data() at the start of + * the loop to deal with our first buffer of data (read in above to verify + * that the file is a PNG image), then loop through the file and continue + * calling the same routine to handle each chunk of data. It in turn + * passes the data to libpng, which will invoke one or more of our call- + * backs as decoded data become available. We optionally call sleep() for + * one second per iteration to simulate downloading the image via an analog + * modem. */ + + for (;;) { + Trace((stderr, "about to call readpng2_decode_data()\n")) + if (readpng2_decode_data(&rpng2_info, inbuf, incount)) + ++error; + Trace((stderr, "done with readpng2_decode_data()\n")) + + if (error || incount != INBUFSIZE || rpng2_info.state == kDone) { + if (rpng2_info.state == kDone) { + Trace((stderr, "done decoding PNG image\n")) + } else if (ferror(infile)) { + fprintf(stderr, PROGNAME + ": error while reading PNG image file\n"); + exit(3); + } else if (feof(infile)) { + fprintf(stderr, PROGNAME ": end of file reached " + "(unexpectedly) while reading PNG image file\n"); + exit(3); + } else /* if (error) */ { + /* will print error message below */ + } + break; + } + + if (timing) + sleep(1); + + incount = fread(inbuf, 1, INBUFSIZE, infile); + } + + + /* clean up PNG stuff and report any decoding errors */ + + fclose(infile); + Trace((stderr, "about to call readpng2_cleanup()\n")) + readpng2_cleanup(&rpng2_info); + + if (error) { + fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n"); + exit(3); + } + + +#ifdef FEATURE_LOOP + + if (loop && bg_image) { + Trace((stderr, "entering -loop loop (FEATURE_LOOP)\n")) + for (;;) { + int i, use_sleep; + struct timeval now, then; + + /* get current time and add loop_interval to get target time */ + if (gettimeofday(&then, NULL) == 0) { + then.tv_sec += loop_interval; + use_sleep = FALSE; + } else + use_sleep = TRUE; + + /* do quick check for a quit event but don't wait for it */ + /* GRR BUG: should also check for Expose events and redraw... */ + if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &e)) + if (QUIT(e,k)) + break; + + /* generate next background image */ + if (++pat >= num_bgpat) + pat = 0; + rpng2_x_reload_bg_image(); + + /* wait for timeout, using whatever means are available */ + if (use_sleep || gettimeofday(&now, NULL) != 0) { + for (i = loop_interval; i > 0; --i) { + sleep(1); + /* GRR BUG: also need to check for Expose (and redraw!) */ + if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, + &e) && QUIT(e,k)) + break; + } + } else { + /* Y2038 BUG! */ + if (now.tv_sec < then.tv_sec || + (now.tv_sec == then.tv_sec && now.tv_usec < then.tv_usec)) + { + int quit = FALSE; + long seconds_to_go = then.tv_sec - now.tv_sec; + long usleep_usec; + + /* basically chew up most of remaining loop-interval with + * calls to sleep(1) interleaved with checks for quit + * events, but also recalc time-to-go periodically; when + * done, clean up any remaining time with usleep() call + * (could also use SIGALRM, but signals are a pain...) */ + while (seconds_to_go-- > 1) { + int seconds_done = 0; + + for (i = seconds_to_go; i > 0 && !quit; --i) { + sleep(1); + /* GRR BUG: need to check for Expose and redraw */ + if (XCheckMaskEvent(display, KeyPressMask | + ButtonPressMask, &e) && QUIT(e,k)) + quit = TRUE; + if (++seconds_done > 1000) + break; /* time to redo seconds_to_go meas. */ + } + if (quit) + break; + + /* OK, more than 1000 seconds since last check: + * correct the time-to-go measurement for drift */ + if (gettimeofday(&now, NULL) == 0) { + if (now.tv_sec >= then.tv_sec) + break; + seconds_to_go = then.tv_sec - now.tv_sec; + } else + ++seconds_to_go; /* restore what we subtracted */ + } + if (quit) + break; /* breaks outer do-loop, skips redisplay */ + + /* since difference between "now" and "then" is already + * eaten up to within a couple of seconds, don't need to + * worry about overflow--but might have overshot (neg.) */ + if (gettimeofday(&now, NULL) == 0) { + usleep_usec = 1000000L*(then.tv_sec - now.tv_sec) + + then.tv_usec - now.tv_usec; + if (usleep_usec > 0) + usleep((ulg)usleep_usec); + } + } + } + + /* composite image against new background and display (note that + * we do not take into account the time spent doing this...) */ + rpng2_x_redisplay_image (0, 0, rpng2_info.width, rpng2_info.height); + } + + } else /* FALL THROUGH and do the normal thing */ + +#endif /* FEATURE_LOOP */ + + /* wait for the user to tell us when to quit */ + + if (rpng2_info.state >= kWindowInit) { + Trace((stderr, "entering final wait-for-quit-event loop\n")) + do { + XNextEvent(display, &e); + if (e.type == Expose) { + XExposeEvent *ex = (XExposeEvent *)&e; + rpng2_x_redisplay_image (ex->x, ex->y, ex->width, ex->height); + } + } while (!QUIT(e,k)); + } else { + fprintf(stderr, PROGNAME ": init callback never called: probable " + "libpng error while decoding PNG metadata\n"); + exit(4); + } + + + /* we're done: clean up all image and X resources and go away */ + + Trace((stderr, "about to call rpng2_x_cleanup()\n")) + rpng2_x_cleanup(); + + return 0; +} + + + + + +/* this function is called by readpng2_info_callback() in readpng2.c, which + * in turn is called by libpng after all of the pre-IDAT chunks have been + * read and processed--i.e., we now have enough info to finish initializing */ + +static void rpng2_x_init(void) +{ + ulg i; + ulg rowbytes = rpng2_info.rowbytes; + + Trace((stderr, "beginning rpng2_x_init()\n")) + Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes)) + Trace((stderr, " width = %ld\n", rpng2_info.width)) + Trace((stderr, " height = %ld\n", rpng2_info.height)) + + rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height); + if (!rpng2_info.image_data) { + readpng2_cleanup(&rpng2_info); + return; + } + + rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *)); + if (!rpng2_info.row_pointers) { + free(rpng2_info.image_data); + rpng2_info.image_data = NULL; + readpng2_cleanup(&rpng2_info); + return; + } + + for (i = 0; i < rpng2_info.height; ++i) + rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes; + + + /* do the basic X initialization stuff, make the window, and fill it with + * the user-specified, file-specified or default background color or + * pattern */ + + if (rpng2_x_create_window()) { + + /* GRR TEMPORARY HACK: this is fundamentally no different from cases + * above; libpng should call our error handler to longjmp() back to us + * when png_ptr goes away. If we/it segfault instead, seems like a + * libpng bug... */ + + /* we're here via libpng callback, so if window fails, clean and bail */ + readpng2_cleanup(&rpng2_info); + rpng2_x_cleanup(); + exit(2); + } + + rpng2_info.state = kWindowInit; +} + + + + + +static int rpng2_x_create_window(void) +{ + ulg bg_red = rpng2_info.bg_red; + ulg bg_green = rpng2_info.bg_green; + ulg bg_blue = rpng2_info.bg_blue; + ulg bg_pixel = 0L; + ulg attrmask; + int need_colormap = FALSE; + int screen, pad; + uch *xdata; + Window root; + XEvent e; + XGCValues gcvalues; + XSetWindowAttributes attr; + XTextProperty windowName, *pWindowName = &windowName; + XTextProperty iconName, *pIconName = &iconName; + XVisualInfo visual_info; + XSizeHints *size_hints; + XWMHints *wm_hints; + XClassHint *class_hints; + + + Trace((stderr, "beginning rpng2_x_create_window()\n")) + + screen = DefaultScreen(display); + depth = DisplayPlanes(display, screen); + root = RootWindow(display, screen); + +#ifdef DEBUG + XSynchronize(display, True); +#endif + + if (depth != 16 && depth != 24 && depth != 32) { + int visuals_matched = 0; + + Trace((stderr, "default depth is %d: checking other visuals\n", + depth)) + + /* 24-bit first */ + visual_info.screen = screen; + visual_info.depth = 24; + visual_list = XGetVisualInfo(display, + VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched); + if (visuals_matched == 0) { +/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */ + fprintf(stderr, "default screen depth %d not supported, and no" + " 24-bit visuals found\n", depth); + return 2; + } + Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n", + visuals_matched)) + visual = visual_list[0].visual; + depth = visual_list[0].depth; +/* + colormap_size = visual_list[0].colormap_size; + visual_class = visual->class; + visualID = XVisualIDFromVisual(visual); + */ + have_nondefault_visual = TRUE; + need_colormap = TRUE; + } else { + XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info); + visual = visual_info.visual; + } + + RMask = visual->red_mask; + GMask = visual->green_mask; + BMask = visual->blue_mask; + +/* GRR: add/check 8-bit support */ + if (depth == 8 || need_colormap) { + colormap = XCreateColormap(display, root, visual, AllocNone); + if (!colormap) { + fprintf(stderr, "XCreateColormap() failed\n"); + return 2; + } + have_colormap = TRUE; + if (depth == 8) + bg_image = FALSE; /* gradient just wastes palette entries */ + } + if (depth == 15 || depth == 16) { + RShift = 15 - rpng2_x_msb(RMask); /* these are right-shifts */ + GShift = 15 - rpng2_x_msb(GMask); + BShift = 15 - rpng2_x_msb(BMask); + } else if (depth > 16) { + RShift = rpng2_x_msb(RMask) - 7; /* these are left-shifts */ + GShift = rpng2_x_msb(GMask) - 7; + BShift = rpng2_x_msb(BMask) - 7; + } + if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) { + fprintf(stderr, "rpng2 internal logic error: negative X shift(s)!\n"); + return 2; + } + +/*--------------------------------------------------------------------------- + Finally, create the window. + ---------------------------------------------------------------------------*/ + + attr.backing_store = Always; + attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask; + attrmask = CWBackingStore | CWEventMask; + if (have_nondefault_visual) { + attr.colormap = colormap; + attr.background_pixel = 0; + attr.border_pixel = 1; + attrmask |= CWColormap | CWBackPixel | CWBorderPixel; + } + + window = XCreateWindow(display, root, 0, 0, rpng2_info.width, + rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr); + + if (window == None) { + fprintf(stderr, "XCreateWindow() failed\n"); + return 2; + } else + have_window = TRUE; + + if (depth == 8) + XSetWindowColormap(display, window, colormap); + + if (!XStringListToTextProperty(&window_name, 1, pWindowName)) + pWindowName = NULL; + if (!XStringListToTextProperty(&icon_name, 1, pIconName)) + pIconName = NULL; + + /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */ + + if ((size_hints = XAllocSizeHints()) != NULL) { + /* window will not be resizable */ + size_hints->flags = PMinSize | PMaxSize; + size_hints->min_width = size_hints->max_width = (int)rpng2_info.width; + size_hints->min_height = size_hints->max_height = + (int)rpng2_info.height; + } + + if ((wm_hints = XAllocWMHints()) != NULL) { + wm_hints->initial_state = NormalState; + wm_hints->input = True; + /* wm_hints->icon_pixmap = icon_pixmap; */ + wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ; + } + + if ((class_hints = XAllocClassHint()) != NULL) { + class_hints->res_name = res_name; + class_hints->res_class = res_class; + } + + XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0, + size_hints, wm_hints, class_hints); + + /* various properties and hints no longer needed; free memory */ + if (pWindowName) + XFree(pWindowName->value); + if (pIconName) + XFree(pIconName->value); + if (size_hints) + XFree(size_hints); + if (wm_hints) + XFree(wm_hints); + if (class_hints) + XFree(class_hints); + + XMapWindow(display, window); + + gc = XCreateGC(display, window, 0, &gcvalues); + have_gc = TRUE; + +/*--------------------------------------------------------------------------- + Allocate memory for the X- and display-specific version of the image. + ---------------------------------------------------------------------------*/ + + if (depth == 24 || depth == 32) { + xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height); + pad = 32; + } else if (depth == 16) { + xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height); + pad = 16; + } else /* depth == 8 */ { + xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height); + pad = 8; + } + + if (!xdata) { + fprintf(stderr, PROGNAME ": unable to allocate image memory\n"); + return 4; + } + + ximage = XCreateImage(display, visual, depth, ZPixmap, 0, + (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0); + + if (!ximage) { + fprintf(stderr, PROGNAME ": XCreateImage() failed\n"); + free(xdata); + return 3; + } + + /* to avoid testing the byte order every pixel (or doubling the size of + * the drawing routine with a giant if-test), we arbitrarily set the byte + * order to MSBFirst and let Xlib worry about inverting things on little- + * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the + * most efficient approach (the giant if-test would be better), but in + * the interest of clarity, we'll take the easy way out... */ + + ximage->byte_order = MSBFirst; + +/*--------------------------------------------------------------------------- + Fill window with the specified background color (default is black) or + faked "background image" (but latter is disabled if 8-bit; gradients + just waste palette entries). + ---------------------------------------------------------------------------*/ + + if (bg_image) + rpng2_x_load_bg_image(); /* resets bg_image if fails */ + + if (!bg_image) { + if (depth == 24 || depth == 32) { + bg_pixel = (bg_red << RShift) | + (bg_green << GShift) | + (bg_blue << BShift); + } else if (depth == 16) { + bg_pixel = (((bg_red << 8) >> RShift) & RMask) | + (((bg_green << 8) >> GShift) & GMask) | + (((bg_blue << 8) >> BShift) & BMask); + } else /* depth == 8 */ { + + /* GRR: add 8-bit support */ + + } + XSetForeground(display, gc, bg_pixel); + XFillRectangle(display, window, gc, 0, 0, rpng2_info.width, + rpng2_info.height); + } + +/*--------------------------------------------------------------------------- + Wait for first Expose event to do any drawing, then flush and return. + ---------------------------------------------------------------------------*/ + + do + XNextEvent(display, &e); + while (e.type != Expose || e.xexpose.count); + + XFlush(display); + + return 0; + +} /* end function rpng2_x_create_window() */ + + + + + +static int rpng2_x_load_bg_image(void) +{ + uch *src; + char *dest; + uch r1, r2, g1, g2, b1, b2; + uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv; + int k, hmax, max; + int xidx, yidx, yidx_max; + int even_odd_vert, even_odd_horiz, even_odd; + int invert_gradient2 = (bg[pat].type & 0x08); + int invert_column; + int ximage_rowbytes = ximage->bytes_per_line; + ulg i, row; + ulg pixel; + +/*--------------------------------------------------------------------------- + Allocate buffer for fake background image to be used with transparent + images; if this fails, revert to plain background color. + ---------------------------------------------------------------------------*/ + + bg_rowbytes = 3 * rpng2_info.width; + bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height); + if (!bg_data) { + fprintf(stderr, PROGNAME + ": unable to allocate memory for background image\n"); + bg_image = 0; + return 1; + } + + bgscale = (pat == 0)? 8 : bgscale_default; + yidx_max = bgscale - 1; + +/*--------------------------------------------------------------------------- + Vertical gradients (ramps) in NxN squares, alternating direction and + colors (N == bgscale). + ---------------------------------------------------------------------------*/ + + if ((bg[pat].type & 0x07) == 0) { + uch r1_min = rgb[bg[pat].rgb1_min].r; + uch g1_min = rgb[bg[pat].rgb1_min].g; + uch b1_min = rgb[bg[pat].rgb1_min].b; + uch r2_min = rgb[bg[pat].rgb2_min].r; + uch g2_min = rgb[bg[pat].rgb2_min].g; + uch b2_min = rgb[bg[pat].rgb2_min].b; + int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min; + int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min; + int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min; + int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min; + int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min; + int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min; + + for (row = 0; row < rpng2_info.height; ++row) { + yidx = (int)(row % bgscale); + even_odd_vert = (int)((row / bgscale) & 1); + + r1 = r1_min + (r1_diff * yidx) / yidx_max; + g1 = g1_min + (g1_diff * yidx) / yidx_max; + b1 = b1_min + (b1_diff * yidx) / yidx_max; + r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max; + g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max; + b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max; + + r2 = r2_min + (r2_diff * yidx) / yidx_max; + g2 = g2_min + (g2_diff * yidx) / yidx_max; + b2 = b2_min + (b2_diff * yidx) / yidx_max; + r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max; + g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max; + b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max; + + dest = (char *)bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + even_odd_horiz = (int)((i / bgscale) & 1); + even_odd = even_odd_vert ^ even_odd_horiz; + invert_column = + (even_odd_horiz && (bg[pat].type & 0x10)); + if (even_odd == 0) { /* gradient #1 */ + if (invert_column) { + *dest++ = r1_inv; + *dest++ = g1_inv; + *dest++ = b1_inv; + } else { + *dest++ = r1; + *dest++ = g1; + *dest++ = b1; + } + } else { /* gradient #2 */ + if ((invert_column && invert_gradient2) || + (!invert_column && !invert_gradient2)) + { + *dest++ = r2; /* not inverted or */ + *dest++ = g2; /* doubly inverted */ + *dest++ = b2; + } else { + *dest++ = r2_inv; + *dest++ = g2_inv; /* singly inverted */ + *dest++ = b2_inv; + } + } + } + } + +/*--------------------------------------------------------------------------- + Soft gradient-diamonds with scale = bgscale. Code contributed by Adam + M. Costello. + ---------------------------------------------------------------------------*/ + + } else if ((bg[pat].type & 0x07) == 1) { + + hmax = (bgscale-1)/2; /* half the max weight of a color */ + max = 2*hmax; /* the max weight of a color */ + + r1 = rgb[bg[pat].rgb1_max].r; + g1 = rgb[bg[pat].rgb1_max].g; + b1 = rgb[bg[pat].rgb1_max].b; + r2 = rgb[bg[pat].rgb2_max].r; + g2 = rgb[bg[pat].rgb2_max].g; + b2 = rgb[bg[pat].rgb2_max].b; + + for (row = 0; row < rpng2_info.height; ++row) { + yidx = (int)(row % bgscale); + if (yidx > hmax) + yidx = bgscale-1 - yidx; + dest = (char *)bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + xidx = (int)(i % bgscale); + if (xidx > hmax) + xidx = bgscale-1 - xidx; + k = xidx + yidx; + *dest++ = (k*r1 + (max-k)*r2) / max; + *dest++ = (k*g1 + (max-k)*g2) / max; + *dest++ = (k*b1 + (max-k)*b2) / max; + } + } + +/*--------------------------------------------------------------------------- + Radial "starburst" with azimuthal sinusoids; [eventually number of sinu- + soids will equal bgscale?]. This one is slow but very cool. Code con- + tributed by Pieter S. van der Meulen (originally in Smalltalk). + ---------------------------------------------------------------------------*/ + + } else if ((bg[pat].type & 0x07) == 2) { + uch ch; + int ii, x, y, hw, hh, grayspot; + double freq, rotate, saturate, gray, intensity; + double angle=0.0, aoffset=0.0, maxDist, dist; + double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t; + + fprintf(stderr, "%s: computing radial background...", + PROGNAME); + fflush(stderr); + + hh = (int)(rpng2_info.height / 2); + hw = (int)(rpng2_info.width / 2); + + /* variables for radial waves: + * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED] + * freq: number of color beams originating from the center + * grayspot: size of the graying center area (anti-alias) + * rotate: rotation of the beams as a function of radius + * saturate: saturation of beams' shape azimuthally + */ + angle = CLIP(angle, 0.0, 360.0); + grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw)); + freq = MAX((double)bg[pat].bg_freq, 0.0); + saturate = (double)bg[pat].bg_bsat * 0.1; + rotate = (double)bg[pat].bg_brot * 0.1; + gray = 0.0; + intensity = 0.0; + maxDist = (double)((hw*hw) + (hh*hh)); + + for (row = 0; row < rpng2_info.height; ++row) { + y = (int)(row - hh); + dest = (char *)bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + x = (int)(i - hw); + angle = (x == 0)? PI_2 : atan((double)y / (double)x); + gray = (double)MAX(ABS(y), ABS(x)) / grayspot; + gray = MIN(1.0, gray); + dist = (double)((x*x) + (y*y)) / maxDist; + intensity = cos((angle+(rotate*dist*PI)) * freq) * + gray * saturate; + intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5; + hue = (angle + PI) * INV_PI_360 + aoffset; + s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh)); + s = MIN(MAX(s,0.0), 1.0); + v = MIN(MAX(intensity,0.0), 1.0); + + if (s == 0.0) { + ch = (uch)(v * 255.0); + *dest++ = ch; + *dest++ = ch; + *dest++ = ch; + } else { + if ((hue < 0.0) || (hue >= 360.0)) + hue -= (((int)(hue / 360.0)) * 360.0); + hue /= 60.0; + ii = (int)hue; + f = hue - (double)ii; + p = (1.0 - s) * v; + q = (1.0 - (s * f)) * v; + t = (1.0 - (s * (1.0 - f))) * v; + if (ii == 0) { red = v; green = t; blue = p; } + else if (ii == 1) { red = q; green = v; blue = p; } + else if (ii == 2) { red = p; green = v; blue = t; } + else if (ii == 3) { red = p; green = q; blue = v; } + else if (ii == 4) { red = t; green = p; blue = v; } + else if (ii == 5) { red = v; green = p; blue = q; } + *dest++ = (uch)(red * 255.0); + *dest++ = (uch)(green * 255.0); + *dest++ = (uch)(blue * 255.0); + } + } + } + fprintf(stderr, "done.\n"); + fflush(stderr); + } + +/*--------------------------------------------------------------------------- + Blast background image to display buffer before beginning PNG decode. + ---------------------------------------------------------------------------*/ + + if (depth == 24 || depth == 32) { + ulg red, green, blue; + int bpp = ximage->bits_per_pixel; + + for (row = 0; row < rpng2_info.height; ++row) { + src = bg_data + row*bg_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (bpp == 32) { /* slightly optimized version */ + for (i = rpng2_info.width; i > 0; --i) { + red = *src++; + green = *src++; + blue = *src++; + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } else { + for (i = rpng2_info.width; i > 0; --i) { + red = *src++; + green = *src++; + blue = *src++; + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + /* GRR BUG? this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift, RMask, etc.) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + } + + } else if (depth == 16) { + ush red, green, blue; + + for (row = 0; row < rpng2_info.height; ++row) { + src = bg_data + row*bg_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + for (i = rpng2_info.width; i > 0; --i) { + red = ((ush)(*src) << 8); ++src; + green = ((ush)(*src) << 8); ++src; + blue = ((ush)(*src) << 8); ++src; + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + + } else /* depth == 8 */ { + + /* GRR: add 8-bit support */ + + } + + XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width, + rpng2_info.height); + + return 0; + +} /* end function rpng2_x_load_bg_image() */ + + + + + +static void rpng2_x_display_row(ulg row) +{ + uch bg_red = rpng2_info.bg_red; + uch bg_green = rpng2_info.bg_green; + uch bg_blue = rpng2_info.bg_blue; + uch *src, *src2=NULL; + char *dest; + uch r, g, b, a; + int ximage_rowbytes = ximage->bytes_per_line; + ulg i, pixel; + static int rows=0, prevpass=(-1); + static ulg firstrow; + +/*--------------------------------------------------------------------------- + rows and firstrow simply track how many rows (and which ones) have not + yet been displayed; alternatively, we could call XPutImage() for every + row and not bother with the records-keeping. + ---------------------------------------------------------------------------*/ + + Trace((stderr, "beginning rpng2_x_display_row()\n")) + + if (rpng2_info.pass != prevpass) { + if (pause_after_pass && rpng2_info.pass > 0) { + XEvent e; + KeySym k; + + fprintf(stderr, + "%s: end of pass %d of 7; click in image window to continue\n", + PROGNAME, prevpass + 1); + do + XNextEvent(display, &e); + while (!QUIT(e,k)); + } + fprintf(stderr, "%s: pass %d of 7\r", PROGNAME, rpng2_info.pass + 1); + fflush(stderr); + prevpass = rpng2_info.pass; + } + + if (rows == 0) + firstrow = row; /* first row that is not yet displayed */ + + ++rows; /* count of rows received but not yet displayed */ + +/*--------------------------------------------------------------------------- + Aside from the use of the rpng2_info struct, the lack of an outer loop + (over rows) and moving the XPutImage() call outside the "if (depth)" + tests, this routine is identical to rpng_x_display_image() in the non- + progressive version of the program. + ---------------------------------------------------------------------------*/ + + if (depth == 24 || depth == 32) { + ulg red, green, blue; + int bpp = ximage->bits_per_pixel; + + src = rpng2_info.image_data + row*rpng2_info.rowbytes; + if (bg_image) + src2 = bg_data + row*bg_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (rpng2_info.channels == 3) { + for (i = rpng2_info.width; i > 0; --i) { + red = *src++; + green = *src++; + blue = *src++; + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + if (bpp == 32) { + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } else { + /* GRR BUG? this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift, RMask, etc.) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + } else /* if (rpng2_info.channels == 4) */ { + for (i = rpng2_info.width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (bg_image) { + bg_red = *src2++; + bg_green = *src2++; + bg_blue = *src2++; + } + if (a == 255) { + red = r; + green = g; + blue = b; + } else if (a == 0) { + red = bg_red; + green = bg_green; + blue = bg_blue; + } else { + /* this macro (from png.h) composites the foreground + * and background values and puts the result into the + * first argument */ + alpha_composite(red, r, a, bg_red); + alpha_composite(green, g, a, bg_green); + alpha_composite(blue, b, a, bg_blue); + } + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + if (bpp == 32) { + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } else { + /* GRR BUG? this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift, RMask, etc.) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + } + + } else if (depth == 16) { + ush red, green, blue; + + src = rpng2_info.row_pointers[row]; + if (bg_image) + src2 = bg_data + row*bg_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (rpng2_info.channels == 3) { + for (i = rpng2_info.width; i > 0; --i) { + red = ((ush)(*src) << 8); + ++src; + green = ((ush)(*src) << 8); + ++src; + blue = ((ush)(*src) << 8); + ++src; + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } else /* if (rpng2_info.channels == 4) */ { + for (i = rpng2_info.width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (bg_image) { + bg_red = *src2++; + bg_green = *src2++; + bg_blue = *src2++; + } + if (a == 255) { + red = ((ush)r << 8); + green = ((ush)g << 8); + blue = ((ush)b << 8); + } else if (a == 0) { + red = ((ush)bg_red << 8); + green = ((ush)bg_green << 8); + blue = ((ush)bg_blue << 8); + } else { + /* this macro (from png.h) composites the foreground + * and background values and puts the result back into + * the first argument (== fg byte here: safe) */ + alpha_composite(r, r, a, bg_red); + alpha_composite(g, g, a, bg_green); + alpha_composite(b, b, a, bg_blue); + red = ((ush)r << 8); + green = ((ush)g << 8); + blue = ((ush)b << 8); + } + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + + } else /* depth == 8 */ { + + /* GRR: add 8-bit support */ + + } + + +/*--------------------------------------------------------------------------- + Display after every 16 rows or when on one of last two rows. (Region + may include previously displayed lines due to interlacing--i.e., not + contiguous. Also, second-to-last row is final one in interlaced images + with odd number of rows.) For demos, flush (and delay) after every 16th + row so "sparse" passes don't go twice as fast. + ---------------------------------------------------------------------------*/ + + if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) { + XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0, + (int)firstrow, rpng2_info.width, row - firstrow + 1); + XFlush(display); + rows = 0; + usleep(usleep_duration); + } else + if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) { + XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0, + (int)firstrow, rpng2_info.width, row - firstrow + 1); + XFlush(display); + rows = 0; + } + +} + + + + + +static void rpng2_x_finish_display(void) +{ + Trace((stderr, "beginning rpng2_x_finish_display()\n")) + + /* last row has already been displayed by rpng2_x_display_row(), so we + * have nothing to do here except set a flag and let the user know that + * the image is done */ + + rpng2_info.state = kDone; + printf( + "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n"); + fflush(stdout); +} + + + + + +static void rpng2_x_redisplay_image(ulg startcol, ulg startrow, + ulg width, ulg height) +{ + uch bg_red = rpng2_info.bg_red; + uch bg_green = rpng2_info.bg_green; + uch bg_blue = rpng2_info.bg_blue; + uch *src, *src2=NULL; + char *dest; + uch r, g, b, a; + ulg i, row, lastrow = 0; + ulg pixel; + int ximage_rowbytes = ximage->bytes_per_line; + + + Trace((stderr, "beginning display loop (image_channels == %d)\n", + rpng2_info.channels)) + Trace((stderr, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n", + rpng2_info.width, rpng2_info.rowbytes, ximage_rowbytes)) + Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel)) + Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst? + "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown"))) + +/*--------------------------------------------------------------------------- + Aside from the use of the rpng2_info struct and of src2 (for background + image), this routine is identical to rpng_x_display_image() in the non- + progressive version of the program--for the simple reason that redisplay + of the image against a new background happens after the image is fully + decoded and therefore is, by definition, non-progressive. + ---------------------------------------------------------------------------*/ + + if (depth == 24 || depth == 32) { + ulg red, green, blue; + int bpp = ximage->bits_per_pixel; + + for (lastrow = row = startrow; row < startrow+height; ++row) { + src = rpng2_info.image_data + row*rpng2_info.rowbytes; + if (bg_image) + src2 = bg_data + row*bg_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (rpng2_info.channels == 3) { + for (i = rpng2_info.width; i > 0; --i) { + red = *src++; + green = *src++; + blue = *src++; +#ifdef NO_24BIT_MASKS + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + if (bpp == 32) { + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } else { + /* this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift, RMask, etc.) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } +#else + red = (RShift < 0)? red << (-RShift) : red >> RShift; + green = (GShift < 0)? green << (-GShift) : green >> GShift; + blue = (BShift < 0)? blue << (-BShift) : blue >> BShift; + pixel = (red & RMask) | (green & GMask) | (blue & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + if (bpp == 32) { + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } else { + /* GRR BUG */ + /* this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift/RMask/etc. here, too) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } +#endif + } + + } else /* if (rpng2_info.channels == 4) */ { + for (i = rpng2_info.width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (bg_image) { + bg_red = *src2++; + bg_green = *src2++; + bg_blue = *src2++; + } + if (a == 255) { + red = r; + green = g; + blue = b; + } else if (a == 0) { + red = bg_red; + green = bg_green; + blue = bg_blue; + } else { + /* this macro (from png.h) composites the foreground + * and background values and puts the result into the + * first argument */ + alpha_composite(red, r, a, bg_red); + alpha_composite(green, g, a, bg_green); + alpha_composite(blue, b, a, bg_blue); + } +#ifdef NO_24BIT_MASKS + pixel = (red << RShift) | + (green << GShift) | + (blue << BShift); + /* recall that we set ximage->byte_order = MSBFirst above */ + if (bpp == 32) { + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } else { + /* this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift, RMask, etc.) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } +#else + red = (RShift < 0)? red << (-RShift) : red >> RShift; + green = (GShift < 0)? green << (-GShift) : green >> GShift; + blue = (BShift < 0)? blue << (-BShift) : blue >> BShift; + pixel = (red & RMask) | (green & GMask) | (blue & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + if (bpp == 32) { + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } else { + /* GRR BUG */ + /* this assumes bpp == 24 & bits are packed low */ + /* (probably need to use RShift/RMask/etc. here, too) */ + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } +#endif + } + } + /* display after every 16 lines */ + if (((row+1) & 0xf) == 0) { + XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, rpng2_info.width, 16); + XFlush(display); + lastrow = row + 1; + } + } + + } else if (depth == 16) { + ush red, green, blue; + + for (lastrow = row = startrow; row < startrow+height; ++row) { + src = rpng2_info.row_pointers[row]; + if (bg_image) + src2 = bg_data + row*bg_rowbytes; + dest = ximage->data + row*ximage_rowbytes; + if (rpng2_info.channels == 3) { + for (i = rpng2_info.width; i > 0; --i) { + red = ((ush)(*src) << 8); + ++src; + green = ((ush)(*src) << 8); + ++src; + blue = ((ush)(*src) << 8); + ++src; + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } else /* if (rpng2_info.channels == 4) */ { + for (i = rpng2_info.width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (bg_image) { + bg_red = *src2++; + bg_green = *src2++; + bg_blue = *src2++; + } + if (a == 255) { + red = ((ush)r << 8); + green = ((ush)g << 8); + blue = ((ush)b << 8); + } else if (a == 0) { + red = ((ush)bg_red << 8); + green = ((ush)bg_green << 8); + blue = ((ush)bg_blue << 8); + } else { + /* this macro (from png.h) composites the foreground + * and background values and puts the result back into + * the first argument (== fg byte here: safe) */ + alpha_composite(r, r, a, bg_red); + alpha_composite(g, g, a, bg_green); + alpha_composite(b, b, a, bg_blue); + red = ((ush)r << 8); + green = ((ush)g << 8); + blue = ((ush)b << 8); + } + pixel = ((red >> RShift) & RMask) | + ((green >> GShift) & GMask) | + ((blue >> BShift) & BMask); + /* recall that we set ximage->byte_order = MSBFirst above */ + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)( pixel & 0xff); + } + } + /* display after every 16 lines */ + if (((row+1) & 0xf) == 0) { + XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, rpng2_info.width, 16); + XFlush(display); + lastrow = row + 1; + } + } + + } else /* depth == 8 */ { + + /* GRR: add 8-bit support */ + + } + + Trace((stderr, "calling final XPutImage()\n")) + if (lastrow < startrow+height) { + XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, rpng2_info.width, rpng2_info.height-lastrow); + XFlush(display); + } + +} /* end function rpng2_x_redisplay_image() */ + + + + + +#ifdef FEATURE_LOOP + +static void rpng2_x_reload_bg_image(void) +{ + char *dest; + uch r1, r2, g1, g2, b1, b2; + uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv; + int k, hmax, max; + int xidx, yidx, yidx_max; + int even_odd_vert, even_odd_horiz, even_odd; + int invert_gradient2 = (bg[pat].type & 0x08); + int invert_column; + ulg i, row; + + + bgscale = (pat == 0)? 8 : bgscale_default; + yidx_max = bgscale - 1; + +/*--------------------------------------------------------------------------- + Vertical gradients (ramps) in NxN squares, alternating direction and + colors (N == bgscale). + ---------------------------------------------------------------------------*/ + + if ((bg[pat].type & 0x07) == 0) { + uch r1_min = rgb[bg[pat].rgb1_min].r; + uch g1_min = rgb[bg[pat].rgb1_min].g; + uch b1_min = rgb[bg[pat].rgb1_min].b; + uch r2_min = rgb[bg[pat].rgb2_min].r; + uch g2_min = rgb[bg[pat].rgb2_min].g; + uch b2_min = rgb[bg[pat].rgb2_min].b; + int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min; + int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min; + int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min; + int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min; + int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min; + int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min; + + for (row = 0; row < rpng2_info.height; ++row) { + yidx = (int)(row % bgscale); + even_odd_vert = (int)((row / bgscale) & 1); + + r1 = r1_min + (r1_diff * yidx) / yidx_max; + g1 = g1_min + (g1_diff * yidx) / yidx_max; + b1 = b1_min + (b1_diff * yidx) / yidx_max; + r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max; + g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max; + b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max; + + r2 = r2_min + (r2_diff * yidx) / yidx_max; + g2 = g2_min + (g2_diff * yidx) / yidx_max; + b2 = b2_min + (b2_diff * yidx) / yidx_max; + r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max; + g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max; + b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max; + + dest = (char *)bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + even_odd_horiz = (int)((i / bgscale) & 1); + even_odd = even_odd_vert ^ even_odd_horiz; + invert_column = + (even_odd_horiz && (bg[pat].type & 0x10)); + if (even_odd == 0) { /* gradient #1 */ + if (invert_column) { + *dest++ = r1_inv; + *dest++ = g1_inv; + *dest++ = b1_inv; + } else { + *dest++ = r1; + *dest++ = g1; + *dest++ = b1; + } + } else { /* gradient #2 */ + if ((invert_column && invert_gradient2) || + (!invert_column && !invert_gradient2)) + { + *dest++ = r2; /* not inverted or */ + *dest++ = g2; /* doubly inverted */ + *dest++ = b2; + } else { + *dest++ = r2_inv; + *dest++ = g2_inv; /* singly inverted */ + *dest++ = b2_inv; + } + } + } + } + +/*--------------------------------------------------------------------------- + Soft gradient-diamonds with scale = bgscale. Code contributed by Adam + M. Costello. + ---------------------------------------------------------------------------*/ + + } else if ((bg[pat].type & 0x07) == 1) { + + hmax = (bgscale-1)/2; /* half the max weight of a color */ + max = 2*hmax; /* the max weight of a color */ + + r1 = rgb[bg[pat].rgb1_max].r; + g1 = rgb[bg[pat].rgb1_max].g; + b1 = rgb[bg[pat].rgb1_max].b; + r2 = rgb[bg[pat].rgb2_max].r; + g2 = rgb[bg[pat].rgb2_max].g; + b2 = rgb[bg[pat].rgb2_max].b; + + for (row = 0; row < rpng2_info.height; ++row) { + yidx = (int)(row % bgscale); + if (yidx > hmax) + yidx = bgscale-1 - yidx; + dest = (char *)bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + xidx = (int)(i % bgscale); + if (xidx > hmax) + xidx = bgscale-1 - xidx; + k = xidx + yidx; + *dest++ = (k*r1 + (max-k)*r2) / max; + *dest++ = (k*g1 + (max-k)*g2) / max; + *dest++ = (k*b1 + (max-k)*b2) / max; + } + } + +/*--------------------------------------------------------------------------- + Radial "starburst" with azimuthal sinusoids; [eventually number of sinu- + soids will equal bgscale?]. This one is slow but very cool. Code con- + tributed by Pieter S. van der Meulen (originally in Smalltalk). + ---------------------------------------------------------------------------*/ + + } else if ((bg[pat].type & 0x07) == 2) { + uch ch; + int ii, x, y, hw, hh, grayspot; + double freq, rotate, saturate, gray, intensity; + double angle=0.0, aoffset=0.0, maxDist, dist; + double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t; + + hh = (int)(rpng2_info.height / 2); + hw = (int)(rpng2_info.width / 2); + + /* variables for radial waves: + * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED] + * freq: number of color beams originating from the center + * grayspot: size of the graying center area (anti-alias) + * rotate: rotation of the beams as a function of radius + * saturate: saturation of beams' shape azimuthally + */ + angle = CLIP(angle, 0.0, 360.0); + grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw)); + freq = MAX((double)bg[pat].bg_freq, 0.0); + saturate = (double)bg[pat].bg_bsat * 0.1; + rotate = (double)bg[pat].bg_brot * 0.1; + gray = 0.0; + intensity = 0.0; + maxDist = (double)((hw*hw) + (hh*hh)); + + for (row = 0; row < rpng2_info.height; ++row) { + y = (int)(row - hh); + dest = (char *)bg_data + row*bg_rowbytes; + for (i = 0; i < rpng2_info.width; ++i) { + x = (int)(i - hw); + angle = (x == 0)? PI_2 : atan((double)y / (double)x); + gray = (double)MAX(ABS(y), ABS(x)) / grayspot; + gray = MIN(1.0, gray); + dist = (double)((x*x) + (y*y)) / maxDist; + intensity = cos((angle+(rotate*dist*PI)) * freq) * + gray * saturate; + intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5; + hue = (angle + PI) * INV_PI_360 + aoffset; + s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh)); + s = MIN(MAX(s,0.0), 1.0); + v = MIN(MAX(intensity,0.0), 1.0); + + if (s == 0.0) { + ch = (uch)(v * 255.0); + *dest++ = ch; + *dest++ = ch; + *dest++ = ch; + } else { + if ((hue < 0.0) || (hue >= 360.0)) + hue -= (((int)(hue / 360.0)) * 360.0); + hue /= 60.0; + ii = (int)hue; + f = hue - (double)ii; + p = (1.0 - s) * v; + q = (1.0 - (s * f)) * v; + t = (1.0 - (s * (1.0 - f))) * v; + if (ii == 0) { red = v; green = t; blue = p; } + else if (ii == 1) { red = q; green = v; blue = p; } + else if (ii == 2) { red = p; green = v; blue = t; } + else if (ii == 3) { red = p; green = q; blue = v; } + else if (ii == 4) { red = t; green = p; blue = v; } + else if (ii == 5) { red = v; green = p; blue = q; } + *dest++ = (uch)(red * 255.0); + *dest++ = (uch)(green * 255.0); + *dest++ = (uch)(blue * 255.0); + } + } + } + } + +} /* end function rpng2_x_reload_bg_image() */ + + + + + +static int is_number(char *p) +{ + while (*p) { + if (!isdigit(*p)) + return FALSE; + ++p; + } + return TRUE; +} + +#endif /* FEATURE_LOOP */ + + + + + +static void rpng2_x_cleanup(void) +{ + if (bg_image && bg_data) { + free(bg_data); + bg_data = NULL; + } + + if (rpng2_info.image_data) { + free(rpng2_info.image_data); + rpng2_info.image_data = NULL; + } + + if (rpng2_info.row_pointers) { + free(rpng2_info.row_pointers); + rpng2_info.row_pointers = NULL; + } + + if (ximage) { + if (ximage->data) { + free(ximage->data); /* we allocated it, so we free it */ + ximage->data = (char *)NULL; /* instead of XDestroyImage() */ + } + XDestroyImage(ximage); + ximage = NULL; + } + + if (have_gc) + XFreeGC(display, gc); + + if (have_window) + XDestroyWindow(display, window); + + if (have_colormap) + XFreeColormap(display, colormap); + + if (have_nondefault_visual) + XFree(visual_list); +} + + + + + +static int rpng2_x_msb(ulg u32val) +{ + int i; + + for (i = 31; i >= 0; --i) { + if (u32val & 0x80000000L) + break; + u32val <<= 1; + } + return i; +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/wpng.c b/main/source/includes/lpng1610/contrib/gregbook/wpng.c index 30372a30..a06e3529 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/wpng.c +++ b/main/source/includes/lpng1610/contrib/gregbook/wpng.c @@ -1,853 +1,853 @@ -/*--------------------------------------------------------------------------- - - wpng - simple PNG-writing program wpng.c - - This program converts certain NetPBM binary files (grayscale and RGB, - maxval = 255) to PNG. Non-interlaced PNGs are written progressively; - interlaced PNGs are read and written in one memory-intensive blast. - - Thanks to Jean-loup Gailly for providing the necessary trick to read - interactive text from the keyboard while stdin is redirected. Thanks - to Cosmin Truta for Cygwin fixes. - - NOTE: includes provisional support for PNM type "8" (portable alphamap) - images, presumed to be a 32-bit interleaved RGBA format; no pro- - vision for possible interleaved grayscale+alpha (16-bit) format. - THIS IS UNLIKELY TO BECOME AN OFFICIAL NETPBM ALPHA FORMAT! - - to do: - - delete output file if quit before calling any writepng routines - - process backspace with -text option under DOS/Win? (currently get ^H) - - --------------------------------------------------------------------------- - - Changelog: - - 1.01: initial public release - - 1.02: modified to allow abbreviated options - - 1.03: removed extraneous character from usage screen; fixed bug in - command-line parsing - - 1.04: fixed DOS/OS2/Win32 detection, including partial Cygwin fix - (see http://home.att.net/~perlspinr/diffs/GregBook_cygwin.diff) - - 2.00: dual-licensed (added GNU GPL) - - [REPORTED BUG (win32 only): "contrib/gregbook/wpng.c - cmd line - dose not work! In order to do something useful I needed to redirect - both input and output, with cygwin and with bcc32 as well. Under - Linux, the same wpng appears to work fine. I don't know what is - the problem."] - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#define PROGNAME "wpng" -#define VERSION "2.00 of 2 June 2007" -#define APPNAME "Simple PGM/PPM/PAM to PNG Converter" - -#if defined(__MSDOS__) || defined(__OS2__) -# define DOS_OS2_W32 -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) -# ifndef __GNUC__ /* treat Win32 native ports of gcc as Unix environments */ -# define DOS_OS2_W32 -# endif -#endif - -#include -#include -#include -#include /* for jmpbuf declaration in writepng.h */ -#include - -#ifdef DOS_OS2_W32 -# include /* for isatty(), setmode() prototypes */ -# include /* O_BINARY for fdopen() without text translation */ -# ifdef __EMX__ -# ifndef getch -# define getch() _read_kbd(0, 1, 0) /* need getche() */ -# endif -# else /* !__EMX__ */ -# ifdef __GO32__ -# include -# define getch() getkey() /* GRR: need getche() */ -# else -# include /* for getche() console input */ -# endif -# endif /* ?__EMX__ */ -# define FGETS(buf,len,stream) dos_kbd_gets(buf,len) -#else -# include /* for isatty() prototype */ -# define FGETS fgets -#endif - -/* #define DEBUG : this enables the Trace() macros */ - -/* #define FORBID_LATIN1_CTRL : this requires the user to re-enter any - text that includes control characters discouraged by the PNG spec; text - that includes an escape character (27) must be re-entered regardless */ - -#include "writepng.h" /* typedefs, common macros, writepng prototypes */ - - - -/* local prototypes */ - -static int wpng_isvalid_latin1(uch *p, int len); -static void wpng_cleanup(void); - -#ifdef DOS_OS2_W32 - static char *dos_kbd_gets(char *buf, int len); -#endif - - - -static mainprog_info wpng_info; /* lone global */ - - - -int main(int argc, char **argv) -{ -#ifndef DOS_OS2_W32 - FILE *keybd; -#endif -#ifdef sgi - FILE *tmpfile; /* or we could just use keybd, since no overlap */ - char tmpline[80]; -#endif - char *inname = NULL, outname[256]; - char *p, pnmchar, pnmline[256]; - char *bgstr, *textbuf = NULL; - ulg rowbytes; - int rc, len = 0; - int error = 0; - int text = FALSE; - int maxval; - double LUT_exponent; /* just the lookup table */ - double CRT_exponent = 2.2; /* just the monitor */ - double default_display_exponent; /* whole display system */ - double default_gamma = 0.0; - - - wpng_info.infile = NULL; - wpng_info.outfile = NULL; - wpng_info.image_data = NULL; - wpng_info.row_pointers = NULL; - wpng_info.filter = FALSE; - wpng_info.interlaced = FALSE; - wpng_info.have_bg = FALSE; - wpng_info.have_time = FALSE; - wpng_info.have_text = 0; - wpng_info.gamma = 0.0; - - - /* First get the default value for our display-system exponent, i.e., - * the product of the CRT exponent and the exponent corresponding to - * the frame-buffer's lookup table (LUT), if any. If the PNM image - * looks correct on the user's display system, its file gamma is the - * inverse of this value. (Note that this is not an exhaustive list - * of LUT values--e.g., OpenStep has a lot of weird ones--but it should - * cover 99% of the current possibilities. This section must ensure - * that default_display_exponent is positive.) */ - -#if defined(NeXT) - /* third-party utilities can modify the default LUT exponent */ - LUT_exponent = 1.0 / 2.2; - /* - if (some_next_function_that_returns_gamma(&next_gamma)) - LUT_exponent = 1.0 / next_gamma; - */ -#elif defined(sgi) - LUT_exponent = 1.0 / 1.7; - /* there doesn't seem to be any documented function to - * get the "gamma" value, so we do it the hard way */ - tmpfile = fopen("/etc/config/system.glGammaVal", "r"); - if (tmpfile) { - double sgi_gamma; - - fgets(tmpline, 80, tmpfile); - fclose(tmpfile); - sgi_gamma = atof(tmpline); - if (sgi_gamma > 0.0) - LUT_exponent = 1.0 / sgi_gamma; - } -#elif defined(Macintosh) - LUT_exponent = 1.8 / 2.61; - /* - if (some_mac_function_that_returns_gamma(&mac_gamma)) - LUT_exponent = mac_gamma / 2.61; - */ -#else - LUT_exponent = 1.0; /* assume no LUT: most PCs */ -#endif - - /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ - default_display_exponent = LUT_exponent * CRT_exponent; - - - /* If the user has set the SCREEN_GAMMA environment variable as suggested - * (somewhat imprecisely) in the libpng documentation, use that; otherwise - * use the default value we just calculated. Either way, the user may - * override this via a command-line option. */ - - if ((p = getenv("SCREEN_GAMMA")) != NULL) { - double exponent = atof(p); - - if (exponent > 0.0) - default_gamma = 1.0 / exponent; - } - - if (default_gamma == 0.0) - default_gamma = 1.0 / default_display_exponent; - - - /* Now parse the command line for options and the PNM filename. */ - - while (*++argv && !error) { - if (!strncmp(*argv, "-i", 2)) { - wpng_info.interlaced = TRUE; - } else if (!strncmp(*argv, "-time", 3)) { - wpng_info.modtime = time(NULL); - wpng_info.have_time = TRUE; - } else if (!strncmp(*argv, "-text", 3)) { - text = TRUE; - } else if (!strncmp(*argv, "-gamma", 2)) { - if (!*++argv) - ++error; - else { - wpng_info.gamma = atof(*argv); - if (wpng_info.gamma <= 0.0) - ++error; - else if (wpng_info.gamma > 1.01) - fprintf(stderr, PROGNAME - " warning: file gammas are usually less than 1.0\n"); - } - } else if (!strncmp(*argv, "-bgcolor", 4)) { - if (!*++argv) - ++error; - else { - bgstr = *argv; - if (strlen(bgstr) != 7 || bgstr[0] != '#') - ++error; - else { - unsigned r, g, b; /* this way quiets compiler warnings */ - - sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); - wpng_info.bg_red = (uch)r; - wpng_info.bg_green = (uch)g; - wpng_info.bg_blue = (uch)b; - wpng_info.have_bg = TRUE; - } - } - } else { - if (**argv != '-') { - inname = *argv; - if (argv[1]) /* shouldn't be any more args after filename */ - ++error; - } else - ++error; /* not expecting any other options */ - } - } - - - /* open the input and output files, or register an error and abort */ - - if (!inname) { - if (isatty(0)) { - fprintf(stderr, PROGNAME - ": must give input filename or provide image data via stdin\n"); - ++error; - } else { -#ifdef DOS_OS2_W32 - /* some buggy C libraries require BOTH setmode() and fdopen(bin) */ - setmode(fileno(stdin), O_BINARY); - setmode(fileno(stdout), O_BINARY); -#endif - if ((wpng_info.infile = fdopen(fileno(stdin), "rb")) == NULL) { - fprintf(stderr, PROGNAME - ": unable to reopen stdin in binary mode\n"); - ++error; - } else - if ((wpng_info.outfile = fdopen(fileno(stdout), "wb")) == NULL) { - fprintf(stderr, PROGNAME - ": unable to reopen stdout in binary mode\n"); - fclose(wpng_info.infile); - ++error; - } else - wpng_info.filter = TRUE; - } - } else if ((len = strlen(inname)) > 250) { - fprintf(stderr, PROGNAME ": input filename is too long [%d chars]\n", - len); - ++error; - } else if (!(wpng_info.infile = fopen(inname, "rb"))) { - fprintf(stderr, PROGNAME ": can't open input file [%s]\n", inname); - ++error; - } - - if (!error) { - fgets(pnmline, 256, wpng_info.infile); - if (pnmline[0] != 'P' || ((pnmchar = pnmline[1]) != '5' && - pnmchar != '6' && pnmchar != '8')) - { - fprintf(stderr, PROGNAME - ": input file [%s] is not a binary PGM, PPM or PAM file\n", - inname); - ++error; - } else { - wpng_info.pnmtype = (int)(pnmchar - '0'); - if (wpng_info.pnmtype != 8) - wpng_info.have_bg = FALSE; /* no need for bg if opaque */ - do { - fgets(pnmline, 256, wpng_info.infile); /* lose any comments */ - } while (pnmline[0] == '#'); - sscanf(pnmline, "%ld %ld", &wpng_info.width, &wpng_info.height); - do { - fgets(pnmline, 256, wpng_info.infile); /* more comment lines */ - } while (pnmline[0] == '#'); - sscanf(pnmline, "%d", &maxval); - if (wpng_info.width <= 0L || wpng_info.height <= 0L || - maxval != 255) - { - fprintf(stderr, PROGNAME - ": only positive width/height, maxval == 255 allowed \n"); - ++error; - } - wpng_info.sample_depth = 8; /* <==> maxval 255 */ - - if (!wpng_info.filter) { - /* make outname from inname */ - if ((p = strrchr(inname, '.')) == NULL || - (p - inname) != (len - 4)) - { - strcpy(outname, inname); - strcpy(outname+len, ".png"); - } else { - len -= 4; - strncpy(outname, inname, len); - strcpy(outname+len, ".png"); - } - /* check if outname already exists; if not, open */ - if ((wpng_info.outfile = fopen(outname, "rb")) != NULL) { - fprintf(stderr, PROGNAME ": output file exists [%s]\n", - outname); - fclose(wpng_info.outfile); - ++error; - } else if (!(wpng_info.outfile = fopen(outname, "wb"))) { - fprintf(stderr, PROGNAME ": can't open output file [%s]\n", - outname); - ++error; - } - } - } - if (error) { - fclose(wpng_info.infile); - wpng_info.infile = NULL; - if (wpng_info.filter) { - fclose(wpng_info.outfile); - wpng_info.outfile = NULL; - } - } - } - - - /* if we had any errors, print usage and die horrible death...arrr! */ - - if (error) { - fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, APPNAME); - writepng_version_info(); - fprintf(stderr, "\n" -"Usage: %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] pnmfile\n" -"or: ... | %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] | ...\n" - " exp \ttransfer-function exponent (``gamma'') of the image in\n" - "\t\t floating-point format (e.g., ``%.5f''); if image looks\n" - "\t\t correct on given display system, image gamma is equal to\n" - "\t\t inverse of display-system exponent, i.e., 1 / (LUT * CRT)\n" - "\t\t (where LUT = lookup-table exponent and CRT = CRT exponent;\n" - "\t\t first varies, second is usually 2.2, all are positive)\n" - " bg \tdesired background color for alpha-channel images, in\n" - "\t\t 7-character hex RGB format (e.g., ``#ff7700'' for orange:\n" - "\t\t same as HTML colors)\n" - " -text\tprompt interactively for text info (tEXt chunks)\n" - " -time\tinclude a tIME chunk (last modification time)\n" - " -interlace\twrite interlaced PNG image\n" - "\n" -"pnmfile or stdin must be a binary PGM (`P5'), PPM (`P6') or (extremely\n" -"unofficial and unsupported!) PAM (`P8') file. Currently it is required\n" -"to have maxval == 255 (i.e., no scaling). If pnmfile is specified, it\n" -"is converted to the corresponding PNG file with the same base name but a\n" -"``.png'' extension; files read from stdin are converted and sent to stdout.\n" -"The conversion is progressive (low memory usage) unless interlacing is\n" -"requested; in that case the whole image will be buffered in memory and\n" -"written in one call.\n" - "\n", PROGNAME, PROGNAME, default_gamma); - exit(1); - } - - - /* prepare the text buffers for libpng's use; note that even though - * PNG's png_text struct includes a length field, we don't have to fill - * it out */ - - if (text && -#ifndef DOS_OS2_W32 - (keybd = fdopen(fileno(stderr), "r")) != NULL && -#endif - (textbuf = (char *)malloc((5 + 9)*75)) != NULL) - { - int i, valid, result; - - fprintf(stderr, - "Enter text info (no more than 72 characters per line);\n"); - fprintf(stderr, "to skip a field, hit the key.\n"); - /* note: just leaves len == 1 */ - - do { - valid = TRUE; - p = textbuf + TEXT_TITLE_OFFSET; - fprintf(stderr, " Title: "); - fflush(stderr); - if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { - if (p[len-1] == '\n') - p[--len] = '\0'; - wpng_info.title = p; - wpng_info.have_text |= TEXT_TITLE; - if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { - fprintf(stderr, " " PROGNAME " warning: character code" - " %u is %sdiscouraged by the PNG\n specification " - "[first occurrence was at character position #%d]\n", - (unsigned)p[result], (p[result] == 27)? "strongly " : "", - result+1); - fflush(stderr); -#ifdef FORBID_LATIN1_CTRL - wpng_info.have_text &= ~TEXT_TITLE; - valid = FALSE; -#else - if (p[result] == 27) { /* escape character */ - wpng_info.have_text &= ~TEXT_TITLE; - valid = FALSE; - } -#endif - } - } - } while (!valid); - - do { - valid = TRUE; - p = textbuf + TEXT_AUTHOR_OFFSET; - fprintf(stderr, " Author: "); - fflush(stderr); - if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { - if (p[len-1] == '\n') - p[--len] = '\0'; - wpng_info.author = p; - wpng_info.have_text |= TEXT_AUTHOR; - if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { - fprintf(stderr, " " PROGNAME " warning: character code" - " %u is %sdiscouraged by the PNG\n specification " - "[first occurrence was at character position #%d]\n", - (unsigned)p[result], (p[result] == 27)? "strongly " : "", - result+1); - fflush(stderr); -#ifdef FORBID_LATIN1_CTRL - wpng_info.have_text &= ~TEXT_AUTHOR; - valid = FALSE; -#else - if (p[result] == 27) { /* escape character */ - wpng_info.have_text &= ~TEXT_AUTHOR; - valid = FALSE; - } -#endif - } - } - } while (!valid); - - do { - valid = TRUE; - p = textbuf + TEXT_DESC_OFFSET; - fprintf(stderr, " Description (up to 9 lines):\n"); - for (i = 1; i < 10; ++i) { - fprintf(stderr, " [%d] ", i); - fflush(stderr); - if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) - p += len; /* now points at NULL; char before is newline */ - else - break; - } - if ((len = p - (textbuf + TEXT_DESC_OFFSET)) > 1) { - if (p[-1] == '\n') { - p[-1] = '\0'; - --len; - } - wpng_info.desc = textbuf + TEXT_DESC_OFFSET; - wpng_info.have_text |= TEXT_DESC; - p = textbuf + TEXT_DESC_OFFSET; - if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { - fprintf(stderr, " " PROGNAME " warning: character code" - " %u is %sdiscouraged by the PNG\n specification " - "[first occurrence was at character position #%d]\n", - (unsigned)p[result], (p[result] == 27)? "strongly " : "", - result+1); - fflush(stderr); -#ifdef FORBID_LATIN1_CTRL - wpng_info.have_text &= ~TEXT_DESC; - valid = FALSE; -#else - if (p[result] == 27) { /* escape character */ - wpng_info.have_text &= ~TEXT_DESC; - valid = FALSE; - } -#endif - } - } - } while (!valid); - - do { - valid = TRUE; - p = textbuf + TEXT_COPY_OFFSET; - fprintf(stderr, " Copyright: "); - fflush(stderr); - if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { - if (p[len-1] == '\n') - p[--len] = '\0'; - wpng_info.copyright = p; - wpng_info.have_text |= TEXT_COPY; - if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { - fprintf(stderr, " " PROGNAME " warning: character code" - " %u is %sdiscouraged by the PNG\n specification " - "[first occurrence was at character position #%d]\n", - (unsigned)p[result], (p[result] == 27)? "strongly " : "", - result+1); - fflush(stderr); -#ifdef FORBID_LATIN1_CTRL - wpng_info.have_text &= ~TEXT_COPY; - valid = FALSE; -#else - if (p[result] == 27) { /* escape character */ - wpng_info.have_text &= ~TEXT_COPY; - valid = FALSE; - } -#endif - } - } - } while (!valid); - - do { - valid = TRUE; - p = textbuf + TEXT_EMAIL_OFFSET; - fprintf(stderr, " E-mail: "); - fflush(stderr); - if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { - if (p[len-1] == '\n') - p[--len] = '\0'; - wpng_info.email = p; - wpng_info.have_text |= TEXT_EMAIL; - if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { - fprintf(stderr, " " PROGNAME " warning: character code" - " %u is %sdiscouraged by the PNG\n specification " - "[first occurrence was at character position #%d]\n", - (unsigned)p[result], (p[result] == 27)? "strongly " : "", - result+1); - fflush(stderr); -#ifdef FORBID_LATIN1_CTRL - wpng_info.have_text &= ~TEXT_EMAIL; - valid = FALSE; -#else - if (p[result] == 27) { /* escape character */ - wpng_info.have_text &= ~TEXT_EMAIL; - valid = FALSE; - } -#endif - } - } - } while (!valid); - - do { - valid = TRUE; - p = textbuf + TEXT_URL_OFFSET; - fprintf(stderr, " URL: "); - fflush(stderr); - if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { - if (p[len-1] == '\n') - p[--len] = '\0'; - wpng_info.url = p; - wpng_info.have_text |= TEXT_URL; - if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { - fprintf(stderr, " " PROGNAME " warning: character code" - " %u is %sdiscouraged by the PNG\n specification " - "[first occurrence was at character position #%d]\n", - (unsigned)p[result], (p[result] == 27)? "strongly " : "", - result+1); - fflush(stderr); -#ifdef FORBID_LATIN1_CTRL - wpng_info.have_text &= ~TEXT_URL; - valid = FALSE; -#else - if (p[result] == 27) { /* escape character */ - wpng_info.have_text &= ~TEXT_URL; - valid = FALSE; - } -#endif - } - } - } while (!valid); - -#ifndef DOS_OS2_W32 - fclose(keybd); -#endif - - } else if (text) { - fprintf(stderr, PROGNAME ": unable to allocate memory for text\n"); - text = FALSE; - wpng_info.have_text = 0; - } - - - /* allocate libpng stuff, initialize transformations, write pre-IDAT data */ - - if ((rc = writepng_init(&wpng_info)) != 0) { - switch (rc) { - case 2: - fprintf(stderr, PROGNAME - ": libpng initialization problem (longjmp)\n"); - break; - case 4: - fprintf(stderr, PROGNAME ": insufficient memory\n"); - break; - case 11: - fprintf(stderr, PROGNAME - ": internal logic error (unexpected PNM type)\n"); - break; - default: - fprintf(stderr, PROGNAME - ": unknown writepng_init() error\n"); - break; - } - exit(rc); - } - - - /* free textbuf, since it's a completely local variable and all text info - * has just been written to the PNG file */ - - if (text && textbuf) { - free(textbuf); - textbuf = NULL; - } - - - /* calculate rowbytes on basis of image type; note that this becomes much - * more complicated if we choose to support PBM type, ASCII PNM types, or - * 16-bit-per-sample binary data [currently not an official NetPBM type] */ - - if (wpng_info.pnmtype == 5) - rowbytes = wpng_info.width; - else if (wpng_info.pnmtype == 6) - rowbytes = wpng_info.width * 3; - else /* if (wpng_info.pnmtype == 8) */ - rowbytes = wpng_info.width * 4; - - - /* read and write the image, either in its entirety (if writing interlaced - * PNG) or row by row (if non-interlaced) */ - - fprintf(stderr, "Encoding image data...\n"); - fflush(stderr); - - if (wpng_info.interlaced) { - long i; - ulg bytes; - ulg image_bytes = rowbytes * wpng_info.height; /* overflow? */ - - wpng_info.image_data = (uch *)malloc(image_bytes); - wpng_info.row_pointers = (uch **)malloc(wpng_info.height*sizeof(uch *)); - if (wpng_info.image_data == NULL || wpng_info.row_pointers == NULL) { - fprintf(stderr, PROGNAME ": insufficient memory for image data\n"); - writepng_cleanup(&wpng_info); - wpng_cleanup(); - exit(5); - } - for (i = 0; i < wpng_info.height; ++i) - wpng_info.row_pointers[i] = wpng_info.image_data + i*rowbytes; - bytes = fread(wpng_info.image_data, 1, image_bytes, wpng_info.infile); - if (bytes != image_bytes) { - fprintf(stderr, PROGNAME ": expected %lu bytes, got %lu bytes\n", - image_bytes, bytes); - fprintf(stderr, " (continuing anyway)\n"); - } - if (writepng_encode_image(&wpng_info) != 0) { - fprintf(stderr, PROGNAME - ": libpng problem (longjmp) while writing image data\n"); - writepng_cleanup(&wpng_info); - wpng_cleanup(); - exit(2); - } - - } else /* not interlaced: write progressively (row by row) */ { - long j; - ulg bytes; - - wpng_info.image_data = (uch *)malloc(rowbytes); - if (wpng_info.image_data == NULL) { - fprintf(stderr, PROGNAME ": insufficient memory for row data\n"); - writepng_cleanup(&wpng_info); - wpng_cleanup(); - exit(5); - } - error = 0; - for (j = wpng_info.height; j > 0L; --j) { - bytes = fread(wpng_info.image_data, 1, rowbytes, wpng_info.infile); - if (bytes != rowbytes) { - fprintf(stderr, PROGNAME - ": expected %lu bytes, got %lu bytes (row %ld)\n", rowbytes, - bytes, wpng_info.height-j); - ++error; - break; - } - if (writepng_encode_row(&wpng_info) != 0) { - fprintf(stderr, PROGNAME - ": libpng problem (longjmp) while writing row %ld\n", - wpng_info.height-j); - ++error; - break; - } - } - if (error) { - writepng_cleanup(&wpng_info); - wpng_cleanup(); - exit(2); - } - if (writepng_encode_finish(&wpng_info) != 0) { - fprintf(stderr, PROGNAME ": error on final libpng call\n"); - writepng_cleanup(&wpng_info); - wpng_cleanup(); - exit(2); - } - } - - - /* OK, we're done (successfully): clean up all resources and quit */ - - fprintf(stderr, "Done.\n"); - fflush(stderr); - - writepng_cleanup(&wpng_info); - wpng_cleanup(); - - return 0; -} - - - - - -static int wpng_isvalid_latin1(uch *p, int len) -{ - int i, result = -1; - - for (i = 0; i < len; ++i) { - if (p[i] == 10 || (p[i] > 31 && p[i] < 127) || p[i] > 160) - continue; /* character is completely OK */ - if (result < 0 || (p[result] != 27 && p[i] == 27)) - result = i; /* mark location of first questionable one */ - } /* or of first escape character (bad) */ - - return result; -} - - - - - -static void wpng_cleanup(void) -{ - if (wpng_info.outfile) { - fclose(wpng_info.outfile); - wpng_info.outfile = NULL; - } - - if (wpng_info.infile) { - fclose(wpng_info.infile); - wpng_info.infile = NULL; - } - - if (wpng_info.image_data) { - free(wpng_info.image_data); - wpng_info.image_data = NULL; - } - - if (wpng_info.row_pointers) { - free(wpng_info.row_pointers); - wpng_info.row_pointers = NULL; - } -} - - - - -#ifdef DOS_OS2_W32 - -static char *dos_kbd_gets(char *buf, int len) -{ - int ch, count=0; - - do { - buf[count++] = ch = getche(); - } while (ch != '\r' && count < len-1); - - buf[count--] = '\0'; /* terminate string */ - if (buf[count] == '\r') /* Enter key makes CR, so change to newline */ - buf[count] = '\n'; - - fprintf(stderr, "\n"); /* Enter key does *not* cause a newline */ - fflush(stderr); - - return buf; -} - -#endif /* DOS_OS2_W32 */ +/*--------------------------------------------------------------------------- + + wpng - simple PNG-writing program wpng.c + + This program converts certain NetPBM binary files (grayscale and RGB, + maxval = 255) to PNG. Non-interlaced PNGs are written progressively; + interlaced PNGs are read and written in one memory-intensive blast. + + Thanks to Jean-loup Gailly for providing the necessary trick to read + interactive text from the keyboard while stdin is redirected. Thanks + to Cosmin Truta for Cygwin fixes. + + NOTE: includes provisional support for PNM type "8" (portable alphamap) + images, presumed to be a 32-bit interleaved RGBA format; no pro- + vision for possible interleaved grayscale+alpha (16-bit) format. + THIS IS UNLIKELY TO BECOME AN OFFICIAL NETPBM ALPHA FORMAT! + + to do: + - delete output file if quit before calling any writepng routines + - process backspace with -text option under DOS/Win? (currently get ^H) + + --------------------------------------------------------------------------- + + Changelog: + - 1.01: initial public release + - 1.02: modified to allow abbreviated options + - 1.03: removed extraneous character from usage screen; fixed bug in + command-line parsing + - 1.04: fixed DOS/OS2/Win32 detection, including partial Cygwin fix + (see http://home.att.net/~perlspinr/diffs/GregBook_cygwin.diff) + - 2.00: dual-licensed (added GNU GPL) + + [REPORTED BUG (win32 only): "contrib/gregbook/wpng.c - cmd line + dose not work! In order to do something useful I needed to redirect + both input and output, with cygwin and with bcc32 as well. Under + Linux, the same wpng appears to work fine. I don't know what is + the problem."] + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#define PROGNAME "wpng" +#define VERSION "2.00 of 2 June 2007" +#define APPNAME "Simple PGM/PPM/PAM to PNG Converter" + +#if defined(__MSDOS__) || defined(__OS2__) +# define DOS_OS2_W32 +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# ifndef __GNUC__ /* treat Win32 native ports of gcc as Unix environments */ +# define DOS_OS2_W32 +# endif +#endif + +#include +#include +#include +#include /* for jmpbuf declaration in writepng.h */ +#include + +#ifdef DOS_OS2_W32 +# include /* for isatty(), setmode() prototypes */ +# include /* O_BINARY for fdopen() without text translation */ +# ifdef __EMX__ +# ifndef getch +# define getch() _read_kbd(0, 1, 0) /* need getche() */ +# endif +# else /* !__EMX__ */ +# ifdef __GO32__ +# include +# define getch() getkey() /* GRR: need getche() */ +# else +# include /* for getche() console input */ +# endif +# endif /* ?__EMX__ */ +# define FGETS(buf,len,stream) dos_kbd_gets(buf,len) +#else +# include /* for isatty() prototype */ +# define FGETS fgets +#endif + +/* #define DEBUG : this enables the Trace() macros */ + +/* #define FORBID_LATIN1_CTRL : this requires the user to re-enter any + text that includes control characters discouraged by the PNG spec; text + that includes an escape character (27) must be re-entered regardless */ + +#include "writepng.h" /* typedefs, common macros, writepng prototypes */ + + + +/* local prototypes */ + +static int wpng_isvalid_latin1(uch *p, int len); +static void wpng_cleanup(void); + +#ifdef DOS_OS2_W32 + static char *dos_kbd_gets(char *buf, int len); +#endif + + + +static mainprog_info wpng_info; /* lone global */ + + + +int main(int argc, char **argv) +{ +#ifndef DOS_OS2_W32 + FILE *keybd; +#endif +#ifdef sgi + FILE *tmpfile; /* or we could just use keybd, since no overlap */ + char tmpline[80]; +#endif + char *inname = NULL, outname[256]; + char *p, pnmchar, pnmline[256]; + char *bgstr, *textbuf = NULL; + ulg rowbytes; + int rc, len = 0; + int error = 0; + int text = FALSE; + int maxval; + double LUT_exponent; /* just the lookup table */ + double CRT_exponent = 2.2; /* just the monitor */ + double default_display_exponent; /* whole display system */ + double default_gamma = 0.0; + + + wpng_info.infile = NULL; + wpng_info.outfile = NULL; + wpng_info.image_data = NULL; + wpng_info.row_pointers = NULL; + wpng_info.filter = FALSE; + wpng_info.interlaced = FALSE; + wpng_info.have_bg = FALSE; + wpng_info.have_time = FALSE; + wpng_info.have_text = 0; + wpng_info.gamma = 0.0; + + + /* First get the default value for our display-system exponent, i.e., + * the product of the CRT exponent and the exponent corresponding to + * the frame-buffer's lookup table (LUT), if any. If the PNM image + * looks correct on the user's display system, its file gamma is the + * inverse of this value. (Note that this is not an exhaustive list + * of LUT values--e.g., OpenStep has a lot of weird ones--but it should + * cover 99% of the current possibilities. This section must ensure + * that default_display_exponent is positive.) */ + +#if defined(NeXT) + /* third-party utilities can modify the default LUT exponent */ + LUT_exponent = 1.0 / 2.2; + /* + if (some_next_function_that_returns_gamma(&next_gamma)) + LUT_exponent = 1.0 / next_gamma; + */ +#elif defined(sgi) + LUT_exponent = 1.0 / 1.7; + /* there doesn't seem to be any documented function to + * get the "gamma" value, so we do it the hard way */ + tmpfile = fopen("/etc/config/system.glGammaVal", "r"); + if (tmpfile) { + double sgi_gamma; + + fgets(tmpline, 80, tmpfile); + fclose(tmpfile); + sgi_gamma = atof(tmpline); + if (sgi_gamma > 0.0) + LUT_exponent = 1.0 / sgi_gamma; + } +#elif defined(Macintosh) + LUT_exponent = 1.8 / 2.61; + /* + if (some_mac_function_that_returns_gamma(&mac_gamma)) + LUT_exponent = mac_gamma / 2.61; + */ +#else + LUT_exponent = 1.0; /* assume no LUT: most PCs */ +#endif + + /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */ + default_display_exponent = LUT_exponent * CRT_exponent; + + + /* If the user has set the SCREEN_GAMMA environment variable as suggested + * (somewhat imprecisely) in the libpng documentation, use that; otherwise + * use the default value we just calculated. Either way, the user may + * override this via a command-line option. */ + + if ((p = getenv("SCREEN_GAMMA")) != NULL) { + double exponent = atof(p); + + if (exponent > 0.0) + default_gamma = 1.0 / exponent; + } + + if (default_gamma == 0.0) + default_gamma = 1.0 / default_display_exponent; + + + /* Now parse the command line for options and the PNM filename. */ + + while (*++argv && !error) { + if (!strncmp(*argv, "-i", 2)) { + wpng_info.interlaced = TRUE; + } else if (!strncmp(*argv, "-time", 3)) { + wpng_info.modtime = time(NULL); + wpng_info.have_time = TRUE; + } else if (!strncmp(*argv, "-text", 3)) { + text = TRUE; + } else if (!strncmp(*argv, "-gamma", 2)) { + if (!*++argv) + ++error; + else { + wpng_info.gamma = atof(*argv); + if (wpng_info.gamma <= 0.0) + ++error; + else if (wpng_info.gamma > 1.01) + fprintf(stderr, PROGNAME + " warning: file gammas are usually less than 1.0\n"); + } + } else if (!strncmp(*argv, "-bgcolor", 4)) { + if (!*++argv) + ++error; + else { + bgstr = *argv; + if (strlen(bgstr) != 7 || bgstr[0] != '#') + ++error; + else { + unsigned r, g, b; /* this way quiets compiler warnings */ + + sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b); + wpng_info.bg_red = (uch)r; + wpng_info.bg_green = (uch)g; + wpng_info.bg_blue = (uch)b; + wpng_info.have_bg = TRUE; + } + } + } else { + if (**argv != '-') { + inname = *argv; + if (argv[1]) /* shouldn't be any more args after filename */ + ++error; + } else + ++error; /* not expecting any other options */ + } + } + + + /* open the input and output files, or register an error and abort */ + + if (!inname) { + if (isatty(0)) { + fprintf(stderr, PROGNAME + ": must give input filename or provide image data via stdin\n"); + ++error; + } else { +#ifdef DOS_OS2_W32 + /* some buggy C libraries require BOTH setmode() and fdopen(bin) */ + setmode(fileno(stdin), O_BINARY); + setmode(fileno(stdout), O_BINARY); +#endif + if ((wpng_info.infile = fdopen(fileno(stdin), "rb")) == NULL) { + fprintf(stderr, PROGNAME + ": unable to reopen stdin in binary mode\n"); + ++error; + } else + if ((wpng_info.outfile = fdopen(fileno(stdout), "wb")) == NULL) { + fprintf(stderr, PROGNAME + ": unable to reopen stdout in binary mode\n"); + fclose(wpng_info.infile); + ++error; + } else + wpng_info.filter = TRUE; + } + } else if ((len = strlen(inname)) > 250) { + fprintf(stderr, PROGNAME ": input filename is too long [%d chars]\n", + len); + ++error; + } else if (!(wpng_info.infile = fopen(inname, "rb"))) { + fprintf(stderr, PROGNAME ": can't open input file [%s]\n", inname); + ++error; + } + + if (!error) { + fgets(pnmline, 256, wpng_info.infile); + if (pnmline[0] != 'P' || ((pnmchar = pnmline[1]) != '5' && + pnmchar != '6' && pnmchar != '8')) + { + fprintf(stderr, PROGNAME + ": input file [%s] is not a binary PGM, PPM or PAM file\n", + inname); + ++error; + } else { + wpng_info.pnmtype = (int)(pnmchar - '0'); + if (wpng_info.pnmtype != 8) + wpng_info.have_bg = FALSE; /* no need for bg if opaque */ + do { + fgets(pnmline, 256, wpng_info.infile); /* lose any comments */ + } while (pnmline[0] == '#'); + sscanf(pnmline, "%ld %ld", &wpng_info.width, &wpng_info.height); + do { + fgets(pnmline, 256, wpng_info.infile); /* more comment lines */ + } while (pnmline[0] == '#'); + sscanf(pnmline, "%d", &maxval); + if (wpng_info.width <= 0L || wpng_info.height <= 0L || + maxval != 255) + { + fprintf(stderr, PROGNAME + ": only positive width/height, maxval == 255 allowed \n"); + ++error; + } + wpng_info.sample_depth = 8; /* <==> maxval 255 */ + + if (!wpng_info.filter) { + /* make outname from inname */ + if ((p = strrchr(inname, '.')) == NULL || + (p - inname) != (len - 4)) + { + strcpy(outname, inname); + strcpy(outname+len, ".png"); + } else { + len -= 4; + strncpy(outname, inname, len); + strcpy(outname+len, ".png"); + } + /* check if outname already exists; if not, open */ + if ((wpng_info.outfile = fopen(outname, "rb")) != NULL) { + fprintf(stderr, PROGNAME ": output file exists [%s]\n", + outname); + fclose(wpng_info.outfile); + ++error; + } else if (!(wpng_info.outfile = fopen(outname, "wb"))) { + fprintf(stderr, PROGNAME ": can't open output file [%s]\n", + outname); + ++error; + } + } + } + if (error) { + fclose(wpng_info.infile); + wpng_info.infile = NULL; + if (wpng_info.filter) { + fclose(wpng_info.outfile); + wpng_info.outfile = NULL; + } + } + } + + + /* if we had any errors, print usage and die horrible death...arrr! */ + + if (error) { + fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, APPNAME); + writepng_version_info(); + fprintf(stderr, "\n" +"Usage: %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] pnmfile\n" +"or: ... | %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] | ...\n" + " exp \ttransfer-function exponent (``gamma'') of the image in\n" + "\t\t floating-point format (e.g., ``%.5f''); if image looks\n" + "\t\t correct on given display system, image gamma is equal to\n" + "\t\t inverse of display-system exponent, i.e., 1 / (LUT * CRT)\n" + "\t\t (where LUT = lookup-table exponent and CRT = CRT exponent;\n" + "\t\t first varies, second is usually 2.2, all are positive)\n" + " bg \tdesired background color for alpha-channel images, in\n" + "\t\t 7-character hex RGB format (e.g., ``#ff7700'' for orange:\n" + "\t\t same as HTML colors)\n" + " -text\tprompt interactively for text info (tEXt chunks)\n" + " -time\tinclude a tIME chunk (last modification time)\n" + " -interlace\twrite interlaced PNG image\n" + "\n" +"pnmfile or stdin must be a binary PGM (`P5'), PPM (`P6') or (extremely\n" +"unofficial and unsupported!) PAM (`P8') file. Currently it is required\n" +"to have maxval == 255 (i.e., no scaling). If pnmfile is specified, it\n" +"is converted to the corresponding PNG file with the same base name but a\n" +"``.png'' extension; files read from stdin are converted and sent to stdout.\n" +"The conversion is progressive (low memory usage) unless interlacing is\n" +"requested; in that case the whole image will be buffered in memory and\n" +"written in one call.\n" + "\n", PROGNAME, PROGNAME, default_gamma); + exit(1); + } + + + /* prepare the text buffers for libpng's use; note that even though + * PNG's png_text struct includes a length field, we don't have to fill + * it out */ + + if (text && +#ifndef DOS_OS2_W32 + (keybd = fdopen(fileno(stderr), "r")) != NULL && +#endif + (textbuf = (char *)malloc((5 + 9)*75)) != NULL) + { + int i, valid, result; + + fprintf(stderr, + "Enter text info (no more than 72 characters per line);\n"); + fprintf(stderr, "to skip a field, hit the key.\n"); + /* note: just leaves len == 1 */ + + do { + valid = TRUE; + p = textbuf + TEXT_TITLE_OFFSET; + fprintf(stderr, " Title: "); + fflush(stderr); + if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { + if (p[len-1] == '\n') + p[--len] = '\0'; + wpng_info.title = p; + wpng_info.have_text |= TEXT_TITLE; + if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { + fprintf(stderr, " " PROGNAME " warning: character code" + " %u is %sdiscouraged by the PNG\n specification " + "[first occurrence was at character position #%d]\n", + (unsigned)p[result], (p[result] == 27)? "strongly " : "", + result+1); + fflush(stderr); +#ifdef FORBID_LATIN1_CTRL + wpng_info.have_text &= ~TEXT_TITLE; + valid = FALSE; +#else + if (p[result] == 27) { /* escape character */ + wpng_info.have_text &= ~TEXT_TITLE; + valid = FALSE; + } +#endif + } + } + } while (!valid); + + do { + valid = TRUE; + p = textbuf + TEXT_AUTHOR_OFFSET; + fprintf(stderr, " Author: "); + fflush(stderr); + if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { + if (p[len-1] == '\n') + p[--len] = '\0'; + wpng_info.author = p; + wpng_info.have_text |= TEXT_AUTHOR; + if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { + fprintf(stderr, " " PROGNAME " warning: character code" + " %u is %sdiscouraged by the PNG\n specification " + "[first occurrence was at character position #%d]\n", + (unsigned)p[result], (p[result] == 27)? "strongly " : "", + result+1); + fflush(stderr); +#ifdef FORBID_LATIN1_CTRL + wpng_info.have_text &= ~TEXT_AUTHOR; + valid = FALSE; +#else + if (p[result] == 27) { /* escape character */ + wpng_info.have_text &= ~TEXT_AUTHOR; + valid = FALSE; + } +#endif + } + } + } while (!valid); + + do { + valid = TRUE; + p = textbuf + TEXT_DESC_OFFSET; + fprintf(stderr, " Description (up to 9 lines):\n"); + for (i = 1; i < 10; ++i) { + fprintf(stderr, " [%d] ", i); + fflush(stderr); + if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) + p += len; /* now points at NULL; char before is newline */ + else + break; + } + if ((len = p - (textbuf + TEXT_DESC_OFFSET)) > 1) { + if (p[-1] == '\n') { + p[-1] = '\0'; + --len; + } + wpng_info.desc = textbuf + TEXT_DESC_OFFSET; + wpng_info.have_text |= TEXT_DESC; + p = textbuf + TEXT_DESC_OFFSET; + if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { + fprintf(stderr, " " PROGNAME " warning: character code" + " %u is %sdiscouraged by the PNG\n specification " + "[first occurrence was at character position #%d]\n", + (unsigned)p[result], (p[result] == 27)? "strongly " : "", + result+1); + fflush(stderr); +#ifdef FORBID_LATIN1_CTRL + wpng_info.have_text &= ~TEXT_DESC; + valid = FALSE; +#else + if (p[result] == 27) { /* escape character */ + wpng_info.have_text &= ~TEXT_DESC; + valid = FALSE; + } +#endif + } + } + } while (!valid); + + do { + valid = TRUE; + p = textbuf + TEXT_COPY_OFFSET; + fprintf(stderr, " Copyright: "); + fflush(stderr); + if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { + if (p[len-1] == '\n') + p[--len] = '\0'; + wpng_info.copyright = p; + wpng_info.have_text |= TEXT_COPY; + if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { + fprintf(stderr, " " PROGNAME " warning: character code" + " %u is %sdiscouraged by the PNG\n specification " + "[first occurrence was at character position #%d]\n", + (unsigned)p[result], (p[result] == 27)? "strongly " : "", + result+1); + fflush(stderr); +#ifdef FORBID_LATIN1_CTRL + wpng_info.have_text &= ~TEXT_COPY; + valid = FALSE; +#else + if (p[result] == 27) { /* escape character */ + wpng_info.have_text &= ~TEXT_COPY; + valid = FALSE; + } +#endif + } + } + } while (!valid); + + do { + valid = TRUE; + p = textbuf + TEXT_EMAIL_OFFSET; + fprintf(stderr, " E-mail: "); + fflush(stderr); + if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { + if (p[len-1] == '\n') + p[--len] = '\0'; + wpng_info.email = p; + wpng_info.have_text |= TEXT_EMAIL; + if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { + fprintf(stderr, " " PROGNAME " warning: character code" + " %u is %sdiscouraged by the PNG\n specification " + "[first occurrence was at character position #%d]\n", + (unsigned)p[result], (p[result] == 27)? "strongly " : "", + result+1); + fflush(stderr); +#ifdef FORBID_LATIN1_CTRL + wpng_info.have_text &= ~TEXT_EMAIL; + valid = FALSE; +#else + if (p[result] == 27) { /* escape character */ + wpng_info.have_text &= ~TEXT_EMAIL; + valid = FALSE; + } +#endif + } + } + } while (!valid); + + do { + valid = TRUE; + p = textbuf + TEXT_URL_OFFSET; + fprintf(stderr, " URL: "); + fflush(stderr); + if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) { + if (p[len-1] == '\n') + p[--len] = '\0'; + wpng_info.url = p; + wpng_info.have_text |= TEXT_URL; + if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) { + fprintf(stderr, " " PROGNAME " warning: character code" + " %u is %sdiscouraged by the PNG\n specification " + "[first occurrence was at character position #%d]\n", + (unsigned)p[result], (p[result] == 27)? "strongly " : "", + result+1); + fflush(stderr); +#ifdef FORBID_LATIN1_CTRL + wpng_info.have_text &= ~TEXT_URL; + valid = FALSE; +#else + if (p[result] == 27) { /* escape character */ + wpng_info.have_text &= ~TEXT_URL; + valid = FALSE; + } +#endif + } + } + } while (!valid); + +#ifndef DOS_OS2_W32 + fclose(keybd); +#endif + + } else if (text) { + fprintf(stderr, PROGNAME ": unable to allocate memory for text\n"); + text = FALSE; + wpng_info.have_text = 0; + } + + + /* allocate libpng stuff, initialize transformations, write pre-IDAT data */ + + if ((rc = writepng_init(&wpng_info)) != 0) { + switch (rc) { + case 2: + fprintf(stderr, PROGNAME + ": libpng initialization problem (longjmp)\n"); + break; + case 4: + fprintf(stderr, PROGNAME ": insufficient memory\n"); + break; + case 11: + fprintf(stderr, PROGNAME + ": internal logic error (unexpected PNM type)\n"); + break; + default: + fprintf(stderr, PROGNAME + ": unknown writepng_init() error\n"); + break; + } + exit(rc); + } + + + /* free textbuf, since it's a completely local variable and all text info + * has just been written to the PNG file */ + + if (text && textbuf) { + free(textbuf); + textbuf = NULL; + } + + + /* calculate rowbytes on basis of image type; note that this becomes much + * more complicated if we choose to support PBM type, ASCII PNM types, or + * 16-bit-per-sample binary data [currently not an official NetPBM type] */ + + if (wpng_info.pnmtype == 5) + rowbytes = wpng_info.width; + else if (wpng_info.pnmtype == 6) + rowbytes = wpng_info.width * 3; + else /* if (wpng_info.pnmtype == 8) */ + rowbytes = wpng_info.width * 4; + + + /* read and write the image, either in its entirety (if writing interlaced + * PNG) or row by row (if non-interlaced) */ + + fprintf(stderr, "Encoding image data...\n"); + fflush(stderr); + + if (wpng_info.interlaced) { + long i; + ulg bytes; + ulg image_bytes = rowbytes * wpng_info.height; /* overflow? */ + + wpng_info.image_data = (uch *)malloc(image_bytes); + wpng_info.row_pointers = (uch **)malloc(wpng_info.height*sizeof(uch *)); + if (wpng_info.image_data == NULL || wpng_info.row_pointers == NULL) { + fprintf(stderr, PROGNAME ": insufficient memory for image data\n"); + writepng_cleanup(&wpng_info); + wpng_cleanup(); + exit(5); + } + for (i = 0; i < wpng_info.height; ++i) + wpng_info.row_pointers[i] = wpng_info.image_data + i*rowbytes; + bytes = fread(wpng_info.image_data, 1, image_bytes, wpng_info.infile); + if (bytes != image_bytes) { + fprintf(stderr, PROGNAME ": expected %lu bytes, got %lu bytes\n", + image_bytes, bytes); + fprintf(stderr, " (continuing anyway)\n"); + } + if (writepng_encode_image(&wpng_info) != 0) { + fprintf(stderr, PROGNAME + ": libpng problem (longjmp) while writing image data\n"); + writepng_cleanup(&wpng_info); + wpng_cleanup(); + exit(2); + } + + } else /* not interlaced: write progressively (row by row) */ { + long j; + ulg bytes; + + wpng_info.image_data = (uch *)malloc(rowbytes); + if (wpng_info.image_data == NULL) { + fprintf(stderr, PROGNAME ": insufficient memory for row data\n"); + writepng_cleanup(&wpng_info); + wpng_cleanup(); + exit(5); + } + error = 0; + for (j = wpng_info.height; j > 0L; --j) { + bytes = fread(wpng_info.image_data, 1, rowbytes, wpng_info.infile); + if (bytes != rowbytes) { + fprintf(stderr, PROGNAME + ": expected %lu bytes, got %lu bytes (row %ld)\n", rowbytes, + bytes, wpng_info.height-j); + ++error; + break; + } + if (writepng_encode_row(&wpng_info) != 0) { + fprintf(stderr, PROGNAME + ": libpng problem (longjmp) while writing row %ld\n", + wpng_info.height-j); + ++error; + break; + } + } + if (error) { + writepng_cleanup(&wpng_info); + wpng_cleanup(); + exit(2); + } + if (writepng_encode_finish(&wpng_info) != 0) { + fprintf(stderr, PROGNAME ": error on final libpng call\n"); + writepng_cleanup(&wpng_info); + wpng_cleanup(); + exit(2); + } + } + + + /* OK, we're done (successfully): clean up all resources and quit */ + + fprintf(stderr, "Done.\n"); + fflush(stderr); + + writepng_cleanup(&wpng_info); + wpng_cleanup(); + + return 0; +} + + + + + +static int wpng_isvalid_latin1(uch *p, int len) +{ + int i, result = -1; + + for (i = 0; i < len; ++i) { + if (p[i] == 10 || (p[i] > 31 && p[i] < 127) || p[i] > 160) + continue; /* character is completely OK */ + if (result < 0 || (p[result] != 27 && p[i] == 27)) + result = i; /* mark location of first questionable one */ + } /* or of first escape character (bad) */ + + return result; +} + + + + + +static void wpng_cleanup(void) +{ + if (wpng_info.outfile) { + fclose(wpng_info.outfile); + wpng_info.outfile = NULL; + } + + if (wpng_info.infile) { + fclose(wpng_info.infile); + wpng_info.infile = NULL; + } + + if (wpng_info.image_data) { + free(wpng_info.image_data); + wpng_info.image_data = NULL; + } + + if (wpng_info.row_pointers) { + free(wpng_info.row_pointers); + wpng_info.row_pointers = NULL; + } +} + + + + +#ifdef DOS_OS2_W32 + +static char *dos_kbd_gets(char *buf, int len) +{ + int ch, count=0; + + do { + buf[count++] = ch = getche(); + } while (ch != '\r' && count < len-1); + + buf[count--] = '\0'; /* terminate string */ + if (buf[count] == '\r') /* Enter key makes CR, so change to newline */ + buf[count] = '\n'; + + fprintf(stderr, "\n"); /* Enter key does *not* cause a newline */ + fflush(stderr); + + return buf; +} + +#endif /* DOS_OS2_W32 */ diff --git a/main/source/includes/lpng1610/contrib/gregbook/writepng.c b/main/source/includes/lpng1610/contrib/gregbook/writepng.c index ac2edae1..0dda62ea 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/writepng.c +++ b/main/source/includes/lpng1610/contrib/gregbook/writepng.c @@ -1,401 +1,401 @@ -/*--------------------------------------------------------------------------- - - wpng - simple PNG-writing program writepng.c - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - - -#include /* for exit() prototype */ -#include - -#include "png.h" /* libpng header, includes setjmp.h */ -#include "writepng.h" /* typedefs, common macros, public prototypes */ - - -/* local prototype */ - -static void writepng_error_handler(png_structp png_ptr, png_const_charp msg); - - - -void writepng_version_info(void) -{ - fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", - PNG_LIBPNG_VER_STRING, png_libpng_ver); - fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", - ZLIB_VERSION, zlib_version); -} - - - - -/* returns 0 for success, 2 for libpng problem, 4 for out of memory, 11 for - * unexpected pnmtype; note that outfile might be stdout */ - -int writepng_init(mainprog_info *mainprog_ptr) -{ - png_structp png_ptr; /* note: temporary variables! */ - png_infop info_ptr; - int color_type, interlace_type; - - - /* could also replace libpng warning-handler (final NULL), but no need: */ - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, - writepng_error_handler, NULL); - if (!png_ptr) - return 4; /* out of memory */ - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, NULL); - return 4; /* out of memory */ - } - - - /* setjmp() must be called in every function that calls a PNG-writing - * libpng function, unless an alternate error handler was installed-- - * but compatible error handlers must either use longjmp() themselves - * (as in this program) or some other method to return control to - * application code, so here we go: */ - - if (setjmp(mainprog_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - return 2; - } - - - /* make sure outfile is (re)opened in BINARY mode */ - - png_init_io(png_ptr, mainprog_ptr->outfile); - - - /* set the compression levels--in general, always want to leave filtering - * turned on (except for palette images) and allow all of the filters, - * which is the default; want 32K zlib window, unless entire image buffer - * is 16K or smaller (unknown here)--also the default; usually want max - * compression (NOT the default); and remaining compression flags should - * be left alone */ - - png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); -/* - >> this is default for no filtering; Z_FILTERED is default otherwise: - png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); - >> these are all defaults: - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - */ - - - /* set the image parameters appropriately */ - - if (mainprog_ptr->pnmtype == 5) - color_type = PNG_COLOR_TYPE_GRAY; - else if (mainprog_ptr->pnmtype == 6) - color_type = PNG_COLOR_TYPE_RGB; - else if (mainprog_ptr->pnmtype == 8) - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - else { - png_destroy_write_struct(&png_ptr, &info_ptr); - return 11; - } - - interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 : - PNG_INTERLACE_NONE; - - png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height, - mainprog_ptr->sample_depth, color_type, interlace_type, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - if (mainprog_ptr->gamma > 0.0) - png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma); - - if (mainprog_ptr->have_bg) { /* we know it's RGBA, not gray+alpha */ - png_color_16 background; - - background.red = mainprog_ptr->bg_red; - background.green = mainprog_ptr->bg_green; - background.blue = mainprog_ptr->bg_blue; - png_set_bKGD(png_ptr, info_ptr, &background); - } - - if (mainprog_ptr->have_time) { - png_time modtime; - - png_convert_from_time_t(&modtime, mainprog_ptr->modtime); - png_set_tIME(png_ptr, info_ptr, &modtime); - } - - if (mainprog_ptr->have_text) { - png_text text[6]; - int num_text = 0; - - if (mainprog_ptr->have_text & TEXT_TITLE) { - text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; - text[num_text].key = "Title"; - text[num_text].text = mainprog_ptr->title; - ++num_text; - } - if (mainprog_ptr->have_text & TEXT_AUTHOR) { - text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; - text[num_text].key = "Author"; - text[num_text].text = mainprog_ptr->author; - ++num_text; - } - if (mainprog_ptr->have_text & TEXT_DESC) { - text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; - text[num_text].key = "Description"; - text[num_text].text = mainprog_ptr->desc; - ++num_text; - } - if (mainprog_ptr->have_text & TEXT_COPY) { - text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; - text[num_text].key = "Copyright"; - text[num_text].text = mainprog_ptr->copyright; - ++num_text; - } - if (mainprog_ptr->have_text & TEXT_EMAIL) { - text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; - text[num_text].key = "E-mail"; - text[num_text].text = mainprog_ptr->email; - ++num_text; - } - if (mainprog_ptr->have_text & TEXT_URL) { - text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; - text[num_text].key = "URL"; - text[num_text].text = mainprog_ptr->url; - ++num_text; - } - png_set_text(png_ptr, info_ptr, text, num_text); - } - - - /* write all chunks up to (but not including) first IDAT */ - - png_write_info(png_ptr, info_ptr); - - - /* if we wanted to write any more text info *after* the image data, we - * would set up text struct(s) here and call png_set_text() again, with - * just the new data; png_set_tIME() could also go here, but it would - * have no effect since we already called it above (only one tIME chunk - * allowed) */ - - - /* set up the transformations: for now, just pack low-bit-depth pixels - * into bytes (one, two or four pixels per byte) */ - - png_set_packing(png_ptr); -/* png_set_shift(png_ptr, &sig_bit); to scale low-bit-depth values */ - - - /* make sure we save our pointers for use in writepng_encode_image() */ - - mainprog_ptr->png_ptr = png_ptr; - mainprog_ptr->info_ptr = info_ptr; - - - /* OK, that's all we need to do for now; return happy */ - - return 0; -} - - - - - -/* returns 0 for success, 2 for libpng (longjmp) problem */ - -int writepng_encode_image(mainprog_info *mainprog_ptr) -{ - png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; - png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; - - - /* as always, setjmp() must be called in every function that calls a - * PNG-writing libpng function */ - - if (setjmp(mainprog_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - mainprog_ptr->png_ptr = NULL; - mainprog_ptr->info_ptr = NULL; - return 2; - } - - - /* and now we just write the whole image; libpng takes care of interlacing - * for us */ - - png_write_image(png_ptr, mainprog_ptr->row_pointers); - - - /* since that's it, we also close out the end of the PNG file now--if we - * had any text or time info to write after the IDATs, second argument - * would be info_ptr, but we optimize slightly by sending NULL pointer: */ - - png_write_end(png_ptr, NULL); - - return 0; -} - - - - - -/* returns 0 if succeeds, 2 if libpng problem */ - -int writepng_encode_row(mainprog_info *mainprog_ptr) /* NON-interlaced only! */ -{ - png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; - png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; - - - /* as always, setjmp() must be called in every function that calls a - * PNG-writing libpng function */ - - if (setjmp(mainprog_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - mainprog_ptr->png_ptr = NULL; - mainprog_ptr->info_ptr = NULL; - return 2; - } - - - /* image_data points at our one row of image data */ - - png_write_row(png_ptr, mainprog_ptr->image_data); - - return 0; -} - - - - - -/* returns 0 if succeeds, 2 if libpng problem */ - -int writepng_encode_finish(mainprog_info *mainprog_ptr) /* NON-interlaced! */ -{ - png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; - png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; - - - /* as always, setjmp() must be called in every function that calls a - * PNG-writing libpng function */ - - if (setjmp(mainprog_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - mainprog_ptr->png_ptr = NULL; - mainprog_ptr->info_ptr = NULL; - return 2; - } - - - /* close out PNG file; if we had any text or time info to write after - * the IDATs, second argument would be info_ptr: */ - - png_write_end(png_ptr, NULL); - - return 0; -} - - - - - -void writepng_cleanup(mainprog_info *mainprog_ptr) -{ - png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; - png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; - - if (png_ptr && info_ptr) - png_destroy_write_struct(&png_ptr, &info_ptr); -} - - - - - -static void writepng_error_handler(png_structp png_ptr, png_const_charp msg) -{ - mainprog_info *mainprog_ptr; - - /* This function, aside from the extra step of retrieving the "error - * pointer" (below) and the fact that it exists within the application - * rather than within libpng, is essentially identical to libpng's - * default error handler. The second point is critical: since both - * setjmp() and longjmp() are called from the same code, they are - * guaranteed to have compatible notions of how big a jmp_buf is, - * regardless of whether _BSD_SOURCE or anything else has (or has not) - * been defined. */ - - fprintf(stderr, "writepng libpng error: %s\n", msg); - fflush(stderr); - - mainprog_ptr = png_get_error_ptr(png_ptr); - if (mainprog_ptr == NULL) { /* we are completely hosed now */ - fprintf(stderr, - "writepng severe error: jmpbuf not recoverable; terminating.\n"); - fflush(stderr); - exit(99); - } - - /* Now we have our data structure we can use the information in it - * to return control to our own higher level code (all the points - * where 'setjmp' is called in this file.) This will work with other - * error handling mechanisms as well - libpng always calls png_error - * when it can proceed no further, thus, so long as the error handler - * is intercepted, application code can do its own error recovery. - */ - longjmp(mainprog_ptr->jmpbuf, 1); -} +/*--------------------------------------------------------------------------- + + wpng - simple PNG-writing program writepng.c + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + + +#include /* for exit() prototype */ +#include + +#include "png.h" /* libpng header, includes setjmp.h */ +#include "writepng.h" /* typedefs, common macros, public prototypes */ + + +/* local prototype */ + +static void writepng_error_handler(png_structp png_ptr, png_const_charp msg); + + + +void writepng_version_info(void) +{ + fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", + PNG_LIBPNG_VER_STRING, png_libpng_ver); + fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", + ZLIB_VERSION, zlib_version); +} + + + + +/* returns 0 for success, 2 for libpng problem, 4 for out of memory, 11 for + * unexpected pnmtype; note that outfile might be stdout */ + +int writepng_init(mainprog_info *mainprog_ptr) +{ + png_structp png_ptr; /* note: temporary variables! */ + png_infop info_ptr; + int color_type, interlace_type; + + + /* could also replace libpng warning-handler (final NULL), but no need: */ + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, + writepng_error_handler, NULL); + if (!png_ptr) + return 4; /* out of memory */ + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + return 4; /* out of memory */ + } + + + /* setjmp() must be called in every function that calls a PNG-writing + * libpng function, unless an alternate error handler was installed-- + * but compatible error handlers must either use longjmp() themselves + * (as in this program) or some other method to return control to + * application code, so here we go: */ + + if (setjmp(mainprog_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return 2; + } + + + /* make sure outfile is (re)opened in BINARY mode */ + + png_init_io(png_ptr, mainprog_ptr->outfile); + + + /* set the compression levels--in general, always want to leave filtering + * turned on (except for palette images) and allow all of the filters, + * which is the default; want 32K zlib window, unless entire image buffer + * is 16K or smaller (unknown here)--also the default; usually want max + * compression (NOT the default); and remaining compression flags should + * be left alone */ + + png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); +/* + >> this is default for no filtering; Z_FILTERED is default otherwise: + png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); + >> these are all defaults: + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + */ + + + /* set the image parameters appropriately */ + + if (mainprog_ptr->pnmtype == 5) + color_type = PNG_COLOR_TYPE_GRAY; + else if (mainprog_ptr->pnmtype == 6) + color_type = PNG_COLOR_TYPE_RGB; + else if (mainprog_ptr->pnmtype == 8) + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else { + png_destroy_write_struct(&png_ptr, &info_ptr); + return 11; + } + + interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 : + PNG_INTERLACE_NONE; + + png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height, + mainprog_ptr->sample_depth, color_type, interlace_type, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + if (mainprog_ptr->gamma > 0.0) + png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma); + + if (mainprog_ptr->have_bg) { /* we know it's RGBA, not gray+alpha */ + png_color_16 background; + + background.red = mainprog_ptr->bg_red; + background.green = mainprog_ptr->bg_green; + background.blue = mainprog_ptr->bg_blue; + png_set_bKGD(png_ptr, info_ptr, &background); + } + + if (mainprog_ptr->have_time) { + png_time modtime; + + png_convert_from_time_t(&modtime, mainprog_ptr->modtime); + png_set_tIME(png_ptr, info_ptr, &modtime); + } + + if (mainprog_ptr->have_text) { + png_text text[6]; + int num_text = 0; + + if (mainprog_ptr->have_text & TEXT_TITLE) { + text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + text[num_text].key = "Title"; + text[num_text].text = mainprog_ptr->title; + ++num_text; + } + if (mainprog_ptr->have_text & TEXT_AUTHOR) { + text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + text[num_text].key = "Author"; + text[num_text].text = mainprog_ptr->author; + ++num_text; + } + if (mainprog_ptr->have_text & TEXT_DESC) { + text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + text[num_text].key = "Description"; + text[num_text].text = mainprog_ptr->desc; + ++num_text; + } + if (mainprog_ptr->have_text & TEXT_COPY) { + text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + text[num_text].key = "Copyright"; + text[num_text].text = mainprog_ptr->copyright; + ++num_text; + } + if (mainprog_ptr->have_text & TEXT_EMAIL) { + text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + text[num_text].key = "E-mail"; + text[num_text].text = mainprog_ptr->email; + ++num_text; + } + if (mainprog_ptr->have_text & TEXT_URL) { + text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + text[num_text].key = "URL"; + text[num_text].text = mainprog_ptr->url; + ++num_text; + } + png_set_text(png_ptr, info_ptr, text, num_text); + } + + + /* write all chunks up to (but not including) first IDAT */ + + png_write_info(png_ptr, info_ptr); + + + /* if we wanted to write any more text info *after* the image data, we + * would set up text struct(s) here and call png_set_text() again, with + * just the new data; png_set_tIME() could also go here, but it would + * have no effect since we already called it above (only one tIME chunk + * allowed) */ + + + /* set up the transformations: for now, just pack low-bit-depth pixels + * into bytes (one, two or four pixels per byte) */ + + png_set_packing(png_ptr); +/* png_set_shift(png_ptr, &sig_bit); to scale low-bit-depth values */ + + + /* make sure we save our pointers for use in writepng_encode_image() */ + + mainprog_ptr->png_ptr = png_ptr; + mainprog_ptr->info_ptr = info_ptr; + + + /* OK, that's all we need to do for now; return happy */ + + return 0; +} + + + + + +/* returns 0 for success, 2 for libpng (longjmp) problem */ + +int writepng_encode_image(mainprog_info *mainprog_ptr) +{ + png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; + png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; + + + /* as always, setjmp() must be called in every function that calls a + * PNG-writing libpng function */ + + if (setjmp(mainprog_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + mainprog_ptr->png_ptr = NULL; + mainprog_ptr->info_ptr = NULL; + return 2; + } + + + /* and now we just write the whole image; libpng takes care of interlacing + * for us */ + + png_write_image(png_ptr, mainprog_ptr->row_pointers); + + + /* since that's it, we also close out the end of the PNG file now--if we + * had any text or time info to write after the IDATs, second argument + * would be info_ptr, but we optimize slightly by sending NULL pointer: */ + + png_write_end(png_ptr, NULL); + + return 0; +} + + + + + +/* returns 0 if succeeds, 2 if libpng problem */ + +int writepng_encode_row(mainprog_info *mainprog_ptr) /* NON-interlaced only! */ +{ + png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; + png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; + + + /* as always, setjmp() must be called in every function that calls a + * PNG-writing libpng function */ + + if (setjmp(mainprog_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + mainprog_ptr->png_ptr = NULL; + mainprog_ptr->info_ptr = NULL; + return 2; + } + + + /* image_data points at our one row of image data */ + + png_write_row(png_ptr, mainprog_ptr->image_data); + + return 0; +} + + + + + +/* returns 0 if succeeds, 2 if libpng problem */ + +int writepng_encode_finish(mainprog_info *mainprog_ptr) /* NON-interlaced! */ +{ + png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; + png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; + + + /* as always, setjmp() must be called in every function that calls a + * PNG-writing libpng function */ + + if (setjmp(mainprog_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + mainprog_ptr->png_ptr = NULL; + mainprog_ptr->info_ptr = NULL; + return 2; + } + + + /* close out PNG file; if we had any text or time info to write after + * the IDATs, second argument would be info_ptr: */ + + png_write_end(png_ptr, NULL); + + return 0; +} + + + + + +void writepng_cleanup(mainprog_info *mainprog_ptr) +{ + png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; + png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; + + if (png_ptr && info_ptr) + png_destroy_write_struct(&png_ptr, &info_ptr); +} + + + + + +static void writepng_error_handler(png_structp png_ptr, png_const_charp msg) +{ + mainprog_info *mainprog_ptr; + + /* This function, aside from the extra step of retrieving the "error + * pointer" (below) and the fact that it exists within the application + * rather than within libpng, is essentially identical to libpng's + * default error handler. The second point is critical: since both + * setjmp() and longjmp() are called from the same code, they are + * guaranteed to have compatible notions of how big a jmp_buf is, + * regardless of whether _BSD_SOURCE or anything else has (or has not) + * been defined. */ + + fprintf(stderr, "writepng libpng error: %s\n", msg); + fflush(stderr); + + mainprog_ptr = png_get_error_ptr(png_ptr); + if (mainprog_ptr == NULL) { /* we are completely hosed now */ + fprintf(stderr, + "writepng severe error: jmpbuf not recoverable; terminating.\n"); + fflush(stderr); + exit(99); + } + + /* Now we have our data structure we can use the information in it + * to return control to our own higher level code (all the points + * where 'setjmp' is called in this file.) This will work with other + * error handling mechanisms as well - libpng always calls png_error + * when it can proceed no further, thus, so long as the error handler + * is intercepted, application code can do its own error recovery. + */ + longjmp(mainprog_ptr->jmpbuf, 1); +} diff --git a/main/source/includes/lpng1610/contrib/gregbook/writepng.h b/main/source/includes/lpng1610/contrib/gregbook/writepng.h index 904e4fb7..78b966b5 100644 --- a/main/source/includes/lpng1610/contrib/gregbook/writepng.h +++ b/main/source/includes/lpng1610/contrib/gregbook/writepng.h @@ -1,133 +1,133 @@ -/*--------------------------------------------------------------------------- - - wpng - simple PNG-writing program writepng.h - - --------------------------------------------------------------------------- - - Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. - - This software is provided "as is," without warranty of any kind, - express or implied. In no event shall the author or contributors - be held liable for any damages arising in any way from the use of - this software. - - The contents of this file are DUAL-LICENSED. You may modify and/or - redistribute this software according to the terms of one of the - following two licenses (at your option): - - - LICENSE 1 ("BSD-like with advertising clause"): - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute - it freely, subject to the following restrictions: - - 1. Redistributions of source code must retain the above copyright - notice, disclaimer, and this list of conditions. - 2. Redistributions in binary form must reproduce the above copyright - notice, disclaimer, and this list of conditions in the documenta- - tion and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - - This product includes software developed by Greg Roelofs - and contributors for the book, "PNG: The Definitive Guide," - published by O'Reilly and Associates. - - - LICENSE 2 (GNU GPL v2 or later): - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - ---------------------------------------------------------------------------*/ - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#ifndef MAX -# define MAX(a,b) ((a) > (b)? (a) : (b)) -# define MIN(a,b) ((a) < (b)? (a) : (b)) -#endif - -#ifdef DEBUG -# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} -#else -# define Trace(x) ; -#endif - -#define TEXT_TITLE 0x01 -#define TEXT_AUTHOR 0x02 -#define TEXT_DESC 0x04 -#define TEXT_COPY 0x08 -#define TEXT_EMAIL 0x10 -#define TEXT_URL 0x20 - -#define TEXT_TITLE_OFFSET 0 -#define TEXT_AUTHOR_OFFSET 72 -#define TEXT_COPY_OFFSET (2*72) -#define TEXT_EMAIL_OFFSET (3*72) -#define TEXT_URL_OFFSET (4*72) -#define TEXT_DESC_OFFSET (5*72) - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -typedef struct _mainprog_info { - double gamma; - long width; - long height; - time_t modtime; - FILE *infile; - FILE *outfile; - void *png_ptr; - void *info_ptr; - uch *image_data; - uch **row_pointers; - char *title; - char *author; - char *desc; - char *copyright; - char *email; - char *url; - int filter; /* command-line-filter flag, not PNG row filter! */ - int pnmtype; - int sample_depth; - int interlaced; - int have_bg; - int have_time; - int have_text; - jmp_buf jmpbuf; - uch bg_red; - uch bg_green; - uch bg_blue; -} mainprog_info; - - -/* prototypes for public functions in writepng.c */ - -void writepng_version_info(void); - -int writepng_init(mainprog_info *mainprog_ptr); - -int writepng_encode_image(mainprog_info *mainprog_ptr); - -int writepng_encode_row(mainprog_info *mainprog_ptr); - -int writepng_encode_finish(mainprog_info *mainprog_ptr); - -void writepng_cleanup(mainprog_info *mainprog_ptr); +/*--------------------------------------------------------------------------- + + wpng - simple PNG-writing program writepng.h + + --------------------------------------------------------------------------- + + Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. + + This software is provided "as is," without warranty of any kind, + express or implied. In no event shall the author or contributors + be held liable for any damages arising in any way from the use of + this software. + + The contents of this file are DUAL-LICENSED. You may modify and/or + redistribute this software according to the terms of one of the + following two licenses (at your option): + + + LICENSE 1 ("BSD-like with advertising clause"): + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright + notice, disclaimer, and this list of conditions. + 2. Redistributions in binary form must reproduce the above copyright + notice, disclaimer, and this list of conditions in the documenta- + tion and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + + This product includes software developed by Greg Roelofs + and contributors for the book, "PNG: The Definitive Guide," + published by O'Reilly and Associates. + + + LICENSE 2 (GNU GPL v2 or later): + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ---------------------------------------------------------------------------*/ + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b)? (a) : (b)) +# define MIN(a,b) ((a) < (b)? (a) : (b)) +#endif + +#ifdef DEBUG +# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} +#else +# define Trace(x) ; +#endif + +#define TEXT_TITLE 0x01 +#define TEXT_AUTHOR 0x02 +#define TEXT_DESC 0x04 +#define TEXT_COPY 0x08 +#define TEXT_EMAIL 0x10 +#define TEXT_URL 0x20 + +#define TEXT_TITLE_OFFSET 0 +#define TEXT_AUTHOR_OFFSET 72 +#define TEXT_COPY_OFFSET (2*72) +#define TEXT_EMAIL_OFFSET (3*72) +#define TEXT_URL_OFFSET (4*72) +#define TEXT_DESC_OFFSET (5*72) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +typedef struct _mainprog_info { + double gamma; + long width; + long height; + time_t modtime; + FILE *infile; + FILE *outfile; + void *png_ptr; + void *info_ptr; + uch *image_data; + uch **row_pointers; + char *title; + char *author; + char *desc; + char *copyright; + char *email; + char *url; + int filter; /* command-line-filter flag, not PNG row filter! */ + int pnmtype; + int sample_depth; + int interlaced; + int have_bg; + int have_time; + int have_text; + jmp_buf jmpbuf; + uch bg_red; + uch bg_green; + uch bg_blue; +} mainprog_info; + + +/* prototypes for public functions in writepng.c */ + +void writepng_version_info(void); + +int writepng_init(mainprog_info *mainprog_ptr); + +int writepng_encode_image(mainprog_info *mainprog_ptr); + +int writepng_encode_row(mainprog_info *mainprog_ptr); + +int writepng_encode_finish(mainprog_info *mainprog_ptr); + +void writepng_cleanup(mainprog_info *mainprog_ptr); diff --git a/main/source/includes/lpng1610/contrib/libtests/fakepng.c b/main/source/includes/lpng1610/contrib/libtests/fakepng.c index bc37254e..ba360d15 100644 --- a/main/source/includes/lpng1610/contrib/libtests/fakepng.c +++ b/main/source/includes/lpng1610/contrib/libtests/fakepng.c @@ -1,57 +1,57 @@ -/* Fake a PNG - just write it out directly. */ -#include -#include /* for crc32 */ - -void -put_uLong(uLong val) -{ - putchar(val >> 24); - putchar(val >> 16); - putchar(val >> 8); - putchar(val >> 0); -} - -void -put_chunk(const unsigned char *chunk, uInt length) -{ - uLong crc; - - put_uLong(length-4); /* Exclude the tag */ - - fwrite(chunk, length, 1, stdout); - - crc = crc32(0, Z_NULL, 0); - put_uLong(crc32(crc, chunk, length)); -} - -const unsigned char signature[] = -{ - 137, 80, 78, 71, 13, 10, 26, 10 -}; - -const unsigned char IHDR[] = -{ - 73, 72, 68, 82, /* IHDR */ - 0, 0, 0, 1, /* width */ - 0, 0, 0, 1, /* height */ - 1, /* bit depth */ - 0, /* color type: greyscale */ - 0, /* compression method */ - 0, /* filter method */ - 0 /* interlace method: none */ -}; - -const unsigned char unknown[] = -{ - 'u', 'n', 'K', 'n' /* "unKn" - private safe to copy */ -}; - -int -main(void) -{ - fwrite(signature, sizeof signature, 1, stdout); - put_chunk(IHDR, sizeof IHDR); - - for(;;) - put_chunk(unknown, sizeof unknown); -} +/* Fake a PNG - just write it out directly. */ +#include +#include /* for crc32 */ + +void +put_uLong(uLong val) +{ + putchar(val >> 24); + putchar(val >> 16); + putchar(val >> 8); + putchar(val >> 0); +} + +void +put_chunk(const unsigned char *chunk, uInt length) +{ + uLong crc; + + put_uLong(length-4); /* Exclude the tag */ + + fwrite(chunk, length, 1, stdout); + + crc = crc32(0, Z_NULL, 0); + put_uLong(crc32(crc, chunk, length)); +} + +const unsigned char signature[] = +{ + 137, 80, 78, 71, 13, 10, 26, 10 +}; + +const unsigned char IHDR[] = +{ + 73, 72, 68, 82, /* IHDR */ + 0, 0, 0, 1, /* width */ + 0, 0, 0, 1, /* height */ + 1, /* bit depth */ + 0, /* color type: greyscale */ + 0, /* compression method */ + 0, /* filter method */ + 0 /* interlace method: none */ +}; + +const unsigned char unknown[] = +{ + 'u', 'n', 'K', 'n' /* "unKn" - private safe to copy */ +}; + +int +main(void) +{ + fwrite(signature, sizeof signature, 1, stdout); + put_chunk(IHDR, sizeof IHDR); + + for(;;) + put_chunk(unknown, sizeof unknown); +} diff --git a/main/source/includes/lpng1610/contrib/libtests/gentests.sh b/main/source/includes/lpng1610/contrib/libtests/gentests.sh index 83586657..f0f8d239 100644 --- a/main/source/includes/lpng1610/contrib/libtests/gentests.sh +++ b/main/source/includes/lpng1610/contrib/libtests/gentests.sh @@ -1,102 +1,102 @@ -#!/bin/sh -# -# Copyright (c) 2013 John Cunningham Bowler -# -# Last changed in libpng 1.6.0 [February 14, 2013] -# -# This code is released under the libpng license. -# For conditions of distribution and use, see the disclaimer -# and license in png.h -# -# Generate a set of PNG test images. The images are generated in a -# sub-directory called 'tests' by default, however a command line argument will -# change that name. The generation requires a built version of makepng in the -# current directory. -# -usage(){ - exec >&2 - echo "$0 []" - echo ' Generate a set of PNG test files in "directory" ("tests" by default)' - exit 1 -} - -mp="$PWD/makepng" -test -x "$mp" || { - exec >&2 - echo "$0: the 'makepng' program must exist" - echo " in the directory within which this program:" - echo " $mp" - echo " is executed" - usage -} - -# Just one argument: the directory -testdir="tests" -test $# -gt 1 && { - testdir="$1" - shift -} -test $# -eq 0 || usage - -# Take care not to clobber something -if test -e "$testdir" -then - test -d "$testdir" || usage -else - # mkdir -p isn't portable, so do the following - mkdir "$testdir" 2>/dev/null || mkdir -p "$testdir" || usage -fi - -# This fails in a very satisfactory way if it's not accessible -cd "$testdir" -:>"test$$.png" || { - exec >&2 - echo "$testdir: directory not writable" - usage -} -rm "test$$.png" || { - exec >&2 - echo "$testdir: you have create but not write privileges here." - echo " This is unexpected. You have a spurion; "'"'"test$$.png"'"'"." - echo " You need to remove this yourself. Try a different directory." - exit 1 -} - -# Now call makepng ($mp) to create every file we can think of with a -# reasonable name -doit(){ - for gamma in "" --sRGB --linear --1.8 - do - case "$gamma" in - "") - gname=;; - --sRGB) - gname="-srgb";; - --linear) - gname="-lin";; - --1.8) - gname="-18";; - *) - gname="-$gamma";; - esac - "$mp" $gamma "$1" "$2" "test-$1-$2$gname.png" - done -} -# -for ct in gray palette -do - for bd in 1 2 4 8 - do - doit "$ct" "$bd" - done -done -# -doit "gray" "16" -# -for ct in gray-alpha rgb rgb-alpha -do - for bd in 8 16 - do - doit "$ct" "$bd" - done -done +#!/bin/sh +# +# Copyright (c) 2013 John Cunningham Bowler +# +# Last changed in libpng 1.6.0 [February 14, 2013] +# +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h +# +# Generate a set of PNG test images. The images are generated in a +# sub-directory called 'tests' by default, however a command line argument will +# change that name. The generation requires a built version of makepng in the +# current directory. +# +usage(){ + exec >&2 + echo "$0 []" + echo ' Generate a set of PNG test files in "directory" ("tests" by default)' + exit 1 +} + +mp="$PWD/makepng" +test -x "$mp" || { + exec >&2 + echo "$0: the 'makepng' program must exist" + echo " in the directory within which this program:" + echo " $mp" + echo " is executed" + usage +} + +# Just one argument: the directory +testdir="tests" +test $# -gt 1 && { + testdir="$1" + shift +} +test $# -eq 0 || usage + +# Take care not to clobber something +if test -e "$testdir" +then + test -d "$testdir" || usage +else + # mkdir -p isn't portable, so do the following + mkdir "$testdir" 2>/dev/null || mkdir -p "$testdir" || usage +fi + +# This fails in a very satisfactory way if it's not accessible +cd "$testdir" +:>"test$$.png" || { + exec >&2 + echo "$testdir: directory not writable" + usage +} +rm "test$$.png" || { + exec >&2 + echo "$testdir: you have create but not write privileges here." + echo " This is unexpected. You have a spurion; "'"'"test$$.png"'"'"." + echo " You need to remove this yourself. Try a different directory." + exit 1 +} + +# Now call makepng ($mp) to create every file we can think of with a +# reasonable name +doit(){ + for gamma in "" --sRGB --linear --1.8 + do + case "$gamma" in + "") + gname=;; + --sRGB) + gname="-srgb";; + --linear) + gname="-lin";; + --1.8) + gname="-18";; + *) + gname="-$gamma";; + esac + "$mp" $gamma "$1" "$2" "test-$1-$2$gname.png" + done +} +# +for ct in gray palette +do + for bd in 1 2 4 8 + do + doit "$ct" "$bd" + done +done +# +doit "gray" "16" +# +for ct in gray-alpha rgb rgb-alpha +do + for bd in 8 16 + do + doit "$ct" "$bd" + done +done diff --git a/main/source/includes/lpng1610/contrib/libtests/makepng.c b/main/source/includes/lpng1610/contrib/libtests/makepng.c index 967fcf1d..9f11b296 100644 --- a/main/source/includes/lpng1610/contrib/libtests/makepng.c +++ b/main/source/includes/lpng1610/contrib/libtests/makepng.c @@ -1,1486 +1,1486 @@ -/* makepng.c - * - * Copyright (c) 2013 John Cunningham Bowler - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * Make a test PNG image. The arguments are as follows: - * - * makepng [--sRGB|--linear|--1.8] [--color=] color-type bit-depth \ - * [file-name] - * - * The color-type may be numeric (and must match the numbers used by the PNG - * specification) or one of the format names listed below. The bit-depth is the - * component bit depth, or the pixel bit-depth for a color-mapped image. - * - * Without any options no color-space information is written, with the options - * an sRGB or the appropriate gAMA chunk is written. "1.8" refers to the - * display system used on older Apple computers to correct for high ambient - * light levels in the viewing environment; it applies a transform of - * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909 - * is written (1.45/2.2). - * - * The image data is generated internally. Unless --color is given the images - * used are as follows: - * - * 1 channel: a square image with a diamond, the least luminous colors are on - * the edge of the image, the most luminous in the center. - * - * 2 channels: the color channel increases in luminosity from top to bottom, the - * alpha channel increases in opacity from left to right. - * - * 3 channels: linear combinations of, from the top-left corner clockwise, - * black, green, white, red. - * - * 4 channels: linear combinations of, from the top-left corner clockwise, - * transparent, red, green, blue. - * - * For color-mapped images a four channel color-map is used and the PNG file has - * a tRNS chunk, as follows: - * - * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white - * 2-bit: entry 0: transparent-green - * entry 1: 40%-red - * entry 2: 80%-blue - * entry 3: opaque-white - * 4-bit: the 16 combinations of the 2-bit case - * 8-bit: the 256 combinations of the 4-bit case - * - * The palette always has 2^bit-depth entries and the tRNS chunk one fewer. The - * image is the 1-channel diamond, but using palette index, not luminosity. - * - * Image size is determined by the final pixel depth in bits, i.e. channels x - * bit-depth, as follows: - * - * 8 bits or less: 64x64 - * 16 bits: 256x256 - * More than 16 bits: 1024x1024 - * - * Row filtering is turned off (the 'none' filter is used on every row) and the - * images are not interlaced. - * - * If --color is given then the whole image has that color, color-mapped images - * will have exactly one palette entry and all image files with be 16x16 in - * size. The color value is 1 to 4 decimal numbers as appropriate for the color - * type. - * - * If file-name is given then the PNG is written to that file, else it is - * written to stdout. Notice that stdout is not supported on systems where, by - * default, it assumes text output; this program makes no attempt to change the - * text mode of stdout! - */ -#define _ISOC99_SOURCE /* for strtoull */ - -#include /* for offsetof */ -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include -#endif - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include -#else -# include "../../png.h" -#endif - -/* This structure is used for inserting extra chunks (the --insert argument, not - * documented above.) - */ -typedef struct chunk_insert -{ - struct chunk_insert *next; - void (*insert)(png_structp, png_infop, int, png_charpp); - int nparams; - png_charp parameters[1]; -} chunk_insert; - -static int -channels_of_type(int color_type) -{ - if (color_type & PNG_COLOR_MASK_PALETTE) - return 1; - - else - { - int channels = 1; - - if (color_type & PNG_COLOR_MASK_COLOR) - channels = 3; - - if (color_type & PNG_COLOR_MASK_ALPHA) - return channels + 1; - - else - return channels; - } -} - -static int -pixel_depth_of_type(int color_type, int bit_depth) -{ - return channels_of_type(color_type) * bit_depth; -} - -static unsigned int -image_size_of_type(int color_type, int bit_depth, unsigned int *colors) -{ - if (*colors) - return 16; - - else - { - int pixel_depth = pixel_depth_of_type(color_type, bit_depth); - - if (pixel_depth < 8) - return 64; - - else if (pixel_depth > 16) - return 1024; - - else - return 256; - } -} - -static void -set_color(png_colorp color, png_bytep trans, unsigned int red, - unsigned int green, unsigned int blue, unsigned int alpha, - png_const_bytep gamma_table) -{ - color->red = gamma_table[red]; - color->green = gamma_table[green]; - color->blue = gamma_table[blue]; - *trans = (png_byte)alpha; -} - -static int -generate_palette(png_colorp palette, png_bytep trans, int bit_depth, - png_const_bytep gamma_table, unsigned int *colors) -{ - /* - * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white - * 2-bit: entry 0: transparent-green - * entry 1: 40%-red - * entry 2: 80%-blue - * entry 3: opaque-white - * 4-bit: the 16 combinations of the 2-bit case - * 8-bit: the 256 combinations of the 4-bit case - */ - switch (colors[0]) - { - default: - fprintf(stderr, "makepng: --colors=...: invalid count %u\n", - colors[0]); - exit(1); - - case 1: - set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255, - gamma_table); - return 1; - - case 2: - set_color(palette+0, trans+0, colors[1], colors[1], colors[1], - colors[2], gamma_table); - return 1; - - case 3: - set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255, - gamma_table); - return 1; - - case 4: - set_color(palette+0, trans+0, colors[1], colors[2], colors[3], - colors[4], gamma_table); - return 1; - - case 0: - if (bit_depth == 1) - { - set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table); - set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table); - return 2; - } - - else - { - unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */ - unsigned int x, y, ip; - - for (x=0; x> 3; - - if (offset < rowbytes && (bit_depth < 16 || offset+1 < rowbytes)) - { - row += offset; - - switch (bit_depth) - { - case 1: - case 2: - case 4: - /* Don't gamma correct - values get smashed */ - { - unsigned int shift = (8 - bit_depth) - (x & 0x7U); - - mask <<= shift; - value = (value << shift) & mask; - *row = (png_byte)((*row & ~mask) | value); - } - return; - - default: - fprintf(stderr, "makepng: bad bit depth (internal error)\n"); - exit(1); - - case 16: - value = (unsigned int)floor(65535*pow(value/65535.,conv)+.5); - *row++ = (png_byte)(value >> 8); - *row = (png_byte)value; - return; - - case 8: - *row = gamma_table[value]; - return; - } - } - - else - { - fprintf(stderr, "makepng: row buffer overflow (internal error)\n"); - exit(1); - } - } - - else - { - fprintf(stderr, "makepng: component overflow (internal error)\n"); - exit(1); - } -} - -static void -generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, - int bit_depth, png_const_bytep gamma_table, double conv, - unsigned int *colors) -{ - png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1; - png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */ - - if (colors[0] == 0) switch (channels_of_type(color_type)) - { - /* 1 channel: a square image with a diamond, the least luminous colors are on - * the edge of the image, the most luminous in the center. - */ - case 1: - { - png_uint_32 x; - png_uint_32 base = 2*size_max - abs(2*y-size_max); - - for (x=0; x<=size_max; ++x) - { - png_uint_32 luma = base - abs(2*x-size_max); - - /* 'luma' is now in the range 0..2*size_max, we need - * 0..depth_max - */ - luma = (luma*depth_max + size_max) / (2*size_max); - set_value(row, rowbytes, x, bit_depth, luma, gamma_table, conv); - } - } - break; - - /* 2 channels: the color channel increases in luminosity from top to bottom, - * the alpha channel increases in opacity from left to right. - */ - case 2: - { - png_uint_32 alpha = (depth_max * y * 2 + size_max) / (2 * size_max); - png_uint_32 x; - - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 2*x, bit_depth, - (depth_max * x * 2 + size_max) / (2 * size_max), gamma_table, - conv); - set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table, - conv); - } - } - break; - - /* 3 channels: linear combinations of, from the top-left corner clockwise, - * black, green, white, red. - */ - case 3: - { - /* x0: the black->red scale (the value of the red component) at the - * start of the row (blue and green are 0). - * x1: the green->white scale (the value of the red and blue - * components at the end of the row; green is depth_max). - */ - png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); - png_uint_32 x; - - /* Interpolate x/depth_max from start to end: - * - * start end difference - * red: Y Y 0 - * green: 0 depth_max depth_max - * blue: 0 Y Y - */ - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 3*x+0, bit_depth, /* red */ Y, - gamma_table, conv); - set_value(row, rowbytes, 3*x+1, bit_depth, /* green */ - (depth_max * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 3*x+2, bit_depth, /* blue */ - (Y * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - } - } - break; - - /* 4 channels: linear combinations of, from the top-left corner clockwise, - * transparent, red, green, blue. - */ - case 4: - { - /* x0: the transparent->blue scale (the value of the blue and alpha - * components) at the start of the row (red and green are 0). - * x1: the red->green scale (the value of the red and green - * components at the end of the row; blue is 0 and alpha is - * depth_max). - */ - png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); - png_uint_32 x; - - /* Interpolate x/depth_max from start to end: - * - * start end difference - * red: 0 depth_max-Y depth_max-Y - * green: 0 Y Y - * blue: Y 0 -Y - * alpha: Y depth_max depth_max-Y - */ - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 4*x+0, bit_depth, /* red */ - ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 4*x+1, bit_depth, /* green */ - (Y * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 4*x+2, bit_depth, /* blue */ - Y - (Y * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 4*x+3, bit_depth, /* alpha */ - Y + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - } - } - break; - - default: - fprintf(stderr, "makepng: internal bad channel count\n"); - exit(2); - } - - else if (color_type & PNG_COLOR_MASK_PALETTE) - { - /* Palette with fixed color: the image rows are all 0 and the image width - * is 16. - */ - memset(row, 0, rowbytes); - } - - else if (colors[0] == channels_of_type(color_type)) - switch (channels_of_type(color_type)) - { - case 1: - { - const png_uint_32 luma = colors[1]; - png_uint_32 x; - - for (x=0; x<=size_max; ++x) - set_value(row, rowbytes, x, bit_depth, luma, gamma_table, - conv); - } - break; - - case 2: - { - const png_uint_32 luma = colors[1]; - const png_uint_32 alpha = colors[2]; - png_uint_32 x; - - for (x=0; x 0 && gamma < 1000) - gamma = PNG_FP_1; - - if (gamma > 0) - real_gamma = gamma; - - { - unsigned int i; - - if (real_gamma == 45455) for (i=0; i<256; ++i) - { - gamma_table[i] = (png_byte)i; - conv = 1.; - } - - else - { - /* Convert 'i' from sRGB (45455) to real_gamma, this makes - * the images look the same regardless of the gAMA chunk. - */ - conv = real_gamma; - conv /= 45455; - - gamma_table[0] = 0; - - for (i=1; i<255; ++i) - gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + .5); - - gamma_table[255] = 255; - } - } - - png_set_IHDR(png_ptr, info_ptr, size, size, bit_depth, color_type, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - if (color_type & PNG_COLOR_MASK_PALETTE) - { - int npalette; - png_color palette[256]; - png_byte trans[256]; - - npalette = generate_palette(palette, trans, bit_depth, gamma_table, - colors); - png_set_PLTE(png_ptr, info_ptr, palette, npalette); - png_set_tRNS(png_ptr, info_ptr, trans, npalette-1, - NULL/*transparent color*/); - - /* Reset gamma_table to prevent the image rows being changed */ - for (npalette=0; npalette<256; ++npalette) - gamma_table[npalette] = (png_byte)npalette; - } - - if (gamma == PNG_DEFAULT_sRGB) - png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); - - else if (gamma > 0) /* Else don't set color space information */ - { - png_set_gAMA_fixed(png_ptr, info_ptr, real_gamma); - - /* Just use the sRGB values here. */ - png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270, 32900, - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000 - ); - } - - /* Insert extra information. */ - while (insert != NULL) - { - insert->insert(png_ptr, info_ptr, insert->nparams, insert->parameters); - insert = insert->next; - } - - /* Write the file header. */ - png_write_info(png_ptr, info_ptr); - - /* Restrict the filters */ - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters); - - { - int passes = png_set_interlace_handling(png_ptr); - int pass; - png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - row = malloc(rowbytes); - - if (row == NULL) - png_error(png_ptr, "OOM allocating row buffer"); - - for (pass = 0; pass < passes; ++pass) - { - unsigned int y; - - for (y=0; y 0) - { - /* Round up to a multiple of 4 here to allow an iCCP profile - * to be padded to a 4x boundary. - */ - png_bytep data = malloc((total+3)&~3); - - if (data != NULL) - { - size_t new_size = 0; - - for (;;) - { - ch = getc(fp); - if (ch == EOF) break; - data[new_size++] = (png_byte)ch; - } - - if (ferror(fp) || new_size != total) - { - perror("temporary file"); - fprintf(stderr, "temporary file read error\n"); - free(data); - } - - else - { - (void)fclose(fp); - *result = data; - return total; - } - } - - else - fprintf(stderr, "%s: out of memory loading file\n", name); - } - - else - fprintf(stderr, "%s: empty file\n", name); - } - } - } - - else - { - perror(name); - fprintf(stderr, "%s: open failed\n", name); - } - - fclose(fp); - } - - else - fprintf(stderr, "makepng: %s: could not open temporary file\n", name); - - exit(1); - return 0; -} - -static png_size_t -load_fake(png_charp param, png_bytepp profile) -{ - char *endptr = NULL; - unsigned long long int size = strtoull(param, &endptr, 0/*base*/); - - /* The 'fake' format is *[string] */ - if (endptr != NULL && *endptr == '*') - { - size_t len = strlen(++endptr); - size_t result = (size_t)size; - - if (len == 0) len = 1; /* capture the terminating '\0' */ - - /* Now repeat that string to fill 'size' bytes. */ - if (result == size && (*profile = malloc(result)) != NULL) - { - png_bytep out = *profile; - - if (len == 1) - memset(out, *endptr, result); - - else - { - while (size >= len) - { - memcpy(out, endptr, len); - out += len; - size -= len; - } - memcpy(out, endptr, size); - } - - return result; - } - - else - { - fprintf(stderr, "%s: size exceeds system limits\n", param); - exit(1); - } - } - - return 0; -} - -static void -check_param_count(int nparams, int expect) -{ - if (nparams != expect) - { - fprintf(stderr, "bad parameter count (internal error)\n"); - exit(1); - } -} - -static void -insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_bytep profile = NULL; - png_uint_32 proflen = 0; - int result; - - check_param_count(nparams, 2); - - switch (params[1][0]) - { - case '<': - { - png_size_t filelen = load_file(params[1]+1, &profile); - if (filelen > 0xfffffffc) /* Maximum profile length */ - { - fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n", - params[1]+1, (unsigned long)filelen); - exit(1); - } - - proflen = (png_uint_32)filelen; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - png_size_t fake_len = load_fake(params[1], &profile); - - if (fake_len > 0) /* else a simple parameter */ - { - if (fake_len > 0xffffffff) /* Maximum profile length */ - { - fprintf(stderr, - "%s: fake data too long (%lu) for an ICC profile\n", - params[1], (unsigned long)fake_len); - exit(1); - } - proflen = (png_uint_32)(fake_len & ~3U); - /* Always fix up the profile length. */ - png_save_uint_32(profile, proflen); - break; - } - } - - default: - fprintf(stderr, "--insert iCCP \"%s\": unrecognized\n", params[1]); - fprintf(stderr, " use '<' to read a file: \" 3) - { - png_uint_32 prof_header = png_get_uint_32(profile); - - if (prof_header != proflen) - { - fprintf(stderr, "--insert iCCP %s: profile length field wrong:\n", - params[1]); - fprintf(stderr, " actual %lu, recorded value %lu (corrected)\n", - (unsigned long)proflen, (unsigned long)prof_header); - png_save_uint_32(profile, proflen); - } - } - - if (result && profile != NULL && proflen >=4) - png_set_iCCP(png_ptr, info_ptr, params[0], PNG_COMPRESSION_TYPE_BASE, - profile, proflen); - - if (profile) - free(profile); - - if (!result) - exit(1); -} - -static void -clear_text(png_text *text, png_charp keyword) -{ - text->compression = -1; /* none */ - text->key = keyword; - text->text = NULL; - text->text_length = 0; /* libpng calculates this */ - text->itxt_length = 0; /* libpng calculates this */ - text->lang = NULL; - text->lang_key = NULL; -} - -static void -set_text(png_structp png_ptr, png_infop info_ptr, png_textp text, - png_charp param) -{ - switch (param[0]) - { - case '<': - { - png_bytep file = NULL; - - text->text_length = load_file(param+1, &file); - text->text = (png_charp)file; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - png_bytep data = NULL; - png_size_t fake_len = load_fake(param, &data); - - if (fake_len > 0) /* else a simple parameter */ - { - text->text_length = fake_len; - text->text = (png_charp)data; - break; - } - } - - default: - text->text = param; - break; - } - - png_set_text(png_ptr, info_ptr, text, 1); - - if (text->text != param) - free(text->text); -} - -static void -insert_tEXt(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_text text; - - check_param_count(nparams, 2); - clear_text(&text, params[0]); - set_text(png_ptr, info_ptr, &text, params[1]); -} - -static void -insert_zTXt(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_text text; - - check_param_count(nparams, 2); - clear_text(&text, params[0]); - text.compression = 0; /* deflate */ - set_text(png_ptr, info_ptr, &text, params[1]); -} - -static void -insert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_text text; - - check_param_count(nparams, 4); - clear_text(&text, params[0]); - text.compression = 2; /* iTXt + deflate */ - text.lang = params[1];/* language tag */ - text.lang_key = params[2]; /* translated keyword */ - set_text(png_ptr, info_ptr, &text, params[3]); -} - -static void -insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params) -{ - int i; - png_uint_16 freq[256]; - - /* libpng takes the count from the PLTE count; we don't check it here but we - * do set the array to 0 for unspecified entries. - */ - memset(freq, 0, sizeof freq); - for (i=0; inext = NULL; - cip->insert = insert; - cip->nparams = nparams; - for (i=0; iparameters[i] = list[i]; - - return cip; -} - -static chunk_insert * -find_insert(png_const_charp what, png_charp param) -{ - png_uint_32 chunk = 0; - png_charp parameter_list[1024]; - int i, nparams; - - /* Assemble the chunk name */ - for (i=0; i<4; ++i) - { - char ch = what[i]; - - if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) - chunk = (chunk << 8) + what[i]; - - else - break; - } - - if (i < 4 || what[4] != 0) - { - fprintf(stderr, "makepng --insert \"%s\": invalid chunk name\n", what); - exit(1); - } - - /* Assemble the parameter list. */ - nparams = find_parameters(what, param, parameter_list, 1024); - -# define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) - - switch (chunk) - { - case CHUNK(105,67,67,80): /* iCCP */ - if (nparams == 2) - return make_insert(what, insert_iCCP, nparams, parameter_list); - break; - - case CHUNK(116,69,88,116): /* tEXt */ - if (nparams == 2) - return make_insert(what, insert_tEXt, nparams, parameter_list); - break; - - case CHUNK(122,84,88,116): /* zTXt */ - if (nparams == 2) - return make_insert(what, insert_zTXt, nparams, parameter_list); - break; - - case CHUNK(105,84,88,116): /* iTXt */ - if (nparams == 4) - return make_insert(what, insert_iTXt, nparams, parameter_list); - break; - - case CHUNK(104,73,83,84): /* hIST */ - if (nparams <= 256) - return make_insert(what, insert_hIST, nparams, parameter_list); - break; - -#if 0 - case CHUNK(115,80,76,84): /* sPLT */ - return make_insert(what, insert_sPLT, nparams, parameter_list); -#endif - - default: - fprintf(stderr, "makepng --insert \"%s\": unrecognized chunk name\n", - what); - exit(1); - } - - bad_parameter_count(what, nparams); - return NULL; -} - -/* This is a not-very-good parser for a sequence of numbers (including 0). It - * doesn't accept some apparently valid things, but it accepts all the sensible - * combinations. - */ -static void -parse_color(char *arg, unsigned int *colors) -{ - unsigned int ncolors = 0; - - while (*arg && ncolors < 4) - { - char *ep = arg; - - unsigned long ul = strtoul(arg, &ep, 0); - - if (ul > 65535) - { - fprintf(stderr, "makepng --color=...'%s': too big\n", arg); - exit(1); - } - - if (ep == arg) - { - fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg); - exit(1); - } - - if (*ep) ++ep; /* skip a separator */ - arg = ep; - - colors[++ncolors] = (unsigned int)ul; /* checked above */ - } - - if (*arg) - { - fprintf(stderr, "makepng --color=...'%s': too many values\n", arg); - exit(1); - } - - *colors = ncolors; -} - -int -main(int argc, char **argv) -{ - FILE *fp = stdout; - const char *file_name = NULL; - int color_type = 8; /* invalid */ - int bit_depth = 32; /* invalid */ - unsigned int colors[5]; - unsigned int filters = PNG_ALL_FILTERS; - png_fixed_point gamma = 0; /* not set */ - chunk_insert *head_insert = NULL; - chunk_insert **insert_ptr = &head_insert; - - memset(colors, 0, sizeof colors); - - while (--argc > 0) - { - char *arg = *++argv; - - if (strcmp(arg, "--sRGB") == 0) - { - gamma = PNG_DEFAULT_sRGB; - continue; - } - - if (strcmp(arg, "--linear") == 0) - { - gamma = PNG_FP_1; - continue; - } - - if (strcmp(arg, "--1.8") == 0) - { - gamma = PNG_GAMMA_MAC_18; - continue; - } - - if (strcmp(arg, "--nofilters") == 0) - { - filters = PNG_FILTER_NONE; - continue; - } - - if (strncmp(arg, "--color=", 8) == 0) - { - parse_color(arg+8, colors); - continue; - } - - if (argc >= 3 && strcmp(arg, "--insert") == 0) - { - png_const_charp what = *++argv; - png_charp param = *++argv; - chunk_insert *new_insert; - - argc -= 2; - - new_insert = find_insert(what, param); - - if (new_insert != NULL) - { - *insert_ptr = new_insert; - insert_ptr = &new_insert->next; - } - - continue; - } - - if (arg[0] == '-') - { - fprintf(stderr, "makepng: %s: invalid option\n", arg); - exit(1); - } - - if (strcmp(arg, "palette") == 0) - { - color_type = PNG_COLOR_TYPE_PALETTE; - continue; - } - - if (strncmp(arg, "gray", 4) == 0) - { - if (arg[4] == 0) - { - color_type = PNG_COLOR_TYPE_GRAY; - continue; - } - - else if (strcmp(arg+4, "a") == 0 || - strcmp(arg+4, "alpha") == 0 || - strcmp(arg+4, "-alpha") == 0) - { - color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - continue; - } - } - - if (strncmp(arg, "rgb", 3) == 0) - { - if (arg[3] == 0) - { - color_type = PNG_COLOR_TYPE_RGB; - continue; - } - - else if (strcmp(arg+3, "a") == 0 || - strcmp(arg+3, "alpha") == 0 || - strcmp(arg+3, "-alpha") == 0) - { - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - continue; - } - } - - if (color_type == 8 && isdigit(arg[0])) - { - color_type = atoi(arg); - if (color_type < 0 || color_type > 6 || color_type == 1 || - color_type == 5) - { - fprintf(stderr, "makepng: %s: not a valid color type\n", arg); - exit(1); - } - - continue; - } - - if (bit_depth == 32 && isdigit(arg[0])) - { - bit_depth = atoi(arg); - if (bit_depth <= 0 || bit_depth > 16 || - (bit_depth & -bit_depth) != bit_depth) - { - fprintf(stderr, "makepng: %s: not a valid bit depth\n", arg); - exit(1); - } - - continue; - } - - if (argc == 1) /* It's the file name */ - { - fp = fopen(arg, "wb"); - if (fp == NULL) - { - fprintf(stderr, "%s: %s: could not open\n", arg, strerror(errno)); - exit(1); - } - - file_name = arg; - continue; - } - - fprintf(stderr, "makepng: %s: unknown argument\n", arg); - exit(1); - } /* argument while loop */ - - if (color_type == 8 || bit_depth == 32) - { - fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] " - "[--color=...] color-type bit-depth [file-name]\n" - " Make a test PNG file, by default writes to stdout.\n"); - exit(1); - } - - /* Check the colors */ - { - const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U : - (1U< lim) - { - fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n", - colors[i], lim); - exit(1); - } - } - - /* Restrict the filters for more speed to those we know are used for the - * generated images. - */ - if (filters == PNG_ALL_FILTERS) - { - if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8) - filters = PNG_FILTER_NONE; - - else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */ - { - if (bit_depth == 8) - filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG); - - else - filters = PNG_FILTER_SUB | PNG_FILTER_PAETH; - } - - else /* gray 8 or 16-bit */ - filters &= ~PNG_FILTER_NONE; - } - - { - int ret = write_png(&file_name, fp, color_type, bit_depth, gamma, - head_insert, filters, colors); - - if (ret != 0 && file_name != NULL) - remove(file_name); - - return ret; - } -} +/* makepng.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Make a test PNG image. The arguments are as follows: + * + * makepng [--sRGB|--linear|--1.8] [--color=] color-type bit-depth \ + * [file-name] + * + * The color-type may be numeric (and must match the numbers used by the PNG + * specification) or one of the format names listed below. The bit-depth is the + * component bit depth, or the pixel bit-depth for a color-mapped image. + * + * Without any options no color-space information is written, with the options + * an sRGB or the appropriate gAMA chunk is written. "1.8" refers to the + * display system used on older Apple computers to correct for high ambient + * light levels in the viewing environment; it applies a transform of + * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909 + * is written (1.45/2.2). + * + * The image data is generated internally. Unless --color is given the images + * used are as follows: + * + * 1 channel: a square image with a diamond, the least luminous colors are on + * the edge of the image, the most luminous in the center. + * + * 2 channels: the color channel increases in luminosity from top to bottom, the + * alpha channel increases in opacity from left to right. + * + * 3 channels: linear combinations of, from the top-left corner clockwise, + * black, green, white, red. + * + * 4 channels: linear combinations of, from the top-left corner clockwise, + * transparent, red, green, blue. + * + * For color-mapped images a four channel color-map is used and the PNG file has + * a tRNS chunk, as follows: + * + * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white + * 2-bit: entry 0: transparent-green + * entry 1: 40%-red + * entry 2: 80%-blue + * entry 3: opaque-white + * 4-bit: the 16 combinations of the 2-bit case + * 8-bit: the 256 combinations of the 4-bit case + * + * The palette always has 2^bit-depth entries and the tRNS chunk one fewer. The + * image is the 1-channel diamond, but using palette index, not luminosity. + * + * Image size is determined by the final pixel depth in bits, i.e. channels x + * bit-depth, as follows: + * + * 8 bits or less: 64x64 + * 16 bits: 256x256 + * More than 16 bits: 1024x1024 + * + * Row filtering is turned off (the 'none' filter is used on every row) and the + * images are not interlaced. + * + * If --color is given then the whole image has that color, color-mapped images + * will have exactly one palette entry and all image files with be 16x16 in + * size. The color value is 1 to 4 decimal numbers as appropriate for the color + * type. + * + * If file-name is given then the PNG is written to that file, else it is + * written to stdout. Notice that stdout is not supported on systems where, by + * default, it assumes text output; this program makes no attempt to change the + * text mode of stdout! + */ +#define _ISOC99_SOURCE /* for strtoull */ + +#include /* for offsetof */ +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +/* This structure is used for inserting extra chunks (the --insert argument, not + * documented above.) + */ +typedef struct chunk_insert +{ + struct chunk_insert *next; + void (*insert)(png_structp, png_infop, int, png_charpp); + int nparams; + png_charp parameters[1]; +} chunk_insert; + +static int +channels_of_type(int color_type) +{ + if (color_type & PNG_COLOR_MASK_PALETTE) + return 1; + + else + { + int channels = 1; + + if (color_type & PNG_COLOR_MASK_COLOR) + channels = 3; + + if (color_type & PNG_COLOR_MASK_ALPHA) + return channels + 1; + + else + return channels; + } +} + +static int +pixel_depth_of_type(int color_type, int bit_depth) +{ + return channels_of_type(color_type) * bit_depth; +} + +static unsigned int +image_size_of_type(int color_type, int bit_depth, unsigned int *colors) +{ + if (*colors) + return 16; + + else + { + int pixel_depth = pixel_depth_of_type(color_type, bit_depth); + + if (pixel_depth < 8) + return 64; + + else if (pixel_depth > 16) + return 1024; + + else + return 256; + } +} + +static void +set_color(png_colorp color, png_bytep trans, unsigned int red, + unsigned int green, unsigned int blue, unsigned int alpha, + png_const_bytep gamma_table) +{ + color->red = gamma_table[red]; + color->green = gamma_table[green]; + color->blue = gamma_table[blue]; + *trans = (png_byte)alpha; +} + +static int +generate_palette(png_colorp palette, png_bytep trans, int bit_depth, + png_const_bytep gamma_table, unsigned int *colors) +{ + /* + * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white + * 2-bit: entry 0: transparent-green + * entry 1: 40%-red + * entry 2: 80%-blue + * entry 3: opaque-white + * 4-bit: the 16 combinations of the 2-bit case + * 8-bit: the 256 combinations of the 4-bit case + */ + switch (colors[0]) + { + default: + fprintf(stderr, "makepng: --colors=...: invalid count %u\n", + colors[0]); + exit(1); + + case 1: + set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255, + gamma_table); + return 1; + + case 2: + set_color(palette+0, trans+0, colors[1], colors[1], colors[1], + colors[2], gamma_table); + return 1; + + case 3: + set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255, + gamma_table); + return 1; + + case 4: + set_color(palette+0, trans+0, colors[1], colors[2], colors[3], + colors[4], gamma_table); + return 1; + + case 0: + if (bit_depth == 1) + { + set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table); + set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table); + return 2; + } + + else + { + unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */ + unsigned int x, y, ip; + + for (x=0; x> 3; + + if (offset < rowbytes && (bit_depth < 16 || offset+1 < rowbytes)) + { + row += offset; + + switch (bit_depth) + { + case 1: + case 2: + case 4: + /* Don't gamma correct - values get smashed */ + { + unsigned int shift = (8 - bit_depth) - (x & 0x7U); + + mask <<= shift; + value = (value << shift) & mask; + *row = (png_byte)((*row & ~mask) | value); + } + return; + + default: + fprintf(stderr, "makepng: bad bit depth (internal error)\n"); + exit(1); + + case 16: + value = (unsigned int)floor(65535*pow(value/65535.,conv)+.5); + *row++ = (png_byte)(value >> 8); + *row = (png_byte)value; + return; + + case 8: + *row = gamma_table[value]; + return; + } + } + + else + { + fprintf(stderr, "makepng: row buffer overflow (internal error)\n"); + exit(1); + } + } + + else + { + fprintf(stderr, "makepng: component overflow (internal error)\n"); + exit(1); + } +} + +static void +generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, + int bit_depth, png_const_bytep gamma_table, double conv, + unsigned int *colors) +{ + png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1; + png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */ + + if (colors[0] == 0) switch (channels_of_type(color_type)) + { + /* 1 channel: a square image with a diamond, the least luminous colors are on + * the edge of the image, the most luminous in the center. + */ + case 1: + { + png_uint_32 x; + png_uint_32 base = 2*size_max - abs(2*y-size_max); + + for (x=0; x<=size_max; ++x) + { + png_uint_32 luma = base - abs(2*x-size_max); + + /* 'luma' is now in the range 0..2*size_max, we need + * 0..depth_max + */ + luma = (luma*depth_max + size_max) / (2*size_max); + set_value(row, rowbytes, x, bit_depth, luma, gamma_table, conv); + } + } + break; + + /* 2 channels: the color channel increases in luminosity from top to bottom, + * the alpha channel increases in opacity from left to right. + */ + case 2: + { + png_uint_32 alpha = (depth_max * y * 2 + size_max) / (2 * size_max); + png_uint_32 x; + + for (x=0; x<=size_max; ++x) + { + set_value(row, rowbytes, 2*x, bit_depth, + (depth_max * x * 2 + size_max) / (2 * size_max), gamma_table, + conv); + set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table, + conv); + } + } + break; + + /* 3 channels: linear combinations of, from the top-left corner clockwise, + * black, green, white, red. + */ + case 3: + { + /* x0: the black->red scale (the value of the red component) at the + * start of the row (blue and green are 0). + * x1: the green->white scale (the value of the red and blue + * components at the end of the row; green is depth_max). + */ + png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); + png_uint_32 x; + + /* Interpolate x/depth_max from start to end: + * + * start end difference + * red: Y Y 0 + * green: 0 depth_max depth_max + * blue: 0 Y Y + */ + for (x=0; x<=size_max; ++x) + { + set_value(row, rowbytes, 3*x+0, bit_depth, /* red */ Y, + gamma_table, conv); + set_value(row, rowbytes, 3*x+1, bit_depth, /* green */ + (depth_max * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 3*x+2, bit_depth, /* blue */ + (Y * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + } + } + break; + + /* 4 channels: linear combinations of, from the top-left corner clockwise, + * transparent, red, green, blue. + */ + case 4: + { + /* x0: the transparent->blue scale (the value of the blue and alpha + * components) at the start of the row (red and green are 0). + * x1: the red->green scale (the value of the red and green + * components at the end of the row; blue is 0 and alpha is + * depth_max). + */ + png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); + png_uint_32 x; + + /* Interpolate x/depth_max from start to end: + * + * start end difference + * red: 0 depth_max-Y depth_max-Y + * green: 0 Y Y + * blue: Y 0 -Y + * alpha: Y depth_max depth_max-Y + */ + for (x=0; x<=size_max; ++x) + { + set_value(row, rowbytes, 4*x+0, bit_depth, /* red */ + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 4*x+1, bit_depth, /* green */ + (Y * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 4*x+2, bit_depth, /* blue */ + Y - (Y * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 4*x+3, bit_depth, /* alpha */ + Y + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + } + } + break; + + default: + fprintf(stderr, "makepng: internal bad channel count\n"); + exit(2); + } + + else if (color_type & PNG_COLOR_MASK_PALETTE) + { + /* Palette with fixed color: the image rows are all 0 and the image width + * is 16. + */ + memset(row, 0, rowbytes); + } + + else if (colors[0] == channels_of_type(color_type)) + switch (channels_of_type(color_type)) + { + case 1: + { + const png_uint_32 luma = colors[1]; + png_uint_32 x; + + for (x=0; x<=size_max; ++x) + set_value(row, rowbytes, x, bit_depth, luma, gamma_table, + conv); + } + break; + + case 2: + { + const png_uint_32 luma = colors[1]; + const png_uint_32 alpha = colors[2]; + png_uint_32 x; + + for (x=0; x 0 && gamma < 1000) + gamma = PNG_FP_1; + + if (gamma > 0) + real_gamma = gamma; + + { + unsigned int i; + + if (real_gamma == 45455) for (i=0; i<256; ++i) + { + gamma_table[i] = (png_byte)i; + conv = 1.; + } + + else + { + /* Convert 'i' from sRGB (45455) to real_gamma, this makes + * the images look the same regardless of the gAMA chunk. + */ + conv = real_gamma; + conv /= 45455; + + gamma_table[0] = 0; + + for (i=1; i<255; ++i) + gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + .5); + + gamma_table[255] = 255; + } + } + + png_set_IHDR(png_ptr, info_ptr, size, size, bit_depth, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if (color_type & PNG_COLOR_MASK_PALETTE) + { + int npalette; + png_color palette[256]; + png_byte trans[256]; + + npalette = generate_palette(palette, trans, bit_depth, gamma_table, + colors); + png_set_PLTE(png_ptr, info_ptr, palette, npalette); + png_set_tRNS(png_ptr, info_ptr, trans, npalette-1, + NULL/*transparent color*/); + + /* Reset gamma_table to prevent the image rows being changed */ + for (npalette=0; npalette<256; ++npalette) + gamma_table[npalette] = (png_byte)npalette; + } + + if (gamma == PNG_DEFAULT_sRGB) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); + + else if (gamma > 0) /* Else don't set color space information */ + { + png_set_gAMA_fixed(png_ptr, info_ptr, real_gamma); + + /* Just use the sRGB values here. */ + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + /* Insert extra information. */ + while (insert != NULL) + { + insert->insert(png_ptr, info_ptr, insert->nparams, insert->parameters); + insert = insert->next; + } + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Restrict the filters */ + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters); + + { + int passes = png_set_interlace_handling(png_ptr); + int pass; + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + row = malloc(rowbytes); + + if (row == NULL) + png_error(png_ptr, "OOM allocating row buffer"); + + for (pass = 0; pass < passes; ++pass) + { + unsigned int y; + + for (y=0; y 0) + { + /* Round up to a multiple of 4 here to allow an iCCP profile + * to be padded to a 4x boundary. + */ + png_bytep data = malloc((total+3)&~3); + + if (data != NULL) + { + size_t new_size = 0; + + for (;;) + { + ch = getc(fp); + if (ch == EOF) break; + data[new_size++] = (png_byte)ch; + } + + if (ferror(fp) || new_size != total) + { + perror("temporary file"); + fprintf(stderr, "temporary file read error\n"); + free(data); + } + + else + { + (void)fclose(fp); + *result = data; + return total; + } + } + + else + fprintf(stderr, "%s: out of memory loading file\n", name); + } + + else + fprintf(stderr, "%s: empty file\n", name); + } + } + } + + else + { + perror(name); + fprintf(stderr, "%s: open failed\n", name); + } + + fclose(fp); + } + + else + fprintf(stderr, "makepng: %s: could not open temporary file\n", name); + + exit(1); + return 0; +} + +static png_size_t +load_fake(png_charp param, png_bytepp profile) +{ + char *endptr = NULL; + unsigned long long int size = strtoull(param, &endptr, 0/*base*/); + + /* The 'fake' format is *[string] */ + if (endptr != NULL && *endptr == '*') + { + size_t len = strlen(++endptr); + size_t result = (size_t)size; + + if (len == 0) len = 1; /* capture the terminating '\0' */ + + /* Now repeat that string to fill 'size' bytes. */ + if (result == size && (*profile = malloc(result)) != NULL) + { + png_bytep out = *profile; + + if (len == 1) + memset(out, *endptr, result); + + else + { + while (size >= len) + { + memcpy(out, endptr, len); + out += len; + size -= len; + } + memcpy(out, endptr, size); + } + + return result; + } + + else + { + fprintf(stderr, "%s: size exceeds system limits\n", param); + exit(1); + } + } + + return 0; +} + +static void +check_param_count(int nparams, int expect) +{ + if (nparams != expect) + { + fprintf(stderr, "bad parameter count (internal error)\n"); + exit(1); + } +} + +static void +insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_bytep profile = NULL; + png_uint_32 proflen = 0; + int result; + + check_param_count(nparams, 2); + + switch (params[1][0]) + { + case '<': + { + png_size_t filelen = load_file(params[1]+1, &profile); + if (filelen > 0xfffffffc) /* Maximum profile length */ + { + fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n", + params[1]+1, (unsigned long)filelen); + exit(1); + } + + proflen = (png_uint_32)filelen; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + png_size_t fake_len = load_fake(params[1], &profile); + + if (fake_len > 0) /* else a simple parameter */ + { + if (fake_len > 0xffffffff) /* Maximum profile length */ + { + fprintf(stderr, + "%s: fake data too long (%lu) for an ICC profile\n", + params[1], (unsigned long)fake_len); + exit(1); + } + proflen = (png_uint_32)(fake_len & ~3U); + /* Always fix up the profile length. */ + png_save_uint_32(profile, proflen); + break; + } + } + + default: + fprintf(stderr, "--insert iCCP \"%s\": unrecognized\n", params[1]); + fprintf(stderr, " use '<' to read a file: \" 3) + { + png_uint_32 prof_header = png_get_uint_32(profile); + + if (prof_header != proflen) + { + fprintf(stderr, "--insert iCCP %s: profile length field wrong:\n", + params[1]); + fprintf(stderr, " actual %lu, recorded value %lu (corrected)\n", + (unsigned long)proflen, (unsigned long)prof_header); + png_save_uint_32(profile, proflen); + } + } + + if (result && profile != NULL && proflen >=4) + png_set_iCCP(png_ptr, info_ptr, params[0], PNG_COMPRESSION_TYPE_BASE, + profile, proflen); + + if (profile) + free(profile); + + if (!result) + exit(1); +} + +static void +clear_text(png_text *text, png_charp keyword) +{ + text->compression = -1; /* none */ + text->key = keyword; + text->text = NULL; + text->text_length = 0; /* libpng calculates this */ + text->itxt_length = 0; /* libpng calculates this */ + text->lang = NULL; + text->lang_key = NULL; +} + +static void +set_text(png_structp png_ptr, png_infop info_ptr, png_textp text, + png_charp param) +{ + switch (param[0]) + { + case '<': + { + png_bytep file = NULL; + + text->text_length = load_file(param+1, &file); + text->text = (png_charp)file; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + png_bytep data = NULL; + png_size_t fake_len = load_fake(param, &data); + + if (fake_len > 0) /* else a simple parameter */ + { + text->text_length = fake_len; + text->text = (png_charp)data; + break; + } + } + + default: + text->text = param; + break; + } + + png_set_text(png_ptr, info_ptr, text, 1); + + if (text->text != param) + free(text->text); +} + +static void +insert_tEXt(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_text text; + + check_param_count(nparams, 2); + clear_text(&text, params[0]); + set_text(png_ptr, info_ptr, &text, params[1]); +} + +static void +insert_zTXt(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_text text; + + check_param_count(nparams, 2); + clear_text(&text, params[0]); + text.compression = 0; /* deflate */ + set_text(png_ptr, info_ptr, &text, params[1]); +} + +static void +insert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_text text; + + check_param_count(nparams, 4); + clear_text(&text, params[0]); + text.compression = 2; /* iTXt + deflate */ + text.lang = params[1];/* language tag */ + text.lang_key = params[2]; /* translated keyword */ + set_text(png_ptr, info_ptr, &text, params[3]); +} + +static void +insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params) +{ + int i; + png_uint_16 freq[256]; + + /* libpng takes the count from the PLTE count; we don't check it here but we + * do set the array to 0 for unspecified entries. + */ + memset(freq, 0, sizeof freq); + for (i=0; inext = NULL; + cip->insert = insert; + cip->nparams = nparams; + for (i=0; iparameters[i] = list[i]; + + return cip; +} + +static chunk_insert * +find_insert(png_const_charp what, png_charp param) +{ + png_uint_32 chunk = 0; + png_charp parameter_list[1024]; + int i, nparams; + + /* Assemble the chunk name */ + for (i=0; i<4; ++i) + { + char ch = what[i]; + + if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) + chunk = (chunk << 8) + what[i]; + + else + break; + } + + if (i < 4 || what[4] != 0) + { + fprintf(stderr, "makepng --insert \"%s\": invalid chunk name\n", what); + exit(1); + } + + /* Assemble the parameter list. */ + nparams = find_parameters(what, param, parameter_list, 1024); + +# define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) + + switch (chunk) + { + case CHUNK(105,67,67,80): /* iCCP */ + if (nparams == 2) + return make_insert(what, insert_iCCP, nparams, parameter_list); + break; + + case CHUNK(116,69,88,116): /* tEXt */ + if (nparams == 2) + return make_insert(what, insert_tEXt, nparams, parameter_list); + break; + + case CHUNK(122,84,88,116): /* zTXt */ + if (nparams == 2) + return make_insert(what, insert_zTXt, nparams, parameter_list); + break; + + case CHUNK(105,84,88,116): /* iTXt */ + if (nparams == 4) + return make_insert(what, insert_iTXt, nparams, parameter_list); + break; + + case CHUNK(104,73,83,84): /* hIST */ + if (nparams <= 256) + return make_insert(what, insert_hIST, nparams, parameter_list); + break; + +#if 0 + case CHUNK(115,80,76,84): /* sPLT */ + return make_insert(what, insert_sPLT, nparams, parameter_list); +#endif + + default: + fprintf(stderr, "makepng --insert \"%s\": unrecognized chunk name\n", + what); + exit(1); + } + + bad_parameter_count(what, nparams); + return NULL; +} + +/* This is a not-very-good parser for a sequence of numbers (including 0). It + * doesn't accept some apparently valid things, but it accepts all the sensible + * combinations. + */ +static void +parse_color(char *arg, unsigned int *colors) +{ + unsigned int ncolors = 0; + + while (*arg && ncolors < 4) + { + char *ep = arg; + + unsigned long ul = strtoul(arg, &ep, 0); + + if (ul > 65535) + { + fprintf(stderr, "makepng --color=...'%s': too big\n", arg); + exit(1); + } + + if (ep == arg) + { + fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg); + exit(1); + } + + if (*ep) ++ep; /* skip a separator */ + arg = ep; + + colors[++ncolors] = (unsigned int)ul; /* checked above */ + } + + if (*arg) + { + fprintf(stderr, "makepng --color=...'%s': too many values\n", arg); + exit(1); + } + + *colors = ncolors; +} + +int +main(int argc, char **argv) +{ + FILE *fp = stdout; + const char *file_name = NULL; + int color_type = 8; /* invalid */ + int bit_depth = 32; /* invalid */ + unsigned int colors[5]; + unsigned int filters = PNG_ALL_FILTERS; + png_fixed_point gamma = 0; /* not set */ + chunk_insert *head_insert = NULL; + chunk_insert **insert_ptr = &head_insert; + + memset(colors, 0, sizeof colors); + + while (--argc > 0) + { + char *arg = *++argv; + + if (strcmp(arg, "--sRGB") == 0) + { + gamma = PNG_DEFAULT_sRGB; + continue; + } + + if (strcmp(arg, "--linear") == 0) + { + gamma = PNG_FP_1; + continue; + } + + if (strcmp(arg, "--1.8") == 0) + { + gamma = PNG_GAMMA_MAC_18; + continue; + } + + if (strcmp(arg, "--nofilters") == 0) + { + filters = PNG_FILTER_NONE; + continue; + } + + if (strncmp(arg, "--color=", 8) == 0) + { + parse_color(arg+8, colors); + continue; + } + + if (argc >= 3 && strcmp(arg, "--insert") == 0) + { + png_const_charp what = *++argv; + png_charp param = *++argv; + chunk_insert *new_insert; + + argc -= 2; + + new_insert = find_insert(what, param); + + if (new_insert != NULL) + { + *insert_ptr = new_insert; + insert_ptr = &new_insert->next; + } + + continue; + } + + if (arg[0] == '-') + { + fprintf(stderr, "makepng: %s: invalid option\n", arg); + exit(1); + } + + if (strcmp(arg, "palette") == 0) + { + color_type = PNG_COLOR_TYPE_PALETTE; + continue; + } + + if (strncmp(arg, "gray", 4) == 0) + { + if (arg[4] == 0) + { + color_type = PNG_COLOR_TYPE_GRAY; + continue; + } + + else if (strcmp(arg+4, "a") == 0 || + strcmp(arg+4, "alpha") == 0 || + strcmp(arg+4, "-alpha") == 0) + { + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + continue; + } + } + + if (strncmp(arg, "rgb", 3) == 0) + { + if (arg[3] == 0) + { + color_type = PNG_COLOR_TYPE_RGB; + continue; + } + + else if (strcmp(arg+3, "a") == 0 || + strcmp(arg+3, "alpha") == 0 || + strcmp(arg+3, "-alpha") == 0) + { + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + continue; + } + } + + if (color_type == 8 && isdigit(arg[0])) + { + color_type = atoi(arg); + if (color_type < 0 || color_type > 6 || color_type == 1 || + color_type == 5) + { + fprintf(stderr, "makepng: %s: not a valid color type\n", arg); + exit(1); + } + + continue; + } + + if (bit_depth == 32 && isdigit(arg[0])) + { + bit_depth = atoi(arg); + if (bit_depth <= 0 || bit_depth > 16 || + (bit_depth & -bit_depth) != bit_depth) + { + fprintf(stderr, "makepng: %s: not a valid bit depth\n", arg); + exit(1); + } + + continue; + } + + if (argc == 1) /* It's the file name */ + { + fp = fopen(arg, "wb"); + if (fp == NULL) + { + fprintf(stderr, "%s: %s: could not open\n", arg, strerror(errno)); + exit(1); + } + + file_name = arg; + continue; + } + + fprintf(stderr, "makepng: %s: unknown argument\n", arg); + exit(1); + } /* argument while loop */ + + if (color_type == 8 || bit_depth == 32) + { + fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] " + "[--color=...] color-type bit-depth [file-name]\n" + " Make a test PNG file, by default writes to stdout.\n"); + exit(1); + } + + /* Check the colors */ + { + const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U : + (1U< lim) + { + fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n", + colors[i], lim); + exit(1); + } + } + + /* Restrict the filters for more speed to those we know are used for the + * generated images. + */ + if (filters == PNG_ALL_FILTERS) + { + if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8) + filters = PNG_FILTER_NONE; + + else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */ + { + if (bit_depth == 8) + filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG); + + else + filters = PNG_FILTER_SUB | PNG_FILTER_PAETH; + } + + else /* gray 8 or 16-bit */ + filters &= ~PNG_FILTER_NONE; + } + + { + int ret = write_png(&file_name, fp, color_type, bit_depth, gamma, + head_insert, filters, colors); + + if (ret != 0 && file_name != NULL) + remove(file_name); + + return ret; + } +} diff --git a/main/source/includes/lpng1610/contrib/libtests/pngimage.c b/main/source/includes/lpng1610/contrib/libtests/pngimage.c index be3ce824..372845ea 100644 --- a/main/source/includes/lpng1610/contrib/libtests/pngimage.c +++ b/main/source/includes/lpng1610/contrib/libtests/pngimage.c @@ -1,1618 +1,1618 @@ -/* pngimage.c - * - * Copyright (c) 2014 John Cunningham Bowler - * - * Last changed in libpng 1.6.10 [March 6, 2014] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * Test the png_read_png and png_write_png interfaces. Given a PNG file load it - * using png_read_png and then write with png_write_png. Test all possible - * transforms. - */ -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include -#endif - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include -#else -# include "../../png.h" -#endif - -#ifndef PNG_SETJMP_SUPPORTED -# include /* because png.h did *not* include this */ -#endif - -#if defined(PNG_INFO_IMAGE_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED) -/* If a transform is valid on both read and write this implies that if the - * transform is applied to read it must also be applied on write to produce - * meaningful data. This is because these transforms when performed on read - * produce data with a memory format that does not correspond to a PNG format. - * - * Most of these transforms are invertible; after applying the transform on - * write the result is the original PNG data that would have would have been - * read if no transform were applied. - * - * The exception is _SHIFT, which destroys the low order bits marked as not - * significant in a PNG with the sBIT chunk. - * - * The following table lists, for each transform, the conditions under which it - * is expected to do anything. Conditions are defined as follows: - * - * 1) Color mask bits required - simply a mask to AND with color_type; one of - * these must be present for the transform to fire, except that 0 means - * 'always'. - * 2) Color mask bits which must be absent - another mask - none of these must - * be present. - * 3) Bit depths - a mask of component bit depths for the transform to fire. - * 4) 'read' - the transform works in png_read_png. - * 5) 'write' - the transform works in png_write_png. - * 6) PNG_INFO_chunk; a mask of the chunks that must be present for the - * transform to fire. All must be present - the requirement is that - * png_get_valid() & mask == mask, so if mask is 0 there is no requirement. - * - * The condition refers to the original image state - if multiple transforms are - * used together it is possible to cause a transform that wouldn't fire on the - * original image to fire. - */ -static struct transform_info -{ - const char *name; - int transform; - png_uint_32 valid_chunks; -# define CHUNK_NONE 0 -# define CHUNK_sBIT PNG_INFO_sBIT -# define CHUNK_tRNS PNG_INFO_tRNS - png_byte color_mask_required; - png_byte color_mask_absent; -# define COLOR_MASK_X 0 -# define COLOR_MASK_P PNG_COLOR_MASK_PALETTE -# define COLOR_MASK_C PNG_COLOR_MASK_COLOR -# define COLOR_MASK_A PNG_COLOR_MASK_ALPHA -# define COLOR_MASK_ALL (PALETTE+COLOR+ALPHA) /* absent = gray, no alpha */ - png_byte bit_depths; -# define BD_ALL (1 + 2 + 4 + 8 + 16) -# define BD_PAL (1 + 2 + 4 + 8) -# define BD_LOW (1 + 2 + 4) -# define BD_16 16 -# define BD_TRUE (8+16) /* i.e. true-color depths */ - png_byte when; -# define TRANSFORM_R 1 -# define TRANSFORM_W 2 -# define TRANSFORM_RW 3 - png_byte tested; /* the transform was tested somewhere */ -} transform_info[] = -{ - /* List ALL the PNG_TRANSFORM_ macros here. Check for support using the READ - * macros; even if the transform is supported on write it cannot be tested - * without the read support. - */ -# define T(name,chunk,cm_required,cm_absent,bd,when)\ - { #name, PNG_TRANSFORM_ ## name, CHUNK_ ## chunk,\ - COLOR_MASK_ ## cm_required, COLOR_MASK_ ## cm_absent, BD_ ## bd,\ - TRANSFORM_ ## when, 0/*!tested*/ } - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - T(STRIP_16, NONE, X, X, 16, R), - /* drops the bottom 8 bits when bit depth is 16 */ -#endif -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - T(STRIP_ALPHA, NONE, A, X, ALL, R), - /* removes the alpha channel if present */ -#endif -#ifdef PNG_WRITE_PACK_SUPPORTED -# define TRANSFORM_RW_PACK TRANSFORM_RW -#else -# define TRANSFORM_RW_PACK TRANSFORM_R -#endif -#ifdef PNG_READ_PACK_SUPPORTED - T(PACKING, NONE, X, X, LOW, RW_PACK), - /* unpacks low-bit-depth components into 1 byte per component on read, - * reverses this on write. - */ -#endif -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED -# define TRANSFORM_RW_PACKSWAP TRANSFORM_RW -#else -# define TRANSFORM_RW_PACKSWAP TRANSFORM_R -#endif -#ifdef PNG_READ_PACKSWAP_SUPPORTED - T(PACKSWAP, NONE, X, X, LOW, RW_PACKSWAP), - /* reverses the order of low-bit-depth components packed into a byte */ -#endif -#ifdef PNG_READ_EXPAND_SUPPORTED - T(EXPAND, NONE, P, X, ALL, R), - /* expands PLTE PNG files to RGB (no tRNS) or RGBA (tRNS) * - * Note that the 'EXPAND' transform does lots of different things: */ - T(EXPAND, NONE, X, C, ALL, R), - /* expands grayscale PNG files to RGB, or RGBA */ - T(EXPAND, tRNS, X, A, ALL, R), - /* expands the tRNS chunk in files without alpha */ -#endif -#ifdef PNG_WRITE_INVERT_SUPPORTED -# define TRANSFORM_RW_INVERT TRANSFORM_RW -#else -# define TRANSFORM_RW_INVERT TRANSFORM_R -#endif -#ifdef PNG_READ_INVERT_SUPPORTED - T(INVERT_MONO, NONE, X, C, ALL, RW_INVERT), - /* converts gray-scale components to 1..0 from 0..1 */ -#endif -#ifdef PNG_WRITE_SHIFT_SUPPORTED -# define TRANSFORM_RW_SHIFT TRANSFORM_RW -#else -# define TRANSFORM_RW_SHIFT TRANSFORM_R -#endif -#ifdef PNG_READ_SHIFT_SUPPORTED - T(SHIFT, sBIT, X, X, ALL, RW_SHIFT), - /* reduces component values to the original range based on the sBIT chunk, - * this is only partially reversible - the low bits are lost and cannot be - * recovered on write. In fact write code replicates the bits to generate - * new low-order bits. - */ -#endif -#ifdef PNG_WRITE_BGR_SUPPORTED -# define TRANSFORM_RW_BGR TRANSFORM_RW -#else -# define TRANSFORM_RW_BGR TRANSFORM_R -#endif -#ifdef PNG_READ_BGR_SUPPORTED - T(BGR, NONE, C, P, TRUE, RW_BGR), - /* reverses the rgb component values of true-color pixels */ -#endif -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -# define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_RW -#else -# define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_R -#endif -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - T(SWAP_ALPHA, NONE, A, X, TRUE, RW_SWAP_ALPHA), - /* swaps the alpha channel of RGBA or GA pixels to the front - ARGB or - * AG, on write reverses the process. - */ -#endif -#ifdef PNG_WRITE_SWAP_SUPPORTED -# define TRANSFORM_RW_SWAP TRANSFORM_RW -#else -# define TRANSFORM_RW_SWAP TRANSFORM_R -#endif -#ifdef PNG_READ_SWAP_SUPPORTED - T(SWAP_ENDIAN, NONE, X, P, 16, RW_SWAP), - /* byte-swaps 16-bit component values */ -#endif -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -# define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_RW -#else -# define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_R -#endif -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - T(INVERT_ALPHA, NONE, A, X, TRUE, RW_INVERT_ALPHA), - /* converts an alpha channel from 0..1 to 1..0 */ -#endif -#ifdef PNG_WRITE_FILLER_SUPPORTED - T(STRIP_FILLER_BEFORE, NONE, A, P, TRUE, W), /* 'A' for a filler! */ - /* on write skips a leading filler channel; testing requires data with a - * filler channel so this is produced from RGBA or GA images by removing - * the 'alpha' flag from the color type in place. - */ - T(STRIP_FILLER_AFTER, NONE, A, P, TRUE, W), - /* on write strips a trailing filler channel */ -#endif -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - T(GRAY_TO_RGB, NONE, X, C, ALL, R), - /* expands grayscale images to RGB, also causes the palette part of - * 'EXPAND' to happen. Low bit depth grayscale images are expanded to - * 8-bits per component and no attempt is made to convert the image to a - * palette image. While this transform is partially reversible - * png_write_png does not currently support this. - */ - T(GRAY_TO_RGB, NONE, P, X, ALL, R), - /* The 'palette' side effect mentioned above; a bit bogus but this is the - * way the libpng code works. - */ -#endif -#ifdef PNG_READ_EXPAND_16_SUPPORTED - T(EXPAND_16, NONE, X, X, PAL, R), - /* expands images to 16-bits per component, as a side effect expands - * palette images to RGB and expands the tRNS chunk if present, so it can - * modify 16-bit per component images as well: - */ - T(EXPAND_16, tRNS, X, A, 16, R), - /* side effect of EXPAND_16 - expands the tRNS chunk in an RGB or G 16-bit - * image. - */ -#endif -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - T(SCALE_16, NONE, X, X, 16, R) - /* scales 16-bit components to 8-bits. */ -#endif - -#undef T -}; - -#define ARRAY_SIZE(a) ((sizeof a)/(sizeof a[0])) -#define TTABLE_SIZE ARRAY_SIZE(transform_info) - -/* Some combinations of options that should be reversible are not; these cases - * are bugs. - */ -static int known_bad_combos[][2] = -{ - /* problem, antidote */ - { PNG_TRANSFORM_SHIFT | PNG_TRANSFORM_INVERT_ALPHA, 0/*antidote*/ } -}; - -static int -is_combo(int transforms) -{ - return transforms & (transforms-1); /* non-zero if more than one set bit */ -} - -static int -first_transform(int transforms) -{ - return transforms & -transforms; /* lowest set bit */ -} - -static int -is_bad_combo(int transforms) -{ - unsigned int i; - - for (i=0; ifirst.next = NULL; - buffer->last = NULL; - buffer->current = NULL; -} - -#ifdef PNG_WRITE_SUPPORTED -static void -buffer_start_write(struct buffer *buffer) -{ - buffer->last = &buffer->first; - buffer->end_count = 0; - buffer->current = NULL; -} -#endif - -static void -buffer_start_read(struct buffer *buffer) -{ - buffer->current = &buffer->first; - buffer->read_count = 0; -} - -#ifdef ENOMEM /* required by POSIX 1003.1 */ -# define MEMORY ENOMEM -#else -# define MEMORY ERANGE /* required by ANSI-C */ -#endif -static struct buffer * -get_buffer(png_structp pp) - /* Used from libpng callbacks to get the current buffer */ -{ - return (struct buffer*)png_get_io_ptr(pp); -} - -#define NEW(type) ((type *)malloc(sizeof (type))) - -static struct buffer_list * -buffer_extend(struct buffer_list *current) -{ - struct buffer_list *add; - - assert(current->next == NULL); - - add = NEW(struct buffer_list); - if (add == NULL) - return NULL; - - add->next = NULL; - current->next = add; - - return add; -} - -/* Load a buffer from a file; does the equivalent of buffer_start_write. On a - * read error returns an errno value, else returns 0. - */ -static int -buffer_from_file(struct buffer *buffer, FILE *fp) -{ - struct buffer_list *last = &buffer->first; - size_t count = 0; - - for (;;) - { - size_t r = fread(last->buffer+count, 1/*size*/, - (sizeof last->buffer)-count, fp); - - if (r > 0) - { - count += r; - - if (count >= sizeof last->buffer) - { - assert(count == sizeof last->buffer); - count = 0; - - if (last->next == NULL) - { - last = buffer_extend(last); - if (last == NULL) - return MEMORY; - } - - else - last = last->next; - } - } - - else /* fread failed - probably end of file */ - { - if (feof(fp)) - { - buffer->last = last; - buffer->end_count = count; - return 0; /* no error */ - } - - /* Some kind of funky error; errno should be non-zero */ - return errno == 0 ? ERANGE : errno; - } - } -} - -/* This structure is used to control the test of a single file. */ -typedef enum -{ - VERBOSE, /* switches on all messages */ - INFORMATION, - WARNINGS, /* switches on warnings */ - LIBPNG_WARNING, - APP_WARNING, - ERRORS, /* just errors */ - APP_FAIL, /* continuable error - no need to longjmp */ - LIBPNG_ERROR, /* this and higher cause a longjmp */ - LIBPNG_BUG, /* erroneous behavior in libpng */ - APP_ERROR, /* such as out-of-memory in a callback */ - QUIET, /* no normal messages */ - USER_ERROR, /* such as file-not-found */ - INTERNAL_ERROR -} error_level; -#define LEVEL_MASK 0xf /* where the level is in 'options' */ - -#define EXHAUSTIVE 0x010 /* Test all combinations of active options */ -#define STRICT 0x020 /* Fail on warnings as well as errors */ -#define LOG 0x040 /* Log pass/fail to stdout */ -#define CONTINUE 0x080 /* Continue on APP_FAIL errors */ -#define SKIP_BUGS 0x100 /* Skip over known bugs */ -#define LOG_SKIPPED 0x200 /* Log skipped bugs */ -#define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */ - -/* Result masks apply to the result bits in the 'results' field below; these - * bits are simple 1U<options = WARNINGS; /* default to !verbose, !quiet */ - dp->filename = NULL; - dp->operation = NULL; - dp->original_pp = NULL; - dp->original_ip = NULL; - dp->original_rows = NULL; - dp->read_pp = NULL; - dp->read_ip = NULL; - buffer_init(&dp->original_file); - -# ifdef PNG_WRITE_SUPPORTED - dp->write_pp = NULL; - buffer_init(&dp->written_file); -# endif -} - -static void -display_clean_read(struct display *dp) -{ - if (dp->read_pp != NULL) - png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL); -} - -#ifdef PNG_WRITE_SUPPORTED -static void -display_clean_write(struct display *dp) -{ - if (dp->write_pp != NULL) - png_destroy_write_struct(&dp->write_pp, NULL); -} -#endif - -static void -display_clean(struct display *dp) -{ -# ifdef PNG_WRITE_SUPPORTED - display_clean_write(dp); -# endif - display_clean_read(dp); - - dp->original_rowbytes = 0; - dp->original_rows = NULL; - dp->chunks = 0; - - png_destroy_read_struct(&dp->original_pp, &dp->original_ip, NULL); - /* leave the filename for error detection */ - dp->results = 0; /* reset for next time */ -} - -static struct display * -get_dp(png_structp pp) - /* The display pointer is always stored in the png_struct error pointer */ -{ - struct display *dp = (struct display*)png_get_error_ptr(pp); - - if (dp == NULL) - { - fprintf(stderr, "pngimage: internal error (no display)\n"); - exit(99); /* prevents a crash */ - } - - return dp; -} - -/* error handling */ -#ifdef __GNUC__ -# define VGATTR __attribute__((__format__ (__printf__,3,4))) - /* Required to quiet GNUC warnings when the compiler sees a stdarg function - * that calls one of the stdio v APIs. - */ -#else -# define VGATTR -#endif -static void VGATTR -display_log(struct display *dp, error_level level, const char *fmt, ...) - /* 'level' is as above, fmt is a stdio style format string. This routine - * does not return if level is above LIBPNG_WARNING - */ -{ - dp->results |= 1U << level; - - if (level > (error_level)(dp->options & LEVEL_MASK)) - { - const char *lp; - va_list ap; - - switch (level) - { - case INFORMATION: lp = "information"; break; - case LIBPNG_WARNING: lp = "warning(libpng)"; break; - case APP_WARNING: lp = "warning(pngimage)"; break; - case APP_FAIL: lp = "error(continuable)"; break; - case LIBPNG_ERROR: lp = "error(libpng)"; break; - case LIBPNG_BUG: lp = "bug(libpng)"; break; - case APP_ERROR: lp = "error(pngimage)"; break; - case USER_ERROR: lp = "error(user)"; break; - - case INTERNAL_ERROR: /* anything unexpected is an internal error: */ - case VERBOSE: case WARNINGS: case ERRORS: case QUIET: - default: lp = "bug(pngimage)"; break; - } - - fprintf(stderr, "%s: %s: %s", - dp->filename != NULL ? dp->filename : "", lp, dp->operation); - - if (dp->transforms != 0) - { - int tr = dp->transforms; - - if (is_combo(tr)) - fprintf(stderr, "(0x%x)", tr); - - else - fprintf(stderr, "(%s)", transform_name(tr)); - } - - fprintf(stderr, ": "); - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - fputc('\n', stderr); - } - /* else do not output any message */ - - /* Errors cause this routine to exit to the fail code */ - if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE))) - longjmp(dp->error_return, level); -} - -/* error handler callbacks for libpng */ -static void PNGCBAPI -display_warning(png_structp pp, png_const_charp warning) -{ - display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning); -} - -static void PNGCBAPI -display_error(png_structp pp, png_const_charp error) -{ - struct display *dp = get_dp(pp); - - display_log(dp, LIBPNG_ERROR, "%s", error); -} - -static void -display_cache_file(struct display *dp, const char *filename) - /* Does the initial cache of the file. */ -{ - FILE *fp; - int ret; - - dp->filename = filename; - - if (filename != NULL) - { - fp = fopen(filename, "rb"); - if (fp == NULL) - display_log(dp, USER_ERROR, "open failed: %s", strerror(errno)); - } - - else - fp = stdin; - - ret = buffer_from_file(&dp->original_file, fp); - - fclose(fp); - - if (ret != 0) - display_log(dp, APP_ERROR, "read failed: %s", strerror(ret)); -} - -static void -buffer_read(struct display *dp, struct buffer *bp, png_bytep data, - png_size_t size) -{ - struct buffer_list *last = bp->current; - size_t read_count = bp->read_count; - - while (size > 0) - { - size_t avail; - - if (last == NULL || - (last == bp->last && read_count >= bp->end_count)) - { - display_log(dp, USER_ERROR, "file truncated (%lu bytes)", - (unsigned long)size); - /*NOTREACHED*/ - break; - } - - else if (read_count >= sizeof last->buffer) - { - /* Move to the next buffer: */ - last = last->next; - read_count = 0; - bp->current = last; /* Avoid update outside the loop */ - - /* And do a sanity check (the EOF case is caught above) */ - if (last == NULL) - { - display_log(dp, INTERNAL_ERROR, "damaged buffer list"); - /*NOTREACHED*/ - break; - } - } - - avail = (sizeof last->buffer) - read_count; - if (avail > size) - avail = size; - - memcpy(data, last->buffer + read_count, avail); - read_count += avail; - size -= avail; - data += avail; - } - - bp->read_count = read_count; -} - -static void PNGCBAPI -read_function(png_structp pp, png_bytep data, png_size_t size) -{ - buffer_read(get_dp(pp), get_buffer(pp), data, size); -} - -static void -read_png(struct display *dp, struct buffer *bp, const char *operation, - int transforms) -{ - png_structp pp; - png_infop ip; - - /* This cleans out any previous read and sets operation and transforms to - * empty. - */ - display_clean_read(dp); - - if (operation != NULL) /* else this is a verify and do not overwrite info */ - { - dp->operation = operation; - dp->transforms = transforms; - } - - dp->read_pp = pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp, - display_error, display_warning); - if (pp == NULL) - display_log(dp, LIBPNG_ERROR, "failed to create read struct"); - - /* The png_read_png API requires us to make the info struct, but it does the - * call to png_read_info. - */ - dp->read_ip = ip = png_create_info_struct(pp); - if (ip == NULL) - display_log(dp, LIBPNG_ERROR, "failed to create info struct"); - -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - /* Remove the user limits, if any */ - png_set_user_limits(pp, 0x7fffffff, 0x7fffffff); -# endif - - /* Set the IO handling */ - buffer_start_read(bp); - png_set_read_fn(pp, bp, read_function); - - png_read_png(pp, ip, transforms, NULL/*params*/); - -#if 0 /* crazy debugging */ - { - png_bytep pr = png_get_rows(pp, ip)[0]; - size_t rb = png_get_rowbytes(pp, ip); - size_t cb; - char c = ' '; - - fprintf(stderr, "%.4x %2d (%3lu bytes):", transforms, png_get_bit_depth(pp,ip), (unsigned long)rb); - - for (cb=0; cboriginal_file, "original read", 0/*no transform*/); - - /* Move the result to the 'original' fields */ - dp->original_pp = pp = dp->read_pp, dp->read_pp = NULL; - dp->original_ip = ip = dp->read_ip, dp->read_ip = NULL; - - dp->original_rowbytes = png_get_rowbytes(pp, ip); - if (dp->original_rowbytes == 0) - display_log(dp, LIBPNG_BUG, "png_get_rowbytes returned 0"); - - dp->chunks = png_get_valid(pp, ip, 0xffffffff); - if ((dp->chunks & PNG_INFO_IDAT) == 0) /* set by png_read_png */ - display_log(dp, LIBPNG_BUG, "png_read_png did not set IDAT flag"); - - dp->original_rows = png_get_rows(pp, ip); - if (dp->original_rows == NULL) - display_log(dp, LIBPNG_BUG, "png_read_png did not create row buffers"); - - if (!png_get_IHDR(pp, ip, - &dp->width, &dp->height, &dp->bit_depth, &dp->color_type, - &dp->interlace_method, &dp->compression_method, &dp->filter_method)) - display_log(dp, LIBPNG_BUG, "png_get_IHDR failed"); - - /* 'active' transforms are discovered based on the original image format; - * running one active transform can activate others. At present the code - * does not attempt to determine the closure. - */ - { - png_uint_32 chunks = dp->chunks; - int active = 0, inactive = 0; - int ct = dp->color_type; - int bd = dp->bit_depth; - unsigned int i; - - for (i=0; iactive_transforms = active; - dp->ignored_transforms = inactive; /* excluding write-only transforms */ - - if (active == 0) - display_log(dp, INTERNAL_ERROR, "bad transform table"); - } -} - -static int -compare_read(struct display *dp, int applied_transforms) -{ - /* Compare the png_info from read_ip with original_info */ - size_t rowbytes; - png_uint_32 width, height; - int bit_depth, color_type; - int interlace_method, compression_method, filter_method; - const char *e = NULL; - - png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth, - &color_type, &interlace_method, &compression_method, &filter_method); - -# define C(item) if (item != dp->item) \ - display_log(dp, APP_WARNING, "IHDR " #item "(%lu) changed to %lu",\ - (unsigned long)dp->item, (unsigned long)item), e = #item - - /* The IHDR should be identical: */ - C(width); - C(height); - C(bit_depth); - C(color_type); - C(interlace_method); - C(compression_method); - C(filter_method); - - /* 'e' remains set to the name of the last thing changed: */ - if (e) - display_log(dp, APP_ERROR, "IHDR changed (%s)", e); - - /* All the chunks from the original PNG should be preserved in the output PNG - * because the PNG format has not been changed. - */ - { - unsigned long chunks = - png_get_valid(dp->read_pp, dp->read_ip, 0xffffffff); - - if (chunks != dp->chunks) - display_log(dp, APP_FAIL, "PNG chunks changed from 0x%lx to 0x%lx", - (unsigned long)dp->chunks, chunks); - } - - /* rowbytes should be the same */ - rowbytes = png_get_rowbytes(dp->read_pp, dp->read_ip); - - /* NOTE: on 64-bit systems this may trash the top bits of rowbytes, - * which could lead to weird error messages. - */ - if (rowbytes != dp->original_rowbytes) - display_log(dp, APP_ERROR, "PNG rowbytes changed from %lu to %lu", - (unsigned long)dp->original_rowbytes, (unsigned long)rowbytes); - - /* The rows should be the same too, unless the applied transforms includes - * the shift transform, in which case low bits may have been lost. - */ - { - png_bytepp rows = png_get_rows(dp->read_pp, dp->read_ip); - unsigned int mask; /* mask (if not zero) for the final byte */ - - if (bit_depth < 8) - { - /* Need the stray bits at the end, this depends only on the low bits - * of the image width; overflow does not matter. If the width is an - * exact multiple of 8 bits this gives a mask of 0, not 0xff. - */ - mask = 0xff & (0xff00 >> ((bit_depth * width) & 7)); - } - - else - mask = 0; - - if (rows == NULL) - display_log(dp, LIBPNG_BUG, "png_get_rows returned NULL"); - - if ((applied_transforms & PNG_TRANSFORM_SHIFT) == 0 || - (dp->active_transforms & PNG_TRANSFORM_SHIFT) == 0 || - color_type == PNG_COLOR_TYPE_PALETTE) - { - unsigned long y; - - for (y=0; yoriginal_rows[y]; - - if (memcmp(row, orig, rowbytes-(mask != 0)) != 0 || (mask != 0 && - ((row[rowbytes-1] & mask) != (orig[rowbytes-1] & mask)))) - { - size_t x; - - /* Find the first error */ - for (x=0; x 0x%.2x", - (unsigned long)x, (unsigned long)y, orig[x], row[x]); - return 0; /* don't keep reporting failed rows on 'continue' */ - } - } - } - - else - { - unsigned long y; - int bpp; /* bits-per-pixel then bytes-per-pixel */ - /* components are up to 8 bytes in size */ - png_byte sig_bits[8]; - png_color_8p sBIT; - - if (png_get_sBIT(dp->read_pp, dp->read_ip, &sBIT) != PNG_INFO_sBIT) - display_log(dp, INTERNAL_ERROR, - "active shift transform but no sBIT in file"); - - switch (color_type) - { - case PNG_COLOR_TYPE_GRAY: - sig_bits[0] = sBIT->gray; - bpp = bit_depth; - break; - - case PNG_COLOR_TYPE_GA: - sig_bits[0] = sBIT->gray; - sig_bits[1] = sBIT->alpha; - bpp = 2 * bit_depth; - break; - - case PNG_COLOR_TYPE_RGB: - sig_bits[0] = sBIT->red; - sig_bits[1] = sBIT->green; - sig_bits[2] = sBIT->blue; - bpp = 3 * bit_depth; - break; - - case PNG_COLOR_TYPE_RGBA: - sig_bits[0] = sBIT->red; - sig_bits[1] = sBIT->green; - sig_bits[2] = sBIT->blue; - sig_bits[3] = sBIT->alpha; - bpp = 4 * bit_depth; - break; - - default: - display_log(dp, LIBPNG_ERROR, "invalid colour type %d", - color_type); - /*NOTREACHED*/ - bpp = 0; - break; - } - - { - int b; - - for (b=0; 8*b bit_depth/*!palette*/) - display_log(dp, LIBPNG_BUG, - "invalid sBIT[%u] value %d returned for PNG bit depth %d", - b, sig_bits[b], bit_depth); - } - } - - if (bpp < 8 && bpp != bit_depth) - { - /* sanity check; this is a grayscale PNG; something is wrong in the - * code above. - */ - display_log(dp, INTERNAL_ERROR, "invalid bpp %u for bit_depth %u", - bpp, bit_depth); - } - - switch (bit_depth) - { - int b; - - case 16: /* Two bytes per component, bit-endian */ - for (b = (bpp >> 4); b > 0; ) - { - unsigned int sig = (unsigned int)(0xffff0000 >> sig_bits[b]); - - sig_bits[2*b+1] = (png_byte)sig; - sig_bits[2*b+0] = (png_byte)(sig >> 8); /* big-endian */ - } - break; - - case 8: /* One byte per component */ - for (b=0; b*8 < bpp; ++b) - sig_bits[b] = (png_byte)(0xff00 >> sig_bits[b]); - break; - - case 1: /* allowed, but dumb */ - /* Value is 1 */ - sig_bits[0] = 0xff; - break; - - case 2: /* Replicate 4 times */ - /* Value is 1 or 2 */ - b = 0x3 & ((0x3<<2) >> sig_bits[0]); - b |= b << 2; - b |= b << 4; - sig_bits[0] = (png_byte)b; - break; - - case 4: /* Relicate twice */ - /* Value is 1, 2, 3 or 4 */ - b = 0xf & ((0xf << 4) >> sig_bits[0]); - b |= b << 4; - sig_bits[0] = (png_byte)b; - break; - - default: - display_log(dp, LIBPNG_BUG, "invalid bit depth %d", bit_depth); - break; - } - - /* Convert bpp to bytes; this gives '1' for low-bit depth grayscale, - * where there are multiple pixels per byte. - */ - bpp = (bpp+7) >> 3; - - /* The mask can be combined with sig_bits[0] */ - if (mask != 0) - { - mask &= sig_bits[0]; - - if (bpp != 1 || mask == 0) - display_log(dp, INTERNAL_ERROR, "mask calculation error %u, %u", - bpp, mask); - } - - for (y=0; yoriginal_rows[y]; - unsigned long x; - - for (x=0; x<(width-(mask!=0)); ++x) - { - int b; - - for (b=0; b%.2x", - x, b, y, orig[-1], row[-1]); - return 0; - } - } - } - - if (mask != 0 && (*row & mask) != (*orig & mask)) - { - display_log(dp, APP_FAIL, - "significant bits at (%lu[end],%lu) changed", x, y); - return 0; - } - } /* for y */ - } - } - - return 1; /* compare succeeded */ -} - -#ifdef PNG_WRITE_SUPPORTED -static void -buffer_write(struct display *dp, struct buffer *buffer, png_bytep data, - png_size_t size) - /* Generic write function used both from the write callback provided to - * libpng and from the generic read code. - */ -{ - /* Write the data into the buffer, adding buffers as required */ - struct buffer_list *last = buffer->last; - size_t end_count = buffer->end_count; - - while (size > 0) - { - size_t avail; - - if (end_count >= sizeof last->buffer) - { - if (last->next == NULL) - { - last = buffer_extend(last); - - if (last == NULL) - display_log(dp, APP_ERROR, "out of memory saving file"); - } - - else - last = last->next; - - buffer->last = last; /* avoid the need to rewrite every time */ - end_count = 0; - } - - avail = (sizeof last->buffer) - end_count; - if (avail > size) - avail = size; - - memcpy(last->buffer + end_count, data, avail); - end_count += avail; - size -= avail; - data += avail; - } - - buffer->end_count = end_count; -} - -static void PNGCBAPI -write_function(png_structp pp, png_bytep data, png_size_t size) -{ - buffer_write(get_dp(pp), get_buffer(pp), data, size); -} - -static void -write_png(struct display *dp, png_infop ip, int transforms) -{ - display_clean_write(dp); /* safety */ - - buffer_start_write(&dp->written_file); - dp->operation = "write"; - dp->transforms = transforms; - - dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp, - display_error, display_warning); - - if (dp->write_pp == NULL) - display_log(dp, APP_ERROR, "failed to create write png_struct"); - - png_set_write_fn(dp->write_pp, &dp->written_file, write_function, - NULL/*flush*/); - -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - /* Remove the user limits, if any */ - png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff); -# endif - - /* Certain transforms require the png_info to be zapped to allow the - * transform to work correctly. - */ - if (transforms & (PNG_TRANSFORM_PACKING| - PNG_TRANSFORM_STRIP_FILLER| - PNG_TRANSFORM_STRIP_FILLER_BEFORE)) - { - int ct = dp->color_type; - - if (transforms & (PNG_TRANSFORM_STRIP_FILLER| - PNG_TRANSFORM_STRIP_FILLER_BEFORE)) - ct &= ~PNG_COLOR_MASK_ALPHA; - - png_set_IHDR(dp->write_pp, ip, dp->width, dp->height, dp->bit_depth, ct, - dp->interlace_method, dp->compression_method, dp->filter_method); - } - - png_write_png(dp->write_pp, ip, transforms, NULL/*params*/); - - /* Clean it on the way out - if control returns to the caller then the - * written_file contains the required data. - */ - display_clean_write(dp); -} -#endif /* WRITE_SUPPORTED */ - -static int -skip_transform(struct display *dp, int tr) - /* Helper to test for a bad combo and log it if it is skipped */ -{ - if ((dp->options & SKIP_BUGS) != 0 && is_bad_combo(tr)) - { - /* Log this to stdout if logging is on, otherwise just do an information - * display_log. - */ - if ((dp->options & LOG_SKIPPED) != 0) - { - printf("SKIP: %s transforms ", dp->filename); - - while (tr != 0) - { - int next = first_transform(tr); - tr &= ~next; - - printf("%s", transform_name(next)); - if (tr != 0) - putchar('+'); - } - - putchar('\n'); - } - - else - display_log(dp, INFORMATION, "%s: skipped known bad combo 0x%x", - dp->filename, tr); - - return 1; /* skip */ - } - - return 0; /* don't skip */ -} - -static void -test_one_file(struct display *dp, const char *filename) -{ - /* First cache the file and update the display original file - * information for the new file. - */ - dp->operation = "cache file"; - dp->transforms = 0; - display_cache_file(dp, filename); - update_display(dp); - - /* First test: if there are options that should be ignored for this file - * verify that they really are ignored. - */ - if (dp->ignored_transforms != 0) - { - read_png(dp, &dp->original_file, "ignored transforms", - dp->ignored_transforms); - - /* The result should be identical to the original_rows */ - if (!compare_read(dp, 0/*transforms applied*/)) - return; /* no point testing more */ - } - -#ifdef PNG_WRITE_SUPPORTED - /* Second test: write the original PNG data out to a new file (to test the - * write side) then read the result back in and make sure that it hasn't - * changed. - */ - dp->operation = "write"; - write_png(dp, dp->original_ip, 0/*transforms*/); - read_png(dp, &dp->written_file, NULL, 0/*transforms*/); - if (!compare_read(dp, 0/*transforms applied*/)) - return; -#endif - - /* Third test: the active options. Test each in turn, or, with the - * EXHAUSTIVE option, test all possible combinations. - */ - { - /* Use unsigned int here because the code below to increment through all - * the possibilities exhaustively has to use a compare and that must be - * unsigned, because some transforms are negative on a 16-bit system. - */ - unsigned int active = dp->active_transforms; - const int exhaustive = (dp->options & EXHAUSTIVE) != 0; - unsigned int current = first_transform(active); - unsigned int bad_transforms = 0; - unsigned int bad_combo = ~0U; /* bitwise AND of failing transforms */ - unsigned int bad_combo_list = 0; /* bitwise OR of failures */ - - for (;;) - { - read_png(dp, &dp->original_file, "active transforms", current); - - /* If this involved any irreversible transformations then if we write - * it out with just the reversible transformations and read it in again - * with the same transforms we should get the same thing. At present - * this isn't done - it just seems like a waste of time and it would - * require two sets of read png_struct/png_info. - * - * If there were no irreversible transformations then if we write it - * out and read it back in again (without the reversible transforms) - * we should get back to the place where we started. - */ -#ifdef PNG_WRITE_SUPPORTED - if ((current & write_transforms) == current) - { - /* All transforms reversible: write the PNG with the transformations - * reversed, then read it back in with no transformations. The - * result should be the same as the original apart from the loss of - * low order bits because of the SHIFT/sBIT transform. - */ - dp->operation = "reversible transforms"; - write_png(dp, dp->read_ip, current); - - /* And if this is read back in, because all the transformations were - * reversible, the result should be the same. - */ - read_png(dp, &dp->written_file, NULL, 0); - if (!compare_read(dp, current/*for the SHIFT/sBIT transform*/)) - { - /* This set of transforms failed. If a single bit is set - if - * there is just one transform - don't include this in further - * 'exhaustive' tests. Notice that each transform is tested on - * its own before testing combos in the exhaustive case. - */ - if (is_combo(current)) - { - bad_combo &= current; - bad_combo_list |= current; - } - - else - bad_transforms |= current; - } - } -#endif - - /* Now move to the next transform */ - if (exhaustive) /* all combinations */ - { - unsigned int next = current; - - do - { - if (next == read_transforms) /* Everything tested */ - goto combo; - - ++next; - } /* skip known bad combos if the relevant option is set; skip - * combos involving known bad single transforms in all cases. - */ - while ( (next & read_transforms) <= current - || (next & active) == 0 /* skip cases that do nothing */ - || (next & bad_transforms) != 0 - || skip_transform(dp, next)); - - assert((next & read_transforms) == next); - current = next; - } - - else /* one at a time */ - { - active &= ~current; - - if (active == 0) - goto combo; - - current = first_transform(active); - } - } - -combo: - if (dp->options & FIND_BAD_COMBOS) - { - /* bad_combos identifies the combos that occur in all failing cases; - * bad_combo_list identifies transforms that do not prevent the - * failure. - */ - if (bad_combo != ~0U) - printf("%s[0x%x]: PROBLEM: 0x%x[0x%x] ANTIDOTE: 0x%x\n", - dp->filename, active, bad_combo, bad_combo_list, - rw_transforms & ~bad_combo_list); - - else - printf("%s: no %sbad combos found\n", dp->filename, - (dp->options & SKIP_BUGS) ? "additional " : ""); - } - } -} - -static int -do_test(struct display *dp, const char *file) - /* Exists solely to isolate the setjmp clobbers */ -{ - int ret = setjmp(dp->error_return); - - if (ret == 0) - { - test_one_file(dp, file); - return 0; - } - - else if (ret < ERRORS) /* shouldn't longjmp on warnings */ - display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret); - - return ret; -} - -int -main(const int argc, const char * const * const argv) -{ - /* For each file on the command line test it with a range of transforms */ - int option_end, ilog = 0; - struct display d; - - validate_T(); - display_init(&d); - - for (option_end=1; option_end QUIET) /* abort on user or internal error */ - return 99; - } - - /* Here on any return, including failures, except user/internal issues - */ - { - const int pass = (d.options & STRICT) ? - RESULT_STRICT(d.results) : RESULT_RELAXED(d.results); - - if (!pass) - ++errors; - - if (d.options & LOG) - { - int j; - - printf("%s: pngimage ", pass ? "PASS" : "FAIL"); - - for (j=1; j +#include +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#ifndef PNG_SETJMP_SUPPORTED +# include /* because png.h did *not* include this */ +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED) +/* If a transform is valid on both read and write this implies that if the + * transform is applied to read it must also be applied on write to produce + * meaningful data. This is because these transforms when performed on read + * produce data with a memory format that does not correspond to a PNG format. + * + * Most of these transforms are invertible; after applying the transform on + * write the result is the original PNG data that would have would have been + * read if no transform were applied. + * + * The exception is _SHIFT, which destroys the low order bits marked as not + * significant in a PNG with the sBIT chunk. + * + * The following table lists, for each transform, the conditions under which it + * is expected to do anything. Conditions are defined as follows: + * + * 1) Color mask bits required - simply a mask to AND with color_type; one of + * these must be present for the transform to fire, except that 0 means + * 'always'. + * 2) Color mask bits which must be absent - another mask - none of these must + * be present. + * 3) Bit depths - a mask of component bit depths for the transform to fire. + * 4) 'read' - the transform works in png_read_png. + * 5) 'write' - the transform works in png_write_png. + * 6) PNG_INFO_chunk; a mask of the chunks that must be present for the + * transform to fire. All must be present - the requirement is that + * png_get_valid() & mask == mask, so if mask is 0 there is no requirement. + * + * The condition refers to the original image state - if multiple transforms are + * used together it is possible to cause a transform that wouldn't fire on the + * original image to fire. + */ +static struct transform_info +{ + const char *name; + int transform; + png_uint_32 valid_chunks; +# define CHUNK_NONE 0 +# define CHUNK_sBIT PNG_INFO_sBIT +# define CHUNK_tRNS PNG_INFO_tRNS + png_byte color_mask_required; + png_byte color_mask_absent; +# define COLOR_MASK_X 0 +# define COLOR_MASK_P PNG_COLOR_MASK_PALETTE +# define COLOR_MASK_C PNG_COLOR_MASK_COLOR +# define COLOR_MASK_A PNG_COLOR_MASK_ALPHA +# define COLOR_MASK_ALL (PALETTE+COLOR+ALPHA) /* absent = gray, no alpha */ + png_byte bit_depths; +# define BD_ALL (1 + 2 + 4 + 8 + 16) +# define BD_PAL (1 + 2 + 4 + 8) +# define BD_LOW (1 + 2 + 4) +# define BD_16 16 +# define BD_TRUE (8+16) /* i.e. true-color depths */ + png_byte when; +# define TRANSFORM_R 1 +# define TRANSFORM_W 2 +# define TRANSFORM_RW 3 + png_byte tested; /* the transform was tested somewhere */ +} transform_info[] = +{ + /* List ALL the PNG_TRANSFORM_ macros here. Check for support using the READ + * macros; even if the transform is supported on write it cannot be tested + * without the read support. + */ +# define T(name,chunk,cm_required,cm_absent,bd,when)\ + { #name, PNG_TRANSFORM_ ## name, CHUNK_ ## chunk,\ + COLOR_MASK_ ## cm_required, COLOR_MASK_ ## cm_absent, BD_ ## bd,\ + TRANSFORM_ ## when, 0/*!tested*/ } + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + T(STRIP_16, NONE, X, X, 16, R), + /* drops the bottom 8 bits when bit depth is 16 */ +#endif +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + T(STRIP_ALPHA, NONE, A, X, ALL, R), + /* removes the alpha channel if present */ +#endif +#ifdef PNG_WRITE_PACK_SUPPORTED +# define TRANSFORM_RW_PACK TRANSFORM_RW +#else +# define TRANSFORM_RW_PACK TRANSFORM_R +#endif +#ifdef PNG_READ_PACK_SUPPORTED + T(PACKING, NONE, X, X, LOW, RW_PACK), + /* unpacks low-bit-depth components into 1 byte per component on read, + * reverses this on write. + */ +#endif +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED +# define TRANSFORM_RW_PACKSWAP TRANSFORM_RW +#else +# define TRANSFORM_RW_PACKSWAP TRANSFORM_R +#endif +#ifdef PNG_READ_PACKSWAP_SUPPORTED + T(PACKSWAP, NONE, X, X, LOW, RW_PACKSWAP), + /* reverses the order of low-bit-depth components packed into a byte */ +#endif +#ifdef PNG_READ_EXPAND_SUPPORTED + T(EXPAND, NONE, P, X, ALL, R), + /* expands PLTE PNG files to RGB (no tRNS) or RGBA (tRNS) * + * Note that the 'EXPAND' transform does lots of different things: */ + T(EXPAND, NONE, X, C, ALL, R), + /* expands grayscale PNG files to RGB, or RGBA */ + T(EXPAND, tRNS, X, A, ALL, R), + /* expands the tRNS chunk in files without alpha */ +#endif +#ifdef PNG_WRITE_INVERT_SUPPORTED +# define TRANSFORM_RW_INVERT TRANSFORM_RW +#else +# define TRANSFORM_RW_INVERT TRANSFORM_R +#endif +#ifdef PNG_READ_INVERT_SUPPORTED + T(INVERT_MONO, NONE, X, C, ALL, RW_INVERT), + /* converts gray-scale components to 1..0 from 0..1 */ +#endif +#ifdef PNG_WRITE_SHIFT_SUPPORTED +# define TRANSFORM_RW_SHIFT TRANSFORM_RW +#else +# define TRANSFORM_RW_SHIFT TRANSFORM_R +#endif +#ifdef PNG_READ_SHIFT_SUPPORTED + T(SHIFT, sBIT, X, X, ALL, RW_SHIFT), + /* reduces component values to the original range based on the sBIT chunk, + * this is only partially reversible - the low bits are lost and cannot be + * recovered on write. In fact write code replicates the bits to generate + * new low-order bits. + */ +#endif +#ifdef PNG_WRITE_BGR_SUPPORTED +# define TRANSFORM_RW_BGR TRANSFORM_RW +#else +# define TRANSFORM_RW_BGR TRANSFORM_R +#endif +#ifdef PNG_READ_BGR_SUPPORTED + T(BGR, NONE, C, P, TRUE, RW_BGR), + /* reverses the rgb component values of true-color pixels */ +#endif +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +# define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_RW +#else +# define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_R +#endif +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + T(SWAP_ALPHA, NONE, A, X, TRUE, RW_SWAP_ALPHA), + /* swaps the alpha channel of RGBA or GA pixels to the front - ARGB or + * AG, on write reverses the process. + */ +#endif +#ifdef PNG_WRITE_SWAP_SUPPORTED +# define TRANSFORM_RW_SWAP TRANSFORM_RW +#else +# define TRANSFORM_RW_SWAP TRANSFORM_R +#endif +#ifdef PNG_READ_SWAP_SUPPORTED + T(SWAP_ENDIAN, NONE, X, P, 16, RW_SWAP), + /* byte-swaps 16-bit component values */ +#endif +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +# define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_RW +#else +# define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_R +#endif +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + T(INVERT_ALPHA, NONE, A, X, TRUE, RW_INVERT_ALPHA), + /* converts an alpha channel from 0..1 to 1..0 */ +#endif +#ifdef PNG_WRITE_FILLER_SUPPORTED + T(STRIP_FILLER_BEFORE, NONE, A, P, TRUE, W), /* 'A' for a filler! */ + /* on write skips a leading filler channel; testing requires data with a + * filler channel so this is produced from RGBA or GA images by removing + * the 'alpha' flag from the color type in place. + */ + T(STRIP_FILLER_AFTER, NONE, A, P, TRUE, W), + /* on write strips a trailing filler channel */ +#endif +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + T(GRAY_TO_RGB, NONE, X, C, ALL, R), + /* expands grayscale images to RGB, also causes the palette part of + * 'EXPAND' to happen. Low bit depth grayscale images are expanded to + * 8-bits per component and no attempt is made to convert the image to a + * palette image. While this transform is partially reversible + * png_write_png does not currently support this. + */ + T(GRAY_TO_RGB, NONE, P, X, ALL, R), + /* The 'palette' side effect mentioned above; a bit bogus but this is the + * way the libpng code works. + */ +#endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED + T(EXPAND_16, NONE, X, X, PAL, R), + /* expands images to 16-bits per component, as a side effect expands + * palette images to RGB and expands the tRNS chunk if present, so it can + * modify 16-bit per component images as well: + */ + T(EXPAND_16, tRNS, X, A, 16, R), + /* side effect of EXPAND_16 - expands the tRNS chunk in an RGB or G 16-bit + * image. + */ +#endif +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + T(SCALE_16, NONE, X, X, 16, R) + /* scales 16-bit components to 8-bits. */ +#endif + +#undef T +}; + +#define ARRAY_SIZE(a) ((sizeof a)/(sizeof a[0])) +#define TTABLE_SIZE ARRAY_SIZE(transform_info) + +/* Some combinations of options that should be reversible are not; these cases + * are bugs. + */ +static int known_bad_combos[][2] = +{ + /* problem, antidote */ + { PNG_TRANSFORM_SHIFT | PNG_TRANSFORM_INVERT_ALPHA, 0/*antidote*/ } +}; + +static int +is_combo(int transforms) +{ + return transforms & (transforms-1); /* non-zero if more than one set bit */ +} + +static int +first_transform(int transforms) +{ + return transforms & -transforms; /* lowest set bit */ +} + +static int +is_bad_combo(int transforms) +{ + unsigned int i; + + for (i=0; ifirst.next = NULL; + buffer->last = NULL; + buffer->current = NULL; +} + +#ifdef PNG_WRITE_SUPPORTED +static void +buffer_start_write(struct buffer *buffer) +{ + buffer->last = &buffer->first; + buffer->end_count = 0; + buffer->current = NULL; +} +#endif + +static void +buffer_start_read(struct buffer *buffer) +{ + buffer->current = &buffer->first; + buffer->read_count = 0; +} + +#ifdef ENOMEM /* required by POSIX 1003.1 */ +# define MEMORY ENOMEM +#else +# define MEMORY ERANGE /* required by ANSI-C */ +#endif +static struct buffer * +get_buffer(png_structp pp) + /* Used from libpng callbacks to get the current buffer */ +{ + return (struct buffer*)png_get_io_ptr(pp); +} + +#define NEW(type) ((type *)malloc(sizeof (type))) + +static struct buffer_list * +buffer_extend(struct buffer_list *current) +{ + struct buffer_list *add; + + assert(current->next == NULL); + + add = NEW(struct buffer_list); + if (add == NULL) + return NULL; + + add->next = NULL; + current->next = add; + + return add; +} + +/* Load a buffer from a file; does the equivalent of buffer_start_write. On a + * read error returns an errno value, else returns 0. + */ +static int +buffer_from_file(struct buffer *buffer, FILE *fp) +{ + struct buffer_list *last = &buffer->first; + size_t count = 0; + + for (;;) + { + size_t r = fread(last->buffer+count, 1/*size*/, + (sizeof last->buffer)-count, fp); + + if (r > 0) + { + count += r; + + if (count >= sizeof last->buffer) + { + assert(count == sizeof last->buffer); + count = 0; + + if (last->next == NULL) + { + last = buffer_extend(last); + if (last == NULL) + return MEMORY; + } + + else + last = last->next; + } + } + + else /* fread failed - probably end of file */ + { + if (feof(fp)) + { + buffer->last = last; + buffer->end_count = count; + return 0; /* no error */ + } + + /* Some kind of funky error; errno should be non-zero */ + return errno == 0 ? ERANGE : errno; + } + } +} + +/* This structure is used to control the test of a single file. */ +typedef enum +{ + VERBOSE, /* switches on all messages */ + INFORMATION, + WARNINGS, /* switches on warnings */ + LIBPNG_WARNING, + APP_WARNING, + ERRORS, /* just errors */ + APP_FAIL, /* continuable error - no need to longjmp */ + LIBPNG_ERROR, /* this and higher cause a longjmp */ + LIBPNG_BUG, /* erroneous behavior in libpng */ + APP_ERROR, /* such as out-of-memory in a callback */ + QUIET, /* no normal messages */ + USER_ERROR, /* such as file-not-found */ + INTERNAL_ERROR +} error_level; +#define LEVEL_MASK 0xf /* where the level is in 'options' */ + +#define EXHAUSTIVE 0x010 /* Test all combinations of active options */ +#define STRICT 0x020 /* Fail on warnings as well as errors */ +#define LOG 0x040 /* Log pass/fail to stdout */ +#define CONTINUE 0x080 /* Continue on APP_FAIL errors */ +#define SKIP_BUGS 0x100 /* Skip over known bugs */ +#define LOG_SKIPPED 0x200 /* Log skipped bugs */ +#define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */ + +/* Result masks apply to the result bits in the 'results' field below; these + * bits are simple 1U<options = WARNINGS; /* default to !verbose, !quiet */ + dp->filename = NULL; + dp->operation = NULL; + dp->original_pp = NULL; + dp->original_ip = NULL; + dp->original_rows = NULL; + dp->read_pp = NULL; + dp->read_ip = NULL; + buffer_init(&dp->original_file); + +# ifdef PNG_WRITE_SUPPORTED + dp->write_pp = NULL; + buffer_init(&dp->written_file); +# endif +} + +static void +display_clean_read(struct display *dp) +{ + if (dp->read_pp != NULL) + png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL); +} + +#ifdef PNG_WRITE_SUPPORTED +static void +display_clean_write(struct display *dp) +{ + if (dp->write_pp != NULL) + png_destroy_write_struct(&dp->write_pp, NULL); +} +#endif + +static void +display_clean(struct display *dp) +{ +# ifdef PNG_WRITE_SUPPORTED + display_clean_write(dp); +# endif + display_clean_read(dp); + + dp->original_rowbytes = 0; + dp->original_rows = NULL; + dp->chunks = 0; + + png_destroy_read_struct(&dp->original_pp, &dp->original_ip, NULL); + /* leave the filename for error detection */ + dp->results = 0; /* reset for next time */ +} + +static struct display * +get_dp(png_structp pp) + /* The display pointer is always stored in the png_struct error pointer */ +{ + struct display *dp = (struct display*)png_get_error_ptr(pp); + + if (dp == NULL) + { + fprintf(stderr, "pngimage: internal error (no display)\n"); + exit(99); /* prevents a crash */ + } + + return dp; +} + +/* error handling */ +#ifdef __GNUC__ +# define VGATTR __attribute__((__format__ (__printf__,3,4))) + /* Required to quiet GNUC warnings when the compiler sees a stdarg function + * that calls one of the stdio v APIs. + */ +#else +# define VGATTR +#endif +static void VGATTR +display_log(struct display *dp, error_level level, const char *fmt, ...) + /* 'level' is as above, fmt is a stdio style format string. This routine + * does not return if level is above LIBPNG_WARNING + */ +{ + dp->results |= 1U << level; + + if (level > (error_level)(dp->options & LEVEL_MASK)) + { + const char *lp; + va_list ap; + + switch (level) + { + case INFORMATION: lp = "information"; break; + case LIBPNG_WARNING: lp = "warning(libpng)"; break; + case APP_WARNING: lp = "warning(pngimage)"; break; + case APP_FAIL: lp = "error(continuable)"; break; + case LIBPNG_ERROR: lp = "error(libpng)"; break; + case LIBPNG_BUG: lp = "bug(libpng)"; break; + case APP_ERROR: lp = "error(pngimage)"; break; + case USER_ERROR: lp = "error(user)"; break; + + case INTERNAL_ERROR: /* anything unexpected is an internal error: */ + case VERBOSE: case WARNINGS: case ERRORS: case QUIET: + default: lp = "bug(pngimage)"; break; + } + + fprintf(stderr, "%s: %s: %s", + dp->filename != NULL ? dp->filename : "", lp, dp->operation); + + if (dp->transforms != 0) + { + int tr = dp->transforms; + + if (is_combo(tr)) + fprintf(stderr, "(0x%x)", tr); + + else + fprintf(stderr, "(%s)", transform_name(tr)); + } + + fprintf(stderr, ": "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputc('\n', stderr); + } + /* else do not output any message */ + + /* Errors cause this routine to exit to the fail code */ + if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE))) + longjmp(dp->error_return, level); +} + +/* error handler callbacks for libpng */ +static void PNGCBAPI +display_warning(png_structp pp, png_const_charp warning) +{ + display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning); +} + +static void PNGCBAPI +display_error(png_structp pp, png_const_charp error) +{ + struct display *dp = get_dp(pp); + + display_log(dp, LIBPNG_ERROR, "%s", error); +} + +static void +display_cache_file(struct display *dp, const char *filename) + /* Does the initial cache of the file. */ +{ + FILE *fp; + int ret; + + dp->filename = filename; + + if (filename != NULL) + { + fp = fopen(filename, "rb"); + if (fp == NULL) + display_log(dp, USER_ERROR, "open failed: %s", strerror(errno)); + } + + else + fp = stdin; + + ret = buffer_from_file(&dp->original_file, fp); + + fclose(fp); + + if (ret != 0) + display_log(dp, APP_ERROR, "read failed: %s", strerror(ret)); +} + +static void +buffer_read(struct display *dp, struct buffer *bp, png_bytep data, + png_size_t size) +{ + struct buffer_list *last = bp->current; + size_t read_count = bp->read_count; + + while (size > 0) + { + size_t avail; + + if (last == NULL || + (last == bp->last && read_count >= bp->end_count)) + { + display_log(dp, USER_ERROR, "file truncated (%lu bytes)", + (unsigned long)size); + /*NOTREACHED*/ + break; + } + + else if (read_count >= sizeof last->buffer) + { + /* Move to the next buffer: */ + last = last->next; + read_count = 0; + bp->current = last; /* Avoid update outside the loop */ + + /* And do a sanity check (the EOF case is caught above) */ + if (last == NULL) + { + display_log(dp, INTERNAL_ERROR, "damaged buffer list"); + /*NOTREACHED*/ + break; + } + } + + avail = (sizeof last->buffer) - read_count; + if (avail > size) + avail = size; + + memcpy(data, last->buffer + read_count, avail); + read_count += avail; + size -= avail; + data += avail; + } + + bp->read_count = read_count; +} + +static void PNGCBAPI +read_function(png_structp pp, png_bytep data, png_size_t size) +{ + buffer_read(get_dp(pp), get_buffer(pp), data, size); +} + +static void +read_png(struct display *dp, struct buffer *bp, const char *operation, + int transforms) +{ + png_structp pp; + png_infop ip; + + /* This cleans out any previous read and sets operation and transforms to + * empty. + */ + display_clean_read(dp); + + if (operation != NULL) /* else this is a verify and do not overwrite info */ + { + dp->operation = operation; + dp->transforms = transforms; + } + + dp->read_pp = pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp, + display_error, display_warning); + if (pp == NULL) + display_log(dp, LIBPNG_ERROR, "failed to create read struct"); + + /* The png_read_png API requires us to make the info struct, but it does the + * call to png_read_info. + */ + dp->read_ip = ip = png_create_info_struct(pp); + if (ip == NULL) + display_log(dp, LIBPNG_ERROR, "failed to create info struct"); + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + /* Remove the user limits, if any */ + png_set_user_limits(pp, 0x7fffffff, 0x7fffffff); +# endif + + /* Set the IO handling */ + buffer_start_read(bp); + png_set_read_fn(pp, bp, read_function); + + png_read_png(pp, ip, transforms, NULL/*params*/); + +#if 0 /* crazy debugging */ + { + png_bytep pr = png_get_rows(pp, ip)[0]; + size_t rb = png_get_rowbytes(pp, ip); + size_t cb; + char c = ' '; + + fprintf(stderr, "%.4x %2d (%3lu bytes):", transforms, png_get_bit_depth(pp,ip), (unsigned long)rb); + + for (cb=0; cboriginal_file, "original read", 0/*no transform*/); + + /* Move the result to the 'original' fields */ + dp->original_pp = pp = dp->read_pp, dp->read_pp = NULL; + dp->original_ip = ip = dp->read_ip, dp->read_ip = NULL; + + dp->original_rowbytes = png_get_rowbytes(pp, ip); + if (dp->original_rowbytes == 0) + display_log(dp, LIBPNG_BUG, "png_get_rowbytes returned 0"); + + dp->chunks = png_get_valid(pp, ip, 0xffffffff); + if ((dp->chunks & PNG_INFO_IDAT) == 0) /* set by png_read_png */ + display_log(dp, LIBPNG_BUG, "png_read_png did not set IDAT flag"); + + dp->original_rows = png_get_rows(pp, ip); + if (dp->original_rows == NULL) + display_log(dp, LIBPNG_BUG, "png_read_png did not create row buffers"); + + if (!png_get_IHDR(pp, ip, + &dp->width, &dp->height, &dp->bit_depth, &dp->color_type, + &dp->interlace_method, &dp->compression_method, &dp->filter_method)) + display_log(dp, LIBPNG_BUG, "png_get_IHDR failed"); + + /* 'active' transforms are discovered based on the original image format; + * running one active transform can activate others. At present the code + * does not attempt to determine the closure. + */ + { + png_uint_32 chunks = dp->chunks; + int active = 0, inactive = 0; + int ct = dp->color_type; + int bd = dp->bit_depth; + unsigned int i; + + for (i=0; iactive_transforms = active; + dp->ignored_transforms = inactive; /* excluding write-only transforms */ + + if (active == 0) + display_log(dp, INTERNAL_ERROR, "bad transform table"); + } +} + +static int +compare_read(struct display *dp, int applied_transforms) +{ + /* Compare the png_info from read_ip with original_info */ + size_t rowbytes; + png_uint_32 width, height; + int bit_depth, color_type; + int interlace_method, compression_method, filter_method; + const char *e = NULL; + + png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth, + &color_type, &interlace_method, &compression_method, &filter_method); + +# define C(item) if (item != dp->item) \ + display_log(dp, APP_WARNING, "IHDR " #item "(%lu) changed to %lu",\ + (unsigned long)dp->item, (unsigned long)item), e = #item + + /* The IHDR should be identical: */ + C(width); + C(height); + C(bit_depth); + C(color_type); + C(interlace_method); + C(compression_method); + C(filter_method); + + /* 'e' remains set to the name of the last thing changed: */ + if (e) + display_log(dp, APP_ERROR, "IHDR changed (%s)", e); + + /* All the chunks from the original PNG should be preserved in the output PNG + * because the PNG format has not been changed. + */ + { + unsigned long chunks = + png_get_valid(dp->read_pp, dp->read_ip, 0xffffffff); + + if (chunks != dp->chunks) + display_log(dp, APP_FAIL, "PNG chunks changed from 0x%lx to 0x%lx", + (unsigned long)dp->chunks, chunks); + } + + /* rowbytes should be the same */ + rowbytes = png_get_rowbytes(dp->read_pp, dp->read_ip); + + /* NOTE: on 64-bit systems this may trash the top bits of rowbytes, + * which could lead to weird error messages. + */ + if (rowbytes != dp->original_rowbytes) + display_log(dp, APP_ERROR, "PNG rowbytes changed from %lu to %lu", + (unsigned long)dp->original_rowbytes, (unsigned long)rowbytes); + + /* The rows should be the same too, unless the applied transforms includes + * the shift transform, in which case low bits may have been lost. + */ + { + png_bytepp rows = png_get_rows(dp->read_pp, dp->read_ip); + unsigned int mask; /* mask (if not zero) for the final byte */ + + if (bit_depth < 8) + { + /* Need the stray bits at the end, this depends only on the low bits + * of the image width; overflow does not matter. If the width is an + * exact multiple of 8 bits this gives a mask of 0, not 0xff. + */ + mask = 0xff & (0xff00 >> ((bit_depth * width) & 7)); + } + + else + mask = 0; + + if (rows == NULL) + display_log(dp, LIBPNG_BUG, "png_get_rows returned NULL"); + + if ((applied_transforms & PNG_TRANSFORM_SHIFT) == 0 || + (dp->active_transforms & PNG_TRANSFORM_SHIFT) == 0 || + color_type == PNG_COLOR_TYPE_PALETTE) + { + unsigned long y; + + for (y=0; yoriginal_rows[y]; + + if (memcmp(row, orig, rowbytes-(mask != 0)) != 0 || (mask != 0 && + ((row[rowbytes-1] & mask) != (orig[rowbytes-1] & mask)))) + { + size_t x; + + /* Find the first error */ + for (x=0; x 0x%.2x", + (unsigned long)x, (unsigned long)y, orig[x], row[x]); + return 0; /* don't keep reporting failed rows on 'continue' */ + } + } + } + + else + { + unsigned long y; + int bpp; /* bits-per-pixel then bytes-per-pixel */ + /* components are up to 8 bytes in size */ + png_byte sig_bits[8]; + png_color_8p sBIT; + + if (png_get_sBIT(dp->read_pp, dp->read_ip, &sBIT) != PNG_INFO_sBIT) + display_log(dp, INTERNAL_ERROR, + "active shift transform but no sBIT in file"); + + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + sig_bits[0] = sBIT->gray; + bpp = bit_depth; + break; + + case PNG_COLOR_TYPE_GA: + sig_bits[0] = sBIT->gray; + sig_bits[1] = sBIT->alpha; + bpp = 2 * bit_depth; + break; + + case PNG_COLOR_TYPE_RGB: + sig_bits[0] = sBIT->red; + sig_bits[1] = sBIT->green; + sig_bits[2] = sBIT->blue; + bpp = 3 * bit_depth; + break; + + case PNG_COLOR_TYPE_RGBA: + sig_bits[0] = sBIT->red; + sig_bits[1] = sBIT->green; + sig_bits[2] = sBIT->blue; + sig_bits[3] = sBIT->alpha; + bpp = 4 * bit_depth; + break; + + default: + display_log(dp, LIBPNG_ERROR, "invalid colour type %d", + color_type); + /*NOTREACHED*/ + bpp = 0; + break; + } + + { + int b; + + for (b=0; 8*b bit_depth/*!palette*/) + display_log(dp, LIBPNG_BUG, + "invalid sBIT[%u] value %d returned for PNG bit depth %d", + b, sig_bits[b], bit_depth); + } + } + + if (bpp < 8 && bpp != bit_depth) + { + /* sanity check; this is a grayscale PNG; something is wrong in the + * code above. + */ + display_log(dp, INTERNAL_ERROR, "invalid bpp %u for bit_depth %u", + bpp, bit_depth); + } + + switch (bit_depth) + { + int b; + + case 16: /* Two bytes per component, bit-endian */ + for (b = (bpp >> 4); b > 0; ) + { + unsigned int sig = (unsigned int)(0xffff0000 >> sig_bits[b]); + + sig_bits[2*b+1] = (png_byte)sig; + sig_bits[2*b+0] = (png_byte)(sig >> 8); /* big-endian */ + } + break; + + case 8: /* One byte per component */ + for (b=0; b*8 < bpp; ++b) + sig_bits[b] = (png_byte)(0xff00 >> sig_bits[b]); + break; + + case 1: /* allowed, but dumb */ + /* Value is 1 */ + sig_bits[0] = 0xff; + break; + + case 2: /* Replicate 4 times */ + /* Value is 1 or 2 */ + b = 0x3 & ((0x3<<2) >> sig_bits[0]); + b |= b << 2; + b |= b << 4; + sig_bits[0] = (png_byte)b; + break; + + case 4: /* Relicate twice */ + /* Value is 1, 2, 3 or 4 */ + b = 0xf & ((0xf << 4) >> sig_bits[0]); + b |= b << 4; + sig_bits[0] = (png_byte)b; + break; + + default: + display_log(dp, LIBPNG_BUG, "invalid bit depth %d", bit_depth); + break; + } + + /* Convert bpp to bytes; this gives '1' for low-bit depth grayscale, + * where there are multiple pixels per byte. + */ + bpp = (bpp+7) >> 3; + + /* The mask can be combined with sig_bits[0] */ + if (mask != 0) + { + mask &= sig_bits[0]; + + if (bpp != 1 || mask == 0) + display_log(dp, INTERNAL_ERROR, "mask calculation error %u, %u", + bpp, mask); + } + + for (y=0; yoriginal_rows[y]; + unsigned long x; + + for (x=0; x<(width-(mask!=0)); ++x) + { + int b; + + for (b=0; b%.2x", + x, b, y, orig[-1], row[-1]); + return 0; + } + } + } + + if (mask != 0 && (*row & mask) != (*orig & mask)) + { + display_log(dp, APP_FAIL, + "significant bits at (%lu[end],%lu) changed", x, y); + return 0; + } + } /* for y */ + } + } + + return 1; /* compare succeeded */ +} + +#ifdef PNG_WRITE_SUPPORTED +static void +buffer_write(struct display *dp, struct buffer *buffer, png_bytep data, + png_size_t size) + /* Generic write function used both from the write callback provided to + * libpng and from the generic read code. + */ +{ + /* Write the data into the buffer, adding buffers as required */ + struct buffer_list *last = buffer->last; + size_t end_count = buffer->end_count; + + while (size > 0) + { + size_t avail; + + if (end_count >= sizeof last->buffer) + { + if (last->next == NULL) + { + last = buffer_extend(last); + + if (last == NULL) + display_log(dp, APP_ERROR, "out of memory saving file"); + } + + else + last = last->next; + + buffer->last = last; /* avoid the need to rewrite every time */ + end_count = 0; + } + + avail = (sizeof last->buffer) - end_count; + if (avail > size) + avail = size; + + memcpy(last->buffer + end_count, data, avail); + end_count += avail; + size -= avail; + data += avail; + } + + buffer->end_count = end_count; +} + +static void PNGCBAPI +write_function(png_structp pp, png_bytep data, png_size_t size) +{ + buffer_write(get_dp(pp), get_buffer(pp), data, size); +} + +static void +write_png(struct display *dp, png_infop ip, int transforms) +{ + display_clean_write(dp); /* safety */ + + buffer_start_write(&dp->written_file); + dp->operation = "write"; + dp->transforms = transforms; + + dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp, + display_error, display_warning); + + if (dp->write_pp == NULL) + display_log(dp, APP_ERROR, "failed to create write png_struct"); + + png_set_write_fn(dp->write_pp, &dp->written_file, write_function, + NULL/*flush*/); + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + /* Remove the user limits, if any */ + png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff); +# endif + + /* Certain transforms require the png_info to be zapped to allow the + * transform to work correctly. + */ + if (transforms & (PNG_TRANSFORM_PACKING| + PNG_TRANSFORM_STRIP_FILLER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) + { + int ct = dp->color_type; + + if (transforms & (PNG_TRANSFORM_STRIP_FILLER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) + ct &= ~PNG_COLOR_MASK_ALPHA; + + png_set_IHDR(dp->write_pp, ip, dp->width, dp->height, dp->bit_depth, ct, + dp->interlace_method, dp->compression_method, dp->filter_method); + } + + png_write_png(dp->write_pp, ip, transforms, NULL/*params*/); + + /* Clean it on the way out - if control returns to the caller then the + * written_file contains the required data. + */ + display_clean_write(dp); +} +#endif /* WRITE_SUPPORTED */ + +static int +skip_transform(struct display *dp, int tr) + /* Helper to test for a bad combo and log it if it is skipped */ +{ + if ((dp->options & SKIP_BUGS) != 0 && is_bad_combo(tr)) + { + /* Log this to stdout if logging is on, otherwise just do an information + * display_log. + */ + if ((dp->options & LOG_SKIPPED) != 0) + { + printf("SKIP: %s transforms ", dp->filename); + + while (tr != 0) + { + int next = first_transform(tr); + tr &= ~next; + + printf("%s", transform_name(next)); + if (tr != 0) + putchar('+'); + } + + putchar('\n'); + } + + else + display_log(dp, INFORMATION, "%s: skipped known bad combo 0x%x", + dp->filename, tr); + + return 1; /* skip */ + } + + return 0; /* don't skip */ +} + +static void +test_one_file(struct display *dp, const char *filename) +{ + /* First cache the file and update the display original file + * information for the new file. + */ + dp->operation = "cache file"; + dp->transforms = 0; + display_cache_file(dp, filename); + update_display(dp); + + /* First test: if there are options that should be ignored for this file + * verify that they really are ignored. + */ + if (dp->ignored_transforms != 0) + { + read_png(dp, &dp->original_file, "ignored transforms", + dp->ignored_transforms); + + /* The result should be identical to the original_rows */ + if (!compare_read(dp, 0/*transforms applied*/)) + return; /* no point testing more */ + } + +#ifdef PNG_WRITE_SUPPORTED + /* Second test: write the original PNG data out to a new file (to test the + * write side) then read the result back in and make sure that it hasn't + * changed. + */ + dp->operation = "write"; + write_png(dp, dp->original_ip, 0/*transforms*/); + read_png(dp, &dp->written_file, NULL, 0/*transforms*/); + if (!compare_read(dp, 0/*transforms applied*/)) + return; +#endif + + /* Third test: the active options. Test each in turn, or, with the + * EXHAUSTIVE option, test all possible combinations. + */ + { + /* Use unsigned int here because the code below to increment through all + * the possibilities exhaustively has to use a compare and that must be + * unsigned, because some transforms are negative on a 16-bit system. + */ + unsigned int active = dp->active_transforms; + const int exhaustive = (dp->options & EXHAUSTIVE) != 0; + unsigned int current = first_transform(active); + unsigned int bad_transforms = 0; + unsigned int bad_combo = ~0U; /* bitwise AND of failing transforms */ + unsigned int bad_combo_list = 0; /* bitwise OR of failures */ + + for (;;) + { + read_png(dp, &dp->original_file, "active transforms", current); + + /* If this involved any irreversible transformations then if we write + * it out with just the reversible transformations and read it in again + * with the same transforms we should get the same thing. At present + * this isn't done - it just seems like a waste of time and it would + * require two sets of read png_struct/png_info. + * + * If there were no irreversible transformations then if we write it + * out and read it back in again (without the reversible transforms) + * we should get back to the place where we started. + */ +#ifdef PNG_WRITE_SUPPORTED + if ((current & write_transforms) == current) + { + /* All transforms reversible: write the PNG with the transformations + * reversed, then read it back in with no transformations. The + * result should be the same as the original apart from the loss of + * low order bits because of the SHIFT/sBIT transform. + */ + dp->operation = "reversible transforms"; + write_png(dp, dp->read_ip, current); + + /* And if this is read back in, because all the transformations were + * reversible, the result should be the same. + */ + read_png(dp, &dp->written_file, NULL, 0); + if (!compare_read(dp, current/*for the SHIFT/sBIT transform*/)) + { + /* This set of transforms failed. If a single bit is set - if + * there is just one transform - don't include this in further + * 'exhaustive' tests. Notice that each transform is tested on + * its own before testing combos in the exhaustive case. + */ + if (is_combo(current)) + { + bad_combo &= current; + bad_combo_list |= current; + } + + else + bad_transforms |= current; + } + } +#endif + + /* Now move to the next transform */ + if (exhaustive) /* all combinations */ + { + unsigned int next = current; + + do + { + if (next == read_transforms) /* Everything tested */ + goto combo; + + ++next; + } /* skip known bad combos if the relevant option is set; skip + * combos involving known bad single transforms in all cases. + */ + while ( (next & read_transforms) <= current + || (next & active) == 0 /* skip cases that do nothing */ + || (next & bad_transforms) != 0 + || skip_transform(dp, next)); + + assert((next & read_transforms) == next); + current = next; + } + + else /* one at a time */ + { + active &= ~current; + + if (active == 0) + goto combo; + + current = first_transform(active); + } + } + +combo: + if (dp->options & FIND_BAD_COMBOS) + { + /* bad_combos identifies the combos that occur in all failing cases; + * bad_combo_list identifies transforms that do not prevent the + * failure. + */ + if (bad_combo != ~0U) + printf("%s[0x%x]: PROBLEM: 0x%x[0x%x] ANTIDOTE: 0x%x\n", + dp->filename, active, bad_combo, bad_combo_list, + rw_transforms & ~bad_combo_list); + + else + printf("%s: no %sbad combos found\n", dp->filename, + (dp->options & SKIP_BUGS) ? "additional " : ""); + } + } +} + +static int +do_test(struct display *dp, const char *file) + /* Exists solely to isolate the setjmp clobbers */ +{ + int ret = setjmp(dp->error_return); + + if (ret == 0) + { + test_one_file(dp, file); + return 0; + } + + else if (ret < ERRORS) /* shouldn't longjmp on warnings */ + display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret); + + return ret; +} + +int +main(const int argc, const char * const * const argv) +{ + /* For each file on the command line test it with a range of transforms */ + int option_end, ilog = 0; + struct display d; + + validate_T(); + display_init(&d); + + for (option_end=1; option_end QUIET) /* abort on user or internal error */ + return 99; + } + + /* Here on any return, including failures, except user/internal issues + */ + { + const int pass = (d.options & STRICT) ? + RESULT_STRICT(d.results) : RESULT_RELAXED(d.results); + + if (!pass) + ++errors; + + if (d.options & LOG) + { + int j; + + printf("%s: pngimage ", pass ? "PASS" : "FAIL"); + + for (j=1; j -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include -#endif - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include -#else -# include "../../png.h" -#endif - -#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */ -#include "../tools/sRGB.h" - -/* KNOWN ISSUES - * - * These defines switch on alternate algorithms for format conversions to match - * the current libpng implementation; they are set to allow pngstest to pass - * even though libpng is producing answers that are not as correct as they - * should be. - */ -#define ALLOW_UNUSED_GPC 0 - /* If true include unused static GPC functions and declare an external array - * of them to hide the fact that they are unused. This is for development - * use while testing the correct function to use to take into account libpng - * misbehavior, such as using a simple power law to correct sRGB to linear. - */ - -/* The following is to support direct compilation of this file as C++ */ -#ifdef __cplusplus -# define voidcast(type, value) static_cast(value) -# define aligncastconst(type, value) \ - static_cast(static_cast(value)) -#else -# define voidcast(type, value) (value) -# define aligncastconst(type, value) ((const void*)(value)) -#endif /* __cplusplus */ - -/* During parallel runs of pngstest each temporary file needs a unique name, - * this is used to permit uniqueness using a command line argument which can be - * up to 22 characters long. - */ -static char tmpf[23] = "TMP"; - -/* Generate random bytes. This uses a boring repeatable algorithm and it - * is implemented here so that it gives the same set of numbers on every - * architecture. It's a linear congruential generator (Knuth or Sedgewick - * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and - * Hill, "The Art of Electronics". - */ -static void -make_random_bytes(png_uint_32* seed, void* pv, size_t size) -{ - png_uint_32 u0 = seed[0], u1 = seed[1]; - png_bytep bytes = voidcast(png_bytep, pv); - - /* There are thirty three bits, the next bit in the sequence is bit-33 XOR - * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. - */ - size_t i; - for (i=0; i> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; - u1 <<= 8; - u1 |= u0 >> 24; - u0 <<= 8; - u0 |= u; - *bytes++ = (png_byte)u; - } - - seed[0] = u0; - seed[1] = u1; -} - -static void -random_color(png_colorp color) -{ - static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef }; - make_random_bytes(color_seed, color, sizeof *color); -} - -/* Math support - neither Cygwin nor Visual Studio have C99 support and we need - * a predictable rounding function, so make one here: - */ -static double -closestinteger(double x) -{ - return floor(x + .5); -} - -/* Cast support: remove GCC whines. */ -static png_byte -u8d(double d) -{ - d = closestinteger(d); - return (png_byte)d; -} - -static png_uint_16 -u16d(double d) -{ - d = closestinteger(d); - return (png_uint_16)d; -} - -/* sRGB support: use exact calculations rounded to the nearest int, see the - * fesetround() call in main(). sRGB_to_d optimizes the 8 to 16-bit conversion. - */ -static double sRGB_to_d[256]; -static double g22_to_d[256]; - -static void -init_sRGB_to_d(void) -{ - int i; - - sRGB_to_d[0] = 0; - for (i=1; i<255; ++i) - sRGB_to_d[i] = linear_from_sRGB(i/255.); - sRGB_to_d[255] = 1; - - g22_to_d[0] = 0; - for (i=1; i<255; ++i) - g22_to_d[i] = pow(i/255., 1/.45455); - g22_to_d[255] = 1; -} - -static png_byte -sRGB(double linear /*range 0.0 .. 1.0*/) -{ - return u8d(255 * sRGB_from_linear(linear)); -} - -static png_byte -isRGB(int fixed_linear) -{ - return sRGB(fixed_linear / 65535.); -} - -#if 0 /* not used */ -static png_byte -unpremultiply(int component, int alpha) -{ - if (alpha <= component) - return 255; /* Arbitrary, but consistent with the libpng code */ - - else if (alpha >= 65535) - return isRGB(component); - - else - return sRGB((double)component / alpha); -} -#endif - -static png_uint_16 -ilinear(int fixed_srgb) -{ - return u16d(65535 * sRGB_to_d[fixed_srgb]); -} - -static png_uint_16 -ilineara(int fixed_srgb, int alpha) -{ - return u16d((257 * alpha) * sRGB_to_d[fixed_srgb]); -} - -static png_uint_16 -ilinear_g22(int fixed_srgb) -{ - return u16d(65535 * g22_to_d[fixed_srgb]); -} - -#if ALLOW_UNUSED_GPC -static png_uint_16 -ilineara_g22(int fixed_srgb, int alpha) -{ - return u16d((257 * alpha) * g22_to_d[fixed_srgb]); -} -#endif - -static double -YfromRGBint(int ir, int ig, int ib) -{ - double r = ir; - double g = ig; - double b = ib; - return YfromRGB(r, g, b); -} - -#if 0 /* unused */ -/* The error that results from using a 2.2 power law in place of the correct - * sRGB transform, given an 8-bit value which might be either sRGB or power-law. - */ -static int -power_law_error8(int value) -{ - if (value > 0 && value < 255) - { - double vd = value / 255.; - double e = fabs( - pow(sRGB_to_d[value], 1/2.2) - sRGB_from_linear(pow(vd, 2.2))); - - /* Always allow an extra 1 here for rounding errors */ - e = 1+floor(255 * e); - return (int)e; - } - - return 0; -} - -static int error_in_sRGB_roundtrip = 56; /* by experiment */ -static int -power_law_error16(int value) -{ - if (value > 0 && value < 65535) - { - /* Round trip the value through an 8-bit representation but using - * non-matching to/from conversions. - */ - double vd = value / 65535.; - double e = fabs( - pow(sRGB_from_linear(vd), 2.2) - linear_from_sRGB(pow(vd, 1/2.2))); - - /* Always allow an extra 1 here for rounding errors */ - e = error_in_sRGB_roundtrip+floor(65535 * e); - return (int)e; - } - - return 0; -} - -static int -compare_8bit(int v1, int v2, int error_limit, int multiple_algorithms) -{ - int e = abs(v1-v2); - int ev1, ev2; - - if (e <= error_limit) - return 1; - - if (!multiple_algorithms) - return 0; - - ev1 = power_law_error8(v1); - if (e <= ev1) - return 1; - - ev2 = power_law_error8(v2); - if (e <= ev2) - return 1; - - return 0; -} - -static int -compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) -{ - int e = abs(v1-v2); - int ev1, ev2; - - if (e <= error_limit) - return 1; - - /* "multiple_algorithms" in this case means that a color-map has been - * involved somewhere, so we can deduce that the values were forced to 8-bit - * (like the via_linear case for 8-bit.) - */ - if (!multiple_algorithms) - return 0; - - ev1 = power_law_error16(v1); - if (e <= ev1) - return 1; - - ev2 = power_law_error16(v2); - if (e <= ev2) - return 1; - - return 0; -} -#endif /* unused */ - -#define READ_FILE 1 /* else memory */ -#define USE_STDIO 2 /* else use file name */ -#define STRICT 4 /* fail on warnings too */ -#define VERBOSE 8 -#define KEEP_TMPFILES 16 /* else delete temporary files */ -#define KEEP_GOING 32 -#define ACCUMULATE 64 -#define FAST_WRITE 128 -#define sRGB_16BIT 256 - -static void -print_opts(png_uint_32 opts) -{ - if (opts & READ_FILE) - printf(" --file"); - if (opts & USE_STDIO) - printf(" --stdio"); - if (opts & STRICT) - printf(" --strict"); - if (opts & VERBOSE) - printf(" --verbose"); - if (opts & KEEP_TMPFILES) - printf(" --preserve"); - if (opts & KEEP_GOING) - printf(" --keep-going"); - if (opts & ACCUMULATE) - printf(" --accumulate"); - if (!(opts & FAST_WRITE)) /* --fast is currently the default */ - printf(" --slow"); - if (opts & sRGB_16BIT) - printf(" --sRGB-16bit"); -} - -#define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ - -/* A name table for all the formats - defines the format of the '+' arguments to - * pngstest. - */ -#define FORMAT_COUNT 64 -#define FORMAT_MASK 0x3f -static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = -{ - "sRGB-gray", - "sRGB-gray+alpha", - "sRGB-rgb", - "sRGB-rgb+alpha", - "linear-gray", - "linear-gray+alpha", - "linear-rgb", - "linear-rgb+alpha", - - "color-mapped-sRGB-gray", - "color-mapped-sRGB-gray+alpha", - "color-mapped-sRGB-rgb", - "color-mapped-sRGB-rgb+alpha", - "color-mapped-linear-gray", - "color-mapped-linear-gray+alpha", - "color-mapped-linear-rgb", - "color-mapped-linear-rgb+alpha", - - "sRGB-gray", - "sRGB-gray+alpha", - "sRGB-bgr", - "sRGB-bgr+alpha", - "linear-gray", - "linear-gray+alpha", - "linear-bgr", - "linear-bgr+alpha", - - "color-mapped-sRGB-gray", - "color-mapped-sRGB-gray+alpha", - "color-mapped-sRGB-bgr", - "color-mapped-sRGB-bgr+alpha", - "color-mapped-linear-gray", - "color-mapped-linear-gray+alpha", - "color-mapped-linear-bgr", - "color-mapped-linear-bgr+alpha", - - "sRGB-gray", - "alpha+sRGB-gray", - "sRGB-rgb", - "alpha+sRGB-rgb", - "linear-gray", - "alpha+linear-gray", - "linear-rgb", - "alpha+linear-rgb", - - "color-mapped-sRGB-gray", - "color-mapped-alpha+sRGB-gray", - "color-mapped-sRGB-rgb", - "color-mapped-alpha+sRGB-rgb", - "color-mapped-linear-gray", - "color-mapped-alpha+linear-gray", - "color-mapped-linear-rgb", - "color-mapped-alpha+linear-rgb", - - "sRGB-gray", - "alpha+sRGB-gray", - "sRGB-bgr", - "alpha+sRGB-bgr", - "linear-gray", - "alpha+linear-gray", - "linear-bgr", - "alpha+linear-bgr", - - "color-mapped-sRGB-gray", - "color-mapped-alpha+sRGB-gray", - "color-mapped-sRGB-bgr", - "color-mapped-alpha+sRGB-bgr", - "color-mapped-linear-gray", - "color-mapped-alpha+linear-gray", - "color-mapped-linear-bgr", - "color-mapped-alpha+linear-bgr", -}; - -/* Decode an argument to a format number. */ -static png_uint_32 -formatof(const char *arg) -{ - char *ep; - unsigned long format = strtoul(arg, &ep, 0); - - if (ep > arg && *ep == 0 && format < FORMAT_COUNT) - return (png_uint_32)format; - - else for (format=0; format < FORMAT_COUNT; ++format) - { - if (strcmp(format_names[format], arg) == 0) - return (png_uint_32)format; - } - - fprintf(stderr, "pngstest: format name '%s' invalid\n", arg); - return FORMAT_COUNT; -} - -/* Bitset/test functions for formats */ -#define FORMAT_SET_COUNT (FORMAT_COUNT / 32) -typedef struct -{ - png_uint_32 bits[FORMAT_SET_COUNT]; -} -format_list; - -static void format_init(format_list *pf) -{ - int i; - for (i=0; ibits[i] = 0; /* All off */ -} - -#if 0 /* currently unused */ -static void format_clear(format_list *pf) -{ - int i; - for (i=0; ibits[i] = 0; -} -#endif - -static int format_is_initial(format_list *pf) -{ - int i; - for (i=0; ibits[i] != 0) - return 0; - - return 1; -} - -static int format_set(format_list *pf, png_uint_32 format) -{ - if (format < FORMAT_COUNT) - return pf->bits[format >> 5] |= ((png_uint_32)1) << (format & 31); - - return 0; -} - -#if 0 /* currently unused */ -static int format_unset(format_list *pf, png_uint_32 format) -{ - if (format < FORMAT_COUNT) - return pf->bits[format >> 5] &= ~((png_uint_32)1) << (format & 31); - - return 0; -} -#endif - -static int format_isset(format_list *pf, png_uint_32 format) -{ - return format < FORMAT_COUNT && - (pf->bits[format >> 5] & (((png_uint_32)1) << (format & 31))) != 0; -} - -static void format_default(format_list *pf, int redundant) -{ - if (redundant) - { - int i; - - /* set everything, including flags that are pointless */ - for (i=0; ibits[i] = ~(png_uint_32)0; - } - - else - { - png_uint_32 f; - - for (f=0; finput_file != NULL) - rewind(image->input_file); -} - -/* Free the image buffer; the buffer is re-used on a re-read, this is just for - * cleanup. - */ -static void -freebuffer(Image *image) -{ - if (image->buffer) free(image->buffer); - image->buffer = NULL; - image->bufsize = 0; - image->allocsize = 0; -} - -/* Delete function; cleans out all the allocated data and the temporary file in - * the image. - */ -static void -freeimage(Image *image) -{ - freebuffer(image); - png_image_free(&image->image); - - if (image->input_file != NULL) - { - fclose(image->input_file); - image->input_file = NULL; - } - - if (image->input_memory != NULL) - { - free(image->input_memory); - image->input_memory = NULL; - image->input_memory_size = 0; - } - - if (image->tmpfile_name[0] != 0 && (image->opts & KEEP_TMPFILES) == 0) - { - remove(image->tmpfile_name); - image->tmpfile_name[0] = 0; - } -} - -/* This is actually a re-initializer; allows an image structure to be re-used by - * freeing everything that relates to an old image. - */ -static void initimage(Image *image, png_uint_32 opts, const char *file_name, - int stride_extra) -{ - freeimage(image); - memset(&image->image, 0, sizeof image->image); - image->opts = opts; - image->file_name = file_name; - image->stride_extra = stride_extra; -} - -/* Make sure the image buffer is big enough; allows re-use of the buffer if the - * image is re-read. - */ -#define BUFFER_INIT8 73 -static void -allocbuffer(Image *image) -{ - png_size_t size = PNG_IMAGE_BUFFER_SIZE(image->image, image->stride); - - if (size+32 > image->bufsize) - { - freebuffer(image); - image->buffer = voidcast(png_bytep, malloc(size+32)); - if (image->buffer == NULL) - { - fflush(stdout); - fprintf(stderr, - "simpletest: out of memory allocating %lu(+32) byte buffer\n", - (unsigned long)size); - exit(1); - } - image->bufsize = size+32; - } - - memset(image->buffer, 95, image->bufsize); - memset(image->buffer+16, BUFFER_INIT8, size); - image->allocsize = size; -} - -/* Make sure 16 bytes match the given byte. */ -static int -check16(png_const_bytep bp, int b) -{ - int i = 16; - - do - if (*bp != b) return 1; - while (--i); - - return 0; -} - -/* Check for overwrite in the image buffer. */ -static void -checkbuffer(Image *image, const char *arg) -{ - if (check16(image->buffer, 95)) - { - fflush(stdout); - fprintf(stderr, "%s: overwrite at start of image buffer\n", arg); - exit(1); - } - - if (check16(image->buffer+16+image->allocsize, 95)) - { - fflush(stdout); - fprintf(stderr, "%s: overwrite at end of image buffer\n", arg); - exit(1); - } -} - -/* ERROR HANDLING */ -/* Log a terminal error, also frees the libpng part of the image if necessary. - */ -static int -logerror(Image *image, const char *a1, const char *a2, const char *a3) -{ - fflush(stdout); - if (image->image.warning_or_error) - fprintf(stderr, "%s%s%s: %s\n", a1, a2, a3, image->image.message); - - else - fprintf(stderr, "%s%s%s\n", a1, a2, a3); - - if (image->image.opaque != NULL) - { - fprintf(stderr, "%s: image opaque pointer non-NULL on error\n", - image->file_name); - png_image_free(&image->image); - } - - return 0; -} - -/* Log an error and close a file (just a utility to do both things in one - * function call.) - */ -static int -logclose(Image *image, FILE *f, const char *name, const char *operation) -{ - int e = errno; - - fclose(f); - return logerror(image, name, operation, strerror(e)); -} - -/* Make sure the png_image has been freed - validates that libpng is doing what - * the spec says and freeing the image. - */ -static int -checkopaque(Image *image) -{ - if (image->image.opaque != NULL) - { - png_image_free(&image->image); - return logerror(image, image->file_name, ": opaque not NULL", ""); - } - - else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0) - return logerror(image, image->file_name, " --strict", ""); - - else - return 1; -} - -/* IMAGE COMPARISON/CHECKING */ -/* Compare the pixels of two images, which should be the same but aren't. The - * images must have been checked for a size match. - */ -typedef struct -{ - /* The components, for grayscale images the gray value is in 'g' and if alpha - * is not present 'a' is set to 255 or 65535 according to format. - */ - int r, g, b, a; -} Pixel; - -typedef struct -{ - /* The background as the original sRGB 8-bit value converted to the final - * integer format and as a double precision linear value in the range 0..1 - * for with partially transparent pixels. - */ - int ir, ig, ib; - double dr, dg, db; /* linear r,g,b scaled to 0..1 */ -} Background; - -/* Basic image formats; control the data but not the layout thereof. */ -#define BASE_FORMATS\ - (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR) - -/* Read a Pixel from a buffer. The code below stores the correct routine for - * the format in a function pointer, these are the routines: - */ -static void -gp_g8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = p->g = p->b = pp[0]; - p->a = 255; -} - -static void -gp_ga8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = p->g = p->b = pp[0]; - p->a = pp[1]; -} - -#ifdef PNG_FORMAT_AFIRST_SUPPORTED -static void -gp_ag8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = p->g = p->b = pp[1]; - p->a = pp[0]; -} -#endif - -static void -gp_rgb8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = 255; -} - -#ifdef PNG_FORMAT_BGR_SUPPORTED -static void -gp_bgr8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = 255; -} -#endif - -static void -gp_rgba8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = pp[3]; -} - -#ifdef PNG_FORMAT_BGR_SUPPORTED -static void -gp_bgra8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = pp[3]; -} -#endif - -#ifdef PNG_FORMAT_AFIRST_SUPPORTED -static void -gp_argb8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[1]; - p->g = pp[2]; - p->b = pp[3]; - p->a = pp[0]; -} -#endif - -#if defined(PNG_FORMAT_AFIRST_SUPPORTED) && defined(PNG_FORMAT_BGR_SUPPORTED) -static void -gp_abgr8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[3]; - p->g = pp[2]; - p->b = pp[1]; - p->a = pp[0]; -} -#endif - -static void -gp_g16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = p->g = p->b = pp[0]; - p->a = 65535; -} - -static void -gp_ga16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = p->g = p->b = pp[0]; - p->a = pp[1]; -} - -#ifdef PNG_FORMAT_AFIRST_SUPPORTED -static void -gp_ag16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = p->g = p->b = pp[1]; - p->a = pp[0]; -} -#endif - -static void -gp_rgb16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = 65535; -} - -#ifdef PNG_FORMAT_BGR_SUPPORTED -static void -gp_bgr16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = 65535; -} -#endif - -static void -gp_rgba16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = pp[3]; -} - -#ifdef PNG_FORMAT_BGR_SUPPORTED -static void -gp_bgra16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = pp[3]; -} -#endif - -#ifdef PNG_FORMAT_AFIRST_SUPPORTED -static void -gp_argb16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[1]; - p->g = pp[2]; - p->b = pp[3]; - p->a = pp[0]; -} -#endif - -#if defined(PNG_FORMAT_AFIRST_SUPPORTED) && defined(PNG_FORMAT_BGR_SUPPORTED) -static void -gp_abgr16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[3]; - p->g = pp[2]; - p->b = pp[1]; - p->a = pp[0]; -} -#endif - -/* Given a format, return the correct one of the above functions. */ -static void (* -get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb) -{ - /* The color-map flag is irrelevant here - the caller of the function - * returned must either pass the buffer or, for a color-mapped image, the - * correct entry in the color-map. - */ - if (format & PNG_FORMAT_FLAG_LINEAR) - { - if (format & PNG_FORMAT_FLAG_COLOR) - { -# ifdef PNG_FORMAT_BGR_SUPPORTED - if (format & PNG_FORMAT_FLAG_BGR) - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_abgr16; - - else -# endif - return gp_bgra16; - } - - else - return gp_bgr16; - } - - else -# endif - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_argb16; - - else -# endif - return gp_rgba16; - } - - else - return gp_rgb16; - } - } - - else - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_ag16; - - else -# endif - return gp_ga16; - } - - else - return gp_g16; - } - } - - else - { - if (format & PNG_FORMAT_FLAG_COLOR) - { -# ifdef PNG_FORMAT_BGR_SUPPORTED - if (format & PNG_FORMAT_FLAG_BGR) - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_abgr8; - - else -# endif - return gp_bgra8; - } - - else - return gp_bgr8; - } - - else -# endif - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_argb8; - - else -# endif - return gp_rgba8; - } - - else - return gp_rgb8; - } - } - - else - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_ag8; - - else -# endif - return gp_ga8; - } - - else - return gp_g8; - } - } -} - -/* Convertion between pixel formats. The code above effectively eliminates the - * component ordering changes leaving three basic changes: - * - * 1) Remove an alpha channel by pre-multiplication or compositing on a - * background color. (Adding an alpha channel is a no-op.) - * - * 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.) - * - * 3) Convert between 8-bit and 16-bit components. (Both directtions are - * relevant.) - * - * This gives the following base format conversion matrix: - * - * OUT: ----- 8-bit ----- ----- 16-bit ----- - * IN G GA RGB RGBA G GA RGB RGBA - * 8 G . . . . lin lin lin lin - * 8 GA bckg . bckc . pre' pre pre' pre - * 8 RGB g8 g8 . . glin glin lin lin - * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre - * 16 G sRGB sRGB sRGB sRGB . . . . - * 16 GA b16g unpg b16c unpc A . A . - * 16 RGB sG sG sRGB sRGB g16 g16 . . - * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . - * - * 8-bit to 8-bit: - * bckg: composite on gray background - * bckc: composite on color background - * g8: convert sRGB components to sRGB grayscale - * g8b: convert sRGB components to grayscale and composite on gray background - * - * 8-bit to 16-bit: - * lin: make sRGB components linear, alpha := 65535 - * pre: make sRGB components linear and premultiply by alpha (scale alpha) - * pre': as 'pre' but alpha := 65535 - * glin: make sRGB components linear, convert to grayscale, alpha := 65535 - * gpre: make sRGB components grayscale and linear and premultiply by alpha - * gpr': as 'gpre' but alpha := 65535 - * - * 16-bit to 8-bit: - * sRGB: convert linear components to sRGB, alpha := 255 - * unpg: unpremultiply gray component and convert to sRGB (scale alpha) - * unpc: unpremultiply color components and convert to sRGB (scale alpha) - * b16g: composite linear onto gray background and convert the result to sRGB - * b16c: composite linear onto color background and convert the result to sRGB - * sG: convert linear RGB to sRGB grayscale - * sGp: unpremultiply RGB then convert to sRGB grayscale - * sCp: unpremultiply RGB then convert to sRGB - * gb16: composite linear onto background and convert to sRGB grayscale - * (order doesn't matter, the composite and grayscale operations permute) - * cb16: composite linear onto background and convert to sRGB - * - * 16-bit to 16-bit: - * A: set alpha to 65535 - * g16: convert linear RGB to linear grayscale (alpha := 65535) - * g16': as 'g16' but alpha is unchanged - */ -/* Simple copy: */ -static void -gpc_noop(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = in->r; - out->g = in->g; - out->b = in->b; - out->a = in->a; -} - -#if ALLOW_UNUSED_GPC -static void -gpc_nop8(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - if (in->a == 0) - out->r = out->g = out->b = 255; - - else - { - out->r = in->r; - out->g = in->g; - out->b = in->b; - } - - out->a = in->a; -} -#endif - -#if ALLOW_UNUSED_GPC -static void -gpc_nop6(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - if (in->a == 0) - out->r = out->g = out->b = 65535; - - else - { - out->r = in->r; - out->g = in->g; - out->b = in->b; - } - - out->a = in->a; -} -#endif - -/* 8-bit to 8-bit conversions */ -/* bckg: composite on gray background */ -static void -gpc_bckg(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else if (in->a >= 255) - out->r = out->g = out->b = in->g; - - else - { - double a = in->a / 255.; - - out->r = out->g = out->b = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); - } - - out->a = 255; -} - -/* bckc: composite on color background */ -static void -gpc_bckc(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - { - out->r = back->ir; - out->g = back->ig; - out->b = back->ib; - } - - else if (in->a >= 255) - { - out->r = in->r; - out->g = in->g; - out->b = in->b; - } - - else - { - double a = in->a / 255.; - - out->r = sRGB(sRGB_to_d[in->r] * a + back->dr * (1-a)); - out->g = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); - out->b = sRGB(sRGB_to_d[in->b] * a + back->db * (1-a)); - } - - out->a = 255; -} - -/* g8: convert sRGB components to sRGB grayscale */ -static void -gpc_g8(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = in->g; - - else - out->r = out->g = out->b = - sRGB(YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = in->a; -} - -/* g8b: convert sRGB components to grayscale and composite on gray background */ -static void -gpc_g8b(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else if (in->a >= 255) - { - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = in->g; - - else - out->r = out->g = out->b = sRGB(YfromRGB( - sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - } - - else - { - double a = in->a/255.; - - out->r = out->g = out->b = sRGB(a * YfromRGB(sRGB_to_d[in->r], - sRGB_to_d[in->g], sRGB_to_d[in->b]) + back->dg * (1-a)); - } - - out->a = 255; -} - -/* 8-bit to 16-bit conversions */ -/* lin: make sRGB components linear, alpha := 65535 */ -static void -gpc_lin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilinear(in->r); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilinear(in->b); - } - - else - { - out->g = ilinear(in->g); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilinear(in->b); - } - - out->a = 65535; -} - -/* pre: make sRGB components linear and premultiply by alpha (scale alpha) */ -static void -gpc_pre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara(in->b, in->a); - } - - else - { - out->g = ilineara(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara(in->b, in->a); - } - - out->a = in->a * 257; -} - -/* pre': as 'pre' but alpha := 65535 */ -static void -gpc_preq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara(in->b, in->a); - } - - else - { - out->g = ilineara(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara(in->b, in->a); - } - - out->a = 65535; -} - -/* glin: make sRGB components linear, convert to grayscale, alpha := 65535 */ -static void -gpc_glin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilinear(in->g); - - else - out->r = out->g = out->b = u16d(65535 * - YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = 65535; -} - -/* gpre: make sRGB components grayscale and linear and premultiply by alpha */ -static void -gpc_gpre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara(in->g, in->a); - - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = 257 * in->a; -} - -/* gpr': as 'gpre' but alpha := 65535 */ -static void -gpc_gprq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara(in->g, in->a); - - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = 65535; -} - -/* 8-bit to 16-bit conversions for gAMA 45455 encoded values */ -/* Lin: make gAMA 45455 components linear, alpha := 65535 */ -static void -gpc_Lin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilinear_g22(in->r); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilinear_g22(in->b); - } - - else - { - out->g = ilinear_g22(in->g); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilinear_g22(in->b); - } - - out->a = 65535; -} - -#if ALLOW_UNUSED_GPC -/* Pre: make gAMA 45455 components linear and premultiply by alpha (scale alpha) - */ -static void -gpc_Pre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara_g22(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara_g22(in->b, in->a); - } - - else - { - out->g = ilineara_g22(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara_g22(in->b, in->a); - } - - out->a = in->a * 257; -} -#endif - -#if ALLOW_UNUSED_GPC -/* Pre': as 'Pre' but alpha := 65535 */ -static void -gpc_Preq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara_g22(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara_g22(in->b, in->a); - } - - else - { - out->g = ilineara_g22(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara_g22(in->b, in->a); - } - - out->a = 65535; -} -#endif - -#if ALLOW_UNUSED_GPC -/* Glin: make gAMA 45455 components linear, convert to grayscale, alpha := 65535 - */ -static void -gpc_Glin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilinear_g22(in->g); - - else - out->r = out->g = out->b = u16d(65535 * - YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); - - out->a = 65535; -} -#endif - -#if ALLOW_UNUSED_GPC -/* Gpre: make gAMA 45455 components grayscale and linear and premultiply by - * alpha. - */ -static void -gpc_Gpre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara_g22(in->g, in->a); - - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); - - out->a = 257 * in->a; -} -#endif - -#if ALLOW_UNUSED_GPC -/* Gpr': as 'Gpre' but alpha := 65535 */ -static void -gpc_Gprq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara_g22(in->g, in->a); - - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); - - out->a = 65535; -} -#endif - -/* 16-bit to 8-bit conversions */ -/* sRGB: convert linear components to sRGB, alpha := 255 */ -static void -gpc_sRGB(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = isRGB(in->r); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = isRGB(in->b); - } - - else - { - out->g = isRGB(in->g); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = isRGB(in->b); - } - - out->a = 255; -} - -/* unpg: unpremultiply gray component and convert to sRGB (scale alpha) */ -static void -gpc_unpg(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = out->g = out->b = sRGB((double)in->g / in->a); - out->a = u8d(in->a / 257.); - } -} - -/* unpc: unpremultiply color components and convert to sRGB (scale alpha) */ -static void -gpc_unpc(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = sRGB((double)in->r / in->a); - out->g = sRGB((double)in->g / in->a); - out->b = sRGB((double)in->b / in->a); - out->a = u8d(in->a / 257.); - } -} - -/* b16g: composite linear onto gray background and convert the result to sRGB */ -static void -gpc_b16g(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else - { - double a = in->a/65535.; - double a1 = 1-a; - - a /= 65535; - out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); - } - - out->a = 255; -} - -/* b16c: composite linear onto color background and convert the result to sRGB*/ -static void -gpc_b16c(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - { - out->r = back->ir; - out->g = back->ig; - out->b = back->ib; - } - - else - { - double a = in->a/65535.; - double a1 = 1-a; - - a /= 65535; - out->r = sRGB(in->r * a + back->dr * a1); - out->g = sRGB(in->g * a + back->dg * a1); - out->b = sRGB(in->b * a + back->db * a1); - } - - out->a = 255; -} - -/* sG: convert linear RGB to sRGB grayscale */ -static void -gpc_sG(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/65535); - out->a = 255; -} - -/* sGp: unpremultiply RGB then convert to sRGB grayscale */ -static void -gpc_sGp(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/in->a); - out->a = u8d(in->a / 257.); - } -} - -/* sCp: unpremultiply RGB then convert to sRGB */ -static void -gpc_sCp(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = sRGB((double)in->r / in->a); - out->g = sRGB((double)in->g / in->a); - out->b = sRGB((double)in->b / in->a); - out->a = u8d(in->a / 257.); - } -} - -/* gb16: composite linear onto background and convert to sRGB grayscale */ -/* (order doesn't matter, the composite and grayscale operations permute) */ -static void -gpc_gb16(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else if (in->a >= 65535) - out->r = out->g = out->b = isRGB(in->g); - - else - { - double a = in->a / 65535.; - double a1 = 1-a; - - a /= 65535; - out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); - } - - out->a = 255; -} - -/* cb16: composite linear onto background and convert to sRGB */ -static void -gpc_cb16(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - { - out->r = back->ir; - out->g = back->ig; - out->b = back->ib; - } - - else if (in->a >= 65535) - { - out->r = isRGB(in->r); - out->g = isRGB(in->g); - out->b = isRGB(in->b); - } - - else - { - double a = in->a / 65535.; - double a1 = 1-a; - - a /= 65535; - out->r = sRGB(in->r * a + back->dr * a1); - out->g = sRGB(in->g * a + back->dg * a1); - out->b = sRGB(in->b * a + back->db * a1); - } - - out->a = 255; -} - -/* 16-bit to 16-bit conversions */ -/* A: set alpha to 65535 */ -static void -gpc_A(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = in->r; - out->g = in->g; - out->b = in->b; - out->a = 65535; -} - -/* g16: convert linear RGB to linear grayscale (alpha := 65535) */ -static void -gpc_g16(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); - out->a = 65535; -} - -/* g16': as 'g16' but alpha is unchanged */ -static void -gpc_g16q(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); - out->a = in->a; -} - -#if ALLOW_UNUSED_GPC -/* Unused functions (to hide them from GCC unused function warnings) */ -void (* const gpc_unused[]) - (Pixel *out, const Pixel *in, const Background *back) = -{ - gpc_Pre, gpc_Preq, gpc_Glin, gpc_Gpre, gpc_Gprq, gpc_nop8, gpc_nop6 -}; -#endif - -/* OUT: ----- 8-bit ----- ----- 16-bit ----- - * IN G GA RGB RGBA G GA RGB RGBA - * 8 G . . . . lin lin lin lin - * 8 GA bckg . bckc . pre' pre pre' pre - * 8 RGB g8 g8 . . glin glin lin lin - * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre - * 16 G sRGB sRGB sRGB sRGB . . . . - * 16 GA b16g unpg b16c unpc A . A . - * 16 RGB sG sG sRGB sRGB g16 g16 . . - * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . - * - * The matrix is held in an array indexed thus: - * - * gpc_fn[out_format & BASE_FORMATS][in_format & BASE_FORMATS]; - */ -/* This will produce a compile time error if the FORMAT_FLAG values don't - * match the above matrix! - */ -#if PNG_FORMAT_FLAG_ALPHA == 1 && PNG_FORMAT_FLAG_COLOR == 2 &&\ - PNG_FORMAT_FLAG_LINEAR == 4 -static void (* const gpc_fn[8/*in*/][8/*out*/]) - (Pixel *out, const Pixel *in, const Background *back) = -{ -/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ - {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_Lin, gpc_Lin, gpc_Lin, gpc_Lin }, - {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, - {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, - {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, - {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, - {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, - {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, - {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} -}; - -/* The array is repeated for the cases where both the input and output are color - * mapped because then different algorithms are used. - */ -static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/]) - (Pixel *out, const Pixel *in, const Background *back) = -{ -/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ - {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_lin, gpc_lin, gpc_lin, gpc_lin }, - {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, - {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, - {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, - {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, - {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, - {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, - {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} -}; - -/* The error arrays record the error in the same matrix; 64 entries, however - * the different algorithms used in libpng for colormap and direct conversions - * mean that four separate matrices are used (for each combination of - * colormapped and direct.) - * - * In some cases the conversion between sRGB formats goes via a linear - * intermediate; an sRGB to linear conversion (as above) is followed by a simple - * linear to sRGB step with no other conversions. This is done by a separate - * error array from an arbitrary 'in' format to one of the four basic outputs - * (since final output is always sRGB not colormapped). - * - * These arrays may be modified if the --accumulate flag is set during the run; - * then instead of logging errors they are simply added in. - * - * The three entries are currently for transparent, partially transparent and - * opaque input pixel values. Notice that alpha should be exact in each case. - * - * Errors in alpha should only occur when converting from a direct format - * to a colormapped format, when alpha is effectively smashed (so large - * errors can occur.) There should be no error in the '0' and 'opaque' - * values. The fourth entry in the array is used for the alpha error (and it - * should always be zero for the 'via linear' case since this is never color - * mapped.) - * - * Mapping to a colormap smashes the colors, it is necessary to have separate - * values for these cases because they are much larger; it is very much - * impossible to obtain a reasonable result, these are held in - * gpc_error_to_colormap. - */ -#if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */ -/* START MACHINE GENERATED */ -static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] = -{ - { /* input: sRGB-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: sRGB-gray+alpha */ - { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: sRGB-rgb */ - { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: sRGB-rgb+alpha */ - { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-gray */ - { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-gray+alpha */ - { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, - { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-rgb */ - { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, - { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-rgb+alpha */ - { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 }, - { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-rgb */ - { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 }, - { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 }, - { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 } - }, { /* input: color-mapped-sRGB-rgb+alpha */ - { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 }, - { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 }, - { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 } - }, { /* input: color-mapped-linear-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 } - } -}; -static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] = -{ - { /* input: sRGB-gray */ - { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 } - }, { /* input: sRGB-gray+alpha */ - { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 } - }, { /* input: sRGB-rgb */ - { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 } - }, { /* input: sRGB-rgb+alpha */ - { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 } - }, { /* input: linear-gray */ - { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } - }, { /* input: linear-gray+alpha */ - { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } - }, { /* input: linear-rgb */ - { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } - }, { /* input: linear-rgb+alpha */ - { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } - }, { /* input: color-mapped-sRGB-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-rgb */ - { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 } - }, { /* input: color-mapped-sRGB-rgb+alpha */ - { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 } - }, { /* input: color-mapped-linear-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - } -}; -static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] = -{ - { /* input: sRGB-gray */ - { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, - { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 } - }, { /* input: sRGB-gray+alpha */ - { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 }, - { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 } - }, { /* input: sRGB-rgb */ - { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 }, - { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 } - }, { /* input: sRGB-rgb+alpha */ - { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 }, - { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 } - }, { /* input: linear-gray */ - { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, - { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 } - }, { /* input: linear-gray+alpha */ - { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 }, - { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 } - }, { /* input: linear-rgb */ - { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 }, - { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 } - }, { /* input: linear-rgb+alpha */ - { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 }, - { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 } - } -}; -/* END MACHINE GENERATED */ -#endif /* COLORMAP flag check */ -#endif /* flag checks */ - -typedef struct -{ - /* Basic pixel information: */ - Image* in_image; /* Input image */ - const Image* out_image; /* Output image */ - - /* 'background' is the value passed to the gpc_ routines, it may be NULL if - * it should not be used (*this* program has an error if it crashes as a - * result!) - */ - Background background_color; - const Background* background; - - /* Precalculated values: */ - int in_opaque; /* Value of input alpha that is opaque */ - int is_palette; /* Sample values come from the palette */ - int accumulate; /* Accumlate component errors (don't log) */ - int output_8bit; /* Output is 8 bit (else 16 bit) */ - - void (*in_gp)(Pixel*, png_const_voidp); - void (*out_gp)(Pixel*, png_const_voidp); - - void (*transform)(Pixel *out, const Pixel *in, const Background *back); - /* A function to perform the required transform */ - - void (*from_linear)(Pixel *out, const Pixel *in, const Background *back); - /* For 'via_linear' transforms the final, from linear, step, else NULL */ - - png_uint_16 error[4]; - /* Three error values for transparent, partially transparent and opaque - * input pixels (in turn). - */ - - png_uint_16 *error_ptr; - /* Where these are stored in the static array (for 'accumulate') */ -} -Transform; - -/* Return a 'transform' as above for the given format conversion. */ -static void -transform_from_formats(Transform *result, Image *in_image, - const Image *out_image, png_const_colorp background, int via_linear) -{ - png_uint_32 in_format, out_format; - png_uint_32 in_base, out_base; - - memset(result, 0, sizeof *result); - - /* Store the original images for error messages */ - result->in_image = in_image; - result->out_image = out_image; - - in_format = in_image->image.format; - out_format = out_image->image.format; - - if (in_format & PNG_FORMAT_FLAG_LINEAR) - result->in_opaque = 65535; - else - result->in_opaque = 255; - - result->output_8bit = (out_format & PNG_FORMAT_FLAG_LINEAR) == 0; - - result->is_palette = 0; /* set by caller if required */ - result->accumulate = (in_image->opts & ACCUMULATE) != 0; - - /* The loaders (which need the ordering information) */ - result->in_gp = get_pixel(in_format); - result->out_gp = get_pixel(out_format); - - /* Remove the ordering information: */ - in_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; - in_base = in_format & BASE_FORMATS; - out_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; - out_base = out_format & BASE_FORMATS; - - if (via_linear) - { - /* Check for an error in this program: */ - if (out_format & (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLORMAP)) - { - fprintf(stderr, "internal transform via linear error 0x%x->0x%x\n", - in_format, out_format); - exit(1); - } - - result->transform = gpc_fn[in_base][out_base | PNG_FORMAT_FLAG_LINEAR]; - result->from_linear = gpc_fn[out_base | PNG_FORMAT_FLAG_LINEAR][out_base]; - result->error_ptr = gpc_error_via_linear[in_format][out_format]; - } - - else if (~in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) - { - /* The input is not colormapped but the output is, the errors will - * typically be large (only the grayscale-no-alpha case permits preserving - * even 8-bit values.) - */ - result->transform = gpc_fn[in_base][out_base]; - result->from_linear = NULL; - result->error_ptr = gpc_error_to_colormap[in_base][out_base]; - } - - else - { - /* The caller handles the colormap->pixel value conversion, so the - * transform function just gets a pixel value, however because libpng - * currently contains a different implementation for mapping a colormap if - * both input and output are colormapped we need different conversion - * functions to deal with errors in the libpng implementation. - */ - if (in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) - result->transform = gpc_fn_colormapped[in_base][out_base]; - else - result->transform = gpc_fn[in_base][out_base]; - result->from_linear = NULL; - result->error_ptr = gpc_error[in_format][out_format]; - } - - /* Follow the libpng simplified API rules to work out what to pass to the gpc - * routines as a background value, if one is not required pass NULL so that - * this program crashes in the even of a programming error. - */ - result->background = NULL; /* default: not required */ - - /* Rule 1: background only need be supplied if alpha is to be removed */ - if (in_format & ~out_format & PNG_FORMAT_FLAG_ALPHA) - { - /* The input value is 'NULL' to use the background and (otherwise) an sRGB - * background color (to use a solid color). The code above uses a fixed - * byte value, BUFFER_INIT8, for buffer even for 16-bit output. For - * linear (16-bit) output the sRGB background color is ignored; the - * composition is always on the background (so BUFFER_INIT8 * 257), except - * that for the colormap (i.e. linear colormapped output) black is used. - */ - result->background = &result->background_color; - - if (out_format & PNG_FORMAT_FLAG_LINEAR || via_linear) - { - if (out_format & PNG_FORMAT_FLAG_COLORMAP) - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = 0; - result->background_color.dr = - result->background_color.dg = - result->background_color.db = 0; - } - - else - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = BUFFER_INIT8 * 257; - result->background_color.dr = - result->background_color.dg = - result->background_color.db = 0; - } - } - - else /* sRGB output */ - { - if (background != NULL) - { - if (out_format & PNG_FORMAT_FLAG_COLOR) - { - result->background_color.ir = background->red; - result->background_color.ig = background->green; - result->background_color.ib = background->blue; - /* TODO: sometimes libpng uses the power law conversion here, how - * to handle this? - */ - result->background_color.dr = sRGB_to_d[background->red]; - result->background_color.dg = sRGB_to_d[background->green]; - result->background_color.db = sRGB_to_d[background->blue]; - } - - else /* grayscale: libpng only looks at 'g' */ - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = background->green; - /* TODO: sometimes libpng uses the power law conversion here, how - * to handle this? - */ - result->background_color.dr = - result->background_color.dg = - result->background_color.db = sRGB_to_d[background->green]; - } - } - - else if ((out_format & PNG_FORMAT_FLAG_COLORMAP) == 0) - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = BUFFER_INIT8; - /* TODO: sometimes libpng uses the power law conversion here, how - * to handle this? - */ - result->background_color.dr = - result->background_color.dg = - result->background_color.db = sRGB_to_d[BUFFER_INIT8]; - } - - /* Else the output is colormapped and a background color must be - * provided; if pngstest crashes then that is a bug in this program - * (though libpng should png_error as well.) - */ - else - result->background = NULL; - } - } - - if (result->background == NULL) - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = -1; /* not used */ - result->background_color.dr = - result->background_color.dg = - result->background_color.db = 1E30; /* not used */ - } - - - /* Copy the error values into the Transform: */ - result->error[0] = result->error_ptr[0]; - result->error[1] = result->error_ptr[1]; - result->error[2] = result->error_ptr[2]; - result->error[3] = result->error_ptr[3]; -} - - -/* Compare two pixels. - * - * OLD error values: -static int error_to_linear = 811; * by experiment * -static int error_to_linear_grayscale = 424; * by experiment * -static int error_to_sRGB = 6; * by experiment * -static int error_to_sRGB_grayscale = 17; * libpng error by calculation + - 2 by experiment * -static int error_in_compose = 2; * by experiment * -static int error_in_premultiply = 1; - * - * The following is *just* the result of a round trip from 8-bit sRGB to linear - * then back to 8-bit sRGB when it is done by libpng. There are two problems: - * - * 1) libpng currently uses a 2.2 power law with no linear segment, this results - * in instability in the low values and even with 16-bit precision sRGB(1) ends - * up mapping to sRGB(0) as a result of rounding in the 16-bit representation. - * This gives an error of 1 in the handling of value 1 only. - * - * 2) libpng currently uses an intermediate 8-bit linear value in gamma - * correction of 8-bit values. This results in many more errors, the worse of - * which is mapping sRGB(14) to sRGB(0). - * - * The general 'error_via_linear' is more complex because of pre-multiplication, - * this compounds the 8-bit errors according to the alpha value of the pixel. - * As a result 256 values are pre-calculated for error_via_linear. - */ -#if 0 -static int error_in_libpng_gamma; -static int error_via_linear[256]; /* Indexed by 8-bit alpha */ - -static void -init_error_via_linear(void) -{ - int alpha; - - error_via_linear[0] = 255; /* transparent pixel */ - - for (alpha=1; alpha<=255; ++alpha) - { - /* 16-bit values less than 128.5 get rounded to 8-bit 0 and so the worst - * case error arises with 16-bit 128.5, work out what sRGB - * (non-associated) value generates 128.5; any value less than this is - * going to map to 0, so the worst error is floor(value). - * - * Note that errors are considerably higher (more than a factor of 2) - * because libpng uses a simple power law for sRGB data at present. - * - * Add .1 for arithmetic errors inside libpng. - */ - double v = floor(255*pow(.5/*(128.5 * 255 / 65535)*/ / alpha, 1/2.2)+.1); - - error_via_linear[alpha] = (int)v; - } - - /* This is actually 14.99, but, despite the closeness to 15, 14 seems to work - * ok in this case. - */ - error_in_libpng_gamma = 14; -} -#endif - -static void -print_pixel(char string[64], const Pixel *pixel, png_uint_32 format) -{ - switch (format & (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR)) - { - case 0: - sprintf(string, "%s(%d)", format_names[format], pixel->g); - break; - - case PNG_FORMAT_FLAG_ALPHA: - sprintf(string, "%s(%d,%d)", format_names[format], pixel->g, - pixel->a); - break; - - case PNG_FORMAT_FLAG_COLOR: - sprintf(string, "%s(%d,%d,%d)", format_names[format], - pixel->r, pixel->g, pixel->b); - break; - - case PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA: - sprintf(string, "%s(%d,%d,%d,%d)", format_names[format], - pixel->r, pixel->g, pixel->b, pixel->a); - break; - - default: - sprintf(string, "invalid-format"); - break; - } -} - -static int -logpixel(const Transform *transform, png_uint_32 x, png_uint_32 y, - const Pixel *in, const Pixel *calc, const Pixel *out, const char *reason) -{ - const png_uint_32 in_format = transform->in_image->image.format; - const png_uint_32 out_format = transform->out_image->image.format; - - png_uint_32 back_format = out_format & ~PNG_FORMAT_FLAG_ALPHA; - const char *via_linear = ""; - - char pixel_in[64], pixel_calc[64], pixel_out[64], pixel_loc[64]; - char background_info[100]; - - print_pixel(pixel_in, in, in_format); - print_pixel(pixel_calc, calc, out_format); - print_pixel(pixel_out, out, out_format); - - if (transform->is_palette) - sprintf(pixel_loc, "palette: %lu", (unsigned long)y); - else - sprintf(pixel_loc, "%lu,%lu", (unsigned long)x, (unsigned long)y); - - if (transform->from_linear != NULL) - { - via_linear = " (via linear)"; - /* And as a result the *read* format which did any background processing - * was itself linear, so the background color information is also - * linear. - */ - back_format |= PNG_FORMAT_FLAG_LINEAR; - } - - if (transform->background != NULL) - { - Pixel back; - char pixel_back[64]; - - back.r = transform->background->ir; - back.g = transform->background->ig; - back.b = transform->background->ib; - back.a = -1; /* not used */ - - print_pixel(pixel_back, &back, back_format); - sprintf(background_info, " on background %s", pixel_back); - } - - else - background_info[0] = 0; - - if (transform->in_image->file_name != transform->out_image->file_name) - { - char error_buffer[512]; - sprintf(error_buffer, - "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" - "Use --preserve and examine: ", pixel_loc, reason, via_linear, - pixel_in, background_info, pixel_out, pixel_calc); - return logerror(transform->in_image, transform->in_image->file_name, - error_buffer, transform->out_image->file_name); - } - - else - { - char error_buffer[512]; - sprintf(error_buffer, - "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" - " The error happened when reading the original file with this format.", - pixel_loc, reason, via_linear, pixel_in, background_info, pixel_out, - pixel_calc); - return logerror(transform->in_image, transform->in_image->file_name, - error_buffer, ""); - } -} - -static int -cmppixel(Transform *transform, png_const_voidp in, png_const_voidp out, - png_uint_32 x, png_uint_32 y/*or palette index*/) -{ - int maxerr; - png_const_charp errmsg; - Pixel pixel_in, pixel_calc, pixel_out; - - transform->in_gp(&pixel_in, in); - - if (transform->from_linear == NULL) - transform->transform(&pixel_calc, &pixel_in, transform->background); - - else - { - transform->transform(&pixel_out, &pixel_in, transform->background); - transform->from_linear(&pixel_calc, &pixel_out, NULL); - } - - transform->out_gp(&pixel_out, out); - - /* Eliminate the case where the input and output values match exactly. */ - if (pixel_calc.a == pixel_out.a && pixel_calc.r == pixel_out.r && - pixel_calc.g == pixel_out.g && pixel_calc.b == pixel_out.b) - return 1; - - /* Eliminate the case where the output pixel is transparent and the output - * is 8-bit - any component values are valid. Don't check the input alpha - * here to also skip the 16-bit small alpha cases. - */ - if (transform->output_8bit && pixel_calc.a == 0 && pixel_out.a == 0) - return 1; - - /* Check for alpha errors first; an alpha error can damage the components too - * so avoid spurious checks on components if one is found. - */ - errmsg = NULL; - { - int err_a = abs(pixel_calc.a-pixel_out.a); - - if (err_a > transform->error[3]) - { - /* If accumulating check the components too */ - if (transform->accumulate) - transform->error[3] = (png_uint_16)err_a; - - else - errmsg = "alpha"; - } - } - - /* Now if *either* of the output alphas are 0 but alpha is within tolerance - * eliminate the 8-bit component comparison. - */ - if (errmsg == NULL && transform->output_8bit && - (pixel_calc.a == 0 || pixel_out.a == 0)) - return 1; - - if (errmsg == NULL) /* else just signal an alpha error */ - { - int err_r = abs(pixel_calc.r - pixel_out.r); - int err_g = abs(pixel_calc.g - pixel_out.g); - int err_b = abs(pixel_calc.b - pixel_out.b); - int limit; - - if ((err_r | err_g | err_b) == 0) - return 1; /* exact match */ - - /* Mismatch on a component, check the input alpha */ - if (pixel_in.a >= transform->in_opaque) - { - errmsg = "opaque component"; - limit = 2; /* opaque */ - } - - else if (pixel_in.a > 0) - { - errmsg = "alpha component"; - limit = 1; /* partially transparent */ - } - - else - { - errmsg = "transparent component (background)"; - limit = 0; /* transparent */ - } - - maxerr = err_r; - if (maxerr < err_g) maxerr = err_g; - if (maxerr < err_b) maxerr = err_b; - - if (maxerr <= transform->error[limit]) - return 1; /* within the error limits */ - - /* Handle a component mis-match; log it, just return an error code, or - * accumulate it. - */ - if (transform->accumulate) - { - transform->error[limit] = (png_uint_16)maxerr; - return 1; /* to cause the caller to keep going */ - } - } - - /* Failure to match and not accumulating, so the error must be logged. */ - return logpixel(transform, x, y, &pixel_in, &pixel_calc, &pixel_out, errmsg); -} - -static png_byte -component_loc(png_byte loc[4], png_uint_32 format) -{ - /* Given a format return the number of channels and the location of - * each channel. - * - * The mask 'loc' contains the component offset of the channels in the - * following order. Note that if 'format' is grayscale the entries 1-3 must - * all contain the location of the gray channel. - * - * 0: alpha - * 1: red or gray - * 2: green or gray - * 3: blue or gray - */ - png_byte channels; - - if (format & PNG_FORMAT_FLAG_COLOR) - { - channels = 3; - - loc[2] = 1; - -# ifdef PNG_FORMAT_BGR_SUPPORTED - if (format & PNG_FORMAT_FLAG_BGR) - { - loc[1] = 2; - loc[3] = 0; - } - - else -# endif - { - loc[1] = 0; - loc[3] = 2; - } - } - - else - { - channels = 1; - loc[1] = loc[2] = loc[3] = 0; - } - - if (format & PNG_FORMAT_FLAG_ALPHA) - { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - { - loc[0] = 0; - ++loc[1]; - ++loc[2]; - ++loc[3]; - } - - else -# endif - loc[0] = channels; - - ++channels; - } - - else - loc[0] = 4; /* not present */ - - return channels; -} - -/* Compare two images, the original 'a', which was written out then read back in - * to * give image 'b'. The formats may have been changed. - */ -static int -compare_two_images(Image *a, Image *b, int via_linear, - png_const_colorp background) -{ - ptrdiff_t stridea = a->stride; - ptrdiff_t strideb = b->stride; - png_const_bytep rowa = a->buffer+16; - png_const_bytep rowb = b->buffer+16; - const png_uint_32 width = a->image.width; - const png_uint_32 height = a->image.height; - const png_uint_32 formata = a->image.format; - const png_uint_32 formatb = b->image.format; - const unsigned int a_sample = PNG_IMAGE_SAMPLE_SIZE(formata); - const unsigned int b_sample = PNG_IMAGE_SAMPLE_SIZE(formatb); - int alpha_added, alpha_removed; - int bchannels; - int btoa[4]; - png_uint_32 y; - Transform tr; - - /* This should never happen: */ - if (width != b->image.width || height != b->image.height) - return logerror(a, a->file_name, ": width x height changed: ", - b->file_name); - - /* Set up the background and the transform */ - transform_from_formats(&tr, a, b, background, via_linear); - - /* Find the first row and inter-row space. */ - if (!(formata & PNG_FORMAT_FLAG_COLORMAP) && - (formata & PNG_FORMAT_FLAG_LINEAR)) - stridea *= 2; - - if (!(formatb & PNG_FORMAT_FLAG_COLORMAP) && - (formatb & PNG_FORMAT_FLAG_LINEAR)) - strideb *= 2; - - if (stridea < 0) rowa += (height-1) * (-stridea); - if (strideb < 0) rowb += (height-1) * (-strideb); - - /* First shortcut the two colormap case by comparing the image data; if it - * matches then we expect the colormaps to match, although this is not - * absolutely necessary for an image match. If the colormaps fail to match - * then there is a problem in libpng. - */ - if (formata & formatb & PNG_FORMAT_FLAG_COLORMAP) - { - /* Only check colormap entries that actually exist; */ - png_const_bytep ppa, ppb; - int match; - png_byte in_use[256], amax = 0, bmax = 0; - - memset(in_use, 0, sizeof in_use); - - ppa = rowa; - ppb = rowb; - - /* Do this the slow way to accumulate the 'in_use' flags, don't break out - * of the loop until the end; this validates the color-mapped data to - * ensure all pixels are valid color-map indexes. - */ - for (y=0, match=1; y bmax) - bmax = bval; - - if (bval != aval) - match = 0; - - in_use[aval] = 1; - if (aval > amax) - amax = aval; - } - } - - /* If the buffers match then the colormaps must too. */ - if (match) - { - /* Do the color-maps match, entry by entry? Only check the 'in_use' - * entries. An error here should be logged as a color-map error. - */ - png_const_bytep a_cmap = (png_const_bytep)a->colormap; - png_const_bytep b_cmap = (png_const_bytep)b->colormap; - int result = 1; /* match by default */ - - /* This is used in logpixel to get the error message correct. */ - tr.is_palette = 1; - - for (y=0; y<256; ++y, a_cmap += a_sample, b_cmap += b_sample) - if (in_use[y]) - { - /* The colormap entries should be valid, but because libpng doesn't - * do any checking at present the original image may contain invalid - * pixel values. These cause an error here (at present) unless - * accumulating errors in which case the program just ignores them. - */ - if (y >= a->image.colormap_entries) - { - if ((a->opts & ACCUMULATE) == 0) - { - char pindex[9]; - sprintf(pindex, "%lu[%lu]", (unsigned long)y, - (unsigned long)a->image.colormap_entries); - logerror(a, a->file_name, ": bad pixel index: ", pindex); - } - result = 0; - } - - else if (y >= b->image.colormap_entries) - { - if ((a->opts & ACCUMULATE) == 0) - { - char pindex[9]; - sprintf(pindex, "%lu[%lu]", (unsigned long)y, - (unsigned long)b->image.colormap_entries); - logerror(b, b->file_name, ": bad pixel index: ", pindex); - } - result = 0; - } - - /* All the mismatches are logged here; there can only be 256! */ - else if (!cmppixel(&tr, a_cmap, b_cmap, 0, y)) - result = 0; - } - - /* If reqested copy the error values back from the Transform. */ - if (a->opts & ACCUMULATE) - { - tr.error_ptr[0] = tr.error[0]; - tr.error_ptr[1] = tr.error[1]; - tr.error_ptr[2] = tr.error[2]; - tr.error_ptr[3] = tr.error[3]; - result = 1; /* force a continue */ - } - - return result; - } - - /* else the image buffers don't match pixel-wise so compare sample values - * instead, but first validate that the pixel indexes are in range (but - * only if not accumulating, when the error is ignored.) - */ - else if ((a->opts & ACCUMULATE) == 0) - { - /* Check the original image first, - * TODO: deal with input images with bad pixel values? - */ - if (amax >= a->image.colormap_entries) - { - char pindex[9]; - sprintf(pindex, "%d[%lu]", amax, - (unsigned long)a->image.colormap_entries); - return logerror(a, a->file_name, ": bad pixel index: ", pindex); - } - - else if (bmax >= b->image.colormap_entries) - { - char pindex[9]; - sprintf(pindex, "%d[%lu]", bmax, - (unsigned long)b->image.colormap_entries); - return logerror(b, b->file_name, ": bad pixel index: ", pindex); - } - } - } - - /* We can directly compare pixel values without the need to use the read - * or transform support (i.e. a memory compare) if: - * - * 1) The bit depth has not changed. - * 2) RGB to grayscale has not been done (the reverse is ok; we just compare - * the three RGB values to the original grayscale.) - * 3) An alpha channel has not been removed from an 8-bit format, or the - * 8-bit alpha value of the pixel was 255 (opaque). - * - * If an alpha channel has been *added* then it must have the relevant opaque - * value (255 or 65535). - * - * The fist two the tests (in the order given above) (using the boolean - * equivalence !a && !b == !(a || b)) - */ - if (!(((formata ^ formatb) & PNG_FORMAT_FLAG_LINEAR) | - (formata & (formatb ^ PNG_FORMAT_FLAG_COLOR) & PNG_FORMAT_FLAG_COLOR))) - { - /* Was an alpha channel changed? */ - const png_uint_32 alpha_changed = (formata ^ formatb) & - PNG_FORMAT_FLAG_ALPHA; - - /* Was an alpha channel removed? (The third test.) If so the direct - * comparison is only possible if the input alpha is opaque. - */ - alpha_removed = (formata & alpha_changed) != 0; - - /* Was an alpha channel added? */ - alpha_added = (formatb & alpha_changed) != 0; - - /* The channels may have been moved between input and output, this finds - * out how, recording the result in the btoa array, which says where in - * 'a' to find each channel of 'b'. If alpha was added then btoa[alpha] - * ends up as 4 (and is not used.) - */ - { - int i; - png_byte aloc[4]; - png_byte bloc[4]; - - /* The following are used only if the formats match, except that - * 'bchannels' is a flag for matching formats. btoa[x] says, for each - * channel in b, where to find the corresponding value in a, for the - * bchannels. achannels may be different for a gray to rgb transform - * (a will be 1 or 2, b will be 3 or 4 channels.) - */ - (void)component_loc(aloc, formata); - bchannels = component_loc(bloc, formatb); - - /* Hence the btoa array. */ - for (i=0; i<4; ++i) if (bloc[i] < 4) - btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */ - - if (alpha_added) - alpha_added = bloc[0]; /* location of alpha channel in image b */ - - else - alpha_added = 4; /* Won't match an image b channel */ - - if (alpha_removed) - alpha_removed = aloc[0]; /* location of alpha channel in image a */ - - else - alpha_removed = 4; - } - } - - else - { - /* Direct compare is not possible, cancel out all the corresponding local - * variables. - */ - bchannels = 0; - alpha_removed = alpha_added = 4; - btoa[3] = btoa[2] = btoa[1] = btoa[0] = 4; /* 4 == not present */ - } - - for (y=0; ycolormap + a_sample * *ppa++; - else - psa = ppa, ppa += a_sample; - - if (formatb & PNG_FORMAT_FLAG_COLORMAP) - psb = (png_const_bytep)b->colormap + b_sample * *ppb++; - else - psb = ppb, ppb += b_sample; - - /* Do the fast test if possible. */ - if (bchannels) - { - /* Check each 'b' channel against either the corresponding 'a' - * channel or the opaque alpha value, as appropriate. If - * alpha_removed value is set (not 4) then also do this only if the - * 'a' alpha channel (alpha_removed) is opaque; only relevant for - * the 8-bit case. - */ - if (formatb & PNG_FORMAT_FLAG_LINEAR) /* 16-bit checks */ - { - png_const_uint_16p pua = aligncastconst(png_const_uint_16p, psa); - png_const_uint_16p pub = aligncastconst(png_const_uint_16p, psb); - - switch (bchannels) - { - case 4: - if (pua[btoa[3]] != pub[3]) break; - case 3: - if (pua[btoa[2]] != pub[2]) break; - case 2: - if (pua[btoa[1]] != pub[1]) break; - case 1: - if (pua[btoa[0]] != pub[0]) break; - if (alpha_added != 4 && pub[alpha_added] != 65535) break; - continue; /* x loop */ - default: - break; /* impossible */ - } - } - - else if (alpha_removed == 4 || psa[alpha_removed] == 255) - { - switch (bchannels) - { - case 4: - if (psa[btoa[3]] != psb[3]) break; - case 3: - if (psa[btoa[2]] != psb[2]) break; - case 2: - if (psa[btoa[1]] != psb[1]) break; - case 1: - if (psa[btoa[0]] != psb[0]) break; - if (alpha_added != 4 && psb[alpha_added] != 255) break; - continue; /* x loop */ - default: - break; /* impossible */ - } - } - } - - /* If we get to here the fast match failed; do the slow match for this - * pixel. - */ - if (!cmppixel(&tr, psa, psb, x, y) && (a->opts & KEEP_GOING) == 0) - return 0; /* error case */ - } - } - - /* If reqested copy the error values back from the Transform. */ - if (a->opts & ACCUMULATE) - { - tr.error_ptr[0] = tr.error[0]; - tr.error_ptr[1] = tr.error[1]; - tr.error_ptr[2] = tr.error[2]; - tr.error_ptr[3] = tr.error[3]; - } - - return 1; -} - -/* Read the file; how the read gets done depends on which of input_file and - * input_memory have been set. - */ -static int -read_file(Image *image, png_uint_32 format, png_const_colorp background) -{ - memset(&image->image, 0, sizeof image->image); - image->image.version = PNG_IMAGE_VERSION; - - if (image->input_memory != NULL) - { - if (!png_image_begin_read_from_memory(&image->image, image->input_memory, - image->input_memory_size)) - return logerror(image, "memory init: ", image->file_name, ""); - } - -# ifdef PNG_STDIO_SUPPORTED - else if (image->input_file != NULL) - { - if (!png_image_begin_read_from_stdio(&image->image, image->input_file)) - return logerror(image, "stdio init: ", image->file_name, ""); - } - - else - { - if (!png_image_begin_read_from_file(&image->image, image->file_name)) - return logerror(image, "file init: ", image->file_name, ""); - } -# else - else - { - return logerror(image, "unsupported file/stdio init: ", - image->file_name, ""); - } -# endif - - /* This must be set after the begin_read call: */ - if (image->opts & sRGB_16BIT) - image->image.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; - - /* Have an initialized image with all the data we need plus, maybe, an - * allocated file (myfile) or buffer (mybuffer) that need to be freed. - */ - { - int result; - png_uint_32 image_format; - - /* Print both original and output formats. */ - image_format = image->image.format; - - if (image->opts & VERBOSE) - { - printf("%s %lu x %lu %s -> %s", image->file_name, - (unsigned long)image->image.width, - (unsigned long)image->image.height, - format_names[image_format & FORMAT_MASK], - (format & FORMAT_NO_CHANGE) != 0 || image->image.format == format - ? "no change" : format_names[format & FORMAT_MASK]); - - if (background != NULL) - printf(" background(%d,%d,%d)\n", background->red, - background->green, background->blue); - else - printf("\n"); - - fflush(stdout); - } - - /* 'NO_CHANGE' combined with the color-map flag forces the base format - * flags to be set on read to ensure that the original representation is - * not lost in the pass through a colormap format. - */ - if ((format & FORMAT_NO_CHANGE) != 0) - { - if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && - (image_format & PNG_FORMAT_FLAG_COLORMAP) != 0) - format = (image_format & ~BASE_FORMATS) | (format & BASE_FORMATS); - - else - format = image_format; - } - - image->image.format = format; - - image->stride = PNG_IMAGE_ROW_STRIDE(image->image) + image->stride_extra; - allocbuffer(image); - - result = png_image_finish_read(&image->image, background, - image->buffer+16, (png_int_32)image->stride, image->colormap); - - checkbuffer(image, image->file_name); - - if (result) - return checkopaque(image); - - else - return logerror(image, image->file_name, ": image read failed", ""); - } -} - -/* Reads from a filename, which must be in image->file_name, but uses - * image->opts to choose the method. The file is always read in its native - * format (the one the simplified API suggests). - */ -static int -read_one_file(Image *image) -{ - if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO)) - { - /* memory or stdio. */ - FILE *f = fopen(image->file_name, "rb"); - - if (f != NULL) - { - if (image->opts & READ_FILE) - image->input_file = f; - - else /* memory */ - { - if (fseek(f, 0, SEEK_END) == 0) - { - long int cb = ftell(f); - - if (cb > 0 && (unsigned long int)cb < (size_t)~(size_t)0) - { - png_bytep b = voidcast(png_bytep, malloc((size_t)cb)); - - if (b != NULL) - { - rewind(f); - - if (fread(b, (size_t)cb, 1, f) == 1) - { - fclose(f); - image->input_memory_size = cb; - image->input_memory = b; - } - - else - { - free(b); - return logclose(image, f, image->file_name, - ": read failed: "); - } - } - - else - return logclose(image, f, image->file_name, - ": out of memory: "); - } - - else if (cb == 0) - return logclose(image, f, image->file_name, - ": zero length: "); - - else - return logclose(image, f, image->file_name, - ": tell failed: "); - } - - else - return logclose(image, f, image->file_name, ": seek failed: "); - } - } - - else - return logerror(image, image->file_name, ": open failed: ", - strerror(errno)); - } - - return read_file(image, FORMAT_NO_CHANGE, NULL); -} - -#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED -static int -write_one_file(Image *output, Image *image, int convert_to_8bit) -{ - if (image->opts & FAST_WRITE) - image->image.flags |= PNG_IMAGE_FLAG_FAST; - - if (image->opts & USE_STDIO) - { - FILE *f = tmpfile(); - - if (f != NULL) - { - if (png_image_write_to_stdio(&image->image, f, convert_to_8bit, - image->buffer+16, (png_int_32)image->stride, image->colormap)) - { - if (fflush(f) == 0) - { - rewind(f); - initimage(output, image->opts, "tmpfile", image->stride_extra); - output->input_file = f; - if (!checkopaque(image)) - return 0; - } - - else - return logclose(image, f, "tmpfile", ": flush: "); - } - - else - { - fclose(f); - return logerror(image, "tmpfile", ": write failed", ""); - } - } - - else - return logerror(image, "tmpfile", ": open: ", strerror(errno)); - } - - else - { - static int counter = 0; - char name[32]; - - sprintf(name, "%s%d.png", tmpf, ++counter); - - if (png_image_write_to_file(&image->image, name, convert_to_8bit, - image->buffer+16, (png_int_32)image->stride, image->colormap)) - { - initimage(output, image->opts, output->tmpfile_name, - image->stride_extra); - /* Afterwards, or freeimage will delete it! */ - strcpy(output->tmpfile_name, name); - - if (!checkopaque(image)) - return 0; - } - - else - return logerror(image, name, ": write failed", ""); - } - - /* 'output' has an initialized temporary image, read this back in and compare - * this against the original: there should be no change since the original - * format was written unmodified unless 'convert_to_8bit' was specified. - * However, if the original image was color-mapped, a simple read will zap - * the linear, color and maybe alpha flags, this will cause spurious failures - * under some circumstances. - */ - if (read_file(output, image->image.format | FORMAT_NO_CHANGE, NULL)) - { - png_uint_32 original_format = image->image.format; - - if (convert_to_8bit) - original_format &= ~PNG_FORMAT_FLAG_LINEAR; - - if ((output->image.format & BASE_FORMATS) != - (original_format & BASE_FORMATS)) - return logerror(image, image->file_name, ": format changed on read: ", - output->file_name); - - return compare_two_images(image, output, 0/*via linear*/, NULL); - } - - else - return logerror(output, output->tmpfile_name, - ": read of new file failed", ""); -} -#endif - -static int -testimage(Image *image, png_uint_32 opts, format_list *pf) -{ - int result; - Image copy; - - /* Copy the original data, stealing it from 'image' */ - checkopaque(image); - copy = *image; - - copy.opts = opts; - copy.buffer = NULL; - copy.bufsize = 0; - copy.allocsize = 0; - - image->input_file = NULL; - image->input_memory = NULL; - image->input_memory_size = 0; - image->tmpfile_name[0] = 0; - - { - png_uint_32 counter; - Image output; - - newimage(&output); - - result = 1; - - /* Use the low bit of 'counter' to indicate whether or not to do alpha - * removal with a background color or by composting onto the image; this - * step gets skipped if it isn't relevant - */ - for (counter=0; counter<2*FORMAT_COUNT; ++counter) - if (format_isset(pf, counter >> 1)) - { - png_uint_32 format = counter >> 1; - - png_color background_color; - png_colorp background = NULL; - - /* If there is a format change that removes the alpha channel then - * the background is relevant. If the output is 8-bit color-mapped - * then a background color *must* be provided, otherwise there are - * two tests to do - one with a color, the other with NULL. The - * NULL test happens second. - */ - if ((counter & 1) == 0) - { - if ((format & PNG_FORMAT_FLAG_ALPHA) == 0 && - (image->image.format & PNG_FORMAT_FLAG_ALPHA) != 0) - { - /* Alpha/transparency will be removed, the background is - * relevant: make it a color the first time - */ - random_color(&background_color); - background = &background_color; - - /* BUT if the output is to a color-mapped 8-bit format then - * the background must always be a color, so increment 'counter' - * to skip the NULL test. - */ - if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && - (format & PNG_FORMAT_FLAG_LINEAR) == 0) - ++counter; - } - - /* Otherwise an alpha channel is not being eliminated, just leave - * background NULL and skip the (counter & 1) NULL test. - */ - else - ++counter; - } - /* else just use NULL for background */ - - resetimage(©); - copy.opts = opts; /* in case read_file needs to change it */ - - result = read_file(©, format, background); - if (!result) - break; - - /* Make sure the file just read matches the original file. */ - result = compare_two_images(image, ©, 0/*via linear*/, background); - if (!result) - break; - -# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED - /* Write the *copy* just made to a new file to make sure the write - * side works ok. Check the conversion to sRGB if the copy is - * linear. - */ - output.opts = opts; - result = write_one_file(&output, ©, 0/*convert to 8bit*/); - if (!result) - break; - - /* Validate against the original too; the background is needed here - * as well so that compare_two_images knows what color was used. - */ - result = compare_two_images(image, &output, 0, background); - if (!result) - break; - - if ((format & PNG_FORMAT_FLAG_LINEAR) != 0 && - (format & PNG_FORMAT_FLAG_COLORMAP) == 0) - { - /* 'output' is linear, convert to the corresponding sRGB format. - */ - output.opts = opts; - result = write_one_file(&output, ©, 1/*convert to 8bit*/); - if (!result) - break; - - /* This may involve a conversion via linear; in the ideal world - * this would round-trip correctly, but libpng 1.5.7 is not the - * ideal world so allow a drift (error_via_linear). - * - * 'image' has an alpha channel but 'output' does not then there - * will a strip-alpha-channel operation (because 'output' is - * linear), handle this by composing on black when doing the - * comparison. - */ - result = compare_two_images(image, &output, 1/*via_linear*/, - background); - if (!result) - break; - } -# endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ - } - - freeimage(&output); - } - - freeimage(©); - - return result; -} - -static int -test_one_file(const char *file_name, format_list *formats, png_uint_32 opts, - int stride_extra, int log_pass) -{ - int result; - Image image; - - newimage(&image); - initimage(&image, opts, file_name, stride_extra); - result = read_one_file(&image); - if (result) - result = testimage(&image, opts, formats); - freeimage(&image); - - /* Ensure that stderr is flushed into any log file */ - fflush(stderr); - - if (log_pass) - { - if (result) - printf("PASS:"); - - else - printf("FAIL:"); - -# ifndef PNG_SIMPLIFIED_WRITE_SUPPORTED - printf(" (no write)"); -# endif - - print_opts(opts); - printf(" %s\n", file_name); - /* stdout may not be line-buffered if it is piped to a file, so: */ - fflush(stdout); - } - - else if (!result) - exit(1); - - return result; -} - -int -main(int argc, char **argv) -{ - png_uint_32 opts = FAST_WRITE; - format_list formats; - const char *touch = NULL; - int log_pass = 0; - int redundant = 0; - int stride_extra = 0; - int retval = 0; - int c; - - init_sRGB_to_d(); -#if 0 - init_error_via_linear(); -#endif - format_init(&formats); - - for (c=1; c= sizeof tmpf) - { - fflush(stdout); - fprintf(stderr, "%s: %s is too long for a temp file prefix\n", - argv[0], argv[c]); - exit(99); - } - - /* Safe: checked above */ - strcpy(tmpf, argv[c]); - } - - else - { - fflush(stdout); - fprintf(stderr, "%s: %s requires a temporary file prefix\n", - argv[0], arg); - exit(99); - } - } - else if (strcmp(arg, "--touch") == 0) - { - if (c+1 < argc) - touch = argv[++c]; - - else - { - fflush(stdout); - fprintf(stderr, "%s: %s requires a file name argument\n", - argv[0], arg); - exit(99); - } - } - else if (arg[0] == '+') - { - png_uint_32 format = formatof(arg+1); - - if (format > FORMAT_COUNT) - exit(99); - - format_set(&formats, format); - } - else if (arg[0] == '-' && arg[1] != 0 && (arg[1] != '0' || arg[2] != 0)) - { - fflush(stdout); - fprintf(stderr, "%s: unknown option: %s\n", argv[0], arg); - exit(99); - } - else - { - if (format_is_initial(&formats)) - format_default(&formats, redundant); - - if (arg[0] == '-') - { - const int term = (arg[1] == '0' ? 0 : '\n'); - unsigned int ich = 0; - - /* Loop reading files, use a static buffer to simplify this and just - * stop if the name gets to long. - */ - static char buffer[4096]; - - do - { - int ch = getchar(); - - /* Don't allow '\0' in file names, and terminate with '\n' or, - * for -0, just '\0' (use -print0 to find to make this work!) - */ - if (ch == EOF || ch == term || ch == 0) - { - buffer[ich] = 0; - - if (ich > 0 && !test_one_file(buffer, &formats, opts, - stride_extra, log_pass)) - retval = 1; - - if (ch == EOF) - break; - - ich = 0; - --ich; /* so that the increment below sets it to 0 again */ - } - - else - buffer[ich] = (char)ch; - } while (++ich < sizeof buffer); - - if (ich) - { - buffer[32] = 0; - buffer[4095] = 0; - fprintf(stderr, "%s...%s: file name too long\n", buffer, - buffer+(4096-32)); - exit(99); - } - } - - else if (!test_one_file(arg, &formats, opts, stride_extra, log_pass)) - retval = 1; - } - } - - if (opts & ACCUMULATE) - { - unsigned int in; - - printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n"); - printf("{\n"); - for (in=0; in<16; ++in) - { - unsigned int out; - printf(" { /* input: %s */\n ", format_names[in]); - for (out=0; out<16; ++out) - { - unsigned int alpha; - printf(" {"); - for (alpha=0; alpha<4; ++alpha) - { - printf(" %d", gpc_error[in][out][alpha]); - if (alpha < 3) putchar(','); - } - printf(" }"); - if (out < 15) - { - putchar(','); - if (out % 4 == 3) printf("\n "); - } - } - printf("\n }"); - - if (in < 15) - putchar(','); - else - putchar('\n'); - } - printf("};\n"); - - printf("static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =\n"); - printf("{\n"); - for (in=0; in<16; ++in) - { - unsigned int out; - printf(" { /* input: %s */\n ", format_names[in]); - for (out=0; out<4; ++out) - { - unsigned int alpha; - printf(" {"); - for (alpha=0; alpha<4; ++alpha) - { - printf(" %d", gpc_error_via_linear[in][out][alpha]); - if (alpha < 3) putchar(','); - } - printf(" }"); - if (out < 3) - putchar(','); - } - printf("\n }"); - - if (in < 15) - putchar(','); - else - putchar('\n'); - } - printf("};\n"); - - printf("static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =\n"); - printf("{\n"); - for (in=0; in<8; ++in) - { - unsigned int out; - printf(" { /* input: %s */\n ", format_names[in]); - for (out=0; out<8; ++out) - { - unsigned int alpha; - printf(" {"); - for (alpha=0; alpha<4; ++alpha) - { - printf(" %d", gpc_error_to_colormap[in][out][alpha]); - if (alpha < 3) putchar(','); - } - printf(" }"); - if (out < 7) - { - putchar(','); - if (out % 4 == 3) printf("\n "); - } - } - printf("\n }"); - - if (in < 7) - putchar(','); - else - putchar('\n'); - } - printf("};\n"); - } - - if (retval == 0 && touch != NULL) - { - FILE *fsuccess = fopen(touch, "wt"); - - if (fsuccess != NULL) - { - int error = 0; - fprintf(fsuccess, "PNG simple API tests succeeded\n"); - fflush(fsuccess); - error = ferror(fsuccess); - - if (fclose(fsuccess) || error) - { - fflush(stdout); - fprintf(stderr, "%s: write failed\n", touch); - exit(99); - } - } - - else - { - fflush(stdout); - fprintf(stderr, "%s: open failed\n", touch); - exit(99); - } - } - - return retval; -} - -#else /* !PNG_SIMPLIFIED_READ_SUPPORTED */ -int main(void) -{ - fprintf(stderr, "pngstest: no read support in libpng, test skipped\n"); - /* So the test is skipped: */ - return 77; -} -#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ +/*- + * pngstest.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.8 [December 19, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Test for the PNG 'simplified' APIs. + */ +#define _ISOC90_SOURCE 1 +#define MALLOC_CHECK_ 2/*glibc facility: turn on debugging*/ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */ +#include "../tools/sRGB.h" + +/* KNOWN ISSUES + * + * These defines switch on alternate algorithms for format conversions to match + * the current libpng implementation; they are set to allow pngstest to pass + * even though libpng is producing answers that are not as correct as they + * should be. + */ +#define ALLOW_UNUSED_GPC 0 + /* If true include unused static GPC functions and declare an external array + * of them to hide the fact that they are unused. This is for development + * use while testing the correct function to use to take into account libpng + * misbehavior, such as using a simple power law to correct sRGB to linear. + */ + +/* The following is to support direct compilation of this file as C++ */ +#ifdef __cplusplus +# define voidcast(type, value) static_cast(value) +# define aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define voidcast(type, value) (value) +# define aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +/* During parallel runs of pngstest each temporary file needs a unique name, + * this is used to permit uniqueness using a command line argument which can be + * up to 22 characters long. + */ +static char tmpf[23] = "TMP"; + +/* Generate random bytes. This uses a boring repeatable algorithm and it + * is implemented here so that it gives the same set of numbers on every + * architecture. It's a linear congruential generator (Knuth or Sedgewick + * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and + * Hill, "The Art of Electronics". + */ +static void +make_random_bytes(png_uint_32* seed, void* pv, size_t size) +{ + png_uint_32 u0 = seed[0], u1 = seed[1]; + png_bytep bytes = voidcast(png_bytep, pv); + + /* There are thirty three bits, the next bit in the sequence is bit-33 XOR + * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. + */ + size_t i; + for (i=0; i> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; + u1 <<= 8; + u1 |= u0 >> 24; + u0 <<= 8; + u0 |= u; + *bytes++ = (png_byte)u; + } + + seed[0] = u0; + seed[1] = u1; +} + +static void +random_color(png_colorp color) +{ + static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef }; + make_random_bytes(color_seed, color, sizeof *color); +} + +/* Math support - neither Cygwin nor Visual Studio have C99 support and we need + * a predictable rounding function, so make one here: + */ +static double +closestinteger(double x) +{ + return floor(x + .5); +} + +/* Cast support: remove GCC whines. */ +static png_byte +u8d(double d) +{ + d = closestinteger(d); + return (png_byte)d; +} + +static png_uint_16 +u16d(double d) +{ + d = closestinteger(d); + return (png_uint_16)d; +} + +/* sRGB support: use exact calculations rounded to the nearest int, see the + * fesetround() call in main(). sRGB_to_d optimizes the 8 to 16-bit conversion. + */ +static double sRGB_to_d[256]; +static double g22_to_d[256]; + +static void +init_sRGB_to_d(void) +{ + int i; + + sRGB_to_d[0] = 0; + for (i=1; i<255; ++i) + sRGB_to_d[i] = linear_from_sRGB(i/255.); + sRGB_to_d[255] = 1; + + g22_to_d[0] = 0; + for (i=1; i<255; ++i) + g22_to_d[i] = pow(i/255., 1/.45455); + g22_to_d[255] = 1; +} + +static png_byte +sRGB(double linear /*range 0.0 .. 1.0*/) +{ + return u8d(255 * sRGB_from_linear(linear)); +} + +static png_byte +isRGB(int fixed_linear) +{ + return sRGB(fixed_linear / 65535.); +} + +#if 0 /* not used */ +static png_byte +unpremultiply(int component, int alpha) +{ + if (alpha <= component) + return 255; /* Arbitrary, but consistent with the libpng code */ + + else if (alpha >= 65535) + return isRGB(component); + + else + return sRGB((double)component / alpha); +} +#endif + +static png_uint_16 +ilinear(int fixed_srgb) +{ + return u16d(65535 * sRGB_to_d[fixed_srgb]); +} + +static png_uint_16 +ilineara(int fixed_srgb, int alpha) +{ + return u16d((257 * alpha) * sRGB_to_d[fixed_srgb]); +} + +static png_uint_16 +ilinear_g22(int fixed_srgb) +{ + return u16d(65535 * g22_to_d[fixed_srgb]); +} + +#if ALLOW_UNUSED_GPC +static png_uint_16 +ilineara_g22(int fixed_srgb, int alpha) +{ + return u16d((257 * alpha) * g22_to_d[fixed_srgb]); +} +#endif + +static double +YfromRGBint(int ir, int ig, int ib) +{ + double r = ir; + double g = ig; + double b = ib; + return YfromRGB(r, g, b); +} + +#if 0 /* unused */ +/* The error that results from using a 2.2 power law in place of the correct + * sRGB transform, given an 8-bit value which might be either sRGB or power-law. + */ +static int +power_law_error8(int value) +{ + if (value > 0 && value < 255) + { + double vd = value / 255.; + double e = fabs( + pow(sRGB_to_d[value], 1/2.2) - sRGB_from_linear(pow(vd, 2.2))); + + /* Always allow an extra 1 here for rounding errors */ + e = 1+floor(255 * e); + return (int)e; + } + + return 0; +} + +static int error_in_sRGB_roundtrip = 56; /* by experiment */ +static int +power_law_error16(int value) +{ + if (value > 0 && value < 65535) + { + /* Round trip the value through an 8-bit representation but using + * non-matching to/from conversions. + */ + double vd = value / 65535.; + double e = fabs( + pow(sRGB_from_linear(vd), 2.2) - linear_from_sRGB(pow(vd, 1/2.2))); + + /* Always allow an extra 1 here for rounding errors */ + e = error_in_sRGB_roundtrip+floor(65535 * e); + return (int)e; + } + + return 0; +} + +static int +compare_8bit(int v1, int v2, int error_limit, int multiple_algorithms) +{ + int e = abs(v1-v2); + int ev1, ev2; + + if (e <= error_limit) + return 1; + + if (!multiple_algorithms) + return 0; + + ev1 = power_law_error8(v1); + if (e <= ev1) + return 1; + + ev2 = power_law_error8(v2); + if (e <= ev2) + return 1; + + return 0; +} + +static int +compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) +{ + int e = abs(v1-v2); + int ev1, ev2; + + if (e <= error_limit) + return 1; + + /* "multiple_algorithms" in this case means that a color-map has been + * involved somewhere, so we can deduce that the values were forced to 8-bit + * (like the via_linear case for 8-bit.) + */ + if (!multiple_algorithms) + return 0; + + ev1 = power_law_error16(v1); + if (e <= ev1) + return 1; + + ev2 = power_law_error16(v2); + if (e <= ev2) + return 1; + + return 0; +} +#endif /* unused */ + +#define READ_FILE 1 /* else memory */ +#define USE_STDIO 2 /* else use file name */ +#define STRICT 4 /* fail on warnings too */ +#define VERBOSE 8 +#define KEEP_TMPFILES 16 /* else delete temporary files */ +#define KEEP_GOING 32 +#define ACCUMULATE 64 +#define FAST_WRITE 128 +#define sRGB_16BIT 256 + +static void +print_opts(png_uint_32 opts) +{ + if (opts & READ_FILE) + printf(" --file"); + if (opts & USE_STDIO) + printf(" --stdio"); + if (opts & STRICT) + printf(" --strict"); + if (opts & VERBOSE) + printf(" --verbose"); + if (opts & KEEP_TMPFILES) + printf(" --preserve"); + if (opts & KEEP_GOING) + printf(" --keep-going"); + if (opts & ACCUMULATE) + printf(" --accumulate"); + if (!(opts & FAST_WRITE)) /* --fast is currently the default */ + printf(" --slow"); + if (opts & sRGB_16BIT) + printf(" --sRGB-16bit"); +} + +#define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ + +/* A name table for all the formats - defines the format of the '+' arguments to + * pngstest. + */ +#define FORMAT_COUNT 64 +#define FORMAT_MASK 0x3f +static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = +{ + "sRGB-gray", + "sRGB-gray+alpha", + "sRGB-rgb", + "sRGB-rgb+alpha", + "linear-gray", + "linear-gray+alpha", + "linear-rgb", + "linear-rgb+alpha", + + "color-mapped-sRGB-gray", + "color-mapped-sRGB-gray+alpha", + "color-mapped-sRGB-rgb", + "color-mapped-sRGB-rgb+alpha", + "color-mapped-linear-gray", + "color-mapped-linear-gray+alpha", + "color-mapped-linear-rgb", + "color-mapped-linear-rgb+alpha", + + "sRGB-gray", + "sRGB-gray+alpha", + "sRGB-bgr", + "sRGB-bgr+alpha", + "linear-gray", + "linear-gray+alpha", + "linear-bgr", + "linear-bgr+alpha", + + "color-mapped-sRGB-gray", + "color-mapped-sRGB-gray+alpha", + "color-mapped-sRGB-bgr", + "color-mapped-sRGB-bgr+alpha", + "color-mapped-linear-gray", + "color-mapped-linear-gray+alpha", + "color-mapped-linear-bgr", + "color-mapped-linear-bgr+alpha", + + "sRGB-gray", + "alpha+sRGB-gray", + "sRGB-rgb", + "alpha+sRGB-rgb", + "linear-gray", + "alpha+linear-gray", + "linear-rgb", + "alpha+linear-rgb", + + "color-mapped-sRGB-gray", + "color-mapped-alpha+sRGB-gray", + "color-mapped-sRGB-rgb", + "color-mapped-alpha+sRGB-rgb", + "color-mapped-linear-gray", + "color-mapped-alpha+linear-gray", + "color-mapped-linear-rgb", + "color-mapped-alpha+linear-rgb", + + "sRGB-gray", + "alpha+sRGB-gray", + "sRGB-bgr", + "alpha+sRGB-bgr", + "linear-gray", + "alpha+linear-gray", + "linear-bgr", + "alpha+linear-bgr", + + "color-mapped-sRGB-gray", + "color-mapped-alpha+sRGB-gray", + "color-mapped-sRGB-bgr", + "color-mapped-alpha+sRGB-bgr", + "color-mapped-linear-gray", + "color-mapped-alpha+linear-gray", + "color-mapped-linear-bgr", + "color-mapped-alpha+linear-bgr", +}; + +/* Decode an argument to a format number. */ +static png_uint_32 +formatof(const char *arg) +{ + char *ep; + unsigned long format = strtoul(arg, &ep, 0); + + if (ep > arg && *ep == 0 && format < FORMAT_COUNT) + return (png_uint_32)format; + + else for (format=0; format < FORMAT_COUNT; ++format) + { + if (strcmp(format_names[format], arg) == 0) + return (png_uint_32)format; + } + + fprintf(stderr, "pngstest: format name '%s' invalid\n", arg); + return FORMAT_COUNT; +} + +/* Bitset/test functions for formats */ +#define FORMAT_SET_COUNT (FORMAT_COUNT / 32) +typedef struct +{ + png_uint_32 bits[FORMAT_SET_COUNT]; +} +format_list; + +static void format_init(format_list *pf) +{ + int i; + for (i=0; ibits[i] = 0; /* All off */ +} + +#if 0 /* currently unused */ +static void format_clear(format_list *pf) +{ + int i; + for (i=0; ibits[i] = 0; +} +#endif + +static int format_is_initial(format_list *pf) +{ + int i; + for (i=0; ibits[i] != 0) + return 0; + + return 1; +} + +static int format_set(format_list *pf, png_uint_32 format) +{ + if (format < FORMAT_COUNT) + return pf->bits[format >> 5] |= ((png_uint_32)1) << (format & 31); + + return 0; +} + +#if 0 /* currently unused */ +static int format_unset(format_list *pf, png_uint_32 format) +{ + if (format < FORMAT_COUNT) + return pf->bits[format >> 5] &= ~((png_uint_32)1) << (format & 31); + + return 0; +} +#endif + +static int format_isset(format_list *pf, png_uint_32 format) +{ + return format < FORMAT_COUNT && + (pf->bits[format >> 5] & (((png_uint_32)1) << (format & 31))) != 0; +} + +static void format_default(format_list *pf, int redundant) +{ + if (redundant) + { + int i; + + /* set everything, including flags that are pointless */ + for (i=0; ibits[i] = ~(png_uint_32)0; + } + + else + { + png_uint_32 f; + + for (f=0; finput_file != NULL) + rewind(image->input_file); +} + +/* Free the image buffer; the buffer is re-used on a re-read, this is just for + * cleanup. + */ +static void +freebuffer(Image *image) +{ + if (image->buffer) free(image->buffer); + image->buffer = NULL; + image->bufsize = 0; + image->allocsize = 0; +} + +/* Delete function; cleans out all the allocated data and the temporary file in + * the image. + */ +static void +freeimage(Image *image) +{ + freebuffer(image); + png_image_free(&image->image); + + if (image->input_file != NULL) + { + fclose(image->input_file); + image->input_file = NULL; + } + + if (image->input_memory != NULL) + { + free(image->input_memory); + image->input_memory = NULL; + image->input_memory_size = 0; + } + + if (image->tmpfile_name[0] != 0 && (image->opts & KEEP_TMPFILES) == 0) + { + remove(image->tmpfile_name); + image->tmpfile_name[0] = 0; + } +} + +/* This is actually a re-initializer; allows an image structure to be re-used by + * freeing everything that relates to an old image. + */ +static void initimage(Image *image, png_uint_32 opts, const char *file_name, + int stride_extra) +{ + freeimage(image); + memset(&image->image, 0, sizeof image->image); + image->opts = opts; + image->file_name = file_name; + image->stride_extra = stride_extra; +} + +/* Make sure the image buffer is big enough; allows re-use of the buffer if the + * image is re-read. + */ +#define BUFFER_INIT8 73 +static void +allocbuffer(Image *image) +{ + png_size_t size = PNG_IMAGE_BUFFER_SIZE(image->image, image->stride); + + if (size+32 > image->bufsize) + { + freebuffer(image); + image->buffer = voidcast(png_bytep, malloc(size+32)); + if (image->buffer == NULL) + { + fflush(stdout); + fprintf(stderr, + "simpletest: out of memory allocating %lu(+32) byte buffer\n", + (unsigned long)size); + exit(1); + } + image->bufsize = size+32; + } + + memset(image->buffer, 95, image->bufsize); + memset(image->buffer+16, BUFFER_INIT8, size); + image->allocsize = size; +} + +/* Make sure 16 bytes match the given byte. */ +static int +check16(png_const_bytep bp, int b) +{ + int i = 16; + + do + if (*bp != b) return 1; + while (--i); + + return 0; +} + +/* Check for overwrite in the image buffer. */ +static void +checkbuffer(Image *image, const char *arg) +{ + if (check16(image->buffer, 95)) + { + fflush(stdout); + fprintf(stderr, "%s: overwrite at start of image buffer\n", arg); + exit(1); + } + + if (check16(image->buffer+16+image->allocsize, 95)) + { + fflush(stdout); + fprintf(stderr, "%s: overwrite at end of image buffer\n", arg); + exit(1); + } +} + +/* ERROR HANDLING */ +/* Log a terminal error, also frees the libpng part of the image if necessary. + */ +static int +logerror(Image *image, const char *a1, const char *a2, const char *a3) +{ + fflush(stdout); + if (image->image.warning_or_error) + fprintf(stderr, "%s%s%s: %s\n", a1, a2, a3, image->image.message); + + else + fprintf(stderr, "%s%s%s\n", a1, a2, a3); + + if (image->image.opaque != NULL) + { + fprintf(stderr, "%s: image opaque pointer non-NULL on error\n", + image->file_name); + png_image_free(&image->image); + } + + return 0; +} + +/* Log an error and close a file (just a utility to do both things in one + * function call.) + */ +static int +logclose(Image *image, FILE *f, const char *name, const char *operation) +{ + int e = errno; + + fclose(f); + return logerror(image, name, operation, strerror(e)); +} + +/* Make sure the png_image has been freed - validates that libpng is doing what + * the spec says and freeing the image. + */ +static int +checkopaque(Image *image) +{ + if (image->image.opaque != NULL) + { + png_image_free(&image->image); + return logerror(image, image->file_name, ": opaque not NULL", ""); + } + + else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0) + return logerror(image, image->file_name, " --strict", ""); + + else + return 1; +} + +/* IMAGE COMPARISON/CHECKING */ +/* Compare the pixels of two images, which should be the same but aren't. The + * images must have been checked for a size match. + */ +typedef struct +{ + /* The components, for grayscale images the gray value is in 'g' and if alpha + * is not present 'a' is set to 255 or 65535 according to format. + */ + int r, g, b, a; +} Pixel; + +typedef struct +{ + /* The background as the original sRGB 8-bit value converted to the final + * integer format and as a double precision linear value in the range 0..1 + * for with partially transparent pixels. + */ + int ir, ig, ib; + double dr, dg, db; /* linear r,g,b scaled to 0..1 */ +} Background; + +/* Basic image formats; control the data but not the layout thereof. */ +#define BASE_FORMATS\ + (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR) + +/* Read a Pixel from a buffer. The code below stores the correct routine for + * the format in a function pointer, these are the routines: + */ +static void +gp_g8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = p->g = p->b = pp[0]; + p->a = 255; +} + +static void +gp_ga8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = p->g = p->b = pp[0]; + p->a = pp[1]; +} + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +static void +gp_ag8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = p->g = p->b = pp[1]; + p->a = pp[0]; +} +#endif + +static void +gp_rgb8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = 255; +} + +#ifdef PNG_FORMAT_BGR_SUPPORTED +static void +gp_bgr8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = 255; +} +#endif + +static void +gp_rgba8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = pp[3]; +} + +#ifdef PNG_FORMAT_BGR_SUPPORTED +static void +gp_bgra8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = pp[3]; +} +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +static void +gp_argb8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[1]; + p->g = pp[2]; + p->b = pp[3]; + p->a = pp[0]; +} +#endif + +#if defined(PNG_FORMAT_AFIRST_SUPPORTED) && defined(PNG_FORMAT_BGR_SUPPORTED) +static void +gp_abgr8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[3]; + p->g = pp[2]; + p->b = pp[1]; + p->a = pp[0]; +} +#endif + +static void +gp_g16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = p->g = p->b = pp[0]; + p->a = 65535; +} + +static void +gp_ga16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = p->g = p->b = pp[0]; + p->a = pp[1]; +} + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +static void +gp_ag16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = p->g = p->b = pp[1]; + p->a = pp[0]; +} +#endif + +static void +gp_rgb16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = 65535; +} + +#ifdef PNG_FORMAT_BGR_SUPPORTED +static void +gp_bgr16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = 65535; +} +#endif + +static void +gp_rgba16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = pp[3]; +} + +#ifdef PNG_FORMAT_BGR_SUPPORTED +static void +gp_bgra16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = pp[3]; +} +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +static void +gp_argb16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[1]; + p->g = pp[2]; + p->b = pp[3]; + p->a = pp[0]; +} +#endif + +#if defined(PNG_FORMAT_AFIRST_SUPPORTED) && defined(PNG_FORMAT_BGR_SUPPORTED) +static void +gp_abgr16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[3]; + p->g = pp[2]; + p->b = pp[1]; + p->a = pp[0]; +} +#endif + +/* Given a format, return the correct one of the above functions. */ +static void (* +get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb) +{ + /* The color-map flag is irrelevant here - the caller of the function + * returned must either pass the buffer or, for a color-mapped image, the + * correct entry in the color-map. + */ + if (format & PNG_FORMAT_FLAG_LINEAR) + { + if (format & PNG_FORMAT_FLAG_COLOR) + { +# ifdef PNG_FORMAT_BGR_SUPPORTED + if (format & PNG_FORMAT_FLAG_BGR) + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_abgr16; + + else +# endif + return gp_bgra16; + } + + else + return gp_bgr16; + } + + else +# endif + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_argb16; + + else +# endif + return gp_rgba16; + } + + else + return gp_rgb16; + } + } + + else + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_ag16; + + else +# endif + return gp_ga16; + } + + else + return gp_g16; + } + } + + else + { + if (format & PNG_FORMAT_FLAG_COLOR) + { +# ifdef PNG_FORMAT_BGR_SUPPORTED + if (format & PNG_FORMAT_FLAG_BGR) + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_abgr8; + + else +# endif + return gp_bgra8; + } + + else + return gp_bgr8; + } + + else +# endif + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_argb8; + + else +# endif + return gp_rgba8; + } + + else + return gp_rgb8; + } + } + + else + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_ag8; + + else +# endif + return gp_ga8; + } + + else + return gp_g8; + } + } +} + +/* Convertion between pixel formats. The code above effectively eliminates the + * component ordering changes leaving three basic changes: + * + * 1) Remove an alpha channel by pre-multiplication or compositing on a + * background color. (Adding an alpha channel is a no-op.) + * + * 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.) + * + * 3) Convert between 8-bit and 16-bit components. (Both directtions are + * relevant.) + * + * This gives the following base format conversion matrix: + * + * OUT: ----- 8-bit ----- ----- 16-bit ----- + * IN G GA RGB RGBA G GA RGB RGBA + * 8 G . . . . lin lin lin lin + * 8 GA bckg . bckc . pre' pre pre' pre + * 8 RGB g8 g8 . . glin glin lin lin + * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre + * 16 G sRGB sRGB sRGB sRGB . . . . + * 16 GA b16g unpg b16c unpc A . A . + * 16 RGB sG sG sRGB sRGB g16 g16 . . + * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . + * + * 8-bit to 8-bit: + * bckg: composite on gray background + * bckc: composite on color background + * g8: convert sRGB components to sRGB grayscale + * g8b: convert sRGB components to grayscale and composite on gray background + * + * 8-bit to 16-bit: + * lin: make sRGB components linear, alpha := 65535 + * pre: make sRGB components linear and premultiply by alpha (scale alpha) + * pre': as 'pre' but alpha := 65535 + * glin: make sRGB components linear, convert to grayscale, alpha := 65535 + * gpre: make sRGB components grayscale and linear and premultiply by alpha + * gpr': as 'gpre' but alpha := 65535 + * + * 16-bit to 8-bit: + * sRGB: convert linear components to sRGB, alpha := 255 + * unpg: unpremultiply gray component and convert to sRGB (scale alpha) + * unpc: unpremultiply color components and convert to sRGB (scale alpha) + * b16g: composite linear onto gray background and convert the result to sRGB + * b16c: composite linear onto color background and convert the result to sRGB + * sG: convert linear RGB to sRGB grayscale + * sGp: unpremultiply RGB then convert to sRGB grayscale + * sCp: unpremultiply RGB then convert to sRGB + * gb16: composite linear onto background and convert to sRGB grayscale + * (order doesn't matter, the composite and grayscale operations permute) + * cb16: composite linear onto background and convert to sRGB + * + * 16-bit to 16-bit: + * A: set alpha to 65535 + * g16: convert linear RGB to linear grayscale (alpha := 65535) + * g16': as 'g16' but alpha is unchanged + */ +/* Simple copy: */ +static void +gpc_noop(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = in->r; + out->g = in->g; + out->b = in->b; + out->a = in->a; +} + +#if ALLOW_UNUSED_GPC +static void +gpc_nop8(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + if (in->a == 0) + out->r = out->g = out->b = 255; + + else + { + out->r = in->r; + out->g = in->g; + out->b = in->b; + } + + out->a = in->a; +} +#endif + +#if ALLOW_UNUSED_GPC +static void +gpc_nop6(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + if (in->a == 0) + out->r = out->g = out->b = 65535; + + else + { + out->r = in->r; + out->g = in->g; + out->b = in->b; + } + + out->a = in->a; +} +#endif + +/* 8-bit to 8-bit conversions */ +/* bckg: composite on gray background */ +static void +gpc_bckg(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else if (in->a >= 255) + out->r = out->g = out->b = in->g; + + else + { + double a = in->a / 255.; + + out->r = out->g = out->b = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); + } + + out->a = 255; +} + +/* bckc: composite on color background */ +static void +gpc_bckc(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + { + out->r = back->ir; + out->g = back->ig; + out->b = back->ib; + } + + else if (in->a >= 255) + { + out->r = in->r; + out->g = in->g; + out->b = in->b; + } + + else + { + double a = in->a / 255.; + + out->r = sRGB(sRGB_to_d[in->r] * a + back->dr * (1-a)); + out->g = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); + out->b = sRGB(sRGB_to_d[in->b] * a + back->db * (1-a)); + } + + out->a = 255; +} + +/* g8: convert sRGB components to sRGB grayscale */ +static void +gpc_g8(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = in->g; + + else + out->r = out->g = out->b = + sRGB(YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = in->a; +} + +/* g8b: convert sRGB components to grayscale and composite on gray background */ +static void +gpc_g8b(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else if (in->a >= 255) + { + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = in->g; + + else + out->r = out->g = out->b = sRGB(YfromRGB( + sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + } + + else + { + double a = in->a/255.; + + out->r = out->g = out->b = sRGB(a * YfromRGB(sRGB_to_d[in->r], + sRGB_to_d[in->g], sRGB_to_d[in->b]) + back->dg * (1-a)); + } + + out->a = 255; +} + +/* 8-bit to 16-bit conversions */ +/* lin: make sRGB components linear, alpha := 65535 */ +static void +gpc_lin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilinear(in->r); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilinear(in->b); + } + + else + { + out->g = ilinear(in->g); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilinear(in->b); + } + + out->a = 65535; +} + +/* pre: make sRGB components linear and premultiply by alpha (scale alpha) */ +static void +gpc_pre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara(in->b, in->a); + } + + else + { + out->g = ilineara(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara(in->b, in->a); + } + + out->a = in->a * 257; +} + +/* pre': as 'pre' but alpha := 65535 */ +static void +gpc_preq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara(in->b, in->a); + } + + else + { + out->g = ilineara(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara(in->b, in->a); + } + + out->a = 65535; +} + +/* glin: make sRGB components linear, convert to grayscale, alpha := 65535 */ +static void +gpc_glin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilinear(in->g); + + else + out->r = out->g = out->b = u16d(65535 * + YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = 65535; +} + +/* gpre: make sRGB components grayscale and linear and premultiply by alpha */ +static void +gpc_gpre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = 257 * in->a; +} + +/* gpr': as 'gpre' but alpha := 65535 */ +static void +gpc_gprq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = 65535; +} + +/* 8-bit to 16-bit conversions for gAMA 45455 encoded values */ +/* Lin: make gAMA 45455 components linear, alpha := 65535 */ +static void +gpc_Lin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilinear_g22(in->r); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilinear_g22(in->b); + } + + else + { + out->g = ilinear_g22(in->g); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilinear_g22(in->b); + } + + out->a = 65535; +} + +#if ALLOW_UNUSED_GPC +/* Pre: make gAMA 45455 components linear and premultiply by alpha (scale alpha) + */ +static void +gpc_Pre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara_g22(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara_g22(in->b, in->a); + } + + else + { + out->g = ilineara_g22(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara_g22(in->b, in->a); + } + + out->a = in->a * 257; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Pre': as 'Pre' but alpha := 65535 */ +static void +gpc_Preq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara_g22(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara_g22(in->b, in->a); + } + + else + { + out->g = ilineara_g22(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara_g22(in->b, in->a); + } + + out->a = 65535; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Glin: make gAMA 45455 components linear, convert to grayscale, alpha := 65535 + */ +static void +gpc_Glin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilinear_g22(in->g); + + else + out->r = out->g = out->b = u16d(65535 * + YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + + out->a = 65535; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Gpre: make gAMA 45455 components grayscale and linear and premultiply by + * alpha. + */ +static void +gpc_Gpre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara_g22(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + + out->a = 257 * in->a; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Gpr': as 'Gpre' but alpha := 65535 */ +static void +gpc_Gprq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara_g22(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + + out->a = 65535; +} +#endif + +/* 16-bit to 8-bit conversions */ +/* sRGB: convert linear components to sRGB, alpha := 255 */ +static void +gpc_sRGB(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = isRGB(in->r); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = isRGB(in->b); + } + + else + { + out->g = isRGB(in->g); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = isRGB(in->b); + } + + out->a = 255; +} + +/* unpg: unpremultiply gray component and convert to sRGB (scale alpha) */ +static void +gpc_unpg(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = out->g = out->b = sRGB((double)in->g / in->a); + out->a = u8d(in->a / 257.); + } +} + +/* unpc: unpremultiply color components and convert to sRGB (scale alpha) */ +static void +gpc_unpc(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = sRGB((double)in->r / in->a); + out->g = sRGB((double)in->g / in->a); + out->b = sRGB((double)in->b / in->a); + out->a = u8d(in->a / 257.); + } +} + +/* b16g: composite linear onto gray background and convert the result to sRGB */ +static void +gpc_b16g(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else + { + double a = in->a/65535.; + double a1 = 1-a; + + a /= 65535; + out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); + } + + out->a = 255; +} + +/* b16c: composite linear onto color background and convert the result to sRGB*/ +static void +gpc_b16c(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + { + out->r = back->ir; + out->g = back->ig; + out->b = back->ib; + } + + else + { + double a = in->a/65535.; + double a1 = 1-a; + + a /= 65535; + out->r = sRGB(in->r * a + back->dr * a1); + out->g = sRGB(in->g * a + back->dg * a1); + out->b = sRGB(in->b * a + back->db * a1); + } + + out->a = 255; +} + +/* sG: convert linear RGB to sRGB grayscale */ +static void +gpc_sG(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/65535); + out->a = 255; +} + +/* sGp: unpremultiply RGB then convert to sRGB grayscale */ +static void +gpc_sGp(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/in->a); + out->a = u8d(in->a / 257.); + } +} + +/* sCp: unpremultiply RGB then convert to sRGB */ +static void +gpc_sCp(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = sRGB((double)in->r / in->a); + out->g = sRGB((double)in->g / in->a); + out->b = sRGB((double)in->b / in->a); + out->a = u8d(in->a / 257.); + } +} + +/* gb16: composite linear onto background and convert to sRGB grayscale */ +/* (order doesn't matter, the composite and grayscale operations permute) */ +static void +gpc_gb16(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else if (in->a >= 65535) + out->r = out->g = out->b = isRGB(in->g); + + else + { + double a = in->a / 65535.; + double a1 = 1-a; + + a /= 65535; + out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); + } + + out->a = 255; +} + +/* cb16: composite linear onto background and convert to sRGB */ +static void +gpc_cb16(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + { + out->r = back->ir; + out->g = back->ig; + out->b = back->ib; + } + + else if (in->a >= 65535) + { + out->r = isRGB(in->r); + out->g = isRGB(in->g); + out->b = isRGB(in->b); + } + + else + { + double a = in->a / 65535.; + double a1 = 1-a; + + a /= 65535; + out->r = sRGB(in->r * a + back->dr * a1); + out->g = sRGB(in->g * a + back->dg * a1); + out->b = sRGB(in->b * a + back->db * a1); + } + + out->a = 255; +} + +/* 16-bit to 16-bit conversions */ +/* A: set alpha to 65535 */ +static void +gpc_A(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = in->r; + out->g = in->g; + out->b = in->b; + out->a = 65535; +} + +/* g16: convert linear RGB to linear grayscale (alpha := 65535) */ +static void +gpc_g16(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); + out->a = 65535; +} + +/* g16': as 'g16' but alpha is unchanged */ +static void +gpc_g16q(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); + out->a = in->a; +} + +#if ALLOW_UNUSED_GPC +/* Unused functions (to hide them from GCC unused function warnings) */ +void (* const gpc_unused[]) + (Pixel *out, const Pixel *in, const Background *back) = +{ + gpc_Pre, gpc_Preq, gpc_Glin, gpc_Gpre, gpc_Gprq, gpc_nop8, gpc_nop6 +}; +#endif + +/* OUT: ----- 8-bit ----- ----- 16-bit ----- + * IN G GA RGB RGBA G GA RGB RGBA + * 8 G . . . . lin lin lin lin + * 8 GA bckg . bckc . pre' pre pre' pre + * 8 RGB g8 g8 . . glin glin lin lin + * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre + * 16 G sRGB sRGB sRGB sRGB . . . . + * 16 GA b16g unpg b16c unpc A . A . + * 16 RGB sG sG sRGB sRGB g16 g16 . . + * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . + * + * The matrix is held in an array indexed thus: + * + * gpc_fn[out_format & BASE_FORMATS][in_format & BASE_FORMATS]; + */ +/* This will produce a compile time error if the FORMAT_FLAG values don't + * match the above matrix! + */ +#if PNG_FORMAT_FLAG_ALPHA == 1 && PNG_FORMAT_FLAG_COLOR == 2 &&\ + PNG_FORMAT_FLAG_LINEAR == 4 +static void (* const gpc_fn[8/*in*/][8/*out*/]) + (Pixel *out, const Pixel *in, const Background *back) = +{ +/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ + {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_Lin, gpc_Lin, gpc_Lin, gpc_Lin }, + {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, + {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, + {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, + {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, + {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, + {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, + {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} +}; + +/* The array is repeated for the cases where both the input and output are color + * mapped because then different algorithms are used. + */ +static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/]) + (Pixel *out, const Pixel *in, const Background *back) = +{ +/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ + {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_lin, gpc_lin, gpc_lin, gpc_lin }, + {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, + {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, + {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, + {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, + {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, + {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, + {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} +}; + +/* The error arrays record the error in the same matrix; 64 entries, however + * the different algorithms used in libpng for colormap and direct conversions + * mean that four separate matrices are used (for each combination of + * colormapped and direct.) + * + * In some cases the conversion between sRGB formats goes via a linear + * intermediate; an sRGB to linear conversion (as above) is followed by a simple + * linear to sRGB step with no other conversions. This is done by a separate + * error array from an arbitrary 'in' format to one of the four basic outputs + * (since final output is always sRGB not colormapped). + * + * These arrays may be modified if the --accumulate flag is set during the run; + * then instead of logging errors they are simply added in. + * + * The three entries are currently for transparent, partially transparent and + * opaque input pixel values. Notice that alpha should be exact in each case. + * + * Errors in alpha should only occur when converting from a direct format + * to a colormapped format, when alpha is effectively smashed (so large + * errors can occur.) There should be no error in the '0' and 'opaque' + * values. The fourth entry in the array is used for the alpha error (and it + * should always be zero for the 'via linear' case since this is never color + * mapped.) + * + * Mapping to a colormap smashes the colors, it is necessary to have separate + * values for these cases because they are much larger; it is very much + * impossible to obtain a reasonable result, these are held in + * gpc_error_to_colormap. + */ +#if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */ +/* START MACHINE GENERATED */ +static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] = +{ + { /* input: sRGB-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: sRGB-gray+alpha */ + { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: sRGB-rgb */ + { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: sRGB-rgb+alpha */ + { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-gray */ + { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-gray+alpha */ + { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, + { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-rgb */ + { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, + { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-rgb+alpha */ + { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 }, + { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-rgb */ + { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 }, + { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 }, + { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 } + }, { /* input: color-mapped-sRGB-rgb+alpha */ + { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 }, + { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 }, + { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 } + }, { /* input: color-mapped-linear-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 } + } +}; +static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] = +{ + { /* input: sRGB-gray */ + { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 } + }, { /* input: sRGB-gray+alpha */ + { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 } + }, { /* input: sRGB-rgb */ + { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 } + }, { /* input: sRGB-rgb+alpha */ + { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 } + }, { /* input: linear-gray */ + { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } + }, { /* input: linear-gray+alpha */ + { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } + }, { /* input: linear-rgb */ + { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } + }, { /* input: linear-rgb+alpha */ + { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } + }, { /* input: color-mapped-sRGB-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-rgb */ + { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 } + }, { /* input: color-mapped-sRGB-rgb+alpha */ + { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 } + }, { /* input: color-mapped-linear-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + } +}; +static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] = +{ + { /* input: sRGB-gray */ + { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, + { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 } + }, { /* input: sRGB-gray+alpha */ + { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 }, + { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 } + }, { /* input: sRGB-rgb */ + { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 }, + { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 } + }, { /* input: sRGB-rgb+alpha */ + { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 }, + { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 } + }, { /* input: linear-gray */ + { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, + { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 } + }, { /* input: linear-gray+alpha */ + { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 }, + { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 } + }, { /* input: linear-rgb */ + { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 }, + { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 } + }, { /* input: linear-rgb+alpha */ + { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 }, + { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 } + } +}; +/* END MACHINE GENERATED */ +#endif /* COLORMAP flag check */ +#endif /* flag checks */ + +typedef struct +{ + /* Basic pixel information: */ + Image* in_image; /* Input image */ + const Image* out_image; /* Output image */ + + /* 'background' is the value passed to the gpc_ routines, it may be NULL if + * it should not be used (*this* program has an error if it crashes as a + * result!) + */ + Background background_color; + const Background* background; + + /* Precalculated values: */ + int in_opaque; /* Value of input alpha that is opaque */ + int is_palette; /* Sample values come from the palette */ + int accumulate; /* Accumlate component errors (don't log) */ + int output_8bit; /* Output is 8 bit (else 16 bit) */ + + void (*in_gp)(Pixel*, png_const_voidp); + void (*out_gp)(Pixel*, png_const_voidp); + + void (*transform)(Pixel *out, const Pixel *in, const Background *back); + /* A function to perform the required transform */ + + void (*from_linear)(Pixel *out, const Pixel *in, const Background *back); + /* For 'via_linear' transforms the final, from linear, step, else NULL */ + + png_uint_16 error[4]; + /* Three error values for transparent, partially transparent and opaque + * input pixels (in turn). + */ + + png_uint_16 *error_ptr; + /* Where these are stored in the static array (for 'accumulate') */ +} +Transform; + +/* Return a 'transform' as above for the given format conversion. */ +static void +transform_from_formats(Transform *result, Image *in_image, + const Image *out_image, png_const_colorp background, int via_linear) +{ + png_uint_32 in_format, out_format; + png_uint_32 in_base, out_base; + + memset(result, 0, sizeof *result); + + /* Store the original images for error messages */ + result->in_image = in_image; + result->out_image = out_image; + + in_format = in_image->image.format; + out_format = out_image->image.format; + + if (in_format & PNG_FORMAT_FLAG_LINEAR) + result->in_opaque = 65535; + else + result->in_opaque = 255; + + result->output_8bit = (out_format & PNG_FORMAT_FLAG_LINEAR) == 0; + + result->is_palette = 0; /* set by caller if required */ + result->accumulate = (in_image->opts & ACCUMULATE) != 0; + + /* The loaders (which need the ordering information) */ + result->in_gp = get_pixel(in_format); + result->out_gp = get_pixel(out_format); + + /* Remove the ordering information: */ + in_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; + in_base = in_format & BASE_FORMATS; + out_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; + out_base = out_format & BASE_FORMATS; + + if (via_linear) + { + /* Check for an error in this program: */ + if (out_format & (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLORMAP)) + { + fprintf(stderr, "internal transform via linear error 0x%x->0x%x\n", + in_format, out_format); + exit(1); + } + + result->transform = gpc_fn[in_base][out_base | PNG_FORMAT_FLAG_LINEAR]; + result->from_linear = gpc_fn[out_base | PNG_FORMAT_FLAG_LINEAR][out_base]; + result->error_ptr = gpc_error_via_linear[in_format][out_format]; + } + + else if (~in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) + { + /* The input is not colormapped but the output is, the errors will + * typically be large (only the grayscale-no-alpha case permits preserving + * even 8-bit values.) + */ + result->transform = gpc_fn[in_base][out_base]; + result->from_linear = NULL; + result->error_ptr = gpc_error_to_colormap[in_base][out_base]; + } + + else + { + /* The caller handles the colormap->pixel value conversion, so the + * transform function just gets a pixel value, however because libpng + * currently contains a different implementation for mapping a colormap if + * both input and output are colormapped we need different conversion + * functions to deal with errors in the libpng implementation. + */ + if (in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) + result->transform = gpc_fn_colormapped[in_base][out_base]; + else + result->transform = gpc_fn[in_base][out_base]; + result->from_linear = NULL; + result->error_ptr = gpc_error[in_format][out_format]; + } + + /* Follow the libpng simplified API rules to work out what to pass to the gpc + * routines as a background value, if one is not required pass NULL so that + * this program crashes in the even of a programming error. + */ + result->background = NULL; /* default: not required */ + + /* Rule 1: background only need be supplied if alpha is to be removed */ + if (in_format & ~out_format & PNG_FORMAT_FLAG_ALPHA) + { + /* The input value is 'NULL' to use the background and (otherwise) an sRGB + * background color (to use a solid color). The code above uses a fixed + * byte value, BUFFER_INIT8, for buffer even for 16-bit output. For + * linear (16-bit) output the sRGB background color is ignored; the + * composition is always on the background (so BUFFER_INIT8 * 257), except + * that for the colormap (i.e. linear colormapped output) black is used. + */ + result->background = &result->background_color; + + if (out_format & PNG_FORMAT_FLAG_LINEAR || via_linear) + { + if (out_format & PNG_FORMAT_FLAG_COLORMAP) + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = 0; + result->background_color.dr = + result->background_color.dg = + result->background_color.db = 0; + } + + else + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = BUFFER_INIT8 * 257; + result->background_color.dr = + result->background_color.dg = + result->background_color.db = 0; + } + } + + else /* sRGB output */ + { + if (background != NULL) + { + if (out_format & PNG_FORMAT_FLAG_COLOR) + { + result->background_color.ir = background->red; + result->background_color.ig = background->green; + result->background_color.ib = background->blue; + /* TODO: sometimes libpng uses the power law conversion here, how + * to handle this? + */ + result->background_color.dr = sRGB_to_d[background->red]; + result->background_color.dg = sRGB_to_d[background->green]; + result->background_color.db = sRGB_to_d[background->blue]; + } + + else /* grayscale: libpng only looks at 'g' */ + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = background->green; + /* TODO: sometimes libpng uses the power law conversion here, how + * to handle this? + */ + result->background_color.dr = + result->background_color.dg = + result->background_color.db = sRGB_to_d[background->green]; + } + } + + else if ((out_format & PNG_FORMAT_FLAG_COLORMAP) == 0) + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = BUFFER_INIT8; + /* TODO: sometimes libpng uses the power law conversion here, how + * to handle this? + */ + result->background_color.dr = + result->background_color.dg = + result->background_color.db = sRGB_to_d[BUFFER_INIT8]; + } + + /* Else the output is colormapped and a background color must be + * provided; if pngstest crashes then that is a bug in this program + * (though libpng should png_error as well.) + */ + else + result->background = NULL; + } + } + + if (result->background == NULL) + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = -1; /* not used */ + result->background_color.dr = + result->background_color.dg = + result->background_color.db = 1E30; /* not used */ + } + + + /* Copy the error values into the Transform: */ + result->error[0] = result->error_ptr[0]; + result->error[1] = result->error_ptr[1]; + result->error[2] = result->error_ptr[2]; + result->error[3] = result->error_ptr[3]; +} + + +/* Compare two pixels. + * + * OLD error values: +static int error_to_linear = 811; * by experiment * +static int error_to_linear_grayscale = 424; * by experiment * +static int error_to_sRGB = 6; * by experiment * +static int error_to_sRGB_grayscale = 17; * libpng error by calculation + + 2 by experiment * +static int error_in_compose = 2; * by experiment * +static int error_in_premultiply = 1; + * + * The following is *just* the result of a round trip from 8-bit sRGB to linear + * then back to 8-bit sRGB when it is done by libpng. There are two problems: + * + * 1) libpng currently uses a 2.2 power law with no linear segment, this results + * in instability in the low values and even with 16-bit precision sRGB(1) ends + * up mapping to sRGB(0) as a result of rounding in the 16-bit representation. + * This gives an error of 1 in the handling of value 1 only. + * + * 2) libpng currently uses an intermediate 8-bit linear value in gamma + * correction of 8-bit values. This results in many more errors, the worse of + * which is mapping sRGB(14) to sRGB(0). + * + * The general 'error_via_linear' is more complex because of pre-multiplication, + * this compounds the 8-bit errors according to the alpha value of the pixel. + * As a result 256 values are pre-calculated for error_via_linear. + */ +#if 0 +static int error_in_libpng_gamma; +static int error_via_linear[256]; /* Indexed by 8-bit alpha */ + +static void +init_error_via_linear(void) +{ + int alpha; + + error_via_linear[0] = 255; /* transparent pixel */ + + for (alpha=1; alpha<=255; ++alpha) + { + /* 16-bit values less than 128.5 get rounded to 8-bit 0 and so the worst + * case error arises with 16-bit 128.5, work out what sRGB + * (non-associated) value generates 128.5; any value less than this is + * going to map to 0, so the worst error is floor(value). + * + * Note that errors are considerably higher (more than a factor of 2) + * because libpng uses a simple power law for sRGB data at present. + * + * Add .1 for arithmetic errors inside libpng. + */ + double v = floor(255*pow(.5/*(128.5 * 255 / 65535)*/ / alpha, 1/2.2)+.1); + + error_via_linear[alpha] = (int)v; + } + + /* This is actually 14.99, but, despite the closeness to 15, 14 seems to work + * ok in this case. + */ + error_in_libpng_gamma = 14; +} +#endif + +static void +print_pixel(char string[64], const Pixel *pixel, png_uint_32 format) +{ + switch (format & (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR)) + { + case 0: + sprintf(string, "%s(%d)", format_names[format], pixel->g); + break; + + case PNG_FORMAT_FLAG_ALPHA: + sprintf(string, "%s(%d,%d)", format_names[format], pixel->g, + pixel->a); + break; + + case PNG_FORMAT_FLAG_COLOR: + sprintf(string, "%s(%d,%d,%d)", format_names[format], + pixel->r, pixel->g, pixel->b); + break; + + case PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA: + sprintf(string, "%s(%d,%d,%d,%d)", format_names[format], + pixel->r, pixel->g, pixel->b, pixel->a); + break; + + default: + sprintf(string, "invalid-format"); + break; + } +} + +static int +logpixel(const Transform *transform, png_uint_32 x, png_uint_32 y, + const Pixel *in, const Pixel *calc, const Pixel *out, const char *reason) +{ + const png_uint_32 in_format = transform->in_image->image.format; + const png_uint_32 out_format = transform->out_image->image.format; + + png_uint_32 back_format = out_format & ~PNG_FORMAT_FLAG_ALPHA; + const char *via_linear = ""; + + char pixel_in[64], pixel_calc[64], pixel_out[64], pixel_loc[64]; + char background_info[100]; + + print_pixel(pixel_in, in, in_format); + print_pixel(pixel_calc, calc, out_format); + print_pixel(pixel_out, out, out_format); + + if (transform->is_palette) + sprintf(pixel_loc, "palette: %lu", (unsigned long)y); + else + sprintf(pixel_loc, "%lu,%lu", (unsigned long)x, (unsigned long)y); + + if (transform->from_linear != NULL) + { + via_linear = " (via linear)"; + /* And as a result the *read* format which did any background processing + * was itself linear, so the background color information is also + * linear. + */ + back_format |= PNG_FORMAT_FLAG_LINEAR; + } + + if (transform->background != NULL) + { + Pixel back; + char pixel_back[64]; + + back.r = transform->background->ir; + back.g = transform->background->ig; + back.b = transform->background->ib; + back.a = -1; /* not used */ + + print_pixel(pixel_back, &back, back_format); + sprintf(background_info, " on background %s", pixel_back); + } + + else + background_info[0] = 0; + + if (transform->in_image->file_name != transform->out_image->file_name) + { + char error_buffer[512]; + sprintf(error_buffer, + "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" + "Use --preserve and examine: ", pixel_loc, reason, via_linear, + pixel_in, background_info, pixel_out, pixel_calc); + return logerror(transform->in_image, transform->in_image->file_name, + error_buffer, transform->out_image->file_name); + } + + else + { + char error_buffer[512]; + sprintf(error_buffer, + "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" + " The error happened when reading the original file with this format.", + pixel_loc, reason, via_linear, pixel_in, background_info, pixel_out, + pixel_calc); + return logerror(transform->in_image, transform->in_image->file_name, + error_buffer, ""); + } +} + +static int +cmppixel(Transform *transform, png_const_voidp in, png_const_voidp out, + png_uint_32 x, png_uint_32 y/*or palette index*/) +{ + int maxerr; + png_const_charp errmsg; + Pixel pixel_in, pixel_calc, pixel_out; + + transform->in_gp(&pixel_in, in); + + if (transform->from_linear == NULL) + transform->transform(&pixel_calc, &pixel_in, transform->background); + + else + { + transform->transform(&pixel_out, &pixel_in, transform->background); + transform->from_linear(&pixel_calc, &pixel_out, NULL); + } + + transform->out_gp(&pixel_out, out); + + /* Eliminate the case where the input and output values match exactly. */ + if (pixel_calc.a == pixel_out.a && pixel_calc.r == pixel_out.r && + pixel_calc.g == pixel_out.g && pixel_calc.b == pixel_out.b) + return 1; + + /* Eliminate the case where the output pixel is transparent and the output + * is 8-bit - any component values are valid. Don't check the input alpha + * here to also skip the 16-bit small alpha cases. + */ + if (transform->output_8bit && pixel_calc.a == 0 && pixel_out.a == 0) + return 1; + + /* Check for alpha errors first; an alpha error can damage the components too + * so avoid spurious checks on components if one is found. + */ + errmsg = NULL; + { + int err_a = abs(pixel_calc.a-pixel_out.a); + + if (err_a > transform->error[3]) + { + /* If accumulating check the components too */ + if (transform->accumulate) + transform->error[3] = (png_uint_16)err_a; + + else + errmsg = "alpha"; + } + } + + /* Now if *either* of the output alphas are 0 but alpha is within tolerance + * eliminate the 8-bit component comparison. + */ + if (errmsg == NULL && transform->output_8bit && + (pixel_calc.a == 0 || pixel_out.a == 0)) + return 1; + + if (errmsg == NULL) /* else just signal an alpha error */ + { + int err_r = abs(pixel_calc.r - pixel_out.r); + int err_g = abs(pixel_calc.g - pixel_out.g); + int err_b = abs(pixel_calc.b - pixel_out.b); + int limit; + + if ((err_r | err_g | err_b) == 0) + return 1; /* exact match */ + + /* Mismatch on a component, check the input alpha */ + if (pixel_in.a >= transform->in_opaque) + { + errmsg = "opaque component"; + limit = 2; /* opaque */ + } + + else if (pixel_in.a > 0) + { + errmsg = "alpha component"; + limit = 1; /* partially transparent */ + } + + else + { + errmsg = "transparent component (background)"; + limit = 0; /* transparent */ + } + + maxerr = err_r; + if (maxerr < err_g) maxerr = err_g; + if (maxerr < err_b) maxerr = err_b; + + if (maxerr <= transform->error[limit]) + return 1; /* within the error limits */ + + /* Handle a component mis-match; log it, just return an error code, or + * accumulate it. + */ + if (transform->accumulate) + { + transform->error[limit] = (png_uint_16)maxerr; + return 1; /* to cause the caller to keep going */ + } + } + + /* Failure to match and not accumulating, so the error must be logged. */ + return logpixel(transform, x, y, &pixel_in, &pixel_calc, &pixel_out, errmsg); +} + +static png_byte +component_loc(png_byte loc[4], png_uint_32 format) +{ + /* Given a format return the number of channels and the location of + * each channel. + * + * The mask 'loc' contains the component offset of the channels in the + * following order. Note that if 'format' is grayscale the entries 1-3 must + * all contain the location of the gray channel. + * + * 0: alpha + * 1: red or gray + * 2: green or gray + * 3: blue or gray + */ + png_byte channels; + + if (format & PNG_FORMAT_FLAG_COLOR) + { + channels = 3; + + loc[2] = 1; + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if (format & PNG_FORMAT_FLAG_BGR) + { + loc[1] = 2; + loc[3] = 0; + } + + else +# endif + { + loc[1] = 0; + loc[3] = 2; + } + } + + else + { + channels = 1; + loc[1] = loc[2] = loc[3] = 0; + } + + if (format & PNG_FORMAT_FLAG_ALPHA) + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + { + loc[0] = 0; + ++loc[1]; + ++loc[2]; + ++loc[3]; + } + + else +# endif + loc[0] = channels; + + ++channels; + } + + else + loc[0] = 4; /* not present */ + + return channels; +} + +/* Compare two images, the original 'a', which was written out then read back in + * to * give image 'b'. The formats may have been changed. + */ +static int +compare_two_images(Image *a, Image *b, int via_linear, + png_const_colorp background) +{ + ptrdiff_t stridea = a->stride; + ptrdiff_t strideb = b->stride; + png_const_bytep rowa = a->buffer+16; + png_const_bytep rowb = b->buffer+16; + const png_uint_32 width = a->image.width; + const png_uint_32 height = a->image.height; + const png_uint_32 formata = a->image.format; + const png_uint_32 formatb = b->image.format; + const unsigned int a_sample = PNG_IMAGE_SAMPLE_SIZE(formata); + const unsigned int b_sample = PNG_IMAGE_SAMPLE_SIZE(formatb); + int alpha_added, alpha_removed; + int bchannels; + int btoa[4]; + png_uint_32 y; + Transform tr; + + /* This should never happen: */ + if (width != b->image.width || height != b->image.height) + return logerror(a, a->file_name, ": width x height changed: ", + b->file_name); + + /* Set up the background and the transform */ + transform_from_formats(&tr, a, b, background, via_linear); + + /* Find the first row and inter-row space. */ + if (!(formata & PNG_FORMAT_FLAG_COLORMAP) && + (formata & PNG_FORMAT_FLAG_LINEAR)) + stridea *= 2; + + if (!(formatb & PNG_FORMAT_FLAG_COLORMAP) && + (formatb & PNG_FORMAT_FLAG_LINEAR)) + strideb *= 2; + + if (stridea < 0) rowa += (height-1) * (-stridea); + if (strideb < 0) rowb += (height-1) * (-strideb); + + /* First shortcut the two colormap case by comparing the image data; if it + * matches then we expect the colormaps to match, although this is not + * absolutely necessary for an image match. If the colormaps fail to match + * then there is a problem in libpng. + */ + if (formata & formatb & PNG_FORMAT_FLAG_COLORMAP) + { + /* Only check colormap entries that actually exist; */ + png_const_bytep ppa, ppb; + int match; + png_byte in_use[256], amax = 0, bmax = 0; + + memset(in_use, 0, sizeof in_use); + + ppa = rowa; + ppb = rowb; + + /* Do this the slow way to accumulate the 'in_use' flags, don't break out + * of the loop until the end; this validates the color-mapped data to + * ensure all pixels are valid color-map indexes. + */ + for (y=0, match=1; y bmax) + bmax = bval; + + if (bval != aval) + match = 0; + + in_use[aval] = 1; + if (aval > amax) + amax = aval; + } + } + + /* If the buffers match then the colormaps must too. */ + if (match) + { + /* Do the color-maps match, entry by entry? Only check the 'in_use' + * entries. An error here should be logged as a color-map error. + */ + png_const_bytep a_cmap = (png_const_bytep)a->colormap; + png_const_bytep b_cmap = (png_const_bytep)b->colormap; + int result = 1; /* match by default */ + + /* This is used in logpixel to get the error message correct. */ + tr.is_palette = 1; + + for (y=0; y<256; ++y, a_cmap += a_sample, b_cmap += b_sample) + if (in_use[y]) + { + /* The colormap entries should be valid, but because libpng doesn't + * do any checking at present the original image may contain invalid + * pixel values. These cause an error here (at present) unless + * accumulating errors in which case the program just ignores them. + */ + if (y >= a->image.colormap_entries) + { + if ((a->opts & ACCUMULATE) == 0) + { + char pindex[9]; + sprintf(pindex, "%lu[%lu]", (unsigned long)y, + (unsigned long)a->image.colormap_entries); + logerror(a, a->file_name, ": bad pixel index: ", pindex); + } + result = 0; + } + + else if (y >= b->image.colormap_entries) + { + if ((a->opts & ACCUMULATE) == 0) + { + char pindex[9]; + sprintf(pindex, "%lu[%lu]", (unsigned long)y, + (unsigned long)b->image.colormap_entries); + logerror(b, b->file_name, ": bad pixel index: ", pindex); + } + result = 0; + } + + /* All the mismatches are logged here; there can only be 256! */ + else if (!cmppixel(&tr, a_cmap, b_cmap, 0, y)) + result = 0; + } + + /* If reqested copy the error values back from the Transform. */ + if (a->opts & ACCUMULATE) + { + tr.error_ptr[0] = tr.error[0]; + tr.error_ptr[1] = tr.error[1]; + tr.error_ptr[2] = tr.error[2]; + tr.error_ptr[3] = tr.error[3]; + result = 1; /* force a continue */ + } + + return result; + } + + /* else the image buffers don't match pixel-wise so compare sample values + * instead, but first validate that the pixel indexes are in range (but + * only if not accumulating, when the error is ignored.) + */ + else if ((a->opts & ACCUMULATE) == 0) + { + /* Check the original image first, + * TODO: deal with input images with bad pixel values? + */ + if (amax >= a->image.colormap_entries) + { + char pindex[9]; + sprintf(pindex, "%d[%lu]", amax, + (unsigned long)a->image.colormap_entries); + return logerror(a, a->file_name, ": bad pixel index: ", pindex); + } + + else if (bmax >= b->image.colormap_entries) + { + char pindex[9]; + sprintf(pindex, "%d[%lu]", bmax, + (unsigned long)b->image.colormap_entries); + return logerror(b, b->file_name, ": bad pixel index: ", pindex); + } + } + } + + /* We can directly compare pixel values without the need to use the read + * or transform support (i.e. a memory compare) if: + * + * 1) The bit depth has not changed. + * 2) RGB to grayscale has not been done (the reverse is ok; we just compare + * the three RGB values to the original grayscale.) + * 3) An alpha channel has not been removed from an 8-bit format, or the + * 8-bit alpha value of the pixel was 255 (opaque). + * + * If an alpha channel has been *added* then it must have the relevant opaque + * value (255 or 65535). + * + * The fist two the tests (in the order given above) (using the boolean + * equivalence !a && !b == !(a || b)) + */ + if (!(((formata ^ formatb) & PNG_FORMAT_FLAG_LINEAR) | + (formata & (formatb ^ PNG_FORMAT_FLAG_COLOR) & PNG_FORMAT_FLAG_COLOR))) + { + /* Was an alpha channel changed? */ + const png_uint_32 alpha_changed = (formata ^ formatb) & + PNG_FORMAT_FLAG_ALPHA; + + /* Was an alpha channel removed? (The third test.) If so the direct + * comparison is only possible if the input alpha is opaque. + */ + alpha_removed = (formata & alpha_changed) != 0; + + /* Was an alpha channel added? */ + alpha_added = (formatb & alpha_changed) != 0; + + /* The channels may have been moved between input and output, this finds + * out how, recording the result in the btoa array, which says where in + * 'a' to find each channel of 'b'. If alpha was added then btoa[alpha] + * ends up as 4 (and is not used.) + */ + { + int i; + png_byte aloc[4]; + png_byte bloc[4]; + + /* The following are used only if the formats match, except that + * 'bchannels' is a flag for matching formats. btoa[x] says, for each + * channel in b, where to find the corresponding value in a, for the + * bchannels. achannels may be different for a gray to rgb transform + * (a will be 1 or 2, b will be 3 or 4 channels.) + */ + (void)component_loc(aloc, formata); + bchannels = component_loc(bloc, formatb); + + /* Hence the btoa array. */ + for (i=0; i<4; ++i) if (bloc[i] < 4) + btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */ + + if (alpha_added) + alpha_added = bloc[0]; /* location of alpha channel in image b */ + + else + alpha_added = 4; /* Won't match an image b channel */ + + if (alpha_removed) + alpha_removed = aloc[0]; /* location of alpha channel in image a */ + + else + alpha_removed = 4; + } + } + + else + { + /* Direct compare is not possible, cancel out all the corresponding local + * variables. + */ + bchannels = 0; + alpha_removed = alpha_added = 4; + btoa[3] = btoa[2] = btoa[1] = btoa[0] = 4; /* 4 == not present */ + } + + for (y=0; ycolormap + a_sample * *ppa++; + else + psa = ppa, ppa += a_sample; + + if (formatb & PNG_FORMAT_FLAG_COLORMAP) + psb = (png_const_bytep)b->colormap + b_sample * *ppb++; + else + psb = ppb, ppb += b_sample; + + /* Do the fast test if possible. */ + if (bchannels) + { + /* Check each 'b' channel against either the corresponding 'a' + * channel or the opaque alpha value, as appropriate. If + * alpha_removed value is set (not 4) then also do this only if the + * 'a' alpha channel (alpha_removed) is opaque; only relevant for + * the 8-bit case. + */ + if (formatb & PNG_FORMAT_FLAG_LINEAR) /* 16-bit checks */ + { + png_const_uint_16p pua = aligncastconst(png_const_uint_16p, psa); + png_const_uint_16p pub = aligncastconst(png_const_uint_16p, psb); + + switch (bchannels) + { + case 4: + if (pua[btoa[3]] != pub[3]) break; + case 3: + if (pua[btoa[2]] != pub[2]) break; + case 2: + if (pua[btoa[1]] != pub[1]) break; + case 1: + if (pua[btoa[0]] != pub[0]) break; + if (alpha_added != 4 && pub[alpha_added] != 65535) break; + continue; /* x loop */ + default: + break; /* impossible */ + } + } + + else if (alpha_removed == 4 || psa[alpha_removed] == 255) + { + switch (bchannels) + { + case 4: + if (psa[btoa[3]] != psb[3]) break; + case 3: + if (psa[btoa[2]] != psb[2]) break; + case 2: + if (psa[btoa[1]] != psb[1]) break; + case 1: + if (psa[btoa[0]] != psb[0]) break; + if (alpha_added != 4 && psb[alpha_added] != 255) break; + continue; /* x loop */ + default: + break; /* impossible */ + } + } + } + + /* If we get to here the fast match failed; do the slow match for this + * pixel. + */ + if (!cmppixel(&tr, psa, psb, x, y) && (a->opts & KEEP_GOING) == 0) + return 0; /* error case */ + } + } + + /* If reqested copy the error values back from the Transform. */ + if (a->opts & ACCUMULATE) + { + tr.error_ptr[0] = tr.error[0]; + tr.error_ptr[1] = tr.error[1]; + tr.error_ptr[2] = tr.error[2]; + tr.error_ptr[3] = tr.error[3]; + } + + return 1; +} + +/* Read the file; how the read gets done depends on which of input_file and + * input_memory have been set. + */ +static int +read_file(Image *image, png_uint_32 format, png_const_colorp background) +{ + memset(&image->image, 0, sizeof image->image); + image->image.version = PNG_IMAGE_VERSION; + + if (image->input_memory != NULL) + { + if (!png_image_begin_read_from_memory(&image->image, image->input_memory, + image->input_memory_size)) + return logerror(image, "memory init: ", image->file_name, ""); + } + +# ifdef PNG_STDIO_SUPPORTED + else if (image->input_file != NULL) + { + if (!png_image_begin_read_from_stdio(&image->image, image->input_file)) + return logerror(image, "stdio init: ", image->file_name, ""); + } + + else + { + if (!png_image_begin_read_from_file(&image->image, image->file_name)) + return logerror(image, "file init: ", image->file_name, ""); + } +# else + else + { + return logerror(image, "unsupported file/stdio init: ", + image->file_name, ""); + } +# endif + + /* This must be set after the begin_read call: */ + if (image->opts & sRGB_16BIT) + image->image.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; + + /* Have an initialized image with all the data we need plus, maybe, an + * allocated file (myfile) or buffer (mybuffer) that need to be freed. + */ + { + int result; + png_uint_32 image_format; + + /* Print both original and output formats. */ + image_format = image->image.format; + + if (image->opts & VERBOSE) + { + printf("%s %lu x %lu %s -> %s", image->file_name, + (unsigned long)image->image.width, + (unsigned long)image->image.height, + format_names[image_format & FORMAT_MASK], + (format & FORMAT_NO_CHANGE) != 0 || image->image.format == format + ? "no change" : format_names[format & FORMAT_MASK]); + + if (background != NULL) + printf(" background(%d,%d,%d)\n", background->red, + background->green, background->blue); + else + printf("\n"); + + fflush(stdout); + } + + /* 'NO_CHANGE' combined with the color-map flag forces the base format + * flags to be set on read to ensure that the original representation is + * not lost in the pass through a colormap format. + */ + if ((format & FORMAT_NO_CHANGE) != 0) + { + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && + (image_format & PNG_FORMAT_FLAG_COLORMAP) != 0) + format = (image_format & ~BASE_FORMATS) | (format & BASE_FORMATS); + + else + format = image_format; + } + + image->image.format = format; + + image->stride = PNG_IMAGE_ROW_STRIDE(image->image) + image->stride_extra; + allocbuffer(image); + + result = png_image_finish_read(&image->image, background, + image->buffer+16, (png_int_32)image->stride, image->colormap); + + checkbuffer(image, image->file_name); + + if (result) + return checkopaque(image); + + else + return logerror(image, image->file_name, ": image read failed", ""); + } +} + +/* Reads from a filename, which must be in image->file_name, but uses + * image->opts to choose the method. The file is always read in its native + * format (the one the simplified API suggests). + */ +static int +read_one_file(Image *image) +{ + if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO)) + { + /* memory or stdio. */ + FILE *f = fopen(image->file_name, "rb"); + + if (f != NULL) + { + if (image->opts & READ_FILE) + image->input_file = f; + + else /* memory */ + { + if (fseek(f, 0, SEEK_END) == 0) + { + long int cb = ftell(f); + + if (cb > 0 && (unsigned long int)cb < (size_t)~(size_t)0) + { + png_bytep b = voidcast(png_bytep, malloc((size_t)cb)); + + if (b != NULL) + { + rewind(f); + + if (fread(b, (size_t)cb, 1, f) == 1) + { + fclose(f); + image->input_memory_size = cb; + image->input_memory = b; + } + + else + { + free(b); + return logclose(image, f, image->file_name, + ": read failed: "); + } + } + + else + return logclose(image, f, image->file_name, + ": out of memory: "); + } + + else if (cb == 0) + return logclose(image, f, image->file_name, + ": zero length: "); + + else + return logclose(image, f, image->file_name, + ": tell failed: "); + } + + else + return logclose(image, f, image->file_name, ": seek failed: "); + } + } + + else + return logerror(image, image->file_name, ": open failed: ", + strerror(errno)); + } + + return read_file(image, FORMAT_NO_CHANGE, NULL); +} + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +static int +write_one_file(Image *output, Image *image, int convert_to_8bit) +{ + if (image->opts & FAST_WRITE) + image->image.flags |= PNG_IMAGE_FLAG_FAST; + + if (image->opts & USE_STDIO) + { + FILE *f = tmpfile(); + + if (f != NULL) + { + if (png_image_write_to_stdio(&image->image, f, convert_to_8bit, + image->buffer+16, (png_int_32)image->stride, image->colormap)) + { + if (fflush(f) == 0) + { + rewind(f); + initimage(output, image->opts, "tmpfile", image->stride_extra); + output->input_file = f; + if (!checkopaque(image)) + return 0; + } + + else + return logclose(image, f, "tmpfile", ": flush: "); + } + + else + { + fclose(f); + return logerror(image, "tmpfile", ": write failed", ""); + } + } + + else + return logerror(image, "tmpfile", ": open: ", strerror(errno)); + } + + else + { + static int counter = 0; + char name[32]; + + sprintf(name, "%s%d.png", tmpf, ++counter); + + if (png_image_write_to_file(&image->image, name, convert_to_8bit, + image->buffer+16, (png_int_32)image->stride, image->colormap)) + { + initimage(output, image->opts, output->tmpfile_name, + image->stride_extra); + /* Afterwards, or freeimage will delete it! */ + strcpy(output->tmpfile_name, name); + + if (!checkopaque(image)) + return 0; + } + + else + return logerror(image, name, ": write failed", ""); + } + + /* 'output' has an initialized temporary image, read this back in and compare + * this against the original: there should be no change since the original + * format was written unmodified unless 'convert_to_8bit' was specified. + * However, if the original image was color-mapped, a simple read will zap + * the linear, color and maybe alpha flags, this will cause spurious failures + * under some circumstances. + */ + if (read_file(output, image->image.format | FORMAT_NO_CHANGE, NULL)) + { + png_uint_32 original_format = image->image.format; + + if (convert_to_8bit) + original_format &= ~PNG_FORMAT_FLAG_LINEAR; + + if ((output->image.format & BASE_FORMATS) != + (original_format & BASE_FORMATS)) + return logerror(image, image->file_name, ": format changed on read: ", + output->file_name); + + return compare_two_images(image, output, 0/*via linear*/, NULL); + } + + else + return logerror(output, output->tmpfile_name, + ": read of new file failed", ""); +} +#endif + +static int +testimage(Image *image, png_uint_32 opts, format_list *pf) +{ + int result; + Image copy; + + /* Copy the original data, stealing it from 'image' */ + checkopaque(image); + copy = *image; + + copy.opts = opts; + copy.buffer = NULL; + copy.bufsize = 0; + copy.allocsize = 0; + + image->input_file = NULL; + image->input_memory = NULL; + image->input_memory_size = 0; + image->tmpfile_name[0] = 0; + + { + png_uint_32 counter; + Image output; + + newimage(&output); + + result = 1; + + /* Use the low bit of 'counter' to indicate whether or not to do alpha + * removal with a background color or by composting onto the image; this + * step gets skipped if it isn't relevant + */ + for (counter=0; counter<2*FORMAT_COUNT; ++counter) + if (format_isset(pf, counter >> 1)) + { + png_uint_32 format = counter >> 1; + + png_color background_color; + png_colorp background = NULL; + + /* If there is a format change that removes the alpha channel then + * the background is relevant. If the output is 8-bit color-mapped + * then a background color *must* be provided, otherwise there are + * two tests to do - one with a color, the other with NULL. The + * NULL test happens second. + */ + if ((counter & 1) == 0) + { + if ((format & PNG_FORMAT_FLAG_ALPHA) == 0 && + (image->image.format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Alpha/transparency will be removed, the background is + * relevant: make it a color the first time + */ + random_color(&background_color); + background = &background_color; + + /* BUT if the output is to a color-mapped 8-bit format then + * the background must always be a color, so increment 'counter' + * to skip the NULL test. + */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && + (format & PNG_FORMAT_FLAG_LINEAR) == 0) + ++counter; + } + + /* Otherwise an alpha channel is not being eliminated, just leave + * background NULL and skip the (counter & 1) NULL test. + */ + else + ++counter; + } + /* else just use NULL for background */ + + resetimage(©); + copy.opts = opts; /* in case read_file needs to change it */ + + result = read_file(©, format, background); + if (!result) + break; + + /* Make sure the file just read matches the original file. */ + result = compare_two_images(image, ©, 0/*via linear*/, background); + if (!result) + break; + +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + /* Write the *copy* just made to a new file to make sure the write + * side works ok. Check the conversion to sRGB if the copy is + * linear. + */ + output.opts = opts; + result = write_one_file(&output, ©, 0/*convert to 8bit*/); + if (!result) + break; + + /* Validate against the original too; the background is needed here + * as well so that compare_two_images knows what color was used. + */ + result = compare_two_images(image, &output, 0, background); + if (!result) + break; + + if ((format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (format & PNG_FORMAT_FLAG_COLORMAP) == 0) + { + /* 'output' is linear, convert to the corresponding sRGB format. + */ + output.opts = opts; + result = write_one_file(&output, ©, 1/*convert to 8bit*/); + if (!result) + break; + + /* This may involve a conversion via linear; in the ideal world + * this would round-trip correctly, but libpng 1.5.7 is not the + * ideal world so allow a drift (error_via_linear). + * + * 'image' has an alpha channel but 'output' does not then there + * will a strip-alpha-channel operation (because 'output' is + * linear), handle this by composing on black when doing the + * comparison. + */ + result = compare_two_images(image, &output, 1/*via_linear*/, + background); + if (!result) + break; + } +# endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ + } + + freeimage(&output); + } + + freeimage(©); + + return result; +} + +static int +test_one_file(const char *file_name, format_list *formats, png_uint_32 opts, + int stride_extra, int log_pass) +{ + int result; + Image image; + + newimage(&image); + initimage(&image, opts, file_name, stride_extra); + result = read_one_file(&image); + if (result) + result = testimage(&image, opts, formats); + freeimage(&image); + + /* Ensure that stderr is flushed into any log file */ + fflush(stderr); + + if (log_pass) + { + if (result) + printf("PASS:"); + + else + printf("FAIL:"); + +# ifndef PNG_SIMPLIFIED_WRITE_SUPPORTED + printf(" (no write)"); +# endif + + print_opts(opts); + printf(" %s\n", file_name); + /* stdout may not be line-buffered if it is piped to a file, so: */ + fflush(stdout); + } + + else if (!result) + exit(1); + + return result; +} + +int +main(int argc, char **argv) +{ + png_uint_32 opts = FAST_WRITE; + format_list formats; + const char *touch = NULL; + int log_pass = 0; + int redundant = 0; + int stride_extra = 0; + int retval = 0; + int c; + + init_sRGB_to_d(); +#if 0 + init_error_via_linear(); +#endif + format_init(&formats); + + for (c=1; c= sizeof tmpf) + { + fflush(stdout); + fprintf(stderr, "%s: %s is too long for a temp file prefix\n", + argv[0], argv[c]); + exit(99); + } + + /* Safe: checked above */ + strcpy(tmpf, argv[c]); + } + + else + { + fflush(stdout); + fprintf(stderr, "%s: %s requires a temporary file prefix\n", + argv[0], arg); + exit(99); + } + } + else if (strcmp(arg, "--touch") == 0) + { + if (c+1 < argc) + touch = argv[++c]; + + else + { + fflush(stdout); + fprintf(stderr, "%s: %s requires a file name argument\n", + argv[0], arg); + exit(99); + } + } + else if (arg[0] == '+') + { + png_uint_32 format = formatof(arg+1); + + if (format > FORMAT_COUNT) + exit(99); + + format_set(&formats, format); + } + else if (arg[0] == '-' && arg[1] != 0 && (arg[1] != '0' || arg[2] != 0)) + { + fflush(stdout); + fprintf(stderr, "%s: unknown option: %s\n", argv[0], arg); + exit(99); + } + else + { + if (format_is_initial(&formats)) + format_default(&formats, redundant); + + if (arg[0] == '-') + { + const int term = (arg[1] == '0' ? 0 : '\n'); + unsigned int ich = 0; + + /* Loop reading files, use a static buffer to simplify this and just + * stop if the name gets to long. + */ + static char buffer[4096]; + + do + { + int ch = getchar(); + + /* Don't allow '\0' in file names, and terminate with '\n' or, + * for -0, just '\0' (use -print0 to find to make this work!) + */ + if (ch == EOF || ch == term || ch == 0) + { + buffer[ich] = 0; + + if (ich > 0 && !test_one_file(buffer, &formats, opts, + stride_extra, log_pass)) + retval = 1; + + if (ch == EOF) + break; + + ich = 0; + --ich; /* so that the increment below sets it to 0 again */ + } + + else + buffer[ich] = (char)ch; + } while (++ich < sizeof buffer); + + if (ich) + { + buffer[32] = 0; + buffer[4095] = 0; + fprintf(stderr, "%s...%s: file name too long\n", buffer, + buffer+(4096-32)); + exit(99); + } + } + + else if (!test_one_file(arg, &formats, opts, stride_extra, log_pass)) + retval = 1; + } + } + + if (opts & ACCUMULATE) + { + unsigned int in; + + printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n"); + printf("{\n"); + for (in=0; in<16; ++in) + { + unsigned int out; + printf(" { /* input: %s */\n ", format_names[in]); + for (out=0; out<16; ++out) + { + unsigned int alpha; + printf(" {"); + for (alpha=0; alpha<4; ++alpha) + { + printf(" %d", gpc_error[in][out][alpha]); + if (alpha < 3) putchar(','); + } + printf(" }"); + if (out < 15) + { + putchar(','); + if (out % 4 == 3) printf("\n "); + } + } + printf("\n }"); + + if (in < 15) + putchar(','); + else + putchar('\n'); + } + printf("};\n"); + + printf("static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =\n"); + printf("{\n"); + for (in=0; in<16; ++in) + { + unsigned int out; + printf(" { /* input: %s */\n ", format_names[in]); + for (out=0; out<4; ++out) + { + unsigned int alpha; + printf(" {"); + for (alpha=0; alpha<4; ++alpha) + { + printf(" %d", gpc_error_via_linear[in][out][alpha]); + if (alpha < 3) putchar(','); + } + printf(" }"); + if (out < 3) + putchar(','); + } + printf("\n }"); + + if (in < 15) + putchar(','); + else + putchar('\n'); + } + printf("};\n"); + + printf("static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =\n"); + printf("{\n"); + for (in=0; in<8; ++in) + { + unsigned int out; + printf(" { /* input: %s */\n ", format_names[in]); + for (out=0; out<8; ++out) + { + unsigned int alpha; + printf(" {"); + for (alpha=0; alpha<4; ++alpha) + { + printf(" %d", gpc_error_to_colormap[in][out][alpha]); + if (alpha < 3) putchar(','); + } + printf(" }"); + if (out < 7) + { + putchar(','); + if (out % 4 == 3) printf("\n "); + } + } + printf("\n }"); + + if (in < 7) + putchar(','); + else + putchar('\n'); + } + printf("};\n"); + } + + if (retval == 0 && touch != NULL) + { + FILE *fsuccess = fopen(touch, "wt"); + + if (fsuccess != NULL) + { + int error = 0; + fprintf(fsuccess, "PNG simple API tests succeeded\n"); + fflush(fsuccess); + error = ferror(fsuccess); + + if (fclose(fsuccess) || error) + { + fflush(stdout); + fprintf(stderr, "%s: write failed\n", touch); + exit(99); + } + } + + else + { + fflush(stdout); + fprintf(stderr, "%s: open failed\n", touch); + exit(99); + } + } + + return retval; +} + +#else /* !PNG_SIMPLIFIED_READ_SUPPORTED */ +int main(void) +{ + fprintf(stderr, "pngstest: no read support in libpng, test skipped\n"); + /* So the test is skipped: */ + return 77; +} +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ diff --git a/main/source/includes/lpng1610/contrib/libtests/pngunknown.c b/main/source/includes/lpng1610/contrib/libtests/pngunknown.c index dd0f879f..b8c4899d 100644 --- a/main/source/includes/lpng1610/contrib/libtests/pngunknown.c +++ b/main/source/includes/lpng1610/contrib/libtests/pngunknown.c @@ -1,1245 +1,1245 @@ - -/* pngunknown.c - test the read side unknown chunk handling - * - * Last changed in libpng 1.6.10 [March 6, 2014] - * Copyright (c) 2014 Glenn Randers-Pehrson - * Written by John Cunningham Bowler - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * NOTES: - * This is a C program that is intended to be linked against libpng. It - * allows the libpng unknown handling code to be tested by interpreting - * arguments to save or discard combinations of chunks. The program is - * currently just a minimal validation for the built-in libpng facilities. - */ - -#include -#include -#include -#include - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include -#else -# include "../../png.h" -#endif - -/* Since this program tests the ability to change the unknown chunk handling - * these must be defined: - */ -#if defined(PNG_SET_UNKNOWN_CHUNKS_SUPPORTED) &&\ - defined(PNG_READ_SUPPORTED) - -/* One of these must be defined to allow us to find out what happened. It is - * still useful to set unknown chunk handling without either of these in order - * to cause *known* chunks to be discarded. This can be a significant - * efficiency gain, but it can't really be tested here. - */ -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) ||\ - defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED) - -#if PNG_LIBPNG_VER < 10500 -/* This deliberately lacks the PNG_CONST. */ -typedef png_byte *png_const_bytep; - -/* This is copied from 1.5.1 png.h: */ -#define PNG_INTERLACE_ADAM7_PASSES 7 -#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) -#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) -#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) -#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) -#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) -#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) -#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ - (((yIn)<>(((7-(off))-(pass))<<2)) & 0xFU) | \ - ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) -#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ - ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) -#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ - ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) - -/* These are needed too for the default build: */ -#define PNG_WRITE_16BIT_SUPPORTED -#define PNG_READ_16BIT_SUPPORTED - -/* This comes from pnglibconf.h afer 1.5: */ -#define PNG_FP_1 100000 -#define PNG_GAMMA_THRESHOLD_FIXED\ - ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) -#endif - -#if PNG_LIBPNG_VER < 10600 - /* 1.6.0 constifies many APIs. The following exists to allow pngvalid to be - * compiled against earlier versions. - */ -# define png_const_structp png_structp -#endif - -#if PNG_LIBPNG_VER < 10700 - /* Copied from libpng 1.7.0 png.h */ -#define PNG_u2(b1, b2) (((unsigned int)(b1) << 8) + (b2)) - -#define PNG_U16(b1, b2) ((png_uint_16)PNG_u2(b1, b2)) -#define PNG_U32(b1, b2, b3, b4)\ - (((png_uint_32)PNG_u2(b1, b2) << 16) + PNG_u2(b3, b4)) - -/* Constants for known chunk types. - */ -#define png_IDAT PNG_U32( 73, 68, 65, 84) -#define png_IEND PNG_U32( 73, 69, 78, 68) -#define png_IHDR PNG_U32( 73, 72, 68, 82) -#define png_PLTE PNG_U32( 80, 76, 84, 69) -#define png_bKGD PNG_U32( 98, 75, 71, 68) -#define png_cHRM PNG_U32( 99, 72, 82, 77) -#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ -#define png_gAMA PNG_U32(103, 65, 77, 65) -#define png_gIFg PNG_U32(103, 73, 70, 103) -#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ -#define png_gIFx PNG_U32(103, 73, 70, 120) -#define png_hIST PNG_U32(104, 73, 83, 84) -#define png_iCCP PNG_U32(105, 67, 67, 80) -#define png_iTXt PNG_U32(105, 84, 88, 116) -#define png_oFFs PNG_U32(111, 70, 70, 115) -#define png_pCAL PNG_U32(112, 67, 65, 76) -#define png_pHYs PNG_U32(112, 72, 89, 115) -#define png_sBIT PNG_U32(115, 66, 73, 84) -#define png_sCAL PNG_U32(115, 67, 65, 76) -#define png_sPLT PNG_U32(115, 80, 76, 84) -#define png_sRGB PNG_U32(115, 82, 71, 66) -#define png_sTER PNG_U32(115, 84, 69, 82) -#define png_tEXt PNG_U32(116, 69, 88, 116) -#define png_tIME PNG_U32(116, 73, 77, 69) -#define png_tRNS PNG_U32(116, 82, 78, 83) -#define png_zTXt PNG_U32(122, 84, 88, 116) - -/* Test on flag values as defined in the spec (section 5.4): */ -#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) -#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) -#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) -#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) -#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) - -#endif /* PNG_LIBPNG_VER < 10700 */ - -#ifdef __cplusplus -# define this not_the_cpp_this -# define new not_the_cpp_new -# define voidcast(type, value) static_cast(value) -#else -# define voidcast(type, value) (value) -#endif /* __cplusplus */ - -/* Unused formal parameter errors are removed using the following macro which is - * expected to have no bad effects on performance. - */ -#ifndef UNUSED -# if defined(__GNUC__) || defined(_MSC_VER) -# define UNUSED(param) (void)param; -# else -# define UNUSED(param) -# endif -#endif - -/* Types of chunks not known to libpng */ -#define png_vpAg PNG_U32(118, 112, 65, 103) - -/* Chunk information */ -#define PNG_INFO_tEXt 0x10000000U -#define PNG_INFO_iTXt 0x20000000U -#define PNG_INFO_zTXt 0x40000000U - -#define PNG_INFO_sTER 0x01000000U -#define PNG_INFO_vpAg 0x02000000U - -#define ABSENT 0 -#define START 1 -#define END 2 - -static struct -{ - char name[5]; - png_uint_32 flag; - png_uint_32 tag; - int unknown; /* Chunk not known to libpng */ - int all; /* Chunk set by the '-1' option */ - int position; /* position in pngtest.png */ - int keep; /* unknown handling setting */ -} chunk_info[] = { - /* Critical chunks */ - { "IDAT", PNG_INFO_IDAT, png_IDAT, 0, 0, START, 0 }, /* must be [0] */ - { "PLTE", PNG_INFO_PLTE, png_PLTE, 0, 0, ABSENT, 0 }, - - /* Non-critical chunks that libpng handles */ - /* This is a mess but it seems to be the only way to do it - there is no way - * to check for a definition outside a #if. - */ - { "bKGD", PNG_INFO_bKGD, png_bKGD, -# ifdef PNG_READ_bKGD_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "cHRM", PNG_INFO_cHRM, png_cHRM, -# ifdef PNG_READ_cHRM_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "gAMA", PNG_INFO_gAMA, png_gAMA, -# ifdef PNG_READ_gAMA_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "hIST", PNG_INFO_hIST, png_hIST, -# ifdef PNG_READ_hIST_SUPPORTED - 0, -# else - 1, -# endif - 1, ABSENT, 0 }, - { "iCCP", PNG_INFO_iCCP, png_iCCP, -# ifdef PNG_READ_iCCP_SUPPORTED - 0, -# else - 1, -# endif - 1, ABSENT, 0 }, - { "iTXt", PNG_INFO_iTXt, png_iTXt, -# ifdef PNG_READ_iTXt_SUPPORTED - 0, -# else - 1, -# endif - 1, ABSENT, 0 }, - { "oFFs", PNG_INFO_oFFs, png_oFFs, -# ifdef PNG_READ_oFFs_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "pCAL", PNG_INFO_pCAL, png_pCAL, -# ifdef PNG_READ_pCAL_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "pHYs", PNG_INFO_pHYs, png_pHYs, -# ifdef PNG_READ_pHYs_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "sBIT", PNG_INFO_sBIT, png_sBIT, -# ifdef PNG_READ_sBIT_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "sCAL", PNG_INFO_sCAL, png_sCAL, -# ifdef PNG_READ_sCAL_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "sPLT", PNG_INFO_sPLT, png_sPLT, -# ifdef PNG_READ_sPLT_SUPPORTED - 0, -# else - 1, -# endif - 1, ABSENT, 0 }, - { "sRGB", PNG_INFO_sRGB, png_sRGB, -# ifdef PNG_READ_sRGB_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "tEXt", PNG_INFO_tEXt, png_tEXt, -# ifdef PNG_READ_tEXt_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "tIME", PNG_INFO_tIME, png_tIME, -# ifdef PNG_READ_tIME_SUPPORTED - 0, -# else - 1, -# endif - 1, START, 0 }, - { "tRNS", PNG_INFO_tRNS, png_tRNS, -# ifdef PNG_READ_tRNS_SUPPORTED - 0, -# else - 1, -# endif - 0, ABSENT, 0 }, - { "zTXt", PNG_INFO_zTXt, png_zTXt, -# ifdef PNG_READ_zTXt_SUPPORTED - 0, -# else - 1, -# endif - 1, END, 0 }, - - /* No libpng handling */ - { "sTER", PNG_INFO_sTER, png_sTER, 1, 1, START, 0 }, - { "vpAg", PNG_INFO_vpAg, png_vpAg, 1, 0, START, 0 }, -}; - -#define NINFO ((int)((sizeof chunk_info)/(sizeof chunk_info[0]))) - -static void -clear_keep(void) -{ - int i = NINFO; - while (--i >= 0) - chunk_info[i].keep = 0; -} - -static int -find(const char *name) -{ - int i = NINFO; - while (--i >= 0) - { - if (memcmp(chunk_info[i].name, name, 4) == 0) - break; - } - - return i; -} - -static int -findb(const png_byte *name) -{ - int i = NINFO; - while (--i >= 0) - { - if (memcmp(chunk_info[i].name, name, 4) == 0) - break; - } - - return i; -} - -static int -find_by_flag(png_uint_32 flag) -{ - int i = NINFO; - - while (--i >= 0) if (chunk_info[i].flag == flag) return i; - - fprintf(stderr, "pngunknown: internal error\n"); - exit(4); -} - -static int -ancillary(const char *name) -{ - return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3])); -} - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -static int -ancillaryb(const png_byte *name) -{ - return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3])); -} -#endif - -/* Type of an error_ptr */ -typedef struct -{ - jmp_buf error_return; - png_structp png_ptr; - png_infop info_ptr, end_ptr; - png_uint_32 before_IDAT; - png_uint_32 after_IDAT; - int error_count; - int warning_count; - int keep; /* the default value */ - const char *program; - const char *file; - const char *test; -} display; - -static const char init[] = "initialization"; -static const char cmd[] = "command line"; - -static void -init_display(display *d, const char *program) -{ - memset(d, 0, sizeof *d); - d->png_ptr = NULL; - d->info_ptr = d->end_ptr = NULL; - d->error_count = d->warning_count = 0; - d->program = program; - d->file = program; - d->test = init; -} - -static void -clean_display(display *d) -{ - png_destroy_read_struct(&d->png_ptr, &d->info_ptr, &d->end_ptr); - - /* This must not happen - it might cause an app crash */ - if (d->png_ptr != NULL || d->info_ptr != NULL || d->end_ptr != NULL) - { - fprintf(stderr, "%s(%s): png_destroy_read_struct error\n", d->file, - d->test); - exit(1); - } -} - -PNG_FUNCTION(void, display_exit, (display *d), static PNG_NORETURN) -{ - ++(d->error_count); - - if (d->png_ptr != NULL) - clean_display(d); - - /* During initialization and if this is a single command line argument set - * exit now - there is only one test, otherwise longjmp to do the next test. - */ - if (d->test == init || d->test == cmd) - exit(1); - - longjmp(d->error_return, 1); -} - -static int -display_rc(const display *d, int strict) -{ - return d->error_count + (strict ? d->warning_count : 0); -} - -/* libpng error and warning callbacks */ -PNG_FUNCTION(void, (PNGCBAPI error), (png_structp png_ptr, const char *message), - static PNG_NORETURN) -{ - display *d = (display*)png_get_error_ptr(png_ptr); - - fprintf(stderr, "%s(%s): libpng error: %s\n", d->file, d->test, message); - display_exit(d); -} - -static void PNGCBAPI -warning(png_structp png_ptr, const char *message) -{ - display *d = (display*)png_get_error_ptr(png_ptr); - - fprintf(stderr, "%s(%s): libpng warning: %s\n", d->file, d->test, message); - ++(d->warning_count); -} - -static png_uint_32 -get_valid(display *d, png_infop info_ptr) -{ - png_uint_32 flags = png_get_valid(d->png_ptr, info_ptr, (png_uint_32)~0); - - /* Map the text chunks back into the flags */ - { - png_textp text; - png_uint_32 ntext = png_get_text(d->png_ptr, info_ptr, &text, NULL); - - while (ntext-- > 0) switch (text[ntext].compression) - { - case -1: - flags |= PNG_INFO_tEXt; - break; - case 0: - flags |= PNG_INFO_zTXt; - break; - case 1: - case 2: - flags |= PNG_INFO_iTXt; - break; - default: - fprintf(stderr, "%s(%s): unknown text compression %d\n", d->file, - d->test, text[ntext].compression); - display_exit(d); - } - } - - return flags; -} - -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED -static int PNGCBAPI -read_callback(png_structp pp, png_unknown_chunkp pc) -{ - /* This function mimics the behavior of png_set_keep_unknown_chunks by - * returning '0' to keep the chunk and '1' to discard it. - */ - display *d = voidcast(display*, png_get_user_chunk_ptr(pp)); - int chunk = findb(pc->name); - int keep, discard; - - if (chunk < 0) /* not one in our list, so not a known chunk */ - keep = d->keep; - - else - { - keep = chunk_info[chunk].keep; - if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - { - /* See the comments in png.h - use the default for unknown chunks, - * do not keep known chunks. - */ - if (chunk_info[chunk].unknown) - keep = d->keep; - - else - keep = PNG_HANDLE_CHUNK_NEVER; - } - } - - switch (keep) - { - default: - fprintf(stderr, "%s(%s): %d: unrecognized chunk option\n", d->file, - d->test, chunk_info[chunk].keep); - display_exit(d); - - case PNG_HANDLE_CHUNK_AS_DEFAULT: - case PNG_HANDLE_CHUNK_NEVER: - discard = 1/*handled; discard*/; - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - case PNG_HANDLE_CHUNK_ALWAYS: - discard = 0/*not handled; keep*/; - break; - } - - /* Also store information about this chunk in the display, the relevant flag - * is set if the chunk is to be kept ('not handled'.) - */ - if (chunk >= 0) if (!discard) /* stupidity to stop a GCC warning */ - { - png_uint_32 flag = chunk_info[chunk].flag; - - if (pc->location & PNG_AFTER_IDAT) - d->after_IDAT |= flag; - - else - d->before_IDAT |= flag; - } - - /* However if there is no support to store unknown chunks don't ask libpng to - * do it; there will be an png_error. - */ -# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - return discard; -# else - return 1; /*handled; discard*/ -# endif -} -#endif /* READ_USER_CHUNKS_SUPPORTED */ - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -static png_uint_32 -get_unknown(display *d, png_infop info_ptr, int after_IDAT) -{ - /* Create corresponding 'unknown' flags */ - png_uint_32 flags = 0; - - UNUSED(after_IDAT) - - { - png_unknown_chunkp unknown; - int num_unknown = png_get_unknown_chunks(d->png_ptr, info_ptr, &unknown); - - while (--num_unknown >= 0) - { - int chunk = findb(unknown[num_unknown].name); - - /* Chunks not known to pngunknown must be validated here; since they - * must also be unknown to libpng the 'display->keep' behavior should - * have been used. - */ - if (chunk < 0) switch (d->keep) - { - default: /* impossible */ - case PNG_HANDLE_CHUNK_AS_DEFAULT: - case PNG_HANDLE_CHUNK_NEVER: - fprintf(stderr, "%s(%s): %s: %s: unknown chunk saved\n", - d->file, d->test, d->keep ? "discard" : "default", - unknown[num_unknown].name); - ++(d->error_count); - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - if (!ancillaryb(unknown[num_unknown].name)) - { - fprintf(stderr, - "%s(%s): if-safe: %s: unknown critical chunk saved\n", - d->file, d->test, unknown[num_unknown].name); - ++(d->error_count); - break; - } - /* FALL THROUGH (safe) */ - case PNG_HANDLE_CHUNK_ALWAYS: - break; - } - - else - flags |= chunk_info[chunk].flag; - } - } - - return flags; -} -#else -static png_uint_32 -get_unknown(display *d, png_infop info_ptr, int after_IDAT) - /* Otherwise this will return the cached values set by any user callback */ -{ - UNUSED(info_ptr); - - if (after_IDAT) - return d->after_IDAT; - - else - return d->before_IDAT; -} - -# ifndef PNG_READ_USER_CHUNKS_SUPPORTED - /* The #defines above should mean this is never reached, it's just here as - * a check to ensure the logic is correct. - */ -# error No store support and no user chunk support, this will not work -# endif -#endif - -static int -check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, - display *d, int set_callback) -{ - int i, npasses, ipass; - png_uint_32 height; - - d->keep = PNG_HANDLE_CHUNK_AS_DEFAULT; - d->before_IDAT = 0; - d->after_IDAT = 0; - - /* Some of these errors are permanently fatal and cause an exit here, others - * are per-test and cause an error return. - */ - d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, d, error, - warning); - if (d->png_ptr == NULL) - { - fprintf(stderr, "%s(%s): could not allocate png struct\n", d->file, - d->test); - /* Terminate here, this error is not test specific. */ - exit(1); - } - - d->info_ptr = png_create_info_struct(d->png_ptr); - d->end_ptr = png_create_info_struct(d->png_ptr); - if (d->info_ptr == NULL || d->end_ptr == NULL) - { - fprintf(stderr, "%s(%s): could not allocate png info\n", d->file, - d->test); - clean_display(d); - exit(1); - } - - png_init_io(d->png_ptr, fp); - -# ifdef PNG_READ_USER_CHUNKS_SUPPORTED - /* This is only done if requested by the caller; it interferes with the - * standard store/save mechanism. - */ - if (set_callback) - png_set_read_user_chunk_fn(d->png_ptr, d, read_callback); -# else - UNUSED(set_callback) -# endif - - /* Handle each argument in turn; multiple settings are possible for the same - * chunk and multiple calls will occur (the last one should override all - * preceding ones). - */ - for (i=0; ipng_ptr, option, name, 1); - chunk_info[chunk].keep = option; - continue; - } - - break; - - case 7: /* default */ - if (memcmp(argv[i], "default", 7) == 0) - { - png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0); - d->keep = option; - continue; - } - - break; - - case 3: /* all */ - if (memcmp(argv[i], "all", 3) == 0) - { - png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1); - d->keep = option; - - for (chunk = 0; chunk < NINFO; ++chunk) - if (chunk_info[chunk].all) - chunk_info[chunk].keep = option; - continue; - } - - break; - - default: /* some misplaced = */ - - break; - } - } - - fprintf(stderr, "%s(%s): %s: unrecognized chunk argument\n", d->file, - d->test, argv[i]); - display_exit(d); - } - - png_read_info(d->png_ptr, d->info_ptr); - - switch (png_get_interlace_type(d->png_ptr, d->info_ptr)) - { - case PNG_INTERLACE_NONE: - npasses = 1; - break; - - case PNG_INTERLACE_ADAM7: - npasses = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - /* Hard error because it is not test specific */ - fprintf(stderr, "%s(%s): invalid interlace type\n", d->file, d->test); - clean_display(d); - exit(1); - } - - /* Skip the image data, if IDAT is not being handled then don't do this - * because it will cause a CRC error. - */ - if (chunk_info[0/*IDAT*/].keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - { - png_start_read_image(d->png_ptr); - height = png_get_image_height(d->png_ptr, d->info_ptr); - - if (npasses > 1) - { - png_uint_32 width = png_get_image_width(d->png_ptr, d->info_ptr); - - for (ipass=0; ipass 0) - { - png_uint_32 y; - - for (y=0; ypng_ptr, NULL, NULL); - } - } - } /* interlaced */ - - else /* not interlaced */ - { - png_uint_32 y; - - for (y=0; ypng_ptr, NULL, NULL); - } - } - - png_read_end(d->png_ptr, d->end_ptr); - - flags[0] = get_valid(d, d->info_ptr); - flags[1] = get_unknown(d, d->info_ptr, 0/*before IDAT*/); - - /* Only png_read_png sets PNG_INFO_IDAT! */ - flags[chunk_info[0/*IDAT*/].keep != PNG_HANDLE_CHUNK_AS_DEFAULT] |= - PNG_INFO_IDAT; - - flags[2] = get_valid(d, d->end_ptr); - flags[3] = get_unknown(d, d->end_ptr, 1/*after IDAT*/); - - clean_display(d); - - return d->keep; -} - -static void -check_error(display *d, png_uint_32 flags, const char *message) -{ - while (flags) - { - png_uint_32 flag = flags & -(png_int_32)flags; - int i = find_by_flag(flag); - - fprintf(stderr, "%s(%s): chunk %s: %s\n", d->file, d->test, - chunk_info[i].name, message); - ++(d->error_count); - - flags &= ~flag; - } -} - -static void -check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known, - png_uint_32 unknown, const char *position, int set_callback) -{ - while (chunks) - { - png_uint_32 flag = chunks & -(png_int_32)chunks; - int i = find_by_flag(flag); - int keep = chunk_info[i].keep; - const char *type; - const char *errorx = NULL; - - if (chunk_info[i].unknown) - { - if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - { - type = "UNKNOWN (default)"; - keep = def; - } - - else - type = "UNKNOWN (specified)"; - - if (flag & known) - errorx = "chunk processed"; - - else switch (keep) - { - case PNG_HANDLE_CHUNK_AS_DEFAULT: - if (flag & unknown) - errorx = "DEFAULT: unknown chunk saved"; - break; - - case PNG_HANDLE_CHUNK_NEVER: - if (flag & unknown) - errorx = "DISCARD: unknown chunk saved"; - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - if (ancillary(chunk_info[i].name)) - { - if (!(flag & unknown)) - errorx = "IF-SAFE: unknown ancillary chunk lost"; - } - - else if (flag & unknown) - errorx = "IF-SAFE: unknown critical chunk saved"; - break; - - case PNG_HANDLE_CHUNK_ALWAYS: - if (!(flag & unknown)) - errorx = "SAVE: unknown chunk lost"; - break; - - default: - errorx = "internal error: bad keep"; - break; - } - } /* unknown chunk */ - - else /* known chunk */ - { - type = "KNOWN"; - - if (flag & known) - { - /* chunk was processed, it won't have been saved because that is - * caught below when checking for inconsistent processing. - */ - if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT) - errorx = "!DEFAULT: known chunk processed"; - } - - else /* not processed */ switch (keep) - { - case PNG_HANDLE_CHUNK_AS_DEFAULT: - errorx = "DEFAULT: known chunk not processed"; - break; - - case PNG_HANDLE_CHUNK_NEVER: - if (flag & unknown) - errorx = "DISCARD: known chunk saved"; - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - if (ancillary(chunk_info[i].name)) - { - if (!(flag & unknown)) - errorx = "IF-SAFE: known ancillary chunk lost"; - } - - else if (flag & unknown) - errorx = "IF-SAFE: known critical chunk saved"; - break; - - case PNG_HANDLE_CHUNK_ALWAYS: - if (!(flag & unknown)) - errorx = "SAVE: known chunk lost"; - break; - - default: - errorx = "internal error: bad keep (2)"; - break; - } - } - - if (errorx != NULL) - { - ++(d->error_count); - fprintf(stderr, "%s(%s%s): %s %s %s: %s\n", d->file, d->test, - set_callback ? ",callback" : "", - type, chunk_info[i].name, position, errorx); - } - - chunks &= ~flag; - } -} - -static void -perform_one_test(FILE *fp, int argc, const char **argv, - png_uint_32 *default_flags, display *d, int set_callback) -{ - int def; - png_uint_32 flags[2][4]; - - rewind(fp); - clear_keep(); - memcpy(flags[0], default_flags, sizeof flags[0]); - - def = check(fp, argc, argv, flags[1], d, set_callback); - - /* Chunks should either be known or unknown, never both and this should apply - * whether the chunk is before or after the IDAT (actually, the app can - * probably change this by swapping the handling after the image, but this - * test does not do that.) - */ - check_error(d, (flags[0][0]|flags[0][2]) & (flags[0][1]|flags[0][3]), - "chunk handled inconsistently in count tests"); - check_error(d, (flags[1][0]|flags[1][2]) & (flags[1][1]|flags[1][3]), - "chunk handled inconsistently in option tests"); - - /* Now find out what happened to each chunk before and after the IDAT and - * determine if the behavior was correct. First some basic sanity checks, - * any known chunk should be known in the original count, any unknown chunk - * should be either known or unknown in the original. - */ - { - png_uint_32 test; - - test = flags[1][0] & ~flags[0][0]; - check_error(d, test, "new known chunk before IDAT"); - test = flags[1][1] & ~(flags[0][0] | flags[0][1]); - check_error(d, test, "new unknown chunk before IDAT"); - test = flags[1][2] & ~flags[0][2]; - check_error(d, test, "new known chunk after IDAT"); - test = flags[1][3] & ~(flags[0][2] | flags[0][3]); - check_error(d, test, "new unknown chunk after IDAT"); - } - - /* Now each chunk in the original list should have been handled according to - * the options set for that chunk, regardless of whether libpng knows about - * it or not. - */ - check_handling(d, def, flags[0][0] | flags[0][1], flags[1][0], flags[1][1], - "before IDAT", set_callback); - check_handling(d, def, flags[0][2] | flags[0][3], flags[1][2], flags[1][3], - "after IDAT", set_callback); -} - -static void -perform_one_test_safe(FILE *fp, int argc, const char **argv, - png_uint_32 *default_flags, display *d, const char *test) -{ - if (setjmp(d->error_return) == 0) - { - d->test = test; /* allow use of d->error_return */ -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - perform_one_test(fp, argc, argv, default_flags, d, 0); -# endif -# ifdef PNG_READ_USER_CHUNKS_SUPPORTED - perform_one_test(fp, argc, argv, default_flags, d, 1); -# endif - d->test = init; /* prevent use of d->error_return */ - } -} - -static const char *standard_tests[] = -{ - "discard", "default=discard", 0, - "save", "default=save", 0, - "if-safe", "default=if-safe", 0, - "vpAg", "vpAg=if-safe", 0, - "sTER", "sTER=if-safe", 0, - "IDAT", "default=discard", "IDAT=save", 0, - "sAPI", "bKGD=save", "cHRM=save", "gAMA=save", "all=discard", "iCCP=save", - "sBIT=save", "sRGB=save", 0, - 0/*end*/ -}; - -static PNG_NORETURN void -usage(const char *program, const char *reason) -{ - fprintf(stderr, "pngunknown: %s: usage:\n %s [--strict] " - "--default|{(CHNK|default|all)=(default|discard|if-safe|save)} " - "testfile.png\n", reason, program); - exit(99); -} - -int -main(int argc, const char **argv) -{ - FILE *fp; - png_uint_32 default_flags[4/*valid,unknown{before,after}*/]; - int strict = 0, default_tests = 0; - const char *count_argv = "default=save"; - const char *touch_file = NULL; - display d; - - init_display(&d, argv[0]); - - while (++argv, --argc > 0) - { - if (strcmp(*argv, "--strict") == 0) - strict = 1; - - else if (strcmp(*argv, "--default") == 0) - default_tests = 1; - - else if (strcmp(*argv, "--touch") == 0) - { - if (argc > 1) - touch_file = *++argv, --argc; - - else - usage(d.program, "--touch: missing file name"); - } - - else - break; - } - - /* A file name is required, but there should be no other arguments if - * --default was specified. - */ - if (argc <= 0) - usage(d.program, "missing test file"); - - /* GCC BUG: if (default_tests && argc != 1) triggers some weird GCC argc - * optimization which causes warnings with -Wstrict-overflow! - */ - else if (default_tests) if (argc != 1) - usage(d.program, "extra arguments"); - - /* The name of the test file is the last argument; remove it. */ - d.file = argv[--argc]; - - fp = fopen(d.file, "rb"); - if (fp == NULL) - { - perror(d.file); - exit(99); - } - - /* First find all the chunks, known and unknown, in the test file, a failure - * here aborts the whole test. - * - * If 'save' is supported then the normal saving method should happen, - * otherwise if 'read' is supported then the read callback will do the - * same thing. If both are supported the 'read' callback won't be - * instantiated by default. If 'save' is *not* supported then a user - * callback is required even though we can call png_get_unknown_chunks. - */ - if (check(fp, 1, &count_argv, default_flags, &d, -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - 0 -# else - 1 -# endif - ) != PNG_HANDLE_CHUNK_ALWAYS) - { - fprintf(stderr, "%s: %s: internal error\n", d.program, d.file); - exit(99); - } - - /* Now find what the various supplied options cause to change: */ - if (!default_tests) - { - d.test = cmd; /* acts as a flag to say exit, do not longjmp */ -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - perform_one_test(fp, argc, argv, default_flags, &d, 0); -# endif -# ifdef PNG_READ_USER_CHUNKS_SUPPORTED - perform_one_test(fp, argc, argv, default_flags, &d, 1); -# endif - d.test = init; - } - - else - { - const char **test = standard_tests; - - /* Set the exit_test pointer here so we can continue after a libpng error. - * NOTE: this leaks memory because the png_struct data from the failing - * test is never freed. - */ - while (*test) - { - const char *this_test = *test++; - const char **next = test; - int count = display_rc(&d, strict), new_count; - const char *result; - int arg_count = 0; - - while (*next) ++next, ++arg_count; - - perform_one_test_safe(fp, arg_count, test, default_flags, &d, - this_test); - - new_count = display_rc(&d, strict); - - if (new_count == count) - result = "PASS"; - - else - result = "FAIL"; - - printf("%s: %s %s\n", result, d.program, this_test); - - test = next+1; - } - } - - fclose(fp); - - if (display_rc(&d, strict) == 0) - { - /* Success, touch the success file if appropriate */ - if (touch_file != NULL) - { - FILE *fsuccess = fopen(touch_file, "wt"); - - if (fsuccess != NULL) - { - int err = 0; - fprintf(fsuccess, "PNG unknown tests succeeded\n"); - fflush(fsuccess); - err = ferror(fsuccess); - - if (fclose(fsuccess) || err) - { - fprintf(stderr, "%s: write failed\n", touch_file); - exit(99); - } - } - - else - { - fprintf(stderr, "%s: open failed\n", touch_file); - exit(99); - } - } - - return 0; - } - - return 1; -} - -#else /* !(READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS) */ -int -main(void) -{ - fprintf(stderr, - " test ignored: no support to find out about unknown chunks\n"); - /* So the test is skipped: */ - return 77; -} -#endif /* READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS */ - -#else /* !(SET_UNKNOWN_CHUNKS && READ) */ -int -main(void) -{ - fprintf(stderr, - " test ignored: no support to modify unknown chunk handling\n"); - /* So the test is skipped: */ - return 77; -} -#endif /* SET_UNKNOWN_CHUNKS && READ*/ + +/* pngunknown.c - test the read side unknown chunk handling + * + * Last changed in libpng 1.6.10 [March 6, 2014] + * Copyright (c) 2014 Glenn Randers-Pehrson + * Written by John Cunningham Bowler + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * NOTES: + * This is a C program that is intended to be linked against libpng. It + * allows the libpng unknown handling code to be tested by interpreting + * arguments to save or discard combinations of chunks. The program is + * currently just a minimal validation for the built-in libpng facilities. + */ + +#include +#include +#include +#include + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +/* Since this program tests the ability to change the unknown chunk handling + * these must be defined: + */ +#if defined(PNG_SET_UNKNOWN_CHUNKS_SUPPORTED) &&\ + defined(PNG_READ_SUPPORTED) + +/* One of these must be defined to allow us to find out what happened. It is + * still useful to set unknown chunk handling without either of these in order + * to cause *known* chunks to be discarded. This can be a significant + * efficiency gain, but it can't really be tested here. + */ +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) ||\ + defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED) + +#if PNG_LIBPNG_VER < 10500 +/* This deliberately lacks the PNG_CONST. */ +typedef png_byte *png_const_bytep; + +/* This is copied from 1.5.1 png.h: */ +#define PNG_INTERLACE_ADAM7_PASSES 7 +#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) +#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ + (((yIn)<>(((7-(off))-(pass))<<2)) & 0xFU) | \ + ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +/* These are needed too for the default build: */ +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED + +/* This comes from pnglibconf.h afer 1.5: */ +#define PNG_FP_1 100000 +#define PNG_GAMMA_THRESHOLD_FIXED\ + ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) +#endif + +#if PNG_LIBPNG_VER < 10600 + /* 1.6.0 constifies many APIs. The following exists to allow pngvalid to be + * compiled against earlier versions. + */ +# define png_const_structp png_structp +#endif + +#if PNG_LIBPNG_VER < 10700 + /* Copied from libpng 1.7.0 png.h */ +#define PNG_u2(b1, b2) (((unsigned int)(b1) << 8) + (b2)) + +#define PNG_U16(b1, b2) ((png_uint_16)PNG_u2(b1, b2)) +#define PNG_U32(b1, b2, b3, b4)\ + (((png_uint_32)PNG_u2(b1, b2) << 16) + PNG_u2(b3, b4)) + +/* Constants for known chunk types. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +#endif /* PNG_LIBPNG_VER < 10700 */ + +#ifdef __cplusplus +# define this not_the_cpp_this +# define new not_the_cpp_new +# define voidcast(type, value) static_cast(value) +#else +# define voidcast(type, value) (value) +#endif /* __cplusplus */ + +/* Unused formal parameter errors are removed using the following macro which is + * expected to have no bad effects on performance. + */ +#ifndef UNUSED +# if defined(__GNUC__) || defined(_MSC_VER) +# define UNUSED(param) (void)param; +# else +# define UNUSED(param) +# endif +#endif + +/* Types of chunks not known to libpng */ +#define png_vpAg PNG_U32(118, 112, 65, 103) + +/* Chunk information */ +#define PNG_INFO_tEXt 0x10000000U +#define PNG_INFO_iTXt 0x20000000U +#define PNG_INFO_zTXt 0x40000000U + +#define PNG_INFO_sTER 0x01000000U +#define PNG_INFO_vpAg 0x02000000U + +#define ABSENT 0 +#define START 1 +#define END 2 + +static struct +{ + char name[5]; + png_uint_32 flag; + png_uint_32 tag; + int unknown; /* Chunk not known to libpng */ + int all; /* Chunk set by the '-1' option */ + int position; /* position in pngtest.png */ + int keep; /* unknown handling setting */ +} chunk_info[] = { + /* Critical chunks */ + { "IDAT", PNG_INFO_IDAT, png_IDAT, 0, 0, START, 0 }, /* must be [0] */ + { "PLTE", PNG_INFO_PLTE, png_PLTE, 0, 0, ABSENT, 0 }, + + /* Non-critical chunks that libpng handles */ + /* This is a mess but it seems to be the only way to do it - there is no way + * to check for a definition outside a #if. + */ + { "bKGD", PNG_INFO_bKGD, png_bKGD, +# ifdef PNG_READ_bKGD_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "cHRM", PNG_INFO_cHRM, png_cHRM, +# ifdef PNG_READ_cHRM_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "gAMA", PNG_INFO_gAMA, png_gAMA, +# ifdef PNG_READ_gAMA_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "hIST", PNG_INFO_hIST, png_hIST, +# ifdef PNG_READ_hIST_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "iCCP", PNG_INFO_iCCP, png_iCCP, +# ifdef PNG_READ_iCCP_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "iTXt", PNG_INFO_iTXt, png_iTXt, +# ifdef PNG_READ_iTXt_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "oFFs", PNG_INFO_oFFs, png_oFFs, +# ifdef PNG_READ_oFFs_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "pCAL", PNG_INFO_pCAL, png_pCAL, +# ifdef PNG_READ_pCAL_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "pHYs", PNG_INFO_pHYs, png_pHYs, +# ifdef PNG_READ_pHYs_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "sBIT", PNG_INFO_sBIT, png_sBIT, +# ifdef PNG_READ_sBIT_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "sCAL", PNG_INFO_sCAL, png_sCAL, +# ifdef PNG_READ_sCAL_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "sPLT", PNG_INFO_sPLT, png_sPLT, +# ifdef PNG_READ_sPLT_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "sRGB", PNG_INFO_sRGB, png_sRGB, +# ifdef PNG_READ_sRGB_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "tEXt", PNG_INFO_tEXt, png_tEXt, +# ifdef PNG_READ_tEXt_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "tIME", PNG_INFO_tIME, png_tIME, +# ifdef PNG_READ_tIME_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "tRNS", PNG_INFO_tRNS, png_tRNS, +# ifdef PNG_READ_tRNS_SUPPORTED + 0, +# else + 1, +# endif + 0, ABSENT, 0 }, + { "zTXt", PNG_INFO_zTXt, png_zTXt, +# ifdef PNG_READ_zTXt_SUPPORTED + 0, +# else + 1, +# endif + 1, END, 0 }, + + /* No libpng handling */ + { "sTER", PNG_INFO_sTER, png_sTER, 1, 1, START, 0 }, + { "vpAg", PNG_INFO_vpAg, png_vpAg, 1, 0, START, 0 }, +}; + +#define NINFO ((int)((sizeof chunk_info)/(sizeof chunk_info[0]))) + +static void +clear_keep(void) +{ + int i = NINFO; + while (--i >= 0) + chunk_info[i].keep = 0; +} + +static int +find(const char *name) +{ + int i = NINFO; + while (--i >= 0) + { + if (memcmp(chunk_info[i].name, name, 4) == 0) + break; + } + + return i; +} + +static int +findb(const png_byte *name) +{ + int i = NINFO; + while (--i >= 0) + { + if (memcmp(chunk_info[i].name, name, 4) == 0) + break; + } + + return i; +} + +static int +find_by_flag(png_uint_32 flag) +{ + int i = NINFO; + + while (--i >= 0) if (chunk_info[i].flag == flag) return i; + + fprintf(stderr, "pngunknown: internal error\n"); + exit(4); +} + +static int +ancillary(const char *name) +{ + return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3])); +} + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static int +ancillaryb(const png_byte *name) +{ + return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3])); +} +#endif + +/* Type of an error_ptr */ +typedef struct +{ + jmp_buf error_return; + png_structp png_ptr; + png_infop info_ptr, end_ptr; + png_uint_32 before_IDAT; + png_uint_32 after_IDAT; + int error_count; + int warning_count; + int keep; /* the default value */ + const char *program; + const char *file; + const char *test; +} display; + +static const char init[] = "initialization"; +static const char cmd[] = "command line"; + +static void +init_display(display *d, const char *program) +{ + memset(d, 0, sizeof *d); + d->png_ptr = NULL; + d->info_ptr = d->end_ptr = NULL; + d->error_count = d->warning_count = 0; + d->program = program; + d->file = program; + d->test = init; +} + +static void +clean_display(display *d) +{ + png_destroy_read_struct(&d->png_ptr, &d->info_ptr, &d->end_ptr); + + /* This must not happen - it might cause an app crash */ + if (d->png_ptr != NULL || d->info_ptr != NULL || d->end_ptr != NULL) + { + fprintf(stderr, "%s(%s): png_destroy_read_struct error\n", d->file, + d->test); + exit(1); + } +} + +PNG_FUNCTION(void, display_exit, (display *d), static PNG_NORETURN) +{ + ++(d->error_count); + + if (d->png_ptr != NULL) + clean_display(d); + + /* During initialization and if this is a single command line argument set + * exit now - there is only one test, otherwise longjmp to do the next test. + */ + if (d->test == init || d->test == cmd) + exit(1); + + longjmp(d->error_return, 1); +} + +static int +display_rc(const display *d, int strict) +{ + return d->error_count + (strict ? d->warning_count : 0); +} + +/* libpng error and warning callbacks */ +PNG_FUNCTION(void, (PNGCBAPI error), (png_structp png_ptr, const char *message), + static PNG_NORETURN) +{ + display *d = (display*)png_get_error_ptr(png_ptr); + + fprintf(stderr, "%s(%s): libpng error: %s\n", d->file, d->test, message); + display_exit(d); +} + +static void PNGCBAPI +warning(png_structp png_ptr, const char *message) +{ + display *d = (display*)png_get_error_ptr(png_ptr); + + fprintf(stderr, "%s(%s): libpng warning: %s\n", d->file, d->test, message); + ++(d->warning_count); +} + +static png_uint_32 +get_valid(display *d, png_infop info_ptr) +{ + png_uint_32 flags = png_get_valid(d->png_ptr, info_ptr, (png_uint_32)~0); + + /* Map the text chunks back into the flags */ + { + png_textp text; + png_uint_32 ntext = png_get_text(d->png_ptr, info_ptr, &text, NULL); + + while (ntext-- > 0) switch (text[ntext].compression) + { + case -1: + flags |= PNG_INFO_tEXt; + break; + case 0: + flags |= PNG_INFO_zTXt; + break; + case 1: + case 2: + flags |= PNG_INFO_iTXt; + break; + default: + fprintf(stderr, "%s(%s): unknown text compression %d\n", d->file, + d->test, text[ntext].compression); + display_exit(d); + } + } + + return flags; +} + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +static int PNGCBAPI +read_callback(png_structp pp, png_unknown_chunkp pc) +{ + /* This function mimics the behavior of png_set_keep_unknown_chunks by + * returning '0' to keep the chunk and '1' to discard it. + */ + display *d = voidcast(display*, png_get_user_chunk_ptr(pp)); + int chunk = findb(pc->name); + int keep, discard; + + if (chunk < 0) /* not one in our list, so not a known chunk */ + keep = d->keep; + + else + { + keep = chunk_info[chunk].keep; + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + { + /* See the comments in png.h - use the default for unknown chunks, + * do not keep known chunks. + */ + if (chunk_info[chunk].unknown) + keep = d->keep; + + else + keep = PNG_HANDLE_CHUNK_NEVER; + } + } + + switch (keep) + { + default: + fprintf(stderr, "%s(%s): %d: unrecognized chunk option\n", d->file, + d->test, chunk_info[chunk].keep); + display_exit(d); + + case PNG_HANDLE_CHUNK_AS_DEFAULT: + case PNG_HANDLE_CHUNK_NEVER: + discard = 1/*handled; discard*/; + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + case PNG_HANDLE_CHUNK_ALWAYS: + discard = 0/*not handled; keep*/; + break; + } + + /* Also store information about this chunk in the display, the relevant flag + * is set if the chunk is to be kept ('not handled'.) + */ + if (chunk >= 0) if (!discard) /* stupidity to stop a GCC warning */ + { + png_uint_32 flag = chunk_info[chunk].flag; + + if (pc->location & PNG_AFTER_IDAT) + d->after_IDAT |= flag; + + else + d->before_IDAT |= flag; + } + + /* However if there is no support to store unknown chunks don't ask libpng to + * do it; there will be an png_error. + */ +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + return discard; +# else + return 1; /*handled; discard*/ +# endif +} +#endif /* READ_USER_CHUNKS_SUPPORTED */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_uint_32 +get_unknown(display *d, png_infop info_ptr, int after_IDAT) +{ + /* Create corresponding 'unknown' flags */ + png_uint_32 flags = 0; + + UNUSED(after_IDAT) + + { + png_unknown_chunkp unknown; + int num_unknown = png_get_unknown_chunks(d->png_ptr, info_ptr, &unknown); + + while (--num_unknown >= 0) + { + int chunk = findb(unknown[num_unknown].name); + + /* Chunks not known to pngunknown must be validated here; since they + * must also be unknown to libpng the 'display->keep' behavior should + * have been used. + */ + if (chunk < 0) switch (d->keep) + { + default: /* impossible */ + case PNG_HANDLE_CHUNK_AS_DEFAULT: + case PNG_HANDLE_CHUNK_NEVER: + fprintf(stderr, "%s(%s): %s: %s: unknown chunk saved\n", + d->file, d->test, d->keep ? "discard" : "default", + unknown[num_unknown].name); + ++(d->error_count); + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + if (!ancillaryb(unknown[num_unknown].name)) + { + fprintf(stderr, + "%s(%s): if-safe: %s: unknown critical chunk saved\n", + d->file, d->test, unknown[num_unknown].name); + ++(d->error_count); + break; + } + /* FALL THROUGH (safe) */ + case PNG_HANDLE_CHUNK_ALWAYS: + break; + } + + else + flags |= chunk_info[chunk].flag; + } + } + + return flags; +} +#else +static png_uint_32 +get_unknown(display *d, png_infop info_ptr, int after_IDAT) + /* Otherwise this will return the cached values set by any user callback */ +{ + UNUSED(info_ptr); + + if (after_IDAT) + return d->after_IDAT; + + else + return d->before_IDAT; +} + +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED + /* The #defines above should mean this is never reached, it's just here as + * a check to ensure the logic is correct. + */ +# error No store support and no user chunk support, this will not work +# endif +#endif + +static int +check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, + display *d, int set_callback) +{ + int i, npasses, ipass; + png_uint_32 height; + + d->keep = PNG_HANDLE_CHUNK_AS_DEFAULT; + d->before_IDAT = 0; + d->after_IDAT = 0; + + /* Some of these errors are permanently fatal and cause an exit here, others + * are per-test and cause an error return. + */ + d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, d, error, + warning); + if (d->png_ptr == NULL) + { + fprintf(stderr, "%s(%s): could not allocate png struct\n", d->file, + d->test); + /* Terminate here, this error is not test specific. */ + exit(1); + } + + d->info_ptr = png_create_info_struct(d->png_ptr); + d->end_ptr = png_create_info_struct(d->png_ptr); + if (d->info_ptr == NULL || d->end_ptr == NULL) + { + fprintf(stderr, "%s(%s): could not allocate png info\n", d->file, + d->test); + clean_display(d); + exit(1); + } + + png_init_io(d->png_ptr, fp); + +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* This is only done if requested by the caller; it interferes with the + * standard store/save mechanism. + */ + if (set_callback) + png_set_read_user_chunk_fn(d->png_ptr, d, read_callback); +# else + UNUSED(set_callback) +# endif + + /* Handle each argument in turn; multiple settings are possible for the same + * chunk and multiple calls will occur (the last one should override all + * preceding ones). + */ + for (i=0; ipng_ptr, option, name, 1); + chunk_info[chunk].keep = option; + continue; + } + + break; + + case 7: /* default */ + if (memcmp(argv[i], "default", 7) == 0) + { + png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0); + d->keep = option; + continue; + } + + break; + + case 3: /* all */ + if (memcmp(argv[i], "all", 3) == 0) + { + png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1); + d->keep = option; + + for (chunk = 0; chunk < NINFO; ++chunk) + if (chunk_info[chunk].all) + chunk_info[chunk].keep = option; + continue; + } + + break; + + default: /* some misplaced = */ + + break; + } + } + + fprintf(stderr, "%s(%s): %s: unrecognized chunk argument\n", d->file, + d->test, argv[i]); + display_exit(d); + } + + png_read_info(d->png_ptr, d->info_ptr); + + switch (png_get_interlace_type(d->png_ptr, d->info_ptr)) + { + case PNG_INTERLACE_NONE: + npasses = 1; + break; + + case PNG_INTERLACE_ADAM7: + npasses = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + /* Hard error because it is not test specific */ + fprintf(stderr, "%s(%s): invalid interlace type\n", d->file, d->test); + clean_display(d); + exit(1); + } + + /* Skip the image data, if IDAT is not being handled then don't do this + * because it will cause a CRC error. + */ + if (chunk_info[0/*IDAT*/].keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + { + png_start_read_image(d->png_ptr); + height = png_get_image_height(d->png_ptr, d->info_ptr); + + if (npasses > 1) + { + png_uint_32 width = png_get_image_width(d->png_ptr, d->info_ptr); + + for (ipass=0; ipass 0) + { + png_uint_32 y; + + for (y=0; ypng_ptr, NULL, NULL); + } + } + } /* interlaced */ + + else /* not interlaced */ + { + png_uint_32 y; + + for (y=0; ypng_ptr, NULL, NULL); + } + } + + png_read_end(d->png_ptr, d->end_ptr); + + flags[0] = get_valid(d, d->info_ptr); + flags[1] = get_unknown(d, d->info_ptr, 0/*before IDAT*/); + + /* Only png_read_png sets PNG_INFO_IDAT! */ + flags[chunk_info[0/*IDAT*/].keep != PNG_HANDLE_CHUNK_AS_DEFAULT] |= + PNG_INFO_IDAT; + + flags[2] = get_valid(d, d->end_ptr); + flags[3] = get_unknown(d, d->end_ptr, 1/*after IDAT*/); + + clean_display(d); + + return d->keep; +} + +static void +check_error(display *d, png_uint_32 flags, const char *message) +{ + while (flags) + { + png_uint_32 flag = flags & -(png_int_32)flags; + int i = find_by_flag(flag); + + fprintf(stderr, "%s(%s): chunk %s: %s\n", d->file, d->test, + chunk_info[i].name, message); + ++(d->error_count); + + flags &= ~flag; + } +} + +static void +check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known, + png_uint_32 unknown, const char *position, int set_callback) +{ + while (chunks) + { + png_uint_32 flag = chunks & -(png_int_32)chunks; + int i = find_by_flag(flag); + int keep = chunk_info[i].keep; + const char *type; + const char *errorx = NULL; + + if (chunk_info[i].unknown) + { + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + { + type = "UNKNOWN (default)"; + keep = def; + } + + else + type = "UNKNOWN (specified)"; + + if (flag & known) + errorx = "chunk processed"; + + else switch (keep) + { + case PNG_HANDLE_CHUNK_AS_DEFAULT: + if (flag & unknown) + errorx = "DEFAULT: unknown chunk saved"; + break; + + case PNG_HANDLE_CHUNK_NEVER: + if (flag & unknown) + errorx = "DISCARD: unknown chunk saved"; + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + if (ancillary(chunk_info[i].name)) + { + if (!(flag & unknown)) + errorx = "IF-SAFE: unknown ancillary chunk lost"; + } + + else if (flag & unknown) + errorx = "IF-SAFE: unknown critical chunk saved"; + break; + + case PNG_HANDLE_CHUNK_ALWAYS: + if (!(flag & unknown)) + errorx = "SAVE: unknown chunk lost"; + break; + + default: + errorx = "internal error: bad keep"; + break; + } + } /* unknown chunk */ + + else /* known chunk */ + { + type = "KNOWN"; + + if (flag & known) + { + /* chunk was processed, it won't have been saved because that is + * caught below when checking for inconsistent processing. + */ + if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT) + errorx = "!DEFAULT: known chunk processed"; + } + + else /* not processed */ switch (keep) + { + case PNG_HANDLE_CHUNK_AS_DEFAULT: + errorx = "DEFAULT: known chunk not processed"; + break; + + case PNG_HANDLE_CHUNK_NEVER: + if (flag & unknown) + errorx = "DISCARD: known chunk saved"; + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + if (ancillary(chunk_info[i].name)) + { + if (!(flag & unknown)) + errorx = "IF-SAFE: known ancillary chunk lost"; + } + + else if (flag & unknown) + errorx = "IF-SAFE: known critical chunk saved"; + break; + + case PNG_HANDLE_CHUNK_ALWAYS: + if (!(flag & unknown)) + errorx = "SAVE: known chunk lost"; + break; + + default: + errorx = "internal error: bad keep (2)"; + break; + } + } + + if (errorx != NULL) + { + ++(d->error_count); + fprintf(stderr, "%s(%s%s): %s %s %s: %s\n", d->file, d->test, + set_callback ? ",callback" : "", + type, chunk_info[i].name, position, errorx); + } + + chunks &= ~flag; + } +} + +static void +perform_one_test(FILE *fp, int argc, const char **argv, + png_uint_32 *default_flags, display *d, int set_callback) +{ + int def; + png_uint_32 flags[2][4]; + + rewind(fp); + clear_keep(); + memcpy(flags[0], default_flags, sizeof flags[0]); + + def = check(fp, argc, argv, flags[1], d, set_callback); + + /* Chunks should either be known or unknown, never both and this should apply + * whether the chunk is before or after the IDAT (actually, the app can + * probably change this by swapping the handling after the image, but this + * test does not do that.) + */ + check_error(d, (flags[0][0]|flags[0][2]) & (flags[0][1]|flags[0][3]), + "chunk handled inconsistently in count tests"); + check_error(d, (flags[1][0]|flags[1][2]) & (flags[1][1]|flags[1][3]), + "chunk handled inconsistently in option tests"); + + /* Now find out what happened to each chunk before and after the IDAT and + * determine if the behavior was correct. First some basic sanity checks, + * any known chunk should be known in the original count, any unknown chunk + * should be either known or unknown in the original. + */ + { + png_uint_32 test; + + test = flags[1][0] & ~flags[0][0]; + check_error(d, test, "new known chunk before IDAT"); + test = flags[1][1] & ~(flags[0][0] | flags[0][1]); + check_error(d, test, "new unknown chunk before IDAT"); + test = flags[1][2] & ~flags[0][2]; + check_error(d, test, "new known chunk after IDAT"); + test = flags[1][3] & ~(flags[0][2] | flags[0][3]); + check_error(d, test, "new unknown chunk after IDAT"); + } + + /* Now each chunk in the original list should have been handled according to + * the options set for that chunk, regardless of whether libpng knows about + * it or not. + */ + check_handling(d, def, flags[0][0] | flags[0][1], flags[1][0], flags[1][1], + "before IDAT", set_callback); + check_handling(d, def, flags[0][2] | flags[0][3], flags[1][2], flags[1][3], + "after IDAT", set_callback); +} + +static void +perform_one_test_safe(FILE *fp, int argc, const char **argv, + png_uint_32 *default_flags, display *d, const char *test) +{ + if (setjmp(d->error_return) == 0) + { + d->test = test; /* allow use of d->error_return */ +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + perform_one_test(fp, argc, argv, default_flags, d, 0); +# endif +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + perform_one_test(fp, argc, argv, default_flags, d, 1); +# endif + d->test = init; /* prevent use of d->error_return */ + } +} + +static const char *standard_tests[] = +{ + "discard", "default=discard", 0, + "save", "default=save", 0, + "if-safe", "default=if-safe", 0, + "vpAg", "vpAg=if-safe", 0, + "sTER", "sTER=if-safe", 0, + "IDAT", "default=discard", "IDAT=save", 0, + "sAPI", "bKGD=save", "cHRM=save", "gAMA=save", "all=discard", "iCCP=save", + "sBIT=save", "sRGB=save", 0, + 0/*end*/ +}; + +static PNG_NORETURN void +usage(const char *program, const char *reason) +{ + fprintf(stderr, "pngunknown: %s: usage:\n %s [--strict] " + "--default|{(CHNK|default|all)=(default|discard|if-safe|save)} " + "testfile.png\n", reason, program); + exit(99); +} + +int +main(int argc, const char **argv) +{ + FILE *fp; + png_uint_32 default_flags[4/*valid,unknown{before,after}*/]; + int strict = 0, default_tests = 0; + const char *count_argv = "default=save"; + const char *touch_file = NULL; + display d; + + init_display(&d, argv[0]); + + while (++argv, --argc > 0) + { + if (strcmp(*argv, "--strict") == 0) + strict = 1; + + else if (strcmp(*argv, "--default") == 0) + default_tests = 1; + + else if (strcmp(*argv, "--touch") == 0) + { + if (argc > 1) + touch_file = *++argv, --argc; + + else + usage(d.program, "--touch: missing file name"); + } + + else + break; + } + + /* A file name is required, but there should be no other arguments if + * --default was specified. + */ + if (argc <= 0) + usage(d.program, "missing test file"); + + /* GCC BUG: if (default_tests && argc != 1) triggers some weird GCC argc + * optimization which causes warnings with -Wstrict-overflow! + */ + else if (default_tests) if (argc != 1) + usage(d.program, "extra arguments"); + + /* The name of the test file is the last argument; remove it. */ + d.file = argv[--argc]; + + fp = fopen(d.file, "rb"); + if (fp == NULL) + { + perror(d.file); + exit(99); + } + + /* First find all the chunks, known and unknown, in the test file, a failure + * here aborts the whole test. + * + * If 'save' is supported then the normal saving method should happen, + * otherwise if 'read' is supported then the read callback will do the + * same thing. If both are supported the 'read' callback won't be + * instantiated by default. If 'save' is *not* supported then a user + * callback is required even though we can call png_get_unknown_chunks. + */ + if (check(fp, 1, &count_argv, default_flags, &d, +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + 0 +# else + 1 +# endif + ) != PNG_HANDLE_CHUNK_ALWAYS) + { + fprintf(stderr, "%s: %s: internal error\n", d.program, d.file); + exit(99); + } + + /* Now find what the various supplied options cause to change: */ + if (!default_tests) + { + d.test = cmd; /* acts as a flag to say exit, do not longjmp */ +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + perform_one_test(fp, argc, argv, default_flags, &d, 0); +# endif +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + perform_one_test(fp, argc, argv, default_flags, &d, 1); +# endif + d.test = init; + } + + else + { + const char **test = standard_tests; + + /* Set the exit_test pointer here so we can continue after a libpng error. + * NOTE: this leaks memory because the png_struct data from the failing + * test is never freed. + */ + while (*test) + { + const char *this_test = *test++; + const char **next = test; + int count = display_rc(&d, strict), new_count; + const char *result; + int arg_count = 0; + + while (*next) ++next, ++arg_count; + + perform_one_test_safe(fp, arg_count, test, default_flags, &d, + this_test); + + new_count = display_rc(&d, strict); + + if (new_count == count) + result = "PASS"; + + else + result = "FAIL"; + + printf("%s: %s %s\n", result, d.program, this_test); + + test = next+1; + } + } + + fclose(fp); + + if (display_rc(&d, strict) == 0) + { + /* Success, touch the success file if appropriate */ + if (touch_file != NULL) + { + FILE *fsuccess = fopen(touch_file, "wt"); + + if (fsuccess != NULL) + { + int err = 0; + fprintf(fsuccess, "PNG unknown tests succeeded\n"); + fflush(fsuccess); + err = ferror(fsuccess); + + if (fclose(fsuccess) || err) + { + fprintf(stderr, "%s: write failed\n", touch_file); + exit(99); + } + } + + else + { + fprintf(stderr, "%s: open failed\n", touch_file); + exit(99); + } + } + + return 0; + } + + return 1; +} + +#else /* !(READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS) */ +int +main(void) +{ + fprintf(stderr, + " test ignored: no support to find out about unknown chunks\n"); + /* So the test is skipped: */ + return 77; +} +#endif /* READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS */ + +#else /* !(SET_UNKNOWN_CHUNKS && READ) */ +int +main(void) +{ + fprintf(stderr, + " test ignored: no support to modify unknown chunk handling\n"); + /* So the test is skipped: */ + return 77; +} +#endif /* SET_UNKNOWN_CHUNKS && READ*/ diff --git a/main/source/includes/lpng1610/contrib/libtests/pngvalid.c b/main/source/includes/lpng1610/contrib/libtests/pngvalid.c index 6ac986dd..788b6932 100644 --- a/main/source/includes/lpng1610/contrib/libtests/pngvalid.c +++ b/main/source/includes/lpng1610/contrib/libtests/pngvalid.c @@ -1,10579 +1,10579 @@ - -/* pngvalid.c - validate libpng by constructing then reading png files. - * - * Last changed in libpng 1.6.10 [March 6, 2014] - * Copyright (c) 2014 Glenn Randers-Pehrson - * Written by John Cunningham Bowler - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * NOTES: - * This is a C program that is intended to be linked against libpng. It - * generates bitmaps internally, stores them as PNG files (using the - * sequential write code) then reads them back (using the sequential - * read code) and validates that the result has the correct data. - * - * The program can be modified and extended to test the correctness of - * transformations performed by libpng. - */ - -#define _POSIX_SOURCE 1 -#define _ISOC99_SOURCE 1 /* For floating point */ -#define _GNU_SOURCE 1 /* For the floating point exception extension */ - -#include -#include - -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include -#endif - -#ifdef HAVE_FEENABLEEXCEPT /* from config.h, if included */ -# include -#endif - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include -#else -# include "../../png.h" -#endif - -#ifdef PNG_ZLIB_HEADER -# include PNG_ZLIB_HEADER -#else -# include /* For crc32 */ -#endif - -/* 1.6.1 added support for the configure test harness, which uses 77 to indicate - * a skipped test, in earlier versions we need to succeed on a skipped test, so: - */ -#if PNG_LIBPNG_VER < 10601 -# define SKIP 0 -#else -# define SKIP 77 -#endif - -/* pngvalid requires write support and one of the fixed or floating point APIs. - */ -#if defined(PNG_WRITE_SUPPORTED) &&\ - (defined(PNG_FIXED_POINT_SUPPORTED) || defined(PNG_FLOATING_POINT_SUPPORTED)) - -#if PNG_LIBPNG_VER < 10500 -/* This deliberately lacks the PNG_CONST. */ -typedef png_byte *png_const_bytep; - -/* This is copied from 1.5.1 png.h: */ -#define PNG_INTERLACE_ADAM7_PASSES 7 -#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) -#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) -#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) -#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) -#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) -#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) -#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ - (((yIn)<>(((7-(off))-(pass))<<2)) & 0xFU) | \ - ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) -#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ - ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) -#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ - ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) - -/* These are needed too for the default build: */ -#define PNG_WRITE_16BIT_SUPPORTED -#define PNG_READ_16BIT_SUPPORTED - -/* This comes from pnglibconf.h afer 1.5: */ -#define PNG_FP_1 100000 -#define PNG_GAMMA_THRESHOLD_FIXED\ - ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) -#endif - -#if PNG_LIBPNG_VER < 10600 - /* 1.6.0 constifies many APIs, the following exists to allow pngvalid to be - * compiled against earlier versions. - */ -# define png_const_structp png_structp -#endif - -#include /* For floating point constants */ -#include /* For malloc */ -#include /* For memcpy, memset */ -#include /* For floor */ - -/* Unused formal parameter errors are removed using the following macro which is - * expected to have no bad effects on performance. - */ -#ifndef UNUSED -# if defined(__GNUC__) || defined(_MSC_VER) -# define UNUSED(param) (void)param; -# else -# define UNUSED(param) -# endif -#endif - -/***************************** EXCEPTION HANDLING *****************************/ -#ifdef PNG_FREESTANDING_TESTS -# include -#else -# include "../visupng/cexcept.h" -#endif - -#ifdef __cplusplus -# define this not_the_cpp_this -# define new not_the_cpp_new -# define voidcast(type, value) static_cast(value) -#else -# define voidcast(type, value) (value) -#endif /* __cplusplus */ - -struct png_store; -define_exception_type(struct png_store*); - -/* The following are macros to reduce typing everywhere where the well known - * name 'the_exception_context' must be defined. - */ -#define anon_context(ps) struct exception_context *the_exception_context = \ - &(ps)->exception_context -#define context(ps,fault) anon_context(ps); png_store *fault - -/******************************* UTILITIES ************************************/ -/* Error handling is particularly problematic in production code - error - * handlers often themselves have bugs which lead to programs that detect - * minor errors crashing. The following functions deal with one very - * common class of errors in error handlers - attempting to format error or - * warning messages into buffers that are too small. - */ -static size_t safecat(char *buffer, size_t bufsize, size_t pos, - PNG_CONST char *cat) -{ - while (pos < bufsize && cat != NULL && *cat != 0) - buffer[pos++] = *cat++; - - if (pos >= bufsize) - pos = bufsize-1; - - buffer[pos] = 0; - return pos; -} - -static size_t safecatn(char *buffer, size_t bufsize, size_t pos, int n) -{ - char number[64]; - sprintf(number, "%d", n); - return safecat(buffer, bufsize, pos, number); -} - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -static size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d, - int precision) -{ - char number[64]; - sprintf(number, "%.*f", precision, d); - return safecat(buffer, bufsize, pos, number); -} -#endif - -static PNG_CONST char invalid[] = "invalid"; -static PNG_CONST char sep[] = ": "; - -static PNG_CONST char *colour_types[8] = -{ - "grayscale", invalid, "truecolour", "indexed-colour", - "grayscale with alpha", invalid, "truecolour with alpha", invalid -}; - -#ifdef PNG_READ_SUPPORTED -/* Convert a double precision value to fixed point. */ -static png_fixed_point -fix(double d) -{ - d = floor(d * PNG_FP_1 + .5); - return (png_fixed_point)d; -} -#endif /* PNG_READ_SUPPORTED */ - -/* Generate random bytes. This uses a boring repeatable algorithm and it - * is implemented here so that it gives the same set of numbers on every - * architecture. It's a linear congruential generator (Knuth or Sedgewick - * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and - * Hill, "The Art of Electronics" (Pseudo-Random Bit Sequences and Noise - * Generation.) - */ -static void -make_random_bytes(png_uint_32* seed, void* pv, size_t size) -{ - png_uint_32 u0 = seed[0], u1 = seed[1]; - png_bytep bytes = voidcast(png_bytep, pv); - - /* There are thirty three bits, the next bit in the sequence is bit-33 XOR - * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. - */ - size_t i; - for (i=0; i> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; - u1 <<= 8; - u1 |= u0 >> 24; - u0 <<= 8; - u0 |= u; - *bytes++ = (png_byte)u; - } - - seed[0] = u0; - seed[1] = u1; -} - -static void -make_four_random_bytes(png_uint_32* seed, png_bytep bytes) -{ - make_random_bytes(seed, bytes, 4); -} - -#ifdef PNG_READ_SUPPORTED -static void -randomize(void *pv, size_t size) -{ - static png_uint_32 random_seed[2] = {0x56789abc, 0xd}; - make_random_bytes(random_seed, pv, size); -} - -#define RANDOMIZE(this) randomize(&(this), sizeof (this)) - -static unsigned int -random_mod(unsigned int max) -{ - unsigned int x; - - RANDOMIZE(x); - - return x % max; /* 0 .. max-1 */ -} - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -static int -random_choice(void) -{ - unsigned char x; - - RANDOMIZE(x); - - return x & 1; -} -#endif -#endif /* PNG_READ_SUPPORTED */ - -/* A numeric ID based on PNG file characteristics. The 'do_interlace' field - * simply records whether pngvalid did the interlace itself or whether it - * was done by libpng. Width and height must be less than 256. 'palette' is an - * index of the palette to use for formats with a palette (0 otherwise.) - */ -#define FILEID(col, depth, palette, interlace, width, height, do_interlace) \ - ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \ - (((do_interlace)!=0)<<15) + ((width)<<16) + ((height)<<24))) - -#define COL_FROM_ID(id) ((png_byte)((id)& 0x7U)) -#define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU)) -#define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f) -#define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3)) -#define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1)) -#define WIDTH_FROM_ID(id) (((id)>>16) & 0xff) -#define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff) - -/* Utility to construct a standard name for a standard image. */ -static size_t -standard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type, - int bit_depth, unsigned int npalette, int interlace_type, - png_uint_32 w, png_uint_32 h, int do_interlace) -{ - pos = safecat(buffer, bufsize, pos, colour_types[colour_type]); - if (npalette > 0) - { - pos = safecat(buffer, bufsize, pos, "["); - pos = safecatn(buffer, bufsize, pos, npalette); - pos = safecat(buffer, bufsize, pos, "]"); - } - pos = safecat(buffer, bufsize, pos, " "); - pos = safecatn(buffer, bufsize, pos, bit_depth); - pos = safecat(buffer, bufsize, pos, " bit"); - - if (interlace_type != PNG_INTERLACE_NONE) - { - pos = safecat(buffer, bufsize, pos, " interlaced"); - if (do_interlace) - pos = safecat(buffer, bufsize, pos, "(pngvalid)"); - else - pos = safecat(buffer, bufsize, pos, "(libpng)"); - } - - if (w > 0 || h > 0) - { - pos = safecat(buffer, bufsize, pos, " "); - pos = safecatn(buffer, bufsize, pos, w); - pos = safecat(buffer, bufsize, pos, "x"); - pos = safecatn(buffer, bufsize, pos, h); - } - - return pos; -} - -static size_t -standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id) -{ - return standard_name(buffer, bufsize, pos, COL_FROM_ID(id), - DEPTH_FROM_ID(id), PALETTE_FROM_ID(id), INTERLACE_FROM_ID(id), - WIDTH_FROM_ID(id), HEIGHT_FROM_ID(id), DO_INTERLACE_FROM_ID(id)); -} - -/* Convenience API and defines to list valid formats. Note that 16 bit read and - * write support is required to do 16 bit read tests (we must be able to make a - * 16 bit image to test!) - */ -#ifdef PNG_WRITE_16BIT_SUPPORTED -# define WRITE_BDHI 4 -# ifdef PNG_READ_16BIT_SUPPORTED -# define READ_BDHI 4 -# define DO_16BIT -# endif -#else -# define WRITE_BDHI 3 -#endif -#ifndef DO_16BIT -# define READ_BDHI 3 -#endif - -/* The following defines the number of different palettes to generate for - * each log bit depth of a colour type 3 standard image. - */ -#define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1U : 16U) - -static int -next_format(png_bytep colour_type, png_bytep bit_depth, - unsigned int* palette_number, int no_low_depth_gray) -{ - if (*bit_depth == 0) - { - *colour_type = 0; - if (no_low_depth_gray) - *bit_depth = 8; - else - *bit_depth = 1; - *palette_number = 0; - return 1; - } - - if (*colour_type == 3) - { - /* Add multiple palettes for colour type 3. */ - if (++*palette_number < PALETTE_COUNT(*bit_depth)) - return 1; - - *palette_number = 0; - } - - *bit_depth = (png_byte)(*bit_depth << 1); - - /* Palette images are restricted to 8 bit depth */ - if (*bit_depth <= 8 -# ifdef DO_16BIT - || (*colour_type != 3 && *bit_depth <= 16) -# endif - ) - return 1; - - /* Move to the next color type, or return 0 at the end. */ - switch (*colour_type) - { - case 0: - *colour_type = 2; - *bit_depth = 8; - return 1; - - case 2: - *colour_type = 3; - *bit_depth = 1; - return 1; - - case 3: - *colour_type = 4; - *bit_depth = 8; - return 1; - - case 4: - *colour_type = 6; - *bit_depth = 8; - return 1; - - default: - return 0; - } -} - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -static unsigned int -sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth, - png_uint_32 x, unsigned int sample_index) -{ - png_uint_32 bit_index, result; - - /* Find a sample index for the desired sample: */ - x *= bit_depth; - bit_index = x; - - if ((colour_type & 1) == 0) /* !palette */ - { - if (colour_type & 2) - bit_index *= 3; - - if (colour_type & 4) - bit_index += x; /* Alpha channel */ - - /* Multiple channels; select one: */ - if (colour_type & (2+4)) - bit_index += sample_index * bit_depth; - } - - /* Return the sample from the row as an integer. */ - row += bit_index >> 3; - result = *row; - - if (bit_depth == 8) - return result; - - else if (bit_depth > 8) - return (result << 8) + *++row; - - /* Less than 8 bits per sample. */ - bit_index &= 7; - return (result >> (8-bit_index-bit_depth)) & ((1U<> 3] & ~destMask; - unsigned int sourceByte = fromBuffer[fromIndex >> 3]; - - /* Don't rely on << or >> supporting '0' here, just in case: */ - fromIndex &= 7; - if (fromIndex > 0) sourceByte <<= fromIndex; - if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7; - - toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask)); - } - else /* One or more bytes */ - memmove(toBuffer+(toIndex>>3), fromBuffer+(fromIndex>>3), pixelSize>>3); -} - -#ifdef PNG_READ_SUPPORTED -/* Copy a complete row of pixels, taking into account potential partial - * bytes at the end. - */ -static void -row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth) -{ - memcpy(toBuffer, fromBuffer, bitWidth >> 3); - - if ((bitWidth & 7) != 0) - { - unsigned int mask; - - toBuffer += bitWidth >> 3; - fromBuffer += bitWidth >> 3; - /* The remaining bits are in the top of the byte, the mask is the bits to - * retain. - */ - mask = 0xff >> (bitWidth & 7); - *toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask)); - } -} - -/* Compare pixels - they are assumed to start at the first byte in the - * given buffers. - */ -static int -pixel_cmp(png_const_bytep pa, png_const_bytep pb, png_uint_32 bit_width) -{ -#if PNG_LIBPNG_VER < 10506 - if (memcmp(pa, pb, bit_width>>3) == 0) - { - png_uint_32 p; - - if ((bit_width & 7) == 0) return 0; - - /* Ok, any differences? */ - p = pa[bit_width >> 3]; - p ^= pb[bit_width >> 3]; - - if (p == 0) return 0; - - /* There are, but they may not be significant, remove the bits - * after the end (the low order bits in PNG.) - */ - bit_width &= 7; - p >>= 8-bit_width; - - if (p == 0) return 0; - } -#else - /* From libpng-1.5.6 the overwrite should be fixed, so compare the trailing - * bits too: - */ - if (memcmp(pa, pb, (bit_width+7)>>3) == 0) - return 0; -#endif - - /* Return the index of the changed byte. */ - { - png_uint_32 where = 0; - - while (pa[where] == pb[where]) ++where; - return 1+where; - } -} -#endif /* PNG_READ_SUPPORTED */ - -/*************************** BASIC PNG FILE WRITING ***************************/ -/* A png_store takes data from the sequential writer or provides data - * to the sequential reader. It can also store the result of a PNG - * write for later retrieval. - */ -#define STORE_BUFFER_SIZE 500 /* arbitrary */ -typedef struct png_store_buffer -{ - struct png_store_buffer* prev; /* NOTE: stored in reverse order */ - png_byte buffer[STORE_BUFFER_SIZE]; -} png_store_buffer; - -#define FILE_NAME_SIZE 64 - -typedef struct store_palette_entry /* record of a single palette entry */ -{ - png_byte red; - png_byte green; - png_byte blue; - png_byte alpha; -} store_palette_entry, store_palette[256]; - -typedef struct png_store_file -{ - struct png_store_file* next; /* as many as you like... */ - char name[FILE_NAME_SIZE]; - png_uint_32 id; /* must be correct (see FILEID) */ - png_size_t datacount; /* In this (the last) buffer */ - png_store_buffer data; /* Last buffer in file */ - int npalette; /* Number of entries in palette */ - store_palette_entry* palette; /* May be NULL */ -} png_store_file; - -/* The following is a pool of memory allocated by a single libpng read or write - * operation. - */ -typedef struct store_pool -{ - struct png_store *store; /* Back pointer */ - struct store_memory *list; /* List of allocated memory */ - png_byte mark[4]; /* Before and after data */ - - /* Statistics for this run. */ - png_alloc_size_t max; /* Maximum single allocation */ - png_alloc_size_t current; /* Current allocation */ - png_alloc_size_t limit; /* Highest current allocation */ - png_alloc_size_t total; /* Total allocation */ - - /* Overall statistics (retained across successive runs). */ - png_alloc_size_t max_max; - png_alloc_size_t max_limit; - png_alloc_size_t max_total; -} store_pool; - -typedef struct png_store -{ - /* For cexcept.h exception handling - simply store one of these; - * the context is a self pointer but it may point to a different - * png_store (in fact it never does in this program.) - */ - struct exception_context - exception_context; - - unsigned int verbose :1; - unsigned int treat_warnings_as_errors :1; - unsigned int expect_error :1; - unsigned int expect_warning :1; - unsigned int saw_warning :1; - unsigned int speed :1; - unsigned int progressive :1; /* use progressive read */ - unsigned int validated :1; /* used as a temporary flag */ - int nerrors; - int nwarnings; - int noptions; /* number of options below: */ - struct { - unsigned char option; /* option number, 0..30 */ - unsigned char setting; /* setting (unset,invalid,on,off) */ - } options[16]; - char test[128]; /* Name of test */ - char error[256]; - - /* Read fields */ - png_structp pread; /* Used to read a saved file */ - png_infop piread; - png_store_file* current; /* Set when reading */ - png_store_buffer* next; /* Set when reading */ - png_size_t readpos; /* Position in *next */ - png_byte* image; /* Buffer for reading interlaced images */ - png_size_t cb_image; /* Size of this buffer */ - png_size_t cb_row; /* Row size of the image(s) */ - png_uint_32 image_h; /* Number of rows in a single image */ - store_pool read_memory_pool; - - /* Write fields */ - png_store_file* saved; - png_structp pwrite; /* Used when writing a new file */ - png_infop piwrite; - png_size_t writepos; /* Position in .new */ - char wname[FILE_NAME_SIZE]; - png_store_buffer new; /* The end of the new PNG file being written. */ - store_pool write_memory_pool; - store_palette_entry* palette; - int npalette; -} png_store; - -/* Initialization and cleanup */ -static void -store_pool_mark(png_bytep mark) -{ - static png_uint_32 store_seed[2] = { 0x12345678, 1}; - - make_four_random_bytes(store_seed, mark); -} - -#ifdef PNG_READ_SUPPORTED -/* Use this for random 32 bit values; this function makes sure the result is - * non-zero. - */ -static png_uint_32 -random_32(void) -{ - - for(;;) - { - png_byte mark[4]; - png_uint_32 result; - - store_pool_mark(mark); - result = png_get_uint_32(mark); - - if (result != 0) - return result; - } -} -#endif /* PNG_READ_SUPPORTED */ - -static void -store_pool_init(png_store *ps, store_pool *pool) -{ - memset(pool, 0, sizeof *pool); - - pool->store = ps; - pool->list = NULL; - pool->max = pool->current = pool->limit = pool->total = 0; - pool->max_max = pool->max_limit = pool->max_total = 0; - store_pool_mark(pool->mark); -} - -static void -store_init(png_store* ps) -{ - memset(ps, 0, sizeof *ps); - init_exception_context(&ps->exception_context); - store_pool_init(ps, &ps->read_memory_pool); - store_pool_init(ps, &ps->write_memory_pool); - ps->verbose = 0; - ps->treat_warnings_as_errors = 0; - ps->expect_error = 0; - ps->expect_warning = 0; - ps->saw_warning = 0; - ps->speed = 0; - ps->progressive = 0; - ps->validated = 0; - ps->nerrors = ps->nwarnings = 0; - ps->pread = NULL; - ps->piread = NULL; - ps->saved = ps->current = NULL; - ps->next = NULL; - ps->readpos = 0; - ps->image = NULL; - ps->cb_image = 0; - ps->cb_row = 0; - ps->image_h = 0; - ps->pwrite = NULL; - ps->piwrite = NULL; - ps->writepos = 0; - ps->new.prev = NULL; - ps->palette = NULL; - ps->npalette = 0; - ps->noptions = 0; -} - -static void -store_freebuffer(png_store_buffer* psb) -{ - if (psb->prev) - { - store_freebuffer(psb->prev); - free(psb->prev); - psb->prev = NULL; - } -} - -static void -store_freenew(png_store *ps) -{ - store_freebuffer(&ps->new); - ps->writepos = 0; - if (ps->palette != NULL) - { - free(ps->palette); - ps->palette = NULL; - ps->npalette = 0; - } -} - -static void -store_storenew(png_store *ps) -{ - png_store_buffer *pb; - - if (ps->writepos != STORE_BUFFER_SIZE) - png_error(ps->pwrite, "invalid store call"); - - pb = voidcast(png_store_buffer*, malloc(sizeof *pb)); - - if (pb == NULL) - png_error(ps->pwrite, "store new: OOM"); - - *pb = ps->new; - ps->new.prev = pb; - ps->writepos = 0; -} - -static void -store_freefile(png_store_file **ppf) -{ - if (*ppf != NULL) - { - store_freefile(&(*ppf)->next); - - store_freebuffer(&(*ppf)->data); - (*ppf)->datacount = 0; - if ((*ppf)->palette != NULL) - { - free((*ppf)->palette); - (*ppf)->palette = NULL; - (*ppf)->npalette = 0; - } - free(*ppf); - *ppf = NULL; - } -} - -/* Main interface to file storeage, after writing a new PNG file (see the API - * below) call store_storefile to store the result with the given name and id. - */ -static void -store_storefile(png_store *ps, png_uint_32 id) -{ - png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf)); - if (pf == NULL) - png_error(ps->pwrite, "storefile: OOM"); - safecat(pf->name, sizeof pf->name, 0, ps->wname); - pf->id = id; - pf->data = ps->new; - pf->datacount = ps->writepos; - ps->new.prev = NULL; - ps->writepos = 0; - pf->palette = ps->palette; - pf->npalette = ps->npalette; - ps->palette = 0; - ps->npalette = 0; - - /* And save it. */ - pf->next = ps->saved; - ps->saved = pf; -} - -/* Generate an error message (in the given buffer) */ -static size_t -store_message(png_store *ps, png_const_structp pp, char *buffer, size_t bufsize, - size_t pos, PNG_CONST char *msg) -{ - if (pp != NULL && pp == ps->pread) - { - /* Reading a file */ - pos = safecat(buffer, bufsize, pos, "read: "); - - if (ps->current != NULL) - { - pos = safecat(buffer, bufsize, pos, ps->current->name); - pos = safecat(buffer, bufsize, pos, sep); - } - } - - else if (pp != NULL && pp == ps->pwrite) - { - /* Writing a file */ - pos = safecat(buffer, bufsize, pos, "write: "); - pos = safecat(buffer, bufsize, pos, ps->wname); - pos = safecat(buffer, bufsize, pos, sep); - } - - else - { - /* Neither reading nor writing (or a memory error in struct delete) */ - pos = safecat(buffer, bufsize, pos, "pngvalid: "); - } - - if (ps->test[0] != 0) - { - pos = safecat(buffer, bufsize, pos, ps->test); - pos = safecat(buffer, bufsize, pos, sep); - } - pos = safecat(buffer, bufsize, pos, msg); - return pos; -} - -/* Verbose output to the error stream: */ -static void -store_verbose(png_store *ps, png_const_structp pp, png_const_charp prefix, - png_const_charp message) -{ - char buffer[512]; - - if (prefix) - fputs(prefix, stderr); - - (void)store_message(ps, pp, buffer, sizeof buffer, 0, message); - fputs(buffer, stderr); - fputc('\n', stderr); -} - -/* Log an error or warning - the relevant count is always incremented. */ -static void -store_log(png_store* ps, png_const_structp pp, png_const_charp message, - int is_error) -{ - /* The warning is copied to the error buffer if there are no errors and it is - * the first warning. The error is copied to the error buffer if it is the - * first error (overwriting any prior warnings). - */ - if (is_error ? (ps->nerrors)++ == 0 : - (ps->nwarnings)++ == 0 && ps->nerrors == 0) - store_message(ps, pp, ps->error, sizeof ps->error, 0, message); - - if (ps->verbose) - store_verbose(ps, pp, is_error ? "error: " : "warning: ", message); -} - -#ifdef PNG_READ_SUPPORTED -/* Internal error function, called with a png_store but no libpng stuff. */ -static void -internal_error(png_store *ps, png_const_charp message) -{ - store_log(ps, NULL, message, 1 /* error */); - - /* And finally throw an exception. */ - { - struct exception_context *the_exception_context = &ps->exception_context; - Throw ps; - } -} -#endif /* PNG_READ_SUPPORTED */ - -/* Functions to use as PNG callbacks. */ -static void PNGCBAPI -store_error(png_structp ppIn, png_const_charp message) /* PNG_NORETURN */ -{ - png_const_structp pp = ppIn; - png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); - - if (!ps->expect_error) - store_log(ps, pp, message, 1 /* error */); - - /* And finally throw an exception. */ - { - struct exception_context *the_exception_context = &ps->exception_context; - Throw ps; - } -} - -static void PNGCBAPI -store_warning(png_structp ppIn, png_const_charp message) -{ - png_const_structp pp = ppIn; - png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); - - if (!ps->expect_warning) - store_log(ps, pp, message, 0 /* warning */); - else - ps->saw_warning = 1; -} - -/* These somewhat odd functions are used when reading an image to ensure that - * the buffer is big enough, the png_structp is for errors. - */ -/* Return a single row from the correct image. */ -static png_bytep -store_image_row(PNG_CONST png_store* ps, png_const_structp pp, int nImage, - png_uint_32 y) -{ - png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2; - - if (ps->image == NULL) - png_error(pp, "no allocated image"); - - if (coffset + ps->cb_row + 3 > ps->cb_image) - png_error(pp, "image too small"); - - return ps->image + coffset; -} - -static void -store_image_free(png_store *ps, png_const_structp pp) -{ - if (ps->image != NULL) - { - png_bytep image = ps->image; - - if (image[-1] != 0xed || image[ps->cb_image] != 0xfe) - { - if (pp != NULL) - png_error(pp, "png_store image overwrite (1)"); - else - store_log(ps, NULL, "png_store image overwrite (2)", 1); - } - - ps->image = NULL; - ps->cb_image = 0; - --image; - free(image); - } -} - -static void -store_ensure_image(png_store *ps, png_const_structp pp, int nImages, - png_size_t cbRow, png_uint_32 cRows) -{ - png_size_t cb = nImages * cRows * (cbRow + 5); - - if (ps->cb_image < cb) - { - png_bytep image; - - store_image_free(ps, pp); - - /* The buffer is deliberately mis-aligned. */ - image = voidcast(png_bytep, malloc(cb+2)); - if (image == NULL) - { - /* Called from the startup - ignore the error for the moment. */ - if (pp == NULL) - return; - - png_error(pp, "OOM allocating image buffer"); - } - - /* These magic tags are used to detect overwrites above. */ - ++image; - image[-1] = 0xed; - image[cb] = 0xfe; - - ps->image = image; - ps->cb_image = cb; - } - - /* We have an adequate sized image; lay out the rows. There are 2 bytes at - * the start and three at the end of each (this ensures that the row - * alignment starts out odd - 2+1 and changes for larger images on each row.) - */ - ps->cb_row = cbRow; - ps->image_h = cRows; - - /* For error checking, the whole buffer is set to 10110010 (0xb2 - 178). - * This deliberately doesn't match the bits in the size test image which are - * outside the image; these are set to 0xff (all 1). To make the row - * comparison work in the 'size' test case the size rows are pre-initialized - * to the same value prior to calling 'standard_row'. - */ - memset(ps->image, 178, cb); - - /* Then put in the marks. */ - while (--nImages >= 0) - { - png_uint_32 y; - - for (y=0; yimage; - - if (image[-1] != 0xed || image[ps->cb_image] != 0xfe) - png_error(pp, "image overwrite"); - else - { - png_size_t cbRow = ps->cb_row; - png_uint_32 rows = ps->image_h; - - image += iImage * (cbRow+5) * ps->image_h; - - image += 2; /* skip image first row markers */ - - while (rows-- > 0) - { - if (image[-2] != 190 || image[-1] != 239) - png_error(pp, "row start overwritten"); - - if (image[cbRow] != 222 || image[cbRow+1] != 173 || - image[cbRow+2] != 17) - png_error(pp, "row end overwritten"); - - image += cbRow+5; - } - } -} -#endif /* PNG_READ_SUPPORTED */ - -static void PNGCBAPI -store_write(png_structp ppIn, png_bytep pb, png_size_t st) -{ - png_const_structp pp = ppIn; - png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); - - if (ps->pwrite != pp) - png_error(pp, "store state damaged"); - - while (st > 0) - { - size_t cb; - - if (ps->writepos >= STORE_BUFFER_SIZE) - store_storenew(ps); - - cb = st; - - if (cb > STORE_BUFFER_SIZE - ps->writepos) - cb = STORE_BUFFER_SIZE - ps->writepos; - - memcpy(ps->new.buffer + ps->writepos, pb, cb); - pb += cb; - st -= cb; - ps->writepos += cb; - } -} - -static void PNGCBAPI -store_flush(png_structp ppIn) -{ - UNUSED(ppIn) /*DOES NOTHING*/ -} - -#ifdef PNG_READ_SUPPORTED -static size_t -store_read_buffer_size(png_store *ps) -{ - /* Return the bytes available for read in the current buffer. */ - if (ps->next != &ps->current->data) - return STORE_BUFFER_SIZE; - - return ps->current->datacount; -} - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -/* Return total bytes available for read. */ -static size_t -store_read_buffer_avail(png_store *ps) -{ - if (ps->current != NULL && ps->next != NULL) - { - png_store_buffer *next = &ps->current->data; - size_t cbAvail = ps->current->datacount; - - while (next != ps->next && next != NULL) - { - next = next->prev; - cbAvail += STORE_BUFFER_SIZE; - } - - if (next != ps->next) - png_error(ps->pread, "buffer read error"); - - if (cbAvail > ps->readpos) - return cbAvail - ps->readpos; - } - - return 0; -} -#endif - -static int -store_read_buffer_next(png_store *ps) -{ - png_store_buffer *pbOld = ps->next; - png_store_buffer *pbNew = &ps->current->data; - if (pbOld != pbNew) - { - while (pbNew != NULL && pbNew->prev != pbOld) - pbNew = pbNew->prev; - - if (pbNew != NULL) - { - ps->next = pbNew; - ps->readpos = 0; - return 1; - } - - png_error(ps->pread, "buffer lost"); - } - - return 0; /* EOF or error */ -} - -/* Need separate implementation and callback to allow use of the same code - * during progressive read, where the io_ptr is set internally by libpng. - */ -static void -store_read_imp(png_store *ps, png_bytep pb, png_size_t st) -{ - if (ps->current == NULL || ps->next == NULL) - png_error(ps->pread, "store state damaged"); - - while (st > 0) - { - size_t cbAvail = store_read_buffer_size(ps) - ps->readpos; - - if (cbAvail > 0) - { - if (cbAvail > st) cbAvail = st; - memcpy(pb, ps->next->buffer + ps->readpos, cbAvail); - st -= cbAvail; - pb += cbAvail; - ps->readpos += cbAvail; - } - - else if (!store_read_buffer_next(ps)) - png_error(ps->pread, "read beyond end of file"); - } -} - -static void PNGCBAPI -store_read(png_structp ppIn, png_bytep pb, png_size_t st) -{ - png_const_structp pp = ppIn; - png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); - - if (ps == NULL || ps->pread != pp) - png_error(pp, "bad store read call"); - - store_read_imp(ps, pb, st); -} - -static void -store_progressive_read(png_store *ps, png_structp pp, png_infop pi) -{ - /* Notice that a call to store_read will cause this function to fail because - * readpos will be set. - */ - if (ps->pread != pp || ps->current == NULL || ps->next == NULL) - png_error(pp, "store state damaged (progressive)"); - - do - { - if (ps->readpos != 0) - png_error(pp, "store_read called during progressive read"); - - png_process_data(pp, pi, ps->next->buffer, store_read_buffer_size(ps)); - } - while (store_read_buffer_next(ps)); -} -#endif /* PNG_READ_SUPPORTED */ - -/* The caller must fill this in: */ -static store_palette_entry * -store_write_palette(png_store *ps, int npalette) -{ - if (ps->pwrite == NULL) - store_log(ps, NULL, "attempt to write palette without write stream", 1); - - if (ps->palette != NULL) - png_error(ps->pwrite, "multiple store_write_palette calls"); - - /* This function can only return NULL if called with '0'! */ - if (npalette > 0) - { - ps->palette = voidcast(store_palette_entry*, malloc(npalette * - sizeof *ps->palette)); - - if (ps->palette == NULL) - png_error(ps->pwrite, "store new palette: OOM"); - - ps->npalette = npalette; - } - - return ps->palette; -} - -#ifdef PNG_READ_SUPPORTED -static store_palette_entry * -store_current_palette(png_store *ps, int *npalette) -{ - /* This is an internal error (the call has been made outside a read - * operation.) - */ - if (ps->current == NULL) - store_log(ps, ps->pread, "no current stream for palette", 1); - - /* The result may be null if there is no palette. */ - *npalette = ps->current->npalette; - return ps->current->palette; -} -#endif /* PNG_READ_SUPPORTED */ - -/***************************** MEMORY MANAGEMENT*** ***************************/ -#ifdef PNG_USER_MEM_SUPPORTED -/* A store_memory is simply the header for an allocated block of memory. The - * pointer returned to libpng is just after the end of the header block, the - * allocated memory is followed by a second copy of the 'mark'. - */ -typedef struct store_memory -{ - store_pool *pool; /* Originating pool */ - struct store_memory *next; /* Singly linked list */ - png_alloc_size_t size; /* Size of memory allocated */ - png_byte mark[4]; /* ID marker */ -} store_memory; - -/* Handle a fatal error in memory allocation. This calls png_error if the - * libpng struct is non-NULL, else it outputs a message and returns. This means - * that a memory problem while libpng is running will abort (png_error) the - * handling of particular file while one in cleanup (after the destroy of the - * struct has returned) will simply keep going and free (or attempt to free) - * all the memory. - */ -static void -store_pool_error(png_store *ps, png_const_structp pp, PNG_CONST char *msg) -{ - if (pp != NULL) - png_error(pp, msg); - - /* Else we have to do it ourselves. png_error eventually calls store_log, - * above. store_log accepts a NULL png_structp - it just changes what gets - * output by store_message. - */ - store_log(ps, pp, msg, 1 /* error */); -} - -static void -store_memory_free(png_const_structp pp, store_pool *pool, store_memory *memory) -{ - /* Note that pp may be NULL (see store_pool_delete below), the caller has - * found 'memory' in pool->list *and* unlinked this entry, so this is a valid - * pointer (for sure), but the contents may have been trashed. - */ - if (memory->pool != pool) - store_pool_error(pool->store, pp, "memory corrupted (pool)"); - - else if (memcmp(memory->mark, pool->mark, sizeof memory->mark) != 0) - store_pool_error(pool->store, pp, "memory corrupted (start)"); - - /* It should be safe to read the size field now. */ - else - { - png_alloc_size_t cb = memory->size; - - if (cb > pool->max) - store_pool_error(pool->store, pp, "memory corrupted (size)"); - - else if (memcmp((png_bytep)(memory+1)+cb, pool->mark, sizeof pool->mark) - != 0) - store_pool_error(pool->store, pp, "memory corrupted (end)"); - - /* Finally give the library a chance to find problems too: */ - else - { - pool->current -= cb; - free(memory); - } - } -} - -static void -store_pool_delete(png_store *ps, store_pool *pool) -{ - if (pool->list != NULL) - { - fprintf(stderr, "%s: %s %s: memory lost (list follows):\n", ps->test, - pool == &ps->read_memory_pool ? "read" : "write", - pool == &ps->read_memory_pool ? (ps->current != NULL ? - ps->current->name : "unknown file") : ps->wname); - ++ps->nerrors; - - do - { - store_memory *next = pool->list; - pool->list = next->next; - next->next = NULL; - - fprintf(stderr, "\t%lu bytes @ %p\n", - (unsigned long)next->size, (PNG_CONST void*)(next+1)); - /* The NULL means this will always return, even if the memory is - * corrupted. - */ - store_memory_free(NULL, pool, next); - } - while (pool->list != NULL); - } - - /* And reset the other fields too for the next time. */ - if (pool->max > pool->max_max) pool->max_max = pool->max; - pool->max = 0; - if (pool->current != 0) /* unexpected internal error */ - fprintf(stderr, "%s: %s %s: memory counter mismatch (internal error)\n", - ps->test, pool == &ps->read_memory_pool ? "read" : "write", - pool == &ps->read_memory_pool ? (ps->current != NULL ? - ps->current->name : "unknown file") : ps->wname); - pool->current = 0; - - if (pool->limit > pool->max_limit) - pool->max_limit = pool->limit; - - pool->limit = 0; - - if (pool->total > pool->max_total) - pool->max_total = pool->total; - - pool->total = 0; - - /* Get a new mark too. */ - store_pool_mark(pool->mark); -} - -/* The memory callbacks: */ -static png_voidp PNGCBAPI -store_malloc(png_structp ppIn, png_alloc_size_t cb) -{ - png_const_structp pp = ppIn; - store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); - store_memory *new = voidcast(store_memory*, malloc(cb + (sizeof *new) + - (sizeof pool->mark))); - - if (new != NULL) - { - if (cb > pool->max) - pool->max = cb; - - pool->current += cb; - - if (pool->current > pool->limit) - pool->limit = pool->current; - - pool->total += cb; - - new->size = cb; - memcpy(new->mark, pool->mark, sizeof new->mark); - memcpy((png_byte*)(new+1) + cb, pool->mark, sizeof pool->mark); - new->pool = pool; - new->next = pool->list; - pool->list = new; - ++new; - } - - else - { - /* NOTE: the PNG user malloc function cannot use the png_ptr it is passed - * other than to retrieve the allocation pointer! libpng calls the - * store_malloc callback in two basic cases: - * - * 1) From png_malloc; png_malloc will do a png_error itself if NULL is - * returned. - * 2) From png_struct or png_info structure creation; png_malloc is - * to return so cleanup can be performed. - * - * To handle this store_malloc can log a message, but can't do anything - * else. - */ - store_log(pool->store, pp, "out of memory", 1 /* is_error */); - } - - return new; -} - -static void PNGCBAPI -store_free(png_structp ppIn, png_voidp memory) -{ - png_const_structp pp = ppIn; - store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); - store_memory *this = voidcast(store_memory*, memory), **test; - - /* Because libpng calls store_free with a dummy png_struct when deleting - * png_struct or png_info via png_destroy_struct_2 it is necessary to check - * the passed in png_structp to ensure it is valid, and not pass it to - * png_error if it is not. - */ - if (pp != pool->store->pread && pp != pool->store->pwrite) - pp = NULL; - - /* First check that this 'memory' really is valid memory - it must be in the - * pool list. If it is, use the shared memory_free function to free it. - */ - --this; - for (test = &pool->list; *test != this; test = &(*test)->next) - { - if (*test == NULL) - { - store_pool_error(pool->store, pp, "bad pointer to free"); - return; - } - } - - /* Unlink this entry, *test == this. */ - *test = this->next; - this->next = NULL; - store_memory_free(pp, pool, this); -} -#endif /* PNG_USER_MEM_SUPPORTED */ - -/* Setup functions. */ -/* Cleanup when aborting a write or after storing the new file. */ -static void -store_write_reset(png_store *ps) -{ - if (ps->pwrite != NULL) - { - anon_context(ps); - - Try - png_destroy_write_struct(&ps->pwrite, &ps->piwrite); - - Catch_anonymous - { - /* memory corruption: continue. */ - } - - ps->pwrite = NULL; - ps->piwrite = NULL; - } - - /* And make sure that all the memory has been freed - this will output - * spurious errors in the case of memory corruption above, but this is safe. - */ -# ifdef PNG_USER_MEM_SUPPORTED - store_pool_delete(ps, &ps->write_memory_pool); -# endif - - store_freenew(ps); -} - -/* The following is the main write function, it returns a png_struct and, - * optionally, a png_info suitable for writiing a new PNG file. Use - * store_storefile above to record this file after it has been written. The - * returned libpng structures as destroyed by store_write_reset above. - */ -static png_structp -set_store_for_write(png_store *ps, png_infopp ppi, - PNG_CONST char * volatile name) -{ - anon_context(ps); - - Try - { - if (ps->pwrite != NULL) - png_error(ps->pwrite, "write store already in use"); - - store_write_reset(ps); - safecat(ps->wname, sizeof ps->wname, 0, name); - - /* Don't do the slow memory checks if doing a speed test, also if user - * memory is not supported we can't do it anyway. - */ -# ifdef PNG_USER_MEM_SUPPORTED - if (!ps->speed) - ps->pwrite = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, - ps, store_error, store_warning, &ps->write_memory_pool, - store_malloc, store_free); - - else -# endif - ps->pwrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, - ps, store_error, store_warning); - - png_set_write_fn(ps->pwrite, ps, store_write, store_flush); - -# ifdef PNG_SET_OPTION_SUPPORTED - { - int opt; - for (opt=0; optnoptions; ++opt) - if (png_set_option(ps->pwrite, ps->options[opt].option, - ps->options[opt].setting) == PNG_OPTION_INVALID) - png_error(ps->pwrite, "png option invalid"); - } -# endif - - if (ppi != NULL) - *ppi = ps->piwrite = png_create_info_struct(ps->pwrite); - } - - Catch_anonymous - return NULL; - - return ps->pwrite; -} - -/* Cleanup when finished reading (either due to error or in the success case). - * This routine exists even when there is no read support to make the code - * tidier (avoid a mass of ifdefs) and so easier to maintain. - */ -static void -store_read_reset(png_store *ps) -{ -# ifdef PNG_READ_SUPPORTED - if (ps->pread != NULL) - { - anon_context(ps); - - Try - png_destroy_read_struct(&ps->pread, &ps->piread, NULL); - - Catch_anonymous - { - /* error already output: continue */ - } - - ps->pread = NULL; - ps->piread = NULL; - } -# endif - -# ifdef PNG_USER_MEM_SUPPORTED - /* Always do this to be safe. */ - store_pool_delete(ps, &ps->read_memory_pool); -# endif - - ps->current = NULL; - ps->next = NULL; - ps->readpos = 0; - ps->validated = 0; -} - -#ifdef PNG_READ_SUPPORTED -static void -store_read_set(png_store *ps, png_uint_32 id) -{ - png_store_file *pf = ps->saved; - - while (pf != NULL) - { - if (pf->id == id) - { - ps->current = pf; - ps->next = NULL; - store_read_buffer_next(ps); - return; - } - - pf = pf->next; - } - - { - size_t pos; - char msg[FILE_NAME_SIZE+64]; - - pos = standard_name_from_id(msg, sizeof msg, 0, id); - pos = safecat(msg, sizeof msg, pos, ": file not found"); - png_error(ps->pread, msg); - } -} - -/* The main interface for reading a saved file - pass the id number of the file - * to retrieve. Ids must be unique or the earlier file will be hidden. The API - * returns a png_struct and, optionally, a png_info. Both of these will be - * destroyed by store_read_reset above. - */ -static png_structp -set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id, - PNG_CONST char *name) -{ - /* Set the name for png_error */ - safecat(ps->test, sizeof ps->test, 0, name); - - if (ps->pread != NULL) - png_error(ps->pread, "read store already in use"); - - store_read_reset(ps); - - /* Both the create APIs can return NULL if used in their default mode - * (because there is no other way of handling an error because the jmp_buf - * by default is stored in png_struct and that has not been allocated!) - * However, given that store_error works correctly in these circumstances - * we don't ever expect NULL in this program. - */ -# ifdef PNG_USER_MEM_SUPPORTED - if (!ps->speed) - ps->pread = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, ps, - store_error, store_warning, &ps->read_memory_pool, store_malloc, - store_free); - - else -# endif - ps->pread = png_create_read_struct(PNG_LIBPNG_VER_STRING, ps, store_error, - store_warning); - - if (ps->pread == NULL) - { - struct exception_context *the_exception_context = &ps->exception_context; - - store_log(ps, NULL, "png_create_read_struct returned NULL (unexpected)", - 1 /*error*/); - - Throw ps; - } - -# ifdef PNG_SET_OPTION_SUPPORTED - { - int opt; - for (opt=0; optnoptions; ++opt) - if (png_set_option(ps->pread, ps->options[opt].option, - ps->options[opt].setting) == PNG_OPTION_INVALID) - png_error(ps->pread, "png option invalid"); - } -# endif - - store_read_set(ps, id); - - if (ppi != NULL) - *ppi = ps->piread = png_create_info_struct(ps->pread); - - return ps->pread; -} -#endif /* PNG_READ_SUPPORTED */ - -/* The overall cleanup of a store simply calls the above then removes all the - * saved files. This does not delete the store itself. - */ -static void -store_delete(png_store *ps) -{ - store_write_reset(ps); - store_read_reset(ps); - store_freefile(&ps->saved); - store_image_free(ps, NULL); -} - -/*********************** PNG FILE MODIFICATION ON READ ************************/ -/* Files may be modified on read. The following structure contains a complete - * png_store together with extra members to handle modification and a special - * read callback for libpng. To use this the 'modifications' field must be set - * to a list of png_modification structures that actually perform the - * modification, otherwise a png_modifier is functionally equivalent to a - * png_store. There is a special read function, set_modifier_for_read, which - * replaces set_store_for_read. - */ -typedef enum modifier_state -{ - modifier_start, /* Initial value */ - modifier_signature, /* Have a signature */ - modifier_IHDR /* Have an IHDR */ -} modifier_state; - -typedef struct CIE_color -{ - /* A single CIE tristimulus value, representing the unique response of a - * standard observer to a variety of light spectra. The observer recognizes - * all spectra that produce this response as the same color, therefore this - * is effectively a description of a color. - */ - double X, Y, Z; -} CIE_color; - -typedef struct color_encoding -{ - /* A description of an (R,G,B) encoding of color (as defined above); this - * includes the actual colors of the (R,G,B) triples (1,0,0), (0,1,0) and - * (0,0,1) plus an encoding value that is used to encode the linear - * components R, G and B to give the actual values R^gamma, G^gamma and - * B^gamma that are stored. - */ - double gamma; /* Encoding (file) gamma of space */ - CIE_color red, green, blue; /* End points */ -} color_encoding; - -#ifdef PNG_READ_SUPPORTED -static double -chromaticity_x(CIE_color c) -{ - return c.X / (c.X + c.Y + c.Z); -} - -static double -chromaticity_y(CIE_color c) -{ - return c.Y / (c.X + c.Y + c.Z); -} - -static CIE_color -white_point(PNG_CONST color_encoding *encoding) -{ - CIE_color white; - - white.X = encoding->red.X + encoding->green.X + encoding->blue.X; - white.Y = encoding->red.Y + encoding->green.Y + encoding->blue.Y; - white.Z = encoding->red.Z + encoding->green.Z + encoding->blue.Z; - - return white; -} - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -static void -normalize_color_encoding(color_encoding *encoding) -{ - PNG_CONST double whiteY = encoding->red.Y + encoding->green.Y + - encoding->blue.Y; - - if (whiteY != 1) - { - encoding->red.X /= whiteY; - encoding->red.Y /= whiteY; - encoding->red.Z /= whiteY; - encoding->green.X /= whiteY; - encoding->green.Y /= whiteY; - encoding->green.Z /= whiteY; - encoding->blue.X /= whiteY; - encoding->blue.Y /= whiteY; - encoding->blue.Z /= whiteY; - } -} -#endif - -static size_t -safecat_color_encoding(char *buffer, size_t bufsize, size_t pos, - PNG_CONST color_encoding *e, double encoding_gamma) -{ - if (e != 0) - { - if (encoding_gamma != 0) - pos = safecat(buffer, bufsize, pos, "("); - pos = safecat(buffer, bufsize, pos, "R("); - pos = safecatd(buffer, bufsize, pos, e->red.X, 4); - pos = safecat(buffer, bufsize, pos, ","); - pos = safecatd(buffer, bufsize, pos, e->red.Y, 4); - pos = safecat(buffer, bufsize, pos, ","); - pos = safecatd(buffer, bufsize, pos, e->red.Z, 4); - pos = safecat(buffer, bufsize, pos, "),G("); - pos = safecatd(buffer, bufsize, pos, e->green.X, 4); - pos = safecat(buffer, bufsize, pos, ","); - pos = safecatd(buffer, bufsize, pos, e->green.Y, 4); - pos = safecat(buffer, bufsize, pos, ","); - pos = safecatd(buffer, bufsize, pos, e->green.Z, 4); - pos = safecat(buffer, bufsize, pos, "),B("); - pos = safecatd(buffer, bufsize, pos, e->blue.X, 4); - pos = safecat(buffer, bufsize, pos, ","); - pos = safecatd(buffer, bufsize, pos, e->blue.Y, 4); - pos = safecat(buffer, bufsize, pos, ","); - pos = safecatd(buffer, bufsize, pos, e->blue.Z, 4); - pos = safecat(buffer, bufsize, pos, ")"); - if (encoding_gamma != 0) - pos = safecat(buffer, bufsize, pos, ")"); - } - - if (encoding_gamma != 0) - { - pos = safecat(buffer, bufsize, pos, "^"); - pos = safecatd(buffer, bufsize, pos, encoding_gamma, 5); - } - - return pos; -} -#endif /* PNG_READ_SUPPORTED */ - -typedef struct png_modifier -{ - png_store this; /* I am a png_store */ - struct png_modification *modifications; /* Changes to make */ - - modifier_state state; /* My state */ - - /* Information from IHDR: */ - png_byte bit_depth; /* From IHDR */ - png_byte colour_type; /* From IHDR */ - - /* While handling PLTE, IDAT and IEND these chunks may be pended to allow - * other chunks to be inserted. - */ - png_uint_32 pending_len; - png_uint_32 pending_chunk; - - /* Test values */ - double *gammas; - unsigned int ngammas; - unsigned int ngamma_tests; /* Number of gamma tests to run*/ - double current_gamma; /* 0 if not set */ - PNG_CONST color_encoding *encodings; - unsigned int nencodings; - PNG_CONST color_encoding *current_encoding; /* If an encoding has been set */ - unsigned int encoding_counter; /* For iteration */ - int encoding_ignored; /* Something overwrote it */ - - /* Control variables used to iterate through possible encodings, the - * following must be set to 0 and tested by the function that uses the - * png_modifier because the modifier only sets it to 1 (true.) - */ - unsigned int repeat :1; /* Repeat this transform test. */ - unsigned int test_uses_encoding :1; - - /* Lowest sbit to test (libpng fails for sbit < 8) */ - png_byte sbitlow; - - /* Error control - these are the limits on errors accepted by the gamma tests - * below. - */ - double maxout8; /* Maximum output value error */ - double maxabs8; /* Absolute sample error 0..1 */ - double maxcalc8; /* Absolute sample error 0..1 */ - double maxpc8; /* Percentage sample error 0..100% */ - double maxout16; /* Maximum output value error */ - double maxabs16; /* Absolute sample error 0..1 */ - double maxcalc16;/* Absolute sample error 0..1 */ - double maxcalcG; /* Absolute sample error 0..1 */ - double maxpc16; /* Percentage sample error 0..100% */ - - /* This is set by transforms that need to allow a higher limit, it is an - * internal check on pngvalid to ensure that the calculated error limits are - * not ridiculous; without this it is too easy to make a mistake in pngvalid - * that allows any value through. - */ - double limit; /* limit on error values, normally 4E-3 */ - - /* Log limits - values above this are logged, but not necessarily - * warned. - */ - double log8; /* Absolute error in 8 bits to log */ - double log16; /* Absolute error in 16 bits to log */ - - /* Logged 8 and 16 bit errors ('output' values): */ - double error_gray_2; - double error_gray_4; - double error_gray_8; - double error_gray_16; - double error_color_8; - double error_color_16; - double error_indexed; - - /* Flags: */ - /* Whether to call png_read_update_info, not png_read_start_image, and how - * many times to call it. - */ - int use_update_info; - - /* Whether or not to interlace. */ - int interlace_type :9; /* int, but must store '1' */ - - /* Run the standard tests? */ - unsigned int test_standard :1; - - /* Run the odd-sized image and interlace read/write tests? */ - unsigned int test_size :1; - - /* Run tests on reading with a combination of transforms, */ - unsigned int test_transform :1; - - /* When to use the use_input_precision option, this controls the gamma - * validation code checks. If set any value that is within the transformed - * range input-.5 to input+.5 will be accepted, otherwise the value must be - * within the normal limits. It should not be necessary to set this; the - * result should always be exact within the permitted error limits. - */ - unsigned int use_input_precision :1; - unsigned int use_input_precision_sbit :1; - unsigned int use_input_precision_16to8 :1; - - /* If set assume that the calculation bit depth is set by the input - * precision, not the output precision. - */ - unsigned int calculations_use_input_precision :1; - - /* If set assume that the calculations are done in 16 bits even if the sample - * depth is 8 bits. - */ - unsigned int assume_16_bit_calculations :1; - - /* Which gamma tests to run: */ - unsigned int test_gamma_threshold :1; - unsigned int test_gamma_transform :1; /* main tests */ - unsigned int test_gamma_sbit :1; - unsigned int test_gamma_scale16 :1; - unsigned int test_gamma_background :1; - unsigned int test_gamma_alpha_mode :1; - unsigned int test_gamma_expand16 :1; - unsigned int test_exhaustive :1; - - unsigned int log :1; /* Log max error */ - - /* Buffer information, the buffer size limits the size of the chunks that can - * be modified - they must fit (including header and CRC) into the buffer! - */ - size_t flush; /* Count of bytes to flush */ - size_t buffer_count; /* Bytes in buffer */ - size_t buffer_position; /* Position in buffer */ - png_byte buffer[1024]; -} png_modifier; - -/* This returns true if the test should be stopped now because it has already - * failed and it is running silently. - */ -static int fail(png_modifier *pm) -{ - return !pm->log && !pm->this.verbose && (pm->this.nerrors > 0 || - (pm->this.treat_warnings_as_errors && pm->this.nwarnings > 0)); -} - -static void -modifier_init(png_modifier *pm) -{ - memset(pm, 0, sizeof *pm); - store_init(&pm->this); - pm->modifications = NULL; - pm->state = modifier_start; - pm->sbitlow = 1U; - pm->ngammas = 0; - pm->ngamma_tests = 0; - pm->gammas = 0; - pm->current_gamma = 0; - pm->encodings = 0; - pm->nencodings = 0; - pm->current_encoding = 0; - pm->encoding_counter = 0; - pm->encoding_ignored = 0; - pm->repeat = 0; - pm->test_uses_encoding = 0; - pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0; - pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0; - pm->maxcalcG = 0; - pm->limit = 4E-3; - pm->log8 = pm->log16 = 0; /* Means 'off' */ - pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0; - pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0; - pm->error_indexed = 0; - pm->use_update_info = 0; - pm->interlace_type = PNG_INTERLACE_NONE; - pm->test_standard = 0; - pm->test_size = 0; - pm->test_transform = 0; - pm->use_input_precision = 0; - pm->use_input_precision_sbit = 0; - pm->use_input_precision_16to8 = 0; - pm->calculations_use_input_precision = 0; - pm->assume_16_bit_calculations = 0; - pm->test_gamma_threshold = 0; - pm->test_gamma_transform = 0; - pm->test_gamma_sbit = 0; - pm->test_gamma_scale16 = 0; - pm->test_gamma_background = 0; - pm->test_gamma_alpha_mode = 0; - pm->test_gamma_expand16 = 0; - pm->test_exhaustive = 0; - pm->log = 0; - - /* Rely on the memset for all the other fields - there are no pointers */ -} - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED - -/* This controls use of checks that explicitly know how libpng digitizes the - * samples in calculations; setting this circumvents simple error limit checking - * in the rgb_to_gray check, replacing it with an exact copy of the libpng 1.5 - * algorithm. - */ -#define DIGITIZE PNG_LIBPNG_VER < 10700 - -/* If pm->calculations_use_input_precision is set then operations will happen - * with the precision of the input, not the precision of the output depth. - * - * If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16 - * bit precision. This only affects those of the following limits that pertain - * to a calculation - not a digitization operation - unless the following API is - * called directly. - */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -#if DIGITIZE -static double digitize(double value, int depth, int do_round) -{ - /* 'value' is in the range 0 to 1, the result is the same value rounded to a - * multiple of the digitization factor - 8 or 16 bits depending on both the - * sample depth and the 'assume' setting. Digitization is normally by - * rounding and 'do_round' should be 1, if it is 0 the digitized value will - * be truncated. - */ - PNG_CONST unsigned int digitization_factor = (1U << depth) -1; - - /* Limiting the range is done as a convenience to the caller - it's easier to - * do it once here than every time at the call site. - */ - if (value <= 0) - value = 0; - - else if (value >= 1) - value = 1; - - value *= digitization_factor; - if (do_round) value += .5; - return floor(value)/digitization_factor; -} -#endif -#endif /* RGB_TO_GRAY */ - -#ifdef PNG_READ_GAMMA_SUPPORTED -static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) -{ - /* Absolute error permitted in linear values - affected by the bit depth of - * the calculations. - */ - if (pm->assume_16_bit_calculations || - (pm->calculations_use_input_precision ? in_depth : out_depth) == 16) - return pm->maxabs16; - else - return pm->maxabs8; -} - -static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) -{ - /* Error in the linear composition arithmetic - only relevant when - * composition actually happens (0 < alpha < 1). - */ - if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16) - return pm->maxcalc16; - else if (pm->assume_16_bit_calculations) - return pm->maxcalcG; - else - return pm->maxcalc8; -} - -static double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) -{ - /* Percentage error permitted in the linear values. Note that the specified - * value is a percentage but this routine returns a simple number. - */ - if (pm->assume_16_bit_calculations || - (pm->calculations_use_input_precision ? in_depth : out_depth) == 16) - return pm->maxpc16 * .01; - else - return pm->maxpc8 * .01; -} - -/* Output error - the error in the encoded value. This is determined by the - * digitization of the output so can be +/-0.5 in the actual output value. In - * the expand_16 case with the current code in libpng the expand happens after - * all the calculations are done in 8 bit arithmetic, so even though the output - * depth is 16 the output error is determined by the 8 bit calculation. - * - * This limit is not determined by the bit depth of internal calculations. - * - * The specified parameter does *not* include the base .5 digitization error but - * it is added here. - */ -static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) -{ - /* There is a serious error in the 2 and 4 bit grayscale transform because - * the gamma table value (8 bits) is simply shifted, not rounded, so the - * error in 4 bit grayscale gamma is up to the value below. This is a hack - * to allow pngvalid to succeed: - * - * TODO: fix this in libpng - */ - if (out_depth == 2) - return .73182-.5; - - if (out_depth == 4) - return .90644-.5; - - if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16) - return pm->maxout16; - - /* This is the case where the value was calculated at 8-bit precision then - * scaled to 16 bits. - */ - else if (out_depth == 16) - return pm->maxout8 * 257; - - else - return pm->maxout8; -} - -/* This does the same thing as the above however it returns the value to log, - * rather than raising a warning. This is useful for debugging to track down - * exactly what set of parameters cause high error values. - */ -static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth) -{ - /* The command line parameters are either 8 bit (0..255) or 16 bit (0..65535) - * and so must be adjusted for low bit depth grayscale: - */ - if (out_depth <= 8) - { - if (pm->log8 == 0) /* switched off */ - return 256; - - if (out_depth < 8) - return pm->log8 / 255 * ((1<log8; - } - - if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16) - { - if (pm->log16 == 0) - return 65536; - - return pm->log16; - } - - /* This is the case where the value was calculated at 8-bit precision then - * scaled to 16 bits. - */ - if (pm->log8 == 0) - return 65536; - - return pm->log8 * 257; -} - -/* This complements the above by providing the appropriate quantization for the - * final value. Normally this would just be quantization to an integral value, - * but in the 8 bit calculation case it's actually quantization to a multiple of - * 257! - */ -static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth, - int out_depth) -{ - if (out_depth == 16 && in_depth != 16 && - pm->calculations_use_input_precision) - return 257; - else - return 1; -} -#endif /* PNG_READ_GAMMA_SUPPORTED */ - -/* One modification structure must be provided for each chunk to be modified (in - * fact more than one can be provided if multiple separate changes are desired - * for a single chunk.) Modifications include adding a new chunk when a - * suitable chunk does not exist. - * - * The caller of modify_fn will reset the CRC of the chunk and record 'modified' - * or 'added' as appropriate if the modify_fn returns 1 (true). If the - * modify_fn is NULL the chunk is simply removed. - */ -typedef struct png_modification -{ - struct png_modification *next; - png_uint_32 chunk; - - /* If the following is NULL all matching chunks will be removed: */ - int (*modify_fn)(struct png_modifier *pm, - struct png_modification *me, int add); - - /* If the following is set to PLTE, IDAT or IEND and the chunk has not been - * found and modified (and there is a modify_fn) the modify_fn will be called - * to add the chunk before the relevant chunk. - */ - png_uint_32 add; - unsigned int modified :1; /* Chunk was modified */ - unsigned int added :1; /* Chunk was added */ - unsigned int removed :1; /* Chunk was removed */ -} png_modification; - -static void -modification_reset(png_modification *pmm) -{ - if (pmm != NULL) - { - pmm->modified = 0; - pmm->added = 0; - pmm->removed = 0; - modification_reset(pmm->next); - } -} - -static void -modification_init(png_modification *pmm) -{ - memset(pmm, 0, sizeof *pmm); - pmm->next = NULL; - pmm->chunk = 0; - pmm->modify_fn = NULL; - pmm->add = 0; - modification_reset(pmm); -} - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -static void -modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce) -{ - if (pm->current_encoding != 0) - *ce = *pm->current_encoding; - - else - memset(ce, 0, sizeof *ce); - - ce->gamma = pm->current_gamma; -} -#endif - -static size_t -safecat_current_encoding(char *buffer, size_t bufsize, size_t pos, - PNG_CONST png_modifier *pm) -{ - pos = safecat_color_encoding(buffer, bufsize, pos, pm->current_encoding, - pm->current_gamma); - - if (pm->encoding_ignored) - pos = safecat(buffer, bufsize, pos, "[overridden]"); - - return pos; -} - -/* Iterate through the usefully testable color encodings. An encoding is one - * of: - * - * 1) Nothing (no color space, no gamma). - * 2) Just a gamma value from the gamma array (including 1.0) - * 3) A color space from the encodings array with the corresponding gamma. - * 4) The same, but with gamma 1.0 (only really useful with 16 bit calculations) - * - * The iterator selects these in turn, the randomizer selects one at random, - * which is used depends on the setting of the 'test_exhaustive' flag. Notice - * that this function changes the colour space encoding so it must only be - * called on completion of the previous test. This is what 'modifier_reset' - * does, below. - * - * After the function has been called the 'repeat' flag will still be set; the - * caller of modifier_reset must reset it at the start of each run of the test! - */ -static unsigned int -modifier_total_encodings(PNG_CONST png_modifier *pm) -{ - return 1 + /* (1) nothing */ - pm->ngammas + /* (2) gamma values to test */ - pm->nencodings + /* (3) total number of encodings */ - /* The following test only works after the first time through the - * png_modifier code because 'bit_depth' is set when the IHDR is read. - * modifier_reset, below, preserves the setting until after it has called - * the iterate function (also below.) - * - * For this reason do not rely on this function outside a call to - * modifier_reset. - */ - ((pm->bit_depth == 16 || pm->assume_16_bit_calculations) ? - pm->nencodings : 0); /* (4) encodings with gamma == 1.0 */ -} - -static void -modifier_encoding_iterate(png_modifier *pm) -{ - if (!pm->repeat && /* Else something needs the current encoding again. */ - pm->test_uses_encoding) /* Some transform is encoding dependent */ - { - if (pm->test_exhaustive) - { - if (++pm->encoding_counter >= modifier_total_encodings(pm)) - pm->encoding_counter = 0; /* This will stop the repeat */ - } - - else - { - /* Not exhaustive - choose an encoding at random; generate a number in - * the range 1..(max-1), so the result is always non-zero: - */ - if (pm->encoding_counter == 0) - pm->encoding_counter = random_mod(modifier_total_encodings(pm)-1)+1; - else - pm->encoding_counter = 0; - } - - if (pm->encoding_counter > 0) - pm->repeat = 1; - } - - else if (!pm->repeat) - pm->encoding_counter = 0; -} - -static void -modifier_reset(png_modifier *pm) -{ - store_read_reset(&pm->this); - pm->limit = 4E-3; - pm->pending_len = pm->pending_chunk = 0; - pm->flush = pm->buffer_count = pm->buffer_position = 0; - pm->modifications = NULL; - pm->state = modifier_start; - modifier_encoding_iterate(pm); - /* The following must be set in the next run. In particular - * test_uses_encodings must be set in the _ini function of each transform - * that looks at the encodings. (Not the 'add' function!) - */ - pm->test_uses_encoding = 0; - pm->current_gamma = 0; - pm->current_encoding = 0; - pm->encoding_ignored = 0; - /* These only become value after IHDR is read: */ - pm->bit_depth = pm->colour_type = 0; -} - -/* The following must be called before anything else to get the encoding set up - * on the modifier. In particular it must be called before the transform init - * functions are called. - */ -static void -modifier_set_encoding(png_modifier *pm) -{ - /* Set the encoding to the one specified by the current encoding counter, - * first clear out all the settings - this corresponds to an encoding_counter - * of 0. - */ - pm->current_gamma = 0; - pm->current_encoding = 0; - pm->encoding_ignored = 0; /* not ignored yet - happens in _ini functions. */ - - /* Now, if required, set the gamma and encoding fields. */ - if (pm->encoding_counter > 0) - { - /* The gammas[] array is an array of screen gammas, not encoding gammas, - * so we need the inverse: - */ - if (pm->encoding_counter <= pm->ngammas) - pm->current_gamma = 1/pm->gammas[pm->encoding_counter-1]; - - else - { - unsigned int i = pm->encoding_counter - pm->ngammas; - - if (i >= pm->nencodings) - { - i %= pm->nencodings; - pm->current_gamma = 1; /* Linear, only in the 16 bit case */ - } - - else - pm->current_gamma = pm->encodings[i].gamma; - - pm->current_encoding = pm->encodings + i; - } - } -} - -/* Enquiry functions to find out what is set. Notice that there is an implicit - * assumption below that the first encoding in the list is the one for sRGB. - */ -static int -modifier_color_encoding_is_sRGB(PNG_CONST png_modifier *pm) -{ - return pm->current_encoding != 0 && pm->current_encoding == pm->encodings && - pm->current_encoding->gamma == pm->current_gamma; -} - -static int -modifier_color_encoding_is_set(PNG_CONST png_modifier *pm) -{ - return pm->current_gamma != 0; -} - -/* Convenience macros. */ -#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) -#define CHUNK_IHDR CHUNK(73,72,68,82) -#define CHUNK_PLTE CHUNK(80,76,84,69) -#define CHUNK_IDAT CHUNK(73,68,65,84) -#define CHUNK_IEND CHUNK(73,69,78,68) -#define CHUNK_cHRM CHUNK(99,72,82,77) -#define CHUNK_gAMA CHUNK(103,65,77,65) -#define CHUNK_sBIT CHUNK(115,66,73,84) -#define CHUNK_sRGB CHUNK(115,82,71,66) - -/* The guts of modification are performed during a read. */ -static void -modifier_crc(png_bytep buffer) -{ - /* Recalculate the chunk CRC - a complete chunk must be in - * the buffer, at the start. - */ - uInt datalen = png_get_uint_32(buffer); - uLong crc = crc32(0, buffer+4, datalen+4); - /* The cast to png_uint_32 is safe because a crc32 is always a 32 bit value. - */ - png_save_uint_32(buffer+datalen+8, (png_uint_32)crc); -} - -static void -modifier_setbuffer(png_modifier *pm) -{ - modifier_crc(pm->buffer); - pm->buffer_count = png_get_uint_32(pm->buffer)+12; - pm->buffer_position = 0; -} - -/* Separate the callback into the actual implementation (which is passed the - * png_modifier explicitly) and the callback, which gets the modifier from the - * png_struct. - */ -static void -modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st) -{ - while (st > 0) - { - size_t cb; - png_uint_32 len, chunk; - png_modification *mod; - - if (pm->buffer_position >= pm->buffer_count) switch (pm->state) - { - static png_byte sign[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; - case modifier_start: - store_read_imp(&pm->this, pm->buffer, 8); /* size of signature. */ - pm->buffer_count = 8; - pm->buffer_position = 0; - - if (memcmp(pm->buffer, sign, 8) != 0) - png_error(pm->this.pread, "invalid PNG file signature"); - pm->state = modifier_signature; - break; - - case modifier_signature: - store_read_imp(&pm->this, pm->buffer, 13+12); /* size of IHDR */ - pm->buffer_count = 13+12; - pm->buffer_position = 0; - - if (png_get_uint_32(pm->buffer) != 13 || - png_get_uint_32(pm->buffer+4) != CHUNK_IHDR) - png_error(pm->this.pread, "invalid IHDR"); - - /* Check the list of modifiers for modifications to the IHDR. */ - mod = pm->modifications; - while (mod != NULL) - { - if (mod->chunk == CHUNK_IHDR && mod->modify_fn && - (*mod->modify_fn)(pm, mod, 0)) - { - mod->modified = 1; - modifier_setbuffer(pm); - } - - /* Ignore removal or add if IHDR! */ - mod = mod->next; - } - - /* Cache information from the IHDR (the modified one.) */ - pm->bit_depth = pm->buffer[8+8]; - pm->colour_type = pm->buffer[8+8+1]; - - pm->state = modifier_IHDR; - pm->flush = 0; - break; - - case modifier_IHDR: - default: - /* Read a new chunk and process it until we see PLTE, IDAT or - * IEND. 'flush' indicates that there is still some data to - * output from the preceding chunk. - */ - if ((cb = pm->flush) > 0) - { - if (cb > st) cb = st; - pm->flush -= cb; - store_read_imp(&pm->this, pb, cb); - pb += cb; - st -= cb; - if (st == 0) return; - } - - /* No more bytes to flush, read a header, or handle a pending - * chunk. - */ - if (pm->pending_chunk != 0) - { - png_save_uint_32(pm->buffer, pm->pending_len); - png_save_uint_32(pm->buffer+4, pm->pending_chunk); - pm->pending_len = 0; - pm->pending_chunk = 0; - } - else - store_read_imp(&pm->this, pm->buffer, 8); - - pm->buffer_count = 8; - pm->buffer_position = 0; - - /* Check for something to modify or a terminator chunk. */ - len = png_get_uint_32(pm->buffer); - chunk = png_get_uint_32(pm->buffer+4); - - /* Terminators first, they may have to be delayed for added - * chunks - */ - if (chunk == CHUNK_PLTE || chunk == CHUNK_IDAT || - chunk == CHUNK_IEND) - { - mod = pm->modifications; - - while (mod != NULL) - { - if ((mod->add == chunk || - (mod->add == CHUNK_PLTE && chunk == CHUNK_IDAT)) && - mod->modify_fn != NULL && !mod->modified && !mod->added) - { - /* Regardless of what the modify function does do not run - * this again. - */ - mod->added = 1; - - if ((*mod->modify_fn)(pm, mod, 1 /*add*/)) - { - /* Reset the CRC on a new chunk */ - if (pm->buffer_count > 0) - modifier_setbuffer(pm); - - else - { - pm->buffer_position = 0; - mod->removed = 1; - } - - /* The buffer has been filled with something (we assume) - * so output this. Pend the current chunk. - */ - pm->pending_len = len; - pm->pending_chunk = chunk; - break; /* out of while */ - } - } - - mod = mod->next; - } - - /* Don't do any further processing if the buffer was modified - - * otherwise the code will end up modifying a chunk that was - * just added. - */ - if (mod != NULL) - break; /* out of switch */ - } - - /* If we get to here then this chunk may need to be modified. To - * do this it must be less than 1024 bytes in total size, otherwise - * it just gets flushed. - */ - if (len+12 <= sizeof pm->buffer) - { - store_read_imp(&pm->this, pm->buffer+pm->buffer_count, - len+12-pm->buffer_count); - pm->buffer_count = len+12; - - /* Check for a modification, else leave it be. */ - mod = pm->modifications; - while (mod != NULL) - { - if (mod->chunk == chunk) - { - if (mod->modify_fn == NULL) - { - /* Remove this chunk */ - pm->buffer_count = pm->buffer_position = 0; - mod->removed = 1; - break; /* Terminate the while loop */ - } - - else if ((*mod->modify_fn)(pm, mod, 0)) - { - mod->modified = 1; - /* The chunk may have been removed: */ - if (pm->buffer_count == 0) - { - pm->buffer_position = 0; - break; - } - modifier_setbuffer(pm); - } - } - - mod = mod->next; - } - } - - else - pm->flush = len+12 - pm->buffer_count; /* data + crc */ - - /* Take the data from the buffer (if there is any). */ - break; - } - - /* Here to read from the modifier buffer (not directly from - * the store, as in the flush case above.) - */ - cb = pm->buffer_count - pm->buffer_position; - - if (cb > st) - cb = st; - - memcpy(pb, pm->buffer + pm->buffer_position, cb); - st -= cb; - pb += cb; - pm->buffer_position += cb; - } -} - -/* The callback: */ -static void PNGCBAPI -modifier_read(png_structp ppIn, png_bytep pb, png_size_t st) -{ - png_const_structp pp = ppIn; - png_modifier *pm = voidcast(png_modifier*, png_get_io_ptr(pp)); - - if (pm == NULL || pm->this.pread != pp) - png_error(pp, "bad modifier_read call"); - - modifier_read_imp(pm, pb, st); -} - -/* Like store_progressive_read but the data is getting changed as we go so we - * need a local buffer. - */ -static void -modifier_progressive_read(png_modifier *pm, png_structp pp, png_infop pi) -{ - if (pm->this.pread != pp || pm->this.current == NULL || - pm->this.next == NULL) - png_error(pp, "store state damaged (progressive)"); - - /* This is another Horowitz and Hill random noise generator. In this case - * the aim is to stress the progressive reader with truly horrible variable - * buffer sizes in the range 1..500, so a sequence of 9 bit random numbers - * is generated. We could probably just count from 1 to 32767 and get as - * good a result. - */ - for (;;) - { - static png_uint_32 noise = 1; - png_size_t cb, cbAvail; - png_byte buffer[512]; - - /* Generate 15 more bits of stuff: */ - noise = (noise << 9) | ((noise ^ (noise >> (9-5))) & 0x1ff); - cb = noise & 0x1ff; - - /* Check that this number of bytes are available (in the current buffer.) - * (This doesn't quite work - the modifier might delete a chunk; unlikely - * but possible, it doesn't happen at present because the modifier only - * adds chunks to standard images.) - */ - cbAvail = store_read_buffer_avail(&pm->this); - if (pm->buffer_count > pm->buffer_position) - cbAvail += pm->buffer_count - pm->buffer_position; - - if (cb > cbAvail) - { - /* Check for EOF: */ - if (cbAvail == 0) - break; - - cb = cbAvail; - } - - modifier_read_imp(pm, buffer, cb); - png_process_data(pp, pi, buffer, cb); - } - - /* Check the invariants at the end (if this fails it's a problem in this - * file!) - */ - if (pm->buffer_count > pm->buffer_position || - pm->this.next != &pm->this.current->data || - pm->this.readpos < pm->this.current->datacount) - png_error(pp, "progressive read implementation error"); -} - -/* Set up a modifier. */ -static png_structp -set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id, - PNG_CONST char *name) -{ - /* Do this first so that the modifier fields are cleared even if an error - * happens allocating the png_struct. No allocation is done here so no - * cleanup is required. - */ - pm->state = modifier_start; - pm->bit_depth = 0; - pm->colour_type = 255; - - pm->pending_len = 0; - pm->pending_chunk = 0; - pm->flush = 0; - pm->buffer_count = 0; - pm->buffer_position = 0; - - return set_store_for_read(&pm->this, ppi, id, name); -} - - -/******************************** MODIFICATIONS *******************************/ -/* Standard modifications to add chunks. These do not require the _SUPPORTED - * macros because the chunks can be there regardless of whether this specific - * libpng supports them. - */ -typedef struct gama_modification -{ - png_modification this; - png_fixed_point gamma; -} gama_modification; - -static int -gama_modify(png_modifier *pm, png_modification *me, int add) -{ - UNUSED(add) - /* This simply dumps the given gamma value into the buffer. */ - png_save_uint_32(pm->buffer, 4); - png_save_uint_32(pm->buffer+4, CHUNK_gAMA); - png_save_uint_32(pm->buffer+8, ((gama_modification*)me)->gamma); - return 1; -} - -static void -gama_modification_init(gama_modification *me, png_modifier *pm, double gammad) -{ - double g; - - modification_init(&me->this); - me->this.chunk = CHUNK_gAMA; - me->this.modify_fn = gama_modify; - me->this.add = CHUNK_PLTE; - g = fix(gammad); - me->gamma = (png_fixed_point)g; - me->this.next = pm->modifications; - pm->modifications = &me->this; -} - -typedef struct chrm_modification -{ - png_modification this; - PNG_CONST color_encoding *encoding; - png_fixed_point wx, wy, rx, ry, gx, gy, bx, by; -} chrm_modification; - -static int -chrm_modify(png_modifier *pm, png_modification *me, int add) -{ - UNUSED(add) - /* As with gAMA this just adds the required cHRM chunk to the buffer. */ - png_save_uint_32(pm->buffer , 32); - png_save_uint_32(pm->buffer+ 4, CHUNK_cHRM); - png_save_uint_32(pm->buffer+ 8, ((chrm_modification*)me)->wx); - png_save_uint_32(pm->buffer+12, ((chrm_modification*)me)->wy); - png_save_uint_32(pm->buffer+16, ((chrm_modification*)me)->rx); - png_save_uint_32(pm->buffer+20, ((chrm_modification*)me)->ry); - png_save_uint_32(pm->buffer+24, ((chrm_modification*)me)->gx); - png_save_uint_32(pm->buffer+28, ((chrm_modification*)me)->gy); - png_save_uint_32(pm->buffer+32, ((chrm_modification*)me)->bx); - png_save_uint_32(pm->buffer+36, ((chrm_modification*)me)->by); - return 1; -} - -static void -chrm_modification_init(chrm_modification *me, png_modifier *pm, - PNG_CONST color_encoding *encoding) -{ - CIE_color white = white_point(encoding); - - /* Original end points: */ - me->encoding = encoding; - - /* Chromaticities (in fixed point): */ - me->wx = fix(chromaticity_x(white)); - me->wy = fix(chromaticity_y(white)); - - me->rx = fix(chromaticity_x(encoding->red)); - me->ry = fix(chromaticity_y(encoding->red)); - me->gx = fix(chromaticity_x(encoding->green)); - me->gy = fix(chromaticity_y(encoding->green)); - me->bx = fix(chromaticity_x(encoding->blue)); - me->by = fix(chromaticity_y(encoding->blue)); - - modification_init(&me->this); - me->this.chunk = CHUNK_cHRM; - me->this.modify_fn = chrm_modify; - me->this.add = CHUNK_PLTE; - me->this.next = pm->modifications; - pm->modifications = &me->this; -} - -typedef struct srgb_modification -{ - png_modification this; - png_byte intent; -} srgb_modification; - -static int -srgb_modify(png_modifier *pm, png_modification *me, int add) -{ - UNUSED(add) - /* As above, ignore add and just make a new chunk */ - png_save_uint_32(pm->buffer, 1); - png_save_uint_32(pm->buffer+4, CHUNK_sRGB); - pm->buffer[8] = ((srgb_modification*)me)->intent; - return 1; -} - -static void -srgb_modification_init(srgb_modification *me, png_modifier *pm, png_byte intent) -{ - modification_init(&me->this); - me->this.chunk = CHUNK_sBIT; - - if (intent <= 3) /* if valid, else *delete* sRGB chunks */ - { - me->this.modify_fn = srgb_modify; - me->this.add = CHUNK_PLTE; - me->intent = intent; - } - - else - { - me->this.modify_fn = 0; - me->this.add = 0; - me->intent = 0; - } - - me->this.next = pm->modifications; - pm->modifications = &me->this; -} - -#ifdef PNG_READ_GAMMA_SUPPORTED -typedef struct sbit_modification -{ - png_modification this; - png_byte sbit; -} sbit_modification; - -static int -sbit_modify(png_modifier *pm, png_modification *me, int add) -{ - png_byte sbit = ((sbit_modification*)me)->sbit; - if (pm->bit_depth > sbit) - { - int cb = 0; - switch (pm->colour_type) - { - case 0: - cb = 1; - break; - - case 2: - case 3: - cb = 3; - break; - - case 4: - cb = 2; - break; - - case 6: - cb = 4; - break; - - default: - png_error(pm->this.pread, - "unexpected colour type in sBIT modification"); - } - - png_save_uint_32(pm->buffer, cb); - png_save_uint_32(pm->buffer+4, CHUNK_sBIT); - - while (cb > 0) - (pm->buffer+8)[--cb] = sbit; - - return 1; - } - else if (!add) - { - /* Remove the sBIT chunk */ - pm->buffer_count = pm->buffer_position = 0; - return 1; - } - else - return 0; /* do nothing */ -} - -static void -sbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit) -{ - modification_init(&me->this); - me->this.chunk = CHUNK_sBIT; - me->this.modify_fn = sbit_modify; - me->this.add = CHUNK_PLTE; - me->sbit = sbit; - me->this.next = pm->modifications; - pm->modifications = &me->this; -} -#endif /* PNG_READ_GAMMA_SUPPORTED */ -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -/***************************** STANDARD PNG FILES *****************************/ -/* Standard files - write and save standard files. */ -/* There are two basic forms of standard images. Those which attempt to have - * all the possible pixel values (not possible for 16bpp images, but a range of - * values are produced) and those which have a range of image sizes. The former - * are used for testing transforms, in particular gamma correction and bit - * reduction and increase. The latter are reserved for testing the behavior of - * libpng with respect to 'odd' image sizes - particularly small images where - * rows become 1 byte and interlace passes disappear. - * - * The first, most useful, set are the 'transform' images, the second set of - * small images are the 'size' images. - * - * The transform files are constructed with rows which fit into a 1024 byte row - * buffer. This makes allocation easier below. Further regardless of the file - * format every row has 128 pixels (giving 1024 bytes for 64bpp formats). - * - * Files are stored with no gAMA or sBIT chunks, with a PLTE only when needed - * and with an ID derived from the colour type, bit depth and interlace type - * as above (FILEID). The width (128) and height (variable) are not stored in - * the FILEID - instead the fields are set to 0, indicating a transform file. - * - * The size files ar constructed with rows a maximum of 128 bytes wide, allowing - * a maximum width of 16 pixels (for the 64bpp case.) They also have a maximum - * height of 16 rows. The width and height are stored in the FILEID and, being - * non-zero, indicate a size file. - * - * Because the PNG filter code is typically the largest CPU consumer within - * libpng itself there is a tendency to attempt to optimize it. This results in - * special case code which needs to be validated. To cause this to happen the - * 'size' images are made to use each possible filter, in so far as this is - * possible for smaller images. - * - * For palette image (colour type 3) multiple transform images are stored with - * the same bit depth to allow testing of more colour combinations - - * particularly important for testing the gamma code because libpng uses a - * different code path for palette images. For size images a single palette is - * used. - */ - -/* Make a 'standard' palette. Because there are only 256 entries in a palette - * (maximum) this actually makes a random palette in the hope that enough tests - * will catch enough errors. (Note that the same palette isn't produced every - * time for the same test - it depends on what previous tests have been run - - * but a given set of arguments to pngvalid will always produce the same palette - * at the same test! This is why pseudo-random number generators are useful for - * testing.) - * - * The store must be open for write when this is called, otherwise an internal - * error will occur. This routine contains its own magic number seed, so the - * palettes generated don't change if there are intervening errors (changing the - * calls to the store_mark seed.) - */ -static store_palette_entry * -make_standard_palette(png_store* ps, int npalette, int do_tRNS) -{ - static png_uint_32 palette_seed[2] = { 0x87654321, 9 }; - - int i = 0; - png_byte values[256][4]; - - /* Always put in black and white plus the six primary and secondary colors. - */ - for (; i<8; ++i) - { - values[i][1] = (png_byte)((i&1) ? 255U : 0U); - values[i][2] = (png_byte)((i&2) ? 255U : 0U); - values[i][3] = (png_byte)((i&4) ? 255U : 0U); - } - - /* Then add 62 grays (one quarter of the remaining 256 slots). */ - { - int j = 0; - png_byte random_bytes[4]; - png_byte need[256]; - - need[0] = 0; /*got black*/ - memset(need+1, 1, (sizeof need)-2); /*need these*/ - need[255] = 0; /*but not white*/ - - while (i<70) - { - png_byte b; - - if (j==0) - { - make_four_random_bytes(palette_seed, random_bytes); - j = 4; - } - - b = random_bytes[--j]; - if (need[b]) - { - values[i][1] = b; - values[i][2] = b; - values[i++][3] = b; - } - } - } - - /* Finally add 192 colors at random - don't worry about matches to things we - * already have, chance is less than 1/65536. Don't worry about grays, - * chance is the same, so we get a duplicate or extra gray less than 1 time - * in 170. - */ - for (; i<256; ++i) - make_four_random_bytes(palette_seed, values[i]); - - /* Fill in the alpha values in the first byte. Just use all possible values - * (0..255) in an apparently random order: - */ - { - store_palette_entry *palette; - png_byte selector[4]; - - make_four_random_bytes(palette_seed, selector); - - if (do_tRNS) - for (i=0; i<256; ++i) - values[i][0] = (png_byte)(i ^ selector[0]); - - else - for (i=0; i<256; ++i) - values[i][0] = 255; /* no transparency/tRNS chunk */ - - /* 'values' contains 256 ARGB values, but we only need 'npalette'. - * 'npalette' will always be a power of 2: 2, 4, 16 or 256. In the low - * bit depth cases select colors at random, else it is difficult to have - * a set of low bit depth palette test with any chance of a reasonable - * range of colors. Do this by randomly permuting values into the low - * 'npalette' entries using an XOR mask generated here. This also - * permutes the npalette == 256 case in a potentially useful way (there is - * no relationship between palette index and the color value therein!) - */ - palette = store_write_palette(ps, npalette); - - for (i=0; i 0) - png_set_tRNS(pp, pi, tRNS, j, 0/*color*/); -# endif - } -} - -/* The number of passes is related to the interlace type. There was no libpng - * API to determine this prior to 1.5, so we need an inquiry function: - */ -static int -npasses_from_interlace_type(png_const_structp pp, int interlace_type) -{ - switch (interlace_type) - { - default: - png_error(pp, "invalid interlace type"); - - case PNG_INTERLACE_NONE: - return 1; - - case PNG_INTERLACE_ADAM7: - return PNG_INTERLACE_ADAM7_PASSES; - } -} - -static unsigned int -bit_size(png_const_structp pp, png_byte colour_type, png_byte bit_depth) -{ - switch (colour_type) - { - default: png_error(pp, "invalid color type"); - - case 0: return bit_depth; - - case 2: return 3*bit_depth; - - case 3: return bit_depth; - - case 4: return 2*bit_depth; - - case 6: return 4*bit_depth; - } -} - -#define TRANSFORM_WIDTH 128U -#define TRANSFORM_ROWMAX (TRANSFORM_WIDTH*8U) -#define SIZE_ROWMAX (16*8U) /* 16 pixels, max 8 bytes each - 128 bytes */ -#define STANDARD_ROWMAX TRANSFORM_ROWMAX /* The larger of the two */ -#define SIZE_HEIGHTMAX 16 /* Maximum range of size images */ - -static size_t -transform_rowsize(png_const_structp pp, png_byte colour_type, - png_byte bit_depth) -{ - return (TRANSFORM_WIDTH * bit_size(pp, colour_type, bit_depth)) / 8; -} - -/* transform_width(pp, colour_type, bit_depth) current returns the same number - * every time, so just use a macro: - */ -#define transform_width(pp, colour_type, bit_depth) TRANSFORM_WIDTH - -static png_uint_32 -transform_height(png_const_structp pp, png_byte colour_type, png_byte bit_depth) -{ - switch (bit_size(pp, colour_type, bit_depth)) - { - case 1: - case 2: - case 4: - return 1; /* Total of 128 pixels */ - - case 8: - return 2; /* Total of 256 pixels/bytes */ - - case 16: - return 512; /* Total of 65536 pixels */ - - case 24: - case 32: - return 512; /* 65536 pixels */ - - case 48: - case 64: - return 2048;/* 4 x 65536 pixels. */ -# define TRANSFORM_HEIGHTMAX 2048 - - default: - return 0; /* Error, will be caught later */ - } -} - -#ifdef PNG_READ_SUPPORTED -/* The following can only be defined here, now we have the definitions - * of the transform image sizes. - */ -static png_uint_32 -standard_width(png_const_structp pp, png_uint_32 id) -{ - png_uint_32 width = WIDTH_FROM_ID(id); - UNUSED(pp) - - if (width == 0) - width = transform_width(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); - - return width; -} - -static png_uint_32 -standard_height(png_const_structp pp, png_uint_32 id) -{ - png_uint_32 height = HEIGHT_FROM_ID(id); - - if (height == 0) - height = transform_height(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); - - return height; -} - -static png_uint_32 -standard_rowsize(png_const_structp pp, png_uint_32 id) -{ - png_uint_32 width = standard_width(pp, id); - - /* This won't overflow: */ - width *= bit_size(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); - return (width + 7) / 8; -} -#endif /* PNG_READ_SUPPORTED */ - -static void -transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], - png_byte colour_type, png_byte bit_depth, png_uint_32 y) -{ - png_uint_32 v = y << 7; - png_uint_32 i = 0; - - switch (bit_size(pp, colour_type, bit_depth)) - { - case 1: - while (i<128/8) buffer[i] = (png_byte)(v & 0xff), v += 17, ++i; - return; - - case 2: - while (i<128/4) buffer[i] = (png_byte)(v & 0xff), v += 33, ++i; - return; - - case 4: - while (i<128/2) buffer[i] = (png_byte)(v & 0xff), v += 65, ++i; - return; - - case 8: - /* 256 bytes total, 128 bytes in each row set as follows: */ - while (i<128) buffer[i] = (png_byte)(v & 0xff), ++v, ++i; - return; - - case 16: - /* Generate all 65536 pixel values in order, which includes the 8 bit - * GA case as well as the 16 bit G case. - */ - while (i<128) - { - buffer[2*i] = (png_byte)((v>>8) & 0xff); - buffer[2*i+1] = (png_byte)(v & 0xff); - ++v; - ++i; - } - - return; - - case 24: - /* 65535 pixels, but rotate the values. */ - while (i<128) - { - /* Three bytes per pixel, r, g, b, make b by r^g */ - buffer[3*i+0] = (png_byte)((v >> 8) & 0xff); - buffer[3*i+1] = (png_byte)(v & 0xff); - buffer[3*i+2] = (png_byte)(((v >> 8) ^ v) & 0xff); - ++v; - ++i; - } - - return; - - case 32: - /* 65535 pixels, r, g, b, a; just replicate */ - while (i<128) - { - buffer[4*i+0] = (png_byte)((v >> 8) & 0xff); - buffer[4*i+1] = (png_byte)(v & 0xff); - buffer[4*i+2] = (png_byte)((v >> 8) & 0xff); - buffer[4*i+3] = (png_byte)(v & 0xff); - ++v; - ++i; - } - - return; - - case 48: - /* y is maximum 2047, giving 4x65536 pixels, make 'r' increase by 1 at - * each pixel, g increase by 257 (0x101) and 'b' by 0x1111: - */ - while (i<128) - { - png_uint_32 t = v++; - buffer[6*i+0] = (png_byte)((t >> 8) & 0xff); - buffer[6*i+1] = (png_byte)(t & 0xff); - t *= 257; - buffer[6*i+2] = (png_byte)((t >> 8) & 0xff); - buffer[6*i+3] = (png_byte)(t & 0xff); - t *= 17; - buffer[6*i+4] = (png_byte)((t >> 8) & 0xff); - buffer[6*i+5] = (png_byte)(t & 0xff); - ++i; - } - - return; - - case 64: - /* As above in the 32 bit case. */ - while (i<128) - { - png_uint_32 t = v++; - buffer[8*i+0] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+1] = (png_byte)(t & 0xff); - buffer[8*i+4] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+5] = (png_byte)(t & 0xff); - t *= 257; - buffer[8*i+2] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+3] = (png_byte)(t & 0xff); - buffer[8*i+6] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+7] = (png_byte)(t & 0xff); - ++i; - } - return; - - default: - break; - } - - png_error(pp, "internal error"); -} - -/* This is just to do the right cast - could be changed to a function to check - * 'bd' but there isn't much point. - */ -#define DEPTH(bd) ((png_byte)(1U << (bd))) - -/* This is just a helper for compiling on minimal systems with no write - * interlacing support. If there is no write interlacing we can't generate test - * cases with interlace: - */ -#ifdef PNG_WRITE_INTERLACING_SUPPORTED -# define INTERLACE_LAST PNG_INTERLACE_LAST -# define check_interlace_type(type) ((void)(type)) -#else -# define INTERLACE_LAST (PNG_INTERLACE_NONE+1) -# define png_set_interlace_handling(a) (1) - -static void -check_interlace_type(int PNG_CONST interlace_type) -{ - if (interlace_type != PNG_INTERLACE_NONE) - { - /* This is an internal error - --interlace tests should be skipped, not - * attempted. - */ - fprintf(stderr, "pngvalid: no interlace support\n"); - exit(99); - } -} -#endif - -/* Make a standardized image given a an image colour type, bit depth and - * interlace type. The standard images have a very restricted range of - * rows and heights and are used for testing transforms rather than image - * layout details. See make_size_images below for a way to make images - * that test odd sizes along with the libpng interlace handling. - */ -static void -make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, - png_byte PNG_CONST bit_depth, unsigned int palette_number, - int interlace_type, png_const_charp name) -{ - context(ps, fault); - - check_interlace_type(interlace_type); - - Try - { - png_infop pi; - png_structp pp = set_store_for_write(ps, &pi, name); - png_uint_32 h; - - /* In the event of a problem return control to the Catch statement below - * to do the clean up - it is not possible to 'return' directly from a Try - * block. - */ - if (pp == NULL) - Throw ps; - - h = transform_height(pp, colour_type, bit_depth); - - png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), h, - bit_depth, colour_type, interlace_type, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - -#ifdef PNG_TEXT_SUPPORTED -# if defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED) -# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_zTXt -# else -# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_NONE -# endif - { - static char key[] = "image name"; /* must be writeable */ - size_t pos; - png_text text; - char copy[FILE_NAME_SIZE]; - - /* Use a compressed text string to test the correct interaction of text - * compression and IDAT compression. - */ - text.compression = TEXT_COMPRESSION; - text.key = key; - /* Yuck: the text must be writable! */ - pos = safecat(copy, sizeof copy, 0, ps->wname); - text.text = copy; - text.text_length = pos; - text.itxt_length = 0; - text.lang = 0; - text.lang_key = 0; - - png_set_text(pp, pi, &text, 1); - } -#endif - - if (colour_type == 3) /* palette */ - init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/); - - png_write_info(pp, pi); - - if (png_get_rowbytes(pp, pi) != - transform_rowsize(pp, colour_type, bit_depth)) - png_error(pp, "row size incorrect"); - - else - { - /* Somewhat confusingly this must be called *after* png_write_info - * because if it is called before, the information in *pp has not been - * updated to reflect the interlaced image. - */ - int npasses = png_set_interlace_handling(pp); - int pass; - - if (npasses != npasses_from_interlace_type(pp, interlace_type)) - png_error(pp, "write: png_set_interlace_handling failed"); - - for (pass=0; passtest, sizeof ps->test, 0, "make standard images"); - - /* Use next_format to enumerate all the combinations we test, including - * generating multiple low bit depth palette images. - */ - while (next_format(&colour_type, &bit_depth, &palette_number, 0)) - { - int interlace_type; - - for (interlace_type = PNG_INTERLACE_NONE; - interlace_type < INTERLACE_LAST; ++interlace_type) - { - char name[FILE_NAME_SIZE]; - - standard_name(name, sizeof name, 0, colour_type, bit_depth, - palette_number, interlace_type, 0, 0, 0); - make_transform_image(ps, colour_type, bit_depth, palette_number, - interlace_type, name); - } - } -} - -/* The following two routines use the PNG interlace support macros from - * png.h to interlace or deinterlace rows. - */ -static void -interlace_row(png_bytep buffer, png_const_bytep imageRow, - unsigned int pixel_size, png_uint_32 w, int pass) -{ - png_uint_32 xin, xout, xstep; - - /* Note that this can, trivially, be optimized to a memcpy on pass 7, the - * code is presented this way to make it easier to understand. In practice - * consult the code in the libpng source to see other ways of doing this. - */ - xin = PNG_PASS_START_COL(pass); - xstep = 1U<= 8) - *buffer++ = (png_byte)y++, bit_width -= 8; - - /* There may be up to 7 remaining bits, these go in the most significant - * bits of the byte. - */ - if (bit_width > 0) - { - png_uint_32 mask = (1U<<(8-bit_width))-1; - *buffer = (png_byte)((*buffer & mask) | (y & ~mask)); - } -} - -static void -make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, - png_byte PNG_CONST bit_depth, int PNG_CONST interlace_type, - png_uint_32 PNG_CONST w, png_uint_32 PNG_CONST h, - int PNG_CONST do_interlace) -{ - context(ps, fault); - - /* At present libpng does not support the write of an interlaced image unless - * PNG_WRITE_INTERLACING_SUPPORTED, even with do_interlace so the code here - * does the pixel interlace itself, so: - */ - check_interlace_type(interlace_type); - - Try - { - png_infop pi; - png_structp pp; - unsigned int pixel_size; - - /* Make a name and get an appropriate id for the store: */ - char name[FILE_NAME_SIZE]; - PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/, - interlace_type, w, h, do_interlace); - - standard_name_from_id(name, sizeof name, 0, id); - pp = set_store_for_write(ps, &pi, name); - - /* In the event of a problem return control to the Catch statement below - * to do the clean up - it is not possible to 'return' directly from a Try - * block. - */ - if (pp == NULL) - Throw ps; - - png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - -#ifdef PNG_TEXT_SUPPORTED - { - static char key[] = "image name"; /* must be writeable */ - size_t pos; - png_text text; - char copy[FILE_NAME_SIZE]; - - /* Use a compressed text string to test the correct interaction of text - * compression and IDAT compression. - */ - text.compression = TEXT_COMPRESSION; - text.key = key; - /* Yuck: the text must be writable! */ - pos = safecat(copy, sizeof copy, 0, ps->wname); - text.text = copy; - text.text_length = pos; - text.itxt_length = 0; - text.lang = 0; - text.lang_key = 0; - - png_set_text(pp, pi, &text, 1); - } -#endif - - if (colour_type == 3) /* palette */ - init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); - - png_write_info(pp, pi); - - /* Calculate the bit size, divide by 8 to get the byte size - this won't - * overflow because we know the w values are all small enough even for - * a system where 'unsigned int' is only 16 bits. - */ - pixel_size = bit_size(pp, colour_type, bit_depth); - if (png_get_rowbytes(pp, pi) != ((w * pixel_size) + 7) / 8) - png_error(pp, "row size incorrect"); - - else - { - int npasses = npasses_from_interlace_type(pp, interlace_type); - png_uint_32 y; - int pass; -# ifdef PNG_WRITE_FILTER_SUPPORTED - int nfilter = PNG_FILTER_VALUE_LAST; -# endif - png_byte image[16][SIZE_ROWMAX]; - - /* To help consistent error detection make the parts of this buffer - * that aren't set below all '1': - */ - memset(image, 0xff, sizeof image); - - if (!do_interlace && npasses != png_set_interlace_handling(pp)) - png_error(pp, "write: png_set_interlace_handling failed"); - - /* Prepare the whole image first to avoid making it 7 times: */ - for (y=0; y 0) - { - /* Set to all 1's for error detection (libpng tends to - * set unset things to 0). - */ - memset(tempRow, 0xff, sizeof tempRow); - interlace_row(tempRow, row, pixel_size, w, pass); - row = tempRow; - } - else - continue; - } - -# ifdef PNG_WRITE_FILTER_SUPPORTED - /* Only get to here if the row has some pixels in it, set the - * filters to 'all' for the very first row and thereafter to a - * single filter. It isn't well documented, but png_set_filter - * does accept a filter number (per the spec) as well as a bit - * mask. - * - * The apparent wackiness of decrementing nfilter rather than - * incrementing is so that Paeth gets used in all images bigger - * than 1 row - it's the tricky one. - */ - png_set_filter(pp, 0/*method*/, - nfilter >= PNG_FILTER_VALUE_LAST ? PNG_ALL_FILTERS : nfilter); - - if (nfilter-- == 0) - nfilter = PNG_FILTER_VALUE_LAST-1; -# endif - - png_write_row(pp, row); - } - } - } - -#ifdef PNG_TEXT_SUPPORTED - { - static char key[] = "end marker"; - static char comment[] = "end"; - png_text text; - - /* Use a compressed text string to test the correct interaction of text - * compression and IDAT compression. - */ - text.compression = TEXT_COMPRESSION; - text.key = key; - text.text = comment; - text.text_length = (sizeof comment)-1; - text.itxt_length = 0; - text.lang = 0; - text.lang_key = 0; - - png_set_text(pp, pi, &text, 1); - } -#endif - - png_write_end(pp, pi); - - /* And store this under the appropriate id, then clean up. */ - store_storefile(ps, id); - - store_write_reset(ps); - } - - Catch(fault) - { - /* Use the png_store returned by the exception. This may help the compiler - * because 'ps' is not used in this branch of the setjmp. Note that fault - * and ps will always be the same value. - */ - store_write_reset(fault); - } -} - -static void -make_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo, - int PNG_CONST bdhi) -{ - for (; bdlo <= bdhi; ++bdlo) - { - png_uint_32 width; - - for (width = 1; width <= 16; ++width) - { - png_uint_32 height; - - for (height = 1; height <= 16; ++height) - { - /* The four combinations of DIY interlace and interlace or not - - * no interlace + DIY should be identical to no interlace with - * libpng doing it. - */ - make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_NONE, - width, height, 0); - make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_NONE, - width, height, 1); -# ifdef PNG_WRITE_INTERLACING_SUPPORTED - make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, - width, height, 0); - make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, - width, height, 1); -# endif - } - } - } -} - -static void -make_size_images(png_store *ps) -{ - /* This is in case of errors. */ - safecat(ps->test, sizeof ps->test, 0, "make size images"); - - /* Arguments are colour_type, low bit depth, high bit depth - */ - make_size(ps, 0, 0, WRITE_BDHI); - make_size(ps, 2, 3, WRITE_BDHI); - make_size(ps, 3, 0, 3 /*palette: max 8 bits*/); - make_size(ps, 4, 3, WRITE_BDHI); - make_size(ps, 6, 3, WRITE_BDHI); -} - -#ifdef PNG_READ_SUPPORTED -/* Return a row based on image id and 'y' for checking: */ -static void -standard_row(png_const_structp pp, png_byte std[STANDARD_ROWMAX], - png_uint_32 id, png_uint_32 y) -{ - if (WIDTH_FROM_ID(id) == 0) - transform_row(pp, std, COL_FROM_ID(id), DEPTH_FROM_ID(id), y); - else - size_row(std, WIDTH_FROM_ID(id) * bit_size(pp, COL_FROM_ID(id), - DEPTH_FROM_ID(id)), y); -} -#endif /* PNG_READ_SUPPORTED */ - -/* Tests - individual test cases */ -/* Like 'make_standard' but errors are deliberately introduced into the calls - * to ensure that they get detected - it should not be possible to write an - * invalid image with libpng! - */ -/* TODO: the 'set' functions can probably all be made to take a - * png_const_structp rather than a modifiable one. - */ -#ifdef PNG_WARNINGS_SUPPORTED -static void -sBIT0_error_fn(png_structp pp, png_infop pi) -{ - /* 0 is invalid... */ - png_color_8 bad; - bad.red = bad.green = bad.blue = bad.gray = bad.alpha = 0; - png_set_sBIT(pp, pi, &bad); -} - -static void -sBIT_error_fn(png_structp pp, png_infop pi) -{ - png_byte bit_depth; - png_color_8 bad; - - if (png_get_color_type(pp, pi) == PNG_COLOR_TYPE_PALETTE) - bit_depth = 8; - - else - bit_depth = png_get_bit_depth(pp, pi); - - /* Now we know the bit depth we can easily generate an invalid sBIT entry */ - bad.red = bad.green = bad.blue = bad.gray = bad.alpha = - (png_byte)(bit_depth+1); - png_set_sBIT(pp, pi, &bad); -} - -static PNG_CONST struct -{ - void (*fn)(png_structp, png_infop); - PNG_CONST char *msg; - unsigned int warning :1; /* the error is a warning... */ -} error_test[] = - { - /* no warnings makes these errors undetectable. */ - { sBIT0_error_fn, "sBIT(0): failed to detect error", 1 }, - { sBIT_error_fn, "sBIT(too big): failed to detect error", 1 }, - }; - -static void -make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type, - png_byte bit_depth, int interlace_type, int test, png_const_charp name) -{ - png_store * volatile ps = psIn; - - context(ps, fault); - - check_interlace_type(interlace_type); - - Try - { - png_structp pp; - png_infop pi; - - pp = set_store_for_write(ps, &pi, name); - - if (pp == NULL) - Throw ps; - - png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), - transform_height(pp, colour_type, bit_depth), bit_depth, colour_type, - interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - if (colour_type == 3) /* palette */ - init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); - - /* Time for a few errors; these are in various optional chunks, the - * standard tests test the standard chunks pretty well. - */ -# define exception__prev exception_prev_1 -# define exception__env exception_env_1 - Try - { - /* Expect this to throw: */ - ps->expect_error = !error_test[test].warning; - ps->expect_warning = error_test[test].warning; - ps->saw_warning = 0; - error_test[test].fn(pp, pi); - - /* Normally the error is only detected here: */ - png_write_info(pp, pi); - - /* And handle the case where it was only a warning: */ - if (ps->expect_warning && ps->saw_warning) - Throw ps; - - /* If we get here there is a problem, we have success - no error or - * no warning - when we shouldn't have success. Log an error. - */ - store_log(ps, pp, error_test[test].msg, 1 /*error*/); - } - - Catch (fault) - ps = fault; /* expected exit, make sure ps is not clobbered */ -#undef exception__prev -#undef exception__env - - /* And clear these flags */ - ps->expect_error = 0; - ps->expect_warning = 0; - - /* Now write the whole image, just to make sure that the detected, or - * undetected, errro has not created problems inside libpng. - */ - if (png_get_rowbytes(pp, pi) != - transform_rowsize(pp, colour_type, bit_depth)) - png_error(pp, "row size incorrect"); - - else - { - png_uint_32 h = transform_height(pp, colour_type, bit_depth); - int npasses = png_set_interlace_handling(pp); - int pass; - - if (npasses != npasses_from_interlace_type(pp, interlace_type)) - png_error(pp, "write: png_set_interlace_handling failed"); - - for (pass=0; passthis, colour_type, DEPTH(bdlo), interlace_type, - test, name); - - if (fail(pm)) - return 0; - } - } - } - - return 1; /* keep going */ -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -static void -perform_error_test(png_modifier *pm) -{ -#ifdef PNG_WARNINGS_SUPPORTED /* else there are no cases that work! */ - /* Need to do this here because we just write in this test. */ - safecat(pm->this.test, sizeof pm->this.test, 0, "error test"); - - if (!make_errors(pm, 0, 0, WRITE_BDHI)) - return; - - if (!make_errors(pm, 2, 3, WRITE_BDHI)) - return; - - if (!make_errors(pm, 3, 0, 3)) - return; - - if (!make_errors(pm, 4, 3, WRITE_BDHI)) - return; - - if (!make_errors(pm, 6, 3, WRITE_BDHI)) - return; -#else - UNUSED(pm) -#endif -} - -/* This is just to validate the internal PNG formatting code - if this fails - * then the warning messages the library outputs will probably be garbage. - */ -static void -perform_formatting_test(png_store *volatile ps) -{ -#ifdef PNG_TIME_RFC1123_SUPPORTED - /* The handle into the formatting code is the RFC1123 support; this test does - * nothing if that is compiled out. - */ - context(ps, fault); - - Try - { - png_const_charp correct = "29 Aug 2079 13:53:60 +0000"; - png_const_charp result; -# if PNG_LIBPNG_VER >= 10600 - char timestring[29]; -# endif - png_structp pp; - png_time pt; - - pp = set_store_for_write(ps, NULL, "libpng formatting test"); - - if (pp == NULL) - Throw ps; - - - /* Arbitrary settings: */ - pt.year = 2079; - pt.month = 8; - pt.day = 29; - pt.hour = 13; - pt.minute = 53; - pt.second = 60; /* a leap second */ - -# if PNG_LIBPNG_VER < 10600 - result = png_convert_to_rfc1123(pp, &pt); -# else - if (png_convert_to_rfc1123_buffer(timestring, &pt)) - result = timestring; - - else - result = NULL; -# endif - - if (result == NULL) - png_error(pp, "png_convert_to_rfc1123 failed"); - - if (strcmp(result, correct) != 0) - { - size_t pos = 0; - char msg[128]; - - pos = safecat(msg, sizeof msg, pos, "png_convert_to_rfc1123("); - pos = safecat(msg, sizeof msg, pos, correct); - pos = safecat(msg, sizeof msg, pos, ") returned: '"); - pos = safecat(msg, sizeof msg, pos, result); - pos = safecat(msg, sizeof msg, pos, "'"); - - png_error(pp, msg); - } - - store_write_reset(ps); - } - - Catch(fault) - { - store_write_reset(fault); - } -#else - UNUSED(ps) -#endif -} - -#ifdef PNG_READ_SUPPORTED -/* Because we want to use the same code in both the progressive reader and the - * sequential reader it is necessary to deal with the fact that the progressive - * reader callbacks only have one parameter (png_get_progressive_ptr()), so this - * must contain all the test parameters and all the local variables directly - * accessible to the sequential reader implementation. - * - * The technique adopted is to reinvent part of what Dijkstra termed a - * 'display'; an array of pointers to the stack frames of enclosing functions so - * that a nested function definition can access the local (C auto) variables of - * the functions that contain its definition. In fact C provides the first - * pointer (the local variables - the stack frame pointer) and the last (the - * global variables - the BCPL global vector typically implemented as global - * addresses), this code requires one more pointer to make the display - the - * local variables (and function call parameters) of the function that actually - * invokes either the progressive or sequential reader. - * - * Perhaps confusingly this technique is confounded with classes - the - * 'standard_display' defined here is sub-classed as the 'gamma_display' below. - * A gamma_display is a standard_display, taking advantage of the ANSI-C - * requirement that the pointer to the first member of a structure must be the - * same as the pointer to the structure. This allows us to reuse standard_ - * functions in the gamma test code; something that could not be done with - * nested functions! - */ -typedef struct standard_display -{ - png_store* ps; /* Test parameters (passed to the function) */ - png_byte colour_type; - png_byte bit_depth; - png_byte red_sBIT; /* Input data sBIT values. */ - png_byte green_sBIT; - png_byte blue_sBIT; - png_byte alpha_sBIT; - int interlace_type; - png_uint_32 id; /* Calculated file ID */ - png_uint_32 w; /* Width of image */ - png_uint_32 h; /* Height of image */ - int npasses; /* Number of interlaced passes */ - png_uint_32 pixel_size; /* Width of one pixel in bits */ - png_uint_32 bit_width; /* Width of output row in bits */ - size_t cbRow; /* Bytes in a row of the output image */ - int do_interlace; /* Do interlacing internally */ - int is_transparent; /* Transparency information was present. */ - int speed; /* Doing a speed test */ - int use_update_info;/* Call update_info, not start_image */ - struct - { - png_uint_16 red; - png_uint_16 green; - png_uint_16 blue; - } transparent; /* The transparent color, if set. */ - int npalette; /* Number of entries in the palette. */ - store_palette - palette; -} standard_display; - -static void -standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id, - int do_interlace, int use_update_info) -{ - memset(dp, 0, sizeof *dp); - - dp->ps = ps; - dp->colour_type = COL_FROM_ID(id); - dp->bit_depth = DEPTH_FROM_ID(id); - if (dp->bit_depth < 1 || dp->bit_depth > 16) - internal_error(ps, "internal: bad bit depth"); - if (dp->colour_type == 3) - dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = 8; - else - dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = - dp->bit_depth; - dp->interlace_type = INTERLACE_FROM_ID(id); - check_interlace_type(dp->interlace_type); - dp->id = id; - /* All the rest are filled in after the read_info: */ - dp->w = 0; - dp->h = 0; - dp->npasses = 0; - dp->pixel_size = 0; - dp->bit_width = 0; - dp->cbRow = 0; - dp->do_interlace = do_interlace; - dp->is_transparent = 0; - dp->speed = ps->speed; - dp->use_update_info = use_update_info; - dp->npalette = 0; - /* Preset the transparent color to black: */ - memset(&dp->transparent, 0, sizeof dp->transparent); - /* Preset the palette to full intensity/opaque througout: */ - memset(dp->palette, 0xff, sizeof dp->palette); -} - -/* Initialize the palette fields - this must be done later because the palette - * comes from the particular png_store_file that is selected. - */ -static void -standard_palette_init(standard_display *dp) -{ - store_palette_entry *palette = store_current_palette(dp->ps, &dp->npalette); - - /* The remaining entries remain white/opaque. */ - if (dp->npalette > 0) - { - int i = dp->npalette; - memcpy(dp->palette, palette, i * sizeof *palette); - - /* Check for a non-opaque palette entry: */ - while (--i >= 0) - if (palette[i].alpha < 255) - break; - -# ifdef __GNUC__ - /* GCC can't handle the more obviously optimizable version. */ - if (i >= 0) - dp->is_transparent = 1; - else - dp->is_transparent = 0; -# else - dp->is_transparent = (i >= 0); -# endif - } -} - -/* Utility to read the palette from the PNG file and convert it into - * store_palette format. This returns 1 if there is any transparency in the - * palette (it does not check for a transparent colour in the non-palette case.) - */ -static int -read_palette(store_palette palette, int *npalette, png_const_structp pp, - png_infop pi) -{ - png_colorp pal; - png_bytep trans_alpha; - int num; - - pal = 0; - *npalette = -1; - - if (png_get_PLTE(pp, pi, &pal, npalette) & PNG_INFO_PLTE) - { - int i = *npalette; - - if (i <= 0 || i > 256) - png_error(pp, "validate: invalid PLTE count"); - - while (--i >= 0) - { - palette[i].red = pal[i].red; - palette[i].green = pal[i].green; - palette[i].blue = pal[i].blue; - } - - /* Mark the remainder of the entries with a flag value (other than - * white/opaque which is the flag value stored above.) - */ - memset(palette + *npalette, 126, (256-*npalette) * sizeof *palette); - } - - else /* !png_get_PLTE */ - { - if (*npalette != (-1)) - png_error(pp, "validate: invalid PLTE result"); - /* But there is no palette, so record this: */ - *npalette = 0; - memset(palette, 113, sizeof (store_palette)); - } - - trans_alpha = 0; - num = 2; /* force error below */ - if ((png_get_tRNS(pp, pi, &trans_alpha, &num, 0) & PNG_INFO_tRNS) != 0 && - (trans_alpha != NULL || num != 1/*returns 1 for a transparent color*/) && - /* Oops, if a palette tRNS gets expanded png_read_update_info (at least so - * far as 1.5.4) does not remove the trans_alpha pointer, only num_trans, - * so in the above call we get a success, we get a pointer (who knows what - * to) and we get num_trans == 0: - */ - !(trans_alpha != NULL && num == 0)) /* TODO: fix this in libpng. */ - { - int i; - - /* Any of these are crash-worthy - given the implementation of - * png_get_tRNS up to 1.5 an app won't crash if it just checks the - * result above and fails to check that the variables it passed have - * actually been filled in! Note that if the app were to pass the - * last, png_color_16p, variable too it couldn't rely on this. - */ - if (trans_alpha == NULL || num <= 0 || num > 256 || num > *npalette) - png_error(pp, "validate: unexpected png_get_tRNS (palette) result"); - - for (i=0; iis_transparent) - png_error(pp, "validate: palette transparency changed"); - - if (npalette != dp->npalette) - { - size_t pos = 0; - char msg[64]; - - pos = safecat(msg, sizeof msg, pos, "validate: palette size changed: "); - pos = safecatn(msg, sizeof msg, pos, dp->npalette); - pos = safecat(msg, sizeof msg, pos, " -> "); - pos = safecatn(msg, sizeof msg, pos, npalette); - png_error(pp, msg); - } - - { - int i = npalette; /* npalette is aliased */ - - while (--i >= 0) - if (palette[i].red != dp->palette[i].red || - palette[i].green != dp->palette[i].green || - palette[i].blue != dp->palette[i].blue || - palette[i].alpha != dp->palette[i].alpha) - png_error(pp, "validate: PLTE or tRNS chunk changed"); - } -} - -/* By passing a 'standard_display' the progressive callbacks can be used - * directly by the sequential code, the functions suffixed "_imp" are the - * implementations, the functions without the suffix are the callbacks. - * - * The code for the info callback is split into two because this callback calls - * png_read_update_info or png_start_read_image and what gets called depends on - * whether the info needs updating (we want to test both calls in pngvalid.) - */ -static void -standard_info_part1(standard_display *dp, png_structp pp, png_infop pi) -{ - if (png_get_bit_depth(pp, pi) != dp->bit_depth) - png_error(pp, "validate: bit depth changed"); - - if (png_get_color_type(pp, pi) != dp->colour_type) - png_error(pp, "validate: color type changed"); - - if (png_get_filter_type(pp, pi) != PNG_FILTER_TYPE_BASE) - png_error(pp, "validate: filter type changed"); - - if (png_get_interlace_type(pp, pi) != dp->interlace_type) - png_error(pp, "validate: interlacing changed"); - - if (png_get_compression_type(pp, pi) != PNG_COMPRESSION_TYPE_BASE) - png_error(pp, "validate: compression type changed"); - - dp->w = png_get_image_width(pp, pi); - - if (dp->w != standard_width(pp, dp->id)) - png_error(pp, "validate: image width changed"); - - dp->h = png_get_image_height(pp, pi); - - if (dp->h != standard_height(pp, dp->id)) - png_error(pp, "validate: image height changed"); - - /* Record (but don't check at present) the input sBIT according to the colour - * type information. - */ - { - png_color_8p sBIT = 0; - - if (png_get_sBIT(pp, pi, &sBIT) & PNG_INFO_sBIT) - { - int sBIT_invalid = 0; - - if (sBIT == 0) - png_error(pp, "validate: unexpected png_get_sBIT result"); - - if (dp->colour_type & PNG_COLOR_MASK_COLOR) - { - if (sBIT->red == 0 || sBIT->red > dp->bit_depth) - sBIT_invalid = 1; - else - dp->red_sBIT = sBIT->red; - - if (sBIT->green == 0 || sBIT->green > dp->bit_depth) - sBIT_invalid = 1; - else - dp->green_sBIT = sBIT->green; - - if (sBIT->blue == 0 || sBIT->blue > dp->bit_depth) - sBIT_invalid = 1; - else - dp->blue_sBIT = sBIT->blue; - } - - else /* !COLOR */ - { - if (sBIT->gray == 0 || sBIT->gray > dp->bit_depth) - sBIT_invalid = 1; - else - dp->blue_sBIT = dp->green_sBIT = dp->red_sBIT = sBIT->gray; - } - - /* All 8 bits in tRNS for a palette image are significant - see the - * spec. - */ - if (dp->colour_type & PNG_COLOR_MASK_ALPHA) - { - if (sBIT->alpha == 0 || sBIT->alpha > dp->bit_depth) - sBIT_invalid = 1; - else - dp->alpha_sBIT = sBIT->alpha; - } - - if (sBIT_invalid) - png_error(pp, "validate: sBIT value out of range"); - } - } - - /* Important: this is validating the value *before* any transforms have been - * put in place. It doesn't matter for the standard tests, where there are - * no transforms, but it does for other tests where rowbytes may change after - * png_read_update_info. - */ - if (png_get_rowbytes(pp, pi) != standard_rowsize(pp, dp->id)) - png_error(pp, "validate: row size changed"); - - /* Validate the colour type 3 palette (this can be present on other color - * types.) - */ - standard_palette_validate(dp, pp, pi); - - /* In any case always check for a tranparent color (notice that the - * colour type 3 case must not give a successful return on the get_tRNS call - * with these arguments!) - */ - { - png_color_16p trans_color = 0; - - if (png_get_tRNS(pp, pi, 0, 0, &trans_color) & PNG_INFO_tRNS) - { - if (trans_color == 0) - png_error(pp, "validate: unexpected png_get_tRNS (color) result"); - - switch (dp->colour_type) - { - case 0: - dp->transparent.red = dp->transparent.green = dp->transparent.blue = - trans_color->gray; - dp->is_transparent = 1; - break; - - case 2: - dp->transparent.red = trans_color->red; - dp->transparent.green = trans_color->green; - dp->transparent.blue = trans_color->blue; - dp->is_transparent = 1; - break; - - case 3: - /* Not expected because it should result in the array case - * above. - */ - png_error(pp, "validate: unexpected png_get_tRNS result"); - break; - - default: - png_error(pp, "validate: invalid tRNS chunk with alpha image"); - } - } - } - - /* Read the number of passes - expected to match the value used when - * creating the image (interlaced or not). This has the side effect of - * turning on interlace handling (if do_interlace is not set.) - */ - dp->npasses = npasses_from_interlace_type(pp, dp->interlace_type); - if (!dp->do_interlace && dp->npasses != png_set_interlace_handling(pp)) - png_error(pp, "validate: file changed interlace type"); - - /* Caller calls png_read_update_info or png_start_read_image now, then calls - * part2. - */ -} - -/* This must be called *after* the png_read_update_info call to get the correct - * 'rowbytes' value, otherwise png_get_rowbytes will refer to the untransformed - * image. - */ -static void -standard_info_part2(standard_display *dp, png_const_structp pp, - png_const_infop pi, int nImages) -{ - /* Record cbRow now that it can be found. */ - dp->pixel_size = bit_size(pp, png_get_color_type(pp, pi), - png_get_bit_depth(pp, pi)); - dp->bit_width = png_get_image_width(pp, pi) * dp->pixel_size; - dp->cbRow = png_get_rowbytes(pp, pi); - - /* Validate the rowbytes here again. */ - if (dp->cbRow != (dp->bit_width+7)/8) - png_error(pp, "bad png_get_rowbytes calculation"); - - /* Then ensure there is enough space for the output image(s). */ - store_ensure_image(dp->ps, pp, nImages, dp->cbRow, dp->h); -} - -static void -standard_info_imp(standard_display *dp, png_structp pp, png_infop pi, - int nImages) -{ - /* Note that the validation routine has the side effect of turning on - * interlace handling in the subsequent code. - */ - standard_info_part1(dp, pp, pi); - - /* And the info callback has to call this (or png_read_update_info - see - * below in the png_modifier code for that variant. - */ - if (dp->use_update_info) - { - /* For debugging the effect of multiple calls: */ - int i = dp->use_update_info; - while (i-- > 0) - png_read_update_info(pp, pi); - } - - else - png_start_read_image(pp); - - /* Validate the height, width and rowbytes plus ensure that sufficient buffer - * exists for decoding the image. - */ - standard_info_part2(dp, pp, pi, nImages); -} - -static void PNGCBAPI -standard_info(png_structp pp, png_infop pi) -{ - standard_display *dp = voidcast(standard_display*, - png_get_progressive_ptr(pp)); - - /* Call with nImages==1 because the progressive reader can only produce one - * image. - */ - standard_info_imp(dp, pp, pi, 1 /*only one image*/); -} - -static void PNGCBAPI -progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass) -{ - png_const_structp pp = ppIn; - PNG_CONST standard_display *dp = voidcast(standard_display*, - png_get_progressive_ptr(pp)); - - /* When handling interlacing some rows will be absent in each pass, the - * callback still gets called, but with a NULL pointer. This is checked - * in the 'else' clause below. We need our own 'cbRow', but we can't call - * png_get_rowbytes because we got no info structure. - */ - if (new_row != NULL) - { - png_bytep row; - - /* In the case where the reader doesn't do the interlace it gives - * us the y in the sub-image: - */ - if (dp->do_interlace && dp->interlace_type == PNG_INTERLACE_ADAM7) - { -#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED - /* Use this opportunity to validate the png 'current' APIs: */ - if (y != png_get_current_row_number(pp)) - png_error(pp, "png_get_current_row_number is broken"); - - if (pass != png_get_current_pass_number(pp)) - png_error(pp, "png_get_current_pass_number is broken"); -#endif - - y = PNG_ROW_FROM_PASS_ROW(y, pass); - } - - /* Validate this just in case. */ - if (y >= dp->h) - png_error(pp, "invalid y to progressive row callback"); - - row = store_image_row(dp->ps, pp, 0, y); - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Combine the new row into the old: */ - if (dp->do_interlace) - { - if (dp->interlace_type == PNG_INTERLACE_ADAM7) - deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass); - else - row_copy(row, new_row, dp->pixel_size * dp->w); - } - else - png_progressive_combine_row(pp, row, new_row); -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - } - -#ifdef PNG_READ_INTERLACING_SUPPORTED - else if (dp->interlace_type == PNG_INTERLACE_ADAM7 && - PNG_ROW_IN_INTERLACE_PASS(y, pass) && - PNG_PASS_COLS(dp->w, pass) > 0) - png_error(pp, "missing row in progressive de-interlacing"); -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -} - -static void -sequential_row(standard_display *dp, png_structp pp, png_infop pi, - PNG_CONST int iImage, PNG_CONST int iDisplay) -{ - PNG_CONST int npasses = dp->npasses; - PNG_CONST int do_interlace = dp->do_interlace && - dp->interlace_type == PNG_INTERLACE_ADAM7; - PNG_CONST png_uint_32 height = standard_height(pp, dp->id); - PNG_CONST png_uint_32 width = standard_width(pp, dp->id); - PNG_CONST png_store* ps = dp->ps; - int pass; - - for (pass=0; pass 0 && PNG_ROW_IN_INTERLACE_PASS(y, pass)) - { - /* Read the row into a pair of temporary buffers, then do the - * merge here into the output rows. - */ - png_byte row[STANDARD_ROWMAX], display[STANDARD_ROWMAX]; - - /* The following aids (to some extent) error detection - we can - * see where png_read_row wrote. Use opposite values in row and - * display to make this easier. Don't use 0xff (which is used in - * the image write code to fill unused bits) or 0 (which is a - * likely value to overwrite unused bits with). - */ - memset(row, 0xc5, sizeof row); - memset(display, 0x5c, sizeof display); - - png_read_row(pp, row, display); - - if (iImage >= 0) - deinterlace_row(store_image_row(ps, pp, iImage, y), row, - dp->pixel_size, dp->w, pass); - - if (iDisplay >= 0) - deinterlace_row(store_image_row(ps, pp, iDisplay, y), display, - dp->pixel_size, dp->w, pass); - } - } - else - png_read_row(pp, - iImage >= 0 ? store_image_row(ps, pp, iImage, y) : NULL, - iDisplay >= 0 ? store_image_row(ps, pp, iDisplay, y) : NULL); - } - } - - /* And finish the read operation (only really necessary if the caller wants - * to find additional data in png_info from chunks after the last IDAT.) - */ - png_read_end(pp, pi); -} - -#ifdef PNG_TEXT_SUPPORTED -static void -standard_check_text(png_const_structp pp, png_const_textp tp, - png_const_charp keyword, png_const_charp text) -{ - char msg[1024]; - size_t pos = safecat(msg, sizeof msg, 0, "text: "); - size_t ok; - - pos = safecat(msg, sizeof msg, pos, keyword); - pos = safecat(msg, sizeof msg, pos, ": "); - ok = pos; - - if (tp->compression != TEXT_COMPRESSION) - { - char buf[64]; - - sprintf(buf, "compression [%d->%d], ", TEXT_COMPRESSION, - tp->compression); - pos = safecat(msg, sizeof msg, pos, buf); - } - - if (tp->key == NULL || strcmp(tp->key, keyword) != 0) - { - pos = safecat(msg, sizeof msg, pos, "keyword \""); - if (tp->key != NULL) - { - pos = safecat(msg, sizeof msg, pos, tp->key); - pos = safecat(msg, sizeof msg, pos, "\", "); - } - - else - pos = safecat(msg, sizeof msg, pos, "null, "); - } - - if (tp->text == NULL) - pos = safecat(msg, sizeof msg, pos, "text lost, "); - - else - { - if (tp->text_length != strlen(text)) - { - char buf[64]; - sprintf(buf, "text length changed[%lu->%lu], ", - (unsigned long)strlen(text), (unsigned long)tp->text_length); - pos = safecat(msg, sizeof msg, pos, buf); - } - - if (strcmp(tp->text, text) != 0) - { - pos = safecat(msg, sizeof msg, pos, "text becomes \""); - pos = safecat(msg, sizeof msg, pos, tp->text); - pos = safecat(msg, sizeof msg, pos, "\" (was \""); - pos = safecat(msg, sizeof msg, pos, text); - pos = safecat(msg, sizeof msg, pos, "\"), "); - } - } - - if (tp->itxt_length != 0) - pos = safecat(msg, sizeof msg, pos, "iTXt length set, "); - - if (tp->lang != NULL) - { - pos = safecat(msg, sizeof msg, pos, "iTXt language \""); - pos = safecat(msg, sizeof msg, pos, tp->lang); - pos = safecat(msg, sizeof msg, pos, "\", "); - } - - if (tp->lang_key != NULL) - { - pos = safecat(msg, sizeof msg, pos, "iTXt keyword \""); - pos = safecat(msg, sizeof msg, pos, tp->lang_key); - pos = safecat(msg, sizeof msg, pos, "\", "); - } - - if (pos > ok) - { - msg[pos-2] = '\0'; /* Remove the ", " at the end */ - png_error(pp, msg); - } -} - -static void -standard_text_validate(standard_display *dp, png_const_structp pp, - png_infop pi, int check_end) -{ - png_textp tp = NULL; - png_uint_32 num_text = png_get_text(pp, pi, &tp, NULL); - - if (num_text == 2 && tp != NULL) - { - standard_check_text(pp, tp, "image name", dp->ps->current->name); - - /* This exists because prior to 1.5.18 the progressive reader left the - * png_struct z_stream unreset at the end of the image, so subsequent - * attempts to use it simply returns Z_STREAM_END. - */ - if (check_end) - standard_check_text(pp, tp+1, "end marker", "end"); - } - - else - { - char msg[64]; - - sprintf(msg, "expected two text items, got %lu", - (unsigned long)num_text); - png_error(pp, msg); - } -} -#else -# define standard_text_validate(dp,pp,pi,check_end) ((void)0) -#endif - -static void -standard_row_validate(standard_display *dp, png_const_structp pp, - int iImage, int iDisplay, png_uint_32 y) -{ - int where; - png_byte std[STANDARD_ROWMAX]; - - /* The row must be pre-initialized to the magic number here for the size - * tests to pass: - */ - memset(std, 178, sizeof std); - standard_row(pp, std, dp->id, y); - - /* At the end both the 'row' and 'display' arrays should end up identical. - * In earlier passes 'row' will be partially filled in, with only the pixels - * that have been read so far, but 'display' will have those pixels - * replicated to fill the unread pixels while reading an interlaced image. -#if PNG_LIBPNG_VER < 10506 - * The side effect inside the libpng sequential reader is that the 'row' - * array retains the correct values for unwritten pixels within the row - * bytes, while the 'display' array gets bits off the end of the image (in - * the last byte) trashed. Unfortunately in the progressive reader the - * row bytes are always trashed, so we always do a pixel_cmp here even though - * a memcmp of all cbRow bytes will succeed for the sequential reader. -#endif - */ - if (iImage >= 0 && - (where = pixel_cmp(std, store_image_row(dp->ps, pp, iImage, y), - dp->bit_width)) != 0) - { - char msg[64]; - sprintf(msg, "PNG image row[%lu][%d] changed from %.2x to %.2x", - (unsigned long)y, where-1, std[where-1], - store_image_row(dp->ps, pp, iImage, y)[where-1]); - png_error(pp, msg); - } - -#if PNG_LIBPNG_VER < 10506 - /* In this case use pixel_cmp because we need to compare a partial - * byte at the end of the row if the row is not an exact multiple - * of 8 bits wide. (This is fixed in libpng-1.5.6 and pixel_cmp is - * changed to match!) - */ -#endif - if (iDisplay >= 0 && - (where = pixel_cmp(std, store_image_row(dp->ps, pp, iDisplay, y), - dp->bit_width)) != 0) - { - char msg[64]; - sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x", - (unsigned long)y, where-1, std[where-1], - store_image_row(dp->ps, pp, iDisplay, y)[where-1]); - png_error(pp, msg); - } -} - -static void -standard_image_validate(standard_display *dp, png_const_structp pp, int iImage, - int iDisplay) -{ - png_uint_32 y; - - if (iImage >= 0) - store_image_check(dp->ps, pp, iImage); - - if (iDisplay >= 0) - store_image_check(dp->ps, pp, iDisplay); - - for (y=0; yh; ++y) - standard_row_validate(dp, pp, iImage, iDisplay, y); - - /* This avoids false positives if the validation code is never called! */ - dp->ps->validated = 1; -} - -static void PNGCBAPI -standard_end(png_structp ppIn, png_infop pi) -{ - png_const_structp pp = ppIn; - standard_display *dp = voidcast(standard_display*, - png_get_progressive_ptr(pp)); - - UNUSED(pi) - - /* Validate the image - progressive reading only produces one variant for - * interlaced images. - */ - standard_text_validate(dp, pp, pi, - PNG_LIBPNG_VER >= 10518/*check_end: see comments above*/); - standard_image_validate(dp, pp, 0, -1); -} - -/* A single test run checking the standard image to ensure it is not damaged. */ -static void -standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id, - int do_interlace, int use_update_info) -{ - standard_display d; - context(psIn, fault); - - /* Set up the display (stack frame) variables from the arguments to the - * function and initialize the locals that are filled in later. - */ - standard_display_init(&d, psIn, id, do_interlace, use_update_info); - - /* Everything is protected by a Try/Catch. The functions called also - * typically have local Try/Catch blocks. - */ - Try - { - png_structp pp; - png_infop pi; - - /* Get a png_struct for reading the image. This will throw an error if it - * fails, so we don't need to check the result. - */ - pp = set_store_for_read(d.ps, &pi, d.id, - d.do_interlace ? (d.ps->progressive ? - "pngvalid progressive deinterlacer" : - "pngvalid sequential deinterlacer") : (d.ps->progressive ? - "progressive reader" : "sequential reader")); - - /* Initialize the palette correctly from the png_store_file. */ - standard_palette_init(&d); - - /* Introduce the correct read function. */ - if (d.ps->progressive) - { - png_set_progressive_read_fn(pp, &d, standard_info, progressive_row, - standard_end); - - /* Now feed data into the reader until we reach the end: */ - store_progressive_read(d.ps, pp, pi); - } - else - { - /* Note that this takes the store, not the display. */ - png_set_read_fn(pp, d.ps, store_read); - - /* Check the header values: */ - png_read_info(pp, pi); - - /* The code tests both versions of the images that the sequential - * reader can produce. - */ - standard_info_imp(&d, pp, pi, 2 /*images*/); - - /* Need the total bytes in the image below; we can't get to this point - * unless the PNG file values have been checked against the expected - * values. - */ - { - sequential_row(&d, pp, pi, 0, 1); - - /* After the last pass loop over the rows again to check that the - * image is correct. - */ - if (!d.speed) - { - standard_text_validate(&d, pp, pi, 1/*check_end*/); - standard_image_validate(&d, pp, 0, 1); - } - else - d.ps->validated = 1; - } - } - - /* Check for validation. */ - if (!d.ps->validated) - png_error(pp, "image read failed silently"); - - /* Successful completion. */ - } - - Catch(fault) - d.ps = fault; /* make sure this hasn't been clobbered. */ - - /* In either case clean up the store. */ - store_read_reset(d.ps); -} - -static int -test_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, - int bdlo, int PNG_CONST bdhi) -{ - for (; bdlo <= bdhi; ++bdlo) - { - int interlace_type; - - for (interlace_type = PNG_INTERLACE_NONE; - interlace_type < INTERLACE_LAST; ++interlace_type) - { - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - interlace_type, 0, 0, 0), 0/*do_interlace*/, pm->use_update_info); - - if (fail(pm)) - return 0; - } - } - - return 1; /* keep going */ -} - -static void -perform_standard_test(png_modifier *pm) -{ - /* Test each colour type over the valid range of bit depths (expressed as - * log2(bit_depth) in turn, stop as soon as any error is detected. - */ - if (!test_standard(pm, 0, 0, READ_BDHI)) - return; - - if (!test_standard(pm, 2, 3, READ_BDHI)) - return; - - if (!test_standard(pm, 3, 0, 3)) - return; - - if (!test_standard(pm, 4, 3, READ_BDHI)) - return; - - if (!test_standard(pm, 6, 3, READ_BDHI)) - return; -} - - -/********************************** SIZE TESTS ********************************/ -static int -test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, - int bdlo, int PNG_CONST bdhi) -{ - /* Run the tests on each combination. - * - * NOTE: on my 32 bit x86 each of the following blocks takes - * a total of 3.5 seconds if done across every combo of bit depth - * width and height. This is a waste of time in practice, hence the - * hinc and winc stuff: - */ - static PNG_CONST png_byte hinc[] = {1, 3, 11, 1, 5}; - static PNG_CONST png_byte winc[] = {1, 9, 5, 7, 1}; - for (; bdlo <= bdhi; ++bdlo) - { - png_uint_32 h, w; - - for (h=1; h<=16; h+=hinc[bdlo]) for (w=1; w<=16; w+=winc[bdlo]) - { - /* First test all the 'size' images against the sequential - * reader using libpng to deinterlace (where required.) This - * validates the write side of libpng. There are four possibilities - * to validate. - */ - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - PNG_INTERLACE_NONE, w, h, 0), 0/*do_interlace*/, - pm->use_update_info); - - if (fail(pm)) - return 0; - - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - PNG_INTERLACE_NONE, w, h, 1), 0/*do_interlace*/, - pm->use_update_info); - - if (fail(pm)) - return 0; - -# ifdef PNG_WRITE_INTERLACING_SUPPORTED - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/, - pm->use_update_info); - - if (fail(pm)) - return 0; - - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/, - pm->use_update_info); - - if (fail(pm)) - return 0; -# endif - - /* Now validate the interlaced read side - do_interlace true, - * in the progressive case this does actually make a difference - * to the code used in the non-interlaced case too. - */ - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/, - pm->use_update_info); - - if (fail(pm)) - return 0; - -# ifdef PNG_WRITE_INTERLACING_SUPPORTED - standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, - PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/, - pm->use_update_info); - - if (fail(pm)) - return 0; -# endif - } - } - - return 1; /* keep going */ -} - -static void -perform_size_test(png_modifier *pm) -{ - /* Test each colour type over the valid range of bit depths (expressed as - * log2(bit_depth) in turn, stop as soon as any error is detected. - */ - if (!test_size(pm, 0, 0, READ_BDHI)) - return; - - if (!test_size(pm, 2, 3, READ_BDHI)) - return; - - /* For the moment don't do the palette test - it's a waste of time when - * compared to the grayscale test. - */ -#if 0 - if (!test_size(pm, 3, 0, 3)) - return; -#endif - - if (!test_size(pm, 4, 3, READ_BDHI)) - return; - - if (!test_size(pm, 6, 3, READ_BDHI)) - return; -} - - -/******************************* TRANSFORM TESTS ******************************/ -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -/* A set of tests to validate libpng image transforms. The possibilities here - * are legion because the transforms can be combined in a combinatorial - * fashion. To deal with this some measure of restraint is required, otherwise - * the tests would take forever. - */ -typedef struct image_pixel -{ - /* A local (pngvalid) representation of a PNG pixel, in all its - * various forms. - */ - unsigned int red, green, blue, alpha; /* For non-palette images. */ - unsigned int palette_index; /* For a palette image. */ - png_byte colour_type; /* As in the spec. */ - png_byte bit_depth; /* Defines bit size in row */ - png_byte sample_depth; /* Scale of samples */ - int have_tRNS; /* tRNS chunk may need processing */ - - /* For checking the code calculates double precision floating point values - * along with an error value, accumulated from the transforms. Because an - * sBIT setting allows larger error bounds (indeed, by the spec, apparently - * up to just less than +/-1 in the scaled value) the *lowest* sBIT for each - * channel is stored. This sBIT value is folded in to the stored error value - * at the end of the application of the transforms to the pixel. - */ - double redf, greenf, bluef, alphaf; - double rede, greene, bluee, alphae; - png_byte red_sBIT, green_sBIT, blue_sBIT, alpha_sBIT; -} image_pixel; - -/* Shared utility function, see below. */ -static void -image_pixel_setf(image_pixel *this, unsigned int max) -{ - this->redf = this->red / (double)max; - this->greenf = this->green / (double)max; - this->bluef = this->blue / (double)max; - this->alphaf = this->alpha / (double)max; - - if (this->red < max) - this->rede = this->redf * DBL_EPSILON; - else - this->rede = 0; - if (this->green < max) - this->greene = this->greenf * DBL_EPSILON; - else - this->greene = 0; - if (this->blue < max) - this->bluee = this->bluef * DBL_EPSILON; - else - this->bluee = 0; - if (this->alpha < max) - this->alphae = this->alphaf * DBL_EPSILON; - else - this->alphae = 0; -} - -/* Initialize the structure for the next pixel - call this before doing any - * transforms and call it for each pixel since all the fields may need to be - * reset. - */ -static void -image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type, - png_byte bit_depth, png_uint_32 x, store_palette palette) -{ - PNG_CONST png_byte sample_depth = (png_byte)(colour_type == - PNG_COLOR_TYPE_PALETTE ? 8 : bit_depth); - PNG_CONST unsigned int max = (1U<palette_index = this->red = this->green = this->blue = - sample(row, colour_type, bit_depth, x, 0); - this->alpha = max; - this->red_sBIT = this->green_sBIT = this->blue_sBIT = this->alpha_sBIT = - sample_depth; - - /* Then override as appropriate: */ - if (colour_type == 3) /* palette */ - { - /* This permits the caller to default to the sample value. */ - if (palette != 0) - { - PNG_CONST unsigned int i = this->palette_index; - - this->red = palette[i].red; - this->green = palette[i].green; - this->blue = palette[i].blue; - this->alpha = palette[i].alpha; - } - } - - else /* not palette */ - { - unsigned int i = 0; - - if (colour_type & 2) - { - this->green = sample(row, colour_type, bit_depth, x, 1); - this->blue = sample(row, colour_type, bit_depth, x, 2); - i = 2; - } - if (colour_type & 4) - this->alpha = sample(row, colour_type, bit_depth, x, ++i); - } - - /* Calculate the scaled values, these are simply the values divided by - * 'max' and the error is initialized to the double precision epsilon value - * from the header file. - */ - image_pixel_setf(this, max); - - /* Store the input information for use in the transforms - these will - * modify the information. - */ - this->colour_type = colour_type; - this->bit_depth = bit_depth; - this->sample_depth = sample_depth; - this->have_tRNS = 0; -} - -/* Convert a palette image to an rgb image. This necessarily converts the tRNS - * chunk at the same time, because the tRNS will be in palette form. The way - * palette validation works means that the original palette is never updated, - * instead the image_pixel value from the row contains the RGB of the - * corresponding palette entry and *this* is updated. Consequently this routine - * only needs to change the colour type information. - */ -static void -image_pixel_convert_PLTE(image_pixel *this) -{ - if (this->colour_type == PNG_COLOR_TYPE_PALETTE) - { - if (this->have_tRNS) - { - this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; - this->have_tRNS = 0; - } - else - this->colour_type = PNG_COLOR_TYPE_RGB; - - /* The bit depth of the row changes at this point too (notice that this is - * the row format, not the sample depth, which is separate.) - */ - this->bit_depth = 8; - } -} - -/* Add an alpha channel; this will import the tRNS information because tRNS is - * not valid in an alpha image. The bit depth will invariably be set to at - * least 8. Palette images will be converted to alpha (using the above API). - */ -static void -image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display) -{ - if (this->colour_type == PNG_COLOR_TYPE_PALETTE) - image_pixel_convert_PLTE(this); - - if ((this->colour_type & PNG_COLOR_MASK_ALPHA) == 0) - { - if (this->colour_type == PNG_COLOR_TYPE_GRAY) - { - if (this->bit_depth < 8) - this->bit_depth = 8; - - if (this->have_tRNS) - { - this->have_tRNS = 0; - - /* Check the input, original, channel value here against the - * original tRNS gray chunk valie. - */ - if (this->red == display->transparent.red) - this->alphaf = 0; - else - this->alphaf = 1; - } - else - this->alphaf = 1; - - this->colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; - } - - else if (this->colour_type == PNG_COLOR_TYPE_RGB) - { - if (this->have_tRNS) - { - this->have_tRNS = 0; - - /* Again, check the exact input values, not the current transformed - * value! - */ - if (this->red == display->transparent.red && - this->green == display->transparent.green && - this->blue == display->transparent.blue) - this->alphaf = 0; - else - this->alphaf = 1; - - this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; - } - } - - /* The error in the alpha is zero and the sBIT value comes from the - * original sBIT data (actually it will always be the original bit depth). - */ - this->alphae = 0; - this->alpha_sBIT = display->alpha_sBIT; - } -} - -struct transform_display; -typedef struct image_transform -{ - /* The name of this transform: a string. */ - PNG_CONST char *name; - - /* Each transform can be disabled from the command line: */ - int enable; - - /* The global list of transforms; read only. */ - struct image_transform *PNG_CONST list; - - /* The global count of the number of times this transform has been set on an - * image. - */ - unsigned int global_use; - - /* The local count of the number of times this transform has been set. */ - unsigned int local_use; - - /* The next transform in the list, each transform must call its own next - * transform after it has processed the pixel successfully. - */ - PNG_CONST struct image_transform *next; - - /* A single transform for the image, expressed as a series of function - * callbacks and some space for values. - * - * First a callback to add any required modifications to the png_modifier; - * this gets called just before the modifier is set up for read. - */ - void (*ini)(PNG_CONST struct image_transform *this, - struct transform_display *that); - - /* And a callback to set the transform on the current png_read_struct: - */ - void (*set)(PNG_CONST struct image_transform *this, - struct transform_display *that, png_structp pp, png_infop pi); - - /* Then a transform that takes an input pixel in one PNG format or another - * and modifies it by a pngvalid implementation of the transform (thus - * duplicating the libpng intent without, we hope, duplicating the bugs - * in the libpng implementation!) The png_structp is solely to allow error - * reporting via png_error and png_warning. - */ - void (*mod)(PNG_CONST struct image_transform *this, image_pixel *that, - png_const_structp pp, PNG_CONST struct transform_display *display); - - /* Add this transform to the list and return true if the transform is - * meaningful for this colour type and bit depth - if false then the - * transform should have no effect on the image so there's not a lot of - * point running it. - */ - int (*add)(struct image_transform *this, - PNG_CONST struct image_transform **that, png_byte colour_type, - png_byte bit_depth); -} image_transform; - -typedef struct transform_display -{ - standard_display this; - - /* Parameters */ - png_modifier* pm; - PNG_CONST image_transform* transform_list; - - /* Local variables */ - png_byte output_colour_type; - png_byte output_bit_depth; - - /* Modifications (not necessarily used.) */ - gama_modification gama_mod; - chrm_modification chrm_mod; - srgb_modification srgb_mod; -} transform_display; - -/* Set sRGB, cHRM and gAMA transforms as required by the current encoding. */ -static void -transform_set_encoding(transform_display *this) -{ - /* Set up the png_modifier '_current' fields then use these to determine how - * to add appropriate chunks. - */ - png_modifier *pm = this->pm; - - modifier_set_encoding(pm); - - if (modifier_color_encoding_is_set(pm)) - { - if (modifier_color_encoding_is_sRGB(pm)) - srgb_modification_init(&this->srgb_mod, pm, PNG_sRGB_INTENT_ABSOLUTE); - - else - { - /* Set gAMA and cHRM separately. */ - gama_modification_init(&this->gama_mod, pm, pm->current_gamma); - - if (pm->current_encoding != 0) - chrm_modification_init(&this->chrm_mod, pm, pm->current_encoding); - } - } -} - -/* Three functions to end the list: */ -static void -image_transform_ini_end(PNG_CONST image_transform *this, - transform_display *that) -{ - UNUSED(this) - UNUSED(that) -} - -static void -image_transform_set_end(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - UNUSED(this) - UNUSED(that) - UNUSED(pp) - UNUSED(pi) -} - -/* At the end of the list recalculate the output image pixel value from the - * double precision values set up by the preceding 'mod' calls: - */ -static unsigned int -sample_scale(double sample_value, unsigned int scale) -{ - sample_value = floor(sample_value * scale + .5); - - /* Return NaN as 0: */ - if (!(sample_value > 0)) - sample_value = 0; - else if (sample_value > scale) - sample_value = scale; - - return (unsigned int)sample_value; -} - -static void -image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that, - png_const_structp pp, PNG_CONST transform_display *display) -{ - PNG_CONST unsigned int scale = (1U<sample_depth)-1; - - UNUSED(this) - UNUSED(pp) - UNUSED(display) - - /* At the end recalculate the digitized red green and blue values according - * to the current sample_depth of the pixel. - * - * The sample value is simply scaled to the maximum, checking for over - * and underflow (which can both happen for some image transforms, - * including simple size scaling, though libpng doesn't do that at present. - */ - that->red = sample_scale(that->redf, scale); - - /* The error value is increased, at the end, according to the lowest sBIT - * value seen. Common sense tells us that the intermediate integer - * representations are no more accurate than +/- 0.5 in the integral values, - * the sBIT allows the implementation to be worse than this. In addition the - * PNG specification actually permits any error within the range (-1..+1), - * but that is ignored here. Instead the final digitized value is compared, - * below to the digitized value of the error limits - this has the net effect - * of allowing (almost) +/-1 in the output value. It's difficult to see how - * any algorithm that digitizes intermediate results can be more accurate. - */ - that->rede += 1./(2*((1U<red_sBIT)-1)); - - if (that->colour_type & PNG_COLOR_MASK_COLOR) - { - that->green = sample_scale(that->greenf, scale); - that->blue = sample_scale(that->bluef, scale); - that->greene += 1./(2*((1U<green_sBIT)-1)); - that->bluee += 1./(2*((1U<blue_sBIT)-1)); - } - else - { - that->blue = that->green = that->red; - that->bluef = that->greenf = that->redf; - that->bluee = that->greene = that->rede; - } - - if ((that->colour_type & PNG_COLOR_MASK_ALPHA) || - that->colour_type == PNG_COLOR_TYPE_PALETTE) - { - that->alpha = sample_scale(that->alphaf, scale); - that->alphae += 1./(2*((1U<alpha_sBIT)-1)); - } - else - { - that->alpha = scale; /* opaque */ - that->alpha = 1; /* Override this. */ - that->alphae = 0; /* It's exact ;-) */ - } -} - -/* Static 'end' structure: */ -static image_transform image_transform_end = -{ - "(end)", /* name */ - 1, /* enable */ - 0, /* list */ - 0, /* global_use */ - 0, /* local_use */ - 0, /* next */ - image_transform_ini_end, - image_transform_set_end, - image_transform_mod_end, - 0 /* never called, I want it to crash if it is! */ -}; - -/* Reader callbacks and implementations, where they differ from the standard - * ones. - */ -static void -transform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id, - PNG_CONST image_transform *transform_list) -{ - memset(dp, 0, sizeof *dp); - - /* Standard fields */ - standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/, - pm->use_update_info); - - /* Parameter fields */ - dp->pm = pm; - dp->transform_list = transform_list; - - /* Local variable fields */ - dp->output_colour_type = 255; /* invalid */ - dp->output_bit_depth = 255; /* invalid */ -} - -static void -transform_info_imp(transform_display *dp, png_structp pp, png_infop pi) -{ - /* Reuse the standard stuff as appropriate. */ - standard_info_part1(&dp->this, pp, pi); - - /* Now set the list of transforms. */ - dp->transform_list->set(dp->transform_list, dp, pp, pi); - - /* Update the info structure for these transforms: */ - { - int i = dp->this.use_update_info; - /* Always do one call, even if use_update_info is 0. */ - do - png_read_update_info(pp, pi); - while (--i > 0); - } - - /* And get the output information into the standard_display */ - standard_info_part2(&dp->this, pp, pi, 1/*images*/); - - /* Plus the extra stuff we need for the transform tests: */ - dp->output_colour_type = png_get_color_type(pp, pi); - dp->output_bit_depth = png_get_bit_depth(pp, pi); - - /* Validate the combination of colour type and bit depth that we are getting - * out of libpng; the semantics of something not in the PNG spec are, at - * best, unclear. - */ - switch (dp->output_colour_type) - { - case PNG_COLOR_TYPE_PALETTE: - if (dp->output_bit_depth > 8) goto error; - /*FALL THROUGH*/ - case PNG_COLOR_TYPE_GRAY: - if (dp->output_bit_depth == 1 || dp->output_bit_depth == 2 || - dp->output_bit_depth == 4) - break; - /*FALL THROUGH*/ - default: - if (dp->output_bit_depth == 8 || dp->output_bit_depth == 16) - break; - /*FALL THROUGH*/ - error: - { - char message[128]; - size_t pos; - - pos = safecat(message, sizeof message, 0, - "invalid final bit depth: colour type("); - pos = safecatn(message, sizeof message, pos, dp->output_colour_type); - pos = safecat(message, sizeof message, pos, ") with bit depth: "); - pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); - - png_error(pp, message); - } - } - - /* Use a test pixel to check that the output agrees with what we expect - - * this avoids running the whole test if the output is unexpected. - */ - { - image_pixel test_pixel; - - memset(&test_pixel, 0, sizeof test_pixel); - test_pixel.colour_type = dp->this.colour_type; /* input */ - test_pixel.bit_depth = dp->this.bit_depth; - if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE) - test_pixel.sample_depth = 8; - else - test_pixel.sample_depth = test_pixel.bit_depth; - /* Don't need sBIT here, but it must be set to non-zero to avoid - * arithmetic overflows. - */ - test_pixel.have_tRNS = dp->this.is_transparent; - test_pixel.red_sBIT = test_pixel.green_sBIT = test_pixel.blue_sBIT = - test_pixel.alpha_sBIT = test_pixel.sample_depth; - - dp->transform_list->mod(dp->transform_list, &test_pixel, pp, dp); - - if (test_pixel.colour_type != dp->output_colour_type) - { - char message[128]; - size_t pos = safecat(message, sizeof message, 0, "colour type "); - - pos = safecatn(message, sizeof message, pos, dp->output_colour_type); - pos = safecat(message, sizeof message, pos, " expected "); - pos = safecatn(message, sizeof message, pos, test_pixel.colour_type); - - png_error(pp, message); - } - - if (test_pixel.bit_depth != dp->output_bit_depth) - { - char message[128]; - size_t pos = safecat(message, sizeof message, 0, "bit depth "); - - pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); - pos = safecat(message, sizeof message, pos, " expected "); - pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth); - - png_error(pp, message); - } - - /* If both bit depth and colour type are correct check the sample depth. - * I believe these are both internal errors. - */ - if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE) - { - if (test_pixel.sample_depth != 8) /* oops - internal error! */ - png_error(pp, "pngvalid: internal: palette sample depth not 8"); - } - else if (test_pixel.sample_depth != dp->output_bit_depth) - { - char message[128]; - size_t pos = safecat(message, sizeof message, 0, - "internal: sample depth "); - - pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); - pos = safecat(message, sizeof message, pos, " expected "); - pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth); - - png_error(pp, message); - } - } -} - -static void PNGCBAPI -transform_info(png_structp pp, png_infop pi) -{ - transform_info_imp(voidcast(transform_display*, png_get_progressive_ptr(pp)), - pp, pi); -} - -static void -transform_range_check(png_const_structp pp, unsigned int r, unsigned int g, - unsigned int b, unsigned int a, unsigned int in_digitized, double in, - unsigned int out, png_byte sample_depth, double err, double limit, - PNG_CONST char *name, double digitization_error) -{ - /* Compare the scaled, digitzed, values of our local calculation (in+-err) - * with the digitized values libpng produced; 'sample_depth' is the actual - * digitization depth of the libpng output colors (the bit depth except for - * palette images where it is always 8.) The check on 'err' is to detect - * internal errors in pngvalid itself. - */ - unsigned int max = (1U< limit || !(out >= in_min && out <= in_max)) - { - char message[256]; - size_t pos; - - pos = safecat(message, sizeof message, 0, name); - pos = safecat(message, sizeof message, pos, " output value error: rgba("); - pos = safecatn(message, sizeof message, pos, r); - pos = safecat(message, sizeof message, pos, ","); - pos = safecatn(message, sizeof message, pos, g); - pos = safecat(message, sizeof message, pos, ","); - pos = safecatn(message, sizeof message, pos, b); - pos = safecat(message, sizeof message, pos, ","); - pos = safecatn(message, sizeof message, pos, a); - pos = safecat(message, sizeof message, pos, "): "); - pos = safecatn(message, sizeof message, pos, out); - pos = safecat(message, sizeof message, pos, " expected: "); - pos = safecatn(message, sizeof message, pos, in_digitized); - pos = safecat(message, sizeof message, pos, " ("); - pos = safecatd(message, sizeof message, pos, (in-err)*max, 3); - pos = safecat(message, sizeof message, pos, ".."); - pos = safecatd(message, sizeof message, pos, (in+err)*max, 3); - pos = safecat(message, sizeof message, pos, ")"); - - png_error(pp, message); - } -} - -static void -transform_image_validate(transform_display *dp, png_const_structp pp, - png_infop pi) -{ - /* Constants for the loop below: */ - PNG_CONST png_store* PNG_CONST ps = dp->this.ps; - PNG_CONST png_byte in_ct = dp->this.colour_type; - PNG_CONST png_byte in_bd = dp->this.bit_depth; - PNG_CONST png_uint_32 w = dp->this.w; - PNG_CONST png_uint_32 h = dp->this.h; - PNG_CONST png_byte out_ct = dp->output_colour_type; - PNG_CONST png_byte out_bd = dp->output_bit_depth; - PNG_CONST png_byte sample_depth = (png_byte)(out_ct == - PNG_COLOR_TYPE_PALETTE ? 8 : out_bd); - PNG_CONST png_byte red_sBIT = dp->this.red_sBIT; - PNG_CONST png_byte green_sBIT = dp->this.green_sBIT; - PNG_CONST png_byte blue_sBIT = dp->this.blue_sBIT; - PNG_CONST png_byte alpha_sBIT = dp->this.alpha_sBIT; - PNG_CONST int have_tRNS = dp->this.is_transparent; - double digitization_error; - - store_palette out_palette; - png_uint_32 y; - - UNUSED(pi) - - /* Check for row overwrite errors */ - store_image_check(dp->this.ps, pp, 0); - - /* Read the palette corresponding to the output if the output colour type - * indicates a palette, othewise set out_palette to garbage. - */ - if (out_ct == PNG_COLOR_TYPE_PALETTE) - { - /* Validate that the palette count itself has not changed - this is not - * expected. - */ - int npalette = (-1); - - (void)read_palette(out_palette, &npalette, pp, pi); - if (npalette != dp->this.npalette) - png_error(pp, "unexpected change in palette size"); - - digitization_error = .5; - } - else - { - png_byte in_sample_depth; - - memset(out_palette, 0x5e, sizeof out_palette); - - /* use-input-precision means assume that if the input has 8 bit (or less) - * samples and the output has 16 bit samples the calculations will be done - * with 8 bit precision, not 16. - */ - if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16) - in_sample_depth = 8; - else - in_sample_depth = in_bd; - - if (sample_depth != 16 || in_sample_depth > 8 || - !dp->pm->calculations_use_input_precision) - digitization_error = .5; - - /* Else calculations are at 8 bit precision, and the output actually - * consists of scaled 8-bit values, so scale .5 in 8 bits to the 16 bits: - */ - else - digitization_error = .5 * 257; - } - - for (y=0; ythis.palette); - - in_pixel.red_sBIT = red_sBIT; - in_pixel.green_sBIT = green_sBIT; - in_pixel.blue_sBIT = blue_sBIT; - in_pixel.alpha_sBIT = alpha_sBIT; - in_pixel.have_tRNS = have_tRNS; - - /* For error detection, below. */ - r = in_pixel.red; - g = in_pixel.green; - b = in_pixel.blue; - a = in_pixel.alpha; - - dp->transform_list->mod(dp->transform_list, &in_pixel, pp, dp); - - /* Read the output pixel and compare it to what we got, we don't - * use the error field here, so no need to update sBIT. - */ - image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette); - - /* We don't expect changes to the index here even if the bit depth is - * changed. - */ - if (in_ct == PNG_COLOR_TYPE_PALETTE && - out_ct == PNG_COLOR_TYPE_PALETTE) - { - if (in_pixel.palette_index != out_pixel.palette_index) - png_error(pp, "unexpected transformed palette index"); - } - - /* Check the colours for palette images too - in fact the palette could - * be separately verified itself in most cases. - */ - if (in_pixel.red != out_pixel.red) - transform_range_check(pp, r, g, b, a, in_pixel.red, in_pixel.redf, - out_pixel.red, sample_depth, in_pixel.rede, - dp->pm->limit + 1./(2*((1U<pm->limit + 1./(2*((1U<pm->limit + 1./(2*((1U<pm->limit + 1./(2*((1U<this.ps->validated = 1; -} - -static void PNGCBAPI -transform_end(png_structp ppIn, png_infop pi) -{ - png_const_structp pp = ppIn; - transform_display *dp = voidcast(transform_display*, - png_get_progressive_ptr(pp)); - - if (!dp->this.speed) - transform_image_validate(dp, pp, pi); - else - dp->this.ps->validated = 1; -} - -/* A single test run. */ -static void -transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn, - PNG_CONST image_transform* transform_listIn, PNG_CONST char * volatile name) -{ - transform_display d; - context(&pmIn->this, fault); - - transform_display_init(&d, pmIn, idIn, transform_listIn); - - Try - { - size_t pos = 0; - png_structp pp; - png_infop pi; - char full_name[256]; - - /* Make sure the encoding fields are correct and enter the required - * modifications. - */ - transform_set_encoding(&d); - - /* Add any modifications required by the transform list. */ - d.transform_list->ini(d.transform_list, &d); - - /* Add the color space information, if any, to the name. */ - pos = safecat(full_name, sizeof full_name, pos, name); - pos = safecat_current_encoding(full_name, sizeof full_name, pos, d.pm); - - /* Get a png_struct for reading the image. */ - pp = set_modifier_for_read(d.pm, &pi, d.this.id, full_name); - standard_palette_init(&d.this); - -# if 0 - /* Logging (debugging only) */ - { - char buffer[256]; - - (void)store_message(&d.pm->this, pp, buffer, sizeof buffer, 0, - "running test"); - - fprintf(stderr, "%s\n", buffer); - } -# endif - - /* Introduce the correct read function. */ - if (d.pm->this.progressive) - { - /* Share the row function with the standard implementation. */ - png_set_progressive_read_fn(pp, &d, transform_info, progressive_row, - transform_end); - - /* Now feed data into the reader until we reach the end: */ - modifier_progressive_read(d.pm, pp, pi); - } - else - { - /* modifier_read expects a png_modifier* */ - png_set_read_fn(pp, d.pm, modifier_read); - - /* Check the header values: */ - png_read_info(pp, pi); - - /* Process the 'info' requirements. Only one image is generated */ - transform_info_imp(&d, pp, pi); - - sequential_row(&d.this, pp, pi, -1, 0); - - if (!d.this.speed) - transform_image_validate(&d, pp, pi); - else - d.this.ps->validated = 1; - } - - modifier_reset(d.pm); - } - - Catch(fault) - { - modifier_reset(voidcast(png_modifier*,(void*)fault)); - } -} - -/* The transforms: */ -#define ITSTRUCT(name) image_transform_##name -#define ITDATA(name) image_transform_data_##name -#define image_transform_ini image_transform_default_ini -#define IT(name)\ -static image_transform ITSTRUCT(name) =\ -{\ - #name,\ - 1, /*enable*/\ - &PT, /*list*/\ - 0, /*global_use*/\ - 0, /*local_use*/\ - 0, /*next*/\ - image_transform_ini,\ - image_transform_png_set_##name##_set,\ - image_transform_png_set_##name##_mod,\ - image_transform_png_set_##name##_add\ -} -#define PT ITSTRUCT(end) /* stores the previous transform */ - -/* To save code: */ -static void -image_transform_default_ini(PNG_CONST image_transform *this, - transform_display *that) -{ - this->next->ini(this->next, that); -} - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -static int -image_transform_default_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(colour_type) - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - return 1; -} -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* png_set_palette_to_rgb */ -static void -image_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_palette_to_rgb(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - if (that->colour_type == PNG_COLOR_TYPE_PALETTE) - image_pixel_convert_PLTE(that); - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_palette_to_rgb_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - return colour_type == PNG_COLOR_TYPE_PALETTE; -} - -IT(palette_to_rgb); -#undef PT -#define PT ITSTRUCT(palette_to_rgb) -#endif /* PNG_READ_EXPAND_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* png_set_tRNS_to_alpha */ -static void -image_transform_png_set_tRNS_to_alpha_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_tRNS_to_alpha(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - /* LIBPNG BUG: this always forces palette images to RGB. */ - if (that->colour_type == PNG_COLOR_TYPE_PALETTE) - image_pixel_convert_PLTE(that); - - /* This effectively does an 'expand' only if there is some transparency to - * convert to an alpha channel. - */ - if (that->have_tRNS) - image_pixel_add_alpha(that, &display->this); - - /* LIBPNG BUG: otherwise libpng still expands to 8 bits! */ - else - { - if (that->bit_depth < 8) - that->bit_depth =8; - if (that->sample_depth < 8) - that->sample_depth = 8; - } - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_tRNS_to_alpha_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - /* We don't know yet whether there will be a tRNS chunk, but we know that - * this transformation should do nothing if there already is an alpha - * channel. - */ - return (colour_type & PNG_COLOR_MASK_ALPHA) == 0; -} - -IT(tRNS_to_alpha); -#undef PT -#define PT ITSTRUCT(tRNS_to_alpha) -#endif /* PNG_READ_EXPAND_SUPPORTED */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -/* png_set_gray_to_rgb */ -static void -image_transform_png_set_gray_to_rgb_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_gray_to_rgb(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - /* NOTE: we can actually pend the tRNS processing at this point because we - * can correctly recognize the original pixel value even though we have - * mapped the one gray channel to the three RGB ones, but in fact libpng - * doesn't do this, so we don't either. - */ - if ((that->colour_type & PNG_COLOR_MASK_COLOR) == 0 && that->have_tRNS) - image_pixel_add_alpha(that, &display->this); - - /* Simply expand the bit depth and alter the colour type as required. */ - if (that->colour_type == PNG_COLOR_TYPE_GRAY) - { - /* RGB images have a bit depth at least equal to '8' */ - if (that->bit_depth < 8) - that->sample_depth = that->bit_depth = 8; - - /* And just changing the colour type works here because the green and blue - * channels are being maintained in lock-step with the red/gray: - */ - that->colour_type = PNG_COLOR_TYPE_RGB; - } - - else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) - that->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_gray_to_rgb_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - return (colour_type & PNG_COLOR_MASK_COLOR) == 0; -} - -IT(gray_to_rgb); -#undef PT -#define PT ITSTRUCT(gray_to_rgb) -#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* png_set_expand */ -static void -image_transform_png_set_expand_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_expand(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_expand_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - /* The general expand case depends on what the colour type is: */ - if (that->colour_type == PNG_COLOR_TYPE_PALETTE) - image_pixel_convert_PLTE(that); - else if (that->bit_depth < 8) /* grayscale */ - that->sample_depth = that->bit_depth = 8; - - if (that->have_tRNS) - image_pixel_add_alpha(that, &display->this); - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_expand_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - /* 'expand' should do nothing for RGBA or GA input - no tRNS and the bit - * depth is at least 8 already. - */ - return (colour_type & PNG_COLOR_MASK_ALPHA) == 0; -} - -IT(expand); -#undef PT -#define PT ITSTRUCT(expand) -#endif /* PNG_READ_EXPAND_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* png_set_expand_gray_1_2_4_to_8 - * LIBPNG BUG: this just does an 'expand' - */ -static void -image_transform_png_set_expand_gray_1_2_4_to_8_set( - PNG_CONST image_transform *this, transform_display *that, png_structp pp, - png_infop pi) -{ - png_set_expand_gray_1_2_4_to_8(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_expand_gray_1_2_4_to_8_mod( - PNG_CONST image_transform *this, image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - image_transform_png_set_expand_mod(this, that, pp, display); -} - -static int -image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - return image_transform_png_set_expand_add(this, that, colour_type, - bit_depth); -} - -IT(expand_gray_1_2_4_to_8); -#undef PT -#define PT ITSTRUCT(expand_gray_1_2_4_to_8) -#endif /* PNG_READ_EXPAND_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_16_SUPPORTED -/* png_set_expand_16 */ -static void -image_transform_png_set_expand_16_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_expand_16(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - /* Expect expand_16 to expand everything to 16 bits as a result of also - * causing 'expand' to happen. - */ - if (that->colour_type == PNG_COLOR_TYPE_PALETTE) - image_pixel_convert_PLTE(that); - - if (that->have_tRNS) - image_pixel_add_alpha(that, &display->this); - - if (that->bit_depth < 16) - that->sample_depth = that->bit_depth = 16; - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_expand_16_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(colour_type) - - this->next = *that; - *that = this; - - /* expand_16 does something unless the bit depth is already 16. */ - return bit_depth < 16; -} - -IT(expand_16); -#undef PT -#define PT ITSTRUCT(expand_16) -#endif /* PNG_READ_EXPAND_16_SUPPORTED */ - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* API added in 1.5.4 */ -/* png_set_scale_16 */ -static void -image_transform_png_set_scale_16_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_scale_16(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_scale_16_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - if (that->bit_depth == 16) - { - that->sample_depth = that->bit_depth = 8; - if (that->red_sBIT > 8) that->red_sBIT = 8; - if (that->green_sBIT > 8) that->green_sBIT = 8; - if (that->blue_sBIT > 8) that->blue_sBIT = 8; - if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; - } - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_scale_16_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(colour_type) - - this->next = *that; - *that = this; - - return bit_depth > 8; -} - -IT(scale_16); -#undef PT -#define PT ITSTRUCT(scale_16) -#endif /* PNG_READ_SCALE_16_TO_8_SUPPORTED (1.5.4 on) */ - -#ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */ -/* png_set_strip_16 */ -static void -image_transform_png_set_strip_16_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_strip_16(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - if (that->bit_depth == 16) - { - that->sample_depth = that->bit_depth = 8; - if (that->red_sBIT > 8) that->red_sBIT = 8; - if (that->green_sBIT > 8) that->green_sBIT = 8; - if (that->blue_sBIT > 8) that->blue_sBIT = 8; - if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; - - /* Prior to 1.5.4 png_set_strip_16 would use an 'accurate' method if this - * configuration option is set. From 1.5.4 the flag is never set and the - * 'scale' API (above) must be used. - */ -# ifdef PNG_READ_ACCURATE_SCALE_SUPPORTED -# if PNG_LIBPNG_VER >= 10504 -# error PNG_READ_ACCURATE_SCALE should not be set -# endif - - /* The strip 16 algorithm drops the low 8 bits rather than calculating - * 1/257, so we need to adjust the permitted errors appropriately: - * Notice that this is only relevant prior to the addition of the - * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!) - */ - { - PNG_CONST double d = (255-128.5)/65535; - that->rede += d; - that->greene += d; - that->bluee += d; - that->alphae += d; - } -# endif - } - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_strip_16_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(colour_type) - - this->next = *that; - *that = this; - - return bit_depth > 8; -} - -IT(strip_16); -#undef PT -#define PT ITSTRUCT(strip_16) -#endif /* PNG_READ_16_TO_8_SUPPORTED */ - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -/* png_set_strip_alpha */ -static void -image_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_strip_alpha(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) - that->colour_type = PNG_COLOR_TYPE_GRAY; - else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) - that->colour_type = PNG_COLOR_TYPE_RGB; - - that->have_tRNS = 0; - that->alphaf = 1; - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_strip_alpha_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - return (colour_type & PNG_COLOR_MASK_ALPHA) != 0; -} - -IT(strip_alpha); -#undef PT -#define PT ITSTRUCT(strip_alpha) -#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */ - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -/* png_set_rgb_to_gray(png_structp, int err_action, double red, double green) - * png_set_rgb_to_gray_fixed(png_structp, int err_action, png_fixed_point red, - * png_fixed_point green) - * png_get_rgb_to_gray_status - * - * The 'default' test here uses values known to be used inside libpng: - * - * red: 6968 - * green: 23434 - * blue: 2366 - * - * These values are being retained for compatibility, along with the somewhat - * broken truncation calculation in the fast-and-inaccurate code path. Older - * versions of libpng will fail the accuracy tests below because they use the - * truncation algorithm everywhere. - */ -#define data ITDATA(rgb_to_gray) -static struct -{ - double gamma; /* File gamma to use in processing */ - - /* The following are the parameters for png_set_rgb_to_gray: */ -# ifdef PNG_FLOATING_POINT_SUPPORTED - double red_to_set; - double green_to_set; -# else - png_fixed_point red_to_set; - png_fixed_point green_to_set; -# endif - - /* The actual coefficients: */ - double red_coefficient; - double green_coefficient; - double blue_coefficient; - - /* Set if the coeefficients have been overridden. */ - int coefficients_overridden; -} data; - -#undef image_transform_ini -#define image_transform_ini image_transform_png_set_rgb_to_gray_ini -static void -image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this, - transform_display *that) -{ - png_modifier *pm = that->pm; - PNG_CONST color_encoding *e = pm->current_encoding; - - UNUSED(this) - - /* Since we check the encoding this flag must be set: */ - pm->test_uses_encoding = 1; - - /* If 'e' is not NULL chromaticity information is present and either a cHRM - * or an sRGB chunk will be inserted. - */ - if (e != 0) - { - /* Coefficients come from the encoding, but may need to be normalized to a - * white point Y of 1.0 - */ - PNG_CONST double whiteY = e->red.Y + e->green.Y + e->blue.Y; - - data.red_coefficient = e->red.Y; - data.green_coefficient = e->green.Y; - data.blue_coefficient = e->blue.Y; - - if (whiteY != 1) - { - data.red_coefficient /= whiteY; - data.green_coefficient /= whiteY; - data.blue_coefficient /= whiteY; - } - } - - else - { - /* The default (built in) coeffcients, as above: */ - data.red_coefficient = 6968 / 32768.; - data.green_coefficient = 23434 / 32768.; - data.blue_coefficient = 2366 / 32768.; - } - - data.gamma = pm->current_gamma; - - /* If not set then the calculations assume linear encoding (implicitly): */ - if (data.gamma == 0) - data.gamma = 1; - - /* The arguments to png_set_rgb_to_gray can override the coefficients implied - * by the color space encoding. If doing exhaustive checks do the override - * in each case, otherwise do it randomly. - */ - if (pm->test_exhaustive) - { - /* First time in coefficients_overridden is 0, the following sets it to 1, - * so repeat if it is set. If a test fails this may mean we subsequently - * skip a non-override test, ignore that. - */ - data.coefficients_overridden = !data.coefficients_overridden; - pm->repeat = data.coefficients_overridden != 0; - } - - else - data.coefficients_overridden = random_choice(); - - if (data.coefficients_overridden) - { - /* These values override the color encoding defaults, simply use random - * numbers. - */ - png_uint_32 ru; - double total; - - RANDOMIZE(ru); - data.green_coefficient = total = (ru & 0xffff) / 65535.; - ru >>= 16; - data.red_coefficient = (1 - total) * (ru & 0xffff) / 65535.; - total += data.red_coefficient; - data.blue_coefficient = 1 - total; - -# ifdef PNG_FLOATING_POINT_SUPPORTED - data.red_to_set = data.red_coefficient; - data.green_to_set = data.green_coefficient; -# else - data.red_to_set = fix(data.red_coefficient); - data.green_to_set = fix(data.green_coefficient); -# endif - - /* The following just changes the error messages: */ - pm->encoding_ignored = 1; - } - - else - { - data.red_to_set = -1; - data.green_to_set = -1; - } - - /* Adjust the error limit in the png_modifier because of the larger errors - * produced in the digitization during the gamma handling. - */ - if (data.gamma != 1) /* Use gamma tables */ - { - if (that->this.bit_depth == 16 || pm->assume_16_bit_calculations) - { - /* The computations have the form: - * - * r * rc + g * gc + b * bc - * - * Each component of which is +/-1/65535 from the gamma_to_1 table - * lookup, resulting in a base error of +/-6. The gamma_from_1 - * conversion adds another +/-2 in the 16-bit case and - * +/-(1<<(15-PNG_MAX_GAMMA_8)) in the 8-bit case. - */ - that->pm->limit += pow( -# if PNG_MAX_GAMMA_8 < 14 - (that->this.bit_depth == 16 ? 8. : - 6. + (1<<(15-PNG_MAX_GAMMA_8))) -# else - 8. -# endif - /65535, data.gamma); - } - - else - { - /* Rounding to 8 bits in the linear space causes massive errors which - * will trigger the error check in transform_range_check. Fix that - * here by taking the gamma encoding into account. - * - * When DIGITIZE is set because a pre-1.7 version of libpng is being - * tested allow a bigger slack. - * - * NOTE: this magic number was determined by experiment to be 1.1 (when - * using fixed point arithmetic). There's no great merit to the value - * below, however it only affects the limit used for checking for - * internal calculation errors, not the actual limit imposed by - * pngvalid on the output errors. - */ - that->pm->limit += pow( -# if DIGITIZE - 1.1 -# else - 1. -# endif - /255, data.gamma); - } - } - - else - { - /* With no gamma correction a large error comes from the truncation of the - * calculation in the 8 bit case, allow for that here. - */ - if (that->this.bit_depth != 16 && !pm->assume_16_bit_calculations) - that->pm->limit += 4E-3; - } -} - -static void -image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - PNG_CONST int error_action = 1; /* no error, no defines in png.h */ - -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_rgb_to_gray(pp, error_action, data.red_to_set, data.green_to_set); -# else - png_set_rgb_to_gray_fixed(pp, error_action, data.red_to_set, - data.green_to_set); -# endif - -# ifdef PNG_READ_cHRM_SUPPORTED - if (that->pm->current_encoding != 0) - { - /* We have an encoding so a cHRM chunk may have been set; if so then - * check that the libpng APIs give the correct (X,Y,Z) values within - * some margin of error for the round trip through the chromaticity - * form. - */ -# ifdef PNG_FLOATING_POINT_SUPPORTED -# define API_function png_get_cHRM_XYZ -# define API_form "FP" -# define API_type double -# define API_cvt(x) (x) -# else -# define API_function png_get_cHRM_XYZ_fixed -# define API_form "fixed" -# define API_type png_fixed_point -# define API_cvt(x) ((double)(x)/PNG_FP_1) -# endif - - API_type rX, gX, bX; - API_type rY, gY, bY; - API_type rZ, gZ, bZ; - - if ((API_function(pp, pi, &rX, &rY, &rZ, &gX, &gY, &gZ, &bX, &bY, &bZ) - & PNG_INFO_cHRM) != 0) - { - double maxe; - PNG_CONST char *el; - color_encoding e, o; - - /* Expect libpng to return a normalized result, but the original - * color space encoding may not be normalized. - */ - modifier_current_encoding(that->pm, &o); - normalize_color_encoding(&o); - - /* Sanity check the pngvalid code - the coefficients should match - * the normalized Y values of the encoding unless they were - * overridden. - */ - if (data.red_to_set == -1 && data.green_to_set == -1 && - (fabs(o.red.Y - data.red_coefficient) > DBL_EPSILON || - fabs(o.green.Y - data.green_coefficient) > DBL_EPSILON || - fabs(o.blue.Y - data.blue_coefficient) > DBL_EPSILON)) - png_error(pp, "internal pngvalid cHRM coefficient error"); - - /* Generate a colour space encoding. */ - e.gamma = o.gamma; /* not used */ - e.red.X = API_cvt(rX); - e.red.Y = API_cvt(rY); - e.red.Z = API_cvt(rZ); - e.green.X = API_cvt(gX); - e.green.Y = API_cvt(gY); - e.green.Z = API_cvt(gZ); - e.blue.X = API_cvt(bX); - e.blue.Y = API_cvt(bY); - e.blue.Z = API_cvt(bZ); - - /* This should match the original one from the png_modifier, within - * the range permitted by the libpng fixed point representation. - */ - maxe = 0; - el = "-"; /* Set to element name with error */ - -# define CHECK(col,x)\ - {\ - double err = fabs(o.col.x - e.col.x);\ - if (err > maxe)\ - {\ - maxe = err;\ - el = #col "(" #x ")";\ - }\ - } - - CHECK(red,X) - CHECK(red,Y) - CHECK(red,Z) - CHECK(green,X) - CHECK(green,Y) - CHECK(green,Z) - CHECK(blue,X) - CHECK(blue,Y) - CHECK(blue,Z) - - /* Here in both fixed and floating cases to check the values read - * from the cHRm chunk. PNG uses fixed point in the cHRM chunk, so - * we can't expect better than +/-.5E-5 on the result, allow 1E-5. - */ - if (maxe >= 1E-5) - { - size_t pos = 0; - char buffer[256]; - - pos = safecat(buffer, sizeof buffer, pos, API_form); - pos = safecat(buffer, sizeof buffer, pos, " cHRM "); - pos = safecat(buffer, sizeof buffer, pos, el); - pos = safecat(buffer, sizeof buffer, pos, " error: "); - pos = safecatd(buffer, sizeof buffer, pos, maxe, 7); - pos = safecat(buffer, sizeof buffer, pos, " "); - /* Print the color space without the gamma value: */ - pos = safecat_color_encoding(buffer, sizeof buffer, pos, &o, 0); - pos = safecat(buffer, sizeof buffer, pos, " -> "); - pos = safecat_color_encoding(buffer, sizeof buffer, pos, &e, 0); - - png_error(pp, buffer); - } - } - } -# endif /* READ_cHRM */ - - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - if ((that->colour_type & PNG_COLOR_MASK_COLOR) != 0) - { - double gray, err; - - if (that->colour_type == PNG_COLOR_TYPE_PALETTE) - image_pixel_convert_PLTE(that); - - /* Image now has RGB channels... */ -# if DIGITIZE - { - PNG_CONST png_modifier *pm = display->pm; - const unsigned int sample_depth = that->sample_depth; - const unsigned int calc_depth = (pm->assume_16_bit_calculations ? 16 : - sample_depth); - const unsigned int gamma_depth = (sample_depth == 16 ? 16 : - (pm->assume_16_bit_calculations ? PNG_MAX_GAMMA_8 : sample_depth)); - int isgray; - double r, g, b; - double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi; - - /* Do this using interval arithmetic, otherwise it is too difficult to - * handle the errors correctly. - * - * To handle the gamma correction work out the upper and lower bounds - * of the digitized value. Assume rounding here - normally the values - * will be identical after this operation if there is only one - * transform, feel free to delete the png_error checks on this below in - * the future (this is just me trying to ensure it works!) - */ - r = rlo = rhi = that->redf; - rlo -= that->rede; - rlo = digitize(rlo, calc_depth, 1/*round*/); - rhi += that->rede; - rhi = digitize(rhi, calc_depth, 1/*round*/); - - g = glo = ghi = that->greenf; - glo -= that->greene; - glo = digitize(glo, calc_depth, 1/*round*/); - ghi += that->greene; - ghi = digitize(ghi, calc_depth, 1/*round*/); - - b = blo = bhi = that->bluef; - blo -= that->bluee; - blo = digitize(blo, calc_depth, 1/*round*/); - bhi += that->greene; - bhi = digitize(bhi, calc_depth, 1/*round*/); - - isgray = r==g && g==b; - - if (data.gamma != 1) - { - PNG_CONST double power = 1/data.gamma; - PNG_CONST double abse = calc_depth == 16 ? .5/65535 : .5/255; - - /* 'abse' is the absolute error permitted in linear calculations. It - * is used here to capture the error permitted in the handling - * (undoing) of the gamma encoding. Once again digitization occurs - * to handle the upper and lower bounds of the values. This is - * where the real errors are introduced. - */ - r = pow(r, power); - rlo = digitize(pow(rlo, power)-abse, calc_depth, 1); - rhi = digitize(pow(rhi, power)+abse, calc_depth, 1); - - g = pow(g, power); - glo = digitize(pow(glo, power)-abse, calc_depth, 1); - ghi = digitize(pow(ghi, power)+abse, calc_depth, 1); - - b = pow(b, power); - blo = digitize(pow(blo, power)-abse, calc_depth, 1); - bhi = digitize(pow(bhi, power)+abse, calc_depth, 1); - } - - /* Now calculate the actual gray values. Although the error in the - * coefficients depends on whether they were specified on the command - * line (in which case truncation to 15 bits happened) or not (rounding - * was used) the maxium error in an individual coefficient is always - * 1/32768, because even in the rounding case the requirement that - * coefficients add up to 32768 can cause a larger rounding error. - * - * The only time when rounding doesn't occur in 1.5.5 and later is when - * the non-gamma code path is used for less than 16 bit data. - */ - gray = r * data.red_coefficient + g * data.green_coefficient + - b * data.blue_coefficient; - - { - PNG_CONST int do_round = data.gamma != 1 || calc_depth == 16; - PNG_CONST double ce = 1. / 32768; - - graylo = digitize(rlo * (data.red_coefficient-ce) + - glo * (data.green_coefficient-ce) + - blo * (data.blue_coefficient-ce), gamma_depth, do_round); - if (graylo <= 0) - graylo = 0; - - grayhi = digitize(rhi * (data.red_coefficient+ce) + - ghi * (data.green_coefficient+ce) + - bhi * (data.blue_coefficient+ce), gamma_depth, do_round); - if (grayhi >= 1) - grayhi = 1; - } - - /* And invert the gamma. */ - if (data.gamma != 1) - { - PNG_CONST double power = data.gamma; - - gray = pow(gray, power); - graylo = digitize(pow(graylo, power), sample_depth, 1); - grayhi = digitize(pow(grayhi, power), sample_depth, 1); - } - - /* Now the error can be calculated. - * - * If r==g==b because there is no overall gamma correction libpng - * currently preserves the original value. - */ - if (isgray) - err = (that->rede + that->greene + that->bluee)/3; - - else - { - err = fabs(grayhi-gray); - if (fabs(gray - graylo) > err) - err = fabs(graylo-gray); - - /* Check that this worked: */ - if (err > pm->limit) - { - size_t pos = 0; - char buffer[128]; - - pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error "); - pos = safecatd(buffer, sizeof buffer, pos, err, 6); - pos = safecat(buffer, sizeof buffer, pos, " exceeds limit "); - pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6); - png_error(pp, buffer); - } - } - } -# else /* DIGITIZE */ - { - double r = that->redf; - double re = that->rede; - double g = that->greenf; - double ge = that->greene; - double b = that->bluef; - double be = that->bluee; - - /* The true gray case involves no math. */ - if (r == g && r == b) - { - gray = r; - err = re; - if (err < ge) err = ge; - if (err < be) err = be; - } - - else if (data.gamma == 1) - { - /* There is no need to do the conversions to and from linear space, - * so the calculation should be a lot more accurate. There is a - * built in 1/32768 error in the coefficients because they only have - * 15 bits and are adjusted to make sure they add up to 32768, so - * the result may have an additional error up to 1/32768. (Note - * that adding the 1/32768 here avoids needing to increase the - * global error limits to take this into account.) - */ - gray = r * data.red_coefficient + g * data.green_coefficient + - b * data.blue_coefficient; - err = re * data.red_coefficient + ge * data.green_coefficient + - be * data.blue_coefficient + 1./32768 + gray * 5 * DBL_EPSILON; - } - - else - { - /* The calculation happens in linear space, and this produces much - * wider errors in the encoded space. These are handled here by - * factoring the errors in to the calculation. There are two table - * lookups in the calculation and each introduces a quantization - * error defined by the table size. - */ - PNG_CONST png_modifier *pm = display->pm; - double in_qe = (that->sample_depth > 8 ? .5/65535 : .5/255); - double out_qe = (that->sample_depth > 8 ? .5/65535 : - (pm->assume_16_bit_calculations ? .5/(1< 1) rhi = 1; - r -= re + in_qe; if (r < 0) r = 0; - ghi = g + ge + in_qe; if (ghi > 1) ghi = 1; - g -= ge + in_qe; if (g < 0) g = 0; - bhi = b + be + in_qe; if (bhi > 1) bhi = 1; - b -= be + in_qe; if (b < 0) b = 0; - - r = pow(r, g1)*(1-DBL_EPSILON); rhi = pow(rhi, g1)*(1+DBL_EPSILON); - g = pow(g, g1)*(1-DBL_EPSILON); ghi = pow(ghi, g1)*(1+DBL_EPSILON); - b = pow(b, g1)*(1-DBL_EPSILON); bhi = pow(bhi, g1)*(1+DBL_EPSILON); - - /* Work out the lower and upper bounds for the gray value in the - * encoded space, then work out an average and error. Remove the - * previously added input quantization error at this point. - */ - gray = r * data.red_coefficient + g * data.green_coefficient + - b * data.blue_coefficient - 1./32768 - out_qe; - if (gray <= 0) - gray = 0; - else - { - gray *= (1 - 6 * DBL_EPSILON); - gray = pow(gray, data.gamma) * (1-DBL_EPSILON); - } - - grayhi = rhi * data.red_coefficient + ghi * data.green_coefficient + - bhi * data.blue_coefficient + 1./32768 + out_qe; - grayhi *= (1 + 6 * DBL_EPSILON); - if (grayhi >= 1) - grayhi = 1; - else - grayhi = pow(grayhi, data.gamma) * (1+DBL_EPSILON); - - err = (grayhi - gray) / 2; - gray = (grayhi + gray) / 2; - - if (err <= in_qe) - err = gray * DBL_EPSILON; - - else - err -= in_qe; - - /* Validate that the error is within limits (this has caused - * problems before, it's much easier to detect them here.) - */ - if (err > pm->limit) - { - size_t pos = 0; - char buffer[128]; - - pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error "); - pos = safecatd(buffer, sizeof buffer, pos, err, 6); - pos = safecat(buffer, sizeof buffer, pos, " exceeds limit "); - pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6); - png_error(pp, buffer); - } - } - } -# endif /* !DIGITIZE */ - - that->bluef = that->greenf = that->redf = gray; - that->bluee = that->greene = that->rede = err; - - /* The sBIT is the minium of the three colour channel sBITs. */ - if (that->red_sBIT > that->green_sBIT) - that->red_sBIT = that->green_sBIT; - if (that->red_sBIT > that->blue_sBIT) - that->red_sBIT = that->blue_sBIT; - that->blue_sBIT = that->green_sBIT = that->red_sBIT; - - /* And remove the colour bit in the type: */ - if (that->colour_type == PNG_COLOR_TYPE_RGB) - that->colour_type = PNG_COLOR_TYPE_GRAY; - else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) - that->colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; - } - - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_rgb_to_gray_add(image_transform *this, - PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) -{ - UNUSED(bit_depth) - - this->next = *that; - *that = this; - - return (colour_type & PNG_COLOR_MASK_COLOR) != 0; -} - -#undef data -IT(rgb_to_gray); -#undef PT -#define PT ITSTRUCT(rgb_to_gray) -#undef image_transform_ini -#define image_transform_ini image_transform_default_ini -#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */ - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -/* png_set_background(png_structp, png_const_color_16p background_color, - * int background_gamma_code, int need_expand, double background_gamma) - * png_set_background_fixed(png_structp, png_const_color_16p background_color, - * int background_gamma_code, int need_expand, - * png_fixed_point background_gamma) - * - * This ignores the gamma (at present.) -*/ -#define data ITDATA(background) -static image_pixel data; - -static void -image_transform_png_set_background_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_byte colour_type, bit_depth; - png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */ - int expand; - png_color_16 back; - - /* We need a background colour, because we don't know exactly what transforms - * have been set we have to supply the colour in the original file format and - * so we need to know what that is! The background colour is stored in the - * transform_display. - */ - RANDOMIZE(random_bytes); - - /* Read the random value, for colour type 3 the background colour is actually - * expressed as a 24bit rgb, not an index. - */ - colour_type = that->this.colour_type; - if (colour_type == 3) - { - colour_type = PNG_COLOR_TYPE_RGB; - bit_depth = 8; - expand = 0; /* passing in an RGB not a pixel index */ - } - - else - { - bit_depth = that->this.bit_depth; - expand = 1; - } - - image_pixel_init(&data, random_bytes, colour_type, - bit_depth, 0/*x*/, 0/*unused: palette*/); - - /* Extract the background colour from this image_pixel, but make sure the - * unused fields of 'back' are garbage. - */ - RANDOMIZE(back); - - if (colour_type & PNG_COLOR_MASK_COLOR) - { - back.red = (png_uint_16)data.red; - back.green = (png_uint_16)data.green; - back.blue = (png_uint_16)data.blue; - } - - else - back.gray = (png_uint_16)data.red; - -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0); -# else - png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0); -# endif - - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_background_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - /* Check for tRNS first: */ - if (that->have_tRNS && that->colour_type != PNG_COLOR_TYPE_PALETTE) - image_pixel_add_alpha(that, &display->this); - - /* This is only necessary if the alpha value is less than 1. */ - if (that->alphaf < 1) - { - /* Now we do the background calculation without any gamma correction. */ - if (that->alphaf <= 0) - { - that->redf = data.redf; - that->greenf = data.greenf; - that->bluef = data.bluef; - - that->rede = data.rede; - that->greene = data.greene; - that->bluee = data.bluee; - - that->red_sBIT= data.red_sBIT; - that->green_sBIT= data.green_sBIT; - that->blue_sBIT= data.blue_sBIT; - } - - else /* 0 < alpha < 1 */ - { - double alf = 1 - that->alphaf; - - that->redf = that->redf * that->alphaf + data.redf * alf; - that->rede = that->rede * that->alphaf + data.rede * alf + - DBL_EPSILON; - that->greenf = that->greenf * that->alphaf + data.greenf * alf; - that->greene = that->greene * that->alphaf + data.greene * alf + - DBL_EPSILON; - that->bluef = that->bluef * that->alphaf + data.bluef * alf; - that->bluee = that->bluee * that->alphaf + data.bluee * alf + - DBL_EPSILON; - } - - /* Remove the alpha type and set the alpha (not in that order.) */ - that->alphaf = 1; - that->alphae = 0; - - if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) - that->colour_type = PNG_COLOR_TYPE_RGB; - else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) - that->colour_type = PNG_COLOR_TYPE_GRAY; - /* PNG_COLOR_TYPE_PALETTE is not changed */ - } - - this->next->mod(this->next, that, pp, display); -} - -#define image_transform_png_set_background_add image_transform_default_add - -#undef data -IT(background); -#undef PT -#define PT ITSTRUCT(background) -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - -/* This may just be 'end' if all the transforms are disabled! */ -static image_transform *PNG_CONST image_transform_first = &PT; - -static void -transform_enable(PNG_CONST char *name) -{ - /* Everything starts out enabled, so if we see an 'enable' disabled - * everything else the first time round. - */ - static int all_disabled = 0; - int found_it = 0; - image_transform *list = image_transform_first; - - while (list != &image_transform_end) - { - if (strcmp(list->name, name) == 0) - { - list->enable = 1; - found_it = 1; - } - else if (!all_disabled) - list->enable = 0; - - list = list->list; - } - - all_disabled = 1; - - if (!found_it) - { - fprintf(stderr, "pngvalid: --transform-enable=%s: unknown transform\n", - name); - exit(99); - } -} - -static void -transform_disable(PNG_CONST char *name) -{ - image_transform *list = image_transform_first; - - while (list != &image_transform_end) - { - if (strcmp(list->name, name) == 0) - { - list->enable = 0; - return; - } - - list = list->list; - } - - fprintf(stderr, "pngvalid: --transform-disable=%s: unknown transform\n", - name); - exit(99); -} - -static void -image_transform_reset_count(void) -{ - image_transform *next = image_transform_first; - int count = 0; - - while (next != &image_transform_end) - { - next->local_use = 0; - next->next = 0; - next = next->list; - ++count; - } - - /* This can only happen if we every have more than 32 transforms (excluding - * the end) in the list. - */ - if (count > 32) abort(); -} - -static int -image_transform_test_counter(png_uint_32 counter, unsigned int max) -{ - /* Test the list to see if there is any point contining, given a current - * counter and a 'max' value. - */ - image_transform *next = image_transform_first; - - while (next != &image_transform_end) - { - /* For max 0 or 1 continue until the counter overflows: */ - counter >>= 1; - - /* Continue if any entry hasn't reacked the max. */ - if (max > 1 && next->local_use < max) - return 1; - next = next->list; - } - - return max <= 1 && counter == 0; -} - -static png_uint_32 -image_transform_add(PNG_CONST image_transform **this, unsigned int max, - png_uint_32 counter, char *name, size_t sizeof_name, size_t *pos, - png_byte colour_type, png_byte bit_depth) -{ - for (;;) /* until we manage to add something */ - { - png_uint_32 mask; - image_transform *list; - - /* Find the next counter value, if the counter is zero this is the start - * of the list. This routine always returns the current counter (not the - * next) so it returns 0 at the end and expects 0 at the beginning. - */ - if (counter == 0) /* first time */ - { - image_transform_reset_count(); - if (max <= 1) - counter = 1; - else - counter = random_32(); - } - else /* advance the counter */ - { - switch (max) - { - case 0: ++counter; break; - case 1: counter <<= 1; break; - default: counter = random_32(); break; - } - } - - /* Now add all these items, if possible */ - *this = &image_transform_end; - list = image_transform_first; - mask = 1; - - /* Go through the whole list adding anything that the counter selects: */ - while (list != &image_transform_end) - { - if ((counter & mask) != 0 && list->enable && - (max == 0 || list->local_use < max)) - { - /* Candidate to add: */ - if (list->add(list, this, colour_type, bit_depth) || max == 0) - { - /* Added, so add to the name too. */ - *pos = safecat(name, sizeof_name, *pos, " +"); - *pos = safecat(name, sizeof_name, *pos, list->name); - } - - else - { - /* Not useful and max>0, so remove it from *this: */ - *this = list->next; - list->next = 0; - - /* And, since we know it isn't useful, stop it being added again - * in this run: - */ - list->local_use = max; - } - } - - mask <<= 1; - list = list->list; - } - - /* Now if anything was added we have something to do. */ - if (*this != &image_transform_end) - return counter; - - /* Nothing added, but was there anything in there to add? */ - if (!image_transform_test_counter(counter, max)) - return 0; - } -} - -#ifdef THIS_IS_THE_PROFORMA -static void -image_transform_png_set_@_set(PNG_CONST image_transform *this, - transform_display *that, png_structp pp, png_infop pi) -{ - png_set_@(pp); - this->next->set(this->next, that, pp, pi); -} - -static void -image_transform_png_set_@_mod(PNG_CONST image_transform *this, - image_pixel *that, png_const_structp pp, - PNG_CONST transform_display *display) -{ - this->next->mod(this->next, that, pp, display); -} - -static int -image_transform_png_set_@_add(image_transform *this, - PNG_CONST image_transform **that, char *name, size_t sizeof_name, - size_t *pos, png_byte colour_type, png_byte bit_depth) -{ - this->next = *that; - *that = this; - - *pos = safecat(name, sizeof_name, *pos, " +@"); - - return 1; -} - -IT(@); -#endif - -/* png_set_quantize(png_structp, png_colorp palette, int num_palette, - * int maximum_colors, png_const_uint_16p histogram, int full_quantize) - * - * Very difficult to validate this! - */ -/*NOTE: TBD NYI */ - -/* The data layout transforms are handled by swapping our own channel data, - * necessarily these need to happen at the end of the transform list because the - * semantic of the channels changes after these are executed. Some of these, - * like set_shift and set_packing, can't be done at present because they change - * the layout of the data at the sub-sample level so sample() won't get the - * right answer. - */ -/* png_set_invert_alpha */ -/*NOTE: TBD NYI */ - -/* png_set_bgr */ -/*NOTE: TBD NYI */ - -/* png_set_swap_alpha */ -/*NOTE: TBD NYI */ - -/* png_set_swap */ -/*NOTE: TBD NYI */ - -/* png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags)); */ -/*NOTE: TBD NYI */ - -/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */ -/*NOTE: TBD NYI */ - -/* png_set_packing */ -/*NOTE: TBD NYI */ - -/* png_set_packswap */ -/*NOTE: TBD NYI */ - -/* png_set_invert_mono */ -/*NOTE: TBD NYI */ - -/* png_set_shift(png_structp, png_const_color_8p true_bits) */ -/*NOTE: TBD NYI */ - -static void -perform_transform_test(png_modifier *pm) -{ - png_byte colour_type = 0; - png_byte bit_depth = 0; - unsigned int palette_number = 0; - - while (next_format(&colour_type, &bit_depth, &palette_number, 0)) - { - png_uint_32 counter = 0; - size_t base_pos; - char name[64]; - - base_pos = safecat(name, sizeof name, 0, "transform:"); - - for (;;) - { - size_t pos = base_pos; - PNG_CONST image_transform *list = 0; - - /* 'max' is currently hardwired to '1'; this should be settable on the - * command line. - */ - counter = image_transform_add(&list, 1/*max*/, counter, - name, sizeof name, &pos, colour_type, bit_depth); - - if (counter == 0) - break; - - /* The command line can change this to checking interlaced images. */ - do - { - pm->repeat = 0; - transform_test(pm, FILEID(colour_type, bit_depth, palette_number, - pm->interlace_type, 0, 0, 0), list, name); - - if (fail(pm)) - return; - } - while (pm->repeat); - } - } -} -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -/********************************* GAMMA TESTS ********************************/ -#ifdef PNG_READ_GAMMA_SUPPORTED -/* Reader callbacks and implementations, where they differ from the standard - * ones. - */ -typedef struct gamma_display -{ - standard_display this; - - /* Parameters */ - png_modifier* pm; - double file_gamma; - double screen_gamma; - double background_gamma; - png_byte sbit; - int threshold_test; - int use_input_precision; - int scale16; - int expand16; - int do_background; - png_color_16 background_color; - - /* Local variables */ - double maxerrout; - double maxerrpc; - double maxerrabs; -} gamma_display; - -#define ALPHA_MODE_OFFSET 4 - -static void -gamma_display_init(gamma_display *dp, png_modifier *pm, png_uint_32 id, - double file_gamma, double screen_gamma, png_byte sbit, int threshold_test, - int use_input_precision, int scale16, int expand16, - int do_background, PNG_CONST png_color_16 *pointer_to_the_background_color, - double background_gamma) -{ - /* Standard fields */ - standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/, - pm->use_update_info); - - /* Parameter fields */ - dp->pm = pm; - dp->file_gamma = file_gamma; - dp->screen_gamma = screen_gamma; - dp->background_gamma = background_gamma; - dp->sbit = sbit; - dp->threshold_test = threshold_test; - dp->use_input_precision = use_input_precision; - dp->scale16 = scale16; - dp->expand16 = expand16; - dp->do_background = do_background; - if (do_background && pointer_to_the_background_color != 0) - dp->background_color = *pointer_to_the_background_color; - else - memset(&dp->background_color, 0, sizeof dp->background_color); - - /* Local variable fields */ - dp->maxerrout = dp->maxerrpc = dp->maxerrabs = 0; -} - -static void -gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi) -{ - /* Reuse the standard stuff as appropriate. */ - standard_info_part1(&dp->this, pp, pi); - - /* If requested strip 16 to 8 bits - this is handled automagically below - * because the output bit depth is read from the library. Note that there - * are interactions with sBIT but, internally, libpng makes sbit at most - * PNG_MAX_GAMMA_8 when doing the following. - */ - if (dp->scale16) -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - png_set_scale_16(pp); -# else - /* The following works both in 1.5.4 and earlier versions: */ -# ifdef PNG_READ_16_TO_8_SUPPORTED - png_set_strip_16(pp); -# else - png_error(pp, "scale16 (16 to 8 bit conversion) not supported"); -# endif -# endif - - if (dp->expand16) -# ifdef PNG_READ_EXPAND_16_SUPPORTED - png_set_expand_16(pp); -# else - png_error(pp, "expand16 (8 to 16 bit conversion) not supported"); -# endif - - if (dp->do_background >= ALPHA_MODE_OFFSET) - { -# ifdef PNG_READ_ALPHA_MODE_SUPPORTED - { - /* This tests the alpha mode handling, if supported. */ - int mode = dp->do_background - ALPHA_MODE_OFFSET; - - /* The gamma value is the output gamma, and is in the standard, - * non-inverted, represenation. It provides a default for the PNG file - * gamma, but since the file has a gAMA chunk this does not matter. - */ - PNG_CONST double sg = dp->screen_gamma; -# ifndef PNG_FLOATING_POINT_SUPPORTED - PNG_CONST png_fixed_point g = fix(sg); -# endif - -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_alpha_mode(pp, mode, sg); -# else - png_set_alpha_mode_fixed(pp, mode, g); -# endif - - /* However, for the standard Porter-Duff algorithm the output defaults - * to be linear, so if the test requires non-linear output it must be - * corrected here. - */ - if (mode == PNG_ALPHA_STANDARD && sg != 1) - { -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_gamma(pp, sg, dp->file_gamma); -# else - png_fixed_point f = fix(dp->file_gamma); - png_set_gamma_fixed(pp, g, f); -# endif - } - } -# else - png_error(pp, "alpha mode handling not supported"); -# endif - } - - else - { - /* Set up gamma processing. */ -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_gamma(pp, dp->screen_gamma, dp->file_gamma); -# else - { - png_fixed_point s = fix(dp->screen_gamma); - png_fixed_point f = fix(dp->file_gamma); - png_set_gamma_fixed(pp, s, f); - } -# endif - - if (dp->do_background) - { -# ifdef PNG_READ_BACKGROUND_SUPPORTED - /* NOTE: this assumes the caller provided the correct background gamma! - */ - PNG_CONST double bg = dp->background_gamma; -# ifndef PNG_FLOATING_POINT_SUPPORTED - PNG_CONST png_fixed_point g = fix(bg); -# endif - -# ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_background(pp, &dp->background_color, dp->do_background, - 0/*need_expand*/, bg); -# else - png_set_background_fixed(pp, &dp->background_color, - dp->do_background, 0/*need_expand*/, g); -# endif -# else - png_error(pp, "png_set_background not supported"); -# endif - } - } - - { - int i = dp->this.use_update_info; - /* Always do one call, even if use_update_info is 0. */ - do - png_read_update_info(pp, pi); - while (--i > 0); - } - - /* Now we may get a different cbRow: */ - standard_info_part2(&dp->this, pp, pi, 1 /*images*/); -} - -static void PNGCBAPI -gamma_info(png_structp pp, png_infop pi) -{ - gamma_info_imp(voidcast(gamma_display*, png_get_progressive_ptr(pp)), pp, - pi); -} - -/* Validate a single component value - the routine gets the input and output - * sample values as unscaled PNG component values along with a cache of all the - * information required to validate the values. - */ -typedef struct validate_info -{ - png_const_structp pp; - gamma_display *dp; - png_byte sbit; - int use_input_precision; - int do_background; - int scale16; - unsigned int sbit_max; - unsigned int isbit_shift; - unsigned int outmax; - - double gamma_correction; /* Overall correction required. */ - double file_inverse; /* Inverse of file gamma. */ - double screen_gamma; - double screen_inverse; /* Inverse of screen gamma. */ - - double background_red; /* Linear background value, red or gray. */ - double background_green; - double background_blue; - - double maxabs; - double maxpc; - double maxcalc; - double maxout; - double maxout_total; /* Total including quantization error */ - double outlog; - int outquant; -} -validate_info; - -static void -init_validate_info(validate_info *vi, gamma_display *dp, png_const_structp pp, - int in_depth, int out_depth) -{ - PNG_CONST unsigned int outmax = (1U<pp = pp; - vi->dp = dp; - - if (dp->sbit > 0 && dp->sbit < in_depth) - { - vi->sbit = dp->sbit; - vi->isbit_shift = in_depth - dp->sbit; - } - - else - { - vi->sbit = (png_byte)in_depth; - vi->isbit_shift = 0; - } - - vi->sbit_max = (1U << vi->sbit)-1; - - /* This mimics the libpng threshold test, '0' is used to prevent gamma - * correction in the validation test. - */ - vi->screen_gamma = dp->screen_gamma; - if (fabs(vi->screen_gamma-1) < PNG_GAMMA_THRESHOLD) - vi->screen_gamma = vi->screen_inverse = 0; - else - vi->screen_inverse = 1/vi->screen_gamma; - - vi->use_input_precision = dp->use_input_precision; - vi->outmax = outmax; - vi->maxabs = abserr(dp->pm, in_depth, out_depth); - vi->maxpc = pcerr(dp->pm, in_depth, out_depth); - vi->maxcalc = calcerr(dp->pm, in_depth, out_depth); - vi->maxout = outerr(dp->pm, in_depth, out_depth); - vi->outquant = output_quantization_factor(dp->pm, in_depth, out_depth); - vi->maxout_total = vi->maxout + vi->outquant * .5; - vi->outlog = outlog(dp->pm, in_depth, out_depth); - - if ((dp->this.colour_type & PNG_COLOR_MASK_ALPHA) != 0 || - (dp->this.colour_type == 3 && dp->this.is_transparent)) - { - vi->do_background = dp->do_background; - - if (vi->do_background != 0) - { - PNG_CONST double bg_inverse = 1/dp->background_gamma; - double r, g, b; - - /* Caller must at least put the gray value into the red channel */ - r = dp->background_color.red; r /= outmax; - g = dp->background_color.green; g /= outmax; - b = dp->background_color.blue; b /= outmax; - -# if 0 - /* libpng doesn't do this optimization, if we do pngvalid will fail. - */ - if (fabs(bg_inverse-1) >= PNG_GAMMA_THRESHOLD) -# endif - { - r = pow(r, bg_inverse); - g = pow(g, bg_inverse); - b = pow(b, bg_inverse); - } - - vi->background_red = r; - vi->background_green = g; - vi->background_blue = b; - } - } - else - vi->do_background = 0; - - if (vi->do_background == 0) - vi->background_red = vi->background_green = vi->background_blue = 0; - - vi->gamma_correction = 1/(dp->file_gamma*dp->screen_gamma); - if (fabs(vi->gamma_correction-1) < PNG_GAMMA_THRESHOLD) - vi->gamma_correction = 0; - - vi->file_inverse = 1/dp->file_gamma; - if (fabs(vi->file_inverse-1) < PNG_GAMMA_THRESHOLD) - vi->file_inverse = 0; - - vi->scale16 = dp->scale16; -} - -/* This function handles composition of a single non-alpha component. The - * argument is the input sample value, in the range 0..1, and the alpha value. - * The result is the composed, linear, input sample. If alpha is less than zero - * this is the alpha component and the function should not be called! - */ -static double -gamma_component_compose(int do_background, double input_sample, double alpha, - double background, int *compose) -{ - switch (do_background) - { -#ifdef PNG_READ_BACKGROUND_SUPPORTED - case PNG_BACKGROUND_GAMMA_SCREEN: - case PNG_BACKGROUND_GAMMA_FILE: - case PNG_BACKGROUND_GAMMA_UNIQUE: - /* Standard PNG background processing. */ - if (alpha < 1) - { - if (alpha > 0) - { - input_sample = input_sample * alpha + background * (1-alpha); - if (compose != NULL) - *compose = 1; - } - - else - input_sample = background; - } - break; -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: - case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: - /* The components are premultiplied in either case and the output is - * gamma encoded (to get standard Porter-Duff we expect the output - * gamma to be set to 1.0!) - */ - case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: - /* The optimization is that the partial-alpha entries are linear - * while the opaque pixels are gamma encoded, but this only affects the - * output encoding. - */ - if (alpha < 1) - { - if (alpha > 0) - { - input_sample *= alpha; - if (compose != NULL) - *compose = 1; - } - - else - input_sample = 0; - } - break; -#endif - - default: - /* Standard cases where no compositing is done (so the component - * value is already correct.) - */ - UNUSED(alpha) - UNUSED(background) - UNUSED(compose) - break; - } - - return input_sample; -} - -/* This API returns the encoded *input* component, in the range 0..1 */ -static double -gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi, - PNG_CONST unsigned int id, PNG_CONST unsigned int od, - PNG_CONST double alpha /* <0 for the alpha channel itself */, - PNG_CONST double background /* component background value */) -{ - PNG_CONST unsigned int isbit = id >> vi->isbit_shift; - PNG_CONST unsigned int sbit_max = vi->sbit_max; - PNG_CONST unsigned int outmax = vi->outmax; - PNG_CONST int do_background = vi->do_background; - - double i; - - /* First check on the 'perfect' result obtained from the digitized input - * value, id, and compare this against the actual digitized result, 'od'. - * 'i' is the input result in the range 0..1: - */ - i = isbit; i /= sbit_max; - - /* Check for the fast route: if we don't do any background composition or if - * this is the alpha channel ('alpha' < 0) or if the pixel is opaque then - * just use the gamma_correction field to correct to the final output gamma. - */ - if (alpha == 1 /* opaque pixel component */ || !do_background -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - || do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_PNG -#endif - || (alpha < 0 /* alpha channel */ -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - && do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN -#endif - )) - { - /* Then get the gamma corrected version of 'i' and compare to 'od', any - * error less than .5 is insignificant - just quantization of the output - * value to the nearest digital value (nevertheless the error is still - * recorded - it's interesting ;-) - */ - double encoded_sample = i; - double encoded_error; - - /* alpha less than 0 indicates the alpha channel, which is always linear - */ - if (alpha >= 0 && vi->gamma_correction > 0) - encoded_sample = pow(encoded_sample, vi->gamma_correction); - encoded_sample *= outmax; - - encoded_error = fabs(od-encoded_sample); - - if (encoded_error > vi->dp->maxerrout) - vi->dp->maxerrout = encoded_error; - - if (encoded_error < vi->maxout_total && encoded_error < vi->outlog) - return i; - } - - /* The slow route - attempt to do linear calculations. */ - /* There may be an error, or background processing is required, so calculate - * the actual sample values - unencoded light intensity values. Note that in - * practice these are not completely unencoded because they include a - * 'viewing correction' to decrease or (normally) increase the perceptual - * contrast of the image. There's nothing we can do about this - we don't - * know what it is - so assume the unencoded value is perceptually linear. - */ - { - double input_sample = i; /* In range 0..1 */ - double output, error, encoded_sample, encoded_error; - double es_lo, es_hi; - int compose = 0; /* Set to one if composition done */ - int output_is_encoded; /* Set if encoded to screen gamma */ - int log_max_error = 1; /* Check maximum error values */ - png_const_charp pass = 0; /* Reason test passes (or 0 for fail) */ - - /* Convert to linear light (with the above caveat.) The alpha channel is - * already linear. - */ - if (alpha >= 0) - { - int tcompose; - - if (vi->file_inverse > 0) - input_sample = pow(input_sample, vi->file_inverse); - - /* Handle the compose processing: */ - tcompose = 0; - input_sample = gamma_component_compose(do_background, input_sample, - alpha, background, &tcompose); - - if (tcompose) - compose = 1; - } - - /* And similarly for the output value, but we need to check the background - * handling to linearize it correctly. - */ - output = od; - output /= outmax; - - output_is_encoded = vi->screen_gamma > 0; - - if (alpha < 0) /* The alpha channel */ - { -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - if (do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN) -#endif - { - /* In all other cases the output alpha channel is linear already, - * don't log errors here, they are much larger in linear data. - */ - output_is_encoded = 0; - log_max_error = 0; - } - } - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - else /* A component */ - { - if (do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED && - alpha < 1) /* the optimized case - linear output */ - { - if (alpha > 0) log_max_error = 0; - output_is_encoded = 0; - } - } -#endif - - if (output_is_encoded) - output = pow(output, vi->screen_gamma); - - /* Calculate (or recalculate) the encoded_sample value and repeat the - * check above (unnecessary if we took the fast route, but harmless.) - */ - encoded_sample = input_sample; - if (output_is_encoded) - encoded_sample = pow(encoded_sample, vi->screen_inverse); - encoded_sample *= outmax; - - encoded_error = fabs(od-encoded_sample); - - /* Don't log errors in the alpha channel, or the 'optimized' case, - * neither are significant to the overall perception. - */ - if (log_max_error && encoded_error > vi->dp->maxerrout) - vi->dp->maxerrout = encoded_error; - - if (encoded_error < vi->maxout_total) - { - if (encoded_error < vi->outlog) - return i; - - /* Test passed but error is bigger than the log limit, record why the - * test passed: - */ - pass = "less than maxout:\n"; - } - - /* i: the original input value in the range 0..1 - * - * pngvalid calculations: - * input_sample: linear result; i linearized and composed, range 0..1 - * encoded_sample: encoded result; input_sample scaled to ouput bit depth - * - * libpng calculations: - * output: linear result; od scaled to 0..1 and linearized - * od: encoded result from libpng - */ - - /* Now we have the numbers for real errors, both absolute values as as a - * percentage of the correct value (output): - */ - error = fabs(input_sample-output); - - if (log_max_error && error > vi->dp->maxerrabs) - vi->dp->maxerrabs = error; - - /* The following is an attempt to ignore the tendency of quantization to - * dominate the percentage errors for lower result values: - */ - if (log_max_error && input_sample > .5) - { - double percentage_error = error/input_sample; - if (percentage_error > vi->dp->maxerrpc) - vi->dp->maxerrpc = percentage_error; - } - - /* Now calculate the digitization limits for 'encoded_sample' using the - * 'max' values. Note that maxout is in the encoded space but maxpc and - * maxabs are in linear light space. - * - * First find the maximum error in linear light space, range 0..1: - */ - { - double tmp = input_sample * vi->maxpc; - if (tmp < vi->maxabs) tmp = vi->maxabs; - /* If 'compose' is true the composition was done in linear space using - * integer arithmetic. This introduces an extra error of +/- 0.5 (at - * least) in the integer space used. 'maxcalc' records this, taking - * into account the possibility that even for 16 bit output 8 bit space - * may have been used. - */ - if (compose && tmp < vi->maxcalc) tmp = vi->maxcalc; - - /* The 'maxout' value refers to the encoded result, to compare with - * this encode input_sample adjusted by the maximum error (tmp) above. - */ - es_lo = encoded_sample - vi->maxout; - - if (es_lo > 0 && input_sample-tmp > 0) - { - double low_value = input_sample-tmp; - if (output_is_encoded) - low_value = pow(low_value, vi->screen_inverse); - low_value *= outmax; - if (low_value < es_lo) es_lo = low_value; - - /* Quantize this appropriately: */ - es_lo = ceil(es_lo / vi->outquant - .5) * vi->outquant; - } - - else - es_lo = 0; - - es_hi = encoded_sample + vi->maxout; - - if (es_hi < outmax && input_sample+tmp < 1) - { - double high_value = input_sample+tmp; - if (output_is_encoded) - high_value = pow(high_value, vi->screen_inverse); - high_value *= outmax; - if (high_value > es_hi) es_hi = high_value; - - es_hi = floor(es_hi / vi->outquant + .5) * vi->outquant; - } - - else - es_hi = outmax; - } - - /* The primary test is that the final encoded value returned by the - * library should be between the two limits (inclusive) that were - * calculated above. - */ - if (od >= es_lo && od <= es_hi) - { - /* The value passes, but we may need to log the information anyway. */ - if (encoded_error < vi->outlog) - return i; - - if (pass == 0) - pass = "within digitization limits:\n"; - } - - { - /* There has been an error in processing, or we need to log this - * value. - */ - double is_lo, is_hi; - - /* pass is set at this point if either of the tests above would have - * passed. Don't do these additional tests here - just log the - * original [es_lo..es_hi] values. - */ - if (pass == 0 && vi->use_input_precision && vi->dp->sbit) - { - /* Ok, something is wrong - this actually happens in current libpng - * 16-to-8 processing. Assume that the input value (id, adjusted - * for sbit) can be anywhere between value-.5 and value+.5 - quite a - * large range if sbit is low. - * - * NOTE: at present because the libpng gamma table stuff has been - * changed to use a rounding algorithm to correct errors in 8-bit - * calculations the precise sbit calculation (a shift) has been - * lost. This can result in up to a +/-1 error in the presence of - * an sbit less than the bit depth. - */ -# if PNG_LIBPNG_VER < 10700 -# define SBIT_ERROR .5 -# else -# define SBIT_ERROR 1. -# endif - double tmp = (isbit - SBIT_ERROR)/sbit_max; - - if (tmp <= 0) - tmp = 0; - - else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) - tmp = pow(tmp, vi->file_inverse); - - tmp = gamma_component_compose(do_background, tmp, alpha, background, - NULL); - - if (output_is_encoded && tmp > 0 && tmp < 1) - tmp = pow(tmp, vi->screen_inverse); - - is_lo = ceil(outmax * tmp - vi->maxout_total); - - if (is_lo < 0) - is_lo = 0; - - tmp = (isbit + SBIT_ERROR)/sbit_max; - - if (tmp >= 1) - tmp = 1; - - else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) - tmp = pow(tmp, vi->file_inverse); - - tmp = gamma_component_compose(do_background, tmp, alpha, background, - NULL); - - if (output_is_encoded && tmp > 0 && tmp < 1) - tmp = pow(tmp, vi->screen_inverse); - - is_hi = floor(outmax * tmp + vi->maxout_total); - - if (is_hi > outmax) - is_hi = outmax; - - if (!(od < is_lo || od > is_hi)) - { - if (encoded_error < vi->outlog) - return i; - - pass = "within input precision limits:\n"; - } - - /* One last chance. If this is an alpha channel and the 16to8 - * option has been used and 'inaccurate' scaling is used then the - * bit reduction is obtained by simply using the top 8 bits of the - * value. - * - * This is only done for older libpng versions when the 'inaccurate' - * (chop) method of scaling was used. - */ -# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED -# if PNG_LIBPNG_VER < 10504 - /* This may be required for other components in the future, - * but at present the presence of gamma correction effectively - * prevents the errors in the component scaling (I don't quite - * understand why, but since it's better this way I care not - * to ask, JB 20110419.) - */ - if (pass == 0 && alpha < 0 && vi->scale16 && vi->sbit > 8 && - vi->sbit + vi->isbit_shift == 16) - { - tmp = ((id >> 8) - .5)/255; - - if (tmp > 0) - { - is_lo = ceil(outmax * tmp - vi->maxout_total); - if (is_lo < 0) is_lo = 0; - } - - else - is_lo = 0; - - tmp = ((id >> 8) + .5)/255; - - if (tmp < 1) - { - is_hi = floor(outmax * tmp + vi->maxout_total); - if (is_hi > outmax) is_hi = outmax; - } - - else - is_hi = outmax; - - if (!(od < is_lo || od > is_hi)) - { - if (encoded_error < vi->outlog) - return i; - - pass = "within 8 bit limits:\n"; - } - } -# endif -# endif - } - else /* !use_input_precision */ - is_lo = es_lo, is_hi = es_hi; - - /* Attempt to output a meaningful error/warning message: the message - * output depends on the background/composite operation being performed - * because this changes what parameters were actually used above. - */ - { - size_t pos = 0; - /* Need either 1/255 or 1/65535 precision here; 3 or 6 decimal - * places. Just use outmax to work out which. - */ - int precision = (outmax >= 1000 ? 6 : 3); - int use_input=1, use_background=0, do_compose=0; - char msg[256]; - - if (pass != 0) - pos = safecat(msg, sizeof msg, pos, "\n\t"); - - /* Set up the various flags, the output_is_encoded flag above - * is also used below. do_compose is just a double check. - */ - switch (do_background) - { -# ifdef PNG_READ_BACKGROUND_SUPPORTED - case PNG_BACKGROUND_GAMMA_SCREEN: - case PNG_BACKGROUND_GAMMA_FILE: - case PNG_BACKGROUND_GAMMA_UNIQUE: - use_background = (alpha >= 0 && alpha < 1); - /*FALL THROUGH*/ -# endif -# ifdef PNG_READ_ALPHA_MODE_SUPPORTED - case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: - case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: - case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: -# endif /* ALPHA_MODE_SUPPORTED */ - do_compose = (alpha > 0 && alpha < 1); - use_input = (alpha != 0); - break; - - default: - break; - } - - /* Check the 'compose' flag */ - if (compose != do_compose) - png_error(vi->pp, "internal error (compose)"); - - /* 'name' is the component name */ - pos = safecat(msg, sizeof msg, pos, name); - pos = safecat(msg, sizeof msg, pos, "("); - pos = safecatn(msg, sizeof msg, pos, id); - if (use_input || pass != 0/*logging*/) - { - if (isbit != id) - { - /* sBIT has reduced the precision of the input: */ - pos = safecat(msg, sizeof msg, pos, ", sbit("); - pos = safecatn(msg, sizeof msg, pos, vi->sbit); - pos = safecat(msg, sizeof msg, pos, "): "); - pos = safecatn(msg, sizeof msg, pos, isbit); - } - pos = safecat(msg, sizeof msg, pos, "/"); - /* The output is either "id/max" or "id sbit(sbit): isbit/max" */ - pos = safecatn(msg, sizeof msg, pos, vi->sbit_max); - } - pos = safecat(msg, sizeof msg, pos, ")"); - - /* A component may have been multiplied (in linear space) by the - * alpha value, 'compose' says whether this is relevant. - */ - if (compose || pass != 0) - { - /* If any form of composition is being done report our - * calculated linear value here (the code above doesn't record - * the input value before composition is performed, so what - * gets reported is the value after composition.) - */ - if (use_input || pass != 0) - { - if (vi->file_inverse > 0) - { - pos = safecat(msg, sizeof msg, pos, "^"); - pos = safecatd(msg, sizeof msg, pos, vi->file_inverse, 2); - } - - else - pos = safecat(msg, sizeof msg, pos, "[linear]"); - - pos = safecat(msg, sizeof msg, pos, "*(alpha)"); - pos = safecatd(msg, sizeof msg, pos, alpha, precision); - } - - /* Now record the *linear* background value if it was used - * (this function is not passed the original, non-linear, - * value but it is contained in the test name.) - */ - if (use_background) - { - pos = safecat(msg, sizeof msg, pos, use_input ? "+" : " "); - pos = safecat(msg, sizeof msg, pos, "(background)"); - pos = safecatd(msg, sizeof msg, pos, background, precision); - pos = safecat(msg, sizeof msg, pos, "*"); - pos = safecatd(msg, sizeof msg, pos, 1-alpha, precision); - } - } - - /* Report the calculated value (input_sample) and the linearized - * libpng value (output) unless this is just a component gamma - * correction. - */ - if (compose || alpha < 0 || pass != 0) - { - pos = safecat(msg, sizeof msg, pos, - pass != 0 ? " =\n\t" : " = "); - pos = safecatd(msg, sizeof msg, pos, input_sample, precision); - pos = safecat(msg, sizeof msg, pos, " (libpng: "); - pos = safecatd(msg, sizeof msg, pos, output, precision); - pos = safecat(msg, sizeof msg, pos, ")"); - - /* Finally report the output gamma encoding, if any. */ - if (output_is_encoded) - { - pos = safecat(msg, sizeof msg, pos, " ^"); - pos = safecatd(msg, sizeof msg, pos, vi->screen_inverse, 2); - pos = safecat(msg, sizeof msg, pos, "(to screen) ="); - } - - else - pos = safecat(msg, sizeof msg, pos, " [screen is linear] ="); - } - - if ((!compose && alpha >= 0) || pass != 0) - { - if (pass != 0) /* logging */ - pos = safecat(msg, sizeof msg, pos, "\n\t[overall:"); - - /* This is the non-composition case, the internal linear - * values are irrelevant (though the log below will reveal - * them.) Output a much shorter warning/error message and report - * the overall gamma correction. - */ - if (vi->gamma_correction > 0) - { - pos = safecat(msg, sizeof msg, pos, " ^"); - pos = safecatd(msg, sizeof msg, pos, vi->gamma_correction, 2); - pos = safecat(msg, sizeof msg, pos, "(gamma correction) ="); - } - - else - pos = safecat(msg, sizeof msg, pos, - " [no gamma correction] ="); - - if (pass != 0) - pos = safecat(msg, sizeof msg, pos, "]"); - } - - /* This is our calculated encoded_sample which should (but does - * not) match od: - */ - pos = safecat(msg, sizeof msg, pos, pass != 0 ? "\n\t" : " "); - pos = safecatd(msg, sizeof msg, pos, is_lo, 1); - pos = safecat(msg, sizeof msg, pos, " < "); - pos = safecatd(msg, sizeof msg, pos, encoded_sample, 1); - pos = safecat(msg, sizeof msg, pos, " (libpng: "); - pos = safecatn(msg, sizeof msg, pos, od); - pos = safecat(msg, sizeof msg, pos, ")"); - pos = safecat(msg, sizeof msg, pos, "/"); - pos = safecatn(msg, sizeof msg, pos, outmax); - pos = safecat(msg, sizeof msg, pos, " < "); - pos = safecatd(msg, sizeof msg, pos, is_hi, 1); - - if (pass == 0) /* The error condition */ - { -# ifdef PNG_WARNINGS_SUPPORTED - png_warning(vi->pp, msg); -# else - store_warning(vi->pp, msg); -# endif - } - - else /* logging this value */ - store_verbose(&vi->dp->pm->this, vi->pp, pass, msg); - } - } - } - - return i; -} - -static void -gamma_image_validate(gamma_display *dp, png_const_structp pp, - png_infop pi) -{ - /* Get some constants derived from the input and output file formats: */ - PNG_CONST png_store* PNG_CONST ps = dp->this.ps; - PNG_CONST png_byte in_ct = dp->this.colour_type; - PNG_CONST png_byte in_bd = dp->this.bit_depth; - PNG_CONST png_uint_32 w = dp->this.w; - PNG_CONST png_uint_32 h = dp->this.h; - PNG_CONST size_t cbRow = dp->this.cbRow; - PNG_CONST png_byte out_ct = png_get_color_type(pp, pi); - PNG_CONST png_byte out_bd = png_get_bit_depth(pp, pi); - - /* There are three sources of error, firstly the quantization in the - * file encoding, determined by sbit and/or the file depth, secondly - * the output (screen) gamma and thirdly the output file encoding. - * - * Since this API receives the screen and file gamma in double - * precision it is possible to calculate an exact answer given an input - * pixel value. Therefore we assume that the *input* value is exact - - * sample/maxsample - calculate the corresponding gamma corrected - * output to the limits of double precision arithmetic and compare with - * what libpng returns. - * - * Since the library must quantize the output to 8 or 16 bits there is - * a fundamental limit on the accuracy of the output of +/-.5 - this - * quantization limit is included in addition to the other limits - * specified by the paramaters to the API. (Effectively, add .5 - * everywhere.) - * - * The behavior of the 'sbit' paramter is defined by section 12.5 - * (sample depth scaling) of the PNG spec. That section forces the - * decoder to assume that the PNG values have been scaled if sBIT is - * present: - * - * png-sample = floor( input-sample * (max-out/max-in) + .5); - * - * This means that only a subset of the possible PNG values should - * appear in the input. However, the spec allows the encoder to use a - * variety of approximations to the above and doesn't require any - * restriction of the values produced. - * - * Nevertheless the spec requires that the upper 'sBIT' bits of the - * value stored in a PNG file be the original sample bits. - * Consequently the code below simply scales the top sbit bits by - * (1<this.palette; - PNG_CONST int in_is_transparent = dp->this.is_transparent; - int out_npalette = -1; - int out_is_transparent = 0; /* Just refers to the palette case */ - store_palette out_palette; - validate_info vi; - - /* Check for row overwrite errors */ - store_image_check(dp->this.ps, pp, 0); - - /* Supply the input and output sample depths here - 8 for an indexed image, - * otherwise the bit depth. - */ - init_validate_info(&vi, dp, pp, in_ct==3?8:in_bd, out_ct==3?8:out_bd); - - processing = (vi.gamma_correction > 0 && !dp->threshold_test) - || in_bd != out_bd || in_ct != out_ct || vi.do_background; - - /* TODO: FIX THIS: MAJOR BUG! If the transformations all happen inside - * the palette there is no way of finding out, because libpng fails to - * update the palette on png_read_update_info. Indeed, libpng doesn't - * even do the required work until much later, when it doesn't have any - * info pointer. Oops. For the moment 'processing' is turned off if - * out_ct is palette. - */ - if (in_ct == 3 && out_ct == 3) - processing = 0; - - if (processing && out_ct == 3) - out_is_transparent = read_palette(out_palette, &out_npalette, pp, pi); - - for (y=0; ythis.palette[in_index].alpha : - sample(std, in_ct, in_bd, x, samples_per_pixel); - - unsigned int output_alpha = 65536 /* as a flag value */; - - if (out_ct == 3) - { - if (out_is_transparent) - output_alpha = out_palette[out_index].alpha; - } - - else if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0) - output_alpha = sample(pRow, out_ct, out_bd, x, - samples_per_pixel); - - if (output_alpha != 65536) - alpha = gamma_component_validate("alpha", &vi, input_alpha, - output_alpha, -1/*alpha*/, 0/*background*/); - - else /* no alpha in output */ - { - /* This is a copy of the calculation of 'i' above in order to - * have the alpha value to use in the background calculation. - */ - alpha = input_alpha >> vi.isbit_shift; - alpha /= vi.sbit_max; - } - } - - /* Handle grayscale or RGB components. */ - if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* grayscale */ - (void)gamma_component_validate("gray", &vi, - sample(std, in_ct, in_bd, x, 0), - sample(pRow, out_ct, out_bd, x, 0), alpha/*component*/, - vi.background_red); - else /* RGB or palette */ - { - (void)gamma_component_validate("red", &vi, - in_ct == 3 ? in_palette[in_index].red : - sample(std, in_ct, in_bd, x, 0), - out_ct == 3 ? out_palette[out_index].red : - sample(pRow, out_ct, out_bd, x, 0), - alpha/*component*/, vi.background_red); - - (void)gamma_component_validate("green", &vi, - in_ct == 3 ? in_palette[in_index].green : - sample(std, in_ct, in_bd, x, 1), - out_ct == 3 ? out_palette[out_index].green : - sample(pRow, out_ct, out_bd, x, 1), - alpha/*component*/, vi.background_green); - - (void)gamma_component_validate("blue", &vi, - in_ct == 3 ? in_palette[in_index].blue : - sample(std, in_ct, in_bd, x, 2), - out_ct == 3 ? out_palette[out_index].blue : - sample(pRow, out_ct, out_bd, x, 2), - alpha/*component*/, vi.background_blue); - } - } - } - - else if (memcmp(std, pRow, cbRow) != 0) - { - char msg[64]; - - /* No transform is expected on the threshold tests. */ - sprintf(msg, "gamma: below threshold row %lu changed", - (unsigned long)y); - - png_error(pp, msg); - } - } /* row (y) loop */ - - dp->this.ps->validated = 1; -} - -static void PNGCBAPI -gamma_end(png_structp ppIn, png_infop pi) -{ - png_const_structp pp = ppIn; - gamma_display *dp = voidcast(gamma_display*, png_get_progressive_ptr(pp)); - - if (!dp->this.speed) - gamma_image_validate(dp, pp, pi); - else - dp->this.ps->validated = 1; -} - -/* A single test run checking a gamma transformation. - * - * maxabs: maximum absolute error as a fraction - * maxout: maximum output error in the output units - * maxpc: maximum percentage error (as a percentage) - */ -static void -gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn, - PNG_CONST png_byte bit_depthIn, PNG_CONST int palette_numberIn, - PNG_CONST int interlace_typeIn, - PNG_CONST double file_gammaIn, PNG_CONST double screen_gammaIn, - PNG_CONST png_byte sbitIn, PNG_CONST int threshold_testIn, - PNG_CONST char *name, - PNG_CONST int use_input_precisionIn, PNG_CONST int scale16In, - PNG_CONST int expand16In, PNG_CONST int do_backgroundIn, - PNG_CONST png_color_16 *bkgd_colorIn, double bkgd_gammaIn) -{ - gamma_display d; - context(&pmIn->this, fault); - - gamma_display_init(&d, pmIn, FILEID(colour_typeIn, bit_depthIn, - palette_numberIn, interlace_typeIn, 0, 0, 0), - file_gammaIn, screen_gammaIn, sbitIn, - threshold_testIn, use_input_precisionIn, scale16In, - expand16In, do_backgroundIn, bkgd_colorIn, bkgd_gammaIn); - - Try - { - png_structp pp; - png_infop pi; - gama_modification gama_mod; - srgb_modification srgb_mod; - sbit_modification sbit_mod; - - /* For the moment don't use the png_modifier support here. */ - d.pm->encoding_counter = 0; - modifier_set_encoding(d.pm); /* Just resets everything */ - d.pm->current_gamma = d.file_gamma; - - /* Make an appropriate modifier to set the PNG file gamma to the - * given gamma value and the sBIT chunk to the given precision. - */ - d.pm->modifications = NULL; - gama_modification_init(&gama_mod, d.pm, d.file_gamma); - srgb_modification_init(&srgb_mod, d.pm, 127 /*delete*/); - if (d.sbit > 0) - sbit_modification_init(&sbit_mod, d.pm, d.sbit); - - modification_reset(d.pm->modifications); - - /* Get a png_struct for writing the image. */ - pp = set_modifier_for_read(d.pm, &pi, d.this.id, name); - standard_palette_init(&d.this); - - /* Introduce the correct read function. */ - if (d.pm->this.progressive) - { - /* Share the row function with the standard implementation. */ - png_set_progressive_read_fn(pp, &d, gamma_info, progressive_row, - gamma_end); - - /* Now feed data into the reader until we reach the end: */ - modifier_progressive_read(d.pm, pp, pi); - } - else - { - /* modifier_read expects a png_modifier* */ - png_set_read_fn(pp, d.pm, modifier_read); - - /* Check the header values: */ - png_read_info(pp, pi); - - /* Process the 'info' requirements. Only one image is generated */ - gamma_info_imp(&d, pp, pi); - - sequential_row(&d.this, pp, pi, -1, 0); - - if (!d.this.speed) - gamma_image_validate(&d, pp, pi); - else - d.this.ps->validated = 1; - } - - modifier_reset(d.pm); - - if (d.pm->log && !d.threshold_test && !d.this.speed) - fprintf(stderr, "%d bit %s %s: max error %f (%.2g, %2g%%)\n", - d.this.bit_depth, colour_types[d.this.colour_type], name, - d.maxerrout, d.maxerrabs, 100*d.maxerrpc); - - /* Log the summary values too. */ - if (d.this.colour_type == 0 || d.this.colour_type == 4) - { - switch (d.this.bit_depth) - { - case 1: - break; - - case 2: - if (d.maxerrout > d.pm->error_gray_2) - d.pm->error_gray_2 = d.maxerrout; - - break; - - case 4: - if (d.maxerrout > d.pm->error_gray_4) - d.pm->error_gray_4 = d.maxerrout; - - break; - - case 8: - if (d.maxerrout > d.pm->error_gray_8) - d.pm->error_gray_8 = d.maxerrout; - - break; - - case 16: - if (d.maxerrout > d.pm->error_gray_16) - d.pm->error_gray_16 = d.maxerrout; - - break; - - default: - png_error(pp, "bad bit depth (internal: 1)"); - } - } - - else if (d.this.colour_type == 2 || d.this.colour_type == 6) - { - switch (d.this.bit_depth) - { - case 8: - - if (d.maxerrout > d.pm->error_color_8) - d.pm->error_color_8 = d.maxerrout; - - break; - - case 16: - - if (d.maxerrout > d.pm->error_color_16) - d.pm->error_color_16 = d.maxerrout; - - break; - - default: - png_error(pp, "bad bit depth (internal: 2)"); - } - } - - else if (d.this.colour_type == 3) - { - if (d.maxerrout > d.pm->error_indexed) - d.pm->error_indexed = d.maxerrout; - } - } - - Catch(fault) - modifier_reset(voidcast(png_modifier*,(void*)fault)); -} - -static void gamma_threshold_test(png_modifier *pm, png_byte colour_type, - png_byte bit_depth, int interlace_type, double file_gamma, - double screen_gamma) -{ - size_t pos = 0; - char name[64]; - pos = safecat(name, sizeof name, pos, "threshold "); - pos = safecatd(name, sizeof name, pos, file_gamma, 3); - pos = safecat(name, sizeof name, pos, "/"); - pos = safecatd(name, sizeof name, pos, screen_gamma, 3); - - (void)gamma_test(pm, colour_type, bit_depth, 0/*palette*/, interlace_type, - file_gamma, screen_gamma, 0/*sBIT*/, 1/*threshold test*/, name, - 0 /*no input precision*/, - 0 /*no scale16*/, 0 /*no expand16*/, 0 /*no background*/, 0 /*hence*/, - 0 /*no background gamma*/); -} - -static void -perform_gamma_threshold_tests(png_modifier *pm) -{ - png_byte colour_type = 0; - png_byte bit_depth = 0; - unsigned int palette_number = 0; - - /* Don't test more than one instance of each palette - it's pointless, in - * fact this test is somewhat excessive since libpng doesn't make this - * decision based on colour type or bit depth! - */ - while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) - if (palette_number == 0) - { - double test_gamma = 1.0; - while (test_gamma >= .4) - { - /* There's little point testing the interlacing vs non-interlacing, - * but this can be set from the command line. - */ - gamma_threshold_test(pm, colour_type, bit_depth, pm->interlace_type, - test_gamma, 1/test_gamma); - test_gamma *= .95; - } - - /* And a special test for sRGB */ - gamma_threshold_test(pm, colour_type, bit_depth, pm->interlace_type, - .45455, 2.2); - - if (fail(pm)) - return; - } -} - -static void gamma_transform_test(png_modifier *pm, - PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, - PNG_CONST int palette_number, - PNG_CONST int interlace_type, PNG_CONST double file_gamma, - PNG_CONST double screen_gamma, PNG_CONST png_byte sbit, - PNG_CONST int use_input_precision, PNG_CONST int scale16) -{ - size_t pos = 0; - char name[64]; - - if (sbit != bit_depth && sbit != 0) - { - pos = safecat(name, sizeof name, pos, "sbit("); - pos = safecatn(name, sizeof name, pos, sbit); - pos = safecat(name, sizeof name, pos, ") "); - } - - else - pos = safecat(name, sizeof name, pos, "gamma "); - - if (scale16) - pos = safecat(name, sizeof name, pos, "16to8 "); - - pos = safecatd(name, sizeof name, pos, file_gamma, 3); - pos = safecat(name, sizeof name, pos, "->"); - pos = safecatd(name, sizeof name, pos, screen_gamma, 3); - - gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type, - file_gamma, screen_gamma, sbit, 0, name, use_input_precision, - scale16, pm->test_gamma_expand16, 0 , 0, 0); -} - -static void perform_gamma_transform_tests(png_modifier *pm) -{ - png_byte colour_type = 0; - png_byte bit_depth = 0; - unsigned int palette_number = 0; - - while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) - { - unsigned int i, j; - - for (i=0; ingamma_tests; ++i) for (j=0; jngamma_tests; ++j) - if (i != j) - { - gamma_transform_test(pm, colour_type, bit_depth, palette_number, - pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/, - pm->use_input_precision, 0 /*do not scale16*/); - - if (fail(pm)) - return; - } - } -} - -static void perform_gamma_sbit_tests(png_modifier *pm) -{ - png_byte sbit; - - /* The only interesting cases are colour and grayscale, alpha is ignored here - * for overall speed. Only bit depths where sbit is less than the bit depth - * are tested. - */ - for (sbit=pm->sbitlow; sbit<(1<ngamma_tests; ++i) - { - unsigned int j; - - for (j=0; jngamma_tests; ++j) if (i != j) - { - gamma_transform_test(pm, colour_type, bit_depth, npalette, - pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], - sbit, pm->use_input_precision_sbit, 0 /*scale16*/); - - if (fail(pm)) - return; - } - } - } - } -} - -/* Note that this requires a 16 bit source image but produces 8 bit output, so - * we only need the 16bit write support, but the 16 bit images are only - * generated if DO_16BIT is defined. - */ -#ifdef DO_16BIT -static void perform_gamma_scale16_tests(png_modifier *pm) -{ -# ifndef PNG_MAX_GAMMA_8 -# define PNG_MAX_GAMMA_8 11 -# endif -# define SBIT_16_TO_8 PNG_MAX_GAMMA_8 - /* Include the alpha cases here. Note that sbit matches the internal value - * used by the library - otherwise we will get spurious errors from the - * internal sbit style approximation. - * - * The threshold test is here because otherwise the 16 to 8 conversion will - * proceed *without* gamma correction, and the tests above will fail (but not - * by much) - this could be fixed, it only appears with the -g option. - */ - unsigned int i, j; - for (i=0; ingamma_tests; ++i) - { - for (j=0; jngamma_tests; ++j) - { - if (i != j && - fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD) - { - gamma_transform_test(pm, 0, 16, 0, pm->interlace_type, - 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, - pm->use_input_precision_16to8, 1 /*scale16*/); - - if (fail(pm)) - return; - - gamma_transform_test(pm, 2, 16, 0, pm->interlace_type, - 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, - pm->use_input_precision_16to8, 1 /*scale16*/); - - if (fail(pm)) - return; - - gamma_transform_test(pm, 4, 16, 0, pm->interlace_type, - 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, - pm->use_input_precision_16to8, 1 /*scale16*/); - - if (fail(pm)) - return; - - gamma_transform_test(pm, 6, 16, 0, pm->interlace_type, - 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, - pm->use_input_precision_16to8, 1 /*scale16*/); - - if (fail(pm)) - return; - } - } - } -} -#endif /* 16 to 8 bit conversion */ - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) -static void gamma_composition_test(png_modifier *pm, - PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, - PNG_CONST int palette_number, - PNG_CONST int interlace_type, PNG_CONST double file_gamma, - PNG_CONST double screen_gamma, - PNG_CONST int use_input_precision, PNG_CONST int do_background, - PNG_CONST int expand_16) -{ - size_t pos = 0; - png_const_charp base; - double bg; - char name[128]; - png_color_16 background; - - /* Make up a name and get an appropriate background gamma value. */ - switch (do_background) - { - default: - base = ""; - bg = 4; /* should not be used */ - break; - case PNG_BACKGROUND_GAMMA_SCREEN: - base = " bckg(Screen):"; - bg = 1/screen_gamma; - break; - case PNG_BACKGROUND_GAMMA_FILE: - base = " bckg(File):"; - bg = file_gamma; - break; - case PNG_BACKGROUND_GAMMA_UNIQUE: - base = " bckg(Unique):"; - /* This tests the handling of a unique value, the math is such that the - * value tends to be <1, but is neither screen nor file (even if they - * match!) - */ - bg = (file_gamma + screen_gamma) / 3; - break; -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - case ALPHA_MODE_OFFSET + PNG_ALPHA_PNG: - base = " alpha(PNG)"; - bg = 4; /* should not be used */ - break; - case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: - base = " alpha(Porter-Duff)"; - bg = 4; /* should not be used */ - break; - case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: - base = " alpha(Optimized)"; - bg = 4; /* should not be used */ - break; - case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: - base = " alpha(Broken)"; - bg = 4; /* should not be used */ - break; -#endif - } - - /* Use random background values - the background is always presented in the - * output space (8 or 16 bit components). - */ - if (expand_16 || bit_depth == 16) - { - png_uint_32 r = random_32(); - - background.red = (png_uint_16)r; - background.green = (png_uint_16)(r >> 16); - r = random_32(); - background.blue = (png_uint_16)r; - background.gray = (png_uint_16)(r >> 16); - - /* In earlier libpng versions, those where DIGITIZE is set, any background - * gamma correction in the expand16 case was done using 8-bit gamma - * correction tables, resulting in larger errors. To cope with those - * cases use a 16-bit background value which will handle this gamma - * correction. - */ -# if DIGITIZE - if (expand_16 && (do_background == PNG_BACKGROUND_GAMMA_UNIQUE || - do_background == PNG_BACKGROUND_GAMMA_FILE) && - fabs(bg*screen_gamma-1) > PNG_GAMMA_THRESHOLD) - { - /* The background values will be looked up in an 8-bit table to do - * the gamma correction, so only select values which are an exact - * match for the 8-bit table entries: - */ - background.red = (png_uint_16)((background.red >> 8) * 257); - background.green = (png_uint_16)((background.green >> 8) * 257); - background.blue = (png_uint_16)((background.blue >> 8) * 257); - background.gray = (png_uint_16)((background.gray >> 8) * 257); - } -# endif - } - - else /* 8 bit colors */ - { - png_uint_32 r = random_32(); - - background.red = (png_byte)r; - background.green = (png_byte)(r >> 8); - background.blue = (png_byte)(r >> 16); - background.gray = (png_byte)(r >> 24); - } - - background.index = 193; /* rgb(193,193,193) to detect errors */ - if (!(colour_type & PNG_COLOR_MASK_COLOR)) - { - /* Grayscale input, we do not convert to RGB (TBD), so we must set the - * background to gray - else libpng seems to fail. - */ - background.red = background.green = background.blue = background.gray; - } - - pos = safecat(name, sizeof name, pos, "gamma "); - pos = safecatd(name, sizeof name, pos, file_gamma, 3); - pos = safecat(name, sizeof name, pos, "->"); - pos = safecatd(name, sizeof name, pos, screen_gamma, 3); - - pos = safecat(name, sizeof name, pos, base); - if (do_background < ALPHA_MODE_OFFSET) - { - /* Include the background color and gamma in the name: */ - pos = safecat(name, sizeof name, pos, "("); - /* This assumes no expand gray->rgb - the current code won't handle that! - */ - if (colour_type & PNG_COLOR_MASK_COLOR) - { - pos = safecatn(name, sizeof name, pos, background.red); - pos = safecat(name, sizeof name, pos, ","); - pos = safecatn(name, sizeof name, pos, background.green); - pos = safecat(name, sizeof name, pos, ","); - pos = safecatn(name, sizeof name, pos, background.blue); - } - else - pos = safecatn(name, sizeof name, pos, background.gray); - pos = safecat(name, sizeof name, pos, ")^"); - pos = safecatd(name, sizeof name, pos, bg, 3); - } - - gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type, - file_gamma, screen_gamma, 0/*sBIT*/, 0, name, use_input_precision, - 0/*strip 16*/, expand_16, do_background, &background, bg); -} - - -static void -perform_gamma_composition_tests(png_modifier *pm, int do_background, - int expand_16) -{ - png_byte colour_type = 0; - png_byte bit_depth = 0; - unsigned int palette_number = 0; - - /* Skip the non-alpha cases - there is no setting of a transparency colour at - * present. - */ - while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) - if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0) - { - unsigned int i, j; - - /* Don't skip the i==j case here - it's relevant. */ - for (i=0; ingamma_tests; ++i) for (j=0; jngamma_tests; ++j) - { - gamma_composition_test(pm, colour_type, bit_depth, palette_number, - pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], - pm->use_input_precision, do_background, expand_16); - - if (fail(pm)) - return; - } - } -} -#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ - -static void -init_gamma_errors(png_modifier *pm) -{ - /* Use -1 to catch tests that were not actually run */ - pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = -1.; - pm->error_color_8 = -1.; - pm->error_indexed = -1.; - pm->error_gray_16 = pm->error_color_16 = -1.; -} - -static void -print_one(const char *leader, double err) -{ - if (err != -1.) - printf(" %s %.5f\n", leader, err); -} - -static void -summarize_gamma_errors(png_modifier *pm, png_const_charp who, int low_bit_depth, - int indexed) -{ - fflush(stderr); - - if (who) - printf("\nGamma correction with %s:\n", who); - - else - printf("\nBasic gamma correction:\n"); - - if (low_bit_depth) - { - print_one(" 2 bit gray: ", pm->error_gray_2); - print_one(" 4 bit gray: ", pm->error_gray_4); - print_one(" 8 bit gray: ", pm->error_gray_8); - print_one(" 8 bit color:", pm->error_color_8); - if (indexed) - print_one(" indexed: ", pm->error_indexed); - } - - print_one("16 bit gray: ", pm->error_gray_16); - print_one("16 bit color:", pm->error_color_16); - - fflush(stdout); -} - -static void -perform_gamma_test(png_modifier *pm, int summary) -{ - /*TODO: remove this*/ - /* Save certain values for the temporary overrides below. */ - unsigned int calculations_use_input_precision = - pm->calculations_use_input_precision; -# ifdef PNG_READ_BACKGROUND_SUPPORTED - double maxout8 = pm->maxout8; -# endif - - /* First some arbitrary no-transform tests: */ - if (!pm->this.speed && pm->test_gamma_threshold) - { - perform_gamma_threshold_tests(pm); - - if (fail(pm)) - return; - } - - /* Now some real transforms. */ - if (pm->test_gamma_transform) - { - if (summary) - { - fflush(stderr); - printf("Gamma correction error summary\n\n"); - printf("The printed value is the maximum error in the pixel values\n"); - printf("calculated by the libpng gamma correction code. The error\n"); - printf("is calculated as the difference between the output pixel\n"); - printf("value (always an integer) and the ideal value from the\n"); - printf("libpng specification (typically not an integer).\n\n"); - - printf("Expect this value to be less than .5 for 8 bit formats,\n"); - printf("less than 1 for formats with fewer than 8 bits and a small\n"); - printf("number (typically less than 5) for the 16 bit formats.\n"); - printf("For performance reasons the value for 16 bit formats\n"); - printf("increases when the image file includes an sBIT chunk.\n"); - fflush(stdout); - } - - init_gamma_errors(pm); - /*TODO: remove this. Necessary because the current libpng - * implementation works in 8 bits: - */ - if (pm->test_gamma_expand16) - pm->calculations_use_input_precision = 1; - perform_gamma_transform_tests(pm); - if (!calculations_use_input_precision) - pm->calculations_use_input_precision = 0; - - if (summary) - summarize_gamma_errors(pm, 0/*who*/, 1/*low bit depth*/, 1/*indexed*/); - - if (fail(pm)) - return; - } - - /* The sbit tests produce much larger errors: */ - if (pm->test_gamma_sbit) - { - init_gamma_errors(pm); - perform_gamma_sbit_tests(pm); - - if (summary) - summarize_gamma_errors(pm, "sBIT", pm->sbitlow < 8U, 1/*indexed*/); - - if (fail(pm)) - return; - } - -#ifdef DO_16BIT /* Should be READ_16BIT_SUPPORTED */ - if (pm->test_gamma_scale16) - { - /* The 16 to 8 bit strip operations: */ - init_gamma_errors(pm); - perform_gamma_scale16_tests(pm); - - if (summary) - { - fflush(stderr); - printf("\nGamma correction with 16 to 8 bit reduction:\n"); - printf(" 16 bit gray: %.5f\n", pm->error_gray_16); - printf(" 16 bit color: %.5f\n", pm->error_color_16); - fflush(stdout); - } - - if (fail(pm)) - return; - } -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (pm->test_gamma_background) - { - init_gamma_errors(pm); - - /*TODO: remove this. Necessary because the current libpng - * implementation works in 8 bits: - */ - if (pm->test_gamma_expand16) - { - pm->calculations_use_input_precision = 1; - pm->maxout8 = .499; /* because the 16 bit background is smashed */ - } - perform_gamma_composition_tests(pm, PNG_BACKGROUND_GAMMA_UNIQUE, - pm->test_gamma_expand16); - if (!calculations_use_input_precision) - pm->calculations_use_input_precision = 0; - pm->maxout8 = maxout8; - - if (summary) - summarize_gamma_errors(pm, "background", 1, 0/*indexed*/); - - if (fail(pm)) - return; - } -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - if (pm->test_gamma_alpha_mode) - { - int do_background; - - init_gamma_errors(pm); - - /*TODO: remove this. Necessary because the current libpng - * implementation works in 8 bits: - */ - if (pm->test_gamma_expand16) - pm->calculations_use_input_precision = 1; - for (do_background = ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD; - do_background <= ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN && !fail(pm); - ++do_background) - perform_gamma_composition_tests(pm, do_background, - pm->test_gamma_expand16); - if (!calculations_use_input_precision) - pm->calculations_use_input_precision = 0; - - if (summary) - summarize_gamma_errors(pm, "alpha mode", 1, 0/*indexed*/); - - if (fail(pm)) - return; - } -#endif -} -#endif /* PNG_READ_GAMMA_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ - -/* INTERLACE MACRO VALIDATION */ -/* This is copied verbatim from the specification, it is simply the pass - * number in which each pixel in each 8x8 tile appears. The array must - * be indexed adam7[y][x] and notice that the pass numbers are based at - * 1, not 0 - the base libpng uses. - */ -static PNG_CONST -png_byte adam7[8][8] = -{ - { 1,6,4,6,2,6,4,6 }, - { 7,7,7,7,7,7,7,7 }, - { 5,6,5,6,5,6,5,6 }, - { 7,7,7,7,7,7,7,7 }, - { 3,6,4,6,3,6,4,6 }, - { 7,7,7,7,7,7,7,7 }, - { 5,6,5,6,5,6,5,6 }, - { 7,7,7,7,7,7,7,7 } -}; - -/* This routine validates all the interlace support macros in png.h for - * a variety of valid PNG widths and heights. It uses a number of similarly - * named internal routines that feed off the above array. - */ -static png_uint_32 -png_pass_start_row(int pass) -{ - int x, y; - ++pass; - for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) - return y; - return 0xf; -} - -static png_uint_32 -png_pass_start_col(int pass) -{ - int x, y; - ++pass; - for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) - return x; - return 0xf; -} - -static int -png_pass_row_shift(int pass) -{ - int x, y, base=(-1), inc=8; - ++pass; - for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) - { - if (base == (-1)) - base = y; - else if (base == y) - {} - else if (inc == y-base) - base=y; - else if (inc == 8) - inc = y-base, base=y; - else if (inc != y-base) - return 0xff; /* error - more than one 'inc' value! */ - } - - if (base == (-1)) return 0xfe; /* error - no row in pass! */ - - /* The shift is always 1, 2 or 3 - no pass has all the rows! */ - switch (inc) - { -case 2: return 1; -case 4: return 2; -case 8: return 3; -default: break; - } - - /* error - unrecognized 'inc' */ - return (inc << 8) + 0xfd; -} - -static int -png_pass_col_shift(int pass) -{ - int x, y, base=(-1), inc=8; - ++pass; - for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) - { - if (base == (-1)) - base = x; - else if (base == x) - {} - else if (inc == x-base) - base=x; - else if (inc == 8) - inc = x-base, base=x; - else if (inc != x-base) - return 0xff; /* error - more than one 'inc' value! */ - } - - if (base == (-1)) return 0xfe; /* error - no row in pass! */ - - /* The shift is always 1, 2 or 3 - no pass has all the rows! */ - switch (inc) - { -case 1: return 0; /* pass 7 has all the columns */ -case 2: return 1; -case 4: return 2; -case 8: return 3; -default: break; - } - - /* error - unrecognized 'inc' */ - return (inc << 8) + 0xfd; -} - -static png_uint_32 -png_row_from_pass_row(png_uint_32 yIn, int pass) -{ - /* By examination of the array: */ - switch (pass) - { -case 0: return yIn * 8; -case 1: return yIn * 8; -case 2: return yIn * 8 + 4; -case 3: return yIn * 4; -case 4: return yIn * 4 + 2; -case 5: return yIn * 2; -case 6: return yIn * 2 + 1; -default: break; - } - - return 0xff; /* bad pass number */ -} - -static png_uint_32 -png_col_from_pass_col(png_uint_32 xIn, int pass) -{ - /* By examination of the array: */ - switch (pass) - { -case 0: return xIn * 8; -case 1: return xIn * 8 + 4; -case 2: return xIn * 4; -case 3: return xIn * 4 + 2; -case 4: return xIn * 2; -case 5: return xIn * 2 + 1; -case 6: return xIn; -default: break; - } - - return 0xff; /* bad pass number */ -} - -static int -png_row_in_interlace_pass(png_uint_32 y, int pass) -{ - /* Is row 'y' in pass 'pass'? */ - int x; - y &= 7; - ++pass; - for (x=0; x<8; ++x) if (adam7[y][x] == pass) - return 1; - - return 0; -} - -static int -png_col_in_interlace_pass(png_uint_32 x, int pass) -{ - /* Is column 'x' in pass 'pass'? */ - int y; - x &= 7; - ++pass; - for (y=0; y<8; ++y) if (adam7[y][x] == pass) - return 1; - - return 0; -} - -static png_uint_32 -png_pass_rows(png_uint_32 height, int pass) -{ - png_uint_32 tiles = height>>3; - png_uint_32 rows = 0; - unsigned int x, y; - - height &= 7; - ++pass; - for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) - { - rows += tiles; - if (y < height) ++rows; - break; /* i.e. break the 'x', column, loop. */ - } - - return rows; -} - -static png_uint_32 -png_pass_cols(png_uint_32 width, int pass) -{ - png_uint_32 tiles = width>>3; - png_uint_32 cols = 0; - unsigned int x, y; - - width &= 7; - ++pass; - for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) - { - cols += tiles; - if (x < width) ++cols; - break; /* i.e. break the 'y', row, loop. */ - } - - return cols; -} - -static void -perform_interlace_macro_validation(void) -{ - /* The macros to validate, first those that depend only on pass: - * - * PNG_PASS_START_ROW(pass) - * PNG_PASS_START_COL(pass) - * PNG_PASS_ROW_SHIFT(pass) - * PNG_PASS_COL_SHIFT(pass) - */ - int pass; - - for (pass=0; pass<7; ++pass) - { - png_uint_32 m, f, v; - - m = PNG_PASS_START_ROW(pass); - f = png_pass_start_row(pass); - if (m != f) - { - fprintf(stderr, "PNG_PASS_START_ROW(%d) = %u != %x\n", pass, m, f); - exit(99); - } - - m = PNG_PASS_START_COL(pass); - f = png_pass_start_col(pass); - if (m != f) - { - fprintf(stderr, "PNG_PASS_START_COL(%d) = %u != %x\n", pass, m, f); - exit(99); - } - - m = PNG_PASS_ROW_SHIFT(pass); - f = png_pass_row_shift(pass); - if (m != f) - { - fprintf(stderr, "PNG_PASS_ROW_SHIFT(%d) = %u != %x\n", pass, m, f); - exit(99); - } - - m = PNG_PASS_COL_SHIFT(pass); - f = png_pass_col_shift(pass); - if (m != f) - { - fprintf(stderr, "PNG_PASS_COL_SHIFT(%d) = %u != %x\n", pass, m, f); - exit(99); - } - - /* Macros that depend on the image or sub-image height too: - * - * PNG_PASS_ROWS(height, pass) - * PNG_PASS_COLS(width, pass) - * PNG_ROW_FROM_PASS_ROW(yIn, pass) - * PNG_COL_FROM_PASS_COL(xIn, pass) - * PNG_ROW_IN_INTERLACE_PASS(y, pass) - * PNG_COL_IN_INTERLACE_PASS(x, pass) - */ - for (v=0;;) - { - /* First the base 0 stuff: */ - m = PNG_ROW_FROM_PASS_ROW(v, pass); - f = png_row_from_pass_row(v, pass); - if (m != f) - { - fprintf(stderr, "PNG_ROW_FROM_PASS_ROW(%u, %d) = %u != %x\n", - v, pass, m, f); - exit(99); - } - - m = PNG_COL_FROM_PASS_COL(v, pass); - f = png_col_from_pass_col(v, pass); - if (m != f) - { - fprintf(stderr, "PNG_COL_FROM_PASS_COL(%u, %d) = %u != %x\n", - v, pass, m, f); - exit(99); - } - - m = PNG_ROW_IN_INTERLACE_PASS(v, pass); - f = png_row_in_interlace_pass(v, pass); - if (m != f) - { - fprintf(stderr, "PNG_ROW_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", - v, pass, m, f); - exit(99); - } - - m = PNG_COL_IN_INTERLACE_PASS(v, pass); - f = png_col_in_interlace_pass(v, pass); - if (m != f) - { - fprintf(stderr, "PNG_COL_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", - v, pass, m, f); - exit(99); - } - - /* Then the base 1 stuff: */ - ++v; - m = PNG_PASS_ROWS(v, pass); - f = png_pass_rows(v, pass); - if (m != f) - { - fprintf(stderr, "PNG_PASS_ROWS(%u, %d) = %u != %x\n", - v, pass, m, f); - exit(99); - } - - m = PNG_PASS_COLS(v, pass); - f = png_pass_cols(v, pass); - if (m != f) - { - fprintf(stderr, "PNG_PASS_COLS(%u, %d) = %u != %x\n", - v, pass, m, f); - exit(99); - } - - /* Move to the next v - the stepping algorithm starts skipping - * values above 1024. - */ - if (v > 1024) - { - if (v == PNG_UINT_31_MAX) - break; - - v = (v << 1) ^ v; - if (v >= PNG_UINT_31_MAX) - v = PNG_UINT_31_MAX-1; - } - } - } -} - -/* Test color encodings. These values are back-calculated from the published - * chromaticities. The values are accurate to about 14 decimal places; 15 are - * given. These values are much more accurate than the ones given in the spec, - * which typically don't exceed 4 decimal places. This allows testing of the - * libpng code to its theoretical accuracy of 4 decimal places. (If pngvalid - * used the published errors the 'slack' permitted would have to be +/-.5E-4 or - * more.) - * - * The png_modifier code assumes that encodings[0] is sRGB and treats it - * specially: do not change the first entry in this list! - */ -static PNG_CONST color_encoding test_encodings[] = -{ -/* sRGB: must be first in this list! */ -/*gamma:*/ { 1/2.2, -/*red: */ { 0.412390799265959, 0.212639005871510, 0.019330818715592 }, -/*green:*/ { 0.357584339383878, 0.715168678767756, 0.119194779794626 }, -/*blue: */ { 0.180480788401834, 0.072192315360734, 0.950532152249660} }, -/* Kodak ProPhoto (wide gamut) */ -/*gamma:*/ { 1/1.6 /*approximate: uses 1.8 power law compared to sRGB 2.4*/, -/*red: */ { 0.797760489672303, 0.288071128229293, 0.000000000000000 }, -/*green:*/ { 0.135185837175740, 0.711843217810102, 0.000000000000000 }, -/*blue: */ { 0.031349349581525, 0.000085653960605, 0.825104602510460} }, -/* Adobe RGB (1998) */ -/*gamma:*/ { 1/(2+51./256), -/*red: */ { 0.576669042910131, 0.297344975250536, 0.027031361386412 }, -/*green:*/ { 0.185558237906546, 0.627363566255466, 0.070688852535827 }, -/*blue: */ { 0.188228646234995, 0.075291458493998, 0.991337536837639} }, -/* Adobe Wide Gamut RGB */ -/*gamma:*/ { 1/(2+51./256), -/*red: */ { 0.716500716779386, 0.258728243040113, 0.000000000000000 }, -/*green:*/ { 0.101020574397477, 0.724682314948566, 0.051211818965388 }, -/*blue: */ { 0.146774385252705, 0.016589442011321, 0.773892783545073} }, -}; - -/* signal handler - * - * This attempts to trap signals and escape without crashing. It needs a - * context pointer so that it can throw an exception (call longjmp) to recover - * from the condition; this is handled by making the png_modifier used by 'main' - * into a global variable. - */ -static png_modifier pm; - -static void signal_handler(int signum) -{ - - size_t pos = 0; - char msg[64]; - - pos = safecat(msg, sizeof msg, pos, "caught signal: "); - - switch (signum) - { - case SIGABRT: - pos = safecat(msg, sizeof msg, pos, "abort"); - break; - - case SIGFPE: - pos = safecat(msg, sizeof msg, pos, "floating point exception"); - break; - - case SIGILL: - pos = safecat(msg, sizeof msg, pos, "illegal instruction"); - break; - - case SIGINT: - pos = safecat(msg, sizeof msg, pos, "interrupt"); - break; - - case SIGSEGV: - pos = safecat(msg, sizeof msg, pos, "invalid memory access"); - break; - - case SIGTERM: - pos = safecat(msg, sizeof msg, pos, "termination request"); - break; - - default: - pos = safecat(msg, sizeof msg, pos, "unknown "); - pos = safecatn(msg, sizeof msg, pos, signum); - break; - } - - store_log(&pm.this, NULL/*png_structp*/, msg, 1/*error*/); - - /* And finally throw an exception so we can keep going, unless this is - * SIGTERM in which case stop now. - */ - if (signum != SIGTERM) - { - struct exception_context *the_exception_context = - &pm.this.exception_context; - - Throw &pm.this; - } - - else - exit(1); -} - -/* main program */ -int main(int argc, char **argv) -{ - volatile int summary = 1; /* Print the error summary at the end */ - volatile int memstats = 0; /* Print memory statistics at the end */ - - /* Create the given output file on success: */ - PNG_CONST char *volatile touch = NULL; - - /* This is an array of standard gamma values (believe it or not I've seen - * every one of these mentioned somewhere.) - * - * In the following list the most useful values are first! - */ - static double - gammas[]={2.2, 1.0, 2.2/1.45, 1.8, 1.5, 2.4, 2.5, 2.62, 2.9}; - - /* This records the command and arguments: */ - size_t cp = 0; - char command[1024]; - - anon_context(&pm.this); - - /* Add appropriate signal handlers, just the ANSI specified ones: */ - signal(SIGABRT, signal_handler); - signal(SIGFPE, signal_handler); - signal(SIGILL, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGSEGV, signal_handler); - signal(SIGTERM, signal_handler); - -#ifdef HAVE_FEENABLEEXCEPT - /* Only required to enable FP exceptions on platforms where they start off - * disabled; this is not necessary but if it is not done pngvalid will likely - * end up ignoring FP conditions that other platforms fault. - */ - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -#endif - - modifier_init(&pm); - - /* Preallocate the image buffer, because we know how big it needs to be, - * note that, for testing purposes, it is deliberately mis-aligned by tag - * bytes either side. All rows have an additional five bytes of padding for - * overwrite checking. - */ - store_ensure_image(&pm.this, NULL, 2, TRANSFORM_ROWMAX, TRANSFORM_HEIGHTMAX); - - /* Don't give argv[0], it's normally some horrible libtool string: */ - cp = safecat(command, sizeof command, cp, "pngvalid"); - - /* Default to error on warning: */ - pm.this.treat_warnings_as_errors = 1; - - /* Default assume_16_bit_calculations appropriately; this tells the checking - * code that 16-bit arithmetic is used for 8-bit samples when it would make a - * difference. - */ - pm.assume_16_bit_calculations = PNG_LIBPNG_VER >= 10700; - - /* Currently 16 bit expansion happens at the end of the pipeline, so the - * calculations are done in the input bit depth not the output. - * - * TODO: fix this - */ - pm.calculations_use_input_precision = 1U; - - /* Store the test gammas */ - pm.gammas = gammas; - pm.ngammas = (sizeof gammas) / (sizeof gammas[0]); - pm.ngamma_tests = 0; /* default to off */ - - /* And the test encodings */ - pm.encodings = test_encodings; - pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]); - - pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */ - - /* The following allows results to pass if they correspond to anything in the - * transformed range [input-.5,input+.5]; this is is required because of the - * way libpng treates the 16_TO_8 flag when building the gamma tables in - * releases up to 1.6.0. - * - * TODO: review this - */ - pm.use_input_precision_16to8 = 1U; - pm.use_input_precision_sbit = 1U; /* because libpng now rounds sBIT */ - - /* Some default values (set the behavior for 'make check' here). - * These values simply control the maximum error permitted in the gamma - * transformations. The practial limits for human perception are described - * below (the setting for maxpc16), however for 8 bit encodings it isn't - * possible to meet the accepted capabilities of human vision - i.e. 8 bit - * images can never be good enough, regardless of encoding. - */ - pm.maxout8 = .1; /* Arithmetic error in *encoded* value */ - pm.maxabs8 = .00005; /* 1/20000 */ - pm.maxcalc8 = 1./255; /* +/-1 in 8 bits for compose errors */ - pm.maxpc8 = .499; /* I.e., .499% fractional error */ - pm.maxout16 = .499; /* Error in *encoded* value */ - pm.maxabs16 = .00005;/* 1/20000 */ - pm.maxcalc16 =1./65535;/* +/-1 in 16 bits for compose errors */ - pm.maxcalcG = 1./((1<38149 by the following: - */ - pm.maxpc16 = .005; /* I.e., 1/200% - 1/20000 */ - - /* Now parse the command line options. */ - while (--argc >= 1) - { - int catmore = 0; /* Set if the argument has an argument. */ - - /* Record each argument for posterity: */ - cp = safecat(command, sizeof command, cp, " "); - cp = safecat(command, sizeof command, cp, *++argv); - - if (strcmp(*argv, "-v") == 0) - pm.this.verbose = 1; - - else if (strcmp(*argv, "-l") == 0) - pm.log = 1; - - else if (strcmp(*argv, "-q") == 0) - summary = pm.this.verbose = pm.log = 0; - - else if (strcmp(*argv, "-w") == 0) - pm.this.treat_warnings_as_errors = 0; - - else if (strcmp(*argv, "--speed") == 0) - pm.this.speed = 1, pm.ngamma_tests = pm.ngammas, pm.test_standard = 0, - summary = 0; - - else if (strcmp(*argv, "--memory") == 0) - memstats = 1; - - else if (strcmp(*argv, "--size") == 0) - pm.test_size = 1; - - else if (strcmp(*argv, "--nosize") == 0) - pm.test_size = 0; - - else if (strcmp(*argv, "--standard") == 0) - pm.test_standard = 1; - - else if (strcmp(*argv, "--nostandard") == 0) - pm.test_standard = 0; - - else if (strcmp(*argv, "--transform") == 0) - pm.test_transform = 1; - - else if (strcmp(*argv, "--notransform") == 0) - pm.test_transform = 0; - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED - else if (strncmp(*argv, "--transform-disable=", - sizeof "--transform-disable") == 0) - { - pm.test_transform = 1; - transform_disable(*argv + sizeof "--transform-disable"); - } - - else if (strncmp(*argv, "--transform-enable=", - sizeof "--transform-enable") == 0) - { - pm.test_transform = 1; - transform_enable(*argv + sizeof "--transform-enable"); - } -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - - else if (strcmp(*argv, "--gamma") == 0) - { - /* Just do two gamma tests here (2.2 and linear) for speed: */ - pm.ngamma_tests = 2U; - pm.test_gamma_threshold = 1; - pm.test_gamma_transform = 1; - pm.test_gamma_sbit = 1; - pm.test_gamma_scale16 = 1; - pm.test_gamma_background = 1; - pm.test_gamma_alpha_mode = 1; - } - - else if (strcmp(*argv, "--nogamma") == 0) - pm.ngamma_tests = 0; - - else if (strcmp(*argv, "--gamma-threshold") == 0) - pm.ngamma_tests = 2U, pm.test_gamma_threshold = 1; - - else if (strcmp(*argv, "--nogamma-threshold") == 0) - pm.test_gamma_threshold = 0; - - else if (strcmp(*argv, "--gamma-transform") == 0) - pm.ngamma_tests = 2U, pm.test_gamma_transform = 1; - - else if (strcmp(*argv, "--nogamma-transform") == 0) - pm.test_gamma_transform = 0; - - else if (strcmp(*argv, "--gamma-sbit") == 0) - pm.ngamma_tests = 2U, pm.test_gamma_sbit = 1; - - else if (strcmp(*argv, "--nogamma-sbit") == 0) - pm.test_gamma_sbit = 0; - - else if (strcmp(*argv, "--gamma-16-to-8") == 0) - pm.ngamma_tests = 2U, pm.test_gamma_scale16 = 1; - - else if (strcmp(*argv, "--nogamma-16-to-8") == 0) - pm.test_gamma_scale16 = 0; - - else if (strcmp(*argv, "--gamma-background") == 0) - pm.ngamma_tests = 2U, pm.test_gamma_background = 1; - - else if (strcmp(*argv, "--nogamma-background") == 0) - pm.test_gamma_background = 0; - - else if (strcmp(*argv, "--gamma-alpha-mode") == 0) - pm.ngamma_tests = 2U, pm.test_gamma_alpha_mode = 1; - - else if (strcmp(*argv, "--nogamma-alpha-mode") == 0) - pm.test_gamma_alpha_mode = 0; - - else if (strcmp(*argv, "--expand16") == 0) - pm.test_gamma_expand16 = 1; - - else if (strcmp(*argv, "--noexpand16") == 0) - pm.test_gamma_expand16 = 0; - - else if (strcmp(*argv, "--more-gammas") == 0) - pm.ngamma_tests = 3U; - - else if (strcmp(*argv, "--all-gammas") == 0) - pm.ngamma_tests = pm.ngammas; - - else if (strcmp(*argv, "--progressive-read") == 0) - pm.this.progressive = 1; - - else if (strcmp(*argv, "--use-update-info") == 0) - ++pm.use_update_info; /* Can call multiple times */ - - else if (strcmp(*argv, "--interlace") == 0) - { -# ifdef PNG_WRITE_INTERLACING_SUPPORTED - pm.interlace_type = PNG_INTERLACE_ADAM7; -# else - fprintf(stderr, "pngvalid: no write interlace support\n"); - return SKIP; -# endif - } - - else if (strcmp(*argv, "--use-input-precision") == 0) - pm.use_input_precision = 1U; - - else if (strcmp(*argv, "--use-calculation-precision") == 0) - pm.use_input_precision = 0; - - else if (strcmp(*argv, "--calculations-use-input-precision") == 0) - pm.calculations_use_input_precision = 1U; - - else if (strcmp(*argv, "--assume-16-bit-calculations") == 0) - pm.assume_16_bit_calculations = 1U; - - else if (strcmp(*argv, "--calculations-follow-bit-depth") == 0) - pm.calculations_use_input_precision = - pm.assume_16_bit_calculations = 0; - - else if (strcmp(*argv, "--exhaustive") == 0) - pm.test_exhaustive = 1; - - else if (argc > 1 && strcmp(*argv, "--sbitlow") == 0) - --argc, pm.sbitlow = (png_byte)atoi(*++argv), catmore = 1; - - else if (argc > 1 && strcmp(*argv, "--touch") == 0) - --argc, touch = *++argv, catmore = 1; - - else if (argc > 1 && strncmp(*argv, "--max", 5) == 0) - { - --argc; - - if (strcmp(5+*argv, "abs8") == 0) - pm.maxabs8 = atof(*++argv); - - else if (strcmp(5+*argv, "abs16") == 0) - pm.maxabs16 = atof(*++argv); - - else if (strcmp(5+*argv, "calc8") == 0) - pm.maxcalc8 = atof(*++argv); - - else if (strcmp(5+*argv, "calc16") == 0) - pm.maxcalc16 = atof(*++argv); - - else if (strcmp(5+*argv, "out8") == 0) - pm.maxout8 = atof(*++argv); - - else if (strcmp(5+*argv, "out16") == 0) - pm.maxout16 = atof(*++argv); - - else if (strcmp(5+*argv, "pc8") == 0) - pm.maxpc8 = atof(*++argv); - - else if (strcmp(5+*argv, "pc16") == 0) - pm.maxpc16 = atof(*++argv); - - else - { - fprintf(stderr, "pngvalid: %s: unknown 'max' option\n", *argv); - exit(99); - } - - catmore = 1; - } - - else if (strcmp(*argv, "--log8") == 0) - --argc, pm.log8 = atof(*++argv), catmore = 1; - - else if (strcmp(*argv, "--log16") == 0) - --argc, pm.log16 = atof(*++argv), catmore = 1; - -#ifdef PNG_SET_OPTION_SUPPORTED - else if (strncmp(*argv, "--option=", 9) == 0) - { - /* Syntax of the argument is